CPU Implemented on an Xilinix FPGA

62
RAT CPU User’s Manual Evan Kirkbride Bret Omsberg CPE 233

Transcript of CPU Implemented on an Xilinix FPGA

Page 1: CPU Implemented on an Xilinix FPGA

RAT CPU User’s Manual

Evan Kirkbride

Bret Omsberg

CPE 233

Page 2: CPU Implemented on an Xilinix FPGA

Table of Contents

Introduction to RAT CPU and RAT Application .......... 1 Design and Theory of Operation .................................. 1

Register File ................................................................................. 2

Control Unit ................................................................................... 3

Program Counter .......................................................................... 4

Prog_Rom .................................................................................... 5

ALU............................................................................................... 5

Scratch RAM ................................................................................ 6

Stack Pointer ................................................................................ 7

Flags ............................................................................................. 8

Specifications of RAT CPU ........................................... 9 Integration of RAT with External Components ......... 10 Development Environment ......................................... 11 Operational Description ............................................. 13 Specification of RAT Application ............................... 13 Theory of Operation .................................................... 14 User Guide ................................................................... 15 Future Development ................................................... 15 Appendix A .................................................................. 16 Appendix B .................................................................. 54

Page 3: CPU Implemented on an Xilinix FPGA

1

Introduction to RAT CPU and RAT

Application

The RAT CPU is a complex, fully functional computer. When working with the RAT assembler, this CPU can perform nearly any function imaginable. From engendering video games, to connecting to the internet, the RAT CPU is capable of accomplishing such tasks. For most everyday computing needs, the RAT CPU would suffice. The RAT application is an integral part of the RAT CPU. The RAT CPU would not be able to use of its internal components without the program file generated by the RAT application. The RAT application is what allows for the development of assembly language programs as well as generating the program file that delivers all of the necessary information into the RAT CPU in order to operate correctly. Neither one would be much use on their own, but when working with one another, the RAT CPU and application make it into a powerful processing unit.

Design and Theory of Operation

The CPU is made of multiple different components that are specifically designed to perform different operations. Each one plays an integral part in the success of the CPU’s operation and varies in degree of complexity. Each component was extensively tested before being implemented into the overall CPU design to assure performance.

Part

A

Page 4: CPU Implemented on an Xilinix FPGA

2

Figure 1 Entire RAT CPU Architecture

Register File

The Register File is relatively small in terms of overall size of memory but is essential to the proper functionality of the CPU as a whole. The register file is 32 locations by 8 bits wide (32x8). This means that 32 different registers holding 8 bits each are location inside the register file at any given time. What makes the Register File so useful is its ability, compared to other forms of memory, to access to addresses simultaneously. This is made possible by the two input address lines and the two output lines that the register file contains. The Register File is read asynchronously meaning no clock edge is necessary to read the contents of the registers but is written to the registers on the rising clock edge.

The Register File is one of the most essential parts of the RAT CPU. It is involved in nearly every operation that the CPU runs. The Register File’s input register lines come from the IR that is feed from the prog_rom. The register file outputs two lines, one being a tri-state meaning that this line will only output if the register file makes RF_OE high. The tri-state output is connected directly into one of the inputs to the ALU. This line also connects to the Multi_Bus line and eventually to the output port. The non tri-state output is sent into two different multiplexors. The first multiplexor is for the ALU second input. The other multiplexor is feed into one of the inputs of the scratch pad multiplexor. The multiplexor also has a data in line. This is feed through a multiplexor that can come from three different places: the In_Port, the Multi_Bus, and the sum output of the ALU. If the control unit makes the write enable of the Register File, RF_OE, go high, the data that is selected from the data in line will be written to the register file.

Page 5: CPU Implemented on an Xilinix FPGA

3

Control Unit

The control unit is responsible for directing the entire CPU. The control unit controls multiplexor select lines, write enables, output enables, load lines and set and clear lines. The control unit decides which multiplexor select line to be high through the combination of inputs. The control unit also outputs the IO_OE output directly. The control unit uses states to choose where signals need to be sent. This is decided by the present state and next states that the control unit finds itself as well as the seven bit opcode coming from the Prog Rom. Each state of the control unit has a value given to each output depending on how the state should react. If a state calls to output a value, the IO_OE lines goes high as well as the RF_OE. The control unit will be able to recognize this as an output by the opcode coming from the Prog Rom. The control unit allows the rest of the CPU to work in unison. The entire CPU takes a total of four input lines and 3 output lines. The input lines consist of an inport line, a reset line, and INT_In and a clock. The CPU’s outputs are outport, port ID and IO_OE. The input port of the CPU runs directly to the register file multiplexor. This value will be selected depending on the opcode given from the Prog Rom that is loaded from the RAT Simulator. The RAT Simulator takes each operation and creates the seven bit opcode that will move the control unit into the proper state to execute each command. As the program counter increments, the Prog Rom will move down the operation list and deliver via the IR, the next opcode. With each new opcode, a new state in the control unit is reached causing different values to multiplexors, write enables, output enables to be given to various components throughout the CPU. The Program Counter, in conjunction with the Prog Rom created from the RAT Simulator; allow the correct opcode to be delivered to the control unit. The control unit in turn will deliver back the times when the program counter should increment and when the program counter should load the next value to be passed into the Prog Rom to pass the next operation code to the control unit. Once the control unit receives this value, it will pass this information to the rest of the CPU.

Figure 2 Black Box Diagram of the Register File

Page 6: CPU Implemented on an Xilinix FPGA

4

Program Counter

The Program Counter signals are as follows: PC_OE, PC_LD, PC_INC, PC_RST, and D_IN. The PC takes an input (D_IN) and will either load or output D_IN to PC_COUNT if PC_LD is on, or can increment this value and count up periodically if PC_INC is on. There is also a tri-state output (PC_TRI) that will display high Z’s unless PC_OE is on, in which case PC_TRI will mirror PC_COUNT. There is also a reset (RST) that will make the PC_COUNT output all zeroes if it is turned on. The PC in relation to the rest of the CPU will output into the address of the ROM, meaning it will access the ROM with whatever the PC displays. The PC will also have a multiplexor that will decide what to load into it, and therefore which address to access. This address is either from any immediate needs such as contents from the ROM itself that can either branch or call, or be something from the stack with a return. The program counter is essential for changing the instructions inside the prog_rom and eventually the entire CPU. During the fetch state of the CPU, the program counter will add one to the previous count inside in the program counter. The program counter gets its initial value from a multiplexor that is feed by the IR line that comes from the prog_rom, the Multi_Bus line, and an external 0x3FF line. The control unit will control which line is feed and at what point the line will be feed into the PC. Once the value is loaded into the PC, it will be incremented in the fetch states to properly run through the code of the prog_rom. The value of the PC can also be stored in the memory of the scratch pad via the tri-state output of the PC. The program counters essential purpose is to navigate through the prog_rom and keep track of what instructions have been delivered and the next instruction of the RAT CPU. The PC feeds directly into the prog_rom with the 10 bit address line that the prog_rom will deliver and output its 18 bit contents to the rest of the CPU. If the current value of the PC needs to be stored for use at a later

Figure 3 Black Box Diagram of Control Unit

Page 7: CPU Implemented on an Xilinix FPGA

5

point, the tri-state output will be sent to the scratch pad to be written to a specific address that will be available for use at any given time.

Figure 4 Black Box Diagram of Program Counter

Prog_rom

The Prog_rom, as the name implies, is a type of read-only memory, or ROM. The Prog_Rom provides the instructions created from the RAT assembler. The contents of the Prog_Rom cannot be changed by any hardware of the RAT CPU. The Prog_Rom is 1024 rows by 18 bits wide (1024x8) meaning that it has 10 address lines and 18 data lines. Once the Prog_rom is generated in the RAT Assembler, it will be controlled by the Program Counter to move between address lines and deliver the necessary information throughout the CPU.

Figure 5 Black Box Diagram of Prog Rom

ALU

The Arithmetic Logic Unit or the ALU is responsible for performing the mathematical operations that have to be performed in order for the RAT instructions to run properly. The RAT ALU has four inputs and three outputs. The four inputs consist of two 8 bit lines, a carry in line and a 4 bit select line. The three outputs of the ALU are the SUM line that is an 8 bit line, a carry flag, and a zero flag. The two eight bit input lines can either come from registers or a register

Page 8: CPU Implemented on an Xilinix FPGA

6

and from the immediate lie. The carry in input is connected the carry flag and will only be high if the carry flag is high. The four bit select line comes from the control unit and selects which operation to be carried out. Each combination of inputs to the select line corresponds to some type of operation inside the ALU. For example, if “0000” is inputted into the select line from the control unit, the ALU will recognize this as the operation to add the values from the two 8 bit inputs. Once the ALU has all the information it needs to perform an operation, the ALU will then output the sum, carry flag and zero flag. The sum comes from the addition to the two 8 bit numbers. The carry flag will only be high a ninth bit is necessary to complete the operation. For example, if the values of “11111111” and 00000001”, the sum will output “00000000” but the carry flag will output ‘1’. These two outputs are then concatenated together to create “100000000” which is nine bits instead of eight. The zero flag will only be high if the value of the sum and zero. In any other cases, the zero flag will be held low. In terms of connecting the ALU to the rest of the RAT CPU, the two 8 bit input lines come from two different destinations. One of the lines is connected the tri-state output of the register file. The second line is connected to the multiplexor from the register file and IR. The carry in line will be directed connected to the c flag. The Sum output of the ALU is connected to the multiplexor leading into the Register File.

Figure 6 Black Box Diagram of ALU

Scratch RAM

The Scratch RAM serves as the random access memory of the CPU. What makes RAM different from other forms of memory is the ability to access data directly in any random order. What also makes RAM different is the loss of stored information if the power is removed. This type of memory is known as volatile memory. In terms of the CPU, the Scratch RAM device serves as the temporary storage of data. The contents of the memory can be accessed through the RAT instructions. The Ram is also used as the storage device for the stack. Like the register file, the RAM is read asynchronously meaning no clock is necessary in reading from the RAM. The reason for this is because the RAM will need to be accessed at any given moment instead of on a clock edge. If the RAM were accessed synchronously, the system would be considerably slower. However, the RAM is written with the rising edge of the clock. The Scratch RAM has five inputs: SCR_WR, SCR_OE, CLK, SCR_ADDR and DATA. The RAM is 256 bits by 10. The 256 bits is inputted from the SCR_ADDR that is 8 bits wide. This provides the location in which data will be written too. The SCR_DATA provides the information that will be loaded into each address only if SCR_WE is high. If

Page 9: CPU Implemented on an Xilinix FPGA

7

SCR_WE is low and SCR_OE is high, the address that was inputted from the SCR_ADDR will be outputted on the tri-state output. This output will be pushed onto the multi_bus to its next location. The SCR_ADDR is passed through a multiplexor that is feed from four different places. One is from the IR that comes from Prog_Rom, another comes from the Reg_File, and the last two come from the SP. The SCR_ADDR_SEL selects which line to pass into the Scratch Pad and ultimately controls the Ram.

Figure 7 Black Box Diagram of Scratch Ram

Stack Pointer

The stack pointer is essential for finding old values that have since been stored on the scratch pad. The SP stores the value of the current address that is on top of the stack. This value is essential when trying to retrieve the latest data written to the scratch pad. The stack pointer works in conjunction with the scratch pad when the information that was recently stored to the scratch pad is trying to be accessed by a different component of the CPU. Depending on the operational code that is given to the control unit, the stack pointer may have to be increased by one or decreased by one to maintain stack integrity. This value will then be passed back into the SP and eventually into the scratch pad.

The stack pointer has four input lines. A clock, an 8 bit input address line, an asynchronous reset and an asynchronous load. The input line is controlled by a three input multiplexor. One line comes from the tri-state output of the program counter. The other two lines are come from external modules outside of the stack pointer. One line goes into a module that decrements the count by one while the other increments by one. Depending on the command given from the prog_rom, the stack pointer will control whether to increment by one, decrement by one, or feed the exact count into the scratch pad.

Figure 8 Black Box Diagram of Stack Pointer

Page 10: CPU Implemented on an Xilinix FPGA

8

Flags

The Flags are used for an important purpose involving branching and other operational codes. Some operational codes, most involving branching to other subroutines in the prog_rom, requires information from flags. For example, the command “BREQ” (branch if equals), will only branch if the zero flag is set to high. The zero flag will then be checked. If the zero flag is indeed high, the branch command will be carried out. The flag modules hold contents that have no other place to be stored. The shadow flags serve as storage devices of the flag modules during interrupts to allow for restoring information to the previous state before the interrupt occurred.

