Files
Toooba/src_Testbench/Fabrics/AXI4/AXI4_Mem_Model.bsv
rsnikhil 83829590dd Fixed up logic for "Non-Debug-Module reset" request/response from the Debug Module
Now able to run multiple ISA tests in a single simulation run
connected to remote debugger DSharp, using either hart_reset or
ndm_reset between tests to bring the system back into reset state.
All Debug Module commands working:
 - dm_reset, hart_reset, ndm_reset
 - break    (set breakpoint)
 - step
 - continue (until breakpoint of 'halt' command)
 - halt
 - read/write GPR, FPR, CSR, memory
 - elf_load
2020-02-04 16:02:53 -05:00

212 lines
6.5 KiB
Plaintext

// Copyright (c) 2019 Bluespec, Inc. All Rights Reserved.
// Author: Rishiyur S. Nikhil
package AXI4_Mem_Model;
// ================================================================
// A memory-model to be used as a slave on an AXI4 bus.
// Only partical functionality; will be gradually improved over time.
// Current status:
// Address and Data bus widths: 64b
// Bursts: 'fixed' and 'incr' only
// Size: Full 64-bit width reads/writes only
// Strobes: Not yet handled
// memory size: See 'mem_size_word64' definition below
// ================================================================
// Exports
export AXI4_Mem_Model_IFC (..);
export mkAXI4_Mem_Model;
// ================================================================
// Bluespec library imports
import RegFile :: *;
import FIFOF :: *;
import GetPut :: *;
import ClientServer :: *;
// ----------------
// BSV additional libs
import Cur_Cycle :: *;
import GetPut_Aux :: *;
import Semi_FIFOF :: *;
// ================================================================
// Project imports
import AXI4_Types :: *;
// ================================================================
// INTERFACE
interface AXI4_Mem_Model_IFC #(numeric type wd_id,
numeric type wd_addr,
numeric type wd_data,
numeric type wd_user);
method Action init (Bit #(wd_addr) addr_map_base, Bit #(wd_addr) addr_map_lim);
interface AXI4_Slave_IFC #(wd_id, wd_addr, wd_data, wd_user) slave;
endinterface
// ================================================================
// IMPLEMENTATION
Integer mem_size_word64 = 'h100_0000; // 16M x 64b words = 128MiB
function Bool fn_addr_ok (Bit #(64) base, Bit #(64) lim, Bit #(64) addr, AXI4_Size size);
let aligned = fn_addr_is_aligned (addr, size);
let in_range = ((base <= addr) && (addr < lim));
return (aligned && in_range);
endfunction
// ----------------
module mkAXI4_Mem_Model (AXI4_Mem_Model_IFC #(wd_id, wd_addr, wd_data, wd_user))
provisos (NumAlias #(wd_addr, 64),
NumAlias #(wd_data, 64));
// 0 = quiet; 1 = show mem transactions
Integer verbosity = 1;
Reg #(Bool) rg_initialized <- mkReg (False);
Reg #(Bit #(wd_addr)) rg_addr_map_base <- mkRegU;
Reg #(Bit #(wd_addr)) rg_addr_map_lim <- mkRegU;
AXI4_Slave_Xactor_IFC #(wd_id, wd_addr, wd_data, wd_user) xactor <- mkAXI4_Slave_Xactor;
RegFile #(Bit #(wd_addr), Bit #(wd_data)) rf <- mkRegFile (0, fromInteger (mem_size_word64));
// ================================================================
// Read requests
// TODO: does a bad addr return 'burst-len' err responses or just 1?
Reg #(Bit #(8)) rg_rd_beat <- mkReg (0);
// Recv request on RD_ADDR bus
// Send burst responses on RD_DATA bus
rule rl_read (rg_initialized);
let rd_addr = xactor.o_rd_addr.first;
let rf_index = ((rd_addr.araddr - rg_addr_map_base) >> 3);
if (rd_addr.arburst == axburst_incr)
rf_index = rf_index + zeroExtend (rg_rd_beat);
let last = (rg_rd_beat == rd_addr.arlen);
let addr_ok = fn_addr_ok (rg_addr_map_base, rg_addr_map_lim, rd_addr.araddr, rd_addr.arsize);
let data = (addr_ok ? rf.sub (rf_index) : 0);
AXI4_Rd_Data #(wd_id, wd_data, wd_user)
rd_data = AXI4_Rd_Data {rid: rd_addr.arid,
rdata: data,
rresp: (addr_ok ? axi4_resp_okay : axi4_resp_slverr),
rlast: last,
ruser: rd_addr.aruser};
xactor.i_rd_data.enq (rd_data);
if (last) begin
xactor.o_rd_addr.deq;
rg_rd_beat <= 0;
end
else
rg_rd_beat <= rg_rd_beat + 1;
if (verbosity != 0) begin
$write ("%0d: %m.rl_read: ", cur_cycle);
$write (fshow_Rd_Addr (rd_addr));
$write (fshow_Rd_Data (rd_data));
if (addr_ok)
$display (" beat %0d rf_index 0x%0h", rg_rd_beat, rf_index);
else
$display (" beat 0x%0h BAD ADDR", rg_rd_beat);
end
endrule
// ================================================================
// Write requests
Reg #(Bit #(8)) rg_wr_beat <- mkReg (0);
// Recv request on WR_ADDR bus and burst data on WR_DATA bus,
// send final response on WR_RESP bus
rule rl_write (rg_initialized);
let wr_addr = xactor.o_wr_addr.first;
let wr_data <- pop_o (xactor.o_wr_data);
let rf_index = ((wr_addr.awaddr - rg_addr_map_base) >> 3);
if (wr_addr.awburst == axburst_incr)
rf_index = rf_index + zeroExtend (rg_wr_beat);
let last = (rg_wr_beat == wr_addr.awlen);
let addr_ok = fn_addr_ok (rg_addr_map_base, rg_addr_map_lim, wr_addr.awaddr, wr_addr.awsize);
if (addr_ok)
rf.upd (rf_index, wr_data.wdata);
if (verbosity != 0) begin
$write ("%0d: %m.rl_write: ", cur_cycle);
$write (fshow_Wr_Data (wr_data));
$write (" ", fshow_Wr_Addr (wr_addr));
if (addr_ok)
$display (" beat %0d rf_index %0h", rg_wr_beat, rf_index);
else
$display (" beat %0d BAD ADDR", rg_wr_beat);
end
if (last) begin
AXI4_Wr_Resp #(wd_id, wd_user) wr_resp = ?;
wr_resp = AXI4_Wr_Resp {bid: wr_addr.awid,
bresp: (addr_ok ? axi4_resp_okay : axi4_resp_slverr),
buser: wr_addr.awuser};
xactor.i_wr_resp.enq (wr_resp);
xactor.o_wr_addr.deq;
rg_wr_beat <= 0;
if (verbosity != 0)
$display (" ", fshow_Wr_Resp (wr_resp));
end
else
rg_wr_beat <= rg_wr_beat + 1;
endrule
// ================================================================
// INTERFACE
method Action init (Bit #(wd_addr) addr_map_base, Bit #(wd_addr) addr_map_lim);
if (addr_map_base [2:0] != 3'b0)
$display ("%0d: %m.init: ERROR: unaligned addr_map_base 0x%0h", cur_cycle, addr_map_base);
else if (addr_map_lim [2:0] != 3'b0)
$display ("%0d: %m.init: ERROR: unaligned addr_map_lim 0x%0h", cur_cycle, addr_map_lim);
else if (addr_map_lim <= addr_map_base)
$display ("%0d: %m.init: ERROR: addr_map_base 0x%0h > addr_map_lim 0x%0h",
cur_cycle,
addr_map_base,
addr_map_lim);
else if ((addr_map_lim - addr_map_base) > fromInteger (mem_size_word64 * 8))
$display ("%0d: %m.init: ERROR: mem size (base 0x%0h, lim 0x%0h) > max (0x%0h)",
cur_cycle,
addr_map_base,
addr_map_lim,
fromInteger (mem_size_word64 * 8));
else begin
xactor.reset;
rg_addr_map_base <= addr_map_base;
rg_addr_map_lim <= addr_map_lim;
rg_initialized <= True;
$display ("%0d: %m.init: addr_map_base 0x%0h, addr_map_lim 0x%0h",
cur_cycle,
addr_map_base,
addr_map_lim);
end
endmethod
interface slave = xactor.axi_side;
endmodule
// ================================================================
endpackage