NEC SUB4S and CMP4S instructions (#11)
* NEC SUB4S and CMP4S instructions * Return to original IP properly in case of POP PS * NEC REPC/REPNC instructions * Make NEC BRKEM instruction a fatal for now * Fix wrong segment addresses in some NEC instructions
This commit is contained in:
110
src/cpu/808x.c
110
src/cpu/808x.c
@@ -67,7 +67,7 @@ static uint16_t last_addr = 0x0000;
|
|||||||
|
|
||||||
static uint32_t *ovr_seg = NULL;
|
static uint32_t *ovr_seg = NULL;
|
||||||
static int prefetching = 1, completed = 1;
|
static int prefetching = 1, completed = 1;
|
||||||
static int in_rep = 0, repeating = 0;
|
static int in_rep = 0, repeating = 0, rep_c_flag = 0;
|
||||||
static int oldc, clear_lock = 0;
|
static int oldc, clear_lock = 0;
|
||||||
static int refresh = 0, cycdiff;
|
static int refresh = 0, cycdiff;
|
||||||
|
|
||||||
@@ -1830,14 +1830,13 @@ execx86(int cycs)
|
|||||||
uint8_t zero = 1;
|
uint8_t zero = 1;
|
||||||
uint8_t nibbles_count = CL - odd;
|
uint8_t nibbles_count = CL - odd;
|
||||||
uint32_t i = 0, carry = 0, nibble = 0;
|
uint32_t i = 0, carry = 0, nibble = 0;
|
||||||
uint32_t srcseg = ovr_seg ? *ovr_seg : DS;
|
uint32_t srcseg = ovr_seg ? *ovr_seg : ds;
|
||||||
|
|
||||||
srcseg <<= 4;
|
|
||||||
wait(5, 0);
|
wait(5, 0);
|
||||||
for (i = 0; i < ((nibbles_count / 2) + odd); i++) {
|
for (i = 0; i < ((nibbles_count / 2) + odd); i++) {
|
||||||
wait(19, 0);
|
wait(19, 0);
|
||||||
for (nibble = 0; nibble < 2; nibble++) {
|
for (nibble = 0; nibble < 2; nibble++) {
|
||||||
uint8_t destbyte = read_mem_b((ES << 4) + DI + i) >> (nibble ? 4 : 0);
|
uint8_t destbyte = read_mem_b((es) + DI + i) >> (nibble ? 4 : 0);
|
||||||
uint8_t srcbyte = read_mem_b(srcseg + SI + i) >> (nibble ? 4 : 0);
|
uint8_t srcbyte = read_mem_b(srcseg + SI + i) >> (nibble ? 4 : 0);
|
||||||
destbyte &= 0xF;
|
destbyte &= 0xF;
|
||||||
srcbyte &= 0xF;
|
srcbyte &= 0xF;
|
||||||
@@ -1848,9 +1847,80 @@ execx86(int cycs)
|
|||||||
carry++;
|
carry++;
|
||||||
}
|
}
|
||||||
if (zero != 0) zero = (nibble_result == 0);
|
if (zero != 0) zero = (nibble_result == 0);
|
||||||
write_mem_b((ES << 4) + DI + i, (read_mem_b((ES << 4) + DI + i) & (nibble ? 0x0F : 0xF0)) | (nibble_result << (4 * nibble)));
|
write_mem_b((es) + DI + i, (read_mem_b((es) + DI + i) & (nibble ? 0x0F : 0xF0)) | (nibble_result << (4 * nibble)));
|
||||||
if (i == ((nibbles_count / 2)) && odd && nibble == 0) {
|
if (i == ((nibbles_count / 2)) && odd && nibble == 0) {
|
||||||
zero = ((read_mem_b((ES << 4) + DI + i) & 0xF0) == 0);
|
zero = ((read_mem_b((es) + DI + i) & 0xF0) == 0);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
set_cf(!!carry);
|
||||||
|
set_zf(!!zero);
|
||||||
|
handled = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 0x22: /* SUB4S */
|
||||||
|
{
|
||||||
|
uint8_t odd = !!(CL % 2);
|
||||||
|
uint8_t zero = 1;
|
||||||
|
uint8_t nibbles_count = CL - odd;
|
||||||
|
uint32_t i = 0, carry = 0, nibble = 0;
|
||||||
|
uint32_t srcseg = ovr_seg ? *ovr_seg : ds;
|
||||||
|
|
||||||
|
wait(5, 0);
|
||||||
|
for (i = 0; i < ((nibbles_count / 2) + odd); i++) {
|
||||||
|
wait(19, 0);
|
||||||
|
for (nibble = 0; nibble < 2; nibble++) {
|
||||||
|
uint8_t destbyte = read_mem_b((es) + DI + i) >> (nibble ? 4 : 0);
|
||||||
|
uint8_t srcbyte = read_mem_b(srcseg + SI + i) >> (nibble ? 4 : 0);
|
||||||
|
destbyte &= 0xF;
|
||||||
|
srcbyte &= 0xF;
|
||||||
|
int8_t nibble_result = ((int8_t)(destbyte)) - ((int8_t)(srcbyte)) - ((int8_t)carry);
|
||||||
|
carry = 0;
|
||||||
|
while (nibble_result < 0) {
|
||||||
|
nibble_result += 10;
|
||||||
|
carry++;
|
||||||
|
}
|
||||||
|
if (zero != 0) zero = (nibble_result == 0);
|
||||||
|
write_mem_b((es) + DI + i, (read_mem_b((es) + DI + i) & (nibble ? 0x0F : 0xF0)) | (nibble_result << (4 * nibble)));
|
||||||
|
if (i == ((nibbles_count / 2)) && odd && nibble == 0) {
|
||||||
|
zero = ((read_mem_b((es) + DI + i) & 0xF0) == 0);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
set_cf(!!carry);
|
||||||
|
set_zf(!!zero);
|
||||||
|
handled = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 0x26: /* CMP4S */
|
||||||
|
{
|
||||||
|
uint8_t odd = !!(CL % 2);
|
||||||
|
uint8_t zero = 1;
|
||||||
|
uint8_t nibbles_count = CL - odd;
|
||||||
|
uint32_t i = 0, carry = 0, nibble = 0;
|
||||||
|
uint32_t srcseg = ovr_seg ? *ovr_seg : ds;
|
||||||
|
|
||||||
|
wait(5, 0);
|
||||||
|
for (i = 0; i < ((nibbles_count / 2) + odd); i++) {
|
||||||
|
wait(19, 0);
|
||||||
|
uint8_t destcmp = read_mem_b((es) + DI + i);
|
||||||
|
for (nibble = 0; nibble < 2; nibble++) {
|
||||||
|
uint8_t destbyte = destcmp >> (nibble ? 4 : 0);
|
||||||
|
uint8_t srcbyte = read_mem_b(srcseg + SI + i) >> (nibble ? 4 : 0);
|
||||||
|
destbyte &= 0xF;
|
||||||
|
srcbyte &= 0xF;
|
||||||
|
int8_t nibble_result = ((int8_t)(destbyte)) - ((int8_t)(srcbyte)) - ((int8_t)carry);
|
||||||
|
carry = 0;
|
||||||
|
while (nibble_result < 0) {
|
||||||
|
nibble_result += 10;
|
||||||
|
carry++;
|
||||||
|
}
|
||||||
|
if (zero != 0) zero = (nibble_result == 0);
|
||||||
|
destcmp = ((destcmp & (nibble ? 0x0F : 0xF0)) | (nibble_result << (4 * nibble)));
|
||||||
|
if (i == ((nibbles_count / 2)) && odd && nibble == 0) {
|
||||||
|
zero = ((destcmp & 0xF0) == 0);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1868,12 +1938,12 @@ execx86(int cycs)
|
|||||||
{
|
{
|
||||||
uint8_t bit_length = ((opcode & 0x8) ? (pfq_fetchb() & 0xF) : (getr8(cpu_reg) & 0xF)) + 1;
|
uint8_t bit_length = ((opcode & 0x8) ? (pfq_fetchb() & 0xF) : (getr8(cpu_reg) & 0xF)) + 1;
|
||||||
uint8_t bit_offset = getr8(cpu_rm) & 0xF;
|
uint8_t bit_offset = getr8(cpu_rm) & 0xF;
|
||||||
uint32_t byteaddr = (ES << 4) + DI;
|
uint32_t byteaddr = (es) + DI;
|
||||||
uint32_t i = 0;
|
uint32_t i = 0;
|
||||||
if (bit_offset >= 8) { DI++; byteaddr++; bit_offset -= 8; }
|
if (bit_offset >= 8) { DI++; byteaddr++; bit_offset -= 8; }
|
||||||
for (i = 0; i < bit_length; i++) {
|
for (i = 0; i < bit_length; i++) {
|
||||||
byteaddr = (ES << 4) + DI;
|
byteaddr = (es) + DI;
|
||||||
writememb(ES << 4, DI, (read_mem_b(byteaddr) & ~(1 << (bit_offset))) | ((!!(AX & (1 << i))) << bit_offset));
|
writememb(es, DI, (read_mem_b(byteaddr) & ~(1 << (bit_offset))) | ((!!(AX & (1 << i))) << bit_offset));
|
||||||
bit_offset++;
|
bit_offset++;
|
||||||
if (bit_offset == 8) { DI++; bit_offset = 0; }
|
if (bit_offset == 8) { DI++; bit_offset = 0; }
|
||||||
}
|
}
|
||||||
@@ -1890,14 +1960,14 @@ execx86(int cycs)
|
|||||||
{
|
{
|
||||||
uint8_t bit_length = ((opcode & 0x8) ? (pfq_fetchb() & 0xF) : (getr8(cpu_reg) & 0xF)) + 1;
|
uint8_t bit_length = ((opcode & 0x8) ? (pfq_fetchb() & 0xF) : (getr8(cpu_reg) & 0xF)) + 1;
|
||||||
uint8_t bit_offset = getr8(cpu_rm) & 0xF;
|
uint8_t bit_offset = getr8(cpu_rm) & 0xF;
|
||||||
uint32_t byteaddr = (DS << 4) + SI;
|
uint32_t byteaddr = (ds) + SI;
|
||||||
uint32_t i = 0;
|
uint32_t i = 0;
|
||||||
|
|
||||||
if (bit_offset >= 8) { SI++; byteaddr++; bit_offset -= 8; }
|
if (bit_offset >= 8) { SI++; byteaddr++; bit_offset -= 8; }
|
||||||
|
|
||||||
AX = 0;
|
AX = 0;
|
||||||
for (i = 0; i < bit_length; i++) {
|
for (i = 0; i < bit_length; i++) {
|
||||||
byteaddr = (DS << 4) + SI;
|
byteaddr = (ds) + SI;
|
||||||
AX |= (!!(readmemb(byteaddr) & (1 << bit_offset))) << i;
|
AX |= (!!(readmemb(byteaddr) & (1 << bit_offset))) << i;
|
||||||
bit_offset++;
|
bit_offset++;
|
||||||
if (bit_offset == 8) { SI++; bit_offset = 0; }
|
if (bit_offset == 8) { SI++; bit_offset = 0; }
|
||||||
@@ -1908,8 +1978,14 @@ execx86(int cycs)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case 0xFF: { /* BRKEM */
|
||||||
|
/* Unimplemented for now. */
|
||||||
|
fatal("808x: Unsupported 8080 emulation mode attempted to enter into!");
|
||||||
|
break;
|
||||||
|
}
|
||||||
default: {
|
default: {
|
||||||
opcode = orig_opcode;
|
opcode = orig_opcode;
|
||||||
|
cpu_state.pc--;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2144,7 +2220,14 @@ execx86(int cycs)
|
|||||||
case 0x74: /*JE*/
|
case 0x74: /*JE*/
|
||||||
case 0x65: /*JNE alias*/
|
case 0x65: /*JNE alias*/
|
||||||
case 0x75: /*JNE*/
|
case 0x75: /*JNE*/
|
||||||
jcc(opcode, cpu_state.flags & Z_FLAG);
|
if (is_nec && (opcode & 0xFE) == 0x64) {
|
||||||
|
/* REPC/REPNC */
|
||||||
|
wait(1, 0);
|
||||||
|
in_rep = (opcode == 0x64 ? 1 : 2);
|
||||||
|
rep_c_flag = 1;
|
||||||
|
completed = 0;
|
||||||
|
}
|
||||||
|
else jcc(opcode, cpu_state.flags & Z_FLAG);
|
||||||
break;
|
break;
|
||||||
case 0x66: /*JBE alias*/
|
case 0x66: /*JBE alias*/
|
||||||
case 0x76: /*JBE*/
|
case 0x76: /*JBE*/
|
||||||
@@ -2463,7 +2546,7 @@ execx86(int cycs)
|
|||||||
wait(3, 0);
|
wait(3, 0);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if ((!!(cpu_state.flags & Z_FLAG)) == (in_rep == 1)) {
|
if ((!!(cpu_state.flags & (rep_c_flag ? C_FLAG : Z_FLAG))) == (in_rep == 1)) {
|
||||||
completed = 1;
|
completed = 1;
|
||||||
wait(4, 0);
|
wait(4, 0);
|
||||||
break;
|
break;
|
||||||
@@ -3056,6 +3139,7 @@ execx86(int cycs)
|
|||||||
repeating = 0;
|
repeating = 0;
|
||||||
ovr_seg = NULL;
|
ovr_seg = NULL;
|
||||||
in_rep = 0;
|
in_rep = 0;
|
||||||
|
rep_c_flag = 0;
|
||||||
if (in_lock)
|
if (in_lock)
|
||||||
clear_lock = 1;
|
clear_lock = 1;
|
||||||
clock_end();
|
clock_end();
|
||||||
|
Reference in New Issue
Block a user