32bit #2
5
.gitignore
vendored
5
.gitignore
vendored
@@ -1,2 +1,5 @@
|
||||
sim_build
|
||||
__pycache__
|
||||
__pycache__
|
||||
|
||||
*.o
|
||||
*.lst
|
||||
@@ -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
29
sim/asm_source/Makefile
Normal file
@@ -0,0 +1,29 @@
|
||||
|
||||
|
||||
# work in progress
|
||||
.SUFFIXES:
|
||||
|
||||
|
||||
PROGRAMS=jsr_test lda_test
|
||||
|
||||
SRCS=$(wildcard *.s)
|
||||
OBJS=$(SRCS:.s=.o)
|
||||
|
||||
CA65=$(CC65_BIN)/ca65
|
||||
LD65=$(CC65_BIN)/ld65
|
||||
|
||||
CA_ARGS=--cpu 65c032
|
||||
|
||||
all: $(PROGRAMS)
|
||||
|
||||
$(PROGRAMS): $(PROGRAM=$(.TARGET))
|
||||
|
||||
%.o: %.s
|
||||
$(CA65) $(CA_ARGS) $^ -o $@ -l $@.lst
|
||||
|
||||
$(PROGRAMS): $(OBJS)
|
||||
$(LD65) -o $@ -C memory.cfg vectors.o $@.o
|
||||
|
||||
clean:
|
||||
rm -rf $(PROGRAMS) $(OBJS)
|
||||
rm -rf *.o *.lst
|
||||
32
sim/asm_source/jsr_test.s
Normal file
32
sim/asm_source/jsr_test.s
Normal 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
121
sim/asm_source/lda_test.s
Normal 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
13
sim/asm_source/memory.cfg
Normal file
@@ -0,0 +1,13 @@
|
||||
MEMORY {
|
||||
ZP: start = $0, size = $100;
|
||||
RAM: start = $fffff000, size = $1000, file=%O;
|
||||
}
|
||||
|
||||
SEGMENTS {
|
||||
ZEROPAGE: load = ZP, type = zp;
|
||||
CODE: load = RAM, type = ro;
|
||||
RODATA: load = RAM, type = ro;
|
||||
DATA: load = RAM, type = rw;
|
||||
BSS: load = RAM, type = bss, define = yes;
|
||||
VECTORS: load = RAM, type = ro, start = $FFFFFFF4;
|
||||
}
|
||||
7
sim/asm_source/vectors.s
Normal file
7
sim/asm_source/vectors.s
Normal file
@@ -0,0 +1,7 @@
|
||||
.import vec_reset, vec_irq, vec_nmi
|
||||
|
||||
.segment "VECTORS": dword
|
||||
|
||||
.addr vec_nmi
|
||||
.addr vec_reset
|
||||
.addr vec_irq
|
||||
9
sim/verilog6502_32bit.yaml
Normal file
9
sim/verilog6502_32bit.yaml
Normal file
@@ -0,0 +1,9 @@
|
||||
tests:
|
||||
- name: "cpu_65c02"
|
||||
toplevel: "cpu_65c02"
|
||||
modules:
|
||||
- "verilog6502_32bit_test"
|
||||
sources: "sources.list"
|
||||
waves: True
|
||||
defines:
|
||||
SIM: "hi"
|
||||
9
sim/verilog6502_32bit_asm.yaml
Normal file
9
sim/verilog6502_32bit_asm.yaml
Normal file
@@ -0,0 +1,9 @@
|
||||
tests:
|
||||
- name: "cpu_65c02"
|
||||
toplevel: "cpu_65c02"
|
||||
modules:
|
||||
- "verilog6502_32bit_asm_test"
|
||||
sources: "sources.list"
|
||||
waves: True
|
||||
defines:
|
||||
SIM: "hi"
|
||||
71
sim/verilog6502_32bit_asm_test.py
Normal file
71
sim/verilog6502_32bit_asm_test.py
Normal 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")
|
||||
806
sim/verilog6502_32bit_test.py
Normal file
806
sim/verilog6502_32bit_test.py
Normal 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)
|
||||
@@ -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))
|
||||
|
||||
|
||||
542
src/cpu_65c02.v
542
src/cpu_65c02.v
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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),
|
||||
|
||||
|
||||
Reference in New Issue
Block a user