summaryrefslogtreecommitdiffstatshomepage
path: root/src/mame/machine/aim65.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/mame/machine/aim65.cpp')
-rw-r--r--src/mame/machine/aim65.cpp424
1 files changed, 424 insertions, 0 deletions
diff --git a/src/mame/machine/aim65.cpp b/src/mame/machine/aim65.cpp
new file mode 100644
index 00000000000..3e7d4f2a309
--- /dev/null
+++ b/src/mame/machine/aim65.cpp
@@ -0,0 +1,424 @@
+// license:GPL-2.0+
+// copyright-holders:Peter Trauner, Dan Boris, Dirk Best, Robbbert
+/******************************************************************************
+
+ AIM65
+
+******************************************************************************/
+
+
+#include "includes/aim65.h"
+
+
+/******************************************************************************
+ Interrupt handling
+******************************************************************************/
+
+/* STEP/RUN
+ *
+ * Switch S2 (STEP/RUN) causes AIM 65 to operate either in the RUN mode or the
+ * single STEP mode. In the STEP mode, the NMI interrupt line is driven low
+ * when SYNC and O2 go high during instruction execution if the address lines
+ * are outside the A000-FFFF range. The NMI interrupt occurs on the high to
+ * low transition of the NMI line. The Monitor software will trace instructions
+ * and register, outside the Monitor instruction address range if the trace
+ * modes are selected and the NMI Interrupt Routine is not bypassed.
+ */
+
+
+
+/******************************************************************************
+ 6821 PIA
+******************************************************************************/
+
+/* PA0: A0 (Address)
+ * PA1: A1 (Address)
+ * PA2: CE1 (Chip enable)
+ * PA3: CE2 (Chip enable)
+ * PA4: CE3 (Chip enable)
+ * PA5: CE4 (Chip enable)
+ * PA6: CE5 (Chip enable)
+ * PA7: W (Write enable)
+ * PB0-6: D0-D6 (Data)
+ * PB7: CU (Cursor)
+ */
+
+void aim65_state::dl1416_update(dl1416_device *device, int index)
+{
+ device->ce_w(m_pia_a & (0x04 << index));
+ device->wr_w(BIT(m_pia_a, 7));
+ device->cu_w(BIT(m_pia_b, 7));
+ device->data_w(generic_space(), m_pia_a & 0x03, m_pia_b & 0x7f);
+}
+
+void aim65_state::aim65_pia()
+{
+ dl1416_update(m_ds1, 0);
+ dl1416_update(m_ds2, 1);
+ dl1416_update(m_ds3, 2);
+ dl1416_update(m_ds4, 3);
+ dl1416_update(m_ds5, 4);
+}
+
+
+WRITE8_MEMBER( aim65_state::aim65_pia_a_w )
+{
+ m_pia_a = data;
+ aim65_pia();
+}
+
+
+WRITE8_MEMBER( aim65_state::aim65_pia_b_w )
+{
+ m_pia_b = data;
+ aim65_pia();
+}
+
+
+WRITE16_MEMBER( aim65_state::aim65_update_ds1)
+{
+ output_set_digit_value(0 + (offset ^ 3), data);
+}
+
+WRITE16_MEMBER( aim65_state::aim65_update_ds2)
+{
+ output_set_digit_value(4 + (offset ^ 3), data);
+}
+
+WRITE16_MEMBER( aim65_state::aim65_update_ds3)
+{
+ output_set_digit_value(8 + (offset ^ 3), data);
+}
+
+WRITE16_MEMBER( aim65_state::aim65_update_ds4)
+{
+ output_set_digit_value(12 + (offset ^ 3), data);
+}
+
+WRITE16_MEMBER( aim65_state::aim65_update_ds5)
+{
+ output_set_digit_value(16 + (offset ^ 3), data);
+}
+
+
+
+/******************************************************************************
+ 6532 RIOT
+******************************************************************************/
+
+
+READ8_MEMBER( aim65_state::aim65_riot_b_r )
+{
+ static const char *const keynames[] =
+ {
+ "keyboard_0", "keyboard_1", "keyboard_2", "keyboard_3",
+ "keyboard_4", "keyboard_5", "keyboard_6", "keyboard_7"
+ };
+
+ UINT8 row, data = 0xff;
+
+ /* scan keyboard rows */
+ for (row = 0; row < 8; row++)
+ {
+ if (!BIT(m_riot_port_a, row))
+ data &= ioport(keynames[row])->read();
+ }
+
+ return data;
+}
+
+
+WRITE8_MEMBER( aim65_state::aim65_riot_a_w )
+{
+ m_riot_port_a = data;
+}
+
+
+
+/***************************************************************************
+ DRIVER INIT
+***************************************************************************/
+
+void aim65_state::machine_start()
+{
+ ram_device *ram = m_ram;
+ address_space &space = m_maincpu->space(AS_PROGRAM);
+
+ // Init ROM sockets
+ if (m_z24->exists())
+ space.install_read_handler(0xd000, 0xdfff, read8_delegate(FUNC(generic_slot_device::read_rom),(generic_slot_device*)m_z24));
+ if (m_z25->exists())
+ space.install_read_handler(0xc000, 0xcfff, read8_delegate(FUNC(generic_slot_device::read_rom),(generic_slot_device*)m_z25));
+ if (m_z26->exists())
+ space.install_read_handler(0xb000, 0xbfff, read8_delegate(FUNC(generic_slot_device::read_rom),(generic_slot_device*)m_z26));
+
+ // Init RAM
+ space.install_ram(0x0000, ram->size() - 1, ram->pointer());
+
+ m_pb_save = 0;
+}
+
+
+/* RESET
+ *
+ * Pushbutton switch S1 initiates RESET of the AIM65 hardware and software.
+ * Timer Z4 holds the RES low for at least 15 ms from the time the pushbutton
+ * is released. RES is routed to the R6502 CPU, the Monitor R6522 (Z32), the
+ * Monitor R6532 RIOT (Z33), the user R6522 VIA (Z1), and the display R6520 PIA
+ * (U1). To initiate the device RESET function is also routed to the expansion
+ * connector for off-board RESET functions. The Monitor performs a software
+ * reset when the RES line goes high.
+ */
+
+
+/******************************************************************************
+ Cassette
+******************************************************************************/
+
+WRITE8_MEMBER( aim65_state::aim65_pb_w )
+{
+/*
+ d7 = cass out (both decks)
+ d5 = cass2 motor
+ d4 = cass1 motor
+ d2 = tty out (not emulated)
+ d0/1 = printer data (not emulated)
+*/
+
+ UINT8 bits = data ^ m_pb_save;
+ m_pb_save = data;
+
+ if (BIT(bits, 7))
+ {
+ m_cassette1->output(BIT(data, 7) ? -1.0 : +1.0);
+ m_cassette2->output(BIT(data, 7) ? -1.0 : +1.0);
+ }
+
+ if (BIT(bits, 5))
+ {
+ if (BIT(data, 5))
+ m_cassette2->change_state(CASSETTE_MOTOR_DISABLED,CASSETTE_MASK_MOTOR);
+ else
+ m_cassette2->change_state(CASSETTE_MOTOR_ENABLED,CASSETTE_MASK_MOTOR);
+ }
+
+ if (BIT(bits, 4))
+ {
+ if (BIT(data, 4))
+ m_cassette1->change_state(CASSETTE_MOTOR_DISABLED,CASSETTE_MASK_MOTOR);
+ else
+ m_cassette1->change_state(CASSETTE_MOTOR_ENABLED,CASSETTE_MASK_MOTOR);
+ }
+}
+
+
+READ8_MEMBER( aim65_state::aim65_pb_r )
+{
+/*
+ d7 = cassette in (deck 1)
+ d6 = tty in (not emulated)
+ d3 = kb/tty switch
+*/
+
+ UINT8 data = ioport("switches")->read();
+ data |= (m_cassette1->input() > +0.03) ? 0x80 : 0;
+ data |= 0x40; // TTY must be H if not used.
+ data |= m_pb_save & 0x37;
+ return data;
+}
+
+
+/******************************************************************************
+ Printer
+******************************************************************************/
+
+#ifdef UNUSED_FUNCTION
+/*
+
+2012-01-24 Printer code removed [Robbbert]
+
+From here to the end is not compiled. It is the remnants of the old printer
+code. Have a look at version 0.114 or 0.115 for the original working code.
+
+I've left it here for the idly curious.
+
+The system sends out the pattern of dots to the 'dot-matrix' print-head.
+
+This is why we can't simply replace it with a Centronics-like 'Printer'
+device - the output will be gibberish.
+*/
+
+
+
+/*
+ aim65 thermal printer (20 characters)
+ 10 heat elements (place on 1 line, space between 2 characters(about 14dots))
+ (pa0..pa7,pb0,pb1 1 heat element on)
+
+ cb2 0 motor, heat elements on
+ cb1 output start!?
+ ca1 input
+
+ normally printer 5x7 characters
+ (horizontal movement limits not known, normally 2 dots between characters)
+
+ 3 dots space between lines?
+*/
+
+
+/* Part of aim65_pb_w
+
+ data &= 0x03;
+
+ if (m_flag_b == 0)
+ {
+ printerRAM[(m_printer_y * 20) + m_printer_x ] |= (data << 8);
+ m_flag_b = 1;
+ }
+*/
+
+
+/* Items for driver state
+
+ emu_timer *m_print_timer;
+ int m_printer_x;
+ int m_printer_y;
+ bool m_printer_dir;
+ bool m_flag_a;
+ bool m_flag_b;
+ bool m_printer_level;
+ UINT16 *m_printerRAM;
+*/
+
+
+/* Other items from H file
+
+VIDEO_UPDATE( aim65 );
+*/
+
+
+/* From 6522 config
+DRIVER_MEMBER(aim65_state, aim65_pa_w), // out port A
+DRIVER_MEMBER(aim65_state, aim65_printer_on), // out CB2
+*/
+
+
+/* From Machine Config
+ MCFG_VIDEO_START_OVERRIDE(aim65_state,aim65)
+ MCFG_VIDEO_UPDATE(aim65)
+*/
+
+
+TIMER_CALLBACK_MEMBER(aim65_state::aim65_printer_timer)
+{
+ via6522_device *via_0 = machine().device<via6522_device>("via6522_0");
+
+ via_0->write_cb1(m_printer_level);
+ via_0->write_cb1(!m_printer_level);
+ m_printer_level ^= 1;
+
+ if (m_printer_dir)
+ {
+ if (m_printer_x > 0)
+ m_printer_x--;
+ else
+ {
+ m_printer_dir = 0;
+ m_printer_x++;
+ m_printer_y++;
+ }
+ }
+ else
+ {
+ if (m_printer_x < 9)
+ m_printer_x++;
+ else
+ {
+ m_printer_dir = 1;
+ m_printer_x--;
+ m_printer_y++;
+ }
+ }
+
+ if (m_printer_y > 500) m_printer_y = 0;
+
+ m_flag_a=0;
+ m_flag_b=0;
+}
+
+
+WRITE8_MEMBER( aim65_state::aim65_printer_on )
+{
+ via6522_device *via_0 = machine().device<via6522_device>("via6522_0");
+ if (!data)
+ {
+ m_printer_x=0;
+ m_printer_y++;
+ if (m_printer_y > 500) m_printer_y = 0;
+ m_flag_a = m_flag_b=0;
+ via_0->write_cb1(0);
+ m_print_timer->adjust(attotime::zero, 0, attotime::from_usec(10));
+ m_printer_level = 1;
+ }
+ else
+ m_print_timer->reset();
+}
+
+
+WRITE8_MEMBER( aim65_state::aim65_pa_w )
+{
+// All bits are for printer data (not emulated)
+ if (m_flag_a == 0)
+ {
+ m_printerRAM[(m_printer_y * 20) + m_printer_x] |= data;
+ m_flag_a = 1;
+ }
+}
+
+VIDEO_START_MEMBER(aim65_state,aim65)
+{
+ m_print_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(aim65_state::aim65_printer_timer),this));
+ m_printerRAM = auto_alloc_array(machine(), UINT16, (600 * 10 * 2) / 2);
+ memset(m_printerRAM, 0, videoram_size);
+ VIDEO_START_CALL_MEMBER(generic);
+ m_printer_x = 0;
+ m_printer_y = 0;
+ m_printer_dir = 0;
+ m_flag_a = 0;
+ m_flag_b = 0;
+ m_printer_level = 0;
+}
+
+SCREEN_UPDATE( aim65 )
+{
+ aim65_state *state = screen.machine().driver_data<aim65_state>();
+ /* Display printer output */
+ bool dir = 1;
+ UINT8 b,x,pen;
+ UINT16 y;
+
+ for (y = 0; y<500; y++)
+ {
+ for(x = 0; x< 10; x++)
+ {
+ if (dir == 1)
+ data = state->m_printerRAM[y * 10 + x];
+ else
+ data = state->m_printerRAM[(y * 10) + (9 - x)];
+
+
+ for (b = 0; b<10; b++)
+ {
+ pen = screen.m_palette->pen(BIT(data, 0) ? 2 : 0);
+ plot_pixel(bitmap,700 - ((b * 10) + x), y, pen);
+ data >>= 1;
+ }
+ }
+
+ dir ^= 1;
+ }
+ return 0;
+}
+
+
+#endif