bus/gio64/newport.cpp, cpu/mips/mips3.cpp: Fixed issues affecting IRIX. (#11117)

* cpu/mips/mips3.cpp: Sign-extend result of COP0 LL instruction.
* cpu/mips/mips3.cpp: Ported COP0 Random implementation from new R4000 interpreter.
* bus/gio64/newport.cpp: Use octant encoding used by hardware, and fixed Scr2Scr.
This commit is contained in:
Jiaxun Yang 2023-04-17 16:24:36 +01:00 committed by GitHub
parent b5ead1f823
commit 96af9667b6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 81 additions and 100 deletions

View File

@ -2701,20 +2701,33 @@ uint32_t newport_base_device::get_rgb_color(int16_t x, int16_t y)
uint8_t newport_base_device::get_octant(int32_t x1, int32_t y1, int32_t x2, int32_t y2, int32_t dx, int32_t dy)
{
if (x1 < x2)
{
if (y2 < y1)
return (dx > dy) ? 0 : 1;
else
return (dx > dy) ? 7 : 6;
}
else
{
if (y2 < y1)
return (dx > dy) ? 3 : 2;
else
return (dx > dy) ? 4 : 5;
}
uint8_t octant = 0;
// Octant format: {MSB, 2nd, LSB} = {XMAJOR, XDEC, YDEC}
// Mapping of hardware octant to peseudocode octant in manual
// | Pseudocode | hardware | hardware(dec) |
// | 1 | 3'b101 | 5 |
// | 2 | 3'b001 | 1 |
// | 3 | 3'b011 | 3 |
// | 4 | 3'b111 | 7 |
// | 5 | 3'b110 | 6 |
// | 6 | 3'b010 | 2 |
// | 7 | 3'b000 | 0 |
// | 8 | 3'b100 | 4 |
/* YDEC */
if (y1 > y2)
octant |= (1 << 0); // Bit 0
/* XDEC */
if (x1 > x2)
octant |= (1 << 1); // Bit 1
/* XMAJOR */
if (dx > dy)
octant |= (1 << 2); // Bit 2
return octant;
}
void newport_base_device::do_setup(void)
@ -2725,39 +2738,13 @@ void newport_base_device::do_setup(void)
const int32_t y2 = util::sext(m_rex3.m_y_end >> 7, 20);
const int32_t dx = abs(x1 - x2);
const int32_t dy = abs(y1 - y2);
const uint8_t adrmode = (m_rex3.m_draw_mode0 >> 2) & 7;
if (adrmode >= 0 && adrmode <= 1)
{
/* quadrant for block or span */
uint8_t quadrant = 0;
/* This is purely guessed */
if (x1 > x2)
{
if (y1 > y2)
quadrant = 3;
else
quadrant = 2;
}
else
{
if (y1 > y2)
quadrant = 1;
else
quadrant = 0;
}
m_rex3.m_bres_octant_inc1 &= ~(0x7 << 24);
m_rex3.m_bres_octant_inc1 |= quadrant << 24;
}
else if (adrmode >= 2 && adrmode <= 4)
{
uint8_t octant;
/* octant for line */
/* FIXME: error terms and Bresenham terms */
octant = get_octant(x1, y1, x2, y2, dx, dy);
m_rex3.m_bres_octant_inc1 &= ~(0x7 << 24);
m_rex3.m_bres_octant_inc1 |= octant << 24;
}
/* octant for line and block, span */
const uint8_t octant = get_octant(x1, y1, x2, y2, dx, dy);
m_rex3.m_bres_octant_inc1 &= ~(0x7 << 24);
m_rex3.m_bres_octant_inc1 |= (uint32_t)octant << 24;
/* FIXME: error terms (incr1, incr2) and Bresenham terms (d) */
LOGMASKED(LOG_REX3, "do_setup: octant = %d, x1 = %d, y1 = %d, x2 = %d, y2 = %d, dx = %d, dy = %d\n", octant, x1, y1, x2, y2, dx, dy);
}
void newport_base_device::do_fline(uint32_t color)
@ -2792,14 +2779,14 @@ void newport_base_device::do_fline(uint32_t color)
static const bresenham_octant_info_t s_bresenham_infos[8] =
{
{ 1, 1, 0, 1, 0 },
{ 0, 1, 1, 1, 1 },
{ 0, -1, 1, 1, 1 },
{ -1, -1, 0, 1, 0 },
{ -1, -1, 0, -1, 0 },
{ 0, -1, -1, -1, 1 },
{ 0, 1, -1, -1, 1 },
{ 1, 1, 0, -1, 0 }
{ 0, 1, -1, -1, 1 }, // Pseudo 7
{ 0, 1, 1, 1, 1 }, // Pseudo 2
{ 0, -1, -1, -1, 1 }, // Pseudo 6
{ 0, -1, 1, 1, 1 }, // Pseudo 3
{ 1, 1, 0, -1, 0 }, // Pseudo 8
{ 1, 1, 0, 1, 0 }, // Pseudo 1
{ -1, -1, 0, -1, 0 }, // Pseudo 5
{ -1, -1, 0, 1, 0 } // Pseudo 4
};
const uint8_t octant = (m_rex3.m_bres_octant_inc1 >> 24) & 0x7;
@ -2818,10 +2805,10 @@ void newport_base_device::do_fline(uint32_t color)
switch (octant)
{
case 0:
case 5: // Pseudo 1
// Nothing special needed
break;
case 1:
case 1: // Pseudo 2
{
const int16_t temp_fract = x1_fract;
x1_fract = y1_fract;
@ -2831,7 +2818,7 @@ void newport_base_device::do_fline(uint32_t color)
dy = temp_d;
break;
}
case 2:
case 3: // Pseudo 3
{
const int16_t temp_fract = 0x10 - x1_fract;
x1_fract = y1_fract;
@ -2841,14 +2828,14 @@ void newport_base_device::do_fline(uint32_t color)
dy = temp_d;
break;
}
case 3:
case 7: // Pseudo 4
x1_fract = 0x10 - x1_fract;
break;
case 4:
case 6: // Pseudo 5
x1_fract = 0x10 - x1_fract;
y1_fract = 0x10 - y1_fract;
break;
case 5:
case 2: // Pseudo 6
{
const int16_t temp_fract = 0x10 - x1_fract;
x1_fract = 0x10 - y1_fract;
@ -2858,7 +2845,7 @@ void newport_base_device::do_fline(uint32_t color)
dy = temp_d;
break;
}
case 6:
case 0: // Pseudo 7
{
const int16_t temp_fract = 0x10 - y1_fract;
y1_fract = x1_fract;
@ -2868,7 +2855,7 @@ void newport_base_device::do_fline(uint32_t color)
dy = temp_d;
break;
}
case 7:
case 4: // Pseudo 8
y1_fract = 0x10 - y1_fract;
break;
}
@ -2983,14 +2970,14 @@ void newport_base_device::do_iline(uint32_t color)
static const bresenham_octant_info_t s_bresenham_infos[8] =
{
{ 1, 1, 0, 1, 0 },
{ 0, 1, 1, 1, 1 },
{ 0, -1, 1, 1, 1 },
{ -1, -1, 0, 1, 0 },
{ -1, -1, 0, -1, 0 },
{ 0, -1, -1, -1, 1 },
{ 0, 1, -1, -1, 1 },
{ 1, 1, 0, -1, 0 }
{ 0, 1, -1, -1, 1 }, // Pseudo 7
{ 0, 1, 1, 1, 1 }, // Pseudo 2
{ 0, -1, -1, -1, 1 }, // Pseudo 6
{ 0, -1, 1, 1, 1 }, // Pseudo 3
{ 1, 1, 0, -1, 0 }, // Pseudo 8
{ 1, 1, 0, 1, 0 }, // Pseudo 1
{ -1, -1, 0, -1, 0 }, // Pseudo 5
{ -1, -1, 0, 1, 0 } // Pseudo 4
};
const uint8_t octant = (m_rex3.m_bres_octant_inc1 >> 24) & 0x7;
@ -3092,7 +3079,6 @@ void newport_base_device::do_iline(uint32_t color)
uint32_t newport_base_device::do_pixel_read()
{
m_rex3.m_bres_octant_inc1 = 0;
const int16_t src_x = m_rex3.m_x_start_i + m_rex3.m_x_window - 0x1000;
const int16_t src_y = m_rex3.m_y_start_i + m_rex3.m_y_window - 0x1000;
uint32_t ret = 0;
@ -3342,8 +3328,9 @@ void newport_base_device::do_rex3_command()
int16_t end_x = m_rex3.m_x_end_i;
int16_t end_y = m_rex3.m_y_end_i;
int16_t dx = 1, dy = 1;
int8_t octant;
LOGMASKED(LOG_COMMANDS, "REX3 Command: %08x|%08x - %s %s\n", mode0, mode1, s_opcode_str[mode0 & 3], s_adrmode_str[(mode0 >> 2) & 7]);
LOGMASKED(LOG_COMMANDS, "REX3 Command: %08x|%08x - %s %s %s\n", mode0, mode1, s_opcode_str[mode0 & 3], s_adrmode_str[(mode0 >> 2) & 7], BIT(mode0, 5) ? "Setup" : "NoSetup");
const uint8_t opcode = mode0 & 3;
const uint8_t adrmode = (mode0 >> 2) & 7;
@ -3353,31 +3340,18 @@ void newport_base_device::do_rex3_command()
case 0: // NoOp
break;
case 1: // Read
if (BIT(mode0, 5))
do_setup();
// Our do_pixel_word_read does not use octant, but seems like hardware is still updating it
m_rex3.m_host_dataport = do_pixel_word_read();
break;
case 2: // Draw
if (BIT(mode0, 5))
do_setup();
octant = (m_rex3.m_bres_octant_inc1 >> 24) & 0x7;
dx = BIT(octant, 1) ? -1 : 1;
dy = BIT(octant, 0) ? -1 : 1;
switch ((m_rex3.m_bres_octant_inc1 >> 24) & 0x3)
{
case 0:
dx = 1;
dy = 1;
break;
case 1:
dx = 1;
dy = -1;
break;
case 2:
dx = -1;
dy = 1;
break;
case 3:
dx = -1;
dy = -1;
break;
}
switch (adrmode)
{
case 0: // Span
@ -3548,6 +3522,12 @@ void newport_base_device::do_rex3_command()
const bool stop_on_x = BIT(mode0, 8);
const bool stop_on_y = BIT(mode0, 9);
if (BIT(mode0, 5))
do_setup();
octant = (m_rex3.m_bres_octant_inc1 >> 24) & 0x7;
dx = BIT(octant, 1) ? -1 : 1;
dy = BIT(octant, 0) ? -1 : 1;
end_x += dx;
end_y += dy;

View File

@ -441,9 +441,9 @@ void mips3_device::device_start()
for (int regnum = 0; regnum < 32; regnum++)
{
char buf[10];
sprintf(buf, "r%d", regnum);
snprintf(buf, 10, "r%d", regnum);
m_drcuml->symbol_add(&m_core->r[regnum], sizeof(m_core->r[regnum]), buf);
sprintf(buf, "f%d", regnum);
snprintf(buf, 10, "f%d", regnum);
m_drcuml->symbol_add(&m_core->cpr[1][regnum], sizeof(m_core->cpr[1][regnum]), buf);
}
m_drcuml->symbol_add(&m_core->r[REG_LO], sizeof(m_core->r[REG_LO]), "lo");
@ -1881,12 +1881,13 @@ uint64_t mips3_device::get_cop0_reg(int idx)
}
else if (idx == COP0_Random)
{
int wired = m_core->cpr[0][COP0_Wired] & 0x3f;
int range = 48 - wired;
if (range > 0)
return ((total_cycles() - m_core->count_zero_time) % range + wired) & 0x3f;
else
return 47;
uint32_t wired = m_core->cpr[0][COP0_Wired] & 0x3f;
uint32_t unwired = m_tlbentries - wired;
if (unwired == 0)
return m_tlbentries - 1;
return (generate_tlb_index() % unwired) + wired;
}
return m_core->cpr[0][idx];
}
@ -5397,7 +5398,7 @@ void mips3_device::execute_run()
{
// Should actually use physical address
m_core->cpr[0][COP0_LLAddr] = SIMMVAL + RSVAL32;
RTVAL64 = temp;
RTVAL64 = int64_t(int32_t(temp));
m_core->llbit = 1;
if LL_BREAK
machine().debug_break();