1
0
mirror of https://github.com/dschmenk/PLASMA.git synced 2025-04-07 16:41:59 +00:00

Prep plvm.c for 6502 emulation

This commit is contained in:
David Schmenk 2024-08-07 19:32:26 -07:00
parent c5824ed632
commit 867e282a36
27 changed files with 1307 additions and 1041 deletions

View File

@ -1,896 +0,0 @@
/* lib6502.c -- MOS Technology 6502 emulator -*- C -*- */
/* Copyright (c) 2005 Ian Piumarta
*
* All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the 'Software'),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, provided that the above copyright notice(s) and this
* permission notice appear in all copies of the Software and that both the
* above copyright notice(s) and this permission notice appear in supporting
* documentation.
*
* THE SOFTWARE IS PROVIDED 'AS IS'. USE ENTIRELY AT YOUR OWN RISK.
*/
/* Last edited: 2013-06-07 23:03:39 by piumarta on emilia.local
*
* BUGS:
* - RTS and RTI do not check the return address for a callback
* - the disassembler cannot be configured to read two bytes for BRK
* - architectural variations (unimplemented/extended instructions) not implemented
* - ANSI versions (from from gcc extensions) of the dispatch macros are missing
* - emulator+disassembler in same object file (library is kind of pointless)
*/
#include <stdio.h>
#include <stdlib.h>
#include "lib6502.h"
typedef uint8_t byte;
typedef uint16_t word;
enum {
flagN= (1<<7), /* negative */
flagV= (1<<6), /* overflow */
flagX= (1<<5), /* unused */
flagB= (1<<4), /* irq from brk */
flagD= (1<<3), /* decimal mode */
flagI= (1<<2), /* irq disable */
flagZ= (1<<1), /* zero */
flagC= (1<<0) /* carry */
};
#define getN() (P & flagN)
#define getV() (P & flagV)
#define getB() (P & flagB)
#define getD() (P & flagD)
#define getI() (P & flagI)
#define getZ() (P & flagZ)
#define getC() (P & flagC)
#define setNVZC(N,V,Z,C) (P= (P & ~(flagN | flagV | flagZ | flagC)) | (N) | ((V)<<6) | ((Z)<<1) | (C))
#define setNZC(N,Z,C) (P= (P & ~(flagN | flagZ | flagC)) | (N) | ((Z)<<1) | (C))
#define setNZ(N,Z) (P= (P & ~(flagN | flagZ )) | (N) | ((Z)<<1) )
#define setZ(Z) (P= (P & ~( flagZ )) | ((Z)<<1) )
#define setC(C) (P= (P & ~( flagC)) | (C))
#define NAND(P, Q) (!((P) & (Q)))
#define tick(n)
#define tickIf(p)
/* memory access (indirect if callback installed) -- ARGUMENTS ARE EVALUATED MORE THAN ONCE! */
#define putMemory(ADDR, BYTE) \
( writeCallback[ADDR] \
? writeCallback[ADDR](mpu, ADDR, BYTE) \
: (memory[ADDR]= BYTE) )
#define getMemory(ADDR) \
( readCallback[ADDR] \
? readCallback[ADDR](mpu, ADDR, 0) \
: memory[ADDR] )
/* stack access (always direct) */
#define push(BYTE) (memory[0x0100 + S--]= (BYTE))
#define pop() (memory[++S + 0x0100])
/* adressing modes (memory access direct) */
#define implied(ticks) \
tick(ticks);
#define immediate(ticks) \
tick(ticks); \
ea= PC++;
#define abs(ticks) \
tick(ticks); \
ea= memory[PC] + (memory[PC + 1] << 8); \
PC += 2;
#define relative(ticks) \
tick(ticks); \
ea= memory[PC++]; \
if (ea & 0x80) ea -= 0x100; \
tickIf((ea >> 8) != (PC >> 8));
#define indirect(ticks) \
tick(ticks); \
{ \
word tmp; \
tmp= memory[PC] + (memory[PC + 1] << 8); \
ea = memory[tmp] + (memory[tmp + 1] << 8); \
PC += 2; \
}
#define absx(ticks) \
tick(ticks); \
ea= memory[PC] + (memory[PC + 1] << 8); \
PC += 2; \
tickIf((ticks == 4) && ((ea >> 8) != ((ea + X) >> 8))); \
ea += X;
#define absy(ticks) \
tick(ticks); \
ea= memory[PC] + (memory[PC + 1] << 8); \
PC += 2; \
tickIf((ticks == 4) && ((ea >> 8) != ((ea + Y) >> 8))); \
ea += Y
#define zp(ticks) \
tick(ticks); \
ea= memory[PC++];
#define zpx(ticks) \
tick(ticks); \
ea= memory[PC++] + X; \
ea &= 0x00ff;
#define zpy(ticks) \
tick(ticks); \
ea= memory[PC++] + Y; \
ea &= 0x00ff;
#define indx(ticks) \
tick(ticks); \
{ \
byte tmp= memory[PC++] + X; \
ea= memory[tmp] + (memory[tmp + 1] << 8); \
}
#define indy(ticks) \
tick(ticks); \
{ \
byte tmp= memory[PC++]; \
ea= memory[tmp] + (memory[tmp + 1] << 8); \
tickIf((ticks == 5) && ((ea >> 8) != ((ea + Y) >> 8))); \
ea += Y; \
}
#define indabsx(ticks) \
tick(ticks); \
{ \
word tmp; \
tmp= memory[PC ] + (memory[PC + 1] << 8) + X; \
ea = memory[tmp] + (memory[tmp + 1] << 8); \
}
#define indzp(ticks) \
tick(ticks); \
{ \
byte tmp; \
tmp= memory[PC++]; \
ea = memory[tmp] + (memory[tmp + 1] << 8); \
}
/* insns */
#define adc(ticks, adrmode) \
adrmode(ticks); \
{ \
byte B= getMemory(ea); \
if (!getD()) \
{ \
int c= A + B + getC(); \
int v= (int8_t)A + (int8_t)B + getC(); \
fetch(); \
A= c; \
setNVZC((A & 0x80), (((A & 0x80) > 0) ^ (v < 0)), (A == 0), ((c & 0x100) > 0)); \
next(); \
} \
else \
{ \
int l, h, s; \
/* inelegant & slow, but consistent with the hw for illegal digits */ \
l= (A & 0x0F) + (B & 0x0F) + getC(); \
h= (A & 0xF0) + (B & 0xF0); \
if (l >= 0x0A) { l -= 0x0A; h += 0x10; } \
if (h >= 0xA0) { h -= 0xA0; } \
fetch(); \
s= h | (l & 0x0F); \
/* only C is valid on NMOS 6502 */ \
setNVZC(s & 0x80, !(((A ^ B) & 0x80) && ((A ^ s) & 0x80)), !s, !!(h & 0x80)); \
A= s; \
tick(1); \
next(); \
} \
}
#define sbc(ticks, adrmode) \
adrmode(ticks); \
{ \
byte B= getMemory(ea); \
if (!getD()) \
{ \
int b= 1 - (P &0x01); \
int c= A - B - b; \
int v= (int8_t)A - (int8_t) B - b; \
fetch(); \
A= c; \
setNVZC(A & 0x80, ((A & 0x80) > 0) ^ ((v & 0x100) != 0), A == 0, c >= 0); \
next(); \
} \
else \
{ \
/* this is verbatim ADC, with a 10's complemented operand */ \
int l, h, s; \
B= 0x99 - B; \
l= (A & 0x0F) + (B & 0x0F) + getC(); \
h= (A & 0xF0) + (B & 0xF0); \
if (l >= 0x0A) { l -= 0x0A; h += 0x10; } \
if (h >= 0xA0) { h -= 0xA0; } \
fetch(); \
s= h | (l & 0x0F); \
/* only C is valid on NMOS 6502 */ \
setNVZC(s & 0x80, !(((A ^ B) & 0x80) && ((A ^ s) & 0x80)), !s, !!(h & 0x80)); \
A= s; \
tick(1); \
next(); \
} \
}
#define cmpR(ticks, adrmode, R) \
adrmode(ticks); \
fetch(); \
{ \
byte B= getMemory(ea); \
byte d= R - B; \
setNZC(d & 0x80, !d, R >= B); \
} \
next();
#define cmp(ticks, adrmode) cmpR(ticks, adrmode, A)
#define cpx(ticks, adrmode) cmpR(ticks, adrmode, X)
#define cpy(ticks, adrmode) cmpR(ticks, adrmode, Y)
#define dec(ticks, adrmode) \
adrmode(ticks); \
fetch(); \
{ \
byte B= getMemory(ea); \
--B; \
putMemory(ea, B); \
setNZ(B & 0x80, !B); \
} \
next();
#define decR(ticks, adrmode, R) \
fetch(); \
tick(ticks); \
--R; \
setNZ(R & 0x80, !R); \
next();
#define dea(ticks, adrmode) decR(ticks, adrmode, A)
#define dex(ticks, adrmode) decR(ticks, adrmode, X)
#define dey(ticks, adrmode) decR(ticks, adrmode, Y)
#define inc(ticks, adrmode) \
adrmode(ticks); \
fetch(); \
{ \
byte B= getMemory(ea); \
++B; \
putMemory(ea, B); \
setNZ(B & 0x80, !B); \
} \
next();
#define incR(ticks, adrmode, R) \
fetch(); \
tick(ticks); \
++R; \
setNZ(R & 0x80, !R); \
next();
#define ina(ticks, adrmode) incR(ticks, adrmode, A)
#define inx(ticks, adrmode) incR(ticks, adrmode, X)
#define iny(ticks, adrmode) incR(ticks, adrmode, Y)
#define bit(ticks, adrmode) \
adrmode(ticks); \
fetch(); \
{ \
byte B= getMemory(ea); \
P= (P & ~(flagN | flagV | flagZ)) \
| (B & (0xC0)) | (((A & B) == 0) << 1); \
} \
next();
#define tsb(ticks, adrmode) \
adrmode(ticks); \
fetch(); \
{ \
byte b= getMemory(ea); \
b |= A; \
putMemory(ea, b); \
setZ(!b); \
} \
next();
#define trb(ticks, adrmode) \
adrmode(ticks); \
fetch(); \
{ \
byte b= getMemory(ea); \
b |= (A ^ 0xFF); \
putMemory(ea, b); \
setZ(!b); \
} \
next();
#define bitwise(ticks, adrmode, op) \
adrmode(ticks); \
fetch(); \
A op##= getMemory(ea); \
setNZ(A & 0x80, !A); \
next();
#define and(ticks, adrmode) bitwise(ticks, adrmode, &)
#define eor(ticks, adrmode) bitwise(ticks, adrmode, ^)
#define ora(ticks, adrmode) bitwise(ticks, adrmode, |)
#define asl(ticks, adrmode) \
adrmode(ticks); \
{ \
unsigned int i= getMemory(ea) << 1; \
putMemory(ea, i); \
fetch(); \
setNZC(i & 0x80, !i, i >> 8); \
} \
next();
#define asla(ticks, adrmode) \
tick(ticks); \
fetch(); \
{ \
int c= A >> 7; \
A <<= 1; \
setNZC(A & 0x80, !A, c); \
} \
next();
#define lsr(ticks, adrmode) \
adrmode(ticks); \
{ \
byte b= getMemory(ea); \
int c= b & 1; \
fetch(); \
b >>= 1; \
putMemory(ea, b); \
setNZC(0, !b, c); \
} \
next();
#define lsra(ticks, adrmode) \
tick(ticks); \
fetch(); \
{ \
int c= A & 1; \
A >>= 1; \
setNZC(0, !A, c); \
} \
next();
#define rol(ticks, adrmode) \
adrmode(ticks); \
{ \
word b= (getMemory(ea) << 1) | getC(); \
fetch(); \
putMemory(ea, b); \
setNZC(b & 0x80, !(b & 0xFF), b >> 8); \
} \
next();
#define rola(ticks, adrmode) \
tick(ticks); \
fetch(); \
{ \
word b= (A << 1) | getC(); \
A= b; \
setNZC(A & 0x80, !A, b >> 8); \
} \
next();
#define ror(ticks, adrmode) \
adrmode(ticks); \
{ \
int c= getC(); \
byte m= getMemory(ea); \
byte b= (c << 7) | (m >> 1); \
fetch(); \
putMemory(ea, b); \
setNZC(b & 0x80, !b, m & 1); \
} \
next();
#define rora(ticks, adrmode) \
adrmode(ticks); \
{ \
int ci= getC(); \
int co= A & 1; \
fetch(); \
A= (ci << 7) | (A >> 1); \
setNZC(A & 0x80, !A, co); \
} \
next();
#define tRS(ticks, adrmode, R, S) \
fetch(); \
tick(ticks); \
S= R; \
setNZ(S & 0x80, !S); \
next();
#define tax(ticks, adrmode) tRS(ticks, adrmode, A, X)
#define txa(ticks, adrmode) tRS(ticks, adrmode, X, A)
#define tay(ticks, adrmode) tRS(ticks, adrmode, A, Y)
#define tya(ticks, adrmode) tRS(ticks, adrmode, Y, A)
#define tsx(ticks, adrmode) tRS(ticks, adrmode, S, X)
#define txs(ticks, adrmode) \
fetch(); \
tick(ticks); \
S= X; \
next();
#define ldR(ticks, adrmode, R) \
adrmode(ticks); \
fetch(); \
R= getMemory(ea); \
setNZ(R & 0x80, !R); \
next();
#define lda(ticks, adrmode) ldR(ticks, adrmode, A)
#define ldx(ticks, adrmode) ldR(ticks, adrmode, X)
#define ldy(ticks, adrmode) ldR(ticks, adrmode, Y)
#define stR(ticks, adrmode, R) \
adrmode(ticks); \
fetch(); \
putMemory(ea, R); \
next();
#define sta(ticks, adrmode) stR(ticks, adrmode, A)
#define stx(ticks, adrmode) stR(ticks, adrmode, X)
#define sty(ticks, adrmode) stR(ticks, adrmode, Y)
#define stz(ticks, adrmode) stR(ticks, adrmode, 0)
#define branch(ticks, adrmode, cond) \
if (cond) \
{ \
adrmode(ticks); \
PC += ea; \
tick(1); \
} \
else \
{ \
tick(ticks); \
PC++; \
} \
fetch(); \
next();
#define bcc(ticks, adrmode) branch(ticks, adrmode, !getC())
#define bcs(ticks, adrmode) branch(ticks, adrmode, getC())
#define bne(ticks, adrmode) branch(ticks, adrmode, !getZ())
#define beq(ticks, adrmode) branch(ticks, adrmode, getZ())
#define bpl(ticks, adrmode) branch(ticks, adrmode, !getN())
#define bmi(ticks, adrmode) branch(ticks, adrmode, getN())
#define bvc(ticks, adrmode) branch(ticks, adrmode, !getV())
#define bvs(ticks, adrmode) branch(ticks, adrmode, getV())
#define bra(ticks, adrmode) \
adrmode(ticks); \
PC += ea; \
fetch(); \
tick(1); \
next();
#define jmp(ticks, adrmode) \
adrmode(ticks); \
PC= ea; \
if (mpu->callbacks->call[ea]) \
{ \
word addr; \
externalise(); \
if ((addr= mpu->callbacks->call[ea](mpu, ea, 0))) \
{ \
internalise(); \
PC= addr; \
} \
} \
fetch(); \
next();
#define jsr(ticks, adrmode) \
PC++; \
push(PC >> 8); \
push(PC & 0xff); \
PC--; \
adrmode(ticks); \
if (mpu->callbacks->call[ea]) \
{ \
word addr; \
externalise(); \
if ((addr= mpu->callbacks->call[ea](mpu, ea, 0))) \
{ \
internalise(); \
PC= addr; \
fetch(); \
next(); \
} \
} \
PC=ea; \
fetch(); \
next();
#define rts(ticks, adrmode) \
tick(ticks); \
PC = pop(); \
PC |= (pop() << 8); \
PC++; \
fetch(); \
next();
#define brk(ticks, adrmode) \
tick(ticks); \
PC++; \
push(PC >> 8); \
push(PC & 0xff); \
P |= flagB; \
push(P | flagX); \
P |= flagI; \
{ \
word hdlr= getMemory(0xfffe) + (getMemory(0xffff) << 8); \
if (mpu->callbacks->call[hdlr]) \
{ \
word addr; \
externalise(); \
if ((addr= mpu->callbacks->call[hdlr](mpu, PC - 2, 0))) \
{ \
internalise(); \
hdlr= addr; \
} \
} \
PC= hdlr; \
} \
fetch(); \
next();
#define rti(ticks, adrmode) \
tick(ticks); \
P= pop(); \
PC= pop(); \
PC |= (pop() << 8); \
fetch(); \
next();
#define nop(ticks, adrmode) \
fetch(); \
tick(ticks); \
next();
#define ill(ticks, adrmode) \
fetch(); \
tick(ticks); \
fflush(stdout); \
fprintf(stderr, "\nundefined instruction %02X\n", memory[PC-1]); \
return 0;
#define phR(ticks, adrmode, R) \
fetch(); \
tick(ticks); \
push(R); \
next();
#define pha(ticks, adrmode) phR(ticks, adrmode, A)
#define phx(ticks, adrmode) phR(ticks, adrmode, X)
#define phy(ticks, adrmode) phR(ticks, adrmode, Y)
#define php(ticks, adrmode) phR(ticks, adrmode, P | flagX | flagB)
#define plR(ticks, adrmode, R) \
fetch(); \
tick(ticks); \
R= pop(); \
setNZ(R & 0x80, !R); \
next();
#define pla(ticks, adrmode) plR(ticks, adrmode, A)
#define plx(ticks, adrmode) plR(ticks, adrmode, X)
#define ply(ticks, adrmode) plR(ticks, adrmode, Y)
#define plp(ticks, adrmode) \
fetch(); \
tick(ticks); \
P= pop(); \
next();
#define clF(ticks, adrmode, F) \
fetch(); \
tick(ticks); \
P &= ~F; \
next();
#define clc(ticks, adrmode) clF(ticks, adrmode, flagC)
#define cld(ticks, adrmode) clF(ticks, adrmode, flagD)
#define cli(ticks, adrmode) clF(ticks, adrmode, flagI)
#define clv(ticks, adrmode) clF(ticks, adrmode, flagV)
#define seF(ticks, adrmode, F) \
fetch(); \
tick(ticks); \
P |= F; \
next();
#define sec(ticks, adrmode) seF(ticks, adrmode, flagC)
#define sed(ticks, adrmode) seF(ticks, adrmode, flagD)
#define sei(ticks, adrmode) seF(ticks, adrmode, flagI)
#define do_insns(_) \
_(00, brk, implied, 7); _(01, ora, indx, 6); _(02, ill, implied, 2); _(03, ill, implied, 2); \
_(04, tsb, zp, 3); _(05, ora, zp, 3); _(06, asl, zp, 5); _(07, ill, implied, 2); \
_(08, php, implied, 3); _(09, ora, immediate, 3); _(0a, asla,implied, 2); _(0b, ill, implied, 2); \
_(0c, tsb, abs, 4); _(0d, ora, abs, 4); _(0e, asl, abs, 6); _(0f, ill, implied, 2); \
_(10, bpl, relative, 2); _(11, ora, indy, 5); _(12, ora, indzp, 3); _(13, ill, implied, 2); \
_(14, trb, zp, 3); _(15, ora, zpx, 4); _(16, asl, zpx, 6); _(17, ill, implied, 2); \
_(18, clc, implied, 2); _(19, ora, absy, 4); _(1a, ina, implied, 2); _(1b, ill, implied, 2); \
_(1c, trb, abs, 4); _(1d, ora, absx, 4); _(1e, asl, absx, 7); _(1f, ill, implied, 2); \
_(20, jsr, abs, 6); _(21, and, indx, 6); _(22, ill, implied, 2); _(23, ill, implied, 2); \
_(24, bit, zp, 3); _(25, and, zp, 3); _(26, rol, zp, 5); _(27, ill, implied, 2); \
_(28, plp, implied, 4); _(29, and, immediate, 3); _(2a, rola,implied, 2); _(2b, ill, implied, 2); \
_(2c, bit, abs, 4); _(2d, and, abs, 4); _(2e, rol, abs, 6); _(2f, ill, implied, 2); \
_(30, bmi, relative, 2); _(31, and, indy, 5); _(32, and, indzp, 3); _(33, ill, implied, 2); \
_(34, bit, zpx, 4); _(35, and, zpx, 4); _(36, rol, zpx, 6); _(37, ill, implied, 2); \
_(38, sec, implied, 2); _(39, and, absy, 4); _(3a, dea, implied, 2); _(3b, ill, implied, 2); \
_(3c, bit, absx, 4); _(3d, and, absx, 4); _(3e, rol, absx, 7); _(3f, ill, implied, 2); \
_(40, rti, implied, 6); _(41, eor, indx, 6); _(42, ill, implied, 2); _(43, ill, implied, 2); \
_(44, ill, implied, 2); _(45, eor, zp, 3); _(46, lsr, zp, 5); _(47, ill, implied, 2); \
_(48, pha, implied, 3); _(49, eor, immediate, 3); _(4a, lsra,implied, 2); _(4b, ill, implied, 2); \
_(4c, jmp, abs, 3); _(4d, eor, abs, 4); _(4e, lsr, abs, 6); _(4f, ill, implied, 2); \
_(50, bvc, relative, 2); _(51, eor, indy, 5); _(52, eor, indzp, 3); _(53, ill, implied, 2); \
_(54, ill, implied, 2); _(55, eor, zpx, 4); _(56, lsr, zpx, 6); _(57, ill, implied, 2); \
_(58, cli, implied, 2); _(59, eor, absy, 4); _(5a, phy, implied, 3); _(5b, ill, implied, 2); \
_(5c, ill, implied, 2); _(5d, eor, absx, 4); _(5e, lsr, absx, 7); _(5f, ill, implied, 2); \
_(60, rts, implied, 6); _(61, adc, indx, 6); _(62, ill, implied, 2); _(63, ill, implied, 2); \
_(64, stz, zp, 3); _(65, adc, zp, 3); _(66, ror, zp, 5); _(67, ill, implied, 2); \
_(68, pla, implied, 4); _(69, adc, immediate, 3); _(6a, rora,implied, 2); _(6b, ill, implied, 2); \
_(6c, jmp, indirect, 5); _(6d, adc, abs, 4); _(6e, ror, abs, 6); _(6f, ill, implied, 2); \
_(70, bvs, relative, 2); _(71, adc, indy, 5); _(72, adc, indzp, 3); _(73, ill, implied, 2); \
_(74, stz, zpx, 4); _(75, adc, zpx, 4); _(76, ror, zpx, 6); _(77, ill, implied, 2); \
_(78, sei, implied, 2); _(79, adc, absy, 4); _(7a, ply, implied, 4); _(7b, ill, implied, 2); \
_(7c, jmp, indabsx, 6); _(7d, adc, absx, 4); _(7e, ror, absx, 7); _(7f, ill, implied, 2); \
_(80, bra, relative, 2); _(81, sta, indx, 6); _(82, ill, implied, 2); _(83, ill, implied, 2); \
_(84, sty, zp, 2); _(85, sta, zp, 2); _(86, stx, zp, 2); _(87, ill, implied, 2); \
_(88, dey, implied, 2); _(89, bit, immediate, 2); _(8a, txa, implied, 2); _(8b, ill, implied, 2); \
_(8c, sty, abs, 4); _(8d, sta, abs, 4); _(8e, stx, abs, 4); _(8f, ill, implied, 2); \
_(90, bcc, relative, 2); _(91, sta, indy, 6); _(92, sta, indzp, 3); _(93, ill, implied, 2); \
_(94, sty, zpx, 4); _(95, sta, zpx, 4); _(96, stx, zpy, 4); _(97, ill, implied, 2); \
_(98, tya, implied, 2); _(99, sta, absy, 5); _(9a, txs, implied, 2); _(9b, ill, implied, 2); \
_(9c, stz, abs, 4); _(9d, sta, absx, 5); _(9e, stz, absx, 5); _(9f, ill, implied, 2); \
_(a0, ldy, immediate, 3); _(a1, lda, indx, 6); _(a2, ldx, immediate, 3); _(a3, ill, implied, 2); \
_(a4, ldy, zp, 3); _(a5, lda, zp, 3); _(a6, ldx, zp, 3); _(a7, ill, implied, 2); \
_(a8, tay, implied, 2); _(a9, lda, immediate, 3); _(aa, tax, implied, 2); _(ab, ill, implied, 2); \
_(ac, ldy, abs, 4); _(ad, lda, abs, 4); _(ae, ldx, abs, 4); _(af, ill, implied, 2); \
_(b0, bcs, relative, 2); _(b1, lda, indy, 5); _(b2, lda, indzp, 3); _(b3, ill, implied, 2); \
_(b4, ldy, zpx, 4); _(b5, lda, zpx, 4); _(b6, ldx, zpy, 4); _(b7, ill, implied, 2); \
_(b8, clv, implied, 2); _(b9, lda, absy, 4); _(ba, tsx, implied, 2); _(bb, ill, implied, 2); \
_(bc, ldy, absx, 4); _(bd, lda, absx, 4); _(be, ldx, absy, 4); _(bf, ill, implied, 2); \
_(c0, cpy, immediate, 3); _(c1, cmp, indx, 6); _(c2, ill, implied, 2); _(c3, ill, implied, 2); \
_(c4, cpy, zp, 3); _(c5, cmp, zp, 3); _(c6, dec, zp, 5); _(c7, ill, implied, 2); \
_(c8, iny, implied, 2); _(c9, cmp, immediate, 3); _(ca, dex, implied, 2); _(cb, ill, implied, 2); \
_(cc, cpy, abs, 4); _(cd, cmp, abs, 4); _(ce, dec, abs, 6); _(cf, ill, implied, 2); \
_(d0, bne, relative, 2); _(d1, cmp, indy, 5); _(d2, cmp, indzp, 3); _(d3, ill, implied, 2); \
_(d4, ill, implied, 2); _(d5, cmp, zpx, 4); _(d6, dec, zpx, 6); _(d7, ill, implied, 2); \
_(d8, cld, implied, 2); _(d9, cmp, absy, 4); _(da, phx, implied, 3); _(db, ill, implied, 2); \
_(dc, ill, implied, 2); _(dd, cmp, absx, 4); _(de, dec, absx, 7); _(df, ill, implied, 2); \
_(e0, cpx, immediate, 3); _(e1, sbc, indx, 6); _(e2, ill, implied, 2); _(e3, ill, implied, 2); \
_(e4, cpx, zp, 3); _(e5, sbc, zp, 3); _(e6, inc, zp, 5); _(e7, ill, implied, 2); \
_(e8, inx, implied, 2); _(e9, sbc, immediate, 3); _(ea, nop, implied, 2); _(eb, ill, implied, 2); \
_(ec, cpx, abs, 4); _(ed, sbc, abs, 4); _(ee, inc, abs, 6); _(ef, ill, implied, 2); \
_(f0, beq, relative, 2); _(f1, sbc, indy, 5); _(f2, sbc, indzp, 3); _(f3, ill, implied, 2); \
_(f4, ill, implied, 2); _(f5, sbc, zpx, 4); _(f6, inc, zpx, 6); _(f7, ill, implied, 2); \
_(f8, sed, implied, 2); _(f9, sbc, absy, 4); _(fa, plx, implied, 4); _(fb, ill, implied, 2); \
_(fc, ill, implied, 2); _(fd, sbc, absx, 4); _(fe, inc, absx, 7); _(ff, ill, implied, 2);
void M6502_irq(M6502 *mpu)
{
if (!(mpu->registers->p & flagI))
{
mpu->memory[0x0100 + mpu->registers->s--] = (byte)(mpu->registers->pc >> 8);
mpu->memory[0x0100 + mpu->registers->s--] = (byte)(mpu->registers->pc & 0xff);
mpu->memory[0x0100 + mpu->registers->s--] = mpu->registers->p;
mpu->registers->p &= ~flagB;
mpu->registers->p |= flagI;
mpu->registers->pc = M6502_getVector(mpu, IRQ);
}
}
void M6502_nmi(M6502 *mpu)
{
mpu->memory[0x0100 + mpu->registers->s--] = (byte)(mpu->registers->pc >> 8);
mpu->memory[0x0100 + mpu->registers->s--] = (byte)(mpu->registers->pc & 0xff);
mpu->memory[0x0100 + mpu->registers->s--] = mpu->registers->p;
mpu->registers->p &= ~flagB;
mpu->registers->p |= flagI;
mpu->registers->pc = M6502_getVector(mpu, NMI);
}
void M6502_reset(M6502 *mpu)
{
mpu->registers->p &= ~flagD;
mpu->registers->p |= flagI;
mpu->registers->pc = M6502_getVector(mpu, RST);
}
/* the compiler should elminate all call to this function */
static void oops(void)
{
fprintf(stderr, "\noops -- instruction dispatch missing\n");
}
int M6502_run(M6502 *mpu)
{
#if defined(__GNUC__) && !defined(__STRICT_ANSI__)
static void *itab[256]= { &&_00, &&_01, &&_02, &&_03, &&_04, &&_05, &&_06, &&_07, &&_08, &&_09, &&_0a, &&_0b, &&_0c, &&_0d, &&_0e, &&_0f,
&&_10, &&_11, &&_12, &&_13, &&_14, &&_15, &&_16, &&_17, &&_18, &&_19, &&_1a, &&_1b, &&_1c, &&_1d, &&_1e, &&_1f,
&&_20, &&_21, &&_22, &&_23, &&_24, &&_25, &&_26, &&_27, &&_28, &&_29, &&_2a, &&_2b, &&_2c, &&_2d, &&_2e, &&_2f,
&&_30, &&_31, &&_32, &&_33, &&_34, &&_35, &&_36, &&_37, &&_38, &&_39, &&_3a, &&_3b, &&_3c, &&_3d, &&_3e, &&_3f,
&&_40, &&_41, &&_42, &&_43, &&_44, &&_45, &&_46, &&_47, &&_48, &&_49, &&_4a, &&_4b, &&_4c, &&_4d, &&_4e, &&_4f,
&&_50, &&_51, &&_52, &&_53, &&_54, &&_55, &&_56, &&_57, &&_58, &&_59, &&_5a, &&_5b, &&_5c, &&_5d, &&_5e, &&_5f,
&&_60, &&_61, &&_62, &&_63, &&_64, &&_65, &&_66, &&_67, &&_68, &&_69, &&_6a, &&_6b, &&_6c, &&_6d, &&_6e, &&_6f,
&&_70, &&_71, &&_72, &&_73, &&_74, &&_75, &&_76, &&_77, &&_78, &&_79, &&_7a, &&_7b, &&_7c, &&_7d, &&_7e, &&_7f,
&&_80, &&_81, &&_82, &&_83, &&_84, &&_85, &&_86, &&_87, &&_88, &&_89, &&_8a, &&_8b, &&_8c, &&_8d, &&_8e, &&_8f,
&&_90, &&_91, &&_92, &&_93, &&_94, &&_95, &&_96, &&_97, &&_98, &&_99, &&_9a, &&_9b, &&_9c, &&_9d, &&_9e, &&_9f,
&&_a0, &&_a1, &&_a2, &&_a3, &&_a4, &&_a5, &&_a6, &&_a7, &&_a8, &&_a9, &&_aa, &&_ab, &&_ac, &&_ad, &&_ae, &&_af,
&&_b0, &&_b1, &&_b2, &&_b3, &&_b4, &&_b5, &&_b6, &&_b7, &&_b8, &&_b9, &&_ba, &&_bb, &&_bc, &&_bd, &&_be, &&_bf,
&&_c0, &&_c1, &&_c2, &&_c3, &&_c4, &&_c5, &&_c6, &&_c7, &&_c8, &&_c9, &&_ca, &&_cb, &&_cc, &&_cd, &&_ce, &&_cf,
&&_d0, &&_d1, &&_d2, &&_d3, &&_d4, &&_d5, &&_d6, &&_d7, &&_d8, &&_d9, &&_da, &&_db, &&_dc, &&_dd, &&_de, &&_df,
&&_e0, &&_e1, &&_e2, &&_e3, &&_e4, &&_e5, &&_e6, &&_e7, &&_e8, &&_e9, &&_ea, &&_eb, &&_ec, &&_ed, &&_ee, &&_ef,
&&_f0, &&_f1, &&_f2, &&_f3, &&_f4, &&_f5, &&_f6, &&_f7, &&_f8, &&_f9, &&_fa, &&_fb, &&_fc, &&_fd, &&_fe, &&_ff };
register void **itabp= &itab[0];
register void *tpc;
//# define begin() fetch(); next()
# define begin() goto *(itabp[memory[PC++]])
# define fetch() tpc= itabp[memory[PC++]]
# define next() if (STEP) { PC--; externalise(); return 1; } goto *tpc
# define dispatch(num, name, mode, cycles) _##num: name(cycles, mode) oops(); next()
# define end()
#else /* (!__GNUC__) || (__STRICT_ANSI__) */
# define begin() for (;;) switch (memory[PC++]) {
# define fetch()
# define next() if (STEP) { externalise(); return 1; } break
# define dispatch(num, name, mode, cycles) case 0x##num: name(cycles, mode); next()
# define end() }
#endif
register byte *memory= mpu->memory;
register word PC;
word ea;
byte A, X, Y, P, S;
M6502_Callback *readCallback= mpu->callbacks->read;
M6502_Callback *writeCallback= mpu->callbacks->write;
unsigned int STEP;
# define internalise() STEP=mpu->flags&M6502_SingleStep; A= mpu->registers->a; X= mpu->registers->x; Y= mpu->registers->y; P= mpu->registers->p; S= mpu->registers->s; PC= mpu->registers->pc
# define externalise() mpu->registers->a= A; mpu->registers->x= X; mpu->registers->y= Y; mpu->registers->p= P; mpu->registers->s= S; mpu->registers->pc= PC
internalise();
begin();
do_insns(dispatch);
end();
# undef begin
# undef internalise
# undef externalise
# undef fetch
# undef next
# undef dispatch
# undef end
(void)oops;
return 0;
}
int M6502_disassemble(M6502 *mpu, word ip, char buffer[64])
{
char *s= buffer;
byte *b= mpu->memory + ip;
switch (b[0])
{
# define _implied return 1;
# define _immediate sprintf(s, "#%02X", b[1]); return 2;
# define _zp sprintf(s, "%02X", b[1]); return 2;
# define _zpx sprintf(s, "%02X,X", b[1]); return 2;
# define _zpy sprintf(s, "%02X,Y", b[1]); return 2;
# define _abs sprintf(s, "%02X%02X", b[2], b[1]); return 3;
# define _absx sprintf(s, "%02X%02X,X", b[2], b[1]); return 3;
# define _absy sprintf(s, "%02X%02X,Y", b[2], b[1]); return 3;
# define _relative sprintf(s, "%04X", ip + 2 + (int8_t)b[1]); return 2;
# define _indirect sprintf(s, "(%02X%02X)", b[2], b[1]); return 3;
# define _indzp sprintf(s, "(%02X)", b[1]); return 2;
# define _indx sprintf(s, "(%02X,X)", b[1]); return 2;
# define _indy sprintf(s, "(%02X),Y", b[1]); return 2;
# define _indabsx sprintf(s, "(%02X%02X,X)", b[2], b[1]); return 3;
# define disassemble(num, name, mode, cycles) case 0x##num: s += sprintf(s, "%s ", #name); _##mode
do_insns(disassemble);
# undef _do
}
return 0;
}
void M6502_dump(M6502 *mpu, char buffer[64])
{
M6502_Registers *r= mpu->registers;
uint8_t p= r->p;
# define P(N,C) (p & (1 << (N)) ? (C) : '-')
sprintf(buffer, "PC=%04X SP=%04X A=%02X X=%02X Y=%02X P=%02X %c%c%c%c%c%c%c%c",
r->pc, 0x0100 + r->s,
r->a, r->x, r->y, r->p,
P(7,'N'), P(6,'V'), P(5,'?'), P(4,'B'), P(3,'D'), P(2,'I'), P(1,'Z'), P(0,'C'));
# undef P
}
static void outOfMemory(void)
{
fflush(stdout);
fprintf(stderr, "\nout of memory\n");
abort();
}
M6502 *M6502_new(M6502_Registers *registers, M6502_Memory memory, M6502_Callbacks *callbacks)
{
M6502 *mpu= calloc(1, sizeof(M6502));
if (!mpu) outOfMemory();
if (!registers) { registers = (M6502_Registers *)calloc(1, sizeof(M6502_Registers)); mpu->flags |= M6502_RegistersAllocated; }
if (!memory ) { memory = (uint8_t *)calloc(1, sizeof(M6502_Memory )); mpu->flags |= M6502_MemoryAllocated; }
if (!callbacks) { callbacks = (M6502_Callbacks *)calloc(1, sizeof(M6502_Callbacks)); mpu->flags |= M6502_CallbacksAllocated; }
if (!registers || !memory || !callbacks) outOfMemory();
mpu->registers = registers;
mpu->memory = memory;
mpu->callbacks = callbacks;
return mpu;
}
void M6502_delete(M6502 *mpu)
{
if (mpu->flags & M6502_CallbacksAllocated) free(mpu->callbacks);
if (mpu->flags & M6502_MemoryAllocated ) free(mpu->memory);
if (mpu->flags & M6502_RegistersAllocated) free(mpu->registers);
free(mpu);
}

