summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.hgignore1
-rw-r--r--68kinst.c1113
-rw-r--r--68kinst.h113
-rw-r--r--Makefile19
-rw-r--r--blastem.c92
-rw-r--r--debug.c11
-rw-r--r--default.cfg7
-rw-r--r--dis.c199
-rw-r--r--gen_test_hv.s68631
-rw-r--r--io.c466
-rw-r--r--io.h51
-rw-r--r--render_sdl.c2
-rw-r--r--tern.c12
-rw-r--r--tern.h3
-rw-r--r--vdp.c893
-rw-r--r--vdp.h8
-rw-r--r--vos_prog_info.c100
-rw-r--r--vos_program_module.c208
-rw-r--r--vos_program_module.h134
-rw-r--r--ym2612.c2
-rw-r--r--z80_to_x86.c289
-rw-r--r--z80_to_x86.h9
-rw-r--r--z80inst.c38
23 files changed, 3589 insertions, 812 deletions
diff --git a/.hgignore b/.hgignore
index 6484579..b27d1e8 100644
--- a/.hgignore
+++ b/.hgignore
@@ -17,6 +17,7 @@ html/*
generated_tests/*
ztests/*
*.o
+*.list
blastem
dis
stateview
diff --git a/68kinst.c b/68kinst.c
index 2ca1e02..f53aabe 100644
--- a/68kinst.c
+++ b/68kinst.c
@@ -19,7 +19,7 @@ uint32_t sign_extend8(uint32_t val)
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 @@ uint16_t *m68k_decode_op_ex(uint16_t *cur, uint8_t mode, uint8_t reg, uint8_t si
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 @@ uint16_t *m68k_decode_op_ex(uint16_t *cur, uint8_t mode, uint8_t reg, uint8_t si
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 @@ uint16_t * m68k_decode(uint16_t * istream, m68kinst * decoded, uint32_t address)
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 @@ uint16_t * m68k_decode(uint16_t * istream, m68kinst * decoded, uint32_t address)
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 @@ uint16_t * m68k_decode(uint16_t * istream, m68kinst * decoded, uint32_t address)
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 @@ uint16_t * m68k_decode(uint16_t * istream, m68kinst * decoded, uint32_t address)
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 @@ uint16_t * m68k_decode(uint16_t * istream, m68kinst * decoded, uint32_t address)
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 @@ uint16_t * m68k_decode(uint16_t * istream, m68kinst * decoded, uint32_t address)
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 @@ uint16_t * m68k_decode(uint16_t * istream, m68kinst * decoded, uint32_t address)
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 @@ uint16_t * m68k_decode(uint16_t * istream, m68kinst * decoded, uint32_t address)
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 @@ uint16_t * m68k_decode(uint16_t * istream, m68kinst * decoded, uint32_t address)
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 @@ uint16_t * m68k_decode(uint16_t * istream, m68kinst * decoded, uint32_t address)
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 @@ uint16_t * m68k_decode(uint16_t * istream, m68kinst * decoded, uint32_t address)
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 @@ uint16_t * m68k_decode(uint16_t * istream, m68kinst * decoded, uint32_t address)
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 @@ uint16_t * m68k_decode(uint16_t * istream, m68kinst * decoded, uint32_t address)
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 @@ uint16_t * m68k_decode(uint16_t * istream, m68kinst * decoded, uint32_t address)
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 @@ uint16_t * m68k_decode(uint16_t * istream, m68kinst * decoded, uint32_t address)
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 @@ uint16_t * m68k_decode(uint16_t * istream, m68kinst * decoded, uint32_t address)
decoded->op = M68K_MOVE_FROM_CCR;
size = OPSIZE_WORD;
#else
- return istream+1;
+ break;
#endif
} else {
decoded->op = M68K_CLR;
@@ -555,7 +729,7 @@ uint16_t * m68k_decode(uint16_t * istream, m68kinst * decoded, uint32_t address)
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 @@ uint16_t * m68k_decode(uint16_t * istream, m68kinst * decoded, uint32_t address)
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 @@ uint16_t * m68k_decode(uint16_t * istream, m68kinst * decoded, uint32_t address)
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 @@ uint16_t * m68k_decode(uint16_t * istream, m68kinst * decoded, uint32_t address)
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 @@ uint16_t * m68k_decode(uint16_t * istream, m68kinst * decoded, uint32_t address)
istream = m68k_decode_op(istream, OPSIZE_LONG, &(decoded->src));
if (!istream) {
decoded->op = M68K_INVALID;
- return start+1;
+ break;
}
}
}
@@ -678,7 +852,7 @@ uint16_t * m68k_decode(uint16_t * istream, m68kinst * decoded, uint32_t address)
istream = m68k_decode_op(istream, decoded->extra.size, &(decoded->src));
if (!istream) {
decoded->op = M68K_INVALID;
- return start+1;
+ break;
}
}
}
@@ -702,7 +876,7 @@ uint16_t * m68k_decode(uint16_t * istream, m68kinst * decoded, uint32_t address)
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 @@ uint16_t * m68k_decode(uint16_t * istream, m68kinst * decoded, uint32_t address)
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 @@ uint16_t * m68k_decode(uint16_t * istream, m68kinst * decoded, uint32_t address)
istream = m68k_decode_op(istream, OPSIZE_BYTE, &(decoded->dst));
if (!istream) {
decoded->op = M68K_INVALID;
- return start+1;
+ break;
}
}
} else {
@@ -837,7 +1038,7 @@ uint16_t * m68k_decode(uint16_t * istream, m68kinst * decoded, uint32_t address)
istream = m68k_decode_op(istream, size, &(decoded->dst));
if (!istream) {
decoded->op = M68K_INVALID;
- return start+1;
+ break;
}
}
break;
@@ -865,7 +1066,7 @@ uint16_t * m68k_decode(uint16_t * istream, m68kinst * decoded, uint32_t address)
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 @@ uint16_t * m68k_decode(uint16_t * istream, m68kinst * decoded, uint32_t address)
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 @@ uint16_t * m68k_decode(uint16_t * istream, m68kinst * decoded, uint32_t address)
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 @@ uint16_t * m68k_decode(uint16_t * istream, m68kinst * decoded, uint32_t address)
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 @@ uint16_t * m68k_decode(uint16_t * istream, m68kinst * decoded, uint32_t address)
istream = m68k_decode_op(istream, size, &(decoded->src));
if (!istream) {
decoded->op = M68K_INVALID;
- return start+1;
+ break;
}
}
}
@@ -957,7 +1158,7 @@ uint16_t * m68k_decode(uint16_t * istream, m68kinst * decoded, uint32_t address)
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 @@ uint16_t * m68k_decode(uint16_t * istream, m68kinst * decoded, uint32_t address)
istream = m68k_decode_op(istream, size, &(decoded->dst));
if (!istream) {
decoded->op = M68K_INVALID;
- return start+1;
+ break;
}
}
} else {
@@ -994,7 +1195,7 @@ uint16_t * m68k_decode(uint16_t * istream, m68kinst * decoded, uint32_t address)
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 @@ uint16_t * m68k_decode(uint16_t * istream, m68kinst * decoded, uint32_t address)
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 @@ uint16_t * m68k_decode(uint16_t * istream, m68kinst * decoded, uint32_t address)
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 @@ uint16_t * m68k_decode(uint16_t * istream, m68kinst * decoded, uint32_t address)
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 @@ uint16_t * m68k_decode(uint16_t * istream, m68kinst * decoded, uint32_t address)
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 @@ uint16_t * m68k_decode(uint16_t * istream, m68kinst * decoded, uint32_t address)
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 @@ uint16_t * m68k_decode(uint16_t * istream, m68kinst * decoded, uint32_t address)
istream = m68k_decode_op(istream, decoded->extra.size, &(decoded->src));
if (!istream) {
decoded->op = M68K_INVALID;
- return start+1;
+ break;
}
}
}
@@ -1142,7 +1343,7 @@ uint16_t * m68k_decode(uint16_t * istream, m68kinst * decoded, uint32_t address)
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 @@ uint16_t * m68k_decode(uint16_t * istream, m68kinst * decoded, uint32_t address)
istream = m68k_decode_op(istream, size, &(decoded->dst));
if (!istream) {
decoded->op = M68K_INVALID;
- return start+1;
+ break;
}
}
} else {
@@ -1179,7 +1380,7 @@ uint16_t * m68k_decode(uint16_t * istream, m68kinst * decoded, uint32_t address)
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 @@ uint16_t * m68k_decode(uint16_t * istream, m68kinst * decoded, uint32_t address)
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 @@ uint16_t * m68k_decode(uint16_t * istream, m68kinst * decoded, uint32_t address)
} else {
#ifdef M68020
//TODO: Implement bitfield instructions for M68020+ support
+ switch (*istream >> 8 & 7)
+ {
+ case 0:
+ decoded->op = M68K_BFTST; //<ea>
+ break;
+ case 1:
+ decoded->op = M68K_BFEXTU; //<ea>, Dn
+ break;
+ case 2:
+ decoded->op = M68K_BFCHG; //<ea>
+ break;
+ case 3:
+ decoded->op = M68K_BFEXTS; //<ea>, Dn
+ break;
+ case 4:
+ decoded->op = M68K_BFCLR; //<ea>
+ break;
+ case 5:
+ decoded->op = M68K_BFFFO; //<ea>, Dn
+ break;
+ case 6:
+ decoded->op = M68K_BFSET; //<ea>
+ break;
+ case 7:
+ decoded->op = M68K_BFINS; //Dn, <ea>
+ 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 @@ uint16_t * m68k_decode(uint16_t * istream, m68kinst * decoded, uint32_t address)
//TODO: Implement me
break;
}
+ if (decoded->op == M68K_INVALID) {
+ decoded->src.params.immed = *start;
+ return start + 1;
+ }
return istream+1;
}
@@ -1417,7 +1672,43 @@ char * mnemonics[] = {
"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 @@ char * cond_mnem[] = {
"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 @@ int m68k_disasm_movem_op(m68k_op_info *decoded, m68k_op_info *other, char *dst,
}
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 @@ int m68k_disasm_ex(m68kinst * decoded, char * dst, uint8_t labels)
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 @@ int m68k_disasm_ex(m68kinst * decoded, char * dst, uint8_t labels)
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 @@ int m68k_disasm_ex(m68kinst * decoded, char * dst, uint8_t labels)
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 @@ int m68k_disasm_ex(m68kinst * decoded, char * dst, uint8_t labels)
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 @@ int m68k_disasm_ex(m68kinst * decoded, char * dst, uint8_t labels)
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 --git a/68kinst.h b/68kinst.h
index 768793f..0d5072f 100644
--- a/68kinst.h
+++ b/68kinst.h
@@ -8,6 +8,13 @@
#include <stdint.h>
+#ifdef M68030
+#define M68020
+#endif
+#ifdef M68020
+#define M68010
+#endif
+
typedef enum {
BIT_MOVEP_IMMED = 0,
MOVE_BYTE,
@@ -97,7 +104,43 @@ typedef enum {
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 @@ typedef enum {
//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 @@ typedef enum {
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 @@ typedef enum {
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 --git a/Makefile b/Makefile
index 272605d..c81b86d 100644
--- a/Makefile
+++ b/Makefile
@@ -19,6 +19,16 @@ ifdef NOGL
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 @@ all : dis zdis stateview vgmplay blastem
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 @@ gen_fib : gen_fib.o gen_x86.o mem.o
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 @@ offsets : offsets.c z80_to_x86.h m68k_core.h
$(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 --git a/blastem.c b/blastem.c
index 0ffa4ea..ddbf8ae 100644
--- a/blastem.c
+++ b/blastem.c
@@ -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 @@ void sync_z80(z80_context * z_context, uint32_t mclks)
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 @@ m68k_context * sync_components(m68k_context * context, uint32_t address)
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 @@ m68k_context * sync_components(m68k_context * context, uint32_t address)
}
}
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 @@ m68k_context * vdp_port_write(uint32_t vdp_port, m68k_context * context, uint16_
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 @@ m68k_context * vdp_port_write(uint32_t vdp_port, m68k_context * context, uint16_
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 @@ void init_run_cpu(genesis_context * gen, FILE * address_log, char * statefile, u
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 @@ int main(int argc, char ** argv)
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 @@ int main(int argc, char ** argv)
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 @@ int main(int argc, char ** argv)
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 @@ int main(int argc, char ** argv)
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 --git a/debug.c b/debug.c
index 5f1897d..fa0e26e 100644
--- a/debug.c
+++ b/debug.c
@@ -632,9 +632,14 @@ m68k_context * debugger(m68k_context * context, uint32_t address)
}
} 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 --git a/default.cfg b/default.cfg
index 32df104..1b939be 100644
--- a/default.cfg
+++ b/default.cfg
@@ -54,6 +54,13 @@ bindings {
}
}
+io {
+ devices {
+ 1 gamepad6.1
+ 2 gamepad6.2
+ }
+}
+
video {
width 640
vertex_shader default.v.glsl
diff --git a/dis.c b/dis.c
index 0b26e31..17dbc56 100644
--- a/dis.c
+++ b/dis.c
@@ -6,9 +6,12 @@
#include "68kinst.h"
#include <stdio.h>
#include <stdlib.h>
+#include <string.h>
+#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 @@ void reference(uint32_t address)
{
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 @@ uint8_t is_visited(uint32_t address)
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 @@ typedef struct deferred {
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 @@ void check_reference(m68kinst * inst, m68k_op_info * op)
}
}
-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 @@ int main(int argc, char ** argv)
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 @@ int main(int argc, char ** argv)
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 @@ int main(int argc, char ** argv)
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 @@ int main(int argc, char ** argv)
break;
}
for(;;) {
- if (address > filesize) {
+ if (address > address_end || address < address_off) {
break;
}
visit(address);
@@ -175,7 +275,7 @@ int main(int argc, char ** argv)
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 @@ int main(int argc, char ** argv)
} 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 @@ int main(int argc, char ** argv)
}
}
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 @@ int main(int argc, char ** argv)
}
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 --git a/gen_test_hv.s68 b/gen_test_hv.s68
new file mode 100644
index 0000000..0ee0c22
--- /dev/null
+++ b/gen_test_hv.s68
@@ -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 --git a/io.c b/io.c
index 4935321..3ec8672 100644
--- a/io.c
+++ b/io.c
@@ -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 <unistd.h>
+#include <fcntl.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <string.h>
+
#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 @@ typedef enum {
} 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_dpad(int joystick, int dpad, int direction, uint8_t bind_type, uint8_t
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_gamepad(int keycode, int gamepadnum, int button)
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_button_gamepad(int joystick, int joybutton, int gamepadnum, int padbut
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 bind_dpad_ui(int joystick, int dpad, uint8_t direction, ui_action action, u
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 @@ void handle_binding_up(keybinding * binding)
{
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 process_speeds(tern_node * cur, char * prefix)
}
}
-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 @@ void set_keybindings()
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);
}
}
-void io_data_write(io_port * pad, uint8_t value, uint32_t current_cycle)
+static void service_pipe(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 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));
+ }
+}
+
+static void service_socket(io_port *port)
+{
+ 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;
+ }
+ } else {
+ //no new data, but that's ok
+ break;
+ }
+ }
+
+ 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;
+ }
}
- pad->timeout_cycle = current_cycle + TH_TIMEOUT;
}
}
- pad->output = value;
}
-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];
- } else {
- input = pad->input[GAMEPAD_TH1];
+ case IO_GAMEPAD6:
+ {
+ if (current_cycle >= port->device.pad.timeout_cycle) {
+ port->device.pad.th_counter = 0;
}
- } else {
- if (pad->th_counter == 3) {
- input = pad->input[GAMEPAD_TH0] | 0xF;
- } else if(pad->th_counter == 4) {
- input = pad->input[GAMEPAD_TH0] & 0x30;
+ /*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_TH0] | 0xC;
+ 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;
+ }
}
+ 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 --git a/io.h b/io.h
index b0fd1e9..b73be67 100644
--- a/io.h
+++ b/io.h
@@ -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 <stdint.h>
+#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 @@ typedef struct {
#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 --git a/render_sdl.c b/render_sdl.c
index e5f5c96..9f635a8 100644
--- a/render_sdl.c
+++ b/render_sdl.c
@@ -364,7 +364,7 @@ void render_context_gl(vdp_context * context)
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 --git a/tern.c b/tern.c
index f61e2aa..73ea08d 100644
--- a/tern.c
+++ b/tern.c
@@ -122,4 +122,14 @@ tern_node * tern_insert_ptr(tern_node * head, char * key, void * value)
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 --git a/tern.h b/tern.h
index e95e0c9..cdf6948 100644
--- a/tern.h
+++ b/tern.h
@@ -8,6 +8,8 @@
#include <stdint.h>
+#define MAX_INT_KEY_SIZE (sizeof(uint32_t) + 2)
+
typedef union {
void *ptrval;
intptr_t intval;
@@ -31,5 +33,6 @@ tern_node * tern_insert_int(tern_node * head, char * key, intptr_t value);
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 --git a/vdp.c b/vdp.c
index 5cf5797..6250e0e 100644
--- a/vdp.c
+++ b/vdp.c
@@ -9,8 +9,8 @@
#include <string.h>
#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 debug_base[][3] = {
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 @@ void init_vdp_context(vdp_context * context)
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 @@ void vdp_print_reg_explain(vdp_context * context)
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 @@ void vdp_print_reg_explain(vdp_context * context)
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 @@ void scan_sprite_table(uint32_t line, vdp_context * context)
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 @@ void run_dma_src(vdp_context * context, uint32_t slot)
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 @@ void read_map_scroll(uint16_t column, uint16_t vsram_off, uint32_t line, uint16_
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 @@ void vdp_h40(uint32_t line, uint32_t linecyc, vdp_context * context)
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 @@ void vdp_h40(uint32_t line, uint32_t linecyc, vdp_context * context)
}
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 @@ void vdp_h40(uint32_t line, uint32_t linecyc, vdp_context * context)
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 @@ void vdp_h40(uint32_t line, uint32_t linecyc, vdp_context * context)
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 @@ void vdp_h32(uint32_t line, uint32_t linecyc, vdp_context * context)
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 @@ void vdp_h32(uint32_t line, uint32_t linecyc, vdp_context * context)
}
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 @@ void vdp_h32(uint32_t line, uint32_t linecyc, vdp_context * context)
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 @@ void vdp_h32(uint32_t line, uint32_t linecyc, vdp_context * context)
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 @@ void vdp_h40_line(uint32_t line, vdp_context * 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);
+ }
+ 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 @@ void vdp_h40_line(uint32_t line, vdp_context * context)
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 @@ void vdp_h40_line(uint32_t line, vdp_context * context)
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 @@ void vdp_run_context(vdp_context * context, uint32_t target_cycles)
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 @@ void vdp_run_context(vdp_context * context, uint32_t target_cycles)
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 @@ void vdp_run_dma_done(vdp_context * context, uint32_t target_cycles)
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 @@ int vdp_data_port_write(vdp_context * context, uint16_t value)
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 @@ uint16_t vdp_control_port_read(vdp_context * context)
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 @@ uint16_t vdp_data_port_read(vdp_context * context)
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 @@ uint16_t vdp_data_port_read(vdp_context * context)
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 @@ uint16_t vdp_hv_counter_read(vdp_context * context)
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 @@ void vdp_adjust_cycles(vdp_context * context, uint32_t deduction)
}
}
+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 @@ uint32_t vdp_next_hint(vdp_context * context)
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 linecyc = context->cycles % MCLKS_LINE;
- uint32_t hcycle = context->cycles + context->hint_counter * MCLKS_LINE + MCLKS_LINE - linecyc;
- if (!line) {
- hcycle += MCLKS_LINE;
+ 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;
}
- return hcycle;
+
+ return context->cycles + vdp_cycles_to_line(context, hint_line);
}
uint32_t vdp_next_vint(vdp_context * context)
@@ -1939,29 +1929,44 @@ uint32_t vdp_next_vint(vdp_context * context)
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 --git a/vdp.h b/vdp.h
index 830aa5a..184521a 100644
--- a/vdp.h
+++ b/vdp.h
@@ -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 @@ typedef struct {
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 @@ typedef struct {
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_int_ack(vdp_context * context, uint16_t int_num);
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 --git a/vos_prog_info.c b/vos_prog_info.c
new file mode 100644
index 0000000..1fb4895
--- /dev/null
+++ b/vos_prog_info.c
@@ -0,0 +1,100 @@
+#include <stdio.h>
+#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 --git a/vos_program_module.c b/vos_program_module.c
new file mode 100644
index 0000000..7019623
--- /dev/null
+++ b/vos_program_module.c
@@ -0,0 +1,208 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <string.h>
+#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 --git a/vos_program_module.h b/vos_program_module.h
new file mode 100644
index 0000000..7febb05
--- /dev/null
+++ b/vos_program_module.h
@@ -0,0 +1,134 @@
+#ifndef VOS_PROGRAM_MODULE_H_
+#define VOS_PROGRAM_MODULE_H_
+
+#include <stdint.h>
+
+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 --git a/ym2612.c b/ym2612.c
index 3e43b63..2d3404a 100644
--- a/ym2612.c
+++ b/ym2612.c
@@ -521,6 +521,7 @@ void ym_address_write_part1(ym2612_context * context, uint8_t address)
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 @@ void ym_address_write_part2(ym2612_context * context, uint8_t address)
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 --git a/z80_to_x86.c b/z80_to_x86.c
index bb701a6..6da2321 100644
--- a/z80_to_x86.c
+++ b/z80_to_x86.c
@@ -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 @@ void translate_z80_ea(z80inst * inst, host_ea * ea, z80_options * opts, uint8_t
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 @@ void translate_z80_ea(z80inst * inst, host_ea * ea, z80_options * opts, uint8_t
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 @@ void z80_print_regs_exit(z80_context * context)
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 @@ void translate_z80inst(z80inst * inst, z80_context * context, uint16_t address)
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 @@ void translate_z80inst(z80inst * inst, z80_context * context, uint16_t address)
} 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 @@ void translate_z80inst(z80inst * inst, z80_context * context, uint16_t address)
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 @@ void translate_z80inst(z80inst * inst, z80_context * context, uint16_t address)
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 @@ void translate_z80inst(z80inst * inst, z80_context * context, uint16_t address)
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 @@ void translate_z80inst(z80inst * inst, z80_context * context, uint16_t address)
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 @@ void translate_z80inst(z80inst * inst, z80_context * context, uint16_t address)
}
}
+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_address(z80_context * context, uint32_t address)
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 @@ void z80_map_native_address(z80_context * context, uint32_t address, uint8_t * n
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 @@ void z80_map_native_address(z80_context * context, uint32_t address, uint8_t * n
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 @@ void z80_map_native_address(z80_context * context, uint32_t address, uint8_t * n
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 @@ void * z80_retranslate_inst(uint32_t address, z80_context * context, uint8_t * o
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 @@ void * z80_retranslate_inst(uint32_t address, z80_context * context, uint8_t * o
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 @@ void translate_z80_stream(z80_context * context, uint32_t address)
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 @@ void translate_z80_stream(z80_context * context, uint32_t address)
}
#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 @@ void translate_z80_stream(z80_context * context, uint32_t address)
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 @@ void init_x86_z80_opts(z80_options * options, memmap_chunk const * chunks, uint3
} 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 @@ void init_x86_z80_opts(z80_options * options, memmap_chunk const * chunks, uint3
*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 @@ void init_x86_z80_opts(z80_options * options, memmap_chunk const * chunks, uint3
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 @@ void init_x86_z80_opts(z80_options * options, memmap_chunk const * chunks, uint3
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 @@ void init_x86_z80_opts(z80_options * options, memmap_chunk const * chunks, uint3
//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 @@ void init_z80_context(z80_context * context, z80_options * options)
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 @@ void z80_reset(z80_context * context)
context->extra_pc = NULL;
}
-void zinsert_breakpoint(z80_context * context, uint16_t address, uint8_t * bp_handler)
+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)
{
- 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);
+ code_info *code = &opts->gen.code;
+ check_code_prologue(code);
+ context->bp_stub = code->cur;
- //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);
+ //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)
+{
+ 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 --git a/z80_to_x86.h b/z80_to_x86.h
index 507965d..71d6f10 100644
--- a/z80_to_x86.h
+++ b/z80_to_x86.h
@@ -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 @@ typedef struct {
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 --git a/z80inst.c b/z80inst.c
index 0605ebc..cecce6e 100644
--- a/z80inst.c
+++ b/z80inst.c
@@ -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 @@ z80inst z80_tbl_extd[0xC0-0x40] = {
{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 @@ z80inst z80_tbl_ix[256] = {
};
#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 @@ z80inst z80_tbl_iy[256] = {
};
#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 @@ uint8_t * z80_decode(uint8_t * istream, z80inst * decoded)
}
} 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);