43
Final Design Project: CPU221 By Peter Burrows, Joanna Wycech, Hokchhay Tann, Jessica L’Heureux, Junius Santoso, Bicky Shakya, Vishal Bharam, Marco Eberth Engineering 221 12.13.11

Final Design Project: CPU221 By Peter Burrows, Joanna ...commons.trincoll.edu/.../03/FINAL-CPU_221-REPORT1.pdf · Peter Burrows, Joanna Wycech, Hokchhay Tann ... use of an extensive

  • Upload
    dodan

  • View
    216

  • Download
    0

Embed Size (px)

Citation preview

Final Design Project: CPU221

By

Peter Burrows, Joanna Wycech, Hokchhay Tann, Jessica

L’Heureux, Junius Santoso, Bicky Shakya, Vishal Bharam, Marco

Eberth

Engineering 221

12.13.11

Table Of Contents: Page No

Introduction 1

Design Goals & Objectives 1

Methodology: 1

Control Unit 2

Register 2

Instruction 2

ALU 4

Addressing Logic 8

VGA 12

Understanding of the VGA 12

Programming Aspect 12

Creating blocks on screen 14

Final VGA Interface 15

Result and Discussion

Control Unit 16

ALU 17

Addressing Logic 17

VGA 18

Debounce Switch: 19

Conclusion 20

Bibliography

Appendix:

Schematic diagram for CPU 21

Schematic for RAM and ROM combined 22

Programming Model 23

CPU timing diagram 24

Instruction Table 25

Sample Subtraction Program 26

Truth Table for Control Unit 27

VHDL for Control 28

Timing diagram for ALU 33

VHDL for addressing logic 37

Timing Diagram for addressing logic 39

Complete Schematic for CPU including VGA 41

Final timing diagram for complete CPU 42

VHDL for VGA Display 43

Introduction

The CPU221 allows one to apply their knowledge of VHDL code to program a microprocessor

system, which carries out a designated operation. The code is split up into sections, each of which are

compiled and simulated to determine if the CPU does in fact perform the correct instruction based on the

operation codes.

Design Goals & Objectives

The CPU221 problem presents the opportunity to design a complete “tiny” microprocessor

system, including CPU and memory, which will execute programs you write in its native machine

language. The design proceeds in a stepwise, modular fashion that involves designing and verifying each

sub-system with VHDL, integrating the elements into a whole and running program. One may realize the

design in a large CPLD or in the FPGA that is resident on the Altera University Program UP-2

development board or on the Xilinx BASYS board. By doing this project one will gain a clear

understanding of how a simple processor works, how the processor executes instructions, and how the

hardware executes software instructions. This is good preparation for further work in hardware and

software engineering.

In order to complete these goals, the group of eight must be divided into different groups

determined by the various sections of the project; thus, each group is responsible for the design and

VHDL verification of their sub-system. The groups are responsible for the following sections: Control

Unit, ALU, Addressing Logic/FPGA, and VGA. Upon the establishment of each group, it is necessary

that the entire group understand the basic instructions carried out by the CPU – this is done through the

use of an extensive Planning Sheet and Schematic Diagram. With these tools, VHDL programming is

completed to carry out operations based on their respective opcodes. Finally, the ultimate goal is to

engineer a CPU that successfully performs the ADD operation.

The detailed description about the work distribution is given below:

CPU Architecture and programming:

Addressing Logic and FPGA: Joanna and Jessica

Control Unit: Hokchhay and Junius

ALU: Peter and Marco

VGA Interfacing and Debounce: Bicky and Vishal

Methodology

Control Unit

CU, which stands for Control Unit is the circuitry that controls the flow of information through

the processor, and the coordinates the activities of the other units within it. The control unit determines

the sequence in which computer programs and instructions are executed. Things like processing of

programs stored in the main memory, interpretation of the instructions and issuing of signals for other

units of the computer to execute them. It also acts as a switchboard operator when several users access the

computer simultaneously.

The control unit is a finite state machine that takes its inputs as the IR, the status register (which

is partly filled by the status output from the ALU), and the current major state of the cycle. Its rules are

encoded either in random logic, a Programmable Logic Array (PLA), or Read-Only Memory (ROM), and

its outputs are sent across the processor to each point requiring coordination or direction for the control

unit. Following is the more detailed overview of the various registers and states implemented in the status

register.

i) Register:

PC ( 8 bits): The Program Counter register, pointing to the memory location, corresponding to the

instructions given in the program.

MAR (8 bits): The Memory Address register points to the desired memory locations. It could be

loaded from PC, X or TEMP register through MARMUX.

TEMP (8 bits): This register was created in order to hold temporary memory. This was mainly

introduced to avoid the racing errors. For example, when we had to send data from Idbus to

MAR, it was stored in the TEMP, which directly loads it to MAR.

Read/~Write Enable (1 bit): This one bit register controls if we were writing into the memory or

reading from the memory. When R/~W equal to 1, the data was being read from memory and

when R/~W equal 0, the data was written on the memory.

IR (4 bits): This register was responsible for all the instruction given to the control unit. It holds

the opcode that is to be executed. However, IR was not really necessary, as the instruction could

have also read from the memory and could have decoded using a decoder.

A (8 bits): This is main operational register through which most of the arithmetic operands and

results are stored. The data from Idbus is also transferred to the ALU, through this register using

AMUX.

X (8 bits): This is secondary operational register, where the second operands are being stored.

This register basically holds the memory address. The data from Idbus is transferred to X through

XMUX.

SR (4 bits): This is the status register, which is being used to show the status of the output though

ALU. This register is kept as a four bit register, where each bit represent a status.

ii) Instruction:

As mentioned earlier, Control Unit (CU) is used to control all of the instruction.

Control unit is separated into two parts which are state generator and control logic. As we might be

able to tell from its name, state generator will generate states (TR, T0, T1, T2, T3, T4, T5). The states will

move in sequentially from T0 up to T5 every time we pulse the clock with low rise pulse (negative edge

triggered) while the state will stay in TR state (reset state) if we let reset input equal to 1. Each states will

have appropriate value of signal y(state) that will be used to driven the control logic, for example at T0

we let yT0 to be equal 1 while yT1, yT2, yT3, yT4, yT5 equal to 0.

The code writing process for the control logic part will solely base on the CPU 221 planning sheet.

This planning sheet will record all the steps required by each opcodes at each state in order to finish its

operation. Furthermore, it will also include all the required selects (selo, selad0, selad1, selx, sela, selpc)

and enables (enmar, entmp, ena, enir, enx, enpc, ensr) for each state. For example, at state T0 program

counter (PC) will always point to MAR, this step will require r_w, selad0, selad1, and enmar to be 1.

After recording all those steps we can then start to find the logic expressions for all the selects and

enables. In order to do this we implemented an excel file that includes the appropriate conditions (state

and opcode) for each selects and enables signal to be on (logic-high).

enmar T0 T1 T2 T3 T4 T5 T6

LDAI 1 1

LDAD 1 1 1

LDAX 1 1 1

ADDI 1 1

ADDX 1 1

NANDX 1 1

STAD 1 1 1

STAX 1 1

NANDI 1 1

LDXI 1 1

LDXD 1 1 1

STXD 1 1 1

UDXI 1 1

BRA 1 1

BEQ 1 1

FigureXX: Truth table for enmar signal.

See appendix 1 for the complete tables of all selects and enables signals.

For example, if we see from the figure above the enmar signal will always be equal to 1 at T0 and T2

regardless the input of opcodes. The signal will also be equal to 1 at T4 for several opcodes while 0 at

other states. Thus the logic expression for enmar signal is:

enmar =T0 OR T2 OR (T4 AND LDAD) OR (T4 AND LDAX) OR (T4 AND STAD) OR (T4 AND

LDXD) OR (T4 AND STXD).

As mentioned before, the control logic part will be driven by the signal y(state) from the state generator

thus the code will end up looks like:

enmar =yT0 OR yT2 OR (yT4 AND LDAD) OR (yT4 AND LDAX) OR (yT4 AND STAD) OR (yT4

AND LDXD) OR (yT4 AND STXD).

After getting both the state generator and control logic part, the next step will be writing the VHDL code

and simulating it. Details explanation of the timing diagram will be explained in the Result and

Discussion part but basically we just need to test the code for each input of opcodes.

For Timing Diagrams & VHDL code for the CU, refer to Appendix.

ALU:

The arithmetic logic unit (ALU) is a standard component in the CPU. Bitwise logic operations

and operations such as addition, subtraction, multiplication, etc. can be performed by the ALU. The ALU

in CPU221 loads and stores data transmitted by the idbus [8...0] into the registers based on the instruction.

The instruction is generated by the control unit, which manipulates all of the enablers and MUX

controllers depending on the current state. The idbus data can be stored in either the Instruction Register

(IR), the TMP register, or the A register depending on each enabler and clock edge.

The IR translates the idbus data into an operational code. To change the opcode, the idbus must

be changed and the IR must be enabled while the clock pulse is on the positive edge. Essentially, the

