Initial commit
This commit is contained in:
parent
a1c97f70b2
commit
5804084401
14
Makefile
Normal file
14
Makefile
Normal 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
43694
fox32rom.h
Normal file
File diff suppressed because it is too large
Load Diff
81
src/cpu.h
Normal file
81
src/cpu.h
Normal 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
23
src/framebuffer.c
Normal 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
10
src/framebuffer.h
Normal 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
101
src/main.c
Normal 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
217
src/screen.c
Normal 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
46
src/screen.h
Normal 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
|
||||
);
|
Loading…
Reference in New Issue
Block a user