mirror of
https://github.com/pevans/erc-c.git
synced 2024-10-08 07:58:04 +00:00
130 lines
3.1 KiB
C
130 lines
3.1 KiB
C
/*
|
|
* mos6502.arith.c
|
|
*
|
|
* We define here the logic for arithmetic instructions for the MOS 6502
|
|
* processor.
|
|
*/
|
|
|
|
#include "mos6502.h"
|
|
#include "mos6502.enums.h"
|
|
|
|
/*
|
|
* The adc instruction will add a number to the accumulator, "with
|
|
* carry". If the carry bit is set, we will add 1 to the accumulator as
|
|
* an after-effect.
|
|
*/
|
|
DEFINE_INST(adc)
|
|
{
|
|
MOS_CARRY_BIT();
|
|
cpu->A += oper + carry;
|
|
|
|
mos6502_modify_status(cpu, MOS_NEGATIVE | MOS_OVERFLOW | MOS_CARRY | MOS_ZERO, cpu->A);
|
|
}
|
|
|
|
/*
|
|
* The cmp instruction will consider the difference of the accumulator
|
|
* minus the operand. It will then set the zero, negative, or carry bits
|
|
* based upon that difference. _The accumulator is neither modified nor
|
|
* harmed by this operation._ (We have trained experts on the set to
|
|
* monitor the health of the accumulator, whom we've named George.)
|
|
*/
|
|
DEFINE_INST(cmp)
|
|
{
|
|
mos6502_modify_status(cpu, MOS_ZERO | MOS_NEGATIVE | MOS_CARRY, cpu->A - oper);
|
|
}
|
|
|
|
/*
|
|
* This instruction is functionally identical to CMP, with the exception
|
|
* that it considers the X register rather than the accumulator.
|
|
*/
|
|
DEFINE_INST(cpx)
|
|
{
|
|
mos6502_modify_status(cpu, MOS_ZERO | MOS_NEGATIVE | MOS_CARRY, cpu->X - oper);
|
|
}
|
|
|
|
/*
|
|
* Again, this is a variant of the CMP instruction, except that it works
|
|
* with the Y register.
|
|
*/
|
|
DEFINE_INST(cpy)
|
|
{
|
|
mos6502_modify_status(cpu, MOS_ZERO | MOS_NEGATIVE | MOS_CARRY, cpu->Y - oper);
|
|
}
|
|
|
|
/*
|
|
* Here we will decrement the value at the effective address in memory
|
|
* by 1. The DEC instruction is _unable_ to decrement the accumulator,
|
|
* which was a tiny oversight in the original build of the 6502.
|
|
* (Whoopsie!)
|
|
*/
|
|
DEFINE_INST(dec)
|
|
{
|
|
if (cpu->last_addr) {
|
|
vm_segment_set(cpu->memory, cpu->last_addr, oper - 1);
|
|
mos6502_modify_status(cpu, MOS_NEGATIVE | MOS_ZERO, oper - 1);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* In contrast, this does directly decrement the X register.
|
|
*/
|
|
DEFINE_INST(dex)
|
|
{
|
|
cpu->X--;
|
|
mos6502_modify_status(cpu, MOS_NEGATIVE | MOS_ZERO, cpu->X);
|
|
}
|
|
|
|
/*
|
|
* And, again, here we decrement the Y register.
|
|
*/
|
|
DEFINE_INST(dey)
|
|
{
|
|
cpu->Y--;
|
|
mos6502_modify_status(cpu, MOS_NEGATIVE | MOS_ZERO, cpu->Y);
|
|
}
|
|
|
|
/*
|
|
* The INC instruction is basically the same as the DEC one. It, also,
|
|
* can only work with an address in memory, and it increments the value
|
|
* by 1.
|
|
*/
|
|
DEFINE_INST(inc)
|
|
{
|
|
if (cpu->last_addr) {
|
|
vm_segment_set(cpu->memory, cpu->last_addr, oper + 1);
|
|
mos6502_modify_status(cpu, MOS_NEGATIVE | MOS_ZERO, oper + 1);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* See DEX.
|
|
*/
|
|
DEFINE_INST(inx)
|
|
{
|
|
cpu->X++;
|
|
mos6502_modify_status(cpu, MOS_NEGATIVE | MOS_ZERO, cpu->X);
|
|
}
|
|
|
|
/*
|
|
* See DEY.
|
|
*/
|
|
DEFINE_INST(iny)
|
|
{
|
|
cpu->Y++;
|
|
mos6502_modify_status(cpu, MOS_NEGATIVE | MOS_ZERO, cpu->Y);
|
|
}
|
|
|
|
/*
|
|
* This instruction will subtract the operand from the accumulator,
|
|
* again, "with carry". In this context, that means that if the carry
|
|
* bit is set, then we will subtract 1 again from the A register after
|
|
* the operand is subtracted. The result is stored in the accumulator.
|
|
*/
|
|
DEFINE_INST(sbc)
|
|
{
|
|
MOS_CARRY_BIT();
|
|
cpu->A = cpu->A - oper - carry;
|
|
|
|
mos6502_modify_status(cpu, MOS_NEGATIVE | MOS_OVERFLOW | MOS_CARRY | MOS_ZERO, cpu->A);
|
|
}
|