idbus is changed through a string of data on the Read Only Memory (ROM) controlled by the PC counter.

The IR becomes enabled when the opcode is transmitted on the idbus from the ROM.

For our program, 4+1 is carried out and stored in the RAM. The A register serves as an

accumulator that stores the two numbers being added. A is loaded with ‘4’ from the idbus through the

instruction LDAI. Then ‘1’ is loaded into the TMP register and added to A through the instruction ADDI.

The ALU in CPU221 performs arithmetic on four different instructions (ADDI, ADDX, NANDI, and

NANDX) when initiated by the ROM. For all other instructions, the idbus is stored in the registers

depending on the enablers, which are triggered by the Control Unit. The instructions with their

corresponding opcodes are seen in the table to the right.

Many instructions aren’t used in our simple program. However, if we were to develop a

subtraction program for example, more instructions would be utilized. NANDI followed by ADDI (ADD

0000 0001 immediately) would be used to develop a two’s complement and so on.

sela

gclk

ena

ensr

enir

entmp

idbus[7..0]

TMP_out[7..0]

A_out[7..0]

opcode_out[7..0]

Z_out[7..0]

SR

CPU_ALU

inst

The diagrams above illustrate the inputs and outputs of the ALU. The symbol to the left displays

detailed approach of the system, and the symbol to the right displays the general block diagram of the

system. Outputs opcode_out [7…0] and Z_out [7…0] in the Quartus ALU symbol were implemented to

make the simulations easier to see. The Quartus ALU symbol was generated from the VHDL code seen

below. In the file, the inputs and outputs are defined in the notation.

ARCHITECTURE Behavior OF CPU_ALU IS

--opcode = instruction coming out of the IR

--A_mux = output data from the A multiplexer

--TMP_sout = same as TMP_out

--sum_ab = the ALU sum operation of the TMP and A registers

--car_ab = the carry from each bit from the TMP and A bytes

--nand_ab = the nand value from each bit from the TMP and A bytes

--z_vnout = the carry output from the ALU; will be stored in the SR when enabled

--LDAIcode...etc = will tell the ALU whether or not it needs to add, nand, etc.

--sela = select A; determines the A MUX output

--ena = enable A; enables the A register

--ensr = enable SR; enables the status register

--enir = enable IR; enables the instruction register

--entmp = enable TMP; enables the Temporary storage register

--gclk = synchronous clock

Diagram of ALU

TMP_out Opcode[7…0]

Block Diagram/Quartus

ALU Symbol

--idbus = constanly transmitting data and data addresses from the ROM

--TMP_out = The data coming out of the TMP register

--A_out = the data coming out of the A register

--opcode_out = the data coming out of the IR; represents the opcode

--Z_out = the Z data coming out the ALU; the end result of the operation

--SR = the data coming out of the status register; represents the zero condition only

For all timing Diagrams, code & Simulations for the ALU , see Appendix.

Addressing Logic

The first step in writing the VHDL code for the addressing logic of the CPU was to understand

what each part of it is responsible for. The addressing logic includes a register X, an adder, a program

counter (PC) and a memory address (MAR), as well as four muxes. Going from the top of the diagram

(For Diagram/Schematic, see Lab Handout) the top register is labeled X, it is an index register that

contains an address. When the gclk is high and x is enabled, the data stored under that address comes

either from the idbus, when selx is high in the xmux, or from the offsum, when selx is low. Following the

X register, we have an 8-bit adder, which adds whatever values come from the TMP register, which is a

part of the CPU logic, to either a value stored in the PC (when selo is low in the OMUX), or value stored

in the X register (when selo is high). The next piece is the program counter, which contains the address of

the next instruction. The PC stores the value coming from the adder when selpc is low, however when

selpc is high, the value that is stored in PC gets incremented as PC+1. The final and most important piece

of the addressing logic is the MAR register that contains the current 8-bit memory address; it stores

locations that start with a 0 in the ROM, and the locations that start with 1 in the RAM. The location in

the MAR is stored from the register X, when selad1 is low, and selad0 is high, from TMP register when

both selad1 and selad0 are low, and from the PC when both selad1 and selad0 are zero.

The first piece of VHDL logic was specifying the inputs and outputs. There are four select inputs:

selad1 and selad0, which are responsible for transferring an address to the MAR, as well as selx which is

responsible for transferring the address into X register, and selo putting an address into the adder. There

are also three enable inputs: enx- enables the x register; enpc- enables to store the address into program

counter and enmar- enabling the storage in MAR. With that we have a gclk input that will call an enable

at the positive edge of the rising clock. For the addressing logic we also needed to have two 8-bit inputs

(tmp_out and idbus). Tmp_out is an 8-bit input of the adder that comes from the ALU part of the CPU,

and idbus is an 8-bit address coming from the bus interface unit of the CPU. With all the inputs we really

needed one output ADDR, which is an 8-bit memory address, however it make it easier for us to see if the

addressing logic circuit works properly we added pc_out, x_out, offsum_out and marmux_out outputs to

display the values stored in different registers.

LIBRARY ieee;

USE ieee.std_logic_1164.all ;

ENTITY addressinglogic IS

PORT (selad1,selad0,selx, enx, selo, selpc, enpc, enmar, reset :IN STD_LOGIC;

gclk :IN STD_LOGIC;

tmp_out, idbus :IN STD_LOGIC_VECTOR (7 DOWNTO 0);

ADDR, pc_out, x_out, offsum_out, marmux_out :OUT STD_LOGIC_VECTOR (7 DOWNTO 0));

END addressinglogic;

The next part of the code was building the architecture for the addressing logic. First, we had to

specify the signals that will connect all the registers in the unit. We used signal X to symbolize the X

register, offsum to show the output of an adder, car_ad to be used as a carry in the adder, pcplusone which

increments the new program counter, mar that contains the current 8-bit memory address, adder adding

values from either program counter or the X register with the value in TMP register, and finally carry_pc

that is a carry for the program counter. We also had four signals for the four different muxes in the circuit.

ARCHITECTURE behavior OF addressinglogic IS

SIGNAL X,offsum, pc, car_ad, pcplusone,mar,adder, carry_pc :STD_LOGIC_VECTOR

(7 DOWNTO 0);

SIGNAL pcmux, omux, marmux, xmux :STD_LOGIC_VECTOR (7 DOWNTO 0);

The next piece was writing the body of the code for the muxes. For the o multiplexer, when selo

is set to low omux gets the value from pc, but when set to high it gets the address from the X register. For

x multiplexer, when selx is set to low, xmux gets the address from offsum (adder), however when it is set

to high its gets the value from the idbus. For pc multiplexer, when selpc is set to low pcmux gets the

address from the adder (offsum) and if it is set to high it gets the incremented value of the program

counter. For the final MAR multiplexer, since there are two controls (selad1 and selad0) we needed to

base the select input on two values. When selad1 is low and selad0 is low the marmux gets an address

from the X register. When selad1 is set to low and selad0 is set to high, marmux gets the value from TMP

register, finally when selad1 is set to high and selad0 is high as well then marmux gets the address from

the pc register.

BEGIN

-- ss <= selad1, selad0;

WITH selo SELECT

omux <= pc WHEN '0',

X WHEN OTHERS;

WITH selx SELECT

xmux <= offsum WHEN '0',

idbus WHEN OTHERS;

WITH selpc SELECT

pcmux <= offsum WHEN '0',

pcplusone WHEN OTHERS;

marmux <= X WHEN (selad1 = '0') AND (selad0 = '0') ELSE

tmp_out WHEN (selad1 = '0') AND (selad0 = '1') ELSE

pcmux WHEN (selad1 = '1') AND (selad0 = '1') ELSE

"00000000";

The next part was writing the code for an adder, which adds the value put through the OMUX

(designated by the selo switch) and the value from the TMP register in the arithmetic logic unit. The code

adds the values bit-by- bit and includes the needed carry (car_ad) when adding the bits.

offsum(0) <= omux(0) XOR tmp_out(0);

car_ad (0) <= omux(0) AND tmp_out(0);

offsum(1) <= omux (1) XOR tmp_out(1) XOR car_ad(0);

car_ad(1) <= (omux(1) AND tmp_out(1)) OR (omux(1) AND car_ad(0)) OR (tmp_out(1)

AND car_ad(0));

offsum(2) <= omux (2) XOR tmp_out(2) XOR car_ad(1);

car_ad(2) <= (omux(2) AND tmp_out(2)) OR (omux(2) AND car_ad(1)) OR (tmp_out(2)

AND car_ad(1));

offsum(3) <= omux (3) XOR tmp_out(3) XOR car_ad(2);

car_ad(3) <= (omux(3) AND tmp_out(3)) OR (omux(3) AND car_ad(2)) OR (tmp_out(3)

AND car_ad(2));

offsum(4) <= omux (4) XOR tmp_out(4) XOR car_ad(3);

car_ad(4) <= (omux(4) AND tmp_out(4)) OR (omux(4) AND car_ad(3)) OR (tmp_out(4)

AND car_ad(3));

