Reviewed-on: #2
Co-authored-by: Byron Lathi <byron@byronlathi.com>
Co-committed-by: Byron Lathi <byron@byronlathi.com>
This commit was merged in pull request #2.
This commit is contained in:
2026-05-09 15:33:54 -07:00
committed by bslathi19
parent 06f933fa56
commit 089df744aa
21 changed files with 1645 additions and 284 deletions

3
.gitignore vendored
View File

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

View File

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

32
sim/asm_source/jsr_test.s Normal file
View File

@@ -0,0 +1,32 @@
.export vec_reset, vec_irq, vec_nmi
.ZEROPAGE
result: .res 1
.segment "CODE"
vec_nmi:
vec_reset:
vec_irq:
jsr_test:
lda #$ff
sta result
ldx #$ff
txs
jsr function_1
lda #$01
sta result
wai
function_2:
pha
pla
rts
function_1:
jsr function_2
rts

121
sim/asm_source/lda_test.s Normal file
View File

@@ -0,0 +1,121 @@
.export vec_reset, vec_irq, vec_nmi
.ZEROPAGE
result: .res 1
zp0: .res 1
zp1: .res 4
zp2: .res 8
zp3: .res 4
good_count: .res 1
.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
stz good_count
lda_test:
@test1:
lda zp0 ; data 1
cmp #$1
bne @test2
inc good_count
@test2:
lda (zp1) ; data 2
cmp #$2
bne @test3
inc good_count
@test3:
lda data3 ; data 3
cmp #$3
bne @test4
inc good_count
@test4:
ldx #$4
ldy #$2
lda (zp2,x) ; data 4
cmp #$4
bne @test5
inc good_count
@test5:
lda (zp3),y ; data 5
cmp #$5
bne @test6
inc good_count
@test6:
lda data6,x ; data 6
cmp #$6
bne @test7
inc good_count
@test7:
lda data7,y ; data 7
cmp #$7
bne @done
inc good_count
@done:
lda good_count
cmp #$7
bne @fail
lda #$1
sta result
wai
@fail:
lda #$ff
sta result
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_test"
sources: "sources.list"
waves: True
defines:
SIM: "hi"

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,71 @@
import cocotb
from cocotb.handle import Immediate
from cocotb.clock import Clock
from cocotb.triggers import Timer, RisingEdge, FallingEdge, with_timeout
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)
async def do_asm_test(dut, filename):
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/{filename}", "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 with_timeout(FallingEdge(dut.RDY_O), 10, "us")
assert memory[0] == 1
@cocotb.test
async def test_lda(dut):
await do_asm_test(dut, "lda_test")
@cocotb.test
async def test_jsr(dut):
await do_asm_test(dut, "jsr_test")

View File

