You are on page 1of 32

PROJECT II

ECE 485
COMPUTER
ORGANIZATION AND
DESIGN
DESIGN AND IMPLEMENTATION OF A
MIPS CPU WITH MULTICYCLE
DATAPATH

BHUSHAN JAVAREGOWDA
A20379777

NAVANEETH GOWDA
THANDAVAMURTHY
A20378763
ABSTRACT
This report presents the design and simulation of non-pipelined multicycle version of the 32-
bit MIPS processor datapath. This design is simulated using VHDL with behavioral and
structural modelling. The processor supports a small subset of the MIPS 32-bit ISA, though
more instructions can be added to the existing design with few modifications. The processor
is designed and simulated for load word (lw), store word (sw), addition (add), conditional
branch (bne and beq) and immediate subtraction (subi). The datapath includes the PC,
Memory, Register file, ALU, MUXs for selecting the signals, Shifter, Extender, IR and other
required. Here we have used an external clock to drive the unit. The final model is tested with
a test bench program that includes the control logic for the various cycles for all the
instructions and the simulations are obtained.

1
CONTENTS

Abstract…………………………………………………………………………………….….1

Introduction…………………………………………………………………………………....3

Design………………………………………………………………….………………………4

Simulation Results…………………………………………………….……………………….8

Conclusion……………………………………………………………………………………12

Problems and Improvements…………………………………………………………………12

Appendix………………………………………………………………………………….….13

2
INTRODUCTION
A processor is the computer hardware that responds to the request made. The computation of
the data is performed in the processor and the data output is the information useful for the
users. Processor is provided with the various types of inputs which includes the real-time data
such as the number, characters or even voice. These data are not understood by the processor
and it needs to be converted to the binary and various algorithms are used to convert these
data in to binary. When a program is written in the higher-level language, it must be
converted to the binary which is performed by the compiler. The compiler converts the series
of code in to the binary that is understood by the processor by following the MIPS instruction
set.

The MIPS consists of the various instructions that are used to implement the program written
in the high-level language. In this project a processor is designed for a few instructions
mainly concentrating on the data path of the processor. The data path mainly consists of the
components such as the instruction register, memory, register file, ALU and the MUX’s. The
32-bit data path is designed where each functional unit can process data up to 32-bits.

3
DESIGN

The below figure shows the architecture of MIPS with a multicycle datapath operation.

Fig 1. Multicycle Datapath

Few modifications are made to this design in terms of simplification for supporting the
specific instructions required in the project. Here the control logic unit is not designed as the
control signals are directly fed into the test bench program.

The figure 2 shows the module of a MIPS CPU with various input and output signals. We use
an externa clock signal in the test bench to drive the model. The pcwrite signal is a control
signal which when set will update the PC value. The memaddress specifies the address
location in the memory. The memdata is the data obtained from the memory. The rewrite is a
control signal for writing into the register files. The aluop signal specifies the type of
operation to be performed in the ALU.

4
Fig 2. MIPS CPU Module

The instructions executed in this design are as shown in the below table

Opcode Function Field Instruction Operation


[31:26] [5:0]
100011 -- lw lw $t3, 300($s2)

101011 -- sw sw $t6, 400($s7)

000000 -- add add $t5, $t3, $s1

000100 100000 bne bne $s6, $t5, 200

000101 -- beq beq $s3, $t5, 100

001001 -- subi subi $t6, $s2, 27

Table 1. Core MIPS instruction set

The operation of each instruction is explained as follows

 The load word operation (lw $t3, 300($s2)) loads the content of the address specified
by the addition of 300 and s2 into register t3
 The store word operation (sw $t6, 400($s7)) stores the content of the register t6 into
address specified by the addition of 400 and s2

5
 The addition operation (add $t5, $t3, $s1) adds the contents of the registers t3 and s1
and stores the value in the register
 The branch on not equal operation (bne $s6, $t5, 200) compares s6 and t5, if they are