View File

@ -189,8 +189,9 @@ $(DRAWL): lisp/s-expr.pla lisp/drawl.pla
#
# PLASMA VMs
#
$(PLVM): vmsrc/plvm.c
cc vmsrc/plvm.c -o $(PLVM)
$(PLVM): vmsrc/plvm.c vmsrc/lib6502/lib6502.a
make -C vmsrc/lib6502
cc vmsrc/plvm.c vmsrc/lib6502/lib6502.a -o $(PLVM)
$(PLVMZP_APL): FORCE
-mkdir -p rel

921
src/vmsrc/lib6502/lib6502.c Normal file
View File

@ -0,0 +1,921 @@
/* lib6502.c -- MOS Technology 6502 emulator -*- C -*- */
/* Copyright (c) 2005 Ian Piumarta
*
* All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the 'Software'),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, provided that the above copyright notice(s) and this
* permission notice appear in all copies of the Software and that both the
* above copyright notice(s) and this permission notice appear in supporting
* documentation.
*
* THE SOFTWARE IS PROVIDED 'AS IS'. USE ENTIRELY AT YOUR OWN RISK.
*/
/* Last edited: 2013-06-07 23:03:39 by piumarta on emilia.local
*
* BUGS:
* - RTS and RTI do not check the return address for a callback
* - the disassembler cannot be configured to read two bytes for BRK
* - architectural variations (unimplemented/extended instructions) not implemented
* - ANSI versions (from from gcc extensions) of the dispatch macros are missing
* - emulator+disassembler in same object file (library is kind of pointless)
*/
#include <stdio.h>
#include <stdlib.h>
#include "lib6502.h"
typedef uint8_t byte;
typedef uint16_t word;
enum {
flagN= (1<<7), /* negative */
flagV= (1<<6), /* overflow */
flagX= (1<<5), /* unused */
flagB= (1<<4), /* irq from brk */
flagD= (1<<3), /* decimal mode */
flagI= (1<<2), /* irq disable */
flagZ= (1<<1), /* zero */
flagC= (1<<0) /* carry */
};
#define getN() (P & flagN)
#define getV() (P & flagV)
#define getB() (P & flagB)
#define getD() (P & flagD)
#define getI() (P & flagI)
#define getZ() (P & flagZ)
#define getC() (P & flagC)
#define setNVZC(N,V,Z,C) (P= (P & ~(flagN | flagV | flagZ | flagC)) | (N) | ((V)<<6) | ((Z)<<1) | (C))
#define setNZC(N,Z,C) (P= (P & ~(flagN | flagZ | flagC)) | (N) | ((Z)<<1) | (C))
#define setNZ(N,Z) (P= (P & ~(flagN | flagZ )) | (N) | ((Z)<<1) )
#define setZ(Z) (P= (P & ~( flagZ )) | ((Z)<<1) )
#define setC(C) (P= (P & ~( flagC)) | (C))
#define NAND(P, Q) (!((P) & (Q)))
#define tick(n)
#define tickIf(p)
/* memory access (indirect if callback installed) -- ARGUMENTS ARE EVALUATED MORE THAN ONCE! */
#define putMemory(ADDR, BYTE) \
( writeCallback[ADDR] \
? writeCallback[ADDR](mpu, ADDR, BYTE) \
: (memory[ADDR]= BYTE) )
#define getMemory(ADDR) \
( readCallback[ADDR] \
? readCallback[ADDR](mpu, ADDR, 0) \
: memory[ADDR] )
/* stack access (always direct) */
#define push(BYTE) (memory[0x0100 + S--]= (BYTE))
#define pop() (memory[++S + 0x0100])
/* adressing modes (memory access direct) */
#define implied(ticks) \
tick(ticks);
#define immediate(ticks) \
tick(ticks); \
ea= PC++;
#define abs(ticks) \
tick(ticks); \
ea= memory[PC] + (memory[PC + 1] << 8); \
PC += 2;
#define relative(ticks) \
tick(ticks); \
ea= memory[PC++]; \
if (ea & 0x80) ea -= 0x100; \
tickIf((ea >> 8) != (PC >> 8));
#define indirect(ticks) \
tick(ticks); \
{ \
word tmp; \
tmp= memory[PC] + (memory[PC + 1] << 8); \
ea = memory[tmp] + (memory[tmp + 1] << 8); \
PC += 2; \
}
#define absx(ticks) \
tick(ticks); \
ea= memory[PC] + (memory[PC + 1] << 8); \
PC += 2; \
tickIf((ticks == 4) && ((ea >> 8) != ((ea + X) >> 8))); \
ea += X;
#define absy(ticks) \
tick(ticks); \
ea= memory[PC] + (memory[PC + 1] << 8); \
PC += 2; \
tickIf((ticks == 4) && ((ea >> 8) != ((ea + Y) >> 8))); \
ea += Y
#define zp(ticks) \
tick(ticks); \
ea= memory[PC++];
#define zpx(ticks) \
tick(ticks); \
ea= memory[PC++] + X; \
ea &= 0x00ff;
#define zpy(ticks) \
tick(ticks); \
ea= memory[PC++] + Y; \
ea &= 0x00ff;
#define indx(ticks) \
tick(ticks); \
{ \
byte tmp= memory[PC++] + X; \
ea= memory[tmp] + (memory[tmp + 1] << 8); \
}
#define indy(ticks) \
tick(ticks); \
{ \
byte tmp= memory[PC++]; \
ea= memory[tmp] + (memory[tmp + 1] << 8); \
tickIf((ticks == 5) && ((ea >> 8) != ((ea + Y) >> 8))); \
ea += Y; \
}
#define indabsx(ticks) \
tick(ticks); \
{ \
word tmp; \
tmp= memory[PC ] + (memory[PC + 1] << 8) + X; \
ea = memory[tmp] + (memory[tmp + 1] << 8); \
}
#define indzp(ticks) \
tick(ticks); \
{ \
byte tmp; \
tmp= memory[PC++]; \
ea = memory[tmp] + (memory[tmp + 1] << 8); \
}
/* insns */
#define adc(ticks, adrmode) \
adrmode(ticks); \
{ \
byte B= getMemory(ea); \
if (!getD()) \
{ \
int c= A + B + getC(); \
int v= (int8_t)A + (int8_t)B + getC(); \
fetch(); \
A= c; \
setNVZC((A & 0x80), (((A & 0x80) > 0) ^ (v < 0)), (A == 0), ((c & 0x100) > 0)); \
next(); \
} \
else \
{ \
int l, h, s; \
/* inelegant & slow, but consistent with the hw for illegal digits */ \
l= (A & 0x0F) + (B & 0x0F) + getC(); \
h= (A & 0xF0) + (B & 0xF0); \
if (l >= 0x0A) { l -= 0x0A; h += 0x10; } \
if (h >= 0xA0) { h -= 0xA0; } \
fetch(); \
s= h | (l & 0x0F); \
/* only C is valid on NMOS 6502 */ \
setNVZC(s & 0x80, !(((A ^ B) & 0x80) && ((A ^ s) & 0x80)), !s, !!(h & 0x80)); \
A= s; \
tick(1); \
next(); \
} \
}
#define sbc(ticks, adrmode) \
adrmode(ticks); \
{ \
byte B= getMemory(ea); \
if (!getD()) \
{ \
int b= 1 - (P &0x01); \
int c= A - B - b; \
int v= (int8_t)A - (int8_t) B - b; \
fetch(); \
A= c; \
setNVZC(A & 0x80, ((A & 0x80) > 0) ^ ((v & 0x100) != 0), A == 0, c >= 0); \
next(); \
} \
else \
{ \
/* this is verbatim ADC, with a 10's complemented operand */ \
int l, h, s; \
B= 0x99 - B; \
l= (A & 0x0F) + (B & 0x0F) + getC(); \
h= (A & 0xF0) + (B & 0xF0); \
if (l >= 0x0A) { l -= 0x0A; h += 0x10; } \
if (h >= 0xA0) { h -= 0xA0; } \
fetch(); \
s= h | (l & 0x0F); \
/* only C is valid on NMOS 6502 */ \
setNVZC(s & 0x80, !(((A ^ B) & 0x80) && ((A ^ s) & 0x80)), !s, !!(h & 0x80)); \
A= s; \
tick(1); \
next(); \
} \
}
#define cmpR(ticks, adrmode, R) \
adrmode(ticks); \
fetch(); \
{ \
byte B= getMemory(ea); \
byte d= R - B; \
setNZC(d & 0x80, !d, R >= B); \
} \
next();
#define cmp(ticks, adrmode) cmpR(ticks, adrmode, A)
#define cpx(ticks, adrmode) cmpR(ticks, adrmode, X)
#define cpy(ticks, adrmode) cmpR(ticks, adrmode, Y)
#define dec(ticks, adrmode) \
adrmode(ticks); \
fetch(); \
{ \
byte B= getMemory(ea); \
--B; \
putMemory(ea, B); \
setNZ(B & 0x80, !B); \
} \
next();
#define decR(ticks, adrmode, R) \
fetch(); \
tick(ticks); \
--R; \
setNZ(R & 0x80, !R); \
next();
#define dea(ticks, adrmode) decR(ticks, adrmode, A)
#define dex(ticks, adrmode) decR(ticks, adrmode, X)
#define dey(ticks, adrmode) decR(ticks, adrmode, Y)
#define inc(ticks, adrmode) \
adrmode(ticks); \
fetch(); \
{ \
byte B= getMemory(ea); \
++B; \
putMemory(ea, B); \
setNZ(B & 0x80, !B); \
} \
next();
#define incR(ticks, adrmode, R) \
fetch(); \
tick(ticks); \
++R; \
setNZ(R & 0x80, !R); \
next();
#define ina(ticks, adrmode) incR(ticks, adrmode, A)
#define inx(ticks, adrmode) incR(ticks, adrmode, X)
#define iny(ticks, adrmode) incR(ticks, adrmode, Y)
#define bit(ticks, adrmode) \
adrmode(ticks); \
fetch(); \
{ \
byte B= getMemory(ea); \
P= (P & ~(flagN | flagV | flagZ)) \
| (B & (0xC0)) | (((A & B) == 0) << 1); \
} \
next();
#define tsb(ticks, adrmode) \
adrmode(ticks); \
fetch(); \
{ \
byte b= getMemory(ea); \
b |= A; \
putMemory(ea, b); \
setZ(!b); \
} \
next();
#define trb(ticks, adrmode) \
adrmode(ticks); \
fetch(); \
{ \
byte b= getMemory(ea); \
b |= (A ^ 0xFF); \
putMemory(ea, b); \
setZ(!b); \
} \
next();
#define bitwise(ticks, adrmode, op) \
adrmode(ticks); \
fetch(); \
A op##= getMemory(ea); \
setNZ(A & 0x80, !A); \
next();
#define and(ticks, adrmode) bitwise(ticks, adrmode, &)
#define eor(ticks, adrmode) bitwise(ticks, adrmode, ^)
#define ora(ticks, adrmode) bitwise(ticks, adrmode, |)
#define asl(ticks, adrmode) \
adrmode(ticks); \
{ \
unsigned int i= getMemory(ea) << 1; \
putMemory(ea, i); \
fetch(); \
setNZC(i & 0x80, !i, i >> 8); \
} \
next();
#define asla(ticks, adrmode) \
tick(ticks); \
fetch(); \
{ \
int c= A >> 7; \
A <<= 1; \
setNZC(A & 0x80, !A, c); \
} \
next();
#define lsr(ticks, adrmode) \
adrmode(ticks); \
{ \
byte b= getMemory(ea); \
int c= b & 1; \
fetch(); \
b >>= 1; \
putMemory(ea, b); \
setNZC(0, !b, c); \
} \
next();
#define lsra(ticks, adrmode) \
tick(ticks); \
fetch(); \
{ \
int c= A & 1; \
A >>= 1; \
setNZC(0, !A, c); \
} \
next();
#define rol(ticks, adrmode) \
adrmode(ticks); \
{ \
word b= (getMemory(ea) << 1) | getC(); \
fetch(); \
putMemory(ea, b); \
setNZC(b & 0x80, !(b & 0xFF), b >> 8); \
} \
next();
#define rola(ticks, adrmode) \
tick(ticks); \
fetch(); \
{ \
word b= (A << 1) | getC(); \
A= b; \
setNZC(A & 0x80, !A, b >> 8); \
} \
next();
#define ror(ticks, adrmode) \
adrmode(ticks); \
{ \
int c= getC(); \
byte m= getMemory(ea); \
byte b= (c << 7) | (m >> 1); \
fetch(); \
putMemory(ea, b); \
setNZC(b & 0x80, !b, m & 1); \
} \
next();
#define rora(ticks, adrmode) \
adrmode(ticks); \
{ \
int ci= getC(); \
int co= A & 1; \
fetch(); \
A= (ci << 7) | (A >> 1); \
setNZC(A & 0x80, !A, co); \
} \
next();
#define tRS(ticks, adrmode, R, S) \
fetch(); \
tick(ticks); \
S= R; \
setNZ(S & 0x80, !S); \
next();
#define tax(ticks, adrmode) tRS(ticks, adrmode, A, X)
#define txa(ticks, adrmode) tRS(ticks, adrmode, X, A)
#define tay(ticks, adrmode) tRS(ticks, adrmode, A, Y)
#define tya(ticks, adrmode) tRS(ticks, adrmode, Y, A)
#define tsx(ticks, adrmode) tRS(ticks, adrmode, S, X)
#define txs(ticks, adrmode) \
fetch(); \
tick(ticks); \
S= X; \
next();
#define ldR(ticks, adrmode, R) \
adrmode(ticks); \
fetch(); \
R= getMemory(ea); \
setNZ(R & 0x80, !R); \
next();
#define lda(ticks, adrmode) ldR(ticks, adrmode, A)
#define ldx(ticks, adrmode) ldR(ticks, adrmode, X)
#define ldy(ticks, adrmode) ldR(ticks, adrmode, Y)
#define stR(ticks, adrmode, R) \
adrmode(ticks); \
fetch(); \
putMemory(ea, R); \
next();
#define sta(ticks, adrmode) stR(ticks, adrmode, A)
#define stx(ticks, adrmode) stR(ticks, adrmode, X)
#define sty(ticks, adrmode) stR(ticks, adrmode, Y)
#define stz(ticks, adrmode) stR(ticks, adrmode, 0)
#define branch(ticks, adrmode, cond) \
if (cond) \
{ \
adrmode(ticks); \
PC += ea; \
tick(1); \
} \
else \
{ \
tick(ticks); \
PC++; \
} \
fetch(); \
next();
#define bcc(ticks, adrmode) branch(ticks, adrmode, !getC())
#define bcs(ticks, adrmode) branch(ticks, adrmode, getC())
#define bne(ticks, adrmode) branch(ticks, adrmode, !getZ())
#define beq(ticks, adrmode) branch(ticks, adrmode, getZ())
#define bpl(ticks, adrmode) branch(ticks, adrmode, !getN())
#define bmi(ticks, adrmode) branch(ticks, adrmode, getN())
#define bvc(ticks, adrmode) branch(ticks, adrmode, !getV())
#define bvs(ticks, adrmode) branch(ticks, adrmode, getV())
#define bra(ticks, adrmode) \
adrmode(ticks); \
PC += ea; \
fetch(); \
tick(1); \
next();
#define jmp(ticks, adrmode) \
adrmode(ticks); \
PC= ea; \
if (mpu->callbacks->call[ea]) \
{ \
word addr; \
externalise(); \
if ((addr= mpu->callbacks->call[ea](mpu, ea, 0))) \
{ \
internalise(); \
PC= addr; \
} \
} \
fetch(); \
next();
#define jsr(ticks, adrmode) \
PC++; \
push(PC >> 8); \
push(PC & 0xff); \
PC--; \
adrmode(ticks); \
if (mpu->callbacks->call[ea]) \
{ \
word addr; \
externalise(); \
if ((addr= mpu->callbacks->call[ea](mpu, ea, 0))) \
{ \
internalise(); \
PC= addr; \
fetch(); \
next(); \
} \
} \
PC=ea; \
fetch(); \
next();
#define rts(ticks, adrmode) \
tick(ticks); \
PC = pop(); \
PC |= (pop() << 8); \
PC++; \
fetch(); \
next();
#define brk(ticks, adrmode) \
tick(ticks); \
PC++; \
push(PC >> 8); \
push(PC & 0xff); \
P |= flagB; \
push(P | flagX); \
P |= flagI; \
{ \
word hdlr= getMemory(0xfffe) + (getMemory(0xffff) << 8); \
if (mpu->callbacks->call[hdlr]) \
{ \
word addr; \
externalise(); \
if ((addr= mpu->callbacks->call[hdlr](mpu, PC - 2, 0))) \
{ \
internalise(); \
hdlr= addr; \
} \
} \
PC= hdlr; \
} \
fetch(); \
next();
#define cop(ticks, adrmode) \
tick(ticks); \
PC++; \
push(PC >> 8); \
push(PC & 0xff); \
P |= flagB; \
push(P | flagX); \
P |= flagI; \
{ \
word hdlr= getMemory(0xfff4) + (getMemory(0xfff5) << 8); \
if (mpu->callbacks->call[hdlr]) \
{ \
word addr; \
externalise(); \
if ((addr= mpu->callbacks->call[hdlr](mpu, PC - 2, 0))) \
{ \
internalise(); \
hdlr= addr; \
} \
} \
PC= hdlr; \
} \
fetch(); \
next();
#define rti(ticks, adrmode) \
tick(ticks); \
P= pop(); \
PC= pop(); \
PC |= (pop() << 8); \
fetch(); \
next();
#define nop(ticks, adrmode) \
fetch(); \
tick(ticks); \
next();
#define ill(ticks, adrmode) \
fetch(); \
tick(ticks); \
fflush(stdout); \
fprintf(stderr, "\nundefined instruction %02X\n", memory[PC-1]); \
return 0;
#define phR(ticks, adrmode, R) \
fetch(); \
tick(ticks); \
push(R); \
next();
#define pha(ticks, adrmode) phR(ticks, adrmode, A)
#define phx(ticks, adrmode) phR(ticks, adrmode, X)
#define phy(ticks, adrmode) phR(ticks, adrmode, Y)
#define php(ticks, adrmode) phR(ticks, adrmode, P | flagX | flagB)
#define plR(ticks, adrmode, R) \
fetch(); \
tick(ticks); \
R= pop(); \
setNZ(R & 0x80, !R); \
next();
#define pla(ticks, adrmode) plR(ticks, adrmode, A)
#define plx(ticks, adrmode) plR(ticks, adrmode, X)
#define ply(ticks, adrmode) plR(ticks, adrmode, Y)
#define plp(ticks, adrmode) \
fetch(); \
tick(ticks); \
P= pop(); \
next();
#define clF(ticks, adrmode, F) \
fetch(); \
tick(ticks); \
P &= ~F; \
next();
#define clc(ticks, adrmode) clF(ticks, adrmode, flagC)
#define cld(ticks, adrmode) clF(ticks, adrmode, flagD)
#define cli(ticks, adrmode) clF(ticks, adrmode, flagI)
#define clv(ticks, adrmode) clF(ticks, adrmode, flagV)
#define seF(ticks, adrmode, F) \
fetch(); \
tick(ticks); \
P |= F; \
next();
#define sec(ticks, adrmode) seF(ticks, adrmode, flagC)
#define sed(ticks, adrmode) seF(ticks, adrmode, flagD)
#define sei(ticks, adrmode) seF(ticks, adrmode, flagI)
#define do_insns(_) \
_(00, brk, implied, 7); _(01, ora, indx, 6); _(02, cop, implied, 2); _(03, ill, implied, 2); \
_(04, tsb, zp, 3); _(05, ora, zp, 3); _(06, asl, zp, 5); _(07, ill, implied, 2); \
_(08, php, implied, 3); _(09, ora, immediate, 3); _(0a, asla,implied, 2); _(0b, ill, implied, 2); \
_(0c, tsb, abs, 4); _(0d, ora, abs, 4); _(0e, asl, abs, 6); _(0f, ill, implied, 2); \
_(10, bpl, relative, 2); _(11, ora, indy, 5); _(12, ora, indzp, 3); _(13, ill, implied, 2); \
_(14, trb, zp, 3); _(15, ora, zpx, 4); _(16, asl, zpx, 6); _(17, ill, implied, 2); \
_(18, clc, implied, 2); _(19, ora, absy, 4); _(1a, ina, implied, 2); _(1b, ill, implied, 2); \
_(1c, trb, abs, 4); _(1d, ora, absx, 4); _(1e, asl, absx, 7); _(1f, ill, implied, 2); \
_(20, jsr, abs, 6); _(21, and, indx, 6); _(22, ill, implied, 2); _(23, ill, implied, 2); \
_(24, bit, zp, 3); _(25, and, zp, 3); _(26, rol, zp, 5); _(27, ill, implied, 2); \
_(28, plp, implied, 4); _(29, and, immediate, 3); _(2a, rola,implied, 2); _(2b, ill, implied, 2); \
_(2c, bit, abs, 4); _(2d, and, abs, 4); _(2e, rol, abs, 6); _(2f, ill, implied, 2); \
_(30, bmi, relative, 2); _(31, and, indy, 5); _(32, and, indzp, 3); _(33, ill, implied, 2); \
_(34, bit, zpx, 4); _(35, and, zpx, 4); _(36, rol, zpx, 6); _(37, ill, implied, 2); \
_(38, sec, implied, 2); _(39, and, absy, 4); _(3a, dea, implied, 2); _(3b, ill, implied, 2); \
_(3c, bit, absx, 4); _(3d, and, absx, 4); _(3e, rol, absx, 7); _(3f, ill, implied, 2); \
_(40, rti, implied, 6); _(41, eor, indx, 6); _(42, ill, implied, 2); _(43, ill, implied, 2); \
_(44, ill, implied, 2); _(45, eor, zp, 3); _(46, lsr, zp, 5); _(47, ill, implied, 2); \
_(48, pha, implied, 3); _(49, eor, immediate, 3); _(4a, lsra,implied, 2); _(4b, ill, implied, 2); \
_(4c, jmp, abs, 3); _(4d, eor, abs, 4); _(4e, lsr, abs, 6); _(4f, ill, implied, 2); \
_(50, bvc, relative, 2); _(51, eor, indy, 5); _(52, eor, indzp, 3); _(53, ill, implied, 2); \
_(54, ill, implied, 2); _(55, eor, zpx, 4); _(56, lsr, zpx, 6); _(57, ill, implied, 2); \
_(58, cli, implied, 2); _(59, eor, absy, 4); _(5a, phy, implied, 3); _(5b, ill, implied, 2); \
_(5c, ill, implied, 2); _(5d, eor, absx, 4); _(5e, lsr, absx, 7); _(5f, ill, implied, 2); \
_(60, rts, implied, 6); _(61, adc, indx, 6); _(62, ill, implied, 2); _(63, ill, implied, 2); \
_(64, stz, zp, 3); _(65, adc, zp, 3); _(66, ror, zp, 5); _(67, ill, implied, 2); \
_(68, pla, implied, 4); _(69, adc, immediate, 3); _(6a, rora,implied, 2); _(6b, ill, implied, 2); \
_(6c, jmp, indirect, 5); _(6d, adc, abs, 4); _(6e, ror, abs, 6); _(6f, ill, implied, 2); \
_(70, bvs, relative, 2); _(71, adc, indy, 5); _(72, adc, indzp, 3); _(73, ill, implied, 2); \
_(74, stz, zpx, 4); _(75, adc, zpx, 4); _(76, ror, zpx, 6); _(77, ill, implied, 2); \
_(78, sei, implied, 2); _(79, adc, absy, 4); _(7a, ply, implied, 4); _(7b, ill, implied, 2); \
_(7c, jmp, indabsx, 6); _(7d, adc, absx, 4); _(7e, ror, absx, 7); _(7f, ill, implied, 2); \
_(80, bra, relative, 2); _(81, sta, indx, 6); _(82, ill, implied, 2); _(83, ill, implied, 2); \
_(84, sty, zp, 2); _(85, sta, zp, 2); _(86, stx, zp, 2); _(87, ill, implied, 2); \
_(88, dey, implied, 2); _(89, bit, immediate, 2); _(8a, txa, implied, 2); _(8b, ill, implied, 2); \
_(8c, sty, abs, 4); _(8d, sta, abs, 4); _(8e, stx, abs, 4); _(8f, ill, implied, 2); \
_(90, bcc, relative, 2); _(91, sta, indy, 6); _(92, sta, indzp, 3); _(93, ill, implied, 2); \
_(94, sty, zpx, 4); _(95, sta, zpx, 4); _(96, stx, zpy, 4); _(97, ill, implied, 2); \
_(98, tya, implied, 2); _(99, sta, absy, 5); _(9a, txs, implied, 2); _(9b, ill, implied, 2); \
_(9c, stz, abs, 4); _(9d, sta, absx, 5); _(9e, stz, absx, 5); _(9f, ill, implied, 2); \
_(a0, ldy, immediate, 3); _(a1, lda, indx, 6); _(a2, ldx, immediate, 3); _(a3, ill, implied, 2); \
_(a4, ldy, zp, 3); _(a5, lda, zp, 3); _(a6, ldx, zp, 3); _(a7, ill, implied, 2); \
_(a8, tay, implied, 2); _(a9, lda, immediate, 3); _(aa, tax, implied, 2); _(ab, ill, implied, 2); \
_(ac, ldy, abs, 4); _(ad, lda, abs, 4); _(ae, ldx, abs, 4); _(af, ill, implied, 2); \
_(b0, bcs, relative, 2); _(b1, lda, indy, 5); _(b2, lda, indzp, 3); _(b3, ill, implied, 2); \
_(b4, ldy, zpx, 4); _(b5, lda, zpx, 4); _(b6, ldx, zpy, 4); _(b7, ill, implied, 2); \
_(b8, clv, implied, 2); _(b9, lda, absy, 4); _(ba, tsx, implied, 2); _(bb, ill, implied, 2); \
_(bc, ldy, absx, 4); _(bd, lda, absx, 4); _(be, ldx, absy, 4); _(bf, ill, implied, 2); \
_(c0, cpy, immediate, 3); _(c1, cmp, indx, 6); _(c2, ill, implied, 2); _(c3, ill, implied, 2); \
_(c4, cpy, zp, 3); _(c5, cmp, zp, 3); _(c6, dec, zp, 5); _(c7, ill, implied, 2); \
_(c8, iny, implied, 2); _(c9, cmp, immediate, 3); _(ca, dex, implied, 2); _(cb, ill, implied, 2); \
_(cc, cpy, abs, 4); _(cd, cmp, abs, 4); _(ce, dec, abs, 6); _(cf, ill, implied, 2); \
_(d0, bne, relative, 2); _(d1, cmp, indy, 5); _(d2, cmp, indzp, 3); _(d3, ill, implied, 2); \
_(d4, ill, implied, 2); _(d5, cmp, zpx, 4); _(d6, dec, zpx, 6); _(d7, ill, implied, 2); \
_(d8, cld, implied, 2); _(d9, cmp, absy, 4); _(da, phx, implied, 3); _(db, ill, implied, 2); \
_(dc, ill, implied, 2); _(dd, cmp, absx, 4); _(de, dec, absx, 7); _(df, ill, implied, 2); \
_(e0, cpx, immediate, 3); _(e1, sbc, indx, 6); _(e2, ill, implied, 2); _(e3, ill, implied, 2); \
_(e4, cpx, zp, 3); _(e5, sbc, zp, 3); _(e6, inc, zp, 5); _(e7, ill, implied, 2); \
_(e8, inx, implied, 2); _(e9, sbc, immediate, 3); _(ea, nop, implied, 2); _(eb, ill, implied, 2); \
_(ec, cpx, abs, 4); _(ed, sbc, abs, 4); _(ee, inc, abs, 6); _(ef, ill, implied, 2); \
_(f0, beq, relative, 2); _(f1, sbc, indy, 5); _(f2, sbc, indzp, 3); _(f3, ill, implied, 2); \
_(f4, ill, implied, 2); _(f5, sbc, zpx, 4); _(f6, inc, zpx, 6); _(f7, ill, implied, 2); \
_(f8, sed, implied, 2); _(f9, sbc, absy, 4); _(fa, plx, implied, 4); _(fb, ill, implied, 2); \
_(fc, ill, implied, 2); _(fd, sbc, absx, 4); _(fe, inc, absx, 7); _(ff, ill, implied, 2);
void M6502_irq(M6502 *mpu)
{
if (!(mpu->registers->p & flagI))
{
mpu->memory[0x0100 + mpu->registers->s--] = (byte)(mpu->registers->pc >> 8);
mpu->memory[0x0100 + mpu->registers->s--] = (byte)(mpu->registers->pc & 0xff);
mpu->memory[0x0100 + mpu->registers->s--] = mpu->registers->p;
mpu->registers->p &= ~flagB;
mpu->registers->p |= flagI;
mpu->registers->pc = M6502_getVector(mpu, IRQ);
}
}
void M6502_nmi(M6502 *mpu)
{
mpu->memory[0x0100 + mpu->registers->s--] = (byte)(mpu->registers->pc >> 8);
mpu->memory[0x0100 + mpu->registers->s--] = (byte)(mpu->registers->pc & 0xff);
mpu->memory[0x0100 + mpu->registers->s--] = mpu->registers->p;
mpu->registers->p &= ~flagB;
mpu->registers->p |= flagI;
mpu->registers->pc = M6502_getVector(mpu, NMI);
}
void M6502_reset(M6502 *mpu)
{
mpu->registers->p &= ~flagD;
mpu->registers->p |= flagI;
mpu->registers->pc = M6502_getVector(mpu, RST);
}
/* the compiler should elminate all call to this function */
static void oops(void)
{
fprintf(stderr, "\noops -- instruction dispatch missing\n");
}
int M6502_run(M6502 *mpu)
{
#if defined(__GNUC__) && !defined(__STRICT_ANSI__)
static void *itab[256]= { &&_00, &&_01, &&_02, &&_03, &&_04, &&_05, &&_06, &&_07, &&_08, &&_09, &&_0a, &&_0b, &&_0c, &&_0d, &&_0e, &&_0f,
&&_10, &&_11, &&_12, &&_13, &&_14, &&_15, &&_16, &&_17, &&_18, &&_19, &&_1a, &&_1b, &&_1c, &&_1d, &&_1e, &&_1f,
&&_20, &&_21, &&_22, &&_23, &&_24, &&_25, &&_26, &&_27, &&_28, &&_29, &&_2a, &&_2b, &&_2c, &&_2d, &&_2e, &&_2f,
&&_30, &&_31, &&_32, &&_33, &&_34, &&_35, &&_36, &&_37, &&_38, &&_39, &&_3a, &&_3b, &&_3c, &&_3d, &&_3e, &&_3f,
&&_40, &&_41, &&_42, &&_43, &&_44, &&_45, &&_46, &&_47, &&_48, &&_49, &&_4a, &&_4b, &&_4c, &&_4d, &&_4e, &&_4f,
&&_50, &&_51, &&_52, &&_53, &&_54, &&_55, &&_56, &&_57, &&_58, &&_59, &&_5a, &&_5b, &&_5c, &&_5d, &&_5e, &&_5f,
&&_60, &&_61, &&_62, &&_63, &&_64, &&_65, &&_66, &&_67, &&_68, &&_69, &&_6a, &&_6b, &&_6c, &&_6d, &&_6e, &&_6f,
&&_70, &&_71, &&_72, &&_73, &&_74, &&_75, &&_76, &&_77, &&_78, &&_79, &&_7a, &&_7b, &&_7c, &&_7d, &&_7e, &&_7f,
&&_80, &&_81, &&_82, &&_83, &&_84, &&_85, &&_86, &&_87, &&_88, &&_89, &&_8a, &&_8b, &&_8c, &&_8d, &&_8e, &&_8f,
&&_90, &&_91, &&_92, &&_93, &&_94, &&_95, &&_96, &&_97, &&_98, &&_99, &&_9a, &&_9b, &&_9c, &&_9d, &&_9e, &&_9f,
&&_a0, &&_a1, &&_a2, &&_a3, &&_a4, &&_a5, &&_a6, &&_a7, &&_a8, &&_a9, &&_aa, &&_ab, &&_ac, &&_ad, &&_ae, &&_af,
&&_b0, &&_b1, &&_b2, &&_b3, &&_b4, &&_b5, &&_b6, &&_b7, &&_b8, &&_b9, &&_ba, &&_bb, &&_bc, &&_bd, &&_be, &&_bf,
&&_c0, &&_c1, &&_c2, &&_c3, &&_c4, &&_c5, &&_c6, &&_c7, &&_c8, &&_c9, &&_ca, &&_cb, &&_cc, &&_cd, &&_ce, &&_cf,
&&_d0, &&_d1, &&_d2, &&_d3, &&_d4, &&_d5, &&_d6, &&_d7, &&_d8, &&_d9, &&_da, &&_db, &&_dc, &&_dd, &&_de, &&_df,
&&_e0, &&_e1, &&_e2, &&_e3, &&_e4, &&_e5, &&_e6, &&_e7, &&_e8, &&_e9, &&_ea, &&_eb, &&_ec, &&_ed, &&_ee, &&_ef,
&&_f0, &&_f1, &&_f2, &&_f3, &&_f4, &&_f5, &&_f6, &&_f7, &&_f8, &&_f9, &&_fa, &&_fb, &&_fc, &&_fd, &&_fe, &&_ff };
register void **itabp= &itab[0];
register void *tpc;
//# define begin() fetch(); next()
# define begin() goto *(itabp[memory[PC++]])
# define fetch() tpc= itabp[memory[PC++]]
# define next() if (STEP) { PC--; externalise(); return 1; } goto *tpc
# define dispatch(num, name, mode, cycles) _##num: name(cycles, mode) oops(); next()
# define end()
#else /* (!__GNUC__) || (__STRICT_ANSI__) */
# define begin() for (;;) switch (memory[PC++]) {
# define fetch()
# define next() if (STEP) { externalise(); return 1; } break
# define dispatch(num, name, mode, cycles) case 0x##num: name(cycles, mode); next()
# define end() }
#endif
register byte *memory= mpu->memory;
register word PC;
word ea;
byte A, X, Y, P, S;
M6502_Callback *readCallback= mpu->callbacks->read;
M6502_Callback *writeCallback= mpu->callbacks->write;
unsigned int STEP;
# define internalise() STEP=mpu->flags&M6502_SingleStep; A= mpu->registers->a; X= mpu->registers->x; Y= mpu->registers->y; P= mpu->registers->p; S= mpu->registers->s; PC= mpu->registers->pc
# define externalise() mpu->registers->a= A; mpu->registers->x= X; mpu->registers->y= Y; mpu->registers->p= P; mpu->registers->s= S; mpu->registers->pc= PC
internalise();
begin();
do_insns(dispatch);
end();
# undef begin
# undef internalise
# undef externalise
# undef fetch
# undef next
# undef dispatch
# undef end
(void)oops;
return 0;
}
int M6502_disassemble(M6502 *mpu, word ip, char buffer[64])
{
char *s= buffer;
byte *b= mpu->memory + ip;
switch (b[0])
{
# define _implied return 1;
# define _immediate sprintf(s, "#%02X", b[1]); return 2;
# define _zp sprintf(s, "%02X", b[1]); return 2;
# define _zpx sprintf(s, "%02X,X", b[1]); return 2;
# define _zpy sprintf(s, "%02X,Y", b[1]); return 2;
# define _abs sprintf(s, "%02X%02X", b[2], b[1]); return 3;
# define _absx sprintf(s, "%02X%02X,X", b[2], b[1]); return 3;
# define _absy sprintf(s, "%02X%02X,Y", b[2], b[1]); return 3;
# define _relative sprintf(s, "%04X", ip + 2 + (int8_t)b[1]); return 2;
# define _indirect sprintf(s, "(%02X%02X)", b[2], b[1]); return 3;
# define _indzp sprintf(s, "(%02X)", b[1]); return 2;
# define _indx sprintf(s, "(%02X,X)", b[1]); return 2;
# define _indy sprintf(s, "(%02X),Y", b[1]); return 2;
# define _indabsx sprintf(s, "(%02X%02X,X)", b[2], b[1]); return 3;
# define disassemble(num, name, mode, cycles) case 0x##num: s += sprintf(s, "%s ", #name); _##mode
do_insns(disassemble);
# undef _do
}
return 0;
}
void M6502_dump(M6502 *mpu, char buffer[64])
{
M6502_Registers *r= mpu->registers;
uint8_t p= r->p;
# define P(N,C) (p & (1 << (N)) ? (C) : '-')
sprintf(buffer, "PC=%04X SP=%04X A=%02X X=%02X Y=%02X P=%02X %c%c%c%c%c%c%c%c",
r->pc, 0x0100 + r->s,
r->a, r->x, r->y, r->p,
P(7,'N'), P(6,'V'), P(5,'?'), P(4,'B'), P(3,'D'), P(2,'I'), P(1,'Z'), P(0,'C'));
# undef P
}
static void outOfMemory(void)
{
fflush(stdout);
fprintf(stderr, "\nout of memory\n");
abort();
}
M6502 *M6502_new(M6502_Registers *registers, M6502_Memory memory, M6502_Callbacks *callbacks)
{
M6502 *mpu= calloc(1, sizeof(M6502));
if (!mpu) outOfMemory();
if (!registers) { registers = (M6502_Registers *)calloc(1, sizeof(M6502_Registers)); mpu->flags |= M6502_RegistersAllocated; }
if (!memory ) { memory = (uint8_t *)calloc(1, sizeof(M6502_Memory )); mpu->flags |= M6502_MemoryAllocated; }
if (!callbacks) { callbacks = (M6502_Callbacks *)calloc(1, sizeof(M6502_Callbacks)); mpu->flags |= M6502_CallbacksAllocated; }
if (!registers || !memory || !callbacks) outOfMemory();
mpu->registers = registers;
mpu->memory = memory;
mpu->callbacks = callbacks;
return mpu;
}
void M6502_delete(M6502 *mpu)
{
if (mpu->flags & M6502_CallbacksAllocated) free(mpu->callbacks);
if (mpu->flags & M6502_MemoryAllocated ) free(mpu->memory);
if (mpu->flags & M6502_RegistersAllocated) free(mpu->registers);
free(mpu);
}

