mirror of
https://github.com/holub/mame
synced 2025-04-16 05:24:54 +03:00
lnw80: used derived class to reduce number of duplicate functions.
This commit is contained in:
parent
92ebbbaee1
commit
1da36f8ce5
@ -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<cpu_device> m_maincpu;
|
||||
required_memory_region m_region_maincpu;
|
||||
required_region_ptr<u8> m_p_chargen;
|
||||
required_shared_ptr<u8> m_p_videoram;
|
||||
required_shared_ptr<u8> m_p_gfxram;
|
||||
required_device<address_map_bank_device> m_lnw_bank;
|
||||
required_device<centronics_device> m_centronics;
|
||||
required_device<output_latch_device> m_cent_data_out;
|
||||
required_device<input_buffer_device> m_cent_status_in;
|
||||
required_device<ay31015_device> m_uart;
|
||||
required_device<clock_device> m_uart_clock;
|
||||
required_device<fd1771_device> m_fdc;
|
||||
required_device<floppy_connector> m_floppy0;
|
||||
required_device<floppy_connector> m_floppy1;
|
||||
required_device<floppy_connector> m_floppy2;
|
||||
required_device<floppy_connector> m_floppy3;
|
||||
required_device<speaker_sound_device> m_speaker;
|
||||
required_device<cassette_image_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);
|
||||
|
Loading…
Reference in New Issue
Block a user