Add absolute indexed indirect
This commit is contained in:
@@ -34,6 +34,22 @@ async def handle_memory(dut):
|
|||||||
if we:
|
if we:
|
||||||
memory[addr] = int(dut.DO.value)
|
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
|
@cocotb.test
|
||||||
async def test_reset(dut):
|
async def test_reset(dut):
|
||||||
cocotb.start_soon(Clock(dut.clk, CLK_PERIOD, unit="ns").start())
|
cocotb.start_soon(Clock(dut.clk, CLK_PERIOD, unit="ns").start())
|
||||||
@@ -62,17 +78,7 @@ async def test_reset(dut):
|
|||||||
(0x12345679, False, int(dut.regfile.value)), # Read second byte
|
(0x12345679, False, int(dut.regfile.value)), # Read second byte
|
||||||
]
|
]
|
||||||
|
|
||||||
for expected_output in expected_cpu_outputs:
|
await check_instruction_sequence(dut, expected_cpu_outputs)
|
||||||
await RisingEdge(dut.clk)
|
|
||||||
|
|
||||||
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
|
|
||||||
assert dut_do == expected_do
|
|
||||||
|
|
||||||
@cocotb.test
|
@cocotb.test
|
||||||
async def test_absolute(dut):
|
async def test_absolute(dut):
|
||||||
@@ -120,20 +126,8 @@ async def test_absolute(dut):
|
|||||||
(0x50515253, True, 0x55), # Write to absolute address
|
(0x50515253, True, 0x55), # Write to absolute address
|
||||||
]
|
]
|
||||||
|
|
||||||
for expected_output in expected_cpu_outputs:
|
await check_instruction_sequence(dut, expected_cpu_outputs)
|
||||||
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
|
@cocotb.test
|
||||||
async def test_absolute_x(dut):
|
async def test_absolute_x(dut):
|
||||||
@@ -191,20 +185,8 @@ async def test_absolute_x(dut):
|
|||||||
(0x01020306, True, 0xaa), # Write to address
|
(0x01020306, True, 0xaa), # Write to address
|
||||||
]
|
]
|
||||||
|
|
||||||
for expected_output in expected_cpu_outputs:
|
await check_instruction_sequence(dut, expected_cpu_outputs)
|
||||||
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
|
@cocotb.test
|
||||||
async def test_absolute_y(dut):
|
async def test_absolute_y(dut):
|
||||||
@@ -262,17 +244,53 @@ async def test_absolute_y(dut):
|
|||||||
(0x01020306, True, 0xaa), # Write to address
|
(0x01020306, True, 0xaa), # Write to address
|
||||||
]
|
]
|
||||||
|
|
||||||
for expected_output in expected_cpu_outputs:
|
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)
|
await RisingEdge(dut.clk)
|
||||||
|
dut.reset.value = 0
|
||||||
|
|
||||||
if expected_output:
|
expected_cpu_outputs = [
|
||||||
expected_addr, expected_we, expected_do = expected_output
|
None, # ignore reset sequence
|
||||||
dut_addr = int(dut.AB.value)
|
None,
|
||||||
dut_we = bool(dut.WE.value)
|
None,
|
||||||
dut_do = int(dut.DO.value)
|
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 0
|
||||||
|
(0xdeadbef2, False, None), # addr 0
|
||||||
|
(0xdeadbef3, False, None), # addr 0
|
||||||
|
(0xbeefb055, False, None), #
|
||||||
|
]
|
||||||
|
|
||||||
assert dut_addr == expected_addr
|
await check_instruction_sequence(dut, expected_cpu_outputs)
|
||||||
assert dut_we == expected_we
|
|
||||||
|
|
||||||
if dut_we:
|
|
||||||
assert dut_do == expected_do
|
|
||||||
|
|||||||
148
src/cpu_65c02.v
148
src/cpu_65c02.v
@@ -208,69 +208,71 @@ 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 = 6'd55, // TODO
|
BRK4 = 7'd55, // TODO
|
||||||
BRK5 = 6'd56, // TODO
|
BRK5 = 7'd56, // TODO
|
||||||
JMP2 = 6'd57, // TODO
|
JMP2 = 7'd57, // TODO
|
||||||
JMP3 = 6'd58, // TODO
|
JMP3 = 7'd58, // TODO
|
||||||
ABS2 = 6'd59, // TODO
|
ABS2 = 7'd59, // TODO
|
||||||
ABS3 = 6'd60, // TODO
|
ABS3 = 7'd60, // TODO
|
||||||
ABSX3 = 6'd61, // TODO
|
ABSX3 = 7'd61, // TODO
|
||||||
ABSX4 = 6'd62; // TODO
|
ABSX4 = 7'd62, // TODO
|
||||||
|
JMPIX3 = 7'd63, // TODO
|
||||||
|
JMPIX4 = 7'd64; // TODO
|
||||||
|
|
||||||
`ifdef SIM
|
`ifdef SIM
|
||||||
|
|
||||||
@@ -343,6 +345,8 @@ always @*
|
|||||||
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
|
||||||
@@ -368,14 +372,14 @@ always @*
|
|||||||
|
|
||||||
JMP3,
|
JMP3,
|
||||||
JMPI1,
|
JMPI1,
|
||||||
JMPIX1,
|
JMPIX3,
|
||||||
JSR3,
|
JSR3,
|
||||||
RTS3,
|
RTS3,
|
||||||
RTI4: PC_temp = { DIMUX, ADD, alu_sr_0, alu_sr_1};
|
RTI4: PC_temp = { DIMUX, ADD, alu_sr_0, alu_sr_1};
|
||||||
|
|
||||||
BRA1: PC_temp = { ABR[15:8], ADD };
|
BRA1: PC_temp = { ABR[15:8], ADD };
|
||||||
|
|
||||||
JMPIX2,
|
JMPIX4,
|
||||||
BRA2: PC_temp = { ADD, PC[7:0] }; // TODO
|
BRA2: PC_temp = { ADD, PC[7:0] }; // TODO
|
||||||
|
|
||||||
BRK4: PC_temp = res ? 32'hFFFFFFF4 :
|
BRK4: PC_temp = res ? 32'hFFFFFFF4 :
|
||||||
@@ -398,7 +402,9 @@ always @*
|
|||||||
ABS1,
|
ABS1,
|
||||||
ABS2,
|
ABS2,
|
||||||
JMPIX0,
|
JMPIX0,
|
||||||
|
JMPIX1,
|
||||||
JMPIX2,
|
JMPIX2,
|
||||||
|
JMPIX4,
|
||||||
ABSX0,
|
ABSX0,
|
||||||
ABSX1,
|
ABSX1,
|
||||||
ABSX2,
|
ABSX2,
|
||||||
@@ -414,7 +420,7 @@ always @*
|
|||||||
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;
|
||||||
|
|
||||||
@@ -438,7 +444,7 @@ parameter
|
|||||||
|
|
||||||
always @*
|
always @*
|
||||||
case( state )
|
case( state )
|
||||||
JMPIX1,
|
JMPIX3,
|
||||||
ABSX3,
|
ABSX3,
|
||||||
INDX3,
|
INDX3,
|
||||||
INDY2,
|
INDY2,
|
||||||
@@ -449,7 +455,7 @@ always @*
|
|||||||
|
|
||||||
BRA2,
|
BRA2,
|
||||||
INDY3,
|
INDY3,
|
||||||
JMPIX2,
|
JMPIX4,
|
||||||
ABSX4: AB = { ADD, ABR[23:0] }; // TODO
|
ABSX4: AB = { ADD, ABR[23:0] }; // TODO
|
||||||
|
|
||||||
BRA1: AB = { ABR[15:8], ADD }; // TODO
|
BRA1: AB = { ABR[15:8], ADD }; // TODO
|
||||||
@@ -1061,8 +1067,10 @@ always @(posedge clk or posedge reset)
|
|||||||
ABSX4 : state <= write_back ? READ : 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;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user