Fixed divide operations

This commit is contained in:
Michael Zapf 2013-08-08 13:38:19 +00:00
parent 87428a0f36
commit 24dfc80a3f

View File

@ -530,15 +530,15 @@ MICROPROGRAM(divide_signed_mp)
{ {
OPERAND_ADDR, // Address of divisor S in Q=W1W2/S OPERAND_ADDR, // Address of divisor S in Q=W1W2/S
MEMORY_READ, // Get S MEMORY_READ, // Get S
ALU_DIV, ALU_DIVS,
MEMORY_READ, // Get W1 MEMORY_READ, // Get W1
ALU_DIV, // ALU_DIVS, //
MEMORY_READ, // Get W2 MEMORY_READ, // Get W2
ALU_DIV, // Check for overflow, skip next instruction if not ALU_DIVS, // Check for overflow, skip next instruction if not
ABORT, ABORT,
ALU_DIV, // Calculate quotient ALU_DIVS, // Calculate quotient
MEMORY_WRITE, // Write quotient to &W1 MEMORY_WRITE, // Write quotient to &W1
ALU_DIV, ALU_DIVS,
PREFETCH, PREFETCH,
MEMORY_WRITE, // Write remainder to &W2 MEMORY_WRITE, // Write remainder to &W2
END END
@ -1218,9 +1218,16 @@ void tms9995_device::set_ready(int state)
m_ready_state = (state==ASSERT_LINE); m_ready_state = (state==ASSERT_LINE);
} }
/*
When the divide operations fail, we get to this operation.
*/
void tms9995_device::abort_operation() void tms9995_device::abort_operation()
{ {
command_completed(); int_prefetch_and_decode(); // do not forget to prefetch
// And don't forget that prefetch is a 2-pass operation, so this method
// will be called a second time. Only when the lowbyte has been fetched,
// continue with the next step
if (!m_lowbyte) command_completed();
} }
/* /*
@ -2384,8 +2391,9 @@ void tms9995_device::alu_divide_signed()
{ {
int n=1; int n=1;
bool overflow = true; bool overflow = true;
UINT16 w1, w2, d; UINT16 w1, w2, dwait;
INT32 w; INT16 divisor;
INT32 dividend;
switch (m_instruction->state) switch (m_instruction->state)
{ {
@ -2406,93 +2414,59 @@ void tms9995_device::alu_divide_signed()
w1 = m_value_copy; w1 = m_value_copy;
w2 = m_current_value; w2 = m_current_value;
d = m_source_value; divisor = m_source_value;
dividend = w1 << 16 | w2;
// Now check for overflow // Now check for overflow
// Seems a bit complex, and don't ask me how they did it in the chip. // We need to go for four cases
// The basic idea is that the division of a 32-bit number by a 16-bit // if the divisor is not 0 anyway
// number must result in a 16-bit quotient and a remainder, AND the if (divisor != 0)
// quotient must have positive sign when the signs of the dividend and
// the divisor are equal. When any of these conditions are not met, an
// overflow is indicated.
// Unlike with the unsigned division we cannot tell whether we will
// run into an overflow before we have the complete dividend value.
// It might be easier to just try and divide, but the real machine
// requires much less cycles when there is an overflow, so it seems as
// if this is tested before the algorithm starts.
if ((w1 & 0x8000)==0) // positive dividend
{ {
if ((d & 0x8000)==0) // positive divisor if (dividend >= 0)
{ {
if ((d & 1)==0) // even divisor if (divisor > 0)
{ {
if (w1 < d/2) overflow = false; overflow = (dividend > ((divisor<<15) - 1));
} }
else // odd divisor else
{ {
if ((w1 < (d-1)/2) || (w1 == (d-1)/2 && w2 < 0x8000)) overflow = false; overflow = (dividend > (((-divisor)<<15) + (-divisor) - 1));
} }
} }
else // negative divisor else
{ {
d = -d; if (divisor > 0)
if ((d & 1)==0) // even divisor
{ {
if ((w1 < d/2) || (w1 == d/2 && w2 < d)) overflow = false; overflow = ((-dividend) > ((divisor<<15) + divisor - 1));
} }
else // odd divisor else
{ {
if ((w1 < (d+1)/2) || (w1 == (d+1)/2 && w2 < 0x8000+d)) overflow = false; overflow = ((-dividend) > (((-divisor)<<15) - 1));
} }
} }
} }
else // negative dividend else
{ {
w1 = -w1; overflow = true; // divisor is 0
if ((d & 0x8000)==0) // positive divisor
{
if ((d & 1)==0) // even divisor
{
if ((w1 < d/2+1) || (w1 == d/2+1 && w2 > (-d))) overflow = false;
}
else // odd divisor
{
if ((w1 < (d+1)/2) || (w1 == (d+1)/2 && w2 > 0x8000-d)) overflow = false;
}
}
else // negative divisor
{
d = -d;
if ((d & 1)==0) // even divisor
{
if ((w1 < d/2) || (w1 == d/2 && w2 > 0)) overflow = false;
}
else // odd divisor
{
if ((w1 < (d+1)/2) || (w1 == (d+1)/2 && w2 > 0x8000)) overflow = false;
}
}
} }
set_status_bit(ST_OV, overflow); set_status_bit(ST_OV, overflow);
if (!overflow) MPC++; // Skip the next microinstruction when there is no overflow if (!overflow) MPC++; // Skip the next microinstruction when there is no overflow
break; break;
case 3: case 3:
// We are here because there was no overflow // We are here because there was no overflow
w = (m_value_copy << 16) | m_current_value; dividend = m_value_copy << 16 | m_current_value;
// Do the calculation // Do the calculation
m_current_value = (UINT16)(w / (INT16)m_source_value); m_current_value = (UINT16)(dividend / (INT16)m_source_value);
m_value_copy = (UINT16)(w % (INT16)m_source_value); m_value_copy = (UINT16)(dividend % (INT16)m_source_value);
m_address = WP; m_address = WP;
// As we have not implemented the real division algorithm we must // As we have not implemented the real division algorithm we must
// simulate the number of steps required for calculating the result. // simulate the number of steps required for calculating the result.
// This is just a guess. // This is just a guess.
d = m_value_copy; dwait = m_value_copy;
while (d != 0) while (dwait != 0)
{ {
d = (d >> 1) & 0xffff; dwait = (dwait >> 1) & 0xffff;
n++; n++;
} }
// go write the quotient into R0 // go write the quotient into R0