The flag components are fairly simple devices but are very important to the overall success of the CPU. Three different flags are present on the CPU. One is for the carry flag. The carry flag is attached to the ALU and is used to detect an over or under flow by mathematical operations inside the ALU. The carry flag will only be set if the C_LD input, controlled by the control unit, is high. The carry flag also has two asynchronous clear and set lines. If the clear is set by the control unit, the carry flag will be set to zero. If the set is made high by the control unit, the Carry flag will be set to one. The zero flag is much like that of the carry flag but does not have the asynchronous set and clears. The carry and zero flags also have another module added to them to deal with interrupts correctly. The zero and carry flag have what is called a shadow carry flag and shadow zero flag. These two flags work the same as the flags except the loads of these modules will only be high when the interrupt line is high. The interrupt flag is a little different from the carry and zero flags. The interrupt has no input but only lines feeding from the control unit. If the control unit sets the clear line high, the interrupt flag will be set to zero. If the control unit makes the set line high, the interrupt flag will be set to one. This carry flag feeds into an AND gate between the interrupt line and the interrupt flag that runs into the control unit.

Page 11: CPU Implemented on an Xilinix FPGA

9

Figure 9 Black Box Diagram of Carry, Zero and Interrupt Flags

Specifications of RAT CPU

DESCRIPTION NEXYS 2

Processor MicroBlaze

Gates 500K-gate Xilinx Sparatan 3E FPGA

RAM 16MB of Micron PSDRAM

ROM 16MB of Intel StrataFlash ROM

Clock 50MHz oscillator plus socket for second oscillator

Power USB Cable, 2.1mm wall-plug supply, battery pack

I/O (INPUT/OUTPUT)

Ports

60 FPGA I/O’s routed to expansion connectors

1 High speed Hirose FX2 connector and four 6-pin headers

8 LEDs

4 7-segment displays

4 buttons

Page 12: CPU Implemented on an Xilinix FPGA

10

DESCRIPTION NEXYS 2

8 slide switches

VGA Port

PS2 Port

USB Port

Serial Port

External Memory 128Mbit Micron M45W8MW 16 Cellular RAM pseudo-

static DRAM

128Mbit Intel TE28F128J3D75-110 StrataFLash Device

Peripheral Connectors Four two-row 6-pin Pmod connectors that can

accommodate up to 8Pmods

Integration of RAT with External

Components

Integrating the RAT CPU with the external components on the Nexys-2 board requires the need of a wrapper that would use the CPU as component, and have the inputs and outputs of the wrapper mapped to whatever components (LEDs, switches, buttons) as needed. The port-id would need to be unique for each kind of input and output needed in the wrapper so that the correct inputs and outputs of the CPU can be used. Within the wrapper code if the port-id is equal to a certain specified number, then an input or output would be transmitted. Examples of an input and output code that is tied to the wrapper can be seen below. The outputs would also require the IO_OE to be high in order to ensure an output of the RAT CPU is outputting.

inputs: process(s_port_id, SWITCHES)

begin

if (s_port_id = SWITCHES_ID) then

s_input_port <= SWITCHES;

else

s_input_port <= x"00";

end if;

end process inputs;

Port ID unique to switches

Port ID unique to each output required

Page 13: CPU Implemented on an Xilinix FPGA

11

Integrating other components outside the Nexys-2 board requires a very similar method depending on the peripheral. For example the PS/2 keyboard used in the application in Part B has a Key Code that would act as an input to the CPU, so a port-id for this input would be assigned to the input process of the RAT CPU as seen in the example. A PS/2 control register would need to be assigned an output from the CPU, so a similar port ID system would be used for the outputs. The VGA display would use the same methods for interfacing with the inputs and outputs of the CPU, and any required registers or modules needed for these peripherals to function would be port-mapped within the Wrapper accordingly.

Development Environment

In order to execute assembly level programming to create actions within the RAT CPU, a RAT simulator program was used. The program would take the assembly language that would manipulate the bits and registers of the prog_rom and would simulate how the bits would be manipulated within the CPU. The simulator would step through each instruction and show what would be changed within the CPU. Whenever the assembly program was complied, a prog_rom VHDL module would be created and used in the RAT CPU in Xilinx. The layout of the UI can be seen below.

outputs: process(CLK, s_load, s_port_id)

begin

if (rising_edge(CLK)) then

if (s_load = '1') then

if (s_port_id = LEDS_ID) then

r_LEDS <= s_output_port;

elsif (S_port_id = VGA_HADDR_ID) then

r_vga_wa(10 downto 8) <= S_output_port(2 downto 0);

elsif (s_port_id = VGA_LADDR_ID) then

r_vga_wa(7 downto 0) <= S_output_port;

elsif (s_port_id = VGA_WRITE_ID) then

r_vga_wd <= S_output_port;

end if;

end if;

end if;

end process outputs;

s_load = IO_OE

Port ID unique to each output required

Page 14: CPU Implemented on an Xilinix FPGA

12

Can step-through line-by-line or have interrupts

Registers and Bits changed as program plays out

Assembly Program – highlight one current instruction

Page 15: CPU Implemented on an Xilinix FPGA

13

Operational Description

The RAT application is what allows the RAT CPU to function. The application that was developed was “Guitar Hero +”. The application builds in the use of external components that work with the help of interrupts. The interrupts are only engaged when the user makes a command that the program is expecting. Two external peripherals are used, as well as the use of the 7-segment display. The first being a display monitor. The display monitor creates the environment in which the user will interact with the CPU. This is done by using a keyboard, connected via the PS2 port on the Nexys2 board. The keys that the CPU will accept are the “A”, “S”, “D”, and “F” keys. Each key corresponds to a column on the display. A block will fall down the screen and bounce between one of the four columns at any given time. The block will not become clear as to which column it will end in until the last second. If the block ends in column A and the user inputs the “A” key at the same time as the block is leaving the bottom of the screen, a point will be rewarded. If the user presses the wrong button, or mistimes the “A” key, the user will not be rewarded a point. The score is tracked on the 7-segment display on the Nexys2 board. The high score that is achievable is 10. After 10 blocks have fallen, the game will reset. After each block falls, the block will fall at an increasing rate each time. “Guitar Hero +” is a rather challenging game that ultimately tests the ability of the user to stay focused on the block and have the ability to react to the change in the column until it reaches the bottom.

Specifications of Application

DESCRIPTION GUITAR HERO +

Players 1

Buttons in use on

Keyboard

4 – A, S, D, F

High Score 10

Screen Resolution 8 bit color, 40pixels x 30pixels

Part

B

Page 16: CPU Implemented on an Xilinix FPGA

14

DESCRIPTION GUITAR HERO +

Aspect Ratio 4:3

Peripherals Needed 2- Keyboard and Monitor with VGA hookup

Theory of Operation

“Guitar Hero +” utilizes all features that the RAT CPU has to offer. In order for “Guitar Hero +” to operate efficiently and correctly, the assembly language code that the game is designed in must be properly inserted into the RAT CPU. This is done by generating a prog_rom file and synthesizing it within the RAT CPU itself. This prog_rom file, as discussed previously, will send all necessary operational codes to the control unit. The control unit now must deal, in addition to controlling the entire RAT CPU, the ability of user inputs. This is done by configuring the RAT CPU to work properly with the keyboard. The keyboard will accept four buttons to be pressed by the user: keys A, S, D and F. These four buttons correspond with the four red blocks at the bottom of the monitor. Going right to left, A corresponds with the first column, S corresponds with the second column, D corresponds with the third and F corresponds with the far left column on the monitor. As the block falls down the screen, it will be moved, with the use of the random number generator, between the four columns and alternate all the way down the screen. As the block gets close to the bottom, the block will stay in the same column allowing the user to select the button that corresponds with the location of the falling block. If the user times it correctly, a point will be added to the 7-segment display on the Nexys2 board. The RAT CPU deals with this interrupt by changing states of the Finite State Machine of the CPU. The CPU will then deliver all the information corresponding with the interrupt to the proper locations of the RAT CPU. Once the interrupt is removed, the CPU will return to its previous State and go on with operation until another interrupt is activated. This leads to a new block being generated at the top of the screen with a twist, it will fall faster than the previous block. This process will be repeated 10 times. The score of the 7-segment display will show how the amount of blocks that were correct out of 10. At the end of the 10 blocks, a game over screen will be displayed. The prog_rom file of “Guitar Hero +” handles all necessary commands of moving the blocks and comparing locations of the block with respect to the bottom of the screen. The only direct input to the RAT CPU is the interrupt line that feeds into the CPU. This interrupt line ultimately controls the state at which the CPU is in at any given time and allows “Guitar Hero +” to run effectively with external interrupts from the user.

Page 17: CPU Implemented on an Xilinix FPGA

15

User Guide

“Guitar Hero +” prides itself on its friendly environment. A monitor, keyboard, VGA cable, and a Nexys2 board programmed with the RAT CPU are the essential elements to run “Guitar Hero +”. The user only has to interact with the keyboard in order to play the game. The keys of “A”, “S”, “D”, and “F” are the only keys that the user needs to press. These are the only elements that the user needs to take into account.

“Guitar Hero +” rules are simple and have a natural feeling to them. As the block drops down the screen, the user must focus on which column the block is bouncing between. Once the block reaches the bottom red blocks, the user must correctly select the key that corresponds with the column the block is in. For example, if the block is in the second column and is just about to reach the bottom, the user would select “S”. This would reward the user with one point that would show on the 7-segment display on the Nexys2 board. If the user would have selected any other button besides “S”, or would have selected “S” after the block had already passed through the bottom of the screen or pressed it too soon, a point would not be rewarded to the user. In both scenarios the next block would then drop from the top of the screen just as before and would repeat this process a total of ten times.

Future Development

There are many possibilities for Future Development of “Guitar Hero +”. The first change would be to implement a scoring featuring on the screen instead of the 7-segment display of the Nexys2 board. Another feature would be for multiply settings. This would include the ability to change the difficulty. The difficulty could range from easy, medium, hard, and finally expert. The higher level modes could even incorporate more keys into the program. Instead of only having four keys, five to six would be possible. Another feature that would improve game play would be to incorporate another peripheral to the Nexys2 board that allowed for audio. This would allow music to be implemented into the game and have a more realistic feeling to the game. One last implementation would be to add a multiplayer feature. This could be added by using the number pad on the keyboard as player 2 and implementing a second screen that would duplicate player 1 screens over to player 2s. Each player would have the exact same keys but their scores could be prepared on screen. These additions would make the game better and be more enjoyable to the user.

Page 18: CPU Implemented on an Xilinix FPGA

16

Appendix A

ALU Code

library IEEE;

use IEEE.STD_LOGIC_1164.ALL;

use IEEE.STD_LOGIC_UNSIGNED.all;

entity ALU is

Port ( A : in STD_LOGIC_VECTOR (7 downto 0);

B : in STD_LOGIC_VECTOR (7 downto 0);

C_IN : in STD_LOGIC;

SEL : in STD_LOGIC_VECTOR (3 downto 0);

SUM : out STD_LOGIC_VECTOR (7 downto 0);

C_FLAG : out STD_LOGIC;

Z_FLAG : out STD_LOGIC);

end ALU;

architecture Behavioral of ALU is

signal output : STD_LOGIC_VECTOR(8 downto 0);

begin

selection: process(A, B, C_IN, SEL)

begin

case SEL is

when "0000" => output <= '0' & A + B; --ADD

when "0001" => output <= ('0' & A) + B + C_IN; --

ADDC

when "0010" => output <= '0' & A - B; --SUB

when "0011" => output <= '0' & A - B - C_IN; --SUBC

when "0100" => output <= '0' & A - B; --CMP

when "0101" => output <= '0' & (A AND B); --AND

when "0110" => output <= '0' & (A OR B); --OR

when "0111" => output <= '0' & (A XOR B); --EXOR

when "1000" => output <= '0' & (A AND B); --TEST

when "1001" => output <= A(7 downto 0) & C_IN; --LSL

when "1010" => output <= A(0) & C_IN & A(7 downto

1); --LSR

when "1011" => output <= A(7 downto 0) & A(7); --ROL

when "1100" => output <= A(0) & A(0) & A(7 downto

1); --ROR

