mirror of
https://github.com/ArthurFerreira2/reinette-II-plus.git
synced 2024-09-27 16:57:39 +00:00
corrected numerous bus
This commit is contained in:
parent
441c22151b
commit
f01216aba2
433
reinetteII+.c
433
reinetteII+.c
@ -2,8 +2,8 @@
|
|||||||
|
|
||||||
reinette II plus, a french Apple II emulator, using SDL2
|
reinette II plus, a french Apple II emulator, using SDL2
|
||||||
and powered by puce6502 - a MOS 6502 cpu emulator by the same author
|
and powered by puce6502 - a MOS 6502 cpu emulator by the same author
|
||||||
Last modified 1st of August 2020
|
Last modified 13th of August 2020
|
||||||
Copyright (c) 2020 Arthur Ferreira (arthur.ferreira2@gmail.com)
|
Copyright (c) 2020 Arthur Ferreira (arthur.ferreira2gmail.com)
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
@ -30,20 +30,18 @@
|
|||||||
#include "puce6502.h"
|
#include "puce6502.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//================================================================ SOFT SWITCHES
|
//================================================================ SOFT SWITCHES
|
||||||
|
|
||||||
uint8_t TEXT = 0; // start of text (0=full text, 20=mixed or 24=full GR)
|
|
||||||
uint8_t PAGE = 1; // 0xC054 for page1 or 0xC055 for page2
|
|
||||||
bool HIRES = false; // 0xC056 (off: GR) or 0xC057 (on: HGR)
|
|
||||||
|
|
||||||
bool SPKR = false; // 0xC030 Speaker toggle
|
|
||||||
bool MUTED = false; // not an Apple II Soft Switch, press F9 to mute/unmute
|
|
||||||
|
|
||||||
uint8_t KBD = 0; // 0xC000, 0xC010 ascii value of keyboard input
|
uint8_t KBD = 0; // 0xC000, 0xC010 ascii value of keyboard input
|
||||||
|
bool SPKR = false; // 0xC030 Speaker toggle
|
||||||
|
bool TEXT = true; // 0xC050 CLRTEXT / 0xC051 SETTEXT
|
||||||
|
bool MIXED = false; // 0xC052 CLRMIXED / 0xC053 SETMIXED
|
||||||
|
uint8_t PAGE = 1; // 0xC054 PAGE1 / 0xC055 PAGE2
|
||||||
|
bool HIRES = false; // 0xC056 GR / 0xC057 HGR
|
||||||
uint8_t PB0 = 0; // 0xC061 Push Button 0 (bit 7) / Open Apple
|
uint8_t PB0 = 0; // 0xC061 Push Button 0 (bit 7) / Open Apple
|
||||||
uint8_t PB1 = 0; // 0xC062 Push Button 1 (bit 7) / Solid Apple
|
uint8_t PB1 = 0; // 0xC062 Push Button 1 (bit 7) / Solid Apple
|
||||||
|
uint8_t PB2 = 0; // 0xC063 Push Button 2 (bit 7) / shift mod !!!
|
||||||
uint8_t GC0 = 0; // 0xC064 Game Controller 0 (bit 7)
|
uint8_t GC0 = 0; // 0xC064 Game Controller 0 (bit 7)
|
||||||
uint8_t GC1 = 0; // 0xC065 Game Controller 1 (bit 7)
|
uint8_t GC1 = 0; // 0xC065 Game Controller 1 (bit 7)
|
||||||
float TGC0, TGC1; // Timers for GC0 and GC1
|
float TGC0, TGC1; // Timers for GC0 and GC1
|
||||||
@ -53,15 +51,15 @@ float trimGC = .24; // Game Controller trim use F5 and F6 to adjust it
|
|||||||
//======================================================================== AUDIO
|
//======================================================================== AUDIO
|
||||||
|
|
||||||
#define audioBufferSize 512 // found to be large enought
|
#define audioBufferSize 512 // found to be large enought
|
||||||
#define rate 50 // 1 Mhz / 20000 Hz (the wavSpec.freq)
|
double rate = 23.19727891156463; // 1023000 Hz / 44100 Hz (the wavSpec.freq)
|
||||||
|
bool muted = false; // press F9 to mute/unmute
|
||||||
SDL_AudioDeviceID audioDevice;
|
SDL_AudioDeviceID audioDevice;
|
||||||
uint8_t audioBuffer[2][audioBufferSize]; // see main() for more details
|
Sint8 audioBuffer[2][audioBufferSize] = {0}; // see main() for more details
|
||||||
long long int lastTick = 0LL;
|
|
||||||
|
|
||||||
|
|
||||||
//====================================================================== DISK ][
|
//====================================================================== DISK ][
|
||||||
|
|
||||||
uint8_t slot6[256] = {0}; // disk ][ PROM in slot 6
|
uint8_t slot6[256] = {0}; // P5A disk ][ PROM in slot 6
|
||||||
|
|
||||||
struct drive{
|
struct drive{
|
||||||
char filename[512]; // the full disk image path
|
char filename[512]; // the full disk image path
|
||||||
@ -70,11 +68,52 @@ struct drive{
|
|||||||
bool motorOn; // motor status
|
bool motorOn; // motor status
|
||||||
bool writeMode; // writes to file are not implemented
|
bool writeMode; // writes to file are not implemented
|
||||||
uint8_t track; // current track position
|
uint8_t track; // current track position
|
||||||
uint16_t nibble; // current nibble under head position
|
uint16_t nibble; // ptr to nibble under head position
|
||||||
} disk[2] = {0}; // two disk ][ drive units
|
} disk[2] = {0}; // two disk ][ drive units
|
||||||
|
|
||||||
int curDrv = 0; // only one can be enabled at a time
|
int curDrv = 0; // only one can be enabled at a time
|
||||||
|
|
||||||
|
|
||||||
|
int insertFloppy(SDL_Window *wdo, char *filename, int drv){
|
||||||
|
int i, a, b;
|
||||||
|
char title[1024];
|
||||||
|
|
||||||
|
FILE *f = fopen(filename, "rb"); // open it in read binary
|
||||||
|
if (!f){
|
||||||
|
printf("Could not open %s\n", filename);
|
||||||
|
return(0);
|
||||||
|
}
|
||||||
|
if (fread(disk[drv].data, 1, 232960, f) != 232960){ // load it into memory and check size
|
||||||
|
printf("Floppy image should be exactly 232960 Bytes long\n");
|
||||||
|
return(0);
|
||||||
|
}
|
||||||
|
fclose(f);
|
||||||
|
|
||||||
|
sprintf(disk[drv].filename,"%s", filename); // update disk filename
|
||||||
|
|
||||||
|
f = fopen(filename, "ab"); // check if file is writeable
|
||||||
|
if (f){
|
||||||
|
disk[drv].readOnly = false; // f will be NULL if open in W failed
|
||||||
|
fclose(f);
|
||||||
|
}
|
||||||
|
else disk[drv].readOnly = true;
|
||||||
|
|
||||||
|
i = a = 0;
|
||||||
|
while (disk[0].filename[i] != 0) // find start of filename for disk0
|
||||||
|
if (disk[0].filename[i++] == '\\') a = i;
|
||||||
|
|
||||||
|
i = b = 0;
|
||||||
|
while (disk[1].filename[i] != 0) // find start of filename for disk1
|
||||||
|
if (disk[1].filename[i++] == '\\') b = i;
|
||||||
|
|
||||||
|
sprintf(title, "reinette II+ D1: %s D2: %s", disk[0].filename + a, \
|
||||||
|
disk[1].filename + b);
|
||||||
|
SDL_SetWindowTitle(wdo, title); // updates window title
|
||||||
|
|
||||||
|
return(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void stepMotor(uint16_t address){
|
void stepMotor(uint16_t address){
|
||||||
static bool phases[2][4] = {0}; // phases states (for both drives)
|
static bool phases[2][4] = {0}; // phases states (for both drives)
|
||||||
static bool phasesB[2][4] = {0}; // phases states Before
|
static bool phasesB[2][4] = {0}; // phases states Before
|
||||||
@ -91,19 +130,20 @@ void stepMotor(uint16_t address){
|
|||||||
pIdxB[curDrv] = pIdx[curDrv];
|
pIdxB[curDrv] = pIdx[curDrv];
|
||||||
pIdx[curDrv] = phase;
|
pIdx[curDrv] = phase;
|
||||||
|
|
||||||
if ((address & 1) == 0){ // head not moving (PHASE X OFF)
|
if (!(address & 1)){ // head not moving (PHASE x OFF)
|
||||||
phases[curDrv][phase] = false;
|
phases[curDrv][phase] = false;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// head is moving in
|
|
||||||
if ((phasesBB[curDrv][(phase + 1) & 3]) && (--halfTrackPos[curDrv] < 0))
|
if ((phasesBB[curDrv][(phase + 1) & 3]) && (--halfTrackPos[curDrv] < 0)) // head is moving in
|
||||||
halfTrackPos[curDrv] = 0;
|
halfTrackPos[curDrv] = 0;
|
||||||
// head is moving out
|
|
||||||
if ((phasesBB[curDrv][(phase - 1) & 3]) && (++halfTrackPos[curDrv] > 140))
|
if ((phasesBB[curDrv][(phase - 1) & 3]) && (++halfTrackPos[curDrv] > 140)) // head is moving out
|
||||||
halfTrackPos[curDrv] = 140;
|
halfTrackPos[curDrv] = 140;
|
||||||
// update track
|
|
||||||
phases[curDrv][phase] = true;
|
phases[curDrv][phase] = true; // update track#
|
||||||
disk[curDrv].track = (halfTrackPos[curDrv] + 1) / 2;
|
disk[curDrv].track = (halfTrackPos[curDrv] + 1) / 2;
|
||||||
|
disk[curDrv].nibble = 0; // not sure this is necessary ?
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -113,35 +153,38 @@ void stepMotor(uint16_t address){
|
|||||||
|
|
||||||
uint8_t softSwitches(uint16_t address, uint8_t value){
|
uint8_t softSwitches(uint16_t address, uint8_t value){
|
||||||
static uint8_t dLatch = 0; // disk ][ I/O reg
|
static uint8_t dLatch = 0; // disk ][ I/O reg
|
||||||
|
static long long int lastTick = 0LL;
|
||||||
|
|
||||||
if (address>>8 == 0xC6) return(slot6[address - 0xC600]); // disk ][ PROM
|
if ((address >> 8) == 0xC6) return(slot6[address - 0xC600]); // disk ][ PROM
|
||||||
|
|
||||||
switch (address){
|
switch (address){
|
||||||
case 0xC000: return(KBD); // keyboard
|
case 0xC000: return(KBD); // KEYBOARD
|
||||||
case 0xC010: KBD &= 0x7F; return(KBD); // key strobe
|
case 0xC010: KBD &= 0x7F; return(KBD); // key STROBE
|
||||||
|
|
||||||
case 0xC030: // Sound
|
case 0xC020: // TAPEOUT (shall we listen it ?)
|
||||||
|
case 0xC030: // SPEAKER
|
||||||
|
case 0xC033: // apple invader
|
||||||
|
if (!muted){
|
||||||
SPKR = !SPKR; // toggle speaker
|
SPKR = !SPKR; // toggle speaker
|
||||||
if (!MUTED){
|
Uint32 length = (ticks - lastTick) / rate;
|
||||||
uint16_t length = (ticks - lastTick) / rate;
|
|
||||||
if (length > audioBufferSize) length = audioBufferSize;
|
|
||||||
ticks -= length << 2; // speed up CPU
|
|
||||||
lastTick = ticks;
|
lastTick = ticks;
|
||||||
|
if (length > audioBufferSize) length = audioBufferSize;
|
||||||
SDL_QueueAudio(audioDevice, audioBuffer[SPKR], length);
|
SDL_QueueAudio(audioDevice, audioBuffer[SPKR], length);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 0xC050: if (!TEXT) TEXT = 20; break; // Graphics
|
case 0xC050: TEXT = false; break; // Graphics
|
||||||
case 0xC051: TEXT = 0; break; // Text
|
case 0xC051: TEXT = true; break; // Text
|
||||||
case 0xC052: TEXT = 24; break; // Full Screen
|
case 0xC052: MIXED = false; break; // Mixed off
|
||||||
case 0xC053: TEXT = 20; break; // Mixed Screen
|
case 0xC053: MIXED = true; break; // Mixed on
|
||||||
case 0xC054: PAGE = 1; break; // Page 1
|
case 0xC054: PAGE = 1; break; // Page 1
|
||||||
case 0xC055: PAGE = 2; if (HIRES) TEXT = 24; break; // Page 2
|
case 0xC055: PAGE = 2; break; // Page 2
|
||||||
case 0xC056: HIRES = false; break; // HiRes off
|
case 0xC056: HIRES = false; break; // HiRes off
|
||||||
case 0xC057: HIRES = true; break; // HiRes on
|
case 0xC057: HIRES = true; break; // HiRes on
|
||||||
|
|
||||||
case 0xC061: return(PB0); // Push Button 0
|
case 0xC061: return(PB0); // Push Button 0
|
||||||
case 0xC062: return(PB1); // Push Button 1
|
case 0xC062: return(PB1); // Push Button 1
|
||||||
|
case 0xC063: return(PB2); // Push Button 2
|
||||||
case 0xC064: return((TGC0-=trimGC) > 192? 0x80: 0x00); // Paddle 0
|
case 0xC064: return((TGC0-=trimGC) > 192? 0x80: 0x00); // Paddle 0
|
||||||
case 0xC065: return((TGC1-=trimGC) > 192? 0x80: 0x00); // Paddle 1
|
case 0xC065: return((TGC1-=trimGC) > 192? 0x80: 0x00); // Paddle 1
|
||||||
case 0xC070: TGC0 = GC0; TGC1 = GC1; break; // paddle timer RST
|
case 0xC070: TGC0 = GC0; TGC1 = GC1; break; // paddle timer RST
|
||||||
@ -184,7 +227,10 @@ uint8_t softSwitches(uint16_t address, uint8_t value){
|
|||||||
return(disk[curDrv].readOnly ? 0x80 : 0); // check protection
|
return(disk[curDrv].readOnly ? 0x80 : 0); // check protection
|
||||||
|
|
||||||
case 0xC0EF: disk[curDrv].writeMode = true; break; // latch for WRITE
|
case 0xC0EF: disk[curDrv].writeMode = true; break; // latch for WRITE
|
||||||
|
|
||||||
|
default: printf("Uncaught Soft Switch access at %04X\n", address);
|
||||||
}
|
}
|
||||||
|
|
||||||
return(0); // catch all
|
return(0); // catch all
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -193,60 +239,14 @@ uint8_t softSwitches(uint16_t address, uint8_t value){
|
|||||||
|
|
||||||
int main(int argc, char *argv[]){
|
int main(int argc, char *argv[]){
|
||||||
|
|
||||||
// VM INITIALIZATION
|
|
||||||
|
|
||||||
FILE *f = fopen("appleII+.rom", "rb"); // load the Apple II+ ROM
|
|
||||||
if (f){
|
|
||||||
if (fread(rom, 1, ROMSIZE, f) != ROMSIZE){
|
|
||||||
printf("appleII+.rom should be 12 K Bytes\n");
|
|
||||||
return(1);
|
|
||||||
}
|
|
||||||
fclose(f);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
printf("Could not open appleII+.rom\n");
|
|
||||||
return(2);
|
|
||||||
}
|
|
||||||
|
|
||||||
f = fopen("diskII.rom", "rb"); // load the disk ][ PROM
|
|
||||||
if (f){
|
|
||||||
if (fread(slot6, 1, 256, f) != 256){
|
|
||||||
printf("diskII.rom should be 256 Bytes\n");
|
|
||||||
return(3);
|
|
||||||
}
|
|
||||||
fclose(f);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
printf("Could not open diskII.rom\n");
|
|
||||||
return(4);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (argc > 1){ // load .nib in drive 0
|
|
||||||
f = fopen(argv[1], "rb"); // open it in read binary
|
|
||||||
if (f){
|
|
||||||
if (fread(disk[0].data, 1, 232960, f) != 232960){
|
|
||||||
printf("This floppy image should be 232960 Bytes\n");
|
|
||||||
return(5);
|
|
||||||
}
|
|
||||||
fclose(f);
|
|
||||||
sprintf(disk[0].filename,"%s", argv[1]); // update disk filename
|
|
||||||
|
|
||||||
f = fopen(argv[1], "ab"); // check if file is writeable
|
|
||||||
if (f){
|
|
||||||
disk[0].readOnly = true; // f will be NULL if open failed
|
|
||||||
fclose(f);
|
|
||||||
}
|
|
||||||
else disk[0].readOnly = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
puce6502Reset(); // reset the 6502
|
|
||||||
|
|
||||||
|
|
||||||
// SDL INITIALIZATION
|
// SDL INITIALIZATION
|
||||||
|
|
||||||
int zoom = 2;
|
int zoom = 2;
|
||||||
char title[1024] = "reinette II+";
|
const float frameDelay = 1000/60; // targeting 60 FPS
|
||||||
|
float fps = 60;
|
||||||
|
Uint32 frameStart = 0, frameTime = 0, frame = 0, reftime = 0, blink = 0;
|
||||||
|
SDL_Event event;
|
||||||
|
bool paused = false, running = true, ctrl, shift, alt;
|
||||||
|
|
||||||
if(SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO) < 0) {
|
if(SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO) < 0) {
|
||||||
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "[DEBUG] > %s", SDL_GetError());
|
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "[DEBUG] > %s", SDL_GetError());
|
||||||
@ -255,29 +255,26 @@ int main(int argc, char *argv[]){
|
|||||||
|
|
||||||
SDL_EventState(SDL_DROPFILE, SDL_ENABLE);
|
SDL_EventState(SDL_DROPFILE, SDL_ENABLE);
|
||||||
|
|
||||||
SDL_Window *wdo = SDL_CreateWindow(title, SDL_WINDOWPOS_CENTERED, \
|
SDL_Window *wdo = SDL_CreateWindow("reinette II+", SDL_WINDOWPOS_CENTERED, \
|
||||||
SDL_WINDOWPOS_CENTERED, 280*zoom, 192*zoom, SDL_WINDOW_OPENGL);
|
SDL_WINDOWPOS_CENTERED, 280*zoom, 192*zoom, SDL_WINDOW_OPENGL);
|
||||||
|
|
||||||
SDL_Renderer *rdr = SDL_CreateRenderer(wdo, -1, SDL_RENDERER_ACCELERATED);
|
SDL_Surface *icon = SDL_LoadBMP("icon.bmp"); // add an icon to the window title bar
|
||||||
|
SDL_SetColorKey(icon, SDL_TRUE, SDL_MapRGB(icon->format, 255, 255, 255));
|
||||||
|
SDL_SetWindowIcon(wdo, icon);
|
||||||
|
|
||||||
SDL_SetRenderDrawBlendMode(rdr, SDL_BLENDMODE_BLEND);
|
SDL_Renderer *rdr = SDL_CreateRenderer(wdo, -1, SDL_RENDERER_ACCELERATED); // | SDL_RENDERER_PRESENTVSYNC);
|
||||||
|
SDL_SetRenderDrawBlendMode(rdr, SDL_BLENDMODE_NONE); // SDL_BLENDMODE_BLEND);
|
||||||
SDL_RenderSetScale(rdr, zoom, zoom);
|
SDL_RenderSetScale(rdr, zoom, zoom);
|
||||||
|
|
||||||
const int frameDelay = 1000/60; // targeting 60 FPS
|
|
||||||
Uint32 frameStart = 0, frameTime = 0, frame = 0;
|
|
||||||
SDL_Event event;
|
|
||||||
bool paused = false, running = true, ctrl, shift, alt;
|
|
||||||
|
|
||||||
|
|
||||||
// SDL AUDIO INITIALIZATION
|
// SDL AUDIO INITIALIZATION
|
||||||
|
|
||||||
SDL_AudioSpec wavSpec = {20000, AUDIO_U8, 1, 0, 8, 0, 0, NULL, NULL};
|
SDL_AudioSpec desired = {44100, AUDIO_S8, 1, 0, 4096, 0, 0, NULL, NULL};
|
||||||
audioDevice = SDL_OpenAudioDevice(NULL, 0, &wavSpec, NULL, 0);
|
audioDevice = SDL_OpenAudioDevice(NULL, 0, &desired, NULL, SDL_FALSE);
|
||||||
SDL_PauseAudioDevice(audioDevice, MUTED);
|
SDL_PauseAudioDevice(audioDevice, muted);
|
||||||
|
|
||||||
// two audio buffers, one when the speaker is 'on', the other when it's 'off'
|
for (int i=0; i<audioBufferSize; i++){ // two audio buffers, one when the speaker is 'on', the other when it's 'off'
|
||||||
for (int i=0; i<audioBufferSize; i++){
|
audioBuffer[true][i] = 127; // when SPKR==true : 1/2 of max amplitude
|
||||||
audioBuffer[true][i] = 32; // when SPKR==true : 1/8 of max amplitude
|
|
||||||
audioBuffer[false][i] = 0; // when SPKR==false : silence
|
audioBuffer[false][i] = 0; // when SPKR==false : silence
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -295,11 +292,16 @@ int main(int argc, char *argv[]){
|
|||||||
|
|
||||||
// VARIABLES USED IN THE VIDEO PRODUCTION
|
// VARIABLES USED IN THE VIDEO PRODUCTION
|
||||||
|
|
||||||
uint16_t previousDots[192][40]={0}; // check which Hi-Res 7 dots needs redraw
|
uint16_t previousDots[192][40] = {0}; // check which Hi-Res 7 dots needs redraw
|
||||||
int previousBit[192][40]={0}; // the dot value of the byte before.
|
int previousBit[192][40] = {0}; // the last bit value of the byte before.
|
||||||
uint8_t glyph; // a TEXT character, or 2 blocks in GR
|
uint8_t glyph; // a TEXT character, or 2 blocks in GR
|
||||||
uint16_t vRamBase = 0x0400; // can be 0x0400, 0x0800, 0x2000 or 0x4000
|
|
||||||
uint8_t colorIdx = 0; // to index the color arrays
|
uint8_t colorIdx = 0; // to index the color arrays
|
||||||
|
uint16_t vRamBase = 0x0400; // can be 0x0400, 0x0800, 0x2000 or 0x4000
|
||||||
|
int lineLimit;
|
||||||
|
enum characterAttribute {A_NORMAL, A_INVERSE, A_FLASH} glyphAttribute;
|
||||||
|
bool monochrome = false;
|
||||||
|
|
||||||
|
SDL_Rect drvRect[2] = { {272, 188, 4, 4}, {276, 188, 4, 4} }; // disk drive status squares
|
||||||
SDL_Rect pixelGR = {0, 0, 7, 4}; // a block in LoRes
|
SDL_Rect pixelGR = {0, 0, 7, 4}; // a block in LoRes
|
||||||
SDL_Rect dstRect = {0, 0, 7, 8}; // the dst character in rdr
|
SDL_Rect dstRect = {0, 0, 7, 8}; // the dst character in rdr
|
||||||
SDL_Rect charRects[128]; // the src from the norm and rev textures
|
SDL_Rect charRects[128]; // the src from the norm and rev textures
|
||||||
@ -309,11 +311,6 @@ int main(int argc, char *argv[]){
|
|||||||
charRects[c].w = 7;
|
charRects[c].w = 7;
|
||||||
charRects[c].h = 8;
|
charRects[c].h = 8;
|
||||||
}
|
}
|
||||||
SDL_Rect drvRect[2] = { // disk drive status squares
|
|
||||||
{272, 188, 4, 4}, {276, 188, 4, 4}};
|
|
||||||
|
|
||||||
enum characterAttribute {A_NORMAL, A_INVERSE, A_FLASH} glyphAttribute;
|
|
||||||
bool MONOCHROME = false;
|
|
||||||
|
|
||||||
const int color[16][3] = { // the 16 low res colors
|
const int color[16][3] = { // the 16 low res colors
|
||||||
{ 0, 0, 0}, {226, 57, 86}, { 28, 116,205}, {126, 110, 173},
|
{ 0, 0, 0}, {226, 57, 86}, { 28, 116,205}, {126, 110, 173},
|
||||||
@ -321,11 +318,9 @@ int main(int argc, char *argv[]){
|
|||||||
{151, 88, 34}, {234, 108, 21}, {158, 151,143}, {255, 206, 240},
|
{151, 88, 34}, {234, 108, 21}, {158, 151,143}, {255, 206, 240},
|
||||||
{144, 192, 49}, {255, 253, 166}, {159, 210,213}, {255, 255, 255}};
|
{144, 192, 49}, {255, 253, 166}, {159, 210,213}, {255, 255, 255}};
|
||||||
|
|
||||||
const int hcolor[8][3] = { // the high res colors (2 color sets)
|
const int hcolor[16][3] = { // the high res colors (2 lights)
|
||||||
{ 0, 0, 0}, {144, 192, 49}, {126, 110, 173}, {255, 255, 255},
|
{ 0, 0, 0}, {144, 192, 49}, {126, 110, 173}, {255, 255, 255},
|
||||||
{ 0, 0, 0}, {234, 108, 21}, { 86, 168, 228}, {255, 255, 255}};
|
{ 0, 0, 0}, {234, 108, 21}, { 86, 168, 228}, {255, 255, 255},
|
||||||
|
|
||||||
const int dhcolor[8][3] = { // the high res 2nd half pixel, darker
|
|
||||||
{ 0, 0, 0}, { 63, 55, 86}, { 72, 96, 25}, {255, 255, 255},
|
{ 0, 0, 0}, { 63, 55, 86}, { 72, 96, 25}, {255, 255, 255},
|
||||||
{ 0, 0, 0}, { 43, 84, 114}, {117, 54, 10}, {255, 255, 255}};
|
{ 0, 0, 0}, { 43, 84, 114}, {117, 54, 10}, {255, 255, 255}};
|
||||||
|
|
||||||
@ -361,72 +356,83 @@ int main(int argc, char *argv[]){
|
|||||||
0x03D0, 0x07D0, 0x0BD0, 0x0FD0, 0x13D0, 0x17D0, 0x1BD0, 0x1FD0}; // 184-191
|
0x03D0, 0x07D0, 0x0BD0, 0x0FD0, 0x13D0, 0x17D0, 0x1BD0, 0x1FD0}; // 184-191
|
||||||
|
|
||||||
|
|
||||||
|
// VM INITIALIZATION
|
||||||
|
|
||||||
|
FILE *f = fopen("appleII+.rom", "rb"); // load the Apple II+ ROM
|
||||||
|
if (!f){
|
||||||
|
printf("Could not open appleII+.rom\n");
|
||||||
|
return(1);
|
||||||
|
}
|
||||||
|
if (fread(rom, 1, ROMSIZE, f) != ROMSIZE){
|
||||||
|
printf("appleII+.rom should be 12KB\n");
|
||||||
|
return(1);
|
||||||
|
}
|
||||||
|
fclose(f);
|
||||||
|
|
||||||
|
f = fopen("diskII.rom", "rb"); // load the P5A disk ][ PROM
|
||||||
|
if (!f){
|
||||||
|
printf("Could not open diskII.rom\n");
|
||||||
|
return(1);
|
||||||
|
}
|
||||||
|
if (fread(slot6, 1, 256, f) != 256){
|
||||||
|
printf("diskII.rom should be 256 Bytes\n");
|
||||||
|
return(1);
|
||||||
|
}
|
||||||
|
fclose(f);
|
||||||
|
|
||||||
|
if (argc > 1) insertFloppy(wdo, argv[1], 0); // load .nib in drive 0
|
||||||
|
|
||||||
|
puce6502Reset(); // reset the 6502
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//================================================================== MAIN LOOP
|
//================================================================== MAIN LOOP
|
||||||
|
|
||||||
|
reftime = SDL_GetTicks();
|
||||||
|
|
||||||
while (running){
|
while (running){
|
||||||
|
|
||||||
frameStart = SDL_GetTicks(); // start of a new frame
|
frameStart = SDL_GetTicks(); // start of a new frame
|
||||||
|
|
||||||
|
|
||||||
//================================================================== RUN CPU
|
|
||||||
|
|
||||||
if (!paused){
|
if (!paused){
|
||||||
puce6502Exec(16666); // execute 1000000/60 cycles at each frame
|
puce6502Exec((long long int)(1023000.0 / fps)); // adjusted ~1M/60 to the actual frame rate
|
||||||
if (disk[curDrv].motorOn) // drive is active
|
int i;
|
||||||
puce6502Exec(500000); // artificial drive speed up
|
i = 0;
|
||||||
|
while (disk[curDrv].motorOn && i < 50){ // until motor is off or i reaches 50
|
||||||
|
puce6502Exec(10000); // artificial drive speed up
|
||||||
|
i++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//=============================================================== USER INPUT
|
||||||
//=========================================================== KEYBOARD INPUT
|
|
||||||
|
|
||||||
while (SDL_PollEvent(&event)){
|
while (SDL_PollEvent(&event)){
|
||||||
|
|
||||||
ctrl = SDL_GetModState() & KMOD_CTRL ? true : false;
|
|
||||||
alt = SDL_GetModState() & KMOD_ALT ? true : false;
|
alt = SDL_GetModState() & KMOD_ALT ? true : false;
|
||||||
|
ctrl = SDL_GetModState() & KMOD_CTRL ? true : false;
|
||||||
shift = SDL_GetModState() & KMOD_SHIFT ? true : false;;
|
shift = SDL_GetModState() & KMOD_SHIFT ? true : false;;
|
||||||
PB0 = alt ? 0xFF : 0x00; // update push button 0
|
PB0 = alt ? 0xFF : 0x00; // update push button 0
|
||||||
PB1 = ctrl ? 0xFF : 0x00; // update push button 1
|
PB1 = ctrl ? 0xFF : 0x00; // update push button 1
|
||||||
|
PB2 = shift ? 0xFF : 0x00; // update push button 2
|
||||||
|
|
||||||
if (event.type == SDL_QUIT) running = false; // WM sent TERM signal
|
if (event.type == SDL_QUIT) running = false; // WM sent TERM signal
|
||||||
|
|
||||||
|
// if (event.type == SDL_WINDOWEVENT){
|
||||||
|
// if(event.window.event == SDL_WINDOWEVENT_FOCUS_LOST)
|
||||||
|
// paused = true;
|
||||||
|
// if (event.window.event == SDL_WINDOWEVENT_FOCUS_GAINED)
|
||||||
|
// paused = false;
|
||||||
|
// }
|
||||||
|
|
||||||
if (event.type == SDL_DROPFILE){ // user dropped a file
|
if (event.type == SDL_DROPFILE){ // user dropped a file
|
||||||
|
|
||||||
char* filename = event.drop.file; // get full pathname
|
char* filename = event.drop.file; // get full pathname
|
||||||
f = fopen(filename, "rb"); // open it in read binary
|
insertFloppy(wdo, filename, alt); // if ALT : drv 1 else drv 0
|
||||||
if (f){
|
|
||||||
fread(disk[alt].data, 1, 232960, f); // if ALT : drv 1 else drv 0
|
|
||||||
fclose(f);
|
|
||||||
}
|
|
||||||
|
|
||||||
f = fopen(filename, "ab"); // check if file is writable
|
|
||||||
if (f) {
|
|
||||||
disk[alt].readOnly = true; // f is NULL if open failed
|
|
||||||
fclose(f);
|
|
||||||
}
|
|
||||||
else disk[alt].readOnly = false;
|
|
||||||
|
|
||||||
sprintf(disk[alt].filename,"%s", filename); // update disk filename
|
|
||||||
SDL_free(filename); // free filename memory
|
SDL_free(filename); // free filename memory
|
||||||
|
|
||||||
int i, a, b; // updates window title
|
|
||||||
i = a = 0;
|
|
||||||
while (disk[0].filename[i] != 0) // find start of filename
|
|
||||||
if (disk[0].filename[i++] == '\\') a = i; // for disk0
|
|
||||||
i = b = 0;
|
|
||||||
while (disk[1].filename[i] != 0) // find start of filename
|
|
||||||
if (disk[1].filename[i++] == '\\') b = i; // for disk1
|
|
||||||
sprintf(title, "reinette II+ D1: %s D2: %s", \
|
|
||||||
disk[0].filename + a, disk[1].filename + b);
|
|
||||||
|
|
||||||
SDL_SetWindowTitle(wdo, title); // set the title
|
|
||||||
paused = false; // might already be the case
|
paused = false; // might already be the case
|
||||||
if (!alt) puce6502Goto(0xC600); // force reboot
|
if (!(alt || ctrl)) // unless ALT or CTRL were
|
||||||
|
puce6502Goto(0xC600); // pressed, force reboot
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (event.type == SDL_KEYDOWN) // a key has been pressed
|
if (event.type == SDL_KEYDOWN) // a key has been pressed
|
||||||
|
|
||||||
switch (event.key.keysym.sym){
|
switch (event.key.keysym.sym){
|
||||||
@ -439,7 +445,6 @@ int main(int argc, char *argv[]){
|
|||||||
if (f){
|
if (f){
|
||||||
if (fwrite(disk[0].data, 1, 232960, f) != 232960){
|
if (fwrite(disk[0].data, 1, 232960, f) != 232960){
|
||||||
printf("Write failed\n");
|
printf("Write failed\n");
|
||||||
return(20);
|
|
||||||
}
|
}
|
||||||
fclose(f);
|
fclose(f);
|
||||||
}
|
}
|
||||||
@ -452,15 +457,13 @@ int main(int argc, char *argv[]){
|
|||||||
if (f){
|
if (f){
|
||||||
if (fwrite(disk[1].data, 1, 232960, f) != 232960){
|
if (fwrite(disk[1].data, 1, 232960, f) != 232960){
|
||||||
printf("Write failed\n");
|
printf("Write failed\n");
|
||||||
return(21);
|
|
||||||
}
|
}
|
||||||
fclose(f);
|
fclose(f);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case SDLK_F3: paused = !paused; break; // pause / un-pause
|
||||||
case SDLK_F3: paused = !paused; break; //
|
|
||||||
|
|
||||||
case SDLK_F4: // paste txt from clipboard
|
case SDLK_F4: // paste txt from clipboard
|
||||||
if (SDL_HasClipboardText()){
|
if (SDL_HasClipboardText()){
|
||||||
@ -475,34 +478,31 @@ int main(int argc, char *argv[]){
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
||||||
case SDLK_F5: if ((zoom-=2) < 0) zoom = 0; // zoom out
|
case SDLK_F5: if ((zoom-=2) < 0) zoom = 0; // zoom out
|
||||||
case SDLK_F6: if (++zoom > 8) zoom = 8; // zoom in
|
case SDLK_F6: if (++zoom > 8) zoom = 8; // zoom in
|
||||||
SDL_SetWindowSize(wdo, 280*zoom, 192*zoom);
|
SDL_SetWindowSize(wdo, 280*zoom, 192*zoom);
|
||||||
SDL_RenderSetScale(rdr, zoom, zoom); break;
|
SDL_RenderSetScale(rdr, zoom, zoom); break;
|
||||||
|
|
||||||
|
|
||||||
case SDLK_F7: trimGC -= .01; break; // PDL Trim
|
case SDLK_F7: trimGC -= .01; break; // PDL Trim
|
||||||
case SDLK_F8: trimGC += .01; break; // PDL Trim
|
case SDLK_F8: trimGC += .01; break; // PDL Trim
|
||||||
|
|
||||||
case SDLK_F9: MUTED = !MUTED; break; // mute
|
case SDLK_F9: muted = !muted; break; // mute
|
||||||
|
case SDLK_F10: monochrome = !monochrome; break; // ...
|
||||||
case SDLK_F10: MONOCHROME = !MONOCHROME; break; //
|
|
||||||
|
|
||||||
case SDLK_F11: // reset
|
case SDLK_F11: // reset
|
||||||
if (ctrl)
|
if (ctrl)
|
||||||
puce6502Break();
|
puce6502Break();
|
||||||
else {
|
else {
|
||||||
puce6502Reset();
|
puce6502Reset();
|
||||||
softSwitches(0xC0E8,0); // motorOff
|
|
||||||
softSwitches(0xC0E9,0); // drive0En
|
softSwitches(0xC0E9,0); // drive0En
|
||||||
|
softSwitches(0xC0E8,0); // motorOff
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SDLK_F12: running = false; break; // goodbye
|
case SDLK_F12: running = false; break; // goodbye
|
||||||
|
|
||||||
|
|
||||||
// EMULATED KEYS :
|
// EMULATED KEYS :
|
||||||
|
|
||||||
case SDLK_ESCAPE: KBD = 0x9B; break; // ESC
|
case SDLK_ESCAPE: KBD = 0x9B; break; // ESC
|
||||||
case SDLK_RETURN: KBD = 0x8D; break; // CR
|
case SDLK_RETURN: KBD = 0x8D; break; // CR
|
||||||
case SDLK_DELETE: KBD = 0x80; break; // DEL->NUL
|
case SDLK_DELETE: KBD = 0x80; break; // DEL->NUL
|
||||||
@ -538,7 +538,7 @@ int main(int argc, char *argv[]){
|
|||||||
case SDLK_z: KBD = ctrl ? 0x9A: 0xDA; break; // z
|
case SDLK_z: KBD = ctrl ? 0x9A: 0xDA; break; // z
|
||||||
case SDLK_0: KBD = shift? 0xA9: 0xB0; break; // 0 )
|
case SDLK_0: KBD = shift? 0xA9: 0xB0; break; // 0 )
|
||||||
case SDLK_1: KBD = shift? 0xA1: 0xB1; break; // 1 !
|
case SDLK_1: KBD = shift? 0xA1: 0xB1; break; // 1 !
|
||||||
case SDLK_2: KBD = shift? 0xC0: 0xB2; break; // 2 @
|
case SDLK_2: KBD = shift? 0xC0: 0xB2; break; // 2
|
||||||
case SDLK_3: KBD = shift? 0xA3: 0xB3; break; // 3 #
|
case SDLK_3: KBD = shift? 0xA3: 0xB3; break; // 3 #
|
||||||
case SDLK_4: KBD = shift? 0xA4: 0xB4; break; // 4 $
|
case SDLK_4: KBD = shift? 0xA4: 0xB4; break; // 4 $
|
||||||
case SDLK_5: KBD = shift? 0xA5: 0xB5; break; // 5 %
|
case SDLK_5: KBD = shift? 0xA5: 0xB5; break; // 5 %
|
||||||
@ -558,6 +558,8 @@ int main(int argc, char *argv[]){
|
|||||||
case SDLK_RIGHTBRACKET: KBD = shift? 0xFD: 0xDD; break; // ] }
|
case SDLK_RIGHTBRACKET: KBD = shift? 0xFD: 0xDD; break; // ] }
|
||||||
case SDLK_BACKQUOTE: KBD = shift? 0xFE: 0xE0; break; // ` ~
|
case SDLK_BACKQUOTE: KBD = shift? 0xFE: 0xE0; break; // ` ~
|
||||||
|
|
||||||
|
// EMULATED JOYSTICK
|
||||||
|
|
||||||
case SDLK_KP_1: GC0 = 192; break; // pdl0 <-
|
case SDLK_KP_1: GC0 = 192; break; // pdl0 <-
|
||||||
case SDLK_KP_3: GC0 = 255; break; // pdl0 ->
|
case SDLK_KP_3: GC0 = 255; break; // pdl0 ->
|
||||||
case SDLK_KP_5: GC1 = 192; break; // pdl1 <-
|
case SDLK_KP_5: GC1 = 192; break; // pdl1 <-
|
||||||
@ -573,86 +575,71 @@ int main(int argc, char *argv[]){
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//============================================================= VIDEO OUTPUT
|
//============================================================= VIDEO OUTPUT
|
||||||
|
|
||||||
//======================================================== HIGH RES GRAPHICS
|
// HIGH RES GRAPHICS
|
||||||
|
|
||||||
if (HIRES){
|
|
||||||
int word, bits[16], bit, pbit, colorSet;
|
|
||||||
bool even;
|
|
||||||
|
|
||||||
|
if (!TEXT && HIRES){
|
||||||
|
int word, bits[16], bit, pbit, colorSet, even;
|
||||||
vRamBase = PAGE * 0x2000; // PAGE is 1 or 2
|
vRamBase = PAGE * 0x2000; // PAGE is 1 or 2
|
||||||
|
lineLimit = MIXED ? 160 : 192;
|
||||||
|
|
||||||
for (int line=0; line<TEXT*8; line++){ // for every line
|
for (int line=0; line<lineLimit; line++){ // for every line
|
||||||
for (int col=0; col<40; col += 2){ // for every 7 horizontal dots
|
for (int col=0; col<40; col += 2){ // for every 7 horizontal dots
|
||||||
int x = col * 7;
|
int x = col * 7;
|
||||||
even = true;
|
even = 0;
|
||||||
|
|
||||||
// put the two next bytes into one word (in reverse order)
|
word = (uint16_t)(ram[ vRamBase + offsetHGR[line] + col + 1 ]) << 8; // put the two next bytes into one word (in reverse order)
|
||||||
word = (uint16_t)(ram[ vRamBase + offsetHGR[line] + col + 1 ]) << 8;
|
|
||||||
word += ram[ vRamBase + offsetHGR[line] + col ];
|
word += ram[ vRamBase + offsetHGR[line] + col ];
|
||||||
|
|
||||||
// check if this group of 7 dots need a redraw (ie was modified)
|
// check if this group of 7 dots need a redraw (ie was modified)
|
||||||
if (previousDots[line][col] != word || frame == 0){
|
if (previousDots[line][col] != word || !blink){ // or refresh the full screen every 1/2 second (everytime blink is reset to 0)
|
||||||
|
|
||||||
// store all bits of the word into the bits array
|
for (bit=0; bit<16; bit++) bits[bit] = (word >> bit) & 1; // store all bits of the word into the 'bits' array
|
||||||
for (bit=0; bit<16; bit++) bits[bit] = (word >> bit) & 1;
|
|
||||||
|
|
||||||
colorSet = bits[7] * 4; // select the right color set
|
colorSet = bits[7] * 4; // select the right color set
|
||||||
pbit = previousBit[line][col];
|
pbit = previousBit[line][col]; // the bit value of the left dot
|
||||||
bit = 0; // starting at 1st bit of 1st byte
|
bit = 0; // starting at 1st bit of 1st byte
|
||||||
|
|
||||||
while (bit < 15){ // until we reach bit7 of 2nd byte
|
while (bit < 15){ // until we reach bit7 of 2nd byte
|
||||||
|
|
||||||
if (bit == 7){ // moving into the second byte
|
if (bit == 7){ // moving into the second byte
|
||||||
colorSet = bits[15] * 4; // update the color set
|
colorSet = bits[15] * 4; // update the color set
|
||||||
pbit = bits[6];
|
|
||||||
bit++; // skip bit 7
|
bit++; // skip bit 7
|
||||||
}
|
}
|
||||||
|
|
||||||
if (MONOCHROME)
|
if (monochrome)
|
||||||
colorIdx = bits[bit] * 3;
|
colorIdx = bits[bit] * 3; // black if bit==0, white if bit==1
|
||||||
else
|
else
|
||||||
colorIdx = colorSet + (bits[bit] << 1) + (pbit);
|
colorIdx = even + colorSet + (bits[bit] << 1) + (pbit);
|
||||||
|
|
||||||
if (even)
|
|
||||||
SDL_SetRenderDrawColor(rdr, hcolor[colorIdx][0], \
|
SDL_SetRenderDrawColor(rdr, hcolor[colorIdx][0], \
|
||||||
hcolor[colorIdx][1], hcolor[colorIdx][2], SDL_ALPHA_OPAQUE);
|
hcolor[colorIdx][1], hcolor[colorIdx][2], SDL_ALPHA_OPAQUE);
|
||||||
else
|
SDL_RenderDrawPoint(rdr, x++, line);
|
||||||
SDL_SetRenderDrawColor(rdr, dhcolor[colorIdx][0], \
|
|
||||||
dhcolor[colorIdx][1], dhcolor[colorIdx][2], SDL_ALPHA_OPAQUE);
|
|
||||||
|
|
||||||
SDL_RenderDrawPoint(rdr, x, line);
|
pbit = bits[bit++]; // proceed to the next pixel
|
||||||
|
even = even ? 0 : 8; // one pixel every two is darker
|
||||||
x++; // proceed to the next dot
|
}
|
||||||
pbit = bits[bit];
|
|
||||||
bit++;
|
|
||||||
even = !even;
|
|
||||||
} // while (bit < 15)
|
|
||||||
|
|
||||||
previousDots[line][col] = word; // update the video cache
|
previousDots[line][col] = word; // update the video cache
|
||||||
|
if ((col < 37) && (previousBit[line][col + 2] != pbit)){ // check it this dot has a color franging effect on the next dot
|
||||||
if ((col < 37) && (previousBit[line][col + 2] != pbit)){
|
previousBit[line][col + 2] = pbit; // set pbit and clear the
|
||||||
previousBit[line][col + 2] = pbit; // check for color franging
|
previousDots[line][col + 2] = -1; // video cache for next dot
|
||||||
previousDots[line][col + 2] = -1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // if (previousDots[line][col] ...
|
} // if (previousDots[line][col] ...
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} // if (HIRES)
|
}
|
||||||
|
|
||||||
|
// lOW RES GRAPHICS
|
||||||
|
|
||||||
|
else if (!TEXT){ // not in text
|
||||||
|
|
||||||
//========================================================= lOW RES GRAPHICS
|
|
||||||
|
|
||||||
else if (TEXT){ // not in full text
|
|
||||||
vRamBase = PAGE * 0x0400;
|
vRamBase = PAGE * 0x0400;
|
||||||
|
lineLimit = MIXED ? 20 : 24;
|
||||||
|
|
||||||
for (int col=0; col<40; col++){ // for each column
|
for (int col=0; col<40; col++){ // for each column
|
||||||
pixelGR.x = col * 7;
|
pixelGR.x = col * 7;
|
||||||
for (int line=0; line<TEXT; line++){ // for each row
|
for (int line=0; line<lineLimit; line++){ // for each row
|
||||||
pixelGR.y = line * 8; // first block
|
pixelGR.y = line * 8; // first block
|
||||||
|
|
||||||
glyph = ram[vRamBase + offsetGR[line] + col]; // read video memory
|
glyph = ram[vRamBase + offsetGR[line] + col]; // read video memory
|
||||||
@ -671,20 +658,21 @@ int main(int argc, char *argv[]){
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TEXT 40 COLUMNS
|
||||||
|
|
||||||
//========================================================== TEXT 40 COLUMNS
|
if (TEXT || MIXED){
|
||||||
|
|
||||||
if (TEXT != 24){
|
|
||||||
vRamBase = PAGE * 0x0400;
|
vRamBase = PAGE * 0x0400;
|
||||||
|
lineLimit = TEXT ? 0 : 20;
|
||||||
|
|
||||||
for (int col=0; col<40; col++){ // for each column
|
for (int col=0; col<40; col++){ // for each column
|
||||||
dstRect.x = col * 7;
|
dstRect.x = col * 7;
|
||||||
for (int line=TEXT; line<24; line++){ // for each row
|
for (int line=lineLimit; line<24; line++){ // for each row
|
||||||
dstRect.y = line * 8;
|
dstRect.y = line * 8;
|
||||||
|
|
||||||
glyph = ram[vRamBase + offsetGR[line] + col]; // read video memory
|
glyph = ram[vRamBase + offsetGR[line] + col]; // read video memory
|
||||||
|
|
||||||
if (glyph < 0x40) glyphAttribute = A_INVERSE; // is INVERSE ?
|
if (glyph > 0x7F) glyphAttribute = A_NORMAL; // is NORMAL ?
|
||||||
else if (glyph > 0x7F) glyphAttribute = A_NORMAL; // is NORMAL ?
|
else if (glyph < 0x40) glyphAttribute = A_INVERSE; // is INVERSE ?
|
||||||
else glyphAttribute = A_FLASH; // it's FLASH !
|
else glyphAttribute = A_FLASH; // it's FLASH !
|
||||||
|
|
||||||
glyph &= 0x7F; // unset bit 7
|
glyph &= 0x7F; // unset bit 7
|
||||||
@ -692,7 +680,7 @@ int main(int argc, char *argv[]){
|
|||||||
if (glyph > 0x5F) glyph &= 0x3F; // shifts to match
|
if (glyph > 0x5F) glyph &= 0x3F; // shifts to match
|
||||||
if (glyph < 0x20) glyph |= 0x40; // the ASCII codes
|
if (glyph < 0x20) glyph |= 0x40; // the ASCII codes
|
||||||
|
|
||||||
if (glyphAttribute==A_NORMAL || (glyphAttribute==A_FLASH && frame<15))
|
if (glyphAttribute == A_NORMAL || blink < 15)
|
||||||
SDL_RenderCopy(rdr, normCharTexture, &charRects[glyph], &dstRect);
|
SDL_RenderCopy(rdr, normCharTexture, &charRects[glyph], &dstRect);
|
||||||
else
|
else
|
||||||
SDL_RenderCopy(rdr, revCharTexture, &charRects[glyph], &dstRect);
|
SDL_RenderCopy(rdr, revCharTexture, &charRects[glyph], &dstRect);
|
||||||
@ -700,7 +688,6 @@ int main(int argc, char *argv[]){
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//====================================================== DISPLAY DISK STATUS
|
//====================================================== DISPLAY DISK STATUS
|
||||||
|
|
||||||
if (disk[curDrv].motorOn){ // drive is active
|
if (disk[curDrv].motorOn){ // drive is active
|
||||||
@ -709,21 +696,29 @@ int main(int argc, char *argv[]){
|
|||||||
else
|
else
|
||||||
SDL_SetRenderDrawColor(rdr, 0, 255, 0, 85); // green for reads
|
SDL_SetRenderDrawColor(rdr, 0, 255, 0, 85); // green for reads
|
||||||
|
|
||||||
SDL_RenderFillRect(rdr, &drvRect[curDrv]);
|
SDL_RenderFillRect(rdr, &drvRect[curDrv]); // square actually
|
||||||
}
|
}
|
||||||
|
|
||||||
//========================================================= SDL RENDER FRAME
|
//========================================================= SDL RENDER FRAME
|
||||||
|
|
||||||
if (++frame == 30) frame = 0; // 1/2 second timer
|
|
||||||
|
|
||||||
frameTime = SDL_GetTicks() - frameStart; // frame duration
|
frameTime = SDL_GetTicks() - frameStart; // frame duration
|
||||||
if (frameDelay > frameTime) SDL_Delay(frameDelay - frameTime); // wait vsync
|
if (frameDelay > frameTime) { // do we have time ?
|
||||||
|
SDL_Delay(frameDelay - frameTime); // wait 'vsync'
|
||||||
SDL_RenderPresent(rdr); // swap buffers
|
SDL_RenderPresent(rdr); // swap buffers
|
||||||
|
} // else, skip frame
|
||||||
|
|
||||||
|
frame++;
|
||||||
|
if (frameStart > reftime + 1000){
|
||||||
|
fps = (float)(frame * 1000.0) / (float)(frameStart - reftime);
|
||||||
|
// printf("TIME:%d FPS:%f FRAME:%d\n", frameStart - reftime, fps, frame);
|
||||||
|
frame = 0;
|
||||||
|
reftime = SDL_GetTicks();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (++blink == 30) blink = 0;
|
||||||
|
|
||||||
} // while (running)
|
} // while (running)
|
||||||
|
|
||||||
|
|
||||||
//================================================ RELEASE RESSOURSES AND EXIT
|
//================================================ RELEASE RESSOURSES AND EXIT
|
||||||
|
|
||||||
SDL_AudioQuit();
|
SDL_AudioQuit();
|
||||||
|
Loading…
Reference in New Issue
Block a user