offsum(5) <= omux (5) XOR tmp_out(5) XOR car_ad(4);

car_ad(5) <= (omux(5) AND tmp_out(5)) OR (omux(5) AND car_ad(4)) OR (tmp_out(5)

AND car_ad(4));

offsum(6) <= omux (6) XOR tmp_out(6) XOR car_ad(5);

car_ad(6) <= (omux(6) AND tmp_out(6)) OR (omux(6) AND car_ad(5)) OR (tmp_out(6)

AND car_ad(5));

offsum(7) <= omux (7) XOR tmp_out(7) XOR car_ad(6);

car_ad(7) <= (omux(7) AND tmp_out(7)) OR (omux(7) AND car_ad(6)) OR (tmp_out(7)

AND car_ad(6));

The next part of the architecture of the code was writing the implementation of the program

counter that contains the address of the next instruction and is updated by branching. It includes carry_pc,

similarly to our code for the adder, it has to add 1 to each bit to update the current location, that is why the

carry needs to be accounted for.

pcplusone(0) <= NOT pc(0);

carry_pc(0) <= pc(0);

pcplusone(1) <= pc(1) XOR carry_pc(0);

carry_pc(1) <= pc(1) AND carry_pc(0);

pcplusone(2) <= pc(2) XOR carry_pc(1);

carry_pc(2) <= pc(2) AND carry_pc(1);

pcplusone(3) <= pc(3) XOR carry_pc(2);

carry_pc(3) <= pc(3) AND carry_pc(2);

pcplusone(4) <= pc(4) XOR carry_pc(3);

carry_pc(4) <= pc(4) AND carry_pc(3);

pcplusone(5) <= pc(5) XOR carry_pc(4);

carry_pc(5) <= pc(5) AND carry_pc(4);

pcplusone(6) <= pc(6) XOR carry_pc(5);

carry_pc(6) <= pc(6) AND carry_pc(5);

pcplusone(7) <= pc(7) XOR carry_pc(6);

The final piece of the code was storing the address in the registers. We are going to process gclk

and reset. If the reset is set to high, then the value in the program counter will be all zeros, which means

the whole program will start the process from the beginning. When enpc is set to high then pc register will

get the value from pcmux. In the case when reset is no longer one, and gclk is high, as well as register x is

enabled, then X register gets the address from XMUX. With glck set to high and enmar set to high, out

final output memory address gets the address stored in MARMUX. Then the process and behavior are

finished in the addressing logic part of the CPU.

pc_out <= pcmux;

x_out <= X;

offsum_out <= offsum;

marmux_out <= marmux;

load: PROCESS (gclk, reset)

BEGIN

IF reset = '1' THEN pc <= "00000000"; ELSIF gclk 'EVENT AND gclk = '1' THEN

IF enpc = '1' THEN pc <= pcmux; END IF; END IF;

IF gclk 'EVENT AND gclk = '1' THEN

IF enx = '1' THEN X <= xmux; END IF;

IF enmar = '1' THEN ADDR <= marmux; END IF;

END IF;

END PROCESS load;

END behavior;

The VHDL code was then compiled successfully and the simulation was run and an appropriate

timing diagram was created (For Timing Diagram of the Simulation, see Appendix) as explained in the

results and discussion section.

VGA

Making a VGA was not the requirement for the initial project; however, as there were eight people in

the group, we decided to implement a VGA, as it would also help to verify the whole project. Thus, we

decided to go on with the VGA.

i) Understanding of the VGA:

VGA (Video Graphics Array) is a popular mode of computer display. In this system, an electron

beam is sent out to a phosphorescent screen. This screen has color-phosphor dots, which radiate red,

green and blue color when an electron beam falls on them. These dots are what we know as ‘pixels’.

Normal clocked frequency for a VGA display ranges around 25 MHz and the display resolution

corresponds to 640*480 pixels, in accordance with the frequency.

When we started to work on the VGA project, we had no idea about any single component of the

VGA. Thus, in order to understand how it is possible to generate a video image using the Altera board, it

was first necessary to understand the various components of the VGA.

After studying about the various parts of the VGA, using different sources, we realized there are

total of 5 active signals are coming out of the VGA, which are known as Red_out, Green_out, Blue_out,

Horiz_out and Vert_out. The three-color signals are often called as RGB, which stands for the primary

colors. Along with these five active signals, there were two 10-bit outputs known as pixel_row and

pixel_columb. These two extra outputs were used to show the exact position of every bit of inputs

(Furman and Hamblen, 140).

640 Pixels

480 pixels

ii) Programming Aspects:

After understanding the ‘physics’ aspect of the VGA display, we started on implementing the

display on VHDL. Our main focus was on generating a coded mechanism for tracing the position of

pixels on the screen. Pixels could either be along a row or switch from row-to-row. With this in mind,

we started the VHDL coding.

In this part of the program, we are first concerned with the input clock signal of 25 Mhz. When

there is a positive clock edge from the clock signal (a high of ‘1’), the program first checks if our variable

h_count has reached the end of the row in the pixel grid. If it has, the value of h_count is set to

‘0000000000’ (RESET), placing our ‘cursor’ at the beginning of the row. If not, the pixels in a row are

counted with the clock signal (counted at every positive clock edge). Thus, we are advancing with the

pixels in a row (from left to right).

Summary: h_count keeps track of position of pixel in a row.

In the h_count section, we were concerned with counting pixels in the same row. Now, the

v_count will be implemented to count the number of rows. When the ‘cursor’ (our electron beam) has

reached the last row (524) and the last column (699), this will trigger the value of v_count to reset. If this

is not the case, when the cursor reaches the last pixel in every row, it will cause the value of v_count to go

up by one.

Summary: v_count helps us to count the number of rows.

Note: Values implemented in the program are not exactly ‘640’ or ‘480’ because we are taking

into consideration the inherent delays in the synchronization signals. This means that we need to leave

some time before and after the actual counting of pixels and rows.

iii) Creating the Blocks on the screen:

After generating the horizontal and vertical timing signals for the video signals, screen signals for

pixel data was used to create the box for the each and every input bit used. Using specific number of the

v_count, which and vertical pixel and h_count, which stands for the horizontal pixel, the boxes were

created.

As you can see in the given code above, vertical and horizontal data was created in order to show

the blocks for the each bit. If it is observed carefully, we can see that from 10 to 400 vertical pixels were

taken into the account in order to create ten rows, where from 50 to 350 horizontal pixels were taken into

the account in order to generate the eight columns referring to the eight bits. All of the blocks were

created as squares of values (twenty pixels × twenty pixels).

After generating the limits of the horizontal and vertical pixel and creating blocks for each bit, we

were supposed to assign them for the bits of the input. All of the blocks were assigned in the same way

using its horizontal and vertical position. The following part of the code shows the block assigned for the

R/~W signal. For this particular block, vertical pixels are in the range of 10-30, and horizontal pixels are

in the range of 50-70. Furthermore, we had choice to show all of these blocks either in red, green or blue

color, where we chose green. Thus, green_out was enabled by assigned it to ‘1’ and blue_out and red_out

were assigned to the bit value as shown below.

As seen above, if the w_e, for example, is 0 then the color of the block remains green, otherwise

if the R/~W (w_e) is ‘1’, then all red, green and blue output would be activated and the color of the block

would change from the green to white (R+G+B = W). Therefore, we had create separate section of ‘IF…

END IF’ for each bit.

iv) The final VGA interface

The Final VGA Interface with Grids Representing States of Components of CPU

1st row - R/~W

2nd

row - IR

3rd

row - PC

4th row - MAR

5th row - IDBUS

6th row - DBUS

7th row - A

8th row - X

9th row - TEMP

10th row - Z

11th row - CLK_COUNT

Results and Discussions

Control Unit

A) Control unit:

Figure1: Timing diagram for control unit

Figure2: Timing diagram for control unit – instruction LDAI

As mentioned before we need to simulate the VHDL code for all opcode inputs, however in this

section we will discuss only the simulation for opcode “0000” or instruction LDAI just for the simplicity.

If we see at the second low rise pulse, TR state changes to T0 state so according to our planning

sheet PC goes to MAR so we should get signal 1 for r_w, enmar, selad0, and salad1. In fact that is what

shown in the timing diagram.

After the third low rise pulse, again state should change form T0 to T1. According to the planning

sheet idbus goes to IR, so we should get signal 1 for r_w, enpc, enir, and selpc. In fact that what is we

have in the diagram.

After the fourth low rise pulse, again state should change form T1 to T2. According to the

planning sheet PC goes to MAR, so we should get signal 1 for r_w, enmar, selad0, and salad1. In fact that

what is we have in the diagram.

After the fifth low rise pulse, again state should change form T1 to T2. According to the planning

sheet idbus goes to A and PC increments by 1, so we should get signal 1 for r_w, ena, enpc, selpc. In fact

that what is we have in the diagram.

Since we get all the correct signals for each states thus we could conclude that our VHDL code is

correct. One important thing to note is that we need to set reset input to be 1 every time we finished

