Add cc65 code

This commit is contained in:
2026-05-08 09:54:14 -07:00
parent 3c8df89769
commit c4d91a1994
11 changed files with 226 additions and 22 deletions

3
.gitignore vendored
View File

@@ -1,2 +1,5 @@
sim_build
__pycache__
*.o
*.lst

View File

@@ -8,3 +8,5 @@ pip install -r requirements.txt
export PYTHON3=$(which python)
module load verilator
export CC65_BIN="$REPO_TOP/../cc65/bin/"

29
sim/asm_source/Makefile Normal file
View 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
View 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
View 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
View 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
View File

@@ -0,0 +1,7 @@
.import vec_reset, vec_irq, vec_nmi
.segment "VECTORS": dword
.addr vec_nmi
.addr vec_reset
.addr vec_irq

View 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"

View 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)

View File

@@ -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 <anywhere>
@@ -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():

View File

@@ -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