mirror of
https://github.com/pevans/erc-c.git
synced 2024-12-21 08:30:55 +00:00
Add TSB (Test and Set Bits) instruction
This commit also moves the TRB code from loadstor to bits, which is where it should have been all along.
This commit is contained in:
parent
a4c3d1c4ef
commit
90892c32e4
@ -126,6 +126,7 @@ enum instruction {
|
|||||||
TAX, // Transfer Accumulator to X
|
TAX, // Transfer Accumulator to X
|
||||||
TAY, // Transfer Accumulator to Y
|
TAY, // Transfer Accumulator to Y
|
||||||
TRB, // Test and Reset Bits
|
TRB, // Test and Reset Bits
|
||||||
|
TSB, // Test and Set Bits
|
||||||
TSX, // Transfer Stack register to X
|
TSX, // Transfer Stack register to X
|
||||||
TXA, // Transfer X to Accumulator
|
TXA, // Transfer X to Accumulator
|
||||||
TXS, // Transfer X to Stack register
|
TXS, // Transfer X to Stack register
|
||||||
|
@ -235,6 +235,7 @@ DECL_INST(stz);
|
|||||||
DECL_INST(tax);
|
DECL_INST(tax);
|
||||||
DECL_INST(tay);
|
DECL_INST(tay);
|
||||||
DECL_INST(trb);
|
DECL_INST(trb);
|
||||||
|
DECL_INST(tsb);
|
||||||
DECL_INST(tsx);
|
DECL_INST(tsx);
|
||||||
DECL_INST(txa);
|
DECL_INST(txa);
|
||||||
DECL_INST(txs);
|
DECL_INST(txs);
|
||||||
|
@ -19,7 +19,7 @@
|
|||||||
*/
|
*/
|
||||||
static int addr_modes[] = {
|
static int addr_modes[] = {
|
||||||
// 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
|
// 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
|
||||||
IMP, IDX, NOA, NOA, NOA, ZPG, ZPG, NOA, IMP, IMM, ACC, NOA, NOA, ABS, ABS, NOA, // 0x
|
IMP, IDX, NOA, NOA, ZPG, ZPG, ZPG, NOA, IMP, IMM, ACC, NOA, ABS, ABS, ABS, NOA, // 0x
|
||||||
REL, IDY, ZPG, NOA, ZPG, ZPX, ZPX, NOA, IMP, ABY, ACC, NOA, ABS, ABX, ABX, NOA, // 1x
|
REL, IDY, ZPG, NOA, ZPG, ZPX, ZPX, NOA, IMP, ABY, ACC, NOA, ABS, ABX, ABX, NOA, // 1x
|
||||||
ABS, IDX, NOA, NOA, ZPG, ZPG, ZPG, NOA, IMP, IMM, ACC, NOA, ABS, ABS, ABS, NOA, // 2x
|
ABS, IDX, NOA, NOA, ZPG, ZPG, ZPG, NOA, IMP, IMM, ACC, NOA, ABS, ABS, ABS, NOA, // 2x
|
||||||
REL, IDY, ZPG, NOA, ZPX, ZPX, ZPX, NOA, IMP, ABY, ACC, NOA, ABX, ABX, ABX, NOA, // 3x
|
REL, IDY, ZPG, NOA, ZPX, ZPX, ZPX, NOA, IMP, ABY, ACC, NOA, ABX, ABX, ABX, NOA, // 3x
|
||||||
|
@ -203,3 +203,53 @@ DEFINE_INST(ror)
|
|||||||
cpu->A = result & 0xff;
|
cpu->A = result & 0xff;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This is a really funky instruction. And not in the good, dancy kinda
|
||||||
|
* way.
|
||||||
|
*
|
||||||
|
* First, it does a BIT-style test to see if A & oper are zero; if so,
|
||||||
|
* it sets the Z flag.
|
||||||
|
*
|
||||||
|
* Second, it clears all bits in eff_addr where A's corresponding bits
|
||||||
|
* are set to 1. It ignores all bits in eff_addr where A's bits are
|
||||||
|
* zero.
|
||||||
|
*
|
||||||
|
* E.g.:
|
||||||
|
*
|
||||||
|
* A: 01011001 (accumulator)
|
||||||
|
* M: 11111111 (value in memory)
|
||||||
|
* R: 10100110 (result)
|
||||||
|
*
|
||||||
|
* And, as following that, the Z flag should be zero because A&M is a
|
||||||
|
* non-zero result.
|
||||||
|
*/
|
||||||
|
DEFINE_INST(trb)
|
||||||
|
{
|
||||||
|
cpu->P &= ~MOS_ZERO;
|
||||||
|
if (!(cpu->A & oper)) {
|
||||||
|
cpu->P |= MOS_ZERO;
|
||||||
|
}
|
||||||
|
|
||||||
|
mos6502_set(cpu, cpu->eff_addr,
|
||||||
|
(cpu->A ^ 0xff) & oper);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Test to see if (A & oper) are zero and set Z flag if so.
|
||||||
|
* Additionally, set the bits in the byte at a given effective address
|
||||||
|
* (M) to 1 where the A register's bits are also 1. (Bits that are 0 in
|
||||||
|
* A are unchanged in M.)
|
||||||
|
*/
|
||||||
|
DEFINE_INST(tsb)
|
||||||
|
{
|
||||||
|
cpu->P &= ~MOS_ZERO;
|
||||||
|
if (!(cpu->A & oper)) {
|
||||||
|
cpu->P |= MOS_ZERO;
|
||||||
|
}
|
||||||
|
|
||||||
|
// The behavior described in the docblock here can be accomplished
|
||||||
|
// simply by OR'ing the accumulator and the operand, and storing
|
||||||
|
// back into memory at eff_addr.
|
||||||
|
mos6502_set(cpu, cpu->eff_addr, cpu->A | oper);
|
||||||
|
}
|
||||||
|
@ -27,7 +27,7 @@
|
|||||||
*/
|
*/
|
||||||
static int instructions[] = {
|
static int instructions[] = {
|
||||||
// 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
|
// 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
|
||||||
BRK, ORA, BAD, BAD, BAD, ORA, ASL, BAD, PHP, ORA, ASL, BAD, BAD, ORA, ASL, BAD, // 0x
|
BRK, ORA, BAD, BAD, TSB, ORA, ASL, BAD, PHP, ORA, ASL, BAD, TSB, ORA, ASL, BAD, // 0x
|
||||||
BPL, ORA, ORA, BAD, TRB, ORA, ASL, BAD, CLC, ORA, INC, BAD, TRB, ORA, ASL, BAD, // 1x
|
BPL, ORA, ORA, BAD, TRB, ORA, ASL, BAD, CLC, ORA, INC, BAD, TRB, ORA, ASL, BAD, // 1x
|
||||||
JSR, AND, BAD, BAD, BIT, AND, ROL, BAD, PLP, AND, ROL, BAD, BIT, AND, ROL, BAD, // 2x
|
JSR, AND, BAD, BAD, BIT, AND, ROL, BAD, PLP, AND, ROL, BAD, BIT, AND, ROL, BAD, // 2x
|
||||||
BMI, AND, AND, BAD, BIT, AND, ROL, BAD, SEC, AND, DEC, BAD, BIT, AND, ROL, BAD, // 3x
|
BMI, AND, AND, BAD, BIT, AND, ROL, BAD, SEC, AND, DEC, BAD, BIT, AND, ROL, BAD, // 3x
|
||||||
@ -118,6 +118,7 @@ static mos6502_instruction_handler instruction_handlers[] = {
|
|||||||
INST_HANDLER(tax),
|
INST_HANDLER(tax),
|
||||||
INST_HANDLER(tay),
|
INST_HANDLER(tay),
|
||||||
INST_HANDLER(trb),
|
INST_HANDLER(trb),
|
||||||
|
INST_HANDLER(tsb),
|
||||||
INST_HANDLER(tsx),
|
INST_HANDLER(tsx),
|
||||||
INST_HANDLER(txa),
|
INST_HANDLER(txa),
|
||||||
INST_HANDLER(txs),
|
INST_HANDLER(txs),
|
||||||
@ -131,7 +132,7 @@ static mos6502_instruction_handler instruction_handlers[] = {
|
|||||||
*/
|
*/
|
||||||
static int cycles[] = {
|
static int cycles[] = {
|
||||||
// 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
|
// 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
|
||||||
7, 6, 0, 0, 0, 3, 5, 0, 3, 2, 2, 0, 0, 4, 6, 0, // 0x
|
7, 6, 0, 0, 5, 3, 5, 0, 3, 2, 2, 0, 6, 4, 6, 0, // 0x
|
||||||
2, 5, 5, 0, 5, 4, 6, 0, 2, 4, 2, 0, 6, 4, 7, 0, // 1x
|
2, 5, 5, 0, 5, 4, 6, 0, 2, 4, 2, 0, 6, 4, 7, 0, // 1x
|
||||||
6, 6, 0, 0, 3, 3, 5, 0, 4, 2, 2, 0, 4, 4, 6, 0, // 2x
|
6, 6, 0, 0, 3, 3, 5, 0, 4, 2, 2, 0, 4, 4, 6, 0, // 2x
|
||||||
2, 5, 5, 0, 4, 4, 6, 0, 2, 4, 2, 0, 4, 4, 7, 0, // 3x
|
2, 5, 5, 0, 4, 4, 6, 0, 2, 4, 2, 0, 4, 4, 7, 0, // 3x
|
||||||
|
@ -102,6 +102,7 @@ static char *instruction_strings[] = {
|
|||||||
"TAX",
|
"TAX",
|
||||||
"TAY",
|
"TAY",
|
||||||
"TRB",
|
"TRB",
|
||||||
|
"TSB",
|
||||||
"TSX",
|
"TSX",
|
||||||
"TXA",
|
"TXA",
|
||||||
"TXS",
|
"TXS",
|
||||||
|
@ -156,37 +156,6 @@ DEFINE_INST(tay)
|
|||||||
cpu->Y = cpu->A;
|
cpu->Y = cpu->A;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* This is a really funky instruction. And not in the good, dancy kinda
|
|
||||||
* way.
|
|
||||||
*
|
|
||||||
* First, it does a BIT-style test to see if A & oper are zero; if so,
|
|
||||||
* it sets the Z flag.
|
|
||||||
*
|
|
||||||
* Second, it clears all bits in eff_addr where A's corresponding bits
|
|
||||||
* are set to 1. It ignores all bits in eff_addr where A's bits are
|
|
||||||
* zero.
|
|
||||||
*
|
|
||||||
* E.g.:
|
|
||||||
*
|
|
||||||
* A: 01011001 (accumulator)
|
|
||||||
* M: 11111111 (value in memory)
|
|
||||||
* R: 10100110 (result)
|
|
||||||
*
|
|
||||||
* And, as following that, the Z flag should be zero because A&M is a
|
|
||||||
* non-zero result.
|
|
||||||
*/
|
|
||||||
DEFINE_INST(trb)
|
|
||||||
{
|
|
||||||
cpu->P &= ~MOS_ZERO;
|
|
||||||
if (!(cpu->A & oper)) {
|
|
||||||
cpu->P |= MOS_ZERO;
|
|
||||||
}
|
|
||||||
|
|
||||||
mos6502_set(cpu, cpu->eff_addr,
|
|
||||||
(cpu->A ^ 0xff) & oper);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Transfer the stack pointer (S register) to X.
|
* Transfer the stack pointer (S register) to X.
|
||||||
*/
|
*/
|
||||||
|
@ -127,3 +127,43 @@ Test(mos6502_bits, ror)
|
|||||||
mos6502_handle_ror(cpu, 0);
|
mos6502_handle_ror(cpu, 0);
|
||||||
cr_assert_eq(mos6502_get(cpu, 123), 128);
|
cr_assert_eq(mos6502_get(cpu, 123), 128);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Test(mos6502_bits, trb)
|
||||||
|
{
|
||||||
|
cpu->A = 6;
|
||||||
|
mos6502_handle_trb(cpu, 3);
|
||||||
|
cr_assert_eq(cpu->P & MOS_ZERO, 0);
|
||||||
|
cpu->A = 9;
|
||||||
|
mos6502_handle_trb(cpu, 2);
|
||||||
|
cr_assert_eq(cpu->P & MOS_ZERO, MOS_ZERO);
|
||||||
|
|
||||||
|
cpu->eff_addr = 111;
|
||||||
|
mos6502_set(cpu, cpu->eff_addr, 123);
|
||||||
|
mos6502_handle_trb(cpu, 123);
|
||||||
|
|
||||||
|
cr_assert_eq(mos6502_get(cpu, cpu->eff_addr),
|
||||||
|
(cpu->A ^ 0xff) & 123);
|
||||||
|
}
|
||||||
|
|
||||||
|
Test(mos6502_bits, tsb)
|
||||||
|
{
|
||||||
|
// I borrowed this code from the trb test; TSB and TRB do exactly
|
||||||
|
// the same thing in regards to the zero bit.
|
||||||
|
cpu->A = 6;
|
||||||
|
mos6502_handle_trb(cpu, 3);
|
||||||
|
cr_assert_eq(cpu->P & MOS_ZERO, 0);
|
||||||
|
cpu->A = 9;
|
||||||
|
mos6502_handle_trb(cpu, 2);
|
||||||
|
cr_assert_eq(cpu->P & MOS_ZERO, MOS_ZERO);
|
||||||
|
|
||||||
|
// This is similar to the segment in the trb test that focuses on
|
||||||
|
// the resetting (clearing) of bits, but modified to account for the
|
||||||
|
// differing result that tsb would provide--namely that the 1s in A
|
||||||
|
// will be set in the location in memory, rather than cleared.
|
||||||
|
cpu->eff_addr = 111;
|
||||||
|
mos6502_set(cpu, cpu->eff_addr, 123);
|
||||||
|
mos6502_handle_tsb(cpu, 123);
|
||||||
|
|
||||||
|
cr_assert_eq(mos6502_get(cpu, cpu->eff_addr), cpu->A | 123);
|
||||||
|
}
|
||||||
|
|
||||||
|
@ -140,23 +140,6 @@ Test(mos6502_loadstor, tay)
|
|||||||
cr_assert_eq(cpu->Y, 111);
|
cr_assert_eq(cpu->Y, 111);
|
||||||
}
|
}
|
||||||
|
|
||||||
Test(mos6502_loadstor, trb)
|
|
||||||
{
|
|
||||||
cpu->A = 6;
|
|
||||||
mos6502_handle_trb(cpu, 3);
|
|
||||||
cr_assert_eq(cpu->P & MOS_ZERO, 0);
|
|
||||||
cpu->A = 9;
|
|
||||||
mos6502_handle_trb(cpu, 2);
|
|
||||||
cr_assert_eq(cpu->P & MOS_ZERO, MOS_ZERO);
|
|
||||||
|
|
||||||
cpu->eff_addr = 111;
|
|
||||||
mos6502_set(cpu, cpu->eff_addr, 123);
|
|
||||||
mos6502_handle_trb(cpu, 123);
|
|
||||||
|
|
||||||
cr_assert_eq(mos6502_get(cpu, cpu->eff_addr),
|
|
||||||
(cpu->A ^ 0xff) & 123);
|
|
||||||
}
|
|
||||||
|
|
||||||
Test(mos6502_loadstor, tsx)
|
Test(mos6502_loadstor, tsx)
|
||||||
{
|
{
|
||||||
cpu->S = 111;
|
cpu->S = 111;
|
||||||
|
Loading…
Reference in New Issue
Block a user