OpenCores
URL https://opencores.org/ocsvn/yifive/yifive/trunk

Subversion Repositories yifive

[/] [yifive/] [trunk/] [caravel_yifive/] [verilog/] [rtl/] [syntacore/] [scr1/] [src/] [top/] [scr1_mem_axi.sv] - Rev 11

Go to most recent revision | Compare with Previous | Blame | View Log

/// Copyright by Syntacore LLC © 2016-2020. See LICENSE for details
/// @file       <scr1_mem_axi.sv>
/// @brief      Memory AXI bridge
///

`include "scr1_memif.svh"
`include "scr1_arch_description.svh"

module scr1_mem_axi
#(
    parameter SCR1_REQ_BUF_SIZE     = 2,                    // Power of 2 value
    parameter SCR1_AXI_IDWIDTH      = 4,
    parameter SCR1_ADDR_WIDTH       = 32,
    parameter SCR1_AXI_REQ_BP       = 1,
    parameter SCR1_AXI_RESP_BP      = 1
)
(
    // Clock and Reset
    input   logic                           clk,
    input   logic                           rst_n,
    input   logic                           axi_reinit,
    // Core Interface
    output  logic                           core_idle,
    output  logic                           core_req_ack,
    input   logic                           core_req,
    input   type_scr1_mem_cmd_e             core_cmd,
    input   type_scr1_mem_width_e           core_width,
    input   logic [SCR1_ADDR_WIDTH-1:0]     core_addr,
    input   logic [31:0]                    core_wdata,
    output  logic [31:0]                    core_rdata,
    output  type_scr1_mem_resp_e            core_resp,

    // AXI
    output  logic [SCR1_AXI_IDWIDTH-1:0]    awid,
    output  logic [SCR1_ADDR_WIDTH-1:0]     awaddr,
    output  logic [ 7:0]                    awlen,
    output  logic [ 2:0]                    awsize,
    output  logic [ 1:0]                    awburst,
    output  logic                           awlock,
    output  logic [ 3:0]                    awcache,
    output  logic [ 2:0]                    awprot,
    output  logic [ 3:0]                    awregion,
    output  logic [ 3:0]                    awuser,
    output  logic [ 3:0]                    awqos,
    output  logic                           awvalid,
    input   logic                           awready,
    output  logic [31:0]                    wdata,
    output  logic [3:0]                     wstrb,
    output  logic                           wlast,
    output  logic [3:0]                     wuser,
    output  logic                           wvalid,
    input   logic                           wready,
    input   logic [SCR1_AXI_IDWIDTH-1:0]    bid,
    input   logic [ 1:0]                    bresp,
    input   logic                           bvalid,
    input   logic [ 3:0]                    buser,
    output  logic                           bready,
    output  logic [SCR1_AXI_IDWIDTH-1:0]    arid,
    output  logic [SCR1_ADDR_WIDTH-1:0]     araddr,
    output  logic [ 7:0]                    arlen,
    output  logic [ 2:0]                    arsize,
    output  logic [ 1:0]                    arburst,
    output  logic                           arlock,
    output  logic [ 3:0]                    arcache,
    output  logic [ 2:0]                    arprot,
    output  logic [ 3:0]                    arregion,
    output  logic [ 3:0]                    aruser,
    output  logic [ 3:0]                    arqos,
    output  logic                           arvalid,
    input   logic                           arready,
    input   logic [SCR1_AXI_IDWIDTH-1:0]    rid,
    input   logic [31:0]                    rdata,
    input   logic [ 1:0]                    rresp,
    input   logic                           rlast,
    input   logic [ 3:0]                    ruser,
    input   logic                           rvalid,
    output  logic                           rready
);


// Local functions
function automatic logic [2:0] width2axsize (
    input   type_scr1_mem_width_e    width );
    logic [2:0] axsize;
begin
    case (width)
        SCR1_MEM_WIDTH_BYTE :  axsize = 3'b000;
        SCR1_MEM_WIDTH_HWORD:  axsize = 3'b001;
        SCR1_MEM_WIDTH_WORD :  axsize = 3'b010;
                     default:  axsize = 'x;
    endcase

    width2axsize = axsize; // cp.11
end
endfunction

typedef struct packed {
    type_scr1_mem_width_e                               axi_width;
    logic                    [SCR1_ADDR_WIDTH-1:0]      axi_addr;
    logic                                   [31:0]      axi_wdata;
} type_scr1_request_s;

