# HG changeset patch # User Mike Pavone # Date 1368049248 25200 # Node ID b970ea214ecb4f42f5562085c805231f3a43e11c # Parent eea3b118940df52deb09c64f5548273e07918d86 Added z80 test generator and z80 test runner. diff -r eea3b118940d -r b970ea214ecb Makefile --- a/Makefile Mon May 06 00:57:56 2013 -0700 +++ b/Makefile Wed May 08 14:40:48 2013 -0700 @@ -25,6 +25,12 @@ transz80 : transz80.o z80inst.o gen_x86.o z80_to_x86.o x86_backend.o zruntime.o mem.o $(CC) -o transz80 transz80.o z80inst.o gen_x86.o z80_to_x86.o x86_backend.o zruntime.o mem.o +ztestrun : ztestrun.o z80inst.o gen_x86.o z80_to_x86.o x86_backend.o zruntime.o mem.o + $(CC) -o ztestrun ztestrun.o z80inst.o gen_x86.o z80_to_x86.o x86_backend.o zruntime.o mem.o + +ztestgen : ztestgen.o z80inst.o + $(CC) -o ztestgen ztestgen.o z80inst.o + stateview : stateview.o vdp.o render_sdl.o $(CC) -o stateview stateview.o vdp.o render_sdl.o `pkg-config --libs $(LIBS)` diff -r eea3b118940d -r b970ea214ecb z80_to_x86.c --- a/z80_to_x86.c Mon May 06 00:57:56 2013 -0700 +++ b/z80_to_x86.c Wed May 08 14:40:48 2013 -0700 @@ -47,54 +47,6 @@ return SZ_B; } -uint8_t z80_high_reg(uint8_t reg) -{ - switch(reg) - { - case Z80_C: - case Z80_BC: - return Z80_B; - case Z80_E: - case Z80_DE: - return Z80_D; - case Z80_L: - case Z80_HL: - return Z80_H; - case Z80_IXL: - case Z80_IX: - return Z80_IXH; - case Z80_IYL: - case Z80_IY: - return Z80_IYH; - default: - return Z80_UNUSED; - } -} - -uint8_t z80_low_reg(uint8_t reg) -{ - switch(reg) - { - case Z80_B: - case Z80_BC: - return Z80_C; - case Z80_D: - case Z80_DE: - return Z80_E; - case Z80_H: - case Z80_HL: - return Z80_L; - case Z80_IXH: - case Z80_IX: - return Z80_IXL; - case Z80_IYH: - case Z80_IY: - return Z80_IYL; - default: - return Z80_UNUSED; - } -} - uint8_t * zcycles(uint8_t * dst, uint32_t num_cycles) { return add_ir(dst, num_cycles, ZCYCLES, SZ_D); diff -r eea3b118940d -r b970ea214ecb z80inst.c --- a/z80inst.c Mon May 06 00:57:56 2013 -0700 +++ b/z80inst.c Wed May 08 14:40:48 2013 -0700 @@ -1459,3 +1459,76 @@ return len; } +uint8_t z80_high_reg(uint8_t reg) +{ + switch(reg) + { + case Z80_C: + case Z80_BC: + return Z80_B; + case Z80_E: + case Z80_DE: + return Z80_D; + case Z80_L: + case Z80_HL: + return Z80_H; + case Z80_IXL: + case Z80_IX: + return Z80_IXH; + case Z80_IYL: + case Z80_IY: + return Z80_IYH; + default: + return Z80_UNUSED; + } +} + +uint8_t z80_low_reg(uint8_t reg) +{ + switch(reg) + { + case Z80_B: + case Z80_BC: + return Z80_C; + case Z80_D: + case Z80_DE: + return Z80_E; + case Z80_H: + case Z80_HL: + return Z80_L; + case Z80_IXH: + case Z80_IX: + return Z80_IXL; + case Z80_IYH: + case Z80_IY: + return Z80_IYL; + default: + return Z80_UNUSED; + } +} + +uint8_t z80_word_reg(uint8_t reg) +{ + switch(reg) + { + case Z80_B: + case Z80_C: + return Z80_BC; + case Z80_D: + case Z80_E: + return Z80_DE; + case Z80_H: + case Z80_L: + return Z80_HL; + case Z80_IXH: + case Z80_IXL: + return Z80_IX; + case Z80_IYH: + case Z80_IYL: + return Z80_IY; + default: + return Z80_UNUSED; + } +} + + diff -r eea3b118940d -r b970ea214ecb z80inst.h --- a/z80inst.h Mon May 06 00:57:56 2013 -0700 +++ b/z80inst.h Wed May 08 14:40:48 2013 -0700 @@ -132,6 +132,9 @@ uint8_t * z80_decode(uint8_t * istream, z80inst * decoded); int z80_disasm(z80inst * decoded, char * dst); +uint8_t z80_high_reg(uint8_t reg); +uint8_t z80_low_reg(uint8_t reg); +uint8_t z80_word_reg(uint8_t reg); #endif //Z80INST_H_ diff -r eea3b118940d -r b970ea214ecb ztestgen.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ztestgen.c Wed May 08 14:40:48 2013 -0700 @@ -0,0 +1,332 @@ +#include "z80inst.h" +#include +#include +#include +#include +#include +#include +#include + +extern z80inst z80_tbl_a[256]; +extern z80inst z80_tbl_extd[0xC0-0x40]; +extern z80inst z80_tbl_bit[256]; +extern z80inst z80_tbl_ix[256]; +extern z80inst z80_tbl_iy[256]; +extern z80inst z80_tbl_ix_bit[256]; +extern z80inst z80_tbl_iy_bit[256]; +extern char *z80_mnemonics[Z80_OTDR+1]; +extern char * z80_regs[Z80_USE_IMMED]; +#define PRE_IX 0xDD +#define PRE_IY 0xFD +#define LD_IR16 0x01 +#define LD_IR8 0x06 +#define PUSH 0xC5 +#define POP 0xC1 + +uint8_t * ld_ir16(uint8_t * dst, uint8_t reg, uint16_t val) +{ + if (reg == Z80_IX) { + *(dst++) = PRE_IX; + return ld_ir16(dst, Z80_HL, val); + } else if(reg == Z80_IY) { + *(dst++) = PRE_IY; + return ld_ir16(dst, Z80_HL, val); + } else { + *(dst++) = LD_IR16 | ((reg - Z80_BC) << 4); + *(dst++) = val & 0xFF; + *(dst++) = val >> 8; + return dst; + } +} + +uint8_t * ld_ir8(uint8_t * dst, uint8_t reg, uint8_t val) +{ + if (reg <= Z80_H) { + reg = (reg - Z80_C) ^ 1; + } else { + reg = 0x7; + } + *(dst++) = LD_IR8 | (reg << 3); + *(dst++) = val; + return dst; +} + +uint8_t * ld_amem(uint8_t * dst, uint16_t address) +{ + *(dst++) = 0x32; + *(dst++) = address & 0xFF; + *(dst++) = address >> 8; + return dst; +} + +uint8_t * push(uint8_t * dst, uint8_t reg) +{ + if (reg == Z80_IX) { + *(dst++) = PRE_IX; + return push(dst, Z80_HL); + } else if(reg == Z80_IY) { + *(dst++) = PRE_IY; + return push(dst, Z80_HL); + } else { + if (reg == Z80_AF) { + reg--; + } + *(dst++) = PUSH | ((reg - Z80_BC) << 4); + return dst; + } +} + +uint8_t * pop(uint8_t * dst, uint8_t reg) +{ + if (reg == Z80_IX) { + *(dst++) = PRE_IX; + return pop(dst, Z80_HL); + } else if(reg == Z80_IY) { + *(dst++) = PRE_IY; + return pop(dst, Z80_HL); + } else { + if (reg == Z80_AF) { + reg--; + } + *(dst++) = POP | ((reg - Z80_BC) << 4); + return dst; + } +} + +void z80_gen_test(z80inst * inst, uint8_t *instbuf, uint8_t instlen) +{ + z80inst copy; + uint16_t reg_values[Z80_UNUSED]; + memset(reg_values, 0, sizeof(reg_values)); + uint8_t addr_mode = inst->addr_mode & 0x1F; + uint8_t word_sized = ((inst->reg != Z80_USE_IMMED && inst->reg != Z80_UNUSED && inst->reg >= Z80_BC) || (addr_mode == Z80_REG && inst->ea_reg >= Z80_BC)) ? 1 : 0; + + if (inst->reg == Z80_USE_IMMED || addr_mode == Z80_IMMED || addr_mode == Z80_IMMED_INDIRECT + || addr_mode == Z80_IX_DISPLACE || addr_mode == Z80_IY_DISPLACE) + { + memcpy(©, inst, sizeof(copy)); + inst = © + if ((inst->reg == Z80_USE_IMMED && inst->op != Z80_BIT && inst->op != Z80_RES && inst->op != Z80_SET) + || (addr_mode == Z80_IMMED && inst->op != Z80_IM)) + { + copy.immed = rand() % (word_sized ? 65536 : 256); + } + if (addr_mode == Z80_IX_DISPLACE || addr_mode == Z80_IY_DISPLACE) { + copy.ea_reg = rand() % 256; + } + if (addr_mode == Z80_IMMED_INDIRECT) { + copy.immed = 0x1000 + (rand() % 256 - 128); + } + } + uint8_t is_mem = 0; + uint16_t address; + int16_t offset; + switch(addr_mode) + { + case Z80_REG: + if (word_sized) { + reg_values[inst->ea_reg] = rand() % 65536; + reg_values[z80_high_reg(inst->ea_reg)] = reg_values[inst->ea_reg] >> 8; + reg_values[z80_low_reg(inst->ea_reg)] = reg_values[inst->ea_reg] & 0xFF; + } else { + reg_values[inst->ea_reg] = rand() % 256; + uint8_t word_reg = z80_word_reg(inst->ea_reg); + if (word_reg != Z80_UNUSED) { + reg_values[word_reg] = (reg_values[z80_high_reg(word_reg)] << 8) | (reg_values[z80_low_reg(word_reg)] & 0xFF); + } + } + break; + case Z80_REG_INDIRECT: + is_mem = 1; + reg_values[inst->ea_reg] = 0x1000 + (rand() % 256 - 128); + address = reg_values[inst->ea_reg]; + reg_values[z80_high_reg(inst->ea_reg)] = reg_values[inst->ea_reg] >> 8; + reg_values[z80_low_reg(inst->ea_reg)] = reg_values[inst->ea_reg] & 0xFF; + break; + case Z80_IMMED_INDIRECT: + is_mem = 1; + address = inst->immed; + break; + case Z80_IX_DISPLACE: + reg_values[Z80_IX] = 0x1000; + reg_values[Z80_IXH] = 0x10; + reg_values[Z80_IXL] = 0; + is_mem = 1; + offset = inst->ea_reg; + if (offset > 0x7F) { + offset -= 256; + } + address = 0x1000 + offset; + break; + case Z80_IY_DISPLACE: + reg_values[Z80_IY] = 0x1000; + reg_values[Z80_IYH] = 0x10; + reg_values[Z80_IYL] = 0; + is_mem = 1; + offset = inst->ea_reg; + if (offset > 0x7F) { + offset -= 256; + } + address = 0x1000 + offset; + break; + } + if (inst->reg != Z80_UNUSED && inst->reg != Z80_USE_IMMED) { + if (word_sized) { + reg_values[inst->reg] = rand() % 65536; + reg_values[z80_high_reg(inst->reg)] = reg_values[inst->reg] >> 8; + reg_values[z80_low_reg(inst->reg)] = reg_values[inst->reg] & 0xFF; + } else { + reg_values[inst->reg] = rand() % 255; + uint8_t word_reg = z80_word_reg(inst->reg); + if (word_reg != Z80_UNUSED) { + reg_values[word_reg] = (reg_values[z80_high_reg(word_reg)] << 8) | (reg_values[z80_low_reg(word_reg)] & 0xFF); + } + } + } + puts("--------------"); + for (uint8_t reg = 0; reg < Z80_UNUSED; reg++) { + if (reg_values[reg]) { + printf("%s: %X\n", z80_regs[reg], reg_values[reg]); + } + } + char disbuf[80]; + z80_disasm(inst, disbuf); + puts(disbuf); + char pathbuf[128]; + sprintf(pathbuf, "ztests/%s", z80_mnemonics[inst->op]); + if (mkdir(pathbuf, 0777) != 0) { + if (errno != EEXIST) { + fprintf(stderr, "Failed to create directory %s\n", disbuf); + exit(1); + } + } + uint8_t prog[200]; + uint8_t *cur = prog; + uint8_t mem_val; + //disable interrupts + *(cur++) = 0xF3; + //setup SP + cur = ld_ir16(cur, Z80_SP, 0x2000); + //setup memory + if (is_mem) { + mem_val = rand() % 256; + cur = ld_ir8(cur, Z80_A, mem_val); + cur = ld_amem(cur, address); + } + //setup AF + cur = ld_ir16(cur, Z80_BC, reg_values[Z80_A] << 8); + cur = push(cur, Z80_BC); + cur = pop(cur, Z80_AF); + + //setup other regs + for (uint8_t reg = Z80_BC; reg <= Z80_IY; reg++) { + if (reg != Z80_AF && reg != Z80_SP) { + cur = ld_ir16(cur, reg, reg_values[reg]); + } + } + + //copy instruction + memcpy(cur, instbuf, instlen); + cur += instlen; + + //immed/displacement byte(s) + if (addr_mode == Z80_IX_DISPLACE || addr_mode == Z80_IY_DISPLACE) { + *(cur++) = inst->ea_reg; + } else if (addr_mode == Z80_IMMED & inst->op != Z80_IM) { + *(cur++) = inst->immed & 0xFF; + if (word_sized) { + *(cur++) = inst->immed >> 8; + } + } else if (addr_mode == Z80_IMMED_INDIRECT) { + *(cur++) = inst->immed & 0xFF; + *(cur++) = inst->immed >> 8; + } + if (inst->reg == Z80_USE_IMMED && inst->op != Z80_BIT && inst->op != Z80_RES && inst->op != Z80_SET) { + *(cur++) = inst->immed & 0xFF; + } + + for (char * cur = disbuf; *cur != 0; cur++) { + if (*cur == ',' || *cur == ' ') { + *cur = '_'; + } + } + //halt + *(cur++) = 0x76; + sprintf(pathbuf + strlen(pathbuf), "/%s.bin", disbuf); + FILE * progfile = fopen(pathbuf, "wb"); + fwrite(prog, 1, cur - prog, progfile); + fclose(progfile); +} + + +uint8_t should_skip(z80inst * inst) +{ + return inst->op >= Z80_JP || (inst->op >= Z80_LDI && inst->op <= Z80_CPDR) || inst->op == Z80_HALT + || inst->op == Z80_DAA || inst->op == Z80_RLD || inst->op == Z80_RRD || inst->op == Z80_NOP + || inst->op == Z80_DI || inst->op == Z80_EI; +} + +void z80_gen_all() +{ + uint8_t inst[3]; + for (int op = 0; op < 256; op++) { + inst[0] = op; + if (op == 0xCB) { + for (int subop = 0; subop < 256; subop++) { + if (!should_skip(z80_tbl_bit + subop)) { + inst[1] = subop; + z80_gen_test(z80_tbl_bit + subop, inst, 2); + } + } + } else if(op == 0xDD) { + for (int ixop = 0; ixop < 256; ixop++) { + inst[1] = ixop; + if (ixop == 0xCB) { + for (int subop = 0; subop < 256; subop++) { + if (!should_skip(z80_tbl_ix_bit + subop)) { + inst[2] = subop; + z80_gen_test(z80_tbl_ix_bit + subop, inst, 3); + } + } + } else { + if (!should_skip(z80_tbl_ix + ixop)) { + z80_gen_test(z80_tbl_ix + ixop, inst, 2); + } + } + } + } else if(op == 0xED) { + for (int subop = 0; subop < sizeof(z80_tbl_extd)/sizeof(z80inst); subop++) { + if (!should_skip(z80_tbl_extd + subop)) { + inst[1] = subop; + z80_gen_test(z80_tbl_extd + subop, inst, 2); + } + } + } else if(op == 0xFD) { + for (int iyop = 0; iyop < 256; iyop++) { + inst[1] = iyop; + if (iyop == 0xCB) { + for (int subop = 0; subop < 256; subop++) { + if (!should_skip(z80_tbl_iy_bit + subop)) { + inst[2] = subop; + z80_gen_test(z80_tbl_iy_bit + subop, inst, 3); + } + } + } else { + if (!should_skip(z80_tbl_iy + iyop)) { + z80_gen_test(z80_tbl_iy + iyop, inst, 2); + } + } + } + } else { + if (!should_skip(z80_tbl_a + op)) { + z80_gen_test(z80_tbl_a + op, inst, 1); + } + } + } +} + +int main(int argc, char ** argv) +{ + z80_gen_all(); + return 0; +} diff -r eea3b118940d -r b970ea214ecb ztestrun.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ztestrun.c Wed May 08 14:40:48 2013 -0700 @@ -0,0 +1,92 @@ +#include "z80inst.h" +#include "z80_to_x86.h" +#include "mem.h" +#include "vdp.h" +#include +#include + +uint8_t z80_ram[0x2000]; +uint16_t cart[0x200000]; + +#define MCLKS_PER_Z80 15 +//TODO: Figure out the exact value for this +#define MCLKS_PER_FRAME (MCLKS_LINE*262) +#define VINT_CYCLE ((MCLKS_LINE * 226)/MCLKS_PER_Z80) +#define CYCLE_NEVER 0xFFFFFFFF + +uint8_t z80_read_ym(uint16_t location, z80_context * context) +{ + return 0xFF; +} + +z80_context * z80_write_ym(uint16_t location, z80_context * context, uint8_t value) +{ + return context; +} + +int main(int argc, char ** argv) +{ + long filesize; + uint8_t *filebuf; + x86_z80_options opts; + z80_context context; + if (argc < 2) { + fputs("usage: transz80 zrom [cartrom]\n", stderr); + exit(1); + } + FILE * f = fopen(argv[1], "rb"); + if (!f) { + fprintf(stderr, "unable to open file %s\n", argv[2]); + exit(1); + } + fseek(f, 0, SEEK_END); + filesize = ftell(f); + fseek(f, 0, SEEK_SET); + fread(z80_ram, 1, filesize < sizeof(z80_ram) ? filesize : sizeof(z80_ram), f); + fclose(f); + if (argc > 2) { + f = fopen(argv[2], "rb"); + if (!f) { + fprintf(stderr, "unable to open file %s\n", argv[2]); + exit(1); + } + fseek(f, 0, SEEK_END); + filesize = ftell(f); + fseek(f, 0, SEEK_SET); + fread(cart, 1, filesize < sizeof(cart) ? filesize : sizeof(cart), f); + fclose(f); + for(unsigned short * cur = cart; cur - cart < (filesize/2); ++cur) + { + *cur = (*cur >> 8) | (*cur << 8); + } + } + init_x86_z80_opts(&opts); + init_z80_context(&context, &opts); + //Z80 RAM + context.mem_pointers[0] = z80_ram; + context.sync_cycle = context.target_cycle = 1000; + context.int_cycle = CYCLE_NEVER; + //cartridge/bank + context.mem_pointers[1] = context.mem_pointers[2] = (uint8_t *)cart; + z80_reset(&context); + while (context.current_cycle < 1000) { + z80_run(&context); + } + printf("A: %X\nB: %X\nC: %X\nD: %X\nE: %X\nHL: %X\nIX: %X\nIY: %X\nSP: %X\n\nIM: %d, IFF1: %d, IFF2: %d\n", + context.regs[Z80_A], context.regs[Z80_B], context.regs[Z80_C], + context.regs[Z80_D], context.regs[Z80_E], + (context.regs[Z80_H] << 8) | context.regs[Z80_L], + (context.regs[Z80_IXH] << 8) | context.regs[Z80_IXL], + (context.regs[Z80_IYH] << 8) | context.regs[Z80_IYL], + context.sp, context.im, context.iff1, context.iff2); + printf("Flags: SZVNC\n" + " %d%d%d%d%d\n", context.flags[ZF_S], context.flags[ZF_Z], context.flags[ZF_PV], context.flags[ZF_N], context.flags[ZF_C]); + puts("--Alternate Regs--"); + printf("A: %X\nB: %X\nC: %X\nD: %X\nE: %X\nHL: %X\nIX: %X\nIY: %X\n", + context.alt_regs[Z80_A], context.alt_regs[Z80_B], context.alt_regs[Z80_C], + context.alt_regs[Z80_D], context.alt_regs[Z80_E], + (context.alt_regs[Z80_H] << 8) | context.alt_regs[Z80_L], + (context.alt_regs[Z80_IXH] << 8) | context.alt_regs[Z80_IXL], + (context.alt_regs[Z80_IYH] << 8) | context.alt_regs[Z80_IYL]); + return 0; +}