From 9205d549a775eba342e6b5ad00dd5ac27c3ce40a Mon Sep 17 00:00:00 2001 From: arbee Date: Sun, 7 Feb 2016 21:11:28 -0500 Subject: [PATCH] apple1: completely rewrote the driver in modern idioms. All functionality should be the same. [R. Belmont] --- src/mame/drivers/apple1.cpp | 715 +++++++++++++++++++++++++----------- src/mame/includes/apple1.h | 92 ----- src/mame/machine/apple1.cpp | 404 -------------------- src/mame/video/apple1.cpp | 392 -------------------- 4 files changed, 500 insertions(+), 1103 deletions(-) delete mode 100644 src/mame/includes/apple1.h delete mode 100644 src/mame/machine/apple1.cpp delete mode 100644 src/mame/video/apple1.cpp diff --git a/src/mame/drivers/apple1.cpp b/src/mame/drivers/apple1.cpp index a99810887bc..65e2d0604e1 100644 --- a/src/mame/drivers/apple1.cpp +++ b/src/mame/drivers/apple1.cpp @@ -1,135 +1,78 @@ -// license:??? -// copyright-holders:Paul Daniels, Colin Howell, R. Belmont -/********************************************************************** +// license:BSD-3-Clause +// copyright-holders:R. Belmont +/*************************************************************************** -Apple I + apple1.cpp - Apple I -CPU: 6502 @ 1.023 MHz - (Effective speed with RAM refresh waits is 0.960 MHz.) + Next generation driver written in February 2016 by R. Belmont. + Thanks to the original crew. + + Apple I has: + 6502 @ 1.023 MHz (~0.960 MHz with RAM refresh) + 4 or 8 KB RAM on-board + 256 byte Monitor ROM + No IRQs, no sound, dumb terminal video + 6820 PIA for keyboard / terminal interface + + ------------------------------------------------------------------- + + How to use cassettes: + The system has no error checking or checksums, and the cassette + has no header. + Therefore, you must know the details, and pass these to the + interface yourself. + + BASIC has no cassette handling. You must enter the monitor + with: CALL -151 + then when finished, re-enter BASIC with: E2B3R -RAM: 4-8 KB on main board (4 KB standard) + Examples: - Additional memory could be added via the expansion - connector, but the user was responsible for making sure - the extra memory was properly interfaced. - - Some users replaced the onboard 4-kilobit RAM chips with - 16-kilobit RAM chips, increasing on-board memory to 32 KB, - but this required modifying the RAM interface circuitry. - -ROM: 256 bytes for Monitor program - - Optional cassette interface included 256 bytes for - cassette routines. - -Interrupts: None. - (The system board had jumpers to allow interrupts, but - these were not connected in a standard system.) - -Video: Dumb terminal, based on 7 1K-bit shift registers - -Sound: None - -Hardware: Motorola 6820 PIA for keyboard and display interface - -Memory map: - -$0000-$1FFF: RAM address space - $0000-$00FF: 6502 zero page - $0024-$002B: Zero page locations used by the Monitor - $0100-$01FF: 6502 processor stack - $0200-$027F: Keyboard input buffer storage used by the Monitor - $0280-$0FFF: RAM space available for a program in a 4 KB system - $1000-$1FFF: Extra RAM space available for a program in an 8 KB system - not using cassette BASIC - -$2000-$BFFF: Unused address space, available for RAM in systems larger - than 8 KB. - -$C000-$CFFF: Address space for optional cassette interface - $C000-$C0FF: Cassette interface I/O range - $C100-$C1FF: Cassette interface ROM - -$D000-$DFFF: I/O address space - $D010-$D013: Motorola 6820 PIA registers. - $D010: Keyboard input port - $D011: Control register for keyboard input port, with - key-available flag. - $D012: Display output port (bit 7 is a status input) - $D013: Control register for display output port - (PIA registers also mirrored at $D014-$D017, $D018-$D01B, $D01C-$D01F, - $D030-$D03F, $D050-$D05F, ... , $DFD0-$DFDF, $DFF0-$DFFF.) - -$E000-$EFFF: Extra RAM space available for a program in an 8 KB system - modified to use cassette BASIC - (The system simulated here always includes this RAM.) - -If you wanted to load the BASIC as rom, here are the details: -ROM_LOAD("basic.bin", 0xE000, 0x1000, CRC(d5e86efc) SHA1(04269c1c66e7d5b4aa5035462c6e612bf2ae9b91) ) + A machine-language program will typically be like this: + C100R (enter the interface) + 0300.0FFFR (enter the load and end addresses, then load the tape) + You start the tape. + When the prompt returns you stop the tape. + 0300R (run your program) -$F000-$FFFF: ROM address space - $FF00-$FFFF: Apple Monitor ROM + To Load Tape Basic: + C100R + E000.EFFFR + You start the tape. + When the prompt returns you stop the tape. + E000R (It must say 4C - if not, your tape is no good). + The BASIC prompt will appear + >@ -How to use cassettes: -The system has no error checking or checksums, and the cassette -has no header. -Therefore, you must know the details, and pass these to the -interface yourself. -BASIC has no cassette handling. You must enter the monitor -with: CALL -151 -then when finished, re-enter BASIC with: E2B3R + A BASIC program is split into two areas, one for the scratch pad, + and one for the program proper. + In BASIC you may have to adjust the allowed memory area, such as + LOMEM = 768 + Then, go to the monitor: CALL -151 + C100R (enter the interface) + 00A4.00FFR 0300.0FFFR (load the 2 parts) + You start the tape. + When the prompt returns you stop the tape. + E2B3R (back to BASIC) + You can LIST or RUN now. -Examples: + Saving is almost the same, when you specify the address range, enter + W instead of R. The difficulty is finding out how long your program is. -A machine-language program will typically be like this: -C100R (enter the interface) -0300.0FFFR (enter the load and end addresses, then load the tape) -You start the tape. -When the prompt returns you stop the tape. -0300R (run your program) - - -To Load Tape Basic: -C100R -E000.EFFFR -You start the tape. -When the prompt returns you stop the tape. -E000R (It must say 4C - if not, your tape is no good). -The BASIC prompt will appear ->@ - - -A BASIC program is split into two areas, one for the scratch pad, -and one for the program proper. -In BASIC you may have to adjust the allowed memory area, such as -LOMEM = 768 -Then, go to the monitor: CALL -151 -C100R (enter the interface) -00A4.00FFR 0300.0FFFR (load the 2 parts) -You start the tape. -When the prompt returns you stop the tape. -E2B3R (back to BASIC) -You can LIST or RUN now. - - -Saving is almost the same, when you specify the address range, enter -W instead of R. The difficulty is finding out how long your program is. - -Insert a blank tape -C100R -0300.0FFFW -Quickly press Record. -When the prompt returns, press Stop. + Insert a blank tape + C100R + 0300.0FFFW + Quickly press Record. + When the prompt returns, press Stop. **********************************************************************/ #include "emu.h" #include "cpu/m6502/m6502.h" #include "machine/6821pia.h" -#include "includes/apple1.h" #include "imagedev/snapquik.h" #include "machine/ram.h" @@ -139,59 +82,428 @@ When the prompt returns, press Stop. #include "softlist.h" -/* port i/o functions */ +#define A1_CPU_TAG "maincpu" +#define A1_PIA_TAG "pia6821" +#define A1_BUS_TAG "a1bus" +#define A1_BASICRAM_TAG "basicram" -/* memory w/r functions */ - -static ADDRESS_MAP_START( apple1_map, AS_PROGRAM, 8, apple1_state ) - /* In $D000-$DFFF, PIA is selected by address bit 4 being high, - and PIA registers are addressed with address bits 0-1. All - other address bits are ignored. Thus $D010-$D013 is mirrored - at all $Dxxx addresses with bit 4 high. */ - AM_RANGE(0xd010, 0xd013) AM_MIRROR(0x0fec) AM_DEVREADWRITE("pia",pia6821_device, read, write) - - /* We always include the remapped RAM for cassette BASIC, both for - simplicity and to allow the running of BASIC programs. */ - AM_RANGE(0xe000, 0xefff) AM_RAM - - AM_RANGE(0xf000, 0xfeff) AM_NOP - - /* Monitor ROM: */ - AM_RANGE(0xff00, 0xffff) AM_ROM AM_REGION("maincpu", 0) -ADDRESS_MAP_END - -/* graphics output */ - -const gfx_layout apple1_charlayout = +class apple1_state : public driver_device { - 7, 8, /* character cell is 7 pixels wide by 8 pixels high */ - 64, /* 64 characters in 2513 character generator ROM */ - 1, /* 1 bitplane */ - { 0 }, - /* 5 visible pixels per row, starting at bit 3, with MSB being 0: */ - { 3, 4, 5, 6, 7 }, - /* pixel rows stored from top to bottom: */ - { 0*8, 1*8, 2*8, 3*8, 4*8, 5*8, 6*8, 7*8 }, - 8 * 8 /* 8 8-bit pixel rows per character */ +public: + apple1_state(const machine_config &mconfig, device_type type, const char *tag) + : driver_device(mconfig, type, tag), + m_maincpu(*this, A1_CPU_TAG), + m_pia(*this, A1_PIA_TAG), + m_ram(*this, RAM_TAG), + m_basicram(*this, A1_BASICRAM_TAG), + m_kb0(*this, "KEY0"), + m_kb1(*this, "KEY1"), + m_kb2(*this, "KEY2"), + m_kb3(*this, "KEY3"), + m_kbspecial(*this, "KBSPECIAL") + { } + + required_device m_maincpu; + required_device m_pia; + required_device m_ram; + required_shared_ptr m_basicram; + required_ioport m_kb0, m_kb1, m_kb2, m_kb3, m_kbspecial; + + virtual void machine_start() override; + virtual void machine_reset() override; + + DECLARE_PALETTE_INIT(apple2); + UINT32 screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect); + + DECLARE_READ8_MEMBER(ram_r); + DECLARE_WRITE8_MEMBER(ram_w); + DECLARE_READ8_MEMBER(pia_keyboard_r); + DECLARE_WRITE8_MEMBER(pia_display_w); + DECLARE_WRITE_LINE_MEMBER(pia_display_gate_w); + DECLARE_SNAPSHOT_LOAD_MEMBER( apple1 ); + TIMER_CALLBACK_MEMBER(ready_start_cb); + TIMER_CALLBACK_MEMBER(ready_end_cb); + TIMER_CALLBACK_MEMBER(keyboard_strobe_cb); + +private: + UINT8 *m_ram_ptr, *m_char_ptr; + int m_ram_size, m_char_size; + + UINT8 m_vram[40*24]; + int m_cursx, m_cursy; + + bool m_reset_down; + bool m_clear_down; + + UINT8 m_transchar; + UINT16 m_lastports[4]; + + void plot_text_character(bitmap_ind16 &bitmap, int xpos, int ypos, int xscale, UINT32 code, const UINT8 *textgfx_data, UINT32 textgfx_datalen); + void poll_keyboard(); + + emu_timer *m_ready_start_timer, *m_ready_end_timer, *m_kbd_strobe_timer; }; -static GFXDECODE_START( apple1 ) - GFXDECODE_ENTRY( "gfx1", 0x0000, apple1_charlayout, 0, 1 ) -GFXDECODE_END +static const UINT8 apple1_keymap[] = +{ + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '-', '=', '[', ']', ';', '\'', // KEY0 + ',', '.', '/', '\\', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', // KEY1 + 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '\r', '_', // KEY2 + ' ', '\x1b', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // KEY3 -/* keyboard input */ -/* - It's very likely that the keyboard assgnments are totally wrong: the code in machine/apple1.c - makes arbitrary assumptions about the mapping of the keys. The schematics that are available - on the web can help revealing the real layout. - The large picture of Woz's Apple I at http://home.earthlink.net/~judgementcall/apple1.jpg - show probably how the real keyboard was meant to be: note how the shifted symbols on the digits - and on some letters are different from the ones produced by current emulation and the presence - of the gray keys. -*/ + ')', '!', '@', '#', '$', '%', '^', '&', '*', '(', '_', '+', '[', ']', ':', '"', // KEY0 + shift + '<', '>', '?', '\\', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', // KEY1 + shift + 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '\r', '_', // KEY2 + shift + ' ', '\x1b', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // KEY3 + shift + + '0', '1', '\x00', '\x1b', '\x1c', '\x1d', '\x1e', '\x1f', '8', '9', '\x1f', '=', '\x1b', '\x1d', ';', '\'', // KEY0 + CTRL + ',', '.', '/', '\x1c', '\x01', '\x02', '\x03', '\x04', '\x05', '\x06', '\x07', '\x08', '\x09', '\x0a', '\x0b', '\x0c', // KEY1 + CTRL + '\x0d', '\x0e', '\x0f', '\x10', '\x11', '\x12', '\x13', '\x14', '\x15', '\x16', '\x17', '\x18', '\x19', '\x1a', '\r', '_', // KEY2 + CTRL + ' ', '\x1b', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // KEY3 + CTRL + +}; + +// header is "LOAD:abcdDATA:" where abcd is the starting address +SNAPSHOT_LOAD_MEMBER( apple1_state, apple1 ) +{ + UINT64 snapsize; + UINT8 *data; + UINT16 start, end; + static const char hd1[6] = "LOAD:"; + static const char hd2[6] = "DATA:"; + + // get the snapshot's size + snapsize = image.length(); + + if (snapsize < 12) + { + logerror("Snapshot is too short\n"); + return IMAGE_INIT_FAIL; + } + + if ((snapsize - 12) > 65535) + { + logerror("Snapshot is too long\n"); + return IMAGE_INIT_FAIL; + } + + data = (UINT8 *)image.ptr(); + if (!data) + { + logerror("Internal error loading snapshot\n"); + return IMAGE_INIT_FAIL; + } + + if ((memcmp(hd1, data, 5)) || (memcmp(hd2, &data[7], 5))) + { + logerror("Snapshot is invalid\n"); + return IMAGE_INIT_FAIL; + } + + start = (data[5]<<8) | data[6]; + end = (snapsize - 12) + start; + + // check if this fits in RAM; load below 0xe000 must fit in RAMSIZE, + // load at 0xe000 must fit in 4K + if (((start < 0xe000) && (end > (m_ram_size - 1))) || (end > 0xefff)) + { + logerror("Snapshot can't fit in RAM\n"); + return IMAGE_INIT_FAIL; + } + + if (start < 0xe000) + { + memcpy(m_ram_ptr + start, &data[12], snapsize - 12); + } + else if ((start >= 0xe000) && (start <= 0xefff)) + { + memcpy(m_basicram + (start - 0xe000), &data[12], snapsize - 12); + } + else + { + logerror("Snapshot has invalid load address %04x\n", start); + return IMAGE_INIT_FAIL; + } + + return IMAGE_INIT_PASS; +} + +void apple1_state::poll_keyboard() +{ + UINT8 special = m_kbspecial->read(); + UINT16 ports[4]; + int rawkey = 0; + bool bKeypress = false; + + // handle special keys first: + if (special & 0x10) // RESET + { + m_reset_down = true; + m_maincpu->set_input_line(INPUT_LINE_RESET, ASSERT_LINE); + m_pia->reset(); + } + else if (m_reset_down) + { + m_reset_down = false; + m_maincpu->set_input_line(INPUT_LINE_RESET, CLEAR_LINE); + } + + if (special & 0x20) // CLEAR SCREEN + { + m_clear_down = true; + memset(m_vram, 0, sizeof(m_vram)); + m_cursx = m_cursy = 0; + } + else + { + m_clear_down = false; + } + + // lower the keyboard strobe + m_pia->ca1_w(0); + + // cache all the rows + ports[0] = m_kb0->read(); + ports[1] = m_kb1->read(); + ports[2] = m_kb2->read(); + ports[3] = m_kb3->read(); + + for (int port = 0; port < 4; port++) + { + UINT16 ptread = ports[port] ^ m_lastports[port]; + + for (int bit = 0; bit < 16; bit++) + { + // key changed? + if (ptread & (1 << bit)) + { + // key down? + if (ports[port] & (1 << bit)) + { + rawkey = (port * 16) + bit; + m_lastports[port] |= (1 << bit); + port = 4; // force outer for loop to quit too + bKeypress = true; + } + else // key up + { + m_lastports[port] &= ~(1 << bit); + } + break; + } + } + } + + if (bKeypress) + { + if ((special & 0xc) != 0) + { + m_transchar = apple1_keymap[rawkey + (8*16)]; + } + else if ((special & 0x3) != 0) + { + m_transchar = apple1_keymap[rawkey + (4*16)]; + } + else + { + m_transchar = apple1_keymap[rawkey]; + } + // pulse the strobe line + m_pia->ca1_w(1); + } +} + +void apple1_state::plot_text_character(bitmap_ind16 &bitmap, int xpos, int ypos, int xscale, UINT32 code, + const UINT8 *textgfx_data, UINT32 textgfx_datalen) +{ + int x, y, i; + const UINT8 *chardata; + UINT16 color; + int fg = 1, bg = 0; + int charcode = (code & 0x1f) | (((code ^ 0x40) & 0x40) >> 1); + + /* look up the character data */ + chardata = &textgfx_data[(charcode * 8)]; + + for (y = 0; y < 8; y++) + { + for (x = 0; x < 7; x++) + { + color = (chardata[y] & (1 << (6-x))) ? fg : bg; + + for (i = 0; i < xscale; i++) + { + bitmap.pix16(ypos + y, xpos + (x * xscale) + i) = color; + } + } + } +} + +UINT32 apple1_state::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect) +{ + int vramad; + int cursor_blink = 0; + UINT8 curs_save = 0; + + poll_keyboard(); + + // the cursor 555 timer counts 0.52 of a second; the cursor is ON for + // 2 of those counts and OFF for the last one. + if (((int)(machine().time().as_double() / (0.52 / 3.0)) % 3) < 2) + { + curs_save = m_vram[(m_cursy * 40) + m_cursx]; + m_vram[(m_cursy * 40) + m_cursx] = 0x40; + cursor_blink = 1; + } + + for (int row = 0; row < cliprect.max_y; row += 8) + { + for (int col = 0; col < 40; col++) + { + vramad = ((row/8) * 40) + col; + + plot_text_character(bitmap, col * 14, row, 2, m_vram[vramad], + m_char_ptr, m_char_size); + } + } + + if (cursor_blink) + { + m_vram[(m_cursy * 40) + m_cursx] = curs_save; + } + + return 0; +} + +void apple1_state::machine_start() +{ + m_ram_ptr = m_ram->pointer(); + m_ram_size = m_ram->size(); + m_char_ptr = memregion("gfx1")->base(); + m_char_size = memregion("gfx1")->bytes(); + + m_reset_down = m_clear_down = false; + + m_ready_start_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(apple1_state::ready_start_cb), this)); + m_ready_end_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(apple1_state::ready_end_cb), this)); + m_kbd_strobe_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(apple1_state::keyboard_strobe_cb), this)); +} + +void apple1_state::machine_reset() +{ + memset(m_vram, 0, sizeof(m_vram)); + m_transchar = 0; + m_cursx = m_cursy = 0; + m_lastports[0] = m_lastports[1] = m_lastports[2] = m_lastports[3] = 0; +} + +READ8_MEMBER(apple1_state::ram_r) +{ + if (offset < m_ram_size) + { + return m_ram_ptr[offset]; + } + + return 0xff; +} + +WRITE8_MEMBER(apple1_state::ram_w) +{ + if (offset < m_ram_size) + { + m_ram_ptr[offset] = data; + } +} + +static ADDRESS_MAP_START( apple1_map, AS_PROGRAM, 8, apple1_state ) + AM_RANGE(0x0000, 0xbfff) AM_READWRITE(ram_r, ram_w) + AM_RANGE(0xd010, 0xd013) AM_MIRROR(0x0fec) AM_DEVREADWRITE(A1_PIA_TAG, pia6821_device, read, write) + AM_RANGE(0xe000, 0xefff) AM_RAM AM_SHARE(A1_BASICRAM_TAG) + AM_RANGE(0xff00, 0xffff) AM_ROM AM_REGION(A1_CPU_TAG, 0) +ADDRESS_MAP_END + +READ8_MEMBER(apple1_state::pia_keyboard_r) +{ + return m_transchar | 0x80; // bit 7 is wired high, similar-ish to the Apple II +} + +WRITE8_MEMBER(apple1_state::pia_display_w) +{ + data &= 0x7f; // D7 is ignored by the video h/w + + // ignore characters if CLEAR is down + if (m_clear_down) + { + return; + } + + // video h/w rejects control characters except CR + if ((data < 32) && (data != '\r')) + { + return; + } + + if (data == '\r') + { + m_cursx = 0; + m_cursy++; + } + else + { + m_vram[(m_cursy * 40) + m_cursx] = data; + + m_cursx++; + if (m_cursx > 39) + { + m_cursx = 0; + m_cursy++; + } + } + + // scroll the screen if we're at the bottom + if (m_cursy > 23) + { + for (int sy = 0; sy < 23; sy++) + { + memcpy(&m_vram[sy * 40], &m_vram[(sy + 1) * 40], 40); + } + memset(&m_vram[23*40], 0, 40); + m_cursy = 23; + } +} + +// CB2 here is connected two places: Port B bit 7 for CPU readback, +// and to the display hardware +WRITE_LINE_MEMBER(apple1_state::pia_display_gate_w) +{ + m_pia->portb_w((state << 7) ^ 0x80); + + // falling edge means start the display timer + if (state == CLEAR_LINE) + { + m_ready_start_timer->adjust(machine().first_screen()->time_until_pos(m_cursy, m_cursx)); + } +} + +TIMER_CALLBACK_MEMBER(apple1_state::ready_start_cb) +{ + // we're ready, pulse CB1 for 3500 nanoseconds + m_pia->cb1_w(0); + m_ready_end_timer->adjust(attotime::from_nsec(3500)); +} + +TIMER_CALLBACK_MEMBER(apple1_state::ready_end_cb) +{ + m_pia->cb1_w(1); +} + +TIMER_CALLBACK_MEMBER(apple1_state::keyboard_strobe_cb) +{ + m_pia->ca1_w(0); +} static INPUT_PORTS_START( apple1 ) - PORT_START("KEY0") /* first sixteen keys */ + PORT_START("KEY0") PORT_BIT( 0x0001, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_0) PORT_CHAR('0') PORT_CHAR(')') PORT_BIT( 0x0002, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_1) PORT_CHAR('1') PORT_CHAR('!') PORT_BIT( 0x0004, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_2) PORT_CHAR('2') PORT_CHAR('@') @@ -209,7 +521,7 @@ static INPUT_PORTS_START( apple1 ) PORT_BIT( 0x4000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_COLON) PORT_CHAR(';') PORT_CHAR(':') PORT_BIT( 0x8000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_QUOTE) PORT_CHAR('\'') PORT_CHAR('"') - PORT_START("KEY1") /* second sixteen keys */ + PORT_START("KEY1") PORT_BIT( 0x0001, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_COMMA) PORT_CHAR(',') PORT_CHAR('<') PORT_BIT( 0x0002, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_STOP) PORT_CHAR('.') PORT_CHAR('>') PORT_BIT( 0x0004, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_SLASH) PORT_CHAR('/') PORT_CHAR('?') @@ -227,7 +539,7 @@ static INPUT_PORTS_START( apple1 ) PORT_BIT( 0x4000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_K) PORT_CHAR('K') PORT_BIT( 0x8000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_L) PORT_CHAR('L') - PORT_START("KEY2") /* third sixteen keys */ + PORT_START("KEY2") PORT_BIT( 0x0001, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_M) PORT_CHAR('M') PORT_BIT( 0x0002, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_N) PORT_CHAR('N') PORT_BIT( 0x0004, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_O) PORT_CHAR('O') @@ -243,21 +555,19 @@ static INPUT_PORTS_START( apple1 ) PORT_BIT( 0x1000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_Y) PORT_CHAR('Y') PORT_BIT( 0x2000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_Z) PORT_CHAR('Z') PORT_BIT( 0x4000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_ENTER) PORT_CHAR(13) - PORT_BIT( 0x8000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Backarrow") PORT_CODE(KEYCODE_BACKSPACE) PORT_CHAR('_') + PORT_BIT( 0x8000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Backspace") PORT_CODE(KEYCODE_BACKSPACE) PORT_CHAR('_') - PORT_START("KEY3") /* fourth sixteen keys */ + PORT_START("KEY3") PORT_BIT( 0x0001, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_SPACE) PORT_CHAR(' ') PORT_BIT( 0x0002, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Escape") PORT_CODE(KEYCODE_ESC) PORT_CHAR(UCHAR_MAMEKEY(ESC)) - PORT_START("KEY4") /* shift keys */ - PORT_BIT( 0x0001, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Shift (Left)") PORT_CODE(KEYCODE_LSHIFT) PORT_CHAR(UCHAR_SHIFT_1) - PORT_BIT( 0x0002, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Shift (Right)") PORT_CODE(KEYCODE_RSHIFT) PORT_CHAR(UCHAR_SHIFT_1) - PORT_BIT( 0x0004, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Control (Left)") PORT_CODE(KEYCODE_LCONTROL) PORT_CHAR(UCHAR_SHIFT_2) - PORT_BIT( 0x0008, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Control (Right)") PORT_CODE(KEYCODE_RCONTROL) PORT_CHAR(UCHAR_SHIFT_2) - - PORT_START("KEY5") /* RESET and CLEAR SCREEN pushbutton switches */ - PORT_BIT( 0x0001, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Reset") PORT_CODE(KEYCODE_F12) PORT_CHAR(UCHAR_MAMEKEY(F1)) - PORT_BIT( 0x0002, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Clear") PORT_CODE(KEYCODE_F2) PORT_CHAR(UCHAR_MAMEKEY(F2)) + PORT_START("KBSPECIAL") + PORT_BIT( 0x0001, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Left Shift") PORT_CODE(KEYCODE_LSHIFT) PORT_CHAR(UCHAR_SHIFT_1) + PORT_BIT( 0x0002, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Right Shift") PORT_CODE(KEYCODE_RSHIFT) PORT_CHAR(UCHAR_SHIFT_1) + PORT_BIT( 0x0004, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Left Control") PORT_CODE(KEYCODE_LCONTROL) PORT_CHAR(UCHAR_SHIFT_2) + PORT_BIT( 0x0008, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Right Control") PORT_CODE(KEYCODE_RCONTROL) PORT_CHAR(UCHAR_SHIFT_2) + PORT_BIT( 0x0010, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Reset") PORT_CODE(KEYCODE_F12) PORT_CHAR(UCHAR_MAMEKEY(F1)) + PORT_BIT( 0x0020, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Clear") PORT_CODE(KEYCODE_F2) PORT_CHAR(UCHAR_MAMEKEY(F2)) INPUT_PORTS_END static SLOT_INTERFACE_START(apple1_cards) @@ -265,69 +575,44 @@ static SLOT_INTERFACE_START(apple1_cards) SLOT_INTERFACE("cffa", A1BUS_CFFA) SLOT_INTERFACE_END -/* machine definition */ static MACHINE_CONFIG_START( apple1, apple1_state ) - /* basic machine hardware */ - /* Actual CPU speed is 1.023 MHz, but RAM refresh effectively - slows it to 960 kHz. */ - MCFG_CPU_ADD("maincpu", M6502, 960000) /* 1.023 MHz */ + MCFG_CPU_ADD(A1_CPU_TAG, M6502, 960000) // effective CPU speed MCFG_CPU_PROGRAM_MAP(apple1_map) - MCFG_QUANTUM_TIME(attotime::from_hz(60)) - + // video timings are identical to the Apple II, unsurprisingly MCFG_SCREEN_ADD("screen", RASTER) - MCFG_SCREEN_REFRESH_RATE(60) - /* Video is blanked for 70 out of 262 scanlines per refresh cycle. - Each scanline is composed of 65 character times, 40 of which - are visible, and each character time is 7 dot times; a dot time - is 2 cycles of the fundamental 14.31818 MHz oscillator. The - total blanking time is about 4450 microseconds. */ - MCFG_SCREEN_VBLANK_TIME(ATTOSECONDS_IN_USEC((int) (70 * 65 * 7 * 2 / 14.31818))) - /* It would be nice if we could implement some sort of display - overscan here. */ - MCFG_SCREEN_SIZE(40 * 7, 24 * 8) - MCFG_SCREEN_VISIBLE_AREA(0, 40 * 7 - 1, 0, 24 * 8 - 1) - MCFG_SCREEN_UPDATE_DRIVER(apple1_state, screen_update_apple1) + MCFG_SCREEN_RAW_PARAMS(XTAL_14_31818MHz, (65*7)*2, 0, (40*7)*2, 262, 0, 192) + MCFG_SCREEN_UPDATE_DRIVER(apple1_state, screen_update) MCFG_SCREEN_PALETTE("palette") - MCFG_GFXDECODE_ADD("gfxdecode", "palette", apple1) - MCFG_PALETTE_ADD_BLACK_AND_WHITE("palette") - MCFG_DEVICE_ADD( "pia", PIA6821, 0) - MCFG_PIA_READPA_HANDLER(READ8(apple1_state,apple1_pia0_kbdin)) - MCFG_PIA_WRITEPB_HANDLER(WRITE8(apple1_state,apple1_pia0_dspout)) - MCFG_PIA_CB2_HANDLER(WRITELINE(apple1_state,apple1_pia0_dsp_write_signal)) + MCFG_DEVICE_ADD( A1_PIA_TAG, PIA6821, 0) + MCFG_PIA_READPA_HANDLER(READ8(apple1_state, pia_keyboard_r)) + MCFG_PIA_WRITEPB_HANDLER(WRITE8(apple1_state, pia_display_w)) + MCFG_PIA_CB2_HANDLER(WRITELINE(apple1_state, pia_display_gate_w)) - MCFG_DEVICE_ADD("a1bus", A1BUS, 0) + MCFG_DEVICE_ADD(A1_BUS_TAG, A1BUS, 0) MCFG_A1BUS_CPU("maincpu") - MCFG_A1BUS_SLOT_ADD("a1bus", "exp", apple1_cards, "cassette") + MCFG_A1BUS_SLOT_ADD(A1_BUS_TAG, "exp", apple1_cards, "cassette") - /* snapshot */ MCFG_SNAPSHOT_ADD("snapshot", apple1_state, apple1, "snp", 0) - MCFG_SOFTWARE_LIST_ADD("cass_list","apple1") + MCFG_SOFTWARE_LIST_ADD("cass_list", "apple1") - /* Note that because we always include 4K of RAM at $E000-$EFFF, - the RAM amounts listed here will be 4K below the actual RAM - total. */ - /* internal ram */ MCFG_RAM_ADD(RAM_TAG) MCFG_RAM_DEFAULT_SIZE("48K") MCFG_RAM_EXTRA_OPTIONS("4K,8K,12K,16K,20K,24K,28K,32K,36K,40K,44K") - MACHINE_CONFIG_END ROM_START(apple1) - ROM_REGION(0x100, "maincpu",0) - /* 256-byte main monitor ROM, in two 82s129 or mmi6301 256x4 proms at A1 and A2 called APPLE-A1(bits D3-D0) and APPLE-A2(bits D7-D4) */ - ROM_LOAD_NIB_HIGH( "apple-a2.a2", 0x0000, 0x0100, CRC(254bfb95) SHA1(b6468b72295b7d8ac288d104d252f24de1f1d611) ) - ROM_LOAD_NIB_LOW( "apple-a1.a1", 0x0000, 0x0100, CRC(434f8ce6) SHA1(9deee2d39903209b20c3fc6b58e16372f8efece1) ) - /* 512-byte Signetics 2513 character generator ROM at location D2-D3 */ + ROM_REGION(0x100, A1_CPU_TAG, 0) + ROM_LOAD_NIB_HIGH("apple-a2.a2", 0x0000, 0x0100, CRC(254bfb95) SHA1(b6468b72295b7d8ac288d104d252f24de1f1d611) ) + ROM_LOAD_NIB_LOW("apple-a1.a1", 0x0000, 0x0100, CRC(434f8ce6) SHA1(9deee2d39903209b20c3fc6b58e16372f8efece1) ) ROM_REGION(0x0200, "gfx1",0) ROM_LOAD("s2513.d2", 0x0000, 0x0200, CRC(a7e567fc) SHA1(b18aae0a2d4f92f5a7e22640719bbc4652f3f4ee)) // apple1.vid ROM_END +/* YEAR NAME PARENT COMPAT MACHINE INPUT STATE INIT COMPANY FULLNAME */ +COMP( 1976, apple1, 0, 0, apple1, apple1, driver_device, 0, "Apple Computer", "Apple I", MACHINE_NO_SOUND_HW ) -/* YEAR NAME PARENT COMPAT MACHINE INPUT INIT COMPANY FULLNAME */ -COMP( 1976, apple1, 0, 0, apple1, apple1, apple1_state, apple1, "Apple Computer", "Apple I" , MACHINE_NO_SOUND ) diff --git a/src/mame/includes/apple1.h b/src/mame/includes/apple1.h deleted file mode 100644 index 35215b9e9a3..00000000000 --- a/src/mame/includes/apple1.h +++ /dev/null @@ -1,92 +0,0 @@ -// license:??? -// copyright-holders:Paul Daniels, Colin Howell, R. Belmont -/***************************************************************************** - * - * includes/apple1.h - * - ****************************************************************************/ - -#ifndef APPLE1_H_ -#define APPLE1_H_ - -#include "imagedev/snapquik.h" -#include "machine/ram.h" - -typedef short termchar_t; - -struct terminal_t -{ - tilemap_t *tm; - int gfx; - int blank_char; - int char_bits; - int num_cols; - int num_rows; - int (*getcursorcode)(int original_code); - int cur_offset; - int cur_hidden; - termchar_t mem[1]; -}; - - -class apple1_state : public driver_device -{ -public: - apple1_state(const machine_config &mconfig, device_type type, const char *tag) - : driver_device(mconfig, type, tag), - m_maincpu(*this, "maincpu"), - m_ram(*this, RAM_TAG), - m_gfxdecode(*this, "gfxdecode"), - m_screen(*this, "screen") { } - - int m_vh_clrscrn_pressed; - int m_kbd_data; - UINT32 m_kbd_last_scan[4]; - int m_reset_flag; - terminal_t *m_current_terminal; - terminal_t *m_terminal; - int m_blink_on; - DECLARE_DRIVER_INIT(apple1); - TILE_GET_INFO_MEMBER(terminal_gettileinfo); - virtual void machine_reset() override; - virtual void video_start() override; - UINT32 screen_update_apple1(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect); - TIMER_CALLBACK_MEMBER(apple1_kbd_poll); - TIMER_CALLBACK_MEMBER(apple1_kbd_strobe_end); - TIMER_CALLBACK_MEMBER(apple1_dsp_ready_start); - TIMER_CALLBACK_MEMBER(apple1_dsp_ready_end); - DECLARE_READ8_MEMBER(apple1_pia0_kbdin); - DECLARE_WRITE8_MEMBER(apple1_pia0_dspout); - DECLARE_WRITE_LINE_MEMBER(apple1_pia0_dsp_write_signal); - required_device m_maincpu; - void terminal_draw(screen_device &screen, bitmap_ind16 &dest, const rectangle &cliprect, terminal_t *terminal); - void verify_coords(terminal_t *terminal, int x, int y); - void terminal_putchar(terminal_t *terminal, int x, int y, int ch); - int terminal_getchar(terminal_t *terminal, int x, int y); - void terminal_putblank(terminal_t *terminal, int x, int y); - void terminal_dirtycursor(terminal_t *terminal); - void terminal_setcursor(terminal_t *terminal, int x, int y); - void terminal_hidecursor(terminal_t *terminal); - void terminal_showcursor(terminal_t *terminal); - void terminal_getcursor(terminal_t *terminal, int *x, int *y); - void terminal_fill(terminal_t *terminal, int val); - void terminal_clear(terminal_t *terminal); - void apple1_vh_dsp_w (int data); - void apple1_vh_dsp_clr (); - void apple1_vh_cursor_blink (); - int apple1_verify_header (UINT8 *data); - terminal_t *terminal_create(int gfx, int blank_char, int char_bits,int (*getcursorcode)(int original_code),int num_cols, int num_rows); - attotime apple1_vh_dsp_time_to_ready(); - DECLARE_SNAPSHOT_LOAD_MEMBER( apple1 ); - required_device m_ram; - required_device m_gfxdecode; - required_device m_screen; -}; - - -/*----------- defined in drivers/apple1.c -----------*/ - -extern const gfx_layout apple1_charlayout; - - -#endif /* APPLE1_H_ */ diff --git a/src/mame/machine/apple1.cpp b/src/mame/machine/apple1.cpp deleted file mode 100644 index 59b360aea7e..00000000000 --- a/src/mame/machine/apple1.cpp +++ /dev/null @@ -1,404 +0,0 @@ -// license:??? -// copyright-holders:Paul Daniels, Colin Howell, R. Belmont -/*************************************************************************** - - machine.c - - Functions to emulate general aspects of the machine (RAM, ROM, interrupts, - I/O ports) - - The Apple I used a Motorola 6820 PIA for its keyboard and display - I/O. The keyboard was mapped to PIA port A, and the display to port - B. - - Port A, the keyboard, was an input port connected to a standard - ASCII-encoded keyboard. The high bit of the port was tied to +5V. - The keyboard strobe signal was connected to the PIA's CA1 control - input so that the keyboard could signal each keypress to the PIA. - The processor could check for a keypress by testing the IRQA1 flag - in the Port A Control Register and then reading the character value - from Port A. - - The keyboard connector also had two special lines, RESET and CLEAR - SCREEN, which were meant to be connected to pushbutton switches on - the keyboard. RESET was tied to the reset inputs for the CPU and - PIA; it allowed the user to stop a program and return control to the - Monitor. CLEAR SCREEN was directly tied to the video hardware and - would clear the display. - - Port B, the display, was an output port which accepted 7-bit ASCII - characters from the PIA and wrote them on the display. The details - of this are described in video/apple1.c. Control line CB2 served - as an output signal to inform the display of a new character. (CB2 - was also connected to line 7 of port B, which was configured as an - input, so that the CPU could more easily check the status of the - write.) The CB1 control input signaled the PIA when the display had - finished writing the character and could accept a new one. - - MAME models the 6821 instead of the earlier 6820 used in the Apple - I, but there is no difference in functionality between the two - chips; the 6821 simply has a better ability to drive electrical - loads. - - The Apple I had an optional cassette interface which plugged into - the expansion connector. This is described below in the "Cassette - interface I/O" section. - -***************************************************************************/ - -#include "emu.h" -#include "includes/apple1.h" -#include "machine/6821pia.h" -#include "cpu/m6502/m6502.h" -#include "imagedev/cassette.h" -#include "machine/ram.h" - -/***************************************************************************** -** Structures -*****************************************************************************/ - -/* Use the same keyboard mapping as on a modern keyboard. This is not - the same as the keyboard mapping of the actual teletype-style - keyboards used with the Apple I, but it's less likely to cause - confusion for people who haven't memorized that layout. - - The Backspace key is mapped to the '_' (underscore) character - because the Apple I ROM Monitor used "back-arrow" to erase - characters, rather than backspace, and back-arrow is an earlier - form of the underscore. */ - -#define ESCAPE '\x1b' - -static const UINT8 apple1_unshifted_keymap[] = -{ - '0', '1', '2', '3', '4', '5', '6', '7', - '8', '9', '-', '=', '[', ']', ';', '\'', - ',', '.', '/', '\\', 'A', 'B', 'C', 'D', - 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', - 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', - 'U', 'V', 'W', 'X', 'Y', 'Z', '\r', '_', - ' ', ESCAPE -}; - -static const UINT8 apple1_shifted_keymap[] = -{ - ')', '!', '@', '#', '$', '%', '^', '&', - '*', '(', '_', '+', '[', ']', ':', '"', - '<', '>', '?', '\\', 'A', 'B', 'C', 'D', - 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', - 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', - 'U', 'V', 'W', 'X', 'Y', 'Z', '\r', '_', - ' ', ESCAPE -}; - -/* Control key mappings, like the other mappings, conform to a modern - keyboard where possible. Note that the Apple I ROM Monitor ignores - most control characters. */ - -static const UINT8 apple1_control_keymap[] = -{ - '0', '1', '\x00', '\x1b', '\x1c', '\x1d', '\x1e', '\x1f', - '8', '9', '\x1f', '=', '\x1b', '\x1d', ';', '\'', - ',', '.', '/', '\x1c', '\x01', '\x02', '\x03', '\x04', - '\x05', '\x06', '\x07', '\x08', '\x09', '\x0a', '\x0b', '\x0c', - '\x0d', '\x0e', '\x0f', '\x10', '\x11', '\x12', '\x13', '\x14', - '\x15', '\x16', '\x17', '\x18', '\x19', '\x1a', '\r', '_', - '\x00', ESCAPE -}; - - - -/***************************************************************************** -** DRIVER_INIT: driver-specific setup, executed once at MESS startup. -*****************************************************************************/ - -DRIVER_INIT_MEMBER(apple1_state,apple1) -{ - address_space& space = m_maincpu->space(AS_PROGRAM); - /* Set up the handlers for MESS's dynamically-sized RAM. */ - space.install_readwrite_bank(0x0000, m_ram->size() - 1, "bank1"); - membank("bank1")->set_base(m_ram->pointer()); - - /* Poll the keyboard input ports periodically. These include both - ordinary keys and the RESET and CLEAR SCREEN pushbutton - switches. We can't handle these switches in a VBLANK_INT or - PERIODIC_INT because both switches need to be monitored even - while the CPU is suspended during RESET; VBLANK_INT and - PERIODIC_INT callbacks aren't run while the CPU is in this - state. - - A 120-Hz poll rate seems to be fast enough to ensure no - keystrokes are missed. */ - machine().scheduler().timer_pulse(attotime::from_hz(120), timer_expired_delegate(FUNC(apple1_state::apple1_kbd_poll),this)); -} - - -void apple1_state::machine_reset() -{ - /* Reset the display hardware. */ - apple1_vh_dsp_clr(); -} - - -/***************************************************************************** -** apple1_verify_header -*****************************************************************************/ -int apple1_state::apple1_verify_header (UINT8 *data) -{ - /* Verify the format for the snapshot */ - if ((data[0] == 'L') && - (data[1] == 'O') && - (data[2] == 'A') && - (data[3] == 'D') && - (data[4] == ':') && - (data[7] == 'D') && - (data[8] == 'A') && - (data[9] == 'T') && - (data[10]== 'A') && - (data[11]== ':')) - { - return(IMAGE_VERIFY_PASS); - } - else - { - return(IMAGE_VERIFY_FAIL); - } -} - -#define SNAP_HEADER_LEN 12 - -/***************************************************************************** -** snapshot_load_apple1 -** -** Format of the binary snapshot image is: -** -** [ LOAD:xxyyDATA:zzzzzz...] -** -** where xxyy is the binary starting address (in big-endian byte -** order) to load the binary data zzzzzz to. -** -** The image can be of arbitrary length, but it must fit in available -** memory. -*****************************************************************************/ -SNAPSHOT_LOAD_MEMBER( apple1_state,apple1) -{ - UINT64 filesize, datasize; - UINT8 *snapbuf, *snapptr; - UINT16 start_addr, end_addr, addr; - - filesize = image.length(); - - /* Read the snapshot data into a temporary array */ - if (filesize < SNAP_HEADER_LEN) - return IMAGE_INIT_FAIL; - snapbuf = (UINT8*)image.ptr(); - if (!snapbuf) - return IMAGE_INIT_FAIL; - - /* Verify the snapshot header */ - if (apple1_verify_header(snapbuf) == IMAGE_VERIFY_FAIL) - { - logerror("apple1 - Snapshot Header is in incorrect format - needs to be LOAD:xxyyDATA:\n"); - return IMAGE_INIT_FAIL; - } - - datasize = filesize - SNAP_HEADER_LEN; - - /* Extract the starting address to load the snapshot to. */ - start_addr = (snapbuf[5] << 8) | (snapbuf[6]); - logerror("apple1 - LoadAddress is 0x%04x\n", start_addr); - - end_addr = start_addr + datasize - 1; - - if ((start_addr < 0xE000 && end_addr > m_ram->size() - 1) - || end_addr > 0xEFFF) - { - logerror("apple1 - Snapshot won't fit in this memory configuration;\n" - "needs memory from $%04X to $%04X.\n", start_addr, end_addr); - return IMAGE_INIT_FAIL; - } - - /* Copy the data into memory space. */ - for (addr = start_addr, snapptr = snapbuf + SNAP_HEADER_LEN; - addr <= end_addr; - addr++, snapptr++) - m_maincpu->space(AS_PROGRAM).write_byte(addr, *snapptr); - - - return IMAGE_INIT_PASS; -} - - -/***************************************************************************** -** apple1_kbd_poll -** -** Keyboard polling handles both ordinary keys and the special RESET -** and CLEAR SCREEN switches. -** -** For ordinary keys, this implements 2-key rollover to reduce the -** chance of missed keypresses. If we press a key and then press a -** second key while the first hasn't been completely released, as -** might happen during rapid typing, only the second key is -** registered; the first key is ignored. -** -** If multiple newly-pressed keys are found, the one closest to the -** end of the input ports list is counted; the others are ignored. -*****************************************************************************/ -TIMER_CALLBACK_MEMBER(apple1_state::apple1_kbd_poll) -{ - int port, bit; - int key_pressed; - UINT32 shiftkeys, ctrlkeys; - pia6821_device *pia = machine().device("pia"); - static const char *const keynames[] = { "KEY0", "KEY1", "KEY2", "KEY3" }; - - /* This holds the values of all the input ports for ordinary keys - seen during the last scan. */ - - /* First we check the RESET and CLEAR SCREEN pushbutton switches. */ - - /* The RESET switch resets the CPU and the 6820 PIA. */ - if (ioport("KEY5")->read() & 0x0001) - { - if (!m_reset_flag) { - m_reset_flag = 1; - /* using PULSE_LINE does not allow us to press and hold key */ - m_maincpu->set_input_line(INPUT_LINE_RESET, ASSERT_LINE); - pia->reset(); - } - } - else if (m_reset_flag) { - /* RESET released--allow the processor to continue. */ - m_reset_flag = 0; - m_maincpu->set_input_line(INPUT_LINE_RESET, CLEAR_LINE); - } - - /* The CLEAR SCREEN switch clears the video hardware. */ - if (ioport("KEY5")->read() & 0x0002) - { - if (!m_vh_clrscrn_pressed) - { - /* Ignore further video writes, and clear the screen. */ - m_vh_clrscrn_pressed = 1; - apple1_vh_dsp_clr(); - } - } - else if (m_vh_clrscrn_pressed) - { - /* CLEAR SCREEN released--pay attention to video writes again. */ - m_vh_clrscrn_pressed = 0; - } - - /* Now we scan all the input ports for ordinary keys, recording - new keypresses while ignoring keys that were already pressed in - the last scan. */ - - m_kbd_data = 0; - key_pressed = 0; - - /* The keyboard strobe line should always be low when a scan starts. */ - pia->ca1_w(0); - - shiftkeys = ioport("KEY4")->read() & 0x0003; - ctrlkeys = ioport("KEY4")->read() & 0x000c; - - for (port = 0; port < 4; port++) - { - UINT32 portval, newkeys; - - portval = ioport(keynames[port])->read(); - newkeys = portval & ~(m_kbd_last_scan[port]); - - if (newkeys) - { - key_pressed = 1; - for (bit = 0; bit < 16; bit++) { - if (newkeys & 1) - { - m_kbd_data = (ctrlkeys) - ? apple1_control_keymap[port*16 + bit] - : (shiftkeys) - ? apple1_shifted_keymap[port*16 + bit] - : apple1_unshifted_keymap[port*16 + bit]; - } - newkeys >>= 1; - } - } - m_kbd_last_scan[port] = portval; - } - - if (key_pressed) - { - /* The keyboard will pulse its strobe line when a key is - pressed. A 10-usec pulse is typical. */ - pia->ca1_w(1); - machine().scheduler().timer_set(attotime::from_usec(10), timer_expired_delegate(FUNC(apple1_state::apple1_kbd_strobe_end),this)); - } -} - -TIMER_CALLBACK_MEMBER(apple1_state::apple1_kbd_strobe_end) -{ - pia6821_device *pia = machine().device("pia"); - - /* End of the keyboard strobe pulse. */ - pia->ca1_w(0); -} - - -/***************************************************************************** -** READ/WRITE HANDLERS -*****************************************************************************/ -READ8_MEMBER(apple1_state::apple1_pia0_kbdin) -{ - /* Bit 7 of the keyboard input is permanently wired high. This is - what the ROM Monitor software expects. */ - return m_kbd_data | 0x80; -} - -WRITE8_MEMBER(apple1_state::apple1_pia0_dspout) -{ - /* Send an ASCII character to the video hardware. */ - apple1_vh_dsp_w(data); -} - -WRITE_LINE_MEMBER(apple1_state::apple1_pia0_dsp_write_signal) -{ - device_t *device = machine().device("pia"); - /* PIA output CB2 is inverted to become the DA signal, used to - signal a display write to the video hardware. */ - - /* DA is directly connected to PIA input PB7, so the processor can - read bit 7 of port B to test whether the display has completed - a write. */ - pia6821_device *pia = downcast(device); - pia->portb_w((!state) << 7); - - /* Once DA is asserted, the display will wait until it can perform - the write, when the cursor position is about to be refreshed. - Only then will it assert \RDA to signal readiness for another - write. Thus the write delay depends on the cursor position and - where the display is in the refresh cycle. */ - if (!state) - machine().scheduler().timer_set(apple1_vh_dsp_time_to_ready(), timer_expired_delegate(FUNC(apple1_state::apple1_dsp_ready_start),this)); -} - -TIMER_CALLBACK_MEMBER(apple1_state::apple1_dsp_ready_start) -{ - pia6821_device *pia = machine().device("pia"); - - /* When the display asserts \RDA to signal it is ready, it - triggers a 74123 one-shot to send a 3.5-usec low pulse to PIA - input CB1. The end of this pulse will tell the PIA that the - display is ready for another write. */ - pia->cb1_w(0); - machine().scheduler().timer_set(attotime::from_nsec(3500), timer_expired_delegate(FUNC(apple1_state::apple1_dsp_ready_end),this)); -} - -TIMER_CALLBACK_MEMBER(apple1_state::apple1_dsp_ready_end) -{ - pia6821_device *pia = machine().device("pia"); - - /* The one-shot pulse has ended; return CB1 to high, so we can do - another display write. */ - pia->cb1_w(1); -} diff --git a/src/mame/video/apple1.cpp b/src/mame/video/apple1.cpp deleted file mode 100644 index 2dc880127b5..00000000000 --- a/src/mame/video/apple1.cpp +++ /dev/null @@ -1,392 +0,0 @@ -// license:??? -// copyright-holders:Paul Daniels, Colin Howell, R. Belmont -/*************************************************************************** - - apple1.c - - Functions to emulate the video hardware of the Apple I. - - The Apple I video hardware was basically a dumb video terminal; in - fact it was based on Steve Wozniak's own design for a simple video - terminal. It had 40 columns by 24 lines of uppercase-only text. - Text could only be output at 60 characters per second, one character - per video frame. The cursor (a blinking @) could only be advanced - using spaces or carriage returns. Carriage returns were the only - control characters recognized. Previously written text could not be - altered, only scrolled off the top of the screen. - - The video memory used seven 1k-bit dynamic shift registers. Six of - these held the 6-bit visible character codes, and one stored the - cursor location as a simple bitmap--the bit for the cursor position - was set to 0, and all the other bits were 1. - - These shift registers were continuously recirculated, completing one - cycle per video frame. As a new line of characters was about to be - scanned by the video beam, that character line would be recirculated - into the shift registers and would simultaneously be stored into a - 6x40-bit line buffer (also a shift register). At this point, if the - cursor location was in this line, a new character could be written - into that location in the shift registers and the cursor could be - advanced. (Carriage returns were not written into the shift - registers; they only advanced the cursor.) - - The characters in the line buffer were recirculated 7 times to - display the 8 scan lines of the characters, before being replaced by - a new line of characters from the main shift registers. - - Cursor blinking was performed by a Signetics 555 timer IC whose - output was gated into the character code signals as they passed into - the line buffer. - - Character images were provided by a Signetics 2513 character - generator ROM, a chip also used in computer terminals such as the - ADM-3A. This ROM had 9 address lines and 5 data lines; it contained - 64 character images, each 5 pixels wide by 8 pixels high, with one - line of pixels being blank for vertical separation. The video - circuitry added the 2 pixels of horizontal separation for each - character. - - A special CLEAR SCREEN switch on the keyboard, directly connected to - the video hardware, could be used to clear the video memory and - return the cursor to the home position. This was completely - independent of the processor. - - A schematic of the Apple I video hardware can be found in the - Apple-1 Operation Manual; look for the schematic titled "Terminal - Section". Most of the functionality modeled here was determined by - reading this schematic. Many of the chips used were standard 74xx - TTL chips, but the shift registers used for the video memory and - line buffer were Signetics 25xx PMOS ICs. These were already - becoming obsolete when the Apple I was built, and detailed - information on them is very hard to find today. - -***************************************************************************/ - -#include "emu.h" -#include "includes/apple1.h" - - -/*************************************************************************** - - Terminal code - -***************************************************************************/ - -TILE_GET_INFO_MEMBER(apple1_state::terminal_gettileinfo) -{ - int ch, gfxfont, code, color; - - ch = m_current_terminal->mem[tile_index]; - code = ch & ((1 << m_current_terminal->char_bits) - 1); - color = ch >> m_current_terminal->char_bits; - gfxfont = m_current_terminal->gfx; - - if ((tile_index == m_current_terminal->cur_offset) && !m_current_terminal->cur_hidden && m_current_terminal->getcursorcode) - code = m_current_terminal->getcursorcode(code); - - SET_TILE_INFO_MEMBER(gfxfont, /* gfx */ - code, /* character */ - color, /* color */ - 0); /* flags */ -} - -void apple1_state::terminal_draw(screen_device &screen, bitmap_ind16 &dest, const rectangle &cliprect, terminal_t *terminal) -{ - m_current_terminal = terminal; - terminal->tm->draw(screen, dest, cliprect, 0, 0); - m_current_terminal = nullptr; -} - -void apple1_state::verify_coords(terminal_t *terminal, int x, int y) -{ - assert(x >= 0); - assert(y >= 0); - assert(x < terminal->num_cols); - assert(y < terminal->num_rows); -} - -void apple1_state::terminal_putchar(terminal_t *terminal, int x, int y, int ch) -{ - int offs; - - verify_coords(terminal, x, y); - - offs = y * terminal->num_cols + x; - if (terminal->mem[offs] != ch) - { - terminal->mem[offs] = ch; - terminal->tm->mark_tile_dirty(offs); - } -} - -int apple1_state::terminal_getchar(terminal_t *terminal, int x, int y) -{ - int offs; - - verify_coords(terminal, x, y); - offs = y * terminal->num_cols + x; - return terminal->mem[offs]; -} - -void apple1_state::terminal_putblank(terminal_t *terminal, int x, int y) -{ - terminal_putchar(terminal, x, y, terminal->blank_char); -} - -void apple1_state::terminal_dirtycursor(terminal_t *terminal) -{ - if (terminal->cur_offset >= 0) - terminal->tm->mark_tile_dirty(terminal->cur_offset); -} - -void apple1_state::terminal_setcursor(terminal_t *terminal, int x, int y) -{ - terminal_dirtycursor(terminal); - terminal->cur_offset = y * terminal->num_cols + x; - terminal_dirtycursor(terminal); -} - -void apple1_state::terminal_hidecursor(terminal_t *terminal) -{ - terminal->cur_hidden = 1; - terminal_dirtycursor(terminal); -} - -void apple1_state::terminal_showcursor(terminal_t *terminal) -{ - terminal->cur_hidden = 0; - terminal_dirtycursor(terminal); -} - -void apple1_state::terminal_getcursor(terminal_t *terminal, int *x, int *y) -{ - *x = terminal->cur_offset % terminal->num_cols; - *y = terminal->cur_offset / terminal->num_cols; -} - -void apple1_state::terminal_fill(terminal_t *terminal, int val) -{ - int i; - for (i = 0; i < terminal->num_cols * terminal->num_rows; i++) - terminal->mem[i] = val; - terminal->tm->mark_all_dirty(); -} - -void apple1_state::terminal_clear(terminal_t *terminal) -{ - terminal_fill(terminal, terminal->blank_char); -} - -terminal_t *apple1_state::terminal_create( - int gfx, int blank_char, int char_bits, - int (*getcursorcode)(int original_code), - int num_cols, int num_rows) -{ - terminal_t *term; - int char_width, char_height; - - char_width = m_gfxdecode->gfx(gfx)->width(); - char_height = m_gfxdecode->gfx(gfx)->height(); - - term = (terminal_t *) auto_alloc_array(machine(), char, sizeof(terminal_t) - sizeof(term->mem) - + (num_cols * num_rows * sizeof(termchar_t))); - - term->tm = &machine().tilemap().create(m_gfxdecode, tilemap_get_info_delegate(FUNC(apple1_state::terminal_gettileinfo),this), TILEMAP_SCAN_ROWS, - char_width, char_height, num_cols, num_rows); - - term->gfx = gfx; - term->blank_char = blank_char; - term->char_bits = char_bits; - term->num_cols = num_cols; - term->num_rows = num_rows; - term->getcursorcode = getcursorcode; - term->cur_offset = -1; - term->cur_hidden = 0; - terminal_clear(term); - return term; -} - - -/**************************************************************************/ - - - -/* The cursor blinking is generated by a free-running timer with a - 0.52-second period. It is on for 2/3 of this period and off for - 1/3. */ -#define CURSOR_OFF_LENGTH (0.52/3) - -/**************************************************************************/ - -static int apple1_getcursorcode(int original_code) -{ - /* Cursor uses symbol 0 (an @ sign) in the character generator ROM. */ - return 0; -} - -/**************************************************************************/ - -void apple1_state::video_start() -{ - m_blink_on = 1; /* cursor is visible initially */ - m_terminal = terminal_create( - 0, /* graphics font 0 (the only one we have) */ - 32, /* Blank character is symbol 32 in the ROM */ - 8, /* use 8 bits for the character code */ - apple1_getcursorcode, - 40, 24); /* 40 columns, 24 rows */ - - terminal_setcursor(m_terminal, 0, 0); -} - -/* This function handles all writes to the video display. */ -void apple1_state::apple1_vh_dsp_w (int data) -{ - int x, y; - int cursor_x, cursor_y; - - /* While CLEAR SCREEN is being held down, the hardware is forced - to clear the video memory, so video writes have no effect. */ - if (m_vh_clrscrn_pressed) - return; - - /* The video display port only accepts the 7 lowest bits of the char. */ - data &= 0x7f; - - terminal_getcursor(m_terminal, &cursor_x, &cursor_y); - - if (data == '\r') { - /* Carriage-return moves the cursor to the start of the next - line. */ - cursor_x = 0; - cursor_y++; - } - else if (data < ' ') { - /* Except for carriage-return, the video hardware completely - ignores all control characters. */ - return; - } - else { - /* For visible characters, only 6 bits of the ASCII code are - used, because the 2513 character generator ROM only - contains 64 symbols. The low 5 bits of the ASCII code are - used directly. Bit 6 is ignored, since it is the same for - all the available characters in the ROM. Bit 7 is inverted - before being used as the high bit of the 6-bit ROM symbol - index, because the block of 32 ASCII symbols containing the - uppercase letters comes first in the ROM. */ - - int romindx = (data & 0x1f) | (((data ^ 0x40) & 0x40) >> 1); - - terminal_putchar(m_terminal, cursor_x, cursor_y, romindx); - if (cursor_x < 39) - { - cursor_x++; - } - else - { - cursor_x = 0; - cursor_y++; - } - } - - /* If the cursor went past the bottom line, scroll the text up one line. */ - if (cursor_y == 24) - { - for (y = 1; y < 24; y++) - for (x = 0; x < 40; x++) - terminal_putchar(m_terminal, x, y-1, - terminal_getchar(m_terminal, x, y)); - - for (x = 0; x < 40; x++) - terminal_putblank(m_terminal, x, 23); - - cursor_y--; - } - - terminal_setcursor(m_terminal, cursor_x, cursor_y); -} - -/* This function handles clearing the video display on cold-boot or in - response to a press of the CLEAR SCREEN switch. */ -void apple1_state::apple1_vh_dsp_clr () -{ - terminal_setcursor(m_terminal, 0, 0); - terminal_clear(m_terminal); -} - -/* Calculate how long it will take for the display to assert the RDA - signal in response to a video display write. This signal indicates - the display has completed the write and is ready to accept another - write. */ -attotime apple1_state::apple1_vh_dsp_time_to_ready () -{ - int cursor_x, cursor_y; - int cursor_scanline; - double scanline_period = m_screen->scan_period().as_double(); - double cursor_hfrac; - - /* The video hardware refreshes the screen by reading the - character codes from its circulating shift-register memory. - Because of the way this memory works, a new character can only - be written into the cursor location at the moment this location - is about to be read. This happens during the first scanline of - the cursor's character line, when the beam reaches the cursor's - horizontal position. */ - - terminal_getcursor(m_terminal, &cursor_x, &cursor_y); - cursor_scanline = cursor_y * apple1_charlayout.height; - - /* Each scanline is composed of 455 pixel times. The first 175 of - these are the horizontal blanking period; the remaining 280 are - for the visible part of the scanline. */ - cursor_hfrac = (175 + cursor_x * apple1_charlayout.width) / 455; - - if (m_screen->vpos() == cursor_scanline) { - /* video_screen_get_hpos() doesn't account for the horizontal - blanking interval; it acts as if the scanline period is - entirely composed of visible pixel times. However, we can - still use it to find what fraction of the current scanline - period has elapsed. */ - double current_hfrac = m_screen->hpos() / - m_screen->width(); - if (current_hfrac < cursor_hfrac) - return attotime::from_double(scanline_period * (cursor_hfrac - current_hfrac)); - } - - return attotime::from_double( - m_screen->time_until_pos(cursor_scanline, 0).as_double() + - scanline_period * cursor_hfrac); -} - -/* Blink the cursor on or off, as appropriate. */ -void apple1_state::apple1_vh_cursor_blink () -{ - int new_blink_on; - - /* The cursor is on for 2/3 of its blink period and off for 1/3. - This is most easily handled by dividing the total elapsed time - by the length of the off-portion of the cycle, giving us the - number of one-third-cycles elapsed, then checking the result - modulo 3. */ - - if (((int) (machine().time().as_double() / CURSOR_OFF_LENGTH)) % 3 < 2) - new_blink_on = 1; - else - new_blink_on = 0; - - if (new_blink_on != m_blink_on) { /* have we changed state? */ - if (new_blink_on) - terminal_showcursor(m_terminal); - else - terminal_hidecursor(m_terminal); - m_blink_on = new_blink_on; - } -} - -UINT32 apple1_state::screen_update_apple1(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect) -{ - apple1_vh_cursor_blink(); - terminal_draw(screen, bitmap, cliprect, m_terminal); - return 0; -}