Compare commits

..

10 Commits

Author SHA1 Message Date
0xmac
a97f24fbc6 Added via.c 2025-01-07 14:36:20 +01:00
0xmac
ac2400c555 Moved Variables to main.c 2025-01-07 14:36:11 +01:00
0xmac
6f2c89964f Updated keyboard.c for SDL 2025-01-07 14:35:57 +01:00
0xmac
13603f61f8 Updated events.c for SDL 2025-01-07 14:35:49 +01:00
0xmac
c777421c79 Updated main.c for SDL 2025-01-07 14:35:39 +01:00
0xmac
98b435f570 Updated video.c for SDL 2025-01-07 14:35:28 +01:00
0xmac
1884b56533 Added helper file for SDL window creation 2025-01-07 14:06:42 +01:00
0xmac
29e5bea5f5 Updated README 2025-01-07 14:01:52 +01:00
0xmac
59833d3447 Added dynamic SDL flag support 2025-01-07 14:00:25 +01:00
0xmac
a87358662b Changed Makefile to SDL 2025-01-07 08:14:50 +01:00
9 changed files with 230 additions and 165 deletions

View File

@ -2,7 +2,7 @@
CC=gcc
O=2
CFLAGS=-lcsfml-window -lcsfml-system -lcsfml-graphics
CFLAGS=`sdl2-config --cflags` `sdl2-config --libs`
PREFIX=$(HOME)/.local
all: ls7emulator
@ -14,7 +14,6 @@ clean:
ls7emulator:
cd src
$(CC) main.c -o ls7emulator $(CFLAGS) -O$(O)
rm ../bin -rf
mkdir ../bin
cd ../bin

View File

@ -1,3 +1,33 @@
# LS7-Emulator
Emulator for the LS7 Computer written in C
# ToDo
- Adjust cpu.c for 65c02 Instructions
- video.c 16 color support
- video.c accent color support
- cpu snapshot load/save
# Usage
Start the Program with `ls7emulator [OPTIONS]... [FILE]`.
A file has to be specified and **must** be exactly 16k in size.
Preferably a 65c02 program.
# OPTIONS
# Hotkeys
# Building
The Program is so small, that I won't distribute a binary package.
The `Makefile` provides the build utilities. Simply build it in a Unix based terminal with
`make` and to install it in /usr/bin `make install` as root
# Dependencies
- gcc
- sdl2

View File

@ -11,6 +11,10 @@
#define BACKCOLOR sfBlack
#define FPS 60
#define SCREEN_WIDTH 786
#define SCREEN_HEIGHT 512
#define SDL_X_SIZE 786
#define SDL_Y_SIZE 786
#define PREAMBLE "LS7 Emulator by Gabriel Weingardt.\nLicense: GPL v.3+\n\n"
@ -38,8 +42,3 @@ F9 Save CPU snapshot\n\
F10 Load previous snapshot\n\
F11 CPU NMI\n\
F12 CPU IRQ\n\n"
static float displayscale = 2;
static int cpuspeed = 100000; // 100 kHz
static int singlestep = 0;
static int clocksteps = 1;

View File

