diff options
author | Ian C <ianc@noddybox.co.uk> | 2010-11-26 15:00:08 +0000 |
---|---|---|
committer | Ian C <ianc@noddybox.co.uk> | 2010-11-26 15:00:08 +0000 |
commit | 5601353fc9cd66dbcca4d06fc7068af853317442 (patch) | |
tree | 88a85955b3fce3c4b23dbbeca623020328fb50e7 /source | |
parent | 1007ee9a4027826cf9c9067e0f1d1e1be1123b1f (diff) |
Diffstat (limited to 'source')
-rw-r--r-- | source/config.c | 145 | ||||
-rw-r--r-- | source/framebuffer.c | 386 | ||||
-rw-r--r-- | source/gui.c | 862 | ||||
-rw-r--r-- | source/keyboard.c | 483 | ||||
-rw-r--r-- | source/main.c | 461 | ||||
-rw-r--r-- | source/monitor.c | 362 | ||||
-rw-r--r-- | source/snapshot.c | 195 | ||||
-rw-r--r-- | source/stream.c | 86 | ||||
-rw-r--r-- | source/tapes.c | 282 | ||||
-rw-r--r-- | source/textmode.c | 157 | ||||
-rw-r--r-- | source/touchwrap.c | 55 | ||||
-rw-r--r-- | source/z80.c | 394 | ||||
-rw-r--r-- | source/z80_decode.c | 2533 | ||||
-rw-r--r-- | source/z80_dis.c | 2494 | ||||
-rw-r--r-- | source/zx81.c | 1171 |
15 files changed, 10066 insertions, 0 deletions
diff --git a/source/config.c b/source/config.c new file mode 100644 index 0000000..1bf2341 --- /dev/null +++ b/source/config.c @@ -0,0 +1,145 @@ +/* + ds81 - Nintendo DS ZX81 emulator. + + Copyright (C) 2006 Ian Cowburn <ianc@noddybox.co.uk> + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + 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. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + $Id: config.c 65 2008-12-12 00:19:08Z ianc $ +*/ + +#include <nds.h> +#include <stdio.h> +#include <string.h> + +#include "config.h" + +/* ---------------------------------------- PRIVATE DATA +*/ +const char *conf_filename = "DS81.CFG"; + +const char *conf_entry[DS81_NUM_CONFIG_ITEMS]= +{ + "sticky_shift", + "average_touchscreen", + "static_ram_at_0x2000", + "allow_tape_save", + "load_default_snapshot" +}; + + +/* ---------------------------------------- GLOBAL DATA +*/ +int DS81_Config[DS81_NUM_CONFIG_ITEMS]= +{ + TRUE, + FALSE, + FALSE, + FALSE, + FALSE +}; + + +/* ---------------------------------------- PUBLIC INTERFACES +*/ +int LoadConfig(void) +{ + FILE *fp = NULL; + +#ifndef DS81_DISABLE_FAT + fp=fopen(conf_filename,"r"); +#endif + + if (fp) + { + char line[80]; + + while(fgets(line, sizeof line, fp)) + { + char *p; + + if ((p = strchr(line, '='))) + { + int f; + + for(f=0;f<DS81_NUM_CONFIG_ITEMS;f++) + { + if (strncmp(line, conf_entry[f], + strlen(conf_entry[f])) == 0) + { + DS81_Config[f] = (*(p+1) == '1'); + } + } + + } + } + + fclose(fp); + + return TRUE; + } + + return FALSE; +} + +int SaveConfig(void) +{ + FILE *fp = NULL; + +#ifndef DS81_DISABLE_FAT + fp=fopen(conf_filename,"w"); +#endif + + if (fp) + { + int f; + + for(f=0;f<DS81_NUM_CONFIG_ITEMS;f++) + { + fprintf(fp,"%s=%d\n",conf_entry[f],DS81_Config[f]); + } + + fclose(fp); + + return TRUE; + } + + return FALSE; +} + +const char *ConfigDesc(DS81_ConfigItem item) +{ + switch(item) + { + case DS81_STICKY_SHIFT: + return "STICKY SHIFT"; + + case DS81_AVERAGE_TOUCHSCREEN: + return "AVERAGE TOUCHSCREEN"; + + case DS81_STATIC_RAM_AT_0x2000: + return "RAM AT 8192"; + + case DS81_LOAD_DEFAULT_SNAPSHOT: + return "LOAD DEFAULT SNAPSHOT"; + + case DS81_ALLOW_TAPE_SAVE: + return "ALLOW TAPE SAVING"; + + default: + return "UNKNOWN"; + } +} + diff --git a/source/framebuffer.c b/source/framebuffer.c new file mode 100644 index 0000000..0884f76 --- /dev/null +++ b/source/framebuffer.c @@ -0,0 +1,386 @@ +/* + ds81 - Nintendo DS ZX81 emulator. + + Copyright (C) 2006 Ian Cowburn <ianc@noddybox.co.uk> + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + 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. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + $Id: framebuffer.c 43 2007-03-12 00:59:51Z ianc $ +*/ + +#include <nds.h> +#include <stdio.h> +#include <stdarg.h> +#include <string.h> + +#include "framebuffer.h" + +/* ---------------------------------------- STATIC DATA +*/ +#define WIDTH 256 +#define SCAN 128 +#define HEIGHT 192 + +static uint16 *buff; +static uint16 *pal; + +static uint8 font[]= +{ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x08, 0x08, 0x08, 0x08, 0x00, 0x08, 0x00, + 0x00, 0x24, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x24, 0x7e, 0x24, 0x24, 0x7e, 0x24, 0x00, + 0x00, 0x10, 0x7c, 0x14, 0x7c, 0x50, 0x7c, 0x10, + 0x00, 0x46, 0x26, 0x10, 0x08, 0x64, 0x62, 0x00, + 0x00, 0x08, 0x14, 0x08, 0x54, 0x22, 0x5c, 0x00, + 0x00, 0x10, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x20, 0x10, 0x10, 0x10, 0x10, 0x20, 0x00, + 0x00, 0x04, 0x08, 0x08, 0x08, 0x08, 0x04, 0x00, + 0x00, 0x00, 0x28, 0x10, 0x7c, 0x10, 0x28, 0x00, + 0x00, 0x00, 0x10, 0x10, 0x7c, 0x10, 0x10, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x08, + 0x00, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, + 0x00, 0x00, 0x40, 0x20, 0x10, 0x08, 0x04, 0x00, + 0x00, 0x3c, 0x62, 0x52, 0x4a, 0x46, 0x3c, 0x00, + 0x00, 0x18, 0x14, 0x10, 0x10, 0x10, 0x7c, 0x00, + 0x00, 0x3c, 0x42, 0x40, 0x3c, 0x02, 0x7e, 0x00, + 0x00, 0x3c, 0x42, 0x30, 0x40, 0x42, 0x3c, 0x00, + 0x00, 0x10, 0x18, 0x14, 0x12, 0x7e, 0x10, 0x00, + 0x00, 0x7e, 0x02, 0x3e, 0x40, 0x42, 0x3c, 0x00, + 0x00, 0x3c, 0x02, 0x3e, 0x42, 0x42, 0x3c, 0x00, + 0x00, 0x7e, 0x40, 0x20, 0x10, 0x08, 0x08, 0x00, + 0x00, 0x3c, 0x42, 0x3c, 0x42, 0x42, 0x3c, 0x00, + 0x00, 0x3c, 0x42, 0x42, 0x7c, 0x40, 0x3c, 0x00, + 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x08, 0x00, + 0x00, 0x00, 0x08, 0x00, 0x00, 0x08, 0x08, 0x04, + 0x00, 0x00, 0x20, 0x10, 0x08, 0x10, 0x20, 0x00, + 0x00, 0x00, 0x00, 0x7c, 0x00, 0x7c, 0x00, 0x00, + 0x00, 0x00, 0x08, 0x10, 0x20, 0x10, 0x08, 0x00, + 0x00, 0x3c, 0x42, 0x20, 0x10, 0x00, 0x10, 0x00, + 0x00, 0x3c, 0x52, 0x6a, 0x7a, 0x02, 0x3c, 0x00, + 0x00, 0x3c, 0x42, 0x42, 0x7e, 0x42, 0x42, 0x00, + 0x00, 0x3e, 0x42, 0x3e, 0x42, 0x42, 0x3e, 0x00, + 0x00, 0x3c, 0x42, 0x02, 0x02, 0x42, 0x3c, 0x00, + 0x00, 0x1e, 0x22, 0x42, 0x42, 0x22, 0x1e, 0x00, + 0x00, 0x7e, 0x02, 0x3e, 0x02, 0x02, 0x7e, 0x00, + 0x00, 0x7e, 0x02, 0x3e, 0x02, 0x02, 0x02, 0x00, + 0x00, 0x3c, 0x42, 0x02, 0x72, 0x42, 0x3c, 0x00, + 0x00, 0x42, 0x42, 0x7e, 0x42, 0x42, 0x42, 0x00, + 0x00, 0x7c, 0x10, 0x10, 0x10, 0x10, 0x7c, 0x00, + 0x00, 0x40, 0x40, 0x40, 0x42, 0x42, 0x3c, 0x00, + 0x00, 0x22, 0x12, 0x0e, 0x12, 0x22, 0x42, 0x00, + 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x7e, 0x00, + 0x00, 0x42, 0x66, 0x5a, 0x42, 0x42, 0x42, 0x00, + 0x00, 0x42, 0x46, 0x4a, 0x52, 0x62, 0x42, 0x00, + 0x00, 0x3c, 0x42, 0x42, 0x42, 0x42, 0x3c, 0x00, + 0x00, 0x3e, 0x42, 0x42, 0x3e, 0x02, 0x02, 0x00, + 0x00, 0x3c, 0x42, 0x42, 0x4a, 0x52, 0x3c, 0x00, + 0x00, 0x3e, 0x42, 0x42, 0x3e, 0x22, 0x42, 0x00, + 0x00, 0x3c, 0x02, 0x3c, 0x40, 0x42, 0x3c, 0x00, + 0x00, 0x7f, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00, + 0x00, 0x42, 0x42, 0x42, 0x42, 0x42, 0x3c, 0x00, + 0x00, 0x42, 0x42, 0x42, 0x42, 0x24, 0x18, 0x00, + 0x00, 0x42, 0x42, 0x42, 0x42, 0x5a, 0x24, 0x00, + 0x00, 0x42, 0x24, 0x18, 0x18, 0x24, 0x42, 0x00, + 0x00, 0x41, 0x22, 0x14, 0x08, 0x08, 0x08, 0x00, + 0x00, 0x7e, 0x20, 0x10, 0x08, 0x04, 0x7e, 0x00, + 0x00, 0x70, 0x10, 0x10, 0x10, 0x10, 0x70, 0x00, + 0x00, 0x00, 0x02, 0x04, 0x08, 0x10, 0x20, 0x00, + 0x00, 0x0e, 0x08, 0x08, 0x08, 0x08, 0x0e, 0x00, + 0x00, 0x08, 0x1c, 0x2a, 0x08, 0x08, 0x08, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, + 0x00, 0x38, 0x44, 0x1e, 0x04, 0x04, 0x7e, 0x00, + 0x00, 0x00, 0x1c, 0x20, 0x3c, 0x22, 0x3c, 0x00, + 0x00, 0x04, 0x04, 0x3c, 0x44, 0x44, 0x3c, 0x00, + 0x00, 0x00, 0x38, 0x04, 0x04, 0x04, 0x38, 0x00, + 0x00, 0x20, 0x20, 0x3c, 0x22, 0x22, 0x3c, 0x00, + 0x00, 0x00, 0x1c, 0x22, 0x1e, 0x02, 0x3c, 0x00, + 0x00, 0x30, 0x08, 0x18, 0x08, 0x08, 0x08, 0x00, + 0x00, 0x00, 0x3c, 0x22, 0x22, 0x3c, 0x20, 0x1c, + 0x00, 0x02, 0x02, 0x1e, 0x22, 0x22, 0x22, 0x00, + 0x00, 0x08, 0x00, 0x0c, 0x08, 0x08, 0x1c, 0x00, + 0x00, 0x20, 0x00, 0x20, 0x20, 0x20, 0x24, 0x18, + 0x00, 0x04, 0x14, 0x0c, 0x0c, 0x14, 0x24, 0x00, + 0x00, 0x08, 0x08, 0x08, 0x08, 0x08, 0x30, 0x00, + 0x00, 0x00, 0x16, 0x2a, 0x2a, 0x2a, 0x2a, 0x00, + 0x00, 0x00, 0x1e, 0x22, 0x22, 0x22, 0x22, 0x00, + 0x00, 0x00, 0x1c, 0x22, 0x22, 0x22, 0x1c, 0x00, + 0x00, 0x00, 0x1e, 0x22, 0x22, 0x1e, 0x02, 0x02, + 0x00, 0x00, 0x3c, 0x22, 0x22, 0x3c, 0x20, 0x60, + 0x00, 0x00, 0x38, 0x04, 0x04, 0x04, 0x04, 0x00, + 0x00, 0x00, 0x1c, 0x02, 0x1c, 0x20, 0x1e, 0x00, + 0x00, 0x08, 0x1c, 0x08, 0x08, 0x08, 0x30, 0x00, + 0x00, 0x00, 0x22, 0x22, 0x22, 0x22, 0x1c, 0x00, + 0x00, 0x00, 0x22, 0x22, 0x14, 0x14, 0x08, 0x00, + 0x00, 0x00, 0x22, 0x2a, 0x2a, 0x2a, 0x14, 0x00, + 0x00, 0x00, 0x22, 0x14, 0x08, 0x14, 0x22, 0x00, + 0x00, 0x00, 0x22, 0x22, 0x22, 0x3c, 0x20, 0x1c, + 0x00, 0x00, 0x3e, 0x10, 0x08, 0x04, 0x3e, 0x00, + 0x00, 0x70, 0x10, 0x0c, 0x10, 0x10, 0x70, 0x00, + 0x00, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, + 0x00, 0x0e, 0x08, 0x30, 0x08, 0x08, 0x0e, 0x00, + 0x00, 0x28, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x3c, 0x42, 0x99, 0x85, 0x85, 0x99, 0x42, 0x3c +}; + + +/* ---------------------------------------- PRIVATE INTERFACES +*/ +static inline void Plot(int x, int y, int col) +{ + uint16 *base; + uint16 cur; + int odd; + + if (col == -1) + return; + + odd = x&1; + x /= 2; + + base = buff+x+y*SCAN; + cur = *base; + + if (odd) + { + cur = (cur & 0xff) | (col<<8); + } + else + { + cur = (cur & 0xff00) | col; + } + + *base = cur; +} + + +/* ---------------------------------------- PUBLIC INTERFACES +*/ +void FB_Init(uint16 *vram, uint16 *palette) +{ + buff = vram; + pal = palette; + + pal[COL_BLACK] = RGB15(0,0,0); + pal[COL_WHITE] = RGB15(31,31,31); + pal[COL_RED] = RGB15(31,0,0); + pal[COL_GREEN] = RGB15(0,31,0); + pal[COL_BLUE] = RGB15(0,0,31); + pal[COL_GUISELECT] = RGB15(8,8,31); + pal[COL_GREY] = RGB15(15,15,15); + pal[COL_LIGHTGREY] = RGB15(22,22,22); + pal[COL_DARKGREY] = RGB15(8,8,8); + pal[COL_YELLOW] = RGB15(31,31,0); +} + + +uint16 *FB_VRAM(void) +{ + return buff; +} + + +uint16 *FB_PALETTE(void) +{ + return pal; +} + + +void FB_LoadASCIITiles(uint16 *tiles) +{ + uint8 *src; + int c; + int row; + int val; + int mask; + + src = font; + + for(c = 32; c < 127; c++) + { + for(row = 0; row < 8; row++) + { + for(mask = 1; mask < 0xff; mask<<=1) + { + if (*src & mask) + { + val = COL_WHITE; + } + else + { + val = 0; + } + + mask <<= 1; + + if (*src & mask) + { + val |= COL_WHITE << 8; + } + + *tiles++ = val; + } + + src++; + } + } +} + + +void FB_Print(const char *text, int x, int y, FB_Colour colour, FB_Colour paper) +{ + int cx,cy; + int ch; + + while(*text) + { + ch=((*text)-32)*8; + + for(cy=0;cy<8;cy++) + { + for(cx=0;cx<8;cx++) + { + if (font[ch]&(1<<cx)) + { + Plot(x+cx, y+cy, colour); + } + else + { + Plot(x+cx, y+cy, paper); + } + } + + ch++; + } + + x+=8; + text++; + } +} + + +void FB_Centre(const char *text, int y, FB_Colour colour, FB_Colour paper) +{ + FB_Print(text,WIDTH/2-strlen(text)*4,y,colour,paper); +} + + +void FB_printf(int x, int y, FB_Colour colour, FB_Colour paper, + const char *format, ...) +{ + char buff[80]; + va_list va; + + va_start(va,format); + vsnprintf(buff,sizeof buff,format,va); + va_end(va); + + FB_Print(buff,x,y,colour,paper); +} + + +void FB_HLine(int x1, int x2, int y, FB_Colour colour) +{ + uint16 *line; + + line=buff+y*WIDTH+x1; + + while(x1<=x2) + { + Plot(x1++,y,colour); + } +} + + +void FB_VLine(int x, int y1, int y2, FB_Colour colour) +{ + while(y1<=y2) + { + Plot(x,y1++,colour); + } +} + + +void FB_Box(int x, int y, int w, int h, FB_Colour colour) +{ + FB_HLine(x,x+w-1,y,colour); + FB_HLine(x,x+w-1,y+h-1,colour); + FB_VLine(x,y,y+h-1,colour); + FB_VLine(x+w-1,y,y+h-1,colour); +} + + +void FB_FillBox(int x, int y, int w, int h, FB_Colour colour) +{ + while(h--) + { + FB_HLine(x,x+w-1,y++,colour); + } +} + + +void FB_Clear(void) +{ + uint16 *p; + int f; + + f=WIDTH*HEIGHT/2; + p=buff; + + while(f--) + { + *p++=0; + } +} + + +void FB_Blit(sImage *img, int x, int y, int offset) +{ + uint16 *dest; + uint16 *row; + uint8 *src; + uint16 pix; + int hww; + int ht; + int f; + + x /= 2; + + ht = img->height; + hww = img->width / 2; + dest = buff+x+y*SCAN; + src = img->image.data8; + + for(f=0;f<16;f++) + { + pal[offset+f] = img->palette[f]; + } + + while(ht--) + { + row = dest; + + for(f=0;f<hww;f++) + { + pix = *src++ + offset; + pix |= (*src++ + offset) << 8; + + *row++ = pix; + } + + dest += SCAN; + } +} diff --git a/source/gui.c b/source/gui.c new file mode 100644 index 0000000..d465aca --- /dev/null +++ b/source/gui.c @@ -0,0 +1,862 @@ +/* + ds81 - Nintendo DS ZX81 emulator. + + Copyright (C) 2006 Ian Cowburn <ianc@noddybox.co.uk> + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + 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. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + $Id: gui.c 75 2010-11-19 14:52:49Z ianc $ +*/ + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <nds.h> + +#include <sys/dir.h> + +#include "framebuffer.h" +#include "zx81.h" +#include "keyboard.h" +#include "config.h" + + +/* ---------------------------------------- PRIVATE INTERFACES - PATH HANDLING +*/ +#define FSEL_FILENAME_LEN 20 +#define FSEL_LINES 16 +#define FSEL_MAX_FILES 1024 + +#define FSEL_LIST_Y 10 +#define FSEL_LIST_H FSEL_LINES*8 + +typedef struct +{ + char name[FSEL_FILENAME_LEN+1]; + int is_dir; + int size; +} FSEL_File; + +static FSEL_File fsel[FSEL_MAX_FILES]; + + +static void CheckPath(char *path) +{ + size_t l; + + l = strlen(path); + + if (l == 1) + { + path[0] = '/'; + } + else + { + if (path[l-1] != '/') + { + path[l] = '/'; + path[l+1] = 0; + } + } +} + + +static void AddPath(char *path, const char *dir) +{ + if (strcmp(dir,"..") == 0) + { + size_t l; + + l = strlen(path); + + if (l > 1) + { + path[--l] = 0; + + while(l && path[l] != '/') + { + path[l--] = 0; + } + } + } + else + { + strcat(path,dir); + strcat(path,"/"); + } +} + + + + +static int SortFiles(const void *a, const void *b) +{ + const FSEL_File *f1; + const FSEL_File *f2; + + f1 = (const FSEL_File *)a; + f2 = (const FSEL_File *)b; + + if (f1->is_dir == f2->is_dir) + { + return strcasecmp(f1->name, f2->name); + } + else if (f1->is_dir) + { + return -1; + } + else + { + return 1; + } +} + + +static int ValidFilename(const char *name, int is_dir, const char *filter) +{ + size_t l; + size_t f; + + l = strlen(name); + + if (l > FSEL_FILENAME_LEN) + return 0; + + if (strcmp(name,".") == 0) + return 0; + + if (is_dir || !filter) + return 1; + + f = strlen(filter); + + if (l > f) + { + if (strcasecmp(name+l-f,filter) == 0) + { + return 1; + } + } + + return 0; +} + + +static int LoadDir(const char *path, const char *filter) +{ + DIR_ITER *dir; + struct stat st; + char name[FILENAME_MAX]; + int no = 0; + + if ((dir = diropen(path))) + { + while(no < FSEL_MAX_FILES && dirnext(dir,name,&st) == 0) + { + if (ValidFilename(name, (st.st_mode & S_IFDIR), filter)) + { + strcpy(fsel[no].name,name); + fsel[no].is_dir = (st.st_mode & S_IFDIR); + fsel[no].size = (int)st.st_size; + no++; + } + } + + dirclose(dir); + + qsort(fsel,no,sizeof fsel[0],SortFiles); + } + + return no; +} + + +/* ---------------------------------------- PUBLIC INTERFACES +*/ +int GUI_Menu(const char *opts[]) +{ + int x,y; + int h; + int w; + int no; + int sel; + int f; + int done; + int defer; + + w=0; + h=0; + sel=0; + done=FALSE; + defer=FALSE; + + for(no=0;opts[no];no++) + { + h+=16; + + if (strlen(opts[no])>w) + { + w=strlen(opts[no]); + } + } + + w=w*8+16; + + x=SCREEN_WIDTH/2-w/2; + y=2; + + while(!done) + { + uint32 key=0; + + FB_FillBox(x,y,w,h,COL_BLACK); + FB_Box(x,y,w,h,COL_WHITE); + FB_FillBox(x+1,y+sel*16+1,w-2,14,COL_GUISELECT); + + for(f=0;f<no;f++) + { + FB_Centre(opts[f],y+4+f*16,COL_WHITE,COL_TRANSPARENT); + } + + do + { + swiWaitForVBlank(); + } while(!defer && !(key=keysDownRepeat())); + + if (defer) + { + do + { + swiWaitForVBlank(); + } while (keysHeld()&KEY_TOUCH); + done=TRUE; + } + else + { + if (key & (KEY_A|KEY_B|KEY_X|KEY_Y)) + { + done=TRUE; + } + else if ((key & KEY_UP) && sel) + { + sel--; + } + else if ((key & KEY_DOWN) && sel<no-1) + { + sel++; + } + else if (key & KEY_TOUCH) + { + touchPosition tp; + + touchRead(&tp); + + if (tp.px>=x && tp.px<(w+w) && tp.py>=y && tp.py<(y+h)) + { + defer=TRUE; + sel=(tp.py-y)/16; + } + } + } + } + + return sel; +} + + +void GUI_Alert(int fatal, const char *text) +{ + char line[80]; + int h; + const char *p; + char *d; + + h=40; + p=text; + + while(*p) + { + if (*p++=='\n') + { + h+=8; + } + } + + FB_FillBox(0,0,SCREEN_WIDTH,h,COL_BLACK); + FB_Box(1,1,SCREEN_WIDTH-2,h-2,COL_WHITE); + + p=text; + h=4; + d=line; + + while(*p) + { + if (*p=='\n') + { + *d++=0; + p++; + FB_Centre(line,h,COL_WHITE,COL_TRANSPARENT); + h+=8; + d=line; + } + else + { + *d++=*p++; + } + } + + if (d>line) + { + *d=0; + FB_Centre(line,h,COL_WHITE,COL_TRANSPARENT); + h+=8; + } + + if (!fatal) + { + FB_Centre("PRESS ANY BUTTON OR SCREEN",h+16,COL_YELLOW,COL_TRANSPARENT); + + while(!keysDown()) + { + swiWaitForVBlank(); + } + + while(keysHeld()) + { + swiWaitForVBlank(); + } + } + else + { + FB_Centre("PLEASE RESET YOUR CONSOLE",h+16,COL_YELLOW,COL_TRANSPARENT); + + while(1) + { + swiWaitForVBlank(); + } + } +} + + +void GUI_Config(void) +{ + int sel; + DS81_ConfigItem f; + int done; + int save; + + sel = 0; + done = FALSE; + save = FALSE; + + FB_Clear(); + + FB_Centre("Up/Down to select",140,COL_YELLOW,COL_TRANSPARENT); + FB_Centre("A to toggle",150,COL_YELLOW,COL_TRANSPARENT); + FB_Centre("Or use touchscreen",160,COL_YELLOW,COL_TRANSPARENT); + FB_Centre("START to finish",170,COL_YELLOW,COL_TRANSPARENT); + +#ifndef DS81_DISABLE_FAT + FB_Centre("SELECT to finish and save",180,COL_YELLOW,COL_TRANSPARENT); +#endif + + for(f=0;f<DS81_NUM_CONFIG_ITEMS;f++) + { + FB_Print(ConfigDesc(f),14,20+f*14,COL_WHITE,COL_TRANSPARENT); + } + + while(!done) + { + uint32 key=0; + + for(f=0;f<DS81_NUM_CONFIG_ITEMS;f++) + { + FB_FillBox(2,20+f*14-1,10,10, + DS81_Config[f] ? COL_WHITE : COL_BLACK); + + FB_Box(2,20+f*14-1,10,10,COL_GREY); + } + + FB_Box(0,20+sel*14-3,SCREEN_WIDTH-1,14,COL_GUISELECT); + + do + { + swiWaitForVBlank(); + } while(!(key=keysDownRepeat())); + + FB_Box(0,20+sel*14-3,SCREEN_WIDTH-1,14,COL_BLACK); + + if (key & KEY_START) + { + done=TRUE; + } +#ifndef DS81_DISABLE_FAT + else if (key & KEY_SELECT) + { + done=TRUE; + save=TRUE; + } +#endif + else if (key & KEY_A) + { + DS81_Config[sel] = !DS81_Config[sel]; + } + else if ((key & KEY_UP) && sel) + { + sel--; + } + else if ((key & KEY_DOWN) && sel<DS81_NUM_CONFIG_ITEMS-1) + { + sel++; + } + else if (key & KEY_TOUCH) + { + touchPosition tp; + int nsel; + + touchRead(&tp); + + nsel = (tp.py-18)/14; + + if (nsel>=0 && nsel<DS81_NUM_CONFIG_ITEMS) + { + sel = nsel; + DS81_Config[sel] = !DS81_Config[sel]; + } + } + } + + if (save) + { + SaveConfig(); + } +} + + +int GUI_FileSelect(char pwd[], char selected_file[], const char *filter) +{ + int no; + int sel; + int top; + int bar_size; + double bar_step; + int done; + int ret; + FB_Colour paper; + int off; + int f; + int drag; + int drag_start; + + CheckPath(pwd); + + FB_Clear(); + + FB_printf(0,0,COL_BLACK,COL_LIGHTGREY,"%-32.32s",pwd); + + FB_Centre("Use pad and A to select",140,COL_YELLOW,COL_TRANSPARENT); + FB_Centre("L and R to page up/down",150,COL_YELLOW,COL_TRANSPARENT); + FB_Centre("Or use touchscreen",160,COL_YELLOW,COL_TRANSPARENT); + FB_Centre("B to cancel",170,COL_YELLOW,COL_TRANSPARENT); + + no = LoadDir(pwd,filter); + + sel = 0; + top = 0; + done = FALSE; + ret = FALSE; + drag = FALSE; + drag_start = 0; + + if (no<=FSEL_LINES) + { + bar_step = 0; + bar_size = FSEL_LIST_H; + } + else + { + bar_step = FSEL_LIST_H/(double)no; + bar_size = bar_step*FSEL_LINES; + } + + while(!done) + { + uint32 key=0; + + for (f=0;f<FSEL_LINES;f++) + { + off = f + top; + + if (off<no) + { + if (off == sel) + { + paper = COL_GUISELECT; + } + else + { + paper = COL_BLACK; + } + + FB_printf(8,FSEL_LIST_Y+f*8,COL_WHITE,paper, + "%-*s %s", + FSEL_FILENAME_LEN, + fsel[off].name, + fsel[off].is_dir ? "DIR" : " "); + } + else + { + FB_printf(8,FSEL_LIST_Y+f*8,COL_WHITE,COL_BLACK, + "%-*s %s", + FSEL_FILENAME_LEN, + off==0 ? "No Files!" : "", + " "); + } + } + + FB_FillBox(240,FSEL_LIST_Y,16,FSEL_LIST_H,COL_DARKGREY); + FB_FillBox(240,FSEL_LIST_Y+top*bar_step,16,bar_size,COL_WHITE); + + if (drag) + { + touchPosition tp = {0}; + int diff = 0; + + while (((key=keysHeld()) & KEY_TOUCH) && diff == 0) + { + touchRead(&tp); + diff = tp.py - drag_start; + swiWaitForVBlank(); + } + + if (key & KEY_TOUCH) + { + int new_top; + + new_top = top + diff / bar_step; + + if (new_top > (no - FSEL_LINES)) + { + new_top = no - FSEL_LINES; + } + + if (new_top < 0) + { + new_top = 0; + } + + if (new_top != top) + { + top = new_top; + sel = top; + drag_start = tp.py; + } + } + else + { + drag = FALSE; + } + } + + if (!drag) + { + int activate = FALSE; + + do + { + swiWaitForVBlank(); + } while(!(key=keysDownRepeat())); + + if (key & KEY_TOUCH) + { + touchPosition tp; + + touchRead(&tp); + + if (tp.py >= FSEL_LIST_Y && tp.py <= (FSEL_LIST_Y+FSEL_LIST_H)) + { + if (tp.px > 239) + { + drag = TRUE; + drag_start = tp.py; + } + else + { + int new_sel; + + new_sel = top + (tp.py - FSEL_LIST_Y)/8; + + if (new_sel < no) + { + if (new_sel == sel) + { + activate = TRUE; + } + else + { + sel = new_sel; + } + } + } + } + } + else if (key & KEY_UP) + { + if (sel) + { + sel--; + + if (sel<top) + { + top--; + } + } + } + else if (key & KEY_DOWN) + { + if (sel < (no-1)) + { + sel++; + + if (sel >= (top+FSEL_LINES)) + { + top++; + } + } + } + else if (key & KEY_L) + { + if (sel) + { + sel-=FSEL_LINES; + + if (sel < 0) + { + sel = 0; + } + + top = sel; + } + } + else if (key & KEY_R) + { + if (sel < (no-1)) + { + sel+=FSEL_LINES; + + if (sel > (no-1)) + { + sel = no-1; + } + + top = sel - FSEL_LINES + 1; + + if (top < 0) + { + top = 0; + } + } + } + else if (key & KEY_A) + { + activate = TRUE; + } + else if (key & KEY_B) + { + done = TRUE; + } + + if (activate) + { + if (fsel[sel].is_dir) + { + AddPath(pwd,fsel[sel].name); + + FB_printf(0,0,COL_BLACK,COL_LIGHTGREY,"%-32.32s",pwd); + + no = LoadDir(pwd,filter); + + sel = 0; + top = 0; + + if (no<=FSEL_LINES) + { + bar_step = 0; + bar_size = FSEL_LIST_H; + } + else + { + bar_step = FSEL_LIST_H/(double)no; + bar_size = bar_step*FSEL_LINES; + } + } + else + { + done = TRUE; + ret = TRUE; + + strcpy(selected_file,pwd); + strcat(selected_file,fsel[sel].name); + } + } + } + } + + while (keysHeld()); + + return ret; +} + + +int GUI_InputName(const char *prompt, const char *ext, char name[], int maxlen) +{ + struct + { + SoftKey key; + int ascii; + } keymap[] = + { + {SK_1, '1'}, + {SK_2, '2'}, + {SK_3, '3'}, + {SK_4, '4'}, + {SK_5, '5'}, + {SK_6, '6'}, + {SK_7, '7'}, + {SK_8, '8'}, + {SK_9, '9'}, + {SK_0, '0'}, + {SK_A, 'A'}, + {SK_B, 'B'}, + {SK_C, 'C'}, + {SK_D, 'D'}, + {SK_E, 'E'}, + {SK_F, 'F'}, + {SK_G, 'G'}, + {SK_H, 'H'}, + {SK_I, 'I'}, + {SK_J, 'J'}, + {SK_K, 'K'}, + {SK_L, 'L'}, + {SK_M, 'M'}, + {SK_N, 'N'}, + {SK_O, 'O'}, + {SK_P, 'P'}, + {SK_Q, 'Q'}, + {SK_R, 'R'}, + {SK_S, 'S'}, + {SK_T, 'T'}, + {SK_U, 'U'}, + {SK_V, 'V'}, + {SK_W, 'W'}, + {SK_X, 'X'}, + {SK_Y, 'Y'}, + {SK_Z, 'Z'}, + {0, 0} + }; + + SoftKeyEvent ev; + char text[1024]; + int done = FALSE; + int accept = FALSE; + int update = TRUE; + + SK_DisplayKeyboard(); + ZX81SuspendDisplay(); + + name[0] = 0; + + while(!done) + { + if (update) + { + sprintf(text, "%s:\n" + "\"%s%%l%%%s\"" + "\n\n\npress enter to accept.\n" + "press period to backspace.\n" + "press space/break to cancel.\n", + prompt, name, ext); + + ZX81DisplayString(text); + + update = FALSE; + } + + while(SK_GetBareEvent(&ev)) + { + if (!ev.pressed) + { + size_t l; + int f; + int ascii; + + l = strlen(name); + + switch(ev.key) + { + case SK_PERIOD: + if (l) + { + name[--l] = 0; + update = TRUE; + } + break; + + case SK_SPACE: + done = TRUE; + accept = FALSE; + break; + + case SK_NEWLINE: + done = TRUE; + accept = TRUE; + break; + + default: + if (l < maxlen) + { + f = 0; + ascii = 0; + + while(!ascii && keymap[f].ascii) + { + if (ev.key == keymap[f].key) + { + ascii = keymap[f].ascii; + } + + f++; + } + + if (ascii) + { + name[l++] = ascii; + name[l] = 0; + update = TRUE; + } + } + break; + } + } + } + + swiWaitForVBlank(); + } + + ZX81ResumeDisplay(); + + return accept; +} + diff --git a/source/keyboard.c b/source/keyboard.c new file mode 100644 index 0000000..001d906 --- /dev/null +++ b/source/keyboard.c @@ -0,0 +1,483 @@ +/* + ds81 - Nintendo DS ZX81 emulator. + + Copyright (C) 2006 Ian Cowburn <ianc@noddybox.co.uk> + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + 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. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + $Id: keyboard.c 64 2008-12-05 00:37:26Z ianc $ +*/ + +#include <nds.h> + +#include "keyboard.h" +#include "framebuffer.h" +#include "touchwrap.h" +#include "keyb_bin.h" +#include "stream.h" + +/* ---------------------------------------- STATIC DATA +*/ + +#define PAL_OFFSET 110 + +static int is_dim = FALSE; +static int selection_on = COL_WHITE; +static int selection_off = COL_BLACK; + +static struct +{ + int state; + int new_state; + int handled; + int is_sticky; +} key_state[NUM_SOFT_KEYS]; + +static SoftKey pad_left_key = SK_5; +static SoftKey pad_right_key = SK_8; +static SoftKey pad_up_key = SK_7; +static SoftKey pad_down_key = SK_6; +static SoftKey pad_A_key = SK_0; +static SoftKey pad_B_key = SK_NEWLINE; +static SoftKey pad_X_key = NUM_SOFT_KEYS; +static SoftKey pad_Y_key = NUM_SOFT_KEYS; +static SoftKey pad_R_key = NUM_SOFT_KEYS; +static SoftKey pad_L_key = NUM_SOFT_KEYS; +static SoftKey pad_start_key = NUM_SOFT_KEYS; +static SoftKey pad_select_key = NUM_SOFT_KEYS; + +#define CLEAR_STATE(SHORTCUT) \ + do \ + { \ + if (SHORTCUT != NUM_SOFT_KEYS && \ + !key_state[SHORTCUT].handled) \ + { \ + key_state[SHORTCUT].new_state = FALSE; \ + } \ + } while(0) + +#define CHECK_STATE(KEYS,BIT,CODE,SHORTCUT,USE_SHORTCUT) \ + do \ + { \ + key_state[CODE].new_state = (KEYS & BIT); \ + if (USE_SHORTCUT && SHORTCUT != NUM_SOFT_KEYS && \ + !key_state[SHORTCUT].handled && (KEYS & BIT)) \ + { \ + key_state[SHORTCUT].new_state = TRUE; \ + } \ + } while(0) + + +static const char *keynames[]= +{ + "1", "2", "3", "4", "5", + "6", "7", "8", "9", "0", + "Q", "W", "E", "R", "T", + "Y", "U", "I", "O", "P", + "A", "S", "D", "F", "G", + "H", "J", "K", "L", "NEWLINE", + "SHIFT", "Z", "X", "C", "V", + "B", "N", "M", "PERIOD", "SPACE", + + "ABOUT", + "CONFIG", + "JOYPAD UP", + "JOYPAD DOWN", + "JOYPAD LEFT", + "JOYPAD RIGHT", + "A BUTTON", + "B BUTTON", + "X BUTTON", + "Y BUTTON", + "RIGHT SHOULDER BUTTON", + "LEFT SHOULDER BUTTON", + "START BUTTON", + "SELECT BUTTON" +}; + +/* ---------------------------------------- PRIVATE INTERFACES +*/ +static SoftKey LocatePress(const touchPosition *p) +{ + int kx=0,ky=0; + int py=0; + SoftKey key = NUM_SOFT_KEYS; + + if (p->py > 36 && p->px > 2) + { + kx = (p->px - 3) / 25; + ky = p->py - 37; + + py = ky % 30; + ky /= 30; + + if (py<17 && kx >= 0 && kx<10 && ky>=0 && ky<=4) + { + key = kx + ky * 10; + } + } + + if (key>SK_SPACE) + { + key = NUM_SOFT_KEYS; + } + + return key; +} + + +static int GetEvent(SoftKeyEvent *ev, int map) +{ + static SoftKey last = NUM_SOFT_KEYS; + static int poll_index = -1; + + /* Read the keys if this is a new loop + */ + if (poll_index == -1) + { + int f; + uint32 keys; + + keys = keysHeld(); + + /* Clear the non-sticky keys + */ + for(f=SK_1; f<=SK_CONFIG; f++) + { + key_state[f].handled = FALSE; + + if (key_state[f].is_sticky) + { + key_state[f].new_state = key_state[f].state; + } + else + { + key_state[f].new_state = FALSE; + } + } + + /* Check the soft keyboard + */ + if (keys & KEY_TOUCH) + { + touchPosition tp; + + if (AllowTouch(&tp)) + { + if (tp.py<21 || tp.py>165) + { + key_state[SK_CONFIG].new_state = TRUE; + } + else + { + SoftKey press; + + press = LocatePress(&tp); + + if (press != NUM_SOFT_KEYS) + { + key_state[press].handled = TRUE; + + if (key_state[press].is_sticky) + { + if (last != press) + { + key_state[press].new_state = + !key_state[press].state; + } + } + else + { + key_state[press].new_state = TRUE; + } + + last = press; + } + } + } + } + else + { + last = NUM_SOFT_KEYS; + } + + /* Check non soft-keyboard controls + */ + CHECK_STATE(keys, KEY_A, SK_PAD_A, pad_A_key, map); + CHECK_STATE(keys, KEY_B, SK_PAD_B, pad_B_key, map); + CHECK_STATE(keys, KEY_X, SK_PAD_X, pad_X_key, map); + CHECK_STATE(keys, KEY_Y, SK_PAD_Y, pad_Y_key, map); + CHECK_STATE(keys, KEY_R, SK_PAD_R, pad_R_key, map); + CHECK_STATE(keys, KEY_L, SK_PAD_L, pad_L_key, map); + CHECK_STATE(keys, KEY_START, SK_PAD_START, pad_start_key, map); + CHECK_STATE(keys, KEY_SELECT, SK_PAD_SELECT, pad_select_key, map); + CHECK_STATE(keys, KEY_UP, SK_PAD_UP, pad_up_key, map); + CHECK_STATE(keys, KEY_DOWN, SK_PAD_DOWN, pad_down_key, map); + CHECK_STATE(keys, KEY_LEFT, SK_PAD_LEFT, pad_left_key, map); + CHECK_STATE(keys, KEY_RIGHT, SK_PAD_RIGHT, pad_right_key, map); + + /* Reset key event poll index + */ + poll_index = 0; + + /* Update any on-screen indicators + */ + for(f=SK_1; f<SK_CONFIG; f++) + { + if (key_state[f].state != key_state[f].new_state) + { + int x,y; + + x = 3 + (f % 10) * 25; + y = 37 + (f / 10) * 30; + + FB_Box(x, y, 25, 18, key_state[f].new_state ? + selection_on : selection_off); + } + } + } + + while(poll_index < NUM_SOFT_KEYS && + key_state[poll_index].state == key_state[poll_index].new_state) + { + poll_index++; + } + + if (poll_index < NUM_SOFT_KEYS) + { + key_state[poll_index].state = key_state[poll_index].new_state; + + ev->key = poll_index; + ev->pressed = key_state[poll_index].state; + + return TRUE; + } + else + { + poll_index = -1; + return FALSE; + } +} + + +/* ---------------------------------------- PUBLIC INTERFACES +*/ +void SK_DisplayKeyboard(void) +{ + static sImage img; + static int loaded; + int f; + + if (!loaded) + { + loadPCX(keyb_bin,&img); + loaded = true; + } + + FB_Blit(&img,0,0,PAL_OFFSET); + + /* Update any on-screen indicators + */ + for(f=SK_1; f<SK_CONFIG; f++) + { + if (key_state[f].state) + { + int x,y; + + x = 3 + (f % 10) * 25; + y = 37 + (f / 10) * 30; + + FB_Box(x, y, 25, 18, key_state[f].new_state ? + selection_on : selection_off); + } + } +} + + +void SK_SetDisplayBrightness(int dim) +{ + static uint16 saved_pal[16]; + int f; + uint16 *pal; + + pal = FB_PALETTE(); + + if (dim != is_dim) + { + is_dim = dim; + + if (is_dim) + { + selection_on = COL_DARKGREY; + + for(f=0;f<16;f++) + { + int r,g,b; + + saved_pal[f] = pal[PAL_OFFSET + f]; + + r = saved_pal[f] & 0x1f; + g = (saved_pal[f]>>5) & 0x1f; + b = (saved_pal[f]>>10) & 0x1f; + + r/=3; + g/=3; + b/=3; + + pal[PAL_OFFSET + f] = RGB15(r,g,b); + } + } + else + { + selection_on = COL_WHITE; + + for(f=0;f<16;f++) + { + pal[PAL_OFFSET + f] = saved_pal[f]; + } + } + } +} + + +int SK_GetEvent(SoftKeyEvent *ev) +{ + return GetEvent(ev,TRUE); +} + + +int SK_GetBareEvent(SoftKeyEvent *ev) +{ + return GetEvent(ev,FALSE); +} + + +void SK_SetSticky(SoftKey key, int is_sticky) +{ + key_state[key].is_sticky = is_sticky; + + if (!is_sticky) + { + key_state[key].new_state = FALSE; + } +} + + +void SK_DefinePad(SoftKey pad, SoftKey key) +{ + switch(pad) + { + case SK_PAD_LEFT: + pad_left_key = key; + break; + case SK_PAD_RIGHT: + pad_right_key = key; + break; + case SK_PAD_UP: + pad_up_key = key; + break; + case SK_PAD_DOWN: + pad_down_key = key; + break; + case SK_PAD_A: + pad_A_key = key; + break; + case SK_PAD_B: + pad_B_key = key; + break; + case SK_PAD_X: + pad_X_key = key; + break; + case SK_PAD_Y: + pad_Y_key = key; + break; + case SK_PAD_R: + pad_R_key = key; + break; + case SK_PAD_L: + pad_L_key = key; + break; + case SK_PAD_START: + pad_start_key = key; + break; + case SK_PAD_SELECT: + pad_select_key = key; + break; + default: + break; + } +} + + +const char *SK_KeyName(SoftKey k) +{ + return keynames[k]; +} + + +void SK_SaveSnapshot(FILE *fp) +{ + int f; + + PUT_Long(fp, pad_left_key); + PUT_Long(fp, pad_right_key); + PUT_Long(fp, pad_up_key); + PUT_Long(fp, pad_down_key); + PUT_Long(fp, pad_A_key); + PUT_Long(fp, pad_B_key); + PUT_Long(fp, pad_X_key); + PUT_Long(fp, pad_Y_key); + PUT_Long(fp, pad_R_key); + PUT_Long(fp, pad_L_key); + PUT_Long(fp, pad_start_key); + PUT_Long(fp, pad_select_key); + + for(f = 0; f < NUM_SOFT_KEYS; f++) + { + PUT_Long(fp, key_state[f].state); + PUT_Long(fp, key_state[f].new_state); + PUT_Long(fp, key_state[f].handled); + PUT_Long(fp, key_state[f].is_sticky); + } +} + + +void SK_LoadSnapshot(FILE *fp) +{ + int f; + + pad_left_key = GET_Long(fp); + pad_right_key = GET_Long(fp); + pad_up_key = GET_Long(fp); + pad_down_key = GET_Long(fp); + pad_A_key = GET_Long(fp); + pad_B_key = GET_Long(fp); + pad_X_key = GET_Long(fp); + pad_Y_key = GET_Long(fp); + pad_R_key = GET_Long(fp); + pad_L_key = GET_Long(fp); + pad_start_key = GET_Long(fp); + pad_select_key = GET_Long(fp); + + for(f = 0; f < NUM_SOFT_KEYS; f++) + { + key_state[f].state = GET_Long(fp); + key_state[f].new_state = GET_Long(fp); + key_state[f].handled = GET_Long(fp); + key_state[f].is_sticky = GET_Long(fp); + } +} + + diff --git a/source/main.c b/source/main.c new file mode 100644 index 0000000..349e49e --- /dev/null +++ b/source/main.c @@ -0,0 +1,461 @@ +/* + ds81 - Nintendo DS ZX81 emulator. + + Copyright (C) 2006 Ian Cowburn <ianc@noddybox.co.uk> + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + 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. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + $Id: main.c 77 2010-11-23 08:10:25Z ianc $ +*/ + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <nds.h> +#include <fat.h> + +#include "framebuffer.h" +#include "gui.h" +#include "keyboard.h" +#include "z80.h" +#include "zx81.h" +#include "tapes.h" +#include "config.h" +#include "textmode.h" +#include "monitor.h" +#include "snapshot.h" + +#include "splashimg_bin.h" +#include "rom_font_bin.h" + +#include "ds81_debug.h" + +#ifndef DS81_VERSION +#define DS81_VERSION "DEV " __TIME__ "/" __DATE__ +#endif + + +/* ---------------------------------------- STATIC DATA +*/ +static const char *main_menu[]= + { + "Reset ZX81", + "Select Tape", + "Configure", + "Map Joypad to Keys", + "Machine Code Monitor", +#ifndef DS81_DISABLE_FAT + "Save Memory Snapshot", + "Load Memory Snapshot", + "Save Joypad/Key State", + "Load Joypad/Key State", +#endif + "Cancel", + NULL + }; + +typedef enum +{ + MenuReset, + MenuSelectTape, + MenuConfigure, + MenuMapJoypad, + MenuMonitor, +#ifndef DS81_DISABLE_FAT + MenuSaveSnapshot, + MenuLoadSnapshot, + MenuSaveMappings, + MenuLoadMappings +#endif +} MenuOpt; + + +/* Backgrounds +*/ +static int main_bitmap_bg; +static int main_text_overlay_bg; +static int sub_bitmap_bg; +static int sub_text_overlay_bg; + +/* ---------------------------------------- IRQ FUNCS +*/ + +/* ---------------------------------------- DISPLAY FUNCS +*/ +static void VBlankFunc(void) +{ + scanKeys(); +} + +static void Splash(void) +{ + static char scroller[]= + { + " " + "Welcome to DS81, a ZX81 emulator for the Ninetendo DS. " + "You can safely ignore this message. I was just bored for half an " + "hour. And no retro game is complete without a side-scroller... " + "Thanks to Slay Radio, Ladytron, the Genki Rockets, the High " + "Voltage SID Collection and Retro Gamer for coding fuel." + }; + + static const char *text[]= + { + "DS81 \177 2006 Ian C", + " ", + "ZX81 ROM \177 1981", + "Nine Tiles Networks LTD", + " ", + "PRESS A TO CONTINUE", + " ", + "http://www.noddybox.co.uk/", + " ", + " ", + " ", + " ", + "Checking for FAT device...", + NULL + }; + + sImage img; + int f; + int y; + int res=FALSE; + int scr_x=0; + + ZX81SuspendDisplay(); + ZX81DisplayString("10 rem " DS81_VERSION "\n" + "20 print \"%the zx81 is ace%\"\n" + "30 goto 20"); + + bgSetScale(sub_text_overlay_bg, 0x80, 0x80); + + TM_printf(0,11,"%-18.18s",scroller); + + FB_Clear(); + + loadPCX(splashimg_bin,&img); + + FB_Blit(&img,0,0,1); + + y = 10; + + for(f=0;text[f];f++) + { + FB_Centre(text[f],y,COL_WHITE,COL_TRANSPARENT); + y += 8; + } + + y += 8; + +#ifndef DS81_DISABLE_FAT + res = fatInitDefault(); +#endif + + if (res) + { + ZX81EnableFileSystem(TRUE); + SNAP_Enable(TRUE); + + FB_Centre("Found a FAT device.",y,COL_WHITE,COL_TRANSPARENT); + y += 8; + + FB_Centre("If you place .P tape files in",y,COL_WHITE,COL_TRANSPARENT); + y += 8; + + FB_Centre("the top directory or ZX81SNAP",y,COL_WHITE,COL_TRANSPARENT); + y += 8; + + FB_Centre("then you should be able to load",y, + COL_WHITE,COL_TRANSPARENT); + y += 8; + + FB_Centre("GAME.P with the command",y,COL_WHITE,COL_TRANSPARENT); + y += 8; + + FB_Centre("LOAD \"GAME\"",y,COL_WHITE,COL_TRANSPARENT); + y += 8; + } + else + { + ZX81EnableFileSystem(FALSE); + SNAP_Enable(FALSE); + + FB_Centre("Sorry, but you don't have a",y,COL_WHITE,COL_TRANSPARENT); + y += 8; + + FB_Centre("supported FAT device.",y,COL_WHITE,COL_TRANSPARENT); + y += 8; + + FB_Centre("Only the internal tape",y,COL_WHITE,COL_TRANSPARENT); + y += 8; + + FB_Centre("files can be used.",y,COL_WHITE,COL_TRANSPARENT); + y += 8; + } + + while(!(keysDown() & KEY_A)) + { + swiWaitForVBlank(); + + if (++scr_x == 8) + { + size_t l = sizeof scroller; + char c; + + scr_x = 0; + + c = scroller[0]; + memmove(scroller,scroller+1,l-2); + scroller[l-2] = c; + + TM_printf(0,11,"%-18.18s",scroller); + } + + bgSetScroll(sub_text_overlay_bg, scr_x << 8, 0); + bgUpdate(); + } + + bgSetScale(sub_text_overlay_bg, 0x100, 0x100); + bgSetScroll(sub_text_overlay_bg, 0, 0); + bgUpdate(); + + TM_Cls(); + + ZX81ResumeDisplay(); +} + + +/* ---------------------------------------- JOYPAD MAPPING +*/ +static void MapJoypad(void) +{ + SoftKeyEvent ev; + SoftKey pad = NUM_SOFT_KEYS; + int done = FALSE; + char text[256]; + + SK_DisplayKeyboard(); + + ZX81SuspendDisplay(); + + ZX81DisplayString("press the joypad button you want\n" + "to define and then the ZX81 key\n" + "you want to use.\n\n" + "press on the config banner to\n" + "finish."); + + while(!done) + { + while(SK_GetBareEvent(&ev)) + { + if (ev.pressed) + { + if (ev.key==SK_ABOUT || ev.key==SK_CONFIG) + { + done = true; + } + } + else + { + if (ev.key>=SK_PAD_UP && ev.key<=SK_PAD_SELECT) + { + pad = ev.key; + + /* Now, just how dumb was making % the inverse on/off... + */ + sprintf(text,"defining\n %%%s%%",SK_KeyName(pad)); + ZX81DisplayString(text); + } + + if (ev.key<=SK_SPACE && pad!=NUM_SOFT_KEYS) + { + sprintf(text,"mapped\n %%%s%%\nto\n %%%s%%", + SK_KeyName(pad),SK_KeyName(ev.key)); + ZX81DisplayString(text); + + SK_DefinePad(pad,ev.key); + + pad = NUM_SOFT_KEYS; + } + } + } + + swiWaitForVBlank(); + } + + ZX81ResumeDisplay(); +} + + +/* ---------------------------------------- MAIN +*/ +int main(int argc, char *argv[]) +{ + Z80 *z80; + + powerOn(POWER_ALL_2D); + + /* Set up main screen for ZX81 and load the ROM character data + */ + videoSetMode(MODE_3_2D); + + vramSetBankA(VRAM_A_MAIN_BG_0x06000000); + vramSetBankB(VRAM_B_MAIN_BG_0x06020000); + + main_bitmap_bg = bgInit(3, BgType_Bmp16, BgSize_B16_256x256, 2, 0); + main_text_overlay_bg = bgInit(0, BgType_Text8bpp, BgSize_T_256x256, 0, 1); + + bgSetPriority(main_bitmap_bg, 1); + bgSetPriority(main_text_overlay_bg, 0); + + BG_PALETTE[0] = RGB15(31,31,31); + BG_PALETTE[1] = RGB15(0,0,0); + + dmaCopy(rom_font_bin,(void *)BG_TILE_RAM(1),rom_font_bin_size); + + /* Set up the sub-screen for rotation (basically for use as a framebuffer). + Now overlaid with a text screen for the monitor (I thought a bitmapped + printing routine would needlessly slow down the monitor when watching + the ZX81 run). Having said the overlay is currently a rotation map + for some pointless frippery! Still be quicker though. + */ + videoSetModeSub(MODE_4_2D); + + vramSetBankC(VRAM_C_SUB_BG_0x06200000); + + sub_bitmap_bg = bgInitSub(3, BgType_Bmp8, BgSize_B8_256x256, 1, 0); + sub_text_overlay_bg = bgInitSub(2, BgType_Rotation, BgSize_R_256x256, 4, 0); + + bgSetPriority(sub_bitmap_bg, 1); + bgSetPriority(sub_text_overlay_bg, 0); + + /* Tell 'framebuffer' routines to use this + */ + FB_Init((uint16*)BG_BMP_RAM_SUB(1), BG_PALETTE_SUB); + + /* Set up lower screen text overlay + */ + FB_LoadASCIITiles((uint16*)BG_TILE_RAM_SUB(0)); + TM_Init((uint16*)BG_MAP_RAM_SUB(4),32,32,TRUE); + + /* Set up interrupts and timers + */ + irqInit(); + irqSet(IRQ_VBLANK,VBlankFunc); + irqEnable(IRQ_VBLANK); + + /* All required stuff initialised + */ + keysSetRepeat(30,15); + + z80 = Z80Init(ZX81ReadMem, + ZX81WriteMem, + ZX81ReadPort, + ZX81WritePort, + ZX81ReadDisassem); + + if (!z80) + { + GUI_Alert(TRUE,"Failed to initialise\nthe Z80 CPU emulation!"); + } + + ZX81Init((uint16*)BG_MAP_RAM(0), (uint16*)BG_BMP_RAM(2), z80); + + Splash(); + + LoadConfig(); + ZX81Reconfigure(); + + SK_DisplayKeyboard(); + + SK_SetSticky(SK_SHIFT,DS81_Config[DS81_STICKY_SHIFT]); + + if (DS81_Config[DS81_LOAD_DEFAULT_SNAPSHOT]) + { + SNAP_Load(z80, "AUTO", SNAP_TYPE_FULL); + } + + while(1) + { + SoftKeyEvent ev; + + Z80Exec(z80); + + while(SK_GetEvent(&ev)) + { + switch(ev.key) + { + case SK_ABOUT: + case SK_CONFIG: + if (ev.pressed) + { + switch(GUI_Menu(main_menu)) + { + case MenuReset: + ZX81Reset(z80); + break; + + case MenuSelectTape: + SelectTape(); + break; + + case MenuConfigure: + GUI_Config(); + SK_SetSticky(SK_SHIFT, + DS81_Config[DS81_STICKY_SHIFT]); + ZX81Reconfigure(); + break; + + case MenuMapJoypad: + MapJoypad(); + break; + + case MenuMonitor: + MachineCodeMonitor(z80); + break; + +#ifndef DS81_DISABLE_FAT + case MenuSaveSnapshot: + SNAP_Save(z80, SNAP_TYPE_FULL); + break; + + case MenuLoadSnapshot: + SNAP_Load(z80, NULL, SNAP_TYPE_FULL); + break; + + case MenuSaveMappings: + SNAP_Save(z80, SNAP_TYPE_KEYBOARD); + break; + + case MenuLoadMappings: + SNAP_Load(z80, NULL, SNAP_TYPE_KEYBOARD); + break; +#endif + } + + SK_DisplayKeyboard(); + } + break; + + default: + ZX81HandleKey(ev.key,ev.pressed); + break; + } + } + } + + return 0; +} diff --git a/source/monitor.c b/source/monitor.c new file mode 100644 index 0000000..5ba370d --- /dev/null +++ b/source/monitor.c @@ -0,0 +1,362 @@ +/* + ds81 - Nintendo DS ZX81 emulator. + + Copyright (C) 2006 Ian Cowburn <ianc@noddybox.co.uk> + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + 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. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + $Id: monitor.c 48 2007-03-25 19:06:31Z ianc $ +*/ + +#include <nds.h> +#include <stdlib.h> + +#include "monitor.h" +#include "keyboard.h" +#include "textmode.h" +#include "framebuffer.h" +#include "zx81.h" +#include "config.h" + +/* ---------------------------------------- PRIVATE DATA AND TYPES +*/ +typedef enum +{ + DISPLAY_ADDR, + DISPLAY_HL, + DISPLAY_IX, + DISPLAY_SP, + DISPLAY_IY, + DISPLAY_BC, + DISPLAY_DE, + DISPLAY_PC, + DISPLAY_TYPE_COUNT +} MemDisplayType; + +typedef enum +{ + MODE_CPU_STATE, + MODE_HEX, + MODE_ASSEM, + MODE_TYPE_COUNT +} DisplayModeType; + + +/* ---------------------------------------- STATIC INTERFACES +*/ +static void DisplayHelp() +{ + static const char *help[]= + { + /* 12345678901234567890123456789012 */ + "MONITOR HELP", + "", + "Click on the config bar to exit.", + "", + "Press START to toggle between", + "single step mode and running.", + "", + "Press SELECT to toggle between", + "CPU info and memory display.", + "", + "In single step mode press A", + "to execute next instruction.", + "", + "Use L/R (+ Y for larger jumps)", + "to alter address in mem display.", + "", + "Press B to cycle between address", + "and register memory display.", + "", + "Note that all numbers are in hex", + "and the all keyboard keys are", + "sticky until the monitor exits.", + "", + "Press X to continue", + NULL + }; + + int f; + + TM_Cls(); + + for(f=0; help[f]; f++) + { + TM_Put(0,f,help[f]); + } + + while(!(keysDownRepeat() & KEY_X)) + { + swiWaitForVBlank(); + } +} + +static void DisplayRunningState(int running) +{ + if (running) + { + TM_Put(0,23,"RUNNING [PRESS X FOR HELP]"); + } + else + { + TM_Put(0,23,"SINGLE STEP [PRESS X FOR HELP]"); + } +} + + +static void DisplayCPU(Z80 *cpu) +{ + static const char *flag_char = "SZ5H3PNC"; + Z80Word tmp; + int f; + char flags[]="--------"; + + tmp = cpu->PC; + + /* Display disassembly + */ + for(f=0;f<17;f++) + { + /* These may seem a bit convuluted, but there's no point being at home + to Mr Undefined Behaviour + */ + TM_printf(0,f,"%c%4.4x:",f==0 ? '>':' ',tmp); + TM_Put(7,f,Z80Disassemble(cpu,&tmp)); + } + + /* Display process state + */ + tmp = cpu->AF.b[Z80_LO_WORD]; + + for(f=0;f<8;f++) + { + if (tmp & 1<<(7-f)) + { + flags[f] = flag_char[f]; + } + } + + TM_printf(0,18,"A:%2.2x F:%s IM:%2.2x", + cpu->AF.b[Z80_HI_WORD],flags,cpu->IM); + + TM_printf(0,19,"BC:%4.4x DE:%4.4x HL:%4.4x", + cpu->BC.w,cpu->DE.w,cpu->HL.w); + + TM_printf(0,20,"IX:%4.4x IY:%4.4x SP:%4.4x", + cpu->IX.w,cpu->IY.w,cpu->SP); + + TM_printf(0,21,"PC:%4.4x IF:%d/%d IR:%2.2x%2.2x", + cpu->PC,cpu->IFF1,cpu->IFF2,cpu->I,cpu->R); +} + + +static void DisplayMem(Z80 *cpu, MemDisplayType disp, Z80Word addr, int as_hex) +{ + static const char *label[]= + { + "Address", + "HL", + "IX", + "SP", + "IY", + "BC", + "DE", + "PC" + }; + + int x,y; + + switch(disp) + { + case DISPLAY_HL: + addr = cpu->HL.w; + break; + + case DISPLAY_IX: + addr = cpu->IX.w; + break; + + case DISPLAY_SP: + addr = cpu->SP; + break; + + case DISPLAY_IY: + addr = cpu->IY.w; + break; + + case DISPLAY_BC: + addr = cpu->BC.w; + break; + + case DISPLAY_DE: + addr = cpu->DE.w; + break; + + case DISPLAY_PC: + addr = cpu->PC; + break; + + default: + break; + } + + TM_printf(0,0,"%s: %4.4x",label[disp],addr); + + if (as_hex) + { + for(y=0;y<20;y++) + { + TM_printf(0,y+2,"%4.4x:",addr); + + for(x=0;x<8;x++) + { + TM_printf(6+x*3,y+2,"%2.2x",ZX81ReadDisassem(cpu,addr++)); + } + } + } + else + { + for(y=0;y<20;y++) + { + TM_printf(0,y+2,"%4.4x:",addr); + TM_Put(7,y+2,Z80Disassemble(cpu,&addr)); + } + } +} + + +/* ---------------------------------------- PUBLIC INTERFACES +*/ +void MachineCodeMonitor(Z80 *cpu) +{ + static Z80Word display_address = 0x4000; + static MemDisplayType mem_display = DISPLAY_ADDR; + int done = FALSE; + int running = FALSE; + DisplayModeType display_mode = MODE_CPU_STATE; + int key; + SoftKey soft_key; + + SK_DisplayKeyboard(); + SK_SetDisplayBrightness(TRUE); + + for(soft_key = SK_1; soft_key <= SK_SPACE; soft_key++) + { + SK_SetSticky(soft_key,TRUE); + } + + while(!done) + { + TM_Cls(); + DisplayRunningState(running); + + switch(display_mode) + { + case MODE_CPU_STATE: + DisplayCPU(cpu); + break; + case MODE_HEX: + DisplayMem(cpu,mem_display,display_address,TRUE); + break; + case MODE_ASSEM: + DisplayMem(cpu,mem_display,display_address,FALSE); + break; + default: + TM_Put(0,0,"Oops!"); + break; + } + + do + { + SoftKeyEvent ev; + + swiWaitForVBlank(); + + while(SK_GetBareEvent(&ev)) + { + ZX81HandleKey(ev.key,ev.pressed); + + if (ev.key == SK_CONFIG && ev.pressed) + { + done = TRUE; + } + } + + key = (keysDownRepeat() & ~KEY_TOUCH); + + } while (!done && !running && !key); + + if (key & KEY_START) + { + running = !running; + } + + if (key & KEY_X) + { + DisplayHelp(); + } + + if (key & KEY_SELECT) + { + display_mode = (display_mode+1) % MODE_TYPE_COUNT; + } + + if (key & KEY_L) + { + if (keysHeld() & KEY_Y) + { + display_address -= 512; + } + else + { + display_address -= 64; + } + } + + if (key & KEY_R) + { + if (keysHeld() & KEY_Y) + { + display_address += 512; + } + else + { + display_address += 64; + } + } + + if (key & KEY_B) + { + mem_display = (mem_display+1) % DISPLAY_TYPE_COUNT; + } + + if (running || (key & KEY_A)) + { + Z80SingleStep(cpu); + } + } + + SK_SetDisplayBrightness(FALSE); + TM_Cls(); + + for(soft_key = SK_1; soft_key <= SK_SPACE; soft_key++) + { + SK_SetSticky(soft_key,FALSE); + ZX81HandleKey(soft_key,FALSE); + } + + SK_SetSticky(SK_SHIFT,DS81_Config[DS81_STICKY_SHIFT]); + +} diff --git a/source/snapshot.c b/source/snapshot.c new file mode 100644 index 0000000..1d5aa37 --- /dev/null +++ b/source/snapshot.c @@ -0,0 +1,195 @@ +/* + ds81 - Nintendo DS ZX81 emulator + + Copyright (C) 2006 Ian Cowburn <ianc@noddybox.co.uk> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + 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. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + ------------------------------------------------------------------------- + + Provides the routines for snapshotting. + +*/ +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <ctype.h> +#include <nds.h> + +#include "snapshot.h" +#include "zx81.h" +#include "gui.h" + +#include "config.h" + +#include "ds81_debug.h" + +#ifndef TRUE +#define TRUE 1 +#endif + +#ifndef FALSE +#define FALSE 0 +#endif + + +/* ---------------------------------------- STATICS +*/ +static int enabled; +static const char *magic = "V01_DS81"; +static const char *extension[2] = {".D81", ".K81"}; + + +/* ---------------------------------------- PRIVATE FUNCTIONS +*/ +static void WriteMagic(FILE *fp, SnapshotType t) +{ + const char *p = magic; + + while(*p) + { + fputc(*p++, fp); + } + + fputc(t, fp); +} + +static int CheckMagic(FILE *fp, SnapshotType t) +{ + const char *p = magic; + + while(*p) + { + if (fgetc(fp) != *p++) + { + return FALSE; + } + } + + return (fgetc(fp) == t); +} + + +/* ---------------------------------------- EXPORTED INTERFACES +*/ +void SNAP_Enable(int enable) +{ + enabled = enable; +} + +void SNAP_Save(Z80 *cpu, SnapshotType type) +{ + char base[FILENAME_MAX] = ""; + char file[FILENAME_MAX]; + FILE *fp = NULL; + + if (!enabled) + { + return; + } + + if(!GUI_InputName("enter snapshot filename", + extension[type], base, 8) || !base[0]) + { + return; + } + + strcat(base, extension[type]); + + strcpy(file, DEFAULT_SNAPDIR); + strcat(file, base); + + fp = fopen(file, "wb"); + + if (!fp) + { + fp = fopen(base, "wb"); + } + + if (fp) + { + WriteMagic(fp, type); + + SK_SaveSnapshot(fp); + + if (type == SNAP_TYPE_FULL) + { + Z80SaveSnapshot(cpu, fp); + ZX81SaveSnapshot(fp); + } + + fclose(fp); + } + else + { + GUI_Alert(FALSE, "Failed to save snapshot"); + } +} + +void SNAP_Load(Z80 *cpu, const char *optional_name, SnapshotType type) +{ + static char last_dir[FILENAME_MAX] = "/"; + char file[FILENAME_MAX]; + FILE *fp = NULL; + + if (!enabled) + { + return; + } + + if (optional_name) + { + strcpy(file, DEFAULT_SNAPDIR); + strcat(file, optional_name); + strcat(file, extension[type]); + + fp = fopen(file, "rb"); + + if (!fp) + { + strcpy(file, optional_name); + strcat(file, extension[type]); + + fp = fopen(file, "rb"); + } + } + else + { + if (GUI_FileSelect(last_dir, file, extension[type])) + { + fp = fopen(file, "rb"); + } + } + + if (fp) + { + if (!CheckMagic(fp, type)) + { + GUI_Alert(FALSE, "Not a valid snapshot"); + } + else + { + SK_LoadSnapshot(fp); + + if (type == SNAP_TYPE_FULL) + { + Z80LoadSnapshot(cpu, fp); + ZX81LoadSnapshot(fp); + } + } + + fclose(fp); + } +} diff --git a/source/stream.c b/source/stream.c new file mode 100644 index 0000000..f471d93 --- /dev/null +++ b/source/stream.c @@ -0,0 +1,86 @@ +/* + ds81 - Nintendo DS ZX81 emulator + + Copyright (C) 2006 Ian Cowburn <ianc@noddybox.co.uk> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + 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. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + ------------------------------------------------------------------------- + + Provides the routines for streaming. + +*/ +#include "stream.h" + +/* The long functions are a tad convuluted, but I'm in a dash. +*/ + +void PUT_Byte(FILE *fp, unsigned char c) +{ + fputc(c, fp); +} + +void PUT_Long(FILE *fp, long l) +{ + union {long l; unsigned char c[4];} u; + + u.l = l; + + fputc(u.c[0], fp); + fputc(u.c[1], fp); + fputc(u.c[2], fp); + fputc(u.c[3], fp); +} + +void PUT_ULong(FILE *fp, unsigned long l) +{ + union {unsigned long l; unsigned char c[4];} u; + + u.l = l; + + fputc(u.c[0], fp); + fputc(u.c[1], fp); + fputc(u.c[2], fp); + fputc(u.c[3], fp); +} + +unsigned char GET_Byte(FILE *fp) +{ + return (unsigned char)fgetc(fp); +} + +long GET_Long(FILE *fp) +{ + union {long l; unsigned char c[4];} u; + + u.c[0] = (unsigned char)fgetc(fp); + u.c[1] = (unsigned char)fgetc(fp); + u.c[2] = (unsigned char)fgetc(fp); + u.c[3] = (unsigned char)fgetc(fp); + + return u.l; +} + +unsigned long GET_ULong(FILE *fp) +{ + union {unsigned long l; unsigned char c[4];} u; + + u.c[0] = (unsigned char)fgetc(fp); + u.c[1] = (unsigned char)fgetc(fp); + u.c[2] = (unsigned char)fgetc(fp); + u.c[3] = (unsigned char)fgetc(fp); + + return u.l; +} diff --git a/source/tapes.c b/source/tapes.c new file mode 100644 index 0000000..81db917 --- /dev/null +++ b/source/tapes.c @@ -0,0 +1,282 @@ +/* + ds81 - Nintendo DS ZX81 emulator. + + Copyright (C) 2006 Ian Cowburn <ianc@noddybox.co.uk> + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + 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. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + $Id: tapes.c 61 2008-11-03 17:07:32Z ianc $ +*/ + +#include <nds.h> + +#include "tapes.h" +#include "framebuffer.h" +#include "keyboard.h" +#include "zx81.h" + +#include "maze_bin.h" +#include "maze_inlay_bin.h" +#include "cpatrol_bin.h" +#include "cpatrol_inlay_bin.h" +#include "sabotage_bin.h" +#include "sabotage_inlay_bin.h" +#include "mazogs_bin.h" +#include "mazogs_inlay_bin.h" + +#include "ds81_debug.h" + + +/* ---------------------------------------- STATIC DATA +*/ +typedef struct +{ + const u8 *tape; + const u8 *tape_end; + sImage img; + const void *source_pcx; + SoftKey *keys; + const char *text; +} Tape; + +#define NO_TAPES 4 + +static SoftKey maze_keys[]= + { + SK_PAD_UP, SK_7, + SK_PAD_LEFT, SK_5, + SK_PAD_RIGHT, SK_8, + SK_PAD_START, SK_C, + SK_PAD_SELECT, SK_A, + NUM_SOFT_KEYS + }; + +static SoftKey cpatrol_keys[]= + { + SK_PAD_UP, SK_F, + SK_PAD_RIGHT, SK_J, + SK_PAD_LEFT, SK_N, + SK_PAD_DOWN, SK_V, + SK_PAD_R, SK_N, + SK_PAD_L, SK_J, + SK_PAD_A, SK_0, + SK_PAD_B, SK_NEWLINE, + NUM_SOFT_KEYS + }; + +static SoftKey sabotage_keys[]= + { + SK_PAD_UP, SK_W, + SK_PAD_LEFT, SK_H, + SK_PAD_RIGHT, SK_J, + SK_PAD_DOWN, SK_S, + SK_PAD_A, SK_E, + SK_PAD_R, SK_1, + SK_PAD_L, SK_2, + SK_PAD_START, SK_0, + NUM_SOFT_KEYS + }; + +static SoftKey mazogs_keys[]= + { + SK_PAD_UP, SK_W, + SK_PAD_LEFT, SK_H, + SK_PAD_RIGHT, SK_J, + SK_PAD_DOWN, SK_S, + SK_PAD_A, SK_NEWLINE, + SK_PAD_R, SK_R, + SK_PAD_L, SK_L, + SK_PAD_START, SK_Y, + SK_PAD_SELECT, SK_V, + NUM_SOFT_KEYS + }; + +static Tape tapes[NO_TAPES]= + { + { + maze_bin, + maze_bin_end, + {0}, + maze_inlay_bin, + maze_keys, + "%3d monster maze%\n" + "(c) 1983 Malcolm E. Evans\n\n" + "Escape the maze and its T-Rex\n\n" + "use joypad for turning and to\n" + "move forward.\n" + "%start% to start.\n" + "%select% to appeal.\n\n" + "%note% when the screen goes grey\n" + "for 30-60 seconds this is not a\n" + "problem - the game is creating\n" + "the maze." + }, + { + mazogs_bin, + mazogs_bin_end, + {0}, + mazogs_inlay_bin, + mazogs_keys, + "%Mazogs%\n" + "(c) 1981 Don Priestley\n\n" + "Find the treasure and\n" + "return to the start.\n" + "Avoid the %Mazogs% that roam\n" + "the maze.\n\n" + "Use joypad to move.\n" + "%select% to view map.\n" + "%start% to quit.\n" + "%L% or %R% shoulder to select\n" + "direction at start." + }, + { + cpatrol_bin, + cpatrol_bin_end, + {0}, + cpatrol_inlay_bin, + cpatrol_keys, + "%city patrol%\n" + "(c) 1982 Don Priestley\n\n" + "Defend the city from the aliens.\n\n" + "yes - that parallax city was\n" + "done with a text mode and the\n" + "equivalent of a 0.8mhz z80\n\n" + "the joypad controls the cursor.\n" + "hold %L% or %R% shoulder buttons\n" + "to move fast when moving in the\n" + "same direction.\n\n" + "%A% fires when moving.\n" + "%B% fires when still.\n\n" + "sorry about that, but the keys\n" + "are a bit odd in this game." + }, + { + sabotage_bin, + sabotage_bin_end, + {0}, + sabotage_inlay_bin, + sabotage_keys, + "%sabotage%\n" + "(c) 1982 Don Priestley\n\n" + "Destroy the boxes before the\n" + "guard finds you.\n\n" + "or find the saboteur as the\n" + "guard.\n\n" + "while this game may not feature\n" + "the dazzling graphics of other\n" + "ZX81 games it more than makes\n" + "up with a simply joyous\n" + "gameplay mechanic.\n\n" + "The joypad controls the player.\n" + "%A% plants a bomb. %L% shoulder\n" + "to play as the guard, %R% as\n" + "the saboteur." + } + }; + + +static int current=0; + +/* ---------------------------------------- PRIVATE INTERFACES +*/ +static void InitTapes(void) +{ + static int init=FALSE; + int f; + + if (init) + { + return; + } + + init=TRUE; + + for(f=0;f<NO_TAPES;f++) + { + loadPCX(tapes[f].source_pcx,&tapes[f].img); + } +} + +static void DisplayTape(Tape *t) +{ + FB_Clear(); + FB_Blit(&t->img,255-t->img.width,0,1); + + FB_Print("LEFT/RIGHT",0,0,COL_WHITE,COL_TRANSPARENT); + FB_Print("to choose",0,10,COL_WHITE,COL_TRANSPARENT); + FB_Print("A to select",0,30,COL_WHITE,COL_TRANSPARENT); + FB_Print("B to cancel",0,40,COL_WHITE,COL_TRANSPARENT); + FB_Print("REMEMBER TO",0,60,COL_WHITE,COL_TRANSPARENT); + FB_Print("LOAD \"\"",0,70,COL_WHITE,COL_TRANSPARENT); + FB_Print("ON THE ZX81!",0,80,COL_WHITE,COL_TRANSPARENT); + + ZX81DisplayString(t->text); +} + +/* ---------------------------------------- PUBLIC INTERFACES +*/ +void SelectTape(void) +{ + int done=FALSE; + + InitTapes(); + + ZX81SuspendDisplay(); + + while(!done) + { + uint32 key=0; + + DisplayTape(tapes+current); + + do + { + swiWaitForVBlank(); + } while(!(key=keysDownRepeat())); + + if (key & KEY_LEFT) + { + if (--current<0) + { + current=NO_TAPES-1; + } + } + else if (key & KEY_RIGHT) + { + current=(current+1)%NO_TAPES; + } + else if (key & KEY_A) + { + int f; + + done=TRUE; + ZX81SetTape(tapes[current].tape, + tapes[current].tape_end - tapes[current].tape); + + for(f=0;tapes[current].keys[f]!=NUM_SOFT_KEYS;f+=2) + { + SK_DefinePad(tapes[current].keys[f], + tapes[current].keys[f+1]); + } + } + else if (key & KEY_B) + { + done=TRUE; + } + } + + ZX81ResumeDisplay(); +} + diff --git a/source/textmode.c b/source/textmode.c new file mode 100644 index 0000000..795fc4f --- /dev/null +++ b/source/textmode.c @@ -0,0 +1,157 @@ +/* + ds81 - Nintendo DS ZX81 emulator. + + Copyright (C) 2007 Ian Cowburn <ianc@noddybox.co.uk> + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + 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. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + $Id: textmode.c 42 2007-03-02 23:18:38Z ianc $ +*/ + +#include <nds.h> +#include <stdio.h> +#include <stdarg.h> +#include <string.h> + +#include "textmode.h" + +/* ---------------------------------------- STATIC DATA +*/ +static int mapw; +static int maph; +static uint16 *text; +static int is_rot; +static void (*draw_string)(const char *str, int x, int y); + + +/* ---------------------------------------- PRIVATE INTERFACES +*/ +static inline void Plot_Text(int x, int y, int c) +{ + int xw; + int yw; + + xw = x/32; + yw = y/32; + x %= 32; + y %= 32; + + *(text + x + y*32 + (xw+yw) * 1024) = c; +} + + +static inline void Plot_RS(int x, int y, int c) +{ + uint16 ch; + int odd; + uint16 *off; + + odd = x&1; + + off = text + x/2 + y*mapw/2; + + ch = *off; + + if (odd) + { + ch = (c<<8) | (ch&0xff); + } + else + { + ch = c | (ch&0xff00); + } + + *off = ch; +} + + +static void Text_Put(const char *str, int x, int y) +{ + while(*str && x<mapw) + { + Plot_Text(x,y,*str - 32); + x++; + str++; + } +} + +static void RS_Put(const char *str, int x, int y) +{ + while(*str && x<mapw) + { + Plot_RS(x,y,*str - 32); + x++; + str++; + } +} + +/* ---------------------------------------- PUBLIC INTERFACES +*/ +void TM_Init(uint16 *vram, int map_width, int map_height, int map_is_rotation) +{ + text = vram; + + mapw = map_width; + maph = map_height; + + is_rot = map_is_rotation; + + draw_string = map_is_rotation ? RS_Put : Text_Put; + + TM_Cls(); +} + + +void TM_Cls(void) +{ + uint16 *scr; + int f; + + scr = text; + + if (is_rot) + { + for(f=0;f<mapw*maph/2;f++) + { + *scr++=0; + } + } + else + { + for(f=0;f<mapw*maph;f++) + { + *scr++=0; + } + } +} + + +void TM_Put(int x, int y, const char *str) +{ + draw_string(str,x,y); +} + + +void TM_printf(int x, int y, const char *format, ...) +{ + char buff[128]; + va_list va; + + va_start(va,format); + vsnprintf(buff,sizeof buff,format,va); + va_end(va); + + draw_string(buff,x,y); +} diff --git a/source/touchwrap.c b/source/touchwrap.c new file mode 100644 index 0000000..dec2b93 --- /dev/null +++ b/source/touchwrap.c @@ -0,0 +1,55 @@ +/* + ds81 - Nintendo DS ZX81 emulator. + + Copyright (C) 2006 Ian Cowburn <ianc@noddybox.co.uk> + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + 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. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + $Id: touchwrap.c 75 2010-11-19 14:52:49Z ianc $ +*/ + +#include <nds.h> +#include <stdlib.h> + +#include "touchwrap.h" +#include "config.h" + +/* ---------------------------------------- PUBLIC INTERFACES +*/ +int AllowTouch(touchPosition *tp) +{ + static touchPosition last; + int16 dx; + int16 dy; + int res; + + touchRead(tp); + + if (DS81_Config[DS81_AVERAGE_TOUCHSCREEN]) + { + dx = last.px - tp->px; + dy = last.py - tp->py; + + res = (abs(dx) < 5 && abs(dy) < 5); + } + else + { + res = TRUE; + } + + last = *tp; + + return res; +} diff --git a/source/z80.c b/source/z80.c new file mode 100644 index 0000000..da63450 --- /dev/null +++ b/source/z80.c @@ -0,0 +1,394 @@ +/* + + z80 - Z80 Emulator + + Copyright (C) 2006 Ian Cowburn <ianc@noddybox.co.uk> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + 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. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + ------------------------------------------------------------------------- + + $Id: z80.c 64 2008-12-05 00:37:26Z ianc $ + + Z80 + +*/ +#include <stdlib.h> +#include <string.h> + +#include "z80.h" +#include "z80_private.h" + +#include "stream.h" + +static const char ident[]="$Id: z80.c 64 2008-12-05 00:37:26Z ianc $"; +static const char ident_z80_header[]=Z80_H; +static const char ident_z80_private_header[]=Z80_PRIVATE_H; + +Z80Label *z80_labels=NULL; + +/* ---------------------------------------- PRIVATE FUNCTIONS +*/ +static void InitTables() +{ + static int init=FALSE; + + if (init) + return; + + init=TRUE; + + Z80_InitialiseInternals(); +} + +static void Z80_CheckInterrupt(Z80 *cpu) +{ + /* Check interrupts + */ + if (PRIV->raise) + { + if (PRIV->nmi) + { + if (PRIV->halt) + { + PRIV->halt=FALSE; + CALLBACK(eZ80_Halt,0); + cpu->PC++; + } + + TSTATE(2); + cpu->IFF1=0; + PRIV->nmi=FALSE; + PUSH(cpu->PC); + cpu->PC=0x66; + } + else if (cpu->IFF1) + { + if (PRIV->halt) + { + PRIV->halt=FALSE; + CALLBACK(eZ80_Halt,0); + cpu->PC++; + } + + TSTATE(2); + + cpu->IFF1=0; + cpu->IFF2=0; + + switch(cpu->IM) + { + default: + case 0: + INC_R; + Z80_Decode(cpu,PRIV->devbyte); + return; + break; + + case 1: + PUSH(cpu->PC); + cpu->PC=0x38; + break; + + case 2: + PUSH(cpu->PC); + cpu->PC=(Z80Word)cpu->I*256+PRIV->devbyte; + break; + } + } + + PRIV->raise=FALSE; + } +} + + +/* ---------------------------------------- INTERFACES +*/ + +#ifdef ENABLE_ARRAY_MEMORY +Z80 *Z80Init(Z80ReadPort read_port, + Z80WritePort write_port) +#else +Z80 *Z80Init(Z80ReadMemory read_memory, + Z80WriteMemory write_memory, + Z80ReadPort read_port, + Z80WritePort write_port, + Z80ReadMemory read_for_disassem) +#endif +{ + Z80 *cpu; + int f; + int r; + + InitTables(); + +#ifndef ENABLE_ARRAY_MEMORY + if (!read_memory || !write_memory) + return NULL; +#endif + + cpu=malloc(sizeof *cpu); + + if (cpu) + { + cpu->priv=malloc(sizeof *cpu->priv); + + if (cpu->priv) + { +#ifndef ENABLE_ARRAY_MEMORY + PRIV->mread=read_memory; + PRIV->mwrite=write_memory; + PRIV->disread=read_for_disassem; +#endif + PRIV->pread=read_port; + PRIV->pwrite=write_port; + + for(f=0;f<eZ80_NO_CALLBACK;f++) + for(r=0;r<MAX_PER_CALLBACK;r++) + PRIV->callback[f][r]=NULL; + + Z80Reset(cpu); + } + else + { + free(cpu); + cpu=NULL; + } + } + + return cpu; +} + + +void Z80Reset(Z80 *cpu) +{ + PRIV->cycle=0; + cpu->PC=0; + + cpu->AF.w=0xffff; + cpu->BC.w=0xffff; + cpu->DE.w=0xffff; + cpu->HL.w=0xffff; + cpu->AF_=0xffff; + cpu->BC_=0xffff; + cpu->DE_=0xffff; + cpu->HL_=0xffff; + + cpu->IX.w=0xffff; + cpu->IY.w=0xffff; + + cpu->SP=0xffff; + cpu->IFF1=0; + cpu->IFF2=0; + cpu->IM=0; + cpu->I=0; + cpu->R=0; + PRIV->halt=0; + + PRIV->raise=FALSE; + PRIV->nmi=FALSE; +} + + +Z80Val Z80Cycles(Z80 *cpu) +{ + return PRIV->cycle; +} + + +void Z80ResetCycles(Z80 *cpu, Z80Val cycles) +{ + PRIV->cycle=cycles; +} + + +int Z80LodgeCallback(Z80 *cpu, Z80CallbackReason reason, Z80Callback callback) +{ + int f; + + for(f=0;f<MAX_PER_CALLBACK;f++) + { + if (!PRIV->callback[reason][f]) + { + PRIV->callback[reason][f]=callback; + return TRUE; + } + } + + return FALSE; +} + + +void Z80RemoveCallback(Z80 *cpu, Z80CallbackReason reason, Z80Callback callback) +{ + int f; + + for(f=0;f<MAX_PER_CALLBACK;f++) + { + if (PRIV->callback[reason][f]==callback) + { + PRIV->callback[reason][f]=NULL; + } + } +} + + +void Z80Interrupt(Z80 *cpu, Z80Byte devbyte) +{ + PRIV->raise=TRUE; + PRIV->devbyte=devbyte; + PRIV->nmi=FALSE; +} + + +void Z80NMI(Z80 *cpu) +{ + PRIV->raise=TRUE; + PRIV->nmi=TRUE; +} + + +int Z80SingleStep(Z80 *cpu) +{ + Z80Byte opcode; + + PRIV->last_cb=TRUE; + PRIV->shift=0; + + Z80_CheckInterrupt(cpu); + + CALLBACK(eZ80_Instruction,PRIV->cycle); + + INC_R; + + opcode=FETCH_BYTE; + + Z80_Decode(cpu,opcode); + + return PRIV->last_cb; +} + + +void Z80Exec(Z80 *cpu) +{ + while (Z80SingleStep(cpu)); +} + + +void Z80SetLabels(Z80Label labels[]) +{ + z80_labels=labels; +} + + +const char *Z80Disassemble(Z80 *cpu, Z80Word *pc) +{ +#ifdef ENABLE_DISASSEM + Z80Byte Z80_Dis_FetchByte(Z80 *cpu, Z80Word *pc); + static char s[80]; + Z80Word opc,npc; + Z80Byte op; + int f; + + opc=*pc; + op=Z80_Dis_FetchByte(cpu,pc); + dis_opcode_z80[op](cpu,op,pc); + npc=*pc; + + strcpy(s,Z80_Dis_Printf("%-5s",Z80_Dis_GetOp())); + strcat(s,Z80_Dis_Printf("%-40s ;",Z80_Dis_GetArg())); + + for(f=0;f<5 && opc!=npc;f++) + { +#ifdef ENABLE_ARRAY_MEMORY + strcat(s,Z80_Dis_Printf(" %.2x",(int)Z80_MEMORY[opc++])); +#else + strcat(s,Z80_Dis_Printf(" %.2x",(int)PRIV->disread(cpu,opc++))); +#endif + } + + if (opc!=npc) + for(f=1;f<3;f++) + s[strlen(s)-f]='.'; + + return s; +#else + (*pc)+=4; + return "NO DISASSEMBLER"; +#endif +} + + +void Z80SaveSnapshot(Z80 *cpu, FILE *fp) +{ + PUT_ULong(fp, cpu->PC); + PUT_ULong(fp, cpu->AF.w); + PUT_ULong(fp, cpu->BC.w); + PUT_ULong(fp, cpu->DE.w); + PUT_ULong(fp, cpu->HL.w); + PUT_ULong(fp, cpu->AF_); + PUT_ULong(fp, cpu->BC_); + PUT_ULong(fp, cpu->DE_); + PUT_ULong(fp, cpu->HL_); + PUT_ULong(fp, cpu->IX.w); + PUT_ULong(fp, cpu->IY.w); + PUT_ULong(fp, cpu->SP); + PUT_Byte(fp, cpu->IFF1); + PUT_Byte(fp, cpu->IFF2); + PUT_Byte(fp, cpu->IM); + PUT_Byte(fp, cpu->I); + PUT_Byte(fp, cpu->R); + PUT_Byte(fp, cpu->R); + + PUT_ULong(fp, cpu->priv->cycle); + PUT_Long(fp, cpu->priv->halt); + PUT_Byte(fp, cpu->priv->shift); + PUT_Long(fp, cpu->priv->raise); + PUT_Byte(fp, cpu->priv->devbyte); + PUT_Long(fp, cpu->priv->nmi); + PUT_Long(fp, cpu->priv->last_cb); +} + +void Z80LoadSnapshot(Z80 *cpu, FILE *fp) +{ + cpu->PC = GET_ULong(fp); + cpu->AF.w = GET_ULong(fp); + cpu->BC.w = GET_ULong(fp); + cpu->DE.w = GET_ULong(fp); + cpu->HL.w = GET_ULong(fp); + cpu->AF_ = GET_ULong(fp); + cpu->BC_ = GET_ULong(fp); + cpu->DE_ = GET_ULong(fp); + cpu->HL_ = GET_ULong(fp); + cpu->IX.w = GET_ULong(fp); + cpu->IY.w = GET_ULong(fp); + cpu->SP = GET_ULong(fp); + cpu->IFF1 = GET_Byte(fp); + cpu->IFF2 = GET_Byte(fp); + cpu->IM = GET_Byte(fp); + cpu->I = GET_Byte(fp); + cpu->R = GET_Byte(fp); + cpu->R = GET_Byte(fp); + + cpu->priv->cycle = GET_ULong(fp); + cpu->priv->halt = GET_Long(fp); + cpu->priv->shift = GET_Byte(fp); + cpu->priv->raise = GET_Long(fp); + cpu->priv->devbyte = GET_Byte(fp); + cpu->priv->nmi = GET_Long(fp); + cpu->priv->last_cb = GET_Long(fp); +} + +/* END OF FILE */ diff --git a/source/z80_decode.c b/source/z80_decode.c new file mode 100644 index 0000000..992e1d1 --- /dev/null +++ b/source/z80_decode.c @@ -0,0 +1,2533 @@ +/* + + z80 - Z80 Emulator + + Copyright (C) 2006 Ian Cowburn <ianc@noddybox.co.uk> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + 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. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + ------------------------------------------------------------------------- + + $Id: z80_decode.c 4 2006-10-04 23:05:43Z ianc $ + +*/ +#include <stdlib.h> +#include <limits.h> + +#include "z80.h" +#include "z80_private.h" + +static const char ident[]="$Id: z80_decode.c 4 2006-10-04 23:05:43Z ianc $"; + +/* ---------------------------------------- TABLES AND INIT +*/ +static Z80Byte PSZtable[512]; +static Z80Byte SZtable[512]; +static Z80Byte Ptable[512]; +static Z80Byte Stable[512]; +static Z80Byte Ztable[512]; + + +int Z80_HI_WORD; +int Z80_LO_WORD; + +#define HI Z80_HI_WORD +#define LO Z80_LO_WORD + +/* ---------------------------------------- MISC FUNCTIONS +*/ +void Z80_InitialiseInternals(void) +{ + Z80Word f; + Z80Reg r; + + /* Check endianness + */ + r.w=0x1234; + + if (r.b[0] == 0x12) + { + HI=0; + LO=1; + } + else if (r.b[1] == 0x12) + { + HI=1; + LO=0; + } + else + { + exit(1); + } + + /* Check variable sizes + */ + if (CHAR_BIT!=8 || sizeof(Z80Word)!=2) + { + exit(2); + } + + /* Initialise flag tables + */ + for(f=0;f<256;f++) + { + Z80Byte p,z,s; + int b; + + p=0; + + for(b=0;b<8;b++) + if (f&(1<<b)) + p++; + + if (p&1) + p=0; + else + p=P_Z80; + + if (f) + z=0; + else + z=Z_Z80; + + if (f&0x80) + s=S_Z80; + else + s=0; + + Ptable[f]=p; + Stable[f]=s; + Ztable[f]=z; + SZtable[f]=z|s; + PSZtable[f]=z|s|p; + + Ptable[f+256]=Ptable[f]|C_Z80; + Stable[f+256]=Stable[f]|C_Z80; + Ztable[f+256]=Ztable[f]|C_Z80; + SZtable[f+256]=SZtable[f]|C_Z80; + PSZtable[f+256]=PSZtable[f]|C_Z80; + } +} + +#ifndef ENABLE_ARRAY_MEMORY +static Z80Word FPEEKW(Z80 *cpu, Z80Word addr) +{ + return (PEEK(addr) | (Z80Word)PEEK(addr+1)<<8); +} + + +static void FPOKEW(Z80 *cpu, Z80Word addr, Z80Word val) +{ + PRIV->mwrite(cpu,addr,val); + PRIV->mwrite(cpu,addr+1,val>>8); +} +#endif + + +/* ---------------------------------------- GENERAL MACROS +*/ +#define SWAP(A,B) \ +do { \ + unsigned swap_tmp; \ + swap_tmp=A; \ + A=B; \ + B=swap_tmp; \ +} while(0) + + +/* ---------------------------------------- ARITHMETIC OPS +*/ +#define ADD8(ONCE) \ +do { \ + Z80Byte VAL=ONCE; \ + unsigned w; \ + w=cpu->AF.b[HI]+(unsigned)VAL; \ + cpu->AF.b[LO]=SZtable[w]; \ + if ((cpu->AF.b[HI]^w^VAL)&H_Z80) cpu->AF.b[LO]|=H_Z80; \ + if ((VAL^cpu->AF.b[HI]^0x80)&(VAL^w)&0x80) cpu->AF.b[LO]|=P_Z80; \ + SETHIDDEN(w); \ + cpu->AF.b[HI]=w; \ +} while(0) + + +#define ADC8(ONCE) \ +do { \ + Z80Byte VAL=ONCE; \ + unsigned w; \ + w=(cpu->AF.b[HI]+(unsigned)VAL+CARRY)&0x1ff; \ + cpu->AF.b[LO]=SZtable[w]; \ + if ((cpu->AF.b[HI]^w^VAL)&H_Z80) cpu->AF.b[LO]|=H_Z80; \ + if ((VAL^cpu->AF.b[HI]^0x80)&(VAL^w)&0x80) cpu->AF.b[LO]|=P_Z80; \ + SETHIDDEN(w); \ + cpu->AF.b[HI]=w; \ +} while(0) + + +#define SUB8(ONCE) \ +do { \ + Z80Byte VAL=ONCE; \ + unsigned w; \ + w=(cpu->AF.b[HI]-(unsigned)VAL)&0x1ff; \ + cpu->AF.b[LO]=SZtable[w]|N_Z80; \ + if ((cpu->AF.b[HI]^w^VAL)&H_Z80) cpu->AF.b[LO]|=H_Z80; \ + if ((VAL^cpu->AF.b[HI])&(cpu->AF.b[HI]^w)&0x80) cpu->AF.b[LO]|=P_Z80; \ + SETHIDDEN(w); \ + cpu->AF.b[HI]=w; \ +} while(0) + + +#define CMP8(ONCE) \ +do { \ + Z80Byte VAL=ONCE; \ + unsigned w; \ + w=(cpu->AF.b[HI]-(unsigned)VAL)&0x1ff; \ + cpu->AF.b[LO]=SZtable[w]|N_Z80; \ + if ((cpu->AF.b[HI]^w^VAL)&H_Z80) cpu->AF.b[LO]|=H_Z80; \ + if ((VAL^cpu->AF.b[HI])&(cpu->AF.b[HI]^w)&0x80) cpu->AF.b[LO]|=P_Z80; \ + SETHIDDEN(VAL); \ +} while(0) + + +#define SBC8(ONCE) \ +do { \ + Z80Byte VAL=ONCE; \ + unsigned w; \ + w=(cpu->AF.b[HI]-(unsigned)VAL-CARRY)&0x1ff; \ + cpu->AF.b[LO]=SZtable[w]|N_Z80; \ + if ((cpu->AF.b[HI]^w^VAL)&H_Z80) cpu->AF.b[LO]|=H_Z80; \ + if ((VAL^cpu->AF.b[HI])&(cpu->AF.b[HI]^w)&0x80) cpu->AF.b[LO]|=P_Z80; \ + SETHIDDEN(w); \ + cpu->AF.b[HI]=w; \ +} while(0) + + +#define ADD16(REG,ONCE) \ +do { \ + Z80Word VAL=ONCE; \ + Z80Val w; \ + w=(REG)+(Z80Val)VAL; \ + cpu->AF.b[LO]&=(S_Z80|Z_Z80|V_Z80); \ + if (w>0xffff) cpu->AF.b[LO]|=C_Z80; \ + if (((REG)^w^VAL)&0x1000) cpu->AF.b[LO]|=H_Z80; \ + SETHIDDEN(w>>8); \ + (REG)=w; \ +} while(0) + + +#define ADC16(REG, ONCE) \ +do { \ + Z80Word VAL=ONCE; \ + Z80Val w; \ + w=(REG)+(Z80Val)VAL+CARRY; \ + cpu->AF.b[LO]=0; \ + if ((w&0xffff)==0) cpu->AF.b[LO]=Z_Z80; \ + if (w&0x8000) cpu->AF.b[LO]|=S_Z80; \ + if (w>0xffff) cpu->AF.b[LO]|=C_Z80; \ + if ((VAL^(REG)^0x8000)&((REG)^w)&0x8000) cpu->AF.b[LO]|=P_Z80; \ + if (((REG)^w^VAL)&0x1000) cpu->AF.b[LO]|=H_Z80; \ + SETHIDDEN(w>>8); \ + (REG)=w; \ +} while(0) + + +#define SBC16(REG, ONCE) \ +do { \ + Z80Word VAL=ONCE; \ + Z80Val w; \ + w=(REG)-(Z80Val)VAL-CARRY; \ + cpu->AF.b[LO]=N_Z80; \ + if (w&0x8000) cpu->AF.b[LO]|=S_Z80; \ + if ((w&0xffff)==0) cpu->AF.b[LO]|=Z_Z80; \ + if (w>0xffff) cpu->AF.b[LO]|=C_Z80; \ + if ((VAL^(REG))&((REG)^w)&0x8000) cpu->AF.b[LO]|=P_Z80; \ + if (((REG)^w^VAL)&0x1000) cpu->AF.b[LO]|=H_Z80; \ + SETHIDDEN(w>>8); \ + (REG)=w; \ +} while(0) + + +#define INC8(REG) \ +do { \ + (REG)++; \ + cpu->AF.b[LO]=CARRY|SZtable[(REG)]; \ + if ((REG)==0x80) cpu->AF.b[LO]|=P_Z80; \ + if (((REG)&0x0f)==0) cpu->AF.b[LO]|=H_Z80; \ +} while(0) + + +#define DEC8(REG) \ +do { \ + (REG)--; \ + cpu->AF.b[LO]=N_Z80|CARRY; \ + if ((REG)==0x7f) cpu->AF.b[LO]|=P_Z80; \ + if (((REG)&0x0f)==0x0f) cpu->AF.b[LO]|=H_Z80; \ + cpu->AF.b[LO]|=SZtable[(REG)]; \ +} while(0) + + +#define OP_ON_MEM(OP,addr) \ +do { \ + Z80Byte memop=PEEK(addr); \ + OP(memop); \ + POKE(addr,memop); \ +} while(0) + + +#define OP_ON_MEM_WITH_ARG(OP,addr,arg) \ +do { \ + Z80Byte memop=PEEK(addr); \ + OP(memop,arg); \ + POKE(addr,memop); \ +} while(0) + + +#define OP_ON_MEM_WITH_COPY(OP,addr,copy) \ +do { \ + Z80Byte memop=PEEK(addr); \ + OP(memop); \ + copy=memop; \ + POKE(addr,memop); \ +} while(0) + + +#define OP_ON_MEM_WITH_ARG_AND_COPY(OP,addr,arg,copy) \ +do { \ + Z80Byte memop=PEEK(addr); \ + OP(memop,arg); \ + copy=memop; \ + POKE(addr,memop); \ +} while(0) + + +/* ---------------------------------------- ROTATE AND SHIFT OPS +*/ +#define RRCA \ +do { \ + cpu->AF.b[LO]=(cpu->AF.b[LO]&(S_Z80|Z_Z80|P_Z80))|(cpu->AF.b[HI]&C_Z80); \ + cpu->AF.b[HI]=(cpu->AF.b[HI]>>1)|(cpu->AF.b[HI]<<7); \ + SETHIDDEN(cpu->AF.b[HI]); \ +} while(0) + + +#define RRA \ +do { \ + Z80Byte c; \ + c=CARRY; \ + cpu->AF.b[LO]=(cpu->AF.b[LO]&(S_Z80|Z_Z80|P_Z80))|(cpu->AF.b[HI]&C_Z80); \ + cpu->AF.b[HI]=(cpu->AF.b[HI]>>1)|(c<<7); \ + SETHIDDEN(cpu->AF.b[HI]); \ +} while(0) + + +#define RRC(REG) \ +do { \ + Z80Byte c; \ + c=(REG)&C_Z80; \ + (REG)=((REG)>>1)|((REG)<<7); \ + cpu->AF.b[LO]=PSZtable[(REG)]|c; \ + SETHIDDEN(REG); \ +} while(0) + + +#define RR(REG) \ +do { \ + Z80Byte c; \ + c=(REG)&C_Z80; \ + (REG)=((REG)>>1)|(CARRY<<7); \ + cpu->AF.b[LO]=PSZtable[(REG)]|c; \ + SETHIDDEN(REG); \ +} while(0) + + +#define RLCA \ +do { \ + cpu->AF.b[LO]=(cpu->AF.b[LO]&(S_Z80|Z_Z80|P_Z80))|(cpu->AF.b[HI]>>7); \ + cpu->AF.b[HI]=(cpu->AF.b[HI]<<1)|(cpu->AF.b[HI]>>7); \ + SETHIDDEN(cpu->AF.b[HI]); \ +} while(0) + + +#define RLA \ +do { \ + Z80Byte c; \ + c=CARRY; \ + cpu->AF.b[LO]=(cpu->AF.b[LO]&(S_Z80|Z_Z80|P_Z80))|(cpu->AF.b[HI]>>7); \ + cpu->AF.b[HI]=(cpu->AF.b[HI]<<1)|c; \ + SETHIDDEN(cpu->AF.b[HI]); \ +} while(0) + + +#define RLC(REG) \ +do { \ + Z80Byte c; \ + c=(REG)>>7; \ + (REG)=((REG)<<1)|c; \ + cpu->AF.b[LO]=PSZtable[(REG)]|c; \ + SETHIDDEN(REG); \ +} while(0) + + +#define RL(REG) \ +do { \ + Z80Byte c; \ + c=(REG)>>7; \ + (REG)=((REG)<<1)|CARRY; \ + cpu->AF.b[LO]=PSZtable[(REG)]|c; \ + SETHIDDEN(REG); \ +} while(0) + + +#define SRL(REG) \ +do { \ + Z80Byte c; \ + c=(REG)&C_Z80; \ + (REG)>>=1; \ + cpu->AF.b[LO]=PSZtable[(REG)]|c; \ + SETHIDDEN(REG); \ +} while(0) + + +#define SRA(REG) \ +do { \ + Z80Byte c; \ + c=(REG)&C_Z80; \ + (REG)=((REG)>>1)|((REG)&0x80); \ + cpu->AF.b[LO]=PSZtable[(REG)]|c; \ + SETHIDDEN(REG); \ +} while(0) + + +#define SLL(REG) \ +do { \ + Z80Byte c; \ + c=(REG)>>7; \ + (REG)=((REG)<<1)|1; \ + cpu->AF.b[LO]=PSZtable[(REG)]|c; \ + SETHIDDEN(REG); \ +} while(0) + + +#define SLA(REG) \ +do { \ + Z80Byte c; \ + c=(REG)>>7; \ + (REG)=(REG)<<1; \ + cpu->AF.b[LO]=PSZtable[(REG)]|c; \ + SETHIDDEN(REG); \ +} while(0) + + +/* ---------------------------------------- BOOLEAN OPS +*/ +#define AND(VAL) \ +do { \ + cpu->AF.b[HI]&=VAL; \ + cpu->AF.b[LO]=PSZtable[cpu->AF.b[HI]]|H_Z80; \ + SETHIDDEN(cpu->AF.b[HI]); \ +} while(0) + + +#define OR(VAL) \ +do { \ + cpu->AF.b[HI]|=VAL; \ + cpu->AF.b[LO]=PSZtable[cpu->AF.b[HI]]; \ + SETHIDDEN(cpu->AF.b[HI]); \ +} while(0) + + +#define XOR(VAL) \ +do { \ + cpu->AF.b[HI]^=VAL; \ + cpu->AF.b[LO]=PSZtable[cpu->AF.b[HI]]; \ + SETHIDDEN(cpu->AF.b[HI]); \ +} while(0) + + +#define BIT(REG,B) \ +do { \ + cpu->AF.b[LO]=CARRY|H_Z80; \ + if ((REG)&(1<<B)) \ + { \ + if (B==7 && (REG&S_Z80)) cpu->AF.b[LO]|=S_Z80; \ + if (B==5 && (REG&B5_Z80)) cpu->AF.b[LO]|=B5_Z80; \ + if (B==3 && (REG&B3_Z80)) cpu->AF.b[LO]|=B3_Z80; \ + } \ + else \ + { \ + cpu->AF.b[LO]|=Z_Z80; \ + cpu->AF.b[LO]|=P_Z80; \ + } \ +} while(0) + +#define BIT_SET(REG,B) (REG)|=(1<<B) +#define BIT_RES(REG,B) (REG)&=~(1<<B) + + +/* ---------------------------------------- JUMP OPERATIONS +*/ +#define JR_COND(COND) \ +do { \ + if (COND) \ + { \ + TSTATE(12); \ + JR; \ + } \ + else \ + { \ + TSTATE(7); \ + NOJR; \ + } \ +} while(0) + + +#define JP_COND(COND) \ +do { \ + TSTATE(10); \ + if (COND) \ + { \ + JP; \ + } \ + else \ + { \ + NOJP; \ + } \ +} while(0) + + +#define CALL_COND(COND) \ +do { \ + if (COND) \ + { \ + TSTATE(17); \ + CALL; \ + } \ + else \ + { \ + TSTATE(10); \ + NOCALL; \ + } \ +} while(0) + + +#define RET_COND(COND) \ +do { \ + if (COND) \ + { \ + TSTATE(11); \ + POP(cpu->PC); \ + } \ + else \ + { \ + TSTATE(5); \ + } \ +} while(0) + + +#define RST(ADDR) \ + TSTATE(11); \ + PUSH(cpu->PC); \ + cpu->PC=ADDR + +/* ---------------------------------------- BLOCK OPERATIONS +*/ +#define LDI \ +do { \ + Z80Byte b; \ + \ + b=PEEK(cpu->HL.w); \ + POKE(cpu->DE.w,b); \ + cpu->DE.w++; \ + cpu->HL.w++; \ + cpu->BC.w--; \ + \ + CLRFLAG(H_Z80); \ + CLRFLAG(N_Z80); \ + \ + if (cpu->BC.w) \ + SETFLAG(P_Z80); \ + else \ + CLRFLAG(P_Z80); \ + \ + SETHIDDEN(cpu->AF.b[HI]+b); \ +} while(0) + +#define LDD \ +do { \ + Z80Byte b; \ + \ + b=PEEK(cpu->HL.w); \ + POKE(cpu->DE.w,b); \ + cpu->DE.w--; \ + cpu->HL.w--; \ + cpu->BC.w--; \ + \ + CLRFLAG(H_Z80); \ + CLRFLAG(N_Z80); \ + \ + if (cpu->BC.w) \ + SETFLAG(P_Z80); \ + else \ + CLRFLAG(P_Z80); \ + \ + SETHIDDEN(cpu->AF.b[HI]+b); \ +} while(0) + +#define CPI \ +do { \ + Z80Byte c,b; \ + \ + c=CARRY; \ + b=PEEK(cpu->HL.w); \ + \ + CMP8(b); \ + \ + if (c) \ + SETFLAG(C_Z80); \ + else \ + CLRFLAG(C_Z80); \ + \ + cpu->HL.w++; \ + cpu->BC.w--; \ + \ + if (cpu->BC.w) \ + SETFLAG(P_Z80); \ + else \ + CLRFLAG(P_Z80); \ +} while(0) + +#define CPD \ +do { \ + Z80Byte c,b; \ + \ + c=CARRY; \ + b=PEEK(cpu->HL.w); \ + \ + CMP8(b); \ + \ + if (c) \ + SETFLAG(C_Z80); \ + else \ + CLRFLAG(C_Z80); \ + \ + cpu->HL.w--; \ + cpu->BC.w--; \ + \ + if (cpu->BC.w) \ + SETFLAG(P_Z80); \ + else \ + CLRFLAG(P_Z80); \ +} while(0) + +#define INI \ +do { \ + Z80Word w; \ + Z80Byte b; \ + \ + b=IN(cpu->BC.w); \ + POKE(cpu->HL.w,b); \ + \ + cpu->BC.b[HI]--; \ + cpu->HL.w++; \ + \ + cpu->AF.b[LO]=SZtable[cpu->BC.b[HI]]; \ + SETHIDDEN(cpu->BC.b[HI]); \ + \ + w=(((Z80Word)cpu->BC.b[LO])&0xff)+b; \ + \ + if (b&0x80) \ + SETFLAG(N_Z80); \ + \ + if (w&0x100) \ + { \ + SETFLAG(C_Z80); \ + SETFLAG(H_Z80); \ + } \ + else \ + { \ + CLRFLAG(C_Z80); \ + CLRFLAG(H_Z80); \ + } \ +} while(0) + +#define IND \ +do { \ + Z80Word w; \ + Z80Byte b; \ + \ + b=IN(cpu->BC.w); \ + POKE(cpu->HL.w,b); \ + \ + cpu->BC.b[HI]--; \ + cpu->HL.w--; \ + \ + cpu->AF.b[LO]=SZtable[cpu->BC.b[HI]]; \ + SETHIDDEN(cpu->BC.b[HI]); \ + \ + w=(((Z80Word)cpu->BC.b[LO])&0xff)+b; \ + \ + if (b&0x80) \ + SETFLAG(N_Z80); \ + \ + if (w&0x100) \ + { \ + SETFLAG(C_Z80); \ + SETFLAG(H_Z80); \ + } \ + else \ + { \ + CLRFLAG(C_Z80); \ + CLRFLAG(H_Z80); \ + } \ +} while(0) \ + +#define OUTI \ +do { \ + OUT(cpu->BC.w,PEEK(cpu->HL.w)); \ + \ + cpu->HL.w++; \ + cpu->BC.b[HI]--; \ + \ + cpu->AF.b[LO]=SZtable[cpu->BC.b[HI]]; \ + SETHIDDEN(cpu->BC.b[HI]); \ +} while(0) + +#define OUTD \ +do { \ + OUT(cpu->BC.w,PEEK(cpu->HL.w)); \ + \ + cpu->HL.w--; \ + cpu->BC.b[HI]--; \ + \ + cpu->AF.b[LO]=SZtable[cpu->BC.b[HI]]; \ + SETFLAG(N_Z80); \ + SETHIDDEN(cpu->BC.b[HI]); \ +} while(0) + + +/* ---------------------------------------- BASE OPCODE SHORT-HAND BLOCKS +*/ + +#define LD_BLOCK(BASE,DEST,DEST2) \ + case BASE: /* LD DEST,B */ \ + TSTATE(4); \ + DEST=cpu->BC.b[HI]; \ + break; \ + \ + case BASE+1: /* LD DEST,C */ \ + TSTATE(4); \ + DEST=cpu->BC.b[LO]; \ + break; \ + \ + case BASE+2: /* LD DEST,D */ \ + TSTATE(4); \ + DEST=cpu->DE.b[HI]; \ + break; \ + \ + case BASE+3: /* LD DEST,E */ \ + TSTATE(4); \ + DEST=cpu->DE.b[LO]; \ + break; \ + \ + case BASE+4: /* LD DEST,H */ \ + TSTATE(4); \ + DEST=*H; \ + break; \ + \ + case BASE+5: /* LD DEST,L */ \ + TSTATE(4); \ + DEST=*L; \ + break; \ + \ + case BASE+6: /* LD DEST,(HL) */ \ + TSTATE(7); \ + OFFSET(off); \ + DEST2=PEEK(*HL+off); \ + break; \ + \ + case BASE+7: /* LD DEST,A */ \ + TSTATE(4); \ + DEST=cpu->AF.b[HI]; \ + break; + +#define ALU_BLOCK(BASE,OP) \ + case BASE: /* OP A,B */ \ + TSTATE(4); \ + OP(cpu->BC.b[HI]); \ + break; \ + \ + case BASE+1: /* OP A,C */ \ + TSTATE(4); \ + OP(cpu->BC.b[LO]); \ + break; \ + \ + case BASE+2: /* OP A,D */ \ + TSTATE(4); \ + OP(cpu->DE.b[HI]); \ + break; \ + \ + case BASE+3: /* OP A,E */ \ + TSTATE(4); \ + OP(cpu->DE.b[LO]); \ + break; \ + \ + case BASE+4: /* OP A,H */ \ + TSTATE(4); \ + OP(*H); \ + break; \ + \ + case BASE+5: /* OP A,L */ \ + TSTATE(4); \ + OP(*L); \ + break; \ + \ + case BASE+6: /* OP A,(HL) */ \ + TSTATE(7); \ + OFFSET(off); \ + OP_ON_MEM(OP,*HL+off); \ + break; \ + \ + case BASE+7: /* OP A,A */ \ + TSTATE(4); \ + OP(cpu->AF.b[HI]); \ + break; + + +/* ---------------------------------------- CB OPCODE SHORT-HAND BLOCKS +*/ + +#define CB_ALU_BLOCK(BASE,OP) \ + case BASE: /* OP B */ \ + TSTATE(8); \ + OP(cpu->BC.b[HI]); \ + break; \ + \ + case BASE+1: /* OP C */ \ + TSTATE(8); \ + OP(cpu->BC.b[LO]); \ + break; \ + \ + case BASE+2: /* OP D */ \ + TSTATE(8); \ + OP(cpu->DE.b[HI]); \ + break; \ + \ + case BASE+3: /* OP E */ \ + TSTATE(8); \ + OP(cpu->DE.b[LO]); \ + break; \ + \ + case BASE+4: /* OP H */ \ + TSTATE(8); \ + OP(cpu->HL.b[HI]); \ + break; \ + \ + case BASE+5: /* OP L */ \ + TSTATE(8); \ + OP(cpu->HL.b[LO]); \ + break; \ + \ + case BASE+6: /* OP (HL) */ \ + TSTATE(15); \ + OP_ON_MEM(OP,cpu->HL.w); \ + break; \ + \ + case BASE+7: /* OP A */ \ + TSTATE(8); \ + OP(cpu->AF.b[HI]); \ + break; + +#define CB_BITMANIP_BLOCK(BASE,OP,BIT_NO) \ + case BASE: /* OP B */ \ + TSTATE(8); \ + OP(cpu->BC.b[HI],BIT_NO); \ + break; \ + \ + case BASE+1: /* OP C */ \ + TSTATE(8); \ + OP(cpu->BC.b[LO],BIT_NO); \ + break; \ + \ + case BASE+2: /* OP D */ \ + TSTATE(8); \ + OP(cpu->DE.b[HI],BIT_NO); \ + break; \ + \ + case BASE+3: /* OP E */ \ + TSTATE(8); \ + OP(cpu->DE.b[LO],BIT_NO); \ + break; \ + \ + case BASE+4: /* OP H */ \ + TSTATE(8); \ + OP(cpu->HL.b[HI],BIT_NO); \ + break; \ + \ + case BASE+5: /* OP L */ \ + TSTATE(8); \ + OP(cpu->HL.b[LO],BIT_NO); \ + break; \ + \ + case BASE+6: /* OP (HL) */ \ + TSTATE(12); \ + OP_ON_MEM_WITH_ARG(OP,cpu->HL.w,BIT_NO); \ + break; \ + \ + case BASE+7: /* OP A */ \ + TSTATE(8); \ + OP(cpu->AF.b[HI],BIT_NO); \ + break; + +/* ---------------------------------------- SHIFTED CB OPCODE SHORT-HAND BLOCKS +*/ + +#define SHIFTED_CB_ALU_BLOCK(BASE,OP) \ + case BASE: /* OP B */ \ + TSTATE(8); \ + OP_ON_MEM_WITH_COPY(OP,addr,cpu->BC.b[HI]); \ + break; \ + \ + case BASE+1: /* OP C */ \ + TSTATE(8); \ + OP_ON_MEM_WITH_COPY(OP,addr,cpu->BC.b[LO]); \ + break; \ + \ + case BASE+2: /* OP D */ \ + TSTATE(8); \ + OP_ON_MEM_WITH_COPY(OP,addr,cpu->DE.b[HI]); \ + break; \ + \ + case BASE+3: /* OP E */ \ + TSTATE(8); \ + OP_ON_MEM_WITH_COPY(OP,addr,cpu->DE.b[LO]); \ + break; \ + \ + case BASE+4: /* OP H */ \ + TSTATE(8); \ + OP_ON_MEM_WITH_COPY(OP,addr,cpu->HL.b[HI]); \ + break; \ + \ + case BASE+5: /* OP L */ \ + TSTATE(8); \ + OP_ON_MEM_WITH_COPY(OP,addr,cpu->HL.b[LO]); \ + break; \ + \ + case BASE+6: /* OP (HL) */ \ + TSTATE(15); \ + OP_ON_MEM(OP,addr); \ + break; \ + \ + case BASE+7: /* OP A */ \ + TSTATE(8); \ + OP_ON_MEM_WITH_COPY(OP,addr,cpu->AF.b[HI]); \ + break; + +#define SHIFTED_CB_BITMANIP_BLOCK(BASE,OP,BIT_NO) \ + case BASE: /* OP B */ \ + TSTATE(8); \ + OP_ON_MEM_WITH_ARG_AND_COPY(OP,addr,BIT_NO,cpu->BC.b[HI]); \ + break; \ + \ + case BASE+1: /* OP C */ \ + TSTATE(8); \ + OP_ON_MEM_WITH_ARG_AND_COPY(OP,addr,BIT_NO,cpu->BC.b[LO]); \ + break; \ + \ + case BASE+2: /* OP D */ \ + TSTATE(8); \ + OP_ON_MEM_WITH_ARG_AND_COPY(OP,addr,BIT_NO,cpu->DE.b[HI]); \ + break; \ + \ + case BASE+3: /* OP E */ \ + TSTATE(8); \ + OP_ON_MEM_WITH_ARG_AND_COPY(OP,addr,BIT_NO,cpu->DE.b[LO]); \ + break; \ + \ + case BASE+4: /* OP H */ \ + TSTATE(8); \ + OP_ON_MEM_WITH_ARG_AND_COPY(OP,addr,BIT_NO,cpu->HL.b[HI]); \ + break; \ + \ + case BASE+5: /* OP L */ \ + TSTATE(8); \ + OP_ON_MEM_WITH_ARG_AND_COPY(OP,addr,BIT_NO,cpu->HL.b[LO]); \ + break; \ + \ + case BASE+6: /* OP (HL) */ \ + TSTATE(12); \ + OP_ON_MEM_WITH_ARG(OP,addr,BIT_NO); \ + break; \ + \ + case BASE+7: /* OP A */ \ + TSTATE(8); \ + OP_ON_MEM_WITH_ARG_AND_COPY(OP,addr,BIT_NO,cpu->AF.b[HI]); \ + break; + +/* ---------------------------------------- DAA +*/ + +/* This alogrithm is based on info from + http://www.worldofspectrum.org/faq/reference/z80reference.htm +*/ +static void DAA (Z80 *cpu) +{ + Z80Byte add=0; + Z80Byte carry=0; + Z80Byte nf=cpu->AF.b[LO]&N_Z80; + Z80Byte acc=cpu->AF.b[HI]; + + if (acc>0x99 || IS_C) + { + add|=0x60; + carry=C_Z80; + } + + if ((acc&0xf)>0x9 || IS_H) + { + add|=0x06; + } + + if (nf) + { + cpu->AF.b[HI]-=add; + } + else + { + cpu->AF.b[HI]+=add; + } + + cpu->AF.b[LO]=PSZtable[cpu->AF.b[HI]] + | carry + | nf + | ((acc^cpu->AF.b[HI])&H_Z80) + | (cpu->AF.b[HI]&(B3_Z80|B5_Z80)); +} + +/* ---------------------------------------- HANDLERS FOR ED OPCODES +*/ +static void DecodeED(Z80 *cpu, Z80Byte opcode) +{ + switch(opcode) + { + case 0x40: /* IN B,(C) */ + TSTATE(12); + + if (PRIV->pread) + { + cpu->BC.b[HI]=PRIV->pread(cpu,cpu->BC.w); + } + else + { + cpu->BC.b[HI]=0; + } + + cpu->AF.b[LO]=CARRY|PSZtable[cpu->BC.b[HI]]; + SETHIDDEN(cpu->BC.b[HI]); + break; + + case 0x41: /* OUT (C),B */ + TSTATE(12); + if (PRIV->pwrite) PRIV->pwrite(cpu,cpu->BC.w,cpu->BC.b[HI]); + break; + + case 0x42: /* SBC HL,BC */ + TSTATE(15); + SBC16(cpu->HL.w,cpu->BC.w); + break; + + case 0x43: /* LD (nnnn),BC */ + TSTATE(20); + POKEW(FETCH_WORD,cpu->BC.w); + break; + + case 0x44: /* NEG */ + { + Z80Byte b; + + TSTATE(8); + + b=cpu->AF.b[HI]; + cpu->AF.b[HI]=0; + SUB8(b); + break; + } + + case 0x45: /* RETN */ + TSTATE(14); + cpu->IFF1=cpu->IFF2; + POP(cpu->PC); + break; + + case 0x46: /* IM 0 */ + TSTATE(8); + cpu->IM=0; + break; + + case 0x47: /* LD I,A */ + TSTATE(9); + cpu->I=cpu->AF.b[HI]; + break; + + case 0x48: /* IN C,(C) */ + TSTATE(12); + + if (PRIV->pread) + { + cpu->BC.b[LO]=PRIV->pread(cpu,cpu->BC.w); + } + else + { + cpu->BC.b[LO]=0; + } + + cpu->AF.b[LO]=CARRY|PSZtable[cpu->BC.b[LO]]; + SETHIDDEN(cpu->BC.b[LO]); + break; + + case 0x49: /* OUT (C),C */ + TSTATE(12); + if (PRIV->pwrite) PRIV->pwrite(cpu,cpu->BC.w,cpu->BC.b[LO]); + break; + + case 0x4a: /* ADC HL,BC */ + TSTATE(15); + ADC16(cpu->HL.w,cpu->BC.w); + break; + + case 0x4b: /* LD BC,(nnnn) */ + TSTATE(20); + cpu->BC.w=PEEKW(FETCH_WORD); + break; + + case 0x4c: /* NEG */ + { + Z80Byte b; + + TSTATE(8); + + b=cpu->AF.b[HI]; + cpu->AF.b[HI]=0; + SUB8(b); + break; + } + + case 0x4d: /* RETI */ + TSTATE(14); + CALLBACK(eZ80_RETI,0); + cpu->IFF1=cpu->IFF2; + POP(cpu->PC); + break; + + case 0x4e: /* IM 0/1 */ + TSTATE(8); + cpu->IM=0; + break; + + case 0x4f: /* LD R,A */ + TSTATE(9); + cpu->R=cpu->AF.b[HI]; + break; + + case 0x50: /* IN D,(C) */ + TSTATE(12); + + if (PRIV->pread) + { + cpu->DE.b[HI]=PRIV->pread(cpu,cpu->BC.w); + } + else + { + cpu->DE.b[HI]=0; + } + + cpu->AF.b[LO]=CARRY|PSZtable[cpu->DE.b[HI]]; + SETHIDDEN(cpu->BC.b[HI]); + break; + + case 0x51: /* OUT (C),D */ + TSTATE(12); + if (PRIV->pwrite) PRIV->pwrite(cpu,cpu->BC.w,cpu->DE.b[HI]); + break; + + case 0x52: /* SBC HL,DE */ + TSTATE(15); + SBC16(cpu->HL.w,cpu->DE.w); + break; + + case 0x53: /* LD (nnnn),DE */ + TSTATE(20); + POKEW(FETCH_WORD,cpu->DE.w); + break; + + case 0x54: /* NEG */ + { + Z80Byte b; + + TSTATE(8); + + b=cpu->AF.b[HI]; + cpu->AF.b[HI]=0; + SUB8(b); + break; + } + + case 0x55: /* RETN */ + TSTATE(14); + cpu->IFF1=cpu->IFF2; + POP(cpu->PC); + break; + + case 0x56: /* IM 1 */ + TSTATE(8); + cpu->IM=1; + break; + + case 0x57: /* LD A,I */ + TSTATE(9); + cpu->AF.b[HI]=cpu->I; + break; + + case 0x58: /* IN E,(C) */ + TSTATE(12); + + if (PRIV->pread) + { + cpu->DE.b[LO]=PRIV->pread(cpu,cpu->BC.w); + } + else + { + cpu->BC.b[LO]=0; + } + + cpu->AF.b[LO]=CARRY|PSZtable[cpu->DE.b[LO]]; + SETHIDDEN(cpu->DE.b[LO]); + break; + + case 0x59: /* OUT (C),E */ + TSTATE(12); + if (PRIV->pwrite) PRIV->pwrite(cpu,cpu->BC.w,cpu->DE.b[LO]); + break; + + case 0x5a: /* ADC HL,DE */ + TSTATE(15); + ADC16(cpu->HL.w,cpu->DE.w); + break; + + case 0x5b: /* LD DE,(nnnn) */ + TSTATE(20); + cpu->DE.w=PEEKW(FETCH_WORD); + break; + + case 0x5c: /* NEG */ + { + Z80Byte b; + + TSTATE(8); + + b=cpu->AF.b[HI]; + cpu->AF.b[HI]=0; + SUB8(b); + break; + } + + case 0x5d: /* RETN */ + TSTATE(14); + cpu->IFF1=cpu->IFF2; + POP(cpu->PC); + break; + + case 0x5e: /* IM 2 */ + TSTATE(8); + cpu->IM=2; + break; + + case 0x5f: /* LD A,R */ + TSTATE(9); + cpu->AF.b[HI]=cpu->R; + break; + + case 0x60: /* IN H,(C) */ + TSTATE(12); + + if (PRIV->pread) + { + cpu->HL.b[HI]=PRIV->pread(cpu,cpu->BC.w); + } + else + { + cpu->HL.b[HI]=0; + } + + cpu->AF.b[LO]=CARRY|PSZtable[cpu->HL.b[HI]]; + SETHIDDEN(cpu->HL.b[HI]); + break; + + case 0x61: /* OUT (C),H */ + TSTATE(12); + if (PRIV->pwrite) PRIV->pwrite(cpu,cpu->BC.w,cpu->HL.b[HI]); + break; + + case 0x62: /* SBC HL,HL */ + TSTATE(15); + SBC16(cpu->HL.w,cpu->HL.w); + break; + + case 0x63: /* LD (nnnn),HL */ + TSTATE(20); + POKEW(FETCH_WORD,cpu->HL.w); + break; + + case 0x64: /* NEG */ + { + Z80Byte b; + + TSTATE(8); + + b=cpu->AF.b[HI]; + cpu->AF.b[HI]=0; + SUB8(b); + break; + } + + case 0x65: /* RETN */ + TSTATE(14); + cpu->IFF1=cpu->IFF2; + POP(cpu->PC); + break; + + case 0x66: /* IM 0 */ + TSTATE(8); + cpu->IM=0; + break; + + case 0x67: /* RRD */ + { + Z80Byte b; + + TSTATE(18); + + b=PEEK(cpu->HL.w); + + POKE(cpu->HL.w,(b>>4)|(cpu->AF.b[HI]<<4)); + cpu->AF.b[HI]=(cpu->AF.b[HI]&0xf0)|(b&0x0f); + + cpu->AF.b[LO]=CARRY|PSZtable[cpu->AF.b[HI]]; + SETHIDDEN(cpu->AF.b[HI]); + break; + } + + case 0x68: /* IN L,(C) */ + TSTATE(12); + + if (PRIV->pread) + { + cpu->HL.b[LO]=PRIV->pread(cpu,cpu->BC.w); + } + else + { + cpu->HL.b[LO]=0; + } + + cpu->AF.b[LO]=CARRY|PSZtable[cpu->HL.b[LO]]; + SETHIDDEN(cpu->HL.b[LO]); + break; + + case 0x69: /* OUT (C),L */ + TSTATE(12); + if (PRIV->pwrite) PRIV->pwrite(cpu,cpu->BC.w,cpu->HL.b[LO]); + break; + + case 0x6a: /* ADC HL,HL */ + TSTATE(15); + ADC16(cpu->HL.w,cpu->HL.w); + break; + + case 0x6b: /* LD HL,(nnnn) */ + TSTATE(20); + cpu->HL.w=PEEKW(FETCH_WORD); + break; + + case 0x6c: /* NEG */ + { + Z80Byte b; + + TSTATE(8); + + b=cpu->AF.b[HI]; + cpu->AF.b[HI]=0; + SUB8(b); + break; + } + + case 0x6d: /* RETN */ + TSTATE(14); + cpu->IFF1=cpu->IFF2; + POP(cpu->PC); + break; + + case 0x6e: /* IM 0/1 */ + TSTATE(8); + cpu->IM=0; + break; + + case 0x6f: /* RLD */ + { + Z80Byte b; + + TSTATE(18); + + b=PEEK(cpu->HL.w); + + POKE(cpu->HL.w,(b<<4)|(cpu->AF.b[HI]&0x0f)); + cpu->AF.b[HI]=(cpu->AF.b[HI]&0xf0)|(b>>4); + + cpu->AF.b[LO]=CARRY|PSZtable[cpu->AF.b[HI]]; + SETHIDDEN(cpu->AF.b[HI]); + break; + } + + case 0x70: /* IN (C) */ + { + Z80Byte b; + + TSTATE(12); + + if (PRIV->pread) + { + b=PRIV->pread(cpu,cpu->BC.w); + } + else + { + b=0; + } + + cpu->AF.b[LO]=CARRY|PSZtable[b]; + SETHIDDEN(b); + break; + } + + case 0x71: /* OUT (C) */ + TSTATE(12); + if (PRIV->pwrite) PRIV->pwrite(cpu,cpu->BC.w,0); + break; + + case 0x72: /* SBC HL,SP */ + TSTATE(15); + SBC16(cpu->HL.w,cpu->SP); + break; + + case 0x73: /* LD (nnnn),SP */ + TSTATE(20); + POKEW(FETCH_WORD,cpu->SP); + break; + + case 0x74: /* NEG */ + { + Z80Byte b; + + TSTATE(8); + + b=cpu->AF.b[HI]; + cpu->AF.b[HI]=0; + SUB8(b); + break; + } + + case 0x75: /* RETN */ + TSTATE(14); + cpu->IFF1=cpu->IFF2; + POP(cpu->PC); + break; + + case 0x76: /* IM 1 */ + TSTATE(8); + cpu->IM=1; + break; + + case 0x77: /* NOP */ + TSTATE(8); + CALLBACK(eZ80_EDHook,opcode); + break; + + case 0x78: /* IN A,(C) */ + TSTATE(12); + + if (PRIV->pread) + { + cpu->AF.b[HI]=PRIV->pread(cpu,cpu->BC.w); + } + else + { + cpu->AF.b[HI]=0; + } + + cpu->AF.b[LO]=CARRY|PSZtable[cpu->AF.b[HI]]; + SETHIDDEN(cpu->AF.b[HI]); + break; + + case 0x79: /* OUT (C),A */ + TSTATE(12); + if (PRIV->pwrite) PRIV->pwrite(cpu,cpu->BC.w,cpu->AF.b[HI]); + break; + + case 0x7a: /* ADC HL,SP */ + TSTATE(15); + ADC16(cpu->HL.w,cpu->SP); + break; + + case 0x7b: /* LD SP,(nnnn) */ + TSTATE(20); + cpu->SP=PEEKW(FETCH_WORD); + break; + + case 0x7c: /* NEG */ + { + Z80Byte b; + + TSTATE(8); + + b=cpu->AF.b[HI]; + cpu->AF.b[HI]=0; + SUB8(b); + break; + } + + case 0x7d: /* RETN */ + TSTATE(14); + cpu->IFF1=cpu->IFF2; + POP(cpu->PC); + break; + + case 0x7e: /* IM 2 */ + TSTATE(8); + cpu->IM=2; + break; + + case 0x7f: /* NOP */ + TSTATE(8); + CALLBACK(eZ80_EDHook,opcode); + break; + + case 0xa0: /* LDI */ + TSTATE(16); + LDI; + break; + + case 0xa1: /* CPI */ + TSTATE(16); + CPI; + break; + + case 0xa2: /* INI */ + TSTATE(16); + INI; + break; + + case 0xa3: /* OUTI */ + TSTATE(16); + OUTI; + break; + + case 0xa8: /* LDD */ + TSTATE(16); + LDD; + break; + + case 0xa9: /* CPD */ + TSTATE(16); + CPD; + break; + + case 0xaa: /* IND */ + TSTATE(16); + IND; + break; + + case 0xab: /* OUTD */ + TSTATE(16); + OUTD; + break; + + case 0xb0: /* LDIR */ + TSTATE(16); + LDI; + if (cpu->BC.w) + { + TSTATE(5); + cpu->PC-=2; + } + break; + + case 0xb1: /* CPIR */ + TSTATE(16); + CPI; + if (cpu->BC.w && !IS_Z) + { + TSTATE(5); + cpu->PC-=2; + } + break; + + case 0xb2: /* INIR */ + TSTATE(16); + INI; + if (cpu->BC.w) + { + TSTATE(5); + cpu->PC-=2; + } + break; + + case 0xb3: /* OTIR */ + TSTATE(16); + OUTI; + if (cpu->BC.w) + { + TSTATE(5); + cpu->PC-=2; + } + break; + + case 0xb8: /* LDDR */ + TSTATE(16); + LDD; + if (cpu->BC.w) + { + TSTATE(5); + cpu->PC-=2; + } + break; + + case 0xb9: /* CPDR */ + TSTATE(16); + CPD; + if (cpu->BC.w && !IS_Z) + { + TSTATE(5); + cpu->PC-=2; + } + break; + + case 0xba: /* INDR */ + TSTATE(16); + IND; + if (cpu->BC.w) + { + TSTATE(5); + cpu->PC-=2; + } + break; + + case 0xbb: /* OTDR */ + TSTATE(16); + OUTD; + if (cpu->BC.w) + { + TSTATE(5); + cpu->PC-=2; + } + break; + + /* All the rest are NOP/invalid + */ + default: + TSTATE(8); + CALLBACK(eZ80_EDHook,opcode); + break; + } +} + + +/* ---------------------------------------- HANDLERS FOR CB OPCODES +*/ +static void DecodeCB(Z80 *cpu, Z80Byte opcode) +{ + switch(opcode) + { + CB_ALU_BLOCK(0x00,RLC) + CB_ALU_BLOCK(0x08,RRC) + CB_ALU_BLOCK(0x10,RL) + CB_ALU_BLOCK(0x18,RR) + CB_ALU_BLOCK(0x20,SLA) + CB_ALU_BLOCK(0x28,SRA) + CB_ALU_BLOCK(0x30,SLL) + CB_ALU_BLOCK(0x38,SRL) + + CB_BITMANIP_BLOCK(0x40,BIT,0) + CB_BITMANIP_BLOCK(0x48,BIT,1) + CB_BITMANIP_BLOCK(0x50,BIT,2) + CB_BITMANIP_BLOCK(0x58,BIT,3) + CB_BITMANIP_BLOCK(0x60,BIT,4) + CB_BITMANIP_BLOCK(0x68,BIT,5) + CB_BITMANIP_BLOCK(0x70,BIT,6) + CB_BITMANIP_BLOCK(0x78,BIT,7) + + CB_BITMANIP_BLOCK(0x80,BIT_RES,0) + CB_BITMANIP_BLOCK(0x88,BIT_RES,1) + CB_BITMANIP_BLOCK(0x90,BIT_RES,2) + CB_BITMANIP_BLOCK(0x98,BIT_RES,3) + CB_BITMANIP_BLOCK(0xa0,BIT_RES,4) + CB_BITMANIP_BLOCK(0xa8,BIT_RES,5) + CB_BITMANIP_BLOCK(0xb0,BIT_RES,6) + CB_BITMANIP_BLOCK(0xb8,BIT_RES,7) + + CB_BITMANIP_BLOCK(0xc0,BIT_SET,0) + CB_BITMANIP_BLOCK(0xc8,BIT_SET,1) + CB_BITMANIP_BLOCK(0xd0,BIT_SET,2) + CB_BITMANIP_BLOCK(0xd8,BIT_SET,3) + CB_BITMANIP_BLOCK(0xe0,BIT_SET,4) + CB_BITMANIP_BLOCK(0xe8,BIT_SET,5) + CB_BITMANIP_BLOCK(0xf0,BIT_SET,6) + CB_BITMANIP_BLOCK(0xf8,BIT_SET,7) + } +} + + +static void ShiftedDecodeCB(Z80 *cpu, Z80Byte opcode, Z80Relative offset) +{ + Z80Word addr; + + /* See if we've come here from a IX/IY shift. + */ + switch (PRIV->shift) + { + case 0xdd: + addr=cpu->IX.w+offset; + break; + case 0xfd: + addr=cpu->IY.w+offset; + break; + default: + addr=cpu->HL.w; /* Play safe... */ + break; + } + + switch(opcode) + { + SHIFTED_CB_ALU_BLOCK(0x00,RLC) + SHIFTED_CB_ALU_BLOCK(0x08,RRC) + SHIFTED_CB_ALU_BLOCK(0x10,RL) + SHIFTED_CB_ALU_BLOCK(0x18,RR) + SHIFTED_CB_ALU_BLOCK(0x20,SLA) + SHIFTED_CB_ALU_BLOCK(0x28,SRA) + SHIFTED_CB_ALU_BLOCK(0x30,SLL) + SHIFTED_CB_ALU_BLOCK(0x38,SRL) + + SHIFTED_CB_BITMANIP_BLOCK(0x40,BIT,0) + SHIFTED_CB_BITMANIP_BLOCK(0x48,BIT,1) + SHIFTED_CB_BITMANIP_BLOCK(0x50,BIT,2) + SHIFTED_CB_BITMANIP_BLOCK(0x58,BIT,3) + SHIFTED_CB_BITMANIP_BLOCK(0x60,BIT,4) + SHIFTED_CB_BITMANIP_BLOCK(0x68,BIT,5) + SHIFTED_CB_BITMANIP_BLOCK(0x70,BIT,6) + SHIFTED_CB_BITMANIP_BLOCK(0x78,BIT,7) + + SHIFTED_CB_BITMANIP_BLOCK(0x80,BIT_RES,0) + SHIFTED_CB_BITMANIP_BLOCK(0x88,BIT_RES,1) + SHIFTED_CB_BITMANIP_BLOCK(0x90,BIT_RES,2) + SHIFTED_CB_BITMANIP_BLOCK(0x98,BIT_RES,3) + SHIFTED_CB_BITMANIP_BLOCK(0xa0,BIT_RES,4) + SHIFTED_CB_BITMANIP_BLOCK(0xa8,BIT_RES,5) + SHIFTED_CB_BITMANIP_BLOCK(0xb0,BIT_RES,6) + SHIFTED_CB_BITMANIP_BLOCK(0xb8,BIT_RES,7) + + SHIFTED_CB_BITMANIP_BLOCK(0xc0,BIT_SET,0) + SHIFTED_CB_BITMANIP_BLOCK(0xc8,BIT_SET,1) + SHIFTED_CB_BITMANIP_BLOCK(0xd0,BIT_SET,2) + SHIFTED_CB_BITMANIP_BLOCK(0xd8,BIT_SET,3) + SHIFTED_CB_BITMANIP_BLOCK(0xe0,BIT_SET,4) + SHIFTED_CB_BITMANIP_BLOCK(0xe8,BIT_SET,5) + SHIFTED_CB_BITMANIP_BLOCK(0xf0,BIT_SET,6) + SHIFTED_CB_BITMANIP_BLOCK(0xf8,BIT_SET,7) + } +} + + +/* ---------------------------------------- NORMAL OPCODE DECODER +*/ +void Z80_Decode(Z80 *cpu, Z80Byte opcode) +{ + Z80Word *HL; + Z80Byte *H; + Z80Byte *L; + Z80Relative off; + + /* See if we've come here from a IX/IY shift + */ + switch (PRIV->shift) + { + case 0xdd: + HL=&(cpu->IX.w); + L=cpu->IX.b+LO; + H=cpu->IX.b+HI; + break; + case 0xfd: + HL=&(cpu->IY.w); + L=cpu->IY.b+LO; + H=cpu->IY.b+HI; + break; + default: + HL=&(cpu->HL.w); + L=cpu->HL.b+LO; + H=cpu->HL.b+HI; + break; + } + + switch(opcode) + { + case 0x00: /* NOP */ + TSTATE(4); + break; + + case 0x01: /* LD BC,nnnn */ + TSTATE(10); + cpu->BC.w=FETCH_WORD; + break; + + case 0x02: /* LD (BC),A */ + TSTATE(7); + POKE(cpu->BC.w,cpu->AF.b[HI]); + break; + + case 0x03: /* INC BC */ + TSTATE(6); + cpu->BC.w++; + break; + + case 0x04: /* INC B */ + TSTATE(4); + INC8(cpu->BC.b[HI]); + break; + + case 0x05: /* DEC B */ + TSTATE(4); + DEC8(cpu->BC.b[HI]); + break; + + case 0x06: /* LD B,n */ + TSTATE(7); + cpu->BC.b[HI]=FETCH_BYTE; + break; + + case 0x07: /* RLCA */ + TSTATE(4); + RLCA; + break; + + case 0x08: /* EX AF,AF' */ + TSTATE(4); + SWAP(cpu->AF.w,cpu->AF_); + break; + + case 0x09: /* ADD HL,BC */ + TSTATE(11); + ADD16(*HL,cpu->BC.w); + break; + + case 0x0a: /* LD A,(BC) */ + TSTATE(7); + cpu->AF.b[HI]=PEEK(cpu->BC.w); + break; + + case 0x0b: /* DEC BC */ + TSTATE(6); + cpu->BC.w--; + break; + + case 0x0c: /* INC C */ + TSTATE(4); + INC8(cpu->BC.b[LO]); + break; + + case 0x0d: /* DEC C */ + TSTATE(4); + DEC8(cpu->BC.b[LO]); + break; + + case 0x0e: /* LD C,n */ + TSTATE(7); + cpu->BC.b[LO]=FETCH_BYTE; + break; + + case 0x0f: /* RRCA */ + TSTATE(4); + RRCA; + break; + + case 0x10: /* DJNZ */ + if (--(cpu->BC.b[HI])) + { + TSTATE(13); + JR; + } + else + { + TSTATE(8); + NOJR; + } + break; + + case 0x11: /* LD DE,nnnn */ + TSTATE(10); + cpu->DE.w=FETCH_WORD; + break; + + case 0x12: /* LD (DE),A */ + TSTATE(7); + POKE(cpu->DE.w,cpu->AF.b[HI]); + break; + + case 0x13: /* INC DE */ + TSTATE(6); + cpu->DE.w++; + break; + + case 0x14: /* INC D */ + TSTATE(4); + INC8(cpu->DE.b[HI]); + break; + + case 0x15: /* DEC D */ + TSTATE(4); + DEC8(cpu->DE.b[HI]); + break; + + case 0x16: /* LD D,n */ + TSTATE(7); + cpu->DE.b[HI]=FETCH_BYTE; + break; + + case 0x17: /* RLA */ + TSTATE(4); + RLA; + break; + + case 0x18: /* JR d */ + TSTATE(12); + JR; + break; + + case 0x19: /* ADD HL,DE */ + TSTATE(11); + ADD16(*HL,cpu->DE.w); + break; + + case 0x1a: /* LD A,(DE) */ + TSTATE(7); + cpu->AF.b[HI]=PEEK(cpu->DE.w); + break; + + case 0x1b: /* DEC DE */ + TSTATE(6); + cpu->DE.w--; + break; + + case 0x1c: /* INC E */ + TSTATE(4); + INC8(cpu->DE.b[LO]); + break; + + case 0x1d: /* DEC E */ + TSTATE(4); + DEC8(cpu->DE.b[LO]); + break; + + case 0x1e: /* LD E,n */ + TSTATE(7); + cpu->DE.b[LO]=FETCH_BYTE; + break; + + case 0x1f: /* RRA */ + TSTATE(4); + RRA; + break; + + case 0x20: /* JR NZ,e */ + JR_COND(!IS_Z); + break; + + case 0x21: /* LD HL,nnnn */ + TSTATE(10); + *HL=FETCH_WORD; + break; + + case 0x22: /* LD (nnnn),HL */ + TSTATE(16); + POKEW(FETCH_WORD,*HL); + break; + + case 0x23: /* INC HL */ + TSTATE(6); + (*HL)++; + break; + + case 0x24: /* INC H */ + TSTATE(4); + INC8(*H); + break; + + case 0x25: /* DEC H */ + TSTATE(4); + DEC8(*H); + break; + + case 0x26: /* LD H,n */ + TSTATE(7); + *H=FETCH_BYTE; + break; + + case 0x27: /* DAA */ + TSTATE(4); + DAA(cpu); + break; + + case 0x28: /* JR Z,d */ + JR_COND(IS_Z); + break; + + case 0x29: /* ADD HL,HL */ + TSTATE(11); + ADD16(*HL,*HL); + break; + + case 0x2a: /* LD HL,(nnnn) */ + TSTATE(7); + *HL=PEEKW(FETCH_WORD); + break; + + case 0x2b: /* DEC HL */ + TSTATE(6); + (*HL)--; + break; + + case 0x2c: /* INC L */ + TSTATE(4); + INC8(*L); + break; + + case 0x2d: /* DEC L */ + TSTATE(4); + DEC8(*L); + break; + + case 0x2e: /* LD L,n */ + TSTATE(7); + *L=FETCH_BYTE; + break; + + case 0x2f: /* CPL */ + TSTATE(4); + cpu->AF.b[HI]^=0xff; + SETFLAG(H_Z80); + SETFLAG(N_Z80); + SETHIDDEN(cpu->AF.b[HI]); + break; + + case 0x30: /* JR NC,d */ + JR_COND(!IS_C); + break; + + case 0x31: /* LD SP,nnnn */ + TSTATE(10); + cpu->SP=FETCH_WORD; + break; + + case 0x32: /* LD (nnnn),A */ + TSTATE(13); + POKE(FETCH_WORD,cpu->AF.b[HI]); + break; + + case 0x33: /* INC SP */ + TSTATE(6); + cpu->SP++; + break; + + case 0x34: /* INC (HL) */ + TSTATE(11); + OFFSET(off); + OP_ON_MEM(INC8,*HL+off); + break; + + case 0x35: /* DEC (HL) */ + TSTATE(11); + OFFSET(off); + OP_ON_MEM(DEC8,*HL+off); + break; + + case 0x36: /* LD (HL),n */ + TSTATE(10); + OFFSET(off); + POKE(*HL+off,FETCH_BYTE); + break; + + case 0x37: /* SCF */ + TSTATE(4); + cpu->AF.b[LO]=(cpu->AF.b[LO]&(S_Z80|Z_Z80|P_Z80)) + | C_Z80 + | (cpu->AF.b[HI]&(B3_Z80|B5_Z80)); + break; + + case 0x38: /* JR C,d */ + JR_COND(IS_C); + break; + + case 0x39: /* ADD HL,SP */ + TSTATE(11); + ADD16(*HL,cpu->SP); + break; + + case 0x3a: /* LD A,(nnnn) */ + TSTATE(13); + cpu->AF.b[HI]=PEEK(FETCH_WORD); + break; + + case 0x3b: /* DEC SP */ + TSTATE(6); + cpu->SP--; + break; + + case 0x3c: /* INC A */ + TSTATE(4); + INC8(cpu->AF.b[HI]); + break; + + case 0x3d: /* DEC A */ + TSTATE(4); + DEC8(cpu->AF.b[HI]); + break; + + case 0x3e: /* LD A,n */ + TSTATE(7); + cpu->AF.b[HI]=FETCH_BYTE; + break; + + case 0x3f: /* CCF */ + TSTATE(4); + + if (CARRY) + SETFLAG(H_Z80); + else + CLRFLAG(H_Z80); + + cpu->AF.b[LO]^=C_Z80; + SETHIDDEN(cpu->AF.b[HI]); + break; + + LD_BLOCK(0x40,cpu->BC.b[HI],cpu->BC.b[HI]) + LD_BLOCK(0x48,cpu->BC.b[LO],cpu->BC.b[LO]) + LD_BLOCK(0x50,cpu->DE.b[HI],cpu->DE.b[HI]) + LD_BLOCK(0x58,cpu->DE.b[LO],cpu->DE.b[LO]) + LD_BLOCK(0x60,*H,cpu->HL.b[HI]) + LD_BLOCK(0x68,*L,cpu->HL.b[LO]) + + case 0x70: /* LD (HL),B */ + TSTATE(7); + OFFSET(off); + POKE(*HL+off,cpu->BC.b[HI]); + break; + + case 0x71: /* LD (HL),C */ + TSTATE(7); + OFFSET(off); + POKE(*HL+off,cpu->BC.b[LO]); + break; + + case 0x72: /* LD (HL),D */ + TSTATE(7); + OFFSET(off); + POKE(*HL+off,cpu->DE.b[HI]); + break; + + case 0x73: /* LD (HL),E */ + TSTATE(7); + OFFSET(off); + POKE(*HL+off,cpu->DE.b[LO]); + break; + + case 0x74: /* LD (HL),H */ + TSTATE(7); + OFFSET(off); + POKE(*HL+off,cpu->HL.b[HI]); + break; + + case 0x75: /* LD (HL),L */ + TSTATE(7); + OFFSET(off); + POKE(*HL+off,cpu->HL.b[LO]); + break; + + case 0x76: /* HALT */ + TSTATE(4); + cpu->PC--; + + if (!PRIV->halt) + CALLBACK(eZ80_Halt,1); + + PRIV->halt=TRUE; + break; + + case 0x77: /* LD (HL),A */ + TSTATE(7); + OFFSET(off); + POKE(*HL+off,cpu->AF.b[HI]); + break; + + LD_BLOCK(0x78,cpu->AF.b[HI],cpu->AF.b[HI]) + + ALU_BLOCK(0x80,ADD8) + ALU_BLOCK(0x88,ADC8) + ALU_BLOCK(0x90,SUB8) + ALU_BLOCK(0x98,SBC8) + ALU_BLOCK(0xa0,AND) + ALU_BLOCK(0xa8,XOR) + ALU_BLOCK(0xb0,OR) + ALU_BLOCK(0xb8,CMP8) + + case 0xc0: /* RET NZ */ + RET_COND(!IS_Z); + break; + + case 0xc1: /* POP BC */ + TSTATE(10); + POP(cpu->BC.w); + break; + + case 0xc2: /* JP NZ,nnnn */ + JP_COND(!IS_Z); + break; + + case 0xc3: /* JP nnnn */ + JP_COND(1); + break; + + case 0xc4: /* CALL NZ,nnnn */ + CALL_COND(!IS_Z); + break; + + case 0xc5: /* PUSH BC */ + TSTATE(10); + PUSH(cpu->BC.w); + break; + + case 0xc6: /* ADD A,n */ + TSTATE(7); + ADD8(FETCH_BYTE); + break; + + case 0xc7: /* RST 0 */ + RST(0); + break; + + case 0xc8: /* RET Z */ + RET_COND(IS_Z); + break; + + case 0xc9: /* RET */ + TSTATE(10); + POP(cpu->PC); + break; + + case 0xca: /* JP Z,nnnn */ + JP_COND(IS_Z); + break; + + case 0xcb: /* CB PREFIX */ + INC_R; + + /* Check for previous IX/IY shift. + */ + if (PRIV->shift!=0) + { + Z80Relative cb_offset; + + TSTATE(4); /* Wild stab in the dark! */ + cb_offset=FETCH_BYTE; + ShiftedDecodeCB(cpu,FETCH_BYTE,cb_offset); + } + else + { + DecodeCB(cpu,FETCH_BYTE); + } + break; + + case 0xcc: /* CALL Z,nnnn */ + CALL_COND(IS_Z); + break; + + case 0xcd: /* CALL nnnn */ + CALL_COND(1); + break; + + case 0xce: /* ADC A,n */ + ADC8(FETCH_BYTE); + break; + + case 0xcf: /* RST 8 */ + RST(8); + break; + + case 0xd0: /* RET NC */ + RET_COND(!IS_C); + break; + + case 0xd1: /* POP DE */ + TSTATE(10); + POP(cpu->DE.w); + break; + + case 0xd2: /* JP NC,nnnn */ + JP_COND(!IS_C); + break; + + case 0xd3: /* OUT (n),A */ + TSTATE(11); + if (PRIV->pwrite) + { + Z80Word port; + + port=FETCH_BYTE; + port|=(Z80Word)cpu->AF.b[HI]<<8; + PRIV->pwrite(cpu,port,cpu->AF.b[HI]); + } + else + cpu->PC++; + break; + + case 0xd4: /* CALL NC,nnnn */ + CALL_COND(!IS_C); + break; + + case 0xd5: /* PUSH DE */ + TSTATE(11); + PUSH(cpu->DE.w); + break; + + case 0xd6: /* SUB A,n */ + TSTATE(7); + SUB8(FETCH_BYTE); + break; + + case 0xd7: /* RST 10 */ + RST(0x10); + break; + + case 0xd8: /* RET C */ + RET_COND(IS_C); + break; + + case 0xd9: /* EXX */ + TSTATE(4); + SWAP(cpu->BC.w,cpu->BC_); + SWAP(cpu->DE.w,cpu->DE_); + SWAP(cpu->HL.w,cpu->HL_); + break; + + case 0xda: /* JP C,nnnn */ + JP_COND(IS_C); + break; + + case 0xdb: /* IN A,(n) */ + TSTATE(11); + if (PRIV->pread) + { + Z80Word port; + + port=FETCH_BYTE; + port|=(Z80Word)cpu->AF.b[HI]<<8; + cpu->AF.b[HI]=PRIV->pread(cpu,port); + } + else + cpu->PC++; + break; + + case 0xdc: /* CALL C,nnnn */ + CALL_COND(IS_C); + break; + + case 0xdd: /* DD PREFIX */ + TSTATE(4); + INC_R; + + PRIV->shift=opcode; + Z80_Decode(cpu,FETCH_BYTE); + break; + + case 0xde: /* SBC A,n */ + TSTATE(7); + SBC8(FETCH_BYTE); + break; + + case 0xdf: /* RST 18 */ + RST(0x18); + break; + + case 0xe0: /* RET PO */ + RET_COND(!IS_P); + break; + + case 0xe1: /* POP HL */ + TSTATE(10); + POP(*HL); + break; + + case 0xe2: /* JP PO,nnnn */ + JP_COND(!IS_P); + break; + + case 0xe3: /* EX (SP),HL */ + { + Z80Word tmp; + TSTATE(19); + POP(tmp); + PUSH(*HL); + *HL=tmp; + } + break; + + case 0xe4: /* CALL PO,nnnn */ + CALL_COND(!IS_P); + break; + + case 0xe5: /* PUSH HL */ + TSTATE(10); + PUSH(*HL); + break; + + case 0xe6: /* AND A,n */ + TSTATE(7); + AND(FETCH_BYTE); + break; + + case 0xe7: /* RST 20 */ + RST(0x20); + break; + + case 0xe8: /* RET PE */ + RET_COND(IS_P); + break; + + case 0xe9: /* JP (HL) */ + TSTATE(4); + cpu->PC=*HL; + break; + + case 0xea: /* JP PE,nnnn */ + JP_COND(IS_P); + break; + + case 0xeb: /* EX DE,HL */ + TSTATE(4); + SWAP(cpu->DE.w,*HL); + break; + + case 0xec: /* CALL PE,nnnn */ + CALL_COND(IS_P); + break; + + case 0xed: /* ED PREFIX */ + INC_R; + DecodeED(cpu,FETCH_BYTE); + break; + + case 0xee: /* XOR A,n */ + TSTATE(7); + XOR(FETCH_BYTE); + break; + + case 0xef: /* RST 28 */ + RST(0x28); + break; + + case 0xf0: /* RET P */ + RET_COND(!IS_S); + break; + + case 0xf1: /* POP AF */ + TSTATE(10); + POP(cpu->AF.w); + break; + + case 0xf2: /* JP P,nnnn */ + JP_COND(!IS_S); + break; + + case 0xf3: /* DI */ + TSTATE(4); + cpu->IFF1=0; + cpu->IFF2=0; + break; + + case 0xf4: /* CALL P,nnnn */ + CALL_COND(!IS_S); + break; + + case 0xf5: /* PUSH AF */ + TSTATE(10); + PUSH(cpu->AF.w); + break; + + case 0xf6: /* OR A,n */ + TSTATE(7); + OR(FETCH_BYTE); + break; + + case 0xf7: /* RST 30 */ + RST(0x30); + break; + + case 0xf8: /* RET M */ + RET_COND(IS_S); + break; + + case 0xf9: /* LD SP,HL */ + TSTATE(6); + cpu->SP=*HL; + break; + + case 0xfa: /* JP M,nnnn */ + JP_COND(IS_S); + break; + + case 0xfb: /* EI */ + TSTATE(4); + cpu->IFF1=1; + cpu->IFF2=1; + break; + + case 0xfc: /* CALL M,nnnn */ + CALL_COND(IS_S); + break; + + case 0xfd: /* FD PREFIX */ + TSTATE(4); + INC_R; + + PRIV->shift=opcode; + Z80_Decode(cpu,FETCH_BYTE); + break; + + case 0xfe: /* CP A,n */ + TSTATE(7); + CMP8(FETCH_BYTE); + break; + + case 0xff: /* RST 38 */ + RST(0x38); + break; + + } +} + + +/* END OF FILE */ diff --git a/source/z80_dis.c b/source/z80_dis.c new file mode 100644 index 0000000..28bc098 --- /dev/null +++ b/source/z80_dis.c @@ -0,0 +1,2494 @@ +/* + + z80 - Z80 Emulator + + Copyright (C) 2006 Ian Cowburn <ianc@noddybox.co.uk> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + 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. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + ------------------------------------------------------------------------- + + $Id: z80_dis.c 4 2006-10-04 23:05:43Z ianc $ + +*/ +static const char ident[]="$Id: z80_dis.c 4 2006-10-04 23:05:43Z ianc $"; + +#include "z80_config.h" + +#ifdef ENABLE_DISASSEM + +#include <stdio.h> +#include <string.h> +#include <stdarg.h> + +#include "z80.h" +#include "z80_private.h" + +static Z80Relative cb_off; + +/* ---------------------------------------- SHARED ROUTINES +*/ +static const char *z80_dis_reg8[]={"b","c","d","e","h","l","(hl)","a"}; +static const char *z80_dis_reg16[]={"bc","de","hl","sp"}; +static const char *z80_dis_condition[]={"nz","z","nc","c","po","pe","p","m"}; + +static const char *dis_op; +static const char *dis_arg; + +const char *Z80_Dis_Printf(const char *format, ...) +{ + static int p=0; + static char s[16][80]; + va_list arg; + + va_start(arg,format); + p=(p+1)%16; + vsprintf(s[p],format,arg); + va_end(arg); + + return s[p]; +} + + +Z80Byte Z80_Dis_FetchByte(Z80 *cpu, Z80Word *pc) +{ +#ifdef ENABLE_ARRAY_MEMORY + return Z80_MEMORY[(*pc)++]; +#else + return cpu->priv->disread(cpu,(*pc)++); +#endif +} + + +Z80Word Z80_Dis_FetchWord(Z80 *cpu, Z80Word *pc) +{ + Z80Byte l,h; + + l=Z80_Dis_FetchByte(cpu,pc); + h=Z80_Dis_FetchByte(cpu,pc); + + return ((Z80Word)h<<8)|l; +} + + +void Z80_Dis_Set(const char *op, const char *arg) +{ + dis_op=op; + dis_arg=arg; +} + + +const char *Z80_Dis_GetOp(void) +{ + return dis_op ? dis_op : ""; +} + + +const char *Z80_Dis_GetArg(void) +{ + return dis_arg ? dis_arg : ""; +} + + +static const char *GetLabel(Z80Word w) +{ + if (z80_labels) + { + int f; + + for(f=0;z80_labels[f].label;f++) + { + if (z80_labels[f].address==w) + { + return z80_labels[f].label; + } + } + } + + return NULL; +} + + + +/* ---------------------------------------- CB xx BYTE OPCODES +*/ +static void DIS_RLC_R8 (Z80 *z80, Z80Byte op, Z80Word *pc) +{ + const char *reg; + + reg=z80_dis_reg8[op%8]; + Z80_Dis_Set("rlc",reg); +} + +static void DIS_RRC_R8 (Z80 *z80, Z80Byte op, Z80Word *pc) +{ + const char *reg; + + reg=z80_dis_reg8[op%8]; + Z80_Dis_Set("rrc",reg); +} + +static void DIS_RL_R8 (Z80 *z80, Z80Byte op, Z80Word *pc) +{ + const char *reg; + + reg=z80_dis_reg8[op%8]; + Z80_Dis_Set("rl",reg); +} + +static void DIS_RR_R8 (Z80 *z80, Z80Byte op, Z80Word *pc) +{ + const char *reg; + + reg=z80_dis_reg8[op%8]; + Z80_Dis_Set("rr",reg); +} + +static void DIS_SLA_R8 (Z80 *z80, Z80Byte op, Z80Word *pc) +{ + const char *reg; + + reg=z80_dis_reg8[op%8]; + Z80_Dis_Set("sla",reg); +} + +static void DIS_SRA_R8 (Z80 *z80, Z80Byte op, Z80Word *pc) +{ + const char *reg; + + reg=z80_dis_reg8[op%8]; + Z80_Dis_Set("sra",reg); +} + +static void DIS_SLL_R8 (Z80 *z80, Z80Byte op, Z80Word *pc) +{ + const char *reg; + + reg=z80_dis_reg8[op%8]; + Z80_Dis_Set("sll",reg); +} + +static void DIS_SRL_R8 (Z80 *z80, Z80Byte op, Z80Word *pc) +{ + const char *reg; + + reg=z80_dis_reg8[op%8]; + Z80_Dis_Set("srl",reg); +} + +static void DIS_BIT_R8 (Z80 *z80, Z80Byte op, Z80Word *pc) +{ + const char *reg; + int bit; + + reg=z80_dis_reg8[op%8]; + bit=(op-0x40)/8; + Z80_Dis_Set("bit",Z80_Dis_Printf("%d,%s",bit,reg)); +} + +static void DIS_RES_R8 (Z80 *z80, Z80Byte op, Z80Word *pc) +{ + const char *reg; + int bit; + + reg=z80_dis_reg8[op%8]; + bit=(op-0x80)/8; + Z80_Dis_Set("res",Z80_Dis_Printf("%d,%s",bit,reg)); +} + +static void DIS_SET_R8 (Z80 *z80, Z80Byte op, Z80Word *pc) +{ + const char *reg; + int bit; + + reg=z80_dis_reg8[op%8]; + bit=(op-0xc0)/8; + Z80_Dis_Set("set",Z80_Dis_Printf("%d,%s",bit,reg)); +} + +/* ---------------------------------------- DD OPCODES +*/ + +static const char *IX_RelStr(Z80 *z80, Z80Byte op, Z80Word *pc) +{ + static char s[80]; + Z80Relative r; + + r=(Z80Relative)Z80_Dis_FetchByte(z80,pc); + + if (r<0) + sprintf(s,"(ix-$%.2x)",-r); + else + sprintf(s,"(ix+$%.2x)",r); + + return(s); +} + + +static const char *IX_RelStrCB(Z80 *z80, Z80Byte op, Z80Word *pc) +{ + static char s[80]; + Z80Relative r; + + r=(Z80Relative)cb_off; + + if (r<0) + sprintf(s,"(ix-$%.2x)",-r); + else + sprintf(s,"(ix+$%.2x)",r); + + return(s); +} + + +static const char *XR8(Z80 *z80, int reg, Z80Word *pc) +{ + switch(reg) + { + case 0: + return("b"); + break; + case 1: + return("c"); + break; + case 2: + return("d"); + break; + case 3: + return("e"); + break; + case 4: + return("ixh"); + break; + case 5: + return("ixl"); + break; + case 6: + return(IX_RelStr(z80,0,pc)); + break; + case 7: + return("a"); + break; + default: + return(Z80_Dis_Printf("BUG %d",reg)); + break; + } +} + +static void DIS_DD_NOP(Z80 *z80, Z80Byte op, Z80Word *pc) +{ + dis_opcode_z80[op](z80,op,pc); +} + +static void DIS_ADD_IX_BC(Z80 *z80, Z80Byte op, Z80Word *pc) +{ + Z80_Dis_Set("add","ix,bc"); +} + +static void DIS_ADD_IX_DE(Z80 *z80, Z80Byte op, Z80Word *pc) +{ + Z80_Dis_Set("add","ix,de"); +} + +static void DIS_LD_IX_WORD(Z80 *z80, Z80Byte op, Z80Word *pc) +{ + Z80_Dis_Set("ld",Z80_Dis_Printf("ix,$%.4x",Z80_Dis_FetchWord(z80,pc))); +} + +static void DIS_LD_ADDR_IX(Z80 *z80, Z80Byte op, Z80Word *pc) +{ + Z80Word w; + const char *p; + + w=Z80_Dis_FetchWord(z80,pc); + + if ((p=GetLabel(w))) + Z80_Dis_Set("ld",Z80_Dis_Printf("(%s),ix",p)); + else + Z80_Dis_Set("ld",Z80_Dis_Printf("($%.4x),ix",w)); +} + +static void DIS_INC_IX(Z80 *z80, Z80Byte op, Z80Word *pc) +{ + Z80_Dis_Set("inc","ix"); +} + +static void DIS_INC_IXH(Z80 *z80, Z80Byte op, Z80Word *pc) +{ + Z80_Dis_Set("inc","ixh"); +} + +static void DIS_DEC_IXH(Z80 *z80, Z80Byte op, Z80Word *pc) +{ + Z80_Dis_Set("dec","ixh"); +} + +static void DIS_LD_IXH_BYTE(Z80 *z80, Z80Byte op, Z80Word *pc) +{ + Z80_Dis_Set("ld",Z80_Dis_Printf("ixh,$%.2x",Z80_Dis_FetchByte(z80,pc))); +} + +static void DIS_ADD_IX_IX(Z80 *z80, Z80Byte op, Z80Word *pc) +{ + Z80_Dis_Set("add","ix,ix"); +} + +static void DIS_LD_IX_ADDR(Z80 *z80, Z80Byte op, Z80Word *pc) +{ + Z80Word w; + const char *p; + + w=Z80_Dis_FetchWord(z80,pc); + + if ((p=GetLabel(w))) + Z80_Dis_Set("ld",Z80_Dis_Printf("ix,(%s)",p)); + else + Z80_Dis_Set("ld",Z80_Dis_Printf("ix,($%.4x)",w)); +} + +static void DIS_DEC_IX(Z80 *z80, Z80Byte op, Z80Word *pc) +{ + Z80_Dis_Set("dec","ix"); +} + +static void DIS_INC_IXL(Z80 *z80, Z80Byte op, Z80Word *pc) +{ + Z80_Dis_Set("inc","ixl"); +} + +static void DIS_DEC_IXL(Z80 *z80, Z80Byte op, Z80Word *pc) +{ + Z80_Dis_Set("dec","ixl"); +} + +static void DIS_LD_IXL_BYTE(Z80 *z80, Z80Byte op, Z80Word *pc) +{ + Z80_Dis_Set("ld",Z80_Dis_Printf("ixl,$%.2x",Z80_Dis_FetchByte(z80,pc))); +} + +static void DIS_INC_IIX(Z80 *z80, Z80Byte op, Z80Word *pc) +{ + Z80_Dis_Set("inc",Z80_Dis_Printf("%s",IX_RelStr(z80,op,pc))); +} + +static void DIS_DEC_IIX(Z80 *z80, Z80Byte op, Z80Word *pc) +{ + Z80_Dis_Set("dec",Z80_Dis_Printf("%s",IX_RelStr(z80,op,pc))); +} + +static void DIS_LD_IIX_BYTE(Z80 *z80, Z80Byte op, Z80Word *pc) +{ + const char *rel; + int b; + + rel=IX_RelStr(z80,op,pc); + b=Z80_Dis_FetchByte(z80,pc); + Z80_Dis_Set("ld",Z80_Dis_Printf("%s,$%.2x",rel,b)); +} + + +static void DIS_ADD_IX_SP(Z80 *z80, Z80Byte op, Z80Word *pc) +{ + Z80_Dis_Set("add","ix,sp"); +} + +static void DIS_XLD_R8_R8(Z80 *z80, Z80Byte op, Z80Word *pc) +{ + int src_r,dest_r; + const char *src,*dest; + + dest_r=(op-0x40)/8; + src_r=op%8; + + /* IX can't be used as source and destination when reading z80ory + */ + if (dest_r==6) + { + dest=XR8(z80,dest_r,pc); + src=z80_dis_reg8[src_r]; + } + else if (((dest_r==4)||(dest_r==5))&&(src_r==6)) + { + dest=z80_dis_reg8[dest_r]; + src=XR8(z80,src_r,pc); + } + else + { + dest=XR8(z80,dest_r,pc); + src=XR8(z80,src_r,pc); + } + + Z80_Dis_Set("ld",Z80_Dis_Printf("%s,%s",dest,src)); +} + +static void DIS_XADD_R8(Z80 *z80, Z80Byte op, Z80Word *pc) +{ + Z80_Dis_Set("add",Z80_Dis_Printf("a,%s",XR8(z80,(op%8),pc))); +} + +static void DIS_XADC_R8(Z80 *z80, Z80Byte op, Z80Word *pc) +{ + Z80_Dis_Set("adc",Z80_Dis_Printf("a,%s",XR8(z80,(op%8),pc))); +} + +static void DIS_XSUB_R8(Z80 *z80, Z80Byte op, Z80Word *pc) +{ + Z80_Dis_Set("sub",Z80_Dis_Printf("a,%s",XR8(z80,(op%8),pc))); +} + +static void DIS_XSBC_R8(Z80 *z80, Z80Byte op, Z80Word *pc) +{ + Z80_Dis_Set("sbc",Z80_Dis_Printf("a,%s",XR8(z80,(op%8),pc))); +} + +static void DIS_XAND_R8(Z80 *z80, Z80Byte op, Z80Word *pc) +{ + Z80_Dis_Set("and",Z80_Dis_Printf("%s",XR8(z80,(op%8),pc))); +} + +static void DIS_XXOR_R8(Z80 *z80, Z80Byte op, Z80Word *pc) +{ + Z80_Dis_Set("xor",Z80_Dis_Printf("%s",XR8(z80,(op%8),pc))); +} + +static void DIS_X_OR_R8(Z80 *z80, Z80Byte op, Z80Word *pc) +{ + Z80_Dis_Set("or",Z80_Dis_Printf("%s",XR8(z80,(op%8),pc))); +} + +static void DIS_XCP_R8(Z80 *z80, Z80Byte op, Z80Word *pc) +{ + Z80_Dis_Set("cp",Z80_Dis_Printf("%s",XR8(z80,(op%8),pc))); +} + +static void DIS_POP_IX(Z80 *z80, Z80Byte op, Z80Word *pc) +{ + Z80_Dis_Set("pop","ix"); +} + +static void DIS_EX_ISP_IX(Z80 *z80, Z80Byte op, Z80Word *pc) +{ + Z80_Dis_Set("ex","(sp),ix"); +} + +static void DIS_PUSH_IX(Z80 *z80, Z80Byte op, Z80Word *pc) +{ + Z80_Dis_Set("push","ix"); +} + +static void DIS_JP_IX(Z80 *z80, Z80Byte op, Z80Word *pc) +{ + Z80_Dis_Set("jp","(ix)"); +} + +static void DIS_LD_SP_IX(Z80 *z80, Z80Byte op, Z80Word *pc) +{ + Z80_Dis_Set("ld","sp,ix"); +} + +static void DIS_DD_CB_DECODE(Z80 *z80, Z80Byte op, Z80Word *pc) +{ + int nop; + + cb_off=(Z80Relative)Z80_Dis_FetchByte(z80,pc); + nop=Z80_Dis_FetchByte(z80,pc); + dis_DD_CB_opcode[nop](z80,nop,pc); +} + +static void DIS_DD_DD_DECODE(Z80 *z80, Z80Byte op, Z80Word *pc) +{ + int nop; + + nop=Z80_Dis_FetchByte(z80,pc); + dis_DD_opcode[nop](z80,nop,pc); +} + +static void DIS_DD_ED_DECODE(Z80 *z80, Z80Byte op, Z80Word *pc) +{ + int nop; + + nop=Z80_Dis_FetchByte(z80,pc); + dis_ED_opcode[nop](z80,nop,pc); +} + +static void DIS_DD_FD_DECODE(Z80 *z80, Z80Byte op, Z80Word *pc) +{ + int nop; + + nop=Z80_Dis_FetchByte(z80,pc); + dis_FD_opcode[nop](z80,nop,pc); +} + + +/* ---------------------------------------- DD CB OPCODES +*/ + +static void DIS_RLC_IX (Z80 *z80, Z80Byte op, Z80Word *pc) +{ + int reg; + + reg=(op%8); + + if (reg==6) + Z80_Dis_Set("rlc",Z80_Dis_Printf("%s",IX_RelStrCB(z80,op,pc))); + else + { + Z80_Dis_Set("rlc",Z80_Dis_Printf("%s[%s]",IX_RelStrCB(z80,op,pc),z80_dis_reg8[reg])); + } +} + +static void DIS_RRC_IX (Z80 *z80, Z80Byte op, Z80Word *pc) +{ + int reg; + + reg=(op%8); + + if (reg==6) + Z80_Dis_Set("rrc",Z80_Dis_Printf("%s",IX_RelStrCB(z80,op,pc))); + else + Z80_Dis_Set("rrc",Z80_Dis_Printf("%s[%s]",IX_RelStrCB(z80,op,pc),z80_dis_reg8[reg])); +} + +static void DIS_RL_IX (Z80 *z80, Z80Byte op, Z80Word *pc) +{ + int reg; + + reg=(op%8); + + if (reg==6) + Z80_Dis_Set("rl",Z80_Dis_Printf("%s",IX_RelStrCB(z80,op,pc))); + else + Z80_Dis_Set("rl",Z80_Dis_Printf("%s[%s]",IX_RelStrCB(z80,op,pc),z80_dis_reg8[reg])); +} + +static void DIS_RR_IX (Z80 *z80, Z80Byte op, Z80Word *pc) +{ + int reg; + + reg=(op%8); + + if (reg==6) + Z80_Dis_Set("rr",Z80_Dis_Printf("%s",IX_RelStrCB(z80,op,pc))); + else + Z80_Dis_Set("rr",Z80_Dis_Printf("%s[%s]",IX_RelStrCB(z80,op,pc),z80_dis_reg8[reg])); +} + +static void DIS_SLA_IX (Z80 *z80, Z80Byte op, Z80Word *pc) +{ + int reg; + + reg=(op%8); + + if (reg==6) + Z80_Dis_Set("sla",Z80_Dis_Printf("%s",IX_RelStrCB(z80,op,pc))); + else + Z80_Dis_Set("sla",Z80_Dis_Printf("%s[%s]",IX_RelStrCB(z80,op,pc),z80_dis_reg8[reg])); +} + +static void DIS_SRA_IX (Z80 *z80, Z80Byte op, Z80Word *pc) +{ + int reg; + + reg=(op%8); + + if (reg==6) + Z80_Dis_Set("sra",Z80_Dis_Printf("%s",IX_RelStrCB(z80,op,pc))); + else + Z80_Dis_Set("sra",Z80_Dis_Printf("%s[%s]",IX_RelStrCB(z80,op,pc),z80_dis_reg8[reg])); +} + +static void DIS_SRL_IX (Z80 *z80, Z80Byte op, Z80Word *pc) +{ + int reg; + + reg=(op%8); + + if (reg==6) + Z80_Dis_Set("srl",Z80_Dis_Printf("%s",IX_RelStrCB(z80,op,pc))); + else + Z80_Dis_Set("srl",Z80_Dis_Printf("%s[%s]",IX_RelStrCB(z80,op,pc),z80_dis_reg8[reg])); +} + +static void DIS_SLL_IX (Z80 *z80, Z80Byte op, Z80Word *pc) +{ + int reg; + + reg=(op%8); + + if (reg==6) + Z80_Dis_Set("sll",Z80_Dis_Printf("%s",IX_RelStrCB(z80,op,pc))); + else + Z80_Dis_Set("sll",Z80_Dis_Printf("%s[%s]",IX_RelStrCB(z80,op,pc),z80_dis_reg8[reg])); +} + +static void DIS_BIT_IX (Z80 *z80, Z80Byte op, Z80Word *pc) +{ + int reg; + int bit; + + reg=(op%8); + bit=(op-0x40)/8; + + if (reg==6) + Z80_Dis_Set("bit",Z80_Dis_Printf("%d,%s",bit,IX_RelStrCB(z80,op,pc))); + else + Z80_Dis_Set("bit",Z80_Dis_Printf("%d,%s[%s]",bit,IX_RelStrCB(z80,op,pc),z80_dis_reg8[reg])); +} + +static void DIS_RES_IX (Z80 *z80, Z80Byte op, Z80Word *pc) +{ + int reg; + int bit; + + reg=(op%8); + bit=(op-0x80)/8; + + if (reg==6) + Z80_Dis_Set("res",Z80_Dis_Printf("%d,%s",bit,IX_RelStrCB(z80,op,pc))); + else + Z80_Dis_Set("res",Z80_Dis_Printf("%d,%s[%s]",bit,IX_RelStrCB(z80,op,pc),z80_dis_reg8[reg])); +} + +static void DIS_SET_IX (Z80 *z80, Z80Byte op, Z80Word *pc) +{ + int reg; + int bit; + + reg=(op%8); + bit=(op-0xc0)/8; + + if (reg==6) + Z80_Dis_Set("set",Z80_Dis_Printf("%d,%s",bit,IX_RelStrCB(z80,op,pc))); + else + Z80_Dis_Set("set",Z80_Dis_Printf("%d,%s[%s]",bit,IX_RelStrCB(z80,op,pc),z80_dis_reg8[reg])); +} + + +/* ---------------------------------------- ED OPCODES +*/ + +static const char *ER8(int reg) +{ + switch(reg) + { + case 0: + return("b"); + break; + case 1: + return("c"); + break; + case 2: + return("d"); + break; + case 3: + return("e"); + break; + case 4: + return("h"); + break; + case 5: + return("l"); + break; + case 6: + return("0"); + break; + case 7: + return("a"); + break; + } + + return "?"; +} + +/* Assumes illegal ED ops are being used for break points +*/ +static void DIS_ED_NOP(Z80 *z80, Z80Byte op, Z80Word *pc) +{ + Z80_Dis_Set("brk",Z80_Dis_Printf("$%.2x",op)); +} + +static void DIS_IN_R8_C(Z80 *z80, Z80Byte op, Z80Word *pc) +{ + Z80_Dis_Set("in",Z80_Dis_Printf("%s,(c)",ER8((op-0x40)/8))); +} + +static void DIS_OUT_C_R8(Z80 *z80, Z80Byte op, Z80Word *pc) +{ + Z80_Dis_Set("out",Z80_Dis_Printf("(c),%s",ER8((op-0x40)/8))); +} + +static void DIS_SBC_HL_R16(Z80 *z80, Z80Byte op, Z80Word *pc) +{ + Z80_Dis_Set("sbc",Z80_Dis_Printf("hl,%s",z80_dis_reg16[(op-0x40)/16])); +} + +static void DIS_ED_LD_ADDR_R16(Z80 *z80, Z80Byte op, Z80Word *pc) +{ + Z80Word w; + const char *p; + + w=Z80_Dis_FetchWord(z80,pc); + + if ((p=GetLabel(w))) + Z80_Dis_Set("ld",Z80_Dis_Printf("(%s),%s",p,z80_dis_reg16[(op-0x40)/16])); + else + Z80_Dis_Set("ld",Z80_Dis_Printf("($%.4x),%s",w,z80_dis_reg16[(op-0x40)/16])); +} + +static void DIS_NEG(Z80 *z80, Z80Byte op, Z80Word *pc) +{ + Z80_Dis_Set("neg",NULL); +} + +static void DIS_RETN(Z80 *z80, Z80Byte op, Z80Word *pc) +{ + Z80_Dis_Set("retn",NULL); +} + +static void DIS_IM_0(Z80 *z80, Z80Byte op, Z80Word *pc) +{ + Z80_Dis_Set("im","0"); +} + +static void DIS_LD_I_A(Z80 *z80, Z80Byte op, Z80Word *pc) +{ + Z80_Dis_Set("ld","i,a"); +} + +static void DIS_ADC_HL_R16(Z80 *z80, Z80Byte op, Z80Word *pc) +{ + Z80_Dis_Set("adc",Z80_Dis_Printf("hl,%s",z80_dis_reg16[(op-0x40)/16])); +} + +static void DIS_ED_LD_R16_ADDR(Z80 *z80, Z80Byte op, Z80Word *pc) +{ + Z80Word w; + const char *p; + + w=Z80_Dis_FetchWord(z80,pc); + + if ((p=GetLabel(w))) + Z80_Dis_Set("ld",Z80_Dis_Printf("%s,(%s)",z80_dis_reg16[(op-0x40)/16],p)); + else + Z80_Dis_Set("ld",Z80_Dis_Printf("%s,($%.4x)",z80_dis_reg16[(op-0x40)/16],w)); +} + +static void DIS_RETI(Z80 *z80, Z80Byte op, Z80Word *pc) +{ + Z80_Dis_Set("reti",NULL); +} + +static void DIS_LD_R_A(Z80 *z80, Z80Byte op, Z80Word *pc) +{ + Z80_Dis_Set("ld","r,a"); +} + +static void DIS_IM_1(Z80 *z80, Z80Byte op, Z80Word *pc) +{ + Z80_Dis_Set("im","1"); +} + +static void DIS_LD_A_I(Z80 *z80, Z80Byte op, Z80Word *pc) +{ + Z80_Dis_Set("ld","a,i"); +} + +static void DIS_IM_2(Z80 *z80, Z80Byte op, Z80Word *pc) +{ + Z80_Dis_Set("im","2"); +} + +static void DIS_LD_A_R(Z80 *z80, Z80Byte op, Z80Word *pc) +{ + Z80_Dis_Set("ld","a,r"); +} + +static void DIS_RRD(Z80 *z80, Z80Byte op, Z80Word *pc) +{ + Z80_Dis_Set("rrd",NULL); +} + +static void DIS_RLD(Z80 *z80, Z80Byte op, Z80Word *pc) +{ + Z80_Dis_Set("rld",NULL); +} + +static void DIS_LDI(Z80 *z80, Z80Byte op, Z80Word *pc) +{ + Z80_Dis_Set("ldi",NULL); +} + +static void DIS_CPI(Z80 *z80, Z80Byte op, Z80Word *pc) +{ + Z80_Dis_Set("cpi",NULL); +} + +static void DIS_INI(Z80 *z80, Z80Byte op, Z80Word *pc) +{ + Z80_Dis_Set("ini",NULL); +} + +static void DIS_OUTI(Z80 *z80, Z80Byte op, Z80Word *pc) +{ + Z80_Dis_Set("outi",NULL); +} + +static void DIS_LDD(Z80 *z80, Z80Byte op, Z80Word *pc) +{ + Z80_Dis_Set("ldd",NULL); +} + +static void DIS_CPD(Z80 *z80, Z80Byte op, Z80Word *pc) +{ + Z80_Dis_Set("cpd",NULL); +} + +static void DIS_IND(Z80 *z80, Z80Byte op, Z80Word *pc) +{ + Z80_Dis_Set("ind",NULL); +} + +static void DIS_OUTD(Z80 *z80, Z80Byte op, Z80Word *pc) +{ + Z80_Dis_Set("outd",NULL); +} + +static void DIS_LDIR(Z80 *z80, Z80Byte op, Z80Word *pc) +{ + Z80_Dis_Set("ldir",NULL); +} + +static void DIS_CPIR(Z80 *z80, Z80Byte op, Z80Word *pc) +{ + Z80_Dis_Set("cpir",NULL); +} + +static void DIS_INIR(Z80 *z80, Z80Byte op, Z80Word *pc) +{ + Z80_Dis_Set("inir",NULL); +} + +static void DIS_OTIR(Z80 *z80, Z80Byte op, Z80Word *pc) +{ + Z80_Dis_Set("otir",NULL); +} + +static void DIS_LDDR(Z80 *z80, Z80Byte op, Z80Word *pc) +{ + Z80_Dis_Set("lddr",NULL); +} + +static void DIS_CPDR(Z80 *z80, Z80Byte op, Z80Word *pc) +{ + Z80_Dis_Set("cpdr",NULL); +} + +static void DIS_INDR(Z80 *z80, Z80Byte op, Z80Word *pc) +{ + Z80_Dis_Set("indr",NULL); +} + +static void DIS_OTDR(Z80 *z80, Z80Byte op, Z80Word *pc) +{ + Z80_Dis_Set("otdr",NULL); +} + + +/* ---------------------------------------- FD OPCODES +*/ + +static const char *IY_RelStr(Z80 *z80, Z80Byte op, Z80Word *pc) +{ + static char s[80]; + Z80Relative r; + + r=(Z80Relative)Z80_Dis_FetchByte(z80,pc); + + if (r<0) + sprintf(s,"(iy-$%.2x)",-r); + else + sprintf(s,"(iy+$%.2x)",r); + + return(s); +} + + +static const char *IY_RelStrCB(Z80 *z80, Z80Byte op, Z80Word *pc) +{ + static char s[80]; + Z80Relative r; + + r=(Z80Relative)cb_off; + + if (r<0) + sprintf(s,"(iy-$%.2x)",-r); + else + sprintf(s,"(iy+$%.2x)",r); + + return(s); +} + + +static const char *YR8(Z80 *z80, int reg, Z80Word *pc) +{ + switch(reg) + { + case 0: + return("b"); + break; + case 1: + return("c"); + break; + case 2: + return("d"); + break; + case 3: + return("e"); + break; + case 4: + return("iyh"); + break; + case 5: + return("iyl"); + break; + case 6: + return(IY_RelStr(z80,0,pc)); + break; + case 7: + return("a"); + break; + default: + return(Z80_Dis_Printf("BUG %d",reg)); + break; + } +} + +static void DIS_FD_NOP(Z80 *z80, Z80Byte op, Z80Word *pc) +{ + dis_opcode_z80[op](z80,op,pc); +} + +static void DIS_ADD_IY_BC(Z80 *z80, Z80Byte op, Z80Word *pc) +{ + Z80_Dis_Set("add","iy,bc"); +} + +static void DIS_ADD_IY_DE(Z80 *z80, Z80Byte op, Z80Word *pc) +{ + Z80_Dis_Set("add","iy,de"); +} + +static void DIS_LD_IY_WORD(Z80 *z80, Z80Byte op, Z80Word *pc) +{ + Z80_Dis_Set("ld",Z80_Dis_Printf("iy,$%.4x",Z80_Dis_FetchWord(z80,pc))); +} + +static void DIS_LD_ADDR_IY(Z80 *z80, Z80Byte op, Z80Word *pc) +{ + Z80Word w; + const char *p; + + w=Z80_Dis_FetchWord(z80,pc); + + if ((p=GetLabel(w))) + Z80_Dis_Set("ld",Z80_Dis_Printf("(%s),iy",p)); + else + Z80_Dis_Set("ld",Z80_Dis_Printf("($%.4x),iy",w)); +} + +static void DIS_INC_IY(Z80 *z80, Z80Byte op, Z80Word *pc) +{ + Z80_Dis_Set("inc","iy"); +} + +static void DIS_INC_IYH(Z80 *z80, Z80Byte op, Z80Word *pc) +{ + Z80_Dis_Set("inc","iyh"); +} + +static void DIS_DEC_IYH(Z80 *z80, Z80Byte op, Z80Word *pc) +{ + Z80_Dis_Set("dec","iyh"); +} + +static void DIS_LD_IYH_BYTE(Z80 *z80, Z80Byte op, Z80Word *pc) +{ + Z80_Dis_Set("ld",Z80_Dis_Printf("iyh,$%.2x",Z80_Dis_FetchByte(z80,pc))); +} + +static void DIS_ADD_IY_IY(Z80 *z80, Z80Byte op, Z80Word *pc) +{ + Z80_Dis_Set("add","iy,iy"); +} + +static void DIS_LD_IY_ADDR(Z80 *z80, Z80Byte op, Z80Word *pc) +{ + Z80Word w; + const char *p; + + w=Z80_Dis_FetchWord(z80,pc); + + if ((p=GetLabel(w))) + Z80_Dis_Set("ld",Z80_Dis_Printf("iy,(%s)",p)); + else + Z80_Dis_Set("ld",Z80_Dis_Printf("iy,($%.4x)",w)); +} + +static void DIS_DEC_IY(Z80 *z80, Z80Byte op, Z80Word *pc) +{ + Z80_Dis_Set("dec","iy"); +} + +static void DIS_INC_IYL(Z80 *z80, Z80Byte op, Z80Word *pc) +{ + Z80_Dis_Set("inc","iyl"); +} + +static void DIS_DEC_IYL(Z80 *z80, Z80Byte op, Z80Word *pc) +{ + Z80_Dis_Set("dec","iyl"); +} + +static void DIS_LD_IYL_BYTE(Z80 *z80, Z80Byte op, Z80Word *pc) +{ + Z80_Dis_Set("ld",Z80_Dis_Printf("iyl,$%.2x",Z80_Dis_FetchByte(z80,pc))); +} + +static void DIS_INC_IIY(Z80 *z80, Z80Byte op, Z80Word *pc) +{ + Z80_Dis_Set("inc",Z80_Dis_Printf("%s",IY_RelStr(z80,op,pc))); +} + +static void DIS_DEC_IIY(Z80 *z80, Z80Byte op, Z80Word *pc) +{ + Z80_Dis_Set("dec",Z80_Dis_Printf("%s",IY_RelStr(z80,op,pc))); +} + +static void DIS_LD_IIY_BYTE(Z80 *z80, Z80Byte op, Z80Word *pc) +{ + const char *rel; + int b; + + rel=IY_RelStr(z80,op,pc); + b=Z80_Dis_FetchByte(z80,pc); + Z80_Dis_Set("ld",Z80_Dis_Printf("%s,$%.2x",rel,b)); +} + + +static void DIS_ADD_IY_SP(Z80 *z80, Z80Byte op, Z80Word *pc) +{ + Z80_Dis_Set("add","iy,sp"); +} + +static void DIS_YLD_R8_R8(Z80 *z80, Z80Byte op, Z80Word *pc) +{ + int src_r,dest_r; + const char *src,*dest; + + dest_r=(op-0x40)/8; + src_r=op%8; + + /* IY can't be used as source and destination when reading z80ory + */ + if (dest_r==6) + { + dest=YR8(z80,dest_r,pc); + src=z80_dis_reg8[src_r]; + } + else if (((dest_r==4)||(dest_r==5))&&(src_r==6)) + { + dest=z80_dis_reg8[dest_r]; + src=YR8(z80,src_r,pc); + } + else + { + dest=YR8(z80,dest_r,pc); + src=YR8(z80,src_r,pc); + } + + Z80_Dis_Set("ld",Z80_Dis_Printf("%s,%s",dest,src)); +} + +static void DIS_YADD_R8(Z80 *z80, Z80Byte op, Z80Word *pc) +{ + Z80_Dis_Set("add",Z80_Dis_Printf("a,%s",YR8(z80,(op%8),pc))); +} + +static void DIS_YADC_R8(Z80 *z80, Z80Byte op, Z80Word *pc) +{ + Z80_Dis_Set("adc",Z80_Dis_Printf("a,%s",YR8(z80,(op%8),pc))); +} + +static void DIS_YSUB_R8(Z80 *z80, Z80Byte op, Z80Word *pc) +{ + Z80_Dis_Set("sub",Z80_Dis_Printf("a,%s",YR8(z80,(op%8),pc))); +} + +static void DIS_YSBC_R8(Z80 *z80, Z80Byte op, Z80Word *pc) +{ + Z80_Dis_Set("sbc",Z80_Dis_Printf("a,%s",YR8(z80,(op%8),pc))); +} + +static void DIS_YAND_R8(Z80 *z80, Z80Byte op, Z80Word *pc) +{ + Z80_Dis_Set("and",Z80_Dis_Printf("%s",YR8(z80,(op%8),pc))); +} + +static void DIS_YYOR_R8(Z80 *z80, Z80Byte op, Z80Word *pc) +{ + Z80_Dis_Set("xor",Z80_Dis_Printf("%s",YR8(z80,(op%8),pc))); +} + +static void DIS_Y_OR_R8(Z80 *z80, Z80Byte op, Z80Word *pc) +{ + Z80_Dis_Set("or",Z80_Dis_Printf("%s",YR8(z80,(op%8),pc))); +} + +static void DIS_YCP_R8(Z80 *z80, Z80Byte op, Z80Word *pc) +{ + Z80_Dis_Set("cp",Z80_Dis_Printf("%s",YR8(z80,(op%8),pc))); +} + +static void DIS_POP_IY(Z80 *z80, Z80Byte op, Z80Word *pc) +{ + Z80_Dis_Set("pop","iy"); +} + +static void DIS_EY_ISP_IY(Z80 *z80, Z80Byte op, Z80Word *pc) +{ + Z80_Dis_Set("ex","(sp),iy"); +} + +static void DIS_PUSH_IY(Z80 *z80, Z80Byte op, Z80Word *pc) +{ + Z80_Dis_Set("push","iy"); +} + +static void DIS_JP_IY(Z80 *z80, Z80Byte op, Z80Word *pc) +{ + Z80_Dis_Set("jp","(iy)"); +} + +static void DIS_LD_SP_IY(Z80 *z80, Z80Byte op, Z80Word *pc) +{ + Z80_Dis_Set("ld","sp,iy"); +} + +static void DIS_FD_CB_DECODE(Z80 *z80, Z80Byte op, Z80Word *pc) +{ + int nop; + + cb_off=(Z80Relative)Z80_Dis_FetchByte(z80,pc); + nop=Z80_Dis_FetchByte(z80,pc); + dis_FD_CB_opcode[nop](z80,nop,pc); +} + +static void DIS_FD_DD_DECODE(Z80 *z80, Z80Byte op, Z80Word *pc) +{ + int nop; + + nop=Z80_Dis_FetchByte(z80,pc); + dis_DD_opcode[nop](z80,nop,pc); +} + +static void DIS_FD_ED_DECODE(Z80 *z80, Z80Byte op, Z80Word *pc) +{ + int nop; + + nop=Z80_Dis_FetchByte(z80,pc); + dis_ED_opcode[nop](z80,nop,pc); +} + +static void DIS_FD_FD_DECODE(Z80 *z80, Z80Byte op, Z80Word *pc) +{ + int nop; + + nop=Z80_Dis_FetchByte(z80,pc); + dis_FD_opcode[nop](z80,nop,pc); +} + + +/* ---------------------------------------- FD CB OPCODES +*/ + +static void DIS_RLC_IY (Z80 *z80, Z80Byte op, Z80Word *pc) +{ + int reg; + + reg=(op%8); + + if (reg==6) + Z80_Dis_Set("rlc",Z80_Dis_Printf("%s",IY_RelStrCB(z80,op,pc))); + else + Z80_Dis_Set("rlc",Z80_Dis_Printf("%s[%s]",IY_RelStrCB(z80,op,pc),z80_dis_reg8[reg])); +} + +static void DIS_RRC_IY (Z80 *z80, Z80Byte op, Z80Word *pc) +{ + int reg; + + reg=(op%8); + + if (reg==6) + Z80_Dis_Set("rrc",Z80_Dis_Printf("%s",IY_RelStrCB(z80,op,pc))); + else + Z80_Dis_Set("rrc",Z80_Dis_Printf("%s[%s]",IY_RelStrCB(z80,op,pc),z80_dis_reg8[reg])); +} + +static void DIS_RL_IY (Z80 *z80, Z80Byte op, Z80Word *pc) +{ + int reg; + + reg=(op%8); + + if (reg==6) + Z80_Dis_Set("rl",Z80_Dis_Printf("%s",IY_RelStrCB(z80,op,pc))); + else + Z80_Dis_Set("rl",Z80_Dis_Printf("%s[%s]",IY_RelStrCB(z80,op,pc),z80_dis_reg8[reg])); +} + +static void DIS_RR_IY (Z80 *z80, Z80Byte op, Z80Word *pc) +{ + int reg; + + reg=(op%8); + + if (reg==6) + Z80_Dis_Set("rr",Z80_Dis_Printf("%s",IY_RelStrCB(z80,op,pc))); + else + Z80_Dis_Set("rr",Z80_Dis_Printf("%s[%s]",IY_RelStrCB(z80,op,pc),z80_dis_reg8[reg])); +} + +static void DIS_SLA_IY (Z80 *z80, Z80Byte op, Z80Word *pc) +{ + int reg; + + reg=(op%8); + + if (reg==6) + Z80_Dis_Set("sla",Z80_Dis_Printf("%s",IY_RelStrCB(z80,op,pc))); + else + Z80_Dis_Set("sla",Z80_Dis_Printf("%s[%s]",IY_RelStrCB(z80,op,pc),z80_dis_reg8[reg])); +} + +static void DIS_SRA_IY (Z80 *z80, Z80Byte op, Z80Word *pc) +{ + int reg; + + reg=(op%8); + + if (reg==6) + Z80_Dis_Set("sra",Z80_Dis_Printf("%s",IY_RelStrCB(z80,op,pc))); + else + Z80_Dis_Set("sra",Z80_Dis_Printf("%s[%s]",IY_RelStrCB(z80,op,pc),z80_dis_reg8[reg])); +} + +static void DIS_SRL_IY (Z80 *z80, Z80Byte op, Z80Word *pc) +{ + int reg; + + reg=(op%8); + + if (reg==6) + Z80_Dis_Set("srl",Z80_Dis_Printf("%s",IY_RelStrCB(z80,op,pc))); + else + Z80_Dis_Set("srl",Z80_Dis_Printf("%s[%s]",IY_RelStrCB(z80,op,pc),z80_dis_reg8[reg])); +} + +static void DIS_SLL_IY (Z80 *z80, Z80Byte op, Z80Word *pc) +{ + int reg; + + reg=(op%8); + + if (reg==6) + Z80_Dis_Set("sll",Z80_Dis_Printf("%s",IY_RelStrCB(z80,op,pc))); + else + Z80_Dis_Set("sll",Z80_Dis_Printf("%s[%s]",IY_RelStrCB(z80,op,pc),z80_dis_reg8[reg])); +} + +static void DIS_BIT_IY (Z80 *z80, Z80Byte op, Z80Word *pc) +{ + int reg; + int bit; + + reg=(op%8); + bit=(op-0x40)/8; + + if (reg==6) + Z80_Dis_Set("bit",Z80_Dis_Printf("%d,%s",bit,IY_RelStrCB(z80,op,pc))); + else + Z80_Dis_Set("bit",Z80_Dis_Printf("%d,%s[%s]",bit,IY_RelStrCB(z80,op,pc),z80_dis_reg8[reg])); +} + +static void DIS_RES_IY (Z80 *z80, Z80Byte op, Z80Word *pc) +{ + int reg; + int bit; + + reg=(op%8); + bit=(op-0x80)/8; + + if (reg==6) + Z80_Dis_Set("res",Z80_Dis_Printf("%d,%s",bit,IY_RelStrCB(z80,op,pc))); + else + Z80_Dis_Set("res",Z80_Dis_Printf("%d,%s[%s]",bit,IY_RelStrCB(z80,op,pc),z80_dis_reg8[reg])); +} + +static void DIS_SET_IY (Z80 *z80, Z80Byte op, Z80Word *pc) +{ + int reg; + int bit; + + reg=(op%8); + bit=(op-0xc0)/8; + + if (reg==6) + Z80_Dis_Set("set",Z80_Dis_Printf("%d,%s",bit,IY_RelStrCB(z80,op,pc))); + else + Z80_Dis_Set("set",Z80_Dis_Printf("%d,%s[%s]",bit,IY_RelStrCB(z80,op,pc),z80_dis_reg8[reg])); +} + + +/* ---------------------------------------- SINGLE BYTE OPCODES +*/ +static void DIS_NOP (Z80 *z80, Z80Byte op, Z80Word *pc) +{ + Z80_Dis_Set("nop",NULL); +} + +static void DIS_LD_R16_WORD (Z80 *z80, Z80Byte op, Z80Word *pc) +{ + const char *reg; + + reg=z80_dis_reg16[(op&0x30)/0x10]; + Z80_Dis_Set("ld",Z80_Dis_Printf("%s,$%.4x",reg,Z80_Dis_FetchWord(z80,pc))); +} + +static void DIS_LD_R16_A (Z80 *z80, Z80Byte op, Z80Word *pc) +{ + const char *reg; + + reg=z80_dis_reg16[(op&0x30)/0x10]; + Z80_Dis_Set("ld",Z80_Dis_Printf("(%s),a",reg)); +} + +static void DIS_INC_R16 (Z80 *z80, Z80Byte op, Z80Word *pc) +{ + const char *reg; + + reg=z80_dis_reg16[(op&0x30)/0x10]; + Z80_Dis_Set("inc",reg); +} + +static void DIS_INC_R8 (Z80 *z80, Z80Byte op, Z80Word *pc) +{ + const char *reg; + + reg=z80_dis_reg8[(op&0x38)/0x8]; + Z80_Dis_Set("inc",reg); +} + +static void DIS_DEC_R8 (Z80 *z80, Z80Byte op, Z80Word *pc) +{ + const char *reg; + + reg=z80_dis_reg8[(op&0x38)/0x8]; + Z80_Dis_Set("dec",reg); +} + +static void DIS_LD_R8_BYTE (Z80 *z80, Z80Byte op, Z80Word *pc) +{ + const char *reg; + + reg=z80_dis_reg8[(op&0x38)/0x8]; + Z80_Dis_Set("ld",Z80_Dis_Printf("%s,$%.2x",reg,Z80_Dis_FetchByte(z80,pc))); +} + +static void DIS_RLCA (Z80 *z80, Z80Byte op, Z80Word *pc) +{ + Z80_Dis_Set("rlca",NULL); +} + +static void DIS_EX_AF_AF (Z80 *z80, Z80Byte op, Z80Word *pc) +{ + Z80_Dis_Set("ex","af,af'"); +} + +static void DIS_ADD_HL_R16 (Z80 *z80, Z80Byte op, Z80Word *pc) +{ + const char *reg; + + reg=z80_dis_reg16[(op&0x30)/0x10]; + Z80_Dis_Set("add",Z80_Dis_Printf("hl,%s",reg)); +} + +static void DIS_LD_A_R16 (Z80 *z80, Z80Byte op, Z80Word *pc) +{ + const char *reg; + + reg=z80_dis_reg16[(op&0x30)/0x10]; + Z80_Dis_Set("ld",Z80_Dis_Printf("a,(%s)",reg)); +} + +static void DIS_DEC_R16 (Z80 *z80, Z80Byte op, Z80Word *pc) +{ + const char *reg; + + reg=z80_dis_reg16[(op&0x30)/0x10]; + Z80_Dis_Set("dec",reg); +} + +static void DIS_RRCA (Z80 *z80, Z80Byte op, Z80Word *pc) +{ + Z80_Dis_Set("rrca",NULL); +} + +static void DIS_DJNZ (Z80 *z80, Z80Byte op, Z80Word *pc) +{ + Z80Word new; + +#ifdef ENABLE_ARRAY_MEMORY + new=*pc+(Z80Relative)Z80_MEMORY[*pc]+1; +#else + new=*pc+(Z80Relative)z80->priv->disread(z80,*pc)+1; +#endif + (*pc)++; + Z80_Dis_Set("djnz",Z80_Dis_Printf("$%.4x",new)); +} + +static void DIS_RLA (Z80 *z80, Z80Byte op, Z80Word *pc) +{ + Z80_Dis_Set("rla",NULL); +} + +static void DIS_JR (Z80 *z80, Z80Byte op, Z80Word *pc) +{ + Z80Word new; + const char *p; + +#ifdef ENABLE_ARRAY_MEMORY + new=*pc+(Z80Relative)Z80_MEMORY[*pc]+1; +#else + new=*pc+(Z80Relative)z80->priv->disread(z80,*pc)+1; +#endif + (*pc)++; + + if ((p=GetLabel(new))) + Z80_Dis_Set("jr",Z80_Dis_Printf("%s",p)); + else + Z80_Dis_Set("jr",Z80_Dis_Printf("$%.4x",new)); +} + +static void DIS_RRA (Z80 *z80, Z80Byte op, Z80Word *pc) +{ + Z80_Dis_Set("rra",NULL); +} + +static void DIS_JR_CO (Z80 *z80, Z80Byte op, Z80Word *pc) +{ + const char *con; + Z80Word new; + const char *p; + + con=z80_dis_condition[(op-0x20)/8]; +#ifdef ENABLE_ARRAY_MEMORY + new=*pc+(Z80Relative)Z80_MEMORY[*pc]+1; +#else + new=*pc+(Z80Relative)z80->priv->disread(z80,*pc)+1; +#endif + (*pc)++; + + if ((p=GetLabel(new))) + Z80_Dis_Set("jr",Z80_Dis_Printf("%s,%s",con,p)); + else + Z80_Dis_Set("jr",Z80_Dis_Printf("%s,$%.4x",con,new)); +} + +static void DIS_LD_ADDR_HL (Z80 *z80, Z80Byte op, Z80Word *pc) +{ + Z80Word w; + const char *p; + + w=Z80_Dis_FetchWord(z80,pc); + + if ((p=GetLabel(w))) + Z80_Dis_Set("ld",Z80_Dis_Printf("(%s),hl",p)); + else + Z80_Dis_Set("ld",Z80_Dis_Printf("($%.4x),hl",w)); +} + +static void DIS_DAA (Z80 *z80, Z80Byte op, Z80Word *pc) +{ + Z80_Dis_Set("daa",NULL); +} + +static void DIS_LD_HL_ADDR (Z80 *z80, Z80Byte op, Z80Word *pc) +{ + Z80Word w; + const char *p; + + w=Z80_Dis_FetchWord(z80,pc); + + if ((p=GetLabel(w))) + Z80_Dis_Set("ld",Z80_Dis_Printf("hl,(%s)",p)); + else + Z80_Dis_Set("ld",Z80_Dis_Printf("hl,($%.4x)",w)); +} + +static void DIS_CPL (Z80 *z80, Z80Byte op, Z80Word *pc) +{ + Z80_Dis_Set("cpl",NULL); +} + +static void DIS_LD_ADDR_A (Z80 *z80, Z80Byte op, Z80Word *pc) +{ + Z80Word w; + const char *p; + + w=Z80_Dis_FetchWord(z80,pc); + + if ((p=GetLabel(w))) + Z80_Dis_Set("ld",Z80_Dis_Printf("(%s),a",p)); + else + Z80_Dis_Set("ld",Z80_Dis_Printf("($%.4x),a",w)); +} + +static void DIS_SCF (Z80 *z80, Z80Byte op, Z80Word *pc) +{ + Z80_Dis_Set("scf",NULL); +} + +static void DIS_LD_A_ADDR (Z80 *z80, Z80Byte op, Z80Word *pc) +{ + Z80Word w; + const char *p; + + w=Z80_Dis_FetchWord(z80,pc); + + if ((p=GetLabel(w))) + Z80_Dis_Set("ld",Z80_Dis_Printf("a,(%s)",p)); + else + Z80_Dis_Set("ld",Z80_Dis_Printf("a,($%.4x)",w)); +} + +static void DIS_CCF (Z80 *z80, Z80Byte op, Z80Word *pc) +{ + Z80_Dis_Set("ccf",NULL); +} + +static void DIS_LD_R8_R8 (Z80 *z80, Z80Byte op, Z80Word *pc) +{ + const char *src,*dest; + + dest=z80_dis_reg8[(op-0x40)/8]; + src=z80_dis_reg8[op%8]; + Z80_Dis_Set("ld",Z80_Dis_Printf("%s,%s",dest,src)); +} + +static void DIS_HALT (Z80 *z80, Z80Byte op, Z80Word *pc) +{ + Z80_Dis_Set("halt",NULL); +} + +static void DIS_ADD_R8 (Z80 *z80, Z80Byte op, Z80Word *pc) +{ + const char *reg; + + reg=z80_dis_reg8[op%8]; + Z80_Dis_Set("add",Z80_Dis_Printf("a,%s",reg)); +} + +static void DIS_ADC_R8 (Z80 *z80, Z80Byte op, Z80Word *pc) +{ + const char *reg; + + reg=z80_dis_reg8[op%8]; + Z80_Dis_Set("adc",Z80_Dis_Printf("a,%s",reg)); +} + +static void DIS_SUB_R8 (Z80 *z80, Z80Byte op, Z80Word *pc) +{ + const char *reg; + + reg=z80_dis_reg8[op%8]; + Z80_Dis_Set("sub",Z80_Dis_Printf("a,%s",reg)); +} + +static void DIS_SBC_R8 (Z80 *z80, Z80Byte op, Z80Word *pc) +{ + const char *reg; + + reg=z80_dis_reg8[op%8]; + Z80_Dis_Set("sbc",Z80_Dis_Printf("a,%s",reg)); +} + +static void DIS_AND_R8 (Z80 *z80, Z80Byte op, Z80Word *pc) +{ + const char *reg; + + reg=z80_dis_reg8[op%8]; + Z80_Dis_Set("and",Z80_Dis_Printf("%s",reg)); +} + +static void DIS_XOR_R8 (Z80 *z80, Z80Byte op, Z80Word *pc) +{ + const char *reg; + + reg=z80_dis_reg8[op%8]; + Z80_Dis_Set("xor",Z80_Dis_Printf("%s",reg)); +} + +static void DIS_OR_R8 (Z80 *z80, Z80Byte op, Z80Word *pc) +{ + const char *reg; + + reg=z80_dis_reg8[op%8]; + Z80_Dis_Set("or",Z80_Dis_Printf("%s",reg)); +} + +static void DIS_CP_R8 (Z80 *z80, Z80Byte op, Z80Word *pc) +{ + const char *reg; + + reg=z80_dis_reg8[op%8]; + Z80_Dis_Set("cp",Z80_Dis_Printf("%s",reg)); +} + + +static void DIS_RET_CO (Z80 *z80, Z80Byte op, Z80Word *pc) +{ + const char *con; + + con=z80_dis_condition[(op-0xc0)/8]; + Z80_Dis_Set("ret",con); +} + +static void DIS_POP_R16 (Z80 *z80, Z80Byte op, Z80Word *pc) +{ + const char *reg; + + reg=z80_dis_reg16[(op-0xc0)/16]; + + if (!strcmp(reg,"sp")) + reg="af"; + + Z80_Dis_Set("pop",reg); +} + +static void DIS_JP (Z80 *z80, Z80Byte op, Z80Word *pc) +{ + Z80Word w; + const char *p; + + w=Z80_Dis_FetchWord(z80,pc); + + if ((p=GetLabel(w))) + Z80_Dis_Set("jp",Z80_Dis_Printf("%s",p)); + else + Z80_Dis_Set("jp",Z80_Dis_Printf("$%.4x",w)); +} + +static void DIS_PUSH_R16 (Z80 *z80, Z80Byte op, Z80Word *pc) +{ + const char *reg; + + reg=z80_dis_reg16[(op-0xc0)/16]; + + if (!strcmp(reg,"sp")) + reg="af"; + + Z80_Dis_Set("push",reg); +} + +static void DIS_ADD_A_BYTE (Z80 *z80, Z80Byte op, Z80Word *pc) +{ + Z80_Dis_Set("add",Z80_Dis_Printf("a,$%.2x",Z80_Dis_FetchByte(z80,pc))); +} + +static void DIS_RST (Z80 *z80, Z80Byte op, Z80Word *pc) +{ + int add; + + add=(op&0x3f)-7; + Z80_Dis_Set("rst",Z80_Dis_Printf("%.2xh",add)); +} + +static void DIS_RET (Z80 *z80, Z80Byte op, Z80Word *pc) +{ + Z80_Dis_Set("ret",NULL); +} + +static void DIS_JP_CO (Z80 *z80, Z80Byte op, Z80Word *pc) +{ + const char *con; + Z80Word w; + const char *p; + + w=Z80_Dis_FetchWord(z80,pc); + con=z80_dis_condition[(op-0xc0)/8]; + + if ((p=GetLabel(w))) + Z80_Dis_Set("jp",Z80_Dis_Printf("%s,%s",con,p)); + else + Z80_Dis_Set("jp",Z80_Dis_Printf("%s,$%.4x",con,w)); +} + +static void DIS_CB_DECODE (Z80 *z80, Z80Byte op, Z80Word *pc) +{ + int nop; + + nop=Z80_Dis_FetchByte(z80,pc); + dis_CB_opcode[nop](z80,nop,pc); +} + +static void DIS_CALL_CO (Z80 *z80, Z80Byte op, Z80Word *pc) +{ + const char *con; + Z80Word w; + const char *p; + + w=Z80_Dis_FetchWord(z80,pc); + con=z80_dis_condition[(op-0xc0)/8]; + + if ((p=GetLabel(w))) + Z80_Dis_Set("call",Z80_Dis_Printf("%s,%s",con,p)); + else + Z80_Dis_Set("call",Z80_Dis_Printf("%s,$%.4x",con,w)); +} + +static void DIS_CALL (Z80 *z80, Z80Byte op, Z80Word *pc) +{ + Z80Word w; + const char *p; + + w=Z80_Dis_FetchWord(z80,pc); + + if ((p=GetLabel(w))) + Z80_Dis_Set("call",Z80_Dis_Printf("%s",p)); + else + Z80_Dis_Set("call",Z80_Dis_Printf("$%.4x",w)); +} + +static void DIS_ADC_A_BYTE (Z80 *z80, Z80Byte op, Z80Word *pc) +{ + Z80_Dis_Set("adc",Z80_Dis_Printf("a,$%.2x",Z80_Dis_FetchByte(z80,pc))); +} + +static void DIS_OUT_BYTE_A (Z80 *z80, Z80Byte op, Z80Word *pc) +{ + Z80_Dis_Set("out",Z80_Dis_Printf("($%.2x),a",Z80_Dis_FetchByte(z80,pc))); +} + +static void DIS_SUB_A_BYTE (Z80 *z80, Z80Byte op, Z80Word *pc) +{ + Z80_Dis_Set("sub",Z80_Dis_Printf("a,$%.2x",Z80_Dis_FetchByte(z80,pc))); +} + +static void DIS_EXX (Z80 *z80, Z80Byte op, Z80Word *pc) +{ + Z80_Dis_Set("exx",NULL); +} + +static void DIS_IN_A_BYTE (Z80 *z80, Z80Byte op, Z80Word *pc) +{ + Z80_Dis_Set("in",Z80_Dis_Printf("a,($%.2x)",Z80_Dis_FetchByte(z80,pc))); +} + +static void DIS_DD_DECODE (Z80 *z80, Z80Byte op, Z80Word *pc) +{ + int nop; + + nop=Z80_Dis_FetchByte(z80,pc); + dis_DD_opcode[nop](z80,nop,pc); +} + +static void DIS_SBC_A_BYTE (Z80 *z80, Z80Byte op, Z80Word *pc) +{ + Z80_Dis_Set("sbc",Z80_Dis_Printf("a,$%.2x",Z80_Dis_FetchByte(z80,pc))); +} + + +static void DIS_EX_ISP_HL (Z80 *z80, Z80Byte op, Z80Word *pc) +{ + Z80_Dis_Set("ex","(sp),hl"); +} + +static void DIS_AND_A_BYTE (Z80 *z80, Z80Byte op, Z80Word *pc) +{ + Z80_Dis_Set("and",Z80_Dis_Printf("$%.2x",Z80_Dis_FetchByte(z80,pc))); +} + +static void DIS_JP_HL (Z80 *z80, Z80Byte op, Z80Word *pc) +{ + Z80_Dis_Set("jp","(hl)"); +} + +static void DIS_EX_DE_HL (Z80 *z80, Z80Byte op, Z80Word *pc) +{ + Z80_Dis_Set("ex","de,hl"); +} + +static void DIS_ED_DECODE (Z80 *z80, Z80Byte op, Z80Word *pc) +{ + int nop; + + nop=Z80_Dis_FetchByte(z80,pc); + dis_ED_opcode[nop](z80,nop,pc); +} + +static void DIS_XOR_A_BYTE (Z80 *z80, Z80Byte op, Z80Word *pc) +{ + Z80_Dis_Set("xor",Z80_Dis_Printf("$%.2x",Z80_Dis_FetchByte(z80,pc))); +} + +static void DIS_DI (Z80 *z80, Z80Byte op, Z80Word *pc) +{ + Z80_Dis_Set("di",NULL); +} + +static void DIS_OR_A_BYTE (Z80 *z80, Z80Byte op, Z80Word *pc) +{ + Z80_Dis_Set("or",Z80_Dis_Printf("$%.2x",Z80_Dis_FetchByte(z80,pc))); +} + +static void DIS_LD_SP_HL (Z80 *z80, Z80Byte op, Z80Word *pc) +{ + Z80_Dis_Set("ld","sp,hl"); +} + +static void DIS_EI (Z80 *z80, Z80Byte op, Z80Word *pc) +{ + Z80_Dis_Set("ei",NULL); +} + +static void DIS_FD_DECODE (Z80 *z80, Z80Byte op, Z80Word *pc) +{ + int nop; + + nop=Z80_Dis_FetchByte(z80,pc); + dis_FD_opcode[nop](z80,nop,pc); +} + +static void DIS_CP_A_BYTE (Z80 *z80, Z80Byte op, Z80Word *pc) +{ + Z80_Dis_Set("cp",Z80_Dis_Printf("$%.2x",Z80_Dis_FetchByte(z80,pc))); +} + + +/* ---------------------------------------- TABLES +*/ + +/* CB opcodes +*/ +DIS_OP_CALLBACK dis_CB_opcode[0x100]= + { +/* 0x00 - 0x03 */ DIS_RLC_R8, DIS_RLC_R8, DIS_RLC_R8, DIS_RLC_R8, +/* 0x04 - 0x07 */ DIS_RLC_R8, DIS_RLC_R8, DIS_RLC_R8, DIS_RLC_R8, +/* 0x08 - 0x0b */ DIS_RRC_R8, DIS_RRC_R8, DIS_RRC_R8, DIS_RRC_R8, +/* 0x0c - 0x0f */ DIS_RRC_R8, DIS_RRC_R8, DIS_RRC_R8, DIS_RRC_R8, + +/* 0x10 - 0x13 */ DIS_RL_R8, DIS_RL_R8, DIS_RL_R8, DIS_RL_R8, +/* 0x14 - 0x17 */ DIS_RL_R8, DIS_RL_R8, DIS_RL_R8, DIS_RL_R8, +/* 0x18 - 0x1b */ DIS_RR_R8, DIS_RR_R8, DIS_RR_R8, DIS_RR_R8, +/* 0x1c - 0x1f */ DIS_RR_R8, DIS_RR_R8, DIS_RR_R8, DIS_RR_R8, + +/* 0x20 - 0x23 */ DIS_SLA_R8, DIS_SLA_R8, DIS_SLA_R8, DIS_SLA_R8, +/* 0x24 - 0x27 */ DIS_SLA_R8, DIS_SLA_R8, DIS_SLA_R8, DIS_SLA_R8, +/* 0x28 - 0x2b */ DIS_SRA_R8, DIS_SRA_R8, DIS_SRA_R8, DIS_SRA_R8, +/* 0x2c - 0x2f */ DIS_SRA_R8, DIS_SRA_R8, DIS_SRA_R8, DIS_SRA_R8, + +/* 0x30 - 0x33 */ DIS_SLL_R8, DIS_SLL_R8, DIS_SLL_R8, DIS_SLL_R8, +/* 0x34 - 0x37 */ DIS_SLL_R8, DIS_SLL_R8, DIS_SLL_R8, DIS_SLL_R8, +/* 0x38 - 0x3b */ DIS_SRL_R8, DIS_SRL_R8, DIS_SRL_R8, DIS_SRL_R8, +/* 0x3c - 0x3f */ DIS_SRL_R8, DIS_SRL_R8, DIS_SRL_R8, DIS_SRL_R8, + +/* 0x40 - 0x43 */ DIS_BIT_R8, DIS_BIT_R8, DIS_BIT_R8, DIS_BIT_R8, +/* 0x44 - 0x47 */ DIS_BIT_R8, DIS_BIT_R8, DIS_BIT_R8, DIS_BIT_R8, +/* 0x48 - 0x4b */ DIS_BIT_R8, DIS_BIT_R8, DIS_BIT_R8, DIS_BIT_R8, +/* 0x4c - 0x4f */ DIS_BIT_R8, DIS_BIT_R8, DIS_BIT_R8, DIS_BIT_R8, + +/* 0x50 - 0x53 */ DIS_BIT_R8, DIS_BIT_R8, DIS_BIT_R8, DIS_BIT_R8, +/* 0x54 - 0x57 */ DIS_BIT_R8, DIS_BIT_R8, DIS_BIT_R8, DIS_BIT_R8, +/* 0x58 - 0x5b */ DIS_BIT_R8, DIS_BIT_R8, DIS_BIT_R8, DIS_BIT_R8, +/* 0x5c - 0x5f */ DIS_BIT_R8, DIS_BIT_R8, DIS_BIT_R8, DIS_BIT_R8, + +/* 0x60 - 0x63 */ DIS_BIT_R8, DIS_BIT_R8, DIS_BIT_R8, DIS_BIT_R8, +/* 0x64 - 0x67 */ DIS_BIT_R8, DIS_BIT_R8, DIS_BIT_R8, DIS_BIT_R8, +/* 0x68 - 0x6b */ DIS_BIT_R8, DIS_BIT_R8, DIS_BIT_R8, DIS_BIT_R8, +/* 0x6c - 0x6f */ DIS_BIT_R8, DIS_BIT_R8, DIS_BIT_R8, DIS_BIT_R8, + +/* 0x70 - 0x73 */ DIS_BIT_R8, DIS_BIT_R8, DIS_BIT_R8, DIS_BIT_R8, +/* 0x74 - 0x77 */ DIS_BIT_R8, DIS_BIT_R8, DIS_BIT_R8, DIS_BIT_R8, +/* 0x78 - 0x7b */ DIS_BIT_R8, DIS_BIT_R8, DIS_BIT_R8, DIS_BIT_R8, +/* 0x7c - 0x7f */ DIS_BIT_R8, DIS_BIT_R8, DIS_BIT_R8, DIS_BIT_R8, + +/* 0x80 - 0x83 */ DIS_RES_R8, DIS_RES_R8, DIS_RES_R8, DIS_RES_R8, +/* 0x84 - 0x87 */ DIS_RES_R8, DIS_RES_R8, DIS_RES_R8, DIS_RES_R8, +/* 0x88 - 0x8b */ DIS_RES_R8, DIS_RES_R8, DIS_RES_R8, DIS_RES_R8, +/* 0x8c - 0x8f */ DIS_RES_R8, DIS_RES_R8, DIS_RES_R8, DIS_RES_R8, + +/* 0x90 - 0x93 */ DIS_RES_R8, DIS_RES_R8, DIS_RES_R8, DIS_RES_R8, +/* 0x94 - 0x97 */ DIS_RES_R8, DIS_RES_R8, DIS_RES_R8, DIS_RES_R8, +/* 0x98 - 0x9b */ DIS_RES_R8, DIS_RES_R8, DIS_RES_R8, DIS_RES_R8, +/* 0x9c - 0x9f */ DIS_RES_R8, DIS_RES_R8, DIS_RES_R8, DIS_RES_R8, + +/* 0xa0 - 0xa3 */ DIS_RES_R8, DIS_RES_R8, DIS_RES_R8, DIS_RES_R8, +/* 0xa4 - 0xa7 */ DIS_RES_R8, DIS_RES_R8, DIS_RES_R8, DIS_RES_R8, +/* 0xa8 - 0xab */ DIS_RES_R8, DIS_RES_R8, DIS_RES_R8, DIS_RES_R8, +/* 0xac - 0xaf */ DIS_RES_R8, DIS_RES_R8, DIS_RES_R8, DIS_RES_R8, + +/* 0xb0 - 0xb3 */ DIS_RES_R8, DIS_RES_R8, DIS_RES_R8, DIS_RES_R8, +/* 0xb4 - 0xb7 */ DIS_RES_R8, DIS_RES_R8, DIS_RES_R8, DIS_RES_R8, +/* 0xb8 - 0xbb */ DIS_RES_R8, DIS_RES_R8, DIS_RES_R8, DIS_RES_R8, +/* 0xbc - 0xbf */ DIS_RES_R8, DIS_RES_R8, DIS_RES_R8, DIS_RES_R8, + +/* 0xc0 - 0xc3 */ DIS_SET_R8, DIS_SET_R8, DIS_SET_R8, DIS_SET_R8, +/* 0xc4 - 0xc7 */ DIS_SET_R8, DIS_SET_R8, DIS_SET_R8, DIS_SET_R8, +/* 0xc8 - 0xcb */ DIS_SET_R8, DIS_SET_R8, DIS_SET_R8, DIS_SET_R8, +/* 0xcc - 0xcf */ DIS_SET_R8, DIS_SET_R8, DIS_SET_R8, DIS_SET_R8, + +/* 0xd0 - 0xd3 */ DIS_SET_R8, DIS_SET_R8, DIS_SET_R8, DIS_SET_R8, +/* 0xd4 - 0xd7 */ DIS_SET_R8, DIS_SET_R8, DIS_SET_R8, DIS_SET_R8, +/* 0xd8 - 0xdb */ DIS_SET_R8, DIS_SET_R8, DIS_SET_R8, DIS_SET_R8, +/* 0xdc - 0xdf */ DIS_SET_R8, DIS_SET_R8, DIS_SET_R8, DIS_SET_R8, + +/* 0xe0 - 0xe3 */ DIS_SET_R8, DIS_SET_R8, DIS_SET_R8, DIS_SET_R8, +/* 0xe4 - 0xe7 */ DIS_SET_R8, DIS_SET_R8, DIS_SET_R8, DIS_SET_R8, +/* 0xe8 - 0xeb */ DIS_SET_R8, DIS_SET_R8, DIS_SET_R8, DIS_SET_R8, +/* 0xec - 0xef */ DIS_SET_R8, DIS_SET_R8, DIS_SET_R8, DIS_SET_R8, + +/* 0xf0 - 0xf3 */ DIS_SET_R8, DIS_SET_R8, DIS_SET_R8, DIS_SET_R8, +/* 0xf4 - 0xf7 */ DIS_SET_R8, DIS_SET_R8, DIS_SET_R8, DIS_SET_R8, +/* 0xf8 - 0xfb */ DIS_SET_R8, DIS_SET_R8, DIS_SET_R8, DIS_SET_R8, +/* 0xfc - 0xff */ DIS_SET_R8, DIS_SET_R8, DIS_SET_R8, DIS_SET_R8, + }; + +/* DIS_DD opcodes +*/ +DIS_OP_CALLBACK dis_DD_opcode[0x100]= + { +/* 0x00 - 0x03 */ DIS_DD_NOP, DIS_DD_NOP, DIS_DD_NOP, DIS_DD_NOP, +/* 0x04 - 0x07 */ DIS_DD_NOP, DIS_DD_NOP, DIS_DD_NOP, DIS_DD_NOP, +/* 0x08 - 0x0b */ DIS_DD_NOP, DIS_ADD_IX_BC, DIS_DD_NOP, DIS_DD_NOP, +/* 0x0c - 0x0f */ DIS_DD_NOP, DIS_DD_NOP, DIS_DD_NOP, DIS_DD_NOP, + +/* 0x10 - 0x13 */ DIS_DD_NOP, DIS_DD_NOP, DIS_DD_NOP, DIS_DD_NOP, +/* 0x14 - 0x17 */ DIS_DD_NOP, DIS_DD_NOP, DIS_DD_NOP, DIS_DD_NOP, +/* 0x18 - 0x1b */ DIS_DD_NOP, DIS_ADD_IX_DE, DIS_DD_NOP, DIS_DD_NOP, +/* 0x1c - 0x1f */ DIS_DD_NOP, DIS_DD_NOP, DIS_DD_NOP, DIS_DD_NOP, + +/* 0x20 - 0x23 */ DIS_DD_NOP, DIS_LD_IX_WORD, DIS_LD_ADDR_IX, DIS_INC_IX, +/* 0x24 - 0x27 */ DIS_INC_IXH, DIS_DEC_IXH, DIS_LD_IXH_BYTE, DIS_DD_NOP, +/* 0x28 - 0x2b */ DIS_DD_NOP, DIS_ADD_IX_IX, DIS_LD_IX_ADDR, DIS_DEC_IX, +/* 0x2c - 0x2f */ DIS_INC_IXL, DIS_DEC_IXL, DIS_LD_IXL_BYTE, DIS_DD_NOP, + +/* 0x30 - 0x33 */ DIS_DD_NOP, DIS_DD_NOP, DIS_DD_NOP, DIS_DD_NOP, +/* 0x34 - 0x37 */ DIS_INC_IIX, DIS_DEC_IIX, DIS_LD_IIX_BYTE, DIS_DD_NOP, +/* 0x38 - 0x3b */ DIS_DD_NOP, DIS_ADD_IX_SP, DIS_DD_NOP, DIS_DD_NOP, +/* 0x3c - 0x3f */ DIS_DD_NOP, DIS_DD_NOP, DIS_DD_NOP, DIS_DD_NOP, + +/* 0x40 - 0x43 */ DIS_DD_NOP, DIS_DD_NOP, DIS_DD_NOP, DIS_DD_NOP, +/* 0x44 - 0x47 */ DIS_XLD_R8_R8, DIS_XLD_R8_R8, DIS_XLD_R8_R8, DIS_DD_NOP, +/* 0x48 - 0x4b */ DIS_DD_NOP, DIS_DD_NOP, DIS_DD_NOP, DIS_DD_NOP, +/* 0x4c - 0x4f */ DIS_XLD_R8_R8, DIS_XLD_R8_R8, DIS_XLD_R8_R8, DIS_DD_NOP, + +/* 0x50 - 0x53 */ DIS_DD_NOP, DIS_DD_NOP, DIS_DD_NOP, DIS_DD_NOP, +/* 0x54 - 0x57 */ DIS_XLD_R8_R8, DIS_XLD_R8_R8, DIS_XLD_R8_R8, DIS_DD_NOP, +/* 0x58 - 0x5b */ DIS_DD_NOP, DIS_DD_NOP, DIS_DD_NOP, DIS_DD_NOP, +/* 0x5c - 0x5f */ DIS_XLD_R8_R8, DIS_XLD_R8_R8, DIS_XLD_R8_R8, DIS_DD_NOP, + +/* 0x60 - 0x63 */ DIS_XLD_R8_R8, DIS_XLD_R8_R8, DIS_XLD_R8_R8, DIS_XLD_R8_R8, +/* 0x64 - 0x67 */ DIS_XLD_R8_R8, DIS_XLD_R8_R8, DIS_XLD_R8_R8, DIS_XLD_R8_R8, +/* 0x68 - 0x6b */ DIS_XLD_R8_R8, DIS_XLD_R8_R8, DIS_XLD_R8_R8, DIS_XLD_R8_R8, +/* 0x6c - 0x6f */ DIS_XLD_R8_R8, DIS_XLD_R8_R8, DIS_XLD_R8_R8, DIS_XLD_R8_R8, + +/* 0x70 - 0x73 */ DIS_XLD_R8_R8, DIS_XLD_R8_R8, DIS_XLD_R8_R8, DIS_XLD_R8_R8, +/* 0x74 - 0x77 */ DIS_XLD_R8_R8, DIS_XLD_R8_R8, DIS_DD_NOP, DIS_XLD_R8_R8, +/* 0x78 - 0x7b */ DIS_DD_NOP, DIS_DD_NOP, DIS_DD_NOP, DIS_DD_NOP, +/* 0x7c - 0x7f */ DIS_XLD_R8_R8, DIS_XLD_R8_R8, DIS_XLD_R8_R8, DIS_DD_NOP, + +/* 0x80 - 0x83 */ DIS_DD_NOP, DIS_DD_NOP, DIS_DD_NOP, DIS_DD_NOP, +/* 0x84 - 0x87 */ DIS_XADD_R8, DIS_XADD_R8, DIS_XADD_R8, DIS_DD_NOP, +/* 0x88 - 0x8b */ DIS_DD_NOP, DIS_DD_NOP, DIS_DD_NOP, DIS_DD_NOP, +/* 0x8c - 0x8f */ DIS_XADC_R8, DIS_XADC_R8, DIS_XADC_R8, DIS_DD_NOP, + +/* 0x90 - 0x93 */ DIS_DD_NOP, DIS_DD_NOP, DIS_DD_NOP, DIS_DD_NOP, +/* 0x94 - 0x97 */ DIS_XSUB_R8, DIS_XSUB_R8, DIS_XSUB_R8, DIS_DD_NOP, +/* 0x98 - 0x9b */ DIS_DD_NOP, DIS_DD_NOP, DIS_DD_NOP, DIS_DD_NOP, +/* 0x9c - 0x9f */ DIS_XSBC_R8, DIS_XSBC_R8, DIS_XSBC_R8, DIS_DD_NOP, + +/* 0xa0 - 0xa3 */ DIS_DD_NOP, DIS_DD_NOP, DIS_DD_NOP, DIS_DD_NOP, +/* 0xa4 - 0xa7 */ DIS_XAND_R8, DIS_XAND_R8, DIS_XAND_R8, DIS_DD_NOP, +/* 0xa8 - 0xab */ DIS_DD_NOP, DIS_DD_NOP, DIS_DD_NOP, DIS_DD_NOP, +/* 0xac - 0xaf */ DIS_XXOR_R8, DIS_XXOR_R8, DIS_XXOR_R8, DIS_DD_NOP, + +/* 0xb0 - 0xb3 */ DIS_DD_NOP, DIS_DD_NOP, DIS_DD_NOP, DIS_DD_NOP, +/* 0xb4 - 0xb7 */ DIS_X_OR_R8, DIS_X_OR_R8, DIS_X_OR_R8, DIS_DD_NOP, +/* 0xb8 - 0xbb */ DIS_DD_NOP, DIS_DD_NOP, DIS_DD_NOP, DIS_DD_NOP, +/* 0xbc - 0xbf */ DIS_XCP_R8, DIS_XCP_R8, DIS_XCP_R8, DIS_DD_NOP, + +/* 0xc0 - 0xc3 */ DIS_DD_NOP, DIS_DD_NOP, DIS_DD_NOP, DIS_DD_NOP, +/* 0xc4 - 0xc7 */ DIS_DD_NOP, DIS_DD_NOP, DIS_DD_NOP, DIS_DD_NOP, +/* 0xc8 - 0xcb */ DIS_DD_NOP, DIS_DD_NOP, DIS_DD_NOP, DIS_DD_CB_DECODE, +/* 0xcc - 0xcf */ DIS_DD_NOP, DIS_DD_NOP, DIS_DD_NOP, DIS_DD_NOP, + +/* 0xd0 - 0xd3 */ DIS_DD_NOP, DIS_DD_NOP, DIS_DD_NOP, DIS_DD_NOP, +/* 0xd4 - 0xd7 */ DIS_DD_NOP, DIS_DD_NOP, DIS_DD_NOP, DIS_DD_NOP, +/* 0xd8 - 0xdb */ DIS_DD_NOP, DIS_DD_NOP, DIS_DD_NOP, DIS_DD_NOP, +/* 0xdc - 0xdf */ DIS_DD_NOP, DIS_DD_DD_DECODE, DIS_DD_NOP, DIS_DD_NOP, + +/* 0xe0 - 0xe3 */ DIS_DD_NOP, DIS_POP_IX, DIS_DD_NOP, DIS_EX_ISP_IX, +/* 0xe4 - 0xe7 */ DIS_DD_NOP, DIS_PUSH_IX, DIS_DD_NOP, DIS_DD_NOP, +/* 0xe8 - 0xeb */ DIS_DD_NOP, DIS_JP_IX, DIS_DD_NOP, DIS_DD_NOP, +/* 0xec - 0xef */ DIS_DD_NOP, DIS_DD_ED_DECODE, DIS_DD_NOP, DIS_DD_NOP, + +/* 0xf0 - 0xf3 */ DIS_DD_NOP, DIS_DD_NOP, DIS_DD_NOP, DIS_DD_NOP, +/* 0xf4 - 0xf7 */ DIS_DD_NOP, DIS_DD_NOP, DIS_DD_NOP, DIS_DD_NOP, +/* 0xf8 - 0xfb */ DIS_DD_NOP, DIS_LD_SP_IX, DIS_DD_NOP, DIS_DD_NOP, +/* 0xfc - 0xff */ DIS_DD_NOP, DIS_DD_FD_DECODE, DIS_DD_NOP, DIS_DD_NOP, + }; + + +/* DIS_DD DIS_CB opcodes +*/ +DIS_OP_CALLBACK dis_DD_CB_opcode[0x100]= + { +/* 0x00 - 0x03 */ DIS_RLC_IX, DIS_RLC_IX, DIS_RLC_IX, DIS_RLC_IX, +/* 0x04 - 0x07 */ DIS_RLC_IX, DIS_RLC_IX, DIS_RLC_IX, DIS_RLC_IX, +/* 0x08 - 0x0b */ DIS_RRC_IX, DIS_RRC_IX, DIS_RRC_IX, DIS_RRC_IX, +/* 0x0c - 0x0f */ DIS_RRC_IX, DIS_RRC_IX, DIS_RRC_IX, DIS_RRC_IX, + +/* 0x10 - 0x13 */ DIS_RL_IX, DIS_RL_IX, DIS_RL_IX, DIS_RL_IX, +/* 0x14 - 0x17 */ DIS_RL_IX, DIS_RL_IX, DIS_RL_IX, DIS_RL_IX, +/* 0x18 - 0x1b */ DIS_RR_IX, DIS_RR_IX, DIS_RR_IX, DIS_RR_IX, +/* 0x1c - 0x1f */ DIS_RR_IX, DIS_RR_IX, DIS_RR_IX, DIS_RR_IX, + +/* 0x20 - 0x23 */ DIS_SLA_IX, DIS_SLA_IX, DIS_SLA_IX, DIS_SLA_IX, +/* 0x24 - 0x27 */ DIS_SLA_IX, DIS_SLA_IX, DIS_SLA_IX, DIS_SLA_IX, +/* 0x28 - 0x2b */ DIS_SRA_IX, DIS_SRA_IX, DIS_SRA_IX, DIS_SRA_IX, +/* 0x2c - 0x2f */ DIS_SRA_IX, DIS_SRA_IX, DIS_SRA_IX, DIS_SRA_IX, + +/* 0x30 - 0x33 */ DIS_SLL_IX, DIS_SLL_IX, DIS_SLL_IX, DIS_SLL_IX, +/* 0x34 - 0x37 */ DIS_SLL_IX, DIS_SLL_IX, DIS_SLL_IX, DIS_SLL_IX, +/* 0x38 - 0x3b */ DIS_SRL_IX, DIS_SRL_IX, DIS_SRL_IX, DIS_SRL_IX, +/* 0x3c - 0x3f */ DIS_SRL_IX, DIS_SRL_IX, DIS_SRL_IX, DIS_SRL_IX, + +/* 0x40 - 0x43 */ DIS_BIT_IX,DIS_BIT_IX, DIS_BIT_IX, DIS_BIT_IX, +/* 0x44 - 0x47 */ DIS_BIT_IX,DIS_BIT_IX, DIS_BIT_IX, DIS_BIT_IX, +/* 0x48 - 0x4b */ DIS_BIT_IX,DIS_BIT_IX, DIS_BIT_IX, DIS_BIT_IX, +/* 0x4c - 0x4f */ DIS_BIT_IX,DIS_BIT_IX, DIS_BIT_IX, DIS_BIT_IX, + +/* 0x50 - 0x53 */ DIS_BIT_IX,DIS_BIT_IX, DIS_BIT_IX, DIS_BIT_IX, +/* 0x54 - 0x57 */ DIS_BIT_IX,DIS_BIT_IX, DIS_BIT_IX, DIS_BIT_IX, +/* 0x58 - 0x5b */ DIS_BIT_IX,DIS_BIT_IX, DIS_BIT_IX, DIS_BIT_IX, +/* 0x5c - 0x5f */ DIS_BIT_IX,DIS_BIT_IX, DIS_BIT_IX, DIS_BIT_IX, + +/* 0x60 - 0x63 */ DIS_BIT_IX,DIS_BIT_IX, DIS_BIT_IX, DIS_BIT_IX, +/* 0x64 - 0x67 */ DIS_BIT_IX,DIS_BIT_IX, DIS_BIT_IX, DIS_BIT_IX, +/* 0x68 - 0x6b */ DIS_BIT_IX,DIS_BIT_IX, DIS_BIT_IX, DIS_BIT_IX, +/* 0x6c - 0x6f */ DIS_BIT_IX,DIS_BIT_IX, DIS_BIT_IX, DIS_BIT_IX, + +/* 0x70 - 0x73 */ DIS_BIT_IX,DIS_BIT_IX, DIS_BIT_IX, DIS_BIT_IX, +/* 0x74 - 0x77 */ DIS_BIT_IX,DIS_BIT_IX, DIS_BIT_IX, DIS_BIT_IX, +/* 0x78 - 0x7b */ DIS_BIT_IX,DIS_BIT_IX, DIS_BIT_IX, DIS_BIT_IX, +/* 0x7c - 0x7f */ DIS_BIT_IX,DIS_BIT_IX, DIS_BIT_IX, DIS_BIT_IX, + +/* 0x80 - 0x83 */ DIS_RES_IX,DIS_RES_IX, DIS_RES_IX, DIS_RES_IX, +/* 0x84 - 0x87 */ DIS_RES_IX,DIS_RES_IX, DIS_RES_IX, DIS_RES_IX, +/* 0x88 - 0x8b */ DIS_RES_IX,DIS_RES_IX, DIS_RES_IX, DIS_RES_IX, +/* 0x8c - 0x8f */ DIS_RES_IX,DIS_RES_IX, DIS_RES_IX, DIS_RES_IX, + +/* 0x90 - 0x93 */ DIS_RES_IX,DIS_RES_IX, DIS_RES_IX, DIS_RES_IX, +/* 0x94 - 0x97 */ DIS_RES_IX,DIS_RES_IX, DIS_RES_IX, DIS_RES_IX, +/* 0x98 - 0x9b */ DIS_RES_IX,DIS_RES_IX, DIS_RES_IX, DIS_RES_IX, +/* 0x9c - 0x9f */ DIS_RES_IX,DIS_RES_IX, DIS_RES_IX, DIS_RES_IX, + +/* 0xa0 - 0xa3 */ DIS_RES_IX,DIS_RES_IX, DIS_RES_IX, DIS_RES_IX, +/* 0xa4 - 0xa7 */ DIS_RES_IX,DIS_RES_IX, DIS_RES_IX, DIS_RES_IX, +/* 0xa8 - 0xab */ DIS_RES_IX,DIS_RES_IX, DIS_RES_IX, DIS_RES_IX, +/* 0xac - 0xaf */ DIS_RES_IX,DIS_RES_IX, DIS_RES_IX, DIS_RES_IX, + +/* 0xb0 - 0xb3 */ DIS_RES_IX,DIS_RES_IX, DIS_RES_IX, DIS_RES_IX, +/* 0xb4 - 0xb7 */ DIS_RES_IX,DIS_RES_IX, DIS_RES_IX, DIS_RES_IX, +/* 0xb8 - 0xbb */ DIS_RES_IX,DIS_RES_IX, DIS_RES_IX, DIS_RES_IX, +/* 0xbc - 0xbf */ DIS_RES_IX,DIS_RES_IX, DIS_RES_IX, DIS_RES_IX, + +/* 0xc0 - 0xc3 */ DIS_SET_IX,DIS_SET_IX, DIS_SET_IX, DIS_SET_IX, +/* 0xc4 - 0xc7 */ DIS_SET_IX,DIS_SET_IX, DIS_SET_IX, DIS_SET_IX, +/* 0xc8 - 0xcb */ DIS_SET_IX,DIS_SET_IX, DIS_SET_IX, DIS_SET_IX, +/* 0xcc - 0xcf */ DIS_SET_IX,DIS_SET_IX, DIS_SET_IX, DIS_SET_IX, + +/* 0xd0 - 0xd3 */ DIS_SET_IX,DIS_SET_IX, DIS_SET_IX, DIS_SET_IX, +/* 0xd4 - 0xd7 */ DIS_SET_IX,DIS_SET_IX, DIS_SET_IX, DIS_SET_IX, +/* 0xd8 - 0xdb */ DIS_SET_IX,DIS_SET_IX, DIS_SET_IX, DIS_SET_IX, +/* 0xdc - 0xdf */ DIS_SET_IX,DIS_SET_IX, DIS_SET_IX, DIS_SET_IX, + +/* 0xe0 - 0xe3 */ DIS_SET_IX,DIS_SET_IX, DIS_SET_IX, DIS_SET_IX, +/* 0xe4 - 0xe7 */ DIS_SET_IX,DIS_SET_IX, DIS_SET_IX, DIS_SET_IX, +/* 0xe8 - 0xeb */ DIS_SET_IX,DIS_SET_IX, DIS_SET_IX, DIS_SET_IX, +/* 0xec - 0xef */ DIS_SET_IX,DIS_SET_IX, DIS_SET_IX, DIS_SET_IX, + +/* 0xf0 - 0xf3 */ DIS_SET_IX,DIS_SET_IX, DIS_SET_IX, DIS_SET_IX, +/* 0xf4 - 0xf7 */ DIS_SET_IX,DIS_SET_IX, DIS_SET_IX, DIS_SET_IX, +/* 0xf8 - 0xfb */ DIS_SET_IX,DIS_SET_IX, DIS_SET_IX, DIS_SET_IX, +/* 0xfc - 0xff */ DIS_SET_IX,DIS_SET_IX, DIS_SET_IX, DIS_SET_IX, + }; + +/* DIS_ED opcodes +*/ +DIS_OP_CALLBACK dis_ED_opcode[0x100]= + { +/* 0x00 - 0x03 */ DIS_ED_NOP, DIS_ED_NOP, DIS_ED_NOP, DIS_ED_NOP, +/* 0x04 - 0x07 */ DIS_ED_NOP, DIS_ED_NOP, DIS_ED_NOP, DIS_ED_NOP, +/* 0x08 - 0x0b */ DIS_ED_NOP, DIS_ED_NOP, DIS_ED_NOP, DIS_ED_NOP, +/* 0x0c - 0x0f */ DIS_ED_NOP, DIS_ED_NOP, DIS_ED_NOP, DIS_ED_NOP, + +/* 0x10 - 0x13 */ DIS_ED_NOP, DIS_ED_NOP, DIS_ED_NOP, DIS_ED_NOP, +/* 0x14 - 0x17 */ DIS_ED_NOP, DIS_ED_NOP, DIS_ED_NOP, DIS_ED_NOP, +/* 0x18 - 0x1b */ DIS_ED_NOP, DIS_ED_NOP, DIS_ED_NOP, DIS_ED_NOP, +/* 0x1c - 0x1f */ DIS_ED_NOP, DIS_ED_NOP, DIS_ED_NOP, DIS_ED_NOP, + +/* 0x20 - 0x23 */ DIS_ED_NOP, DIS_ED_NOP, DIS_ED_NOP, DIS_ED_NOP, +/* 0x24 - 0x27 */ DIS_ED_NOP, DIS_ED_NOP, DIS_ED_NOP, DIS_ED_NOP, +/* 0x28 - 0x2b */ DIS_ED_NOP, DIS_ED_NOP, DIS_ED_NOP, DIS_ED_NOP, +/* 0x2c - 0x2f */ DIS_ED_NOP, DIS_ED_NOP, DIS_ED_NOP, DIS_ED_NOP, + +/* 0x30 - 0x33 */ DIS_ED_NOP, DIS_ED_NOP, DIS_ED_NOP, DIS_ED_NOP, +/* 0x34 - 0x37 */ DIS_ED_NOP, DIS_ED_NOP, DIS_ED_NOP, DIS_ED_NOP, +/* 0x38 - 0x3b */ DIS_ED_NOP, DIS_ED_NOP, DIS_ED_NOP, DIS_ED_NOP, +/* 0x3c - 0x3f */ DIS_ED_NOP, DIS_ED_NOP, DIS_ED_NOP, DIS_ED_NOP, + +/* 0x40 - 0x43 */ DIS_IN_R8_C, DIS_OUT_C_R8, DIS_SBC_HL_R16, DIS_ED_LD_ADDR_R16, +/* 0x44 - 0x47 */ DIS_NEG, DIS_RETN, DIS_IM_0, DIS_LD_I_A, +/* 0x48 - 0x4b */ DIS_IN_R8_C, DIS_OUT_C_R8, DIS_ADC_HL_R16, DIS_ED_LD_R16_ADDR, +/* 0x4c - 0x4f */ DIS_NEG, DIS_RETI, DIS_IM_0, DIS_LD_R_A, + +/* 0x50 - 0x53 */ DIS_IN_R8_C, DIS_OUT_C_R8, DIS_SBC_HL_R16, DIS_ED_LD_ADDR_R16, +/* 0x54 - 0x57 */ DIS_NEG, DIS_RETN, DIS_IM_1, DIS_LD_A_I, +/* 0x58 - 0x5b */ DIS_IN_R8_C, DIS_OUT_C_R8, DIS_ADC_HL_R16, DIS_ED_LD_R16_ADDR, +/* 0x5c - 0x5f */ DIS_NEG, DIS_RETI, DIS_IM_2, DIS_LD_A_R, + +/* 0x60 - 0x63 */ DIS_IN_R8_C, DIS_OUT_C_R8, DIS_SBC_HL_R16, DIS_ED_LD_ADDR_R16, +/* 0x64 - 0x67 */ DIS_NEG, DIS_RETN, DIS_IM_0, DIS_RRD, +/* 0x68 - 0x6b */ DIS_IN_R8_C, DIS_OUT_C_R8, DIS_ADC_HL_R16, DIS_ED_LD_R16_ADDR, +/* 0x6c - 0x6f */ DIS_NEG, DIS_RETI, DIS_IM_0, DIS_RLD, + +/* 0x70 - 0x73 */ DIS_IN_R8_C, DIS_OUT_C_R8, DIS_SBC_HL_R16, DIS_ED_LD_ADDR_R16, +/* 0x74 - 0x77 */ DIS_NEG, DIS_RETN, DIS_IM_1, DIS_ED_NOP, +/* 0x78 - 0x7b */ DIS_IN_R8_C, DIS_OUT_C_R8, DIS_ADC_HL_R16, DIS_ED_LD_R16_ADDR, +/* 0x7c - 0x7f */ DIS_NEG, DIS_RETI, DIS_IM_2, DIS_ED_NOP, + +/* 0x80 - 0x83 */ DIS_ED_NOP, DIS_ED_NOP, DIS_ED_NOP, DIS_ED_NOP, +/* 0x84 - 0x87 */ DIS_ED_NOP, DIS_ED_NOP, DIS_ED_NOP, DIS_ED_NOP, +/* 0x88 - 0x8b */ DIS_ED_NOP, DIS_ED_NOP, DIS_ED_NOP, DIS_ED_NOP, +/* 0x8c - 0x8f */ DIS_ED_NOP, DIS_ED_NOP, DIS_ED_NOP, DIS_ED_NOP, + +/* 0x90 - 0x93 */ DIS_ED_NOP, DIS_ED_NOP, DIS_ED_NOP, DIS_ED_NOP, +/* 0x94 - 0x97 */ DIS_ED_NOP, DIS_ED_NOP, DIS_ED_NOP, DIS_ED_NOP, +/* 0x98 - 0x9b */ DIS_ED_NOP, DIS_ED_NOP, DIS_ED_NOP, DIS_ED_NOP, +/* 0x9c - 0x9f */ DIS_ED_NOP, DIS_ED_NOP, DIS_ED_NOP, DIS_ED_NOP, + +/* 0xa0 - 0xa3 */ DIS_LDI, DIS_CPI, DIS_INI, DIS_OUTI, +/* 0xa4 - 0xa7 */ DIS_ED_NOP, DIS_ED_NOP, DIS_ED_NOP, DIS_ED_NOP, +/* 0xa8 - 0xab */ DIS_LDD, DIS_CPD, DIS_IND, DIS_OUTD, +/* 0xac - 0xaf */ DIS_ED_NOP, DIS_ED_NOP, DIS_ED_NOP, DIS_ED_NOP, + +/* 0xb0 - 0xb3 */ DIS_LDIR, DIS_CPIR, DIS_INIR, DIS_OTIR, +/* 0xb4 - 0xb7 */ DIS_ED_NOP, DIS_ED_NOP, DIS_ED_NOP, DIS_ED_NOP, +/* 0xb8 - 0xbb */ DIS_LDDR, DIS_CPDR, DIS_INDR, DIS_OTDR, +/* 0xbc - 0xbf */ DIS_ED_NOP, DIS_ED_NOP, DIS_ED_NOP, DIS_ED_NOP, + +/* 0xc0 - 0xc3 */ DIS_ED_NOP, DIS_ED_NOP, DIS_ED_NOP, DIS_ED_NOP, +/* 0xc4 - 0xc7 */ DIS_ED_NOP, DIS_ED_NOP, DIS_ED_NOP, DIS_ED_NOP, +/* 0xc8 - 0xcb */ DIS_ED_NOP, DIS_ED_NOP, DIS_ED_NOP, DIS_ED_NOP, +/* 0xcc - 0xcf */ DIS_ED_NOP, DIS_ED_NOP, DIS_ED_NOP, DIS_ED_NOP, + +/* 0xd0 - 0xd3 */ DIS_ED_NOP, DIS_ED_NOP, DIS_ED_NOP, DIS_ED_NOP, +/* 0xd4 - 0xd7 */ DIS_ED_NOP, DIS_ED_NOP, DIS_ED_NOP, DIS_ED_NOP, +/* 0xd8 - 0xdb */ DIS_ED_NOP, DIS_ED_NOP, DIS_ED_NOP, DIS_ED_NOP, +/* 0xdc - 0xdf */ DIS_ED_NOP, DIS_ED_NOP, DIS_ED_NOP, DIS_ED_NOP, + +/* 0xe0 - 0xe3 */ DIS_ED_NOP, DIS_ED_NOP, DIS_ED_NOP, DIS_ED_NOP, +/* 0xe4 - 0xe7 */ DIS_ED_NOP, DIS_ED_NOP, DIS_ED_NOP, DIS_ED_NOP, +/* 0xe8 - 0xeb */ DIS_ED_NOP, DIS_ED_NOP, DIS_ED_NOP, DIS_ED_NOP, +/* 0xec - 0xef */ DIS_ED_NOP, DIS_ED_NOP, DIS_ED_NOP, DIS_ED_NOP, + +/* 0xf0 - 0xf3 */ DIS_ED_NOP, DIS_ED_NOP, DIS_ED_NOP, DIS_ED_NOP, +/* 0xf4 - 0xf7 */ DIS_ED_NOP, DIS_ED_NOP, DIS_ED_NOP, DIS_ED_NOP, +/* 0xf8 - 0xfb */ DIS_ED_NOP, DIS_ED_NOP, DIS_ED_NOP, DIS_ED_NOP, +/* 0xfc - 0xff */ DIS_ED_NOP, DIS_ED_NOP, DIS_ED_NOP, DIS_ED_NOP, + }; + +/* DIS_FD opcodes +*/ +DIS_OP_CALLBACK dis_FD_opcode[0x100]= + { +/* 0x00 - 0x03 */ DIS_FD_NOP, DIS_FD_NOP, DIS_FD_NOP, DIS_FD_NOP, +/* 0x04 - 0x07 */ DIS_FD_NOP, DIS_FD_NOP, DIS_FD_NOP, DIS_FD_NOP, +/* 0x08 - 0x0b */ DIS_FD_NOP, DIS_ADD_IY_BC, DIS_FD_NOP, DIS_FD_NOP, +/* 0x0c - 0x0f */ DIS_FD_NOP, DIS_FD_NOP, DIS_FD_NOP, DIS_FD_NOP, + +/* 0x10 - 0x13 */ DIS_FD_NOP, DIS_FD_NOP, DIS_FD_NOP, DIS_FD_NOP, +/* 0x14 - 0x17 */ DIS_FD_NOP, DIS_FD_NOP, DIS_FD_NOP, DIS_FD_NOP, +/* 0x18 - 0x1b */ DIS_FD_NOP, DIS_ADD_IY_DE, DIS_FD_NOP, DIS_FD_NOP, +/* 0x1c - 0x1f */ DIS_FD_NOP, DIS_FD_NOP, DIS_FD_NOP, DIS_FD_NOP, + +/* 0x20 - 0x23 */ DIS_FD_NOP, DIS_LD_IY_WORD, DIS_LD_ADDR_IY, DIS_INC_IY, +/* 0x24 - 0x27 */ DIS_INC_IYH, DIS_DEC_IYH, DIS_LD_IYH_BYTE, DIS_FD_NOP, +/* 0x28 - 0x2b */ DIS_FD_NOP, DIS_ADD_IY_IY, DIS_LD_IY_ADDR, DIS_DEC_IY, +/* 0x2c - 0x2f */ DIS_INC_IYL, DIS_DEC_IYL, DIS_LD_IYL_BYTE, DIS_FD_NOP, + +/* 0x30 - 0x33 */ DIS_FD_NOP, DIS_FD_NOP, DIS_FD_NOP, DIS_FD_NOP, +/* 0x34 - 0x37 */ DIS_INC_IIY, DIS_DEC_IIY, DIS_LD_IIY_BYTE, DIS_FD_NOP, +/* 0x38 - 0x3b */ DIS_FD_NOP, DIS_ADD_IY_SP, DIS_FD_NOP, DIS_FD_NOP, +/* 0x3c - 0x3f */ DIS_FD_NOP, DIS_FD_NOP, DIS_FD_NOP, DIS_FD_NOP, + +/* 0x40 - 0x43 */ DIS_FD_NOP, DIS_FD_NOP, DIS_FD_NOP, DIS_FD_NOP, +/* 0x44 - 0x47 */ DIS_YLD_R8_R8, DIS_YLD_R8_R8, DIS_YLD_R8_R8, DIS_FD_NOP, +/* 0x48 - 0x4b */ DIS_FD_NOP, DIS_FD_NOP, DIS_FD_NOP, DIS_FD_NOP, +/* 0x4c - 0x4f */ DIS_YLD_R8_R8, DIS_YLD_R8_R8, DIS_YLD_R8_R8, DIS_FD_NOP, + +/* 0x50 - 0x53 */ DIS_FD_NOP, DIS_FD_NOP, DIS_FD_NOP, DIS_FD_NOP, +/* 0x54 - 0x57 */ DIS_YLD_R8_R8, DIS_YLD_R8_R8, DIS_YLD_R8_R8, DIS_FD_NOP, +/* 0x58 - 0x5b */ DIS_FD_NOP, DIS_FD_NOP, DIS_FD_NOP, DIS_FD_NOP, +/* 0x5c - 0x5f */ DIS_YLD_R8_R8, DIS_YLD_R8_R8, DIS_YLD_R8_R8, DIS_FD_NOP, + +/* 0x60 - 0x63 */ DIS_YLD_R8_R8, DIS_YLD_R8_R8, DIS_YLD_R8_R8, DIS_YLD_R8_R8, +/* 0x64 - 0x67 */ DIS_YLD_R8_R8, DIS_YLD_R8_R8, DIS_YLD_R8_R8, DIS_YLD_R8_R8, +/* 0x68 - 0x6b */ DIS_YLD_R8_R8, DIS_YLD_R8_R8, DIS_YLD_R8_R8, DIS_YLD_R8_R8, +/* 0x6c - 0x6f */ DIS_YLD_R8_R8, DIS_YLD_R8_R8, DIS_YLD_R8_R8, DIS_YLD_R8_R8, + +/* 0x70 - 0x73 */ DIS_YLD_R8_R8, DIS_YLD_R8_R8, DIS_YLD_R8_R8, DIS_YLD_R8_R8, +/* 0x74 - 0x77 */ DIS_YLD_R8_R8, DIS_YLD_R8_R8, DIS_FD_NOP, DIS_YLD_R8_R8, +/* 0x78 - 0x7b */ DIS_FD_NOP, DIS_FD_NOP, DIS_FD_NOP, DIS_FD_NOP, +/* 0x7c - 0x7f */ DIS_YLD_R8_R8, DIS_YLD_R8_R8, DIS_YLD_R8_R8, DIS_FD_NOP, + +/* 0x80 - 0x83 */ DIS_FD_NOP, DIS_FD_NOP, DIS_FD_NOP, DIS_FD_NOP, +/* 0x84 - 0x87 */ DIS_YADD_R8, DIS_YADD_R8, DIS_YADD_R8, DIS_FD_NOP, +/* 0x88 - 0x8b */ DIS_FD_NOP, DIS_FD_NOP, DIS_FD_NOP, DIS_FD_NOP, +/* 0x8c - 0x8f */ DIS_YADC_R8, DIS_YADC_R8, DIS_YADC_R8, DIS_FD_NOP, + +/* 0x90 - 0x93 */ DIS_FD_NOP, DIS_FD_NOP, DIS_FD_NOP, DIS_FD_NOP, +/* 0x94 - 0x97 */ DIS_YSUB_R8, DIS_YSUB_R8, DIS_YSUB_R8, DIS_FD_NOP, +/* 0x98 - 0x9b */ DIS_FD_NOP, DIS_FD_NOP, DIS_FD_NOP, DIS_FD_NOP, +/* 0x9c - 0x9f */ DIS_YSBC_R8, DIS_YSBC_R8, DIS_YSBC_R8, DIS_FD_NOP, + +/* 0xa0 - 0xa3 */ DIS_FD_NOP, DIS_FD_NOP, DIS_FD_NOP, DIS_FD_NOP, +/* 0xa4 - 0xa7 */ DIS_YAND_R8, DIS_YAND_R8, DIS_YAND_R8, DIS_FD_NOP, +/* 0xa8 - 0xab */ DIS_FD_NOP, DIS_FD_NOP, DIS_FD_NOP, DIS_FD_NOP, +/* 0xac - 0xaf */ DIS_YYOR_R8, DIS_YYOR_R8, DIS_YYOR_R8, DIS_FD_NOP, + +/* 0xb0 - 0xb3 */ DIS_FD_NOP, DIS_FD_NOP, DIS_FD_NOP, DIS_FD_NOP, +/* 0xb4 - 0xb7 */ DIS_Y_OR_R8, DIS_Y_OR_R8, DIS_Y_OR_R8, DIS_FD_NOP, +/* 0xb8 - 0xbb */ DIS_FD_NOP, DIS_FD_NOP, DIS_FD_NOP, DIS_FD_NOP, +/* 0xbc - 0xbf */ DIS_YCP_R8, DIS_YCP_R8, DIS_YCP_R8, DIS_FD_NOP, + +/* 0xc0 - 0xc3 */ DIS_FD_NOP, DIS_FD_NOP, DIS_FD_NOP, DIS_FD_NOP, +/* 0xc4 - 0xc7 */ DIS_FD_NOP, DIS_FD_NOP, DIS_FD_NOP, DIS_FD_NOP, +/* 0xc8 - 0xcb */ DIS_FD_NOP, DIS_FD_NOP, DIS_FD_NOP, DIS_FD_CB_DECODE, +/* 0xcc - 0xcf */ DIS_FD_NOP, DIS_FD_NOP, DIS_FD_NOP, DIS_FD_NOP, + +/* 0xd0 - 0xd3 */ DIS_FD_NOP, DIS_FD_NOP, DIS_FD_NOP, DIS_FD_NOP, +/* 0xd4 - 0xd7 */ DIS_FD_NOP, DIS_FD_NOP, DIS_FD_NOP, DIS_FD_NOP, +/* 0xd8 - 0xdb */ DIS_FD_NOP, DIS_FD_NOP, DIS_FD_NOP, DIS_FD_NOP, +/* 0xdc - 0xdf */ DIS_FD_NOP, DIS_FD_DD_DECODE, DIS_FD_NOP, DIS_FD_NOP, + +/* 0xe0 - 0xe3 */ DIS_FD_NOP, DIS_POP_IY, DIS_FD_NOP, DIS_EY_ISP_IY, +/* 0xe4 - 0xe7 */ DIS_FD_NOP, DIS_PUSH_IY, DIS_FD_NOP, DIS_FD_NOP, +/* 0xe8 - 0xeb */ DIS_FD_NOP, DIS_JP_IY, DIS_FD_NOP, DIS_FD_NOP, +/* 0xec - 0xef */ DIS_FD_NOP, DIS_FD_ED_DECODE, DIS_FD_NOP, DIS_FD_NOP, + +/* 0xf0 - 0xf3 */ DIS_FD_NOP, DIS_FD_NOP, DIS_FD_NOP, DIS_FD_NOP, +/* 0xf4 - 0xf7 */ DIS_FD_NOP, DIS_FD_NOP, DIS_FD_NOP, DIS_FD_NOP, +/* 0xf8 - 0xfb */ DIS_FD_NOP, DIS_LD_SP_IY, DIS_FD_NOP, DIS_FD_NOP, +/* 0xfc - 0xff */ DIS_FD_NOP, DIS_FD_FD_DECODE, DIS_FD_NOP, DIS_FD_NOP, + }; + + +/* DIS_FD DIS_CB opcodes +*/ +DIS_OP_CALLBACK dis_FD_CB_opcode[0x100]= + { +/* 0x00 - 0x03 */ DIS_RLC_IY, DIS_RLC_IY, DIS_RLC_IY, DIS_RLC_IY, +/* 0x04 - 0x07 */ DIS_RLC_IY, DIS_RLC_IY, DIS_RLC_IY, DIS_RLC_IY, +/* 0x08 - 0x0b */ DIS_RRC_IY, DIS_RRC_IY, DIS_RRC_IY, DIS_RRC_IY, +/* 0x0c - 0x0f */ DIS_RRC_IY, DIS_RRC_IY, DIS_RRC_IY, DIS_RRC_IY, + +/* 0x10 - 0x13 */ DIS_RL_IY, DIS_RL_IY, DIS_RL_IY, DIS_RL_IY, +/* 0x14 - 0x17 */ DIS_RL_IY, DIS_RL_IY, DIS_RL_IY, DIS_RL_IY, +/* 0x18 - 0x1b */ DIS_RR_IY, DIS_RR_IY, DIS_RR_IY, DIS_RR_IY, +/* 0x1c - 0x1f */ DIS_RR_IY, DIS_RR_IY, DIS_RR_IY, DIS_RR_IY, + +/* 0x20 - 0x23 */ DIS_SLA_IY, DIS_SLA_IY, DIS_SLA_IY, DIS_SLA_IY, +/* 0x24 - 0x27 */ DIS_SLA_IY, DIS_SLA_IY, DIS_SLA_IY, DIS_SLA_IY, +/* 0x28 - 0x2b */ DIS_SRA_IY, DIS_SRA_IY, DIS_SRA_IY, DIS_SRA_IY, +/* 0x2c - 0x2f */ DIS_SRA_IY, DIS_SRA_IY, DIS_SRA_IY, DIS_SRA_IY, + +/* 0x30 - 0x33 */ DIS_SLL_IY, DIS_SLL_IY, DIS_SLL_IY, DIS_SLL_IY, +/* 0x34 - 0x37 */ DIS_SLL_IY, DIS_SLL_IY, DIS_SLL_IY, DIS_SLL_IY, +/* 0x38 - 0x3b */ DIS_SRL_IY, DIS_SRL_IY, DIS_SRL_IY, DIS_SRL_IY, +/* 0x3c - 0x3f */ DIS_SRL_IY, DIS_SRL_IY, DIS_SRL_IY, DIS_SRL_IY, + +/* 0x40 - 0x43 */ DIS_BIT_IY,DIS_BIT_IY, DIS_BIT_IY, DIS_BIT_IY, +/* 0x44 - 0x47 */ DIS_BIT_IY,DIS_BIT_IY, DIS_BIT_IY, DIS_BIT_IY, +/* 0x48 - 0x4b */ DIS_BIT_IY,DIS_BIT_IY, DIS_BIT_IY, DIS_BIT_IY, +/* 0x4c - 0x4f */ DIS_BIT_IY,DIS_BIT_IY, DIS_BIT_IY, DIS_BIT_IY, + +/* 0x50 - 0x53 */ DIS_BIT_IY,DIS_BIT_IY, DIS_BIT_IY, DIS_BIT_IY, +/* 0x54 - 0x57 */ DIS_BIT_IY,DIS_BIT_IY, DIS_BIT_IY, DIS_BIT_IY, +/* 0x58 - 0x5b */ DIS_BIT_IY,DIS_BIT_IY, DIS_BIT_IY, DIS_BIT_IY, +/* 0x5c - 0x5f */ DIS_BIT_IY,DIS_BIT_IY, DIS_BIT_IY, DIS_BIT_IY, + +/* 0x60 - 0x63 */ DIS_BIT_IY,DIS_BIT_IY, DIS_BIT_IY, DIS_BIT_IY, +/* 0x64 - 0x67 */ DIS_BIT_IY,DIS_BIT_IY, DIS_BIT_IY, DIS_BIT_IY, +/* 0x68 - 0x6b */ DIS_BIT_IY,DIS_BIT_IY, DIS_BIT_IY, DIS_BIT_IY, +/* 0x6c - 0x6f */ DIS_BIT_IY,DIS_BIT_IY, DIS_BIT_IY, DIS_BIT_IY, + +/* 0x70 - 0x73 */ DIS_BIT_IY,DIS_BIT_IY, DIS_BIT_IY, DIS_BIT_IY, +/* 0x74 - 0x77 */ DIS_BIT_IY,DIS_BIT_IY, DIS_BIT_IY, DIS_BIT_IY, +/* 0x78 - 0x7b */ DIS_BIT_IY,DIS_BIT_IY, DIS_BIT_IY, DIS_BIT_IY, +/* 0x7c - 0x7f */ DIS_BIT_IY,DIS_BIT_IY, DIS_BIT_IY, DIS_BIT_IY, + +/* 0x80 - 0x83 */ DIS_RES_IY,DIS_RES_IY, DIS_RES_IY, DIS_RES_IY, +/* 0x84 - 0x87 */ DIS_RES_IY,DIS_RES_IY, DIS_RES_IY, DIS_RES_IY, +/* 0x88 - 0x8b */ DIS_RES_IY,DIS_RES_IY, DIS_RES_IY, DIS_RES_IY, +/* 0x8c - 0x8f */ DIS_RES_IY,DIS_RES_IY, DIS_RES_IY, DIS_RES_IY, + +/* 0x90 - 0x93 */ DIS_RES_IY,DIS_RES_IY, DIS_RES_IY, DIS_RES_IY, +/* 0x94 - 0x97 */ DIS_RES_IY,DIS_RES_IY, DIS_RES_IY, DIS_RES_IY, +/* 0x98 - 0x9b */ DIS_RES_IY,DIS_RES_IY, DIS_RES_IY, DIS_RES_IY, +/* 0x9c - 0x9f */ DIS_RES_IY,DIS_RES_IY, DIS_RES_IY, DIS_RES_IY, + +/* 0xa0 - 0xa3 */ DIS_RES_IY,DIS_RES_IY, DIS_RES_IY, DIS_RES_IY, +/* 0xa4 - 0xa7 */ DIS_RES_IY,DIS_RES_IY, DIS_RES_IY, DIS_RES_IY, +/* 0xa8 - 0xab */ DIS_RES_IY,DIS_RES_IY, DIS_RES_IY, DIS_RES_IY, +/* 0xac - 0xaf */ DIS_RES_IY,DIS_RES_IY, DIS_RES_IY, DIS_RES_IY, + +/* 0xb0 - 0xb3 */ DIS_RES_IY,DIS_RES_IY, DIS_RES_IY, DIS_RES_IY, +/* 0xb4 - 0xb7 */ DIS_RES_IY,DIS_RES_IY, DIS_RES_IY, DIS_RES_IY, +/* 0xb8 - 0xbb */ DIS_RES_IY,DIS_RES_IY, DIS_RES_IY, DIS_RES_IY, +/* 0xbc - 0xbf */ DIS_RES_IY,DIS_RES_IY, DIS_RES_IY, DIS_RES_IY, + +/* 0xc0 - 0xc3 */ DIS_SET_IY,DIS_SET_IY, DIS_SET_IY, DIS_SET_IY, +/* 0xc4 - 0xc7 */ DIS_SET_IY,DIS_SET_IY, DIS_SET_IY, DIS_SET_IY, +/* 0xc8 - 0xcb */ DIS_SET_IY,DIS_SET_IY, DIS_SET_IY, DIS_SET_IY, +/* 0xcc - 0xcf */ DIS_SET_IY,DIS_SET_IY, DIS_SET_IY, DIS_SET_IY, + +/* 0xd0 - 0xd3 */ DIS_SET_IY,DIS_SET_IY, DIS_SET_IY, DIS_SET_IY, +/* 0xd4 - 0xd7 */ DIS_SET_IY,DIS_SET_IY, DIS_SET_IY, DIS_SET_IY, +/* 0xd8 - 0xdb */ DIS_SET_IY,DIS_SET_IY, DIS_SET_IY, DIS_SET_IY, +/* 0xdc - 0xdf */ DIS_SET_IY,DIS_SET_IY, DIS_SET_IY, DIS_SET_IY, + +/* 0xe0 - 0xe3 */ DIS_SET_IY,DIS_SET_IY, DIS_SET_IY, DIS_SET_IY, +/* 0xe4 - 0xe7 */ DIS_SET_IY,DIS_SET_IY, DIS_SET_IY, DIS_SET_IY, +/* 0xe8 - 0xeb */ DIS_SET_IY,DIS_SET_IY, DIS_SET_IY, DIS_SET_IY, +/* 0xec - 0xef */ DIS_SET_IY,DIS_SET_IY, DIS_SET_IY, DIS_SET_IY, + +/* 0xf0 - 0xf3 */ DIS_SET_IY,DIS_SET_IY, DIS_SET_IY, DIS_SET_IY, +/* 0xf4 - 0xf7 */ DIS_SET_IY,DIS_SET_IY, DIS_SET_IY, DIS_SET_IY, +/* 0xf8 - 0xfb */ DIS_SET_IY,DIS_SET_IY, DIS_SET_IY, DIS_SET_IY, +/* 0xfc - 0xff */ DIS_SET_IY,DIS_SET_IY, DIS_SET_IY, DIS_SET_IY, + }; + +/* DIS_First/single byte opcodes +*/ +DIS_OP_CALLBACK dis_opcode_z80[0x100]= + { +/* 0x00 - 0x03 */ DIS_NOP, DIS_LD_R16_WORD, DIS_LD_R16_A, DIS_INC_R16, +/* 0x04 - 0x07 */ DIS_INC_R8, DIS_DEC_R8, DIS_LD_R8_BYTE, DIS_RLCA, +/* 0x08 - 0x0b */ DIS_EX_AF_AF, DIS_ADD_HL_R16, DIS_LD_A_R16, DIS_DEC_R16, +/* 0x0c - 0x0f */ DIS_INC_R8, DIS_DEC_R8, DIS_LD_R8_BYTE, DIS_RRCA, + +/* 0x10 - 0x13 */ DIS_DJNZ, DIS_LD_R16_WORD, DIS_LD_R16_A, DIS_INC_R16, +/* 0x14 - 0x17 */ DIS_INC_R8, DIS_DEC_R8, DIS_LD_R8_BYTE, DIS_RLA, +/* 0x18 - 0x1b */ DIS_JR, DIS_ADD_HL_R16, DIS_LD_A_R16, DIS_DEC_R16, +/* 0x1c - 0x1f */ DIS_INC_R8, DIS_DEC_R8, DIS_LD_R8_BYTE, DIS_RRA, + +/* 0x20 - 0x23 */ DIS_JR_CO, DIS_LD_R16_WORD, DIS_LD_ADDR_HL, DIS_INC_R16, +/* 0x24 - 0x27 */ DIS_INC_R8, DIS_DEC_R8, DIS_LD_R8_BYTE, DIS_DAA, +/* 0x28 - 0x2b */ DIS_JR_CO, DIS_ADD_HL_R16, DIS_LD_HL_ADDR, DIS_DEC_R16, +/* 0x2c - 0x2f */ DIS_INC_R8, DIS_DEC_R8, DIS_LD_R8_BYTE, DIS_CPL, + +/* 0x30 - 0x33 */ DIS_JR_CO, DIS_LD_R16_WORD, DIS_LD_ADDR_A, DIS_INC_R16, +/* 0x34 - 0x37 */ DIS_INC_R8, DIS_DEC_R8, DIS_LD_R8_BYTE, DIS_SCF, +/* 0x38 - 0x3b */ DIS_JR_CO, DIS_ADD_HL_R16, DIS_LD_A_ADDR, DIS_DEC_R16, +/* 0x3c - 0x3f */ DIS_INC_R8, DIS_DEC_R8, DIS_LD_R8_BYTE, DIS_CCF, + +/* 0x40 - 0x43 */ DIS_LD_R8_R8, DIS_LD_R8_R8, DIS_LD_R8_R8, DIS_LD_R8_R8, +/* 0x44 - 0x47 */ DIS_LD_R8_R8, DIS_LD_R8_R8, DIS_LD_R8_R8, DIS_LD_R8_R8, +/* 0x48 - 0x4b */ DIS_LD_R8_R8, DIS_LD_R8_R8, DIS_LD_R8_R8, DIS_LD_R8_R8, +/* 0x4c - 0x4f */ DIS_LD_R8_R8, DIS_LD_R8_R8, DIS_LD_R8_R8, DIS_LD_R8_R8, + +/* 0x50 - 0x53 */ DIS_LD_R8_R8, DIS_LD_R8_R8, DIS_LD_R8_R8, DIS_LD_R8_R8, +/* 0x54 - 0x57 */ DIS_LD_R8_R8, DIS_LD_R8_R8, DIS_LD_R8_R8, DIS_LD_R8_R8, +/* 0x58 - 0x5b */ DIS_LD_R8_R8, DIS_LD_R8_R8, DIS_LD_R8_R8, DIS_LD_R8_R8, +/* 0x5c - 0x5f */ DIS_LD_R8_R8, DIS_LD_R8_R8, DIS_LD_R8_R8, DIS_LD_R8_R8, + +/* 0x60 - 0x63 */ DIS_LD_R8_R8, DIS_LD_R8_R8, DIS_LD_R8_R8, DIS_LD_R8_R8, +/* 0x64 - 0x67 */ DIS_LD_R8_R8, DIS_LD_R8_R8, DIS_LD_R8_R8, DIS_LD_R8_R8, +/* 0x68 - 0x6b */ DIS_LD_R8_R8, DIS_LD_R8_R8, DIS_LD_R8_R8, DIS_LD_R8_R8, +/* 0x6c - 0x6f */ DIS_LD_R8_R8, DIS_LD_R8_R8, DIS_LD_R8_R8, DIS_LD_R8_R8, + +/* 0x70 - 0x73 */ DIS_LD_R8_R8, DIS_LD_R8_R8, DIS_LD_R8_R8, DIS_LD_R8_R8, +/* 0x74 - 0x77 */ DIS_LD_R8_R8, DIS_LD_R8_R8, DIS_HALT, DIS_LD_R8_R8, +/* 0x78 - 0x7b */ DIS_LD_R8_R8, DIS_LD_R8_R8, DIS_LD_R8_R8, DIS_LD_R8_R8, +/* 0x7c - 0x7f */ DIS_LD_R8_R8, DIS_LD_R8_R8, DIS_LD_R8_R8, DIS_LD_R8_R8, + +/* 0x80 - 0x83 */ DIS_ADD_R8, DIS_ADD_R8, DIS_ADD_R8, DIS_ADD_R8, +/* 0x84 - 0x87 */ DIS_ADD_R8, DIS_ADD_R8, DIS_ADD_R8, DIS_ADD_R8, +/* 0x88 - 0x8b */ DIS_ADC_R8, DIS_ADC_R8, DIS_ADC_R8, DIS_ADC_R8, +/* 0x8c - 0x8f */ DIS_ADC_R8, DIS_ADC_R8, DIS_ADC_R8, DIS_ADC_R8, + +/* 0x90 - 0x93 */ DIS_SUB_R8, DIS_SUB_R8, DIS_SUB_R8, DIS_SUB_R8, +/* 0x94 - 0x97 */ DIS_SUB_R8, DIS_SUB_R8, DIS_SUB_R8, DIS_SUB_R8, +/* 0x98 - 0x9b */ DIS_SBC_R8, DIS_SBC_R8, DIS_SBC_R8, DIS_SBC_R8, +/* 0x9c - 0x9f */ DIS_SBC_R8, DIS_SBC_R8, DIS_SBC_R8, DIS_SBC_R8, + +/* 0xa0 - 0xa3 */ DIS_AND_R8, DIS_AND_R8, DIS_AND_R8, DIS_AND_R8, +/* 0xa4 - 0xa7 */ DIS_AND_R8, DIS_AND_R8, DIS_AND_R8, DIS_AND_R8, +/* 0xa8 - 0xab */ DIS_XOR_R8, DIS_XOR_R8, DIS_XOR_R8, DIS_XOR_R8, +/* 0xac - 0xaf */ DIS_XOR_R8, DIS_XOR_R8, DIS_XOR_R8, DIS_XOR_R8, + +/* 0xb0 - 0xb3 */ DIS_OR_R8, DIS_OR_R8, DIS_OR_R8, DIS_OR_R8, +/* 0xb4 - 0xb7 */ DIS_OR_R8, DIS_OR_R8, DIS_OR_R8, DIS_OR_R8, +/* 0xb8 - 0xbb */ DIS_CP_R8, DIS_CP_R8, DIS_CP_R8, DIS_CP_R8, +/* 0xbc - 0xbf */ DIS_CP_R8, DIS_CP_R8, DIS_CP_R8, DIS_CP_R8, + +/* 0xc0 - 0xc3 */ DIS_RET_CO, DIS_POP_R16, DIS_JP_CO, DIS_JP, +/* 0xc4 - 0xc7 */ DIS_CALL_CO, DIS_PUSH_R16, DIS_ADD_A_BYTE, DIS_RST, +/* 0xc8 - 0xcb */ DIS_RET_CO, DIS_RET, DIS_JP_CO, DIS_CB_DECODE, +/* 0xcc - 0xcf */ DIS_CALL_CO, DIS_CALL, DIS_ADC_A_BYTE, DIS_RST, + +/* 0xd0 - 0xd3 */ DIS_RET_CO, DIS_POP_R16, DIS_JP_CO, DIS_OUT_BYTE_A, +/* 0xd4 - 0xd7 */ DIS_CALL_CO, DIS_PUSH_R16, DIS_SUB_A_BYTE, DIS_RST, +/* 0xd8 - 0xdb */ DIS_RET_CO, DIS_EXX, DIS_JP_CO, DIS_IN_A_BYTE, +/* 0xdc - 0xdf */ DIS_CALL_CO, DIS_DD_DECODE, DIS_SBC_A_BYTE, DIS_RST, + +/* 0xe0 - 0xe3 */ DIS_RET_CO, DIS_POP_R16, DIS_JP_CO, DIS_EX_ISP_HL, +/* 0xe4 - 0xe7 */ DIS_CALL_CO, DIS_PUSH_R16, DIS_AND_A_BYTE, DIS_RST, +/* 0xe8 - 0xeb */ DIS_RET_CO, DIS_JP_HL, DIS_JP_CO, DIS_EX_DE_HL, +/* 0xec - 0xef */ DIS_CALL_CO, DIS_ED_DECODE, DIS_XOR_A_BYTE, DIS_RST, + +/* 0xf0 - 0xf3 */ DIS_RET_CO, DIS_POP_R16, DIS_JP_CO, DIS_DI, +/* 0xf4 - 0xf7 */ DIS_CALL_CO, DIS_PUSH_R16, DIS_OR_A_BYTE, DIS_RST, +/* 0xf8 - 0xfb */ DIS_RET_CO, DIS_LD_SP_HL, DIS_JP_CO, DIS_EI, +/* 0xfc - 0xff */ DIS_CALL_CO, DIS_FD_DECODE, DIS_CP_A_BYTE, DIS_RST, + }; + + +#endif + +/* END OF FILE */ diff --git a/source/zx81.c b/source/zx81.c new file mode 100644 index 0000000..7aa5380 --- /dev/null +++ b/source/zx81.c @@ -0,0 +1,1171 @@ +/* + ds81 - Nintendo DS ZX81 emulator + + Copyright (C) 2006 Ian Cowburn <ianc@noddybox.co.uk> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + 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. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + ------------------------------------------------------------------------- + + Provides the emulation for the ZX81 + +*/ +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <ctype.h> +#include <nds.h> + +#include "zx81.h" +#include "gui.h" + +#include "stream.h" + +#include "config.h" + +#include "zx81_bin.h" + +#include "ds81_debug.h" + +#ifndef TRUE +#define TRUE 1 +#endif + +#ifndef FALSE +#define FALSE 0 +#endif + +/* ---------------------------------------- STATICS +*/ +#define ROMLEN 0x2000 +#define ROM_SAVE 0x2fc +#define ROM_LOAD 0x347 + +#define ED_SAVE 0xf0 +#define ED_LOAD 0xf1 +#define ED_WAITKEY 0xf2 +#define ED_ENDWAITKEY 0xf3 +#define ED_PAUSE 0xf4 + +#define SLOW_TSTATES 16000 +#define FAST_TSTATES 64000 + +#define E_LINE 16404 +#define LASTK1 16421 +#define LASTK2 16422 +#define MARGIN 16424 +#define FRAMES 16436 +#define CDFLAG 16443 + +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; + +static unsigned prev_lk1; +static unsigned prev_lk2; + +#define SCR_W 256 +#define SCR_H 192 +#define TXT_W 32 +#define TXT_H 24 + +static Z80Byte mem[0x10000]; + +static Z80Byte scr_mirror[7000]; + +static Z80Word RAMBOT=0; +static Z80Word RAMTOP=0; + +#define DFILE 0x400c + +#define WORD(a) (mem[a] | (Z80Word)mem[a+1]<<8) + +/* Tape +*/ +static int enable_filesystem; +static int allow_save; +static const Z80Byte *tape_image; +static int tape_len; + +static char last_dir[FILENAME_MAX] = "/"; + +/* GFX vars +*/ +static uint16 *txt_screen; +static uint16 *bmp_screen; + +/* The keyboard +*/ +static Z80Byte matrix[8]; + +static struct +{ + int row; + int bit; +} key_matrix[]= + { + {3,0x01}, {3,0x02}, {3,0x04}, {3,0x08}, {3,0x10}, /* 1 - 5 */ + {4,0x10}, {4,0x08}, {4,0x04}, {4,0x02}, {4,0x01}, /* 6 - 0 */ + {2,0x01}, {2,0x02}, {2,0x04}, {2,0x08}, {2,0x10}, /* Q - T */ + {5,0x10}, {5,0x08}, {5,0x04}, {5,0x02}, {5,0x01}, /* Y - P */ + {1,0x01}, {1,0x02}, {1,0x04}, {1,0x08}, {1,0x10}, /* A - G */ + {6,0x10}, {6,0x08}, {6,0x04}, {6,0x02}, {6,0x01}, /* H - NL */ + {0,0x01}, {0,0x02}, {0,0x04}, {0,0x08}, {0,0x10}, /* CAPS - V */ + {7,0x10}, {7,0x08}, {7,0x04}, {7,0x02}, {7,0x01} /* B - SPACE */ + }; + + +/* ---------------------------------------- PRIVATE FUNCTIONS +*/ +#define PEEKW(addr) (mem[addr] | (Z80Word)mem[addr+1]<<8) + +#define POKEW(addr,val) do \ + { \ + Z80Word wa=addr; \ + Z80Word wv=val; \ + mem[wa]=wv; \ + mem[wa+1]=wv>>8; \ + } while(0) + +static void RomPatch(void) +{ + static const Z80Byte save[]= + { + 0xed, ED_SAVE, /* (SAVE) */ + 0xc3, 0x07, 0x02, /* JP $0207 */ + 0xff /* End of patch */ + }; + + static const Z80Byte load[]= + { + 0xed, ED_LOAD, /* (LOAD) */ + 0xc3, 0x07, 0x02, /* JP $0207 */ + 0xff /* End of patch */ + }; + + static const Z80Byte fast_hack[]= + { + 0xed, ED_WAITKEY, /* (START KEY WAIT) */ + 0xcb,0x46, /* L: bit 0,(hl) */ + 0x28,0xfc, /* jr z,L */ + 0xed, ED_ENDWAITKEY, /* (END KEY WAIT) */ + 0x00, /* nop */ + 0xff /* End of patch */ + }; + + static const Z80Byte kbd_hack[]= + { + 0x2a,0x25,0x40, /* ld hl,(LASTK) */ + 0xc9, /* ret */ + 0xff /* End of patch */ + }; + + static const Z80Byte pause_hack[]= + { + 0xed, ED_PAUSE, /* (PAUSE) */ + 0x00, /* nop */ + 0xff /* End of patch */ + }; + + int f; + + for(f=0;save[f]!=0xff;f++) + { + mem[ROM_SAVE+f]=save[f]; + } + + for(f=0;load[f]!=0xff;f++) + { + mem[ROM_LOAD+f]=load[f]; + } + + for(f=0;fast_hack[f]!=0xff;f++) + { + mem[0x4ca+f]=fast_hack[f]; + } + + for(f=0;kbd_hack[f]!=0xff;f++) + { + mem[0x2bb+f]=kbd_hack[f]; + } + + for(f=0;pause_hack[f]!=0xff;f++) + { + mem[0xf3a+f]=pause_hack[f]; + } + + /* Trust me, we have a ZX81... Honestly. + */ + mem[0x21c]=0x00; + mem[0x21d]=0x00; + + /* Remove HALTs as we don't do interrupts + */ + mem[0x0079]=0; + mem[0x02ec]=0; +} + +static Z80Byte FromASCII(char c) +{ + static const char *charset = + /* 0123456789 */ + " _________" + "_\"#$:?()><" + "=+-*/:,.01" + "23456789ab" + "cdefghijkl" + "mnopqrstuv" + "wxyz"; + + int f; + + c = tolower(c); + + for(f = 0; charset[f]; f++) + { + if (charset[f] == c) + { + return f; + } + } + + return 0; +} + + +/* Open a tape file the passed address +*/ +static FILE *OpenTapeFile(Z80Word addr, int *cancelled, const char *mode) +{ + static const char zx_chars[] = "\"#$:?()><=+-*/;,." + "0123456789" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + FILE *fp; + char full_fn[FILENAME_MAX] = DEFAULT_SNAPDIR; + char fn[FILENAME_MAX]; + int f; + int done; + + fp = NULL; + f = 0; + done = FALSE; + *cancelled = FALSE; + + while(f<(FILENAME_MAX-3) && !done) + { + int ch; + + ch = mem[addr++]; + + if (ch&0x80) + { + done = TRUE; + ch &= 0x7f; + } + + if (ch>=11 && ch<=63) + { + fn[f++] = zx_chars[ch-11]; + } + } + + if (fn[0] == '*') + { + if (GUI_FileSelect(last_dir,fn,".P")) + { + fp = fopen(fn, mode); + } + else + { + *cancelled = TRUE; + } + + SK_DisplayKeyboard(); + } + else + { + fn[f++] = '.'; + fn[f++] = 'P'; + fn[f] = 0; + + strcat(full_fn,fn); + + if (!(fp = fopen(full_fn, mode))) + { + fp = fopen(fn, mode); + } + } + + return fp; +} + + +static void LoadInternalTape(Z80 *z80) +{ + memcpy(mem+0x4009,tape_image,tape_len); +} + + +static void LoadExternalTape(FILE *tape, Z80 *z80) +{ + int c; + Z80Byte *a; + + a=mem+0x4009; + + while((c=getc(tape))!=EOF) + { + *a++=c; + } +} + + +static void SaveExternalTape(FILE *tape, Z80 *z80) +{ + int f; + int end; + + f = 0x4009; + end = WORD(E_LINE); + + while(f <= end) + { + fputc(mem[f++], tape); + } +} + + +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_Dirty(Z80 *z80) +{ + uint16 *bmp; + Z80Byte *scr; + Z80Byte *mirror; + int x,y; + int table; + int c; + int v; + int b; + + scr = mem + hires_dfile; + mirror = scr_mirror; + bmp = bmp_screen; + table = z80->I << 8; + + /* scr is increment in both loops so that it can skip the end-of-line + character + */ + for(y=0; y<192; y++) + { + for(x=0; x<32; x++) + { + c = *scr; + + if (c != *mirror) + { + *mirror++ = c; + + 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; + } + } + else + { + mirror++; + bmp+=8; + } + + scr++; + } + + scr++; + } +} + + +static void DrawScreen_HIRES_Full(Z80 *z80) +{ + uint16 *bmp; + Z80Byte *scr; + Z80Byte *mirror; + int x,y; + int table; + + scr = mem + hires_dfile; + mirror = scr_mirror; + bmp = bmp_screen; + table = z80->I << 8; + + /* scr is increment in both loops so that it can skip the end-of-line + character + */ + for(y=0; y<192; y++) + { + for(x=0; x<32; x++) + { + int c; + int v; + int b; + + c = *mirror++ = *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++; + } + + DrawScreen = DrawScreen_HIRES_Dirty; +} + + +static void DrawScreen_TEXT(Z80 *z80) +{ + Z80Byte *scr=mem+WORD(DFILE); + int x,y; + + x=0; + y=0; + + while(y<TXT_H) + { + scr++; + x=0; + + while((*scr!=118)&&(x<TXT_W)) + { + Z80Byte ch = *scr++; + + if (ch&0x80) + { + txt_screen[x+y*32]=(ch&0x3f)|0x40; + } + else + { + txt_screen[x+y*32]=(ch&0x3f); + } + + x++; + } + + while (x<TXT_W) + { + txt_screen[x+y*32]=0; + x++; + } + + y++; + } +} + + +static void DrawSnow(Z80 *z80) +{ + uint16 *s; + int f; + + s = txt_screen; + + for(f=0;f<TXT_W*TXT_H;f++) + { + *s++=8; + } +} + + +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) +{ + unsigned row; + unsigned lastk1; + unsigned lastk2; + + /* British ZX81 + */ + mem[MARGIN]=55; + + /* Update FRAMES + */ + if (FRAME_TSTATES==SLOW_TSTATES) + { + Z80Word frame=PEEKW(FRAMES)&0x7fff; + + if (frame) + { + frame--; + } + + POKEW(FRAMES,frame|0x8000); + } + + if (!started) + { + prev_lk1=0; + prev_lk2=0; + return; + } + + /* Update LASTK + */ + lastk1=0; + lastk2=0; + + for(row=0;row<8;row++) + { + unsigned b; + + b=(~matrix[row]&0x1f)<<1; + + if (row==0) + { + unsigned shift; + + shift=b&2; + b&=~2; + b|=(shift>>1); + } + + if (b) + { + if (b>1) + { + lastk1|=(1<<row); + } + + lastk2|=b; + } + } + + if (lastk1 && (lastk1!=prev_lk1 || lastk2!=prev_lk2)) + { + mem[CDFLAG]|=1; + } + else + { + mem[CDFLAG]&=~1; + } + + mem[LASTK1]=lastk1^0xff; + mem[LASTK2]=lastk2^0xff; + + prev_lk1=lastk1; + prev_lk2=lastk2; +} + + +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_Full; + ClearBitmap(); + ClearText(); + FindHiresDFILE(); + } + } + + Z80ResetCycles(z80,val-FRAME_TSTATES); + + /* 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; + } + else + { + DrawSnow(z80); + FRAME_TSTATES=FAST_TSTATES; + } + + /* Update FRAMES (if in SLOW) and scan the keyboard. This only happens + once we've got to a decent point in the boot cycle (detected with + a valid stack pointer). + */ + if (z80->SP<0x8000) + { + ZX81HouseKeeping(z80); + } + + swiWaitForVBlank(); + + return FALSE; + } + else + { + return TRUE; + } +} + + +static int EDCallback(Z80 *z80, Z80Val data) +{ + Z80Word pause; + + switch((Z80Byte)data) + { + case ED_SAVE: + if (allow_save && z80->DE.w<0x8000) + { + FILE *fp; + int cancel; + + if ((fp=OpenTapeFile(z80->HL.w, &cancel, "wb"))) + { + SaveExternalTape(fp,z80); + fclose(fp); + } + } + break; + + case ED_LOAD: + /* Try and load the external file if a name given. Otherwise, we + try the internal one. Some of this is slightly dodgy -- it was + never intended for the emulator to be doing any GUI related + nonsense (like the alerts) but simply emulating. + */ + if (enable_filesystem && z80->DE.w<0x8000) + { + FILE *fp; + int cancel; + + if ((fp=OpenTapeFile(z80->DE.w, &cancel, "rb"))) + { + LoadExternalTape(fp,z80); + fclose(fp); + } + else + { + if (!cancel) + { + GUI_Alert(FALSE,"Couldn't open tape"); + SK_DisplayKeyboard(); + } + } + } + else + { + if (tape_image) + { + LoadInternalTape(z80); + } + else + { + GUI_Alert(FALSE,"No tape image selected"); + SK_DisplayKeyboard(); + } + } + + mem[CDFLAG]=0xc0; + break; + + case ED_WAITKEY: + waitkey=TRUE; + started=TRUE; + break; + + case ED_ENDWAITKEY: + waitkey=FALSE; + break; + + case ED_PAUSE: + waitkey=TRUE; + + pause=z80->BC.w; + + while(pause-- && !(mem[CDFLAG]&1)) + { + SoftKeyEvent ev; + + while (SK_GetEvent(&ev)) + { + ZX81HandleKey(ev.key,ev.pressed); + } + + CheckTimers(z80,FRAME_TSTATES); + } + + waitkey=FALSE; + break; + + default: + break; + } + + return TRUE; +} + + +/* ---------------------------------------- EXPORTED INTERFACES +*/ +void ZX81Init(uint16 *text_vram, uint16* bitmap_vram, Z80 *z80) +{ + Z80Word f; + + txt_screen = text_vram; + bmp_screen = bitmap_vram; + + hires = FALSE; + hires_dfile = 0; + last_I = 0x1e; + DrawScreen = DrawScreen_TEXT; + + ClearBitmap(); + + /* Load the ROM + */ + memcpy(mem,zx81_bin,ROMLEN); + + /* Patch the ROM + */ + RomPatch(); + Z80LodgeCallback(z80,eZ80_EDHook,EDCallback); + Z80LodgeCallback(z80,eZ80_Instruction,CheckTimers); + + /* Mirror the ROM + */ + memcpy(mem+ROMLEN,mem,ROMLEN); + + /* Memory size (16K) + */ + RAMBOT=0x4000; + RAMTOP=RAMBOT+0x4000; + + for(f = RAMBOT; f <= RAMTOP; f++) + { + mem[f] = 0; + } + + for(f = 0; f < 8; f++) + { + matrix[f] = 0x1f; + } + + /* Fill the upper 32K with RET opcodes -- hopefully by simply returning + RET for ULA reads we save a lot of ROM patching shenanigans. + + Note that this check used to be in ZX81ReadMem, but obviously this + should cut down on a *lot* of pointless expression evaluation! + */ + for(f = 0x8000; f <= RAMTOP; f++) + { + mem[f] = 0xc9; + } + +} + + +void ZX81HandleKey(SoftKey key, int is_pressed) +{ + if (key<SK_CONFIG) + { + if (is_pressed) + { + matrix[key_matrix[key].row]&=~key_matrix[key].bit; + } + else + { + matrix[key_matrix[key].row]|=key_matrix[key].bit; + } + } + else + { + /* TODO: Joysticks? Were there any common ones for the 81? */ + } +} + + +Z80Byte ZX81ReadMem(Z80 *z80, Z80Word addr) +{ + return mem[addr]; +} + + +void ZX81WriteMem(Z80 *z80, Z80Word addr, Z80Byte val) +{ + if (addr>=RAMBOT && addr<=RAMTOP) + { + mem[addr]=val; + } +} + + +Z80Byte ZX81ReadPort(Z80 *z80, Z80Word port) +{ + Z80Byte b=0; + + 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; + } + + /* Some code expects some of the top bits set... Of course, whether + or not this may be worse as other code doesn't expect the bits, + we shall find out! + */ + b |= 0x60; + + break; + + default: + b = 0xff; /* Idle bus */ + break; + } + + return b; +} + + +void ZX81WritePort(Z80 *z80, Z80Word port, Z80Byte val) +{ + switch(port&0xff) + { + case 0xfd: + break; + + case 0xfe: + break; + } +} + + +void ZX81Reset(Z80 *z80) +{ + int f; + + for(f=0;f<8;f++) + matrix[f]=0x1f; + + Z80Reset(z80); + Z80ResetCycles(z80,0); + + started=FALSE; + + hires = FALSE; + hires_dfile = 0; + last_I = 0x1e; + DrawScreen = DrawScreen_TEXT; + + ClearBitmap(); +} + + +void ZX81EnableFileSystem(int enable) +{ + enable_filesystem=enable; +} + + +void ZX81SetTape(const Z80Byte *image, int len) +{ + tape_image=image; + tape_len=len; +} + + +void ZX81SuspendDisplay(void) +{ + ClearBitmap(); + ClearText(); +} + + +void ZX81ResumeDisplay(void) +{ + ClearText(); + + /* Reset last_I to force hi/lo res detection + */ + last_I = 0; +} + + +void ZX81DisplayString(const char *p) +{ + uint16 *s; + uint16 inv=0; + int f; + + ClearText(); + + s = txt_screen; + f = 0; + + while(*p) + { + switch(*p) + { + case '\n': + s+=32; + f=0; + break; + + case '%': + inv^=0x40; + break; + + default: + s[f++]=FromASCII(*p)|inv; + break; + } + + p++; + } +} + + +void ZX81Reconfigure(void) +{ + if (DS81_Config[DS81_STATIC_RAM_AT_0x2000]) + { + RAMBOT = 0x2000; + } + else + { + RAMBOT = 0x4000; + memcpy(mem+ROMLEN,mem,ROMLEN); + } + + allow_save = enable_filesystem && DS81_Config[DS81_ALLOW_TAPE_SAVE]; +} + + +void ZX81SaveSnapshot(FILE *fp) +{ + int f; + + for(f=0; f<sizeof mem; f++) + { + PUT_Byte(fp, mem[f]); + } + + for(f=0; f<sizeof matrix; f++) + { + PUT_Byte(fp, matrix[f]); + } + + PUT_Long(fp, waitkey); + PUT_Long(fp, started); + + PUT_ULong(fp, RAMBOT); + PUT_ULong(fp, RAMTOP); + + PUT_ULong(fp, prev_lk1); + PUT_ULong(fp, prev_lk2); +} + + +void ZX81LoadSnapshot(FILE *fp) +{ + int f; + + for(f=0; f<sizeof mem; f++) + { + mem[f] = GET_Byte(fp); + } + + for(f=0; f<sizeof matrix; f++) + { + matrix[f] = GET_Byte(fp); + } + + waitkey = GET_Long(fp); + started = GET_Long(fp); + + RAMBOT = GET_ULong(fp); + RAMTOP = GET_ULong(fp); + + prev_lk1 = GET_ULong(fp); + prev_lk2 = GET_ULong(fp); + + /* Reset last_I to force hi/lo res detection + */ + last_I = 0; +} + + +/* END OF FILE */ |