360 likes | 505 Views
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 entity one_complement is
E N D
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 entity one_complement is generic(constant N : integer := 16); port(i_A: in std_logic_vector(N-1 downto 0); o_F: 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_complementis 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; … begin … • 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
Entityand Component • Be default a component is associated with an entity of the same name • Component can be configured in configuration specificationto associate with an entity and an architecture for C1 : one_complement use entity work.one_complment(behavior) for all : one_complement use entity work.one_complment(behavior)
Generate Statement • A for…generate statement may used in an architecture to instantiate an array of component instances G1: fori 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; begin 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_complementis … -- components, signals, component instances -- The test sequence process begin 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, behavior • 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 technique • 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 component entity my_circuit is port(i1, i2, i3, i4 : in bit; o : out bit); end my_circuit;
Structure, Dataflow and Behavior architecture mixed of my_circuit is signal wire1, wire2 : bit; begin nand_gate1 : entity work.nand2(dataflow) port map (i1, i2, wire1); nand_gata2 : block begin wire2 <= i1 nand i2; end block; nand_data3 : process (wire1, wire2) begin if (wire1 = ‘1’) and (wire2 = ‘1’) then o <= ‘0’; else o <= ‘1’; end if; end process; end
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 circuit
Model Truth Table Use case statement (behavior) architecture behaviorof reg_decoder is begin -- input : 5-bit addr; output: 32-bit sel D : process (addr) begin 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 begin -- input : 5-bit addr; output: 32-bit sel with addrselect 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 32-bit 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; begin REG_READ : process (clk, src1, src2) variable r1, r2 : integer; begin r1 := to_integer(unsigned(src1)); r2 := to_integer(unsigned(src2)); rdata1 <= reg_array(r1); rdata2 <= reg_array(r2); end process; Continue…
Model Regfile Continue… REG_WRITE: process (clk) variable r : integer; begin 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 statements • Example: Use two processes in REGFILE test bench • 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 begin REG_A: reg32 port map (clk, rst, WE, D, Q); P_CLK : process -- Clock generation begin clk <= '0'; wait for HCT; -- Wait for half clock cycle clk <= '1'; wait for HCT; -- Wait for half clock cycle end process;
Multiple Testing Processes P_DATA : process begin -- Reset the register rst <= '1'; wait for CCT; rst <= '0'; -- Write hex 0x12345678 WE <= '1'; D <= X"12345678"; wait for CCT;
Multiple Testing Processes -- Test with WE = ‘0’ WE <= '0'; D <= 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 testing • 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'; D <= 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 stop. assert(Q = X"12345678") report "Test input 0x12345678” severity ERROR; • Four severity levels and ModelSim behavior note: Just print the message warning: Print “warning” message error: Print “error” message (default) failure: 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 begin … 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