Add files via upload

This commit is contained in:
ArthurFerreira2 2019-03-25 23:30:20 +01:00 committed by GitHub
parent a3a54577cc
commit 99b540bd75
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 47 additions and 62 deletions

View File

@ -1,5 +1,5 @@
all:reinette-II all:reinette-II
reinette-II:reinette-II.c reinette-II:reinette-II.c
gcc -Wall -O3 reinette-II.c -o reinette-II -lncurses gcc -Wall -Werror -O3 reinette-II.c -o reinette-II -lncurses

View File

@ -1,21 +1,18 @@
# reinette-II # reinette-II
The french Apple II emulator The french Apple II emulator
A simple Apple II emulator in about 600 lines of code ! A simple Apple II emulator in less 600 lines of C !
Based on reinette, the french Apple 1 emulator ( https://github.com/ArthurFerreira2/reinette ) Based on reinette, the french Apple 1 emulator ( https://github.com/ArthurFerreira2/reinette )
Only supports text, page 1 - No sound, no joystick, no card support and thus no disk support Very limited hardware support : only supports text, page 1
Runs Applesoft II and monitor from ROM runs either the original Apple II ROM with Interger Basic and the Programmers Aid at $D000 or the later Applesoft II ROM : just change the filename at line 548.
Requires ncurses. To be run in a terminal at least 41x26
- F9 : reset Requires ncurses. Meant to be run in a terminal at least 41x25
- F10 : break
- F7 : reset
- F12 : exit - F12 : exit
Uncomment lines 566-567 to display some debug info
Comment line 569 to go full speed
Have fun ! Have fun !

BIN
appleII+.rom Normal file

Binary file not shown.

BIN
appleII.rom Normal file

Binary file not shown.

BIN
reinette-II Normal file

Binary file not shown.

View File

@ -23,7 +23,6 @@
THE SOFTWARE. THE SOFTWARE.
*/ */
#include <stdlib.h>
#include <ncurses.h> #include <ncurses.h>
#include <unistd.h> // for usleep() #include <unistd.h> // for usleep()
@ -53,8 +52,8 @@ struct Register{
uint16_t PC; uint16_t PC;
}reg; }reg;
uint8_t key; uint8_t key = 0;
bool videoNeedsRefresh; bool videoNeedsRefresh = true;
// MEMORY AND I/O // MEMORY AND I/O
@ -66,7 +65,7 @@ static uint8_t readMem(uint16_t address){
else if (address >= ROMSTART) return(rom[address - ROMSTART]); else if (address >= ROMSTART) return(rom[address - ROMSTART]);
else if (address == 0xC000) { // KBD else if (address == 0xC000) { // KBD
if (! ++queries) usleep(100); // sleep 100ms every 256 requests if (!queries++) usleep(100); // sleep 100ms every 256 requests
return(key); return(key);
} }
else if (address == 0xC010){ // KBDSTRB else if (address == 0xC010){ // KBDSTRB
@ -77,9 +76,8 @@ static uint8_t readMem(uint16_t address){
} }
static void writeMem(uint16_t address, uint8_t value){ static void writeMem(uint16_t address, uint8_t value){
if (address>=0x400 && address<=0x7FF) videoNeedsRefresh = true; if (address & 0x400) videoNeedsRefresh = true;
if (address < RAMSIZE) ram[address] = value; if (address < RAMSIZE) ram[address] = value;
else if (address == 0xC010) key &= 0x7F; // KBDSTRB, similar as in readMem else if (address == 0xC010) key &= 0x7F; // KBDSTRB, similar as in readMem
} }
@ -107,7 +105,7 @@ uint8_t pull(){
} }
static void setSZ(uint8_t value){ // update both the Sign & Zero FLAGS static void setSZ(uint8_t value){ // update both the Sign & Zero FLAGS
if (value & 0x00FF) reg.SR &= ~ZERO; if (value) reg.SR &= ~ZERO;
else reg.SR |= ZERO; else reg.SR |= ZERO;
if (value & 0x80) reg.SR |= SIGN; if (value & 0x80) reg.SR |= SIGN;
else reg.SR &= ~SIGN; else reg.SR &= ~SIGN;
@ -523,7 +521,7 @@ static void (*addressing[])(void) = {
REL, IDY, IMP, IMP, IMP, ZPX, ZPX, IMP, IMP, ABY, IMP, IMP, IMP, ABX, ABX, IMP REL, IDY, IMP, IMP, IMP, ZPX, ZPX, IMP, IMP, ABY, IMP, IMP, IMP, ABX, ABX, IMP
}; };
static int baseForLines[24] = { // helper for video generation static int offsetsForRows[24] = { // helper for video generation
0x400, 0x480, 0x500, 0x580, 0x600, 0x680, 0x700, 0x780, 0x400, 0x480, 0x500, 0x580, 0x600, 0x680, 0x700, 0x780,
0x428, 0x4A8, 0x528, 0x5A8, 0x628, 0x6A8, 0x728, 0x7A8, 0x428, 0x4A8, 0x528, 0x5A8, 0x628, 0x6A8, 0x728, 0x7A8,
0x450, 0x4D0, 0x550, 0x5D0, 0x650, 0x6D0, 0x750, 0x7D0 0x450, 0x4D0, 0x550, 0x5D0, 0x650, 0x6D0, 0x750, 0x7D0
@ -533,9 +531,8 @@ static int baseForLines[24] = { // helper for video generation
// PROGRAM ENTRY POINT // PROGRAM ENTRY POINT
int main(int argc, char *argv[]) { int main(int argc, char *argv[]) {
int ch = 0; uint8_t opcode, glyph;
uint8_t opcode = 0; int ch;
uint8_t character = 0;
// ncurses initialization // ncurses initialization
initscr(); initscr();
@ -543,12 +540,12 @@ int main(int argc, char *argv[]) {
noecho(); noecho();
curs_set(0); curs_set(0);
qiflush(); qiflush();
keypad (stdscr, TRUE); keypad (stdscr, TRUE);
nodelay (stdscr, TRUE); nodelay (stdscr, TRUE);
scrollok(stdscr, TRUE); scrollok (stdscr, TRUE);
// load the ROM // load the original Apple][ ROM, including the Programmer's Aid at $D000
FILE *f=fopen("apple2.rom","rb"); FILE *f=fopen("appleII.rom","rb");
if (f != NULL) fread(rom, sizeof(uint8_t), ROMSIZE, f); if (f != NULL) fread(rom, sizeof(uint8_t), ROMSIZE, f);
fclose(f); fclose(f);
@ -561,52 +558,43 @@ int main(int argc, char *argv[]) {
opcode = readMem(reg.PC++); // FETCH and increment the Program Counter opcode = readMem(reg.PC++); // FETCH and increment the Program Counter
addressing[opcode](); // DECODE operands against the addressing mode addressing[opcode](); // DECODE operands against the addressing mode
instruction[opcode](); // EXECUTE the instruction instruction[opcode](); // EXECUTE the instruction
// DEBUG : print registers values and keypressed
//move(25,0); // at bottom of screen
//printw("PC-%04X A-%02X X-%02X Y-%02X S-%02X P-%02X KEY-%02X",reg.PC ,reg.A, reg.X, reg.Y, reg.SP, reg.SR, key);
} }
usleep(225); // 225ms for 100 instructions gives roughly the original speed
// slow down emulation - so you can hit thoses colored monsters
usleep(160);
// keyboard controller // keyboard controller
if (key < 0x80 && (ch = getch()) != ERR){ // non blocking read if ((ch = getch()) != ERR){
if (ch == KEY_F( 9)) reset(); // F09, reset if (ch == KEY_F( 7)) reset(); // F7, reset
else if (ch == KEY_F(10)) BRK(); // F10, break if (ch == KEY_F(12)) { endwin(); return(0); } // F12, exit program
else if (ch == KEY_F(12)) { // F12, exit program switch(key=(uint8_t)ch){ // key translations
endwin(); // reset terminal case 0x0A: key = 0x0D; break; // LF to CR
exit(0); // and terminate case 0x04: key = 0x08; break; // LEFT to BS
} case 0x05: key = 0x15; break; // RIGHT to NAK
else { // the key is sent to the emulator after some translations case 0x07: key = 0x08; break; // BELL to BS ?
switch(key=(uint8_t)ch){
case 0x0A: key = 0x0D; break; // LF to CR
case 0x04: key = 0x08; break; // LEFT to BS
case 0x05: key = 0x15; break; // RIGHT to LF
case 0x07: key = 0x08; break; // BELL to BS
}
key |= 0x80; // set bit 7
} }
if ((key > 0x60) && (key < 0x7B)) key -= 0x20; // to upper case
key |= 0x80; // set bit 7
} }
// video controller only supports page 1 text mode // video controller - supports only page 1 text mode
if (videoNeedsRefresh){ // content changed if (videoNeedsRefresh){ // if content changed
move(0, 0); move(0, 0);
for(int line=0; line<24; line++){ // for each row for(int row=0; row<24; row++){ // for each row
for(int col=0; col<40; col++){ // for each column for(int col=0; col<40; col++){ // for each column
character = ram[baseForLines[line]+col]; // read video memory glyph = ram[offsetsForRows[row] + col]; // read video memory
if (character == '`') character = '_'; // change cursor if (glyph == '`') glyph = '_'; // change cursor shape
if (character < 0x40) attrset(A_REVERSE); // is REVERSE ? if (glyph < 0x40) attrset(A_REVERSE); // is REVERSE ?
else if (character > 0x7F) attrset(A_NORMAL); // is NORMAL ? else if (glyph > 0x7F) attrset(A_NORMAL); // is NORMAL ?
else attrset(A_BLINK); // is FLASHING ? else attrset(A_BLINK); // it's FLASHING !
character &= 0x7F; // unset bit 7 glyph &= 0x7F; // unset bit 7
if (character > 0x5F) character &= 0x3F; // shifts to obtain if (glyph > 0x5F) glyph &= 0x3F; // shifts to match
if (character < 0x20) character |= 0x40; // the ASCII codes if (glyph < 0x20) glyph |= 0x40; // the ASCII codes
printw("%c", character); // print character addch(glyph); // print the glyph
} }
printw("%c", 0x0A); // carriage return addch(0x0A); // to next row
} }
videoNeedsRefresh = false; videoNeedsRefresh = false;
attrset(A_NORMAL);
} }
} }
} }