when "1101" => output <= A(0) & A(7) & A(7 downto

1); --ASR

when "1110" => output <= C_IN & B; --MOV

when others => output <= C_IN & A;

end case;

end process selection;

Page 19: CPU Implemented on an Xilinix FPGA

17

Flags: process(output)

begin

if(output(7 downto 0) = "00000000") then

Z_FLAG <= '1';

else

Z_FLAG <= '0';

end if;

end process flags;

C_FLAG <= output(8);

SUM <= output(7 downto 0);

end Behavioral

ALU Mux Code

library IEEE;

use IEEE.STD_LOGIC_1164.ALL;

entity ALUMUX is

Port ( In0 : in STD_LOGIC_VECTOR (7 downto 0);

In1 : in STD_LOGIC_VECTOR (7 downto 0);

Sel : in STD_LOGIC;

Output : out STD_LOGIC_VECTOR (7 downto 0));

end ALUMUX;

architecture Behavioral of ALUMUX is

begin

process(sel, in0, in1)

begin

case sel is

when '0' => Output <= in0;

when others => output <= in1;

end case;

end process;

end Behavioral;

C Flag Code

library IEEE;

use IEEE.STD_LOGIC_1164.ALL;

entity C is

Port ( Input : in STD_LOGIC;

Page 20: CPU Implemented on an Xilinix FPGA

18

SET : in STD_LOGIC;

LoaD : in STD_LOGIC;

RST : in STD_LOGIC;

CLK : in STD_LOGIC;

FLAG : out STD_LOGIC);

end C;

architecture Behavioral of C is

begin

process(clk, set, input, load, rst) is

begin

if(rst = '1')then

flag <= '0';

elsif(set = '1') then

flag <= '1';

else

if(load = '1' and rising_edge(clk))then

flag <= input;

end if;

end if;

end process;

end Behavioral;

Z Flag Code

library IEEE;

use IEEE.STD_LOGIC_1164.ALL;

entity Z is

Port ( Input : in STD_LOGIC;

SET : in STD_LOGIC;

LoaD : in STD_LOGIC;

RST : in STD_LOGIC;

CLK : in STD_LOGIC;

FLAG : out STD_LOGIC);

end Z;

architecture Behavioral of C is

begin

process(clk, set, input, load, rst) is

begin

if(rst = '1')then

flag <= '0';

elsif(set = '1') then

flag <= '1';

Page 21: CPU Implemented on an Xilinix FPGA

19

else

if(load = '1' and rising_edge(clk))then

flag <= input;

end if;

end if;

end process;

end Behavioral;

Flag Mux Code

library IEEE;

use IEEE.STD_LOGIC_1164.ALL;

entity flagMUX is

Port ( in0 : in STD_LOGIC;

in1 : in STD_LOGIC;

sel : in STD_LOGIC;

output : out STD_LOGIC);

end flagMUX;

architecture Behavioral of flagMUX is

begin

process(in0, in1, sel) is

begin

case sel is

when '0' => output <= in0;

when others => output <= in1;

end case;

end process;

end Behavioral;

Control Unit Code

library IEEE;

use IEEE.STD_LOGIC_1164.ALL;

entity ControlUnit is

Port ( CLK : in STD_LOGIC;

C : in STD_LOGIC;

Z : in STD_LOGIC;

INT : in STD_LOGIC;

RST : in STD_LOGIC;

OPCODE_HI_5 : in STD_LOGIC_VECTOR (4 downto 0);

OPCODE_LO_2 : in STD_LOGIC_VECTOR (1 downto 0);

Page 22: CPU Implemented on an Xilinix FPGA

20

PC_LD : out STD_LOGIC;

PC_INC : out STD_LOGIC;

PC_RESET : out STD_LOGIC;

PC_OE : out STD_LOGIC;

PC_MUX_SEL : out STD_LOGIC_VECTOR (1 downto 0);

SP_LD : out STD_LOGIC;

SP_MUX_SEL : out STD_LOGIC_VECTOR (1 downto 0);

SP_RESET : out STD_LOGIC;

RF_WR : out STD_LOGIC;

RF_WR_SEL : out STD_LOGIC_VECTOR (1 downto 0);

RF_OE : out STD_LOGIC;

REG_IMMED_SEL : out STD_LOGIC;

ALU_SEL : out STD_LOGIC_VECTOR (3 downto 0);

SCR_WR : out STD_LOGIC;

SCR_OE : out STD_LOGIC;

SCR_ADDR_SEL : out STD_LOGIC_VECTOR (1 downto 0);

C_FLAG_SEL : out STD_LOGIC;

C_FLAG_LD : out STD_LOGIC;

C_FLAG_SET : out STD_LOGIC;

C_FLAG_CLR : out STD_LOGIC;

SHAD_C_LD : out STD_LOGIC;

Z_FLAG_SEL : out STD_LOGIC;

Z_FLAG_LD : out STD_LOGIC;

Z_FLAG_SET : out STD_LOGIC;

Z_FLAG_CLR : out STD_LOGIC;

SHAD_Z_LD : out STD_LOGIC;

I_FLAG_SET : out STD_LOGIC;

I_FLAG_CLR : out STD_LOGIC;

IO_OE : out STD_LOGIC);

end ControlUnit;

architecture Behavioral of ControlUnit is

type state_type is (ST_init, ST_fet, ST_exec, ST_interrupt);

signal PS,NS : state_type := ST_init;

signal sig_OPCODE_7: std_logic_vector (6 downto 0);

begin

-- concatenate the all opcodes into a 7-bit complete opcode

for

-- easy instruction decoding.

sig_OPCODE_7 <= OPCODE_HI_5 & OPCODE_LO_2;

sync_p: process (CLK, NS, RST)

begin

if (RST = '1') then

PS <= ST_init;

elsif (rising_edge(CLK)) then

PS <= NS;

end if;

end process sync_p;

Page 23: CPU Implemented on an Xilinix FPGA

21

comb_p: process (sig_OPCODE_7, PS, NS, C, Z)

begin

case PS is

-- STATE: the init cycle ------------------------------------

-- Initialize all control outputs to non-active states and reset

the PC and --SP to all zeros.

when ST_init =>

NS <= ST_fet;

PC_LD <= '0'; PC_MUX_SEL <= "00"; PC_RESET <= '1'; PC_OE

<= '0'; PC_INC <= '0';

SP_LD <= '0'; SP_MUX_SEL <= "00"; SP_RESET <= '1';

RF_WR <= '0'; RF_WR_SEL <= "00"; RF_OE <= '0';

REG_IMMED_SEL <= '0'; ALU_SEL <= "0000";

SCR_WR <= '0'; SCR_OE <= '0'; SCR_ADDR_SEL <= "00";

C_FLAG_SEL <= '0'; C_FLAG_LD <= '0'; C_FLAG_SET <= '0';

C_FLAG_CLR <= '0'; SHAD_C_LD <= '0';

Z_FLAG_SEL <= '0'; Z_FLAG_LD <= '0'; Z_FLAG_SET <= '0';

Z_FLAG_CLR <= '0'; SHAD_Z_LD <= '0';

I_FLAG_SET <= '0'; I_FLAG_CLR <= '0';

IO_OE <= '0';

-- STATE: the fetch cycle -----------------------------------

when ST_fet =>

NS <= ST_exec;

PC_LD <= '0'; PC_MUX_SEL <= "00"; PC_RESET <= '0'; PC_OE

<= '0'; PC_INC <= '1';

SP_LD <= '0'; SP_MUX_SEL <= "00"; SP_RESET <= '0';

RF_WR <= '0'; RF_WR_SEL <= "00"; RF_OE <= '0';

REG_IMMED_SEL <= '0'; ALU_SEL <= "0000";

SCR_WR <= '0'; SCR_OE <= '0'; SCR_ADDR_SEL <= "00";

C_FLAG_SEL <= '0'; C_FLAG_LD <= '0'; C_FLAG_SET <= '0';

C_FLAG_CLR <= '0'; SHAD_C_LD <= '0';

Z_FLAG_SEL <= '0'; Z_FLAG_LD <= '0'; Z_FLAG_SET <= '0';

Z_FLAG_CLR <= '0'; SHAD_Z_LD <= '0';

I_FLAG_SET <= '0'; I_FLAG_CLR <= '0';

IO_OE <= '0';

-- STATE: the execute cycle ---------------------------------

when ST_exec =>

if(INT = '0') then

NS <= ST_fet;

else

NS <= ST_interrupt;

end if;

PC_LD <= '0'; PC_MUX_SEL <= "00"; PC_RESET <= '0';

PC_OE <= '0'; PC_INC <= '0'; PC_INC <= '0';

SP_LD <= '0'; SP_MUX_SEL <= "00"; SP_RESET <= '0';

RF_WR <= '0'; RF_WR_SEL <= "00"; RF_OE <= '0';

REG_IMMED_SEL <= '0'; ALU_SEL <= "0000";

Page 24: CPU Implemented on an Xilinix FPGA

22

SCR_WR <= '0'; SCR_OE <= '0'; SCR_ADDR_SEL <= "00";

C_FLAG_SEL <= '0'; C_FLAG_LD <= '0'; C_FLAG_SET <= '0';

C_FLAG_CLR <= '0'; SHAD_C_LD <= '0';

Z_FLAG_SEL <= '0'; Z_FLAG_LD <= '0'; Z_FLAG_SET <=

'0';

Z_FLAG_CLR <= '0'; SHAD_Z_LD <= '0';

I_FLAG_SET <= '0'; I_FLAG_CLR <= '0';

IO_OE <= '0';

case sig_OPCODE_7 is

-- BRN -------------------

when "0010000" =>

PC_LD <= '1';

PC_MUX_SEL <= "00";

-- EXOR reg-reg --------

when "0000010" =>

RF_WR <= '1';

RF_OE <= '1';

ALU_SEL <= "0111";

REG_IMMED_SEL <= '0';

RF_WR_SEL <= "00";

Z_FLAG_LD <= '1';

SHAD_Z_LD <= '1';

-- EXOR reg-immed ------

when "1001000" | "1001001" | "1001010" |

"1001011" =>

RF_WR <= '1';

RF_OE <= '1';

ALU_SEL <= "0111";

REG_IMMED_SEL <= '1';

Z_FLAG_LD <= '1';

SHAD_Z_LD <= '1';

-- IN -------------------

when "1100100" | "1100101" | "1100110" |

"1100111" =>

RF_WR <= '1';

RF_WR_SEL <= "11";

-- MOV reg-reg ----------

when "0001001" =>

RF_OE <= '1';

RF_WR <='1';

ALU_SEL <= "1110";

RF_WR_SEL <= "00";

REG_IMMED_SEL <= '0';

-- MOV reg-immed --------

when "1101100" | "1101101" | "1101110" |

"1101111" =>

RF_WR <= '1';

ALU_SEL <= "1110";

REG_IMMED_SEL <= '1';

-- OUT -----------------

Page 25: CPU Implemented on an Xilinix FPGA

23

when "1101000" | "1101001" | "1101010" |

"1101011" =>

RF_OE <= '1';

IO_OE <= '1';

-- LSL ------------------

when "0100000" =>

RF_OE <= '1';

RF_WR <= '1';

RF_WR_SEL <= "00";

ALU_SEL <= "1001";

C_FLAG_LD <= '1';

Z_FLAG_LD <= '1';

SHAD_C_LD <= '1';

SHAD_Z_LD <= '1';

-- LSR -------------------

when "0100001" =>

RF_OE <= '1';

RF_WR <= '1';

ALU_SEL <= "1010";

C_FLAG_LD <= '1';

Z_FLAG_LD <= '1';

SHAD_C_LD <= '1';

SHAD_Z_LD <= '1';

-- CALL ------------------

when "0010001" =>

PC_LD <= '1';

PC_OE <= '1';

PC_MUX_SEL <= "00";

SP_MUX_SEL <= "10";

SP_LD <= '1';

SCR_ADDR_SEL <= "11";

SCR_WR <= '1';

-- RET -------------------

when "0110010" =>

PC_LD <= '1';

PC_MUX_SEL <= "01";

SP_MUX_SEL <= "11";

SP_LD <= '1';

SCR_ADDR_SEL <= "10";

SCR_OE <= '1';

-- PUSH -----------------

when "0100101" =>

SP_MUX_SEL <= "10";

SP_LD <= '1';

SCR_ADDR_SEL <= "11";

