# HG changeset patch # User Michael Pavone # Date 1419995494 28800 # Node ID f822d92169685bbcb6566585adf1e18151352da3 # Parent 9d6fed6501baf2592e6cf65752a21568d9caf6bf# Parent 103d5cabbe144d61820ed6a37f40be500180725c Merge diff -r 9d6fed6501ba -r f822d9216968 .hgignore --- a/.hgignore Mon Dec 29 23:08:39 2014 -0800 +++ b/.hgignore Tue Dec 30 19:11:34 2014 -0800 @@ -17,6 +17,7 @@ generated_tests/* ztests/* *.o +*.list blastem dis stateview diff -r 9d6fed6501ba -r f822d9216968 68kinst.c --- a/68kinst.c Mon Dec 29 23:08:39 2014 -0800 +++ b/68kinst.c Tue Dec 30 19:11:34 2014 -0800 @@ -19,7 +19,7 @@ uint16_t *m68k_decode_op_ex(uint16_t *cur, uint8_t mode, uint8_t reg, uint8_t size, m68k_op_info *dst) { - uint16_t ext; + uint16_t ext, tmp; dst->addr_mode = mode; switch(mode) { @@ -36,15 +36,95 @@ dst->params.regs.displacement = sign_extend16(ext); break; case MODE_AREG_INDEX_MEM: - #ifdef M68020 - //TODO: implement me for M68020+ support - #else + dst->params.regs.pri = reg; + ext = *(++cur); + dst->params.regs.sec = ext >> 11;//includes areg/dreg bit, reg num and word/long bit +#ifdef M68020 + dst->params.regs.scale = ext >> 9 & 3; + if (ext & 0x100) + { + dst->params.regs.disp_sizes = ext >> 4 & 3; + switch (dst->params.regs.disp_sizes) + { + case 0: + //reserved + return NULL; + case 1: + dst->params.regs.displacement = 0; + break; + case 2: + dst->params.regs.displacement = sign_extend16(*(cur++)); + break; + case 3: + tmp = *(cur++); + dst->params.regs.displacement = tmp << 16 | *(cur++); + break; + } + if (ext & 0x3) + { + //memory indirect + switch (ext & 0xC4) + { + case 0x00: + dst->addr_mode = MODE_AREG_PREINDEX; + break; + case 0x04: + dst->addr_mode = MODE_AREG_POSTINDEX; + break; + case 0x40: + dst->addr_mode = MODE_AREG_MEM_INDIRECT; + break; + case 0x80: + dst->addr_mode = MODE_PREINDEX; + break; + case 0x84: + dst->addr_mode = MODE_POSTINDEX; + break; + case 0xC0: + dst->addr_mode = MODE_MEM_INDIRECT; + break; + } + dst->params.regs.disp_sizes |= ext << 4 & 0x30; + switch (ext & 0x3) + { + case 0: + //reserved + return NULL; + case 1: + dst->params.regs.outer_disp = 0; + break; + case 2: + dst->params.regs.outer_disp = sign_extend16(*(cur++)); + break; + case 3: + tmp = *(cur++); + dst->params.regs.outer_disp = tmp << 16 | *(cur++); + break; + } + } else { + switch (ext >> 6 & 3) + { + case 0: + dst->addr_mode = MODE_AREG_INDEX_BASE_DISP; + break; + case 1: + dst->addr_mode = MODE_AREG_BASE_DISP; + break; + case 2: + dst->addr_mode = MODE_INDEX_BASE_DISP; + break; + case 3: + dst->addr_mode = MODE_BASE_DISP; + break; + } + } + } else { +#endif dst->addr_mode = MODE_AREG_INDEX_DISP8; - dst->params.regs.pri = reg; - ext = *(++cur); - dst->params.regs.sec = ext >> 11;//includes areg/dreg bit, reg num and word/long bit dst->params.regs.displacement = sign_extend8(ext&0xFF); - #endif +#ifdef M68020 + } +#endif break; case MODE_PC_INDIRECT_ABS_IMMED: switch(reg) @@ -60,13 +140,93 @@ dst->params.immed = ext << 16 | *(++cur); break; case 3: -#ifdef M68020 - //TODO: Implement me for M68020+ support; -#else - dst->addr_mode = MODE_PC_INDEX_DISP8; ext = *(++cur); dst->params.regs.sec = ext >> 11;//includes areg/dreg bit, reg num and word/long bit - dst->params.regs.displacement = sign_extend8(ext&0xFF); +#ifdef M68020 + dst->params.regs.scale = ext >> 9 & 3; + if (ext & 0x100) + { + dst->params.regs.disp_sizes = ext >> 4 & 3; + switch (dst->params.regs.disp_sizes) + { + case 0: + //reserved + return NULL; + case 1: + dst->params.regs.displacement = 0; + break; + case 2: + dst->params.regs.displacement = sign_extend16(*(cur++)); + break; + case 3: + tmp = *(cur++); + dst->params.regs.displacement = tmp << 16 | *(cur++); + break; + } + if (ext & 0x3) + { + //memory indirect + switch (ext & 0xC4) + { + case 0x00: + dst->addr_mode = MODE_PC_PREINDEX; + break; + case 0x04: + dst->addr_mode = MODE_PC_POSTINDEX; + break; + case 0x40: + dst->addr_mode = MODE_PC_MEM_INDIRECT; + break; + case 0x80: + dst->addr_mode = MODE_ZPC_PREINDEX; + break; + case 0x84: + dst->addr_mode = MODE_ZPC_POSTINDEX; + break; + case 0xC0: + dst->addr_mode = MODE_ZPC_MEM_INDIRECT; + break; + } + dst->params.regs.disp_sizes |= ext << 4 & 0x30; + switch (ext & 0x3) + { + case 0: + //reserved + return NULL; + case 1: + dst->params.regs.outer_disp = 0; + break; + case 2: + dst->params.regs.outer_disp = sign_extend16(*(cur++)); + break; + case 3: + tmp = *(cur++); + dst->params.regs.outer_disp = tmp << 16 | *(cur++); + break; + } + } else { + switch (ext >> 6 & 3) + { + case 0: + dst->addr_mode = MODE_PC_INDEX_BASE_DISP; + break; + case 1: + dst->addr_mode = MODE_PC_BASE_DISP; + break; + case 2: + dst->addr_mode = MODE_ZPC_INDEX_BASE_DISP; + break; + case 3: + dst->addr_mode = MODE_ZPC_BASE_DISP; + break; + } + } + } else { +#endif + dst->addr_mode = MODE_PC_INDEX_DISP8; + dst->params.regs.displacement = sign_extend8(ext&0xFF); +#ifdef M68020 + } #endif break; case 2: @@ -172,7 +332,7 @@ istream = m68k_decode_op(istream, decoded->extra.size, &(decoded->dst)); if (!istream) { decoded->op = M68K_INVALID; - return start+1; + break; } if (decoded->dst.addr_mode == MODE_REG) { decoded->extra.size = OPSIZE_LONG; @@ -202,7 +362,7 @@ istream = m68k_decode_op_ex(istream, opmode, reg, decoded->extra.size, &(decoded->dst)); if (!istream) { decoded->op = M68K_INVALID; - return start+1; + break; } if (decoded->dst.addr_mode == MODE_REG) { decoded->extra.size = OPSIZE_LONG; @@ -248,7 +408,7 @@ istream = m68k_decode_op_ex(istream, opmode, reg, size, &(decoded->dst)); if (!istream) { decoded->op = M68K_INVALID; - return start+1; + break; } } break; @@ -287,7 +447,7 @@ istream = m68k_decode_op_ex(istream, opmode, reg, size, &(decoded->dst)); if (!istream) { decoded->op = M68K_INVALID; - return start+1; + break; } } break; @@ -314,7 +474,7 @@ istream = m68k_decode_op_ex(istream, opmode, reg, size, &(decoded->dst)); if (!istream) { decoded->op = M68K_INVALID; - return start+1; + break; } break; case 3: @@ -340,7 +500,7 @@ istream = m68k_decode_op_ex(istream, opmode, reg, size, &(decoded->dst)); if (!istream) { decoded->op = M68K_INVALID; - return start+1; + break; } break; case 4: @@ -365,7 +525,7 @@ istream = m68k_decode_op(istream, OPSIZE_BYTE, &(decoded->dst)); if (!istream) { decoded->op = M68K_INVALID; - return start+1; + break; } break; case 5: @@ -403,7 +563,7 @@ istream = m68k_decode_op_ex(istream, opmode, reg, size, &(decoded->dst)); if (!istream) { decoded->op = M68K_INVALID; - return start+1; + break; } } break; @@ -427,15 +587,29 @@ decoded->src.params.immed = (immed << 16) | *(++istream); break; } - istream = m68k_decode_op_ex(istream, opmode, reg, size, &(decoded->dst)); + istream = m68k_decode_op_ex(istream, opmode, reg, decoded->extra.size, &(decoded->dst)); if (!istream) { decoded->op = M68K_INVALID; - return start+1; + break; } break; case 7: - - +#ifdef M68010 + decoded->op = M68K_MOVES; + decoded->extra.size = *istream >> 6 & 0x3; + immed = *(++istream); + reg = immed >> 12 & 0x7; + opmode = immed & 0x8000 ? MODE_AREG : MODE_REG; + if (immed & 0x800) { + decoded->src.addr_mode = opmode; + decoded->src.params.regs.pri = reg; + m68k_decode_op_ex(istream, *start >> 3 & 0x7, *start & 0x7, decoded->extra.size, &(decoded->dst)); + } else { + m68k_decode_op_ex(istream, *start >> 3 & 0x7, *start & 0x7, decoded->extra.size, &(decoded->src)); + decoded->dst.addr_mode = opmode; + decoded->dst.params.regs.pri = reg; + } +#endif break; } } @@ -450,12 +624,12 @@ istream = m68k_decode_op(istream, decoded->extra.size, &(decoded->src)); if (!istream) { decoded->op = M68K_INVALID; - return start+1; + break; } istream = m68k_decode_op_ex(istream, opmode, reg, decoded->extra.size, &(decoded->dst)); if (!istream || decoded->dst.addr_mode == MODE_IMMEDIATE) { decoded->op = M68K_INVALID; - return start+1; + break; } break; case MISC: @@ -468,7 +642,7 @@ istream = m68k_decode_op(istream, decoded->extra.size, &(decoded->src)); if (!istream) { decoded->op = M68K_INVALID; - return start+1; + break; } } else { if (*istream & 0x100) { @@ -489,7 +663,7 @@ istream = m68k_decode_op(istream, decoded->extra.size, &(decoded->src)); if (!istream) { decoded->op = M68K_INVALID; - return start+1; + break; } } else { opmode = (*istream >> 3) & 0x7; @@ -504,7 +678,7 @@ istream = m68k_decode_op_ex(istream, opmode, reg, decoded->extra.size, &(decoded->src)); if (!istream) { decoded->op = M68K_INVALID; - return start+1; + break; } if (decoded->src.addr_mode == MODE_PC_DISPLACE || decoded->src.addr_mode == MODE_PC_INDEX_DISP8) { //adjust displacement to account for extra instruction word @@ -516,7 +690,7 @@ istream = m68k_decode_op_ex(istream, opmode, reg, decoded->extra.size, &(decoded->dst)); if (!istream) { decoded->op = M68K_INVALID; - return start+1; + break; } } } else { @@ -536,7 +710,7 @@ istream= m68k_decode_op(istream, size, &(decoded->dst)); if (!istream) { decoded->op = M68K_INVALID; - return start+1; + break; } break; case 1: @@ -546,7 +720,7 @@ decoded->op = M68K_MOVE_FROM_CCR; size = OPSIZE_WORD; #else - return istream+1; + break; #endif } else { decoded->op = M68K_CLR; @@ -555,7 +729,7 @@ istream= m68k_decode_op(istream, size, &(decoded->dst)); if (!istream) { decoded->op = M68K_INVALID; - return start+1; + break; } break; case 2: @@ -566,14 +740,14 @@ istream= m68k_decode_op(istream, size, &(decoded->src)); if (!istream) { decoded->op = M68K_INVALID; - return start+1; + break; } } else { decoded->op = M68K_NEG; istream= m68k_decode_op(istream, size, &(decoded->dst)); if (!istream) { decoded->op = M68K_INVALID; - return start+1; + break; } } decoded->extra.size = size; @@ -586,14 +760,14 @@ istream= m68k_decode_op(istream, size, &(decoded->src)); if (!istream) { decoded->op = M68K_INVALID; - return start+1; + break; } } else { decoded->op = M68K_NOT; istream= m68k_decode_op(istream, size, &(decoded->dst)); if (!istream) { decoded->op = M68K_INVALID; - return start+1; + break; } } decoded->extra.size = size; @@ -648,7 +822,7 @@ istream = m68k_decode_op(istream, OPSIZE_BYTE, &(decoded->dst)); if (!istream) { decoded->op = M68K_INVALID; - return start+1; + break; } } else if((*istream & 0x1C0) == 0x40) { decoded->op = M68K_PEA; @@ -656,7 +830,7 @@ istream = m68k_decode_op(istream, OPSIZE_LONG, &(decoded->src)); if (!istream) { decoded->op = M68K_INVALID; - return start+1; + break; } } } @@ -678,7 +852,7 @@ istream = m68k_decode_op(istream, decoded->extra.size, &(decoded->src)); if (!istream) { decoded->op = M68K_INVALID; - return start+1; + break; } } } @@ -702,7 +876,7 @@ istream = m68k_decode_op(istream, OPSIZE_UNSIZED, &(decoded->src)); if (!istream) { decoded->op = M68K_INVALID; - return start+1; + break; } } else { //it would appear bit 6 needs to be set for it to be a valid instruction here @@ -783,6 +957,33 @@ case 7: //MOVEC #ifdef M68010 + decoded->op = M68K_MOVEC; + immed = *(++istream); + reg = immed >> 12 & 0x7; + opmode = immed & 0x8000 ? MODE_AREG : MODE_REG; + immed &= 0xFFF; + if (immed & 0x800) { + if (immed > MAX_HIGH_CR) { + decoded->op = M68K_INVALID; + break; + } else { + immed = immed - 0x800 + CR_USP; + } + } else { + if (immed > MAX_LOW_CR) { + decoded->op = M68K_INVALID; + break; + } + } + if (*start & 1) { + decoded->src.addr_mode = opmode; + decoded->src.params.regs.pri = reg; + decoded->dst.params.immed = immed; + } else { + decoded->dst.addr_mode = opmode; + decoded->dst.params.regs.pri = reg; + decoded->src.params.immed = immed; + } #endif break; } @@ -816,7 +1017,7 @@ istream = m68k_decode_op(istream, OPSIZE_BYTE, &(decoded->dst)); if (!istream) { decoded->op = M68K_INVALID; - return start+1; + break; } } } else { @@ -837,7 +1038,7 @@ istream = m68k_decode_op(istream, size, &(decoded->dst)); if (!istream) { decoded->op = M68K_INVALID; - return start+1; + break; } } break; @@ -865,7 +1066,7 @@ case MOVEQ: if (*istream & 0x100) { decoded->op = M68K_INVALID; - return start+1; + break; } decoded->op = M68K_MOVE; decoded->variant = VAR_QUICK; @@ -891,7 +1092,7 @@ istream = m68k_decode_op(istream, OPSIZE_WORD, &(decoded->src)); if (!istream || decoded->src.addr_mode == MODE_AREG) { decoded->op = M68K_INVALID; - return start+1; + break; } break; case 4: @@ -917,7 +1118,7 @@ istream = m68k_decode_op(istream, OPSIZE_WORD, &(decoded->src)); if (!istream || decoded->src.addr_mode == MODE_AREG) { decoded->op = M68K_INVALID; - return start+1; + break; } break; } @@ -930,7 +1131,7 @@ istream = m68k_decode_op(istream, size, &(decoded->dst)); if (!istream) { decoded->op = M68K_INVALID; - return start+1; + break; } } else { decoded->dst.addr_mode = MODE_REG; @@ -938,7 +1139,7 @@ istream = m68k_decode_op(istream, size, &(decoded->src)); if (!istream) { decoded->op = M68K_INVALID; - return start+1; + break; } } } @@ -957,7 +1158,7 @@ istream = m68k_decode_op(istream, OPSIZE_LONG, &(decoded->src)); if (!istream) { decoded->op = M68K_INVALID; - return start+1; + break; } } else { decoded->extra.size = size; @@ -966,7 +1167,7 @@ istream = m68k_decode_op(istream, size, &(decoded->dst)); if (!istream) { decoded->op = M68K_INVALID; - return start+1; + break; } } } else { @@ -994,7 +1195,7 @@ istream = m68k_decode_op(istream, decoded->extra.size, &(decoded->src)); if (!istream) { decoded->op = M68K_INVALID; - return start+1; + break; } } break; @@ -1012,14 +1213,14 @@ istream = m68k_decode_op(istream, decoded->extra.size, &(decoded->src)); if (!istream) { decoded->op = M68K_INVALID; - return start+1; + break; } } else { reg = m68k_reg_quick_field(*istream); istream = m68k_decode_op(istream, size, &(decoded->dst)); if (!istream) { decoded->op = M68K_INVALID; - return start+1; + break; } decoded->extra.size = size; if (decoded->dst.addr_mode == MODE_AREG) { @@ -1047,7 +1248,7 @@ istream = m68k_decode_op(istream, decoded->extra.size, &(decoded->src)); if (!istream) { decoded->op = M68K_INVALID; - return start+1; + break; } } break; @@ -1070,7 +1271,7 @@ istream = m68k_decode_op(istream, OPSIZE_WORD, &(decoded->src)); if (!istream) { decoded->op = M68K_INVALID; - return start+1; + break; } } else if(!(*istream & 0xF0)) { decoded->op = M68K_ABCD; @@ -1101,7 +1302,7 @@ istream = m68k_decode_op(istream, decoded->extra.size, &(decoded->dst)); if (!istream) { decoded->op = M68K_INVALID; - return start+1; + break; } } } else { @@ -1113,7 +1314,7 @@ istream = m68k_decode_op(istream, OPSIZE_WORD, &(decoded->src)); if (!istream) { decoded->op = M68K_INVALID; - return start+1; + break; } } else { decoded->op = M68K_AND; @@ -1123,7 +1324,7 @@ istream = m68k_decode_op(istream, decoded->extra.size, &(decoded->src)); if (!istream) { decoded->op = M68K_INVALID; - return start+1; + break; } } } @@ -1142,7 +1343,7 @@ istream = m68k_decode_op(istream, OPSIZE_LONG, &(decoded->src)); if (!istream) { decoded->op = M68K_INVALID; - return start+1; + break; } } else { decoded->extra.size = size; @@ -1151,7 +1352,7 @@ istream = m68k_decode_op(istream, size, &(decoded->dst)); if (!istream) { decoded->op = M68K_INVALID; - return start+1; + break; } } } else { @@ -1179,7 +1380,7 @@ istream = m68k_decode_op(istream, decoded->extra.size, &(decoded->src)); if (!istream) { decoded->op = M68K_INVALID; - return start+1; + break; } } break; @@ -1216,7 +1417,7 @@ istream = m68k_decode_op(istream, OPSIZE_WORD, &(decoded->dst)); if (!istream) { decoded->op = M68K_INVALID; - return start+1; + break; } } else if((*istream & 0xC0) != 0xC0) { switch(((*istream >> 2) & 0x6) | ((*istream >> 8) & 1)) @@ -1264,6 +1465,56 @@ } else { #ifdef M68020 //TODO: Implement bitfield instructions for M68020+ support + switch (*istream >> 8 & 7) + { + case 0: + decoded->op = M68K_BFTST; // + break; + case 1: + decoded->op = M68K_BFEXTU; //, Dn + break; + case 2: + decoded->op = M68K_BFCHG; // + break; + case 3: + decoded->op = M68K_BFEXTS; //, Dn + break; + case 4: + decoded->op = M68K_BFCLR; // + break; + case 5: + decoded->op = M68K_BFFFO; //, Dn + break; + case 6: + decoded->op = M68K_BFSET; // + break; + case 7: + decoded->op = M68K_BFINS; //Dn, + break; + } + opmode = *istream >> 3 & 0x7; + reg = *istream & 0x7; + m68k_op_info *ea, *other; + if (decoded->op == M68K_BFEXTU || decoded->op == M68K_BFEXTS || decoded->op == M68K_BFFFO) + { + ea = &(decoded->src); + other = &(decoded->dst); + } else { + ea = &(decoded->dst); + other = &(decoded->dst); + } + if (*istream & 0x100) + { + immed = *(istream++); + other->addr_mode = MODE_REG; + other->params.regs.pri = immed >> 12 & 0x7; + } else { + immed = *(istream++); + } + decoded->extra.size = OPSIZE_UNSIZED; + istream = m68k_decode_op_ex(istream, opmode, reg, decoded->extra.size, ea); + ea->addr_mode |= M68K_FLAG_BITFIELD; + ea->bitfield = immed & 0xFFF; #endif } break; @@ -1271,6 +1522,10 @@ //TODO: Implement me break; } + if (decoded->op == M68K_INVALID) { + decoded->src.params.immed = *start; + return start + 1; + } return istream+1; } @@ -1417,7 +1672,43 @@ "trapv", "tst", "unlk", - "invalid" + "invalid", +#ifdef M68010 + "bkpt", + "move", //from ccr + "movec", + "moves", + "rtd", +#endif +#ifdef M68020 + "bfchg", + "bfclr", + "bfexts", + "bfextu", + "bfffo", + "bfins", + "bfset", + "bftst", + "callm", + "cas", + "cas2", + "chk2", + "cmp2", + "cpbcc", + "cpdbcc", + "cpgen", + "cprestore", + "cpsave", + "cpscc", + "cptrapcc", + "divsl", + "divul", + "extb", + "pack", + "rtm", + "trapcc", + "unpk" +#endif }; char * cond_mnem[] = { @@ -1438,55 +1729,651 @@ "gt", "le" }; +#ifdef M68010 +char * cr_mnem[] = { + "SFC", + "DFC", +#ifdef M68020 + "CACR", +#endif + "USP", + "VBR", +#ifdef M68020 + "CAAR", + "MSP", + "ISP" +#endif +}; +#endif -int m68k_disasm_op(m68k_op_info *decoded, char *dst, int need_comma, uint8_t labels, uint32_t address) +int m68k_disasm_op(m68k_op_info *decoded, char *dst, int need_comma, uint8_t labels, uint32_t address, format_label_fun label_fun, void * data) { char * c = need_comma ? "," : ""; - switch(decoded->addr_mode) + int ret = 0; +#ifdef M68020 + uint8_t addr_mode = decoded->addr_mode & (~M68K_FLAG_BITFIELD); +#else + uint8_t addr_mode = decoded->addr_mode; +#endif + switch(addr_mode) { case MODE_REG: - return sprintf(dst, "%s d%d", c, decoded->params.regs.pri); + ret = sprintf(dst, "%s d%d", c, decoded->params.regs.pri); + break; case MODE_AREG: - return sprintf(dst, "%s a%d", c, decoded->params.regs.pri); + ret = sprintf(dst, "%s a%d", c, decoded->params.regs.pri); + break; case MODE_AREG_INDIRECT: - return sprintf(dst, "%s (a%d)", c, decoded->params.regs.pri); + ret = sprintf(dst, "%s (a%d)", c, decoded->params.regs.pri); + break; case MODE_AREG_POSTINC: - return sprintf(dst, "%s (a%d)+", c, decoded->params.regs.pri); + ret = sprintf(dst, "%s (a%d)+", c, decoded->params.regs.pri); + break; case MODE_AREG_PREDEC: - return sprintf(dst, "%s -(a%d)", c, decoded->params.regs.pri); + ret = sprintf(dst, "%s -(a%d)", c, decoded->params.regs.pri); + break; case MODE_AREG_DISPLACE: - return sprintf(dst, "%s (%d, a%d)", c, decoded->params.regs.displacement, decoded->params.regs.pri); + ret = sprintf(dst, "%s (%d, a%d)", c, decoded->params.regs.displacement, decoded->params.regs.pri); + break; case MODE_AREG_INDEX_DISP8: - return sprintf(dst, "%s (%d, a%d, %c%d.%c)", c, decoded->params.regs.displacement, decoded->params.regs.pri, (decoded->params.regs.sec & 0x10) ? 'a': 'd', (decoded->params.regs.sec >> 1) & 0x7, (decoded->params.regs.sec & 1) ? 'l': 'w'); +#ifdef M68020 + if (decoded->params.regs.scale) + { + ret = sprintf(dst, "%s (%d, a%d, %c%d.%c*%d)", c, decoded->params.regs.displacement, decoded->params.regs.pri, (decoded->params.regs.sec & 0x10) ? 'a': 'd', (decoded->params.regs.sec >> 1) & 0x7, (decoded->params.regs.sec & 1) ? 'l': 'w', 1 << decoded->params.regs.scale); + } else { +#endif + ret = sprintf(dst, "%s (%d, a%d, %c%d.%c)", c, decoded->params.regs.displacement, decoded->params.regs.pri, (decoded->params.regs.sec & 0x10) ? 'a': 'd', (decoded->params.regs.sec >> 1) & 0x7, (decoded->params.regs.sec & 1) ? 'l': 'w'); +#ifdef M68020 + } +#endif + break; +#ifdef M68020 + case MODE_AREG_INDEX_BASE_DISP: + if (decoded->params.regs.disp_sizes > 1) + { + ret = sprintf(dst, "%s (%d.%c, a%d, %c%d.%c*%d)", c, decoded->params.regs.displacement, + decoded->params.regs.disp_sizes == 2 ? 'w' : 'l', decoded->params.regs.pri, + (decoded->params.regs.sec & 0x10) ? 'a': 'd', (decoded->params.regs.sec >> 1) & 0x7, + (decoded->params.regs.sec & 1) ? 'l': 'w', 1 << decoded->params.regs.scale); + } else { + ret = sprintf(dst, "%s (a%d, %c%d.%c*%d)", c, decoded->params.regs.pri, + (decoded->params.regs.sec & 0x10) ? 'a': 'd', (decoded->params.regs.sec >> 1) & 0x7, + (decoded->params.regs.sec & 1) ? 'l': 'w', 1 << decoded->params.regs.scale); + } + break; + case MODE_AREG_PREINDEX: + switch (decoded->params.regs.disp_sizes) + { + case 0x11: + //no base displacement or outer displacement + ret = sprintf(dst, "%s ([a%d, %c%d.%c*%d])", c, decoded->params.regs.pri, + (decoded->params.regs.sec & 0x10) ? 'a': 'd', (decoded->params.regs.sec >> 1) & 0x7, + (decoded->params.regs.sec & 1) ? 'l': 'w', 1 << decoded->params.regs.scale); + break; + case 0x12: + case 0x13: + //base displacement only + ret = sprintf(dst, "%s ([%d.%c, a%d, %c%d.%c*%d])", c, decoded->params.regs.displacement, + decoded->params.regs.disp_sizes & 3 == 2 ? 'w' : 'l', decoded->params.regs.pri, + (decoded->params.regs.sec & 0x10) ? 'a': 'd', (decoded->params.regs.sec >> 1) & 0x7, + (decoded->params.regs.sec & 1) ? 'l': 'w', 1 << decoded->params.regs.scale); + break; + case 0x21: + case 0x31: + //outer displacement only + ret = sprintf(dst, "%s ([a%d, %c%d.%c*%d], %d.%c)", c, decoded->params.regs.pri, + (decoded->params.regs.sec & 0x10) ? 'a': 'd', (decoded->params.regs.sec >> 1) & 0x7, + (decoded->params.regs.sec & 1) ? 'l': 'w', 1 << decoded->params.regs.scale, + decoded->params.regs.outer_disp, decoded->params.regs.disp_sizes & 0x30 == 0x20 ? 'w' : 'l'); + break; + case 0x22: + case 0x23: + case 0x32: + case 0x33: + //both outer and inner displacement + ret = sprintf(dst, "%s ([%d.%c, a%d, %c%d.%c*%d], %d.%c)", c, decoded->params.regs.displacement, + decoded->params.regs.disp_sizes & 3 == 2 ? 'w' : 'l', decoded->params.regs.pri, + (decoded->params.regs.sec & 0x10) ? 'a': 'd', (decoded->params.regs.sec >> 1) & 0x7, + (decoded->params.regs.sec & 1) ? 'l': 'w', 1 << decoded->params.regs.scale, + decoded->params.regs.outer_disp, decoded->params.regs.disp_sizes & 0x30 == 0x20 ? 'w' : 'l'); + break; + } + break; + case MODE_AREG_POSTINDEX: + switch (decoded->params.regs.disp_sizes) + { + case 0x11: + //no base displacement or outer displacement + ret = sprintf(dst, "%s ([a%d], %c%d.%c*%d)", c, decoded->params.regs.pri, + (decoded->params.regs.sec & 0x10) ? 'a': 'd', (decoded->params.regs.sec >> 1) & 0x7, + (decoded->params.regs.sec & 1) ? 'l': 'w', 1 << decoded->params.regs.scale); + break; + case 0x12: + case 0x13: + //base displacement only + ret = sprintf(dst, "%s ([%d.%c, a%d], %c%d.%c*%d)", c, decoded->params.regs.displacement, + decoded->params.regs.disp_sizes & 3 == 2 ? 'w' : 'l', decoded->params.regs.pri, + (decoded->params.regs.sec & 0x10) ? 'a': 'd', (decoded->params.regs.sec >> 1) & 0x7, + (decoded->params.regs.sec & 1) ? 'l': 'w', 1 << decoded->params.regs.scale); + break; + case 0x21: + case 0x31: + //outer displacement only + ret = sprintf(dst, "%s ([a%d], %c%d.%c*%d, %d.%c)", c, decoded->params.regs.pri, + (decoded->params.regs.sec & 0x10) ? 'a': 'd', (decoded->params.regs.sec >> 1) & 0x7, + (decoded->params.regs.sec & 1) ? 'l': 'w', 1 << decoded->params.regs.scale, + decoded->params.regs.outer_disp, decoded->params.regs.disp_sizes & 0x30 == 0x20 ? 'w' : 'l'); + break; + case 0x22: + case 0x23: + case 0x32: + case 0x33: + //both outer and inner displacement + ret = sprintf(dst, "%s ([%d.%c, a%d], %c%d.%c*%d, %d.%c)", c, decoded->params.regs.displacement, + decoded->params.regs.disp_sizes & 3 == 2 ? 'w' : 'l', decoded->params.regs.pri, + (decoded->params.regs.sec & 0x10) ? 'a': 'd', (decoded->params.regs.sec >> 1) & 0x7, + (decoded->params.regs.sec & 1) ? 'l': 'w', 1 << decoded->params.regs.scale, + decoded->params.regs.outer_disp, decoded->params.regs.disp_sizes & 0x30 == 0x20 ? 'w' : 'l'); + break; + } + break; + case MODE_AREG_MEM_INDIRECT: + switch (decoded->params.regs.disp_sizes) + { + case 0x11: + //no base displacement or outer displacement + ret = sprintf(dst, "%s ([a%d])", c, decoded->params.regs.pri); + break; + case 0x12: + case 0x13: + //base displacement only + ret = sprintf(dst, "%s ([%d.%c, a%d])", c, decoded->params.regs.displacement, + decoded->params.regs.disp_sizes & 3 == 2 ? 'w' : 'l', decoded->params.regs.pri); + break; + case 0x21: + case 0x31: + //outer displacement only + ret = sprintf(dst, "%s ([a%d], %d.%c)", c, decoded->params.regs.pri, decoded->params.regs.outer_disp, + decoded->params.regs.disp_sizes & 0x30 == 0x20 ? 'w' : 'l'); + break; + case 0x22: + case 0x23: + case 0x32: + case 0x33: + //both outer and inner displacement + ret = sprintf(dst, "%s ([%d.%c, a%d], %d.%c)", c, decoded->params.regs.displacement, + decoded->params.regs.disp_sizes & 3 == 2 ? 'w' : 'l', decoded->params.regs.pri, + decoded->params.regs.outer_disp, decoded->params.regs.disp_sizes & 0x30 == 0x20 ? 'w' : 'l'); + break; + } + break; + case MODE_AREG_BASE_DISP: + if (decoded->params.regs.disp_sizes > 1) + { + ret = sprintf(dst, "%s (%d.%c, a%d)", c, decoded->params.regs.displacement, + decoded->params.regs.disp_sizes == 2 ? 'w' : 'l', decoded->params.regs.pri); + } else { + //this is a lossy representation of the encoded instruction + //not sure if there's a better way to print it though + ret = sprintf(dst, "%s (a%d)", c, decoded->params.regs.pri); + } + break; + case MODE_INDEX_BASE_DISP: + if (decoded->params.regs.disp_sizes > 1) + { + ret = sprintf(dst, "%s (%d.%c, %c%d.%c*%d)", c, decoded->params.regs.displacement, + decoded->params.regs.disp_sizes == 2 ? 'w' : 'l', + (decoded->params.regs.sec & 0x10) ? 'a': 'd', (decoded->params.regs.sec >> 1) & 0x7, + (decoded->params.regs.sec & 1) ? 'l': 'w', 1 << decoded->params.regs.scale); + } else { + ret = sprintf(dst, "%s (%c%d.%c*%d)", c, (decoded->params.regs.sec & 0x10) ? 'a': 'd', + (decoded->params.regs.sec >> 1) & 0x7, (decoded->params.regs.sec & 1) ? 'l': 'w', + 1 << decoded->params.regs.scale); + } + break; + case MODE_PREINDEX: + switch (decoded->params.regs.disp_sizes) + { + case 0x11: + //no base displacement or outer displacement + ret = sprintf(dst, "%s ([%c%d.%c*%d])", c, (decoded->params.regs.sec & 0x10) ? 'a': 'd', + (decoded->params.regs.sec >> 1) & 0x7, (decoded->params.regs.sec & 1) ? 'l': 'w', + 1 << decoded->params.regs.scale); + break; + case 0x12: + case 0x13: + //base displacement only + ret = sprintf(dst, "%s ([%d.%c, %c%d.%c*%d])", c, decoded->params.regs.displacement, + decoded->params.regs.disp_sizes & 3 == 2 ? 'w' : 'l', + (decoded->params.regs.sec & 0x10) ? 'a': 'd', (decoded->params.regs.sec >> 1) & 0x7, + (decoded->params.regs.sec & 1) ? 'l': 'w', 1 << decoded->params.regs.scale); + break; + case 0x21: + case 0x31: + //outer displacement only + ret = sprintf(dst, "%s ([%c%d.%c*%d], %d.%c)", c, (decoded->params.regs.sec & 0x10) ? 'a': 'd', + (decoded->params.regs.sec >> 1) & 0x7, (decoded->params.regs.sec & 1) ? 'l': 'w', + 1 << decoded->params.regs.scale, decoded->params.regs.outer_disp, + decoded->params.regs.disp_sizes & 0x30 == 0x20 ? 'w' : 'l'); + break; + case 0x22: + case 0x23: + case 0x32: + case 0x33: + //both outer and inner displacement + ret = sprintf(dst, "%s ([%d.%c, %c%d.%c*%d], %d.%c)", c, decoded->params.regs.displacement, + decoded->params.regs.disp_sizes & 3 == 2 ? 'w' : 'l', + (decoded->params.regs.sec & 0x10) ? 'a': 'd', (decoded->params.regs.sec >> 1) & 0x7, + (decoded->params.regs.sec & 1) ? 'l': 'w', 1 << decoded->params.regs.scale, + decoded->params.regs.outer_disp, decoded->params.regs.disp_sizes & 0x30 == 0x20 ? 'w' : 'l'); + break; + } + break; + case MODE_POSTINDEX: + switch (decoded->params.regs.disp_sizes) + { + case 0x11: + //no base displacement or outer displacement + ret = sprintf(dst, "%s ([], %c%d.%c*%d)", c, (decoded->params.regs.sec & 0x10) ? 'a': 'd', + (decoded->params.regs.sec >> 1) & 0x7, (decoded->params.regs.sec & 1) ? 'l': 'w', + 1 << decoded->params.regs.scale); + break; + case 0x12: + case 0x13: + //base displacement only + ret = sprintf(dst, "%s ([%d.%c], %c%d.%c*%d)", c, decoded->params.regs.displacement, + decoded->params.regs.disp_sizes & 3 == 2 ? 'w' : 'l', + (decoded->params.regs.sec & 0x10) ? 'a': 'd', (decoded->params.regs.sec >> 1) & 0x7, + (decoded->params.regs.sec & 1) ? 'l': 'w', 1 << decoded->params.regs.scale); + break; + case 0x21: + case 0x31: + //outer displacement only + ret = sprintf(dst, "%s ([], %c%d.%c*%d, %d.%c)", c, (decoded->params.regs.sec & 0x10) ? 'a': 'd', + (decoded->params.regs.sec >> 1) & 0x7, (decoded->params.regs.sec & 1) ? 'l': 'w', + 1 << decoded->params.regs.scale, decoded->params.regs.outer_disp, + decoded->params.regs.disp_sizes & 0x30 == 0x20 ? 'w' : 'l'); + break; + case 0x22: + case 0x23: + case 0x32: + case 0x33: + //both outer and inner displacement + ret = sprintf(dst, "%s ([%d.%c], %c%d.%c*%d, %d.%c)", c, decoded->params.regs.displacement, + decoded->params.regs.disp_sizes & 3 == 2 ? 'w' : 'l', + (decoded->params.regs.sec & 0x10) ? 'a': 'd', (decoded->params.regs.sec >> 1) & 0x7, + (decoded->params.regs.sec & 1) ? 'l': 'w', 1 << decoded->params.regs.scale, + decoded->params.regs.outer_disp, decoded->params.regs.disp_sizes & 0x30 == 0x20 ? 'w' : 'l'); + break; + } + break; + case MODE_MEM_INDIRECT: + switch (decoded->params.regs.disp_sizes) + { + case 0x11: + //no base displacement or outer displacement + ret = sprintf(dst, "%s ([])", c); + break; + case 0x12: + case 0x13: + //base displacement only + ret = sprintf(dst, "%s ([%d.%c])", c, decoded->params.regs.displacement, + decoded->params.regs.disp_sizes & 3 == 2 ? 'w' : 'l'); + break; + case 0x21: + case 0x31: + //outer displacement only + ret = sprintf(dst, "%s ([], %d.%c)", c, decoded->params.regs.outer_disp, + decoded->params.regs.disp_sizes & 0x30 == 0x20 ? 'w' : 'l'); + break; + case 0x22: + case 0x23: + case 0x32: + case 0x33: + //both outer and inner displacement + ret = sprintf(dst, "%s ([%d.%c], %d.%c)", c, decoded->params.regs.displacement, + decoded->params.regs.disp_sizes & 3 == 2 ? 'w' : 'l', decoded->params.regs.outer_disp, + decoded->params.regs.disp_sizes & 0x30 == 0x20 ? 'w' : 'l'); + break; + } + break; + case MODE_BASE_DISP: + if (decoded->params.regs.disp_sizes > 1) + { + ret = sprintf(dst, "%s (%d.%c)", c, decoded->params.regs.displacement, + decoded->params.regs.disp_sizes & 3 == 2 ? 'w' : 'l'); + } else { + ret = sprintf(dst, "%s ()", c); + } + break; +#endif case MODE_IMMEDIATE: case MODE_IMMEDIATE_WORD: - return sprintf(dst, (decoded->params.immed <= 128 ? "%s #%d" : "%s #$%X"), c, decoded->params.immed); + ret = sprintf(dst, (decoded->params.immed <= 128 ? "%s #%d" : "%s #$%X"), c, decoded->params.immed); + break; case MODE_ABSOLUTE_SHORT: if (labels) { - return sprintf(dst, "%s ADR_%X.w", c, decoded->params.immed); + ret = sprintf(dst, "%s ", c); + ret += label_fun(dst+ret, decoded->params.immed, data); + strcat(dst+ret, ".w"); + ret = ret + 2; } else { - return sprintf(dst, "%s $%X.w", c, decoded->params.immed); + ret = sprintf(dst, "%s $%X.w", c, decoded->params.immed); } + break; case MODE_ABSOLUTE: if (labels) { - return sprintf(dst, "%s ADR_%X.l", c, decoded->params.immed); + ret = sprintf(dst, "%s ", c); + ret += label_fun(dst+ret, decoded->params.immed, data); + strcat(dst+ret, ".l"); + ret = ret + 2; } else { - return sprintf(dst, "%s $%X", c, decoded->params.immed); + ret = sprintf(dst, "%s $%X", c, decoded->params.immed); } + break; case MODE_PC_DISPLACE: if (labels) { - return sprintf(dst, "%s ADR_%X(pc)", c, address + 2 + decoded->params.regs.displacement); + ret = sprintf(dst, "%s ", c); + ret += label_fun(dst+ret, address + 2 + decoded->params.regs.displacement, data); + strcat(dst+ret, "(pc)"); + ret = ret + 4; } else { - return sprintf(dst, "%s (%d, pc)", c, decoded->params.regs.displacement); + ret = sprintf(dst, "%s (%d, pc)", c, decoded->params.regs.displacement); } + break; case MODE_PC_INDEX_DISP8: - return sprintf(dst, "%s (%d, pc, %c%d.%c)", c, decoded->params.regs.displacement, (decoded->params.regs.sec & 0x10) ? 'a': 'd', (decoded->params.regs.sec >> 1) & 0x7, (decoded->params.regs.sec & 1) ? 'l': 'w'); +#ifdef M68020 + if (decoded->params.regs.scale) + { + ret = sprintf(dst, "%s (%d, pc, %c%d.%c*%d)", c, decoded->params.regs.displacement, (decoded->params.regs.sec & 0x10) ? 'a': 'd', (decoded->params.regs.sec >> 1) & 0x7, (decoded->params.regs.sec & 1) ? 'l': 'w', 1 << decoded->params.regs.scale); + } else { +#endif + ret = sprintf(dst, "%s (%d, pc, %c%d.%c)", c, decoded->params.regs.displacement, (decoded->params.regs.sec & 0x10) ? 'a': 'd', (decoded->params.regs.sec >> 1) & 0x7, (decoded->params.regs.sec & 1) ? 'l': 'w'); +#ifdef M68020 + } +#endif + break; +#ifdef M68020 + case MODE_PC_INDEX_BASE_DISP: + if (decoded->params.regs.disp_sizes > 1) + { + ret = sprintf(dst, "%s (%d.%c, pc, %c%d.%c*%d)", c, decoded->params.regs.displacement, + decoded->params.regs.disp_sizes == 2 ? 'w' : 'l', + (decoded->params.regs.sec & 0x10) ? 'a': 'd', (decoded->params.regs.sec >> 1) & 0x7, + (decoded->params.regs.sec & 1) ? 'l': 'w', 1 << decoded->params.regs.scale); + } else { + ret = sprintf(dst, "%s (pc, %c%d.%c*%d)", c, (decoded->params.regs.sec & 0x10) ? 'a': 'd', + (decoded->params.regs.sec >> 1) & 0x7, (decoded->params.regs.sec & 1) ? 'l': 'w', + 1 << decoded->params.regs.scale); + } + break; + case MODE_PC_PREINDEX: + switch (decoded->params.regs.disp_sizes) + { + case 0x11: + //no base displacement or outer displacement + ret = sprintf(dst, "%s ([pc, %c%d.%c*%d])", c, (decoded->params.regs.sec & 0x10) ? 'a': 'd', + (decoded->params.regs.sec >> 1) & 0x7, (decoded->params.regs.sec & 1) ? 'l': 'w', + 1 << decoded->params.regs.scale); + break; + case 0x12: + case 0x13: + //base displacement only + ret = sprintf(dst, "%s ([%d.%c, pc, %c%d.%c*%d])", c, decoded->params.regs.displacement, + decoded->params.regs.disp_sizes & 3 == 2 ? 'w' : 'l', + (decoded->params.regs.sec & 0x10) ? 'a': 'd', (decoded->params.regs.sec >> 1) & 0x7, + (decoded->params.regs.sec & 1) ? 'l': 'w', 1 << decoded->params.regs.scale); + break; + case 0x21: + case 0x31: + //outer displacement only + ret = sprintf(dst, "%s ([pc, %c%d.%c*%d], %d.%c)", c, (decoded->params.regs.sec & 0x10) ? 'a': 'd', + (decoded->params.regs.sec >> 1) & 0x7, (decoded->params.regs.sec & 1) ? 'l': 'w', + 1 << decoded->params.regs.scale, decoded->params.regs.outer_disp, + decoded->params.regs.disp_sizes & 0x30 == 0x20 ? 'w' : 'l'); + break; + case 0x22: + case 0x23: + case 0x32: + case 0x33: + //both outer and inner displacement + ret = sprintf(dst, "%s ([%d.%c, pc, %c%d.%c*%d], %d.%c)", c, decoded->params.regs.displacement, + decoded->params.regs.disp_sizes & 3 == 2 ? 'w' : 'l', + (decoded->params.regs.sec & 0x10) ? 'a': 'd', (decoded->params.regs.sec >> 1) & 0x7, + (decoded->params.regs.sec & 1) ? 'l': 'w', 1 << decoded->params.regs.scale, + decoded->params.regs.outer_disp, decoded->params.regs.disp_sizes & 0x30 == 0x20 ? 'w' : 'l'); + break; + } + break; + case MODE_PC_POSTINDEX: + switch (decoded->params.regs.disp_sizes) + { + case 0x11: + //no base displacement or outer displacement + ret = sprintf(dst, "%s ([pc], %c%d.%c*%d)", c, (decoded->params.regs.sec & 0x10) ? 'a': 'd', + (decoded->params.regs.sec >> 1) & 0x7, (decoded->params.regs.sec & 1) ? 'l': 'w', + 1 << decoded->params.regs.scale); + break; + case 0x12: + case 0x13: + //base displacement only + ret = sprintf(dst, "%s ([%d.%c, pc], %c%d.%c*%d)", c, decoded->params.regs.displacement, + decoded->params.regs.disp_sizes & 3 == 2 ? 'w' : 'l', + (decoded->params.regs.sec & 0x10) ? 'a': 'd', (decoded->params.regs.sec >> 1) & 0x7, + (decoded->params.regs.sec & 1) ? 'l': 'w', 1 << decoded->params.regs.scale); + break; + case 0x21: + case 0x31: + //outer displacement only + ret = sprintf(dst, "%s ([pc], %c%d.%c*%d, %d.%c)", c, (decoded->params.regs.sec & 0x10) ? 'a': 'd', + (decoded->params.regs.sec >> 1) & 0x7, (decoded->params.regs.sec & 1) ? 'l': 'w', + 1 << decoded->params.regs.scale, decoded->params.regs.outer_disp, + decoded->params.regs.disp_sizes & 0x30 == 0x20 ? 'w' : 'l'); + break; + case 0x22: + case 0x23: + case 0x32: + case 0x33: + //both outer and inner displacement + ret = sprintf(dst, "%s ([%d.%c, pc], %c%d.%c*%d, %d.%c)", c, decoded->params.regs.displacement, + decoded->params.regs.disp_sizes & 3 == 2 ? 'w' : 'l', + (decoded->params.regs.sec & 0x10) ? 'a': 'd', (decoded->params.regs.sec >> 1) & 0x7, + (decoded->params.regs.sec & 1) ? 'l': 'w', 1 << decoded->params.regs.scale, + decoded->params.regs.outer_disp, decoded->params.regs.disp_sizes & 0x30 == 0x20 ? 'w' : 'l'); + break; + } + break; + case MODE_PC_MEM_INDIRECT: + switch (decoded->params.regs.disp_sizes) + { + case 0x11: + //no base displacement or outer displacement + ret = sprintf(dst, "%s ([pc])", c); + break; + case 0x12: + case 0x13: + //base displacement only + ret = sprintf(dst, "%s ([%d.%c, pc])", c, decoded->params.regs.displacement, + decoded->params.regs.disp_sizes & 3 == 2 ? 'w' : 'l'); + break; + case 0x21: + case 0x31: + //outer displacement only + ret = sprintf(dst, "%s ([pc], %d.%c)", c, decoded->params.regs.outer_disp, + decoded->params.regs.disp_sizes & 0x30 == 0x20 ? 'w' : 'l'); + break; + case 0x22: + case 0x23: + case 0x32: + case 0x33: + //both outer and inner displacement + ret = sprintf(dst, "%s ([%d.%c, pc], %d.%c)", c, decoded->params.regs.displacement, + decoded->params.regs.disp_sizes & 3 == 2 ? 'w' : 'l', decoded->params.regs.outer_disp, + decoded->params.regs.disp_sizes & 0x30 == 0x20 ? 'w' : 'l'); + break; + } + break; + case MODE_PC_BASE_DISP: + if (decoded->params.regs.disp_sizes > 1) + { + ret = sprintf(dst, "%s (%d.%c, pc)", c, decoded->params.regs.displacement, + decoded->params.regs.disp_sizes & 3 == 2 ? 'w' : 'l'); + } else { + ret = sprintf(dst, "%s (pc)", c); + } + break; + case MODE_ZPC_INDEX_BASE_DISP: + if (decoded->params.regs.disp_sizes > 1) + { + ret = sprintf(dst, "%s (%d.%c, zpc, %c%d.%c*%d)", c, decoded->params.regs.displacement, + decoded->params.regs.disp_sizes == 2 ? 'w' : 'l', + (decoded->params.regs.sec & 0x10) ? 'a': 'd', (decoded->params.regs.sec >> 1) & 0x7, + (decoded->params.regs.sec & 1) ? 'l': 'w', 1 << decoded->params.regs.scale); + } else { + ret = sprintf(dst, "%s (zpc, %c%d.%c*%d)", c, (decoded->params.regs.sec & 0x10) ? 'a': 'd', + (decoded->params.regs.sec >> 1) & 0x7, (decoded->params.regs.sec & 1) ? 'l': 'w', + 1 << decoded->params.regs.scale); + } + break; + case MODE_ZPC_PREINDEX: + switch (decoded->params.regs.disp_sizes) + { + case 0x11: + //no base displacement or outer displacement + ret = sprintf(dst, "%s ([zpc, %c%d.%c*%d])", c, (decoded->params.regs.sec & 0x10) ? 'a': 'd', + (decoded->params.regs.sec >> 1) & 0x7, (decoded->params.regs.sec & 1) ? 'l': 'w', + 1 << decoded->params.regs.scale); + break; + case 0x12: + case 0x13: + //base displacement only + ret = sprintf(dst, "%s ([%d.%c, zpc, %c%d.%c*%d])", c, decoded->params.regs.displacement, + decoded->params.regs.disp_sizes & 3 == 2 ? 'w' : 'l', + (decoded->params.regs.sec & 0x10) ? 'a': 'd', (decoded->params.regs.sec >> 1) & 0x7, + (decoded->params.regs.sec & 1) ? 'l': 'w', 1 << decoded->params.regs.scale); + break; + case 0x21: + case 0x31: + //outer displacement only + ret = sprintf(dst, "%s ([zpc, %c%d.%c*%d], %d.%c)", c, (decoded->params.regs.sec & 0x10) ? 'a': 'd', + (decoded->params.regs.sec >> 1) & 0x7, (decoded->params.regs.sec & 1) ? 'l': 'w', + 1 << decoded->params.regs.scale, decoded->params.regs.outer_disp, + decoded->params.regs.disp_sizes & 0x30 == 0x20 ? 'w' : 'l'); + break; + case 0x22: + case 0x23: + case 0x32: + case 0x33: + //both outer and inner displacement + ret = sprintf(dst, "%s ([%d.%c, zpc, %c%d.%c*%d], %d.%c)", c, decoded->params.regs.displacement, + decoded->params.regs.disp_sizes & 3 == 2 ? 'w' : 'l', + (decoded->params.regs.sec & 0x10) ? 'a': 'd', (decoded->params.regs.sec >> 1) & 0x7, + (decoded->params.regs.sec & 1) ? 'l': 'w', 1 << decoded->params.regs.scale, + decoded->params.regs.outer_disp, decoded->params.regs.disp_sizes & 0x30 == 0x20 ? 'w' : 'l'); + break; + } + break; + case MODE_ZPC_POSTINDEX: + switch (decoded->params.regs.disp_sizes) + { + case 0x11: + //no base displacement or outer displacement + ret = sprintf(dst, "%s ([zpc], %c%d.%c*%d)", c, (decoded->params.regs.sec & 0x10) ? 'a': 'd', + (decoded->params.regs.sec >> 1) & 0x7, (decoded->params.regs.sec & 1) ? 'l': 'w', + 1 << decoded->params.regs.scale); + break; + case 0x12: + case 0x13: + //base displacement only + ret = sprintf(dst, "%s ([%d.%c, zpc], %c%d.%c*%d)", c, decoded->params.regs.displacement, + decoded->params.regs.disp_sizes & 3 == 2 ? 'w' : 'l', + (decoded->params.regs.sec & 0x10) ? 'a': 'd', (decoded->params.regs.sec >> 1) & 0x7, + (decoded->params.regs.sec & 1) ? 'l': 'w', 1 << decoded->params.regs.scale); + break; + case 0x21: + case 0x31: + //outer displacement only + ret = sprintf(dst, "%s ([zpc], %c%d.%c*%d, %d.%c)", c, (decoded->params.regs.sec & 0x10) ? 'a': 'd', + (decoded->params.regs.sec >> 1) & 0x7, (decoded->params.regs.sec & 1) ? 'l': 'w', + 1 << decoded->params.regs.scale, decoded->params.regs.outer_disp, + decoded->params.regs.disp_sizes & 0x30 == 0x20 ? 'w' : 'l'); + break; + case 0x22: + case 0x23: + case 0x32: + case 0x33: + //both outer and inner displacement + ret = sprintf(dst, "%s ([%d.%c, zpc], %c%d.%c*%d, %d.%c)", c, decoded->params.regs.displacement, + decoded->params.regs.disp_sizes & 3 == 2 ? 'w' : 'l', + (decoded->params.regs.sec & 0x10) ? 'a': 'd', (decoded->params.regs.sec >> 1) & 0x7, + (decoded->params.regs.sec & 1) ? 'l': 'w', 1 << decoded->params.regs.scale, + decoded->params.regs.outer_disp, decoded->params.regs.disp_sizes & 0x30 == 0x20 ? 'w' : 'l'); + break; + } + break; + case MODE_ZPC_MEM_INDIRECT: + switch (decoded->params.regs.disp_sizes) + { + case 0x11: + //no base displacement or outer displacement + ret = sprintf(dst, "%s ([zpc])", c); + break; + case 0x12: + case 0x13: + //base displacement only + ret = sprintf(dst, "%s ([%d.%c, zpc])", c, decoded->params.regs.displacement, + decoded->params.regs.disp_sizes & 3 == 2 ? 'w' : 'l'); + break; + case 0x21: + case 0x31: + //outer displacement only + ret = sprintf(dst, "%s ([zpc], %d.%c)", c, decoded->params.regs.outer_disp, + decoded->params.regs.disp_sizes & 0x30 == 0x20 ? 'w' : 'l'); + break; + case 0x22: + case 0x23: + case 0x32: + case 0x33: + //both outer and inner displacement + ret = sprintf(dst, "%s ([%d.%c, zpc], %d.%c)", c, decoded->params.regs.displacement, + decoded->params.regs.disp_sizes & 3 == 2 ? 'w' : 'l', decoded->params.regs.outer_disp, + decoded->params.regs.disp_sizes & 0x30 == 0x20 ? 'w' : 'l'); + break; + } + break; + case MODE_ZPC_BASE_DISP: + if (decoded->params.regs.disp_sizes > 1) + { + ret = sprintf(dst, "%s (%d.%c, zpc)", c, decoded->params.regs.displacement, + decoded->params.regs.disp_sizes & 3 == 2 ? 'w' : 'l'); + } else { + ret = sprintf(dst, "%s (zpc)", c); + } + break; +#endif default: - return 0; + ret = 0; } +#ifdef M68020 + if (decoded->addr_mode & M68K_FLAG_BITFIELD) + { + switch (decoded->bitfield & 0x820) + { + case 0: + return ret + sprintf(dst+ret, " {$%X:%d}", decoded->bitfield >> 6 & 0x1F, decoded->bitfield & 0x1F ? decoded->bitfield & 0x1F : 32); + case 0x20: + return ret + sprintf(dst+ret, " {$%X:d%d}", decoded->bitfield >> 6 & 0x1F, decoded->bitfield & 0x7); + case 0x800: + return ret + sprintf(dst+ret, " {d%d:%d}", decoded->bitfield >> 6 & 0x7, decoded->bitfield & 0x1F ? decoded->bitfield & 0x1F : 32); + case 0x820: + return ret + sprintf(dst+ret, " {d%d:d%d}", decoded->bitfield >> 6 & 0x7, decoded->bitfield & 0x7); + } + } +#endif + return ret; } -int m68k_disasm_movem_op(m68k_op_info *decoded, m68k_op_info *other, char *dst, int need_comma, uint8_t labels, uint32_t address) +int m68k_disasm_movem_op(m68k_op_info *decoded, m68k_op_info *other, char *dst, int need_comma, uint8_t labels, uint32_t address, format_label_fun label_fun, void * data) { int8_t dir, reg, bit, regnum, last=-1, lastreg, first=-1; char *rtype, *last_rtype; @@ -1540,11 +2427,16 @@ } return oplen; } else { - return m68k_disasm_op(decoded, dst, need_comma, labels, address); + return m68k_disasm_op(decoded, dst, need_comma, labels, address, label_fun, data); } } -int m68k_disasm_ex(m68kinst * decoded, char * dst, uint8_t labels) +int m68k_default_label_fun(char * dst, uint32_t address, void * data) +{ + return sprintf(dst, "ADR_%X", address); +} + +int m68k_disasm_ex(m68kinst * decoded, char * dst, uint8_t labels, format_label_fun label_fun, void * data) { int ret,op1len; uint8_t size; @@ -1562,9 +2454,11 @@ if (decoded->op != M68K_SCC) { if (labels) { if (decoded->op == M68K_DBCC) { - ret += sprintf(dst+ret, " d%d, ADR_%X", decoded->dst.params.regs.pri, decoded->address + 2 + decoded->src.params.immed); + ret += sprintf(dst+ret, " d%d, ", decoded->dst.params.regs.pri); + ret += label_fun(dst+ret, decoded->address + 2 + decoded->src.params.immed, data); } else { - ret += sprintf(dst+ret, " ADR_%X", decoded->address + 2 + decoded->src.params.immed); + dst[ret++] = ' '; + ret += label_fun(dst+ret, decoded->address + 2 + decoded->src.params.immed, data); } } else { if (decoded->op == M68K_DBCC) { @@ -1578,8 +2472,8 @@ break; case M68K_BSR: if (labels) { - ret = sprintf(dst, "bsr%s ADR_%X", decoded->variant == VAR_BYTE ? ".s" : "", - decoded->address + 2 + decoded->src.params.immed); + ret = sprintf(dst, "bsr%s ", decoded->variant == VAR_BYTE ? ".s" : ""); + ret += label_fun(dst+ret, decoded->address + 2 + decoded->src.params.immed, data); } else { ret = sprintf(dst, "bsr%s #%d <%X>", decoded->variant == VAR_BYTE ? ".s" : "", decoded->src.params.immed, decoded->address + 2 + decoded->src.params.immed); } @@ -1587,7 +2481,7 @@ case M68K_MOVE_FROM_SR: ret = sprintf(dst, "%s", mnemonics[decoded->op]); ret += sprintf(dst + ret, " SR"); - ret += m68k_disasm_op(&(decoded->dst), dst + ret, 1, labels, decoded->address); + ret += m68k_disasm_op(&(decoded->dst), dst + ret, 1, labels, decoded->address, label_fun, data); return ret; case M68K_ANDI_SR: case M68K_EORI_SR: @@ -1599,19 +2493,34 @@ case M68K_MOVE_CCR: case M68K_ORI_CCR: ret = sprintf(dst, "%s", mnemonics[decoded->op]); - ret += m68k_disasm_op(&(decoded->src), dst + ret, 0, labels, decoded->address); + ret += m68k_disasm_op(&(decoded->src), dst + ret, 0, labels, decoded->address, label_fun, data); ret += sprintf(dst + ret, ", %s", special_op); return ret; case M68K_MOVE_USP: ret = sprintf(dst, "%s", mnemonics[decoded->op]); if (decoded->src.addr_mode != MODE_UNUSED) { - ret += m68k_disasm_op(&(decoded->src), dst + ret, 0, labels, decoded->address); + ret += m68k_disasm_op(&(decoded->src), dst + ret, 0, labels, decoded->address, label_fun, data); ret += sprintf(dst + ret, ", USP"); } else { ret += sprintf(dst + ret, "USP, "); - ret += m68k_disasm_op(&(decoded->dst), dst + ret, 0, labels, decoded->address); + ret += m68k_disasm_op(&(decoded->dst), dst + ret, 0, labels, decoded->address, label_fun, data); } return ret; + case M68K_INVALID: + ret = sprintf(dst, "dc.w $%X", decoded->src.params.immed); + return ret; +#ifdef M68010 + case M68K_MOVEC: + ret = sprintf(dst, "%s ", mnemonics[decoded->op]); + if (decoded->src.addr_mode == MODE_UNUSED) { + ret += sprintf(dst + ret, "%s, ", cr_mnem[decoded->src.params.immed]); + ret += m68k_disasm_op(&(decoded->dst), dst + ret, 0, labels, decoded->address, label_fun, data); + } else { + ret += m68k_disasm_op(&(decoded->src), dst + ret, 0, labels, decoded->address, label_fun, data); + ret += sprintf(dst + ret, ", %s", cr_mnem[decoded->dst.params.immed]); + } + return ret; +#endif default: size = decoded->extra.size; ret = sprintf(dst, "%s%s%s", @@ -1620,23 +2529,27 @@ size == OPSIZE_BYTE ? ".b" : (size == OPSIZE_WORD ? ".w" : (size == OPSIZE_LONG ? ".l" : ""))); } if (decoded->op == M68K_MOVEM) { - op1len = m68k_disasm_movem_op(&(decoded->src), &(decoded->dst), dst + ret, 0, labels, decoded->address); + op1len = m68k_disasm_movem_op(&(decoded->src), &(decoded->dst), dst + ret, 0, labels, decoded->address, label_fun, data); ret += op1len; - ret += m68k_disasm_movem_op(&(decoded->dst), &(decoded->src), dst + ret, op1len, labels, decoded->address); + ret += m68k_disasm_movem_op(&(decoded->dst), &(decoded->src), dst + ret, op1len, labels, decoded->address, label_fun, data); } else { - op1len = m68k_disasm_op(&(decoded->src), dst + ret, 0, labels, decoded->address); + op1len = m68k_disasm_op(&(decoded->src), dst + ret, 0, labels, decoded->address, label_fun, data); ret += op1len; - ret += m68k_disasm_op(&(decoded->dst), dst + ret, op1len, labels, decoded->address); + ret += m68k_disasm_op(&(decoded->dst), dst + ret, op1len, labels, decoded->address, label_fun, data); } return ret; } int m68k_disasm(m68kinst * decoded, char * dst) { - return m68k_disasm_ex(decoded, dst, 0); + return m68k_disasm_ex(decoded, dst, 0, NULL, NULL); } -int m68k_disasm_labels(m68kinst * decoded, char * dst) +int m68k_disasm_labels(m68kinst * decoded, char * dst, format_label_fun label_fun, void * data) { - return m68k_disasm_ex(decoded, dst, 1); + if (!label_fun) + { + label_fun = m68k_default_label_fun; + } + return m68k_disasm_ex(decoded, dst, 1, label_fun, data); } diff -r 9d6fed6501ba -r f822d9216968 68kinst.h --- a/68kinst.h Mon Dec 29 23:08:39 2014 -0800 +++ b/68kinst.h Tue Dec 30 19:11:34 2014 -0800 @@ -8,6 +8,13 @@ #include +#ifdef M68030 +#define M68020 +#endif +#ifdef M68020 +#define M68010 +#endif + typedef enum { BIT_MOVEP_IMMED = 0, MOVE_BYTE, @@ -97,7 +104,43 @@ M68K_TRAPV, M68K_TST, M68K_UNLK, - M68K_INVALID + M68K_INVALID, +#ifdef M68010 + M68K_BKPT, + M68K_MOVE_FROM_CCR, + M68K_MOVEC, + M68K_MOVES, + M68K_RTD, +#endif +#ifdef M68020 + M68K_BFCHG, + M68K_BFCLR, + M68K_BFEXTS, + M68K_BFEXTU, + M68K_BFFFO, + M68K_BFINS, + M68K_BFSET, + M68K_BFTST, + M68K_CALLM, + M68K_CAS, + M68K_CAS2, + M68K_CHK2, + M68K_CMP2, + M68K_CP_BCC, + M68K_CP_DBCC, + M68K_CP_GEN, + M68K_CP_RESTORE, + M68K_CP_SAVE, + M68K_CP_SCC, + M68K_CP_TRAPCC, + M68K_DIVSL, + M68K_DIVUL, + M68K_EXTB, + M68K_PACK, + M68K_RTM, + M68K_TRAPCC, + M68K_UNPK, +#endif } m68K_op; typedef enum { @@ -130,19 +173,40 @@ //expanded values MODE_AREG_INDEX_DISP8, #ifdef M68020 - MODE_AREG_INDEX_DISP32, + MODE_AREG_INDEX_BASE_DISP, + MODE_AREG_PREINDEX, + MODE_AREG_POSTINDEX, + MODE_AREG_MEM_INDIRECT, + MODE_AREG_BASE_DISP, + MODE_INDEX_BASE_DISP, + MODE_PREINDEX, + MODE_POSTINDEX, + MODE_MEM_INDIRECT, + MODE_BASE_DISP, #endif MODE_ABSOLUTE_SHORT, MODE_ABSOLUTE, MODE_PC_DISPLACE, MODE_PC_INDEX_DISP8, #ifdef M68020 - MODE_PC_INDEX_DISP32, + MODE_PC_INDEX_BASE_DISP, + MODE_PC_PREINDEX, + MODE_PC_POSTINDEX, + MODE_PC_MEM_INDIRECT, + MODE_PC_BASE_DISP, + MODE_ZPC_INDEX_BASE_DISP, + MODE_ZPC_PREINDEX, + MODE_ZPC_POSTINDEX, + MODE_ZPC_MEM_INDIRECT, + MODE_ZPC_BASE_DISP, #endif MODE_IMMEDIATE, MODE_IMMEDIATE_WORD,//used to indicate an immediate operand that only uses a single extension word even for a long operation MODE_UNUSED } m68k_addr_modes; +#ifdef M68020 +#define M68K_FLAG_BITFIELD 0x80 +#endif typedef enum { COND_TRUE, @@ -163,13 +227,49 @@ COND_LESS_EQ } m68K_condition; +#ifdef M68010 +typedef enum { + CR_SFC, + CR_DFC, +#ifdef M68020 + CR_CACR, +#endif + CR_USP, + CR_VBR, +#ifdef M68020 + CR_CAAR, + CR_MSP, + CR_ISP +#endif +} m68k_control_reg; + +#ifdef M68020 +#define MAX_HIGH_CR 0x804 +#define MAX_LOW_CR 0x002 +#else +#define MAX_HIGH_CR 0x801 +#define MAX_LOW_CR 0x001 +#endif + +#endif + typedef struct { - uint8_t addr_mode; +#ifdef M68020 + uint16_t bitfield; +#endif + uint8_t addr_mode; union { struct { uint8_t pri; uint8_t sec; +#ifdef M68020 + uint8_t scale; + uint8_t disp_sizes; +#endif int32_t displacement; +#ifdef M68020 + int32_t outer_disp; +#endif } regs; uint32_t immed; } params; @@ -229,12 +329,15 @@ VECTOR_TRAP_15 } m68k_vector; +typedef int (*format_label_fun)(char * dst, uint32_t address, void * data); + uint16_t * m68k_decode(uint16_t * istream, m68kinst * dst, uint32_t address); uint32_t m68k_branch_target(m68kinst * inst, uint32_t *dregs, uint32_t *aregs); uint8_t m68k_is_branch(m68kinst * inst); uint8_t m68k_is_noncall_branch(m68kinst * inst); int m68k_disasm(m68kinst * decoded, char * dst); -int m68k_disasm_labels(m68kinst * decoded, char * dst); +int m68k_disasm_labels(m68kinst * decoded, char * dst, format_label_fun label_fun, void * data); +int m68k_default_label_fun(char * dst, uint32_t address, void * data); #endif diff -r 9d6fed6501ba -r f822d9216968 Makefile --- a/Makefile Mon Dec 29 23:08:39 2014 -0800 +++ b/Makefile Tue Dec 30 19:11:34 2014 -0800 @@ -19,6 +19,16 @@ CFLAGS+= -DDISABLE_OPENGL endif +ifdef M68030 +CFLAGS+= -DM68030 +endif +ifdef M68020 +CFLAGS+= -DM68020 +endif +ifdef M68010 +CFLAGS+= -DM68010 +endif + ifndef CPU CPU:=$(shell uname -m) endif @@ -64,8 +74,8 @@ blastem : $(MAINOBJS) $(CC) -o blastem $(MAINOBJS) $(LDFLAGS) -dis : dis.o 68kinst.o - $(CC) -o dis dis.o 68kinst.o +dis : dis.o 68kinst.o tern.o vos_program_module.o + $(CC) -o dis dis.o 68kinst.o tern.o vos_program_module.o zdis : zdis.o z80inst.o $(CC) -o zdis zdis.o z80inst.o @@ -106,6 +116,9 @@ offsets : offsets.c z80_to_x86.h m68k_core.h $(CC) -o offsets offsets.c +vos_prog_info : vos_prog_info.o vos_program_module.o + $(CC) -o vos_prog_info vos_prog_info.o vos_program_module.o + %.o : %.S $(CC) -c -o $@ $< @@ -113,7 +126,7 @@ $(CC) $(CFLAGS) -c -o $@ $< %.bin : %.s68 - vasmm68k_mot -Fbin -m68000 -no-opt -spaces -o $@ $< + vasmm68k_mot -Fbin -m68000 -no-opt -spaces -o $@ -L $@.list $< %.bin : %.sz8 vasmz80_mot -Fbin -spaces -o $@ $< diff -r 9d6fed6501ba -r f822d9216968 blastem.c --- a/blastem.c Mon Dec 29 23:08:39 2014 -0800 +++ b/blastem.c Tue Dec 30 19:11:34 2014 -0800 @@ -33,7 +33,7 @@ #define MAX_SOUND_CYCLES 100000 -uint32_t mclks_per_frame = MCLKS_LINE*LINES_NTSC; +uint32_t mclk_target = 0; uint16_t cart[CARTRIDGE_WORDS]; uint16_t ram[RAM_WORDS]; @@ -191,15 +191,19 @@ z80_reset(z_context); need_reset = 0; } - uint32_t vint_cycle = vdp_next_vint_z80(gen->vdp) / MCLKS_PER_Z80; + while (z_context->current_cycle < z_context->sync_cycle) { - if (z_context->iff1 && z_context->current_cycle < (vint_cycle + Z80_VINT_DURATION)) { - z_context->int_cycle = vint_cycle < z_context->int_enable_cycle ? z_context->int_enable_cycle : vint_cycle; + if (z_context->int_pulse_end < z_context->current_cycle || z_context->int_pulse_end == CYCLE_NEVER) { + z_context->int_pulse_start = vdp_next_vint_z80(gen->vdp) / MCLKS_PER_Z80; + z_context->int_pulse_end = z_context->int_pulse_start + Z80_VINT_DURATION; + } + if (z_context->iff1) { + z_context->int_cycle = z_context->int_pulse_start < z_context->int_enable_cycle ? z_context->int_enable_cycle : z_context->int_pulse_start; } else { z_context->int_cycle = CYCLE_NEVER; } z_context->target_cycle = z_context->sync_cycle < z_context->int_cycle ? z_context->sync_cycle : z_context->int_cycle; - dprintf("Running Z80 from cycle %d to cycle %d. Native PC: %p\n", z_context->current_cycle, z_context->sync_cycle, z_context->native_pc); + dprintf("Running Z80 from cycle %d to cycle %d. Int cycle: %d\n", z_context->current_cycle, z_context->sync_cycle, z_context->int_cycle); z_context->run(z_context); dprintf("Z80 ran to cycle %d\n", z_context->current_cycle); } @@ -236,15 +240,15 @@ z80_context * z_context = gen->z80; uint32_t mclks = context->current_cycle * MCLKS_PER_68K; sync_z80(z_context, mclks); - if (mclks >= mclks_per_frame) { + if (mclks >= mclk_target) { sync_sound(gen, mclks); - gen->ym->current_cycle -= mclks_per_frame; - gen->psg->cycles -= mclks_per_frame; + gen->ym->current_cycle -= mclk_target; + gen->psg->cycles -= mclk_target; if (gen->ym->write_cycle != CYCLE_NEVER) { - gen->ym->write_cycle = gen->ym->write_cycle >= mclks_per_frame/MCLKS_PER_68K ? gen->ym->write_cycle - mclks_per_frame/MCLKS_PER_68K : 0; + gen->ym->write_cycle = gen->ym->write_cycle >= mclk_target/MCLKS_PER_68K ? gen->ym->write_cycle - mclk_target/MCLKS_PER_68K : 0; } //printf("reached frame end | 68K Cycles: %d, MCLK Cycles: %d\n", context->current_cycle, mclks); - vdp_run_context(v_context, mclks_per_frame); + vdp_run_context(v_context, mclk_target); if (!headless) { break_on_sync |= wait_render_frame(v_context, frame_limit); @@ -255,28 +259,54 @@ } } frame++; - mclks -= mclks_per_frame; - vdp_adjust_cycles(v_context, mclks_per_frame); - io_adjust_cycles(gen->ports, context->current_cycle, mclks_per_frame/MCLKS_PER_68K); - io_adjust_cycles(gen->ports+1, context->current_cycle, mclks_per_frame/MCLKS_PER_68K); - io_adjust_cycles(gen->ports+2, context->current_cycle, mclks_per_frame/MCLKS_PER_68K); + mclks -= mclk_target; + vdp_adjust_cycles(v_context, mclk_target); + io_adjust_cycles(gen->ports, context->current_cycle, mclk_target/MCLKS_PER_68K); + io_adjust_cycles(gen->ports+1, context->current_cycle, mclk_target/MCLKS_PER_68K); + io_adjust_cycles(gen->ports+2, context->current_cycle, mclk_target/MCLKS_PER_68K); if (busack_cycle != CYCLE_NEVER) { - if (busack_cycle > mclks_per_frame/MCLKS_PER_68K) { - busack_cycle -= mclks_per_frame/MCLKS_PER_68K; + if (busack_cycle > mclk_target/MCLKS_PER_68K) { + busack_cycle -= mclk_target/MCLKS_PER_68K; } else { busack_cycle = CYCLE_NEVER; busack = new_busack; } } - context->current_cycle -= mclks_per_frame/MCLKS_PER_68K; - if (z_context->current_cycle >= mclks_per_frame/MCLKS_PER_Z80) { - z_context->current_cycle -= mclks_per_frame/MCLKS_PER_Z80; + context->current_cycle -= mclk_target/MCLKS_PER_68K; + if (z_context->current_cycle >= mclk_target/MCLKS_PER_Z80) { + z_context->current_cycle -= mclk_target/MCLKS_PER_Z80; } else { z_context->current_cycle = 0; } + if (z_context->int_cycle != CYCLE_NEVER) { + if (z_context->int_cycle >= mclk_target/MCLKS_PER_Z80) { + z_context->int_cycle -= mclk_target/MCLKS_PER_Z80; + } else { + z_context->int_cycle = 0; + } + } + if (z_context->int_pulse_start != CYCLE_NEVER) { + if (z_context->int_pulse_end >= mclk_target/MCLKS_PER_Z80) { + z_context->int_pulse_end -= mclk_target/MCLKS_PER_Z80; + if (z_context->int_pulse_start >= mclk_target/MCLKS_PER_Z80) { + z_context->int_pulse_start -= mclk_target/MCLKS_PER_Z80; + } else { + z_context->int_pulse_start = 0; + } + } + } else { + z_context->int_pulse_start = CYCLE_NEVER; + z_context->int_pulse_end = CYCLE_NEVER; + } + if (z_context->int_enable_cycle >= mclk_target/MCLKS_PER_Z80) { + z_context->int_enable_cycle -= mclk_target/MCLKS_PER_Z80; + } else { + z_context->int_enable_cycle = 0; + } if (mclks) { vdp_run_context(v_context, mclks); } + mclk_target = vdp_cycles_to_frame_end(v_context); } else { //printf("running VDP for %d cycles\n", mclks - v_context->cycles); vdp_run_context(v_context, mclks); @@ -322,10 +352,10 @@ gen->bus_busy = 1; while (vdp_data_port_write(v_context, value) < 0) { while(v_context->flags & FLAG_DMA_RUN) { - vdp_run_dma_done(v_context, mclks_per_frame); - if (v_context->cycles >= mclks_per_frame) { + vdp_run_dma_done(v_context, mclk_target); + if (v_context->cycles >= mclk_target) { context->current_cycle = v_context->cycles / MCLKS_PER_68K; - if (context->current_cycle * MCLKS_PER_68K < mclks_per_frame) { + if (context->current_cycle * MCLKS_PER_68K < mclk_target) { ++context->current_cycle; } sync_components(context, 0); @@ -339,10 +369,10 @@ if (blocked) { while (blocked) { while(v_context->flags & FLAG_DMA_RUN) { - vdp_run_dma_done(v_context, mclks_per_frame); - if (v_context->cycles >= mclks_per_frame) { + vdp_run_dma_done(v_context, mclk_target); + if (v_context->cycles >= mclk_target) { context->current_cycle = v_context->cycles / MCLKS_PER_68K; - if (context->current_cycle * MCLKS_PER_68K < mclks_per_frame) { + if (context->current_cycle * MCLKS_PER_68K < mclk_target) { ++context->current_cycle; } sync_components(context, 0); @@ -1045,7 +1075,7 @@ context.system = gen; //cartridge ROM context.mem_pointers[0] = cart; - context.target_cycle = context.sync_cycle = mclks_per_frame/MCLKS_PER_68K; + context.target_cycle = context.sync_cycle = mclk_target/MCLKS_PER_68K; //work RAM context.mem_pointers[1] = ram; //save RAM/map @@ -1300,7 +1330,6 @@ height = height < 240 ? (width/320) * 240 : height; uint32_t fps = 60; if (version_reg & 0x40) { - mclks_per_frame = MCLKS_LINE * LINES_PAL; fps = 50; } if (!headless) { @@ -1311,7 +1340,8 @@ memset(&gen, 0, sizeof(gen)); gen.master_clock = gen.normal_clock = fps == 60 ? MCLKS_NTSC : MCLKS_PAL; - init_vdp_context(&v_context); + init_vdp_context(&v_context, version_reg & 0x40); + mclk_target = vdp_cycles_to_frame_end(&v_context); ym2612_context y_context; ym_init(&y_context, render_sample_rate(), gen.master_clock, MCLKS_PER_YM, render_audio_buffer(), ym_log ? YM_OPT_WAVE_LOG : 0); @@ -1328,7 +1358,7 @@ z_context.system = &gen; z_context.mem_pointers[0] = z80_ram; - z_context.sync_cycle = z_context.target_cycle = mclks_per_frame/MCLKS_PER_Z80; + z_context.sync_cycle = z_context.target_cycle = mclk_target/MCLKS_PER_Z80; z_context.int_cycle = CYCLE_NEVER; z_context.mem_pointers[1] = z_context.mem_pointers[2] = (uint8_t *)cart; @@ -1351,7 +1381,7 @@ if (i < 0) { strcpy(sram_filename + fname_size, ".sram"); } - set_keybindings(); + set_keybindings(gen.ports); init_run_cpu(&gen, address_log, statefile, debuggerfun); return 0; diff -r 9d6fed6501ba -r f822d9216968 debug.c --- a/debug.c Mon Dec 29 23:08:39 2014 -0800 +++ b/debug.c Tue Dec 30 19:11:34 2014 -0800 @@ -632,9 +632,14 @@ } } else if(param[0] == 'c') { value = context->current_cycle; - } else if (param[0] == '0' && param[1] == 'x') { - uint32_t p_addr = strtol(param+2, NULL, 16); - value = read_dma_value(p_addr/2); + } else if ((param[0] == '0' && param[1] == 'x') || param[0] == '$') { + uint32_t p_addr = strtol(param+(param[0] == '0' ? 2 : 1), NULL, 16); + if ((p_addr & 0xFFFFFF) == 0xC00004) { + genesis_context * gen = context->system; + value = vdp_hv_counter_read(gen->vdp); + } else { + value = read_dma_value(p_addr/2); + } } else { fprintf(stderr, "Unrecognized parameter to p: %s\n", param); break; diff -r 9d6fed6501ba -r f822d9216968 default.cfg --- a/default.cfg Mon Dec 29 23:08:39 2014 -0800 +++ b/default.cfg Tue Dec 30 19:11:34 2014 -0800 @@ -54,6 +54,13 @@ } } +io { + devices { + 1 gamepad6.1 + 2 gamepad6.2 + } +} + video { width 640 vertex_shader default.v.glsl diff -r 9d6fed6501ba -r f822d9216968 dis.c --- a/dis.c Mon Dec 29 23:08:39 2014 -0800 +++ b/dis.c Tue Dec 30 19:11:34 2014 -0800 @@ -6,9 +6,12 @@ #include "68kinst.h" #include #include +#include +#include "vos_program_module.h" +#include "tern.h" uint8_t visited[(16*1024*1024)/16]; -uint8_t label[(16*1024*1024)/8]; +uint16_t label[(16*1024*1024)/8]; void visit(uint32_t address) { @@ -20,7 +23,7 @@ { address &= 0xFFFFFF; //printf("referenced: %X\n", address); - label[address/16] |= 1 << (address % 8); + label[address/16] |= 1 << (address % 16); } uint8_t is_visited(uint32_t address) @@ -29,10 +32,40 @@ return visited[address/16] & (1 << ((address / 2) % 8)); } -uint8_t is_label(uint32_t address) +uint16_t is_label(uint32_t address) { address &= 0xFFFFFF; - return label[address/16] & (1 << (address % 8)); + return label[address/16] & (1 << (address % 16)); +} + +typedef struct { + uint32_t num_labels; + uint32_t storage; + char *labels[]; +} label_names; + +tern_node * add_label(tern_node * head, char * name, uint32_t address) +{ + char key[MAX_INT_KEY_SIZE]; + address &= 0xFFFFFF; + reference(address); + tern_int_key(address, key); + label_names * names = tern_find_ptr(head, key); + if (names) + { + if (names->num_labels == names->storage) + { + names->storage = names->storage + (names->storage >> 1); + names = realloc(names, sizeof(label_names) + names->storage * sizeof(char *)); + } + } else { + names = malloc(sizeof(label_names) + 4 * sizeof(char *)); + names->num_labels = 0; + names->storage = 4; + head = tern_insert_ptr(head, key, names); + } + names->labels[names->num_labels++] = strdup(name); + return head; } typedef struct deferred { @@ -42,7 +75,7 @@ deferred * defer(uint32_t address, deferred * next) { - if (is_visited(address)) { + if (is_visited(address) || address & 1) { return next; } //printf("deferring %X\n", address); @@ -66,9 +99,18 @@ } } -uint8_t labels = 0; -uint8_t addr = 0; -uint8_t only = 0; +int label_fun(char *dst, uint32_t address, void * data) +{ + tern_node * labels = data; + char key[MAX_INT_KEY_SIZE]; + label_names * names = tern_find_ptr(labels, tern_int_key(address & 0xFFFFFF, key)); + if (names) + { + return sprintf(dst, "%s", names->labels[0]); + } else { + return m68k_default_label_fun(dst, address, NULL); + } +} int main(int argc, char ** argv) { @@ -77,14 +119,10 @@ char disbuf[1024]; m68kinst instbuf; unsigned short * cur; - FILE * f = fopen(argv[1], "rb"); - fseek(f, 0, SEEK_END); - filesize = ftell(f); - fseek(f, 0, SEEK_SET); - filebuf = malloc(filesize); - fread(filebuf, 2, filesize/2, f); - fclose(f); deferred *def = NULL, *tmpd; + + uint8_t labels = 0, addr = 0, only = 0, vos = 0, reset = 0; + for(uint8_t opt = 2; opt < argc; ++opt) { if (argv[opt][0] == '-') { FILE * address_log; @@ -99,6 +137,12 @@ case 'o': only = 1; break; + case 'v': + vos = 1; + break; + case 'r': + reset = 1; + break; case 'f': opt++; if (opt >= argc) { @@ -126,29 +170,85 @@ reference(address); } } - for(cur = filebuf; cur - filebuf < (filesize/2); ++cur) + + FILE * f = fopen(argv[1], "rb"); + fseek(f, 0, SEEK_END); + filesize = ftell(f); + fseek(f, 0, SEEK_SET); + + tern_node * named_labels = NULL; + char int_key[MAX_INT_KEY_SIZE]; + uint32_t address_off, address_end; + if (vos) { - *cur = (*cur >> 8) | (*cur << 8); + vos_program_module header; + vos_read_header(f, &header); + vos_read_alloc_module_map(f, &header); + address_off = header.user_boundary; + address_end = address_off + filesize - 0x1000; + def = defer(header.main_entry_link.code_address, def); + named_labels = add_label(named_labels, "main_entry_link", header.main_entry_link.code_address); + for (int i = 0; i < header.n_modules; i++) + { + if (!reset || header.module_map_entries[i].code_address != header.user_boundary) + { + def = defer(header.module_map_entries[i].code_address, def); + } + named_labels = add_label(named_labels, header.module_map_entries[i].name.str, header.module_map_entries[i].code_address); + } + fseek(f, 0x1000, SEEK_SET); + filebuf = malloc(filesize - 0x1000); + if (fread(filebuf, 2, (filesize - 0x1000)/2, f) != (filesize - 0x1000)/2) + { + fprintf(stderr, "Failure while reading file %s\n", argv[1]); + } + fclose(f); + for(cur = filebuf; cur - filebuf < ((filesize - 0x1000)/2); ++cur) + { + *cur = (*cur >> 8) | (*cur << 8); + } + if (reset) + { + def = defer(filebuf[2] << 16 | filebuf[3], def); + named_labels = add_label(named_labels, "reset", filebuf[2] << 16 | filebuf[3]); + } + } else { + address_off = 0; + address_end = filesize; + filebuf = malloc(filesize); + if (fread(filebuf, 2, filesize/2, f) != filesize/2) + { + fprintf(stderr, "Failure while reading file %s\n", argv[1]); + } + fclose(f); + for(cur = filebuf; cur - filebuf < (filesize/2); ++cur) + { + *cur = (*cur >> 8) | (*cur << 8); + } + uint32_t start = filebuf[2] << 16 | filebuf[3]; + uint32_t int_2 = filebuf[0x68/2] << 16 | filebuf[0x6A/2]; + uint32_t int_4 = filebuf[0x70/2] << 16 | filebuf[0x72/2]; + uint32_t int_6 = filebuf[0x78/2] << 16 | filebuf[0x7A/2]; + named_labels = add_label(named_labels, "start", start); + named_labels = add_label(named_labels, "int_2", int_2); + named_labels = add_label(named_labels, "int_4", int_4); + named_labels = add_label(named_labels, "int_6", int_6); + if (!def || !only) { + def = defer(start, def); + def = defer(int_2, def); + def = defer(int_4, def); + def = defer(int_6, def); + } } - uint32_t start = filebuf[2] << 16 | filebuf[3], tmp_addr; - uint32_t int_2 = filebuf[0x68/2] << 16 | filebuf[0x6A/2]; - uint32_t int_4 = filebuf[0x70/2] << 16 | filebuf[0x72/2]; - uint32_t int_6 = filebuf[0x78/2] << 16 | filebuf[0x7A/2]; uint16_t *encoded, *next; - uint32_t size; - if (!def || !only) { - def = defer(start, def); - def = defer(int_2, def); - def = defer(int_4, def); - def = defer(int_6, def); - } + uint32_t size, tmp_addr; uint32_t address; while(def) { do { encoded = NULL; address = def->address; if (!is_visited(address)) { - encoded = filebuf + address/2; + encoded = filebuf + (address - address_off)/2; } tmpd = def; def = def->next; @@ -158,7 +258,7 @@ break; } for(;;) { - if (address > filesize) { + if (address > address_end || address < address_off) { break; } visit(address); @@ -175,7 +275,7 @@ if (instbuf.op == M68K_BCC || instbuf.op == M68K_DBCC || instbuf.op == M68K_BSR) { if (instbuf.op == M68K_BCC && instbuf.extra.cond == COND_TRUE) { address = instbuf.address + 2 + instbuf.src.params.immed; - encoded = filebuf + address/2; + encoded = filebuf + (address - address_off)/2; reference(address); if (is_visited(address)) { break; @@ -188,13 +288,13 @@ } else if(instbuf.op == M68K_JMP) { if (instbuf.src.addr_mode == MODE_ABSOLUTE || instbuf.src.addr_mode == MODE_ABSOLUTE_SHORT) { address = instbuf.src.params.immed; - encoded = filebuf + address/2; + encoded = filebuf + (address - address_off)/2; if (is_visited(address)) { break; } } else if (instbuf.src.addr_mode == MODE_PC_DISPLACE) { address = instbuf.src.params.regs.displacement + instbuf.address + 2; - encoded = filebuf + address/2; + encoded = filebuf + (address - address_off)/2; if (is_visited(address)) { break; } @@ -211,6 +311,11 @@ } } if (labels) { + for (address = 0; address < address_off; address++) { + if (is_label(address)) { + printf("ADR_%X equ $%X\n", address, address); + } + } for (address = filesize; address < (16*1024*1024); address++) { if (is_label(address)) { printf("ADR_%X equ $%X\n", address, address); @@ -218,25 +323,21 @@ } puts(""); } - for (address = 0; address < filesize; address+=2) { + for (address = address_off; address < address_end; address+=2) { if (is_visited(address)) { - encoded = filebuf + address/2; + encoded = filebuf + (address-address_off)/2; m68k_decode(encoded, &instbuf, address); if (labels) { - m68k_disasm_labels(&instbuf, disbuf); - if (address == start) { - puts("start:"); - } - if(address == int_2) { - puts("int_2:"); - } - if(address == int_4) { - puts("int_4:"); - } - if(address == int_6) { - puts("int_6:"); - } - if (is_label(instbuf.address)) { + m68k_disasm_labels(&instbuf, disbuf, label_fun, named_labels); + char keybuf[MAX_INT_KEY_SIZE]; + label_names * names = tern_find_ptr(named_labels, tern_int_key(address, keybuf)); + if (names) + { + for (int i = 0; i < names->num_labels; i++) + { + printf("%s:\n", names->labels[i]); + } + } else if (is_label(instbuf.address)) { printf("ADR_%X:\n", instbuf.address); } if (addr) { diff -r 9d6fed6501ba -r f822d9216968 gen_test_hv.s68 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gen_test_hv.s68 Tue Dec 30 19:11:34 2014 -0800 @@ -0,0 +1,631 @@ + dc.l $0, start + dc.l empty_handler + dc.l empty_handler + ;$10 + dc.l empty_handler + dc.l empty_handler + dc.l empty_handler + dc.l empty_handler + ;$20 + dc.l empty_handler + dc.l empty_handler + dc.l empty_handler + dc.l empty_handler + ;$30 + dc.l empty_handler + dc.l empty_handler + dc.l empty_handler + dc.l empty_handler + ;$40 + dc.l empty_handler + dc.l empty_handler + dc.l empty_handler + dc.l empty_handler + ;$50 + dc.l empty_handler + dc.l empty_handler + dc.l empty_handler + dc.l empty_handler + ;$60 + dc.l empty_handler + dc.l empty_handler + dc.l empty_handler + dc.l empty_handler + ;$70 + dc.l int_4 + dc.l empty_handler + dc.l int_6 + dc.l empty_handler + ;$80 + dc.l empty_handler + dc.l empty_handler + dc.l empty_handler + dc.l empty_handler + ;$90 + dc.l empty_handler + dc.l empty_handler + dc.l empty_handler + dc.l empty_handler + ;$A0 + dc.l empty_handler + dc.l empty_handler + dc.l empty_handler + dc.l empty_handler + ;$B0 + dc.l empty_handler + dc.l empty_handler + dc.l empty_handler + dc.l empty_handler + ;$C0 + dc.l empty_handler + dc.l empty_handler + dc.l empty_handler + dc.l empty_handler + ;$D0 + dc.l empty_handler + dc.l empty_handler + dc.l empty_handler + dc.l empty_handler + ;$E0 + dc.l empty_handler + dc.l empty_handler + dc.l empty_handler + dc.l empty_handler + ;$F0 + dc.l empty_handler + dc.l empty_handler + dc.l empty_handler + dc.l empty_handler + dc.b "SEGA" +empty_handler: +int_6: + rte +int_4: + move.w (a2), d0 + ori.w #$8000, d0 + move.w d0, (a4)+ + rte + +start: + lea $C00000, a0 + lea $C00004, a1 + move.w #$8104, (a1) ;Mode 5, everything turned off + move.w #$8004, (a1) + move.w #$8220, (a1) ;Scroll a table $8000 + move.w #$8404, (a1) ;Scroll b table $8000 + move.w #$8560, (a1) ;SAT table $C000 + move.w #$8700, (a1) ;backdrop color 0 + move.w #$8B00, (a1) ;full screen scroll + move.w #$8C81, (a1) ;40 cell mode, no interlace + move.w #$8C81, (mode).w + move.w #$8D00, (a1) ;hscroll table at 0 + move.w #$8F02, (a1) ;autoinc 2 + move.w #$9011, (a1) ;64x64 scroll size + move.l #$C0000000, (a1) + move.w #$000, (a0) + move.w #$EEE, (a0) + + ;clear scroll table + move.l #$40000000, (a1) + move.l #0, (a0) + + ;load tiles + move.l #$44000000, (a1) + lea font(pc), a2 + move.w #((fontend-font)/4 - 1), d0 +tloop: + move.l (a2)+, (a0) + dbra d0, tloop + + + + ;clear name table + move.l #$40000002, (a1) + moveq #32, d0 + move.w #(64*64-1), d1 +ploop: + move.w d0, (a0) + dbra d1, ploop + + + lea $FF0000, a4 + move.b #$40, (a4, 6) + move.w #$8144, (a1) ;enable display + move #$2300, sr + + lea (4, a1), a2 ;hv counter line address + lea (2, a1), a3 ;second contro/status address + + move.b #254, d0 +init_wait: + cmp.b (a2), d0 + beq init_wait + +top: + move.b #254, d0 + lea $FF0000, a4 + move.w #$8F00, (a1) ;autoinc of 0 + move.l #$40040000, (a1) ;unused VRAM address +wait_active: + cmp.b (a2), d0 + bne.s wait_active + + move.l #$8A718014, (a1) ;enable Hints + + ;sync to VDP by attempting to fill FIFO + ;being in vblank makes this a bit difficult + + rept 8 + move.l d0, (a0) + endr + + ;sample data for vblank flag off + rept 82 ;two lines worth of move.l + move.l (a3), (a4)+ + endr + + move.l a4, a5 ;save end of first buffer + + move.b (a2), d0 +wait_new_line: + cmp.b (a2), d0 + beq.s wait_new_line + + ;sync to VDP by filling FIFO + move.l d0, (a0) + move.l d0, (a0) + move.w d0, (a0) + + ;sample data for line change HV value + rept 45 ;one line worth of move.l + move.l (a2), (a4)+ + endr + + move.l a4, usp ;save end of second buffer + + moveq #$70, d0 +wait_hint_line: + cmp.b (a2), d0 + bne.s wait_hint_line + + ;sample data for line change HV value + rept 45 ;one line worth of move.l + move.l (a2), (a4)+ + endr + + move.l a4, a6 + + move.b #223, d0 +wait_inactive: + cmp.b (a2), d0 + bne.s wait_inactive + + ;sync to VDP by filling FIFO + move.l d0, (a0) + move.l d0, (a0) + move.w d0, (a0) + + ;sample data for vblank on + rept 82 ;two lines worth of move.l + move.l (a3), (a4)+ + endr + + move.l #$8AFF8004, (a1) ;disable Hints + + rsset $FFFF8000 +vblank_start_min rs.w 1 +vblank_start_max rs.w 1 +vblank_end_min rs.w 1 +vblank_end_max rs.w 1 +hblank_start_min rs.w 1 +hblank_start_max rs.w 1 +hblank_end_min rs.w 1 +hblank_end_max rs.w 1 +line_change_min rs.w 1 +line_change_max rs.w 1 +hint_min rs.w 1 +hint_max rs.w 1 +mode rs.w 1 +printed_hv_dump rs.b 1 +button_state rs.b 1 + + lea $FF0001, a4 +.loop: + btst.b #3, (a4) + beq.s found_vblank_off + move.w 1(a4), d6 + addq #4, a4 + bra.s .loop +found_vblank_off: + + move.w (vblank_end_max).w, d0 + beq .new_max + cmp.w d0, d6 + blo .no_new_max +.new_max + move.w d6, (vblank_end_max).w +.no_new_max: + + + move.w 1(a4), d6 + + move.w (vblank_end_min).w, d0 + beq .new_min + cmp.w d0, d6 + bhi .no_new_min +.new_min + move.w d6, (vblank_end_min).w +.no_new_min: + + lea $FF0001, a4 +;first find a point where HBLANK is not set + bra.s .start +.loop: + addq #4, a4 +.start + btst.b #2, (a4) + bne.s .loop + +;then find a point after that where it switches to on +.loop2: + btst.b #2, (a4) + bne.s found_hblank_on + move.w 1(a4), d5 + addq #4, a4 + bra.s .loop2 +found_hblank_on: + + move.w (hblank_start_max).w, d0 + beq .new_max + cmp.w d0, d5 + blo .no_new_max +.new_max + move.w d5, (hblank_start_max).w +.no_new_max: + + + move.w 1(a4), d5 + + move.w (hblank_start_min).w, d0 + beq .new_min + cmp.w d0, d5 + bhi .no_new_min +.new_min + move.w d5, (hblank_start_min).w +.no_new_min: + +;finally find a point after that where it switches back off +.loop2: + btst.b #2, (a4) + beq.s found_hblank_off + move.w 1(a4), d5 + addq #4, a4 + bra.s .loop2 +found_hblank_off: + + move.w (hblank_end_max).w, d0 + beq .new_max + cmp.w d0, d5 + blo .no_new_max +.new_max + move.w d5, (hblank_end_max).w +.no_new_max: + + + move.w 1(a4), d5 + + move.w (hblank_end_min).w, d0 + beq .new_min + cmp.w d0, d5 + bhi .no_new_min +.new_min + move.w d5, (hblank_end_min).w +.no_new_min: + + move.l a5, a4 ;save line change buffer for later + move.b (a5), d0 +.loop + move.w (a5), d7 + addq #2, a5 + cmp.b (a5), d0 + beq .loop +found_line_change: + + move.w (line_change_max).w, d0 + beq .new_max + cmp.w d0, d7 + blo .no_new_max +.new_max + move.w d7, (line_change_max).w +.no_new_max: + + move.w (a5), d7 + + move.w (line_change_min).w, d0 + beq .new_min + cmp.w d0, d7 + bhi .no_new_min +.new_min + move.w d7, (line_change_min).w +.no_new_min: + + addq #1, a6 +.loop: + btst.b #3, (a6) + bne.s found_vblank_on + move.w 1(a6), d5 + addq #4, a6 + bra.s .loop +found_vblank_on: + + move.w (vblank_start_max).w, d0 + beq .new_max + cmp.w d0, d5 + blo .no_new_max +.new_max + move.w d5, (vblank_start_max).w +.no_new_max: + + move.w 1(a6), d5 + + move.w (vblank_start_min).w, d0 + beq .new_min + cmp.b d0, d5 + bhi .no_new_min +.new_min + move.w d5, (vblank_start_min).w +.no_new_min: + + move usp, a5 +.loop: + btst.b #7, (a5) + bne.s found_hint + move.w (a5), d1 + addq #2, a5 + bra.s .loop +found_hint: + + move.w (hint_max).w, d0 + beq .new_max + cmp.w d0, d1 + blo .no_new_max +.new_max + move.w d1, (hint_max).w +.no_new_max: + + move.w (a5), d1 + and.w #$7FFF, d1 + + move.w (hint_min).w, d0 + beq .new_min + cmp.b d0, d1 + bhi .no_new_min +.new_min + move.w d1, (hint_min).w +.no_new_min: + +draw_info: + ;draw data + move.w #$8F02, (a1) ;autoinc of 2 + move.l #$40840002, (a1) + + moveq #0, d0 + lea VBlankStart(pc), a6 + bsr print_string + + + move.w (vblank_start_max), d0 + moveq #0, d1 + bsr print_hexw + + move.w #32, (a0) + move.w d5, d0 + bsr print_hexw + + move.w #32, (a0) + move.w (vblank_start_min), d0 + bsr print_hexw + + moveq #0, d0 + move.l #$41040002, (a1) + lea VBlankEnd(pc), a6 + bsr print_string + + ;max value before vblank end + moveq #0, d1 + move.w (vblank_end_max), d0 + bsr print_hexw + + move.w #32, (a0) + move.w d6, d0 + bsr print_hexw + + ;min value after vblank end + move.w (vblank_end_min), d0 + move.w #32, (a0) + bsr print_hexw + + moveq #0, d0 + move.l #$41840002, (a1) + lea LineChange(pc), a6 + bsr print_string + + move.w (line_change_max), d0 + moveq #0, d1 + bsr print_hexw + + move.w #32, (a0) + move.w d7, d0 + bsr print_hexw + + move.w (line_change_min), d0 + move.w #32, (a0) + bsr print_hexw + + moveq #0, d0 + move.l #$42040002, (a1) + lea HBlankStart(pc), a6 + bsr print_string + + move.w (hblank_start_max), d0 + moveq #0, d1 + bsr print_hexw + + move.w (hblank_start_min), d0 + move.w #32, (a0) + bsr print_hexw + + moveq #0, d0 + move.l #$42840002, (a1) + lea HBlankEnd(pc), a6 + bsr print_string + + move.w (hblank_end_max), d0 + moveq #0, d1 + bsr print_hexw + + move.w (hblank_end_min), d0 + move.w #32, (a0) + bsr print_hexw + + moveq #0, d0 + move.l #$43040002, (a1) + lea HInterrupt(pc), a6 + bsr print_string + + move.w (hint_max), d0 + moveq #0, d1 + bsr print_hexw + + move.w (hint_min), d0 + move.w #32, (a0) + bsr print_hexw + + ;read pad + move.b #$40, $A10003 + move.b $A10003, d0 + move.b #$00, $A10003 + and.b #$3f, d0 + move.b $A10003, d1 + and.b #$30, d1 + lsl.b #2, d1 + or.b d1, d0 + not.b d0 + move.b (button_state).w, d2 + eor.b d0, d2 + and.b d0, d2 + move.b d2, d3 ;d3 contains newly pressed buttons, SACBRLDU + move.b d0, (button_state).w + + btst.l #7, d3 + beq not_pressed + + moveq #0, d0 + move.l d0, (vblank_start_min).w + move.l d0, (vblank_end_min).w + move.l d0, (hblank_start_min).w + move.l d0, (hblank_end_min).w + move.l d0, (line_change_min).w + move.l d0, (hint_min).w + move.b d0, (printed_hv_dump).w + move.w (mode).w, d0 + eor.w #$81, d0 + move.w d0, (mode).w + move.w d0, (a1) + bra top + +not_pressed + + move.b (printed_hv_dump).w, d0 + bne top + move.b #1, (printed_hv_dump).w + + moveq #0, d1 + moveq #89, d4 + moveq #6, d5 + move.l #$45820002, d6 + move.l d6, (a1) + +print_loop: + dbra d5, .no_line_change + ;#$45820002 + add.l #$00800000, d6 + move.l d6, (a1) + moveq #5, d5 +.no_line_change + move.w #32, (a0) + move.w (a4)+, d0 + bsr print_hexw + dbra d4, print_loop + + add.l #$01020000, d6 + move.l d6, (a1) + moveq #0, d0 + lea Instructions(pc), a6 + bsr print_string + + bra top + +VBlankStart: + dc.b "VBlank Start: ", 0 +VBlankEnd: + dc.b "VBlank End: ", 0 +LineChange: + dc.b "Line Change: ", 0 +HBlankStart: + dc.b "HBlank Start: ", 0 +HBlankEnd: + dc.b "HBlank End: ", 0 +HInterrupt: + dc.b "HInterrupt: ", 0 +Instructions: + dc.b "Press Start to switch modes", 0 + + align 1 +;Prints a number in hex format +;d0.w - number to print +;d1.w - base tile attribute +;a0 - VDP data port +; +;Clobbers: d2.l, d3.l +; +print_hexw: + moveq #3, d3 +.digitloop + rol.w #4, d0 + moveq #$F, d2 + and.b d0, d2 + cmp.b #$A, d2 + bge .hex + add.w #$30, d2 + bra .makeattrib +.hex + add.w #($41-$A), d2 +.makeattrib + add.w d1, d2 + move.w d2, (a0) + dbra d3, .digitloop + rts + +;Prints a null terminated string +;a6 - pointer to string +;a0 - VDP data port +;d0 - base tile attribute +; +;Clobbers: d1.w +print_string: +.loop + moveq #0, d1 + move.b (a6)+, d1 + beq .end + add.w d0, d1 + move.w d1, (a0) + bra .loop +.end + rts + + align 1 +font: + incbin font.tiles +fontend + diff -r 9d6fed6501ba -r f822d9216968 io.c --- a/io.c Mon Dec 29 23:08:39 2014 -0800 +++ b/io.c Tue Dec 30 19:11:34 2014 -0800 @@ -3,15 +3,44 @@ This file is part of BlastEm. BlastEm is free software distributed under the terms of the GNU General Public License version 3 or greater. See COPYING for full license text. */ +#include +#include +#include +#include +#include +#include +#include +#include + #include "io.h" #include "blastem.h" #include "render.h" +const char * device_type_names[] = { + "3-button gamepad", + "6-button gamepad", + "Mega Mouse", + "Menacer", + "Justifier", + "Sega multi-tap", + "EA 4-way Play cable A", + "EA 4-way Play cable B", + "Sega Parallel Transfer Board", + "Generic Device", + "None" +}; + enum { BIND_NONE, + BIND_UI, BIND_GAMEPAD1, BIND_GAMEPAD2, - BIND_UI + BIND_GAMEPAD3, + BIND_GAMEPAD4, + BIND_GAMEPAD5, + BIND_GAMEPAD6, + BIND_GAMEPAD7, + BIND_GAMEPAD8 }; typedef enum { @@ -26,6 +55,7 @@ } ui_action; typedef struct { + io_port *port; uint8_t bind_type; uint8_t subtype_a; uint8_t subtype_b; @@ -117,7 +147,7 @@ void bind_gamepad(int keycode, int gamepadnum, int button) { - if (gamepadnum < 1 || gamepadnum > 2) { + if (gamepadnum < 1 || gamepadnum > 8) { return; } uint8_t bind_type = gamepadnum - 1 + BIND_GAMEPAD1; @@ -126,7 +156,7 @@ void bind_button_gamepad(int joystick, int joybutton, int gamepadnum, int padbutton) { - if (gamepadnum < 1 || gamepadnum > 2) { + if (gamepadnum < 1 || gamepadnum > 8) { return; } uint8_t bind_type = gamepadnum - 1 + BIND_GAMEPAD1; @@ -135,7 +165,7 @@ void bind_dpad_gamepad(int joystick, int dpad, uint8_t direction, int gamepadnum, int button) { - if (gamepadnum < 1 || gamepadnum > 2) { + if (gamepadnum < 1 || gamepadnum > 8) { return; } uint8_t bind_type = gamepadnum - 1 + BIND_GAMEPAD1; @@ -159,17 +189,14 @@ void handle_binding_down(keybinding * binding) { - switch(binding->bind_type) + if (binding->bind_type >= BIND_GAMEPAD1) { - case BIND_GAMEPAD1: - case BIND_GAMEPAD2: - if (binding->subtype_a <= GAMEPAD_EXTRA) { - genesis->ports[binding->bind_type - BIND_GAMEPAD1].input[binding->subtype_a] |= binding->value; + if (binding->subtype_a <= GAMEPAD_EXTRA && binding->port) { + binding->port->input[binding->subtype_a] |= binding->value; } - if (binding->subtype_b <= GAMEPAD_EXTRA) { - genesis->ports[binding->bind_type - BIND_GAMEPAD1].input[binding->subtype_b] |= binding->value; + if (binding->subtype_b <= GAMEPAD_EXTRA && binding->port) { + binding->port->input[binding->subtype_b] |= binding->value; } - break; } } @@ -206,11 +233,11 @@ { case BIND_GAMEPAD1: case BIND_GAMEPAD2: - if (binding->subtype_a <= GAMEPAD_EXTRA) { - genesis->ports[binding->bind_type - BIND_GAMEPAD1].input[binding->subtype_a] &= ~binding->value; + if (binding->subtype_a <= GAMEPAD_EXTRA && binding->port) { + binding->port->input[binding->subtype_a] &= ~binding->value; } - if (binding->subtype_b <= GAMEPAD_EXTRA) { - genesis->ports[binding->bind_type - BIND_GAMEPAD1].input[binding->subtype_b] &= ~binding->value; + if (binding->subtype_b <= GAMEPAD_EXTRA && binding->port) { + binding->port->input[binding->subtype_b] &= ~binding->value; } break; case BIND_UI: @@ -447,7 +474,169 @@ } } -void set_keybindings() +void process_device(char * device_type, io_port * port) +{ + port->device_type = IO_NONE; + if (!device_type) + { + return; + } + + const int gamepad_len = strlen("gamepad"); + if (!memcmp(device_type, "gamepad", gamepad_len)) + { + if ( + (device_type[gamepad_len] != '3' && device_type[gamepad_len] != '6') + || device_type[gamepad_len+1] != '.' || device_type[gamepad_len+2] < '1' + || device_type[gamepad_len+2] > '8' || device_type[gamepad_len+3] != 0 + ) + { + fprintf(stderr, "%s is not a valid gamepad type\n", device_type); + } else if (device_type[gamepad_len] == '3') + { + port->device_type = IO_GAMEPAD3; + } else { + port->device_type = IO_GAMEPAD6; + } + port->device.pad.gamepad_num = device_type[gamepad_len+2] - '1'; + } else if(!strcmp(device_type, "sega_parallel")) { + port->device_type = IO_SEGA_PARALLEL; + port->device.stream.data_fd = -1; + port->device.stream.listen_fd = -1; + } else if(!strcmp(device_type, "generic")) { + port->device_type = IO_GENERIC; + port->device.stream.data_fd = -1; + port->device.stream.listen_fd = -1; + } +} + +char * io_name(int i) +{ + switch (i) + { + case 0: + return "1"; + case 1: + return "2"; + case 2: + return "EXT"; + default: + return "invalid"; + } +} + +static char * sockfile_name; +static void cleanup_sockfile() +{ + unlink(sockfile_name); +} + +void setup_io_devices(tern_node * config, io_port * ports) +{ + tern_node *io_nodes = tern_find_prefix(config, "iodevices"); + char * io_1 = tern_find_ptr(io_nodes, "1"); + char * io_2 = tern_find_ptr(io_nodes, "2"); + char * io_ext = tern_find_ptr(io_nodes, "ext"); + + process_device(io_1, ports); + process_device(io_2, ports+1); + process_device(io_ext, ports+2); + + for (int i = 0; i < 3; i++) + { + + if (ports[i].device_type == IO_SEGA_PARALLEL) + { + char *pipe_name = tern_find_ptr(config, "ioparallel_pipe"); + if (!pipe_name) + { + fprintf(stderr, "IO port %s is configured to use the sega parallel board, but no paralell_pipe is set!\n", io_name(i)); + ports[i].device_type = IO_NONE; + } else { + printf("IO port: %s connected to device '%s' with pipe name: %s\n", io_name(i), device_type_names[ports[i].device_type], pipe_name); + if (!strcmp("stdin", pipe_name)) + { + ports[i].device.stream.data_fd = STDIN_FILENO; + } else { + if (mkfifo(pipe_name, 0666) && errno != EEXIST) + { + fprintf(stderr, "Failed to create fifo %s for Sega parallel board emulation: %d %s\n", pipe_name, errno, strerror(errno)); + ports[i].device_type = IO_NONE; + } else { + ports[i].device.stream.data_fd = open(pipe_name, O_NONBLOCK | O_RDONLY); + if (ports[i].device.stream.data_fd == -1) + { + fprintf(stderr, "Failed to open fifo %s for Sega parallel board emulation: %d %s\n", pipe_name, errno, strerror(errno)); + ports[i].device_type = IO_NONE; + } + } + } + } + } else if (ports[i].device_type == IO_GENERIC) { + char *sock_name = tern_find_ptr(config, "iosocket"); + if (!sock_name) + { + fprintf(stderr, "IO port %s is configured to use generic IO, but no socket is set!\n", io_name(i)); + ports[i].device_type = IO_NONE; + } else { + printf("IO port: %s connected to device '%s' with socket name: %s\n", io_name(i), device_type_names[ports[i].device_type], sock_name); + ports[i].device.stream.data_fd = -1; + ports[i].device.stream.listen_fd = socket(AF_UNIX, SOCK_STREAM, 0); + size_t pathlen = strlen(sock_name); + size_t addrlen = offsetof(struct sockaddr_un, sun_path) + pathlen + 1; + struct sockaddr_un *saddr = malloc(addrlen); + saddr->sun_family = AF_UNIX; + memcpy(saddr->sun_path, sock_name, pathlen+1); + if (bind(ports[i].device.stream.listen_fd, (struct sockaddr *)saddr, addrlen)) + { + fprintf(stderr, "Failed to bind socket for IO Port %s to path %s: %d %s\n", io_name(i), sock_name, errno, strerror(errno)); + goto cleanup_sock; + } + if (listen(ports[i].device.stream.listen_fd, 1)) + { + fprintf(stderr, "Failed to listen on socket for IO Port %s: %d %s\n", io_name(i), errno, strerror(errno)); + goto cleanup_sockfile; + } + sockfile_name = sock_name; + atexit(cleanup_sockfile); + continue; +cleanup_sockfile: + unlink(sock_name); +cleanup_sock: + close(ports[i].device.stream.listen_fd); + ports[i].device_type = IO_NONE; + } + } else if (ports[i].device_type == IO_GAMEPAD3 || ports[i].device_type == IO_GAMEPAD6) { + printf("IO port %s connected to gamepad #%d with type '%s'\n", io_name(i), ports[i].device.pad.gamepad_num + 1, device_type_names[ports[i].device_type]); + } else { + printf("IO port %s connected to device '%s'\n", io_name(i), device_type_names[ports[i].device_type]); + } + } +} + +void map_bindings(io_port *ports, keybinding *bindings, int numbindings) +{ + for (int i = 0; i < numbindings; i++) + { + if (bindings[i].bind_type >= BIND_GAMEPAD1) + { + int num = bindings[i].bind_type - BIND_GAMEPAD1; + for (int j = 0; j < 3; j++) + { + if ((ports[j].device_type == IO_GAMEPAD3 + || ports[j].device_type ==IO_GAMEPAD6) + && ports[j].device.pad.gamepad_num == num + ) + { + bindings[i].port = ports + j; + break; + } + } + } + } +} + +void set_keybindings(io_port *ports) { tern_node * special = tern_insert_int(NULL, "up", RENDERKEY_UP); special = tern_insert_int(special, "down", RENDERKEY_DOWN); @@ -532,76 +721,245 @@ speeds = malloc(sizeof(uint32_t)); speeds[0] = 100; process_speeds(speed_nodes, NULL); - for (int i = 0; i < num_speeds; i++) { + for (int i = 0; i < num_speeds; i++) + { if (!speeds[i]) { fprintf(stderr, "Speed index %d was not set to a valid percentage!", i); speeds[i] = 100; } } + for (int bucket = 0; bucket < 256; bucket++) + { + if (bindings[bucket]) + { + map_bindings(ports, bindings[bucket], 256); + } + } + for (int stick = 0; stick < MAX_JOYSTICKS; stick++) + { + if (joybindings[stick]) + { + int numbuttons = render_joystick_num_buttons(stick); + map_bindings(ports, joybindings[stick], render_joystick_num_buttons(stick)); + } + if (joydpads[stick]) + { + map_bindings(ports, joydpads[stick]->bindings, 4); + } + } } #define TH 0x40 #define TH_TIMEOUT 8000 -void io_adjust_cycles(io_port * pad, uint32_t current_cycle, uint32_t deduction) +void io_adjust_cycles(io_port * port, uint32_t current_cycle, uint32_t deduction) { /*uint8_t control = pad->control | 0x80; uint8_t th = control & pad->output; if (pad->input[GAMEPAD_TH0] || pad->input[GAMEPAD_TH1]) { printf("adjust_cycles | control: %X, TH: %X, GAMEPAD_TH0: %X, GAMEPAD_TH1: %X, TH Counter: %d, Timeout: %d, Cycle: %d\n", control, th, pad->input[GAMEPAD_TH0], pad->input[GAMEPAD_TH1], pad->th_counter,pad->timeout_cycle, current_cycle); }*/ - if (current_cycle >= pad->timeout_cycle) { - pad->th_counter = 0; - } else { - pad->timeout_cycle -= deduction; + if (port->device_type == IO_GAMEPAD6) + { + if (current_cycle >= port->device.pad.timeout_cycle) + { + port->device.pad.th_counter = 0; + } else { + port->device.pad.timeout_cycle -= deduction; + } + } +} + +static void wait_for_connection(io_port * port) +{ + if (port->device.stream.data_fd == -1) + { + puts("Waiting for socket connection..."); + port->device.stream.data_fd = accept(port->device.stream.listen_fd, NULL, NULL); + fcntl(port->device.stream.data_fd, F_SETFL, O_NONBLOCK | O_RDWR); + } +} + +static void service_pipe(io_port * port) +{ + uint8_t value; + int numRead = read(port->device.stream.data_fd, &value, sizeof(value)); + if (numRead > 0) + { + port->input[IO_TH0] = (value & 0xF) | 0x10; + port->input[IO_TH1] = (value >> 4) | 0x10; + } else if(numRead == -1 && errno != EAGAIN && errno != EWOULDBLOCK) { + fprintf(stderr, "Error reading pipe for IO port: %d %s\n", errno, strerror(errno)); } } -void io_data_write(io_port * pad, uint8_t value, uint32_t current_cycle) +static void service_socket(io_port *port) { - if (pad->control & TH) { - //check if TH has changed - if ((pad->output & TH) ^ (value & TH)) { - if (current_cycle >= pad->timeout_cycle) { - pad->th_counter = 0; + uint8_t buf[32]; + uint8_t blocking = 0; + int numRead = 0; + while (numRead <= 0) + { + numRead = recv(port->device.stream.data_fd, buf, sizeof(buf), 0); + if (numRead > 0) + { + port->input[IO_TH0] = buf[numRead-1]; + if (port->input[IO_STATE] == IO_READ_PENDING) + { + port->input[IO_STATE] = IO_READ; + if (blocking) + { + //pending read satisfied, back to non-blocking mode + fcntl(port->device.stream.data_fd, F_SETFL, O_RDWR | O_NONBLOCK); + } + } else if (port->input[IO_STATE] == IO_WRITTEN) { + port->input[IO_STATE] = IO_READ; } - if (!(value & TH)) { - pad->th_counter++; + } else if (numRead == 0) { + port->device.stream.data_fd = -1; + wait_for_connection(port); + } else if (errno != EAGAIN && errno != EWOULDBLOCK) { + fprintf(stderr, "Error reading from socket for IO port: %d %s\n", errno, strerror(errno)); + close(port->device.stream.data_fd); + wait_for_connection(port); + } else if (port->input[IO_STATE] == IO_READ_PENDING) { + //clear the nonblocking flag so the next read will block + if (!blocking) + { + fcntl(port->device.stream.data_fd, F_SETFL, O_RDWR); + blocking = 1; } - pad->timeout_cycle = current_cycle + TH_TIMEOUT; + } else { + //no new data, but that's ok + break; } } - pad->output = value; + + if (port->input[IO_STATE] == IO_WRITE_PENDING) + { + uint8_t value = port->output & port->control; + int written = 0; + blocking = 0; + while (written <= 0) + { + send(port->device.stream.data_fd, &value, sizeof(value), 0); + if (written > 0) + { + port->input[IO_STATE] = IO_WRITTEN; + if (blocking) + { + //pending write satisfied, back to non-blocking mode + fcntl(port->device.stream.data_fd, F_SETFL, O_RDWR | O_NONBLOCK); + } + } else if (written == 0) { + port->device.stream.data_fd = -1; + wait_for_connection(port); + } else if (errno != EAGAIN && errno != EWOULDBLOCK) { + fprintf(stderr, "Error writing to socket for IO port: %d %s\n", errno, strerror(errno)); + close(port->device.stream.data_fd); + wait_for_connection(port); + } else { + //clear the nonblocking flag so the next write will block + if (!blocking) + { + fcntl(port->device.stream.data_fd, F_SETFL, O_RDWR); + blocking = 1; + } + } + } + } } -uint8_t io_data_read(io_port * pad, uint32_t current_cycle) +void io_data_write(io_port * port, uint8_t value, uint32_t current_cycle) { - uint8_t control = pad->control | 0x80; - uint8_t th = control & pad->output; + switch (port->device_type) + { + case IO_GAMEPAD6: + if (port->control & TH) { + //check if TH has changed + if ((port->output & TH) ^ (value & TH)) { + if (current_cycle >= port->device.pad.timeout_cycle) { + port->device.pad.th_counter = 0; + } + if (!(value & TH)) { + port->device.pad.th_counter++; + } + port->device.pad.timeout_cycle = current_cycle + TH_TIMEOUT; + } + } + port->output = value; + break; + case IO_GENERIC: + wait_for_connection(port); + port->input[IO_STATE] = IO_WRITE_PENDING; + port->output = value; + service_socket(port); + break; + default: + port->output = value; + } + +} + +uint8_t io_data_read(io_port * port, uint32_t current_cycle) +{ + uint8_t control = port->control | 0x80; + uint8_t th = control & port->output & 0x40; uint8_t input; - if (current_cycle >= pad->timeout_cycle) { - pad->th_counter = 0; + switch (port->device_type) + { + case IO_GAMEPAD3: + { + input = port->input[th ? GAMEPAD_TH1 : GAMEPAD_TH0]; + break; } - /*if (pad->input[GAMEPAD_TH0] || pad->input[GAMEPAD_TH1]) { - printf("io_data_read | control: %X, TH: %X, GAMEPAD_TH0: %X, GAMEPAD_TH1: %X, TH Counter: %d, Timeout: %d, Cycle: %d\n", control, th, pad->input[GAMEPAD_TH0], pad->input[GAMEPAD_TH1], pad->th_counter,pad->timeout_cycle, context->current_cycle); - }*/ - if (th) { - if (pad->th_counter == 3) { - input = pad->input[GAMEPAD_EXTRA]; + case IO_GAMEPAD6: + { + if (current_cycle >= port->device.pad.timeout_cycle) { + port->device.pad.th_counter = 0; + } + /*if (port->input[GAMEPAD_TH0] || port->input[GAMEPAD_TH1]) { + printf("io_data_read | control: %X, TH: %X, GAMEPAD_TH0: %X, GAMEPAD_TH1: %X, TH Counter: %d, Timeout: %d, Cycle: %d\n", control, th, port->input[GAMEPAD_TH0], port->input[GAMEPAD_TH1], port->th_counter,port->timeout_cycle, context->current_cycle); + }*/ + if (th) { + if (port->device.pad.th_counter == 3) { + input = port->input[GAMEPAD_EXTRA]; + } else { + input = port->input[GAMEPAD_TH1]; + } } else { - input = pad->input[GAMEPAD_TH1]; + if (port->device.pad.th_counter == 3) { + input = port->input[GAMEPAD_TH0] | 0xF; + } else if(port->device.pad.th_counter == 4) { + input = port->input[GAMEPAD_TH0] & 0x30; + } else { + input = port->input[GAMEPAD_TH0] | 0xC; + } } - } else { - if (pad->th_counter == 3) { - input = pad->input[GAMEPAD_TH0] | 0xF; - } else if(pad->th_counter == 4) { - input = pad->input[GAMEPAD_TH0] & 0x30; - } else { - input = pad->input[GAMEPAD_TH0] | 0xC; + break; + } + case IO_SEGA_PARALLEL: + if (!th) + { + service_pipe(port); } + input = ~port->input[th ? IO_TH1 : IO_TH0]; + break; + case IO_GENERIC: + if (port->input[IO_TH0] & 0x80 && port->input[IO_STATE] == IO_WRITTEN) + { + //device requested a blocking read after writes + port->input[IO_STATE] = IO_READ_PENDING; + } + service_socket(port); + input = ~port->input[IO_TH0]; + break; + default: + input = 0; + break; } - uint8_t value = ((~input) & (~control)) | (pad->output & control); - /*if (pad->input[GAMEPAD_TH0] || pad->input[GAMEPAD_TH1]) { + uint8_t value = ((~input) & (~control)) | (port->output & control); + /*if (port->input[GAMEPAD_TH0] || port->input[GAMEPAD_TH1]) { printf ("value: %X\n", value); }*/ return value; diff -r 9d6fed6501ba -r f822d9216968 io.h --- a/io.h Mon Dec 29 23:08:39 2014 -0800 +++ b/io.h Tue Dec 30 19:11:34 2014 -0800 @@ -1,18 +1,43 @@ /* Copyright 2013 Michael Pavone - This file is part of BlastEm. + This file is part of BlastEm. BlastEm is free software distributed under the terms of the GNU General Public License version 3 or greater. See COPYING for full license text. */ #ifndef IO_H_ #define IO_H_ #include +#include "tern.h" + +enum { + IO_GAMEPAD3, + IO_GAMEPAD6, + IO_MOUSE, + IO_MENACER, + IO_JUSTIFIER, + IO_SEGA_MULTI, + IO_EA_MULTI_A, + IO_EA_MULTI_B, + IO_SEGA_PARALLEL, + IO_GENERIC, + IO_NONE +}; typedef struct { - uint32_t th_counter; - uint32_t timeout_cycle; - uint8_t output; - uint8_t control; - uint8_t input[3]; + union { + struct { + uint32_t timeout_cycle; + uint16_t th_counter; + uint16_t gamepad_num; + } pad; + struct { + int data_fd; + int listen_fd; + } stream; + } device; + uint8_t output; + uint8_t control; + uint8_t input[3]; + uint8_t device_type; } io_port; #define GAMEPAD_TH0 0 @@ -20,7 +45,19 @@ #define GAMEPAD_EXTRA 2 #define GAMEPAD_NONE 0xF -void set_keybindings(); +#define IO_TH0 0 +#define IO_TH1 1 +#define IO_STATE 2 + +enum { + IO_WRITE_PENDING, + IO_WRITTEN, + IO_READ_PENDING, + IO_READ +}; + +void set_keybindings(io_port *ports); +void setup_io_devices(tern_node * config, io_port * ports); void io_adjust_cycles(io_port * pad, uint32_t current_cycle, uint32_t deduction); void io_data_write(io_port * pad, uint8_t value, uint32_t current_cycle); uint8_t io_data_read(io_port * pad, uint32_t current_cycle); diff -r 9d6fed6501ba -r f822d9216968 render_sdl.c --- a/render_sdl.c Mon Dec 29 23:08:39 2014 -0800 +++ b/render_sdl.c Tue Dec 30 19:11:34 2014 -0800 @@ -364,7 +364,7 @@ glBindTexture(GL_TEXTURE_2D, (context->regs[REG_MODE_4] & BIT_INTERLACE) ? textures[1] : textures[2]); glUniform1i(un_textures[1], 1); - glUniform1f(un_width, context->latched_mode & BIT_H40 ? 320.0f : 256.0f); + glUniform1f(un_width, context->regs[REG_MODE_4] & BIT_H40 ? 320.0f : 256.0f); glBindBuffer(GL_ARRAY_BUFFER, buffers[0]); glVertexAttribPointer(at_pos, 2, GL_FLOAT, GL_FALSE, sizeof(GLfloat[2]), (void *)0); diff -r 9d6fed6501ba -r f822d9216968 tern.c --- a/tern.c Mon Dec 29 23:08:39 2014 -0800 +++ b/tern.c Tue Dec 30 19:11:34 2014 -0800 @@ -122,4 +122,14 @@ return tern_insert(head, key, val); } - +char * tern_int_key(uint32_t key, char * buf) +{ + char * cur = buf; + while (key) + { + *(cur++) = (key & 0x7F) + 1; + key >>= 7; + } + *cur = 0; + return buf; +} diff -r 9d6fed6501ba -r f822d9216968 tern.h --- a/tern.h Mon Dec 29 23:08:39 2014 -0800 +++ b/tern.h Tue Dec 30 19:11:34 2014 -0800 @@ -8,6 +8,8 @@ #include +#define MAX_INT_KEY_SIZE (sizeof(uint32_t) + 2) + typedef union { void *ptrval; intptr_t intval; @@ -31,5 +33,6 @@ void * tern_find_ptr_default(tern_node * head, char * key, void * def); void * tern_find_ptr(tern_node * head, char * key); tern_node * tern_insert_ptr(tern_node * head, char * key, void * value); +char * tern_int_key(uint32_t key, char * buf); #endif //TERN_H_ diff -r 9d6fed6501ba -r f822d9216968 vdp.c --- a/vdp.c Mon Dec 29 23:08:39 2014 -0800 +++ b/vdp.c Tue Dec 30 19:11:34 2014 -0800 @@ -9,8 +9,8 @@ #include #include "render.h" -#define NTSC_ACTIVE 225 -#define PAL_ACTIVE 241 +#define NTSC_INACTIVE_START 224 +#define PAL_INACTIVE_START 240 #define BUF_BIT_PRIORITY 0x40 #define MAP_BIT_PRIORITY 0x8000 #define MAP_BIT_H_FLIP 0x800 @@ -22,14 +22,17 @@ #define MCLKS_SLOT_H40 16 #define MCLKS_SLOT_H32 20 -#define VINT_CYCLE_H40 (21*MCLKS_SLOT_H40+332+9*MCLKS_SLOT_H40) //21 slots before HSYNC, 16 during, 10 after -#define VINT_CYCLE_H32 ((33+20+7)*MCLKS_SLOT_H32) //33 slots before HSYNC, 20 during, 7 after TODO: confirm final number -#define HSYNC_SLOT_H40 21 -#define MCLK_WEIRD_END (HSYNC_SLOT_H40*MCLKS_SLOT_H40 + 332) -#define SLOT_WEIRD_END (HSYNC_SLOT_H40+17) +#define VINT_SLOT_H40 4 //21 slots before HSYNC, 16 during, 10 after +#define VINT_SLOT_H32 23 //33 slots before HSYNC, 20 during, 7 after TODO: confirm final number +#define HSYNC_SLOT_H40 240 +#define HSYNC_END_H40 (240+17) #define HSYNC_END_H32 (33 * MCLKS_SLOT_H32) -#define HBLANK_CLEAR_H40 (MCLK_WEIRD_END+61*4) -#define HBLANK_CLEAR_H32 (HSYNC_END_H32 + 46*5) +#define HBLANK_START_H40 178 //should be 179 according to Nemesis, but 178 seems to fit slightly better with my test ROM results +#define HBLANK_END_H40 0 //should be 5.5 according to Nemesis, but 0 seems to fit better with my test ROM results +#define HBLANK_START_H32 233 //should be 147 according to Nemesis which is very different from my test ROM result +#define HBLANK_END_H32 0 //should be 5 according to Nemesis, but 0 seems to fit better with my test ROM results +#define LINE_CHANGE_H40 165 +#define LINE_CHANGE_H32 132 #define FIFO_LATENCY 3 int32_t color_map[1 << 12]; @@ -45,7 +48,7 @@ uint8_t color_map_init_done; -void init_vdp_context(vdp_context * context) +void init_vdp_context(vdp_context * context, uint8_t region_pal) { memset(context, 0, sizeof(*context)); context->vdpmem = malloc(VRAM_SIZE); @@ -132,18 +135,21 @@ context->debugcolors[color] = render_map_color(r, g, b); } } + if (region_pal) { + context->flags2 |= FLAG2_REGION_PAL; + } } int is_refresh(vdp_context * context, uint32_t slot) { - if (context->latched_mode & BIT_H40) { - return (slot == 37 || slot == 69 || slot == 102 || slot == 133 || slot == 165 || slot == 197 || slot >= 210); + if (context->regs[REG_MODE_4] & BIT_H40) { + return slot == 250 || slot == 26 || slot == 59 || slot == 90 || slot == 122 || slot == 154; } else { //TODO: Figure out which slots are refresh when display is off in 32-cell mode //These numbers are guesses based on H40 numbers - return (slot == 24 || slot == 56 || slot == 88 || slot == 120 || slot == 152); + return slot == 243 || slot == 19 || slot == 51 || slot == 83 || slot == 115; //The numbers below are the refresh slots during active display - //return (slot == 66 || slot == 98 || slot == 130 || slot == 162); + //return (slot == 29 || slot == 61 || slot == 93 || slot == 125); } } @@ -227,8 +233,8 @@ context->regs[REG_SCROLL_A], (context->regs[REG_SCROLL_A] & 0x38) << 10, context->regs[REG_WINDOW], (context->regs[REG_WINDOW] & (context->regs[REG_MODE_4] & BIT_H40 ? 0x3C : 0x3E)) << 10, context->regs[REG_SCROLL_B], (context->regs[REG_SCROLL_B] & 0x7) << 13, - context->regs[REG_SAT], (context->regs[REG_SAT] & (context->regs[REG_MODE_4] & BIT_H40 ? 0x3E : 0x3F)) << 9, - context->regs[REG_HSCROLL], (context->regs[REG_HSCROLL] & 0x1F) << 10); + context->regs[REG_SAT], (context->regs[REG_SAT] & (context->regs[REG_MODE_4] & BIT_H40 ? 0x7E : 0x7F)) << 9, + context->regs[REG_HSCROLL], (context->regs[REG_HSCROLL] & 0x3F) << 10); char * sizes[] = {"32", "64", "invalid", "128"}; printf("\n**Misc Group**\n" "07: %.2X | Backdrop Color: $%X\n" @@ -239,11 +245,28 @@ context->regs[REG_HINT], context->regs[REG_HINT], context->regs[REG_AUTOINC], context->regs[REG_AUTOINC], context->regs[REG_SCROLL], sizes[context->regs[REG_SCROLL] & 0x3], sizes[context->regs[REG_SCROLL] >> 4 & 0x3]); + char * src_types[] = {"68K", "68K", "Copy", "Fill"}; + printf("\n**DMA Group**\n" + "13: %.2X |\n" + "14: %.2X | DMA Length: $%.4X words\n" + "15: %.2X |\n" + "16: %.2X |\n" + "17: %.2X | DMA Source Address: $%.6X, Type: %s\n", + context->regs[REG_DMALEN_L], + context->regs[REG_DMALEN_H], context->regs[REG_DMALEN_H] << 8 | context->regs[REG_DMALEN_L], + context->regs[REG_DMASRC_L], + context->regs[REG_DMASRC_M], + context->regs[REG_DMASRC_H], + context->regs[REG_DMASRC_H] << 17 | context->regs[REG_DMASRC_M] << 9 | context->regs[REG_DMASRC_L] << 1, + src_types[context->regs[REG_DMASRC_H] >> 6 & 3]); printf("\n**Internal Group**\n" "Address: %X\n" "CD: %X\n" - "Pending: %s\n", - context->address, context->cd, (context->flags & FLAG_PENDING) ? "true" : "false"); + "Pending: %s\n" + "VCounter: %d\n" + "HCounter: %d\n", + context->address, context->cd, (context->flags & FLAG_PENDING) ? "true" : "false", + context->vcounter, context->hslot*2); //TODO: Window Group, DMA Group } @@ -269,7 +292,7 @@ height_mult = 8; } context->sprite_index &= 0x7F; - if (context->latched_mode & BIT_H40) { + if (context->regs[REG_MODE_4] & BIT_H40) { if (context->sprite_index >= MAX_SPRITES_FRAME) { context->sprite_index = 0; return; @@ -472,7 +495,7 @@ case 0x40: if (!slot || !is_refresh(context, slot-1)) { cur = context->fifo + context->fifo_write; - cur->cycle = context->cycles + ((context->latched_mode & BIT_H40) ? 16 : 20)*FIFO_LATENCY; + cur->cycle = context->cycles + ((context->regs[REG_MODE_4] & BIT_H40) ? 16 : 20)*FIFO_LATENCY; cur->address = context->address; cur->value = read_dma_value((context->regs[REG_DMASRC_H] << 16) | (context->regs[REG_DMASRC_M] << 8) | context->regs[REG_DMASRC_L]); cur->cd = context->cd; @@ -567,7 +590,7 @@ if ((column >= left_col && column < right_col) || (line >= top_line && line < bottom_line)) { uint16_t address = context->regs[REG_WINDOW] << 10; uint16_t line_offset, offset, mask; - if (context->latched_mode & BIT_H40) { + if (context->regs[REG_MODE_4] & BIT_H40) { address &= 0xF000; line_offset = (((line) >> vscroll_shift) * 64 * 2) & 0xFFF; mask = 0x7F; @@ -893,13 +916,15 @@ uint32_t mask; switch(linecyc) { + case 165: + case 166: + external_slot(context); + break; //sprite render to line buffer starts - case 0: - context->cur_slot = MAX_DRAWS-1; - memset(context->linebuf, 0, LINEBUF_SIZE); - case 1: - case 2: - case 3: + case 167: + case 168: + case 169: + case 170: if (line == 0xFF) { external_slot(context); } else { @@ -907,52 +932,50 @@ } break; //sprite attribute table scan starts - case 4: + case 171: render_sprite_cells( context); - context->sprite_index = 0x80; - context->slot_counter = MAX_SPRITES_LINE; scan_sprite_table(line, context); break; - case 5: - case 6: - case 7: - case 8: - case 9: - case 10: - case 11: - case 12: - case 13: - case 14: - case 15: - case 16: - case 17: - case 18: - case 19: - case 20: + case 172: + case 173: + case 174: + case 175: + case 176: + case 177: + case 178: + case 179: + case 180: + case 181: + case 182: + case 229: + case 230: + case 231: + case 232: + case 233: //!HSYNC asserted - case 21: - case 22: + case 234: + case 235: render_sprite_cells(context); scan_sprite_table(line, context); break; - case 23: + case 236: external_slot(context); break; - case 24: - case 25: - case 26: - case 27: - case 28: - case 29: - case 30: - case 31: - case 32: - case 33: - case 34: + case 237: + case 238: + case 239: + case 240: + case 241: + case 242: + case 243: + case 244: + case 245: + case 246: + case 247: render_sprite_cells(context); scan_sprite_table(line, context); break; - case 35: + case 248: address = (context->regs[REG_HSCROLL] & 0x3F) << 10; mask = 0; if (context->regs[REG_MODE_3] & 0x2) { @@ -967,41 +990,41 @@ context->hscroll_b = context->vdpmem[address+2] << 8 | context->vdpmem[address+3]; //printf("%d: HScroll A: %d, HScroll B: %d\n", line, context->hscroll_a, context->hscroll_b); break; - case 36: + case 249: //!HSYNC high - case 37: - case 38: - case 39: + case 250: + case 251: + case 252: render_sprite_cells(context); scan_sprite_table(line, context); break; - case 40: + case 253: read_map_scroll_a(0, line, context); break; - case 41: + case 254: render_sprite_cells(context); scan_sprite_table(line, context); break; - case 42: + case 255: render_map_1(context); scan_sprite_table(line, context);//Just a guess break; - case 43: + case 0: render_map_2(context); scan_sprite_table(line, context);//Just a guess break; - case 44: + case 1: read_map_scroll_b(0, line, context); break; - case 45: + case 2: render_sprite_cells(context); scan_sprite_table(line, context); break; - case 46: + case 3: render_map_3(context); scan_sprite_table(line, context);//Just a guess break; - case 47: + case 4: render_map_output(line, 0, context); scan_sprite_table(line, context);//Just a guess //reverse context slot counter so it counts the number of sprite slots @@ -1011,33 +1034,26 @@ context->sprite_draws = MAX_DRAWS; context->flags &= (~FLAG_CAN_MASK & ~FLAG_MASKED); break; - COLUMN_RENDER_BLOCK(2, 48) - COLUMN_RENDER_BLOCK(4, 56) - COLUMN_RENDER_BLOCK(6, 64) - COLUMN_RENDER_BLOCK_REFRESH(8, 72) - COLUMN_RENDER_BLOCK(10, 80) - COLUMN_RENDER_BLOCK(12, 88) - COLUMN_RENDER_BLOCK(14, 96) - COLUMN_RENDER_BLOCK_REFRESH(16, 104) - COLUMN_RENDER_BLOCK(18, 112) - COLUMN_RENDER_BLOCK(20, 120) - COLUMN_RENDER_BLOCK(22, 128) - COLUMN_RENDER_BLOCK_REFRESH(24, 136) - COLUMN_RENDER_BLOCK(26, 144) - COLUMN_RENDER_BLOCK(28, 152) - COLUMN_RENDER_BLOCK(30, 160) - COLUMN_RENDER_BLOCK_REFRESH(32, 168) - COLUMN_RENDER_BLOCK(34, 176) - COLUMN_RENDER_BLOCK(36, 184) - COLUMN_RENDER_BLOCK(38, 192) - COLUMN_RENDER_BLOCK_REFRESH(40, 200) - case 208: - case 209: - external_slot(context); - break; - default: - //leftovers from HSYNC clock change nonsense - break; + COLUMN_RENDER_BLOCK(2, 5) + COLUMN_RENDER_BLOCK(4, 13) + COLUMN_RENDER_BLOCK(6, 21) + COLUMN_RENDER_BLOCK_REFRESH(8, 29) + COLUMN_RENDER_BLOCK(10, 37) + COLUMN_RENDER_BLOCK(12, 45) + COLUMN_RENDER_BLOCK(14, 53) + COLUMN_RENDER_BLOCK_REFRESH(16, 61) + COLUMN_RENDER_BLOCK(18, 69) + COLUMN_RENDER_BLOCK(20, 77) + COLUMN_RENDER_BLOCK(22, 85) + COLUMN_RENDER_BLOCK_REFRESH(24, 93) + COLUMN_RENDER_BLOCK(26, 101) + COLUMN_RENDER_BLOCK(28, 109) + COLUMN_RENDER_BLOCK(30, 117) + COLUMN_RENDER_BLOCK_REFRESH(32, 125) + COLUMN_RENDER_BLOCK(34, 133) + COLUMN_RENDER_BLOCK(36, 141) + COLUMN_RENDER_BLOCK(38, 149) + COLUMN_RENDER_BLOCK_REFRESH(40, 157) } } @@ -1047,13 +1063,15 @@ uint32_t mask; switch(linecyc) { + case 132: + case 133: + external_slot(context); + break; //sprite render to line buffer starts - case 0: - context->cur_slot = MAX_DRAWS_H32-1; - memset(context->linebuf, 0, LINEBUF_SIZE); - case 1: - case 2: - case 3: + case 134: + case 135: + case 136: + case 137: if (line == 0xFF) { external_slot(context); } else { @@ -1061,46 +1079,44 @@ } break; //sprite attribute table scan starts - case 4: + case 138: render_sprite_cells( context); - context->sprite_index = 0x80; - context->slot_counter = MAX_SPRITES_LINE_H32; scan_sprite_table(line, context); break; - case 5: - case 6: - case 7: - case 8: - case 9: - case 10: - case 11: - case 12: - case 13: + case 139: + case 140: + case 141: + case 142: + case 143: + case 144: + case 145: + case 146: + case 147: render_sprite_cells(context); scan_sprite_table(line, context); - case 14: + case 233: external_slot(context); break; - case 15: - case 16: - case 17: - case 18: - case 19: + case 234: + case 235: + case 236: + case 237: + case 238: //HSYNC start - case 20: - case 21: - case 22: - case 23: - case 24: - case 25: - case 26: + case 239: + case 240: + case 241: + case 242: + case 243: + case 244: + case 245: render_sprite_cells(context); scan_sprite_table(line, context); break; - case 27: + case 246: external_slot(context); break; - case 28: + case 247: address = (context->regs[REG_HSCROLL] & 0x3F) << 10; mask = 0; if (context->regs[REG_MODE_3] & 0x2) { @@ -1115,41 +1131,41 @@ context->hscroll_b = context->vdpmem[address+2] << 8 | context->vdpmem[address+3]; //printf("%d: HScroll A: %d, HScroll B: %d\n", line, context->hscroll_a, context->hscroll_b); break; - case 29: - case 30: - case 31: - case 32: + case 248: + case 249: + case 250: + case 251: render_sprite_cells(context); scan_sprite_table(line, context); break; //!HSYNC high - case 33: + case 252: read_map_scroll_a(0, line, context); break; - case 34: + case 253: render_sprite_cells(context); scan_sprite_table(line, context); break; - case 35: + case 254: render_map_1(context); scan_sprite_table(line, context);//Just a guess break; - case 36: + case 255: render_map_2(context); scan_sprite_table(line, context);//Just a guess break; - case 37: + case 0: read_map_scroll_b(0, line, context); break; - case 38: + case 1: render_sprite_cells(context); scan_sprite_table(line, context); break; - case 39: + case 2: render_map_3(context); scan_sprite_table(line, context);//Just a guess break; - case 40: + case 3: render_map_output(line, 0, context); scan_sprite_table(line, context);//Just a guess //reverse context slot counter so it counts the number of sprite slots @@ -1159,26 +1175,22 @@ context->sprite_draws = MAX_DRAWS_H32; context->flags &= (~FLAG_CAN_MASK & ~FLAG_MASKED); break; - COLUMN_RENDER_BLOCK(2, 41) - COLUMN_RENDER_BLOCK(4, 49) - COLUMN_RENDER_BLOCK(6, 57) - COLUMN_RENDER_BLOCK_REFRESH(8, 65) - COLUMN_RENDER_BLOCK(10, 73) - COLUMN_RENDER_BLOCK(12, 81) - COLUMN_RENDER_BLOCK(14, 89) - COLUMN_RENDER_BLOCK_REFRESH(16, 97) - COLUMN_RENDER_BLOCK(18, 105) - COLUMN_RENDER_BLOCK(20, 113) - COLUMN_RENDER_BLOCK(22, 121) - COLUMN_RENDER_BLOCK_REFRESH(24, 129) - COLUMN_RENDER_BLOCK(26, 137) - COLUMN_RENDER_BLOCK(28, 145) - COLUMN_RENDER_BLOCK(30, 153) - COLUMN_RENDER_BLOCK_REFRESH(32, 161) - case 169: - case 170: - external_slot(context); - break; + COLUMN_RENDER_BLOCK(2, 4) + COLUMN_RENDER_BLOCK(4, 12) + COLUMN_RENDER_BLOCK(6, 20) + COLUMN_RENDER_BLOCK_REFRESH(8, 28) + COLUMN_RENDER_BLOCK(10, 36) + COLUMN_RENDER_BLOCK(12, 44) + COLUMN_RENDER_BLOCK(14, 52) + COLUMN_RENDER_BLOCK_REFRESH(16, 60) + COLUMN_RENDER_BLOCK(18, 68) + COLUMN_RENDER_BLOCK(20, 76) + COLUMN_RENDER_BLOCK(22, 84) + COLUMN_RENDER_BLOCK_REFRESH(24, 92) + COLUMN_RENDER_BLOCK(26, 100) + COLUMN_RENDER_BLOCK(28, 108) + COLUMN_RENDER_BLOCK(30, 116) + COLUMN_RENDER_BLOCK_REFRESH(32, 124) } } @@ -1203,6 +1215,14 @@ if (context->flags & FLAG_DMA_RUN) { run_dma_src(context, 0); } + external_slot(context); + if (context->flags & FLAG_DMA_RUN) { + run_dma_src(context, 0); + } + external_slot(context); + if (context->flags & FLAG_DMA_RUN) { + run_dma_src(context, 0); + } for (int i = 0; i < 19; i++) { scan_sprite_table(line, context); @@ -1240,13 +1260,17 @@ read_sprite_x(line, context); } - external_slot(context); - if (context->flags & FLAG_DMA_RUN) { - run_dma_src(context, 0); - } - external_slot(context); + return; } + external_slot(context); + if (context->flags & FLAG_DMA_RUN) { + run_dma_src(context, 0); + } + external_slot(context); + if (context->flags & FLAG_DMA_RUN) { + run_dma_src(context, 0); + } render_sprite_cells(context); render_sprite_cells(context); @@ -1356,73 +1380,81 @@ render_map_3(context); render_map_output(line, column, context); } - external_slot(context); - if (context->flags & FLAG_DMA_RUN) { - run_dma_src(context, 0); - } - external_slot(context); } void latch_mode(vdp_context * context) { - context->latched_mode = (context->regs[REG_MODE_4] & 0x81) | (context->regs[REG_MODE_2] & BIT_PAL); + context->latched_mode = context->regs[REG_MODE_2] & BIT_PAL; } void check_render_bg(vdp_context * context, int32_t line, uint32_t slot) { - if (line > 0) { - line -= 1; - int starti = -1; - if (context->latched_mode & BIT_H40) { - if (slot >= 55 && slot < 210) { - uint32_t x = (slot-55)*2; - starti = line * 320 + x; - } else if (slot < 5) { - uint32_t x = (slot + 155)*2; - starti = (line-1)*320 + x; + int starti = -1; + if (context->regs[REG_MODE_4] & BIT_H40) { + if (slot >= 12 && slot < 172) { + uint32_t x = (slot-12)*2; + starti = line * 320 + x; + } + } else { + if (slot >= 11 && slot < 139) { + uint32_t x = (slot-11)*2; + starti = line * 320 + x; + } + } + if (starti >= 0) { + if (context->b32) { + uint32_t color = context->colors[context->regs[REG_BG_COLOR]]; + uint32_t * start = context->framebuf; + start += starti; + for (int i = 0; i < 2; i++) { + *(start++) = color; } } else { - if (slot >= 48 && slot < 171) { - uint32_t x = (slot-48)*2; - starti = line * 320 + x; - } else if (slot < 5) { - uint32_t x = (slot + 123)*2; - starti = (line-1)*320 + x; - } - } - if (starti >= 0) { - if (context->b32) { - uint32_t color = context->colors[context->regs[REG_BG_COLOR]]; - uint32_t * start = context->framebuf; - start += starti; - for (int i = 0; i < 2; i++) { - *(start++) = color; - } - } else { - uint16_t color = context->colors[context->regs[REG_BG_COLOR]]; - uint16_t * start = context->framebuf; - start += starti; - for (int i = 0; i < 2; i++) { - *(start++) = color; - } + uint16_t color = context->colors[context->regs[REG_BG_COLOR]]; + uint16_t * start = context->framebuf; + start += starti; + for (int i = 0; i < 2; i++) { + *(start++) = color; } } } } +uint32_t h40_hsync_cycles[] = {19, 20, 20, 20, 18, 20, 20, 20, 18, 20, 20, 20, 18, 20, 20, 20, 19}; + void vdp_run_context(vdp_context * context, uint32_t target_cycles) { while(context->cycles < target_cycles) { context->flags &= ~FLAG_UNUSED_SLOT; - uint32_t line = context->cycles / MCLKS_LINE; - uint32_t active_lines = context->latched_mode & BIT_PAL ? PAL_ACTIVE : NTSC_ACTIVE; - if (!context->cycles) { + uint32_t line = context->vcounter; + uint32_t inactive_start = context->latched_mode & BIT_PAL ? PAL_INACTIVE_START : NTSC_INACTIVE_START; + uint32_t slot = context->hslot; + //TODO: Figure out when this actually happens + if (!line && !slot) { latch_mode(context); } - uint32_t linecyc = context->cycles % MCLKS_LINE; - if (linecyc == 0) { - if (line <= 1 || line >= active_lines) { + + uint8_t is_h40 = context->regs[REG_MODE_4] & BIT_H40; + if (is_h40) { + if (slot == 167) { + context->cur_slot = MAX_DRAWS-1; + memset(context->linebuf, 0, LINEBUF_SIZE); + } else if (slot == 171) { + context->sprite_index = 0x80; + context->slot_counter = MAX_SPRITES_LINE; + } + } else { + if (slot == 134) { + context->cur_slot = MAX_DRAWS_H32-1; + memset(context->linebuf, 0, LINEBUF_SIZE); + } else if (slot == 138) { + context->sprite_index = 0x80; + context->slot_counter = MAX_SPRITES_LINE_H32; + } + } + if (is_h40 && slot == LINE_CHANGE_H40 || !is_h40 && slot == LINE_CHANGE_H32) { + if (line >= inactive_start) { context->hint_counter = context->regs[REG_HINT]; } else if (context->hint_counter) { context->hint_counter--; @@ -1430,111 +1462,41 @@ context->flags2 |= FLAG2_HINT_PENDING; context->hint_counter = context->regs[REG_HINT]; } - } else if(line == active_lines) { - uint32_t intcyc = context->latched_mode & BIT_H40 ? VINT_CYCLE_H40 : VINT_CYCLE_H32; - if (linecyc == intcyc) { + } else if(line == inactive_start) { + uint32_t intslot = context->regs[REG_MODE_4] & BIT_H40 ? VINT_SLOT_H40 : VINT_SLOT_H32; + if (slot == intslot) { context->flags2 |= FLAG2_VINT_PENDING; } } - uint32_t inccycles, slot; - if (context->latched_mode & BIT_H40){ - if (linecyc < MCLKS_SLOT_H40*HSYNC_SLOT_H40) { - slot = linecyc/MCLKS_SLOT_H40; + uint32_t inccycles; + //line 0x1FF is basically active even though it's not displayed + uint8_t active_slot = line < inactive_start || line == 0x1FF; + if (is_h40) { + if (slot < HSYNC_SLOT_H40 || slot >= HSYNC_END_H40) { inccycles = MCLKS_SLOT_H40; - } else if(linecyc < MCLK_WEIRD_END) { - switch(linecyc-(MCLKS_SLOT_H40*HSYNC_SLOT_H40)) - { - case 0: - inccycles = 19; - slot = 0; - break; - case 19: - slot = 1; - inccycles = 20; - break; - case 39: - slot = 2; - inccycles = 20; - break; - case 59: - slot = 3; - inccycles = 20; - break; - case 79: - slot = 4; - inccycles = 18; - break; - case 97: - slot = 5; - inccycles = 20; - break; - case 117: - slot = 6; - inccycles = 20; - break; - case 137: - slot = 7; - inccycles = 20; - break; - case 157: - slot = 8; - inccycles = 18; - break; - case 175: - slot = 9; - inccycles = 20; - break; - case 195: - slot = 10; - inccycles = 20; - break; - case 215: - slot = 11; - inccycles = 20; - break; - case 235: - slot = 12; - inccycles = 18; - break; - case 253: - slot = 13; - inccycles = 20; - break; - case 273: - slot = 14; - inccycles = 20; - break; - case 293: - slot = 15; - inccycles = 20; - break; - case 313: - slot = 16; - inccycles = 19; - break; - default: - fprintf(stderr, "cycles after weirdness %d\n", linecyc-(MCLKS_SLOT_H40*HSYNC_SLOT_H40)); - exit(1); - } - slot += HSYNC_SLOT_H40; } else { - slot = (linecyc-MCLK_WEIRD_END)/MCLKS_SLOT_H40 + SLOT_WEIRD_END; - inccycles = MCLKS_SLOT_H40; + inccycles = h40_hsync_cycles[slot-HSYNC_SLOT_H40]; + } + //the first inactive line behaves as an active one for the first 4 slots + if (line == inactive_start && slot > 166 && slot < 171) { + active_slot = 1; } } else { inccycles = MCLKS_SLOT_H32; - slot = linecyc/MCLKS_SLOT_H32; + //the first inactive line behaves as an active one for the first 4 slots + if (line == inactive_start && slot > 166 && slot < 171) { + active_slot = 1; + } } - if ((line < active_lines || (line == active_lines && linecyc < (context->latched_mode & BIT_H40 ? 64 : 80))) && context->regs[REG_MODE_2] & DISPLAY_ENABLE) { - //first sort-of active line is treated as 255 internally - //it's used for gathering sprite info for line - line = (line - 1) & 0xFF; - - //Convert to slot number - if (context->latched_mode & BIT_H40){ - if (!slot && line != (active_lines-1) && (target_cycles - context->cycles) >= MCLKS_LINE) { + uint8_t inc_slot = 1; + if (context->regs[REG_MODE_2] & DISPLAY_ENABLE && active_slot) { + //run VDP rendering for a slot or a line + if (is_h40) { + if (slot == LINE_CHANGE_H40 && line < inactive_start && (target_cycles - context->cycles) >= MCLKS_LINE) { vdp_h40_line(line, context); inccycles = MCLKS_LINE; + context->vcounter++; + inc_slot = 0; } else { vdp_h40(line, slot, context); } @@ -1545,20 +1507,50 @@ if (!is_refresh(context, slot)) { external_slot(context); } - if (line < active_lines) { + if (line < inactive_start) { check_render_bg(context, line, slot); } } if (context->flags & FLAG_DMA_RUN && !is_refresh(context, slot)) { run_dma_src(context, slot); } + if (inc_slot) { + context->hslot++; + context->hslot &= 0xFF; + if (is_h40) { + if (context->hslot == LINE_CHANGE_H40) { + context->vcounter++; + } else if (context->hslot == 183) { + context->hslot = 229; + } + } else { + if (context->hslot == LINE_CHANGE_H32) { + context->vcounter++; + } else if (context->hslot == 148) { + context->hslot = 233; + } + } + + } + context->vcounter &= 0x1FF; + if (context->flags2 & FLAG2_REGION_PAL) { + if (context->latched_mode & BIT_PAL) { + if (context->vcounter == 0x10B) { + context->vcounter = 0x1D2; + } + } else if (context->vcounter == 0x103){ + context->vcounter = 0x1CA; + } + } else if (!(context->latched_mode & BIT_PAL) && context->vcounter == 0xEB) { + context->vcounter = 0x1E5; + } context->cycles += inccycles; } } uint32_t vdp_run_to_vblank(vdp_context * context) { - uint32_t target_cycles = ((context->latched_mode & BIT_PAL) ? PAL_ACTIVE : NTSC_ACTIVE) * MCLKS_LINE; + uint32_t target_cycles = ((context->latched_mode & BIT_PAL) ? PAL_INACTIVE_START : NTSC_INACTIVE_START) * MCLKS_LINE; vdp_run_context(context, target_cycles); return context->cycles; } @@ -1570,7 +1562,7 @@ if (!dmalen) { dmalen = 0x10000; } - uint32_t min_dma_complete = dmalen * (context->latched_mode & BIT_H40 ? 16 : 20); + uint32_t min_dma_complete = dmalen * (context->regs[REG_MODE_4] & BIT_H40 ? 16 : 20); if ((context->regs[REG_DMASRC_H] & 0xC0) == 0xC0 || (context->cd & 0xF) == VRAM_WRITE) { //DMA copies take twice as long to complete since they require a read and a write //DMA Fills and transfers to VRAM also take twice as long as it requires 2 writes for a single word @@ -1661,10 +1653,10 @@ context->flags &= ~FLAG_DMA_RUN; } while (context->fifo_write == context->fifo_read) { - vdp_run_context(context, context->cycles + ((context->latched_mode & BIT_H40) ? 16 : 20)); + vdp_run_context(context, context->cycles + ((context->regs[REG_MODE_4] & BIT_H40) ? 16 : 20)); } fifo_entry * cur = context->fifo + context->fifo_write; - cur->cycle = context->cycles + ((context->latched_mode & BIT_H40) ? 16 : 20)*FIFO_LATENCY; + cur->cycle = context->cycles + ((context->regs[REG_MODE_4] & BIT_H40) ? 16 : 20)*FIFO_LATENCY; cur->address = context->address; cur->value = value; if (context->cd & 0x20 && (context->regs[REG_DMASRC_H] & 0xC0) == 0x80) { @@ -1709,13 +1701,25 @@ if ((context->regs[REG_MODE_4] & BIT_INTERLACE) && context->framebuf == context->oddbuf) { value |= 0x10; } - uint32_t line= context->cycles / MCLKS_LINE; - uint32_t linecyc = context->cycles % MCLKS_LINE; - if (line >= (context->latched_mode & BIT_PAL ? PAL_ACTIVE : NTSC_ACTIVE) || !(context->regs[REG_MODE_2] & BIT_DISP_EN)) { + uint32_t line= context->vcounter; + uint32_t slot = context->hslot; + if ( + ( + line >= (context->latched_mode & BIT_PAL ? PAL_INACTIVE_START : NTSC_INACTIVE_START) + && line < 0x1FF + ) + || !(context->regs[REG_MODE_2] & BIT_DISP_EN) + ) { value |= 0x8; } - if (linecyc < (context->latched_mode & BIT_H40 ? HBLANK_CLEAR_H40 : HBLANK_CLEAR_H32)) { - value |= 0x4; + if (context->regs[REG_MODE_4] & BIT_H40) { + if (slot < HBLANK_END_H40 || slot > HBLANK_START_H40) { + value |= 0x4; + } + } else { + if (slot < HBLANK_END_H32 || slot > HBLANK_START_H32) { + value |= 0x4; + } } if (context->flags & FLAG_DMA_RUN) { value |= 0x2; @@ -1741,7 +1745,7 @@ context->flags &= ~FLAG_UNUSED_SLOT; //context->flags2 |= FLAG2_READ_PENDING; while (!(context->flags & FLAG_UNUSED_SLOT)) { - vdp_run_context(context, context->cycles + ((context->latched_mode & BIT_H40) ? 16 : 20)); + vdp_run_context(context, context->cycles + ((context->regs[REG_MODE_4] & BIT_H40) ? 16 : 20)); } uint16_t value = 0; switch (context->cd & 0xF) @@ -1751,7 +1755,7 @@ context->flags &= ~FLAG_UNUSED_SLOT; context->flags2 |= FLAG2_READ_PENDING; while (!(context->flags & FLAG_UNUSED_SLOT)) { - vdp_run_context(context, context->cycles + ((context->latched_mode & BIT_H40) ? 16 : 20)); + vdp_run_context(context, context->cycles + ((context->regs[REG_MODE_4] & BIT_H40) ? 16 : 20)); } value |= context->vdpmem[context->address | 1]; break; @@ -1782,102 +1786,8 @@ if (context->regs[REG_MODE_1] & BIT_HVC_LATCH) { return context->hv_latch; } - uint32_t line= context->cycles / MCLKS_LINE; - if (!line) { - line = 0xFF; - } else { - line--; - if (line > 0xEA) { - line = (line + 0xFA) & 0xFF; - } - } - uint32_t linecyc = context->cycles % MCLKS_LINE; - if (context->latched_mode & BIT_H40) { - uint32_t slot; - if (linecyc < MCLKS_SLOT_H40*HSYNC_SLOT_H40) { - slot = linecyc/MCLKS_SLOT_H40; - } else if(linecyc < MCLK_WEIRD_END) { - switch(linecyc-(MCLKS_SLOT_H40*HSYNC_SLOT_H40)) - { - case 0: - slot = 0; - break; - case 19: - slot = 1; - break; - case 39: - slot = 2; - break; - case 59: - slot = 2; - break; - case 79: - slot = 3; - break; - case 97: - slot = 4; - break; - case 117: - slot = 5; - break; - case 137: - slot = 6; - break; - case 157: - slot = 7; - break; - case 175: - slot = 8; - break; - case 195: - slot = 9; - break; - case 215: - slot = 11; - break; - case 235: - slot = 12; - break; - case 253: - slot = 13; - break; - case 273: - slot = 14; - break; - case 293: - slot = 15; - break; - case 313: - slot = 16; - break; - default: - fprintf(stderr, "cycles after weirdness %d\n", linecyc-(MCLKS_SLOT_H40*HSYNC_SLOT_H40)); - exit(1); - } - slot += HSYNC_SLOT_H40; - } else { - slot = (linecyc-MCLK_WEIRD_END)/MCLKS_SLOT_H40 + SLOT_WEIRD_END; - } - linecyc = slot * 2; - if (linecyc >= 86) { - linecyc -= 86; - } else { - linecyc += 334; - } - if (linecyc > 0x16C) { - linecyc += 92; - } - } else { - linecyc /= 10; - if (linecyc >= 74) { - linecyc -= 74; - } else { - linecyc += 268; - } - if (linecyc > 0x127) { - linecyc += 170; - } - } + uint32_t line= context->vcounter & 0xFF; + uint32_t linecyc = context->hslot; linecyc &= 0xFF; if (context->double_res) { line <<= 1; @@ -1910,6 +1820,88 @@ } } +uint32_t vdp_cycles_next_line(vdp_context * context) +{ + if (context->regs[REG_MODE_4] & BIT_H40) { + if (context->hslot < LINE_CHANGE_H40) { + return (HBLANK_START_H40 - context->hslot) * MCLKS_SLOT_H40; + } else if (context->hslot < 183) { + return MCLKS_LINE - (context->hslot - LINE_CHANGE_H40) * MCLKS_SLOT_H40; + } else { + return (256-context->hslot + LINE_CHANGE_H40) * MCLKS_SLOT_H40; + } + } else { + if (context->hslot < LINE_CHANGE_H32) { + return (LINE_CHANGE_H32 - context->hslot) * MCLKS_SLOT_H32; + } else if (context->hslot < 148) { + return MCLKS_LINE - (context->hslot - LINE_CHANGE_H32) * MCLKS_SLOT_H32; + } else { + return (256-context->hslot + LINE_CHANGE_H32) * MCLKS_SLOT_H32; + } + } +} + +uint32_t vdp_cycles_to_line(vdp_context * context, uint32_t target) +{ + uint32_t jump_start, jump_dst; + if (context->flags2 & FLAG2_REGION_PAL) { + if (context->latched_mode & BIT_PAL) { + jump_start = 0x10B; + jump_dst = 0x1D2; + } else { + jump_start = 0x103; + jump_dst = 0x1CA; + } + } else { + if (context->latched_mode & BIT_PAL) { + jump_start = 0; + jump_dst = 0; + } else { + jump_start = 0xEB; + jump_dst = 0x1E5; + } + } + uint32_t lines; + if (context->vcounter < target) { + if (target < jump_start) { + lines = target - context->vcounter; + } else { + lines = jump_start - context->vcounter + target - jump_dst; + } + } else { + if (context->vcounter < jump_start) { + lines = jump_start - context->vcounter + 512 - jump_dst; + } else { + lines = 512 - context->vcounter; + } + if (target < jump_start) { + lines += target; + } else { + lines += jump_start + target - jump_dst; + } + } + return MCLKS_LINE * (lines - 1) + vdp_cycles_next_line(context); +} + +uint32_t vdp_cycles_to_frame_end(vdp_context * context) +{ + uint32_t frame_end; + if (context->flags2 & FLAG2_REGION_PAL) { + if (context->latched_mode & BIT_PAL) { + frame_end = PAL_INACTIVE_START + 8; + } else { + frame_end = NTSC_INACTIVE_START + 8; + } + } else { + if (context->latched_mode & BIT_PAL) { + frame_end = 512; + } else { + frame_end = NTSC_INACTIVE_START + 8; + } + } + return context->cycles + vdp_cycles_to_line(context, frame_end); +} + uint32_t vdp_next_hint(vdp_context * context) { if (!(context->regs[REG_MODE_1] & BIT_HINT_EN)) { @@ -1918,17 +1910,15 @@ if (context->flags2 & FLAG2_HINT_PENDING) { return context->cycles; } - uint32_t active_lines = context->latched_mode & BIT_PAL ? PAL_ACTIVE : NTSC_ACTIVE; - uint32_t line = context->cycles / MCLKS_LINE; - if (line >= active_lines) { - return 0xFFFFFFFF; + uint32_t inactive_start = context->latched_mode & BIT_PAL ? PAL_INACTIVE_START : NTSC_INACTIVE_START; + uint32_t hint_line; + if (context->vcounter >= inactive_start) { + hint_line = context->regs[REG_HINT]; + } else { + hint_line = context->vcounter + context->hint_counter + 1; } - uint32_t linecyc = context->cycles % MCLKS_LINE; - uint32_t hcycle = context->cycles + context->hint_counter * MCLKS_LINE + MCLKS_LINE - linecyc; - if (!line) { - hcycle += MCLKS_LINE; - } - return hcycle; + + return context->cycles + vdp_cycles_to_line(context, hint_line); } uint32_t vdp_next_vint(vdp_context * context) @@ -1939,29 +1929,44 @@ if (context->flags2 & FLAG2_VINT_PENDING) { return context->cycles; } - uint32_t active_lines = context->latched_mode & BIT_PAL ? PAL_ACTIVE : NTSC_ACTIVE; - uint32_t vcycle = MCLKS_LINE * active_lines; - if (context->latched_mode & BIT_H40) { - vcycle += VINT_CYCLE_H40; - } else { - vcycle += VINT_CYCLE_H32; - } - if (vcycle < context->cycles) { - return 0xFFFFFFFF; - } - return vcycle; + + + return vdp_next_vint_z80(context); } uint32_t vdp_next_vint_z80(vdp_context * context) { - uint32_t active_lines = context->latched_mode & BIT_PAL ? PAL_ACTIVE : NTSC_ACTIVE; - uint32_t vcycle = MCLKS_LINE * active_lines; - if (context->latched_mode & BIT_H40) { - vcycle += VINT_CYCLE_H40; + uint32_t inactive_start = context->latched_mode & BIT_PAL ? PAL_INACTIVE_START : NTSC_INACTIVE_START; + if (context->vcounter == inactive_start) { + if (context->regs[REG_MODE_4] & BIT_H40) { + if (context->hslot >= HBLANK_START_H40) { + if (context->hslot < 183) { + return context->cycles + (VINT_SLOT_H40 + 183 - context->hslot + 256 - 229) * MCLKS_SLOT_H40; + } else { + return context->cycles + (VINT_SLOT_H40 + 256 - context->hslot) * MCLKS_SLOT_H40; + } + } else if (context->hslot < VINT_SLOT_H40) { + return context->cycles + (VINT_SLOT_H40 - context->hslot) * MCLKS_SLOT_H40; + } + } else { + if (context->hslot >= HBLANK_START_H32) { + if (context->hslot < 148) { + return context->cycles + (VINT_SLOT_H32 + 148 - context->hslot + 256 - 233) * MCLKS_SLOT_H32; + } else { + return context->cycles + (VINT_SLOT_H32 + 256 - context->hslot) * MCLKS_SLOT_H32; + } + } else if (context->hslot < VINT_SLOT_H32) { + return context->cycles + (VINT_SLOT_H32 - context->hslot) * MCLKS_SLOT_H32; + } + } + } + int32_t cycles_to_vint = vdp_cycles_to_line(context, inactive_start); + if (context->regs[REG_MODE_4] & BIT_H40) { + cycles_to_vint += (VINT_SLOT_H40 + 183 - HBLANK_START_H40 + 256 - 229) * MCLKS_SLOT_H40; } else { - vcycle += VINT_CYCLE_H32; + cycles_to_vint += (VINT_SLOT_H32 + 148 - HBLANK_START_H32 + 256 - 233) * MCLKS_SLOT_H32; } - return vcycle; + return context->cycles + cycles_to_vint; } void vdp_int_ack(vdp_context * context, uint16_t int_num) diff -r 9d6fed6501ba -r f822d9216968 vdp.h --- a/vdp.h Mon Dec 29 23:08:39 2014 -0800 +++ b/vdp.h Tue Dec 30 19:11:34 2014 -0800 @@ -49,6 +49,7 @@ #define FLAG2_HINT_PENDING 0x02 #define FLAG2_READ_PENDING 0x04 #define FLAG2_SPRITE_COLLIDE 0x08 +#define FLAG2_REGION_PAL 0x10 #define DISPLAY_ENABLE 0x40 @@ -142,9 +143,11 @@ uint32_t colors[CRAM_SIZE*3]; uint32_t debugcolors[1 << (3 + 1 + 1 + 1)];//3 bits for source, 1 bit for priority, 1 bit for shadow, 1 bit for hilight uint16_t vsram[VSRAM_SIZE]; - uint8_t latched_mode; + uint16_t vcounter; + uint16_t hslot; //hcounter/2 uint16_t hscroll_a; uint16_t hscroll_b; + uint8_t latched_mode; uint8_t sprite_index; uint8_t sprite_draws; int8_t slot_counter; @@ -167,7 +170,7 @@ uint8_t *tmp_buf_b; } vdp_context; -void init_vdp_context(vdp_context * context); +void init_vdp_context(vdp_context * context, uint8_t region_pal); void vdp_run_context(vdp_context * context, uint32_t target_cycles); //runs from current cycle count to VBLANK for the current mode, returns ending cycle count uint32_t vdp_run_to_vblank(vdp_context * context); @@ -190,6 +193,7 @@ void vdp_print_sprite_table(vdp_context * context); void vdp_print_reg_explain(vdp_context * context); void latch_mode(vdp_context * context); +uint32_t vdp_cycles_to_frame_end(vdp_context * context); extern int32_t color_map[1 << 12]; diff -r 9d6fed6501ba -r f822d9216968 vos_prog_info.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vos_prog_info.c Tue Dec 30 19:11:34 2014 -0800 @@ -0,0 +1,100 @@ +#include +#include "vos_program_module.h" + +int main(int argc, char ** argv) +{ + vos_program_module header; + FILE * f = fopen(argv[1], "rb"); + vos_read_header(f, &header); + vos_read_alloc_module_map(f, &header); + vos_read_alloc_external_vars(f, &header); + + printf("Version: %d\n", header.version); + printf("Binder Version: %s\n", header.binder_version.str); + printf("Binder Options: %s\n", header.binder_options.str); + printf("System name: %s\n", header.system_name.str); + printf("User name: %s\n", header.user_name.str); + printf("Date bound: %d\n", header.date_bound); + printf("Code addresss: 0x%X, Static address: 0x%X\n", + header.main_entry_link.code_address, header.main_entry_link.static_address); + printf("User boundary: 0x%X\n", header.user_boundary); + printf("Num modules: %d\n", header.n_modules); + printf("Num extern vars: %d\n", header.n_external_vars); + printf("Num link names: %d\n", header.n_link_names); + printf("Num unsapped links: %d\n", header.n_unsnapped_links); + printf("Num VM pages: %d\n", header.n_vm_pages); + printf("Num header pages: %d\n", header.n_header_pages); + for (int i = 0; i < 3; i++) { + for (int j = 0; j < 4; j++) { + printf("Info %d:%d\n\tAddress: 0x%X\n\tLength: 0x%X\n", + i, j, header.info[i][j].address, header.info[i][j].len); + } + } + printf("Module map address: 0x%X\n", header.module_map_address); + printf("Module map length: 0x%X\n", header.module_map_len); + printf("External vars map address: 0x%X\n", header.external_vars_map_address); + printf("External vars map length: 0x%X\n", header.external_vars_map_len); + printf("Link names map address: 0x%X\n", header.link_names_map_address); + printf("Link names map length: 0x%X\n", header.link_names_map_len); + printf("Header address: 0x%X\n", header.header_address); + printf("Header length: 0x%X\n", header.header_len); + //printf("Access Info: 0x%X\n", header.header_address); + printf("Flags: 0x%X\n", header.flags); + printf("Num tasks: %d\n", header.n_tasks); + printf("Stack Size: 0x%X\n", header.stack_len); + printf("Num entries: %d\n", header.n_entries); + printf("Entry map address: 0x%X\n", header.entry_map_address); + printf("Entry map length: 0x%X\n", header.entry_map_len); + printf("Pop Version: %d\n", header.pop_version); + printf("Processor: %d\n", header.processor); + printf("Processor family: %d\n", header.processor_family); + printf("Release name: %s\n", header.release_name.str); + printf("Relocation info:\n\tMap Addres: 0x%X\n\tMap Length: 0x%X\n\tNum Relocations: %d\n", + header.relocation_info.map_address, header.relocation_info.map_len, + header.relocation_info.n_relocations); + printf("High water mark: 0x%X\n", header.high_water_mark); + printf("Copyright notice: %s\n", header.program_name.str); + printf("String pool address: 0x%X\n", header.string_pool_address); + printf("String pool length: 0x%X\n", header.string_pool_len); + printf("Object dir map address: 0x%X\n", header.obj_dir_map_address); + printf("Object dir map length: 0x%X\n", header.obj_dir_map_len); + puts("Global offset table addresses:"); + for (int i = 0; i < 3; i++) { + printf("\t%d: 0x%X\n", i, header.global_offset_table_address[i]); + } + for (int i = 0; i < 3; i++) { + printf("Block map info %d\n\tAddress: 0x%X\n\tLength: 0x%X\n", + i, header.block_map_info[i].address, header.block_map_info[i].len); + } + printf("Secton map file address: 0x%X\n", header.section_map_file_address); + printf("Secton map address: 0x%X\n", header.section_map_address); + printf("Secton map length: 0x%X\n", header.section_map_len); + printf("Num sections: %d\n", header.n_sections); + printf("Max heap size: 0x%X\n", header.max_heap_size); + printf("Max program size: 0x%X\n", header.max_program_size); + printf("Max stack size: 0x%X\n", header.max_stack_size); + printf("Stack fence size: 0x%X\n", header.stack_fence_size); + + puts("\nModules"); + for (int i = 0; i < header.n_modules; i++) { + printf("\t%s:\n\t\tCode Address: 0x%X, Length: 0x%X\n", + header.module_map_entries[i].name.str, + header.module_map_entries[i].code_address, + header.module_map_entries[i].code_length); + printf("\t\tFoo Address: 0x%X, Length: 0x%X\n", + header.module_map_entries[i].foo_address, + header.module_map_entries[i].foo_length); + printf("\t\tBar Address: 0x%X, Length: 0x%X\n", + header.module_map_entries[i].bar_address, + header.module_map_entries[i].bar_length); + } + + puts("\nExtrnal Vars"); + for (int i = 0; i < header.n_external_vars; i++) { + printf("\t%s: 0x%X\n", + header.external_vars[i].name.str, header.external_vars[i].address); + } + + vos_header_cleanup(&header); + return 0; +} diff -r 9d6fed6501ba -r f822d9216968 vos_program_module.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vos_program_module.c Tue Dec 30 19:11:34 2014 -0800 @@ -0,0 +1,208 @@ +#include +#include +#include +#include +#include "vos_program_module.h" + +static uint16_t big16(uint8_t ** src) +{ + uint16_t ret = *((*src)++) << 8; + ret |= *((*src)++); + return ret; +} + +static uint32_t big32(uint8_t ** src) +{ + uint32_t ret = *((*src)++) << 24; + ret |= *((*src)++) << 16; + ret |= *((*src)++) << 8; + ret |= *((*src)++); + return ret; +} + +static void string_(uint8_t ** src, uint16_t *len, char * str, uint32_t storage) +{ + *len = big16(src); + memcpy(str, *src, storage); + *src += storage; + if (*len >= storage) + { + *len = storage; + } else { + str[*len] = 0; + } + if (storage & 1) + { + (*src)++; + } +} + +#define string(src, field) string_(src, &(field).len, (field).str, sizeof((field).str)) + + +int vos_read_header(FILE * f, vos_program_module *out) +{ + uint8_t buffer[4096]; + if (fread(buffer, 1, sizeof(buffer), f) != sizeof(buffer)) + { + return 0; + } + uint8_t *cur = buffer; + out->version = big16(&cur); + string(&cur, out->binder_version); + string(&cur, out->binder_options); + string(&cur, out->system_name); + string(&cur, out->user_name); + out->date_bound = big32(&cur); + out->main_entry_link.code_address = big32(&cur); + out->main_entry_link.static_address = big32(&cur); + out->user_boundary = big32(&cur); + out->n_modules = big16(&cur); + out->n_external_vars = big16(&cur); + out->n_link_names = big16(&cur); + out->n_unsnapped_links = big16(&cur); + out->n_vm_pages = big16(&cur); + out->n_header_pages = big16(&cur); + for (int i = 0; i < 3; i++) + { + for (int j = 0; j < 4; j++) + { + out->info[i][j].address = big32(&cur); + out->info[i][j].len = big32(&cur); + } + } + out->module_map_address = big32(&cur); + out->module_map_len = big32(&cur); + out->external_vars_map_address = big32(&cur); + out->external_vars_map_len = big32(&cur); + out->link_names_map_address = big32(&cur); + out->link_names_map_len = big32(&cur); + out->link_map_address = big32(&cur); + out->link_map_len = big32(&cur); + out->header_address = big32(&cur); + out->header_len = big32(&cur); + memcpy(out->access_info, cur, sizeof(out->access_info)); + cur += sizeof(out->access_info); + out->flags = big32(&cur); + out->n_tasks = big16(&cur); + for (int i = 0; i < 3; i++) + { + out->task_static_len[i] = big32(&cur); + } + out->stack_len = big32(&cur); + out->n_entries = big16(&cur); + out->entry_map_address = big32(&cur); + out->entry_map_len = big32(&cur); + out->pop_version = big16(&cur); + out->processor = big16(&cur); + string(&cur, out->release_name); + out->relocation_info.map_address = big32(&cur); + out->relocation_info.map_len = big32(&cur); + out->relocation_info.n_relocations = big32(&cur); + out->high_water_mark = big32(&cur); + string(&cur, out->copyright_notice); + for (int i = 0; i < 14; i++) + { + out->module_origins[i] = big32(&cur); + } + out->processor_family = big16(&cur); + string(&cur, out->program_name); + out->string_pool_address = big32(&cur); + out->string_pool_len = big32(&cur); + out->obj_dir_map_address = big32(&cur); + out->obj_dir_map_len = big32(&cur); + for (int i = 0; i < 3; i++) + { + out->global_offset_table_address[i] = big32(&cur); + } + for (int i = 0; i < 3; i++) + { + out->block_map_info[i].address = big32(&cur); + out->block_map_info[i].len = big32(&cur); + } + out->section_map_file_address = big32(&cur); + out->section_map_address = big32(&cur); + out->section_map_len = big32(&cur); + out->n_sections = big16(&cur); + out->max_heap_size = big32(&cur); + out->max_program_size = big32(&cur); + out->max_stack_size = big32(&cur); + out->stack_fence_size = big32(&cur); + + out->module_map_entries = NULL; + out->external_vars = NULL; + return 1; +} + +#define MODULE_MAP_ENTRY_SIZE 74 + +int vos_read_alloc_module_map(FILE * f, vos_program_module *header) +{ + if (header->module_map_len != header->n_modules * MODULE_MAP_ENTRY_SIZE) + { + return 0; + } + uint8_t * buf = malloc(header->module_map_len); + fseek(f, header->module_map_address + 0x1000 - header->user_boundary, SEEK_SET); + if (fread(buf, 1, header->module_map_len, f) != header->module_map_len) + { + free(buf); + return 0; + } + uint8_t * cur = buf; + header->module_map_entries = malloc(sizeof(vos_module_map_entry) * header->n_modules); + for (int i = 0; i < header->n_modules; i++) + { + string(&cur, header->module_map_entries[i].name); + for (int j = 0; j < 5; j++) + { + header->module_map_entries[i].unknown[j] = big16(&cur); + } + header->module_map_entries[i].code_address = big32(&cur); + header->module_map_entries[i].code_length = big32(&cur); + header->module_map_entries[i].foo_address = big32(&cur); + header->module_map_entries[i].foo_length = big32(&cur); + header->module_map_entries[i].bar_address = big32(&cur); + header->module_map_entries[i].bar_length = big32(&cur); + for (int j = 0; j < 3; j++) + { + header->module_map_entries[i].unknown2[j] = big16(&cur); + } + } + return 1; +} + +#define EXTERNAL_VAR_ENTRY_SIZE 44 + +int vos_read_alloc_external_vars(FILE * f, vos_program_module *header) +{ + if (header->external_vars_map_len != header->n_external_vars * EXTERNAL_VAR_ENTRY_SIZE) + { + return 0; + } + uint8_t * buf = malloc(header->external_vars_map_len); + fseek(f, header->external_vars_map_address + 0x1000 - header->user_boundary, SEEK_SET); + if (fread(buf, 1, header->external_vars_map_len, f) != header->external_vars_map_len) + { + free(buf); + return 0; + } + uint8_t * cur = buf; + header->external_vars = malloc(sizeof(vos_external_var_entry) * header->n_external_vars); + for (int i = 0; i < header->n_external_vars; i++) + { + string(&cur, header->external_vars[i].name); + header->external_vars[i].address = big32(&cur); + for (int j = 0; j < 3; j++) + { + header->external_vars[i].unknown[j] = big16(&cur); + } + } + return 1; +} + +void vos_header_cleanup(vos_program_module *header) +{ + free(header->module_map_entries); + free(header->external_vars); +} diff -r 9d6fed6501ba -r f822d9216968 vos_program_module.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vos_program_module.h Tue Dec 30 19:11:34 2014 -0800 @@ -0,0 +1,134 @@ +#ifndef VOS_PROGRAM_MODULE_H_ +#define VOS_PROGRAM_MODULE_H_ + +#include + +typedef struct +{ + struct { + uint16_t len; + char str[32]; + } name; + uint16_t unknown[5]; + uint32_t code_address; + uint32_t code_length; + uint32_t foo_address; + uint32_t foo_length; + uint32_t bar_address; + uint32_t bar_length; + uint16_t unknown2[3]; +} vos_module_map_entry; + +typedef struct +{ + struct { + uint16_t len; + char str[32]; + } name; + uint32_t address; + uint16_t unknown[3]; +} vos_external_var_entry; + +typedef struct +{ + uint16_t version; + struct { + uint16_t len; + char str[32]; + } binder_version; + struct { + uint16_t len; + char str[32]; + } binder_options; + struct { + uint16_t len; + char str[32]; + } system_name; + struct { + uint16_t len; + char str[65]; + } user_name; + uint32_t date_bound; + struct { + uint32_t code_address; + uint32_t static_address; + } main_entry_link; + uint32_t user_boundary; + uint16_t n_modules; + uint16_t n_external_vars; + uint16_t n_link_names; + uint16_t n_unsnapped_links; + uint16_t n_vm_pages; + uint16_t n_header_pages; + struct { + uint32_t address; + uint32_t len; + } info[3][4]; + uint32_t module_map_address; + uint32_t module_map_len; + uint32_t external_vars_map_address; + uint32_t external_vars_map_len; + uint32_t link_names_map_address; + uint32_t link_names_map_len; + uint32_t link_map_address; + uint32_t link_map_len; + uint32_t header_address; + uint32_t header_len; + uint8_t access_info[2048]; + uint32_t flags; + uint16_t n_tasks; + uint32_t task_static_len[3]; + uint32_t stack_len; + uint16_t n_entries; + uint32_t entry_map_address; + uint32_t entry_map_len; + uint16_t pop_version; + uint16_t processor; + struct { + uint16_t len; + char str[32]; + } release_name; + struct { + uint32_t map_address; + uint32_t map_len; + uint32_t n_relocations; + } relocation_info; + uint32_t high_water_mark; + struct { + uint16_t len; + char str[256]; + } copyright_notice; + uint32_t module_origins[14]; + uint16_t processor_family; + struct { + uint16_t len; + char str[32]; + } program_name; + uint32_t string_pool_address; + uint32_t string_pool_len; + uint32_t obj_dir_map_address; + uint32_t obj_dir_map_len; + uint32_t global_offset_table_address[3]; + struct { + uint32_t address; + uint32_t len; + } block_map_info[3]; + uint32_t section_map_file_address; + uint32_t section_map_address; + uint32_t section_map_len; + uint16_t n_sections; + uint32_t max_heap_size; + uint32_t max_program_size; + uint32_t max_stack_size; + uint32_t stack_fence_size; + + vos_module_map_entry *module_map_entries; + vos_external_var_entry *external_vars; +} vos_program_module; + +int vos_read_header(FILE * f, vos_program_module *out); +int vos_read_alloc_module_map(FILE * f, vos_program_module *header); +int vos_read_alloc_external_vars(FILE * f, vos_program_module *header); +void vos_header_cleanup(vos_program_module *header); + +#endif //VOS_PROGRAM_MODULE_H_ diff -r 9d6fed6501ba -r f822d9216968 ym2612.c --- a/ym2612.c Mon Dec 29 23:08:39 2014 -0800 +++ b/ym2612.c Tue Dec 30 19:11:34 2014 -0800 @@ -521,6 +521,7 @@ context->selected_part = 0; context->write_cycle = context->current_cycle; context->busy_cycles = BUSY_CYCLES_ADDRESS; + context->status |= 0x80; } void ym_address_write_part2(ym2612_context * context, uint8_t address) @@ -530,6 +531,7 @@ context->selected_part = 1; context->write_cycle = context->current_cycle; context->busy_cycles = BUSY_CYCLES_ADDRESS; + context->status |= 0x80; } uint8_t fnum_to_keycode[] = { diff -r 9d6fed6501ba -r f822d9216968 z80_to_x86.c --- a/z80_to_x86.c Mon Dec 29 23:08:39 2014 -0800 +++ b/z80_to_x86.c Tue Dec 30 19:11:34 2014 -0800 @@ -28,6 +28,8 @@ #define dprintf #endif +uint32_t zbreakpoint_patch(z80_context * context, uint16_t address, code_ptr dst); + uint8_t z80_size(z80inst * inst) { uint8_t reg = (inst->reg & 0x1F); @@ -124,7 +126,7 @@ ea->base = opts->regs[Z80_IYL]; ror_ir(code, 8, opts->regs[Z80_IY], SZ_W); } - } else { + } else if(opts->regs[inst->ea_reg] >= 0) { ea->base = opts->regs[inst->ea_reg]; if (ea->base >= AH && ea->base <= BH && inst->reg != Z80_UNUSED && inst->reg != Z80_USE_IMMED) { uint8_t other_reg = opts->regs[inst->reg]; @@ -134,6 +136,10 @@ ror_ir(code, 8, ea->base, SZ_W); } } + } else { + ea->mode = MODE_REG_DISPLACE8; + ea->base = CONTEXT; + ea->disp = offsetof(z80_context, regs) + inst->ea_reg; } break; case Z80_REG_INDIRECT: @@ -292,7 +298,7 @@ exit(0); } -void translate_z80inst(z80inst * inst, z80_context * context, uint16_t address) +void translate_z80inst(z80inst * inst, z80_context * context, uint16_t address, uint8_t interp) { uint32_t num_cycles; host_ea src_op, dst_op; @@ -300,7 +306,12 @@ z80_options *opts = context->options; uint8_t * start = opts->gen.code.cur; code_info *code = &opts->gen.code; - check_cycles_int(&opts->gen, address); + if (!interp) { + check_cycles_int(&opts->gen, address); + if (context->breakpoint_flags[address / sizeof(uint8_t)] & (1 << (address % sizeof(uint8_t)))) { + zbreakpoint_patch(context, address, start); + } + } switch(inst->op) { case Z80_LD: @@ -350,6 +361,16 @@ } else { mov_rdispr(code, src_op.base, src_op.disp, dst_op.base, size); } + if (inst->ea_reg == Z80_I && inst->addr_mode == Z80_REG) { + //ld a, i sets some flags + //TODO: Implement half-carry flag + cmp_ir(code, 0, dst_op.base, SZ_B); + setcc_rdisp(code, CC_Z, opts->gen.context_reg, zf_off(ZF_Z)); + setcc_rdisp(code, CC_S, opts->gen.context_reg, zf_off(ZF_S)); + mov_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_N), SZ_B);; + mov_rdispr(code, opts->gen.context_reg, offsetof(z80_context, iff2), SCRATCH1, SZ_B); + mov_rrdisp(code, opts->gen.scratch1, opts->gen.context_reg, zf_off(ZF_PV), SZ_B); + } z80_save_reg(inst, opts); z80_save_ea(code, inst, opts); if (inst->addr_mode & Z80_DIR) { @@ -915,10 +936,13 @@ setcc_rdisp(code, CC_C, opts->gen.context_reg, zf_off(ZF_C)); mov_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_N), SZ_B); //TODO: Implement half-carry flag + if (inst->immed) { + //rlca does not set these flags cmp_ir(code, 0, dst_op.base, SZ_B); setcc_rdisp(code, CC_P, opts->gen.context_reg, zf_off(ZF_PV)); setcc_rdisp(code, CC_Z, opts->gen.context_reg, zf_off(ZF_Z)); setcc_rdisp(code, CC_S, opts->gen.context_reg, zf_off(ZF_S)); + } if (inst->addr_mode != Z80_UNUSED) { z80_save_result(opts, inst); if (src_op.mode != MODE_UNUSED) { @@ -947,10 +971,13 @@ setcc_rdisp(code, CC_C, opts->gen.context_reg, zf_off(ZF_C)); mov_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_N), SZ_B); //TODO: Implement half-carry flag + if (inst->immed) { + //rla does not set these flags cmp_ir(code, 0, dst_op.base, SZ_B); setcc_rdisp(code, CC_P, opts->gen.context_reg, zf_off(ZF_PV)); setcc_rdisp(code, CC_Z, opts->gen.context_reg, zf_off(ZF_Z)); setcc_rdisp(code, CC_S, opts->gen.context_reg, zf_off(ZF_S)); + } if (inst->addr_mode != Z80_UNUSED) { z80_save_result(opts, inst); if (src_op.mode != MODE_UNUSED) { @@ -978,10 +1005,13 @@ setcc_rdisp(code, CC_C, opts->gen.context_reg, zf_off(ZF_C)); mov_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_N), SZ_B); //TODO: Implement half-carry flag + if (inst->immed) { + //rrca does not set these flags cmp_ir(code, 0, dst_op.base, SZ_B); setcc_rdisp(code, CC_P, opts->gen.context_reg, zf_off(ZF_PV)); setcc_rdisp(code, CC_Z, opts->gen.context_reg, zf_off(ZF_Z)); setcc_rdisp(code, CC_S, opts->gen.context_reg, zf_off(ZF_S)); + } if (inst->addr_mode != Z80_UNUSED) { z80_save_result(opts, inst); if (src_op.mode != MODE_UNUSED) { @@ -1010,10 +1040,13 @@ setcc_rdisp(code, CC_C, opts->gen.context_reg, zf_off(ZF_C)); mov_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_N), SZ_B); //TODO: Implement half-carry flag + if (inst->immed) { + //rra does not set these flags cmp_ir(code, 0, dst_op.base, SZ_B); setcc_rdisp(code, CC_P, opts->gen.context_reg, zf_off(ZF_PV)); setcc_rdisp(code, CC_Z, opts->gen.context_reg, zf_off(ZF_Z)); setcc_rdisp(code, CC_S, opts->gen.context_reg, zf_off(ZF_S)); + } if (inst->addr_mode != Z80_UNUSED) { z80_save_result(opts, inst); if (src_op.mode != MODE_UNUSED) { @@ -1631,18 +1664,73 @@ } } +uint8_t * z80_interp_handler(uint8_t opcode, z80_context * context) +{ + if (!context->interp_code[opcode]) { + if (opcode == 0xCB || (opcode >= 0xDD && opcode & 0xF == 0xD)) { + fprintf(stderr, "Encountered prefix byte %X at address %X. Z80 interpeter doesn't support those yet.", opcode, context->pc); + exit(1); + } + uint8_t codebuf[8]; + memset(codebuf, 0, sizeof(codebuf)); + codebuf[0] = opcode; + z80inst inst; + uint8_t * after = z80_decode(codebuf, &inst); + if (after - codebuf > 1) { + fprintf(stderr, "Encountered multi-byte Z80 instruction at %X. Z80 interpeter doesn't support those yet.", context->pc); + exit(1); + } + + z80_options * opts = context->options; + code_info *code = &opts->gen.code; + check_alloc_code(code, ZMAX_NATIVE_SIZE); + context->interp_code[opcode] = code->cur; + translate_z80inst(&inst, context, 0, 1); + mov_rdispr(code, opts->gen.context_reg, offsetof(z80_context, pc), opts->gen.scratch1, SZ_W); + add_ir(code, after - codebuf, opts->gen.scratch1, SZ_W); + call(code, opts->native_addr); + jmp_r(code, opts->gen.scratch1); + } + return context->interp_code[opcode]; +} + +code_info z80_make_interp_stub(z80_context * context, uint16_t address) +{ + z80_options *opts = context->options; + code_info * code = &opts->gen.code; + check_alloc_code(code, 32); + code_info stub = {code->cur, NULL}; + //TODO: make this play well with the breakpoint code + mov_ir(code, address, opts->gen.scratch1, SZ_W); + call(code, opts->read_8); + //normal opcode fetch is already factored into instruction timing + //back out the base 3 cycles from a read here + //not quite perfect, but it will have to do for now + cycles(&opts->gen, -3); + check_cycles_int(&opts->gen, address); + call(code, opts->gen.save_context); + mov_rr(code, opts->gen.scratch1, RDI, SZ_B); + mov_irdisp(code, address, opts->gen.context_reg, offsetof(z80_context, pc), SZ_W); + push_r(code, opts->gen.context_reg); + call(code, (code_ptr)z80_interp_handler); + mov_rr(code, RAX, opts->gen.scratch1, SZ_Q); + pop_r(code, opts->gen.context_reg); + call(code, opts->gen.load_context); + jmp_r(code, opts->gen.scratch1); + stub.last = code->cur; + return stub; +} + + uint8_t * z80_get_native_address(z80_context * context, uint32_t address) { native_map_slot *map; if (address < 0x4000) { address &= 0x1FFF; map = context->static_code_map; - } else if (address >= 0x8000) { - address &= 0x7FFF; - map = context->banked_code_map + context->bank_reg; } else { - //dprintf("z80_get_native_address: %X NULL\n", address); - return NULL; + address -= 0x4000; + map = context->banked_code_map; } if (!map->base || !map->offsets || map->offsets[address] == INVALID_OFFSET || map->offsets[address] == EXTENSION_WORD) { //dprintf("z80_get_native_address: %X NULL\n", address); @@ -1654,6 +1742,7 @@ uint8_t z80_get_native_inst_size(z80_options * opts, uint32_t address) { + //TODO: Fix for addresses >= 0x4000 if (address >= 0x4000) { return 0; } @@ -1671,15 +1760,14 @@ opts->gen.ram_inst_sizes[0][address] = native_size; context->ram_code_flags[(address & 0x1C00) >> 10] |= 1 << ((address & 0x380) >> 7); context->ram_code_flags[((address + size) & 0x1C00) >> 10] |= 1 << (((address + size) & 0x380) >> 7); - } else if (address >= 0x8000) { - address &= 0x7FFF; - map = context->banked_code_map + context->bank_reg; + } else { + //HERE + address -= 0x4000; + map = context->banked_code_map; if (!map->offsets) { - map->offsets = malloc(sizeof(int32_t) * 0x8000); - memset(map->offsets, 0xFF, sizeof(int32_t) * 0x8000); + map->offsets = malloc(sizeof(int32_t) * 0xC000); + memset(map->offsets, 0xFF, sizeof(int32_t) * 0xC000); } - } else { - return; } if (!map->base) { map->base = native_address; @@ -1690,15 +1778,13 @@ if (address < 0x4000) { address &= 0x1FFF; map = context->static_code_map; - } else if (address >= 0x8000) { - address &= 0x7FFF; - map = context->banked_code_map + context->bank_reg; } else { - return; + address -= 0x4000; + map = context->banked_code_map; } if (!map->offsets) { - map->offsets = malloc(sizeof(int32_t) * 0x8000); - memset(map->offsets, 0xFF, sizeof(int32_t) * 0x8000); + map->offsets = malloc(sizeof(int32_t) * 0xC000); + memset(map->offsets, 0xFF, sizeof(int32_t) * 0xC000); } map->offsets[address] = EXTENSION_WORD; } @@ -1708,6 +1794,7 @@ uint32_t z80_get_instruction_start(native_map_slot * static_code_map, uint32_t address) { + //TODO: Fixme for address >= 0x4000 if (!static_code_map->base || address >= 0x4000) { return INVALID_INSTRUCTION_START; } @@ -1782,13 +1869,13 @@ check_alloc_code(code, ZMAX_NATIVE_SIZE); code_ptr start = code->cur; deferred_addr * orig_deferred = opts->gen.deferred; - translate_z80inst(&instbuf, context, address); + translate_z80inst(&instbuf, context, address, 0); /* if ((native_end - dst) <= orig_size) { uint8_t * native_next = z80_get_native_address(context, address + after-inst); if (native_next && ((native_next == orig_start + orig_size) || (orig_size - (native_end - dst)) > 5)) { remove_deferred_until(&opts->gen.deferred, orig_deferred); - native_end = translate_z80inst(&instbuf, orig_start, context, address); + native_end = translate_z80inst(&instbuf, orig_start, context, address, 0); if (native_next == orig_start + orig_size && (native_next-native_end) < 2) { while (native_end < orig_start + orig_size) { *(native_end++) = 0x90; //NOP @@ -1814,11 +1901,11 @@ code_info tmp_code = *code; code->cur = orig_start; code->last = orig_start + ZMAX_NATIVE_SIZE; - translate_z80inst(&instbuf, context, address); + translate_z80inst(&instbuf, context, address, 0); code_info tmp2 = *code; *code = tmp_code; if (!z80_is_terminal(&instbuf)) { - + jmp(&tmp2, z80_get_native_address_trans(context, address + after-inst)); } z80_handle_deferred(context); @@ -1837,19 +1924,16 @@ uint8_t * encoded = NULL, *next; if (address < 0x4000) { encoded = context->mem_pointers[0] + (address & 0x1FFF); - } else if(address >= 0x8000 && context->mem_pointers[1]) { - printf("attempt to translate Z80 code from banked area at address %X\n", address); - exit(1); - //encoded = context->mem_pointers[1] + (address & 0x7FFF); } - while (encoded != NULL) + + while (encoded != NULL || address >= 0x4000) { z80inst inst; dprintf("translating Z80 code at address %X\n", address); do { - if (address > 0x4000 && address < 0x8000) { - xor_rr(&opts->gen.code, RDI, RDI, SZ_D); - call(&opts->gen.code, (uint8_t *)exit); + if (address >= 0x4000) { + code_info stub = z80_make_interp_stub(context, address); + z80_map_native_address(context, address, stub.cur, 1, stub.last - stub.cur); break; } uint8_t * existing = z80_get_native_address(context, address); @@ -1869,7 +1953,7 @@ } #endif code_ptr start = opts->gen.code.cur; - translate_z80inst(&inst, context, address); + translate_z80inst(&inst, context, address, 0); z80_map_native_address(context, address, start, next-encoded, opts->gen.code.cur - start); address += next-encoded; if (address > 0xFFFF) { @@ -1885,14 +1969,12 @@ dprintf("defferred address: %X\n", address); if (address < 0x4000) { encoded = context->mem_pointers[0] + (address & 0x1FFF); - } else if (address > 0x8000 && context->mem_pointers[1]) { - encoded = context->mem_pointers[1] + (address & 0x7FFF); } else { - printf("attempt to translate non-memory address: %X\n", address); - exit(1); + encoded = NULL; } } else { encoded = NULL; + address = 0; } } } @@ -1965,7 +2047,7 @@ } else { reg = i; size = SZ_B; - } +} if (options->regs[reg] >= 0) { mov_rrdisp(code, options->regs[reg], options->gen.context_reg, offsetof(z80_context, regs) + i, size); } @@ -2045,7 +2127,7 @@ *no_sync = code->cur - (no_sync + 1); //return to caller of z80_run retn(code); - + options->gen.handle_code_write = (code_ptr)z80_handle_code_write; options->read_8 = gen_mem_fun(&options->gen, chunks, num_chunks, READ_8, &options->read_8_noinc); @@ -2117,7 +2199,7 @@ check_cycles(&options->gen); cycles(&options->gen, 4); retn(code); - + options->read_16 = code->cur; cycles(&options->gen, 3); check_cycles(&options->gen); @@ -2134,7 +2216,7 @@ shl_ir(code, 8, options->gen.scratch1, SZ_W); mov_rr(code, options->gen.scratch2, options->gen.scratch1, SZ_B); retn(code); - + options->write_16_highfirst = code->cur; cycles(&options->gen, 3); check_cycles(&options->gen); @@ -2150,7 +2232,7 @@ //TODO: Check if we can get away with TCO here call(code, options->write_8_noinc); retn(code); - + options->write_16_lowfirst = code->cur; cycles(&options->gen, 3); check_cycles(&options->gen); @@ -2215,9 +2297,12 @@ context->static_code_map->base = NULL; context->static_code_map->offsets = malloc(sizeof(int32_t) * 0x2000); memset(context->static_code_map->offsets, 0xFF, sizeof(int32_t) * 0x2000); - context->banked_code_map = malloc(sizeof(native_map_slot) * (1 << 9)); - memset(context->banked_code_map, 0, sizeof(native_map_slot) * (1 << 9)); + context->banked_code_map = malloc(sizeof(native_map_slot)); + memset(context->banked_code_map, 0, sizeof(native_map_slot)); context->options = options; + context->int_cycle = 0xFFFFFFFF; + context->int_pulse_start = 0xFFFFFFFF; + context->int_pulse_end = 0xFFFFFFFF; context->run = options->run; } @@ -2229,61 +2314,81 @@ context->extra_pc = NULL; } +uint32_t zbreakpoint_patch(z80_context * context, uint16_t address, code_ptr dst) +{ + code_info code = {dst, dst+16}; + mov_ir(&code, address, SCRATCH1, SZ_W); + call(&code, context->bp_stub); + return code.cur-dst; +} + +void zcreate_stub(z80_context * context) +{ + z80_options * opts = context->options; + code_info *code = &opts->gen.code; + check_code_prologue(code); + context->bp_stub = code->cur; + + //Calculate length of prologue + check_cycles_int(&opts->gen, 0); + int check_int_size = code->cur-context->bp_stub; + code->cur = context->bp_stub; + + //Calculate length of patch + int patch_size = zbreakpoint_patch(context, 0, code->cur); + + //Save context and call breakpoint handler + call(code, opts->gen.save_context); + push_r(code, opts->gen.scratch1); + mov_rr(code, opts->gen.context_reg, RDI, SZ_Q); + mov_rr(code, opts->gen.scratch1, RSI, SZ_W); + call(code, context->bp_handler); + mov_rr(code, RAX, opts->gen.context_reg, SZ_Q); + //Restore context + call(code, opts->gen.load_context); + pop_r(code, opts->gen.scratch1); + //do prologue stuff + cmp_rr(code, opts->gen.cycles, opts->gen.limit, SZ_D); + uint8_t * jmp_off = code->cur+1; + jcc(code, CC_NC, code->cur + 7); + pop_r(code, opts->gen.scratch1); + add_ir(code, check_int_size - patch_size, opts->gen.scratch1, SZ_Q); + push_r(code, opts->gen.scratch1); + jmp(code, opts->gen.handle_cycle_limit_int); + *jmp_off = code->cur - (jmp_off+1); + //jump back to body of translated instruction + pop_r(code, opts->gen.scratch1); + add_ir(code, check_int_size - patch_size, opts->gen.scratch1, SZ_Q); + jmp_r(code, opts->gen.scratch1); +} + void zinsert_breakpoint(z80_context * context, uint16_t address, uint8_t * bp_handler) { - static uint8_t * bp_stub = NULL; - z80_options * opts = context->options; - code_ptr native = z80_get_native_address_trans(context, address); - code_info tmp_code = {native, native+16}; - mov_ir(&tmp_code, address, opts->gen.scratch1, SZ_W); - if (!bp_stub) { - code_info *code = &opts->gen.code; - check_code_prologue(code); - bp_stub = code->cur; - call(&tmp_code, bp_stub); - - //Calculate length of prologue - check_cycles_int(&opts->gen, address); - int check_int_size = code->cur-bp_stub; - code->cur = bp_stub; - - //Save context and call breakpoint handler - call(code, opts->gen.save_context); - push_r(code, opts->gen.scratch1); - mov_rr(code, opts->gen.context_reg, RDI, SZ_Q); - mov_rr(code, opts->gen.scratch1, RSI, SZ_W); - call(code, bp_handler); - mov_rr(code, RAX, opts->gen.context_reg, SZ_Q); - //Restore context - call(code, opts->gen.load_context); - pop_r(code, opts->gen.scratch1); - //do prologue stuff - cmp_rr(code, opts->gen.cycles, opts->gen.limit, SZ_D); - uint8_t * jmp_off = code->cur+1; - jcc(code, CC_NC, code->cur + 7); - pop_r(code, opts->gen.scratch1); - add_ir(code, check_int_size - (tmp_code.cur-native), opts->gen.scratch1, SZ_Q); - push_r(code, opts->gen.scratch1); - jmp(code, opts->gen.handle_cycle_limit_int); - *jmp_off = code->cur - (jmp_off+1); - //jump back to body of translated instruction - pop_r(code, opts->gen.scratch1); - add_ir(code, check_int_size - (tmp_code.cur-native), opts->gen.scratch1, SZ_Q); - jmp_r(code, opts->gen.scratch1); - } else { - call(&tmp_code, bp_stub); + context->bp_handler = bp_handler; + uint8_t bit = 1 << (address % sizeof(uint8_t)); + if (!(bit & context->breakpoint_flags[address / sizeof(uint8_t)])) { + context->breakpoint_flags[address / sizeof(uint8_t)] |= bit; + if (!context->bp_stub) { + zcreate_stub(context); + } + uint8_t * native = z80_get_native_address(context, address); + if (native) { + zbreakpoint_patch(context, address, native); + } } } void zremove_breakpoint(z80_context * context, uint16_t address) { + context->breakpoint_flags[address / sizeof(uint8_t)] &= ~(1 << (address % sizeof(uint8_t))); uint8_t * native = z80_get_native_address(context, address); - z80_options * opts = context->options; - code_info tmp_code = opts->gen.code; - opts->gen.code.cur = native; - opts->gen.code.last = native + 16; - check_cycles_int(&opts->gen, address); - opts->gen.code = tmp_code; + if (native) { + z80_options * opts = context->options; + code_info tmp_code = opts->gen.code; + opts->gen.code.cur = native; + opts->gen.code.last = native + 16; + check_cycles_int(&opts->gen, address); + opts->gen.code = tmp_code; + } } - diff -r 9d6fed6501ba -r f822d9216968 z80_to_x86.h --- a/z80_to_x86.h Mon Dec 29 23:08:39 2014 -0800 +++ b/z80_to_x86.h Tue Dec 30 19:11:34 2014 -0800 @@ -1,6 +1,6 @@ /* Copyright 2013 Michael Pavone - This file is part of BlastEm. + This file is part of BlastEm. BlastEm is free software distributed under the terms of the GNU General Public License version 3 or greater. See COPYING for full license text. */ #ifndef Z80_TO_X86_H_ @@ -74,6 +74,13 @@ uint32_t int_enable_cycle; z80_run_fun run; uint16_t pc; + uint32_t int_pulse_start; + uint32_t int_pulse_end; + uint8_t breakpoint_flags[(16 * 1024)/sizeof(uint8_t)]; + uint8_t * bp_handler; + uint8_t * bp_stub; + uint8_t * interp_code[256]; + } z80_context; void translate_z80_stream(z80_context * context, uint32_t address); diff -r 9d6fed6501ba -r f822d9216968 z80inst.c --- a/z80inst.c Mon Dec 29 23:08:39 2014 -0800 +++ b/z80inst.c Tue Dec 30 19:11:34 2014 -0800 @@ -1,6 +1,6 @@ /* Copyright 2013 Michael Pavone - This file is part of BlastEm. + This file is part of BlastEm. BlastEm is free software distributed under the terms of the GNU General Public License version 3 or greater. See COPYING for full license text. */ #include "z80inst.h" @@ -433,7 +433,7 @@ {op, Z80_L, Z80_UNUSED, Z80_UNUSED, 1},\ {op, Z80_UNUSED, Z80_REG_INDIRECT, Z80_HL, 1},\ {op, Z80_A, Z80_UNUSED, Z80_UNUSED, 1} - + #define BIT_BLOCK(op, bit) \ {op, Z80_USE_IMMED, Z80_REG, Z80_B, bit},\ {op, Z80_USE_IMMED, Z80_REG, Z80_C, bit},\ @@ -771,14 +771,14 @@ }; #define SHIFT_BLOCK_IX(op) \ - {op, Z80_B, Z80_IX_DISPLACE | Z80_DIR, 0, 0},\ - {op, Z80_C, Z80_IX_DISPLACE | Z80_DIR, 0, 0},\ - {op, Z80_D, Z80_IX_DISPLACE | Z80_DIR, 0, 0},\ - {op, Z80_E, Z80_IX_DISPLACE | Z80_DIR, 0, 0},\ - {op, Z80_H, Z80_IX_DISPLACE | Z80_DIR, 0, 0},\ - {op, Z80_L, Z80_IX_DISPLACE | Z80_DIR, 0, 0},\ - {op, Z80_UNUSED, Z80_IX_DISPLACE | Z80_DIR, 0, 0},\ - {op, Z80_A, Z80_IX_DISPLACE | Z80_DIR, 0, 0} + {op, Z80_B, Z80_IX_DISPLACE | Z80_DIR, 0, 1},\ + {op, Z80_C, Z80_IX_DISPLACE | Z80_DIR, 0, 1},\ + {op, Z80_D, Z80_IX_DISPLACE | Z80_DIR, 0, 1},\ + {op, Z80_E, Z80_IX_DISPLACE | Z80_DIR, 0, 1},\ + {op, Z80_H, Z80_IX_DISPLACE | Z80_DIR, 0, 1},\ + {op, Z80_L, Z80_IX_DISPLACE | Z80_DIR, 0, 1},\ + {op, Z80_UNUSED, Z80_IX_DISPLACE | Z80_DIR, 0, 1},\ + {op, Z80_A, Z80_IX_DISPLACE | Z80_DIR, 0, 1} #define BIT_BLOCK_IX(bit) \ {Z80_BIT, Z80_USE_IMMED, Z80_IX_DISPLACE, 0, bit},\ @@ -1129,14 +1129,14 @@ }; #define SHIFT_BLOCK_IY(op) \ - {op, Z80_B, Z80_IY_DISPLACE | Z80_DIR, 0, 0},\ - {op, Z80_C, Z80_IY_DISPLACE | Z80_DIR, 0, 0},\ - {op, Z80_D, Z80_IY_DISPLACE | Z80_DIR, 0, 0},\ - {op, Z80_E, Z80_IY_DISPLACE | Z80_DIR, 0, 0},\ - {op, Z80_H, Z80_IY_DISPLACE | Z80_DIR, 0, 0},\ - {op, Z80_L, Z80_IY_DISPLACE | Z80_DIR, 0, 0},\ - {op, Z80_UNUSED, Z80_IY_DISPLACE | Z80_DIR, 0, 0},\ - {op, Z80_A, Z80_IY_DISPLACE | Z80_DIR, 0, 0} + {op, Z80_B, Z80_IY_DISPLACE | Z80_DIR, 0, 1},\ + {op, Z80_C, Z80_IY_DISPLACE | Z80_DIR, 0, 1},\ + {op, Z80_D, Z80_IY_DISPLACE | Z80_DIR, 0, 1},\ + {op, Z80_E, Z80_IY_DISPLACE | Z80_DIR, 0, 1},\ + {op, Z80_H, Z80_IY_DISPLACE | Z80_DIR, 0, 1},\ + {op, Z80_L, Z80_IY_DISPLACE | Z80_DIR, 0, 1},\ + {op, Z80_UNUSED, Z80_IY_DISPLACE | Z80_DIR, 0, 1},\ + {op, Z80_A, Z80_IY_DISPLACE | Z80_DIR, 0, 1} #define BIT_BLOCK_IY(bit) \ {Z80_BIT, Z80_USE_IMMED, Z80_IY_DISPLACE, 0, bit},\ @@ -1250,7 +1250,7 @@ } } else { memcpy(decoded, z80_tbl_a + *istream, sizeof(z80inst)); - + } if ((decoded->addr_mode & 0x1F) == Z80_IMMED && decoded->op != Z80_RST && decoded->op != Z80_IM) { decoded->immed = *(++istream);