├── testfiles ├── zexall.com ├── zexdoc.com ├── zexall.z80 └── zexdoc.z80 ├── INSTALL ├── Makefile.nmake ├── zextest.h ├── Makefile ├── z80config.h ├── zextest.c ├── README.txt ├── z80emu.h ├── instructions.h ├── z80user.h ├── tables.h ├── macros.h └── maketables.c /testfiles/zexall.com: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/anotherlin/z80emu/HEAD/testfiles/zexall.com -------------------------------------------------------------------------------- /testfiles/zexdoc.com: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/anotherlin/z80emu/HEAD/testfiles/zexdoc.com -------------------------------------------------------------------------------- /INSTALL: -------------------------------------------------------------------------------- 1 | For Linux or Mac, just type "make". It will compile the example zextest. 2 | 3 | For Windows, open a Visual C++ command prompt and then type: 4 | 5 | nmake /f Makefile.nmake 6 | -------------------------------------------------------------------------------- /Makefile.nmake: -------------------------------------------------------------------------------- 1 | CC = cl 2 | CFLAGS = /O2 3 | 4 | all: zextest.exe 5 | 6 | tables.h: maketables.c 7 | $(CC) maketables.c 8 | maketables > $@ 9 | 10 | z80emu.obj: z80emu.c z80emu.h instructions.h macros.h tables.h 11 | $(CC) $(CFLAGS) /c z80emu.c 12 | 13 | zextest.obj: zextest.c z80emu.h 14 | $(CC) /c zextest.c 15 | 16 | OBJECT_FILES = zextest.obj z80emu.obj 17 | 18 | zextest.exe: $(OBJECT_FILES) 19 | link $(OBJECT_FILES) /out:zextest.exe 20 | -------------------------------------------------------------------------------- /zextest.h: -------------------------------------------------------------------------------- 1 | /* zextest.h 2 | * Header for zextest example. 3 | * 4 | * Copyright (c) 2012, 2016 Lin Ke-Fong 5 | * 6 | * This code is free, do whatever you want with it. 7 | */ 8 | 9 | #ifndef __ZEXTEST_INCLUDED__ 10 | #define __ZEXTEST_INCLUDED__ 11 | 12 | #include "z80emu.h" 13 | 14 | typedef struct ZEXTEST { 15 | 16 | Z80_STATE state; 17 | unsigned char memory[1 << 16]; 18 | int is_done; 19 | 20 | } ZEXTEST; 21 | 22 | extern void SystemCall (ZEXTEST *zextest); 23 | 24 | #endif 25 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | CC = gcc 2 | CFLAGS = -Wall -ansi -pedantic -O2 -fomit-frame-pointer 3 | 4 | all: zextest 5 | 6 | tables.h: maketables.c 7 | $(CC) -Wall $< -o maketables 8 | ./maketables > $@ 9 | 10 | z80emu.o: z80emu.c z80emu.h z80config.h z80user.h \ 11 | instructions.h macros.h tables.h 12 | $(CC) $(CFLAGS) -c $< 13 | 14 | zextest.o: zextest.c zextest.h z80emu.h z80config.h 15 | $(CC) -Wall -c $< 16 | 17 | OBJECT_FILES = zextest.o z80emu.o 18 | 19 | zextest: $(OBJECT_FILES) 20 | $(CC) $(OBJECT_FILES) -o $@ 21 | 22 | clean: 23 | rm -f *.o zextest maketables 24 | -------------------------------------------------------------------------------- /z80config.h: -------------------------------------------------------------------------------- 1 | /* z80config.h 2 | * Define or comment out macros in this file to configure the emulator. 3 | * 4 | * Copyright (c) 2016, 2017 Lin Ke-Fong 5 | * 6 | * This code is free, do whatever you want with it. 7 | */ 8 | 9 | #ifndef __Z80CONFIG_INCLUDED__ 10 | #define __Z80CONFIG_INCLUDED__ 11 | 12 | /* Define this macro if the host processor is big endian. */ 13 | 14 | /* #define Z80_BIG_ENDIAN */ 15 | 16 | /* Emulation can be speed up a little bit by emulating only the documented 17 | * flags. 18 | */ 19 | 20 | /* #define Z80_DOCUMENTED_FLAGS_ONLY */ 21 | 22 | /* HALT, DI, EI, RETI, and RETN instructions can be catched. When such an 23 | * instruction is catched, the emulator is stopped and the PC register points 24 | * at the opcode to be executed next. The catched instruction can be determined 25 | * from the Z80_STATE's status value. Keep in mind that no interrupt can be 26 | * accepted at the instruction right after a DI or EI on an actual processor. 27 | */ 28 | 29 | /* 30 | #define Z80_CATCH_HALT 31 | #define Z80_CATCH_DI 32 | #define Z80_CATCH_EI 33 | #define Z80_CATCH_RETI 34 | #define Z80_CATCH_RETN 35 | */ 36 | 37 | /* Undefined 0xed prefixed opcodes may be catched, otherwise they are treated 38 | * like NOP instructions. When one is catched, Z80_STATUS_ED_UNDEFINED is set 39 | * in Z80_STATE's status member and the PC register points at the 0xed prefix 40 | * before the undefined opcode. 41 | */ 42 | 43 | /* #define Z80_CATCH_ED_UNDEFINED */ 44 | 45 | /* The emulator cannot be stopped between prefixed opcodes. This can be a 46 | * problem if there is a long sequence of 0xdd and/or 0xfd prefixes. But if 47 | * Z80_PREFIX_FAILSAFE is defined, it will always be able to stop after at 48 | * least numbers_cycles are executed, in which case Z80_STATE's status is set 49 | * to Z80_STATUS_PREFIX. Note that if the memory where the opcodes are read, 50 | * has wait states (slow memory), then the additional cycles for a one byte 51 | * fetch (the non executed prefix) must be substracted. Even if it is safer, 52 | * most program won't need this feature. 53 | */ 54 | 55 | /* #define Z80_PREFIX_FAILSAFE */ 56 | 57 | /* By defining this macro, the emulator will always fetch the displacement or 58 | * address of a conditionnal jump or call instruction, even if the condition 59 | * is false and the fetch can be avoided. Define this macro if you need to 60 | * account for memory wait states on code read. 61 | */ 62 | 63 | /* #define Z80_FALSE_CONDITION_FETCH */ 64 | 65 | /* It may be possible to overwrite the opcode of the currently executing LDIR, 66 | * LDDR, INIR, or OTDR instruction. Define this macro if you need to handle 67 | * these pathological cases. 68 | */ 69 | 70 | /* #define Z80_HANDLE_SELF_MODIFYING_CODE */ 71 | 72 | /* For interrupt mode 2, bit 0 of the 16-bit address to the interrupt vector 73 | * can be masked to zero. Some documentation states that this bit is forced to 74 | * zero. For instance, Zilog's application note about interrupts, states that 75 | * "only 7 bits are required" and "the least significant bit is zero". Yet, 76 | * this is quite unclear, even from Zilog's manuals. So this is left as an 77 | * option. 78 | */ 79 | 80 | /* #define Z80_MASK_IM2_VECTOR_ADDRESS */ 81 | 82 | #endif 83 | -------------------------------------------------------------------------------- /zextest.c: -------------------------------------------------------------------------------- 1 | /* zextest.c 2 | * Example program using z80emu to run the zexall and zexdoc tests. This will 3 | * check if the Z80 is correctly emulated. 4 | * 5 | * Copyright (c) 2012, 2016 Lin Ke-Fong 6 | * Copyright (c) 2012 Chris Pressey 7 | * 8 | * This code is free, do whatever you want with it. 9 | */ 10 | 11 | #include 12 | #include 13 | #include 14 | #include "zextest.h" 15 | #include "z80emu.h" 16 | 17 | #define Z80_CPU_SPEED 4000000 /* In Hz. */ 18 | #define CYCLES_PER_STEP (Z80_CPU_SPEED / 50) 19 | #define MAXIMUM_STRING_LENGTH 100 20 | 21 | static void emulate (char *filename); 22 | 23 | int main (void) 24 | { 25 | time_t start, stop; 26 | 27 | start = time(NULL); 28 | emulate("testfiles/zexdoc.com"); 29 | emulate("testfiles/zexall.com"); 30 | stop = time(NULL); 31 | printf("Emulating zexdoc and zexall took a total of %d second(s).\n", 32 | (int) (stop - start)); 33 | 34 | return EXIT_SUCCESS; 35 | } 36 | 37 | /* Emulate "zexdoc.com" or "zexall.com". */ 38 | 39 | static void emulate (char *filename) 40 | { 41 | FILE *file; 42 | long l; 43 | ZEXTEST context; 44 | double total; 45 | 46 | printf("Testing \"%s\"...\n", filename); 47 | if ((file = fopen(filename, "rb")) == NULL) { 48 | 49 | fprintf(stderr, "Can't open file!\n"); 50 | exit(EXIT_FAILURE); 51 | 52 | } 53 | fseek(file, 0, SEEK_END); 54 | l = ftell(file); 55 | 56 | fseek(file, 0, SEEK_SET); 57 | fread(context.memory + 0x100, 1, l, file); 58 | 59 | fclose(file); 60 | 61 | /* Patch the memory of the program. Reset at 0x0000 is trapped by an 62 | * OUT which will stop emulation. CP/M bdos call 5 is trapped by an IN. 63 | * See Z80_INPUT_BYTE() and Z80_OUTPUT_BYTE() definitions in z80user.h. 64 | */ 65 | 66 | context.memory[0] = 0xd3; /* OUT N, A */ 67 | context.memory[1] = 0x00; 68 | 69 | context.memory[5] = 0xdb; /* IN A, N */ 70 | context.memory[6] = 0x00; 71 | context.memory[7] = 0xc9; /* RET */ 72 | 73 | context.is_done = 0; 74 | 75 | /* Emulate. */ 76 | 77 | Z80Reset(&context.state); 78 | context.state.pc = 0x100; 79 | total = 0.0; 80 | do 81 | 82 | total += Z80Emulate(&context.state, CYCLES_PER_STEP, &context); 83 | 84 | while (!context.is_done); 85 | printf("\n%.0f cycle(s) emulated.\n" 86 | "For a Z80 running at %.2fMHz, " 87 | "that would be %d second(s) or %.2f hour(s).\n", 88 | total, 89 | Z80_CPU_SPEED / 1000000.0, 90 | (int) (total / Z80_CPU_SPEED), 91 | total / ((double) 3600 * Z80_CPU_SPEED)); 92 | } 93 | 94 | /* Emulate CP/M bdos call 5 functions 2 (output character on screen) and 9 95 | * (output $-terminated string to screen). 96 | */ 97 | 98 | void SystemCall (ZEXTEST *zextest) 99 | { 100 | if (zextest->state.registers.byte[Z80_C] == 2) 101 | 102 | printf("%c", zextest->state.registers.byte[Z80_E]); 103 | 104 | else if (zextest->state.registers.byte[Z80_C] == 9) { 105 | 106 | int i, c; 107 | 108 | for (i = zextest->state.registers.word[Z80_DE], c = 0; 109 | zextest->memory[i] != '$'; 110 | i++) { 111 | 112 | printf("%c", zextest->memory[i & 0xffff]); 113 | if (c++ > MAXIMUM_STRING_LENGTH) { 114 | 115 | fprintf(stderr, 116 | "String to print is too long!\n"); 117 | exit(EXIT_FAILURE); 118 | 119 | } 120 | 121 | } 122 | 123 | } 124 | } 125 | -------------------------------------------------------------------------------- /README.txt: -------------------------------------------------------------------------------- 1 | z80emu 2 | Version 1.1.3 3 | 4 | Copyright (c) 2012-2017 Lin Ke-Fong 5 | 6 | z80emu is a free portable Z80 processor emulator. Its performance is comparable 7 | to other Z80 emulators. It emulates all undocumented features as described in 8 | "The Undocumented Z80 Documented Version 0.91" and passes both the zexdoc and 9 | zexall Z80 instruction exerciser tests. Code is pure ANSI C. 10 | 11 | The Makefile will compile a sample program to run zexdoc.com and zexall.com. 12 | Only needed CP/M BIOS functions are emulated. See zextest.c for details. 13 | 14 | All structures and functions are documented in the code, please read the header 15 | files. To use z80emu in your programs, modify z80config.h to configure the 16 | emulator, and in z80user.h, write the memory read/write and port input/output 17 | macros to interface with your system to emulate. The macros for zextest.c are 18 | simple examples. You shouldn't have to modify z80emu.c or any other files. 19 | 20 | z80emu works a little bit differently from other emulators. Instead of a switch 21 | case for all opcodes, it converts them to "generic" instructions and then do 22 | the switch case. Registers and operands are then decoded during execution. All 23 | of this is done using several tables (see maketables.c). The code is more 24 | compact, which should make it fit inside L1 instruction cache. 25 | 26 | You may find further information regarding the Z80 on http://www.z80.info. This 27 | emulator is heavily based on the information found on this website. And I would 28 | like to thank all its contributors. In particular, Sean Young for "The 29 | Undocumented Z80 Documented" and Christian Dinu for "Decoding Z80 Opcodes". The 30 | zexdoc and zexall programs have been written by Frank D. Cringles. 31 | 32 | I would like to thank Hugo Clement, Guy Hermann, Julien Montmartin, and Pierre 33 | Rousseau for review and testing. 34 | 35 | Sebastien Katz, Pierre Rousseau, and Thibaut Mattern made me start this project 36 | as part of a Sega Master System console emulator. That was long ago, back at 37 | university. I hope I will complete a full emulator someday. 38 | 39 | Feel free to send bug reports, comments, and suggestions to: 40 | 41 | anotherlin@gmail.com 42 | 43 | Revision history: 44 | 45 | 1.1.3 (18th September 2017) 46 | 47 | Another gross mistake fixed in the interrupt handling code: In mode 2, the 48 | interrupt vector wasn't dereferenced! Thank you rootednode for finding and 49 | reporting this issue. 50 | 51 | 1.1.2 (20th June 2017) 52 | 53 | The implementation of the "IM" Interrupt Mode selection instruction was 54 | completely wrong. The zextests don't check it and it seems that it was never 55 | encountered in the few systems emulated so far. This bug has gone unnoticed 56 | until now. Thank you Chris Despoinidis for reporting that bug. 57 | 58 | 1.1.1 (28th February 2017) 59 | 60 | I made the wrong assumption that char is signed by default. It is in fact 61 | implementation (compiler) dependent. So explicit (signed char) casts are now 62 | used instead. Otherwise, with unsigned char compilers, the zextests will have 63 | a few failing CRC checks. In fact, relative jumps will also fail to emulate 64 | correctly. Thank you SmallRoomLabs for finding and reporting this issue, and 65 | Mark Allender for verifying it. 66 | 67 | 1.1.0 "first-app" (22th December 2016) 68 | 69 | Ten years already! But hopefully, work on the Sega Master System emulator has 70 | restarted. For the first application of z80emu, redesign its user API, the 71 | original being really bad. Add 2 header files for the user to customize instead 72 | of having to modify z80emu.h, update the documentation: make it clear what 73 | variables each macro can expect, compute the register decoding tables only once 74 | at reset, and add a (void *) context for interfacing with the system to 75 | emulate. All these changes should make the API better organized and easier to 76 | use. 77 | 78 | 1.0.2 (12th February 2014) 79 | 80 | Conditional relative jump (JR_DD_E) instructions such as "jr NZ, loop_label" 81 | were not decoded correctly, just a silly bug in a macro to extract bits. The 82 | zexdoc and zexall exercisers have excellent coverage of ALU instructions, but 83 | they both don't feature a single "JR" instruction! Hence this (very obvious) 84 | bug has gone unnoticed. Thank you Marcelo Dantas. 85 | 86 | 1.0.1 (14th November 2012) 87 | 88 | Original implementation of zextest used int64_t. In retrospect, this was a poor 89 | choice. Using double to count cycles is ANSI and has more than enough precision 90 | to do so. Thank you Chris Pressey. 91 | 92 | 1.0.0 (13th March 2012) 93 | 94 | Initial commit on github. Actually, the code has been almost entirely written 95 | during the summer of 2006. 96 | -------------------------------------------------------------------------------- /z80emu.h: -------------------------------------------------------------------------------- 1 | /* z80emu.h 2 | * Main header of z80emu. Don't modify this file directly. Use z80config.h and 3 | * z80user.h to customize the emulator to your need. 4 | * 5 | * Copyright (c) 2012, 2016 Lin Ke-Fong 6 | * 7 | * This code is free, do whatever you want with it. 8 | */ 9 | 10 | #ifndef __Z80EMU_INCLUDED__ 11 | #define __Z80EMU_INCLUDED__ 12 | 13 | #ifdef __cplusplus 14 | extern "C" { 15 | #endif 16 | 17 | #include "z80config.h" 18 | 19 | /* If Z80_STATE's status is non-zero, the emulation has been stopped for some 20 | * reason other than emulating the requested number of cycles. See z80config.h. 21 | */ 22 | 23 | enum { 24 | 25 | Z80_STATUS_HALT = 1, 26 | Z80_STATUS_DI, 27 | Z80_STATUS_EI, 28 | Z80_STATUS_RETI, 29 | Z80_STATUS_RETN, 30 | Z80_STATUS_ED_UNDEFINED, 31 | Z80_STATUS_PREFIX 32 | 33 | }; 34 | 35 | /* The main registers are stored inside Z80_STATE as an union of arrays named 36 | * registers. They are referenced using indexes. Words are stored in the 37 | * endianness of the host processor. The alternate set of word registers AF', 38 | * BC', DE', and HL' is stored in the alternates member of Z80_STATE, as an 39 | * array using the same ordering. 40 | */ 41 | 42 | #ifdef Z80_BIG_ENDIAN 43 | 44 | # define Z80_B 0 45 | # define Z80_C 1 46 | # define Z80_D 2 47 | # define Z80_E 3 48 | # define Z80_H 4 49 | # define Z80_L 5 50 | # define Z80_A 6 51 | # define Z80_F 7 52 | 53 | # define Z80_IXH 8 54 | # define Z80_IXL 9 55 | # define Z80_IYH 10 56 | # define Z80_IYL 11 57 | 58 | #else 59 | 60 | # define Z80_B 1 61 | # define Z80_C 0 62 | # define Z80_D 3 63 | # define Z80_E 2 64 | # define Z80_H 5 65 | # define Z80_L 4 66 | # define Z80_A 7 67 | # define Z80_F 6 68 | 69 | # define Z80_IXH 9 70 | # define Z80_IXL 8 71 | # define Z80_IYH 11 72 | # define Z80_IYL 10 73 | 74 | #endif 75 | 76 | #define Z80_BC 0 77 | #define Z80_DE 1 78 | #define Z80_HL 2 79 | #define Z80_AF 3 80 | 81 | #define Z80_IX 4 82 | #define Z80_IY 5 83 | #define Z80_SP 6 84 | 85 | /* Z80's flags. */ 86 | 87 | #define Z80_S_FLAG_SHIFT 7 88 | #define Z80_Z_FLAG_SHIFT 6 89 | #define Z80_Y_FLAG_SHIFT 5 90 | #define Z80_H_FLAG_SHIFT 4 91 | #define Z80_X_FLAG_SHIFT 3 92 | #define Z80_PV_FLAG_SHIFT 2 93 | #define Z80_N_FLAG_SHIFT 1 94 | #define Z80_C_FLAG_SHIFT 0 95 | 96 | #define Z80_S_FLAG (1 << Z80_S_FLAG_SHIFT) 97 | #define Z80_Z_FLAG (1 << Z80_Z_FLAG_SHIFT) 98 | #define Z80_Y_FLAG (1 << Z80_Y_FLAG_SHIFT) 99 | #define Z80_H_FLAG (1 << Z80_H_FLAG_SHIFT) 100 | #define Z80_X_FLAG (1 << Z80_X_FLAG_SHIFT) 101 | #define Z80_PV_FLAG (1 << Z80_PV_FLAG_SHIFT) 102 | #define Z80_N_FLAG (1 << Z80_N_FLAG_SHIFT) 103 | #define Z80_C_FLAG (1 << Z80_C_FLAG_SHIFT) 104 | 105 | #define Z80_P_FLAG_SHIFT Z80_PV_FLAG_SHIFT 106 | #define Z80_V_FLAG_SHIFT Z80_PV_FLAG_SHIFT 107 | #define Z80_P_FLAG Z80_PV_FLAG 108 | #define Z80_V_FLAG Z80_PV_FLAG 109 | 110 | /* Z80's three interrupt modes. */ 111 | 112 | enum { 113 | 114 | Z80_INTERRUPT_MODE_0, 115 | Z80_INTERRUPT_MODE_1, 116 | Z80_INTERRUPT_MODE_2 117 | 118 | }; 119 | 120 | /* Z80 processor's state. You may add your own members if needed. However, it 121 | * is rather suggested to use the context pointer passed to the emulation 122 | * functions for that purpose. See z80user.h. 123 | */ 124 | 125 | typedef struct Z80_STATE { 126 | 127 | int status; 128 | 129 | union { 130 | 131 | unsigned char byte[14]; 132 | unsigned short word[7]; 133 | 134 | } registers; 135 | 136 | unsigned short alternates[4]; 137 | 138 | int i, r, pc, iff1, iff2, im; 139 | 140 | /* Register decoding tables. */ 141 | 142 | void *register_table[16], 143 | *dd_register_table[16], 144 | *fd_register_table[16]; 145 | 146 | } Z80_STATE; 147 | 148 | /* Initialize processor's state to power-on default. */ 149 | 150 | extern void Z80Reset (Z80_STATE *state); 151 | 152 | /* Trigger an interrupt according to the current interrupt mode and return the 153 | * number of cycles elapsed to accept it. If maskable interrupts are disabled, 154 | * this will return zero. In interrupt mode 0, data_on_bus must be a single 155 | * byte opcode. 156 | */ 157 | 158 | extern int Z80Interrupt (Z80_STATE *state, 159 | int data_on_bus, 160 | void *context); 161 | 162 | /* Trigger a non maskable interrupt, then return the number of cycles elapsed 163 | * to accept it. 164 | */ 165 | 166 | extern int Z80NonMaskableInterrupt (Z80_STATE *state, void *context); 167 | 168 | /* Execute instructions as long as the number of elapsed cycles is smaller than 169 | * number_cycles, and return the number of cycles emulated. The emulator can be 170 | * set to stop early on some conditions (see z80config.h). The user macros 171 | * (see z80user.h) also control the emulation. 172 | */ 173 | 174 | extern int Z80Emulate (Z80_STATE *state, 175 | int number_cycles, 176 | void *context); 177 | 178 | #ifdef __cplusplus 179 | } 180 | #endif 181 | 182 | #endif 183 | -------------------------------------------------------------------------------- /instructions.h: -------------------------------------------------------------------------------- 1 | /* instructions.h 2 | * Declaration of the "generic" instructions emulated. 3 | * 4 | * Copyright (c) 2012 Lin Ke-Fong 5 | * 6 | * This code is free, do whatever you want with it. 7 | */ 8 | 9 | /* Some "instructions" handle two opcodes hence they need their encodings to 10 | * be able to distinguish them. 11 | */ 12 | 13 | #define OPCODE_LD_A_I 0x57 14 | #define OPCODE_LD_I_A 0x47 15 | 16 | #define OPCODE_LDI 0xa0 17 | #define OPCODE_LDIR 0xb0 18 | #define OPCODE_CPI 0xa1 19 | #define OPCODE_CPIR 0xb1 20 | 21 | #define OPCODE_RLD 0x6f 22 | 23 | #if defined(Z80_CATCH_RETI) && defined(Z80_CATCH_RETN) 24 | # define OPCODE_RETI 0x4d 25 | #endif 26 | 27 | #define OPCODE_INI 0xa2 28 | #define OPCODE_INIR 0xb2 29 | #define OPCODE_OUTI 0xa3 30 | #define OPCODE_OTIR 0xb3 31 | 32 | /* Instruction numbers, opcodes are converted to these numbers using tables 33 | * generated by maketables.c. 34 | */ 35 | 36 | enum { 37 | 38 | /* 8-bit load group. */ 39 | 40 | LD_R_R, 41 | LD_R_N, 42 | 43 | LD_R_INDIRECT_HL, 44 | LD_INDIRECT_HL_R, 45 | LD_INDIRECT_HL_N, 46 | 47 | LD_A_INDIRECT_BC, 48 | LD_A_INDIRECT_DE, 49 | LD_A_INDIRECT_NN, 50 | LD_INDIRECT_BC_A, 51 | LD_INDIRECT_DE_A, 52 | LD_INDIRECT_NN_A, 53 | 54 | LD_A_I_LD_A_R, /* Handle "LD A, I" and "LD A, R". */ 55 | LD_I_A_LD_R_A, /* Handle "LD I, A" and "LD I, A". */ 56 | 57 | /* 16-bit load group. */ 58 | 59 | LD_RR_NN, 60 | 61 | LD_HL_INDIRECT_NN, 62 | LD_RR_INDIRECT_NN, 63 | LD_INDIRECT_NN_HL, 64 | LD_INDIRECT_NN_RR, 65 | 66 | LD_SP_HL, 67 | 68 | PUSH_SS, 69 | POP_SS, 70 | 71 | /* Exchange, block transfer, and search group. */ 72 | 73 | EX_DE_HL, 74 | EX_AF_AF_PRIME, 75 | EXX, 76 | EX_INDIRECT_SP_HL, 77 | 78 | LDI_LDD, /* Handle "LDI" and "LDD". */ 79 | LDIR_LDDR, /* Handle "LDIR" and "LDDR". */ 80 | 81 | CPI_CPD, /* Handle "CPI" and "CPD". */ 82 | CPIR_CPDR, /* Handle "CPIR" and "CPDR". */ 83 | 84 | /* 8-bit arithmetic and logical group. */ 85 | 86 | ADD_R, 87 | ADD_N, 88 | ADD_INDIRECT_HL, 89 | 90 | ADC_R, 91 | ADC_N, 92 | ADC_INDIRECT_HL, 93 | 94 | SUB_R, 95 | SUB_N, 96 | SUB_INDIRECT_HL, 97 | 98 | SBC_R, 99 | SBC_N, 100 | SBC_INDIRECT_HL, 101 | 102 | AND_R, 103 | AND_N, 104 | AND_INDIRECT_HL, 105 | 106 | XOR_R, 107 | XOR_N, 108 | XOR_INDIRECT_HL, 109 | 110 | OR_R, 111 | OR_N, 112 | OR_INDIRECT_HL, 113 | 114 | CP_R, 115 | CP_N, 116 | CP_INDIRECT_HL, 117 | 118 | INC_R, 119 | INC_INDIRECT_HL, 120 | DEC_R, 121 | DEC_INDIRECT_HL, 122 | 123 | /* 16-bit arithmetic group. */ 124 | 125 | ADD_HL_RR, 126 | 127 | ADC_HL_RR, 128 | SBC_HL_RR, 129 | 130 | INC_RR, 131 | DEC_RR, 132 | 133 | /* General-purpose arithmetic and CPU control group. */ 134 | 135 | DAA, 136 | 137 | CPL, 138 | NEG, 139 | 140 | CCF, 141 | SCF, 142 | 143 | NOP, 144 | HALT, 145 | 146 | DI, 147 | EI, 148 | 149 | IM_N, 150 | 151 | /* Rotate and shift group. */ 152 | 153 | RLCA, 154 | RLA, 155 | RRCA, 156 | RRA, 157 | 158 | RLC_R, 159 | RLC_INDIRECT_HL, 160 | RL_R, 161 | RL_INDIRECT_HL, 162 | RRC_R, 163 | RRC_INDIRECT_HL, 164 | RR_R, 165 | RR_INDIRECT_HL, 166 | SLA_R, 167 | SLA_INDIRECT_HL, 168 | SLL_R, 169 | SLL_INDIRECT_HL, 170 | SRA_R, 171 | SRA_INDIRECT_HL, 172 | SRL_R, 173 | SRL_INDIRECT_HL, 174 | 175 | RLD_RRD, /* Handle "RLD" and "RRD". */ 176 | 177 | /* Bit set, reset, and test group. */ 178 | 179 | BIT_B_R, 180 | BIT_B_INDIRECT_HL, 181 | SET_B_R, 182 | SET_B_INDIRECT_HL, 183 | RES_B_R, 184 | RES_B_INDIRECT_HL, 185 | 186 | /* Jump group. */ 187 | 188 | JP_NN, 189 | JP_CC_NN, 190 | JR_E, 191 | JR_DD_E, 192 | JP_HL, 193 | DJNZ_E, 194 | 195 | /* Call and return group. */ 196 | 197 | CALL_NN, 198 | CALL_CC_NN, 199 | RET, 200 | RET_CC, 201 | 202 | RETI_RETN, /* Handle "RETI" and "RETN". */ 203 | 204 | RST_P, 205 | 206 | /* Input and output group. */ 207 | 208 | IN_A_N, 209 | IN_R_C, /* Correctly handle undocumented "IN F, (C)" 210 | * instruction. 211 | */ 212 | 213 | INI_IND, /* Handle "INI" and "IND". */ 214 | INIR_INDR, /* Handle "INIR" and "INDR". */ 215 | 216 | OUT_N_A, 217 | OUT_C_R, /* Correctly handle undocumented "OUT (C), 0" 218 | * instruction. 219 | */ 220 | 221 | OUTI_OUTD, /* Handle "OUTI" and "OUTD".*/ 222 | OTIR_OTDR, /* Handle "OTIR" and "OTDR". */ 223 | 224 | /* Prefix group. */ 225 | 226 | CB_PREFIX, 227 | DD_PREFIX, 228 | FD_PREFIX, 229 | ED_PREFIX, 230 | 231 | /* Special instruction group. */ 232 | 233 | ED_UNDEFINED /* ED_UNDEFINED is used to catch undefined 234 | * 0xed prefixed opcodes. 235 | */ 236 | 237 | }; 238 | -------------------------------------------------------------------------------- /z80user.h: -------------------------------------------------------------------------------- 1 | /* z80user.h 2 | * Add your code here to interface the emulated system with z80emu. See towards 3 | * the end of the file for an example for running zextest. 4 | * 5 | * Copyright (c) 2016, 2017 Lin Ke-Fong 6 | * 7 | * This code is free, do whatever you want with it. 8 | */ 9 | 10 | #ifndef __Z80USER_INCLUDED__ 11 | #define __Z80USER_INCLUDED__ 12 | 13 | #ifdef __cplusplus 14 | extern "C" { 15 | #endif 16 | 17 | /* Write the following macros for memory access and input/output on the Z80. 18 | * 19 | * Z80_FETCH_BYTE() and Z80_FETCH_WORD() are used by the emulator to read the 20 | * code (opcode, constants, displacement, etc). The upper 16-bit of the address 21 | * parameters is undefined and must be reset to zero before actually reading 22 | * memory (use & 0xffff). The value x read, must be an unsigned 8-bit or 16-bit 23 | * value in the endianness of the host processor. 24 | * 25 | * Z80_READ_BYTE(), Z80_WRITE_BYTE(), Z80_READ_WORD(), and Z80_WRITE_WORD() 26 | * are used for general memory access. They obey the same rules as the code 27 | * reading macros. The upper bits of the value x to write may be non-zero. 28 | * Z80_READ_WORD_INTERRUPT() and Z80_WRITE_WORD_INTERRUPT() are same as 29 | * respectively Z80_READ_WORD() and Z80_WRITE_WORD(), except they are only used 30 | * for interrupt generation. 31 | * 32 | * Z80_INPUT_BYTE() and Z80_OUTPUT_BYTE() are for input and output. The upper 33 | * bits of the port number to read or write are always zero. The input byte x 34 | * must be an unsigned 8-bit value. The value x to write is an unsigned 8-bit 35 | * with its upper bits zeroed. 36 | * 37 | * All macros have access to the following three variables: 38 | * 39 | * state Pointer to the current Z80_STATE. Because the 40 | * instruction is currently executing, its members may not 41 | * be fully up to date, depending on when the macro is 42 | * called in the process. It is rather suggested to access 43 | * the state only when the emulator is stopped. 44 | * 45 | * elapsed_cycles Number of cycles emulated. If needed, you may add wait 46 | * states to it for slow memory accesses. Because the 47 | * macros are called during the execution of the current 48 | * instruction, this number is only precise up to the 49 | * previous one. 50 | * 51 | * context This is the (void *) context passed to the emulation 52 | * functions. 53 | * 54 | * Except for Z80_READ_WORD_INTERRUPT and Z80_WRITE_WORD_INTERRUPT, all macros 55 | * also have access to: 56 | * 57 | * number_cycles Number of cycles to emulate. After executing each 58 | * instruction, the emulator checks if elapsed_cycles is 59 | * greater or equal to number_cycles, and will stops if 60 | * so. Hence you may decrease or increase the value of 61 | * number_cycles to stop the emulation earlier or later. 62 | * In particular, if you set it to zero, the emulator will 63 | * stop after completion of the current instruction. 64 | * 65 | * registers Current register decoding table, use it to determine if 66 | * the current instruction is prefixed. It points on: 67 | * 68 | * state->dd_register_table for 0xdd prefixes; 69 | * state->fd_register_table for 0xfd prefixes; 70 | * state->register_table otherwise. 71 | * 72 | * pc Current PC register (upper bits are undefined), points 73 | * on the opcode, the displacement or constant to read for 74 | * Z80_FETCH_BYTE() and Z80_FETCH_WORD(), or on the next 75 | * instruction otherwise. 76 | * 77 | * Except for Z80_FETCH_BYTE(), Z80_FETCH_WORD(), Z80_READ_WORD_INTERRUPT, and 78 | * Z80_WRITE_WORD_INTERRUPT, all other macros can know which instruction is 79 | * currently executing: 80 | * 81 | * opcode Opcode of the currently executing instruction. 82 | * 83 | * instruction Type of the currently executing instruction, see 84 | * instructions.h for a list. 85 | */ 86 | 87 | /* Here are macros for emulating zexdoc and zexall. Read/write memory macros 88 | * are written for a linear 64k RAM. Input/output port macros are used as 89 | * "traps" to simulate system calls. 90 | */ 91 | 92 | #include "zextest.h" 93 | 94 | #define Z80_READ_BYTE(address, x) \ 95 | { \ 96 | (x) = ((ZEXTEST *) context)->memory[(address) & 0xffff]; \ 97 | } 98 | 99 | #define Z80_FETCH_BYTE(address, x) Z80_READ_BYTE((address), (x)) 100 | 101 | #define Z80_READ_WORD(address, x) \ 102 | { \ 103 | unsigned char *memory; \ 104 | \ 105 | memory = ((ZEXTEST *) context)->memory; \ 106 | (x) = memory[(address) & 0xffff] \ 107 | | (memory[((address) + 1) & 0xffff] << 8); \ 108 | } 109 | 110 | #define Z80_FETCH_WORD(address, x) Z80_READ_WORD((address), (x)) 111 | 112 | #define Z80_WRITE_BYTE(address, x) \ 113 | { \ 114 | ((ZEXTEST *) context)->memory[(address) & 0xffff] = (x); \ 115 | } 116 | 117 | #define Z80_WRITE_WORD(address, x) \ 118 | { \ 119 | unsigned char *memory; \ 120 | \ 121 | memory = ((ZEXTEST *) context)->memory; \ 122 | memory[(address) & 0xffff] = (x); \ 123 | memory[((address) + 1) & 0xffff] = (x) >> 8; \ 124 | } 125 | 126 | #define Z80_READ_WORD_INTERRUPT(address, x) Z80_READ_WORD((address), (x)) 127 | 128 | #define Z80_WRITE_WORD_INTERRUPT(address, x) Z80_WRITE_WORD((address), (x)) 129 | 130 | #define Z80_INPUT_BYTE(port, x) \ 131 | { \ 132 | SystemCall((ZEXTEST *) context); \ 133 | } 134 | 135 | #define Z80_OUTPUT_BYTE(port, x) \ 136 | { \ 137 | ((ZEXTEST *) context)->is_done = !0; \ 138 | number_cycles = 0; \ 139 | } 140 | 141 | #ifdef __cplusplus 142 | } 143 | #endif 144 | 145 | #endif 146 | -------------------------------------------------------------------------------- /tables.h: -------------------------------------------------------------------------------- 1 | /* Generated file, see maketables.c. */ 2 | 3 | static const unsigned char INSTRUCTION_TABLE[256] = { 4 | 5 | NOP, 6 | LD_RR_NN, 7 | LD_INDIRECT_BC_A, 8 | INC_RR, 9 | INC_R, 10 | DEC_R, 11 | LD_R_N, 12 | RLCA, 13 | 14 | EX_AF_AF_PRIME, 15 | ADD_HL_RR, 16 | LD_A_INDIRECT_BC, 17 | DEC_RR, 18 | INC_R, 19 | DEC_R, 20 | LD_R_N, 21 | RRCA, 22 | 23 | DJNZ_E, 24 | LD_RR_NN, 25 | LD_INDIRECT_DE_A, 26 | INC_RR, 27 | INC_R, 28 | DEC_R, 29 | LD_R_N, 30 | RLA, 31 | 32 | JR_E, 33 | ADD_HL_RR, 34 | LD_A_INDIRECT_DE, 35 | DEC_RR, 36 | INC_R, 37 | DEC_R, 38 | LD_R_N, 39 | RRA, 40 | 41 | JR_DD_E, 42 | LD_RR_NN, 43 | LD_INDIRECT_NN_HL, 44 | INC_RR, 45 | INC_R, 46 | DEC_R, 47 | LD_R_N, 48 | DAA, 49 | 50 | JR_DD_E, 51 | ADD_HL_RR, 52 | LD_HL_INDIRECT_NN, 53 | DEC_RR, 54 | INC_R, 55 | DEC_R, 56 | LD_R_N, 57 | CPL, 58 | 59 | JR_DD_E, 60 | LD_RR_NN, 61 | LD_INDIRECT_NN_A, 62 | INC_RR, 63 | INC_INDIRECT_HL, 64 | DEC_INDIRECT_HL, 65 | LD_INDIRECT_HL_N, 66 | SCF, 67 | 68 | JR_DD_E, 69 | ADD_HL_RR, 70 | LD_A_INDIRECT_NN, 71 | DEC_RR, 72 | INC_R, 73 | DEC_R, 74 | LD_R_N, 75 | CCF, 76 | 77 | NOP, 78 | LD_R_R, 79 | LD_R_R, 80 | LD_R_R, 81 | LD_R_R, 82 | LD_R_R, 83 | LD_R_INDIRECT_HL, 84 | LD_R_R, 85 | 86 | LD_R_R, 87 | NOP, 88 | LD_R_R, 89 | LD_R_R, 90 | LD_R_R, 91 | LD_R_R, 92 | LD_R_INDIRECT_HL, 93 | LD_R_R, 94 | 95 | LD_R_R, 96 | LD_R_R, 97 | NOP, 98 | LD_R_R, 99 | LD_R_R, 100 | LD_R_R, 101 | LD_R_INDIRECT_HL, 102 | LD_R_R, 103 | 104 | LD_R_R, 105 | LD_R_R, 106 | LD_R_R, 107 | NOP, 108 | LD_R_R, 109 | LD_R_R, 110 | LD_R_INDIRECT_HL, 111 | LD_R_R, 112 | 113 | LD_R_R, 114 | LD_R_R, 115 | LD_R_R, 116 | LD_R_R, 117 | NOP, 118 | LD_R_R, 119 | LD_R_INDIRECT_HL, 120 | LD_R_R, 121 | 122 | LD_R_R, 123 | LD_R_R, 124 | LD_R_R, 125 | LD_R_R, 126 | LD_R_R, 127 | NOP, 128 | LD_R_INDIRECT_HL, 129 | LD_R_R, 130 | 131 | LD_INDIRECT_HL_R, 132 | LD_INDIRECT_HL_R, 133 | LD_INDIRECT_HL_R, 134 | LD_INDIRECT_HL_R, 135 | LD_INDIRECT_HL_R, 136 | LD_INDIRECT_HL_R, 137 | HALT, 138 | LD_INDIRECT_HL_R, 139 | 140 | LD_R_R, 141 | LD_R_R, 142 | LD_R_R, 143 | LD_R_R, 144 | LD_R_R, 145 | LD_R_R, 146 | LD_R_INDIRECT_HL, 147 | NOP, 148 | 149 | ADD_R, 150 | ADD_R, 151 | ADD_R, 152 | ADD_R, 153 | ADD_R, 154 | ADD_R, 155 | ADD_INDIRECT_HL, 156 | ADD_R, 157 | 158 | ADC_R, 159 | ADC_R, 160 | ADC_R, 161 | ADC_R, 162 | ADC_R, 163 | ADC_R, 164 | ADC_INDIRECT_HL, 165 | ADC_R, 166 | 167 | SUB_R, 168 | SUB_R, 169 | SUB_R, 170 | SUB_R, 171 | SUB_R, 172 | SUB_R, 173 | SUB_INDIRECT_HL, 174 | SUB_R, 175 | 176 | SBC_R, 177 | SBC_R, 178 | SBC_R, 179 | SBC_R, 180 | SBC_R, 181 | SBC_R, 182 | SBC_INDIRECT_HL, 183 | SBC_R, 184 | 185 | AND_R, 186 | AND_R, 187 | AND_R, 188 | AND_R, 189 | AND_R, 190 | AND_R, 191 | AND_INDIRECT_HL, 192 | AND_R, 193 | 194 | XOR_R, 195 | XOR_R, 196 | XOR_R, 197 | XOR_R, 198 | XOR_R, 199 | XOR_R, 200 | XOR_INDIRECT_HL, 201 | XOR_R, 202 | 203 | OR_R, 204 | OR_R, 205 | OR_R, 206 | OR_R, 207 | OR_R, 208 | OR_R, 209 | OR_INDIRECT_HL, 210 | OR_R, 211 | 212 | CP_R, 213 | CP_R, 214 | CP_R, 215 | CP_R, 216 | CP_R, 217 | CP_R, 218 | CP_INDIRECT_HL, 219 | CP_R, 220 | 221 | RET_CC, 222 | POP_SS, 223 | JP_CC_NN, 224 | JP_NN, 225 | CALL_CC_NN, 226 | PUSH_SS, 227 | ADD_N, 228 | RST_P, 229 | 230 | RET_CC, 231 | RET, 232 | JP_CC_NN, 233 | CB_PREFIX, 234 | CALL_CC_NN, 235 | CALL_NN, 236 | ADC_N, 237 | RST_P, 238 | 239 | RET_CC, 240 | POP_SS, 241 | JP_CC_NN, 242 | OUT_N_A, 243 | CALL_CC_NN, 244 | PUSH_SS, 245 | SUB_N, 246 | RST_P, 247 | 248 | RET_CC, 249 | EXX, 250 | JP_CC_NN, 251 | IN_A_N, 252 | CALL_CC_NN, 253 | DD_PREFIX, 254 | SBC_N, 255 | RST_P, 256 | 257 | RET_CC, 258 | POP_SS, 259 | JP_CC_NN, 260 | EX_INDIRECT_SP_HL, 261 | CALL_CC_NN, 262 | PUSH_SS, 263 | AND_N, 264 | RST_P, 265 | 266 | RET_CC, 267 | JP_HL, 268 | JP_CC_NN, 269 | EX_DE_HL, 270 | CALL_CC_NN, 271 | ED_PREFIX, 272 | XOR_N, 273 | RST_P, 274 | 275 | RET_CC, 276 | POP_SS, 277 | JP_CC_NN, 278 | DI, 279 | CALL_CC_NN, 280 | PUSH_SS, 281 | OR_N, 282 | RST_P, 283 | 284 | RET_CC, 285 | LD_SP_HL, 286 | JP_CC_NN, 287 | EI, 288 | CALL_CC_NN, 289 | FD_PREFIX, 290 | CP_N, 291 | RST_P, 292 | 293 | }; 294 | 295 | static const unsigned char CB_INSTRUCTION_TABLE[256] = { 296 | 297 | RLC_R, 298 | RLC_R, 299 | RLC_R, 300 | RLC_R, 301 | RLC_R, 302 | RLC_R, 303 | RLC_INDIRECT_HL, 304 | RLC_R, 305 | 306 | RRC_R, 307 | RRC_R, 308 | RRC_R, 309 | RRC_R, 310 | RRC_R, 311 | RRC_R, 312 | RRC_INDIRECT_HL, 313 | RRC_R, 314 | 315 | RL_R, 316 | RL_R, 317 | RL_R, 318 | RL_R, 319 | RL_R, 320 | RL_R, 321 | RL_INDIRECT_HL, 322 | RL_R, 323 | 324 | RR_R, 325 | RR_R, 326 | RR_R, 327 | RR_R, 328 | RR_R, 329 | RR_R, 330 | RR_INDIRECT_HL, 331 | RR_R, 332 | 333 | SLA_R, 334 | SLA_R, 335 | SLA_R, 336 | SLA_R, 337 | SLA_R, 338 | SLA_R, 339 | SLA_INDIRECT_HL, 340 | SLA_R, 341 | 342 | SRA_R, 343 | SRA_R, 344 | SRA_R, 345 | SRA_R, 346 | SRA_R, 347 | SRA_R, 348 | SRA_INDIRECT_HL, 349 | SRA_R, 350 | 351 | SLL_R, 352 | SLL_R, 353 | SLL_R, 354 | SLL_R, 355 | SLL_R, 356 | SLL_R, 357 | SLL_INDIRECT_HL, 358 | SLL_R, 359 | 360 | SRL_R, 361 | SRL_R, 362 | SRL_R, 363 | SRL_R, 364 | SRL_R, 365 | SRL_R, 366 | SRL_INDIRECT_HL, 367 | SRL_R, 368 | 369 | BIT_B_R, 370 | BIT_B_R, 371 | BIT_B_R, 372 | BIT_B_R, 373 | BIT_B_R, 374 | BIT_B_R, 375 | BIT_B_INDIRECT_HL, 376 | BIT_B_R, 377 | 378 | BIT_B_R, 379 | BIT_B_R, 380 | BIT_B_R, 381 | BIT_B_R, 382 | BIT_B_R, 383 | BIT_B_R, 384 | BIT_B_INDIRECT_HL, 385 | BIT_B_R, 386 | 387 | BIT_B_R, 388 | BIT_B_R, 389 | BIT_B_R, 390 | BIT_B_R, 391 | BIT_B_R, 392 | BIT_B_R, 393 | BIT_B_INDIRECT_HL, 394 | BIT_B_R, 395 | 396 | BIT_B_R, 397 | BIT_B_R, 398 | BIT_B_R, 399 | BIT_B_R, 400 | BIT_B_R, 401 | BIT_B_R, 402 | BIT_B_INDIRECT_HL, 403 | BIT_B_R, 404 | 405 | BIT_B_R, 406 | BIT_B_R, 407 | BIT_B_R, 408 | BIT_B_R, 409 | BIT_B_R, 410 | BIT_B_R, 411 | BIT_B_INDIRECT_HL, 412 | BIT_B_R, 413 | 414 | BIT_B_R, 415 | BIT_B_R, 416 | BIT_B_R, 417 | BIT_B_R, 418 | BIT_B_R, 419 | BIT_B_R, 420 | BIT_B_INDIRECT_HL, 421 | BIT_B_R, 422 | 423 | BIT_B_R, 424 | BIT_B_R, 425 | BIT_B_R, 426 | BIT_B_R, 427 | BIT_B_R, 428 | BIT_B_R, 429 | BIT_B_INDIRECT_HL, 430 | BIT_B_R, 431 | 432 | BIT_B_R, 433 | BIT_B_R, 434 | BIT_B_R, 435 | BIT_B_R, 436 | BIT_B_R, 437 | BIT_B_R, 438 | BIT_B_INDIRECT_HL, 439 | BIT_B_R, 440 | 441 | RES_B_R, 442 | RES_B_R, 443 | RES_B_R, 444 | RES_B_R, 445 | RES_B_R, 446 | RES_B_R, 447 | RES_B_INDIRECT_HL, 448 | RES_B_R, 449 | 450 | RES_B_R, 451 | RES_B_R, 452 | RES_B_R, 453 | RES_B_R, 454 | RES_B_R, 455 | RES_B_R, 456 | RES_B_INDIRECT_HL, 457 | RES_B_R, 458 | 459 | RES_B_R, 460 | RES_B_R, 461 | RES_B_R, 462 | RES_B_R, 463 | RES_B_R, 464 | RES_B_R, 465 | RES_B_INDIRECT_HL, 466 | RES_B_R, 467 | 468 | RES_B_R, 469 | RES_B_R, 470 | RES_B_R, 471 | RES_B_R, 472 | RES_B_R, 473 | RES_B_R, 474 | RES_B_INDIRECT_HL, 475 | RES_B_R, 476 | 477 | RES_B_R, 478 | RES_B_R, 479 | RES_B_R, 480 | RES_B_R, 481 | RES_B_R, 482 | RES_B_R, 483 | RES_B_INDIRECT_HL, 484 | RES_B_R, 485 | 486 | RES_B_R, 487 | RES_B_R, 488 | RES_B_R, 489 | RES_B_R, 490 | RES_B_R, 491 | RES_B_R, 492 | RES_B_INDIRECT_HL, 493 | RES_B_R, 494 | 495 | RES_B_R, 496 | RES_B_R, 497 | RES_B_R, 498 | RES_B_R, 499 | RES_B_R, 500 | RES_B_R, 501 | RES_B_INDIRECT_HL, 502 | RES_B_R, 503 | 504 | RES_B_R, 505 | RES_B_R, 506 | RES_B_R, 507 | RES_B_R, 508 | RES_B_R, 509 | RES_B_R, 510 | RES_B_INDIRECT_HL, 511 | RES_B_R, 512 | 513 | SET_B_R, 514 | SET_B_R, 515 | SET_B_R, 516 | SET_B_R, 517 | SET_B_R, 518 | SET_B_R, 519 | SET_B_INDIRECT_HL, 520 | SET_B_R, 521 | 522 | SET_B_R, 523 | SET_B_R, 524 | SET_B_R, 525 | SET_B_R, 526 | SET_B_R, 527 | SET_B_R, 528 | SET_B_INDIRECT_HL, 529 | SET_B_R, 530 | 531 | SET_B_R, 532 | SET_B_R, 533 | SET_B_R, 534 | SET_B_R, 535 | SET_B_R, 536 | SET_B_R, 537 | SET_B_INDIRECT_HL, 538 | SET_B_R, 539 | 540 | SET_B_R, 541 | SET_B_R, 542 | SET_B_R, 543 | SET_B_R, 544 | SET_B_R, 545 | SET_B_R, 546 | SET_B_INDIRECT_HL, 547 | SET_B_R, 548 | 549 | SET_B_R, 550 | SET_B_R, 551 | SET_B_R, 552 | SET_B_R, 553 | SET_B_R, 554 | SET_B_R, 555 | SET_B_INDIRECT_HL, 556 | SET_B_R, 557 | 558 | SET_B_R, 559 | SET_B_R, 560 | SET_B_R, 561 | SET_B_R, 562 | SET_B_R, 563 | SET_B_R, 564 | SET_B_INDIRECT_HL, 565 | SET_B_R, 566 | 567 | SET_B_R, 568 | SET_B_R, 569 | SET_B_R, 570 | SET_B_R, 571 | SET_B_R, 572 | SET_B_R, 573 | SET_B_INDIRECT_HL, 574 | SET_B_R, 575 | 576 | SET_B_R, 577 | SET_B_R, 578 | SET_B_R, 579 | SET_B_R, 580 | SET_B_R, 581 | SET_B_R, 582 | SET_B_INDIRECT_HL, 583 | SET_B_R, 584 | 585 | }; 586 | 587 | static const unsigned char ED_INSTRUCTION_TABLE[256] = { 588 | 589 | ED_UNDEFINED, 590 | ED_UNDEFINED, 591 | ED_UNDEFINED, 592 | ED_UNDEFINED, 593 | ED_UNDEFINED, 594 | ED_UNDEFINED, 595 | ED_UNDEFINED, 596 | ED_UNDEFINED, 597 | 598 | ED_UNDEFINED, 599 | ED_UNDEFINED, 600 | ED_UNDEFINED, 601 | ED_UNDEFINED, 602 | ED_UNDEFINED, 603 | ED_UNDEFINED, 604 | ED_UNDEFINED, 605 | ED_UNDEFINED, 606 | 607 | ED_UNDEFINED, 608 | ED_UNDEFINED, 609 | ED_UNDEFINED, 610 | ED_UNDEFINED, 611 | ED_UNDEFINED, 612 | ED_UNDEFINED, 613 | ED_UNDEFINED, 614 | ED_UNDEFINED, 615 | 616 | ED_UNDEFINED, 617 | ED_UNDEFINED, 618 | ED_UNDEFINED, 619 | ED_UNDEFINED, 620 | ED_UNDEFINED, 621 | ED_UNDEFINED, 622 | ED_UNDEFINED, 623 | ED_UNDEFINED, 624 | 625 | ED_UNDEFINED, 626 | ED_UNDEFINED, 627 | ED_UNDEFINED, 628 | ED_UNDEFINED, 629 | ED_UNDEFINED, 630 | ED_UNDEFINED, 631 | ED_UNDEFINED, 632 | ED_UNDEFINED, 633 | 634 | ED_UNDEFINED, 635 | ED_UNDEFINED, 636 | ED_UNDEFINED, 637 | ED_UNDEFINED, 638 | ED_UNDEFINED, 639 | ED_UNDEFINED, 640 | ED_UNDEFINED, 641 | ED_UNDEFINED, 642 | 643 | ED_UNDEFINED, 644 | ED_UNDEFINED, 645 | ED_UNDEFINED, 646 | ED_UNDEFINED, 647 | ED_UNDEFINED, 648 | ED_UNDEFINED, 649 | ED_UNDEFINED, 650 | ED_UNDEFINED, 651 | 652 | ED_UNDEFINED, 653 | ED_UNDEFINED, 654 | ED_UNDEFINED, 655 | ED_UNDEFINED, 656 | ED_UNDEFINED, 657 | ED_UNDEFINED, 658 | ED_UNDEFINED, 659 | ED_UNDEFINED, 660 | 661 | IN_R_C, 662 | OUT_C_R, 663 | SBC_HL_RR, 664 | LD_INDIRECT_NN_RR, 665 | NEG, 666 | RETI_RETN, 667 | IM_N, 668 | LD_I_A_LD_R_A, 669 | 670 | IN_R_C, 671 | OUT_C_R, 672 | ADC_HL_RR, 673 | LD_RR_INDIRECT_NN, 674 | NEG, 675 | RETI_RETN, 676 | IM_N, 677 | LD_I_A_LD_R_A, 678 | 679 | IN_R_C, 680 | OUT_C_R, 681 | SBC_HL_RR, 682 | LD_INDIRECT_NN_RR, 683 | NEG, 684 | RETI_RETN, 685 | IM_N, 686 | LD_A_I_LD_A_R, 687 | 688 | IN_R_C, 689 | OUT_C_R, 690 | ADC_HL_RR, 691 | LD_RR_INDIRECT_NN, 692 | NEG, 693 | RETI_RETN, 694 | IM_N, 695 | LD_A_I_LD_A_R, 696 | 697 | IN_R_C, 698 | OUT_C_R, 699 | SBC_HL_RR, 700 | LD_INDIRECT_NN_RR, 701 | NEG, 702 | RETI_RETN, 703 | IM_N, 704 | RLD_RRD, 705 | 706 | IN_R_C, 707 | OUT_C_R, 708 | ADC_HL_RR, 709 | LD_RR_INDIRECT_NN, 710 | NEG, 711 | RETI_RETN, 712 | IM_N, 713 | RLD_RRD, 714 | 715 | IN_R_C, 716 | OUT_C_R, 717 | SBC_HL_RR, 718 | LD_INDIRECT_NN_RR, 719 | NEG, 720 | RETI_RETN, 721 | IM_N, 722 | ED_UNDEFINED, 723 | 724 | IN_R_C, 725 | OUT_C_R, 726 | ADC_HL_RR, 727 | LD_RR_INDIRECT_NN, 728 | NEG, 729 | RETI_RETN, 730 | IM_N, 731 | ED_UNDEFINED, 732 | 733 | ED_UNDEFINED, 734 | ED_UNDEFINED, 735 | ED_UNDEFINED, 736 | ED_UNDEFINED, 737 | ED_UNDEFINED, 738 | ED_UNDEFINED, 739 | ED_UNDEFINED, 740 | ED_UNDEFINED, 741 | 742 | ED_UNDEFINED, 743 | ED_UNDEFINED, 744 | ED_UNDEFINED, 745 | ED_UNDEFINED, 746 | ED_UNDEFINED, 747 | ED_UNDEFINED, 748 | ED_UNDEFINED, 749 | ED_UNDEFINED, 750 | 751 | ED_UNDEFINED, 752 | ED_UNDEFINED, 753 | ED_UNDEFINED, 754 | ED_UNDEFINED, 755 | ED_UNDEFINED, 756 | ED_UNDEFINED, 757 | ED_UNDEFINED, 758 | ED_UNDEFINED, 759 | 760 | ED_UNDEFINED, 761 | ED_UNDEFINED, 762 | ED_UNDEFINED, 763 | ED_UNDEFINED, 764 | ED_UNDEFINED, 765 | ED_UNDEFINED, 766 | ED_UNDEFINED, 767 | ED_UNDEFINED, 768 | 769 | LDI_LDD, 770 | CPI_CPD, 771 | INI_IND, 772 | OUTI_OUTD, 773 | ED_UNDEFINED, 774 | ED_UNDEFINED, 775 | ED_UNDEFINED, 776 | ED_UNDEFINED, 777 | 778 | LDI_LDD, 779 | CPI_CPD, 780 | INI_IND, 781 | OUTI_OUTD, 782 | ED_UNDEFINED, 783 | ED_UNDEFINED, 784 | ED_UNDEFINED, 785 | ED_UNDEFINED, 786 | 787 | LDIR_LDDR, 788 | CPIR_CPDR, 789 | INIR_INDR, 790 | OTIR_OTDR, 791 | ED_UNDEFINED, 792 | ED_UNDEFINED, 793 | ED_UNDEFINED, 794 | ED_UNDEFINED, 795 | 796 | LDIR_LDDR, 797 | CPIR_CPDR, 798 | INIR_INDR, 799 | OTIR_OTDR, 800 | ED_UNDEFINED, 801 | ED_UNDEFINED, 802 | ED_UNDEFINED, 803 | ED_UNDEFINED, 804 | 805 | ED_UNDEFINED, 806 | ED_UNDEFINED, 807 | ED_UNDEFINED, 808 | ED_UNDEFINED, 809 | ED_UNDEFINED, 810 | ED_UNDEFINED, 811 | ED_UNDEFINED, 812 | ED_UNDEFINED, 813 | 814 | ED_UNDEFINED, 815 | ED_UNDEFINED, 816 | ED_UNDEFINED, 817 | ED_UNDEFINED, 818 | ED_UNDEFINED, 819 | ED_UNDEFINED, 820 | ED_UNDEFINED, 821 | ED_UNDEFINED, 822 | 823 | ED_UNDEFINED, 824 | ED_UNDEFINED, 825 | ED_UNDEFINED, 826 | ED_UNDEFINED, 827 | ED_UNDEFINED, 828 | ED_UNDEFINED, 829 | ED_UNDEFINED, 830 | ED_UNDEFINED, 831 | 832 | ED_UNDEFINED, 833 | ED_UNDEFINED, 834 | ED_UNDEFINED, 835 | ED_UNDEFINED, 836 | ED_UNDEFINED, 837 | ED_UNDEFINED, 838 | ED_UNDEFINED, 839 | ED_UNDEFINED, 840 | 841 | ED_UNDEFINED, 842 | ED_UNDEFINED, 843 | ED_UNDEFINED, 844 | ED_UNDEFINED, 845 | ED_UNDEFINED, 846 | ED_UNDEFINED, 847 | ED_UNDEFINED, 848 | ED_UNDEFINED, 849 | 850 | ED_UNDEFINED, 851 | ED_UNDEFINED, 852 | ED_UNDEFINED, 853 | ED_UNDEFINED, 854 | ED_UNDEFINED, 855 | ED_UNDEFINED, 856 | ED_UNDEFINED, 857 | ED_UNDEFINED, 858 | 859 | ED_UNDEFINED, 860 | ED_UNDEFINED, 861 | ED_UNDEFINED, 862 | ED_UNDEFINED, 863 | ED_UNDEFINED, 864 | ED_UNDEFINED, 865 | ED_UNDEFINED, 866 | ED_UNDEFINED, 867 | 868 | ED_UNDEFINED, 869 | ED_UNDEFINED, 870 | ED_UNDEFINED, 871 | ED_UNDEFINED, 872 | ED_UNDEFINED, 873 | ED_UNDEFINED, 874 | ED_UNDEFINED, 875 | ED_UNDEFINED, 876 | 877 | }; 878 | 879 | static const unsigned char SZYX_FLAGS_TABLE[256] = { 880 | 881 | 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 882 | 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 883 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 884 | 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 885 | 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 886 | 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 887 | 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 888 | 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 889 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 890 | 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 891 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 892 | 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 893 | 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 894 | 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 895 | 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 896 | 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 897 | 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 898 | 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 899 | 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 900 | 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 901 | 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 902 | 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 903 | 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 904 | 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 905 | 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 906 | 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 907 | 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 908 | 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 909 | 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 910 | 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 911 | 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 912 | 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 913 | 914 | }; 915 | 916 | static const unsigned char SZYXP_FLAGS_TABLE[256] = { 917 | 918 | 0x44, 0x00, 0x00, 0x04, 0x00, 0x04, 0x04, 0x00, 919 | 0x08, 0x0c, 0x0c, 0x08, 0x0c, 0x08, 0x08, 0x0c, 920 | 0x00, 0x04, 0x04, 0x00, 0x04, 0x00, 0x00, 0x04, 921 | 0x0c, 0x08, 0x08, 0x0c, 0x08, 0x0c, 0x0c, 0x08, 922 | 0x20, 0x24, 0x24, 0x20, 0x24, 0x20, 0x20, 0x24, 923 | 0x2c, 0x28, 0x28, 0x2c, 0x28, 0x2c, 0x2c, 0x28, 924 | 0x24, 0x20, 0x20, 0x24, 0x20, 0x24, 0x24, 0x20, 925 | 0x28, 0x2c, 0x2c, 0x28, 0x2c, 0x28, 0x28, 0x2c, 926 | 0x00, 0x04, 0x04, 0x00, 0x04, 0x00, 0x00, 0x04, 927 | 0x0c, 0x08, 0x08, 0x0c, 0x08, 0x0c, 0x0c, 0x08, 928 | 0x04, 0x00, 0x00, 0x04, 0x00, 0x04, 0x04, 0x00, 929 | 0x08, 0x0c, 0x0c, 0x08, 0x0c, 0x08, 0x08, 0x0c, 930 | 0x24, 0x20, 0x20, 0x24, 0x20, 0x24, 0x24, 0x20, 931 | 0x28, 0x2c, 0x2c, 0x28, 0x2c, 0x28, 0x28, 0x2c, 932 | 0x20, 0x24, 0x24, 0x20, 0x24, 0x20, 0x20, 0x24, 933 | 0x2c, 0x28, 0x28, 0x2c, 0x28, 0x2c, 0x2c, 0x28, 934 | 0x80, 0x84, 0x84, 0x80, 0x84, 0x80, 0x80, 0x84, 935 | 0x8c, 0x88, 0x88, 0x8c, 0x88, 0x8c, 0x8c, 0x88, 936 | 0x84, 0x80, 0x80, 0x84, 0x80, 0x84, 0x84, 0x80, 937 | 0x88, 0x8c, 0x8c, 0x88, 0x8c, 0x88, 0x88, 0x8c, 938 | 0xa4, 0xa0, 0xa0, 0xa4, 0xa0, 0xa4, 0xa4, 0xa0, 939 | 0xa8, 0xac, 0xac, 0xa8, 0xac, 0xa8, 0xa8, 0xac, 940 | 0xa0, 0xa4, 0xa4, 0xa0, 0xa4, 0xa0, 0xa0, 0xa4, 941 | 0xac, 0xa8, 0xa8, 0xac, 0xa8, 0xac, 0xac, 0xa8, 942 | 0x84, 0x80, 0x80, 0x84, 0x80, 0x84, 0x84, 0x80, 943 | 0x88, 0x8c, 0x8c, 0x88, 0x8c, 0x88, 0x88, 0x8c, 944 | 0x80, 0x84, 0x84, 0x80, 0x84, 0x80, 0x80, 0x84, 945 | 0x8c, 0x88, 0x88, 0x8c, 0x88, 0x8c, 0x8c, 0x88, 946 | 0xa0, 0xa4, 0xa4, 0xa0, 0xa4, 0xa0, 0xa0, 0xa4, 947 | 0xac, 0xa8, 0xa8, 0xac, 0xa8, 0xac, 0xac, 0xa8, 948 | 0xa4, 0xa0, 0xa0, 0xa4, 0xa0, 0xa4, 0xa4, 0xa0, 949 | 0xa8, 0xac, 0xac, 0xa8, 0xac, 0xa8, 0xa8, 0xac, 950 | 951 | }; 952 | -------------------------------------------------------------------------------- /macros.h: -------------------------------------------------------------------------------- 1 | /* macros.h 2 | * Helper macros definitions. 3 | * 4 | * Copyright (c) 2012-2017 Lin Ke-Fong 5 | * 6 | * This code is free, do whatever you want with it. 7 | */ 8 | 9 | /* Shortcuts for flags and registers. */ 10 | 11 | #define SZC_FLAGS (Z80_S_FLAG | Z80_Z_FLAG | Z80_C_FLAG) 12 | #define YX_FLAGS (Z80_Y_FLAG | Z80_X_FLAG) 13 | #define SZ_FLAGS (Z80_S_FLAG | Z80_Z_FLAG) 14 | #define SZPV_FLAGS (Z80_S_FLAG | Z80_Z_FLAG | Z80_PV_FLAG) 15 | #define SYX_FLAGS (Z80_S_FLAG | Z80_Y_FLAG | Z80_X_FLAG) 16 | #define HC_FLAGS (Z80_H_FLAG | Z80_C_FLAG) 17 | 18 | #define A (state->registers.byte[Z80_A]) 19 | #define F (state->registers.byte[Z80_F]) 20 | #define B (state->registers.byte[Z80_B]) 21 | #define C (state->registers.byte[Z80_C]) 22 | 23 | #define AF (state->registers.word[Z80_AF]) 24 | #define BC (state->registers.word[Z80_BC]) 25 | #define DE (state->registers.word[Z80_DE]) 26 | #define HL (state->registers.word[Z80_HL]) 27 | #define SP (state->registers.word[Z80_SP]) 28 | 29 | #define HL_IX_IY *((unsigned short *) registers[6]) 30 | 31 | /* Opcode decoding macros. Y() is bits 5-3 of the opcode, Z() is bits 2-0, 32 | * P() bits 5-4, and Q() bits 4-3. 33 | */ 34 | 35 | #define Y(opcode) (((opcode) >> 3) & 0x07) 36 | #define Z(opcode) ((opcode) & 0x07) 37 | #define P(opcode) (((opcode) >> 4) & 0x03) 38 | #define Q(opcode) (((opcode) >> 3) & 0x03) 39 | 40 | /* Registers and conditions are decoded using tables in encodings.h. S() is 41 | * for the special cases "LD H/L, (IX/Y + d)" and "LD (IX/Y + d), H/L". 42 | */ 43 | 44 | #define R(r) *((unsigned char *) (registers[(r)])) 45 | #define S(s) *((unsigned char *) state->register_table[(s)]) 46 | #define RR(rr) *((unsigned short *) registers[(rr) + 8]) 47 | #define SS(ss) *((unsigned short *) registers[(ss) + 12]) 48 | #define CC(cc) ((F ^ XOR_CONDITION_TABLE[(cc)]) \ 49 | & AND_CONDITION_TABLE[(cc)]) 50 | #define DD(dd) CC(dd) 51 | 52 | /* Macros to read constants, displacements, or addresses from code. */ 53 | 54 | #define READ_N(n) \ 55 | { \ 56 | Z80_FETCH_BYTE(pc, (n)); \ 57 | pc++; \ 58 | elapsed_cycles += 3; \ 59 | } 60 | 61 | #define READ_NN(nn) \ 62 | { \ 63 | Z80_FETCH_WORD(pc, (nn)); \ 64 | pc += 2; \ 65 | elapsed_cycles += 6; \ 66 | } 67 | 68 | #define READ_D(d) \ 69 | { \ 70 | Z80_FETCH_BYTE(pc, (d)); \ 71 | (d) = (signed char) (d); \ 72 | pc++; \ 73 | elapsed_cycles += 3; \ 74 | } 75 | 76 | /* Macros to read and write data. */ 77 | 78 | #define READ_BYTE(address, x) \ 79 | { \ 80 | Z80_READ_BYTE((address), (x)); \ 81 | elapsed_cycles += 3; \ 82 | } 83 | 84 | #define WRITE_BYTE(address, x) \ 85 | { \ 86 | Z80_WRITE_BYTE((address), (x)); \ 87 | elapsed_cycles += 3; \ 88 | } 89 | 90 | #define READ_WORD(address, x) \ 91 | { \ 92 | Z80_READ_WORD((address), (x)); \ 93 | elapsed_cycles += 6; \ 94 | } 95 | 96 | #define WRITE_WORD(address, x) \ 97 | { \ 98 | Z80_WRITE_WORD((address), (x)); \ 99 | elapsed_cycles += 6; \ 100 | } 101 | 102 | /* Indirect (HL) and indexed (IX + d) or (IY + d) memory operands read and 103 | * write macros. 104 | */ 105 | 106 | #define READ_INDIRECT_HL(x) \ 107 | { \ 108 | if (registers == state->register_table) { \ 109 | \ 110 | READ_BYTE(HL, (x)); \ 111 | \ 112 | } else { \ 113 | \ 114 | int d; \ 115 | \ 116 | READ_D(d); \ 117 | d += HL_IX_IY; \ 118 | READ_BYTE(d, (x)); \ 119 | \ 120 | elapsed_cycles += 5; \ 121 | \ 122 | } \ 123 | } 124 | 125 | #define WRITE_INDIRECT_HL(x) \ 126 | { \ 127 | if (registers == state->register_table) { \ 128 | \ 129 | WRITE_BYTE(HL, (x)); \ 130 | \ 131 | } else { \ 132 | \ 133 | int d; \ 134 | \ 135 | READ_D(d); \ 136 | d += HL_IX_IY; \ 137 | WRITE_BYTE(d, (x)); \ 138 | \ 139 | elapsed_cycles += 5; \ 140 | \ 141 | } \ 142 | } 143 | 144 | /* Stack operation macros. */ 145 | 146 | #define PUSH(x) \ 147 | { \ 148 | SP -= 2; \ 149 | WRITE_WORD(SP, (x)); \ 150 | } 151 | 152 | #define POP(x) \ 153 | { \ 154 | READ_WORD(SP, (x)); \ 155 | SP += 2; \ 156 | } 157 | 158 | /* Exchange macro. */ 159 | 160 | #define EXCHANGE(a, b) \ 161 | { \ 162 | int t; \ 163 | \ 164 | t = (a); \ 165 | (a) = (b); \ 166 | (b) = t; \ 167 | } 168 | 169 | /* 8-bit arithmetic and logic operations. */ 170 | 171 | #define ADD(x) \ 172 | { \ 173 | int a, z, c, f; \ 174 | \ 175 | a = A; \ 176 | z = a + (x); \ 177 | \ 178 | c = a ^ (x) ^ z; \ 179 | f = c & Z80_H_FLAG; \ 180 | f |= SZYX_FLAGS_TABLE[z & 0xff]; \ 181 | f |= OVERFLOW_TABLE[c >> 7]; \ 182 | f |= z >> (8 - Z80_C_FLAG_SHIFT); \ 183 | \ 184 | A = z; \ 185 | F = f; \ 186 | } 187 | 188 | #define ADC(x) \ 189 | { \ 190 | int a, z, c, f; \ 191 | \ 192 | a = A; \ 193 | z = a + (x) + (F & Z80_C_FLAG); \ 194 | \ 195 | c = a ^ (x) ^ z; \ 196 | f = c & Z80_H_FLAG; \ 197 | f |= SZYX_FLAGS_TABLE[z & 0xff]; \ 198 | f |= OVERFLOW_TABLE[c >> 7]; \ 199 | f |= z >> (8 - Z80_C_FLAG_SHIFT); \ 200 | \ 201 | A = z; \ 202 | F = f; \ 203 | } 204 | 205 | #define SUB(x) \ 206 | { \ 207 | int a, z, c, f; \ 208 | \ 209 | a = A; \ 210 | z = a - (x); \ 211 | \ 212 | c = a ^ (x) ^ z; \ 213 | f = Z80_N_FLAG | (c & Z80_H_FLAG); \ 214 | f |= SZYX_FLAGS_TABLE[z & 0xff]; \ 215 | c &= 0x0180; \ 216 | f |= OVERFLOW_TABLE[c >> 7]; \ 217 | f |= c >> (8 - Z80_C_FLAG_SHIFT); \ 218 | \ 219 | A = z; \ 220 | F = f; \ 221 | } 222 | 223 | #define SBC(x) \ 224 | { \ 225 | int a, z, c, f; \ 226 | \ 227 | a = A; \ 228 | z = a - (x) - (F & Z80_C_FLAG); \ 229 | \ 230 | c = a ^ (x) ^ z; \ 231 | f = Z80_N_FLAG | (c & Z80_H_FLAG); \ 232 | f |= SZYX_FLAGS_TABLE[z & 0xff]; \ 233 | c &= 0x0180; \ 234 | f |= OVERFLOW_TABLE[c >> 7]; \ 235 | f |= c >> (8 - Z80_C_FLAG_SHIFT); \ 236 | \ 237 | A = z; \ 238 | F = f; \ 239 | } 240 | 241 | #define AND(x) \ 242 | { \ 243 | F = SZYXP_FLAGS_TABLE[A &= (x)] | Z80_H_FLAG; \ 244 | } 245 | 246 | #define OR(x) \ 247 | { \ 248 | F = SZYXP_FLAGS_TABLE[A |= (x)]; \ 249 | } 250 | 251 | #define XOR(x) \ 252 | { \ 253 | F = SZYXP_FLAGS_TABLE[A ^= (x)]; \ 254 | } 255 | 256 | #define CP(x) \ 257 | { \ 258 | int a, z, c, f; \ 259 | \ 260 | a = A; \ 261 | z = a - (x); \ 262 | \ 263 | c = a ^ (x) ^ z; \ 264 | f = Z80_N_FLAG | (c & Z80_H_FLAG); \ 265 | f |= SZYX_FLAGS_TABLE[z & 0xff] & SZ_FLAGS; \ 266 | f |= (x) & YX_FLAGS; \ 267 | c &= 0x0180; \ 268 | f |= OVERFLOW_TABLE[c >> 7]; \ 269 | f |= c >> (8 - Z80_C_FLAG_SHIFT); \ 270 | \ 271 | F = f; \ 272 | } 273 | 274 | #define INC(x) \ 275 | { \ 276 | int z, c, f; \ 277 | \ 278 | z = (x) + 1; \ 279 | c = (x) ^ z; \ 280 | \ 281 | f = F & Z80_C_FLAG; \ 282 | f |= c & Z80_H_FLAG; \ 283 | f |= SZYX_FLAGS_TABLE[z & 0xff]; \ 284 | f |= OVERFLOW_TABLE[(c >> 7) & 0x03]; \ 285 | \ 286 | (x) = z; \ 287 | F = f; \ 288 | } 289 | 290 | #define DEC(x) \ 291 | { \ 292 | int z, c, f; \ 293 | \ 294 | z = (x) - 1; \ 295 | c = (x) ^ z; \ 296 | \ 297 | f = Z80_N_FLAG | (F & Z80_C_FLAG); \ 298 | f |= c & Z80_H_FLAG; \ 299 | f |= SZYX_FLAGS_TABLE[z & 0xff]; \ 300 | f |= OVERFLOW_TABLE[(c >> 7) & 0x03]; \ 301 | \ 302 | (x) = z; \ 303 | F = f; \ 304 | } 305 | 306 | /* 0xcb prefixed logical operations. */ 307 | 308 | #define RLC(x) \ 309 | { \ 310 | int c; \ 311 | \ 312 | c = (x) >> 7; \ 313 | (x) = ((x) << 1) | c; \ 314 | F = SZYXP_FLAGS_TABLE[(x) & 0xff] | c; \ 315 | } 316 | 317 | #define RL(x) \ 318 | { \ 319 | int c; \ 320 | \ 321 | c = (x) >> 7; \ 322 | (x) = ((x) << 1) | (F & Z80_C_FLAG); \ 323 | F = SZYXP_FLAGS_TABLE[(x) & 0xff] | c; \ 324 | } 325 | 326 | #define RRC(x) \ 327 | { \ 328 | int c; \ 329 | \ 330 | c = (x) & 0x01; \ 331 | (x) = ((x) >> 1) | (c << 7); \ 332 | F = SZYXP_FLAGS_TABLE[(x) & 0xff] | c; \ 333 | } 334 | 335 | #define RR_INSTRUCTION(x) \ 336 | { \ 337 | int c; \ 338 | \ 339 | c = (x) & 0x01; \ 340 | (x) = ((x) >> 1) | ((F & Z80_C_FLAG) << 7); \ 341 | F = SZYXP_FLAGS_TABLE[(x) & 0xff] | c; \ 342 | } 343 | 344 | #define SLA(x) \ 345 | { \ 346 | int c; \ 347 | \ 348 | c = (x) >> 7; \ 349 | (x) <<= 1; \ 350 | F = SZYXP_FLAGS_TABLE[(x) & 0xff] | c; \ 351 | } 352 | 353 | #define SLL(x) \ 354 | { \ 355 | int c; \ 356 | \ 357 | c = (x) >> 7; \ 358 | (x) = ((x) << 1) | 0x01; \ 359 | F = SZYXP_FLAGS_TABLE[(x) & 0xff] | c; \ 360 | } 361 | 362 | #define SRA(x) \ 363 | { \ 364 | int c; \ 365 | \ 366 | c = (x) & 0x01; \ 367 | (x) = ((signed char) (x)) >> 1; \ 368 | F = SZYXP_FLAGS_TABLE[(x) & 0xff] | c; \ 369 | } 370 | 371 | #define SRL(x) \ 372 | { \ 373 | int c; \ 374 | \ 375 | c = (x) & 0x01; \ 376 | (x) >>= 1; \ 377 | F = SZYXP_FLAGS_TABLE[(x) & 0xff] | c; \ 378 | } 379 | -------------------------------------------------------------------------------- /maketables.c: -------------------------------------------------------------------------------- 1 | /* maketables.c 2 | * Instructions and flags tables generator. 3 | * 4 | * Copyright (c) 2012, 2016 Lin Ke-Fong 5 | * 6 | * This code is free, do whatever you want with it. 7 | */ 8 | 9 | #include 10 | #include 11 | #include "z80emu.h" 12 | 13 | /* Encoding for indirect or indexed 8-bit memory operands. */ 14 | 15 | #define INDIRECT_HL 0x06 16 | 17 | static void make_instruction_table (void); 18 | static void make_cb_instruction_table (void); 19 | static void make_ed_instruction_table (void); 20 | 21 | static void make_szyx_flags_table (void); 22 | static void make_szyxp_flags_table (void); 23 | 24 | int main (void) 25 | { 26 | printf("/* Generated file, see maketables.c. */\n\n"); 27 | 28 | make_instruction_table(); 29 | putchar('\n'); 30 | make_cb_instruction_table(); 31 | putchar('\n'); 32 | make_ed_instruction_table(); 33 | putchar('\n'); 34 | 35 | make_szyx_flags_table(); 36 | putchar('\n'); 37 | make_szyxp_flags_table(); 38 | 39 | return EXIT_SUCCESS; 40 | } 41 | 42 | /* Make single opcodes instruction table. */ 43 | 44 | static void make_instruction_table (void) 45 | { 46 | int i, j, k; 47 | char *s, *t; 48 | static char *accumulator_operations[8] = { 49 | 50 | "ADD", 51 | "ADC", 52 | "SUB", 53 | "SBC", 54 | "AND", 55 | "XOR", 56 | "OR", 57 | "CP", 58 | 59 | }; 60 | 61 | printf("static const unsigned char INSTRUCTION_TABLE[256] = {\n\n"); 62 | for (k = 0; k < (1 << 6); k++) { 63 | 64 | putchar('\t'); 65 | i = k >> 3; 66 | j = k & 0x07; 67 | switch (j) { 68 | 69 | /* Various opcodes. */ 70 | 71 | case 0x00: { 72 | 73 | static char *strings[8] = { 74 | 75 | "NOP", 76 | "EX_AF_AF_PRIME", 77 | "DJNZ_E", 78 | "JR_E", 79 | "JR_DD_E", 80 | "JR_DD_E", 81 | "JR_DD_E", 82 | "JR_DD_E", 83 | 84 | }; 85 | 86 | s = strings[i]; 87 | break; 88 | 89 | } 90 | 91 | /* LD_RR_NN and ADD_HL_RR. */ 92 | 93 | case 0x01: { 94 | 95 | s = i & 1 ? "ADD_HL_RR" : "LD_RR_NN"; 96 | break; 97 | 98 | } 99 | 100 | /* Indirect loading. */ 101 | 102 | case 0x02: { 103 | 104 | static char *strings[8] = { 105 | 106 | "LD_INDIRECT_BC_A", 107 | "LD_A_INDIRECT_BC", 108 | "LD_INDIRECT_DE_A", 109 | "LD_A_INDIRECT_DE", 110 | "LD_INDIRECT_NN_HL", 111 | "LD_HL_INDIRECT_NN", 112 | "LD_INDIRECT_NN_A", 113 | "LD_A_INDIRECT_NN", 114 | 115 | }; 116 | 117 | s = strings[i]; 118 | break; 119 | 120 | } 121 | 122 | /* 16-bit INC and DEC. */ 123 | 124 | case 0x03: { 125 | 126 | s = i & 1 ? "DEC_RR" : "INC_RR"; 127 | break; 128 | 129 | } 130 | 131 | /* 8-bit INC and DEC. */ 132 | 133 | case 0x04: 134 | case 0x05: { 135 | 136 | if (j == 0x04) 137 | 138 | printf("INC_"); 139 | 140 | else 141 | 142 | printf("DEC_"); 143 | 144 | if (i == INDIRECT_HL) 145 | 146 | s = "INDIRECT_HL"; 147 | 148 | else 149 | 150 | s = "R"; 151 | 152 | break; 153 | 154 | } 155 | 156 | /* Immediate 8-bit loading. */ 157 | 158 | case 0x06: { 159 | 160 | if (i == INDIRECT_HL) 161 | 162 | s = "LD_INDIRECT_HL_N"; 163 | 164 | else 165 | 166 | s = "LD_R_N"; 167 | 168 | break; 169 | 170 | } 171 | 172 | /* RLCA, RRCA, RLA, RRA, DAA, CPL, SCF, and CCF. */ 173 | 174 | case 0x07: 175 | default: { 176 | 177 | static char *strings[8] = { 178 | 179 | "RLCA", 180 | "RRCA", 181 | "RLA", 182 | "RRA", 183 | "DAA", 184 | "CPL", 185 | "SCF", 186 | "CCF", 187 | 188 | }; 189 | 190 | s = strings[i]; 191 | break; 192 | 193 | } 194 | 195 | } 196 | printf("%s,\n", s); 197 | if (j == 0x07) 198 | 199 | putchar('\n'); 200 | 201 | } 202 | 203 | /* 8-bit loading and HALT. */ 204 | 205 | for (k = 0; k < (1 << 6); k++) { 206 | 207 | i = k >> 3; 208 | j = k & 0x07; 209 | if (i == j) { 210 | 211 | if (i == INDIRECT_HL) 212 | 213 | s = "HALT"; 214 | 215 | else 216 | 217 | s = "NOP"; 218 | 219 | printf("\t%s,\n", s); 220 | 221 | } else { 222 | 223 | if (i == INDIRECT_HL) 224 | 225 | s = "LD_INDIRECT_HL_"; 226 | 227 | else 228 | 229 | s = "LD_R_"; 230 | 231 | if (j == INDIRECT_HL) 232 | 233 | t = "INDIRECT_HL"; 234 | 235 | else 236 | 237 | t = "R"; 238 | 239 | printf("\t%s%s,\n", s, t); 240 | 241 | } 242 | if (j == 0x07) 243 | 244 | putchar('\n'); 245 | 246 | } 247 | 248 | /* Operation on accumulator and register/memory. */ 249 | 250 | for (i = 0; i < (1 << 3); i++) { 251 | 252 | s = accumulator_operations[i]; 253 | for (j = 0; j < (1 << 3); j++) { 254 | 255 | printf("\t%s_", s); 256 | if (j == INDIRECT_HL) 257 | 258 | t = "INDIRECT_HL"; 259 | 260 | else 261 | 262 | t = "R"; 263 | 264 | printf("%s,\n", t); 265 | 266 | } 267 | putchar('\n'); 268 | 269 | } 270 | 271 | for (k = 0; k < (1 << 6); k++) { 272 | 273 | putchar('\t'); 274 | i = k >> 3; 275 | j = k & 0x07; 276 | switch (j) { 277 | 278 | /* RET CC. */ 279 | 280 | case 0x00: s = "RET_CC"; break; 281 | 282 | /* POP_SS, RET, EXX, JP_HL, and LD_SP_HL. */ 283 | 284 | case 0x01: { 285 | 286 | if (i & 1) { 287 | 288 | static char *strings[4] = { 289 | 290 | "RET", 291 | "EXX", 292 | "JP_HL", 293 | "LD_SP_HL", 294 | 295 | }; 296 | 297 | s = strings[i >> 1]; 298 | 299 | } else 300 | 301 | s = "POP_SS"; 302 | 303 | break; 304 | 305 | } 306 | 307 | /* JP CC, NN. */ 308 | 309 | case 0x02: s = "JP_CC_NN"; break; 310 | 311 | /* Various opcodes. */ 312 | 313 | case 0x03: { 314 | 315 | static char *strings[8] = { 316 | 317 | "JP_NN", 318 | "CB_PREFIX", 319 | "OUT_N_A", 320 | "IN_A_N", 321 | "EX_INDIRECT_SP_HL", 322 | "EX_DE_HL", 323 | "DI", 324 | "EI", 325 | 326 | }; 327 | 328 | s = strings[i]; 329 | break; 330 | 331 | } 332 | 333 | /* CALL_CC_NN. */ 334 | 335 | case 0x04: s = "CALL_CC_NN"; break; 336 | 337 | /* PUSH_SS, CALL_NN, and prefixes. */ 338 | 339 | case 0x05: { 340 | 341 | if (i & 1) { 342 | 343 | static char *strings[4] = { 344 | 345 | "CALL_NN", 346 | "DD_PREFIX", 347 | "ED_PREFIX", 348 | "FD_PREFIX", 349 | 350 | }; 351 | 352 | s = strings[i >> 1]; 353 | 354 | } else 355 | 356 | s = "PUSH_SS"; 357 | 358 | break; 359 | 360 | } 361 | 362 | /* Operation on accumulator and immediate. */ 363 | 364 | case 0x06: { 365 | 366 | printf("%s", accumulator_operations[i]); 367 | s = "_N"; 368 | break; 369 | 370 | } 371 | 372 | /* RST_P. */ 373 | 374 | case 0x07: 375 | default: s = "RST_P"; break; 376 | 377 | } 378 | printf("%s,\n", s); 379 | if (j == 0x07) 380 | 381 | putchar('\n'); 382 | 383 | } 384 | printf("};\n"); 385 | } 386 | 387 | /* Make 0xcb prefixed opcodes instruction table. */ 388 | 389 | static void make_cb_instruction_table (void) 390 | { 391 | int i; 392 | char *s; 393 | 394 | printf("static const unsigned char CB_INSTRUCTION_TABLE[256] = {\n\n"); 395 | 396 | /* Rotation/shift operations. */ 397 | 398 | for (i = 0; i < (1 << 6); i++) { 399 | 400 | static char *rotation_shift_operations[8] = { 401 | 402 | "RLC", 403 | "RRC", 404 | "RL", 405 | "RR", 406 | "SLA", 407 | "SRA", 408 | "SLL", 409 | "SRL", 410 | 411 | }; 412 | 413 | printf("\t%s_", rotation_shift_operations[i >> 3]); 414 | if ((i & 0x07) == INDIRECT_HL) 415 | 416 | s = "INDIRECT_HL"; 417 | 418 | else 419 | 420 | s = "R"; 421 | 422 | printf("%s,\n", s); 423 | if ((i & 0x07) == 0x07) 424 | 425 | putchar('\n'); 426 | 427 | } 428 | 429 | /* BIT_B_R and BIT_B_INDIRECT_HL. */ 430 | 431 | for (i = 0; i < (1 << 6); i++) { 432 | 433 | if ((i & 0x07) == INDIRECT_HL) 434 | 435 | s = "BIT_B_INDIRECT_HL"; 436 | 437 | else 438 | 439 | s = "BIT_B_R"; 440 | 441 | printf("\t%s,\n", s); 442 | if ((i & 0x07) == 0x07) 443 | 444 | putchar('\n'); 445 | 446 | } 447 | 448 | /* RES_B_R and RES_B_INDIRECT_HL. */ 449 | 450 | for (i = 0; i < (1 << 6); i++) { 451 | 452 | if ((i & 0x07) == INDIRECT_HL) 453 | 454 | s = "RES_B_INDIRECT_HL"; 455 | 456 | else 457 | 458 | s = "RES_B_R"; 459 | 460 | printf("\t%s,\n", s); 461 | if ((i & 0x07) == 0x07) 462 | 463 | putchar('\n'); 464 | 465 | } 466 | 467 | /* SET_B_R and SET_B_INDIRECT_HL. */ 468 | 469 | for (i = 0; i < (1 << 6); i++) { 470 | 471 | if ((i & 0x07) == INDIRECT_HL) 472 | 473 | s = "SET_B_INDIRECT_HL"; 474 | 475 | else 476 | 477 | s = "SET_B_R"; 478 | 479 | printf("\t%s,\n", s); 480 | if ((i & 0x07) == 0x07) 481 | 482 | putchar('\n'); 483 | 484 | } 485 | 486 | printf("};\n"); 487 | } 488 | 489 | /* Make 0xed prefixed opcodes instruction table. */ 490 | 491 | static void make_ed_instruction_table (void) 492 | { 493 | int i, j, k; 494 | char *s, *t; 495 | 496 | printf("static const unsigned char ED_INSTRUCTION_TABLE[256] = {\n\n"); 497 | 498 | /* Undefined opcodes are catched and will execute as NOPs. */ 499 | 500 | for (i = 0; i < (1 << 6); i++) { 501 | 502 | printf("\tED_UNDEFINED,\n"); 503 | if ((i & 0x07) == 0x07) 504 | 505 | putchar('\n'); 506 | 507 | } 508 | 509 | /* 0xed prefixed opcodes. */ 510 | 511 | for (k = 0; k < (1 << 6); k++) { 512 | 513 | i = k >> 3; 514 | j = k & 0x07; 515 | switch (j) { 516 | 517 | case 0x00: 518 | case 0x01: { 519 | 520 | s = j ? "OUT_C_R" : "IN_R_C"; 521 | t = ""; 522 | break; 523 | 524 | } 525 | 526 | /* SBC_HL_RR and ADC_HL_RR. */ 527 | 528 | case 0x02: { 529 | 530 | s = i & 1 ? "ADC" : "SBC"; 531 | t = "_HL_RR"; 532 | break; 533 | 534 | } 535 | 536 | /* LD_INDIRECT_NN_RR and LD_RR_INDIRECT_NN. */ 537 | 538 | case 0x03: { 539 | 540 | s = "LD_"; 541 | t = i & 1 542 | ? "RR_INDIRECT_NN" 543 | : "INDIRECT_NN_RR"; 544 | break; 545 | 546 | } 547 | 548 | /* NEG and IM_N. */ 549 | 550 | case 0x04: 551 | case 0x06: { 552 | 553 | s = j == 0x04 ? "NEG" : "IM_N"; 554 | t = ""; 555 | break; 556 | 557 | } 558 | 559 | /* RETN and RETI. */ 560 | 561 | case 0x05: { 562 | 563 | s = "RETI_RETN"; 564 | t = ""; 565 | break; 566 | 567 | } 568 | 569 | /* Various opcodes. */ 570 | 571 | case 0x07: 572 | default: { 573 | 574 | static char *strings[8] = { 575 | 576 | "LD_I_A_LD_R_A", 577 | "LD_I_A_LD_R_A", 578 | "LD_A_I_LD_A_R", 579 | "LD_A_I_LD_A_R", 580 | "RLD_RRD", 581 | "RLD_RRD", 582 | "ED_UNDEFINED", 583 | "ED_UNDEFINED", 584 | 585 | }; 586 | s = strings[i]; 587 | t = ""; 588 | break; 589 | 590 | } 591 | 592 | } 593 | printf("\t%s%s,\n", s, t); 594 | if ((j & 0x07) == 0x07) 595 | 596 | putchar('\n'); 597 | 598 | } 599 | 600 | /* Block instructions opcodes. */ 601 | 602 | for (k = 0; k < (1 << 6); k++) { 603 | 604 | static char *strings[4][4] = { 605 | 606 | { 607 | 608 | "LDI_LDD", 609 | "CPI_CPD", 610 | "INI_IND", 611 | "OUTI_OUTD", 612 | 613 | }, 614 | 615 | { 616 | 617 | "LDI_LDD", 618 | "CPI_CPD", 619 | "INI_IND", 620 | "OUTI_OUTD", 621 | 622 | }, 623 | 624 | { 625 | 626 | "LDIR_LDDR", 627 | "CPIR_CPDR", 628 | "INIR_INDR", 629 | "OTIR_OTDR", 630 | 631 | }, 632 | 633 | { 634 | 635 | "LDIR_LDDR", 636 | "CPIR_CPDR", 637 | "INIR_INDR", 638 | "OTIR_OTDR", 639 | 640 | }, 641 | 642 | }; 643 | i = k >> 3; 644 | j = k & 0x07; 645 | if (i < 4 || j > 3) 646 | 647 | s = "ED_UNDEFINED"; 648 | 649 | else 650 | 651 | s = strings[i - 4][j]; 652 | 653 | printf("\t%s, \n", s); 654 | if ((j & 0x07) == 0x07) 655 | 656 | putchar('\n'); 657 | 658 | } 659 | 660 | for (i = 0; i < (1 << 6); i++) { 661 | 662 | printf("\tED_UNDEFINED,\n"); 663 | if ((i & 0x07) == 0x07) 664 | 665 | putchar('\n'); 666 | 667 | } 668 | 669 | printf("};\n"); 670 | } 671 | 672 | /* Make S, Z, Y, and X flags table. */ 673 | 674 | static void make_szyx_flags_table (void) 675 | { 676 | int i; 677 | 678 | printf("static const unsigned char SZYX_FLAGS_TABLE[256] = {\n"); 679 | for (i = 0; i < 256; i++) { 680 | 681 | int r; 682 | 683 | r = i & (Z80_S_FLAG | Z80_Y_FLAG | Z80_X_FLAG); 684 | r |= !i ? Z80_Z_FLAG : 0; 685 | 686 | if (!(i & 7)) 687 | 688 | printf("\n\t0x%02x, ", r); 689 | 690 | else 691 | 692 | printf("0x%02x, ", r); 693 | 694 | 695 | } 696 | printf("\n\n};\n"); 697 | } 698 | 699 | /* Make S, Z, Y, X, and P flags table. */ 700 | 701 | static void make_szyxp_flags_table (void) 702 | { 703 | int i; 704 | 705 | printf("static const unsigned char SZYXP_FLAGS_TABLE[256] = {\n"); 706 | for (i = 0; i < 256; i++) { 707 | 708 | int j, p, r; 709 | 710 | j = i; 711 | p = !0; 712 | while (j) { 713 | 714 | if (j & 1) 715 | 716 | p = !p; 717 | 718 | j >>= 1; 719 | 720 | } 721 | r = i & (Z80_S_FLAG | Z80_Y_FLAG | Z80_X_FLAG); 722 | r |= !i ? Z80_Z_FLAG : 0; 723 | r |= p ? Z80_PV_FLAG : 0; 724 | 725 | if (!(i & 7)) 726 | 727 | printf("\n\t0x%02x, ", r); 728 | 729 | else 730 | 731 | printf("0x%02x, ", r); 732 | 733 | } 734 | printf("\n\n};\n"); 735 | } 736 | -------------------------------------------------------------------------------- /testfiles/zexall.z80: -------------------------------------------------------------------------------- 1 | .title 'Z80 instruction set exerciser' 2 | 3 | ; zexlax.z80 - Z80 instruction set exerciser 4 | ; Copyright (C) 1994 Frank D. Cringle 5 | ; 6 | ; This program is free software; you can redistribute it and/or 7 | ; modify it under the terms of the GNU General Public License 8 | ; as published by the Free Software Foundation; either version 2 9 | ; of the License, or (at your option) any later version. 10 | ; 11 | ; This program is distributed in the hope that it will be useful, 12 | ; but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | ; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | ; GNU General Public License for more details. 15 | ; 16 | ; You should have received a copy of the GNU General Public License 17 | ; along with this program; if not, write to the Free Software 18 | ; Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 19 | 20 | aseg 21 | org 100h 22 | 23 | jp start 24 | 25 | ; machine state before test (needs to be at predictably constant address) 26 | msbt: ds 14 27 | spbt: ds 2 28 | 29 | ; For the purposes of this test program, the machine state consists of: 30 | ; a 2 byte memory operand, followed by 31 | ; the registers iy,ix,hl,de,bc,af,sp 32 | ; for a total of 16 bytes. 33 | 34 | ; The program tests instructions (or groups of similar instructions) 35 | ; by cycling through a sequence of machine states, executing the test 36 | ; instruction for each one and running a 32-bit crc over the resulting 37 | ; machine states. At the end of the sequence the crc is compared to 38 | ; an expected value that was found empirically on a real Z80. 39 | 40 | ; A test case is defined by a descriptor which consists of: 41 | ; a flag mask byte, 42 | ; the base case, 43 | ; the incement vector, 44 | ; the shift vector, 45 | ; the expected crc, 46 | ; a short descriptive message. 47 | ; 48 | ; The flag mask byte is used to prevent undefined flag bits from 49 | ; influencing the results. Documented flags are as per Mostek Z80 50 | ; Technical Manual. 51 | ; 52 | ; The next three parts of the descriptor are 20 byte vectors 53 | ; corresponding to a 4 byte instruction and a 16 byte machine state. 54 | ; The first part is the base case, which is the first test case of 55 | ; the sequence. This base is then modified according to the next 2 56 | ; vectors. Each 1 bit in the increment vector specifies a bit to be 57 | ; cycled in the form of a binary counter. For instance, if the byte 58 | ; corresponding to the accumulator is set to 0ffh in the increment 59 | ; vector, the test will be repeated for all 256 values of the 60 | ; accumulator. Note that 1 bits don't have to be contiguous. The 61 | ; number of test cases 'caused' by the increment vector is equal to 62 | ; 2^(number of 1 bits). The shift vector is similar, but specifies a 63 | ; set of bits in the test case that are to be successively inverted. 64 | ; Thus the shift vector 'causes' a number of test cases equal to the 65 | ; number of 1 bits in it. 66 | 67 | ; The total number of test cases is the product of those caused by the 68 | ; counter and shift vectors and can easily become unweildy. Each 69 | ; individual test case can take a few milliseconds to execute, due to 70 | ; the overhead of test setup and crc calculation, so test design is a 71 | ; compromise between coverage and execution time. 72 | 73 | ; This program is designed to detect differences between 74 | ; implementations and is not ideal for diagnosing the causes of any 75 | ; discrepancies. However, provided a reference implementation (or 76 | ; real system) is available, a failing test case can be isolated by 77 | ; hand using a binary search of the test space. 78 | 79 | 80 | start: ld hl,(6) 81 | ld sp,hl 82 | ld de,msg1 83 | ld c,9 84 | call bdos 85 | 86 | ld hl,tests ; first test case 87 | loop: ld a,(hl) ; end of list ? 88 | inc hl 89 | or (hl) 90 | jp z,done 91 | dec hl 92 | call stt 93 | jp loop 94 | 95 | done: ld de,msg2 96 | ld c,9 97 | call bdos 98 | jp 0 ; warm boot 99 | 100 | tests: 101 | dw adc16 102 | dw add16 103 | dw add16x 104 | dw add16y 105 | dw alu8i 106 | dw alu8r 107 | dw alu8rx 108 | dw alu8x 109 | dw bitx 110 | dw bitz80 111 | dw cpd1 112 | dw cpi1 113 | dw daa 114 | dw inca 115 | dw incb 116 | dw incbc 117 | dw incc 118 | dw incd 119 | dw incde 120 | dw ince 121 | dw inch 122 | dw inchl 123 | dw incix 124 | dw inciy 125 | dw incl 126 | dw incm 127 | dw incsp 128 | dw incx 129 | dw incxh 130 | dw incxl 131 | dw incyh 132 | dw incyl 133 | dw ld161 134 | dw ld162 135 | dw ld163 136 | dw ld164 137 | dw ld165 138 | dw ld166 139 | dw ld167 140 | dw ld168 141 | dw ld16im 142 | dw ld16ix 143 | dw ld8bd 144 | dw ld8im 145 | dw ld8imx 146 | dw ld8ix1 147 | dw ld8ix2 148 | dw ld8ix3 149 | dw ld8ixy 150 | dw ld8rr 151 | dw ld8rrx 152 | dw lda 153 | dw ldd1 154 | dw ldd2 155 | dw ldi1 156 | dw ldi2 157 | dw neg 158 | dw rld 159 | dw rot8080 160 | dw rotxy 161 | dw rotz80 162 | dw srz80 163 | dw srzx 164 | dw st8ix1 165 | dw st8ix2 166 | dw st8ix3 167 | dw stabd 168 | dw 0 169 | 170 | tstr: macro insn,memop,iy,ix,hl,de,bc,flags,acc,sp 171 | local lab 172 | &lab: db insn 173 | ds &lab+4-$,0 174 | dw &memop,&iy,&ix,&hl,&de,&bc 175 | db &flags 176 | db &acc 177 | dw &sp 178 | if $-&lab ne 20 179 | error 'missing parameter' 180 | endif 181 | endm 182 | 183 | tmsg: macro m 184 | local lab 185 | &lab: db m 186 | if $ ge &lab+30 187 | error 'message too long' 188 | else 189 | ds &lab+30-$,'.' 190 | endif 191 | db '$' 192 | endm 193 | 194 | ; hl, (38,912 cycles) 195 | adc16: db 0ffh ; flag mask 196 | tstr <0edh,042h>,0832ch,04f88h,0f22bh,0b339h,07e1fh,01563h,0d3h,089h,0465eh 197 | tstr <0,038h>,0,0,0,0f821h,0,0,0,0,0 ; (1024 cycles) 198 | tstr 0,0,0,0,-1,-1,-1,0d7h,0,-1 ; (38 cycles) 199 | db 0d4h,08ah,0d5h,019h ; expected crc 200 | tmsg ' hl,' 201 | 202 | ; add hl, (19,456 cycles) 203 | add16: db 0ffh ; flag mask 204 | tstr 9,0c4a5h,0c4c7h,0d226h,0a050h,058eah,08566h,0c6h,0deh,09bc9h 205 | tstr 030h,0,0,0,0f821h,0,0,0,0,0 ; (512 cycles) 206 | tstr 0,0,0,0,-1,-1,-1,0d7h,0,-1 ; (38 cycles) 207 | db 0d9h,0a4h,0cah,005h ; expected crc 208 | tmsg 'add hl,' 209 | 210 | ; add ix, (19,456 cycles) 211 | add16x: db 0ffh ; flag mask 212 | tstr <0ddh,9>,0ddach,0c294h,0635bh,033d3h,06a76h,0fa20h,094h,068h,036f5h 213 | tstr <0,030h>,0,0,0f821h,0,0,0,0,0,0 ; (512 cycles) 214 | tstr 0,0,0,-1,0,-1,-1,0d7h,0,-1 ; (38 cycles) 215 | db 0b1h,0dfh,08eh,0c0h ; expected crc 216 | tmsg 'add ix,' 217 | 218 | ; add iy, (19,456 cycles) 219 | add16y: db 0ffh ; flag mask 220 | tstr <0fdh,9>,0c7c2h,0f407h,051c1h,03e96h,00bf4h,0510fh,092h,01eh,071eah 221 | tstr <0,030h>,0,0f821h,0,0,0,0,0,0,0 ; (512 cycles) 222 | tstr 0,0,-1,0,0,-1,-1,0d7h,0,-1 ; (38 cycles) 223 | db 039h,0c8h,058h,09bh ; expected crc 224 | tmsg 'add iy,' 225 | 226 | ; aluop a,nn (28,672 cycles) 227 | alu8i: db 0ffh ; flag mask 228 | tstr 0c6h,09140h,07e3ch,07a67h,0df6dh,05b61h,00b29h,010h,066h,085b2h 229 | tstr 038h,0,0,0,0,0,0,0,-1,0 ; (2048 cycles) 230 | tstr <0,-1>,0,0,0,0,0,0,0d7h,0,0 ; (14 cycles) 231 | db 051h,0c1h,09ch,02eh ; expected crc 232 | tmsg 'aluop a,nn' 233 | 234 | ; aluop a, (753,664 cycles) 235 | alu8r: db 0ffh ; flag mask 236 | tstr 080h,0c53eh,0573ah,04c4dh,msbt,0e309h,0a666h,0d0h,03bh,0adbbh 237 | tstr 03fh,0,0,0,0,0,0,0,-1,0 ; (16,384 cycles) 238 | tstr 0,0ffh,0,0,0,-1,-1,0d7h,0,0 ; (46 cycles) 239 | db 006h,0c7h,0aah,08eh ; expected crc 240 | tmsg 'aluop a,' 241 | 242 | ; aluop a, (376,832 cycles) 243 | alu8rx: db 0ffh ; flag mask 244 | tstr <0ddh,084h>,0d6f7h,0c76eh,0accfh,02847h,022ddh,0c035h,0c5h,038h,0234bh 245 | tstr <020h,039h>,0,0,0,0,0,0,0,-1,0 ; (8,192 cycles) 246 | tstr 0,0ffh,0,0,0,-1,-1,0d7h,0,0 ; (46 cycles) 247 | db 0a8h,086h,0cch,044h ; expected crc 248 | tmsg 'aluop a,' 249 | 250 | ; aluop a,(+1) (229,376 cycles) 251 | alu8x: db 0ffh ; flag mask 252 | tstr <0ddh,086h,1>,090b7h,msbt-1,msbt-1,032fdh,0406eh,0c1dch,045h,06eh,0e5fah 253 | tstr <020h,038h>,0,1,1,0,0,0,0,-1,0 ; (16,384 cycles) 254 | tstr 0,0ffh,0,0,0,0,0,0d7h,0,0 ; (14 cycles) 255 | db 0d3h,0f2h,0d7h,04ah ; expected crc 256 | tmsg 'aluop a,(+1)' 257 | 258 | ; bit n,(+1) (2048 cycles) 259 | bitx: db 0ffh ; flag mask 260 | tstr <0ddh,0cbh,1,046h>,02075h,msbt-1,msbt-1,03cfch,0a79ah,03d74h,051h,027h,0ca14h 261 | tstr <020h,0,0,038h>,0,0,0,0,0,0,053h,0,0 ; (256 cycles) 262 | tstr 0,0ffh,0,0,0,0,0,0,0,0 ; (8 cycles) 263 | db 083h,053h,04eh,0e1h ; expected crc 264 | tmsg 'bit n,(+1)' 265 | 266 | ; bit n, (49,152 cycles) 267 | bitz80: db 0ffh ; flag mask 268 | tstr <0cbh,040h>,03ef1h,09dfch,07acch,msbt,0be61h,07a86h,050h,024h,01998h 269 | tstr <0,03fh>,0,0,0,0,0,0,053h,0,0 ; (1024 cycles) 270 | tstr 0,0ffh,0,0,0,-1,-1,0,-1,0 ; (48 cycles) 271 | db 05eh,002h,00eh,098h ; expected crc 272 | tmsg 'bit n,' 273 | 274 | ; cpd (1) (6144 cycles) 275 | cpd1: db 0ffh ; flag mask 276 | tstr <0edh,0a9h>,0c7b6h,072b4h,018f6h,msbt+17,08dbdh,1,0c0h,030h,094a3h 277 | tstr <0,010h>,0,0,0,0,0,010,0,-1,0 ; (1024 cycles) 278 | tstr 0,0,0,0,0,0,0,0d7h,0,0 ; (6 cycles) 279 | db 013h,04bh,062h,02dh ; expected crc 280 | tmsg 'cpd' 281 | 282 | ; cpi (1) (6144 cycles) 283 | cpi1: db 0ffh ; flag mask 284 | tstr <0edh,0a1h>,04d48h,0af4ah,0906bh,msbt,04e71h,1,093h,06ah,0907ch 285 | tstr <0,010h>,0,0,0,0,0,010,0,-1,0 ; (1024 cycles) 286 | tstr 0,0,0,0,0,0,0,0d7h,0,0 ; (6 cycles) 287 | db 02dh,0a4h,02dh,019h ; expected crc 288 | tmsg 'cpi' 289 | 290 | ; 291 | daa: db 0ffh ; flag mask 292 | tstr 027h,02141h,009fah,01d60h,0a559h,08d5bh,09079h,004h,08eh,0299dh 293 | tstr 018h,0,0,0,0,0,0,0d7h,-1,0 ; (65,536 cycles) 294 | tstr 0,0,0,0,0,0,0,0,0,0 ; (1 cycle) 295 | db 06dh,02dh,0d2h,013h ; expected crc 296 | tmsg '' 297 | 298 | ; a (3072 cycles) 299 | inca: db 0ffh ; flag mask 300 | tstr 03ch,04adfh,0d5d8h,0e598h,08a2bh,0a7b0h,0431bh,044h,05ah,0d030h 301 | tstr 001h,0,0,0,0,0,0,0,-1,0 ; (512 cycles) 302 | tstr 0,0,0,0,0,0,0,0d7h,0,0 ; (6 cycles) 303 | db 081h,0fah,081h,000h ; expected crc 304 | tmsg ' a' 305 | 306 | ; b (3072 cycles) 307 | incb: db 0ffh ; flag mask 308 | tstr 004h,0d623h,0432dh,07a61h,08180h,05a86h,01e85h,086h,058h,09bbbh 309 | tstr 001h,0,0,0,0,0,0ff00h,0,0,0 ; (512 cycles) 310 | tstr 0,0,0,0,0,0,0,0d7h,0,0 ; (6 cycles) 311 | db 077h,0f3h,05ah,073h ; expected crc 312 | tmsg ' b' 313 | 314 | ; bc (1536 cycles) 315 | incbc: db 0ffh ; flag mask 316 | tstr 003h,0cd97h,044abh,08dc9h,0e3e3h,011cch,0e8a4h,002h,049h,02a4dh 317 | tstr 008h,0,0,0,0,0,0f821h,0,0,0 ; (256 cycles) 318 | tstr 0,0,0,0,0,0,0,0d7h,0,0 ; (6 cycles) 319 | db 0d2h,0aeh,03bh,0ech ; expected crc 320 | tmsg ' bc' 321 | 322 | ; c (3072 cycles) 323 | incc: db 0ffh ; flag mask 324 | tstr 00ch,0d789h,00935h,0055bh,09f85h,08b27h,0d208h,095h,005h,00660h 325 | tstr 001h,0,0,0,0,0,0ffh,0,0,0 ; (512 cycles) 326 | tstr 0,0,0,0,0,0,0,0d7h,0,0 ; (6 cycles) 327 | db 01ah,0f6h,012h,0a7h ; expected crc 328 | tmsg ' c' 329 | 330 | ; d (3072 cycles) 331 | incd: db 0ffh ; flag mask 332 | tstr 014h,0a0eah,05fbah,065fbh,0981ch,038cch,0debch,043h,05ch,003bdh 333 | tstr 001h,0,0,0,0,0ff00h,0,0,0,0 ; (512 cycles) 334 | tstr 0,0,0,0,0,0,0,0d7h,0,0 ; (6 cycles) 335 | db 0d1h,046h,0bfh,051h ; expected crc 336 | tmsg ' d' 337 | 338 | ; de (1536 cycles) 339 | incde: db 0ffh ; flag mask 340 | tstr 013h,0342eh,0131dh,028c9h,00acah,09967h,03a2eh,092h,0f6h,09d54h 341 | tstr 008h,0,0,0,0,0f821h,0,0,0,0 ; (256 cycles) 342 | tstr 0,0,0,0,0,0,0,0d7h,0,0 ; (6 cycles) 343 | db 0aeh,0c6h,0d4h,02ch ; expected crc 344 | tmsg ' de' 345 | 346 | ; e (3072 cycles) 347 | ince: db 0ffh ; flag mask 348 | tstr 01ch,0602fh,04c0dh,02402h,0e2f5h,0a0f4h,0a10ah,013h,032h,05925h 349 | tstr 001h,0,0,0,0,0ffh,0,0,0,0 ; (512 cycles) 350 | tstr 0,0,0,0,0,0,0,0d7h,0,0 ; (6 cycles) 351 | db 0cah,08ch,06ah,0c2h ; expected crc 352 | tmsg ' e' 353 | 354 | ; h (3072 cycles) 355 | inch: db 0ffh ; flag mask 356 | tstr 024h,01506h,0f2ebh,0e8ddh,0262bh,011a6h,0bc1ah,017h,006h,02818h 357 | tstr 001h,0,0,0,0ff00h,0,0,0,0,0 ; (512 cycles) 358 | tstr 0,0,0,0,0,0,0,0d7h,0,0 ; (6 cycles) 359 | db 056h,00fh,095h,05eh ; expected crc 360 | tmsg ' h' 361 | 362 | ; hl (1536 cycles) 363 | inchl: db 0ffh ; flag mask 364 | tstr 023h,0c3f4h,007a5h,01b6dh,04f04h,0e2c2h,0822ah,057h,0e0h,0c3e1h 365 | tstr 008h,0,0,0,0f821h,0,0,0,0,0 ; (256 cycles) 366 | tstr 0,0,0,0,0,0,0,0d7h,0,0 ; (6 cycles) 367 | db 0fch,00dh,06dh,04ah ; expected crc 368 | tmsg ' hl' 369 | 370 | ; ix (1536 cycles) 371 | incix: db 0ffh ; flag mask 372 | tstr <0ddh,023h>,0bc3ch,00d9bh,0e081h,0adfdh,09a7fh,096e5h,013h,085h,00be2h 373 | tstr <0,8>,0,0,0f821h,0,0,0,0,0,0 ; (256 cycles) 374 | tstr 0,0,0,0,0,0,0,0d7h,0,0 ; (6 cycles) 375 | db 0a5h,04dh,0beh,031h ; expected crc 376 | tmsg ' ix' 377 | 378 | ; iy (1536 cycles) 379 | inciy: db 0ffh ; flag mask 380 | tstr <0fdh,023h>,09402h,0637ah,03182h,0c65ah,0b2e9h,0abb4h,016h,0f2h,06d05h 381 | tstr <0,8>,0,0f821h,0,0,0,0,0,0,0 ; (256 cycles) 382 | tstr 0,0,0,0,0,0,0,0d7h,0,0 ; (6 cycles) 383 | db 050h,05dh,051h,0a3h ; expected crc 384 | tmsg ' iy' 385 | 386 | ; l (3072 cycles) 387 | incl: db 0ffh ; flag mask 388 | tstr 02ch,08031h,0a520h,04356h,0b409h,0f4c1h,0dfa2h,0d1h,03ch,03ea2h 389 | tstr 001h,0,0,0,0ffh,0,0,0,0,0 ; (512 cycles) 390 | tstr 0,0,0,0,0,0,0,0d7h,0,0 ; (6 cycles) 391 | db 0a0h,0a1h,0b4h,09fh ; expected crc 392 | tmsg ' l' 393 | 394 | ; (hl) (3072 cycles) 395 | incm: db 0ffh ; flag mask 396 | tstr 034h,0b856h,00c7ch,0e53eh,msbt,0877eh,0da58h,015h,05ch,01f37h 397 | tstr 001h,0ffh,0,0,0,0,0,0,0,0 ; (512 cycles) 398 | tstr 0,0,0,0,0,0,0,0d7h,0,0 ; (6 cycles) 399 | db 028h,029h,05eh,0ceh ; expected crc 400 | tmsg ' (hl)' 401 | 402 | ; sp (1536 cycles) 403 | incsp: db 0ffh ; flag mask 404 | tstr 033h,0346fh,0d482h,0d169h,0deb6h,0a494h,0f476h,053h,002h,0855bh 405 | tstr 008h,0,0,0,0,0,0,0,0,0f821h ; (256 cycles) 406 | tstr 0,0,0,0,0,0,0,0d7h,0,0 ; (6 cycles) 407 | db 05dh,0ach,0d5h,027h ; expected crc 408 | tmsg ' sp' 409 | 410 | ; (+1) (6144 cycles) 411 | incx: db 0ffh ; flag mask 412 | tstr <0ddh,034h,1>,0fa6eh,msbt-1,msbt-1,02c28h,08894h,05057h,016h,033h,0286fh 413 | tstr <020h,1>,0ffh,0,0,0,0,0,0,0,0 ; (1024 cycles) 414 | tstr 0,0,0,0,0,0,0,0d7h,0,0 ; (6 cycles) 415 | db 00bh,095h,0a8h,0eah ; expected crc 416 | tmsg ' (+1)' 417 | 418 | ; ixh (3072 cycles) 419 | incxh: db 0ffh ; flag mask 420 | tstr <0ddh,024h>,0b838h,0316ch,0c6d4h,03e01h,08358h,015b4h,081h,0deh,04259h 421 | tstr <0,1>,0,0ff00h,0,0,0,0,0,0,0 ; (512 cycles) 422 | tstr 0,0,0,0,0,0,0,0d7h,0,0 ; (6 cycles) 423 | db 06fh,046h,036h,062h ; expected crc 424 | tmsg ' ixh' 425 | 426 | ; ixl (3072 cycles) 427 | incxl: db 0ffh ; flag mask 428 | tstr <0ddh,02ch>,04d14h,07460h,076d4h,006e7h,032a2h,0213ch,0d6h,0d7h,099a5h 429 | tstr <0,1>,0,0ffh,0,0,0,0,0,0,0 ; (512 cycles) 430 | tstr 0,0,0,0,0,0,0,0d7h,0,0 ; (6 cycles) 431 | db 002h,07bh,0efh,02ch ; expected crc 432 | tmsg ' ixl' 433 | 434 | ; iyh (3072 cycles) 435 | incyh: db 0ffh ; flag mask 436 | tstr <0ddh,024h>,02836h,09f6fh,09116h,061b9h,082cbh,0e219h,092h,073h,0a98ch 437 | tstr <0,1>,0ff00h,0,0,0,0,0,0,0,0 ; (512 cycles) 438 | tstr 0,0,0,0,0,0,0,0d7h,0,0 ; (6 cycles) 439 | db 02dh,096h,06ch,0f3h ; expected crc 440 | tmsg ' iyh' 441 | 442 | ; iyl (3072 cycles) 443 | incyl: db 0ffh ; flag mask 444 | tstr <0ddh,02ch>,0d7c6h,062d5h,0a09eh,07039h,03e7eh,09f12h,090h,0d9h,0220fh 445 | tstr <0,1>,0ffh,0,0,0,0,0,0,0,0 ; (512 cycles) 446 | tstr 0,0,0,0,0,0,0,0d7h,0,0 ; (6 cycles) 447 | db 036h,0c1h,01eh,075h ; expected crc 448 | tmsg ' iyl' 449 | 450 | ; ld ,(nnnn) (32 cycles) 451 | ld161: db 0ffh ; flag mask 452 | tstr <0edh,04bh,low msbt,high msbt>,0f9a8h,0f559h,093a4h,0f5edh,06f96h,0d968h,086h,0e6h,04bd8h 453 | tstr <0,010h>,0,0,0,0,0,0,0,0,0 ; (2 cycles) 454 | tstr 0,-1,0,0,0,0,0,0,0,0 ; (16 cycles) 455 | db 04dh,045h,0a9h,0ach ; expected crc 456 | tmsg 'ld ,(nnnn)' 457 | 458 | ; ld hl,(nnnn) (16 cycles) 459 | ld162: db 0ffh ; flag mask 460 | tstr <02ah,low msbt,high msbt>,09863h,07830h,02077h,0b1feh,0b9fah,0abb8h,004h,006h,06015h 461 | tstr 0,0,0,0,0,0,0,0,0,0 ; (1 cycle) 462 | tstr 0,-1,0,0,0,0,0,0,0,0 ; (16 cycles) 463 | db 05fh,097h,024h,087h ; expected crc 464 | tmsg 'ld hl,(nnnn)' 465 | 466 | ; ld sp,(nnnn) (16 cycles) 467 | ld163: db 0ffh ; flag mask 468 | tstr <0edh,07bh,low msbt,high msbt>,08dfch,057d7h,02161h,0ca18h,0c185h,027dah,083h,01eh,0f460h 469 | tstr 0,0,0,0,0,0,0,0,0,0 ; (1 cycles) 470 | tstr 0,-1,0,0,0,0,0,0,0,0 ; (16 cycles) 471 | db 07ah,0ceh,0a1h,01bh ; expected crc 472 | tmsg 'ld sp,(nnnn)' 473 | 474 | ; ld ,(nnnn) (32 cycles) 475 | ld164: db 0ffh ; flag mask 476 | tstr <0ddh,02ah,low msbt,high msbt>,0ded7h,0a6fah,0f780h,0244ch,087deh,0bcc2h,016h,063h,04c96h 477 | tstr 020h,0,0,0,0,0,0,0,0,0 ; (2 cycles) 478 | tstr 0,-1,0,0,0,0,0,0,0,0 ; (16 cycles) 479 | db 085h,08bh,0f1h,06dh ; expected crc 480 | tmsg 'ld ,(nnnn)' 481 | 482 | ; ld (nnnn), (64 cycles) 483 | ld165: db 0ffh ; flag mask 484 | tstr <0edh,043h,low msbt,high msbt>,01f98h,0844dh,0e8ach,0c9edh,0c95dh,08f61h,080h,03fh,0c7bfh 485 | tstr <0,010h>,0,0,0,0,0,0,0,0,0 ; (2 cycles) 486 | tstr 0,0,0,0,0,-1,-1,0,0,0 ; (32 cycles) 487 | db 064h,01eh,087h,015h ; expected crc 488 | tmsg 'ld (nnnn),' 489 | 490 | ; ld (nnnn),hl (16 cycles) 491 | ld166: db 0ffh ; flag mask 492 | tstr <022h,low msbt,high msbt>,0d003h,07772h,07f53h,03f72h,064eah,0e180h,010h,02dh,035e9h 493 | tstr 0,0,0,0,0,0,0,0,0,0 ; (1 cycle) 494 | tstr 0,0,0,0,-1,0,0,0,0,0 ; (16 cycles) 495 | db 0a3h,060h,08bh,047h ; expected crc 496 | tmsg 'ld (nnnn),hl' 497 | 498 | ; ld (nnnn),sp (16 cycles) 499 | ld167: db 0ffh ; flag mask 500 | tstr <0edh,073h,low msbt,high msbt>,0c0dch,0d1d6h,0ed5ah,0f356h,0afdah,06ca7h,044h,09fh,03f0ah 501 | tstr 0,0,0,0,0,0,0,0,0,0 ; (1 cycle) 502 | tstr 0,0,0,0,0,0,0,0,0,-1 ; (16 cycles) 503 | db 016h,058h,05fh,0d7h ; expected crc 504 | tmsg 'ld (nnnn),sp' 505 | 506 | ; ld (nnnn), (64 cycles) 507 | ld168: db 0ffh ; flag mask 508 | tstr <0ddh,022h,low msbt,high msbt>,06cc3h,00d91h,06900h,08ef8h,0e3d6h,0c3f7h,0c6h,0d9h,0c2dfh 509 | tstr 020h,0,0,0,0,0,0,0,0,0 ; (2 cycles) 510 | tstr 0,0,-1,-1,0,0,0,0,0,0 ; (32 cycles) 511 | db 0bah,010h,02ah,06bh ; expected crc 512 | tmsg 'ld (nnnn),' 513 | 514 | ; ld ,nnnn (64 cycles) 515 | ld16im: db 0ffh ; flag mask 516 | tstr 1,05c1ch,02d46h,08eb9h,06078h,074b1h,0b30eh,046h,0d1h,030cch 517 | tstr 030h,0,0,0,0,0,0,0,0,0 ; (4 cycles) 518 | tstr <0,0ffh,0ffh>,0,0,0,0,0,0,0,0,0 ; (16 cycles) 519 | db 0deh,039h,019h,069h ; expected crc 520 | tmsg 'ld ,nnnn' 521 | 522 | ; ld ,nnnn (32 cycles) 523 | ld16ix: db 0ffh ; flag mask 524 | tstr <0ddh,021h>,087e8h,02006h,0bd12h,0b69bh,07253h,0a1e5h,051h,013h,0f1bdh 525 | tstr 020h,0,0,0,0,0,0,0,0,0 ; (2 cycles) 526 | tstr <0,0,0ffh,0ffh>,0,0,0,0,0,0,0,0,0 ; (16 cycles) 527 | db 022h,07dh,0d5h,025h ; expected crc 528 | tmsg 'ld ,nnnn' 529 | 530 | ; ld a,<(bc),(de)> (44 cycles) 531 | ld8bd: db 0ffh ; flag mask 532 | tstr 00ah,0b3a8h,01d2ah,07f8eh,042ach,msbt,msbt,0c6h,0b1h,0ef8eh 533 | tstr 010h,0,0,0,0,0,0,0,0,0 ; (2 cycles) 534 | tstr 0,0ffh,0,0,0,0,0,0d7h,-1,0 ; (22 cycles) 535 | db 0b0h,081h,089h,035h ; expected crc 536 | tmsg 'ld a,<(bc),(de)>' 537 | 538 | ; ld ,nn (64 cycles) 539 | ld8im: db 0ffh ; flag mask 540 | tstr 6,0c407h,0f49dh,0d13dh,00339h,0de89h,07455h,053h,0c0h,05509h 541 | tstr 038h,0,0,0,0,0,0,0,0,0 ; (8 cycles) 542 | tstr 0,0,0,0,0,0,0,0,-1,0 ; (8 cycles) 543 | db 0f1h,0dah,0b5h,056h ; expected crc 544 | tmsg 'ld ,nn' 545 | 546 | ; ld (+1),nn (32 cycles) 547 | ld8imx: db 0ffh ; flag mask 548 | tstr <0ddh,036h,1>,01b45h,msbt-1,msbt-1,0d5c1h,061c7h,0bdc4h,0c0h,085h,0cd16h 549 | tstr 020h,0,0,0,0,0,0,0,0,0 ; (2 cycles) 550 | tstr <0,0,0,-1>,0,0,0,0,0,0,0,-1,0 ; (16 cycles) 551 | db 026h,0dbh,047h,07eh ; expected crc 552 | tmsg 'ld (+1),nn' 553 | 554 | ; ld ,(+1) (512 cycles) 555 | ld8ix1: db 0ffh ; flag mask 556 | tstr <0ddh,046h,1>,0d016h,msbt-1,msbt-1,04260h,07f39h,00404h,097h,04ah,0d085h 557 | tstr <020h,018h>,0,1,1,0,0,0,0,0,0 ; (32 cycles) 558 | tstr 0,-1,0,0,0,0,0,0,0,0 ; (16 cycles) 559 | db 0cch,011h,006h,0a8h ; expected crc 560 | tmsg 'ld ,(+1)' 561 | 562 | ; ld ,(+1) (256 cycles) 563 | ld8ix2: db 0ffh ; flag mask 564 | tstr <0ddh,066h,1>,084e0h,msbt-1,msbt-1,09c52h,0a799h,049b6h,093h,000h,0eeadh 565 | tstr <020h,008h>,0,1,1,0,0,0,0,0,0 ; (16 cycles) 566 | tstr 0,-1,0,0,0,0,0,0,0,0 ; (16 cycles) 567 | db 0fah,02ah,04dh,003h ; expected crc 568 | tmsg 'ld ,(+1)' 569 | 570 | ; ld a,(+1) (128 cycles) 571 | ld8ix3: db 0ffh ; flag mask 572 | tstr <0ddh,07eh,1>,0d8b6h,msbt-1,msbt-1,0c612h,0df07h,09cd0h,043h,0a6h,0a0e5h 573 | tstr 020h,0,1,1,0,0,0,0,0,0 ; (8 cycles) 574 | tstr 0,-1,0,0,0,0,0,0,0,0 ; (16 cycles) 575 | db 0a5h,0e9h,0ach,064h ; expected crc 576 | tmsg 'ld a,(+1)' 577 | 578 | ; ld ,nn (32 cycles) 579 | ld8ixy: db 0ffh ; flag mask 580 | tstr <0ddh,026h>,03c53h,04640h,0e179h,07711h,0c107h,01afah,081h,0adh,05d9bh 581 | tstr <020h,8>,0,0,0,0,0,0,0,0,0 ; (4 cycles) 582 | tstr 0,0,0,0,0,0,0,0,-1,0 ; (8 cycles) 583 | db 024h,0e8h,082h,08bh ; expected crc 584 | tmsg 'ld ,nn' 585 | 586 | ; ld , (3456 cycles) 587 | ld8rr: db 0ffh ; flag mask 588 | tstr 040h,072a4h,0a024h,061ach,msbt,082c7h,0718fh,097h,08fh,0ef8eh 589 | tstr 03fh,0,0,0,0,0,0,0,0,0 ; (64 cycles) 590 | tstr 0,0ffh,0,0,0,-1,-1,0d7h,-1,0 ; (54 cycles) 591 | db 074h,04bh,001h,018h ; expected crc 592 | tmsg 'ld ,' 593 | 594 | ; ld , (6912 cycles) 595 | ld8rrx: db 0ffh ; flag mask 596 | tstr <0ddh,040h>,0bcc5h,msbt,msbt,msbt,02fc2h,098c0h,083h,01fh,03bcdh 597 | tstr <020h,03fh>,0,0,0,0,0,0,0,0,0 ; (128 cycles) 598 | tstr 0,0ffh,0,0,0,-1,-1,0d7h,-1,0 ; (54 cycles) 599 | db 047h,08bh,0a3h,06bh ; expected crc 600 | tmsg 'ld ,' 601 | 602 | ; ld a,(nnnn) / ld (nnnn),a (44 cycles) 603 | lda: db 0ffh ; flag mask 604 | tstr <032h,low msbt,high msbt>,0fd68h,0f4ech,044a0h,0b543h,00653h,0cdbah,0d2h,04fh,01fd8h 605 | tstr 008h,0,0,0,0,0,0,0,0,0 ; (2 cycle) 606 | tstr 0,0ffh,0,0,0,0,0,0d7h,-1,0 ; (22 cycles) 607 | db 0c9h,026h,02dh,0e5h ; expected crc 608 | tmsg 'ld a,(nnnn) / ld (nnnn),a' 609 | 610 | ; ldd (1) (44 cycles) 611 | ldd1: db 0ffh ; flag mask 612 | tstr <0edh,0a8h>,09852h,068fah,066a1h,msbt+3,msbt+1,1,0c1h,068h,020b7h 613 | tstr <0,010h>,0,0,0,0,0,0,0,0,0 ; (2 cycles) 614 | tstr 0,-1,0,0,0,0,0,0d7h,0,0 ; (22 cycles) 615 | db 094h,0f4h,027h,069h ; expected crc 616 | tmsg 'ldd (1)' 617 | 618 | ; ldd (2) (44 cycles) 619 | ldd2: db 0ffh ; flag mask 620 | tstr <0edh,0a8h>,0f12eh,0eb2ah,0d5bah,msbt+3,msbt+1,2,047h,0ffh,0fbe4h 621 | tstr <0,010h>,0,0,0,0,0,0,0,0,0 ; (2 cycles) 622 | tstr 0,-1,0,0,0,0,0,0d7h,0,0 ; (22 cycles) 623 | db 039h,0ddh,03dh,0e1h ; expected crc 624 | tmsg 'ldd (2)' 625 | 626 | ; ldi (1) (44 cycles) 627 | ldi1: db 0ffh ; flag mask 628 | tstr <0edh,0a0h>,0fe30h,003cdh,06058h,msbt+2,msbt,1,004h,060h,02688h 629 | tstr <0,010h>,0,0,0,0,0,0,0,0,0 ; (2 cycles) 630 | tstr 0,-1,0,0,0,0,0,0d7h,0,0 ; (22 cycles) 631 | db 0f7h,082h,0b0h,0d1h ; expected crc 632 | tmsg 'ldi (1)' 633 | 634 | ; ldi (2) (44 cycles) 635 | ldi2: db 0ffh ; flag mask 636 | tstr <0edh,0a0h>,04aceh,0c26eh,0b188h,msbt+2,msbt,2,014h,02dh,0a39fh 637 | tstr <0,010h>,0,0,0,0,0,0,0,0,0 ; (2 cycles) 638 | tstr 0,-1,0,0,0,0,0,0d7h,0,0 ; (22 cycles) 639 | db 0e9h,0eah,0d0h,0aeh ; expected crc 640 | tmsg 'ldi (2)' 641 | 642 | ; neg (16,384 cycles) 643 | neg: db 0ffh ; flag mask 644 | tstr <0edh,044h>,038a2h,05f6bh,0d934h,057e4h,0d2d6h,04642h,043h,05ah,009cch 645 | tstr 0,0,0,0,0,0,0,0d7h,-1,0 ; (16,384 cycles) 646 | tstr 0,0,0,0,0,0,0,0,0,0 ; (1 cycle) 647 | db 0d6h,038h,0ddh,06ah ; expected crc 648 | tmsg 'neg' 649 | 650 | ; (7168 cycles) 651 | rld: db 0ffh ; flag mask 652 | tstr <0edh,067h>,091cbh,0c48bh,0fa62h,msbt,0e720h,0b479h,040h,006h,08ae2h 653 | tstr <0,8>,0ffh,0,0,0,0,0,0,0,0 ; (512 cycles) 654 | tstr 0,0,0,0,0,0,0,0d7h,-1,0 ; (14 cycles) 655 | db 0ffh,082h,03eh,077h ; expected crc 656 | tmsg '' 657 | 658 | ; (6144 cycles) 659 | rot8080: db 0ffh ; flag mask 660 | tstr 7,0cb92h,06d43h,00a90h,0c284h,00c53h,0f50eh,091h,0ebh,040fch 661 | tstr 018h,0,0,0,0,0,0,0,-1,0 ; (1024 cycles) 662 | tstr 0,0,0,0,0,0,0,0d7h,0,0 ; (6 cycles) 663 | db 09bh,0a3h,080h,07ch ; expected crc 664 | tmsg '' 665 | 666 | ; shift/rotate (+1) (416 cycles) 667 | rotxy: db 0ffh ; flag mask 668 | tstr <0ddh,0cbh,1,6>,0ddafh,msbt-1,msbt-1,0ff3ch,0dbf6h,094f4h,082h,080h,061d9h 669 | tstr <020h,0,0,038h>,0,0,0,0,0,0,080h,0,0 ; (32 cycles) 670 | tstr 0,0ffh,0,0,0,0,0,057h,0,0 ; (13 cycles) 671 | db 071h,000h,034h,0cbh ; expected crc 672 | tmsg 'shf/rot (+1)' 673 | 674 | ; shift/rotate (6784 cycles) 675 | rotz80: db 0ffh ; flag mask 676 | tstr 0cbh,0ccebh,05d4ah,0e007h,msbt,01395h,030eeh,043h,078h,03dadh 677 | tstr <0,03fh>,0,0,0,0,0,0,080h,0,0 ; (128 cycles) 678 | tstr 0,0ffh,0,0,0,-1,-1,057h,-1,0 ; (53 cycles) 679 | db 0a4h,025h,058h,033h ; expected crc 680 | tmsg 'shf/rot ' 681 | 682 | ; n, (7936 cycles) 683 | srz80: db 0ffh ; flag mask 684 | tstr <0cbh,080h>,02cd5h,097abh,039ffh,msbt,0d14bh,06ab2h,053h,027h,0b538h 685 | tstr <0,07fh>,0,0,0,0,0,0,0,0,0 ; (128 cycles) 686 | tstr 0,0ffh,0,0,0,-1,-1,0d7h,-1,0 ; (62 cycles) 687 | db 08bh,057h,0f0h,008h ; expected crc 688 | tmsg ' n,' 689 | 690 | ; n,(+1) (1792 cycles) 691 | srzx: db 0ffh ; flag mask 692 | tstr <0ddh,0cbh,1,086h>,0fb44h,msbt-1,msbt-1,0ba09h,068beh,032d8h,010h,05eh,0a867h 693 | tstr <020h,0,0,078h>,0,0,0,0,0,0,0,0,0 ; (128 cycles) 694 | tstr 0,0ffh,0,0,0,0,0,0d7h,0,0 ;(14 cycles) 695 | db 0cch,063h,0f9h,08ah ; expected crc 696 | tmsg ' n,(+1)' 697 | 698 | ; ld (+1), (1024 cycles) 699 | st8ix1: db 0ffh ; flag mask 700 | tstr <0ddh,070h,1>,0270dh,msbt-1,msbt-1,0b73ah,0887bh,099eeh,086h,070h,0ca07h 701 | tstr <020h,003h>,0,1,1,0,0,0,0,0,0 ; (32 cycles) 702 | tstr 0,0,0,0,0,-1,-1,0,0,0 ; (32 cycles) 703 | db 004h,062h,06ah,0bfh ; expected crc 704 | tmsg 'ld (+1),' 705 | 706 | ; ld (+1), (256 cycles) 707 | st8ix2: db 0ffh ; flag mask 708 | tstr <0ddh,074h,1>,0b664h,msbt-1,msbt-1,0e8ach,0b5f5h,0aafeh,012h,010h,09566h 709 | tstr <020h,001h>,0,1,1,0,0,0,0,0,0 ; (16 cycles) 710 | tstr 0,0,0,0,-1,0,0,0,0,0 ; (32 cycles) 711 | db 06ah,01ah,088h,031h ; expected crc 712 | tmsg 'ld (+1),' 713 | 714 | ; ld (+1),a (64 cycles) 715 | st8ix3: db 0ffh ; flag mask 716 | tstr <0ddh,077h,1>,067afh,msbt-1,msbt-1,04f13h,00644h,0bcd7h,050h,0ach,05fafh 717 | tstr 020h,0,1,1,0,0,0,0,0,0 ; (8 cycles) 718 | tstr 0,0,0,0,0,0,0,0,-1,0 ; (8 cycles) 719 | db 0cch,0beh,05ah,096h ; expected crc 720 | tmsg 'ld (+1),a' 721 | 722 | ; ld (),a (96 cycles) 723 | stabd: db 0ffh ; flag mask 724 | tstr 2,00c3bh,0b592h,06cffh,0959eh,msbt,msbt+1,0c1h,021h,0bde7h 725 | tstr 018h,0,0,0,0,0,0,0,0,0 ; (4 cycles) 726 | tstr 0,-1,0,0,0,0,0,0,-1,0 ; (24 cycles) 727 | db 07ah,04ch,011h,04fh ; expected crc 728 | tmsg 'ld (),a' 729 | 730 | ; start test pointed to by (hl) 731 | stt: push hl 732 | ld a,(hl) ; get pointer to test 733 | inc hl 734 | ld h,(hl) 735 | ld l,a 736 | ld a,(hl) ; flag mask 737 | ld (flgmsk+1),a 738 | inc hl 739 | push hl 740 | ld de,20 741 | add hl,de ; point to incmask 742 | ld de,counter 743 | call initmask 744 | pop hl 745 | push hl 746 | ld de,20+20 747 | add hl,de ; point to scanmask 748 | ld de,shifter 749 | call initmask 750 | ld hl,shifter 751 | ld (hl),1 ; first bit 752 | pop hl 753 | push hl 754 | ld de,iut ; copy initial instruction under test 755 | ld bc,4 756 | ldir 757 | ld de,msbt ; copy initial machine state 758 | ld bc,16 759 | ldir 760 | ld de,20+20+4 ; skip incmask, scanmask and expcrc 761 | add hl,de 762 | ex de,hl 763 | ld c,9 764 | call bdos ; show test name 765 | call initcrc ; initialise crc 766 | ; test loop 767 | tlp: ld a,(iut) 768 | cp 076h ; pragmatically avoid halt intructions 769 | jp z,tlp2 770 | and a,0dfh 771 | cp 0ddh 772 | jp nz,tlp1 773 | ld a,(iut+1) 774 | cp 076h 775 | tlp1: call nz,test ; execute the test instruction 776 | tlp2: call count ; increment the counter 777 | call nz,shift ; shift the scan bit 778 | pop hl ; pointer to test case 779 | jp z,tlp3 ; done if shift returned NZ 780 | ld de,20+20+20 781 | add hl,de ; point to expected crc 782 | call cmpcrc 783 | ld de,okmsg 784 | jp z,tlpok 785 | ld de,ermsg1 786 | ld c,9 787 | call bdos 788 | call phex8 789 | ld de,ermsg2 790 | ld c,9 791 | call bdos 792 | ld hl,crcval 793 | call phex8 794 | ld de,crlf 795 | tlpok: ld c,9 796 | call bdos 797 | pop hl 798 | inc hl 799 | inc hl 800 | ret 801 | 802 | tlp3: push hl 803 | ld a,1 ; initialise count and shift scanners 804 | ld (cntbit),a 805 | ld (shfbit),a 806 | ld hl,counter 807 | ld (cntbyt),hl 808 | ld hl,shifter 809 | ld (shfbyt),hl 810 | 811 | ld b,4 ; bytes in iut field 812 | pop hl ; pointer to test case 813 | push hl 814 | ld de,iut 815 | call setup ; setup iut 816 | ld b,16 ; bytes in machine state 817 | ld de,msbt 818 | call setup ; setup machine state 819 | jp tlp 820 | 821 | ; setup a field of the test case 822 | ; b = number of bytes 823 | ; hl = pointer to base case 824 | ; de = destination 825 | setup: call subyte 826 | inc hl 827 | dec b 828 | jp nz,setup 829 | ret 830 | 831 | subyte: push bc 832 | push de 833 | push hl 834 | ld c,(hl) ; get base byte 835 | ld de,20 836 | add hl,de ; point to incmask 837 | ld a,(hl) 838 | cp 0 839 | jp z,subshf 840 | ld b,8 ; 8 bits 841 | subclp: rrca 842 | push af 843 | ld a,0 844 | call c,nxtcbit ; get next counter bit if mask bit was set 845 | xor c ; flip bit if counter bit was set 846 | rrca 847 | ld c,a 848 | pop af 849 | dec b 850 | jp nz,subclp 851 | ld b,8 852 | subshf: ld de,20 853 | add hl,de ; point to shift mask 854 | ld a,(hl) 855 | cp 0 856 | jp z,substr 857 | ld b,8 ; 8 bits 858 | sbshf1: rrca 859 | push af 860 | ld a,0 861 | call c,nxtsbit ; get next shifter bit if mask bit was set 862 | xor c ; flip bit if shifter bit was set 863 | rrca 864 | ld c,a 865 | pop af 866 | dec b 867 | jp nz,sbshf1 868 | substr: pop hl 869 | pop de 870 | ld a,c 871 | ld (de),a ; mangled byte to destination 872 | inc de 873 | pop bc 874 | ret 875 | 876 | ; get next counter bit in low bit of a 877 | cntbit: ds 1 878 | cntbyt: ds 2 879 | 880 | nxtcbit: push bc 881 | push hl 882 | ld hl,(cntbyt) 883 | ld b,(hl) 884 | ld hl,cntbit 885 | ld a,(hl) 886 | ld c,a 887 | rlca 888 | ld (hl),a 889 | cp a,1 890 | jp nz,ncb1 891 | ld hl,(cntbyt) 892 | inc hl 893 | ld (cntbyt),hl 894 | ncb1: ld a,b 895 | and c 896 | pop hl 897 | pop bc 898 | ret z 899 | ld a,1 900 | ret 901 | 902 | ; get next shifter bit in low bit of a 903 | shfbit: ds 1 904 | shfbyt: ds 2 905 | 906 | nxtsbit: push bc 907 | push hl 908 | ld hl,(shfbyt) 909 | ld b,(hl) 910 | ld hl,shfbit 911 | ld a,(hl) 912 | ld c,a 913 | rlca 914 | ld (hl),a 915 | cp a,1 916 | jp nz,nsb1 917 | ld hl,(shfbyt) 918 | inc hl 919 | ld (shfbyt),hl 920 | nsb1: ld a,b 921 | and c 922 | pop hl 923 | pop bc 924 | ret z 925 | ld a,1 926 | ret 927 | 928 | 929 | ; clear memory at hl, bc bytes 930 | clrmem: push af 931 | push bc 932 | push de 933 | push hl 934 | ld (hl),0 935 | ld d,h 936 | ld e,l 937 | inc de 938 | dec bc 939 | ldir 940 | pop hl 941 | pop de 942 | pop bc 943 | pop af 944 | ret 945 | 946 | ; initialise counter or shifter 947 | ; de = pointer to work area for counter or shifter 948 | ; hl = pointer to mask 949 | initmask: 950 | push de 951 | ex de,hl 952 | ld bc,20+20 953 | call clrmem ; clear work area 954 | ex de,hl 955 | ld b,20 ; byte counter 956 | ld c,1 ; first bit 957 | ld d,0 ; bit counter 958 | imlp: ld e,(hl) 959 | imlp1: ld a,e 960 | and a,c 961 | jp z,imlp2 962 | inc d 963 | imlp2: ld a,c 964 | rlca 965 | ld c,a 966 | cp a,1 967 | jp nz,imlp1 968 | inc hl 969 | dec b 970 | jp nz,imlp 971 | ; got number of 1-bits in mask in reg d 972 | ld a,d 973 | and 0f8h 974 | rrca 975 | rrca 976 | rrca ; divide by 8 (get byte offset) 977 | ld l,a 978 | ld h,0 979 | ld a,d 980 | and a,7 ; bit offset 981 | inc a 982 | ld b,a 983 | ld a,080h 984 | imlp3: rlca 985 | dec b 986 | jp nz,imlp3 987 | pop de 988 | add hl,de 989 | ld de,20 990 | add hl,de 991 | ld (hl),a 992 | ret 993 | 994 | ; multi-byte counter 995 | count: push bc 996 | push de 997 | push hl 998 | ld hl,counter ; 20 byte counter starts here 999 | ld de,20 ; somewhere in here is the stop bit 1000 | ex de,hl 1001 | add hl,de 1002 | ex de,hl 1003 | cntlp: inc (hl) 1004 | ld a,(hl) 1005 | cp 0 1006 | jp z,cntlp1 ; overflow to next byte 1007 | ld b,a 1008 | ld a,(de) 1009 | and a,b ; test for terminal value 1010 | jp z,cntend 1011 | ld (hl),0 ; reset to zero 1012 | cntend: pop bc 1013 | pop de 1014 | pop hl 1015 | ret 1016 | 1017 | cntlp1: inc hl 1018 | inc de 1019 | jp cntlp 1020 | 1021 | 1022 | ; multi-byte shifter 1023 | shift: push bc 1024 | push de 1025 | push hl 1026 | ld hl,shifter ; 20 byte shift register starts here 1027 | ld de,20 ; somewhere in here is the stop bit 1028 | ex de,hl 1029 | add hl,de 1030 | ex de,hl 1031 | shflp: ld a,(hl) 1032 | or a 1033 | jp z,shflp1 1034 | ld b,a 1035 | ld a,(de) 1036 | and b 1037 | jp nz,shlpe 1038 | ld a,b 1039 | rlca 1040 | cp a,1 1041 | jp nz,shflp2 1042 | ld (hl),0 1043 | inc hl 1044 | inc de 1045 | shflp2: ld (hl),a 1046 | xor a ; set Z 1047 | shlpe: pop hl 1048 | pop de 1049 | pop bc 1050 | ret 1051 | shflp1: inc hl 1052 | inc de 1053 | jp shflp 1054 | 1055 | counter: ds 2*20 1056 | shifter: ds 2*20 1057 | 1058 | ; test harness 1059 | test: push af 1060 | push bc 1061 | push de 1062 | push hl 1063 | if 0 1064 | ld de,crlf 1065 | ld c,9 1066 | call bdos 1067 | ld hl,iut 1068 | ld b,4 1069 | call hexstr 1070 | ld e,' ' 1071 | ld c,2 1072 | call bdos 1073 | ld b,16 1074 | ld hl,msbt 1075 | call hexstr 1076 | endif 1077 | di ; disable interrupts 1078 | ld (spsav),sp ; save stack pointer 1079 | ld sp,msbt+2 ; point to test-case machine state 1080 | pop iy ; and load all regs 1081 | pop ix 1082 | pop hl 1083 | pop de 1084 | pop bc 1085 | pop af 1086 | ld sp,(spbt) 1087 | iut: ds 4 ; max 4 byte instruction under test 1088 | ld (spat),sp ; save stack pointer 1089 | ld sp,spat 1090 | push af ; save other registers 1091 | push bc 1092 | push de 1093 | push hl 1094 | push ix 1095 | push iy 1096 | ld sp,(spsav) ; restore stack pointer 1097 | ei ; enable interrupts 1098 | ld hl,(msbt) ; copy memory operand 1099 | ld (msat),hl 1100 | ld hl,flgsat ; flags after test 1101 | ld a,(hl) 1102 | flgmsk: and a,0d7h ; mask-out irrelevant bits (self-modified code!) 1103 | ld (hl),a 1104 | ld b,16 ; total of 16 bytes of state 1105 | ld de,msat 1106 | ld hl,crcval 1107 | tcrc: ld a,(de) 1108 | inc de 1109 | call updcrc ; accumulate crc of this test case 1110 | dec b 1111 | jp nz,tcrc 1112 | if 0 1113 | ld e,' ' 1114 | ld c,2 1115 | call bdos 1116 | ld hl,crcval 1117 | call phex8 1118 | ld de,crlf 1119 | ld c,9 1120 | call bdos 1121 | ld hl,msat 1122 | ld b,16 1123 | call hexstr 1124 | ld de,crlf 1125 | ld c,9 1126 | call bdos 1127 | endif 1128 | pop hl 1129 | pop de 1130 | pop bc 1131 | pop af 1132 | ret 1133 | 1134 | ; machine state after test 1135 | msat: ds 14 ; memop,iy,ix,hl,de,bc,af 1136 | spat: ds 2 ; stack pointer after test 1137 | flgsat: equ spat-2 ; flags 1138 | 1139 | spsav: ds 2 ; saved stack pointer 1140 | 1141 | ; display hex string (pointer in hl, byte count in b) 1142 | hexstr: ld a,(hl) 1143 | call phex2 1144 | inc hl 1145 | dec b 1146 | jp nz,hexstr 1147 | ret 1148 | 1149 | ; display hex 1150 | ; display the big-endian 32-bit value pointed to by hl 1151 | phex8: push af 1152 | push bc 1153 | push hl 1154 | ld b,4 1155 | ph8lp: ld a,(hl) 1156 | call phex2 1157 | inc hl 1158 | dec b 1159 | jp nz,ph8lp 1160 | pop hl 1161 | pop bc 1162 | pop af 1163 | ret 1164 | 1165 | ; display byte in a 1166 | phex2: push af 1167 | rrca 1168 | rrca 1169 | rrca 1170 | rrca 1171 | call phex1 1172 | pop af 1173 | ; fall through 1174 | 1175 | ; display low nibble in a 1176 | phex1: push af 1177 | push bc 1178 | push de 1179 | push hl 1180 | and a,0fh 1181 | cp a,10 1182 | jp c,ph11 1183 | add a,'a'-'9'-1 1184 | ph11: add a,'0' 1185 | ld e,a 1186 | ld c,2 1187 | call bdos 1188 | pop hl 1189 | pop de 1190 | pop bc 1191 | pop af 1192 | ret 1193 | 1194 | bdos push af 1195 | push bc 1196 | push de 1197 | push hl 1198 | call 5 1199 | pop hl 1200 | pop de 1201 | pop bc 1202 | pop af 1203 | ret 1204 | 1205 | msg1: db 'Z80 instruction exerciser',10,13,'$' 1206 | msg2: db 'Tests complete$' 1207 | okmsg: db ' OK',10,13,'$' 1208 | ermsg1: db ' ERROR **** crc expected:$' 1209 | ermsg2: db ' found:$' 1210 | crlf: db 10,13,'$' 1211 | 1212 | ; compare crc 1213 | ; hl points to value to compare to crcval 1214 | cmpcrc: push bc 1215 | push de 1216 | push hl 1217 | ld de,crcval 1218 | ld b,4 1219 | cclp: ld a,(de) 1220 | cp a,(hl) 1221 | jp nz,cce 1222 | inc hl 1223 | inc de 1224 | dec b 1225 | jp nz,cclp 1226 | cce: pop hl 1227 | pop de 1228 | pop bc 1229 | ret 1230 | 1231 | ; 32-bit crc routine 1232 | ; entry: a contains next byte, hl points to crc 1233 | ; exit: crc updated 1234 | updcrc: push af 1235 | push bc 1236 | push de 1237 | push hl 1238 | push hl 1239 | ld de,3 1240 | add hl,de ; point to low byte of old crc 1241 | xor a,(hl) ; xor with new byte 1242 | ld l,a 1243 | ld h,0 1244 | add hl,hl ; use result as index into table of 4 byte entries 1245 | add hl,hl 1246 | ex de,hl 1247 | ld hl,crctab 1248 | add hl,de ; point to selected entry in crctab 1249 | ex de,hl 1250 | pop hl 1251 | ld bc,4 ; c = byte count, b = accumulator 1252 | crclp: ld a,(de) 1253 | xor a,b 1254 | ld b,(hl) 1255 | ld (hl),a 1256 | inc de 1257 | inc hl 1258 | dec c 1259 | jp nz,crclp 1260 | if 0 1261 | ld hl,crcval 1262 | call phex8 1263 | ld de,crlf 1264 | ld c,9 1265 | call bdos 1266 | endif 1267 | pop hl 1268 | pop de 1269 | pop bc 1270 | pop af 1271 | ret 1272 | 1273 | initcrc:push af 1274 | push bc 1275 | push hl 1276 | ld hl,crcval 1277 | ld a,0ffh 1278 | ld b,4 1279 | icrclp: ld (hl),a 1280 | inc hl 1281 | dec b 1282 | jp nz,icrclp 1283 | pop hl 1284 | pop bc 1285 | pop af 1286 | ret 1287 | 1288 | crcval ds 4 1289 | 1290 | crctab: db 000h,000h,000h,000h 1291 | db 077h,007h,030h,096h 1292 | db 0eeh,00eh,061h,02ch 1293 | db 099h,009h,051h,0bah 1294 | db 007h,06dh,0c4h,019h 1295 | db 070h,06ah,0f4h,08fh 1296 | db 0e9h,063h,0a5h,035h 1297 | db 09eh,064h,095h,0a3h 1298 | db 00eh,0dbh,088h,032h 1299 | db 079h,0dch,0b8h,0a4h 1300 | db 0e0h,0d5h,0e9h,01eh 1301 | db 097h,0d2h,0d9h,088h 1302 | db 009h,0b6h,04ch,02bh 1303 | db 07eh,0b1h,07ch,0bdh 1304 | db 0e7h,0b8h,02dh,007h 1305 | db 090h,0bfh,01dh,091h 1306 | db 01dh,0b7h,010h,064h 1307 | db 06ah,0b0h,020h,0f2h 1308 | db 0f3h,0b9h,071h,048h 1309 | db 084h,0beh,041h,0deh 1310 | db 01ah,0dah,0d4h,07dh 1311 | db 06dh,0ddh,0e4h,0ebh 1312 | db 0f4h,0d4h,0b5h,051h 1313 | db 083h,0d3h,085h,0c7h 1314 | db 013h,06ch,098h,056h 1315 | db 064h,06bh,0a8h,0c0h 1316 | db 0fdh,062h,0f9h,07ah 1317 | db 08ah,065h,0c9h,0ech 1318 | db 014h,001h,05ch,04fh 1319 | db 063h,006h,06ch,0d9h 1320 | db 0fah,00fh,03dh,063h 1321 | db 08dh,008h,00dh,0f5h 1322 | db 03bh,06eh,020h,0c8h 1323 | db 04ch,069h,010h,05eh 1324 | db 0d5h,060h,041h,0e4h 1325 | db 0a2h,067h,071h,072h 1326 | db 03ch,003h,0e4h,0d1h 1327 | db 04bh,004h,0d4h,047h 1328 | db 0d2h,00dh,085h,0fdh 1329 | db 0a5h,00ah,0b5h,06bh 1330 | db 035h,0b5h,0a8h,0fah 1331 | db 042h,0b2h,098h,06ch 1332 | db 0dbh,0bbh,0c9h,0d6h 1333 | db 0ach,0bch,0f9h,040h 1334 | db 032h,0d8h,06ch,0e3h 1335 | db 045h,0dfh,05ch,075h 1336 | db 0dch,0d6h,00dh,0cfh 1337 | db 0abh,0d1h,03dh,059h 1338 | db 026h,0d9h,030h,0ach 1339 | db 051h,0deh,000h,03ah 1340 | db 0c8h,0d7h,051h,080h 1341 | db 0bfh,0d0h,061h,016h 1342 | db 021h,0b4h,0f4h,0b5h 1343 | db 056h,0b3h,0c4h,023h 1344 | db 0cfh,0bah,095h,099h 1345 | db 0b8h,0bdh,0a5h,00fh 1346 | db 028h,002h,0b8h,09eh 1347 | db 05fh,005h,088h,008h 1348 | db 0c6h,00ch,0d9h,0b2h 1349 | db 0b1h,00bh,0e9h,024h 1350 | db 02fh,06fh,07ch,087h 1351 | db 058h,068h,04ch,011h 1352 | db 0c1h,061h,01dh,0abh 1353 | db 0b6h,066h,02dh,03dh 1354 | db 076h,0dch,041h,090h 1355 | db 001h,0dbh,071h,006h 1356 | db 098h,0d2h,020h,0bch 1357 | db 0efh,0d5h,010h,02ah 1358 | db 071h,0b1h,085h,089h 1359 | db 006h,0b6h,0b5h,01fh 1360 | db 09fh,0bfh,0e4h,0a5h 1361 | db 0e8h,0b8h,0d4h,033h 1362 | db 078h,007h,0c9h,0a2h 1363 | db 00fh,000h,0f9h,034h 1364 | db 096h,009h,0a8h,08eh 1365 | db 0e1h,00eh,098h,018h 1366 | db 07fh,06ah,00dh,0bbh 1367 | db 008h,06dh,03dh,02dh 1368 | db 091h,064h,06ch,097h 1369 | db 0e6h,063h,05ch,001h 1370 | db 06bh,06bh,051h,0f4h 1371 | db 01ch,06ch,061h,062h 1372 | db 085h,065h,030h,0d8h 1373 | db 0f2h,062h,000h,04eh 1374 | db 06ch,006h,095h,0edh 1375 | db 01bh,001h,0a5h,07bh 1376 | db 082h,008h,0f4h,0c1h 1377 | db 0f5h,00fh,0c4h,057h 1378 | db 065h,0b0h,0d9h,0c6h 1379 | db 012h,0b7h,0e9h,050h 1380 | db 08bh,0beh,0b8h,0eah 1381 | db 0fch,0b9h,088h,07ch 1382 | db 062h,0ddh,01dh,0dfh 1383 | db 015h,0dah,02dh,049h 1384 | db 08ch,0d3h,07ch,0f3h 1385 | db 0fbh,0d4h,04ch,065h 1386 | db 04dh,0b2h,061h,058h 1387 | db 03ah,0b5h,051h,0ceh 1388 | db 0a3h,0bch,000h,074h 1389 | db 0d4h,0bbh,030h,0e2h 1390 | db 04ah,0dfh,0a5h,041h 1391 | db 03dh,0d8h,095h,0d7h 1392 | db 0a4h,0d1h,0c4h,06dh 1393 | db 0d3h,0d6h,0f4h,0fbh 1394 | db 043h,069h,0e9h,06ah 1395 | db 034h,06eh,0d9h,0fch 1396 | db 0adh,067h,088h,046h 1397 | db 0dah,060h,0b8h,0d0h 1398 | db 044h,004h,02dh,073h 1399 | db 033h,003h,01dh,0e5h 1400 | db 0aah,00ah,04ch,05fh 1401 | db 0ddh,00dh,07ch,0c9h 1402 | db 050h,005h,071h,03ch 1403 | db 027h,002h,041h,0aah 1404 | db 0beh,00bh,010h,010h 1405 | db 0c9h,00ch,020h,086h 1406 | db 057h,068h,0b5h,025h 1407 | db 020h,06fh,085h,0b3h 1408 | db 0b9h,066h,0d4h,009h 1409 | db 0ceh,061h,0e4h,09fh 1410 | db 05eh,0deh,0f9h,00eh 1411 | db 029h,0d9h,0c9h,098h 1412 | db 0b0h,0d0h,098h,022h 1413 | db 0c7h,0d7h,0a8h,0b4h 1414 | db 059h,0b3h,03dh,017h 1415 | db 02eh,0b4h,00dh,081h 1416 | db 0b7h,0bdh,05ch,03bh 1417 | db 0c0h,0bah,06ch,0adh 1418 | db 0edh,0b8h,083h,020h 1419 | db 09ah,0bfh,0b3h,0b6h 1420 | db 003h,0b6h,0e2h,00ch 1421 | db 074h,0b1h,0d2h,09ah 1422 | db 0eah,0d5h,047h,039h 1423 | db 09dh,0d2h,077h,0afh 1424 | db 004h,0dbh,026h,015h 1425 | db 073h,0dch,016h,083h 1426 | db 0e3h,063h,00bh,012h 1427 | db 094h,064h,03bh,084h 1428 | db 00dh,06dh,06ah,03eh 1429 | db 07ah,06ah,05ah,0a8h 1430 | db 0e4h,00eh,0cfh,00bh 1431 | db 093h,009h,0ffh,09dh 1432 | db 00ah,000h,0aeh,027h 1433 | db 07dh,007h,09eh,0b1h 1434 | db 0f0h,00fh,093h,044h 1435 | db 087h,008h,0a3h,0d2h 1436 | db 01eh,001h,0f2h,068h 1437 | db 069h,006h,0c2h,0feh 1438 | db 0f7h,062h,057h,05dh 1439 | db 080h,065h,067h,0cbh 1440 | db 019h,06ch,036h,071h 1441 | db 06eh,06bh,006h,0e7h 1442 | db 0feh,0d4h,01bh,076h 1443 | db 089h,0d3h,02bh,0e0h 1444 | db 010h,0dah,07ah,05ah 1445 | db 067h,0ddh,04ah,0cch 1446 | db 0f9h,0b9h,0dfh,06fh 1447 | db 08eh,0beh,0efh,0f9h 1448 | db 017h,0b7h,0beh,043h 1449 | db 060h,0b0h,08eh,0d5h 1450 | db 0d6h,0d6h,0a3h,0e8h 1451 | db 0a1h,0d1h,093h,07eh 1452 | db 038h,0d8h,0c2h,0c4h 1453 | db 04fh,0dfh,0f2h,052h 1454 | db 0d1h,0bbh,067h,0f1h 1455 | db 0a6h,0bch,057h,067h 1456 | db 03fh,0b5h,006h,0ddh 1457 | db 048h,0b2h,036h,04bh 1458 | db 0d8h,00dh,02bh,0dah 1459 | db 0afh,00ah,01bh,04ch 1460 | db 036h,003h,04ah,0f6h 1461 | db 041h,004h,07ah,060h 1462 | db 0dfh,060h,0efh,0c3h 1463 | db 0a8h,067h,0dfh,055h 1464 | db 031h,06eh,08eh,0efh 1465 | db 046h,069h,0beh,079h 1466 | db 0cbh,061h,0b3h,08ch 1467 | db 0bch,066h,083h,01ah 1468 | db 025h,06fh,0d2h,0a0h 1469 | db 052h,068h,0e2h,036h 1470 | db 0cch,00ch,077h,095h 1471 | db 0bbh,00bh,047h,003h 1472 | db 022h,002h,016h,0b9h 1473 | db 055h,005h,026h,02fh 1474 | db 0c5h,0bah,03bh,0beh 1475 | db 0b2h,0bdh,00bh,028h 1476 | db 02bh,0b4h,05ah,092h 1477 | db 05ch,0b3h,06ah,004h 1478 | db 0c2h,0d7h,0ffh,0a7h 1479 | db 0b5h,0d0h,0cfh,031h 1480 | db 02ch,0d9h,09eh,08bh 1481 | db 05bh,0deh,0aeh,01dh 1482 | db 09bh,064h,0c2h,0b0h 1483 | db 0ech,063h,0f2h,026h 1484 | db 075h,06ah,0a3h,09ch 1485 | db 002h,06dh,093h,00ah 1486 | db 09ch,009h,006h,0a9h 1487 | db 0ebh,00eh,036h,03fh 1488 | db 072h,007h,067h,085h 1489 | db 005h,000h,057h,013h 1490 | db 095h,0bfh,04ah,082h 1491 | db 0e2h,0b8h,07ah,014h 1492 | db 07bh,0b1h,02bh,0aeh 1493 | db 00ch,0b6h,01bh,038h 1494 | db 092h,0d2h,08eh,09bh 1495 | db 0e5h,0d5h,0beh,00dh 1496 | db 07ch,0dch,0efh,0b7h 1497 | db 00bh,0dbh,0dfh,021h 1498 | db 086h,0d3h,0d2h,0d4h 1499 | db 0f1h,0d4h,0e2h,042h 1500 | db 068h,0ddh,0b3h,0f8h 1501 | db 01fh,0dah,083h,06eh 1502 | db 081h,0beh,016h,0cdh 1503 | db 0f6h,0b9h,026h,05bh 1504 | db 06fh,0b0h,077h,0e1h 1505 | db 018h,0b7h,047h,077h 1506 | db 088h,008h,05ah,0e6h 1507 | db 0ffh,00fh,06ah,070h 1508 | db 066h,006h,03bh,0cah 1509 | db 011h,001h,00bh,05ch 1510 | db 08fh,065h,09eh,0ffh 1511 | db 0f8h,062h,0aeh,069h 1512 | db 061h,06bh,0ffh,0d3h 1513 | db 016h,06ch,0cfh,045h 1514 | db 0a0h,00ah,0e2h,078h 1515 | db 0d7h,00dh,0d2h,0eeh 1516 | db 04eh,004h,083h,054h 1517 | db 039h,003h,0b3h,0c2h 1518 | db 0a7h,067h,026h,061h 1519 | db 0d0h,060h,016h,0f7h 1520 | db 049h,069h,047h,04dh 1521 | db 03eh,06eh,077h,0dbh 1522 | db 0aeh,0d1h,06ah,04ah 1523 | db 0d9h,0d6h,05ah,0dch 1524 | db 040h,0dfh,00bh,066h 1525 | db 037h,0d8h,03bh,0f0h 1526 | db 0a9h,0bch,0aeh,053h 1527 | db 0deh,0bbh,09eh,0c5h 1528 | db 047h,0b2h,0cfh,07fh 1529 | db 030h,0b5h,0ffh,0e9h 1530 | db 0bdh,0bdh,0f2h,01ch 1531 | db 0cah,0bah,0c2h,08ah 1532 | db 053h,0b3h,093h,030h 1533 | db 024h,0b4h,0a3h,0a6h 1534 | db 0bah,0d0h,036h,005h 1535 | db 0cdh,0d7h,006h,093h 1536 | db 054h,0deh,057h,029h 1537 | db 023h,0d9h,067h,0bfh 1538 | db 0b3h,066h,07ah,02eh 1539 | db 0c4h,061h,04ah,0b8h 1540 | db 05dh,068h,01bh,002h 1541 | db 02ah,06fh,02bh,094h 1542 | db 0b4h,00bh,0beh,037h 1543 | db 0c3h,00ch,08eh,0a1h 1544 | db 05ah,005h,0dfh,01bh 1545 | db 02dh,002h,0efh,08dh 1546 | 1547 | -------------------------------------------------------------------------------- /testfiles/zexdoc.z80: -------------------------------------------------------------------------------- 1 | .title 'Z80 instruction set exerciser' 2 | 3 | ; zexlax.z80 - Z80 instruction set exerciser 4 | ; Copyright (C) 1994 Frank D. Cringle 5 | ; 6 | ; This program is free software; you can redistribute it and/or 7 | ; modify it under the terms of the GNU General Public License 8 | ; as published by the Free Software Foundation; either version 2 9 | ; of the License, or (at your option) any later version. 10 | ; 11 | ; This program is distributed in the hope that it will be useful, 12 | ; but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | ; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | ; GNU General Public License for more details. 15 | ; 16 | ; You should have received a copy of the GNU General Public License 17 | ; along with this program; if not, write to the Free Software 18 | ; Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 19 | 20 | aseg 21 | org 100h 22 | 23 | jp start 24 | 25 | ; machine state before test (needs to be at predictably constant address) 26 | msbt: ds 14 27 | spbt: ds 2 28 | 29 | ; For the purposes of this test program, the machine state consists of: 30 | ; a 2 byte memory operand, followed by 31 | ; the registers iy,ix,hl,de,bc,af,sp 32 | ; for a total of 16 bytes. 33 | 34 | ; The program tests instructions (or groups of similar instructions) 35 | ; by cycling through a sequence of machine states, executing the test 36 | ; instruction for each one and running a 32-bit crc over the resulting 37 | ; machine states. At the end of the sequence the crc is compared to 38 | ; an expected value that was found empirically on a real Z80. 39 | 40 | ; A test case is defined by a descriptor which consists of: 41 | ; a flag mask byte, 42 | ; the base case, 43 | ; the incement vector, 44 | ; the shift vector, 45 | ; the expected crc, 46 | ; a short descriptive message. 47 | ; 48 | ; The flag mask byte is used to prevent undefined flag bits from 49 | ; influencing the results. Documented flags are as per Mostek Z80 50 | ; Technical Manual. 51 | ; 52 | ; The next three parts of the descriptor are 20 byte vectors 53 | ; corresponding to a 4 byte instruction and a 16 byte machine state. 54 | ; The first part is the base case, which is the first test case of 55 | ; the sequence. This base is then modified according to the next 2 56 | ; vectors. Each 1 bit in the increment vector specifies a bit to be 57 | ; cycled in the form of a binary counter. For instance, if the byte 58 | ; corresponding to the accumulator is set to 0ffh in the increment 59 | ; vector, the test will be repeated for all 256 values of the 60 | ; accumulator. Note that 1 bits don't have to be contiguous. The 61 | ; number of test cases 'caused' by the increment vector is equal to 62 | ; 2^(number of 1 bits). The shift vector is similar, but specifies a 63 | ; set of bits in the test case that are to be successively inverted. 64 | ; Thus the shift vector 'causes' a number of test cases equal to the 65 | ; number of 1 bits in it. 66 | 67 | ; The total number of test cases is the product of those caused by the 68 | ; counter and shift vectors and can easily become unweildy. Each 69 | ; individual test case can take a few milliseconds to execute, due to 70 | ; the overhead of test setup and crc calculation, so test design is a 71 | ; compromise between coverage and execution time. 72 | 73 | ; This program is designed to detect differences between 74 | ; implementations and is not ideal for diagnosing the causes of any 75 | ; discrepancies. However, provided a reference implementation (or 76 | ; real system) is available, a failing test case can be isolated by 77 | ; hand using a binary search of the test space. 78 | 79 | 80 | start: ld hl,(6) 81 | ld sp,hl 82 | ld de,msg1 83 | ld c,9 84 | call bdos 85 | 86 | ld hl,tests ; first test case 87 | loop: ld a,(hl) ; end of list ? 88 | inc hl 89 | or (hl) 90 | jp z,done 91 | dec hl 92 | call stt 93 | jp loop 94 | 95 | done: ld de,msg2 96 | ld c,9 97 | call bdos 98 | jp 0 ; warm boot 99 | 100 | tests: 101 | dw adc16 102 | dw add16 103 | dw add16x 104 | dw add16y 105 | dw alu8i 106 | dw alu8r 107 | dw alu8rx 108 | dw alu8x 109 | dw bitx 110 | dw bitz80 111 | dw cpd1 112 | dw cpi1 113 | dw daa 114 | dw inca 115 | dw incb 116 | dw incbc 117 | dw incc 118 | dw incd 119 | dw incde 120 | dw ince 121 | dw inch 122 | dw inchl 123 | dw incix 124 | dw inciy 125 | dw incl 126 | dw incm 127 | dw incsp 128 | dw incx 129 | dw incxh 130 | dw incxl 131 | dw incyh 132 | dw incyl 133 | dw ld161 134 | dw ld162 135 | dw ld163 136 | dw ld164 137 | dw ld165 138 | dw ld166 139 | dw ld167 140 | dw ld168 141 | dw ld16im 142 | dw ld16ix 143 | dw ld8bd 144 | dw ld8im 145 | dw ld8imx 146 | dw ld8ix1 147 | dw ld8ix2 148 | dw ld8ix3 149 | dw ld8ixy 150 | dw ld8rr 151 | dw ld8rrx 152 | dw lda 153 | dw ldd1 154 | dw ldd2 155 | dw ldi1 156 | dw ldi2 157 | dw neg 158 | dw rld 159 | dw rot8080 160 | dw rotxy 161 | dw rotz80 162 | dw srz80 163 | dw srzx 164 | dw st8ix1 165 | dw st8ix2 166 | dw st8ix3 167 | dw stabd 168 | dw 0 169 | 170 | tstr: macro insn,memop,iy,ix,hl,de,bc,flags,acc,sp 171 | local lab 172 | &lab: db insn 173 | ds &lab+4-$,0 174 | dw &memop,&iy,&ix,&hl,&de,&bc 175 | db &flags 176 | db &acc 177 | dw &sp 178 | if $-&lab ne 20 179 | error 'missing parameter' 180 | endif 181 | endm 182 | 183 | tmsg: macro m 184 | local lab 185 | &lab: db m 186 | if $ ge &lab+30 187 | error 'message too long' 188 | else 189 | ds &lab+30-$,'.' 190 | endif 191 | db '$' 192 | endm 193 | 194 | ; hl, (38,912 cycles) 195 | adc16: db 0c7h ; flag mask 196 | tstr <0edh,042h>,0832ch,04f88h,0f22bh,0b339h,07e1fh,01563h,0d3h,089h,0465eh 197 | tstr <0,038h>,0,0,0,0f821h,0,0,0,0,0 ; (1024 cycles) 198 | tstr 0,0,0,0,-1,-1,-1,0d7h,0,-1 ; (38 cycles) 199 | db 0f8h,0b4h,0eah,0a9h ; expected crc 200 | tmsg ' hl,' 201 | 202 | ; add hl, (19,456 cycles) 203 | add16: db 0c7h ; flag mask 204 | tstr 9,0c4a5h,0c4c7h,0d226h,0a050h,058eah,08566h,0c6h,0deh,09bc9h 205 | tstr 030h,0,0,0,0f821h,0,0,0,0,0 ; (512 cycles) 206 | tstr 0,0,0,0,-1,-1,-1,0d7h,0,-1 ; (38 cycles) 207 | db 089h,0fdh,0b6h,035h ; expected crc 208 | tmsg 'add hl,' 209 | 210 | ; add ix, (19,456 cycles) 211 | add16x: db 0c7h ; flag mask 212 | tstr <0ddh,9>,0ddach,0c294h,0635bh,033d3h,06a76h,0fa20h,094h,068h,036f5h 213 | tstr <0,030h>,0,0,0f821h,0,0,0,0,0,0 ; (512 cycles) 214 | tstr 0,0,0,-1,0,-1,-1,0d7h,0,-1 ; (38 cycles) 215 | db 0c1h,033h,079h,00bh ; expected crc 216 | tmsg 'add ix,' 217 | 218 | ; add iy, (19,456 cycles) 219 | add16y: db 0c7h ; flag mask 220 | tstr <0fdh,9>,0c7c2h,0f407h,051c1h,03e96h,00bf4h,0510fh,092h,01eh,071eah 221 | tstr <0,030h>,0,0f821h,0,0,0,0,0,0,0 ; (512 cycles) 222 | tstr 0,0,-1,0,0,-1,-1,0d7h,0,-1 ; (38 cycles) 223 | db 0e8h,081h,07bh,09eh ; expected crc 224 | tmsg 'add iy,' 225 | 226 | ; aluop a,nn (28,672 cycles) 227 | alu8i: db 0d7h ; flag mask 228 | tstr 0c6h,09140h,07e3ch,07a67h,0df6dh,05b61h,00b29h,010h,066h,085b2h 229 | tstr 038h,0,0,0,0,0,0,0,-1,0 ; (2048 cycles) 230 | tstr <0,-1>,0,0,0,0,0,0,0d7h,0,0 ; (14 cycles) 231 | db 048h,079h,093h,060h ; expected crc 232 | tmsg 'aluop a,nn' 233 | 234 | ; aluop a, (753,664 cycles) 235 | alu8r: db 0d7h ; flag mask 236 | tstr 080h,0c53eh,0573ah,04c4dh,msbt,0e309h,0a666h,0d0h,03bh,0adbbh 237 | tstr 03fh,0,0,0,0,0,0,0,-1,0 ; (16,384 cycles) 238 | tstr 0,0ffh,0,0,0,-1,-1,0d7h,0,0 ; (46 cycles) 239 | db 0feh,043h,0b0h,016h ; expected crc 240 | tmsg 'aluop a,' 241 | 242 | ; aluop a, (376,832 cycles) 243 | alu8rx: db 0d7h ; flag mask 244 | tstr <0ddh,084h>,0d6f7h,0c76eh,0accfh,02847h,022ddh,0c035h,0c5h,038h,0234bh 245 | tstr <020h,039h>,0,0,0,0,0,0,0,-1,0 ; (8,192 cycles) 246 | tstr 0,0ffh,0,0,0,-1,-1,0d7h,0,0 ; (46 cycles) 247 | db 0a4h,002h,06dh,05ah ; expected crc 248 | tmsg 'aluop a,' 249 | 250 | ; aluop a,(+1) (229,376 cycles) 251 | alu8x: db 0d7h ; flag mask 252 | tstr <0ddh,086h,1>,090b7h,msbt-1,msbt-1,032fdh,0406eh,0c1dch,045h,06eh,0e5fah 253 | tstr <020h,038h>,0,1,1,0,0,0,0,-1,0 ; (16,384 cycles) 254 | tstr 0,0ffh,0,0,0,0,0,0d7h,0,0 ; (14 cycles) 255 | db 0e8h,049h,067h,06eh ; expected crc 256 | tmsg 'aluop a,(+1)' 257 | 258 | ; bit n,(+1) (2048 cycles) 259 | bitx: db 053h ; flag mask 260 | tstr <0ddh,0cbh,1,046h>,02075h,msbt-1,msbt-1,03cfch,0a79ah,03d74h,051h,027h,0ca14h 261 | tstr <020h,0,0,038h>,0,0,0,0,0,0,053h,0,0 ; (256 cycles) 262 | tstr 0,0ffh,0,0,0,0,0,0,0,0 ; (8 cycles) 263 | db 0a8h,0eeh,008h,067h ; expected crc 264 | tmsg 'bit n,(+1)' 265 | 266 | ; bit n, (49,152 cycles) 267 | bitz80: db 053h ; flag mask 268 | tstr <0cbh,040h>,03ef1h,09dfch,07acch,msbt,0be61h,07a86h,050h,024h,01998h 269 | tstr <0,03fh>,0,0,0,0,0,0,053h,0,0 ; (1024 cycles) 270 | tstr 0,0ffh,0,0,0,-1,-1,0,-1,0 ; (48 cycles) 271 | db 07bh,055h,0e6h,0c8h ; expected crc 272 | tmsg 'bit n,' 273 | 274 | ; cpd (1) (6144 cycles) 275 | cpd1: db 0d7h ; flag mask 276 | tstr <0edh,0a9h>,0c7b6h,072b4h,018f6h,msbt+17,08dbdh,1,0c0h,030h,094a3h 277 | tstr <0,010h>,0,0,0,0,0,010,0,-1,0 ; (1024 cycles) 278 | tstr 0,0,0,0,0,0,0,0d7h,0,0 ; (6 cycles) 279 | db 0a8h,07eh,06ch,0fah ; expected crc 280 | tmsg 'cpd' 281 | 282 | ; cpi (1) (6144 cycles) 283 | cpi1: db 0d7h ; flag mask 284 | tstr <0edh,0a1h>,04d48h,0af4ah,0906bh,msbt,04e71h,1,093h,06ah,0907ch 285 | tstr <0,010h>,0,0,0,0,0,010,0,-1,0 ; (1024 cycles) 286 | tstr 0,0,0,0,0,0,0,0d7h,0,0 ; (6 cycles) 287 | db 006h,0deh,0b3h,056h ; expected crc 288 | tmsg 'cpi' 289 | 290 | ; 291 | daa: db 0d7h ; flag mask 292 | tstr 027h,02141h,009fah,01d60h,0a559h,08d5bh,09079h,004h,08eh,0299dh 293 | tstr 018h,0,0,0,0,0,0,0d7h,-1,0 ; (65,536 cycles) 294 | tstr 0,0,0,0,0,0,0,0,0,0 ; (1 cycle) 295 | db 09bh,04bh,0a6h,075h ; expected crc 296 | tmsg '' 297 | 298 | ; a (3072 cycles) 299 | inca: db 0d7h ; flag mask 300 | tstr 03ch,04adfh,0d5d8h,0e598h,08a2bh,0a7b0h,0431bh,044h,05ah,0d030h 301 | tstr 001h,0,0,0,0,0,0,0,-1,0 ; (512 cycles) 302 | tstr 0,0,0,0,0,0,0,0d7h,0,0 ; (6 cycles) 303 | db 0d1h,088h,015h,0a4h ; expected crc 304 | tmsg ' a' 305 | 306 | ; b (3072 cycles) 307 | incb: db 0d7h ; flag mask 308 | tstr 004h,0d623h,0432dh,07a61h,08180h,05a86h,01e85h,086h,058h,09bbbh 309 | tstr 001h,0,0,0,0,0,0ff00h,0,0,0 ; (512 cycles) 310 | tstr 0,0,0,0,0,0,0,0d7h,0,0 ; (6 cycles) 311 | db 05fh,068h,022h,064h ; expected crc 312 | tmsg ' b' 313 | 314 | ; bc (1536 cycles) 315 | incbc: db 0d7h ; flag mask 316 | tstr 003h,0cd97h,044abh,08dc9h,0e3e3h,011cch,0e8a4h,002h,049h,02a4dh 317 | tstr 008h,0,0,0,0,0,0f821h,0,0,0 ; (256 cycles) 318 | tstr 0,0,0,0,0,0,0,0d7h,0,0 ; (6 cycles) 319 | db 0d2h,0aeh,03bh,0ech ; expected crc 320 | tmsg ' bc' 321 | 322 | ; c (3072 cycles) 323 | incc: db 0d7h ; flag mask 324 | tstr 00ch,0d789h,00935h,0055bh,09f85h,08b27h,0d208h,095h,005h,00660h 325 | tstr 001h,0,0,0,0,0,0ffh,0,0,0 ; (512 cycles) 326 | tstr 0,0,0,0,0,0,0,0d7h,0,0 ; (6 cycles) 327 | db 0c2h,084h,055h,04ch ; expected crc 328 | tmsg ' c' 329 | 330 | ; d (3072 cycles) 331 | incd: db 0d7h ; flag mask 332 | tstr 014h,0a0eah,05fbah,065fbh,0981ch,038cch,0debch,043h,05ch,003bdh 333 | tstr 001h,0,0,0,0,0ff00h,0,0,0,0 ; (512 cycles) 334 | tstr 0,0,0,0,0,0,0,0d7h,0,0 ; (6 cycles) 335 | db 045h,023h,0deh,010h ; expected crc 336 | tmsg ' d' 337 | 338 | ; de (1536 cycles) 339 | incde: db 0d7h ; flag mask 340 | tstr 013h,0342eh,0131dh,028c9h,00acah,09967h,03a2eh,092h,0f6h,09d54h 341 | tstr 008h,0,0,0,0,0f821h,0,0,0,0 ; (256 cycles) 342 | tstr 0,0,0,0,0,0,0,0d7h,0,0 ; (6 cycles) 343 | db 0aeh,0c6h,0d4h,02ch ; expected crc 344 | tmsg ' de' 345 | 346 | ; e (3072 cycles) 347 | ince: db 0d7h ; flag mask 348 | tstr 01ch,0602fh,04c0dh,02402h,0e2f5h,0a0f4h,0a10ah,013h,032h,05925h 349 | tstr 001h,0,0,0,0,0ffh,0,0,0,0 ; (512 cycles) 350 | tstr 0,0,0,0,0,0,0,0d7h,0,0 ; (6 cycles) 351 | db 0e1h,075h,0afh,0cch ; expected crc 352 | tmsg ' e' 353 | 354 | ; h (3072 cycles) 355 | inch: db 0d7h ; flag mask 356 | tstr 024h,01506h,0f2ebh,0e8ddh,0262bh,011a6h,0bc1ah,017h,006h,02818h 357 | tstr 001h,0,0,0,0ff00h,0,0,0,0,0 ; (512 cycles) 358 | tstr 0,0,0,0,0,0,0,0d7h,0,0 ; (6 cycles) 359 | db 01ch,0edh,084h,07dh ; expected crc 360 | tmsg ' h' 361 | 362 | ; hl (1536 cycles) 363 | inchl: db 0d7h ; flag mask 364 | tstr 023h,0c3f4h,007a5h,01b6dh,04f04h,0e2c2h,0822ah,057h,0e0h,0c3e1h 365 | tstr 008h,0,0,0,0f821h,0,0,0,0,0 ; (256 cycles) 366 | tstr 0,0,0,0,0,0,0,0d7h,0,0 ; (6 cycles) 367 | db 0fch,00dh,06dh,04ah ; expected crc 368 | tmsg ' hl' 369 | 370 | ; ix (1536 cycles) 371 | incix: db 0d7h ; flag mask 372 | tstr <0ddh,023h>,0bc3ch,00d9bh,0e081h,0adfdh,09a7fh,096e5h,013h,085h,00be2h 373 | tstr <0,8>,0,0,0f821h,0,0,0,0,0,0 ; (256 cycles) 374 | tstr 0,0,0,0,0,0,0,0d7h,0,0 ; (6 cycles) 375 | db 0a5h,04dh,0beh,031h ; expected crc 376 | tmsg ' ix' 377 | 378 | ; iy (1536 cycles) 379 | inciy: db 0d7h ; flag mask 380 | tstr <0fdh,023h>,09402h,0637ah,03182h,0c65ah,0b2e9h,0abb4h,016h,0f2h,06d05h 381 | tstr <0,8>,0,0f821h,0,0,0,0,0,0,0 ; (256 cycles) 382 | tstr 0,0,0,0,0,0,0,0d7h,0,0 ; (6 cycles) 383 | db 050h,05dh,051h,0a3h ; expected crc 384 | tmsg ' iy' 385 | 386 | ; l (3072 cycles) 387 | incl: db 0d7h ; flag mask 388 | tstr 02ch,08031h,0a520h,04356h,0b409h,0f4c1h,0dfa2h,0d1h,03ch,03ea2h 389 | tstr 001h,0,0,0,0ffh,0,0,0,0,0 ; (512 cycles) 390 | tstr 0,0,0,0,0,0,0,0d7h,0,0 ; (6 cycles) 391 | db 056h,0cdh,006h,0f3h ; expected crc 392 | tmsg ' l' 393 | 394 | ; (hl) (3072 cycles) 395 | incm: db 0d7h ; flag mask 396 | tstr 034h,0b856h,00c7ch,0e53eh,msbt,0877eh,0da58h,015h,05ch,01f37h 397 | tstr 001h,0ffh,0,0,0,0,0,0,0,0 ; (512 cycles) 398 | tstr 0,0,0,0,0,0,0,0d7h,0,0 ; (6 cycles) 399 | db 0b8h,03ah,0dch,0efh ; expected crc 400 | tmsg ' (hl)' 401 | 402 | ; sp (1536 cycles) 403 | incsp: db 0d7h ; flag mask 404 | tstr 033h,0346fh,0d482h,0d169h,0deb6h,0a494h,0f476h,053h,002h,0855bh 405 | tstr 008h,0,0,0,0,0,0,0,0,0f821h ; (256 cycles) 406 | tstr 0,0,0,0,0,0,0,0d7h,0,0 ; (6 cycles) 407 | db 05dh,0ach,0d5h,027h ; expected crc 408 | tmsg ' sp' 409 | 410 | ; (+1) (6144 cycles) 411 | incx: db 0d7h ; flag mask 412 | tstr <0ddh,034h,1>,0fa6eh,msbt-1,msbt-1,02c28h,08894h,05057h,016h,033h,0286fh 413 | tstr <020h,1>,0ffh,0,0,0,0,0,0,0,0 ; (1024 cycles) 414 | tstr 0,0,0,0,0,0,0,0d7h,0,0 ; (6 cycles) 415 | db 020h,058h,014h,070h ; expected crc 416 | tmsg ' (+1)' 417 | 418 | ; ixh (3072 cycles) 419 | incxh: db 0d7h ; flag mask 420 | tstr <0ddh,024h>,0b838h,0316ch,0c6d4h,03e01h,08358h,015b4h,081h,0deh,04259h 421 | tstr <0,1>,0,0ff00h,0,0,0,0,0,0,0 ; (512 cycles) 422 | tstr 0,0,0,0,0,0,0,0d7h,0,0 ; (6 cycles) 423 | db 06fh,046h,036h,062h ; expected crc 424 | tmsg ' ixh' 425 | 426 | ; ixl (3072 cycles) 427 | incxl: db 0d7h ; flag mask 428 | tstr <0ddh,02ch>,04d14h,07460h,076d4h,006e7h,032a2h,0213ch,0d6h,0d7h,099a5h 429 | tstr <0,1>,0,0ffh,0,0,0,0,0,0,0 ; (512 cycles) 430 | tstr 0,0,0,0,0,0,0,0d7h,0,0 ; (6 cycles) 431 | db 002h,07bh,0efh,02ch ; expected crc 432 | tmsg ' ixl' 433 | 434 | ; iyh (3072 cycles) 435 | incyh: db 0d7h ; flag mask 436 | tstr <0ddh,024h>,02836h,09f6fh,09116h,061b9h,082cbh,0e219h,092h,073h,0a98ch 437 | tstr <0,1>,0ff00h,0,0,0,0,0,0,0,0 ; (512 cycles) 438 | tstr 0,0,0,0,0,0,0,0d7h,0,0 ; (6 cycles) 439 | db 02dh,096h,06ch,0f3h ; expected crc 440 | tmsg ' iyh' 441 | 442 | ; iyl (3072 cycles) 443 | incyl: db 0d7h ; flag mask 444 | tstr <0ddh,02ch>,0d7c6h,062d5h,0a09eh,07039h,03e7eh,09f12h,090h,0d9h,0220fh 445 | tstr <0,1>,0ffh,0,0,0,0,0,0,0,0 ; (512 cycles) 446 | tstr 0,0,0,0,0,0,0,0d7h,0,0 ; (6 cycles) 447 | db 0fbh,0cbh,0bah,095h ; expected crc 448 | tmsg ' iyl' 449 | 450 | ; ld ,(nnnn) (32 cycles) 451 | ld161: db 0d7h ; flag mask 452 | tstr <0edh,04bh,low msbt,high msbt>,0f9a8h,0f559h,093a4h,0f5edh,06f96h,0d968h,086h,0e6h,04bd8h 453 | tstr <0,010h>,0,0,0,0,0,0,0,0,0 ; (2 cycles) 454 | tstr 0,-1,0,0,0,0,0,0,0,0 ; (16 cycles) 455 | db 04dh,045h,0a9h,0ach ; expected crc 456 | tmsg 'ld ,(nnnn)' 457 | 458 | ; ld hl,(nnnn) (16 cycles) 459 | ld162: db 0d7h ; flag mask 460 | tstr <02ah,low msbt,high msbt>,09863h,07830h,02077h,0b1feh,0b9fah,0abb8h,004h,006h,06015h 461 | tstr 0,0,0,0,0,0,0,0,0,0 ; (1 cycle) 462 | tstr 0,-1,0,0,0,0,0,0,0,0 ; (16 cycles) 463 | db 05fh,097h,024h,087h ; expected crc 464 | tmsg 'ld hl,(nnnn)' 465 | 466 | ; ld sp,(nnnn) (16 cycles) 467 | ld163: db 0d7h ; flag mask 468 | tstr <0edh,07bh,low msbt,high msbt>,08dfch,057d7h,02161h,0ca18h,0c185h,027dah,083h,01eh,0f460h 469 | tstr 0,0,0,0,0,0,0,0,0,0 ; (1 cycles) 470 | tstr 0,-1,0,0,0,0,0,0,0,0 ; (16 cycles) 471 | db 07ah,0ceh,0a1h,01bh ; expected crc 472 | tmsg 'ld sp,(nnnn)' 473 | 474 | ; ld ,(nnnn) (32 cycles) 475 | ld164: db 0d7h ; flag mask 476 | tstr <0ddh,02ah,low msbt,high msbt>,0ded7h,0a6fah,0f780h,0244ch,087deh,0bcc2h,016h,063h,04c96h 477 | tstr 020h,0,0,0,0,0,0,0,0,0 ; (2 cycles) 478 | tstr 0,-1,0,0,0,0,0,0,0,0 ; (16 cycles) 479 | db 085h,08bh,0f1h,06dh ; expected crc 480 | tmsg 'ld ,(nnnn)' 481 | 482 | ; ld (nnnn), (64 cycles) 483 | ld165: db 0d7h ; flag mask 484 | tstr <0edh,043h,low msbt,high msbt>,01f98h,0844dh,0e8ach,0c9edh,0c95dh,08f61h,080h,03fh,0c7bfh 485 | tstr <0,010h>,0,0,0,0,0,0,0,0,0 ; (2 cycles) 486 | tstr 0,0,0,0,0,-1,-1,0,0,0 ; (32 cycles) 487 | db 064h,01eh,087h,015h ; expected crc 488 | tmsg 'ld (nnnn),' 489 | 490 | ; ld (nnnn),hl (16 cycles) 491 | ld166: db 0d7h ; flag mask 492 | tstr <022h,low msbt,high msbt>,0d003h,07772h,07f53h,03f72h,064eah,0e180h,010h,02dh,035e9h 493 | tstr 0,0,0,0,0,0,0,0,0,0 ; (1 cycle) 494 | tstr 0,0,0,0,-1,0,0,0,0,0 ; (16 cycles) 495 | db 0a3h,060h,08bh,047h ; expected crc 496 | tmsg 'ld (nnnn),hl' 497 | 498 | ; ld (nnnn),sp (16 cycles) 499 | ld167: db 0d7h ; flag mask 500 | tstr <0edh,073h,low msbt,high msbt>,0c0dch,0d1d6h,0ed5ah,0f356h,0afdah,06ca7h,044h,09fh,03f0ah 501 | tstr 0,0,0,0,0,0,0,0,0,0 ; (1 cycle) 502 | tstr 0,0,0,0,0,0,0,0,0,-1 ; (16 cycles) 503 | db 016h,058h,05fh,0d7h ; expected crc 504 | tmsg 'ld (nnnn),sp' 505 | 506 | ; ld (nnnn), (64 cycles) 507 | ld168: db 0d7h ; flag mask 508 | tstr <0ddh,022h,low msbt,high msbt>,06cc3h,00d91h,06900h,08ef8h,0e3d6h,0c3f7h,0c6h,0d9h,0c2dfh 509 | tstr 020h,0,0,0,0,0,0,0,0,0 ; (2 cycles) 510 | tstr 0,0,-1,-1,0,0,0,0,0,0 ; (32 cycles) 511 | db 0bah,010h,02ah,06bh ; expected crc 512 | tmsg 'ld (nnnn),' 513 | 514 | ; ld ,nnnn (64 cycles) 515 | ld16im: db 0d7h ; flag mask 516 | tstr 1,05c1ch,02d46h,08eb9h,06078h,074b1h,0b30eh,046h,0d1h,030cch 517 | tstr 030h,0,0,0,0,0,0,0,0,0 ; (4 cycles) 518 | tstr <0,0ffh,0ffh>,0,0,0,0,0,0,0,0,0 ; (16 cycles) 519 | db 0deh,039h,019h,069h ; expected crc 520 | tmsg 'ld ,nnnn' 521 | 522 | ; ld ,nnnn (32 cycles) 523 | ld16ix: db 0d7h ; flag mask 524 | tstr <0ddh,021h>,087e8h,02006h,0bd12h,0b69bh,07253h,0a1e5h,051h,013h,0f1bdh 525 | tstr 020h,0,0,0,0,0,0,0,0,0 ; (2 cycles) 526 | tstr <0,0,0ffh,0ffh>,0,0,0,0,0,0,0,0,0 ; (16 cycles) 527 | db 022h,07dh,0d5h,025h ; expected crc 528 | tmsg 'ld ,nnnn' 529 | 530 | ; ld a,<(bc),(de)> (44 cycles) 531 | ld8bd: db 0d7h ; flag mask 532 | tstr 00ah,0b3a8h,01d2ah,07f8eh,042ach,msbt,msbt,0c6h,0b1h,0ef8eh 533 | tstr 010h,0,0,0,0,0,0,0,0,0 ; (2 cycles) 534 | tstr 0,0ffh,0,0,0,0,0,0d7h,-1,0 ; (22 cycles) 535 | db 0b0h,081h,089h,035h ; expected crc 536 | tmsg 'ld a,<(bc),(de)>' 537 | 538 | ; ld ,nn (64 cycles) 539 | ld8im: db 0d7h ; flag mask 540 | tstr 6,0c407h,0f49dh,0d13dh,00339h,0de89h,07455h,053h,0c0h,05509h 541 | tstr 038h,0,0,0,0,0,0,0,0,0 ; (8 cycles) 542 | tstr 0,0,0,0,0,0,0,0,-1,0 ; (8 cycles) 543 | db 0f1h,0dah,0b5h,056h ; expected crc 544 | tmsg 'ld ,nn' 545 | 546 | ; ld (+1),nn (32 cycles) 547 | ld8imx: db 0d7h ; flag mask 548 | tstr <0ddh,036h,1>,01b45h,msbt-1,msbt-1,0d5c1h,061c7h,0bdc4h,0c0h,085h,0cd16h 549 | tstr 020h,0,0,0,0,0,0,0,0,0 ; (2 cycles) 550 | tstr <0,0,0,-1>,0,0,0,0,0,0,0,-1,0 ; (16 cycles) 551 | db 026h,0dbh,047h,07eh ; expected crc 552 | tmsg 'ld (+1),nn' 553 | 554 | ; ld ,(+1) (512 cycles) 555 | ld8ix1: db 0d7h ; flag mask 556 | tstr <0ddh,046h,1>,0d016h,msbt-1,msbt-1,04260h,07f39h,00404h,097h,04ah,0d085h 557 | tstr <020h,018h>,0,1,1,0,0,0,0,0,0 ; (32 cycles) 558 | tstr 0,-1,0,0,0,0,0,0,0,0 ; (16 cycles) 559 | db 0cch,011h,006h,0a8h ; expected crc 560 | tmsg 'ld ,(+1)' 561 | 562 | ; ld ,(+1) (256 cycles) 563 | ld8ix2: db 0d7h ; flag mask 564 | tstr <0ddh,066h,1>,084e0h,msbt-1,msbt-1,09c52h,0a799h,049b6h,093h,000h,0eeadh 565 | tstr <020h,008h>,0,1,1,0,0,0,0,0,0 ; (16 cycles) 566 | tstr 0,-1,0,0,0,0,0,0,0,0 ; (16 cycles) 567 | db 0fah,02ah,04dh,003h ; expected crc 568 | tmsg 'ld ,(+1)' 569 | 570 | ; ld a,(+1) (128 cycles) 571 | ld8ix3: db 0d7h ; flag mask 572 | tstr <0ddh,07eh,1>,0d8b6h,msbt-1,msbt-1,0c612h,0df07h,09cd0h,043h,0a6h,0a0e5h 573 | tstr 020h,0,1,1,0,0,0,0,0,0 ; (8 cycles) 574 | tstr 0,-1,0,0,0,0,0,0,0,0 ; (16 cycles) 575 | db 0a5h,0e9h,0ach,064h ; expected crc 576 | tmsg 'ld a,(+1)' 577 | 578 | ; ld ,nn (32 cycles) 579 | ld8ixy: db 0d7h ; flag mask 580 | tstr <0ddh,026h>,03c53h,04640h,0e179h,07711h,0c107h,01afah,081h,0adh,05d9bh 581 | tstr <020h,8>,0,0,0,0,0,0,0,0,0 ; (4 cycles) 582 | tstr 0,0,0,0,0,0,0,0,-1,0 ; (8 cycles) 583 | db 024h,0e8h,082h,08bh ; expected crc 584 | tmsg 'ld ,nn' 585 | 586 | ; ld , (3456 cycles) 587 | ld8rr: db 0d7h ; flag mask 588 | tstr 040h,072a4h,0a024h,061ach,msbt,082c7h,0718fh,097h,08fh,0ef8eh 589 | tstr 03fh,0,0,0,0,0,0,0,0,0 ; (64 cycles) 590 | tstr 0,0ffh,0,0,0,-1,-1,0d7h,-1,0 ; (54 cycles) 591 | db 074h,04bh,001h,018h ; expected crc 592 | tmsg 'ld ,' 593 | 594 | ; ld , (6912 cycles) 595 | ld8rrx: db 0d7h ; flag mask 596 | tstr <0ddh,040h>,0bcc5h,msbt,msbt,msbt,02fc2h,098c0h,083h,01fh,03bcdh 597 | tstr <020h,03fh>,0,0,0,0,0,0,0,0,0 ; (128 cycles) 598 | tstr 0,0ffh,0,0,0,-1,-1,0d7h,-1,0 ; (54 cycles) 599 | db 047h,08bh,0a3h,06bh ; expected crc 600 | tmsg 'ld ,' 601 | 602 | ; ld a,(nnnn) / ld (nnnn),a (44 cycles) 603 | lda: db 0d7h ; flag mask 604 | tstr <032h,low msbt,high msbt>,0fd68h,0f4ech,044a0h,0b543h,00653h,0cdbah,0d2h,04fh,01fd8h 605 | tstr 008h,0,0,0,0,0,0,0,0,0 ; (2 cycle) 606 | tstr 0,0ffh,0,0,0,0,0,0d7h,-1,0 ; (22 cycles) 607 | db 0c9h,026h,02dh,0e5h ; expected crc 608 | tmsg 'ld a,(nnnn) / ld (nnnn),a' 609 | 610 | ; ldd (1) (44 cycles) 611 | ldd1: db 0d7h ; flag mask 612 | tstr <0edh,0a8h>,09852h,068fah,066a1h,msbt+3,msbt+1,1,0c1h,068h,020b7h 613 | tstr <0,010h>,0,0,0,0,0,0,0,0,0 ; (2 cycles) 614 | tstr 0,-1,0,0,0,0,0,0d7h,0,0 ; (22 cycles) 615 | db 094h,0f4h,027h,069h ; expected crc 616 | tmsg 'ldd (1)' 617 | 618 | ; ldd (2) (44 cycles) 619 | ldd2: db 0d7h ; flag mask 620 | tstr <0edh,0a8h>,0f12eh,0eb2ah,0d5bah,msbt+3,msbt+1,2,047h,0ffh,0fbe4h 621 | tstr <0,010h>,0,0,0,0,0,0,0,0,0 ; (2 cycles) 622 | tstr 0,-1,0,0,0,0,0,0d7h,0,0 ; (22 cycles) 623 | db 05ah,090h,07eh,0d4h ; expected crc 624 | tmsg 'ldd (2)' 625 | 626 | ; ldi (1) (44 cycles) 627 | ldi1: db 0d7h ; flag mask 628 | tstr <0edh,0a0h>,0fe30h,003cdh,06058h,msbt+2,msbt,1,004h,060h,02688h 629 | tstr <0,010h>,0,0,0,0,0,0,0,0,0 ; (2 cycles) 630 | tstr 0,-1,0,0,0,0,0,0d7h,0,0 ; (22 cycles) 631 | db 09ah,0bdh,0f6h,0b5h ; expected crc 632 | tmsg 'ldi (1)' 633 | 634 | ; ldi (2) (44 cycles) 635 | ldi2: db 0d7h ; flag mask 636 | tstr <0edh,0a0h>,04aceh,0c26eh,0b188h,msbt+2,msbt,2,014h,02dh,0a39fh 637 | tstr <0,010h>,0,0,0,0,0,0,0,0,0 ; (2 cycles) 638 | tstr 0,-1,0,0,0,0,0,0d7h,0,0 ; (22 cycles) 639 | db 0ebh,059h,089h,01bh ; expected crc 640 | tmsg 'ldi (2)' 641 | 642 | ; neg (16,384 cycles) 643 | neg: db 0d7h ; flag mask 644 | tstr <0edh,044h>,038a2h,05f6bh,0d934h,057e4h,0d2d6h,04642h,043h,05ah,009cch 645 | tstr 0,0,0,0,0,0,0,0d7h,-1,0 ; (16,384 cycles) 646 | tstr 0,0,0,0,0,0,0,0,0,0 ; (1 cycle) 647 | db 06ah,03ch,03bh,0bdh ; expected crc 648 | tmsg 'neg' 649 | 650 | ; (7168 cycles) 651 | rld: db 0d7h ; flag mask 652 | tstr <0edh,067h>,091cbh,0c48bh,0fa62h,msbt,0e720h,0b479h,040h,006h,08ae2h 653 | tstr <0,8>,0ffh,0,0,0,0,0,0,0,0 ; (512 cycles) 654 | tstr 0,0,0,0,0,0,0,0d7h,-1,0 ; (14 cycles) 655 | db 095h,05bh,0a3h,026h ; expected crc 656 | tmsg '' 657 | 658 | ; (6144 cycles) 659 | rot8080: db 0d7h ; flag mask 660 | tstr 7,0cb92h,06d43h,00a90h,0c284h,00c53h,0f50eh,091h,0ebh,040fch 661 | tstr 018h,0,0,0,0,0,0,0,-1,0 ; (1024 cycles) 662 | tstr 0,0,0,0,0,0,0,0d7h,0,0 ; (6 cycles) 663 | db 025h,013h,030h,0aeh ; expected crc 664 | tmsg '' 665 | 666 | ; shift/rotate (+1) (416 cycles) 667 | rotxy: db 0d7h ; flag mask 668 | tstr <0ddh,0cbh,1,6>,0ddafh,msbt-1,msbt-1,0ff3ch,0dbf6h,094f4h,082h,080h,061d9h 669 | tstr <020h,0,0,038h>,0,0,0,0,0,0,080h,0,0 ; (32 cycles) 670 | tstr 0,0ffh,0,0,0,0,0,057h,0,0 ; (13 cycles) 671 | db 071h,03ah,0cdh,081h ; expected crc 672 | tmsg 'shf/rot (+1)' 673 | 674 | ; shift/rotate (6784 cycles) 675 | rotz80: db 0d7h ; flag mask 676 | tstr 0cbh,0ccebh,05d4ah,0e007h,msbt,01395h,030eeh,043h,078h,03dadh 677 | tstr <0,03fh>,0,0,0,0,0,0,080h,0,0 ; (128 cycles) 678 | tstr 0,0ffh,0,0,0,-1,-1,057h,-1,0 ; (53 cycles) 679 | db 0ebh,060h,04dh,058h ; expected crc 680 | tmsg 'shf/rot ' 681 | 682 | ; n, (7936 cycles) 683 | srz80: db 0d7h ; flag mask 684 | tstr <0cbh,080h>,02cd5h,097abh,039ffh,msbt,0d14bh,06ab2h,053h,027h,0b538h 685 | tstr <0,07fh>,0,0,0,0,0,0,0,0,0 ; (128 cycles) 686 | tstr 0,0ffh,0,0,0,-1,-1,0d7h,-1,0 ; (62 cycles) 687 | db 08bh,057h,0f0h,008h ; expected crc 688 | tmsg ' n,' 689 | 690 | ; n,(+1) (1792 cycles) 691 | srzx: db 0d7h ; flag mask 692 | tstr <0ddh,0cbh,1,086h>,0fb44h,msbt-1,msbt-1,0ba09h,068beh,032d8h,010h,05eh,0a867h 693 | tstr <020h,0,0,078h>,0,0,0,0,0,0,0,0,0 ; (128 cycles) 694 | tstr 0,0ffh,0,0,0,0,0,0d7h,0,0 ;(14 cycles) 695 | db 0cch,063h,0f9h,08ah ; expected crc 696 | tmsg ' n,(+1)' 697 | 698 | ; ld (+1), (1024 cycles) 699 | st8ix1: db 0d7h ; flag mask 700 | tstr <0ddh,070h,1>,0270dh,msbt-1,msbt-1,0b73ah,0887bh,099eeh,086h,070h,0ca07h 701 | tstr <020h,003h>,0,1,1,0,0,0,0,0,0 ; (32 cycles) 702 | tstr 0,0,0,0,0,-1,-1,0,0,0 ; (32 cycles) 703 | db 004h,062h,06ah,0bfh ; expected crc 704 | tmsg 'ld (+1),' 705 | 706 | ; ld (+1), (256 cycles) 707 | st8ix2: db 0d7h ; flag mask 708 | tstr <0ddh,074h,1>,0b664h,msbt-1,msbt-1,0e8ach,0b5f5h,0aafeh,012h,010h,09566h 709 | tstr <020h,001h>,0,1,1,0,0,0,0,0,0 ; (16 cycles) 710 | tstr 0,0,0,0,-1,0,0,0,0,0 ; (32 cycles) 711 | db 06ah,01ah,088h,031h ; expected crc 712 | tmsg 'ld (+1),' 713 | 714 | ; ld (+1),a (64 cycles) 715 | st8ix3: db 0d7h ; flag mask 716 | tstr <0ddh,077h,1>,067afh,msbt-1,msbt-1,04f13h,00644h,0bcd7h,050h,0ach,05fafh 717 | tstr 020h,0,1,1,0,0,0,0,0,0 ; (8 cycles) 718 | tstr 0,0,0,0,0,0,0,0,-1,0 ; (8 cycles) 719 | db 0cch,0beh,05ah,096h ; expected crc 720 | tmsg 'ld (+1),a' 721 | 722 | ; ld (),a (96 cycles) 723 | stabd: db 0d7h ; flag mask 724 | tstr 2,00c3bh,0b592h,06cffh,0959eh,msbt,msbt+1,0c1h,021h,0bde7h 725 | tstr 018h,0,0,0,0,0,0,0,0,0 ; (4 cycles) 726 | tstr 0,-1,0,0,0,0,0,0,-1,0 ; (24 cycles) 727 | db 07ah,04ch,011h,04fh ; expected crc 728 | tmsg 'ld (),a' 729 | 730 | ; start test pointed to by (hl) 731 | stt: push hl 732 | ld a,(hl) ; get pointer to test 733 | inc hl 734 | ld h,(hl) 735 | ld l,a 736 | ld a,(hl) ; flag mask 737 | ld (flgmsk+1),a 738 | inc hl 739 | push hl 740 | ld de,20 741 | add hl,de ; point to incmask 742 | ld de,counter 743 | call initmask 744 | pop hl 745 | push hl 746 | ld de,20+20 747 | add hl,de ; point to scanmask 748 | ld de,shifter 749 | call initmask 750 | ld hl,shifter 751 | ld (hl),1 ; first bit 752 | pop hl 753 | push hl 754 | ld de,iut ; copy initial instruction under test 755 | ld bc,4 756 | ldir 757 | ld de,msbt ; copy initial machine state 758 | ld bc,16 759 | ldir 760 | ld de,20+20+4 ; skip incmask, scanmask and expcrc 761 | add hl,de 762 | ex de,hl 763 | ld c,9 764 | call bdos ; show test name 765 | call initcrc ; initialise crc 766 | ; test loop 767 | tlp: ld a,(iut) 768 | cp 076h ; pragmatically avoid halt intructions 769 | jp z,tlp2 770 | and a,0dfh 771 | cp 0ddh 772 | jp nz,tlp1 773 | ld a,(iut+1) 774 | cp 076h 775 | tlp1: call nz,test ; execute the test instruction 776 | tlp2: call count ; increment the counter 777 | call nz,shift ; shift the scan bit 778 | pop hl ; pointer to test case 779 | jp z,tlp3 ; done if shift returned NZ 780 | ld de,20+20+20 781 | add hl,de ; point to expected crc 782 | call cmpcrc 783 | ld de,okmsg 784 | jp z,tlpok 785 | ld de,ermsg1 786 | ld c,9 787 | call bdos 788 | call phex8 789 | ld de,ermsg2 790 | ld c,9 791 | call bdos 792 | ld hl,crcval 793 | call phex8 794 | ld de,crlf 795 | tlpok: ld c,9 796 | call bdos 797 | pop hl 798 | inc hl 799 | inc hl 800 | ret 801 | 802 | tlp3: push hl 803 | ld a,1 ; initialise count and shift scanners 804 | ld (cntbit),a 805 | ld (shfbit),a 806 | ld hl,counter 807 | ld (cntbyt),hl 808 | ld hl,shifter 809 | ld (shfbyt),hl 810 | 811 | ld b,4 ; bytes in iut field 812 | pop hl ; pointer to test case 813 | push hl 814 | ld de,iut 815 | call setup ; setup iut 816 | ld b,16 ; bytes in machine state 817 | ld de,msbt 818 | call setup ; setup machine state 819 | jp tlp 820 | 821 | ; setup a field of the test case 822 | ; b = number of bytes 823 | ; hl = pointer to base case 824 | ; de = destination 825 | setup: call subyte 826 | inc hl 827 | dec b 828 | jp nz,setup 829 | ret 830 | 831 | subyte: push bc 832 | push de 833 | push hl 834 | ld c,(hl) ; get base byte 835 | ld de,20 836 | add hl,de ; point to incmask 837 | ld a,(hl) 838 | cp 0 839 | jp z,subshf 840 | ld b,8 ; 8 bits 841 | subclp: rrca 842 | push af 843 | ld a,0 844 | call c,nxtcbit ; get next counter bit if mask bit was set 845 | xor c ; flip bit if counter bit was set 846 | rrca 847 | ld c,a 848 | pop af 849 | dec b 850 | jp nz,subclp 851 | ld b,8 852 | subshf: ld de,20 853 | add hl,de ; point to shift mask 854 | ld a,(hl) 855 | cp 0 856 | jp z,substr 857 | ld b,8 ; 8 bits 858 | sbshf1: rrca 859 | push af 860 | ld a,0 861 | call c,nxtsbit ; get next shifter bit if mask bit was set 862 | xor c ; flip bit if shifter bit was set 863 | rrca 864 | ld c,a 865 | pop af 866 | dec b 867 | jp nz,sbshf1 868 | substr: pop hl 869 | pop de 870 | ld a,c 871 | ld (de),a ; mangled byte to destination 872 | inc de 873 | pop bc 874 | ret 875 | 876 | ; get next counter bit in low bit of a 877 | cntbit: ds 1 878 | cntbyt: ds 2 879 | 880 | nxtcbit: push bc 881 | push hl 882 | ld hl,(cntbyt) 883 | ld b,(hl) 884 | ld hl,cntbit 885 | ld a,(hl) 886 | ld c,a 887 | rlca 888 | ld (hl),a 889 | cp a,1 890 | jp nz,ncb1 891 | ld hl,(cntbyt) 892 | inc hl 893 | ld (cntbyt),hl 894 | ncb1: ld a,b 895 | and c 896 | pop hl 897 | pop bc 898 | ret z 899 | ld a,1 900 | ret 901 | 902 | ; get next shifter bit in low bit of a 903 | shfbit: ds 1 904 | shfbyt: ds 2 905 | 906 | nxtsbit: push bc 907 | push hl 908 | ld hl,(shfbyt) 909 | ld b,(hl) 910 | ld hl,shfbit 911 | ld a,(hl) 912 | ld c,a 913 | rlca 914 | ld (hl),a 915 | cp a,1 916 | jp nz,nsb1 917 | ld hl,(shfbyt) 918 | inc hl 919 | ld (shfbyt),hl 920 | nsb1: ld a,b 921 | and c 922 | pop hl 923 | pop bc 924 | ret z 925 | ld a,1 926 | ret 927 | 928 | 929 | ; clear memory at hl, bc bytes 930 | clrmem: push af 931 | push bc 932 | push de 933 | push hl 934 | ld (hl),0 935 | ld d,h 936 | ld e,l 937 | inc de 938 | dec bc 939 | ldir 940 | pop hl 941 | pop de 942 | pop bc 943 | pop af 944 | ret 945 | 946 | ; initialise counter or shifter 947 | ; de = pointer to work area for counter or shifter 948 | ; hl = pointer to mask 949 | initmask: 950 | push de 951 | ex de,hl 952 | ld bc,20+20 953 | call clrmem ; clear work area 954 | ex de,hl 955 | ld b,20 ; byte counter 956 | ld c,1 ; first bit 957 | ld d,0 ; bit counter 958 | imlp: ld e,(hl) 959 | imlp1: ld a,e 960 | and a,c 961 | jp z,imlp2 962 | inc d 963 | imlp2: ld a,c 964 | rlca 965 | ld c,a 966 | cp a,1 967 | jp nz,imlp1 968 | inc hl 969 | dec b 970 | jp nz,imlp 971 | ; got number of 1-bits in mask in reg d 972 | ld a,d 973 | and 0f8h 974 | rrca 975 | rrca 976 | rrca ; divide by 8 (get byte offset) 977 | ld l,a 978 | ld h,0 979 | ld a,d 980 | and a,7 ; bit offset 981 | inc a 982 | ld b,a 983 | ld a,080h 984 | imlp3: rlca 985 | dec b 986 | jp nz,imlp3 987 | pop de 988 | add hl,de 989 | ld de,20 990 | add hl,de 991 | ld (hl),a 992 | ret 993 | 994 | ; multi-byte counter 995 | count: push bc 996 | push de 997 | push hl 998 | ld hl,counter ; 20 byte counter starts here 999 | ld de,20 ; somewhere in here is the stop bit 1000 | ex de,hl 1001 | add hl,de 1002 | ex de,hl 1003 | cntlp: inc (hl) 1004 | ld a,(hl) 1005 | cp 0 1006 | jp z,cntlp1 ; overflow to next byte 1007 | ld b,a 1008 | ld a,(de) 1009 | and a,b ; test for terminal value 1010 | jp z,cntend 1011 | ld (hl),0 ; reset to zero 1012 | cntend: pop bc 1013 | pop de 1014 | pop hl 1015 | ret 1016 | 1017 | cntlp1: inc hl 1018 | inc de 1019 | jp cntlp 1020 | 1021 | 1022 | ; multi-byte shifter 1023 | shift: push bc 1024 | push de 1025 | push hl 1026 | ld hl,shifter ; 20 byte shift register starts here 1027 | ld de,20 ; somewhere in here is the stop bit 1028 | ex de,hl 1029 | add hl,de 1030 | ex de,hl 1031 | shflp: ld a,(hl) 1032 | or a 1033 | jp z,shflp1 1034 | ld b,a 1035 | ld a,(de) 1036 | and b 1037 | jp nz,shlpe 1038 | ld a,b 1039 | rlca 1040 | cp a,1 1041 | jp nz,shflp2 1042 | ld (hl),0 1043 | inc hl 1044 | inc de 1045 | shflp2: ld (hl),a 1046 | xor a ; set Z 1047 | shlpe: pop hl 1048 | pop de 1049 | pop bc 1050 | ret 1051 | shflp1: inc hl 1052 | inc de 1053 | jp shflp 1054 | 1055 | counter: ds 2*20 1056 | shifter: ds 2*20 1057 | 1058 | ; test harness 1059 | test: push af 1060 | push bc 1061 | push de 1062 | push hl 1063 | if 0 1064 | ld de,crlf 1065 | ld c,9 1066 | call bdos 1067 | ld hl,iut 1068 | ld b,4 1069 | call hexstr 1070 | ld e,' ' 1071 | ld c,2 1072 | call bdos 1073 | ld b,16 1074 | ld hl,msbt 1075 | call hexstr 1076 | endif 1077 | di ; disable interrupts 1078 | ld (spsav),sp ; save stack pointer 1079 | ld sp,msbt+2 ; point to test-case machine state 1080 | pop iy ; and load all regs 1081 | pop ix 1082 | pop hl 1083 | pop de 1084 | pop bc 1085 | pop af 1086 | ld sp,(spbt) 1087 | iut: ds 4 ; max 4 byte instruction under test 1088 | ld (spat),sp ; save stack pointer 1089 | ld sp,spat 1090 | push af ; save other registers 1091 | push bc 1092 | push de 1093 | push hl 1094 | push ix 1095 | push iy 1096 | ld sp,(spsav) ; restore stack pointer 1097 | ei ; enable interrupts 1098 | ld hl,(msbt) ; copy memory operand 1099 | ld (msat),hl 1100 | ld hl,flgsat ; flags after test 1101 | ld a,(hl) 1102 | flgmsk: and a,0d7h ; mask-out irrelevant bits (self-modified code!) 1103 | ld (hl),a 1104 | ld b,16 ; total of 16 bytes of state 1105 | ld de,msat 1106 | ld hl,crcval 1107 | tcrc: ld a,(de) 1108 | inc de 1109 | call updcrc ; accumulate crc of this test case 1110 | dec b 1111 | jp nz,tcrc 1112 | if 0 1113 | ld e,' ' 1114 | ld c,2 1115 | call bdos 1116 | ld hl,crcval 1117 | call phex8 1118 | ld de,crlf 1119 | ld c,9 1120 | call bdos 1121 | ld hl,msat 1122 | ld b,16 1123 | call hexstr 1124 | ld de,crlf 1125 | ld c,9 1126 | call bdos 1127 | endif 1128 | pop hl 1129 | pop de 1130 | pop bc 1131 | pop af 1132 | ret 1133 | 1134 | ; machine state after test 1135 | msat: ds 14 ; memop,iy,ix,hl,de,bc,af 1136 | spat: ds 2 ; stack pointer after test 1137 | flgsat: equ spat-2 ; flags 1138 | 1139 | spsav: ds 2 ; saved stack pointer 1140 | 1141 | ; display hex string (pointer in hl, byte count in b) 1142 | hexstr: ld a,(hl) 1143 | call phex2 1144 | inc hl 1145 | dec b 1146 | jp nz,hexstr 1147 | ret 1148 | 1149 | ; display hex 1150 | ; display the big-endian 32-bit value pointed to by hl 1151 | phex8: push af 1152 | push bc 1153 | push hl 1154 | ld b,4 1155 | ph8lp: ld a,(hl) 1156 | call phex2 1157 | inc hl 1158 | dec b 1159 | jp nz,ph8lp 1160 | pop hl 1161 | pop bc 1162 | pop af 1163 | ret 1164 | 1165 | ; display byte in a 1166 | phex2: push af 1167 | rrca 1168 | rrca 1169 | rrca 1170 | rrca 1171 | call phex1 1172 | pop af 1173 | ; fall through 1174 | 1175 | ; display low nibble in a 1176 | phex1: push af 1177 | push bc 1178 | push de 1179 | push hl 1180 | and a,0fh 1181 | cp a,10 1182 | jp c,ph11 1183 | add a,'a'-'9'-1 1184 | ph11: add a,'0' 1185 | ld e,a 1186 | ld c,2 1187 | call bdos 1188 | pop hl 1189 | pop de 1190 | pop bc 1191 | pop af 1192 | ret 1193 | 1194 | bdos push af 1195 | push bc 1196 | push de 1197 | push hl 1198 | call 5 1199 | pop hl 1200 | pop de 1201 | pop bc 1202 | pop af 1203 | ret 1204 | 1205 | msg1: db 'Z80 instruction exerciser',10,13,'$' 1206 | msg2: db 'Tests complete$' 1207 | okmsg: db ' OK',10,13,'$' 1208 | ermsg1: db ' ERROR **** crc expected:$' 1209 | ermsg2: db ' found:$' 1210 | crlf: db 10,13,'$' 1211 | 1212 | ; compare crc 1213 | ; hl points to value to compare to crcval 1214 | cmpcrc: push bc 1215 | push de 1216 | push hl 1217 | ld de,crcval 1218 | ld b,4 1219 | cclp: ld a,(de) 1220 | cp a,(hl) 1221 | jp nz,cce 1222 | inc hl 1223 | inc de 1224 | dec b 1225 | jp nz,cclp 1226 | cce: pop hl 1227 | pop de 1228 | pop bc 1229 | ret 1230 | 1231 | ; 32-bit crc routine 1232 | ; entry: a contains next byte, hl points to crc 1233 | ; exit: crc updated 1234 | updcrc: push af 1235 | push bc 1236 | push de 1237 | push hl 1238 | push hl 1239 | ld de,3 1240 | add hl,de ; point to low byte of old crc 1241 | xor a,(hl) ; xor with new byte 1242 | ld l,a 1243 | ld h,0 1244 | add hl,hl ; use result as index into table of 4 byte entries 1245 | add hl,hl 1246 | ex de,hl 1247 | ld hl,crctab 1248 | add hl,de ; point to selected entry in crctab 1249 | ex de,hl 1250 | pop hl 1251 | ld bc,4 ; c = byte count, b = accumulator 1252 | crclp: ld a,(de) 1253 | xor a,b 1254 | ld b,(hl) 1255 | ld (hl),a 1256 | inc de 1257 | inc hl 1258 | dec c 1259 | jp nz,crclp 1260 | if 0 1261 | ld hl,crcval 1262 | call phex8 1263 | ld de,crlf 1264 | ld c,9 1265 | call bdos 1266 | endif 1267 | pop hl 1268 | pop de 1269 | pop bc 1270 | pop af 1271 | ret 1272 | 1273 | initcrc:push af 1274 | push bc 1275 | push hl 1276 | ld hl,crcval 1277 | ld a,0ffh 1278 | ld b,4 1279 | icrclp: ld (hl),a 1280 | inc hl 1281 | dec b 1282 | jp nz,icrclp 1283 | pop hl 1284 | pop bc 1285 | pop af 1286 | ret 1287 | 1288 | crcval ds 4 1289 | 1290 | crctab: db 000h,000h,000h,000h 1291 | db 077h,007h,030h,096h 1292 | db 0eeh,00eh,061h,02ch 1293 | db 099h,009h,051h,0bah 1294 | db 007h,06dh,0c4h,019h 1295 | db 070h,06ah,0f4h,08fh 1296 | db 0e9h,063h,0a5h,035h 1297 | db 09eh,064h,095h,0a3h 1298 | db 00eh,0dbh,088h,032h 1299 | db 079h,0dch,0b8h,0a4h 1300 | db 0e0h,0d5h,0e9h,01eh 1301 | db 097h,0d2h,0d9h,088h 1302 | db 009h,0b6h,04ch,02bh 1303 | db 07eh,0b1h,07ch,0bdh 1304 | db 0e7h,0b8h,02dh,007h 1305 | db 090h,0bfh,01dh,091h 1306 | db 01dh,0b7h,010h,064h 1307 | db 06ah,0b0h,020h,0f2h 1308 | db 0f3h,0b9h,071h,048h 1309 | db 084h,0beh,041h,0deh 1310 | db 01ah,0dah,0d4h,07dh 1311 | db 06dh,0ddh,0e4h,0ebh 1312 | db 0f4h,0d4h,0b5h,051h 1313 | db 083h,0d3h,085h,0c7h 1314 | db 013h,06ch,098h,056h 1315 | db 064h,06bh,0a8h,0c0h 1316 | db 0fdh,062h,0f9h,07ah 1317 | db 08ah,065h,0c9h,0ech 1318 | db 014h,001h,05ch,04fh 1319 | db 063h,006h,06ch,0d9h 1320 | db 0fah,00fh,03dh,063h 1321 | db 08dh,008h,00dh,0f5h 1322 | db 03bh,06eh,020h,0c8h 1323 | db 04ch,069h,010h,05eh 1324 | db 0d5h,060h,041h,0e4h 1325 | db 0a2h,067h,071h,072h 1326 | db 03ch,003h,0e4h,0d1h 1327 | db 04bh,004h,0d4h,047h 1328 | db 0d2h,00dh,085h,0fdh 1329 | db 0a5h,00ah,0b5h,06bh 1330 | db 035h,0b5h,0a8h,0fah 1331 | db 042h,0b2h,098h,06ch 1332 | db 0dbh,0bbh,0c9h,0d6h 1333 | db 0ach,0bch,0f9h,040h 1334 | db 032h,0d8h,06ch,0e3h 1335 | db 045h,0dfh,05ch,075h 1336 | db 0dch,0d6h,00dh,0cfh 1337 | db 0abh,0d1h,03dh,059h 1338 | db 026h,0d9h,030h,0ach 1339 | db 051h,0deh,000h,03ah 1340 | db 0c8h,0d7h,051h,080h 1341 | db 0bfh,0d0h,061h,016h 1342 | db 021h,0b4h,0f4h,0b5h 1343 | db 056h,0b3h,0c4h,023h 1344 | db 0cfh,0bah,095h,099h 1345 | db 0b8h,0bdh,0a5h,00fh 1346 | db 028h,002h,0b8h,09eh 1347 | db 05fh,005h,088h,008h 1348 | db 0c6h,00ch,0d9h,0b2h 1349 | db 0b1h,00bh,0e9h,024h 1350 | db 02fh,06fh,07ch,087h 1351 | db 058h,068h,04ch,011h 1352 | db 0c1h,061h,01dh,0abh 1353 | db 0b6h,066h,02dh,03dh 1354 | db 076h,0dch,041h,090h 1355 | db 001h,0dbh,071h,006h 1356 | db 098h,0d2h,020h,0bch 1357 | db 0efh,0d5h,010h,02ah 1358 | db 071h,0b1h,085h,089h 1359 | db 006h,0b6h,0b5h,01fh 1360 | db 09fh,0bfh,0e4h,0a5h 1361 | db 0e8h,0b8h,0d4h,033h 1362 | db 078h,007h,0c9h,0a2h 1363 | db 00fh,000h,0f9h,034h 1364 | db 096h,009h,0a8h,08eh 1365 | db 0e1h,00eh,098h,018h 1366 | db 07fh,06ah,00dh,0bbh 1367 | db 008h,06dh,03dh,02dh 1368 | db 091h,064h,06ch,097h 1369 | db 0e6h,063h,05ch,001h 1370 | db 06bh,06bh,051h,0f4h 1371 | db 01ch,06ch,061h,062h 1372 | db 085h,065h,030h,0d8h 1373 | db 0f2h,062h,000h,04eh 1374 | db 06ch,006h,095h,0edh 1375 | db 01bh,001h,0a5h,07bh 1376 | db 082h,008h,0f4h,0c1h 1377 | db 0f5h,00fh,0c4h,057h 1378 | db 065h,0b0h,0d9h,0c6h 1379 | db 012h,0b7h,0e9h,050h 1380 | db 08bh,0beh,0b8h,0eah 1381 | db 0fch,0b9h,088h,07ch 1382 | db 062h,0ddh,01dh,0dfh 1383 | db 015h,0dah,02dh,049h 1384 | db 08ch,0d3h,07ch,0f3h 1385 | db 0fbh,0d4h,04ch,065h 1386 | db 04dh,0b2h,061h,058h 1387 | db 03ah,0b5h,051h,0ceh 1388 | db 0a3h,0bch,000h,074h 1389 | db 0d4h,0bbh,030h,0e2h 1390 | db 04ah,0dfh,0a5h,041h 1391 | db 03dh,0d8h,095h,0d7h 1392 | db 0a4h,0d1h,0c4h,06dh 1393 | db 0d3h,0d6h,0f4h,0fbh 1394 | db 043h,069h,0e9h,06ah 1395 | db 034h,06eh,0d9h,0fch 1396 | db 0adh,067h,088h,046h 1397 | db 0dah,060h,0b8h,0d0h 1398 | db 044h,004h,02dh,073h 1399 | db 033h,003h,01dh,0e5h 1400 | db 0aah,00ah,04ch,05fh 1401 | db 0ddh,00dh,07ch,0c9h 1402 | db 050h,005h,071h,03ch 1403 | db 027h,002h,041h,0aah 1404 | db 0beh,00bh,010h,010h 1405 | db 0c9h,00ch,020h,086h 1406 | db 057h,068h,0b5h,025h 1407 | db 020h,06fh,085h,0b3h 1408 | db 0b9h,066h,0d4h,009h 1409 | db 0ceh,061h,0e4h,09fh 1410 | db 05eh,0deh,0f9h,00eh 1411 | db 029h,0d9h,0c9h,098h 1412 | db 0b0h,0d0h,098h,022h 1413 | db 0c7h,0d7h,0a8h,0b4h 1414 | db 059h,0b3h,03dh,017h 1415 | db 02eh,0b4h,00dh,081h 1416 | db 0b7h,0bdh,05ch,03bh 1417 | db 0c0h,0bah,06ch,0adh 1418 | db 0edh,0b8h,083h,020h 1419 | db 09ah,0bfh,0b3h,0b6h 1420 | db 003h,0b6h,0e2h,00ch 1421 | db 074h,0b1h,0d2h,09ah 1422 | db 0eah,0d5h,047h,039h 1423 | db 09dh,0d2h,077h,0afh 1424 | db 004h,0dbh,026h,015h 1425 | db 073h,0dch,016h,083h 1426 | db 0e3h,063h,00bh,012h 1427 | db 094h,064h,03bh,084h 1428 | db 00dh,06dh,06ah,03eh 1429 | db 07ah,06ah,05ah,0a8h 1430 | db 0e4h,00eh,0cfh,00bh 1431 | db 093h,009h,0ffh,09dh 1432 | db 00ah,000h,0aeh,027h 1433 | db 07dh,007h,09eh,0b1h 1434 | db 0f0h,00fh,093h,044h 1435 | db 087h,008h,0a3h,0d2h 1436 | db 01eh,001h,0f2h,068h 1437 | db 069h,006h,0c2h,0feh 1438 | db 0f7h,062h,057h,05dh 1439 | db 080h,065h,067h,0cbh 1440 | db 019h,06ch,036h,071h 1441 | db 06eh,06bh,006h,0e7h 1442 | db 0feh,0d4h,01bh,076h 1443 | db 089h,0d3h,02bh,0e0h 1444 | db 010h,0dah,07ah,05ah 1445 | db 067h,0ddh,04ah,0cch 1446 | db 0f9h,0b9h,0dfh,06fh 1447 | db 08eh,0beh,0efh,0f9h 1448 | db 017h,0b7h,0beh,043h 1449 | db 060h,0b0h,08eh,0d5h 1450 | db 0d6h,0d6h,0a3h,0e8h 1451 | db 0a1h,0d1h,093h,07eh 1452 | db 038h,0d8h,0c2h,0c4h 1453 | db 04fh,0dfh,0f2h,052h 1454 | db 0d1h,0bbh,067h,0f1h 1455 | db 0a6h,0bch,057h,067h 1456 | db 03fh,0b5h,006h,0ddh 1457 | db 048h,0b2h,036h,04bh 1458 | db 0d8h,00dh,02bh,0dah 1459 | db 0afh,00ah,01bh,04ch 1460 | db 036h,003h,04ah,0f6h 1461 | db 041h,004h,07ah,060h 1462 | db 0dfh,060h,0efh,0c3h 1463 | db 0a8h,067h,0dfh,055h 1464 | db 031h,06eh,08eh,0efh 1465 | db 046h,069h,0beh,079h 1466 | db 0cbh,061h,0b3h,08ch 1467 | db 0bch,066h,083h,01ah 1468 | db 025h,06fh,0d2h,0a0h 1469 | db 052h,068h,0e2h,036h 1470 | db 0cch,00ch,077h,095h 1471 | db 0bbh,00bh,047h,003h 1472 | db 022h,002h,016h,0b9h 1473 | db 055h,005h,026h,02fh 1474 | db 0c5h,0bah,03bh,0beh 1475 | db 0b2h,0bdh,00bh,028h 1476 | db 02bh,0b4h,05ah,092h 1477 | db 05ch,0b3h,06ah,004h 1478 | db 0c2h,0d7h,0ffh,0a7h 1479 | db 0b5h,0d0h,0cfh,031h 1480 | db 02ch,0d9h,09eh,08bh 1481 | db 05bh,0deh,0aeh,01dh 1482 | db 09bh,064h,0c2h,0b0h 1483 | db 0ech,063h,0f2h,026h 1484 | db 075h,06ah,0a3h,09ch 1485 | db 002h,06dh,093h,00ah 1486 | db 09ch,009h,006h,0a9h 1487 | db 0ebh,00eh,036h,03fh 1488 | db 072h,007h,067h,085h 1489 | db 005h,000h,057h,013h 1490 | db 095h,0bfh,04ah,082h 1491 | db 0e2h,0b8h,07ah,014h 1492 | db 07bh,0b1h,02bh,0aeh 1493 | db 00ch,0b6h,01bh,038h 1494 | db 092h,0d2h,08eh,09bh 1495 | db 0e5h,0d5h,0beh,00dh 1496 | db 07ch,0dch,0efh,0b7h 1497 | db 00bh,0dbh,0dfh,021h 1498 | db 086h,0d3h,0d2h,0d4h 1499 | db 0f1h,0d4h,0e2h,042h 1500 | db 068h,0ddh,0b3h,0f8h 1501 | db 01fh,0dah,083h,06eh 1502 | db 081h,0beh,016h,0cdh 1503 | db 0f6h,0b9h,026h,05bh 1504 | db 06fh,0b0h,077h,0e1h 1505 | db 018h,0b7h,047h,077h 1506 | db 088h,008h,05ah,0e6h 1507 | db 0ffh,00fh,06ah,070h 1508 | db 066h,006h,03bh,0cah 1509 | db 011h,001h,00bh,05ch 1510 | db 08fh,065h,09eh,0ffh 1511 | db 0f8h,062h,0aeh,069h 1512 | db 061h,06bh,0ffh,0d3h 1513 | db 016h,06ch,0cfh,045h 1514 | db 0a0h,00ah,0e2h,078h 1515 | db 0d7h,00dh,0d2h,0eeh 1516 | db 04eh,004h,083h,054h 1517 | db 039h,003h,0b3h,0c2h 1518 | db 0a7h,067h,026h,061h 1519 | db 0d0h,060h,016h,0f7h 1520 | db 049h,069h,047h,04dh 1521 | db 03eh,06eh,077h,0dbh 1522 | db 0aeh,0d1h,06ah,04ah 1523 | db 0d9h,0d6h,05ah,0dch 1524 | db 040h,0dfh,00bh,066h 1525 | db 037h,0d8h,03bh,0f0h 1526 | db 0a9h,0bch,0aeh,053h 1527 | db 0deh,0bbh,09eh,0c5h 1528 | db 047h,0b2h,0cfh,07fh 1529 | db 030h,0b5h,0ffh,0e9h 1530 | db 0bdh,0bdh,0f2h,01ch 1531 | db 0cah,0bah,0c2h,08ah 1532 | db 053h,0b3h,093h,030h 1533 | db 024h,0b4h,0a3h,0a6h 1534 | db 0bah,0d0h,036h,005h 1535 | db 0cdh,0d7h,006h,093h 1536 | db 054h,0deh,057h,029h 1537 | db 023h,0d9h,067h,0bfh 1538 | db 0b3h,066h,07ah,02eh 1539 | db 0c4h,061h,04ah,0b8h 1540 | db 05dh,068h,01bh,002h 1541 | db 02ah,06fh,02bh,094h 1542 | db 0b4h,00bh,0beh,037h 1543 | db 0c3h,00ch,08eh,0a1h 1544 | db 05ah,005h,0dfh,01bh 1545 | db 02dh,002h,0efh,08dh 1546 | 1547 | --------------------------------------------------------------------------------