typedef struct packed {
    logic                                               req_write;
    logic                                               req_addr;
    logic                                               req_data;
    logic                                               req_resp;
} type_scr1_req_status_s;


//type_scr1_request_s         [SCR1_REQ_BUF_SIZE-1:0]   req_fifo;
logic [1:0]                                             req_fifo_axi_width[SCR1_REQ_BUF_SIZE-1:0];
logic [SCR1_ADDR_WIDTH-1:0]                             req_fifo_axi_addr [SCR1_REQ_BUF_SIZE-1:0];
logic [31:0]                                            req_fifo_axi_wdata [SCR1_REQ_BUF_SIZE-1:0];
//type_scr1_req_status_s      [SCR1_REQ_BUF_SIZE-1:0]   req_status;
logic   [SCR1_REQ_BUF_SIZE-1:0]                         req_status_req_write ;
logic   [SCR1_REQ_BUF_SIZE-1:0]                         req_status_req_addr ;
logic   [SCR1_REQ_BUF_SIZE-1:0]                         req_status_req_data ;
logic   [SCR1_REQ_BUF_SIZE-1:0]                         req_status_req_resp ;
//type_scr1_req_status_s      [SCR1_REQ_BUF_SIZE-1:0]   req_status_new;
logic   [SCR1_REQ_BUF_SIZE-1:0]                         req_status_new_req_write ;
logic   [SCR1_REQ_BUF_SIZE-1:0]                         req_status_new_req_addr ;
logic   [SCR1_REQ_BUF_SIZE-1:0]                         req_status_new_req_data ;
logic   [SCR1_REQ_BUF_SIZE-1:0]                         req_status_new_req_resp ;

logic                       [SCR1_REQ_BUF_SIZE-1:0]     req_status_en;
logic               [$clog2(SCR1_REQ_BUF_SIZE)-1:0]     req_aval_ptr;
logic               [$clog2(SCR1_REQ_BUF_SIZE)-1:0]     req_proc_ptr;
logic               [$clog2(SCR1_REQ_BUF_SIZE)-1:0]     req_done_ptr;
logic                                                   rresp_err;
logic                                       [31:0]      rcvd_rdata;
type_scr1_mem_resp_e                                    rcvd_resp;
logic                                                   force_read;
logic                                                   force_write;



assign core_req_ack =   ~axi_reinit                        &
                        ~req_status_req_resp[req_aval_ptr] &
                         core_resp!=SCR1_MEM_RESP_RDY_ER;


assign rready      = ~req_status_req_write[req_done_ptr];
assign bready      =  req_status_req_write[req_done_ptr];


assign force_read  = SCR1_AXI_REQ_BP & core_req & core_req_ack & req_aval_ptr==req_proc_ptr & core_cmd==SCR1_MEM_CMD_RD;
assign force_write = SCR1_AXI_REQ_BP & core_req & core_req_ack & req_aval_ptr==req_proc_ptr & core_cmd==SCR1_MEM_CMD_WR;

integer i;
always_comb begin: idle_status
    core_idle = 1'b1;
    for (i=0; i<SCR1_REQ_BUF_SIZE; i=i+1) begin
        core_idle &= req_status_req_resp[i]==1'b0;
    end
end

always_ff @(posedge clk) begin
    if (core_req & core_req_ack) begin
        req_fifo_axi_width[req_aval_ptr] <= core_width;
        req_fifo_axi_addr[req_aval_ptr]  <= core_addr;
        req_fifo_axi_wdata[req_aval_ptr] <= core_wdata;
    end
end

// Request Status Queue
// It is used for holding control info of processing requests

