481 lines
16 KiB
Systemverilog
481 lines
16 KiB
Systemverilog
/// Copyright by Syntacore LLC © 2016-2021. See LICENSE for details
|
|
/// @file <scr1_dmem_ahb.sv>
|
|
/// @brief Data memory AHB bridge
|
|
///
|
|
|
|
`include "scr1_ahb.svh"
|
|
`include "scr1_memif.svh"
|
|
|
|
module scr1_dmem_ahb (
|
|
// Control Signals
|
|
input logic rst_n,
|
|
input logic clk,
|
|
|
|
// Core Interface
|
|
output logic dmem_req_ack,
|
|
input logic dmem_req,
|
|
input type_scr1_mem_cmd_e dmem_cmd,
|
|
input type_scr1_mem_width_e dmem_width,
|
|
input logic [SCR1_AHB_WIDTH-1:0] dmem_addr,
|
|
input logic [SCR1_AHB_WIDTH-1:0] dmem_wdata,
|
|
output logic [SCR1_AHB_WIDTH-1:0] dmem_rdata,
|
|
output type_scr1_mem_resp_e dmem_resp,
|
|
|
|
// AHB Interface
|
|
output logic [3:0] hprot,
|
|
output logic [2:0] hburst,
|
|
output logic [2:0] hsize,
|
|
output logic [1:0] htrans,
|
|
output logic hmastlock,
|
|
output logic [SCR1_AHB_WIDTH-1:0] haddr,
|
|
output logic hwrite,
|
|
output logic [SCR1_AHB_WIDTH-1:0] hwdata,
|
|
input logic hready,
|
|
input logic [SCR1_AHB_WIDTH-1:0] hrdata,
|
|
input logic hresp
|
|
|
|
);
|
|
|
|
//-------------------------------------------------------------------------------
|
|
// Local Parameters
|
|
//-------------------------------------------------------------------------------
|
|
`ifndef SCR1_DMEM_AHB_OUT_BP
|
|
localparam SCR1_FIFO_WIDTH = 2;
|
|
localparam SCR1_FIFO_CNT_WIDTH = $clog2(SCR1_FIFO_WIDTH+1);
|
|
`endif // SCR1_DMEM_AHB_OUT_BP
|
|
|
|
//-------------------------------------------------------------------------------
|
|
// Local type declaration
|
|
//-------------------------------------------------------------------------------
|
|
typedef enum logic {
|
|
SCR1_FSM_ADDR = 1'b0,
|
|
SCR1_FSM_DATA = 1'b1
|
|
`ifdef SCR1_XPROP_EN
|
|
,
|
|
SCR1_FSM_ERR = 1'bx
|
|
`endif // SCR1_XPROP_EN
|
|
} type_scr1_fsm_e;
|
|
|
|
typedef struct packed {
|
|
logic hwrite;
|
|
logic [2:0] hwidth;
|
|
logic [SCR1_AHB_WIDTH-1:0] haddr;
|
|
logic [SCR1_AHB_WIDTH-1:0] hwdata;
|
|
} type_scr1_req_fifo_s;
|
|
|
|
typedef struct packed {
|
|
logic [2:0] hwidth;
|
|
logic [1:0] haddr;
|
|
logic [SCR1_AHB_WIDTH-1:0] hwdata;
|
|
} type_scr1_data_fifo_s;
|
|
|
|
typedef struct packed {
|
|
logic hresp;
|
|
logic [2:0] hwidth;
|
|
logic [1:0] haddr;
|
|
logic [SCR1_AHB_WIDTH-1:0] hrdata;
|
|
} type_scr1_resp_fifo_s;
|
|
|
|
//-------------------------------------------------------------------------------
|
|
// Local functions
|
|
//-------------------------------------------------------------------------------
|
|
function automatic logic [2:0] scr1_conv_mem2ahb_width (
|
|
input type_scr1_mem_width_e dmem_width
|
|
);
|
|
logic [2:0] tmp;
|
|
begin
|
|
case (dmem_width)
|
|
SCR1_MEM_WIDTH_BYTE : begin
|
|
tmp = SCR1_HSIZE_8B;
|
|
end
|
|
SCR1_MEM_WIDTH_HWORD : begin
|
|
tmp = SCR1_HSIZE_16B;
|
|
end
|
|
SCR1_MEM_WIDTH_WORD : begin
|
|
tmp = SCR1_HSIZE_32B;
|
|
end
|
|
default : begin
|
|
tmp = SCR1_HSIZE_ERR;
|
|
end
|
|
endcase
|
|
return tmp;
|
|
end
|
|
endfunction : scr1_conv_mem2ahb_width
|
|
|
|
function automatic logic[SCR1_AHB_WIDTH-1:0] scr1_conv_mem2ahb_wdata (
|
|
input logic [1:0] dmem_addr,
|
|
input type_scr1_mem_width_e dmem_width,
|
|
input logic [SCR1_AHB_WIDTH-1:0] dmem_wdata
|
|
);
|
|
logic [SCR1_AHB_WIDTH-1:0] tmp;
|
|
begin
|
|
`ifdef SCR1_XPROP_EN
|
|
tmp = 'x;
|
|
`else // SCR1_XPROP_EN
|
|
tmp = '0;
|
|
`endif // SCR1_XPROP_EN
|
|
case (dmem_width)
|
|
SCR1_MEM_WIDTH_BYTE : begin
|
|
case (dmem_addr)
|
|
2'b00 : begin
|
|
tmp[7:0] = dmem_wdata[7:0];
|
|
end
|
|
2'b01 : begin
|
|
tmp[15:8] = dmem_wdata[7:0];
|
|
end
|
|
2'b10 : begin
|
|
tmp[23:16] = dmem_wdata[7:0];
|
|
end
|
|
2'b11 : begin
|
|
tmp[31:24] = dmem_wdata[7:0];
|
|
end
|
|
default : begin
|
|
end
|
|
endcase
|
|
end
|
|
SCR1_MEM_WIDTH_HWORD : begin
|
|
case (dmem_addr[1])
|
|
1'b0 : begin
|
|
tmp[15:0] = dmem_wdata[15:0];
|
|
end
|
|
1'b1 : begin
|
|
tmp[31:16] = dmem_wdata[15:0];
|
|
end
|
|
default : begin
|
|
end
|
|
endcase
|
|
end
|
|
SCR1_MEM_WIDTH_WORD : begin
|
|
tmp = dmem_wdata;
|
|
end
|
|
default : begin
|
|
end
|
|
endcase
|
|
return tmp;
|
|
end
|
|
endfunction : scr1_conv_mem2ahb_wdata
|
|
|
|
function automatic logic[SCR1_AHB_WIDTH-1:0] scr1_conv_ahb2mem_rdata (
|
|
input logic [2:0] hwidth,
|
|
input logic [1:0] haddr,
|
|
input logic [SCR1_AHB_WIDTH-1:0] hrdata
|
|
);
|
|
logic [SCR1_AHB_WIDTH-1:0] tmp;
|
|
begin
|
|
`ifdef SCR1_XPROP_EN
|
|
tmp = 'x;
|
|
`else // SCR1_XPROP_EN
|
|
tmp = '0;
|
|
`endif // SCR1_XPROP_EN
|
|
case (hwidth)
|
|
SCR1_HSIZE_8B : begin
|
|
case (haddr)
|
|
2'b00 : tmp[7:0] = hrdata[7:0];
|
|
2'b01 : tmp[7:0] = hrdata[15:8];
|
|
2'b10 : tmp[7:0] = hrdata[23:16];
|
|
2'b11 : tmp[7:0] = hrdata[31:24];
|
|
default : begin
|
|
end
|
|
endcase
|
|
end
|
|
SCR1_HSIZE_16B : begin
|
|
case (haddr[1])
|
|
1'b0 : tmp[15:0] = hrdata[15:0];
|
|
1'b1 : tmp[15:0] = hrdata[31:16];
|
|
default : begin
|
|
end
|
|
endcase
|
|
end
|
|
SCR1_HSIZE_32B : begin
|
|
tmp = hrdata;
|
|
end
|
|
default : begin
|
|
end
|
|
endcase
|
|
return tmp;
|
|
end
|
|
endfunction : scr1_conv_ahb2mem_rdata
|
|
|
|
//-------------------------------------------------------------------------------
|
|
// Local signal declaration
|
|
//-------------------------------------------------------------------------------
|
|
type_scr1_fsm_e fsm;
|
|
logic req_fifo_rd;
|
|
logic req_fifo_wr;
|
|
logic req_fifo_up;
|
|
`ifdef SCR1_DMEM_AHB_OUT_BP
|
|
type_scr1_req_fifo_s req_fifo_new;
|
|
type_scr1_req_fifo_s req_fifo_r;
|
|
type_scr1_req_fifo_s [0:0] req_fifo;
|
|
`else // SCR1_DMEM_AHB_OUT_BP
|
|
type_scr1_req_fifo_s [0:SCR1_FIFO_WIDTH-1] req_fifo;
|
|
type_scr1_req_fifo_s [0:SCR1_FIFO_WIDTH-1] req_fifo_new;
|
|
logic [SCR1_FIFO_CNT_WIDTH-1:0] req_fifo_cnt;
|
|
logic [SCR1_FIFO_CNT_WIDTH-1:0] req_fifo_cnt_new;
|
|
`endif // SCR1_DMEM_AHB_OUT_BP
|
|
logic req_fifo_empty;
|
|
logic req_fifo_full;
|
|
|
|
type_scr1_data_fifo_s data_fifo;
|
|
type_scr1_resp_fifo_s resp_fifo;
|
|
logic resp_fifo_hready;
|
|
|
|
//-------------------------------------------------------------------------------
|
|
// Interface to Core
|
|
//-------------------------------------------------------------------------------
|
|
assign dmem_req_ack = ~req_fifo_full;
|
|
assign req_fifo_wr = ~req_fifo_full & dmem_req;
|
|
|
|
assign dmem_rdata = scr1_conv_ahb2mem_rdata(resp_fifo.hwidth, resp_fifo.haddr, resp_fifo.hrdata);
|
|
|
|
assign dmem_resp = (resp_fifo_hready)
|
|
? (resp_fifo.hresp == SCR1_HRESP_OKAY)
|
|
? SCR1_MEM_RESP_RDY_OK
|
|
: SCR1_MEM_RESP_RDY_ER
|
|
: SCR1_MEM_RESP_NOTRDY ;
|
|
|
|
//-------------------------------------------------------------------------------
|
|
// REQ_FIFO
|
|
//-------------------------------------------------------------------------------
|
|
`ifdef SCR1_DMEM_AHB_OUT_BP
|
|
always_ff @(negedge rst_n, posedge clk) begin
|
|
if (~rst_n) begin
|
|
req_fifo_full <= 1'b0;
|
|
end else begin
|
|
if (~req_fifo_full) begin
|
|
req_fifo_full <= dmem_req & ~req_fifo_rd;
|
|
end else begin
|
|
req_fifo_full <= ~req_fifo_rd;
|
|
end
|
|
end
|
|
end
|
|
assign req_fifo_empty = ~(req_fifo_full | dmem_req);
|
|
|
|
assign req_fifo_up = ~req_fifo_rd & req_fifo_wr;
|
|
always_ff @(posedge clk) begin
|
|
if (req_fifo_up) begin
|
|
req_fifo_r <= req_fifo_new;
|
|
end
|
|
end
|
|
|
|
assign req_fifo_new.hwrite = dmem_req ? (dmem_cmd == SCR1_MEM_CMD_WR) : 1'b0;
|
|
assign req_fifo_new.hwidth = dmem_req ? scr1_conv_mem2ahb_width(dmem_width) : '0;
|
|
assign req_fifo_new.haddr = dmem_req ? dmem_addr : '0;
|
|
assign req_fifo_new.hwdata = (dmem_req & (dmem_cmd == SCR1_MEM_CMD_WR))
|
|
? scr1_conv_mem2ahb_wdata(dmem_addr[1:0], dmem_width, dmem_wdata)
|
|
: '0;
|
|
assign req_fifo[0] = (req_fifo_full) ? req_fifo_r: req_fifo_new;
|
|
|
|
`else // SCR1_DMEM_AHB_OUT_BP
|
|
always_comb begin
|
|
req_fifo_up = 1'b0;
|
|
req_fifo_cnt_new = req_fifo_cnt;
|
|
req_fifo_new = req_fifo;
|
|
case ({req_fifo_rd, req_fifo_wr})
|
|
2'b00 : begin
|
|
// nothing todo
|
|
end
|
|
2'b01: begin
|
|
// FIFO write
|
|
req_fifo_up = 1'b1;
|
|
req_fifo_new[req_fifo_cnt].hwrite = (dmem_cmd == SCR1_MEM_CMD_WR);
|
|
req_fifo_new[req_fifo_cnt].hwidth = scr1_conv_mem2ahb_width(dmem_width);
|
|
req_fifo_new[req_fifo_cnt].haddr = dmem_addr;
|
|
req_fifo_new[req_fifo_cnt].hwdata = scr1_conv_mem2ahb_wdata(dmem_addr[1:0], dmem_width, dmem_wdata);
|
|
req_fifo_cnt_new = req_fifo_cnt + 1'b1;
|
|
end
|
|
2'b10 : begin
|
|
// FIFO read
|
|
req_fifo_up = 1'b1;
|
|
req_fifo_new[0] = req_fifo_new[1];
|
|
req_fifo_new[1].hwrite = 1'b0;
|
|
req_fifo_new[1].hwidth = SCR1_HSIZE_32B;
|
|
`ifdef SCR1_XPROP_EN
|
|
req_fifo_new[1].haddr = 'x;
|
|
req_fifo_new[1].hwdata = 'x;
|
|
`endif // SCR1_XPROP_EN
|
|
req_fifo_cnt_new = req_fifo_cnt - 1'b1;
|
|
end
|
|
2'b11 : begin
|
|
// Read and Write FIFO. It is possible only when fifo_cnt = 1
|
|
req_fifo_up = 1'b1;
|
|
req_fifo_new[0].hwrite = (dmem_cmd == SCR1_MEM_CMD_WR);
|
|
req_fifo_new[0].hwidth = scr1_conv_mem2ahb_width(dmem_width);
|
|
req_fifo_new[0].haddr = dmem_addr;
|
|
req_fifo_new[0].hwdata = scr1_conv_mem2ahb_wdata(dmem_addr[1:0], dmem_width, dmem_wdata);
|
|
end
|
|
default : begin
|
|
`ifdef SCR1_XPROP_EN
|
|
req_fifo_up = 'x;
|
|
req_fifo_cnt_new = 'x;
|
|
req_fifo_new = 'x;
|
|
`endif // SCR1_XPROP_EN
|
|
end
|
|
endcase
|
|
end
|
|
|
|
always_ff @(negedge rst_n, posedge clk) begin
|
|
if (~rst_n) begin
|
|
req_fifo_cnt <= '0;
|
|
end else begin
|
|
if (req_fifo_up) begin
|
|
req_fifo_cnt <= req_fifo_cnt_new;
|
|
end
|
|
end
|
|
end
|
|
assign req_fifo_full = (req_fifo_cnt == SCR1_FIFO_WIDTH);
|
|
assign req_fifo_empty = ~(|req_fifo_cnt);
|
|
|
|
always_ff @(posedge clk) begin
|
|
if (req_fifo_up) begin
|
|
req_fifo <= req_fifo_new;
|
|
end
|
|
end
|
|
`endif // SCR1_DMEM_AHB_OUT_BP
|
|
//-------------------------------------------------------------------------------
|
|
// FSM
|
|
//-------------------------------------------------------------------------------
|
|
always_ff @(negedge rst_n, posedge clk) begin
|
|
if (~rst_n) begin
|
|
fsm <= SCR1_FSM_ADDR;
|
|
end else begin
|
|
case (fsm)
|
|
SCR1_FSM_ADDR : begin
|
|
if (hready) begin
|
|
fsm <= (req_fifo_empty) ? SCR1_FSM_ADDR : SCR1_FSM_DATA;
|
|
end
|
|
end
|
|
SCR1_FSM_DATA : begin
|
|
if (hready) begin
|
|
if (hresp == SCR1_HRESP_OKAY) begin
|
|
fsm <= (req_fifo_empty) ? SCR1_FSM_ADDR : SCR1_FSM_DATA;
|
|
end else begin
|
|
fsm <= SCR1_FSM_ADDR;
|
|
end
|
|
end
|
|
end
|
|
default : begin
|
|
`ifdef SCR1_XPROP_EN
|
|
fsm <= SCR1_FSM_ERR;
|
|
`endif // SCR1_XPROP_EN
|
|
end
|
|
endcase
|
|
end
|
|
end
|
|
|
|
always_comb begin
|
|
req_fifo_rd = 1'b0;
|
|
case (fsm)
|
|
SCR1_FSM_ADDR : begin
|
|
if (hready) begin
|
|
req_fifo_rd = ~req_fifo_empty;
|
|
end
|
|
end
|
|
SCR1_FSM_DATA : begin
|
|
if (hready) begin
|
|
req_fifo_rd = ~req_fifo_empty & (hresp == SCR1_HRESP_OKAY);
|
|
end
|
|
end
|
|
default : begin
|
|
req_fifo_rd = 1'bx;
|
|
end
|
|
endcase
|
|
end
|
|
|
|
//-------------------------------------------------------------------------------
|
|
// FIFO data
|
|
//-------------------------------------------------------------------------------
|
|
always_ff @(posedge clk) begin
|
|
case (fsm)
|
|
SCR1_FSM_ADDR : begin
|
|
if (~req_fifo_empty) begin
|
|
data_fifo.hwidth <= req_fifo[0].hwidth;
|
|
data_fifo.haddr <= req_fifo[0].haddr[1:0];
|
|
data_fifo.hwdata <= req_fifo[0].hwdata;
|
|
end
|
|
end
|
|
SCR1_FSM_DATA : begin
|
|
if (hready) begin
|
|
if (hresp == SCR1_HRESP_OKAY) begin
|
|
if (~req_fifo_empty) begin
|
|
data_fifo.hwidth <= req_fifo[0].hwidth;
|
|
data_fifo.haddr <= req_fifo[0].haddr[1:0];
|
|
data_fifo.hwdata <= req_fifo[0].hwdata;
|
|
end
|
|
end
|
|
end
|
|
end
|
|
default : begin
|
|
end
|
|
endcase
|
|
end
|
|
|
|
//-------------------------------------------------------------------------------
|
|
// FIFO response
|
|
//-------------------------------------------------------------------------------
|
|
`ifdef SCR1_DMEM_AHB_IN_BP
|
|
assign resp_fifo_hready = (fsm == SCR1_FSM_DATA) ? hready : 1'b0;
|
|
assign resp_fifo.hresp = hresp;
|
|
assign resp_fifo.hwidth = data_fifo.hwidth;
|
|
assign resp_fifo.haddr = data_fifo.haddr;
|
|
assign resp_fifo.hrdata = hrdata;
|
|
`else // SCR1_DMEM_AHB_IN_BP
|
|
always_ff @(negedge rst_n, posedge clk) begin
|
|
if (~rst_n) begin
|
|
resp_fifo_hready <= 1'b0;
|
|
end else begin
|
|
resp_fifo_hready <= (fsm == SCR1_FSM_DATA) ? hready : 1'b0;
|
|
end
|
|
end
|
|
|
|
always_ff @(posedge clk) begin
|
|
if (hready & (fsm == SCR1_FSM_DATA)) begin
|
|
resp_fifo.hresp <= hresp;
|
|
resp_fifo.hwidth <= data_fifo.hwidth;
|
|
resp_fifo.haddr <= data_fifo.haddr;
|
|
resp_fifo.hrdata <= hrdata;
|
|
end
|
|
end
|
|
`endif // SCR1_DMEM_AHB_IN_BP
|
|
|
|
//-------------------------------------------------------------------------------
|
|
// Interface to AHB
|
|
//-------------------------------------------------------------------------------
|
|
assign hprot[SCR1_HPROT_DATA] = 1'b1;
|
|
assign hprot[SCR1_HPROT_PRV] = 1'b0;
|
|
assign hprot[SCR1_HPROT_BUF] = 1'b0;
|
|
assign hprot[SCR1_HPROT_CACHE] = 1'b0;
|
|
|
|
assign hburst = SCR1_HBURST_SINGLE;
|
|
assign hsize = req_fifo[0].hwidth;
|
|
assign hmastlock = 1'b0;
|
|
|
|
always_comb begin
|
|
htrans = SCR1_HTRANS_IDLE;
|
|
case (fsm)
|
|
SCR1_FSM_ADDR : begin
|
|
if (~req_fifo_empty) begin
|
|
htrans = SCR1_HTRANS_NONSEQ;
|
|
end
|
|
end
|
|
SCR1_FSM_DATA : begin
|
|
if (hready) begin
|
|
if (hresp == SCR1_HRESP_OKAY) begin
|
|
if (~req_fifo_empty) begin
|
|
htrans = SCR1_HTRANS_NONSEQ;
|
|
end
|
|
end
|
|
end
|
|
end
|
|
default : begin
|
|
htrans = SCR1_HTRANS_ERR;
|
|
end
|
|
endcase
|
|
end
|
|
|
|
assign haddr = req_fifo[0].haddr;
|
|
assign hwrite = req_fifo[0].hwrite;
|
|
assign hwdata = data_fifo.hwdata;
|
|
|
|
endmodule : scr1_dmem_ahb
|