not equal then it jumps to the address with the offset 200
 The branch on equal operation (beq $s3, $t5, 100) compares s3 and t5, if they are
equal then it jumps to the address with the offset 100.
 The immediate subtraction operation (subi $t6, $s2, 27) subtracts the value of s2 and
27, stores the result in the register t6.

The key components in the design are briefly discussed below

ALU

ALU stands for Arithmetic and Logic Unit. An ALU is a digital electronic circuit which
performs arithmetic and bitwise logical operations on integer binary numbers that are fed into
it. ALU is the fundamental building block of many types of computing circuits which
includes the Central Processing Unit (CPU), graphics processing units and so on. The ALU
accepts two inputs called the operands on which the operation has to be performed and it has
a code which specifies the operation of the ALU and it provides a processed output which is
used further.

PC

PC stands for program counter, which is basically a 32-bit register. It contains the address of
the instruction being executed. In a sequential execution the PC is incremented to the next
instruction address to be executed. However, in branch instructions, the PC will be updated
with the address calculated using the offset and new PC if the condition is met or else the
sequential execution continues.

Memory

In the multi‐cycle implementation, the memory module is used for both data and instruction.
To be able to use one memory module for both data and instruction a multiplexor is needed to
determine whether to read the next instruction or to read a piece of data from memory. In
addition, control lines are needed to enable reading and writing. Closer inspection will show
that this can be further simplified by using the negation of either the read signal or the write
signal, thus reducing the control lines from two to one.

Register File

The register file is an array holds all the registers. The size depends on the number of
registers required. A control signal is used to specify the write or read operation to or from
the register respectively. It is of 32-bit size.

Instruction Register

The below figure 3 shows the different format of an instruction

6
Fig 3. IR formats

The first format is of aa R-type instruction and second is for I-type instruction. The IR size is
of 32 bits

For a R-type instruction, the bits from 31 down to 26 consists of the opcode and if the opcode
is 0 then it looks at the function code from 5 to 0 for the operation. The bits from 25 to 21, 20
to 16 and 15 to 11 specifies the source register rs, register rt and destination register rd. The
shamt part from 10 to 6 specifies the amount of shift to be done and in this design it is set to 0
as it won’t be used in any operation.

For an I-type instruction, the bits from 31 down to 26 consists of the opcode. The bits from
25 to 21 and 20 to 16 specifies the source register rs and register rt. The immediate data will
be at the block from 15 to 0 which is 16 bits wide.

The below table shows the IR value for the corresponding instructions.

Instruction IR
lw $t3, 300($s2) 8E4B012C
sw $t6, 400($s7) ADD70190
add $t5, $t3, $s1 01716820
bne $s6, $t5, 200 12CD00C8
beq $s3, $t5, 100 166D0064
subi $t6, $s2, 27 1327001B
Table 2. Instructions and corresponding IRs

MUXs

The model uses various MUXs like 2 to 1 MUX, 3 to 1 MUX and 4 to 1 MUX to select the
different inputs to appropriate blocks. The control signals to the MUXs to select the input are
generated from the control block which in this design is directly given by the code.

7
SIMULATION RESULTS

The processor designed for the given set of instructions is tested with the help of the test
bench coded to provide the proper signals to the design. The operation of the design is
verified by analysing the contents of the registers at the end of the simulation and comparing
it with the expected results and simulation results of the instructions is discussed.

1) lw $t3, 300($s2)
The data in the memory location obtained by the addition of the contents of s2 and
immediate 300 is stored in to the register $t3. The simulation result is as shown in the
figure below:

In the above simulation, it can be observed the 32-bit hexadecimal data:12345678 that
was present in the memory location is laded in to the register $t3 which has the number
11. Further in the figure the instruction register contents can also be verified which has
the hexadecimal representation of the instruction which is 32’h 8E4B012C.

