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]
This commit is contained in:
cracyc 2023-04-08 14:02:35 -05:00
parent b94a5f9d6a
commit e8fbb39587
4 changed files with 1101 additions and 0 deletions

View File

@ -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);
}

View File

@ -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

909
src/mame/brother/lw350.cpp Normal file
View File

@ -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<hd64180rp_device> maincpu;
required_device<screen_device> screen;
required_device<floppy_connector> floppy;
required_device<hd63266f_device> fdc;
required_device<beep_device> beeper;
required_ioport_array<9> io_kbrow;
required_memory_bank rombank;
required_shared_ptr<u8> 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<z80180_device> maincpu; // use z80180 instead of hd64180rp, because hd64180rf doesn't have hd64180rp's 19-bit address width
required_device<screen_device> screen;
required_device<palette_device> palette;
required_device<floppy_connector> floppy;
required_device<hd63266f_device> fdc;
required_device<hd6345_device> m_crtc;
required_shared_ptr<uint8_t> vram;
required_device<beep_device> speaker;
required_ioport_array<9> io_kbrow;
required_region_ptr<uint8_t> 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 )

View File

@ -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