initial
This commit is contained in:
commit
79259bafa2
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
*.o
|
||||||
|
main
|
31
Makefile
Normal file
31
Makefile
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
CFLAGS = -O3 -march=native -g -Wall -Wextra -Werror -Wpedantic -Wno-error=unused-parameter -Wno-error=unused-variable
|
||||||
|
CFLAGS += $(shell pkg-config --cflags sdl2)
|
||||||
|
CFLAGS += $(shell pkg-config --cflags freetype2)
|
||||||
|
LDFLAGS = $(shell pkg-config --libs sdl2)
|
||||||
|
LDFLAGS += $(shell pkg-config --libs freetype2)
|
||||||
|
|
||||||
|
TARGET =
|
||||||
|
CC = $(TARGET)gcc
|
||||||
|
AS = $(TARGET)as
|
||||||
|
AS = $(TARGET)ar
|
||||||
|
LD = $(TARGET)ld
|
||||||
|
OBJCOPY = $(TARGET)objcopy
|
||||||
|
OBJDUMP = $(TARGET)objdump
|
||||||
|
|
||||||
|
OBJS = fake6502.o main.o instruction.o mneumonic.o present.o text.o cpu.o
|
||||||
|
HEADERS = $(wildcard *.h)
|
||||||
|
|
||||||
|
all: main
|
||||||
|
|
||||||
|
%.o: %.c $(HEADERS) Makefile
|
||||||
|
$(CC) $(ARCH) $(CFLAGS) -c $< -o $@
|
||||||
|
|
||||||
|
main: $(OBJS)
|
||||||
|
$(CC) $(ARCH) $(LDFLAGS) $^ -o $@
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -f *.o *.elf *.bin *.out *.imem *.hex
|
||||||
|
|
||||||
|
.SUFFIXES:
|
||||||
|
.INTERMEDIATE:
|
||||||
|
.PHONY: all clean %.dump
|
19
convert.py
Normal file
19
convert.py
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
import sys
|
||||||
|
|
||||||
|
stdout = sys.stdout.buffer
|
||||||
|
|
||||||
|
ix = 0
|
||||||
|
for line in sys.stdin:
|
||||||
|
words = line.split()
|
||||||
|
for word in words:
|
||||||
|
if ';' in word:
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
if word == '??':
|
||||||
|
print(f'?? at {ix:02x}', file=sys.stderr)
|
||||||
|
number = 0xff
|
||||||
|
else:
|
||||||
|
number = int(word, 16)
|
||||||
|
assert number < 256
|
||||||
|
stdout.write(bytes([number]))
|
||||||
|
ix += 1;
|
234
cpu.c
Normal file
234
cpu.c
Normal file
@ -0,0 +1,234 @@
|
|||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
#include "cpu.h"
|
||||||
|
#include "opcodes.h"
|
||||||
|
|
||||||
|
extern void reset6502(void);
|
||||||
|
extern void step6502(void);
|
||||||
|
|
||||||
|
uint8_t cpu_memory[65536] = {
|
||||||
|
[0xfffc] = 0x0,
|
||||||
|
[0xfffd] = 0x0,
|
||||||
|
};
|
||||||
|
|
||||||
|
uint8_t read6502(uint16_t address)
|
||||||
|
{
|
||||||
|
return cpu_memory[address];
|
||||||
|
}
|
||||||
|
|
||||||
|
void write6502(uint16_t address, uint8_t value)
|
||||||
|
{
|
||||||
|
cpu_memory[address] = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
extern uint16_t pc;
|
||||||
|
extern uint8_t sp, a, x, y, status;
|
||||||
|
|
||||||
|
cpu_history_t cpu_history[65536] = { 0 };
|
||||||
|
int cpu_history_len;
|
||||||
|
int cpu_history_ix;
|
||||||
|
|
||||||
|
void cpu_get_state(cpu_state_t * state) {
|
||||||
|
*state = (cpu_state_t){
|
||||||
|
.a = a,
|
||||||
|
.y = y,
|
||||||
|
.x = x,
|
||||||
|
.pc = pc,
|
||||||
|
.sp = sp,
|
||||||
|
.status = status,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void update_history(void)
|
||||||
|
{
|
||||||
|
instruction_t instruction = decode_ins[cpu_memory[pc]];
|
||||||
|
addressing_mode_t addressing_mode = addressing_modes[instruction.mode];
|
||||||
|
|
||||||
|
if (cpu_history_len < 65536)
|
||||||
|
cpu_history_len++;
|
||||||
|
|
||||||
|
cpu_history[cpu_history_ix] = (cpu_history_t){
|
||||||
|
.state = (cpu_state_t){
|
||||||
|
.a = a,
|
||||||
|
.y = y,
|
||||||
|
.x = x,
|
||||||
|
.pc = pc,
|
||||||
|
.sp = sp,
|
||||||
|
.status = status,
|
||||||
|
},
|
||||||
|
.pc_mem = { cpu_memory[pc], cpu_memory[pc+1], cpu_memory[pc+2] },
|
||||||
|
.value = (addressing_mode.func)(pc),
|
||||||
|
};
|
||||||
|
|
||||||
|
cpu_history_ix = (cpu_history_ix + 1) & 0xffff;
|
||||||
|
}
|
||||||
|
|
||||||
|
void cpu_reset(void)
|
||||||
|
{
|
||||||
|
reset6502();
|
||||||
|
|
||||||
|
cpu_history_len = 0;
|
||||||
|
cpu_history_ix = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void cpu_step(void)
|
||||||
|
{
|
||||||
|
update_history();
|
||||||
|
step6502();
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint8_t * mem = cpu_memory;
|
||||||
|
|
||||||
|
uint16_t absolute(uint16_t _pc)
|
||||||
|
{
|
||||||
|
uint16_t effective = ((uint16_t)mem[_pc + 2] << 8) | ((uint16_t)mem[_pc + 1] << 0);
|
||||||
|
|
||||||
|
return effective;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t absolute_indexed_indirect(uint16_t _pc)
|
||||||
|
{
|
||||||
|
uint16_t effective = (((uint16_t)mem[_pc + 2] << 8) | ((uint16_t)mem[_pc + 1] << 0))
|
||||||
|
+ x;
|
||||||
|
|
||||||
|
uint16_t indirect = ((uint16_t)mem[effective + 1] << 8)
|
||||||
|
| ((uint16_t)mem[effective + 0] << 0);
|
||||||
|
|
||||||
|
return indirect;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t absolute_indexed_with_x(uint16_t _pc)
|
||||||
|
{
|
||||||
|
uint16_t effective = (((uint16_t)mem[_pc + 2] << 8) | ((uint16_t)mem[_pc + 1] << 0))
|
||||||
|
+ x;
|
||||||
|
|
||||||
|
return effective;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t absolute_indexed_with_y(uint16_t _pc)
|
||||||
|
{
|
||||||
|
uint16_t effective = (((uint16_t)mem[_pc + 2] << 8) | ((uint16_t)mem[_pc + 1] << 0))
|
||||||
|
+ y;
|
||||||
|
|
||||||
|
return effective;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t absolute_indirect(uint16_t _pc)
|
||||||
|
{
|
||||||
|
uint16_t effective = (((uint16_t)mem[_pc + 2] << 8) | ((uint16_t)mem[_pc + 1] << 0))
|
||||||
|
+ y;
|
||||||
|
|
||||||
|
uint16_t indirect = ((uint16_t)mem[effective + 1] << 8)
|
||||||
|
| ((uint16_t)mem[effective + 0] << 0);
|
||||||
|
|
||||||
|
return indirect;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t accumulator(uint16_t _pc)
|
||||||
|
{
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t immediate(uint16_t _pc)
|
||||||
|
{
|
||||||
|
return (uint8_t)mem[_pc + 1];
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t implied(uint16_t _pc)
|
||||||
|
{
|
||||||
|
return 0; // ???
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t program_counter_relative(uint16_t _pc)
|
||||||
|
{
|
||||||
|
uint16_t effective = _pc + 2 + ((int8_t)mem[_pc + 1]);
|
||||||
|
|
||||||
|
return effective;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t stack(uint16_t _pc)
|
||||||
|
{
|
||||||
|
uint16_t effective = (0x01 << 8) | (sp << 0);
|
||||||
|
|
||||||
|
return effective;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t zero_page(uint16_t _pc)
|
||||||
|
{
|
||||||
|
uint16_t effective = (0x00 << 8) | ((uint16_t)mem[_pc + 1] << 0);
|
||||||
|
|
||||||
|
return effective;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t zero_page_indexed_indirect(uint16_t _pc)
|
||||||
|
{
|
||||||
|
uint8_t base = x + ((uint8_t)mem[_pc + 1] << 0);
|
||||||
|
|
||||||
|
uint16_t effective = (0x00 << 8) | base;
|
||||||
|
|
||||||
|
uint16_t indirect = ((uint16_t)mem[effective + 1] << 8)
|
||||||
|
| ((uint16_t)mem[effective + 0] << 0);
|
||||||
|
|
||||||
|
return indirect;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t zero_page_indexed_with_x(uint16_t _pc)
|
||||||
|
{
|
||||||
|
uint8_t base = x + ((uint8_t)mem[_pc + 1] << 0);
|
||||||
|
|
||||||
|
uint16_t effective = (0x00 << 8) | base;
|
||||||
|
|
||||||
|
return effective;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t zero_page_indexed_with_y(uint16_t _pc)
|
||||||
|
{
|
||||||
|
uint8_t base = y + ((uint8_t)mem[_pc + 1] << 0);
|
||||||
|
|
||||||
|
uint16_t effective = (0x00 << 8) | base;
|
||||||
|
|
||||||
|
return effective;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t zero_page_indirect(uint16_t _pc)
|
||||||
|
{
|
||||||
|
uint8_t base = ((uint8_t)mem[_pc + 1] << 0);
|
||||||
|
|
||||||
|
uint16_t effective = (0x00 << 8) | base;
|
||||||
|
|
||||||
|
uint16_t indirect = ((uint16_t)mem[effective + 1] << 8)
|
||||||
|
| ((uint16_t)mem[effective + 0] << 0);
|
||||||
|
|
||||||
|
return indirect;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t zero_page_indirect_indexed_with_y(uint16_t _pc)
|
||||||
|
{
|
||||||
|
uint8_t base = ((uint8_t)mem[_pc + 1] << 0);
|
||||||
|
|
||||||
|
uint16_t indirect = ((uint16_t)mem[base + 1] << 8)
|
||||||
|
| ((uint16_t)mem[base + 0] << 0);
|
||||||
|
|
||||||
|
uint16_t effective = indirect + y;
|
||||||
|
|
||||||
|
return effective;
|
||||||
|
}
|
||||||
|
|
||||||
|
addressing_mode_t addressing_modes[16] = {
|
||||||
|
[A] = { .alen = 2, .olen = 2, .func = absolute },
|
||||||
|
[AII] = { .alen = 2, .olen = 2, .func = absolute_indexed_indirect },
|
||||||
|
[AIX] = { .alen = 2, .olen = 2, .func = absolute_indexed_with_x },
|
||||||
|
[AIY] = { .alen = 2, .olen = 2, .func = absolute_indexed_with_y },
|
||||||
|
[AI] = { .alen = 2, .olen = 2, .func = absolute_indirect },
|
||||||
|
[ACC] = { .alen = 0, .olen = 1, .func = accumulator },
|
||||||
|
[IMM] = { .alen = 1, .olen = 1, .func = immediate },
|
||||||
|
[I] = { .alen = 0, .olen = 0, .func = implied },
|
||||||
|
[R] = { .alen = 1, .olen = 2, .func = program_counter_relative },
|
||||||
|
[S] = { .alen = 0, .olen = 2, .func = stack },
|
||||||
|
[ZP] = { .alen = 1, .olen = 2, .func = zero_page },
|
||||||
|
[ZPII] = { .alen = 1, .olen = 2, .func = zero_page_indexed_indirect },
|
||||||
|
[ZPX] = { .alen = 1, .olen = 2, .func = zero_page_indexed_with_x },
|
||||||
|
[ZPY] = { .alen = 1, .olen = 2, .func = zero_page_indexed_with_y },
|
||||||
|
[ZPI] = { .alen = 1, .olen = 2, .func = zero_page_indirect },
|
||||||
|
[ZPIY] = { .alen = 1, .olen = 2, .func = zero_page_indirect_indexed_with_y },
|
||||||
|
};
|
42
cpu.h
Normal file
42
cpu.h
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include "instruction.h"
|
||||||
|
|
||||||
|
extern uint8_t cpu_memory[];
|
||||||
|
|
||||||
|
void cpu_reset(void);
|
||||||
|
|
||||||
|
void cpu_step(void);
|
||||||
|
|
||||||
|
typedef struct cpu_state {
|
||||||
|
uint8_t a;
|
||||||
|
uint8_t y;
|
||||||
|
uint8_t x;
|
||||||
|
uint16_t pc;
|
||||||
|
uint8_t sp;
|
||||||
|
uint8_t status;
|
||||||
|
} cpu_state_t;
|
||||||
|
|
||||||
|
typedef struct cpu_history {
|
||||||
|
cpu_state_t state;
|
||||||
|
uint8_t pc_mem[3];
|
||||||
|
uint16_t value;
|
||||||
|
} cpu_history_t;
|
||||||
|
|
||||||
|
extern cpu_history_t cpu_history[];
|
||||||
|
extern int cpu_history_len;
|
||||||
|
extern int cpu_history_ix;
|
||||||
|
|
||||||
|
typedef uint16_t (* mode_value_t)(uint16_t);
|
||||||
|
|
||||||
|
typedef struct addressing_mode {
|
||||||
|
int alen;
|
||||||
|
int olen;
|
||||||
|
mode_value_t func;
|
||||||
|
} addressing_mode_t;
|
||||||
|
|
||||||
|
extern addressing_mode_t addressing_modes[16];
|
||||||
|
|
||||||
|
void cpu_get_state(cpu_state_t * state);
|
30
debug-table.c
Normal file
30
debug-table.c
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
|
||||||
|
|
||||||
|
for (int y = 0; y < 16; y++) {
|
||||||
|
for (int x = 0; x < 16; x++) {
|
||||||
|
int i = x | (y << 4);
|
||||||
|
instruction_t ins = decode_ins[i];
|
||||||
|
if (x == 0)
|
||||||
|
fprintf(stdout, "|%5s |", opcode_string[ins.opcode]);
|
||||||
|
else
|
||||||
|
fprintf(stdout, "%6s |", opcode_string[ins.opcode]);
|
||||||
|
}
|
||||||
|
|
||||||
|
fprintf(stdout, "\n");
|
||||||
|
|
||||||
|
for (int x = 0; x < 16; x++) {
|
||||||
|
int i = x | (y << 4);
|
||||||
|
instruction_t ins = decode_ins[i];
|
||||||
|
if (x == 0)
|
||||||
|
fprintf(stdout, "|%5s |", mode_string[ins.mode]);
|
||||||
|
else
|
||||||
|
fprintf(stdout, "%6s |", mode_string[ins.mode]);
|
||||||
|
}
|
||||||
|
|
||||||
|
fprintf(stdout, "\n");
|
||||||
|
|
||||||
|
for (int c = 0; c < 128; c++) {
|
||||||
|
fputc('-', stdout);
|
||||||
|
}
|
||||||
|
fputc('\n', stdout);
|
||||||
|
}
|
944
fake6502.c
Normal file
944
fake6502.c
Normal file
@ -0,0 +1,944 @@
|
|||||||
|
/* Fake6502 CPU emulator core v1.1 *******************
|
||||||
|
* (c)2011 Mike Chambers (miker00lz@gmail.com) *
|
||||||
|
*****************************************************
|
||||||
|
* v1.1 - Small bugfix in BIT opcode, but it was the *
|
||||||
|
* difference between a few games in my NES *
|
||||||
|
* emulator working and being broken! *
|
||||||
|
* I went through the rest carefully again *
|
||||||
|
* after fixing it just to make sure I didn't *
|
||||||
|
* have any other typos! (Dec. 17, 2011) *
|
||||||
|
* *
|
||||||
|
* v1.0 - First release (Nov. 24, 2011) *
|
||||||
|
*****************************************************
|
||||||
|
* LICENSE: This source code is released into the *
|
||||||
|
* public domain, but if you use it please do give *
|
||||||
|
* credit. I put a lot of effort into writing this! *
|
||||||
|
* *
|
||||||
|
*****************************************************
|
||||||
|
* Fake6502 is a MOS Technology 6502 CPU emulation *
|
||||||
|
* engine in C. It was written as part of a Nintendo *
|
||||||
|
* Entertainment System emulator I've been writing. *
|
||||||
|
* *
|
||||||
|
* A couple important things to know about are two *
|
||||||
|
* defines in the code. One is "UNDOCUMENTED" which, *
|
||||||
|
* when defined, allows Fake6502 to compile with *
|
||||||
|
* full support for the more predictable *
|
||||||
|
* undocumented instructions of the 6502. If it is *
|
||||||
|
* undefined, undocumented opcodes just act as NOPs. *
|
||||||
|
* *
|
||||||
|
* The other define is "NES_CPU", which causes the *
|
||||||
|
* code to compile without support for binary-coded *
|
||||||
|
* decimal (BCD) support for the ADC and SBC *
|
||||||
|
* opcodes. The Ricoh 2A03 CPU in the NES does not *
|
||||||
|
* support BCD, but is otherwise identical to the *
|
||||||
|
* standard MOS 6502. (Note that this define is *
|
||||||
|
* enabled in this file if you haven't changed it *
|
||||||
|
* yourself. If you're not emulating a NES, you *
|
||||||
|
* should comment it out.) *
|
||||||
|
* *
|
||||||
|
* If you do discover an error in timing accuracy, *
|
||||||
|
* or operation in general please e-mail me at the *
|
||||||
|
* address above so that I can fix it. Thank you! *
|
||||||
|
* *
|
||||||
|
*****************************************************
|
||||||
|
* Usage: *
|
||||||
|
* *
|
||||||
|
* Fake6502 requires you to provide two external *
|
||||||
|
* functions: *
|
||||||
|
* *
|
||||||
|
* uint8_t read6502(uint16_t address) *
|
||||||
|
* void write6502(uint16_t address, uint8_t value) *
|
||||||
|
* *
|
||||||
|
* You may optionally pass Fake6502 the pointer to a *
|
||||||
|
* function which you want to be called after every *
|
||||||
|
* emulated instruction. This function should be a *
|
||||||
|
* void with no parameters expected to be passed to *
|
||||||
|
* it. *
|
||||||
|
* *
|
||||||
|
* This can be very useful. For example, in a NES *
|
||||||
|
* emulator, you check the number of clock ticks *
|
||||||
|
* that have passed so you can know when to handle *
|
||||||
|
* APU events. *
|
||||||
|
* *
|
||||||
|
* To pass Fake6502 this pointer, use the *
|
||||||
|
* hookexternal(void *funcptr) function provided. *
|
||||||
|
* *
|
||||||
|
* To disable the hook later, pass NULL to it. *
|
||||||
|
*****************************************************
|
||||||
|
* Useful functions in this emulator: *
|
||||||
|
* *
|
||||||
|
* void reset6502() *
|
||||||
|
* - Call this once before you begin execution. *
|
||||||
|
* *
|
||||||
|
* void exec6502(uint32_t tickcount) *
|
||||||
|
* - Execute 6502 code up to the next specified *
|
||||||
|
* count of clock ticks. *
|
||||||
|
* *
|
||||||
|
* void step6502() *
|
||||||
|
* - Execute a single instrution. *
|
||||||
|
* *
|
||||||
|
* void irq6502() *
|
||||||
|
* - Trigger a hardware IRQ in the 6502 core. *
|
||||||
|
* *
|
||||||
|
* void nmi6502() *
|
||||||
|
* - Trigger an NMI in the 6502 core. *
|
||||||
|
* *
|
||||||
|
* void hookexternal(void *funcptr) *
|
||||||
|
* - Pass a pointer to a void function taking no *
|
||||||
|
* parameters. This will cause Fake6502 to call *
|
||||||
|
* that function once after each emulated *
|
||||||
|
* instruction. *
|
||||||
|
* *
|
||||||
|
*****************************************************
|
||||||
|
* Useful variables in this emulator: *
|
||||||
|
* *
|
||||||
|
* uint32_t clockticks6502 *
|
||||||
|
* - A running total of the emulated cycle count. *
|
||||||
|
* *
|
||||||
|
* uint32_t instructions *
|
||||||
|
* - A running total of the total emulated *
|
||||||
|
* instruction count. This is not related to *
|
||||||
|
* clock cycle timing. *
|
||||||
|
* *
|
||||||
|
*****************************************************/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
//6502 defines
|
||||||
|
|
||||||
|
#define FLAG_CARRY 0x01
|
||||||
|
#define FLAG_ZERO 0x02
|
||||||
|
#define FLAG_INTERRUPT 0x04
|
||||||
|
#define FLAG_DECIMAL 0x08
|
||||||
|
#define FLAG_BREAK 0x10
|
||||||
|
#define FLAG_CONSTANT 0x20
|
||||||
|
#define FLAG_OVERFLOW 0x40
|
||||||
|
#define FLAG_SIGN 0x80
|
||||||
|
|
||||||
|
#define BASE_STACK 0x100
|
||||||
|
|
||||||
|
#define saveaccum(n) a = (uint8_t)((n) & 0x00FF)
|
||||||
|
|
||||||
|
|
||||||
|
//flag modifier macros
|
||||||
|
#define setcarry() status |= FLAG_CARRY
|
||||||
|
#define clearcarry() status &= (~FLAG_CARRY)
|
||||||
|
#define setzero() status |= FLAG_ZERO
|
||||||
|
#define clearzero() status &= (~FLAG_ZERO)
|
||||||
|
#define setinterrupt() status |= FLAG_INTERRUPT
|
||||||
|
#define clearinterrupt() status &= (~FLAG_INTERRUPT)
|
||||||
|
#define setdecimal() status |= FLAG_DECIMAL
|
||||||
|
#define cleardecimal() status &= (~FLAG_DECIMAL)
|
||||||
|
#define setoverflow() status |= FLAG_OVERFLOW
|
||||||
|
#define clearoverflow() status &= (~FLAG_OVERFLOW)
|
||||||
|
#define setsign() status |= FLAG_SIGN
|
||||||
|
#define clearsign() status &= (~FLAG_SIGN)
|
||||||
|
|
||||||
|
|
||||||
|
//flag calculation macros
|
||||||
|
#define zerocalc(n) {\
|
||||||
|
if ((n) & 0x00FF) clearzero();\
|
||||||
|
else setzero();\
|
||||||
|
}
|
||||||
|
|
||||||
|
#define signcalc(n) {\
|
||||||
|
if ((n) & 0x0080) setsign();\
|
||||||
|
else clearsign();\
|
||||||
|
}
|
||||||
|
|
||||||
|
#define carrycalc(n) {\
|
||||||
|
if ((n) & 0xFF00) setcarry();\
|
||||||
|
else clearcarry();\
|
||||||
|
}
|
||||||
|
|
||||||
|
#define overflowcalc(n, m, o) { /* n = result, m = accumulator, o = memory */ \
|
||||||
|
if (((n) ^ (uint16_t)(m)) & ((n) ^ (o)) & 0x0080) setoverflow();\
|
||||||
|
else clearoverflow();\
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//6502 CPU registers
|
||||||
|
uint16_t pc;
|
||||||
|
uint8_t sp, a, x, y, status;
|
||||||
|
|
||||||
|
|
||||||
|
//helper variables
|
||||||
|
uint64_t instructions = 0; //keep track of total instructions executed
|
||||||
|
uint64_t clockticks6502 = 0, clockgoal6502 = 0;
|
||||||
|
uint16_t oldpc, ea, reladdr, value, result;
|
||||||
|
uint8_t opcode, oldstatus;
|
||||||
|
|
||||||
|
//externally supplied functions
|
||||||
|
extern uint8_t read6502(uint16_t address);
|
||||||
|
extern void write6502(uint16_t address, uint8_t value);
|
||||||
|
|
||||||
|
//a few general functions used by various other functions
|
||||||
|
void push16(uint16_t pushval) {
|
||||||
|
write6502(BASE_STACK + sp, (pushval >> 8) & 0xFF);
|
||||||
|
write6502(BASE_STACK + ((sp - 1) & 0xFF), pushval & 0xFF);
|
||||||
|
sp -= 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
void push8(uint8_t pushval) {
|
||||||
|
write6502(BASE_STACK + sp--, pushval);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t pull16() {
|
||||||
|
uint16_t temp16;
|
||||||
|
temp16 = read6502(BASE_STACK + ((sp + 1) & 0xFF)) | ((uint16_t)read6502(BASE_STACK + ((sp + 2) & 0xFF)) << 8);
|
||||||
|
sp += 2;
|
||||||
|
return(temp16);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t pull8() {
|
||||||
|
return (read6502(BASE_STACK + ++sp));
|
||||||
|
}
|
||||||
|
|
||||||
|
void reset6502() {
|
||||||
|
pc = (uint16_t)read6502(0xFFFC) | ((uint16_t)read6502(0xFFFD) << 8);
|
||||||
|
a = 0;
|
||||||
|
x = 0;
|
||||||
|
y = 0;
|
||||||
|
sp = 0xFD;
|
||||||
|
status |= FLAG_CONSTANT;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void (*addrtable[256])();
|
||||||
|
static void (*optable[256])();
|
||||||
|
uint8_t penaltyop, penaltyaddr;
|
||||||
|
|
||||||
|
//addressing mode functions, calculates effective addresses
|
||||||
|
static void imp() { //implied
|
||||||
|
}
|
||||||
|
|
||||||
|
static void acc() { //accumulator
|
||||||
|
}
|
||||||
|
|
||||||
|
static void stk() { //stack
|
||||||
|
}
|
||||||
|
|
||||||
|
static void imm() { //immediate
|
||||||
|
ea = pc++;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void zp() { //zero-page
|
||||||
|
ea = (uint16_t)read6502((uint16_t)pc++);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void zpx() { //zero-page,X
|
||||||
|
ea = ((uint16_t)read6502((uint16_t)pc++) + (uint16_t)x) & 0xFF; //zero-page wraparound
|
||||||
|
}
|
||||||
|
|
||||||
|
static void zpy() { //zero-page,Y
|
||||||
|
ea = ((uint16_t)read6502((uint16_t)pc++) + (uint16_t)y) & 0xFF; //zero-page wraparound
|
||||||
|
}
|
||||||
|
|
||||||
|
static void rel() { //relative for branch ops (8-bit immediate value, sign-extended)
|
||||||
|
reladdr = (uint16_t)read6502(pc++);
|
||||||
|
if (reladdr & 0x80) reladdr |= 0xFF00;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void abso() { //absolute
|
||||||
|
ea = (uint16_t)read6502(pc) | ((uint16_t)read6502(pc+1) << 8);
|
||||||
|
pc += 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void absx() { //absolute,X
|
||||||
|
uint16_t startpage;
|
||||||
|
ea = ((uint16_t)read6502(pc) | ((uint16_t)read6502(pc+1) << 8));
|
||||||
|
startpage = ea & 0xFF00;
|
||||||
|
ea += (uint16_t)x;
|
||||||
|
|
||||||
|
if (startpage != (ea & 0xFF00)) { //one cycle penlty for page-crossing on some opcodes
|
||||||
|
penaltyaddr = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
pc += 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void absy() { //absolute,Y
|
||||||
|
uint16_t startpage;
|
||||||
|
ea = ((uint16_t)read6502(pc) | ((uint16_t)read6502(pc+1) << 8));
|
||||||
|
startpage = ea & 0xFF00;
|
||||||
|
ea += (uint16_t)y;
|
||||||
|
|
||||||
|
if (startpage != (ea & 0xFF00)) { //one cycle penlty for page-crossing on some opcodes
|
||||||
|
penaltyaddr = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
pc += 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ind() { //indirect
|
||||||
|
uint16_t eahelp, eahelp2;
|
||||||
|
eahelp = (uint16_t)read6502(pc) | (uint16_t)((uint16_t)read6502(pc+1) << 8);
|
||||||
|
eahelp2 = (eahelp & 0xFF00) | ((eahelp + 1) & 0x00FF); //replicate 6502 page-boundary wraparound bug
|
||||||
|
ea = (uint16_t)read6502(eahelp) | ((uint16_t)read6502(eahelp2) << 8);
|
||||||
|
pc += 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void indx() { // (indirect,X)
|
||||||
|
uint16_t eahelp;
|
||||||
|
eahelp = (uint16_t)(((uint16_t)read6502(pc++) + (uint16_t)x) & 0xFF); //zero-page wraparound for table pointer
|
||||||
|
ea = (uint16_t)read6502(eahelp & 0x00FF) | ((uint16_t)read6502((eahelp+1) & 0x00FF) << 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void indz() { // (indirect)
|
||||||
|
uint16_t eahelp;
|
||||||
|
eahelp = (uint16_t)(((uint16_t)read6502(pc++)) & 0xFF); //zero-page wraparound for table pointer
|
||||||
|
ea = (uint16_t)read6502(eahelp & 0x00FF) | ((uint16_t)read6502((eahelp+1) & 0x00FF) << 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void indy() { // (indirect),Y
|
||||||
|
uint16_t eahelp, eahelp2, startpage;
|
||||||
|
eahelp = (uint16_t)read6502(pc++);
|
||||||
|
eahelp2 = (eahelp & 0xFF00) | ((eahelp + 1) & 0x00FF); //zero-page wraparound
|
||||||
|
ea = (uint16_t)read6502(eahelp) | ((uint16_t)read6502(eahelp2) << 8);
|
||||||
|
startpage = ea & 0xFF00;
|
||||||
|
ea += (uint16_t)y;
|
||||||
|
|
||||||
|
if (startpage != (ea & 0xFF00)) { //one cycle penlty for page-crossing on some opcodes
|
||||||
|
penaltyaddr = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint16_t getvalue() {
|
||||||
|
if (addrtable[opcode] == acc) return((uint16_t)a);
|
||||||
|
else return((uint16_t)read6502(ea));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void putvalue(uint16_t saveval) {
|
||||||
|
if (addrtable[opcode] == acc) a = (uint8_t)(saveval & 0x00FF);
|
||||||
|
else write6502(ea, (saveval & 0x00FF));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//instruction handler functions
|
||||||
|
static void adc() {
|
||||||
|
penaltyop = 1;
|
||||||
|
value = getvalue();
|
||||||
|
result = (uint16_t)a + value + (uint16_t)(status & FLAG_CARRY);
|
||||||
|
|
||||||
|
carrycalc(result);
|
||||||
|
zerocalc(result);
|
||||||
|
overflowcalc(result, a, value);
|
||||||
|
signcalc(result);
|
||||||
|
|
||||||
|
#ifndef NES_CPU
|
||||||
|
if (status & FLAG_DECIMAL) {
|
||||||
|
clearcarry();
|
||||||
|
|
||||||
|
if ((a & 0x0F) > 0x09) {
|
||||||
|
a += 0x06;
|
||||||
|
}
|
||||||
|
if ((a & 0xF0) > 0x90) {
|
||||||
|
a += 0x60;
|
||||||
|
setcarry();
|
||||||
|
}
|
||||||
|
|
||||||
|
clockticks6502++;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
saveaccum(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void and() {
|
||||||
|
penaltyop = 1;
|
||||||
|
value = getvalue();
|
||||||
|
result = (uint16_t)a & value;
|
||||||
|
|
||||||
|
zerocalc(result);
|
||||||
|
signcalc(result);
|
||||||
|
|
||||||
|
saveaccum(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void asl() {
|
||||||
|
value = getvalue();
|
||||||
|
result = value << 1;
|
||||||
|
|
||||||
|
carrycalc(result);
|
||||||
|
zerocalc(result);
|
||||||
|
signcalc(result);
|
||||||
|
|
||||||
|
putvalue(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void bcc() {
|
||||||
|
if ((status & FLAG_CARRY) == 0) {
|
||||||
|
oldpc = pc;
|
||||||
|
pc += reladdr;
|
||||||
|
if ((oldpc & 0xFF00) != (pc & 0xFF00)) clockticks6502 += 2; //check if jump crossed a page boundary
|
||||||
|
else clockticks6502++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void bcs() {
|
||||||
|
if ((status & FLAG_CARRY) == FLAG_CARRY) {
|
||||||
|
oldpc = pc;
|
||||||
|
pc += reladdr;
|
||||||
|
if ((oldpc & 0xFF00) != (pc & 0xFF00)) clockticks6502 += 2; //check if jump crossed a page boundary
|
||||||
|
else clockticks6502++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void beq() {
|
||||||
|
if ((status & FLAG_ZERO) == FLAG_ZERO) {
|
||||||
|
oldpc = pc;
|
||||||
|
pc += reladdr;
|
||||||
|
if ((oldpc & 0xFF00) != (pc & 0xFF00)) clockticks6502 += 2; //check if jump crossed a page boundary
|
||||||
|
else clockticks6502++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void bit() {
|
||||||
|
value = getvalue();
|
||||||
|
result = (uint16_t)a & value;
|
||||||
|
|
||||||
|
zerocalc(result);
|
||||||
|
status = (status & 0x3F) | (uint8_t)(value & 0xC0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void bmi() {
|
||||||
|
if ((status & FLAG_SIGN) == FLAG_SIGN) {
|
||||||
|
oldpc = pc;
|
||||||
|
pc += reladdr;
|
||||||
|
if ((oldpc & 0xFF00) != (pc & 0xFF00)) clockticks6502 += 2; //check if jump crossed a page boundary
|
||||||
|
else clockticks6502++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void bne() {
|
||||||
|
if ((status & FLAG_ZERO) == 0) {
|
||||||
|
oldpc = pc;
|
||||||
|
pc += reladdr;
|
||||||
|
if ((oldpc & 0xFF00) != (pc & 0xFF00)) clockticks6502 += 2; //check if jump crossed a page boundary
|
||||||
|
else clockticks6502++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void bpl() {
|
||||||
|
if ((status & FLAG_SIGN) == 0) {
|
||||||
|
oldpc = pc;
|
||||||
|
pc += reladdr;
|
||||||
|
if ((oldpc & 0xFF00) != (pc & 0xFF00)) clockticks6502 += 2; //check if jump crossed a page boundary
|
||||||
|
else clockticks6502++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void bra() {
|
||||||
|
oldpc = pc;
|
||||||
|
pc += reladdr;
|
||||||
|
if ((oldpc & 0xFF00) != (pc & 0xFF00)) clockticks6502 += 2; //check if jump crossed a page boundary
|
||||||
|
else clockticks6502++;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void brk() {
|
||||||
|
pc++;
|
||||||
|
push16(pc); //push next instruction address onto stack
|
||||||
|
push8(status | FLAG_BREAK); //push CPU status to stack
|
||||||
|
setinterrupt(); //set interrupt flag
|
||||||
|
pc = (uint16_t)read6502(0xFFFE) | ((uint16_t)read6502(0xFFFF) << 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void bvc() {
|
||||||
|
if ((status & FLAG_OVERFLOW) == 0) {
|
||||||
|
oldpc = pc;
|
||||||
|
pc += reladdr;
|
||||||
|
if ((oldpc & 0xFF00) != (pc & 0xFF00)) clockticks6502 += 2; //check if jump crossed a page boundary
|
||||||
|
else clockticks6502++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void bvs() {
|
||||||
|
if ((status & FLAG_OVERFLOW) == FLAG_OVERFLOW) {
|
||||||
|
oldpc = pc;
|
||||||
|
pc += reladdr;
|
||||||
|
if ((oldpc & 0xFF00) != (pc & 0xFF00)) clockticks6502 += 2; //check if jump crossed a page boundary
|
||||||
|
else clockticks6502++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void clc() {
|
||||||
|
clearcarry();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void cld() {
|
||||||
|
cleardecimal();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void cli() {
|
||||||
|
clearinterrupt();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void clv() {
|
||||||
|
clearoverflow();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void cmp() {
|
||||||
|
penaltyop = 1;
|
||||||
|
value = getvalue();
|
||||||
|
result = (uint16_t)a - value;
|
||||||
|
|
||||||
|
if (a >= (uint8_t)(value & 0x00FF)) setcarry();
|
||||||
|
else clearcarry();
|
||||||
|
if (a == (uint8_t)(value & 0x00FF)) setzero();
|
||||||
|
else clearzero();
|
||||||
|
signcalc(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void cpx() {
|
||||||
|
value = getvalue();
|
||||||
|
result = (uint16_t)x - value;
|
||||||
|
|
||||||
|
if (x >= (uint8_t)(value & 0x00FF)) setcarry();
|
||||||
|
else clearcarry();
|
||||||
|
if (x == (uint8_t)(value & 0x00FF)) setzero();
|
||||||
|
else clearzero();
|
||||||
|
signcalc(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void cpy() {
|
||||||
|
value = getvalue();
|
||||||
|
result = (uint16_t)y - value;
|
||||||
|
|
||||||
|
if (y >= (uint8_t)(value & 0x00FF)) setcarry();
|
||||||
|
else clearcarry();
|
||||||
|
if (y == (uint8_t)(value & 0x00FF)) setzero();
|
||||||
|
else clearzero();
|
||||||
|
signcalc(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void dec() {
|
||||||
|
value = getvalue();
|
||||||
|
result = value - 1;
|
||||||
|
|
||||||
|
zerocalc(result);
|
||||||
|
signcalc(result);
|
||||||
|
|
||||||
|
putvalue(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void dex() {
|
||||||
|
x--;
|
||||||
|
|
||||||
|
zerocalc(x);
|
||||||
|
signcalc(x);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void dey() {
|
||||||
|
y--;
|
||||||
|
|
||||||
|
zerocalc(y);
|
||||||
|
signcalc(y);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void eor() {
|
||||||
|
penaltyop = 1;
|
||||||
|
value = getvalue();
|
||||||
|
result = (uint16_t)a ^ value;
|
||||||
|
|
||||||
|
zerocalc(result);
|
||||||
|
signcalc(result);
|
||||||
|
|
||||||
|
saveaccum(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void inc() {
|
||||||
|
value = getvalue();
|
||||||
|
result = value + 1;
|
||||||
|
|
||||||
|
zerocalc(result);
|
||||||
|
signcalc(result);
|
||||||
|
|
||||||
|
putvalue(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void inx() {
|
||||||
|
x++;
|
||||||
|
|
||||||
|
zerocalc(x);
|
||||||
|
signcalc(x);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void iny() {
|
||||||
|
y++;
|
||||||
|
|
||||||
|
zerocalc(y);
|
||||||
|
signcalc(y);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void jmp() {
|
||||||
|
pc = ea;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void jsr() {
|
||||||
|
push16(pc - 1);
|
||||||
|
pc = ea;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void lda() {
|
||||||
|
penaltyop = 1;
|
||||||
|
value = getvalue();
|
||||||
|
a = (uint8_t)(value & 0x00FF);
|
||||||
|
|
||||||
|
zerocalc(a);
|
||||||
|
signcalc(a);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ldx() {
|
||||||
|
penaltyop = 1;
|
||||||
|
value = getvalue();
|
||||||
|
x = (uint8_t)(value & 0x00FF);
|
||||||
|
|
||||||
|
zerocalc(x);
|
||||||
|
signcalc(x);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ldy() {
|
||||||
|
penaltyop = 1;
|
||||||
|
value = getvalue();
|
||||||
|
y = (uint8_t)(value & 0x00FF);
|
||||||
|
|
||||||
|
zerocalc(y);
|
||||||
|
signcalc(y);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void lsr() {
|
||||||
|
value = getvalue();
|
||||||
|
result = value >> 1;
|
||||||
|
|
||||||
|
if (value & 1) setcarry();
|
||||||
|
else clearcarry();
|
||||||
|
zerocalc(result);
|
||||||
|
signcalc(result);
|
||||||
|
|
||||||
|
putvalue(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void nop() {
|
||||||
|
switch (opcode) {
|
||||||
|
case 0x1C:
|
||||||
|
case 0x3C:
|
||||||
|
case 0x5C:
|
||||||
|
case 0x7C:
|
||||||
|
case 0xDC:
|
||||||
|
case 0xFC:
|
||||||
|
penaltyop = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ora() {
|
||||||
|
penaltyop = 1;
|
||||||
|
value = getvalue();
|
||||||
|
result = (uint16_t)a | value;
|
||||||
|
|
||||||
|
zerocalc(result);
|
||||||
|
signcalc(result);
|
||||||
|
|
||||||
|
saveaccum(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void pha() {
|
||||||
|
push8(a);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void phx() {
|
||||||
|
push8(x);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void phy() {
|
||||||
|
push8(y);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void php() {
|
||||||
|
push8(status | FLAG_BREAK);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void pla() {
|
||||||
|
a = pull8();
|
||||||
|
|
||||||
|
zerocalc(a);
|
||||||
|
signcalc(a);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void plx() {
|
||||||
|
x = pull8();
|
||||||
|
|
||||||
|
zerocalc(x);
|
||||||
|
signcalc(x);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ply() {
|
||||||
|
y = pull8();
|
||||||
|
|
||||||
|
zerocalc(y);
|
||||||
|
signcalc(y);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void plp() {
|
||||||
|
status = pull8() | FLAG_CONSTANT;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void rol() {
|
||||||
|
value = getvalue();
|
||||||
|
result = (value << 1) | (status & FLAG_CARRY);
|
||||||
|
|
||||||
|
carrycalc(result);
|
||||||
|
zerocalc(result);
|
||||||
|
signcalc(result);
|
||||||
|
|
||||||
|
putvalue(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ror() {
|
||||||
|
value = getvalue();
|
||||||
|
result = (value >> 1) | ((status & FLAG_CARRY) << 7);
|
||||||
|
|
||||||
|
if (value & 1) setcarry();
|
||||||
|
else clearcarry();
|
||||||
|
zerocalc(result);
|
||||||
|
signcalc(result);
|
||||||
|
|
||||||
|
putvalue(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void rti() {
|
||||||
|
status = pull8();
|
||||||
|
value = pull16();
|
||||||
|
pc = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void rts() {
|
||||||
|
value = pull16();
|
||||||
|
pc = value + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void sbc() {
|
||||||
|
penaltyop = 1;
|
||||||
|
value = getvalue() ^ 0x00FF;
|
||||||
|
result = (uint16_t)a + value + (uint16_t)(status & FLAG_CARRY);
|
||||||
|
|
||||||
|
carrycalc(result);
|
||||||
|
zerocalc(result);
|
||||||
|
overflowcalc(result, a, value);
|
||||||
|
signcalc(result);
|
||||||
|
|
||||||
|
#ifndef NES_CPU
|
||||||
|
if (status & FLAG_DECIMAL) {
|
||||||
|
clearcarry();
|
||||||
|
|
||||||
|
a -= 0x66;
|
||||||
|
if ((a & 0x0F) > 0x09) {
|
||||||
|
a += 0x06;
|
||||||
|
}
|
||||||
|
if ((a & 0xF0) > 0x90) {
|
||||||
|
a += 0x60;
|
||||||
|
setcarry();
|
||||||
|
}
|
||||||
|
|
||||||
|
clockticks6502++;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
saveaccum(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void sec() {
|
||||||
|
setcarry();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void sed() {
|
||||||
|
setdecimal();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void sei() {
|
||||||
|
setinterrupt();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void sta() {
|
||||||
|
putvalue(a);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void stx() {
|
||||||
|
putvalue(x);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void sty() {
|
||||||
|
putvalue(y);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void stz() {
|
||||||
|
putvalue(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void tax() {
|
||||||
|
x = a;
|
||||||
|
|
||||||
|
zerocalc(x);
|
||||||
|
signcalc(x);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void tay() {
|
||||||
|
y = a;
|
||||||
|
|
||||||
|
zerocalc(y);
|
||||||
|
signcalc(y);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void tsx() {
|
||||||
|
x = sp;
|
||||||
|
|
||||||
|
zerocalc(x);
|
||||||
|
signcalc(x);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void txa() {
|
||||||
|
a = x;
|
||||||
|
|
||||||
|
zerocalc(a);
|
||||||
|
signcalc(a);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void txs() {
|
||||||
|
sp = x;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void tya() {
|
||||||
|
a = y;
|
||||||
|
|
||||||
|
zerocalc(a);
|
||||||
|
signcalc(a);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void (*addrtable[256])() = {
|
||||||
|
/* | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | A | B | C | D | E | F | */
|
||||||
|
/* 0 */ imp, indx, imp, indx, zp, zp, zp, zp, stk, imm, acc, imm, abso, abso, abso, abso, /* 0 */
|
||||||
|
/* 1 */ rel, indy, indz, indy, zpx, zpx, zpx, zpx, imp, absy, acc, absy, absx, absx, absx, absx, /* 1 */
|
||||||
|
/* 2 */ abso, indx, imp, indx, zp, zp, zp, zp, stk, imm, acc, imm, abso, abso, abso, abso, /* 2 */
|
||||||
|
/* 3 */ rel, indy, indz, indy, zpx, zpx, zpx, zpx, imp, absy, acc, absy, absx, absx, absx, absx, /* 3 */
|
||||||
|
/* 4 */ imp, indx, imp, indx, zp, zp, zp, zp, imp, imm, acc, imm, abso, abso, abso, abso, /* 4 */
|
||||||
|
/* 5 */ rel, indy, indz, indy, zpx, zpx, zpx, zpx, imp, absy, stk, absy, absx, absx, absx, absx, /* 5 */
|
||||||
|
/* 6 */ imp, indx, imp, indx, zp, zp, zp, zp, imp, imm, acc, imm, ind, abso, abso, abso, /* 6 */
|
||||||
|
/* 7 */ rel, indy, indz, indy, zpx, zpx, zpx, zpx, imp, absy, stk, absy, absx, absx, absx, absx, /* 7 */
|
||||||
|
/* 8 */ rel, indx, imp, indx, zp, zp, zp, zp, imp, imm, imp, imm, abso, abso, abso, abso, /* 8 */
|
||||||
|
/* 9 */ rel, indy, indz, indy, zpx, zpx, zpy, zpy, imp, absy, imp, absy, abso, absx, absx, absy, /* 9 */
|
||||||
|
/* A */ imm, indx, imm, indx, zp, zp, zp, zp, imp, imm, imp, imm, abso, abso, abso, abso, /* A */
|
||||||
|
/* B */ rel, indy, indz, indy, zpx, zpx, zpy, zpy, imp, absy, imp, absy, absx, absx, absy, absy, /* B */
|
||||||
|
/* C */ imm, indx, imp, indx, zp, zp, zp, zp, imp, imm, imp, imm, abso, abso, abso, abso, /* C */
|
||||||
|
/* D */ rel, indy, indz, indy, zpx, zpx, zpx, zpx, imp, absy, stk, absy, absx, absx, absx, absx, /* D */
|
||||||
|
/* E */ imm, indx, imp, indx, zp, zp, zp, zp, imp, imm, imp, imm, abso, abso, abso, abso, /* E */
|
||||||
|
/* F */ rel, indy, indz, indy, zpx, zpx, zpx, zpx, imp, absy, stk, absy, absx, absx, absx, absx /* F */
|
||||||
|
};
|
||||||
|
|
||||||
|
static void (*optable[256])() = {
|
||||||
|
/* | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | A | B | C | D | E | F | */
|
||||||
|
/* 0 */ brk, ora, nop, nop, nop, ora, asl, nop, php, ora, asl, nop, nop, ora, asl, nop, /* 0 */
|
||||||
|
/* 1 */ bpl, ora, ora, nop, nop, ora, asl, nop, clc, ora, inc, nop, nop, ora, asl, nop, /* 1 */
|
||||||
|
/* 2 */ jsr, and, nop, nop, bit, and, rol, nop, plp, and, rol, nop, bit, and, rol, nop, /* 2 */
|
||||||
|
/* 3 */ bmi, and, and, nop, nop, and, rol, nop, sec, and, dec, nop, nop, and, rol, nop, /* 3 */
|
||||||
|
/* 4 */ rti, eor, nop, nop, nop, eor, lsr, nop, pha, eor, lsr, nop, jmp, eor, lsr, nop, /* 4 */
|
||||||
|
/* 5 */ bvc, eor, eor, nop, nop, eor, lsr, nop, cli, eor, phy, nop, nop, eor, lsr, nop, /* 5 */
|
||||||
|
/* 6 */ rts, adc, nop, nop, stz, adc, ror, nop, pla, adc, ror, nop, jmp, adc, ror, nop, /* 6 */
|
||||||
|
/* 7 */ bvs, adc, adc, nop, stz, adc, ror, nop, sei, adc, ply, nop, nop, adc, ror, nop, /* 7 */
|
||||||
|
/* 8 */ bra, sta, nop, nop, sty, sta, stx, nop, dey, nop, txa, nop, sty, sta, stx, nop, /* 8 */
|
||||||
|
/* 9 */ bcc, sta, sta, nop, sty, sta, stx, nop, tya, sta, txs, nop, stz, sta, stz, nop, /* 9 */
|
||||||
|
/* A */ ldy, lda, ldx, nop, ldy, lda, ldx, nop, tay, lda, tax, nop, ldy, lda, ldx, nop, /* A */
|
||||||
|
/* B */ bcs, lda, lda, nop, ldy, lda, ldx, nop, clv, lda, tsx, nop, ldy, lda, ldx, nop, /* B */
|
||||||
|
/* C */ cpy, cmp, nop, nop, cpy, cmp, dec, nop, iny, cmp, dex, nop, cpy, cmp, dec, nop, /* C */
|
||||||
|
/* D */ bne, cmp, cmp, nop, nop, cmp, dec, nop, cld, cmp, phx, nop, nop, cmp, dec, nop, /* D */
|
||||||
|
/* E */ cpx, sbc, nop, nop, cpx, sbc, inc, nop, inx, sbc, nop, sbc, cpx, sbc, inc, nop, /* E */
|
||||||
|
/* F */ beq, sbc, sbc, nop, nop, sbc, inc, nop, sed, sbc, plx, nop, nop, sbc, inc, nop /* F */
|
||||||
|
};
|
||||||
|
|
||||||
|
static const uint32_t ticktable[256] = {
|
||||||
|
/* | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | A | B | C | D | E | F | */
|
||||||
|
/* 0 */ 7, 6, 2, 8, 3, 3, 5, 5, 3, 2, 2, 2, 4, 4, 6, 6, /* 0 */
|
||||||
|
/* 1 */ 2, 5, 2, 8, 4, 4, 6, 6, 2, 4, 2, 7, 4, 4, 7, 7, /* 1 */
|
||||||
|
/* 2 */ 6, 6, 2, 8, 3, 3, 5, 5, 4, 2, 2, 2, 4, 4, 6, 6, /* 2 */
|
||||||
|
/* 3 */ 2, 5, 2, 8, 4, 4, 6, 6, 2, 4, 2, 7, 4, 4, 7, 7, /* 3 */
|
||||||
|
/* 4 */ 6, 6, 2, 8, 3, 3, 5, 5, 3, 2, 2, 2, 3, 4, 6, 6, /* 4 */
|
||||||
|
/* 5 */ 2, 5, 2, 8, 4, 4, 6, 6, 2, 4, 2, 7, 4, 4, 7, 7, /* 5 */
|
||||||
|
/* 6 */ 6, 6, 2, 8, 3, 3, 5, 5, 4, 2, 2, 2, 5, 4, 6, 6, /* 6 */
|
||||||
|
/* 7 */ 2, 5, 2, 8, 4, 4, 6, 6, 2, 4, 2, 7, 4, 4, 7, 7, /* 7 */
|
||||||
|
/* 8 */ 2, 6, 2, 6, 3, 3, 3, 3, 2, 2, 2, 2, 4, 4, 4, 4, /* 8 */
|
||||||
|
/* 9 */ 2, 6, 2, 6, 4, 4, 4, 4, 2, 5, 2, 5, 5, 5, 5, 5, /* 9 */
|
||||||
|
/* A */ 2, 6, 2, 6, 3, 3, 3, 3, 2, 2, 2, 2, 4, 4, 4, 4, /* A */
|
||||||
|
/* B */ 2, 5, 2, 5, 4, 4, 4, 4, 2, 4, 2, 4, 4, 4, 4, 4, /* B */
|
||||||
|
/* C */ 2, 6, 2, 8, 3, 3, 5, 5, 2, 2, 2, 2, 4, 4, 6, 6, /* C */
|
||||||
|
/* D */ 2, 5, 2, 8, 4, 4, 6, 6, 2, 4, 2, 7, 4, 4, 7, 7, /* D */
|
||||||
|
/* E */ 2, 6, 2, 8, 3, 3, 5, 5, 2, 2, 2, 2, 4, 4, 6, 6, /* E */
|
||||||
|
/* F */ 2, 5, 2, 8, 4, 4, 6, 6, 2, 4, 2, 7, 4, 4, 7, 7 /* F */
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
void nmi6502() {
|
||||||
|
push16(pc);
|
||||||
|
push8(status);
|
||||||
|
status |= FLAG_INTERRUPT;
|
||||||
|
pc = (uint16_t)read6502(0xFFFA) | ((uint16_t)read6502(0xFFFB) << 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
void irq6502() {
|
||||||
|
push16(pc);
|
||||||
|
push8(status);
|
||||||
|
status |= FLAG_INTERRUPT;
|
||||||
|
pc = (uint16_t)read6502(0xFFFE) | ((uint16_t)read6502(0xFFFF) << 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t callexternal = 0;
|
||||||
|
void (*loopexternal)();
|
||||||
|
|
||||||
|
void exec6502(uint32_t tickcount) {
|
||||||
|
clockgoal6502 += tickcount;
|
||||||
|
|
||||||
|
while (clockticks6502 < clockgoal6502) {
|
||||||
|
opcode = read6502(pc++);
|
||||||
|
status |= FLAG_CONSTANT;
|
||||||
|
|
||||||
|
penaltyop = 0;
|
||||||
|
penaltyaddr = 0;
|
||||||
|
|
||||||
|
(*addrtable[opcode])();
|
||||||
|
(*optable[opcode])();
|
||||||
|
clockticks6502 += ticktable[opcode];
|
||||||
|
if (penaltyop && penaltyaddr) clockticks6502++;
|
||||||
|
|
||||||
|
instructions++;
|
||||||
|
|
||||||
|
if (callexternal) (*loopexternal)();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void step6502() {
|
||||||
|
opcode = read6502(pc++);
|
||||||
|
status |= FLAG_CONSTANT;
|
||||||
|
|
||||||
|
penaltyop = 0;
|
||||||
|
penaltyaddr = 0;
|
||||||
|
|
||||||
|
(*addrtable[opcode])();
|
||||||
|
(*optable[opcode])();
|
||||||
|
clockticks6502 += ticktable[opcode];
|
||||||
|
if (penaltyop && penaltyaddr) clockticks6502++;
|
||||||
|
clockgoal6502 = clockticks6502;
|
||||||
|
|
||||||
|
instructions++;
|
||||||
|
|
||||||
|
if (callexternal) (*loopexternal)();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
void hookexternal(void *funcptr) {
|
||||||
|
if (funcptr != (void *)NULL) {
|
||||||
|
loopexternal = funcptr;
|
||||||
|
callexternal = 1;
|
||||||
|
} else callexternal = 0;
|
||||||
|
}
|
||||||
|
*/
|
17
input-convert.py
Normal file
17
input-convert.py
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
from itertools import chain
|
||||||
|
|
||||||
|
input = """
|
||||||
|
1721
|
||||||
|
979
|
||||||
|
366
|
||||||
|
299
|
||||||
|
675
|
||||||
|
1456
|
||||||
|
"""
|
||||||
|
|
||||||
|
l = map(int, input.split())
|
||||||
|
|
||||||
|
f = lambda n: ((n & 0xff), ((n >> 8) & 0xff))
|
||||||
|
|
||||||
|
for n in chain.from_iterable(map(f, l)):
|
||||||
|
print(f"{n:02x}")
|
276
instruction.c
Normal file
276
instruction.c
Normal file
@ -0,0 +1,276 @@
|
|||||||
|
#include "instruction.h"
|
||||||
|
#include "opcodes.h"
|
||||||
|
|
||||||
|
const struct instruction decode_ins[256] = {
|
||||||
|
{BRK, S},
|
||||||
|
{ORA, ZPII},
|
||||||
|
{O_INVALID, M_INVALID},
|
||||||
|
{O_INVALID, M_INVALID},
|
||||||
|
{TSB, ZP},
|
||||||
|
{ORA, ZP},
|
||||||
|
{ASL, ZP},
|
||||||
|
{RMB0, ZP},
|
||||||
|
{PHP, S},
|
||||||
|
{ORA, IMM},
|
||||||
|
{ASL, ACC},
|
||||||
|
{O_INVALID, M_INVALID},
|
||||||
|
{TSB, A},
|
||||||
|
{ORA, A},
|
||||||
|
{ASL, A},
|
||||||
|
{BBR0, R},
|
||||||
|
|
||||||
|
{BPL, R},
|
||||||
|
{ORA, ZPIY},
|
||||||
|
{ORA, ZPI},
|
||||||
|
{O_INVALID, M_INVALID},
|
||||||
|
{TRB, ZP},
|
||||||
|
{ORA, ZPX},
|
||||||
|
{ASL, ZPX},
|
||||||
|
{RMB1, ZP},
|
||||||
|
{CLC, I},
|
||||||
|
{ORA, AIY},
|
||||||
|
{INC, ACC},
|
||||||
|
{O_INVALID, M_INVALID},
|
||||||
|
{TRB, A},
|
||||||
|
{ORA, AIX},
|
||||||
|
{ASL, AIX},
|
||||||
|
{BBR1, R},
|
||||||
|
|
||||||
|
{JSR, A},
|
||||||
|
{AND, ZPII},
|
||||||
|
{O_INVALID, M_INVALID},
|
||||||
|
{O_INVALID, M_INVALID},
|
||||||
|
{BIT, ZP},
|
||||||
|
{AND, ZP},
|
||||||
|
{ROL, ZP},
|
||||||
|
{RMB2, ZP},
|
||||||
|
{PLP, S},
|
||||||
|
{AND, IMM},
|
||||||
|
{ROL, ACC},
|
||||||
|
{O_INVALID, M_INVALID},
|
||||||
|
{BIT, A},
|
||||||
|
{AND, A},
|
||||||
|
{ROL, A},
|
||||||
|
{BBR2, R},
|
||||||
|
|
||||||
|
{BMI, R},
|
||||||
|
{AND, ZPIY},
|
||||||
|
{AND, ZPI},
|
||||||
|
{O_INVALID, M_INVALID},
|
||||||
|
{BIT, ZPX},
|
||||||
|
{AND, ZPX},
|
||||||
|
{ROL, ZPX},
|
||||||
|
{RMB3, ZP},
|
||||||
|
{SEC, I},
|
||||||
|
{AND, AIY},
|
||||||
|
{DEC, ACC},
|
||||||
|
{O_INVALID, M_INVALID},
|
||||||
|
{BIT, AIX},
|
||||||
|
{AND, AIX},
|
||||||
|
{ROL, AIX},
|
||||||
|
{BBR3, R},
|
||||||
|
|
||||||
|
{RTI, S},
|
||||||
|
{EOR, ZPII},
|
||||||
|
{O_INVALID, M_INVALID},
|
||||||
|
{O_INVALID, M_INVALID},
|
||||||
|
{O_INVALID, M_INVALID},
|
||||||
|
{EOR, ZP},
|
||||||
|
{LSR, ZP},
|
||||||
|
{RMB4, ZP},
|
||||||
|
{PHA, S},
|
||||||
|
{EOR, IMM},
|
||||||
|
{LSR, ACC},
|
||||||
|
{O_INVALID, M_INVALID},
|
||||||
|
{JMP, A},
|
||||||
|
{EOR, A},
|
||||||
|
{LSR, A},
|
||||||
|
{BBR4, R},
|
||||||
|
|
||||||
|
{BVC, R},
|
||||||
|
{EOR, ZPIY},
|
||||||
|
{EOR, ZPI},
|
||||||
|
{EOR, ZPX},
|
||||||
|
{O_INVALID, M_INVALID},
|
||||||
|
{O_INVALID, M_INVALID},
|
||||||
|
{LSR, ZPX},
|
||||||
|
{RMB5, ZP},
|
||||||
|
{CLI, I},
|
||||||
|
{EOR, AIY},
|
||||||
|
{PHY, S},
|
||||||
|
{O_INVALID, M_INVALID},
|
||||||
|
{O_INVALID, M_INVALID},
|
||||||
|
{EOR, AIX},
|
||||||
|
{LSR, AIX},
|
||||||
|
{BBR5, R},
|
||||||
|
|
||||||
|
{RTS, S},
|
||||||
|
{ADC, ZPII},
|
||||||
|
{O_INVALID, M_INVALID},
|
||||||
|
{O_INVALID, M_INVALID},
|
||||||
|
{STZ, ZP},
|
||||||
|
{ADC, ZP},
|
||||||
|
{ROR, ZP},
|
||||||
|
{RMB6, ZP},
|
||||||
|
{PLA, S},
|
||||||
|
{ADC, IMM},
|
||||||
|
{ROR, ACC},
|
||||||
|
{O_INVALID, M_INVALID},
|
||||||
|
{JMP, AI},
|
||||||
|
{ADC, A},
|
||||||
|
{ROR, A},
|
||||||
|
{BBR6, R},
|
||||||
|
|
||||||
|
{BVS, R},
|
||||||
|
{ADC, ZPIY},
|
||||||
|
{ADC, ZPI},
|
||||||
|
{O_INVALID, M_INVALID},
|
||||||
|
{STZ, ZPX},
|
||||||
|
{ADC, ZPX},
|
||||||
|
{ROR, ZPX},
|
||||||
|
{RMB7, ZP},
|
||||||
|
{SEI, I},
|
||||||
|
{ADC, AIY},
|
||||||
|
{PLY, S},
|
||||||
|
{O_INVALID, M_INVALID},
|
||||||
|
{JMP, AII},
|
||||||
|
{ADC, AIX},
|
||||||
|
{ROR, AIX},
|
||||||
|
{BBR7, R},
|
||||||
|
|
||||||
|
{BRA, R},
|
||||||
|
{STA, ZPII},
|
||||||
|
{O_INVALID, M_INVALID},
|
||||||
|
{O_INVALID, M_INVALID},
|
||||||
|
{STY, ZP},
|
||||||
|
{STA, ZP},
|
||||||
|
{STX, ZP},
|
||||||
|
{SMB0, ZP},
|
||||||
|
{DEY, I},
|
||||||
|
{BIT, IMM},
|
||||||
|
{TXA, I},
|
||||||
|
{O_INVALID, M_INVALID},
|
||||||
|
{STY, A},
|
||||||
|
{STA, A},
|
||||||
|
{STX, A},
|
||||||
|
{BBS0, R},
|
||||||
|
|
||||||
|
{BCC, R},
|
||||||
|
{STA, ZPIY},
|
||||||
|
{STA, ZPI},
|
||||||
|
{O_INVALID, M_INVALID},
|
||||||
|
{STY, ZPX},
|
||||||
|
{STA, ZPX},
|
||||||
|
{STX, ZPY},
|
||||||
|
{SMB1, ZP},
|
||||||
|
{TYA, I},
|
||||||
|
{STA, AIY},
|
||||||
|
{TXS, I},
|
||||||
|
{O_INVALID, M_INVALID},
|
||||||
|
{STZ, A},
|
||||||
|
{STA, AIX},
|
||||||
|
{STZ, AIX},
|
||||||
|
{BBS1, R},
|
||||||
|
|
||||||
|
{LDY, IMM},
|
||||||
|
{LDA, ZPII},
|
||||||
|
{LDX, IMM},
|
||||||
|
{O_INVALID, M_INVALID},
|
||||||
|
{LDY, ZP},
|
||||||
|
{LDA, ZP},
|
||||||
|
{LDX, ZP},
|
||||||
|
{SMB2, ZP},
|
||||||
|
{TAY, I},
|
||||||
|
{LDA, IMM},
|
||||||
|
{TAX, I},
|
||||||
|
{O_INVALID, M_INVALID},
|
||||||
|
{LDY, A},
|
||||||
|
{LDA, A},
|
||||||
|
{LDX, A},
|
||||||
|
{BBS2, R},
|
||||||
|
|
||||||
|
{BCS, R},
|
||||||
|
{LDA, ZPIY},
|
||||||
|
{LDA, ZPI},
|
||||||
|
{O_INVALID, M_INVALID},
|
||||||
|
{LDY, ZPX},
|
||||||
|
{LDA, ZPX},
|
||||||
|
{LDX, ZPY},
|
||||||
|
{SMB3, ZP},
|
||||||
|
{CLV, I},
|
||||||
|
{LDA, AIY},
|
||||||
|
{TSX, I},
|
||||||
|
{O_INVALID, M_INVALID},
|
||||||
|
{LDY, AIX},
|
||||||
|
{LDA, AIX},
|
||||||
|
{LDX, AIY},
|
||||||
|
{BBS3, R},
|
||||||
|
|
||||||
|
{CPY, IMM},
|
||||||
|
{CMP, ZPII},
|
||||||
|
{O_INVALID, M_INVALID},
|
||||||
|
{O_INVALID, M_INVALID},
|
||||||
|
{CPY, ZP},
|
||||||
|
{CMP, ZP},
|
||||||
|
{DEC, ZP},
|
||||||
|
{SMB4, ZP},
|
||||||
|
{INY, I},
|
||||||
|
{CMP, IMM},
|
||||||
|
{DEX, I},
|
||||||
|
{WAI, I},
|
||||||
|
{CPY, A},
|
||||||
|
{CMP, A},
|
||||||
|
{DEC, A},
|
||||||
|
{BBS4, R},
|
||||||
|
|
||||||
|
{BNE, R},
|
||||||
|
{CMP, ZPIY},
|
||||||
|
{CMP, ZPI},
|
||||||
|
{O_INVALID, M_INVALID},
|
||||||
|
{O_INVALID, M_INVALID},
|
||||||
|
{CMP, ZPX},
|
||||||
|
{DEC, ZPX},
|
||||||
|
{SMB5, ZP},
|
||||||
|
{CLD, I},
|
||||||
|
{CMP, AIY},
|
||||||
|
{PHX, S},
|
||||||
|
{STP, I},
|
||||||
|
{O_INVALID, M_INVALID},
|
||||||
|
{CMP, AIX},
|
||||||
|
{DEC, AIX},
|
||||||
|
{BBS5, R},
|
||||||
|
|
||||||
|
{CPX, IMM},
|
||||||
|
{SBC, ZPII},
|
||||||
|
{O_INVALID, M_INVALID},
|
||||||
|
{O_INVALID, M_INVALID},
|
||||||
|
{CPX, ZP},
|
||||||
|
{SBC, ZP},
|
||||||
|
{INC, ZP},
|
||||||
|
{SMB6, ZP},
|
||||||
|
{INX, I},
|
||||||
|
{SBC, IMM},
|
||||||
|
{NOP, I},
|
||||||
|
{O_INVALID, M_INVALID},
|
||||||
|
{CPX, A},
|
||||||
|
{SBC, A},
|
||||||
|
{INC, A},
|
||||||
|
{BBS6, R},
|
||||||
|
|
||||||
|
{BEQ, R},
|
||||||
|
{SBC, ZPIY},
|
||||||
|
{SBC, ZPI},
|
||||||
|
{O_INVALID, M_INVALID},
|
||||||
|
{O_INVALID, M_INVALID},
|
||||||
|
{SBC, ZPX},
|
||||||
|
{INC, ZPX},
|
||||||
|
{SMB7, ZP},
|
||||||
|
{SED, I},
|
||||||
|
{SBC, AIY},
|
||||||
|
{PLX, S},
|
||||||
|
{O_INVALID, M_INVALID},
|
||||||
|
{O_INVALID, M_INVALID},
|
||||||
|
{SBC, AIX},
|
||||||
|
{INC, AIX},
|
||||||
|
{BBS7, R},
|
||||||
|
};
|
8
instruction.h
Normal file
8
instruction.h
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
typedef struct instruction {
|
||||||
|
int opcode;
|
||||||
|
int mode;
|
||||||
|
} instruction_t;
|
||||||
|
|
||||||
|
extern const struct instruction decode_ins[256];
|
29
main.c
Normal file
29
main.c
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
#include <stdint.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#include "cpu.h"
|
||||||
|
#include "present.h"
|
||||||
|
|
||||||
|
int main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
if (argc < 2) {
|
||||||
|
fprintf(stderr, "argc < 2\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
FILE * f;
|
||||||
|
size_t ret;
|
||||||
|
|
||||||
|
f = fopen(argv[1], "r");
|
||||||
|
const int program_location = 0x0200;
|
||||||
|
ret = fread(cpu_memory + program_location, 1, 0x10000 - program_location, f);
|
||||||
|
fprintf(stderr, "loaded %ld program bytes at %x\n", ret, program_location);
|
||||||
|
fclose(f);
|
||||||
|
|
||||||
|
cpu_memory[0xfffc] = (program_location >> 0) & 0xff;
|
||||||
|
cpu_memory[0xfffd] = (program_location >> 8) & 0xff;
|
||||||
|
|
||||||
|
cpu_reset();
|
||||||
|
|
||||||
|
return present_main();
|
||||||
|
}
|
120
mneumonic-strings.h
Normal file
120
mneumonic-strings.h
Normal file
@ -0,0 +1,120 @@
|
|||||||
|
#pragma once
|
||||||
|
// addressing modes
|
||||||
|
|
||||||
|
#define S_A "a"
|
||||||
|
#define S_AII "(a,x)"
|
||||||
|
#define S_AIX "a,x"
|
||||||
|
#define S_AIY "a,y"
|
||||||
|
#define S_AI "(a)"
|
||||||
|
#define S_ACC "A"
|
||||||
|
#define S_IMM "#"
|
||||||
|
#define S_I "i"
|
||||||
|
#define S_R "r"
|
||||||
|
#define S_S "s"
|
||||||
|
#define S_ZP "zp"
|
||||||
|
#define S_ZPII "(zp,x)"
|
||||||
|
#define S_ZPX "zp,x"
|
||||||
|
#define S_ZPY "zp,y"
|
||||||
|
#define S_ZPI "(zp)"
|
||||||
|
#define S_ZPIY "(zp),y"
|
||||||
|
#define S_M_INVALID "?"
|
||||||
|
|
||||||
|
#define S_ADC "ADC"
|
||||||
|
#define S_AND "AND"
|
||||||
|
#define S_ASL "ASL"
|
||||||
|
#define S_BBR0 "BBR0"
|
||||||
|
#define S_BBR1 "BBR1"
|
||||||
|
#define S_BBR2 "BBR2"
|
||||||
|
#define S_BBR3 "BBR3"
|
||||||
|
#define S_BBR4 "BBR4"
|
||||||
|
#define S_BBR5 "BBR5"
|
||||||
|
#define S_BBR6 "BBR6"
|
||||||
|
#define S_BBR7 "BBR7"
|
||||||
|
#define S_BBS0 "BBS0"
|
||||||
|
#define S_BBS1 "BBS1"
|
||||||
|
#define S_BBS2 "BBS2"
|
||||||
|
#define S_BBS3 "BBS3"
|
||||||
|
#define S_BBS4 "BBS4"
|
||||||
|
#define S_BBS5 "BBS5"
|
||||||
|
#define S_BBS6 "BBS6"
|
||||||
|
#define S_BBS7 "BBS7"
|
||||||
|
#define S_BCC "BCC"
|
||||||
|
#define S_BCS "BCS"
|
||||||
|
#define S_BEQ "BEQ"
|
||||||
|
#define S_BIT "BIT"
|
||||||
|
#define S_BMI "BMI"
|
||||||
|
#define S_BNE "BNE"
|
||||||
|
#define S_BPL "BPL"
|
||||||
|
#define S_BRA "BRA"
|
||||||
|
#define S_BRK "BRK"
|
||||||
|
#define S_BVC "BVC"
|
||||||
|
#define S_BVS "BVS"
|
||||||
|
#define S_CLC "CLC"
|
||||||
|
#define S_CLD "CLD"
|
||||||
|
#define S_CLI "CLI"
|
||||||
|
#define S_CLV "CLV"
|
||||||
|
#define S_CMP "CMP"
|
||||||
|
#define S_CPX "CPX"
|
||||||
|
#define S_CPY "CPY"
|
||||||
|
#define S_DEC "DEC"
|
||||||
|
#define S_DEX "DEX"
|
||||||
|
#define S_DEY "DEY"
|
||||||
|
#define S_EOR "EOR"
|
||||||
|
#define S_INC "INC"
|
||||||
|
#define S_INX "INX"
|
||||||
|
#define S_INY "INY"
|
||||||
|
#define S_JMP "JMP"
|
||||||
|
#define S_JSR "JSR"
|
||||||
|
#define S_LDA "LDA"
|
||||||
|
#define S_LDX "LDX"
|
||||||
|
#define S_LDY "LDY"
|
||||||
|
#define S_LSR "LSR"
|
||||||
|
#define S_NOP "NOP"
|
||||||
|
#define S_ORA "ORA"
|
||||||
|
#define S_PHA "PHA"
|
||||||
|
#define S_PHP "PHP"
|
||||||
|
#define S_PHX "PHX"
|
||||||
|
#define S_PHY "PHY"
|
||||||
|
#define S_PLA "PLA"
|
||||||
|
#define S_PLP "PLP"
|
||||||
|
#define S_PLX "PLX"
|
||||||
|
#define S_PLY "PLY"
|
||||||
|
#define S_RMB0 "RMB0"
|
||||||
|
#define S_RMB1 "RMB1"
|
||||||
|
#define S_RMB2 "RMB2"
|
||||||
|
#define S_RMB3 "RMB3"
|
||||||
|
#define S_RMB4 "RMB4"
|
||||||
|
#define S_RMB5 "RMB5"
|
||||||
|
#define S_RMB6 "RMB6"
|
||||||
|
#define S_RMB7 "RMB7"
|
||||||
|
#define S_ROL "ROL"
|
||||||
|
#define S_ROR "ROR"
|
||||||
|
#define S_RTI "RTI"
|
||||||
|
#define S_RTS "RTS"
|
||||||
|
#define S_SBC "SBC"
|
||||||
|
#define S_SEC "SEC"
|
||||||
|
#define S_SED "SED"
|
||||||
|
#define S_SEI "SEI"
|
||||||
|
#define S_SMB0 "SMB0"
|
||||||
|
#define S_SMB1 "SMB1"
|
||||||
|
#define S_SMB2 "SMB2"
|
||||||
|
#define S_SMB3 "SMB3"
|
||||||
|
#define S_SMB4 "SMB4"
|
||||||
|
#define S_SMB5 "SMB5"
|
||||||
|
#define S_SMB6 "SMB6"
|
||||||
|
#define S_SMB7 "SMB7"
|
||||||
|
#define S_STA "STA"
|
||||||
|
#define S_STP "STP"
|
||||||
|
#define S_STX "STX"
|
||||||
|
#define S_STY "STY"
|
||||||
|
#define S_STZ "STZ"
|
||||||
|
#define S_TAX "TAX"
|
||||||
|
#define S_TAY "TAY"
|
||||||
|
#define S_TRB "TRB"
|
||||||
|
#define S_TSB "TSB"
|
||||||
|
#define S_TSX "TSX"
|
||||||
|
#define S_TXA "TXA"
|
||||||
|
#define S_TXS "TXS"
|
||||||
|
#define S_TYA "TYA"
|
||||||
|
#define S_WAI "WAI"
|
||||||
|
#define S_O_INVALID "?"
|
124
mneumonic.c
Normal file
124
mneumonic.c
Normal file
@ -0,0 +1,124 @@
|
|||||||
|
#include "mneumonic-strings.h"
|
||||||
|
#include "opcodes.h"
|
||||||
|
|
||||||
|
const char * opcode_string[] = {
|
||||||
|
[ADC] = S_ADC,
|
||||||
|
[AND] = S_AND,
|
||||||
|
[ASL] = S_ASL,
|
||||||
|
[BBR0] = S_BBR0,
|
||||||
|
[BBR1] = S_BBR1,
|
||||||
|
[BBR2] = S_BBR2,
|
||||||
|
[BBR3] = S_BBR3,
|
||||||
|
[BBR4] = S_BBR4,
|
||||||
|
[BBR5] = S_BBR5,
|
||||||
|
[BBR6] = S_BBR6,
|
||||||
|
[BBR7] = S_BBR7,
|
||||||
|
[BBS0] = S_BBS0,
|
||||||
|
[BBS1] = S_BBS1,
|
||||||
|
[BBS2] = S_BBS2,
|
||||||
|
[BBS3] = S_BBS3,
|
||||||
|
[BBS4] = S_BBS4,
|
||||||
|
[BBS5] = S_BBS5,
|
||||||
|
[BBS6] = S_BBS6,
|
||||||
|
[BBS7] = S_BBS7,
|
||||||
|
[BCC] = S_BCC,
|
||||||
|
[BCS] = S_BCS,
|
||||||
|
[BEQ] = S_BEQ,
|
||||||
|
[BIT] = S_BIT,
|
||||||
|
[BMI] = S_BMI,
|
||||||
|
[BNE] = S_BNE,
|
||||||
|
[BPL] = S_BPL,
|
||||||
|
[BRA] = S_BRA,
|
||||||
|
[BRK] = S_BRK,
|
||||||
|
[BVC] = S_BVC,
|
||||||
|
[BVS] = S_BVS,
|
||||||
|
[CLC] = S_CLC,
|
||||||
|
[CLD] = S_CLD,
|
||||||
|
[CLI] = S_CLI,
|
||||||
|
[CLV] = S_CLV,
|
||||||
|
[CMP] = S_CMP,
|
||||||
|
[CPX] = S_CPX,
|
||||||
|
[CPY] = S_CPY,
|
||||||
|
[DEC] = S_DEC,
|
||||||
|
[DEX] = S_DEX,
|
||||||
|
[DEY] = S_DEY,
|
||||||
|
[EOR] = S_EOR,
|
||||||
|
[INC] = S_INC,
|
||||||
|
[INX] = S_INX,
|
||||||
|
[INY] = S_INY,
|
||||||
|
[JMP] = S_JMP,
|
||||||
|
[JSR] = S_JSR,
|
||||||
|
[LDA] = S_LDA,
|
||||||
|
[LDX] = S_LDX,
|
||||||
|
[LDY] = S_LDY,
|
||||||
|
[LSR] = S_LSR,
|
||||||
|
[NOP] = S_NOP,
|
||||||
|
[ORA] = S_ORA,
|
||||||
|
[PHA] = S_PHA,
|
||||||
|
[PHP] = S_PHP,
|
||||||
|
[PHX] = S_PHX,
|
||||||
|
[PHY] = S_PHY,
|
||||||
|
[PLA] = S_PLA,
|
||||||
|
[PLP] = S_PLP,
|
||||||
|
[PLX] = S_PLX,
|
||||||
|
[PLY] = S_PLY,
|
||||||
|
[RMB0] = S_RMB0,
|
||||||
|
[RMB1] = S_RMB1,
|
||||||
|
[RMB2] = S_RMB2,
|
||||||
|
[RMB3] = S_RMB3,
|
||||||
|
[RMB4] = S_RMB4,
|
||||||
|
[RMB5] = S_RMB5,
|
||||||
|
[RMB6] = S_RMB6,
|
||||||
|
[RMB7] = S_RMB7,
|
||||||
|
[ROL] = S_ROL,
|
||||||
|
[ROR] = S_ROR,
|
||||||
|
[RTI] = S_RTI,
|
||||||
|
[RTS] = S_RTS,
|
||||||
|
[SBC] = S_SBC,
|
||||||
|
[SEC] = S_SEC,
|
||||||
|
[SED] = S_SED,
|
||||||
|
[SEI] = S_SEI,
|
||||||
|
[SMB0] = S_SMB0,
|
||||||
|
[SMB1] = S_SMB1,
|
||||||
|
[SMB2] = S_SMB2,
|
||||||
|
[SMB3] = S_SMB3,
|
||||||
|
[SMB4] = S_SMB4,
|
||||||
|
[SMB5] = S_SMB5,
|
||||||
|
[SMB6] = S_SMB6,
|
||||||
|
[SMB7] = S_SMB7,
|
||||||
|
[STA] = S_STA,
|
||||||
|
[STP] = S_STP,
|
||||||
|
[STX] = S_STX,
|
||||||
|
[STY] = S_STY,
|
||||||
|
[STZ] = S_STZ,
|
||||||
|
[TAX] = S_TAX,
|
||||||
|
[TAY] = S_TAY,
|
||||||
|
[TRB] = S_TRB,
|
||||||
|
[TSB] = S_TSB,
|
||||||
|
[TSX] = S_TSX,
|
||||||
|
[TXA] = S_TXA,
|
||||||
|
[TXS] = S_TXS,
|
||||||
|
[TYA] = S_TYA,
|
||||||
|
[WAI] = S_WAI,
|
||||||
|
[O_INVALID] = S_O_INVALID,
|
||||||
|
};
|
||||||
|
|
||||||
|
const char * mode_string[] = {
|
||||||
|
[A] = S_A,
|
||||||
|
[AII] = S_AII,
|
||||||
|
[AIX] = S_AIX,
|
||||||
|
[AIY] = S_AIY,
|
||||||
|
[AI] = S_AI,
|
||||||
|
[ACC] = S_ACC,
|
||||||
|
[IMM] = S_IMM,
|
||||||
|
[I] = S_I,
|
||||||
|
[R] = S_R,
|
||||||
|
[S] = S_S,
|
||||||
|
[ZP] = S_ZP,
|
||||||
|
[ZPII] = S_ZPII,
|
||||||
|
[ZPX] = S_ZPX,
|
||||||
|
[ZPY] = S_ZPY,
|
||||||
|
[ZPI] = S_ZPI,
|
||||||
|
[ZPIY] = S_ZPIY,
|
||||||
|
[M_INVALID] = S_M_INVALID,
|
||||||
|
};
|
7
mneumonic.h
Normal file
7
mneumonic.h
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
extern const char * opcode_string[];
|
||||||
|
extern const char * mode_string[];
|
||||||
|
|
||||||
|
#define MAX_MODE_LEN (6)
|
||||||
|
#define MAX_OPCODE_LEN (4)
|
121
opcodes.h
Normal file
121
opcodes.h
Normal file
@ -0,0 +1,121 @@
|
|||||||
|
enum opcode {
|
||||||
|
ADC,
|
||||||
|
AND,
|
||||||
|
ASL,
|
||||||
|
BBR0,
|
||||||
|
BBR1,
|
||||||
|
BBR2,
|
||||||
|
BBR3,
|
||||||
|
BBR4,
|
||||||
|
BBR5,
|
||||||
|
BBR6,
|
||||||
|
BBR7,
|
||||||
|
BBS0,
|
||||||
|
BBS1,
|
||||||
|
BBS2,
|
||||||
|
BBS3,
|
||||||
|
BBS4,
|
||||||
|
BBS5,
|
||||||
|
BBS6,
|
||||||
|
BBS7,
|
||||||
|
BCC,
|
||||||
|
BCS,
|
||||||
|
BEQ,
|
||||||
|
BIT,
|
||||||
|
BMI,
|
||||||
|
BNE,
|
||||||
|
BPL,
|
||||||
|
BRA,
|
||||||
|
BRK,
|
||||||
|
BVC,
|
||||||
|
BVS,
|
||||||
|
CLC,
|
||||||
|
CLD,
|
||||||
|
CLI,
|
||||||
|
CLV,
|
||||||
|
CMP,
|
||||||
|
CPX,
|
||||||
|
CPY,
|
||||||
|
DEC,
|
||||||
|
DEX,
|
||||||
|
DEY,
|
||||||
|
EOR,
|
||||||
|
INC,
|
||||||
|
INX,
|
||||||
|
INY,
|
||||||
|
JMP,
|
||||||
|
JSR,
|
||||||
|
LDA,
|
||||||
|
LDX,
|
||||||
|
LDY,
|
||||||
|
LSR,
|
||||||
|
NOP,
|
||||||
|
ORA,
|
||||||
|
PHA,
|
||||||
|
PHP,
|
||||||
|
PHX,
|
||||||
|
PHY,
|
||||||
|
PLA,
|
||||||
|
PLP,
|
||||||
|
PLX,
|
||||||
|
PLY,
|
||||||
|
RMB0,
|
||||||
|
RMB1,
|
||||||
|
RMB2,
|
||||||
|
RMB3,
|
||||||
|
RMB4,
|
||||||
|
RMB5,
|
||||||
|
RMB6,
|
||||||
|
RMB7,
|
||||||
|
ROL,
|
||||||
|
ROR,
|
||||||
|
RTI,
|
||||||
|
RTS,
|
||||||
|
SBC,
|
||||||
|
SEC,
|
||||||
|
SED,
|
||||||
|
SEI,
|
||||||
|
SMB0,
|
||||||
|
SMB1,
|
||||||
|
SMB2,
|
||||||
|
SMB3,
|
||||||
|
SMB4,
|
||||||
|
SMB5,
|
||||||
|
SMB6,
|
||||||
|
SMB7,
|
||||||
|
STA,
|
||||||
|
STP,
|
||||||
|
STX,
|
||||||
|
STY,
|
||||||
|
STZ,
|
||||||
|
TAX,
|
||||||
|
TAY,
|
||||||
|
TRB,
|
||||||
|
TSB,
|
||||||
|
TSX,
|
||||||
|
TXA,
|
||||||
|
TXS,
|
||||||
|
TYA,
|
||||||
|
WAI,
|
||||||
|
O_INVALID,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum mode {
|
||||||
|
A, // Absolute a
|
||||||
|
AII, // Absolute Indexed Indirect (a,x)
|
||||||
|
AIX, // Absolute Indexed with X a,x
|
||||||
|
AIY, // Absolute Indexed with Y a,y
|
||||||
|
AI, // Absolute Indrect (a)
|
||||||
|
ACC, // Accumulator A
|
||||||
|
IMM, // Immediate #
|
||||||
|
I, // Implied i
|
||||||
|
R, // Program Counter Relative r
|
||||||
|
S, // Stack s
|
||||||
|
ZP, // Zero Page zp
|
||||||
|
ZPII, // Zero Page Indexed Indirect (zp,x)
|
||||||
|
ZPX, // Zero Page Indexed with X zp,x
|
||||||
|
ZPY, // Zero Page Indexed with Y zp,y
|
||||||
|
ZPI, // Zero Page Indirect (zp)
|
||||||
|
ZPIY, // Zero Page Indirect Indexed with Y (zp),y
|
||||||
|
M_INVALID,
|
||||||
|
};
|
367
present.c
Normal file
367
present.c
Normal file
@ -0,0 +1,367 @@
|
|||||||
|
#include <stdint.h>
|
||||||
|
#include <assert.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <netinet/in.h>
|
||||||
|
|
||||||
|
#include <SDL.h>
|
||||||
|
#include <SDL_events.h>
|
||||||
|
#include <SDL_rect.h>
|
||||||
|
#include <SDL_render.h>
|
||||||
|
#include <SDL_surface.h>
|
||||||
|
|
||||||
|
#include "text.h"
|
||||||
|
#include "cpu.h"
|
||||||
|
#include "instruction.h"
|
||||||
|
#include "mneumonic.h"
|
||||||
|
|
||||||
|
void render_memory(SDL_Renderer * renderer, int origin_col, int origin_row)
|
||||||
|
{
|
||||||
|
int col = 0;
|
||||||
|
int row = 0;
|
||||||
|
|
||||||
|
uint8_t mem_s[2];
|
||||||
|
|
||||||
|
int row_length = 8;
|
||||||
|
|
||||||
|
#define MEM_COLOR 0xc8, 0xc8, 0xc9
|
||||||
|
|
||||||
|
col += 5;
|
||||||
|
for (int i = 0; i < row_length; i++) {
|
||||||
|
ull_base16(mem_s, 2, i);
|
||||||
|
render_text(renderer, origin_col + col, origin_row + row,
|
||||||
|
mem_s, 2,
|
||||||
|
MEM_COLOR);
|
||||||
|
col += 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
row += 1;
|
||||||
|
col = 0;
|
||||||
|
|
||||||
|
#define MEM_COLOR_2 0xff, 0xff, 0xff
|
||||||
|
for (int ix = 0xee; ix < 0x100; ix++) {
|
||||||
|
if (col == 0) {
|
||||||
|
uint8_t mem_addr_s[4];
|
||||||
|
ull_base16(mem_addr_s, 4, ix);
|
||||||
|
render_text(renderer, origin_col + col, origin_row + row,
|
||||||
|
mem_addr_s, 4,
|
||||||
|
MEM_COLOR);
|
||||||
|
col += 5;
|
||||||
|
}
|
||||||
|
|
||||||
|
ull_base16(mem_s, 2, cpu_memory[ix]);
|
||||||
|
render_text(renderer, origin_col + col, origin_row + row,
|
||||||
|
mem_s, 2,
|
||||||
|
MEM_COLOR_2);
|
||||||
|
col += 3;
|
||||||
|
|
||||||
|
if ((ix & 0x7) == 0x7) {
|
||||||
|
row += 1;
|
||||||
|
col = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
row += 1;
|
||||||
|
|
||||||
|
for (int ix = 0; ix < 64; ix++) {
|
||||||
|
if (col == 0) {
|
||||||
|
uint8_t mem_addr_s[4];
|
||||||
|
ull_base16(mem_addr_s, 4, 0x02dd + ix);
|
||||||
|
render_text(renderer, origin_col + col, origin_row + row,
|
||||||
|
mem_addr_s, 4,
|
||||||
|
MEM_COLOR);
|
||||||
|
col += 5;
|
||||||
|
}
|
||||||
|
|
||||||
|
ull_base16(mem_s, 2, cpu_memory[0x02dd + ix]);
|
||||||
|
render_text(renderer, origin_col + col, origin_row + row,
|
||||||
|
mem_s, 2,
|
||||||
|
MEM_COLOR_2);
|
||||||
|
col += 3;
|
||||||
|
|
||||||
|
if ((ix & 0x7) == 0x7) {
|
||||||
|
row += 1;
|
||||||
|
col = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void render_instruction(SDL_Renderer * renderer, int origin_col, int origin_row,
|
||||||
|
uint16_t pc, uint8_t * mem, uint16_t value)
|
||||||
|
{
|
||||||
|
int col = 0;
|
||||||
|
instruction_t instruction = decode_ins[mem[0]];
|
||||||
|
|
||||||
|
uint8_t pc_s[4];
|
||||||
|
ull_base16(pc_s, 4, pc);
|
||||||
|
render_text(renderer, origin_col + col, origin_row,
|
||||||
|
pc_s, 4,
|
||||||
|
MEM_COLOR);
|
||||||
|
col += 6;
|
||||||
|
|
||||||
|
uint8_t mem_s[2];
|
||||||
|
for (int ix = 0; ix < 3; ix++) {
|
||||||
|
if (addressing_modes[instruction.mode].alen >= ix) {
|
||||||
|
ull_base16(mem_s, 2, mem[ix]);
|
||||||
|
render_text(renderer, origin_col + col, origin_row,
|
||||||
|
mem_s, 2,
|
||||||
|
MEM_COLOR);
|
||||||
|
}
|
||||||
|
col += 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
col += 1;
|
||||||
|
|
||||||
|
#define INS_COLOR 0xf0, 0xdf, 0xaf
|
||||||
|
|
||||||
|
const char * opcode = opcode_string[instruction.opcode];
|
||||||
|
const char * mode = mode_string[instruction.mode];
|
||||||
|
|
||||||
|
int opcode_len = strlen(opcode);
|
||||||
|
int mode_len = strlen(mode);
|
||||||
|
|
||||||
|
render_text(renderer, origin_col + col, origin_row,
|
||||||
|
opcode, opcode_len,
|
||||||
|
INS_COLOR);
|
||||||
|
col += opcode_len + 1;
|
||||||
|
|
||||||
|
render_text(renderer, origin_col + col, origin_row,
|
||||||
|
mode, mode_len,
|
||||||
|
INS_COLOR);
|
||||||
|
col += mode_len + 1;
|
||||||
|
|
||||||
|
#define EFF_COLOR 0x7c, 0xb8, 0xbb
|
||||||
|
|
||||||
|
int value_len = 2 * addressing_modes[instruction.mode].olen;
|
||||||
|
if (value_len) {
|
||||||
|
uint8_t value_s[value_len];
|
||||||
|
ull_base16(value_s, value_len, value);
|
||||||
|
render_text(renderer, origin_col + col, origin_row,
|
||||||
|
value_s, value_len,
|
||||||
|
EFF_COLOR);
|
||||||
|
col += value_len + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void render_history(SDL_Renderer * renderer, int origin_col, int origin_row)
|
||||||
|
{
|
||||||
|
#define HISTORY_COLOR 0xbb, 0x7c, 0xb8
|
||||||
|
|
||||||
|
int row = 0;
|
||||||
|
render_text(renderer, origin_col - 2, origin_row + row,
|
||||||
|
"history", 7,
|
||||||
|
HISTORY_COLOR);
|
||||||
|
row++;
|
||||||
|
|
||||||
|
for (int i = 0; i < cpu_history_len; i++) {
|
||||||
|
int ix = (cpu_history_ix - (1 + i)) & 0xffff;
|
||||||
|
render_instruction(renderer, origin_col, origin_row + row++,
|
||||||
|
cpu_history[ix].state.pc,
|
||||||
|
cpu_history[ix].pc_mem,
|
||||||
|
cpu_history[ix].value);
|
||||||
|
if (row > 15)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void render_state(SDL_Renderer * renderer, int origin_col, int origin_row)
|
||||||
|
{
|
||||||
|
uint8_t pc_s[4];
|
||||||
|
uint8_t sp_s[2];
|
||||||
|
uint8_t a_s[2];
|
||||||
|
uint8_t x_s[2];
|
||||||
|
uint8_t y_s[2];
|
||||||
|
uint8_t status_s[8];
|
||||||
|
|
||||||
|
cpu_state_t state;
|
||||||
|
cpu_get_state(&state);
|
||||||
|
|
||||||
|
ull_base16(pc_s, 4, state.pc);
|
||||||
|
ull_base16(sp_s, 2, state.sp);
|
||||||
|
ull_base16(a_s, 2, state.a);
|
||||||
|
ull_base16(x_s, 2, state.x);
|
||||||
|
ull_base16(y_s, 2, state.y);
|
||||||
|
for (int i = 0; i < 8; i++) {
|
||||||
|
status_s[i] = (((state.status) >> (7 - i)) & 1) ? '1' : '0';
|
||||||
|
}
|
||||||
|
|
||||||
|
int col = 0;
|
||||||
|
|
||||||
|
#define HEADER_COLOR 0x77, 0xdd, 0x11
|
||||||
|
#define VALUE_COLOR 0xff, 0xff, 0xff
|
||||||
|
|
||||||
|
render_text(renderer, origin_col + col, origin_row,
|
||||||
|
"PC", 2,
|
||||||
|
HEADER_COLOR);
|
||||||
|
render_text(renderer, origin_col + col, origin_row + 1,
|
||||||
|
pc_s, 4,
|
||||||
|
VALUE_COLOR);
|
||||||
|
col += 2 + 3;
|
||||||
|
|
||||||
|
render_text(renderer, origin_col + col, origin_row,
|
||||||
|
"A", 1,
|
||||||
|
HEADER_COLOR);
|
||||||
|
render_text(renderer, origin_col + col, origin_row + 1,
|
||||||
|
a_s, 2,
|
||||||
|
VALUE_COLOR);
|
||||||
|
col += 2 + 1;
|
||||||
|
|
||||||
|
render_text(renderer, origin_col + col, origin_row,
|
||||||
|
"X", 1,
|
||||||
|
HEADER_COLOR);
|
||||||
|
render_text(renderer, origin_col + col, origin_row + 1,
|
||||||
|
x_s, 2,
|
||||||
|
VALUE_COLOR);
|
||||||
|
col += 2 + 1;
|
||||||
|
|
||||||
|
render_text(renderer, origin_col + col, origin_row,
|
||||||
|
"Y", 1,
|
||||||
|
HEADER_COLOR);
|
||||||
|
render_text(renderer, origin_col + col, origin_row + 1,
|
||||||
|
y_s, 2,
|
||||||
|
VALUE_COLOR);
|
||||||
|
col += 2 + 1;
|
||||||
|
|
||||||
|
render_text(renderer, origin_col + col, origin_row,
|
||||||
|
"SP", 2,
|
||||||
|
HEADER_COLOR);
|
||||||
|
render_text(renderer, origin_col + col, origin_row + 1,
|
||||||
|
sp_s, 2,
|
||||||
|
VALUE_COLOR);
|
||||||
|
col += 2 + 2;
|
||||||
|
|
||||||
|
render_text(renderer, origin_col + col, origin_row,
|
||||||
|
"NV-BDIZC", 8,
|
||||||
|
HEADER_COLOR);
|
||||||
|
render_text(renderer, origin_col + col, origin_row + 1,
|
||||||
|
status_s, 8,
|
||||||
|
VALUE_COLOR);
|
||||||
|
col += 8;
|
||||||
|
|
||||||
|
instruction_t instruction = decode_ins[cpu_memory[state.pc]];
|
||||||
|
addressing_mode_t addressing_mode = addressing_modes[instruction.mode];
|
||||||
|
uint16_t value = (addressing_mode.func)(state.pc);
|
||||||
|
|
||||||
|
render_instruction(renderer, origin_row + 2, origin_col,
|
||||||
|
state.pc,
|
||||||
|
&cpu_memory[state.pc],
|
||||||
|
value);
|
||||||
|
|
||||||
|
render_history(renderer, origin_col, origin_row + 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
void render(SDL_Renderer * renderer)
|
||||||
|
{
|
||||||
|
SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);
|
||||||
|
SDL_RenderClear(renderer);
|
||||||
|
|
||||||
|
render_state(renderer, 5, 3);
|
||||||
|
render_memory(renderer, 5 + 35, 3);
|
||||||
|
|
||||||
|
SDL_RenderPresent(renderer);
|
||||||
|
}
|
||||||
|
|
||||||
|
int present_main()
|
||||||
|
{
|
||||||
|
SDL_Window * window;
|
||||||
|
SDL_Renderer * renderer;
|
||||||
|
|
||||||
|
SDL_Init(SDL_INIT_VIDEO | SDL_INIT_EVENTS);
|
||||||
|
|
||||||
|
window = SDL_CreateWindow("cpu",
|
||||||
|
SDL_WINDOWPOS_CENTERED,
|
||||||
|
SDL_WINDOWPOS_CENTERED,
|
||||||
|
1500,
|
||||||
|
1000,
|
||||||
|
SDL_WINDOW_SHOWN);
|
||||||
|
|
||||||
|
renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED);
|
||||||
|
|
||||||
|
int ret = create_instruction_textures(renderer);
|
||||||
|
if (ret == -1)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
SDL_Event event;
|
||||||
|
int got_event = 1;
|
||||||
|
int freerun = 0;
|
||||||
|
uint64_t ticks;
|
||||||
|
uint64_t ins_count;
|
||||||
|
uint64_t clocks;
|
||||||
|
extern uint64_t clockticks6502;
|
||||||
|
while (1) {
|
||||||
|
SDL_PumpEvents();
|
||||||
|
while (SDL_PeepEvents(&event, 1, SDL_GETEVENT, SDL_FIRSTEVENT, SDL_LASTEVENT) != 0) {
|
||||||
|
switch (event.type) {
|
||||||
|
case SDL_QUIT:
|
||||||
|
goto quit;
|
||||||
|
break;
|
||||||
|
case SDL_KEYDOWN:
|
||||||
|
got_event = 1;
|
||||||
|
if (event.key.keysym.scancode == SDL_SCANCODE_Q)
|
||||||
|
goto quit;
|
||||||
|
if (event.key.keysym.scancode == SDL_SCANCODE_SPACE) {
|
||||||
|
freerun = 0;
|
||||||
|
cpu_step();
|
||||||
|
}
|
||||||
|
if (event.key.keysym.scancode == SDL_SCANCODE_RETURN) {
|
||||||
|
if (freerun == 0) {
|
||||||
|
ticks = SDL_GetTicks64();
|
||||||
|
ins_count = 0;
|
||||||
|
clocks = clockticks6502;
|
||||||
|
freerun = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case SDL_MOUSEBUTTONDOWN:
|
||||||
|
got_event = 1;
|
||||||
|
break;
|
||||||
|
case SDL_WINDOWEVENT:
|
||||||
|
got_event = 1;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
while (freerun == 1) {
|
||||||
|
cpu_state_t last_state;
|
||||||
|
cpu_get_state(&last_state);
|
||||||
|
|
||||||
|
cpu_step();
|
||||||
|
ins_count++;
|
||||||
|
|
||||||
|
cpu_state_t state;
|
||||||
|
cpu_get_state(&state);
|
||||||
|
|
||||||
|
if (last_state.pc == state.pc) {
|
||||||
|
freerun = 0;
|
||||||
|
printf("time %ju\n", SDL_GetTicks64() - ticks);
|
||||||
|
printf("ins %ju\n", ins_count);
|
||||||
|
printf("clocks %ld\n", clockticks6502 - clocks);
|
||||||
|
|
||||||
|
FILE * f = fopen("memdump.bin", "w");
|
||||||
|
assert (f != NULL);
|
||||||
|
int ret = fwrite(cpu_memory, 1, 0x10000, f);
|
||||||
|
assert (ret != -1);
|
||||||
|
fclose(f);
|
||||||
|
}
|
||||||
|
|
||||||
|
got_event = 1;
|
||||||
|
|
||||||
|
if ((ins_count % 160000) == 0)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (got_event) {
|
||||||
|
render(renderer);
|
||||||
|
got_event = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
//if (freerun == 1)
|
||||||
|
// SDL_Delay(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
quit:
|
||||||
|
SDL_DestroyWindow(window);
|
||||||
|
SDL_Quit();
|
||||||
|
return 0;
|
||||||
|
}
|
9
test/ana.asm
Normal file
9
test/ana.asm
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
;; task:
|
||||||
|
;; - there are two numbers, at addresses 0 and 1
|
||||||
|
;; - find the sum of the two numbers
|
||||||
|
;; - store the result at address 2
|
||||||
|
|
||||||
|
LDA # h0
|
||||||
|
ADC zp d0
|
||||||
|
ADC zp d1
|
||||||
|
STA zp d2
|
9
test/ana2.asm
Normal file
9
test/ana2.asm
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
;; task
|
||||||
|
;; - there are an unknown quantity of numbers, anything between 1 and 99 (dec)
|
||||||
|
;; - the `quantity` is stored at address 0
|
||||||
|
;; - the numbers are stored at addresses 1 to (1 + `quantity`)
|
||||||
|
;; - add all numbers together
|
||||||
|
;; - store the sum at address AF (hex)
|
||||||
|
|
||||||
|
LDX # h5
|
||||||
|
DEX i
|
6
test/bra.asm
Normal file
6
test/bra.asm
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
BRA r :there
|
||||||
|
NOP i
|
||||||
|
NOP i
|
||||||
|
NOP i
|
||||||
|
there: LDA # 0
|
||||||
|
LDA # 1
|
25
test/foo.asm
Normal file
25
test/foo.asm
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
; task :
|
||||||
|
; - sum the following 5 numbers
|
||||||
|
; - save the result of the sum at memory address 7F
|
||||||
|
; (numbers are in base16 notation)
|
||||||
|
11
|
||||||
|
18
|
||||||
|
23
|
||||||
|
25
|
||||||
|
30
|
||||||
|
; expected sum: A1
|
||||||
|
|
||||||
|
; program:
|
||||||
|
|
||||||
|
; mem = [0] * 128
|
||||||
|
; mem[0:5] = [0x11, 0x18, 0x23, 0x25, 0x30]
|
||||||
|
A2 00 ; LDX # 0 ; x = 0
|
||||||
|
A9 00 ; LDA # 0 ; a = 0
|
||||||
|
; loop: ; while True:
|
||||||
|
75 00 ; ADC zp,x 0 ; a += mem[0 + x]
|
||||||
|
E8 ; INX i ; x += 1
|
||||||
|
E0 05 ; CPX # 05 ; _ = (x == 5)
|
||||||
|
D0 F9 ; BNE r loop ; if _ == True: break
|
||||||
|
85 7F ; STA zp 7F ; mem[0x7f] = a
|
||||||
|
; forever: :
|
||||||
|
4C 12 00 ; JMP a forever ; while True: pass
|
14
test/instructions.asm
Normal file
14
test/instructions.asm
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
LDA # ; load the value immediately after # into the A register
|
||||||
|
STA zp ; store the value of the A register into the address at zp
|
||||||
|
|
||||||
|
;; new instructions
|
||||||
|
|
||||||
|
|
||||||
|
LDX zp ; load the value at the address in zp into the X register
|
||||||
|
DEX i ; subtract 1 to the value of the X register, store the result in the X register
|
||||||
|
BNE r ; if the result of the last subtraction is not equal to zero,
|
||||||
|
; - jump to a the specified location in the program
|
||||||
|
; otherwise,
|
||||||
|
; - continue to the next instruction immediately following this one
|
||||||
|
|
||||||
|
ADC zp,x ;
|
122
test/program.asm
Normal file
122
test/program.asm
Normal file
@ -0,0 +1,122 @@
|
|||||||
|
;; uint8_t * input_len = 8000;
|
||||||
|
;; uint16_t * input = 8001;
|
||||||
|
;; uint16_t ** input_j = 2;
|
||||||
|
;; uint16_t ** input_k = 4;
|
||||||
|
;; uint8_t * k_index = 0;
|
||||||
|
LDA # :_bin_input_start_l ;;
|
||||||
|
STA zp 4 ;;
|
||||||
|
LDA # :_bin_input_start_h ;;
|
||||||
|
STA zp 5 ;; *input_k = input
|
||||||
|
LDA # :_bin_input_size_h ;;
|
||||||
|
LSR A ;;
|
||||||
|
LDA # :_bin_input_size_l ;;
|
||||||
|
ROR A ;;
|
||||||
|
STA zp 0 ;; *input_len = _bin_input_size / 2
|
||||||
|
STA zp 1 ;; *k_index = *input_len
|
||||||
|
|
||||||
|
|
||||||
|
_loopx: LDA # :_bin_input_start_l ;;
|
||||||
|
STA zp 2 ;;
|
||||||
|
LDA # :_bin_input_start_h ;;
|
||||||
|
STA zp 3 ;; *input_j = input
|
||||||
|
LDA zp 0 ;; (input_size)
|
||||||
|
TAX i ;; X = *input_len
|
||||||
|
|
||||||
|
_loop: CLC i ;; /* 16-bit addition+comparison (lower byte) */
|
||||||
|
LDY # 0 ;;
|
||||||
|
LDA (zp),y 2 ;;
|
||||||
|
ADC (zp),y 4 ;; A = ((uint8_t *)(*input_j))[0] + ((uint8_t *)(*input_k))[0]
|
||||||
|
PHP s ;;
|
||||||
|
CMP # e4 ;;
|
||||||
|
BNE r :_next ;; if (A != 0xE4) goto _next
|
||||||
|
|
||||||
|
PLP s ;; /* 16-bit addition+comparison (upper byte) */
|
||||||
|
LDY # 1 ;;
|
||||||
|
LDA (zp),y 2 ;;
|
||||||
|
ADC (zp),y 4 ;; A = ((uint8_t *)(*input_j))[1] + ((uint8_t *)(*input_k))[1]
|
||||||
|
CMP # 07 ;;
|
||||||
|
BEQ r :_found ;; if (A == 0x07) goto _found
|
||||||
|
|
||||||
|
_next: CLC i ;;
|
||||||
|
LDA zp 2 ;;
|
||||||
|
ADC # 2 ;;
|
||||||
|
STA zp 2 ;;
|
||||||
|
LDA zp 3 ;;
|
||||||
|
ADC # 0 ;;
|
||||||
|
STA zp 3 ;; *input_j = *input_j + 2
|
||||||
|
DEX i ;;
|
||||||
|
BNE r :_loop ;; if (--X != 0) goto _loop
|
||||||
|
|
||||||
|
CLC i ;;
|
||||||
|
LDA zp 4 ;;
|
||||||
|
ADC # 2 ;;
|
||||||
|
STA zp 4 ;;
|
||||||
|
LDA zp 5 ;;
|
||||||
|
ADC # 0 ;;
|
||||||
|
STA zp 5 ;; *input_k = *input_k + 2
|
||||||
|
LDY zp 1 ;;
|
||||||
|
DEY i ;;
|
||||||
|
STY zp 1 ;; *k_index = k_index - 1;
|
||||||
|
BNE r :_loopx ;; if (*k_index != 0) goto _loopx
|
||||||
|
|
||||||
|
_not_found: JMP a :_not_found
|
||||||
|
|
||||||
|
_found: LDY # 0 ;; copy **input_j and **input_k to mul24 `a` and `b` arguments
|
||||||
|
LDA (zp),y 2 ;;
|
||||||
|
STA zp 8 ;;
|
||||||
|
LDA (zp),y 4 ;;
|
||||||
|
STA zp b ;;
|
||||||
|
;;
|
||||||
|
LDY # 1 ;;
|
||||||
|
LDA (zp),y 2 ;;
|
||||||
|
STA zp 9 ;;
|
||||||
|
LDA (zp),y 4 ;;
|
||||||
|
STA zp c ;;
|
||||||
|
;;
|
||||||
|
LDA # 0 ;;
|
||||||
|
STA zp a ;;
|
||||||
|
STA zp d ;;
|
||||||
|
|
||||||
|
;; multiply two 24-bit operands; 24-bit product
|
||||||
|
;;
|
||||||
|
;; r = a * b
|
||||||
|
|
||||||
|
;; uint24_t * a = [8, 9, a]
|
||||||
|
;; uint24_t * b = [b, c, d]
|
||||||
|
;; uint24_t * r = [10, 11, 12]
|
||||||
|
mul24: LDA # 0
|
||||||
|
STA zp 10
|
||||||
|
STA zp 11
|
||||||
|
STA zp 12
|
||||||
|
|
||||||
|
_mul24_loop: LDA zp 8 ;; while (a) {
|
||||||
|
ORA zp 9 ;;
|
||||||
|
ORA zp a ;;
|
||||||
|
BEQ r :_mul24_ret ;;
|
||||||
|
|
||||||
|
LDA # 1 ;; if (a & 1)
|
||||||
|
AND zp 8 ;;
|
||||||
|
BEQ r :_mul24_nand_1 ;;
|
||||||
|
|
||||||
|
CLC i ;; r += b;
|
||||||
|
LDA zp b ;;; 7..0
|
||||||
|
ADC zp 10 ;;
|
||||||
|
STA zp 10 ;;
|
||||||
|
LDA zp c ;;; 15..8
|
||||||
|
ADC zp 11 ;;
|
||||||
|
STA zp 11 ;;
|
||||||
|
LDA zp d ;;; 23..16
|
||||||
|
ADC zp 12 ;;
|
||||||
|
STA zp 12 ;;
|
||||||
|
|
||||||
|
_mul24_nand_1: LSR zp a ;; a >>= 1
|
||||||
|
ROR zp 9 ;;
|
||||||
|
ROR zp 8 ;;
|
||||||
|
|
||||||
|
ASL zp b ;; b <<= 1
|
||||||
|
ROL zp c ;;
|
||||||
|
ROL zp d ;;
|
||||||
|
|
||||||
|
JMP a :_mul24_loop ;; }
|
||||||
|
|
||||||
|
_mul24_ret: JMP a :_mul24_ret ;; return r
|
106
test/test.asm
Normal file
106
test/test.asm
Normal file
@ -0,0 +1,106 @@
|
|||||||
|
;; input
|
||||||
|
|
||||||
|
0D ; end of input
|
||||||
|
B9 06 ; 1721
|
||||||
|
D3 03 ; 979
|
||||||
|
6E 01 ; 366
|
||||||
|
2B 01 ; 299
|
||||||
|
A3 02 ; 675
|
||||||
|
B0 05 ; 1456
|
||||||
|
|
||||||
|
;; program
|
||||||
|
|
||||||
|
; start:
|
||||||
|
|
||||||
|
A2 01 ; LDX # 01
|
||||||
|
A0 01 ; LDY # 01
|
||||||
|
|
||||||
|
; loop:
|
||||||
|
|
||||||
|
; add16:
|
||||||
|
18 ; CLC i
|
||||||
|
B5 00 ; LDA zp,x 00
|
||||||
|
79 00 00 ; ADC a,y 00
|
||||||
|
85 AE ; STA zp AE
|
||||||
|
B5 01 ; LDA zp,x 01
|
||||||
|
79 01 00 ; ADC a,y 01
|
||||||
|
85 AF ; STA zp AF
|
||||||
|
|
||||||
|
; sub16
|
||||||
|
38 ; SEC i
|
||||||
|
A9 E4 ; LDA # E4
|
||||||
|
E5 AE ; SBC zp AE
|
||||||
|
D0 09 ; BNE r next
|
||||||
|
A9 07 ; LDA # 07
|
||||||
|
E5 AF ; SBC zp AF
|
||||||
|
D0 03 ; BNE r next
|
||||||
|
|
||||||
|
; goto multiply
|
||||||
|
4C 41 00 ; JMP a multiply
|
||||||
|
|
||||||
|
; next
|
||||||
|
E8 ; INX i
|
||||||
|
E8 ; INX i
|
||||||
|
E4 00 ; CPX zp 00
|
||||||
|
D0 DB ; BNE r loop
|
||||||
|
A2 01 ; LDX # 01
|
||||||
|
C8 ; INY i
|
||||||
|
C8 ; INY i
|
||||||
|
C4 00 ; CPY zp 00
|
||||||
|
D0 D3 ; BNE r loop
|
||||||
|
4C 0D 00 ; JMP a start
|
||||||
|
|
||||||
|
; multiply
|
||||||
|
|
||||||
|
B5 00 ; LDA zp,x 00
|
||||||
|
85 AE ; STA zp AE
|
||||||
|
B5 01 ; LDA zp,x 01
|
||||||
|
85 AF ; STA zp AF
|
||||||
|
|
||||||
|
B9 00 00 ; LDA a,y 00
|
||||||
|
AA ; TAX i
|
||||||
|
B9 01 00 ; LDA a,y 01
|
||||||
|
A8 ; TAY i
|
||||||
|
|
||||||
|
A9 00 ; LDA # 00
|
||||||
|
85 A8 ; STA zp A8
|
||||||
|
85 A9 ; STA zp A9
|
||||||
|
85 AA ; STA zp AA
|
||||||
|
|
||||||
|
; add16_24 @ 59
|
||||||
|
18 ; CLC i
|
||||||
|
A5 A8 ; LDA zp A8
|
||||||
|
65 AE ; ADC zp AE
|
||||||
|
85 A8 ; STA zp A8
|
||||||
|
|
||||||
|
A5 A9 ; LDA zp A9
|
||||||
|
65 AF ; ADC zp AF
|
||||||
|
85 A9 ; STA zp A9
|
||||||
|
|
||||||
|
A5 AA ; LDA zp AA
|
||||||
|
69 00 ; ADC # 00
|
||||||
|
85 AA ; STA zp AA
|
||||||
|
|
||||||
|
E0 00 ; CPX # 00
|
||||||
|
F0 04 ; BEQ r inc_y ; -> 74
|
||||||
|
CA ; DEX i
|
||||||
|
4C 59 00 ; JMP add16_24 ; -> 59
|
||||||
|
; inc_y
|
||||||
|
C0 00 ; CPY # 00
|
||||||
|
F0 05 ; BEQ r end ; -> 7d
|
||||||
|
CA ; DEX i
|
||||||
|
88 ; DEY i
|
||||||
|
4C 59 00 ; JMP add16_24 ; -> 59
|
||||||
|
|
||||||
|
; end
|
||||||
|
38 ; SEC i
|
||||||
|
A5 A8 ; LDA zp A8
|
||||||
|
E5 AE ; SBC zp AE
|
||||||
|
85 A8 ; STA zp A8
|
||||||
|
|
||||||
|
A5 A9 ; LDA zp A9
|
||||||
|
E5 AF ; SBC zp AF
|
||||||
|
85 A9 ; STA zp A9
|
||||||
|
|
||||||
|
; forever:
|
||||||
|
4C 8a 00 ; JMP a forever ; 8a
|
170
text.c
Normal file
170
text.c
Normal file
@ -0,0 +1,170 @@
|
|||||||
|
#include <stdint.h>
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
#include <SDL_render.h>
|
||||||
|
|
||||||
|
#include <ft2build.h>
|
||||||
|
#include FT_FREETYPE_H
|
||||||
|
|
||||||
|
typedef struct glyph_texture {
|
||||||
|
SDL_Texture * texture;
|
||||||
|
int advance;
|
||||||
|
int bearing_x;
|
||||||
|
int bearing_y;
|
||||||
|
} glyph_texture_t;
|
||||||
|
|
||||||
|
static int line_height;
|
||||||
|
|
||||||
|
static glyph_texture_t glyph_textures[256] = {0};
|
||||||
|
|
||||||
|
const char * printable = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!\"#$%&\'()*+,-./:;<=>?@[\\]^_`{|}~ ";
|
||||||
|
|
||||||
|
int create_instruction_textures(SDL_Renderer * renderer)
|
||||||
|
{
|
||||||
|
FT_Library library;
|
||||||
|
FT_Face face;
|
||||||
|
FT_Error error;
|
||||||
|
|
||||||
|
error = FT_Init_FreeType(&library);
|
||||||
|
if (error) {
|
||||||
|
fprintf(stderr, "FT_Init_FreeType\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
error = FT_New_Face(library, "/usr/share/fonts/TTF/DejaVuSansMono.ttf", 0, &face);
|
||||||
|
if (error) {
|
||||||
|
fprintf(stderr, "FT_New_Face\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(FT_IS_FIXED_WIDTH(face));
|
||||||
|
|
||||||
|
error = FT_Set_Pixel_Sizes(face, 0, 32);
|
||||||
|
if (error) {
|
||||||
|
fprintf(stderr, "FT_Select_Size: %s %d\n", FT_Error_String(error), error);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
line_height = (face->height * face->size->metrics.y_ppem) / face->units_per_EM;
|
||||||
|
|
||||||
|
SDL_Surface * surface;
|
||||||
|
SDL_Texture * texture;
|
||||||
|
|
||||||
|
unsigned long c;
|
||||||
|
int ix = 0;
|
||||||
|
|
||||||
|
while ((c = printable[ix++]) != 0) {
|
||||||
|
unsigned int glyph_index = FT_Get_Char_Index(face, c);
|
||||||
|
|
||||||
|
error = FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT);
|
||||||
|
if (error) {
|
||||||
|
fprintf(stderr, "FT_Load_Glyph: %ld %s %d\n", c, FT_Error_String(error), error);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
error = FT_Render_Glyph(face->glyph, FT_RENDER_MODE_NORMAL);
|
||||||
|
if (error) {
|
||||||
|
fprintf(stderr, "FT_Render_Glyph: %ld %s %d\n", c, FT_Error_String(error), error);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(face->glyph->bitmap.pixel_mode == FT_PIXEL_MODE_GRAY);
|
||||||
|
|
||||||
|
surface = SDL_CreateRGBSurface(0,
|
||||||
|
face->glyph->bitmap.width,
|
||||||
|
face->glyph->bitmap.rows,
|
||||||
|
32,
|
||||||
|
0xFF000000,
|
||||||
|
0x00FF0000,
|
||||||
|
0x0000FF00,
|
||||||
|
0x000000FF);
|
||||||
|
assert(surface != NULL);
|
||||||
|
SDL_SetSurfaceBlendMode(surface, SDL_BLENDMODE_BLEND);
|
||||||
|
|
||||||
|
SDL_LockSurface(surface);
|
||||||
|
|
||||||
|
for (unsigned int y = 0; y < face->glyph->bitmap.rows; y++) {
|
||||||
|
for (unsigned int x = 0; x < face->glyph->bitmap.width; x++) {
|
||||||
|
uint8_t alpha = ((uint8_t *)face->glyph->bitmap.buffer)[face->glyph->bitmap.pitch * y + x];
|
||||||
|
((uint32_t *)surface->pixels)[(surface->pitch / 4) * y + x] = 0xFFFFFF00 + alpha;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
SDL_UnlockSurface(surface);
|
||||||
|
|
||||||
|
texture = SDL_CreateTextureFromSurface(renderer, surface);
|
||||||
|
|
||||||
|
SDL_FreeSurface(surface);
|
||||||
|
|
||||||
|
glyph_textures[c] = (glyph_texture_t){
|
||||||
|
.texture = texture,
|
||||||
|
.advance = face->glyph->metrics.horiAdvance / 64,
|
||||||
|
.bearing_x = face->glyph->metrics.horiBearingX / 64,
|
||||||
|
.bearing_y = face->glyph->metrics.horiBearingY / 64,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ull_base16(void * buf, size_t len, unsigned long long n)
|
||||||
|
{
|
||||||
|
while (len > 0) {
|
||||||
|
uint8_t ni = n & 0xf;
|
||||||
|
n >>= 4;
|
||||||
|
uint8_t c;
|
||||||
|
|
||||||
|
switch (ni) {
|
||||||
|
case 0x0:
|
||||||
|
case 0x1:
|
||||||
|
case 0x2:
|
||||||
|
case 0x3:
|
||||||
|
case 0x4:
|
||||||
|
case 0x5:
|
||||||
|
case 0x6:
|
||||||
|
case 0x7:
|
||||||
|
case 0x8:
|
||||||
|
case 0x9:
|
||||||
|
c = '0' + (ni - 0x0);
|
||||||
|
break;
|
||||||
|
case 0xA:
|
||||||
|
case 0xB:
|
||||||
|
case 0xC:
|
||||||
|
case 0xD:
|
||||||
|
case 0xE:
|
||||||
|
case 0xF:
|
||||||
|
c = 'A' + (ni - 0xA);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
assert(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
((uint8_t *)buf)[--len] = c;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void render_text(SDL_Renderer * renderer, int col, int row,
|
||||||
|
const void * buf, int len,
|
||||||
|
uint8_t r, uint8_t g, uint8_t b)
|
||||||
|
{
|
||||||
|
uint8_t c;
|
||||||
|
assert(buf != NULL);
|
||||||
|
int x_origin = col * glyph_textures[((uint8_t *)buf)[0]].advance;
|
||||||
|
int y_origin = row * line_height;
|
||||||
|
int x_offset = 0;
|
||||||
|
|
||||||
|
SDL_Rect rect;
|
||||||
|
|
||||||
|
for (int ix = 0; ix < len; ix++) {
|
||||||
|
c = ((uint8_t *)buf)[ix];
|
||||||
|
assert(c != 0);
|
||||||
|
glyph_texture_t * glyph = &glyph_textures[c];
|
||||||
|
|
||||||
|
SDL_QueryTexture(glyph->texture, NULL, NULL, &rect.w, &rect.h);
|
||||||
|
rect.x = x_origin + x_offset + glyph->bearing_x;
|
||||||
|
rect.y = y_origin - glyph->bearing_y;
|
||||||
|
|
||||||
|
SDL_SetTextureColorMod(glyph->texture, r, g, b);
|
||||||
|
SDL_RenderCopy(renderer, glyph->texture, NULL, &rect);
|
||||||
|
|
||||||
|
x_offset += glyph->advance;
|
||||||
|
}
|
||||||
|
}
|
8
text.h
Normal file
8
text.h
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
int create_instruction_textures(SDL_Renderer * renderer);
|
||||||
|
void ull_base16(void * buf, size_t len, unsigned long long n);
|
||||||
|
|
||||||
|
void render_text(SDL_Renderer * renderer, int col, int row,
|
||||||
|
const void * buf, int len,
|
||||||
|
uint8_t r, uint8_t g, uint8_t b);
|
Loading…
x
Reference in New Issue
Block a user