@@ -0,0 +1,806 @@
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
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)
async def check_instruction_sequence(dut, instruction_sequence):
for expected_output in instruction_sequence:
await RisingEdge(dut.clk)
if expected_output:
expected_addr, expected_we, expected_do = expected_output
dut_addr = int(dut.AB.value)
dut_we = bool(dut.WE.value)
dut_do = int(dut.DO.value)
assert dut_addr == expected_addr
assert dut_we == expected_we
if dut_we:
assert dut_do == expected_do
@cocotb.test
async def test_reset(dut):
cocotb.start_soon(Clock(dut.clk, CLK_PERIOD, unit="ns").start())
cocotb.start_soon(handle_memory(dut))
write_dword(0xfffffff8, 0x12345678)
dut.RDY.value = Immediate(1)
dut.reset.value = Immediate(1)
for _ in range(10):
await RisingEdge(dut.clk)
dut.reset.value = 0
expected_cpu_outputs = [
(0x00000100, True, (int(dut.PC.value) >> 24) & 0xff), # High addr
(0x000001ff, True, (int(dut.PC.value) >> 16) & 0xff), # Mid high addr
(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
(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
]
await check_instruction_sequence(dut, expected_cpu_outputs)
@cocotb.test
async def test_absolute(dut):
cocotb.start_soon(Clock(dut.clk, CLK_PERIOD, unit="ns").start())
cocotb.start_soon(handle_memory(dut))
write_dword(0xfffffff8, 0x200)
# lda $abcd1234
# sta $50515253
# wai
write_bytes(0x200, [0xad, 0x34, 0x12, 0xcd, 0xab])
write_bytes(0x205, [0x8d, 0x53, 0x52, 0x51, 0x50])
write_byte(0x20a, 0xcb)
write_byte(0xabcd1234, 0x55)
dut.RDY.value = Immediate(1)
dut.reset.value = Immediate(1)
for _ in range(10):
await RisingEdge(dut.clk)
dut.reset.value = 0
expected_cpu_outputs = [
None, # ignore reset sequence
None,
None,
None,
None,
None,
None,
None,
None,
(0x00000200, False, None), # Read first instruction
(0x00000201, False, None), # Read address byte 0
(0x00000202, False, None), # Read address byte 1
(0x00000203, False, None), # Read address byte 2
(0x00000204, False, None), # Read address byte 3
(0xabcd1234, False, None), # Read from absolute address
(0x00000205, False, None), # Read second instruction
(0x00000206, False, None), # Read address byte 0
(0x00000207, False, None), # Read address byte 1
(0x00000208, False, None), # Read address byte 2
(0x00000209, False, None), # Read address byte 3
(0x50515253, True, 0x55), # Write to absolute address
]
await check_instruction_sequence(dut, expected_cpu_outputs)
@cocotb.test
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(0xfffffff8, 0x200)
# ldx #1
# lda $abcd1234,x
# inx
# sta $01020304,x
# wai
write_bytes(0x200, [0xa2, 0x01])
write_bytes(0x202, [0xbd, 0x34, 0x12, 0xcd, 0xab])
write_bytes(0x207, [0xe8])
write_bytes(0x208, [0x9d, 0x04, 0x03, 0x02, 0x01])
write_byte(0x20d, 0xcb)
write_byte(0xabcd1235, 0xaa)
dut.RDY.value = Immediate(1)
dut.reset.value = Immediate(1)
for _ in range(10):
await RisingEdge(dut.clk)
dut.reset.value = 0
expected_cpu_outputs = [
None, # ignore reset sequence
None,
None,
None,
None,
None,
None,
None,
None,
(0x00000200, False, None), # ldx #1
(0x00000201, False, None), # Immediate
(0x00000202, False, None), # ldx $abcd1234,x
(0x00000203, False, None), # addr 0
(0x00000204, False, None), # addr 1
(0x00000205, False, None), # addr 2
(0x00000206, False, None), # addr 3
(0xabcd1235, False, None), # Read from address
(0x00000207, False, None), # inx
(0x00000208, False, None), # sta $01020304,x
(0x00000208, False, None), # store reg
(0x00000209, False, None), # addr 0
(0x0000020a, False, None), # addr 1
(0x0000020b, False, None), # addr 2
(0x0000020c, False, None), # addr 3
(0x01020306, False, None), # Write to address
(0x01020306, True, 0xaa), # Write to address
]
await check_instruction_sequence(dut, expected_cpu_outputs)
@cocotb.test
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(0xfffffff8, 0x200)
# ldy #1
# lda $abcd1234,y
# iny
# sta $01020304,y
# wai
write_bytes(0x200, [0xa0, 0x01])
write_bytes(0x202, [0xb9, 0x34, 0x12, 0xcd, 0xab])
write_bytes(0x207, [0xc8])
write_bytes(0x208, [0x99, 0x04, 0x03, 0x02, 0x01])
write_byte(0x20d, 0xcb)
write_byte(0xabcd1235, 0xaa)
dut.RDY.value = Immediate(1)
dut.reset.value = Immediate(1)
for _ in range(10):
await RisingEdge(dut.clk)
dut.reset.value = 0
expected_cpu_outputs = [
None, # ignore reset sequence
None,
None,
None,
None,
None,
None,
None,
None,
(0x00000200, False, None), # ldx #1
(0x00000201, False, None), # Immediate
(0x00000202, False, None), # ldx $abcd1234,x
(0x00000203, False, None), # addr 0
(0x00000204, False, None), # addr 1
(0x00000205, False, None), # addr 2
(0x00000206, False, None), # addr 3
(0xabcd1235, False, None), # Read from address
(0x00000207, False, None), # inx
(0x00000208, False, None), # sta $01020304,x
(0x00000208, False, None), # store reg
(0x00000209, False, None), # addr 0
(0x0000020a, False, None), # addr 1
(0x0000020b, False, None), # addr 2
(0x0000020c, False, None), # addr 3
(0x01020306, False, None), # Write to address
(0x01020306, True, 0xaa), # Write to address
]
await check_instruction_sequence(dut, expected_cpu_outputs)
@cocotb.test
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(0xfffffff8, 0x200)
# ldx #1
# jmp ($deadbeef,x)
write_bytes(0x200, [0xa2, 0x01])
write_bytes(0x202, [0x7c, 0xef, 0xbe, 0xad, 0xde])
write_byte(0xbeefb055, 0xcb)
write_dword(0xdeadbeef + 1, 0xbeefb055)
dut.RDY.value = Immediate(1)
dut.reset.value = Immediate(1)
for _ in range(10):
await RisingEdge(dut.clk)
dut.reset.value = 0
expected_cpu_outputs = [
None, # ignore reset sequence
None,
None,
None,
None,
None,
None,
None,
None,
(0x00000200, False, None), # ldx #1
(0x00000201, False, None), # Immediate
(0x00000202, False, None), # jmp ($deadbeef,x)
(0x00000203, False, None), # addr 0
(0x00000204, False, None), # addr 1
(0x00000205, False, None), # addr 2
(0x00000206, False, None), # addr 3
(0xdeadbef0, False, None), # addr 0
(0xdeadbef1, False, None), # addr 1
(0xdeadbef2, False, None), # addr 2
(0xdeadbef3, False, None), # addr 3
(0xbeefb055, False, None), # target
]
await check_instruction_sequence(dut, expected_cpu_outputs)
@cocotb.test
async def test_indirect(dut):
cocotb.start_soon(Clock(dut.clk, CLK_PERIOD, unit="ns").start())
cocotb.start_soon(handle_memory(dut))
write_dword(0xfffffff8, 0x200)
# jmp ($deadbeef)
write_bytes(0x200, [0x6c, 0xef, 0xbe, 0xad, 0xde])
write_byte(0xbeefb055, 0xcb)
write_dword(0xdeadbeef, 0xbeefb055)
dut.RDY.value = Immediate(1)
dut.reset.value = Immediate(1)
for _ in range(10):
await RisingEdge(dut.clk)
dut.reset.value = 0
expected_cpu_outputs = [
None, # ignore reset sequence
None,
None,
None,
None,
None,
None,
None,
None,
(0x00000200, False, None), # jmp ($deadbeef)
(0x00000201, False, None), # addr 0
(0x00000202, False, None), # addr 1
(0x00000203, False, None), # addr 2
(0x00000204, False, None), # addr 3
(0xdeadbeef, False, None), # addr 0
(0xdeadbef0, False, None), # addr 1
(0xdeadbef1, False, None), # addr 2
(0xdeadbef2, False, None), # addr 3
(0xbeefb055, False, None), # target
]
await check_instruction_sequence(dut, expected_cpu_outputs)
@cocotb.test
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(0xfffffff8, 0x200)
# ldy #1
# lda ($04),y
# iny
# inc
# sta ($04),y
write_bytes(0x200, [0xa0, 0x02])
write_bytes(0x202, [0xb1, 0x04])
write_bytes(0x204, [0xc8])
write_bytes(0x205, [0x1a])
write_bytes(0x206, [0x91, 0x04])
write_byte(0x208, 0xcb)
write_dword(0x04, 0xabcdbeef)
write_dword(0xabcdbeef+2, 0xaa)
dut.RDY.value = Immediate(1)
dut.reset.value = Immediate(1)
for _ in range(10):
await RisingEdge(dut.clk)
dut.reset.value = 0
expected_cpu_outputs = [
None, # ignore reset sequence
None,
None,
None,
None,
None,
None,
None,
None,
(0x00000200, False, None), # ldy #0
(0x00000201, False, None), # Immediate
(0x00000202, False, None), # lda ($04),y
(0x00000203, False, None), # ZP index
(0x00000004, False, None), # zp addr 0
(0x00000005, False, None), # zp addr 1
(0x00000006, False, None), # zp addr 2
(0x00000007, False, None), # zp addr 3
(0xabcdbef1, False, None), # fetch data
(0x00000204, False, None), # iny
(0x00000205, False, None), # iny
(0x00000205, False, None), # inc
(0x00000206, False, None), # inc
(0x00000206, False, None), # sta ($04),y
(0x00000207, False, None), # ZP index
(0x00000004, False, None), # zp addr 0
(0x00000005, False, None), # zp addr 1
(0x00000006, False, None), # zp addr 2
(0x00000007, False, None), # zp addr 3
(0xabcdbef2, False, None), # store takes extra cycle
(0xabcdbef2, True, 0xAB), # write data
]
await check_instruction_sequence(dut, expected_cpu_outputs)
@cocotb.test
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(0xfffffff8, 0x200)
# ldx #4
# lda ($04,x)
# inc
# ldx #8
# sta ($04,x)
write_bytes(0x200, [0xa2, 0x04])
write_bytes(0x202, [0xa1, 0x04])
write_bytes(0x204, [0x1a])
write_bytes(0x205, [0xa2, 0x08])
write_bytes(0x207, [0x81, 0x04])
write_byte(0x209, 0xcb)
write_dword(0x08, 0xfeedf00d)
write_dword(0x0c, 0xf00d600d)
write_byte(0xfeedf00d, 0x69)
dut.RDY.value = Immediate(1)
dut.reset.value = Immediate(1)
for _ in range(10):
await RisingEdge(dut.clk)
dut.reset.value = 0
expected_cpu_outputs = [
None, # ignore reset sequence
None,
None,
None,
None,
None,
None,
None,
None,
(0x00000200, False, None), # ldx #4
(0x00000201, False, None), # Immediate
(0x00000202, False, None), # lda ($04,x)
(0x00000203, False, None), # ZP index
(0x00000004, False, None), # Compute ZP index
(0x00000008, False, None), # zp addr 0
(0x00000009, False, None), # zp addr 1
(0x0000000a, False, None), # zp addr 2
(0x0000000b, False, None), # zp addr 3
(0xfeedf00d, False, None), # fetch data
(0x00000204, False, None), # iny
(0x00000205, False, None), # iny
(0x00000205, False, None), # inc
(0x00000206, False, None), # inc
(0x00000207, False, None), # sta ($04),y
(0x00000208, False, None), # ZP index
(0x00000004, False, None), # Compute ZP index
(0x0000000c, False, None), # zp addr 0
(0x0000000d, False, None), # zp addr 1
(0x0000000e, False, None), # zp addr 2
(0x0000000f, False, None), # zp addr 3
(0xf00d600d, True, 0x6a), # write data
]
await check_instruction_sequence(dut, expected_cpu_outputs)
@cocotb.test
async def test_jsr(dut):
cocotb.start_soon(Clock(dut.clk, CLK_PERIOD, unit="ns").start())
cocotb.start_soon(handle_memory(dut))
write_dword(0xfffffff8, 0x200)
# @0x200
# ldx #$0
# txs
# jsr $12345678
# wai
#
# @0x1234
# rts
write_bytes(0x200, [0xa2, 0xff, 0x9a, 0x20, 0x78, 0x56, 0x34, 0x12, 0xcb])
write_bytes(0x12345678, [0x60])
dut.RDY.value = Immediate(1)
dut.reset.value = Immediate(1)
for _ in range(10):
await RisingEdge(dut.clk)
dut.reset.value = 0
expected_cpu_outputs = [
None, # ignore reset sequence
None,
None,
None,
None,
None,
None,
None,
None,
(0x00000200, False, None), # ldx #$00
(0x00000201, False, None), # Immediate
(0x00000202, False, None), # txs
(0x00000203, False, None), # second cycle of txs
(0x00000203, False, None), # jsr $12345678
(0x00000204, False, None), # first byte of address
(0x000001ff, True, 0x00), # 24-31
(0x000001fe, True, 0x00), # 16-23
(0x000001fd, True, 0x02), # 8-15
(0x000001fc, True, 0x05), # 7-0
(0x00000205, False, None), # second byte of address
(0x00000206, False, None), # third byte of address
(0x00000207, False, None), # fourth byte of address
(0x00000208, False, None), # receive last byte of address
(0x12345678, False, None), # rts
(0x12345679, False, None), # rts
(0x000001fb, False, None), # current stack while we add 1 to it
(0x000001fc, False, None), # 7-0
(0x000001fd, False, None), # 15-8
(0x000001fe, False, None), # 23-16
(0x000001ff, False, None), # 31-24
(0x1234567c, False, None), # Updating PC before jump
(0x00000208, False, None), # WAI
(0x00000209, False, None), # second wai
]
await check_instruction_sequence(dut, expected_cpu_outputs)
@cocotb.test
async def test_rti(dut):
cocotb.start_soon(Clock(dut.clk, CLK_PERIOD, unit="ns").start())
cocotb.start_soon(handle_memory(dut))
write_dword(0xfffffff8, 0x200)
write_dword(0xfffffffc, 0x300)
# @0x200
# ldx #$ff
# txs
# brk
# wai
# @0x300
# rti
write_bytes(0x200, [0xa2, 0xff, 0x9a, 0x00, 0x00, 0xcb]) # BRK is technically a 2 byte instruction
write_bytes(0x300, [0x40])
dut.RDY.value = Immediate(1)
dut.reset.value = Immediate(1)
for _ in range(10):
await RisingEdge(dut.clk)
dut.reset.value = 0
expected_cpu_outputs = [
None, # ignore reset sequence
None,
None,
None,
None,
None,
None,
None,
None,
(0x00000200, False, None), # ldx #$ff
(0x00000201, False, None), # immediate
(0x00000202, False, None), # txs
(0x00000203, False, None), # txs
(0x00000203, False, None), # brk
(0x00000204, False, None), # brk
(0x000001ff, True, 0x00), # brk 31-24
(0x000001fe, True, 0x00), # brk 13-16
(0x000001fd, True, 0x02), # brk 15-08
(0x000001fc, True, 0x05), # brk 07-00
(0x000001fb, True, 0xb4), # brk flags
(0xfffffffc, False, None), # vector
(0xfffffffd, False, None), # vector
(0xfffffffe, False, None), # vector
(0xffffffff, False, None), # vector
(0x00000300, False, None), # rti
(0x00000301, False, None), # rti
(0x000001fa, False, None), # rti
(0x000001fb, False, None), # rti
(0x000001fc, False, None), # rti
(0x000001fd, False, None), # rti
(0x000001fe, False, None), # rti
(0x000001ff, False, None), # rti
(0x00000205, False, None), # wai
]
await check_instruction_sequence(dut, expected_cpu_outputs)
@cocotb.test
async def test_irq(dut):
cocotb.start_soon(Clock(dut.clk, CLK_PERIOD, unit="ns").start())
cocotb.start_soon(handle_memory(dut))
write_dword(0xfffffff8, 0x200)
write_dword(0xfffffffc, 0x300)
# @0x200
# cli
# wai
# wai
# 0x300
# rti
write_bytes(0x200, [0x58, 0xcb, 0xcb])
write_bytes(0x300, [0x40])
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)
await RisingEdge(dut.clk)
await RisingEdge(dut.clk)
dut.IRQ.value = 1
while True:
await RisingEdge(dut.clk)
if int(dut.state.value) == 0x08:
break
dut.IRQ.value = 0
await Timer(300, "ns")
assert int(dut.RDY_O.value) == 0
@cocotb.test
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(0xfffffff8, 0xfffffd)
# L1: bra L1 0x80 0x03
# nop
# nop
# L2: bra L2
write_bytes(0xfffffd, [0x80, 0x3, 0x00, 0x00, 0x00, 0x80, 0xfe])
dut.RDY.value = Immediate(1)
dut.reset.value = Immediate(1)
for _ in range(10):
await RisingEdge(dut.clk)
dut.reset.value = 0
count = 0
async def count_address():
nonlocal count
while True:
await RisingEdge(dut.clk)
if int(dut.AB.value) == 0x01000004:
count+=1
cocotb.start_soon(count_address())
await Timer(1, "us")
assert count > 0
@cocotb.test
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(0xfffffff8, 0xfffffd)
# lda #$00
# bne <anywhere>
# wai
write_bytes(0xfffffd, [0xa9, 0x00, 0xd0, 0x7f, 0xd0, 0x80, 0xd0, 0xfe, 0xcb])
dut.RDY.value = Immediate(1)
dut.reset.value = Immediate(1)
for _ in range(10):
await RisingEdge(dut.clk)
dut.reset.value = 0
expected_cpu_outputs = [
None, # ignore reset sequence
None,
None,
None,
None,
None,
None,
None,
None,
(0x00fffffd, False, None),
(0x00fffffe, False, None),
(0x00ffffff, False, None),
(0x01000000, False, None),
(0x01000001, False, None),
(0x01000002, False, None),
(0x01000003, False, None),
(0x01000004, False, None),
(0x01000005, False, None),
(0x01000006, False, None),
(0x01000006, False, None),
(0x01000006, False, None),
]
await check_instruction_sequence(dut, expected_cpu_outputs)
@cocotb.test
async def test_adc(dut):
cocotb.start_soon(Clock(dut.clk, CLK_PERIOD, unit="ns").start())
cocotb.start_soon(handle_memory(dut))
write_dword(0xfffffff8, 0x200)
def zp_indirect():
value = random.randint(0,255)
address = random.randint(0x300, 0xffffffff)
address_le = struct.pack("<I", address)
# lda #$0
# adc ($00)
# wai
write_bytes(0x200, [0xa9, 0x00, 0x72, 0x00, 0xcb])
write_bytes(0x00, address_le)
write_byte(address, value)
return value
def absolute():
value = random.randint(0,255)
address = random.randint(0x300, 0xffffffff)
address_le = struct.pack("<I", address)
# lda $#0
# adc $address
# wai
write_bytes(0x200, [0xa9, 0x00, 0x6d])
write_bytes(0x203, address_le)
write_bytes(0x207, [0xcb])
write_byte(address, value)
return value
def indirect_x():
value = random.randint(0,255)
address = random.randint(0x300, 0xffffff00)
x_offset = random.randint(0,250)
address_le = struct.pack("<I", address)
# lda #$0
# ldx #x_offset
# adc ($00,x)
# wai
write_bytes(0x200, [0xa9, 0x00, 0xa2, x_offset, 0x61, 0x00, 0xcb])
write_bytes(x_offset, address_le)
write_byte(address, value)
return value
tests = [zp_indirect, absolute, indirect_x]
for test in tests:
value = test()
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)
assert value == int(dut.A.value)

View File

