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