Add cc65 code
This commit is contained in:
3
.gitignore
vendored
3
.gitignore
vendored
@@ -1,2 +1,5 @@
|
|||||||
sim_build
|
sim_build
|
||||||
__pycache__
|
__pycache__
|
||||||
|
|
||||||
|
*.o
|
||||||
|
*.lst
|
||||||
@@ -8,3 +8,5 @@ pip install -r requirements.txt
|
|||||||
export PYTHON3=$(which python)
|
export PYTHON3=$(which python)
|
||||||
|
|
||||||
module load verilator
|
module load verilator
|
||||||
|
|
||||||
|
export CC65_BIN="$REPO_TOP/../cc65/bin/"
|
||||||
29
sim/asm_source/Makefile
Normal file
29
sim/asm_source/Makefile
Normal file
@@ -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
|
||||||
11
sim/asm_source/jsr_test.s
Normal file
11
sim/asm_source/jsr_test.s
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
.export vec_reset, vec_irq, vec_nmi
|
||||||
|
|
||||||
|
.segment "CODE"
|
||||||
|
|
||||||
|
vec_nmi:
|
||||||
|
vec_reset:
|
||||||
|
vec_irq:
|
||||||
|
|
||||||
|
|
||||||
|
jsr_test:
|
||||||
|
bra jsr_test
|
||||||
68
sim/asm_source/lda_test.s
Normal file
68
sim/asm_source/lda_test.s
Normal file
@@ -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
|
||||||
13
sim/asm_source/memory.cfg
Normal file
13
sim/asm_source/memory.cfg
Normal file
@@ -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;
|
||||||
|
}
|
||||||
7
sim/asm_source/vectors.s
Normal file
7
sim/asm_source/vectors.s
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
.import vec_reset, vec_irq, vec_nmi
|
||||||
|
|
||||||
|
.segment "VECTORS": dword
|
||||||
|
|
||||||
|
.addr vec_nmi
|
||||||
|
.addr vec_reset
|
||||||
|
.addr vec_irq
|
||||||
9
sim/verilog6502_32bit_asm.yaml
Normal file
9
sim/verilog6502_32bit_asm.yaml
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
tests:
|
||||||
|
- name: "cpu_65c02"
|
||||||
|
toplevel: "cpu_65c02"
|
||||||
|
modules:
|
||||||
|
- "verilog6502_32bit_asm_test"
|
||||||
|
sources: "sources.list"
|
||||||
|
waves: True
|
||||||
|
defines:
|
||||||
|
SIM: "hi"
|
||||||
62
sim/verilog6502_32bit_asm_test.py
Normal file
62
sim/verilog6502_32bit_asm_test.py
Normal file
@@ -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)
|
||||||
@@ -58,7 +58,7 @@ async def test_reset(dut):
|
|||||||
cocotb.start_soon(Clock(dut.clk, CLK_PERIOD, unit="ns").start())
|
cocotb.start_soon(Clock(dut.clk, CLK_PERIOD, unit="ns").start())
|
||||||
cocotb.start_soon(handle_memory(dut))
|
cocotb.start_soon(handle_memory(dut))
|
||||||
|
|
||||||
write_dword(0xfffffff4, 0x12345678)
|
write_dword(0xfffffff8, 0x12345678)
|
||||||
|
|
||||||
dut.RDY.value = Immediate(1)
|
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
|
(0x000001fe, True, (int(dut.PC.value) >> 8) & 0xff), # Mid low addr
|
||||||
(0x000001fd, True, (int(dut.PC.value) >> 0) & 0xff), # Low addr
|
(0x000001fd, True, (int(dut.PC.value) >> 0) & 0xff), # Low addr
|
||||||
(0x000001fc, True, int(dut.P.value)), # Status
|
(0x000001fc, True, int(dut.P.value)), # Status
|
||||||
(0xfffffff4, False, int(dut.regfile.value)), # read vector byte 0
|
(0xfffffff8, False, int(dut.regfile.value)), # read vector byte 0
|
||||||
(0xfffffff5, False, int(dut.regfile.value)), # read vector byte 1
|
(0xfffffff9, False, int(dut.regfile.value)), # read vector byte 1
|
||||||
(0xfffffff6, False, int(dut.regfile.value)), # read vector byte 2
|
(0xfffffffa, False, int(dut.regfile.value)), # read vector byte 2
|
||||||
(0xfffffff7, False, int(dut.regfile.value)), # read vector byte 3
|
(0xfffffffb, False, int(dut.regfile.value)), # read vector byte 3
|
||||||
(0x12345678, False, int(dut.regfile.value)), # Read first instruction
|
(0x12345678, False, int(dut.regfile.value)), # Read first instruction
|
||||||
(0x12345679, False, int(dut.regfile.value)), # Read second byte
|
(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(Clock(dut.clk, CLK_PERIOD, unit="ns").start())
|
||||||
cocotb.start_soon(handle_memory(dut))
|
cocotb.start_soon(handle_memory(dut))
|
||||||
|
|
||||||
write_dword(0xfffffff4, 0x200)
|
write_dword(0xfffffff8, 0x200)
|
||||||
|
|
||||||
# lda $abcd1234
|
# lda $abcd1234
|
||||||
# sta $50515253
|
# 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(Clock(dut.clk, CLK_PERIOD, unit="ns").start())
|
||||||
cocotb.start_soon(handle_memory(dut))
|
cocotb.start_soon(handle_memory(dut))
|
||||||
|
|
||||||
write_dword(0xfffffff4, 0x200)
|
write_dword(0xfffffff8, 0x200)
|
||||||
|
|
||||||
# ldx #1
|
# ldx #1
|
||||||
# lda $abcd1234,x
|
# 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(Clock(dut.clk, CLK_PERIOD, unit="ns").start())
|
||||||
cocotb.start_soon(handle_memory(dut))
|
cocotb.start_soon(handle_memory(dut))
|
||||||
|
|
||||||
write_dword(0xfffffff4, 0x200)
|
write_dword(0xfffffff8, 0x200)
|
||||||
|
|
||||||
# ldy #1
|
# ldy #1
|
||||||
# lda $abcd1234,y
|
# 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(Clock(dut.clk, CLK_PERIOD, unit="ns").start())
|
||||||
cocotb.start_soon(handle_memory(dut))
|
cocotb.start_soon(handle_memory(dut))
|
||||||
|
|
||||||
write_dword(0xfffffff4, 0x200)
|
write_dword(0xfffffff8, 0x200)
|
||||||
|
|
||||||
# ldx #1
|
# ldx #1
|
||||||
# jmp ($deadbeef,x)
|
# 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(Clock(dut.clk, CLK_PERIOD, unit="ns").start())
|
||||||
cocotb.start_soon(handle_memory(dut))
|
cocotb.start_soon(handle_memory(dut))
|
||||||
|
|
||||||
write_dword(0xfffffff4, 0x200)
|
write_dword(0xfffffff8, 0x200)
|
||||||
|
|
||||||
# jmp ($deadbeef)
|
# jmp ($deadbeef)
|
||||||
write_bytes(0x200, [0x6c, 0xef, 0xbe, 0xad, 0xde])
|
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(Clock(dut.clk, CLK_PERIOD, unit="ns").start())
|
||||||
cocotb.start_soon(handle_memory(dut))
|
cocotb.start_soon(handle_memory(dut))
|
||||||
|
|
||||||
write_dword(0xfffffff4, 0x200)
|
write_dword(0xfffffff8, 0x200)
|
||||||
|
|
||||||
# ldy #1
|
# ldy #1
|
||||||
# lda ($04),y
|
# 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(Clock(dut.clk, CLK_PERIOD, unit="ns").start())
|
||||||
cocotb.start_soon(handle_memory(dut))
|
cocotb.start_soon(handle_memory(dut))
|
||||||
|
|
||||||
write_dword(0xfffffff4, 0x200)
|
write_dword(0xfffffff8, 0x200)
|
||||||
|
|
||||||
|
|
||||||
# ldx #4
|
# 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(Clock(dut.clk, CLK_PERIOD, unit="ns").start())
|
||||||
cocotb.start_soon(handle_memory(dut))
|
cocotb.start_soon(handle_memory(dut))
|
||||||
|
|
||||||
write_dword(0xfffffff4, 0x200)
|
write_dword(0xfffffff8, 0x200)
|
||||||
|
|
||||||
# @0x200
|
# @0x200
|
||||||
# ldx #$0
|
# 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(Clock(dut.clk, CLK_PERIOD, unit="ns").start())
|
||||||
cocotb.start_soon(handle_memory(dut))
|
cocotb.start_soon(handle_memory(dut))
|
||||||
|
|
||||||
write_dword(0xfffffff4, 0x200)
|
write_dword(0xfffffff8, 0x200)
|
||||||
write_dword(0xfffffffc, 0x300)
|
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(Clock(dut.clk, CLK_PERIOD, unit="ns").start())
|
||||||
cocotb.start_soon(handle_memory(dut))
|
cocotb.start_soon(handle_memory(dut))
|
||||||
|
|
||||||
write_dword(0xfffffff4, 0x200)
|
write_dword(0xfffffff8, 0x200)
|
||||||
write_dword(0xfffffffc, 0x300)
|
write_dword(0xfffffffc, 0x300)
|
||||||
|
|
||||||
# @0x200
|
# @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(Clock(dut.clk, CLK_PERIOD, unit="ns").start())
|
||||||
cocotb.start_soon(handle_memory(dut))
|
cocotb.start_soon(handle_memory(dut))
|
||||||
|
|
||||||
write_dword(0xfffffff4, 0xfffffd)
|
write_dword(0xfffffff8, 0xfffffd)
|
||||||
|
|
||||||
# L1: bra L1 0x80 0x03
|
# L1: bra L1 0x80 0x03
|
||||||
# nop
|
# 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(Clock(dut.clk, CLK_PERIOD, unit="ns").start())
|
||||||
cocotb.start_soon(handle_memory(dut))
|
cocotb.start_soon(handle_memory(dut))
|
||||||
|
|
||||||
write_dword(0xfffffff4, 0xfffffd)
|
write_dword(0xfffffff8, 0xfffffd)
|
||||||
|
|
||||||
# lda #$00
|
# lda #$00
|
||||||
# bne <anywhere>
|
# bne <anywhere>
|
||||||
@@ -734,7 +734,7 @@ async def test_adc(dut):
|
|||||||
cocotb.start_soon(Clock(dut.clk, CLK_PERIOD, unit="ns").start())
|
cocotb.start_soon(Clock(dut.clk, CLK_PERIOD, unit="ns").start())
|
||||||
cocotb.start_soon(handle_memory(dut))
|
cocotb.start_soon(handle_memory(dut))
|
||||||
|
|
||||||
write_dword(0xfffffff4, 0x200)
|
write_dword(0xfffffff8, 0x200)
|
||||||
|
|
||||||
|
|
||||||
def zp_indirect():
|
def zp_indirect():
|
||||||
|
|||||||
@@ -429,8 +429,8 @@ always @*
|
|||||||
|
|
||||||
JMPIX4,
|
JMPIX4,
|
||||||
|
|
||||||
BRK4: PC_temp = res ? 32'hFFFFFFF4 :
|
BRK4: PC_temp = res ? 32'hFFFFFFF8 :
|
||||||
NMI_edge ? 32'hFFFFFFF8 : 32'hFFFFFFFC;
|
NMI_edge ? 32'hFFFFFFFC : 32'hFFFFFFFC;
|
||||||
|
|
||||||
default: PC_temp = PC;
|
default: PC_temp = PC;
|
||||||
endcase
|
endcase
|
||||||
|
|||||||
Reference in New Issue
Block a user