2) sw $t6, 400($s7)
The store word instruction stores the contents of the register, $t6 in the above
implementation to the memory location specified by the sum of the contents of the
register $s7 and the immediate value 400. The simulation results of the store word (SW)
is as shown in the below figure.

8
In the above simulation, it can be clearly verified that the data at the memdata i.e.
A64B201D is stored to the data memory at the location 19A from the register $t6 and it
can also be verified from the above result that the register file contents at # 14 is also the
same data. ADD70190 is the hexadecimal representation of the instruction and is stored
in the ‘ir’.

3) add $t5, $t3, $s1

9
The instruction ADD adds the contents of the registers $t3 and $ts1 with the register
numbers 11 and 17 to the register $5 with #13. The instruction is represented in
hexadecimal as 01716820 and is stored in ir. Register contents along with the ir can be
verified in the simulation shown above.
From the above simulation, it can be analysed that the given inputs are the 0A2113811
and 123AEC18 are the input values saved in the register number 11 and 17 respectively
and the result 1C5BFF99 is stored in the #13. Since it is the addition, carry in is 0.

4) bne $s6, $t5, 200


The above instruction performs the conditional branching in which the PC will be loaded
with the new address if the contents of the registers are not equal. In the above taken
example the contents of the $s6 and $t5 are subtracted to test if the result is 0 and the
address 200+new PC will be loaded to the PC. The simulation is as shown in the below
figure:

The contents of the registers are 3216ABCD and 2CA89362 which are subtracted and the
result is 056E186B and the zero output of the ALU is 0 which shows that the value is not
equal and the branch address is updated.

5) beq $s3, $t5, 100


This is also a conditional branching in which the condition for the branch is that the
contents of the registers are to be equal and this is verified by subtracting the contents of
the registers $s3 and $ t5 with the numbers 19 and 13 respectively. The simulation is as
shown in the below figure:

10
In the simulation, it can be verified that the contents of the registers, 64AC320D,
64AC320D is saved in both the registers and the result is zero and it can be verified in the
ALU result. Since subtraction is performed the carry in is 1 and the zero output is high.

6) subi $t6, $s2, 27

11
This the subtraction immediate instruction which subtracts the contents of the $2 with the 27,
an immediate value and the result is stored in the $t6 register. The contents can be verified in
the simulation shown above.

In the above simulation, it is verified that result 036A2C02 is stored in the register #14 i.e.
$t6 which is the result of the subtraction of 036A2C1D in register #18 and immediate value
27 which is 1B in hexadecimal representation.

CONCLUSION

A 32-bit MIPS processor is designed for the given instruction set by coding all the
component required. The data path is designed to link all the components. The functioning of
the processor is tested for the given instructions using the test bench program coded. The
simulation results are compared with the expected results and the results are discussed.

PROBLEMS AND IMPROVEMENTS

The processor designed is always tested with the 32-bit data which is not in the real
implementation and also the overflow detection logic is not implemented which may lead to
error when large data is considered for arithmetic operation. Additionally, we use the same
memory for both instruction and data which may sometimes leads to failure when operating
at the same time. So the design can be enhanced by implementing these features so that a part
of real time computation is considered in the design. The design can be improved further by
implementing a logic for the control part and using separate memory blocks for instruction
and data.

12
APPENDIX

1) alu package:
--All signals lingth and the types are declared
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_bit.all;
package mips_definitions is
type reg_mem is array(0 to 31) of mips_bus;
subtype reg_bus is std_ulogic_vector(4 downto 0);
subtype reg_size is unsigned(4 downto 0);
subtype mips_bus is std_ulogic_vector(31 downto 0);
subtype immed16 is std_ulogic_vector(15 downto 0);
subtype mips_word is unsigned(31 downto 0);
type instr_type is (load, store, add, bne, ori, shrl);
constant t_clk: delay_length := 20 ns;
subtype mem_byte is std_ulogic_vector(7 downto 0);
constant mem_size: integer := 512;
type mem_table is array(0 to mem_size-1) of mem_byte;
subtype state_type is integer range 0 to 9;
subtype shamt is std_ulogic_vector(4 downto 0);
end package mips_definitions;