SCR_WR <= '1';

RF_OE <= '1';

-- POP ------------------

when "0100110" =>

SP_MUX_SEL <= "11";

SP_LD <= '1';

SCR_ADDR_SEL <= "10";

SCR_OE <= '1';

Page 26: CPU Implemented on an Xilinix FPGA

24

RF_WR <= '1';

RF_WR_SEL <= "01";

-- AND reg-reg -----------

when "0000000" =>

RF_WR <= '1';

RF_OE <= '1';

RF_WR_SEL <= "00";

ALU_SEL <= "0101";

REG_IMMED_SEL <= '0';

Z_FLAG_LD <= '1';

SHAD_Z_LD <= '1';

-- AND reg-immed ---------

when "1000000" | "1000001" | "1000010" |

"1000011" =>

RF_WR <= '1';

RF_OE <= '1';

RF_WR_SEL <= "00";

ALU_SEL <= "0101";

REG_IMMED_SEL <= '1';

Z_FLAG_LD <= '1';

SHAD_Z_LD <= '1';

-- OR reg-reg ------------

when "0000001" =>

RF_WR <= '1';

RF_OE <= '1';

RF_WR_SEL <= "00";

ALU_SEL <= "0110";

REG_IMMED_SEL <= '0';

Z_FLAG_LD <= '1';

SHAD_Z_LD <= '1';

-- OR reg-immed -----------

when "1000100" | "1000101" | "1000110" |

"1000111" =>

RF_WR <= '1';

RF_OE <= '1';

RF_WR_SEL <= "00";

ALU_SEL <= "0110";

REG_IMMED_SEL <= '1';

Z_FLAG_LD <= '1';

SHAD_Z_LD <= '1';

-- ROL --------------------

when "0100010" =>

RF_WR <= '1';

RF_OE <= '1';

RF_WR_SEL <= "00";

ALU_SEL <= "1011";

Z_FLAG_LD <= '1';

C_FLAG_LD <= '1';

SHAD_C_LD <= '1';

SHAD_Z_LD <= '1';

-- ROR --------------------

when "0100011" =>

RF_WR <= '1';

RF_OE <= '1';

RF_WR_SEL <= "00";

Page 27: CPU Implemented on an Xilinix FPGA

25

ALU_SEL <= "1100";

Z_FLAG_LD <= '1';

C_FLAG_LD <= '1';

SHAD_C_LD <= '1';

SHAD_Z_LD <= '1';

-- ASR --------------------

when "0100100" =>

RF_WR <= '1';

RF_OE <= '1';

RF_WR_SEL <= "00";

ALU_SEL <= "1101";

Z_FLAG_LD <= '1';

C_FLAG_LD <= '1';

SHAD_C_LD <= '1';

SHAD_Z_LD <= '1';

-- BRCS -------------------

when "0010100" =>

if(C = '1') then

PC_LD <= '1';

PC_MUX_SEL <= "00";

end if;

-- BRCC -------------------

when "0010101" =>

if(C = '0') then

PC_LD <= '1';

PC_MUX_SEL <= "00";

end if;

-- BREQ -------------------

when "0010010" =>

if(Z = '1') then

PC_LD <= '1';

PC_MUX_SEL <= "00";

end if;

-- BRNE -------------------

when "0010011" =>

if(z = '0') then

PC_LD <= '1';

PC_MUX_SEL <= "00";

end if;

-- CLC -------------------

when "0110000" =>

C_FLAG_CLR <= '1';

-- SEC -------------------

when "0110001" =>

C_FLAG_SET <= '1';

-- ADD reg-reg -----------

when "0000100" =>

RF_WR <= '1';

RF_OE <= '1';

RF_WR_SEL <= "00";

ALU_SEL <= "0000";

REG_IMMED_SEL <= '0';

Page 28: CPU Implemented on an Xilinix FPGA

26

C_FLAG_LD <= '1';

Z_FLAG_LD <= '1';

SHAD_C_LD <= '1';

SHAD_Z_LD <= '1';

-- ADD reg-immed ---------

when "1010000" | "1010001" | "1010010" |

"1010011" =>

RF_WR <= '1';

RF_OE <= '1';

RF_WR_SEL <= "00";

ALU_SEL <= "0000";

REG_IMMED_SEL <= '1';

C_FLAG_LD <= '1';

Z_FLAG_LD <= '1';

SHAD_C_LD <= '1';

SHAD_Z_LD <= '1';

-- ADDC reg-reg ----------

when "0000101" =>

RF_WR <= '1';

RF_OE <= '1';

RF_WR_SEL <= "00";

ALU_SEL <= "0001";

REG_IMMED_SEL <= '0';

C_FLAG_LD <= '1';

Z_FLAG_LD <= '1';

SHAD_C_LD <= '1';

SHAD_Z_LD <= '1';

-- ADDC reg-immed --------

when "1010100" | "1010101" | "1010110" |

"1010111" =>

RF_WR <= '1';

RF_OE <= '1';

RF_WR_SEL <= "00";

ALU_SEL <= "0001";

REG_IMMED_SEL <= '1';

C_FLAG_LD <= '1';

Z_FLAG_LD <= '1';

SHAD_C_LD <= '1';

SHAD_Z_LD <= '1';

-- SUB reg-reg ----------

when "0000110" =>

RF_WR <= '1';

RF_OE <= '1';

RF_WR_SEL <= "00";

ALU_SEL <= "0010";

REG_IMMED_SEL <= '0';

C_FLAG_LD <= '1';

Z_FLAG_LD <= '1';

SHAD_C_LD <= '1';

SHAD_Z_LD <= '1';

-- SUB reg-immed --------

when "1011000" | "1011001" | "1011010" |

"1011011" =>

RF_WR <= '1';

Page 29: CPU Implemented on an Xilinix FPGA

27

RF_OE <= '1';

RF_WR_SEL <= "00";

ALU_SEL <= "0010";

REG_IMMED_SEL <= '1';

C_FLAG_LD <= '1';

Z_FLAG_LD <= '1';

SHAD_C_LD <= '1';

SHAD_Z_LD <= '1';

-- SUBC reg-reg ----------

when "0000111" =>

RF_WR <= '1';

RF_OE <= '1';

RF_WR_SEL <= "00";

ALU_SEL <= "0011";

REG_IMMED_SEL <= '0';

C_FLAG_LD <= '1';

Z_FLAG_LD <= '1';

SHAD_C_LD <= '1';

SHAD_Z_LD <= '1';

-- SUBC reg-immed --------

when "1011100" | "1011101" | "1011110" |

"1011111" =>

RF_WR <= '1';

RF_OE <= '1';

RF_WR_SEL <= "00";

ALU_SEL <= "0011";

REG_IMMED_SEL <= '1';

C_FLAG_LD <= '1';

Z_FLAG_LD <= '1';

SHAD_C_LD <= '1';

SHAD_Z_LD <= '1';

-- WSP -------------------

when "0101000" =>

RF_OE <= '1';

SP_LD <= '1';

SP_MUX_SEL <= "00";

-- CMP reg-reg -----------

when "0001000" =>

RF_OE <= '1';

C_FLAG_LD <= '1';

Z_FLAG_LD <= '1';

SHAD_C_LD <= '1';

SHAD_Z_LD <= '1';

ALU_SEL <= "0100";

REG_IMMED_SEL <= '0';

-- CMP reg-immed ----------

when "1100000" | "1100001" | "1100010" |

"1100011" =>

RF_OE <= '1';

C_FLAG_LD <= '1';

Z_FLAG_LD <= '1';

SHAD_C_LD <= '1';

SHAD_Z_LD <= '1';

Page 30: CPU Implemented on an Xilinix FPGA

28

ALU_SEL <= "0100";

REG_IMMED_SEL <= '1';

-- LD reg-reg -------------

when "0001010" =>

RF_WR <= '1';

SCR_OE <= '1';

RF_WR_SEL <= "01";

SCR_ADDR_SEL <= "00";

-- LD reg-immed ----------

when "1110000" | "1110001" | "1110010" |

"1110011" =>

RF_WR <= '1';

RF_WR_SEL <= "01";

SCR_OE <= '1';

SCR_ADDR_SEL <= "01";

-- ST reg-reg ------------

when "0001011" =>

RF_OE <= '1';

SCR_WR <= '1';

SCR_ADDR_SEL <= "00";

-- ST re-immed -----------

when "1110100" | "1110101" | "1110110" |

"1110111" =>

RF_OE <= '1';

SCR_WR <= '1';

SCR_ADDR_SEL <= "01";

-- RETID ----------------

when "0110110" =>

SP_LD <= '1';

SP_MUX_SEL <= "11";

PC_LD <= '1';

PC_MUX_SEL <= "01";

SCR_OE <= '1';

SCR_ADDR_SEL <= "10";

C_FLAG_LD <= '1';

Z_FLAG_LD <= '1';

C_FLAG_SEL <= '1';

Z_FLAG_SEL <= '1';

I_FLAG_CLR <= '1';

-- RETIE ----------------

when "0110111" =>

SP_LD <= '1';

SP_MUX_SEL <= "11";

PC_LD <= '1';

PC_MUX_SEL <= "01";

SCR_OE <= '1';

SCR_ADDR_SEL <= "10";

C_FLAG_LD <= '1';

Z_FLAG_LD <= '1';

C_FLAG_SEL <= '1';

Z_FLAG_SEL <= '1';

I_FLAG_SET <= '1';

Page 31: CPU Implemented on an Xilinix FPGA

29

-- SEI -----------------

when "0110100" =>

I_FLAG_SET <= '1';

-- CLI ----------------

when "0110101" =>

I_FLAG_CLR <= '1';

-- TEST reg-reg -----------------

when "0000011" =>

RF_OE <= '1';

ALU_SEL <= "0101";

REG_IMMED_SEL <= '0';

Z_FLAG_LD <= '1';

SHAD_Z_LD <= '1';

-- TEST reg-immed ------------

when "1001100" | "1001101" | "1001110" |

"1001111" =>

RF_OE <= '1';

ALU_SEL <= "0101";

REG_IMMED_SEL <= '1';

Z_FLAG_LD <= '1';

SHAD_Z_LD <= '1';

when others =>

PC_LD <= '0'; PC_MUX_SEL <= "00"; PC_RESET <= '0'; PC_OE

<= '0'; PC_INC <= '0';

SP_LD <= '0'; SP_MUX_SEL <= "00"; SP_RESET <= '0';

RF_WR <= '0'; RF_WR_SEL <= "00"; RF_OE <= '0';

REG_IMMED_SEL <= '0'; ALU_SEL <= "0000";

SCR_WR <= '0'; SCR_OE <= '0'; SCR_ADDR_SEL <= "00";

C_FLAG_SEL <= '0'; C_FLAG_LD <= '0'; C_FLAG_SET <= '0';

C_FLAG_CLR <= '0'; SHAD_C_LD <= '0';

Z_FLAG_SEL <= '0'; Z_FLAG_LD <= '0'; Z_FLAG_SET <= '0';

Z_FLAG_CLR <= '0'; SHAD_Z_LD <= '0';

I_FLAG_SET <= '0'; I_FLAG_CLR <= '0';

IO_OE <= '0';

end case;

when ST_interrupt =>

NS <= ST_fet;

PC_LD <= '1'; PC_MUX_SEL <= "10"; PC_RESET <= '0'; PC_OE

<= '1'; PC_INC <= '1';

SP_LD <= '1'; SP_MUX_SEL <= "10"; SP_RESET <= '0';

RF_WR <= '0'; RF_WR_SEL <= "00"; RF_OE <= '0';

REG_IMMED_SEL <= '0'; ALU_SEL <= "0000";

SCR_WR <= '1'; SCR_OE <= '0'; SCR_ADDR_SEL <= "11";

C_FLAG_SEL <= '0'; C_FLAG_LD <= '0'; C_FLAG_SET <= '0';

C_FLAG_CLR <= '0'; SHAD_C_LD <= '0';

Z_FLAG_SEL <= '0'; Z_FLAG_LD <= '0'; Z_FLAG_SET <= '0';

Z_FLAG_CLR <= '0'; SHAD_Z_LD <= '0';

I_FLAG_SET <= '0'; I_FLAG_CLR <= '1';

IO_OE <= '0';

Page 32: CPU Implemented on an Xilinix FPGA

30

when others =>

NS <= ST_fet;

PC_LD <= '0'; PC_MUX_SEL <= "00"; PC_RESET <= '0'; PC_OE

