module scratchpad ( input CLK_I, input RST_I, input [31:0] EBR_ADR_I, input [31:0] EBR_DAT_I, input EBR_WE_I, input EBR_CYC_I, input EBR_STB_I, input [3:0] EBR_SEL_I, input [2:0] EBR_CTI_I, input [1:0] EBR_BTE_I, input EBR_LOCK_I, output reg [31:0] EBR_DAT_O, output reg EBR_ACK_O, output reg EBR_ERR_O, output reg EBR_RTY_O ); parameter UDLY = 1; parameter EBR_WB_ADR_WIDTH = 10; parameter ST_IDLE = 3'b000; parameter ST_BURST = 3'b001; parameter ST_END = 3'b010; parameter ST_SUBRD = 3'b100; parameter ST_SUB = 3'b101; parameter ST_SUBWR = 3'b110; // Internal Nets and Registers wire [31:0] data; // Data read from RAM reg write_enable; // RAM write enable reg [31:0] write_data, write_data_d; // RAM write data reg [EBR_WB_ADR_WIDTH+1:0] pmi_address, pmi_address_nxt; reg [EBR_WB_ADR_WIDTH-1:0] read_address, write_address; reg EBR_ACK_O_nxt; reg [31:0] read_data; reg read_enable; reg raw_hazard, raw_hazard_nxt; reg [31:0] EBR_DAT_I_d; reg [3:0] EBR_SEL_I_d; reg delayed_write; reg [2:0] state, state_nxt; always @(/*AUTOSENSE*/EBR_ACK_O or EBR_CTI_I or EBR_CYC_I or EBR_SEL_I or EBR_STB_I or EBR_WE_I or state) case (state) ST_IDLE: if (EBR_STB_I && EBR_CYC_I && (EBR_ACK_O == 1'b0)) if ((EBR_CTI_I == 3'b000) || (EBR_CTI_I == 3'b111)) state_nxt = ST_END; else if (EBR_WE_I && (EBR_SEL_I != 4'b1111)) state_nxt = ST_SUBRD; else state_nxt = ST_BURST; else state_nxt = state; ST_BURST: if (EBR_CTI_I == 3'b111) state_nxt = ST_IDLE; else state_nxt = state; ST_SUBRD: state_nxt = ST_SUB; ST_SUB: if (EBR_CTI_I == 3'b111) state_nxt = ST_SUBWR; else state_nxt = state; default: state_nxt = ST_IDLE; endcase /*---------------------------------------------------------------------- ----------------------------------------------------------------------*/ always @(/*AUTOSENSE*/read_address or state or write_address) if ((state == ST_SUB) && (read_address == write_address)) raw_hazard_nxt = 1'b1; else raw_hazard_nxt = 1'b0; // Set up read to EBR always @(/*AUTOSENSE*/EBR_CTI_I or EBR_SEL_I or EBR_WE_I or data or raw_hazard or raw_hazard_nxt or state or write_data_d) begin if ((EBR_WE_I == 1'b0) || (EBR_WE_I && (((state == ST_IDLE) && ((EBR_CTI_I == 3'b000) || (EBR_CTI_I == 3'b111) || (EBR_SEL_I != 4'b1111))) || (state == ST_SUBRD) || ((state == ST_SUB) && (raw_hazard_nxt == 1'b0))))) read_enable = 1'b1; else read_enable = 1'b0; read_data = raw_hazard ? write_data_d : data; end // Set up write to EBR always @(/*AUTOSENSE*/EBR_CTI_I or EBR_CYC_I or EBR_DAT_I or EBR_DAT_I_d or EBR_SEL_I or EBR_SEL_I_d or EBR_STB_I or EBR_WE_I or data or read_data or state) begin if ((EBR_WE_I && (// Word Burst Write (first write in a sequence) ((state == ST_IDLE) && EBR_CYC_I && EBR_STB_I && (EBR_CTI_I != 3'b000) && (EBR_CTI_I != 3'b111) && (EBR_SEL_I == 4'b1111)) // Single Write || (state == ST_END) // Burst Write (all writes beyond first write) || (state == ST_BURST))) // Sub-Word Burst Write || ((state == ST_SUB) || (state == ST_SUBWR))) write_enable = 1'b1; else write_enable = 1'b0; if ((state == ST_SUBRD) || (state == ST_SUB) || (state == ST_SUBWR)) delayed_write = 1'b1; else delayed_write = 1'b0; write_data[7:0] = (delayed_write ? (EBR_SEL_I_d[0] ? EBR_DAT_I_d[7:0] : read_data[7:0]) : (EBR_SEL_I[0] ? EBR_DAT_I[7:0] : data[7:0])); write_data[15:8] = (delayed_write ? (EBR_SEL_I_d[1] ? EBR_DAT_I_d[15:8] : read_data[15:8]) : (EBR_SEL_I[1] ? EBR_DAT_I[15:8] : data[15:8])); write_data[23:16] = (delayed_write ? (EBR_SEL_I_d[2] ? EBR_DAT_I_d[23:16] : read_data[23:16]) : (EBR_SEL_I[2] ? EBR_DAT_I[23:16] : data[23:16])); write_data[31:24] = (delayed_write ? (EBR_SEL_I_d[3] ? EBR_DAT_I_d[31:24] : read_data[31:24]) : (EBR_SEL_I[3] ? EBR_DAT_I[31:24] : data[31:24])); end // Set up address to EBR always @(/*AUTOSENSE*/EBR_ADR_I or EBR_SEL_I or EBR_WE_I or pmi_address or state) begin if (// First address of any access is obtained from Wishbone signals (state == ST_IDLE) // Read for a Sub-Word Wishbone Burst Write || (state == ST_SUB)) read_address = EBR_ADR_I[EBR_WB_ADR_WIDTH+1:2]; else read_address = pmi_address[EBR_WB_ADR_WIDTH+1:2]; if ((state == ST_SUB) || (state == ST_SUBWR)) write_address = pmi_address[EBR_WB_ADR_WIDTH+1:2]; else write_address = EBR_ADR_I[EBR_WB_ADR_WIDTH+1:2]; // Keep track of first address and subsequently increment it by 4 // bytes on a burst read if (EBR_WE_I) pmi_address_nxt = EBR_ADR_I[EBR_WB_ADR_WIDTH+1:0]; else if (state == ST_IDLE) if ((EBR_SEL_I == 4'b1000) || (EBR_SEL_I == 4'b0100) || (EBR_SEL_I == 4'b0010) || (EBR_SEL_I == 4'b0001)) pmi_address_nxt = EBR_ADR_I[EBR_WB_ADR_WIDTH+1:0] + 1'b1; else if ((EBR_SEL_I == 4'b1100) || (EBR_SEL_I == 4'b0011)) pmi_address_nxt = {(EBR_ADR_I[EBR_WB_ADR_WIDTH+1:1] + 1'b1), 1'b0}; else pmi_address_nxt = {(EBR_ADR_I[EBR_WB_ADR_WIDTH+1:2] + 1'b1), 2'b00}; else if ((EBR_SEL_I == 4'b1000) || (EBR_SEL_I == 4'b0100) || (EBR_SEL_I == 4'b0010) || (EBR_SEL_I == 4'b0001)) pmi_address_nxt = pmi_address + 1'b1; else if ((EBR_SEL_I == 4'b1100) || (EBR_SEL_I == 4'b0011)) pmi_address_nxt = {(pmi_address[EBR_WB_ADR_WIDTH+1:1] + 1'b1), 1'b0}; else pmi_address_nxt = {(pmi_address[EBR_WB_ADR_WIDTH+1:2] + 1'b1), 2'b00}; end always @(/*AUTOSENSE*/EBR_ACK_O or EBR_CYC_I or EBR_STB_I or data or state) begin if (((state == ST_IDLE) && EBR_CYC_I && EBR_STB_I && (EBR_ACK_O == 1'b0)) || (state == ST_BURST) || (state == ST_SUBRD) || (state == ST_SUB)) EBR_ACK_O_nxt = 1'b1; else EBR_ACK_O_nxt = 1'b0; EBR_DAT_O = data; EBR_RTY_O = 1'b0; EBR_ERR_O = 1'b0; end always @(posedge CLK_I) if (RST_I) begin EBR_ACK_O <= #UDLY 1'b0; EBR_DAT_I_d <= #UDLY 0; EBR_SEL_I_d <= #UDLY 0; state <= #UDLY ST_IDLE; pmi_address <= #UDLY 0; write_data_d <= #UDLY 0; raw_hazard <= #UDLY 0; end else begin EBR_ACK_O <= #UDLY EBR_ACK_O_nxt; EBR_DAT_I_d <= #UDLY EBR_DAT_I; EBR_SEL_I_d <= #UDLY EBR_SEL_I; state <= #UDLY state_nxt; pmi_address <= #UDLY pmi_address_nxt; write_data_d <= #UDLY write_data; raw_hazard <= #UDLY raw_hazard_nxt; end scratchpad_ebr scratchpad_ebr ( .Reset (RST_I), .WrClock (CLK_I), .RdClock (CLK_I), .WrClockEn (1'b1), .RdClockEn (read_enable), .RdAddress (read_address), .WrAddress (write_address), .Data (write_data), .WE (write_enable), .Q (data) ); endmodule