From 6a86fc4668ce7e213330bb78aff45c578e159f54 Mon Sep 17 00:00:00 2001 From: Ian C Date: Wed, 24 Dec 2003 18:19:00 +0000 Subject: devel snapshot --- src/spec.c | 531 ++++++++++++++++++++++--------------------------------------- 1 file changed, 192 insertions(+), 339 deletions(-) (limited to 'src/spec.c') diff --git a/src/spec.c b/src/spec.c index 51006df..a8cb9eb 100644 --- a/src/spec.c +++ b/src/spec.c @@ -47,51 +47,79 @@ static const char ident_h[]=ESPEC_SPECH; /* ---------------------------------------- STATICS */ -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; +static const int ROMLEN=0x4000; +static const int ROM_SAVE=0x4c6; +static const int ROM_LOAD=0x562; /* The SPEC 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; +#define GFX_W 320 +#define GFX_H 300 +#define SCR_W 256 +#define SCR_H 192 +#define TXT_W 32 +#define TXT_H 24 +#define SCRDATA 0x4000 +#define ATTR 0x5800 -/* These assume a 320x200 screen -*/ -static const int OFF_X=(320-256)/2; -static const int OFF_Y=(200-192)/2; +#define ATTR_AT(x,y) \ + mem[ATTR+(x)+((y)/8)*32] + +static const int OFF_X=(GFX_W-SCR_W)/2; +static const int OFF_Y=(GFX_H-SCR_H)/2; static Z80Byte mem[0x10000]; -static Z80Word RAMBOT=0; -static Z80Word RAMTOP=0; -static Z80Word RAMLEN=0; -/* Counter used when triggering the interrupts for the display +/* Number of cycles per scan lines and scan line control */ -static int nmigen=FALSE; -static int hsync=FALSE; +static Z80Val SCAN_CYCLES=224; +static int scanline=0; + -/* The ULA +/* GFX vars */ +#define FLASH 16 /* Frames per flash */ + +static int flash=0; +static int flashctr=0; + +static int border=0; + +#define TOPL 64 /* Scanlines before 'first' line */ +#define SCRL SCR_H /* Scanlines making up screen data */ +#define BOTL 56 /* Scanlines after 'last' line */ + +#define TOTL (TOPL+SCRL+BOTL) + +#define NVAL 235 /* Normal RGB intensity */ +#define BVAL 255 /* Bright RGB intensity */ + static struct { - int x; - int y; - int c; - int release; -} ULA; + Uint32 col; + int r,g,b; +} coltable[16]= +{ + {0, 0x00,0x00,0x00}, /* BLACK */ + {0, 0x00,0x00,NVAL}, /* BLUE */ + {0, NVAL,0x00,0x00}, /* RED */ + {0, NVAL,0x00,NVAL}, /* MAGENTA */ + {0, 0x00,NVAL,0x00}, /* GREEN */ + {0, 0x00,NVAL,NVAL}, /* CYAN */ + {0, NVAL,NVAL,0x00}, /* YELLOW */ + {0, NVAL,NVAL,NVAL}, /* WHITE */ + + {0, 0x00,0x00,0x00}, /* BLACK */ + {0, 0x00,0x00,BVAL}, /* BLUE */ + {0, BVAL,0x00,0x00}, /* RED */ + {0, BVAL,0x00,BVAL}, /* MAGENTA */ + {0, 0x00,BVAL,0x00}, /* GREEN */ + {0, 0x00,BVAL,BVAL}, /* CYAN */ + {0, BVAL,BVAL,0x00}, /* YELLOW */ + {0, BVAL,BVAL,BVAL}, /* WHITE */ -/* GFX vars -*/ -static Uint32 white; -static Uint32 black; +}; /* The keyboard @@ -150,9 +178,6 @@ static const MatrixMap keymap[]= {SDLK_RETURN, KY1(6,0)}, {SDLK_SPACE, KY1(7,0)}, - {SDLK_COMMA, KY1(7,1)}, /* In the right place... */ - {SDLK_PERIOD, KY1(7,1)}, /* ...or the right key... */ - {SDLK_BACKSPACE, KY2(0,0,4,0)}, {SDLK_DELETE, KY2(0,0,4,0)}, {SDLK_UP, KY2(0,0,4,3)}, @@ -160,8 +185,13 @@ static const MatrixMap keymap[]= {SDLK_LEFT, KY2(0,0,3,4)}, {SDLK_RIGHT, KY2(0,0,4,2)}, - {SDLK_RSHIFT, KY1(0,0)}, {SDLK_LSHIFT, KY1(0,0)}, + {SDLK_RSHIFT, KY1(7,1)}, + {SDLK_LCTRL, KY1(0,0)}, + {SDLK_RCTRL, KY1(7,1)}, + {SDLK_LALT, KY1(0,0)}, + {SDLK_RALT, KY1(7,1)}, + {SDLK_CAPSLOCK, KY2(0,0,3,1)}, {SDLK_UNKNOWN, 0,0,0,0}, }; @@ -169,19 +199,71 @@ static const MatrixMap keymap[]= /* ---------------------------------------- PRIVATE FUNCTIONS */ +void DrawScanline(int y) +{ + int aline; + int f,r; + int ink,paper,t; + Z80Byte *scr; + Z80Byte b; + Z80Byte att; + + aline=scanline-TOPL; + + GFXHLine(0,GFX_W-1,y,coltable[border].col); + + if (aline>=0 && aline>3; + + if (att&0x40) + { + ink+=8; + paper+=8; + } + + if ((att&0x80)&&(flash)) + { + t=ink; + ink=paper; + paper=t; + } + + for(r=7,b=*scr++;r>=0;r--) + if (b&(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); + state->AF|=Z80_F_Carry; } 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); + state->AF|=Z80_F_Carry; } @@ -333,87 +310,51 @@ static int EDCallback(Z80 *z80, Z80Val data) break; } + Z80SetState(z80,&state); + return TRUE; } -static void ULA_Video_Shifter(Z80 *z80, Z80Byte val) +static int CheckTimers(Z80 *z80, Z80Val 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.ySCAN_CYCLES) { - Uint32 fg,bg; + int y; - /* Position on screen corresponding to ULA - */ - x=OFF_X+ULA.x*8; - y=OFF_Y+ULA.y; + Z80ResetCycles(z80,val-SCAN_CYCLES); - /* Get ULA invert state and clear to ULA 6-but code + /* Increment scan line and check for frame flyback */ - inv=val&0x80; - val&=0x3f; + scanline++; - base=((Z80Word)state.I<<8)|(val<<3)|ULA.c; - - if (inv) - { - fg=white; - bg=black; - } - else + if (scanline==TOTL) { - fg=black; - bg=white; - } + scanline=0; - for(b=0;b<8;b++) - { - if (mem[base]&(1<<(7-b))) - GFXPlot(x+b,y,fg); - else - GFXPlot(x+b,y,bg); - } - } + flashctr++; - ULA.x=(ULA.x+1)&0x1f; + if (flashctr==FLASH) + { + flash^=1; + flashctr=0; + } - if (ULA.x==0) - Z80Interrupt(z80,0xff); -} + Z80Interrupt(z80,0xff); + GFXEndFrame(TRUE); + GFXStartFrame(); + } -static int CheckTimers(Z80 *z80, Z80Val val) -{ - if (val>HSYNC_PERIOD) - { - Z80ResetCycles(z80,0); + /* Draw scanline + y=OFF_X-TOPL+scanline; + */ + y=scanline-TOPL+OFF_Y; - if (nmigen) - { - Z80NMI(z80,0xff); - printf("NMIGEN\n"); - } - else if (hsync) - { - printf("HSYNC\n"); - if (ULA.release) - { - /* ULA.release=FALSE; */ - ULA.c=(ULA.c+1)&7; - ULA.y++; - ULA.x=0; - } - } + if (y>=0 && y0x7fff) - { - Z80Byte b; - - /* B6 of R is tied to the IRQ line (only when HSYNC active?) - if ((HSYNC)&&(!(z80->R&0x40))) - z80->IRQ=TRUE; - */ - - b=mem[addr&0x7fff]; - - /* If bit 6 of the opcode is set the opcode is sent as is to the - Z80. If it's not, the byte is interretted by the ULA. - */ - if (b&0x40) - { - ULA_Video_Shifter(z80,0); - } - else - { - ULA_Video_Shifter(z80,b); - b=0; - } - - return b; - } - else - return mem[addr&0x7fff]; - + /* TODO: Emulation of contention */ + return mem[addr]; } void SPECWriteMem(Z80 *z80, Z80Word addr, Z80Byte val) { - addr=addr&0x7fff; - - if (addr>=RAMBOT && addr<=RAMTOP) + if (addr>=ROMLEN) mem[addr]=val; } Z80Byte SPECReadPort(Z80 *z80, Z80Word port) { - Z80Byte b=0; - - printf("IN %4.4x\n",port); + Z80Byte lo=port&0xff; + Z80Byte hi=port>>8; + Z80Byte b=0xff; + int f; - switch(port&0xff) + switch(lo) { - case 0xfe: /* ULA */ + case 0x1f: /* TODO: Kempston joystick */ + break; + + case 0x7f: /* TODO: Fuller joystick */ + break; + + case 0xfb: /* TODO: ZX Printer */ + break; + + case 0x01: /* 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; - } + b=0; - /* Turn off HSYNC if NMI generator is OFF and redraw screen to - match output ULA has since sent out. - */ - if (!nmigen && hsync) - { - hsync=FALSE; + for(f=0;f<8;f++) + if (!(hi&(1<