Files
stack/cpu_tb2.v
2026-03-07 23:45:11 -05:00

323 lines
15 KiB
Verilog

`timescale 1ns / 1ps
module cpu_tb_enhanced;
// Clock and reset
reg clk;
reg rst_n;
reg uart_rx;
wire uart_tx;
wire [5:0] led;
// Instantiate the CPU
cpu dut (
.i_clk(clk),
.i_rst_n(rst_n),
.i_uart_rx(uart_rx),
.o_uart_tx(uart_tx),
.o_led(led)
);
// Clock generation - 10ns period (100MHz)
initial begin
clk = 0;
forever #5 clk = ~clk;
end
// ============================================================================
// HELPER FUNCTIONS FOR DISPLAY
// ============================================================================
function [63:0] reg_name;
input [2:0] addr;
begin
case (addr)
3'd0: reg_name = "PCP";
3'd1: reg_name = "DSP";
3'd2: reg_name = "RSP";
3'd3: reg_name = "TMP";
3'd4: reg_name = "MDR";
3'd5: reg_name = "TOS";
3'd6: reg_name = "ACC";
3'd7: reg_name = "IMM";
default: reg_name = "???";
endcase
end
endfunction
function [63:0] rma_name;
input [1:0] addr;
begin
case (addr)
2'd0: rma_name = "PCP";
2'd1: rma_name = "DSP";
2'd2: rma_name = "RSP";
2'd3: rma_name = "TMP";
default: rma_name = "???";
endcase
end
endfunction
function [63:0] alu_op_name;
input [3:0] op;
begin
case (op)
4'h0: alu_op_name = "A ";
4'h1: alu_op_name = "NOT ";
4'h2: alu_op_name = "ADD ";
4'h3: alu_op_name = "SUB ";
4'h4: alu_op_name = "SGT ";
4'h5: alu_op_name = "SLT ";
4'h6: alu_op_name = "GT ";
4'h7: alu_op_name = "LT ";
4'h8: alu_op_name = "AND ";
4'h9: alu_op_name = "OR ";
4'ha: alu_op_name = "XOR ";
4'hb: alu_op_name = "LSL ";
4'hc: alu_op_name = "ASR ";
4'hd: alu_op_name = "MUL ";
4'he: alu_op_name = "SEXTB ";
4'hf: alu_op_name = "SEXTH ";
default: alu_op_name = "??? ";
endcase
end
endfunction
function [63:0] seq_op_name;
input [1:0] op;
begin
case (op)
2'b00: seq_op_name = "STEP";
2'b01: seq_op_name = "JUMP";
2'b10: seq_op_name = "RTRN";
2'b11: seq_op_name = "CALL";
default: seq_op_name = "????";
endcase
end
endfunction
function [63:0] mem_act_name;
input [1:0] act;
begin
case (act)
2'b00: mem_act_name = "NOP ";
2'b01: mem_act_name = "WORD";
2'b10: mem_act_name = "HWRD";
2'b11: mem_act_name = "BYTE";
default: mem_act_name = "????";
endcase
end
endfunction
// ============================================================================
// MONITORING CONFIGURATION
// ============================================================================
parameter SHOW_UNCHANGED_REGS = 1; // Set to 1 to always show all registers
parameter SHOW_MEMORY_CONTENTS = 1; // Set to 1 to show memory around stack pointers
parameter MEM_CONTEXT_LINES = 4; // How many memory locations to show around SP
parameter COMPACT_MODE = 1; // Set to 1 for more compact output
// Previous register values for change detection
reg [31:0] prev_regs [0:6];
integer cycle;
// ============================================================================
// MAIN MONITOR
// ============================================================================
initial begin
cycle = 0;
for (integer i = 0; i < 7; i = i + 1)
prev_regs[i] = 0;
$display("\n");
$display("╔════════════════════════════════════════════════════════════════════════════════╗");
$display("║ CPU EXECUTION MONITOR ║");
$display("╚════════════════════════════════════════════════════════════════════════════════╝");
$display("\n");
end
always @(posedge clk) begin
if (rst_n) begin
cycle = cycle + 1;
if (!COMPACT_MODE) begin
$display("\n┌────────────────────────────────────────────────────────────────────────────────┐");
$display("│ CYCLE %-5d │", cycle);
$display("└────────────────────────────────────────────────────────────────────────────────┘");
end else begin
$display("\n═══ CYCLE %-5d ═══", cycle);
end
// ============ SEQUENCER ============
if (!COMPACT_MODE) $display("\n┌─ SEQUENCER ───────────────────────────────────────────────────────────────────┐");
else $display("\n[SEQ]");
$display(" PC=0x%03h → 0x%03h RA=0x%03h %s %s%s%s",
dut.sequencer_inst.pc,
dut.seq_y,
dut.sequencer_inst.ra,
seq_op_name(dut.u_seq_op),
dut.u_seq_src ? "MAP" : "IMM",
dut.u_seq_cce ? $sformatf(" CC=%b", dut.seq_cc) : "",
dut.halt ? " [HALT]" : "");
if (!COMPACT_MODE) $display("└───────────────────────────────────────────────────────────────────────────────┘");
// ============ MICROCODE ============
if (!COMPACT_MODE) $display("\n┌─ MICROCODE @ 0x%03h ──────────────────────────────────────────────────────────┐", dut.sequencer_inst.pc);
else $display("\n[UCODE @ 0x%03h]", dut.sequencer_inst.pc);
$display(" Raw: 0x%09h IMM=0x%03h(%0d)", dut.uinst, dut.u_imm, dut.u_imm);
// Decode and display operation
$write(" Op: ");
// Register write operation
if (dut.u_rf_we && !dut.halt) begin
$write("%s ← ", reg_name(dut.u_rf_rd));
if (dut.u_alu_src)
$write("%s(%s,%s)[RMA[3:0]=0x%h]",
alu_op_name(dut.rf_rma_data[3:0]),
reg_name(dut.u_rf_rs1),
reg_name(dut.u_rf_rs2),
dut.rf_rma_data[3:0]);
else
$write("%s(%s,%s)",
alu_op_name(dut.u_alu_op),
reg_name(dut.u_rf_rs1),
reg_name(dut.u_rf_rs2));
end
// Memory operation
if (dut.u_mem_act != 2'b00) begin
if (dut.u_rf_we && !dut.halt) $write("; ");
if (dut.u_mem_dir)
$write("MEM[%s]=MDR %s", rma_name(dut.u_rf_rma), mem_act_name(dut.u_mem_act));
else
$write("MDR←MEM[%s] %s", rma_name(dut.u_rf_rma), mem_act_name(dut.u_mem_act));
end
if (!dut.u_rf_we && dut.u_mem_act == 2'b00)
$write("NOP");
$display("");
if (!COMPACT_MODE) $display("└───────────────────────────────────────────────────────────────────────────────┘");
// ============ REGISTERS ============
if (!COMPACT_MODE) $display("\n┌─ REGISTERS ───────────────────────────────────────────────────────────────────┐");
else $display("\n[REGS]");
// Show registers with change indicators
for (integer i = 0; i < 7; i = i + 1) begin
if (SHOW_UNCHANGED_REGS ||
(i > 3 ? dut.register_file_inst.data_registers[i % 4] : dut.register_file_inst.addr_registers[i % 4]) != prev_regs[i] ||
(dut.u_rf_rd == i && dut.rf_we && !dut.halt)) begin
$write(" %s: 0x%08h", reg_name(i), (i > 3 ? dut.register_file_inst.data_registers[i % 4] : dut.register_file_inst.addr_registers[i % 4]));
if ((i > 3 ? dut.register_file_inst.data_registers[i % 4] : dut.register_file_inst.addr_registers[i % 4]) != prev_regs[i])
$write(" ← 0x%08h", prev_regs[i]);
$display("");
prev_regs[i] = (i > 3 ? dut.register_file_inst.data_registers[i % 4] : dut.register_file_inst.addr_registers[i % 4]);
end
end
if (!COMPACT_MODE) $display("└───────────────────────────────────────────────────────────────────────────────┘");
// ============ ALU ============
if (!COMPACT_MODE) $display("\n┌─ ALU ─────────────────────────────────────────────────────────────────────────┐");
else $display("\n[ALU]");
$display(" %s: A=0x%08h B=0x%08h Y=0x%08h Z=%b",
alu_op_name(dut.alu_op),
dut.alu_a,
dut.alu_b,
dut.alu_y,
dut.alu_zero);
if (!COMPACT_MODE) $display("└───────────────────────────────────────────────────────────────────────────────┘");
// ============ MEMORY CONTENTS ============
if (SHOW_MEMORY_CONTENTS && dut.u_mem_act != 2'b00) begin
if (!COMPACT_MODE) $display("\n┌─ MEMORY ACCESS ──────────────────────────────────────────────────────────────┐");
else $display("\n[MEM]");
$display(" Addr: 0x%08h %s %s",
dut.rf_rma_data,
dut.u_mem_dir ? "WRITE" : "READ ",
mem_act_name(dut.u_mem_act));
if (dut.u_mem_dir)
$display(" Data: 0x%08h (from MDR)", dut.rf_mdr_data_r);
else
$display(" Data: 0x%08h (to MDR)", dut.srr_data);
if (!COMPACT_MODE) $display("└───────────────────────────────────────────────────────────────────────────────┘");
end
// ============ STACK CONTEXT ============
if (SHOW_MEMORY_CONTENTS && !COMPACT_MODE) begin
$display("\n┌─ STACK CONTEXT ──────────────────────────────────────────────────────────────┐");
$display(" Data Stack (DSP=0x%08h):", dut.register_file_inst.registers[1]);
$display(" Return Stack (RSP=0x%08h):", dut.register_file_inst.registers[2]);
$display("└───────────────────────────────────────────────────────────────────────────────┘");
end
// ============ OUTPUT ============
if (led != 0 || cycle < 10) begin
if (!COMPACT_MODE) $display("\n┌─ OUTPUT ──────────────────────────────────────────────────────────────────────┐");
else $display("\n[OUT]");
$display(" LED: 0x%02h (0b%06b)", led, led);
if (!COMPACT_MODE) $display("└───────────────────────────────────────────────────────────────────────────────┘");
end
end
end
// ============================================================================
// TEST STIMULUS
// ============================================================================
initial begin
// Initialize signals
rst_n = 0;
uart_rx = 1;
// Wait for a few cycles
repeat(5) @(posedge clk);
// Release reset
rst_n = 1;
$display("\n*** RESET RELEASED ***\n");
// Run for specified number of cycles
repeat(500) @(posedge clk);
// End simulation
$display("\n");
$display("╔════════════════════════════════════════════════════════════════════════════════╗");
$display("║ SIMULATION COMPLETE ║");
$display("║ Total Cycles: %-5d ║", cycle);
$display("╚════════════════════════════════════════════════════════════════════════════════╝");
$display("\n");
$finish;
end
// Waveform dump
initial begin
$dumpfile("cpu_tb_enhanced.vcd");
$dumpvars(0, cpu_tb_enhanced);
end
// Timeout watchdog
initial begin
#200000; // 200us timeout
$display("\n*** SIMULATION TIMEOUT ***\n");
$finish;
end
endmodule