📄 memory_sizer_dual_path.v
字号:
// 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 cycle reg [LOG2_N_PP-1:0] rd_byte_mux_select; // selects which bytes to transferreg [LOG2_N_PP-1:0] wr_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] wr_steer_dat_o; // data from byte steering logicreg [`BYTE_SIZE*N_PP-1:0] wr_revrs_dat_o; // data from byte reversing logicreg [`BYTE_SIZE*N_PP-1:0] rd_revrs_dat_o; // data from byte reversing logicreg [`BYTE_SIZE*N_PP-1:0] rd_steer_dat_o; // data 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)?rd_revrs_dat_o:{`BYTE_SIZE*N_PP{1'bZ}};assign memory_dat_io = (sel_i && we_i)?wr_steer_dat_o:{`BYTE_SIZE*N_PP{1'bZ}};// THIS LOGIC IS FOR THE WRITING PATH//-------------------------------------// Byte reversal logicalways @( dat_io or access_big_endian_i )begin // Reverse the bytes of the data bus, if needed if (access_big_endian_i) wr_revrs_dat_o <= byte_reversal(dat_io); else wr_revrs_dat_o <= dat_io;end// Steering logicalways @( wr_revrs_dat_o 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) wr_byte_mux_select <= (dat_shift[LOG2_N_PP-1:0] ^ ~(access_width_i-1)) - alignment; else wr_byte_mux_select <= dat_shift - alignment; // Rotate the data bus (byte-sized barrel shifter!) wr_steer_dat_o <= ( (wr_revrs_dat_o >> `BYTE_SIZE*wr_byte_mux_select) |(wr_revrs_dat_o << `BYTE_SIZE*(N_PP-wr_byte_mux_select)) );end// THIS LOGIC IS FOR THE READING PATH//-------------------------------------// Steering logicalways @( memory_dat_io or dat_shift or alignment or we_i or access_width_i or access_big_endian_i )begin // For reads, negate the shift amount if (access_big_endian_i) rd_byte_mux_select <= alignment - (dat_shift[LOG2_N_PP-1:0] ^ ~(access_width_i-1)); else rd_byte_mux_select <= alignment - dat_shift; // Rotate the data bus (byte-sized barrel shifter!) rd_steer_dat_o <= ( (memory_dat_io >> `BYTE_SIZE*rd_byte_mux_select) |(memory_dat_io << `BYTE_SIZE*(N_PP-rd_byte_mux_select)) );end// 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] <= rd_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 rd_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] <= rd_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 logicalways @( read_dat or access_big_endian_i )begin // Reverse the bytes of the data bus, if needed if (access_big_endian_i) rd_revrs_dat_o <= byte_reversal(read_dat); else rd_revrs_dat_o <= read_dat;end// THIS LOGIC IS GENERAL//--------------------------// 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 + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -