BBC Basic in Z80 emulation on the mbed, USB serial terminal output only. LOAD and SAVE work on the local file system but there is no error signalling.

Dependencies:   mbed

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers main.cpp Source File

main.cpp

00001 /* BBC Basic emulator on NXP mbed by Gert van der Knokke
00002  * Emulation of the Z80 CPU
00003  * The z80 emulator is heavily modified by me (Gert)
00004  * original Copyright (C) 1994 Ian Collier.
00005  *
00006  * This program is free software; you can redistribute it and/or modify
00007  * it under the terms of the GNU General Public License as published by
00008  * the Free Software Foundation; either version 2 of the License, or
00009  * (at your option) any later version.
00010  *
00011  * This program is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  * GNU General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU General Public License
00017  * along with this program; if not, write to the Free Software
00018  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
00019  */
00020 
00021 #include "mbed.h"
00022 #include "module.h"
00023 #include "z80.h"
00024 
00025 #define DEBUG false
00026 
00027 // define serial port for debug
00028 Serial linktopc(USBTX,USBRX);
00029 
00030 
00031 // VDU queue
00032 unsigned char vdu_queue[256];   // a somewhat large queue
00033 unsigned char queue_bytes=0;    // vdu queue pointer
00034 unsigned char oldchar;          // which VDU function needs the queue
00035 
00036 volatile unsigned char flag,oldy=0;
00037 
00038 
00039 int background_color;   // for clear screen
00040 int cursor_xpos;
00041 int cursor_ypos;
00042 int last_line_processed;
00043 int previous_line_found;
00044 
00045 int current_background_color;
00046 int current_text_color;
00047 
00048 
00049 // prepare mbed storage for local use
00050 LocalFileSystem local("local");               // Create the local filesystem under the name "local"
00051 
00052 // clear the screen
00053 void cls() {
00054     putchar(0x0c);
00055 }
00056 
00057 // dummy function
00058 void set_cursor_position() {
00059 }
00060 
00061 // home cursor
00062 void home_cursor() {
00063     cursor_xpos=0x00;  // ypos
00064     cursor_ypos=0x00;  // xpos
00065     set_cursor_position();
00066 }
00067 
00068 // prepare the screen
00069 void init_screen() {
00070     current_background_color=0;  // set initial background color
00071     current_text_color=7;  // initial text color attributes
00072     cls();
00073     home_cursor();
00074 }
00075 
00076 // handle VDU calls after all bytes are in queue
00077 // Note! queue is working front to back (255 is first, 0 is last)
00078 void do_handle_queue(unsigned char code) {
00079     switch (code) {
00080         case 0x11:  // select text color
00081             current_text_color=vdu_queue[255];
00082             break;
00083         case 0x16:  // Mode
00084             current_text_color=7;
00085             current_background_color=0;
00086             init_screen();
00087             home_cursor();
00088             break;
00089         case 0x17:  // define character n
00090             break;
00091         case 0x1f:  // move cursor to x,y
00092             cursor_xpos=vdu_queue[254];
00093             cursor_ypos=vdu_queue[255];
00094             set_cursor_position();
00095             break;
00096     }
00097 }
00098 
00099 // VDU OSWRCHR
00100 // this routine evaluates the stream characters
00101 // and prepares the queue if needed
00102 void printchar(unsigned char ch) {
00103 
00104     // do we need more queue bytes ?
00105     if (queue_bytes) {
00106         vdu_queue[queue_bytes++]=ch;
00107         // all bytes in queue, now handle the call
00108         if (queue_bytes==0)
00109             do_handle_queue(oldchar);
00110 
00111     } else {
00112 
00113         switch (ch) {
00114             case 0x00:  // NULL
00115                 break;
00116             case 0x08:  // CURSOR LEFT
00117                 putchar(0x08);
00118                 if (cursor_xpos>0) {
00119                     cursor_xpos--;
00120                     set_cursor_position();
00121                 }
00122                 break;
00123             case 0x09:  // CURSOR RIGHT
00124                 if (cursor_xpos<39) {
00125                     cursor_xpos++;
00126                     set_cursor_position();
00127                 }
00128                 break;
00129             case 0x0a:  // CURSOR DOWN
00130                 if (cursor_ypos<23) {
00131                     cursor_ypos++;
00132                     set_cursor_position();
00133                 } else {
00134                     cursor_ypos=23;
00135                 }
00136                 break;
00137             case 0x0b:  // CURSOR UP
00138                 cursor_ypos++;
00139                 if (cursor_ypos>0) {
00140                     cursor_ypos--;
00141                     set_cursor_position();
00142                 } else {
00143                     cursor_ypos=0;
00144                 }
00145                 break;
00146             case 0x0d:  // Carriage Return
00147                 cursor_xpos=0;
00148                 putchar(0x0d);
00149                 putchar(0x0a);
00150                 set_cursor_position();
00151                 break;
00152             case 0x0c:  // CLEAR TEXT WINDOW
00153             case 0x10:  // CLEAR GRAPHIC WINDOW
00154                 cls();
00155                 cursor_xpos=0;
00156                 cursor_ypos=0;
00157                 set_cursor_position();
00158                 break;
00159             case 0x11:    // set TEXT color
00160                 oldchar=ch;         // this was the code of the initial call
00161                 queue_bytes=256-1;      // for this call we need one more byte
00162                 break;
00163             case 0x14:    // reset colors
00164                 current_text_color=7;
00165                 current_background_color=0;
00166                 break;
00167             case 0x16:  // MODE select
00168                 oldchar=ch;
00169                 queue_bytes=256-1;
00170                 break;
00171             case 0x17:  // define character n
00172                 break;
00173             case 0x1e:
00174                 cursor_xpos=0;
00175                 cursor_ypos=0;
00176                 set_cursor_position();
00177                 break;
00178             case 0x1f:              // set cursor to position X,Y
00179                 oldchar=ch;         // this was the code of the initial call
00180                 queue_bytes=256-2;      // for this call we need two more bytes
00181                 break;
00182                 // all else is put on screen literally
00183             default:
00184                 putchar(ch);
00185                 break;
00186         }
00187     }
00188 }
00189 
00190 
00191 void init_ramtop() {
00192 
00193 
00194     // set all MOS calls to illegal opcode 0xed55
00195     // that code is trapped by a mbed routine
00196     wrmem(OSWRCH,0xed);
00197     wrmem(OSWRCH+1,0x55);
00198 
00199     wrmem(OSWORD,0xed);
00200     wrmem(OSWORD+1,0x55);
00201 
00202     wrmem(OSBYTE,0xed);
00203     wrmem(OSBYTE+1,0x55);
00204 
00205     wrmem(OSRDCH,0xed);
00206     wrmem(OSRDCH+1,0x55);
00207 
00208     wrmem(OSNEWL,0xed);
00209     wrmem(OSNEWL+1,0x55);
00210 
00211     wrmem(OSASCI,0xed);
00212     wrmem(OSASCI+1,0x55);
00213 
00214     wrmem(OSRDCH,0xed);
00215     wrmem(OSRDCH+1,0x55);
00216 
00217     wrmem(MAINVDU,0xed);
00218     wrmem(MAINVDU+1,0x55);
00219 
00220     wrmem(GSINIT,0xed);
00221     wrmem(GSINIT+1,0x55);
00222 
00223     wrmem(GSREAD,0xed);
00224     wrmem(GSREAD+1,0x55);
00225 
00226     wrmem(OSRDRM,0xed);
00227     wrmem(OSRDRM+1,0x55);
00228 
00229     wrmem(OSEVEN,0xed);
00230     wrmem(OSEVEN+1,0x55);
00231 
00232     wrmem(OSCLI,0xed);
00233     wrmem(OSCLI+1,0x55);
00234 
00235     wrmem(OSFILE,0xed);
00236     wrmem(OSFILE+1,0x55);
00237 
00238     wrmem(CMDPTR,0xf0); // pointer to CR terminated string (auto start filename)
00239     wrmem(CMDPTR+1,0x00); // it is set here to 0x00f0
00240 
00241     wrmem(BRKV,0x00);   // break vector
00242     wrmem(BRKV+1,0x00);
00243 
00244     wrmem(FAULT,0x38);  // fault vector
00245     wrmem(FAULT+1,0x00);
00246 }
00247 
00248 unsigned char getkey() {
00249     unsigned char key=0x00;
00250     if (linktopc.readable())        // get USB status
00251         key=linktopc.getc();        // get ASCII key
00252     return key;
00253 }
00254 
00255 // crude getline routine
00256 void mygets(int ad,int max,unsigned char minasc,unsigned char maxasc) {
00257     int n=0;
00258     int key=0;
00259 
00260     bool eflag=1;
00261 
00262     // show cursor
00263     set_cursor_position();
00264 
00265     while (eflag) {
00266 //        key=getkey();
00267 #if !DEBUG
00268         // USB serial data ? then override key  (only when NOT in debug mode)
00269         if (linktopc.readable())        // get USB status
00270             key=linktopc.getc();        // get ASCII key code
00271         else key=0;
00272         // key=getchar();  // BLOCKING MODE
00273 #endif
00274 
00275         if (key)    // printf("got key code: %02x\n\r",key);
00276 
00277             // only ASCII should arrive here
00278             switch (key) {
00279                 case 0x00:  // no key
00280                     break;
00281                 case 0x0d:  // Enter or Return
00282                     wrmem(ad+n,key);
00283                     h=n;
00284                     // clear carry flag
00285                     anda(a); // z80 way of clearing carry...
00286                     eflag=0; // terminate the loop
00287                     printchar(key);
00288                     printchar(0x0a);
00289                     break;
00290                 case 0x1b:    // Escape
00291                     wrmem(ad+n,key);
00292                     // set carry flag
00293                     f=(f&0xc4)|1|(a&0x28);
00294                     eflag=0;
00295                     h=n;
00296                     break;
00297                 case 0x15:    // CTRL-U (clear input)
00298                     while (n) {
00299 
00300                         printchar(0x08);
00301                         printchar(0x20);
00302                         printchar(0x08);
00303                         n--;
00304                     }
00305                     wrmem(ad,0x0d);
00306                     break;
00307                 case 0x7f:   // DELETE
00308                     if (n) {
00309                         n--;
00310                         printchar(0x08);    // cursor left
00311                         printchar(0x20);    // delete character by printing a space
00312                         printchar(0x08);    // cursor left
00313                         wrmem(ad+n,0x20);   // overwrite with space
00314                     }
00315                     break;
00316                 default:    // all else
00317                     // keep within maximum lenght and given ascii limits
00318                     if ((key>=minasc) && (key<=maxasc) && n<max) {
00319                         wrmem(ad+n,key);
00320                         n++;
00321                         printchar(key);
00322                     }
00323                     break;
00324             }
00325     }
00326 }
00327 
00328 
00329 // OSWORD
00330 void do_osword() {
00331     int ad,n;
00332     char buf[40];
00333     time_t seconds;
00334 
00335     // printf("OSWORD called with PC=%04x A=%02x HL=%02x%02x\n\r",pc,a,h,l);
00336     switch (a) {
00337 
00338         case 0x00:  // get a line from the keyboard/input channel
00339             ad=(h<<8)+l;
00340 //        printf("Control block:\n\r");
00341 //        printf("buffer address %02x%02x\n\r",rdmem(ad+1),rdmem(ad));
00342 //        printf("maximum length: %d\n\r",rdmem(ad+2));
00343 //        printf("minimum ASCII value %d\n\r",rdmem(ad+3));
00344 //        printf("maximum ASCII value %d\n\r",rdmem(ad+4));
00345 
00346             mygets((rdmem(ad+1)<<8)+rdmem(ad),rdmem(ad+2),rdmem(ad+3),rdmem(ad+4));
00347 
00348             break;
00349         case 0x01:  // read systemclock (long integer)
00350             break;
00351         case 0x02:  // write systemclock (long integer)
00352             break;
00353         case 0x07:  // emit a sound from the sound library (0-7)
00354             break;
00355         case 0x0e:  // read TIME$ (not present in original BBC Basic)
00356             ad=hl;              // get pointer to function number
00357             switch (rdmem(hl)) { // select function number
00358                 case 0:     // return time string
00359                     seconds = time(NULL);   // get current time from mbed RTC
00360                     strftime(buf,40, "%a,%d %m %Y.%H:%M:%S\r", localtime(&seconds));   // write to temporary buffer
00361                     n=0;
00362                     while (buf[n]) wrmem(ad++,buf[n++]);    // copy to pointer from HL
00363                     break;
00364                 case 1:     // return BCD values of clock
00365                     // On exit:
00366                     //  XY?0=year (&00-&99)
00367                     //  XY?1=month (&01-&12)
00368                     //  XY?2=date (&01-&31)
00369                     //  XY?3=day of week (&01-&07, Sun-Sat)
00370                     //  XY?4=hours (&00-&23)
00371                     //  XY?5=minutes (&00-&59)
00372                     //  XY?6=seconds (&00-&59).
00373                     //
00374                     // A year value of &80-&99 represents 1980-1999, a value of
00375                     // &00-&79 represents 2000-2079.
00376                     //
00377                     break;
00378                 case 2:     // Convert BCD to string.
00379                     // On entry:
00380                     //  XY+1..7=BCD value
00381                     // On exit:
00382                     // XY+1..25=CR-terminated string
00383                     break;
00384             }
00385             break;
00386         case 0x0f:  // write TIME$ (not present in original BBC Basic)
00387             //        On entry:
00388             // XY?0=function code
00389             // XY+1.. value to use.
00390             // Functions are:
00391             // 8 - Set time to value in format "HH:MM:SS"
00392             // 16 - Set date to value in format "Day,DD Mon Year"
00393             // 24 - Set time and date to value in format
00394             // "Day,DD Mon Year.HH:MM:SS"
00395             n=0;
00396             ad=hl;
00397             // printf(" write time$ function %d\n\r",rdmem(ad));
00398             ad++;
00399             while (rdmem(ad)!=0x0d) buf[n++]=rdmem(ad++);  // copy timestring to buffer
00400             buf[n]=0;
00401             // printf("trying to set time from %s\n\r",buf);
00402             break;
00403     }
00404 }
00405 
00406 // OSBYTE
00407 // on 6502 A register and X,Y are used for Low,High parameters
00408 // Z80 uses L and H  (so X=L and H=Y <-> L=X and Y=H)
00409 void do_osbyte() {
00410     unsigned char temp;
00411 
00412     // printf("OSBYTE called with PC=%04x A=%02x H=%02x L=%02x\n\r",pc,a,h,l);
00413     switch (a) {
00414         case 0x00:      // NULL
00415             l=0xff;
00416             break;
00417         case 0x13:      // ASCII 19
00418             break;
00419         case 0x7c:    // clear ESCAPE state
00420             wrmem(0xff80,rdmem(0xff80)&0x7f);
00421             break;
00422         case 0x7d:    // set ESCAPE state
00423             wrmem(0xff80,rdmem(0xff80)|0x80);
00424             break;
00425         case 0x7e:    // acknowledge ESCAPE state ? (CLOSE ALL!)
00426             wrmem(0xff80,rdmem(0xff80)&0x7f);
00427             break;
00428         case 0x7f:    // read EOF on channel
00429             l=0x01;
00430             break;
00431         case 0x80:    // read ADVAL(hl)
00432             h=0;
00433             l=0;
00434             break;
00435         case 0x81:    // read key within time limit 'hl' centiseconds
00436             temp=hl;        // get timeout value (100th seconds)
00437             do {
00438                 l=getkey();
00439                 wait(0.01);
00440             } while ((temp--) && (!l));
00441 
00442             if (l) {    // we got a key
00443                 if (l==0x1b) { // Escape ?
00444                     f=(f&0xc4)|1|(a&0x28);  // set carry
00445                     h=0x1b;
00446                 } else {
00447                     anda(a); // clear carry
00448                     h=0x00; // clear h
00449                 }
00450             } else {    // timeout
00451                 f=(f&0xc4)|1|(a&0x28);  // set carry
00452                 h=0xff;                 // signal no key
00453             }
00454             break;                     // scan keyboard etc
00455         case 0x82:
00456             h=l=0;
00457             break;                              // Machine high order address
00458         case 0x83:
00459             h=PAGE>>8;
00460             l=(PAGE & 0xff);
00461             break;                       // lowest available memory address (PAGE)
00462         case 0x84:  // highest available memory address (HIMEM)
00463             h=RAMEND>>8;
00464             l=RAMEND & 0xff;
00465             break;
00466         case 0x85:  // read bottom of display RAM for a specific mode
00467             h=0x80;
00468             l=0x00;
00469             break;
00470         case 0x86:    // return H=VPOS, L=POS
00471             h=cursor_ypos;
00472             l=cursor_xpos;
00473             break;
00474         case 0x87:  // L=character on screen at cursor position
00475             h=7;
00476             l=0;
00477             break;
00478         case 0xda:    // read/write the number of items in the VDU queue
00479             // on return H contains the new value, L the old
00480             temp=queue_bytes;
00481             queue_bytes=(queue_bytes & h)^l;
00482             h=queue_bytes;
00483             l=temp;
00484             break;   // read/write the number of items in the VDU queue
00485     }
00486 //   show_registers();
00487 //   wait(0.1);
00488 }
00489 
00490 void do_osreadchar() {
00491     a=getchar();
00492     // test for ESCAPE
00493     if (a==27) {
00494         f=(f&0xc4)|1|(a&0x28);
00495         wrmem(0xff80,rdmem(0xff80)|0x80);
00496     }
00497 }
00498 
00499 void do_osnewline() {
00500     printchar(0x0a);
00501     printchar(0x0d);
00502     a=0x0d;
00503 }
00504 
00505 void do_osasci() {
00506     if (a==0x0d) do_osnewline();
00507     else printchar(a);
00508 }
00509 
00510 void do_mainvdu() {
00511     printchar(a);
00512 }
00513 
00514 void do_gsinit() {
00515     printf("GSINIT called with PC=%04x A=%02x\n\r",pc,a);
00516 }
00517 
00518 void do_gsread() {
00519 }
00520 
00521 void do_osrdrm() {
00522     printf("OSRDRM called with PC=%04x A=%02x H=%02x L=%02x\n\r",pc,a,h,l);
00523 }
00524 
00525 void do_oseven() {
00526     printf("OSEVEN called with PC=%04x A=%02x H=%02x L=%02x\n\r",pc,a,h,l);
00527 }
00528 
00529 void do_oscli() {
00530     printf("OSCLI called with PC=%04x A=%02x H=%02x L=%02x\n\r",pc,a,h,l);
00531     do {
00532         a=rdmem((h<<8)+l);
00533         if (!++l)h++;
00534         putchar(a);
00535     } while (a!=0x0d);
00536 }
00537 
00538 void do_osfile() {
00539     char buffer[200];
00540     int n=0;
00541     FILE *fp;
00542     // get address of control block
00543     int controlblock=hl;
00544     int offset=rdmem(controlblock)+(rdmem(controlblock+1)<<8);
00545     // create a kludgy pointer from this offset to the filename
00546     char *filename=(char *)(ram+offset-RAMSTART);
00547     long load_address=rdmem(controlblock+2)+(rdmem(controlblock+3)<<8)+(rdmem(controlblock+4)<<16)+(rdmem(controlblock+5)<<24);
00548     long execution_address=rdmem(controlblock+6)+(rdmem(controlblock+7)<<8)+(rdmem(controlblock+8)<<16)+(rdmem(controlblock+9)<<24);
00549     long start_or_length=rdmem(controlblock+10)+(rdmem(controlblock+11)<<8)+(rdmem(controlblock+12)<<16)+(rdmem(controlblock+13)<<24);
00550     long end_address_or_attributes=rdmem(controlblock+14)+(rdmem(controlblock+15)<<8)+(rdmem(controlblock+16)<<16)+(rdmem(controlblock+17)<<24);
00551 
00552 
00553     // printf("OSFILE called with PC=%04x A=%02x H=%02x L=%02x\n\r",pc,a,h,l);
00554 
00555     // for (n=0; n<=0x11; n++) printf("offset %02x value %02x\n\r",n,rdmem(controlblock+n));
00556 
00557     n=0;
00558     while (filename[n]!=0x0d) n++;
00559     // overwrite 0x0d with end of string
00560     filename[n]=0x00;
00561 
00562     // now determine what to do
00563     switch (a) {
00564         case 0x00: // save a section of memory as a named file
00565             sprintf(buffer,"/local/%s",filename);
00566             // printf("Saving file %s load adr:%08lx exec adr:%08lx start/length%08lx end/attr:%08lx\n\r",filename,load_address,execution_address,start_or_length,end_address_or_attributes);
00567             fp=fopen(buffer, "w");
00568             if (fp) {
00569                 n=start_or_length;
00570                 while (n!=end_address_or_attributes) fputc(rdmem(n++),fp);
00571                 fclose(fp);
00572                 a=1;
00573             } else {
00574                 // printf("could not write %s\n\r",buffer);
00575                 a=0;
00576                 pc=rdmem(0xfffa)+(rdmem(0xfffb)<<8);    // do BRK
00577             }
00578             break;
00579         case 0x01: // write the catalogue information (only) for the named file (disc only)
00580             break;
00581         case 0x02: // write the load address  (only) for the named file (disc only)
00582             break;
00583         case 0x03: // write the execution address  (only) for the named file (disc only)
00584             break;
00585         case 0x04: // write the attributes  (only) for the named file (disc only)
00586             break;
00587         case 0x05: // read the named file's catalogue information, place file type in A (disc only)
00588             break;
00589         case 0x06: // delete the named file (disc only)
00590             break;
00591         case 0xff: // load the named file and read the named file's catalogue information
00592             sprintf(buffer,"/local/%s",filename);
00593             // printf("Loading file %s load adr:%08lx exec adr:%08lx start/length%08lx end/attr:%08lx\n\r",buffer,load_address,execution_address,start_or_length,end_address_or_attributes);
00594             fp = fopen(buffer, "r");
00595             if (fp) {
00596                 n=load_address;
00597                 while (!feof(fp)) wrmem(n++,fgetc(fp));
00598                 fclose(fp);
00599                 a=1;    // file found
00600             } else {
00601                 // printf("Could not open %s\n",buffer);
00602                 a=0;
00603                 pc=rdmem(0xfffa)+(rdmem(0xfffb)<<8);    // do BRK
00604             }
00605             break;
00606     }
00607 }
00608 
00609 void terminalgets(char *buffer) {
00610     int n=0;
00611     int key=0;
00612     do {
00613         key=getchar();
00614         buffer[n]=key;
00615         putchar(key);
00616         if (n<16) n++;
00617     } while (key != 0x0d);
00618     buffer[n]=0;
00619 }
00620 
00621 
00622 // here the OS calls are recognized and
00623 // diverted to the mbed routines.
00624 // this needs to be replaced by native Z80 code
00625 void do_mos() {
00626     //  printf("Entering MOS emulation with PC %04x\n\r",pc);
00627 
00628     // compensate pc for length of ED55 opcode
00629     switch (pc-2) {
00630         case OSBYTE:
00631             do_osbyte();
00632             break;
00633         case OSWORD:
00634             do_osword();
00635             break;
00636         case OSWRCH:
00637             printchar(a);
00638             break;
00639         case OSRDCH:
00640             do_osreadchar();
00641             break;
00642         case OSNEWL:
00643             do_osnewline();
00644             break;
00645         case OSASCI:
00646             do_osasci();
00647             break;
00648         case MAINVDU:
00649             do_mainvdu();
00650             break;
00651         case GSINIT:
00652             do_gsinit();
00653             break;
00654         case GSREAD:
00655             do_gsread();
00656             break;
00657         case OSRDRM:
00658             do_osrdrm();
00659             break;
00660         case OSEVEN:
00661             do_oseven();
00662             break;
00663         case OSCLI:
00664             do_oscli();
00665             break;
00666         case OSFILE:
00667             do_osfile();
00668             break;
00669     }
00670 }
00671 
00672 void listdir(void) {
00673     DIR *d;
00674     struct dirent *p;
00675 
00676     d = opendir("/sd");
00677     if (d != NULL) {
00678         while ((p = readdir(d)) != NULL) {
00679             printf(" - %s\r\n", p->d_name);
00680         }
00681     } else {
00682         printf("Could not open directory!\n");
00683     }
00684     closedir(d);
00685 }
00686 
00687 
00688 
00689 
00690 
00691 // ================================================================
00692 //  main loop
00693 // ================================================================
00694 int  main() {
00695 
00696     // serial port on at 115200 baud
00697     linktopc.baud(115200);
00698     setbuf(stdout, NULL); // no buffering for this filehandle
00699 
00700     // reset all Z80 registers to some initial values
00701     a=f=b=c=d=e=h=l=a1=f1=b1=c1=d1=e1=h1=l1=i=iff1=iff2=im=r=0;
00702     ixoriy=new_ixoriy=0;
00703     ix=iy=sp=pc=0;
00704 
00705     queue_bytes=0;
00706 
00707     // init MOS vectors
00708     init_ramtop();
00709 
00710     init_screen();
00711     home_cursor();
00712 
00713     // endless loop
00714     while (1) {
00715         //    wait(0.01);
00716         r++;
00717         // this is some optimization for the IX and IY opcodes (DD/FD)
00718         ixoriy=new_ixoriy;
00719         new_ixoriy=0;
00720 
00721         // fetch opcode and execute, the include does all the heavy decoding
00722         switch (fetch(pc++)) {
00723 #include "z80ops.h"
00724         }
00725 
00726         // next is the interrupt emulator (only IM1 mode)
00727         // interrupt pending? if new_ixoriy is set or iff1==0 don't do interrupt yet (continue DD/FD opcode)
00728         //    if (intpend && !new_ixoriy && iff1) {
00729         // are we HALT-ed ? then resume
00730         //      if (fetch(pc)==0x76) pc++;
00731 
00732         // block further interrupts for now
00733         //    iff1=0;
00734 
00735         // do the call to 00x38
00736         //   push2(pc);   // save old pc
00737         //  pc=0x0038;   // setup new pc
00738         //  intpend=0;   // release interrupt pending flag;
00739         //   } // if intpend
00740     } // while
00741 }