2) sign extension
-- sign extension design

--library declaration

library ieee;

use ieee.std_logic_1164.all;

use work.mips_definitions.all;

use ieee.numeric_bit_unsigned.all;

use ieee.numeric_std.all;

entity sign_extender is

port (a: in immed16;

b: out mips_bus;

sign: in bit);

end entity sign_extender;

13
architecture behav of sign_extender is

begin

extend: process(a, sign) is

-- a and sign is sensitvity list for the process

begin

b(15 downto 0) <= a;

if a(15) = '1' and sign = '1' then -- if the MSB of the given number is extended

b(31 downto 16) <= (others => '1');

else

b(31 downto 16) <= (others => '0');

end if;

end process extend;

end architecture behav;

3) register files
-- design of the 32 registers of 32 bit wide each

library ieee;

use ieee.std_logic_1164.all;

use ieee.numeric_bit.all;

use work.mips_definitions.all;-- the bus size is declared in this file

entity regfile is

port (clk: in std_ulogic;

write_en: in std_ulogic;

read_reg1: in reg_bus;

read_reg2: in reg_bus;

write_reg: in reg_bus;

14
write_data: in mips_bus;--32bit data

read_data1: out mips_bus;--32bit data

read_data2: out mips_bus);--32bit data

end entity regfile;

architecture behav of regfile is

signal reg_file: reg_mem;

begin

-- write is performed in the first half of the cycle

proc_write: process(clk, read_reg1, read_reg2, write_reg, write_data, write_en) is

variable initial: bit := '0';

begin

-- Initial values of registers for the operations

if initial = '0' then

reg_file(18) <= X"00000001";

reg_file(14) <= X"A64B201D";

reg_file(12) <= X"0A211381";

reg_file(17) <= X"123AEC18";

reg_file(22) <= X"3216ABCD";

reg_file(13) <= X"2CA89362";

reg_file(19) <= X"64AC320D";

initial := '1';

end if;

if rising_edge(clk) then

if write_en = '1' then

reg_file(to_integer(reg_size(to_bitvector(write_reg)))) <= write_data;

end if;

end if;

15
end process proc_write;

-- read registers

read_data1 <= reg_file(to_integer(reg_size(to_bitvector(read_reg1))));

read_data2 <= reg_file(to_integer(reg_size(to_bitvector(read_reg2))));

end architecture behav;

4) register enable send data to be added to get new PC


library ieee;

use ieee.std_logic_1164.all;

use work.mips_definitions.all;

entity reg_en is

port (clk: in std_ulogic;

write_en: in std_ulogic;

reg_in: in mips_bus;

reg_out: out mips_bus);

end entity reg_en;

architecture behav of reg_en is

signal reg_data: mips_bus;

begin

proc_reg: process(clk, write_en, reg_in) is

variable initial: bit := '0';

begin

-- Inital register value for PC to 1.

if initial = '0' then

reg_data <= X"00000001"; -- For add

initial := '1';

end if;

16
if rising_edge(clk) then

if write_en = '1' then

reg_data <= reg_in;

end if;

end if;

-- Send out the register contents

reg_out <= reg_data;

end process proc_reg;

end architecture behav;

library ieee;

use ieee.std_logic_1164.all;

use work.mips_definitions.all;

entity reg is

port (clk: in std_ulogic;

reg_out: out mips_bus;

reg_in: in mips_bus);

end entity reg;

architecture behav of reg is

begin

proc_reg: process(clk, reg_in) is

begin

if rising_edge(clk) then

reg_out <= reg_in;

end if;

end process proc_reg;

end architecture behav;

17
5) register
library ieee;

use ieee.std_logic_1164.all;

use work.mips_definitions.all;

entity reg_en is