@@ -33,7 +33,8 @@ async def test_sanity(dut):
await RisingEdge(dut.clk) await RisingEdge(dut.clk)
# await s_axi.write(0x200, [0x58, 0xa9, 0x00, 0x1a, 0xcb, 0x4c, 0x03, 0x02]) # await s_axi.write(0x200, [0x58, 0xa9, 0x00, 0x1a, 0xcb, 0x4c, 0x03, 0x02])
await s_axi.write(0x200, [0xAD, 0x00, 0xE0, 0xAD, 0x01, 0xE0, 0xAD, 0x02, 0xE0, 0xAD, 0x03, 0xE0, 0xAD, 0x04, 0xE0, 0xCB]) # await s_axi.write(0x200, [0xAD, 0x00, 0xE0, 0xAD, 0x01, 0xE0, 0xAD, 0x02, 0xE0, 0xAD, 0x03, 0xE0, 0xAD, 0x04, 0xE0, 0xCB])
await s_axi.write(0x200, [0x80, 0xfe])
cocotb.start_soon(s_axi.read(0x200, 8)) cocotb.start_soon(s_axi.read(0x200, 8))

View File

@@ -52,7 +52,7 @@ module cpu_65c02( clk, reset, AB, DI, DO, WE, IRQ, NMI, RDY, RDY_O, SYNC );
input clk; // CPU clock input clk; // CPU clock
input reset; // reset signal input reset; // reset signal
output reg [15:0] AB; // address bus output reg [31:0] AB; // address bus
input [7:0] DI; // data in, read bus input [7:0] DI; // data in, read bus
output [7:0] DO; // data out, write bus output [7:0] DO; // data out, write bus
output WE; // write enable output WE; // write enable
@@ -66,10 +66,13 @@ output reg SYNC; // AB is first cycle of the intruction
* internal signals * internal signals
*/ */
reg [15:0] PC; // Program Counter reg [31:0] PC; // Program Counter
reg [7:0] ABL; // Address Bus Register LSB reg abr_inc; // should increase address bus register
reg [7:0] ABH; // Address Bus Register MSB reg [31:0] ABR; // Address Bus Register
wire [7:0] ADD; // Adder Hold Register (registered in ALU) wire [7:0] ADD; // Adder Hold Register (registered in ALU)
reg [7:0] alu_sr_0; // ALU output shift register 0
reg [7:0] alu_sr_1; // ALU output shift register 1
reg [7:0] alu_sr_2; // ALU output shift register 2
reg [7:0] DIHOLD; // Hold for Data In reg [7:0] DIHOLD; // Hold for Data In
reg DIHOLD_valid; // reg DIHOLD_valid; //
@@ -103,8 +106,6 @@ wire [7:0] AO; // ALU output after BCD adjustment
reg WE; // Write Enable reg WE; // Write Enable
reg CI; // Carry In reg CI; // Carry In
wire CO; // Carry Out wire CO; // Carry Out
wire [7:0] PCH = PC[15:8];
wire [7:0] PCL = PC[7:0];
reg NMI_edge = 0; // captured NMI edge reg NMI_edge = 0; // captured NMI edge
@@ -135,18 +136,21 @@ wire [7:0] P = { N, V, 2'b11, D, I, Z, C };
* instruction decoder/sequencer * instruction decoder/sequencer
*/ */
reg [5:0] state; reg [6:0] state;
/* /*
* control signals * control signals
*/ */
reg PC_inc; // Increment PC reg [1:0] PC_inc; // Increment PC
reg [15:0] PC_temp; // intermediate value of PC reg [31:0] PC_temp; // intermediate value of PC
reg [1:0] src_reg; // source register index reg [1:0] src_reg; // source register index
reg [1:0] dst_reg; // destination register index reg [1:0] dst_reg; // destination register index
reg sr_sel; // choose to load shift register from dimux or from alu
reg alu_sr_enable; // choose to shift or not
reg index_y; // if set, then Y is index reg rather than X reg index_y; // if set, then Y is index reg rather than X
reg load_reg; // loading a register (A, X, Y, S) in this instruction reg load_reg; // loading a register (A, X, Y, S) in this instruction
reg inc; // increment reg inc; // increment
@@ -201,6 +205,10 @@ parameter
OP_ROL = 4'b1011, OP_ROL = 4'b1011,
OP_A = 4'b1111; OP_A = 4'b1111;
parameter
SR_ALU = 1'b0,
SR_DI = 1'b1;
/* /*
* Microcode state machine. Basically, every addressing mode has its own * Microcode state machine. Basically, every addressing mode has its own
* path through the state machine. Additional information, such as the * path through the state machine. Additional information, such as the
@@ -209,61 +217,89 @@ parameter
*/ */
parameter parameter
ABS0 = 6'd0, // ABS - fetch LSB ABS0 = 7'd0, // ABS - fetch LSB
ABS1 = 6'd1, // ABS - fetch MSB ABS1 = 7'd1, // ABS - fetch MSB
ABSX0 = 6'd2, // ABS, X - fetch LSB and send to ALU (+X) ABSX0 = 7'd2, // ABS, X - fetch LSB and send to ALU (+X)
ABSX1 = 6'd3, // ABS, X - fetch MSB and send to ALU (+Carry) ABSX1 = 7'd3, // ABS, X - fetch MSB and send to ALU (+Carry)
ABSX2 = 6'd4, // ABS, X - Wait for ALU (only if needed) ABSX2 = 7'd4, // ABS, X - Wait for ALU (only if needed)
BRA0 = 6'd5, // Branch - fetch offset and send to ALU (+PC[7:0]) BRA0 = 7'd5, // Branch - fetch offset and send to ALU (+PC[7:0])
BRA1 = 6'd6, // Branch - fetch opcode, and send PC[15:8] to ALU BRA1 = 7'd6, // Branch - fetch opcode, and send PC[15:8] to ALU
BRA2 = 6'd7, // Branch - fetch opcode (if page boundary crossed) BRA2 = 7'd7, // Branch - fetch opcode (if page boundary crossed)
BRK0 = 6'd8, // BRK/IRQ - push PCH, send S to ALU (-1) BRK0 = 7'd8, // BRK/IRQ - push PCH, send S to ALU (-1)
BRK1 = 6'd9, // BRK/IRQ - push PCL, send S to ALU (-1) BRK1 = 7'd9, // BRK/IRQ - push PCL, send S to ALU (-1)
BRK2 = 6'd10, // BRK/IRQ - push P, send S to ALU (-1) BRK2 = 7'd10, // BRK/IRQ - push P, send S to ALU (-1)
BRK3 = 6'd11, // BRK/IRQ - write S, and fetch @ fffe BRK3 = 7'd11, // BRK/IRQ - write S, and fetch @ fffe
DECODE = 6'd12, // IR is valid, decode instruction, and write prev reg DECODE = 7'd12, // IR is valid, decode instruction, and write prev reg
FETCH = 6'd13, // fetch next opcode, and perform prev ALU op FETCH = 7'd13, // fetch next opcode, and perform prev ALU op
INDX0 = 6'd14, // (ZP,X) - fetch ZP address, and send to ALU (+X) INDX0 = 7'd14, // (ZP,X) - fetch ZP address, and send to ALU (+X)
INDX1 = 6'd15, // (ZP,X) - fetch LSB at ZP+X, calculate ZP+X+1 INDX1 = 7'd15, // (ZP,X) - fetch LSB at ZP+X, calculate ZP+X+1
INDX2 = 6'd16, // (ZP,X) - fetch MSB at ZP+X+1 INDX2 = 7'd16, // (ZP,X) - fetch MSB at ZP+X+1
INDX3 = 6'd17, // (ZP,X) - fetch data INDX5 = 7'd17, // (ZP,X) - fetch data
INDY0 = 6'd18, // (ZP),Y - fetch ZP address, and send ZP to ALU (+1) INDY0 = 7'd18, // (ZP),Y - fetch ZP address
INDY1 = 6'd19, // (ZP),Y - fetch at ZP+1, and send LSB to ALU (+Y) INDY1 = 7'd19, // (ZP),Y - fetch at ZP+1, and send byte 0 to ALU (+Y)
INDY2 = 6'd20, // (ZP),Y - fetch data, and send MSB to ALU (+Carry) INDY2 = 7'd20, // (ZP),Y - fetch at ZP+2, and send byte 1 to ALU (+Carry)
INDY3 = 6'd21, // (ZP),Y) - fetch data (if page boundary crossed) INDY5 = 7'd21, // (ZP),Y) - fetch data (if page boundary crossed)
JMP0 = 6'd22, // JMP - fetch PCL and hold JMP0 = 7'd22, // JMP - fetch PCL and hold
JMP1 = 6'd23, // JMP - fetch PCH JMP1 = 7'd23, // JMP - fetch PCH
JMPI0 = 6'd24, // JMP IND - fetch LSB and send to ALU for delay (+0) JMPI0 = 7'd24, // JMP IND - fetch LSB and send to ALU for delay (+0)
JMPI1 = 6'd25, // JMP IND - fetch MSB, proceed with JMP0 state JMPI1 = 7'd25, // JMP IND - fetch MSB, proceed with JMP0 state
JSR0 = 6'd26, // JSR - push PCH, save LSB, send S to ALU (-1) JSR0 = 7'd26, // JSR - push PCH, save LSB, send S to ALU (-1)
JSR1 = 6'd27, // JSR - push PCL, send S to ALU (-1) JSR1 = 7'd27, // JSR - push PCL, send S to ALU (-1)
JSR2 = 6'd28, // JSR - write S JSR2 = 7'd28, // JSR - write S
JSR3 = 6'd29, // JSR - fetch MSB JSR4 = 7'd29, // JSR - fetch MSB
PULL0 = 6'd30, // PLP/PLA/PLX/PLY - save next op in IRHOLD, send S to ALU (+1) PULL0 = 7'd30, // PLP/PLA/PLX/PLY - save next op in IRHOLD, send S to ALU (+1)
PULL1 = 6'd31, // PLP/PLA/PLX/PLY - fetch data from stack, write S PULL1 = 7'd31, // PLP/PLA/PLX/PLY - fetch data from stack, write S
PULL2 = 6'd32, // PLP/PLA/PLX/PLY - prefetch op, but don't increment PC PULL2 = 7'd32, // PLP/PLA/PLX/PLY - prefetch op, but don't increment PC
PUSH0 = 6'd33, // PHP/PHA/PHX/PHY - send A to ALU (+0) PUSH0 = 7'd33, // PHP/PHA/PHX/PHY - send A to ALU (+0)
PUSH1 = 6'd34, // PHP/PHA/PHX/PHY - write A/P, send S to ALU (-1) PUSH1 = 7'd34, // PHP/PHA/PHX/PHY - write A/P, send S to ALU (-1)
READ = 6'd35, // Read memory for read/modify/write (INC, DEC, shift) READ = 7'd35, // Read memory for read/modify/write (INC, DEC, shift)
REG = 6'd36, // Read register for reg-reg transfers REG = 7'd36, // Read register for reg-reg transfers
RTI0 = 6'd37, // RTI - send S to ALU (+1) RTI0 = 7'd37, // RTI - send S to ALU (+1)
RTI1 = 6'd38, // RTI - read P from stack RTI1 = 7'd38, // RTI - read P from stack
RTI2 = 6'd39, // RTI - read PCL from stack RTI2 = 7'd39, // RTI - read PCL from stack
RTI3 = 6'd40, // RTI - read PCH from stack RTI3 = 7'd40, // RTI - read PCH from stack
RTI4 = 6'd41, // RTI - read PCH from stack RTI6 = 7'd41, // RTI - read PCH from stack
RTS0 = 6'd42, // RTS - send S to ALU (+1) RTS0 = 7'd42, // RTS - send S to ALU (+1)
RTS1 = 6'd43, // RTS - read PCL from stack RTS1 = 7'd43, // RTS - read PCL from stack
RTS2 = 6'd44, // RTS - write PCL to ALU, read PCH RTS2 = 7'd44, // RTS - write PCL to ALU, read PCH
RTS3 = 6'd45, // RTS - load PC and increment RTS5 = 7'd45, // RTS - load PC and increment
WRITE = 6'd46, // Write memory for read/modify/write WRITE = 7'd46, // Write memory for read/modify/write
ZP0 = 6'd47, // Z-page - fetch ZP address ZP0 = 7'd47, // Z-page - fetch ZP address
ZPX0 = 6'd48, // ZP, X - fetch ZP, and send to ALU (+X) ZPX0 = 7'd48, // ZP, X - fetch ZP, and send to ALU (+X)
ZPX1 = 6'd49, // ZP, X - load from memory ZPX1 = 7'd49, // ZP, X - load from memory
IND0 = 6'd50, // (ZP) - fetch ZP address, and send to ALU (+0) IND0 = 7'd50, // (ZP) - fetch ZP address, and send to ALU (+0)
JMPIX0 = 6'd51, // JMP (,X)- fetch LSB and send to ALU (+X) JMPIX0 = 7'd51, // JMP (,X)- fetch LSB and send to ALU (+X)
JMPIX1 = 6'd52, // JMP (,X)- fetch MSB and send to ALU (+Carry) JMPIX1 = 7'd52, // JMP (,X)- fetch MSB and send to ALU (+Carry)
JMPIX2 = 6'd53, // JMP (,X)- Wait for ALU (only if needed) JMPIX2 = 7'd53, // JMP (,X)- Wait for ALU (only if needed)
WAI = 6'd54; // WAI - Wait for interrupt, then go to decode WAI = 7'd54, // WAI - Wait for interrupt, then go to decode
BRK4 = 7'd55, // TODO
BRK5 = 7'd56, // TODO
JMP2 = 7'd57, // TODO
JMP3 = 7'd58, // TODO
ABS2 = 7'd59, // TODO
ABS3 = 7'd60, // TODO
ABSX3 = 7'd61, // TODO
ABSX4 = 7'd62, // TODO
JMPIX3 = 7'd63, // TODO
JMPIX4 = 7'd64, // TODO
JMPI2 = 7'd65, // TODO
JMPI3 = 7'd66, // TODO
INDY3 = 7'd67, // (ZP),Y - fetch at ZP+3, and send byte 2 to ALU (+Carry)
INDY4 = 7'd68, // (ZP),Y - fetch data, and send byte 3 to ALU (+Carry)
INDX3 = 7'd69, // (ZP,X) - fetch addr 2 at ZP+X+2
INDX4 = 7'd70, // (ZP,X) - fetch addr 3 at ZP+X+3
JSR3 = 7'd71,
JSR5 = 7'd73,
JSR6 = 7'd74,
JSR7 = 7'd75,
RTS3 = 7'd76,
RTS4 = 7'd77,
RTI4 = 7'd78,
RTI5 = 7'd79,
BRA3 = 7'd80,
BRA4 = 7'd81,
BRA5 = 7'd82;
`ifdef SIM `ifdef SIM
@@ -281,18 +317,26 @@ always @*
ZPX1: statename = "ZPX1"; ZPX1: statename = "ZPX1";
ABS0: statename = "ABS0"; ABS0: statename = "ABS0";
ABS1: statename = "ABS1"; ABS1: statename = "ABS1";
ABS2: statename = "ABS2";
ABS3: statename = "ABS3";
ABSX0: statename = "ABSX0"; ABSX0: statename = "ABSX0";
ABSX1: statename = "ABSX1"; ABSX1: statename = "ABSX1";
ABSX2: statename = "ABSX2"; ABSX2: statename = "ABSX2";
ABSX3: statename = "ABSX3";
ABSX4: statename = "ABSX4";
IND0: statename = "IND0"; IND0: statename = "IND0";
INDX0: statename = "INDX0"; INDX0: statename = "INDX0";
INDX1: statename = "INDX1"; INDX1: statename = "INDX1";
INDX2: statename = "INDX2"; INDX2: statename = "INDX2";
INDX3: statename = "INDX3"; INDX3: statename = "INDX3";
INDX4: statename = "INDX4";
INDX5: statename = "INDX5";
INDY0: statename = "INDY0"; INDY0: statename = "INDY0";
INDY1: statename = "INDY1"; INDY1: statename = "INDY1";
INDY2: statename = "INDY2"; INDY2: statename = "INDY2";
INDY3: statename = "INDY3"; INDY3: statename = "INDY3";
INDY4: statename = "INDY4";
INDY5: statename = "INDY5";
READ: statename = "READ"; READ: statename = "READ";
WRITE: statename = "WRITE"; WRITE: statename = "WRITE";
FETCH: statename = "FETCH"; FETCH: statename = "FETCH";
@@ -305,29 +349,48 @@ always @*
JSR1: statename = "JSR1"; JSR1: statename = "JSR1";
JSR2: statename = "JSR2"; JSR2: statename = "JSR2";
JSR3: statename = "JSR3"; JSR3: statename = "JSR3";
JSR4: statename = "JSR4";
JSR5: statename = "JSR5";
JSR6: statename = "JSR6";
JSR7: statename = "JSR7";
RTI0: statename = "RTI0"; RTI0: statename = "RTI0";
RTI1: statename = "RTI1"; RTI1: statename = "RTI1";
RTI2: statename = "RTI2"; RTI2: statename = "RTI2";
RTI3: statename = "RTI3"; RTI3: statename = "RTI3";
RTI4: statename = "RTI4"; RTI4: statename = "RTI4";
RTI5: statename = "RTI5";
RTI6: statename = "RTI6";
RTS0: statename = "RTS0"; RTS0: statename = "RTS0";
RTS1: statename = "RTS1"; RTS1: statename = "RTS1";
RTS2: statename = "RTS2"; RTS2: statename = "RTS2";
RTS3: statename = "RTS3"; RTS3: statename = "RTS3";
RTS4: statename = "RTS4";
RTS5: statename = "RTS5";
BRK0: statename = "BRK0"; BRK0: statename = "BRK0";
BRK1: statename = "BRK1"; BRK1: statename = "BRK1";
BRK2: statename = "BRK2"; BRK2: statename = "BRK2";
BRK3: statename = "BRK3"; BRK3: statename = "BRK3";
BRK4: statename = "BRK4";
BRK5: statename = "BRK5";
BRA0: statename = "BRA0"; BRA0: statename = "BRA0";
BRA1: statename = "BRA1"; BRA1: statename = "BRA1";
BRA2: statename = "BRA2"; BRA2: statename = "BRA2";
BRA3: statename = "BRA3";
BRA4: statename = "BRA4";
BRA5: statename = "BRA5";
JMP0: statename = "JMP0"; JMP0: statename = "JMP0";
JMP1: statename = "JMP1"; JMP1: statename = "JMP1";
JMP2: statename = "JMP2";
JMP3: statename = "JMP3";
JMPI0: statename = "JMPI0"; JMPI0: statename = "JMPI0";
JMPI1: statename = "JMPI1"; JMPI1: statename = "JMPI1";
JMPI2: statename = "JMPI2";
JMPI3: statename = "JMPI3";
JMPIX0: statename = "JMPIX0"; JMPIX0: statename = "JMPIX0";
JMPIX1: statename = "JMPIX1"; JMPIX1: statename = "JMPIX1";
JMPIX2: statename = "JMPIX2"; JMPIX2: statename = "JMPIX2";
JMPIX3: statename = "JMPIX3";
JMPIX4: statename = "JMPIX4";
WAI: statename = "WAI"; WAI: statename = "WAI";
endcase endcase
@@ -346,25 +409,28 @@ always @*
always @* always @*
case( state ) case( state )
DECODE: if( (~I & IRQ) | NMI_edge ) DECODE: if( (~I & IRQ) | NMI_edge )
PC_temp = { ABH, ABL }; PC_temp = ABR;
else else
PC_temp = PC; PC_temp = PC;
JMP1, JMP3,
JMPI1, JMPI3,
JMPIX1, JMPIX3,
JSR3, JSR7,
RTS3, RTI6: PC_temp = { DIMUX, ADD, alu_sr_0, alu_sr_1};
RTI4: PC_temp = { DIMUX, ADD };
BRA1: PC_temp = { ABH, ADD }; RTS5: PC_temp = { DIMUX, ADD, alu_sr_0, alu_sr_1} + 2;
JMPIX2, BRA1: PC_temp = AB;
BRA2: PC_temp = { ADD, PCL }; BRA2: PC_temp = AB;
BRA3: PC_temp = AB;
BRA4: PC_temp = AB;
BRK2: PC_temp = res ? 16'hfffc : JMPIX4,
NMI_edge ? 16'hfffa : 16'hfffe;
BRK4: PC_temp = res ? 32'hFFFFFFF8 :
NMI_edge ? 32'hFFFFFFFC : 32'hFFFFFFFC;
default: PC_temp = PC; default: PC_temp = PC;
endcase endcase
@@ -374,27 +440,51 @@ always @*
*/ */
always @* always @*
case( state ) case( state )
DECODE: if( (~I & IRQ) | NMI_edge ) DECODE: if( (~I & IRQ) | NMI_edge ) begin
PC_inc = 0; PC_inc = 0;
else end else if (IR == 8'b1100_1011) begin
PC_inc = 0;
end else begin
PC_inc = 1; PC_inc = 1;
end
ABS0, ABS0,
ABS1,
ABS2,
JMPIX0, JMPIX0,
JMPIX1,
JMPIX2, JMPIX2,
JMPIX4,
ABSX0, ABSX0,
ABSX1,
ABSX2,
FETCH, FETCH,
BRA0, BRA0,
BRA1,
BRA2, BRA2,
BRK3, BRA3,
BRA4,
BRA5,
BRK5,
JMPI0,
JMPI1, JMPI1,
JMPI2,
JMPI3,
JMP0,
JMP1, JMP1,
RTI4, JMP2,
RTS3: PC_inc = 1; JMP3,
JSR4,
JSR5,
JSR6,
RTI6,
RTS3,
RTS4,
RTS5: PC_inc = 1;
JMPIX1: PC_inc = ~CO; // Don't increment PC if we are going to go through JMPIX2 JMPIX3: PC_inc = {1'b0, ~CO}; // Don't increment PC if we are going to go through JMPIX4
BRA1: PC_inc = CO ^~ backwards; BRA1: PC_inc = {1'b0, CO ^~ backwards};
default: PC_inc = 0; default: PC_inc = 0;
endcase endcase
@@ -416,49 +506,65 @@ parameter
always @* always @*
case( state ) case( state )
JMPIX1, JMPIX3,
ABSX1, ABSX3,
INDX3, INDX5,
INDY2, JMP3,
JMP1, JMPI3,
JMPI1, RTI6,
RTI4, ABS3: AB = { DIMUX, ADD, alu_sr_0, alu_sr_1};
ABS1: AB = { DIMUX, ADD };
BRA2, JMPIX4,
INDY3, ABSX4: AB = { ADD, ABR[23:0] }; // TODO
JMPIX2,
ABSX2: AB = { ADD, ABL };
BRA1: AB = { ABH, ADD }; BRA1: AB = { ABR[31:8], ADD };
BRA2: AB = { ABR[31:16], ADD, alu_sr_0 };
BRA3: AB = { ABR[31:24], ADD, alu_sr_0, alu_sr_1 };
BRA4: AB = { ADD, alu_sr_0, alu_sr_1, alu_sr_2 };
JSR0, JSR0,
PUSH1, PUSH1,
RTS0, RTS0,
RTI0, RTI0,
BRK0: AB = { STACKPAGE, regfile }; BRK0: AB = { 16'h0, STACKPAGE, regfile };
BRK1, BRK1,
JSR1, JSR1,
JSR2,
JSR3,
PULL1, PULL1,
RTS1, RTS1,
RTS2, RTS2,
RTS3,
RTS4,
RTI1, RTI1,
RTI2, RTI2,
RTI3, RTI3,
BRK2: AB = { STACKPAGE, ADD }; RTI4,
RTI5,
BRK2,
BRK3,
BRK4: AB = { 16'h0, STACKPAGE, ADD };
INDY1,
INDX1, INDX1,
ZPX1, ZPX1: AB = { ZEROPAGE, ADD };
INDX2: AB = { ZEROPAGE, ADD };
ZP0, ZP0,
INDX0,
INDY0: AB = { ZEROPAGE, DIMUX }; INDY0: AB = { ZEROPAGE, DIMUX };
REG, REG,
READ, READ,
WRITE: AB = { ABH, ABL }; INDY1,
INDY2,
INDY3,
INDX2,
INDX3,
INDX4,
WRITE: AB = ABR;
INDY4: AB = {DIMUX, ADD, alu_sr_0, alu_sr_1};
INDY5: AB = {ADD, ABR[23:0]};
default: AB = PC; default: AB = PC;
endcase endcase
@@ -472,10 +578,25 @@ always @(posedge clk)
if( state != PUSH0 && state != PUSH1 && RDY && if( state != PUSH0 && state != PUSH1 && RDY &&
state != PULL0 && state != PULL1 && state != PULL2 ) state != PULL0 && state != PULL1 && state != PULL2 )
begin begin
ABL <= AB[7:0]; if (abr_inc) begin
ABH <= AB[15:8]; ABR <= AB + 1;
end else begin
ABR <= AB;
end
end end
always @* begin
case( state )
INDY0,
INDY1,
INDY2,
INDX1,
INDX2,
INDX3: abr_inc = 1;
default: abr_inc = 0;
endcase
end
/* /*
* Data Out MUX * Data Out MUX
*/ */
@@ -484,14 +605,20 @@ always @*
WRITE: DO = ADD; WRITE: DO = ADD;
JSR0, JSR0,
BRK0: DO = PCH; BRK0: DO = PC[31:24];
JSR1, JSR1,
BRK1: DO = PCL; BRK1: DO = PC[23:16];
JSR2,
BRK2: DO = PC[15:8];
JSR3,
BRK3: DO = PC[7:0];
PUSH1: DO = php ? P : ADD; PUSH1: DO = php ? P : ADD;
BRK2: DO = (IRQ | NMI_edge) ? (P & 8'b1110_1111) : P; BRK4: DO = (IRQ | NMI_edge) ? (P & 8'b1110_1111) : P;
default: DO = store_zero ? 8'b0 : regfile; default: DO = store_zero ? 8'b0 : regfile;
endcase endcase
@@ -505,15 +632,20 @@ always @*
BRK0, // writing to stack or memory BRK0, // writing to stack or memory
BRK1, BRK1,
BRK2, BRK2,
BRK2,
BRK3,
BRK4,
JSR0, JSR0,
JSR1, JSR1,
JSR2,
JSR3,
PUSH1, PUSH1,
WRITE: WE = 1; WRITE: WE = 1;
INDX3, // only if doing a STA, STX or STY INDX5, // only if doing a STA, STX or STY
INDY3, INDY5,
ABSX2, ABSX4,
ABS1, ABS3,
ZPX1, ZPX1,
ZP0: WE = store; ZP0: WE = store;
@@ -533,11 +665,11 @@ always @*
DECODE: write_register = load_reg & ~plp; DECODE: write_register = load_reg & ~plp;
PULL1, PULL1,
RTS2, RTS4,
RTI3, RTI5,
BRK3, BRK5,
JSR0, JSR0,
JSR2 : write_register = 1; JSR4 : write_register = 1;
default: write_register = 0; default: write_register = 0;
endcase endcase
@@ -621,16 +753,18 @@ always @*
DECODE : regsel = dst_reg; DECODE : regsel = dst_reg;
BRK0, BRK0,
BRK3, BRK5,
JSR0, JSR0,
JSR2, JSR2,
JSR3,
JSR4,
PULL0, PULL0,
PULL1, PULL1,
PUSH1, PUSH1,
RTI0, RTI0,
RTI3, RTI5,
RTS0, RTS0,
RTS2 : regsel = SEL_S; RTS4 : regsel = SEL_S;
default: regsel = src_reg; default: regsel = src_reg;
endcase endcase
@@ -654,6 +788,38 @@ ALU ALU( .clk(clk),
.HC(HC), .HC(HC),
.RDY(RDY) ); .RDY(RDY) );
always @(posedge clk) begin
if( RDY )
if (alu_sr_enable) begin
if (sr_sel == SR_ALU) begin
alu_sr_0 <= ADD;
end else begin
alu_sr_0 <= DIMUX;
end
alu_sr_1 <= alu_sr_0;
alu_sr_2 <= alu_sr_1;
end
end
always @* begin
case ( state )
RTS2,
RTS3,
RTI3,
RTI4: sr_sel = SR_DI;
default: sr_sel = SR_ALU;
endcase
end
always @*begin
case ( state)
RTS4,
RTI5: alu_sr_enable = 0;
default: alu_sr_enable = 1;
endcase
end
/* /*
* Select current ALU operation * Select current ALU operation
*/ */
@@ -662,20 +828,27 @@ always @*
case( state ) case( state )
READ: alu_op = op; READ: alu_op = op;
BRA1: alu_op = backwards ? OP_SUB : OP_ADD; BRA1,
BRA2,
BRA3,
BRA4: alu_op = OP_ADD;
FETCH, FETCH,
REG : alu_op = op; REG : alu_op = op;
DECODE, DECODE,
ABS1: alu_op = 1'bx; ABS3: alu_op = 1'bx;
PUSH1, PUSH1,
BRK0, BRK0,
BRK1, BRK1,
BRK2, BRK2,
BRK3,
BRK4,
JSR0, JSR0,
JSR1: alu_op = OP_SUB; JSR1,
JSR2,
JSR3: alu_op = OP_SUB;
default: alu_op = OP_ADD; default: alu_op = OP_ADD;
endcase endcase
@@ -695,7 +868,7 @@ always @*
*/ */
always @(posedge clk) always @(posedge clk)
if( RDY ) if( RDY && state == BRA0)
backwards <= DIMUX[7]; backwards <= DIMUX[7];
/* /*
@@ -705,12 +878,19 @@ always @(posedge clk)
always @* always @*
case( state ) case( state )
JSR1, JSR1,
JSR2,
JSR3,
RTS1, RTS1,
RTS2,
RTS3,
RTI1, RTI1,
RTI2, RTI2,
RTI3,
RTI4,
BRK1, BRK1,
BRK2, BRK2,
INDX1: AI = ADD; BRK3,
BRK4: AI = ADD;
REG, REG,
ZPX0, ZPX0,
@@ -719,8 +899,10 @@ always @*
ABSX0, ABSX0,
RTI0, RTI0,
RTS0, RTS0,
RTS1,
RTS2,
JSR0, JSR0,
JSR2, JSR4,
BRK0, BRK0,
PULL0, PULL0,
INDY1, INDY1,
@@ -730,12 +912,15 @@ always @*
BRA0, BRA0,
READ: AI = DIMUX; READ: AI = DIMUX;
BRA1: AI = ABH; // don't use PCH in case we're BRA1,
BRA2,
BRA3,
BRA4: AI = backwards ? 8'hff : 0;
FETCH: AI = load_only ? 8'b0 : regfile; FETCH: AI = load_only ? 8'b0 : regfile;
DECODE, DECODE,
ABS1: AI = 8'hxx; // don't care ABS3: AI = 8'hxx; // don't care
default: AI = 0; default: AI = 0;
endcase endcase
@@ -747,19 +932,25 @@ always @*
always @* always @*
case( state ) case( state )
BRA1,
RTS1, RTS1,
RTS2,
RTS3,
RTI0, RTI0,
RTI1, RTI1,
RTI2, RTI2,
INDX1, RTI3,
RTI4,
REG, REG,
JSR0, JSR0,
JSR1, JSR1,
JSR2, JSR2,
JSR3,
JSR4,
BRK0, BRK0,
BRK1, BRK1,
BRK2, BRK2,
BRK3,
BRK4,
PUSH0, PUSH0,
PUSH1, PUSH1,
PULL0, PULL0,
@@ -767,10 +958,13 @@ always @*
READ: BI = txb_ins ? (trb_ins ? ~regfile : regfile) : 8'h00; READ: BI = txb_ins ? (trb_ins ? ~regfile : regfile) : 8'h00;
BRA0: BI = PCL; BRA0: BI = ABR[7:0];
BRA1: BI = ABR[15:8];
BRA2: BI = ABR[23:16];
BRA3: BI = ABR[31:24];
DECODE, DECODE,
ABS1: BI = 8'hxx; ABS3: BI = 8'hxx;
default: BI = DIMUX; default: BI = DIMUX;
endcase endcase
@@ -783,11 +977,15 @@ always @*
case( state ) case( state )
INDY2, INDY2,
BRA1, BRA1,
BRA2,
BRA3,
JMPIX1, JMPIX1,
ABSX1: CI = CO; ABSX1,
ABSX2,
ABSX3: CI = CO;
DECODE, DECODE,
ABS1: CI = 1'bx; ABS3: CI = 1'bx;
READ, READ,
REG: CI = rotate ? C : REG: CI = rotate ? C :
@@ -801,10 +999,13 @@ always @*
RTI0, RTI0,
RTI1, RTI1,
RTI2, RTI2,
RTI3,
RTI4,
RTS0, RTS0,
RTS1, RTS1,
INDY0, RTS2,
INDX1: CI = 1; RTS3,
INDY0: CI = 1;
default: CI = 0; default: CI = 0;
endcase endcase
@@ -880,7 +1081,7 @@ always @(posedge clk)
*/ */
always @(posedge clk) always @(posedge clk)
if( state == BRK3 ) if( state == BRK5 )
I <= 1; I <= 1;
else if( state == RTI2 ) else if( state == RTI2 )
I <= DIMUX[2]; I <= DIMUX[2];
@@ -1005,27 +1206,37 @@ always @(posedge clk or posedge reset)
ZPX1 : state <= write_back ? READ : FETCH; ZPX1 : state <= write_back ? READ : FETCH;
ABS0 : state <= ABS1; ABS0 : state <= ABS1;
ABS1 : state <= write_back ? READ : FETCH; ABS1 : state <= ABS2;
ABS2 : state <= ABS3;
ABS3 : state <= write_back ? READ : FETCH;
ABSX0 : state <= ABSX1; ABSX0 : state <= ABSX1;
ABSX1 : state <= (CO | store | write_back) ? ABSX2 : FETCH; ABSX1 : state <= ABSX2;
ABSX2 : state <= write_back ? READ : FETCH; ABSX2 : state <= ABSX3;
ABSX3 : state <= (CO | store | write_back) ? ABSX4 : FETCH;
ABSX4 : state <= write_back ? READ : FETCH;
JMPIX0 : state <= JMPIX1; JMPIX0 : state <= JMPIX1;
JMPIX1 : state <= CO ? JMPIX2 : JMP0; JMPIX1 : state <= JMPIX2;
JMPIX2 : state <= JMP0; JMPIX2 : state <= JMPIX3;
JMPIX3 : state <= CO ? JMPIX4 : JMP0;
JMPIX4 : state <= JMP0;
IND0 : state <= INDX1; IND0 : state <= INDX1;
INDX0 : state <= INDX1; INDX0 : state <= INDX1;
INDX1 : state <= INDX2; INDX1 : state <= INDX2;
INDX2 : state <= INDX3; INDX2 : state <= INDX3;
INDX3 : state <= FETCH; INDX3 : state <= INDX4;
INDX4 : state <= INDX5;
INDX5 : state <= FETCH;
INDY0 : state <= INDY1; INDY0 : state <= INDY1;
INDY1 : state <= INDY2; INDY1 : state <= INDY2;
INDY2 : state <= (CO | store) ? INDY3 : FETCH; INDY2 : state <= INDY3;
INDY3 : state <= FETCH; INDY3 : state <= INDY4;
INDY4 : state <= (CO | store) ? INDY5 : FETCH;
INDY5 : state <= FETCH;
READ : state <= WRITE; READ : state <= WRITE;
WRITE : state <= FETCH; WRITE : state <= FETCH;
@@ -1043,33 +1254,50 @@ always @(posedge clk or posedge reset)
JSR0 : state <= JSR1; JSR0 : state <= JSR1;
JSR1 : state <= JSR2; JSR1 : state <= JSR2;
JSR2 : state <= JSR3; JSR2 : state <= JSR3;
JSR3 : state <= FETCH; JSR3 : state <= JSR4;
JSR4 : state <= JSR5;
JSR5 : state <= JSR6;
JSR6 : state <= JSR7;
JSR7 : state <= FETCH;
RTI0 : state <= RTI1; RTI0 : state <= RTI1;
RTI1 : state <= RTI2; RTI1 : state <= RTI2;
RTI2 : state <= RTI3; RTI2 : state <= RTI3;
RTI3 : state <= RTI4; RTI3 : state <= RTI4;
RTI4 : state <= DECODE; RTI4 : state <= RTI5;
RTI5 : state <= RTI6;
RTI6 : state <= DECODE;
RTS0 : state <= RTS1; RTS0 : state <= RTS1;
RTS1 : state <= RTS2; RTS1 : state <= RTS2;
RTS2 : state <= RTS3; RTS2 : state <= RTS3;
RTS3 : state <= FETCH; RTS3 : state <= RTS4;
RTS4 : state <= RTS5;
RTS5 : state <= FETCH;
BRA0 : state <= cond_true ? BRA1 : DECODE; BRA0 : state <= cond_true ? BRA1 : DECODE;
BRA1 : state <= (CO ^ backwards) ? BRA2 : DECODE; BRA1 : state <= (CO ^ backwards) ? BRA2 : BRA5;
BRA2 : state <= DECODE; BRA2 : state <= (CO ^ backwards) ? BRA3 : BRA5;
BRA3 : state <= (CO ^ backwards) ? BRA4 : BRA5;
BRA4 : state <= BRA5;
BRA5 : state <= DECODE;
JMP0 : state <= JMP1; JMP0 : state <= JMP1;
JMP1 : state <= DECODE; JMP1 : state <= JMP2;
JMP2 : state <= JMP3;
JMP3 : state <= DECODE;
JMPI0 : state <= JMPI1; JMPI0 : state <= JMPI1;
JMPI1 : state <= JMP0; JMPI1 : state <= JMPI2;
JMPI2 : state <= JMPI3;
JMPI3 : state <= JMP0;
BRK0 : state <= BRK1; BRK0 : state <= BRK1;
BRK1 : state <= BRK2; BRK1 : state <= BRK2;
BRK2 : state <= BRK3; BRK2 : state <= BRK3;
BRK3 : state <= JMP0; BRK3 : state <= BRK4;
BRK4 : state <= BRK5;
BRK5 : state <= JMP0;
WAI : state <= ( (~I & IRQ) | NMI_edge ) ? DECODE : WAI; WAI : state <= ( (~I & IRQ) | NMI_edge ) ? DECODE : WAI;
@@ -1085,14 +1313,16 @@ always @(posedge clk or posedge reset)
else if( RDY ) case( state ) else if( RDY ) case( state )
BRA0 : SYNC <= !cond_true; BRA0 : SYNC <= !cond_true;
BRA1 : SYNC <= !(CO ^ backwards); BRA1 : SYNC <= !(CO ^ backwards);
BRA2, BRA2 : SYNC <= !(CO ^ backwards);
BRA3 : SYNC <= !(CO ^ backwards);
BRA4 : SYNC <= !(CO ^ backwards);
FETCH, FETCH,
REG, REG,
PUSH1, PUSH1,
PULL2, PULL2,
RTI4, RTI6,
JMP1, JMP3,
BRA2 : SYNC <= 1'b1; BRA5 : SYNC <= 1'b1;
default: SYNC <= 1'b0; default: SYNC <= 1'b0;
endcase endcase
@@ -1415,7 +1645,7 @@ always @(posedge clk)
NMI_1 <= NMI; NMI_1 <= NMI;
always @(posedge clk ) always @(posedge clk )
if( NMI_edge && state == BRK3 ) if( NMI_edge && state == BRK5 )
NMI_edge <= 0; NMI_edge <= 0;
else if( NMI & ~NMI_1 ) else if( NMI & ~NMI_1 )
NMI_edge <= 1; NMI_edge <= 1;

View File

@@ -13,20 +13,27 @@ addrmap verilog6502_io_regs {
sw = rw; sw = rw;
} reset[0:0] = 0x1; } reset[0:0] = 0x1;
} core_ctrl @ 0x0;
reg {
name = "AXI Base Address";
desc = "";
field { field {
name = "val"; name = "rdy";
desc = ""; desc = "";
hw = r; hw = r;
sw = rw; sw = rw;
} val[31:0] = 0x0; } rdy[1:1] = 0x0;
} axi_base_address @ 0x10; } core_ctrl @ 0x0;
reg {
name = "Core Status";
desc = "";
field {
name = "rdy_o";
desc = "";
hw = r;
sw = r;
} rdy_o[0:0] = 0x0;
} core_status @ 0x4;
reg { reg {
name = "nmi"; name = "nmi";
@@ -36,11 +43,11 @@ addrmap verilog6502_io_regs {
desc = ""; desc = "";
hw = r; hw = r;
sw = rw; sw = rw;
} nmi[31:16] = 0x200; } nmi[31:0] = 0x200;
} nmi @ 0xff8; } nmi @ 0xff4;
reg { reg {
name = "reset_brq"; name = "reset";
desc = ""; desc = "";
field { field {
@@ -48,13 +55,17 @@ addrmap verilog6502_io_regs {
desc = ""; desc = "";
hw = r; hw = r;
sw = rw; sw = rw;
} reset[15:0] = 0x200; } reset[31:0] = 0x200;
} rst @ 0xff8;
reg {
name = "brk";
field { field {
name = "brq"; name = "brq";
desc = ""; desc = "";
hw = r; hw = r;
sw = rw; sw = rw;
} brk[31:16] = 0x200; } brk[31:0] = 0x200;
} reset_brq @ 0xffc; } brk @ 0xffc;
}; };

