This commit is contained in:
2025-07-16 15:37:55 +02:00
parent 1b66052212
commit 06b0192bb9
2 changed files with 83 additions and 44 deletions

View File

@@ -269,7 +269,7 @@ void chip8_step(CHIP8 *c) {
case 0x4: { case 0x4: {
uint16_t res = (uint16_t)(c->reg[x]) + (uint16_t)c->reg[y]; uint16_t res = (uint16_t)(c->reg[x]) + (uint16_t)c->reg[y];
c->reg[0xF] = res > 0xFF; c->reg[0xF] = res > 0xFF;
c->reg[x] = (uint8_t)(res & 0xFF); c->reg[x] = res;
} break; } break;
case 0x5: case 0x5:
c->reg[0xF] = c->reg[x] > c->reg[y]; c->reg[0xF] = c->reg[x] > c->reg[y];

125
mos6502.c
View File

@@ -1,4 +1,7 @@
// https://www.masswerk.at/6502/6502_instruction_set.html // https://www.masswerk.at/6502/6502_instruction_set.html
// TODO: decimal mode
// TODO: interrupts?
// TODO: cycles?
#include <stdint.h> #include <stdint.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
@@ -31,6 +34,7 @@ MOS6502 mos6502_create(void) {
m.pc = 0x600; m.pc = 0x600;
m.memory = calloc(1, 1 << 16); m.memory = calloc(1, 1 << 16);
m.SP = 0xFF; m.SP = 0xFF;
m.P = 0x24;
return m; return m;
} }
@@ -66,8 +70,8 @@ void mos6502_step(MOS6502 *m) {
} break; } break;
case 0x01: { case 0x01: {
uint16_t oper = READ_U8() + m->X; uint16_t oper = READ_U8() + m->X;
uint16_t addr = uint16_t addr = mos6502_mem_read(m, oper) |
mos6502_mem_read(m, oper) | (mos6502_mem_read(m, oper + 1) << 8); (mos6502_mem_read(m, (uint8_t)(oper + 1)) << 8);
m->A |= mos6502_mem_read(m, addr); m->A |= mos6502_mem_read(m, addr);
mos6502_set_zn(m, m->A); mos6502_set_zn(m, m->A);
} break; } break;
@@ -84,10 +88,7 @@ void mos6502_step(MOS6502 *m) {
mos6502_set_zn(m, res); mos6502_set_zn(m, res);
} break; } break;
case 0x08: { case 0x08: {
uint8_t res = m->P; mos6502_mem_write(m, 0x0100 + m->SP--, m->P | 0x30);
res |= (1 << 4);
res |= (1 << 5);
mos6502_mem_write(m, 0x0100 + m->SP--, res);
} break; } break;
case 0x09: { case 0x09: {
m->A |= READ_U8(); m->A |= READ_U8();
@@ -119,8 +120,8 @@ void mos6502_step(MOS6502 *m) {
} break; } break;
case 0x11: { case 0x11: {
uint16_t oper = READ_U8(); uint16_t oper = READ_U8();
uint16_t addr = uint16_t addr = mos6502_mem_read(m, oper) |
mos6502_mem_read(m, oper) | (mos6502_mem_read(m, oper + 1) << 8); (mos6502_mem_read(m, (uint8_t)(oper + 1)) << 8);
m->A |= mos6502_mem_read(m, addr + m->Y); m->A |= mos6502_mem_read(m, addr + m->Y);
mos6502_set_zn(m, m->A); mos6502_set_zn(m, m->A);
} break; } break;
@@ -158,14 +159,14 @@ void mos6502_step(MOS6502 *m) {
case 0x20: { case 0x20: {
uint16_t target = READ_U16(); uint16_t target = READ_U16();
uint16_t ret_addr = m->pc - 1; uint16_t ret_addr = m->pc - 1;
mos6502_mem_write(m, 0x0100 + m->SP--, (ret_addr >> 8) & 0xFF); mos6502_mem_write(m, 0x0100 + m->SP--, (uint8_t)(ret_addr >> 8));
mos6502_mem_write(m, 0x0100 + m->SP--, ret_addr & 0xFF); mos6502_mem_write(m, 0x0100 + m->SP--, (uint8_t)ret_addr);
m->pc = target; m->pc = target;
} break; } break;
case 0x21: { case 0x21: {
uint16_t oper = READ_U8() + m->X; uint16_t oper = READ_U8() + m->X;
uint16_t addr = uint16_t addr = mos6502_mem_read(m, oper) |
mos6502_mem_read(m, oper) | (mos6502_mem_read(m, oper + 1) << 8); (mos6502_mem_read(m, (uint8_t)(oper + 1)) << 8);
m->A &= mos6502_mem_read(m, addr); m->A &= mos6502_mem_read(m, addr);
mos6502_set_zn(m, m->A); mos6502_set_zn(m, m->A);
} break; } break;
@@ -227,8 +228,8 @@ void mos6502_step(MOS6502 *m) {
} break; } break;
case 0x31: { case 0x31: {
uint16_t oper = READ_U8(); uint16_t oper = READ_U8();
uint16_t addr = uint16_t addr = mos6502_mem_read(m, oper) |
mos6502_mem_read(m, oper) | (mos6502_mem_read(m, oper + 1) << 8); (mos6502_mem_read(m, (uint8_t)(oper + 1)) << 8);
m->A &= mos6502_mem_read(m, addr + m->Y); m->A &= mos6502_mem_read(m, addr + m->Y);
mos6502_set_zn(m, m->A); mos6502_set_zn(m, m->A);
} break; } break;
@@ -263,10 +264,16 @@ void mos6502_step(MOS6502 *m) {
mos6502_set_flag(m, FLAG_C, (oper & 0x80) >> 7); mos6502_set_flag(m, FLAG_C, (oper & 0x80) >> 7);
mos6502_set_zn(m, res); mos6502_set_zn(m, res);
} break; } break;
case 0x40: {
m->P = mos6502_mem_read(m, 0x0100 + (++m->SP));
uint16_t low = mos6502_mem_read(m, 0x0100 + (++m->SP));
uint16_t high = mos6502_mem_read(m, 0x0100 + (++m->SP));
m->pc = (((uint16_t)high << 8) | low);
} break;
case 0x41: { case 0x41: {
uint16_t oper = READ_U8() + m->X; uint16_t oper = READ_U8() + m->X;
uint16_t addr = uint16_t addr = mos6502_mem_read(m, oper) |
mos6502_mem_read(m, oper) | (mos6502_mem_read(m, oper + 1) << 8); (mos6502_mem_read(m, (uint8_t)(oper + 1)) << 8);
m->A ^= mos6502_mem_read(m, addr); m->A ^= mos6502_mem_read(m, addr);
mos6502_set_zn(m, m->A); mos6502_set_zn(m, m->A);
} break; } break;
@@ -274,6 +281,14 @@ void mos6502_step(MOS6502 *m) {
m->A ^= mos6502_mem_read(m, READ_U8()); m->A ^= mos6502_mem_read(m, READ_U8());
mos6502_set_zn(m, m->A); mos6502_set_zn(m, m->A);
} break; } break;
case 0x46: {
uint8_t addr = READ_U8();
uint8_t oper = mos6502_mem_read(m, addr);
uint8_t res = oper >> 1;
mos6502_set_flag(m, FLAG_C, oper & 0x01);
mos6502_set_zn(m, res);
mos6502_mem_write(m, addr, res);
} break;
case 0x48: { case 0x48: {
mos6502_mem_write(m, 0x0100 + m->SP--, m->A); mos6502_mem_write(m, 0x0100 + m->SP--, m->A);
} break; } break;
@@ -293,6 +308,14 @@ void mos6502_step(MOS6502 *m) {
m->A ^= mos6502_mem_read(m, READ_U16()); m->A ^= mos6502_mem_read(m, READ_U16());
mos6502_set_zn(m, m->A); mos6502_set_zn(m, m->A);
} break; } break;
case 0x4E: {
uint16_t addr = READ_U16();
uint8_t oper = mos6502_mem_read(m, addr);
uint8_t res = oper >> 1;
mos6502_set_flag(m, FLAG_C, oper & 0x01);
mos6502_set_zn(m, res);
mos6502_mem_write(m, addr, res);
} break;
case 0x50: { case 0x50: {
int8_t offset = READ_U8(); int8_t offset = READ_U8();
if (!(m->P & FLAG_V)) { if (!(m->P & FLAG_V)) {
@@ -301,8 +324,8 @@ void mos6502_step(MOS6502 *m) {
} break; } break;
case 0x51: { case 0x51: {
uint16_t oper = READ_U8(); uint16_t oper = READ_U8();
uint16_t addr = uint16_t addr = mos6502_mem_read(m, oper) |
mos6502_mem_read(m, oper) | (mos6502_mem_read(m, oper + 1) << 8); (mos6502_mem_read(m, (uint8_t)(oper + 1)) << 8);
m->A ^= mos6502_mem_read(m, addr + m->Y); m->A ^= mos6502_mem_read(m, addr + m->Y);
mos6502_set_zn(m, m->A); mos6502_set_zn(m, m->A);
} break; } break;
@@ -310,6 +333,14 @@ void mos6502_step(MOS6502 *m) {
m->A ^= mos6502_mem_read(m, READ_U8() + m->X); m->A ^= mos6502_mem_read(m, READ_U8() + m->X);
mos6502_set_zn(m, m->A); mos6502_set_zn(m, m->A);
} break; } break;
case 0x56: {
uint8_t addr = READ_U8() + m->X;
uint8_t oper = mos6502_mem_read(m, addr);
uint8_t res = oper >> 1;
mos6502_set_flag(m, FLAG_C, oper & 0x01);
mos6502_set_zn(m, res);
mos6502_mem_write(m, addr, res);
} break;
case 0x58: { case 0x58: {
mos6502_set_flag(m, FLAG_I, 0); mos6502_set_flag(m, FLAG_I, 0);
} break; } break;
@@ -321,6 +352,14 @@ void mos6502_step(MOS6502 *m) {
m->A ^= mos6502_mem_read(m, READ_U16() + m->X); m->A ^= mos6502_mem_read(m, READ_U16() + m->X);
mos6502_set_zn(m, m->A); mos6502_set_zn(m, m->A);
} break; } break;
case 0x5E: {
uint16_t addr = READ_U16() + m->X;
uint8_t oper = mos6502_mem_read(m, addr);
uint8_t res = oper >> 1;
mos6502_set_flag(m, FLAG_C, oper & 0x01);
mos6502_set_zn(m, res);
mos6502_mem_write(m, addr, res);
} break;
case 0x60: { case 0x60: {
uint16_t low = mos6502_mem_read(m, 0x0100 + (++m->SP)); uint16_t low = mos6502_mem_read(m, 0x0100 + (++m->SP));
uint16_t high = mos6502_mem_read(m, 0x0100 + (++m->SP)); uint16_t high = mos6502_mem_read(m, 0x0100 + (++m->SP));
@@ -328,13 +367,13 @@ void mos6502_step(MOS6502 *m) {
} break; } break;
case 0x61: { case 0x61: {
uint8_t oper = READ_U8() + m->X; uint8_t oper = READ_U8() + m->X;
uint16_t addr = uint16_t addr = mos6502_mem_read(m, oper) |
mos6502_mem_read(m, oper) | (mos6502_mem_read(m, oper + 1) << 8); (mos6502_mem_read(m, (uint8_t)(oper + 1)) << 8);
uint8_t value = mos6502_mem_read(m, addr); uint8_t value = mos6502_mem_read(m, addr);
uint16_t res = (uint16_t)m->A + value + (m->P & FLAG_C); uint16_t res = (uint16_t)m->A + value + (m->P & FLAG_C);
mos6502_set_flag(m, FLAG_C, res > 0xFF); mos6502_set_flag(m, FLAG_C, res > 0xFF);
mos6502_set_flag(m, FLAG_V, (~(m->A ^ oper) & (m->A ^ res) & 0x80)); mos6502_set_flag(m, FLAG_V, (~(m->A ^ value) & (m->A ^ res) & 0x80));
m->A = res; m->A = res;
mos6502_set_zn(m, m->A); mos6502_set_zn(m, m->A);
} break; } break;
@@ -374,8 +413,8 @@ void mos6502_step(MOS6502 *m) {
} break; } break;
case 0x6C: { case 0x6C: {
uint16_t oper = READ_U16(); uint16_t oper = READ_U16();
uint16_t addr = uint16_t addr = mos6502_mem_read(m, oper) |
mos6502_mem_read(m, oper) | (mos6502_mem_read(m, oper + 1) << 8); (mos6502_mem_read(m, (uint8_t)(oper + 1)) << 8);
m->pc = addr; m->pc = addr;
} break; } break;
case 0x6D: { case 0x6D: {
@@ -402,13 +441,13 @@ void mos6502_step(MOS6502 *m) {
} break; } break;
case 0x71: { case 0x71: {
uint8_t oper = READ_U8(); uint8_t oper = READ_U8();
uint16_t addr = uint16_t addr = mos6502_mem_read(m, oper) |
mos6502_mem_read(m, oper) | (mos6502_mem_read(m, oper + 1) << 8); (mos6502_mem_read(m, (uint8_t)(oper + 1)) << 8);
uint8_t value = mos6502_mem_read(m, addr + m->Y); uint8_t value = mos6502_mem_read(m, addr + m->Y);
uint16_t res = (uint16_t)m->A + value + (m->P & FLAG_C); uint16_t res = (uint16_t)m->A + value + (m->P & FLAG_C);
mos6502_set_flag(m, FLAG_C, res > 0xFF); mos6502_set_flag(m, FLAG_C, res > 0xFF);
mos6502_set_flag(m, FLAG_V, (~(m->A ^ oper) & (m->A ^ res) & 0x80)); mos6502_set_flag(m, FLAG_V, (~(m->A ^ value) & (m->A ^ res) & 0x80));
m->A = res; m->A = res;
mos6502_set_zn(m, m->A); mos6502_set_zn(m, m->A);
} break; } break;
@@ -457,8 +496,8 @@ void mos6502_step(MOS6502 *m) {
} break; } break;
case 0x81: { case 0x81: {
uint8_t oper = READ_U8() + m->X; uint8_t oper = READ_U8() + m->X;
uint16_t addr = uint16_t addr = mos6502_mem_read(m, oper) |
mos6502_mem_read(m, oper) | (mos6502_mem_read(m, oper + 1) << 8); (mos6502_mem_read(m, (uint8_t)(oper + 1)) << 8);
mos6502_mem_write(m, addr, m->A); mos6502_mem_write(m, addr, m->A);
} break; } break;
case 0x84: { case 0x84: {
@@ -495,8 +534,8 @@ void mos6502_step(MOS6502 *m) {
} break; } break;
case 0x91: { case 0x91: {
uint8_t oper = READ_U8(); uint8_t oper = READ_U8();
uint16_t addr = uint16_t addr = mos6502_mem_read(m, oper) |
mos6502_mem_read(m, oper) | (mos6502_mem_read(m, oper + 1) << 8); (mos6502_mem_read(m, (uint8_t)(oper + 1)) << 8);
mos6502_mem_write(m, addr + m->Y, m->A); mos6502_mem_write(m, addr + m->Y, m->A);
} break; } break;
case 0x94: { case 0x94: {
@@ -528,7 +567,7 @@ void mos6502_step(MOS6502 *m) {
case 0xA1: { case 0xA1: {
uint8_t oper = READ_U8() + m->X; uint8_t oper = READ_U8() + m->X;
uint16_t addr = mos6502_mem_read(m, oper) | uint16_t addr = mos6502_mem_read(m, oper) |
(mos6502_mem_read(m, (oper + 1 & 0xFF)) << 8); (mos6502_mem_read(m, (uint8_t)(oper + 1)) << 8);
m->A = mos6502_mem_read(m, addr); m->A = mos6502_mem_read(m, addr);
mos6502_set_zn(m, m->A); mos6502_set_zn(m, m->A);
} break; } break;
@@ -581,7 +620,7 @@ void mos6502_step(MOS6502 *m) {
case 0xB1: { case 0xB1: {
uint8_t oper = READ_U8(); uint8_t oper = READ_U8();
uint16_t addr = mos6502_mem_read(m, oper) | uint16_t addr = mos6502_mem_read(m, oper) |
(mos6502_mem_read(m, (oper + 1 & 0xFF)) << 8); (mos6502_mem_read(m, (uint8_t)(oper + 1)) << 8);
m->A = mos6502_mem_read(m, addr + m->Y); m->A = mos6502_mem_read(m, addr + m->Y);
mos6502_set_zn(m, m->A); mos6502_set_zn(m, m->A);
} break; } break;
@@ -628,8 +667,8 @@ void mos6502_step(MOS6502 *m) {
} break; } break;
case 0xC1: { case 0xC1: {
uint8_t oper = READ_U8() + m->X; uint8_t oper = READ_U8() + m->X;
uint16_t addr = uint16_t addr = mos6502_mem_read(m, oper) |
mos6502_mem_read(m, oper) | (mos6502_mem_read(m, oper + 1) << 8); (mos6502_mem_read(m, (uint8_t)(oper + 1)) << 8);
uint8_t res = mos6502_mem_read(m, addr); uint8_t res = mos6502_mem_read(m, addr);
mos6502_set_flag(m, FLAG_C, m->A >= res); mos6502_set_flag(m, FLAG_C, m->A >= res);
mos6502_set_zn(m, m->A - res); mos6502_set_zn(m, m->A - res);
@@ -690,7 +729,7 @@ void mos6502_step(MOS6502 *m) {
case 0xD1: { case 0xD1: {
uint8_t oper = READ_U8(); uint8_t oper = READ_U8();
uint16_t addr = mos6502_mem_read(m, oper) | uint16_t addr = mos6502_mem_read(m, oper) |
(mos6502_mem_read(m, (oper + 1 & 0xFF)) << 8); (mos6502_mem_read(m, (uint8_t)(oper + 1)) << 8);
uint8_t res = mos6502_mem_read(m, addr + m->Y); uint8_t res = mos6502_mem_read(m, addr + m->Y);
mos6502_set_flag(m, FLAG_C, m->A >= res); mos6502_set_flag(m, FLAG_C, m->A >= res);
mos6502_set_zn(m, m->A - res); mos6502_set_zn(m, m->A - res);
@@ -734,11 +773,11 @@ void mos6502_step(MOS6502 *m) {
case 0xE1: { case 0xE1: {
uint8_t oper = READ_U8() + m->X; uint8_t oper = READ_U8() + m->X;
uint16_t addr = mos6502_mem_read(m, oper) | uint16_t addr = mos6502_mem_read(m, oper) |
(mos6502_mem_read(m, (oper + 1 & 0xFF)) << 8); (mos6502_mem_read(m, (uint8_t)(oper + 1)) << 8);
oper = mos6502_mem_read(m, addr); uint8_t value = mos6502_mem_read(m, addr);
uint16_t res = m->A - oper - ((m->P & FLAG_C) ? 0 : 1); uint16_t res = m->A - value - ((m->P & FLAG_C) ? 0 : 1);
mos6502_set_flag(m, FLAG_C, res < 0x100); mos6502_set_flag(m, FLAG_C, res < 0x100);
mos6502_set_flag(m, FLAG_V, (m->A ^ oper) & (m->A ^ res) & 0x80); mos6502_set_flag(m, FLAG_V, (m->A ^ value) & (m->A ^ res) & 0x80);
m->A = res; m->A = res;
mos6502_set_zn(m, m->A); mos6502_set_zn(m, m->A);
} break; } break;
@@ -805,11 +844,11 @@ void mos6502_step(MOS6502 *m) {
case 0xF1: { case 0xF1: {
uint8_t oper = READ_U8(); uint8_t oper = READ_U8();
uint16_t addr = mos6502_mem_read(m, oper) | uint16_t addr = mos6502_mem_read(m, oper) |
(mos6502_mem_read(m, (oper + 1 & 0xFF)) << 8); (mos6502_mem_read(m, (uint8_t)(oper + 1)) << 8);
oper = mos6502_mem_read(m, addr + m->Y); uint8_t value = mos6502_mem_read(m, addr + m->Y);
uint16_t res = m->A - oper - ((m->P & FLAG_C) ? 0 : 1); uint16_t res = m->A - value - ((m->P & FLAG_C) ? 0 : 1);
mos6502_set_flag(m, FLAG_C, res < 0x100); mos6502_set_flag(m, FLAG_C, res < 0x100);
mos6502_set_flag(m, FLAG_V, (m->A ^ oper) & (m->A ^ res) & 0x80); mos6502_set_flag(m, FLAG_V, (m->A ^ value) & (m->A ^ res) & 0x80);
m->A = res; m->A = res;
mos6502_set_zn(m, m->A); mos6502_set_zn(m, m->A);
} break; } break;