rc759: Major improvements to I82730, hook up SN76489A, preliminary palette

This commit is contained in:
Dirk Best 2021-03-15 23:15:57 +01:00
parent d26be5231a
commit 62fdcc28df
3 changed files with 571 additions and 170 deletions

View File

@ -13,14 +13,12 @@
#include "screen.h"
//**************************************************************************
// CONSTANTS
//**************************************************************************
#define VERBOSE 1
#define VERBOSE_COMMANDS 1
#define VERBOSE_DATASTREAM 0
#define LOG_GENERAL (1U << 0)
#define LOG_COMMANDS (1U << 1)
#define LOG_DATASTREAM (1U << 2)
//#define VERBOSE (LOG_GENERAL | LOG_COMMANDS | LOG_DATASTREAM)
#define VERBOSE (LOG_GENERAL)
#include "logmacro.h"
//**************************************************************************
@ -29,22 +27,6 @@
DEFINE_DEVICE_TYPE(I82730, i82730_device, "i82730", "Intel 82730")
const char *const i82730_device::s_command_names[] =
{
/* 00 */ "NOP",
/* 01 */ "START DISPLAY",
/* 02 */ "START VIRTUAL DISPLAY",
/* 03 */ "STOP DISPLAY",
/* 04 */ "MODE SET",
/* 05 */ "LOAD CBP",
/* 06 */ "LOAD INTMASK",
/* 07 */ "LPEN ENABLE",
/* 08 */ "READ STATUS",
/* 09 */ "LD CUR POS",
/* 0a */ "SELF TEST",
/* 0b */ "TEST ROW BUFFER"
};
//**************************************************************************
// LIVE DEVICE
@ -65,26 +47,20 @@ i82730_device::i82730_device(const machine_config &mconfig, const char *tag, dev
m_initialized(false),
m_mode_set(false),
m_ca(0),
m_ca_latch(false),
m_sysbus(0x00),
m_ibp(0x0000),
m_cbp(0x0000),
m_intmask(0xffff),
m_status(0x0000),
m_list_switch(0),
m_auto_line_feed(0),
m_list_switch(false),
m_auto_line_feed(false),
m_max_dma_count(0),
m_lptr(0),
m_status(0x0000),
m_intmask(0xffff),
m_sptr(0),
m_dma_burst_space(0),
m_dma_burst_length(0),
m_hfldstrt(0),
m_margin(0),
m_lpr(0),
m_field_attribute_mask(0),
m_vsyncstp(0),
m_vfldstrt(0),
m_vfldstp(0),
m_frame_int_count(0),
m_row(nullptr),
m_dma_count(0),
m_row_count(0),
m_row_index(0)
{
}
@ -120,6 +96,7 @@ void i82730_device::device_reset()
m_mode_set = false;
m_ca = 0;
m_ca_latch = false;
m_status = 0x0000;
}
@ -188,66 +165,119 @@ void i82730_device::mode_set()
uint16_t tmp;
tmp = read_word(mptr);
m_dma_burst_space = tmp & 0x7f;
m_dma_burst_length = (tmp >> 8) & 0x7f;
m_mb.burst_length = (tmp >> 8) & 0x7f;
m_mb.burst_space = tmp & 0x7f;
tmp = read_word(mptr + 2);
uint8_t hsyncstp = tmp & 0xff;
uint8_t line_length = (tmp >> 8) & 0xff;
m_mb.line_length = (tmp >> 8) & 0xff;
m_mb.hsyncstp = tmp & 0xff;
tmp = read_word(mptr + 4);
uint8_t hfldstp = tmp & 0xff;
m_hfldstrt = (tmp >> 8) & 0xff;
m_mb.hfldstrt = (tmp >> 8) & 0xff;
m_mb.hfldstp = tmp & 0xff;
tmp = read_word(mptr + 6);
uint8_t hbrdstp = tmp & 0xff;
uint8_t hbrdstrt = (tmp >> 8) & 0xff;
m_mb.hbrdstrt = (tmp >> 8) & 0xff;
m_mb.hbrdstp = tmp & 0xff;
tmp = read_word(mptr + 8);
m_margin = tmp & 0x1f;
m_mb.scroll_margin = tmp & 0x1f;
tmp = read_word(mptr + 10);
m_lpr = tmp & 0x1f;
m_mb.rvv_row = bool(BIT(tmp, 11));
m_mb.blk_row = bool(BIT(tmp, 10));
m_mb.dbl_hgt = bool(BIT(tmp, 9));
m_mb.wdef = bool(BIT(tmp, 8));
m_mb.lpr = tmp & 0x1f;
tmp = read_word(mptr + 12);
m_mb.nrmstrt = (tmp >> 8) & 0x1f;
m_mb.nrmstp = tmp & 0x1f;
tmp = read_word(mptr + 14);
m_mb.supstrt = (tmp >> 8) & 0x1f;
m_mb.supstp = tmp & 0x1f;
tmp = read_word(mptr + 16);
m_mb.substrt = (tmp >> 8) & 0x1f;
m_mb.substp = tmp & 0x1f;
tmp = read_word(mptr + 18);
m_mb.cur1strt = (tmp >> 8) & 0x1f;
m_mb.cur1stp = tmp & 0x1f;
tmp = read_word(mptr + 20);
m_mb.cur2strt = (tmp >> 8) & 0x1f;
m_mb.cur2stp = tmp & 0x1f;
tmp = read_word(mptr + 22);
m_mb.u2_line_sel = (tmp >> 8) & 0x1f;
m_mb.u1_line_sel = tmp & 0x1f;
tmp = read_word(mptr + 24);
m_field_attribute_mask = tmp & 0x7fff;
m_mb.field_attribute_mask = tmp & 0x7fff;
tmp = read_word(mptr + 26);
uint16_t frame_length = tmp & 0x7ff;
m_mb.frame_length = tmp & 0x7ff;
tmp = read_word(mptr + 28);
m_vsyncstp = tmp & 0x7ff;
m_mb.vsyncstp = tmp & 0x7ff;
tmp = read_word(mptr + 30);
m_vfldstrt = tmp & 0x7ff;
m_mb.vfldstrt = tmp & 0x7ff;
tmp = read_word(mptr + 32);
m_vfldstp = tmp & 0x7ff;
m_mb.vfldstp = tmp & 0x7ff;
tmp = read_word(mptr + 38);
m_frame_int_count = tmp & 0x0f;
m_mb.duty_cyc_cursor = (tmp >> 12) & 0x0f;
m_mb.cursor_blink = (tmp >> 8) & 0x0f;
m_mb.frame_int_count = tmp & 0x0f;
tmp = read_word(mptr + 40);
m_mb.duty_cyc_char = (tmp >> 12) & 0x0f;
m_mb.char_blink = (tmp >> 8) & 0x0f;
m_mb.ile = bool(BIT(tmp, 7));
m_mb.rfe = bool(BIT(tmp, 6));
m_mb.bpol = bool(BIT(tmp, 5));
m_mb.bue = bool(BIT(tmp, 4));
m_mb.cr2_cd = bool(BIT(tmp, 3));
m_mb.cr1_cd = bool(BIT(tmp, 2));
m_mb.cr2_be = bool(BIT(tmp, 1));
m_mb.cr1_be = bool(BIT(tmp, 0));
tmp = read_word(mptr + 40);
m_mb.reverse_video = (tmp >> 12) & 0x0f;
m_mb.blinking_char = (tmp >> 8) & 0x0f;
m_mb.cr2_rvv = bool(BIT(tmp, 3));
m_mb.cr1_rvv = bool(BIT(tmp, 2));
m_mb.cr2_oe = bool(BIT(tmp, 1));
m_mb.cr1_oe = bool(BIT(tmp, 0));
tmp = read_word(mptr + 42);
m_mb.abs_line_count = (tmp >> 12) & 0x0f;
m_mb.invisible_char = (tmp >> 8) & 0x0f;
m_mb.underline2 = (tmp >> 4) & 0x0f;
m_mb.underline1 = tmp & 0x0f;
// setup screen mode
rectangle visarea(hbrdstrt * 16, hbrdstp * 16 - 1, m_vsyncstp, m_vfldstp + m_margin + 1 + m_lpr - 1);
attoseconds_t period = HZ_TO_ATTOSECONDS(clock() * 16) * line_length * 16 * frame_length;
screen().configure(line_length * 16, frame_length, visarea, period);
rectangle visarea(m_mb.hbrdstrt * 16, m_mb.hbrdstp * 16 - 1, m_mb.vsyncstp, m_mb.vfldstp + m_mb.scroll_margin + 1 + m_mb.lpr - 1);
attoseconds_t period = HZ_TO_ATTOSECONDS(clock() * 16) * m_mb.line_length * 16 * m_mb.frame_length;
screen().configure(m_mb.line_length * 16, m_mb.frame_length, visarea, period);
// start display is now valid
m_mode_set = true;
// adjust timer for the new mode
m_row_timer->adjust(screen().time_until_pos(0));
// output some debug info
if (VERBOSE)
{
logerror("%s('%s'): ---- setting mode ----\n", shortname(), basetag());
logerror("%s('%s'): dma burst length %02x, space %02x\n", shortname(), basetag(), m_dma_burst_length, m_dma_burst_space);
logerror("%s('%s'): margin %02x, lpr %02x\n", shortname(), basetag(), m_margin, m_lpr);
logerror("%s('%s'): ---- modeset ----\n", shortname(), basetag());
logerror("%s('%s'): dma burst length %02x, space %02x\n", shortname(), basetag(), m_mb.burst_length, m_mb.burst_space);
logerror("%s('%s'): margin %02x, lpr %02x\n", shortname(), basetag(), m_mb.scroll_margin, m_mb.lpr);
logerror("%s('%s'): hsyncstp: %02x, line_length: %02x, hfldstrt: %02x, hbrdstart: %02x, hfldstop: %02x, hbrdstop: %02x\n",
shortname(), basetag(), hsyncstp, line_length, m_hfldstrt, hbrdstrt, hfldstp, hbrdstp);
shortname(), basetag(), m_mb.hsyncstp, m_mb.line_length, m_mb.hfldstrt, m_mb.hbrdstrt, m_mb.hfldstp, m_mb.hbrdstp);
logerror("%s('%s'): frame_length %04x, vsyncstp: %04x, vfldstrt: %04x, vfldstp: %04x\n",
shortname(), basetag(), frame_length, m_vsyncstp, m_vfldstrt, m_vfldstp);
shortname(), basetag(), m_mb.frame_length, m_mb.vsyncstp, m_mb.vfldstrt, m_mb.vfldstp);
}
}
@ -256,16 +286,15 @@ void i82730_device::execute_command()
uint8_t command = read_byte(m_cbp + 1);
uint16_t tmp;
if (VERBOSE_COMMANDS && command < std::size(s_command_names))
logerror("%s('%s'): executing command: %s [cbp = %08x]\n", shortname(), basetag(), s_command_names[command], m_cbp);
tmp = read_word(m_cbp + 2);
m_list_switch = BIT(tmp, 6);
m_auto_line_feed = BIT(tmp, 7);
m_list_switch = bool(BIT(tmp, 7));
m_auto_line_feed = bool(BIT(tmp, 6));
tmp = read_word(m_cbp + 4);
m_max_dma_count = tmp & 0xff;
LOGMASKED(LOG_COMMANDS, "list switch %d, autolf %d, dma count %02x\n", m_list_switch, m_auto_line_feed, m_max_dma_count);
switch (command)
{
// NOP
@ -274,68 +303,83 @@ void i82730_device::execute_command()
// START DISPLAY
case 0x01:
LOGMASKED(LOG_COMMANDS, "Executing command START DISPLAY\n");
if (m_mode_set)
{
m_status = (m_status & ~VDIP) | DIP;
m_row_timer->adjust(screen().time_until_pos(0));
}
break;
// START VIRTUAL DISPLAY
case 0x02:
if (m_mode_set)
m_status = VDIP | (m_status & ~DIP);
LOGMASKED(LOG_COMMANDS, "Executing command START VIRTUAL DISPLAY - not implemented\n");
break;
// STOP DISPLAY
case 0x03:
LOGMASKED(LOG_COMMANDS, "Executing command STOP DISPLAY\n");
m_status &= ~(VDIP | DIP);
m_row_timer->reset();
break;
// MODE SET
case 0x04:
LOGMASKED(LOG_COMMANDS, "Executing command MODE SET\n");
mode_set();
break;
// LOAD CBP
case 0x05:
LOGMASKED(LOG_COMMANDS, "Executing command LOAD CBP\n");
m_cbp = (read_word(m_cbp + 16) << 16) | read_word(m_cbp + 14);
LOGMASKED(LOG_COMMANDS, "--> New value = %08x\n", m_cbp);
execute_command();
break;
// LOAD INTMASK
case 0x06:
LOGMASKED(LOG_COMMANDS, "Executing command LOAD INTMASK\n");
m_intmask = read_word(m_cbp + 22);
if (VERBOSE_COMMANDS)
logerror("%s('%s'): intmask now %04x\n", shortname(), basetag(), m_intmask);
LOGMASKED(LOG_COMMANDS, "--> New value = %02x\n", m_intmask);
break;
// LPEN ENABLE
case 0x07:
fatalerror("%s('%s'): Unimplemented command %s\n", shortname(), basetag(), s_command_names[command]);
LOGMASKED(LOG_COMMANDS, "Executing command LPEN ENABLE - not implemented\n");
break;
// READ STATUS
case 0x08:
LOGMASKED(LOG_COMMANDS, "Executing command READ STATUS\n");
write_word(m_cbp + 18, m_status);
m_status &= (VDIP | DIP);
break;
// LD CUR POS
case 0x09:
fatalerror("%s('%s'): Unimplemented command %s\n", shortname(), basetag(), s_command_names[command]);
LOGMASKED(LOG_COMMANDS, "Executing command LD CUR POS\n");
tmp = read_word(m_cbp + 26);
m_cursor[0].y = (tmp >> 8) & 0xff;
m_cursor[0].x = tmp & 0xff;
tmp = read_word(m_cbp + 28);
m_cursor[1].y = (tmp >> 8) & 0xff;
m_cursor[1].x = tmp & 0xff;
LOGMASKED(LOG_COMMANDS, "--> Cursor %d, %d and %d, %d\n", m_cursor[0].x, m_cursor[0].y, m_cursor[1].x, m_cursor[1].y);
break;
// SELF TEST
case 0x0a:
fatalerror("%s('%s'): Unimplemented command %s\n", shortname(), basetag(), s_command_names[command]);
LOGMASKED(LOG_COMMANDS, "Executing command SELF TEST - not implemented\n");
break;
// TEST ROW BUFFER
case 0x0b:
fatalerror("%s('%s'): Unimplemented command %s\n", shortname(), basetag(), s_command_names[command]);
LOGMASKED(LOG_COMMANDS, "Executing command TEST ROW BUFFER - not implemented\n");
break;
default:
if (VERBOSE_COMMANDS)
logerror("%s('%s'): executing command: (reserved) [cbp = %08x]\n", shortname(), basetag(), m_cbp);
LOGMASKED(LOG_COMMANDS, "Executing command %02x - unknown\n", command);
m_status |= RCC;
update_interrupts();
break;
@ -345,11 +389,269 @@ void i82730_device::execute_command()
write_word(m_cbp, read_word(m_cbp) & 0xff00);
}
bool i82730_device::dscmd_endrow()
{
LOGMASKED(LOG_DATASTREAM, "Executing datastream command ENDROW\n");
return true;
}
bool i82730_device::dscmd_eof()
{
LOGMASKED(LOG_DATASTREAM, "Executing datastream command EOF - not implemented\n");
return false;
}
bool i82730_device::dscmd_eol()
{
LOGMASKED(LOG_DATASTREAM, "Executing datastream command EOL\n");
m_sptr = (read_word(m_lptr + 2) << 16) | read_word(m_lptr);
m_lptr += 4;
return true;
}
bool i82730_device::dscmd_fulrowdescrpt(uint8_t param)
{
LOGMASKED(LOG_DATASTREAM, "Executing datastream command FULROWDESCRPT %d\n", param);
uint16_t tmp;
if (param >= 1)
{
tmp = read_word(m_sptr);
m_sptr += 2;
m_mb.rvv_row = bool(BIT(tmp, 11));
m_mb.blk_row = bool(BIT(tmp, 10));
m_mb.dbl_hgt = bool(BIT(tmp, 9));
m_mb.wdef = bool(BIT(tmp, 8));
m_mb.lpr = tmp & 0x1f;
LOGMASKED(LOG_DATASTREAM, "--> RVV_ROW %d, BLK_ROW %d, DBL_HGT %d, WDEF %d, LPR %d\n", m_mb.rvv_row, m_mb.blk_row, m_mb.dbl_hgt, m_mb.wdef, m_mb.lpr);
}
if (param >= 2)
{
tmp = read_word(m_sptr);
m_sptr += 2;
m_mb.nrmstrt = (tmp >> 8) & 0x1f;
m_mb.nrmstp = tmp & 0x1f;
LOGMASKED(LOG_DATASTREAM, "--> NRMSTRT %d, NRMSTP %d\n", m_mb.nrmstrt, m_mb.nrmstp);
}
if (param >= 3)
{
tmp = read_word(m_sptr);
m_sptr += 2;
m_mb.supstrt = (tmp >> 8) & 0x1f;
m_mb.supstp = tmp & 0x1f;
LOGMASKED(LOG_DATASTREAM, "--> SUPSTRT %d, SUPSTP %d\n", m_mb.supstrt, m_mb.supstp);
}
if (param >= 4)
{
tmp = read_word(m_sptr);
m_sptr += 2;
m_mb.substrt = (tmp >> 8) & 0x1f;
m_mb.substp = tmp & 0x1f;
LOGMASKED(LOG_DATASTREAM, "--> SUBSTRT %d, SUBSTP %d\n", m_mb.substrt, m_mb.substp);
}
if (param >= 5)
{
tmp = read_word(m_sptr);
m_sptr += 2;
m_mb.cur1strt = (tmp >> 8) & 0x1f;
m_mb.cur1stp = tmp & 0x1f;
LOGMASKED(LOG_DATASTREAM, "--> CUR1STRT %d, CUR1STP %d\n", m_mb.cur1strt, m_mb.cur1stp);
}
if (param >= 6)
{
tmp = read_word(m_sptr);
m_sptr += 2;
m_mb.cur2strt = (tmp >> 8) & 0x1f;
m_mb.cur2stp = tmp & 0x1f;
LOGMASKED(LOG_DATASTREAM, "--> CUR2STRT %d, CUR2STP %d\n", m_mb.cur2strt, m_mb.cur2stp);
}
if (param >= 7)
{
tmp = read_word(m_sptr);
m_sptr += 2;
m_mb.u2_line_sel = (tmp >> 8) & 0x1f;
m_mb.u1_line_sel = tmp & 0x1f;
LOGMASKED(LOG_DATASTREAM, "--> U2 LINE SEL %d, U1 LINE SEL %d\n", m_mb.u2_line_sel, m_mb.u1_line_sel);
}
return false;
}
bool i82730_device::dscmd_sl_scroll_strt(uint8_t param)
{
LOGMASKED(LOG_DATASTREAM, "Executing datastream command SL SCROLL START %d - not implemented\n", param);
return false;
}
bool i82730_device::dscmd_sl_scroll_end(uint8_t param)
{
LOGMASKED(LOG_DATASTREAM, "Executing datastream command SL SCROLL END %d - not implemented\n", param);
return false;
}
bool i82730_device::dscmd_tab_to(uint8_t param)
{
LOGMASKED(LOG_DATASTREAM, "Executing datastream command TAB TO %d - not implemented\n", param);
return false;
}
bool i82730_device::dscmd_max_dma_count(uint8_t param)
{
LOGMASKED(LOG_DATASTREAM, "Executing datastream command LD MAX DMA COUNT %02x\n", param);
m_max_dma_count = param;
return false;
}
bool i82730_device::dscmd_endstrg()
{
LOGMASKED(LOG_DATASTREAM, "Executing datastream command ENDSTRG\n");
m_sptr = (read_word(m_lptr + 2) << 16) | read_word(m_lptr);
m_lptr += 4;
LOGMASKED(LOG_DATASTREAM, "--> SPTR %08x\n", m_sptr);
return false;
}
bool i82730_device::dscmd_skip(uint8_t param)
{
LOGMASKED(LOG_DATASTREAM, "Executing datastream command SKIP %d - not implemented\n", param);
return false;
}
bool i82730_device::dscmd_repeat(uint8_t param)
{
LOGMASKED(LOG_DATASTREAM, "Executing datastream command REPEAT %d\n", param);
uint16_t data = read_word(m_sptr);
m_sptr += 2;
LOGMASKED(LOG_DATASTREAM, "--> Repeating %02x\n", data);
while (param--)
{
if (--m_dma_count && m_row_count < 200)
m_row[m_row_count++] = data;
else
return true;
}
return false;
}
bool i82730_device::dscmd_sub_sup(uint8_t param)
{
LOGMASKED(LOG_DATASTREAM, "Executing datastream command SUP SUB - not implemented\n", param);
return false;
}
bool i82730_device::dscmd_rpt_sub_sup(uint8_t param)
{
LOGMASKED(LOG_DATASTREAM, "Executing datastream command RPT SUP SUB - not implemented\n", param);
return false;
}
bool i82730_device::dscmd_set_gen_pur_attrib(uint8_t param)
{
LOGMASKED(LOG_DATASTREAM, "Executing datastream command SET GEN PUR ATTRIB - not implemented\n", param);
return false;
}
bool i82730_device::dscmd_set_field_attrib()
{
LOGMASKED(LOG_DATASTREAM, "Executing datastream command SET FIELD ATTRIB\n");
m_mb.field_attribute_mask = read_word(m_sptr) & 0x7fff;
m_sptr += 2;
LOGMASKED(LOG_DATASTREAM, "--> New value = %04x\n", m_mb.field_attribute_mask);
return false;
}
bool i82730_device::dscmd_init_next_process()
{
LOGMASKED(LOG_DATASTREAM, "Executing datastream command INIT NEXT PROCESS - not implemented\n");
return false;
}
bool i82730_device::execute_datastream_command(uint8_t command, uint8_t param)
{
// RESERVED
if (command >= 0x90 && command <= 0xbf)
{
LOGMASKED(LOG_DATASTREAM, "Executing reserved datastream command %02x\n", command);
m_status |= RDC;
update_interrupts();
return false;
}
// NOP
if (command >= 0xc0)
return false;
// DATASTREAM COMMANDS
switch (command)
{
case 0x80: return dscmd_endrow();
case 0x81: return dscmd_eof();
case 0x82: return dscmd_eol();
case 0x83: return dscmd_fulrowdescrpt(param);
case 0x84: return dscmd_sl_scroll_strt(param);
case 0x85: return dscmd_sl_scroll_end(param);
case 0x86: return dscmd_tab_to(param);
case 0x87: return dscmd_max_dma_count(param);
case 0x88: return dscmd_endstrg();
case 0x89: return dscmd_skip(param);
case 0x8a: return dscmd_repeat(param);
case 0x8b: return dscmd_sub_sup(param);
case 0x8c: return dscmd_rpt_sub_sup(param);
case 0x8d: return dscmd_set_gen_pur_attrib(param);
case 0x8e: return dscmd_set_field_attrib();
case 0x8f: return dscmd_init_next_process();
}
// should never get here
return false;
}
void i82730_device::load_row()
{
bool finished = false;
m_row[m_row_index].count = 0;
m_dma_count = m_max_dma_count;
m_row_count = 0;
while (!finished)
{
@ -358,44 +660,37 @@ void i82730_device::load_row()
if (BIT(data, 15))
{
switch (data >> 8)
{
case 0x8e:
m_field_attribute_mask = read_word(m_sptr) & 0x7fff;
m_sptr += 2;
if (VERBOSE_DATASTREAM)
logerror("%s('%s'): SET FIELD ATTRIB to %04x\n", shortname(), basetag(), m_field_attribute_mask);
break;
default:
fatalerror("%s('%s'): Unimplemented datastream command %02x\n", shortname(), basetag(), data >> 8);
}
finished = execute_datastream_command(data >> 8, data & 0xff);
}
else
{
// maximum row size is 200
if (m_row[m_row_index].count < m_max_dma_count && m_row[m_row_index].count < 200)
// fetch data
if (--m_dma_count > 0)
{
m_row[m_row_index].data[m_row[m_row_index].count++] = data;
if (m_row_count < 200)
{
m_row[m_row_count++] = data;
}
else
{
// buffer overrun
m_status |= DBOR;
update_interrupts();
finished = true;
}
}
else
{
#if 0
// move to next string?
if (m_auto_line_feed == 0)
if (!m_auto_line_feed)
{
m_sptr = (read_word(m_lptr + 2) << 16) | read_word(m_lptr);
m_lptr += 4;
}
#endif
finished = true;
}
}
}
m_sptr -= 2;
}
TIMER_CALLBACK_MEMBER( i82730_device::row_update )
@ -408,10 +703,10 @@ TIMER_CALLBACK_MEMBER( i82730_device::row_update )
m_status &= (VDIP | DIP);
// clear field attribute mask
m_field_attribute_mask = 0;
m_mb.field_attribute_mask = 0;
// get listbase
if (m_list_switch)
if (m_list_switch == 0)
m_lptr = (read_word(m_cbp + 8) << 16) | read_word(m_cbp + 6);
else
m_lptr = (read_word(m_cbp + 12) << 16) | read_word(m_cbp + 10);
@ -421,46 +716,52 @@ TIMER_CALLBACK_MEMBER( i82730_device::row_update )
// fetch initial row
m_row_index = 0;
m_row = &m_row_buffer[m_row_index][0];
load_row();
}
else if (y >= m_vsyncstp && y < m_vfldstrt)
else if (y >= m_mb.vsyncstp && y < m_mb.vfldstrt)
{
// blank (top border)
}
else if (y >= m_vfldstrt && y < m_vfldstp)
else if (y >= m_mb.vfldstrt && y < m_mb.vfldstp)
{
uint8_t lc = (y - m_vfldstrt) % (m_lpr + 1);
uint8_t lc = (y - m_mb.vfldstrt) % (m_mb.lpr + 1);
// call driver
m_update_row_cb(m_bitmap, m_row[m_row_index].data, lc, y - m_vsyncstp, m_row[m_row_index].count);
m_update_row_cb(m_bitmap, m_row, lc, y - m_mb.vsyncstp, m_row_count);
// swap buffers at end of row
if (lc == m_lpr)
if (lc == m_mb.lpr)
{
m_row_index ^= 1;
m_row = &m_row_buffer[m_row_index][0];
// load status row data at end of regular display
if (y == (m_mb.vfldstp - 1))
m_sptr = (read_word(m_cbp + 36) << 16) | read_word(m_cbp + 34);
load_row();
}
}
else if (y >= m_vfldstp && y < m_vfldstp + m_margin + 1)
else if (y >= m_mb.vfldstp && y < m_mb.vfldstp + m_mb.scroll_margin + 1)
{
// margin
}
else if (y >= m_vfldstp + m_margin + 1 && y < m_vfldstp + m_margin + 1 + m_lpr + 1)
else if (y >= m_mb.vfldstp + m_mb.scroll_margin + 1 && y < m_mb.vfldstp + m_mb.scroll_margin + 1 + m_mb.lpr + 1)
{
uint8_t lc = (y - (m_vfldstp + m_margin + 1)) % (m_lpr + 1);
m_sptr = (read_word(m_cbp + 36) << 16) | read_word(m_cbp + 34);
load_row();
uint8_t lc = (y - (m_mb.vfldstp + m_mb.scroll_margin + 1)) % (m_mb.lpr + 1);
// call driver
m_update_row_cb(m_bitmap, m_row[m_row_index].data, lc, y - m_vsyncstp, m_row[m_row_index].count);
m_update_row_cb(m_bitmap, m_row, lc, y - m_mb.vsyncstp, m_row_count);
}
else if (y == m_vfldstp + m_margin + 1 + m_lpr + 1)
else if (y == m_mb.vfldstp + m_mb.scroll_margin + 1 + m_mb.lpr + 1)
{
// todo: check ca
// check ca latch
if (m_ca_latch)
attention();
// frame interrupt?
if ((screen().frame_number() % m_frame_int_count) == 0)
if ((screen().frame_number() % m_mb.frame_int_count) == 0)
m_status |= EONF;
// check interrupts
@ -471,16 +772,27 @@ TIMER_CALLBACK_MEMBER( i82730_device::row_update )
// vblank
}
m_row_timer->adjust(screen().time_until_pos((y + 1) % screen().height()));
// schedule next line (if enabled)
if (m_status & DIP)
m_row_timer->adjust(screen().time_until_pos((y + 1) % screen().height()));
}
void i82730_device::attention()
{
execute_command();
m_ca_latch = false;
}
WRITE_LINE_MEMBER( i82730_device::ca_w )
{
if (VERBOSE)
logerror("%s('%s'): ca_w %d\n", shortname(), basetag(), state);
// falling edge
if (m_ca == 1 && state == 0)
m_ca_latch = true;
m_ca = state;
// check ca every cycle if the display isn't active
if (m_ca_latch && ((m_status & DIP) == 0))
{
if (!m_initialized)
{
@ -490,6 +802,8 @@ WRITE_LINE_MEMBER( i82730_device::ca_w )
// get intermediate block pointer
m_ibp = (read_word(0xfffffffe) << 16) | read_word(0xfffffffc);
m_cbp = (read_word(m_ibp + 4) << 16) | read_word(m_ibp + 2);
// get system configuration byte
uint8_t scb = read_byte(m_ibp + 6);
@ -511,26 +825,17 @@ WRITE_LINE_MEMBER( i82730_device::ca_w )
}
}
// fetch command block pointer
m_cbp = (read_word(m_ibp + 4) << 16) | read_word(m_ibp + 2);
// and execute command
execute_command();
attention();
}
m_ca = state;
}
WRITE_LINE_MEMBER( i82730_device::irst_w )
{
if (VERBOSE)
logerror("%s('%s'): irst_w %d\n", shortname(), basetag(), state);
m_sint_handler(0);
}
uint32_t i82730_device::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect)
{
copybitmap(bitmap, m_bitmap, 0, 0, m_hfldstrt * 16, 0, cliprect);
copybitmap(bitmap, m_bitmap, 0, 0, m_mb.hfldstrt * 16, 0, cliprect);
return 0;
}

