memory_sizer.v
来自「硬件方面的源代码-有关IP核的」· Verilog 代码 · 共 445 行 · 第 1/2 页
V
445 行
output [N_PP-1:0] memory_be_o; // byte enables to memoryoutput access_ack_o; // shows that access is completedoutput exception_be_o; // exception for write to non-byte-enabled memoryoutput exception_watchdog_o; // exception for memory_ack_i watch dog timeout// Internal signal declarationswire [2*N_PP-1:0] memory_be_source; // Unshifted byte enables for writingwire [2*N_PP-1:0] latch_be_source; // Unshifted byte enables for readingwire [N_PP-1:0] latch_be; // "latch_be" is like "memory_be_o" wire [N_PP-1:0] latch_be_lil_endian; // but used internally for reads.wire [N_PP-1:0] latch_be_big_endian;wire [LOG2_N_PP-1:0] latch_be_adjust;wire [LOG2_N_PP+1:0] dat_shift_next; // Next dat_shift value (extra bit // is for terminal count compare.)wire [LOG2_N_PP-1:0] alignment; // shows aligment of accesswire terminal_count; // signifies last store cyclewire [`BYTE_SIZE*N_PP-1:0] steer_dat_i; // data input to byte steering logicwire [`BYTE_SIZE*N_PP-1:0] revrs_dat_i; // data input to byte reversing logic reg [LOG2_N_PP-1:0] byte_mux_select; // selects which bytes to transferreg [LOG2_N_PP:0] dat_shift; // shift amt. for data and byte enablesreg [`BYTE_SIZE*N_PP-1:0] revrs_dat_o; // data out from byte reversing logicreg [`BYTE_SIZE*N_PP-1:0] steer_dat_o; // data out from byte steering logicreg [`BYTE_SIZE*N_PP-1:0] read_dat; // read data (after latch bypassing)reg [`BYTE_SIZE*N_PP-1:0] latched_read_dat; // read values before latch bypassreg [WATCHDOG_TIMER_BITS_PP-1:0] watchdog_count;//--------------------------------------------------------------------------// Instantiations//--------------------------------------------------------------------------//--------------------------------------------------------------------------// Functions & Tasks//--------------------------------------------------------------------------function [`BYTE_SIZE*N_PP-1:0] byte_reversal; input [`BYTE_SIZE*N_PP-1:0] din; integer k; begin for (k=0; k<N_PP; k=k+1) byte_reversal[`BYTE_SIZE*(N_PP-k)-1:`BYTE_SIZE*(N_PP-k-1)] <= din[`BYTE_SIZE*(k+1)-1:`BYTE_SIZE*k]; endendfunction//--------------------------------------------------------------------------// Module code//--------------------------------------------------------------------------// Mask off the address bits that don't matter for alignmentassign alignment = (memory_width_i - 1) & adr_i[LOG2_N_PP-1:0];// Setting up the basic (alignment shifted) byte enablesassign memory_be_source = ((1<<access_width_i)-1);assign latch_be_source = ((1<<memory_width_i)-1);// Assigning the byte enables and latch enablesassign memory_be_o = we_i?((memory_be_source << alignment) >> dat_shift) :{N_PP{1'b1}}; // (memory byte enables are all high for reads!)// For big_endian reads, the latch byte enables (and indeed the data also)// are shifted using a special mapping, which causes the data to appear at // the opposite end of the "read_data" bus.assign latch_be_lil_endian = ((latch_be_source << dat_shift) >> alignment);assign latch_be_adjust = ~(access_width_i[LOG2_N_PP-1:0]-1);assign latch_be_big_endian = latch_be_lil_endian << latch_be_adjust;assign latch_be = (access_big_endian_i)?latch_be_big_endian :latch_be_lil_endian;// Exceptionsassign exception_be_o = (alignment != 0) && ~memory_has_be_i;assign exception_watchdog_o = (watchdog_count == WATCHDOG_TIMER_VALUE_PP);// Pass signals to memoryassign memory_we_o = we_i;// Enable the data bus outputs in each directionassign dat_io = (sel_i && ~we_i)?revrs_dat_o:{`BYTE_SIZE*N_PP{1'bZ}};assign memory_dat_io = (sel_i && we_i)?steer_dat_o:{`BYTE_SIZE*N_PP{1'bZ}};// Decide which bus supplies the byte reversing logic// (One could just use a single mux here instead of the tri-state buffers.// in fact, the synthesis tool might decide to change the tri-state buffers// into simple 2:1 muxes...)assign revrs_dat_i = (~we_i)?read_dat:{`BYTE_SIZE*N_PP{1'bZ}};assign revrs_dat_i = (we_i)?dat_io:{`BYTE_SIZE*N_PP{1'bZ}};// Decide which bus supplies the byte steering logic// (One could just use a single mux here instead of the tri-state buffers.// in fact, the synthesis tool might decide to change the tri-state buffers// into simple 2:1 muxes...)assign steer_dat_i = (~we_i)?memory_dat_io:{`BYTE_SIZE*N_PP{1'bZ}};assign steer_dat_i = (we_i)?revrs_dat_o:{`BYTE_SIZE*N_PP{1'bZ}};// This logic latches the data bytes which are read during the first cycles// of an access. During the final cycle of the access, then "terminal_count"// is asserted by the counting logic, which causes the latches which are// "non-dirty" (i.e. which do not yet contain data) to be bypassed by muxes.// This means that for single cycle accesses, the data will flow directly// around the latches and an extra clock cycle will not be needed in order// to latch the data...always @(posedge clk_i)begin: BYTE_LATCHES integer i; if (reset_i || terminal_count || ~sel_i) begin latched_read_dat <= 0; end else if (sel_i && ~we_i && memory_ack_i) begin for (i=0;i<N_PP;i=i+1) begin if (latch_be[i]) latched_read_dat[`BYTE_SIZE*(i+1)-1:`BYTE_SIZE*i] <= steer_dat_o[`BYTE_SIZE*(i+1)-1:`BYTE_SIZE*i]; end endend// This part handles the bypass muxesalways @( terminal_count or latch_be or steer_dat_o or latched_read_dat )begin: LATCH_BYPASS integer j; for (j=0;j<N_PP;j=j+1) begin if (terminal_count && latch_be[j]) read_dat[`BYTE_SIZE*(j+1)-1:`BYTE_SIZE*j] <= steer_dat_o[`BYTE_SIZE*(j+1)-1:`BYTE_SIZE*j]; else read_dat[`BYTE_SIZE*(j+1)-1:`BYTE_SIZE*j] <= latched_read_dat[`BYTE_SIZE*(j+1)-1:`BYTE_SIZE*j]; endend// Byte reversal logic (reused for both reads and writes)always @( revrs_dat_i or access_big_endian_i )begin // Reverse the bytes of the data bus, if needed if (access_big_endian_i) revrs_dat_o <= byte_reversal(revrs_dat_i); else revrs_dat_o <= revrs_dat_i;end// Steering logic (reused for both reads and writes)always @( steer_dat_i or dat_shift or alignment or we_i or access_width_i or access_big_endian_i )begin // If bytes are reversed, an extra "bit inversion mask" is applied // to reflect a new mapping which is correct for reversed bytes. if (access_big_endian_i && we_i) byte_mux_select <= (dat_shift[LOG2_N_PP-1:0] ^ ~(access_width_i-1)) - alignment; else if (~access_big_endian_i && we_i) byte_mux_select <= dat_shift - alignment; // For reads, negate the shift amount else if (access_big_endian_i && ~we_i) byte_mux_select <= alignment - (dat_shift[LOG2_N_PP-1:0] ^ ~(access_width_i-1)); else if (~access_big_endian_i && ~we_i) byte_mux_select <= alignment - dat_shift; // Rotate the data bus (byte-sized barrel shifter!) steer_dat_o <= ( (steer_dat_i >> `BYTE_SIZE*byte_mux_select) |(steer_dat_i << `BYTE_SIZE*(N_PP-byte_mux_select)) );end// This is the counting logic.// It is implemented using "count_next" in order to detect when// the last cycle is being performed, which is when the "next" count// equals or exceeds the total size of the access requested in bytes.// (Using the "next" approach avoids issues relating to different// memory sizes!)always @(posedge clk_i)begin if (reset_i || terminal_count || ~sel_i) dat_shift <= 0; else if (memory_ack_i) dat_shift <= dat_shift_next;endassign dat_shift_next = dat_shift + memory_width_i;assign terminal_count = (dat_shift_next >= (access_width_i + alignment));assign memory_adr_o = adr_i + dat_shift;assign access_ack_o = terminal_count && sel_i;// This is the watchdog timer// It runs whenever the memory_sizer is selected for an access, and the// memory has not yet responded with an ack signal.always @(posedge clk_i)begin if (reset_i || ~sel_i || memory_ack_i) watchdog_count <= 0; else if (~exception_watchdog_o) watchdog_count <= watchdog_count + 1;endendmodule
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?