dawnos/SUBLEQ

dawnos is cool and i like to write emulators so i wrote a shoddy emulator!!!

#include <stdint.h>
#include <stdlib.h>
#include <stdio.h>
#include <byteswap.h>
#include <SDL.h>

#define MEMSIZE (512 * 1024 * 1024)
#define CPU0FLAGS 0x13EE0000
#define CPU0PC 0x13EE0008
#define CPU_RUNNING 1
#define CPU_STOP_REQUESTED 2
#define CPU_STOPPED 4
#define DISPLAY_LOC (256 * 1024 * 1024)
#define DISPLAY_ON 0x13FFEFB0
#define TIMER 0x13FFFFF0
#define MOUSE_X 0x13FFF7D0
#define MOUSE_Y 0x13FFF7D8
#define MOUSE_BUTTON(v) (0x13FFF7A0 + (v == 3 ? 1 : v == 2 ? 2 : 0) * 8)
#define KEYBOARD 0x13FFF7F0

static void *mem;

static uint64_t mread(uint64_t off)
{
    return __bswap_64(*(uint64_t *)(mem + off));
}

static void mwrite(uint64_t val, uint64_t off)
{
    *(uint64_t *)(mem + off) = __bswap_64(val);
}

static void mouse_motion(int x, int y)
{
    mwrite((double)x / (double)1024 * (double)((uint64_t)1 << 32), MOUSE_X);
    mwrite((double)y / (double)512 * (double)((uint64_t)1 << 32), MOUSE_Y);
}

static void mouse_button(int which, int state)
{
    mwrite(state, MOUSE_BUTTON(which));
}

static int key_convert(int code)
{
    switch (code)
    {
        case SDLK_BACKSPACE: return 9;
        case SDLK_RETURN: return 13;
        case SDLK_UP: return 14;
        case SDLK_LEFT: return 15;
        case SDLK_DOWN: return 16;
        case SDLK_RIGHT: return 17;
        case SDLK_ESCAPE: return 27;
        default: return code;
    }
}

static void key_down(int code)
{
    mwrite(key_convert(code), KEYBOARD);
}

static uint64_t cpu0pc;
static void cpu0(void)
{
    uint64_t restore = cpu0pc;
    uint64_t a_addr = mread(cpu0pc);
    uint64_t b_addr = mread(cpu0pc + 8);
    cpu0pc = mread(cpu0pc + 16);
    int64_t s = (int64_t)mread(b_addr) - (int64_t)mread(a_addr);
    mwrite(s, b_addr);
    if (s > 0) cpu0pc = restore + 24;
}

int main(int argc, char *argv[])
{
    if (argc < 2) return 1;
    
    FILE *f = fopen(argv[1], "rb");
    if (!f) return 1;

    mem = malloc(MEMSIZE);
    if (!mem) return 1;
    memset(mem, 0, MEMSIZE);
    memset(mem + MEMSIZE - 4096, 255, 4096);

    if (!fread(mem, 1, MEMSIZE, f)) return 1;
    fclose(f);

    if (SDL_Init(SDL_INIT_VIDEO)) return 1;

    SDL_Window *window = SDL_CreateWindow("SUBLEQ1", 0, 0, 1024, 512, 0);
    if (!window) goto die1;

    SDL_Renderer *renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_PRESENTVSYNC | SDL_RENDERER_ACCELERATED);
    if (!renderer) goto die2;

    SDL_Texture *texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_RGB24, SDL_TEXTUREACCESS_STREAMING, 1024, 512);
    if (!texture) goto die3;

    cpu0pc = mread(CPU0PC);
    mwrite(CPU_RUNNING, CPU0FLAGS);

    SDL_Event e;
    uint64_t t = SDL_GetTicks64();
    for (;;)
    {
        while (SDL_PollEvent(&e) != 0)
        {
            switch (e.type)
            {
                case SDL_QUIT: goto die2;
                case SDL_MOUSEMOTION: mouse_motion(e.motion.x, e.motion.y); break;
                case SDL_MOUSEBUTTONUP: mouse_button(e.button.button, 0); break;
                case SDL_MOUSEBUTTONDOWN: mouse_button(e.button.button, 1); break;
                case SDL_KEYDOWN: key_down(e.key.keysym.sym); break;
            }
        }

        while (SDL_GetTicks64() < t + 32)
        {
            for (int i = 0; i < 1024; i++) cpu0();
        }

        t =  SDL_GetTicks64();
        mwrite((uint64_t)((double)t / (double)1000 * (double)((uint64_t)1 << 32)), TIMER);
        uint64_t on = mread(DISPLAY_ON);

        if (on == 0)
        {
            SDL_UpdateTexture(texture, NULL, mem + DISPLAY_LOC, 1024 * 3);
            SDL_RenderCopy(renderer, texture, NULL, NULL);
            SDL_RenderPresent(renderer);
        }
    }

die3:
    SDL_DestroyTexture(texture);
die2:
    SDL_DestroyRenderer(renderer);
die1:
    SDL_DestroyWindow(window);
    SDL_Quit();
}

it had multicore at some point but it kept race conditioning on memory access and didnt really make it faster (atleast on my craptop) so i scrapped it

BYE!!!