From e8fbb39587f9f2ee4c5a937b2ac487b8dd38c718 Mon Sep 17 00:00:00 2001 From: cracyc Date: Sat, 8 Apr 2023 14:02:35 -0500 Subject: brother/lw350.cpp: Added driver for Brother LW-350,LW-450 word processor. (#10998) New working systems --------------------- Brother LW-350 [BartmanAbyss] Brother LW-450 [BartmanAbyss] --- src/devices/machine/upd765.cpp | 159 +++++++ src/devices/machine/upd765.h | 29 ++ src/mame/brother/lw350.cpp | 909 +++++++++++++++++++++++++++++++++++++++++ src/mame/mame.lst | 4 + 4 files changed, 1101 insertions(+) create mode 100644 src/mame/brother/lw350.cpp diff --git a/src/devices/machine/upd765.cpp b/src/devices/machine/upd765.cpp index 2bacd5bdbf9..0ca0e4d72cf 100644 --- a/src/devices/machine/upd765.cpp +++ b/src/devices/machine/upd765.cpp @@ -57,6 +57,7 @@ DEFINE_DEVICE_TYPE(PC8477B, pc8477b_device, "pc8477b", "Nat DEFINE_DEVICE_TYPE(WD37C65C, wd37c65c_device, "wd37c65c", "Western Digital WD37C65C FDC") DEFINE_DEVICE_TYPE(MCS3201, mcs3201_device, "mcs3201", "Motorola MCS3201 FDC") DEFINE_DEVICE_TYPE(TC8566AF, tc8566af_device, "tc8566af", "Toshiba TC8566AF FDC") +DEFINE_DEVICE_TYPE(HD63266F, hd63266f_device, "hd63266f", "Hitachi HD63266F FDC") void upd765a_device::map(address_map &map) { @@ -3310,3 +3311,161 @@ void upd72069_device::auxcmd_w(uint8_t data) break; } } + + +hd63266f_device::hd63266f_device(const machine_config& mconfig, const char* tag, device_t* owner, uint32_t clock) +: upd765_family_device(mconfig, HD63266F, tag, owner, clock) +, inp_cb(*this) +{ + has_dor = false; +} + +void hd63266f_device::device_start() +{ + upd765_family_device::device_start(); + inp_cb.resolve(); +} + +void hd63266f_device::map(address_map& map) +{ + map(0x0, 0x0).rw(FUNC(upd765a_device::msr_r), FUNC(hd63266f_device::abort_w)); + map(0x1, 0x1).rw(FUNC(upd765a_device::fifo_r), FUNC(upd765a_device::fifo_w)); + map(0x2, 0x2).r(FUNC(hd63266f_device::extstat_r)); +} + +void hd63266f_device::soft_reset() +{ + upd765_family_device::soft_reset(); + delayed_command = 0; + motor_state = 0; + for(int i = 0; i < 4; i++) + if(flopi[i].dev) flopi[i].dev->mon_w(1); +} + +void hd63266f_device::abort_w(u8 data) +{ + if(data == 0xff) { + soft_reset(); + LOGCOMMAND("abort\n"); + } +} + +int hd63266f_device::check_command() +{ + switch(command[0] & 0x1f) { + case 0x0e: + return C_SLEEP; + } + return upd765_family_device::check_command(); +} + +void hd63266f_device::execute_command(int cmd) +{ + switch(cmd) + { + case C_SLEEP: + for(int i = 0; i < 4; i++) + if(flopi[i].dev) flopi[i].dev->mon_w(1); + main_phase = PHASE_CMD; + motor_state = 0; + LOGCOMMAND("sleep\n"); + break; + case C_SENSE_DRIVE_STATUS: + upd765_family_device::execute_command(cmd); + if(inp_cb) + result[0] = (result[0] & ~ST3_TS) | (inp_cb() ? 0 : 8); + break; + default: + upd765_family_device::execute_command(cmd); + break; + } +} + +u8 hd63266f_device::extstat_r() +{ + return (irq << 6) | motor_state; +} + +// no documentation for motor control so borrow some of 82072 +void hd63266f_device::start_command(int cmd) +{ + // check if the command specifies a target drive + switch(cmd) { + case C_READ_TRACK: + case C_WRITE_DATA: + case C_READ_DATA: + case C_RECALIBRATE: + //case C_WRITE_DELETED_DATA: + case C_READ_ID: + //case C_READ_DELETED_DATA: + case C_FORMAT_TRACK: + case C_SEEK: + // start the motor + motor_control(command[1] & 0x3, true); + break; + default: + motor_on_counter = 0; + break; + } + + // execute the command immediately if there's no motor on delay + if(motor_on_counter == 0) { + upd765_family_device::start_command(cmd); + } else + delayed_command = cmd; +} + +void hd63266f_device::motor_control(int fid, bool start_motor) +{ + floppy_info &fi = flopi[fid]; + + if(start_motor) { + // if we are selecting a different drive, stop the motor on the previously selected drive + if(selected_drive != fid && flopi[selected_drive].dev && flopi[selected_drive].dev->mon_r() == 0) + flopi[selected_drive].dev->mon_w(1); + + // start the motor on the selected drive + if(fi.dev && fi.dev->mon_r() == 1) { + LOGCOMMAND("motor_control: switching on motor for drive %d\n", fid); + + // select the drive and enable the motor + set_ds(fid); + fi.dev->mon_w(0); + motor_on_counter = 3; + motor_state |= 1 << fid; + } + } else { + // motor off timer only applies to the selected drive + if(selected_drive != fid) + return; + + logerror("motor_on_counter %d\n", motor_on_counter); + // decrement motor on counter + if(motor_on_counter) + motor_on_counter--; + + // execute the command if the motor on counter has expired + if(motor_on_counter == 0 && main_phase == PHASE_CMD && delayed_command) { + upd765_family_device::start_command(delayed_command); + + delayed_command = 0; + + return; + } + } +} + +void hd63266f_device::index_callback(floppy_image_device *floppy, int state) +{ + if(state) + for(floppy_info &fi : flopi) { + if(fi.dev != floppy) + continue; + + // update motor on/off counters and stop motor if necessary + motor_control(fi.id, false); + } + + upd765_family_device::index_callback(floppy, state); +} + diff --git a/src/devices/machine/upd765.h b/src/devices/machine/upd765.h index a6069a386b3..6c25022770e 100644 --- a/src/devices/machine/upd765.h +++ b/src/devices/machine/upd765.h @@ -280,6 +280,8 @@ protected: C_SCAN_HIGH, C_MOTOR_ONOFF, C_VERSION, + C_SLEEP, + C_ABORT, C_INVALID, C_INCOMPLETE @@ -593,6 +595,32 @@ private: uint8_t m_cr1; }; +class hd63266f_device : public upd765_family_device { +public: + hd63266f_device(const machine_config& mconfig, const char* tag, device_t* owner, uint32_t clock); + + virtual void map(address_map& map) override; + auto inp_rd_callback() { return inp_cb.bind(); } // this is really the ts signal + + void rate_w(u8 state) { state ? set_rate(500000) : set_rate(250000); } + void abort_w(u8 data); + u8 extstat_r(); +protected: + virtual void soft_reset() override; + virtual void device_start() override; +private: + virtual int check_command() override; + virtual void execute_command(int cmd) override; + virtual void start_command(int cmd) override; + void motor_control(int fid, bool start_motor); + virtual void index_callback(floppy_image_device *floppy, int state) override; + + u8 motor_on_counter; + int delayed_command; + u8 motor_state; + devcb_read_line inp_cb; +}; + DECLARE_DEVICE_TYPE(UPD765A, upd765a_device) DECLARE_DEVICE_TYPE(UPD765B, upd765b_device) DECLARE_DEVICE_TYPE(I8272A, i8272a_device) @@ -609,5 +637,6 @@ DECLARE_DEVICE_TYPE(PC8477B, pc8477b_device) DECLARE_DEVICE_TYPE(WD37C65C, wd37c65c_device) DECLARE_DEVICE_TYPE(MCS3201, mcs3201_device) DECLARE_DEVICE_TYPE(TC8566AF, tc8566af_device) +DECLARE_DEVICE_TYPE(HD63266F, hd63266f_device) #endif // MAME_DEVICES_MACHINE_UPD765_H diff --git a/src/mame/brother/lw350.cpp b/src/mame/brother/lw350.cpp new file mode 100644 index 00000000000..3f00cc9eee5 --- /dev/null +++ b/src/mame/brother/lw350.cpp @@ -0,0 +1,909 @@ +// license:BSD-3-Clause +// copyright-holders:Bartman/Abyss + +#include "emu.h" +#include "cpu/z180/z180.h" +#include "imagedev/floppy.h" +#include "machine/timer.h" +#include "sound/beep.h" +#include "video/mc6845.h" +#include "debug/debugcpu.h" +#include "emupal.h" +#include "screen.h" +#include "speaker.h" +#include "util/utf8.h" + +// command line parameters: +// -log -debug -window -intscalex 2 -intscaley 2 lw350 -resolution 960x256 -flop roms\lw350\Brother_LW-200-300_GW-24-45_Ver1.0_SpreadsheetProgramAndDataStorageDisk.img + +/*************************************************************************** + +Brother LW-350 +1995 + +Hardware: + +#4 +Hitachi HG62F33R63FH +US0021-A +CMOS Gate Array +3,297 gates, QFPS-136 +Murata Ceralock CST-MXW 16.00 MHz Ceramic Resonator + +#1 +Hitachi HD63266F +CMOS Floppy Disk Controller +QFP-64 +Murata Ceralock CST-MXW 16.00 MHz Ceramic Resonator + +#2 +Hitachi HM658128ALP-10 +01105330 +131072-word x 8-bit High Speed CMOS Pseudo Static RAM +DP-32 +100 ns + +#3 +Hitachi HN62334BP +UC6273-A-LWB6 +524288-word x 8-bit CMOS Mask Programmable ROM +DP-32 +150 ns + +#5 +Hitachi HD64180ZP8 +8-bit CMOS Micro Processing Unit +fully compatible with Zilog Z80180 (Z180) +8 MHz, DP-64S, Address Space 512 K Byte +Murata Ceralock CST-MXW 16.00 MHz Ceramic Resonator + +1.44MB Floppy Drive +MS-DOS compatible FAT12 disk format + +Hidden Keys during "DECKEL OFFEN!" ("Case Open!") +- Ctrl+Shift+Cursor Right: LCD Test Menu +- Ctrl+Shift+Backspace: Adjustment Printer Menu + +Hidden Keys during "SCHREIBMASCHINE" ("Typewriter") +- Ctrl+Shift+Cursor Right: LCD Test Menu +- Ctrl+Shift+Backspace: Self Test Menu +- Ctrl+Shift+Enter: Self Print Menu + +Emulation Status: +- Printer not working + +see https://github.com/BartmanAbyss/brother-hardware/tree/master/2G%20-%20Brother%20LW-350 for datasheets, photos + +***************************************************************************/ + +#include "machine/upd765.h" +#include "imagedev/floppy.h" + +class lw350_state : public driver_device +{ +public: + lw350_state(const machine_config &mconfig, device_type type, const char *tag) + : driver_device(mconfig, type, tag), + maincpu(*this, "maincpu"), + screen(*this, "screen"), + floppy(*this, "fdc:0"), + fdc(*this, "fdc"), + beeper(*this, "beeper"), + io_kbrow(*this, "kbrow.%u", 0), + rombank(*this, "rom"), + vram(*this, "vram") + { } + + void lw350(machine_config& config); + +protected: + // driver_device overrides + void machine_start() override; + void machine_reset() override; + void video_start() override; + +private: + // devices + required_device maincpu; + required_device screen; + required_device floppy; + required_device fdc; + required_device beeper; + required_ioport_array<9> io_kbrow; + required_memory_bank rombank; + + required_shared_ptr vram; + uint8_t io_70, io_b8, io_90; + int fdc_drq; + + // screen updates + uint32_t screen_update(screen_device& screen, bitmap_rgb32& bitmap, const rectangle& cliprect); + + uint8_t illegal_r(offs_t offset, uint8_t mem_mask = ~0) { + logerror("%s: unmapped memory read from %0*X & %0*X\n", machine().describe_context(), 6, offset, 2, mem_mask); + return 0; + } + void illegal_w(offs_t offset, uint8_t data, uint8_t mem_mask = ~0) { + logerror("%s: unmapped memory write to %0*X = %0*X & %0*X\n", machine().describe_context(), 6, offset, 2, data, 2, mem_mask); + } + + // IO + void io_70_w(uint8_t data) { + io_70 = data; + } + uint8_t io_74_r() { + // 0x00: 7 lines display (64 pixels height) + // 0x80: 14 lines display (128 pixels height) + return 0x80; + } + uint8_t io_a8_r() { + // bit 0: case open + // bit 2: carriage return indicator + //return 0x01; // case open + return 0x00; + } + uint8_t io_b8_r() { + // keyboard matrix + if(io_b8 <= 8) + return io_kbrow[io_b8]->read(); + + switch(io_b8) { + // get language + case 0x09: // valid results (see get_index_from_language) + //return ~0x20; // french + //return ~0x10; // french + //return ~0x08; // german + //return ~0x04; // french + //return ~0x02; // french + //return ~0x01; // german + return ~0x00; // german + default: return 0x00; + } + } + void io_b8_w(uint8_t data) { + io_b8 = data; + } + void rombank_w(uint8_t data) { // E0 + rombank->set_entry(data & 0x03); + } + void beeper_w(uint8_t data) { // F0 + beeper->set_state(data == 0); + } + void irqack_w(uint8_t) { // F8 + maincpu->set_input_line(INPUT_LINE_IRQ1, CLEAR_LINE); + } + + uint8_t io_7e_r() { + return 0x80; // 1.44mb floppy + } + void io_7e_w(uint8_t data) { // 7e + } + uint8_t io_90_r() { // 90 + return floppy ? (!floppy->get_device()->idx_r()) << 6 : 0; + } + + TIMER_DEVICE_CALLBACK_MEMBER(io_90_timer_callback); + TIMER_DEVICE_CALLBACK_MEMBER(int1_timer_callback); + + void map_program(address_map& map) { + map(0x00000, 0x01fff).rom(); + map(0x02000, 0x05fff).ram(); + map(0x06000, 0x3ffff).rom(); + map(0x40000, 0x5ffff).bankr("rom"); + map(0x60000, 0x617ff).ram(); + map(0x61800, 0x63fff).ram().share("vram"); + map(0x64000, 0x71fff).ram(); + map(0x72000, 0x75fff).rom().region("maincpu", 0x2000); // => ROM 0x02000-0x05fff + map(0x76000, 0x7ffff).ram(); + } + + void map_io(address_map& map) { + map.global_mask(0xff); + map(0x00, 0x3f).noprw(); // Z180 internal registers + map(0x70, 0x70).w(FUNC(lw350_state::io_70_w)); + map(0x74, 0x74).r(FUNC(lw350_state::io_74_r)); + + // floppy + map(0x78, 0x78).rw(fdc, FUNC(upd765a_device::msr_r), FUNC(hd63266f_device::abort_w)); + map(0x79, 0x79).lrw8([this](){ return (fdc_drq ? fdc->dma_r() : fdc->fifo_r()); }, "fdc_r", + [this](u8 data) { fdc_drq ? fdc->dma_w(data) : fdc->fifo_w(data); }, "fdc_w"); + map(0x7a, 0x7a).r(fdc, FUNC(hd63266f_device::extstat_r)); + map(0x7e, 0x7e).rw(FUNC(lw350_state::io_7e_r), FUNC(lw350_state::io_7e_w)); + map(0x90, 0x90).r(FUNC(lw350_state::io_90_r)); + + // printer + map(0xa8, 0xa8).r(FUNC(lw350_state::io_a8_r)); + + map(0xb8, 0xb8).rw(FUNC(lw350_state::io_b8_r), FUNC(lw350_state::io_b8_w)); + map(0xd8, 0xd8).nopw(); + map(0xe0, 0xe0).w(FUNC(lw350_state::rombank_w)); + map(0xf0, 0xf0).w(FUNC(lw350_state::beeper_w)); + map(0xf8, 0xf8).w(FUNC(lw350_state::irqack_w)); + + //map(0x40, 0xff).rw(FUNC(lw350_state::illegal_io_r), FUNC(lw350_state::illegal_io_w)); + } +}; + +void lw350_state::video_start() +{ +} + +uint32_t lw350_state::screen_update(screen_device& screen, bitmap_rgb32& bitmap, const rectangle& cliprect) +{ + // video on? + if(!BIT(io_70, 0)) + return 0; + + // backlight on? + //if(BIT(io_70, 7)) + //... + + const rgb_t palette[]{ + 0xffffffff, + 0xff000000, + }; + + for(auto y = 0; y < 128; y++) { + uint32_t* p = &bitmap.pix(y); + for(auto x = 0; x < 640; x += 8) { + auto gfx = vram[y * 80 + x / 8]; + //*p++ = palette[BIT(gfx, 7)]; + //*p++ = palette[BIT(gfx, 6)]; + *p++ = palette[BIT(gfx, 5)]; + *p++ = palette[BIT(gfx, 4)]; + *p++ = palette[BIT(gfx, 3)]; + *p++ = palette[BIT(gfx, 2)]; + *p++ = palette[BIT(gfx, 1)]; + *p++ = palette[BIT(gfx, 0)]; + } + } + return 0; +} + +static INPUT_PORTS_START(lw350) + PORT_START("kbrow.0") + PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_4) PORT_CHAR('4') PORT_CHAR('%') + PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_3) PORT_CHAR('3') PORT_CHAR(U'§') + PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_W) PORT_CHAR('w') PORT_CHAR('W') + PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_E) PORT_CHAR('e') PORT_CHAR('E') + PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_D) PORT_CHAR('d') PORT_CHAR('D') + PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_X) PORT_CHAR('x') PORT_CHAR('X') + PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_UNUSED) + PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_TAB) PORT_CHAR(UCHAR_MAMEKEY(TAB)) + + PORT_START("kbrow.1") + PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_5) PORT_CHAR('5') PORT_CHAR('%') + PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_6) PORT_CHAR('6') PORT_CHAR('&') + PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_R) PORT_CHAR('r') PORT_CHAR('R') + PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_T) PORT_CHAR('t') PORT_CHAR('T') + PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_C) PORT_CHAR('c') PORT_CHAR('C') + PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_F) PORT_CHAR('f') PORT_CHAR('F') + PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_UNUSED) + PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME(UTF8_UP) PORT_CODE(KEYCODE_UP) PORT_CHAR(UCHAR_MAMEKEY(UP)) + + PORT_START("kbrow.2") + PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_8) PORT_CHAR('8') PORT_CHAR('(') + PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_7) PORT_CHAR('7') PORT_CHAR('/') + PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_Z) PORT_CHAR('z') PORT_CHAR('Z') + PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_H) PORT_CHAR('h') PORT_CHAR('H') + PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_G) PORT_CHAR('g') PORT_CHAR('G') + PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_V) PORT_CHAR('v') PORT_CHAR('V') + PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_UNUSED) + PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("G.S.END") PORT_CODE(KEYCODE_END) PORT_CHAR(UCHAR_MAMEKEY(END)) + + PORT_START("kbrow.3") + PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_1) PORT_CHAR('1') PORT_CHAR('!') + PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_2) PORT_CHAR('2') PORT_CHAR('"') + 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_Y) PORT_CHAR('y') PORT_CHAR('Y') + PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_A) PORT_CHAR('a') PORT_CHAR('A') + PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_S) PORT_CHAR('s') PORT_CHAR('S') + PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_UNUSED) + PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_CAPSLOCK) PORT_CHAR(UCHAR_MAMEKEY(CAPSLOCK)) + + PORT_START("kbrow.4") + PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_9) PORT_CHAR('9') PORT_CHAR(')') + PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_J) PORT_CHAR('j') PORT_CHAR('J') + PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_I) PORT_CHAR('i') PORT_CHAR('I') + PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_U) PORT_CHAR('u') PORT_CHAR('U') + PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_B) PORT_CHAR('b') PORT_CHAR('B') + PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_N) PORT_CHAR('n') PORT_CHAR('N') + PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_UNUSED) + PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_RIGHT) PORT_CHAR(UCHAR_MAMEKEY(RIGHT)) + + PORT_START("kbrow.5") + PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_MINUS) PORT_CHAR(U'ß') PORT_CHAR('?') + PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_0) PORT_CHAR('0') PORT_CHAR('=') + PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_P) PORT_CHAR('p') PORT_CHAR('P') + PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_O) PORT_CHAR('o') PORT_CHAR('O') + PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_M) PORT_CHAR('m') PORT_CHAR('M') + PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_COMMA) PORT_CHAR(',') PORT_CHAR(';') + PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_UNUSED) + PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_MENU) PORT_CHAR(UCHAR_MAMEKEY(MENU)) + + PORT_START("kbrow.6") + PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Inhalt") PORT_CODE(KEYCODE_HOME) PORT_CHAR(UCHAR_MAMEKEY(HOME)) + PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_COLON) PORT_CHAR(U'ö') PORT_CHAR(U'Ö') + PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_CLOSEBRACE) PORT_CHAR('+') PORT_CHAR('*') + PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_OPENBRACE) PORT_CHAR(U'ü') PORT_CHAR(U'Ü') + PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_LEFT) PORT_CHAR(UCHAR_MAMEKEY(LEFT)) + PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_DOWN) PORT_CHAR(UCHAR_MAMEKEY(DOWN)) + PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_LCONTROL) PORT_CHAR(UCHAR_MAMEKEY(LCONTROL)) + PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_UNUSED) + + PORT_START("kbrow.7") + PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("SM/Layout") PORT_CODE(KEYCODE_PRTSCR) + PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("STORNO") PORT_CODE(KEYCODE_PAUSE) PORT_CHAR(UCHAR_MAMEKEY(CANCEL)) + PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_ENTER) PORT_CHAR(UCHAR_MAMEKEY(ENTER)) + PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_BACKSPACE) PORT_CHAR(UCHAR_MAMEKEY(BACKSPACE)) + PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) //PORT_CODE(KEYCODE_) + PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Horz/Vert") //PORT_CODE(KEYCODE_) + PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_SPACE) PORT_CHAR(UCHAR_MAMEKEY(SPACE)) + PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_LSHIFT) PORT_CHAR(UCHAR_SHIFT_1) + + PORT_START("kbrow.8") + PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_QUOTE) PORT_CHAR(U'´') PORT_CHAR(U'`') + PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_L) PORT_CHAR('l') PORT_CHAR('L') + PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_TILDE) PORT_CHAR('\'') PORT_CHAR(U'°') + PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_K) PORT_CHAR('k') PORT_CHAR('K') + PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_STOP) PORT_CHAR('.') PORT_CHAR(':') + PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_SLASH) PORT_CHAR('-') PORT_CHAR('_') + PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_QUOTE) PORT_CHAR(U'ä') PORT_CHAR(U'Ä') + PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_UNUSED) +INPUT_PORTS_END + +TIMER_DEVICE_CALLBACK_MEMBER(lw350_state::int1_timer_callback) +{ + maincpu->set_input_line(INPUT_LINE_IRQ1, ASSERT_LINE); +} + +//uint8_t char_attribute = 0x00; + +void lw350_state::machine_start() +{ + auto rom = memregion("maincpu")->base(); + rombank->configure_entries(0, 4, rom, 0x20000); + screen->set_visible_area(0, 480 - 1, 0, 128 - 1); + + fdc->set_floppy(floppy->get_device()); + + // ROM patches + + // force jump to self-test menu +// rom[0x280f2] = 0x20; +// rom[0x280f2+1] = 0x05; + + // force jump to lcd-test menu +// rom[0x280f2] = 0x2c; +// rom[0x280f2+1] = 0x05; + + // force jump to self-print menu +// rom[0x280f2] = 0x32; +// rom[0x280f2 + 1] = 0x05; + + // set initial mode + //rom[0x29a12] = 0x0a; + + // patch out printer init + rom[0x280df] = 0x00; + + // force RAM DOWN + //rom[0x280c3] = rom[0x280be]; + //rom[0x280c3 + 1] = rom[0x280be + 1]; + + // patch out self test bit 5 check; causes reboot loop + //rom[0x280c0] = 0x00; + //rom[0x280c1] = 0x00; + //rom[0x280c2] = 0x00; + + // force bold font + //rom[0x6b29] = 0x00; + //rom[0x6b29+1] = 0x00; + + // char attributes + //rom[0x6b47] = 0x3e; + //rom[0x6b48] = char_attribute; + //rom[0x6b49] = 0x00; + //rom[0x6b4a] = 0x00; + //rom[0x6b4b] = 0x00; + //rom[0x6b4c] = 0x00; +} + +void lw350_state::machine_reset() +{ + io_90 = 0x00; + fdc->reset(); + fdc_drq = 0; +} + +static void lw350_floppies(device_slot_interface& device) { + device.option_add("35dd", FLOPPY_35_DD); + device.option_add("35hd", FLOPPY_35_HD); +} + +void lw350_state::lw350(machine_config& config) { + // basic machine hardware + HD64180RP(config, maincpu, 16'000'000 / 2); + maincpu->set_addrmap(AS_PROGRAM, &lw350_state::map_program); + maincpu->set_addrmap(AS_IO, &lw350_state::map_io); + maincpu->tend0_wr_callback().set([this](int state){ fdc->tc_w((fdc_drq && state) ? 1 : 0); }); + maincpu->rts0_wr_callback().set(fdc, FUNC(hd63266f_device::rate_w)); + TIMER(config, "1khz").configure_periodic(FUNC(lw350_state::int1_timer_callback), attotime::from_hz(1000)); + + // video hardware + SCREEN(config, screen, SCREEN_TYPE_RASTER); + screen->set_color(rgb_t(6, 245, 206)); + screen->set_physical_aspect(480, 128); + screen->set_refresh_hz(78.1); + screen->set_screen_update(FUNC(lw350_state::screen_update)); + screen->set_size(480, 128); + + HD63266F(config, fdc, XTAL(16'000'000)); + fdc->drq_wr_callback().set([this](int state){ fdc_drq = state; maincpu->set_input_line(Z180_INPUT_LINE_DREQ0, state); }); + fdc->set_ready_line_connected(false); + fdc->set_select_lines_connected(false); + fdc->inp_rd_callback().set([this](){ return floppy->get_device()->dskchg_r(); }); + + FLOPPY_CONNECTOR(config, floppy, lw350_floppies, "35hd", floppy_image_device::default_pc_floppy_formats); + + // sound hardware + SPEAKER(config, "mono").front_center(); + BEEP(config, "beeper", 4'000).add_route(ALL_OUTPUTS, "mono", 1.0); // 4.0 kHz +} + +////////////////////////////////////////////////////////////////////////// +// LW-450 +////////////////////////////////////////////////////////////////////////// + +/*************************************************************************** + +Brother LW-450 +1992 + +Hardware: + +#13 +Hitachi +HD64180RF6X +8-bit CMOS Micro Processing Unit +fully compatible with Zilog Z80180 (Z180) +6 MHz, FP-80B, Address Space 1 M Byte +MuRata CST12MTW 12.00 MHz Ceramic Resonator + +#12 +Mitsubishi +M65020FP +UA7777-A + +#15 +Hitachi +HD74LS368AP + +#10, #11 +Hitachi +HD74LS157P + +#7, #8 +NEC +D41464C-10 +65,536 x 4-Bit +Dynamic NMOS RAM +100 ns +18-pin plastic DIP + +#1 +NEC +D23C4001EC-172 +UA2849-A +4MBit Mask ROM + +#2 +AMD +AM27C020 +2BC04 +2MBit (256K x 8-Bit) CMOS EPROM + +#3 +Hitachi +HM65256BSP-10 +32,768 word x 8-bit High Speed Pseudo Static RAM +100 ns +DP-28N + +#4 +Hitachi HD63266F +CMOS Floppy Disk Controller +QFP-64 +Murata Ceralock CST-MXW 16.00 MHz Ceramic Resonator + +#5 +Hitachi +HD6445P4 +CRTC-II (CRT Controller) +DP-40 +80 system Bus Interface +4.0 MHz Bus Timing + +#9 +Mitsubishi +M65133FP +UA7550-A + +#14 +Hitachi +HM62256AF-8 +32,768 word x 8-bit High Speed CMOS Static RAM +85 ns +FP-28 + +720kb Floppy Drive + +D-SUB9 CRT Connector +HSYNC 18.5 kHz +VSYNC 50 Hz +PC MDA standard + DB9 connector 1+2 GND, 3+4+5 nc, 6 Intensity, 7 Brightness, 8 HSync, 9 VSync + HSync positive, VSync negative active + +see https://github.com/BartmanAbyss/brother-hardware/tree/master/1G%20-%20Brother%20LW-450 for datasheets, photos + +Emulation Status: +Printer not working +Floppy Read has some problems (directory working, but LW-450 reports illegal file format when trying to load a .wpt file (content verified with LW-350), but writing seems fine) +Dictionary ROM probably not correctly mapped + +***************************************************************************/ + +constexpr int MDA_CLOCK = 16'257'000; + +class lw450_state : public driver_device +{ +public: + lw450_state(const machine_config& mconfig, device_type type, const char* tag) + : driver_device(mconfig, type, tag), + maincpu(*this, "maincpu"), + screen(*this, "screen"), + palette(*this, "palette"), + floppy(*this, "fdc:0"), + fdc(*this, "fdc"), + m_crtc(*this, "hd6445"), + vram(*this, "vram"), + speaker(*this, "beeper"), + io_kbrow(*this, "kbrow.%u", 0), + rom(*this, "maincpu"), + rombank(*this, "rom") + { } + + void lw450(machine_config& config); + +protected: + // driver_device overrides + void machine_start() override; + void machine_reset() override; + void video_start() override; + +private: + // devices + required_device maincpu; // use z80180 instead of hd64180rp, because hd64180rf doesn't have hd64180rp's 19-bit address width + required_device screen; + required_device palette; + required_device floppy; + required_device fdc; + required_device m_crtc; + required_shared_ptr vram; + required_device speaker; + required_ioport_array<9> io_kbrow; + required_region_ptr rom; + required_memory_bank rombank; + + uint8_t io_72, io_73, io_74, io_75; // gfx + uint8_t io_b8; + uint32_t framecnt; + + uint8_t illegal_r(offs_t offset) { + if(!machine().side_effects_disabled()) + logerror("%s: unmapped memory read from %0*X\n", machine().describe_context(), 6, offset); + return 0; + } + void illegal_w(offs_t offset, uint8_t data) { + if(!machine().side_effects_disabled()) + logerror("%s: unmapped memory write to %0*X = %0*X\n", machine().describe_context(), 6, offset, 2, data); + } + + uint8_t rom72000_r(offs_t offset) { + return rom[0x02000 + offset]; + } + + // IO + uint8_t io_b0_r() { return ~0x00; } + uint8_t io_b8_r() { + // keyboard matrix + if(io_b8 <= 8) + return io_kbrow[io_b8]->read(); + return 0x00; + } + void io_b8_w(uint8_t data) { + io_b8 = data; + } + void rombank_w(uint8_t data) { // E0 + if(data >= 4 && data < 8) + rombank->set_entry(data - 4); + } + void beeper_w(uint8_t data) { // F0 + speaker->set_state(data == 0); + } + void irqack_w(uint8_t) { // F8 + maincpu->set_input_line(INPUT_LINE_IRQ1, CLEAR_LINE); + } + + // CRTC + MC6845_UPDATE_ROW(crtc_update_row); + DECLARE_WRITE_LINE_MEMBER(crtc_vsync); + void io_72_w(uint8_t data) { io_72 = data; } + void io_73_w(uint8_t data) { io_73 = data; } + void io_74_w(uint8_t data); + void io_75_w(uint8_t data) { io_75 = data; } + + TIMER_DEVICE_CALLBACK_MEMBER(int1_timer_callback); + + void map_program(address_map& map); + void map_io(address_map& map); +}; + +void lw450_state::video_start() +{ +} + +void lw450_state::map_program(address_map& map) +{ + map(0x00000, 0x01fff).rom(); + map(0x02000, 0x05fff).ram(); + map(0x06000, 0x3ffff).rom(); + map(0x40000, 0x5ffff).bankr("dictionary"); + map(0x62000, 0x71fff).ram(); // D-RAM UPPER/LOWER + map(0x72000, 0x75fff).r(FUNC(lw450_state::rom72000_r)); // => ROM 0x02000-0x05fff + map(0x78000, 0x7ffff).ram(); // PS-RAM + map(0xf8000, 0xfffff).ram().share("vram"); // VRAM + // text vram @ F8000-F8C80 (2*80 bytes/line) + // font @ FC000-FD000 pitch 16 +} + +void lw450_state::map_io(address_map& map) +{ + map.global_mask(0xff); + map(0x00, 0x3f).noprw(); // Z180 internal registers + + map(0x70, 0x70).w("hd6445", FUNC(hd6345_device::address_w)); + map(0x71, 0x71).w("hd6445", FUNC(hd6345_device::register_w)); + map(0x72, 0x72).w(FUNC(lw450_state::io_72_w)); + map(0x73, 0x73).w(FUNC(lw450_state::io_73_w)); + map(0x74, 0x74).w(FUNC(lw450_state::io_74_w)); + map(0x75, 0x75).w(FUNC(lw450_state::io_75_w)); + + // floppy + map(0x78, 0x7a).m(fdc, FUNC(hd63266f_device::map)); + + map(0xb0, 0xb0).r(FUNC(lw450_state::io_b0_r)); + map(0xb8, 0xb8).rw(FUNC(lw450_state::io_b8_r), FUNC(lw450_state::io_b8_w)); + map(0xe0, 0xe0).w(FUNC(lw450_state::rombank_w)); + map(0xf0, 0xf0).w(FUNC(lw450_state::beeper_w)); + map(0xf8, 0xf8).w(FUNC(lw450_state::irqack_w)); + + //map(0x40, 0xff) AM_READWRITE(illegal_io_r, illegal_io_w) +} + +// CRTC +////////////////////////////////////////////////////////////////////////// + +TIMER_DEVICE_CALLBACK_MEMBER(lw450_state::int1_timer_callback) +{ + maincpu->set_input_line(INPUT_LINE_IRQ1, ASSERT_LINE); +} + +WRITE_LINE_MEMBER(lw450_state::crtc_vsync) +{ + if(state) { + framecnt++; + } +} + +void lw450_state::io_74_w(uint8_t data) +{ + io_74 = data; + if(io_74 & 0x04) { + // graphics mode + m_crtc->set_char_width(8); + m_crtc->set_clock(MDA_CLOCK / 8); + } else { + // text mode + m_crtc->set_char_width(9); + m_crtc->set_clock(MDA_CLOCK / 9); + } +} + +//(bitmap_rgb32 &bitmap, const rectangle &cliprect, uint16_t ma, uint8_t ra, uint16_t y, uint8_t x_count, int8_t cursor_x, int de, int hbp, int vbp) +MC6845_UPDATE_ROW(lw450_state::crtc_update_row) +{ + // IO 72 73 74 75 + // ============================ + // typewriter: 05 02 08 f8 text inverted + // crt test menu: 07 02 00 f8 text + // main menu: 05 02 0c f8 graphics inverted + + // based on LW-450 CRT Test Menu + enum attrs { + underline = 0b00000001, + extended_charset = 0b00000100, + bold = 0b00001000, + reverse = 0b00010000, + blink = 0b10000000, + }; + + const rgb_t *palette = this->palette->palette()->entry_list_raw(); + uint32_t* p = &bitmap.pix(y); + uint16_t chr_base = ra; + + // video off + if(!(io_72 & 0b1)) { + for(int x = 0; x < cliprect.width(); x++) + *p++ = palette[0]; + return; + } + + // graphics mode + if(io_74 & 0x04) { + uint8_t bg = 0, fg = 1; + // inverse display + if(!(io_72 & 0x02)) + std::swap(bg, fg); + + for(int x = 0; x < x_count; x++) { + auto data = vram[(ma + x + (ra << 14)) & 0x7fff]; + *p++ = palette[(data & 0x80) ? fg : bg]; + *p++ = palette[(data & 0x40) ? fg : bg]; + *p++ = palette[(data & 0x20) ? fg : bg]; + *p++ = palette[(data & 0x10) ? fg : bg]; + *p++ = palette[(data & 0x08) ? fg : bg]; + *p++ = palette[(data & 0x04) ? fg : bg]; + *p++ = palette[(data & 0x02) ? fg : bg]; + *p++ = palette[(data & 0x01) ? fg : bg]; + } + } else { + // text mode + auto charram = &vram[0]; + auto fontram = &vram[0x4000]; + + for(int x = 0; x < x_count; x++) { + uint16_t offset = ((ma + x) << 1) & 0x0FFF; + auto atr = charram[offset]; + uint32_t chr = charram[offset + 1]; + if(atr & extended_charset) chr += 0x100; + auto data = fontram[chr_base + chr * 16]; + uint8_t bit9 = 0x00; + if(atr & extended_charset) bit9 = BIT(data, 0) ? 0xff : 0x00; + uint8_t bg = 0, fg = 1; + + if(atr & bold) + fg = 2; + + // inverse display + if(!(io_72 & 0x02)) + std::swap(bg, fg); + + if((atr & underline) && ra == 13) { + data = bit9 = 0xff; + } + if(atr & reverse) + std::swap(bg, fg); + + if(x == cursor_x) { + data = 0xff; + bit9 = 0x00; + } else { + if((atr & blink) && (framecnt & 0x10)) // TODO: check blinking frequency + data = 0x00; + } + + for(int b = 0; b < 8; b++) + *p++ = BIT(data, 7 - b) ? palette[fg] : palette[bg]; + *p++ = BIT(bit9, 7) ? palette[fg] : palette[bg]; + } + } +} + +// PIN 21 (Character Clock) of CRTC-II: menu: 2.0 MHz; schreibmaschine: 1.8 MHz + +// these timings are all at MDA clock +// bootup: [:hd6445] M6845 config screen: HTOTAL: 882 VTOTAL: 370 MAX_X: 719 MAX_Y: 319 HSYNC: 729-863 VSYNC: 320-335 Freq: 49.816133fps +// menu: [:hd6445] M6845 config screen: HTOTAL: 990 VTOTAL: 370 MAX_X: 809 MAX_Y: 319 HSYNC: 819-953 VSYNC: 334-349 Freq: 44.381646fps +// schreibmaschine: [:hd6445] M6845 config screen: HTOTAL: 882 VTOTAL: 370 MAX_X: 719 MAX_Y: 319 HSYNC: 729-863 VSYNC: 320-335 Freq: 49.816133fps + +void lw450_state::machine_start() +{ + rombank->configure_entries(0, 4, memregion("dictionary")->base(), 0x20000); + + palette->set_pen_color(0, rgb_t(0, 0, 0)); + palette->set_pen_color(1, rgb_t(0xaa, 0xaa, 0xaa)); + palette->set_pen_color(2, rgb_t(0xff, 0xff, 0xff)); + + // patch out printer init + rom[0x280db] = 0x00; +} + +void lw450_state::machine_reset() +{ + framecnt = 0; +} + +static const gfx_layout pc_16_charlayout { + 8, 16, // 8 x 16 characters + 256, // 256 characters + 1, // 1 bits per pixel + { 0 }, // no bitplanes + { 0, 1, 2, 3, 4, 5, 6, 7 }, // x offsets + { 0 * 8, 1 * 8, 2 * 8, 3 * 8, 4 * 8, 5 * 8, 6 * 8, 7 * 8, 8 * 8, 9 * 8, 10 * 8, 11 * 8, 12 * 8, 13 * 8, 14 * 8, 15 * 8 }, // y offsets + 16*8 // every char takes 2 x 8 bytes +}; + +static GFXDECODE_START( gfx_lw450 ) + GFXDECODE_RAM("vram", 0x4000, pc_16_charlayout, 0, 1) +GFXDECODE_END + +void lw450_state::lw450(machine_config& config) { + // basic machine hardware + Z80180(config, maincpu, 12'000'000 / 2); + maincpu->set_addrmap(AS_PROGRAM, &lw450_state::map_program); + maincpu->set_addrmap(AS_IO, &lw450_state::map_io); + maincpu->tend0_wr_callback().set(fdc, FUNC(hd63266f_device::tc_line_w)); + TIMER(config, "1khz").configure_periodic(FUNC(lw450_state::int1_timer_callback), attotime::from_hz(1000)); + + // video hardware + SCREEN(config, screen, SCREEN_TYPE_RASTER); + screen->set_color(rgb_t::white()); + screen->set_physical_aspect(720, 320); + screen->set_screen_update("hd6445", FUNC(hd6345_device::screen_update)); + screen->set_raw(MDA_CLOCK, 882, 0, 729, 370, 0, 320); // based on bootup crtc values + + GFXDECODE(config, "gfxdecode", palette, gfx_lw450); + PALETTE(config, palette).set_entries(4); + + // CRTC + HD6345(config, m_crtc, MDA_CLOCK / 9); + m_crtc->set_screen(screen); + m_crtc->set_show_border_area(false); + m_crtc->set_char_width(9); + m_crtc->set_update_row_callback(FUNC(lw450_state::crtc_update_row)); + m_crtc->out_vsync_callback().set(FUNC(lw450_state::crtc_vsync)); + + HD63266F(config, fdc, XTAL(16'000'000)); + fdc->drq_wr_callback().set_inputline(maincpu, Z180_INPUT_LINE_DREQ0); + fdc->set_ready_line_connected(false); + fdc->set_select_lines_connected(false); + + FLOPPY_CONNECTOR(config, floppy, lw350_floppies, "35hd", floppy_image_device::default_pc_floppy_formats); + + // sound hardware + SPEAKER(config, "mono").front_center(); + BEEP(config, "beeper", 4'000).add_route(ALL_OUTPUTS, "mono", 1.0); // 4.0 kHz +} + +/*************************************************************************** + Machine driver(s) +***************************************************************************/ + +ROM_START( lw350 ) + ROM_REGION( 0x80000, "maincpu", 0 ) + ROM_LOAD("uc6273-a-lwb6", 0x00000, 0x80000, CRC(5E85D1EC) SHA1(4ca68186fc70f30ccac95429604c88db4f0c34d2)) +// ROM_LOAD("patched", 0x00000, 0x80000, CRC(5E85D1EC) SHA1(4ca68186fc70f30ccac95429604c88db4f0c34d2)) +ROM_END + +ROM_START( lw450 ) + ROM_REGION( 0x40000, "maincpu", 0 ) + ROM_LOAD("2bc04", 0x00000, 0x40000, CRC(96C2A6F1) SHA1(eb47e37ea46e3becc1b4453286f120682a0a1ddc)) + ROM_REGION(0x80000, "dictionary", 0) + ROM_LOAD("ua2849-a", 0x00000, 0x80000, CRC(FA8712EB) SHA1(2d3454138c79e75604b30229c05ed8fb8e7d15fe)) +ROM_END + +// YEAR NAME PARENT COMPAT MACHINE INPUT CLASS INIT COMPANY FULLNAME FLAGS +COMP( 1995, lw350, 0, 0, lw350, lw350, lw350_state, empty_init, "Brother", "Brother LW-350", MACHINE_NODEVICE_PRINTER ) +COMP( 1992, lw450, 0, 0, lw450, lw350, lw450_state, empty_init, "Brother", "Brother LW-450", MACHINE_NODEVICE_PRINTER ) diff --git a/src/mame/mame.lst b/src/mame/mame.lst index ae2204dcd0f..cdd39187b70 100755 --- a/src/mame/mame.lst +++ b/src/mame/mame.lst @@ -14795,6 +14795,10 @@ ax145 // Brother AX-145 (c) 198? Brother Industries, L @source:brother/lw30.cpp lw30 // Brother LW-30 (c) 1991 Brother Industries, Ltd. +@source:brother/lw350.cpp +lw350 // Brother LW-350 (c) 1995 Brother Industries, Ltd. +lw450 // Brother LW-450 (c) 1992 Brother Industries, Ltd. + @source:brother/lw700i.cpp lw700i // (c) 1995 Brother -- cgit v1.2.3