<= '0'; PC_INC <= '0';

SP_LD <= '0'; SP_MUX_SEL <= "00"; SP_RESET <= '0';

RF_WR <= '0'; RF_WR_SEL <= "00"; RF_OE <= '0';

REG_IMMED_SEL <= '0'; ALU_SEL <= "0000";

SCR_WR <= '0'; SCR_OE <= '0'; SCR_ADDR_SEL <= "00";

C_FLAG_SEL <= '0'; C_FLAG_LD <= '0'; C_FLAG_SET <= '0';

C_FLAG_CLR <= '0'; SHAD_C_LD <= '0';

Z_FLAG_SEL <= '0'; Z_FLAG_LD <= '0'; Z_FLAG_SET <= '0';

Z_FLAG_CLR <= '0'; SHAD_Z_LD <= '0';

I_FLAG_SET <= '0'; I_FLAG_CLR <= '0';

IO_OE <= '0';

end case;

end process comb_p;

end Behavioral;

I Flag Code

library IEEE;

use IEEE.STD_LOGIC_1164.ALL;

entity I is

Port ( SET : in STD_LOGIC;

CLR : in STD_LOGIC;

FLAG : out STD_LOGIC);

end I;

architecture Behavioral of I is

begin

process(set, clr) is

begin

if(clr = '1')then

flag <= '0';

elsif(set = '1') then

flag <= '1';

end if;

end process;

end Behavioral;

Program Counter Code

Page 33: CPU Implemented on an Xilinix FPGA

31

library IEEE;

use IEEE.STD_LOGIC_1164.ALL;

use IEEE.STD_LOGIC_ARITH.ALL;

use IEEE.STD_LOGIC_UNSIGNED.all;

entity ProgramCounter is

Port ( D_IN : in STD_LOGIC_VECTOR (9 downto 0);

PC_OE : in STD_LOGIC;

PC_LD : in STD_LOGIC;

PC_INC : in STD_LOGIC;

RST : in STD_LOGIC;

CLK : in STD_LOGIC;

PC_COUNT : out STD_LOGIC_VECTOR (9 downto 0);

PC_TRI : out STD_LOGIC_VECTOR (9 downto 0));

end ProgramCounter;

architecture Behavioral of ProgramCounter is

signal PC_STORE : std_logic_vector(9 downto 0);

begin

synch: process(RST, CLK) is

begin

if(RST = '1') then

PC_STORE <= "0000000000";

elsif(rising_edge(CLK)) then

if(PC_LD = '1') then

PC_STORE <= D_IN;

elsif(PC_INC = '1') then

PC_STORE <= PC_STORE + 1;

end if;

end if;

end process synch;

oe : process(PC_OE, PC_STORE)is

begin

if(PC_OE = '1') then

PC_TRI <= PC_Store;

else

PC_TRI <= "ZZZZZZZZZZ";

end if;

end process oe;

PC_COUNT <= PC_STORE;

Page 34: CPU Implemented on an Xilinix FPGA

32

end Behavioral;

Program Counter Mux Code

library IEEE;

use IEEE.STD_LOGIC_1164.ALL;

entity MUX is

Port ( IN_0 : in STD_LOGIC_VECTOR (9 downto 0);

IN_1 : in STD_LOGIC_VECTOR (9 downto 0);

IN_2 : in STD_LOGIC_VECTOR (9 downto 0);

SEL : in STD_LOGIC_VECTOR (1 downto 0);

MUX_OUT : out STD_LOGIC_VECTOR (9 downto 0));

end MUX;

architecture Behavioral of MUX is

begin

With SEL select

MUX_OUT <= IN_0 when "00",

IN_1 when "01",

IN_2 when "10",

"0000000000" when others;

end Behavioral;

Plus One Module Code

library IEEE;

use IEEE.STD_LOGIC_1164.ALL;

use IEEE.STD_LOGIC_UNSIGNED.ALL;

entity Plus1 is

Port ( Input : in STD_LOGIC_VECTOR (7 downto 0);

Output : out STD_LOGIC_VECTOR (7 downto 0));

end Plus1;

architecture Behavioral of Plus1 is

begin

Output <= Input + 1;

end Behavioral;

Minus One Module

Page 35: CPU Implemented on an Xilinix FPGA

33

library IEEE;

use IEEE.STD_LOGIC_1164.ALL;

use IEEE.STD_LOGIC_UNSIGNED.ALL;

entity Minus1 is

Port ( Input : in STD_LOGIC_VECTOR (7 downto 0);

Output : out STD_LOGIC_VECTOR (7 downto 0));

end Minus1;

architecture Behavioral of Minus1 is

begin

Output <= Input - 1;

end Behavioral;

Random Number Generator Code

library IEEE;

use IEEE.STD_LOGIC_1164.ALL;

entity randnumbdecoder is

Port ( input : in STD_LOGIC_VECTOR (7 downto 0);

output : out STD_LOGIC_VECTOR (7 downto 0));

end randnumbdecoder;

architecture Behavioral of randnumbdecoder is

begin

process(input) is

begin

if(input(7 downto 4) = x"1" or input(7 downto 4) = x"2" or

input(7 downto 4)

= x"3" or input(7 downto 4) = x"4") then

output <= x"10";

elsif(input(7 downto 4) = x"5" or input(7 downto 4) = x"6" or

input(7 downto

4) = x"7" or input(7 downto 4) = x"8") then

output <= x"12";

elsif(input(7 downto 4) = x"0" or input(7 downto 4) = x"9" or

input(7 downto

4) = x"A0" or input(7 downto 4) = x"B") then

output <= x"14";

elsif(input(7 downto 4) = x"C" or input(7 downto 4) = x"D" or

input(7 downto

4) = x"E" or input(7 downto 4) = x"F") then

output <= x"16";

end if;

end process;

Page 36: CPU Implemented on an Xilinix FPGA

34

end Behavioral;

Register File Code

library IEEE;

use IEEE.STD_LOGIC_1164.ALL;

use IEEE.STD_LOGIC_UNSIGNED.ALL;

entity RegisterFile is

Port ( D_IN : in STD_LOGIC_VECTOR (7 downto 0);

DX_OUT : out STD_LOGIC_VECTOR (7 downto 0);

DY_OUT : out STD_LOGIC_VECTOR (7 downto 0);

ADRX : in STD_LOGIC_VECTOR (4 downto 0);

ADRY : in STD_LOGIC_VECTOR (4 downto 0);

DX_OE : in STD_LOGIC;

WE : in STD_LOGIC;

CLK : in STD_LOGIC);

end RegisterFile;

architecture Behavioral of RegisterFile is

TYPE memory is array (0 to 31) of std_logic_vector(7 downto

0);

SIGNAL REG: memory := (others=>(others=>'0'));

begin

process(clk)

begin

if (rising_edge(clk)) then

if (WE = '1') then

REG(conv_integer(ADRX)) <= D_IN;

end if;

end if;

end process;

DX_OUT <= REG(conv_integer(ADRX)) when DX_OE='1' else

(others=>'Z');

DY_OUT <= REG(conv_integer(ADRY));

end Behavioral;

Register File Mux Code

library IEEE;

use IEEE.STD_LOGIC_1164.ALL;

entity RegMUX is

Port ( In0 : in STD_LOGIC_VECTOR (7 downto 0);

In1 : in STD_LOGIC_VECTOR (7 downto 0);

In2 : in STD_LOGIC_VECTOR (7 downto 0);

In3 : in STD_LOGIC_VECTOR (7 downto 0);

Page 37: CPU Implemented on an Xilinix FPGA

35

Sel : in STD_LOGIC_VECTOR (1 downto 0);

Output : out STD_LOGIC_VECTOR (7 downto 0));

end RegMUX;

architecture Behavioral of RegMUX is

begin

process(sel, in0, in1, in2, in3)

begin

case sel is

when "00" => output <= in0;

when "01" => output <= in1;

when "10" => output <= in2;

when others => output <= in3;

end case;

end process;

end Behavioral;

Scratch Pad Code

library IEEE;

use IEEE.STD_LOGIC_1164.ALL;

use IEEE.STD_LOGIC_UNSIGNED.ALL;

entity ScratchPad is

Port ( SCR_ADDR : in STD_LOGIC_VECTOR (7 downto 0);

SCR_OE : in STD_LOGIC;

SCR_WE : in STD_LOGIC;

CLK : in STD_LOGIC;

SCR_DATA : inout STD_LOGIC_VECTOR (9 downto 0));

end ScratchPad;

architecture Behavioral of ScratchPad is

TYPE memory is array (0 to 255) of std_logic_vector(9 downto 0);

SIGNAL REG: memory := (others=>(others=>'0'));

begin

stuff: process(CLK, REG, SCR_WE, SCR_ADDR, SCR_DATA) is

begin

if(rising_edge(CLK))then

if(SCR_WE = '1') then

REG(conv_integer(SCR_ADDR)) <= SCR_DATA;

end if;

end if;

end process stuff;

Page 38: CPU Implemented on an Xilinix FPGA

36

tri: process(SCR_OE, SCR_ADDR, REG) is

begin

if(SCR_OE = '1') then

SCR_DATA <= REG(conv_integer(SCR_ADDR));

else

SCR_DATA <= "ZZZZZZZZZZ";

end if;

end process tri;

end Behavioral;

Seven Segment Display Decoder Code

library IEEE;

use IEEE.STD_LOGIC_1164.ALL;

entity decoder is

Port ( load : in STD_LOGIC;

portid : in STD_LOGIC_VECTOR (7 downto 0);

input : in STD_LOGIC_VECTOR (3 downto 0);

output1 : out STD_LOGIC_VECTOR (6 downto 0);

output2 : out STD_LOGIC_VECTOR (6 downto 0));

end decoder;

architecture Behavioral of decoder is

begin

process(load, portid, input) is

begin

if(load = '1') then

if( portid = x"40") then

case input is

when "0000" => output1 <= "0000001";

when "0001" => output1 <= "1001111";

when "0010" => output1 <= "0010010";

when "0011" => output1 <= "0000110";

when "0100" => output1 <= "1001100";

when "0101" => output1 <= "0100100";

when "0110" => output1 <= "1100000";

when "0111" => output1 <= "0001111";

when "1000" => output1 <= "0000000";

when "1001" => output1 <= "0001100";

when others => output1 <= "1111111";

end case;

elsif(portid = x"10") then

case input is

when "0000" => output2 <= "0000001";

Page 39: CPU Implemented on an Xilinix FPGA

37

when "0001" => output2 <= "1001111";

when "0010" => output2 <= "0010010";

when "0011" => output2 <= "0000110";

when "0100" => output2 <= "1001100";

when "0101" => output2 <= "0100100";

when "0110" => output2 <= "1100000";

when "0111" => output2 <= "0001111";

when "1000" => output2 <= "0000000";

when "1001" => output2 <= "0001100";

when others => output2 <= "1111111";

end case;

end if;

end if;

end process;

end Behavioral;

Seven Segment Display Code

library IEEE;

use IEEE.STD_LOGIC_1164.ALL;

entity displayer is

Port ( CLK : in STD_LOGIC; --CLK needs to be slow

display1 : in STD_LOGIC_VECTOR(6 downto 0);

display2 : in STD_LOGIC_VECTOR(6 downto 0);

Displayout : out STD_LOGIC_VECTOR(6 downto 0);

LED1out : out STD_LOGIC;

LED2out : out STD_LOGIC);

end displayer;

architecture Behavioral of displayer is

begin

process(CLK) is

begin

if(CLK = '1')then

LED1out <= '0';

LED2out <= '1';

displayout <= display1;

elsif(CLK = '0')then

LED1out <= '1';

LED2out <= '0';

displayout <= display2;

end if;

end process;

end Behavioral;

Page 40: CPU Implemented on an Xilinix FPGA

38

Shadow Flag Code

library IEEE;

use IEEE.STD_LOGIC_1164.ALL;

entity shadow is

Port ( input : in STD_LOGIC;

load : in STd_LOGic;

CLK : in STD_LOGIC;

output : out STD_LOGIC);

end shadow;

architecture Behavioral of shadow is

begin

process(clk, input) is

begin

if(load = '1' and rising_edge(CLK))then

output <= input;

end if;

end process;

end Behavioral;

Stack Pointer Code

library IEEE;

use IEEE.STD_LOGIC_1164.ALL;

entity SP is

