Initial commit

This commit is contained in:
Ry 2022-10-22 18:00:51 -07:00
parent a1c97f70b2
commit 5804084401
9 changed files with 45252 additions and 0 deletions

14
Makefile Normal file
View File

@ -0,0 +1,14 @@
SDL2_CONFIG = sdl2-config
CFLAGS = -g -Ofast -std=c99 `$(SDL2_CONFIG) --cflags --libs`
TARGET=fox32
CFILES = src/main.c \
src/cpu.c \
src/framebuffer.c \
src/screen.c
$(TARGET): $(CFILES)
$(CC) -o $@ $(filter %.c, $^) $(CFLAGS)
clean:
rm -rf fox32*

43694
fox32rom.h Normal file

File diff suppressed because it is too large Load Diff

1066
src/cpu.c Normal file

File diff suppressed because it is too large Load Diff

81
src/cpu.h Normal file
View File

@ -0,0 +1,81 @@
#pragma once
#include <stddef.h>
#include <stdint.h>
#include <stdbool.h>
#include <setjmp.h>
#define FOX32_CPU_HZ 33000000
#define FOX32_MEMORY_RAM 0x04000000 // 64 MiB
#define FOX32_MEMORY_ROM 0x00080000 // 512 KiB
#define FOX32_MEMORY_ROM_START 0xF0000000
#define FOX32_POINTER_DEFAULT_INSTR FOX32_MEMORY_ROM_START
#define FOX32_POINTER_DEFAULT_STACK 0x00000000
#define FOX32_POINTER_INTERRUPTVECS 0x00000000
#define FOX32_REGISTER_LOOP 31
#define FOX32_REGISTER_COUNT 32
typedef enum {
FOX32_ERR_OK,
FOX32_ERR_INTERNAL,
FOX32_ERR_DEBUGGER,
FOX32_ERR_FAULT,
FOX32_ERR_BADOPCODE,
FOX32_ERR_BADCONDITION,
FOX32_ERR_BADREGISTER,
FOX32_ERR_BADIMMEDIATE,
FOX32_ERR_DIVZERO,
FOX32_ERR_IOREAD,
FOX32_ERR_IOWRITE,
FOX32_ERR_NOINTERRUPTS,
FOX32_ERR_CANTRECOVER
} fox32_err_t;
const char *fox32_strerr(fox32_err_t err);
typedef int fox32_io_read_t(void *user, uint32_t *value, uint32_t port);
typedef int fox32_io_write_t(void *user, uint32_t value, uint32_t port);
typedef struct {
uint32_t pointer_instr_mut;
uint32_t pointer_instr;
uint32_t pointer_stack;
uint32_t registers[FOX32_REGISTER_COUNT];
bool flag_zero;
bool flag_carry;
bool flag_interrupt;
bool halted;
bool debug;
jmp_buf panic_jmp;
fox32_err_t panic_err;
void *io_user;
fox32_io_read_t *io_read;
fox32_io_write_t *io_write;
uint8_t memory_ram[FOX32_MEMORY_RAM];
uint8_t memory_rom[FOX32_MEMORY_ROM];
} fox32_vm_t;
void fox32_init(fox32_vm_t *vm);
fox32_err_t fox32_step(fox32_vm_t *vm);
fox32_err_t fox32_resume(fox32_vm_t *vm, uint32_t count);
fox32_err_t fox32_raise(fox32_vm_t *vm, uint16_t vector);
fox32_err_t fox32_recover(fox32_vm_t *vm, fox32_err_t err);
fox32_err_t fox32_push_byte(fox32_vm_t *vm, uint8_t value);
fox32_err_t fox32_push_half(fox32_vm_t *vm, uint16_t value);
fox32_err_t fox32_push_word(fox32_vm_t *vm, uint32_t value);
fox32_err_t fox32_pop_byte(fox32_vm_t *vm, uint8_t *value);
fox32_err_t fox32_pop_half(fox32_vm_t *vm, uint16_t *value);
fox32_err_t fox32_pop_word(fox32_vm_t *vm, uint32_t *value);

23
src/framebuffer.c Normal file
View File

@ -0,0 +1,23 @@
#include <SDL2/SDL.h>
#include <getopt.h>
#include <math.h>
#include <stdarg.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "cpu.h"
#include "framebuffer.h"
#include "screen.h"
uint32_t PixelBuffer[FRAMEBUFFER_WIDTH * FRAMEBUFFER_HEIGHT];
extern fox32_vm_t vm;
void FramebufferDraw(struct Screen screen) {
SDL_Texture *texture = ScreenGetTexture(screen);
memcpy(PixelBuffer, &vm.memory_ram[0x02000000], FRAMEBUFFER_WIDTH * FRAMEBUFFER_HEIGHT * 4);
SDL_UpdateTexture(texture, NULL, PixelBuffer, FRAMEBUFFER_WIDTH * 4);
}

