disassemble simple 6502 instructions
This commit is contained in:
2
build.sh
2
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
|
||||
cc -O3 -o mos6502 mos6502.c
|
||||
372
chip8.c
372
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);
|
||||
}
|
||||
|
||||
82
mos6502.c
Normal file
82
mos6502.c
Normal file
@@ -0,0 +1,82 @@
|
||||
// https://www.masswerk.at/6502/6502_instruction_set.html
|
||||
// https://tutorial-6502.sourceforge.io/specification/opcodes/
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#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 <path>\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);
|
||||
}
|
||||
Reference in New Issue
Block a user