forked from PlaneteCasio/Casio_asm
675 lines
15 KiB
C
675 lines
15 KiB
C
#include "platform.h"
|
|
#include "event.h"
|
|
#include "opcodeInfo.h"
|
|
|
|
int running=1;
|
|
int error=0;
|
|
|
|
int Platform_running() {
|
|
return running;
|
|
}
|
|
void Platform_setError(int err) {
|
|
error=err;
|
|
}
|
|
int Platform_getError() {
|
|
return error;
|
|
}
|
|
|
|
#if defined(PC)
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
|
|
//BEGIN SDL handling
|
|
#include <SDL2/SDL.h>
|
|
#include "keyboard.h"
|
|
#define ZOOM 4
|
|
|
|
//prepare variables
|
|
SDL_Window *window;
|
|
SDL_Renderer *renderer;
|
|
SDL_Rect rect={.w=ZOOM, .h=ZOOM};
|
|
|
|
//create our own vram and screen buffers
|
|
char vram[VRAM_LENGTH];
|
|
char screen[VRAM_LENGTH];
|
|
|
|
//macros to draw to screen
|
|
#define white() SDL_SetRenderDrawColor(renderer, 255, 255, 255, SDL_ALPHA_OPAQUE)
|
|
#define black() SDL_SetRenderDrawColor(renderer, 0, 0, 0, SDL_ALPHA_OPAQUE)
|
|
#define pixel(x, y) do {rect.x=x*ZOOM; rect.y=y*ZOOM; SDL_RenderFillRect(renderer, &rect);} while(0)
|
|
|
|
void sdlInit() {
|
|
//create a window
|
|
SDL_Init(SDL_INIT_VIDEO|SDL_INIT_TIMER);
|
|
SDL_CreateWindowAndRenderer(VRAM_WIDTH*ZOOM, VRAM_HEIGHT*ZOOM, 0, &window, &renderer);
|
|
|
|
//clear the window
|
|
white();
|
|
SDL_RenderClear(renderer);
|
|
SDL_RenderPresent(renderer);
|
|
}
|
|
void sdlQuit() {
|
|
//destroy everything and quit SDL
|
|
SDL_DestroyRenderer(renderer);
|
|
SDL_DestroyWindow(window);
|
|
SDL_Quit();
|
|
}
|
|
|
|
char* Graph_getVramAddress() {
|
|
return vram;
|
|
}
|
|
|
|
void printScreen() {
|
|
for(unsigned char y=0; y<VRAM_HEIGHT; y++) {
|
|
for(unsigned char x=0; x<VRAM_WIDTH; x++) {
|
|
//read the color of the pixel
|
|
int byte=y*VRAM_BYTES_PER_LINE+x/8;
|
|
char bit=x%8;
|
|
char value=(vram[byte]>>(8-bit-1))&0x01;
|
|
//set the color accordingly
|
|
if(value) black();
|
|
else white();
|
|
//and print this now
|
|
pixel(x, y);
|
|
}
|
|
}
|
|
SDL_RenderPresent(renderer);
|
|
}
|
|
void Graph_printVram() {
|
|
//copy the VRAM into the screen buffer and then display it
|
|
for(int i=0; i<VRAM_LENGTH; i++) screen[i]=vram[i];
|
|
printScreen();
|
|
}
|
|
|
|
void sdlEvt(SDL_Event *event) {
|
|
//if it's a quit event, then quit
|
|
if(event->type==SDL_QUIT) running=0;
|
|
//redraw the window if it gets exposed
|
|
if(event->type==SDL_WINDOWEVENT&&event->window.event==SDL_WINDOWEVENT_EXPOSED) printScreen();
|
|
|
|
//if it's a keyboard event, handle it
|
|
if(event->type==SDL_KEYDOWN||event->type==SDL_KEYUP) {
|
|
event_t evt={
|
|
.type=EVENT_TYPE_KEYBOARD,
|
|
.subtype=event->type==SDL_KEYDOWN?EVENT_TYPE_KEYBOARD_PRESS:EVENT_TYPE_KEYBOARD_RELEASE
|
|
};
|
|
evt.keyevent.repeat=event->key.repeat;
|
|
evt.keyevent.code=Keyboard_getCode(event->key.keysym.sym);
|
|
if(evt.keyevent.code!=-1) Event_put(&evt);
|
|
}
|
|
|
|
//if it's a timer event(using USEREVENT as a convinience), handle it
|
|
if(event->type==SDL_USEREVENT) {
|
|
event_t evt={
|
|
.type=EVENT_TYPE_TIMER,
|
|
.subtype=0
|
|
};
|
|
evt.timerevent.code=event->user.code;
|
|
Event_put(&evt);
|
|
}
|
|
}
|
|
|
|
void sdlTick(int block) {
|
|
SDL_Event event;
|
|
if(block) {
|
|
//block until we have an event
|
|
if(SDL_WaitEvent(&event)) sdlEvt(&event);
|
|
}
|
|
//iterate all pending events
|
|
while(SDL_PollEvent(&event)) sdlEvt(&event);
|
|
}
|
|
//END SDL handling
|
|
#endif
|
|
|
|
#if defined(LINUX)
|
|
#include <sys/types.h>
|
|
#include <sys/stat.h>
|
|
#include <fcntl.h>
|
|
#include <unistd.h>
|
|
|
|
//BEGIN file handling
|
|
#define MAX_FILES 256
|
|
typedef struct file_info_t {
|
|
int fd;
|
|
int offset;
|
|
int mode;
|
|
} file_info_t;
|
|
int fileCount=0;
|
|
file_info_t files[MAX_FILES];
|
|
|
|
//check if a file is opened
|
|
int checkFile(int fd) {
|
|
for(int i=0; i<fileCount; i++) {
|
|
if(files[i].fd==fd) return i;
|
|
}
|
|
return -1;
|
|
}
|
|
//seeks a file
|
|
int seekFile(int no, int off) {
|
|
int val=lseek(files[no].fd, off, SEEK_SET);
|
|
if(val==-1) return -1;
|
|
files[no].offset=off;
|
|
return val;
|
|
}
|
|
|
|
int File_open(char* path, int mode) {
|
|
if(fileCount==MAX_FILES) return -1;
|
|
|
|
int flags=0;
|
|
if((mode&FILE_OPEN_read)&&(mode&FILE_OPEN_write)) flags=O_RDWR;
|
|
else if(mode&FILE_OPEN_write) flags=O_WRONLY;
|
|
else if(mode&FILE_OPEN_read) flags=O_RDONLY;
|
|
if(mode&FILE_OPEN_create) flags|=O_CREAT;
|
|
|
|
int fd=open(path, flags);
|
|
if(fd!=-1) {
|
|
files[fileCount].offset=0;
|
|
files[fileCount].mode=mode;
|
|
files[fileCount++].fd=fd;
|
|
return fd;
|
|
}
|
|
return -1;
|
|
}
|
|
int File_close(int fd) {
|
|
for(int i=0; i<fileCount; i++) {
|
|
if(files[i].fd==fd) {
|
|
files[i]=files[--fileCount];
|
|
fsync(fd);
|
|
return close(fd);
|
|
}
|
|
}
|
|
return -1;
|
|
}
|
|
int File_read(int fd, int pos, void* buffer, int len) {
|
|
int no=checkFile(fd);
|
|
if(no==-1) return -1;
|
|
if(pos<0) return -1;
|
|
if(!(files[no].mode&FILE_OPEN_read)) return -1;
|
|
seekFile(no, pos);
|
|
return read(fd, buffer, len);
|
|
}
|
|
int File_write(int fd, int pos, void* buffer, int len) {
|
|
int no=checkFile(fd);
|
|
if(no==-1) return -1;
|
|
if(pos<0) return -1;
|
|
if(!(files[no].mode&FILE_OPEN_write)) return -1;
|
|
seekFile(no, pos);
|
|
return write(fd, buffer, len);
|
|
}
|
|
int File_length(int fd) {
|
|
int no=checkFile(fd);
|
|
if(no==-1) return -1;
|
|
int len=lseek(fd, 0, SEEK_END);
|
|
if(len!=-1) files[no].offset=len;
|
|
return len;
|
|
}
|
|
int File_truncate(int fd, int len) {
|
|
int no=checkFile(fd);
|
|
if(no==-1) return -1;
|
|
return !ftruncate(fd, len);
|
|
}
|
|
int File_mkdir(char* path) {
|
|
return !mkdir(path, 0755);
|
|
}
|
|
int File_delete(char* path) {
|
|
return !unlink(path);
|
|
}
|
|
|
|
int fileExit() {
|
|
for(int i=1; i<fileCount; i++) {
|
|
close(files[i].fd);
|
|
}
|
|
}
|
|
//END file handling
|
|
|
|
//BEGIN common
|
|
int Platform_init() {
|
|
Event_init();
|
|
sdlInit();
|
|
running=1;
|
|
}
|
|
|
|
void Platform_tick(int block) {
|
|
sdlTick(block);
|
|
}
|
|
|
|
int Platform_quit() {
|
|
sdlQuit();
|
|
fileExit();
|
|
Opcode_quit();
|
|
Event_quit();
|
|
running=0;
|
|
}
|
|
//END common
|
|
#endif
|
|
|
|
#if defined(CASIO_fxlib)
|
|
#include "fxlib.h"
|
|
#include "keybios.h"
|
|
#include "keyboard.h"
|
|
#include "string.h"
|
|
|
|
//BEGIN syscals
|
|
#define SCA 0xD201D002
|
|
#define SCB 0x422B0009
|
|
#define SCE 0x80010070
|
|
typedef void*(*sc_vp_i)(int);
|
|
typedef void*(*sc_vp_i_i)(int,int);
|
|
typedef void(*sc_v_vp)(void*);
|
|
typedef void(*sc_v_v)(void);
|
|
typedef void*(*sc_vp_v)(void);
|
|
typedef void*(*sc_vp_vp_i)(void*, int);
|
|
typedef int(*sc_i_sp)(short*);
|
|
const unsigned int sc_malloc[] = { SCA, SCB, SCE, 0x0ACD };
|
|
const unsigned int sc_realloc[] = { SCA, SCB, SCE, 0x0E6D };
|
|
const unsigned int sc_free[] = { SCA, SCB, SCE, 0x0ACC };
|
|
const unsigned int sc_calloc[] = { SCA, SCB, SCE, 0x0E6B };
|
|
const unsigned int sc_isKeyPressed[] = { SCA, SCB, SCE, 0x024B };
|
|
const unsigned int sc_printVram[] = { SCA, SCB, SCE, 0x0028 };
|
|
const unsigned int sc_getVramAddress[] = { SCA, SCB, SCE, 0x0135 };
|
|
|
|
|
|
void* malloc(int sz) {
|
|
return ((*(sc_vp_i)sc_malloc)(sz));
|
|
}
|
|
void free(void* ptr) {
|
|
if(!ptr) return;
|
|
(*(sc_v_vp)sc_free)(ptr);
|
|
}
|
|
void* realloc(void* ptr, int sz) {
|
|
if(!ptr) return malloc(sz);
|
|
return ((*(sc_vp_vp_i)sc_realloc)(ptr, sz));
|
|
}
|
|
void* calloc(int sz, int n) {
|
|
return ((*(sc_vp_i_i)sc_calloc)(sz,n));
|
|
}
|
|
int isKeyDown(int keycode){
|
|
return key_down(keycode);
|
|
//yeah, this function is supposed to work better
|
|
/*short matcode=0x0000;
|
|
if(keycode>=0x0101||keycode==0x0000) matcode=keycode;
|
|
else if(keycode!=34) {
|
|
matcode=(keycode/10-1)<<8;
|
|
matcode|=keycode%10;
|
|
}
|
|
return ((*(sc_i_sp)sc_isKeyPressed)(&matcode));*/
|
|
}
|
|
void printVram() {
|
|
(*(sc_v_v)sc_printVram)();
|
|
}
|
|
void* getVramAddress() {
|
|
return ((*(sc_vp_v)sc_getVramAddress)());
|
|
}
|
|
//END syscalls
|
|
|
|
//BEGIN graphical functions
|
|
char* Graph_getVramAddress() {
|
|
return getVramAddress();
|
|
}
|
|
void Graph_printVram() {
|
|
printVram();
|
|
}
|
|
//END graphical functions
|
|
|
|
//BEGIN file functions
|
|
//get the file path
|
|
FONTCHARACTER path[32];
|
|
FONTCHARACTER* getPath(char* filename) {
|
|
char* str="\\\\fls0\\";
|
|
for(int i=0; i<32; i++) path[i]='\0';
|
|
for(int i=0; i<7; i++) path[i]=str[i];
|
|
int len=strlend(filename);
|
|
for(int i=0; i<=len; i++) path[i+7]=filename[i];
|
|
return path;
|
|
}
|
|
|
|
//fuck CASIO for making me do this!
|
|
//store information on the files
|
|
int deleteFile(int fd);
|
|
|
|
int lastFd;
|
|
typedef struct file_info_t {
|
|
int fd;
|
|
int handle;
|
|
int length;
|
|
char mode;
|
|
FONTCHARACTER path[32];
|
|
char* buffer;
|
|
} file_info_t;
|
|
file_info_t* files=0;
|
|
|
|
int fileInit() {
|
|
files=calloc(32, sizeof(file_info_t));
|
|
lastFd=1;
|
|
return files!=0;
|
|
}
|
|
int fileQuit() {
|
|
for(int i=0; i<32; i++) {
|
|
if(files[i].fd) deleteFile(files[i].fd);
|
|
}
|
|
free(files);
|
|
return 1;
|
|
}
|
|
|
|
//get free space
|
|
int getFreeFile() {
|
|
for(int i=0; i<32; i++) {
|
|
if(files[i].fd==0) return i;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
//create a file information
|
|
int openFile(char* path, int mode) {
|
|
//check if we have enough room for files
|
|
int spot=getFreeFile();
|
|
if(spot==-1) return -100;
|
|
|
|
//store info here
|
|
file_info_t info;
|
|
info.fd=lastFd++;
|
|
info.mode=mode;
|
|
info.buffer=0;
|
|
info.handle=-1;
|
|
|
|
//set path
|
|
FONTCHARACTER* fPath=getPath(path);
|
|
for(int i=0; i<32; i++) info.path[i]=fPath[i];
|
|
|
|
if(mode&FILE_OPEN_read) {
|
|
//read file size
|
|
int len=0;
|
|
int handle=Bfile_OpenFile(info.path, _OPENMODE_READ);
|
|
if(handle>=0) len=Bfile_GetFileSize(handle);
|
|
else return handle;
|
|
info.length=len>=0?len:0;
|
|
//read file data
|
|
if(len&&handle) {
|
|
char* ptr=malloc(len);
|
|
info.buffer=ptr;
|
|
if(!ptr) {
|
|
Bfile_CloseFile(handle);
|
|
return -200;
|
|
}
|
|
int val=Bfile_ReadFile(handle, ptr, len, 0);
|
|
if(val<0) {
|
|
free(ptr);
|
|
Bfile_CloseFile(handle);
|
|
return val;
|
|
}
|
|
}
|
|
} else {
|
|
info.length=0;
|
|
info.buffer=0;
|
|
}
|
|
|
|
|
|
//add the file to the list
|
|
files[spot]=info;
|
|
|
|
//return the fd
|
|
return info.fd;
|
|
}
|
|
//retrieve a file information
|
|
int getFile(int fd, file_info_t *info) {
|
|
for(int i=0; i<32; i++) {
|
|
*info=files[i];
|
|
if(info->fd==fd) return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
void putFile(int fd, file_info_t *info) {
|
|
for(int i=0; i<32; i++) {
|
|
if(info->fd==fd) {
|
|
files[i]=*info;
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
//returns the mode
|
|
int getMode(int mode) {
|
|
if((mode&FILE_OPEN_read)&&(mode&FILE_OPEN_write)) return _OPENMODE_READWRITE;
|
|
else if(mode&FILE_OPEN_write) return _OPENMODE_WRITE;
|
|
return _OPENMODE_READ;
|
|
}
|
|
//delete a file information
|
|
int deleteFile(int fd) {
|
|
for(int i=0; i<32; i++) {
|
|
if(files[i].fd==fd) {
|
|
file_info_t info=files[i];
|
|
//close the file if it is already open
|
|
if(info.handle) {
|
|
Bfile_CloseFile(info.handle);
|
|
info.handle=0;
|
|
}
|
|
//if the file is not empty
|
|
int err=0;
|
|
if(info.length) {
|
|
if(!info.buffer) err=-101;
|
|
//create it if absent
|
|
Bfile_DeleteFile(info.path);
|
|
int create=Bfile_CreateFile(info.path, info.length);
|
|
if(create&&!err) err=create;
|
|
//write data to file
|
|
info.handle=Bfile_OpenFile(info.path, getMode(info.mode));
|
|
if(info.handle<0) err=info.handle;
|
|
int len=Bfile_WriteFile(info.handle, info.buffer, info.length);
|
|
if(len<0&&!err) err=len;
|
|
int close=Bfile_CloseFile(info.handle);
|
|
if(close<0&!err) err=close;
|
|
}
|
|
//free the buffer
|
|
if(info.buffer) free(info.buffer);
|
|
//some checks
|
|
if(info.length<0) err=-102;
|
|
if((info.mode&FILE_OPEN_write)&&!info.length) err=-103;
|
|
// remove the data
|
|
info.fd=0;
|
|
files[i]=info;
|
|
return err;
|
|
}
|
|
}
|
|
return -100;
|
|
}
|
|
|
|
int File_open(char* path, int mode) {
|
|
return openFile(path, mode);
|
|
}
|
|
int File_close(int fd) {
|
|
return deleteFile(fd);
|
|
}
|
|
int File_read(int fd, int pos, void* buffer, int len) {
|
|
//get file and check the position
|
|
file_info_t info;
|
|
if(!getFile(fd, &info)) return -1;
|
|
if(pos<0||len<0) return -2;
|
|
if(pos+len>info.length) len=info.length;
|
|
|
|
//if we have the file in a buffer, read from the buffer
|
|
if(info.buffer) {
|
|
char* ptr=(char*) buffer;
|
|
for(int i=0; i<len; i++) ptr[i]=info.buffer[i+pos];
|
|
return len;
|
|
}
|
|
|
|
//we don't, so read from disk
|
|
return Bfile_ReadFile(info.handle, buffer, len, pos);
|
|
}
|
|
int File_write(int fd, int pos, void* buffer, int len) {
|
|
//get file and check the position
|
|
file_info_t info;
|
|
if(!getFile(fd, &info)) return -1;
|
|
if(pos<0||len<0) return -2;
|
|
|
|
//if we already have a buffer, AND it is big enough, write in it
|
|
if(info.buffer&&pos+len<=info.length) {
|
|
char* ptr=(char*) buffer;
|
|
for(int i=0; i<len; i++) info.buffer[i+pos]=ptr[i];
|
|
return len;
|
|
}
|
|
//if we have one, enlarge it
|
|
else if(info.buffer) {
|
|
char* newptr=realloc(info.buffer, pos+len);
|
|
if(!newptr) {
|
|
//we couldn't enlarge the buffer, write what we can and fail properly
|
|
char* ptr=(char*) buffer;
|
|
for(int i=0; i<info.length; i++) info.buffer[i+pos]=ptr[i];
|
|
putFile(fd, &info);
|
|
return info.length;
|
|
}
|
|
//fill the new buffer
|
|
info.buffer=newptr;
|
|
char* ptr=(char*) buffer;
|
|
for(int i=0; i<len; i++) info.buffer[i+pos]=ptr[i];
|
|
putFile(fd, &info);
|
|
return len;
|
|
}
|
|
//we don't have any buffer, create one
|
|
info.buffer=calloc(1, pos+len);
|
|
if(!info.buffer) return -3;
|
|
char* ptr=(char*) buffer;
|
|
for(int i=0; i<len; i++) info.buffer[i+pos]=ptr[i];
|
|
info.length=pos+len;
|
|
putFile(fd, &info);
|
|
return len;
|
|
}
|
|
int File_length(int fd) {
|
|
//get file info
|
|
file_info_t info;
|
|
if(!getFile(fd, &info)) return -1;
|
|
|
|
//return file size
|
|
return info.length;
|
|
}
|
|
int File_truncate(int fd, int size) {
|
|
//get file and check size
|
|
file_info_t info;
|
|
if(!getFile(fd, &info)) return -1;
|
|
if(size<0) return -2;
|
|
|
|
//check if we have a buffer already
|
|
if(info.buffer) {
|
|
if(info.length>size) {
|
|
info.length=size;
|
|
putFile(fd, &info);
|
|
return 0;
|
|
} else {
|
|
char* newptr=realloc(info.buffer, size);
|
|
if(newptr) {
|
|
info.length=size;
|
|
info.buffer=newptr;
|
|
putFile(fd, &info);
|
|
return 0;
|
|
}
|
|
return -4;
|
|
}
|
|
} else {
|
|
info.buffer=calloc(1, size);
|
|
if(!info.buffer) return -3;
|
|
info.length=size;
|
|
putFile(fd, &info);
|
|
return 0;
|
|
}
|
|
}
|
|
int File_delete(char* path) {
|
|
if(!Bfile_DeleteFile(getPath(path))) return 0;
|
|
return Bfile_DeleteDirectory(getPath(path));
|
|
}
|
|
int File_mkdir(char* path) {
|
|
return Bfile_CreateDirectory(getPath(path));
|
|
}
|
|
//END file functions
|
|
|
|
//BEGIN timer-related functions
|
|
#define KEY_TIMER 1
|
|
#define KEY_DELAY 50
|
|
#define KEY_COUNT 50
|
|
typedef struct key_info_t {
|
|
char code;
|
|
char time;
|
|
//short matcode;
|
|
} key_info_t;
|
|
key_info_t keys[KEY_COUNT];
|
|
#include "test.h"
|
|
void keyHandle(int pos) {
|
|
event_t evt={
|
|
.type=EVENT_TYPE_KEYBOARD,
|
|
.keyevent={
|
|
.code=keys[pos].code,
|
|
.repeat=0
|
|
}
|
|
};
|
|
|
|
// check the old status of the key
|
|
if(keys[pos].time) {
|
|
// check if the key is still down
|
|
if(isKeyDown(keys[pos].code)) {
|
|
// first repeat is after 10 periods, so 500ms or 1/2sec
|
|
if(keys[pos].time==10) {
|
|
evt.subtype=EVENT_TYPE_KEYBOARD_PRESS;
|
|
evt.keyevent.repeat=1;
|
|
Event_put(&evt);
|
|
// repeat event every 4 periods, so 200ms or 1/5sec
|
|
keys[pos].time-=4;
|
|
}
|
|
// increment key time counter
|
|
keys[pos].time++;
|
|
} else {
|
|
// detect key release
|
|
evt.subtype=EVENT_TYPE_KEYBOARD_RELEASE;
|
|
Event_put(&evt);
|
|
keys[pos].time=0;
|
|
}
|
|
} else if(isKeyDown(keys[pos].code)) {
|
|
// set the key status to pressed
|
|
evt.subtype=EVENT_TYPE_KEYBOARD_PRESS;
|
|
Event_put(&evt);
|
|
keys[pos].time=1;
|
|
}
|
|
}
|
|
void keyHandler() {
|
|
for(int i=0; i<KEY_COUNT; i++) keyHandle(i);
|
|
}
|
|
void keyClear() {
|
|
int pos=0;
|
|
for(int x=1; x<=6; x++) {
|
|
for(int y=(x==1?5:1); y<=9; y++) {
|
|
key_info_t key;
|
|
key.time=0;
|
|
key.code=10*(x+1)+y;
|
|
//key.matcode=(x<<8)|y;
|
|
//if(x==2&&y==4) key.matcode=0x0000;
|
|
keys[pos++]=key;
|
|
}
|
|
}
|
|
}
|
|
|
|
void startTimers() {
|
|
SetTimer(KEY_TIMER, KEY_DELAY, keyHandler);
|
|
}
|
|
void killTimers() {
|
|
KillTimer(KEY_TIMER);
|
|
}
|
|
//END timer-related functions
|
|
|
|
//BEGIN common functions
|
|
int Platform_init() {
|
|
Event_init();
|
|
fileInit();
|
|
keyClear();
|
|
startTimers();
|
|
return 1;
|
|
}
|
|
int Platform_quit() {
|
|
killTimers();
|
|
Event_quit();
|
|
fileQuit();
|
|
return 1;
|
|
}
|
|
void Platform_tick(int block) {
|
|
if(block) while(Platform_running()&&!Event_count()) Sleep(1);
|
|
}
|
|
//END common functions
|
|
|
|
#endif
|