summaryrefslogtreecommitdiff
path: root/source/zx81.c
diff options
context:
space:
mode:
authorIan C <ianc@noddybox.co.uk>2007-01-30 23:46:49 +0000
committerIan C <ianc@noddybox.co.uk>2007-01-30 23:46:49 +0000
commit6fca8cfe0bcbe30767c30ac9b6d9a79e4fa19edc (patch)
tree303f46557317a8e43524ba7999715f547ab9783e /source/zx81.c
parentef641589bf763ea12e73abf4bf42e45ac1acd2ff (diff)
Added pseudo-hires support
Diffstat (limited to 'source/zx81.c')
-rw-r--r--source/zx81.c218
1 files changed, 202 insertions, 16 deletions
diff --git a/source/zx81.c b/source/zx81.c
index d6edaa0..9a053b5 100644
--- a/source/zx81.c
+++ b/source/zx81.c
@@ -69,9 +69,15 @@ static Z80Val FRAME_TSTATES=FAST_TSTATES;
/* The ZX81 screen and memory
*/
+static void (*DrawScreen)(Z80 *z80);
+
static int waitkey=FALSE;
static int started=FALSE;
+static int hires=FALSE;
+static int hires_dfile;
+static int last_I;
+
#define SCR_W 256
#define SCR_H 192
#define TXT_W 32
@@ -95,7 +101,8 @@ static int tape_len;
/* GFX vars
*/
-static uint16 *screen;
+static uint16 *txt_screen;
+static uint16 *bmp_screen;
/* The keyboard
*/
@@ -330,7 +337,89 @@ static void LoadExternalTape(FILE *tape, Z80 *z80)
}
-static void DrawScreen(Z80 *z80)
+static void ClearBitmap(void)
+{
+ uint16 *s;
+ uint16 p;
+ int f;
+
+ s = bmp_screen;
+ p = 0x8000|RGB15(31,31,31);
+
+ for(f=0;f<SCREEN_WIDTH*SCREEN_HEIGHT;f++)
+ {
+ *s++=p;
+ }
+}
+
+
+static void ClearText(void)
+{
+ uint16 *s;
+ int f;
+
+ s = txt_screen;
+
+ for(f=0;f<TXT_W*TXT_H;f++)
+ {
+ *s++=0;
+ }
+}
+
+
+static void DrawScreen_HIRES(Z80 *z80)
+{
+ uint16 *bmp;
+ Z80Byte *scr;
+ int x,y;
+ int table;
+
+ scr = mem + hires_dfile;
+ bmp = bmp_screen;
+ table = z80->I << 8;
+
+ /* scr is increment in both loops so that it can skip of the end-of-line
+ character
+ */
+ for(y=0; y<192; y++)
+ {
+ for(x=0; x<32; x++)
+ {
+ int c;
+ int v;
+ int b;
+
+ c = *scr;
+
+ v = mem[table + (c&0x3f)*8];
+
+ if (c & 0x80)
+ {
+ v ^= 0xff;
+ }
+
+ for(b=0;b<8;b++)
+ {
+ if (v & 0x80)
+ {
+ *bmp++ = 0x8000;
+ }
+ else
+ {
+ *bmp++ = 0xffff;
+ }
+
+ v=v<<1;
+ }
+
+ scr++;
+ }
+
+ scr++;
+ }
+}
+
+static void DrawScreen_TEXT(Z80 *z80)
{
Z80Byte *scr=mem+WORD(DFILE);
int x,y;
@@ -349,11 +438,11 @@ static void DrawScreen(Z80 *z80)
if (ch&0x80)
{
- screen[x+y*32]=(ch&0x3f)|0x40;
+ txt_screen[x+y*32]=(ch&0x3f)|0x40;
}
else
{
- screen[x+y*32]=(ch&0x3f);
+ txt_screen[x+y*32]=(ch&0x3f);
}
x++;
@@ -369,7 +458,7 @@ static void DrawSnow(Z80 *z80)
uint16 *s;
int f;
- s = screen;
+ s = txt_screen;
for(f=0;f<TXT_W*TXT_H;f++)
{
@@ -378,6 +467,56 @@ static void DrawSnow(Z80 *z80)
}
+static void FindHiresDFILE(void)
+{
+ /* Somewhat based on the code from xz81, an X-based ZX81 emulator,
+ (C) 1994 Ian Collier. Search the ZX81's RAM until we find what looks
+ like a hi-res display file.
+
+ Bizarrely the original code used 'f' for a loop counter too... Another
+ poor soul forever damaged by the ZX81's keyword entry system...
+ */
+ int f;
+
+ for(f=0x8000-(33*192); f>0x4000 ; f--)
+ {
+ int v;
+
+ v = mem[f+32];
+
+ if (v&0x40)
+ {
+ int ok = TRUE;
+ int n;
+
+ for(n=0;n<192 && ok;n++)
+ {
+ if (mem[f+33*n]&0x40)
+ {
+ ok = FALSE;
+ }
+
+ if (mem[f+32+33*n] != v)
+ {
+ ok = FALSE;
+ }
+ }
+
+ if (ok)
+ {
+ hires_dfile = f;
+ return;
+ }
+ }
+ }
+
+ /* All else fails, put the hires dfile at 0x4000 -- at least it should be
+ obvious that the hires won't work for whatever is being run.
+ */
+ hires_dfile = 0x4000;
+}
+
+
/* Perform ZX81 housekeeping functions like updating FRAMES and updating LASTK
*/
static void ZX81HouseKeeping(Z80 *z80)
@@ -464,9 +603,33 @@ static int CheckTimers(Z80 *z80, Z80Val val)
{
if (val>=FRAME_TSTATES)
{
+ /* Check for hi-res modes
+ */
+ if (z80->I && z80->I != last_I)
+ {
+ last_I = z80->I;
+
+ if (z80->I == 0x1e)
+ {
+ hires = FALSE;
+ DrawScreen = DrawScreen_TEXT;
+ ClearBitmap();
+ }
+ else
+ {
+ hires = TRUE;
+ DrawScreen = DrawScreen_HIRES;
+ ClearText();
+ FindHiresDFILE();
+ }
+ }
+
Z80ResetCycles(z80,val-FRAME_TSTATES);
- if (started && ((mem[CDFLAG] & 0x80) || waitkey))
+ /* Kludge warning - We assume that a hires display will not be in
+ FAST mode!
+ */
+ if (started && ((mem[CDFLAG] & 0x80) || waitkey || hires))
{
DrawScreen(z80);
FRAME_TSTATES=SLOW_TSTATES;
@@ -582,11 +745,19 @@ static int EDCallback(Z80 *z80, Z80Val data)
/* ---------------------------------------- EXPORTED INTERFACES
*/
-void ZX81Init(uint16 *vram, Z80 *z80)
+void ZX81Init(uint16 *text_vram, uint16* bitmap_vram, Z80 *z80)
{
Z80Word f;
- screen = vram;
+ txt_screen = text_vram;
+ bmp_screen = bitmap_vram;
+
+ hires = FALSE;
+ hires_dfile = 0;
+ last_I = 0x1e;
+ DrawScreen = DrawScreen_TEXT;
+
+ ClearBitmap();
/* Load the ROM
*/
@@ -602,7 +773,6 @@ void ZX81Init(uint16 *vram, Z80 *z80)
*/
memcpy(mem+ROMLEN,mem,ROMLEN);
-
/* Memory size (16K)
*/
RAMBOT=0x4000;
@@ -701,6 +871,7 @@ Z80Byte ZX81ReadPort(Z80 *z80, Z80Word port)
break;
default:
+ b = 0xff; /* Idle bus */
break;
}
@@ -732,6 +903,13 @@ void ZX81Reset(Z80 *z80)
Z80ResetCycles(z80,0);
started=FALSE;
+
+ hires = FALSE;
+ hires_dfile = 0;
+ last_I = 0x1e;
+ DrawScreen = DrawScreen_TEXT;
+
+ ClearBitmap();
}
@@ -748,20 +926,28 @@ void ZX81SetTape(const Z80Byte *image, int len)
}
+void ZX81SuspendDisplay(void)
+{
+ ClearBitmap();
+ ClearText();
+}
+
+
+void ZX81ResumeDisplay(void)
+{
+ ClearText();
+}
+
+
void ZX81DisplayString(const char *p)
{
uint16 *s;
uint16 inv=0;
int f;
- s = screen;
-
- for(f=0;f<TXT_W*TXT_H;f++)
- {
- *s++=0;
- }
+ ClearText();
- s = screen;
+ s = txt_screen;
f = 0;
while(*p)