View File

@ -5,14 +5,14 @@
#include <stdio.h>
#include <stdint.h>
typedef struct _M6502 M6502;
typedef struct _M6502_Registers M6502_Registers;
typedef struct _M6502_Callbacks M6502_Callbacks;
typedef struct _M6502 M6502;
typedef struct _M6502_Registers M6502_Registers;
typedef struct _M6502_Callbacks M6502_Callbacks;
typedef int (*M6502_Callback)(M6502 *mpu, uint16_t address, uint8_t data);
typedef M6502_Callback M6502_CallbackTable[0x10000];
typedef uint8_t M6502_Memory[0x10000];
typedef M6502_Callback M6502_CallbackTable[0x10000];
typedef uint8_t M6502_Memory[0x10000];
enum {
M6502_NMIVector= 0xfffa, M6502_NMIVectorLSB= 0xfffa, M6502_NMIVectorMSB= 0xfffb,
@ -22,12 +22,12 @@ enum {
struct _M6502_Registers
{
uint8_t a; /* accumulator */
uint8_t x; /* X index register */
uint8_t y; /* Y index register */
uint8_t p; /* processor status register */
uint8_t s; /* stack pointer */
uint16_t pc; /* program counter */
uint8_t a; /* accumulator */
uint8_t x; /* X index register */
uint8_t y; /* Y index register */
uint8_t p; /* processor status register */
uint8_t s; /* stack pointer */
uint16_t pc; /* program counter */
};
struct _M6502_Callbacks
@ -40,9 +40,9 @@ struct _M6502_Callbacks
struct _M6502
{
M6502_Registers *registers;
uint8_t *memory;
uint8_t *memory;
M6502_Callbacks *callbacks;
unsigned int flags;
unsigned int flags;
};
enum {
@ -61,16 +61,16 @@ extern int M6502_disassemble(M6502 *mpu, uint16_t addr, char buffer[64]);
extern void M6502_dump(M6502 *mpu, char buffer[64]);
extern void M6502_delete(M6502 *mpu);
#define M6502_getVector(MPU, VEC) \
( ( ((MPU)->memory[M6502_##VEC##VectorLSB]) ) \
#define M6502_getVector(MPU, VEC) \
( ( ((MPU)->memory[M6502_##VEC##VectorLSB]) ) \
| ((MPU)->memory[M6502_##VEC##VectorMSB] << 8) )
#define M6502_setVector(MPU, VEC, ADDR) \
( ( ((MPU)->memory[M6502_##VEC##VectorLSB]= ((uint8_t)(ADDR)) & 0xff) ) \
#define M6502_setVector(MPU, VEC, ADDR) \
( ( ((MPU)->memory[M6502_##VEC##VectorLSB]= ((uint8_t)(ADDR)) & 0xff) ) \
, ((MPU)->memory[M6502_##VEC##VectorMSB]= (uint8_t)((ADDR) >> 8)) )
#define M6502_getCallback(MPU, TYPE, ADDR) ((MPU)->callbacks->TYPE[ADDR])
#define M6502_setCallback(MPU, TYPE, ADDR, FN) ((MPU)->callbacks->TYPE[ADDR]= (FN))
#define M6502_getCallback(MPU, TYPE, ADDR) ((MPU)->callbacks->TYPE[ADDR])
#define M6502_setCallback(MPU, TYPE, ADDR, FN) ((MPU)->callbacks->TYPE[ADDR]= (FN))
#endif __m6502_h
#endif // __m6502_h

View File

@ -1,51 +1,72 @@
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <ctype.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <termios.h>
#include "lib6502/config.h"
#include "lib6502/lib6502.h"
typedef uint8_t code;
typedef uint8_t byte;
typedef int16_t word;
typedef uint16_t uword;
typedef uint16_t address;
typedef unsigned char code;
typedef unsigned char byte;
typedef signed short word;
typedef unsigned short uword;
typedef unsigned short address;
/*
* Debug
* Debug flag
*/
int show_state = 0;
/*
* Bytecode memory
*/
#ifdef __LITTLE_ENDIAN__
#define BYTE_PTR(bp) (*(byte *)bp)
#define WORD_PTR(bp) (*(word *)bp)
#define UWORD_PTR(bp) (*(uword *)bp)
#else
#define BYTE_PTR(bp) ((byte)((bp)[0]))
#define WORD_PTR(bp) ((word)((bp)[0] | ((bp)[1] << 8)))
#define UWORD_PTR(bp) ((uword)((bp)[0] | ((bp)[1] << 8)))
#define TO_UWORD(w) ((uword)((w)))
#define MOD_ADDR 0x1000
#define DEF_CALL 0x0800
#define DEF_CALLSZ 0x0800
#define DEF_ENTRYSZ 6
#define MEM_SIZE 65536
byte mem_data[MEM_SIZE];
uword sp = 0x01FE, fp = 0xFFFF, heap = 0x0200, deftbl = DEF_CALL, lastdef = DEF_CALL;
#define PHA(b) (mem_data[sp--]=(b))
#define PLA (mem_data[++sp])
#endif
#define TO_UWORD(w) ((uword)((w)))
/*
* 6502 memory map
*/
#define MOD_ADDR 0x1000
#define DEF_CALL 0x0300
#define DEF_CALLSZ 0x0B00
#define DEF_ENTRYSZ 6
#define MEM_SIZE 0x00010000
byte mem6502[MEM_SIZE];
uword sp = 0x01FE, fp = 0xFF00, heap = 0x0200, deftbl = DEF_CALL, lastdef = DEF_CALL;
/*
* 6502 H/W stack
*/
#define PHA(b) (mem6502[sp--]=(b))
#define PLA (mem6502[++sp])
#define EVAL_STACKSZ 16
#define PUSH(v) (*(--esp))=(v)
#define POP ((word)(*(esp++)))
#define UPOP ((uword)(*(esp++)))
#define TOS (esp[0])
/*
* VM eval stack
*/
#define PUSH(v) (*(--esp))=(v)
#define POP ((word)(*(esp++)))
#define UPOP ((uword)(*(esp++)))
#define TOS (esp[0])
word eval_stack[EVAL_STACKSZ];
word *esp = &eval_stack[EVAL_STACKSZ];
/*
* Symbol table
*/
#define SYMTBLSZ 1024
#define SYMSZ 16
byte symtbl[SYMTBLSZ];
byte *lastsym = symtbl;
/*
* Predef.
*/
void interp(code *ip);
/*
* CMDSYS exports
*/
@ -80,7 +101,196 @@ char *syslib_exp[] = {
"ISULE",
0
};
/*
* TERM I/O structure for CLI interface
*/
struct termios org_tio;
/*
* Predefine
*/
void interp(code *ip);
void pfail(const char *msg)
{
fflush(stdout);
perror(msg);
exit(1);
}
/*
* Simple I/O routines
*/
#define rts \
{ \
word pc; \
pc = mpu->memory[++mpu->registers->s + 0x100]; \
pc |= mpu->memory[++mpu->registers->s + 0x100] << 8; \
return pc + 1; \
}
//
// CFFA1 emulation
//
#define CFFADest 0x00
#define CFFAFileName 0x02
#define CFFAOldName 0x04
#define CFFAFileType 0x06
#define CFFAAuxType 0x07
#define CFFAFileSize 0x09
#define CFFAEntryPtr 0x0B
int save(M6502 *mpu, uword address, unsigned length, const char *path)
{
FILE *file;
int count;
if (!(file = fopen(path, "wb")))
return 0;
while ((count = fwrite(mpu->memory + address, 1, length, file)))
{
address += count;
length -= count;
}
fclose(file);
return 1;
}
int load(M6502 *mpu, uword address, const char *path)
{
FILE *file;
int count;
size_t max = 0x10000 - address;
if (!(file = fopen(path, "rb")))
return 0;
while ((count = fread(mpu->memory + address, 1, max, file)) > 0)
{
address += count;
max -= count;
}
fclose(file);
return 1;
}
int cffa1(M6502 *mpu, uword address, byte data)
{
char *fileptr, filename[64];
int addr;
struct stat sbuf;
switch (mpu->registers->x)
{
case 0x02: /* quit */
exit(0);
break;
case 0x14: /* find dir entry */
addr = mpu->memory[CFFAFileName] | (mpu->memory[CFFAFileName + 1] << 8);
memset(filename, 0, 64);
strncpy(filename, (char *)(mpu->memory + addr + 1), mpu->memory[addr]);
strcat(filename, "#FE1000");
if (!(stat(filename, &sbuf)))
{
/* DirEntry @ $9100 */
mpu->memory[CFFAEntryPtr] = 0x00;
mpu->memory[CFFAEntryPtr + 1] = 0x91;
mpu->memory[0x9115] = sbuf.st_size;
mpu->memory[0x9116] = sbuf.st_size >> 8;
mpu->registers->a = 0;
}
else
mpu->registers->a = -1;
break;
case 0x22: /* load file */
addr = mpu->memory[CFFAFileName] | (mpu->memory[CFFAFileName + 1] << 8);
memset(filename, 0, 64);
strncpy(filename, (char *)(mpu->memory + addr + 1), mpu->memory[addr]);
strcat(filename, "#FE1000");
addr = mpu->memory[CFFADest] | (mpu->memory[CFFADest + 1] << 8);
mpu->registers->a = load(mpu, addr, filename) - 1;
break;
default:
{
char state[64];
fprintf(stderr, "Unimplemented CFFA function: %02X\n", mpu->registers->x);
M6502_dump(mpu, state);
fflush(stdout);
fprintf(stderr, "\nCFFA1 %s\n", state);
pfail("ABORT");
}
break;
}
rts;
}
//
// Character I/O emulation
//
int paused = 0;
unsigned char keypending = 0;
int bye(M6502 *mpu, uword addr, byte data) { exit(0); return 0; }
int cout(M6502 *mpu, uword addr, byte data) { if (mpu->registers->a == 0x8D) putchar('\n'); putchar(mpu->registers->a & 0x7F); fflush(stdout); rts; }
unsigned char keypressed(M6502 *mpu)
{
unsigned char cin, cext[2];
if (read(STDIN_FILENO, &cin, 1) > 0)
{
if (cin == 0x03) // CTRL-C
{
mpu->flags |= M6502_SingleStep;
paused = 1;
}
if (cin == 0x1B) // Look for left arrow
{
if (read(STDIN_FILENO, cext, 2) == 2 && cext[0] == '[' && cext[1] == 'D')
cin = 0x08;
}
keypending = cin | 0x80;
}
return keypending & 0x80;
}
unsigned char keyin(M6502 *mpu)
{
unsigned char cin;
if (!keypending)
keypressed(mpu);
cin = keypending;
keypending = 0;
return cin;
}
int rd6820kbdctl(M6502 *mpu, uword addr, byte data) { return keypressed(mpu); }
int rd6820vidctl(M6502 *mpu, uword addr, byte data) { return 0x00; }
int rd6820kbd(M6502 *mpu, uword addr, byte data) { return keyin(mpu); }
int rd6820vid(M6502 *mpu, uword addr, byte data) { return 0x80; }
int wr6820vid(M6502 *mpu, uword addr, byte data) { if (data == 0x8D) putchar('\n'); putchar(data & 0x7F); fflush(stdout); return 0; }
int setTraps(M6502 *mpu)
{
/* Apple 1 memory-mapped IO */
M6502_setCallback(mpu, read, 0xD010, rd6820kbd);
M6502_setCallback(mpu, read, 0xD011, rd6820kbdctl);
M6502_setCallback(mpu, read, 0xD012, rd6820vid);
M6502_setCallback(mpu, write, 0xD012, wr6820vid);
M6502_setCallback(mpu, read, 0xD013, rd6820vidctl);
/* CFFA1 and ROM calls */
M6502_setCallback(mpu, call, 0x9000, bye);
M6502_setCallback(mpu, call, 0x900C, cffa1);
M6502_setCallback(mpu, call, 0xFFEF, cout);
return 0;
}
void resetInput(void)
{
tcsetattr(STDIN_FILENO, TCSANOW, &org_tio);
}
void setRawInput(void)
{
struct termios termio;
// Save input settings.
tcgetattr(STDIN_FILENO, &termio); /* save current port settings */
memcpy(&org_tio, &termio, sizeof(struct termios));
termio.c_cflag = /*BAUDRATE | CRTSCTS |*/ CS8 | CLOCAL | CREAD;
termio.c_iflag = IGNPAR;
termio.c_oflag = 0;
termio.c_lflag = 0; /* set input mode (non-canonical, no echo,...) */
termio.c_cc[VTIME] = 0; /* inter-character timer unused */
termio.c_cc[VMIN] = 0; /* non-blocking read */
tcsetattr(STDIN_FILENO, TCSANOW, &termio);
atexit(resetInput);
}
/*
* Utility routines.
*
@ -190,7 +400,6 @@ uword add_tbl(byte *dci, int val, byte **last)
*(*last)++ = val >> 8;
return 0;
}
/*
* Symbol table routines.
*/
@ -207,15 +416,14 @@ uword add_sym(byte *sym, int addr)
{
return add_tbl(sym, addr, &lastsym);
}
/*
* Module routines.
*/
uword defcall_add(int bank, int addr)
{
mem_data[lastdef] = bank ? 2 : 1;
mem_data[lastdef + 1] = addr;
mem_data[lastdef + 2] = addr >> 8;
mem6502[lastdef] = bank ? 2 : 1;
mem6502[lastdef + 1] = addr;
mem6502[lastdef + 2] = addr >> 8;
return lastdef++;
}
uword def_lookup(byte *cdd, int defaddr)
@ -225,7 +433,7 @@ uword def_lookup(byte *cdd, int defaddr)
{
if ((cdd[i * 4 + 1] | (cdd[i * 4 + 2] << 8)) == defaddr)
{
calldef = cdd + i * 4 - mem_data;
calldef = cdd + i * 4 - mem6502;
break;
}
}
@ -308,8 +516,8 @@ int load_mod(byte *mod)
/*
* Read in remainder of module into memory for fixups.
*/
memcpy(mem_data + modaddr, moddep, len);
while ((len = read(fd, mem_data + end, 4096)) > 0)
memcpy(mem6502 + modaddr, moddep, len);
while ((len = read(fd, mem6502 + end, 4096)) > 0)
end += len;
close(fd);
/*
@ -318,7 +526,7 @@ int load_mod(byte *mod)
modfix = modaddr - hdrlen + 2; // - MOD_ADDR;
bytecode += modfix - MOD_ADDR;
end = modaddr - hdrlen + modsize + 2;
rld = mem_data + end; // Re-Locatable Directory
rld = mem6502 + end; // Re-Locatable Directory
esd = rld; // Extern+Entry Symbol Directory
while (*esd != 0x00) // Scan to end of RLD
esd += 4;
@ -357,7 +565,7 @@ int load_mod(byte *mod)
rld[0] = 0; // Set call code to 0
rld[1] = addr;
rld[2] = addr >> 8;
end = rld - mem_data + 4;
end = rld - mem6502 + 4;
}
else
{
@ -366,9 +574,9 @@ int load_mod(byte *mod)
{
addr += modfix;
if (rld[0] & 0x80)
fixup = (mem_data[addr] | (mem_data[addr + 1] << 8));
fixup = (mem6502[addr] | (mem6502[addr + 1] << 8));
else
fixup = mem_data[addr];
fixup = mem6502[addr];
if (rld[0] & 0x10)
{
if (show_state) printf("\tEXTERN[$%02X] ", rld[3]);
@ -392,13 +600,13 @@ int load_mod(byte *mod)
if (rld[0] & 0x80)
{
if (show_state) printf("WORD");
mem_data[addr] = fixup;
mem_data[addr + 1] = fixup >> 8;
mem6502[addr] = fixup;
mem6502[addr + 1] = fixup >> 8;
}
else
{
if (show_state) printf("BYTE");
mem_data[addr] = fixup;
mem6502[addr] = fixup;
}
}
else
@ -444,14 +652,12 @@ int load_mod(byte *mod)
*/
if (init)
{
interp(mem_data + init + modfix - MOD_ADDR);
interp(mem6502 + init + modfix - MOD_ADDR);
// release_heap(init + modfix - MOD_ADDR); // Free up init code
return POP;
}
return 0;
}
void interp(code *ip);
void call(uword pc)
{
unsigned int i, s;
@ -459,11 +665,11 @@ void call(uword pc)
char c, sz[64];
if (show_state)
printf("\nCall: %s\n", mem_data[pc] ? syslib_exp[mem_data[pc] - 1] : "BYTECODE");
switch (mem_data[pc++])
printf("\nCall: %s\n", mem6502[pc] ? syslib_exp[mem6502[pc] - 1] : "BYTECODE");
switch (mem6502[pc++])
{
case 0: // BYTECODE in mem_data
interp(mem_data + (mem_data[pc] + (mem_data[pc + 1] << 8)));
case 0: // BYTECODE in mem6502
interp(mem6502 + (mem6502[pc] + (mem6502[pc + 1] << 8)));
break;
case 1: // CMDSYS call
printf("CMD call code!\n");
@ -483,10 +689,10 @@ void call(uword pc)
break;
case 5: // LIBRARY STDLIB::PUTS
s = POP;
i = mem_data[s++];
i = mem6502[s++];
while (i--)
{
c = mem_data[s++];
c = mem6502[s++];
if (c == 0x0D)
c = '\n';
putchar(c);
@ -504,9 +710,9 @@ void call(uword pc)
putchar(c);
fgets(sz, 63, stdin);
for (i = 0; sz[i]; i++)
mem_data[0x200 + i] = sz[i];
mem_data[0x200 + i] = 0;
mem_data[0x1FF] = i;
mem6502[0x200 + i] = sz[i];
mem6502[0x200 + i] = 0;
mem6502[0x1FF] = i;
PUSH(0x1FF);
break;
case 9: // LIBRARY STDLIB::PUTB
@ -524,11 +730,10 @@ void call(uword pc)
PUSH(b % a);
break;
default:
printf("\nUnimplemented call code:$%02X\n", mem_data[pc - 1]);
printf("\nUnimplemented call code:$%02X\n", mem6502[pc - 1]);
exit(1);
}
}
/*
* OPCODE TABLE
*
@ -544,6 +749,7 @@ OPTBL DW CN,CN,CN,CN,CN,CN,CN,CN ; 00 02 04 06
DW NEG,COMP,BAND,IOR,XOR,SHL,SHR,IDXW ; 90 92 94 96 98 9A 9C 9E
DW BRGT,BRLT,INCBRLE,ADDBRLE,DECBRGE,SUBBRGE,BRAND,BROR ; A0 A2 A4 A6 A8 AA AC AE
DW ADDLB,ADDLW,ADDAB,ADDAW,IDXLB,IDXLW,IDXAB,IDXAW ; B0 B2 B4 B6 B8 BA BC BE
DW NATV,JUMPZ,JUMP ; C0 C2 C4
*/
void interp(code *ip)
{
@ -554,16 +760,16 @@ void interp(code *ip)
{
if ((esp - eval_stack) < 0 || (esp - eval_stack) > EVAL_STACKSZ)
{
printf("Eval stack over/underflow! - $%04X: $%02X [%d]\n", previp - mem_data, *previp, EVAL_STACKSZ - (esp - eval_stack));
printf("Eval stack over/underflow! - $%04X: $%02X [%d]\n", (unsigned int)(previp - mem6502), (unsigned int)*previp, (int)(EVAL_STACKSZ - (esp - eval_stack)));
show_state = 1;
}
if (show_state)
{
char cmdline[16];
word *dsp = &eval_stack[EVAL_STACKSZ - 1];
printf("$%04X: $%02X [ ", ip - mem_data, *ip);
printf("$%04X: $%02X [ ", (unsigned int)(ip - mem6502), (unsigned int)*ip);
while (dsp >= esp)
printf("$%04X ", (*dsp--) & 0xFFFF);
printf("$%04X ", (unsigned int)((*dsp--) & 0xFFFF));
printf("]\n");
fgets(cmdline, 15, stdin);
}
@ -628,7 +834,7 @@ void interp(code *ip)
ip += 2;
break;
case 0x2E: // CS: TOS = CONSTANTSTRING (IP)
PUSH(ip - mem_data);
PUSH(ip - mem6502);
ip += BYTE_PTR(ip) + 1;
break;
/*
@ -732,7 +938,7 @@ void interp(code *ip)
break;
}
else
ip += 4;
ip += 4;
}
break;
case 0x54: // CALL : TOFP = IP, IP = (IP) ; call
@ -754,10 +960,10 @@ void interp(code *ip)
while (parmcnt--)
{
val = POP;
mem_data[fp + parmcnt * 2 + 0] = val;
mem_data[fp + parmcnt * 2 + 1] = val >> 8;
mem6502[fp + parmcnt * 2 + 0] = val;
mem6502[fp + parmcnt * 2 + 1] = val >> 8;
if (show_state)
printf("< $%04X: $%04X > ", fp + parmcnt * 2 + 0, mem_data[fp + parmcnt * 2 + 0] | (mem_data[fp + parmcnt * 2 + 1] >> 8));
printf("< $%04X: $%04X > ", fp + parmcnt * 2 + 0, mem6502[fp + parmcnt * 2 + 0] | (mem6502[fp + parmcnt * 2 + 1] >> 8));
}
if (show_state)
printf("\n");
@ -775,39 +981,39 @@ void interp(code *ip)
*/
case 0x60: // LB : TOS = BYTE (TOS)
ea = TO_UWORD(POP);
PUSH(mem_data[ea]);
PUSH(mem6502[ea]);
break;
case 0x62: // LW : TOS = WORD (TOS)
ea = UPOP;
PUSH(mem_data[ea] | (mem_data[ea + 1] << 8));
PUSH(mem6502[ea] | (mem6502[ea + 1] << 8));
break;
case 0x64: // LLB : TOS = LOCALBYTE [IP]
PUSH(mem_data[TO_UWORD(fp + BYTE_PTR(ip))]);
PUSH(mem6502[TO_UWORD(fp + BYTE_PTR(ip))]);
ip++;
break;
case 0x66: // LLW : TOS = LOCALWORD [IP]
ea = TO_UWORD(fp + BYTE_PTR(ip));
PUSH(mem_data[ea] | (mem_data[ea + 1] << 8));
PUSH(mem6502[ea] | (mem6502[ea + 1] << 8));
ip++;
break;
case 0x68: // LAB : TOS = BYTE (IP)
PUSH(mem_data[UWORD_PTR(ip)]);
PUSH(mem6502[UWORD_PTR(ip)]);
ip += 2;
break;
case 0x6A: // LAW : TOS = WORD (IP)
ea = UWORD_PTR(ip);
PUSH(mem_data[ea] | (mem_data[ea + 1] << 8));
PUSH(mem6502[ea] | (mem6502[ea + 1] << 8));
ip += 2;
break;
case 0x6C: // DLB : TOS = TOS, LOCALBYTE [IP] = TOS
mem_data[TO_UWORD(fp + BYTE_PTR(ip))] = TOS;
mem6502[TO_UWORD(fp + BYTE_PTR(ip))] = TOS;
TOS = TOS & 0xFF;
ip++;
break;
case 0x6E: // DLW : TOS = TOS, LOCALWORD [IP] = TOS
ea = TO_UWORD(fp + BYTE_PTR(ip));
mem_data[ea] = TOS;
mem_data[ea + 1] = TOS >> 8;
mem6502[ea] = TOS;
mem6502[ea + 1] = TOS >> 8;
ip++;
break;
/*
@ -816,45 +1022,45 @@ void interp(code *ip)
case 0x70: // SB : BYTE (TOS-1) = TOS
ea = UPOP;
val = POP;
mem_data[ea] = val;
mem6502[ea] = val;
break;
case 0x72: // SW : WORD (TOS-1) = TOS
ea = UPOP;
val = POP;
mem_data[ea] = val;
mem_data[ea + 1] = val >> 8;
mem6502[ea] = val;
mem6502[ea + 1] = val >> 8;
break;
case 0x74: // SLB : LOCALBYTE [TOS] = TOS-1
mem_data[TO_UWORD(fp + BYTE_PTR(ip))] = POP;
mem6502[TO_UWORD(fp + BYTE_PTR(ip))] = POP;
ip++;
break;
case 0x76: // SLW : LOCALWORD [TOS] = TOS-1
ea = TO_UWORD(fp + BYTE_PTR(ip));
val = POP;
mem_data[ea] = val;
mem_data[ea + 1] = val >> 8;
mem6502[ea] = val;
mem6502[ea + 1] = val >> 8;
ip++;
break;
case 0x78: // SAB : BYTE (IP) = TOS
mem_data[UWORD_PTR(ip)] = POP;
mem6502[UWORD_PTR(ip)] = POP;
ip += 2;
break;
case 0x7A: // SAW : WORD (IP) = TOS
ea = UWORD_PTR(ip);
val = POP;
mem_data[ea] = val;
mem_data[ea + 1] = val >> 8;
mem6502[ea] = val;
mem6502[ea + 1] = val >> 8;
ip += 2;
break;
case 0x7C: // DAB : TOS = TOS, BYTE (IP) = TOS
mem_data[UWORD_PTR(ip)] = TOS;
mem6502[UWORD_PTR(ip)] = TOS;
TOS = TOS & 0xFF;
ip += 2;
break;
case 0x7E: // DAW : TOS = TOS, WORD (IP) = TOS
ea = UWORD_PTR(ip);
mem_data[ea] = TOS;
mem_data[ea + 1] = TOS >> 8;
mem6502[ea] = TOS;
mem6502[ea + 1] = TOS >> 8;
ip += 2;
break;
/*
@ -1016,100 +1222,134 @@ void interp(code *ip)
* 0xB0-0xBF
*/
case 0xB0: // ADDLB : TOS = TOS + LOCALBYTE[IP]
val = POP + mem_data[TO_UWORD(fp + BYTE_PTR(ip))];
val = POP + mem6502[TO_UWORD(fp + BYTE_PTR(ip))];
PUSH(val);
ip++;
break;
case 0xB2: // ADDLW : TOS = TOS + LOCALWORD[IP]
ea = TO_UWORD(fp + BYTE_PTR(ip));
val = POP + (mem_data[ea] | (mem_data[ea + 1] << 8));
val = POP + (mem6502[ea] | (mem6502[ea + 1] << 8));
PUSH(val);
ip++;
break;
case 0xB4: // ADDAB : TOS = TOS + BYTE[IP]
val = POP + mem_data[UWORD_PTR(ip)];
val = POP + mem6502[UWORD_PTR(ip)];
PUSH(val);
ip += 2;
break;
case 0xB6: // ADDAW : TOS = TOS + WORD[IP]
ea = UWORD_PTR(ip);
val = POP + (mem_data[ea] | (mem_data[ea + 1] << 8));
val = POP + (mem6502[ea] | (mem6502[ea + 1] << 8));
PUSH(val);
ip += 2;
break;
case 0xB8: // IDXLB : TOS = TOS + LOCALBYTE[IP]*2
val = POP + mem_data[TO_UWORD(fp + BYTE_PTR(ip))] * 2;
val = POP + mem6502[TO_UWORD(fp + BYTE_PTR(ip))] * 2;
PUSH(val);
ip++;
break;
case 0xBA: // IDXLW : TOS = TOS + LOCALWORD[IP]*2
ea = TO_UWORD(fp + BYTE_PTR(ip));
val = POP + (mem_data[ea] | (mem_data[ea + 1] << 8)) * 2;
val = POP + (mem6502[ea] | (mem6502[ea + 1] << 8)) * 2;
PUSH(val);
ip++;
break;
case 0xBC: // IDXAB : TOS = TOS + BYTE[IP]*2
val = POP + mem_data[UWORD_PTR(ip)] * 2;
val = POP + mem6502[UWORD_PTR(ip)] * 2;
PUSH(val);
ip += 2;
break;
case 0xBE: // IDXAW : TOS = TOS + WORD[IP]*2
ea = UWORD_PTR(ip);
val = POP + (mem_data[ea] | (mem_data[ea + 1] << 8)) * 2;
val = POP + (mem6502[ea] | (mem6502[ea + 1] << 8)) * 2;
PUSH(val);
ip += 2;
break;
case 0xC0: // NATV - unused inthis VM
break;
case 0xC2: // JUMPZ
if (!POP)
ip = &mem6502[WORD_PTR(ip)] ;
else
ip += 2;
break;
case 0xC4: // JUMP
ip = &mem6502[WORD_PTR(ip)];
break;
/*
* Odd codes and everything else are errors.
*/
default:
fprintf(stderr, "Illegal opcode 0x%02X @ 0x%04X\n", ip[-1], ip - mem_data);
fprintf(stderr, "Illegal opcode 0x%02X @ 0x%04X\n", (unsigned int)ip[-1], (unsigned int)(ip - mem6502));
exit(-1);
}
}
}
int main(int argc, char **argv)
{
byte dci[32];
int i;
byte dci[32];
int i;
char *interpfile = "A1PLASMA#060280";
M6502 *mpu = M6502_new(0, mem6502, 0);
if (--argc)
{
argv++;
if ((*argv)[0] == '-' && (*argv)[1] == 's')
while (argc && (*argv)[0] == '-')
{
show_state = 1;
argc--;
argv++;
}
/*
* Add default library.
*/
for (i = 0; syslib_exp[i]; i++)
{
mem_data[i] = i;
stodci(syslib_exp[i], dci);
add_sym(dci, i+1);
}
if (argc)
{
stodci(*argv, dci);
if (show_state) dump_sym();
load_mod(dci);
if (show_state) dump_sym();
if ((*argv)[1] == 's')
show_state = 1;
else if ((*argv)[1] == 't')
mpu->flags |= M6502_SingleStep;
argc--;
argv++;
}
if (argc)
interpfile = *argv;
}
/*
* Add default library.
*/
for (i = 0; syslib_exp[i]; i++)
{
mem6502[i] = i;
stodci(syslib_exp[i], dci);
add_sym(dci, i+1);
}
/*
* Load module from command line
*/
// PLVMC version
//stodci(interpfile, dci);
//if (show_state) dump_sym();
//load_mod(dci);
//if (show_state) dump_sym();
// lib6502 version
if (!load(mpu, 0x280, interpfile))
pfail(interpfile);
setRawInput();
setTraps(mpu);
M6502_reset(mpu);
mpu->registers->pc = 0x0280;
while (M6502_run(mpu))
{
char state[64];
char insn[64];
M6502_dump(mpu, state);
M6502_disassemble(mpu, mpu->registers->pc, insn);
printf("%s : %s\r\n", state, insn);
if (paused || (keypressed(mpu) && keypending == 0x83))
{
stodci(*argv, dci);
call(lookup_sym(dci));
}
if (esp != &eval_stack[EVAL_STACKSZ])
{
printf("Eval stack pointer mismatch at end of execution = %d.\n", EVAL_STACKSZ - (esp - eval_stack));
keypending = 0;
while (!keypressed(mpu));
if (keypending == (0x80|'C'))
paused = 0;
else if (keypending == (0x80|'Q'))
break;
keypending = 0;
}
}
M6502_delete(mpu);
if (esp != &eval_stack[EVAL_STACKSZ])
printf("Eval stack pointer mismatch at end of execution = %d.\n", (unsigned int)(EVAL_STACKSZ - (esp - eval_stack)));
return 0;
}