home *** CD-ROM | disk | FTP | other *** search
- /* Z80 Emulator
- Copyright (C) 1994 G.Woigk
-
- This file is part of Mac Spectacle and it is free software
- See application.c for details
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
-
- 16.Jan.95 Fixed wrong calculation of parity flag KIO !
- 28.Jan.95 CMD_PROFILE KIO !
- 29.Mrz.95 Separated this file from Z80.c KIO !
- 01.Nov.95 Started work on paged memory model again KIO !
- */
-
- #include "kio.h"
- #include "z80.options"
- #include "z80.h"
- #include "application.h"
- #include "quick_strings.h"
- #include "z80 main.h"
- #include "display.h"
-
-
- #define maxrampages 8 // 128k RAM in 8 pages à 16k
- #define maxrompages 5 // the plus3 has 4 roms + if1 rom
- #define pagesize 0x4000 // 16 kByte
- #define pagemask 0x3FFF // 16k-1
- #define pagebits 14 // 14 bit address inside page
-
-
- int z80_hardware = zx_48k; // actually emulated hardware ( as set up by Init_Z80() )
-
-
- #if CMD_PROFILE
-
- Boolean count_instr = false;
-
- long *cnt_xx = nil; // array: count use of normal instructions
- long *cnt_cb = nil; // array: count use of CB instructions
- long *cnt_ed = nil; // array: count use of ED instructions
- long *cnt_xy = nil; // array: count use of ix and iy instructions
- long *cnt_xycb = nil; // array: count use of ix/CB and iy/CB instructions
-
- #endif
-
-
- #if PC_PROFILE
-
- Boolean count_pc = false;
-
- long *cnt_pc = nil; // array: count instruction executions per location in RAM
-
- #endif
-
-
- // ----- The Z80 core --------------------------------------------------------------
- Char** CORE_M = nil; // master handle for all allocated RAM and ROM
- Char* CORE = nil; // do not use any longer!!!
- Char* rpage[4]; // mapped in pages for reading
- Char* wpage[4]; // mapped in pages for writing
- Char* ram[maxrampages]; // real RAM pages
- Char* rom[maxrompages]; // real ROM pages
- Char* norom = nil; // dummy page for writing to ROM
-
- Char zx128pagectrl = 0; // last byte sent to ZX 128's paging control port
-
-
- // ----- The Z80 registers --------------------------------------------------
- z80 zreg; // contains z80 registers on entry/return of Z80()
-
-
- // ----- Flags after logic operations -------------------------------------
- Char zlog_flags[256]; // convert: A -> Z80-flags with V=parity, S, Z, and C=0
- #if !GENERATINGPOWERPC
- Char mlog_flags[256]; // convert: A-register -> 68000 flags with V=parity and C=0
- Char z80flags[256]; // convert: 68000 flagbyte -> Z80 flagbyte
- Char m68flags[256]; // convert: Z80 flagbyte -> 68000 flagbyte
- #endif
-
-
- // ===== Utilities ========================================================
-
-
- // ----- Peek, Poke and calculate EA for peeking and poking -----------------------------
- // These are inappropriate for macros, because the address is used twice
- // note: rpage[] and wpage[] pointers are calculated that way, that the unmasked address
- // must be added to address the right byte in the Macintosh's RAM !
-
- Char* RdPtr ( Short addr ) { return rpage[addr>>pagebits] + addr; } // ptr for reading
- Char* WrPtr ( Short addr ) { return wpage[addr>>pagebits] + addr; } // ptr for writing
-
- Char Peek ( Short addr ) { return rpage[addr>>pagebits][addr]; }
- Poke ( Short addr, Char byte ) { wpage[addr>>pagebits][addr] = byte; }
-
-
- // ----- Write from/to core, buffer and file -------------------------------------------
- // file operations return 0 if ok else OS error
-
- long tfu; // after read/write to file: bytes actually transferred
-
-
- /* ----- Write buffer to file ----------------------------------------------------------
- */
- OSErr Buffer2File ( void* bu, short fileID, long len )
- {
- tfu = len;
- return FSWrite ( fileID, &tfu, bu );
- }
-
-
- /* ----- Read buffer from file --------------------------------------------------------
- */
- OSErr File2Buffer ( short fileID, void* bu, long len )
- {
- tfu = len;
- return FSRead ( fileID, &tfu, bu );
- }
-
-
- /* ----- Write core to file ------------------------------------------------------------
- saves what the z80 cpu would read
- */
- OSErr Core2File ( Short addr, short fileID, long len )
- { OSErr err; long n;
-
- tfu = 0;
- for ( err=noErr; !err && len; )
- { n = min ( len, pagesize-(addr&pagemask) );
- PrintDebug ( CatString(CatString("\pCore->File; addr: ",NumString(addr)), CatString("\p; bytes: ",NumString(n))),0);
- err = FSWrite ( fileID, &n, RdPtr(addr) );
- addr += n;
- len -= n;
- tfu += n;
- }
- return err;
- }
-
-
- /* ----- Read core from file -----------------------------------------------------------
- stores what the z80 cpu would write
- ROM is automatically protected
- */
- OSErr File2Core ( short fileID, Short addr, long len )
- { OSErr err; long n;
-
- tfu = 0;
- for ( err=noErr; !err && len; )
- { n = min ( len, pagesize-(addr&pagemask ) );
- PrintDebug ( CatString(CatString("\pFile->Core; addr: ",NumString(addr)), CatString("\p; bytes: ",NumString(n))),0);
- err = FSRead ( fileID, &n, WrPtr(addr) );
- addr += n;
- len -= n;
- tfu += n;
- }
- return err;
- }
-
-
- /* ----- Copy core to buffer -----------------------------------------------------------
- copies what the z80 cpu would read
- */
- Core2Buffer ( Short addr, void* bu, long len )
- { long n;
-
- while ( len )
- { n = min ( len, pagesize-(addr&pagemask ) );
- memcpy ( bu, RdPtr(addr), n );
- bu = (Char*)bu+n;
- addr += n;
- len -= n;
- }
- }
-
- /* ----- Copy buffer to core ------------------------------------------------------------
- copies what the z80 cpu would write
- */
- Buffer2Core ( void* bu, Short addr, long len )
- { long n;
-
- while ( len )
- { n = min ( len, pagesize-(addr&pagemask ) );
- memcpy ( WrPtr(addr), bu, n );
- bu = (Char*)bu+n;
- addr += n;
- len -= n;
- }
- }
-
- /* ----- Copy core to core --------------------------------------------------------------
- copies what the z80 cpu would copy
- */
- Core2Core ( Short src, Short dest, long len )
- { long n;
-
- while (len)
- { n = min ( min ( len, pagesize-(src&pagemask ) ), pagesize-(dest&pagemask ) );
- memcpy ( WrPtr(dest), RdPtr(src), n );
- src += n;
- dest += n;
- len -= n;
- }
- }
-
- /* ----- Copy buffer to buffer (just for completeness) ------------------------------------
- */
- Buffer2Buffer ( void* src, void* dest, long len )
- {
- memcpy ( dest, src, len );
- }
-
-
- /* ----- Send byte to ZX 128's paging control port ----------------------------------------
- Bits 0-2: Ram for top 16k: 0 is the usual bank; 7 contains some scratchpads used by the 128k editor.
- Bit 3: Screen select: 0 => Use the normal screen in bank 5; 1 => Use the shadow screen in bank 7.
- Bit 4: ROM for lower 16k: 0 => 128k editor; 1 => 48k BASIC
- Bit 5: Lock. If set, disables all further paging.
- */
- ZX128PageCtrl ( Char n )
- {
- if (z80_hardware!=zx_128) return; // not a ZX 128
- if (zx128pagectrl&0x20) return; // further paging disabled
- zx128pagectrl = n;
- rpage[0] = (n&0x10) ? rom[1] : rom[0]; // ROM select
- video_page = (n&0x08) ? ram[7] : ram[5]; // video RAM select
- rpage[3] = wpage[3] = ram[n&0x07]-0xc000; // upper RAM page select
- }
-
-
- /* ----- Initialialize the z80 engine --------------------------------------------
- allocate rom, ram, and norom pages
- initialize rom[], ram[] and norom
- initialize rpage[] and wpage[] for reset
- CORE points to reset core which is allocated in 4 consecutive pages!
- init random generator for r register handling
- calculate flag tables
- initialize zreg
- reset z80
- On a 68k machine:
- • the core is aligned to a multiple of 0x00010000
- • some byte behind the last byte a preset with rst0 opcodes
- • high words of pointers in zreg struct are set to point to the core
- */
- InitZ80 ( int hardware )
- { int i, roms, rams;
- OSErr err=noErr;
- Char *p;
-
- switch (hardware)
- {
- case zx_48k: roms=1; rams=3; break;
- case zx_128: roms=2; rams=8; break;
- default: abort("\pInitZ80():","\pillegal model number: ",NumString(hardware));
- }
- z80_hardware = hardware;
-
- // allocate dummy write page for ROMs
- if (!norom) norom = (Char*)NewPtr(pagesize);
- if (!norom) abort_oomem ( "\pInitZ80()" );
-
- // dispose of old core
- if (CORE_M) DisposHandle((Handle)CORE_M);
- CORE = nil; CORE_M = nil;
-
- for (i=maxrompages;i--;) rom[i] = nil;
- for (i=maxrampages;i--;) ram[i] = nil;
- for (i=4;i--;) rpage[i] = wpage[i] = norom-i*pagesize; // fail safe pointers
-
- /* allocate rom and ram pages:
- zx_48k: CORE+0x0000 = rom[0] = rpage[0]
- CORE+0x4000 = ram[1] = rpage[1]
- CORE+0x8000 = ram[2] = rpage[2]
- CORE+0xC000 = ram[3] = rpage[3]
-
- zx_128: CORE+0x0000 = rom[0] = rpage[0]
- CORE+0x4000 = ram[5] = rpage[1]
- CORE+0x8000 = ram[2] = rpage[2]
- CORE+0xC000 = ram[0] = rpage[3]
- */
- #if !GENERATINGPOWERPC
- // put rom[0] and ram[1...3] resp. ram[5/2/0] in a memory block aligned to a multiple of 0x10000
- // additional ram and rom is located physically before pointer CORE !!!
- CORE_M = (Char**)TempNewHandle ((roms+rams)*pagesize+0x10010,&err);
- if (!CORE_M||err) abort_oomem ( "\pInitZ80()" );
- HLock((Handle)CORE_M);
- CORE = *CORE_M+(roms+rams)*pagesize;
- CORE -= (Short)CORE;
- memset ( CORE+0x10000, 199, 0x10 ); // rst 0
- ABC=ADE=AHL=AIX=AIY=APC=ASP=CORE; // setup high words of register pointers
- #else
- // simple allocation in PowerPC version
- CORE_M = (Char**)TempNewHandle ((roms+rams)*pagesize,&err);
- if (!CORE_M||err) abort_oomem ( "\pInitZ80()" );
- HLock((Handle)CORE_M);
- CORE = *CORE_M + (roms+rams-4)*pagesize; // to mimic 68k version
- #endif
-
- // initialize rom[] and ram[]
- switch (z80_hardware)
- {
- case zx_48k:
- rom[0] = CORE;
- ram[1] = CORE+0x4000;
- ram[2] = CORE+0x8000;
- ram[3] = CORE+0xc000;
- break;
- case zx_128:
- rom[0] = CORE;
- ram[5] = CORE+0x4000;
- ram[2] = CORE+0x8000;
- ram[0] = CORE+0xc000;
- p=CORE;
- rom[1] = p-=pagesize;
- for (i=0;i<rams;i++) if (!ram[i]) ram[i] = p-=pagesize;
- break;
- }
-
- // initialize rpage[], wpage[]
- for (i=4;i--;) rpage[i] = wpage[i] = CORE;
- wpage[0] = norom;
-
- // init z80 registers:
- zreg.ff2 = zreg.aa2 = zreg.ff = zreg.aa = 0; // clear high bytes of A/A2 and F/F2
- BC=DE=HL=IX=IY=PC=SP=BC2=DE2=HL2=0; // clear registers
- RA=RA2=RF=RF2=RR=RI=0;
- IFF1 = IFF2 = disabled; // disable interrupts
- IM = 1; // interrupt mode := 1
- WUFF= 0; // clear irpt, nmi
- EXIT = 0; // clear watchdog
- IRPTCMD = 0xff; // byte read from bus in im0 or im2 mode
-
- // build flag tables:
- // Z80: %SZ-H-VNC --- H & N ignored
- // m68: %---XSZVC --- X ignored
- // the unused flags correspond as follows: z80{%--1H2-N-} == m68{%1H2N----} 11.12.94 KIO !
- for (i=0; i<256; i++)
- {
- zlog_flags[i] = (i&0x80) + ((i==0)<<6) + ( ( (~i+(i>>1)+(i>>2)+(i>>3)+(i>>4)+(i>>5)+(i>>6)+(i>>7))&1 ) << 2 );
- #if !GENERATINGPOWERPC
- mlog_flags[i] = ((i>=128)<<3) + ((i==0)<<2) + ( ( (~i+(i>>1)+(i>>2)+(i>>3)+(i>>4)+(i>>5)+(i>>6)+(i>>7))&1 ) << 1 );
- z80flags[i] = ((i<<4)&0xc0) + ((i<<1)&4) + (i&1) + ((i>>2)&0x38) + ((i>>3)&2);
- m68flags[i] = ((i>>4)&0x0c) + ((i>>1)&2) + (i&1) + ((i<<2)&0xe0) + ((i<<3)&0x10);
- #endif
- };
-
- // initialize random generator for r register
- GetDateTime((unsigned long*)&qd.randSeed);
- }
-
-
-
-
-
-
-
-
-
-
-