Mac-related emulation fixes:

* bus/nubus: Started emulating SuperMac Spectrum/8 CRTC.
* bus/nubus: Respect Apple 4•8 screen base register.
* cpu/m68000: Fixed disassembly of bit field extract instructions.
* Also cleaned up data plugin a little.
This commit is contained in:
Vas Crabb 2022-06-20 07:52:24 +10:00
parent e43f51d245
commit 742de90a65
5 changed files with 303 additions and 127 deletions

View File

@ -13,8 +13,10 @@ exports.author = { name = "Carl" }
local data = exports
local plugindir
function data.set_folder(path)
data.path = path
plugindir = path
end
function data.startplugin()
@ -22,60 +24,66 @@ function data.startplugin()
local valid_lst = {}
local cur_set
local cur_list
emu.register_start(function()
data_scr = {}
for file in lfs.dir(data.path) do
local name = string.match(file, "^(data_.*).lua$")
if name then
local script = require("data/" .. name)
if script then
data_scr[#data_scr + 1] = script
emu.register_start(
function()
data_scr = {}
for file in lfs.dir(plugindir) do
local name = string.match(file, '^(data_.*).lua$')
if name then
local script = require('data/' .. name)
if script then
table.insert(data_scr, script)
end
end
end
end
end
end)
emu.register_callback(function(set)
local ret = {}
if set == "" then
set = emu.romname()
end
if set == cur_set then
return cur_list
end
cur_set = set
if not set then
return nil
end
valid_lst = {}
for num, scr in ipairs(data_scr) do
local setname, softname = set:match("^([^,]+),?(.*)$")
if softname == "" then
softname = nil
end
local name = scr.check(setname, softname)
if name then
ret[#ret + 1] = name
valid_lst[#valid_lst + 1] = scr
end
end
cur_list = ret
return ret
end, "data_list")
end)
emu.register_callback(function(num)
return valid_lst[num + 1].get()
end, "data")
emu.register_callback(
function(set)
local ret = {}
if set == '' then
set = emu.romname()
end
if set == cur_set then
return cur_list
end
cur_set = set
if not set then
return nil
end
valid_lst = {}
for num, scr in ipairs(data_scr) do
local setname, softname = set:match('^([^,]+),?(.*)$')
if softname == '' then
softname = nil
end
local name = scr.check(setname, softname)
if name then
table.insert(ret, name)
table.insert(valid_lst, scr)
end
end
cur_list = ret
return ret
end,
'data_list')
emu.register_callback(function(num)
local ver
if valid_lst[num + 1].ver then
ver = valid_lst[num + 1].ver()
end
if ver then
return ver
end
return ""
end, "data_version")
emu.register_callback(
function(num)
return valid_lst[num + 1].get()
end,
'data')
emu.register_callback(
function(num)
local ver
if valid_lst[num + 1].ver then
ver = valid_lst[num + 1].ver()
end
return ver or ''
end,
'data_version')
end
return exports

View File

@ -155,7 +155,7 @@ TIMER_CALLBACK_MEMBER(jmfb_device::vbl_tick)
uint32_t jmfb_device::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect)
{
auto const vram8 = util::big_endian_cast<uint8_t const>(&m_vram[0]) + 0xa00;
auto const vram8 = util::big_endian_cast<uint8_t const>(&m_vram[0]) + m_base;
// first time? kick off the VBL timer
if (!m_screen)
@ -233,7 +233,7 @@ uint32_t jmfb_device::screen_update(screen_device &screen, bitmap_rgb32 &bitmap,
uint32_t const stride = m_stride * 8 / 3;
for (int y = 0; y < m_yres; y++)
{
std::copy_n(&m_vram[(0xa00 / 4) + (y * stride)], m_xres, &bitmap.pix(y));
std::copy_n(&m_vram[(m_base / 4) + (y * stride)], m_xres, &bitmap.pix(y));
}
}
break;
@ -250,7 +250,7 @@ void jmfb_device::mac_48gc_w(offs_t offset, uint32_t data, uint32_t mem_mask)
{
case 0x8/4: // base
// printf("%x to base\n", data);
m_base = (data*2)<<4;
m_base = (data * 2) << 4;
break;
case 0xc/4: // stride

View File

@ -18,6 +18,9 @@
#include <algorithm>
//#define VERBOSE 1
#include "logmacro.h"
#define SPEC8S3_SCREEN_NAME "spec8s3_screen"
#define SPEC8S3_ROM_REGION "spec8s3_rom"
@ -38,6 +41,17 @@ ROM_END
DEFINE_DEVICE_TYPE(NUBUS_SPEC8S3, nubus_spec8s3_device, "nb_sp8s3", "SuperMac Spectrum/8 Series III video card")
//-------------------------------------------------
// crtc_w - write CRTC register byte
//-------------------------------------------------
void nubus_spec8s3_device::crtc_w(int16_t &param, uint32_t offset, uint32_t data)
{
param &= 0xff << (BIT(offset, 1) ? 0 : 8);
param |= (data & 0xff) << (BIT(offset, 1) ? 8 : 0);
}
//-------------------------------------------------
// device_add_mconfig - add device configuration
//-------------------------------------------------
@ -46,9 +60,7 @@ void nubus_spec8s3_device::device_add_mconfig(machine_config &config)
{
screen_device &screen(SCREEN(config, SPEC8S3_SCREEN_NAME, SCREEN_TYPE_RASTER));
screen.set_screen_update(FUNC(nubus_spec8s3_device::screen_update));
screen.set_raw(25175000, 800, 0, 640, 525, 0, 480);
screen.set_size(1024, 768);
screen.set_visarea(0, 1024-1, 0, 768-1);
screen.set_raw(64_MHz_XTAL, 332*4, 64*4, 320*4, 804, 33, 801);
}
//-------------------------------------------------
@ -77,7 +89,9 @@ nubus_spec8s3_device::nubus_spec8s3_device(const machine_config &mconfig, device
device_t(mconfig, type, tag, owner, clock),
device_video_interface(mconfig, *this),
device_nubus_card_interface(mconfig, *this),
m_mode(0), m_vbl_disable(0), m_count(0), m_clutoffs(0), m_timer(nullptr),
m_timer(nullptr),
m_mode(0), m_vbl_disable(0),
m_count(0), m_clutoffs(0),
m_vbl_pending(false), m_parameter(0)
{
set_screen(*this, SPEC8S3_SCREEN_NAME);
@ -89,13 +103,10 @@ nubus_spec8s3_device::nubus_spec8s3_device(const machine_config &mconfig, device
void nubus_spec8s3_device::device_start()
{
uint32_t slotspace;
install_declaration_rom(SPEC8S3_ROM_REGION);
slotspace = get_slotspace();
// printf("[SPEC8S3 %p] slotspace = %x\n", this, slotspace);
const uint32_t slotspace = get_slotspace();
LOG("[SPEC8S3 %p] slotspace = %x\n", this, slotspace);
m_vram.resize(VRAM_SIZE / sizeof(uint32_t));
nubus().install_device(slotspace, slotspace+VRAM_SIZE-1, read32s_delegate(*this, FUNC(nubus_spec8s3_device::vram_r)), write32s_delegate(*this, FUNC(nubus_spec8s3_device::vram_w)));
@ -103,7 +114,23 @@ void nubus_spec8s3_device::device_start()
nubus().install_device(slotspace+0xd0000, slotspace+0xfffff, read32s_delegate(*this, FUNC(nubus_spec8s3_device::spec8s3_r)), write32s_delegate(*this, FUNC(nubus_spec8s3_device::spec8s3_w)));
m_timer = timer_alloc(FUNC(nubus_spec8s3_device::vbl_tick), this);
m_timer->adjust(screen().time_until_pos(767, 0), 0);
save_item(NAME(m_vram));
save_item(NAME(m_mode));
save_item(NAME(m_vbl_disable));
save_item(NAME(m_palette));
save_item(NAME(m_colors));
save_item(NAME(m_count));
save_item(NAME(m_clutoffs));
save_item(NAME(m_hstart));
save_item(NAME(m_hend));
save_item(NAME(m_htotal));
save_item(NAME(m_vstart));
save_item(NAME(m_vend));
save_item(NAME(m_vtotal));
save_item(NAME(m_interlace));
save_item(NAME(m_vbl_pending));
save_item(NAME(m_parameter));
}
//-------------------------------------------------
@ -112,17 +139,27 @@ void nubus_spec8s3_device::device_start()
void nubus_spec8s3_device::device_reset()
{
std::fill(m_vram.begin(), m_vram.end(), 0);
m_mode = 0;
m_vbl_disable = 1;
std::fill(std::begin(m_palette), std::end(m_palette), rgb_t(0));
std::fill(std::begin(m_colors), std::end(m_colors), 0);
m_count = 0;
m_clutoffs = 0;
m_vbl_disable = 1;
m_mode = 0;
m_hstart = -64;
m_hend = -320;
m_htotal = -332;
m_vstart = -33;
m_vend = -801;
m_vtotal = -804;
m_interlace = false;
m_vbl_pending = false;
m_parameter = 0;
std::fill(m_vram.begin(), m_vram.end(), 0);
memset(m_palette, 0, sizeof(m_palette));
m_palette[0] = rgb_t(255, 255, 255);
m_palette[1] = rgb_t(0, 0, 0);
update_crtc();
}
@ -134,79 +171,157 @@ TIMER_CALLBACK_MEMBER(nubus_spec8s3_device::vbl_tick)
m_vbl_pending = true;
}
m_timer->adjust(screen().time_until_pos(767, 0), 0);
m_timer->adjust(screen().time_until_pos(-m_vend * (m_interlace ? 2 : 1), 0));
}
/***************************************************************************
Spectrum 24 PDQ section
Spectrum/8 Series III
***************************************************************************/
void nubus_spec8s3_device::update_crtc()
{
// FIXME: Blatant hack - I have no idea how the clock source is configured
// (there's space for five clock modules on the board)
// Interlace mode configuration is also complicated, so it's hacked here
// The user-supplied clock module should be a machine configuration option
uint32_t clock = 64'000'000; // supplied - 1024x768 60Hz
m_interlace = false;
switch (m_vtotal)
{
case -803:
clock = 80'000'000; // supplied - 1024x768 75Hz
break;
case -654:
clock = 55'000'000; // supplied with newer revisions - 832x625 75Hz
break;
case -525:
clock = 30'240'000; // supplied - 640x480 67Hz
break;
case -411:
clock = 15'821'851; // user-supplied - 512x384 60.15Hz FIXME: what's the real recommended clock for this?
break;
case -262:
clock = 14'318'180; // user-supplied - 640x480i NTSC
m_interlace = true;
break;
}
// for some reason you temporarily get invalid screen parameters - ignore them
if ((m_hend < m_hstart) && (m_htotal < m_hend) && (m_vend < m_vstart) && (m_vtotal < m_vend))
{
screen().configure(
-4 * m_htotal,
-m_vtotal * (m_interlace ? 2 : 1),
rectangle(
-4 * m_hstart, (-4 * m_hend) - 1,
-m_vstart * (m_interlace ? 2 : 1), (-m_vend * (m_interlace ? 2 : 1)) - 1),
attotime::from_ticks(-4 * m_htotal * -m_vtotal * (m_interlace ? 2 : 1), clock).attoseconds());
m_timer->adjust(screen().time_until_pos(-m_vend * (m_interlace ? 2 : 1), 0));
}
else
{
LOG("Ignoring invalid CRTC parameters (%d %d %d) (%d %d %d)\n", m_hstart, m_hend, m_htotal, m_vstart, m_vend, m_vtotal);
}
}
uint32_t nubus_spec8s3_device::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect)
{
auto const vram8 = util::big_endian_cast<uint8_t const>(&m_vram[0]) + 0x400;
const int vstart = -m_vstart * (m_interlace ? 2 : 1);
const int vend = -m_vend * (m_interlace ? 2 : 1);
switch (m_mode)
{
case 0: // 1 bpp
for (int y = 0; y < 768; y++)
for (int y = cliprect.top(); y <= cliprect.bottom(); y++)
{
uint32_t *scanline = &bitmap.pix(y);
for (int x = 0; x < 1024/8; x++)
uint32_t *scanline = &bitmap.pix(y, -4 * m_hstart);
if ((y >= vstart) && (y < vend))
{
uint8_t const pixels = vram8[(y * 512) + x];
for (int x = 0; x < ((m_hstart - m_hend) / 2); x++)
{
uint8_t const pixels = vram8[((y + m_vstart) * 512) + x];
*scanline++ = m_palette[pixels&0x80];
*scanline++ = m_palette[(pixels<<1)&0x80];
*scanline++ = m_palette[(pixels<<2)&0x80];
*scanline++ = m_palette[(pixels<<3)&0x80];
*scanline++ = m_palette[(pixels<<4)&0x80];
*scanline++ = m_palette[(pixels<<5)&0x80];
*scanline++ = m_palette[(pixels<<6)&0x80];
*scanline++ = m_palette[(pixels<<7)&0x80];
*scanline++ = m_palette[pixels & 0x80];
*scanline++ = m_palette[(pixels << 1) & 0x80];
*scanline++ = m_palette[(pixels << 2) & 0x80];
*scanline++ = m_palette[(pixels << 3) & 0x80];
*scanline++ = m_palette[(pixels << 4) & 0x80];
*scanline++ = m_palette[(pixels << 5) & 0x80];
*scanline++ = m_palette[(pixels << 6) & 0x80];
*scanline++ = m_palette[(pixels << 7) & 0x80];
}
}
else
{
std::fill_n(scanline, (m_hstart - m_hend) * 4, 0);
}
}
break;
case 1: // 2 bpp
for (int y = 0; y < 768; y++)
for (int y = cliprect.top(); y <= cliprect.bottom(); y++)
{
uint32_t *scanline = &bitmap.pix(y);
for (int x = 0; x < 1024/4; x++)
uint32_t *scanline = &bitmap.pix(y, -4 * m_hstart);
if ((y >= vstart) && (y < vend))
{
uint8_t const pixels = vram8[(y * 512) + x];
for (int x = 0; x < (m_hstart - m_hend); x++)
{
uint8_t const pixels = vram8[((y + m_vstart) * 512) + x];
*scanline++ = m_palette[pixels&0xc0];
*scanline++ = m_palette[(pixels<<2)&0xc0];
*scanline++ = m_palette[(pixels<<4)&0xc0];
*scanline++ = m_palette[(pixels<<6)&0xc0];
*scanline++ = m_palette[pixels&0xc0];
*scanline++ = m_palette[(pixels<<2)&0xc0];
*scanline++ = m_palette[(pixels<<4)&0xc0];
*scanline++ = m_palette[(pixels<<6)&0xc0];
}
}
else
{
std::fill_n(scanline, (m_hstart - m_hend) * 4, 0);
}
}
break;
case 2: // 4 bpp
for (int y = 0; y < 768; y++)
for (int y = cliprect.top(); y <= cliprect.bottom(); y++)
{
uint32_t *scanline = &bitmap.pix(y);
for (int x = 0; x < 1024/2; x++)
uint32_t *scanline = &bitmap.pix(y, -4 * m_hstart);
if ((y >= vstart) && (y < vend))
{
uint8_t const pixels = vram8[(y * 512) + x];
for (int x = 0; x < ((m_hstart - m_hend) * 2); x++)
{
uint8_t const pixels = vram8[((y + m_vstart) * 512) + x];
*scanline++ = m_palette[pixels&0xf0];
*scanline++ = m_palette[(pixels<<4)&0xf0];
*scanline++ = m_palette[pixels&0xf0];
*scanline++ = m_palette[(pixels<<4)&0xf0];
}
}
else
{
std::fill_n(scanline, (m_hstart - m_hend) * 4, 0);
}
}
break;
case 3: // 8 bpp
for (int y = 0; y < 768; y++)
for (int y = cliprect.top(); y <= cliprect.bottom(); y++)
{
uint32_t *scanline = &bitmap.pix(y);
for (int x = 0; x < 1024; x++)
uint32_t *scanline = &bitmap.pix(y, -4 * m_hstart);
if ((y >= vstart) && (y < vend))
{
uint8_t const pixels = vram8[(y * 1024) + x];
*scanline++ = m_palette[pixels];
for (int x = 0; x < ((m_hstart - m_hend) * 4); x++)
{
uint8_t const pixels = vram8[((y + m_vstart) * 1024) + x];
*scanline++ = m_palette[pixels];
}
}
else
{
std::fill_n(scanline, (m_hstart - m_hend) * 4, 0);
}
}
break;
@ -221,6 +336,48 @@ void nubus_spec8s3_device::spec8s3_w(offs_t offset, uint32_t data, uint32_t mem_
{
switch (offset)
{
case 0x3808:
case 0x380a:
crtc_w(m_hstart, offset, data);
if (!BIT(offset, 1))
update_crtc();
break;
case 0x380c:
case 0x380e:
crtc_w(m_hend, offset, data);
if (!BIT(offset, 1))
update_crtc();
break;
case 0x3810:
case 0x3812:
crtc_w(m_htotal, offset, data);
if (!BIT(offset, 1))
update_crtc();
break;
case 0x381c:
case 0x381e:
crtc_w(m_vstart, offset, data);
if (!BIT(offset, 1))
update_crtc();
break;
case 0x3824:
case 0x3826:
crtc_w(m_vend, offset, data);
if (!BIT(offset, 1))
update_crtc();
break;
case 0x3828:
case 0x382a:
crtc_w(m_vtotal, offset, data);
if (!BIT(offset, 1))
update_crtc();
break;
case 0x385c: // IRQ enable
if (data & 0x10)
{
@ -245,20 +402,16 @@ void nubus_spec8s3_device::spec8s3_w(offs_t offset, uint32_t data, uint32_t mem_
break;
case 0x3a01:
// printf("%08x to color (%08x invert)\n", data, data ^ 0xffffffff);
LOG("%08x to color (%08x invert)\n", data, data ^ 0xffffffff);
m_colors[m_count++] = (data & 0xff) ^ 0xff;
if (m_count == 3)
{
int actual_color = bitswap<8>(m_clutoffs, 0, 1, 2, 3, 4, 5, 6, 7);
const int actual_color = bitswap<8>(m_clutoffs, 0, 1, 2, 3, 4, 5, 6, 7);
// logerror("RAMDAC: color %d = %02x %02x %02x %s\n", actual_color, m_colors[0], m_colors[1], m_colors[2], machine().describe_context() );
LOG("RAMDAC: color %d = %02x %02x %02x %s\n", actual_color, m_colors[0], m_colors[1], m_colors[2], machine().describe_context());
m_palette[actual_color] = rgb_t(m_colors[0], m_colors[1], m_colors[2]);
m_clutoffs++;
if (m_clutoffs > 255)
{
m_clutoffs = 0;
}
m_clutoffs = (m_clutoffs + 1) & 0xff;
m_count = 0;
}
break;
@ -267,7 +420,7 @@ void nubus_spec8s3_device::spec8s3_w(offs_t offset, uint32_t data, uint32_t mem_
if ((m_parameter == 2) && (data != 0xffffffff))
{
data &= 0xff;
// logerror("%x to mode\n", data);
LOG("%x to mode\n", data);
switch (data)
{
case 0x5f:

View File

@ -41,17 +41,22 @@ private:
uint32_t vram_r(offs_t offset, uint32_t mem_mask = ~0);
void vram_w(offs_t offset, uint32_t data, uint32_t mem_mask = ~0);
void update_crtc();
uint32_t screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect);
static void crtc_w(int16_t &param, uint32_t offset, uint32_t data);
emu_timer *m_timer;
std::vector<uint32_t> m_vram;
uint32_t m_mode, m_vbl_disable;
uint32_t m_palette[256], m_colors[3], m_count, m_clutoffs;
emu_timer *m_timer;
//uint32_t m_7xxxxx_regs[0x100000/4];
//int m_width, m_height, m_patofsx, m_patofsy;
//uint32_t m_vram_addr, m_vram_src;
//uint8_t m_fillbytes[256];
int16_t m_hstart, m_hend, m_htotal;
int16_t m_vstart, m_vend, m_vtotal;
bool m_interlace;
bool m_vbl_pending;
int m_parameter;
};

View File

@ -718,30 +718,40 @@ std::string m68k_disassembler::d68020_bfclr()
std::string m68k_disassembler::d68020_bfexts()
{
auto limit = limit_cpu_types(M68020_PLUS);
auto const limit = limit_cpu_types(M68020_PLUS);
if(limit.first)
return limit.second;
u16 extension = read_imm_16();
u16 const extension = read_imm_16();
std::string offset = BIT(extension, 11) ? util::string_format("D%d", (extension>>6)&7) : util::string_format("%d", (extension>>6)&31);
std::string const offset = BIT(extension, 11)
? util::string_format("D%d", (extension >> 6) & 7)
: util::string_format("%d", (extension >> 6) & 31);
std::string width = BIT(extension, 5) ? util::string_format("D%d", extension&7) : util::string_format("%d", m_5bit_data_table[extension&31]);
return util::string_format("bfexts D%d, %s {%s:%s}; (2+)", (extension>>12)&7, get_ea_mode_str_8(m_cpu_ir), offset, width);
std::string const width = BIT(extension, 5)
? util::string_format("D%d", extension & 7)
: util::string_format("%d", m_5bit_data_table[extension & 31]);
return util::string_format("bfexts %s {%s:%s}, D%d; (2+)", get_ea_mode_str_8(m_cpu_ir), offset, width, (extension >> 12) & 7);
}
std::string m68k_disassembler::d68020_bfextu()
{
auto limit = limit_cpu_types(M68020_PLUS);
auto const limit = limit_cpu_types(M68020_PLUS);
if(limit.first)
return limit.second;
u16 extension = read_imm_16();
u16 const extension = read_imm_16();
std::string offset = BIT(extension, 11) ? util::string_format("D%d", (extension>>6)&7) : util::string_format("%d", (extension>>6)&31);
std::string const offset = BIT(extension, 11)
? util::string_format("D%d", (extension >> 6) & 7)
: util::string_format("%d", (extension >> 6) & 31);
std::string width = BIT(extension, 5) ? util::string_format("D%d", extension&7) : util::string_format("%d", m_5bit_data_table[extension&31]);
return util::string_format("bfextu D%d, %s {%s:%s}; (2+)", (extension>>12)&7, get_ea_mode_str_8(m_cpu_ir), offset, width);
std::string const width = BIT(extension, 5)
? util::string_format("D%d", extension & 7)
: util::string_format("%d", m_5bit_data_table[extension & 31]);
return util::string_format("bfextu %s {%s:%s}, D%d; (2+)", get_ea_mode_str_8(m_cpu_ir), offset, width, (extension >> 12) & 7);
}
std::string m68k_disassembler::d68020_bfffo()
@ -3133,7 +3143,7 @@ std::string m68k_disassembler::d68040_fbcc_32()
const m68k_disassembler::opcode_struct m68k_disassembler::m_opcode_info[] =
{
/* opcode handler mask match ea mask */
/* opcode handler mask match ea mask */
{&m68k_disassembler::d68000_1010 , 0xf000, 0xa000, 0x000},
{&m68k_disassembler::d68000_1111 , 0xf000, 0xf000, 0x000},
{&m68k_disassembler::d68000_abcd_rr , 0xf1f8, 0xc100, 0x000},