Compare commits

7 Commits

Author SHA1 Message Date
b31d7490b2 Add indirect jump 2026-04-26 22:13:42 -07:00
dc339cb725 Add absolute indexed indirect 2026-04-26 21:57:08 -07:00
7164a8172f Add test for abs,y 2026-04-26 21:08:21 -07:00
cb6cac1245 add absolute,x 2026-04-26 21:03:53 -07:00
747438a9b6 Add absolute addressing 2026-04-26 20:34:11 -07:00
019b84f41d Get reset sequence to work 2026-04-26 19:28:39 -07:00
9476c6a0dd Add 32 bit BRK 2026-04-26 08:53:59 -07:00
3 changed files with 533 additions and 113 deletions

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,341 @@
import cocotb
from cocotb.handle import Immediate
from cocotb.clock import Clock
from cocotb.triggers import Timer, RisingEdge
from collections import defaultdict
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(0xfffffff4, 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
(0xfffffff4, False, int(dut.regfile.value)), # read vector byte 0
(0xfffffff5, False, int(dut.regfile.value)), # read vector byte 1
(0xfffffff6, False, int(dut.regfile.value)), # read vector byte 2
(0xfffffff7, False, int(dut.regfile.value)), # read vector byte 3
(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(0xfffffff4, 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(0xfffffff4, 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(0xfffffff4, 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(0xfffffff4, 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(0xfffffff4, 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)

View File

@@ -52,7 +52,7 @@ module cpu_65c02( clk, reset, AB, DI, DO, WE, IRQ, NMI, RDY, RDY_O, SYNC );
input clk; // CPU clock input clk; // CPU clock
input reset; // reset signal input reset; // reset signal
output reg [15:0] AB; // address bus output reg [31:0] AB; // address bus
input [7:0] DI; // data in, read bus input [7:0] DI; // data in, read bus
output [7:0] DO; // data out, write bus output [7:0] DO; // data out, write bus
output WE; // write enable output WE; // write enable
@@ -66,10 +66,11 @@ output reg SYNC; // AB is first cycle of the intruction
* internal signals * internal signals
*/ */
reg [15:0] PC; // Program Counter reg [31:0] PC; // Program Counter
reg [7:0] ABL; // Address Bus Register LSB reg [31:0] ABR; // Address Bus Register
reg [7:0] ABH; // Address Bus Register MSB
wire [7:0] ADD; // Adder Hold Register (registered in ALU) wire [7:0] ADD; // Adder Hold Register (registered in ALU)
reg [7:0] alu_sr_0; // ALU output shift register 0
reg [7:0] alu_sr_1; // ALU output shift register 1
reg [7:0] DIHOLD; // Hold for Data In reg [7:0] DIHOLD; // Hold for Data In
reg DIHOLD_valid; // reg DIHOLD_valid; //
@@ -103,8 +104,6 @@ wire [7:0] AO; // ALU output after BCD adjustment
reg WE; // Write Enable reg WE; // Write Enable
reg CI; // Carry In reg CI; // Carry In
wire CO; // Carry Out wire CO; // Carry Out
wire [7:0] PCH = PC[15:8];
wire [7:0] PCL = PC[7:0];
reg NMI_edge = 0; // captured NMI edge reg NMI_edge = 0; // captured NMI edge
@@ -135,14 +134,14 @@ wire [7:0] P = { N, V, 2'b11, D, I, Z, C };
* instruction decoder/sequencer * instruction decoder/sequencer
*/ */
reg [5:0] state; reg [6:0] state;
/* /*
* control signals * control signals
*/ */
reg PC_inc; // Increment PC reg PC_inc; // Increment PC
reg [15:0] PC_temp; // intermediate value of PC reg [31:0] PC_temp; // intermediate value of PC
reg [1:0] src_reg; // source register index reg [1:0] src_reg; // source register index
reg [1:0] dst_reg; // destination register index reg [1:0] dst_reg; // destination register index
@@ -209,61 +208,73 @@ parameter
*/ */
parameter parameter
ABS0 = 6'd0, // ABS - fetch LSB ABS0 = 7'd0, // ABS - fetch LSB
ABS1 = 6'd1, // ABS - fetch MSB ABS1 = 7'd1, // ABS - fetch MSB
ABSX0 = 6'd2, // ABS, X - fetch LSB and send to ALU (+X) ABSX0 = 7'd2, // ABS, X - fetch LSB and send to ALU (+X)
ABSX1 = 6'd3, // ABS, X - fetch MSB and send to ALU (+Carry) ABSX1 = 7'd3, // ABS, X - fetch MSB and send to ALU (+Carry)
ABSX2 = 6'd4, // ABS, X - Wait for ALU (only if needed) ABSX2 = 7'd4, // ABS, X - Wait for ALU (only if needed)
BRA0 = 6'd5, // Branch - fetch offset and send to ALU (+PC[7:0]) BRA0 = 7'd5, // Branch - fetch offset and send to ALU (+PC[7:0])
BRA1 = 6'd6, // Branch - fetch opcode, and send PC[15:8] to ALU BRA1 = 7'd6, // Branch - fetch opcode, and send PC[15:8] to ALU
BRA2 = 6'd7, // Branch - fetch opcode (if page boundary crossed) BRA2 = 7'd7, // Branch - fetch opcode (if page boundary crossed)
BRK0 = 6'd8, // BRK/IRQ - push PCH, send S to ALU (-1) BRK0 = 7'd8, // BRK/IRQ - push PCH, send S to ALU (-1)
BRK1 = 6'd9, // BRK/IRQ - push PCL, send S to ALU (-1) BRK1 = 7'd9, // BRK/IRQ - push PCL, send S to ALU (-1)
BRK2 = 6'd10, // BRK/IRQ - push P, send S to ALU (-1) BRK2 = 7'd10, // BRK/IRQ - push P, send S to ALU (-1)
BRK3 = 6'd11, // BRK/IRQ - write S, and fetch @ fffe BRK3 = 7'd11, // BRK/IRQ - write S, and fetch @ fffe
DECODE = 6'd12, // IR is valid, decode instruction, and write prev reg DECODE = 7'd12, // IR is valid, decode instruction, and write prev reg
FETCH = 6'd13, // fetch next opcode, and perform prev ALU op FETCH = 7'd13, // fetch next opcode, and perform prev ALU op
INDX0 = 6'd14, // (ZP,X) - fetch ZP address, and send to ALU (+X) INDX0 = 7'd14, // (ZP,X) - fetch ZP address, and send to ALU (+X)
INDX1 = 6'd15, // (ZP,X) - fetch LSB at ZP+X, calculate ZP+X+1 INDX1 = 7'd15, // (ZP,X) - fetch LSB at ZP+X, calculate ZP+X+1
INDX2 = 6'd16, // (ZP,X) - fetch MSB at ZP+X+1 INDX2 = 7'd16, // (ZP,X) - fetch MSB at ZP+X+1
INDX3 = 6'd17, // (ZP,X) - fetch data INDX3 = 7'd17, // (ZP,X) - fetch data
INDY0 = 6'd18, // (ZP),Y - fetch ZP address, and send ZP to ALU (+1) INDY0 = 7'd18, // (ZP),Y - fetch ZP address, and send ZP to ALU (+1)
INDY1 = 6'd19, // (ZP),Y - fetch at ZP+1, and send LSB to ALU (+Y) INDY1 = 7'd19, // (ZP),Y - fetch at ZP+1, and send LSB to ALU (+Y)
INDY2 = 6'd20, // (ZP),Y - fetch data, and send MSB to ALU (+Carry) INDY2 = 7'd20, // (ZP),Y - fetch data, and send MSB to ALU (+Carry)
INDY3 = 6'd21, // (ZP),Y) - fetch data (if page boundary crossed) INDY3 = 7'd21, // (ZP),Y) - fetch data (if page boundary crossed)
JMP0 = 6'd22, // JMP - fetch PCL and hold JMP0 = 7'd22, // JMP - fetch PCL and hold
JMP1 = 6'd23, // JMP - fetch PCH JMP1 = 7'd23, // JMP - fetch PCH
JMPI0 = 6'd24, // JMP IND - fetch LSB and send to ALU for delay (+0) JMPI0 = 7'd24, // JMP IND - fetch LSB and send to ALU for delay (+0)
JMPI1 = 6'd25, // JMP IND - fetch MSB, proceed with JMP0 state JMPI1 = 7'd25, // JMP IND - fetch MSB, proceed with JMP0 state
JSR0 = 6'd26, // JSR - push PCH, save LSB, send S to ALU (-1) JSR0 = 7'd26, // JSR - push PCH, save LSB, send S to ALU (-1)
JSR1 = 6'd27, // JSR - push PCL, send S to ALU (-1) JSR1 = 7'd27, // JSR - push PCL, send S to ALU (-1)
JSR2 = 6'd28, // JSR - write S JSR2 = 7'd28, // JSR - write S
JSR3 = 6'd29, // JSR - fetch MSB JSR3 = 7'd29, // JSR - fetch MSB
PULL0 = 6'd30, // PLP/PLA/PLX/PLY - save next op in IRHOLD, send S to ALU (+1) PULL0 = 7'd30, // PLP/PLA/PLX/PLY - save next op in IRHOLD, send S to ALU (+1)
PULL1 = 6'd31, // PLP/PLA/PLX/PLY - fetch data from stack, write S PULL1 = 7'd31, // PLP/PLA/PLX/PLY - fetch data from stack, write S
PULL2 = 6'd32, // PLP/PLA/PLX/PLY - prefetch op, but don't increment PC PULL2 = 7'd32, // PLP/PLA/PLX/PLY - prefetch op, but don't increment PC
PUSH0 = 6'd33, // PHP/PHA/PHX/PHY - send A to ALU (+0) PUSH0 = 7'd33, // PHP/PHA/PHX/PHY - send A to ALU (+0)
PUSH1 = 6'd34, // PHP/PHA/PHX/PHY - write A/P, send S to ALU (-1) PUSH1 = 7'd34, // PHP/PHA/PHX/PHY - write A/P, send S to ALU (-1)
READ = 6'd35, // Read memory for read/modify/write (INC, DEC, shift) READ = 7'd35, // Read memory for read/modify/write (INC, DEC, shift)
REG = 6'd36, // Read register for reg-reg transfers REG = 7'd36, // Read register for reg-reg transfers
RTI0 = 6'd37, // RTI - send S to ALU (+1) RTI0 = 7'd37, // RTI - send S to ALU (+1)
RTI1 = 6'd38, // RTI - read P from stack RTI1 = 7'd38, // RTI - read P from stack
RTI2 = 6'd39, // RTI - read PCL from stack RTI2 = 7'd39, // RTI - read PCL from stack
RTI3 = 6'd40, // RTI - read PCH from stack RTI3 = 7'd40, // RTI - read PCH from stack
RTI4 = 6'd41, // RTI - read PCH from stack RTI4 = 7'd41, // RTI - read PCH from stack
RTS0 = 6'd42, // RTS - send S to ALU (+1) RTS0 = 7'd42, // RTS - send S to ALU (+1)
RTS1 = 6'd43, // RTS - read PCL from stack RTS1 = 7'd43, // RTS - read PCL from stack
RTS2 = 6'd44, // RTS - write PCL to ALU, read PCH RTS2 = 7'd44, // RTS - write PCL to ALU, read PCH
RTS3 = 6'd45, // RTS - load PC and increment RTS3 = 7'd45, // RTS - load PC and increment
WRITE = 6'd46, // Write memory for read/modify/write WRITE = 7'd46, // Write memory for read/modify/write
ZP0 = 6'd47, // Z-page - fetch ZP address ZP0 = 7'd47, // Z-page - fetch ZP address
ZPX0 = 6'd48, // ZP, X - fetch ZP, and send to ALU (+X) ZPX0 = 7'd48, // ZP, X - fetch ZP, and send to ALU (+X)
ZPX1 = 6'd49, // ZP, X - load from memory ZPX1 = 7'd49, // ZP, X - load from memory
IND0 = 6'd50, // (ZP) - fetch ZP address, and send to ALU (+0) IND0 = 7'd50, // (ZP) - fetch ZP address, and send to ALU (+0)
JMPIX0 = 6'd51, // JMP (,X)- fetch LSB and send to ALU (+X) JMPIX0 = 7'd51, // JMP (,X)- fetch LSB and send to ALU (+X)
JMPIX1 = 6'd52, // JMP (,X)- fetch MSB and send to ALU (+Carry) JMPIX1 = 7'd52, // JMP (,X)- fetch MSB and send to ALU (+Carry)
JMPIX2 = 6'd53, // JMP (,X)- Wait for ALU (only if needed) JMPIX2 = 7'd53, // JMP (,X)- Wait for ALU (only if needed)
WAI = 6'd54; // WAI - Wait for interrupt, then go to decode WAI = 7'd54, // WAI - Wait for interrupt, then go to decode
BRK4 = 7'd55, // TODO
BRK5 = 7'd56, // TODO
JMP2 = 7'd57, // TODO
JMP3 = 7'd58, // TODO
ABS2 = 7'd59, // TODO
ABS3 = 7'd60, // TODO
ABSX3 = 7'd61, // TODO
ABSX4 = 7'd62, // TODO
JMPIX3 = 7'd63, // TODO
JMPIX4 = 7'd64, // TODO
JMPI2 = 7'd65, // TODO
JMPI3 = 7'd66; // TODO
`ifdef SIM `ifdef SIM
@@ -281,9 +292,13 @@ always @*
ZPX1: statename = "ZPX1"; ZPX1: statename = "ZPX1";
ABS0: statename = "ABS0"; ABS0: statename = "ABS0";
ABS1: statename = "ABS1"; ABS1: statename = "ABS1";
ABS2: statename = "ABS2";
ABS3: statename = "ABS3";
ABSX0: statename = "ABSX0"; ABSX0: statename = "ABSX0";
ABSX1: statename = "ABSX1"; ABSX1: statename = "ABSX1";
ABSX2: statename = "ABSX2"; ABSX2: statename = "ABSX2";
ABSX3: statename = "ABSX3";
ABSX4: statename = "ABSX4";
IND0: statename = "IND0"; IND0: statename = "IND0";
INDX0: statename = "INDX0"; INDX0: statename = "INDX0";
INDX1: statename = "INDX1"; INDX1: statename = "INDX1";
@@ -318,16 +333,24 @@ always @*
BRK1: statename = "BRK1"; BRK1: statename = "BRK1";
BRK2: statename = "BRK2"; BRK2: statename = "BRK2";
BRK3: statename = "BRK3"; BRK3: statename = "BRK3";
BRK4: statename = "BRK4";
BRK5: statename = "BRK5";
BRA0: statename = "BRA0"; BRA0: statename = "BRA0";
BRA1: statename = "BRA1"; BRA1: statename = "BRA1";
BRA2: statename = "BRA2"; BRA2: statename = "BRA2";
JMP0: statename = "JMP0"; JMP0: statename = "JMP0";
JMP1: statename = "JMP1"; JMP1: statename = "JMP1";
JMP2: statename = "JMP2";
JMP3: statename = "JMP3";
JMPI0: statename = "JMPI0"; JMPI0: statename = "JMPI0";
JMPI1: statename = "JMPI1"; JMPI1: statename = "JMPI1";
JMPI2: statename = "JMPI2";
JMPI3: statename = "JMPI3";
JMPIX0: statename = "JMPIX0"; JMPIX0: statename = "JMPIX0";
JMPIX1: statename = "JMPIX1"; JMPIX1: statename = "JMPIX1";
JMPIX2: statename = "JMPIX2"; JMPIX2: statename = "JMPIX2";
JMPIX3: statename = "JMPIX3";
JMPIX4: statename = "JMPIX4";
WAI: statename = "WAI"; WAI: statename = "WAI";
endcase endcase
@@ -346,25 +369,25 @@ always @*
always @* always @*
case( state ) case( state )
DECODE: if( (~I & IRQ) | NMI_edge ) DECODE: if( (~I & IRQ) | NMI_edge )
PC_temp = { ABH, ABL }; PC_temp = ABR;
else else
PC_temp = PC; PC_temp = PC;
JMP1, JMP3,
JMPI1, JMPI3,
JMPIX1, JMPIX3,
JSR3, JSR3,
RTS3, RTS3,
RTI4: PC_temp = { DIMUX, ADD }; RTI4: PC_temp = { DIMUX, ADD, alu_sr_0, alu_sr_1};
BRA1: PC_temp = { ABH, ADD }; BRA1: PC_temp = { ABR[15:8], ADD };
JMPIX2, JMPIX4,
BRA2: PC_temp = { ADD, PCL }; BRA2: PC_temp = { ADD, PC[7:0] }; // TODO
BRK2: PC_temp = res ? 16'hfffc : BRK4: PC_temp = res ? 32'hFFFFFFF4 :
NMI_edge ? 16'hfffa : 16'hfffe; NMI_edge ? 32'hFFFFFFF8 : 32'hFFFFFFFC;
default: PC_temp = PC; default: PC_temp = PC;
endcase endcase
@@ -380,19 +403,31 @@ always @*
PC_inc = 1; PC_inc = 1;
ABS0, ABS0,
ABS1,
ABS2,
JMPIX0, JMPIX0,
JMPIX1,
JMPIX2, JMPIX2,
JMPIX4,
ABSX0, ABSX0,
ABSX1,
ABSX2,
FETCH, FETCH,
BRA0, BRA0,
BRA2, BRA2,
BRK3, BRK5,
JMPI0,
JMPI1, JMPI1,
JMPI2,
JMPI3,
JMP0,
JMP1, JMP1,
JMP2,
JMP3,
RTI4, RTI4,
RTS3: PC_inc = 1; RTS3: PC_inc = 1;
JMPIX1: PC_inc = ~CO; // Don't increment PC if we are going to go through JMPIX2 JMPIX3: PC_inc = ~CO; // Don't increment PC if we are going to go through JMPIX4
BRA1: PC_inc = CO ^~ backwards; BRA1: PC_inc = CO ^~ backwards;
@@ -416,27 +451,27 @@ parameter
always @* always @*
case( state ) case( state )
JMPIX1, JMPIX3,
ABSX1, ABSX3,
INDX3, INDX3,
INDY2, INDY2,
JMP1, JMP3,
JMPI1, JMPI3,
RTI4, RTI4,
ABS1: AB = { DIMUX, ADD }; ABS3: AB = { DIMUX, ADD, alu_sr_0, alu_sr_1};
BRA2, BRA2,
INDY3, INDY3,
JMPIX2, JMPIX4,
ABSX2: AB = { ADD, ABL }; ABSX4: AB = { ADD, ABR[23:0] }; // TODO
BRA1: AB = { ABH, ADD }; BRA1: AB = { ABR[15:8], ADD }; // TODO
JSR0, JSR0,
PUSH1, PUSH1,
RTS0, RTS0,
RTI0, RTI0,
BRK0: AB = { STACKPAGE, regfile }; BRK0: AB = { 16'h0, STACKPAGE, regfile };
BRK1, BRK1,
JSR1, JSR1,
@@ -446,7 +481,9 @@ always @*
RTI1, RTI1,
RTI2, RTI2,
RTI3, RTI3,
BRK2: AB = { STACKPAGE, ADD }; BRK2,
BRK3,
BRK4: AB = { 16'h0, STACKPAGE, ADD };
INDY1, INDY1,
INDX1, INDX1,
@@ -458,7 +495,7 @@ always @*
REG, REG,
READ, READ,
WRITE: AB = { ABH, ABL }; WRITE: AB = ABR;
default: AB = PC; default: AB = PC;
endcase endcase
@@ -472,8 +509,7 @@ always @(posedge clk)
if( state != PUSH0 && state != PUSH1 && RDY && if( state != PUSH0 && state != PUSH1 && RDY &&
state != PULL0 && state != PULL1 && state != PULL2 ) state != PULL0 && state != PULL1 && state != PULL2 )
begin begin
ABL <= AB[7:0]; ABR <= AB;
ABH <= AB[15:8];
end end
/* /*
@@ -484,14 +520,20 @@ always @*
WRITE: DO = ADD; WRITE: DO = ADD;
JSR0, JSR0,
BRK0: DO = PCH; BRK0: DO = PC[31:24];
JSR1, JSR1,
BRK1: DO = PCL; BRK1: DO = PC[23:16];
JSR2,
BRK2: DO = PC[15:8];
JSR3,
BRK3: DO = PC[7:0];
PUSH1: DO = php ? P : ADD; PUSH1: DO = php ? P : ADD;
BRK2: DO = (IRQ | NMI_edge) ? (P & 8'b1110_1111) : P; BRK4: DO = (IRQ | NMI_edge) ? (P & 8'b1110_1111) : P;
default: DO = store_zero ? 8'b0 : regfile; default: DO = store_zero ? 8'b0 : regfile;
endcase endcase
@@ -505,15 +547,20 @@ always @*
BRK0, // writing to stack or memory BRK0, // writing to stack or memory
BRK1, BRK1,
BRK2, BRK2,
BRK2,
BRK3,
BRK4,
JSR0, JSR0,
JSR1, JSR1,
JSR2,
JSR3,
PUSH1, PUSH1,
WRITE: WE = 1; WRITE: WE = 1;
INDX3, // only if doing a STA, STX or STY INDX3, // only if doing a STA, STX or STY
INDY3, INDY3,
ABSX2, ABSX4,
ABS1, ABS3,
ZPX1, ZPX1,
ZP0: WE = store; ZP0: WE = store;
@@ -535,7 +582,7 @@ always @*
PULL1, PULL1,
RTS2, RTS2,
RTI3, RTI3,
BRK3, BRK5,
JSR0, JSR0,
JSR2 : write_register = 1; JSR2 : write_register = 1;
@@ -621,7 +668,7 @@ always @*
DECODE : regsel = dst_reg; DECODE : regsel = dst_reg;
BRK0, BRK0,
BRK3, BRK5,
JSR0, JSR0,
JSR2, JSR2,
PULL0, PULL0,
@@ -654,6 +701,11 @@ ALU ALU( .clk(clk),
.HC(HC), .HC(HC),
.RDY(RDY) ); .RDY(RDY) );
always @(posedge clk) begin
alu_sr_0 <= ADD;
alu_sr_1 <= alu_sr_0;
end
/* /*
* Select current ALU operation * Select current ALU operation
*/ */
@@ -668,12 +720,14 @@ always @*
REG : alu_op = op; REG : alu_op = op;
DECODE, DECODE,
ABS1: alu_op = 1'bx; ABS3: alu_op = 1'bx;
PUSH1, PUSH1,
BRK0, BRK0,
BRK1, BRK1,
BRK2, BRK2,
BRK3,
BRK4,
JSR0, JSR0,
JSR1: alu_op = OP_SUB; JSR1: alu_op = OP_SUB;
@@ -710,6 +764,8 @@ always @*
RTI2, RTI2,
BRK1, BRK1,
BRK2, BRK2,
BRK3,
BRK4,
INDX1: AI = ADD; INDX1: AI = ADD;
REG, REG,
@@ -730,12 +786,12 @@ always @*
BRA0, BRA0,
READ: AI = DIMUX; READ: AI = DIMUX;
BRA1: AI = ABH; // don't use PCH in case we're BRA1: AI = ABR[15:8]; // don't use PCH in case we're TODO
FETCH: AI = load_only ? 8'b0 : regfile; FETCH: AI = load_only ? 8'b0 : regfile;
DECODE, DECODE,
ABS1: AI = 8'hxx; // don't care ABS3: AI = 8'hxx; // don't care
default: AI = 0; default: AI = 0;
endcase endcase
@@ -767,10 +823,10 @@ always @*
READ: BI = txb_ins ? (trb_ins ? ~regfile : regfile) : 8'h00; READ: BI = txb_ins ? (trb_ins ? ~regfile : regfile) : 8'h00;
BRA0: BI = PCL; BRA0: BI = PC[7:0]; // TODO
DECODE, DECODE,
ABS1: BI = 8'hxx; ABS3: BI = 8'hxx;
default: BI = DIMUX; default: BI = DIMUX;
endcase endcase
@@ -784,10 +840,12 @@ always @*
INDY2, INDY2,
BRA1, BRA1,
JMPIX1, JMPIX1,
ABSX1: CI = CO; ABSX1,
ABSX2,
ABSX3: CI = CO;
DECODE, DECODE,
ABS1: CI = 1'bx; ABS3: CI = 1'bx;
READ, READ,
REG: CI = rotate ? C : REG: CI = rotate ? C :
@@ -880,7 +938,7 @@ always @(posedge clk)
*/ */
always @(posedge clk) always @(posedge clk)
if( state == BRK3 ) if( state == BRK5 )
I <= 1; I <= 1;
else if( state == RTI2 ) else if( state == RTI2 )
I <= DIMUX[2]; I <= DIMUX[2];
@@ -1005,15 +1063,21 @@ always @(posedge clk or posedge reset)
ZPX1 : state <= write_back ? READ : FETCH; ZPX1 : state <= write_back ? READ : FETCH;
ABS0 : state <= ABS1; ABS0 : state <= ABS1;
ABS1 : state <= write_back ? READ : FETCH; ABS1 : state <= ABS2;
ABS2 : state <= ABS3;
ABS3 : state <= write_back ? READ : FETCH;
ABSX0 : state <= ABSX1; ABSX0 : state <= ABSX1;
ABSX1 : state <= (CO | store | write_back) ? ABSX2 : FETCH; ABSX1 : state <= ABSX2;
ABSX2 : state <= write_back ? READ : FETCH; ABSX2 : state <= ABSX3;
ABSX3 : state <= (CO | store | write_back) ? ABSX4 : FETCH;
ABSX4 : state <= write_back ? READ : FETCH;
JMPIX0 : state <= JMPIX1; JMPIX0 : state <= JMPIX1;
JMPIX1 : state <= CO ? JMPIX2 : JMP0; JMPIX1 : state <= JMPIX2;
JMPIX2 : state <= JMP0; JMPIX2 : state <= JMPIX3;
JMPIX3 : state <= CO ? JMPIX4 : JMP0;
JMPIX4 : state <= JMP0;
IND0 : state <= INDX1; IND0 : state <= INDX1;
@@ -1061,15 +1125,21 @@ always @(posedge clk or posedge reset)
BRA2 : state <= DECODE; BRA2 : state <= DECODE;
JMP0 : state <= JMP1; JMP0 : state <= JMP1;
JMP1 : state <= DECODE; JMP1 : state <= JMP2;
JMP2 : state <= JMP3;
JMP3 : state <= DECODE;
JMPI0 : state <= JMPI1; JMPI0 : state <= JMPI1;
JMPI1 : state <= JMP0; JMPI1 : state <= JMPI2;
JMPI2 : state <= JMPI3;
JMPI3 : state <= JMP0;
BRK0 : state <= BRK1; BRK0 : state <= BRK1;
BRK1 : state <= BRK2; BRK1 : state <= BRK2;
BRK2 : state <= BRK3; BRK2 : state <= BRK3;
BRK3 : state <= JMP0; BRK3 : state <= BRK4;
BRK4 : state <= BRK5;
BRK5 : state <= JMP0;
WAI : state <= ( (~I & IRQ) | NMI_edge ) ? DECODE : WAI; WAI : state <= ( (~I & IRQ) | NMI_edge ) ? DECODE : WAI;
@@ -1091,7 +1161,7 @@ always @(posedge clk or posedge reset)
PUSH1, PUSH1,
PULL2, PULL2,
RTI4, RTI4,
JMP1, JMP3,
BRA2 : SYNC <= 1'b1; BRA2 : SYNC <= 1'b1;
default: SYNC <= 1'b0; default: SYNC <= 1'b0;
endcase endcase
@@ -1415,7 +1485,7 @@ always @(posedge clk)
NMI_1 <= NMI; NMI_1 <= NMI;
always @(posedge clk ) always @(posedge clk )
if( NMI_edge && state == BRK3 ) if( NMI_edge && state == BRK5 )
NMI_edge <= 0; NMI_edge <= 0;
else if( NMI & ~NMI_1 ) else if( NMI & ~NMI_1 )
NMI_edge <= 1; NMI_edge <= 1;