From c5086e685165654b985eb1ced20a023ba4ecdf78 Mon Sep 17 00:00:00 2001 From: angelosa Date: Sat, 29 Jun 2024 15:43:12 +0200 Subject: [PATCH] casio/fp200.cpp: rewrite video section --- src/mame/casio/fp200.cpp | 372 +++++++++++++-------------------------- 1 file changed, 123 insertions(+), 249 deletions(-) diff --git a/src/mame/casio/fp200.cpp b/src/mame/casio/fp200.cpp index 3bdbb785638..d357a5e335a 100644 --- a/src/mame/casio/fp200.cpp +++ b/src/mame/casio/fp200.cpp @@ -1,19 +1,20 @@ // license:BSD-3-Clause // copyright-holders:Angelo Salese +// thanks-to: Takeda Toshiya /************************************************************************************************** FP-200 (c) 1982 Casio TODO: -- Identify LCDC, move to devices - (2x MSM6216-01GS-1K + 1x MSM6215-01GS-K glued together by the gate array); - backup RAM; -- cassette i/f; +- cassette i/f, glued together by discrete; +- serial i/f; - FDC (requires test program that Service manual mentions); +- mini plotter printer (FP-1011PL) +- graphic printer (FP-1012PR) Notes: -- on start-up there's a "memory illegal" warning. Enter "RESET" command - to initialize it (thanks to Takeda Toshiya for pointing this out). +- on start-up there's a "memory illegal" warning. Issue a "RESET" command to initialize it. **************************************************************************************************/ @@ -38,6 +39,7 @@ public: , m_rtc(*this, "rtc") , m_ioview(*this, "ioview") , m_key(*this, "KEY%X", 0U) + , m_gfxrom(*this, "chargen") { } void fp200(machine_config &config); @@ -50,26 +52,24 @@ private: required_device m_rtc; memory_view m_ioview; required_ioport_array<16> m_key; + required_memory_region m_gfxrom; + uint8_t *m_chargen = nullptr; uint8_t m_keyb_matrix = 0; - struct{ - uint8_t x = 0; - uint8_t y = 0; - uint8_t status = 0; - std::unique_ptr vram; - std::unique_ptr attr; - }m_lcd; - uint8_t read_lcd_attr(uint16_t X, uint16_t Y); - uint8_t read_lcd_vram(uint16_t X, uint16_t Y); - void write_lcd_attr(uint16_t X, uint16_t Y,uint8_t data); - void write_lcd_vram(uint16_t X, uint16_t Y,uint8_t data); + std::unique_ptr m_lcd_vram[2]; + u16 m_lcd_yoffset[2]{}; + u16 m_lcd_address = 0; + u8 m_lcd_status = 0; + bool m_lcd_text_mode = false; - // screen updates uint32_t screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect); - uint8_t lcd_r(offs_t offset); - void lcd_w(offs_t offset, uint8_t data); + template u8 lcd_data_r(offs_t offset); + template void lcd_data_w(offs_t offset, u8 data); + + void lcd_map(address_map &map); + uint8_t keyb_r(offs_t offset); void keyb_w(offs_t offset, uint8_t data); @@ -89,239 +89,120 @@ private: void fp200_state::video_start() { - m_lcd.vram = make_unique_clear(20*64); - m_lcd.attr = make_unique_clear(20*64); + m_lcd_vram[0] = make_unique_clear(0x400); + m_lcd_vram[1] = make_unique_clear(0x400); + + save_pointer(NAME(m_lcd_vram[0]), 0x400); + save_pointer(NAME(m_lcd_vram[1]), 0x400); } -// TODO: rewrite, don't loop 4 times uint32_t fp200_state::screen_update( screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect ) { - uint16_t l_offs, r_offs; - - bitmap.fill(0, cliprect); - - l_offs = 0; - r_offs = 0; - for(int y = cliprect.top(); y <= cliprect.bottom(); y++) + for(int y = cliprect.min_x; y <= cliprect.max_y; y ++) { - for(int x = 0; x < 80;x++) + for(int x = cliprect.min_x; x <= cliprect.max_x; x ++) { - if(m_lcd.attr[x / 8 + y * 20] == 0x50) - { - l_offs = (y & ~7); - break; - } - } - } + const u8 which = x < 80; + const u8 x_tile = x >> 3; + const u8 y_tile = y >> 3; + const u16 base_addr = ((x_tile % 10 + y_tile * 0x80) + m_lcd_yoffset[which]) & 0x3ff; + const u8 xi = x & 7; + const u8 yi = y & 7; - for(int y = cliprect.top(); y <= cliprect.bottom(); y++) - { - for(int x=80;x<160;x++) - { - if(m_lcd.attr[x/8+y*20] == 0x50) - { - r_offs = (y & ~7); - break; - } - } - } - - for(int y = cliprect.top(); y <= cliprect.bottom(); y++) - { - for(int x=0;x<80;x++) - { - uint16_t yoffs; - - yoffs = y + l_offs; - - if(yoffs >= 64) - yoffs -= 64; - - if(m_lcd.attr[x/8+yoffs*20] == 0x60 || m_lcd.attr[x/8+yoffs*20] == 0x50) - { - uint8_t const vram = m_lcd.vram[x/8+yoffs*20]; - uint8_t const pix = ((m_chargen[vram*8+(x & 7)]) >> (7-(yoffs & 7))) & 1; - bitmap.pix(y,x) = pix; - } - /* - else if(m_lcd.attr[x/8+yoffs*20] == 0x40) - { - uint8_t const vram = m_lcd.vram[x/8+yoffs*20]; - uint8_t const pix = (vram) >> (7-(yoffs & 7)) & 1; - bitmap.pix(y,x) = pix; - }*/ - } - } - - for(int y = cliprect.top(); y <= cliprect.bottom(); y++) - { - for(int x=80;x<160;x++) - { - uint16_t yoffs; - - yoffs = y + r_offs; - - if(yoffs >= 64) - yoffs -= 64; - - if(m_lcd.attr[x/8+yoffs*20] == 0x60 || m_lcd.attr[x/8+yoffs*20] == 0x50) - { - uint8_t const vram = m_lcd.vram[x/8+yoffs*20]; - uint8_t const pix = ((m_chargen[vram*8+(x & 7)]) >> (7-(yoffs & 7))) & 1; - bitmap.pix(y,x) = pix; - } - /*else if(m_lcd.attr[x/8+yoffs*20] == 0x40) - { - uint8_t const vram = m_lcd.vram[x/8+yoffs*20]; - uint8_t const pix = (vram) >> (7-(yoffs & 7)) & 1; - bitmap.pix(y,x) = pix; - }*/ + const u8 vram = m_lcd_vram[which][(base_addr + yi * 0x10) & 0x3ff]; + uint8_t const pix = BIT(vram, xi); + bitmap.pix(y, x) = pix; } } return 0; } +template u8 fp200_state::lcd_data_r(offs_t offset) +{ + return m_lcd_vram[N][m_lcd_address & 0x3ff]; +} + +template void fp200_state::lcd_data_w(offs_t offset, u8 data) +{ + switch (m_lcd_status) + { + // select mode + case 0xb: + if (BIT(data, 6)) + { + if (BIT(data, 4)) + m_lcd_yoffset[N] = m_lcd_address; + else + m_lcd_text_mode = bool(BIT(data, 5)); + } + + if (data & 0x8f) + logerror("Warning: LCD write with unknown mode %02x\n", data); + + break; + + // data write + case 0x1: + if (m_lcd_text_mode) + { + // The handling doesn't make a whole lot of sense for being practically usable ... + const u8 tile_address = bitswap<8>(data, 3, 2, 1, 0, 7, 6, 5, 4); + for (int yi = 0; yi < 8; yi ++) + { + u8 tile = 0; + for (int xi = 0; xi < 8; xi ++) + tile |= BIT(m_gfxrom->base()[tile_address * 8 + xi], 7 - yi) << xi; + m_lcd_vram[N][(m_lcd_address + 0x10 * yi) & 0x3ff] = tile; + } + } + else + m_lcd_vram[N][m_lcd_address & 0x3ff] = data; + + break; + default: + logerror("Warning: LCD write with unknown status type %02x\n", m_lcd_status); + break; + } +} /* -[1] DDDD DDDD vram data/attr (left half) -[2] DDDD DDDD vram data/attr (right half) -[8] SSSS --YY Status code (1=vram type/0xb=attr type) / upper part of Y address -[9] YYYY XXXX lower part of Y address / X address -*/ -uint8_t fp200_state::read_lcd_attr(uint16_t X, uint16_t Y) + * video section is 2x MSM6216-01GS-1K + 1x MSM6215-01GS-K glued together by the gate array + * + * [1] DDDD DDDD vram data/mode select (right half) + * [2] DDDD DDDD vram data/mode select (left half) + * [8] SSSS ---- Status code (1=vram type/0xb=attr type) + * ---- --YY upper part of Y address + * [9] YYYY XXXX lower part of Y address / X address + */ +void fp200_state::lcd_map(address_map &map) { - uint16_t base_offs; - uint8_t res = 0; - - for(int yi=0;yi<8;yi++) - { - base_offs = X+(Y+yi)*20; - - if(base_offs >= 20*64) - return 0xff; - - res = m_lcd.attr[base_offs]; - } - - return res; -} - -uint8_t fp200_state::read_lcd_vram(uint16_t X, uint16_t Y) -{ - uint16_t base_offs; - uint8_t res = 0; - - for(int yi=0;yi<8;yi++) - { - base_offs = X+(Y+yi)*20; - - if(base_offs >= 20*64) - return 0xff; - - res = m_lcd.vram[base_offs]; - } - - return res; -} - -uint8_t fp200_state::lcd_r(offs_t offset) -{ - uint8_t res; - - res = 0; - - switch(offset) - { - case 1: - //logerror("%d %d -> (L) %02x\n",m_lcd.x,m_lcd.y,m_lcd.status); - if(m_lcd.status == 0xb) - res = read_lcd_attr(m_lcd.x,m_lcd.y); - else if(m_lcd.status == 1) - res = read_lcd_vram(m_lcd.x,m_lcd.y); - break; - case 2: - //logerror("%d %d -> (R) %02x\n",m_lcd.x,m_lcd.y,m_lcd.status); - if(m_lcd.status == 0xb) - res = read_lcd_attr(m_lcd.x + 10,m_lcd.y); - else if(m_lcd.status == 1) - res = read_lcd_vram(m_lcd.x + 10,m_lcd.y); - break; - case 8: - res = (m_lcd.status & 0xf) << 4; - res |= (m_lcd.y & 0x30) >> 4; - break; - case 9: - res = (m_lcd.y & 0xf) << 4; - res |= (m_lcd.x & 0xf); - break; - } - - - return res; -} - -void fp200_state::write_lcd_attr(uint16_t X, uint16_t Y,uint8_t data) -{ - uint16_t base_offs; - - for(int yi=0;yi<8;yi++) - { - base_offs = X+(Y+yi)*20; - - if(base_offs >= 20*64) - return; - - //if(data != 0x60) - // logerror("%d %d %02x\n",X,Y,data); - - m_lcd.attr[base_offs] = data; - } -} - -void fp200_state::write_lcd_vram(uint16_t X, uint16_t Y,uint8_t data) -{ - uint16_t base_offs; - - for(int yi=0;yi<8;yi++) - { - base_offs = X+(Y+yi)*20; - - if(base_offs >= 20*64) - return; - - m_lcd.vram[base_offs] = data; - } -} - -void fp200_state::lcd_w(offs_t offset, uint8_t data) -{ - switch(offset) - { - case 1: - //logerror("%d %d -> %02x (%c) (L %02x)\n",m_lcd.x,m_lcd.y,data,data,m_lcd.status); - if(m_lcd.status == 0xb) - write_lcd_attr(m_lcd.x,m_lcd.y,data); - else if(m_lcd.status == 1) - write_lcd_vram(m_lcd.x,m_lcd.y,data); - break; - case 2: - //logerror("%d %d -> %02x (%c) (R %02x)\n",m_lcd.x + 10,m_lcd.y,data,data,m_lcd.status); - if(m_lcd.status == 0xb) - write_lcd_attr(m_lcd.x + 10,m_lcd.y,data); - else if(m_lcd.status == 1) - write_lcd_vram(m_lcd.x + 10,m_lcd.y,data); - break; - case 8: - m_lcd.status = (data & 0xf0) >> 4; - if(m_lcd.status == 0x0b) - m_lcd.y = (m_lcd.y & 0xf) | ((data & 3) << 4); - break; - case 9: - m_lcd.y = (m_lcd.y & 0x30) | ((data & 0xf0) >> 4); - m_lcd.x = data & 0xf; - break; - } + map(0x1, 0x1).rw(FUNC(fp200_state::lcd_data_r<1>), FUNC(fp200_state::lcd_data_w<1>)); + map(0x2, 0x2).rw(FUNC(fp200_state::lcd_data_r<0>), FUNC(fp200_state::lcd_data_w<0>)); + map(0x8, 0x8).lrw8( + NAME([this] (offs_t offset) { + u8 res = (m_lcd_status & 0xf) << 4 | (m_lcd_address & 0x300) >> 4; + return res; + }), + NAME([this] (offs_t offset, u8 data) { + m_lcd_status = (data & 0xf0) >> 4; + if (m_lcd_status == 0xb) + { + m_lcd_address &= 0xff; + m_lcd_address |= (data & 0x3) << 8; + } + }) + ); + map(0x9, 0x9).lrw8( + NAME([this] (offs_t offset) { + u8 res = m_lcd_address & 0xff; + return res; + }), + NAME([this] (offs_t offset, u8 data) { + m_lcd_address &= 0x300; + m_lcd_address |= data; + }) + ); } uint8_t fp200_state::keyb_r(offs_t offset) @@ -353,10 +234,11 @@ void fp200_state::main_io(address_map &map) // m_ioview[0](0x20, 0x2f) AUTO-POWER OFF // m_ioview[0](0x40, 0x4f) FDC Device ID Code (5 for "FP-1021FD") // m_ioview[0](0x80, 0xff) FDD (unknown type) - m_ioview[1](0x00, 0x0f).rw(FUNC(fp200_state::lcd_r), FUNC(fp200_state::lcd_w)); + m_ioview[1](0x00, 0x0f).m(*this, FUNC(fp200_state::lcd_map)); // m_ioview[1](0x10, 0x10) I/O control (w/o), D1 selects CMT or RS-232C // m_ioview[1](0x11, 0x11) I/O control (w/o), uPD65010G gate array control - m_ioview[1](0x20, 0x20).r(FUNC(fp200_state::keyb_r)); + // TODO: writes are undocumented, just before reads PC=35C (strobe for update?) + m_ioview[1](0x20, 0x20).r(FUNC(fp200_state::keyb_r)).nopw(); m_ioview[1](0x21, 0x21).w(FUNC(fp200_state::keyb_w)); // m_ioview[1](0x40, 0x4f) CMT & RS-232C control // m_ioview[1](0x80, 0x8f) [Centronics] printer @@ -364,7 +246,6 @@ void fp200_state::main_io(address_map &map) INPUT_CHANGED_MEMBER(fp200_state::keyb_irq) { - /* a keyboard stroke causes a rst7.5 */ m_maincpu->set_input_line(I8085_RST75_LINE, (newval) ? ASSERT_LINE : CLEAR_LINE); } @@ -477,7 +358,8 @@ static INPUT_PORTS_START( fp200 ) PORT_START("KEYMOD") PORT_BIT( 0x01f, IP_ACTIVE_LOW, IPT_UNUSED ) - PORT_BIT( 0x020, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("CETL") PORT_TOGGLE + // positional switch on keyboard + PORT_BIT( 0x020, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("Basic / CETL Mode") PORT_TOGGLE PORT_BIT( 0x040, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("SHIFT") PORT_CODE(KEYCODE_LSHIFT) PORT_CODE(KEYCODE_RSHIFT) PORT_BIT( 0x080, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("BREAK") PORT_BIT( 0x100, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("GRAPH") @@ -505,12 +387,6 @@ GFXDECODE_END void fp200_state::machine_start() { - uint8_t *raw_gfx = memregion("raw_gfx")->base(); - m_chargen = memregion("chargen")->base(); - - // HACK: convert GFX to a more usable format - for(int i = 0; i < 0x800; i++) - m_chargen[i] = raw_gfx[bitswap<16>(i, 15, 14, 13, 12, 11, 6, 5, 4, 3, 10, 9, 8, 7, 2, 1, 0)]; } void fp200_state::machine_reset() @@ -572,10 +448,8 @@ ROM_START( fp200 ) ROM_REGION( 0x10000, "maincpu", ROMREGION_ERASE00 ) ROM_LOAD( "fp200rom.bin", 0x0000, 0x8000, CRC(dba6e41b) SHA1(c694fa19172eb56585a9503997655bcf9d369c34) ) - ROM_REGION( 0x800, "raw_gfx", ROMREGION_ERASE00 ) - ROM_LOAD( "chr.bin", 0x0000, 0x800, CRC(2e6501a5) SHA1(6186e25feabe6db851ee7d61dad11e182a6d3a4a) ) - ROM_REGION( 0x800, "chargen", ROMREGION_ERASE00 ) + ROM_LOAD( "chr.bin", 0x0000, 0x800, CRC(2e6501a5) SHA1(6186e25feabe6db851ee7d61dad11e182a6d3a4a) ) ROM_END } // anonymous namespace