View File

@@ -87,9 +87,10 @@ module verilog6502_io_regs (
//-------------------------------------------------------------------------- //--------------------------------------------------------------------------
typedef struct { typedef struct {
logic core_ctrl; logic core_ctrl;
logic axi_base_address; logic core_status;
logic nmi; logic nmi;
logic reset_brq; logic rst;
logic brk;
} decoded_reg_strb_t; } decoded_reg_strb_t;
decoded_reg_strb_t decoded_reg_strb; decoded_reg_strb_t decoded_reg_strb;
logic decoded_err; logic decoded_err;
@@ -105,9 +106,10 @@ module verilog6502_io_regs (
is_valid_addr = '1; // No valid address check is_valid_addr = '1; // No valid address check
is_valid_rw = '1; // No valid RW check is_valid_rw = '1; // No valid RW check
decoded_reg_strb.core_ctrl = cpuif_req_masked & (cpuif_addr == 12'h0); decoded_reg_strb.core_ctrl = cpuif_req_masked & (cpuif_addr == 12'h0);
decoded_reg_strb.axi_base_address = cpuif_req_masked & (cpuif_addr == 12'h10); decoded_reg_strb.core_status = cpuif_req_masked & (cpuif_addr == 12'h4) & !cpuif_req_is_wr;
decoded_reg_strb.nmi = cpuif_req_masked & (cpuif_addr == 12'hff8); decoded_reg_strb.nmi = cpuif_req_masked & (cpuif_addr == 12'hff4);
decoded_reg_strb.reset_brq = cpuif_req_masked & (cpuif_addr == 12'hffc); decoded_reg_strb.rst = cpuif_req_masked & (cpuif_addr == 12'hff8);
decoded_reg_strb.brk = cpuif_req_masked & (cpuif_addr == 12'hffc);
decoded_err = '0; decoded_err = '0;
end end
@@ -127,29 +129,29 @@ module verilog6502_io_regs (
logic next; logic next;
logic load_next; logic load_next;
} reset; } reset;
struct {
logic next;
logic load_next;
} rdy;
} core_ctrl; } core_ctrl;
struct { struct {
struct { struct {
logic [31:0] next; logic [31:0] next;
logic load_next; logic load_next;
} val;
} axi_base_address;
struct {
struct {
logic [15:0] next;
logic load_next;
} nmi; } nmi;
} nmi; } nmi;
struct { struct {
struct { struct {
logic [15:0] next; logic [31:0] next;
logic load_next; logic load_next;
} reset; } reset;
} rst;
struct {
struct { struct {
logic [15:0] next; logic [31:0] next;
logic load_next; logic load_next;
} brk; } brk;
} reset_brq; } brk;
} field_combo_t; } field_combo_t;
field_combo_t field_combo; field_combo_t field_combo;
@@ -158,25 +160,25 @@ module verilog6502_io_regs (
struct { struct {
logic value; logic value;
} reset; } reset;
struct {
logic value;
} rdy;
} core_ctrl; } core_ctrl;
struct { struct {
struct { struct {
logic [31:0] value; logic [31:0] value;
} val;
} axi_base_address;
struct {
struct {
logic [15:0] value;
} nmi; } nmi;
} nmi; } nmi;
struct { struct {
struct { struct {
logic [15:0] value; logic [31:0] value;
} reset; } reset;
} rst;
struct {
struct { struct {
logic [15:0] value; logic [31:0] value;
} brk; } brk;
} reset_brq; } brk;
} field_storage_t; } field_storage_t;
field_storage_t field_storage; field_storage_t field_storage;
@@ -203,37 +205,38 @@ module verilog6502_io_regs (
end end
end end
assign hwif_out.core_ctrl.reset.value = field_storage.core_ctrl.reset.value; assign hwif_out.core_ctrl.reset.value = field_storage.core_ctrl.reset.value;
// Field: verilog6502_io_regs.axi_base_address.val // Field: verilog6502_io_regs.core_ctrl.rdy
always_comb begin always_comb begin
automatic logic [31:0] next_c; automatic logic [0:0] next_c;
automatic logic load_next_c; automatic logic load_next_c;
next_c = field_storage.axi_base_address.val.value; next_c = field_storage.core_ctrl.rdy.value;
load_next_c = '0; load_next_c = '0;
if(decoded_reg_strb.axi_base_address && decoded_req_is_wr) begin // SW write if(decoded_reg_strb.core_ctrl && decoded_req_is_wr) begin // SW write
next_c = (field_storage.axi_base_address.val.value & ~decoded_wr_biten[31:0]) | (decoded_wr_data[31:0] & decoded_wr_biten[31:0]); next_c = (field_storage.core_ctrl.rdy.value & ~decoded_wr_biten[1:1]) | (decoded_wr_data[1:1] & decoded_wr_biten[1:1]);
load_next_c = '1; load_next_c = '1;
end end
field_combo.axi_base_address.val.next = next_c; field_combo.core_ctrl.rdy.next = next_c;
field_combo.axi_base_address.val.load_next = load_next_c; field_combo.core_ctrl.rdy.load_next = load_next_c;
end end
always_ff @(posedge clk) begin always_ff @(posedge clk) begin
if(rst) begin if(rst) begin
field_storage.axi_base_address.val.value <= 32'h0; field_storage.core_ctrl.rdy.value <= 1'h0;
end else begin end else begin
if(field_combo.axi_base_address.val.load_next) begin if(field_combo.core_ctrl.rdy.load_next) begin
field_storage.axi_base_address.val.value <= field_combo.axi_base_address.val.next; field_storage.core_ctrl.rdy.value <= field_combo.core_ctrl.rdy.next;
end end
end end
end end
assign hwif_out.axi_base_address.val.value = field_storage.axi_base_address.val.value; assign hwif_out.core_ctrl.rdy.value = field_storage.core_ctrl.rdy.value;
assign hwif_out.core_status.rdy_o.value = 1'h0;
// Field: verilog6502_io_regs.nmi.nmi // Field: verilog6502_io_regs.nmi.nmi
always_comb begin always_comb begin
automatic logic [15:0] next_c; automatic logic [31:0] next_c;
automatic logic load_next_c; automatic logic load_next_c;
next_c = field_storage.nmi.nmi.value; next_c = field_storage.nmi.nmi.value;
load_next_c = '0; load_next_c = '0;
if(decoded_reg_strb.nmi && decoded_req_is_wr) begin // SW write if(decoded_reg_strb.nmi && decoded_req_is_wr) begin // SW write
next_c = (field_storage.nmi.nmi.value & ~decoded_wr_biten[31:16]) | (decoded_wr_data[31:16] & decoded_wr_biten[31:16]); next_c = (field_storage.nmi.nmi.value & ~decoded_wr_biten[31:0]) | (decoded_wr_data[31:0] & decoded_wr_biten[31:0]);
load_next_c = '1; load_next_c = '1;
end end
field_combo.nmi.nmi.next = next_c; field_combo.nmi.nmi.next = next_c;
@@ -241,7 +244,7 @@ module verilog6502_io_regs (
end end
always_ff @(posedge clk) begin always_ff @(posedge clk) begin
if(rst) begin if(rst) begin
field_storage.nmi.nmi.value <= 16'h200; field_storage.nmi.nmi.value <= 32'h200;
end else begin end else begin
if(field_combo.nmi.nmi.load_next) begin if(field_combo.nmi.nmi.load_next) begin
field_storage.nmi.nmi.value <= field_combo.nmi.nmi.next; field_storage.nmi.nmi.value <= field_combo.nmi.nmi.next;
@@ -249,52 +252,52 @@ module verilog6502_io_regs (
end end
end end
assign hwif_out.nmi.nmi.value = field_storage.nmi.nmi.value; assign hwif_out.nmi.nmi.value = field_storage.nmi.nmi.value;
// Field: verilog6502_io_regs.reset_brq.reset // Field: verilog6502_io_regs.rst.reset
always_comb begin always_comb begin
automatic logic [15:0] next_c; automatic logic [31:0] next_c;
automatic logic load_next_c; automatic logic load_next_c;
next_c = field_storage.reset_brq.reset.value; next_c = field_storage.rst.reset.value;
load_next_c = '0; load_next_c = '0;
if(decoded_reg_strb.reset_brq && decoded_req_is_wr) begin // SW write if(decoded_reg_strb.rst && decoded_req_is_wr) begin // SW write
next_c = (field_storage.reset_brq.reset.value & ~decoded_wr_biten[15:0]) | (decoded_wr_data[15:0] & decoded_wr_biten[15:0]); next_c = (field_storage.rst.reset.value & ~decoded_wr_biten[31:0]) | (decoded_wr_data[31:0] & decoded_wr_biten[31:0]);
load_next_c = '1; load_next_c = '1;
end end
field_combo.reset_brq.reset.next = next_c; field_combo.rst.reset.next = next_c;
field_combo.reset_brq.reset.load_next = load_next_c; field_combo.rst.reset.load_next = load_next_c;
end end
always_ff @(posedge clk) begin always_ff @(posedge clk) begin
if(rst) begin if(rst) begin
field_storage.reset_brq.reset.value <= 16'h200; field_storage.rst.reset.value <= 32'h200;
end else begin end else begin
if(field_combo.reset_brq.reset.load_next) begin if(field_combo.rst.reset.load_next) begin
field_storage.reset_brq.reset.value <= field_combo.reset_brq.reset.next; field_storage.rst.reset.value <= field_combo.rst.reset.next;
end end
end end
end end
assign hwif_out.reset_brq.reset.value = field_storage.reset_brq.reset.value; assign hwif_out.rst.reset.value = field_storage.rst.reset.value;
// Field: verilog6502_io_regs.reset_brq.brk // Field: verilog6502_io_regs.brk.brk
always_comb begin always_comb begin
automatic logic [15:0] next_c; automatic logic [31:0] next_c;
automatic logic load_next_c; automatic logic load_next_c;
next_c = field_storage.reset_brq.brk.value; next_c = field_storage.brk.brk.value;
load_next_c = '0; load_next_c = '0;
if(decoded_reg_strb.reset_brq && decoded_req_is_wr) begin // SW write if(decoded_reg_strb.brk && decoded_req_is_wr) begin // SW write
next_c = (field_storage.reset_brq.brk.value & ~decoded_wr_biten[31:16]) | (decoded_wr_data[31:16] & decoded_wr_biten[31:16]); next_c = (field_storage.brk.brk.value & ~decoded_wr_biten[31:0]) | (decoded_wr_data[31:0] & decoded_wr_biten[31:0]);
load_next_c = '1; load_next_c = '1;
end end
field_combo.reset_brq.brk.next = next_c; field_combo.brk.brk.next = next_c;
field_combo.reset_brq.brk.load_next = load_next_c; field_combo.brk.brk.load_next = load_next_c;
end end
always_ff @(posedge clk) begin always_ff @(posedge clk) begin
if(rst) begin if(rst) begin
field_storage.reset_brq.brk.value <= 16'h200; field_storage.brk.brk.value <= 32'h200;
end else begin end else begin
if(field_combo.reset_brq.brk.load_next) begin if(field_combo.brk.brk.load_next) begin
field_storage.reset_brq.brk.value <= field_combo.reset_brq.brk.next; field_storage.brk.brk.value <= field_combo.brk.brk.next;
end end
end end
end end
assign hwif_out.reset_brq.brk.value = field_storage.reset_brq.brk.value; assign hwif_out.brk.brk.value = field_storage.brk.brk.value;
//-------------------------------------------------------------------------- //--------------------------------------------------------------------------
// Write response // Write response
@@ -318,16 +321,19 @@ module verilog6502_io_regs (
readback_data_var = '0; readback_data_var = '0;
if(rd_mux_addr == 12'h0) begin if(rd_mux_addr == 12'h0) begin
readback_data_var[0] = field_storage.core_ctrl.reset.value; readback_data_var[0] = field_storage.core_ctrl.reset.value;
readback_data_var[1] = field_storage.core_ctrl.rdy.value;
end end
if(rd_mux_addr == 12'h10) begin if(rd_mux_addr == 12'h4) begin
readback_data_var[31:0] = field_storage.axi_base_address.val.value; readback_data_var[0] = 1'h0;
end
if(rd_mux_addr == 12'hff4) begin
readback_data_var[31:0] = field_storage.nmi.nmi.value;
end end
if(rd_mux_addr == 12'hff8) begin if(rd_mux_addr == 12'hff8) begin
readback_data_var[31:16] = field_storage.nmi.nmi.value; readback_data_var[31:0] = field_storage.rst.reset.value;
end end
if(rd_mux_addr == 12'hffc) begin if(rd_mux_addr == 12'hffc) begin
readback_data_var[15:0] = field_storage.reset_brq.reset.value; readback_data_var[31:0] = field_storage.brk.brk.value;
readback_data_var[31:16] = field_storage.reset_brq.brk.value;
end end
readback_data = readback_data_var; readback_data = readback_data_var;
readback_done = decoded_req & ~decoded_req_is_wr; readback_done = decoded_req & ~decoded_req_is_wr;

View File

@@ -11,20 +11,25 @@ package verilog6502_io_regs_pkg;
logic value; logic value;
} verilog6502_io_regs__core_ctrl__reset__out_t; } verilog6502_io_regs__core_ctrl__reset__out_t;
typedef struct {
logic value;
} verilog6502_io_regs__core_ctrl__rdy__out_t;
typedef struct { typedef struct {
verilog6502_io_regs__core_ctrl__reset__out_t reset; verilog6502_io_regs__core_ctrl__reset__out_t reset;
verilog6502_io_regs__core_ctrl__rdy__out_t rdy;
} verilog6502_io_regs__core_ctrl__out_t; } verilog6502_io_regs__core_ctrl__out_t;
typedef struct {
logic value;
} verilog6502_io_regs__core_status__rdy_o__out_t;
typedef struct {
verilog6502_io_regs__core_status__rdy_o__out_t rdy_o;
} verilog6502_io_regs__core_status__out_t;
typedef struct { typedef struct {
logic [31:0] value; logic [31:0] value;
} verilog6502_io_regs__axi_base_address__val__out_t;
typedef struct {
verilog6502_io_regs__axi_base_address__val__out_t val;
} verilog6502_io_regs__axi_base_address__out_t;
typedef struct {
logic [15:0] value;
} verilog6502_io_regs__nmi__nmi__out_t; } verilog6502_io_regs__nmi__nmi__out_t;
typedef struct { typedef struct {
@@ -32,22 +37,26 @@ package verilog6502_io_regs_pkg;
} verilog6502_io_regs__nmi__out_t; } verilog6502_io_regs__nmi__out_t;
typedef struct { typedef struct {
logic [15:0] value; logic [31:0] value;
} verilog6502_io_regs__reset_brq__reset__out_t; } verilog6502_io_regs__rst__reset__out_t;
typedef struct { typedef struct {
logic [15:0] value; verilog6502_io_regs__rst__reset__out_t reset;
} verilog6502_io_regs__reset_brq__brk__out_t; } verilog6502_io_regs__rst__out_t;
typedef struct { typedef struct {
verilog6502_io_regs__reset_brq__reset__out_t reset; logic [31:0] value;
verilog6502_io_regs__reset_brq__brk__out_t brk; } verilog6502_io_regs__brk__brk__out_t;
} verilog6502_io_regs__reset_brq__out_t;
typedef struct {
verilog6502_io_regs__brk__brk__out_t brk;
} verilog6502_io_regs__brk__out_t;
typedef struct { typedef struct {
verilog6502_io_regs__core_ctrl__out_t core_ctrl; verilog6502_io_regs__core_ctrl__out_t core_ctrl;
verilog6502_io_regs__axi_base_address__out_t axi_base_address; verilog6502_io_regs__core_status__out_t core_status;
verilog6502_io_regs__nmi__out_t nmi; verilog6502_io_regs__nmi__out_t nmi;
verilog6502_io_regs__reset_brq__out_t reset_brq; verilog6502_io_regs__rst__out_t rst;
verilog6502_io_regs__brk__out_t brk;
} verilog6502_io_regs__out_t; } verilog6502_io_regs__out_t;
endpackage endpackage

View File

@@ -2,7 +2,7 @@ module verilog6502_addr_decoder(
input i_clk, input i_clk,
input i_rst, input i_rst,
input logic [15:0] i_cpu_addr, input logic [31:0] i_cpu_addr,
input logic [7:0] i_cpu_data, input logic [7:0] i_cpu_data,
output logic [7:0] o_cpu_data, output logic [7:0] o_cpu_data,
input logic i_cpu_we, input logic i_cpu_we,
@@ -17,14 +17,14 @@ module verilog6502_addr_decoder(
output logic o_mem_we, output logic o_mem_we,
input logic i_mem_rdy, input logic i_mem_rdy,
output logic [15:0] o_external_addr, output logic [31:0] o_external_addr,
output logic [7:0] o_external_data, output logic [7:0] o_external_data,
input logic [7:0] i_external_data, input logic [7:0] i_external_data,
output logic o_external_rd, output logic o_external_rd,
output logic o_external_we, output logic o_external_we,
input logic i_external_rdy, input logic i_external_rdy,
output logic [15:0] o_io_addr, output logic [11:0] o_io_addr,
output logic [7:0] o_io_data, output logic [7:0] o_io_data,
input logic [7:0] i_io_data, input logic [7:0] i_io_data,
output logic o_io_rd, output logic o_io_rd,
@@ -88,20 +88,20 @@ always_comb begin
endcase endcase
if (o_cpu_rdy) begin if (o_cpu_rdy) begin
if (i_cpu_addr < 16'hE000) begin if (i_cpu_addr < 32'hFFFF) begin
o_mem_addr = i_cpu_addr; o_mem_addr = i_cpu_addr[15:0];
o_mem_data = i_cpu_data; o_mem_data = i_cpu_data;
o_mem_we = i_cpu_we & o_cpu_rdy; o_mem_we = i_cpu_we & o_cpu_rdy;
o_mem_rd = ~i_cpu_we & o_cpu_rdy; o_mem_rd = ~i_cpu_we & o_cpu_rdy;
prev_addr_next = MEM; prev_addr_next = MEM;
end else if (i_cpu_addr < 16'hF000) begin end else if (i_cpu_addr < 32'hFFFFEFFF) begin
o_external_addr = {4'b0, i_cpu_addr[11:0]}; o_external_addr = i_cpu_addr;
o_external_data = i_cpu_data; o_external_data = i_cpu_data;
o_external_we = i_cpu_we & o_cpu_rdy; o_external_we = i_cpu_we & o_cpu_rdy;
o_external_rd = ~i_cpu_we & o_cpu_rdy; o_external_rd = ~i_cpu_we & o_cpu_rdy;
prev_addr_next = EXT; prev_addr_next = EXT;
end else begin end else begin
o_io_addr = {4'b0, i_cpu_addr[11:0]}; o_io_addr = i_cpu_addr[11:0];
o_io_data = i_cpu_data; o_io_data = i_cpu_data;
o_io_we = i_cpu_we & o_cpu_rdy; o_io_we = i_cpu_we & o_cpu_rdy;
o_io_rd = ~i_cpu_we & o_cpu_rdy; o_io_rd = ~i_cpu_we & o_cpu_rdy;

View File

@@ -1,8 +1,10 @@
module verilog6502_apb_adapter( module verilog6502_apb_adapter #(
parameter ADDR_WIDTH = 32
)(
input i_clk, input i_clk,
input i_rst, input i_rst,
input logic [15:0] i_addr, input logic [ADDR_WIDTH-1:0] i_addr,
input logic [7:0] i_data, input logic [7:0] i_data,
output logic [7:0] o_data, output logic [7:0] o_data,
input logic i_rd, input logic i_rd,
@@ -12,10 +14,12 @@ module verilog6502_apb_adapter(
taxi_apb_if.mst m_apb taxi_apb_if.mst m_apb
); );
localparam APB_ADDR_WIDTH = m_apb.ADDR_W;
enum logic {IDLE, ENABLE} state, state_next; enum logic {IDLE, ENABLE} state, state_next;
logic [15:0] latched_addr, latched_addr_next; logic [ADDR_WIDTH-1:0] latched_addr, latched_addr_next;
logic [15:0] second_addr, second_addr_next; logic [ADDR_WIDTH-1:0] second_addr, second_addr_next;
logic second_we, second_rd, second_we_next, second_rd_next; logic second_we, second_rd, second_we_next, second_rd_next;
logic [7:0] latched_data, latched_data_next; logic [7:0] latched_data, latched_data_next;
logic [7:0] second_data, second_data_next; logic [7:0] second_data, second_data_next;
@@ -51,7 +55,7 @@ always_comb begin
IDLE: begin IDLE: begin
if (i_rd | i_we) begin if (i_rd | i_we) begin
m_apb.pprot = '0; m_apb.pprot = '0;
m_apb.paddr = {16'b0, i_addr} & 32'hfffc; // 32 bit address m_apb.paddr = APB_ADDR_WIDTH'({i_addr[ADDR_WIDTH-1:2], 2'b0});
m_apb.psel = '1; m_apb.psel = '1;
m_apb.pwrite = i_we; m_apb.pwrite = i_we;
m_apb.pstrb = 4'h1 << i_addr[1:0]; // shift based on lower 2 bits m_apb.pstrb = 4'h1 << i_addr[1:0]; // shift based on lower 2 bits
@@ -65,7 +69,7 @@ always_comb begin
latched_pwrite_next = i_we; latched_pwrite_next = i_we;
end else if (second_rd | second_we) begin end else if (second_rd | second_we) begin
m_apb.pprot = '0; m_apb.pprot = '0;
m_apb.paddr = {16'b0, second_addr} & 32'hfffc; // 32 bit address m_apb.paddr = APB_ADDR_WIDTH'({second_addr[ADDR_WIDTH-1:2], 2'b0});
m_apb.psel = '1; m_apb.psel = '1;
m_apb.pwrite = second_we; m_apb.pwrite = second_we;
m_apb.pstrb = 4'h1 << second_addr[1:0]; // shift based on lower 2 bits m_apb.pstrb = 4'h1 << second_addr[1:0]; // shift based on lower 2 bits
@@ -97,7 +101,7 @@ always_comb begin
second_data_next = i_data; second_data_next = i_data;
m_apb.pprot = '0; m_apb.pprot = '0;
m_apb.paddr = {16'b0, latched_addr} & 32'hfffc; // 32 bit address m_apb.paddr = APB_ADDR_WIDTH'({latched_addr[ADDR_WIDTH-1:2], 2'b0});
m_apb.psel = '1; m_apb.psel = '1;
m_apb.pwrite = latched_pwrite; m_apb.pwrite = latched_pwrite;
m_apb.pstrb = 4'h1 << latched_addr[1:0]; // shift based on lower 2 bits m_apb.pstrb = 4'h1 << latched_addr[1:0]; // shift based on lower 2 bits

View File

@@ -2,15 +2,13 @@ module verilog6502_external_memory (
input i_clk, input i_clk,
input i_rst, input i_rst,
input logic [15:0] i_addr, input logic [31:0] i_addr,
input logic [7:0] i_data, input logic [7:0] i_data,
output logic [7:0] o_data, output logic [7:0] o_data,
input logic i_rd, input logic i_rd,
input logic i_we, input logic i_we,
output logic o_rdy, output logic o_rdy,
input logic [31:0] i_axi_base_addr,
taxi_axil_if.wr_mst m_axil_wr, taxi_axil_if.wr_mst m_axil_wr,
taxi_axil_if.rd_mst m_axil_rd taxi_axil_if.rd_mst m_axil_rd
@@ -33,7 +31,7 @@ verilog6502_apb_adapter u_internal_apb_adapter (
.m_apb (internal_apb) .m_apb (internal_apb)
); );
assign addr_shift_apb.paddr = {i_axi_base_addr[31:12], {internal_apb.paddr[11:0]}}; assign addr_shift_apb.paddr = internal_apb.paddr;
assign addr_shift_apb.pprot = internal_apb.pprot; assign addr_shift_apb.pprot = internal_apb.pprot;
assign addr_shift_apb.psel = internal_apb.psel; assign addr_shift_apb.psel = internal_apb.psel;
assign addr_shift_apb.penable = internal_apb.penable; assign addr_shift_apb.penable = internal_apb.penable;

View File

@@ -73,7 +73,7 @@ taxi_axi_ram_if_rdwr #(
); );
logic [7:0] mem [4][14*1024]; logic [7:0] mem [4][16*1024];
enum logic {CPU, EXT} sel, sel_next; enum logic {CPU, EXT} sel, sel_next;

View File

@@ -1,11 +1,11 @@
// Wrapper around verilog-6502 // Wrapper around verilog-6502
// memory map: // memory map:
// 0x0000-0x00FF Zero Page (Hard coded) // 0x00000000-0x000000FF Zero Page (Hard coded)
// 0x0100-0x01FF Stack (Hard coded) // 0x00000100-0x000001FF Stack (Hard coded)
// 0x0200-0xCFFF Internal Memory // 0x00000200-0x0000FFFF Internal Memory
// 0xE000-0xEFFF External AXI // 0x00010000-0xFFFFEFFF External AXI
// 0xF000-0xFFFF Processor IO // 0xFFFFF000-0xFFFFFFFF Processor IO
module verilog6502_wrapper( module verilog6502_wrapper(
input clk, input clk,
@@ -59,7 +59,7 @@ taxi_apb_interconnect #(
logic cpu_clk; logic cpu_clk;
logic cpu_reset; logic cpu_reset;
logic [15:0] cpu_addr; logic [31:0] cpu_addr;
logic [7:0] cpu_data_in; logic [7:0] cpu_data_in;
logic [7:0] cpu_data_out; logic [7:0] cpu_data_out;
@@ -83,14 +83,14 @@ logic mem_rd;
logic mem_we; logic mem_we;
logic mem_rdy; logic mem_rdy;
logic [15:0] ext_addr; logic [31:0] ext_addr;
logic [7:0] ext_data_in; logic [7:0] ext_data_in;
logic [7:0] ext_data_out; logic [7:0] ext_data_out;
logic ext_rd; logic ext_rd;
logic ext_we; logic ext_we;
logic ext_rdy; logic ext_rdy;
logic [15:0] io_addr; logic [11:0] io_addr;
logic [7:0] io_data_in; logic [7:0] io_data_in;
logic [7:0] io_data_out; logic [7:0] io_data_out;
logic io_rd; logic io_rd;
@@ -173,13 +173,13 @@ verilog6502_external_memory u_external_memory (
.i_we (ext_we), .i_we (ext_we),
.o_rdy (ext_rdy), .o_rdy (ext_rdy),
.i_axi_base_addr (hwif_out.axi_base_address.val.value),
.m_axil_rd (m_axil_rd), .m_axil_rd (m_axil_rd),
.m_axil_wr (m_axil_wr) .m_axil_wr (m_axil_wr)
); );
verilog6502_apb_adapter u_io_apb_adapter( verilog6502_apb_adapter #(
.ADDR_WIDTH(12)
) u_io_apb_adapter(
.i_clk (cpu_clk), .i_clk (cpu_clk),
.i_rst (rst), .i_rst (rst),