mirror of
https://github.com/mist64/perfect6502.git
synced 2024-12-27 20:29:43 +00:00
314 lines
3.7 KiB
C
314 lines
3.7 KiB
C
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
|
|
typedef unsigned char uint8_t;
|
|
typedef unsigned short uint16_t;
|
|
|
|
typedef uint8_t BOOL;
|
|
#define YES 1
|
|
#define NO 0
|
|
|
|
typedef uint8_t step_t;
|
|
|
|
static step_t t; /* step inside the instruction */
|
|
static uint8_t ir; /* instruction register */
|
|
static uint8_t operand;
|
|
static uint16_t PC;
|
|
static uint8_t A, X, Y, S, P;
|
|
static uint8_t temp_lo, temp_hi;
|
|
|
|
#define TEMP16 (temp_lo | temp_hi << 8)
|
|
|
|
static uint16_t AB;
|
|
static uint8_t DB;
|
|
static BOOL RW;
|
|
extern uint8_t memory[65536];
|
|
|
|
#define RW_WRITE 0
|
|
#define RW_READ 1
|
|
|
|
uint8_t
|
|
LOAD(uint16_t a)
|
|
{
|
|
return memory[a];
|
|
}
|
|
|
|
#define T1 (1<<0)
|
|
#define T2 (1<<1)
|
|
#define T3 (1<<2)
|
|
#define T4 (1<<3)
|
|
#define T5 (1<<4)
|
|
#define T6 (1<<5)
|
|
#define T7 (1<<6)
|
|
|
|
#define IS_T1 (t & T1)
|
|
#define IS_T2 (t & T2)
|
|
#define IS_T3 (t & T3)
|
|
#define IS_T4 (t & T4)
|
|
#define IS_T5 (t & T5)
|
|
#define IS_T6 (t & T6)
|
|
#define IS_T7 (t & T7)
|
|
|
|
void
|
|
IFETCH()
|
|
{
|
|
AB = PC;
|
|
RW = RW_READ;
|
|
t = T1;
|
|
}
|
|
|
|
void
|
|
init()
|
|
{
|
|
t = T1;
|
|
ir = 0;
|
|
PC = 0;
|
|
A = 0;
|
|
X = 0;
|
|
Y = 0;
|
|
S = 0;
|
|
P = 0;
|
|
IFETCH();
|
|
}
|
|
|
|
void
|
|
EOI_INCPC_READPC()
|
|
{
|
|
PC++;
|
|
t <<= 1;
|
|
AB = PC;
|
|
RW = RW_READ;
|
|
}
|
|
|
|
void
|
|
DB_TO_ADDRLO()
|
|
{
|
|
temp_lo = DB;
|
|
}
|
|
void
|
|
DB_TO_ADDRHI()
|
|
{
|
|
temp_hi = DB;
|
|
}
|
|
|
|
void
|
|
EOI()
|
|
{
|
|
t <<= 1;
|
|
}
|
|
|
|
void
|
|
EOI_INCPC()
|
|
{
|
|
PC++;
|
|
EOI();
|
|
}
|
|
|
|
void
|
|
EOI_INCPC_READADDR()
|
|
{
|
|
EOI_INCPC();
|
|
AB = TEMP16;
|
|
RW = RW_READ;
|
|
}
|
|
|
|
void
|
|
EOI_INCPC_WRITEADDR()
|
|
{
|
|
EOI_INCPC();
|
|
AB = TEMP16;
|
|
RW = RW_WRITE;
|
|
}
|
|
|
|
void
|
|
pha()
|
|
{
|
|
printf("%s",__func__);
|
|
if (IS_T2) {
|
|
S--;
|
|
EOI();
|
|
} else if (IS_T3) {
|
|
AB = 0x0100 + S;
|
|
DB = A;
|
|
RW = RW_WRITE;
|
|
S++;
|
|
EOI();
|
|
} else if (IS_T4) {
|
|
IFETCH();
|
|
}
|
|
}
|
|
|
|
void
|
|
plp()
|
|
{
|
|
printf("%s",__func__);
|
|
if (IS_T2) {
|
|
EOI();
|
|
} else if (IS_T3) {
|
|
temp_lo = S;
|
|
temp_hi = 0x01;
|
|
AB = TEMP16;
|
|
RW = RW_READ;
|
|
S++;
|
|
EOI();
|
|
} else if (IS_T4) {
|
|
temp_lo = S;
|
|
AB = TEMP16;
|
|
RW = RW_READ;
|
|
EOI();
|
|
} else if (IS_T5) {
|
|
P = DB;
|
|
IFETCH();
|
|
}
|
|
}
|
|
|
|
void
|
|
txs()
|
|
{
|
|
printf("%s",__func__);
|
|
/* T2 */
|
|
S = X;
|
|
IFETCH();
|
|
}
|
|
|
|
void
|
|
lda_imm()
|
|
{
|
|
printf("%s",__func__);
|
|
/* T2 */
|
|
A = DB;
|
|
PC++;
|
|
IFETCH();
|
|
}
|
|
|
|
void
|
|
ldx_imm()
|
|
{
|
|
printf("%s",__func__);
|
|
/* T2 */
|
|
X = DB;
|
|
PC++;
|
|
IFETCH();
|
|
}
|
|
|
|
void
|
|
ldy_imm()
|
|
{
|
|
printf("%s",__func__);
|
|
/* T2 */
|
|
Y = DB;
|
|
PC++;
|
|
IFETCH();
|
|
}
|
|
|
|
void
|
|
lda_abs()
|
|
{
|
|
printf("%s",__func__);
|
|
if (IS_T2) {
|
|
DB_TO_ADDRLO();
|
|
EOI_INCPC_READPC();
|
|
} else if (IS_T3) {
|
|
DB_TO_ADDRHI();
|
|
EOI_INCPC_READADDR();
|
|
} else if (IS_T4) {
|
|
A = DB;
|
|
IFETCH();
|
|
}
|
|
}
|
|
|
|
void
|
|
sta_abs()
|
|
{
|
|
printf("%s",__func__);
|
|
if (IS_T2) {
|
|
DB_TO_ADDRLO();
|
|
EOI_INCPC_READPC();
|
|
} else if (IS_T3) {
|
|
DB_TO_ADDRHI();
|
|
DB = A;
|
|
EOI_INCPC_WRITEADDR();
|
|
} else if (IS_T4) {
|
|
IFETCH();
|
|
}
|
|
}
|
|
|
|
static int cycle = 0;
|
|
|
|
void
|
|
emulate_step()
|
|
{
|
|
/* memory */
|
|
if (RW == RW_READ) {
|
|
printf("PEEK(%04X)=%02X ", AB, memory[AB]);
|
|
DB = memory[AB];
|
|
} else {
|
|
printf("POKE %04X, %02X ", AB, DB);
|
|
memory[AB] = DB;
|
|
}
|
|
|
|
//printf("T%d PC=%04X ", t, PC);
|
|
if (IS_T1) { /* T0: get result of IFETCH */
|
|
printf("fetch");
|
|
ir = DB;
|
|
EOI_INCPC_READPC();
|
|
} else {
|
|
//printf ("IR: %02X ", ir);
|
|
switch (ir) {
|
|
case 0x28: plp(); break;
|
|
case 0x48: pha(); break;
|
|
case 0x8D: sta_abs(); break;
|
|
case 0x9A: txs(); break;
|
|
case 0xA0: ldy_imm(); break;
|
|
case 0xA2: ldx_imm(); break;
|
|
case 0xA9: lda_imm(); break;
|
|
case 0xAD: lda_abs(); break;
|
|
default:
|
|
printf("unimplemented opcode: %02X\n", ir);
|
|
exit(0);
|
|
}
|
|
}
|
|
|
|
printf("\ncycle:%d phi0:1 AB:%04X D:%02X RnW:%d PC:%04X A:%02X X:%02X Y:%02X SP:%02X P:%02X IR:%02X",
|
|
cycle,
|
|
AB,
|
|
DB,
|
|
RW,
|
|
PC,
|
|
A,
|
|
X,
|
|
Y,
|
|
S,
|
|
P,
|
|
ir);
|
|
|
|
}
|
|
|
|
void
|
|
setup_emu()
|
|
{
|
|
init();
|
|
}
|
|
|
|
void
|
|
reset_emu()
|
|
{
|
|
init();
|
|
PC = memory[0xFFFC] | memory[0xFFFD] << 8;
|
|
printf("PC %x\n", PC);
|
|
IFETCH();
|
|
}
|
|
|
|
int
|
|
emu_measure_instruction()
|
|
{
|
|
|
|
for (;;) {
|
|
printf("cycle %d: ", cycle);
|
|
emulate_step();
|
|
printf("\n");
|
|
cycle++;
|
|
}
|
|
return 0;
|
|
}
|