Project Full coverage report
Current view: Cores-VeeR-EL2—Cores-VeeR-EL2—design—lib—ahb_to_axi4.sv Coverage Hit Total
Test Date: 27-12-2024 Toggle 92.5% 49 53
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              :    CHECK_RANGES = 1,
      28              :    `include "el2_param.vh"
      29              : )
      30              : (
      31     75475744 :    input                   clk,
      32           35 :    input                   rst_l,
      33              :    /* pragma coverage off */
      34              :    input                   scan_mode,
      35              :    /* pragma coverage on */
      36           23 :    input                   bus_clk_en,
      37            0 :    input                   clk_override,
      38              : 
      39              :    // AXI signals
      40              :    // AXI Write Channels
      41       247142 :    output logic            axi_awvalid,
      42       247163 :    input  logic            axi_awready,
      43              :    /* exclude signals that are tied to constant value in this file */
      44              :    /*pragma coverage off*/
      45              :    output logic [TAG-1:0]  axi_awid,
      46              :    /*pragma coverage on*/
      47       338210 :    output logic [31:0]     axi_awaddr,
      48       185915 :    output logic [2:0]      axi_awsize,
      49              :    /* exclude signals that are tied to constant value in this file */
      50              :    /*pragma coverage off*/
      51              :    output logic [2:0]      axi_awprot,
      52              :    output logic [7:0]      axi_awlen,
      53              :    output logic [1:0]      axi_awburst,
      54              :    /*pragma coverage on*/
      55              : 
      56       247142 :    output logic            axi_wvalid,
      57       247067 :    input  logic            axi_wready,
      58        49638 :    output logic [63:0]     axi_wdata,
      59       205881 :    output logic [7:0]      axi_wstrb,
      60              :    /* exclude signals that are tied to constant value in this file */
      61              :    /*pragma coverage off*/
      62              :    output logic            axi_wlast,
      63              :    /*pragma coverage on*/
      64              : 
      65       247044 :    input  logic            axi_bvalid,
      66              :    /* exclude signals that are tied to constant value in this file */
      67              :    /*pragma coverage off*/
      68              :    output logic            axi_bready,
      69              :    /*pragma coverage on*/
      70            2 :    input  logic [1:0]      axi_bresp,
      71              :    /* Exclude unused AXI rid since it has no equivalent in AHB */
      72              :    /*pragma coverage off*/
      73              :    input  logic [TAG-1:0]  axi_bid,
      74              :    /*pragma coverage on*/
      75              : 
      76              :    // AXI Read Channels
      77       537688 :    output logic            axi_arvalid,
      78       537749 :    input  logic            axi_arready,
      79              :    /* exclude signals that are tied to constant value in this file */
      80              :    /*pragma coverage off*/
      81              :    output logic [TAG-1:0]  axi_arid,
      82              :    /*pragma coverage on*/
      83       338210 :    output logic [31:0]     axi_araddr,
      84       185915 :    output logic [2:0]      axi_arsize,
      85              :    /* exclude signals that are tied to constant value in this file */
      86              :    /*pragma coverage off*/
      87              :    output logic [2:0]      axi_arprot,
      88              :    output logic [7:0]      axi_arlen,
      89              :    output logic [1:0]      axi_arburst,
      90              :    /*pragma coverage on*/
      91              : 
      92       537686 :    input  logic            axi_rvalid,
      93              :    /* exclude signals that are tied to constant value in this file */
      94              :    /*pragma coverage off*/
      95              :    output logic            axi_rready,
      96              :    /*pragma coverage on*/
      97              :    /* Exclude unused AXI rid since it has no equivalent in AHB */
      98              :    /*pragma coverage off*/
      99              :    input  logic [TAG-1:0]  axi_rid,
     100              :    /*pragma coverage on*/
     101        14595 :    input  logic [63:0]     axi_rdata,
     102            2 :    input  logic [1:0]      axi_rresp,
     103              : 
     104              :    // AHB-Lite signals
     105       339180 :    input logic [31:0]      ahb_haddr,     // ahb bus address
     106              :    // Exclude input signals that are unused in this file (their AXI equivalents
     107              :    // are tied to constants)
     108              :    /*pragma coverage off*/
     109              :    input logic [2:0]       ahb_hburst,    // tied to 0
     110              :    input logic             ahb_hmastlock, // tied to 0
     111              :    input logic [3:0]       ahb_hprot,     // tied to 4'b0011
     112              :    /*pragma coverage on*/
     113       186275 :    input logic [2:0]       ahb_hsize,     // size of bus transaction (possible values 0,1,2,3)
     114       783453 :    input logic [1:0]       ahb_htrans,    // Transaction type (possible values 0,2 only right now)
     115       185255 :    input logic             ahb_hwrite,    // ahb bus write
     116       131450 :    input logic [63:0]      ahb_hwdata,    // ahb bus write data
     117           35 :    input logic             ahb_hsel,      // this slave was selected
     118           23 :    input logic             ahb_hreadyin,  // previous hready was accepted or not
     119              : 
     120        14578 :    output logic [63:0]      ahb_hrdata,      // ahb bus read data
     121       537714 :    output logic             ahb_hreadyout,   // slave ready to accept transaction
     122            0 :    output logic             ahb_hresp        // slave response (high indicates erro)
     123              : 
     124              : );
     125              : 
     126       205881 :    logic [7:0]       master_wstrb;
     127              : 
     128              :  typedef enum logic [1:0] {   IDLE   = 2'b00,    // Nothing in the buffer. No commands yet recieved
     129              :                               WR     = 2'b01,    // Write Command recieved
     130              :                               RD     = 2'b10,    // Read Command recieved
     131              :                               PEND   = 2'b11     // Waiting on Read Data from core
     132              :                             } state_t;
     133       969967 :    state_t      buf_state, buf_nxtstate;
     134      1320523 :    logic        buf_state_en;
     135              : 
     136              :    // Buffer signals (one entry buffer)
     137            0 :    logic                    buf_read_error_in, buf_read_error;
     138        14578 :    logic [63:0]             buf_rdata;
     139              : 
     140       537714 :    logic                    ahb_hready;
     141       537724 :    logic                    ahb_hready_q;
     142       783453 :    logic [1:0]              ahb_htrans_in, ahb_htrans_q;
     143       185915 :    logic [2:0]              ahb_hsize_q;
     144       185252 :    logic                    ahb_hwrite_q;
     145       338210 :    logic [31:0]             ahb_haddr_q;
     146            0 :    logic                    ahb_hresp_q;
     147              : 
     148              :    // signals needed for the read data coming back from the core and to block any further commands as AHB is a blocking bus
     149       537686 :    logic                    buf_rdata_en;
     150              : 
     151       784835 :    logic                    ahb_addr_clk_en, buf_rdata_clk_en;
     152        12224 :    logic                    bus_clk, ahb_addr_clk, buf_rdata_clk;
     153              :    // Command buffer is the holding station where we convert to AXI and send to core
     154       784834 :    logic                    cmdbuf_wr_en, cmdbuf_rst;
     155          206 :    logic                    cmdbuf_full;
     156       784830 :    logic                    cmdbuf_vld, cmdbuf_write;
     157       185915 :    logic [1:0]              cmdbuf_size;
     158       205881 :    logic [7:0]              cmdbuf_wstrb;
     159       338210 :    logic [31:0]             cmdbuf_addr;
     160        49638 :    logic [63:0]             cmdbuf_wdata;
     161              : 
     162              : // FSM to control the bus states and when to block the hready and load the command buffer
     163     23719916 :    always_comb begin
     164     23719916 :       buf_nxtstate      = IDLE;
     165     23719916 :       buf_state_en      = 1'b0;
     166     23719916 :       buf_rdata_en      = 1'b0;              // signal to load the buffer when the core sends read data back
     167     23719916 :       buf_read_error_in = 1'b0;              // signal indicating that an error came back with the read from the core
     168     23719916 :       cmdbuf_wr_en      = 1'b0;              // all clear from the gasket to load the buffer with the command for reads, command/dat for writes
     169     23719916 :       case (buf_state)
     170     22778942 :          IDLE: begin  // No commands recieved
     171     22778942 :                   buf_nxtstate      = ahb_hwrite ? WR : RD;
     172     22778942 :                   buf_state_en      = ahb_hready & ahb_htrans[1] & ahb_hsel;                 // only transition on a valid hrtans
     173              :           end
     174       126516 :          WR: begin // Write command recieved last cycle
     175       126516 :                   buf_nxtstate      = (ahb_hresp | (ahb_htrans[1:0] == 2'b0) | ~ahb_hsel) ? IDLE : ahb_hwrite  ? WR : RD;
     176       126516 :                   buf_state_en      = (~cmdbuf_full | ahb_hresp) ;
     177       126516 :                   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.
     178              :          end
     179       270934 :          RD: begin // Read command recieved last cycle.
     180       270934 :                  buf_nxtstate      = ahb_hresp ? IDLE :PEND;                                       // If error go to idle, else wait for read data
     181       270934 :                  buf_state_en      = (~cmdbuf_full | ahb_hresp);                                   // only when command can go, or if its an error
     182       270934 :                  cmdbuf_wr_en      = ~ahb_hresp & ~cmdbuf_full;                                    // send command only when no error
     183              :          end
     184       543524 :          PEND: begin // Read Command has been sent. Waiting on Data.
     185       543524 :                  buf_nxtstate      = IDLE;                                                          // go back for next command and present data next cycle
     186       543524 :                  buf_state_en      = axi_rvalid & ~cmdbuf_write;                                    // read data is back
     187       543524 :                  buf_rdata_en      = buf_state_en;                                                  // buffer the read data coming back from core
     188       543524 :                  buf_read_error_in = buf_state_en & |axi_rresp[1:0];                                // buffer error flag if return has Error ( ECC )
     189              :          end
     190              :      endcase
     191              :    end // always_comb begin
     192              : 
     193              :     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));
     194              : 
     195              :    assign master_wstrb[7:0]   = ({8{ahb_hsize_q[2:0] == 3'b0}}  & (8'b1    << ahb_haddr_q[2:0])) |
     196              :                                 ({8{ahb_hsize_q[2:0] == 3'b1}}  & (8'b11   << ahb_haddr_q[2:0])) |
     197              :                                 ({8{ahb_hsize_q[2:0] == 3'b10}} & (8'b1111 << ahb_haddr_q[2:0])) |
     198              :                                 ({8{ahb_hsize_q[2:0] == 3'b11}} & 8'b1111_1111);
     199              : 
     200              :    // AHB signals
     201              :    assign ahb_hreadyout       = ahb_hresp ? (ahb_hresp_q & ~ahb_hready_q) :
     202              :                                          ((~cmdbuf_full | (buf_state == IDLE)) & ~(buf_state == RD | buf_state == PEND)  & ~buf_read_error);
     203              : 
     204              :    assign ahb_hready          = ahb_hreadyout & ahb_hreadyin;
     205              :    assign ahb_htrans_in[1:0]  = {2{ahb_hsel}} & ahb_htrans[1:0];
     206              :    assign ahb_hrdata[63:0]    = buf_rdata[63:0];
     207              : 
     208              :    if (CHECK_RANGES) begin
     209              :        // Miscellaneous signals
     210              :        logic                    ahb_addr_in_dccm, ahb_addr_in_iccm, ahb_addr_in_pic;
     211              :        logic                    ahb_addr_in_dccm_region_nc, ahb_addr_in_iccm_region_nc, ahb_addr_in_pic_region_nc;
     212              : 
     213              :        assign ahb_hresp    = ((ahb_htrans_q[1:0] != 2'b0) & (buf_state != IDLE)  &
     214              :                              ((~(ahb_addr_in_dccm | ahb_addr_in_iccm)) |                                                                                   // request not for ICCM or DCCM
     215              :                              ((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
     216              :                              ((ahb_hsize_q[2:0] == 3'h1) & ahb_haddr_q[0])   |                                                                             // HW size but unaligned
     217              :                              ((ahb_hsize_q[2:0] == 3'h2) & (|ahb_haddr_q[1:0])) |                                                                          // W size but unaligned
     218              :                              ((ahb_hsize_q[2:0] == 3'h3) & (|ahb_haddr_q[2:0])))) |                                                                        // DW size but unaligned
     219              :                              buf_read_error |                                                                                                              // Read ECC error
     220              :                              (ahb_hresp_q & ~ahb_hready_q);
     221              : 
     222              :        // Address check  dccm
     223              :        rvrangecheck #(.CCM_SADR(pt.DCCM_SADR),
     224              :                       .CCM_SIZE(pt.DCCM_SIZE)) addr_dccm_rangecheck (
     225              :           .addr(ahb_haddr_q[31:0]),
     226              :           .in_range(ahb_addr_in_dccm),
     227              :           .in_region(ahb_addr_in_dccm_region_nc)
     228              :        );
     229              : 
     230              :       // Address check  iccm
     231              :       if (pt.ICCM_ENABLE == 1) begin: GenICCM
     232              :          rvrangecheck #(.CCM_SADR(pt.ICCM_SADR),
     233              :                         .CCM_SIZE(pt.ICCM_SIZE)) addr_iccm_rangecheck (
     234              :             .addr(ahb_haddr_q[31:0]),
     235              :             .in_range(ahb_addr_in_iccm),
     236              :             .in_region(ahb_addr_in_iccm_region_nc)
     237              :          );
     238              :       end else begin: GenNoICCM
     239              :          assign ahb_addr_in_iccm = '0;
     240              :          assign ahb_addr_in_iccm_region_nc = '0;
     241              :       end
     242              : 
     243              :       // PIC memory address check
     244              :       rvrangecheck #(.CCM_SADR(pt.PIC_BASE_ADDR),
     245              :                      .CCM_SIZE(pt.PIC_SIZE)) addr_pic_rangecheck (
     246              :          .addr(ahb_haddr_q[31:0]),
     247              :          .in_range(ahb_addr_in_pic),
     248              :          .in_region(ahb_addr_in_pic_region_nc)
     249              :       );
     250              :    end else begin // !CHECK_RANGES
     251              :        assign ahb_hresp    = ((ahb_htrans_q[1:0] != 2'b0) & (buf_state != IDLE)  &
     252              :                              (((ahb_hsize_q[2:0] == 3'h1) & ahb_haddr_q[0]) |       // HW size but unaligned
     253              :                              ((ahb_hsize_q[2:0] == 3'h2) & (|ahb_haddr_q[1:0])) |   // W size but unaligned
     254              :                              ((ahb_hsize_q[2:0] == 3'h3) & (|ahb_haddr_q[2:0])))) | // DW size but unaligned
     255              :                              buf_read_error |                                       // Read ECC error
     256              :                              (ahb_hresp_q & ~ahb_hready_q);
     257              :    end // CHECK_RANGES
     258              : 
     259              :    // Buffer signals - needed for the read data and ECC error response
     260              :    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), .*);
     261              :    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
     262              : 
     263              :    // All the Master signals are captured before presenting it to the command buffer. We check for Hresp before sending it to the cmd buffer.
     264              :    rvdff_fpga #(.WIDTH(1))  hresp_ff  (.din(ahb_hresp),          .dout(ahb_hresp_q),       .clk(bus_clk),      .clken(bus_clk_en),      .rawclk(clk), .*);
     265              :    rvdff_fpga #(.WIDTH(1))  hready_ff (.din(ahb_hready),         .dout(ahb_hready_q),      .clk(bus_clk),      .clken(bus_clk_en),      .rawclk(clk), .*);
     266              :    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), .*);
     267              :    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), .*);
     268              :    rvdff_fpga #(.WIDTH(1))  hwrite_ff (.din(ahb_hwrite),         .dout(ahb_hwrite_q),      .clk(ahb_addr_clk), .clken(ahb_addr_clk_en), .rawclk(clk), .*);
     269              :    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), .*);
     270              : 
     271              :    // Command Buffer - Holding for the commands to be sent for the AXI. It will be converted to the AXI signals.
     272              :    assign cmdbuf_rst         = (((axi_awvalid & axi_awready) | (axi_arvalid & axi_arready)) & ~cmdbuf_wr_en) | (ahb_hresp & ~cmdbuf_write);
     273              :    assign cmdbuf_full        = (cmdbuf_vld & ~((axi_awvalid & axi_awready) | (axi_arvalid & axi_arready)));
     274              : 
     275              :    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), .*);
     276              :    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), .*);
     277              :    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), .*);
     278              :    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), .*);
     279              :    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), .*);
     280              :    rvdffe       #(.WIDTH(64)) cmdbuf_wdataff    (.din(ahb_hwdata[63:0]),  .dout(cmdbuf_wdata[63:0]), .en(cmdbuf_wr_en & bus_clk_en),        .clk(clk), .*);
     281              : 
     282              :    // AXI Write Command Channel
     283              :    assign axi_awvalid           = cmdbuf_vld & cmdbuf_write;
     284              :    assign axi_awid[TAG-1:0]     = '0;
     285              :    assign axi_awaddr[31:0]      = cmdbuf_addr[31:0];
     286              :    assign axi_awsize[2:0]       = {1'b0, cmdbuf_size[1:0]};
     287              :    assign axi_awprot[2:0]       = 3'b0;
     288              :    assign axi_awlen[7:0]        = '0;
     289              :    assign axi_awburst[1:0]      = 2'b01;
     290              :    // AXI Write Data Channel - This is tied to the command channel as we only write the command buffer once we have the data.
     291              :    assign axi_wvalid            = cmdbuf_vld & cmdbuf_write;
     292              :    assign axi_wdata[63:0]       = cmdbuf_wdata[63:0];
     293              :    assign axi_wstrb[7:0]        = cmdbuf_wstrb[7:0];
     294              :    assign axi_wlast             = 1'b1;
     295              :   // AXI Write Response - Always ready. AHB does not require a write response.
     296              :    assign axi_bready            = 1'b1;
     297              :    // AXI Read Channels
     298              :    assign axi_arvalid           = cmdbuf_vld & ~cmdbuf_write;
     299              :    assign axi_arid[TAG-1:0]     = '0;
     300              :    assign axi_araddr[31:0]      = cmdbuf_addr[31:0];
     301              :    assign axi_arsize[2:0]       = {1'b0, cmdbuf_size[1:0]};
     302              :    assign axi_arprot            = 3'b0;
     303              :    assign axi_arlen[7:0]        = '0;
     304              :    assign axi_arburst[1:0]      = 2'b01;
     305              :    // AXI Read Response Channel - Always ready as AHB reads are blocking and the the buffer is available for the read coming back always.
     306              :    assign axi_rready            = 1'b1;
     307              : 
     308              :    // Clock header logic
     309              :    assign ahb_addr_clk_en = bus_clk_en & (ahb_hready & ahb_htrans[1]);
     310              :    assign buf_rdata_clk_en    = bus_clk_en & buf_rdata_en;
     311              : 
     312              : `ifdef RV_FPGA_OPTIMIZE
     313              :    assign bus_clk = 1'b0;
     314              :    assign ahb_addr_clk = 1'b0;
     315              :    assign buf_rdata_clk = 1'b0;
     316              : `else
     317              :    rvclkhdr bus_cgc       (.en(bus_clk_en),       .l1clk(bus_clk),       .*);
     318              :    rvclkhdr ahb_addr_cgc  (.en(ahb_addr_clk_en),  .l1clk(ahb_addr_clk),  .*);
     319              :    rvclkhdr buf_rdata_cgc (.en(buf_rdata_clk_en), .l1clk(buf_rdata_clk), .*);
     320              : `endif
     321              : 
     322              : `ifdef RV_ASSERT_ON
     323              :    property ahb_error_protocol;
     324              :       @(posedge bus_clk) (ahb_hready & ahb_hresp) |-> (~$past(ahb_hready) & $past(ahb_hresp));
     325              :    endproperty
     326              :    assert_ahb_error_protocol: assert property (ahb_error_protocol) else
     327              :       $display("Bus Error with hReady isn't preceded with Bus Error without hready");
     328              : 
     329              : `endif
     330              : 
     331              : endmodule // ahb_to_axi4