├── .gitignore ├── cpu_tests ├── 8080EXM.COM ├── 8080PRE.COM ├── CPUTEST.COM ├── TST8080.COM ├── 8080EXER.COM ├── 8080EXER.PNG ├── README.TXT ├── 8080PRE.MAC ├── TST8080.ASM ├── 8080PRE.PRN ├── TST8080.PRN ├── 8080EXER.MAC └── 8080EXM.MAC ├── Makefile ├── .github └── workflows │ └── tests_runner.yml ├── .clang-format ├── LICENSE ├── i8080.h ├── README.md ├── i8080_tests.c └── i8080.c /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | *.o 3 | i8080_tests 4 | cpm 5 | cpu_tests/sunhillow 6 | TODO.md 7 | -------------------------------------------------------------------------------- /cpu_tests/8080EXM.COM: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/superzazu/8080/HEAD/cpu_tests/8080EXM.COM -------------------------------------------------------------------------------- /cpu_tests/8080PRE.COM: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/superzazu/8080/HEAD/cpu_tests/8080PRE.COM -------------------------------------------------------------------------------- /cpu_tests/CPUTEST.COM: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/superzazu/8080/HEAD/cpu_tests/CPUTEST.COM -------------------------------------------------------------------------------- /cpu_tests/TST8080.COM: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/superzazu/8080/HEAD/cpu_tests/TST8080.COM -------------------------------------------------------------------------------- /cpu_tests/8080EXER.COM: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/superzazu/8080/HEAD/cpu_tests/8080EXER.COM -------------------------------------------------------------------------------- /cpu_tests/8080EXER.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/superzazu/8080/HEAD/cpu_tests/8080EXER.PNG -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | bin = i8080_tests 2 | src = $(wildcard *.c) 3 | obj = $(src:.c=.o) 4 | CFLAGS = -g -Wall -Wextra -O2 -std=c99 -pedantic 5 | LDFLAGS = 6 | 7 | .PHONY: all clean 8 | 9 | all: $(bin) 10 | 11 | $(bin): $(obj) 12 | $(CC) -o $@ $^ $(LDFLAGS) 13 | 14 | clean: 15 | -rm $(bin) $(obj) 16 | -------------------------------------------------------------------------------- /.github/workflows/tests_runner.yml: -------------------------------------------------------------------------------- 1 | name: tests runner 2 | 3 | on: [push] 4 | 5 | jobs: 6 | build: 7 | 8 | runs-on: ubuntu-latest 9 | 10 | steps: 11 | - uses: actions/checkout@v1 12 | - name: make 13 | run: make 14 | - name: ./i8080_tests 15 | run: ./i8080_tests 16 | -------------------------------------------------------------------------------- /.clang-format: -------------------------------------------------------------------------------- 1 | BasedOnStyle: llvm 2 | SortIncludes: false 3 | PointerAlignment: Left 4 | AllowShortIfStatementsOnASingleLine: false 5 | AllowShortFunctionsOnASingleLine: false 6 | AllowShortLoopsOnASingleLine: false 7 | AllowShortCaseLabelsOnASingleLine: true 8 | AllowShortBlocksOnASingleLine: false 9 | AlignEscapedNewlines: DontAlign 10 | AlignAfterOpenBracket: DontAlign 11 | SpaceAfterCStyleCast: true 12 | AlignTrailingComments: false 13 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Nicolas Allemand 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /i8080.h: -------------------------------------------------------------------------------- 1 | #ifndef I8080_I8080_H_ 2 | #define I8080_I8080_H_ 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | typedef struct i8080 { 9 | // memory + io interface 10 | uint8_t (*read_byte)(void*, uint16_t); // user function to read from memory 11 | void (*write_byte)(void*, uint16_t, uint8_t); // same for writing to memory 12 | uint8_t (*port_in)(void*, uint8_t); // user function to read from port 13 | void (*port_out)(void*, uint8_t, uint8_t); // same for writing to port 14 | void* userdata; // user custom pointer 15 | 16 | unsigned long cyc; // cycle count 17 | 18 | uint16_t pc, sp; // program counter, stack pointer 19 | uint8_t a, b, c, d, e, h, l; // registers 20 | // flags: sign, zero, half-carry, parity, carry, interrupt flip-flop 21 | bool sf : 1, zf : 1, hf : 1, pf : 1, cf : 1, iff : 1; 22 | bool halted : 1; 23 | 24 | bool interrupt_pending : 1; 25 | uint8_t interrupt_vector; 26 | uint8_t interrupt_delay; 27 | } i8080; 28 | 29 | void i8080_init(i8080* const c); 30 | void i8080_step(i8080* const c); 31 | void i8080_interrupt(i8080* const c, uint8_t opcode); 32 | void i8080_debug_output(i8080* const c, bool print_disassembly); 33 | 34 | #endif // I8080_I8080_H_ 35 | -------------------------------------------------------------------------------- /cpu_tests/README.TXT: -------------------------------------------------------------------------------- 1 | This folder contains 8080 CPU test programs that run under CP/M 2 | 3 | TST8080 4 | 8080/8085 CPU Diagnostic, version 1.0, by Microcosm Associates 5 | (Kelly Smith test) 6 | 7 | 8080PRE 8 | Preliminary test for 8080/8085 CPU Exerciser by Ian Bartholomew 9 | and Frank Cringles. 10 | 11 | 8080EXER 12 | 8080/8085 CPU Exerciser by Ian Bartholomew and Frank Cringles. 13 | This is a very thorough test that generates a CRC code for each 14 | group of tests. The program will say "Error" for every test, but 15 | it's not actually an error. Instead, compare the reported CRC 16 | with results from tests against real silicon. See 8080EXER.PNG in 17 | this directory and http://www.idb.me.uk/sunhillow/8080.html. The 18 | full test takes several hours. The "aluop " section 19 | takes especially long. 20 | 21 | 8080EXM 22 | 8080/80805 Exerciser "M"odified with the correct result CRCs in 23 | the program so it can display "pass" or "fail" correctly. 24 | 25 | CPUTEST 26 | SuperSoft Associates CPU test from the Diagnostic II 27 | suite. When it displays "ABCDEF..." those are actually 28 | indications of test that have passed. Additional testing 29 | occurs during the "Begin Timing Test" and "End Timing Test" 30 | period. On a 2MHz 8080, the timing test period lasts about 31 | two minutes. 32 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 8080 2 | 3 | A complete emulation of the Intel 8080 processor written in C99. Goals: 4 | 5 | - accuracy: it passes all test roms at my disposal 6 | - readability 7 | - portability: tested on debian 8 with gcc 5, macOS 10.12+ with clang and emscripten 1.39 8 | 9 | You can see it in action in my [Space Invaders emulator](https://github.com/superzazu/invaders). 10 | 11 | ## Running tests 12 | 13 | You can run the tests by running `make && ./i8080_tests`. The emulator passes the following tests: 14 | 15 | - [x] TST8080.COM 16 | - [x] CPUTEST.COM 17 | - [x] 8080PRE.COM 18 | - [x] 8080EXM.COM 19 | 20 | The test roms (`cpu_tests` folder) are taken from [here](http://altairclone.com/downloads/cpu_tests/) and take approximately 30 seconds on my computer (MacBook Pro mid-2014) to run. 21 | 22 | The standard output is as follows: 23 | 24 | ``` 25 | *** TEST: cpu_tests/TST8080.COM 26 | MICROCOSM ASSOCIATES 8080/8085 CPU DIAGNOSTIC 27 | VERSION 1.0 (C) 1980 28 | 29 | CPU IS OPERATIONAL 30 | *** 651 instructions executed on 4924 cycles (expected=4924, diff=0) 31 | 32 | *** TEST: cpu_tests/CPUTEST.COM 33 | 34 | DIAGNOSTICS II V1.2 - CPU TEST 35 | COPYRIGHT (C) 1981 - SUPERSOFT ASSOCIATES 36 | 37 | ABCDEFGHIJKLMNOPQRSTUVWXYZ 38 | CPU IS 8080/8085 39 | BEGIN TIMING TEST 40 | END TIMING TEST 41 | CPU TESTS OK 42 | 43 | *** 33971311 instructions executed on 255653383 cycles (expected=255653383, diff=0) 44 | 45 | *** TEST: cpu_tests/8080PRE.COM 46 | 8080 Preliminary tests complete 47 | *** 1061 instructions executed on 7817 cycles (expected=7817, diff=0) 48 | 49 | *** TEST: cpu_tests/8080EXM.COM 50 | 8080 instruction exerciser 51 | dad ................ PASS! crc is:14474ba6 52 | aluop nn...................... PASS! crc is:9e922f9e 53 | aluop ....... PASS! crc is:cf762c86 54 | ............. PASS! crc is:bb3f030c 55 | a................... PASS! crc is:adb6460e 56 | b................... PASS! crc is:83ed1345 57 | b................... PASS! crc is:f79287cd 58 | c................... PASS! crc is:e5f6721b 59 | d................... PASS! crc is:15b5579a 60 | d................... PASS! crc is:7f4e2501 61 | e................... PASS! crc is:cf2ab396 62 | h................... PASS! crc is:12b2952c 63 | h................... PASS! crc is:9f2b23c0 64 | l................... PASS! crc is:ff57d356 65 | m................... PASS! crc is:92e963bd 66 | sp.................. PASS! crc is:d5702fab 67 | lhld nnnn..................... PASS! crc is:a9c3d5cb 68 | shld nnnn..................... PASS! crc is:e8864f26 69 | lxi ,nnnn........... PASS! crc is:fcf46e12 70 | ldax .................... PASS! crc is:2b821d5f 71 | mvi ,nn...... PASS! crc is:eaa72044 72 | mov ,....... PASS! crc is:10b58cee 73 | sta nnnn / lda nnnn........... PASS! crc is:ed57af72 74 | ............. PASS! crc is:e0d89235 75 | stax .................... PASS! crc is:2b0471e9 76 | Tests complete 77 | *** 2919050698 instructions executed on 23803381171 cycles (expected=23803381171, diff=0) 78 | 79 | ``` 80 | 81 | ## Resources used 82 | 83 | - [CPU instructions](http://nemesis.lonestar.org/computers/tandy/software/apps/m4/qd/opcodes.html) and [this table](http://www.pastraiser.com/cpu/i8080/i8080_opcodes.html) 84 | - [MAME i8085](https://github.com/mamedev/mame/blob/6c0fdfc5257ca20555fbc527203710d5af5401d1/src/devices/cpu/i8085/i8085.cpp) 85 | - [thibaultimbert's Intel8080](https://github.com/thibaultimbert/Intel8080/blob/master/8080.js) and [begoon's i8080-js](https://github.com/begoon/i8080-js) 86 | -------------------------------------------------------------------------------- /i8080_tests.c: -------------------------------------------------------------------------------- 1 | // This file uses the 8080 emulator to run the test suite (roms in cpu_tests 2 | // directory). It uses a simple array as memory. 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include "i8080.h" 9 | 10 | // memory callbacks 11 | #define MEMORY_SIZE 0x10000 12 | static uint8_t* memory = NULL; 13 | static bool test_finished = 0; 14 | 15 | static uint8_t rb(void* userdata, uint16_t addr) { 16 | return memory[addr]; 17 | } 18 | 19 | static void wb(void* userdata, uint16_t addr, uint8_t val) { 20 | memory[addr] = val; 21 | } 22 | 23 | static uint8_t port_in(void* userdata, uint8_t port) { 24 | return 0x00; 25 | } 26 | 27 | static void port_out(void* userdata, uint8_t port, uint8_t value) { 28 | i8080* const c = (i8080*) userdata; 29 | 30 | if (port == 0) { 31 | test_finished = 1; 32 | } else if (port == 1) { 33 | uint8_t operation = c->c; 34 | 35 | if (operation == 2) { // print a character stored in E 36 | printf("%c", c->e); 37 | } else if (operation == 9) { // print from memory at (DE) until '$' char 38 | uint16_t addr = (c->d << 8) | c->e; 39 | do { 40 | printf("%c", rb(c, addr++)); 41 | } while (rb(c, addr) != '$'); 42 | } 43 | } 44 | } 45 | 46 | static inline int load_file(const char* filename, uint16_t addr) { 47 | FILE* f = fopen(filename, "rb"); 48 | if (f == NULL) { 49 | fprintf(stderr, "error: can't open file '%s'.\n", filename); 50 | return 1; 51 | } 52 | 53 | // file size check: 54 | fseek(f, 0, SEEK_END); 55 | size_t file_size = ftell(f); 56 | rewind(f); 57 | 58 | if (file_size + addr >= MEMORY_SIZE) { 59 | fprintf(stderr, "error: file %s can't fit in memory.\n", filename); 60 | return 1; 61 | } 62 | 63 | // copying the bytes in memory: 64 | size_t result = fread(&memory[addr], sizeof(uint8_t), file_size, f); 65 | if (result != file_size) { 66 | fprintf(stderr, "error: while reading file '%s'\n", filename); 67 | return 1; 68 | } 69 | 70 | fclose(f); 71 | return 0; 72 | } 73 | 74 | static inline void run_test( 75 | i8080* const c, const char* filename, unsigned long cyc_expected) { 76 | i8080_init(c); 77 | c->userdata = c; 78 | c->read_byte = rb; 79 | c->write_byte = wb; 80 | c->port_in = port_in; 81 | c->port_out = port_out; 82 | memset(memory, 0, MEMORY_SIZE); 83 | 84 | if (load_file(filename, 0x100) != 0) { 85 | return; 86 | } 87 | printf("*** TEST: %s\n", filename); 88 | 89 | c->pc = 0x100; 90 | 91 | // inject "out 0,a" at 0x0000 (signal to stop the test) 92 | memory[0x0000] = 0xD3; 93 | memory[0x0001] = 0x00; 94 | 95 | // inject "out 1,a" at 0x0005 (signal to output some characters) 96 | memory[0x0005] = 0xD3; 97 | memory[0x0006] = 0x01; 98 | memory[0x0007] = 0xC9; 99 | 100 | long nb_instructions = 0; 101 | 102 | test_finished = 0; 103 | while (!test_finished) { 104 | nb_instructions += 1; 105 | 106 | // uncomment following line to have a debug output of machine state 107 | // warning: will output multiple GB of data for the whole test suite 108 | // i8080_debug_output(c, false); 109 | 110 | i8080_step(c); 111 | } 112 | 113 | long long diff = cyc_expected - c->cyc; 114 | printf("\n*** %lu instructions executed on %lu cycles" 115 | " (expected=%lu, diff=%lld)\n\n", 116 | nb_instructions, c->cyc, cyc_expected, diff); 117 | } 118 | 119 | int main(void) { 120 | memory = malloc(MEMORY_SIZE); 121 | if (memory == NULL) { 122 | return 1; 123 | } 124 | 125 | i8080 cpu; 126 | run_test(&cpu, "cpu_tests/TST8080.COM", 4924LU); 127 | run_test(&cpu, "cpu_tests/CPUTEST.COM", 255653383LU); 128 | run_test(&cpu, "cpu_tests/8080PRE.COM", 7817LU); 129 | run_test(&cpu, "cpu_tests/8080EXM.COM", 23803381171LU); 130 | 131 | free(memory); 132 | 133 | return 0; 134 | } 135 | -------------------------------------------------------------------------------- /cpu_tests/8080PRE.MAC: -------------------------------------------------------------------------------- 1 | title 'Preliminary Z80 tests' 2 | 3 | ; prelim.z80 - Preliminary Z80 tests 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 | 21 | ; These tests have two goals. To start with, we assume the worst and 22 | ; successively test the instructions needed to continue testing. 23 | ; Then we try to test all instructions which cannot be handled by 24 | ; zexlax - the crc-based instruction exerciser. 25 | 26 | ; Initially errors are 'reported' by jumping to 0. This should reboot 27 | ; cp/m, so if the program terminates without any output one of the 28 | ; early tests failed. Later errors are reported by outputting an 29 | ; address via the bdos conout routine. The address can be located in 30 | ; a listing of this program. 31 | 32 | ; If the program runs to completion it displays a suitable message. 33 | 34 | ;****************************************************************************** 35 | ; 36 | ; Modified by Ian Bartholomew to run a preliminary test on an 8080 CPU 37 | ; 38 | ; Assemble using M80 39 | ; 40 | ;****************************************************************************** 41 | 42 | .8080 43 | aseg 44 | org 100h 45 | 46 | start: mvi a,1 ; test simple compares and z/nz jumps 47 | cpi 2 48 | jz 0 49 | cpi 1 50 | jnz 0 51 | jmp lab0 52 | hlt ; emergency exit 53 | db 0ffh 54 | 55 | lab0: call lab2 ; does a simple call work? 56 | lab1: jmp 0 ; fail 57 | 58 | lab2: pop h ; check return address 59 | mov a,h 60 | cpi high lab1 61 | jz lab3 62 | jmp 0 63 | lab3: mov a,l 64 | cpi low lab1 65 | jz lab4 66 | jmp 0 67 | 68 | ; test presence and uniqueness of all machine registers 69 | ; (except ir) 70 | lab4: lxi sp,regs1 71 | pop psw 72 | pop b 73 | pop d 74 | pop h 75 | lxi sp,regs2+8 76 | push h 77 | push d 78 | push b 79 | push psw 80 | 81 | v defl 0 82 | rept 8 83 | lda regs2+v/2 84 | v defl v+2 85 | cpi v 86 | jnz 0 87 | endm 88 | 89 | ; test access to memory via (hl) 90 | lxi h,hlval 91 | mov a,m 92 | cpi 0a5h 93 | jnz 0 94 | lxi h,hlval+1 95 | mov a,m 96 | cpi 03ch 97 | jnz 0 98 | 99 | ; test unconditional return 100 | lxi sp,stack 101 | lxi h,reta 102 | push h 103 | ret 104 | jmp 0 105 | 106 | ; test instructions needed for hex output 107 | reta: mvi a,0ffh 108 | ani 0fh 109 | cpi 0fh 110 | jnz 0 111 | mvi a,05ah 112 | ani 0fh 113 | cpi 0ah 114 | jnz 0 115 | rrc 116 | cpi 05h 117 | jnz 0 118 | rrc 119 | cpi 82h 120 | jnz 0 121 | rrc 122 | cpi 41h 123 | jnz 0 124 | rrc 125 | cpi 0a0h 126 | jnz 0 127 | lxi h,01234h 128 | push h 129 | pop b 130 | mov a,b 131 | cpi 12h 132 | jnz 0 133 | mov a,c 134 | cpi 34h 135 | jnz 0 136 | 137 | ; from now on we can report errors by displaying an address 138 | 139 | ; test conditional call, ret, jp, jr 140 | tcond macro flag,pcond,ncond,rel 141 | lxi h,&flag 142 | push h 143 | pop psw 144 | c&pcond lab1&pcond 145 | jmp error 146 | lab1&pcond: pop h 147 | lxi h,0d7h xor &flag 148 | push h 149 | pop psw 150 | c&ncond lab2&pcond 151 | jmp error 152 | lab2&pcond: pop h 153 | lxi h,lab3&pcond 154 | push h 155 | lxi h,&flag 156 | push h 157 | pop psw 158 | r&pcond 159 | call error 160 | lab3&pcond: lxi h,lab4&pcond 161 | push h 162 | lxi h,0d7h xor &flag 163 | push h 164 | pop psw 165 | r&ncond 166 | call error 167 | lab4&pcond: lxi h,&flag 168 | push h 169 | pop psw 170 | j&pcond lab5&pcond 171 | call error 172 | lab5&pcond: lxi h,0d7h xor &flag 173 | push h 174 | pop psw 175 | j&ncond lab6&pcond 176 | call error 177 | lab6&pcond: 178 | endm 179 | 180 | tcond 1,c,nc,1 181 | tcond 4,pe,po,0 182 | tcond 040h,z,nz,1 183 | tcond 080h,m,p,0 184 | 185 | ; test indirect jumps 186 | lxi h,lab7 187 | pchl 188 | call error 189 | 190 | ; djnz (and (partially) inc a, inc hl) 191 | lab7: mvi a,0a5h 192 | mvi b,4 193 | lab8: rrc 194 | dcr b 195 | jnz lab8 196 | cpi 05ah 197 | cnz error 198 | mvi b,16 199 | lab9: inr a 200 | dcr b 201 | jnz lab9 202 | cpi 06ah 203 | cnz error 204 | mvi b,0 205 | lxi h,0 206 | lab10: inx h 207 | dcr b 208 | jnz lab10 209 | mov a,h 210 | cpi 1 211 | cnz error 212 | mov a,l 213 | cpi 0 214 | cnz error 215 | 216 | allok: lxi d,okmsg 217 | mvi c,9 218 | call 5 219 | jmp 0 220 | 221 | okmsg: db '8080 Preliminary tests complete$' 222 | 223 | ; display address at top of stack and exit 224 | error: pop b 225 | mvi h,high hextab 226 | mov a,b 227 | rrc 228 | rrc 229 | rrc 230 | rrc 231 | ani 15 232 | mov l,a 233 | mov a,m 234 | call conout 235 | mov a,b 236 | ani 15 237 | mov l,a 238 | mov a,m 239 | call conout 240 | mov a,c 241 | rrc 242 | rrc 243 | rrc 244 | rrc 245 | ani 15 246 | mov l,a 247 | mov a,m 248 | call conout 249 | mov a,c 250 | ani 15 251 | mov l,a 252 | mov a,m 253 | call conout 254 | mvi a,13 255 | call conout 256 | mvi a,10 257 | call conout 258 | jmp 0 259 | 260 | conout: push psw 261 | push b 262 | push d 263 | push h 264 | mvi c,2 265 | mov e,a 266 | call 5 267 | pop h 268 | pop d 269 | pop b 270 | pop psw 271 | ret 272 | 273 | v defl 0 274 | regs1: rept 8 275 | v defl v+2 276 | db v 277 | endm 278 | 279 | regs2: ds 8,0 280 | 281 | hlval: db 0a5h,03ch 282 | 283 | ; skip to next page boundary 284 | org (($+255)/256)*256 285 | hextab: db '0123456789abcdef' 286 | ds 240 287 | 288 | stack equ $ 289 | 290 | end start 291 | -------------------------------------------------------------------------------- /cpu_tests/TST8080.ASM: -------------------------------------------------------------------------------- 1 | ;*********************************************************************** 2 | ; MICROCOSM ASSOCIATES 8080/8085 CPU DIAGNOSTIC VERSION 1.0 (C) 1980 3 | ;*********************************************************************** 4 | ; 5 | ;DONATED TO THE "SIG/M" CP/M USER'S GROUP BY: 6 | ;KELLY SMITH, MICROCOSM ASSOCIATES 7 | ;3055 WACO AVENUE 8 | ;SIMI VALLEY, CALIFORNIA, 93065 9 | ;(805) 527-9321 (MODEM, CP/M-NET (TM)) 10 | ;(805) 527-0518 (VERBAL) 11 | ; 12 | ; Updated by Mike Douglas October, 2012 13 | ; 14 | ; Added the following tests that were missing: 15 | ; mov c,m 16 | ; mov m,c 17 | ; ana b 18 | ; 19 | ; Fixed the CPUER exit routine which did not display the 20 | ; low byte of the failure address properly. 21 | ; 22 | ; Added display of the Microcosm welcome message 23 | ; 24 | ORG 00100H 25 | 26 | ; 27 | JMP CPU ;JUMP TO 8080 CPU DIAGNOSTIC 28 | ; 29 | WELCOM DB 'MICROCOSM ASSOCIATES 8080/8085 CPU DIAGNOSTIC',13,10 30 | DB ' VERSION 1.0 (C) 1980',13,10,'$' 31 | ; 32 | BDOS EQU 00005H ;BDOS ENTRY TO CP/M 33 | WBOOT EQU 00000H ;RE-ENTRY TO CP/M WARM BOOT 34 | ; 35 | ; 36 | ; 37 | ;MESSAGE OUTPUT ROUTINE 38 | ; 39 | MSG: PUSH D ;EXILE D REG. 40 | XCHG ;SWAP H&L REGS. TO D&E REGS. 41 | MVI C,9 ;LET BDOS KNOW WE WANT TO SEND A MESSAGE 42 | CALL BDOS 43 | POP D ;BACK FROM EXILE 44 | RET 45 | ; 46 | ; 47 | ; 48 | ;CHARACTER OUTPUT ROUTINE 49 | ; 50 | PCHAR: MVI C,2 51 | CALL BDOS 52 | RET 53 | ; 54 | ; 55 | ; 56 | BYTEO: PUSH PSW 57 | CALL BYTO1 58 | MOV E,A 59 | CALL PCHAR 60 | POP PSW 61 | CALL BYTO2 62 | MOV E,A 63 | JMP PCHAR 64 | BYTO1: RRC 65 | RRC 66 | RRC 67 | RRC 68 | BYTO2: ANI 0FH 69 | CPI 0AH 70 | JM BYTO3 71 | ADI 7 72 | BYTO3: ADI 30H 73 | RET 74 | ; 75 | ; 76 | ; 77 | ;************************************************************ 78 | ; MESSAGE TABLE FOR OPERATIONAL CPU TEST 79 | ;************************************************************ 80 | ; 81 | OKCPU: DB 0DH,0AH,' CPU IS OPERATIONAL$' 82 | ; 83 | NGCPU: DB 0DH,0AH,' CPU HAS FAILED! ERROR EXIT=$' 84 | ; 85 | ; 86 | ; 87 | ;************************************************************ 88 | ; 8080/8085 CPU TEST/DIAGNOSTIC 89 | ;************************************************************ 90 | ; 91 | ;NOTE: (1) PROGRAM ASSUMES "CALL",AND "LXI SP" INSTRUCTIONS WORK! 92 | ; 93 | ; (2) INSTRUCTIONS NOT TESTED ARE "HLT","DI","EI","RIM","SIM", 94 | ; AND "RST 0" THRU "RST 7" 95 | ; 96 | ; 97 | ; 98 | ;TEST JUMP INSTRUCTIONS AND FLAGS 99 | ; 100 | CPU: LXI SP,STACK ;SET THE STACK POINTER 101 | LXI H,WELCOM 102 | CALL MSG 103 | ANI 0 ;INITIALIZE A REG. AND CLEAR ALL FLAGS 104 | JZ J010 ;TEST "JZ" 105 | CALL CPUER 106 | J010: JNC J020 ;TEST "JNC" 107 | CALL CPUER 108 | J020: JPE J030 ;TEST "JPE" 109 | CALL CPUER 110 | J030: JP J040 ;TEST "JP" 111 | CALL CPUER 112 | J040: JNZ J050 ;TEST "JNZ" 113 | JC J050 ;TEST "JC" 114 | JPO J050 ;TEST "JPO" 115 | JM J050 ;TEST "JM" 116 | JMP J060 ;TEST "JMP" (IT'S A LITTLE LATE,BUT WHAT THE HELL! 117 | J050: CALL CPUER 118 | J060: ADI 6 ;A=6,C=0,P=1,S=0,Z=0 119 | JNZ J070 ;TEST "JNZ" 120 | CALL CPUER 121 | J070: JC J080 ;TEST "JC" 122 | JPO J080 ;TEST "JPO" 123 | JP J090 ;TEST "JP" 124 | J080: CALL CPUER 125 | J090: ADI 070H ;A=76H,C=0,P=0,S=0,Z=0 126 | JPO J100 ;TEST "JPO" 127 | CALL CPUER 128 | J100: JM J110 ;TEST "JM" 129 | JZ J110 ;TEST "JZ" 130 | JNC J120 ;TEST "JNC" 131 | J110: CALL CPUER 132 | J120: ADI 081H ;A=F7H,C=0,P=0,S=1,Z=0 133 | JM J130 ;TEST "JM" 134 | CALL CPUER 135 | J130: JZ J140 ;TEST "JZ" 136 | JC J140 ;TEST "JC" 137 | JPO J150 ;TEST "JPO" 138 | J140: CALL CPUER 139 | J150: ADI 0FEH ;A=F5H,C=1,P=1,S=1,Z=0 140 | JC J160 ;TEST "JC" 141 | CALL CPUER 142 | J160: JZ J170 ;TEST "JZ" 143 | JPO J170 ;TEST "JPO" 144 | JM AIMM ;TEST "JM" 145 | J170: CALL CPUER 146 | ; 147 | ; 148 | ; 149 | ;TEST ACCUMULATOR IMMEDIATE INSTRUCTIONS 150 | ; 151 | AIMM: CPI 0 ;A=F5H,C=0,Z=0 152 | JC CPIE ;TEST "CPI" FOR RE-SET CARRY 153 | JZ CPIE ;TEST "CPI" FOR RE-SET ZERO 154 | CPI 0F5H ;A=F5H,C=0,Z=1 155 | JC CPIE ;TEST "CPI" FOR RE-SET CARRY ("ADI") 156 | JNZ CPIE ;TEST "CPI" FOR RE-SET ZERO 157 | CPI 0FFH ;A=F5H,C=1,Z=0 158 | JZ CPIE ;TEST "CPI" FOR RE-SET ZERO 159 | JC ACII ;TEST "CPI" FOR SET CARRY 160 | CPIE: CALL CPUER 161 | ACII: ACI 00AH ;A=F5H+0AH+CARRY(1)=0,C=1 162 | ACI 00AH ;A=0+0AH+CARRY(0)=0BH,C=0 163 | CPI 00BH 164 | JZ SUII ;TEST "ACI" 165 | CALL CPUER 166 | SUII: SUI 00CH ;A=FFH,C=0 167 | SUI 00FH ;A=F0H,C=1 168 | CPI 0F0H 169 | JZ SBII ;TEST "SUI" 170 | CALL CPUER 171 | SBII: SBI 0F1H ;A=F0H-0F1H-CARRY(0)=FFH,C=1 172 | SBI 00EH ;A=FFH-OEH-CARRY(1)=F0H,C=0 173 | CPI 0F0H 174 | JZ ANII ;TEST "SBI" 175 | CALL CPUER 176 | ANII: ANI 055H ;A=F0H55H=50H,C=0,P=1,S=0,Z=0 177 | CPI 050H 178 | JZ ORII ;TEST "ANI" 179 | CALL CPUER 180 | ORII: ORI 03AH ;A=50H3AH=7AH,C=0,P=0,S=0,Z=0 181 | CPI 07AH 182 | JZ XRII ;TEST "ORI" 183 | CALL CPUER 184 | XRII: XRI 00FH ;A=7AH0FH=75H,C=0,P=0,S=0,Z=0 185 | CPI 075H 186 | JZ C010 ;TEST "XRI" 187 | CALL CPUER 188 | ; 189 | ; 190 | ; 191 | ;TEST CALLS AND RETURNS 192 | ; 193 | C010: ANI 000H ;A=0,C=0,P=1,S=0,Z=1 194 | CC CPUER ;TEST "CC" 195 | CPO CPUER ;TEST "CPO" 196 | CM CPUER ;TEST "CM" 197 | CNZ CPUER ;TEST "CNZ" 198 | CPI 000H 199 | JZ C020 ;A=0,C=0,P=0,S=0,Z=1 200 | CALL CPUER 201 | C020: SUI 077H ;A=89H,C=1,P=0,S=1,Z=0 202 | CNC CPUER ;TEST "CNC" 203 | CPE CPUER ;TEST "CPE" 204 | CP CPUER ;TEST "CP" 205 | CZ CPUER ;TEST "CZ" 206 | CPI 089H 207 | JZ C030 ;TEST FOR "CALLS" TAKING BRANCH 208 | CALL CPUER 209 | C030: ANI 0FFH ;SET FLAGS BACK! 210 | CPO CPOI ;TEST "CPO" 211 | CPI 0D9H 212 | JZ MOVI ;TEST "CALL" SEQUENCE SUCCESS 213 | CALL CPUER 214 | CPOI: RPE ;TEST "RPE" 215 | ADI 010H ;A=99H,C=0,P=0,S=1,Z=0 216 | CPE CPEI ;TEST "CPE" 217 | ADI 002H ;A=D9H,C=0,P=0,S=1,Z=0 218 | RPO ;TEST "RPO" 219 | CALL CPUER 220 | CPEI: RPO ;TEST "RPO" 221 | ADI 020H ;A=B9H,C=0,P=0,S=1,Z=0 222 | CM CMI ;TEST "CM" 223 | ADI 004H ;A=D7H,C=0,P=1,S=1,Z=0 224 | RPE ;TEST "RPE" 225 | CALL CPUER 226 | CMI: RP ;TEST "RP" 227 | ADI 080H ;A=39H,C=1,P=1,S=0,Z=0 228 | CP TCPI ;TEST "CP" 229 | ADI 080H ;A=D3H,C=0,P=0,S=1,Z=0 230 | RM ;TEST "RM" 231 | CALL CPUER 232 | TCPI: RM ;TEST "RM" 233 | ADI 040H ;A=79H,C=0,P=0,S=0,Z=0 234 | CNC CNCI ;TEST "CNC" 235 | ADI 040H ;A=53H,C=0,P=1,S=0,Z=0 236 | RP ;TEST "RP" 237 | CALL CPUER 238 | CNCI: RC ;TEST "RC" 239 | ADI 08FH ;A=08H,C=1,P=0,S=0,Z=0 240 | CC CCI ;TEST "CC" 241 | SUI 002H ;A=13H,C=0,P=0,S=0,Z=0 242 | RNC ;TEST "RNC" 243 | CALL CPUER 244 | CCI: RNC ;TEST "RNC" 245 | ADI 0F7H ;A=FFH,C=0,P=1,S=1,Z=0 246 | CNZ CNZI ;TEST "CNZ" 247 | ADI 0FEH ;A=15H,C=1,P=0,S=0,Z=0 248 | RC ;TEST "RC" 249 | CALL CPUER 250 | CNZI: RZ ;TEST "RZ" 251 | ADI 001H ;A=00H,C=1,P=1,S=0,Z=1 252 | CZ CZI ;TEST "CZ" 253 | ADI 0D0H ;A=17H,C=1,P=1,S=0,Z=0 254 | RNZ ;TEST "RNZ" 255 | CALL CPUER 256 | CZI: RNZ ;TEST "RNZ" 257 | ADI 047H ;A=47H,C=0,P=1,S=0,Z=0 258 | CPI 047H ;A=47H,C=0,P=1,S=0,Z=1 259 | RZ ;TEST "RZ" 260 | CALL CPUER 261 | ; 262 | ; 263 | ; 264 | ;TEST "MOV","INR",AND "DCR" INSTRUCTIONS 265 | ; 266 | MOVI: MVI A,077H 267 | INR A 268 | MOV B,A 269 | INR B 270 | MOV C,B 271 | DCR C 272 | MOV D,C 273 | MOV E,D 274 | MOV H,E 275 | MOV L,H 276 | MOV A,L ;TEST "MOV" A,L,H,E,D,C,B,A 277 | DCR A 278 | MOV C,A 279 | MOV E,C 280 | MOV L,E 281 | MOV B,L 282 | MOV D,B 283 | MOV H,D 284 | MOV A,H ;TEST "MOV" A,H,D,B,L,E,C,A 285 | MOV D,A 286 | INR D 287 | MOV L,D 288 | MOV C,L 289 | INR C 290 | MOV H,C 291 | MOV B,H 292 | DCR B 293 | MOV E,B 294 | MOV A,E ;TEST "MOV" A,E,B,H,C,L,D,A 295 | MOV E,A 296 | INR E 297 | MOV B,E 298 | MOV H,B 299 | INR H 300 | MOV C,H 301 | MOV L,C 302 | MOV D,L 303 | DCR D 304 | MOV A,D ;TEST "MOV" A,D,L,C,H,B,E,A 305 | MOV H,A 306 | DCR H 307 | MOV D,H 308 | MOV B,D 309 | MOV L,B 310 | INR L 311 | MOV E,L 312 | DCR E 313 | MOV C,E 314 | MOV A,C ;TEST "MOV" A,C,E,L,B,D,H,A 315 | MOV L,A 316 | DCR L 317 | MOV H,L 318 | MOV E,H 319 | MOV D,E 320 | MOV C,D 321 | MOV B,C 322 | MOV A,B 323 | CPI 077H 324 | CNZ CPUER ;TEST "MOV" A,B,C,D,E,H,L,A 325 | ; 326 | ; 327 | ; 328 | ;TEST ARITHMETIC AND LOGIC INSTRUCTIONS 329 | ; 330 | XRA A 331 | MVI B,001H 332 | MVI C,003H 333 | MVI D,007H 334 | MVI E,00FH 335 | MVI H,01FH 336 | MVI L,03FH 337 | ADD B 338 | ADD C 339 | ADD D 340 | ADD E 341 | ADD H 342 | ADD L 343 | ADD A 344 | CPI 0F0H 345 | CNZ CPUER ;TEST "ADD" B,C,D,E,H,L,A 346 | SUB B 347 | SUB C 348 | SUB D 349 | SUB E 350 | SUB H 351 | SUB L 352 | CPI 078H 353 | CNZ CPUER ;TEST "SUB" B,C,D,E,H,L 354 | SUB A 355 | CNZ CPUER ;TEST "SUB" A 356 | MVI A,080H 357 | ADD A 358 | MVI B,001H 359 | MVI C,002H 360 | MVI D,003H 361 | MVI E,004H 362 | MVI H,005H 363 | MVI L,006H 364 | ADC B 365 | MVI B,080H 366 | ADD B 367 | ADD B 368 | ADC C 369 | ADD B 370 | ADD B 371 | ADC D 372 | ADD B 373 | ADD B 374 | ADC E 375 | ADD B 376 | ADD B 377 | ADC H 378 | ADD B 379 | ADD B 380 | ADC L 381 | ADD B 382 | ADD B 383 | ADC A 384 | CPI 037H 385 | CNZ CPUER ;TEST "ADC" B,C,D,E,H,L,A 386 | MVI A,080H 387 | ADD A 388 | MVI B,001H 389 | SBB B 390 | MVI B,0FFH 391 | ADD B 392 | SBB C 393 | ADD B 394 | SBB D 395 | ADD B 396 | SBB E 397 | ADD B 398 | SBB H 399 | ADD B 400 | SBB L 401 | CPI 0E0H 402 | CNZ CPUER ;TEST "SBB" B,C,D,E,H,L 403 | MVI A,080H 404 | ADD A 405 | SBB A 406 | CPI 0FFH 407 | CNZ CPUER ;TEST "SBB" A 408 | MVI A,0FFH 409 | MVI B,0FEH 410 | MVI C,0FCH 411 | MVI D,0EFH 412 | MVI E,07FH 413 | MVI H,0F4H 414 | MVI L,0BFH 415 | ANA B ;changed from ANA A (mwd) 416 | ANA C 417 | ANA D 418 | ANA E 419 | ANA H 420 | ANA L 421 | ANA A 422 | CPI 024H 423 | CNZ CPUER ;TEST "ANA" B,C,D,E,H,L,A 424 | XRA A 425 | MVI B,001H 426 | MVI C,002H 427 | MVI D,004H 428 | MVI E,008H 429 | MVI H,010H 430 | MVI L,020H 431 | ORA B 432 | ORA C 433 | ORA D 434 | ORA E 435 | ORA H 436 | ORA L 437 | ORA A 438 | CPI 03FH 439 | CNZ CPUER ;TEST "ORA" B,C,D,E,H,L,A 440 | MVI A,000H 441 | MVI H,08FH 442 | MVI L,04FH 443 | XRA B 444 | XRA C 445 | XRA D 446 | XRA E 447 | XRA H 448 | XRA L 449 | CPI 0CFH 450 | CNZ CPUER ;TEST "XRA" B,C,D,E,H,L 451 | XRA A 452 | CNZ CPUER ;TEST "XRA" A 453 | MVI B,044H 454 | MVI C,045H 455 | MVI D,046H 456 | MVI E,047H 457 | MVI H,(TEMP0 / 0FFH) ;HIGH BYTE OF TEST MEMORY LOCATION 458 | MVI L,(TEMP0 AND 0FFH) ;LOW BYTE OF TEST MEMORY LOCATION 459 | MOV M,B 460 | MVI B,000H 461 | MOV B,M 462 | MVI A,044H 463 | CMP B 464 | CNZ CPUER ;TEST "MOV" M,B AND B,M 465 | MOV M,C ;added (mwd) 466 | MVI C,000H ;added (mwd) 467 | MOV C,M ;added (mwd) 468 | MVI A,045H ;added (mwd) 469 | CMP C ;added (mwd) 470 | CNZ CPUER ;TEST "MOV" M,C AND C,M added (mwd) 471 | MOV M,D 472 | MVI D,000H 473 | MOV D,M 474 | MVI A,046H 475 | CMP D 476 | CNZ CPUER ;TEST "MOV" M,D AND D,M 477 | MOV M,E 478 | MVI E,000H 479 | MOV E,M 480 | MVI A,047H 481 | CMP E 482 | CNZ CPUER ;TEST "MOV" M,E AND E,M 483 | MOV M,H 484 | MVI H,(TEMP0 / 0FFH) 485 | MVI L,(TEMP0 AND 0FFH) 486 | MOV H,M 487 | MVI A,(TEMP0 / 0FFH) 488 | CMP H 489 | CNZ CPUER ;TEST "MOV" M,H AND H,M 490 | MOV M,L 491 | MVI H,(TEMP0 / 0FFH) 492 | MVI L,(TEMP0 AND 0FFH) 493 | MOV L,M 494 | MVI A,(TEMP0 AND 0FFH) 495 | CMP L 496 | CNZ CPUER ;TEST "MOV" M,L AND L,M 497 | MVI H,(TEMP0 / 0FFH) 498 | MVI L,(TEMP0 AND 0FFH) 499 | MVI A,032H 500 | MOV M,A 501 | CMP M 502 | CNZ CPUER ;TEST "MOV" M,A 503 | ADD M 504 | CPI 064H 505 | CNZ CPUER ;TEST "ADD" M 506 | XRA A 507 | MOV A,M 508 | CPI 032H 509 | CNZ CPUER ;TEST "MOV" A,M 510 | MVI H,(TEMP0 / 0FFH) 511 | MVI L,(TEMP0 AND 0FFH) 512 | MOV A,M 513 | SUB M 514 | CNZ CPUER ;TEST "SUB" M 515 | MVI A,080H 516 | ADD A 517 | ADC M 518 | CPI 033H 519 | CNZ CPUER ;TEST "ADC" M 520 | MVI A,080H 521 | ADD A 522 | SBB M 523 | CPI 0CDH 524 | CNZ CPUER ;TEST "SBB" M 525 | ANA M 526 | CNZ CPUER ;TEST "ANA" M 527 | MVI A,025H 528 | ORA M 529 | CPI 037H 530 | CNZ CPUER ;TEST "ORA" M 531 | XRA M 532 | CPI 005H 533 | CNZ CPUER ;TEST "XRA" M 534 | MVI M,055H 535 | INR M 536 | DCR M 537 | ADD M 538 | CPI 05AH 539 | CNZ CPUER ;TEST "INR","DCR",AND "MVI" M 540 | LXI B,12FFH 541 | LXI D,12FFH 542 | LXI H,12FFH 543 | INX B 544 | INX D 545 | INX H 546 | MVI A,013H 547 | CMP B 548 | CNZ CPUER ;TEST "LXI" AND "INX" B 549 | CMP D 550 | CNZ CPUER ;TEST "LXI" AND "INX" D 551 | CMP H 552 | CNZ CPUER ;TEST "LXI" AND "INX" H 553 | MVI A,000H 554 | CMP C 555 | CNZ CPUER ;TEST "LXI" AND "INX" B 556 | CMP E 557 | CNZ CPUER ;TEST "LXI" AND "INX" D 558 | CMP L 559 | CNZ CPUER ;TEST "LXI" AND "INX" H 560 | DCX B 561 | DCX D 562 | DCX H 563 | MVI A,012H 564 | CMP B 565 | CNZ CPUER ;TEST "DCX" B 566 | CMP D 567 | CNZ CPUER ;TEST "DCX" D 568 | CMP H 569 | CNZ CPUER ;TEST "DCX" H 570 | MVI A,0FFH 571 | CMP C 572 | CNZ CPUER ;TEST "DCX" B 573 | CMP E 574 | CNZ CPUER ;TEST "DCX" D 575 | CMP L 576 | CNZ CPUER ;TEST "DCX" H 577 | STA TEMP0 578 | XRA A 579 | LDA TEMP0 580 | CPI 0FFH 581 | CNZ CPUER ;TEST "LDA" AND "STA" 582 | LHLD TEMPP 583 | SHLD TEMP0 584 | LDA TEMPP 585 | MOV B,A 586 | LDA TEMP0 587 | CMP B 588 | CNZ CPUER ;TEST "LHLD" AND "SHLD" 589 | LDA TEMPP+1 590 | MOV B,A 591 | LDA TEMP0+1 592 | CMP B 593 | CNZ CPUER ;TEST "LHLD" AND "SHLD" 594 | MVI A,0AAH 595 | STA TEMP0 596 | MOV B,H 597 | MOV C,L 598 | XRA A 599 | LDAX B 600 | CPI 0AAH 601 | CNZ CPUER ;TEST "LDAX" B 602 | INR A 603 | STAX B 604 | LDA TEMP0 605 | CPI 0ABH 606 | CNZ CPUER ;TEST "STAX" B 607 | MVI A,077H 608 | STA TEMP0 609 | LHLD TEMPP 610 | LXI D,00000H 611 | XCHG 612 | XRA A 613 | LDAX D 614 | CPI 077H 615 | CNZ CPUER ;TEST "LDAX" D AND "XCHG" 616 | XRA A 617 | ADD H 618 | ADD L 619 | CNZ CPUER ;TEST "XCHG" 620 | MVI A,0CCH 621 | STAX D 622 | LDA TEMP0 623 | CPI 0CCH 624 | STAX D 625 | LDA TEMP0 626 | CPI 0CCH 627 | CNZ CPUER ;TEST "STAX" D 628 | LXI H,07777H 629 | DAD H 630 | MVI A,0EEH 631 | CMP H 632 | CNZ CPUER ;TEST "DAD" H 633 | CMP L 634 | CNZ CPUER ;TEST "DAD" H 635 | LXI H,05555H 636 | LXI B,0FFFFH 637 | DAD B 638 | MVI A,055H 639 | CNC CPUER ;TEST "DAD" B 640 | CMP H 641 | CNZ CPUER ;TEST "DAD" B 642 | MVI A,054H 643 | CMP L 644 | CNZ CPUER ;TEST "DAD" B 645 | LXI H,0AAAAH 646 | LXI D,03333H 647 | DAD D 648 | MVI A,0DDH 649 | CMP H 650 | CNZ CPUER ;TEST "DAD" D 651 | CMP L 652 | CNZ CPUER ;TEST "DAD" B 653 | STC 654 | CNC CPUER ;TEST "STC" 655 | CMC 656 | CC CPUER ;TEST "CMC 657 | MVI A,0AAH 658 | CMA 659 | CPI 055H 660 | CNZ CPUER ;TEST "CMA" 661 | ORA A ;RE-SET AUXILIARY CARRY 662 | DAA 663 | CPI 055H 664 | CNZ CPUER ;TEST "DAA" 665 | MVI A,088H 666 | ADD A 667 | DAA 668 | CPI 076H 669 | CNZ CPUER ;TEST "DAA" 670 | XRA A 671 | MVI A,0AAH 672 | DAA 673 | CNC CPUER ;TEST "DAA" 674 | CPI 010H 675 | CNZ CPUER ;TEST "DAA" 676 | XRA A 677 | MVI A,09AH 678 | DAA 679 | CNC CPUER ;TEST "DAA" 680 | CNZ CPUER ;TEST "DAA" 681 | STC 682 | MVI A,042H 683 | RLC 684 | CC CPUER ;TEST "RLC" FOR RE-SET CARRY 685 | RLC 686 | CNC CPUER ;TEST "RLC" FOR SET CARRY 687 | CPI 009H 688 | CNZ CPUER ;TEST "RLC" FOR ROTATION 689 | RRC 690 | CNC CPUER ;TEST "RRC" FOR SET CARRY 691 | RRC 692 | CPI 042H 693 | CNZ CPUER ;TEST "RRC" FOR ROTATION 694 | RAL 695 | RAL 696 | CNC CPUER ;TEST "RAL" FOR SET CARRY 697 | CPI 008H 698 | CNZ CPUER ;TEST "RAL" FOR ROTATION 699 | RAR 700 | RAR 701 | CC CPUER ;TEST "RAR" FOR RE-SET CARRY 702 | CPI 002H 703 | CNZ CPUER ;TEST "RAR" FOR ROTATION 704 | LXI B,01234H 705 | LXI D,0AAAAH 706 | LXI H,05555H 707 | XRA A 708 | PUSH B 709 | PUSH D 710 | PUSH H 711 | PUSH PSW 712 | LXI B,00000H 713 | LXI D,00000H 714 | LXI H,00000H 715 | MVI A,0C0H 716 | ADI 0F0H 717 | POP PSW 718 | POP H 719 | POP D 720 | POP B 721 | CC CPUER ;TEST "PUSH PSW" AND "POP PSW" 722 | CNZ CPUER ;TEST "PUSH PSW" AND "POP PSW" 723 | CPO CPUER ;TEST "PUSH PSW" AND "POP PSW" 724 | CM CPUER ;TEST "PUSH PSW" AND "POP PSW" 725 | MVI A,012H 726 | CMP B 727 | CNZ CPUER ;TEST "PUSH B" AND "POP B" 728 | MVI A,034H 729 | CMP C 730 | CNZ CPUER ;TEST "PUSH B" AND "POP B" 731 | MVI A,0AAH 732 | CMP D 733 | CNZ CPUER ;TEST "PUSH D" AND "POP D" 734 | CMP E 735 | CNZ CPUER ;TEST "PUSH D" AND "POP D" 736 | MVI A,055H 737 | CMP H 738 | CNZ CPUER ;TEST "PUSH H" AND "POP H" 739 | CMP L 740 | CNZ CPUER ;TEST "PUSH H" AND "POP H" 741 | LXI H,00000H 742 | DAD SP 743 | SHLD SAVSTK ;SAVE THE "OLD" STACK-POINTER! 744 | LXI SP,TEMP4 745 | DCX SP 746 | DCX SP 747 | INX SP 748 | DCX SP 749 | MVI A,055H 750 | STA TEMP2 751 | CMA 752 | STA TEMP3 753 | POP B 754 | CMP B 755 | CNZ CPUER ;TEST "LXI","DAD","INX",AND "DCX" SP 756 | CMA 757 | CMP C 758 | CNZ CPUER ;TEST "LXI","DAD","INX", AND "DCX" SP 759 | LXI H,TEMP4 760 | SPHL 761 | LXI H,07733H 762 | DCX SP 763 | DCX SP 764 | XTHL 765 | LDA TEMP3 766 | CPI 077H 767 | CNZ CPUER ;TEST "SPHL" AND "XTHL" 768 | LDA TEMP2 769 | CPI 033H 770 | CNZ CPUER ;TEST "SPHL" AND "XTHL" 771 | MVI A,055H 772 | CMP L 773 | CNZ CPUER ;TEST "SPHL" AND "XTHL" 774 | CMA 775 | CMP H 776 | CNZ CPUER ;TEST "SPHL" AND "XTHL" 777 | LHLD SAVSTK ;RESTORE THE "OLD" STACK-POINTER 778 | SPHL 779 | LXI H,CPUOK 780 | PCHL ;TEST "PCHL" 781 | ; 782 | ; 783 | ; 784 | CPUER: LXI H,NGCPU ;OUTPUT "CPU HAS FAILED ERROR EXIT=" TO CONSOLE 785 | CALL MSG 786 | POP H ;HL = ADDRESS FOLLOWING CALL CPUER 787 | PUSH H 788 | MOV A,H 789 | CALL BYTEO ;SHOW ERROR EXIT ADDRESS HIGH BYTE 790 | POP H 791 | MOV A,L 792 | CALL BYTEO ;SHOW ERROR EXIT ADDRESS LOW BYTE 793 | JMP WBOOT ;EXIT TO CP/M WARM BOOT 794 | ; 795 | ; 796 | ; 797 | CPUOK: LXI H,OKCPU ;OUTPUT "CPU IS OPERATIONAL" TO CONSOLE 798 | CALL MSG 799 | JMP WBOOT ;EXIT TO CP/M WARM BOOT 800 | ; 801 | ; 802 | ; 803 | TEMPP: DW TEMP0 ;POINTER USED TO TEST "LHLD","SHLD", 804 | ; AND "LDAX" INSTRUCTIONS 805 | ; 806 | TEMP0: DS 1 ;TEMPORARY STORAGE FOR CPU TEST MEMORY LOCATIONS 807 | TEMP1: DS 1 ;TEMPORARY STORAGE FOR CPU TEST MEMORY LOCATIONS 808 | TEMP2 DS 1 ;TEMPORARY STORAGE FOR CPU TEST MEMORY LOCATIONS 809 | TEMP3: DS 1 ;TEMPORARY STORAGE FOR CPU TEST MEMORY LOCATIONS 810 | TEMP4: DS 1 ;TEMPORARY STORAGE FOR CPU TEST MEMORY LOCATIONS 811 | SAVSTK: DS 2 ;TEMPORARY STACK-POINTER STORAGE LOCATION 812 | ; 813 | ; 814 | ; 815 | STACK EQU TEMPP+256 ;DE-BUG STACK POINTER STORAGE AREA 816 | ; 817 | ; 818 | ; 819 | END 820 | -------------------------------------------------------------------------------- /cpu_tests/8080PRE.PRN: -------------------------------------------------------------------------------- 1 | 'Preliminary Z80 tests' MACRO-80 3.44 09-Dec-81 PAGE 1 2 | 3 | 4 | title 'Preliminary Z80 tests' 5 | 6 | ; prelim.z80 - Preliminary Z80 tests 7 | ; Copyright (C) 1994 Frank D. Cringle 8 | ; 9 | ; This program is free software; you can redistribute it and/or 10 | ; modify it under the terms of the GNU General Public License 11 | ; as published by the Free Software Foundation; either version 2 12 | ; of the License, or (at your option) any later version. 13 | ; 14 | ; This program is distributed in the hope that it will be useful, 15 | ; but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | ; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | ; GNU General Public License for more details. 18 | ; 19 | ; You should have received a copy of the GNU General Public License 20 | ; along with this program; if not, write to the Free Software 21 | ; Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 22 | 23 | 24 | ; These tests have two goals. To start with, we assume the worst and 25 | ; successively test the instructions needed to continue testing. 26 | ; Then we try to test all instructions which cannot be handled by 27 | ; zexlax - the crc-based instruction exerciser. 28 | 29 | ; Initially errors are 'reported' by jumping to 0. This should reboot 30 | ; cp/m, so if the program terminates without any output one of the 31 | ; early tests failed. Later errors are reported by outputting an 32 | ; address via the bdos conout routine. The address can be located in 33 | ; a listing of this program. 34 | 35 | ; If the program runs to completion it displays a suitable message. 36 | 37 | ;****************************************************************************** 38 | ; 39 | ; Modified by Ian Bartholomew to run a preliminary test on an 8080 CPU 40 | ; 41 | ; Assemble using M80 42 | ; 43 | ;****************************************************************************** 44 | 45 | .8080 46 | 0000' aseg 47 | org 100h 48 | 49 | 0100 3E 01 start: mvi a,1 ; test simple compares and z/nz jumps 50 | 0102 FE 02 cpi 2 51 | 0104 CA 0000 jz 0 52 | 0107 FE 01 cpi 1 53 | 0109 C2 0000 jnz 0 54 | 010C C3 0111 jmp lab0 55 | 010F 76 hlt ; emergency exit 56 | 0110 FF db 0ffh 57 | 58 | 0111 CD 0117 lab0: call lab2 ; does a simple call work? 59 | 0114 C3 0000 lab1: jmp 0 ; fail 60 | 'Preliminary Z80 tests' MACRO-80 3.44 09-Dec-81 PAGE 1-1 61 | 62 | 63 | 64 | 0117 E1 lab2: pop h ; check return address 65 | 0118 7C mov a,h 66 | 0119 FE 01 cpi high lab1 67 | 011B CA 0121 jz lab3 68 | 011E C3 0000 jmp 0 69 | 0121 7D lab3: mov a,l 70 | 0122 FE 14 cpi low lab1 71 | 0124 CA 012A jz lab4 72 | 0127 C3 0000 jmp 0 73 | 74 | ; test presence and uniqueness of all machine registers 75 | ; (except ir) 76 | 012A 31 0399 lab4: lxi sp,regs1 77 | 012D F1 pop psw 78 | 012E C1 pop b 79 | 012F D1 pop d 80 | 0130 E1 pop h 81 | 0131 31 03A9 lxi sp,regs2+8 82 | 0134 E5 push h 83 | 0135 D5 push d 84 | 0136 C5 push b 85 | 0137 F5 push psw 86 | 87 | 0000 v defl 0 88 | rept 8 89 | lda regs2+v/2 90 | v defl v+2 91 | cpi v 92 | jnz 0 93 | endm 94 | 0138 3A 03A1 + lda regs2+v/2 95 | 013B FE 02 + cpi v 96 | 013D C2 0000 + jnz 0 97 | 0140 3A 03A2 + lda regs2+v/2 98 | 0143 FE 04 + cpi v 99 | 0145 C2 0000 + jnz 0 100 | 0148 3A 03A3 + lda regs2+v/2 101 | 014B FE 06 + cpi v 102 | 014D C2 0000 + jnz 0 103 | 0150 3A 03A4 + lda regs2+v/2 104 | 0153 FE 08 + cpi v 105 | 0155 C2 0000 + jnz 0 106 | 0158 3A 03A5 + lda regs2+v/2 107 | 015B FE 0A + cpi v 108 | 015D C2 0000 + jnz 0 109 | 0160 3A 03A6 + lda regs2+v/2 110 | 0163 FE 0C + cpi v 111 | 0165 C2 0000 + jnz 0 112 | 0168 3A 03A7 + lda regs2+v/2 113 | 016B FE 0E + cpi v 114 | 016D C2 0000 + jnz 0 115 | 0170 3A 03A8 + lda regs2+v/2 116 | 0173 FE 10 + cpi v 117 | 0175 C2 0000 + jnz 0 118 | 119 | 'Preliminary Z80 tests' MACRO-80 3.44 09-Dec-81 PAGE 1-2 120 | 121 | 122 | ; test access to memory via (hl) 123 | 0178 21 03A9 lxi h,hlval 124 | 017B 7E mov a,m 125 | 017C FE A5 cpi 0a5h 126 | 017E C2 0000 jnz 0 127 | 0181 21 03AA lxi h,hlval+1 128 | 0184 7E mov a,m 129 | 0185 FE 3C cpi 03ch 130 | 0187 C2 0000 jnz 0 131 | 132 | ; test unconditional return 133 | 018A 31 0500 lxi sp,stack 134 | 018D 21 0195 lxi h,reta 135 | 0190 E5 push h 136 | 0191 C9 ret 137 | 0192 C3 0000 jmp 0 138 | 139 | ; test instructions needed for hex output 140 | 0195 3E FF reta: mvi a,0ffh 141 | 0197 E6 0F ani 0fh 142 | 0199 FE 0F cpi 0fh 143 | 019B C2 0000 jnz 0 144 | 019E 3E 5A mvi a,05ah 145 | 01A0 E6 0F ani 0fh 146 | 01A2 FE 0A cpi 0ah 147 | 01A4 C2 0000 jnz 0 148 | 01A7 0F rrc 149 | 01A8 FE 05 cpi 05h 150 | 01AA C2 0000 jnz 0 151 | 01AD 0F rrc 152 | 01AE FE 82 cpi 82h 153 | 01B0 C2 0000 jnz 0 154 | 01B3 0F rrc 155 | 01B4 FE 41 cpi 41h 156 | 01B6 C2 0000 jnz 0 157 | 01B9 0F rrc 158 | 01BA FE A0 cpi 0a0h 159 | 01BC C2 0000 jnz 0 160 | 01BF 21 1234 lxi h,01234h 161 | 01C2 E5 push h 162 | 01C3 C1 pop b 163 | 01C4 78 mov a,b 164 | 01C5 FE 12 cpi 12h 165 | 01C7 C2 0000 jnz 0 166 | 01CA 79 mov a,c 167 | 01CB FE 34 cpi 34h 168 | 01CD C2 0000 jnz 0 169 | 170 | ; from now on we can report errors by displaying an address 171 | 172 | ; test conditional call, ret, jp, jr 173 | tcond macro flag,pcond,ncond,rel 174 | lxi h,&flag 175 | push h 176 | pop psw 177 | c&pcond lab1&pcond 178 | 'Preliminary Z80 tests' MACRO-80 3.44 09-Dec-81 PAGE 1-3 179 | 180 | 181 | jmp error 182 | lab1&pcond: pop h 183 | lxi h,0d7h xor &flag 184 | push h 185 | pop psw 186 | c&ncond lab2&pcond 187 | jmp error 188 | lab2&pcond: pop h 189 | lxi h,lab3&pcond 190 | push h 191 | lxi h,&flag 192 | push h 193 | pop psw 194 | r&pcond 195 | call error 196 | lab3&pcond: lxi h,lab4&pcond 197 | push h 198 | lxi h,0d7h xor &flag 199 | push h 200 | pop psw 201 | r&ncond 202 | call error 203 | lab4&pcond: lxi h,&flag 204 | push h 205 | pop psw 206 | j&pcond lab5&pcond 207 | call error 208 | lab5&pcond: lxi h,0d7h xor &flag 209 | push h 210 | pop psw 211 | j&ncond lab6&pcond 212 | call error 213 | lab6&pcond: 214 | endm 215 | 216 | tcond 1,c,nc,1 217 | 01D0 21 0001 + lxi h,&1 218 | 01D3 E5 + push h 219 | 01D4 F1 + pop psw 220 | 01D5 DC 01DB + c&c lab1&c 221 | 01D8 C3 0352 + jmp error 222 | 01DB E1 + lab1&c: pop h 223 | 01DC 21 00D6 + lxi h,0d7h xor &1 224 | 01DF E5 + push h 225 | 01E0 F1 + pop psw 226 | 01E1 D4 01E7 + c&nc lab2&c 227 | 01E4 C3 0352 + jmp error 228 | 01E7 E1 + lab2&c: pop h 229 | 01E8 21 01F5 + lxi h,lab3&c 230 | 01EB E5 + push h 231 | 01EC 21 0001 + lxi h,&1 232 | 01EF E5 + push h 233 | 01F0 F1 + pop psw 234 | 01F1 D8 + r&c 235 | 01F2 CD 0352 + call error 236 | 01F5 21 0202 + lab3&c: lxi h,lab4&c 237 | 'Preliminary Z80 tests' MACRO-80 3.44 09-Dec-81 PAGE 1-4 238 | 239 | 240 | 01F8 E5 + push h 241 | 01F9 21 00D6 + lxi h,0d7h xor &1 242 | 01FC E5 + push h 243 | 01FD F1 + pop psw 244 | 01FE D0 + r&nc 245 | 01FF CD 0352 + call error 246 | 0202 21 0001 + lab4&c: lxi h,&1 247 | 0205 E5 + push h 248 | 0206 F1 + pop psw 249 | 0207 DA 020D + j&c lab5&c 250 | 020A CD 0352 + call error 251 | 020D 21 00D6 + lab5&c: lxi h,0d7h xor &1 252 | 0210 E5 + push h 253 | 0211 F1 + pop psw 254 | 0212 D2 0218 + j&nc lab6&c 255 | 0215 CD 0352 + call error 256 | 0218 + lab6&c: 257 | tcond 4,pe,po,0 258 | 0218 21 0004 + lxi h,&4 259 | 021B E5 + push h 260 | 021C F1 + pop psw 261 | 021D EC 0223 + c&pe lab1&pe 262 | 0220 C3 0352 + jmp error 263 | 0223 E1 + lab1&pe: pop h 264 | 0224 21 00D3 + lxi h,0d7h xor &4 265 | 0227 E5 + push h 266 | 0228 F1 + pop psw 267 | 0229 E4 022F + c&po lab2&pe 268 | 022C C3 0352 + jmp error 269 | 022F E1 + lab2&pe: pop h 270 | 0230 21 023D + lxi h,lab3&pe 271 | 0233 E5 + push h 272 | 0234 21 0004 + lxi h,&4 273 | 0237 E5 + push h 274 | 0238 F1 + pop psw 275 | 0239 E8 + r&pe 276 | 023A CD 0352 + call error 277 | 023D 21 024A + lab3&pe: lxi h,lab4&pe 278 | 0240 E5 + push h 279 | 0241 21 00D3 + lxi h,0d7h xor &4 280 | 0244 E5 + push h 281 | 0245 F1 + pop psw 282 | 0246 E0 + r&po 283 | 0247 CD 0352 + call error 284 | 024A 21 0004 + lab4&pe: lxi h,&4 285 | 024D E5 + push h 286 | 024E F1 + pop psw 287 | 024F EA 0255 + j&pe lab5&pe 288 | 0252 CD 0352 + call error 289 | 0255 21 00D3 + lab5&pe: lxi h,0d7h xor &4 290 | 0258 E5 + push h 291 | 0259 F1 + pop psw 292 | 025A E2 0260 + j&po lab6&pe 293 | 025D CD 0352 + call error 294 | 0260 + lab6&pe: 295 | tcond 040h,z,nz,1 296 | 'Preliminary Z80 tests' MACRO-80 3.44 09-Dec-81 PAGE 1-5 297 | 298 | 299 | 0260 21 0040 + lxi h,&040h 300 | 0263 E5 + push h 301 | 0264 F1 + pop psw 302 | 0265 CC 026B + c&z lab1&z 303 | 0268 C3 0352 + jmp error 304 | 026B E1 + lab1&z: pop h 305 | 026C 21 0097 + lxi h,0d7h xor &040h 306 | 026F E5 + push h 307 | 0270 F1 + pop psw 308 | 0271 C4 0277 + c&nz lab2&z 309 | 0274 C3 0352 + jmp error 310 | 0277 E1 + lab2&z: pop h 311 | 0278 21 0285 + lxi h,lab3&z 312 | 027B E5 + push h 313 | 027C 21 0040 + lxi h,&040h 314 | 027F E5 + push h 315 | 0280 F1 + pop psw 316 | 0281 C8 + r&z 317 | 0282 CD 0352 + call error 318 | 0285 21 0292 + lab3&z: lxi h,lab4&z 319 | 0288 E5 + push h 320 | 0289 21 0097 + lxi h,0d7h xor &040h 321 | 028C E5 + push h 322 | 028D F1 + pop psw 323 | 028E C0 + r&nz 324 | 028F CD 0352 + call error 325 | 0292 21 0040 + lab4&z: lxi h,&040h 326 | 0295 E5 + push h 327 | 0296 F1 + pop psw 328 | 0297 CA 029D + j&z lab5&z 329 | 029A CD 0352 + call error 330 | 029D 21 0097 + lab5&z: lxi h,0d7h xor &040h 331 | 02A0 E5 + push h 332 | 02A1 F1 + pop psw 333 | 02A2 C2 02A8 + j&nz lab6&z 334 | 02A5 CD 0352 + call error 335 | 02A8 + lab6&z: 336 | tcond 080h,m,p,0 337 | 02A8 21 0080 + lxi h,&080h 338 | 02AB E5 + push h 339 | 02AC F1 + pop psw 340 | 02AD FC 02B3 + c&m lab1&m 341 | 02B0 C3 0352 + jmp error 342 | 02B3 E1 + lab1&m: pop h 343 | 02B4 21 0057 + lxi h,0d7h xor &080h 344 | 02B7 E5 + push h 345 | 02B8 F1 + pop psw 346 | 02B9 F4 02BF + c&p lab2&m 347 | 02BC C3 0352 + jmp error 348 | 02BF E1 + lab2&m: pop h 349 | 02C0 21 02CD + lxi h,lab3&m 350 | 02C3 E5 + push h 351 | 02C4 21 0080 + lxi h,&080h 352 | 02C7 E5 + push h 353 | 02C8 F1 + pop psw 354 | 02C9 F8 + r&m 355 | 'Preliminary Z80 tests' MACRO-80 3.44 09-Dec-81 PAGE 1-6 356 | 357 | 358 | 02CA CD 0352 + call error 359 | 02CD 21 02DA + lab3&m: lxi h,lab4&m 360 | 02D0 E5 + push h 361 | 02D1 21 0057 + lxi h,0d7h xor &080h 362 | 02D4 E5 + push h 363 | 02D5 F1 + pop psw 364 | 02D6 F0 + r&p 365 | 02D7 CD 0352 + call error 366 | 02DA 21 0080 + lab4&m: lxi h,&080h 367 | 02DD E5 + push h 368 | 02DE F1 + pop psw 369 | 02DF FA 02E5 + j&m lab5&m 370 | 02E2 CD 0352 + call error 371 | 02E5 21 0057 + lab5&m: lxi h,0d7h xor &080h 372 | 02E8 E5 + push h 373 | 02E9 F1 + pop psw 374 | 02EA F2 02F0 + j&p lab6&m 375 | 02ED CD 0352 + call error 376 | 02F0 + lab6&m: 377 | 378 | ; test indirect jumps 379 | 02F0 21 02F7 lxi h,lab7 380 | 02F3 E9 pchl 381 | 02F4 CD 0352 call error 382 | 383 | ; djnz (and (partially) inc a, inc hl) 384 | 02F7 3E A5 lab7: mvi a,0a5h 385 | 02F9 06 04 mvi b,4 386 | 02FB 0F lab8: rrc 387 | 02FC 05 dcr b 388 | 02FD C2 02FB jnz lab8 389 | 0300 FE 5A cpi 05ah 390 | 0302 C4 0352 cnz error 391 | 0305 06 10 mvi b,16 392 | 0307 3C lab9: inr a 393 | 0308 05 dcr b 394 | 0309 C2 0307 jnz lab9 395 | 030C FE 6A cpi 06ah 396 | 030E C4 0352 cnz error 397 | 0311 06 00 mvi b,0 398 | 0313 21 0000 lxi h,0 399 | 0316 23 lab10: inx h 400 | 0317 05 dcr b 401 | 0318 C2 0316 jnz lab10 402 | 031B 7C mov a,h 403 | 031C FE 01 cpi 1 404 | 031E C4 0352 cnz error 405 | 0321 7D mov a,l 406 | 0322 FE 00 cpi 0 407 | 0324 C4 0352 cnz error 408 | 409 | 0327 11 0332 allok: lxi d,okmsg 410 | 032A 0E 09 mvi c,9 411 | 032C CD 0005 call 5 412 | 032F C3 0000 jmp 0 413 | 414 | 'Preliminary Z80 tests' MACRO-80 3.44 09-Dec-81 PAGE 1-7 415 | 416 | 417 | 0332 38 30 38 30 okmsg: db '8080 Preliminary tests complete$' 418 | 0336 20 50 72 65 419 | 033A 6C 69 6D 69 420 | 033E 6E 61 72 79 421 | 0342 20 74 65 73 422 | 0346 74 73 20 63 423 | 034A 6F 6D 70 6C 424 | 034E 65 74 65 24 425 | 426 | ; display address at top of stack and exit 427 | 0352 C1 error: pop b 428 | 0353 26 04 mvi h,high hextab 429 | 0355 78 mov a,b 430 | 0356 0F rrc 431 | 0357 0F rrc 432 | 0358 0F rrc 433 | 0359 0F rrc 434 | 035A E6 0F ani 15 435 | 035C 6F mov l,a 436 | 035D 7E mov a,m 437 | 035E CD 038A call conout 438 | 0361 78 mov a,b 439 | 0362 E6 0F ani 15 440 | 0364 6F mov l,a 441 | 0365 7E mov a,m 442 | 0366 CD 038A call conout 443 | 0369 79 mov a,c 444 | 036A 0F rrc 445 | 036B 0F rrc 446 | 036C 0F rrc 447 | 036D 0F rrc 448 | 036E E6 0F ani 15 449 | 0370 6F mov l,a 450 | 0371 7E mov a,m 451 | 0372 CD 038A call conout 452 | 0375 79 mov a,c 453 | 0376 E6 0F ani 15 454 | 0378 6F mov l,a 455 | 0379 7E mov a,m 456 | 037A CD 038A call conout 457 | 037D 3E 0D mvi a,13 458 | 037F CD 038A call conout 459 | 0382 3E 0A mvi a,10 460 | 0384 CD 038A call conout 461 | 0387 C3 0000 jmp 0 462 | 463 | 038A F5 conout: push psw 464 | 038B C5 push b 465 | 038C D5 push d 466 | 038D E5 push h 467 | 038E 0E 02 mvi c,2 468 | 0390 5F mov e,a 469 | 0391 CD 0005 call 5 470 | 0394 E1 pop h 471 | 0395 D1 pop d 472 | 0396 C1 pop b 473 | 'Preliminary Z80 tests' MACRO-80 3.44 09-Dec-81 PAGE 1-8 474 | 475 | 476 | 0397 F1 pop psw 477 | 0398 C9 ret 478 | 479 | 0000 v defl 0 480 | 0399 regs1: rept 8 481 | v defl v+2 482 | db v 483 | endm 484 | 0399 02 + db v 485 | 039A 04 + db v 486 | 039B 06 + db v 487 | 039C 08 + db v 488 | 039D 0A + db v 489 | 039E 0C + db v 490 | 039F 0E + db v 491 | 03A0 10 + db v 492 | 493 | 03A1 regs2: ds 8,0 494 | 495 | 03A9 A5 3C hlval: db 0a5h,03ch 496 | 497 | ; skip to next page boundary 498 | org (($+255)/256)*256 499 | 0400 30 31 32 33 hextab: db '0123456789abcdef' 500 | 0404 34 35 36 37 501 | 0408 38 39 61 62 502 | 040C 63 64 65 66 503 | 0410 ds 240 504 | 505 | 0500 stack equ $ 506 | 507 | end start 508 | 'Preliminary Z80 tests' MACRO-80 3.44 09-Dec-81 PAGE S 509 | 510 | 511 | Macros: 512 | TCOND 513 | 514 | Symbols: 515 | 0327 ALLOK 038A CONOUT 0352 ERROR 516 | 0400 HEXTAB 03A9 HLVAL 0111 LAB0 517 | 0114 LAB1 0316 LAB10 01DB LAB1C 518 | 02B3 LAB1M 0223 LAB1PE 026B LAB1Z 519 | 0117 LAB2 01E7 LAB2C 02BF LAB2M 520 | 022F LAB2PE 0277 LAB2Z 0121 LAB3 521 | 01F5 LAB3C 02CD LAB3M 023D LAB3PE 522 | 0285 LAB3Z 012A LAB4 0202 LAB4C 523 | 02DA LAB4M 024A LAB4PE 0292 LAB4Z 524 | 020D LAB5C 02E5 LAB5M 0255 LAB5PE 525 | 029D LAB5Z 0218 LAB6C 02F0 LAB6M 526 | 0260 LAB6PE 02A8 LAB6Z 02F7 LAB7 527 | 02FB LAB8 0307 LAB9 0332 OKMSG 528 | 0399 REGS1 03A1 REGS2 0195 RETA 529 | 0500 STACK 0100 START 0010 V 530 | 531 | 532 | 533 | No Fatal error(s) 534 | 535 | 536 | -------------------------------------------------------------------------------- /cpu_tests/TST8080.PRN: -------------------------------------------------------------------------------- 1 | 2 | 3 | ;*********************************************************************** 4 | ; MICROCOSM ASSOCIATES 8080/8085 CPU DIAGNOSTIC VERSION 1.0 (C) 1980 5 | ;*********************************************************************** 6 | ; 7 | ;DONATED TO THE "SIG/M" CP/M USER'S GROUP BY: 8 | ;KELLY SMITH, MICROCOSM ASSOCIATES 9 | ;3055 WACO AVENUE 10 | ;SIMI VALLEY, CALIFORNIA, 93065 11 | ;(805) 527-9321 (MODEM, CP/M-NET (TM)) 12 | ;(805) 527-0518 (VERBAL) 13 | ; 14 | ; Updated by Mike Douglas October, 2012 15 | ; 16 | ; Added the following tests that were missing: 17 | ; mov c,m 18 | ; mov m,c 19 | ; ana b 20 | ; 21 | ; Fixed the CPUER exit routine which did not display the 22 | ; low byte of the failure address properly. 23 | ; 24 | ; Added display of the Microcosm welcome message 25 | ; 26 | 0100 ORG 00100H 27 | 28 | ; 29 | 0100 C3B201 JMP CPU ;JUMP TO 8080 CPU DIAGNOSTIC 30 | ; 31 | 0103 4D4943524FWELCOM DB 'MICROCOSM ASSOCIATES 8080/8085 CPU DIAGNOSTIC',13,10 32 | 0132 2056455253 DB ' VERSION 1.0 (C) 1980',13,10,'$' 33 | ; 34 | 0005 = BDOS EQU 00005H ;BDOS ENTRY TO CP/M 35 | 0000 = WBOOT EQU 00000H ;RE-ENTRY TO CP/M WARM BOOT 36 | ; 37 | ; 38 | ; 39 | ;MESSAGE OUTPUT ROUTINE 40 | ; 41 | 014B D5 MSG: PUSH D ;EXILE D REG. 42 | 014C EB XCHG ;SWAP H&L REGS. TO D&E REGS. 43 | 014D 0E09 MVI C,9 ;LET BDOS KNOW WE WANT TO SEND A MESSAGE 44 | 014F CD0500 CALL BDOS 45 | 0152 D1 POP D ;BACK FROM EXILE 46 | 0153 C9 RET 47 | ; 48 | ; 49 | ; 50 | ;CHARACTER OUTPUT ROUTINE 51 | ; 52 | 0154 0E02 PCHAR: MVI C,2 53 | 0156 CD0500 CALL BDOS 54 | 0159 C9 RET 55 | ; 56 | ; 57 | ; 58 | 015A F5 BYTEO: PUSH PSW 59 | 015B CD6A01 CALL BYTO1 60 | 015E 5F MOV E,A 61 | 015F CD5401 CALL PCHAR 62 | 0162 F1 POP PSW 63 | 0163 CD6E01 CALL BYTO2 64 | 0166 5F MOV E,A 65 | 0167 C35401 JMP PCHAR 66 | 016A 0F BYTO1: RRC 67 | 016B 0F RRC 68 | 016C 0F RRC 69 | 016D 0F RRC 70 | 016E E60F BYTO2: ANI 0FH 71 | 0170 FE0A CPI 0AH 72 | 0172 FA7701 JM BYTO3 73 | 0175 C607 ADI 7 74 | 0177 C630 BYTO3: ADI 30H 75 | 0179 C9 RET 76 | ; 77 | ; 78 | ; 79 | ;************************************************************ 80 | ; MESSAGE TABLE FOR OPERATIONAL CPU TEST 81 | ;************************************************************ 82 | ; 83 | 017A 0D0A204350OKCPU: DB 0DH,0AH,' CPU IS OPERATIONAL$' 84 | ; 85 | 0190 0D0A204350NGCPU: DB 0DH,0AH,' CPU HAS FAILED! ERROR EXIT=$' 86 | ; 87 | ; 88 | ; 89 | ;************************************************************ 90 | ; 8080/8085 CPU TEST/DIAGNOSTIC 91 | ;************************************************************ 92 | ; 93 | ;NOTE: (1) PROGRAM ASSUMES "CALL",AND "LXI SP" INSTRUCTIONS WORK! 94 | ; 95 | ; (2) INSTRUCTIONS NOT TESTED ARE "HLT","DI","EI","RIM","SIM", 96 | ; AND "RST 0" THRU "RST 7" 97 | ; 98 | ; 99 | ; 100 | ;TEST JUMP INSTRUCTIONS AND FLAGS 101 | ; 102 | 01B2 31BD07 CPU: LXI SP,STACK ;SET THE STACK POINTER 103 | 01B5 210301 LXI H,WELCOM 104 | 01B8 CD4B01 CALL MSG 105 | 01BB E600 ANI 0 ;INITIALIZE A REG. AND CLEAR ALL FLAGS 106 | 01BD CAC301 JZ J010 ;TEST "JZ" 107 | 01C0 CDA006 CALL CPUER 108 | 01C3 D2C901 J010: JNC J020 ;TEST "JNC" 109 | 01C6 CDA006 CALL CPUER 110 | 01C9 EACF01 J020: JPE J030 ;TEST "JPE" 111 | 01CC CDA006 CALL CPUER 112 | 01CF F2D501 J030: JP J040 ;TEST "JP" 113 | 01D2 CDA006 CALL CPUER 114 | 01D5 C2E401 J040: JNZ J050 ;TEST "JNZ" 115 | 01D8 DAE401 JC J050 ;TEST "JC" 116 | 01DB E2E401 JPO J050 ;TEST "JPO" 117 | 01DE FAE401 JM J050 ;TEST "JM" 118 | 01E1 C3E701 JMP J060 ;TEST "JMP" (IT'S A LITTLE LATE,BUT WHAT THE HELL! 119 | 01E4 CDA006 J050: CALL CPUER 120 | 01E7 C606 J060: ADI 6 ;A=6,C=0,P=1,S=0,Z=0 121 | 01E9 C2EF01 JNZ J070 ;TEST "JNZ" 122 | 01EC CDA006 CALL CPUER 123 | 01EF DAF801 J070: JC J080 ;TEST "JC" 124 | 01F2 E2F801 JPO J080 ;TEST "JPO" 125 | 01F5 F2FB01 JP J090 ;TEST "JP" 126 | 01F8 CDA006 J080: CALL CPUER 127 | 01FB C670 J090: ADI 070H ;A=76H,C=0,P=0,S=0,Z=0 128 | 01FD E20302 JPO J100 ;TEST "JPO" 129 | 0200 CDA006 CALL CPUER 130 | 0203 FA0C02 J100: JM J110 ;TEST "JM" 131 | 0206 CA0C02 JZ J110 ;TEST "JZ" 132 | 0209 D20F02 JNC J120 ;TEST "JNC" 133 | 020C CDA006 J110: CALL CPUER 134 | 020F C681 J120: ADI 081H ;A=F7H,C=0,P=0,S=1,Z=0 135 | 0211 FA1702 JM J130 ;TEST "JM" 136 | 0214 CDA006 CALL CPUER 137 | 0217 CA2002 J130: JZ J140 ;TEST "JZ" 138 | 021A DA2002 JC J140 ;TEST "JC" 139 | 021D E22302 JPO J150 ;TEST "JPO" 140 | 0220 CDA006 J140: CALL CPUER 141 | 0223 C6FE J150: ADI 0FEH ;A=F5H,C=1,P=1,S=1,Z=0 142 | 0225 DA2B02 JC J160 ;TEST "JC" 143 | 0228 CDA006 CALL CPUER 144 | 022B CA3402 J160: JZ J170 ;TEST "JZ" 145 | 022E E23402 JPO J170 ;TEST "JPO" 146 | 0231 FA3702 JM AIMM ;TEST "JM" 147 | 0234 CDA006 J170: CALL CPUER 148 | ; 149 | ; 150 | ; 151 | ;TEST ACCUMULATOR IMMEDIATE INSTRUCTIONS 152 | ; 153 | 0237 FE00 AIMM: CPI 0 ;A=F5H,C=0,Z=0 154 | 0239 DA4F02 JC CPIE ;TEST "CPI" FOR RE-SET CARRY 155 | 023C CA4F02 JZ CPIE ;TEST "CPI" FOR RE-SET ZERO 156 | 023F FEF5 CPI 0F5H ;A=F5H,C=0,Z=1 157 | 0241 DA4F02 JC CPIE ;TEST "CPI" FOR RE-SET CARRY ("ADI") 158 | 0244 C24F02 JNZ CPIE ;TEST "CPI" FOR RE-SET ZERO 159 | 0247 FEFF CPI 0FFH ;A=F5H,C=1,Z=0 160 | 0249 CA4F02 JZ CPIE ;TEST "CPI" FOR RE-SET ZERO 161 | 024C DA5202 JC ACII ;TEST "CPI" FOR SET CARRY 162 | 024F CDA006 CPIE: CALL CPUER 163 | 0252 CE0A ACII: ACI 00AH ;A=F5H+0AH+CARRY(1)=0,C=1 164 | 0254 CE0A ACI 00AH ;A=0+0AH+CARRY(0)=0BH,C=0 165 | 0256 FE0B CPI 00BH 166 | 0258 CA5E02 JZ SUII ;TEST "ACI" 167 | 025B CDA006 CALL CPUER 168 | 025E D60C SUII: SUI 00CH ;A=FFH,C=0 169 | 0260 D60F SUI 00FH ;A=F0H,C=1 170 | 0262 FEF0 CPI 0F0H 171 | 0264 CA6A02 JZ SBII ;TEST "SUI" 172 | 0267 CDA006 CALL CPUER 173 | 026A DEF1 SBII: SBI 0F1H ;A=F0H-0F1H-CARRY(0)=FFH,C=1 174 | 026C DE0E SBI 00EH ;A=FFH-OEH-CARRY(1)=F0H,C=0 175 | 026E FEF0 CPI 0F0H 176 | 0270 CA7602 JZ ANII ;TEST "SBI" 177 | 0273 CDA006 CALL CPUER 178 | 0276 E655 ANII: ANI 055H ;A=F0H55H=50H,C=0,P=1,S=0,Z=0 179 | 0278 FE50 CPI 050H 180 | 027A CA8002 JZ ORII ;TEST "ANI" 181 | 027D CDA006 CALL CPUER 182 | 0280 F63A ORII: ORI 03AH ;A=50H3AH=7AH,C=0,P=0,S=0,Z=0 183 | 0282 FE7A CPI 07AH 184 | 0284 CA8A02 JZ XRII ;TEST "ORI" 185 | 0287 CDA006 CALL CPUER 186 | 028A EE0F XRII: XRI 00FH ;A=7AH0FH=75H,C=0,P=0,S=0,Z=0 187 | 028C FE75 CPI 075H 188 | 028E CA9402 JZ C010 ;TEST "XRI" 189 | 0291 CDA006 CALL CPUER 190 | ; 191 | ; 192 | ; 193 | ;TEST CALLS AND RETURNS 194 | ; 195 | 0294 E600 C010: ANI 000H ;A=0,C=0,P=1,S=0,Z=1 196 | 0296 DCA006 CC CPUER ;TEST "CC" 197 | 0299 E4A006 CPO CPUER ;TEST "CPO" 198 | 029C FCA006 CM CPUER ;TEST "CM" 199 | 029F C4A006 CNZ CPUER ;TEST "CNZ" 200 | 02A2 FE00 CPI 000H 201 | 02A4 CAAA02 JZ C020 ;A=0,C=0,P=0,S=0,Z=1 202 | 02A7 CDA006 CALL CPUER 203 | 02AA D677 C020: SUI 077H ;A=89H,C=1,P=0,S=1,Z=0 204 | 02AC D4A006 CNC CPUER ;TEST "CNC" 205 | 02AF ECA006 CPE CPUER ;TEST "CPE" 206 | 02B2 F4A006 CP CPUER ;TEST "CP" 207 | 02B5 CCA006 CZ CPUER ;TEST "CZ" 208 | 02B8 FE89 CPI 089H 209 | 02BA CAC002 JZ C030 ;TEST FOR "CALLS" TAKING BRANCH 210 | 02BD CDA006 CALL CPUER 211 | 02C0 E6FF C030: ANI 0FFH ;SET FLAGS BACK! 212 | 02C2 E4CD02 CPO CPOI ;TEST "CPO" 213 | 02C5 FED9 CPI 0D9H 214 | 02C7 CA2A03 JZ MOVI ;TEST "CALL" SEQUENCE SUCCESS 215 | 02CA CDA006 CALL CPUER 216 | 02CD E8 CPOI: RPE ;TEST "RPE" 217 | 02CE C610 ADI 010H ;A=99H,C=0,P=0,S=1,Z=0 218 | 02D0 ECD902 CPE CPEI ;TEST "CPE" 219 | 02D3 C602 ADI 002H ;A=D9H,C=0,P=0,S=1,Z=0 220 | 02D5 E0 RPO ;TEST "RPO" 221 | 02D6 CDA006 CALL CPUER 222 | 02D9 E0 CPEI: RPO ;TEST "RPO" 223 | 02DA C620 ADI 020H ;A=B9H,C=0,P=0,S=1,Z=0 224 | 02DC FCE502 CM CMI ;TEST "CM" 225 | 02DF C604 ADI 004H ;A=D7H,C=0,P=1,S=1,Z=0 226 | 02E1 E8 RPE ;TEST "RPE" 227 | 02E2 CDA006 CALL CPUER 228 | 02E5 F0 CMI: RP ;TEST "RP" 229 | 02E6 C680 ADI 080H ;A=39H,C=1,P=1,S=0,Z=0 230 | 02E8 F4F102 CP TCPI ;TEST "CP" 231 | 02EB C680 ADI 080H ;A=D3H,C=0,P=0,S=1,Z=0 232 | 02ED F8 RM ;TEST "RM" 233 | 02EE CDA006 CALL CPUER 234 | 02F1 F8 TCPI: RM ;TEST "RM" 235 | 02F2 C640 ADI 040H ;A=79H,C=0,P=0,S=0,Z=0 236 | 02F4 D4FD02 CNC CNCI ;TEST "CNC" 237 | 02F7 C640 ADI 040H ;A=53H,C=0,P=1,S=0,Z=0 238 | 02F9 F0 RP ;TEST "RP" 239 | 02FA CDA006 CALL CPUER 240 | 02FD D8 CNCI: RC ;TEST "RC" 241 | 02FE C68F ADI 08FH ;A=08H,C=1,P=0,S=0,Z=0 242 | 0300 DC0903 CC CCI ;TEST "CC" 243 | 0303 D602 SUI 002H ;A=13H,C=0,P=0,S=0,Z=0 244 | 0305 D0 RNC ;TEST "RNC" 245 | 0306 CDA006 CALL CPUER 246 | 0309 D0 CCI: RNC ;TEST "RNC" 247 | 030A C6F7 ADI 0F7H ;A=FFH,C=0,P=1,S=1,Z=0 248 | 030C C41503 CNZ CNZI ;TEST "CNZ" 249 | 030F C6FE ADI 0FEH ;A=15H,C=1,P=0,S=0,Z=0 250 | 0311 D8 RC ;TEST "RC" 251 | 0312 CDA006 CALL CPUER 252 | 0315 C8 CNZI: RZ ;TEST "RZ" 253 | 0316 C601 ADI 001H ;A=00H,C=1,P=1,S=0,Z=1 254 | 0318 CC2103 CZ CZI ;TEST "CZ" 255 | 031B C6D0 ADI 0D0H ;A=17H,C=1,P=1,S=0,Z=0 256 | 031D C0 RNZ ;TEST "RNZ" 257 | 031E CDA006 CALL CPUER 258 | 0321 C0 CZI: RNZ ;TEST "RNZ" 259 | 0322 C647 ADI 047H ;A=47H,C=0,P=1,S=0,Z=0 260 | 0324 FE47 CPI 047H ;A=47H,C=0,P=1,S=0,Z=1 261 | 0326 C8 RZ ;TEST "RZ" 262 | 0327 CDA006 CALL CPUER 263 | ; 264 | ; 265 | ; 266 | ;TEST "MOV","INR",AND "DCR" INSTRUCTIONS 267 | ; 268 | 032A 3E77 MOVI: MVI A,077H 269 | 032C 3C INR A 270 | 032D 47 MOV B,A 271 | 032E 04 INR B 272 | 032F 48 MOV C,B 273 | 0330 0D DCR C 274 | 0331 51 MOV D,C 275 | 0332 5A MOV E,D 276 | 0333 63 MOV H,E 277 | 0334 6C MOV L,H 278 | 0335 7D MOV A,L ;TEST "MOV" A,L,H,E,D,C,B,A 279 | 0336 3D DCR A 280 | 0337 4F MOV C,A 281 | 0338 59 MOV E,C 282 | 0339 6B MOV L,E 283 | 033A 45 MOV B,L 284 | 033B 50 MOV D,B 285 | 033C 62 MOV H,D 286 | 033D 7C MOV A,H ;TEST "MOV" A,H,D,B,L,E,C,A 287 | 033E 57 MOV D,A 288 | 033F 14 INR D 289 | 0340 6A MOV L,D 290 | 0341 4D MOV C,L 291 | 0342 0C INR C 292 | 0343 61 MOV H,C 293 | 0344 44 MOV B,H 294 | 0345 05 DCR B 295 | 0346 58 MOV E,B 296 | 0347 7B MOV A,E ;TEST "MOV" A,E,B,H,C,L,D,A 297 | 0348 5F MOV E,A 298 | 0349 1C INR E 299 | 034A 43 MOV B,E 300 | 034B 60 MOV H,B 301 | 034C 24 INR H 302 | 034D 4C MOV C,H 303 | 034E 69 MOV L,C 304 | 034F 55 MOV D,L 305 | 0350 15 DCR D 306 | 0351 7A MOV A,D ;TEST "MOV" A,D,L,C,H,B,E,A 307 | 0352 67 MOV H,A 308 | 0353 25 DCR H 309 | 0354 54 MOV D,H 310 | 0355 42 MOV B,D 311 | 0356 68 MOV L,B 312 | 0357 2C INR L 313 | 0358 5D MOV E,L 314 | 0359 1D DCR E 315 | 035A 4B MOV C,E 316 | 035B 79 MOV A,C ;TEST "MOV" A,C,E,L,B,D,H,A 317 | 035C 6F MOV L,A 318 | 035D 2D DCR L 319 | 035E 65 MOV H,L 320 | 035F 5C MOV E,H 321 | 0360 53 MOV D,E 322 | 0361 4A MOV C,D 323 | 0362 41 MOV B,C 324 | 0363 78 MOV A,B 325 | 0364 FE77 CPI 077H 326 | 0366 C4A006 CNZ CPUER ;TEST "MOV" A,B,C,D,E,H,L,A 327 | ; 328 | ; 329 | ; 330 | ;TEST ARITHMETIC AND LOGIC INSTRUCTIONS 331 | ; 332 | 0369 AF XRA A 333 | 036A 0601 MVI B,001H 334 | 036C 0E03 MVI C,003H 335 | 036E 1607 MVI D,007H 336 | 0370 1E0F MVI E,00FH 337 | 0372 261F MVI H,01FH 338 | 0374 2E3F MVI L,03FH 339 | 0376 80 ADD B 340 | 0377 81 ADD C 341 | 0378 82 ADD D 342 | 0379 83 ADD E 343 | 037A 84 ADD H 344 | 037B 85 ADD L 345 | 037C 87 ADD A 346 | 037D FEF0 CPI 0F0H 347 | 037F C4A006 CNZ CPUER ;TEST "ADD" B,C,D,E,H,L,A 348 | 0382 90 SUB B 349 | 0383 91 SUB C 350 | 0384 92 SUB D 351 | 0385 93 SUB E 352 | 0386 94 SUB H 353 | 0387 95 SUB L 354 | 0388 FE78 CPI 078H 355 | 038A C4A006 CNZ CPUER ;TEST "SUB" B,C,D,E,H,L 356 | 038D 97 SUB A 357 | 038E C4A006 CNZ CPUER ;TEST "SUB" A 358 | 0391 3E80 MVI A,080H 359 | 0393 87 ADD A 360 | 0394 0601 MVI B,001H 361 | 0396 0E02 MVI C,002H 362 | 0398 1603 MVI D,003H 363 | 039A 1E04 MVI E,004H 364 | 039C 2605 MVI H,005H 365 | 039E 2E06 MVI L,006H 366 | 03A0 88 ADC B 367 | 03A1 0680 MVI B,080H 368 | 03A3 80 ADD B 369 | 03A4 80 ADD B 370 | 03A5 89 ADC C 371 | 03A6 80 ADD B 372 | 03A7 80 ADD B 373 | 03A8 8A ADC D 374 | 03A9 80 ADD B 375 | 03AA 80 ADD B 376 | 03AB 8B ADC E 377 | 03AC 80 ADD B 378 | 03AD 80 ADD B 379 | 03AE 8C ADC H 380 | 03AF 80 ADD B 381 | 03B0 80 ADD B 382 | 03B1 8D ADC L 383 | 03B2 80 ADD B 384 | 03B3 80 ADD B 385 | 03B4 8F ADC A 386 | 03B5 FE37 CPI 037H 387 | 03B7 C4A006 CNZ CPUER ;TEST "ADC" B,C,D,E,H,L,A 388 | 03BA 3E80 MVI A,080H 389 | 03BC 87 ADD A 390 | 03BD 0601 MVI B,001H 391 | 03BF 98 SBB B 392 | 03C0 06FF MVI B,0FFH 393 | 03C2 80 ADD B 394 | 03C3 99 SBB C 395 | 03C4 80 ADD B 396 | 03C5 9A SBB D 397 | 03C6 80 ADD B 398 | 03C7 9B SBB E 399 | 03C8 80 ADD B 400 | 03C9 9C SBB H 401 | 03CA 80 ADD B 402 | 03CB 9D SBB L 403 | 03CC FEE0 CPI 0E0H 404 | 03CE C4A006 CNZ CPUER ;TEST "SBB" B,C,D,E,H,L 405 | 03D1 3E80 MVI A,080H 406 | 03D3 87 ADD A 407 | 03D4 9F SBB A 408 | 03D5 FEFF CPI 0FFH 409 | 03D7 C4A006 CNZ CPUER ;TEST "SBB" A 410 | 03DA 3EFF MVI A,0FFH 411 | 03DC 06FE MVI B,0FEH 412 | 03DE 0EFC MVI C,0FCH 413 | 03E0 16EF MVI D,0EFH 414 | 03E2 1E7F MVI E,07FH 415 | 03E4 26F4 MVI H,0F4H 416 | 03E6 2EBF MVI L,0BFH 417 | 03E8 A0 ANA B ;changed from ANA A (mwd) 418 | 03E9 A1 ANA C 419 | 03EA A2 ANA D 420 | 03EB A3 ANA E 421 | 03EC A4 ANA H 422 | 03ED A5 ANA L 423 | 03EE A7 ANA A 424 | 03EF FE24 CPI 024H 425 | 03F1 C4A006 CNZ CPUER ;TEST "ANA" B,C,D,E,H,L,A 426 | 03F4 AF XRA A 427 | 03F5 0601 MVI B,001H 428 | 03F7 0E02 MVI C,002H 429 | 03F9 1604 MVI D,004H 430 | 03FB 1E08 MVI E,008H 431 | 03FD 2610 MVI H,010H 432 | 03FF 2E20 MVI L,020H 433 | 0401 B0 ORA B 434 | 0402 B1 ORA C 435 | 0403 B2 ORA D 436 | 0404 B3 ORA E 437 | 0405 B4 ORA H 438 | 0406 B5 ORA L 439 | 0407 B7 ORA A 440 | 0408 FE3F CPI 03FH 441 | 040A C4A006 CNZ CPUER ;TEST "ORA" B,C,D,E,H,L,A 442 | 040D 3E00 MVI A,000H 443 | 040F 268F MVI H,08FH 444 | 0411 2E4F MVI L,04FH 445 | 0413 A8 XRA B 446 | 0414 A9 XRA C 447 | 0415 AA XRA D 448 | 0416 AB XRA E 449 | 0417 AC XRA H 450 | 0418 AD XRA L 451 | 0419 FECF CPI 0CFH 452 | 041B C4A006 CNZ CPUER ;TEST "XRA" B,C,D,E,H,L 453 | 041E AF XRA A 454 | 041F C4A006 CNZ CPUER ;TEST "XRA" A 455 | 0422 0644 MVI B,044H 456 | 0424 0E45 MVI C,045H 457 | 0426 1646 MVI D,046H 458 | 0428 1E47 MVI E,047H 459 | 042A 2606 MVI H,(TEMP0 / 0FFH) ;HIGH BYTE OF TEST MEMORY LOCATION 460 | 042C 2EBF MVI L,(TEMP0 AND 0FFH) ;LOW BYTE OF TEST MEMORY LOCATION 461 | 042E 70 MOV M,B 462 | 042F 0600 MVI B,000H 463 | 0431 46 MOV B,M 464 | 0432 3E44 MVI A,044H 465 | 0434 B8 CMP B 466 | 0435 C4A006 CNZ CPUER ;TEST "MOV" M,B AND B,M 467 | 0438 71 MOV M,C ;added (mwd) 468 | 0439 0E00 MVI C,000H ;added (mwd) 469 | 043B 4E MOV C,M ;added (mwd) 470 | 043C 3E45 MVI A,045H ;added (mwd) 471 | 043E B9 CMP C ;added (mwd) 472 | 043F C4A006 CNZ CPUER ;TEST "MOV" M,C AND C,M added (mwd) 473 | 0442 72 MOV M,D 474 | 0443 1600 MVI D,000H 475 | 0445 56 MOV D,M 476 | 0446 3E46 MVI A,046H 477 | 0448 BA CMP D 478 | 0449 C4A006 CNZ CPUER ;TEST "MOV" M,D AND D,M 479 | 044C 73 MOV M,E 480 | 044D 1E00 MVI E,000H 481 | 044F 5E MOV E,M 482 | 0450 3E47 MVI A,047H 483 | 0452 BB CMP E 484 | 0453 C4A006 CNZ CPUER ;TEST "MOV" M,E AND E,M 485 | 0456 74 MOV M,H 486 | 0457 2606 MVI H,(TEMP0 / 0FFH) 487 | 0459 2EBF MVI L,(TEMP0 AND 0FFH) 488 | 045B 66 MOV H,M 489 | 045C 3E06 MVI A,(TEMP0 / 0FFH) 490 | 045E BC CMP H 491 | 045F C4A006 CNZ CPUER ;TEST "MOV" M,H AND H,M 492 | 0462 75 MOV M,L 493 | 0463 2606 MVI H,(TEMP0 / 0FFH) 494 | 0465 2EBF MVI L,(TEMP0 AND 0FFH) 495 | 0467 6E MOV L,M 496 | 0468 3EBF MVI A,(TEMP0 AND 0FFH) 497 | 046A BD CMP L 498 | 046B C4A006 CNZ CPUER ;TEST "MOV" M,L AND L,M 499 | 046E 2606 MVI H,(TEMP0 / 0FFH) 500 | 0470 2EBF MVI L,(TEMP0 AND 0FFH) 501 | 0472 3E32 MVI A,032H 502 | 0474 77 MOV M,A 503 | 0475 BE CMP M 504 | 0476 C4A006 CNZ CPUER ;TEST "MOV" M,A 505 | 0479 86 ADD M 506 | 047A FE64 CPI 064H 507 | 047C C4A006 CNZ CPUER ;TEST "ADD" M 508 | 047F AF XRA A 509 | 0480 7E MOV A,M 510 | 0481 FE32 CPI 032H 511 | 0483 C4A006 CNZ CPUER ;TEST "MOV" A,M 512 | 0486 2606 MVI H,(TEMP0 / 0FFH) 513 | 0488 2EBF MVI L,(TEMP0 AND 0FFH) 514 | 048A 7E MOV A,M 515 | 048B 96 SUB M 516 | 048C C4A006 CNZ CPUER ;TEST "SUB" M 517 | 048F 3E80 MVI A,080H 518 | 0491 87 ADD A 519 | 0492 8E ADC M 520 | 0493 FE33 CPI 033H 521 | 0495 C4A006 CNZ CPUER ;TEST "ADC" M 522 | 0498 3E80 MVI A,080H 523 | 049A 87 ADD A 524 | 049B 9E SBB M 525 | 049C FECD CPI 0CDH 526 | 049E C4A006 CNZ CPUER ;TEST "SBB" M 527 | 04A1 A6 ANA M 528 | 04A2 C4A006 CNZ CPUER ;TEST "ANA" M 529 | 04A5 3E25 MVI A,025H 530 | 04A7 B6 ORA M 531 | 04A8 FE37 CPI 037H 532 | 04AA C4A006 CNZ CPUER ;TEST "ORA" M 533 | 04AD AE XRA M 534 | 04AE FE05 CPI 005H 535 | 04B0 C4A006 CNZ CPUER ;TEST "XRA" M 536 | 04B3 3655 MVI M,055H 537 | 04B5 34 INR M 538 | 04B6 35 DCR M 539 | 04B7 86 ADD M 540 | 04B8 FE5A CPI 05AH 541 | 04BA C4A006 CNZ CPUER ;TEST "INR","DCR",AND "MVI" M 542 | 04BD 01FF12 LXI B,12FFH 543 | 04C0 11FF12 LXI D,12FFH 544 | 04C3 21FF12 LXI H,12FFH 545 | 04C6 03 INX B 546 | 04C7 13 INX D 547 | 04C8 23 INX H 548 | 04C9 3E13 MVI A,013H 549 | 04CB B8 CMP B 550 | 04CC C4A006 CNZ CPUER ;TEST "LXI" AND "INX" B 551 | 04CF BA CMP D 552 | 04D0 C4A006 CNZ CPUER ;TEST "LXI" AND "INX" D 553 | 04D3 BC CMP H 554 | 04D4 C4A006 CNZ CPUER ;TEST "LXI" AND "INX" H 555 | 04D7 3E00 MVI A,000H 556 | 04D9 B9 CMP C 557 | 04DA C4A006 CNZ CPUER ;TEST "LXI" AND "INX" B 558 | 04DD BB CMP E 559 | 04DE C4A006 CNZ CPUER ;TEST "LXI" AND "INX" D 560 | 04E1 BD CMP L 561 | 04E2 C4A006 CNZ CPUER ;TEST "LXI" AND "INX" H 562 | 04E5 0B DCX B 563 | 04E6 1B DCX D 564 | 04E7 2B DCX H 565 | 04E8 3E12 MVI A,012H 566 | 04EA B8 CMP B 567 | 04EB C4A006 CNZ CPUER ;TEST "DCX" B 568 | 04EE BA CMP D 569 | 04EF C4A006 CNZ CPUER ;TEST "DCX" D 570 | 04F2 BC CMP H 571 | 04F3 C4A006 CNZ CPUER ;TEST "DCX" H 572 | 04F6 3EFF MVI A,0FFH 573 | 04F8 B9 CMP C 574 | 04F9 C4A006 CNZ CPUER ;TEST "DCX" B 575 | 04FC BB CMP E 576 | 04FD C4A006 CNZ CPUER ;TEST "DCX" D 577 | 0500 BD CMP L 578 | 0501 C4A006 CNZ CPUER ;TEST "DCX" H 579 | 0504 32BF06 STA TEMP0 580 | 0507 AF XRA A 581 | 0508 3ABF06 LDA TEMP0 582 | 050B FEFF CPI 0FFH 583 | 050D C4A006 CNZ CPUER ;TEST "LDA" AND "STA" 584 | 0510 2ABD06 LHLD TEMPP 585 | 0513 22BF06 SHLD TEMP0 586 | 0516 3ABD06 LDA TEMPP 587 | 0519 47 MOV B,A 588 | 051A 3ABF06 LDA TEMP0 589 | 051D B8 CMP B 590 | 051E C4A006 CNZ CPUER ;TEST "LHLD" AND "SHLD" 591 | 0521 3ABE06 LDA TEMPP+1 592 | 0524 47 MOV B,A 593 | 0525 3AC006 LDA TEMP0+1 594 | 0528 B8 CMP B 595 | 0529 C4A006 CNZ CPUER ;TEST "LHLD" AND "SHLD" 596 | 052C 3EAA MVI A,0AAH 597 | 052E 32BF06 STA TEMP0 598 | 0531 44 MOV B,H 599 | 0532 4D MOV C,L 600 | 0533 AF XRA A 601 | 0534 0A LDAX B 602 | 0535 FEAA CPI 0AAH 603 | 0537 C4A006 CNZ CPUER ;TEST "LDAX" B 604 | 053A 3C INR A 605 | 053B 02 STAX B 606 | 053C 3ABF06 LDA TEMP0 607 | 053F FEAB CPI 0ABH 608 | 0541 C4A006 CNZ CPUER ;TEST "STAX" B 609 | 0544 3E77 MVI A,077H 610 | 0546 32BF06 STA TEMP0 611 | 0549 2ABD06 LHLD TEMPP 612 | 054C 110000 LXI D,00000H 613 | 054F EB XCHG 614 | 0550 AF XRA A 615 | 0551 1A LDAX D 616 | 0552 FE77 CPI 077H 617 | 0554 C4A006 CNZ CPUER ;TEST "LDAX" D AND "XCHG" 618 | 0557 AF XRA A 619 | 0558 84 ADD H 620 | 0559 85 ADD L 621 | 055A C4A006 CNZ CPUER ;TEST "XCHG" 622 | 055D 3ECC MVI A,0CCH 623 | 055F 12 STAX D 624 | 0560 3ABF06 LDA TEMP0 625 | 0563 FECC CPI 0CCH 626 | 0565 12 STAX D 627 | 0566 3ABF06 LDA TEMP0 628 | 0569 FECC CPI 0CCH 629 | 056B C4A006 CNZ CPUER ;TEST "STAX" D 630 | 056E 217777 LXI H,07777H 631 | 0571 29 DAD H 632 | 0572 3EEE MVI A,0EEH 633 | 0574 BC CMP H 634 | 0575 C4A006 CNZ CPUER ;TEST "DAD" H 635 | 0578 BD CMP L 636 | 0579 C4A006 CNZ CPUER ;TEST "DAD" H 637 | 057C 215555 LXI H,05555H 638 | 057F 01FFFF LXI B,0FFFFH 639 | 0582 09 DAD B 640 | 0583 3E55 MVI A,055H 641 | 0585 D4A006 CNC CPUER ;TEST "DAD" B 642 | 0588 BC CMP H 643 | 0589 C4A006 CNZ CPUER ;TEST "DAD" B 644 | 058C 3E54 MVI A,054H 645 | 058E BD CMP L 646 | 058F C4A006 CNZ CPUER ;TEST "DAD" B 647 | 0592 21AAAA LXI H,0AAAAH 648 | 0595 113333 LXI D,03333H 649 | 0598 19 DAD D 650 | 0599 3EDD MVI A,0DDH 651 | 059B BC CMP H 652 | 059C C4A006 CNZ CPUER ;TEST "DAD" D 653 | 059F BD CMP L 654 | 05A0 C4A006 CNZ CPUER ;TEST "DAD" B 655 | 05A3 37 STC 656 | 05A4 D4A006 CNC CPUER ;TEST "STC" 657 | 05A7 3F CMC 658 | 05A8 DCA006 CC CPUER ;TEST "CMC 659 | 05AB 3EAA MVI A,0AAH 660 | 05AD 2F CMA 661 | 05AE FE55 CPI 055H 662 | 05B0 C4A006 CNZ CPUER ;TEST "CMA" 663 | 05B3 B7 ORA A ;RE-SET AUXILIARY CARRY 664 | 05B4 27 DAA 665 | 05B5 FE55 CPI 055H 666 | 05B7 C4A006 CNZ CPUER ;TEST "DAA" 667 | 05BA 3E88 MVI A,088H 668 | 05BC 87 ADD A 669 | 05BD 27 DAA 670 | 05BE FE76 CPI 076H 671 | 05C0 C4A006 CNZ CPUER ;TEST "DAA" 672 | 05C3 AF XRA A 673 | 05C4 3EAA MVI A,0AAH 674 | 05C6 27 DAA 675 | 05C7 D4A006 CNC CPUER ;TEST "DAA" 676 | 05CA FE10 CPI 010H 677 | 05CC C4A006 CNZ CPUER ;TEST "DAA" 678 | 05CF AF XRA A 679 | 05D0 3E9A MVI A,09AH 680 | 05D2 27 DAA 681 | 05D3 D4A006 CNC CPUER ;TEST "DAA" 682 | 05D6 C4A006 CNZ CPUER ;TEST "DAA" 683 | 05D9 37 STC 684 | 05DA 3E42 MVI A,042H 685 | 05DC 07 RLC 686 | 05DD DCA006 CC CPUER ;TEST "RLC" FOR RE-SET CARRY 687 | 05E0 07 RLC 688 | 05E1 D4A006 CNC CPUER ;TEST "RLC" FOR SET CARRY 689 | 05E4 FE09 CPI 009H 690 | 05E6 C4A006 CNZ CPUER ;TEST "RLC" FOR ROTATION 691 | 05E9 0F RRC 692 | 05EA D4A006 CNC CPUER ;TEST "RRC" FOR SET CARRY 693 | 05ED 0F RRC 694 | 05EE FE42 CPI 042H 695 | 05F0 C4A006 CNZ CPUER ;TEST "RRC" FOR ROTATION 696 | 05F3 17 RAL 697 | 05F4 17 RAL 698 | 05F5 D4A006 CNC CPUER ;TEST "RAL" FOR SET CARRY 699 | 05F8 FE08 CPI 008H 700 | 05FA C4A006 CNZ CPUER ;TEST "RAL" FOR ROTATION 701 | 05FD 1F RAR 702 | 05FE 1F RAR 703 | 05FF DCA006 CC CPUER ;TEST "RAR" FOR RE-SET CARRY 704 | 0602 FE02 CPI 002H 705 | 0604 C4A006 CNZ CPUER ;TEST "RAR" FOR ROTATION 706 | 0607 013412 LXI B,01234H 707 | 060A 11AAAA LXI D,0AAAAH 708 | 060D 215555 LXI H,05555H 709 | 0610 AF XRA A 710 | 0611 C5 PUSH B 711 | 0612 D5 PUSH D 712 | 0613 E5 PUSH H 713 | 0614 F5 PUSH PSW 714 | 0615 010000 LXI B,00000H 715 | 0618 110000 LXI D,00000H 716 | 061B 210000 LXI H,00000H 717 | 061E 3EC0 MVI A,0C0H 718 | 0620 C6F0 ADI 0F0H 719 | 0622 F1 POP PSW 720 | 0623 E1 POP H 721 | 0624 D1 POP D 722 | 0625 C1 POP B 723 | 0626 DCA006 CC CPUER ;TEST "PUSH PSW" AND "POP PSW" 724 | 0629 C4A006 CNZ CPUER ;TEST "PUSH PSW" AND "POP PSW" 725 | 062C E4A006 CPO CPUER ;TEST "PUSH PSW" AND "POP PSW" 726 | 062F FCA006 CM CPUER ;TEST "PUSH PSW" AND "POP PSW" 727 | 0632 3E12 MVI A,012H 728 | 0634 B8 CMP B 729 | 0635 C4A006 CNZ CPUER ;TEST "PUSH B" AND "POP B" 730 | 0638 3E34 MVI A,034H 731 | 063A B9 CMP C 732 | 063B C4A006 CNZ CPUER ;TEST "PUSH B" AND "POP B" 733 | 063E 3EAA MVI A,0AAH 734 | 0640 BA CMP D 735 | 0641 C4A006 CNZ CPUER ;TEST "PUSH D" AND "POP D" 736 | 0644 BB CMP E 737 | 0645 C4A006 CNZ CPUER ;TEST "PUSH D" AND "POP D" 738 | 0648 3E55 MVI A,055H 739 | 064A BC CMP H 740 | 064B C4A006 CNZ CPUER ;TEST "PUSH H" AND "POP H" 741 | 064E BD CMP L 742 | 064F C4A006 CNZ CPUER ;TEST "PUSH H" AND "POP H" 743 | 0652 210000 LXI H,00000H 744 | 0655 39 DAD SP 745 | 0656 22C406 SHLD SAVSTK ;SAVE THE "OLD" STACK-POINTER! 746 | 0659 31C306 LXI SP,TEMP4 747 | 065C 3B DCX SP 748 | 065D 3B DCX SP 749 | 065E 33 INX SP 750 | 065F 3B DCX SP 751 | 0660 3E55 MVI A,055H 752 | 0662 32C106 STA TEMP2 753 | 0665 2F CMA 754 | 0666 32C206 STA TEMP3 755 | 0669 C1 POP B 756 | 066A B8 CMP B 757 | 066B C4A006 CNZ CPUER ;TEST "LXI","DAD","INX",AND "DCX" SP 758 | 066E 2F CMA 759 | 066F B9 CMP C 760 | 0670 C4A006 CNZ CPUER ;TEST "LXI","DAD","INX", AND "DCX" SP 761 | 0673 21C306 LXI H,TEMP4 762 | 0676 F9 SPHL 763 | 0677 213377 LXI H,07733H 764 | 067A 3B DCX SP 765 | 067B 3B DCX SP 766 | 067C E3 XTHL 767 | 067D 3AC206 LDA TEMP3 768 | 0680 FE77 CPI 077H 769 | 0682 C4A006 CNZ CPUER ;TEST "SPHL" AND "XTHL" 770 | 0685 3AC106 LDA TEMP2 771 | 0688 FE33 CPI 033H 772 | 068A C4A006 CNZ CPUER ;TEST "SPHL" AND "XTHL" 773 | 068D 3E55 MVI A,055H 774 | 068F BD CMP L 775 | 0690 C4A006 CNZ CPUER ;TEST "SPHL" AND "XTHL" 776 | 0693 2F CMA 777 | 0694 BC CMP H 778 | 0695 C4A006 CNZ CPUER ;TEST "SPHL" AND "XTHL" 779 | 0698 2AC406 LHLD SAVSTK ;RESTORE THE "OLD" STACK-POINTER 780 | 069B F9 SPHL 781 | 069C 21B406 LXI H,CPUOK 782 | 069F E9 PCHL ;TEST "PCHL" 783 | ; 784 | ; 785 | ; 786 | 06A0 219001 CPUER: LXI H,NGCPU ;OUTPUT "CPU HAS FAILED ERROR EXIT=" TO CONSOLE 787 | 06A3 CD4B01 CALL MSG 788 | 06A6 E1 POP H ;HL = ADDRESS FOLLOWING CALL CPUER 789 | 06A7 E5 PUSH H 790 | 06A8 7C MOV A,H 791 | 06A9 CD5A01 CALL BYTEO ;SHOW ERROR EXIT ADDRESS HIGH BYTE 792 | 06AC E1 POP H 793 | 06AD 7D MOV A,L 794 | 06AE CD5A01 CALL BYTEO ;SHOW ERROR EXIT ADDRESS LOW BYTE 795 | 06B1 C30000 JMP WBOOT ;EXIT TO CP/M WARM BOOT 796 | ; 797 | ; 798 | ; 799 | 06B4 217A01 CPUOK: LXI H,OKCPU ;OUTPUT "CPU IS OPERATIONAL" TO CONSOLE 800 | 06B7 CD4B01 CALL MSG 801 | 06BA C30000 JMP WBOOT ;EXIT TO CP/M WARM BOOT 802 | ; 803 | ; 804 | ; 805 | 06BD BF06 TEMPP: DW TEMP0 ;POINTER USED TO TEST "LHLD","SHLD", 806 | ; AND "LDAX" INSTRUCTIONS 807 | ; 808 | 06BF TEMP0: DS 1 ;TEMPORARY STORAGE FOR CPU TEST MEMORY LOCATIONS 809 | 06C0 TEMP1: DS 1 ;TEMPORARY STORAGE FOR CPU TEST MEMORY LOCATIONS 810 | 06C1 TEMP2 DS 1 ;TEMPORARY STORAGE FOR CPU TEST MEMORY LOCATIONS 811 | 06C2 TEMP3: DS 1 ;TEMPORARY STORAGE FOR CPU TEST MEMORY LOCATIONS 812 | 06C3 TEMP4: DS 1 ;TEMPORARY STORAGE FOR CPU TEST MEMORY LOCATIONS 813 | 06C4 SAVSTK: DS 2 ;TEMPORARY STACK-POINTER STORAGE LOCATION 814 | ; 815 | ; 816 | ; 817 | 07BD = STACK EQU TEMPP+256 ;DE-BUG STACK POINTER STORAGE AREA 818 | ; 819 | ; 820 | ; 821 | 06C6 END 822 | -------------------------------------------------------------------------------- /i8080.c: -------------------------------------------------------------------------------- 1 | #include "i8080.h" 2 | 3 | // this array defines the number of cycles one opcode takes. 4 | // note that there are some special cases: conditional RETs and CALLs 5 | // add +6 cycles if the condition is met 6 | // clang-format off 7 | static const uint8_t OPCODES_CYCLES[256] = { 8 | // 0 1 2 3 4 5 6 7 8 9 A B C D E F 9 | 4, 10, 7, 5, 5, 5, 7, 4, 4, 10, 7, 5, 5, 5, 7, 4, // 0 10 | 4, 10, 7, 5, 5, 5, 7, 4, 4, 10, 7, 5, 5, 5, 7, 4, // 1 11 | 4, 10, 16, 5, 5, 5, 7, 4, 4, 10, 16, 5, 5, 5, 7, 4, // 2 12 | 4, 10, 13, 5, 10, 10, 10, 4, 4, 10, 13, 5, 5, 5, 7, 4, // 3 13 | 5, 5, 5, 5, 5, 5, 7, 5, 5, 5, 5, 5, 5, 5, 7, 5, // 4 14 | 5, 5, 5, 5, 5, 5, 7, 5, 5, 5, 5, 5, 5, 5, 7, 5, // 5 15 | 5, 5, 5, 5, 5, 5, 7, 5, 5, 5, 5, 5, 5, 5, 7, 5, // 6 16 | 7, 7, 7, 7, 7, 7, 7, 7, 5, 5, 5, 5, 5, 5, 7, 5, // 7 17 | 4, 4, 4, 4, 4, 4, 7, 4, 4, 4, 4, 4, 4, 4, 7, 4, // 8 18 | 4, 4, 4, 4, 4, 4, 7, 4, 4, 4, 4, 4, 4, 4, 7, 4, // 9 19 | 4, 4, 4, 4, 4, 4, 7, 4, 4, 4, 4, 4, 4, 4, 7, 4, // A 20 | 4, 4, 4, 4, 4, 4, 7, 4, 4, 4, 4, 4, 4, 4, 7, 4, // B 21 | 5, 10, 10, 10, 11, 11, 7, 11, 5, 10, 10, 10, 11, 17, 7, 11, // C 22 | 5, 10, 10, 10, 11, 11, 7, 11, 5, 10, 10, 10, 11, 17, 7, 11, // D 23 | 5, 10, 10, 18, 11, 11, 7, 11, 5, 5, 10, 4, 11, 17, 7, 11, // E 24 | 5, 10, 10, 4, 11, 11, 7, 11, 5, 5, 10, 4, 11, 17, 7, 11 // F 25 | }; 26 | // clang-format on 27 | 28 | static const char* DISASSEMBLE_TABLE[] = {"nop", "lxi b,#", "stax b", "inx b", 29 | "inr b", "dcr b", "mvi b,#", "rlc", "ill", "dad b", "ldax b", "dcx b", 30 | "inr c", "dcr c", "mvi c,#", "rrc", "ill", "lxi d,#", "stax d", "inx d", 31 | "inr d", "dcr d", "mvi d,#", "ral", "ill", "dad d", "ldax d", "dcx d", 32 | "inr e", "dcr e", "mvi e,#", "rar", "ill", "lxi h,#", "shld", "inx h", 33 | "inr h", "dcr h", "mvi h,#", "daa", "ill", "dad h", "lhld", "dcx h", 34 | "inr l", "dcr l", "mvi l,#", "cma", "ill", "lxi sp,#", "sta $", "inx sp", 35 | "inr M", "dcr M", "mvi M,#", "stc", "ill", "dad sp", "lda $", "dcx sp", 36 | "inr a", "dcr a", "mvi a,#", "cmc", "mov b,b", "mov b,c", "mov b,d", 37 | "mov b,e", "mov b,h", "mov b,l", "mov b,M", "mov b,a", "mov c,b", "mov c,c", 38 | "mov c,d", "mov c,e", "mov c,h", "mov c,l", "mov c,M", "mov c,a", "mov d,b", 39 | "mov d,c", "mov d,d", "mov d,e", "mov d,h", "mov d,l", "mov d,M", "mov d,a", 40 | "mov e,b", "mov e,c", "mov e,d", "mov e,e", "mov e,h", "mov e,l", "mov e,M", 41 | "mov e,a", "mov h,b", "mov h,c", "mov h,d", "mov h,e", "mov h,h", "mov h,l", 42 | "mov h,M", "mov h,a", "mov l,b", "mov l,c", "mov l,d", "mov l,e", "mov l,h", 43 | "mov l,l", "mov l,M", "mov l,a", "mov M,b", "mov M,c", "mov M,d", "mov M,e", 44 | "mov M,h", "mov M,l", "hlt", "mov M,a", "mov a,b", "mov a,c", "mov a,d", 45 | "mov a,e", "mov a,h", "mov a,l", "mov a,M", "mov a,a", "add b", "add c", 46 | "add d", "add e", "add h", "add l", "add M", "add a", "adc b", "adc c", 47 | "adc d", "adc e", "adc h", "adc l", "adc M", "adc a", "sub b", "sub c", 48 | "sub d", "sub e", "sub h", "sub l", "sub M", "sub a", "sbb b", "sbb c", 49 | "sbb d", "sbb e", "sbb h", "sbb l", "sbb M", "sbb a", "ana b", "ana c", 50 | "ana d", "ana e", "ana h", "ana l", "ana M", "ana a", "xra b", "xra c", 51 | "xra d", "xra e", "xra h", "xra l", "xra M", "xra a", "ora b", "ora c", 52 | "ora d", "ora e", "ora h", "ora l", "ora M", "ora a", "cmp b", "cmp c", 53 | "cmp d", "cmp e", "cmp h", "cmp l", "cmp M", "cmp a", "rnz", "pop b", 54 | "jnz $", "jmp $", "cnz $", "push b", "adi #", "rst 0", "rz", "ret", "jz $", 55 | "ill", "cz $", "call $", "aci #", "rst 1", "rnc", "pop d", "jnc $", "out p", 56 | "cnc $", "push d", "sui #", "rst 2", "rc", "ill", "jc $", "in p", "cc $", 57 | "ill", "sbi #", "rst 3", "rpo", "pop h", "jpo $", "xthl", "cpo $", "push h", 58 | "ani #", "rst 4", "rpe", "pchl", "jpe $", "xchg", "cpe $", "ill", "xri #", 59 | "rst 5", "rp", "pop psw", "jp $", "di", "cp $", "push psw", "ori #", 60 | "rst 6", "rm", "sphl", "jm $", "ei", "cm $", "ill", "cpi #", "rst 7"}; 61 | 62 | #define SET_ZSP(c, val) \ 63 | do { \ 64 | c->zf = (val) == 0; \ 65 | c->sf = (val) >> 7; \ 66 | c->pf = parity(val); \ 67 | } while (0) 68 | 69 | // memory helpers (the only four to use `read_byte` and `write_byte` function 70 | // pointers) 71 | 72 | // reads a byte from memory 73 | static inline uint8_t i8080_rb(i8080* const c, uint16_t addr) { 74 | return c->read_byte(c->userdata, addr); 75 | } 76 | 77 | // writes a byte to memory 78 | static inline void i8080_wb(i8080* const c, uint16_t addr, uint8_t val) { 79 | c->write_byte(c->userdata, addr, val); 80 | } 81 | 82 | // reads a word from memory 83 | static inline uint16_t i8080_rw(i8080* const c, uint16_t addr) { 84 | return c->read_byte(c->userdata, addr + 1) << 8 | 85 | c->read_byte(c->userdata, addr); 86 | } 87 | 88 | // writes a word to memory 89 | static inline void i8080_ww(i8080* const c, uint16_t addr, uint16_t val) { 90 | c->write_byte(c->userdata, addr, val & 0xFF); 91 | c->write_byte(c->userdata, addr + 1, val >> 8); 92 | } 93 | 94 | // returns the next byte in memory (and updates the program counter) 95 | static inline uint8_t i8080_next_byte(i8080* const c) { 96 | return i8080_rb(c, c->pc++); 97 | } 98 | 99 | // returns the next word in memory (and updates the program counter) 100 | static inline uint16_t i8080_next_word(i8080* const c) { 101 | uint16_t result = i8080_rw(c, c->pc); 102 | c->pc += 2; 103 | return result; 104 | } 105 | 106 | // paired registers helpers (setters and getters) 107 | static inline void i8080_set_bc(i8080* const c, uint16_t val) { 108 | c->b = val >> 8; 109 | c->c = val & 0xFF; 110 | } 111 | 112 | static inline void i8080_set_de(i8080* const c, uint16_t val) { 113 | c->d = val >> 8; 114 | c->e = val & 0xFF; 115 | } 116 | 117 | static inline void i8080_set_hl(i8080* const c, uint16_t val) { 118 | c->h = val >> 8; 119 | c->l = val & 0xFF; 120 | } 121 | 122 | static inline uint16_t i8080_get_bc(i8080* const c) { 123 | return (c->b << 8) | c->c; 124 | } 125 | 126 | static inline uint16_t i8080_get_de(i8080* const c) { 127 | return (c->d << 8) | c->e; 128 | } 129 | 130 | static inline uint16_t i8080_get_hl(i8080* const c) { 131 | return (c->h << 8) | c->l; 132 | } 133 | 134 | // stack helpers 135 | 136 | // pushes a value into the stack and updates the stack pointer 137 | static inline void i8080_push_stack(i8080* const c, uint16_t val) { 138 | c->sp -= 2; 139 | i8080_ww(c, c->sp, val); 140 | } 141 | 142 | // pops a value from the stack and updates the stack pointer 143 | static inline uint16_t i8080_pop_stack(i8080* const c) { 144 | uint16_t val = i8080_rw(c, c->sp); 145 | c->sp += 2; 146 | return val; 147 | } 148 | 149 | // opcodes 150 | 151 | // returns the parity of byte: 0 if number of 1 bits in `val` is odd, else 1 152 | static inline bool parity(uint8_t val) { 153 | uint8_t nb_one_bits = 0; 154 | for (int i = 0; i < 8; i++) { 155 | nb_one_bits += ((val >> i) & 1); 156 | } 157 | 158 | return (nb_one_bits & 1) == 0; 159 | } 160 | 161 | // returns if there was a carry between bit "bit_no" and "bit_no - 1" when 162 | // executing "a + b + cy" 163 | static inline bool carry(int bit_no, uint8_t a, uint8_t b, bool cy) { 164 | int16_t result = a + b + cy; 165 | int16_t carry = result ^ a ^ b; 166 | return carry & (1 << bit_no); 167 | } 168 | 169 | // adds a value (+ an optional carry flag) to a register 170 | static inline void i8080_add( 171 | i8080* const c, uint8_t* const reg, uint8_t val, bool cy) { 172 | uint8_t result = *reg + val + cy; 173 | c->cf = carry(8, *reg, val, cy); 174 | c->hf = carry(4, *reg, val, cy); 175 | SET_ZSP(c, result); 176 | *reg = result; 177 | } 178 | 179 | // substracts a byte (+ an optional carry flag) from a register 180 | // see https://stackoverflow.com/a/8037485 181 | static inline void i8080_sub( 182 | i8080* const c, uint8_t* const reg, uint8_t val, bool cy) { 183 | i8080_add(c, reg, ~val, !cy); 184 | c->cf = !c->cf; 185 | } 186 | 187 | // adds a word to HL 188 | static inline void i8080_dad(i8080* const c, uint16_t val) { 189 | c->cf = ((i8080_get_hl(c) + val) >> 16) & 1; 190 | i8080_set_hl(c, i8080_get_hl(c) + val); 191 | } 192 | 193 | // increments a byte 194 | static inline uint8_t i8080_inr(i8080* const c, uint8_t val) { 195 | uint8_t result = val + 1; 196 | c->hf = (result & 0xF) == 0; 197 | SET_ZSP(c, result); 198 | return result; 199 | } 200 | 201 | // decrements a byte 202 | static inline uint8_t i8080_dcr(i8080* const c, uint8_t val) { 203 | uint8_t result = val - 1; 204 | c->hf = !((result & 0xF) == 0xF); 205 | SET_ZSP(c, result); 206 | return result; 207 | } 208 | 209 | // executes a logic "and" between register A and a byte, then stores the 210 | // result in register A 211 | static inline void i8080_ana(i8080* const c, uint8_t val) { 212 | uint8_t result = c->a & val; 213 | c->cf = 0; 214 | c->hf = ((c->a | val) & 0x08) != 0; 215 | SET_ZSP(c, result); 216 | c->a = result; 217 | } 218 | 219 | // executes a logic "xor" between register A and a byte, then stores the 220 | // result in register A 221 | static inline void i8080_xra(i8080* const c, uint8_t val) { 222 | c->a ^= val; 223 | c->cf = 0; 224 | c->hf = 0; 225 | SET_ZSP(c, c->a); 226 | } 227 | 228 | // executes a logic "or" between register A and a byte, then stores the 229 | // result in register A 230 | static inline void i8080_ora(i8080* const c, uint8_t val) { 231 | c->a |= val; 232 | c->cf = 0; 233 | c->hf = 0; 234 | SET_ZSP(c, c->a); 235 | } 236 | 237 | // compares the register A to another byte 238 | static inline void i8080_cmp(i8080* const c, uint8_t val) { 239 | int16_t result = c->a - val; 240 | c->cf = result >> 8; 241 | c->hf = ~(c->a ^ result ^ val) & 0x10; 242 | SET_ZSP(c, result & 0xFF); 243 | } 244 | 245 | // sets the program counter to a given address 246 | static inline void i8080_jmp(i8080* const c, uint16_t addr) { 247 | c->pc = addr; 248 | } 249 | 250 | // jumps to next address pointed by the next word in memory if a condition 251 | // is met 252 | static inline void i8080_cond_jmp(i8080* const c, bool condition) { 253 | uint16_t addr = i8080_next_word(c); 254 | if (condition) { 255 | c->pc = addr; 256 | } 257 | } 258 | 259 | // pushes the current pc to the stack, then jumps to an address 260 | static inline void i8080_call(i8080* const c, uint16_t addr) { 261 | i8080_push_stack(c, c->pc); 262 | i8080_jmp(c, addr); 263 | } 264 | 265 | // calls to next word in memory if a condition is met 266 | static inline void i8080_cond_call(i8080* const c, bool condition) { 267 | uint16_t addr = i8080_next_word(c); 268 | if (condition) { 269 | i8080_call(c, addr); 270 | c->cyc += 6; 271 | } 272 | } 273 | 274 | // returns from subroutine 275 | static inline void i8080_ret(i8080* const c) { 276 | c->pc = i8080_pop_stack(c); 277 | } 278 | 279 | // returns from subroutine if a condition is met 280 | static inline void i8080_cond_ret(i8080* const c, bool condition) { 281 | if (condition) { 282 | i8080_ret(c); 283 | c->cyc += 6; 284 | } 285 | } 286 | 287 | // pushes register A and the flags into the stack 288 | static inline void i8080_push_psw(i8080* const c) { 289 | // note: bit 3 and 5 are always 0 290 | uint8_t psw = 0; 291 | psw |= c->sf << 7; 292 | psw |= c->zf << 6; 293 | psw |= c->hf << 4; 294 | psw |= c->pf << 2; 295 | psw |= 1 << 1; // bit 1 is always 1 296 | psw |= c->cf << 0; 297 | i8080_push_stack(c, c->a << 8 | psw); 298 | } 299 | 300 | // pops register A and the flags from the stack 301 | static inline void i8080_pop_psw(i8080* const c) { 302 | uint16_t af = i8080_pop_stack(c); 303 | c->a = af >> 8; 304 | uint8_t psw = af & 0xFF; 305 | 306 | c->sf = (psw >> 7) & 1; 307 | c->zf = (psw >> 6) & 1; 308 | c->hf = (psw >> 4) & 1; 309 | c->pf = (psw >> 2) & 1; 310 | c->cf = (psw >> 0) & 1; 311 | } 312 | 313 | // rotate register A left 314 | static inline void i8080_rlc(i8080* const c) { 315 | c->cf = c->a >> 7; 316 | c->a = (c->a << 1) | c->cf; 317 | } 318 | 319 | // rotate register A right 320 | static inline void i8080_rrc(i8080* const c) { 321 | c->cf = c->a & 1; 322 | c->a = (c->a >> 1) | (c->cf << 7); 323 | } 324 | 325 | // rotate register A left with the carry flag 326 | static inline void i8080_ral(i8080* const c) { 327 | bool cy = c->cf; 328 | c->cf = c->a >> 7; 329 | c->a = (c->a << 1) | cy; 330 | } 331 | 332 | // rotate register A right with the carry flag 333 | static inline void i8080_rar(i8080* const c) { 334 | bool cy = c->cf; 335 | c->cf = c->a & 1; 336 | c->a = (c->a >> 1) | (cy << 7); 337 | } 338 | 339 | // Decimal Adjust Accumulator: the eight-bit number in register A is adjusted 340 | // to form two four-bit binary-coded-decimal digits. 341 | // For example, if A=$2B and DAA is executed, A becomes $31. 342 | static inline void i8080_daa(i8080* const c) { 343 | bool cy = c->cf; 344 | uint8_t correction = 0; 345 | 346 | uint8_t lsb = c->a & 0x0F; 347 | uint8_t msb = c->a >> 4; 348 | 349 | if (c->hf || lsb > 9) { 350 | correction += 0x06; 351 | } 352 | 353 | if (c->cf || msb > 9 || (msb >= 9 && lsb > 9)) { 354 | correction += 0x60; 355 | cy = 1; 356 | } 357 | 358 | i8080_add(c, &c->a, correction, 0); 359 | c->cf = cy; 360 | } 361 | 362 | // switches the value of registers DE and HL 363 | static inline void i8080_xchg(i8080* const c) { 364 | uint16_t de = i8080_get_de(c); 365 | i8080_set_de(c, i8080_get_hl(c)); 366 | i8080_set_hl(c, de); 367 | } 368 | 369 | // switches the value of a word at (sp) and HL 370 | static inline void i8080_xthl(i8080* const c) { 371 | uint16_t val = i8080_rw(c, c->sp); 372 | i8080_ww(c, c->sp, i8080_get_hl(c)); 373 | i8080_set_hl(c, val); 374 | } 375 | 376 | // executes one opcode 377 | static inline void i8080_execute(i8080* const c, uint8_t opcode) { 378 | c->cyc += OPCODES_CYCLES[opcode]; 379 | 380 | // when DI is executed, interrupts won't be serviced 381 | // until the end of next instruction: 382 | if (c->interrupt_delay > 0) { 383 | c->interrupt_delay -= 1; 384 | } 385 | 386 | switch (opcode) { 387 | case 0x7F: c->a = c->a; break; // MOV A,A 388 | case 0x78: c->a = c->b; break; // MOV A,B 389 | case 0x79: c->a = c->c; break; // MOV A,C 390 | case 0x7A: c->a = c->d; break; // MOV A,D 391 | case 0x7B: c->a = c->e; break; // MOV A,E 392 | case 0x7C: c->a = c->h; break; // MOV A,H 393 | case 0x7D: c->a = c->l; break; // MOV A,L 394 | case 0x7E: c->a = i8080_rb(c, i8080_get_hl(c)); break; // MOV A,M 395 | 396 | case 0x0A: c->a = i8080_rb(c, i8080_get_bc(c)); break; // LDAX B 397 | case 0x1A: c->a = i8080_rb(c, i8080_get_de(c)); break; // LDAX D 398 | case 0x3A: c->a = i8080_rb(c, i8080_next_word(c)); break; // LDA word 399 | 400 | case 0x47: c->b = c->a; break; // MOV B,A 401 | case 0x40: c->b = c->b; break; // MOV B,B 402 | case 0x41: c->b = c->c; break; // MOV B,C 403 | case 0x42: c->b = c->d; break; // MOV B,D 404 | case 0x43: c->b = c->e; break; // MOV B,E 405 | case 0x44: c->b = c->h; break; // MOV B,H 406 | case 0x45: c->b = c->l; break; // MOV B,L 407 | case 0x46: c->b = i8080_rb(c, i8080_get_hl(c)); break; // MOV B,M 408 | 409 | case 0x4F: c->c = c->a; break; // MOV C,A 410 | case 0x48: c->c = c->b; break; // MOV C,B 411 | case 0x49: c->c = c->c; break; // MOV C,C 412 | case 0x4A: c->c = c->d; break; // MOV C,D 413 | case 0x4B: c->c = c->e; break; // MOV C,E 414 | case 0x4C: c->c = c->h; break; // MOV C,H 415 | case 0x4D: c->c = c->l; break; // MOV C,L 416 | case 0x4E: c->c = i8080_rb(c, i8080_get_hl(c)); break; // MOV C,M 417 | 418 | case 0x57: c->d = c->a; break; // MOV D,A 419 | case 0x50: c->d = c->b; break; // MOV D,B 420 | case 0x51: c->d = c->c; break; // MOV D,C 421 | case 0x52: c->d = c->d; break; // MOV D,D 422 | case 0x53: c->d = c->e; break; // MOV D,E 423 | case 0x54: c->d = c->h; break; // MOV D,H 424 | case 0x55: c->d = c->l; break; // MOV D,L 425 | case 0x56: c->d = i8080_rb(c, i8080_get_hl(c)); break; // MOV D,M 426 | 427 | case 0x5F: c->e = c->a; break; // MOV E,A 428 | case 0x58: c->e = c->b; break; // MOV E,B 429 | case 0x59: c->e = c->c; break; // MOV E,C 430 | case 0x5A: c->e = c->d; break; // MOV E,D 431 | case 0x5B: c->e = c->e; break; // MOV E,E 432 | case 0x5C: c->e = c->h; break; // MOV E,H 433 | case 0x5D: c->e = c->l; break; // MOV E,L 434 | case 0x5E: c->e = i8080_rb(c, i8080_get_hl(c)); break; // MOV E,M 435 | 436 | case 0x67: c->h = c->a; break; // MOV H,A 437 | case 0x60: c->h = c->b; break; // MOV H,B 438 | case 0x61: c->h = c->c; break; // MOV H,C 439 | case 0x62: c->h = c->d; break; // MOV H,D 440 | case 0x63: c->h = c->e; break; // MOV H,E 441 | case 0x64: c->h = c->h; break; // MOV H,H 442 | case 0x65: c->h = c->l; break; // MOV H,L 443 | case 0x66: c->h = i8080_rb(c, i8080_get_hl(c)); break; // MOV H,M 444 | 445 | case 0x6F: c->l = c->a; break; // MOV L,A 446 | case 0x68: c->l = c->b; break; // MOV L,B 447 | case 0x69: c->l = c->c; break; // MOV L,C 448 | case 0x6A: c->l = c->d; break; // MOV L,D 449 | case 0x6B: c->l = c->e; break; // MOV L,E 450 | case 0x6C: c->l = c->h; break; // MOV L,H 451 | case 0x6D: c->l = c->l; break; // MOV L,L 452 | case 0x6E: c->l = i8080_rb(c, i8080_get_hl(c)); break; // MOV L,M 453 | 454 | case 0x77: i8080_wb(c, i8080_get_hl(c), c->a); break; // MOV M,A 455 | case 0x70: i8080_wb(c, i8080_get_hl(c), c->b); break; // MOV M,B 456 | case 0x71: i8080_wb(c, i8080_get_hl(c), c->c); break; // MOV M,C 457 | case 0x72: i8080_wb(c, i8080_get_hl(c), c->d); break; // MOV M,D 458 | case 0x73: i8080_wb(c, i8080_get_hl(c), c->e); break; // MOV M,E 459 | case 0x74: i8080_wb(c, i8080_get_hl(c), c->h); break; // MOV M,H 460 | case 0x75: i8080_wb(c, i8080_get_hl(c), c->l); break; // MOV M,L 461 | 462 | case 0x3E: c->a = i8080_next_byte(c); break; // MVI A,byte 463 | case 0x06: c->b = i8080_next_byte(c); break; // MVI B,byte 464 | case 0x0E: c->c = i8080_next_byte(c); break; // MVI C,byte 465 | case 0x16: c->d = i8080_next_byte(c); break; // MVI D,byte 466 | case 0x1E: c->e = i8080_next_byte(c); break; // MVI E,byte 467 | case 0x26: c->h = i8080_next_byte(c); break; // MVI H,byte 468 | case 0x2E: c->l = i8080_next_byte(c); break; // MVI L,byte 469 | case 0x36: 470 | i8080_wb(c, i8080_get_hl(c), i8080_next_byte(c)); 471 | break; // MVI M,byte 472 | 473 | case 0x02: i8080_wb(c, i8080_get_bc(c), c->a); break; // STAX B 474 | case 0x12: i8080_wb(c, i8080_get_de(c), c->a); break; // STAX D 475 | case 0x32: i8080_wb(c, i8080_next_word(c), c->a); break; // STA word 476 | 477 | case 0x01: i8080_set_bc(c, i8080_next_word(c)); break; // LXI B,word 478 | case 0x11: i8080_set_de(c, i8080_next_word(c)); break; // LXI D,word 479 | case 0x21: i8080_set_hl(c, i8080_next_word(c)); break; // LXI H,word 480 | case 0x31: c->sp = i8080_next_word(c); break; // LXI SP,word 481 | case 0x2A: i8080_set_hl(c, i8080_rw(c, i8080_next_word(c))); break; // LHLD 482 | case 0x22: i8080_ww(c, i8080_next_word(c), i8080_get_hl(c)); break; // SHLD 483 | case 0xF9: c->sp = i8080_get_hl(c); break; // SPHL 484 | 485 | case 0xEB: i8080_xchg(c); break; // XCHG 486 | case 0xE3: i8080_xthl(c); break; // XTHL 487 | 488 | case 0x87: i8080_add(c, &c->a, c->a, 0); break; // ADD A 489 | case 0x80: i8080_add(c, &c->a, c->b, 0); break; // ADD B 490 | case 0x81: i8080_add(c, &c->a, c->c, 0); break; // ADD C 491 | case 0x82: i8080_add(c, &c->a, c->d, 0); break; // ADD D 492 | case 0x83: i8080_add(c, &c->a, c->e, 0); break; // ADD E 493 | case 0x84: i8080_add(c, &c->a, c->h, 0); break; // ADD H 494 | case 0x85: i8080_add(c, &c->a, c->l, 0); break; // ADD L 495 | case 0x86: 496 | i8080_add(c, &c->a, i8080_rb(c, i8080_get_hl(c)), 0); 497 | break; // ADD M 498 | case 0xC6: i8080_add(c, &c->a, i8080_next_byte(c), 0); break; // ADI byte 499 | 500 | case 0x8F: i8080_add(c, &c->a, c->a, c->cf); break; // ADC A 501 | case 0x88: i8080_add(c, &c->a, c->b, c->cf); break; // ADC B 502 | case 0x89: i8080_add(c, &c->a, c->c, c->cf); break; // ADC C 503 | case 0x8A: i8080_add(c, &c->a, c->d, c->cf); break; // ADC D 504 | case 0x8B: i8080_add(c, &c->a, c->e, c->cf); break; // ADC E 505 | case 0x8C: i8080_add(c, &c->a, c->h, c->cf); break; // ADC H 506 | case 0x8D: i8080_add(c, &c->a, c->l, c->cf); break; // ADC L 507 | case 0x8E: 508 | i8080_add(c, &c->a, i8080_rb(c, i8080_get_hl(c)), c->cf); 509 | break; // ADC M 510 | case 0xCE: i8080_add(c, &c->a, i8080_next_byte(c), c->cf); break; // ACI byte 511 | 512 | case 0x97: i8080_sub(c, &c->a, c->a, 0); break; // SUB A 513 | case 0x90: i8080_sub(c, &c->a, c->b, 0); break; // SUB B 514 | case 0x91: i8080_sub(c, &c->a, c->c, 0); break; // SUB C 515 | case 0x92: i8080_sub(c, &c->a, c->d, 0); break; // SUB D 516 | case 0x93: i8080_sub(c, &c->a, c->e, 0); break; // SUB E 517 | case 0x94: i8080_sub(c, &c->a, c->h, 0); break; // SUB H 518 | case 0x95: i8080_sub(c, &c->a, c->l, 0); break; // SUB L 519 | case 0x96: 520 | i8080_sub(c, &c->a, i8080_rb(c, i8080_get_hl(c)), 0); 521 | break; // SUB M 522 | case 0xD6: i8080_sub(c, &c->a, i8080_next_byte(c), 0); break; // SUI byte 523 | 524 | case 0x9F: i8080_sub(c, &c->a, c->a, c->cf); break; // SBB A 525 | case 0x98: i8080_sub(c, &c->a, c->b, c->cf); break; // SBB B 526 | case 0x99: i8080_sub(c, &c->a, c->c, c->cf); break; // SBB C 527 | case 0x9A: i8080_sub(c, &c->a, c->d, c->cf); break; // SBB D 528 | case 0x9B: i8080_sub(c, &c->a, c->e, c->cf); break; // SBB E 529 | case 0x9C: i8080_sub(c, &c->a, c->h, c->cf); break; // SBB H 530 | case 0x9D: i8080_sub(c, &c->a, c->l, c->cf); break; // SBB L 531 | case 0x9E: 532 | i8080_sub(c, &c->a, i8080_rb(c, i8080_get_hl(c)), c->cf); 533 | break; // SBB M 534 | case 0xDE: i8080_sub(c, &c->a, i8080_next_byte(c), c->cf); break; // SBI byte 535 | 536 | case 0x09: i8080_dad(c, i8080_get_bc(c)); break; // DAD B 537 | case 0x19: i8080_dad(c, i8080_get_de(c)); break; // DAD D 538 | case 0x29: i8080_dad(c, i8080_get_hl(c)); break; // DAD H 539 | case 0x39: i8080_dad(c, c->sp); break; // DAD SP 540 | 541 | case 0xF3: c->iff = 0; break; // DI 542 | case 0xFB: 543 | c->iff = 1; 544 | c->interrupt_delay = 1; 545 | break; // EI 546 | case 0x00: break; // NOP 547 | case 0x76: c->halted = 1; break; // HLT 548 | 549 | case 0x3C: c->a = i8080_inr(c, c->a); break; // INR A 550 | case 0x04: c->b = i8080_inr(c, c->b); break; // INR B 551 | case 0x0C: c->c = i8080_inr(c, c->c); break; // INR C 552 | case 0x14: c->d = i8080_inr(c, c->d); break; // INR D 553 | case 0x1C: c->e = i8080_inr(c, c->e); break; // INR E 554 | case 0x24: c->h = i8080_inr(c, c->h); break; // INR H 555 | case 0x2C: c->l = i8080_inr(c, c->l); break; // INR L 556 | case 0x34: 557 | i8080_wb(c, i8080_get_hl(c), i8080_inr(c, i8080_rb(c, i8080_get_hl(c)))); 558 | break; // INR M 559 | 560 | case 0x3D: c->a = i8080_dcr(c, c->a); break; // DCR A 561 | case 0x05: c->b = i8080_dcr(c, c->b); break; // DCR B 562 | case 0x0D: c->c = i8080_dcr(c, c->c); break; // DCR C 563 | case 0x15: c->d = i8080_dcr(c, c->d); break; // DCR D 564 | case 0x1D: c->e = i8080_dcr(c, c->e); break; // DCR E 565 | case 0x25: c->h = i8080_dcr(c, c->h); break; // DCR H 566 | case 0x2D: c->l = i8080_dcr(c, c->l); break; // DCR L 567 | case 0x35: 568 | i8080_wb(c, i8080_get_hl(c), i8080_dcr(c, i8080_rb(c, i8080_get_hl(c)))); 569 | break; // DCR M 570 | 571 | case 0x03: i8080_set_bc(c, i8080_get_bc(c) + 1); break; // INX B 572 | case 0x13: i8080_set_de(c, i8080_get_de(c) + 1); break; // INX D 573 | case 0x23: i8080_set_hl(c, i8080_get_hl(c) + 1); break; // INX H 574 | case 0x33: c->sp += 1; break; // INX SP 575 | 576 | case 0x0B: i8080_set_bc(c, i8080_get_bc(c) - 1); break; // DCX B 577 | case 0x1B: i8080_set_de(c, i8080_get_de(c) - 1); break; // DCX D 578 | case 0x2B: i8080_set_hl(c, i8080_get_hl(c) - 1); break; // DCX H 579 | case 0x3B: c->sp -= 1; break; // DCX SP 580 | 581 | case 0x27: i8080_daa(c); break; // DAA 582 | case 0x2F: c->a = ~c->a; break; // CMA 583 | case 0x37: c->cf = 1; break; // STC 584 | case 0x3F: c->cf = !c->cf; break; // CMC 585 | 586 | case 0x07: i8080_rlc(c); break; // RLC (rotate left) 587 | case 0x0F: i8080_rrc(c); break; // RRC (rotate right) 588 | case 0x17: i8080_ral(c); break; // RAL 589 | case 0x1F: i8080_rar(c); break; // RAR 590 | 591 | case 0xA7: i8080_ana(c, c->a); break; // ANA A 592 | case 0xA0: i8080_ana(c, c->b); break; // ANA B 593 | case 0xA1: i8080_ana(c, c->c); break; // ANA C 594 | case 0xA2: i8080_ana(c, c->d); break; // ANA D 595 | case 0xA3: i8080_ana(c, c->e); break; // ANA E 596 | case 0xA4: i8080_ana(c, c->h); break; // ANA H 597 | case 0xA5: i8080_ana(c, c->l); break; // ANA L 598 | case 0xA6: i8080_ana(c, i8080_rb(c, i8080_get_hl(c))); break; // ANA M 599 | case 0xE6: i8080_ana(c, i8080_next_byte(c)); break; // ANI byte 600 | 601 | case 0xAF: i8080_xra(c, c->a); break; // XRA A 602 | case 0xA8: i8080_xra(c, c->b); break; // XRA B 603 | case 0xA9: i8080_xra(c, c->c); break; // XRA C 604 | case 0xAA: i8080_xra(c, c->d); break; // XRA D 605 | case 0xAB: i8080_xra(c, c->e); break; // XRA E 606 | case 0xAC: i8080_xra(c, c->h); break; // XRA H 607 | case 0xAD: i8080_xra(c, c->l); break; // XRA L 608 | case 0xAE: i8080_xra(c, i8080_rb(c, i8080_get_hl(c))); break; // XRA M 609 | case 0xEE: i8080_xra(c, i8080_next_byte(c)); break; // XRI byte 610 | 611 | case 0xB7: i8080_ora(c, c->a); break; // ORA A 612 | case 0xB0: i8080_ora(c, c->b); break; // ORA B 613 | case 0xB1: i8080_ora(c, c->c); break; // ORA C 614 | case 0xB2: i8080_ora(c, c->d); break; // ORA D 615 | case 0xB3: i8080_ora(c, c->e); break; // ORA E 616 | case 0xB4: i8080_ora(c, c->h); break; // ORA H 617 | case 0xB5: i8080_ora(c, c->l); break; // ORA L 618 | case 0xB6: i8080_ora(c, i8080_rb(c, i8080_get_hl(c))); break; // ORA M 619 | case 0xF6: i8080_ora(c, i8080_next_byte(c)); break; // ORI byte 620 | 621 | case 0xBF: i8080_cmp(c, c->a); break; // CMP A 622 | case 0xB8: i8080_cmp(c, c->b); break; // CMP B 623 | case 0xB9: i8080_cmp(c, c->c); break; // CMP C 624 | case 0xBA: i8080_cmp(c, c->d); break; // CMP D 625 | case 0xBB: i8080_cmp(c, c->e); break; // CMP E 626 | case 0xBC: i8080_cmp(c, c->h); break; // CMP H 627 | case 0xBD: i8080_cmp(c, c->l); break; // CMP L 628 | case 0xBE: i8080_cmp(c, i8080_rb(c, i8080_get_hl(c))); break; // CMP M 629 | case 0xFE: i8080_cmp(c, i8080_next_byte(c)); break; // CPI byte 630 | 631 | case 0xC3: i8080_jmp(c, i8080_next_word(c)); break; // JMP 632 | case 0xC2: i8080_cond_jmp(c, c->zf == 0); break; // JNZ 633 | case 0xCA: i8080_cond_jmp(c, c->zf == 1); break; // JZ 634 | case 0xD2: i8080_cond_jmp(c, c->cf == 0); break; // JNC 635 | case 0xDA: i8080_cond_jmp(c, c->cf == 1); break; // JC 636 | case 0xE2: i8080_cond_jmp(c, c->pf == 0); break; // JPO 637 | case 0xEA: i8080_cond_jmp(c, c->pf == 1); break; // JPE 638 | case 0xF2: i8080_cond_jmp(c, c->sf == 0); break; // JP 639 | case 0xFA: i8080_cond_jmp(c, c->sf == 1); break; // JM 640 | 641 | case 0xE9: c->pc = i8080_get_hl(c); break; // PCHL 642 | case 0xCD: i8080_call(c, i8080_next_word(c)); break; // CALL 643 | 644 | case 0xC4: i8080_cond_call(c, c->zf == 0); break; // CNZ 645 | case 0xCC: i8080_cond_call(c, c->zf == 1); break; // CZ 646 | case 0xD4: i8080_cond_call(c, c->cf == 0); break; // CNC 647 | case 0xDC: i8080_cond_call(c, c->cf == 1); break; // CC 648 | case 0xE4: i8080_cond_call(c, c->pf == 0); break; // CPO 649 | case 0xEC: i8080_cond_call(c, c->pf == 1); break; // CPE 650 | case 0xF4: i8080_cond_call(c, c->sf == 0); break; // CP 651 | case 0xFC: i8080_cond_call(c, c->sf == 1); break; // CM 652 | 653 | case 0xC9: i8080_ret(c); break; // RET 654 | case 0xC0: i8080_cond_ret(c, c->zf == 0); break; // RNZ 655 | case 0xC8: i8080_cond_ret(c, c->zf == 1); break; // RZ 656 | case 0xD0: i8080_cond_ret(c, c->cf == 0); break; // RNC 657 | case 0xD8: i8080_cond_ret(c, c->cf == 1); break; // RC 658 | case 0xE0: i8080_cond_ret(c, c->pf == 0); break; // RPO 659 | case 0xE8: i8080_cond_ret(c, c->pf == 1); break; // RPE 660 | case 0xF0: i8080_cond_ret(c, c->sf == 0); break; // RP 661 | case 0xF8: i8080_cond_ret(c, c->sf == 1); break; // RM 662 | 663 | case 0xC7: i8080_call(c, 0x00); break; // RST 0 664 | case 0xCF: i8080_call(c, 0x08); break; // RST 1 665 | case 0xD7: i8080_call(c, 0x10); break; // RST 2 666 | case 0xDF: i8080_call(c, 0x18); break; // RST 3 667 | case 0xE7: i8080_call(c, 0x20); break; // RST 4 668 | case 0xEF: i8080_call(c, 0x28); break; // RST 5 669 | case 0xF7: i8080_call(c, 0x30); break; // RST 6 670 | case 0xFF: i8080_call(c, 0x38); break; // RST 7 671 | 672 | case 0xC5: i8080_push_stack(c, i8080_get_bc(c)); break; // PUSH B 673 | case 0xD5: i8080_push_stack(c, i8080_get_de(c)); break; // PUSH D 674 | case 0xE5: i8080_push_stack(c, i8080_get_hl(c)); break; // PUSH H 675 | case 0xF5: i8080_push_psw(c); break; // PUSH PSW 676 | case 0xC1: i8080_set_bc(c, i8080_pop_stack(c)); break; // POP B 677 | case 0xD1: i8080_set_de(c, i8080_pop_stack(c)); break; // POP D 678 | case 0xE1: i8080_set_hl(c, i8080_pop_stack(c)); break; // POP H 679 | case 0xF1: i8080_pop_psw(c); break; // POP PSW 680 | 681 | case 0xDB: c->a = c->port_in(c->userdata, i8080_next_byte(c)); break; // IN 682 | case 0xD3: c->port_out(c->userdata, i8080_next_byte(c), c->a); break; // OUT 683 | 684 | case 0x08: 685 | case 0x10: 686 | case 0x18: 687 | case 0x20: 688 | case 0x28: 689 | case 0x30: 690 | case 0x38: break; // undocumented NOPs 691 | 692 | case 0xD9: i8080_ret(c); break; // undocumented RET 693 | 694 | case 0xDD: 695 | case 0xED: 696 | case 0xFD: i8080_call(c, i8080_next_word(c)); break; // undocumented CALLs 697 | 698 | case 0xCB: i8080_jmp(c, i8080_next_word(c)); break; // undocumented JMP 699 | } 700 | } 701 | 702 | // initialises the emulator with default values 703 | void i8080_init(i8080* const c) { 704 | c->read_byte = NULL; 705 | c->write_byte = NULL; 706 | c->port_in = NULL; 707 | c->port_out = NULL; 708 | c->userdata = NULL; 709 | 710 | c->cyc = 0; 711 | 712 | c->pc = 0; 713 | c->sp = 0; 714 | 715 | c->a = 0; 716 | c->b = 0; 717 | c->c = 0; 718 | c->d = 0; 719 | c->e = 0; 720 | c->h = 0; 721 | c->l = 0; 722 | 723 | c->sf = 0; 724 | c->zf = 0; 725 | c->hf = 0; 726 | c->pf = 0; 727 | c->cf = 0; 728 | c->iff = 0; 729 | 730 | c->halted = 0; 731 | c->interrupt_pending = 0; 732 | c->interrupt_vector = 0; 733 | c->interrupt_delay = 0; 734 | } 735 | 736 | // executes one instruction 737 | void i8080_step(i8080* const c) { 738 | // interrupt processing: if an interrupt is pending and IFF is set, 739 | // we execute the interrupt vector passed by the user. 740 | if (c->interrupt_pending && c->iff && c->interrupt_delay == 0) { 741 | c->interrupt_pending = 0; 742 | c->iff = 0; 743 | c->halted = 0; 744 | 745 | i8080_execute(c, c->interrupt_vector); 746 | } else if (!c->halted) { 747 | i8080_execute(c, i8080_next_byte(c)); 748 | } 749 | } 750 | 751 | // asks for an interrupt to be serviced 752 | void i8080_interrupt(i8080* const c, uint8_t opcode) { 753 | c->interrupt_pending = 1; 754 | c->interrupt_vector = opcode; 755 | } 756 | 757 | // outputs a debug trace of the emulator state to the standard output, 758 | // including registers and flags 759 | void i8080_debug_output(i8080* const c, bool print_disassembly) { 760 | uint8_t f = 0; 761 | f |= c->sf << 7; 762 | f |= c->zf << 6; 763 | f |= c->hf << 4; 764 | f |= c->pf << 2; 765 | f |= 1 << 1; // bit 1 is always 1 766 | f |= c->cf << 0; 767 | 768 | printf("PC: %04X, AF: %04X, BC: %04X, DE: %04X, HL: %04X, SP: %04X, CYC: %lu", 769 | c->pc, c->a << 8 | f, i8080_get_bc(c), i8080_get_de(c), i8080_get_hl(c), 770 | c->sp, c->cyc); 771 | 772 | printf("\t(%02X %02X %02X %02X)", i8080_rb(c, c->pc), i8080_rb(c, c->pc + 1), 773 | i8080_rb(c, c->pc + 2), i8080_rb(c, c->pc + 3)); 774 | 775 | if (print_disassembly) { 776 | printf(" - %s", DISASSEMBLE_TABLE[i8080_rb(c, c->pc)]); 777 | } 778 | 779 | printf("\n"); 780 | } 781 | 782 | #undef SET_ZSP 783 | -------------------------------------------------------------------------------- /cpu_tests/8080EXER.MAC: -------------------------------------------------------------------------------- 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 | ;****************************************************************************** 21 | ; 22 | ; Modified to exercise an 8080 by Ian Bartholomew, February 2009 23 | ; 24 | ; I have made the following changes - 25 | ; 26 | ; Converted all mnemonics to 8080 and rewritten any Z80 code used 27 | ; in the original exerciser. Changes are tagged with a #idb in the 28 | ; source code listing. 29 | ; 30 | ; Removed any test descriptors that are not used. 31 | ; 32 | ; Changed the macro definitions to work in M80 33 | ; 34 | ; The machine state snapshot has been changed to remove the IX/IY registers. 35 | ; They have been replaced by two more copies of HL to obviate the need 36 | ; for major changes in the exerciser code. 37 | ; 38 | ; Changed flag mask in all tests to 0ffh to reflect that the 8080, unlike the 8085 39 | ; and Z80, does define the unused bits in the flag register - [S Z 0 AC 0 P 1 C] 40 | ; 41 | ;****************************************************************************** 42 | 43 | .8080 44 | aseg 45 | org 100h 46 | 47 | begin: jmp start 48 | 49 | ; machine state before test (needs to be at predictably constant address) 50 | msbt: ds 14 51 | spbt: ds 2 52 | 53 | ; For the purposes of this test program, the machine state consists of: 54 | ; a 2 byte memory operand, followed by 55 | ; the registers iy,ix,hl,de,bc,af,sp 56 | ; for a total of 16 bytes. 57 | 58 | ; The program tests instructions (or groups of similar instructions) 59 | ; by cycling through a sequence of machine states, executing the test 60 | ; instruction for each one and running a 32-bit crc over the resulting 61 | ; machine states. At the end of the sequence the crc is compared to 62 | ; an expected value that was found empirically on a real Z80. 63 | 64 | ; A test case is defined by a descriptor which consists of: 65 | ; a flag mask byte, 66 | ; the base case, 67 | ; the incement vector, 68 | ; the shift vector, 69 | ; the expected crc, 70 | ; a short descriptive message. 71 | ; 72 | ; The flag mask byte is used to prevent undefined flag bits from 73 | ; influencing the results. Documented flags are as per Mostek Z80 74 | ; Technical Manual. 75 | ; 76 | ; The next three parts of the descriptor are 20 byte vectors 77 | ; corresponding to a 4 byte instruction and a 16 byte machine state. 78 | ; The first part is the base case, which is the first test case of 79 | ; the sequence. This base is then modified according to the next 2 80 | ; vectors. Each 1 bit in the increment vector specifies a bit to be 81 | ; cycled in the form of a binary counter. For instance, if the byte 82 | ; corresponding to the accumulator is set to 0ffh in the increment 83 | ; vector, the test will be repeated for all 256 values of the 84 | ; accumulator. Note that 1 bits don't have to be contiguous. The 85 | ; number of test cases 'caused' by the increment vector is equal to 86 | ; 2^(number of 1 bits). The shift vector is similar, but specifies a 87 | ; set of bits in the test case that are to be successively inverted. 88 | ; Thus the shift vector 'causes' a number of test cases equal to the 89 | ; number of 1 bits in it. 90 | 91 | ; The total number of test cases is the product of those caused by the 92 | ; counter and shift vectors and can easily become unweildy. Each 93 | ; individual test case can take a few milliseconds to execute, due to 94 | ; the overhead of test setup and crc calculation, so test design is a 95 | ; compromise between coverage and execution time. 96 | 97 | ; This program is designed to detect differences between 98 | ; implementations and is not ideal for diagnosing the causes of any 99 | ; discrepancies. However, provided a reference implementation (or 100 | ; real system) is available, a failing test case can be isolated by 101 | ; hand using a binary search of the test space. 102 | 103 | 104 | start: lhld 6 105 | sphl 106 | lxi d,msg1 107 | mvi c,9 108 | call bdos 109 | 110 | lxi h,tests ; first test case 111 | loop: mov a,m ; end of list ? 112 | inx h 113 | ora m 114 | jz done 115 | dcx h 116 | call stt 117 | jmp loop 118 | 119 | done: lxi d,msg2 120 | mvi c,9 121 | call bdos 122 | jmp 0 ; warm boot 123 | 124 | tests: 125 | dw add16 126 | dw alu8i 127 | dw alu8r 128 | dw daa 129 | dw inca 130 | dw incb 131 | dw incbc 132 | dw incc 133 | dw incd 134 | dw incde 135 | dw ince 136 | dw inch 137 | dw inchl 138 | dw incl 139 | dw incm 140 | dw incsp 141 | dw ld162 142 | dw ld166 143 | dw ld16im 144 | dw ld8bd 145 | dw ld8im 146 | dw ld8rr 147 | dw lda 148 | dw rot8080 149 | dw stabd 150 | dw 0 151 | 152 | tstr macro insn,memop,hliy,hlix,hl,de,bc,flags,acc,sp 153 | local lab 154 | lab: db insn 155 | ds lab+4-$,0 156 | dw memop,hliy,hlix,hl,de,bc 157 | db flags 158 | db acc 159 | dw sp 160 | if $-lab ne 20 161 | error 'missing parameter' 162 | endif 163 | endm 164 | 165 | tmsg macro m 166 | local lab 167 | lab: db m 168 | if $ ge lab+30 169 | error 'message too long' 170 | else 171 | ds lab+30-$,'.' 172 | endif 173 | db '$' 174 | endm 175 | 176 | ; add hl, (19,456 cycles) 177 | add16: db 0ffh ; flag mask 178 | tstr 9,0c4a5h,0c4c7h,0d226h,0a050h,058eah,08566h,0c6h,0deh,09bc9h 179 | tstr 030h,0,0,0,0f821h,0,0,0,0,0 ; (512 cycles) 180 | tstr 0,0,0,0,-1,-1,-1,0d7h,0,-1 ; (38 cycles) 181 | db 014h, 047h, 04Bh, 0A6h ; expected crc 182 | tmsg 'dad ' 183 | 184 | ; aluop a,nn (28,672 cycles) 185 | alu8i: db 0ffh ; flag mask 186 | tstr 0c6h,09140h,07e3ch,07a67h,0df6dh,05b61h,00b29h,010h,066h,085b2h 187 | tstr 038h,0,0,0,0,0,0,0,-1,0 ; (2048 cycles) 188 | tstr <0,-1>,0,0,0,0,0,0,0d7h,0,0 ; (14 cycles) 189 | db 09Eh, 092h, 02Fh, 09Eh ; expected crc 190 | tmsg 'aluop nn' 191 | 192 | ; aluop a, (753,664 cycles) 193 | alu8r: db 0ffh ; flag mask 194 | tstr 080h,0c53eh,0573ah,04c4dh,msbt,0e309h,0a666h,0d0h,03bh,0adbbh 195 | tstr 03fh,0,0,0,0,0,0,0,-1,0 ; (16,384 cycles) 196 | tstr 0,0ffh,0,0,0,-1,-1,0d7h,0,0 ; (46 cycles) 197 | db 0CFh, 076h, 02Ch, 086h ; expected crc 198 | tmsg 'aluop ' 199 | 200 | ; 201 | daa: db 0ffh ; flag mask 202 | tstr 027h,02141h,009fah,01d60h,0a559h,08d5bh,09079h,004h,08eh,0299dh 203 | tstr 018h,0,0,0,0,0,0,0d7h,-1,0 ; (65,536 cycles) 204 | tstr 0,0,0,0,0,0,0,0,0,0 ; (1 cycle) 205 | db 0BBh, 03Fh, 003h, 00Ch ; expected crc 206 | tmsg '' 207 | 208 | ; a (3072 cycles) 209 | inca: db 0ffh ; flag mask 210 | tstr 03ch,04adfh,0d5d8h,0e598h,08a2bh,0a7b0h,0431bh,044h,05ah,0d030h 211 | tstr 001h,0,0,0,0,0,0,0,-1,0 ; (512 cycles) 212 | tstr 0,0,0,0,0,0,0,0d7h,0,0 ; (6 cycles) 213 | db 0ADh, 0B6h, 046h, 00Eh ; expected crc 214 | tmsg ' a' 215 | 216 | ; b (3072 cycles) 217 | incb: db 0ffh ; flag mask 218 | tstr 004h,0d623h,0432dh,07a61h,08180h,05a86h,01e85h,086h,058h,09bbbh 219 | tstr 001h,0,0,0,0,0,0ff00h,0,0,0 ; (512 cycles) 220 | tstr 0,0,0,0,0,0,0,0d7h,0,0 ; (6 cycles) 221 | db 083h, 0EDh, 013h, 045h ; expected crc 222 | tmsg ' b' 223 | 224 | ; bc (1536 cycles) 225 | incbc: db 0ffh ; flag mask 226 | tstr 003h,0cd97h,044abh,08dc9h,0e3e3h,011cch,0e8a4h,002h,049h,02a4dh 227 | tstr 008h,0,0,0,0,0,0f821h,0,0,0 ; (256 cycles) 228 | tstr 0,0,0,0,0,0,0,0d7h,0,0 ; (6 cycles) 229 | db 0F7h, 092h, 087h, 0CDh ; expected crc 230 | tmsg ' b' 231 | 232 | ; c (3072 cycles) 233 | incc: db 0ffh ; flag mask 234 | tstr 00ch,0d789h,00935h,0055bh,09f85h,08b27h,0d208h,095h,005h,00660h 235 | tstr 001h,0,0,0,0,0,0ffh,0,0,0 ; (512 cycles) 236 | tstr 0,0,0,0,0,0,0,0d7h,0,0 ; (6 cycles) 237 | db 0E5h, 0F6h, 072h, 01Bh ; expected crc 238 | tmsg ' c' 239 | 240 | ; d (3072 cycles) 241 | incd: db 0ffh ; flag mask 242 | tstr 014h,0a0eah,05fbah,065fbh,0981ch,038cch,0debch,043h,05ch,003bdh 243 | tstr 001h,0,0,0,0,0ff00h,0,0,0,0 ; (512 cycles) 244 | tstr 0,0,0,0,0,0,0,0d7h,0,0 ; (6 cycles) 245 | db 015h, 0B5h, 057h, 09Ah ; expected crc 246 | tmsg ' d' 247 | 248 | ; de (1536 cycles) 249 | incde: db 0ffh ; flag mask 250 | tstr 013h,0342eh,0131dh,028c9h,00acah,09967h,03a2eh,092h,0f6h,09d54h 251 | tstr 008h,0,0,0,0,0f821h,0,0,0,0 ; (256 cycles) 252 | tstr 0,0,0,0,0,0,0,0d7h,0,0 ; (6 cycles) 253 | db 07Fh, 04Eh, 025h, 001h ; expected crc 254 | tmsg ' d' 255 | 256 | ; e (3072 cycles) 257 | ince: db 0ffh ; flag mask 258 | tstr 01ch,0602fh,04c0dh,02402h,0e2f5h,0a0f4h,0a10ah,013h,032h,05925h 259 | tstr 001h,0,0,0,0,0ffh,0,0,0,0 ; (512 cycles) 260 | tstr 0,0,0,0,0,0,0,0d7h,0,0 ; (6 cycles) 261 | db 0CFh, 02Ah, 0B3h, 096h ; expected crc 262 | tmsg ' e' 263 | 264 | ; h (3072 cycles) 265 | inch: db 0ffh ; flag mask 266 | tstr 024h,01506h,0f2ebh,0e8ddh,0262bh,011a6h,0bc1ah,017h,006h,02818h 267 | tstr 001h,0,0,0,0ff00h,0,0,0,0,0 ; (512 cycles) 268 | tstr 0,0,0,0,0,0,0,0d7h,0,0 ; (6 cycles) 269 | db 012h, 0B2h, 095h, 02Ch ; expected crc 270 | tmsg ' h' 271 | 272 | ; hl (1536 cycles) 273 | inchl: db 0ffh ; flag mask 274 | tstr 023h,0c3f4h,007a5h,01b6dh,04f04h,0e2c2h,0822ah,057h,0e0h,0c3e1h 275 | tstr 008h,0,0,0,0f821h,0,0,0,0,0 ; (256 cycles) 276 | tstr 0,0,0,0,0,0,0,0d7h,0,0 ; (6 cycles) 277 | db 09Fh, 02Bh, 023h, 0C0h ; expected crc 278 | tmsg ' h' 279 | 280 | ; l (3072 cycles) 281 | incl: db 0ffh ; flag mask 282 | tstr 02ch,08031h,0a520h,04356h,0b409h,0f4c1h,0dfa2h,0d1h,03ch,03ea2h 283 | tstr 001h,0,0,0,0ffh,0,0,0,0,0 ; (512 cycles) 284 | tstr 0,0,0,0,0,0,0,0d7h,0,0 ; (6 cycles) 285 | db 0FFh, 057h, 0D3h, 056h ; expected crc 286 | tmsg ' l' 287 | 288 | ; (hl) (3072 cycles) 289 | incm: db 0ffh ; flag mask 290 | tstr 034h,0b856h,00c7ch,0e53eh,msbt,0877eh,0da58h,015h,05ch,01f37h 291 | tstr 001h,0ffh,0,0,0,0,0,0,0,0 ; (512 cycles) 292 | tstr 0,0,0,0,0,0,0,0d7h,0,0 ; (6 cycles) 293 | db 092h, 0E9h, 063h, 0BDh ; expected crc 294 | tmsg ' m' 295 | 296 | ; sp (1536 cycles) 297 | incsp: db 0ffh ; flag mask 298 | tstr 033h,0346fh,0d482h,0d169h,0deb6h,0a494h,0f476h,053h,002h,0855bh 299 | tstr 008h,0,0,0,0,0,0,0,0,0f821h ; (256 cycles) 300 | tstr 0,0,0,0,0,0,0,0d7h,0,0 ; (6 cycles) 301 | db 0D5h, 070h, 02Fh, 0ABh ; expected crc 302 | tmsg ' sp' 303 | 304 | ; ld hl,(nnnn) (16 cycles) 305 | ld162: db 0ffh ; flag mask 306 | tstr <02ah,low msbt,high msbt>,09863h,07830h,02077h,0b1feh,0b9fah,0abb8h,004h,006h,06015h 307 | tstr 0,0,0,0,0,0,0,0,0,0 ; (1 cycle) 308 | tstr 0,-1,0,0,0,0,0,0,0,0 ; (16 cycles) 309 | db 0A9h, 0C3h, 0D5h, 0CBh ; expected crc 310 | tmsg 'lhld nnnn' 311 | 312 | ; ld (nnnn),hl (16 cycles) 313 | ld166: db 0ffh ; flag mask 314 | tstr <022h,low msbt,high msbt>,0d003h,07772h,07f53h,03f72h,064eah,0e180h,010h,02dh,035e9h 315 | tstr 0,0,0,0,0,0,0,0,0,0 ; (1 cycle) 316 | tstr 0,0,0,0,-1,0,0,0,0,0 ; (16 cycles) 317 | db 0E8h, 086h, 04Fh, 026h ; expected crc 318 | tmsg 'shld nnnn' 319 | 320 | ; ld ,nnnn (64 cycles) 321 | ld16im: db 0ffh ; flag mask 322 | tstr 1,05c1ch,02d46h,08eb9h,06078h,074b1h,0b30eh,046h,0d1h,030cch 323 | tstr 030h,0,0,0,0,0,0,0,0,0 ; (4 cycles) 324 | tstr <0,0ffh,0ffh>,0,0,0,0,0,0,0,0,0 ; (16 cycles) 325 | db 0FCh, 0F4h, 06Eh, 012h ; expected crc 326 | tmsg 'lxi ,nnnn' 327 | 328 | ; ld a,<(bc),(de)> (44 cycles) 329 | ld8bd: db 0ffh ; flag mask 330 | tstr 00ah,0b3a8h,01d2ah,07f8eh,042ach,msbt,msbt,0c6h,0b1h,0ef8eh 331 | tstr 010h,0,0,0,0,0,0,0,0,0 ; (2 cycles) 332 | tstr 0,0ffh,0,0,0,0,0,0d7h,-1,0 ; (22 cycles) 333 | db 02Bh, 082h, 01Dh, 05Fh ; expected crc 334 | tmsg 'ldax ' 335 | 336 | ; ld ,nn (64 cycles) 337 | ld8im: db 0ffh ; flag mask 338 | tstr 6,0c407h,0f49dh,0d13dh,00339h,0de89h,07455h,053h,0c0h,05509h 339 | tstr 038h,0,0,0,0,0,0,0,0,0 ; (8 cycles) 340 | tstr 0,0,0,0,0,0,0,0,-1,0 ; (8 cycles) 341 | db 0EAh, 0A7h, 020h, 044h ; expected crc 342 | tmsg 'mvi ,nn' 343 | 344 | ; ld , (3456 cycles) 345 | ld8rr: db 0ffh ; flag mask 346 | tstr 040h,072a4h,0a024h,061ach,msbt,082c7h,0718fh,097h,08fh,0ef8eh 347 | tstr 03fh,0,0,0,0,0,0,0,0,0 ; (64 cycles) 348 | tstr 0,0ffh,0,0,0,-1,-1,0d7h,-1,0 ; (54 cycles) 349 | db 010h, 0B5h, 08Ch, 0EEh ; expected crc 350 | tmsg 'mov ,' 351 | 352 | ; ld a,(nnnn) / ld (nnnn),a (44 cycles) 353 | lda: db 0ffh ; flag mask 354 | tstr <032h,low msbt,high msbt>,0fd68h,0f4ech,044a0h,0b543h,00653h,0cdbah,0d2h,04fh,01fd8h 355 | tstr 008h,0,0,0,0,0,0,0,0,0 ; (2 cycle) 356 | tstr 0,0ffh,0,0,0,0,0,0d7h,-1,0 ; (22 cycles) 357 | db 0EDh, 057h, 0AFh, 072h ; expected crc 358 | tmsg 'sta nnnn / lda nnnn' 359 | 360 | ; (6144 cycles) 361 | rot8080: db 0ffh ; flag mask 362 | tstr 7,0cb92h,06d43h,00a90h,0c284h,00c53h,0f50eh,091h,0ebh,040fch 363 | tstr 018h,0,0,0,0,0,0,0,-1,0 ; (1024 cycles) 364 | tstr 0,0,0,0,0,0,0,0d7h,0,0 ; (6 cycles) 365 | db 0E0h, 0D8h, 092h, 035h ; expected crc 366 | tmsg '' 367 | 368 | ; ld (),a (96 cycles) 369 | stabd: db 0ffh ; flag mask 370 | tstr 2,00c3bh,0b592h,06cffh,0959eh,msbt,msbt+1,0c1h,021h,0bde7h 371 | tstr 018h,0,0,0,0,0,0,0,0,0 ; (4 cycles) 372 | tstr 0,-1,0,0,0,0,0,0,-1,0 ; (24 cycles) 373 | db 02Bh, 004h, 071h, 0E9h ; expected crc 374 | tmsg 'stax ' 375 | 376 | ; start test pointed to by (hl) 377 | stt: push h 378 | mov a,m ; get pointer to test 379 | inx h 380 | mov h,m 381 | mov l,a 382 | mov a,m ; flag mask 383 | sta flgmsk+1 384 | inx h 385 | push h 386 | lxi d,20 387 | dad d ; point to incmask 388 | lxi d,counter 389 | call initmask 390 | pop h 391 | push h 392 | lxi d,20+20 393 | dad d ; point to scanmask 394 | lxi d,shifter 395 | call initmask 396 | lxi h,shifter 397 | mvi m,1 ; first bit 398 | pop h 399 | push h 400 | lxi d,iut ; copy initial instruction under test 401 | lxi b,4 402 | 403 | ;#idb ldir replaced with following code 404 | ldir1: mov a,m 405 | stax d 406 | inx h 407 | inx d 408 | dcx b 409 | mov a,b 410 | ora c 411 | jnz ldir1 412 | ;#idb 413 | 414 | lxi d,msbt ; copy initial machine state 415 | lxi b,16 416 | 417 | ;#idb ldir replaced with following code 418 | ldir2: mov a,m 419 | stax d 420 | inx h 421 | inx d 422 | dcx b 423 | mov a,b 424 | ora c 425 | jnz ldir2 426 | ;#idb 427 | 428 | lxi d,20+20+4 ; skip incmask, scanmask and expcrc 429 | dad d 430 | xchg 431 | mvi c,9 432 | call bdos ; show test name 433 | call initcrc ; initialise crc 434 | ; test loop 435 | tlp: lda iut 436 | cpi 076h ; pragmatically avoid halt intructions 437 | jz tlp2 438 | ani 0dfh 439 | cpi 0ddh 440 | jnz tlp1 441 | lda iut+1 442 | cpi 076h 443 | tlp1: cnz test ; execute the test instruction 444 | tlp2: call count ; increment the counter 445 | cnz shift ; shift the scan bit 446 | pop h ; pointer to test case 447 | jz tlp3 ; done if shift returned NZ 448 | lxi d,20+20+20 449 | dad d ; point to expected crc 450 | call cmpcrc 451 | lxi d,okmsg 452 | jz tlpok 453 | lxi d,ermsg1 454 | mvi c,9 455 | call bdos 456 | call phex8 457 | lxi d,ermsg2 458 | mvi c,9 459 | call bdos 460 | lxi h,crcval 461 | call phex8 462 | lxi d,crlf 463 | tlpok: mvi c,9 464 | call bdos 465 | pop h 466 | inx h 467 | inx h 468 | ret 469 | 470 | tlp3: push h 471 | mvi a,1 ; initialise count and shift scanners 472 | sta cntbit 473 | sta shfbit 474 | lxi h,counter 475 | shld cntbyt 476 | lxi h,shifter 477 | shld shfbyt 478 | 479 | mvi b,4 ; bytes in iut field 480 | pop h ; pointer to test case 481 | push h 482 | lxi d,iut 483 | call setup ; setup iut 484 | mvi b,16 ; bytes in machine state 485 | lxi d,msbt 486 | call setup ; setup machine state 487 | jmp tlp 488 | 489 | ; setup a field of the test case 490 | ; b = number of bytes 491 | ; hl = pointer to base case 492 | ; de = destination 493 | setup: call subyte 494 | inx h 495 | dcr b 496 | jnz setup 497 | ret 498 | 499 | subyte: push b 500 | push d 501 | push h 502 | mov c,m ; get base byte 503 | lxi d,20 504 | dad d ; point to incmask 505 | mov a,m 506 | cpi 0 507 | jz subshf 508 | mvi b,8 ; 8 bits 509 | subclp: rrc 510 | push psw 511 | mvi a,0 512 | cc nxtcbit ; get next counter bit if mask bit was set 513 | xra c ; flip bit if counter bit was set 514 | rrc 515 | mov c,a 516 | pop psw 517 | dcr b 518 | jnz subclp 519 | mvi b,8 520 | subshf: lxi d,20 521 | dad d ; point to shift mask 522 | mov a,m 523 | cpi 0 524 | jz substr 525 | mvi b,8 ; 8 bits 526 | sbshf1: rrc 527 | push psw 528 | mvi a,0 529 | cc nxtsbit ; get next shifter bit if mask bit was set 530 | xra c ; flip bit if shifter bit was set 531 | rrc 532 | mov c,a 533 | pop psw 534 | dcr b 535 | jnz sbshf1 536 | substr: pop h 537 | pop d 538 | mov a,c 539 | stax d ; mangled byte to destination 540 | inx d 541 | pop b 542 | ret 543 | 544 | ; get next counter bit in low bit of a 545 | cntbit: ds 1 546 | cntbyt: ds 2 547 | 548 | nxtcbit: push b 549 | push h 550 | lhld cntbyt 551 | mov b,m 552 | lxi h,cntbit 553 | mov a,m 554 | mov c,a 555 | rlc 556 | mov m,a 557 | cpi 1 558 | jnz ncb1 559 | lhld cntbyt 560 | inx h 561 | shld cntbyt 562 | ncb1: mov a,b 563 | ana c 564 | pop h 565 | pop b 566 | rz 567 | mvi a,1 568 | ret 569 | 570 | ; get next shifter bit in low bit of a 571 | shfbit: ds 1 572 | shfbyt: ds 2 573 | 574 | nxtsbit: push b 575 | push h 576 | lhld shfbyt 577 | mov b,m 578 | lxi h,shfbit 579 | mov a,m 580 | mov c,a 581 | rlc 582 | mov m,a 583 | cpi 1 584 | jnz nsb1 585 | lhld shfbyt 586 | inx h 587 | shld shfbyt 588 | nsb1: mov a,b 589 | ana c 590 | pop h 591 | pop b 592 | rz 593 | mvi a,1 594 | ret 595 | 596 | 597 | ; clear memory at hl, bc bytes 598 | clrmem: push psw 599 | push b 600 | push d 601 | push h 602 | mvi m,0 603 | mov d,h 604 | mov e,l 605 | inx d 606 | dcx b 607 | 608 | ;#idb ldir replaced with following code 609 | ldir3: mov a,m 610 | stax d 611 | inx h 612 | inx d 613 | dcx b 614 | mov a,b 615 | ora c 616 | jnz ldir3 617 | ;#idb 618 | 619 | pop h 620 | pop d 621 | pop b 622 | pop psw 623 | ret 624 | 625 | ; initialise counter or shifter 626 | ; de = pointer to work area for counter or shifter 627 | ; hl = pointer to mask 628 | initmask: 629 | push d 630 | xchg 631 | lxi b,20+20 632 | call clrmem ; clear work area 633 | xchg 634 | mvi b,20 ; byte counter 635 | mvi c,1 ; first bit 636 | mvi d,0 ; bit counter 637 | imlp: mov e,m 638 | imlp1: mov a,e 639 | ana c 640 | jz imlp2 641 | inr d 642 | imlp2: mov a,c 643 | rlc 644 | mov c,a 645 | cpi 1 646 | jnz imlp1 647 | inx h 648 | dcr b 649 | jnz imlp 650 | ; got number of 1-bits in mask in reg d 651 | mov a,d 652 | ani 0f8h 653 | rrc 654 | rrc 655 | rrc ; divide by 8 (get byte offset) 656 | mov l,a 657 | mvi h,0 658 | mov a,d 659 | ani 7 ; bit offset 660 | inr a 661 | mov b,a 662 | mvi a,080h 663 | imlp3: rlc 664 | dcr b 665 | jnz imlp3 666 | pop d 667 | dad d 668 | lxi d,20 669 | dad d 670 | mov m,a 671 | ret 672 | 673 | ; multi-byte counter 674 | count: push b 675 | push d 676 | push h 677 | lxi h,counter ; 20 byte counter starts here 678 | lxi d,20 ; somewhere in here is the stop bit 679 | xchg 680 | dad d 681 | xchg 682 | cntlp: inr m 683 | mov a,m 684 | cpi 0 685 | jz cntlp1 ; overflow to next byte 686 | mov b,a 687 | ldax d 688 | ana b ; test for terminal value 689 | jz cntend 690 | mvi m,0 ; reset to zero 691 | cntend: pop b 692 | pop d 693 | pop h 694 | ret 695 | 696 | cntlp1: inx h 697 | inx d 698 | jmp cntlp 699 | 700 | 701 | ; multi-byte shifter 702 | shift: push b 703 | push d 704 | push h 705 | lxi h,shifter ; 20 byte shift register starts here 706 | lxi d,20 ; somewhere in here is the stop bit 707 | xchg 708 | dad d 709 | xchg 710 | shflp: mov a,m 711 | ora a 712 | jz shflp1 713 | mov b,a 714 | ldax d 715 | ana b 716 | jnz shlpe 717 | mov a,b 718 | rlc 719 | cpi 1 720 | jnz shflp2 721 | mvi m,0 722 | inx h 723 | inx d 724 | shflp2: mov m,a 725 | xra a ; set Z 726 | shlpe: pop h 727 | pop d 728 | pop b 729 | ret 730 | shflp1: inx h 731 | inx d 732 | jmp shflp 733 | 734 | counter: ds 2*20 735 | shifter: ds 2*20 736 | 737 | ; test harness 738 | test: push psw 739 | push b 740 | push d 741 | push h 742 | if 0 743 | lxi d,crlf 744 | mvi c,9 745 | call bdos 746 | lxi h,iut 747 | mvi b,4 748 | call hexstr 749 | mvi e,' ' 750 | mvi c,2 751 | call bdos 752 | mvi b,16 753 | lxi h,msbt 754 | call hexstr 755 | endif 756 | di ; disable interrupts 757 | 758 | ;#idb ld (spsav),sp replaced by following code 759 | ;#idb All registers and flages are immediately overwritten so 760 | ;#idb no need to preserve any state. 761 | lxi h,0 ; save stack pointer 762 | dad sp 763 | shld spsav 764 | ;#idb 765 | 766 | lxi sp,msbt+2 ; point to test-case machine state 767 | 768 | ;#idb pop iy 769 | ;#idb pop ix both replaced by following code 770 | ;#idb Just dummy out ix/iy with copies of hl 771 | pop h ; and load all regs 772 | pop h 773 | ;#idb 774 | 775 | pop h 776 | pop d 777 | pop b 778 | pop psw 779 | 780 | ;#idb ld sp,(spbt) replaced with the following code 781 | ;#idb HL is copied/restored before/after load so no state changed 782 | shld temp 783 | lhld spbt 784 | sphl 785 | lhld temp 786 | ;#idb 787 | 788 | iut: ds 4 ; max 4 byte instruction under test 789 | 790 | ;#idb ld (spat),sp replaced with the following code 791 | ;#idb Must be very careful to preserve registers and flag 792 | ;#idb state resulting from the test. The temptation is to use the 793 | ;#idb stack - but that doesn't work because of the way the app 794 | ;#idb uses SP as a quick way of pointing to memory. 795 | ;#idb Bit of a code smell, but I can't think of an easier way. 796 | shld temp 797 | lxi h,0 798 | jc temp1 ;jump on the state of the C flag set in the test 799 | 800 | dad sp ;this code will clear the C flag (0 + nnnn = nc) 801 | jmp temp2 ;C flag is same state as before 802 | 803 | temp1: dad sp ;this code will clear the C flag (0 + nnnn = nc) 804 | stc ;C flage needs re-setting to preserve state 805 | 806 | temp2: shld spat 807 | lhld temp 808 | ;#idb 809 | 810 | lxi sp,spat 811 | push psw ; save other registers 812 | push b 813 | push d 814 | push h 815 | 816 | ;#idb push ix 817 | ;#idb push iy both replaced by following code 818 | ;#idb Must match change made to pops made before test 819 | push h 820 | push h 821 | ;#idb 822 | 823 | ;#idb ld sp,(spsav) replaced with following code 824 | ;#idb No need to preserve state 825 | lhld spsav ; restore stack pointer 826 | sphl 827 | ;#idb 828 | 829 | ei ; enable interrupts 830 | lhld msbt ; copy memory operand 831 | shld msat 832 | lxi h,flgsat ; flags after test 833 | mov a,m 834 | flgmsk: ani 0ffh ; mask-out irrelevant bits (self-modified code!) 835 | mov m,a 836 | mvi b,16 ; total of 16 bytes of state 837 | lxi d,msat 838 | lxi h,crcval 839 | tcrc: ldax d 840 | inx d 841 | call updcrc ; accumulate crc of this test case 842 | dcr b 843 | jnz tcrc 844 | if 0 845 | mvi e,' ' 846 | mvi c,2 847 | call bdos 848 | lxi h,crcval 849 | call phex8 850 | lxi d,crlf 851 | mvi c,9 852 | call bdos 853 | lxi h,msat 854 | mvi b,16 855 | call hexstr 856 | lxi d,crlf 857 | mvi c,9 858 | call bdos 859 | endif 860 | pop h 861 | pop d 862 | pop b 863 | pop psw 864 | ret 865 | 866 | ;#idb Added to store HL state 867 | temp: ds 2 868 | ;#idb 869 | 870 | ; machine state after test 871 | msat: ds 14 ; memop,iy,ix,hl,de,bc,af 872 | spat: ds 2 ; stack pointer after test 873 | flgsat equ spat-2 ; flags 874 | 875 | spsav: ds 2 ; saved stack pointer 876 | 877 | ; display hex string (pointer in hl, byte count in b) 878 | hexstr: mov a,m 879 | call phex2 880 | inx h 881 | dcr b 882 | jnz hexstr 883 | ret 884 | 885 | ; display hex 886 | ; display the big-endian 32-bit value pointed to by hl 887 | phex8: push psw 888 | push b 889 | push h 890 | mvi b,4 891 | ph8lp: mov a,m 892 | call phex2 893 | inx h 894 | dcr b 895 | jnz ph8lp 896 | pop h 897 | pop b 898 | pop psw 899 | ret 900 | 901 | ; display byte in a 902 | phex2: push psw 903 | rrc 904 | rrc 905 | rrc 906 | rrc 907 | call phex1 908 | pop psw 909 | ; fall through 910 | 911 | ; display low nibble in a 912 | phex1: push psw 913 | push b 914 | push d 915 | push h 916 | ani 0fh 917 | cpi 10 918 | jc ph11 919 | adi 'a'-'9'-1 920 | ph11: adi '0' 921 | mov e,a 922 | mvi c,2 923 | call bdos 924 | pop h 925 | pop d 926 | pop b 927 | pop psw 928 | ret 929 | 930 | bdos: push psw 931 | push b 932 | push d 933 | push h 934 | call 5 935 | pop h 936 | pop d 937 | pop b 938 | pop psw 939 | ret 940 | 941 | msg1: db '8080 instruction exerciser',10,13,'$' 942 | msg2: db 'Tests complete$' 943 | okmsg: db ' OK',10,13,'$' 944 | ermsg1: db ' ERROR **** crc expected:$' 945 | ermsg2: db ' found:$' 946 | crlf: db 10,13,'$' 947 | 948 | ; compare crc 949 | ; hl points to value to compare to crcval 950 | cmpcrc: push b 951 | push d 952 | push h 953 | lxi d,crcval 954 | mvi b,4 955 | cclp: ldax d 956 | cmp m 957 | jnz cce 958 | inx h 959 | inx d 960 | dcr b 961 | jnz cclp 962 | cce: pop h 963 | pop d 964 | pop b 965 | ret 966 | 967 | ; 32-bit crc routine 968 | ; entry: a contains next byte, hl points to crc 969 | ; exit: crc updated 970 | updcrc: push psw 971 | push b 972 | push d 973 | push h 974 | push h 975 | lxi d,3 976 | dad d ; point to low byte of old crc 977 | xra m ; xor with new byte 978 | mov l,a 979 | mvi h,0 980 | dad h ; use result as index into table of 4 byte entries 981 | dad h 982 | xchg 983 | lxi h,crctab 984 | dad d ; point to selected entry in crctab 985 | xchg 986 | pop h 987 | lxi b,4 ; c = byte count, b = accumulator 988 | crclp: ldax d 989 | xra b 990 | mov b,m 991 | mov m,a 992 | inx d 993 | inx h 994 | dcr c 995 | jnz crclp 996 | if 0 997 | lxi h,crcval 998 | call phex8 999 | lxi d,crlf 1000 | mvi c,9 1001 | call bdos 1002 | endif 1003 | pop h 1004 | pop d 1005 | pop b 1006 | pop psw 1007 | ret 1008 | 1009 | initcrc:push psw 1010 | push b 1011 | push h 1012 | lxi h,crcval 1013 | mvi a,0ffh 1014 | mvi b,4 1015 | icrclp: mov m,a 1016 | inx h 1017 | dcr b 1018 | jnz icrclp 1019 | pop h 1020 | pop b 1021 | pop psw 1022 | ret 1023 | 1024 | crcval: ds 4 1025 | 1026 | crctab: db 000h,000h,000h,000h 1027 | db 077h,007h,030h,096h 1028 | db 0eeh,00eh,061h,02ch 1029 | db 099h,009h,051h,0bah 1030 | db 007h,06dh,0c4h,019h 1031 | db 070h,06ah,0f4h,08fh 1032 | db 0e9h,063h,0a5h,035h 1033 | db 09eh,064h,095h,0a3h 1034 | db 00eh,0dbh,088h,032h 1035 | db 079h,0dch,0b8h,0a4h 1036 | db 0e0h,0d5h,0e9h,01eh 1037 | db 097h,0d2h,0d9h,088h 1038 | db 009h,0b6h,04ch,02bh 1039 | db 07eh,0b1h,07ch,0bdh 1040 | db 0e7h,0b8h,02dh,007h 1041 | db 090h,0bfh,01dh,091h 1042 | db 01dh,0b7h,010h,064h 1043 | db 06ah,0b0h,020h,0f2h 1044 | db 0f3h,0b9h,071h,048h 1045 | db 084h,0beh,041h,0deh 1046 | db 01ah,0dah,0d4h,07dh 1047 | db 06dh,0ddh,0e4h,0ebh 1048 | db 0f4h,0d4h,0b5h,051h 1049 | db 083h,0d3h,085h,0c7h 1050 | db 013h,06ch,098h,056h 1051 | db 064h,06bh,0a8h,0c0h 1052 | db 0fdh,062h,0f9h,07ah 1053 | db 08ah,065h,0c9h,0ech 1054 | db 014h,001h,05ch,04fh 1055 | db 063h,006h,06ch,0d9h 1056 | db 0fah,00fh,03dh,063h 1057 | db 08dh,008h,00dh,0f5h 1058 | db 03bh,06eh,020h,0c8h 1059 | db 04ch,069h,010h,05eh 1060 | db 0d5h,060h,041h,0e4h 1061 | db 0a2h,067h,071h,072h 1062 | db 03ch,003h,0e4h,0d1h 1063 | db 04bh,004h,0d4h,047h 1064 | db 0d2h,00dh,085h,0fdh 1065 | db 0a5h,00ah,0b5h,06bh 1066 | db 035h,0b5h,0a8h,0fah 1067 | db 042h,0b2h,098h,06ch 1068 | db 0dbh,0bbh,0c9h,0d6h 1069 | db 0ach,0bch,0f9h,040h 1070 | db 032h,0d8h,06ch,0e3h 1071 | db 045h,0dfh,05ch,075h 1072 | db 0dch,0d6h,00dh,0cfh 1073 | db 0abh,0d1h,03dh,059h 1074 | db 026h,0d9h,030h,0ach 1075 | db 051h,0deh,000h,03ah 1076 | db 0c8h,0d7h,051h,080h 1077 | db 0bfh,0d0h,061h,016h 1078 | db 021h,0b4h,0f4h,0b5h 1079 | db 056h,0b3h,0c4h,023h 1080 | db 0cfh,0bah,095h,099h 1081 | db 0b8h,0bdh,0a5h,00fh 1082 | db 028h,002h,0b8h,09eh 1083 | db 05fh,005h,088h,008h 1084 | db 0c6h,00ch,0d9h,0b2h 1085 | db 0b1h,00bh,0e9h,024h 1086 | db 02fh,06fh,07ch,087h 1087 | db 058h,068h,04ch,011h 1088 | db 0c1h,061h,01dh,0abh 1089 | db 0b6h,066h,02dh,03dh 1090 | db 076h,0dch,041h,090h 1091 | db 001h,0dbh,071h,006h 1092 | db 098h,0d2h,020h,0bch 1093 | db 0efh,0d5h,010h,02ah 1094 | db 071h,0b1h,085h,089h 1095 | db 006h,0b6h,0b5h,01fh 1096 | db 09fh,0bfh,0e4h,0a5h 1097 | db 0e8h,0b8h,0d4h,033h 1098 | db 078h,007h,0c9h,0a2h 1099 | db 00fh,000h,0f9h,034h 1100 | db 096h,009h,0a8h,08eh 1101 | db 0e1h,00eh,098h,018h 1102 | db 07fh,06ah,00dh,0bbh 1103 | db 008h,06dh,03dh,02dh 1104 | db 091h,064h,06ch,097h 1105 | db 0e6h,063h,05ch,001h 1106 | db 06bh,06bh,051h,0f4h 1107 | db 01ch,06ch,061h,062h 1108 | db 085h,065h,030h,0d8h 1109 | db 0f2h,062h,000h,04eh 1110 | db 06ch,006h,095h,0edh 1111 | db 01bh,001h,0a5h,07bh 1112 | db 082h,008h,0f4h,0c1h 1113 | db 0f5h,00fh,0c4h,057h 1114 | db 065h,0b0h,0d9h,0c6h 1115 | db 012h,0b7h,0e9h,050h 1116 | db 08bh,0beh,0b8h,0eah 1117 | db 0fch,0b9h,088h,07ch 1118 | db 062h,0ddh,01dh,0dfh 1119 | db 015h,0dah,02dh,049h 1120 | db 08ch,0d3h,07ch,0f3h 1121 | db 0fbh,0d4h,04ch,065h 1122 | db 04dh,0b2h,061h,058h 1123 | db 03ah,0b5h,051h,0ceh 1124 | db 0a3h,0bch,000h,074h 1125 | db 0d4h,0bbh,030h,0e2h 1126 | db 04ah,0dfh,0a5h,041h 1127 | db 03dh,0d8h,095h,0d7h 1128 | db 0a4h,0d1h,0c4h,06dh 1129 | db 0d3h,0d6h,0f4h,0fbh 1130 | db 043h,069h,0e9h,06ah 1131 | db 034h,06eh,0d9h,0fch 1132 | db 0adh,067h,088h,046h 1133 | db 0dah,060h,0b8h,0d0h 1134 | db 044h,004h,02dh,073h 1135 | db 033h,003h,01dh,0e5h 1136 | db 0aah,00ah,04ch,05fh 1137 | db 0ddh,00dh,07ch,0c9h 1138 | db 050h,005h,071h,03ch 1139 | db 027h,002h,041h,0aah 1140 | db 0beh,00bh,010h,010h 1141 | db 0c9h,00ch,020h,086h 1142 | db 057h,068h,0b5h,025h 1143 | db 020h,06fh,085h,0b3h 1144 | db 0b9h,066h,0d4h,009h 1145 | db 0ceh,061h,0e4h,09fh 1146 | db 05eh,0deh,0f9h,00eh 1147 | db 029h,0d9h,0c9h,098h 1148 | db 0b0h,0d0h,098h,022h 1149 | db 0c7h,0d7h,0a8h,0b4h 1150 | db 059h,0b3h,03dh,017h 1151 | db 02eh,0b4h,00dh,081h 1152 | db 0b7h,0bdh,05ch,03bh 1153 | db 0c0h,0bah,06ch,0adh 1154 | db 0edh,0b8h,083h,020h 1155 | db 09ah,0bfh,0b3h,0b6h 1156 | db 003h,0b6h,0e2h,00ch 1157 | db 074h,0b1h,0d2h,09ah 1158 | db 0eah,0d5h,047h,039h 1159 | db 09dh,0d2h,077h,0afh 1160 | db 004h,0dbh,026h,015h 1161 | db 073h,0dch,016h,083h 1162 | db 0e3h,063h,00bh,012h 1163 | db 094h,064h,03bh,084h 1164 | db 00dh,06dh,06ah,03eh 1165 | db 07ah,06ah,05ah,0a8h 1166 | db 0e4h,00eh,0cfh,00bh 1167 | db 093h,009h,0ffh,09dh 1168 | db 00ah,000h,0aeh,027h 1169 | db 07dh,007h,09eh,0b1h 1170 | db 0f0h,00fh,093h,044h 1171 | db 087h,008h,0a3h,0d2h 1172 | db 01eh,001h,0f2h,068h 1173 | db 069h,006h,0c2h,0feh 1174 | db 0f7h,062h,057h,05dh 1175 | db 080h,065h,067h,0cbh 1176 | db 019h,06ch,036h,071h 1177 | db 06eh,06bh,006h,0e7h 1178 | db 0feh,0d4h,01bh,076h 1179 | db 089h,0d3h,02bh,0e0h 1180 | db 010h,0dah,07ah,05ah 1181 | db 067h,0ddh,04ah,0cch 1182 | db 0f9h,0b9h,0dfh,06fh 1183 | db 08eh,0beh,0efh,0f9h 1184 | db 017h,0b7h,0beh,043h 1185 | db 060h,0b0h,08eh,0d5h 1186 | db 0d6h,0d6h,0a3h,0e8h 1187 | db 0a1h,0d1h,093h,07eh 1188 | db 038h,0d8h,0c2h,0c4h 1189 | db 04fh,0dfh,0f2h,052h 1190 | db 0d1h,0bbh,067h,0f1h 1191 | db 0a6h,0bch,057h,067h 1192 | db 03fh,0b5h,006h,0ddh 1193 | db 048h,0b2h,036h,04bh 1194 | db 0d8h,00dh,02bh,0dah 1195 | db 0afh,00ah,01bh,04ch 1196 | db 036h,003h,04ah,0f6h 1197 | db 041h,004h,07ah,060h 1198 | db 0dfh,060h,0efh,0c3h 1199 | db 0a8h,067h,0dfh,055h 1200 | db 031h,06eh,08eh,0efh 1201 | db 046h,069h,0beh,079h 1202 | db 0cbh,061h,0b3h,08ch 1203 | db 0bch,066h,083h,01ah 1204 | db 025h,06fh,0d2h,0a0h 1205 | db 052h,068h,0e2h,036h 1206 | db 0cch,00ch,077h,095h 1207 | db 0bbh,00bh,047h,003h 1208 | db 022h,002h,016h,0b9h 1209 | db 055h,005h,026h,02fh 1210 | db 0c5h,0bah,03bh,0beh 1211 | db 0b2h,0bdh,00bh,028h 1212 | db 02bh,0b4h,05ah,092h 1213 | db 05ch,0b3h,06ah,004h 1214 | db 0c2h,0d7h,0ffh,0a7h 1215 | db 0b5h,0d0h,0cfh,031h 1216 | db 02ch,0d9h,09eh,08bh 1217 | db 05bh,0deh,0aeh,01dh 1218 | db 09bh,064h,0c2h,0b0h 1219 | db 0ech,063h,0f2h,026h 1220 | db 075h,06ah,0a3h,09ch 1221 | db 002h,06dh,093h,00ah 1222 | db 09ch,009h,006h,0a9h 1223 | db 0ebh,00eh,036h,03fh 1224 | db 072h,007h,067h,085h 1225 | db 005h,000h,057h,013h 1226 | db 095h,0bfh,04ah,082h 1227 | db 0e2h,0b8h,07ah,014h 1228 | db 07bh,0b1h,02bh,0aeh 1229 | db 00ch,0b6h,01bh,038h 1230 | db 092h,0d2h,08eh,09bh 1231 | db 0e5h,0d5h,0beh,00dh 1232 | db 07ch,0dch,0efh,0b7h 1233 | db 00bh,0dbh,0dfh,021h 1234 | db 086h,0d3h,0d2h,0d4h 1235 | db 0f1h,0d4h,0e2h,042h 1236 | db 068h,0ddh,0b3h,0f8h 1237 | db 01fh,0dah,083h,06eh 1238 | db 081h,0beh,016h,0cdh 1239 | db 0f6h,0b9h,026h,05bh 1240 | db 06fh,0b0h,077h,0e1h 1241 | db 018h,0b7h,047h,077h 1242 | db 088h,008h,05ah,0e6h 1243 | db 0ffh,00fh,06ah,070h 1244 | db 066h,006h,03bh,0cah 1245 | db 011h,001h,00bh,05ch 1246 | db 08fh,065h,09eh,0ffh 1247 | db 0f8h,062h,0aeh,069h 1248 | db 061h,06bh,0ffh,0d3h 1249 | db 016h,06ch,0cfh,045h 1250 | db 0a0h,00ah,0e2h,078h 1251 | db 0d7h,00dh,0d2h,0eeh 1252 | db 04eh,004h,083h,054h 1253 | db 039h,003h,0b3h,0c2h 1254 | db 0a7h,067h,026h,061h 1255 | db 0d0h,060h,016h,0f7h 1256 | db 049h,069h,047h,04dh 1257 | db 03eh,06eh,077h,0dbh 1258 | db 0aeh,0d1h,06ah,04ah 1259 | db 0d9h,0d6h,05ah,0dch 1260 | db 040h,0dfh,00bh,066h 1261 | db 037h,0d8h,03bh,0f0h 1262 | db 0a9h,0bch,0aeh,053h 1263 | db 0deh,0bbh,09eh,0c5h 1264 | db 047h,0b2h,0cfh,07fh 1265 | db 030h,0b5h,0ffh,0e9h 1266 | db 0bdh,0bdh,0f2h,01ch 1267 | db 0cah,0bah,0c2h,08ah 1268 | db 053h,0b3h,093h,030h 1269 | db 024h,0b4h,0a3h,0a6h 1270 | db 0bah,0d0h,036h,005h 1271 | db 0cdh,0d7h,006h,093h 1272 | db 054h,0deh,057h,029h 1273 | db 023h,0d9h,067h,0bfh 1274 | db 0b3h,066h,07ah,02eh 1275 | db 0c4h,061h,04ah,0b8h 1276 | db 05dh,068h,01bh,002h 1277 | db 02ah,06fh,02bh,094h 1278 | db 0b4h,00bh,0beh,037h 1279 | db 0c3h,00ch,08eh,0a1h 1280 | db 05ah,005h,0dfh,01bh 1281 | db 02dh,002h,0efh,08dh 1282 | 1283 | end 1284 | -------------------------------------------------------------------------------- /cpu_tests/8080EXM.MAC: -------------------------------------------------------------------------------- 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 | ;****************************************************************************** 21 | ; 22 | ; Modified to exercise an 8080 by Ian Bartholomew, February 2009 23 | ; 24 | ; I have made the following changes - 25 | ; 26 | ; Converted all mnemonics to 8080 and rewritten any Z80 code used 27 | ; in the original exerciser. Changes are tagged with a #idb in the 28 | ; source code listing. 29 | ; 30 | ; Removed any test descriptors that are not used. 31 | ; 32 | ; Changed the macro definitions to work in M80 33 | ; 34 | ; The machine state snapshot has been changed to remove the IX/IY registers. 35 | ; They have been replaced by two more copies of HL to obviate the need 36 | ; for major changes in the exerciser code. 37 | ; 38 | ; Changed flag mask in all tests to 0ffh to reflect that the 8080, unlike the 8085 39 | ; and Z80, does define the unused bits in the flag register - [S Z 0 AC 0 P 1 C] 40 | ; 41 | ;****************************************************************************** 42 | ; 43 | ; Modified to include success CRCs as shown on the 8080/8085 CPU Exerciser 44 | ; website http://www.idb.me.uk/sunhillow/8080.html 45 | ; 46 | ; Also updated to display the CRC when the test is passed instead of just 47 | ; displaying "OK" 48 | ; 49 | ; Mike Douglas, May 2013 50 | ; 51 | .8080 52 | aseg 53 | org 100h 54 | 55 | begin: jmp start 56 | 57 | ; machine state before test (needs to be at predictably constant address) 58 | msbt: ds 14 59 | spbt: ds 2 60 | 61 | ; For the purposes of this test program, the machine state consists of: 62 | ; a 2 byte memory operand, followed by 63 | ; the registers iy,ix,hl,de,bc,af,sp 64 | ; for a total of 16 bytes. 65 | 66 | ; The program tests instructions (or groups of similar instructions) 67 | ; by cycling through a sequence of machine states, executing the test 68 | ; instruction for each one and running a 32-bit crc over the resulting 69 | ; machine states. At the end of the sequence the crc is compared to 70 | ; an expected value that was found empirically on a real Z80. 71 | 72 | ; A test case is defined by a descriptor which consists of: 73 | ; a flag mask byte, 74 | ; the base case, 75 | ; the incement vector, 76 | ; the shift vector, 77 | ; the expected crc, 78 | ; a short descriptive message. 79 | ; 80 | ; The flag mask byte is used to prevent undefined flag bits from 81 | ; influencing the results. Documented flags are as per Mostek Z80 82 | ; Technical Manual. 83 | ; 84 | ; The next three parts of the descriptor are 20 byte vectors 85 | ; corresponding to a 4 byte instruction and a 16 byte machine state. 86 | ; The first part is the base case, which is the first test case of 87 | ; the sequence. This base is then modified according to the next 2 88 | ; vectors. Each 1 bit in the increment vector specifies a bit to be 89 | ; cycled in the form of a binary counter. For instance, if the byte 90 | ; corresponding to the accumulator is set to 0ffh in the increment 91 | ; vector, the test will be repeated for all 256 values of the 92 | ; accumulator. Note that 1 bits don't have to be contiguous. The 93 | ; number of test cases 'caused' by the increment vector is equal to 94 | ; 2^(number of 1 bits). The shift vector is similar, but specifies a 95 | ; set of bits in the test case that are to be successively inverted. 96 | ; Thus the shift vector 'causes' a number of test cases equal to the 97 | ; number of 1 bits in it. 98 | 99 | ; The total number of test cases is the product of those caused by the 100 | ; counter and shift vectors and can easily become unweildy. Each 101 | ; individual test case can take a few milliseconds to execute, due to 102 | ; the overhead of test setup and crc calculation, so test design is a 103 | ; compromise between coverage and execution time. 104 | 105 | ; This program is designed to detect differences between 106 | ; implementations and is not ideal for diagnosing the causes of any 107 | ; discrepancies. However, provided a reference implementation (or 108 | ; real system) is available, a failing test case can be isolated by 109 | ; hand using a binary search of the test space. 110 | 111 | 112 | start: lhld 6 113 | sphl 114 | lxi d,msg1 115 | mvi c,9 116 | call bdos 117 | 118 | lxi h,tests ; first test case 119 | loop: mov a,m ; end of list ? 120 | inx h 121 | ora m 122 | jz done 123 | dcx h 124 | call stt 125 | jmp loop 126 | 127 | done: lxi d,msg2 128 | mvi c,9 129 | call bdos 130 | jmp 0 ; warm boot 131 | 132 | tests: 133 | dw add16 134 | dw alu8i 135 | dw alu8r 136 | dw daa 137 | dw inca 138 | dw incb 139 | dw incbc 140 | dw incc 141 | dw incd 142 | dw incde 143 | dw ince 144 | dw inch 145 | dw inchl 146 | dw incl 147 | dw incm 148 | dw incsp 149 | dw ld162 150 | dw ld166 151 | dw ld16im 152 | dw ld8bd 153 | dw ld8im 154 | dw ld8rr 155 | dw lda 156 | dw rot8080 157 | dw stabd 158 | dw 0 159 | 160 | tstr macro insn,memop,hliy,hlix,hl,de,bc,flags,acc,sp 161 | local lab 162 | lab: db insn 163 | ds lab+4-$,0 164 | dw memop,hliy,hlix,hl,de,bc 165 | db flags 166 | db acc 167 | dw sp 168 | if $-lab ne 20 169 | error 'missing parameter' 170 | endif 171 | endm 172 | 173 | tmsg macro m 174 | local lab 175 | lab: db m 176 | if $ ge lab+30 177 | error 'message too long' 178 | else 179 | ds lab+30-$,'.' 180 | endif 181 | db '$' 182 | endm 183 | 184 | ; add hl, (19,456 cycles) 185 | add16: db 0ffh ; flag mask 186 | tstr 9,0c4a5h,0c4c7h,0d226h,0a050h,058eah,08566h,0c6h,0deh,09bc9h 187 | tstr 030h,0,0,0,0f821h,0,0,0,0,0 ; (512 cycles) 188 | tstr 0,0,0,0,-1,-1,-1,0d7h,0,-1 ; (38 cycles) 189 | db 014h, 047h, 04Bh, 0A6h ; expected crc 190 | tmsg 'dad ' 191 | 192 | ; aluop a,nn (28,672 cycles) 193 | alu8i: db 0ffh ; flag mask 194 | tstr 0c6h,09140h,07e3ch,07a67h,0df6dh,05b61h,00b29h,010h,066h,085b2h 195 | tstr 038h,0,0,0,0,0,0,0,-1,0 ; (2048 cycles) 196 | tstr <0,-1>,0,0,0,0,0,0,0d7h,0,0 ; (14 cycles) 197 | db 09Eh, 092h, 02Fh, 09Eh ; expected crc 198 | tmsg 'aluop nn' 199 | 200 | ; aluop a, (753,664 cycles) 201 | alu8r: db 0ffh ; flag mask 202 | tstr 080h,0c53eh,0573ah,04c4dh,msbt,0e309h,0a666h,0d0h,03bh,0adbbh 203 | tstr 03fh,0,0,0,0,0,0,0,-1,0 ; (16,384 cycles) 204 | tstr 0,0ffh,0,0,0,-1,-1,0d7h,0,0 ; (46 cycles) 205 | db 0CFh, 076h, 02Ch, 086h ; expected crc 206 | tmsg 'aluop ' 207 | 208 | ; 209 | daa: db 0ffh ; flag mask 210 | tstr 027h,02141h,009fah,01d60h,0a559h,08d5bh,09079h,004h,08eh,0299dh 211 | tstr 018h,0,0,0,0,0,0,0d7h,-1,0 ; (65,536 cycles) 212 | tstr 0,0,0,0,0,0,0,0,0,0 ; (1 cycle) 213 | db 0BBh, 03Fh, 003h, 00Ch ; expected crc 214 | tmsg '' 215 | 216 | ; a (3072 cycles) 217 | inca: db 0ffh ; flag mask 218 | tstr 03ch,04adfh,0d5d8h,0e598h,08a2bh,0a7b0h,0431bh,044h,05ah,0d030h 219 | tstr 001h,0,0,0,0,0,0,0,-1,0 ; (512 cycles) 220 | tstr 0,0,0,0,0,0,0,0d7h,0,0 ; (6 cycles) 221 | db 0ADh, 0B6h, 046h, 00Eh ; expected crc 222 | tmsg ' a' 223 | 224 | ; b (3072 cycles) 225 | incb: db 0ffh ; flag mask 226 | tstr 004h,0d623h,0432dh,07a61h,08180h,05a86h,01e85h,086h,058h,09bbbh 227 | tstr 001h,0,0,0,0,0,0ff00h,0,0,0 ; (512 cycles) 228 | tstr 0,0,0,0,0,0,0,0d7h,0,0 ; (6 cycles) 229 | db 083h, 0EDh, 013h, 045h ; expected crc 230 | tmsg ' b' 231 | 232 | ; bc (1536 cycles) 233 | incbc: db 0ffh ; flag mask 234 | tstr 003h,0cd97h,044abh,08dc9h,0e3e3h,011cch,0e8a4h,002h,049h,02a4dh 235 | tstr 008h,0,0,0,0,0,0f821h,0,0,0 ; (256 cycles) 236 | tstr 0,0,0,0,0,0,0,0d7h,0,0 ; (6 cycles) 237 | db 0F7h, 092h, 087h, 0CDh ; expected crc 238 | tmsg ' b' 239 | 240 | ; c (3072 cycles) 241 | incc: db 0ffh ; flag mask 242 | tstr 00ch,0d789h,00935h,0055bh,09f85h,08b27h,0d208h,095h,005h,00660h 243 | tstr 001h,0,0,0,0,0,0ffh,0,0,0 ; (512 cycles) 244 | tstr 0,0,0,0,0,0,0,0d7h,0,0 ; (6 cycles) 245 | db 0E5h, 0F6h, 072h, 01Bh ; expected crc 246 | tmsg ' c' 247 | 248 | ; d (3072 cycles) 249 | incd: db 0ffh ; flag mask 250 | tstr 014h,0a0eah,05fbah,065fbh,0981ch,038cch,0debch,043h,05ch,003bdh 251 | tstr 001h,0,0,0,0,0ff00h,0,0,0,0 ; (512 cycles) 252 | tstr 0,0,0,0,0,0,0,0d7h,0,0 ; (6 cycles) 253 | db 015h, 0B5h, 057h, 09Ah ; expected crc 254 | tmsg ' d' 255 | 256 | ; de (1536 cycles) 257 | incde: db 0ffh ; flag mask 258 | tstr 013h,0342eh,0131dh,028c9h,00acah,09967h,03a2eh,092h,0f6h,09d54h 259 | tstr 008h,0,0,0,0,0f821h,0,0,0,0 ; (256 cycles) 260 | tstr 0,0,0,0,0,0,0,0d7h,0,0 ; (6 cycles) 261 | db 07Fh, 04Eh, 025h, 001h ; expected crc 262 | tmsg ' d' 263 | 264 | ; e (3072 cycles) 265 | ince: db 0ffh ; flag mask 266 | tstr 01ch,0602fh,04c0dh,02402h,0e2f5h,0a0f4h,0a10ah,013h,032h,05925h 267 | tstr 001h,0,0,0,0,0ffh,0,0,0,0 ; (512 cycles) 268 | tstr 0,0,0,0,0,0,0,0d7h,0,0 ; (6 cycles) 269 | db 0CFh, 02Ah, 0B3h, 096h ; expected crc 270 | tmsg ' e' 271 | 272 | ; h (3072 cycles) 273 | inch: db 0ffh ; flag mask 274 | tstr 024h,01506h,0f2ebh,0e8ddh,0262bh,011a6h,0bc1ah,017h,006h,02818h 275 | tstr 001h,0,0,0,0ff00h,0,0,0,0,0 ; (512 cycles) 276 | tstr 0,0,0,0,0,0,0,0d7h,0,0 ; (6 cycles) 277 | db 012h, 0B2h, 095h, 02Ch ; expected crc 278 | tmsg ' h' 279 | 280 | ; hl (1536 cycles) 281 | inchl: db 0ffh ; flag mask 282 | tstr 023h,0c3f4h,007a5h,01b6dh,04f04h,0e2c2h,0822ah,057h,0e0h,0c3e1h 283 | tstr 008h,0,0,0,0f821h,0,0,0,0,0 ; (256 cycles) 284 | tstr 0,0,0,0,0,0,0,0d7h,0,0 ; (6 cycles) 285 | db 09Fh, 02Bh, 023h, 0C0h ; expected crc 286 | tmsg ' h' 287 | 288 | ; l (3072 cycles) 289 | incl: db 0ffh ; flag mask 290 | tstr 02ch,08031h,0a520h,04356h,0b409h,0f4c1h,0dfa2h,0d1h,03ch,03ea2h 291 | tstr 001h,0,0,0,0ffh,0,0,0,0,0 ; (512 cycles) 292 | tstr 0,0,0,0,0,0,0,0d7h,0,0 ; (6 cycles) 293 | db 0FFh, 057h, 0D3h, 056h ; expected crc 294 | tmsg ' l' 295 | 296 | ; (hl) (3072 cycles) 297 | incm: db 0ffh ; flag mask 298 | tstr 034h,0b856h,00c7ch,0e53eh,msbt,0877eh,0da58h,015h,05ch,01f37h 299 | tstr 001h,0ffh,0,0,0,0,0,0,0,0 ; (512 cycles) 300 | tstr 0,0,0,0,0,0,0,0d7h,0,0 ; (6 cycles) 301 | db 092h, 0E9h, 063h, 0BDh ; expected crc 302 | tmsg ' m' 303 | 304 | ; sp (1536 cycles) 305 | incsp: db 0ffh ; flag mask 306 | tstr 033h,0346fh,0d482h,0d169h,0deb6h,0a494h,0f476h,053h,002h,0855bh 307 | tstr 008h,0,0,0,0,0,0,0,0,0f821h ; (256 cycles) 308 | tstr 0,0,0,0,0,0,0,0d7h,0,0 ; (6 cycles) 309 | db 0D5h, 070h, 02Fh, 0ABh ; expected crc 310 | tmsg ' sp' 311 | 312 | ; ld hl,(nnnn) (16 cycles) 313 | ld162: db 0ffh ; flag mask 314 | tstr <02ah,low msbt,high msbt>,09863h,07830h,02077h,0b1feh,0b9fah,0abb8h,004h,006h,06015h 315 | tstr 0,0,0,0,0,0,0,0,0,0 ; (1 cycle) 316 | tstr 0,-1,0,0,0,0,0,0,0,0 ; (16 cycles) 317 | db 0A9h, 0C3h, 0D5h, 0CBh ; expected crc 318 | tmsg 'lhld nnnn' 319 | 320 | ; ld (nnnn),hl (16 cycles) 321 | ld166: db 0ffh ; flag mask 322 | tstr <022h,low msbt,high msbt>,0d003h,07772h,07f53h,03f72h,064eah,0e180h,010h,02dh,035e9h 323 | tstr 0,0,0,0,0,0,0,0,0,0 ; (1 cycle) 324 | tstr 0,0,0,0,-1,0,0,0,0,0 ; (16 cycles) 325 | db 0E8h, 086h, 04Fh, 026h ; expected crc 326 | tmsg 'shld nnnn' 327 | 328 | ; ld ,nnnn (64 cycles) 329 | ld16im: db 0ffh ; flag mask 330 | tstr 1,05c1ch,02d46h,08eb9h,06078h,074b1h,0b30eh,046h,0d1h,030cch 331 | tstr 030h,0,0,0,0,0,0,0,0,0 ; (4 cycles) 332 | tstr <0,0ffh,0ffh>,0,0,0,0,0,0,0,0,0 ; (16 cycles) 333 | db 0FCh, 0F4h, 06Eh, 012h ; expected crc 334 | tmsg 'lxi ,nnnn' 335 | 336 | ; ld a,<(bc),(de)> (44 cycles) 337 | ld8bd: db 0ffh ; flag mask 338 | tstr 00ah,0b3a8h,01d2ah,07f8eh,042ach,msbt,msbt,0c6h,0b1h,0ef8eh 339 | tstr 010h,0,0,0,0,0,0,0,0,0 ; (2 cycles) 340 | tstr 0,0ffh,0,0,0,0,0,0d7h,-1,0 ; (22 cycles) 341 | db 02Bh, 082h, 01Dh, 05Fh ; expected crc 342 | tmsg 'ldax ' 343 | 344 | ; ld ,nn (64 cycles) 345 | ld8im: db 0ffh ; flag mask 346 | tstr 6,0c407h,0f49dh,0d13dh,00339h,0de89h,07455h,053h,0c0h,05509h 347 | tstr 038h,0,0,0,0,0,0,0,0,0 ; (8 cycles) 348 | tstr 0,0,0,0,0,0,0,0,-1,0 ; (8 cycles) 349 | db 0EAh, 0A7h, 020h, 044h ; expected crc 350 | tmsg 'mvi ,nn' 351 | 352 | ; ld , (3456 cycles) 353 | ld8rr: db 0ffh ; flag mask 354 | tstr 040h,072a4h,0a024h,061ach,msbt,082c7h,0718fh,097h,08fh,0ef8eh 355 | tstr 03fh,0,0,0,0,0,0,0,0,0 ; (64 cycles) 356 | tstr 0,0ffh,0,0,0,-1,-1,0d7h,-1,0 ; (54 cycles) 357 | db 010h, 0B5h, 08Ch, 0EEh ; expected crc 358 | tmsg 'mov ,' 359 | 360 | ; ld a,(nnnn) / ld (nnnn),a (44 cycles) 361 | lda: db 0ffh ; flag mask 362 | tstr <032h,low msbt,high msbt>,0fd68h,0f4ech,044a0h,0b543h,00653h,0cdbah,0d2h,04fh,01fd8h 363 | tstr 008h,0,0,0,0,0,0,0,0,0 ; (2 cycle) 364 | tstr 0,0ffh,0,0,0,0,0,0d7h,-1,0 ; (22 cycles) 365 | db 0EDh, 057h, 0AFh, 072h ; expected crc 366 | tmsg 'sta nnnn / lda nnnn' 367 | 368 | ; (6144 cycles) 369 | rot8080: db 0ffh ; flag mask 370 | tstr 7,0cb92h,06d43h,00a90h,0c284h,00c53h,0f50eh,091h,0ebh,040fch 371 | tstr 018h,0,0,0,0,0,0,0,-1,0 ; (1024 cycles) 372 | tstr 0,0,0,0,0,0,0,0d7h,0,0 ; (6 cycles) 373 | db 0E0h, 0D8h, 092h, 035h ; expected crc 374 | tmsg '' 375 | 376 | ; ld (),a (96 cycles) 377 | stabd: db 0ffh ; flag mask 378 | tstr 2,00c3bh,0b592h,06cffh,0959eh,msbt,msbt+1,0c1h,021h,0bde7h 379 | tstr 018h,0,0,0,0,0,0,0,0,0 ; (4 cycles) 380 | tstr 0,-1,0,0,0,0,0,0,-1,0 ; (24 cycles) 381 | db 02Bh, 004h, 071h, 0E9h ; expected crc 382 | tmsg 'stax ' 383 | 384 | ; start test pointed to by (hl) 385 | stt: push h 386 | mov a,m ; get pointer to test 387 | inx h 388 | mov h,m 389 | mov l,a 390 | mov a,m ; flag mask 391 | sta flgmsk+1 392 | inx h 393 | push h 394 | lxi d,20 395 | dad d ; point to incmask 396 | lxi d,counter 397 | call initmask 398 | pop h 399 | push h 400 | lxi d,20+20 401 | dad d ; point to scanmask 402 | lxi d,shifter 403 | call initmask 404 | lxi h,shifter 405 | mvi m,1 ; first bit 406 | pop h 407 | push h 408 | lxi d,iut ; copy initial instruction under test 409 | lxi b,4 410 | 411 | ;#idb ldir replaced with following code 412 | ldir1: mov a,m 413 | stax d 414 | inx h 415 | inx d 416 | dcx b 417 | mov a,b 418 | ora c 419 | jnz ldir1 420 | ;#idb 421 | 422 | lxi d,msbt ; copy initial machine state 423 | lxi b,16 424 | 425 | ;#idb ldir replaced with following code 426 | ldir2: mov a,m 427 | stax d 428 | inx h 429 | inx d 430 | dcx b 431 | mov a,b 432 | ora c 433 | jnz ldir2 434 | ;#idb 435 | 436 | lxi d,20+20+4 ; skip incmask, scanmask and expcrc 437 | dad d 438 | xchg 439 | mvi c,9 440 | call bdos ; show test name 441 | call initcrc ; initialise crc 442 | ; test loop 443 | tlp: lda iut 444 | cpi 076h ; pragmatically avoid halt intructions 445 | jz tlp2 446 | ani 0dfh 447 | cpi 0ddh 448 | jnz tlp1 449 | lda iut+1 450 | cpi 076h 451 | tlp1: cnz test ; execute the test instruction 452 | tlp2: call count ; increment the counter 453 | cnz shift ; shift the scan bit 454 | pop h ; pointer to test case 455 | jz tlp3 ; done if shift returned NZ 456 | lxi d,20+20+20 457 | dad d ; point to expected crc 458 | call cmpcrc 459 | jz crcGood 460 | lxi d,ermsg1 461 | mvi c,9 462 | call bdos 463 | call phex8 464 | lxi d,ermsg2 465 | mvi c,9 466 | call bdos 467 | lxi h,crcval 468 | call phex8 469 | doCrLf: lxi d,crlf 470 | tlpok: mvi c,9 471 | call bdos 472 | pop h 473 | inx h 474 | inx h 475 | ret 476 | 477 | crcGood: lxi d,okMsg 478 | mvi c,9 479 | call bdos 480 | call phex8 481 | jmp doCrLf 482 | 483 | tlp3: push h 484 | mvi a,1 ; initialise count and shift scanners 485 | sta cntbit 486 | sta shfbit 487 | lxi h,counter 488 | shld cntbyt 489 | lxi h,shifter 490 | shld shfbyt 491 | 492 | mvi b,4 ; bytes in iut field 493 | pop h ; pointer to test case 494 | push h 495 | lxi d,iut 496 | call setup ; setup iut 497 | mvi b,16 ; bytes in machine state 498 | lxi d,msbt 499 | call setup ; setup machine state 500 | jmp tlp 501 | 502 | ; setup a field of the test case 503 | ; b = number of bytes 504 | ; hl = pointer to base case 505 | ; de = destination 506 | setup: call subyte 507 | inx h 508 | dcr b 509 | jnz setup 510 | ret 511 | 512 | subyte: push b 513 | push d 514 | push h 515 | mov c,m ; get base byte 516 | lxi d,20 517 | dad d ; point to incmask 518 | mov a,m 519 | cpi 0 520 | jz subshf 521 | mvi b,8 ; 8 bits 522 | subclp: rrc 523 | push psw 524 | mvi a,0 525 | cc nxtcbit ; get next counter bit if mask bit was set 526 | xra c ; flip bit if counter bit was set 527 | rrc 528 | mov c,a 529 | pop psw 530 | dcr b 531 | jnz subclp 532 | mvi b,8 533 | subshf: lxi d,20 534 | dad d ; point to shift mask 535 | mov a,m 536 | cpi 0 537 | jz substr 538 | mvi b,8 ; 8 bits 539 | sbshf1: rrc 540 | push psw 541 | mvi a,0 542 | cc nxtsbit ; get next shifter bit if mask bit was set 543 | xra c ; flip bit if shifter bit was set 544 | rrc 545 | mov c,a 546 | pop psw 547 | dcr b 548 | jnz sbshf1 549 | substr: pop h 550 | pop d 551 | mov a,c 552 | stax d ; mangled byte to destination 553 | inx d 554 | pop b 555 | ret 556 | 557 | ; get next counter bit in low bit of a 558 | cntbit: ds 1 559 | cntbyt: ds 2 560 | 561 | nxtcbit: push b 562 | push h 563 | lhld cntbyt 564 | mov b,m 565 | lxi h,cntbit 566 | mov a,m 567 | mov c,a 568 | rlc 569 | mov m,a 570 | cpi 1 571 | jnz ncb1 572 | lhld cntbyt 573 | inx h 574 | shld cntbyt 575 | ncb1: mov a,b 576 | ana c 577 | pop h 578 | pop b 579 | rz 580 | mvi a,1 581 | ret 582 | 583 | ; get next shifter bit in low bit of a 584 | shfbit: ds 1 585 | shfbyt: ds 2 586 | 587 | nxtsbit: push b 588 | push h 589 | lhld shfbyt 590 | mov b,m 591 | lxi h,shfbit 592 | mov a,m 593 | mov c,a 594 | rlc 595 | mov m,a 596 | cpi 1 597 | jnz nsb1 598 | lhld shfbyt 599 | inx h 600 | shld shfbyt 601 | nsb1: mov a,b 602 | ana c 603 | pop h 604 | pop b 605 | rz 606 | mvi a,1 607 | ret 608 | 609 | 610 | ; clear memory at hl, bc bytes 611 | clrmem: push psw 612 | push b 613 | push d 614 | push h 615 | mvi m,0 616 | mov d,h 617 | mov e,l 618 | inx d 619 | dcx b 620 | 621 | ;#idb ldir replaced with following code 622 | ldir3: mov a,m 623 | stax d 624 | inx h 625 | inx d 626 | dcx b 627 | mov a,b 628 | ora c 629 | jnz ldir3 630 | ;#idb 631 | 632 | pop h 633 | pop d 634 | pop b 635 | pop psw 636 | ret 637 | 638 | ; initialise counter or shifter 639 | ; de = pointer to work area for counter or shifter 640 | ; hl = pointer to mask 641 | initmask: 642 | push d 643 | xchg 644 | lxi b,20+20 645 | call clrmem ; clear work area 646 | xchg 647 | mvi b,20 ; byte counter 648 | mvi c,1 ; first bit 649 | mvi d,0 ; bit counter 650 | imlp: mov e,m 651 | imlp1: mov a,e 652 | ana c 653 | jz imlp2 654 | inr d 655 | imlp2: mov a,c 656 | rlc 657 | mov c,a 658 | cpi 1 659 | jnz imlp1 660 | inx h 661 | dcr b 662 | jnz imlp 663 | ; got number of 1-bits in mask in reg d 664 | mov a,d 665 | ani 0f8h 666 | rrc 667 | rrc 668 | rrc ; divide by 8 (get byte offset) 669 | mov l,a 670 | mvi h,0 671 | mov a,d 672 | ani 7 ; bit offset 673 | inr a 674 | mov b,a 675 | mvi a,080h 676 | imlp3: rlc 677 | dcr b 678 | jnz imlp3 679 | pop d 680 | dad d 681 | lxi d,20 682 | dad d 683 | mov m,a 684 | ret 685 | 686 | ; multi-byte counter 687 | count: push b 688 | push d 689 | push h 690 | lxi h,counter ; 20 byte counter starts here 691 | lxi d,20 ; somewhere in here is the stop bit 692 | xchg 693 | dad d 694 | xchg 695 | cntlp: inr m 696 | mov a,m 697 | cpi 0 698 | jz cntlp1 ; overflow to next byte 699 | mov b,a 700 | ldax d 701 | ana b ; test for terminal value 702 | jz cntend 703 | mvi m,0 ; reset to zero 704 | cntend: pop b 705 | pop d 706 | pop h 707 | ret 708 | 709 | cntlp1: inx h 710 | inx d 711 | jmp cntlp 712 | 713 | 714 | ; multi-byte shifter 715 | shift: push b 716 | push d 717 | push h 718 | lxi h,shifter ; 20 byte shift register starts here 719 | lxi d,20 ; somewhere in here is the stop bit 720 | xchg 721 | dad d 722 | xchg 723 | shflp: mov a,m 724 | ora a 725 | jz shflp1 726 | mov b,a 727 | ldax d 728 | ana b 729 | jnz shlpe 730 | mov a,b 731 | rlc 732 | cpi 1 733 | jnz shflp2 734 | mvi m,0 735 | inx h 736 | inx d 737 | shflp2: mov m,a 738 | xra a ; set Z 739 | shlpe: pop h 740 | pop d 741 | pop b 742 | ret 743 | shflp1: inx h 744 | inx d 745 | jmp shflp 746 | 747 | counter: ds 2*20 748 | shifter: ds 2*20 749 | 750 | ; test harness 751 | test: push psw 752 | push b 753 | push d 754 | push h 755 | if 0 756 | lxi d,crlf 757 | mvi c,9 758 | call bdos 759 | lxi h,iut 760 | mvi b,4 761 | call hexstr 762 | mvi e,' ' 763 | mvi c,2 764 | call bdos 765 | mvi b,16 766 | lxi h,msbt 767 | call hexstr 768 | endif 769 | di ; disable interrupts 770 | 771 | ;#idb ld (spsav),sp replaced by following code 772 | ;#idb All registers and flages are immediately overwritten so 773 | ;#idb no need to preserve any state. 774 | lxi h,0 ; save stack pointer 775 | dad sp 776 | shld spsav 777 | ;#idb 778 | 779 | lxi sp,msbt+2 ; point to test-case machine state 780 | 781 | ;#idb pop iy 782 | ;#idb pop ix both replaced by following code 783 | ;#idb Just dummy out ix/iy with copies of hl 784 | pop h ; and load all regs 785 | pop h 786 | ;#idb 787 | 788 | pop h 789 | pop d 790 | pop b 791 | pop psw 792 | 793 | ;#idb ld sp,(spbt) replaced with the following code 794 | ;#idb HL is copied/restored before/after load so no state changed 795 | shld temp 796 | lhld spbt 797 | sphl 798 | lhld temp 799 | ;#idb 800 | 801 | iut: ds 4 ; max 4 byte instruction under test 802 | 803 | ;#idb ld (spat),sp replaced with the following code 804 | ;#idb Must be very careful to preserve registers and flag 805 | ;#idb state resulting from the test. The temptation is to use the 806 | ;#idb stack - but that doesn't work because of the way the app 807 | ;#idb uses SP as a quick way of pointing to memory. 808 | ;#idb Bit of a code smell, but I can't think of an easier way. 809 | shld temp 810 | lxi h,0 811 | jc temp1 ;jump on the state of the C flag set in the test 812 | 813 | dad sp ;this code will clear the C flag (0 + nnnn = nc) 814 | jmp temp2 ;C flag is same state as before 815 | 816 | temp1: dad sp ;this code will clear the C flag (0 + nnnn = nc) 817 | stc ;C flage needs re-setting to preserve state 818 | 819 | temp2: shld spat 820 | lhld temp 821 | ;#idb 822 | 823 | lxi sp,spat 824 | push psw ; save other registers 825 | push b 826 | push d 827 | push h 828 | 829 | ;#idb push ix 830 | ;#idb push iy both replaced by following code 831 | ;#idb Must match change made to pops made before test 832 | push h 833 | push h 834 | ;#idb 835 | 836 | ;#idb ld sp,(spsav) replaced with following code 837 | ;#idb No need to preserve state 838 | lhld spsav ; restore stack pointer 839 | sphl 840 | ;#idb 841 | 842 | ei ; enable interrupts 843 | lhld msbt ; copy memory operand 844 | shld msat 845 | lxi h,flgsat ; flags after test 846 | mov a,m 847 | flgmsk: ani 0ffh ; mask-out irrelevant bits (self-modified code!) 848 | mov m,a 849 | mvi b,16 ; total of 16 bytes of state 850 | lxi d,msat 851 | lxi h,crcval 852 | tcrc: ldax d 853 | inx d 854 | call updcrc ; accumulate crc of this test case 855 | dcr b 856 | jnz tcrc 857 | if 0 858 | mvi e,' ' 859 | mvi c,2 860 | call bdos 861 | lxi h,crcval 862 | call phex8 863 | lxi d,crlf 864 | mvi c,9 865 | call bdos 866 | lxi h,msat 867 | mvi b,16 868 | call hexstr 869 | lxi d,crlf 870 | mvi c,9 871 | call bdos 872 | endif 873 | pop h 874 | pop d 875 | pop b 876 | pop psw 877 | ret 878 | 879 | ;#idb Added to store HL state 880 | temp: ds 2 881 | ;#idb 882 | 883 | ; machine state after test 884 | msat: ds 14 ; memop,iy,ix,hl,de,bc,af 885 | spat: ds 2 ; stack pointer after test 886 | flgsat equ spat-2 ; flags 887 | 888 | spsav: ds 2 ; saved stack pointer 889 | 890 | ; display hex string (pointer in hl, byte count in b) 891 | hexstr: mov a,m 892 | call phex2 893 | inx h 894 | dcr b 895 | jnz hexstr 896 | ret 897 | 898 | ; display hex 899 | ; display the big-endian 32-bit value pointed to by hl 900 | phex8: push psw 901 | push b 902 | push h 903 | mvi b,4 904 | ph8lp: mov a,m 905 | call phex2 906 | inx h 907 | dcr b 908 | jnz ph8lp 909 | pop h 910 | pop b 911 | pop psw 912 | ret 913 | 914 | ; display byte in a 915 | phex2: push psw 916 | rrc 917 | rrc 918 | rrc 919 | rrc 920 | call phex1 921 | pop psw 922 | ; fall through 923 | 924 | ; display low nibble in a 925 | phex1: push psw 926 | push b 927 | push d 928 | push h 929 | ani 0fh 930 | cpi 10 931 | jc ph11 932 | adi 'a'-'9'-1 933 | ph11: adi '0' 934 | mov e,a 935 | mvi c,2 936 | call bdos 937 | pop h 938 | pop d 939 | pop b 940 | pop psw 941 | ret 942 | 943 | bdos: push psw 944 | push b 945 | push d 946 | push h 947 | call 5 948 | pop h 949 | pop d 950 | pop b 951 | pop psw 952 | ret 953 | 954 | msg1: db '8080 instruction exerciser',10,13,'$' 955 | msg2: db 'Tests complete$' 956 | okmsg: db ' PASS! crc is:$' 957 | ermsg1: db ' ERROR **** crc expected:$' 958 | ermsg2: db ' found:$' 959 | crlf: db 10,13,'$' 960 | 961 | ; compare crc 962 | ; hl points to value to compare to crcval 963 | cmpcrc: push b 964 | push d 965 | push h 966 | lxi d,crcval 967 | mvi b,4 968 | cclp: ldax d 969 | cmp m 970 | jnz cce 971 | inx h 972 | inx d 973 | dcr b 974 | jnz cclp 975 | cce: pop h 976 | pop d 977 | pop b 978 | ret 979 | 980 | ; 32-bit crc routine 981 | ; entry: a contains next byte, hl points to crc 982 | ; exit: crc updated 983 | updcrc: push psw 984 | push b 985 | push d 986 | push h 987 | push h 988 | lxi d,3 989 | dad d ; point to low byte of old crc 990 | xra m ; xor with new byte 991 | mov l,a 992 | mvi h,0 993 | dad h ; use result as index into table of 4 byte entries 994 | dad h 995 | xchg 996 | lxi h,crctab 997 | dad d ; point to selected entry in crctab 998 | xchg 999 | pop h 1000 | lxi b,4 ; c = byte count, b = accumulator 1001 | crclp: ldax d 1002 | xra b 1003 | mov b,m 1004 | mov m,a 1005 | inx d 1006 | inx h 1007 | dcr c 1008 | jnz crclp 1009 | if 0 1010 | lxi h,crcval 1011 | call phex8 1012 | lxi d,crlf 1013 | mvi c,9 1014 | call bdos 1015 | endif 1016 | pop h 1017 | pop d 1018 | pop b 1019 | pop psw 1020 | ret 1021 | 1022 | initcrc:push psw 1023 | push b 1024 | push h 1025 | lxi h,crcval 1026 | mvi a,0ffh 1027 | mvi b,4 1028 | icrclp: mov m,a 1029 | inx h 1030 | dcr b 1031 | jnz icrclp 1032 | pop h 1033 | pop b 1034 | pop psw 1035 | ret 1036 | 1037 | crcval: ds 4 1038 | 1039 | crctab: db 000h,000h,000h,000h 1040 | db 077h,007h,030h,096h 1041 | db 0eeh,00eh,061h,02ch 1042 | db 099h,009h,051h,0bah 1043 | db 007h,06dh,0c4h,019h 1044 | db 070h,06ah,0f4h,08fh 1045 | db 0e9h,063h,0a5h,035h 1046 | db 09eh,064h,095h,0a3h 1047 | db 00eh,0dbh,088h,032h 1048 | db 079h,0dch,0b8h,0a4h 1049 | db 0e0h,0d5h,0e9h,01eh 1050 | db 097h,0d2h,0d9h,088h 1051 | db 009h,0b6h,04ch,02bh 1052 | db 07eh,0b1h,07ch,0bdh 1053 | db 0e7h,0b8h,02dh,007h 1054 | db 090h,0bfh,01dh,091h 1055 | db 01dh,0b7h,010h,064h 1056 | db 06ah,0b0h,020h,0f2h 1057 | db 0f3h,0b9h,071h,048h 1058 | db 084h,0beh,041h,0deh 1059 | db 01ah,0dah,0d4h,07dh 1060 | db 06dh,0ddh,0e4h,0ebh 1061 | db 0f4h,0d4h,0b5h,051h 1062 | db 083h,0d3h,085h,0c7h 1063 | db 013h,06ch,098h,056h 1064 | db 064h,06bh,0a8h,0c0h 1065 | db 0fdh,062h,0f9h,07ah 1066 | db 08ah,065h,0c9h,0ech 1067 | db 014h,001h,05ch,04fh 1068 | db 063h,006h,06ch,0d9h 1069 | db 0fah,00fh,03dh,063h 1070 | db 08dh,008h,00dh,0f5h 1071 | db 03bh,06eh,020h,0c8h 1072 | db 04ch,069h,010h,05eh 1073 | db 0d5h,060h,041h,0e4h 1074 | db 0a2h,067h,071h,072h 1075 | db 03ch,003h,0e4h,0d1h 1076 | db 04bh,004h,0d4h,047h 1077 | db 0d2h,00dh,085h,0fdh 1078 | db 0a5h,00ah,0b5h,06bh 1079 | db 035h,0b5h,0a8h,0fah 1080 | db 042h,0b2h,098h,06ch 1081 | db 0dbh,0bbh,0c9h,0d6h 1082 | db 0ach,0bch,0f9h,040h 1083 | db 032h,0d8h,06ch,0e3h 1084 | db 045h,0dfh,05ch,075h 1085 | db 0dch,0d6h,00dh,0cfh 1086 | db 0abh,0d1h,03dh,059h 1087 | db 026h,0d9h,030h,0ach 1088 | db 051h,0deh,000h,03ah 1089 | db 0c8h,0d7h,051h,080h 1090 | db 0bfh,0d0h,061h,016h 1091 | db 021h,0b4h,0f4h,0b5h 1092 | db 056h,0b3h,0c4h,023h 1093 | db 0cfh,0bah,095h,099h 1094 | db 0b8h,0bdh,0a5h,00fh 1095 | db 028h,002h,0b8h,09eh 1096 | db 05fh,005h,088h,008h 1097 | db 0c6h,00ch,0d9h,0b2h 1098 | db 0b1h,00bh,0e9h,024h 1099 | db 02fh,06fh,07ch,087h 1100 | db 058h,068h,04ch,011h 1101 | db 0c1h,061h,01dh,0abh 1102 | db 0b6h,066h,02dh,03dh 1103 | db 076h,0dch,041h,090h 1104 | db 001h,0dbh,071h,006h 1105 | db 098h,0d2h,020h,0bch 1106 | db 0efh,0d5h,010h,02ah 1107 | db 071h,0b1h,085h,089h 1108 | db 006h,0b6h,0b5h,01fh 1109 | db 09fh,0bfh,0e4h,0a5h 1110 | db 0e8h,0b8h,0d4h,033h 1111 | db 078h,007h,0c9h,0a2h 1112 | db 00fh,000h,0f9h,034h 1113 | db 096h,009h,0a8h,08eh 1114 | db 0e1h,00eh,098h,018h 1115 | db 07fh,06ah,00dh,0bbh 1116 | db 008h,06dh,03dh,02dh 1117 | db 091h,064h,06ch,097h 1118 | db 0e6h,063h,05ch,001h 1119 | db 06bh,06bh,051h,0f4h 1120 | db 01ch,06ch,061h,062h 1121 | db 085h,065h,030h,0d8h 1122 | db 0f2h,062h,000h,04eh 1123 | db 06ch,006h,095h,0edh 1124 | db 01bh,001h,0a5h,07bh 1125 | db 082h,008h,0f4h,0c1h 1126 | db 0f5h,00fh,0c4h,057h 1127 | db 065h,0b0h,0d9h,0c6h 1128 | db 012h,0b7h,0e9h,050h 1129 | db 08bh,0beh,0b8h,0eah 1130 | db 0fch,0b9h,088h,07ch 1131 | db 062h,0ddh,01dh,0dfh 1132 | db 015h,0dah,02dh,049h 1133 | db 08ch,0d3h,07ch,0f3h 1134 | db 0fbh,0d4h,04ch,065h 1135 | db 04dh,0b2h,061h,058h 1136 | db 03ah,0b5h,051h,0ceh 1137 | db 0a3h,0bch,000h,074h 1138 | db 0d4h,0bbh,030h,0e2h 1139 | db 04ah,0dfh,0a5h,041h 1140 | db 03dh,0d8h,095h,0d7h 1141 | db 0a4h,0d1h,0c4h,06dh 1142 | db 0d3h,0d6h,0f4h,0fbh 1143 | db 043h,069h,0e9h,06ah 1144 | db 034h,06eh,0d9h,0fch 1145 | db 0adh,067h,088h,046h 1146 | db 0dah,060h,0b8h,0d0h 1147 | db 044h,004h,02dh,073h 1148 | db 033h,003h,01dh,0e5h 1149 | db 0aah,00ah,04ch,05fh 1150 | db 0ddh,00dh,07ch,0c9h 1151 | db 050h,005h,071h,03ch 1152 | db 027h,002h,041h,0aah 1153 | db 0beh,00bh,010h,010h 1154 | db 0c9h,00ch,020h,086h 1155 | db 057h,068h,0b5h,025h 1156 | db 020h,06fh,085h,0b3h 1157 | db 0b9h,066h,0d4h,009h 1158 | db 0ceh,061h,0e4h,09fh 1159 | db 05eh,0deh,0f9h,00eh 1160 | db 029h,0d9h,0c9h,098h 1161 | db 0b0h,0d0h,098h,022h 1162 | db 0c7h,0d7h,0a8h,0b4h 1163 | db 059h,0b3h,03dh,017h 1164 | db 02eh,0b4h,00dh,081h 1165 | db 0b7h,0bdh,05ch,03bh 1166 | db 0c0h,0bah,06ch,0adh 1167 | db 0edh,0b8h,083h,020h 1168 | db 09ah,0bfh,0b3h,0b6h 1169 | db 003h,0b6h,0e2h,00ch 1170 | db 074h,0b1h,0d2h,09ah 1171 | db 0eah,0d5h,047h,039h 1172 | db 09dh,0d2h,077h,0afh 1173 | db 004h,0dbh,026h,015h 1174 | db 073h,0dch,016h,083h 1175 | db 0e3h,063h,00bh,012h 1176 | db 094h,064h,03bh,084h 1177 | db 00dh,06dh,06ah,03eh 1178 | db 07ah,06ah,05ah,0a8h 1179 | db 0e4h,00eh,0cfh,00bh 1180 | db 093h,009h,0ffh,09dh 1181 | db 00ah,000h,0aeh,027h 1182 | db 07dh,007h,09eh,0b1h 1183 | db 0f0h,00fh,093h,044h 1184 | db 087h,008h,0a3h,0d2h 1185 | db 01eh,001h,0f2h,068h 1186 | db 069h,006h,0c2h,0feh 1187 | db 0f7h,062h,057h,05dh 1188 | db 080h,065h,067h,0cbh 1189 | db 019h,06ch,036h,071h 1190 | db 06eh,06bh,006h,0e7h 1191 | db 0feh,0d4h,01bh,076h 1192 | db 089h,0d3h,02bh,0e0h 1193 | db 010h,0dah,07ah,05ah 1194 | db 067h,0ddh,04ah,0cch 1195 | db 0f9h,0b9h,0dfh,06fh 1196 | db 08eh,0beh,0efh,0f9h 1197 | db 017h,0b7h,0beh,043h 1198 | db 060h,0b0h,08eh,0d5h 1199 | db 0d6h,0d6h,0a3h,0e8h 1200 | db 0a1h,0d1h,093h,07eh 1201 | db 038h,0d8h,0c2h,0c4h 1202 | db 04fh,0dfh,0f2h,052h 1203 | db 0d1h,0bbh,067h,0f1h 1204 | db 0a6h,0bch,057h,067h 1205 | db 03fh,0b5h,006h,0ddh 1206 | db 048h,0b2h,036h,04bh 1207 | db 0d8h,00dh,02bh,0dah 1208 | db 0afh,00ah,01bh,04ch 1209 | db 036h,003h,04ah,0f6h 1210 | db 041h,004h,07ah,060h 1211 | db 0dfh,060h,0efh,0c3h 1212 | db 0a8h,067h,0dfh,055h 1213 | db 031h,06eh,08eh,0efh 1214 | db 046h,069h,0beh,079h 1215 | db 0cbh,061h,0b3h,08ch 1216 | db 0bch,066h,083h,01ah 1217 | db 025h,06fh,0d2h,0a0h 1218 | db 052h,068h,0e2h,036h 1219 | db 0cch,00ch,077h,095h 1220 | db 0bbh,00bh,047h,003h 1221 | db 022h,002h,016h,0b9h 1222 | db 055h,005h,026h,02fh 1223 | db 0c5h,0bah,03bh,0beh 1224 | db 0b2h,0bdh,00bh,028h 1225 | db 02bh,0b4h,05ah,092h 1226 | db 05ch,0b3h,06ah,004h 1227 | db 0c2h,0d7h,0ffh,0a7h 1228 | db 0b5h,0d0h,0cfh,031h 1229 | db 02ch,0d9h,09eh,08bh 1230 | db 05bh,0deh,0aeh,01dh 1231 | db 09bh,064h,0c2h,0b0h 1232 | db 0ech,063h,0f2h,026h 1233 | db 075h,06ah,0a3h,09ch 1234 | db 002h,06dh,093h,00ah 1235 | db 09ch,009h,006h,0a9h 1236 | db 0ebh,00eh,036h,03fh 1237 | db 072h,007h,067h,085h 1238 | db 005h,000h,057h,013h 1239 | db 095h,0bfh,04ah,082h 1240 | db 0e2h,0b8h,07ah,014h 1241 | db 07bh,0b1h,02bh,0aeh 1242 | db 00ch,0b6h,01bh,038h 1243 | db 092h,0d2h,08eh,09bh 1244 | db 0e5h,0d5h,0beh,00dh 1245 | db 07ch,0dch,0efh,0b7h 1246 | db 00bh,0dbh,0dfh,021h 1247 | db 086h,0d3h,0d2h,0d4h 1248 | db 0f1h,0d4h,0e2h,042h 1249 | db 068h,0ddh,0b3h,0f8h 1250 | db 01fh,0dah,083h,06eh 1251 | db 081h,0beh,016h,0cdh 1252 | db 0f6h,0b9h,026h,05bh 1253 | db 06fh,0b0h,077h,0e1h 1254 | db 018h,0b7h,047h,077h 1255 | db 088h,008h,05ah,0e6h 1256 | db 0ffh,00fh,06ah,070h 1257 | db 066h,006h,03bh,0cah 1258 | db 011h,001h,00bh,05ch 1259 | db 08fh,065h,09eh,0ffh 1260 | db 0f8h,062h,0aeh,069h 1261 | db 061h,06bh,0ffh,0d3h 1262 | db 016h,06ch,0cfh,045h 1263 | db 0a0h,00ah,0e2h,078h 1264 | db 0d7h,00dh,0d2h,0eeh 1265 | db 04eh,004h,083h,054h 1266 | db 039h,003h,0b3h,0c2h 1267 | db 0a7h,067h,026h,061h 1268 | db 0d0h,060h,016h,0f7h 1269 | db 049h,069h,047h,04dh 1270 | db 03eh,06eh,077h,0dbh 1271 | db 0aeh,0d1h,06ah,04ah 1272 | db 0d9h,0d6h,05ah,0dch 1273 | db 040h,0dfh,00bh,066h 1274 | db 037h,0d8h,03bh,0f0h 1275 | db 0a9h,0bch,0aeh,053h 1276 | db 0deh,0bbh,09eh,0c5h 1277 | db 047h,0b2h,0cfh,07fh 1278 | db 030h,0b5h,0ffh,0e9h 1279 | db 0bdh,0bdh,0f2h,01ch 1280 | db 0cah,0bah,0c2h,08ah 1281 | db 053h,0b3h,093h,030h 1282 | db 024h,0b4h,0a3h,0a6h 1283 | db 0bah,0d0h,036h,005h 1284 | db 0cdh,0d7h,006h,093h 1285 | db 054h,0deh,057h,029h 1286 | db 023h,0d9h,067h,0bfh 1287 | db 0b3h,066h,07ah,02eh 1288 | db 0c4h,061h,04ah,0b8h 1289 | db 05dh,068h,01bh,002h 1290 | db 02ah,06fh,02bh,094h 1291 | db 0b4h,00bh,0beh,037h 1292 | db 0c3h,00ch,08eh,0a1h 1293 | db 05ah,005h,0dfh,01bh 1294 | db 02dh,002h,0efh,08dh 1295 | 1296 | end 1297 | --------------------------------------------------------------------------------