Documente Academic
Documente Profesional
Documente Cultură
Master of Engineering
VLSI Design Project Report
Processor
Implementation
in VHDL
According to Computer Organisation & Design
by David A. Patterson and John L. Hennessy
Author(s): M. Linder
M. Schmid
Supervisor(s): J. Färber
A. Eder
Submitted: 06/07/07
Document Revision History, Designers
Department of Electrical Engineering
Designer(s)
M. Linder michael-linder@web.de
M. Schmid martin-werner.schmid@gmx.de
Contact
Michael Linder
Angerstraße 8a
86356 Neusäß, Germany
Phone: +49 (0) 176 22 93 58 30
Mail: michael-linder@web.de
Martin Schmid
Fichtenstraße 2
86500 Kutzenhausen, Germany
Phone: +49 (0) 160 92 94 91 54
Mail: martin-werner.schmid@gmx.de
M. Linder, M. Schmid II
Contents
Department of Electrical Engineering
Contents
1 Introduction................................................................................ 1
1.1 Starting from a Simple Implementation Scheme...................................1
1.2 Using Multicycle Implementations.........................................................2
1.3 Enhancing Performance with Pipelining................................................2
2 Target Specification................................................................... 3
2.1 Building a Datapath............................................................................... 3
2.1.1 Major Components.................................................................................... 3
2.1.2 Components for Arithmetic and Logic Functions....................................... 4
2.1.3 Load word (lw) and store word (sw) instructions........................................ 5
2.1.4 Branch on equal instruction....................................................................... 6
2.1.5 Jump Instruction........................................................................................ 6
2.2 Simple Implementation Scheme............................................................7
2.2.1 Creating a Single Datapath....................................................................... 7
2.2.2 ALU Control............................................................................................... 8
2.2.3 Main Control.............................................................................................. 9
2.2.4 Disadvantages of a Single-Cycle Implementation................................... 10
2.3 Multicycle Implementation...................................................................11
2.3.1 Additions and Changes in the Scheme.................................................... 11
2.3.2 Execution of Instructions in Clock Cycles................................................ 14
2.3.3 Defining the Control by a Finite State Machine........................................ 18
3 Design Tasks............................................................................ 21
4 Module Specification............................................................... 22
4.1 ALU......................................................................................................22
4.1.1 Functional Description............................................................................. 22
4.1.2 Block Diagram......................................................................................... 23
4.1.3 Simulation Results................................................................................... 26
4.1.4 Design Files............................................................................................. 26
4.2 Memory................................................................................................27
4.2.1 Functional Description............................................................................. 27
4.2.2 Block Diagram......................................................................................... 28
4.2.3 Simulation Results................................................................................... 28
4.2.4 Design Files............................................................................................. 29
4.3 Control..................................................................................................30
4.3.1 Functional Description............................................................................. 30
4.3.2 State Diagram......................................................................................... 31
4.3.3 Block Diagram......................................................................................... 32
4.3.4 Simulation Results................................................................................... 33
4.3.5 Design Files............................................................................................. 33
4.4 Data Path.............................................................................................34
4.4.1 Instruction Fetch...................................................................................... 34
4.4.1.1 Functional Description.................................................................................... 34
4.4.1.2 Block Diagram................................................................................................ 34
4.4.1.3 Design Files.................................................................................................... 35
4.4.2 Instruction Decode.................................................................................. 35
4.4.2.1 Functional Description.................................................................................... 35
4.4.2.2 Block Diagram................................................................................................ 35
4.4.2.3 Design Files.................................................................................................... 36
4.4.3 Execution................................................................................................. 36
4.4.3.1 Functional Description.................................................................................... 36
4.4.3.2 Block Diagram................................................................................................ 37
4.4.3.3 Design Files.................................................................................................... 38
4.4.4 Memory Writeback.................................................................................. 39
4.4.4.1 Functional Description.................................................................................... 39
4.4.4.2 Block Diagram................................................................................................ 40
4.4.4.3 Design Files.................................................................................................... 41
4.4.5 Data Path................................................................................................ 42
4.4.5.1 Block Diagram................................................................................................ 42
4.4.5.2 Design Files.................................................................................................... 42
4.5 Processor and Memroy........................................................................43
4.5.1 Functional Description............................................................................. 43
4.5.2 Block Diagram......................................................................................... 43
4.5.3 Design Files............................................................................................. 44
5 Synthesis Results.................................................................... 45
6 Results of Prototype Testing.................................................. 47
6.1 Description...........................................................................................47
6.2 Simulation Result.................................................................................49
7 Conclusion................................................................................ 50
7.1 Our own experiences...........................................................................50
M. Linder, M. Schmid IV
Contents
Department of Electrical Engineering
8 Appendix................................................................................... 52
8.1 Design files..........................................................................................52
8.1.1 Project Entities........................................................................................ 52
8.1.2 Project Architectures............................................................................... 58
8.1.3 Package.................................................................................................. 79
8.1.4 Testbenches............................................................................................ 80
8.2 References...........................................................................................91
M. Linder, M. Schmid V
Contents
Department of Electrical Engineering
List of Figures
M. Linder, M. Schmid VI
Contents
Department of Electrical Engineering
List of VHDL-Source
M. Linder, M. Schmid IX
1 Introduction
Department of Electrical Engineering
1 Introduction
“The performance of software systems is dramatically affected by how well soft-
ware designers understand the basic hardware technologies at work in a sys-
tem.” According to the book “Computer Organization & Design” written by David
A. Patterson and John L. Hennessy the hardware and behaviour of a micropro-
cessor is implemented in VHDL.
In the first section starting from a simple implementation scheme of a MIPS sub-
set the basic hardware of the microcontroller´s datapath and its control is devel-
oped step by step and implemented in VHDL. Testbenches will verify the correct
implementation of the arithmetic-logical instructions (add, sub, and, or and slt),
the memory-reference instructions (load word and store word) and the branch in-
structions (beq and jump).
In order to enhance the performance and to get very fast processors another im-
plementation technique called pipelining is introduced. Multiple instructions are
overlapped in execution so that some stages are working in parallel.
2 Target Specification
At first we look at the elements required to execute the MIPS instructions and
their connection.
The first element needed is a place to store the program instructions. This In-
struction Memory is used to hold and supply instructions given an address.
The address must be kept in the Program Counter (PC), and in order to incre-
ment the PC to the address of the next instruction, we also need an Adder.
All these elements are shown in figure 2.1.
After fetching one instruction from the instruction memory, the program counter
has to be incremented so that it points to the address of the next instruction 4
bytes later.
This is realised by the datapath shown in figure 2.2.
The instructions we use all read two registers, perform an ALU operation and
write back the result.
These arithmetic-logical instructions are also called R-type instructions
([PaHe98] p. 154). This instruction class considers add, sub, slt, and and or.
The 32 registers of the processor are stored in a Register File. To read a data-
word two inputs and two outputs are needed. The inputs are 5 bits wide and
specify the register number to be read, the outputs are 32 bits wide and carry the
value of the register.
To write the result back two inputs are needed: one to specify the register num-
ber and one to supply the data to be written. The Register is shown in Figure 2.3.
Two more elements are needed to implement the sw- and lw-instructions: the
Data Memory and the Sign Extension Unit.
Figure 2.5: Data Memory and Sign extension unit [PaHe98] p. 348
The sw- and lw-instructions compute a memory address by adding a register val-
ue to the 16-bit signed offset field contained in the instruction.
Because the ALU has 32-bit values, the instruction offset field must be sign ex-
tended from 16 to 32 bits simply by concatenating the sign-bit 16 times to the
original value.
The instruction field for a lw- or sw-instruction is shown in figure 2.6:
op rs rt address
6 bits 5 bits 5 bits 16 bits
Figure 2.7: Datapath for Load Word and Store Word [PaHe98] p. 348
The beq instruction has three operands, two registers that are compared for
equality, and a 16-bit offset used to compute the branch target address relative
to the branch instruction address.
Figure 2.8 shows the datapath for a branch on equal instruction. This datapath
must do two operations: compare the register contents and compute the branch
target.
Therefore two things must be done: The address field of the branch instruction
must be sign extended from 16 bits to 32 bits and must be shifted left 2 bits so
that it is a word offset.
The branch target address is computed by adding the address of the next in-
struction (PC + 4) to the before computed offset.
The jump instruction is similar to the branch instruction, but computes the target
PC differently and not conditional.
The destination address for a jump is formed by concatenating the upper 4 bits
of the current PC + 4 to the 26-bit address field in the jump instruction (see figure
2.10 on page 8) and adding “00” as the last two bits.
The simplest possible implementation of the MISP Processor contains the datap-
ath segments explained above added by the required control lines.
The simplest datapath might attempt to execute all instructions in one clock cy-
cle. This means that any element can be used only once per instruction. So
these elements have to be duplicated.
Figure 2.9 shows the combined datapath including a memory of instructions and
one for data, the ALU, the PC-unit and the mentioned multiplexers.
The MIPS field that contains the information about the instruction has the follow-
ing structure:
op rs rt rd shamt funct
6 bits 5 bits 5 bits 5 bits 5 bits 6 bits
Figure 2.11 shows in the last column the 3-bit ALU control input.
It depends on the 6-bit funct field of the MIPS instruction and the 2-bit ALUOp
signal generated form the Main Control Unit (see Chapter 2.2.3).
Figure 2.12 shows the datapath including the ALU Control Unit.
The main control unit generates the control bits for the multiplexers, the data
memory and the ALU control unit.
The input of the main control unit is the 6-bit op-field of the MIPS instruction field
(see figure 2.9 on page 7).
Figure 2.13 shows the meaning of the several control signals.
Signal name Effect when deasserted Effect when asserted
RegDst The register destination number for the Write re- The register destination number for the Write re-
gister comes from the rt field (bits 20-16). gister comes from the rd field (bits 15-11).
RegWrite None The register on the Write register input is written
with the value on the Write data input.
ALUSrc The second ALU operand comes from the se- The second ALU operand is the sign-extended,
cond register file output (Read data 2). lower 16 bits of the instruction.
PCSrc The PC is replaced by the output of the adder The PC is replaced by the output of the adder
that computes the value of PC + 4. that computes the branch target.
MemRead None Data memory contents designated by the ad-
dress input are put on the Read data output.
MemWrite None Data memory contents designated by the ad-
dress input are replaced by the value on the Wri-
te data input.
MemtoReg The value fed to the register Write data input co- The value fed to the register Write data input co-
mes from the ALU. mes from the data memory.
The connection of the main control unit is shown in figure 2.14. This and the
meaning of the signals described in figure 2.13 leads directly to the truth table for
the main control unit shown in figure 2.15.
Figure 2.14: The simple datapath with the control unit [PaHe98] p. 360
Figure 2.15: Truth table of the main control unit [PaHe98] p. 361
Comparing to the single-cycle datapath the differences are that only one memory
unit is used for instructions and data, there is only one ALU instead of an ALU
and two adders and several output registers are added to hold the output value
of a unit until it is used in a later clock cycle.
The instruction register (IR) and the memory data register (MDR) are added to
save the output of the memory. The registers A and B hold the register operands
read form the register file and the ALUOut holds the output of the ALU.
With exception of the IR all these registers hold data only between a pair of
adjacent clock cycles.
Because the IR holds the value during the whole time of the execution of a
instruction, it requires a write control signal.
The reduction from former three ALUs to one causes also the following changes
in the datapath:
An additional multiplexer is added for the first ALU input to choose between the
A register and the PC.
The multiplexer at the second ALU input is changed from a two-way to a four-
way multiplexer. The two new inputs are a constant 4 to increment the PC and
the sign-extended and shifted offset field for the branch instruction.
In order to handle branches and jumps more additions in the datapath are
required.
The three cases of R-type instructions, branch instruction and jump instruction
cause three different values to be written into the PC:
• The output of the ALU which is PC + 4 should be stored directly to the PC.
• The register ALUOut after computing the branch target address.
• The lower 26 bits of the IR shifted left by two and concatenated with the
upper 4 bits of the incremented PC, when the instruction is jump.
If the instruction is branch, the write signal for the PC is conditional. Only if the
the two compared registers are equal, the computed branch address has to be
written to the PC.
Therefore the PC needs two write signals, which are PCWrite if the write is
unconditional (value is PC + 4 or jump instruction) and PCWriteCond if the write
is conditional.
The execution of an instruction is broken into clock cycles, that means that each
instruction is divided into a series of steps.
Therefore the setting of the control signals are shown in figures 2.18 and 2.19.
2. Arithmetic-logical instruction:
ALUOut = A op B
3. Branch:
if (A == B) PC = ALUOut
4. Jump:
PC = PC[31-28] & (IR[25-0] << 2)
or
Memory [ALUOut] = B
2. Arithmetic-logical instruction:
Reg[IR[15-11]] = ALUOut
Step name Action for R-type Action for memory- Action for Action for
instructions reference instructions branches jumps
Instruction fetch IR = Memory[PC]
PC = PC + 4
Instruction decode A = Reg[IR[25-21]]
register fetch B = Reg[IR[20-16]]
ALUOut = PC + (sign-extend(IR[15-0] << 2)
Execution, address ALUOut = A op B ALUOut = A + sign-extend if (A == B) then PC = PC[31-28] ||
computation, (IR[15-0]) PC = ALUOut (IR[25-0] << 2)
branch/jump completi-
on
Memory access or R- Reg[IR[15-11]] = Load: MDR = Memory[ALUOut]
type completion ALUOut or
Store: Memory[ALUOut] = B
Memory read comple- Load: Reg[IR[20-16]] = MDR
tion
In the single step implementation the control was defined by simple truth tables
that set the control signals depending on the instruction.
This does not work for a mulitcycle datapath.
The control is more complex, because it must specify both the signals to be set
in any step and the next step in the sequence.
Therefore a finite state machine is used.
Figure 2.21 shows the finite state machine for the control of the multicycle
datapath implementation.
All unused signals have to be deasserted or keep their value during the next
states until they are set again.
3 Design Tasks
• Block Diagram of first hierarchy levels
• Prototype Testing
• Milestone Presentations
Object Description
toplevel Root directory for a VHDL design project
toplevel/src directory for VHDL source code
toplevel/work directory for VHDL working library, contains compiled object code of
ModelSim VHDL compiler
toplevel/simulation simulation results
toplevel/stimuli stimuli files of extended simulation runs should be stored in
this directory
toplevel/pnr data produced after a place&route run can be found in this directory
toplevel/scripts scriptfiles for automated batch processing of the design steps
should be placed here
toplevel/log log files of the different design steps
toplevel/doc directory for project documentation, data sheets, etc.
4 Module Specification
4.1 ALU
The arithmetic-logic unit (ALU) performs basic arithmetic and logic operations
which are controlled by the opcode. The result of the instruction is written to the
output. An additional zero-bit signalizes an high output if the result equals zero.
At the present time, the basic arithmetic operations add and sub and the logic
operations and, or and slt can be applied to inputs. The inputs are 32 bit wide
with type unsigned. A detection of overflow or borrow is not supported at the mo-
ment.
4.2 Memory
Data is synchronously written to or read from the memory with a data bus width
of 32 bit. The memory consists of four ram blocks with 8 bit data width each.
A control signal enables the memory to be written, otherwise data is only read. In
order to store data to the memory the data word is subdivided into four bytes
which are separately written to the ram blocks. Vice versa, the single bytes are
concatenated to get the data word back again.
At the moment, it is only possible to read and write data words. An addressing of
half-words or single bytes is not allowed. In order to write or read data words, all
ram blocks have to be selected. Hence, the lowest two bit are not examined for
chip-select logic.
In order to get an unregistered memory output, another ram block was defined in
VHDL code (a_ram_rtl.vhd). There, the output directly yields the data being ad-
dressed by the unregistered input address. Unfortunately, the synthesizer does
not support memory initialisation files in the RTL-code for setting data to the
memory. Hence, it was not possible to implement the memory in real hardware.
Figure 4.6 shows the simulation results with registered data output.
Figure 4.7 shows the simulation results with unregistered output. Note that the
simulation contains unknown values, because the memory initialisation files are
not supported.
4.3 Control
The input to the State Machine are the upper 6 bits of the function field contain-
ing the instruction.
The outputs of the state machine are the control signals of the single functional
units of the processor implementation especially the multiplexers of the datapath.
The Operation Code of the ALU is stored in a truth table and the corresponding
Opcode is produced depending on the ALUOp signal of the state machine and
the lower 6 bits of the function field containing the information which of the arith-
metic or logic instruction is to use.
ErrorState
The datapath is divided into four sections with respect to the pipelining structure
of a processor. The four parts are the Instruction Fetch, Instruction Decode, Exe-
cution and Memory Writeback.
These sections are synthesized of their own and then combined to the Data
Block.
The Instruction Fetch Block contains the PC the Instruction Register and the
Memory Data Register.
This part provides the data and instruction form the memory.
The Instruction Decode Block writes the instruction of the Instruction Register to
the Register File and computes the second operand for a Branch Instruction or a
sw- or lw-instruction.
4.4.3 Execution
The Execution contains the ALU as main element and computes the desired re-
sult of the instruction.
It also computes the jump target address and provides it for the Memory Write-
back Block.
The operands loaded to the ALU are chosen by two multiplexers which are sen-
sible to the signals ALUSrcA and ALUSrcB.
The Memory Writeback Block consists of the ALUOut register and a multiplexer
with source signal PCSource.
This block leads the result of the computation either back to memory or to the
register file.
The multiplexer leads back the next PC value depending on the PCSource sig-
nal.
The both parts Datapath and Controlpath are combined to the processing unit.
Together with the Memory the whole processor is completed.
5 Synthesis Results
+------------------------------------------------------------------------------+
; Analysis & Synthesis Summary ;
+------------------------------------+-----------------------------------------+
; Analysis & Synthesis Status ; Successful - Thu Jul 05 11:15:33 2007 ;
; Quartus II Version ; 7.0 Build 33 02/05/2007 SJ Full Version ;
; Revision Name ; procmem ;
; Top-level Entity Name ; procmem ;
; Family ; Cyclone II ;
; Total logic elements ; 0 ;
; Total combinational functions ; 0 ;
; Dedicated logic registers ; 0 ;
; Total registers ; 0 ;
; Total pins ; 2 ;
; Total virtual pins ; 0 ;
; Total memory bits ; 0 ;
; Embedded Multiplier 9-bit elements ; 0 ;
; Total PLLs ; 0 ;
+------------------------------------+-----------------------------------------+
+--------------------------------------------------------------------------------------------------------------+
; Analysis & Synthesis Settings ;
+--------------------------------------------------------------------+--------------------+--------------------+
; Option ; Setting ; Default Value ;
+--------------------------------------------------------------------+--------------------+--------------------+
; Device ; EP2C20F484C7 ; ;
; Top-level entity name ; procmem ; procmem ;
; Family name ; Cyclone II ; Stratix ;
; Restructure Multiplexers ; Auto ; Auto ;
; Create Debugging Nodes for IP Cores ; Off ; Off ;
; Preserve fewer node names ; On ; On ;
; Disable OpenCore Plus hardware evaluation ; Off ; Off ;
; Verilog Version ; Verilog_2001 ; Verilog_2001 ;
; VHDL Version ; VHDL93 ; VHDL93 ;
; State Machine Processing ; Auto ; Auto ;
; Safe State Machine ; Off ; Off ;
; Extract Verilog State Machines ; On ; On ;
; Extract VHDL State Machines ; On ; On ;
; Ignore Verilog initial constructs ; Off ; Off ;
; Add Pass-Through Logic to Inferred RAMs ; On ; On ;
; DSP Block Balancing ; Auto ; Auto ;
; NOT Gate Push-Back ; On ; On ;
; Power-Up Don't Care ; On ; On ;
; Remove Redundant Logic Cells ; Off ; Off ;
; Remove Duplicate Registers ; On ; On ;
; Ignore CARRY Buffers ; Off ; Off ;
; Ignore CASCADE Buffers ; Off ; Off ;
; Ignore GLOBAL Buffers ; Off ; Off ;
; Ignore ROW GLOBAL Buffers ; Off ; Off ;
; Ignore LCELL Buffers ; Off ; Off ;
; Ignore SOFT Buffers ; On ; On ;
; Limit AHDL Integers to 32 Bits ; Off ; Off ;
; Optimization Technique -- Cyclone II ; Balanced ; Balanced ;
; Carry Chain Length -- Stratix/Stratix GX/Cyclone/MAX II/Cyclone II ; 70 ; 70 ;
; Auto Carry Chains ; On ; On ;
; Auto Open-Drain Pins ; On ; On ;
; Perform WYSIWYG Primitive Resynthesis ; Off ; Off ;
; Perform gate-level register retiming ; Off ; Off ;
; Allow register retiming to trade off Tsu/Tco with Fmax ; On ; On ;
; Auto ROM Replacement ; On ; On ;
; Auto RAM Replacement ; On ; On ;
; Auto Shift Register Replacement ; On ; On ;
; Auto Clock Enable Replacement ; On ; On ;
; Allow Synchronous Control Signals ; On ; On ;
; Force Use of Synchronous Clear Signals ; Off ; Off ;
; Auto RAM to Logic Cell Conversion ; Off ; Off ;
; Auto Resource Sharing ; Off ; Off ;
; Allow Any RAM Size For Recognition ; Off ; Off ;
; Allow Any ROM Size For Recognition ; Off ; Off ;
; Allow Any Shift Register Size For Recognition ; Off ; Off ;
; Ignore translate_off and synthesis_off directives ; Off ; Off ;
; Show Parameter Settings Tables in Synthesis Report ; On ; On ;
; Ignore Maximum Fan-Out Assignments ; Off ; Off ;
+-----------------------------------------------------+
; Compilation Hierarchy ;
+-----------------------------------------------------+
; |procmem ;
; |mips ;
; |control:inst_control| ;
; |ALUControl:inst_ALUControl| ;
; |ControlFSM:inst_ControlFSM| ;
; |data:inst_data| ;
; |data_decode:inst_data_decode| ;
; |regfile:inst_regfile| ;
; |tempreg:A| ;
; |tempreg:B| ;
; |data_execution:inst_data_execution| ;
; |alu:alu_inst| ;
; |data_fetch:inst_data_fetch| ;
; |instreg:instr_reg| ;
; |pc:proc_cnt| ;
; |tempreg:mem_data_reg| ;
; |data_memwriteback:inst_data_memwriteback| ;
; |tempreg:tempreg_inst| ;
; |memory ;
; |ram:mem_block0| ;
; |altsyncram:ram_block_rtl_0| ;
; |altsyncram_ia61:auto_generated| ;
; |ram:mem_block1| ;
; |altsyncram:ram_block_rtl_1| ;
; |altsyncram_ia61:auto_generated| ;
; |ram:mem_block2| ;
; |altsyncram:ram_block_rtl_2| ;
; |altsyncram_ia61:auto_generated| ;
; |ram:mem_block3| ;
; |altsyncram:ram_block_rtl_3| ;
; |altsyncram_ia61:auto_generated| ;
+-----------------------------------------------------+
6.1 Description
For the first test of the completed processor and the memory a simple addition of
two numbers was done.
Therefore at first the memory has to be loaded with the instructions and data by
using *.mif-files to write the information into the memory blocks before starting
the simulation.
Memory
Address Data (dec) Data (bin)
128 379 00000000 00000000 00000001 01111011
132 383 00000000 00000000 00000001 01111111
Memory
Address Data (dec) Data (bin)
136 762 00000000 00000000 00000010 11111010
140 4 00000000 00000000 00000000 00000100
144 379 00000000 00000000 00000001 01111011
148 383 00000000 00000000 00000001 01111111
152 1 00000000 00000000 00000000 00000001
The simulation starts at memory address 000 with a load word instruction. The
value of memory address 128 is written into register $s0. The PC is incremented
and the next instruction of memory address 004 is executed. It is also an load
word instruction which loads the value of memory address 132 to register $s1.
Then an add instruction follows which adds the two operands written into the reg-
isters $s0 and $s1 and writes the result to register $s2.
Then a store word instruction writes the content of register $s2 to the memory at
address 136.
The following instructions are for subtract, add, or, slt, beq and jump. The result
of a computation is always stored to the memory by a store word instruction.
Note:
For description of the register numbers and names used for the test see Figure
3.13 of [PaHe98] p. 140.
The used assembler instructions are not completely declared in this report.
For information on the machine language see [PaHe98] Chapter 3, especially fig-
ure 3.14 on page 141.
7 Conclusion
Since the design of our MIPS processor is closely connected to the literature
[PaHe98], we read the chapter 5 in detail. Overall, we adjusted the design as
conform as possible to the description in [PaHe98]. There are some passages
which do not provide a full description, e.g. the output signals of the control FSM
are not listed completely for each state. Nevertheless, “Computer Organization &
Design” by Patterson and Hennessy provides a brilliant composition describing
the control and datapath of a processor implementation.
Although we spent much more time than scheduled, we did not reach all our
aims. For further work on the project, we recommend our successors to continue
the following tasks:
– Verify the synthesis results (with VHDL code created by Quartus) with desired
behavior implemented in RTL and seen in testbench simulation in order to
obtain the desired unregistered memory output mentioned in chapter 4.2.
8 Appendix
LIBRARY IEEE;
USE IEEE.std_logic_1164.ALL;
ENTITY ControlFSM IS
PORT (clk, rst_n : IN std_ulogic;
instr_31_26 : IN std_ulogic_vector(5 downto 0);
RegDst, RegWrite, ALUSrcA, MemRead, MemWrite, MemtoReg, IorD, IRWrite, PCWrite,
PCWriteCond : OUT std_ulogic;
ALUOp, ALUSrcB, PCSource : OUT std_ulogic_vector(1 downto 0)
);
END ControlFSM;
VHDLSource 8.1: e_control_ControlFSM.vhd
LIBRARY IEEE;
USE IEEE.std_logic_1164.ALL;
ENTITY ALUControl IS
PORT (instr_15_0 : IN std_ulogic_vector(15 downto 0);
ALUOp : IN std_ulogic_vector(1 downto 0);
ALUopcode : OUT std_ulogic_vector(2 downto 0)
);
END ALUControl;
VHDLSource 8.2: e_control_ALUControl.vhd
LIBRARY IEEE;
USE IEEE.std_logic_1164.ALL;
ENTITY control IS
PORT (clk, rst_n : IN std_ulogic;
instr_31_26 : IN std_ulogic_vector(5 downto 0);
instr_15_0 : IN std_ulogic_vector(15 downto 0);
zero : IN std_ulogic;
ALUopcode : OUT std_ulogic_vector(2 downto 0);
RegDst, RegWrite, ALUSrcA, MemRead, MemWrite, MemtoReg, IorD, IRWrite : OUT
std_ulogic;
ALUSrcB, PCSource : OUT std_ulogic_vector(1 downto 0);
PC_en : OUT std_ulogic
);
END control
VHDLSource 8.3: e_control.vhd
LIBRARY IEEE;
USE IEEE.std_logic_1164.ALL;
USE IEEE.numeric_std.ALL;
-- use package
USE work.procmem_definitions.ALL;
ENTITY tempreg IS
PORT (
clk : IN STD_ULOGIC;
rst_n : IN STD_ULOGIC;
END tempreg
VHDLSource 8.4: e_tempreg.vhd
LIBRARY IEEE;
USE IEEE.std_logic_1164.ALL;
USE IEEE.numeric_std.ALL;
-- use package
USE work.procmem_definitions.ALL;
ENTITY pc IS
PORT (
clk : IN STD_ULOGIC;
rst_n : IN STD_ULOGIC;
pc_in : IN STD_ULOGIC_VECTOR(width-1 DOWNTO 0);
PC_en : IN STD_ULOGIC;
pc_out : OUT STD_ULOGIC_VECTOR(width-1 DOWNTO 0) );
END pc;
VHDLSource 8.5: e_pc.vhd
LIBRARY IEEE;
USE IEEE.std_logic_1164.ALL;
USE IEEE.numeric_std.ALL;
-- use package
USE work.procmem_definitions.ALL;
ENTITY instreg IS
PORT (
clk : IN STD_ULOGIC;
rst_n : IN STD_ULOGIC;
memdata : IN STD_ULOGIC_VECTOR(width-1 DOWNTO 0);
IRWrite : IN STD_ULOGIC;
END instreg;
VHDLSource 8.6: e_instreg.vhd
LIBRARY IEEE;
USE IEEE.std_logic_1164.ALL;
-- use package
USE work.procmem_definitions.ALL;
ENTITY regfile IS
PORT (clk,rst_n : IN std_ulogic;
wen : IN std_ulogic; -- write control
writeport : IN std_ulogic_vector(width-1 DOWNTO 0); -- register input
adrwport : IN std_ulogic_vector(regfile_adrsize-1 DOWNTO 0);-- address write
adrport0 : IN std_ulogic_vector(regfile_adrsize-1 DOWNTO 0);-- address port 0
adrport1 : IN std_ulogic_vector(regfile_adrsize-1 DOWNTO 0);-- address port 1
readport0 : OUT std_ulogic_vector(width-1 DOWNTO 0); -- output port 0
readport1 : OUT std_ulogic_vector(width-1 DOWNTO 0) -- output port 1
);
END regfile;
VHDLSource 8.7: e_regfile.vhd
LIBRARY IEEE;
USE IEEE.std_logic_1164.ALL;
USE IEEE.numeric_std.ALL;
-- use package
USE work.procmem_definitions.ALL;
ENTITY alu IS
PORT (
a, b : IN STD_ULOGIC_VECTOR(width-1 DOWNTO 0);
opcode : IN STD_ULOGIC_VECTOR(2 DOWNTO 0);
LIBRARY IEEE;
USE IEEE.std_logic_1164.ALL;
USE IEEE.numeric_std.ALL;
-- use package
USE work.procmem_definitions.ALL;
ENTITY data_fetch IS
PORT (
-- inputs
clk : IN STD_ULOGIC;
rst_n : IN STD_ULOGIC;
pc_in : IN STD_ULOGIC_VECTOR(width-1 DOWNTO 0);
alu_out : IN STD_ULOGIC_VECTOR(width-1 DOWNTO 0);
mem_data : IN std_ulogic_vector(width-1 DOWNTO 0);
-- control signals
PC_en : IN STD_ULOGIC;
IorD : IN STD_ULOGIC;
IRWrite : IN STD_ULOGIC;
-- outputs
reg_memdata : OUT STD_ULOGIC_VECTOR(width-1 DOWNTO 0);
instr_31_26 : OUT STD_ULOGIC_VECTOR(5 DOWNTO 0);
instr_25_21 : OUT STD_ULOGIC_VECTOR(4 DOWNTO 0);
instr_20_16 : OUT STD_ULOGIC_VECTOR(4 DOWNTO 0);
instr_15_0 : OUT STD_ULOGIC_VECTOR(15 DOWNTO 0);
mem_address : OUT std_ulogic_vector(width-1 DOWNTO 0);
pc_out : OUT std_ulogic_vector(width-1 DOWNTO 0)
);
END data_fetch;
VHDLSource 8.9: e_data_fetch.vhd
LIBRARY IEEE;
USE IEEE.std_logic_1164.ALL;
USE IEEE.numeric_std.ALL;
-- use package
USE work.procmem_definitions.ALL;
ENTITY data_decode IS
PORT (
-- inputs
clk : IN STD_ULOGIC;
rst_n : IN STD_ULOGIC;
instr_25_21 : IN STD_ULOGIC_VECTOR(4 DOWNTO 0);
instr_20_16 : IN STD_ULOGIC_VECTOR(4 DOWNTO 0);
instr_15_0 : IN STD_ULOGIC_VECTOR(15 DOWNTO 0);
reg_memdata : IN STD_ULOGIC_VECTOR(width-1 DOWNTO 0);
alu_out : IN STD_ULOGIC_VECTOR(width-1 DOWNTO 0);
-- control signals
RegDst : IN STD_ULOGIC;
RegWrite : IN STD_ULOGIC;
MemtoReg : IN STD_ULOGIC;
-- outputs
reg_A : OUT STD_ULOGIC_VECTOR(width-1 DOWNTO 0);
reg_B : OUT STD_ULOGIC_VECTOR(width-1 DOWNTO 0);
instr_15_0_se : OUT STD_ULOGIC_VECTOR(width-1 DOWNTO 0);
instr_15_0_se_sl : OUT STD_ULOGIC_VECTOR(width-1 DOWNTO 0)
);
END data_decode;
VHDLSource 8.10: e_data_decode.vhd
LIBRARY IEEE;
USE IEEE.std_logic_1164.ALL;
USE IEEE.numeric_std.ALL;
-- use package
USE work.procmem_definitions.ALL;
ENTITY data_execution IS
PORT (instr_25_21 : IN std_ulogic_vector(4 downto 0);
instr_20_16 : IN std_ulogic_vector(4 downto 0);
instr_15_0 : IN std_ulogic_vector(15 downto 0);
ALUSrcA : IN std_ulogic;
ALUSrcB : IN std_ulogic_vector(1 downto 0);
ALUopcode : IN std_ulogic_vector(2 downto 0);
reg_A, reg_B : IN std_ulogic_vector(width-1 downto 0);
pc_out : IN std_ulogic_vector(width-1 downto 0);
instr_15_0_se : IN std_ulogic_vector(width-1 downto 0);
instr_15_0_se_sl : IN std_ulogic_vector(width-1 downto 0);
LIBRARY IEEE;
USE IEEE.std_logic_1164.ALL;
USE IEEE.numeric_std.ALL;
-- use package
USE work.procmem_definitions.ALL;
ENTITY data_memwriteback IS
PORT (clk, rst_n : IN std_ulogic;
jump_addr : IN std_ulogic_vector(width-1 downto 0);
alu_result : IN std_ulogic_vector(width-1 downto 0);
PCSource : IN std_ulogic_vector(1 downto 0);
LIBRARY IEEE;
USE IEEE.std_logic_1164.ALL;
USE IEEE.numeric_std.ALL;
-- use package
USE work.procmem_definitions.ALL;
ENTITY data IS
LIBRARY IEEE;
USE IEEE.std_logic_1164.ALL;
-- use altera_mf library for RAM block
LIBRARY altera_mf;
USE altera_mf.ALL;
-- use package
USE work.procmem_definitions.ALL;
ENTITY ram IS
GENERIC (adrwidth : positive := ram_adrwidth;
datwidth : positive := ram_datwidth;
ramfile : string := ramfile_std -- initial RAM content
-- in IntelHEX Format
);
PORT (address : IN std_logic_vector(ram_adrwidth-1 DOWNTO 0);
data : IN std_logic_vector(ram_datwidth-1 DOWNTO 0);
inclock : IN std_logic; -- used to write data in RAM cells
wren_p : IN std_logic;
q : OUT std_logic_vector(ram_datwidth-1 DOWNTO 0));
END ram;
VHDLSource 8.14: e_ram.vhd
LIBRARY IEEE;
USE IEEE.std_logic_1164.ALL;
USE IEEE.numeric_std.ALL;
-- use package
USE work.procmem_definitions.ALL;
ENTITY memory IS
PORT (
clk : IN STD_ULOGIC;
rst_n : IN STD_ULOGIC;
MemRead : IN STD_ULOGIC;
MemWrite : IN STD_ULOGIC;
mem_address : IN STD_ULOGIC_VECTOR(width-1 DOWNTO 0);
data_in : IN STD_ULOGIC_VECTOR(width-1 DOWNTO 0);
data_out : OUT STD_ULOGIC_VECTOR(width-1 DOWNTO 0) );
END memory;
VHDLSource 8.15: e_memory.vhd
LIBRARY IEEE;
USE IEEE.std_logic_1164.ALL;
USE IEEE.numeric_std.ALL;
-- use package
USE work.procmem_definitions.ALL;
ENTITY mips IS
PORT (clk, rst_n : IN std_ulogic;
mem_data : IN std_ulogic_vector(width-1 downto 0);
LIBRARY IEEE;
USE IEEE.std_logic_1164.ALL;
USE IEEE.numeric_std.ALL;
-- use package
USE work.procmem_definitions.ALL;
ENTITY procmem IS
PORT (clk, rst_n : IN std_ulogic
);
END procmem;
VHDLSource 8.17: e_procmem.vhd
LIBRARY IEEE;
USE IEEE.std_logic_1164.ALL;
-------------------------------------------------------------------------------
-- Definition of the state names
TYPE state_type IS (InstDec, MemAddComp, MemAccL, MemReadCompl, MemAccS, Exec, RCom-
pl, BranchCompl, JumpCompl, ErrState, InstFetch);
SIGNAL state, next_state : state_type;
BEGIN
-------------------------------------------------------------------------------
-- State process
state_reg : PROCESS(clk, rst_n)
BEGIN
IF rst_n = '0' THEN
state <= InstFetch;
ELSIF RISING_EDGE(clk) THEN
state <= next_state;
END IF;
END PROCESS;
-------------------------------------------------------------------------------
-- Logic Process
logic_process : PROCESS(state, instr_31_26)
-- RegDst RegWrite ALUSrcA MemRead MemWrite MemtoReg IorD IRWrite PCWrite PCWriteCond
10x1bit
-- ALUOp ALUSrcB PCSource
3x2bit
VARIABLE control_signals : std_ulogic_vector(15 downto 0);
BEGIN
CASE state IS
-- Instruction Fetch
WHEN InstFetch =>
control_signals := "0001000110000100";
-- Execution
WHEN Exec =>
control_signals := "0010000000100000";
-- R-type Completion
WHEN RCompl =>
control_signals := "1110000000100000";
-- Branch Completion
WHEN BranchCompl =>
control_signals := "0010000001010001";
-- Jump Completion
WHEN JumpCompl =>
control_signals := "0000000010001110";
END process;
END behave;
VHDLSource 8.18: a_control_ControlFSM.vhd
LIBRARY IEEE;
USE IEEE.std_logic_1164.ALL;
BEGIN
BEGIN
case ALUOp is
when "00" => ALUopcode <= "010"; -- add
when "01" => ALUopcode <= "110"; -- subtract
when "10" => -- operation depends on function field
case instr_15_0(5 downto 0) is
when cADD => ALUopcode <= "010"; -- add
when cSUB => ALUopcode <= "110"; -- subtract
when cAND => ALUopcode <= "000"; -- AND
when cOR => ALUopcode <= "001"; -- OR
when cSLT => ALUopcode <= "111"; -- slt
when others => ALUopcode <= "000";
end case;
when others => ALUopcode <= "000";
end case;
END PROCESS;
END behave;
VHDLSource 8.19: a_control_ALUControl.vhd
LIBRARY IEEE;
USE IEEE.std_logic_1164.ALL;
COMPONENT ControlFSM
PORT (
clk, rst_n : IN std_ulogic;
instr_31_26 : IN std_ulogic_vector(5 downto 0);
RegDst, RegWrite, ALUSrcA, MemRead, MemWrite, MemtoReg, IorD, IRWrite, PCWrite,
PCWriteCond : OUT std_ulogic;
ALUOp, ALUSrcB, PCSource : OUT std_ulogic_vector(1 downto 0)
);
END COMPONENT;
COMPONENT ALUControl
PORT (
instr_15_0 : IN std_ulogic_vector(15 downto 0);
ALUOp : IN std_ulogic_vector(1 downto 0);
ALUopcode : OUT std_ulogic_vector(2 downto 0)
);
END COMPONENT;
BEGIN
inst_ControlFSM : ControlFSM
PORT MAP (
clk => clk,
rst_n => rst_n,
instr_31_26 => instr_31_26,
RegDst => RegDst,
RegWrite => RegWrite,
ALUSrcA => ALUSrcA,
MemRead => MemRead,
MemWrite => MemWrite,
MemtoReg => MemtoReg,
IorD => IorD,
IRWrite => IRWrite,
PCWrite => PCWrite_intern,
PCWriteCond => PCWriteCond_intern,
ALUOp => ALUOp_intern,
ALUSrcB => ALUSrcB,
PCSource => PCSource
);
inst_ALUControl : ALUControl
PORT MAP (
instr_15_0 => instr_15_0,
ALUOp => ALUOp_intern,
ALUopcode => ALUopcode
);
END behave;
VHDLSource 8.20: a_control.vhd
LIBRARY IEEE;
USE IEEE.std_logic_1164.ALL;
USE IEEE.numeric_std.ALL;
-- use package
USE work.procmem_definitions.ALL;
BEGIN
temp_reg: PROCESS(clk, rst_n)
BEGIN
IF rst_n = '0' THEN
reg_out <= (OTHERS => '0');
ELSIF RISING_EDGE(clk) THEN
-- write register input to output at rising edge
reg_out <= reg_in;
END IF;
END PROCESS;
END behave;
VHDLSource 8.21: a_tempreg_behave.vhd
LIBRARY IEEE;
USE IEEE.std_logic_1164.ALL;
USE IEEE.numeric_std.ALL;
-- use package
USE work.procmem_definitions.ALL;
ARCHITECTURE behave OF pc IS
BEGIN
BEGIN
IF rst_n = '0' THEN
pc_temp := (OTHERS => '0');
ELSIF RISING_EDGE(clk) THEN
IF PC_en = '1' THEN
pc_temp := pc_in;
END IF;
END IF;
pc_out <= pc_temp;
END PROCESS;
END behave;
VHDLSource 8.22: a_pc_behave.vhd
LIBRARY IEEE;
USE IEEE.std_logic_1164.ALL;
USE IEEE.numeric_std.ALL;
-- use package
USE work.procmem_definitions.ALL;
BEGIN
END behave;
VHDLSource 8.23: a_instreg_behave.vhd
LIBRARY IEEE;
USE IEEE.std_logic_1164.ALL;
USE IEEE.numeric_std.ALL;
-- use package
USE work.procmem_definitions.ALL;
BEGIN
END behave;
VHDLSource 8.24: a_regfile_behave.vhd
LIBRARY IEEE;
USE IEEE.std_logic_1164.ALL;
USE IEEE.numeric_std.ALL;
BEGIN
PROCESS(a, b, opcode)
-- declaration of variables
VARIABLE a_uns : UNSIGNED(width-1 DOWNTO 0);
VARIABLE b_uns : UNSIGNED(width-1 DOWNTO 0);
VARIABLE r_uns : UNSIGNED(width-1 DOWNTO 0);
VARIABLE z_uns : UNSIGNED(0 DOWNTO 0);
BEGIN
-- initialize values
a_uns := UNSIGNED(a);
b_uns := UNSIGNED(b);
r_uns := (OTHERS => '0');
z_uns(0) := '0';
-- sub
WHEN "110" =>
r_uns := a_uns - b_uns;
-- and
WHEN "000" =>
r_uns := a_uns AND b_uns;
-- or
WHEN "001" =>
r_uns := a_uns OR b_uns;
-- slt
WHEN "111" =>
r_uns := a_uns - b_uns;
IF SIGNED(r_uns) < 0 THEN
r_uns := TO_UNSIGNED(1, r_uns'LENGTH);
ELSE
r_uns := (OTHERS => '0');
END IF;
-- others
WHEN OTHERS => r_uns := (OTHERS => 'X');
END CASE;
END PROCESS;
END behave;
VHDLSource 8.25: a_alu_behave.vhd
LIBRARY IEEE;
USE IEEE.std_logic_1164.ALL;
USE IEEE.numeric_std.ALL;
-- use package
USE work.procmem_definitions.ALL;
COMPONENT instreg IS
PORT (
clk : IN STD_ULOGIC;
rst_n : IN STD_ULOGIC;
memdata : IN STD_ULOGIC_VECTOR(width-1 DOWNTO 0);
IRWrite : IN STD_ULOGIC;
instr_31_26 : OUT STD_ULOGIC_VECTOR(5 DOWNTO 0);
instr_25_21 : OUT STD_ULOGIC_VECTOR(4 DOWNTO 0);
instr_20_16 : OUT STD_ULOGIC_VECTOR(4 DOWNTO 0);
instr_15_0 : OUT STD_ULOGIC_VECTOR(15 DOWNTO 0) );
END COMPONENT;
COMPONENT tempreg IS
PORT (
clk : IN STD_ULOGIC;
rst_n : IN STD_ULOGIC;
reg_in : IN STD_ULOGIC_VECTOR(width-1 DOWNTO 0);
reg_out : OUT STD_ULOGIC_VECTOR(width-1 DOWNTO 0) );
END COMPONENT;
COMPONENT pc IS
PORT (
clk : IN STD_ULOGIC;
rst_n : IN STD_ULOGIC;
pc_in : IN STD_ULOGIC_VECTOR(width-1 DOWNTO 0);
PC_en : IN STD_ULOGIC;
pc_out : OUT STD_ULOGIC_VECTOR(width-1 DOWNTO 0) );
END COMPONENT;
BEGIN
-- instances of components
proc_cnt: pc
PORT MAP (
clk => clk,
rst_n => rst_n,
pc_in => pc_in,
PC_en => PC_en,
pc_out => pc_out_intern);
instr_reg : instreg
PORT MAP (
clk => clk,
rst_n => rst_n,
memdata => mem_data,
IRWrite => IRWrite,
instr_31_26 => instr_31_26,
instr_25_21 => instr_25_21,
instr_20_16 => instr_20_16,
instr_15_0 => instr_15_0 );
mem_data_reg : tempreg
PORT MAP (
clk => clk,
rst_n => rst_n,
reg_in => mem_data,
reg_out => reg_memdata );
-- multiplexer
addr_mux : PROCESS(IorD, pc_out_intern, alu_out)
VARIABLE mem_address_temp : STD_ULOGIC_VECTOR(width-1 DOWNTO 0);
BEGIN
IF IorD = '0' THEN
mem_address_temp := pc_out_intern;
ELSIF IorD = '1' THEN
mem_address_temp := alu_out;
ELSE
END behave;
VHDLSource 8.26: a_data_fetch.vhd
LIBRARY IEEE;
USE IEEE.std_logic_1164.ALL;
USE IEEE.numeric_std.ALL;
-- use package
USE work.procmem_definitions.ALL;
COMPONENT regfile IS
PORT (clk,rst_n : IN std_ulogic;
wen : IN std_ulogic; -- write control
writeport : IN std_ulogic_vector(width-1 DOWNTO 0); -- register input
adrwport : IN std_ulogic_vector(regfile_adrsize-1 DOWNTO 0);-- address write
adrport0 : IN std_ulogic_vector(regfile_adrsize-1 DOWNTO 0);-- address port 0
adrport1 : IN std_ulogic_vector(regfile_adrsize-1 DOWNTO 0);-- address port 1
readport0 : OUT std_ulogic_vector(width-1 DOWNTO 0); -- output port 0
readport1 : OUT std_ulogic_vector(width-1 DOWNTO 0) -- output port 1
);
END COMPONENT;
COMPONENT tempreg IS
PORT (
clk : IN STD_ULOGIC;
rst_n : IN STD_ULOGIC;
reg_in : IN STD_ULOGIC_VECTOR(width-1 DOWNTO 0);
reg_out : OUT STD_ULOGIC_VECTOR(width-1 DOWNTO 0) );
END COMPONENT;
-- internal signals
SIGNAL write_reg : STD_ULOGIC_VECTOR(regfile_adrsize-1 DOWNTO 0);
SIGNAL write_data : STD_ULOGIC_VECTOR(width-1 DOWNTO 0);
SIGNAL data_1 : STD_ULOGIC_VECTOR(width-1 DOWNTO 0);
SIGNAL data_2 : STD_ULOGIC_VECTOR(width-1 DOWNTO 0);
BEGIN
A : tempreg
PORT MAP (
clk => clk,
rst_n => rst_n,
reg_in => data_1,
reg_out => reg_A );
B : tempreg
PORT MAP (
clk => clk,
rst_n => rst_n,
reg_in => data_2,
reg_out => reg_B );
inst_regfile : regfile
PORT MAP (
clk => clk,
rst_n => rst_n,
wen => RegWrite,
writeport => write_data,
adrwport => write_reg,
adrport0 => instr_25_21,
adrport1 => instr_20_16,
readport0 => data_1,
readport1 => data_2 );
END behave;
VHDLSource 8.27: a_data_decode.vhd
LIBRARY IEEE;
USE IEEE.std_logic_1164.ALL;
USE IEEE.numeric_std.ALL;
-- use package
USE work.procmem_definitions.ALL;
COMPONENT alu
PORT (
a, b : IN STD_ULOGIC_VECTOR(width-1 DOWNTO 0);
opcode : IN STD_ULOGIC_VECTOR(2 DOWNTO 0);
result : OUT STD_ULOGIC_VECTOR(width-1 DOWNTO 0);
zero : OUT STD_ULOGIC
);
END COMPONENT;
BEGIN
alu_inst: alu
PORT MAP (
a => mux_A_out,
b => mux_B_out,
opcode => ALUopcode,
result => alu_result,
zero => zero
);
END behave;
VHDLSource 8.28: a_data_execution.vhd
LIBRARY IEEE;
USE IEEE.std_logic_1164.ALL;
USE IEEE.numeric_std.ALL;
-- use package
USE work.procmem_definitions.ALL;
COMPONENT tempreg
PORT (
clk : IN STD_ULOGIC;
rst_n : IN STD_ULOGIC;
reg_in : IN STD_ULOGIC_VECTOR(width-1 DOWNTO 0);
reg_out : OUT STD_ULOGIC_VECTOR(width-1 DOWNTO 0)
);
END COMPONENT;
BEGIN
tempreg_inst: tempreg
PORT MAP (
clk => clk,
rst_n => rst_n,
reg_in => alu_result,
reg_out => alu_out_internal
);
END behave;
VHDLSource 8.29: a_data_memwriteback.vhd
LIBRARY IEEE;
USE IEEE.std_logic_1164.ALL;
USE IEEE.numeric_std.ALL;
-- use package
USE work.procmem_definitions.ALL;
COMPONENT data_fetch
PORT (
clk : IN STD_ULOGIC;
rst_n : IN STD_ULOGIC;
pc_in : IN STD_ULOGIC_VECTOR(width-1 DOWNTO 0);
alu_out : IN STD_ULOGIC_VECTOR(width-1 DOWNTO 0);
mem_data : IN std_ulogic_vector(width-1 DOWNTO 0);
PC_en : IN STD_ULOGIC;
IorD : IN STD_ULOGIC;
IRWrite : IN STD_ULOGIC;
reg_memdata : OUT STD_ULOGIC_VECTOR(width-1 DOWNTO 0);
instr_31_26 : OUT STD_ULOGIC_VECTOR(5 DOWNTO 0);
instr_25_21 : OUT STD_ULOGIC_VECTOR(4 DOWNTO 0);
instr_20_16 : OUT STD_ULOGIC_VECTOR(4 DOWNTO 0);
instr_15_0 : OUT STD_ULOGIC_VECTOR(15 DOWNTO 0);
mem_address : OUT std_ulogic_vector(width-1 DOWNTO 0);
pc_out : OUT std_ulogic_vector(width-1 DOWNTO 0));
END COMPONENT;
COMPONENT data_decode
PORT (
clk : IN STD_ULOGIC;
rst_n : IN STD_ULOGIC;
instr_25_21 : IN STD_ULOGIC_VECTOR(4 DOWNTO 0);
instr_20_16 : IN STD_ULOGIC_VECTOR(4 DOWNTO 0);
instr_15_0 : IN STD_ULOGIC_VECTOR(15 DOWNTO 0);
reg_memdata : IN STD_ULOGIC_VECTOR(width-1 DOWNTO 0);
alu_out : IN STD_ULOGIC_VECTOR(width-1 DOWNTO 0);
RegDst : IN STD_ULOGIC;
RegWrite : IN STD_ULOGIC;
MemtoReg : IN STD_ULOGIC;
reg_A : OUT STD_ULOGIC_VECTOR(width-1 DOWNTO 0);
reg_B : OUT STD_ULOGIC_VECTOR(width-1 DOWNTO 0);
instr_15_0_se : OUT STD_ULOGIC_VECTOR(width-1 DOWNTO 0);
instr_15_0_se_sl : OUT STD_ULOGIC_VECTOR(width-1 DOWNTO 0));
END COMPONENT;
COMPONENT data_execution
PORT (
instr_25_21 : IN std_ulogic_vector(4 downto 0);
instr_20_16 : IN std_ulogic_vector(4 downto 0);
instr_15_0 : IN std_ulogic_vector(15 downto 0);
ALUSrcA : IN std_ulogic;
ALUSrcB : IN std_ulogic_vector(1 downto 0);
ALUopcode : IN std_ulogic_vector(2 downto 0);
reg_A, reg_B : IN std_ulogic_vector(width-1 downto 0);
pc_out : IN std_ulogic_vector(width-1 downto 0);
instr_15_0_se : IN std_ulogic_vector(width-1 downto 0);
instr_15_0_se_sl : IN std_ulogic_vector(width-1 downto 0);
jump_addr : OUT std_ulogic_vector(width-1 downto 0);
alu_result : OUT std_ulogic_vector(width-1 downto 0);
zero : OUT std_ulogic);
END COMPONENT;
COMPONENT data_memwriteback
PORT (
clk, rst_n : IN std_ulogic;
jump_addr : IN std_ulogic_vector(width-1 downto 0);
alu_result : IN std_ulogic_vector(width-1 downto 0);
PCSource : IN std_ulogic_vector(1 downto 0);
pc_in : OUT std_ulogic_vector(width-1 downto 0);
alu_out : OUT std_ulogic_vector(width-1 downto 0));
END COMPONENT;
BEGIN
inst_data_fetch: data_fetch
PORT MAP (
clk => clk,
rst_n => rst_n,
pc_in => pc_in_intern,
alu_out => alu_out_intern,
mem_data => mem_data,
PC_en => PC_en,
IorD => IorD,
IRWrite => IRWrite,
reg_memdata => reg_memdata_intern,
instr_31_26 => instr_31_26,
instr_25_21 => instr_25_21_intern,
instr_20_16 => instr_20_16_intern,
instr_15_0 => instr_15_0_intern,
mem_address => mem_address,
pc_out => pc_out_intern);
inst_data_decode : data_decode
PORT MAP (
clk => clk,
rst_n => rst_n,
instr_25_21 => instr_25_21_intern,
instr_20_16 => instr_20_16_intern,
instr_15_0 => instr_15_0_intern,
reg_memdata => reg_memdata_intern,
alu_out => alu_out_intern,
RegDst => RegDst,
RegWrite => RegWrite,
MemtoReg => MemtoReg,
reg_A => reg_A_intern,
reg_B => reg_B_intern,
instr_15_0_se => instr_15_0_se_intern,
instr_15_0_se_sl => instr_15_0_se_sl_intern
);
inst_data_execution: data_execution
PORT MAP (
instr_25_21 => instr_25_21_intern,
instr_20_16 => instr_20_16_intern,
instr_15_0 => instr_15_0_intern,
ALUSrcA => ALUSrcA,
ALUSrcB => ALUSrcB,
ALUopcode => ALUopcode,
reg_A => reg_A_intern,
reg_B => reg_B_intern,
pc_out => pc_out_intern,
instr_15_0_se => instr_15_0_se_intern,
instr_15_0_se_sl => instr_15_0_se_sl_intern,
jump_addr => jump_addr_intern,
alu_result => alu_result_intern,
zero => zero
);
inst_data_memwriteback : data_memwriteback
PORT MAP (
clk => clk,
rst_n => rst_n,
jump_addr => jump_addr_intern,
alu_result => alu_result_intern,
PCSource => PCSource,
pc_in => pc_in_intern,
alu_out => alu_out_intern
);
END behave;
VHDLSource 8.30: a_data.vhd
LIBRARY ieee;
USE ieee.std_logic_1164.ALL;
USE ieee.numeric_std.ALL;
-- use package
USE work.procmem_definitions.ALL;
LIBRARY IEEE;
USE IEEE.std_logic_1164.ALL;
USE IEEE.numeric_std.ALL;
-- use package
USE work.procmem_definitions.ALL;
COMPONENT ram IS
GENERIC (adrwidth : positive := 8;
datwidth : positive := 8;
-- initial RAM content in IntelHEX Format
ramfile : string := "../simulation/ram256x8.hex"
);
PORT (address : IN std_logic_vector(adrwidth-1 DOWNTO 0);
data : IN std_logic_vector(datwidth-1 DOWNTO 0);
inclock : IN std_logic; -- used to write data in RAM cells
wren_p : IN std_logic;
q : OUT std_logic_vector(datwidth-1 DOWNTO 0));
END COMPONENT;
-- internal signals
SIGNAL wren_p : STD_LOGIC;
SIGNAL data_in_0 : STD_LOGIC_VECTOR(ram_datwidth-1 DOWNTO 0);
SIGNAL data_in_1 : STD_LOGIC_VECTOR(ram_datwidth-1 DOWNTO 0);
SIGNAL data_in_2 : STD_LOGIC_VECTOR(ram_datwidth-1 DOWNTO 0);
SIGNAL data_in_3 : STD_LOGIC_VECTOR(ram_datwidth-1 DOWNTO 0);
SIGNAL data_out_0 : STD_LOGIC_VECTOR(ram_datwidth-1 DOWNTO 0);
SIGNAL data_out_1 : STD_LOGIC_VECTOR(ram_datwidth-1 DOWNTO 0);
SIGNAL data_out_2 : STD_LOGIC_VECTOR(ram_datwidth-1 DOWNTO 0);
SIGNAL data_out_3 : STD_LOGIC_VECTOR(ram_datwidth-1 DOWNTO 0);
SIGNAL address_0 : STD_LOGIC_VECTOR(ram_adrwidth-1 DOWNTO 0);
SIGNAL address_1 : STD_LOGIC_VECTOR(ram_adrwidth-1 DOWNTO 0);
SIGNAL address_2 : STD_LOGIC_VECTOR(ram_adrwidth-1 DOWNTO 0);
SIGNAL address_3 : STD_LOGIC_VECTOR(ram_adrwidth-1 DOWNTO 0);
BEGIN
mem_block1 : ram
-- generic map used for definition of different ramfiles
GENERIC MAP (
adrwidth => ram_adrwidth,
datwidth => ram_datwidth,
ramfile => ramfile_block1)
PORT MAP (
address => address_1,
data => data_in_1,
inclock => clk,
wren_p => wren_p,
q => data_out_1 );
mem_block2 : ram
-- generic map used for definition of different ramfiles
GENERIC MAP (
adrwidth => ram_adrwidth,
datwidth => ram_datwidth,
ramfile => ramfile_block2)
PORT MAP (
address => address_2,
data => data_in_2,
inclock => clk,
wren_p => wren_p,
q => data_out_2 );
mem_block3 : ram
-- generic map used for definition of different ramfiles
GENERIC MAP (
adrwidth => ram_adrwidth,
datwidth => ram_datwidth,
ramfile => ramfile_block3)
PORT MAP (
address => address_3,
data => data_in_3,
inclock => clk,
wren_p => wren_p,
q => data_out_3 );
END behave;
VHDLSource 8.32: a_memory_behave.vhd
LIBRARY IEEE;
USE IEEE.std_logic_1164.ALL;
USE IEEE.numeric_std.ALL;
-- use package
USE work.procmem_definitions.ALL;
COMPONENT control
PORT (
clk, rst_n : IN
std_ulogic;
instr_31_26 : IN
std_ulogic_vector(5 downto 0);
instr_15_0 : IN
std_ulogic_vector(15 downto 0);
zero : IN
std_ulogic;
ALUopcode : OUT
std_ulogic_vector(2 downto 0);
RegDst, RegWrite, ALUSrcA, MemRead, MemWrite, MemtoReg, IorD, IRWrite : OUT
std_ulogic;
ALUSrcB, PCSource : OUT
std_ulogic_vector(1 downto 0);
PC_en : OUT
std_ulogic);
END COMPONENT;
COMPONENT data
PORT (
clk, rst_n : IN std_ulogic;
PC_en, IorD, MemtoReg, IRWrite, ALUSrcA, RegWrite, RegDst : IN std_ulogic;
PCSource, ALUSrcB : IN
std_ulogic_vector(1 downto 0);
ALUopcode : IN
std_ulogic_vector(2 downto 0);
mem_data : IN
std_ulogic_vector(width-1 downto 0);
reg_B, mem_address : OUT
std_ulogic_vector(width-1 downto 0);
instr_31_26 : OUT
std_ulogic_vector(5 downto 0);
instr_15_0 : OUT
std_ulogic_vector(15 downto 0);
zero : OUT std_ulogic);
END COMPONENT;
BEGIN
inst_control : control
PORT MAP (
clk => clk,
rst_n => rst_n,
instr_31_26 => instr_31_26_intern,
instr_15_0 => instr_15_0_intern,
zero => zero_intern,
ALUopcode => ALUopcode_intern,
RegDst => RegDst_intern,
RegWrite => RegWrite_intern,
ALUSrcA => ALUSrcA_intern,
MemRead => MemRead,
MemWrite => MemWrite,
MemtoReg => MemtoReg_intern,
inst_data: data
PORT MAP (
clk => clk,
rst_n => rst_n,
PC_en => PC_en_intern,
IorD => IorD_intern,
MemtoReg => MemtoReg_intern,
IRWrite => IRWrite_intern,
ALUSrcA => ALUSrcA_intern,
RegWrite => RegWrite_intern,
RegDst => RegDst_intern,
PCSource => PCSource_intern,
ALUSrcB => ALUSrcB_intern,
ALUopcode => ALUopcode_intern,
mem_data => mem_data,
reg_B => reg_B,
mem_address => mem_address,
instr_31_26 => instr_31_26_intern,
instr_15_0 => instr_15_0_intern,
zero => zero_intern
);
END behave;
VHDLSource 8.33: a_mips.vhd
LIBRARY IEEE;
USE IEEE.std_logic_1164.ALL;
USE IEEE.numeric_std.ALL;
-- use package
USE work.procmem_definitions.ALL;
COMPONENT mips
PORT (
clk, rst_n : IN std_ulogic;
mem_data : IN std_ulogic_vector(width-1 downto 0);
reg_B, mem_address : OUT std_ulogic_vector(width-1 downto 0);
MemRead, MemWrite : OUT std_ulogic);
END COMPONENT;
COMPONENT memory
PORT (
clk : IN STD_ULOGIC;
rst_n : IN STD_ULOGIC;
MemRead : IN STD_ULOGIC;
MemWrite : IN STD_ULOGIC;
mem_address : IN STD_ULOGIC_VECTOR(width-1 DOWNTO 0);
data_in : IN STD_ULOGIC_VECTOR(width-1 DOWNTO 0);
data_out : OUT STD_ULOGIC_VECTOR(width-1 DOWNTO 0));
END COMPONENT;
BEGIN
inst_mips : mips
PORT MAP (
clk => clk,
rst_n => rst_n,
mem_data => mem_data,
reg_B => reg_B,
mem_address => mem_address,
MemRead => MemRead,
MemWrite => MemWrite
);
inst_memory : memory
PORT MAP (
clk => clk,
rst_n => rst_n,
MemRead => MemRead,
MemWrite => MemWrite,
mem_address => mem_address,
data_in => reg_B,
data_out => mem_data
);
END behave;
VHDLSource 8.34: a_procmem.vhd
8.1.3 Package
PACKAGE ProcMem_definitions IS
-- globals
CONSTANT width : NATURAL := 32;
-- definitions for regfile
CONSTANT regfile_depth : positive := 32; -- register file depth = 2**adrsize
CONSTANT regfile_adrsize : positive := 5; -- address vector size = log2(depth)
-- definitions for memory
CONSTANT ram_adrwidth : positive := 8; -- m x n - RAM Block
CONSTANT ram_datwidth : positive := 8;
-- initial RAM content in IntelHEX Format
CONSTANT ramfile_std : string := "./simulation/ram_256x8.hex";
CONSTANT ramfile_block0 : string := "./simulation/ram0_256x8.hex";
CONSTANT ramfile_block1 : string := "./simulation/ram1_256x8.hex";
CONSTANT ramfile_block2 : string := "./simulation/ram2_256x8.hex";
CONSTANT ramfile_block3 : string := "./simulation/ram3_256x8.hex";
END ProcMem_definitions;
VHDLSource 8.35: p_procmem_definitions.vhd
8.1.4 Testbenches
LIBRARY ieee;
USE ieee.std_logic_1164.ALL;
USE ieee.numeric_std.ALL;
USE std.textio.ALL;
USE ieee.std_logic_textio.ALL;
-- use package
USE work.procmem_definitions.ALL;
-------------------------------------------------------------------------------
ENTITY t_alu IS
END t_alu;
-------------------------------------------------------------------------------
-- component generics
CONSTANT width : NATURAL := 32;
COMPONENT alu
PORT (
a, b : IN STD_ULOGIC_VECTOR(width-1 DOWNTO 0);
opcode : IN STD_ULOGIC_VECTOR(2 DOWNTO 0);
result : OUT STD_ULOGIC_VECTOR(width-1 DOWNTO 0);
zero : OUT STD_ULOGIC);
END COMPONENT;
-- component ports
SIGNAL a, b : STD_ULOGIC_VECTOR(width-1 DOWNTO 0);
SIGNAL opcode : STD_ULOGIC_VECTOR(2 DOWNTO 0);
SIGNAL result : STD_ULOGIC_VECTOR(width-1 DOWNTO 0);
SIGNAL zero : STD_ULOGIC;
BEGIN -- tbenchfileio
-- component instantiation
DUT: alu
PORT MAP (
a => a,
b => b,
opcode => opcode,
result => result,
zero => zero);
stimuli_observer : PROCESS
BEGIN
-- read result
read(Li, vectordelimit);
read(Li, result_fio);
-- read zero bit
read(Li, vectordelimit);
read(Li, zero_fio);
-- compare zero-bit
IF zero /= zero_fio THEN
ASSERT errflag
REPORT "No errors !"
SEVERITY note;
WAIT;
END PROCESS;
END tbenchfileio;
VHDLSource 8.36: t_alu_fileio.vhd
LIBRARY ieee;
USE ieee.std_logic_1164.ALL;
USE IEEE.numeric_std.ALL;
-- use package
USE work.procmem_definitions.ALL;
-------------------------------------------------------------------------------
ENTITY t_memory IS
END t_memory;
-------------------------------------------------------------------------------
COMPONENT memory IS
PORT (
clk : IN STD_ULOGIC;
rst_n : IN STD_ULOGIC;
MemRead : IN STD_ULOGIC;
MemWrite : IN STD_ULOGIC;
mem_address : IN STD_ULOGIC_VECTOR(width-1 DOWNTO 0);
data_in : IN STD_ULOGIC_VECTOR(width-1 DOWNTO 0);
data_out : OUT STD_ULOGIC_VECTOR(width-1 DOWNTO 0) );
END COMPONENT;
-- component ports
SIGNAL clk : STD_ULOGIC;
SIGNAL rst_n : STD_ULOGIC;
SIGNAL MemRead : STD_ULOGIC;
SIGNAL MemWrite : STD_ULOGIC;
SIGNAL mem_address : STD_ULOGIC_VECTOR(width-1 DOWNTO 0);
SIGNAL data_in : STD_ULOGIC_VECTOR(width-1 DOWNTO 0);
SIGNAL data_out : STD_ULOGIC_VECTOR(width-1 DOWNTO 0);
-- STD_ULOGIC_VECTOR TO STRING
FUNCTION TO_string(arg : std_ulogic_vector) RETURN string IS
ALIAS u : STD_ULOGIC_VECTOR(arg'length DOWNTO 1) IS arg;
VARIABLE result : string(arg'length DOWNTO 1);
BEGIN
FOR i IN u'range LOOP
CASE u(i) IS
WHEN 'U' => result(i) := 'U';
WHEN 'X' => result(i) := 'X';
WHEN '0' => result(i) := '0';
WHEN '1' => result(i) := '1';
WHEN 'Z' => result(i) := 'Z';
WHEN 'W' => result(i) := 'W';
WHEN 'L' => result(i) := 'L';
WHEN 'H' => result(i) := 'H';
WHEN '-' => result(i) := '-';
END CASE;
END LOOP;
RETURN result;
END TO_string;
-- UNSIGNED TO STRING
FUNCTION TO_string(arg : unsigned) RETURN string IS
ALIAS u : unsigned(arg'length DOWNTO 1) IS arg;
VARIABLE result : string(arg'length DOWNTO 1);
BEGIN
FOR i IN u'range LOOP
CASE u(i) IS
WHEN 'U' => result(i) := 'U';
WHEN 'X' => result(i) := 'X';
WHEN '0' => result(i) := '0';
WHEN '1' => result(i) := '1';
WHEN 'Z' => result(i) := 'Z';
WHEN 'W' => result(i) := 'W';
WHEN 'L' => result(i) := 'L';
WHEN 'H' => result(i) := 'H';
WHEN '-' => result(i) := '-';
END CASE;
END LOOP;
RETURN result;
END TO_string;
BEGIN -- tbench
-- component instantiation
DUT: memory
PORT MAP (
clk => clk,
rst_n => rst_n,
MemRead => MemRead,
MemWrite => MemWrite,
mem_address => mem_address,
data_in => data_in,
data_out => data_out );
-- clock generation
clock_proc : PROCESS
BEGIN
WHILE clken_p LOOP
clk <= '0'; WAIT FOR period/2;
clk <= '1'; WAIT FOR period/2;
END LOOP;
WAIT;
END PROCESS;
-- reset generation
reset : rst_n <= '0', '1' AFTER period;
-- waveform generation
WaveGen_Proc : PROCESS
BEGIN
-- initialization
MemRead <= '1';
MemWrite <= '0';
mem_address <= (OTHERS => '0');
-- addr_pattern
addr_pattern := ( -- block: 3, 2, 1, 0
x"00000000", -- use correct word address
x"00000004",
x"00000008",
x"0000000C",
x"00000010",
x"00000014");
-- reset
WAIT FOR period;
END tbench;
VHDLSource 8.37: t_memory.vhd
LIBRARY ieee;
USE ieee.std_logic_1164.ALL;
USE IEEE.numeric_std.ALL;
USE work.procmem_definitions.ALL;
-------------------------------------------------------------------------------
ENTITY t_procmem IS
END t_procmem;
-------------------------------------------------------------------------------
COMPONENT procmem IS
PORT (
clk, rst_n : IN STD_ULOGIC
);
END COMPONENT;
-- component ports
SIGNAL clk : STD_ULOGIC;
SIGNAL rst_n : STD_ULOGIC;
BEGIN -- tbench
-- component instantiation
DUT: procmem
PORT MAP (
clk => clk,
rst_n => rst_n
);
-- clock generation
clock_proc : PROCESS
BEGIN
WHILE clken_p LOOP
clk <= '0'; WAIT FOR period/2;
clk <= '1'; WAIT FOR period/2;
END LOOP;
WAIT;
END PROCESS;
-- reset generation
reset : rst_n <= '0', '1' AFTER period;
-- waveform generation
WaveGen_Proc : PROCESS
BEGIN
-- reset
WAIT FOR period;
END tbench;
VHDLSource 8.38: t_procmem.vhd
LIBRARY ieee;
USE ieee.std_logic_1164.ALL;
USE IEEE.numeric_std.ALL;
-- use package
USE work.procmem_definitions.ALL;
-------------------------------------------------------------------------------
ENTITY t_procmem_init IS
END t_procmem_init;
-------------------------------------------------------------------------------
COMPONENT mips
PORT (
clk, rst_n : IN std_ulogic;
mem_data : IN std_ulogic_vector(width-1 downto 0);
reg_B, mem_address : OUT std_ulogic_vector(width-1 downto 0);
MemRead, MemWrite : OUT std_ulogic);
END COMPONENT;
COMPONENT memory
PORT (
clk : IN STD_ULOGIC;
rst_n : IN STD_ULOGIC;
MemRead : IN STD_ULOGIC;
MemWrite : IN STD_ULOGIC;
mem_address : IN STD_ULOGIC_VECTOR(width-1 DOWNTO 0);
data_in : IN STD_ULOGIC_VECTOR(width-1 DOWNTO 0);
data_out : OUT STD_ULOGIC_VECTOR(width-1 DOWNTO 0));
END COMPONENT;
-- component ports
SIGNAL clk : STD_ULOGIC;
SIGNAL rst_n : STD_ULOGIC;
BEGIN -- tbench
inst_mips : mips
PORT MAP (
clk => clk,
rst_n => rst_n,
mem_data => mem_data_mux,
reg_B => reg_B,
mem_address => mem_address,
MemRead => MemRead,
MemWrite => MemWrite
);
inst_memory : memory
PORT MAP (
clk => clk,
rst_n => rst_n,
MemRead => MemRead_mux,
MemWrite => MemWrite_mux,
mem_address => mem_address_mux,
data_in => reg_B_mux,
data_out => mem_data
);
-- clock generation
clock_proc : PROCESS
BEGIN
WHILE clken_p LOOP
clk <= '0'; WAIT FOR period/2;
clk <= '1'; WAIT FOR period/2;
END LOOP;
WAIT;
END PROCESS;
-- reset generation
-- not used because of initialisation during explicit reset
--reset : rst_n <= '0', '1' AFTER period;
-- waveform generation
WaveGen_Proc : PROCESS
BEGIN
x"00000080",
x"00000084"
);
data_pattern := (
"10001100000100000000000010000000",
"10001100000100010000000010000100",
"00000010000100011001000000100000",
"10101100000100100000000010001000",
"00000010001100001001100000100010",
"10101100000100110000000010001100",
"00000010001100001010000000100100",
"10101100000101000000000010010000",
"00000010001100001010100000100101",
"10101100000101010000000010010100",
"00000010000100011011000000101010",
"10101100000101100000000010011000",
"00010010000101000000000000000001",
"00001000000000000000000000000010",
"00000000000000000000000101111011",
"00000000000000000000000101111111");
-- explicit reset
rst_n <= '0';
-- start
rst_n <= '1';
END tbench;
8.2 References