Port ( Load : in STD_LOGIC;

RST : in STD_LOGIC;

CLK : in STD_LOGIC;

Input : in STD_LOGIC_VECTOR (7 downto 0);

Output : out STD_LOGIC_VECTOR (7 downto 0));

end SP;

architecture Behavioral of SP is

begin

process (RST, Load, CLK) is

begin

if(RST = '1') then

Output <= "00000000";

elsif(Load = '1' and rising_edge(CLK))then

Output <= Input;

end if;

Page 41: CPU Implemented on an Xilinix FPGA

39

end process;

end Behavioral;

Stack Pointer Mux Code

library IEEE;

use IEEE.STD_LOGIC_1164.ALL;

entity SPMUX is

Port ( In0 : in STD_LOGIC_VECTOR (7 downto 0);

In1 : in STD_LOGIC_VECTOR (7 downto 0);

In2 : in STD_LOGIC_VECTOR (7 downto 0);

In3 : in STD_LOGIC_VECTOR (7 downto 0);

SEL : in STD_LOGIC_VECTOR (1 downto 0);

Output : out STD_LOGIC_VECTOR (7 downto 0));

end SPMUX;

architecture Behavioral of SPMUX is

begin

process(Sel, in0, in1, in2, in3) is

begin

case SEL is

when "00" => output <= in0;

when "01" => output <= in1;

when "10" => output <= in2;

when others => output <= in3;

end case;

end process;

end Behavioral;

Scratch Pad Mux Code

library IEEE;

use IEEE.STD_LOGIC_1164.ALL;

entity SMUX is

Port ( In0 : in STD_LOGIC_VECTOR (7 downto 0);

In1 : in STD_LOGIC_VECTOR (7 downto 0);

In2 : in STD_LOGIC_VECTOR (7 downto 0);

In3 : in STD_LOGIC_VECTOR (7 downto 0);

SEL : in STD_LOGIC_VECTOR (1 downto 0);

Output : out STD_LOGIC_VECTOR (7 downto 0));

end SPMUX;

architecture Behavioral of SPMUX is

begin

Page 42: CPU Implemented on an Xilinix FPGA

40

process(Sel, in0, in1, in2, in3) is

begin

case SEL is

when "00" => output <= in0;

when "01" => output <= in1;

when "10" => output <= in2;

when others => output <= in3;

end case;

end process;

end Behavioral;

RAT CPU Code

library IEEE;

use IEEE.STD_LOGIC_1164.ALL;

entity RAT_CPU is

Port ( IN_PORT : in STD_LOGIC_VECTOR (7 downto 0);

RST : in STD_LOGIC;

INT_IN : in STD_LOGIC;

CLK : in STD_LOGIC;

OUT_PORT : out STD_LOGIC_VECTOR (7 downto 0);

PORT_ID : out STD_LOGIC_VECTOR (7 downto 0);

IO_OE : out STD_LOGIC);

end RAT_CPU;

architecture Behavioral of RAT_CPU is

component ControlUnit is

Port ( CLK : in STD_LOGIC;

C : in STD_LOGIC;

Z : in STD_LOGIC;

INT : in STD_LOGIC;

RST : in STD_LOGIC;

OPCODE_HI_5 : in STD_LOGIC_VECTOR (4 downto

0);

OPCODE_LO_2 : in STD_LOGIC_VECTOR (1 downto

0);

PC_LD : out STD_LOGIC;

PC_INC : out STD_LOGIC;

PC_RESET : out STD_LOGIC;

PC_OE : out STD_LOGIC;

PC_MUX_SEL : out STD_LOGIC_VECTOR (1 downto

0);

SP_LD : out STD_LOGIC;

SP_MUX_SEL : out STD_LOGIC_VECTOR (1 downto

0);

SP_RESET : out STD_LOGIC;

Page 43: CPU Implemented on an Xilinix FPGA

41

RF_WR : out STD_LOGIC;

RF_WR_SEL : out STD_LOGIC_VECTOR (1 downto

0);

RF_OE : out STD_LOGIC;

REG_IMMED_SEL : out STD_LOGIC;

ALU_SEL : out STD_LOGIC_VECTOR (3 downto

0);

SCR_WR : out STD_LOGIC;

SCR_OE : out STD_LOGIC;

SCR_ADDR_SEL : out STD_LOGIC_VECTOR (1 downto

0);

C_FLAG_SEL : out STD_LOGIC;

C_FLAG_LD : out STD_LOGIC;

C_FLAG_SET : out STD_LOGIC;

C_FLAG_CLR : out STD_LOGIC;

SHAD_C_LD : out STD_LOGIC;

Z_FLAG_SEL : out STD_LOGIC;

Z_FLAG_LD : out STD_LOGIC;

Z_FLAG_SET : out STD_LOGIC;

Z_FLAG_CLR : out STD_LOGIC;

SHAD_Z_LD : out STD_LOGIC;

I_FLAG_SET : out STD_LOGIC;

I_FLAG_CLR : out STD_LOGIC;

IO_OE : out STD_LOGIC);

end component;

component PCandMUX is

Port ( FROM_IMMED : in STD_LOGIC_VECTOR (9 downto 0);

FROM_STACK : in STD_LOGIC_VECTOR (9 downto 0);

FF : in STD_LOGIC_VECTOR (9 downto 0);

PC_MUX_SEL : in STD_LOGIC_VECTOR (1 downto 0);

PC_OE : in STD_LOGIC;

PC_LD : in STD_LOGIC;

PC_INC : in STD_LOGIC;

RST : in STD_LOGIC;

CLK : in STD_LOGIC;

PC_COUNT : out STD_LOGIC_VECTOR (9 downto 0);

PC_TRI : out STD_LOGIC_VECTOR (9 downto 0));

end component;

component prog_rom is

port ( ADDRESS : in std_logic_vector(9 downto 0);

INSTRUCTION : out std_logic_vector(17 downto 0);

CLK : in std_logic);

end component;

component RegisterFile is

Port ( D_IN : in STD_LOGIC_VECTOR (7 downto 0);

DX_OUT : out STD_LOGIC_VECTOR (7 downto 0);

DY_OUT : out STD_LOGIC_VECTOR (7 downto 0);

ADRX : in STD_LOGIC_VECTOR (4 downto 0);

ADRY : in STD_LOGIC_VECTOR (4 downto 0);

DX_OE : in STD_LOGIC;

WE : in STD_LOGIC;

Page 44: CPU Implemented on an Xilinix FPGA

42

CLK : in STD_LOGIC);

end component;

component ALU is

Port ( A : in STD_LOGIC_VECTOR (7 downto 0);

B : in STD_LOGIC_VECTOR (7 downto 0);

C_IN : in STD_LOGIC;

SEL : in STD_LOGIC_VECTOR (3 downto 0);

SUM : out STD_LOGIC_VECTOR (7 downto 0);

C_FLAG : out STD_LOGIC;

Z_FLAG : out STD_LOGIC);

end component;

component ALUMUX is

Port ( In0 : in STD_LOGIC_VECTOR (7 downto 0);

In1 : in STD_LOGIC_VECTOR (7 downto 0);

Sel : in STD_LOGIC;

Output : out STD_LOGIC_VECTOR (7 downto 0));

end component;

component RegMUX is

Port ( In0 : in STD_LOGIC_VECTOR (7 downto 0);

In1 : in STD_LOGIC_VECTOR (7 downto 0);

In2 : in STD_LOGIC_VECTOR (7 downto 0);

In3 : in STD_LOGIC_VECTOR (7 downto 0);

Sel : in STD_LOGIC_VECTOR (1 downto 0);

Output : out STD_LOGIC_VECTOR (7 downto 0));

end component;

component SP is

Port ( Load : in STD_LOGIC;

RST : in STD_LOGIC;

CLK : in STD_LOGIC;

Input : in STD_LOGIC_VECTOR (7 downto 0);

Output : out STD_LOGIC_VECTOR (7 downto 0));

end component;

component Plus1 is

Port ( Input : in STD_LOGIC_VECTOR (7 downto 0);

Output : out STD_LOGIC_VECTOR (7 downto 0));

end component;

component Minus1 is

Port ( Input : in STD_LOGIC_VECTOR (7 downto 0);

Output : out STD_LOGIC_VECTOR (7 downto 0));

end component;

component SPMUX is

Port ( In0 : in STD_LOGIC_VECTOR (7 downto 0);

In1 : in STD_LOGIC_VECTOR (7 downto 0);

In2 : in STD_LOGIC_VECTOR (7 downto 0);

In3 : in STD_LOGIC_VECTOR (7 downto 0);

SEL : in STD_LOGIC_VECTOR (1 downto 0);

Output : out STD_LOGIC_VECTOR (7 downto 0));

end component;

Page 45: CPU Implemented on an Xilinix FPGA

43

component ScratchPad is

Port ( SCR_ADDR : in STD_LOGIC_VECTOR (7 downto 0);

SCR_OE : in STD_LOGIC;

SCR_WE : in STD_LOGIC;

CLK : in STD_LOGIC;

SCR_DATA : inout STD_LOGIC_VECTOR (9 downto 0));

end component;

component C is

Port ( Input : in STD_LOGIC;

SET : in STD_LOGIC;

LoaD : in STD_LOGIC;

RST : in STD_LOGIC;

CLK : in std_Logic;

FLAG : out STD_LOGIC);

end component;

component Z is

Port ( Input : in STD_LOGIC;

SET : in STD_LOGIC;

Load : in STD_LOGIC;

RST : in STD_LOGIC;

Clk : in std_logic;

flag : out STD_LOGIC);

end component;

component I is

Port ( SET : in STD_LOGIC;

CLR : in STD_LOGIC;

FLAG : out STD_LOGIC);

end component;

component shadow is

Port ( input : in STD_LOGIC;

load : in STD_LOGIC;

CLK : in STD_LOGIC;

output : out STD_LOGIC);

end component;

component flagMUX is

Port ( in0 : in STD_LOGIC;

in1 : in STD_LOGIC;

sel : in STD_LOGIC;

output : out STD_LOGIC);

end component;

component db_1Shot is

Port ( A, CLK : in STD_LOGIC;

A_DB : out STD_LOGIC);

end component;

--ControlUnitSigs

signal S_PC_MUX_SEL, S_RF_WR_SEL, S_SP_MUX_SEL, S_SCR_ADDR_SEL :

STD_LOGIC_VECTOR(1 downto 0);

Page 46: CPU Implemented on an Xilinix FPGA

44

signal S_ALU_SEL : STD_LOGIC_VECTOR(3 downto 0);

signal S_C, S_Z, S_INT, S_RST, S_PC_LD, S_PC_INC, S_PC_RESET,

S_PC_OE, S_SP_LD, S_SP_RESET, S_RF_WR, S_RF_OE, S_REG_IMMED_SEL,

S_SCR_WR, S_SCR_OE, S_C_FLAG_LD, S_C_FLAG_SET,S_C_FLAG_CLR,

S_SHAD_C_LD, S_Z_FLAG_LD, S_Z_FLAG_SET, S_Z_FLAG_CLR,

S_SHAD_Z_LD,

S_I_FLAG_SET, S_I_FLAG_CLR, S_I_FLAG, S_C_FLAG_SEL,

S_Z_FLAG_SEL, S_IO_OE : STD_LOGIC;

--Other Connections

signal S_FROM_STACK, S_PC_to_PROGROM, S_MULT_BUS :

STD_LOGIC_VECTOR(9 downto 0);

signal S_IR : STD_LOGIC_VECTOR(17 downto 0);

signal S_REG_to_ALUMUX, S_FROM_ALU_MUX, S_SUM, S_FROM_RegMUX,

S_toSP, S_plusone, S_minusone, S_fromSP, S_toSCR :

STD_LOGIC_VECTOR(7 downto 0);

signal S_to_C_FLAG, S_to_Z_FLAG, S_shadC, S_shadZ, S_CflagIn,

S_ZflagIn, S_interrupt, S_DB : STD_LOGIC;

begin

S_interrupt <= S_DB and S_I_flag;

DB : db_1shot PORT MAP(A => INT_IN,

CLK => CLK,

A_DB => S_DB);

