Complete rewrite from scratch, bootstrap WIP
Rewrite to use several bus multiplexers, resulting into a less messy microarchitecture (hopefully). Some more room for cleanup though... Supports every instruction from the bootstrap rom, more or less. LY hacked at 0x90 to progress through vsync instantly. No cartridge is present yet, so we will always fail checksum test and lock up.
This commit is contained in:
18
sim/clkgen.sv
Normal file
18
sim/clkgen.sv
Normal file
@@ -0,0 +1,18 @@
|
||||
module clkgen #(
|
||||
PERIOD_NS = 10,
|
||||
RESET_DELAY_NS = 45
|
||||
) (
|
||||
output logic clk,
|
||||
output logic nreset
|
||||
);
|
||||
|
||||
initial begin
|
||||
clk <= 1'b1;
|
||||
nreset <= 1'b0;
|
||||
#RESET_DELAY_NS nreset <= 1'b1;
|
||||
end
|
||||
|
||||
always
|
||||
#(PERIOD_NS/2) clk <= ~clk;
|
||||
|
||||
endmodule
|
||||
@@ -1,18 +0,0 @@
|
||||
module clkgen #(
|
||||
PERIOD_NS = 10,
|
||||
RESET_DELAY_NS = 100
|
||||
) (
|
||||
output logic clk_o,
|
||||
output logic nreset_o
|
||||
);
|
||||
|
||||
initial begin
|
||||
clk_o <= 1'b1;
|
||||
nreset_o <= 1'b0;
|
||||
#RESET_DELAY_NS nreset_o <= 1'b1;
|
||||
end
|
||||
|
||||
always
|
||||
#(PERIOD_NS/2) clk_o <= ~clk_o;
|
||||
|
||||
endmodule
|
||||
76
sim/tb_top.sv
Normal file
76
sim/tb_top.sv
Normal file
@@ -0,0 +1,76 @@
|
||||
module tb_top;
|
||||
|
||||
logic clk;
|
||||
logic nreset;
|
||||
|
||||
clkgen clkgen_inst (
|
||||
.clk (clk),
|
||||
.nreset(nreset)
|
||||
);
|
||||
|
||||
gb gb_inst (
|
||||
.clk (clk),
|
||||
.nreset(nreset)
|
||||
);
|
||||
|
||||
logic instr_valid;
|
||||
logic instr_undef;
|
||||
logic halted;
|
||||
logic [15:0] current_pc;
|
||||
logic [ 7:0] current_opcode[2:0];
|
||||
|
||||
logic we;
|
||||
logic [15:0] last_write_address;
|
||||
logic [ 7:0] last_write_value;
|
||||
|
||||
logic vram_sel;
|
||||
logic hiram_sel;
|
||||
|
||||
assign halted = gb_inst.cpu_inst.ctrl_inst.halted_r;
|
||||
assign instr_valid = gb_inst.cpu_inst.instr_valid;
|
||||
assign instr_undef = gb_inst.cpu_inst.ctrl_inst.instr_undef;
|
||||
assign current_opcode = gb_inst.cpu_inst.instr;
|
||||
|
||||
assign we = gb_inst.cpu_we;
|
||||
|
||||
assign vram_sel = gb_inst.vram_sel;
|
||||
assign hiram_sel = gb_inst.hiram_sel;
|
||||
|
||||
always_ff @(posedge clk or negedge nreset) begin
|
||||
if (!nreset)
|
||||
current_pc <= '0;
|
||||
else if (instr_valid)
|
||||
current_pc <= gb_inst.cpu_inst.pc_r;
|
||||
end
|
||||
|
||||
always_ff @(posedge clk or negedge nreset) begin
|
||||
if (!nreset) begin
|
||||
last_write_address <= '0;
|
||||
last_write_value <= '0;
|
||||
end else if (we) begin
|
||||
last_write_address <= gb_inst.cpu_addr;
|
||||
last_write_value <= gb_inst.cpu_wdata;
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
// SVA code here
|
||||
`include "sva_common.svh"
|
||||
`SVA_DEF_CLK(clk);
|
||||
`SVA_DEF_NRESET(nreset);
|
||||
|
||||
`SVA_ASSERT_PROP_FATAL(undefined_opcode_pushed,
|
||||
halted |-> !instr_undef,
|
||||
$sformatf("PC: 0x%X | Undefined opcode pushed: 0x%X (0x%X, 0x%X)", current_pc, current_opcode[0], current_opcode[1], current_opcode[2])
|
||||
);
|
||||
|
||||
logic selected_memory_implemented;
|
||||
assign selected_memory_implemented = hiram_sel | vram_sel;
|
||||
|
||||
`SVA_ASSERT_PROP(write_to_unimplemented_memory,
|
||||
we |-> selected_memory_implemented,
|
||||
$sformatf("PC: 0x%X | Write to unimplemented memory: 0x%X <= 0x%X",
|
||||
current_pc, last_write_address, last_write_value)
|
||||
);
|
||||
|
||||
endmodule : tb_top
|
||||
@@ -1,50 +0,0 @@
|
||||
module tb_top ();
|
||||
|
||||
logic clk;
|
||||
logic nreset;
|
||||
|
||||
clkgen clkgen_inst (
|
||||
.clk_o (clk),
|
||||
.nreset_o(nreset)
|
||||
);
|
||||
|
||||
gb gb_inst (
|
||||
.clk_i (clk),
|
||||
.nreset_i(nreset)
|
||||
);
|
||||
|
||||
// Testbench code
|
||||
logic instr_undef;
|
||||
logic halted;
|
||||
logic [15:0] last_pc;
|
||||
logic [ 7:0] last_opcode;
|
||||
logic [ 7:0] last_op1;
|
||||
logic [ 7:0] last_op2;
|
||||
|
||||
logic we;
|
||||
logic [15:0] address;
|
||||
logic [ 7:0] wdata;
|
||||
|
||||
assign halted = gb_inst.cpu_inst.control_inst.halted_r;
|
||||
assign instr_undef = gb_inst.cpu_inst.control_inst.is_undef;
|
||||
assign last_pc = gb_inst.cpu_inst.control_inst.instr_pc_r;
|
||||
assign last_opcode = gb_inst.cpu_inst.control_inst.instr_r;
|
||||
assign last_op1 = gb_inst.cpu_inst.control_inst.operand0_r;
|
||||
assign last_op2 = gb_inst.cpu_inst.control_inst.operand1_r;
|
||||
|
||||
assign we = gb_inst.we;
|
||||
assign address = gb_inst.address;
|
||||
assign wdata = gb_inst.wdata;
|
||||
|
||||
always @(posedge clk) begin
|
||||
if (nreset && instr_undef & ~halted) begin
|
||||
$display($sformatf("[%0t] %X: Undefined opcode %X | [%X | %X]", $time(), last_pc, last_opcode, last_op1, last_op2));
|
||||
$fatal(0);
|
||||
$finish();
|
||||
end
|
||||
if (nreset && we) begin
|
||||
$display($sformatf("[%0t] Write: [%X] <= %X", $time(), address, wdata));
|
||||
end
|
||||
end
|
||||
|
||||
endmodule : tb_top
|
||||
Reference in New Issue
Block a user