diff --git a/6502.c b/6502.c deleted file mode 100644 index 79c21e3..0000000 --- a/6502.c +++ /dev/null @@ -1,3 +0,0 @@ -#include - -int main() { printf("Hello, World!\n"); } \ No newline at end of file diff --git a/build.sh b/build.sh index 6e07bbd..4a05ca9 100755 --- a/build.sh +++ b/build.sh @@ -1,4 +1,4 @@ #!/bin/bash set -xe cc -O3 -o chip8 chip8.c -L/usr/local/lib/libraylib.a -lraylib -lm -cc -O3 -o 6502 6502.c \ No newline at end of file +cc -O3 -o mos6502 mos6502.c \ No newline at end of file diff --git a/chip8.c b/chip8.c index b61f341..738485b 100644 --- a/chip8.c +++ b/chip8.c @@ -205,199 +205,189 @@ void chip8_disassemble(CHIP8 *c, size_t ins_count) { } void chip8_step(CHIP8 *c) { - do { - if (c->delay_timer > 0) { - c->delay_timer--; - } - if (c->sound_timer > 0) { - c->sound_timer--; - // TODO: buzzer - } + READ_INS(); - READ_INS(); - - switch ((ins >> 12) & 0xF) { - case 0x0: { - switch (nnn) { - case 0x0E0: - memset(c->display, 0, 64 * 32); - break; - case 0x0EE: - c->pc = c->stack[c->sp]; - c->sp--; - break; - default: - // >This instruction is only used on the old computers on which Chip-8 - // >was originally implemented. It is ignored by modern interpreters. - break; - } - } break; - case 0x1: { - c->pc = nnn; - } break; - case 0x2: { - c->sp++; - c->stack[c->sp] = c->pc; - c->pc = nnn; - } break; - case 0x3: { - if (c->reg[x] == kk) { - c->pc += 2; - } - } break; + switch ((ins >> 12) & 0xF) { + case 0x0: { + switch (nnn) { + case 0x0E0: + memset(c->display, 0, 64 * 32); + break; + case 0x0EE: + c->pc = c->stack[c->sp]; + c->sp--; + break; + default: + // >This instruction is only used on the old computers on which Chip-8 + // >was originally implemented. It is ignored by modern interpreters. + break; + } + } break; + case 0x1: { + c->pc = nnn; + } break; + case 0x2: { + c->sp++; + c->stack[c->sp] = c->pc; + c->pc = nnn; + } break; + case 0x3: { + if (c->reg[x] == kk) { + c->pc += 2; + } + } break; + case 0x4: { + if (c->reg[x] != kk) { + c->pc += 2; + } + } break; + case 0x5: { + if (c->reg[x] == c->reg[y]) { + c->pc += 2; + } + } break; + case 0x6: { + c->reg[x] = kk; + } break; + case 0x7: { + c->reg[x] += kk; + } break; + case 0x8: { + switch (n) { + case 0x0: + c->reg[x] = c->reg[y]; + break; + case 0x1: + c->reg[x] |= c->reg[y]; + break; + case 0x2: + c->reg[x] &= c->reg[y]; + break; + case 0x3: + c->reg[x] ^= c->reg[y]; + break; case 0x4: { - if (c->reg[x] != kk) { - c->pc += 2; - } - } break; - case 0x5: { - if (c->reg[x] == c->reg[y]) { - c->pc += 2; - } - } break; - case 0x6: { - c->reg[x] = kk; - } break; - case 0x7: { - c->reg[x] += kk; - } break; - case 0x8: { - switch (n) { - case 0x0: - c->reg[x] = c->reg[y]; - break; - case 0x1: - c->reg[x] |= c->reg[y]; - break; - case 0x2: - c->reg[x] &= c->reg[y]; - break; - case 0x3: - c->reg[x] ^= c->reg[y]; - break; - case 0x4: { - uint16_t res = (uint16_t)(c->reg[x]) + (uint16_t)c->reg[y]; - c->reg[0xF] = res > 0xFF; - c->reg[x] = (uint8_t)(res & 0xFF); - } break; - case 0x5: - c->reg[0xF] = c->reg[x] > c->reg[y]; - c->reg[x] -= c->reg[y]; - break; - case 0x6: - c->reg[0xF] = c->reg[x] & 0x1; - c->reg[x] >>= 1; - break; - case 0x7: - c->reg[0xF] = c->reg[y] > c->reg[x]; - c->reg[x] = c->reg[y] - c->reg[x]; - break; - case 0xE: - c->reg[0xF] = (c->reg[x] & 0b10000000) >> 7; - c->reg[x] <<= 1; - break; - default: - BAD_INS(); - } - } break; - case 0x9: { - if (c->reg[x] != c->reg[y]) { - c->pc += 2; - } - } break; - case 0xA: { - c->I = nnn; - } break; - case 0xB: { - c->pc = nnn + c->reg[0]; - } break; - case 0xC: { - c->reg[x] = (rand() % 256) & kk; - } break; - case 0xD: { - c->reg[0xF] = 0; - for (size_t row = 0; row < n; row++) { - for (int col = 0; col < 8; col++) { - if ((c->memory[c->I + row] & (0b10000000 >> col)) != 0) { - size_t pixel_x = (c->reg[x] + col) % 64; - size_t pixel_y = (c->reg[y] + row) % 32; - size_t offset = pixel_x + (pixel_y * 64); - - if (c->display[offset] == 1) { - c->reg[0xF] = 1; - } - c->display[offset] ^= 1; - } - } - } - } break; - case 0xE: { - switch (kk) { - case 0x9E: - if (IsKeyDown(keyboard_map[c->reg[x]])) { - c->pc += 2; - } - break; - case 0xA1: - if (!IsKeyDown(keyboard_map[c->reg[x]])) { - c->pc += 2; - } - break; - default: - BAD_INS(); - } - } break; - case 0xF: { - switch (kk) { - case 0x07: - c->reg[x] = c->delay_timer; - break; - case 0x0A: { - bool key_pressed = false; - while (!key_pressed && WindowShouldClose()) { - for (size_t i = 0; i < 16; i++) { - if (IsKeyDown(keyboard_map[i])) { - key_pressed = true; - break; - } - } - } - } break; - case 0x15: - c->delay_timer = c->reg[x]; - break; - case 0x18: - c->sound_timer = c->reg[x]; - break; - case 0x1E: - c->I += c->reg[x]; - break; - case 0x29: - c->I = c->reg[x] * 5; - break; - case 0x33: - c->memory[c->I] = c->reg[x] / 100; - c->memory[c->I + 1] = (c->reg[x] / 10) % 10; - c->memory[c->I + 2] = c->reg[x] % 10; - break; - case 0x55: - for (size_t i = 0; i <= x; i++) { - c->memory[c->I + i] = c->reg[i]; - } - break; - case 0x65: - for (size_t i = 0; i <= x; i++) { - c->reg[i] = c->memory[c->I + i]; - } - break; - default: - BAD_INS(); - } + uint16_t res = (uint16_t)(c->reg[x]) + (uint16_t)c->reg[y]; + c->reg[0xF] = res > 0xFF; + c->reg[x] = (uint8_t)(res & 0xFF); } break; + case 0x5: + c->reg[0xF] = c->reg[x] > c->reg[y]; + c->reg[x] -= c->reg[y]; + break; + case 0x6: + c->reg[0xF] = c->reg[x] & 0x1; + c->reg[x] >>= 1; + break; + case 0x7: + c->reg[0xF] = c->reg[y] > c->reg[x]; + c->reg[x] = c->reg[y] - c->reg[x]; + break; + case 0xE: + c->reg[0xF] = (c->reg[x] & 0b10000000) >> 7; + c->reg[x] <<= 1; + break; default: BAD_INS(); } - } while (0); + } break; + case 0x9: { + if (c->reg[x] != c->reg[y]) { + c->pc += 2; + } + } break; + case 0xA: { + c->I = nnn; + } break; + case 0xB: { + c->pc = nnn + c->reg[0]; + } break; + case 0xC: { + c->reg[x] = (rand() % 256) & kk; + } break; + case 0xD: { + c->reg[0xF] = 0; + for (size_t row = 0; row < n; row++) { + for (int col = 0; col < 8; col++) { + if ((c->memory[c->I + row] & (0b10000000 >> col)) != 0) { + size_t pixel_x = (c->reg[x] + col) % 64; + size_t pixel_y = (c->reg[y] + row) % 32; + size_t offset = pixel_x + (pixel_y * 64); + + if (c->display[offset] == 1) { + c->reg[0xF] = 1; + } + c->display[offset] ^= 1; + } + } + } + } break; + case 0xE: { + switch (kk) { + case 0x9E: + if (IsKeyDown(keyboard_map[c->reg[x]])) { + c->pc += 2; + } + break; + case 0xA1: + if (!IsKeyDown(keyboard_map[c->reg[x]])) { + c->pc += 2; + } + break; + default: + BAD_INS(); + } + } break; + case 0xF: { + switch (kk) { + case 0x07: + c->reg[x] = c->delay_timer; + break; + case 0x0A: { + bool key_pressed = false; + while (!key_pressed && WindowShouldClose()) { + for (size_t i = 0; i < 16; i++) { + if (IsKeyDown(keyboard_map[i])) { + key_pressed = true; + break; + } + } + } + } break; + case 0x15: + c->delay_timer = c->reg[x]; + break; + case 0x18: + c->sound_timer = c->reg[x]; + break; + case 0x1E: + c->I += c->reg[x]; + break; + case 0x29: + c->I = c->reg[x] * 5; + break; + case 0x33: + c->memory[c->I] = c->reg[x] / 100; + c->memory[c->I + 1] = (c->reg[x] / 10) % 10; + c->memory[c->I + 2] = c->reg[x] % 10; + break; + case 0x55: + for (size_t i = 0; i <= x; i++) { + c->memory[c->I + i] = c->reg[i]; + } + break; + case 0x65: + for (size_t i = 0; i <= x; i++) { + c->reg[i] = c->memory[c->I + i]; + } + break; + default: + BAD_INS(); + } + } break; + default: + BAD_INS(); + } } void chip8_free(CHIP8 c) { @@ -426,6 +416,14 @@ int main(int argc, char *argv[]) { SetTargetFPS(60); while (!WindowShouldClose()) { + if (c.delay_timer > 0) { + c.delay_timer--; + } + if (c.sound_timer > 0) { + c.sound_timer--; + // TODO: buzzer + } + for (int i = 0; i < 25; i++) { chip8_step(&c); } diff --git a/mos6502.c b/mos6502.c new file mode 100644 index 0000000..2c467cd --- /dev/null +++ b/mos6502.c @@ -0,0 +1,82 @@ +// https://www.masswerk.at/6502/6502_instruction_set.html +// https://tutorial-6502.sourceforge.io/specification/opcodes/ +#include +#include +#include + +#define READ_ADDR() \ + uint16_t low = m->memory[m->pc++]; \ + uint16_t high = m->memory[m->pc++]; \ + uint16_t addr = (high << 8) | low + +typedef struct MOS6502 { + uint8_t *memory; + uint16_t pc; + uint8_t A; + uint8_t X; + uint8_t Y; + uint8_t SP; + uint8_t P; +} MOS6502; + +MOS6502 mos6502_create() { + MOS6502 m = {0}; + m.pc = 0x600; + m.memory = malloc(1 << 16); + return m; +} + +void mos6502_disassemble(MOS6502 *m, size_t ins_count) { + for (size_t i = 0; i < ins_count; i++) { + uint8_t op = m->memory[m->pc++]; + switch (op) { + case 0x00: { + printf("BRK\n"); + } break; + case 0x4C: { + READ_ADDR(); + printf("JMP $%X\n", addr); + } break; + case 0x8D: { + READ_ADDR(); + printf("STA $%X\n", addr); + } break; + case 0xA2: { + printf("LDX #$%X\n", m->memory[m->pc++]); + } break; + case 0xBD: { + READ_ADDR(); + printf("LDA $%X,X\n", addr); + } break; + case 0xE8: { + printf("INX\n"); + } break; + case 0xF0: { + printf("BEQ %d\n", m->memory[m->pc++]); + } break; + default: + fprintf(stderr, "unrecognized opcode: %x\n", op); + exit(1); + } + } +} + +int main(int argc, char *argv[]) { + if (argc < 2) { + fprintf(stderr, "Usage: %s \n", argv[0]); + return 1; + } + + MOS6502 m = mos6502_create(); + + uint8_t buffer[4000] = {0}; + FILE *f = fopen(argv[1], "rb"); + size_t n = fread(buffer, 1, 4000, f); + fclose(f); + + for (size_t i = 0; i < n; i++) { + m.memory[0x600 + i] = buffer[i]; + } + + mos6502_disassemble(&m, 7); +} \ No newline at end of file