diff --git a/src/mame/drivers/lnw80.cpp b/src/mame/drivers/lnw80.cpp index 988f97c4a0e..efcc022b165 100644 --- a/src/mame/drivers/lnw80.cpp +++ b/src/mame/drivers/lnw80.cpp @@ -3,8 +3,7 @@ /*************************************************************************** Memory map -0000-2fff ROM R D0-D7 -3000-37ff ROM R D0-D7 +0000-37ff ROM R D0-D7 37de UART status R/W D0-D7 37df UART data R/W D0-D7 37e0 for the realtime clock @@ -79,50 +78,17 @@ To Do / Status: *******************************************************************************************************/ #include "emu.h" -#include "bus/centronics/ctronics.h" -#include "cpu/z80/z80.h" +#include "includes/trs80.h" #include "machine/bankdev.h" -#include "imagedev/cassette.h" -#include "imagedev/floppy.h" -#include "imagedev/snapquik.h" -#include "machine/ay31015.h" -#include "machine/clock.h" -#include "bus/rs232/rs232.h" -#include "machine/buffer.h" -#include "machine/wd_fdc.h" -#include "sound/spkrdev.h" -#include "emupal.h" -#include "screen.h" -#include "speaker.h" #include "formats/td0_dsk.h" -#include "formats/trs80_dsk.h" -class lnw80_state : public driver_device +class lnw80_state : public trs80_state { public: lnw80_state(const machine_config &mconfig, device_type type, const char *tag) - : driver_device(mconfig, type, tag) - , m_maincpu(*this, "maincpu") - , m_region_maincpu(*this, "maincpu") - , m_p_chargen(*this, "chargen") - , m_p_videoram(*this, "videoram") + : trs80_state(mconfig, type, tag) , m_p_gfxram(*this, "gfxram") , m_lnw_bank(*this, "lnw_banked_mem") - , m_centronics(*this, "centronics") - , m_cent_data_out(*this, "cent_data_out") - , m_cent_status_in(*this, "cent_status_in") - , m_uart(*this, "uart") - , m_uart_clock(*this, "uart_clock") - , m_fdc(*this, "fdc") - , m_floppy0(*this, "fdc:0") - , m_floppy1(*this, "fdc:1") - , m_floppy2(*this, "fdc:2") - , m_floppy3(*this, "fdc:3") - , m_speaker(*this, "speaker") - , m_cassette(*this, "cassette") - , m_io_baud(*this, "BAUD") - , m_io_config(*this, "CONFIG") - , m_io_keyboard(*this, "LINE%u", 0) { } void lnw80(machine_config &config); @@ -133,66 +99,18 @@ protected: private: static void floppy_formats(format_registration &fr); - void port_ff_w(uint8_t data); void lnw80_fe_w(uint8_t data); - void port_ea_w(uint8_t data); - void port_e8_w(uint8_t data); uint8_t lnw80_fe_r(); - uint8_t port_ff_r(); - uint8_t port_ea_r(); - uint8_t port_e8_r(); - uint8_t irq_status_r(); - uint8_t printer_r(); - void printer_w(uint8_t data); - void motor_w(uint8_t data); - uint8_t keyboard_r(offs_t offset); - u8 fdc_r(offs_t offset); - void fdc_w(offs_t offset, u8 data); - - INTERRUPT_GEN_MEMBER(rtc_interrupt); - INTERRUPT_GEN_MEMBER(fdc_interrupt); - TIMER_CALLBACK_MEMBER(cassette_data_callback); - DECLARE_WRITE_LINE_MEMBER(intrq_w); - DECLARE_QUICKLOAD_LOAD_MEMBER(quickload_cb); void lnw80_palette(palette_device &palette) const; - uint32_t screen_update_lnw80(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect); + uint32_t screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect); void lnw80_io(address_map &map); void lnw80_mem(address_map &map); void lnw_banked_mem(address_map &map); - bool m_mode; - uint8_t m_irq; - uint8_t m_mask; - bool m_reg_load; u8 m_lnw_mode; - bool m_cassette_data; - emu_timer *m_cassette_data_timer; - double m_old_cassette_val; - uint8_t m_size_store; - uint16_t m_timeout; - floppy_image_device *m_floppy; - required_device m_maincpu; - required_memory_region m_region_maincpu; - required_region_ptr m_p_chargen; - required_shared_ptr m_p_videoram; required_shared_ptr m_p_gfxram; required_device m_lnw_bank; - required_device m_centronics; - required_device m_cent_data_out; - required_device m_cent_status_in; - required_device m_uart; - required_device m_uart_clock; - required_device m_fdc; - required_device m_floppy0; - required_device m_floppy1; - required_device m_floppy2; - required_device m_floppy3; - required_device m_speaker; - required_device m_cassette; - required_ioport m_io_baud; - required_ioport m_io_config; - required_ioport_array<8> m_io_keyboard; }; @@ -363,21 +281,6 @@ static INPUT_PORTS_START( lnw80 ) PORT_DIPSETTING( 0x07, "19200") INPUT_PORTS_END -#define IRQ_M1_RTC 0x80 /* RTC on Model I */ -#define IRQ_M1_FDC 0x40 /* FDC on Model I */ - - -TIMER_CALLBACK_MEMBER(lnw80_state::cassette_data_callback) -{ - double new_val = (m_cassette->input()); - - /* Check for HI-LO transition */ - if ( m_old_cassette_val > -0.2 && new_val < -0.2 ) - m_cassette_data = true; - - m_old_cassette_val = new_val; -} - /************************************* * @@ -386,98 +289,11 @@ TIMER_CALLBACK_MEMBER(lnw80_state::cassette_data_callback) *************************************/ -uint8_t lnw80_state::port_e8_r() -{ -/* not emulated - d7 Clear-to-Send (CTS), Pin 5 - d6 Data-Set-Ready (DSR), pin 6 - d5 Carrier Detect (CD), pin 8 - d4 Ring Indicator (RI), pin 22 - d3,d2,d0 Not used - d1 UART Receiver Input, pin 20 (pin 20 is also DTR) */ - - return 0; -} - -uint8_t lnw80_state::port_ea_r() -{ -/* UART Status Register - d7 Data Received ('1'=condition true) - d6 Transmitter Holding Register empty ('1'=condition true) - d5 Overrun Error ('1'=condition true) - d4 Framing Error ('1'=condition true) - d3 Parity Error ('1'=condition true) - d2..d0 Not used */ - - uint8_t data=7; - m_uart->write_swe(0); - data |= m_uart->tbmt_r() ? 0x40 : 0; - data |= m_uart->dav_r( ) ? 0x80 : 0; - data |= m_uart->or_r( ) ? 0x20 : 0; - data |= m_uart->fe_r( ) ? 0x10 : 0; - data |= m_uart->pe_r( ) ? 0x08 : 0; - m_uart->write_swe(1); - - return data; -} - -void lnw80_state::port_e8_w(uint8_t data) -{ - m_reg_load = BIT(data, 1); -} - -void lnw80_state::port_ea_w(uint8_t data) -{ - if (m_reg_load) - -/* d2..d0 not emulated - d7 Even Parity Enable ('1'=even, '0'=odd) - d6='1',d5='1' for 8 bits - d6='0',d5='1' for 7 bits - d6='1',d5='0' for 6 bits - d6='0',d5='0' for 5 bits - d4 Stop Bit Select ('1'=two stop bits, '0'=one stop bit) - d3 Parity Inhibit ('1'=disable; No parity, '0'=parity enabled) - d2 Break ('0'=disable transmit data; continuous RS232 'SPACE' condition) - d1 Request-to-Send (RTS), pin 4 - d0 Data-Terminal-Ready (DTR), pin 20 */ - - { - m_uart->write_cs(0); - m_uart->write_nb1(BIT(data, 6)); - m_uart->write_nb2(BIT(data, 5)); - m_uart->write_tsb(BIT(data, 4)); - m_uart->write_eps(BIT(data, 7)); - m_uart->write_np(BIT(data, 3)); - m_uart->write_cs(1); - } - else - { -/* not emulated - d7,d6 Not used - d5 Secondary Unassigned, pin 18 - d4 Secondary Transmit Data, pin 14 - d3 Secondary Request-to-Send, pin 19 - d2 Break ('0'=disable transmit data; continuous RS232 'SPACE' condition) - d1 Data-Terminal-Ready (DTR), pin 20 - d0 Request-to-Send (RTS), pin 4 */ - - } -} - uint8_t lnw80_state::lnw80_fe_r() { return m_lnw_mode; } -uint8_t lnw80_state::port_ff_r() -{ -/* ModeSel and cassette data - d7 cassette data from tape - d6 modesel setting */ - - return (m_mode ? 0 : 0x40) | (m_cassette_data ? 0x80 : 0) | 0x3f; -} /* lnw80 can switch out all the devices, roms and video ram to be replaced by graphics ram. */ void lnw80_state::lnw80_fe_w(uint8_t data) @@ -493,147 +309,6 @@ void lnw80_state::lnw80_fe_w(uint8_t data) m_lnw_bank->set_bank(BIT(data, 3)); } -void lnw80_state::port_ff_w(uint8_t data) -{ -/* Standard output port of Model I - d3 ModeSel bit - d2 Relay - d1, d0 Cassette output */ - - static const double levels[4] = { 0.0, 1.0, -1.0, 0.0 }; - - m_cassette->change_state(BIT(data, 2) ? CASSETTE_MOTOR_ENABLED : CASSETTE_MOTOR_DISABLED, CASSETTE_MASK_MOTOR ); - m_cassette->output(levels[data & 3]); - m_cassette_data = false; - - m_mode = BIT(data, 3); - - static const double speaker_levels[4] = { 0.0, -1.0, 0.0, 1.0 }; - m_speaker->set_levels(4, speaker_levels); - m_speaker->level_w(data & 3); -} - -/************************************* - * - * Interrupt handlers. - * - *************************************/ - -INTERRUPT_GEN_MEMBER(lnw80_state::rtc_interrupt) -{ -/* This enables the processing of interrupts for the clock and the flashing cursor. - The OS counts one tick for each interrupt. It is called 40 times per second. */ - - m_irq |= IRQ_M1_RTC; - m_maincpu->set_input_line(0, HOLD_LINE); - - // While we're here, let's countdown the motor timeout too. - // Let's not... LDOS often freezes -// if (m_timeout) -// { -// m_timeout--; -// if (m_timeout == 0) -// if (m_floppy) -// m_floppy->mon_w(1); // motor off -// } -} - - -WRITE_LINE_MEMBER(lnw80_state::intrq_w) -{ - if (state) - { - m_irq |= IRQ_M1_FDC; - m_maincpu->set_input_line(0, HOLD_LINE); - } - else - m_irq &= ~IRQ_M1_FDC; -} - - -/************************************* - * * - * Memory handlers * - * * - *************************************/ - -u8 lnw80_state::fdc_r(offs_t offset) -{ - if ((offset == 0) && (!BIT(m_io_config->read(), 7))) - return 0xff; - else - return m_fdc->read(offset) ^ 0xff; -} - -void lnw80_state::fdc_w(offs_t offset, u8 data) -{ - m_fdc->write(offset, data ^ 0xff); -} - -uint8_t lnw80_state::printer_r() -{ - return m_cent_status_in->read(); -} - -void lnw80_state::printer_w(uint8_t data) -{ - m_cent_data_out->write(data); - m_centronics->write_strobe(0); - m_centronics->write_strobe(1); -} - -uint8_t lnw80_state::irq_status_r() -{ -/* (trs80l2) Whenever an interrupt occurs, 37E0 is read to see what devices require service. - d7 = RTC - d6 = FDC - d2 = Communications (not emulated) - All interrupting devices are serviced in a single interrupt. There is a mask byte, - which is dealt with by the DOS. We take the opportunity to reset the cpu INT line. */ - - u8 result = m_irq; - m_maincpu->set_input_line(0, CLEAR_LINE); - m_irq = 0; - return result; -} - - -void lnw80_state::motor_w(uint8_t data) -{ - m_floppy = nullptr; - - if (BIT(data, 0)) m_floppy = m_floppy0->get_device(); - if (BIT(data, 1)) m_floppy = m_floppy1->get_device(); - if (BIT(data, 2)) m_floppy = m_floppy2->get_device(); - if (BIT(data, 3)) m_floppy = m_floppy3->get_device(); - - m_fdc->set_floppy(m_floppy); - - if (m_floppy) - { - m_floppy->mon_w(0); - m_floppy->ss_w(BIT(data, 4)); - m_timeout = 200; - } - - // switch to fm - m_fdc->dden_w(1); -} - -/************************************* - * Keyboard * - *************************************/ -uint8_t lnw80_state::keyboard_r(offs_t offset) -{ - u8 i, result = 0; - - for (i = 0; i < 8; i++) - if (BIT(offset, i)) - result |= m_io_keyboard[i]->read(); - - return result; -} - /************************************* * Machine * @@ -671,95 +346,8 @@ void lnw80_state::machine_reset() lnw80_fe_w(0); } - -/*************************************************************************** - PARAMETERS -***************************************************************************/ - -#define LOG 1 - -#define CMD_TYPE_OBJECT_CODE 0x01 -#define CMD_TYPE_TRANSFER_ADDRESS 0x02 -#define CMD_TYPE_END_OF_PARTITIONED_DATA_SET_MEMBER 0x04 -#define CMD_TYPE_LOAD_MODULE_HEADER 0x05 -#define CMD_TYPE_PARTITIONED_DATA_SET_HEADER 0x06 -#define CMD_TYPE_PATCH_NAME_HEADER 0x07 -#define CMD_TYPE_ISAM_DIRECTORY_ENTRY 0x08 -#define CMD_TYPE_END_OF_ISAM_DIRECTORY_ENTRY 0x0a -#define CMD_TYPE_PDS_DIRECTORY_ENTRY 0x0c -#define CMD_TYPE_END_OF_PDS_DIRECTORY_ENTRY 0x0e -#define CMD_TYPE_YANKED_LOAD_BLOCK 0x10 -#define CMD_TYPE_COPYRIGHT_BLOCK 0x1f - -/*************************************************************************** - IMPLEMENTATION -***************************************************************************/ - -QUICKLOAD_LOAD_MEMBER(lnw80_state::quickload_cb) -{ - address_space &program = m_maincpu->space(AS_PROGRAM); - - uint8_t type, length; - uint8_t data[0x100]; - uint8_t addr[2]; - void *ptr; - - while (!image.image_feof()) - { - image.fread( &type, 1); - image.fread( &length, 1); - - switch (type) - { - case CMD_TYPE_OBJECT_CODE: // 01 - block of data - { - length -= 2; - u16 block_length = length ? length : 256; - image.fread( &addr, 2); - u16 address = (addr[1] << 8) | addr[0]; - if (LOG) logerror("/CMD object code block: address %04x length %u\n", address, block_length); - if (address < 0x3c00) - { - image.message("Attempting to write outside of RAM"); - return image_init_result::FAIL; - } - ptr = program.get_write_ptr(address); - image.fread( ptr, block_length); - } - break; - - case CMD_TYPE_TRANSFER_ADDRESS: // 02 - go address - { - image.fread( &addr, 2); - u16 address = (addr[1] << 8) | addr[0]; - if (LOG) logerror("/CMD transfer address %04x\n", address); - m_maincpu->set_state_int(Z80_PC, address); - } - return image_init_result::PASS; - - case CMD_TYPE_LOAD_MODULE_HEADER: // 05 - name - image.fread( &data, length); - if (LOG) logerror("/CMD load module header '%s'\n", data); - break; - - case CMD_TYPE_COPYRIGHT_BLOCK: // 1F - copyright info - image.fread( &data, length); - if (LOG) logerror("/CMD copyright block '%s'\n", data); - break; - - default: - image.fread( &data, length); - logerror("/CMD unsupported block type %u!\n", type); - image.message("Unsupported or invalid block type"); - return image_init_result::FAIL; - } - } - - return image_init_result::PASS; -} - /* 8-bit video, 64/80 characters per line = lnw80 */ -uint32_t lnw80_state::screen_update_lnw80(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect) +uint32_t lnw80_state::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect) { static const uint16_t rows[] = { 0, 0x200, 0x100, 0x300, 1, 0x201, 0x101, 0x301 }; uint16_t sy=0,ma=0; @@ -996,7 +584,7 @@ void lnw80_state::lnw80(machine_config &config) screen_device &screen(SCREEN(config, "screen", SCREEN_TYPE_RASTER)); // LNW80 Theory of Operations gives H and V periods as 15.750kHz and 59.66Hz, probably due to rounding the calculated ~15.7468kHz to 4 figures screen.set_raw(3.579545_MHz_XTAL * 3, 682, 0, 480, 264, 0, 192); // 10.738MHz generated by tank circuit (top left of page 2 of schematics) - screen.set_screen_update(FUNC(lnw80_state::screen_update_lnw80)); + screen.set_screen_update(FUNC(lnw80_state::screen_update)); screen.set_palette("palette"); PALETTE(config, "palette", FUNC(lnw80_state::lnw80_palette), 8); GFXDECODE(config, "gfxdecode", "palette", gfx_lnw80);