CU: ControlUnit PORT MAP(CLK => CLK,

C => S_C,

Z => S_Z,

INT => S_interrupt,

RST => RST,

OPCODE_HI_5 => S_IR(17 downto 13),

OPCODE_LO_2 => S_IR(1 downto 0),

PC_LD => S_PC_LD,

PC_INC => S_PC_INC,

PC_RESET => S_PC_RESET,

PC_OE => S_PC_OE,

PC_MUX_SEL => S_PC_MUX_SEL,

SP_LD => S_SP_LD,

SP_MUX_SEL => S_SP_MUX_SEL,

SP_RESET => S_SP_RESET,

RF_WR => S_RF_WR,

RF_WR_SEL => S_RF_WR_SEL,

RF_OE => S_RF_OE,

REG_IMMED_SEL=> S_REG_IMMED_SEL,

ALU_SEL => S_ALU_SEL,

SCR_WR => S_SCR_WR,

SCR_OE => S_SCR_OE,

SCR_ADDR_SEL => S_SCR_ADDR_SEL,

C_FLAG_SEL => S_C_FLAG_SEL,

C_FLAG_LD => S_C_FLAG_LD,

Page 47: CPU Implemented on an Xilinix FPGA

45

C_FLAG_SET => S_C_FLAG_SET,

C_FLAG_CLR => S_C_FLAG_CLR,

SHAD_C_LD => S_SHAD_C_LD,

Z_FLAG_SEL => S_Z_FLAG_SEL,

Z_FLAG_LD => S_Z_FLAG_LD,

Z_FLAG_SET => S_Z_FLAG_SET,

Z_FLAG_CLR => S_Z_FLAG_CLR,

SHAD_Z_LD => S_SHAD_Z_LD,

I_FLAG_SET => S_I_FLAG_SET,

I_FLAG_CLR => S_I_FLAG_CLR,

IO_OE => S_IO_OE);

PC: PCandMUX PORT MAP(FROM_IMMED => S_IR(12 downto 3),

FROM_STACK => S_MULT_BUS,

FF => "1111111111",

PC_MUX_SEL => S_PC_MUX_SEL,

PC_OE => S_PC_OE,

PC_LD => S_PC_LD,

PC_INC => S_PC_INC,

RST => S_PC_RESET,

CLK => CLK,

PC_COUNT => S_PC_to_PROGROM,

PC_TRI => S_MULT_BUS);

PR: prog_rom PORT MAP( ADDRESS => S_PC_to_PROGROM,

INSTRUCTION => S_IR,

CLK => CLK);

M1: ALUMUX PORT MAP(In0 => S_REG_TO_ALUMUX,

In1 => S_IR(7 downto 0),

Sel => S_REG_IMMED_SEL,

Output => S_FROM_ALU_MUX);

M2: RegMUX PORT MAP(In0 => S_SUM,

In1 => S_MULT_BUS(7 downto 0),

In2 => "00000000",

In3 => IN_PORT,

Sel => S_RF_WR_SEL,

Output => S_FROM_RegMUX);

RF: RegisterFile PORT MAP(D_IN => S_FROM_RegMUX,

DX_OUT => S_MULT_BUS(7 downto 0),

DY_OUT => S_REG_TO_ALUMUX,

ADRX => S_IR(12 downto 8),

ADRY => S_IR(7 downto 3),

DX_OE => S_RF_OE,

WE => S_RF_WR,

CLK => CLK);

AL: ALU PORT MAP(A => S_MULT_BUS(7 downto 0),

B => S_FROM_ALU_MUX,

C_IN => S_C,

SEL => S_ALU_SEL,

SUM => S_SUM,

Page 48: CPU Implemented on an Xilinix FPGA

46

C_FLAG => S_to_C_FLAG,

Z_FLAG => S_to_Z_FLAG);

M3: SPMUX PORT MAP(In0 => S_MULT_BUS(7 downto 0),

In1 => "00000000",

In2 => S_minusone,

In3 => S_plusone,

SEL => S_SP_MUX_SEL,

Output => S_toSP);

ST: SP PORT MAP(Load => S_SP_LD,

RST => S_SP_RESET,

CLK => CLK,

Input => S_toSP,

Output => S_fromSP);

M4: SPMUX PORT MAP(In0 => S_REG_TO_ALUMUX,

In1 => S_IR(7 downto 0),

In2 => S_fromSP,

In3 => S_minusone,

SEL => S_SCR_ADDR_SEL,

Output => S_toSCR);

Pl: Plus1 PORT MAP(Input => S_fromSP,

Output => S_plusone);

Mi: Minus1 PORT MAP(Input => S_fromSP,

output => S_minusone);

SCR: ScratchPad PORT MAP(SCR_ADDR => S_toSCR,

SCR_OE => S_SCR_OE,

SCR_WE => S_SCR_WR,

CLK => CLK,

SCR_DATA => S_MULT_BUS);

flagc : C PORT MAP(Input => S_Cflagin,

SET => S_C_FLAG_SET,

LoaD => S_C_FLAG_LD,

RST => S_C_FLAG_CLR,

clk => clk,

FLAG => S_C);

flagZ : Z PORT MAP(Input => S_Zflagin,

SET => S_Z_FLAG_SET,

LoaD => S_Z_FLAG_LD,

RST => S_Z_FLAG_CLR,

clk => clk,

FLAG => S_Z);

flagI : I PORT MAP( SET => S_I_FLAG_SET,

CLR => S_I_FLAG_CLR,

FLAG => S_I_FLAG);

shadC : Shadow PORT MAP(input => S_C,

load => S_SHAD_C_LD,

Page 49: CPU Implemented on an Xilinix FPGA

47

CLK => CLK,

output => S_shadC);

shadZ : shadow PORT MAP(input => S_C,

load => S_SHAD_Z_LD,

CLK => CLK,

output => S_shadZ);

CMux : flagMUX PORT MAP(In0 => S_to_C_FLAG,

In1 => S_shadC,

Sel => S_C_FLAG_SEL,

Output => S_CflagIn);

ZMux : flagMUX PORT MAP(In0 => S_to_Z_FLAG,

In1 => S_shadZ,

Sel => S_Z_FLAG_SEL,

Output => S_ZflagIn);

OUT_PORT <= S_MULT_BUS(7 downto 0);

PORT_ID <= S_IR(7 downto 0);

IO_OE <= S_IO_OE;

end Behavioral;

RAT Wrapper Code

library IEEE;

use IEEE.STD_LOGIC_1164.ALL;

use IEEE.STD_LOGIC_ARITH.ALL;

use IEEE.STD_LOGIC_UNSIGNED.ALL;

entity RAT_wrapper is

Port ( LEDS : out STD_LOGIC_VECTOR (3 downto 0);

display : out STD_LOGIC_VECTOR (6 downto 0);

DP : out std_logic;

SWITCHES : in STD_LOGIC_VECTOR (7 downto 0);

RST : in STD_LOGIC;

CLK : in STD_LOGIC;

ps2d, ps2c : inout std_logic;

VGA_RGB : out std_logic_vector(7 downto 0);

VGA_HS : out std_logic;

VGA_VS : out std_logic);

end RAT_wrapper;

architecture Behavioral of RAT_wrapper is

-- INPUT PORT IDS -------------------------------------------

------------

Page 50: CPU Implemented on an Xilinix FPGA

48

CONSTANT SWITCHES_ID : STD_LOGIC_VECTOR (7 downto 0) :=

X"20";

CONSTANT VGA_READ_ID : STD_LOGIC_VECTOR (7 downto 0) :=

x"93";

CONSTANT PS2_KEY_CODE_ID : STD_LOGIC_VECTOR (7 downto 0) :=

X"44";

CONSTANT PS2_STATUS_ID : STD_LOGIC_VECTOR (7 downto 0) :=

X"45";

-------------------------------------------------------------

-------------

-------------------------------------------------------------

-------------

-- OUTPUT PORT IDS ------------------------------------------

-------------

CONSTANT LEDS_ID : STD_LOGIC_VECTOR (7 downto 0) :=

X"40";

CONSTANT VGA_HADDR_ID : STD_LOGIC_VECTOR (7 downto 0) :=

x"90";

CONSTANT VGA_LADDR_ID : STD_LOGIC_VECTOR (7 downto 0) :=

x"91";

CONSTANT VGA_WRITE_ID : STD_LOGIC_VECTOR (7 downto 0) :=

x"92";

CONSTANT PS2_CONTROL_ID : STD_LOGIC_VECTOR (7 downto 0) :=

X"46";

--components ------------------------------------------------

------------

component RAT_CPU

Port ( IN_PORT : in STD_LOGIC_VECTOR (7 downto 0);

RST : in STD_LOGIC;

INT_IN : in STD_LOGIC;

CLK : in STD_LOGIC;

OUT_PORT : out STD_LOGIC_VECTOR (7 downto 0);

PORT_ID : out STD_LOGIC_VECTOR (7 downto 0);

IO_OE : out STD_LOGIC);

end component RAT_CPU;

component vgaDriverBuffer is

Port ( CLK, we : in std_logic;

wa : in std_logic_vector (10 downto

0);

wd : in std_logic_vector (7 downto

0);

Rout : out std_logic_vector (2 downto

0);

Gout : out std_logic_vector (2 downto

0);

Bout : out std_logic_vector(1 downto 0);

HS : out std_logic;

VS : out std_logic;

Page 51: CPU Implemented on an Xilinix FPGA

49

pixelData : out std_logic_vector(7 downto

0));

end component;

component displayer is

Port ( CLK : in STD_LOGIC;

display1 : in STD_LOGIC_VECTOR(6 downto 0);

display2 : in STD_LOGIC_VECTOR(6 downto 0);

Displayout : out STD_LOGIC_VECTOR(6 downto 0);

LED1out : out STD_LOGIC;

LED2out : out STD_LOGIC);

end component;

component clk_div2 is

Port ( clk : in STD_LOGIC;

sclk : out STD_LOGIC);

end component;

component decoder is

PORT ( load : in STD_LOGIC;

portid : in STD_LOGIC_VECTOR (7 downto 0);

input : in STD_LOGIC_VECTOR (3 downto 0);

output1 : out STD_LOGIC_VECTOR (6 downto 0);

output2 : out STD_LOGIC_VECTOR (6 downto 0));

end component;

component pseudo_random is

port ( clk : in std_logic;

pseudo_random_num : out std_logic_vector (7 downto

0));

end component;

component randnumbdecoder is

Port ( input : in STD_LOGIC_VECTOR (7 downto 0);

output : out STD_LOGIC_VECTOR (7 downto 0));

end component;

component PS2_REGISTER is

PORT (

PS2_DATA_READY,

PS2_ERROR : out STD_LOGIC;

PS2_KEY_CODE : out STD_LOGIC_VECTOR(7 downto

0);

PS2_CLK : inout STD_LOGIC;

PS2_DATA : in STD_LOGIC;

PS2_CLEAR_DATA_READY : in STD_LOGIC);

end component;

-------------------------------------------------------------

-------------

-- Signals for connecting RAT_CPU to RAT_wrapper ------------

-------------

signal s_input_port : std_logic_vector (7 downto 0);

Page 52: CPU Implemented on an Xilinix FPGA

50

signal s_output_port : std_logic_vector (7 downto 0);

signal s_port_id : std_logic_vector (7 downto 0);

signal s_load : std_logic;

--vga signals------------------------------------------------

-------------

signal r_vga_we : std_logic;

signal r_vga_wa : std_logic_vector(10 downto 0);

signal r_vga_wd : std_logic_vector(7 downto 0);

signal r_vgaData : std_logic_vector(7 downto 0);

-- random number/decoder ------------------------------------

signal r_LEDS, s_random, s_randin : std_logic_vector (7

downto 0);

--LED display signals ------------------------------------------

---------

signal sclk, sint_in : std_logic;

signal sLEDS1out, sLEDS2out : STD_LOGIC := '1';

signal Sdisplay1, sdisplay2 : STD_LOGIC_VECTOR(6 downto 0)

:= "0000000";

signal sintr : STD_LOGIC_VECTOR(9 downto 0);

--Keyboard signals----------------------------

signal kbd_data : std_logic_vector(7 downto 0);

signal ps2KeyCode, ps2Status, ps2ControlReg, new_ps2status :

std_logic_vector (7 downto 0);

-------------------------------------------------------------

-------------

begin

-- Instantiate RAT_CPU --------------------------------------

-------------

CPU: RAT_CPU

port map( IN_PORT => s_input_port,

OUT_PORT => s_output_port,

PORT_ID => s_port_id,

RST => RST,

IO_OE => s_load,

INT_IN => new_ps2status(1),

CLK => CLK);

-------------------------------------------------------------

