i8275: Moderate change to API and major expansion of configuration possibilities

- Change the "draw character" callback to pack all attribute flags in a single parameter. A bit enum is provided to facilitate unpacking the bits.
- Allow for configurations in which up to four CRTCs are attached to the same character clock and screen. The secondary CRTCs are not fully emulated with regard to timing and some output callbacks, but their character and attribute outputs may be merged with those of the primary screen through the same display callback.

* wy100: Add half-intensity display for protected characters.
* ms6102: Support attribute that enables Cyrillic character set.
* t7000: Show cursor and several character attributes.

Machines promoted to WORKING
----------------------------
WY-100 [AJR]
This commit is contained in:
AJR 2024-01-27 12:17:40 -05:00
parent 05b623dbe7
commit 1bd8bb35d6
28 changed files with 485 additions and 346 deletions

View File

@ -1,10 +1,25 @@
// license:BSD-3-Clause
// copyright-holders:Curt Coder
// copyright-holders:Curt Coder, AJR
/**********************************************************************
Intel 8275 Programmable CRT Controller
Intel 8276 Small Systems CRT Controller
This emulation allows up to four 8275 or 8276 CRTCs connected in
parallel and reading out their row buffers simultaneously. The
secondary CRTCs are assumed to use identical timings to the
primary CRTC and run in perfect sync with each other.
The features provided by 8276 are practically a subset of the
8275. Light pen input, line attributes, invisible character
attributes and DMA bursts are not supported on the 8276. Also,
the DRQ and _DACK pins are renamed BRDY (Buffer Ready) and _BS
(Buffer Select), and the latter must be asserted coincident
with _WR (but not _CS). (Even in systems without a DMAC, the
processor usually does not write to the row buffer directly,
but enables some pseudo-DMA mode which causes memory read
operations to transmit data to the CRTC in the same cycle.)
**********************************************************************/
/*
@ -31,46 +46,6 @@
//**************************************************************************
static const int DMA_BURST_SPACING[] = { 0, 7, 15, 23, 31, 39, 47, 55 };
#define DOUBLE_SPACED_ROWS \
BIT(m_param[REG_SCN1], 7)
#define CHARACTERS_PER_ROW \
((m_param[REG_SCN1] & 0x7f) + 1)
#define VRTC_ROW_COUNT \
((m_param[REG_SCN2] >> 6) + 1)
#define CHARACTER_ROWS_PER_FRAME \
((m_param[REG_SCN2] & 0x3f) + 1)
#define UNDERLINE \
(m_param[REG_SCN3] >> 4)
#define SCANLINES_PER_ROW \
((m_param[REG_SCN3] & 0x0f) + 1)
#define OFFSET_LINE_COUNTER \
BIT(m_param[REG_SCN4], 7)
#define VISIBLE_FIELD_ATTRIBUTE \
BIT(m_param[REG_SCN4], 6)
#define CURSOR_FORMAT \
((m_param[REG_SCN4] >> 4) & 0x03)
#define HRTC_COUNT \
(((m_param[REG_SCN4] & 0x0f) + 1) * 2)
#define DMA_BURST_COUNT \
(1 << (m_param[REG_DMA] & 0x03))
#define DMA_BURST_SPACE \
DMA_BURST_SPACING[(m_param[REG_DMA] >> 2) & 0x07]
const int i8275_device::character_attribute[3][16] =
{
{ 2, 2, 4, 4, 2, 4, 4, 4, 2, 4, 4, 0, 2, 0, 0, 0 },
@ -108,11 +83,14 @@ i8275_device::i8275_device(const machine_config &mconfig, device_type type, cons
m_write_lc(*this),
m_display_cb(*this),
m_refresh_hack(false),
m_next_crtc(*this, finder_base::DUMMY_TAG),
m_is_crtc0(true),
m_status(0),
m_param_idx(0),
m_param_end(0),
m_buffer_idx(0),
m_fifo_idx(0),
m_fifo_idx_out(0),
m_dma_idx(0),
m_dma_last_char(0),
m_buffer_dma(0),
@ -140,22 +118,32 @@ i8276_device::i8276_device(const machine_config &mconfig, const char *tag, devic
}
void i8275_device::device_resolve_objects()
{
if (m_next_crtc.found())
m_next_crtc->m_is_crtc0 = false;
}
//-------------------------------------------------
// device_start - device-specific startup
//-------------------------------------------------
void i8275_device::device_start()
{
// get the screen device
screen().register_screen_bitmap(m_bitmap);
if (m_is_crtc0)
{
// get the screen device
screen().register_screen_bitmap(m_bitmap);
// resolve delegates
m_display_cb.resolve_safe();
// resolve delegates
m_display_cb.resolve_safe();
// allocate timers
m_hrtc_on_timer = timer_alloc(FUNC(i8275_device::hrtc_on), this);
m_drq_on_timer = timer_alloc(FUNC(i8275_device::drq_on), this);
m_scanline_timer = timer_alloc(FUNC(i8275_device::scanline_tick), this);
// allocate timers
m_hrtc_on_timer = timer_alloc(FUNC(i8275_device::hrtc_on), this);
m_drq_on_timer = timer_alloc(FUNC(i8275_device::drq_on), this);
m_scanline_timer = timer_alloc(FUNC(i8275_device::scanline_tick), this);
}
// state saving
save_item(NAME(m_status));
@ -164,6 +152,8 @@ void i8275_device::device_start()
save_item(NAME(m_param_end));
save_item(NAME(m_buffer[0]));
save_item(NAME(m_buffer[1]));
save_item(NAME(m_fifo[0]));
save_item(NAME(m_fifo[1]));
save_item(NAME(m_buffer_idx));
save_item(NAME(m_fifo_idx));
save_item(NAME(m_dma_idx));
@ -205,16 +195,13 @@ void i8275_device::device_reset()
void i8275_device::vrtc_start()
{
//LOG("I8275 y %u x %u VRTC 1\n", y, x);
m_write_vrtc(1);
// reset field attributes
m_field_attr = 0;
// Intel datasheets imply DMA requests begin only after a "Start Display" command is issued.
// WY-100, however, expects a BRDY cycle from the 8276 after the program first configures and stops the display.
// This suggests that DMA bursts proceed as normal in this case, but any characters sent will not be displayed.
m_buffer_idx = CHARACTERS_PER_ROW;
m_buffer_idx = characters_per_row();
m_dma_stop = false;
m_end_of_screen = !(m_status & ST_VE);
@ -250,7 +237,8 @@ void i8275_device::dma_start()
m_dma_idx = 0;
m_dma_last_char = 0;
m_drq_on_timer->adjust(clocks_to_attotime(DMA_BURST_SPACE));
if (m_is_crtc0)
m_drq_on_timer->adjust(clocks_to_attotime(dma_burst_space()));
}
@ -270,10 +258,10 @@ TIMER_CALLBACK_MEMBER(i8275_device::drq_on)
TIMER_CALLBACK_MEMBER(i8275_device::scanline_tick)
{
int rc = m_scanline / SCANLINES_PER_ROW;
int lc = m_scanline % SCANLINES_PER_ROW;
int rc = m_scanline / scanlines_per_row();
int lc = m_scanline % scanlines_per_row();
int line_counter = OFFSET_LINE_COUNTER ? ((lc - 1) % SCANLINES_PER_ROW) : lc;
int line_counter = offset_line_counter() ? ((lc - 1) % scanlines_per_row()) : lc;
m_write_lc(line_counter);
m_write_hrtc(0);
@ -282,170 +270,214 @@ TIMER_CALLBACK_MEMBER(i8275_device::scanline_tick)
if (lc == 0 && m_scanline < m_vrtc_scanline)
{
if (!m_dma_stop && m_buffer_idx < CHARACTERS_PER_ROW)
for (i8275_device *crtc = this; crtc != nullptr; crtc = crtc->m_next_crtc)
{
m_status |= ST_DU;
m_dma_stop = true;
if (!crtc->m_dma_stop && crtc->m_buffer_idx < characters_per_row())
{
crtc->m_status |= ST_DU;
crtc->m_dma_stop = true;
// blank screen until after VRTC
m_end_of_screen = true;
// blank screen until after VRTC
crtc->m_end_of_screen = true;
m_write_drq(0);
}
crtc->m_write_drq(0);
}
if (!m_dma_stop)
{
// swap line buffers
m_buffer_dma = !m_buffer_dma;
if (!crtc->m_dma_stop)
{
// swap line buffers
crtc->m_buffer_dma = !crtc->m_buffer_dma;
if (m_scanline < (m_vrtc_scanline - SCANLINES_PER_ROW))
dma_start();
if (m_scanline < (m_vrtc_scanline - scanlines_per_row()))
crtc->dma_start();
}
}
}
if ((m_status & ST_IE) && !(m_status & ST_IR) && m_scanline == m_irq_scanline)
if (m_scanline == m_irq_scanline)
{
m_status |= ST_IR;
m_write_irq(ASSERT_LINE);
for (i8275_device *crtc = this; crtc != nullptr; crtc = crtc->m_next_crtc)
{
if ((crtc->m_status & ST_IE) && !(crtc->m_status & ST_IR))
{
crtc->m_status |= ST_IR;
crtc->m_write_irq(ASSERT_LINE);
}
}
}
if (m_scanline == m_vrtc_scanline)
vrtc_start();
if (!m_dma_stop && m_scanline == m_vrtc_drq_scanline)
{
// swap line buffers
m_buffer_dma = !m_buffer_dma;
//LOG("I8275 y %u x %u VRTC 1\n", y, x);
m_write_vrtc(1);
// start DMA burst
dma_start();
for (i8275_device *crtc = this; crtc != nullptr; crtc = crtc->m_next_crtc)
crtc->vrtc_start();
}
if ((m_status & ST_VE) && m_scanline < m_vrtc_scanline)
if (m_scanline == m_vrtc_drq_scanline)
{
bool end_of_row = false;
bool blank_row = (UNDERLINE >= 8) && ((lc == 0) || (lc == SCANLINES_PER_ROW - 1));
int fifo_idx = 0;
m_field_attr = m_stored_attr;
for (int sx = 0; sx < CHARACTERS_PER_ROW; sx++)
for (i8275_device *crtc = this; crtc != nullptr; crtc = crtc->m_next_crtc)
{
int lineattr = 0;
uint8_t data = (end_of_row || m_end_of_screen) ? 0 : m_buffer[!m_buffer_dma][sx];
uint8_t attr = m_field_attr;
if ((data & 0xc0) == 0x80)
if (!crtc->m_dma_stop)
{
// field attribute code
m_field_attr = data & (FAC_H | FAC_B | FAC_GG | FAC_R | FAC_U);
// swap line buffers
crtc->m_buffer_dma = !crtc->m_buffer_dma;
if (!VISIBLE_FIELD_ATTRIBUTE)
{
attr = m_field_attr;
data = m_fifo[!m_buffer_dma][fifo_idx];
fifo_idx++;
fifo_idx &= 0xf;
if (blank_row)
attr |= FAC_B;
else if (!(m_char_blink < 32))
attr &= ~FAC_B;
if (lc != UNDERLINE)
attr &= ~FAC_U;
}
else
{
// simply blank the attribute character itself
attr = FAC_B;
}
// start DMA burst
crtc->dma_start();
}
else if (data >= 0xf0 || end_of_row || m_end_of_screen)
{
// special control character
switch (data)
{
case SCC_END_OF_ROW:
case SCC_END_OF_ROW_DMA:
end_of_row = true;
break;
}
}
case SCC_END_OF_SCREEN:
case SCC_END_OF_SCREEN_DMA:
m_end_of_screen = true;
break;
}
attr = FAC_B;
if (m_scanline < m_vrtc_scanline)
{
int end_of_row = 0;
int blank_row = 0;
{
int n = 0;
for (i8275_device *crtc = this; crtc != nullptr; crtc = crtc->m_next_crtc, n++)
{
if (crtc->m_end_of_screen || !(m_status & ST_VE))
end_of_row |= 1 << n;
if ((crtc->underline() >= 8) && ((lc == 0) || (lc == scanlines_per_row() - 1)))
blank_row |= 1 << n;
crtc->m_fifo_idx_out = 0;
crtc->m_field_attr = crtc->m_stored_attr;
}
else if (data >= 0xc0)
}
for (int sx = 0; sx < characters_per_row(); sx++)
{
int n = 0;
uint32_t charcode = 0;
uint32_t attrcode = 0;
for (i8275_device *crtc = this; crtc != nullptr; crtc = crtc->m_next_crtc, n++)
{
// character attribute code
attr = data & (m_char_blink < 32 ? (CA_H | CA_B) : CA_H);
uint8_t ca;
int cccc = (data >> 2) & 0x0f;
if (lc < UNDERLINE)
{
ca = character_attribute[0][cccc];
}
else if (lc == UNDERLINE)
{
ca = character_attribute[1][cccc];
}
else
{
ca = character_attribute[2][cccc];
}
if (ca & CA_LTEN)
attr |= FAC_U;
if (ca & CA_VSP)
attr |= FAC_B;
lineattr = ca >> 2;
}
else
{
if (blank_row)
attr |= FAC_B;
else if (!(m_char_blink < 32))
attr &= ~FAC_B;
if (lc != UNDERLINE)
attr &= ~FAC_U;
}
if ((rc == m_param[REG_CUR_ROW]) && (sx == m_param[REG_CUR_COL]))
{
if ((CURSOR_FORMAT & 0x02) || (m_cursor_blink < 16))
{
if (CURSOR_FORMAT & 0x01)
attr |= (lc == UNDERLINE) ? FAC_U : 0;
else
attr ^= FAC_R;
}
auto [data, attr] = crtc->char_from_buffer(n, sx, rc, lc, end_of_row, blank_row);
charcode |= uint32_t(data) << (n * 8);
attrcode |= uint32_t(attr) << (n * 8);
}
m_display_cb(m_bitmap,
sx * m_hpixels_per_column, // x position on screen of starting point
m_scanline, // y position on screen
line_counter, // current line of char
(data & 0x7f), // char code to be displayed
lineattr, // line attribute code
(attr & FAC_U) ? 1 : 0, // light enable signal
(attr & FAC_R) ? 1 : 0, // reverse video signal
(attr & FAC_B) ? 1 : 0, // video suppression
(attr & FAC_GG) >> 2, // general purpose attribute code
(attr & FAC_H) ? 1 : 0 // highlight
);
charcode, // char code to be displayed
attrcode);
}
if ((SCANLINES_PER_ROW - lc) == 1)
m_stored_attr = m_field_attr;
if ((scanlines_per_row() - lc) == 1)
{
for (i8275_device *crtc = this; crtc != nullptr; crtc = crtc->m_next_crtc)
crtc->m_stored_attr = crtc->m_field_attr;
}
}
m_scanline++;
m_scanline %= ((CHARACTER_ROWS_PER_FRAME + VRTC_ROW_COUNT) * SCANLINES_PER_ROW);
m_scanline %= ((character_rows_per_frame() + vrtc_row_count()) * scanlines_per_row());
}
std::pair<uint8_t, uint8_t> i8275_device::char_from_buffer(int n, int sx, int rc, int lc, int &end_of_row, int blank_row)
{
uint8_t data = BIT(end_of_row, n) ? 0 : m_buffer[!m_buffer_dma][sx];
uint8_t attr = m_field_attr;
int lineattr = 0;
if ((data & 0xc0) == 0x80)
{
// field attribute code
m_field_attr = data & (FAC_H | FAC_B | FAC_GG | FAC_R | FAC_U);
if (!visible_field_attribute())
{
attr = m_field_attr;
data = m_fifo[!m_buffer_dma][m_fifo_idx_out];
m_fifo_idx_out++;
m_fifo_idx_out &= 0xf;
if (BIT(blank_row, n))
attr |= FAC_B;
else if (!(m_char_blink < 32))
attr &= ~FAC_B;
if (lc != underline())
attr &= ~FAC_U;
}
else
{
// simply blank the attribute character itself
attr = FAC_B;
}
}
else if (data >= 0xf0 || BIT(end_of_row, n))
{
// special control character
switch (data)
{
case SCC_END_OF_ROW:
case SCC_END_OF_ROW_DMA:
end_of_row |= 1 << n;
break;
case SCC_END_OF_SCREEN:
case SCC_END_OF_SCREEN_DMA:
m_end_of_screen = true;
break;
}
attr = FAC_B;
}
else if (data >= 0xc0)
{
// character attribute code
attr = data & (m_char_blink < 32 ? (CA_H | CA_B) : CA_H);
uint8_t ca;
int cccc = (data >> 2) & 0x0f;
if (lc < underline())
{
ca = character_attribute[0][cccc];
}
else if (lc == underline())
{
ca = character_attribute[1][cccc];
}
else
{
ca = character_attribute[2][cccc];
}
if (ca & CA_LTEN)
attr |= FAC_U;
if (ca & CA_VSP)
attr |= FAC_B;
lineattr = ca >> 2;
}
else
{
if (BIT(blank_row, n))
attr |= FAC_B;
else if (!(m_char_blink < 32))
attr &= ~FAC_B;
if (lc != underline())
attr &= ~FAC_U;
}
if ((rc == m_param[REG_CUR_ROW]) && (sx == m_param[REG_CUR_COL]))
{
if ((cursor_format() & 0x02) || (m_cursor_blink < 16))
{
if (cursor_format() & 0x01)
attr |= (lc == underline()) ? FAC_U : 0;
else
attr ^= FAC_R;
}
}
return std::make_pair(data & 0x7f, attr | lineattr << 6);
}
@ -508,12 +540,15 @@ void i8275_device::write(offs_t offset, uint8_t data)
*/
if (m_preset)
{
int hrtc_on_pos = CHARACTERS_PER_ROW * m_hpixels_per_column;
int hrtc_on_pos = characters_per_row() * m_hpixels_per_column;
m_preset = false;
m_hrtc_on_timer->adjust(screen().time_until_pos(screen().vpos(), hrtc_on_pos), 0, screen().scan_period());
m_scanline = m_vrtc_drq_scanline;
m_scanline_timer->adjust(screen().time_until_pos(m_vrtc_drq_scanline, 0), 0, screen().scan_period());
if (m_is_crtc0)
{
m_hrtc_on_timer->adjust(screen().time_until_pos(screen().vpos(), hrtc_on_pos), 0, screen().scan_period());
m_scanline_timer->adjust(screen().time_until_pos(m_vrtc_drq_scanline, 0), 0, screen().scan_period());
}
}
switch (data >> 5)
@ -532,7 +567,8 @@ void i8275_device::write(offs_t offset, uint8_t data)
LOG("I8275 IRQ 0\n");
m_write_irq(CLEAR_LINE);
m_write_drq(0);
m_drq_on_timer->adjust(attotime::never);
if (m_is_crtc0)
m_drq_on_timer->adjust(attotime::never);
m_dma_stop = true;
m_param_idx = REG_SCN1;
@ -546,7 +582,7 @@ void i8275_device::write(offs_t offset, uint8_t data)
*/
case CMD_START_DISPLAY:
m_param[REG_DMA] = data;
LOG("I8275 Start Display %u %u\n", DMA_BURST_COUNT, DMA_BURST_SPACE);
LOG("I8275 Start Display %u %u\n", dma_burst_count(), dma_burst_space());
m_dma_stop = false;
m_status |= (ST_IE | ST_VE);
break;
@ -585,8 +621,11 @@ void i8275_device::write(offs_t offset, uint8_t data)
case CMD_PRESET_COUNTERS:
LOG("I8275 Preset Counters\n");
m_preset = true;
m_scanline_timer->adjust(attotime::never);
m_hrtc_on_timer->adjust(attotime::never);
if (m_is_crtc0)
{
m_scanline_timer->adjust(attotime::never);
m_hrtc_on_timer->adjust(attotime::never);
}
break;
}
}
@ -614,7 +653,7 @@ void i8275_device::dack_w(uint8_t data)
m_write_drq(0);
if (!VISIBLE_FIELD_ATTRIBUTE && ((m_dma_last_char & 0xc0) == 0x80))
if (!visible_field_attribute() && ((m_dma_last_char & 0xc0) == 0x80))
{
if (m_fifo_idx == 16)
{
@ -627,7 +666,7 @@ void i8275_device::dack_w(uint8_t data)
data = 0;
}
else if (m_buffer_idx < CHARACTERS_PER_ROW)
else if (m_buffer_idx < characters_per_row())
{
m_buffer[m_buffer_dma][m_buffer_idx++] = data;
}
@ -638,27 +677,30 @@ void i8275_device::dack_w(uint8_t data)
{
case SCC_END_OF_ROW_DMA:
// stop DMA
m_buffer_idx = CHARACTERS_PER_ROW;
m_buffer_idx = characters_per_row();
break;
case SCC_END_OF_SCREEN_DMA:
m_dma_stop = true;
m_buffer_idx = CHARACTERS_PER_ROW;
m_buffer_idx = characters_per_row();
break;
default:
if (m_buffer_idx == CHARACTERS_PER_ROW)
if (m_is_crtc0)
{
// stop DMA
m_drq_on_timer->adjust(attotime::never);
}
else if (!(m_dma_idx % DMA_BURST_COUNT))
{
m_drq_on_timer->adjust(clocks_to_attotime(DMA_BURST_SPACE));
}
else
{
m_drq_on_timer->adjust(attotime::zero);
if (m_buffer_idx == characters_per_row())
{
// stop DMA
m_drq_on_timer->adjust(attotime::never);
}
else if (!(m_dma_idx % dma_burst_count()))
{
m_drq_on_timer->adjust(clocks_to_attotime(dma_burst_space()));
}
else
{
m_drq_on_timer->adjust(attotime::zero);
}
}
}
@ -675,7 +717,7 @@ void i8275_device::lpen_w(int state)
if (!m_lpen && state)
{
m_param[REG_LPEN_COL] = screen().hpos() / m_hpixels_per_column;
m_param[REG_LPEN_ROW] = screen().vpos() / SCANLINES_PER_ROW;
m_param[REG_LPEN_ROW] = screen().vpos() / scanlines_per_row();
m_status |= ST_LP;
}
@ -707,30 +749,33 @@ uint32_t i8275_device::screen_update(screen_device &screen, bitmap_rgb32 &bitmap
void i8275_device::recompute_parameters()
{
if (!m_is_crtc0)
return;
int y = screen().vpos();
int horiz_pix_total = (CHARACTERS_PER_ROW + HRTC_COUNT) * m_hpixels_per_column;
int vert_pix_total = (CHARACTER_ROWS_PER_FRAME + VRTC_ROW_COUNT) * SCANLINES_PER_ROW;
attotime refresh = clocks_to_attotime((CHARACTERS_PER_ROW + HRTC_COUNT) * vert_pix_total);
int max_visible_x = (CHARACTERS_PER_ROW * m_hpixels_per_column) - 1;
int max_visible_y = (CHARACTER_ROWS_PER_FRAME * SCANLINES_PER_ROW) - 1;
int horiz_pix_total = (characters_per_row() + hrtc_count()) * m_hpixels_per_column;
int vert_pix_total = (character_rows_per_frame() + vrtc_row_count()) * scanlines_per_row();
attotime refresh = clocks_to_attotime((characters_per_row() + hrtc_count()) * vert_pix_total);
int max_visible_x = (characters_per_row() * m_hpixels_per_column) - 1;
int max_visible_y = (character_rows_per_frame() * scanlines_per_row()) - 1;
LOG("width %u height %u max_x %u max_y %u refresh %f\n", horiz_pix_total, vert_pix_total, max_visible_x, max_visible_y, refresh.as_hz());
rectangle visarea(0, max_visible_x, 0, max_visible_y);
screen().configure(horiz_pix_total, vert_pix_total, visarea, (m_refresh_hack ? screen().frame_period() : refresh).as_attoseconds());
int hrtc_on_pos = CHARACTERS_PER_ROW * m_hpixels_per_column;
int hrtc_on_pos = characters_per_row() * m_hpixels_per_column;
m_hrtc_on_timer->adjust(screen().time_until_pos(y, hrtc_on_pos), 0, screen().scan_period());
m_irq_scanline = (CHARACTER_ROWS_PER_FRAME - 1) * SCANLINES_PER_ROW;
m_vrtc_scanline = CHARACTER_ROWS_PER_FRAME * SCANLINES_PER_ROW;
m_vrtc_drq_scanline = vert_pix_total - SCANLINES_PER_ROW;
m_irq_scanline = (character_rows_per_frame() - 1) * scanlines_per_row();
m_vrtc_scanline = character_rows_per_frame() * scanlines_per_row();
m_vrtc_drq_scanline = vert_pix_total - scanlines_per_row();
LOG("irq_y %u vrtc_y %u drq_y %u\n", m_irq_scanline, m_vrtc_scanline, m_vrtc_drq_scanline);
m_scanline = y;
m_scanline_timer->adjust(screen().time_until_pos((y + 1) % vert_pix_total, 0), 0, screen().scan_period());
if (DOUBLE_SPACED_ROWS) fatalerror("Double spaced rows not supported!");
if (double_spaced_rows()) fatalerror("Double spaced rows not supported!");
}

View File

@ -1,5 +1,5 @@
// license:BSD-3-Clause
// copyright-holders:Curt Coder
// copyright-holders:Curt Coder, AJR
/**********************************************************************
Intel 8275/8276 CRT Controller emulation
@ -41,7 +41,29 @@
// INTERFACE CONFIGURATION MACROS
//**************************************************************************
#define I8275_DRAW_CHARACTER_MEMBER(_name) void _name(bitmap_rgb32 &bitmap, int x, int y, uint8_t linecount, uint8_t charcode, uint8_t lineattr, uint8_t lten, uint8_t rvv, uint8_t vsp, uint8_t gpa, uint8_t hlgt)
#define I8275_DRAW_CHARACTER_MEMBER(_name) void _name(bitmap_rgb32 &bitmap, int x, int y, uint8_t linecount, uint32_t charcode, uint32_t attrcode)
//**************************************************************************
// CONSTANTS
//**************************************************************************
namespace i8275_attributes
{
// Each 8275 outputs eight attribute signals in parallel for each character.
// Except for LA1 and LA0, the bit assignments provided here match the encoding of character attributes.
enum
{
LA1 = 7, // line attribute code 1
LA0 = 6, // line attribute code 0
LTEN = 5, // light enable signal
RVV = 4, // reverse video signal
GPA1 = 3, // general purpose attribute code 1
GPA0 = 2, // general purpose attribute code 0
VSP = 1, // video suppression
HLGT = 0 // highlight
};
};
//**************************************************************************
@ -55,7 +77,7 @@ class i8275_device : public device_t,
public device_video_interface
{
public:
typedef device_delegate<void (bitmap_rgb32 &bitmap, int x, int y, uint8_t linecount, uint8_t charcode, uint8_t lineattr, uint8_t lten, uint8_t rvv, uint8_t vsp, uint8_t gpa, uint8_t hlgt)> draw_character_delegate;
typedef device_delegate<void (bitmap_rgb32 &bitmap, int x, int y, uint8_t linecount, uint32_t charcode, uint32_t attrcode)> draw_character_delegate;
// construction/destruction
i8275_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
@ -63,6 +85,7 @@ public:
void set_character_width(int value) { m_hpixels_per_column = value; }
void set_refresh_hack(bool hack) { m_refresh_hack = hack; }
template <typename... T> void set_display_callback(T &&... args) { m_display_cb.set(std::forward<T>(args)...); }
template <typename T> void set_next_crtc(T &&tag) { m_next_crtc.set_tag(std::forward<T>(tag)); }
auto drq_wr_callback() { return m_write_drq.bind(); }
auto irq_wr_callback() { return m_write_irq.bind(); }
@ -83,6 +106,7 @@ protected:
i8275_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock);
// device-level overrides
virtual void device_resolve_objects() override;
virtual void device_start() override;
virtual void device_reset() override;
@ -94,9 +118,24 @@ protected:
void vrtc_end();
void dma_start();
std::pair<uint8_t, uint8_t> char_from_buffer(int n, int sx, int rc, int lc, int &end_of_row, int blank_row);
void recompute_parameters();
enum
bool double_spaced_rows() const { return BIT(m_param[REG_SCN1], 7); }
uint8_t characters_per_row() const { return (m_param[REG_SCN1] & 0x7f) + 1; }
uint8_t vrtc_row_count() const { return (m_param[REG_SCN2] >> 6) + 1; }
uint8_t character_rows_per_frame() const { return (m_param[REG_SCN2] & 0x3f) + 1; }
uint8_t underline() const { return m_param[REG_SCN3] >> 4; }
uint8_t scanlines_per_row() const { return (m_param[REG_SCN3] & 0x0f) + 1; }
bool offset_line_counter() const { return BIT(m_param[REG_SCN4], 7); }
bool visible_field_attribute() const { return BIT(m_param[REG_SCN4], 6); }
uint8_t cursor_format() const { return (m_param[REG_SCN4] >> 4) & 0x03; }
uint8_t hrtc_count() const { return ((m_param[REG_SCN4] & 0x0f) + 1) * 2; }
uint8_t dma_burst_count() const { return 1 << (m_param[REG_DMA] & 0x03); }
uint8_t dma_burst_space() const { uint8_t sp = (m_param[REG_DMA] >> 2) & 0x07; return sp ? sp * 8 - 1 : 0; }
enum : uint8_t
{
ST_IE = 0x40,
ST_IR = 0x20,
@ -132,7 +171,7 @@ protected:
REG_DMA
};
enum
enum : uint8_t
{
CA_H = 0x01,
CA_B = 0x02,
@ -143,7 +182,7 @@ protected:
CA_LA1 = 0x08
};
enum
enum : uint8_t
{
SCC_END_OF_ROW = 0xf0,
SCC_END_OF_ROW_DMA = 0xf1,
@ -151,7 +190,7 @@ protected:
SCC_END_OF_SCREEN_DMA = 0xf3
};
enum
enum : uint8_t
{
FAC_H = 0x01,
FAC_B = 0x02,
@ -172,6 +211,9 @@ protected:
int m_hpixels_per_column;
bool m_refresh_hack;
optional_device<i8275_device> m_next_crtc;
bool m_is_crtc0;
bitmap_rgb32 m_bitmap;
uint8_t m_status;
@ -182,7 +224,8 @@ protected:
uint8_t m_buffer[2][80];
uint8_t m_fifo[2][16];
int m_buffer_idx;
int m_fifo_idx;
uint8_t m_fifo_idx;
uint8_t m_fifo_idx_out;
int m_dma_idx;
uint8_t m_dma_last_char;
int m_buffer_dma;

View File

@ -280,12 +280,14 @@ void microb_state::machine_start()
I8275_DRAW_CHARACTER_MEMBER(microb_state::draw_character)
{
u8 dots = lten ? 0xff : (vsp || linecount == 9) ? 0 : m_p_chargen[(charcode << 4) | linecount];
if (rvv)
using namespace i8275_attributes;
u8 dots = BIT(attrcode, LTEN) ? 0xff : (BIT(attrcode, VSP) || linecount == 9) ? 0 : m_p_chargen[(charcode << 4) | linecount];
if (BIT(attrcode, RVV))
dots ^= 0xff;
// HLGT is active on status line
rgb_t const fg = hlgt ? rgb_t(0xc0, 0xc0, 0xc0) : rgb_t::white();
rgb_t const fg = BIT(attrcode, HLGT) ? rgb_t(0xc0, 0xc0, 0xc0) : rgb_t::white();
u32 *pix = &bitmap.pix(y, x);
for (int i = 0; i < 8; i++)

View File

@ -477,16 +477,17 @@ I8275_DRAW_CHARACTER_MEMBER(hp64k_state::crtc_display_pixels)
uint8_t chargen_byte = m_chargen[ linecount | ((unsigned)charcode << 4) ];
uint16_t pixels_lvid , pixels_livid;
if (vsp) {
using namespace i8275_attributes;
if (BIT(attrcode , VSP)) {
pixels_lvid = pixels_livid = ~0;
} else if (lten) {
} else if (BIT(attrcode , LTEN)) {
pixels_livid = ~0;
if (rvv) {
if (BIT(attrcode , RVV)) {
pixels_lvid = ~0;
} else {
pixels_lvid = 0;
}
} else if (rvv) {
} else if (BIT(attrcode , RVV)) {
pixels_lvid = ~0;
pixels_livid = (uint16_t)chargen_byte << 1;
} else {

View File

@ -337,9 +337,10 @@ I8275_DRAW_CHARACTER_MEMBER(imds2ioc_device::crtc_display_pixels)
uint8_t const chargen_byte = m_chargen[ (linecount & 7) | ((unsigned)charcode << 3) ];
uint16_t pixels;
if (lten) {
using namespace i8275_attributes;
if (BIT(attrcode, LTEN)) {
pixels = ~0;
} else if (vsp != 0 || (linecount & 8) != 0) {
} else if (BIT(attrcode, VSP) || (linecount & 8) != 0) {
pixels = 0; // VSP is gated with LC3
} else {
// See hardware ref. manual, pg 58 for the very peculiar way of generating character images
@ -373,7 +374,7 @@ I8275_DRAW_CHARACTER_MEMBER(imds2ioc_device::crtc_display_pixels)
pixels = exp_pix_l | exp_pix_r;
}
if (rvv) {
if (BIT(attrcode, RVV)) {
pixels = ~pixels;
}

View File

@ -98,15 +98,18 @@ I8275_DRAW_CHARACTER_MEMBER( ipds_state::crtc_display_pixels )
uint8_t *charmap = memregion("chargen")->base();
uint8_t pixels = charmap[(linecount & 7) + (charcode << 3)] ^ 0xff;
if (vsp)
using namespace i8275_attributes;
if (BIT(attrcode, VSP))
pixels = 0;
if (lten)
if (BIT(attrcode, LTEN))
pixels = 0xff;
if (rvv)
if (BIT(attrcode, RVV))
pixels ^= 0xff;
bool hlgt = BIT(attrcode, HLGT);
for(int i=0;i<6;i++)
bitmap.pix(y, x + i) = palette[(pixels >> (5-i)) & 1 ? (hlgt ? 2 : 1) : 0];
}

View File

@ -609,19 +609,18 @@ INPUT_PORTS_END
I8275_DRAW_CHARACTER_MEMBER(dwarfd_state::pesp_display_pixels)
{
int bank = ((gpa & 2) ? 0 : 2) + (gpa & 1);
using namespace i8275_attributes;
int bank = (BIT(attrcode, GPA1) ? 0 : 2) + (BIT(attrcode, GPA0) ? 1 : 0);
int palbank = (BIT(attrcode, RVV) ? 2 : 0) + (BIT(attrcode, VSP) ? 1 : 0);
const rgb_t *palette = m_palette->palette()->entry_list_raw();
uint16_t pixels = m_charmap[(linecount & 7) + ((charcode + (bank * 128)) << 3)];
if(!x)
m_back_color = false;
//if(!linecount)
// logerror("%d %d %02x %02x %02x %02x %02x %02x %02x\n", x/8, y/8, charcode, lineattr, lten, rvv, vsp, gpa, hlgt);
for (int i = 0; i < 8; i += 2)
{
uint8_t pixel = (pixels >> (i * 2)) & 0xf;
uint8_t value = (pixel >> 1) | (rvv << 4) | (vsp << 3);
uint8_t value = (pixel >> 1) | (palbank << 3);
bitmap.pix(y, x + i) = palette[value];
bitmap.pix(y, x + i + 1) = palette[(pixel & 1) ? 0 : value];
if(m_back_color)
@ -632,19 +631,18 @@ I8275_DRAW_CHARACTER_MEMBER(dwarfd_state::pesp_display_pixels)
I8275_DRAW_CHARACTER_MEMBER(dwarfd_state::display_pixels)
{
int bank = ((gpa & 2) ? 0 : 4) + (gpa & 1) + (m_dsw2->read() & 2);
using namespace i8275_attributes;
int bank = (BIT(attrcode, GPA1) ? 0 : 4) + (BIT(attrcode, GPA0) ? 1 : 0) + (m_dsw2->read() & 2);
int palbank = (BIT(attrcode, RVV) ? 2 : 0) + (BIT(attrcode, VSP) ? 1 : 0);
const rgb_t *palette = m_palette->palette()->entry_list_raw();
uint16_t pixels = m_charmap[(linecount & 7) + ((charcode + (bank * 128)) << 3)];
if(!x)
m_back_color = false;
//if(!linecount)
// logerror("%d %d %02x %02x %02x %02x %02x %02x %02x\n", x/8, y/8, charcode, lineattr, lten, rvv, vsp, gpa, hlgt);
for (int i = 0; i < 8; i += 2)
{
uint8_t pixel = (pixels >> (i * 2)) & 0xf;
uint8_t value = (pixel >> 1) | (rvv << 4) | (vsp << 3);
uint8_t value = (pixel >> 1) | (palbank << 3);
bitmap.pix(y, x + i) = palette[value];
bitmap.pix(y, x + i + 1) = palette[(pixel & 1) ? 0 : value];
if(m_back_color)
@ -655,19 +653,18 @@ I8275_DRAW_CHARACTER_MEMBER(dwarfd_state::display_pixels)
I8275_DRAW_CHARACTER_MEMBER(dwarfd_state::qc_display_pixels)
{
int bank = gpa;
using namespace i8275_attributes;
int bank = BIT(attrcode, GPA0, 2);
int palbank = (BIT(attrcode, RVV) ? 2 : 0) + (BIT(attrcode, VSP) ? 1 : 0);
const rgb_t *palette = m_palette->palette()->entry_list_raw();
uint16_t pixels = m_charmap[(linecount & 7) + ((charcode + (bank * 128)) << 3)];
if(!x)
m_back_color = false;
//if(!linecount)
// logerror("%d %d %02x %02x %02x %02x %02x %02x %02x\n", x/8, y/8, charcode, lineattr, lten, rvv, vsp, gpa, hlgt);
for (int i = 0; i < 8; i += 2)
{
uint8_t pixel = (pixels >> (i * 2)) & 0xf;
uint8_t value = (pixel >> 1) | (rvv << 4) | (vsp << 3);
uint8_t value = (pixel >> 1) | (palbank << 3);
bitmap.pix(y, x + i) = palette[value];
bitmap.pix(y, x + i + 1) = palette[(pixel & 1) ? 0 : value];
if(m_back_color)

View File

@ -14,14 +14,17 @@ I8275_DRAW_CHARACTER_MEMBER( mm1_state::crtc_display_pixels )
{
uint8_t romdata = m_char_rom->base()[(charcode << 4) | linecount];
int gpa0 = BIT(gpa, 0); // general purpose attribute 0
int llen = m_llen; // light enable
int compl_in = rvv; // reverse video
int hlt_in = hlgt; // highlight;
int color; // 0 = black, 1 = dk green, 2 = lt green; on MikroMikko 1, "highlight" is actually the darker shade of green
using namespace i8275_attributes;
bool vsp = BIT(attrcode, VSP);
bool lten = BIT(attrcode, LTEN);
bool gpa0 = BIT(attrcode, GPA0); // general purpose attribute 0
int llen = m_llen; // light enable
bool compl_in = BIT(attrcode, RVV); // reverse video
bool hlt_in = BIT(attrcode, HLGT); // highlight
int color; // 0 = black, 1 = dk green, 2 = lt green; on MikroMikko 1, "highlight" is actually the darker shade of green
int d7 = BIT(romdata, 7); // save MSB (1 indicates that this is a Visual Attribute or Special Code instead of a normal display character)
int d6 = BIT(romdata, 6); // save also first and last char bitmap bits before shifting out the MSB
int d7 = BIT(romdata, 7); // save MSB (1 indicates that this is a Visual Attribute or Special Code instead of a normal display character)
int d6 = BIT(romdata, 6); // save also first and last char bitmap bits before shifting out the MSB
int d0 = BIT(romdata, 0);
uint8_t data = (romdata << 1) | (d7 & d0); // get rid of MSB, duplicate LSB for special characters

View File

@ -273,13 +273,15 @@ I8275_DRAW_CHARACTER_MEMBER( rc702_state::display_pixels )
const rgb_t *palette = m_palette->palette()->entry_list_raw();
uint8_t gfx = 0;
if (!vsp)
using namespace i8275_attributes;
if (!BIT(attrcode, VSP))
gfx = m_p_chargen[(linecount & 15) | (charcode << 4)];
if (lten)
if (BIT(attrcode, LTEN))
gfx = 0xff;
if (rvv)
if (BIT(attrcode, RVV))
gfx ^= 0xff;
// Highlight not used

View File

@ -423,15 +423,18 @@ void rt1715_state::crtc_drq_w(int state)
I8275_DRAW_CHARACTER_MEMBER(rt1715_state::crtc_display_pixels)
{
using namespace i8275_attributes;
rgb_t const *const palette = m_palette->palette()->entry_list_raw();
u8 gfx = (lten) ? 0xff : 0;
u8 gfx = BIT(attrcode, LTEN) ? 0xff : 0;
if (!vsp)
gfx = m_p_chargen[((gpa & 1) << 11) | (linecount << 7) | charcode];
if (!BIT(attrcode, VSP))
gfx = m_p_chargen[(BIT(attrcode, GPA0) ? 0x800 : 0) | (linecount << 7) | charcode];
if (rvv)
if (BIT(attrcode, RVV))
gfx ^= 0xff;
bool hlgt = BIT(attrcode, HLGT);
for (u8 i=0; i<8; i++)
bitmap.pix(y, x + i) = palette[BIT(gfx, 7-i) ? (hlgt ? 2 : 1) : 0];
}

View File

@ -142,16 +142,18 @@ I8275_DRAW_CHARACTER_MEMBER( tim100_state::crtc_display_pixels )
rgb_t const *const palette = m_palette->palette()->entry_list_raw();
for (uint8_t i = 0; i < 2; i++)
{
using namespace i8275_attributes;
uint8_t pixels = m_charmap[(i * 0x1000) | (linecount & 15) | (charcode << 4)];
if (vsp)
if (BIT(attrcode, VSP))
pixels = 0;
if (lten)
if (BIT(attrcode, LTEN))
pixels = 0xff;
if (rvv)
if (BIT(attrcode, RVV))
pixels ^= 0xff;
bool hlgt = BIT(attrcode, HLGT);
bitmap.pix(y, x++) = palette[BIT(pixels, 7) ? (hlgt ? 2 : 1) : 0];
bitmap.pix(y, x++) = palette[BIT(pixels, 6) ? (hlgt ? 2 : 1) : 0];
bitmap.pix(y, x++) = palette[BIT(pixels, 5) ? (hlgt ? 2 : 1) : 0];

View File

@ -92,10 +92,12 @@ void grfd2301_state::vrtc_w(int state)
I8275_DRAW_CHARACTER_MEMBER(grfd2301_state::draw_character)
{
using namespace i8275_attributes;
// HACK: adjust for incorrect character generator
u8 lc = (linecount - 1) & 0x0f;
u8 gfx = lten ? 0xff : (vsp || lc > 8) ? 0 : m_p_chargen[(charcode << 4) | lc];
if (rvv)
u8 gfx = BIT(attrcode, LTEN) ? 0xff : (BIT(attrcode, VSP) || lc > 8) ? 0 : m_p_chargen[(charcode << 4) | lc];
if (BIT(attrcode, RVV))
gfx ^= 0xff;
for (int i = 8; --i >= 0; )
bitmap.pix(y, x++) = BIT(gfx, i) ? rgb_t::white() : rgb_t::black();

View File

@ -101,15 +101,16 @@ I8275_DRAW_CHARACTER_MEMBER(sagitta180_state::crtc_display_pixels)
uint8_t const chargen_byte = m_chargen[ (linecount & 7) | ((unsigned)charcode << 3) ];
uint8_t pixels;
if (lten) {
using namespace i8275_attributes;
if (BIT(attrcode, LTEN)) {
pixels = ~0;
} else if (vsp != 0 || (linecount & 8) != 0) {
} else if (BIT(attrcode, VSP) || (linecount & 8) != 0) {
pixels = 0;
} else {
pixels = chargen_byte;
}
if (rvv) {
if (BIT(attrcode, RVV)) {
pixels = ~pixels;
}

View File

@ -105,8 +105,9 @@ void systel1_state::memory_w(offs_t offset, u8 data)
I8275_DRAW_CHARACTER_MEMBER(systel1_state::draw_character)
{
u8 dots = lten ? 0xff : vsp ? 0 : m_chargen[(charcode << 4) | linecount];
if (rvv)
using namespace i8275_attributes;
u8 dots = BIT(attrcode, LTEN) ? 0xff : BIT(attrcode, VSP) ? 0 : m_chargen[(charcode << 4) | linecount];
if (BIT(attrcode, RVV))
dots ^= 0xff;
for (int i = 0; i < 7; i++)

View File

@ -141,15 +141,18 @@ I8275_DRAW_CHARACTER_MEMBER(unistar_state::draw_character)
rgb_t const *const palette = m_palette->palette()->entry_list_raw();
u8 gfx = m_chargen[(linecount & 15) | (charcode << 4)];
if (vsp)
using namespace i8275_attributes;
if (BIT(attrcode, VSP))
gfx = 0;
if (lten)
if (BIT(attrcode, LTEN))
gfx = 0xff;
if (rvv)
if (BIT(attrcode, RVV))
gfx ^= 0xff;
bool hlgt = BIT(attrcode, HLGT);
for(u8 i=0;i<8;i++)
bitmap.pix(y, x + i) = palette[BIT(gfx, 7-i) ? (hlgt ? 2 : 1) : 0];
}

View File

@ -612,18 +612,20 @@ I8275_DRAW_CHARACTER_MEMBER( zorba_state::zorba_update_chr )
{
rgb_t const *const palette = m_palette->palette()->entry_list_raw();
uint8_t gfx = m_p_chargen[(linecount & 15) + (charcode << 4) + ((gpa & 1) << 11)];
using namespace i8275_attributes;
uint8_t gfx = m_p_chargen[(linecount & 15) + (charcode << 4) + (BIT(attrcode, GPA0) ? 0x800 : 0)];
if (rvv)
if (BIT(attrcode, RVV))
gfx ^= 0xff;
// VSP actually overrides reverse video here
if (vsp)
if (BIT(attrcode, VSP))
gfx = 0;
if (lten)
if (BIT(attrcode, LTEN))
gfx = 0xff;
bool hlgt = BIT(attrcode, HLGT);
for (int i = 0; i < 8; i++)
bitmap.pix(y, x + 7 - i) = palette[BIT(gfx, i) ? (hlgt ? 2 : 1) : 0];
}

View File

@ -335,18 +335,19 @@ I8275_DRAW_CHARACTER_MEMBER( trs80dt1_state::crtc_update_row )
rgb_t const *const palette = m_palette->palette()->entry_list_raw();
u8 gfx = 0;
if (lten) // underline attr
using namespace i8275_attributes;
if (BIT(attrcode, LTEN)) // underline attr
gfx = 0xff;
else
if ((gpa | vsp)==0) // blinking and invisible attributes
else if (BIT(attrcode, GPA0, 2) == 0 && !BIT(attrcode, VSP)) // blinking and invisible attributes
gfx = m_p_chargen[linecount | (charcode << 4)];
if (rvv) // reverse video attr
if (BIT(attrcode, RVV)) // reverse video attr
gfx ^= 0xff;
if (m_bow) // black-on-white
gfx ^= 0xff;
bool hlgt = BIT(attrcode, HLGT);
for(u8 i=0; i<8; i++)
bitmap.pix(y, x + i) = palette[BIT(gfx, 7-i) ? (hlgt ? 2 : 1) : 0];
}

View File

@ -208,18 +208,20 @@ void apogee_state::machine_start()
I8275_DRAW_CHARACTER_MEMBER(apogee_state::display_pixels)
{
using namespace i8275_attributes;
rgb_t const *const palette = m_palette->palette()->entry_list_raw();
uint8_t const *const charmap = &m_chargen[(gpa & 1) * 0x400];
uint8_t const *const charmap = &m_chargen[BIT(attrcode, GPA0) ? 0x400 : 0];
uint8_t pixels = charmap[(linecount & 7) + (charcode << 3)] ^ 0xff;
if (vsp)
if (BIT(attrcode, VSP))
pixels = 0;
if (lten)
if (BIT(attrcode, LTEN))
pixels = 0xff;
if (rvv)
if (BIT(attrcode, RVV))
pixels ^= 0xff;
bool hlgt = BIT(attrcode, HLGT);
for(int i=0;i<6;i++)
bitmap.pix(y, x + i) = palette[(pixels >> (5-i)) & 1 ? (hlgt ? 2 : 1) : 0];
}

View File

@ -257,19 +257,22 @@ I8275_DRAW_CHARACTER_MEMBER(argo_state::display_pixels)
const rgb_t *palette = m_palette->palette()->entry_list_raw();
u8 gfx = m_p_chargen[(linecount & 15) | (charcode << 4)];
if (vsp)
using namespace i8275_attributes;
if (BIT(attrcode, VSP))
gfx = 0;
if (lten)
if (BIT(attrcode, LTEN))
{
gfx = 0xff;
if (x > 6)
x-=6; // hack to fix cursor position
}
if (rvv)
if (BIT(attrcode, RVV))
gfx ^= 0xff;
bool hlgt = BIT(attrcode, HLGT);
for(u8 i=0;i<7;i++)
bitmap.pix(y, x + i) = palette[BIT(gfx, 6-i) ? (hlgt ? 2 : 1) : 0];
}

View File

@ -181,18 +181,21 @@ void mikrosha_state::machine_start()
I8275_DRAW_CHARACTER_MEMBER(mikrosha_state::display_pixels)
{
using namespace i8275_attributes;
rgb_t const *const palette = m_palette->palette()->entry_list_raw();
uint8_t const *const charmap = &m_chargen[(m_mikrosha_font_page & 1) * 0x400];
uint8_t pixels = charmap[(linecount & 7) + (charcode << 3)] ^ 0xff;
if (vsp)
if (BIT(attrcode, VSP))
pixels = 0;
if (lten)
if (BIT(attrcode, LTEN))
pixels = 0xff;
if (rvv)
if (BIT(attrcode, RVV))
pixels ^= 0xff;
bool hlgt = BIT(attrcode, HLGT);
for(int i=0;i<6;i++)
bitmap.pix(y, x + i) = palette[(pixels >> (5-i)) & 1 ? (hlgt ? 2 : 1) : 0];
}

View File

@ -93,7 +93,6 @@ private:
template <unsigned N> void irq(int state) { m_pic->r_w(N, state ? 0 : 1); }
I8275_DRAW_CHARACTER_MEMBER(display_pixels);
I8275_DRAW_CHARACTER_MEMBER(display_attr);
void hrq_w(int state);
void irq_w(int state);
@ -188,22 +187,21 @@ u8 ms6102_state::memory_read_byte(offs_t offset)
I8275_DRAW_CHARACTER_MEMBER(ms6102_state::display_pixels)
{
rgb_t const *const palette = m_palette->palette()->entry_list_raw();
u8 gfx = (lten) ? 0xff : 0;
if (!vsp)
gfx = m_p_chargen[linecount | (charcode << 4)];
using namespace i8275_attributes;
if (rvv)
rgb_t const *const palette = m_palette->palette()->entry_list_raw();
u8 gfx = BIT(attrcode, LTEN) ? 0xff : 0;
if (!BIT(attrcode, VSP) && !BIT(attrcode, LTEN))
gfx = m_p_chargen[linecount | (charcode & 0x7f) << 4 | (BIT(attrcode, GPA0 + 8) ? 0x800 : 0)];
if (BIT(attrcode, RVV))
gfx ^= 0xff;
bool hlgt = BIT(attrcode, HLGT);
for(u8 i=0; i<8; i++)
bitmap.pix(y, x + i) = palette[BIT(gfx, 7-i) ? (hlgt ? 2 : 1) : 0];
}
I8275_DRAW_CHARACTER_MEMBER(ms6102_state::display_attr) // TODO: attributes
{
}
u8 ms6102_state::crtc_r(offs_t offset)
{
m_crtc2->read(offset);
@ -245,8 +243,7 @@ void ms6102_state::vdack_w(u8 data)
{
if(m_dmaaddr & 1)
m_crtc1->dack_w(data);
else
m_crtc2->dack_w(data | 0x80);
m_crtc2->dack_w(data | 0x80);
}
IRQ_CALLBACK_MEMBER(ms6102_state::ms6102_int_ack)
@ -279,6 +276,8 @@ void ms6102_state::machine_start()
{
const uint8_t *srcp = &m_p_chargen[0x1000 | bitswap<3>(m_p_charmap[i], 0, 1, 2) << 8 | (m_p_charmap[i] & 8) >> 1 | (i & 0x01) << 1];
uint8_t *dstp = &m_p_chargen[(i & 0x38) << 6 | (i & 0x07) << 1];
// copy a 2-line slice of a 32-character block
for (int j = 0; j < 0x20; j++)
std::copy_n(srcp + j * 8, 2, dstp + j * 16);
}
@ -316,10 +315,10 @@ void ms6102_state::ms6102(machine_config &config)
m_crtc1->set_display_callback(FUNC(ms6102_state::display_pixels));
m_crtc1->drq_wr_callback().set("dma8257", FUNC(i8257_device::dreq2_w));
m_crtc1->set_screen(m_screen);
m_crtc1->set_next_crtc(m_crtc2);
I8275(config, m_crtc2, XTAL(16'400'000) / 8);
m_crtc2->set_character_width(8);
m_crtc2->set_display_callback(FUNC(ms6102_state::display_attr));
m_crtc2->irq_wr_callback().set(FUNC(ms6102_state::irq<5>));
m_crtc2->set_screen(m_screen);

View File

@ -343,16 +343,17 @@ void partner_state::mem_page_w(u8 data)
I8275_DRAW_CHARACTER_MEMBER(partner_state::display_pixels)
{
using namespace i8275_attributes;
rgb_t const *const palette = m_palette->palette()->entry_list_raw();
u8 const *const charmap = &m_chargen[0x400 * (gpa * 2 + hlgt)];
u8 const *const charmap = &m_chargen[0x400 * bitswap<3>(attrcode, GPA1, GPA0, HLGT)];
u8 pixels = charmap[(linecount & 7) + (charcode << 3)] ^ 0xff;
if (vsp)
if (BIT(attrcode, VSP))
pixels = 0;
if (lten)
if (BIT(attrcode, LTEN))
pixels = 0xff;
if (rvv)
if (BIT(attrcode, RVV))
pixels ^= 0xff;
for (int i=0;i<6;i++)

View File

@ -206,17 +206,20 @@ void radio86_state::radio86_romdisk_portc_w(u8 data)
I8275_DRAW_CHARACTER_MEMBER(radio86_state::display_pixels)
{
using namespace i8275_attributes;
rgb_t const *const palette = m_palette->palette()->entry_list_raw();
u8 pixels = m_chargen[(linecount & 7) + (charcode << 3)] ^ 0xff;
if (vsp)
if (BIT(attrcode, VSP))
pixels = 0;
if (lten)
if (BIT(attrcode, LTEN))
pixels = 0xff;
if (rvv)
if (BIT(attrcode, RVV))
pixels ^= 0xff;
bool hlgt = BIT(attrcode, HLGT);
for (u8 i = 0; i < 6; i++)
bitmap.pix(y, x + i) = palette[(pixels >> (5-i)) & 1 ? (hlgt ? 2 : 1) : 0];
}

View File

@ -101,18 +101,21 @@ INTERRUPT_GEN_MEMBER(sm1800_state::vblank_interrupt)
I8275_DRAW_CHARACTER_MEMBER( sm1800_state::crtc_display_pixels )
{
using namespace i8275_attributes;
rgb_t const *const palette = m_palette->palette()->entry_list_raw();
uint8_t const *const charmap = memregion("chargen")->base();
uint8_t pixels = charmap[(linecount & 7) + (charcode << 3)] ^ 0xff;
if (vsp)
if (BIT(attrcode, VSP))
pixels = 0;
if (lten)
if (BIT(attrcode, LTEN))
pixels = 0xff;
if (rvv)
if (BIT(attrcode, RVV))
pixels ^= 0xff;
bool hlgt = BIT(attrcode, HLGT);
for(int i=0;i<8;i++)
bitmap.pix(y, x + i) = palette[(pixels >> (7-i)) & 1 ? (hlgt ? 2 : 1) : 0];
}

View File

@ -288,15 +288,18 @@ I8275_DRAW_CHARACTER_MEMBER(unior_state::display_pixels)
rgb_t const *const palette = m_palette->palette()->entry_list_raw();
u8 gfx = m_p_chargen[(linecount & 7) | (charcode << 3)];
if (vsp)
using namespace i8275_attributes;
if (BIT(attrcode, VSP))
gfx = 0;
if (lten)
if (BIT(attrcode, LTEN))
gfx = 0xff;
if (rvv)
if (BIT(attrcode, RVV))
gfx ^= 0xff;
bool hlgt = BIT(attrcode, HLGT);
for(u8 i=0;i<6;i++)
bitmap.pix(y, x + i) = palette[BIT(gfx, 5-i) ? (hlgt ? 2 : 1) : 0];
}

View File

@ -10,9 +10,7 @@
sets. Keytronic Model L2207 is the specified keyboard. Settings can be
saved to nonvolatile memory by typing "PERM" (all caps) in Set-Up mode.
Currently the cursor display and attributes are not provided due to
8276 emulation not supporting the dual configuration used here. The
optional touch panel is also not supported.
Currently the optional touch panel is not supported.
****************************************************************************/
@ -93,7 +91,18 @@ void t7000_state::machine_start()
I8275_DRAW_CHARACTER_MEMBER(t7000_state::display_character)
{
u16 dots = vsp ? 0 : m_chargen[(charcode << 4) | linecount];
// TODO: blinking and blanked characters
using namespace i8275_attributes;
u16 dots = 0;
if (!BIT(attrcode, VSP))
{
if (BIT(attrcode, LTEN + 8) || (BIT(charcode, 12) && linecount == 10))
dots = 0x3ff; // underscore
else
dots = m_chargen[(charcode & 0x7f) << 4 | linecount] << 1;
if (BIT(attrcode, RVV + 8) || BIT(charcode, 11))
dots ^= 0x3ff; // reverse video
}
rgb_t fg = rgb_t::white();
rgb_t bg = rgb_t::black();
@ -102,10 +111,12 @@ I8275_DRAW_CHARACTER_MEMBER(t7000_state::display_character)
using std::swap;
swap(fg, bg);
}
if (BIT(charcode, 8))
fg = rgb_t(0xc0, 0xc0, 0xc0); // reduced intensity
for (int i = 0; i < 10; i++)
{
bitmap.pix(y, x + i) = ((dots & 0x300) != 0) ? fg : bg;
bitmap.pix(y, x + i) = BIT(dots, 9) ? fg : bg;
dots <<= 1;
}
}
@ -239,6 +250,7 @@ void t7000_state::t7000(machine_config &config)
m_crtc[0]->drq_wr_callback().set("mainnmi", FUNC(input_merger_device::in_w<1>));
m_crtc[0]->vrtc_wr_callback().set(FUNC(t7000_state::vblint_w));
m_crtc[0]->set_screen("screen");
m_crtc[0]->set_next_crtc(m_crtc[1]);
I8276(config, m_crtc[1], 19.6608_MHz_XTAL / 10);
m_crtc[1]->set_character_width(10);

View File

@ -456,12 +456,13 @@ void wicat_state::crtc_irq_clear_w(int state)
I8275_DRAW_CHARACTER_MEMBER(wicat_state::wicat_display_pixels)
{
uint16_t romdata = lten ? 0x3ff : vsp ? 0 : m_chargen->base()[(charcode << 4) | linecount];
using namespace i8275_attributes;
uint16_t romdata = BIT(attrcode, LTEN) ? 0x3ff : BIT(attrcode, VSP) ? 0 : m_chargen->base()[(charcode << 4) | linecount];
pen_t const *const pen = m_palette->pens();
for (int i = 0; i < 10; i++)
{
int color = ((romdata & 0x300) != 0) ^ rvv;
int color = ((romdata & 0x300) != 0) ^ BIT(attrcode, RVV);
bitmap.pix(y, x + i) = pen[color];
romdata <<= 1;

View File

@ -2,17 +2,13 @@
// copyright-holders:AJR
/*******************************************************************************
Skeleton driver for Wyse WY-100 video terminal.
Driver for Wyse WY-100 video terminal.
The WY-100 was Wyse Technology's first product.
Of the two 8276 CRTCs, one is used solely to keep track of which characters
are protected, which is the only transparent attribute supported.
Known emulation bugs:
- Frequent screen glitches when writing to the display
- No dimming of protected characters
*******************************************************************************/
#include "emu.h"
@ -101,19 +97,19 @@ void wy100_state::brdy_w(int state)
I8275_DRAW_CHARACTER_MEMBER(wy100_state::draw_character)
{
// LTEN attribute output is not used (GPA1 generates underline instead)
using namespace i8275_attributes;
u8 dots = 0;
if (!vsp)
if (!BIT(attrcode, VSP))
{
if (BIT(gpa, 1) && (linecount & 0xb) == 0xa)
if (BIT(attrcode, GPA1) && (linecount & 0xb) == 0xa)
dots = 0xff;
else if (!BIT(gpa, 0))
dots = m_chargen[(charcode << 4) | linecount];
else if (!BIT(attrcode, GPA0))
dots = m_chargen[((charcode & 0x7f) << 4) | linecount];
}
if (rvv)
if (BIT(attrcode, RVV))
dots ^= 0xff;
// TODO: dim protected characters
const rgb_t fg = rgb_t::white();
const rgb_t fg = BIT(charcode, 8) && BIT(attrcode, HLGT) ? rgb_t::white() : rgb_t(0xc0, 0xc0, 0xc0);
const rgb_t bg = rgb_t::black();
for (int i = 0; i < 10; i++)
bitmap.pix(y, x + i) = BIT(dots, i < 1 || i > 8 ? 7 : 8 - i) ? fg : bg;
@ -277,6 +273,7 @@ void wy100_state::wy100(machine_config &config)
m_crtc[0]->drq_wr_callback().set_inputline(m_maincpu, MCS48_INPUT_IRQ);
m_crtc[0]->drq_wr_callback().append(FUNC(wy100_state::brdy_w));
m_crtc[0]->lc_wr_callback().set("spkrgate", FUNC(input_merger_device::in_w<1>)).bit(3);
m_crtc[0]->set_next_crtc(m_crtc[1]);
SPEAKER(config, "mono").front_center();
SPEAKER_SOUND(config, "speaker").add_route(ALL_OUTPUTS, "mono", 0.5);
@ -304,4 +301,4 @@ ROM_END
} // anonymous namespace
COMP(1981, wy100, 0, 0, wy100, wy100, wy100_state, empty_init, "Wyse Technology", "WY-100", MACHINE_NOT_WORKING | MACHINE_IMPERFECT_GRAPHICS)
COMP(1981, wy100, 0, 0, wy100, wy100, wy100_state, empty_init, "Wyse Technology", "WY-100", MACHINE_SUPPORTS_SAVE)