@ -1,10 +1,8 @@
#include <stdint.h>
#include <SFML/System.h>
#include <SFML/Graphics.h>
#include <SFML/Window.h>
#include <SDL2/SDL.h>
extern int clockSteps;
extern float displayScale;
extern int clocksteps;
extern uint8_t halt;
extern uint8_t showDebug;
extern uint8_t showHelp;
@ -16,81 +14,75 @@ extern void step6502();
extern void updateRenderStates();
extern void scanKeyboard();
static sfKeyCode currentKey = sfKeyUnknown;
static SDL_Scancode currentKey = SDL_SCANCODE_UNKNOWN;
static SDL_Event event;
void pollEvents(sfRenderWindow *window){
sfEvent event;
while (sfRenderWindow_pollEvent(window, &event)) {
void pollEvents(){
while (SDL_PollEvent(&event)){
switch(event.type){
case sfEvtClosed:
sfRenderWindow_close(window);
case SDL_QUIT:
printf("Exited.\n");
exit(0);
case SDL_KEYDOWN:
switch (event.key.keysym.scancode){
case SDL_SCANCODE_F1: /* Close Window or show help*/
exit(EXIT_SUCCESS);
break;
case sfEvtResized:
sfRenderWindow_setView(window, sfView_createFromRect((sfFloatRect){0, 0, event.size.width, event.size.height}));
break;
case sfEvtKeyPressed:
switch (event.key.code){
case sfKeyF1: /* Close Window or show help*/
sfRenderWindow_close(window);
break;
case sfKeyF2: /* Show Key Help */
case SDL_SCANCODE_F2: /* Show Key Help */
showHelp = !showHelp;
break;
case sfKeyF3: /* Show Debug Menu */
case SDL_SCANCODE_F3: /* Show Debug Menu */
showDebug = !showDebug;
break;
case sfKeyF4: /* CPU Halt */
case SDL_SCANCODE_F4: /* CPU Halt */
halt = !halt;
break;
case sfKeyF5: /* CPU Reset */
case SDL_SCANCODE_F5: /* CPU Reset */
resetSystem();
break;
case sfKeyF6: /* Scale -- */
if (displayscale > 1) displayscale--;
updateRenderStates();
case SDL_SCANCODE_F6: /* Scale -- */
if (displayScale > 1) displayScale--;
break;
case sfKeyF7: /* Scale ++ */
displayscale++;
updateRenderStates();
case SDL_SCANCODE_F7: /* Scale ++ */
displayScale++;
break;
case sfKeyF8: /* CPU Singlestep */
for (int i = 0; i < clocksteps; i++) step6502();
case SDL_SCANCODE_F8: /* CPU Singlestep */
for (int i = 0; i < clockSteps; i++) step6502();
break;
case sfKeyF9: /* CPU Save Snapshot */
case SDL_SCANCODE_F9: /* CPU Save Snapshot */
break;
case sfKeyF10: /* CPU Load recent or given snapshot */
case SDL_SCANCODE_F10: /* CPU Load recent or given snapshot */
break;
case sfKeyF11: /* CPU NMI */
case SDL_SCANCODE_F11: /* CPU NMI */
nmi6502();
break;
case sfKeyF12: /* CPU IRQ */
case SDL_SCANCODE_F12: /* CPU IRQ */
irq6502();
break;
default:
currentKey = event.key.code;
currentKey = event.key.keysym.scancode;
break;
}
break;
case sfEvtKeyReleased:
case SDL_KEYUP:
// To tell keyboard.c, that no key is being pressed
currentKey = sfKeyUnknown;
currentKey = SDL_SCANCODE_UNKNOWN;
break;
default:
break;
default: break;
}
}
}

View File

@ -1,17 +1,30 @@
#include <SDL2/SDL.h>
#include <stdint.h>
#include <SFML/Window.h>
extern uint8_t systemRegister;
extern uint8_t keyboardResult;
extern sfKeyCode currentKey;
extern SDL_Scancode currentKey;
const static sfKeyCode scanMatrix[48] = {
sfKeyNum1, sfKeyNum2, sfKeyNum3, sfKeyNum4, sfKeyNum5, sfKeyNum6, sfKeyNum7, sfKeyNum8,
sfKeyQ, sfKeyW, sfKeyE, sfKeyR, sfKeyT, sfKeyY, sfKeyU, sfKeyI,
sfKeyA, sfKeyS, sfKeyD, sfKeyF, sfKeyG, sfKeyH, sfKeyJ, sfKeyK,
sfKeyZ, sfKeyX, sfKeyC, sfKeyV, sfKeyB, sfKeyN, sfKeyM, sfKeyComma,
sfKeyNum9, sfKeyNum0, sfKeyL, sfKeyO, sfKeyP, sfKeyPeriod,sfKeyEnter, sfKeyBackspace,
sfKeyLShift,sfKeyLControl, sfKeyLAlt, sfKeySpace, sfKeyUp, sfKeyRight, sfKeyDown, sfKeyLeft,
/* Virtual Keyrows */
const static SDL_Scancode scanMatrix[48] = {
SDL_SCANCODE_1, SDL_SCANCODE_2, SDL_SCANCODE_3, SDL_SCANCODE_4,
SDL_SCANCODE_5, SDL_SCANCODE_6, SDL_SCANCODE_7, SDL_SCANCODE_8,
SDL_SCANCODE_Q, SDL_SCANCODE_W, SDL_SCANCODE_E, SDL_SCANCODE_R,
SDL_SCANCODE_T, SDL_SCANCODE_Y, SDL_SCANCODE_U, SDL_SCANCODE_I,
SDL_SCANCODE_A, SDL_SCANCODE_S, SDL_SCANCODE_D, SDL_SCANCODE_F,
SDL_SCANCODE_G, SDL_SCANCODE_H, SDL_SCANCODE_J, SDL_SCANCODE_K,
SDL_SCANCODE_Z, SDL_SCANCODE_X, SDL_SCANCODE_C, SDL_SCANCODE_V,
SDL_SCANCODE_B, SDL_SCANCODE_N, SDL_SCANCODE_M, SDL_SCANCODE_COMMA,
SDL_SCANCODE_9, SDL_SCANCODE_0, SDL_SCANCODE_L, SDL_SCANCODE_O,
SDL_SCANCODE_P, SDL_SCANCODE_PERIOD, SDL_SCANCODE_RETURN, SDL_SCANCODE_BACKSPACE,
SDL_SCANCODE_LSHIFT, SDL_SCANCODE_LCTRL, SDL_SCANCODE_LALT, SDL_SCANCODE_SPACE,
SDL_SCANCODE_UP, SDL_SCANCODE_RIGHT, SDL_SCANCODE_DOWN, SDL_SCANCODE_LEFT,
};

View File

@ -4,28 +4,38 @@
#include <time.h>
#include <string.h>
#include <SFML/System.h>
#include <SFML/Graphics.h>
#include <SFML/Window.h>
#include <SDL2/SDL.h>
#include "config.h"
/* Preset Values */
static float displayScale = 2;
static int cpuSpeed = 100000; // 100 kHz
static int singleStep = 0;
static int clockSteps = 1;
#include "sdlinit.c"
#include "events.c"
#include "cpu.c"
#include "memory.c"
#include "video.c"
#include "keyboard.c"
sfVertexArray *renderArray;
sfRenderWindow *window;
sfFont *font;
sfText *renderText;
sfRenderStates renderStates;
sfRectangleShape *haltRect;
//#include "via.c"
uint8_t halt = 0;
uint8_t showHelp = 0;
uint8_t showDebug = 0;
uint8_t fpsCount = 0;
uint8_t fpsStore;
uint8_t cpuHealth;
unsigned long cpuTicks = 0;
unsigned long tickTrigger = 0;
unsigned long renderTrigger = 0;
char debugString[255];
int openFile(const char *inputFile){
FILE *file = fopen(inputFile, "rb");
@ -50,23 +60,6 @@ void resetSystem(){
reset6502();
}
void updateRenderStates(){
renderStates.transform = sfTransform_Identity;
sfTransform_scale(&renderStates.transform, displayscale, displayscale);
}
void drawScreen(){
sfRenderWindow_drawVertexArray(window, renderArray, &renderStates);
if (halt){
sfRenderWindow_drawRectangleShape(window, haltRect, &renderStates);
}
if (showHelp){
sfText_setString(renderText, HELPKEYS);
sfRenderWindow_drawText(window, renderText, &renderStates);
}
}
void writeHelp(int type){
if (!type) printf(HELP);
else printf(HELPKEYS);
@ -84,10 +77,10 @@ void fetchArgs(int argc, char *argv[]){
for (int i = 1; i < argc; i++) {
if (!strcmp(argv[i], "--help")) writeHelp(0);
else if (!strcmp(argv[i], "--help-keys")) writeHelp(1);
else if (!strcmp(argv[i], "--cpuspeed")) cpuspeed = atoi(argv[++i]);
else if (!strcmp(argv[i], "--scale")) displayscale = atof(argv[++i]);
else if (!strcmp(argv[i], "--singlestep")) singlestep = 1;
else if (!strcmp(argv[i], "--clocksteps")) clocksteps = atoi(argv[++i]);
else if (!strcmp(argv[i], "--cpuspeed")) cpuSpeed = atoi(argv[++i]);
else if (!strcmp(argv[i], "--scale")) displayScale = atof(argv[++i]);
else if (!strcmp(argv[i], "--singlestep")) singleStep = 1;
else if (!strcmp(argv[i], "--clocksteps")) clockSteps = atoi(argv[++i]);
//else if (!strcmp(argv[i], "--snapshot")) snapshotFile = &argv[i];
else {
@ -101,46 +94,52 @@ void fetchArgs(int argc, char *argv[]){
int main(int argc, char *argv[]){
fetchArgs(argc, argv);
window = sfRenderWindow_create((sfVideoMode){800, 600, 24}, "LS7 Emulator", sfResize | sfClose, NULL);
sfRenderWindow_setVerticalSyncEnabled(window, sfFalse);
sfRenderWindow_setFramerateLimit(window, FPS);
sfRenderWindow_setKeyRepeatEnabled(window, sfFalse);
font = sfFont_createFromFile("bin/font.ttf");
renderText = sfText_create();
sfText_setPosition(renderText, (sfVector2f){ 50, 50 });
sfText_setFont(renderText, font);
sfText_setCharacterSize(renderText, 10);
sfText_setFillColor(renderText, sfWhite);
sfText_setOutlineColor(renderText, sfBlack);
sfText_setOutlineThickness(renderText, 1);
haltRect = sfRectangleShape_create();
sfRectangleShape_setFillColor(haltRect, (sfColor){ 0, 0, 0, 128 });
sfRectangleShape_setSize(haltRect, (sfVector2f){ 384, 256 });
renderStates = sfRenderStates_default();
sfTransform_scale(&renderStates.transform, displayscale, displayscale);
initWindow();
clearScreen(renderMemory, 0x000000FF);
resetSystem();
while (sfRenderWindow_isOpen(window)){
pollEvents(window);
while (1){
SDL_Delay(32);
pollEvents();
if (!singlestep && !halt){
for (int i = 0; i < cpuspeed / FPS; i++) step6502();
fpsCount++;
updateVideo();
if (!singleStep && !halt){
for (int i = 0; i < (cpuSpeed / FPS) * 2; i++) {
step6502();
cpuTicks++;
}
irq6502();
}
sfRenderWindow_clear(window, BACKCOLOR);
updateVideo();
drawScreen();
sfRenderWindow_display(window);
if ((unsigned)time(NULL) != tickTrigger){
tickTrigger = (unsigned)time(NULL);
cpuHealth = (uint8_t)((cpuTicks / (float)cpuSpeed) * 100.);
cpuTicks = 0;
fpsStore = fpsCount;
fpsCount = 0;
}
sfRenderWindow_destroy(window);
/* Redraw entire screen every X seconds */
//if ((unsigned)time(NULL) > renderTrigger + 0){
renderTrigger = (unsigned)time(NULL);
if (SDL_UpdateTexture(texture, NULL, renderMemory, (sizeof(uint32_t) * SDL_X_SIZE))) {
fprintf(stderr, "Could not update SDL texture: %s.\n", SDL_GetError());
exit(EXIT_FAILURE);
}
if (SDL_RenderCopy(renderer, texture, NULL, NULL)) {
fprintf(stderr, "Could not display SDL texture: %s.\n", SDL_GetError());
exit(EXIT_FAILURE);
}
SDL_RenderPresent(renderer);
//}
}
return EXIT_SUCCESS;
}

46
src/sdlinit.c Normal file
View File

@ -0,0 +1,46 @@
#include <SDL2/SDL.h>
#include "config.h"
static SDL_Window *window;
static SDL_Renderer *renderer;
static SDL_Texture *texture;
void initWindow(){
if (SDL_Init(SDL_INIT_VIDEO)){
printf("Could not init SDL: %s\n", SDL_GetError());
exit(EXIT_FAILURE);
}
atexit(SDL_Quit);
window = SDL_CreateWindow("LS7 Emulator",
SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED,
SCREEN_WIDTH, SCREEN_HEIGHT, 0);
if (window == NULL){
printf("Fatal! Could not create SDL Window: %s\n", SDL_GetError());
exit(EXIT_FAILURE);
}
renderer = SDL_CreateRenderer(window, -1, 2);
if (renderer == NULL){
printf("Fatal! Could not create SDL Renderer: %s\n", SDL_GetError());
exit(EXIT_FAILURE);
}
texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_RGBA8888,
SDL_TEXTUREACCESS_STREAMING,
SCREEN_WIDTH, SCREEN_HEIGHT);
if (texture == NULL){
printf("Fatal! Could not create SDL Texture: %s\n", SDL_GetError());
exit(EXIT_FAILURE);
}
if (SDL_SetTextureBlendMode(texture, SDL_BLENDMODE_NONE)){
printf("Fatal! Could not set SDL blend mode: %s\n", SDL_GetError());
exit(EXIT_FAILURE);
}
}
void clearScreen(uint32_t pixels[], uint32_t color){
for (uint32_t i = 0; i < SDL_X_SIZE * SDL_Y_SIZE; i++) pixels[i] = color;
}

0
src/via.c Normal file
View File

View File

@ -1,12 +1,9 @@
#include <stdlib.h>
#include <stdint.h>
#include <SFML/System.h>
#include <SFML/Graphics.h>
#include <SFML/Window.h>
extern float displayScale;
/* Public Variables */
extern sfVertexArray *renderArray;
int8_t videoModified;
/* Hardware-like Registers */
@ -19,24 +16,19 @@ uint8_t videoA;
static uint8_t videoRow;
static uint8_t videoValue;
static uint8_t videoColorValue;
static sfColor videoDisplayColor;
static sfColor videoForeColor;
static sfColor videoBackColor;
const static sfColor videoUpperPalette = (sfColor){ 64, 64, 64 };
static sfColor *videoColorIndex[] = {
&sfBlack, &sfRed, &sfGreen, &sfYellow, &sfBlue, &sfMagenta, &sfCyan, &sfWhite//&(sfColor){ 96, 96, 96 } ,
/*&(sfColor){ 0, 0, 0 },
&(sfColor){ 0xFF, 0, 0 },
&(sfColor){ 0, 0xFF, 0 },
&(sfColor){ 0xFF, 0xFF, 0 },
&(sfColor){ 0, 0, 0xFF },
&(sfColor){ 0xFF, 0, 0xFF },
&(sfColor){ 0, 0xFF, 0xFF },
&(sfColor){ 0xFF, 0xFF, 0xFF },*/
static uint32_t videoColorIndex[] = {
0x000000FF,
0xFF0000FF,
0x00FF00FF,
0xFFFF00FF,
0x0000FFFF,
0xFF00FFFF,
0x00FFFFFF,
0xFFFFFFFF
};
static uint8_t videoMemory[0x8000];
static uint32_t renderMemory[(SDL_X_SIZE * SDL_Y_SIZE)];
void writeVideo(){
@ -49,9 +41,6 @@ uint8_t readVideo(){
}
void initVideo(){
renderArray = sfVertexArray_create();
sfVertexArray_setPrimitiveType(renderArray, sfQuads);
videoModified = 1;
videoMode = 0x01;
@ -60,7 +49,7 @@ void initVideo(){
void updateVideo(){
if (videoModified){
sfVertexArray_clear(renderArray);
//sfVertexArray_clear(renderArray);
for (uint8_t y = 0; y < 255; y++){
videoRow = (int8_t)(y & 0x7);
@ -91,18 +80,16 @@ void updateVideo(){
// Snipping out the upper 8 colors
videoColorValue &= 0x77;
videoForeColor = *videoColorIndex[(videoColorValue & 0x0F)];
videoBackColor = *videoColorIndex[((videoColorValue & 0xF0) >> 4)];
for (uint8_t i = 0; i < 8; i++){
if (videoValue & (128 >> i)) videoDisplayColor = videoBackColor;
else videoDisplayColor = videoForeColor;
sfVertexArray_append(renderArray, (sfVertex){ (sfVector2f){ (x * 8) + i, y }, videoDisplayColor});
sfVertexArray_append(renderArray, (sfVertex){ (sfVector2f){ (x * 8) + i + 1, y }, videoDisplayColor});
sfVertexArray_append(renderArray, (sfVertex){ (sfVector2f){ (x * 8) + i + 1, y + 1 }, videoDisplayColor});
sfVertexArray_append(renderArray, (sfVertex){ (sfVector2f){ (x * 8) + i, y + 1 }, videoDisplayColor});
if (displayScale == 1){
renderMemory[(y * SDL_X_SIZE) + ((x * 8) + i)] = (videoValue & (128 >> i)) ? videoColorIndex[((videoColorValue & 0xF0) >> 4)] : videoColorIndex[(videoColorValue & 0x0F)];
} else {
for (uint8_t _x = 0; _x < displayScale; _x++){
for (uint8_t _y = 0; _y < displayScale; _y++){
renderMemory[(((y * (int)displayScale) + _y) * SDL_X_SIZE) + ((((x * (int)displayScale) * 8) + (i * (int)displayScale)) + _x)] = (videoValue & (128 >> i)) ? videoColorIndex[((videoColorValue & 0xF0) >> 4)] : videoColorIndex[(videoColorValue & 0x0F)];
}
}
}
}
}
}