368 lines
8.8 KiB
C
368 lines
8.8 KiB
C
#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;
|
|
}
|