Skip to content

Commit

Permalink
Verilator-driven SDL simulation.
Browse files Browse the repository at this point in the history
  • Loading branch information
nand2mario committed Oct 30, 2022
1 parent b09dbc3 commit 960d58b
Show file tree
Hide file tree
Showing 13 changed files with 216 additions and 48 deletions.
3 changes: 2 additions & 1 deletion loader/Makefile
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@

OBJ := nes_loader.o osd.o util.o

# Link libstdc++ statically: https://web.archive.org/web/20160313071116/http://www.trilithium.com/johan/2005/06/static-libstdc/
loader: $(OBJ)
g++ -o loader $(OBJ)
g++ -static-libgcc -static-libstdc++ -o loader $(OBJ)

%.o: %.cpp
g++ -std=c++17 -c $< -o $@
Expand Down
6 changes: 3 additions & 3 deletions src/cpu.v
Original file line number Diff line number Diff line change
Expand Up @@ -242,9 +242,9 @@ end
// Program counter
ProgramCounter pc(clk, ce, LoadPC, GotInterrupt, DIN, T, PC, JumpNoOverflow);

always @(posedge clk) if (!reset && ce && (PC == 'hc071 || PC == 'hc072)) begin
$write("pc=c071/c072");
end
// always @(posedge clk) if (!reset && ce && (PC == 'hc071 || PC == 'hc072)) begin
// $write("pc=c071/c072");
// end

reg IsNMIInterrupt = 0;
reg LastNMI = 0;
Expand Down
8 changes: 5 additions & 3 deletions src/hw_uart.v
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@
// Example: 10 MHz Clock, 115200 baud UART
// (10000000)/(115200) = 87

typedef logic [7:0] BYTE;

