From a500f050272a8cca97ed0bbb7f8d7156555c61a7 Mon Sep 17 00:00:00 2001 From: Ian C Date: Mon, 22 Dec 2003 00:01:31 +0000 Subject: Added memory menu and some devel changes --- src/zx81.c | 524 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 518 insertions(+), 6 deletions(-) (limited to 'src/zx81.c') diff --git a/src/zx81.c b/src/zx81.c index 9fa09f6..515cd07 100644 --- a/src/zx81.c +++ b/src/zx81.c @@ -29,11 +29,21 @@ static const char ident[]="$Id$"; #include #include #include "zx81.h" +#include "gfx.h" +#include "gui.h" #include "config.h" #include "exit.h" static const char ident_h[]=EZX81ZX81H; +#ifndef TRUE +#define TRUE 1 +#endif + +#ifndef FALSE +#define FALSE 0 +#endif + /* ---------------------------------------- STATICS */ @@ -41,6 +51,17 @@ static const int ROMLEN=0x2000; static const int ROM_SAVE=0x2fc; static const int ROM_LOAD=0x347; +/* No of cycles in each 64us HSYNC (hopefully) +*/ +static const int HSYNC_PERIOD=321; + +/* The ZX81 screen +*/ +static const int SCR_W=256; +static const int SCR_H=192; +static const int TXT_W=32; +static const int TXT_H=24; + /* These assume a 320x200 screen */ static const int OFF_X=(320-256)/2; @@ -52,30 +73,377 @@ static Z80Word RAMBOT=0; static Z80Word RAMTOP=0; static Z80Word RAMLEN=0; +/* Counter used when triggering the interrupts for the display +*/ +static int nmigen=FALSE; +static int hsync=FALSE; + +/* The ULA +*/ +static struct +{ + int x; + int y; + int c; + int release; +} ULA; + +/* GFX vars +*/ +static Uint32 white; +static Uint32 black; + + +/* The keyboard +*/ +static Z80Byte matrix[8]; + +typedef struct +{ + SDLKey key; + int m1,b1,m2,b2; +} MatrixMap; + +#define KY1(m,b) m,1<=28 && b<=37) /* 0-9 */ + return '0'+b-28; + + if (b>=38 && b<=63) /* A-Z */ + return 'a'+b-38; + + return 0; +} + + +static const char *ConvertFilename(Z80Word addr) +{ + static char buff[FILENAME_MAX]; + char *p; + + p=buff; + *p=0; + + if (addr>0x8000) + return buff; + + do + { + char c=ToASCII(mem[addr]&0x7f); + + if (c) + *p++=c; + + } while(mem[addr++]<0x80); + + *p=0; + + return buff; +} + + +static void LoadTape(Z80State *state) +{ + const char *p=ConvertFilename(state->DE); + char path[FILENAME_MAX]; + FILE *fp; + Z80Word addr; + int c; + + if (strlen(p)==0) + { + GUIMessage("ERROR","Can't load empty filename"); + return; + } + + strcpy(path,SConfig(CONF_TAPEDIR)); + strcat(path,"/"); + strcat(path,p); + strcat(path,".p"); + + if (!(fp=fopen(path,"rb"))) + { + GUIMessage("ERROR","Can't load file:\n%s",path); + return; + } + + addr=0x4009; + + while((c=getc(fp))!=EOF) + { + if (addr>=0x4000) + mem[addr]=(Z80Byte)c; + + addr++; + } + + fclose(fp); +} + + +static void SaveTape(Z80State *state) +{ + const char *p=ConvertFilename(state->DE); + char path[FILENAME_MAX]; + FILE *fp; + Z80Word start; + Z80Word end; + + if (strlen(p)==0) + { + GUIMessage("ERROR","Can't save empty filename"); + return; + } + + strcpy(path,SConfig(CONF_TAPEDIR)); + strcat(path,"/"); + strcat(path,p); + strcat(path,".p"); + + if (!(fp=fopen(path,"wb"))) + { + GUIMessage("ERROR","Can't write file:\n%s",path); + return; + } + + start=0x4009; + end=(Z80Word)mem[0x4014]|(Z80Word)mem[0x4015]<<8; + + while(start<=end) + putc(mem[start++],fp); + + fclose(fp); +} + + +static int EDCallback(Z80 *z80, Z80Val data) { + Z80State state; + + Z80GetState(z80,&state); + + switch((Z80Byte)data) + { + case 0xf0: + SaveTape(&state); + break; + + case 0xf1: + LoadTape(&state); + break; + + default: + break; + } + + return TRUE; +} + + +static void ULA_Video_Shifter(Z80 *z80, Z80Byte val) +{ + Z80State state; + Z80Word base; + int x,y; + int inv; + int b; + + Z80GetState(z80,&state); + + /* Extra check due to out dodgy ULA emulation + */ + if (ULA.y>=0 && ULA.yHSYNC_PERIOD) + { + Z80ResetCycles(z80,0); + + if (nmigen) + { + Z80NMI(z80,0xff); + } + else if (hsync) + { + if (ULA.release) + { + /* ULA.release=FALSE; */ + ULA.c=(ULA.c+1)&7; + ULA.y++; + ULA.x=0; + } + } + } + + return TRUE; } /* ---------------------------------------- EXPORTED INTERFACES */ -void ZX81Init(void) +void ZX81Init(Z80 *z80) { FILE *fp; Z80Word f; if (!(fp=fopen(SConfig(CONF_ROMFILE),"rb"))) - Exit("Failed to open ZX81 ROM - %s\n",SConfig(CONF_ROMFILE)); + { + GUIMessage("ERROR","Failed to open ZX81 ROM\n%s",SConfig(CONF_ROMFILE)); + Exit(""); + } if (fread(mem,1,ROMLEN,fp)!=ROMLEN) { fclose(fp); - Exit("ROM file must be %d bytes long\n",ROMLEN); + GUIMessage("ERROR","ROM file must be %d bytes long\n",ROMLEN); + Exit(""); } + /* Patch the ROM + */ + RomPatch(); + Z80LodgeCallback(z80,Z80_EDHook,EDCallback); + Z80LodgeCallback(z80,Z80_Fetch,CheckTimers); + /* Mirror the ROM */ memcpy(mem+ROMLEN,mem,ROMLEN); @@ -93,6 +461,48 @@ void ZX81Init(void) for(f=RAMBOT;f<=RAMTOP;f++) mem[f]=0; + + for(f=0;f<8;f++) + matrix[f]=0x1f; + + white=GFXRGB(230,230,230); + black=GFXRGB(0,0,0); + + nmigen=FALSE; + hsync=FALSE; + + GFXStartFrame(); +} + + +void ZX81KeyEvent(SDL_Event *e) +{ + const MatrixMap *m; + + m=keymap; + + while(m->key!=SDLK_UNKNOWN) + { + if (e->key.keysym.sym==m->key) + { + if (e->key.state==SDL_PRESSED) + { + matrix[m->m1]&=~m->b1; + + if (m->m2!=-1) + matrix[m->m2]&=~m->b2; + } + else + { + matrix[m->m1]|=m->b1; + + if (m->m2!=-1) + matrix[m->m2]|=m->b2; + } + } + + m++; + } } @@ -134,19 +544,109 @@ Z80Byte ZX81ReadMem(Z80 *z80, Z80Word addr) void ZX81WriteMem(Z80 *z80, Z80Word addr, Z80Byte val) { + addr=addr&0x7fff; + if (addr>=RAMBOT && addr<=RAMTOP) - mem[addr&0x7fff]=val; + mem[addr]=val; } Z80Byte ZX81ReadPort(Z80 *z80, Z80Word port) { - return 0; + Z80Byte b=0; + + printf("IN %4.4x\n",port); + + switch(port&0xff) + { + case 0xfe: /* ULA */ + /* Key matrix + */ + switch(port&0xff00) + { + case 0xfe00: + b=matrix[0]; + break; + case 0xfd00: + b=matrix[1]; + break; + case 0xfb00: + b=matrix[2]; + break; + case 0xf700: + b=matrix[3]; + break; + case 0xef00: + b=matrix[4]; + break; + case 0xdf00: + b=matrix[5]; + break; + case 0xbf00: + b=matrix[6]; + break; + case 0x7f00: + b=matrix[7]; + break; + } + + /* Turn off HSYNC if NMI generator is OFF and redraw screen to + match output ULA has since sent out. + */ + if (!nmigen && hsync) + { + hsync=FALSE; + + GFXEndFrame(TRUE); + GFXClear(white); + + ULA.x=0; + ULA.y=-1; + ULA.c=7; + ULA.release=FALSE; + + GFXStartFrame(); + } + else + { + /* Reset and hold ULA counter + */ + ULA.c=0; + ULA.release=FALSE; + } + break; + + default: + break; + } + + return b; } void ZX81WritePort(Z80 *z80, Z80Word port, Z80Byte val) { + printf("OUT %4.4x\n",port); + + /* Any port write releases the ULA line counter + */ + ULA.release=TRUE; + + switch(port&0xff) + { + case 0xfd: /* NMI generator OFF */ + nmigen=FALSE; + break; + + case 0xfe: /* NMI generator ON */ + nmigen=TRUE; + break; + + case 0xff: /* HSYNC generator ON */ + hsync=TRUE; + Z80ResetCycles(z80,0); + break; + } } @@ -156,4 +656,16 @@ Z80Byte ZX81ReadForDisassem(Z80 *z80, Z80Word addr) } +const char *ZX81Info(Z80 *z80) +{ + static char buff[80]; + + sprintf(buff,"NMIGEN: %s HSYNC: %s", + nmigen ? "ON":"OFF", + hsync ? "ON":"OFF"); + + return buff; +} + + /* END OF FILE */ -- cgit v1.2.3