fox32/src/main.c

213 lines
5.0 KiB
C

#include <SDL2/SDL.h>
#include <getopt.h>
#include <stdarg.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/time.h>
#include <time.h>
#ifdef __EMSCRIPTEN__
#include <emscripten.h>
#include <emscripten/html5.h>
#endif
#include "bus.h"
#include "cpu.h"
#include "disk.h"
#include "framebuffer.h"
#include "keyboard.h"
#include "mouse.h"
#include "screen.h"
#include "serial.h"
#include "../fox32rom.h"
#define FPS 60
#define TPF 1
#define TPS (FPS * TPF)
fox32_vm_t vm;
extern bool bus_requests_exit;
extern disk_controller_t disk_controller;
uint32_t tick_start;
uint32_t tick_end;
int ticks = 0;
bool done = false;
time_t rtc_time;
uint32_t rtc_uptime;
void main_loop(void);
void load_rom(const char *filename);
int main(int argc, char *argv[]) {
fox32_init(&vm);
vm.io_read = bus_io_read;
vm.io_write = bus_io_write;
vm.halted = false;
vm.debug = false;
memcpy(vm.memory_rom, fox32rom, sizeof(fox32rom));
size_t disk_id = 0;
#ifndef __EMSCRIPTEN__
for (int i = 1; i < argc; i++) {
if (strcmp(argv[i], "--help") == 0) {
fprintf(stderr,
"Usage: %s [OPTIONS]\n\n"
"Options:\n"
" --help Print this message\n"
" --disk DISK Specify a disk image to use\n"
" --rom ROM Specify a ROM image to use\n"
" --debug Enable debug output\n"
" --headless Headless mode: don't open a window\n"
, argv[0]);
return 0;
} else if (strcmp(argv[i], "--disk") == 0) {
if (i + 1 < argc) {
new_disk(argv[i + 1], disk_id++);
i++;
} else {
fprintf(stderr, "no disk image specified\n");
return 1;
}
} else if (strcmp(argv[i], "--rom") == 0) {
if (i + 1 < argc) {
load_rom(argv[i + 1]);
i++;
} else {
fprintf(stderr, "no rom image specified\n");
return 1;
}
} else if (strcmp(argv[i], "--debug") == 0) {
vm.debug = true;
} else if (strcmp(argv[i], "--headless") == 0) {
vm.headless = true;
} else {
fprintf(stderr, "unrecognized option %s\n", argv[i]);
return 1;
}
}
#else
new_disk("fox32os.img", disk_id++);
#endif
if (!vm.headless) {
if (SDL_Init(SDL_INIT_VIDEO) != 0) {
fprintf(stderr, "unable to initialize SDL: %s", SDL_GetError());
return 1;
}
SDL_ShowCursor(SDL_DISABLE);
ScreenCreate(
FRAMEBUFFER_WIDTH, FRAMEBUFFER_HEIGHT,
draw_framebuffer,
key_pressed,
key_released,
mouse_pressed,
mouse_released,
mouse_moved,
drop_file
);
ScreenInit();
ScreenDraw();
}
#ifndef WINDOWS
serial_init();
#endif
tick_start = SDL_GetTicks();
tick_end = SDL_GetTicks();
#ifdef __EMSCRIPTEN__
emscripten_set_main_loop(main_loop, FPS, 1);
#endif
while (!done && !bus_requests_exit) {
main_loop();
tick_end = SDL_GetTicks();
int delay = 1000/TPS - (tick_end - tick_start);
if (delay > 0) {
SDL_Delay(delay);
} else {
//printf("time overrun %d\n", delay);
}
}
return 0;
}
void main_loop(void) {
#ifdef __EMSCRIPTEN__
if (done || bus_requests_exit) {
emscripten_cancel_main_loop();
}
#endif
int dt = SDL_GetTicks() - tick_start;
tick_start = SDL_GetTicks();
if (!dt)
dt = 1;
int cycles_per_tick = FOX32_CPU_HZ / TPS / dt;
int extra_cycles = FOX32_CPU_HZ / TPS - (cycles_per_tick * dt);
fox32_err_t error = FOX32_ERR_OK;
for (int i = 0; i < dt; i++) {
rtc_uptime += 1;
rtc_time = time(NULL);
int cycles_left = cycles_per_tick;
if (i == dt - 1)
cycles_left += extra_cycles;
while (cycles_left > 0) {
uint32_t executed = 0;
error = fox32_resume(&vm, cycles_left, &executed);
if (error != FOX32_ERR_OK) {
if (vm.debug) puts(fox32_strerr(error));
error = fox32_recover(&vm, error);
if (error != FOX32_ERR_OK)
break;
}
cycles_left -= executed;
}
}
if ((ticks % TPF) == 0) {
if (!vm.headless)
ScreenDraw();
fox32_raise(&vm, VSYNC_INTERRUPT_VECTOR);
vm.halted = false;
}
done = ScreenProcessEvents();
ticks++;
}
void load_rom(const char *filename) {
FILE *rom;
rom = fopen(filename, "r");
if (!rom) {
fprintf(stderr, "couldn't open ROM file %s\n", filename);
return;
}
printf("using %s as boot ROM\n", filename);
fread(&vm.memory_rom, sizeof(fox32rom), 1, rom);
fclose(rom);
}