// license:BSD-3-Clause // copyright-holders:Curt Coder /***************************************************************************** * * video/abc806.c * ****************************************************************************/ /* TODO: - flashing - double height - underline */ #include "includes/abc80x.h" // these are needed because the MC6845 emulation does // not position the active display area correctly #define HORIZONTAL_PORCH_HACK 109 #define VERTICAL_PORCH_HACK 27 static const rgb_t PALETTE[] = { RGB_BLACK, // black MAKE_RGB(0xff, 0x00, 0x00), // red MAKE_RGB(0x00, 0xff, 0x00), // green MAKE_RGB(0xff, 0xff, 0x00), // yellow MAKE_RGB(0x00, 0x00, 0xff), // blue MAKE_RGB(0xff, 0x00, 0xff), // magenta MAKE_RGB(0x00, 0xff, 0xff), // cyan RGB_WHITE // white }; //------------------------------------------------- // hrs_w - high resolution memory banking //------------------------------------------------- WRITE8_MEMBER( abc806_state::hrs_w ) { /* bit signal description 0 VM14 visible screen memory area bit 0 1 VM15 visible screen memory area bit 1 2 VM16 visible screen memory area bit 2 3 VM17 visible screen memory area bit 3 4 F14 cpu accessible screen memory area bit 0 5 F15 cpu accessible screen memory area bit 1 6 F16 cpu accessible screen memory area bit 2 7 F17 cpu accessible screen memory area bit 3 */ m_hrs = data; } //------------------------------------------------- // hrc_w - high resolution color write //------------------------------------------------- WRITE8_MEMBER( abc806_state::hrc_w ) { int reg = (offset >> 8) & 0x0f; m_hrc[reg] = data; } //------------------------------------------------- // charram_r - character RAM read //------------------------------------------------- READ8_MEMBER( abc806_state::charram_r ) { m_attr_data = m_color_ram[offset]; return m_char_ram[offset]; } //------------------------------------------------- // charram_w - character RAM write //------------------------------------------------- WRITE8_MEMBER( abc806_state::charram_w ) { m_color_ram[offset] = m_attr_data; m_char_ram[offset] = data; } //------------------------------------------------- // ami_r - attribute memory read //------------------------------------------------- READ8_MEMBER( abc806_state::ami_r ) { return m_attr_data; } //------------------------------------------------- // amo_w - attribute memory write //------------------------------------------------- WRITE8_MEMBER( abc806_state::amo_w ) { m_attr_data = data; } //------------------------------------------------- // cli_r - palette PROM read //------------------------------------------------- READ8_MEMBER( abc806_state::cli_r ) { /* bit description 0 HRU II data bit 0 1 HRU II data bit 1 2 HRU II data bit 2 3 HRU II data bit 3 4 5 6 7 RTC data output */ UINT16 hru2_addr = (m_hru2_a8 << 8) | (offset >> 8); UINT8 data = m_hru2_prom->base()[hru2_addr] & 0x0f; logerror("HRU II %03x : %01x\n", hru2_addr, data); data |= m_rtc->dio_r() << 7; return data; } //------------------------------------------------- // sti_r - protection device read //------------------------------------------------- READ8_MEMBER( abc806_state::sti_r ) { /* bit description 0 1 2 3 4 5 6 7 PROT DOUT */ return 0x7f; } //------------------------------------------------- // sto_w - //------------------------------------------------- WRITE8_MEMBER( abc806_state::sto_w ) { int level = BIT(data, 7); switch (data & 0x07) { case 0: // external memory enable m_eme = level; break; case 1: // 40/80 column display m_40 = level; break; case 2: // HRU II address line 8, PROT A0 m_hru2_a8 = level; break; case 3: // PROT INI break; case 4: // text display enable m_txoff = level; break; case 5: // RTC chip select m_rtc->cs_w(!level); break; case 6: // RTC clock m_rtc->clk_w(level); break; case 7: // RTC data in, PROT DIN m_rtc->dio_w(level); break; } } //------------------------------------------------- // sso_w - sync offset write //------------------------------------------------- WRITE8_MEMBER( abc806_state::sso_w ) { m_sync = data & 0x3f; } //------------------------------------------------- // MC6845_UPDATE_ROW( abc806_update_row ) //------------------------------------------------- static MC6845_UPDATE_ROW( abc806_update_row ) { abc806_state *state = device->machine().driver_data(); // UINT8 old_data = 0xff; int fg_color = 7; int bg_color = 0; int underline = 0; int flash = 0; int e5 = state->m_40; int e6 = state->m_40; int th = 0; // prevent wraparound if (y >= 240) return; y += state->m_sync + VERTICAL_PORCH_HACK; for (int column = 0; column < x_count; column++) { UINT8 data = state->m_char_ram[(ma + column) & 0x7ff]; UINT8 attr = state->m_color_ram[(ma + column) & 0x7ff]; UINT16 rad_addr; UINT8 rad_data; if ((attr & 0x07) == ((attr >> 3) & 0x07)) { // special case switch (attr >> 6) { case 0: // use previously selected attributes break; case 1: // reserved for future use break; case 2: // blank fg_color = 0; bg_color = 0; underline = 0; flash = 0; break; case 3: // double width e5 = BIT(attr, 0); e6 = BIT(attr, 1); // read attributes from next byte attr = state->m_color_ram[(ma + column + 1) & 0x7ff]; if (attr != 0x00) { fg_color = attr & 0x07; bg_color = (attr >> 3) & 0x07; underline = BIT(attr, 6); flash = BIT(attr, 7); } break; } } else { // normal case fg_color = attr & 0x07; bg_color = (attr >> 3) & 0x07; underline = BIT(attr, 6); flash = BIT(attr, 7); e5 = state->m_40; e6 = state->m_40; } if (column == cursor_x) { rad_data = 0x0f; } else { rad_addr = (e6 << 8) | (e5 << 7) | (flash << 6) | (underline << 5) | (state->m_flshclk << 4) | ra; rad_data = state->m_rad_prom->base()[rad_addr] & 0x0f; rad_data = ra; // HACK because the RAD prom is not dumped yet } UINT16 chargen_addr = (th << 12) | (data << 4) | rad_data; UINT8 chargen_data = state->m_char_rom->base()[chargen_addr & 0xfff] << 2; int x = HORIZONTAL_PORCH_HACK + (column + 4) * ABC800_CHAR_WIDTH; for (int bit = 0; bit < ABC800_CHAR_WIDTH; bit++) { int color = BIT(chargen_data, 7) ? fg_color : bg_color; bitmap.pix32(y, x++) = PALETTE[color]; if (e5 || e6) { bitmap.pix32(y, x++) = PALETTE[color]; } chargen_data <<= 1; } if (e5 || e6) { column++; } // old_data = data; } } //------------------------------------------------- // hs_w - horizontal sync write //------------------------------------------------- WRITE_LINE_MEMBER( abc806_state::hs_w ) { int vsync; if (!state) { m_v50_addr++; // clock current vsync value into the shift register m_vsync_shift <<= 1; m_vsync_shift |= m_vsync; vsync = BIT(m_vsync_shift, m_sync); if (!m_d_vsync && vsync) { // clear V50 address m_v50_addr = 0; } else if (m_d_vsync && !vsync) { // flash clock if (m_flshclk_ctr & 0x20) { m_flshclk = !m_flshclk; m_flshclk_ctr = 0; } else { m_flshclk_ctr++; } } if (m_d_vsync != vsync) { // signal _DEW to DART m_dart->rib_w(!vsync); } m_d_vsync = vsync; } } //------------------------------------------------- // vs_w - vertical sync write //------------------------------------------------- WRITE_LINE_MEMBER( abc806_state::vs_w ) { m_vsync = state; } //------------------------------------------------- // mc6845_interface crtc_intf //------------------------------------------------- static MC6845_INTERFACE( crtc_intf ) { false, ABC800_CHAR_WIDTH, NULL, abc806_update_row, NULL, DEVCB_NULL, DEVCB_NULL, DEVCB_DRIVER_LINE_MEMBER(abc806_state, hs_w), DEVCB_DRIVER_LINE_MEMBER(abc806_state, vs_w), NULL }; //------------------------------------------------- // hr_update - high resolution screen update //------------------------------------------------- void abc806_state::hr_update(bitmap_rgb32 &bitmap, const rectangle &cliprect) { UINT32 addr = (m_hrs & 0x0f) << 15; for (int y = m_sync + VERTICAL_PORCH_HACK; y < MIN(cliprect.max_y + 1, m_sync + VERTICAL_PORCH_HACK + 240); y++) { for (int sx = 0; sx < 128; sx++) { UINT8 data = m_video_ram[addr++]; UINT16 dot = (m_hrc[data >> 4] << 8) | m_hrc[data & 0x0f]; for (int pixel = 0; pixel < 4; pixel++) { int x = HORIZONTAL_PORCH_HACK + (ABC800_CHAR_WIDTH * 4) - 16 + (sx * 4) + pixel; if (BIT(dot, 15) || (bitmap.pix32(y, x) == RGB_BLACK)) { bitmap.pix32(y, x) = PALETTE[(dot >> 12) & 0x07]; } dot <<= 4; } } } } void abc806_state::video_start() { // initialize variables for (int i = 0; i < 16; i++) { m_hrc[i] = 0; } m_sync = 10; m_d_vsync = 1; m_vsync = 1; m_40 = 1; // allocate memory m_char_ram.allocate(ABC806_CHAR_RAM_SIZE); m_color_ram = auto_alloc_array(machine(), UINT8, ABC806_ATTR_RAM_SIZE); // register for state saving save_pointer(NAME(m_char_ram.target()), ABC806_CHAR_RAM_SIZE); save_pointer(NAME(m_color_ram), ABC806_ATTR_RAM_SIZE); save_pointer(NAME(m_video_ram.target()), ABC806_VIDEO_RAM_SIZE); save_item(NAME(m_txoff)); save_item(NAME(m_40)); save_item(NAME(m_flshclk_ctr)); save_item(NAME(m_flshclk)); save_item(NAME(m_attr_data)); save_item(NAME(m_hrs)); save_item(NAME(m_hrc)); save_item(NAME(m_sync)); save_item(NAME(m_v50_addr)); save_item(NAME(m_hru2_a8)); save_item(NAME(m_vsync_shift)); save_item(NAME(m_vsync)); save_item(NAME(m_d_vsync)); } //------------------------------------------------- // SCREEN_UPDATE( abc806 ) //------------------------------------------------- UINT32 abc806_state::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect) { // HACK expand visible area to workaround MC6845 screen.set_visible_area(0, 767, 0, 311); // clear screen bitmap.fill(get_black_pen(machine()), cliprect); if (!m_txoff) { // draw text m_crtc->screen_update(screen, bitmap, cliprect); } // draw HR graphics hr_update(bitmap, cliprect); return 0; } //------------------------------------------------- // MACHINE_CONFIG_FRAGMENT( abc806_video ) //------------------------------------------------- MACHINE_CONFIG_FRAGMENT( abc806_video ) MCFG_MC6845_ADD(MC6845_TAG, MC6845, SCREEN_TAG, ABC800_CCLK, crtc_intf) MCFG_SCREEN_ADD(SCREEN_TAG, RASTER) MCFG_SCREEN_UPDATE_DRIVER(abc806_state, screen_update) MCFG_SCREEN_REFRESH_RATE(60) MCFG_SCREEN_VBLANK_TIME(ATTOSECONDS_IN_USEC(2500)) MCFG_SCREEN_SIZE(768, 312) MCFG_SCREEN_VISIBLE_AREA(0, 768-1, 0, 312-1) MACHINE_CONFIG_END