mirror of
https://github.com/ArthurFerreira2/reinette-II-plus.git
synced 2024-12-11 14:49:28 +00:00
Function keys updated
This commit is contained in:
parent
3a79269dc0
commit
8cd9263453
51
README.md
51
README.md
@ -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 !
|
||||
\
|
||||
\
|
||||
\
|
||||
|
124
reinetteII+.c
124
reinetteII+.c
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user