// Combinational logic of Request Status Queue
always_comb begin
    // Default
    req_status_en  = '0; // No update
    req_status_new_req_write = req_status_req_write; // Hold request info
    req_status_new_req_addr  = req_status_req_addr; // Hold request info
    req_status_new_req_data  = req_status_req_data; // Hold request info
    req_status_new_req_resp  = req_status_req_resp; // Hold request info

    // Update status on new core request
    if( core_req & core_req_ack ) begin
        req_status_en[req_aval_ptr]            = 1'd1;

        req_status_new_req_resp[req_aval_ptr]  = 1'd1;
        req_status_new_req_write[req_aval_ptr] = core_cmd == SCR1_MEM_CMD_WR;

        req_status_new_req_addr[req_aval_ptr]  = ~( (force_read & arready) |
                                                    (force_write & awready) );

        req_status_new_req_data[req_aval_ptr]  = ~( (force_write & wready & awlen == 8'd0) |
                                                    (~force_write & core_cmd == SCR1_MEM_CMD_RD) );
    end

    // Update status on AXI address phase
    if ( (awvalid & awready) | (arvalid & arready) ) begin
        req_status_en[req_proc_ptr]           = 1'd1;
        req_status_new_req_addr[req_proc_ptr] = 1'd0;
    end

    // Update status on AXI data phase
    if ( wvalid & wready & wlast ) begin
        req_status_en[req_proc_ptr]           = 1'd1;
        req_status_new_req_data[req_proc_ptr] = 1'd0;
    end

    // Update status when AXI finish transaction
    if ( (bvalid & bready) | (rvalid & rready & rlast) ) begin
        req_status_en[req_done_ptr]           = 1'd1;
        req_status_new_req_resp[req_done_ptr] = 1'd0;
    end
end

// Request Status Queue register
integer j;
always_ff @(negedge rst_n, posedge clk) begin
    if (~rst_n) begin
        req_status_req_write <= '0;
        req_status_req_addr <= '0;
        req_status_req_data <= '0;
        req_status_req_resp <= '0;
    end else begin
        for (j = 0; j < SCR1_REQ_BUF_SIZE; j = j+1) begin // cp.4
            if ( req_status_en[j] ) begin
                req_status_req_write[j] <= req_status_new_req_write[j];
                req_status_req_addr[j]  <= req_status_new_req_addr[j];
                req_status_req_data[j]  <= req_status_new_req_data[j];
                req_status_req_resp[j]  <= req_status_new_req_resp[j];
            end
        end
    end
end

always_ff @(negedge rst_n, posedge clk) begin
    if (~rst_n)                         req_aval_ptr <= '0;
    else if (core_req & core_req_ack)   req_aval_ptr <= req_aval_ptr + 1'b1;
end

always_ff @(negedge rst_n, posedge clk) begin
    if (~rst_n) begin
        req_proc_ptr <= '0;
    end else begin
        if ((                                                    awvalid & awready & wvalid & wready & wlast) |
            (~force_write & ~req_status_req_data[req_proc_ptr] & awvalid & awready                          ) |
            (~force_write & ~req_status_req_addr[req_proc_ptr] &                     wvalid & wready & wlast) |
            (               ~req_status_req_data[req_proc_ptr] & arvalid & arready                          )  ) begin

            req_proc_ptr <= req_proc_ptr + 1'b1;
        end
    end
end

always_ff @(negedge rst_n, posedge clk) begin
    if (~rst_n) begin
        req_done_ptr <= '0;
    end else begin
        if ((bvalid & bready | rvalid & rready & rlast) & req_status_req_resp[req_done_ptr]) begin

            req_done_ptr <= req_done_ptr + 1'b1;
        end
    end
end



assign arvalid = req_status_req_addr[req_proc_ptr] & ~req_status_req_write[req_proc_ptr] | force_read;
assign awvalid = req_status_req_addr[req_proc_ptr] &  req_status_req_write[req_proc_ptr] | force_write;
assign  wvalid = req_status_req_data[req_proc_ptr] &  req_status_req_write[req_proc_ptr] | force_write;

assign araddr  = (~force_read )? req_fifo_axi_addr[req_proc_ptr] : core_addr;
assign awaddr  = (~force_write)? req_fifo_axi_addr[req_proc_ptr] : core_addr;

always_comb begin
    if (bvalid & bready & req_status_req_resp[req_done_ptr]) begin
        rcvd_resp = (bresp==2'b00)? SCR1_MEM_RESP_RDY_OK :
                                    SCR1_MEM_RESP_RDY_ER;
    end else begin
        if (rvalid & rready & rlast & req_status_req_resp[req_done_ptr]) begin
            rcvd_resp = (rresp==2'b00)? SCR1_MEM_RESP_RDY_OK :
                                        SCR1_MEM_RESP_RDY_ER;
        end else begin
            rcvd_resp = SCR1_MEM_RESP_NOTRDY;
        end
    end
end


wire [SCR1_ADDR_WIDTH-1:0] CurAddr1 = req_fifo_axi_addr[req_proc_ptr];
wire [1:0]  bShift1 = CurAddr1[1:0];

// Write data signals adaptation
always_comb begin
    if (force_write)
        case (core_width)
            SCR1_MEM_WIDTH_BYTE :  wstrb = 4'h1 << core_addr[1:0];
            SCR1_MEM_WIDTH_HWORD:  wstrb = 4'h3 << core_addr[1:0];
            SCR1_MEM_WIDTH_WORD :  wstrb = 4'hf << core_addr[1:0];
                         default:  wstrb = 'x;
        endcase
    else
        case (req_fifo_axi_width[req_proc_ptr])
            SCR1_MEM_WIDTH_BYTE :  wstrb = 4'h1 << bShift1;
            SCR1_MEM_WIDTH_HWORD:  wstrb = 4'h3 << bShift1;
            SCR1_MEM_WIDTH_WORD :  wstrb = 4'hf << bShift1;
                         default:  wstrb = 'x;
        endcase
end



assign wdata = (force_write)?                       core_wdata << (8*                       core_addr[1:0]) :
                              req_fifo_axi_wdata[req_proc_ptr] << (8* bShift1);


// Read data adaptation
always_comb begin
   case (req_fifo_axi_width[req_done_ptr])
        SCR1_MEM_WIDTH_BYTE :  rcvd_rdata = rdata >> (8*bShift2);
        SCR1_MEM_WIDTH_HWORD:  rcvd_rdata = rdata >> (8*bShift2);
        SCR1_MEM_WIDTH_WORD :  rcvd_rdata = rdata >> (8*bShift2);
        default:  rcvd_rdata = 'x;
    endcase 
end


generate
    if (SCR1_AXI_RESP_BP == 1) begin : axi_resp_bp
        assign core_rdata = (rvalid & rready & rlast) ? rcvd_rdata : '0;
        assign core_resp  = (axi_reinit) ? SCR1_MEM_RESP_NOTRDY : rcvd_resp;
    end else begin : axi_resp_no_bp
        always_ff @(negedge rst_n, posedge clk) begin
            if (~rst_n)              core_resp  <= SCR1_MEM_RESP_NOTRDY;
            else                     core_resp  <= (axi_reinit) ? SCR1_MEM_RESP_NOTRDY : rcvd_resp;
        end
        always_ff @(posedge clk) begin
            if (rvalid & rready & rlast) core_rdata <= rcvd_rdata;
        end
    end
endgenerate



// AXI interface assignments
assign awid     = SCR1_AXI_IDWIDTH'(1);
assign awlen    = 8'd0;
assign awsize   = (force_write) ? width2axsize(core_width) : width2axsize(req_fifo_axi_width[req_proc_ptr]);
assign awburst  = 2'd1;
assign awcache  = 4'd2;
assign awlock   = '0;
assign awprot   = '0;
assign awregion = '0;
assign awuser   = '0;
assign awqos    = '0;

assign arid     = SCR1_AXI_IDWIDTH'(0);
assign arlen    = 8'd0;
assign arsize   = (force_read) ? width2axsize(core_width) : width2axsize(req_fifo_axi_width[req_proc_ptr]);
assign arburst  = 2'd1;
assign arcache  = 4'd2;
assign arprot   = '0;
assign arregion = '0;
assign arlock   = '0;
assign arqos    = '0;
assign aruser   = '0;

assign wlast    = 1'd1;
assign wuser    = '0;


`ifdef SCR1_TRGT_SIMULATION
//-------------------------------------------------------------------------------
// Assertion
//-------------------------------------------------------------------------------

// X checks
SCR1_SVA_AXI_X_CHECK0  : assert property (@(negedge clk) disable iff (~rst_n)   !$isunknown({core_req, awready, wready, bvalid, arready, rvalid}) )
                                                                                                        else $error("AXI bridge: X state on input");
SCR1_SVA_AXI_X_CHECK1  : assert property (@(negedge clk) disable iff (~rst_n)   core_req |->
                                                                                    !$isunknown({core_cmd, core_width, core_addr}) )
                                                                                                        else $error("AXI bridge: X state on input");
SCR1_SVA_AXI_X_CHECK2  : assert property (@(negedge clk) disable iff (~rst_n)   bvalid |->
                                                                                    !$isunknown({bid, bresp}) )
                                                                                                        else $error("AXI bridge: X state on input");
SCR1_SVA_AXI_X_CHECK3  : assert property (@(negedge clk) disable iff (~rst_n)   rvalid |->
                                                                                    !$isunknown({rid, rresp}) )
                                                                                                        else $error("AXI bridge: X state on input");
`endif // SCR1_TRGT_SIMULATION

endmodule : scr1_mem_axi

Go to most recent revision | Compare with Previous | Blame | View Log

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.