module uart_rx
#(parameter CLKS_PER_BIT)
(
Expand Down Expand Up @@ -71,7 +73,7 @@ module uart_rx
// Check middle of start bit to make sure it's still low
s_RX_START_BIT :
begin
if (r_Clock_Count == (CLKS_PER_BIT-1)/2)
if (r_Clock_Count == BYTE'((CLKS_PER_BIT-1)/2))
begin
if (r_Rx_Data == 1'b0)
begin
Expand All @@ -92,7 +94,7 @@ module uart_rx
// Wait CLKS_PER_BIT-1 clock cycles to sample serial data
s_RX_DATA_BITS :
begin
if (r_Clock_Count < CLKS_PER_BIT-1)
if (r_Clock_Count < BYTE'(CLKS_PER_BIT-1))
begin
r_Clock_Count <= r_Clock_Count + 1;
r_SM_Main <= s_RX_DATA_BITS;
Expand Down Expand Up @@ -121,7 +123,7 @@ module uart_rx
s_RX_STOP_BIT :
begin
// Wait CLKS_PER_BIT-1 clock cycles for Stop bit to finish
if (r_Clock_Count < CLKS_PER_BIT-1)
if (r_Clock_Count < BYTE'(CLKS_PER_BIT-1))
begin
r_Clock_Count <= r_Clock_Count + 1;
r_SM_Main <= s_RX_STOP_BIT;
Expand Down
2 changes: 1 addition & 1 deletion src/memory_controller.v
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ wire [15:0] MemDout;
reg [2:0] cycles;
reg r_read_a, r_read_b;
wire MemBusy, MemDataReady;
wire fail_high, fail_low, tester_rd, tester_wr, tester_refresh, testing;
wire tester_rd, tester_wr, tester_refresh;
wire [25:0] tester_addr;
wire [15:0] tester_din;

Expand Down
6 changes: 3 additions & 3 deletions src/mmu.v
Original file line number Diff line number Diff line change
Expand Up @@ -447,8 +447,8 @@ module MMC5(input clk, input ce, input reset,
always @(posedge clk) begin
if (ce) begin
if (prg_write && prg_ain[15:10] == 6'b010100) begin // $5000-$53FF
if (prg_ain <= 16'h5113)
$write("%X <= %X (%d)\n", prg_ain, prg_din, ppu_scanline);
// if (prg_ain <= 16'h5113)
// $write("%X <= %X (%d)\n", prg_ain, prg_din, ppu_scanline);
casez(prg_ain[9:0])
10'h100: prg_mode <= prg_din[1:0];
10'h101: chr_mode <= prg_din[1:0];
Expand Down Expand Up @@ -1329,7 +1329,7 @@ module Mapper71(input clk, input ce, input reset,
ciram_select <= 0;
end else if (ce) begin
if (prg_ain[15] && prg_write) begin
$write("%X <= %X (bank = %x)\n", prg_ain, prg_din, prg_bank);
// $write("%X <= %X (bank = %x)\n", prg_ain, prg_din, prg_bank);
if (!prg_ain[14] && mapper232) // $8000-$BFFF Outer bank select (only on iNES 232)
prg_bank[3:2] <= prg_din[4:3];
if (prg_ain[14:13] == 0) // $8000-$9FFF Fire Hawk Mirroring
Expand Down
6 changes: 3 additions & 3 deletions src/nes.v
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ endmodule
module NES(input clk, input reset, input ce,
input [31:0] mapper_flags,
output [15:0] sample, // sample generated from APU
output [5:0] color, // pixel generated from PPU
output [5:0] color /*verilator public*/, // pixel generated from PPU
output joypad_strobe,// Set to 1 to strobe joypads. Then set to zero to keep the value.
output [1:0] joypad_clock, // Set to 1 for each joypad to clock it.
input [1:0] joypad_data, // Data for each joypad.
Expand All @@ -139,8 +139,8 @@ module NES(input clk, input reset, input ce,
output memory_write, // is a write operation
output [7:0] memory_dout,

output [8:0] cycle,
output [8:0] scanline
output [8:0] cycle /*verilator public*/,
output [8:0] scanline /*verilator public*/

// output reg [31:0] dbgadr,
// output [1:0] dbgctr
Expand Down
38 changes: 27 additions & 11 deletions src/nes_tang20k.v
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
// nand2mario, 2022.9
//

`timescale 1ns / 100ps
// `timescale 1ns / 100ps

// Main clock frequency
localparam FREQ=32_250_000;
Expand Down Expand Up @@ -126,10 +126,12 @@ module NES_Tang20k(
wire [7:0] uart_addr;
wire uart_write;
wire uart_error;
`ifndef VERILATOR
UartDemux
#(.FREQ(FREQ), .BAUDRATE(BAUDRATE))
uart_demux(clk, 1'b0, UART_RXD, uart_data, uart_addr, uart_write, uart_error);
// uart_demux(clk, ~sys_resetn, UART_RXD, uart_data, uart_addr, uart_write, uart_error);
`endif

// ROM loader
reg [7:0] loader_conf; // bit 0 is reset
Expand Down Expand Up @@ -200,7 +202,7 @@ module NES_Tang20k(
.clk(clk), .reset(loader_reset), .indata(loader_input), .indata_clk(loader_clk),
.mem_addr(loader_addr), .mem_data(loader_write_data), .mem_write(loader_write),
.mem_refresh(loader_refresh), .mapper_flags(mapper_flags),
.done(loader_done), .error(loader_fail));
.done(loader_done), .error(loader_fail), .loader_state(), .loader_bytes_left());

// The NES machine
// nes_ce / 0 \___/ 1 \___/ 2 \___/ 3 \___/ 4 \___/ 5 \___/ 0 \___/
Expand Down Expand Up @@ -283,6 +285,7 @@ module NES_Tang20k(
wire [1:0] rclkpos;
wire [2:0] rclksel;
wire [3:0] test_state;
wire write_level_done, read_calib_done, ram_testing, fail_high, fail_low;
MemoryController memory(.clk(clk), .pclk(pclk), .fclk(fclk), .ck(ck), .resetn(sys_resetn & nes_lock & mem_resetn),
.read_a(memory_read_cpu && run_mem),
.read_b(memory_read_ppu && run_mem),
Expand Down Expand Up @@ -506,15 +509,23 @@ endmodule


`ifdef EMBED_GAME
// zf: Feed INES data to Game_Loader
// Feed INES data to Game_Loader
module GameData (input clk, input reset, input start,
output reg [7:0] odata, output reg odata_clk
);

// 24KB+ buffer for ROM
reg [7:0] INES[24719:0];
reg [21:0] INES_SIZE = 24719;
initial $readmemh("BattleCity.nes.hex", INES);
// localparam [21:0] INES_SIZE = 24719;
// localparam string INES_FILE="../BattleCity.nes.hex";

// localparam [21:0] INES_SIZE = 131088;
// localparam string INES_FILE="../Contra.nes.hex";

localparam [21:0] INES_SIZE = 262160;
localparam string INES_FILE="../SuperC.nes.hex";

// Buffer for ROM file
reg [7:0] INES[INES_SIZE:0];
initial $readmemh(INES_FILE, INES);

reg [1:0] state = 0;
reg [21:0] addr = 0;
Expand All @@ -525,22 +536,27 @@ module GameData (input clk, input reset, input start,
state <= 0;
addr <= 0; // odata gets INES[0]
odata_clk <= 0;
end else if (start && state == 0) begin
end else if (start && state == 2'd0) begin
// start loading
state <= 1;
end else if (state==1) begin
end else if (state == 2'd1) begin
if (addr == INES_SIZE) begin
// we've just sent the last byte
state <= 2; // end of data
state <= 2'd3; // end of data
odata_clk <= 0;
end else begin
// pump data to Game_Loader
/* verilator lint_off WIDTH */
odata <= INES[addr];
/* verilator lint_on WIDTH */
odata_clk <= 1;
addr <= addr + 1;
state <= 2;
end
end else if (state == 2'd2) begin
// wait one clock cycle, then send next byte
odata_clk <= 0;
addr <= addr + 1;
state <= 1;
end
end
endmodule
Expand Down
19 changes: 14 additions & 5 deletions verilator/Makefile
Original file line number Diff line number Diff line change
@@ -1,13 +1,20 @@

.PHONY: build sim verilate
CFLAGS_SDL=$(shell sdl2-config --cflags) -O3
LIBS_SDL=$(shell sdl2-config --libs)

.PHONY: build sim verilate clean

build: ./obj_dir/VNES_Tang20k

verilate: sim_main.cpp hdl/*.v
verilate: ./obj_dir/VNES_Tang20k.cpp

./obj_dir/VNES_Tang20k.cpp: sim_main.cpp hdl/*.v
@echo
@echo "### VERILATE ####"
verilator --top-module NES_Tang20k --trace -cc hdl/*.v --exe sim_main.cpp
mkdir -p obj_dir
cd obj_dir; ln -sf ../game.nes.hex .; ln -sf ../hdl/src/*.txt .
# verilator --top-module NES_Tang20k --trace -cc -O3 -CFLAGS "$(CFLAGS_SDL)" -LDFLAGS "$(LIBS_SDL)" hdl/*.v --exe sim_main.cpp
verilator --top-module NES_Tang20k -cc -O3 --exe -CFLAGS "$(CFLAGS_SDL)" -LDFLAGS "$(LIBS_SDL)" hdl/*.v sim_main.cpp

./obj_dir/VNES_Tang20k: verilate
@echo
Expand All @@ -17,5 +24,7 @@ verilate: sim_main.cpp hdl/*.v
sim: ./obj_dir/VNES_Tang20k
@echo
@echo "### SIMULATION ###"
@echo "This will take some time..."
@cd obj_dir && ./VNES_Tang20k

clean:
rm -rf obj_dir
1 change: 0 additions & 1 deletion verilator/README

This file was deleted.

22 changes: 22 additions & 0 deletions verilator/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
This is a Verilator-driven graphical simulation of nestang. Should be useful in debugging game / mapper support, among other things.

To run the simulation:

```
./setup.sh `pwd`/..
hexdump -ve '1/1 "%02x\n"' game.nes > game.nes.hex
# change INES_SIZE in nes_tang20k.v to reflect size of game.nes
make sim
```

You need to set up verilator / libsdl2 with something like:

```
# Linux
sudo apt install verilator libsdl2-dev
# Mac
brew install verilator sdl2
```

For an overview of verilator, see: https://www.itsembedded.com/dhd/verilator_2/
12 changes: 12 additions & 0 deletions verilator/nes_palette.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
#pragma once

const unsigned NES_PALETTE[64] = {
0x545454, 0x001e74, 0x081090, 0x300088, 0x440064, 0x5c0030, 0x540400, 0x3c1800,
0x202a00, 0x083a00, 0x004000, 0x003c00, 0x00323c, 0x000000, 0x000000, 0x000000,
0x989698, 0x084cc4, 0x3032ec, 0x5c1ee4, 0x8814b0, 0xa01464, 0x982220, 0x783c00,
0x545a00, 0x287200, 0x087c00, 0x007628, 0x006678, 0x000000, 0x000000, 0x000000,
0xeceeec, 0x4c9aec, 0x787cec, 0xb062ec, 0xe454ec, 0xec58b4, 0xec6a64, 0xd48820,
0xa0aa00, 0x74c400, 0x4cd020, 0x38cc6c, 0x38b4cc, 0x3c3c3c, 0x000000, 0x000000,
0xeceeec, 0xa8ccec, 0xbcbcec, 0xd4b2ec, 0xecaeec, 0xecaed4, 0xecb4b0, 0xe4c490,
0xccd278, 0xb4de78, 0xa8e290, 0x98e2b4, 0xa0d6e4, 0xa0a2a0, 0x000000, 0x000000,
};
33 changes: 17 additions & 16 deletions verilator/setup.sh
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -11,21 +11,22 @@ fi
DIR=$1

mkdir -p hdl
ln -s $DIR/src/apu.v hdl
ln -s $DIR/src/compat.v hdl
ln -s $DIR/src/cpu.v hdl
ln -s $DIR/src/hw_sound.v hdl
ln -s $DIR/src/hw_uart.v hdl
ln -s $DIR/src/MicroCode.v hdl
ln -s $DIR/src/mmu.v hdl
ln -s $DIR/src/nes_tang20k.v hdl
ln -s $DIR/src/nes.v hdl
ln -s $DIR/src/ppu.v hdl
ln -s $DIR/src/sdram.v hdl
ln -sf $DIR/src/apu.v hdl
ln -sf $DIR/src/compat.v hdl
ln -sf $DIR/src/cpu.v hdl
ln -sf $DIR/src/hw_sound.v hdl
ln -sf $DIR/src/MicroCode.v hdl
ln -sf $DIR/src/mmu.v hdl
ln -sf $DIR/src/nes_tang20k.v hdl
ln -sf $DIR/src/nes.v hdl
ln -sf $DIR/src/ppu.v hdl
ln -sf $DIR/src/memory_controller.v hdl
ln -sf $DIR/src/game_loader.v hdl
ln -sf $DIR/src hdl/src

mkdir -p obj_dir
ln -s $DIR/src/oam_palette.txt obj_dir
ln -s $DIR/src/*.hex obj_dir
echo "hdl/ directory setup done."


echo "Setup done."
if [ ! -f game.nes.hex ]; then
echo "You need game.nes.hex ROM file to do simulation. To generate from .nes files: "
echo ' hexdump -ve '"'"'1/1 "%02x\\n'"'"' game.nes > game.nes.hex'
fi
Loading

0 comments on commit 960d58b

Please sign in to comment.