View File

@ -66,8 +66,6 @@ private:
VDIP = 0x100 // virtual display in progress
};
static const char *const s_command_names[];
bool sysbus_16bit() { return BIT(m_sysbus, 0); }
uint8_t read_byte(offs_t address);
@ -78,7 +76,28 @@ private:
void update_interrupts();
void mode_set();
void execute_command();
bool dscmd_endrow();
bool dscmd_eof();
bool dscmd_eol();
bool dscmd_fulrowdescrpt(uint8_t param);
bool dscmd_sl_scroll_strt(uint8_t param);
bool dscmd_sl_scroll_end(uint8_t param);
bool dscmd_tab_to(uint8_t param);
bool dscmd_max_dma_count(uint8_t param);
bool dscmd_endstrg();
bool dscmd_skip(uint8_t param);
bool dscmd_repeat(uint8_t param);
bool dscmd_sub_sup(uint8_t param);
bool dscmd_rpt_sub_sup(uint8_t param);
bool dscmd_set_gen_pur_attrib(uint8_t param);
bool dscmd_set_field_attrib();
bool dscmd_init_next_process();
bool execute_datastream_command(uint8_t command, uint8_t param);
void load_row();
void attention();
TIMER_CALLBACK_MEMBER(row_update);
@ -92,48 +111,99 @@ private:
bitmap_rgb32 m_bitmap;
// internal registers
bool m_initialized;
bool m_mode_set;
int m_ca;
bool m_ca_latch;
// internal registers
uint8_t m_sysbus;
uint32_t m_ibp;
uint32_t m_cbp;
uint16_t m_intmask;
uint16_t m_status;
uint32_t m_ibp; // intermediate block pointer
uint32_t m_cbp; // command block pointer
int m_list_switch;
int m_auto_line_feed;
bool m_list_switch;
bool m_auto_line_feed;
uint8_t m_max_dma_count;
uint32_t m_lptr;
uint16_t m_status;
uint16_t m_intmask;
uint32_t m_sptr;
int m_dma_burst_space;
int m_dma_burst_length;
// display parameters
int m_hfldstrt;
int m_margin;
int m_lpr;
uint16_t m_field_attribute_mask;
int m_vsyncstp;
int m_vfldstrt;
int m_vfldstp;
int m_frame_int_count;
// row buffers
struct row_buffer
struct modeset
{
uint16_t data[200];
int count;
};
// horizontal modes
uint8_t burst_length;
uint8_t burst_space;
uint8_t line_length;
uint8_t hsyncstp;
uint8_t hfldstrt;
uint8_t hfldstp;
uint8_t hbrdstrt;
uint8_t hbrdstp;
uint8_t scroll_margin;
// char row characteristics
bool rvv_row;
bool blk_row;
bool dbl_hgt;
bool wdef;
uint8_t lpr;
uint8_t nrmstrt;
uint8_t nrmstp;
uint8_t supstrt;
uint8_t supstp;
uint8_t substrt;
uint8_t substp;
uint8_t cur1strt;
uint8_t cur1stp;
uint8_t cur2strt;
uint8_t cur2stp;
uint8_t u2_line_sel;
uint8_t u1_line_sel;
uint16_t field_attribute_mask;
// vertical modes
uint16_t frame_length;
uint16_t vsyncstp;
uint16_t vfldstrt;
uint16_t vfldstp;
// blink control
uint8_t duty_cyc_cursor;
uint8_t cursor_blink;
uint8_t frame_int_count;
uint8_t duty_cyc_char;
uint8_t char_blink;
bool ile;
bool rfe;
bool bpol;
bool bue;
bool cr2_cd;
bool cr1_cd;
bool cr2_be;
bool cr1_be;
// atrribute bit selects
uint8_t reverse_video;
uint8_t blinking_char;
bool cr2_rvv;
bool cr1_rvv;
bool cr2_oe;
bool cr1_oe;
uint8_t abs_line_count;
uint8_t invisible_char;
uint8_t underline2;
uint8_t underline1;
} m_mb;
row_buffer m_row[2];
int m_row_index;
uint16_t m_row_buffer[2][200];
uint16_t *m_row; // pointer to currently active row buffer
uint8_t m_dma_count;
uint8_t m_row_count; // maximum 200
int m_row_index; // 0 or 1
struct cursor
{
uint8_t x;
uint8_t y;
} m_cursor[2];
};
// device type definition

