|
| 1 | +// Copyright 2024 ETH Zurich and University of Bologna. |
| 2 | +// Solderpad Hardware License, Version 0.51, see LICENSE for details. |
| 3 | +// SPDX-License-Identifier: SHL-0.51 |
| 4 | +// |
| 5 | +// Authors: |
| 6 | +// - Philippe Sauter <phsauter@iis.ee.ethz.ch> |
| 7 | + |
| 8 | +`include "common_cells/registers.svh" |
| 9 | + |
| 10 | +/// Bootrom containing a WFI trampoline. |
| 11 | +/// After reset the core fetches from here, enables the M-mode interrupt |
| 12 | +/// executes WFI, and waits until woken by CLINT msip. |
| 13 | +/// On wake it clears msip, reads the boot address from soc_ctrl and jumps there. |
| 14 | +module bootrom #( |
| 15 | + /// The OBI configuration for all ports. |
| 16 | + parameter obi_pkg::obi_cfg_t ObiCfg = obi_pkg::ObiDefaultConfig, |
| 17 | + /// OBI request type |
| 18 | + parameter type obi_req_t = logic, |
| 19 | + /// OBI response type |
| 20 | + parameter type obi_rsp_t = logic |
| 21 | +) ( |
| 22 | + input logic clk_i, |
| 23 | + input logic rst_ni, |
| 24 | + input obi_req_t obi_req_i, |
| 25 | + output obi_rsp_t obi_rsp_o |
| 26 | +); |
| 27 | + |
| 28 | + // Bootrom contents (9 words, 36 bytes) |
| 29 | + // https://godbolt.org/z/MP5ejvzdf |
| 30 | + localparam int unsigned RomSize = 9; |
| 31 | + localparam logic [31:0] RomData [RomSize] = '{ |
| 32 | + 32'h00800293, // addi t0, zero, 8 # t0 = 8 (MSIE bit) |
| 33 | + 32'h30429073, // csrw mie, t0 # Enable M-mode software interrupt |
| 34 | + 32'h10500073, // wfi # Sleep until interrupt |
| 35 | + 32'h020402b7, // lui t0, 0x02040 # t0 = CLINT base (0x02040000) |
| 36 | + 32'h0002a023, // sw zero, 0(t0) # Clear msip |
| 37 | + 32'h30401073, // csrw mie, zero # Disable interrupts |
| 38 | + 32'h030002b7, // lui t0, 0x03000 # t0 = SOC_CTRL base (0x03000000) |
| 39 | + 32'h0002a283, // lw t0, 0(t0) # t0 = boot address |
| 40 | + 32'h00028067 // jalr zero, 0(t0) # Jump to boot address |
| 41 | + }; |
| 42 | + |
| 43 | + localparam int unsigned AddressWidth = cf_math_pkg::idx_width(RomSize) +2; // in bytes |
| 44 | + |
| 45 | + // Handle OBI requests |
| 46 | + logic we_d, we_q; // delayed to the response phase |
| 47 | + logic req_d, req_q; // delayed to the response phase |
| 48 | + logic [ObiCfg.IdWidth-1:0] id_d, id_q; // delayed to the response phase |
| 49 | + logic [AddressWidth-1:0] read_addr_d, read_addr_q; // delayed to the response phase (word addr) |
| 50 | + |
| 51 | + assign req_d = obi_req_i.req; |
| 52 | + assign we_d = obi_req_i.a.we; |
| 53 | + assign id_d = obi_req_i.a.aid; |
| 54 | + assign read_addr_d = obi_req_i.a.addr[AddressWidth-1:2]; |
| 55 | + |
| 56 | + // Latch request for one-cycle response |
| 57 | + `FF(req_q, req_d, '0, clk_i, rst_ni) |
| 58 | + `FF(we_q, we_d, '0, clk_i, rst_ni) |
| 59 | + `FF(id_q, id_d, '0, clk_i, rst_ni) |
| 60 | + `FF(read_addr_q, read_addr_d, '0, clk_i, rst_ni) |
| 61 | + |
| 62 | + // Address range check |
| 63 | + logic in_range; |
| 64 | + assign in_range = (read_addr_q < RomSize); |
| 65 | + |
| 66 | + always_comb begin |
| 67 | + obi_rsp_o = '0; |
| 68 | + obi_rsp_o.gnt = 1'b1; // always grant |
| 69 | + obi_rsp_o.rvalid = req_q; |
| 70 | + obi_rsp_o.r.rid = id_q; |
| 71 | + if (we_q || !in_range) begin |
| 72 | + // write request or out of range |
| 73 | + obi_rsp_o.r.rdata = 32'hBADCAB1E; |
| 74 | + obi_rsp_o.r.err = 1'b1; |
| 75 | + end else begin |
| 76 | + obi_rsp_o.r.rdata = RomData[read_addr_q]; |
| 77 | + obi_rsp_o.r.err = 1'b0; |
| 78 | + end |
| 79 | + end |
| 80 | + |
| 81 | +endmodule |
0 commit comments