mirror of
https://github.com/holub/mame
synced 2025-10-08 09:30:17 +03:00
Fixed divide operations
This commit is contained in:
parent
87428a0f36
commit
24dfc80a3f
@ -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
|
||||||
|
Loading…
Reference in New Issue
Block a user