From a0a91cf41e5b83a7223ed90a9156b6933ecb9181 Mon Sep 17 00:00:00 2001 From: Dirk Best Date: Tue, 19 Dec 2023 13:36:08 +0100 Subject: brother/pn8800fxb: Major improvements * Add timer interrupt * Add keyboard emulation * Improve video emulation, support more modes * Cleanup low memory emulation --- src/mame/brother/pn8800fxb.cpp | 362 ++++++++++++++++++++++++++++++++++------- 1 file changed, 301 insertions(+), 61 deletions(-) diff --git a/src/mame/brother/pn8800fxb.cpp b/src/mame/brother/pn8800fxb.cpp index 8d9d21ec174..750546e1aaa 100644 --- a/src/mame/brother/pn8800fxb.cpp +++ b/src/mame/brother/pn8800fxb.cpp @@ -17,16 +17,27 @@ - XTAL XT5 16.0MHz (near FDC) TODO: - - Almost everything, draws the initial screen + - Fix ROM banking (ROM self-test shows NG) + - Improve video emulation (offset, modes, etc.) + - RTC + - Floppy + - Buzzer + - Centronics + - Modem + - Soft power off/on + - RAM contents should be retained when turning off + - Bookman (unlikely to make progress, extra PCB contains custom CPU) Notes: - There is a serially connected daughterbord containing the Bookman logic + - Press CODE+SHIFT+BS on the main menu for a self-test screen ****************************************************************************/ #include "emu.h" #include "cpu/z180/z180.h" +#include "machine/timer.h" #include "emupal.h" #include "screen.h" @@ -46,7 +57,9 @@ public: m_maincpu(*this, "maincpu"), m_rombank(*this, "rombank"), m_palette(*this, "palette"), - m_gfxdecode(*this, "gfxdecode") + m_gfxdecode(*this, "gfxdecode"), + m_keys(*this, "KO%u", 0U), + m_lomem_view(*this, "lomem") { } void pn8800fxb(machine_config &config); @@ -60,29 +73,43 @@ private: required_memory_bank m_rombank; required_device m_palette; required_device m_gfxdecode; + required_ioport_array<9> m_keys; + memory_view m_lomem_view; + + uint8_t m_key_select; std::unique_ptr m_vram; + uint16_t m_cursor_addr; uint16_t m_video_addr; uint8_t m_video_ctrl; + uint8_t m_video_offset; + uint8_t m_cursor_ctrl; uint8_t m_mem_change; void mem_map(address_map &map); void io_map(address_map &map); + uint8_t keyboard_r(); + void keyboard_w(uint8_t data); + void palette(palette_device &palette) const; uint32_t screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect); + void cursor_addr_lo_w(uint8_t data); + void cursor_addr_hi_w(uint8_t data); void video_addr_lo_w(uint8_t data); void video_addr_hi_w(uint8_t data); uint8_t video_data_r(); void video_data_w(uint8_t data); uint8_t video_ctrl_r(); void video_ctrl_w(uint8_t data); + void video_offset_w(uint8_t data); + void cursor_ctrl_w(uint8_t data); void mem_change_w(uint8_t data); void bank_select_w(uint8_t data); - uint8_t lo_mem_r(offs_t offset); - void lo_mem_w(offs_t offset, uint8_t data); + void int_ack_w(uint8_t data); + TIMER_DEVICE_CALLBACK_MEMBER(int1_timer); }; @@ -93,43 +120,49 @@ private: void pn8800fxb_state::mem_map(address_map &map) { map(0x00000, 0x01fff).rom(); - map(0x02000, 0x07fff).rw(FUNC(pn8800fxb_state::lo_mem_r), FUNC(pn8800fxb_state::lo_mem_w)); + map(0x02000, 0x05fff).ram().share("window1"); + map(0x06000, 0x07fff).view(m_lomem_view); + m_lomem_view[0](0x06000, 0x07fff).ram().share("window2"); + m_lomem_view[1](0x06000, 0x07fff).rom().region("maincpu", 0x06000); map(0x08000, 0x3ffff).rom(); map(0x40000, 0x41fff).unmaprw(); - map(0x42000, 0x45fff).rom().region("maincpu", 0x2000); + map(0x42000, 0x45fff).rom().region("maincpu", 0x02000); map(0x46000, 0x4ffff).unmaprw(); map(0x50000, 0x5ffff).bankr(m_rombank); - map(0x60000, 0x7ffff).ram(); + map(0x60000, 0x61fff).ram(); + map(0x62000, 0x65fff).ram().share("window1"); + map(0x66000, 0x67fff).ram().share("window2"); + map(0x68000, 0x7ffff).ram(); } void pn8800fxb_state::io_map(address_map &map) { map.global_mask(0xff); map(0x00, 0x3f).noprw(); // z180 internal - // 70 cursor - // 71 cursor + map(0x70, 0x70).w(FUNC(pn8800fxb_state::cursor_addr_lo_w)); + map(0x71, 0x71).w(FUNC(pn8800fxb_state::cursor_addr_hi_w)); map(0x72, 0x72).w(FUNC(pn8800fxb_state::video_addr_lo_w)); map(0x73, 0x73).w(FUNC(pn8800fxb_state::video_addr_hi_w)); map(0x74, 0x74).rw(FUNC(pn8800fxb_state::video_data_r), FUNC(pn8800fxb_state::video_data_w)); map(0x75, 0x75).rw(FUNC(pn8800fxb_state::video_ctrl_r), FUNC(pn8800fxb_state::video_ctrl_w)); - // 76 display offset - // 77 cursor control + map(0x76, 0x76).w(FUNC(pn8800fxb_state::video_offset_w)); + map(0x77, 0x77).w(FUNC(pn8800fxb_state::cursor_ctrl_w)); // 78-7f mode select // 80-87 fdc // 88-8f input map(0x90, 0x90).mirror(0x07).w(FUNC(pn8800fxb_state::mem_change_w)); // 98-9f rs break // a0-a7 rs232 - // a8-af not used + map(0xa8, 0xa8).mirror(0x07).nopr(); // "not used" - but read often // b0-b7 power supply - // b8-bf keyboard + map(0xb8, 0xb8).rw(FUNC(pn8800fxb_state::keyboard_r), FUNC(pn8800fxb_state::keyboard_w)); // c0-c7 cdcc data // c8-cf cdcc control - // d0-df rtc + map(0xd0, 0xdf).noprw(); // rtc map(0xe0, 0xe0).mirror(0x07).w(FUNC(pn8800fxb_state::bank_select_w)); // e8-ef ga test // f0-f7 buzzer - // f8-ff interrupt ack + map(0xf8, 0xf8).mirror(0x07).w(FUNC(pn8800fxb_state::int_ack_w)); } @@ -138,8 +171,112 @@ void pn8800fxb_state::io_map(address_map &map) //************************************************************************** static INPUT_PORTS_START( pn8800fxb ) + PORT_START("KO0") + PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_LSHIFT) PORT_CODE(KEYCODE_RSHIFT) PORT_CHAR(UCHAR_SHIFT_1) + PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_LEFT) PORT_CHAR(UCHAR_MAMEKEY(LEFT)) PORT_NAME("\xe2\x86\x90 EXPR") // ← + PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_UNUSED) + PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_BACKSPACE) PORT_CHAR(8) PORT_NAME("BS") + PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_ENTER) PORT_CHAR(13) PORT_NAME("RETURN IND CLR =") + PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_UNUSED) + PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_UP) PORT_CHAR(UCHAR_MAMEKEY(UP)) PORT_NAME("\xe2\x86\x91 PRE S") // ↑ + PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_SPACE) PORT_CHAR(' ') + + PORT_START("KO1") + PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_UNUSED) + PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_CLOSEBRACE) PORT_CHAR('[') PORT_CHAR(']') PORT_NAME(u8"[ ] ½ ¼") + PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_EQUALS) PORT_CHAR('=') PORT_CHAR('+') PORT_NAME("= + L OUT") + PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_0) PORT_CHAR('0') PORT_CHAR(')') PORT_NAME("0 ) W OUT") + PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_MINUS) PORT_CHAR('-') PORT_CHAR('_') PORT_NAME("- _ -") + PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_P) PORT_CHAR('p') PORT_CHAR('P') PORT_NAME("p P PRINT +") + PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_SLASH) PORT_CHAR('/') PORT_CHAR('?') PORT_NAME("/ ? /") + PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_UNUSED) + + PORT_START("KO2") + PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_DOWN) PORT_CHAR(UCHAR_MAMEKEY(DOWN)) PORT_NAME("\xe2\x86\x93 NEXT S") // ↓ + PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_QUOTE) PORT_CHAR('\'') PORT_CHAR('"') + PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_L) PORT_CHAR('l') PORT_CHAR('L') PORT_NAME("l L L IND 3") + PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_9) PORT_CHAR('9') PORT_CHAR('(') PORT_NAME("9 ( T CLR 9") + PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_O) PORT_CHAR('o') PORT_CHAR('O') PORT_NAME("o O JUST 6") + PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_STOP) PORT_CHAR('.') PORT_CHAR('>') PORT_CHAR(']') PORT_NAME(". > ] .") + PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_COLON) PORT_CHAR(';') PORT_CHAR(':') PORT_NAME("; : *") + PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_RIGHT) PORT_CHAR(UCHAR_MAMEKEY(RIGHT)) PORT_NAME("\xe2\x86\x92 RELOC") // → + + PORT_START("KO3") + PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_UNUSED) + PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_K) PORT_CHAR('k') PORT_CHAR('K') PORT_NAME("k K KB 2") + PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_8) PORT_CHAR('8') PORT_CHAR('*') PORT_NAME("8 * DT SET 8") + PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_6) PORT_CHAR('6') PORT_CHAR('^') + PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_7) PORT_CHAR('7') PORT_CHAR('&') PORT_NAME("7 & T SET 7") + PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_I) PORT_CHAR('i') PORT_CHAR('I') PORT_NAME("i I INSERT 5") + PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_COMMA) PORT_CHAR(',') PORT_CHAR('<') PORT_CHAR('[') + PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_UNUSED) + + PORT_START("KO4") + PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_UNUSED) + PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_N) PORT_CHAR('n') PORT_CHAR('N') + PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_J) PORT_CHAR('j') PORT_CHAR('J') PORT_NAME("j J LAYOUT 1") + PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_Y) PORT_CHAR('y') PORT_CHAR('Y') PORT_CHAR('{') PORT_NAME("y Y { <") + PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_U) PORT_CHAR('u') PORT_CHAR('U') PORT_CHAR('}') PORT_NAME("u U } >") + PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_H) PORT_CHAR('h') PORT_CHAR('H') PORT_NAME("h H HELP") + PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_M) PORT_CHAR('m') PORT_CHAR('M') PORT_NAME("m M M CODE 0") + PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_UNUSED) + + PORT_START("KO5") + PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_UNUSED) + PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_B) PORT_CHAR('b') PORT_CHAR('B') + PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_F) PORT_CHAR('f') PORT_CHAR('F') + PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_T) PORT_CHAR('t') PORT_CHAR('T') PORT_NAME("t T TEMP") + PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_R) PORT_CHAR('r') PORT_CHAR('R') + PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_G) PORT_CHAR('g') PORT_CHAR('G') PORT_NAME("g G GOTO") + PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_V) PORT_CHAR('v') PORT_CHAR('V') PORT_CHAR(U'`') + PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_UNUSED) + + PORT_START("KO6") + PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_ESC) PORT_CHAR(27) PORT_NAME("CANCEL") + PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_D) PORT_CHAR('d') PORT_CHAR('D') + PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_3) PORT_CHAR('3') PORT_CHAR('#') PORT_NAME("3 # M REL") + PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_5) PORT_CHAR('5') PORT_CHAR('%') PORT_NAME("5 % R MAR") + PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_4) PORT_CHAR('4') PORT_CHAR('$') PORT_NAME("4 $ L MAR") + PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_E) PORT_CHAR('e') PORT_CHAR('E') + PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_C) PORT_CHAR('c') PORT_CHAR('C') + PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_LALT) PORT_NAME("MENU FILE") + + PORT_START("KO7") + PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_UNUSED) + PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_X) PORT_CHAR('x') PORT_CHAR('X') PORT_CHAR('|') PORT_NAME(u8"x X | ²") + PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_W) PORT_CHAR('w') PORT_CHAR('W') PORT_CHAR(U'¢') + PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_TAB) PORT_CHAR(9) PORT_NAME("TAB P IND") + PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_2) PORT_CHAR('2') PORT_CHAR('@') PORT_NAME("2 @ LINE") + PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_S) PORT_CHAR('s') PORT_CHAR('S') PORT_NAME("s S CALC") + PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_UNUSED) + PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_UNUSED) + + PORT_START("KO8") + PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_UNUSED) + PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_A) PORT_CHAR('a') PORT_CHAR('A') PORT_NAME("a A ABBR") + PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_Q) PORT_CHAR('q') PORT_CHAR('Q') + PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_TILDE) PORT_CHAR(U'`') PORT_CHAR('~') PORT_NAME(u8"` ~ SPELL ± °") + PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_1) PORT_CHAR('1') PORT_CHAR('!') PORT_NAME("1 ! PITCH") + PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_CAPSLOCK) PORT_CHAR(UCHAR_MAMEKEY(CAPSLOCK)) PORT_NAME("CAPS SHIFT LOCK") + PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_Z) PORT_CHAR('z') PORT_CHAR('Z') PORT_CHAR('\\') PORT_NAME(u8"z Z \\ §") + PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_LCONTROL) PORT_CHAR(UCHAR_SHIFT_2) PORT_NAME("CODE") INPUT_PORTS_END +uint8_t pn8800fxb_state::keyboard_r() +{ + if (m_key_select < 9) + return m_keys[m_key_select]->read(); + else + logerror("keyboard_r from %02x\n", m_key_select); + + return 0xff; +} + +void pn8800fxb_state::keyboard_w(uint8_t data) +{ + m_key_select = data; +} + //************************************************************************** // VIDEO EMULATION @@ -147,8 +284,8 @@ INPUT_PORTS_END void pn8800fxb_state::palette(palette_device &palette) const { - palette.set_pen_color(0, rgb_t(131, 238, 47)); - palette.set_pen_color(1, rgb_t(31, 84, 67)); + palette.set_pen_color(0, rgb_t(86, 228, 94)); + palette.set_pen_color(1, rgb_t(58, 86, 143)); } uint32_t pn8800fxb_state::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect) @@ -157,26 +294,99 @@ uint32_t pn8800fxb_state::screen_update(screen_device &screen, bitmap_rgb32 &bit const pen_t *const pen = m_palette->pens(); - for (int y = 0; y < 22; y++) + // 22 line text mode doesn't cover the full screen + bitmap.fill(pen[0], cliprect); + + if (BIT(m_video_ctrl, 0)) { - for (int x = 0; x < 80; x++) + if (BIT(m_video_ctrl, 3)) { - //uint8_t attr = m_vram[y * 0x100 + x * 2 + 0]; - uint8_t code = m_vram[y * 0x100 + x * 2 + 1]; + // graphics mode + uint8_t *vram = m_vram.get(); + + // left 512 pixels of screen + for (int y = 0; y < 200; y++) + for (int x = 0; x < 512; x += 8, vram++) + for (int p = 0; p < 8; p++) + bitmap.pix(y, x + p) = pen[BIT(*vram, 7 - p)]; + + // right 128 pixels of screen + for (int y = 0; y < 200; y++) + for (int x = 0; x < 128; x += 8, vram++) + for (int p = 0; p < 8; p++) + bitmap.pix(y, 512 + x + p) = pen[BIT(*vram, 7 - p)]; + } + else + { + // text mode + int lines = BIT(m_video_ctrl, 5) ? 25 : 22; - // draw 9 lines - for (int l = 0; l < 9; l++) + for (int y = 0; y < lines; y++) { - uint8_t data = 0x00; - - // line 9 always blank? - if (l < 8) - data = m_vram[0x3000 + (code << 3) + l]; - - // draw 8 pixels of the character - for (int b = 0; b < 8; b++) + for (int x = 0; x < 80; x++) { - bitmap.pix(y * 9 + l, x * 8 + b) = pen[BIT(data, 7 - b)]; + // attributes + // + // 7------- unknown + // -6------ subscript + // --5----- superscript + // ---4---- invert + // ----3--- vertical line + // -----2-- code high bit + // ------1- overline + // -------0 underline + + uint8_t attr = m_vram[y * 0x100 + x * 2 + 0]; + uint16_t code = m_vram[y * 0x100 + x * 2 + 1]; + + // apply code high bit (high table contains bold characters) + code |= (BIT(attr, 2) << 8) | code; + + bool cursor_active = (y * 0x100 + x * 2) == (m_cursor_addr << 1); + + // draw 8 or 9 lines + for (int l = 0; l < 9; l++) + { + uint8_t data = 0x00; + + // skip empty line in 25 line mode + if (lines == 25 && l == 0) + continue; + + // character data (or cursor) in lines 1 to 8 + if (l > 0) + { + if (cursor_active) + data = 0xff; + else + data = m_vram[0x3000 + (code << 3) + l - 1]; + } + + // underline? + if (BIT(attr, 0) && l == 8) + data = 0xff; + + // overline? + if (BIT(attr, 1) && l == 0) + data = 0xff; + + // vertical line? + if (BIT(attr, 3)) + data |= 0x01; + + // invert? + if (BIT(attr, 4)) + data ^= 0xff; + + // draw 8 pixels of the character + for (int b = 0; b < 8; b++) + { + if (lines == 25) + bitmap.pix(y * 8 + l - 1, x * 8 + b) = pen[BIT(data, 7 - b)]; + else + bitmap.pix(y * 9 + l, x * 8 + b) = pen[BIT(data, 7 - b)]; + } + } } } } @@ -185,6 +395,17 @@ uint32_t pn8800fxb_state::screen_update(screen_device &screen, bitmap_rgb32 &bit return 0; } +void pn8800fxb_state::cursor_addr_lo_w(uint8_t data) +{ + m_cursor_addr = (m_cursor_addr & 0xff00) | (data << 0); +} + +void pn8800fxb_state::cursor_addr_hi_w(uint8_t data) +{ + data &= 0x0f; + m_cursor_addr = (data << 8) | (m_cursor_addr & 0x00ff); +} + void pn8800fxb_state::video_addr_lo_w(uint8_t data) { m_video_addr = (m_video_addr & 0xff00) | (data << 0); @@ -213,8 +434,8 @@ uint8_t pn8800fxb_state::video_ctrl_r() { // 7------- mm // -6------ not used - // --5----- 8r - // ---4---- 8lp + // --5----- 8r (in text mode, 8 pixel height line instead of 9?) + // ---4---- blp // ----3--- grph // -----2-- not used // ------1- rev @@ -225,11 +446,33 @@ uint8_t pn8800fxb_state::video_ctrl_r() void pn8800fxb_state::video_ctrl_w(uint8_t data) { - logerror("video_ctrl_w: %02x\n", data); + if (0) + logerror("video_ctrl_w: %02x\n", data); m_video_ctrl = data; } +void pn8800fxb_state::video_offset_w(uint8_t data) +{ + // 765----- not used + // ---4---- oy + // ----3210 ox6 to ox3 + + m_video_offset = data; +} + +void pn8800fxb_state::cursor_ctrl_w(uint8_t data) +{ + // 7------- curu + // -6------ curl + // --5----- cbkh + // ---4---- crev + // ----3--- curb + // -----210 not used + + m_cursor_ctrl = data; +} + static const gfx_layout charlayout = { 8, 8, @@ -249,29 +492,6 @@ GFXDECODE_END // MACHINE EMULATION //************************************************************************** -uint8_t pn8800fxb_state::lo_mem_r(offs_t offset) -{ - uint8_t data = 0xff; - offset += 0x2000; - - if (offset < 0x6000) - data = m_maincpu->space(AS_PROGRAM).read_byte(0x60000 + offset); - else - data = memregion("maincpu")->base()[offset]; - - return data; -} - -void pn8800fxb_state::lo_mem_w(offs_t offset, uint8_t data) -{ - offset += 0x2000; - - if (offset < 0x6000) - m_maincpu->space(AS_PROGRAM).write_byte(0x60000 + offset, data); - else - logerror("write 6000-7fff %04x %02x\n", offset, data); -} - void pn8800fxb_state::mem_change_w(uint8_t data) { // 7------- dua @@ -280,9 +500,11 @@ void pn8800fxb_state::mem_change_w(uint8_t data) // ------1- dicsel // -------0 rgex - logerror("mem_change_w: dua %d ramin %d dicsel %d rgex %d\n", BIT(data, 7), BIT(data, 6), BIT(data, 1), BIT(data, 0)); + if (data != 0x40) + logerror("mem_change_w: dua %d ramin %d dicsel %d rgex %d\n", BIT(data, 7), BIT(data, 6), BIT(data, 1), BIT(data, 0)); m_mem_change = data; + m_lomem_view.select(BIT(data, 6)); } void pn8800fxb_state::bank_select_w(uint8_t data) @@ -290,10 +512,21 @@ void pn8800fxb_state::bank_select_w(uint8_t data) // 7654---- not used // ----3210 bank selection - logerror("bank_select_w: %02x\n", data); + if (0) + logerror("bank_select_w: %02x\n", data); if (data < 12) - m_rombank->set_entry(data ^ 8); // TODO, but works for now + m_rombank->set_entry(data & 0x07); // TODO, but works for now +} + +void pn8800fxb_state::int_ack_w(uint8_t data) +{ + m_maincpu->set_input_line(INPUT_LINE_IRQ1, CLEAR_LINE); +} + +TIMER_DEVICE_CALLBACK_MEMBER( pn8800fxb_state::int1_timer ) +{ + m_maincpu->set_input_line(INPUT_LINE_IRQ1, ASSERT_LINE); } void pn8800fxb_state::machine_start() @@ -308,15 +541,20 @@ void pn8800fxb_state::machine_start() m_rombank->configure_entries(0, 12, memregion("maincpu")->base() + 0x40000, 0x10000); // register for save states + save_item(NAME(m_key_select)); save_pointer(NAME(m_vram), 0x4000); + save_item(NAME(m_cursor_addr)); save_item(NAME(m_video_addr)); save_item(NAME(m_video_ctrl)); + save_item(NAME(m_video_offset)); + save_item(NAME(m_cursor_ctrl)); save_item(NAME(m_mem_change)); } void pn8800fxb_state::machine_reset() { m_mem_change = 0x00; + m_lomem_view.select(0); } @@ -330,6 +568,8 @@ void pn8800fxb_state::pn8800fxb(machine_config &config) m_maincpu->set_addrmap(AS_PROGRAM, &pn8800fxb_state::mem_map); m_maincpu->set_addrmap(AS_IO, &pn8800fxb_state::io_map); + TIMER(config, "1khz").configure_periodic(FUNC(pn8800fxb_state::int1_timer), attotime::from_hz(1000)); + screen_device &screen(SCREEN(config, "screen", SCREEN_TYPE_LCD)); screen.set_size(640, 200); screen.set_visarea_full(); -- cgit v1.2.3