diff options
Diffstat (limited to 'source')
-rw-r--r-- | source/config.c | 143 | ||||
-rw-r--r-- | source/framebuffer.c | 433 | ||||
-rw-r--r-- | source/gui.c | 919 | ||||
-rw-r--r-- | source/keyboard.c | 428 | ||||
-rw-r--r-- | source/main.c | 358 | ||||
-rw-r--r-- | source/snapshot.c | 192 | ||||
-rw-r--r-- | source/stream.c | 85 | ||||
-rw-r--r-- | source/tapes.c | 258 | ||||
-rw-r--r-- | source/z80.c | 389 | ||||
-rw-r--r-- | source/z80_decode.c | 2530 | ||||
-rw-r--r-- | source/z80_dis.c | 2491 | ||||
-rw-r--r-- | source/zx81.c | 868 |
12 files changed, 9094 insertions, 0 deletions
diff --git a/source/config.c b/source/config.c new file mode 100644 index 0000000..c5635e3 --- /dev/null +++ b/source/config.c @@ -0,0 +1,143 @@ +/* + 3ds81 - Nintendo 3DS ZX81 emulator. + + Copyright (C) 2021 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 3 + 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, see <http://www.gnu.org/licenses/> + + $Id: config.c 65 2008-12-12 00:19:08Z ianc $ +*/ + +#include <3ds.h> +#include <stdio.h> +#include <string.h> + +#include "config.h" + +#ifndef TRUE +#define TRUE 1 +#endif + +#ifndef FALSE +#define FALSE 0 +#endif + +/* ---------------------------------------- PRIVATE DATA +*/ +const char *conf_filename = "DS81.CFG"; + +const char *conf_entry[DS81_NUM_CONFIG_ITEMS]= +{ + "sticky_shift", + "static_ram_at_0x2000", + "allow_tape_save", + "load_default_snapshot" +}; + + +/* ---------------------------------------- GLOBAL DATA +*/ +int DS81_Config[DS81_NUM_CONFIG_ITEMS]= +{ + TRUE, + FALSE, + FALSE, + FALSE +}; + + +/* ---------------------------------------- PUBLIC INTERFACES +*/ +int LoadConfig(void) +{ + FILE *fp = NULL; + + fp=fopen(conf_filename,"r"); + + 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; + + fp=fopen(conf_filename,"w"); + + 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_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..efdd27b --- /dev/null +++ b/source/framebuffer.c @@ -0,0 +1,433 @@ +/* + 3ds81 - Nintendo 3DS ZX81 emulator. + + Copyright (C) 2021 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 3 + 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, see <http://www.gnu.org/licenses/> + + $Id: framebuffer.c 43 2007-03-12 00:59:51Z ianc $ +*/ + +#include <3ds.h> +#include <stdlib.h> +#include <stdio.h> +#include <stdarg.h> +#include <string.h> + +#include "framebuffer.h" + +#include "cpatrol_inlay_bgr.h" +#include "mazogs_inlay_bgr.h" +#include "keyb_bgr.h" +#include "sabotage_inlay_bgr.h" +#include "maze_inlay_bgr.h" +#include "splashimg_bgr.h" + +/* ---------------------------------------- STATIC DATA +*/ +static u16 pal[COL_YELLOW + 1]; + +static Framebuffer image[IMG_SPLASH + 1]; + +static u8 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 void LoadImage(Framebuffer *fb, const u8* img, u16 w, u16 h) +{ + int f; + int x,y; + + fb->width = w; + fb->height = h; + + fb->buffer = malloc(sizeof *fb->buffer * w * h); + + x = 0; + y = h - 1; + + for(f = 0; f < w * h; f++) + { + u8 b = *img++; + u8 g = *img++; + u8 r = *img++; + + FB_ADDR(fb, x, y) = RGB8_to_565(r, g, b); + + if (++x == w) + { + x = 0; + y--; + } + } +} + + +/* ---------------------------------------- PUBLIC INTERFACES +*/ +void FB_Init(void) +{ + pal[COL_BLACK] = RGB8_to_565(0,0,0); + pal[COL_WHITE] = RGB8_to_565(255,255,255); + pal[COL_RED] = RGB8_to_565(255,0,0); + pal[COL_GREEN] = RGB8_to_565(0,255,0); + pal[COL_BLUE] = RGB8_to_565(0,0,255); + pal[COL_GUISELECT] = RGB8_to_565(128,128,255); + pal[COL_GREY] = RGB8_to_565(128,128,128); + pal[COL_LIGHTGREY] = RGB8_to_565(200,200,200); + pal[COL_DARKGREY] = RGB8_to_565(64,64,64); + pal[COL_YELLOW] = RGB8_to_565(255,255,0); + + LoadImage(image + IMG_CITY_PATROL_INLAY, cpatrol_inlay_bgr, 126, 192); + LoadImage(image + IMG_3D_MONSTER_MAZE_INLAY, cpatrol_inlay_bgr, 126, 192); + LoadImage(image + IMG_SABOTAGE_INLAY, sabotage_inlay_bgr, 126, 192); + LoadImage(image + IMG_MAZOGS_INLAY, mazogs_inlay_bgr, 126, 192); + LoadImage(image + IMG_KEYBOARD, keyb_bgr, 320, 240); + LoadImage(image + IMG_SPLASH, splashimg_bgr, 400, 240); +} + + +void FB_StartFrame(Framebuffer *upper, Framebuffer *lower) +{ + if (upper) + { + upper->buffer = (u16*)gfxGetFramebuffer(GFX_TOP, GFX_LEFT, + &upper->height, &upper->width); + } + + if (lower) + { + lower->buffer = (u16*)gfxGetFramebuffer(GFX_BOTTOM, GFX_LEFT, + &lower->height, &lower->width); + } +} + + +void FB_EndFrame(void) +{ + gfxFlushBuffers(); + gfxSwapBuffers(); + gspWaitForVBlank(); + hidScanInput(); +} + + +void FB_Print(Framebuffer *fb, const char *text, int x, int y, + FB_Colour colour, FB_Colour paper) +{ + int cx,cy; + int ch; + u16 fg,bg; + u16 fg_trans,bg_trans; + + fg = pal[colour]; + bg = pal[paper]; + fg_trans = colour == COL_TRANSPARENT; + bg_trans = paper == COL_TRANSPARENT; + + while(*text) + { + if (*text == 1) + { + u16 t; + + t = fg; + fg = bg; + bg = t; + + t = fg_trans; + fg_trans = bg_trans; + bg_trans = t; + + text++; + } + else if (*text == '\n') + { + x = 0; + y -= 8; + + text++; + + if (y < -7) + { + return; + } + } + else + { + ch=((*text)-32)*8; + + for(cy=0;cy<8;cy++) + { + for(cx=0;cx<8;cx++) + { + if (font[ch]&(1<<cx)) + { + if (!fg_trans) + { + FB_PLOT_CLIPPED(fb, x + cx, y - cy, fg); + } + } + else + { + if (!bg_trans) + { + FB_PLOT_CLIPPED(fb, x + cx, y - cy, bg); + } + } + } + + ch++; + } + + x+=8; + text++; + + if (x > fb->width) + { + break; + } + } + } +} + + +void FB_Centre(Framebuffer *fb, const char *text, int y, + FB_Colour colour, FB_Colour paper) +{ + FB_Print(fb, text, fb->width / 2 - strlen(text) * 4, y, colour, paper); +} + + +void FB_printf(Framebuffer *fb, int x, int y, + FB_Colour colour, FB_Colour paper, const char *format, ...) +{ + char buff[256]; + va_list va; + + va_start(va,format); + vsnprintf(buff,sizeof buff,format,va); + va_end(va); + + FB_Print(fb, buff, x, y, colour, paper); +} + + +void FB_HLine(Framebuffer *fb, u16 x1, u16 x2, u16 y, FB_Colour colour) +{ + if (x1 > x2) + { + u16 t; + + t = x1; + x1 = x2; + x2 = t; + } + + while(x1<=x2) + { + FB_PLOT_CLIPPED(fb, x1, y, pal[colour]); + x1++; + } +} + + +void FB_VLine(Framebuffer *fb, u16 x, u16 y1, u16 y2, FB_Colour colour) +{ + if (y1 > y2) + { + u16 t; + + t = y1; + y1 = y2; + y2 = t; + } + + while(y1<=y2) + { + FB_PLOT_CLIPPED(fb, x, y1, pal[colour]); + y1++; + } +} + + +void FB_Box(Framebuffer *fb, u16 x, u16 y, u16 w, u16 h, FB_Colour colour) +{ + FB_HLine(fb, x, x + w - 1, y, colour); + FB_HLine(fb, x, x + w - 1, y - h + 1, colour); + FB_VLine(fb, x, y, y - h + 1, colour); + FB_VLine(fb, x + w - 1, y, y - h + 1, colour); +} + + +void FB_FillBox(Framebuffer *fb, u16 x, u16 y, u16 w, u16 h, FB_Colour colour) +{ + while(h--) + { + FB_HLine(fb, x, x + w - 1, y--, colour); + } +} + + +void FB_Clear(Framebuffer *fb, FB_Colour col) +{ + u16 *p; + int f; + u16 c; + + f = fb->width * fb->height; + p = fb->buffer; + c = pal[col]; + + while(f--) + { + *p++ = c; + } +} + + +void FB_Blit(Framebuffer *fb, FB_Image img, u16 x, u16 y) +{ + Framebuffer *src; + u16 px,py; + + src = image + img; + + if (fb->width == src->width && fb->height == src->height && + x == 0 && y == 0) + { + memcpy(fb->buffer, src->buffer, src->width * src->height * 2); + } + else + { + for(px = 0; px < src->width; px++) + { + u16 dx; + + dx = x + px; + + if (dx < fb->width) + { + u16 dy; + + dy = y; + + for(py = 0; dy < fb->height && py < src->height; py++, dy++) + { + dy = y + py; + FB_ADDR(fb, dx, dy) = FB_ADDR(src, px, py); + } + } + } + } +} diff --git a/source/gui.c b/source/gui.c new file mode 100644 index 0000000..eee82f4 --- /dev/null +++ b/source/gui.c @@ -0,0 +1,919 @@ +/* + 3ds81 - Nintendo 3DS ZX81 emulator. + + Copyright (C) 2021 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 3 + 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, see <http://www.gnu.org/licenses/> + + $Id: gui.c 75 2010-11-19 14:52:49Z ianc $ +*/ + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <3ds.h> + +#include <sys/types.h> +#include <dirent.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 24 +#define FSEL_MAX_FILES 1024 + +#define FSEL_LIST_Y 10 +#define FSEL_LIST_H FSEL_LINES*8 + +#ifndef TRUE +#define TRUE 1 +#endif + +#ifndef FALSE +#define FALSE 0 +#endif + +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 (strcmp(f1->name, "..") == 0) + { + return -1; + } + else if (strcmp(f2->name, "..") == 0) + { + return 1; + } + else 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 *dir; + struct dirent *ent; + struct stat st; + int no = 0; + char whole_path[FILENAME_MAX]; + + if ((dir = opendir(path))) + { + if (strcmp(path, "/") != 0) + { + strcpy(fsel[no].name, ".."); + fsel[no].is_dir = TRUE; + fsel[no].size = 0; + no++; + } + + while(no < FSEL_MAX_FILES && (ent = readdir(dir))) + { + strcpy(whole_path, path); + strcat(whole_path, "/"); + strcat(whole_path, ent->d_name); + + stat(whole_path, &st); + + if (ValidFilename(ent->d_name, (st.st_mode & S_IFDIR), filter)) + { + strcpy(fsel[no].name,ent->d_name); + fsel[no].is_dir = (st.st_mode & S_IFDIR); + fsel[no].size = (int)st.st_size; + no++; + } + } + + closedir(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; + Framebuffer lower; + + 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]); + } + } + + FB_StartFrame(NULL, &lower); + + w=w*8+16; + + x=lower.width/2-w/2; + y=lower.height - 3; + + while(!done) + { + u32 key=0; + + do + { + FB_StartFrame(NULL, &lower); + + FB_Clear(&lower, COL_BLACK); + + FB_Box(&lower,x,y,w,h,COL_WHITE); + FB_FillBox(&lower,x+1,y-sel*16+1,w-2,14,COL_GUISELECT); + + for(f=0;f<no;f++) + { + FB_Centre(&lower, opts[f],y-4-f*16,COL_WHITE,COL_TRANSPARENT); + } + + FB_EndFrame(); + } while(!defer && !(key=hidKeysDownRepeat())); + + if (defer) + { + do + { + gspWaitForVBlank(); + hidScanInput(); + } while (hidKeysHeld()&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; + + hidTouchRead(&tp); + + if (tp.px>=x && tp.px<(x+w) && tp.py>=3 && tp.py<(3+h)) + { + defer=TRUE; + sel=(tp.py-3)/16; + } + } + } + } + + return sel; +} + + +void GUI_Alert(int fatal, const char *text) +{ + char line[80]; + int h; + const char *p; + char *d; + Framebuffer lower; + + FB_StartFrame(NULL, &lower); + + h=40; + p=text; + + while(*p) + { + if (*p++=='\n') + { + h+=8; + } + } + + FB_Clear(&lower, COL_BLACK); + FB_Box(&lower,0,lower.height-1,lower.width-1,lower.height-1,COL_WHITE); + + p=text; + h=lower.height-12; + d=line; + + while(*p) + { + if (*p=='\n') + { + *d++=0; + p++; + FB_Centre(&lower,line,h,COL_WHITE,COL_TRANSPARENT); + h-=8; + d=line; + } + else + { + *d++=*p++; + } + } + + if (d>line) + { + *d=0; + FB_Centre(&lower,line,h,COL_WHITE,COL_TRANSPARENT); + h-=8; + } + + if (!fatal) + { + FB_Centre(&lower, "PRESS ANY BUTTON OR SCREEN",h-16, + COL_YELLOW,COL_TRANSPARENT); + + FB_EndFrame(); + + while(!hidKeysDown()) + { + gspWaitForVBlank(); + hidScanInput(); + } + + while(hidKeysHeld()) + { + gspWaitForVBlank(); + hidScanInput(); + } + } + else + { + FB_Centre(&lower,"PLEASE RESET YOUR CONSOLE",h-16, + COL_YELLOW,COL_TRANSPARENT); + + FB_EndFrame(); + + while(1) + { + gspWaitForVBlank(); + } + } +} + + +void GUI_Config(void) +{ + int sel; + DS81_ConfigItem f; + int done; + int save; + Framebuffer lower; + + sel = 0; + done = FALSE; + save = FALSE; + + while(!done) + { + u32 key=0; + + do + { + FB_StartFrame(NULL, &lower); + + FB_Clear(&lower,COL_BLACK); + + FB_Centre(&lower,"Up/Down to select",40, + COL_YELLOW,COL_TRANSPARENT); + FB_Centre(&lower,"A to toggle",32,COL_YELLOW,COL_TRANSPARENT); + FB_Centre(&lower,"Or use touchscreen",24, + COL_YELLOW,COL_TRANSPARENT); + FB_Centre(&lower,"START to finish",16,COL_YELLOW,COL_TRANSPARENT); + + FB_Centre(&lower,"SELECT to finish and save",8, + COL_YELLOW,COL_TRANSPARENT); + + for(f=0;f<DS81_NUM_CONFIG_ITEMS;f++) + { + FB_Print(&lower,ConfigDesc(f),14,lower.height-(20+f*14), + COL_WHITE,COL_TRANSPARENT); + } + + + for(f=0;f<DS81_NUM_CONFIG_ITEMS;f++) + { + FB_FillBox(&lower,2,lower.height-(20+f*14-1),10,10, + DS81_Config[f] ? COL_WHITE : COL_BLACK); + + FB_Box(&lower,2,lower.height-(20+f*14-1),10,10,COL_GREY); + } + + FB_Box(&lower,0,lower.height-(20+sel*14-3),lower.width-1,14, + COL_GUISELECT); + + FB_EndFrame(); + } while(!(key=hidKeysDownRepeat())); + + if (key & KEY_START) + { + done=TRUE; + } + else if (key & KEY_SELECT) + { + done=TRUE; + save=TRUE; + } + 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; + Framebuffer lower; + + CheckPath(pwd); + no = LoadDir(pwd,filter); + + sel = 0; + top = 0; + done = FALSE; + ret = FALSE; + drag = FALSE; + drag_start = 0; + + while(!done) + { + u32 key=0; + + FB_StartFrame(NULL, &lower); + + FB_Clear(&lower,COL_BLACK); + + FB_printf(&lower,0,lower.height-1,COL_BLACK,COL_LIGHTGREY, + "%-32.32s",pwd); + + FB_Centre(&lower,"Use pad and A to select",32, + COL_YELLOW,COL_TRANSPARENT); + FB_Centre(&lower,"L and R to page up/down",24, + COL_YELLOW,COL_TRANSPARENT); + FB_Centre(&lower,"Or use touchscreen",16,COL_YELLOW,COL_TRANSPARENT); + FB_Centre(&lower,"B to cancel",8,COL_YELLOW,COL_TRANSPARENT); + + 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; + } + + 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(&lower,8,lower.height-(FSEL_LIST_Y+f*8), + COL_WHITE,paper, + "%-*s %s", + FSEL_FILENAME_LEN, + fsel[off].name, + fsel[off].is_dir ? "DIR" : " "); + } + else + { + FB_printf(&lower,8,lower.height-(FSEL_LIST_Y+f*8), + COL_WHITE,COL_BLACK, + "%-*s %s", + FSEL_FILENAME_LEN, + off==0 ? "No Files!" : "", + " "); + } + } + + FB_FillBox(&lower,240,lower.height-(FSEL_LIST_Y),16,FSEL_LIST_H, + COL_DARKGREY); + FB_FillBox(&lower,240,lower.height-(FSEL_LIST_Y+top*bar_step),16, + bar_size,COL_WHITE); + + FB_EndFrame(); + + if (drag) + { + touchPosition tp = {0}; + int diff = 0; + + while (((key=keysHeld()) & KEY_TOUCH) && diff == 0) + { + hidScanInput(); + touchRead(&tp); + diff = tp.py - drag_start; + gspWaitForVBlank(); + } + + 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; + + key=hidKeysDownRepeat(); + + 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); + + 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 (hidKeysHeld()) + { + hidScanInput(); + gspWaitForVBlank(); + } + + 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; + int done = FALSE; + int accept = FALSE; + Framebuffer upper; + + name[0] = 0; + + while(!done) + { + FB_StartFrame(&upper, NULL); + + FB_Clear(&upper, COL_WHITE); + SK_DisplayKeyboard(); + + FB_printf(&upper, 0, 16, COL_BLACK, COL_TRANSPARENT, "%s", prompt); + FB_printf(&upper, 0, 8, COL_BLACK, COL_TRANSPARENT, "\"%s\001L\001\"", + name); + + FB_Print(&upper, "PRESS ENTER TO ACCEPT", 0, 32, + COL_BLACK, COL_TRANSPARENT); + FB_Print(&upper, "PRESS PERIOD TO BACKSPACE", 0, 40, + COL_BLACK, COL_TRANSPARENT); + FB_Print(&upper, "PRESS SPACE/BREAK TO CANCEL", 0, 48, + COL_BLACK, COL_TRANSPARENT); + + FB_EndFrame(); + + 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; + } + 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; + } + } + break; + } + } + } + } + + return accept; +} + diff --git a/source/keyboard.c b/source/keyboard.c new file mode 100644 index 0000000..a08b72d --- /dev/null +++ b/source/keyboard.c @@ -0,0 +1,428 @@ +/* + 3ds81 - Nintendo 3DS ZX81 emulator. + + Copyright (C) 2021 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, see <http://www.gnu.org/licenses/> + + $Id: keyboard.c 64 2008-12-05 00:37:26Z ianc $ +*/ + +#include <3ds.h> + +#include "keyboard.h" +#include "framebuffer.h" +#include "stream.h" + +/* ---------------------------------------- STATIC DATA +*/ + +#ifndef TRUE +#define TRUE 1 +#endif + +#ifndef FALSE +#define FALSE 0 +#endif + +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) + +#define CELL_WIDTH 32 +#define CELL_HEIGHT 48 + +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 key = NUM_SOFT_KEYS; + + kx = p->px / CELL_WIDTH; + ky = p->py / CELL_HEIGHT; + + key = kx + ky * 10; + + if (key>SK_SPACE) + { + key = NUM_SOFT_KEYS; + } + + return key; +} + + +static void DrawSelect(Framebuffer *fb, int key, int selected) +{ + int x,y; + + x = (key % 10) * CELL_WIDTH; + y = (key / 10) * CELL_HEIGHT; + + FB_Box(fb, x, fb->height - 1 - y, CELL_WIDTH, CELL_HEIGHT, + selected ? selection_on : selection_off); +} + + +static int GetEvent(SoftKeyEvent *ev, int map) +{ + static SoftKey last = NUM_SOFT_KEYS; + static int poll_index = -1; + Framebuffer lower; + + FB_StartFrame(NULL, &lower); + + /* Read the keys if this is a new loop + */ + if (poll_index == -1) + { + int f; + u32 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; + + hidTouchRead(&tp); + + if (tp.py>192) + { + 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) + { + DrawSelect(&lower, f, key_state[f].new_state); + } + } + } + + 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) +{ + int f; + Framebuffer lower; + + FB_StartFrame(NULL, &lower); + + FB_Blit(&lower,IMG_KEYBOARD,0,0); + + /* Update any on-screen indicators + */ + for(f=SK_1; f<SK_CONFIG; f++) + { + if (key_state[f].state) + { + DrawSelect(&lower, f, key_state[f].state); + } + } +} + + +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..b41efe6 --- /dev/null +++ b/source/main.c @@ -0,0 +1,358 @@ +/* + 3ds81 - Nintendo 3DS ZX81 emulator. + + Copyright (C) 2021 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 3 + 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, see <http://www.gnu.org/licenses/> + + $Id: main.c 77 2010-11-23 08:10:25Z ianc $ +*/ + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <3ds.h> + +#include "framebuffer.h" +#include "gui.h" +#include "keyboard.h" +#include "z80.h" +#include "zx81.h" +#include "tapes.h" +#include "config.h" +#include "snapshot.h" + +#ifndef DS81_VERSION +#define DS81_VERSION "DEV " __TIME__ "/" __DATE__ +#endif + +#ifndef TRUE +#define TRUE 1 +#endif + +#ifndef FALSE +#define FALSE 0 +#endif + +#define DEBUG(x) \ + do \ + { \ + printf(x); \ + gfxFlushBuffers(); \ + gfxSwapBuffers(); \ + } while(0); \ + do \ + { \ + hidScanInput(); \ + } while(!(hidKeysDown() & KEY_TOUCH)) \ + +/* ---------------------------------------- STATIC DATA +*/ +static const char *main_menu[]= + { + "Reset ZX81", + "Select Tape", + "Configure", + "Map Joypad to Keys", + "Save Memory Snapshot", + "Load Memory Snapshot", + "Save Joypad/Key State", + "Load Joypad/Key State", + "Exit 3DS81", + "Cancel", + NULL + }; + +typedef enum +{ + MenuReset, + MenuSelectTape, + MenuConfigure, + MenuMapJoypad, + MenuSaveSnapshot, + MenuLoadSnapshot, + MenuSaveMappings, + MenuLoadMappings, + MenuExit +} MenuOpt; + + +/* ---------------------------------------- DISPLAY FUNCS +*/ +static void Splash(void) +{ + static char scroller[]= + { + " " + "Welcome to 3DS81, a ZX81 emulator for the Ninetendo 3DS. " + "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, The Prodigy, Paradise Lost and " + "Retro Gamer for coding fuel." + }; + + static const char *text[]= + { + "3DS81 \177 2021 Ian Cowburn", + " ", + "ZX81 ROM \177 1981", + "Nine Tiles Networks LTD", + " ", + "PRESS A TO CONTINUE", + " ", + "https://noddybox.co.uk/", + " ", + "If you place .P tape files in", + "the top directory or ZX81SNAP", + "then you should be able to load", + "GAME.P with the command", + "LOAD \"GAME\"", + NULL + }; + + int f; + int y; + int scr_x = 0; + int scr_y = 240; + Framebuffer upper; + Framebuffer lower; + + ZX81EnableFileSystem(TRUE); + SNAP_Enable(TRUE); + + while(!(hidKeysDown() & KEY_A)) + { + FB_StartFrame(&upper, &lower); + + FB_Clear(&upper, COL_BLACK); + FB_Clear(&lower, COL_BLACK); + + FB_Blit(&upper, IMG_SPLASH, 0, scr_y); + + FB_Print(&upper, "10 REM VERSION \001" DS81_VERSION "\001\n" + "20 PRINT \"\001THE ZX81 IS ACE\001\"\n" + "30 GOTO 20", + 0, 230, COL_WHITE, COL_TRANSPARENT); + + FB_printf(&lower, scr_x, 8, COL_WHITE, COL_TRANSPARENT, + "%-42.42s",scroller); + + y = lower.height - 20; + + for(f=0;text[f];f++) + { + FB_Centre(&lower, text[f], y, COL_WHITE, COL_TRANSPARENT); + y -= 8; + } + + FB_EndFrame(); + + if (scr_y > 0) + { + scr_y--; + } + + 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; + } + } +} + + +/* ---------------------------------------- JOYPAD MAPPING +*/ +static void MapJoypad(void) +{ + SoftKeyEvent ev; + SoftKey pad = NUM_SOFT_KEYS; + int done = FALSE; + Framebuffer upper; + Framebuffer lower; + + while(!done) + { + FB_StartFrame(&upper, &lower); + + SK_DisplayKeyboard(); + + FB_Clear(&upper, COL_WHITE); + + FB_Print(&upper, "Press the joypad button you want\n" + "to define and then the ZX81 key\n" + "you want to use.\n\n" + "Press CONFIG to finish.", + 0, upper.height - 40, COL_BLACK,COL_TRANSPARENT); + + if (pad != NUM_SOFT_KEYS) + { + FB_printf(&upper, 0, 80, COL_BLACK, COL_TRANSPARENT, + "defining\n \001%s\001",SK_KeyName(pad)); + } + + FB_EndFrame(); + + 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; + } + + if (ev.key<=SK_SPACE && pad!=NUM_SOFT_KEYS) + { + SK_DefinePad(pad,ev.key); + pad = NUM_SOFT_KEYS; + } + } + } + } +} + + +/* ---------------------------------------- MAIN +*/ +int main(int argc, char *argv[]) +{ + Z80 *z80; + int quit = FALSE; + + gfxInit(GSP_RGB565_OES, GSP_RGB565_OES, false); + consoleInit(GFX_TOP, NULL); + + FB_Init(); + + z80 = Z80Init(ZX81ReadMem, + ZX81WriteMem, + ZX81ReadPort, + ZX81WritePort, + ZX81ReadDisassem); + + if (!z80) + { + GUI_Alert(TRUE,"Failed to initialise\nthe Z80 CPU emulation!"); + } + + ZX81Init(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(!quit && aptMainLoop()) + { + SoftKeyEvent ev; + Framebuffer upper; + Framebuffer lower; + + FB_StartFrame(&upper, &lower); + + SK_DisplayKeyboard(); + + Z80Exec(z80); + + ZX81RenderDisplay(&upper); + + FB_EndFrame(); + + 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 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; + + case MenuExit: + quit = TRUE; + break; + } + } + break; + + default: + ZX81HandleKey(ev.key,ev.pressed); + break; + } + } + } + + gfxExit(); + + return 0; +} diff --git a/source/snapshot.c b/source/snapshot.c new file mode 100644 index 0000000..b64d309 --- /dev/null +++ b/source/snapshot.c @@ -0,0 +1,192 @@ +/* + 3ds81 - Nintendo 3DS ZX81 emulator + + Copyright (C) 2021 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 3 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, see <http://www.gnu.org/licenses/> + + ------------------------------------------------------------------------- + + Provides the routines for snapshotting. + +*/ +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <ctype.h> +#include <3ds.h> + +#include "snapshot.h" +#include "zx81.h" +#include "gui.h" + +#include "config.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..897fa62 --- /dev/null +++ b/source/stream.c @@ -0,0 +1,85 @@ +/* + 3ds81 - Nintendo 3DS ZX81 emulator + + Copyright (C) 2021 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 3 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, see <http://www.gnu.org/licenses/> + + ------------------------------------------------------------------------- + + 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..98652d0 --- /dev/null +++ b/source/tapes.c @@ -0,0 +1,258 @@ +/* + 3ds81 - Nintendo 3DS ZX81 emulator. + + Copyright (C) 2021 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 3 + 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, see <http://www.gnu.org/licenses/> + + $Id: tapes.c 61 2008-11-03 17:07:32Z ianc $ +*/ + +#include <3ds.h> + +#include "tapes.h" +#include "framebuffer.h" +#include "keyboard.h" +#include "zx81.h" + +#include "maze_bin.h" +#include "cpatrol_bin.h" +#include "sabotage_bin.h" +#include "mazogs_bin.h" + +#ifndef TRUE +#define TRUE 1 +#endif + +#ifndef FALSE +#define FALSE 0 +#endif + + +/* ---------------------------------------- STATIC DATA +*/ +typedef struct +{ + const u8 *tape; + const u8 *tape_end; + FB_Image img; + 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, + IMG_3D_MONSTER_MAZE_INLAY, + maze_keys, + "\0013D Monster maze\001\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" + "\001START\001 to start.\n" + "\001SELECT\001 to appeal.\n\n" + "\001Note\001 when the screen goes grey\n" + "this is not a problem - the game\n" + "is creating the maze." + }, + { + mazogs_bin, + mazogs_bin_end, + IMG_MAZOGS_INLAY, + mazogs_keys, + "\001Mazogs\001\n" + "(c) 1981 Don Priestley\n\n" + "Find the treasure and\n" + "return to the start.\n" + "Avoid the \001Mazogs\001 that roam\n" + "the maze.\n\n" + "Use joypad to move.\n" + "\001SELECT\001 to view map.\n" + "\001START\001 to quit.\n" + "\001L\001 or \001R\001 shoulder to select\n" + "direction at start." + }, + { + cpatrol_bin, + cpatrol_bin_end, + IMG_CITY_PATROL_INLAY, + cpatrol_keys, + "\001City Patrol\001\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 \001L\001 or \001R\001 shoulder buttons\n" + "to move fast when moving in the\n" + "same direction.\n\n" + "\001A\001 fires when moving.\n" + "\001B\001 fires when still.\n\n" + "sorry about that, but the keys\n" + "are a bit odd in this game." + }, + { + sabotage_bin, + sabotage_bin_end, + IMG_SABOTAGE_INLAY, + sabotage_keys, + "\001Sabotage\001\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" + "\001A\001 plants a bomb. \001L\001 shoulder\n" + "to play as the guard, \001R\001 as\n" + "the saboteur." + } + }; + + +static int current=0; + +/* ---------------------------------------- PRIVATE INTERFACES +*/ +static void DisplayTape(Tape *t, Framebuffer *upper, Framebuffer *lower) +{ + FB_Clear(upper,COL_WHITE); + FB_Clear(lower,COL_BLACK); + + FB_Blit(lower,t->img,lower->width-195,0); + + FB_Print(lower,"LEFT/RIGHT",0,lower->height-1,COL_WHITE,COL_TRANSPARENT); + FB_Print(lower,"to choose",0,lower->height-10,COL_WHITE,COL_TRANSPARENT); + FB_Print(lower,"A to select",0,lower->height-30,COL_WHITE,COL_TRANSPARENT); + FB_Print(lower,"B to cancel",0,lower->height-40,COL_WHITE,COL_TRANSPARENT); + FB_Print(lower,"REMEMBER TO",0,lower->height-60,COL_WHITE,COL_TRANSPARENT); + FB_Print(lower,"LOAD \"\"",0,lower->height-70,COL_WHITE,COL_TRANSPARENT); + FB_Print(lower,"ON THE ZX81!",0,lower->height-80,COL_WHITE,COL_TRANSPARENT); + + FB_Print(upper, t->text, 0, upper->height-1, COL_BLACK,COL_TRANSPARENT); +} + +/* ---------------------------------------- PUBLIC INTERFACES +*/ +void SelectTape(void) +{ + int done=FALSE; + Framebuffer upper; + Framebuffer lower; + + while(!done) + { + u32 key=0; + + + do + { + FB_StartFrame(&upper, &lower); + DisplayTape(tapes+current, &upper, &lower); + FB_EndFrame(); + } while(!(key=hidKeysDownRepeat())); + + 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; + } + } +} + diff --git a/source/z80.c b/source/z80.c new file mode 100644 index 0000000..e5f6c92 --- /dev/null +++ b/source/z80.c @@ -0,0 +1,389 @@ +/* + + z80 - Z80 Emulator + + Copyright (C) 2021 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 3 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, see <http://www.gnu.org/licenses/> + + ------------------------------------------------------------------------- + + $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" + +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..614f384 --- /dev/null +++ b/source/z80_decode.c @@ -0,0 +1,2530 @@ +/* + + z80 - Z80 Emulator + + Copyright (C) 2021 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 3 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, see <http://www.gnu.org/licenses/> + + ------------------------------------------------------------------------- + + $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" + +/* ---------------------------------------- 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..6c01b28 --- /dev/null +++ b/source/z80_dis.c @@ -0,0 +1,2491 @@ +/* + + z80 - Z80 Emulator + + Copyright (C) 2021 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 3 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, see <http://www.gnu.org/licenses/> + + ------------------------------------------------------------------------- + + $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..b2d85b1 --- /dev/null +++ b/source/zx81.c @@ -0,0 +1,868 @@ +/* + 3ds81 - Nintendo 3DS ZX81 emulator + + Copyright (C) 2021 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 3 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, see <http://www.gnu.org/licenses/> + + ------------------------------------------------------------------------- + + Provides the emulation for the ZX81 + +*/ +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <ctype.h> +#include <3ds.h> + +#include "zx81.h" +#include "gui.h" + +#include "stream.h" + +#include "config.h" + +#include "zx81_bin.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*10) + +#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 int waitkey=FALSE; +static int started=FALSE; + +static int hires=FALSE; +static int hires_dfile; +static int last_I; + +static int fast_mode=FALSE; + +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 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] = "/"; + +/* 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; +} + +/* 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 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; + } + else + { + hires = TRUE; + 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)) + { + fast_mode = FALSE; + FRAME_TSTATES=SLOW_TSTATES; + } + else + { + fast_mode = TRUE; + 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); + } + + 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(Z80 *z80) +{ + Z80Word f; + + hires = FALSE; + hires_dfile = 0; + last_I = 0x1e; + + /* 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 ZX81RenderDisplay(Framebuffer *fb) +{ + FB_Clear(fb, COL_BLACK); + FB_Centre(fb, "TODO", 10, COL_WHITE, COL_TRANSPARENT); +} + + +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; +} + + +void ZX81EnableFileSystem(int enable) +{ + enable_filesystem=enable; +} + + +void ZX81SetTape(const Z80Byte *image, int len) +{ + tape_image=image; + tape_len=len; +} + + +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 */ |