port (clk: in std_ulogic;

write_en: in std_ulogic;

reg_in: in mips_bus;

reg_out: out mips_bus);

end entity reg_en;

architecture behav of reg_en is

signal reg_data: mips_bus;

begin

proc_reg: process(clk, write_en, reg_in) is

variable initial: bit := '0';

begin

-- Inital register value for PC to 1.

if initial = '0' then

reg_data <= X"00000001";

initial := '1';

end if;

if rising_edge(clk) then

if write_en = '1' then

reg_data <= reg_in;

end if;

end if;

-- Send out the register contents

18
reg_out <= reg_data;

end process proc_reg;

end architecture behav;

library ieee;

use ieee.std_logic_1164.all;

use work.mips_definitions.all;

entity reg is

port (clk: in std_ulogic;

reg_out: out mips_bus;

reg_in: in mips_bus);

end entity reg;

architecture behav of reg is

begin

proc_reg: process(clk, reg_in) is

begin

if rising_edge(clk) then

reg_out <= reg_in;

end if;

end process proc_reg;

end architecture behav;

6) Muxes Design
MUX_1:

--muxes in data path for selecting the inputs for proper operations

library ieee;

use ieee.std_logic_1164.all;

19
use work.mips_definitions.all;

entity mux4 is

port ( sel: in std_ulogic_vector (1 downto 0); --control signals

d0, d1, d2, d3 : in mips_bus;

z : out mips_bus);

end entity mux4;

architecture behav of mux4 is

begin

process is

begin

case sel is

when "00" =>

z <= d0;

when "01" =>

z <= d1;

when "10" =>

z <= d2;

when "11" =>

z <= d3;

when others =>

z <= (others => 'Z');

end case;

wait on sel, d0, d1, d2, d3;

end process;

end architecture behav;

library ieee;

use ieee.std_logic_1164.all;

20
use work.mips_definitions.all;

entity mux5 is

port ( sel: in std_ulogic_vector (2 downto 0);

d0, d1, d2, d3, d4, d5, d6, d7 : in mips_bus;

z : out mips_bus);

end entity mux5;

architecture behav of mux5 is

begin

process is

begin

case sel is

when "000" =>

z <= d0;

when "001" =>

z <= d1;

when "010" =>

z <= d2;

when "011" =>

z <= d3;

when "100" =>

z <= d4;

when others =>

z <= (others => 'Z');

end case;

wait on sel, d0, d1, d2, d3, d4;

end process;

end architecture behav;

21
MUX_2

library ieee;

use ieee.std_logic_1164.all;

use work.mips_definitions.all;

entity mux2 is

port ( sel : in std_ulogic;

d0, d1: in mips_bus;

z : out mips_bus);

end entity mux2;

architecture behav of mux2 is

begin

sel2: process is

begin

case sel is

when '0' =>

z <= d0;

when '1' =>

z <= d1;

when others =>

z <= (others => 'Z');

end case;

wait on sel, d0, d1;

end process;

end architecture behav;

library ieee;

22
use ieee.std_logic_1164.all;

use work.mips_definitions.all;

entity mux2_5bit is

port ( sel : in std_ulogic;

d0, d1: in reg_bus;

z : out reg_bus);

end entity mux2_5bit;

architecture behav of mux2_5bit is

begin

sel2: process is

begin

case sel is

when '0' =>

z <= d0;

when '1' =>

z <= d1;

when others =>

z <= (others => 'Z');

end case;

wait on sel, d0, d1;

end process;

end architecture behav;

7) ALU def
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_bit.all;
use work.mips_definitions.all;
package alu_definitions is
subtype alu_cntrl is std_logic_vector(3 downto 0);
constant alu_add: alu_cntrl := "0000";

