1
0
mirror of https://github.com/mist64/perfect6502.git synced 2024-06-01 10:41:28 +00:00
perfect6502/emu.c
Michael Steil b2cce88620 optimizations (~25%) and cleanup
Optimizations:
1. When a transistor is turned on, only add one of the nodes it
   controls to listout, otherwise group calculation would be done twice
   for this group. This simplifies recalcNodeList(). (This required
   the following change: Instead of adding the nodes that control
   transistors that have changed to listout, put the nodes that are
   switched by transistors on listout.)
2. The group value is calculated while collecting nodes, and the enum
   group_contains_value makes sure we don't check for weaker value
   indicators than have already been established.
3. listout is now a set, no node will be visited twice for group
   calculation, within one interation.
4. When setting input pins of the package to a value, only recalc the
   node if it actually changes.
5. Toggling a transistor is done by assigning it the group value
   instead of the inverse of its value.

Cleanup:
* Merge the concept of listin with the concept of nodes that change
  from the outside and trigger a recalc.
2014-11-28 07:04:07 +01:00

313 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 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;
}