mirror of
https://github.com/andrew-jacobs/emu816.git
synced 2024-10-12 21:23:44 +00:00
1513 lines
22 KiB
C++
1513 lines
22 KiB
C++
//==============================================================================
|
|
// .ooooo. .o .ooo
|
|
// d88' `8. o888 .88'
|
|
// .ooooo. ooo. .oo. .oo. oooo oooo Y88.. .8' 888 d88'
|
|
// d88' `88b `888P"Y88bP"Y88b `888 `888 `88888b. 888 d888P"Ybo.
|
|
// 888ooo888 888 888 888 888 888 .8' ``88b 888 Y88[ ]88
|
|
// 888 .o 888 888 888 888 888 `8. .88P 888 `Y88 88P
|
|
// `Y8bod8P' o888o o888o o888o `V88V"V8P' `boood8' o888o `88bod8'
|
|
//
|
|
// A Portable C++ WDC 65C816 Emulator
|
|
//------------------------------------------------------------------------------
|
|
// Copyright (C)2016 Andrew John Jacobs
|
|
// All rights reserved.
|
|
//
|
|
// This work is made available under the terms of the Creative Commons
|
|
// Attribution-NonCommercial-ShareAlike 4.0 International license. Open the
|
|
// following URL to see the details.
|
|
//
|
|
// http://creativecommons.org/licenses/by-nc-sa/4.0/
|
|
//------------------------------------------------------------------------------
|
|
|
|
#ifndef EMU816_H
|
|
#define EMU816_H
|
|
|
|
#include "mem816.h"
|
|
|
|
#include <stdlib.h>
|
|
|
|
#if 1
|
|
# define TRACE(MNEM) { if (trace) dump(MNEM, ea); }
|
|
# define BYTES(N) { if (trace) bytes(N); pc += N; }
|
|
# define SHOWPC() { if (trace) show(); }
|
|
# ifdef CHIPKIT
|
|
# define ENDL() { Serial.println (); }
|
|
# else
|
|
# define ENDL() { if (trace) cout << endl; }
|
|
# endif
|
|
#else
|
|
# define TRACE(MNEM)
|
|
# define BYTES(N) { pc += N; }
|
|
# define SHOWPC()
|
|
# define ENDL()
|
|
#endif
|
|
|
|
class emu816 :
|
|
public wdc816
|
|
{
|
|
public:
|
|
emu816(mem816 &mem);
|
|
~emu816();
|
|
|
|
void reset(bool trace);
|
|
void step();
|
|
|
|
private:
|
|
union {
|
|
struct {
|
|
Bit f_c : 1;
|
|
Bit f_z : 1;
|
|
Bit f_i : 1;
|
|
Bit f_d : 1;
|
|
Bit f_x : 1;
|
|
Bit f_m : 1;
|
|
Bit f_v : 1;
|
|
Bit f_n : 1;
|
|
};
|
|
Byte b;
|
|
} p;
|
|
|
|
Bit e;
|
|
|
|
union {
|
|
Byte b;
|
|
Word w;
|
|
} a, x, y, sp, dp;
|
|
|
|
Word pc;
|
|
Byte pbr, dbr;
|
|
|
|
mem816 &mem;
|
|
|
|
bool interrupted;
|
|
unsigned long cycles;
|
|
bool trace;
|
|
|
|
void show();
|
|
void bytes(unsigned int);
|
|
void dump(const char *, Addr);
|
|
|
|
// Push a byte on the stack
|
|
INLINE void pushByte(Byte value)
|
|
{
|
|
mem.setByte(sp.w, value);
|
|
|
|
if (e)
|
|
--sp.b;
|
|
else
|
|
--sp.w;
|
|
}
|
|
|
|
// Push a word on the stack
|
|
INLINE void pushWord(Word value)
|
|
{
|
|
pushByte(hi(value));
|
|
pushByte(lo(value));
|
|
}
|
|
|
|
// Pull a byte from the stack
|
|
INLINE Byte pullByte()
|
|
{
|
|
if (e)
|
|
++sp.b;
|
|
else
|
|
++sp.w;
|
|
|
|
return (mem.getByte(sp.w));
|
|
}
|
|
|
|
// Pull a word from the stack
|
|
INLINE Word pullWord()
|
|
{
|
|
register Byte l = pullByte();
|
|
register Byte h = pullByte();
|
|
|
|
return (join(l, h));
|
|
}
|
|
|
|
// Absolute - a
|
|
INLINE Addr am_absl()
|
|
{
|
|
register Addr ea = join (dbr, mem.getWord(bank(pbr) | pc));
|
|
|
|
BYTES(2);
|
|
return (ea);
|
|
}
|
|
|
|
// Absolute Indexed X - a,X
|
|
INLINE Addr am_absx()
|
|
{
|
|
register Addr ea = join(dbr, mem.getWord(bank(pbr) | pc)) + x.w;
|
|
|
|
BYTES(2);
|
|
return (ea);
|
|
}
|
|
|
|
// Absolute Indexed Y - a,Y
|
|
INLINE Addr am_absy()
|
|
{
|
|
register Addr ea = join(dbr, mem.getWord(bank(pbr) | pc)) + y.w;
|
|
|
|
BYTES(2);
|
|
return (ea);
|
|
}
|
|
|
|
// Absolute Indirect - (a)
|
|
INLINE Addr am_absi()
|
|
{
|
|
register Addr ia = join(0, mem.getWord(bank(pbr) | pc));
|
|
|
|
BYTES(2);
|
|
return (join(0, mem.getWord(ia)));
|
|
}
|
|
|
|
// Absolute Indexed Indirect - (a,X)
|
|
INLINE Addr am_abxi()
|
|
{
|
|
register Addr ia = join(pbr, mem.getWord(bank(pbr) | pc)) + x.w;
|
|
|
|
BYTES(2);
|
|
return (join(pbr, mem.getWord(ia)));
|
|
}
|
|
|
|
// Absolute Long - >a
|
|
INLINE Addr am_alng()
|
|
{
|
|
Addr ea = mem.getAddr(bank(pbr) | pc);
|
|
|
|
BYTES(3);
|
|
return (ea);
|
|
}
|
|
|
|
// Absolute Long Indexed - >a,X
|
|
INLINE Addr am_alnx()
|
|
{
|
|
register Addr ea = mem.getAddr(bank(pbr) | pc) + x.w;
|
|
|
|
BYTES(3);
|
|
return (ea);
|
|
}
|
|
|
|
// Absolute Indirect Long - [a]
|
|
INLINE Addr am_abil()
|
|
{
|
|
register Addr ia = bank(0) | mem.getWord(bank(pbr) | pc);
|
|
|
|
BYTES(2);
|
|
return (mem.getAddr(ia));
|
|
}
|
|
|
|
// Direct Page - d
|
|
INLINE Addr am_dpag()
|
|
{
|
|
Byte offset = mem.getByte(bank(pbr) | pc);
|
|
|
|
BYTES(1);
|
|
return (bank(0) | (Word)(dp.w + offset));
|
|
}
|
|
|
|
// Direct Page Indexed X - d,X
|
|
INLINE Addr am_dpgx()
|
|
{
|
|
Byte offset = mem.getByte(bank(pbr) | pc) + x.b;
|
|
|
|
BYTES(1);
|
|
return (bank(0) | (Word)(dp.w + offset));
|
|
}
|
|
|
|
// Direct Page Indexed Y - d,Y
|
|
INLINE Addr am_dpgy()
|
|
{
|
|
Byte offset = mem.getByte(bank(pbr) | pc) + y.b;
|
|
|
|
BYTES(1);
|
|
return (bank(0) | (Word)(dp.w + offset));
|
|
}
|
|
|
|
// Direct Page Indirect - (d)
|
|
INLINE Addr am_dpgi()
|
|
{
|
|
Byte disp = mem.getByte(bank(pbr) | pc);
|
|
|
|
BYTES(1);
|
|
return (bank(dbr) | mem.getWord(bank(0) | (Word)(dp.w + disp)));
|
|
}
|
|
|
|
// Direct Page Indexed Indirect - (d,x)
|
|
INLINE Addr am_dpix()
|
|
{
|
|
Byte disp = mem.getByte(bank(pbr) | pc);
|
|
|
|
BYTES(1);
|
|
return (bank(dbr) | mem.getWord(bank(0) | (Word)(dp.w + disp + x.w)));
|
|
}
|
|
|
|
// Direct Page Indirect Indexed - (d),Y
|
|
INLINE Addr am_dpiy()
|
|
{
|
|
Byte disp = mem.getByte(bank(pbr) | pc);
|
|
|
|
BYTES(1);
|
|
return (bank(dbr) | mem.getWord(bank(0) | (dp.w + disp)) + y.w);
|
|
}
|
|
|
|
// Direct Page Indirect Long - [d]
|
|
INLINE Addr am_dpil()
|
|
{
|
|
Byte disp = mem.getByte(bank(pbr) | pc);
|
|
|
|
BYTES(1);
|
|
return (mem.getAddr(bank(0) | (Word)(dp.w + disp)));
|
|
}
|
|
|
|
// Direct Page Indirect Long Indexed - [d],Y
|
|
INLINE Addr am_dily()
|
|
{
|
|
Byte disp = mem.getByte(bank(pbr) | pc);
|
|
|
|
BYTES(1);
|
|
return (mem.getAddr(bank(0) | (Word)(dp.w + disp)) + y.w);
|
|
}
|
|
|
|
// Implied/Stack
|
|
INLINE Addr am_impl()
|
|
{
|
|
BYTES(0);
|
|
return (0);
|
|
}
|
|
|
|
// Accumulator
|
|
INLINE Addr am_acc()
|
|
{
|
|
BYTES(0);
|
|
return (0);
|
|
}
|
|
|
|
// Immediate Byte
|
|
INLINE Addr am_immb()
|
|
{
|
|
Addr ea = bank(pbr) | pc;
|
|
|
|
BYTES(1);
|
|
return (ea);
|
|
}
|
|
|
|
// Immediate Word
|
|
INLINE Addr am_immw()
|
|
{
|
|
Addr ea = bank(pbr) | pc;
|
|
|
|
BYTES(2);
|
|
return (ea);
|
|
}
|
|
|
|
// Immediate based on size of A/M
|
|
INLINE Addr am_immm()
|
|
{
|
|
Addr ea = bank(pbr) | pc;
|
|
unsigned int size = (e || p.f_m) ? 1 : 2;
|
|
|
|
BYTES(size);
|
|
return (ea);
|
|
}
|
|
|
|
// Immediate based on size of X/Y
|
|
INLINE Addr am_immx()
|
|
{
|
|
Addr ea = bank(pbr) | pc;
|
|
unsigned int size = (e || p.f_x) ? 1 : 2;
|
|
|
|
BYTES(size);
|
|
return (ea);
|
|
}
|
|
|
|
// Long Relative - d
|
|
INLINE Addr am_lrel()
|
|
{
|
|
Word disp = mem.getWord(bank(pbr) | pc);
|
|
|
|
BYTES(2);
|
|
return (bank(pbr) | (Word)(pc + (signed short)disp));
|
|
}
|
|
|
|
// Relative - d
|
|
INLINE Addr am_rela()
|
|
{
|
|
Byte disp = mem.getByte(bank(pbr) | pc);
|
|
|
|
BYTES(1);
|
|
return (bank(pbr) | (Word)(pc + (signed char)disp));
|
|
}
|
|
|
|
// Stack Relative - d,S
|
|
INLINE Addr am_srel()
|
|
{
|
|
Byte disp = mem.getByte(bank(pbr) | pc);
|
|
|
|
BYTES(1);
|
|
|
|
if (e)
|
|
return((bank(0) | join(sp.b + disp, hi(sp.w))));
|
|
else
|
|
return (bank(0) | (Word)(sp.w + disp));
|
|
}
|
|
|
|
// Stack Relative Indirect Indexed Y - (d,S),Y
|
|
INLINE Addr am_sriy()
|
|
{
|
|
Byte disp = mem.getByte(bank(pbr) | pc);
|
|
register Word ia;
|
|
|
|
BYTES(1);
|
|
|
|
if (e)
|
|
ia = mem.getWord(join(sp.b + disp, hi(sp.w)));
|
|
else
|
|
ia = mem.getWord(bank(0) | (sp.w + disp));
|
|
|
|
return (bank(dbr) | (Word)(ia + y.w));
|
|
}
|
|
|
|
// Set the Negative flag
|
|
INLINE void setn(unsigned int flag)
|
|
{
|
|
p.f_n = flag ? 1 : 0;
|
|
}
|
|
|
|
// Set the Overflow flag
|
|
INLINE void setv(unsigned int flag)
|
|
{
|
|
p.f_v = flag ? 1 : 0;
|
|
}
|
|
|
|
// Set the decimal flag
|
|
INLINE void setd(unsigned int flag)
|
|
{
|
|
p.f_d = flag ? 1 : 0;
|
|
}
|
|
|
|
// Set the Interrupt Disable flag
|
|
INLINE void seti(unsigned int flag)
|
|
{
|
|
p.f_i = flag ? 1 : 0;
|
|
}
|
|
|
|
// Set the Zero flag
|
|
INLINE void setz(unsigned int flag)
|
|
{
|
|
p.f_z = flag ? 1 : 0;
|
|
}
|
|
|
|
// Set the Carry flag
|
|
INLINE void setc(unsigned int flag)
|
|
{
|
|
p.f_c = flag ? 1 : 0;
|
|
}
|
|
|
|
// Set the Negative and Zero flags from a byte value
|
|
INLINE void setnz_b(Byte value)
|
|
{
|
|
setn(value & 0x80);
|
|
setz(value == 0);
|
|
}
|
|
|
|
// Set the Negative and Zero flags from a word value
|
|
INLINE void setnz_w(Word value)
|
|
{
|
|
setn(value & 0x8000);
|
|
setz(value == 0);
|
|
}
|
|
|
|
INLINE void op_adc(Addr ea)
|
|
{
|
|
TRACE("ADC");
|
|
|
|
if (e || p.f_m) {
|
|
Byte data = mem.getByte(ea);
|
|
Word temp = a.b + data + p.f_c;
|
|
|
|
setc(temp & 0x100);
|
|
setv((~(a.b ^ data)) & (a.b ^ temp) & 0x80);
|
|
setnz_b(a.b = lo(temp));
|
|
}
|
|
else {
|
|
Word data = mem.getWord(ea);
|
|
int temp = a.w + data + p.f_c;
|
|
|
|
setc(temp & 0x100);
|
|
setv((~(a.w ^ data)) & (a.w ^ temp) & 0x8000);
|
|
setnz_w(a.w = (Word)temp);
|
|
}
|
|
}
|
|
|
|
INLINE void op_and(Addr ea)
|
|
{
|
|
TRACE("AND");
|
|
|
|
if (e || p.f_m)
|
|
setnz_b(a.b &= mem.getByte(ea));
|
|
else
|
|
setnz_w(a.w &= mem.getWord(ea));
|
|
}
|
|
|
|
INLINE void op_asl(Addr ea)
|
|
{
|
|
TRACE("ASL");
|
|
|
|
if (e || p.f_m) {
|
|
register Byte data = mem.getByte(ea);
|
|
|
|
setc(data & 0x80);
|
|
setnz_b(data <<= 1);
|
|
mem.setByte(ea, data);
|
|
}
|
|
else {
|
|
register Word data = mem.getWord(ea);
|
|
|
|
setc(data & 0x8000);
|
|
setnz_w(data <<= 1);
|
|
mem.setWord(ea, data);
|
|
}
|
|
}
|
|
|
|
INLINE void op_asla(Addr ea)
|
|
{
|
|
TRACE("ASL");
|
|
|
|
if (e || p.f_m) {
|
|
setc(a.b & 0x80);
|
|
setnz_b(a.b <<= 1);
|
|
mem.setByte(ea, a.b);
|
|
}
|
|
else {
|
|
setc(a.w & 0x8000);
|
|
setnz_w(a.w <<= 1);
|
|
mem.setWord(ea, a.w);
|
|
}
|
|
}
|
|
|
|
INLINE void op_bcc(Addr ea)
|
|
{
|
|
TRACE("BCC");
|
|
|
|
if (p.f_c == 0)
|
|
pc = (Word)ea;
|
|
}
|
|
|
|
INLINE void op_bcs(Addr ea)
|
|
{
|
|
TRACE("BCS");
|
|
|
|
if (p.f_c == 1)
|
|
pc = (Word)ea;
|
|
}
|
|
|
|
INLINE void op_beq(Addr ea)
|
|
{
|
|
TRACE("BEQ");
|
|
|
|
if (p.f_z == 1)
|
|
pc = (Word)ea;
|
|
}
|
|
|
|
INLINE void op_bit(Addr ea)
|
|
{
|
|
TRACE("BIT");
|
|
|
|
if (e || p.f_m) {
|
|
register Byte data = mem.getByte(ea);
|
|
|
|
setz((a.b & data) == 0);
|
|
setn(data & 0x80);
|
|
setv(data & 0x40);
|
|
}
|
|
else {
|
|
register Word data = mem.getWord(ea);
|
|
|
|
setz((a.w & data) == 0);
|
|
setn(data & 0x8000);
|
|
setv(data & 0x4000);
|
|
}
|
|
}
|
|
|
|
INLINE void op_biti(Addr ea)
|
|
{
|
|
TRACE("BIT");
|
|
|
|
if (e || p.f_m) {
|
|
register Byte data = mem.getByte(ea);
|
|
|
|
setz((a.b & data) == 0);
|
|
}
|
|
else {
|
|
register Word data = mem.getWord(ea);
|
|
|
|
setz((a.w & data) == 0);
|
|
}
|
|
}
|
|
|
|
INLINE void op_bmi(Addr ea)
|
|
{
|
|
TRACE("BMI");
|
|
|
|
if (p.f_n == 1)
|
|
pc = (Word)ea;
|
|
}
|
|
|
|
INLINE void op_bne(Addr ea)
|
|
{
|
|
TRACE("BNE");
|
|
|
|
if (p.f_z == 0)
|
|
pc = (Word)ea;
|
|
}
|
|
|
|
INLINE void op_bpl(Addr ea)
|
|
{
|
|
TRACE("BPL");
|
|
|
|
if (p.f_n == 0)
|
|
pc = (Word)ea;
|
|
}
|
|
|
|
INLINE void op_bra(Addr ea)
|
|
{
|
|
TRACE("BRA");
|
|
|
|
pc = (Word)ea;
|
|
}
|
|
|
|
INLINE void op_brk(Addr ea)
|
|
{
|
|
TRACE("BRK");
|
|
|
|
if (e) {
|
|
pushWord(pc);
|
|
pushByte(p.b | 0x10);
|
|
|
|
p.f_i = 1;
|
|
p.f_d = 0;
|
|
pbr = 0;
|
|
|
|
pc = mem.getWord(0xfffe);
|
|
}
|
|
else {
|
|
pushByte(pbr);
|
|
pushWord(pc);
|
|
pushByte(p.b);
|
|
|
|
p.f_i = 1;
|
|
p.f_d = 0;
|
|
pbr = 0;
|
|
|
|
pc = mem.getWord(0xffe6);
|
|
}
|
|
}
|
|
|
|
INLINE void op_brl(Addr ea)
|
|
{
|
|
TRACE("BRL");
|
|
|
|
pc = (Word)ea;
|
|
}
|
|
|
|
INLINE void op_bvc(Addr ea)
|
|
{
|
|
TRACE("BVC");
|
|
|
|
if (p.f_v == 0)
|
|
pc = (Word)ea;
|
|
}
|
|
|
|
INLINE void op_bvs(Addr ea)
|
|
{
|
|
TRACE("BVS");
|
|
|
|
if (p.f_v == 1)
|
|
pc = (Word)ea;
|
|
}
|
|
|
|
INLINE void op_clc(Addr ea)
|
|
{
|
|
TRACE("CLC");
|
|
|
|
setc(0);
|
|
}
|
|
|
|
INLINE void op_cld(Addr ea)
|
|
{
|
|
TRACE("CLD")
|
|
|
|
setd(0);
|
|
}
|
|
|
|
INLINE void op_cli(Addr ea)
|
|
{
|
|
TRACE("CLI")
|
|
|
|
seti(0);
|
|
}
|
|
|
|
INLINE void op_clv(Addr ea)
|
|
{
|
|
TRACE("CLD")
|
|
|
|
setv(0);
|
|
}
|
|
|
|
INLINE void op_cmp(Addr ea)
|
|
{
|
|
TRACE("CMP");
|
|
|
|
if (e || p.f_m) {
|
|
Byte data = mem.getByte(ea);
|
|
Word temp = a.b - data;
|
|
|
|
setc(temp & 0x100);
|
|
setnz_b(lo(temp));
|
|
}
|
|
else {
|
|
Word data = mem.getWord(ea);
|
|
Addr temp = a.w - data;
|
|
|
|
setc(temp & 0x10000L);
|
|
setnz_w((Word)temp);
|
|
}
|
|
}
|
|
|
|
INLINE void op_cop(Addr ea)
|
|
{
|
|
TRACE("COP");
|
|
|
|
if (e) {
|
|
pushWord(pc);
|
|
pushByte(p.b);
|
|
|
|
p.f_i = 1;
|
|
p.f_d = 0;
|
|
pbr = 0;
|
|
|
|
pc = mem.getWord(0xfff4);
|
|
}
|
|
else {
|
|
pushByte(pbr);
|
|
pushWord(pc);
|
|
pushByte(p.b);
|
|
|
|
p.f_i = 1;
|
|
p.f_d = 0;
|
|
pbr = 0;
|
|
|
|
pc = mem.getWord(0xffe4);
|
|
}
|
|
}
|
|
|
|
INLINE void op_cpx(Addr ea)
|
|
{
|
|
TRACE("CPX");
|
|
|
|
if (e || p.f_x) {
|
|
Byte data = mem.getByte(ea);
|
|
setnz_b(x.b - data);
|
|
setc(x.b >= data);
|
|
}
|
|
else {
|
|
Word data = mem.getWord(ea);
|
|
setnz_w(x.w - data);
|
|
setc(x.w >= data);
|
|
}
|
|
}
|
|
|
|
INLINE void op_cpy(Addr ea)
|
|
{
|
|
TRACE("CPY");
|
|
|
|
if (e || p.f_x) {
|
|
Byte data = mem.getByte(ea);
|
|
setnz_b(y.b - data);
|
|
setc(y.b >= data);
|
|
}
|
|
else {
|
|
Word data = mem.getWord(ea);
|
|
setnz_w(y.w - data);
|
|
setc(y.w >= data);
|
|
}
|
|
}
|
|
|
|
INLINE void op_dec(Addr ea)
|
|
{
|
|
TRACE("DEC");
|
|
|
|
if (e || p.f_m) {
|
|
register Byte data = mem.getByte(ea);
|
|
|
|
mem.setByte(ea, ++data);
|
|
setnz_b(data);
|
|
}
|
|
else {
|
|
register Word data = mem.getWord(ea);
|
|
|
|
mem.setWord(ea, ++data);
|
|
setnz_w(data);
|
|
}
|
|
}
|
|
|
|
INLINE void op_deca(Addr ea)
|
|
{
|
|
TRACE("DEC");
|
|
|
|
if (e || p.f_m)
|
|
setnz_b(--a.b);
|
|
else
|
|
setnz_w(--a.w);
|
|
}
|
|
|
|
INLINE void op_dex(Addr ea)
|
|
{
|
|
TRACE("DEX");
|
|
|
|
if (e || p.f_x)
|
|
setnz_b(x.b -= 1);
|
|
else
|
|
setnz_w(x.w -= 1);
|
|
}
|
|
|
|
INLINE void op_dey(Addr ea)
|
|
{
|
|
TRACE("DEY");
|
|
|
|
if (e || p.f_x)
|
|
setnz_b(y.b -= 1);
|
|
else
|
|
setnz_w(y.w -= 1);
|
|
}
|
|
|
|
INLINE void op_eor(Addr ea)
|
|
{
|
|
TRACE("EOR");
|
|
|
|
if (e || p.f_m)
|
|
setnz_b(a.b ^= mem.getByte(ea));
|
|
else
|
|
setnz_w(a.w ^= mem.getWord(ea));
|
|
}
|
|
|
|
INLINE void op_inc(Addr ea)
|
|
{
|
|
TRACE("INC");
|
|
|
|
if (e || p.f_m) {
|
|
register Byte data = mem.getByte(ea);
|
|
|
|
mem.setByte(ea, ++data);
|
|
setnz_b(data);
|
|
}
|
|
else {
|
|
register Word data = mem.getWord(ea);
|
|
|
|
mem.setWord(ea, ++data);
|
|
setnz_w(data);
|
|
}
|
|
}
|
|
|
|
INLINE void op_inca(Addr ea)
|
|
{
|
|
TRACE("INC");
|
|
|
|
if (e || p.f_m)
|
|
setnz_b(++a.b);
|
|
else
|
|
setnz_w(++a.w);
|
|
}
|
|
|
|
INLINE void op_inx(Addr ea)
|
|
{
|
|
TRACE("INX");
|
|
|
|
if (e || p.f_x)
|
|
setnz_b(++x.b);
|
|
else
|
|
setnz_w(++x.w);
|
|
}
|
|
|
|
INLINE void op_iny(Addr ea)
|
|
{
|
|
TRACE("INY");
|
|
|
|
if (e || p.f_x)
|
|
setnz_b(++y.b);
|
|
else
|
|
setnz_w(++y.w);
|
|
}
|
|
|
|
INLINE void op_jmp(Addr ea)
|
|
{
|
|
TRACE("JMP");
|
|
|
|
pbr = lo(ea >> 16);
|
|
pc = (Word)ea;
|
|
}
|
|
|
|
INLINE void op_jsl(Addr ea)
|
|
{
|
|
TRACE("JSL");
|
|
|
|
pushByte(pbr);
|
|
pushWord(pc - 1);
|
|
|
|
pbr = lo(ea >> 16);
|
|
pc = (Word)ea;
|
|
}
|
|
|
|
INLINE void op_jsr(Addr ea)
|
|
{
|
|
TRACE("JSR");
|
|
|
|
pushWord(pc - 1);
|
|
|
|
pc = (Word)ea;
|
|
}
|
|
|
|
INLINE void op_lda(Addr ea)
|
|
{
|
|
TRACE("LDA");
|
|
|
|
if (e || p.f_m)
|
|
setnz_b(a.b = mem.getByte(ea));
|
|
else
|
|
setnz_w(a.w = mem.getWord(ea));
|
|
}
|
|
|
|
INLINE void op_ldx(Addr ea)
|
|
{
|
|
TRACE("LDX");
|
|
|
|
if (e || p.f_x)
|
|
setnz_b(lo(x.w = mem.getByte(ea)));
|
|
else
|
|
setnz_w(x.w = mem.getWord(ea));
|
|
}
|
|
|
|
INLINE void op_ldy(Addr ea)
|
|
{
|
|
TRACE("LDY");
|
|
|
|
if (e || p.f_x)
|
|
setnz_b(lo(y.w = mem.getByte(ea)));
|
|
else
|
|
setnz_w(y.w = mem.getWord(ea));
|
|
}
|
|
|
|
INLINE void op_lsr(Addr ea)
|
|
{
|
|
TRACE("LSR");
|
|
|
|
if (e || p.f_m) {
|
|
register Byte data = mem.getByte(ea);
|
|
|
|
setc(data & 0x01);
|
|
setnz_b(data >>= 1);
|
|
mem.setByte(ea, data);
|
|
}
|
|
else {
|
|
register Word data = mem.getWord(ea);
|
|
|
|
setc(data & 0x0001);
|
|
setnz_w(data >>= 1);
|
|
mem.setWord(ea, data);
|
|
}
|
|
}
|
|
|
|
INLINE void op_lsra(Addr ea)
|
|
{
|
|
TRACE("LSR");
|
|
|
|
if (e || p.f_m) {
|
|
setc(a.b & 0x01);
|
|
setnz_b(a.b >>= 1);
|
|
mem.setByte(ea, a.b);
|
|
}
|
|
else {
|
|
setc(a.w & 0x0001);
|
|
setnz_w(a.w >>= 1);
|
|
mem.setWord(ea, a.w);
|
|
}
|
|
}
|
|
|
|
INLINE void op_mvn(Addr ea)
|
|
{
|
|
TRACE("MVN");
|
|
}
|
|
|
|
INLINE void op_mvp(Addr ea)
|
|
{
|
|
TRACE("MVP");
|
|
}
|
|
|
|
INLINE void op_nop(Addr ea)
|
|
{
|
|
TRACE("NOP");
|
|
}
|
|
|
|
INLINE void op_ora(Addr ea)
|
|
{
|
|
TRACE("ORA");
|
|
|
|
if (e || p.f_m)
|
|
setnz_b(a.b |= mem.getByte(ea));
|
|
else
|
|
setnz_w(a.w |= mem.getWord(ea));
|
|
}
|
|
|
|
INLINE void op_pea(Addr ea)
|
|
{
|
|
TRACE("PEA");
|
|
|
|
pushWord(mem.getWord(ea));
|
|
}
|
|
|
|
INLINE void op_pei(Addr ea)
|
|
{
|
|
TRACE("PEI");
|
|
}
|
|
|
|
INLINE void op_per(Addr ea)
|
|
{
|
|
TRACE("PER");
|
|
}
|
|
|
|
INLINE void op_pha(Addr ea)
|
|
{
|
|
TRACE("PHA");
|
|
|
|
if (e || p.f_m)
|
|
pushByte(a.b);
|
|
else
|
|
pushWord(a.w);
|
|
}
|
|
|
|
INLINE void op_phb(Addr ea)
|
|
{
|
|
TRACE("PHB");
|
|
|
|
pushByte(dbr);
|
|
}
|
|
|
|
INLINE void op_phd(Addr ea)
|
|
{
|
|
TRACE("PHD");
|
|
|
|
pushWord(dp.w);
|
|
}
|
|
|
|
INLINE void op_phk(Addr ea)
|
|
{
|
|
TRACE("PHK");
|
|
|
|
pushByte(pbr);
|
|
}
|
|
|
|
INLINE void op_php(Addr ea)
|
|
{
|
|
TRACE("PHP");
|
|
|
|
pushByte(p.b);
|
|
}
|
|
|
|
INLINE void op_phx(Addr ea)
|
|
{
|
|
TRACE("PHX");
|
|
|
|
if (e || p.f_x)
|
|
pushByte(x.b);
|
|
else
|
|
pushWord(x.w);
|
|
}
|
|
|
|
INLINE void op_phy(Addr ea)
|
|
{
|
|
TRACE("PHY");
|
|
|
|
if (e || p.f_x)
|
|
pushByte(y.b);
|
|
else
|
|
pushWord(y.w);
|
|
}
|
|
|
|
INLINE void op_pla(Addr ea)
|
|
{
|
|
TRACE("PLA");
|
|
|
|
if (e || p.f_m)
|
|
setnz_b(a.b = pullByte());
|
|
else
|
|
setnz_w(a.w = pullWord());
|
|
}
|
|
|
|
INLINE void op_plb(Addr ea)
|
|
{
|
|
TRACE("PLB");
|
|
|
|
setnz_b(dbr = pullByte());
|
|
}
|
|
|
|
INLINE void op_pld(Addr ea)
|
|
{
|
|
TRACE("PLD");
|
|
|
|
setnz_w(dp.w = pullWord());
|
|
}
|
|
|
|
INLINE void op_plk(Addr ea)
|
|
{
|
|
TRACE("PLK");
|
|
|
|
setnz_b(dbr = pullByte());
|
|
}
|
|
|
|
INLINE void op_plp(Addr ea)
|
|
{
|
|
TRACE("PLP");
|
|
|
|
if (e)
|
|
p.b = pullByte() | 0x30;
|
|
else {
|
|
p.b = pullByte();
|
|
|
|
if (p.f_x) {
|
|
x.w = x.b;
|
|
y.w = y.b;
|
|
}
|
|
}
|
|
}
|
|
|
|
INLINE void op_plx(Addr ea)
|
|
{
|
|
TRACE("PLX");
|
|
|
|
if (e || p.f_x)
|
|
setnz_b(lo(x.w = pullByte()));
|
|
else
|
|
setnz_w(x.w = pullWord());
|
|
}
|
|
|
|
INLINE void op_ply(Addr ea)
|
|
{
|
|
TRACE("PLY");
|
|
|
|
if (e || p.f_x)
|
|
setnz_b(lo(y.w = pullByte()));
|
|
else
|
|
setnz_w(y.w = pullWord());
|
|
}
|
|
|
|
INLINE void op_rep(Addr ea)
|
|
{
|
|
TRACE("REP");
|
|
|
|
p.b &= ~mem.getByte(ea);
|
|
if (e) p.f_m = p.f_x = 1;
|
|
}
|
|
|
|
INLINE void op_rol(Addr ea)
|
|
{
|
|
TRACE("ROL");
|
|
|
|
if (e || p.f_m) {
|
|
register Byte data = mem.getByte(ea);
|
|
register Byte carry = p.f_c ? 0x01 : 0x00;
|
|
|
|
setc(data & 0x80);
|
|
setnz_b(data = (data << 1) | carry);
|
|
mem.setByte(ea, data);
|
|
}
|
|
else {
|
|
register Word data = mem.getWord(ea);
|
|
register Word carry = p.f_c ? 0x0001 : 0x0000;
|
|
|
|
setc(data & 0x8000);
|
|
setnz_w(data = (data << 1) | carry);
|
|
mem.setWord(ea, data);
|
|
}
|
|
}
|
|
|
|
INLINE void op_rola(Addr ea)
|
|
{
|
|
TRACE("ROL");
|
|
|
|
if (e || p.f_m) {
|
|
register Byte carry = p.f_c ? 0x01 : 0x00;
|
|
|
|
setc(a.b & 0x80);
|
|
setnz_b(a.b = (a.b << 1) | carry);
|
|
mem.setByte(ea, a.b);
|
|
}
|
|
else {
|
|
register Word carry = p.f_c ? 0x0001 : 0x0000;
|
|
|
|
setc(a.w & 0x8000);
|
|
setnz_w(a.w = (a.w << 1) | carry);
|
|
mem.setWord(ea, a.w);
|
|
}
|
|
}
|
|
|
|
INLINE void op_ror(Addr ea)
|
|
{
|
|
TRACE("ROR");
|
|
|
|
if (e || p.f_m) {
|
|
register Byte data = mem.getByte(ea);
|
|
register Byte carry = p.f_c ? 0x80 : 0x00;
|
|
|
|
setc(data & 0x80);
|
|
setnz_b(data = (data >> 1) | carry);
|
|
mem.setByte(ea, data);
|
|
}
|
|
else {
|
|
register Word data = mem.getWord(ea);
|
|
register Word carry = p.f_c ? 0x8000 : 0x0000;
|
|
|
|
setc(data & 0x8000);
|
|
setnz_w(data = (data >> 1) | carry);
|
|
mem.setWord(ea, data);
|
|
}
|
|
}
|
|
|
|
INLINE void op_rora(Addr ea)
|
|
{
|
|
TRACE("ROR");
|
|
|
|
if (e || p.f_m) {
|
|
register Byte carry = p.f_c ? 0x80 : 0x00;
|
|
|
|
setc(a.b & 0x80);
|
|
setnz_b(a.b = (a.b >> 1) | carry);
|
|
mem.setByte(ea, a.b);
|
|
}
|
|
else {
|
|
register Word carry = p.f_c ? 0x8000 : 0x0000;
|
|
|
|
setc(a.w & 0x8000);
|
|
setnz_w(a.w = (a.w >> 1) | carry);
|
|
mem.setWord(ea, a.w);
|
|
}
|
|
}
|
|
|
|
INLINE void op_rtl(Addr ea)
|
|
{
|
|
TRACE("RTL");
|
|
|
|
pc = pullWord();
|
|
pbr = pullByte();
|
|
}
|
|
|
|
INLINE void op_rti(Addr ea)
|
|
{
|
|
TRACE("RTI");
|
|
|
|
if (e) {
|
|
p.b = pullByte();
|
|
pc = pullWord();
|
|
}
|
|
else {
|
|
p.b = pullByte();
|
|
pc = pullWord();
|
|
pbr = pullByte();
|
|
}
|
|
p.f_i = 0;
|
|
}
|
|
|
|
INLINE void op_rts(Addr ea)
|
|
{
|
|
TRACE("RTS");
|
|
|
|
pc = pullWord() + 1;
|
|
}
|
|
|
|
INLINE void op_sbc(Addr ea)
|
|
{
|
|
TRACE("SBC");
|
|
|
|
if (e || p.f_m) {
|
|
Byte data = ~mem.getByte(ea);
|
|
Word temp = a.b + data + p.f_c;
|
|
|
|
setc(temp & 0x100);
|
|
setv((~(a.b ^ data)) & (a.b ^ temp) & 0x80);
|
|
setnz_b(a.b = lo(temp));
|
|
}
|
|
else {
|
|
Word data = ~mem.getWord(ea);
|
|
int temp = a.w + data + p.f_c;
|
|
|
|
setc(temp & 0x100);
|
|
setv((~(a.w ^ data)) & (a.w ^ temp) & 0x8000);
|
|
setnz_w(a.w = (Word)temp);
|
|
}
|
|
}
|
|
|
|
INLINE void op_sec(Addr ea)
|
|
{
|
|
TRACE("SEC");
|
|
|
|
setc(1);
|
|
}
|
|
|
|
INLINE void op_sed(Addr ea)
|
|
{
|
|
TRACE("SED");
|
|
|
|
setd(1);
|
|
}
|
|
|
|
INLINE void op_sei(Addr ea)
|
|
{
|
|
TRACE("SEI");
|
|
|
|
seti(1);
|
|
}
|
|
|
|
INLINE void op_sep(Addr ea)
|
|
{
|
|
TRACE("SEP");
|
|
|
|
p.b |= mem.getByte(ea);
|
|
if (e) p.f_m = p.f_x = 1;
|
|
|
|
if (p.f_x) {
|
|
x.w = x.b;
|
|
y.w = y.b;
|
|
}
|
|
}
|
|
|
|
INLINE void op_sta(Addr ea)
|
|
{
|
|
TRACE("STA");
|
|
|
|
if (e || p.f_m)
|
|
mem.setByte(ea, a.b);
|
|
else
|
|
mem.setWord(ea, a.w);
|
|
}
|
|
|
|
INLINE void op_stp(Addr ea)
|
|
{
|
|
TRACE("STP");
|
|
|
|
if (!interrupted) {
|
|
pc -= 1;
|
|
}
|
|
else
|
|
interrupted = false;
|
|
}
|
|
|
|
INLINE void op_stx(Addr ea)
|
|
{
|
|
TRACE("STX");
|
|
|
|
if (e || p.f_x)
|
|
mem.setByte(ea, x.b);
|
|
else
|
|
mem.setWord(ea, x.w);
|
|
}
|
|
|
|
INLINE void op_sty(Addr ea)
|
|
{
|
|
TRACE("STY");
|
|
|
|
if (e || p.f_x)
|
|
mem.setByte(ea, y.b);
|
|
else
|
|
mem.setWord(ea, y.w);
|
|
}
|
|
|
|
INLINE void op_stz(Addr ea)
|
|
{
|
|
TRACE("STZ");
|
|
|
|
if (e || p.f_m)
|
|
mem.setByte(ea, 0);
|
|
else
|
|
mem.setWord(ea, 0);
|
|
}
|
|
|
|
INLINE void op_tax(Addr ea)
|
|
{
|
|
TRACE("TAX");
|
|
|
|
if (e || p.f_x)
|
|
setnz_b(lo(x.w = a.b));
|
|
else
|
|
setnz_w(x.w = a.w);
|
|
}
|
|
|
|
INLINE void op_tay(Addr ea)
|
|
{
|
|
TRACE("TAY");
|
|
|
|
if (e || p.f_x)
|
|
setnz_b(lo(y.w = a.b));
|
|
else
|
|
setnz_w(y.w = a.w);
|
|
}
|
|
|
|
INLINE void op_tcd(Addr ea)
|
|
{
|
|
TRACE("TCD");
|
|
|
|
dp.w = a.w;
|
|
}
|
|
|
|
INLINE void op_tdc(Addr ea)
|
|
{
|
|
TRACE("TDC");
|
|
|
|
if (e || p.f_m)
|
|
setnz_b(lo(a.w = dp.w));
|
|
else
|
|
setnz_w(a.w = dp.w);
|
|
}
|
|
|
|
INLINE void op_tcs(Addr ea)
|
|
{
|
|
TRACE("TCS");
|
|
|
|
sp.w = e ? (0x0100 | a.b) : a.w;
|
|
}
|
|
|
|
INLINE void op_trb(Addr ea)
|
|
{
|
|
TRACE("TRB");
|
|
|
|
if (e || p.f_m) {
|
|
register Byte data = mem.getByte(ea);
|
|
|
|
mem.setByte(ea, data & ~a.b);
|
|
setz((a.b & data) == 0);
|
|
}
|
|
else {
|
|
register Word data = mem.getWord(ea);
|
|
|
|
mem.setWord(ea, data & ~a.w);
|
|
setz((a.w & data) == 0);
|
|
}
|
|
}
|
|
|
|
INLINE void op_tsb(Addr ea)
|
|
{
|
|
TRACE("TSB");
|
|
|
|
if (e || p.f_m) {
|
|
register Byte data = mem.getByte(ea);
|
|
|
|
mem.setByte(ea, data | a.b);
|
|
setz((a.b & data) == 0);
|
|
}
|
|
else {
|
|
register Word data = mem.getWord(ea);
|
|
|
|
mem.setWord(ea, data | a.w);
|
|
setz((a.w & data) == 0);
|
|
}
|
|
}
|
|
|
|
INLINE void op_tsc(Addr ea)
|
|
{
|
|
TRACE("TSC");
|
|
|
|
if (e || p.f_m)
|
|
setnz_b(lo(a.w = sp.w));
|
|
else
|
|
setnz_w(a.w = sp.w);
|
|
}
|
|
|
|
INLINE void op_tsx(Addr ea)
|
|
{
|
|
TRACE("TSX");
|
|
}
|
|
|
|
INLINE void op_txa(Addr ea)
|
|
{
|
|
TRACE("TXA");
|
|
}
|
|
|
|
INLINE void op_txs(Addr ea)
|
|
{
|
|
TRACE("TXS");
|
|
}
|
|
|
|
INLINE void op_txy(Addr ea)
|
|
{
|
|
TRACE("TXY");
|
|
|
|
if (e || p.f_x)
|
|
setnz_b(lo(y.w = x.w));
|
|
else
|
|
setnz_w(y.w = x.w);
|
|
}
|
|
|
|
INLINE void op_tya(Addr ea)
|
|
{
|
|
TRACE("TYA");
|
|
|
|
if (e || p.f_m)
|
|
setnz_b(a.b = y.b);
|
|
else
|
|
setnz_w(a.w = p.f_x ? y.b : y.w);
|
|
}
|
|
|
|
INLINE void op_tyx(Addr ea)
|
|
{
|
|
TRACE("TYX");
|
|
|
|
if (e || p.f_x)
|
|
setnz_b(lo(x.w = y.w));
|
|
else
|
|
setnz_w(x.w = y.w);
|
|
}
|
|
|
|
INLINE void op_wai(Addr ea)
|
|
{
|
|
TRACE("WAI");
|
|
|
|
if (!interrupted) {
|
|
pc -= 1;
|
|
}
|
|
else
|
|
interrupted = false;
|
|
}
|
|
|
|
INLINE void op_wdm(Addr ea)
|
|
{
|
|
TRACE("WDM");
|
|
|
|
switch (mem.getByte(ea)) {
|
|
case 0xff: exit(0);
|
|
}
|
|
}
|
|
|
|
INLINE void op_xba(Addr ea)
|
|
{
|
|
TRACE("XBA");
|
|
|
|
a.w = swap(a.w);
|
|
setnz_b(a.b);
|
|
}
|
|
|
|
INLINE void op_xce(Addr ea)
|
|
{
|
|
TRACE("XCE");
|
|
|
|
unsigned char oe = e;
|
|
|
|
e = p.f_c;
|
|
p.f_c = oe;
|
|
|
|
if (e) {
|
|
sp.w = 0x0100 | sp.b;
|
|
dp.w = 0x0000;
|
|
}
|
|
}
|
|
};
|
|
#endif
|