23
constant alu_uadd: alu_cntrl := "0001";
constant alu_sub: alu_cntrl := "0010";
constant alu_or: alu_cntrl := "0011";
constant alu_srl: alu_cntrl := "0100";
procedure alu_op_add(a, b: in mips_word;
c_in: in bit;
result: out mips_word;
c_out: out bit;
sign_val: in bit);
end package alu_definitions;
package body alu_definitions is
procedure alu_op_add(a, b: in mips_word;
c_in: in bit;
result: out mips_word;
c_out: out bit;
sign_val: in bit) is
variable c: bit := c_in;
variable c_prev: bit;
begin
for i in mips_word'reverse_range loop
c_prev := c;
result(i) := a(i) xor b(i) xor c;
c := (a(i) and b(i)) or (c and (a(i) xor b(i)));
end loop;
if(sign_val = '0') then
c_out := c;
else
c_out := c xor c_prev;
end if;
end procedure alu_op_add;
end package body alu_definitions;

8) ALU

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use ieee.numeric_bit_unsigned.all;
use ieee.numeric_bit.all;
use work.mips_definitions.all;
use work.alu_definitions.all;
entity alu is
port (a: in mips_bus;
b: in mips_bus;

24
alu_op: in alu_cntrl;
result: out mips_bus;
carry_in: in bit;
carry_out, zero: out bit);
end entity alu;
architecture behav of alu is
begin
alu_comp: process(a, b, alu_op, carry_in) is
variable res: mips_word;
variable c_out, z: bit;
variable a_var: mips_word;
variable b_var: mips_word;
begin
res := (others => '0');
c_out := '0';
z := '0';
a_var := mips_word(to_bitvector(a));
b_var := mips_word(to_bitvector(b));
case alu_op is
when alu_add =>
alu_op_add(a_var, b_var, '0', res, c_out, '1');
when alu_uadd =>
alu_op_add(a_var, b_var, '0', res, c_out, '0');
when alu_sub =>
alu_op_add(a_var, not(b_var), '1', res, c_out, '1');
when alu_or =>
res := a_var or b_var;
when alu_srl =>
res := b_var srl to_integer(a_var(4 downto 0));
when others =>null;
end case;
if(to_integer(res) /= 0) then
z := '0';
else
z := '1';
end if;
result <= to_X01((bit_vector(res)));
carry_out <= c_out;
zero <= z;
end process alu_comp;
end architecture behav;

9) MIPS:
library ieee;

