1
0
mirror of https://github.com/pevans/erc-c.git synced 2024-11-24 14:32:08 +00:00
erc-c/src/mos6502.bits.c

162 lines
3.0 KiB
C
Raw Normal View History

2017-12-02 19:05:53 +00:00
/*
* mos6502.bits.c
2017-12-09 04:12:31 +00:00
*
* The code here is used to implement instructions which operate
* specifically on bits of values.
2017-12-02 19:05:53 +00:00
*/
#include "mos6502.h"
#include "mos6502.enums.h"
2017-12-06 23:16:20 +00:00
/*
* The and instruction will assign the bitwise-and of the accumulator
* and a given operand.
*/
2017-12-02 19:05:53 +00:00
DEFINE_INST(and)
{
cpu->A &= oper;
}
2017-12-06 23:16:20 +00:00
/*
* This is the "arithmetic" shift left instruction.
*
* Here we will shift the contents of the given operand left by one bit.
* If the operand was the accumulator, then we'll store it back there;
* if not, we will store it in the last effective address in memory.
*
* Note that we use the carry bit to help us figure out what the "last
* bit" is, and whether we should now set the carry bit as a result of
* our operation.
*/
2017-12-02 19:05:53 +00:00
DEFINE_INST(asl)
{
2017-12-04 02:19:17 +00:00
cpu->P &= ~CARRY;
2017-12-02 19:05:53 +00:00
if (oper & 0x80) {
cpu->P |= CARRY;
}
2017-12-04 02:19:17 +00:00
oper <<= 1;
2017-12-02 19:05:53 +00:00
if (cpu->last_addr) {
vm_segment_set(cpu->memory, cpu->last_addr, oper);
} else {
cpu->A = oper;
}
}
2017-12-06 23:16:20 +00:00
/*
* The bit instruction will test a given operand for certain
* characteristics, and assign the negative, overflow, and/or carry bits
* in the status register as a result.
*/
2017-12-02 19:05:53 +00:00
DEFINE_INST(bit)
{
2017-12-04 02:19:17 +00:00
cpu->P &= ~NEGATIVE;
2017-12-02 19:05:53 +00:00
if (oper & NEGATIVE) {
cpu->P |= NEGATIVE;
}
2017-12-04 02:19:17 +00:00
cpu->P &= ~OVERFLOW;
2017-12-02 19:05:53 +00:00
if (oper & OVERFLOW) {
cpu->P |= OVERFLOW;
}
if (oper & cpu->A) {
cpu->P &= ~ZERO;
2017-12-04 02:19:17 +00:00
} else {
cpu->P |= ZERO;
2017-12-02 19:05:53 +00:00
}
}
2017-12-06 23:16:20 +00:00
/*
* Compute the bitwise-exclusive-or between the accumulator and operand,
* and store the result in A.
*/
2017-12-02 19:05:53 +00:00
DEFINE_INST(eor)
{
cpu->A ^= oper;
}
2017-12-06 23:16:20 +00:00
/*
* This is pretty similar in spirit to the ASL instruction, except we
* shift right rather than left.
*
* Note that the letters in the instruction stand for "logical" shift
* right.
*/
2017-12-02 19:05:53 +00:00
DEFINE_INST(lsr)
{
2017-12-04 02:19:17 +00:00
cpu->P &= ~CARRY;
2017-12-02 19:05:53 +00:00
if (oper & 0x01) {
cpu->P |= CARRY;
}
2017-12-04 02:19:17 +00:00
oper >>= 1;
2017-12-02 19:05:53 +00:00
if (cpu->last_addr) {
vm_segment_set(cpu->memory, cpu->last_addr, oper);
} else {
cpu->A = oper;
}
}
2017-12-06 23:16:20 +00:00
/*
* Compute the bitwise-or of the accumulator and operand, and store the
* result in the A register.
*/
2017-12-02 19:05:53 +00:00
DEFINE_INST(ora)
{
cpu->A |= oper;
}
2017-12-06 23:16:20 +00:00
/*
* This instruction is interesting; it's a _rotation_ left, which means
* that what was in the 8th bit will move to the 1st bit, and everything
* else moves down one place.
*/
2017-12-02 19:05:53 +00:00
DEFINE_INST(rol)
{
CARRY_BIT();
if (oper & 0x80) {
carry = 1;
}
oper <<= 1;
if (carry) {
oper |= 0x01;
}
if (cpu->last_addr) {
vm_segment_set(cpu->memory, cpu->last_addr, oper);
} else {
cpu->A = oper;
}
}
2017-12-06 23:16:20 +00:00
/*
* Here it's a rotation to the right, just like the ROL instruction. All
* bits are maintained.
*/
2017-12-02 19:05:53 +00:00
DEFINE_INST(ror)
{
CARRY_BIT();
if (oper & 0x01) {
carry = 1;
}
oper >>= 1;
if (carry) {
oper |= 0x80;
}
if (cpu->last_addr) {
vm_segment_set(cpu->memory, cpu->last_addr, oper);
} else {
cpu->A = oper;
}
}