simulating an opcode/instruction. This is done because we want the state to come back to 0 before starting

with the new opcode.

ALU

Simulation results for the ADDI, ADDX, NANDI and NANDX instructions are observed and

explained on the next four pages. The Z_out value changed when any of these four instructions were

fetched and was loaded to A depending on the A select MUX and the A enabler. When any other

instruction was fetched, the ALU did not undergo an arithmetic operation, the Z-out value was not

changed, and the registers were loaded or not loaded, depending on the control logic.

It’s important to understand that ADDI and ADDX both yield (A PLUS TMP), and NANDI and

NANDX both yield (A NAND TMP). However, the difference between the pairs is what gets loaded in

the registers and when they get loaded. Once again, that depends on the control logic. The simulations

for the ALU just test to make sure that the A NAND TMP and A PLUS TMP operations work correctly.

They were set up such that ADDI and ADDX differ by the loaded opcode. The same applies to NANDI

and NANDX. Thus the results will be the same for each pair.

Addressing Logic

In writing the VHDL code for the addressing logic of the central processing unit understanding of

the information flow and the importance of using the multiplexers to switch between the data was crucial.

We were able to compile our program and simulate it to perform different instructions. We ran over ten

different simulations, in order to make sure the proper address is stored correctly in the desired register,

and that the select and multiplexers work properly with each other.

The first simulation we are presenting (For Timing Diagram 1 Addressing Logic, see Appendix)

performs storing of the memory address coming in from the idbus in the X register and then recognizing it

as a current 8-bit memory address stored in the MAR (output ADDR). In order to do that we loaded an

address 00001101 on the idbus, and on the positive edge of the gclk we set selx to high, to get the address

from the idbus, and enabled x to store it in X register. Now that the X register contained that address we

wanted to make it the current address for the ADDR output, in order to do that on the next clock pulse we

setselad0 to low and selad1 to low, as well as we enabled MAR register, which stored our memory

address in the MAR register and therefore our output was “00001101”. We were successful, because we

were able to simply follow the diagram from the handout, which presented the registers and multiplexers.

The second simulation we are presenting (For Timing Diagram 1 Addressing Logic, see

Appendix) uses the adder for the address on the idbus and the address in TMP register. It then takes the

output from the adder (offsum) and stores it as a current memory address in the MAR register, giving out

the desired output. On the first clock pulse we load idbus with “00001001”, as well as set selx to high and

enx to high so that the address from the idbus is stored in the X register. On the next clock pulse we load

tmp_out, which in the final, interconnected circuit will be an address stored in the TMP register, to

“00000011”, and set selo to high, which bring the two addresses (from X register and TMP register) into

the adder. Note that the output of the adder (offsum) changes then its value to 12, which means the bit-

by- bit addition was performed correctly. On the same clock pulse we then set selpc to low, and enpc to

high to load the offsum into the program counter. Note that it is done correctly, since pc_out changes to

12. We then also set both selad1 and selad0 to high, in order to enable MAR multiplexer. Finally, on the

next clock pulse we set enmar to high, in order to put the address from the pc to the MAR and out to

ADDR input, which you can see displays “00001100” making our simulation successful.

Writing the code for the addressing logic of the CPU was challenging, because it incorporated a

lot of logic about multiplexers and transferring the data between different registers. We found the

incrementing the pc to be a little tricky, because it involved a code, which was fairly similar to the adder,

but different because it just added one to the given address. With that said, it was exciting to see how in

the end our code was able to store the address in different registers, and perform different functions.

VGA

Making the VGA work was one of the very challenging and we had to go through a lot to make it

actually work. First we were given the UP2 board, which required Quartus 5.1 and parallel port, which

were unable to find in most of the computer, except a computer in the Q-lab. Therefore, we decided to

get a new board DE2, which was able to work on Quartus 9.1 and it had USB interfaced wire, which

could just be connected to any computer or laptop with Quartus 9.1. When we started to work with DE2,

it seemed as it was working fine. However, as we kept going, more and more problem started coming. We

were working with it for more than five-six days. We tried to measure the frequency and period of the

waves coming from all of the outputs from the VGA and it working fine. After that we checked the same

for the clocks. However, it wasn’t working for the 27MHz clock, which was a problem.

After getting a disappointing result from the work of a week, we decided to go back to the UP2

board. Then we had to download Quartus 5.1 in one of the old computer, where the parallel port would

work. After downloading and installing the Quartus 5.1, we also had a lot of trouble finding the valid

license for it, which we found after a long time. After writing a sample program, we created one block

and we were able to show is successfully on the monitor screen after a lot of debugging. After completing

the whole code for the VGA, the next challenge was to actually make it work and implement the program.

Debounce Switch

One last minute addition to our program was the debounce switch. We realized that on the

frequency of the clock we were using (25 MHz), we would barely be able to see any of the processing

going on within the CPU (on the VGA display). Thus, we needed a system to be able to ‘freeze’ the clock

cycles so that we could observe the states of the various data buses and registers.

This system was implemented using a push-button on the UP2. The push-button is always in a

state of ‘1’ but when we press it, the state changes to ‘0’. So, we setup a system such that when we

pressed the push-button, our clock cycle would be activated. But when the push-button was released, the

clock would stop and the system would ‘freeze’ in the state that it was last in. Only then would we be able

to see the states of the various indicators on the VGA display.

In this program, if we press the push button (button = ‘0’), the value of count increases. In the top

part, we can see that if the value of count increases up to 2000000 (clock cycles), the debounce now gets a

value of ‘1’. This is what will clock all our units in the CPU. If the button is released, count gets a value

of ‘0’. So, we are no longer which means that the value of debounce will be stuck at zero. This will

‘freeze’ the system at the state it was before it was stopped. Thus, we are effectively slowing down the

system so that we can observe the various states.

For the Complete Schematic of the entire CPU221, see Appendix.

Conclusion

Ultimately, the CPU221 consisted of applying one’s knowledge of VHDL code for the

programming and engineering of a microprocessor system. The microprocessor must then carry out

operations based on the operation codes, which are established through the combining of each section of

VHDL code for the complete CPU. Unfortunately, the CAD tools were obsolete and couldn’t contain all

the VHDL coding for 8-bits. However, when transferred the whole system into 4-bits, we were able to

perform expected operations.

1. Truth tables for all enables and selects signals

2. VHDL code for ALU

LIBRARY ieee;

USE ieee.std_logic_1164.all;

ENTITY CPU_ALU IS

PORT

(sela,gclk,ena,ensr,enir,entmp:IN STD_LOGIC;

idbus: IN STD_LOGIC_VECTOR(7 DOWNTO 0);

TMP_out,A_out,opcode_out,Z_out: OUT STD_LOGIC_VECTOR (7 DOWNTO 0);

SR: OUT STD_LOGIC);

END CPU_ALU;

SIGNAL opcode,A_mux,A,Z,TMP_sout,sum_ab,car_ab,nand_ab: STD_LOGIC_VECTOR(7 DOWNTO 0);

SIGNAL z_vnout: STD_LOGIC_VECTOR(3 DOWNTO 0);

SIGNAL LDAIcode,LDADcode,LDAXcode,ADDIcode,ADDXcode,NANDXcode,STADcode,

STAXcode,NANDIcode,LDXIcode,LDXDcode,STXDcode,UDXIcode,BRAcode,BEQcode:

STD_LOGIC;

BEGIN

--INSTANT DECODER

ADDIcode <= (NOT opcode(3)) AND (NOT opcode(2)) AND (opcode(1)) AND (opcode(0));

ADDXcode <= (NOT opcode(3)) AND (opcode(2)) AND (NOT opcode(1)) AND (NOT opcode(0));

NANDXcode <= (NOT opcode(3)) AND (opcode(2)) AND (NOT opcode(1)) AND (opcode(0));

NANDIcode <= (opcode(3)) AND (NOT opcode(2)) AND (NOT opcode(1)) AND (NOT opcode(0));

--Add Immediate (ADDI) and Add indexed (ADDX) operations of two bytes stores in the A

and TMP registers

sum_ab(0) <= a(0) XOR TMP_sout(0);

car_ab(0) <= a(0) AND TMP_sout(0);

sum_ab(1) <= a(1) XOR TMP_sout(1) XOR car_ab(0);

car_ab(1) <= (a(1) AND TMP_sout(1)) OR (a(1) AND car_ab(0)) OR (TMP_sout(1) AND

car_ab(0));

sum_ab(2) <= a(2) XOR TMP_sout(2) XOR car_ab(1);

car_ab(2) <= (a(2) AND TMP_sout(2)) OR (a(2) AND car_ab(1)) OR (TMP_sout(2) AND

car_ab(1));

sum_ab(3) <= a(3) XOR TMP_sout(3) XOR car_ab(2);

car_ab(3) <= (a(3) AND TMP_sout(3)) OR (a(3) AND car_ab(2)) OR (TMP_sout(3) AND

car_ab(2));

sum_ab(4) <= a(4) XOR TMP_sout(4) XOR car_ab(3);

