480 likes | 1.12k Views
EEL4712 Digital Design. ROM. Instruction ROM example (1). LIBRARY ieee; USE ieee.std_logic_1164.all; USE ieee. numeric_std .all; ENTITY instruction_rom IS GENERIC ( w : INTEGER := 16; n : INTEGER := 8; m : INTEGER := 3); PORT (
E N D
Instruction ROM example (1) LIBRARY ieee; USE ieee.std_logic_1164.all; USE ieee.numeric_std.all; ENTITY instruction_rom IS GENERIC ( w : INTEGER := 16; n : INTEGER := 8; m : INTEGER := 3); PORT ( Instr_addr : IN STD_LOGIC_VECTOR(m-1 DOWNTO 0); Instr : out STD_LOGIC_VECTOR(w-1 DOWNTO 0) ); END instruction_rom;
Instruction ROM example (2) ARCHITECTURE ins_rom OF instruction_rom IS SIGNAL temp: INTEGER RANGE 0 TO n-1; TYPE vector_array IS ARRAY (0 to n-1) OF STD_LOGIC_VECTOR(w-1 DOWNTO 0); CONSTANT memory : vector_array := ( X"0000", X"D459", X"A870", X"7853", X"650D", X"642F", X"F742", X"F548"); BEGIN temp <= to_integer(unsigned(Instr_addr)); Instr <= memory(temp); END instruction_rom;
Initializations • Declarations of signals (and variables) with initialized values, such as • SIGNAL a : STD_LOGIC := ‘0’; cannot be synthesized, and thus should be avoided. • If present, they will be ignored by the synthesis tools. • Use set and reset signals instead.
Dual-edge triggered register/counter (1) In FPGAs register/counter can change only at either rising (default) or falling edge of the clock. Dual-edge triggered clock is not synthesizable correctly, using either of the descriptions provided below.
Dual-edge triggered register/counter (2) PROCESS (clk) BEGIN IF (clk’EVENT AND clk=‘1’ ) THEN counter <= counter + 1; ELSIF (clk’EVENT AND clk=‘0’ ) THEN counter <= counter + 1; END IF; END PROCESS;
Dual-edge triggered register/counter (3) PROCESS (clk) BEGIN IF (clk’EVENT) THEN counter <= counter + 1; END IF; END PROCESS; PROCESS (clk) BEGIN counter <= counter + 1; END PROCESS;
Poor Design Practices and Remedies • Synchronous design is the most important methodology • Poor practice in the past (to save chips) • Misuse of asynchronous reset • Misuse of gated clock • Disuse of derived clock • Dual-edge triggered register/counter
Misuse of Asynchronous Reset • Problem • Glitches in transition 1001 (9) => 0000 (0) • Glitches in asyn_clr can reset the counter • How about timing analysis? (maximal clock rate) • Asynchronous reset should only be used for power-on initialization
Decade (mod-10) Counter Architecturetwo_seg_archof mod10_counter is Constant TEN: integer : = 10; Signal r_reg : unsigned (3 downto 0); Signal r_next: unsigned (3 downto 0); Begin Process (clk, reset) Begin if (reset = ‘1’) then r_reg <= (others => ‘0’); elsif(clk’eventand clk=‘1’) then r_reg <= r-next; end if; End process; R_next<= (others => ‘0’) when r_reg = (TEN-1) else r_reg +1; -- output logic Q =< std_logic_vector (r_reg); Endtwo_seg_arch;
Misuse of Gated Clock • Problem • Gated clock width can be narrow • Gated clock may pass glitches of en • Difficult to design clock distribution network
Disuse of Derived Clock • Subsystems may run at different clock rate • Poor design: use a derived slow clock for slow subsystems • Multiple clock distribution network • How about timing analysis? (maximal clock rate)
Disuse of Derived Clock - Solution • Better use a synchronous one-clock enable pulse
Bad Design • E.g., second and minutes counter • Input: 1 MHz clock • Poor design
Clock Divider – Same Frequency • Modifying clock phase to generate clock with different phases at the same frequency • Clock1 is the reference clock • Clock2 has 90° phase offset • Clock3 has 180°phase offset
Clock Division by Two • If the clock we need is simply the system clock divided by two, we can implement a simple divider using a flip-flop and inverter: https://surf-vhdl.com/how-to-implement-clock-divider-vhdl/
Clock division by power of two • This clock divider can be implemented using a running simple wrap around counter • The counter LSB flips at half the clock rate, this means that it can be used as clock divider by two. • The bit k rate is 1/(2^(k+1)) clock rate https://surf-vhdl.com/how-to-implement-clock-divider-vhdl/
Clock Divider – Different Frequency • The frequency divider objective is to reduce the input frequency. It is implemented through the use of the scaling factor and a counter. • Scaling factor: the relation between the input frequency and the desired output frequency: • Assuming an input frequency of 50MHz and provided we need an output frequency of 200Hz, we yield: • Therefore, the counter of the frequency divider generates the output signal of 200Hz each 250000 cycles.
Clock Divider (3) architecture Behavioral of clk200Hz is signal temporal: STD_LOGIC; signal counter : integer range 0 to 124999 := 0; begin frequency_divider: process (reset, clk_in) begin if (reset = '1') then temporal <= '0'; counter <= 0; elsifrising_edge(clk_in) then if (counter = 124999) then temporal <= NOT(temporal); counter <= 0; else counter <= counter + 1; end if; end if; end process; clk_out <= temporal; end Behavioral; Library IEEE; use IEEE.STD_LOGIC_1164.ALL; entity clk200Hz is Port ( clk_in : in STD_LOGIC; reset : in STD_LOGIC; clk_out: out STD_LOGIC ); end clk200Hz; A clock signal is a square wave with a 50% of duty cycle(same time active and inactive); for this case, 125000 cycles active and 125000 cycles inactive. Since the counter begins at zero, the superior limit is (250000/2)-1=125000 - 1. Why 124999 not 250000?
Packages • A package in VHDL is a collection of functions, procedures, shared variables, constants, files, aliases, types, subtypes, attributes, and components. • A package file is often (but not always) used in conjunction with a unique VHDL library.
Example: XOR Tree A 2-d array (P) is needed to capture intermediate wires P30 shows the value of 0th wire in stage 3 WIDTH #Stage = log2 (WIDTH)
XOR Tree library ieee; use ieee.std_logic_1164.all; use work.util_pkg.all; entity reduced_xor is generic(WIDTH: natural:=8); port( a: in std_logic_vector(WIDTH-1 downto 0); y: out std_logic );end reduced_xor;
XOR Tree (2) architecture gen_tree_arch of reduced_xor is constant STAGE: natural:= log2c(WIDTH); signal p: std_logic_2d(STAGE downto 0, WIDTH-1 downto 0); Begin -- rename input signal in_gen: for i in 0 to (WIDTH-1) generate p(STAGE, i) <= a(i); end generate; -- replicated structure stage_gen: for s in (STAGE-1) downto 0 generate row_gen: for r in 0 to (2**s-1) generate p(s, r) <= p(s+1, 2*r) xor p(s+1, 2*r+1); end generate; end generate; -- rename output signal y <= p(0, 0); end gen_tree_arch;
Util_pkg (1) library ieee; use ieee.std_logic_1164.all; package util_pkg is type std_logic_2d is array(integer range <>, integer range <>) of std_logic; function log2c (n: integer) return integer; end util_pkg ;
Util_pkg (2) --package body package body util_pkg is function log2c(n: integer) return integer is variable m, p: integer; begin m := 0; p := 1; while p < n loop m := m + 1; p := p * 2; end loop; return m; end log2c; end util_pkg;
Array Data Type • Array Type
XOR Tree with Arbitrary Input Size (1) begin -- rename input signal in_gen: for i in 0 to (WIDTH-1) generate p(STAGE,i) <= a(i); end generate; -- padding 0’s pad0_gen: if WIDTH < (2**STAGE) generate zero_gen: for i in WIDTH to (2**STAGE-1) generate p(STAGE,i) <= '0’; end generate; end generate;
XOR Tree with Arbitrary Input Size (2) -- replicated structure stage_gen: for s in (STAGE-1) downto 0 generate row_gen: for r in 0 to (2**s-1) generate p(s,r) <= p(s+1,2*r) xor p(s+1,2*r+1); end generate; end generate; -- rename output signal y <= p(0,0); end gen_tree2_arch;
Predefined Unconstrained Array Types • Predefined • bit_vector array of bits • string array of characters • Defined in the std_logic_1164 package: • type std_logic_vector is array (natural range <>) of std_logic;
User-defined Unconstrained Array Types type std_logic_2d is array(integer range <>, integer range <>) of std_logic; • Examples: • signal s1: std_logic_2d(3 downto 0, 5 downto 0); • signal s2: std_logic_2d(15 downto 0, 31 downto 0); • signal s3: std_logic_2d(7 downto 0, 1 downto 0);
User-defined Unconstrained Array Type defined in a package use work.util_pkg.all; entity …. generic ( ROW: natural; COL: natural) ); port ( p1: in std_logic_2d(ROW-1 downto 0, COL-1 downto 0); …….. ); architecture signal s1: std_logic_2d(ROW-1 downto 0, COL-1 downto 0);
Array-of-Arrays Data Type constant ROW : natural := 4; constant COL : natural := 6; type sram_row_by_col is array (ROW -1 downto 0) of std_logic_vector(COL – 1 downto 0); …… signal t1: sram_row_by_col; signal v1: std_logic_vector(COL-1 downto 0); signal b1: std_logic; …… t1 <= (“000101”, “101001”, others => (others => ‘0’)); b1 <= t1(3)(0); v1 <= t1(2);
Array Attributes A’left(N) left bound of index range of dimension N of A A’right(N) right bound of index range of dimension N of A A’low(N) lower bound of index range of dimension N of A A’high(N) upper bound of index range of dimension N of A A’range(N) index range of dimension N of A A’reverse_range(N) reversed index range of dimension N of A A’length(N) length of index range of dimension N of A A’ascending(N) true if index range of dimension N of A is an ascending range, false otherwise
Array Attributes - Examples type A is array (1 to 4, 31 downto0); A’left(1) = 1 A’right(2) = 0 A’low(1) = 1 A’high(2) = 31 A’range(1) = 1 to 4 A’length(2) = 32 A’ascending(2) = false
Unconstrained PARITY Generator (1) LIBRARY ieee; USE ieee.std_logic_1164.all; ENTITY parity IS PORT( parity_in : IN STD_LOGIC_VECTOR; parity_out : OUT STD_LOGIC ); END parity;
Unconstrained PARITY Generator (2) ARCHITECTURE parity_dataflow OF parity IS CONSTANT width: natural := parity_in’length; SIGNAL xor_out: STD_LOGIC_VECTOR (width-1 DOWNTO 0); BEGIN xor_out(0) <= parity_in(0); G2: FOR i IN 1 TO width-1 GENERATE xor_out(i) <= xor_out(i-1) XOR parity_in(i); END GENERATE G2; parity_out <= xor_out(width-1); END parity_dataflow;
Unconstrained PARITY Generator (3) • Will the previous code work for the following types of signal parity_in? • std_logic_vector(7 downto 0); • std_logic_vector(0 to 7); • std_logic_vector(15 downto 8); • std_logic_vector(8 to 15);
Unconstrained PARITY Generator (4) ARCHITECTURE parity_dataflow OF parity IS CONSTANT width: natural := parity_in’length; SIGNAL xor_out: STD_LOGIC_VECTOR (width-1 DOWNTO 0); SIGNAL pp: STD_LOGIC_VECTOR (width-1 DOWNTO 0); BEGIN pp <= parity_in; xor_out(0) <= pp(0); G2: FOR i IN 1 TO width-1 GENERATE xor_out(i) <= xor_out(i-1) XOR pp(i); END GENERATE G2; parity_out <= xor_out(width-1); END parity_dataflow;
References • Stephen Brown and ZvonkoVranesic. 2004. Fundamentals of Digital Logic with VHDL Design. McGraw-Hill, Inc., New York, NY, USA. • https://ece.gmu.edu/coursewebpages/ECE/ECE545/F18/viewgraphs/ECE545_lecture_8_regular.pdf • https://ece.gmu.edu/coursewebpages/ECE/ECE545/F18/viewgraphs/ECE545_lecture_9_FSM_refresher.pdf • P. Chu, RTL Hardware Design using VHDL • Chapter 14, Parameterized Design: Principle • Chapter 15, (except 15.4) Parameterized Design: Practice • https://surf-vhdl.com/how-to-implement-clock-divider-vhdl/ • https://forums.xilinx.com/t5/Xilinx-Evaluation-Boards/Generation-of-4-Phase-Shifted-clock-Signals-from-DCM/td-p/330395