Function keys updated

This commit is contained in:
ArthurFerreira2 2020-08-14 21:42:31 +02:00 committed by GitHub
parent 3a79269dc0
commit 8cd9263453
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 80 additions and 95 deletions

View File

@ -4,9 +4,9 @@
![screenshots](screenshots.png)
After [reinette](https://github.com/ArthurFerreira2/reinette) (Apple 1 emulator) and [reinette II](https://github.com/ArthurFerreira2/reinette-II) (the text only Apple II emulator), I am proud to release **reinette II plus**, a french\* Apple II plus emulator using SDL2.
After [reinette](https://github.com/ArthurFerreira2/reinette) (Apple 1 emulator) and [reinette II](https://github.com/ArthurFerreira2/reinette-II) (the text only Apple II emulator), I am proud to release **reinette II plus**, a French\* Apple II plus emulator using SDL2.
\* reinette has two meanings in french : it's a little frog but also a delicious kind of apple
\* reinette has two meanings in French : it's a little frog but also a delicious kind of apple
[download windows binaries](https://github.com/ArthurFerreira2/reinette-II-plus/releases/tag/0.2b)
@ -26,7 +26,6 @@ After [reinette](https://github.com/ArthurFerreira2/reinette) (Apple 1 emulator)
It uses the same MOS 6502 CPU emulator as her sisters (now christened [puce6502](https://github.com/ArthurFerreira2/puce6502)).\
You only need SDL2 to compile it. (I'm not using SDL_Mixer, but only the native SDL2 audio functions)
This emulator is not accurate in many ways and does not compete with
[AppleWin](https://github.com/AppleWin/AppleWin), [Epple](https://github.com/cmosher01/Epple-II) or [LinApple](https://github.com/linappleii/linapple). Better use one of them if you want a good Apple ][ emulation experience.
@ -36,70 +35,68 @@ It's compact, less than 1000 SLOC, with two source files only, one for the CPU e
I did my best to comment the code, and if you have an idea of how an Apple ][ works, it should be easy for you to understand the code, modify and enhance it for your needs (see TODO section).
### Startup
You can specify a .nib file on the command line to start the emulator with a floppy engaged in drive 1. Otherwise, the emulator will start with no floppy (and thus wait one until you press the reset key or drag and drop a .nib file)
You can specify a .nib file on the command line to start the emulator with a floppy engaged in drive 1. Otherwise, the emulator will start with no floppy (and thus waits until you press the reset key or drag and drop a .nib file)
### Usage
Drag and drop a disk image file (.nib format only) to insert it into drive 1\
Drop the file while pressing the ALT key to insert it into drive 2
**reinette II plus** will reboot immediately and try to boot the floppy.\
Press CTRL while dropping the file if you don't want the emulator to reboot \
Pressing the ALT key while dropping the file inserts it into drive 2.
Use the functions keys to control the emulator itself
Use the functions keys to control the emulator itself :
```
* F1 : writes the changes of the floppy in drive 0 back to host
* F2 : writes the changes of the floppy in drive 1 back to host
* F3 : pause / un-pause the emulator
* F4 : paste text from clipboard
* F5 : zoom out down to 1:1 pixels
* F6 : zoom in, no magnification limit
* F7/F8 : adjust joystick trim
* F9 : mute / un-mute sound
* F10 : monochrome / color display (only in HGR mode)
* F11 : reset
* CTRL-F11 : break
* F3 : zoom out down to 1:1 pixels
* F4 : zoom in, no magnification limit
* F5 : reduce joystick trim
* F6 : increase joystick trim
* F7 : paste text from clipboard
* F8 : mute / un-mute sound
* F9 : monochrome / color display (only in HGR mode)
* F10 : pause / un-pause the emulator
* F11 : reset / CTRL-F11 : break
* F12 : quit the emulator
Paddles / Joystic :
Paddles / Joystick :
* numpad 1 : left
* numpad 3 : right
* numpad 5 : up
* numpad 2 : down
* numpad 3 : up
* CTRL : button 0
* ALT : button 1
* SHIFT : button 2 (allow applications to use the shift mod)
```
### Limitations
* high pitch noise at high volume on windows (Linux Ubuntu tested OK)
* ~~high pitch noise at high volume on windows (Linux Ubuntu tested OK)~~
* sound cracks when playing for long period (intro music for example)
* CPU is not 100% cycle accurate - see source file for more details
* colors are approximate (taken from a scan of an old Beagle bros. poster)
* ~~HGR video is inaccurate, and does not implement color fringing~~
* disk ][ access is artificially accelerated
* disk ][ access is artificially accelerated - considered as a feature
* only support .nib floppy images. (you can use [CiderPress](https://github.com/fadden/ciderpress) to convert your images to this format)
* only has 48KB of RAM (can't run software requiring the language card)
* and many others ...
### To do
* fix sound cracks
* give a warning if the application exits with unsaved floppy changes
* give the user the option to start with the original Apple II rom
* colors where taken from an old Beagle Bros poster, find more accurate RGB values.
* check for more accurate RGB values.
* ~~implement color fringe effect in HGR~~
* optimize sound generation
* optimize disk access (speed is actually a bit artificial)
* re-implement Paddles and Joystick support for analog simulation
* implement the language card and extend the RAM of **reinette II plus** to 64K to support more software.
* for 6502 coders :
* add the ability to insert a binary file at a specified address
* give the user the option to start with the original Apple II rom
* dump regs, soft switches and specified memory pages to console
Follow me to be updated !
\
\
\

View File

@ -30,7 +30,6 @@
#include "puce6502.h"
//================================================================ SOFT SWITCHES
uint8_t KBD = 0; // 0xC000, 0xC010 ascii value of keyboard input
@ -54,12 +53,13 @@ float trimGC = .24;
double rate = 23.19727891156463; // 1023000 Hz / 44100 Hz (the wavSpec.freq)
bool muted = false; // press F9 to mute/unmute
SDL_AudioDeviceID audioDevice;
Sint8 audioBuffer[2][audioBufferSize] = {0}; // see main() for more details
Sint8 audioBuffer[2][audioBufferSize] = {0}; // see main() for more details
//====================================================================== DISK ][
uint8_t slot6[256] = {0}; // P5A disk ][ PROM in slot 6
int curDrv = 0; // only one can be enabled at a time
struct drive{
char filename[512]; // the full disk image path
@ -71,8 +71,6 @@ struct drive{
uint16_t nibble; // ptr to nibble under head position
} disk[2] = {0}; // two disk ][ drive units
int curDrv = 0; // only one can be enabled at a time
int insertFloppy(SDL_Window *wdo, char *filename, int drv){
int i, a, b;
@ -113,6 +111,19 @@ int insertFloppy(SDL_Window *wdo, char *filename, int drv){
return(1);
}
int saveFloppy(int drive){
if (disk[drive].filename[0] && !disk[drive].readOnly){
FILE *f = fopen(disk[drive].filename, "wb");
if (f){
if (fwrite(disk[drive].data, 1, 232960, f) != 232960){
printf("Write failed\n");
return(0);
}
fclose(f);
}
}
return(1);
}
void stepMotor(uint16_t address){
static bool phases[2][4] = {0}; // phases states (for both drives)
@ -244,7 +255,7 @@ int main(int argc, char *argv[]){
int zoom = 2;
const float frameDelay = 1000/60; // targeting 60 FPS
float fps = 60;
Uint32 frameStart = 0, frameTime = 0, frame = 0, reftime = 0, blink = 0;
Uint32 frameStart = 0, frameTime = 0, frame = 0, reftime = 0;
SDL_Event event;
bool paused = false, running = true, ctrl, shift, alt;
@ -258,9 +269,9 @@ int main(int argc, char *argv[]){
SDL_Window *wdo = SDL_CreateWindow("reinette II+", SDL_WINDOWPOS_CENTERED, \
SDL_WINDOWPOS_CENTERED, 280*zoom, 192*zoom, SDL_WINDOW_OPENGL);
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_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_Renderer *rdr = SDL_CreateRenderer(wdo, -1, SDL_RENDERER_ACCELERATED); // | SDL_RENDERER_PRESENTVSYNC);
SDL_SetRenderDrawBlendMode(rdr, SDL_BLENDMODE_NONE); // SDL_BLENDMODE_BLEND);
@ -294,12 +305,13 @@ int main(int argc, char *argv[]){
uint16_t previousDots[192][40] = {0}; // check which Hi-Res 7 dots needs redraw
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 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;
uint8_t glyph; // a TEXT character, or 2 blocks in GR
bool blink = true; // cursor blinking
uint8_t colorIdx = 0; // to index the color arrays
bool monochrome = false;
uint16_t vRamBase = 0x0400; // can be 0x0400, 0x0800, 0x2000 or 0x4000
enum characterAttribute {A_NORMAL, A_INVERSE, A_FLASH} glyphAttribute;
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
@ -318,7 +330,7 @@ int main(int argc, char *argv[]){
{151, 88, 34}, {234, 108, 21}, {158, 151,143}, {255, 206, 240},
{144, 192, 49}, {255, 253, 166}, {159, 210,213}, {255, 255, 255}};
const int hcolor[16][3] = { // the high res colors (2 lights)
const int hcolor[16][3] = { // the high res colors (2 light levels)
{ 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}, { 63, 55, 86}, { 72, 96, 25}, {255, 255, 255},
@ -434,60 +446,39 @@ int main(int argc, char *argv[]){
}
if (event.type == SDL_KEYDOWN) // a key has been pressed
switch (event.key.keysym.sym){
// EMULATOR CONTROL :
case SDLK_F1: // save disk 0 back to host
if (disk[0].filename[0] && !disk[0].readOnly){
f = fopen(disk[0].filename, "wb");
if (f){
if (fwrite(disk[0].data, 1, 232960, f) != 232960){
printf("Write failed\n");
}
fclose(f);
}
}
break;
case SDLK_F1: saveFloppy(0); break; // save disk 0 back to host
case SDLK_F2: saveFloppy(1); break; // save disk 1 back to host
case SDLK_F2: // save disk 1 back to host
if (disk[1].filename[0] && !disk[1].readOnly){
f = fopen(disk[1].filename, "wb");
if (f){
if (fwrite(disk[1].data, 1, 232960, f) != 232960){
printf("Write failed\n");
}
fclose(f);
}
}
break;
case SDLK_F3: paused = !paused; break; // pause / un-pause
case SDLK_F4: // paste txt from clipboard
if (SDL_HasClipboardText()){
char *clipboardText = SDL_GetClipboardText();
int c = 0;
while (clipboardText[c]){ // all chars until ascii NUL
KBD = clipboardText[c++] | 0x80; // set bit7
if (KBD == 0x8A) KBD = 0x8D; // Line Feed to Carriage Ret
puce6502Exec(400000); // to process each char
}
SDL_free(clipboardText);
}
break;
case SDLK_F5: if ((zoom-=2) < 0) zoom = 0; // zoom out
case SDLK_F6: if (++zoom > 8) zoom = 8; // zoom in
case SDLK_F3: if ((zoom-=2) < 0) zoom = 0; // zoom out
case SDLK_F4: if (++zoom > 8) zoom = 8; // zoom in
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_F8: trimGC += .01; break; // PDL Trim
case SDLK_F5: trimGC -= .01; break; // PDL Trim
case SDLK_F6: trimGC += .01; break; // PDL Trim
case SDLK_F9: muted = !muted; break; // mute
case SDLK_F10: monochrome = !monochrome; break; // ...
case SDLK_F7: // paste txt from clipboard
if (SDL_HasClipboardText()){
char *clipboardText = SDL_GetClipboardText();
int c = 0;
while (clipboardText[c]){ // all chars until ascii NUL
KBD = clipboardText[c++] | 0x80; // set bit7
if (KBD == 0x8A) KBD = 0x8D; // Line Feed to Carriage Ret
puce6502Exec(400000); // to process each char
}
SDL_free(clipboardText);
}
break;
case SDLK_F8: muted = !muted; break; // mute
case SDLK_F9: monochrome = !monochrome; break; // ...
case SDLK_F10: paused = !paused; break; // pause / un-pause
case SDLK_F12: running = false; break; // goodbye
case SDLK_F11: // reset
if (ctrl)
@ -499,8 +490,6 @@ int main(int argc, char *argv[]){
}
break;
case SDLK_F12: running = false; break; // goodbye
// EMULATED KEYS :
case SDLK_ESCAPE: KBD = 0x9B; break; // ESC
@ -592,7 +581,7 @@ int main(int argc, char *argv[]){
word = (uint16_t)(ram[ vRamBase + offsetHGR[line] + col + 1 ]) << 8; // put the two next bytes into one word (in reverse order)
word += ram[ vRamBase + offsetHGR[line] + col ];
// check if this group of 7 dots need a redraw (ie was modified)
if (previousDots[line][col] != word || !blink){ // or refresh the full screen every 1/2 second (everytime blink is reset to 0)
if (previousDots[line][col] != word || !frame){ // or refresh the full screen every 1 second
for (bit=0; bit<16; bit++) bits[bit] = (word >> bit) & 1; // store all bits of the word into the 'bits' array
@ -680,7 +669,7 @@ int main(int argc, char *argv[]){
if (glyph > 0x5F) glyph &= 0x3F; // shifts to match
if (glyph < 0x20) glyph |= 0x40; // the ASCII codes
if (glyphAttribute == A_NORMAL || blink < 15)
if (glyphAttribute == A_NORMAL || blink)
SDL_RenderCopy(rdr, normCharTexture, &charRects[glyph], &dstRect);
else
SDL_RenderCopy(rdr, revCharTexture, &charRects[glyph], &dstRect);
@ -708,15 +697,14 @@ int main(int argc, char *argv[]){
} // else, skip frame
frame++;
if (frameStart > reftime + 1000){
if (frame > 30) blink = false;
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();
frame = 0;
blink = true;
}
if (++blink == 30) blink = 0;
} // while (running)
//================================================ RELEASE RESSOURSES AND EXIT