car_ab(4) <= (a(4) AND TMP_sout(4)) OR (a(4) AND car_ab(3)) OR (TMP_sout(4) AND

car_ab(3));

sum_ab(5) <= a(5) XOR TMP_sout(5) XOR car_ab(4);

car_ab(5) <= (a(5) AND TMP_sout(5)) OR (a(5) AND car_ab(4)) OR (TMP_sout(5) AND

car_ab(4));

sum_ab(6) <= a(6) XOR TMP_sout(6) XOR car_ab(5);

car_ab(6) <= (a(6) AND TMP_sout(6)) OR (a(6) AND car_ab(5)) OR (TMP_sout(6) AND

car_ab(5));

sum_ab(7) <= a(7) XOR TMP_sout(7) XOR car_ab(6);

car_ab(7) <= (a(7) AND TMP_sout(7)) OR (a(7) AND car_ab(6)) OR (TMP_sout(7) AND

car_ab(6));

--NAND indexed (NANDX) and NAND immediate (NANDI) operations of two bytes

nand_ab(0) <= a(0) NAND TMP_sout(0);

nand_ab(1) <= a(1) NAND TMP_sout(1);

nand_ab(2) <= a(2) NAND TMP_sout(2);

nand_ab(3) <= a(3) NAND TMP_sout(3);

nand_ab(4) <= a(4) NAND TMP_sout(4);

nand_ab(5) <= a(5) NAND TMP_sout(5);

nand_ab(6) <= a(6) NAND TMP_sout(6);

nand_ab(7) <= a(7) NAND TMP_sout(7);

--The sum

Z <= sum_ab WHEN ADDIcode = '1' ELSE

sum_ab WHEN ADDXcode = '1' ELSE

nand_ab WHEN NANDXcode = '1' ELSE

nand_ab WHEN NANDIcode = '1';

--A multiplexer

A_mux <= Z WHEN sela = '1' ELSE

idbus WHEN sela = '0';

--The zero signal

z_vnout(0) <= (NOT Z(0)) AND (NOT Z(1)) AND (NOT Z(2)) AND (NOT Z(3)) AND (NOT Z(4))

AND (NOT Z(5)) AND (NOT Z(6)) AND (NOT Z(7));

--Outputs

TMP_out <= TMP_sout;

A_out <= A;

--Outputs (For simulation use)

opcode_out <= opcode;

Z_out <= Z;

loadregs: PROCESS(gclk)

BEGIN

IF gclk 'EVENT AND gclk = '1' THEN

IF ena = '1' THEN A <= A_mux; END IF;

IF entmp = '1' THEN TMP_sout <= idbus; END IF;

IF enir = '1' THEN opcode <= idbus; END IF;

IF ensr = '1' THEN SR <= z_vnout(0); END IF;--zero bit

END IF;

END PROCESS loadregs;

END Behavior;

3. VHDL code for control unit

Library ieee;

USE ieee.std_logic_1164.all;

ENTITY control_unit IS

PORT

(gclk, reset, sr: IN STD_LOGIC;

opcode : IN STD_LOGIC_VECTOR(7 DOWNTO 0);

enmar, entmp, ena, enir, enx, enpc, ensr : OUT STD_LOGIC; --

selo, selad1, selad0, selx, sela, selpc, r_w : OUT STD_LOGIC;

T0_out, T1_out, T2_out, T3_out, T4_out, T5_out : OUT STD_LOGIC); --

END control_unit;

ARCHITECTURE Behavior OF control_unit IS

TYPE State_type IS (TR, T0, T1, T2, T3, T4, T5);

SIGNAL y: State_type;

SIGNAL yT0, yT1, yT2, yT3, yT4, yT5: std_logic;

signal LDAI, LDAD, LDAX, ADDI, ADDX, NANDX, STAD, STAX, NANDI, LDXI, LDXD,

STXD, UDXI, BRA, BEQ: STD_LOGIC;

BEGIN

PROCESS(reset,gclk)

BEGIN

IF opcode="00000000" THEN

LDAI <= '1';LDAD <= '0'; LDAX <= '0'; ADDI <= '0'; ADDX <= '0';

NANDX <= '0'; STAD <= '0'; STAX <= '0'; NANDI <= '0'; LDXI <= '0';

LDXD <= '0'; STXD <= '0'; UDXI <= '0'; BRA <= '0'; BEQ <= '0';

ELSIF opcode="00000001" THEN

LDAI <= '0';LDAD <= '1'; LDAX <= '0'; ADDI <= '0'; ADDX <= '0';

NANDX <= '0'; STAD <= '0'; STAX <= '0'; NANDI <= '0'; LDXI <= '0';

LDXD <= '0'; STXD <= '0'; UDXI <= '0'; BRA <= '0'; BEQ <= '0';

ELSIF opcode="00000010" THEN

LDAI <= '0';LDAD <= '0'; LDAX <= '1'; ADDI <= '0'; ADDX <= '0';

NANDX <= '0'; STAD <= '0'; STAX <= '0'; NANDI <= '0'; LDXI <= '0';

LDXD <= '0'; STXD <= '0'; UDXI <= '0'; BRA <= '0'; BEQ <= '0';

ELSIF opcode="00000011" THEN

LDAI <= '0';LDAD <= '0'; LDAX <= '0'; ADDI <= '1'; ADDX <= '0';

NANDX <= '0'; STAD <= '0'; STAX <= '0'; NANDI <= '0'; LDXI <= '0';

LDXD <= '0'; STXD <= '0'; UDXI <= '0'; BRA <= '0'; BEQ <= '0';

ELSIF opcode="00000100" THEN

LDAI <= '0';LDAD <= '0'; LDAX <= '0'; ADDI <= '0'; ADDX <= '1';

NANDX <= '0'; STAD <= '0'; STAX <= '0'; NANDI <= '0'; LDXI <= '0';

LDXD <= '0'; STXD <= '0'; UDXI <= '0'; BRA <= '0'; BEQ <= '0';

ELSIF opcode="00000101" THEN

LDAI <= '0';LDAD <= '0'; LDAX <= '0'; ADDI <= '0'; ADDX <= '0';

NANDX <= '1'; STAD <= '0'; STAX <= '0'; NANDI <= '0'; LDXI <= '0';

LDXD <= '0'; STXD <= '0'; UDXI <= '0'; BRA <= '0'; BEQ <= '0';

ELSIF opcode="00000110" THEN

LDAI <= '0';LDAD <= '0'; LDAX <= '0'; ADDI <= '0'; ADDX <= '0';

NANDX <= '0'; STAD <= '1'; STAX <= '0'; NANDI <= '0'; LDXI <= '0';

LDXD <= '0'; STXD <= '0'; UDXI <= '0'; BRA <= '0'; BEQ <= '0';

ELSIF opcode="00000111" THEN

LDAI <= '0';LDAD <= '0'; LDAX <= '0'; ADDI <= '0'; ADDX <= '0';

NANDX <= '0'; STAD <= '0'; STAX <= '1'; NANDI <= '0'; LDXI <= '0';

LDXD <= '0'; STXD <= '0'; UDXI <= '0'; BRA <= '0'; BEQ <= '0';

ELSIF opcode="00001000" THEN

LDAI <= '0';LDAD <= '0'; LDAX <= '0'; ADDI <= '0'; ADDX <= '0';

NANDX <= '0'; STAD <= '0'; STAX <= '0'; NANDI <= '1'; LDXI <= '0';

LDXD <= '0'; STXD <= '0'; UDXI <= '0'; BRA <= '0'; BEQ <= '0';

ELSIF opcode="00001001" THEN

LDAI <= '0';LDAD <= '0'; LDAX <= '0'; ADDI <= '0'; ADDX <= '0';

NANDX <= '0'; STAD <= '0'; STAX <= '0'; NANDI <= '0'; LDXI <= '1';

LDXD <= '0'; STXD <= '0'; UDXI <= '0'; BRA <= '0'; BEQ <= '0';

ELSIF opcode="00001010" THEN

LDAI <= '0';LDAD <= '0'; LDAX <= '0'; ADDI <= '0'; ADDX <= '0';

NANDX <= '0'; STAD <= '0'; STAX <= '0'; NANDI <= '0'; LDXI <= '0';

LDXD <= '1'; STXD <= '0'; UDXI <= '0'; BRA <= '0'; BEQ <= '0';

ELSIF opcode="00001011" THEN

LDAI <= '0';LDAD <= '0'; LDAX <= '0'; ADDI <= '0'; ADDX <= '0';

NANDX <= '0'; STAD <= '0'; STAX <= '0'; NANDI <= '0'; LDXI <= '0';

LDXD <= '0'; STXD <= '1'; UDXI <= '0'; BRA <= '0'; BEQ <= '0';

ELSIF opcode="00001100" THEN

LDAI <= '0';LDAD <= '0'; LDAX <= '0'; ADDI <= '0'; ADDX <= '0';

NANDX <= '0'; STAD <= '0'; STAX <= '0'; NANDI <= '0'; LDXI <= '0';

