diff --git a/.gitignore b/.gitignore index 0eb1c57..1cfdb72 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,5 @@ sim_build -__pycache__ \ No newline at end of file +__pycache__ + +*.o +*.lst \ No newline at end of file diff --git a/init_env.sh b/init_env.sh index 820e49f..d868ec8 100644 --- a/init_env.sh +++ b/init_env.sh @@ -7,4 +7,6 @@ pip install -r requirements.txt export PYTHON3=$(which python) -module load verilator \ No newline at end of file +module load verilator + +export CC65_BIN="$REPO_TOP/../cc65/bin/" \ No newline at end of file diff --git a/sim/asm_source/Makefile b/sim/asm_source/Makefile new file mode 100644 index 0000000..3facd4c --- /dev/null +++ b/sim/asm_source/Makefile @@ -0,0 +1,29 @@ + + +# work in progress +.SUFFIXES: + + +PROGRAMS=jsr_test lda_test + +SRCS=$(wildcard *.s) +OBJS=$(SRCS:.s=.o) + +CA65=$(CC65_BIN)/ca65 +LD65=$(CC65_BIN)/ld65 + +CA_ARGS=--cpu 65c032 + +all: $(PROGRAMS) + +$(PROGRAMS): $(PROGRAM=$(.TARGET)) + +%.o: %.s + $(CA65) $(CA_ARGS) $^ -o $@ -l $@.lst + +$(PROGRAMS): $(OBJS) + $(LD65) -o $@ -C memory.cfg vectors.o $@.o + +clean: + rm -rf $(PROGRAMS) $(OBJS) + rm -rf *.o *.lst \ No newline at end of file diff --git a/sim/asm_source/jsr_test.s b/sim/asm_source/jsr_test.s new file mode 100644 index 0000000..98d4ca1 --- /dev/null +++ b/sim/asm_source/jsr_test.s @@ -0,0 +1,11 @@ +.export vec_reset, vec_irq, vec_nmi + +.segment "CODE" + +vec_nmi: +vec_reset: +vec_irq: + + +jsr_test: + bra jsr_test \ No newline at end of file diff --git a/sim/asm_source/lda_test.s b/sim/asm_source/lda_test.s new file mode 100644 index 0000000..ebd994e --- /dev/null +++ b/sim/asm_source/lda_test.s @@ -0,0 +1,68 @@ +.export vec_reset, vec_irq, vec_nmi + +.ZEROPAGE + +zp0: .res 1 +zp1: .res 4 +zp2: .res 8 +zp3: .res 4 + +.CODE + +data1: .byte 1 +data2: .byte 2 +data3: .byte 3 +data4: .byte 4 +data5: .byte 5 +data6: .res 4 + .byte 6 +data7: .res 2 + .byte 7 + +vec_nmi: +vec_reset: +vec_irq: + + +prepare_test: + lda data1 + sta zp0 + + lda #.LOBYTE(data2) + sta zp1 + lda #.HIBYTE(data2) + sta zp1+1 + lda #.BANKBYTE(data2) + sta zp1+2 + lda #.TOPBYTE(data2) + sta zp1+3 + + lda #.LOBYTE(data4) + sta zp2+4 + lda #.HIBYTE(data4) + sta zp2+5 + lda #.BANKBYTE(data4) + sta zp2+6 + lda #.TOPBYTE(data4) + sta zp2+7 + + lda #.LOBYTE(data5-2) + sta zp3 + lda #.HIBYTE(data5-2) + sta zp3+1 + lda #.BANKBYTE(data5-2) + sta zp3+2 + lda #.TOPBYTE(data5-2) + sta zp3+3 + +lda_test: + lda zp0 ; data 1 + lda (zp1) ; data 2 + lda data3 ; data 3 + ldx #$4 + ldy #$2 + lda (zp2,x) ; data 4 + lda (zp3),y ; data 5 + lda data6,x ; data 6 + lda data7,y ; data 7 + wai \ No newline at end of file diff --git a/sim/asm_source/memory.cfg b/sim/asm_source/memory.cfg new file mode 100644 index 0000000..3f4d098 --- /dev/null +++ b/sim/asm_source/memory.cfg @@ -0,0 +1,13 @@ +MEMORY { + ZP: start = $0, size = $100; + RAM: start = $fffff000, size = $1000, file=%O; +} + +SEGMENTS { + ZEROPAGE: load = ZP, type = zp; + CODE: load = RAM, type = ro; + RODATA: load = RAM, type = ro; + DATA: load = RAM, type = rw; + BSS: load = RAM, type = bss, define = yes; + VECTORS: load = RAM, type = ro, start = $FFFFFFF4; +} \ No newline at end of file diff --git a/sim/asm_source/vectors.s b/sim/asm_source/vectors.s new file mode 100644 index 0000000..cee7ebd --- /dev/null +++ b/sim/asm_source/vectors.s @@ -0,0 +1,7 @@ +.import vec_reset, vec_irq, vec_nmi + +.segment "VECTORS": dword + +.addr vec_nmi +.addr vec_reset +.addr vec_irq \ No newline at end of file diff --git a/sim/verilog6502_32bit_asm.yaml b/sim/verilog6502_32bit_asm.yaml new file mode 100644 index 0000000..c4aec09 --- /dev/null +++ b/sim/verilog6502_32bit_asm.yaml @@ -0,0 +1,9 @@ +tests: + - name: "cpu_65c02" + toplevel: "cpu_65c02" + modules: + - "verilog6502_32bit_asm_test" + sources: "sources.list" + waves: True + defines: + SIM: "hi" \ No newline at end of file diff --git a/sim/verilog6502_32bit_asm_test.py b/sim/verilog6502_32bit_asm_test.py new file mode 100644 index 0000000..28bfaf7 --- /dev/null +++ b/sim/verilog6502_32bit_asm_test.py @@ -0,0 +1,62 @@ +import cocotb +from cocotb.handle import Immediate + +from cocotb.clock import Clock +from cocotb.triggers import Timer, RisingEdge, FallingEdge + +from collections import defaultdict + +import struct +import random + +import os + +CLK_PERIOD = 5 + +memory = defaultdict(int) + +def write_dword(addr: int, data: int): + memory[addr + 0] = (data >> 0) & 0xff + memory[addr + 1] = (data >> 8) & 0xff + memory[addr + 2] = (data >> 16) & 0xff + memory[addr + 3] = (data >> 24) & 0xff + +def write_byte(addr: int, data: int): + memory[addr] = data & 0xff + +def write_bytes(addr: int, data: bytes| list[int]): + for i, val in enumerate(data): + memory[addr + i] = int(val) + +async def handle_memory(dut): + while True: + await RisingEdge(dut.clk) + addr = int(dut.AB.value) + we = bool(dut.WE.value) + + dut.DI.value = memory[addr] + + if we: + memory[addr] = int(dut.DO.value) + +@cocotb.test +async def test_lda(dut): + cocotb.start_soon(Clock(dut.clk, CLK_PERIOD, unit="ns").start()) + cocotb.start_soon(handle_memory(dut)) + + path = os.path.dirname(os.path.abspath(__file__)) + + base_addr = 0xfffff000 + + with open(f"{path}/asm_source/lda_test", "rb") as file: + for i, val in enumerate(file.read()): + write_byte(base_addr+i, val) + + dut.RDY.value = Immediate(1) + + dut.reset.value = Immediate(1) + for _ in range(10): + await RisingEdge(dut.clk) + dut.reset.value = 0 + + await FallingEdge(dut.RDY_O) \ No newline at end of file diff --git a/sim/verilog6502_32bit_test.py b/sim/verilog6502_32bit_test.py index 95f73c7..f43331b 100644 --- a/sim/verilog6502_32bit_test.py +++ b/sim/verilog6502_32bit_test.py @@ -58,7 +58,7 @@ async def test_reset(dut): cocotb.start_soon(Clock(dut.clk, CLK_PERIOD, unit="ns").start()) cocotb.start_soon(handle_memory(dut)) - write_dword(0xfffffff4, 0x12345678) + write_dword(0xfffffff8, 0x12345678) dut.RDY.value = Immediate(1) @@ -73,10 +73,10 @@ async def test_reset(dut): (0x000001fe, True, (int(dut.PC.value) >> 8) & 0xff), # Mid low addr (0x000001fd, True, (int(dut.PC.value) >> 0) & 0xff), # Low addr (0x000001fc, True, int(dut.P.value)), # Status - (0xfffffff4, False, int(dut.regfile.value)), # read vector byte 0 - (0xfffffff5, False, int(dut.regfile.value)), # read vector byte 1 - (0xfffffff6, False, int(dut.regfile.value)), # read vector byte 2 - (0xfffffff7, False, int(dut.regfile.value)), # read vector byte 3 + (0xfffffff8, False, int(dut.regfile.value)), # read vector byte 0 + (0xfffffff9, False, int(dut.regfile.value)), # read vector byte 1 + (0xfffffffa, False, int(dut.regfile.value)), # read vector byte 2 + (0xfffffffb, False, int(dut.regfile.value)), # read vector byte 3 (0x12345678, False, int(dut.regfile.value)), # Read first instruction (0x12345679, False, int(dut.regfile.value)), # Read second byte ] @@ -88,7 +88,7 @@ async def test_absolute(dut): cocotb.start_soon(Clock(dut.clk, CLK_PERIOD, unit="ns").start()) cocotb.start_soon(handle_memory(dut)) - write_dword(0xfffffff4, 0x200) + write_dword(0xfffffff8, 0x200) # lda $abcd1234 # sta $50515253 @@ -137,7 +137,7 @@ async def test_absolute_x(dut): cocotb.start_soon(Clock(dut.clk, CLK_PERIOD, unit="ns").start()) cocotb.start_soon(handle_memory(dut)) - write_dword(0xfffffff4, 0x200) + write_dword(0xfffffff8, 0x200) # ldx #1 # lda $abcd1234,x @@ -196,7 +196,7 @@ async def test_absolute_y(dut): cocotb.start_soon(Clock(dut.clk, CLK_PERIOD, unit="ns").start()) cocotb.start_soon(handle_memory(dut)) - write_dword(0xfffffff4, 0x200) + write_dword(0xfffffff8, 0x200) # ldy #1 # lda $abcd1234,y @@ -255,7 +255,7 @@ async def test_absolute_x_indirect(dut): cocotb.start_soon(Clock(dut.clk, CLK_PERIOD, unit="ns").start()) cocotb.start_soon(handle_memory(dut)) - write_dword(0xfffffff4, 0x200) + write_dword(0xfffffff8, 0x200) # ldx #1 # jmp ($deadbeef,x) @@ -304,7 +304,7 @@ async def test_indirect(dut): cocotb.start_soon(Clock(dut.clk, CLK_PERIOD, unit="ns").start()) cocotb.start_soon(handle_memory(dut)) - write_dword(0xfffffff4, 0x200) + write_dword(0xfffffff8, 0x200) # jmp ($deadbeef) write_bytes(0x200, [0x6c, 0xef, 0xbe, 0xad, 0xde]) @@ -348,7 +348,7 @@ async def test_indexed_indirect(dut): cocotb.start_soon(Clock(dut.clk, CLK_PERIOD, unit="ns").start()) cocotb.start_soon(handle_memory(dut)) - write_dword(0xfffffff4, 0x200) + write_dword(0xfffffff8, 0x200) # ldy #1 # lda ($04),y @@ -412,7 +412,7 @@ async def test_indirect_indexed(dut): cocotb.start_soon(Clock(dut.clk, CLK_PERIOD, unit="ns").start()) cocotb.start_soon(handle_memory(dut)) - write_dword(0xfffffff4, 0x200) + write_dword(0xfffffff8, 0x200) # ldx #4 @@ -480,7 +480,7 @@ async def test_jsr(dut): cocotb.start_soon(Clock(dut.clk, CLK_PERIOD, unit="ns").start()) cocotb.start_soon(handle_memory(dut)) - write_dword(0xfffffff4, 0x200) + write_dword(0xfffffff8, 0x200) # @0x200 # ldx #$0 @@ -543,7 +543,7 @@ async def test_rti(dut): cocotb.start_soon(Clock(dut.clk, CLK_PERIOD, unit="ns").start()) cocotb.start_soon(handle_memory(dut)) - write_dword(0xfffffff4, 0x200) + write_dword(0xfffffff8, 0x200) write_dword(0xfffffffc, 0x300) @@ -608,7 +608,7 @@ async def test_irq(dut): cocotb.start_soon(Clock(dut.clk, CLK_PERIOD, unit="ns").start()) cocotb.start_soon(handle_memory(dut)) - write_dword(0xfffffff4, 0x200) + write_dword(0xfffffff8, 0x200) write_dword(0xfffffffc, 0x300) # @0x200 @@ -651,7 +651,7 @@ async def test_bra_always(dut): cocotb.start_soon(Clock(dut.clk, CLK_PERIOD, unit="ns").start()) cocotb.start_soon(handle_memory(dut)) - write_dword(0xfffffff4, 0xfffffd) + write_dword(0xfffffff8, 0xfffffd) # L1: bra L1 0x80 0x03 # nop @@ -687,7 +687,7 @@ async def test_bra_never(dut): cocotb.start_soon(Clock(dut.clk, CLK_PERIOD, unit="ns").start()) cocotb.start_soon(handle_memory(dut)) - write_dword(0xfffffff4, 0xfffffd) + write_dword(0xfffffff8, 0xfffffd) # lda #$00 # bne @@ -734,7 +734,7 @@ async def test_adc(dut): cocotb.start_soon(Clock(dut.clk, CLK_PERIOD, unit="ns").start()) cocotb.start_soon(handle_memory(dut)) - write_dword(0xfffffff4, 0x200) + write_dword(0xfffffff8, 0x200) def zp_indirect(): diff --git a/src/cpu_65c02.v b/src/cpu_65c02.v index b9886d3..61fa6f5 100644 --- a/src/cpu_65c02.v +++ b/src/cpu_65c02.v @@ -429,8 +429,8 @@ always @* JMPIX4, - BRK4: PC_temp = res ? 32'hFFFFFFF4 : - NMI_edge ? 32'hFFFFFFF8 : 32'hFFFFFFFC; + BRK4: PC_temp = res ? 32'hFFFFFFF8 : + NMI_edge ? 32'hFFFFFFFC : 32'hFFFFFFFC; default: PC_temp = PC; endcase