10
src/framebuffer.h Normal file
View File

@ -0,0 +1,10 @@
#pragma once
#include "screen.h"
#define FRAMEBUFFER_WIDTH 640
#define FRAMEBUFFER_HEIGHT 480
#define VSYNC_INTERRUPT_VECTOR 0xFF
void FramebufferDraw(struct Screen screen);

101
src/main.c Normal file
View File

@ -0,0 +1,101 @@
#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 "cpu.h"
#include "framebuffer.h"
#include "screen.h"
#include "../fox32rom.h"
#define FPS 60
#define TPF 1
#define TPS (FPS * TPF)
fox32_vm_t vm;
uint32_t tick_start;
uint32_t tick_end;
int ticks = 0;
bool done = false;
void MainLoop(void);
int main(int argc, char *argv[]) {
if (SDL_Init(SDL_INIT_VIDEO) != 0) {
fprintf(stderr, "unable to initialize SDL: %s", SDL_GetError());
return 1;
}
fox32_init(&vm);
vm.halted = false;
//vm.debug = true;
memcpy(vm.memory_rom, fox32rom, sizeof(fox32rom));
ScreenCreate(
FRAMEBUFFER_WIDTH, FRAMEBUFFER_HEIGHT,
"fox32 framebuffer",
FramebufferDraw,
0,
0,
0,
0,
0
);
ScreenInit();
ScreenDraw();
tick_start = SDL_GetTicks();
tick_end = SDL_GetTicks();
while (!done) {
MainLoop();
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 MainLoop(void) {
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);
for (int i = 0; i < dt; i++) {
int cycles_left = cycles_per_tick;
if (i == dt - 1)
cycles_left += extra_cycles;
const char *msg = fox32_strerr(fox32_resume(&vm, cycles_left));
//puts(msg != NULL ? msg : "NULL");
}
if ((ticks % TPF) == 0) {
ScreenDraw();
fox32_raise(&vm, VSYNC_INTERRUPT_VECTOR);
vm.halted = false;
}
done = ScreenProcessEvents();
ticks++;
}

217
src/screen.c Normal file
View File

@ -0,0 +1,217 @@
#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 "screen.h"
#define WINDOW_TITLE_UNGRABBED "fox32 emulator"
#define WINDOW_TITLE_GRABBED "fox32 emulator - strike F1 to uncapture mouse"
struct Screen MainScreen;
int WindowWidth = 0;
int WindowHeight = 0;
int ScreenZoom = 1;
bool ScreenFirstDraw = true;
bool ScreenMouseGrabbed = false;
SDL_Window *ScreenWindow;
SDL_Renderer *ScreenRenderer;
SDL_Rect WindowRect;
void ScreenInit() {
ScreenWindow = SDL_CreateWindow(
WINDOW_TITLE_UNGRABBED,
SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED,
(int)(WindowWidth * ScreenZoom),
(int)(WindowHeight * ScreenZoom),
SDL_WINDOW_HIDDEN
);
if (!ScreenWindow) {
fprintf(stderr, "failed to create window\n");
exit(1);
}
ScreenRenderer = SDL_CreateRenderer(ScreenWindow, -1, 0);
if (!ScreenRenderer) {
fprintf(stderr, "failed to create renderer\n");
exit(1);
}
WindowRect = (SDL_Rect) {
.w = WindowWidth,
.h = WindowHeight
};
}
void ScreenDraw() {
MainScreen.Draw(MainScreen);
SDL_Rect screenrect = {
.w = MainScreen.Width,
.h = MainScreen.Height,
};
SDL_Rect winrect = {
.w = MainScreen.Width,
.h = MainScreen.Height,
.x = 0,
.y = 0
};
if ((WindowRect.w != screenrect.w) || (WindowRect.h != screenrect.h)) {
int oldx;
int oldy;
SDL_GetWindowPosition(ScreenWindow, &oldx, &oldy);
oldx += (WindowRect.w - screenrect.w)/2;
oldy += (WindowRect.h - screenrect.h)/2;
SDL_SetWindowSize(ScreenWindow, screenrect.w, screenrect.h);
SDL_SetWindowPosition(ScreenWindow, oldx, oldy);
WindowRect.w = screenrect.w;
WindowRect.h = screenrect.h;
}
SDL_RenderClear(ScreenRenderer);
SDL_RenderCopy(ScreenRenderer, MainScreen.Texture, &screenrect, &winrect);
SDL_RenderPresent(ScreenRenderer);
if (ScreenFirstDraw) {
SDL_ShowWindow(ScreenWindow);
ScreenFirstDraw = false;
}
}
bool IsAltDown = false;
extern bool UserBreak;
int ScreenProcessEvents() {
SDL_Event event;
while (SDL_PollEvent(&event)) {
switch (event.type) {
case SDL_QUIT: {
return 1;
}
case SDL_WINDOWEVENT: {
break;
}
case SDL_MOUSEMOTION: {
if (ScreenMouseGrabbed) {
if (MainScreen.MouseMoved)
MainScreen.MouseMoved(MainScreen, event.motion.xrel, event.motion.yrel);
}
break;
}
case SDL_MOUSEBUTTONDOWN: {
if (!ScreenMouseGrabbed) {
SDL_SetWindowGrab(ScreenWindow, true);
SDL_ShowCursor(false);
SDL_SetWindowTitle(ScreenWindow, WINDOW_TITLE_GRABBED);
SDL_SetRelativeMouseMode(true);
ScreenMouseGrabbed = true;
break;
}
if (MainScreen.MousePressed)
MainScreen.MousePressed(MainScreen, event.button.button);
break;
}
case SDL_MOUSEBUTTONUP: {
if (MainScreen.MouseReleased)
MainScreen.MouseReleased(MainScreen, event.button.button);
break;
}
case SDL_KEYDOWN:
if ((event.key.keysym.scancode == SDL_SCANCODE_F1) && ScreenMouseGrabbed) {
SDL_SetWindowGrab(ScreenWindow, false);
SDL_ShowCursor(true);
SDL_SetWindowTitle(ScreenWindow, WINDOW_TITLE_UNGRABBED);
SDL_SetRelativeMouseMode(false);
ScreenMouseGrabbed = false;
break;
}
if (MainScreen.KeyPressed)
MainScreen.KeyPressed(MainScreen, event.key.keysym.scancode);
break;
case SDL_KEYUP:
if (MainScreen.KeyReleased)
MainScreen.KeyReleased(MainScreen, event.key.keysym.scancode);
break;
}
}
return 0;
}
struct SDL_Texture *ScreenGetTexture(struct Screen screen) {
if (screen.Texture) {
return screen.Texture;
}
screen.Texture = SDL_CreateTexture(
ScreenRenderer,
SDL_PIXELFORMAT_ABGR32,
SDL_TEXTUREACCESS_STREAMING,
screen.Width,
screen.Height
);
SDL_SetTextureScaleMode(screen.Texture, SDL_ScaleModeNearest);
return screen.Texture;
}
struct Screen ScreenCreate(
int w, int h, char *title,
ScreenDrawF draw,
ScreenKeyPressedF keypressed,
ScreenKeyReleasedF keyreleased,
ScreenMousePressedF mousepressed,
ScreenMouseReleasedF mousereleased,
ScreenMouseMovedF mousemoved
) {
struct Screen screen;
if (w > WindowWidth)
WindowWidth = w;
if (h > WindowHeight)
WindowHeight = h;
screen.Width = w;
screen.Height = h;
screen.Title = title;
screen.Draw = draw;
screen.KeyPressed = keypressed;
screen.KeyReleased = keyreleased;
screen.MousePressed = mousepressed;
screen.MouseReleased = mousereleased;
screen.MouseMoved = mousemoved;
MainScreen = screen;
}

46
src/screen.h Normal file
View File

@ -0,0 +1,46 @@
#pragma once
#include <SDL2/SDL.h>
struct Screen;
typedef void (*ScreenDrawF)(struct Screen screen);
typedef void (*ScreenKeyPressedF)(struct Screen screen, int sdlscancode);
typedef void (*ScreenKeyReleasedF)(struct Screen screen, int sdlscancode);
typedef void (*ScreenMousePressedF)(struct Screen screen, int button);
typedef void (*ScreenMouseReleasedF)(struct Screen screen, int button);
typedef void (*ScreenMouseMovedF)(struct Screen screen, int dx, int dy);
struct Screen {
int Width;
int Height;
void *Context1;
void *Context2;
char *Title;
SDL_Texture *Texture;
ScreenDrawF Draw;
ScreenKeyPressedF KeyPressed;
ScreenKeyReleasedF KeyReleased;
ScreenMousePressedF MousePressed;
ScreenMouseReleasedF MouseReleased;
ScreenMouseMovedF MouseMoved;
};
void ScreenInit();
void ScreenDraw();
int ScreenProcessEvents();
struct SDL_Texture *ScreenGetTexture(struct Screen screen);
struct Screen ScreenCreate(
int w, int h, char *title,
ScreenDrawF draw,
ScreenKeyPressedF keypressed,
ScreenKeyReleasedF keyreleased,
ScreenMousePressedF mousepressed,
ScreenMouseReleasedF mousereleased,
ScreenMouseMovedF mousemoved
);