LDXD <= '0'; STXD <= '0'; UDXI <= '1'; BRA <= '0'; BEQ <= '0';

ELSIF opcode="00001101" THEN

LDAI <= '0';LDAD <= '0'; LDAX <= '0'; ADDI <= '0'; ADDX <= '0';

NANDX <= '0'; STAD <= '0'; STAX <= '0'; NANDI <= '0'; LDXI <= '0';

LDXD <= '0'; STXD <= '0'; UDXI <= '0'; BRA <= '1'; BEQ <= '0';

ELSIF opcode="00001110" THEN

LDAI <= '0';LDAD <= '0'; LDAX <= '0'; ADDI <= '0'; ADDX <= '0';

NANDX <= '0'; STAD <= '0'; STAX <= '0'; NANDI <= '0'; LDXI <= '0';

LDXD <= '0'; STXD <= '0'; UDXI <= '0'; BRA <= '0'; BEQ <= '1';

END IF;

IF reset='1' THEN

y <= TR;

ELSIF (gclk'EVENT AND gclk='0')THEN

CASE y IS

WHEN TR =>

y <= T0;

WHEN T0 =>

y <= T1;

yT0 <= '1';

yT1 <= '0';

yT2 <= '0';

yT3 <= '0';

yT4 <= '0';

yT5 <= '0';

T0_out <= '1';

WHEN T1 =>

y <= T2;

yT0 <= '0';

yT1 <= '1';

yT2 <= '0';

yT3 <= '0';

yT4 <= '0';

yT5 <= '0';

T1_out <= '1';

WHEN T2 =>

y <= T3;

yT0 <= '0';

yT1 <= '0';

yT2 <= '1';

yT3 <= '0';

yT4 <= '0';

yT5 <= '0';

T2_out <= '1';

WHEN T3 =>

yT0 <= '0';

yT1 <= '0';

yT2 <= '0';

yT3 <= '1';

yT4 <= '0';

yT5 <= '0';

T3_out <='1';

IF opcode="00000000" OR opcode="00001001" THEN

y <= T0;

ELSE

y <= T4;

END IF;

WHEN T4 =>

yT0 <= '0';

yT1 <= '0';

yT2 <= '0';

yT3 <= '0';

yT4 <= '1';

yT5 <= '0';

T4_out <='1';

IF opcode="00000001" OR opcode="00000010" OR

opcode="00001010" THEN

y <= T5;

ELSE

y <= T0;

END IF;

WHEN T5 =>

y <= T0;

yT0 <= '0';

yT1 <= '0';

yT2 <= '0';

yT3 <= '0';

yT4 <= '0';

yT5 <= '1';

T5_out <= '1';

END CASE;

END IF;

END PROCESS;

enmar<= yT0 OR yT2 OR (yT4 AND LDAD) OR (yT4 AND LDAX) OR (yT4 AND STAD)

OR (yT4 AND LDXD) OR (yT4 AND STXD);

entmp<=(yT3 AND LDAD) OR (yT3 AND ADDI)OR(yT3 AND ADDX)OR(yT3 AND

NANDX)OR(yT3 AND STAD)OR(yT3 AND NANDI)OR(yT3 AND LDXD)OR(yT3 AND STXD)OR

(yT3 AND UDXI)OR(yT3 AND BRA)OR(yT3 AND BEQ);

ena<= (yT3 AND LDAI)OR(yT4 AND ADDI)OR(yT4 AND ADDX)OR(yT4 AND

NANDX)OR(yT4 AND NANDI)OR(yT5 AND LDAD)OR(yT5 AND LDAX);

enir<=yT1;

enx<=(yT3 AND LDAX)OR(yT3 AND STAX)OR(yT3 AND LDXI)OR(yT4 AND UDXI)OR(yT5

AND LDXD);

enpc<= yT1 OR(yT3 AND LDAI)OR(yT3 AND LDAD)OR(yT3 AND LDAX)OR(yT3 AND

ADDI)OR(yT3 AND STAD)OR(yT3 AND NANDI)OR(yT3 AND LDXI)OR

(yT3 AND LDXD)OR(yT3 AND STXD)OR(yT3 AND UDXI)OR(yT4 AND ADDX)OR

(yT4 AND NANDX)OR(yT4 AND BRA)OR(yT4 AND BEQ)OR(yT5 AND LDAD)OR (yT5 AND

LDAX)OR(yT3 AND LDXD);

ensr <= yT1;

selo<=(yT3 AND UDXI)OR(yT3 AND BRA);

r_w<= yT0 OR yT1 OR yT2 OR (yT2 AND LDAI) OR (yT2 AND LDAD) OR (yT2 AND

LDAX) OR (yT2 AND ADDI) OR (yT2 AND ADDX) OR (yT2 AND NANDX) OR

(yT2 AND STAD) OR (yT2 AND STAX) OR (yT2 AND NANDI) OR (yT2 AND LDXI) OR

(yT2 AND LDXD) OR (yT2 AND BRA) OR (yT2 AND BEQ)OR (yT3 AND LDAI) OR

(yT3 AND LDAD) OR (yT3 AND LDAX) OR (yT3 AND ADDI) OR (yT3 AND ADDX) OR

(yT3 AND NANDX) OR (yT3 AND STAX) OR (yT3 AND NANDI) OR (yT3 AND LDXI) OR

(yT3 AND LDXD) OR (yT3 AND STXD) OR (yT3 AND UDXI) OR (yT3 AND BRA) OR

(yT3 AND BEQ) OR (yT4 AND lDAD) OR (yT4 AND LDAX) OR (yT4 AND LDXD) OR

(yT5 AND LDAD) OR (yT5 AND LDAX)OR (yT4 AND LDXD);

selad1<= yT0 OR(yT2 AND LDAI) OR (yT2 AND LDAD) OR (yT2 AND LDAX) OR (yT2

AND ADDI) OR (yT2 AND STAD) OR (yT2 AND STAX) OR (yT2 AND NANDI) OR (yT2

AND LDXI) OR (yT2 AND LDXD) OR (yT2 AND STXD) OR (yT2 AND UDXI) OR (yT2

AND BRA) OR (yT2 AND BEQ);

selad0<= yT0 OR (yT2 AND LDAI) OR (yT2 AND LDAD) OR (yT2 AND LDAX) OR

(yT2 AND ADDI) OR (yT2 AND STAD) OR (yT2 AND STAX) OR (yT2 AND NANDI) OR

(yT2 AND LDXI) OR (yT2 AND LDXD) OR (yT2 AND STXD) OR (yT2 AND UDXI)

OR(yT2 AND BRA) OR (yT2 AND BEQ) OR (yT4 AND LDAD) OR (yT4 AND STAD) OR

(yT4 AND LDXD) OR (yT4 AND STXD);

selx<=(yT3 AND LDAX) OR (yT2 AND STAX) OR (yT2 AND LDXI) OR (yT5 AND

LDXD);

sela <=(yT4 AND ADDI) OR (yT4 AND ADDX) OR (yT4 AND NANDX) OR (yT4 AND

NANDI);

selpc<=(yT1 AND LDAI) OR (yT1 AND LDAD) OR (yT1 AND LDAX) OR (yT1 AND

ADDI) OR (yT1 AND STAD) OR (yT1 AND STAX) OR (yT1 AND NANDI) OR (yT1 AND

LDXI) OR (yT1 AND LDXD) OR (yT1 AND STXD) OR (yT1 AND UDXI) OR (yT1 AND

BRA) OR (yT1 AND BEQ) OR (yT3 AND LDAI) OR (yT3 AND LDAD) OR (yT3 AND

LDAX) OR (yT3 AND ADDI) OR (yT3 AND STAD) OR (yT3 AND STAX) OR (yT3 AND

NANDI) OR (yT3 AND LDXI) OR (yT3 AND LDXD) OR (yT3 AND STXD) OR (yT4 AND

ADDX) OR (yT4 AND NANDX) OR

(yT5 AND LDAD) OR (yT3 AND LDAX) OR (yT3 AND LDXD);

END Behavior;

4. VHDL for VGA

LIBRARY IEEE;

USE IEEE.STD_LOGIC_1164.all;

USE IEEE.STD_LOGIC_ARITH.all;

USE IEEE.STD_LOGIC_UNSIGNED.all;

-- VGA Video Sync generation

ENTITY VGA_SYNC IS

PORT(w_e, clock_25Mhz, cpu_clk : IN STD_LOGIC;

PC, MAR, A, X, TEMP : IN

STD_LOGIC_VECTOR(7 DOWNTO 0);

Idbus, dbus, CLK_CNT : IN

STD_LOGIC_VECTOR(7 DOWNTO 0);

IR

: IN STD_LOGIC_VECTOR(3 DOWNTO 0);

red_out, green_out, blue_out : OUT STD_LOGIC;

horiz_sync_out, vert_sync_out : OUT STD_LOGIC;

pixel_row, pixel_column : OUT

STD_LOGIC_VECTOR(9 DOWNTO 0) );

END VGA_SYNC;

ARCHITECTURE a OF VGA_SYNC IS

SIGNAL horiz_sync, vert_sync : STD_LOGIC;

SIGNAL red_out_s,green_out_s, blue_out_s : STD_LOGIC;

SIGNAL video_on, video_on_v, video_on_h : STD_LOGIC;

SIGNAL h_count, v_count :

STD_LOGIC_VECTOR(9 DOWNTO 0);

BEGIN

green_out_s<= '1';

-- video_on is high only when RGB data is being displayed

video_on <= video_on_H AND video_on_V;

--Generate Horizontal and Vertical Timing Signals for Video Signal

PROCESS

BEGIN

WAIT UNTIL(clock_25Mhz'EVENT) AND (clock_25Mhz='1');

-- H_count counts pixels (640 + extra time for sync signals)

--

-- Horiz_sync ------------------------------------__________--------

-- H_count 0 640 659 755 799

--

IF (h_count = 799) THEN

h_count <= "0000000000";

ELSE

h_count <= h_count + 1;

END IF;

--Generate Horizontal Sync Signal using H_count

IF (h_count <= 755) AND (h_count >= 659) THEN

horiz_sync <= '0';

ELSE

horiz_sync <= '1';

END IF;

--V_count counts rows of pixels (480 + extra time for sync signals)

--

-- Vert_sync ----------------------------------_______------------

-- V_count 0 480 493-494 524

--

IF (v_count >= 524) AND (h_count >= 699) THEN

v_count <= "0000000000";

ELSIF (h_count = 699) THEN

v_count <= v_count + 1;

END IF;

-- Generate Vertical Sync Signal using V_count

IF (v_count <= 494) AND (v_count >= 493) THEN

vert_sync <= '0';

ELSE

vert_sync <= '1';

END IF;

-- Generate Video on Screen Signals for Pixel Data

-- Generating horizatal pixel data

IF ((h_count >=50 AND h_count <= 70) OR (h_count >=90 AND h_count <= 110) OR

(h_count >=130 AND h_count <= 150) OR (h_count >=170 AND h_count <= 190)

OR

(h_count >=210 AND h_count <= 230) OR (h_count >=250 AND h_count <= 270)

OR

(h_count >=290 AND h_count <= 310) OR (h_count >=330 AND h_count <= 350))

THEN

video_on_h <= '1';

pixel_column <= h_count;

ELSE

video_on_h <= '0';

END IF;

-- Generating veritical pixel data

IF (((v_count >=10 AND v_count<=30) AND (h_count >= 50 AND h_count <= 70)) OR

((v_count >=50 AND v_count <= 70) AND (h_count >= 50 AND h_count <= 350))

OR

((v_count >=90 AND v_count<= 110) AND (h_count >= 50 AND h_count <= 190))

OR

((v_count >=130 AND v_count<= 150) AND (h_count >= 50 AND h_count <=

350)) OR

((v_count >=170 AND v_count<= 190) AND (h_count >= 50 AND h_count <= 350)

) OR

((v_count >=210 AND v_count<= 230) AND (h_count >= 50 AND h_count <=

350)) OR

((v_count >=250 AND v_count<= 270) AND (h_count >= 50 AND h_count <=

350)) OR

((v_count >=290 AND v_count<= 310) AND (h_count >= 50 AND h_count <=

350)) OR

((v_count >=330 AND v_count<= 350) AND (h_count >= 50 AND h_count <=

350)) OR

((v_count >=380 AND v_count<= 400) AND (h_count >= 50 AND h_count <=

350))) THEN

video_on_v <= '1';

pixel_row <= v_count;

ELSE

video_on_v <= '0';

END IF;

-- Controlling the first block of R/~W >> w_e

IF ((v_count >=10 AND v_count <= 30) AND (h_count >=50 AND h_count <= 50)) THEN

blue_out_s<= w_e;

green_out_s<= w_e;

END IF;

-- Controlling color data for pc, first row

IF ((v_count >=50 AND v_count <= 70) AND (h_count >=50 AND h_count <= 70)) THEN

blue_out_s<= PC(7);

green_out_s<= PC(7);

END IF;

IF ((v_count >=50 AND v_count <= 70) AND (h_count >=90 AND h_count <= 110))

THEN

blue_out_s<= PC(6);

green_out_s<= PC(6);

END IF;

IF ((v_count >=50 AND v_count <= 70) AND (h_count >=130 AND h_count <= 150))

THEN

blue_out_s<= PC(5);

green_out_s<= PC(5);

END IF;

IF ((v_count >=50 AND v_count <= 70) AND (h_count >=170 AND h_count <= 190))

THEN

blue_out_s<= PC(4);

green_out_s<= PC(4);

END IF;

IF ((v_count >=50 AND v_count <= 70) AND (h_count >=210 AND h_count <= 230))

THEN

blue_out_s<= PC(3);

green_out_s<= PC(3);

END IF;

IF ((v_count >=50 AND v_count <= 70) AND (h_count >=250 AND h_count <= 270))

THEN

blue_out_s<= PC(2);

green_out_s<= PC(2);

END IF;

IF ((v_count >=50 AND v_count <= 70) AND (h_count >=290 AND h_count <= 310))

THEN

blue_out_s<= PC(1);

green_out_s<= PC(1);

END IF;

IF ((v_count >=50 AND v_count <= 70) AND (h_count >=330 AND h_count <= 350))

THEN

blue_out_s<= PC(0);

green_out_s<= PC(0);

END IF;

-- Controlling color data for IR, second row

IF ((v_count >=90 AND v_count <= 110) AND (h_count >=50 AND h_count <= 70))

THEN

blue_out_s<= IR(3);

green_out_s<= IR(3);

END IF;

IF ((v_count >=90 AND v_count <= 110) AND (h_count >=90 AND h_count <= 110))

THEN

blue_out_s<= IR(2);

green_out_s<= IR(2);

END IF;

IF ((v_count >=90 AND v_count <= 110) AND (h_count >=130 AND h_count <= 150))

THEN

blue_out_s<= IR(1);

green_out_s<= IR(1);

END IF;

IF ((v_count >=90 AND v_count <= 110) AND (h_count >=170 AND h_count <= 190))

THEN

blue_out_s<= IR(0);

green_out_s<= IR(0);

END IF;

-- Controlling color data for MAR, third row

IF ((v_count >=130 AND v_count <= 150) AND (h_count >=50 AND h_count <= 70))

THEN

blue_out_s<= MAR(7);

green_out_s<= MAR(7);

END IF;

IF ((v_count >=130 AND v_count <= 150) AND (h_count >=90 AND h_count <= 110))

THEN

blue_out_s<= MAR(6);

green_out_s<= MAR(6);

END IF;

IF ((v_count >=130 AND v_count <= 150) AND (h_count >=130 AND h_count <= 150))

THEN

blue_out_s<= MAR(5);

green_out_s<= MAR(5);

END IF;

IF ((v_count >=130 AND v_count <= 150) AND (h_count >=170 AND h_count <= 190))

THEN

blue_out_s<= MAR(4);

green_out_s<= MAR(4);

END IF;

IF ((v_count >=130 AND v_count <= 150) AND (h_count >=210 AND h_count <= 230))

THEN

blue_out_s<= MAR(3);

green_out_s<= MAR(3);

END IF;

IF ((v_count >=130 AND v_count <= 150) AND (h_count >=250 AND h_count <= 270))

THEN

blue_out_s<= MAR(2);

green_out_s<= MAR(2);

END IF;

IF ((v_count >=130 AND v_count <= 150) AND (h_count >=290 AND h_count <= 310))

THEN

blue_out_s<= MAR(1);

green_out_s<= MAR(1);

END IF;

IF ((v_count >=130 AND v_count <= 150) AND (h_count >=330 AND h_count <= 350))

THEN

blue_out_s<= MAR(0);

green_out_s<= MAR(0);

END IF;

-- Controlling color data for Idbus, fourth row

IF ((v_count >=170 AND v_count <= 50) AND (h_count >=50 AND h_count <= 70))

THEN

blue_out_s<= Idbus(7);

green_out_s<= Idbus(7);

END IF;

IF ((v_count >=170 AND v_count <= 190) AND (h_count >=90 AND h_count <= 110))

THEN

blue_out_s<= Idbus(6);

green_out_s<= Idbus(6);

END IF;

IF ((v_count >=170 AND v_count <= 190) AND (h_count >=130 AND h_count <= 150))

THEN

blue_out_s<= Idbus(5);

green_out_s<= Idbus(5);

END IF;

IF ((v_count >=170 AND v_count <= 190) AND (h_count >=170 AND h_count <= 190))

THEN

blue_out_s<= Idbus(4);

green_out_s<= Idbus(4);

END IF;

IF ((v_count >=170 AND v_count <= 190) AND (h_count >=190 AND h_count <= 210))

THEN

blue_out_s<= Idbus(3);

green_out_s<= Idbus(3);

END IF;

IF ((v_count >=170 AND v_count <= 190) AND (h_count >=230 AND h_count <= 250))

THEN

blue_out_s<= Idbus(2);

green_out_s<= Idbus(2);

END IF;

IF ((v_count >=170 AND v_count <= 190) AND (h_count >=270 AND h_count <= 310))

THEN

blue_out_s<= Idbus(1);

green_out_s<= Idbus(1);

END IF;

IF ((v_count >=170 AND v_count <= 190) AND (h_count >=330 AND h_count <= 350))

THEN

blue_out_s<= Idbus(0);

green_out_s<= Idbus(0);

END IF;

-- Controlling color data for dbus, fifth row

IF ((v_count >=210 AND v_count <= 230) AND (h_count >=50 AND h_count <= 70))

THEN

blue_out_s<= dbus(7);

green_out_s<= dbus(7);

END IF;

IF ((v_count >=210 AND v_count <= 230) AND (h_count >=90 AND h_count <= 110))

THEN

blue_out_s<= dbus(6);

green_out_s<= dbus(6);

END IF;

IF ((v_count >=210 AND v_count <= 230) AND (h_count >=130 AND h_count <= 150))

THEN

blue_out_s<= dbus(5);

green_out_s<= dbus(5);

END IF;

IF ((v_count >=210 AND v_count <= 230) AND (h_count >=170 AND h_count <= 190))

THEN

blue_out_s<= dbus(4);

green_out_s<= dbus(4);

END IF;

IF ((v_count >=210 AND v_count <= 230) AND (h_count >=210 AND h_count <= 230))

THEN

blue_out_s<= dbus(3);

green_out_s<= dbus(3);

END IF;

IF ((v_count >=210 AND v_count <= 230) AND (h_count >=250 AND h_count <= 270))

THEN

blue_out_s<= dbus(2);

green_out_s<= dbus(2);

END IF;

IF ((v_count >=210 AND v_count <= 230) AND (h_count >=290 AND h_count <= 310))

THEN

blue_out_s<= dbus(1);

green_out_s<= dbus(1);

END IF;

IF ((v_count >=210 AND v_count <= 230) AND (h_count >=330 AND h_count <= 350))

THEN

blue_out_s<= dbus(0);

green_out_s<= dbus(0);

END IF;

--Controlling color data for A, sixth row

IF ((v_count >=250 AND v_count <= 270) AND (h_count >=50 AND h_count <= 70))

THEN

blue_out_s<= A(7);

green_out_s<= A(7);

END IF;

IF ((v_count >=250 AND v_count <= 270) AND (h_count >=90 AND h_count <= 110))

THEN

blue_out_s<= A(6);

green_out_s<= A(6);

END IF;

IF ((v_count >=250 AND v_count <= 270) AND (h_count >=130 AND h_count <= 150))

THEN

blue_out_s<= A(5);

green_out_s<= A(5);

END IF;

IF ((v_count >=250 AND v_count <= 270) AND (h_count >=170 AND h_count <= 190))

THEN

blue_out_s<= A(4);

green_out_s<= A(4);

END IF;

IF ((v_count >=250 AND v_count <= 270) AND (h_count >=210 AND h_count <= 230))

THEN

blue_out_s<= A(3);

green_out_s<= A(3);

END IF;

IF ((v_count >=250 AND v_count <= 270) AND (h_count >=250 AND h_count <= 270))

THEN

blue_out_s<= A(2);

green_out_s<= A(2);

END IF;

IF ((v_count >=250 AND v_count <= 270) AND (h_count >=290 AND h_count <= 310))

THEN

blue_out_s<= A(1);

green_out_s<= A(1);

END IF;

IF ((v_count >=250 AND v_count <= 270) AND (h_count >=330 AND h_count <= 350))

THEN

blue_out_s<= A(0);

green_out_s<= A(0);

END IF;

--Controlling color data for A, seventh row

IF ((v_count >=290 AND v_count <= 310) AND (h_count >=50 AND h_count <= 70))

THEN

blue_out_s<= X(7);

green_out_s<= X(7);

END IF;

IF ((v_count >=290 AND v_count <= 310) AND (h_count >=90 AND h_count <= 110))

THEN

blue_out_s<= X(6);

green_out_s<= X(6);

END IF;

IF ((v_count >=290 AND v_count <= 310) AND (h_count >=130 AND h_count <= 150))

THEN

blue_out_s<= X(5);

green_out_s<= X(5);

END IF;

IF ((v_count >=290 AND v_count <= 310) AND (h_count >=170 AND h_count <= 190))

THEN

blue_out_s<= X(4);

green_out_s<= X(4);

END IF;

IF ((v_count >=290 AND v_count <= 310) AND (h_count >=210 AND h_count <= 230))

THEN

blue_out_s<= X(3);

green_out_s<= X(3);

END IF;

IF ((v_count >=290 AND v_count <= 310) AND (h_count >=250 AND h_count <= 270))

THEN

blue_out_s<= X(2);

green_out_s<= X(2);

END IF;

IF ((v_count >=290 AND v_count <= 310) AND (h_count >=290 AND h_count <= 310))

THEN

blue_out_s<= X(1);

green_out_s<= X(1);

END IF;

IF ((v_count >=290 AND v_count <= 310) AND (h_count >=330 AND h_count <= 350))

THEN

blue_out_s<= X(0);

green_out_s<= X(0);

END IF;

--controlling color data for TEMP, eighth row

IF ((v_count >=330 AND v_count <= 350) AND (h_count >=50 AND h_count <= 70))

THEN

blue_out_s<= TEMP(7);

green_out_s<= TEMP(7);

END IF;

IF ((v_count >=330 AND v_count <= 350) AND (h_count >=90 AND h_count <= 110))

THEN

blue_out_s<= TEMP(6);

green_out_s<= TEMP(6);

END IF;

IF ((v_count >=330 AND v_count <= 350) AND (h_count >=130 AND h_count <= 150))

THEN

blue_out_s<= TEMP(5);

green_out_s<= TEMP(5);

END IF;

IF ((v_count >=330 AND v_count <= 350) AND (h_count >=170 AND h_count <= 190))

THEN

blue_out_s<= TEMP(4);

green_out_s<= TEMP(4);

END IF;

IF ((v_count >=330 AND v_count <= 350) AND (h_count >=210 AND h_count <= 230))

THEN

blue_out_s<= TEMP(3);

green_out_s<= TEMP(3);

END IF;

IF ((v_count >=330 AND v_count <= 350) AND (h_count >=250 AND h_count <= 270))

THEN

blue_out_s<= TEMP(2);

green_out_s<= TEMP(2);

END IF;

IF ((v_count >=330 AND v_count <= 350) AND (h_count >=290 AND h_count <= 310))

THEN

blue_out_s<= TEMP(1);

green_out_s<= TEMP(1);

END IF;

IF ((v_count >=330 AND v_count <= 350) AND (h_count >=330 AND h_count <= 350))

THEN

blue_out_s<= TEMP(0);

green_out_s<= TEMP(0);

END IF;

-- FINAL ROW : CLK COUNT

IF ((v_count >=380 AND v_count <= 400) AND (h_count >=50 AND h_count <= 70))

THEN

blue_out_s<= CLK_CNT(7);

green_out_s<= CLK_CNT(7);

END IF;

IF ((v_count >=380 AND v_count <= 400) AND (h_count >=90 AND h_count <= 110))

THEN

blue_out_s<= CLK_CNT(6);

green_out_s<= CLK_CNT(6);

END IF;

IF ((v_count >=380 AND v_count <= 400) AND (h_count >=130 AND h_count <= 150))

THEN

blue_out_s<= CLK_CNT(5);

green_out_s<= CLK_CNT(5);

END IF;

IF ((v_count >=380 AND v_count <= 400) AND (h_count >=170 AND h_count <= 190))

THEN

blue_out_s<= CLK_CNT(4);

green_out_s<= CLK_CNT(4);

END IF;

IF ((v_count >=380 AND v_count <= 400) AND (h_count >=210 AND h_count <= 230))

THEN

blue_out_s<= CLK_CNT(3);

green_out_s<= CLK_CNT(3);

END IF;

IF ((v_count >=380 AND v_count <= 400) AND (h_count >=250 AND h_count <= 270))

THEN

blue_out_s<= CLK_CNT(2);

green_out_s<= CLK_CNT(2);

END IF;

IF ((v_count >=380 AND v_count <= 400) AND (h_count >=290 AND h_count <= 310))

THEN

blue_out_s<= CLK_CNT(1);

green_out_s<= CLK_CNT(1);

END IF;

IF ((v_count >=380 AND v_count <= 400) AND (h_count >=330 AND h_count <= 350))

THEN

blue_out_s<= CLK_CNT(0);

green_out_s<= CLK_CNT(0);

END IF;

-- Put all video signals through DFFs to elminate

-- any logic delays that can cause a blurry image

red_out <= red_out_s AND video_on;

green_out <= green_out_s AND video_on;

blue_out <= blue_out_s AND video_on;

horiz_sync_out <= horiz_sync;

vert_sync_out <= vert_sync;

END PROCESS;

END a;