ec82764bef
RTL (GS rasterizer, EE core stub, platform bridge, LPDDR4B path), sim regression (272 TBs), docs, and tooling. Copyrighted PS2 content (BIOS, game code, GS dumps, and all dump-derived textures/traces) is excluded via .gitignore and stays local. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
487 lines
19 KiB
Systemverilog
487 lines
19 KiB
Systemverilog
// retroDE_ps2 — tb_iop_autonomous_two_xfers
|
|
//
|
|
// First autonomous multi-transaction flow. Extends tb_iop_self_driven
|
|
// one architectural level higher: the RAM-resident control program
|
|
// now contains a BNE back-edge that loops the DMA+IRQ+ack body until
|
|
// DMAC.DONE_COUNT reaches 2. A single `go_i` pulse produces TWO full
|
|
// DMA transactions, two interrupt assertions, and two acks — all
|
|
// fabric-driven, no TB steering between transactions.
|
|
//
|
|
// Chain identical to tb_iop_self_driven (same map, DMAC, INTC, exec
|
|
// stub, ep_ready-on-the-floor endpoint). The only difference is the
|
|
// script: a BNE at the loop tail wires two transactions together.
|
|
//
|
|
// Script (9 ops, laid out in IOP RAM at SCRIPT_BASE):
|
|
// pc=0 WRITE INTC_MASK = 1 (enable bit 0)
|
|
// pc=1 WRITE DMAC_MADR = payload (loop entry)
|
|
// pc=2 WRITE DMAC_BCR = 4
|
|
// pc=3 WRITE DMAC_CHCR = 1 (start transfer)
|
|
// pc=4 WAIT_IRQ (block until completion)
|
|
// pc=5 WRITE INTC_STAT = 1 (W1C ack through real map)
|
|
// pc=6 READ DMAC_DONE_COUNT (latches into last_read_data)
|
|
// pc=7 BNE target=1, expected=2 (branch back if DONE_COUNT != 2)
|
|
// pc=8 HALT
|
|
//
|
|
// Acceptance:
|
|
// - Exactly one go_i pulse from the TB; no orchestration after.
|
|
// - Two DMA_DONE events, two INTC assertions, two INTC acks.
|
|
// - Exactly two WAIT_IRQ exits and exactly one BNE taken (the first
|
|
// time, when DONE_COUNT == 1). On the second iteration DONE_COUNT
|
|
// reads 2, so BNE falls through to HALT.
|
|
// - halt_o asserts exactly once.
|
|
// - Full causal chain reconstructible from the trace.
|
|
|
|
`timescale 1ns/1ps
|
|
|
|
module tb_iop_autonomous_two_xfers;
|
|
|
|
localparam int IOP_RAM_BYTES = 4 * 1024;
|
|
localparam int IOP_RAM_ADDR_W = $clog2(IOP_RAM_BYTES);
|
|
|
|
localparam logic [31:0] SCRIPT_BASE = 32'h0000_0400;
|
|
localparam logic [31:0] PAYLOAD_BASE = 32'h0000_0200;
|
|
|
|
localparam logic [31:0] DMAC_MADR_ADDR = 32'h1F80_1520;
|
|
localparam logic [31:0] DMAC_BCR_ADDR = 32'h1F80_1524;
|
|
localparam logic [31:0] DMAC_CHCR_ADDR = 32'h1F80_1528;
|
|
localparam logic [31:0] DMAC_DONECOUNT_ADDR = 32'h1F80_152C;
|
|
localparam logic [31:0] INTC_STAT_ADDR = 32'h1F80_1070;
|
|
localparam logic [31:0] INTC_MASK_ADDR = 32'h1F80_1074;
|
|
|
|
localparam logic [31:0] OP_HALT = 32'h0000_0000;
|
|
localparam logic [31:0] OP_WRITE = 32'h0000_0001;
|
|
localparam logic [31:0] OP_READ = 32'h0000_0002;
|
|
localparam logic [31:0] OP_WAIT_IRQ = 32'h0000_0003;
|
|
localparam logic [31:0] OP_BNE = 32'h0000_0004;
|
|
|
|
logic clk;
|
|
logic rst_n;
|
|
|
|
initial clk = 1'b0;
|
|
always #5 clk = ~clk;
|
|
|
|
// ------------------------------------------------------------------
|
|
// IOP exec stub
|
|
// ------------------------------------------------------------------
|
|
|
|
logic exec_go;
|
|
logic exec_halt;
|
|
logic [7:0] exec_pc;
|
|
|
|
logic map_cpu_rd_en;
|
|
logic [31:0] map_cpu_rd_addr;
|
|
logic [31:0] map_cpu_rd_data;
|
|
logic map_cpu_rd_valid;
|
|
|
|
logic map_cpu_wr_en;
|
|
logic [31:0] map_cpu_wr_addr;
|
|
logic [31:0] map_cpu_wr_data;
|
|
logic [3:0] map_cpu_wr_be;
|
|
|
|
logic iop_cpu_irq;
|
|
|
|
logic exec_ev_valid;
|
|
trace_pkg::subsys_e exec_ev_subsys;
|
|
trace_pkg::event_e exec_ev_event;
|
|
logic [63:0] exec_ev_arg0, exec_ev_arg1, exec_ev_arg2, exec_ev_arg3;
|
|
logic [31:0] exec_ev_flags;
|
|
|
|
iop_exec_stub #(.SCRIPT_BASE(SCRIPT_BASE)) u_exec (
|
|
.clk(clk), .rst_n(rst_n),
|
|
.go_i(exec_go),
|
|
.map_rd_en(map_cpu_rd_en), .map_rd_addr(map_cpu_rd_addr),
|
|
.map_rd_data(map_cpu_rd_data), .map_rd_valid(map_cpu_rd_valid),
|
|
.map_wr_en(map_cpu_wr_en), .map_wr_addr(map_cpu_wr_addr),
|
|
.map_wr_data(map_cpu_wr_data), .map_wr_be(map_cpu_wr_be),
|
|
.cpu_irq(iop_cpu_irq),
|
|
.halt_o(exec_halt), .pc_o(exec_pc),
|
|
.ev_valid(exec_ev_valid), .ev_subsys(exec_ev_subsys),
|
|
.ev_event(exec_ev_event),
|
|
.ev_arg0(exec_ev_arg0), .ev_arg1(exec_ev_arg1),
|
|
.ev_arg2(exec_ev_arg2), .ev_arg3(exec_ev_arg3),
|
|
.ev_flags(exec_ev_flags)
|
|
);
|
|
|
|
// ------------------------------------------------------------------
|
|
// IOP map + IOP RAM (TB drives bridge_wr_* for preload)
|
|
// ------------------------------------------------------------------
|
|
|
|
logic iop_ram_rd_en;
|
|
logic [20:0] iop_ram_rd_addr;
|
|
logic [31:0] iop_ram_rd_data;
|
|
logic iop_ram_rd_valid;
|
|
logic iop_ram_wr_en;
|
|
logic [20:0] iop_ram_wr_addr;
|
|
logic [31:0] iop_ram_wr_data;
|
|
logic [3:0] iop_ram_wr_be;
|
|
logic [7:0] iop_ram_master_id;
|
|
|
|
logic map_dmac_rd_en;
|
|
logic [3:0] map_dmac_rd_addr;
|
|
logic [31:0] map_dmac_rd_data;
|
|
logic map_dmac_rd_valid;
|
|
logic map_dmac_wr_en;
|
|
logic [3:0] map_dmac_wr_addr;
|
|
logic [31:0] map_dmac_wr_data;
|
|
|
|
logic map_intc_rd_en;
|
|
logic [7:0] map_intc_rd_addr;
|
|
logic [31:0] map_intc_rd_data;
|
|
logic map_intc_rd_valid;
|
|
logic map_intc_wr_en;
|
|
logic [7:0] map_intc_wr_addr;
|
|
logic [31:0] map_intc_wr_data;
|
|
|
|
logic dma_rd_en;
|
|
logic [31:0] dma_rd_addr;
|
|
logic [7:0] dma_master_id;
|
|
logic [31:0] dma_rd_data;
|
|
logic dma_rd_valid;
|
|
|
|
logic tb_br_wr_en;
|
|
logic [31:0] tb_br_wr_addr;
|
|
logic [31:0] tb_br_wr_data;
|
|
logic [3:0] tb_br_wr_be;
|
|
|
|
logic iop_map_ev_valid;
|
|
trace_pkg::subsys_e iop_map_ev_subsys;
|
|
trace_pkg::event_e iop_map_ev_event;
|
|
logic [63:0] iop_map_ev_arg0, iop_map_ev_arg1, iop_map_ev_arg2, iop_map_ev_arg3;
|
|
logic [31:0] iop_map_ev_flags;
|
|
|
|
iop_memory_map_stub u_iop_map (
|
|
.clk(clk), .rst_n(rst_n),
|
|
.iop_rd_en(map_cpu_rd_en), .iop_rd_addr(map_cpu_rd_addr),
|
|
.iop_rd_data(map_cpu_rd_data), .iop_rd_valid(map_cpu_rd_valid),
|
|
.iop_wr_en(map_cpu_wr_en), .iop_wr_addr(map_cpu_wr_addr),
|
|
.iop_wr_data(map_cpu_wr_data), .iop_wr_be(map_cpu_wr_be),
|
|
.master_id(8'd2),
|
|
.bridge_wr_en(tb_br_wr_en), .bridge_wr_addr(tb_br_wr_addr),
|
|
.bridge_wr_data(tb_br_wr_data), .bridge_wr_be(tb_br_wr_be),
|
|
.bridge_master_id(8'd0),
|
|
.dma_rd_en(dma_rd_en), .dma_rd_addr(dma_rd_addr),
|
|
.dma_master_id(dma_master_id),
|
|
.dma_rd_data(dma_rd_data), .dma_rd_valid(dma_rd_valid),
|
|
.sif_rd_en(), .sif_rd_addr(),
|
|
.sif_rd_data(32'd0), .sif_rd_valid(1'b0),
|
|
.sif_wr_en(), .sif_wr_addr(), .sif_wr_data(),
|
|
.iop_dmac_rd_en(map_dmac_rd_en), .iop_dmac_rd_addr(map_dmac_rd_addr),
|
|
.iop_dmac_rd_data(map_dmac_rd_data), .iop_dmac_rd_valid(map_dmac_rd_valid),
|
|
.iop_dmac_wr_en(map_dmac_wr_en), .iop_dmac_wr_addr(map_dmac_wr_addr),
|
|
.iop_dmac_wr_data(map_dmac_wr_data),
|
|
.iop_intc_rd_en(map_intc_rd_en), .iop_intc_rd_addr(map_intc_rd_addr),
|
|
.iop_intc_rd_data(map_intc_rd_data), .iop_intc_rd_valid(map_intc_rd_valid),
|
|
.iop_intc_wr_en(map_intc_wr_en), .iop_intc_wr_addr(map_intc_wr_addr),
|
|
.iop_intc_wr_data(map_intc_wr_data),
|
|
.input_p1(32'd0), .input_p2(32'd0),
|
|
// BIOS ROM port — unused by this TB
|
|
.bios_rd_en(), .bios_rd_addr(),
|
|
.bios_rd_data(32'd0), .bios_rd_valid(1'b0),
|
|
.ram_rd_en(iop_ram_rd_en), .ram_rd_addr(iop_ram_rd_addr),
|
|
.ram_rd_data(iop_ram_rd_data), .ram_rd_valid(iop_ram_rd_valid),
|
|
.ram_wr_en(iop_ram_wr_en), .ram_wr_addr(iop_ram_wr_addr),
|
|
.ram_wr_data(iop_ram_wr_data), .ram_wr_be(iop_ram_wr_be),
|
|
.ram_master_id(iop_ram_master_id),
|
|
.ev_valid(iop_map_ev_valid), .ev_subsys(iop_map_ev_subsys),
|
|
.ev_event(iop_map_ev_event),
|
|
.ev_arg0(iop_map_ev_arg0), .ev_arg1(iop_map_ev_arg1),
|
|
.ev_arg2(iop_map_ev_arg2), .ev_arg3(iop_map_ev_arg3),
|
|
.ev_flags(iop_map_ev_flags)
|
|
);
|
|
|
|
iop_ram_stub #(.SIZE_BYTES(IOP_RAM_BYTES)) u_iop_ram (
|
|
.clk(clk), .rst_n(rst_n),
|
|
.rd_en(iop_ram_rd_en), .rd_addr(iop_ram_rd_addr[IOP_RAM_ADDR_W-1:0]),
|
|
.rd_data(iop_ram_rd_data), .rd_valid(iop_ram_rd_valid),
|
|
.wr_en(iop_ram_wr_en), .wr_addr(iop_ram_wr_addr[IOP_RAM_ADDR_W-1:0]),
|
|
.wr_data(iop_ram_wr_data), .wr_be(iop_ram_wr_be),
|
|
.master_id(iop_ram_master_id),
|
|
.ev_valid(), .ev_subsys(), .ev_event(),
|
|
.ev_arg0(), .ev_arg1(), .ev_arg2(), .ev_arg3(), .ev_flags()
|
|
);
|
|
|
|
// ------------------------------------------------------------------
|
|
// IOP DMAC ch9 — endpoint drained (no stall in this TB)
|
|
// ------------------------------------------------------------------
|
|
|
|
logic ep_valid;
|
|
logic [31:0] ep_data;
|
|
logic ep_last;
|
|
logic ep_ready;
|
|
assign ep_ready = 1'b1;
|
|
|
|
logic dmac_irq_completion;
|
|
logic dmac_busy;
|
|
logic [31:0] dmac_done_count;
|
|
|
|
logic dmac_ev_valid;
|
|
trace_pkg::subsys_e dmac_ev_subsys;
|
|
trace_pkg::event_e dmac_ev_event;
|
|
logic [63:0] dmac_ev_arg0, dmac_ev_arg1, dmac_ev_arg2, dmac_ev_arg3;
|
|
logic [31:0] dmac_ev_flags;
|
|
|
|
iop_dmac_reg_stub u_dmac (
|
|
.clk(clk), .rst_n(rst_n),
|
|
.reg_wr_en(map_dmac_wr_en), .reg_rd_en(map_dmac_rd_en),
|
|
.reg_offset(map_dmac_wr_en ? map_dmac_wr_addr : map_dmac_rd_addr),
|
|
.reg_wr_data(map_dmac_wr_data),
|
|
.reg_rd_data(map_dmac_rd_data), .reg_rd_valid(map_dmac_rd_valid),
|
|
.mem_rd_en(dma_rd_en), .mem_rd_addr(dma_rd_addr),
|
|
.mem_master_id(dma_master_id),
|
|
.mem_rd_data(dma_rd_data), .mem_rd_valid(dma_rd_valid),
|
|
.ep_valid(ep_valid), .ep_data(ep_data), .ep_last(ep_last),
|
|
.ep_ready(ep_ready),
|
|
.irq_completion_o(dmac_irq_completion),
|
|
.busy_o(dmac_busy), .done_count_o(dmac_done_count),
|
|
.ev_valid(dmac_ev_valid), .ev_subsys(dmac_ev_subsys),
|
|
.ev_event(dmac_ev_event),
|
|
.ev_arg0(dmac_ev_arg0), .ev_arg1(dmac_ev_arg1),
|
|
.ev_arg2(dmac_ev_arg2), .ev_arg3(dmac_ev_arg3),
|
|
.ev_flags(dmac_ev_flags)
|
|
);
|
|
|
|
// ------------------------------------------------------------------
|
|
// IOP INTC
|
|
// ------------------------------------------------------------------
|
|
|
|
logic [15:0] iop_irq_src;
|
|
assign iop_irq_src = {15'd0, dmac_irq_completion};
|
|
|
|
logic intc_ev_valid;
|
|
trace_pkg::subsys_e intc_ev_subsys;
|
|
trace_pkg::event_e intc_ev_event;
|
|
logic [63:0] intc_ev_arg0, intc_ev_arg1, intc_ev_arg2, intc_ev_arg3;
|
|
logic [31:0] intc_ev_flags;
|
|
|
|
intc_stub #(
|
|
.INTC_STAT_OFFSET(8'h70),
|
|
.INTC_MASK_OFFSET(8'h74)
|
|
) u_intc (
|
|
.clk(clk), .rst_n(rst_n),
|
|
.reg_wr_en(map_intc_wr_en), .reg_rd_en(map_intc_rd_en),
|
|
.reg_addr(map_intc_wr_en ? map_intc_wr_addr : map_intc_rd_addr),
|
|
.reg_wr_data(map_intc_wr_data),
|
|
.reg_rd_data(map_intc_rd_data), .reg_rd_valid(map_intc_rd_valid),
|
|
.irq_src(iop_irq_src), .cpu_irq(iop_cpu_irq),
|
|
.ev_valid(intc_ev_valid), .ev_subsys(intc_ev_subsys),
|
|
.ev_event(intc_ev_event),
|
|
.ev_arg0(intc_ev_arg0), .ev_arg1(intc_ev_arg1),
|
|
.ev_arg2(intc_ev_arg2), .ev_arg3(intc_ev_arg3),
|
|
.ev_flags(intc_ev_flags)
|
|
);
|
|
|
|
// ------------------------------------------------------------------
|
|
// Trace sinks
|
|
// ------------------------------------------------------------------
|
|
|
|
trace_sink_stub #(.FILENAME("iop_two_xfers_exec.trace"), .SINK_LABEL("iop_exec"))
|
|
u_trace_exec (.clk(clk), .rst_n(rst_n),
|
|
.ev_valid(exec_ev_valid), .ev_subsys(exec_ev_subsys),
|
|
.ev_event(exec_ev_event), .ev_arg0(exec_ev_arg0),
|
|
.ev_arg1(exec_ev_arg1), .ev_arg2(exec_ev_arg2),
|
|
.ev_arg3(exec_ev_arg3), .ev_flags(exec_ev_flags));
|
|
|
|
trace_sink_stub #(.FILENAME("iop_two_xfers_map.trace"), .SINK_LABEL("iop_map"))
|
|
u_trace_map (.clk(clk), .rst_n(rst_n),
|
|
.ev_valid(iop_map_ev_valid), .ev_subsys(iop_map_ev_subsys),
|
|
.ev_event(iop_map_ev_event), .ev_arg0(iop_map_ev_arg0),
|
|
.ev_arg1(iop_map_ev_arg1), .ev_arg2(iop_map_ev_arg2),
|
|
.ev_arg3(iop_map_ev_arg3), .ev_flags(iop_map_ev_flags));
|
|
|
|
trace_sink_stub #(.FILENAME("iop_two_xfers_dmac.trace"), .SINK_LABEL("iop_dmac"))
|
|
u_trace_dmac (.clk(clk), .rst_n(rst_n),
|
|
.ev_valid(dmac_ev_valid), .ev_subsys(dmac_ev_subsys),
|
|
.ev_event(dmac_ev_event), .ev_arg0(dmac_ev_arg0),
|
|
.ev_arg1(dmac_ev_arg1), .ev_arg2(dmac_ev_arg2),
|
|
.ev_arg3(dmac_ev_arg3), .ev_flags(dmac_ev_flags));
|
|
|
|
trace_sink_stub #(.FILENAME("iop_two_xfers_intc.trace"), .SINK_LABEL("iop_intc"))
|
|
u_trace_intc (.clk(clk), .rst_n(rst_n),
|
|
.ev_valid(intc_ev_valid), .ev_subsys(intc_ev_subsys),
|
|
.ev_event(intc_ev_event), .ev_arg0(intc_ev_arg0),
|
|
.ev_arg1(intc_ev_arg1), .ev_arg2(intc_ev_arg2),
|
|
.ev_arg3(intc_ev_arg3), .ev_flags(intc_ev_flags));
|
|
|
|
// ------------------------------------------------------------------
|
|
// Observers
|
|
// ------------------------------------------------------------------
|
|
|
|
int dmac_done_events;
|
|
int intc_assert_events;
|
|
int intc_ack_events;
|
|
int exec_op_events;
|
|
int wait_irq_exit_events;
|
|
int bne_taken_events;
|
|
int halt_events;
|
|
int errors;
|
|
|
|
initial begin
|
|
dmac_done_events = 0;
|
|
intc_assert_events = 0;
|
|
intc_ack_events = 0;
|
|
exec_op_events = 0;
|
|
wait_irq_exit_events = 0;
|
|
bne_taken_events = 0;
|
|
halt_events = 0;
|
|
errors = 0;
|
|
end
|
|
|
|
always_ff @(posedge clk) begin
|
|
if (rst_n && dmac_ev_valid &&
|
|
dmac_ev_subsys == trace_pkg::SUBSYS_DMAC &&
|
|
dmac_ev_event == trace_pkg::EV_DMA_DONE)
|
|
dmac_done_events <= dmac_done_events + 1;
|
|
|
|
if (rst_n && intc_ev_valid &&
|
|
intc_ev_subsys == trace_pkg::SUBSYS_INTC &&
|
|
intc_ev_event == trace_pkg::EV_IRQ) begin
|
|
if (intc_ev_arg3 == 64'd0 && (intc_ev_flags & 32'h1) == 32'd0)
|
|
intc_assert_events <= intc_assert_events + 1;
|
|
else if (intc_ev_arg3 == 64'd1)
|
|
intc_ack_events <= intc_ack_events + 1;
|
|
end
|
|
|
|
if (rst_n && exec_ev_valid) begin
|
|
exec_op_events <= exec_op_events + 1;
|
|
if ((exec_ev_flags & 32'h2) != 32'd0)
|
|
wait_irq_exit_events <= wait_irq_exit_events + 1;
|
|
if ((exec_ev_flags & 32'h4) != 32'd0)
|
|
halt_events <= halt_events + 1;
|
|
if ((exec_ev_flags & 32'h8) != 32'd0)
|
|
bne_taken_events <= bne_taken_events + 1;
|
|
end
|
|
end
|
|
|
|
// ------------------------------------------------------------------
|
|
// Preload helpers
|
|
// ------------------------------------------------------------------
|
|
|
|
task automatic bridge_write(input logic [31:0] addr, input logic [31:0] data);
|
|
@(negedge clk);
|
|
tb_br_wr_en = 1'b1;
|
|
tb_br_wr_addr = addr;
|
|
tb_br_wr_data = data;
|
|
tb_br_wr_be = 4'b1111;
|
|
@(negedge clk);
|
|
tb_br_wr_en = 1'b0;
|
|
tb_br_wr_addr = 32'd0;
|
|
tb_br_wr_data = 32'd0;
|
|
tb_br_wr_be = 4'd0;
|
|
endtask
|
|
|
|
task automatic emit_op(input int slot,
|
|
input logic [31:0] opcode,
|
|
input logic [31:0] addr_or_tgt,
|
|
input logic [31:0] data_or_exp);
|
|
logic [31:0] base;
|
|
base = SCRIPT_BASE + (slot << 4);
|
|
bridge_write(base + 32'd0, opcode);
|
|
bridge_write(base + 32'd4, addr_or_tgt);
|
|
bridge_write(base + 32'd8, data_or_exp);
|
|
bridge_write(base + 32'd12, 32'd0);
|
|
endtask
|
|
|
|
// ------------------------------------------------------------------
|
|
// Stimulus — single go_i pulse; loop-tail BNE drives two transactions
|
|
// ------------------------------------------------------------------
|
|
|
|
initial begin
|
|
rst_n = 1'b0;
|
|
exec_go = 1'b0;
|
|
tb_br_wr_en = 1'b0;
|
|
tb_br_wr_addr = 32'd0;
|
|
tb_br_wr_data = 32'd0;
|
|
tb_br_wr_be = 4'd0;
|
|
|
|
repeat (4) @(posedge clk);
|
|
rst_n = 1'b1;
|
|
repeat (2) @(posedge clk);
|
|
|
|
// Payload (reused by both transactions — exec stub doesn't
|
|
// rewrite between iterations)
|
|
bridge_write(PAYLOAD_BASE + 32'h00, 32'hCAFE_0000);
|
|
bridge_write(PAYLOAD_BASE + 32'h04, 32'hCAFE_0001);
|
|
bridge_write(PAYLOAD_BASE + 32'h08, 32'hCAFE_0002);
|
|
bridge_write(PAYLOAD_BASE + 32'h0C, 32'hCAFE_0003);
|
|
|
|
// Control program
|
|
emit_op( 0, OP_WRITE, INTC_MASK_ADDR, 32'h0000_0001);
|
|
// loop_start @ pc=1
|
|
emit_op( 1, OP_WRITE, DMAC_MADR_ADDR, PAYLOAD_BASE);
|
|
emit_op( 2, OP_WRITE, DMAC_BCR_ADDR, 32'h0000_0004);
|
|
emit_op( 3, OP_WRITE, DMAC_CHCR_ADDR, 32'h0000_0001);
|
|
emit_op( 4, OP_WAIT_IRQ, 32'd0, 32'd0);
|
|
emit_op( 5, OP_WRITE, INTC_STAT_ADDR, 32'h0000_0001);
|
|
emit_op( 6, OP_READ, DMAC_DONECOUNT_ADDR, 32'd0);
|
|
// BNE: branch back to loop_start (pc=1) if DONE_COUNT != 2
|
|
emit_op( 7, OP_BNE, 32'h0000_0001, 32'h0000_0002);
|
|
emit_op( 8, OP_HALT, 32'd0, 32'd0);
|
|
|
|
// Single go_i pulse
|
|
@(negedge clk);
|
|
exec_go = 1'b1;
|
|
@(negedge clk);
|
|
exec_go = 1'b0;
|
|
|
|
while (!exec_halt) @(posedge clk);
|
|
repeat (4) @(posedge clk);
|
|
|
|
// Post-halt checks
|
|
if (dmac_done_events != 2) begin
|
|
$error("[tb_iop_autonomous_two_xfers] expected 2 DMA_DONE, got %0d",
|
|
dmac_done_events);
|
|
errors = errors + 1;
|
|
end
|
|
if (intc_assert_events != 2) begin
|
|
$error("[tb_iop_autonomous_two_xfers] expected 2 INTC asserts, got %0d",
|
|
intc_assert_events);
|
|
errors = errors + 1;
|
|
end
|
|
if (intc_ack_events != 2) begin
|
|
$error("[tb_iop_autonomous_two_xfers] expected 2 INTC acks, got %0d",
|
|
intc_ack_events);
|
|
errors = errors + 1;
|
|
end
|
|
if (wait_irq_exit_events != 2) begin
|
|
$error("[tb_iop_autonomous_two_xfers] expected 2 WAIT_IRQ exits, got %0d",
|
|
wait_irq_exit_events);
|
|
errors = errors + 1;
|
|
end
|
|
if (bne_taken_events != 1) begin
|
|
$error("[tb_iop_autonomous_two_xfers] expected 1 BNE taken, got %0d",
|
|
bne_taken_events);
|
|
errors = errors + 1;
|
|
end
|
|
if (halt_events != 1) begin
|
|
$error("[tb_iop_autonomous_two_xfers] expected 1 halt event, got %0d",
|
|
halt_events);
|
|
errors = errors + 1;
|
|
end
|
|
|
|
$display("[tb_iop_autonomous_two_xfers] ops=%0d wait_irq_exit=%0d bne_taken=%0d halt=%0d done=%0d asserts=%0d acks=%0d errors=%0d",
|
|
exec_op_events, wait_irq_exit_events, bne_taken_events,
|
|
halt_events, dmac_done_events,
|
|
intc_assert_events, intc_ack_events, errors);
|
|
|
|
if (errors == 0 &&
|
|
dmac_done_events == 2 &&
|
|
intc_assert_events == 2 &&
|
|
intc_ack_events == 2 &&
|
|
wait_irq_exit_events == 2 &&
|
|
bne_taken_events == 1 &&
|
|
halt_events == 1)
|
|
$display("[tb_iop_autonomous_two_xfers] PASS");
|
|
else
|
|
$display("[tb_iop_autonomous_two_xfers] FAIL");
|
|
|
|
$finish;
|
|
end
|
|
|
|
initial begin
|
|
#2000000;
|
|
$error("[tb_iop_autonomous_two_xfers] timeout");
|
|
$finish;
|
|
end
|
|
|
|
endmodule : tb_iop_autonomous_two_xfers
|