/// Copyright by Syntacore LLC © 2016-2021. See LICENSE for details
|
/// Copyright by Syntacore LLC © 2016-2021. See LICENSE for details
|
/// @file
|
/// @file
|
/// @brief Instruction memory AHB bridge
|
/// @brief Instruction memory AHB bridge
|
///
|
///
|
|
|
`include "scr1_ahb.svh"
|
`include "scr1_ahb.svh"
|
`include "scr1_memif.svh"
|
`include "scr1_memif.svh"
|
|
|
module scr1_imem_ahb (
|
module scr1_imem_ahb (
|
// Control Signals
|
// Control Signals
|
input logic rst_n,
|
input logic rst_n,
|
input logic clk,
|
input logic clk,
|
|
|
// Core Interface
|
// Core Interface
|
output logic imem_req_ack,
|
output logic imem_req_ack,
|
input logic imem_req,
|
input logic imem_req,
|
input logic [SCR1_AHB_WIDTH-1:0] imem_addr,
|
input logic [SCR1_AHB_WIDTH-1:0] imem_addr,
|
output logic [SCR1_AHB_WIDTH-1:0] imem_rdata,
|
output logic [SCR1_AHB_WIDTH-1:0] imem_rdata,
|
output type_scr1_mem_resp_e imem_resp,
|
output logic [1:0] imem_resp,
|
|
|
// AHB Interface
|
// AHB Interface
|
output logic [3:0] hprot,
|
output logic [3:0] hprot,
|
output logic [2:0] hburst,
|
output logic [2:0] hburst,
|
output logic [2:0] hsize,
|
output logic [2:0] hsize,
|
output logic [1:0] htrans,
|
output logic [1:0] htrans,
|
output logic hmastlock,
|
output logic hmastlock,
|
output logic [SCR1_AHB_WIDTH-1:0] haddr,
|
output logic [SCR1_AHB_WIDTH-1:0] haddr,
|
input logic hready,
|
input logic hready,
|
input logic [SCR1_AHB_WIDTH-1:0] hrdata,
|
input logic [SCR1_AHB_WIDTH-1:0] hrdata,
|
input logic hresp
|
input logic hresp
|
|
|
);
|
);
|
|
|
//-------------------------------------------------------------------------------
|
//-------------------------------------------------------------------------------
|
// Local parameters declaration
|
// Local parameters declaration
|
//-------------------------------------------------------------------------------
|
//-------------------------------------------------------------------------------
|
`ifndef SCR1_IMEM_AHB_OUT_BP
|
`ifndef SCR1_IMEM_AHB_OUT_BP
|
localparam SCR1_FIFO_WIDTH = 2;
|
localparam SCR1_FIFO_WIDTH = 2;
|
localparam SCR1_FIFO_CNT_WIDTH = $clog2(SCR1_FIFO_WIDTH+1);
|
localparam SCR1_FIFO_CNT_WIDTH = $clog2(SCR1_FIFO_WIDTH+1);
|
`endif // SCR1_IMEM_AHB_OUT_BP
|
`endif // SCR1_IMEM_AHB_OUT_BP
|
|
|
//-------------------------------------------------------------------------------
|
//-------------------------------------------------------------------------------
|
// Local types declaration
|
// Local types declaration
|
//-------------------------------------------------------------------------------
|
//-------------------------------------------------------------------------------
|
typedef enum logic {
|
typedef enum logic {
|
SCR1_FSM_ADDR = 1'b0,
|
SCR1_FSM_ADDR = 1'b0,
|
SCR1_FSM_DATA = 1'b1,
|
SCR1_FSM_DATA = 1'b1,
|
SCR1_FSM_ERR = 1'bx
|
SCR1_FSM_ERR = 1'bx
|
} type_scr1_fsm_e;
|
} type_scr1_fsm_e;
|
|
|
typedef struct packed {
|
typedef struct packed {
|
logic [SCR1_AHB_WIDTH-1:0] haddr;
|
logic [SCR1_AHB_WIDTH-1:0] haddr;
|
} type_scr1_req_fifo_s;
|
} type_scr1_req_fifo_s;
|
|
|
typedef struct packed {
|
typedef struct packed {
|
logic hresp;
|
logic hresp;
|
logic [SCR1_AHB_WIDTH-1:0] hrdata;
|
logic [SCR1_AHB_WIDTH-1:0] hrdata;
|
} type_scr1_resp_fifo_s;
|
} type_scr1_resp_fifo_s;
|
|
|
//-------------------------------------------------------------------------------
|
//-------------------------------------------------------------------------------
|
// Local signal declaration
|
// Local signal declaration
|
//-------------------------------------------------------------------------------
|
//-------------------------------------------------------------------------------
|
type_scr1_fsm_e fsm;
|
type_scr1_fsm_e fsm;
|
logic req_fifo_rd;
|
logic req_fifo_rd;
|
logic req_fifo_wr;
|
logic req_fifo_wr;
|
logic req_fifo_up;
|
logic req_fifo_up;
|
`ifdef SCR1_IMEM_AHB_OUT_BP
|
`ifdef SCR1_IMEM_AHB_OUT_BP
|
type_scr1_req_fifo_s req_fifo_r;
|
type_scr1_req_fifo_s req_fifo_r;
|
type_scr1_req_fifo_s [0:0] req_fifo;
|
type_scr1_req_fifo_s [0:0] req_fifo;
|
`else // SCR1_IMEM_AHB_OUT_BP
|
`else // SCR1_IMEM_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;
|
type_scr1_req_fifo_s [0:SCR1_FIFO_WIDTH-1] req_fifo_new;
|
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;
|
logic [SCR1_FIFO_CNT_WIDTH-1:0] req_fifo_cnt_new;
|
logic [SCR1_FIFO_CNT_WIDTH-1:0] req_fifo_cnt_new;
|
`endif // SCR1_IMEM_AHB_OUT_BP
|
`endif // SCR1_IMEM_AHB_OUT_BP
|
logic req_fifo_empty;
|
logic req_fifo_empty;
|
logic req_fifo_full;
|
logic req_fifo_full;
|
|
|
type_scr1_resp_fifo_s resp_fifo;
|
type_scr1_resp_fifo_s resp_fifo;
|
logic resp_fifo_hready;
|
logic resp_fifo_hready;
|
|
|
//-------------------------------------------------------------------------------
|
//-------------------------------------------------------------------------------
|
// Interface to Core
|
// Interface to Core
|
//-------------------------------------------------------------------------------
|
//-------------------------------------------------------------------------------
|
assign imem_req_ack = ~req_fifo_full;
|
assign imem_req_ack = ~req_fifo_full;
|
assign req_fifo_wr = ~req_fifo_full & imem_req;
|
assign req_fifo_wr = ~req_fifo_full & imem_req;
|
|
|
assign imem_rdata = resp_fifo.hrdata;
|
assign imem_rdata = resp_fifo.hrdata;
|
|
|
assign imem_resp = (resp_fifo_hready)
|
assign imem_resp = (resp_fifo_hready)
|
? (resp_fifo.hresp == SCR1_HRESP_OKAY)
|
? (resp_fifo.hresp == SCR1_HRESP_OKAY)
|
? SCR1_MEM_RESP_RDY_OK
|
? SCR1_MEM_RESP_RDY_OK
|
: SCR1_MEM_RESP_RDY_ER
|
: SCR1_MEM_RESP_RDY_ER
|
: SCR1_MEM_RESP_NOTRDY;
|
: SCR1_MEM_RESP_NOTRDY;
|
|
|
//-------------------------------------------------------------------------------
|
//-------------------------------------------------------------------------------
|
// REQ_FIFO
|
// REQ_FIFO
|
//-------------------------------------------------------------------------------
|
//-------------------------------------------------------------------------------
|
`ifdef SCR1_IMEM_AHB_OUT_BP
|
`ifdef SCR1_IMEM_AHB_OUT_BP
|
always_ff @(negedge rst_n, posedge clk) begin
|
always_ff @(negedge rst_n, posedge clk) begin
|
if (~rst_n) begin
|
if (~rst_n) begin
|
req_fifo_full <= 1'b0;
|
req_fifo_full <= 1'b0;
|
end else begin
|
end else begin
|
if (~req_fifo_full) begin
|
if (~req_fifo_full) begin
|
req_fifo_full <= imem_req & ~req_fifo_rd;
|
req_fifo_full <= imem_req & ~req_fifo_rd;
|
end else begin
|
end else begin
|
req_fifo_full <= ~req_fifo_rd;
|
req_fifo_full <= ~req_fifo_rd;
|
end
|
end
|
end
|
end
|
end
|
end
|
assign req_fifo_empty = ~(req_fifo_full | imem_req);
|
assign req_fifo_empty = ~(req_fifo_full | imem_req);
|
|
|
assign req_fifo_up = ~req_fifo_rd & req_fifo_wr;
|
assign req_fifo_up = ~req_fifo_rd & req_fifo_wr;
|
always_ff @(posedge clk) begin
|
always_ff @(posedge clk) begin
|
if (req_fifo_up) begin
|
if (req_fifo_up) begin
|
req_fifo_r.haddr <= imem_addr;
|
req_fifo_r.haddr <= imem_addr;
|
end
|
end
|
end
|
end
|
|
|
assign req_fifo[0] = (req_fifo_full) ? req_fifo_r : imem_addr;
|
assign req_fifo[0] = (req_fifo_full) ? req_fifo_r : imem_addr;
|
|
|
`else // SCR1_IMEM_AHB_OUT_BP
|
`else // SCR1_IMEM_AHB_OUT_BP
|
always_comb begin
|
always_comb begin
|
req_fifo_up = 1'b0;
|
req_fifo_up = 1'b0;
|
req_fifo_cnt_new = req_fifo_cnt;
|
req_fifo_cnt_new = req_fifo_cnt;
|
req_fifo_new = req_fifo;
|
req_fifo_new = req_fifo;
|
case ({req_fifo_rd, req_fifo_wr})
|
case ({req_fifo_rd, req_fifo_wr})
|
2'b00 : begin
|
2'b00 : begin
|
// nothing todo
|
// nothing todo
|
end
|
end
|
2'b01: begin
|
2'b01: begin
|
// FIFO write
|
// FIFO write
|
req_fifo_up = 1'b1;
|
req_fifo_up = 1'b1;
|
req_fifo_new[req_fifo_cnt].haddr = imem_addr;
|
req_fifo_new[req_fifo_cnt].haddr = imem_addr;
|
req_fifo_cnt_new = req_fifo_cnt + 1'b1;
|
req_fifo_cnt_new = req_fifo_cnt + 1'b1;
|
end
|
end
|
2'b10 : begin
|
2'b10 : begin
|
// FIFO read
|
// FIFO read
|
req_fifo_up = 1'b1;
|
req_fifo_up = 1'b1;
|
req_fifo_new[0] = req_fifo_new[1];
|
req_fifo_new[0] = req_fifo_new[1];
|
req_fifo_new[1].haddr = 'x;
|
req_fifo_new[1].haddr = 'x;
|
req_fifo_cnt_new = req_fifo_cnt - 1'b1;
|
req_fifo_cnt_new = req_fifo_cnt - 1'b1;
|
end
|
end
|
2'b11 : begin
|
2'b11 : begin
|
// Read and Write FIFO. It is possible only when fifo_cnt = 1
|
// Read and Write FIFO. It is possible only when fifo_cnt = 1
|
req_fifo_up = 1'b1;
|
req_fifo_up = 1'b1;
|
req_fifo_new[0].haddr = imem_addr;
|
req_fifo_new[0].haddr = imem_addr;
|
end
|
end
|
default : begin
|
default : begin
|
req_fifo_up = 'x;
|
req_fifo_up = 'x;
|
req_fifo_cnt_new = 'x;
|
req_fifo_cnt_new = 'x;
|
req_fifo_new = 'x;
|
req_fifo_new = 'x;
|
end
|
end
|
endcase
|
endcase
|
end
|
end
|
|
|
always_ff @(negedge rst_n, posedge clk) begin
|
always_ff @(negedge rst_n, posedge clk) begin
|
if (~rst_n) begin
|
if (~rst_n) begin
|
req_fifo_cnt <= '0;
|
req_fifo_cnt <= '0;
|
end else begin
|
end else begin
|
if (req_fifo_up) begin
|
if (req_fifo_up) begin
|
req_fifo_cnt <= req_fifo_cnt_new;
|
req_fifo_cnt <= req_fifo_cnt_new;
|
end
|
end
|
end
|
end
|
end
|
end
|
assign req_fifo_full = (req_fifo_cnt == SCR1_FIFO_WIDTH);
|
assign req_fifo_full = (req_fifo_cnt == SCR1_FIFO_WIDTH);
|
assign req_fifo_empty = ~(|req_fifo_cnt);
|
assign req_fifo_empty = ~(|req_fifo_cnt);
|
|
|
always_ff @(posedge clk) begin
|
always_ff @(posedge clk) begin
|
if (req_fifo_up) begin
|
if (req_fifo_up) begin
|
req_fifo <= req_fifo_new;
|
req_fifo <= req_fifo_new;
|
end
|
end
|
end
|
end
|
`endif // SCR1_IMEM_AHB_OUT_BP
|
`endif // SCR1_IMEM_AHB_OUT_BP
|
|
|
//-------------------------------------------------------------------------------
|
//-------------------------------------------------------------------------------
|
// FSM
|
// FSM
|
//-------------------------------------------------------------------------------
|
//-------------------------------------------------------------------------------
|
always_ff @(negedge rst_n, posedge clk) begin
|
always_ff @(negedge rst_n, posedge clk) begin
|
if (~rst_n) begin
|
if (~rst_n) begin
|
fsm <= SCR1_FSM_ADDR;
|
fsm <= SCR1_FSM_ADDR;
|
end else begin
|
end else begin
|
case (fsm)
|
case (fsm)
|
SCR1_FSM_ADDR : begin
|
SCR1_FSM_ADDR : begin
|
if (hready) begin
|
if (hready) begin
|
fsm <= (req_fifo_empty) ? SCR1_FSM_ADDR : SCR1_FSM_DATA;
|
fsm <= (req_fifo_empty) ? SCR1_FSM_ADDR : SCR1_FSM_DATA;
|
end
|
end
|
end
|
end
|
SCR1_FSM_DATA : begin
|
SCR1_FSM_DATA : begin
|
if (hready) begin
|
if (hready) begin
|
if (hresp == SCR1_HRESP_OKAY) begin
|
if (hresp == SCR1_HRESP_OKAY) begin
|
fsm <= (req_fifo_empty) ? SCR1_FSM_ADDR : SCR1_FSM_DATA;
|
fsm <= (req_fifo_empty) ? SCR1_FSM_ADDR : SCR1_FSM_DATA;
|
end else begin
|
end else begin
|
fsm <= SCR1_FSM_ADDR;
|
fsm <= SCR1_FSM_ADDR;
|
end
|
end
|
end
|
end
|
end
|
end
|
default : begin
|
default : begin
|
fsm <= SCR1_FSM_ERR;
|
fsm <= SCR1_FSM_ERR;
|
end
|
end
|
endcase
|
endcase
|
end
|
end
|
end
|
end
|
|
|
always_comb begin
|
always_comb begin
|
req_fifo_rd = 1'b0;
|
req_fifo_rd = 1'b0;
|
case (fsm)
|
case (fsm)
|
SCR1_FSM_ADDR : begin
|
SCR1_FSM_ADDR : begin
|
if (hready) begin
|
if (hready) begin
|
req_fifo_rd = ~req_fifo_empty;
|
req_fifo_rd = ~req_fifo_empty;
|
end
|
end
|
end
|
end
|
SCR1_FSM_DATA : begin
|
SCR1_FSM_DATA : begin
|
if (hready) begin
|
if (hready) begin
|
req_fifo_rd = ~req_fifo_empty & (hresp == SCR1_HRESP_OKAY);
|
req_fifo_rd = ~req_fifo_empty & (hresp == SCR1_HRESP_OKAY);
|
end
|
end
|
end
|
end
|
default : begin
|
default : begin
|
req_fifo_rd = 1'bx;
|
req_fifo_rd = 1'bx;
|
end
|
end
|
endcase
|
endcase
|
end
|
end
|
|
|
//-------------------------------------------------------------------------------
|
//-------------------------------------------------------------------------------
|
// FIFO response
|
// FIFO response
|
//-------------------------------------------------------------------------------
|
//-------------------------------------------------------------------------------
|
`ifdef SCR1_IMEM_AHB_IN_BP
|
`ifdef SCR1_IMEM_AHB_IN_BP
|
assign resp_fifo_hready = (fsm == SCR1_FSM_DATA) ? hready : 1'b0;
|
assign resp_fifo_hready = (fsm == SCR1_FSM_DATA) ? hready : 1'b0;
|
assign resp_fifo.hresp = hresp;
|
assign resp_fifo.hresp = hresp;
|
assign resp_fifo.hrdata = hrdata;
|
assign resp_fifo.hrdata = hrdata;
|
`else // SCR1_IMEM_AHB_IN_BP
|
`else // SCR1_IMEM_AHB_IN_BP
|
always_ff @(negedge rst_n, posedge clk) begin
|
always_ff @(negedge rst_n, posedge clk) begin
|
if (~rst_n) begin
|
if (~rst_n) begin
|
resp_fifo_hready <= 1'b0;
|
resp_fifo_hready <= 1'b0;
|
end else begin
|
end else begin
|
resp_fifo_hready <= (fsm == SCR1_FSM_DATA) ? hready : 1'b0;
|
resp_fifo_hready <= (fsm == SCR1_FSM_DATA) ? hready : 1'b0;
|
end
|
end
|
end
|
end
|
|
|
always_ff @(posedge clk) begin
|
always_ff @(posedge clk) begin
|
if (hready & (fsm == SCR1_FSM_DATA)) begin
|
if (hready & (fsm == SCR1_FSM_DATA)) begin
|
resp_fifo.hresp <= hresp;
|
resp_fifo.hresp <= hresp;
|
resp_fifo.hrdata <= hrdata;
|
resp_fifo.hrdata <= hrdata;
|
end
|
end
|
end
|
end
|
`endif // SCR1_IMEM_AHB_IN_BP
|
`endif // SCR1_IMEM_AHB_IN_BP
|
|
|
//-------------------------------------------------------------------------------
|
//-------------------------------------------------------------------------------
|
// Interface to AHB
|
// Interface to AHB
|
//-------------------------------------------------------------------------------
|
//-------------------------------------------------------------------------------
|
assign hprot[SCR1_HPROT_DATA] = 1'b0;
|
assign hprot[SCR1_HPROT_DATA] = 1'b0;
|
assign hprot[SCR1_HPROT_PRV] = 1'b0;
|
assign hprot[SCR1_HPROT_PRV] = 1'b0;
|
assign hprot[SCR1_HPROT_BUF] = 1'b0;
|
assign hprot[SCR1_HPROT_BUF] = 1'b0;
|
assign hprot[SCR1_HPROT_CACHE] = 1'b0;
|
assign hprot[SCR1_HPROT_CACHE] = 1'b0;
|
|
|
assign hburst = SCR1_HBURST_SINGLE;
|
assign hburst = SCR1_HBURST_SINGLE;
|
assign hsize = SCR1_HSIZE_32B;
|
assign hsize = SCR1_HSIZE_32B;
|
assign hmastlock = 1'b0;
|
assign hmastlock = 1'b0;
|
|
|
always_comb begin
|
always_comb begin
|
htrans = SCR1_HTRANS_IDLE;
|
htrans = SCR1_HTRANS_IDLE;
|
case (fsm)
|
case (fsm)
|
SCR1_FSM_ADDR : begin
|
SCR1_FSM_ADDR : begin
|
if (~req_fifo_empty) begin
|
if (~req_fifo_empty) begin
|
htrans = SCR1_HTRANS_NONSEQ;
|
htrans = SCR1_HTRANS_NONSEQ;
|
end
|
end
|
end
|
end
|
SCR1_FSM_DATA : begin
|
SCR1_FSM_DATA : begin
|
if (hready) begin
|
if (hready) begin
|
if (hresp == SCR1_HRESP_OKAY) begin
|
if (hresp == SCR1_HRESP_OKAY) begin
|
if (~req_fifo_empty) begin
|
if (~req_fifo_empty) begin
|
htrans = SCR1_HTRANS_NONSEQ;
|
htrans = SCR1_HTRANS_NONSEQ;
|
end
|
end
|
end
|
end
|
end
|
end
|
end
|
end
|
default : begin
|
default : begin
|
htrans = SCR1_HTRANS_ERR;
|
htrans = SCR1_HTRANS_ERR;
|
end
|
end
|
endcase
|
endcase
|
end
|
end
|
|
|
assign haddr = req_fifo[0].haddr;
|
assign haddr = req_fifo[0].haddr;
|
|
|
`ifdef SCR1_TRGT_SIMULATION
|
`ifdef SCR1_TRGT_SIMULATION
|
//-------------------------------------------------------------------------------
|
//-------------------------------------------------------------------------------
|
// Assertion
|
// Assertion
|
//-------------------------------------------------------------------------------
|
//-------------------------------------------------------------------------------
|
|
|
// Check Core interface
|
// Check Core interface
|
SCR1_SVA_IMEM_AHB_BRIDGE_REQ_XCHECK : assert property (
|
SCR1_SVA_IMEM_AHB_BRIDGE_REQ_XCHECK : assert property (
|
@(negedge clk) disable iff (~rst_n)
|
@(negedge clk) disable iff (~rst_n)
|
!$isunknown(imem_req)
|
!$isunknown(imem_req)
|
) else $error("IMEM AHB bridge Error: imem_req has unknown values");
|
) else $error("IMEM AHB bridge Error: imem_req has unknown values");
|
|
|
SCR1_IMEM_AHB_BRIDGE_ADDR_XCHECK : assert property (
|
SCR1_IMEM_AHB_BRIDGE_ADDR_XCHECK : assert property (
|
@(negedge clk) disable iff (~rst_n)
|
@(negedge clk) disable iff (~rst_n)
|
imem_req |-> !$isunknown(imem_addr)
|
imem_req |-> !$isunknown(imem_addr)
|
) else $error("IMEM AHB bridge Error: imem_addr has unknown values");
|
) else $error("IMEM AHB bridge Error: imem_addr has unknown values");
|
|
|
SCR1_IMEM_AHB_BRIDGE_ADDR_ALLIGN : assert property (
|
SCR1_IMEM_AHB_BRIDGE_ADDR_ALLIGN : assert property (
|
@(negedge clk) disable iff (~rst_n)
|
@(negedge clk) disable iff (~rst_n)
|
imem_req |-> (imem_addr[1:0] == '0)
|
imem_req |-> (imem_addr[1:0] == '0)
|
) else $error("IMEM AHB bridge Error: imem_addr has unalign values");
|
) else $error("IMEM AHB bridge Error: imem_addr has unalign values");
|
|
|
// Check AHB interface
|
// Check AHB interface
|
SCR1_IMEM_AHB_BRIDGE_HREADY_XCHECK : assert property (
|
SCR1_IMEM_AHB_BRIDGE_HREADY_XCHECK : assert property (
|
@(negedge clk) disable iff (~rst_n)
|
@(negedge clk) disable iff (~rst_n)
|
!$isunknown(hready)
|
!$isunknown(hready)
|
) else $error("IMEM AHB bridge Error: hready has unknown values");
|
) else $error("IMEM AHB bridge Error: hready has unknown values");
|
|
|
SCR1_IMEM_AHB_BRIDGE_HRESP_XCHECK : assert property (
|
SCR1_IMEM_AHB_BRIDGE_HRESP_XCHECK : assert property (
|
@(negedge clk) disable iff (~rst_n)
|
@(negedge clk) disable iff (~rst_n)
|
!$isunknown(hresp)
|
!$isunknown(hresp)
|
) else $error("IMEM AHB bridge Error: hresp has unknown values");
|
) else $error("IMEM AHB bridge Error: hresp has unknown values");
|
|
|
`endif // SCR1_TRGT_SIMULATION
|
`endif // SCR1_TRGT_SIMULATION
|
|
|
endmodule : scr1_imem_ahb
|
endmodule : scr1_imem_ahb
|
|
|