/********************************************************************** Apple I CPU: 6502 @ 1.023 MHz (Effective speed with RAM refresh waits is 0.960 MHz.) RAM: 4-8 KB on main board (4 KB standard) 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) ) $F000-$FFFF: ROM address space $FF00-$FFFF: Apple Monitor ROM 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 Examples: 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. **********************************************************************/ #include "emu.h" #include "cpu/m6502/m6502.h" #include "machine/6821pia.h" #include "includes/apple1.h" #include "imagedev/snapquik.h" #include "imagedev/cassette.h" #include "machine/ram.h" /* port i/o functions */ /* memory w/r functions */ static ADDRESS_MAP_START( apple1_map, AS_PROGRAM, 8, apple1_state ) AM_RANGE(0x0000, 0xbfff) AM_NOP /* Cassette interface I/O space: */ AM_RANGE(0xc000, 0xc0ff) AM_READWRITE(apple1_cassette_r, apple1_cassette_w) /* Cassette interface ROM: */ AM_RANGE(0xc100, 0xc1ff) AM_ROM AM_RANGE(0xc200, 0xcfff) AM_NOP /* 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) /* $Dxxx addresses with bit 4 low are NOPs. */ AM_RANGE(0xd000, 0xd00f) AM_NOP AM_MIRROR(0xfe0) /* 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 ADDRESS_MAP_END /* graphics output */ const gfx_layout apple1_charlayout = { 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 */ }; static GFXDECODE_START( apple1 ) GFXDECODE_ENTRY( "gfx1", 0x0000, apple1_charlayout, 0, 1 ) GFXDECODE_END /* 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. */ static INPUT_PORTS_START( apple1 ) PORT_START("KEY0") /* first sixteen keys */ 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('@') PORT_BIT( 0x0008, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_3) PORT_CHAR('3') PORT_CHAR('#') PORT_BIT( 0x0010, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_4) PORT_CHAR('4') PORT_CHAR('$') PORT_BIT( 0x0020, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_5) PORT_CHAR('5') PORT_CHAR('%') PORT_BIT( 0x0040, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_6) PORT_CHAR('6') PORT_CHAR('^') PORT_BIT( 0x0080, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_7) PORT_CHAR('7') PORT_CHAR('&') PORT_BIT( 0x0100, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_8) PORT_CHAR('8') PORT_CHAR('*') PORT_BIT( 0x0200, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_9) PORT_CHAR('9') PORT_CHAR('(') PORT_BIT( 0x0400, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_MINUS) PORT_CHAR('-') PORT_CHAR('_') PORT_BIT( 0x0800, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_EQUALS) PORT_CHAR('=') PORT_CHAR('+') PORT_BIT( 0x1000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_OPENBRACE) PORT_CHAR('[') PORT_BIT( 0x2000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_CLOSEBRACE) PORT_CHAR(']') 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_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('?') PORT_BIT( 0x0008, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_BACKSLASH) PORT_CHAR('\\') PORT_BIT( 0x0010, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_A) PORT_CHAR('A') PORT_BIT( 0x0020, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_B) PORT_CHAR('B') PORT_BIT( 0x0040, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_C) PORT_CHAR('C') PORT_BIT( 0x0080, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_D) PORT_CHAR('D') PORT_BIT( 0x0100, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_E) PORT_CHAR('E') PORT_BIT( 0x0200, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_F) PORT_CHAR('F') PORT_BIT( 0x0400, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_G) PORT_CHAR('G') PORT_BIT( 0x0800, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_H) PORT_CHAR('H') PORT_BIT( 0x1000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_I) PORT_CHAR('I') PORT_BIT( 0x2000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_J) PORT_CHAR('J') 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_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') PORT_BIT( 0x0008, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_P) PORT_CHAR('P') PORT_BIT( 0x0010, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_Q) PORT_CHAR('Q') PORT_BIT( 0x0020, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_R) PORT_CHAR('R') PORT_BIT( 0x0040, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_S) PORT_CHAR('S') PORT_BIT( 0x0080, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_T) PORT_CHAR('T') PORT_BIT( 0x0100, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_U) PORT_CHAR('U') PORT_BIT( 0x0200, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_V) PORT_CHAR('V') PORT_BIT( 0x0400, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_W) PORT_CHAR('W') PORT_BIT( 0x0800, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_X) PORT_CHAR('X') 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_START("KEY3") /* fourth sixteen keys */ 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)) INPUT_PORTS_END /* sound output */ static const cassette_interface apple1_cassette_interface = { cassette_default_formats, NULL, (cassette_state)(CASSETTE_STOPPED), "apple1_cass", NULL }; /* 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_PROGRAM_MAP(apple1_map) MCFG_QUANTUM_TIME(attotime::from_hz(60)) 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_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)) /* snapshot */ MCFG_SNAPSHOT_ADD("snapshot", apple1_state, apple1, "snp", 0) MCFG_CASSETTE_ADD("cassette", apple1_cassette_interface) 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(0x10000, "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", 0xFF00, 0x0100, CRC(254bfb95) SHA1(b6468b72295b7d8ac288d104d252f24de1f1d611) ) ROM_LOAD_NIB_LOW( "apple-a1.a1", 0xFF00, 0x0100, CRC(434f8ce6) SHA1(9deee2d39903209b20c3fc6b58e16372f8efece1) ) /* 256-byte cassette interface ROM, in two 82s129 or mmi6301 256x4 proms at locations 3 and 4 on the cassette interface daughtercard (they are labeled "MMI 6301-IJ // 7623L // APPLE-A3" and "MMI 6301-IJ // 7623L // APPLE-A4") */ ROM_LOAD_NIB_HIGH( "apple-a3.3", 0xc100, 0x0100, CRC(6eae8f52) SHA1(71906932727ef70952ef6afe6b08708df15cd67d) ) ROM_LOAD_NIB_LOW( "apple-a4.4", 0xc100, 0x0100, CRC(94efa977) SHA1(851f3bd6863859a1a6909179a5e5bf744b3d807e) ) /* 512-byte Signetics 2513 character generator ROM at location D2-D3 */ 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 INIT COMPANY FULLNAME */ COMP( 1976, apple1, 0, 0, apple1, apple1, apple1_state, apple1, "Apple Computer", "Apple I" , GAME_NO_SOUND )