32bit #2

Merged
bslathi19 merged 17 commits from 32bit into master 2026-05-09 15:34:01 -07:00
21 changed files with 1645 additions and 284 deletions

5
.gitignore vendored
View File

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

View File

@@ -7,4 +7,6 @@ pip install -r requirements.txt
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 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))

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

View File

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

View File

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

View File

@@ -11,20 +11,25 @@ package verilog6502_io_regs_pkg;
logic value;
} verilog6502_io_regs__core_ctrl__reset__out_t;
typedef struct {
logic value;
} verilog6502_io_regs__core_ctrl__rdy__out_t;
typedef struct {
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;
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 {
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;
typedef struct {
@@ -32,22 +37,26 @@ package verilog6502_io_regs_pkg;
} verilog6502_io_regs__nmi__out_t;
typedef struct {
logic [15:0] value;
} verilog6502_io_regs__reset_brq__reset__out_t;
logic [31:0] value;
} verilog6502_io_regs__rst__reset__out_t;
typedef struct {
logic [15:0] value;
} verilog6502_io_regs__reset_brq__brk__out_t;
verilog6502_io_regs__rst__reset__out_t reset;
} verilog6502_io_regs__rst__out_t;
typedef struct {
verilog6502_io_regs__reset_brq__reset__out_t reset;
verilog6502_io_regs__reset_brq__brk__out_t brk;
} verilog6502_io_regs__reset_brq__out_t;
logic [31:0] value;
} verilog6502_io_regs__brk__brk__out_t;
typedef struct {
verilog6502_io_regs__brk__brk__out_t brk;
} verilog6502_io_regs__brk__out_t;
typedef struct {
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__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;
endpackage

View File

@@ -2,7 +2,7 @@ module verilog6502_addr_decoder(
input i_clk,
input i_rst,
input logic [15:0] i_cpu_addr,
input logic [31:0] i_cpu_addr,
input logic [7:0] i_cpu_data,
output logic [7:0] o_cpu_data,
input logic i_cpu_we,
@@ -17,14 +17,14 @@ module verilog6502_addr_decoder(
output logic o_mem_we,
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,
input logic [7:0] i_external_data,
output logic o_external_rd,
output logic o_external_we,
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,
input logic [7:0] i_io_data,
output logic o_io_rd,
@@ -88,20 +88,20 @@ always_comb begin
endcase
if (o_cpu_rdy) begin
if (i_cpu_addr < 16'hE000) begin
o_mem_addr = i_cpu_addr;
if (i_cpu_addr < 32'hFFFF) begin
o_mem_addr = i_cpu_addr[15:0];
o_mem_data = i_cpu_data;
o_mem_we = i_cpu_we & o_cpu_rdy;
o_mem_rd = ~i_cpu_we & o_cpu_rdy;
prev_addr_next = MEM;
end else if (i_cpu_addr < 16'hF000) begin
o_external_addr = {4'b0, i_cpu_addr[11:0]};
end else if (i_cpu_addr < 32'hFFFFEFFF) begin
o_external_addr = i_cpu_addr;
o_external_data = i_cpu_data;
o_external_we = i_cpu_we & o_cpu_rdy;
o_external_rd = ~i_cpu_we & o_cpu_rdy;
prev_addr_next = EXT;
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_we = 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_rst,
input logic [15:0] i_addr,
input logic [ADDR_WIDTH-1:0] i_addr,
input logic [7:0] i_data,
output logic [7:0] o_data,
input logic i_rd,
@@ -12,10 +14,12 @@ module verilog6502_apb_adapter(
taxi_apb_if.mst m_apb
);
localparam APB_ADDR_WIDTH = m_apb.ADDR_W;
enum logic {IDLE, ENABLE} state, state_next;
logic [15:0] latched_addr, latched_addr_next;
logic [15:0] second_addr, second_addr_next;
logic [ADDR_WIDTH-1:0] latched_addr, latched_addr_next;
logic [ADDR_WIDTH-1:0] second_addr, second_addr_next;
logic second_we, second_rd, second_we_next, second_rd_next;
logic [7:0] latched_data, latched_data_next;
logic [7:0] second_data, second_data_next;
@@ -51,7 +55,7 @@ always_comb begin
IDLE: begin
if (i_rd | i_we) begin
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.pwrite = i_we;
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;
end else if (second_rd | second_we) begin
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.pwrite = second_we;
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;
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.pwrite = latched_pwrite;
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_rst,
input logic [15:0] i_addr,
input logic [31:0] i_addr,
input logic [7:0] i_data,
output logic [7:0] o_data,
input logic i_rd,
input logic i_we,
output logic o_rdy,
input logic [31:0] i_axi_base_addr,
taxi_axil_if.wr_mst m_axil_wr,
taxi_axil_if.rd_mst m_axil_rd
@@ -33,7 +31,7 @@ verilog6502_apb_adapter u_internal_apb_adapter (
.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.psel = internal_apb.psel;
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;

View File

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