25
use ieee.std_logic_1164.all;
use ieee.numeric_bit.all;
use work.mips_definitions.all;
use work.alu_definitions.all;
entity mips is
port (clk: in std_ulogic;
-- Inputs from control
pcwrite: in std_ulogic;
iord: in std_ulogic;
memtoreg: in std_ulogic;
irwrite: in std_ulogic;
pcsource: in std_ulogic;
aluop: in alu_cntrl;
alusourceB: in std_ulogic_vector(2 downto 0);
alusourceA: in std_ulogic_vector(1 downto 0);
regwrite: in std_ulogic;
regdst: in std_ulogic;
carry_in: in bit;
-- Inputs from memory
memdata: in mips_bus;
-- Outputs to control
ir: out mips_bus;
zero: out bit;
carry_out: out bit;
-- Outputs to memory
memaddress: out mips_bus;
memwritedata: out mips_bus);
end mips;
architecture struct of mips is
component clock is
port (clk: out std_ulogic);
end component clock;
component alu is
port (a: in mips_bus;
b: in mips_bus;
alu_op: in alu_cntrl;
result: out mips_bus;
carry_in: in bit;
carry_out, zero: out bit);
end component alu;
component regfile is
port (clk: in std_ulogic;
write_en: in std_ulogic;
read_reg1: in reg_bus;

26
read_reg2: in reg_bus;
write_reg: in reg_bus;
write_data: in mips_bus;
read_data1: out mips_bus;
read_data2: out mips_bus);
end component regfile;
component reg_en is
port (clk: in std_ulogic;
write_en: in std_ulogic;
reg_in: in mips_bus;
reg_out: out mips_bus);
end component reg_en;
component reg is
port (clk: in std_ulogic;
reg_in: in mips_bus;
reg_out: out mips_bus);
end component reg;
component mux2 is
port ( sel : in std_ulogic;
d0, d1: in mips_bus;
z : out mips_bus);
end component mux2;
component mux2_5bit is
port ( sel : in std_ulogic;
d0, d1: in std_ulogic_vector(4 downto 0);
z : out std_ulogic_vector(4 downto 0));
end component mux2_5bit;
component mux4 is
port ( sel: in std_ulogic_vector (1 downto 0);
d0, d1, d2, d3 : in mips_bus;
z : out mips_bus);
end component mux4;
component mux5 is
port ( sel: in std_ulogic_vector (2 downto 0);
d0, d1, d2, d3, d4, d5, d6, d7 : in mips_bus;
z : out mips_bus);
end component mux5;
component sign_extender is
port (a: in immed16;
b: out mips_bus;
sign: in bit);
end component sign_extender;
component left_shifter is
port (a: in mips_bus;

27
b: out mips_bus);
end component left_shifter;
component shamt_extender is
port (a: in shamt;
b: out mips_bus);
end component shamt_extender;
signal pc_in, pc_out, pcmux_out, ir_out, mdr_out, mdrmux_out: mips_bus;
signal read_data1, read_data2, extender_out1, extender_out2, a_out,
b_out: mips_bus;
signal shifter_out, amux_out, bmux_out, alu_res, alu_reg_out, shamt_out:
mips_bus;
signal irmux_out: reg_bus;
signal z, c_out: bit;
begin
PCReg: reg_en port map(clk, pcwrite, pc_in, pc_out);
PCMux: mux2 port map(iord, pc_out, alu_reg_out, pcmux_out);
IRReg: reg_en port map(clk, irwrite, memdata, ir_out);
MDRReg: reg_en port map(clk, '1', memdata, mdr_out);
IRMux: mux2_5bit port map(regdst, ir_out(20 downto 16), ir_out(15 downto 11),
irmux_out);
MDRMux: mux2 port map(memtoreg, alu_reg_out, mdr_out, mdrmux_out);
Registers: regfile port map(clk, regwrite, ir_out(25 downto 21),
ir_out(20 downto 16), irmux_out, mdrmux_out, read_data1,read_data2);
SignExtender1: sign_extender port map(ir_out(15 downto 0), extender_out1,'1');
SignExtender2: sign_extender port map(ir_out(15 downto 0), extender_out2,'0');
AReg: reg_en port map(clk, '1', read_data1, a_out);
BReg: reg_en port map(clk, '1', read_data2, b_out);
Shift2: left_shifter port map(extender_out1, shifter_out);
Shamt: shamt_extender port map(ir_out(10 downto 6), shamt_out);
AMux: mux4 port map(alusourceA, pc_out, a_out, shamt_out, (others =>
'Z'), amux_out);
BMux: mux5 port map(alusourceB, b_out, X"00000001", extender_out1, shifter_out,
extender_out2,(others => 'Z'), (others => 'Z'), (others => 'Z'), bmux_out);
ALUnit: alu port map(amux_out, bmux_out, aluop, alu_res, carry_in, c_out,z);
ALUOutReg: reg port map(clk, alu_res, alu_reg_out);
BranchMux: mux2 port map(pcsource, alu_res, alu_reg_out, pc_in);
-- assign outputs
ir <= ir_out;
memwritedata <= b_out;
memaddress <= pcmux_out;
carry_out <= c_out;
zero <= z;
end architecture struct;

28
10) Memory

