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
212 lines
6.5 KiB
Plaintext
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
|