-------------

PS2_DRIVER : PS2_REGISTER

port map(PS2_DATA => PS2D,

PS2_CLK => ps2c,

PS2_CLEAR_DATA_READY => ps2ControlReg(0),

PS2_KEY_CODE => ps2KeyCode,

PS2_DATA_READY => ps2Status(1),

PS2_ERROR => ps2Status(0));

------------------------------------------------------------

-------------

VGA: vgaDriverBuffer

port map(CLK => CLK,

WE => r_vga_we,

Page 53: CPU Implemented on an Xilinix FPGA

51

WA => r_vga_wa,

WD => r_vga_wd,

Rout => VGA_RGB(7 downto 5),

Gout => VGA_RGB(4 downto 2),

Bout => VGA_RGB(1 downto 0),

HS => VGA_HS,

VS => VGA_VS,

pixelData => r_vgaData);

------------------------------------------------------------

-------------

div: clk_div2 Port MAP ( clk => CLK,

sclk => sclk);

DPlayer : displayer PORT MAP(CLK => sCLK,

display1 => sdisplay1,

display2 => sdisplay2,

Displayout => display,

LED1out => sLEDs1out,

LED2out => sLEDS2out);

dec: decoder PORT MAP(load => S_load ,

portid => S_PORT_ID,

input => S_OUTPUT_PORT(3 downto 0),

output1 => sdisplay1,

output2 => sdisplay2);

LEDS <= sLEDs2out & sLEDS1out & "11";

DP <= '1';

pseud: pseudo_random port map(clk => clk,

pseudo_random_num => s_random);

rand: randnumbdecoder Port MAP( input => s_random,

output => s_randin);

--------------------------------------------------

--Keyboard bug fix-------------------------------

--------------------------------------------------

stopbug: process (ps2KeyCode, ps2Status, CLK)

begin

if(rising_edge(CLK)) then

case ps2KeyCode is

when x"F0" | x"FF" | x"15" | x"1D" | x"24" | x"1C"

| x"23" | x"1A" | x"22" | x"21" | x"6C" | x"75" | x"7D" | x"6B"

| x"74" | x"69" | x"72" | x"7A" | x"1B" | x"2B" =>

new_ps2Status <= ps2Status;

when others =>

new_ps2Status <= ps2Status(7 downto 2) & '0' &

ps2Status(0);

end case;

end if;

Page 54: CPU Implemented on an Xilinix FPGA

52

end process stopbug;

-------------------------------------------------------------

-------------

-- MUX for selecting what input to read ---------------------

-------------

-------------------------------------------------------------

-------------

inputs: process(CLK, s_port_id, s_randin, ps2KeyCode,

ps2Status, new_ps2Status, r_vgaData)

begin

if (s_port_id = SWITCHES_ID) then

s_input_port <= s_randin;

elsif (s_port_id = VGA_READ_ID) then

s_input_port <= r_vgaData;

elsif (S_port_id = PS2_KEY_CODE_ID) then

s_input_port <= ps2KeyCode;

elsif (s_port_id = PS2_STATUS_ID) then

s_input_port <= new_ps2Status;

else

s_input_port <= x"00";

end if;

end process inputs;

-------------------------------------------------------------

-------------

-------------------------------------------------------------

-------------

-- MUX for updating output registers ------------------------

-------------

-- Register updates depend on rising clock edge and asserted

load signal

-------------------------------------------------------------

-------------

outputs: process(CLK, s_load, s_port_id, s_output_port)

begin

if (rising_edge(CLK)) then

if (s_load = '1') then

-- the register definition for the LEDS

if (s_port_id = LEDS_ID) then

r_LEDS <= s_output_port;

elsif (s_port_id = PS2_CONTROL_ID) then

ps2ControlReg <= s_output_port;

elsif (S_port_id = VGA_HADDR_ID) then

r_vga_wa(10 downto 8) <= S_output_port(2 downto

0);

elsif (s_port_id = VGA_LADDR_ID) then

r_vga_wa(7 downto 0) <= S_output_port;

elsif (s_port_id = VGA_WRITE_ID) then

Page 55: CPU Implemented on an Xilinix FPGA

53

r_vga_wd <= S_output_port;

end if;

if( s_port_id = VGA_WRITE_ID ) then

r_vga_we <= '1';

else

r_vga_we <= '0';

end if;

end if;

end if;

end process outputs;

-------------------------------------------------------------

-------------

end Behavioral;

Page 56: CPU Implemented on an Xilinix FPGA

54

Appendix B

;r7 = y coord

;r8 = x coord

;r6 = color

.cseg

.org 0x10

mov r15, 0x00

mov r14, 0x93 ;delay

mov r11, 0x00

mov r12, 0x00

mov r25, 0x00

mov r19, 0xFF ;keeps track of number of notes

out r11, 0x40

out r11, 0x10

mov r27, 0x00 ;score

firstdot: SEI

add r19, 0x01

cmp r19, 0x0A ;max score

breq end

out r27,0x40

CALL erase

sub r14, 0x03 ;speed subtraction

mov r21, 0x00

Mov r7, 0x1D ;first column

mov r8, 0x10

mov r6, 0xE0

CALL drawdot

Mov r7, 0x1D ;second column

mov r8, 0x12

mov r6, 0xE0

CALL drawdot

Mov r7, 0x1D ;third column

mov r8, 0x14

mov r6, 0xE0

CALL drawdot

Mov r7, 0x1D ;fourth column

mov r8, 0x16

mov r6, 0xE0

CALL drawdot

mov r9, 0x00 ;first real dot

mov r7, 0x00

in r20, 0x20

Page 57: CPU Implemented on an Xilinix FPGA

55

mov r8, r20

cmp r8, 0x00

breq newx1

goback: mov r6, 0x0E

CALL drawdot

push r7 ;store dot

push r8

push r6

CALL delay

newline: mov r7, r9 ;erase dot

mov r8, 0x00

mov r6, 0x00

CALL draw_horiz1

add r9, 0x01

nextdots: pop r6 ;get back dot

pop r8

pop r7

add r7, 0x01 ;change dot coord

cmp r7, 0x1D ;check if it reaches bottom

breq firstdot

cmp r21, 0x01

breq going

in r20, 0x20

mov r8, r20

cmp r8, 0x00

breq newx2

going: cmp r7, 0x1A

breq setint

fromint: CALL drawdot

push r7 ;store new dot

push r8

push r6

CALL delay

brn newline ;erase dot and do again

;drawdot---------------------

drawdot: mov r4, r7

mov r5, r8

and r5, 0x3F

and r4, 0x1F

LSR r4

brcc bit7

or r5, 0x40

clc

bit7: lsr r4

brcc dout

or r5, 0x80

dout: out r5, 0x91

out r4, 0x90

out r6, 0x92

RET

;draw horz----------------------

draw_horiz1: CALL drawdot

Page 58: CPU Implemented on an Xilinix FPGA

56

ADD r8,0x01

CMP r8, 0x27

BRNE draw_horiz1

RET

;---------------------------------------------------------------

-----

;delay-------------------------

delay:

MOV R1, r14

OUTSIDE_FOR1: SUB R1, 0x01

MOV R2, r14

MIDDLE_FOR1: SUB R2, 0x01

MOV R3, r14

INSIDE_FOR1: SUB R3, 0x01

BRNE INSIDE_FOR1

OR R2, 0x00

BRNE MIDDLE_FOR1

OR R1, 0x00

BRNE OUTSIDE_FOR1

ret

;setting x values---------------------------

newx1: mov r8, 0x10 ;sometimes x coord would be zero

brn goback ; this code ensures it is at least

0x10

newx2: mov r8, 0x10

brn going

;ISR Keyboard -----------------------

ISR: cmp r25, 0x01

BRNE continue

MOV r25, 0x00 ; clear key-up flag

BRN reset_ps2_register

continue: cmp r21, 0x01

brne reset_ps2_register

IN r15, 0x44 ; get keycode data

check_1: CMP r15,0x1C ;was a pressed

BRNE check_2

CALL checkinga

BRN reset_ps2_register

check_2: CMP r15,0x1B ;was s pressed

BRNE check_3

CALL checkings

BRN reset_ps2_register

check_3: CMP r15, 0x23 ;was d pressed

BRNE check_4

CALL checkingd

Page 59: CPU Implemented on an Xilinix FPGA

57

brn reset_ps2_register

check_4: CMP r15, 0x2B ;was f pressed

brne key_up_check

call checkingf

brn reset_ps2_register

checkinga: cmp r20, 0x10 ;was a correct

brne enda

add r27, 0x01

enda: RET

checkings: cmp r20, 0x12 ;was s correct

brne ends

add r27, 0x01

ends: RET

checkingd: cmp r20, 0x14 ;was d correct

brne endd

add r27, 0x01

endd: RET

checkingf: cmp r20, 0x16 ;was f correct

brne endf

add r27, 0x01

endf: RET

;------------------------------------------

key_up_check: CMP r15,0xF0 ; look for key-up code

BREQ set_skip_flag ; branch if found

BRN reset_ps2_register

set_skip_flag: ADD r25, 0x01 ; indicate key-up found

BRN reset_ps2_register

reset_ps2_register:

MOV r30, 0x01

OUT r30, 0x46

MOV r30, 0x00

OUT r30, 0x46

RETIE

;game over/ you win---------------------------

gameover:

mov r11, 0x00

mov r12, 0x01

out r11, 0x40

out r12, 0x10

CALL erase

call delay

CALL delay

CALL delay

CALL GH

call delay

CALL delay

CALL delay

Page 60: CPU Implemented on an Xilinix FPGA

58

brn gameover

end: cmp r27, 0x0A

brne gameover

repeat:out r27, 0x40

CALL erase

mov r6, 0x0E

mov r8, 0x04

adding:add r8, 0x02

CALL exclamation

CALL delay

cmp r8, 0x22

brne adding

CALL delay

CALL delay

brn repeat

;erase the screen-----------------------------

erase: MOV r13,0x00

MOV r6, 0x00 ; r13 keeps track of rows

start: MOV r7,r13 ; load current row count

MOV r8,0x00 ; restart x coordinates

CALL draw_horiz1 ; draw a complete line

ADD r13,0x01 ; increment row count

CMP r13,0x1E ; see if more rows to draw

BRNE start ; branch to draw more rows

RET

;background text-------------------------------

GH: CALL delay

CALL delay

CALL delay

mov r7, 0x08

mov r8, 0x10

mov r6, 0xE0

CALL drawdot

add r8, 0x01

CALL drawdot

add r8, 0x01

CALL drawdot

mov r8, 0x10

add r7, 0x01

CALL drawdot

add r7, 0x01

CALl drawdot

add r7, 0x01

CALL drawdot

add r8, 0x01

CALL drawdot

add r8, 0x01

CALL drawdot

add r8, 0x01

CALL drawdot

sub r7, 0x01

Page 61: CPU Implemented on an Xilinix FPGA

59

CALL drawdot

CALL delay

CALL delay

CALL delay

add r7, 0x03

CALL drawdot

add r7, 0x01

CALL drawdot

add r7, 0x01

CALL drawdot

add r7, 0x01

CALL drawdot

add r7, 0x01

CALL drawdot

sub r7, 0x05

mov r8, 0x10

CALL drawdot

add r7, 0x01

CALL drawdot

add r7, 0x01

CALL drawdot

add r7, 0x01

CALL drawdot

add r7, 0x01

CALL drawdot

sub r7, 0x02

add r8, 0x01

CALL drawdot

add r8, 0x01

CALL drawdot

CALL delay

CALL delay

CALL delay

mov r7, 0x08

mov r8, 0x1A

CALL drawdot

add r7, 0x01

CALL drawdot

add r7, 0x01

CALL drawdot

add r7, 0x01

CALL drawdot

add r7, 0x01

CALL drawdot

mov r7, 0x0A

mov r8, 0x18

CALL drawdot

add r8, 0x01

CALL drawdot

add r8, 0x01

CALL drawdot

add r8, 0x01

CALL drawdot

add r8, 0x01

CALL drawdot

Page 62: CPU Implemented on an Xilinix FPGA

60

RET

exclamation: mov r7, 0x07

adds: add r7, 0x01

CALL drawdot

cmp r7, 0x14

brne adds

dot: mov r7, 0x16

CALL drawdot

RET

;interrupt---------------

setint: mov r21, 0x01

brn fromint

.cseg

.org 0x3FF

brn isr