library ieee;
use ieee.std_logic_1164.all;
use work.mips_definitions.all;
use ieee.numeric_bit.all;
entity memory is
port (memread: in std_ulogic;
memwrite: in std_ulogic;
address: in mips_bus;
write_data: in mips_bus;
memdata: out mips_bus);
end entity memory;
architecture behav of memory is
signal mem_file0: mem_table;
signal mem_file1: mem_table;
signal mem_file2: mem_table;
signal mem_file3: mem_table;
begin
access_mem: process(memread, memwrite, address, write_data) is
variable temp: mips_word;
variable i: integer;
begin
-- Initialize memory with the first instruction to execute
-- LW $t3,300($s2)
-- 101011 00011 00010 0000000000000000
mem_file0(0) <= "10101100";
mem_file1(0) <= "01100010";
mem_file2(0) <= "00000000";
mem_file3(0) <= "00001010";
-- SW $t6,400($s7)
-- 000000 00001 00010 00100 00000 100000
mem_file0(1) <= "00000000";
mem_file1(1) <= "00100010";
mem_file2(1) <= "00100000";
mem_file3(1) <= "00100000";
-- ADD $t5, $t3, $s1
-- 000101 00010 00011 0000000000010100
-- 00010100 01000011 00000000 00010100
mem_file0(2) <= "00010100";
mem_file1(2) <= "01000011";
mem_file2(2) <= "00000000";
mem_file3(2) <= "00010100";
-- bne $s6, $t5, 200

29
-- 001101 00011 00101 1010001000110011
-- 00110100 01100101 10100010 00110011
mem_file0(3) <= "00110100";
mem_file1(3) <= "01100101";
mem_file2(3) <= "10100010";
mem_file3(3) <= "00110011";
-- beq $s3, $t5, 100
-- 100011 00011 01010 0000000000010100
-- 10001100 01101010 00000000 00010100
mem_file0(4) <= "10001100";
mem_file1(4) <= "01101010";
mem_file2(4) <= "00000000";
mem_file3(4) <= "00010100";
-- subi $t6, $s2, 27
-- 00000 00000 00001 00100 00101 000010
-- 00000000 00000001 00100001 01000010
mem_file0(5) <= "00000000";
mem_file1(5) <= "00000001";
mem_file2(5) <= "00100001";
mem_file3(5) <= "01000010";
-- Data for load at address 0x18
mem_file0(6) <= "10101011";
mem_file1(6) <= "11001101";
mem_file2(6) <= "11101111";
mem_file3(6) <= "00000000";
-- Fetch memory address
temp := mips_word(to_bitvector(address));
--temp := temp srl 2;
i := to_integer(temp);
if memwrite = '1' and memread = '0' then
mem_file0(i) <= write_data(31 downto 24);
mem_file1(i) <= write_data(23 downto 16);
mem_file2(i) <= write_data(15 downto 8);
mem_file3(i) <= write_data(7 downto 0);
elsif memwrite = '0' and memread = '1' then
memdata(31 downto 24) <= mem_file0(i);
memdata(23 downto 16) <= mem_file1(i);
memdata(15 downto 8) <= mem_file2(i);
memdata(7 downto 0) <= mem_file3(i);
else
memdata(31 downto 0) <= (others => 'Z');
end if;
end process access_mem;
end architecture behav;

30
11) Shifter
library ieee;
use ieee.std_logic_1164.all;
use work.mips_definitions.all;
use ieee.numeric_bit.all;
entity left_shifter is
port (a: in mips_bus;
b: out mips_bus);
end entity left_shifter;
architecture behav of left_shifter is
begin
left_shift: process(a) is
variable temp: mips_word;
begin
temp := mips_word(to_bitvector(a));
temp := temp sll 2;
b <= to_X01((bit_vector(temp)));
end process left_shift;
end architecture behav;

12) Clock
library ieee;
use ieee.std_logic_1164.all;
use work.mips_definitions.all;
entity clock is
port (clk: out std_ulogic);
end entity clock;
architecture behav of clock is
begin
clock: process is
variable count: integer;
begin
count := 0;
loop
clk <= '1', '0' after t_clk/2;
wait for t_clk;
count := count + 1;
exit when count = 6;
end loop;
wait;
end process clock;
end architecture behav;

31

You might also like