Files
Toooba/src_Testbench/Fabrics/AXI4/AXI4_Deburster.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

323 lines
11 KiB
Plaintext

// Copyright (c) 2019 Bluespec, Inc. All Rights Reserved
package AXI4_Deburster;
// ================================================================
// This package defines a AXI4-slave-to-AXI4-slave conversion module.
// The parameter interface is an AXI4-slave that carries no burst transactions.
// The output interface is an AXI4-slave that carries burst transactions.
// ================================================================
// Bluespec library imports
import Vector :: *;
import FIFOF :: *;
import SpecialFIFOs :: *;
import ConfigReg :: *;
// ----------------
// BSV additional libs
import Cur_Cycle :: *;
// ================================================================
// Project imports
import Semi_FIFOF :: *;
import AXI4_Types :: *;
// ================================================================
// The interface for the fabric module
interface AXI4_Deburster_IFC #(numeric type wd_id,
numeric type wd_addr,
numeric type wd_data,
numeric type wd_user);
method Action reset;
// From master
interface AXI4_Slave_IFC #(wd_id, wd_addr, wd_data, wd_user) from_master;
// To slave
interface AXI4_Master_IFC #(wd_id, wd_addr, wd_data, wd_user) to_slave;
endinterface
// ================================================================
// The Deburster module
// The function parameter is an address-decode function, which
// returns (True, slave-port-num) if address is mapped to slave-port-num
// (False, ?) if address is unmapped to any slave port
module mkAXI4_Deburster (AXI4_Deburster_IFC #(wd_id, wd_addr, wd_data, wd_user))
provisos (Add #(a__, 8, wd_addr));
// 0 quiet; 1: display start of burst; 2: display all traffic
Integer cfg_verbosity = 0;
Reg #(Bool) rg_reset <- mkReg (True);
// Transactor facing master
AXI4_Slave_Xactor_IFC #(wd_id, wd_addr, wd_data, wd_user)
xactor_from_master <- mkAXI4_Slave_Xactor;
// Transactor facing slave
AXI4_Master_Xactor_IFC #(wd_id, wd_addr, wd_data, wd_user)
xactor_to_slave <- mkAXI4_Master_Xactor;
// On a write-transaction, this register is the W-channel burst beat count
// (0 => start of burst)
Reg #(AXI4_Len) rg_w_beat_count <- mkReg (0);
// On a write-transaction, records awlen for slave
// Size of FIFO should cover slave latency
FIFOF #(AXI4_Len) f_w_awlen <- mkSizedFIFOF (4);
// On a write-transaction, this register is the B-channel burst beat count
// which is the number of individual (non-burst) responses from the
// slave to be combined into a single burst response to the master.
// (0 => ready for next burst)
Reg #(AXI4_Len) rg_b_beat_count <- mkReg (0);
// On a burst write-transaction, all the individual slave responses
// may not have the same 'resp' on the B channel. This register
// remembers the first 'non-okay' resp (if any), to be returned to
// the master in the burst response.
Reg #(AXI4_Resp) rg_b_resp <- mkReg (axi4_resp_okay);
// On a read-transaction, records arlen for slave
// Size of FIFO should cover slave latency
FIFOF #(AXI4_Len) f_r_arlen <- mkSizedFIFOF (4);
// On a read-transaction, this register is the AR-channel burst beat count
// (0 => start of next burst)
Reg #(AXI4_Len) rg_ar_beat_count <- mkReg (0);
// On a read-transaction, this register is the R-channel burst beat count
// (0 => ready for next burst)
Reg #(AXI4_Len) rg_r_beat_count <- mkReg (0);
// ----------------------------------------------------------------
// Compute address for beat
function Bit #(wd_addr) fv_addr_for_beat (Bit #(wd_addr) start_addr,
AXI4_Size axsize,
AXI4_Burst axburst,
AXI4_Len beat_count);
Bit #(wd_addr) addr = start_addr;
if (axburst == axburst_incr)
addr = start_addr + (zeroExtend (beat_count) << pack (axsize));
else if (axburst == axburst_wrap)
addr = start_addr; // TODO: fixup
return addr;
endfunction
// ----------------------------------------------------------------
// RESET
rule rl_reset (rg_reset);
$display ("%0d: %m::AXI4_Deburster.rl_reset", cur_cycle);
xactor_from_master.reset;
xactor_to_slave.reset;
f_w_awlen.clear;
rg_w_beat_count <= 0;
rg_b_beat_count <= 0;
rg_b_resp <= axi4_resp_okay;
f_r_arlen.clear;
rg_ar_beat_count <= 0;
rg_r_beat_count <= 0;
rg_reset <= False;
endrule
// ----------------------------------------------------------------
// BEHAVIOR
// ----------------
// Wr requests (AW and W channels)
rule rl_wr_xaction_master_to_slave;
AXI4_Wr_Addr #(wd_id, wd_addr, wd_user) a_in = xactor_from_master.o_wr_addr.first;
AXI4_Wr_Data #(wd_data, wd_user) d_in = xactor_from_master.o_wr_data.first;
// Construct output AW item
let a_out = a_in;
a_out.awaddr = fv_addr_for_beat (a_in.awaddr, a_in.awsize, a_in.awburst, rg_w_beat_count);
a_out.awlen = 0;
a_out.awburst = axburst_fixed; // Not necessary when awlen=1, but slave may be finicky
// Set WLAST to true since this is always last beat of outgoing xaction (awlen=1)
let d_out = d_in;
d_out.wlast = True;
// Send to slave
xactor_to_slave.i_wr_addr.enq (a_out);
xactor_to_slave.i_wr_data.enq (d_out);
xactor_from_master.o_wr_data.deq;
// Remember burst length so that individual responses from slave
// can be combined into a single burst response to the master.
if (rg_w_beat_count == 0)
f_w_awlen.enq (a_in.awlen);
if (rg_w_beat_count < a_in.awlen)
rg_w_beat_count <= rg_w_beat_count + 1;
else begin
// Last beat of incoming burst; done with AW item
xactor_from_master.o_wr_addr.deq;
rg_w_beat_count <= 0;
// Simulation-only assertion-check (no action, just display assertion failure)
// Last incoming beat must have WLAST = 1
if (! d_in.wlast) begin
$display ("%0d: ERROR: %m::AXI4_Deburster.rl_wr_xaction_master_to_slave: m -> s", cur_cycle);
$display (" WLAST not set on last data beat (awlen = %0d)", a_in.awlen);
$display (" ", fshow (d_in));
end
end
// Debugging
if (cfg_verbosity > 0) begin
$display ("%0d: %m::AXI4_Deburster.rl_wr_xaction_master_to_slave: m -> s, beat %0d",
cur_cycle, rg_w_beat_count);
if (rg_w_beat_count == 0)
$display (" a_in : ", fshow (a_in));
if ((rg_w_beat_count == 0) || (cfg_verbosity > 1)) begin
$display (" d_in : ", fshow (d_in));
$display (" a_out: ", fshow (a_out));
$display (" d_out: ", fshow (d_out));
end
end
endrule: rl_wr_xaction_master_to_slave
// ----------------
// Wr responses (B channel): consume responses from slave until the
// last response for a burst, then respond to master. Remember if
// any of them was not an 'okay' response.
rule rl_wr_resp_slave_to_master;
AXI4_Wr_Resp #(wd_id, wd_user) b_in <- pop_o (xactor_to_slave.o_wr_resp);
if (rg_b_beat_count < f_w_awlen.first) begin
// Remember first non-okay response (if any) of a burst in rg_b_resp
if ((rg_b_resp == axi4_resp_okay) && (b_in.bresp != axi4_resp_okay))
rg_b_resp <= b_in.bresp;
// not last beat of burst
rg_b_beat_count <= rg_b_beat_count + 1;
if (cfg_verbosity > 1) begin
$display ("%0d: %m::AXI4_Deburster.rl_wr_resp_slave_to_master: m <- s, beat %0d",
cur_cycle, rg_b_beat_count);
$display (" Consuming and discarding beat %0d", rg_b_beat_count);
$display (" ", fshow (b_in));
end
end
else begin
// Last beat of burst
let b_out = b_in;
if (rg_b_resp != axi4_resp_okay)
b_out.bresp = rg_b_resp;
xactor_from_master.i_wr_resp.enq (b_out);
f_w_awlen.deq;
// Get ready for next burst
rg_b_beat_count <= 0;
rg_b_resp <= axi4_resp_okay;
if (cfg_verbosity > 1) begin
$display ("%0d: %m::AXI4_Deburster.rl_wr_resp_slave_to_master: m <- s, beat %0d",
cur_cycle, rg_b_beat_count);
$display (" b_in: ", fshow (b_in));
$display (" b_out: ", fshow (b_out));
end
end
endrule
// ----------------
// Rd requests (AR channel)
rule rl_rd_xaction_master_to_slave;
AXI4_Rd_Addr #(wd_id, wd_addr, wd_user) a_in = xactor_from_master.o_rd_addr.first;
// Compute forwarded request for each beat, and send
let a_out = a_in;
a_out.araddr = fv_addr_for_beat (a_in.araddr, a_in.arsize, a_in.arburst, rg_ar_beat_count);
a_out.arlen = 0;
a_out.arburst = axburst_fixed; // Not necessary when arlen=1, but slave may be finicky
xactor_to_slave.i_rd_addr.enq (a_out);
// On first beat, set up the response count
if (rg_ar_beat_count == 0)
f_r_arlen.enq (a_in.arlen);
if (rg_ar_beat_count < a_in.arlen)
rg_ar_beat_count <= rg_ar_beat_count + 1;
else begin
// Last beat sent; done with AR item
xactor_from_master.o_rd_addr.deq;
rg_ar_beat_count <= 0;
end
// Debugging
if (cfg_verbosity > 0) begin
$display ("%0d: %m::AXI4_Deburster.rl_rd_xaction_master_to_slave: m -> s, beat %0d",
cur_cycle, rg_ar_beat_count);
if (rg_ar_beat_count == 0)
$display (" a_in: ", fshow (a_in));
if ((rg_ar_beat_count == 0) || (cfg_verbosity > 1))
$display (" a_out: ", fshow (a_out));
end
endrule: rl_rd_xaction_master_to_slave
// ----------------
// Rd responses
rule rl_rd_resp_slave_to_master;
AXI4_Rd_Data #(wd_id, wd_data, wd_user) r_in <- pop_o (xactor_to_slave.o_rd_data);
let arlen = f_r_arlen.first;
let r_out = r_in;
if (rg_r_beat_count < arlen) begin
// not last beat of burst
r_out.rlast = False;
rg_r_beat_count <= rg_r_beat_count + 1;
end
else begin
// Last beat of burst
rg_r_beat_count <= 0;
r_out.rlast = True; // should be set already, but override if not
f_r_arlen.deq;
end
xactor_from_master.i_rd_data.enq (r_out);
// Debugging
if (cfg_verbosity > 0) begin
$display ("%0d: %m::AXI4_Deburster.rl_rd_resp_slave_to_master: m <- s, beat %0d",
cur_cycle, rg_r_beat_count);
if ((rg_r_beat_count == 0) || (cfg_verbosity > 1)) begin
$display (" r_in: ", fshow (r_in));
$display (" r_out: ", fshow (r_out));
end
end
endrule: rl_rd_resp_slave_to_master
// ----------------------------------------------------------------
// INTERFACE
method Action reset () if (! rg_reset);
rg_reset <= True;
endmethod
interface from_master = xactor_from_master.axi_side;
interface to_slave = xactor_to_slave .axi_side;
endmodule
// ================================================================
endpackage: AXI4_Deburster