⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 a10281_ph.vhd

📁 TCM解码
💻 VHD
📖 第 1 页 / 共 2 页
字号:
-- Drawing number       : D10281-- Drawing description  : Viterbi decoder core---- Entity name          : d10281_ph-- Short description    : Path history manager-- Architecture(s)      : rtl---- Traceback memory management is a little tricky, because the simple approach-- requires 1 write and <traceback_length> reads per clock!-- The alternative method, known as Register Exchange, would require (for-- traceback depth T = 96) 6K flip-flops all going at full clock rate, that's-- 61 k gates.---- The method used here is based on a paper by Emmanuel Boutillon and -- Nicolas Demassieux.  It utilises a small register exchange unit, of length-- equal to the memory order of the code (i.e. 6).  That's just 384 flip-flops-- or 4k gates.  This produces one 6-bit encoder state value every T clocks,-- which is used as the starting point to trace back for 96 output bits in a RAM-- bank.  Meanwhile, a second RAM bank is being written with the new decisions.ARCHITECTURE rtl OF d10281_ph IS--==========================================-- Combinatorial --==========================================  -- To mux the incoming memory buses, then select just one decision bit...  SIGNAL muxed_mem_din      : std_logic_vector( 2*trellis_width-1 DOWNTO 0 );  SIGNAL selected_memory_bit: std_logic;  SIGNAL selected_y           : std_logic;  -- The decoded data!  SIGNAL dout_int           : std_logic;  SIGNAL dout_y             : std_logic;  SIGNAL mem_write_address : traceback_address_type;  SIGNAL mem_read_address  : traceback_address_type;--==========================================-- Registers--==========================================  -- Address counters are 1-bit bigger than traceback needs, because we have two banks.  SUBTYPE address_counter_type IS unsigned(traceback_address_type'LENGTH DOWNTO 0);  SIGNAL read_counter        : address_counter_type;  SIGNAL write_counter       : address_counter_type;  -- State machine for controlling the rather strange count sequence  TYPE ctr_state_type IS (normal_ascending,  normal_descending, short_ascending,                          offset_descending, offset_ascending,  short_descending);   SIGNAL ctr_state           : ctr_state_type;  -- Count the position within each block of traceback  SIGNAL linear_counter      : unsigned(traceback_address_type'RANGE);  -- Count blocks of traceback at startup  SIGNAL mask_counter        : unsigned(1 DOWNTO 0);  SIGNAL mask_counter_d1     : unsigned(1 DOWNTO 0);  SIGNAL mask_counter_d2     : unsigned(1 DOWNTO 0);  SIGNAL mask_counter_tre    : unsigned(1 DOWNTO 0);  SIGNAL mask_counter_d3     : unsigned(1 DOWNTO 0);  -- values to compare or set the linear counter  CONSTANT linear_counter_zero : unsigned(traceback_address_type'RANGE) := (OTHERS => '0');  CONSTANT linear_counter_max  : unsigned(traceback_address_type'RANGE) :=      conv_unsigned(traceback_length-1, traceback_address_type'LENGTH);  -- The extra memory location, and it's controls  TYPE mem_type       IS ARRAY ( 11 DOWNTO 0 ) OF std_logic_vector(2*trellis_width-1 DOWNTO 0);  SIGNAL mem_2t              : mem_type;  SIGNAL write_mem_2t        : BOOLEAN;  SIGNAL read_mem_2t         : BOOLEAN;  -- The register exchange unit  TYPE   regex_type         IS ARRAY ( trellis_width-1 DOWNTO 0 ) OF std_logic_vector(memory_order-1 DOWNTO 0);  TYPE   trel_regex_type    IS ARRAY ( 11 DOWNTO 0 ) OF regex_type;  SIGNAL regex              : trel_regex_type;  CONSTANT regex_zero : std_logic_vector(memory_order-1 DOWNTO 0) := (OTHERS => '0');  -- Whether the RegEx unit is in CAPTURE or SHUFFLE mode  SIGNAL capture_regs       : BOOLEAN;  -- The traceback unit  TYPE shift_type           IS ARRAY ( 11 DOWNTO 0 ) OF unsigned(memory_order-1 DOWNTO 0);  TYPE shift_left_type      IS ARRAY ( 11 DOWNTO 0 ) OF BOOLEAN;  SIGNAL shifter            : shift_type;  -- Bit reverser is like two back-to-back LIFO stacks  TYPE   rever_type         IS ARRAY ( 11 DOWNTO 0 ) OF std_logic_vector(traceback_length-1 DOWNTO 0);  SIGNAL reverser           : rever_type;  SIGNAL reverser_y         : rever_type;  SIGNAL reverser_shift_left  : BOOLEAN;  SIGNAL reverser_shift_d1  : BOOLEAN;  SIGNAL tre_rd_index       : std_logic_vector( 3 DOWNTO 0 );  SIGNAL tre_rd_d1          : std_logic_vector( 3 DOWNTO 0 );  SIGNAL rd_sel             : std_logic;  SIGNAL rd_sel_2t          : BOOLEAN;  SIGNAL trellis_en         : std_logic;  SIGNAL trellis_en_d1      : std_logic;  SIGNAL shift_d            : std_logic_vector( 11 DOWNTO 0 );  SIGNAL shift_y            : std_logic_vector( 11 DOWNTO 0 );  BEGIN--===========================================================-- Combinatorial--===========================================================      -- Buffer these to the outside world (hold off data for first 3 blocks during startup)  dovalid   <= clk_out_enable WHEN mask_counter_d3 = 3 ELSE '0';  dout      <= ( dout_y & dout_int ) WHEN mask_counter_d1 = 3 ELSE "00";  trellis_index   <= tre_rd_index;  -- DOUT comes from the bit reverser  dout_int <= reverser(conv_integer(unsigned(tre_rd_index)))(traceback_length-1)  WHEN reverser_shift_d1         ELSE  reverser(conv_integer(unsigned(tre_rd_index)))(0);  dout_y   <= reverser_y(conv_integer(unsigned(tre_rd_index)))(traceback_length-1)  WHEN reverser_shift_d1           ELSE  reverser_y(conv_integer(unsigned(tre_rd_index)))(0);  -- Select the appropriate memory, and then select just one decision bit  muxed_mem_din <= mem_2t(conv_integer(unsigned(tre_rd_index)))   WHEN rd_sel_2t              ELSE mem2_din WHEN rd_sel = '1'              ELSE mem1_din;  selected_memory_bit <= muxed_mem_din(conv_integer(shifter(conv_integer(unsigned(tre_rd_index))))) AND mask_counter_d1(1);  selected_y          <= muxed_mem_din(conv_integer('1' & shifter(conv_integer(unsigned(tre_rd_index))))) AND mask_counter_d1(1);  -- For the first two blocks (while reading uninitialised memory) gate off the  -- decision data.  -- memory controls:  -- Split read/write counters into bank select (LSB) and address (the rest)  mem_cs_n  <= NOT clk_out_enable;  mem_dout  <= out_y & decision;  mem_write_address <= std_logic_vector(write_counter(address_counter_type'HIGH DOWNTO 1));  mem_read_address  <= std_logic_vector(read_counter(address_counter_type'HIGH DOWNTO 1));  mem1_a( traceback_addr_width-1 DOWNTO 0 ) <= mem_write_address WHEN write_counter(0) = '0' ELSE mem_read_address;  mem2_a( traceback_addr_width-1 DOWNTO 0 ) <= mem_read_address  WHEN write_counter(0) = '0' ELSE mem_write_address;  mem1_a( traceback_addr_width+4-1 DOWNTO traceback_addr_width )  <= tre_rd_d1;  mem2_a( traceback_addr_width+4-1 DOWNTO traceback_addr_width )  <= tre_rd_d1;    mem1_we_n   <= '1' WHEN write_mem_2t ELSE     write_counter(0);  mem2_we_n   <= '1' WHEN write_mem_2t ELSE NOT write_counter(0);    trellis_en  <= '1' WHEN trellis_count = "0000"                 ELSE '0';--===========================================================-- Clocked--===========================================================    -- During each clock, we need to do one write and one read.  -- In order to use ordinary RAM cells, the read and write need to be  -- in different banks.  To minimise storage, we read the byte we've just  -- written.  Thus the RAM banks are interleaved on the address LSB.  -- Because each block of traceback_length T words needs to be read  -- in reverse order with respect to how it was written, we actually need   -- 2T + 1 words.  The 2T'th word is a register.  -- This mandates a rather strange count sequence!  --  -- The counters have a range 0..2T-1.  The LSB selects which bank to use.  addrgen : PROCESS (clk_out, reset_n)    -- To keep the following constant declarations readable, break out the    -- conversions into a function:    FUNCTION ac_val(n : NATURAL) RETURN address_counter_type IS    BEGIN      RETURN conv_unsigned(n, address_counter_type'LENGTH);    END ac_val;    -- constants with to compare and set the address counter:    CONSTANT ac_0          : address_counter_type := ac_val(0);    CONSTANT ac_1          : address_counter_type := ac_val(1);    CONSTANT ac_t_minus_1  : address_counter_type := ac_val(traceback_length-1);    CONSTANT ac_t          : address_counter_type := ac_val(traceback_length);    CONSTANT ac_t_plus_1   : address_counter_type := ac_val(traceback_length+1);    CONSTANT ac_2t_minus_1 : address_counter_type := ac_val((2*traceback_length)-1);    PROCEDURE modulo_inc(SIGNAL count : INOUT address_counter_type) IS    BEGIN      IF count = ac_2t_minus_1 THEN        count <= ac_0;      ELSE        count <= count + 1;      END IF;    END modulo_inc;    PROCEDURE modulo_dec(SIGNAL count : INOUT address_counter_type) IS    BEGIN      IF count = ac_0 THEN        count <= ac_2t_minus_1;      ELSE        count <= count - 1;      END IF;    END modulo_dec;  BEGIN    IF reset_n = '0' THEN        read_counter   <= ac_1;        write_counter  <= ac_0;        read_mem_2t    <= FALSE;        write_mem_2t   <= FALSE;        ctr_state      <= normal_ascending;    ELSIF clk_out'EVENT AND clk_out = '1' THEN      IF viterbi_init = '1' THEN        read_counter   <= ac_1;        write_counter  <= ac_0;        read_mem_2t    <= FALSE;        write_mem_2t   <= FALSE;        ctr_state      <= normal_ascending;      ELSIF clk_out_enable = '1' AND trellis_en = '1' THEN        -- We always write the address we've just read, so write counter        -- generation is easy:        write_counter  <= read_counter;        write_mem_2t   <= read_mem_2t;        -- The read counter is rather more complex...        IF read_mem_2t THEN          -- Storing into the internal register (the 2T'th element)          read_mem_2t <= FALSE;        ELSE          -- storing into RAM          CASE ctr_state IS            WHEN normal_ascending =>              -- Count up 0..2T-1 (2T counts)              modulo_inc(read_counter);              IF read_counter = ac_2t_minus_1 THEN                ctr_state      <= normal_descending;                read_counter   <= ac_t_minus_1;                read_mem_2t    <= TRUE;              END IF;            -- mem_2T between these two states (1 count)            WHEN normal_descending =>              -- Count down T-1..T (2T counts)              modulo_dec(read_counter);              IF read_counter = ac_t THEN                ctr_state      <= short_ascending;                read_counter   <= ac_1;              END IF;            WHEN short_ascending =>              -- Count up 1..T-1 then 2T then T+1..2T-1 (2T-1 counts)              modulo_inc(read_counter);              IF read_counter = ac_t_minus_1 THEN                read_mem_2t    <= TRUE;                read_counter   <= ac_t_plus_1;              ELSIF read_counter = ac_2t_minus_1 THEN                ctr_state      <= offset_descending;                read_counter   <= ac_0;              END IF;            WHEN offset_descending =>              -- Count down 0, T-1..1, T, 2T-1..T+1 (2T counts)              modulo_dec(read_counter);              IF read_counter = ac_0 THEN

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -