mirror of
https://github.com/mist64/perfect6502.git
synced 2024-12-27 20:29:43 +00:00
b2cce88620
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.
313 lines
3.7 KiB
C
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;
|
|
}
|