加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
文件
克隆/下载
cpu.c 15.33 KB
一键复制 编辑 原始数据 按行查看 历史
小白杨 提交于 2024-01-09 16:52 . :boom:Improve ppu render preference
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572
#include <malloc.h>
#include "hs/cpu.h"
#include "bus.h"
#include "6502.h"
#define IS_IRQ_TRIGGER(cpu, t) \
((((cpu->irq)>>t)&0x01)==0x01) \
#define CLEAR_IRQ(cpu, t) \
(cpu->irq = (cpu->irq & (~(1<<t)))); \
#define TRIGGER_IRQ(cpu, t) \
(cpu->irq = ((cpu->irq)|(1<<t)));\
#define UTF8_CHAR_CACHE (10240)
extern CPU *ines_cpu_new() {
CPU *cpu = malloc(sizeof(CPU));
// A, X, Y = 0
cpu->a = 0;
cpu->x = 0;
cpu->y = 0;
cpu->irq = 0;
cpu->cycle = 0;
cpu->suspend = 0;
cpu->synchronized = 0;
// S = $FD[3]
cpu->s = STACK_PTR_SPOS;
// P = $34 (IRQ disabled)
cpu->p = DEFAULT_STATUS_VAL;
TRIGGER_IRQ(cpu, RESET)
return cpu;
}
static void ines_xy_inc_impl(CPU *cpu, bool x) {
uint8 tmp;
if (x) {
tmp = cpu->x = cpu->x + 1;
} else {
tmp = cpu->y = cpu->y + 1;
}
INES_NZS(cpu, tmp)
}
static void ines_beq_bne_impl(NesConsole *console, bool bne, AddressMode mode) {
CPU *cpu = console->cpu;
bool set = INES_CPU_STATE(cpu, ZERO)
if ((set && !bne) || (!set && bne)) {
cpu->cycle += 1;
uint16 base = cpu->pc + 1;
byte offset = (byte) ines_ops_operand(console, mode);
uint16 addr = base + offset;
INES_CPU_PAGE_CROSS(console, base, addr, 2)
cpu->pc = addr;
}
}
static inline void ines_jsr_impl(NesConsole *console) {
CPU *cpu = console->cpu;
ines_bus_stack_push0(console, cpu->pc + 1);
cpu->pc = ines_ops_decode_addr(console, Absolute, False);
}
static inline void ines_rts_impl(NesConsole *console) {
CPU *cpu = console->cpu;
cpu->pc = ines_bus_stack_pop0(console) + 1;
}
static inline void ines_logic_impl(NesConsole *console, Instruction is, AddressMode mode) {
CPU *cpu = console->cpu;
uint8 a = cpu->a;
uint8 b = ines_ops_operand0(console, mode, True);
if (is == AND) {
a = a & b;
} else if (is == EOR) {
a = a ^ b;
} else {
a = a | b;
}
INES_NZS(cpu, a)
cpu->a = a;
}
static inline void ines_ld_axy(NesConsole *console, Instruction is, AddressMode mode) {
CPU *cpu = console->cpu;
uint8 b = ines_ops_operand0(console, mode, True);
if (is == LDA) {
cpu->a = b;
} else if (is == LDX) {
cpu->x = b;
} else {
cpu->y = b;
}
INES_NZS(cpu, b)
}
static inline void ines_tax_impl(CPU *cpu) {
uint8 x = cpu->a;
cpu->x = x;
INES_NZS(cpu, x)
}
static inline void ines_txa_impl(CPU *cpu) {
uint8 a = cpu->x;
cpu->a = a;
INES_NZS(cpu, a)
}
static inline void ines_tay_impl(CPU *cpu) {
uint8 y = cpu->a;
cpu->y = y;
INES_NZS(cpu, y)
}
static inline void ines_tya_impl(CPU *cpu) {
uint8 a = cpu->y;
cpu->a = a;
INES_NZS(cpu, a)
}
static inline void ines_jmp_impl(NesConsole *console, AddressMode mode) {
uint16 addr = ines_ops_decode_addr(console, mode, False);
console->cpu->pc = addr;
}
static inline void ines_inc_impl(NesConsole *console, AddressMode mode) {
uint16 addr = ines_ops_decode_addr(console, mode, True);
uint8 b = ines_bus_read(console, addr);
b++;
INES_NZS(console->cpu, b)
ines_bus_write(console, addr, b);
}
static inline void ines_asl_lsr_impl(NesConsole *console, Instruction is, AddressMode mode) {
CPU *cpu = console->cpu;
uint8 b = ines_ops_operand(console, mode);
//The bit that was in bit 0 is shifted into the carry flag. Bit 7 is set to zero.
ines_cpu_state(cpu, CARRY, b & 1);
if (is == LSR) {
b >>= 1;
} else {
b <<= 1;
}
INES_NZS(cpu, b)
ines_ops_write(console, mode, b);
}
static inline void ines_ror_rol_impl(NesConsole *console, Instruction is, AddressMode mode) {
CPU *cpu = console->cpu;
bool carry;
uint8 c = cpu->p & 0x01;
uint8 b = ines_ops_operand(console, mode);
if (is == ROL) {
// Move each of the bits in either A or M one place to the left. Bit 0 is filled with the
// current value of the carry flag whilst the old bit 7 becomes the new carry flag value.
carry = (b & 0x80) == 0x80;
b >>= 1;
b = b & (c | 0xFE);
} else {
// Move each of the bits in either A or M one place to the right. Bit 7 is filled with the
// current value of the carry flag whilst the old bit 0 becomes the new carry flag value.
carry = (b & 0x01) == 0x01;
b <<= 1;
b = (b & 0xEF) | (c << 7);
}
ines_ops_write(console, mode, b);
ines_cpu_state(cpu, CARRY, carry);
INES_CPU_STATE_SET_NEG(cpu, b)
}
static void inline ines_xycmp_impl(NesConsole *console, Instruction is, AddressMode mode) {
uint8 a;
CPU *cpu = console->cpu;
uint8 b = ines_ops_operand(console, mode);
if (is == CPX) {
a = cpu->x;
} else {
a = cpu->y;
}
uint8 t = a - b;
ines_cpu_state(cpu, CARRY, a >= b);
INES_NZS(cpu, t)
}
static void inline ines_dec_impl(NesConsole *console, AddressMode mode) {
uint8 b = ines_ops_operand(console, mode);
b = b - 1;
INES_NZS(console->cpu, b);
}
static void inline ines_xydec_impl(NesConsole *console, Instruction is) {
uint8 b;
CPU *cpu = console->cpu;
if (is == DEX) {
b = --cpu->x;
} else {
b = --cpu->y;
}
INES_NZS(cpu, b)
}
static void inline ines_bit_impl(NesConsole *console, AddressMode mode) {
CPU *cpu = console->cpu;
uint8 b = ines_ops_operand(console, mode);
uint8 r = b & cpu->a;
ines_cpu_state(cpu, ZERO, r == 0);
ines_cpu_state(cpu, OVERFLOW, (b >> 6) & 0x01);
ines_cpu_state(cpu, NEGATIVE, (b >> 7) & 0x01);
}
static void inline ines_branch_impl(NesConsole *console, CPU *cpu) {
cpu->cycle = cpu->cycle + 1;
uint16 base = cpu->pc + 1;
byte offset = (byte) ines_ops_operand(console, Relative);
uint16 addr = base + offset;
INES_CPU_PAGE_CROSS(console, base, addr, 2)
cpu->pc = addr;
}
static void inline ines_bmi_bpl_impl(NesConsole *console, Instruction is) {
CPU *cpu = console->cpu;
bool s = INES_CPU_STATE(cpu, NEGATIVE)
if ((s && is == BMI) || (!s && is == BPL)) {
ines_branch_impl(console, cpu);
}
}
static void inline ines_bvs_bvc_impl(NesConsole *console, Instruction is) {
CPU *cpu = console->cpu;
bool s = INES_CPU_STATE(cpu, OVERFLOW)
if ((s && is == BVS) || (!s && is == BVC)) {
ines_branch_impl(console, cpu);
}
}
static void inline ines_cmp_impl(NesConsole *console, AddressMode mode) {
CPU *cpu = console->cpu;
uint8 a = cpu->a;
uint8 b = ines_ops_operand0(console, mode, True);
ines_cpu_state(cpu, CARRY, a >= b);
ines_cpu_state(cpu, ZERO, a == b);
INES_CPU_STATE_SET_NEG(cpu, a - b)
}
static void inline ines_pha_pla_impl(NesConsole *console, Instruction is) {
CPU *cpu = console->cpu;
if (is == PHA) {
uint8 a = cpu->a;
ines_bus_stack_push(console, a);
} else {
uint8 a = ines_bus_stack_pop(console);
cpu->a = a;
}
}
static void inline ines_php_plp_impl(NesConsole *console, Instruction is) {
CPU *cpu = console->cpu;
if (is == PHP) {
uint8 P = cpu->a;
ines_bus_stack_push(console, P);
} else {
uint8 p = ines_bus_stack_pop(console);
cpu->p = p;
}
}
static void inline ines_rti_impl(NesConsole *console) {
CPU *cpu = console->cpu;
cpu->p = ines_bus_stack_pop(console);
cpu->pc = ines_bus_stack_pop0(console);
}
static void inline ines_adc_sbc_impl(NesConsole *console, Instruction is, AddressMode model) {
CPU *cpu = console->cpu;
uint8 b = ines_ops_operand0(console, model, True);
if (is == SBC) {
b = (-b - 1);
}
uint16 tmp = cpu->a + b + INES_CPU_STATE(cpu, CARRY)
ines_cpu_state(cpu, CARRY, tmp > 0xFF);
uint8 sum = (uint8) tmp;
ines_cpu_state(cpu, OVERFLOW, (((b & 0xff ^ sum) & (sum ^ cpu->a)) & 0x80) != 0);
cpu->a = sum;
INES_NZS(cpu, sum)
}
static void inline ines_tsx_txs_impl(NesConsole *console, Instruction is) {
uint8 b;
CPU *cpu = console->cpu;
if (is == TSX) {
b = cpu->p;
cpu->x = b;
} else {
b = cpu->x;
cpu->p = b;
}
INES_NZS(cpu, b)
}
static void inline ines_bcc_bcs_impl(NesConsole *console, Instruction is) {
CPU *cpu = console->cpu;
bool s = INES_CPU_STATE(cpu, CARRY)
if ((s && is == BCS) || (!s && is == BCC)) {
ines_branch_impl(console, cpu);
}
}
/**
* Private debug instruction implement most program language `print` function
*/
static void inline ines_log_impl(NesConsole *console) {
CPU *cpu = console->cpu;
uint16 pc = cpu->pc;
uint8 arr[UTF8_CHAR_CACHE];
int length = ines_bus_read_utf8char(console, arr, UTF8_CHAR_CACHE);
if (length > 0) {
printf("($%04x)Emulator log:%s\n", pc - 1, arr);
cpu->pc = pc + length;
}
}
extern uint32 ines_console_execute(NesConsole *console) {
CPU *cpu = console->cpu;
uint32 suspend = cpu->suspend;
if (suspend != 0) {
INES_CPU_CLOCK_SYNC(console, cpu->suspend)
cpu->suspend = 0;
return suspend;
}
uint32 cycle = 0;
uint16 pc = cpu->pc;
cpu->synchronized = 0;
if (IS_IRQ_TRIGGER(cpu, RESET)) {
CLEAR_IRQ(cpu, RESET)
pc = ines_bus_read_uint16(console, RESET_VECTOR);
} else if (IS_IRQ_TRIGGER(cpu, NMI)) {
CLEAR_IRQ(cpu, NMI)
cycle = 7;
pc = ines_bus_read_uint16(console, NMI_VECTOR);
} else if (IS_IRQ_TRIGGER(cpu, IRQ)) {
cycle = 7;
CLEAR_IRQ(cpu, IRQ)
pc = ines_bus_read_uint16(console, IRQ_BRK_VECTOR);
} else if (IS_IRQ_TRIGGER(cpu, BRK)) {
cycle = 2;
CLEAR_IRQ(cpu, BRK)
pc = ines_bus_read_uint16(console, IRQ_BRK_VECTOR);
}
if (cycle > 0) {
INES_CPU_CLOCK_SYNC(console, cycle)
}
cpu->cycle = cycle;
uint8 opcode = ines_bus_read(console, pc);
uint8 *opWrap = ops[opcode];
Instruction is = opWrap[0];
AddressMode mode = opWrap[1];
uint16 state = pc + 1;
cpu->pc = state;
cpu->cycle = opWrap[3];
if (ines_debug_enable() && is != UWN) {
ines_debug("($%04x) %s m=%s,a=$%02x,x=$%02x,y=$%02x,p=$%02x",
state - 1, IStr[is], AMStr[mode], cpu->a, cpu->x, cpu->y, cpu->p);
}
switch (is) {
case ADC:
ines_adc_sbc_impl(console, ADC, mode);
break;
case SBC:
ines_adc_sbc_impl(console, SBC, mode);
break;
case INX:
ines_xy_inc_impl(cpu, True);
break;
case INY:
ines_xy_inc_impl(cpu, False);
break;
case SEC:
ines_cpu_state(cpu, DECIMAL, True);
break;
case CLC:
ines_cpu_state(cpu, CARRY, False);
break;
case SED:
ines_cpu_state(cpu, DECIMAL, True);
break;
case CLD:
ines_cpu_state(cpu, DECIMAL, False);
break;
case SEI:
ines_cpu_state(cpu, INTERRUPT_DISABLE, True);
break;
case CLI:
ines_cpu_state(cpu, INTERRUPT_DISABLE, False);
break;
case BEQ:
ines_beq_bne_impl(console, False, mode);
break;
case BNE:
ines_beq_bne_impl(console, True, mode);
break;
case JMP:
ines_jmp_impl(console, mode);
break;
case JSR:
ines_jsr_impl(console);
break;
case RTS:
ines_rts_impl(console);
break;
case AND:
ines_logic_impl(console, AND, mode);
break;
case ORA:
ines_logic_impl(console, ORA, mode);
break;
case EOR:
ines_logic_impl(console, EOR, mode);
break;
case LDA:
ines_ld_axy(console, LDA, mode);
break;
case LDX:
ines_ld_axy(console, LDX, mode);
break;
case LDY:
ines_ld_axy(console, LDY, mode);
break;
case STA:
ines_ops_write(console, mode, cpu->a);
break;
case STX:
ines_ops_write(console, mode, cpu->x);
break;
case STY:
ines_ops_write(console, mode, cpu->y);
break;
case TAX:
ines_tax_impl(cpu);
break;
case TXA:
ines_txa_impl(cpu);
break;
case TAY:
ines_tay_impl(cpu);
break;
case TYA:
ines_tya_impl(cpu);
case INC:
ines_inc_impl(console, mode);
break;
case NOP:
case BRK0:
ines_console_irq(cpu, BRK);
break;
case LSR:
ines_asl_lsr_impl(console, LSR, mode);
break;
case ASL:
ines_asl_lsr_impl(console, ASL, mode);
break;
case ROL:
ines_ror_rol_impl(console, ROL, mode);
break;
case ROR:
ines_ror_rol_impl(console, ROR, mode);
break;
case CPY:
ines_xycmp_impl(console, CPY, mode);
break;
case CPX:
ines_xycmp_impl(console, CPX, mode);
break;
case DEC:
ines_dec_impl(console, mode);
break;
case DEX:
ines_xydec_impl(console, DEX);
break;
case DEY:
ines_xydec_impl(console, DEY);
break;
case BIT:
ines_bit_impl(console, mode);
break;
case BMI:
ines_bmi_bpl_impl(console, BMI);
break;
case BPL:
ines_bmi_bpl_impl(console, BPL);
break;
case BVC:
ines_bvs_bvc_impl(console, BVC);
break;
case BVS:
ines_bvs_bvc_impl(console, BVS);
break;
case CLV:
ines_cpu_state(cpu, OVERFLOW, False);
break;
case CMP:
ines_cmp_impl(console, mode);
break;
case PHA:
ines_pha_pla_impl(console, PHA);
break;
case PLA:
ines_pha_pla_impl(console, PLA);
break;
case PHP:
ines_php_plp_impl(console, PHP);
break;
case PLP:
ines_php_plp_impl(console, PLP);
break;
case RTI:
ines_rti_impl(console);
break;
case TSX:
ines_tsx_txs_impl(console, TSX);
break;
case TXS:
ines_tsx_txs_impl(console, TXS);
break;
case BCS:
ines_bcc_bcs_impl(console, BCS);
break;
case BCC:
ines_bcc_bcs_impl(console, BCC);
break;
case LOG:
ines_log_impl(console);
break;
default:
ines_warn("Unknown open code $%02x", opcode);
break;
}
uint16 tmp = cpu->pc;
if (tmp == state) {
cpu->pc = state + (opWrap[2] - 1);
}
uint8 left = cpu->cycle - cpu->synchronized;
if (left != 0) {
INES_CPU_CLOCK_SYNC(console, left)
}
cycle = cpu->cycle;
console->masterCycle += cycle;
return cycle;
}
extern void ines_cpu_dispose(CPU *cpu) {
if (cpu == NULL) {
return;
}
free(cpu);
}
extern void ines_console_irq(CPU *cpu, ExternalIRQ external) {
bool irqDisable = INES_CPU_STATE(cpu, INTERRUPT_DISABLE);
if (irqDisable && (external == IRQ || external == BRK)) {
return;
}
TRIGGER_IRQ(cpu, external)
}
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化