VHDL Notes for CprE 381

Download Report

Transcript VHDL Notes for CprE 381

VHDL Programming in CprE 381
Zhao Zhang
CprE 381, Fall 2013
Iowa State University
Last update: 9/15/2013
VHDL Notes for Week 4
• Generic Constant
• Entity and component
• Test bench
Generic Constant
• Generic constant is used to parameterize an
entity one_complement is
generic(constant N : integer := 16);
: in std_logic_vector(N-1 downto 0);
: out std_logic_vector(N-1 downto 0));
end one_complement;
• Can be added to entity
• Takes a default value
Generic Constant
architecture behavior of tb_one_complement is
component one_complement
generic(constant N: integer := 32);
port(i_A : in std_logic_vector(N-1 downto 0);
o_F : out std_logic_vector(N-1 downto 0));
end component;
• The default value can be changed in a
component statement
Generic Constant
C1: entity work.one_complment(behavior)
generic map (N => 32)
port map (i_A => s_A, o_F => s_F);
C1: one_complement
generic map (N => 32)
port map (i_A => s_A, o_F => s_F);
• The generic constant value can also be decided
in a component instantiation statement
Entity and Component
• Be default a component is associated with an
entity of the same name
• Component can be configured in configuration
specification to associate with an entity and an
for C1
: one_complement use entity
for all : one_complement use entity
Generate Statement
• A for…generate statement may used in an
architecture to instantiate an array of
component instances
G1: for i in 0 to N-1 generate
inv_array: inv
port map(i_A => i_A(i),
o_F => o_F(i));
end generate;
Generic Example
architecture structure of one_complement is
component inv
port(i_A : in std_logic;
o_F : out std_logic);
end component;
G1: for i in 0 to N-1 generate
inv_i: inv
port map(i_A => i_A(i),
o_F => o_F(i));
end generate;
end structure;
Test Bench
• Test bench provides stimulus to the simulation
• Its entity statement is usually empty
entity tb_one_complement is
end tb_one_complement;
Test Bench
architecture behavior of tb_one_complement is
… -- components, signals, component instances
-- The test sequence
s_A <= X"00000001";
wait for 100 ns;
s_A <= X"00001000";
wait for 100 ns;
end process; -- it repeats
end behavior;
VHDL Notes for Week 5
• Mixing VHDL styles: Structure, data flow,
• Model a truth table
• Model a register file
VHDL Notes in 381
• I will discuss VHDL programming techniques just
for the need of CprE 381
– The notes are customized for the labs
– I’m not a VHDL expert (used to program in Verilog)
• Take the notes as exposure to new techniques
– The notes will only cover the essential of each
– Search Internet or get a good VHDL book, for the
complete description and details
– The “VHDL tutorial” is a good starting point but may
not be sufficient
Structure, Dataflow and Behavior
• Those are different ways to model a hardware
entity my_circuit is
port(i1, i2, i3, i4 : in bit;
o : out bit);
end my_circuit;
Structure, Dataflow and Behavior
architecture mixed of
signal wire1, wire2
nand_gate1 : entity
port map (i1, i2,
my_circuit is
: bit;
nand_gata2 : block
wire2 <= i1 nand i2;
end block;
nand_data3 : process (wire1, wire2)
if (wire1 = ‘1’) and (wire2 = ‘1’) then
o <= ‘0’;
o <= ‘1’;
end if;
end process;
Structure, Data Flow and Behavior
• The previous example mixes three modeling
styles: structure, data flow, and behavior
• It uses three VHDL programming constructs
(complex statements), each for a NAND gate
– Component/entity instantiation
– Concurrent signal assignment
– Process statement
• The logic circuits can be the same – Different
modeling styles may or may not lead to the same
Model Truth Table
Use case statement (behavior)
architecture behavior of reg_decoder is
-- input : 5-bit addr; output: 32-bit sel
D : process (addr)
case (addr) is
when b”00000” => sel <= x”00000001”;
when b”00001” => sel <= x”00000002”;
… -- more cases
when b”11111” => sel <= x”80000000”;
end case;
end process;
end behavior;
Model Truth Table
Use selected signal statement (data flow)
architecture dataflow of reg_decoder is
-- input : 5-bit addr; output: 32-bit sel
with addr select
sel <= x”00000001” when b”00000”,
x”00000002” when b”00001”,
… -- more cases
x”80000000” when bb”11111”;
end dataflow;
Model Regfile
• A simplest way to mode register file is to use
two process statements, with an array of 32bit internal signals
– Not acceptable if you do it for Lab 3 assignment
Model Regfile
architecture behavior of regfile is
signal reg_array : m32_regval_array;
REG_READ : process (clk, src1, src2)
variable r1, r2 : integer;
r1 := to_integer(unsigned(src1));
r2 := to_integer(unsigned(src2));
rdata1 <= reg_array(r1);
rdata2 <= reg_array(r2);
end process;
Model Regfile
REG_WRITE : process (clk)
variable r : integer;
if (rising_edge(clk)) then
if (WE = '1') then
r := to_integer(unsigned(dst));
reg_array(r) <= wdata;
end if;
end process;
end behavior;
Lab 4 This Week
• Part 1: Sign and Zero extension
– You will need both in Mini-Projects B and C
• What extension is needed in J instruction
• What extension is needed in BNE instruction?
• Part 2: Test a given memory implementation
– It is like using an IP from other designers
– Write your test carefully, make sure it really works
Multiple Testing Processes
• In a test bench, we may use multiple process
• Example: Use two processes in REGFILE test
– One process for generating clock signal
– Another for providing control and data signals
Multiple Testing Processes
entity tb_reg32 is
-- This is a single reg
-- Half clock Cycle Time
generic (HCT : time := 50 ns);
end tb_reg32;
architecture behavior of tb_reg32 is
-- Clock Cycle Time
constant CCT : time := 2 * HCT;
-- Component and signal declarations
Multiple Testing Processes
REG_A: reg32
port map (clk, rst, WE, D, Q);
P_CLK : process
clk <= '0';
wait for HCT;
clk <= '1';
wait for HCT;
end process;
-- Clock generation
-- Wait for half clock cycle
-- Wait for half clock cycle
Multiple Testing Processes
P_DATA : process
-- Reset the register
rst <= '1';
wait for CCT;
rst <= '0';
-- Write hex 0x12345678
WE <= '1';
<= X"12345678";
wait for CCT;
Multiple Testing Processes
-- Test with WE = ‘0’
WE <= '0';
<= X"00001010";
wait for CCT;
-- More stimulus
end process;
end behavior;
Assert Statements
assert condition report message severity level;
• If the condition is false, report a message, and
potentially stop the simulation
• Can be useful in test bench for automatic
– No need to read the waveform all the time
– Help you quickly identify errors
• Can also be used to self-check a logic circuit
Assert Statement
Example: Use report and assert statements
inside a testing process
-- Test register write
report “Test on input 0x12345678”;
WE <= '1';
<= X"12345678";
wait for CCT;
assert(Q = X"12345678")
report ”Fail on input 0x12345678”;
Assert Statement
• Use severity level to tell the simulator whether to
assert(Q = X"12345678")
report "Test input 0x12345678”
severity ERROR;
• Four severity levels and ModelSim behavior
Just print the message
warning: Print “warning” message
Print “error” message (default)
Print “failure” message, break/pause
the simulation
Report Statement
• You can also use report statements like printf
– Note: You may need functions to convert
std_logic_vector to integer, e.g. hex()
– You may search the Internet or contact Dr. Zhang
for the code
TEST : process
report “rdata1 = “ & hex(rdata1)
“rdata2 = “ & hex(rdata2);
end process;
Debugging Single-Cycle Processor
General debugging skills
• Pause the simulation and inspect signals
• Inspect register and memory contents
• Be selective with waveform signals: There are
too many signals!
• Pause simulation and inspect signals at the
right time, avoiding the rising clock edges
Debugging Single-Cycle Processor
Check the outcome of an instruction to see if it
runs correctly
– Check PC for all instructions
– Check dest register for R-Type and load
– Check memory word for store
– Test taken and not-taken cases for branch
Debugging Single-Cycle Processor
Suggest strategy 1: Trace instruction execution in
forward direction. Check:
PC and instruction memory output
rs, rt, shamt, funct, immediate
All control signals
Register read data
ALU inputs and outputs
Data memory address, data input, data output
Register write data
And other signals
Debugging Single-Cycle Processor
Suggest strategy 2: Trace instruction execution
in backward direction.
The tracing can be more focused
Debugging Single-Cycle Processor
A case of debugging: For code
lw $t0, 0($zero)
lw $t1, 4($zero)
The first instruction runs correctly, the second doesn’t.
Check on the second instruction:
• Memory address: It is 0x00000000, not 0x00000004!
• ALU result (address): it is indeed 0x00000000 (wrong)
• ALU inputs
– rdata1 = 0x00000000: OK
– alu_input2 = 0x00000004: OK
– ALU_code = "0000”: Wrong! That's AND operation
Debugging Single-Cycle Processor
Continue to check:
• ALUop = "00”: OK
Something is wrong with ALU control, continue:
• Check inside of alu_ctrl.vhd:
– I used ‘X’ in programming the truth table
– Thought ‘X’ is “don't care”. No, that's Verilog!
– In VHDL std_logic, ‘X’ is “unknown”, and "-" is “don't care”!
• Then learned that VHDL 2002 doesn't support
matching '0' or '1' with X in case statement
– VHDL 2008 does support this feature
– ModelSim (PE 10.2c) supports VHDL 2002 by default
• Change a programming technique and then it works