View File

@ -6,9 +6,12 @@
TODO:
- Needs better I82730 emulation
- Sound
- Floppy I/O errors
- Many more things
Notes:
- Press SPACE during self-test for an extended menu
***************************************************************************/
#include "emu.h"
@ -28,6 +31,7 @@
#include "imagedev/cassette.h"
#include "imagedev/floppy.h"
#include "formats/rc759_dsk.h"
#include "emupal.h"
#include "screen.h"
#include "speaker.h"
@ -49,6 +53,7 @@ public:
m_nvram(*this, "nvram"),
m_ppi(*this, "ppi"),
m_txt(*this, "txt"),
m_palette(*this, "palette"),
m_cas(*this, "cas"),
m_isbx(*this, "isbx"),
m_speaker(*this, "speaker"),
@ -81,6 +86,7 @@ private:
required_device<nvram_device> m_nvram;
required_device<i8255_device> m_ppi;
required_device<i82730_device> m_txt;
required_device<palette_device> m_palette;
required_device<cassette_image_device> m_cas;
required_device<isbx_slot_device> m_isbx;
required_device<speaker_sound_device> m_speaker;
@ -181,7 +187,8 @@ void rc759_state::rc759_io(address_map &map)
map.unmap_value_high();
map(0x000, 0x003).mirror(0x0c).rw(m_pic, FUNC(pic8259_device::read), FUNC(pic8259_device::write)).umask16(0x00ff);
map(0x020, 0x020).r(m_kbd, FUNC(rc759_kbd_hle_device::read));
// map(0x056, 0x056)
map(0x056, 0x056).w(m_snd, FUNC(sn76494_device::write));
map(0x056, 0x057).nopr();
map(0x05a, 0x05a).w(FUNC(rc759_state::rtc_data_w));
map(0x05c, 0x05c).rw(FUNC(rc759_state::rtc_data_r), FUNC(rc759_state::rtc_addr_w));
// map(0x060, 0x06f).w(FUNC(rc759_state::crt_control_w)).umask16(0x00ff);
@ -264,6 +271,7 @@ void rc759_state::txt_irst_w(uint16_t data)
uint8_t rc759_state::palette_r(offs_t offset)
{
// not sure if it's possible to read back
logerror("palette_r(%02x)\n", offset);
return 0xff;
}
@ -271,6 +279,22 @@ uint8_t rc759_state::palette_r(offs_t offset)
void rc759_state::palette_w(offs_t offset, uint8_t data)
{
logerror("palette_w(%02x): %02x\n", offset, data);
// two colors/byte. format: IRGBIRGB
static constexpr uint8_t val[4] = { 0x00, 0x55, 0xaa, 0xff };
int r, g, b;
r = (BIT(data, 2) << 1) | BIT(data, 3);
g = (BIT(data, 1) << 1) | BIT(data, 3);
b = (BIT(data, 0) << 1) | BIT(data, 3);
m_palette->set_pen_color(offset * 2 + 0, rgb_t(val[r], val[g], val[b]));
r = (BIT(data, 6) << 1) | BIT(data, 7);
g = (BIT(data, 5) << 1) | BIT(data, 7);
b = (BIT(data, 4) << 1) | BIT(data, 7);
m_palette->set_pen_color(offset * 2 + 1, rgb_t(val[r], val[g], val[b]));
}
@ -598,6 +622,8 @@ void rc759_state::rc759(machine_config &config)
m_txt->set_update_row_callback(FUNC(rc759_state::txt_update_row));
m_txt->sint().set(m_pic, FUNC(pic8259_device::ir4_w));
PALETTE(config, m_palette).set_entries(64);
// sound
SPEAKER(config, "mono").front_center();
SPEAKER_SOUND(config, m_speaker).add_route(ALL_OUTPUTS, "mono", 0.50);