Project Full coverage report
Current view: Cores-VeeR-EL2—Cores-VeeR-EL2—design—lib—ahb_to_axi4.sv Coverage Hit Total
Test Date: 19-09-2024 Toggle 64.4% 47 73
Test: all Branch 100.0% 23 23

            Line data    Source code
       1              : // SPDX-License-Identifier: Apache-2.0
       2              : // Copyright 2020 Western Digital Corporation or its affiliates.
       3              : //
       4              : // Licensed under the Apache License, Version 2.0 (the "License");
       5              : // you may not use this file except in compliance with the License.
       6              : // You may obtain a copy of the License at
       7              : //
       8              : // http://www.apache.org/licenses/LICENSE-2.0
       9              : //
      10              : // Unless required by applicable law or agreed to in writing, software
      11              : // distributed under the License is distributed on an "AS IS" BASIS,
      12              : // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      13              : // See the License for the specific language governing permissions and
      14              : // limitations under the License.
      15              : //********************************************************************************
      16              : // $Id$
      17              : //
      18              : // Owner:
      19              : // Function: AHB to AXI4 Bridge
      20              : // Comments:
      21              : //
      22              : //********************************************************************************
      23              : module ahb_to_axi4
      24              : import el2_pkg::*;
      25              : #(
      26              :    TAG = 1,
      27              :    `include "el2_param.vh"
      28              : )
      29              : //   ,TAG  = 1)
      30              : (
      31     27232830 :    input                   clk,
      32           32 :    input                   rst_l,
      33            0 :    input                   scan_mode,
      34           20 :    input                   bus_clk_en,
      35            0 :    input                   clk_override,
      36              : 
      37              :    // AXI signals
      38              :    // AXI Write Channels
      39          402 :    output logic            axi_awvalid,
      40          418 :    input  logic            axi_awready,
      41            0 :    output logic [TAG-1:0]  axi_awid,
      42           14 :    output logic [31:0]     axi_awaddr,
      43            0 :    output logic [2:0]      axi_awsize,
      44            0 :    output logic [2:0]      axi_awprot,
      45            0 :    output logic [7:0]      axi_awlen,
      46            0 :    output logic [1:0]      axi_awburst,
      47              : 
      48          402 :    output logic            axi_wvalid,
      49          322 :    input  logic            axi_wready,
      50           89 :    output logic [63:0]     axi_wdata,
      51           14 :    output logic [7:0]      axi_wstrb,
      52           20 :    output logic            axi_wlast,
      53              : 
      54          302 :    input  logic            axi_bvalid,
      55           20 :    output logic            axi_bready,
      56            0 :    input  logic [1:0]      axi_bresp,
      57            0 :    input  logic [TAG-1:0]  axi_bid,
      58              : 
      59              :    // AXI Read Channels
      60          202 :    output logic            axi_arvalid,
      61          220 :    input  logic            axi_arready,
      62            0 :    output logic [TAG-1:0]  axi_arid,
      63           14 :    output logic [31:0]     axi_araddr,
      64            0 :    output logic [2:0]      axi_arsize,
      65            0 :    output logic [2:0]      axi_arprot,
      66            0 :    output logic [7:0]      axi_arlen,
      67            0 :    output logic [1:0]      axi_arburst,
      68              : 
      69          200 :    input  logic            axi_rvalid,
      70           20 :    output logic            axi_rready,
      71            0 :    input  logic [TAG-1:0]  axi_rid,
      72           38 :    input  logic [63:0]     axi_rdata,
      73            0 :    input  logic [1:0]      axi_rresp,
      74              : 
      75              :    // AHB-Lite signals
      76            2 :    input logic [31:0]      ahb_haddr,     // ahb bus address
      77            0 :    input logic [2:0]       ahb_hburst,    // tied to 0
      78            0 :    input logic             ahb_hmastlock, // tied to 0
      79            0 :    input logic [3:0]       ahb_hprot,     // tied to 4'b0011
      80            0 :    input logic [2:0]       ahb_hsize,     // size of bus transaction (possible values 0,1,2,3)
      81          606 :    input logic [1:0]       ahb_htrans,    // Transaction type (possible values 0,2 only right now)
      82            1 :    input logic             ahb_hwrite,    // ahb bus write
      83           87 :    input logic [63:0]      ahb_hwdata,    // ahb bus write data
      84           20 :    input logic             ahb_hsel,      // this slave was selected
      85           20 :    input logic             ahb_hreadyin,  // previous hready was accepted or not
      86              : 
      87           38 :    output logic [63:0]      ahb_hrdata,      // ahb bus read data
      88          223 :    output logic             ahb_hreadyout,   // slave ready to accept transaction
      89            0 :    output logic             ahb_hresp        // slave response (high indicates erro)
      90              : 
      91              : );
      92              : 
      93            2 :    logic [7:0]       master_wstrb;
      94              : 
      95              :  typedef enum logic [1:0] {   IDLE   = 2'b00,    // Nothing in the buffer. No commands yet recieved
      96              :                               WR     = 2'b01,    // Write Command recieved
      97              :                               RD     = 2'b10,    // Read Command recieved
      98              :                               PEND   = 2'b11     // Waiting on Read Data from core
      99              :                             } state_t;
     100          221 :    state_t      buf_state, buf_nxtstate;
     101          806 :    logic        buf_state_en;
     102              : 
     103              :    // Buffer signals (one entry buffer)
     104            0 :    logic                    buf_read_error_in, buf_read_error;
     105           38 :    logic [63:0]             buf_rdata;
     106              : 
     107          223 :    logic                    ahb_hready;
     108          233 :    logic                    ahb_hready_q;
     109          606 :    logic [1:0]              ahb_htrans_in, ahb_htrans_q;
     110            0 :    logic [2:0]              ahb_hsize_q;
     111            9 :    logic                    ahb_hwrite_q;
     112           14 :    logic [31:0]             ahb_haddr_q;
     113            0 :    logic [63:0]             ahb_hwdata_q;
     114            0 :    logic                    ahb_hresp_q;
     115              : 
     116              :     //Miscellaneous signals
     117            0 :    logic                    ahb_addr_in_dccm, ahb_addr_in_iccm, ahb_addr_in_pic;
     118           14 :    logic                    ahb_addr_in_dccm_region_nc, ahb_addr_in_iccm_region_nc, ahb_addr_in_pic_region_nc;
     119              :    // signals needed for the read data coming back from the core and to block any further commands as AHB is a blocking bus
     120          200 :    logic                    buf_rdata_en;
     121              : 
     122          200 :    logic                    ahb_addr_clk_en, buf_rdata_clk_en;
     123          200 :    logic                    bus_clk, ahb_addr_clk, buf_rdata_clk;
     124              :    // Command buffer is the holding station where we convert to AXI and send to core
     125          602 :    logic                    cmdbuf_wr_en, cmdbuf_rst;
     126          202 :    logic                    cmdbuf_full;
     127            9 :    logic                    cmdbuf_vld, cmdbuf_write;
     128           14 :    logic [1:0]              cmdbuf_size;
     129           14 :    logic [7:0]              cmdbuf_wstrb;
     130           14 :    logic [31:0]             cmdbuf_addr;
     131           89 :    logic [63:0]             cmdbuf_wdata;
     132              : 
     133              : // FSM to control the bus states and when to block the hready and load the command buffer
     134           20 :    always_comb begin
     135           20 :       buf_nxtstate      = IDLE;
     136           20 :       buf_state_en      = 1'b0;
     137           20 :       buf_rdata_en      = 1'b0;              // signal to load the buffer when the core sends read data back
     138           20 :       buf_read_error_in = 1'b0;              // signal indicating that an error came back with the read from the core
     139           20 :       cmdbuf_wr_en      = 1'b0;              // all clear from the gasket to load the buffer with the command for reads, command/dat for writes
     140           20 :       case (buf_state)
     141      6964055 :          IDLE: begin  // No commands recieved
     142      6964055 :                   buf_nxtstate      = ahb_hwrite ? WR : RD;
     143      6964055 :                   buf_state_en      = ahb_hready & ahb_htrans[1] & ahb_hsel;                 // only transition on a valid hrtans
     144              :           end
     145         2210 :          WR: begin // Write command recieved last cycle
     146         2210 :                   buf_nxtstate      = (ahb_hresp | (ahb_htrans[1:0] == 2'b0) | ~ahb_hsel) ? IDLE : ahb_hwrite  ? WR : RD;
     147         2210 :                   buf_state_en      = (~cmdbuf_full | ahb_hresp) ;
     148         2210 :                   cmdbuf_wr_en      = ~cmdbuf_full & ~(ahb_hresp | ((ahb_htrans[1:0] == 2'b01) & ahb_hsel));   // Dont send command to the buffer in case of an error or when the master is not ready with the data now.
     149              :          end
     150          606 :          RD: begin // Read command recieved last cycle.
     151          606 :                  buf_nxtstate      = ahb_hresp ? IDLE :PEND;                                       // If error go to idle, else wait for read data
     152          606 :                  buf_state_en      = (~cmdbuf_full | ahb_hresp);                                   // only when command can go, or if its an error
     153          606 :                  cmdbuf_wr_en      = ~ahb_hresp & ~cmdbuf_full;                                    // send command only when no error
     154              :          end
     155         4248 :          PEND: begin // Read Command has been sent. Waiting on Data.
     156         4248 :                  buf_nxtstate      = IDLE;                                                          // go back for next command and present data next cycle
     157         4248 :                  buf_state_en      = axi_rvalid & ~cmdbuf_write;                                    // read data is back
     158         4248 :                  buf_rdata_en      = buf_state_en;                                                  // buffer the read data coming back from core
     159         4248 :                  buf_read_error_in = buf_state_en & |axi_rresp[1:0];                                // buffer error flag if return has Error ( ECC )
     160              :          end
     161              :      endcase
     162              :    end // always_comb begin
     163              : 
     164              :     rvdffs_fpga #($bits(state_t)) state_reg (.*, .din(buf_nxtstate), .dout({buf_state}), .en(buf_state_en), .clk(bus_clk), .clken(bus_clk_en), .rawclk(clk));
     165              : 
     166              :    assign master_wstrb[7:0]   = ({8{ahb_hsize_q[2:0] == 3'b0}}  & (8'b1    << ahb_haddr_q[2:0])) |
     167              :                                 ({8{ahb_hsize_q[2:0] == 3'b1}}  & (8'b11   << ahb_haddr_q[2:0])) |
     168              :                                 ({8{ahb_hsize_q[2:0] == 3'b10}} & (8'b1111 << ahb_haddr_q[2:0])) |
     169              :                                 ({8{ahb_hsize_q[2:0] == 3'b11}} & 8'b1111_1111);
     170              : 
     171              :    // AHB signals
     172              :    assign ahb_hreadyout       = ahb_hresp ? (ahb_hresp_q & ~ahb_hready_q) :
     173              :                                          ((~cmdbuf_full | (buf_state == IDLE)) & ~(buf_state == RD | buf_state == PEND)  & ~buf_read_error);
     174              : 
     175              :    assign ahb_hready          = ahb_hreadyout & ahb_hreadyin;
     176              :    assign ahb_htrans_in[1:0]  = {2{ahb_hsel}} & ahb_htrans[1:0];
     177              :    assign ahb_hrdata[63:0]    = buf_rdata[63:0];
     178              :    assign ahb_hresp        = ((ahb_htrans_q[1:0] != 2'b0) & (buf_state != IDLE)  &
     179              : 
     180              :                              ((~(ahb_addr_in_dccm | ahb_addr_in_iccm)) |                                                                                   // request not for ICCM or DCCM
     181              :                              ((ahb_addr_in_iccm | (ahb_addr_in_dccm &  ahb_hwrite_q)) & ~((ahb_hsize_q[1:0] == 2'b10) | (ahb_hsize_q[1:0] == 2'b11))) |    // ICCM Rd/Wr OR DCCM Wr not the right size
     182              :                              ((ahb_hsize_q[2:0] == 3'h1) & ahb_haddr_q[0])   |                                                                             // HW size but unaligned
     183              :                              ((ahb_hsize_q[2:0] == 3'h2) & (|ahb_haddr_q[1:0])) |                                                                          // W size but unaligned
     184              :                              ((ahb_hsize_q[2:0] == 3'h3) & (|ahb_haddr_q[2:0])))) |                                                                        // DW size but unaligned
     185              :                              buf_read_error |                                                                                                              // Read ECC error
     186              :                              (ahb_hresp_q & ~ahb_hready_q);
     187              : 
     188              :    // Buffer signals - needed for the read data and ECC error response
     189              :    rvdff_fpga  #(.WIDTH(64)) buf_rdata_ff     (.din(axi_rdata[63:0]),   .dout(buf_rdata[63:0]), .clk(buf_rdata_clk), .clken(buf_rdata_clk_en), .rawclk(clk), .*);
     190              :    rvdff_fpga  #(.WIDTH(1))  buf_read_error_ff(.din(buf_read_error_in), .dout(buf_read_error),  .clk(bus_clk),       .clken(bus_clk_en),       .rawclk(clk), .*);          // buf_read_error will be high only one cycle
     191              : 
     192              :    // All the Master signals are captured before presenting it to the command buffer. We check for Hresp before sending it to the cmd buffer.
     193              :    rvdff_fpga #(.WIDTH(1))  hresp_ff  (.din(ahb_hresp),          .dout(ahb_hresp_q),       .clk(bus_clk),      .clken(bus_clk_en),      .rawclk(clk), .*);
     194              :    rvdff_fpga #(.WIDTH(1))  hready_ff (.din(ahb_hready),         .dout(ahb_hready_q),      .clk(bus_clk),      .clken(bus_clk_en),      .rawclk(clk), .*);
     195              :    rvdff_fpga #(.WIDTH(2))  htrans_ff (.din(ahb_htrans_in[1:0]), .dout(ahb_htrans_q[1:0]), .clk(bus_clk),      .clken(bus_clk_en),      .rawclk(clk), .*);
     196              :    rvdff_fpga #(.WIDTH(3))  hsize_ff  (.din(ahb_hsize[2:0]),     .dout(ahb_hsize_q[2:0]),  .clk(ahb_addr_clk), .clken(ahb_addr_clk_en), .rawclk(clk), .*);
     197              :    rvdff_fpga #(.WIDTH(1))  hwrite_ff (.din(ahb_hwrite),         .dout(ahb_hwrite_q),      .clk(ahb_addr_clk), .clken(ahb_addr_clk_en), .rawclk(clk), .*);
     198              :    rvdff_fpga #(.WIDTH(32)) haddr_ff  (.din(ahb_haddr[31:0]),    .dout(ahb_haddr_q[31:0]), .clk(ahb_addr_clk), .clken(ahb_addr_clk_en), .rawclk(clk), .*);
     199              : 
     200              :    // Address check  dccm
     201              :    rvrangecheck #(.CCM_SADR(pt.DCCM_SADR),
     202              :                   .CCM_SIZE(pt.DCCM_SIZE)) addr_dccm_rangecheck (
     203              :       .addr(ahb_haddr_q[31:0]),
     204              :       .in_range(ahb_addr_in_dccm),
     205              :       .in_region(ahb_addr_in_dccm_region_nc)
     206              :    );
     207              : 
     208              :    // Address check  iccm
     209              :    if (pt.ICCM_ENABLE == 1) begin: GenICCM
     210              :       rvrangecheck #(.CCM_SADR(pt.ICCM_SADR),
     211              :                      .CCM_SIZE(pt.ICCM_SIZE)) addr_iccm_rangecheck (
     212              :          .addr(ahb_haddr_q[31:0]),
     213              :          .in_range(ahb_addr_in_iccm),
     214              :          .in_region(ahb_addr_in_iccm_region_nc)
     215              :       );
     216              :    end else begin: GenNoICCM
     217              :       assign ahb_addr_in_iccm = '0;
     218              :       assign ahb_addr_in_iccm_region_nc = '0;
     219              :    end
     220              : 
     221              :    // PIC memory address check
     222              :    rvrangecheck #(.CCM_SADR(pt.PIC_BASE_ADDR),
     223              :                   .CCM_SIZE(pt.PIC_SIZE)) addr_pic_rangecheck (
     224              :       .addr(ahb_haddr_q[31:0]),
     225              :       .in_range(ahb_addr_in_pic),
     226              :       .in_region(ahb_addr_in_pic_region_nc)
     227              :    );
     228              : 
     229              :    // Command Buffer - Holding for the commands to be sent for the AXI. It will be converted to the AXI signals.
     230              :    assign cmdbuf_rst         = (((axi_awvalid & axi_awready) | (axi_arvalid & axi_arready)) & ~cmdbuf_wr_en) | (ahb_hresp & ~cmdbuf_write);
     231              :    assign cmdbuf_full        = (cmdbuf_vld & ~((axi_awvalid & axi_awready) | (axi_arvalid & axi_arready)));
     232              : 
     233              :    rvdffsc_fpga #(.WIDTH(1))  cmdbuf_vldff      (.din(1'b1),              .dout(cmdbuf_vld),         .en(cmdbuf_wr_en), .clear(cmdbuf_rst), .clk(bus_clk), .clken(bus_clk_en), .rawclk(clk), .*);
     234              :    rvdffs_fpga  #(.WIDTH(1))  cmdbuf_writeff    (.din(ahb_hwrite_q),      .dout(cmdbuf_write),       .en(cmdbuf_wr_en),                     .clk(bus_clk), .clken(bus_clk_en), .rawclk(clk), .*);
     235              :    rvdffs_fpga  #(.WIDTH(2))  cmdbuf_sizeff     (.din(ahb_hsize_q[1:0]),  .dout(cmdbuf_size[1:0]),   .en(cmdbuf_wr_en),                     .clk(bus_clk), .clken(bus_clk_en), .rawclk(clk), .*);
     236              :    rvdffs_fpga  #(.WIDTH(8))  cmdbuf_wstrbff    (.din(master_wstrb[7:0]), .dout(cmdbuf_wstrb[7:0]),  .en(cmdbuf_wr_en),                     .clk(bus_clk), .clken(bus_clk_en), .rawclk(clk), .*);
     237              :    rvdffe       #(.WIDTH(32)) cmdbuf_addrff     (.din(ahb_haddr_q[31:0]), .dout(cmdbuf_addr[31:0]),  .en(cmdbuf_wr_en & bus_clk_en),        .clk(clk), .*);
     238              :    rvdffe       #(.WIDTH(64)) cmdbuf_wdataff    (.din(ahb_hwdata[63:0]),  .dout(cmdbuf_wdata[63:0]), .en(cmdbuf_wr_en & bus_clk_en),        .clk(clk), .*);
     239              : 
     240              :    // AXI Write Command Channel
     241              :    assign axi_awvalid           = cmdbuf_vld & cmdbuf_write;
     242              :    assign axi_awid[TAG-1:0]     = '0;
     243              :    assign axi_awaddr[31:0]      = cmdbuf_addr[31:0];
     244              :    assign axi_awsize[2:0]       = {1'b0, cmdbuf_size[1:0]};
     245              :    assign axi_awprot[2:0]       = 3'b0;
     246              :    assign axi_awlen[7:0]        = '0;
     247              :    assign axi_awburst[1:0]      = 2'b01;
     248              :    // AXI Write Data Channel - This is tied to the command channel as we only write the command buffer once we have the data.
     249              :    assign axi_wvalid            = cmdbuf_vld & cmdbuf_write;
     250              :    assign axi_wdata[63:0]       = cmdbuf_wdata[63:0];
     251              :    assign axi_wstrb[7:0]        = cmdbuf_wstrb[7:0];
     252              :    assign axi_wlast             = 1'b1;
     253              :   // AXI Write Response - Always ready. AHB does not require a write response.
     254              :    assign axi_bready            = 1'b1;
     255              :    // AXI Read Channels
     256              :    assign axi_arvalid           = cmdbuf_vld & ~cmdbuf_write;
     257              :    assign axi_arid[TAG-1:0]     = '0;
     258              :    assign axi_araddr[31:0]      = cmdbuf_addr[31:0];
     259              :    assign axi_arsize[2:0]       = {1'b0, cmdbuf_size[1:0]};
     260              :    assign axi_arprot            = 3'b0;
     261              :    assign axi_arlen[7:0]        = '0;
     262              :    assign axi_arburst[1:0]      = 2'b01;
     263              :    // AXI Read Response Channel - Always ready as AHB reads are blocking and the the buffer is available for the read coming back always.
     264              :    assign axi_rready            = 1'b1;
     265              : 
     266              :    // Clock header logic
     267              :    assign ahb_addr_clk_en = bus_clk_en & (ahb_hready & ahb_htrans[1]);
     268              :    assign buf_rdata_clk_en    = bus_clk_en & buf_rdata_en;
     269              : 
     270              : `ifdef RV_FPGA_OPTIMIZE
     271              :    assign bus_clk = 1'b0;
     272              :    assign ahb_addr_clk = 1'b0;
     273              :    assign buf_rdata_clk = 1'b0;
     274              : `else
     275              :    rvclkhdr bus_cgc       (.en(bus_clk_en),       .l1clk(bus_clk),       .*);
     276              :    rvclkhdr ahb_addr_cgc  (.en(ahb_addr_clk_en),  .l1clk(ahb_addr_clk),  .*);
     277              :    rvclkhdr buf_rdata_cgc (.en(buf_rdata_clk_en), .l1clk(buf_rdata_clk), .*);
     278              : `endif
     279              : 
     280              : `ifdef RV_ASSERT_ON
     281              :    property ahb_error_protocol;
     282              :       @(posedge bus_clk) (ahb_hready & ahb_hresp) |-> (~$past(ahb_hready) & $past(ahb_hresp));
     283              :    endproperty
     284              :    assert_ahb_error_protocol: assert property (ahb_error_protocol) else
     285              :       $display("Bus Error with hReady isn't preceded with Bus Error without hready");
     286              : 
     287              : `endif
     288              : 
     289              : endmodule // ahb_to_axi4