From db3a5af3c5f459523c7f3476ba2a200ad8957799 Mon Sep 17 00:00:00 2001 From: hap Date: Fri, 8 Jul 2022 18:26:41 +0200 Subject: source org: move pdp1 to dec folder --- src/mame/dec/pdp1.cpp | 1849 ++++++++++++++++++++++++++++++++++++++++++++++ src/mame/dec/pdp1.h | 484 ++++++++++++ src/mame/dec/pdp1_v.cpp | 593 +++++++++++++++ src/mame/mame.lst | 2 +- src/mame/mess.flt | 2 +- src/mame/pdp1/pdp1.cpp | 1849 ---------------------------------------------- src/mame/pdp1/pdp1.h | 484 ------------ src/mame/pdp1/pdp1_v.cpp | 593 --------------- 8 files changed, 2928 insertions(+), 2928 deletions(-) create mode 100644 src/mame/dec/pdp1.cpp create mode 100644 src/mame/dec/pdp1.h create mode 100644 src/mame/dec/pdp1_v.cpp delete mode 100644 src/mame/pdp1/pdp1.cpp delete mode 100644 src/mame/pdp1/pdp1.h delete mode 100644 src/mame/pdp1/pdp1_v.cpp diff --git a/src/mame/dec/pdp1.cpp b/src/mame/dec/pdp1.cpp new file mode 100644 index 00000000000..fd719ce63b0 --- /dev/null +++ b/src/mame/dec/pdp1.cpp @@ -0,0 +1,1849 @@ +// license:GPL-2.0+ +// copyright-holders:Raphael Nabet +/* + +Driver for a PDP1 emulator. + + Digital Equipment Corporation + Brian Silverman (original Java Source) + Vadim Gerasimov (original Java Source) + Chris Salomon (MESS driver) + Raphael Nabet (MESS driver) + +Initially, this was a conversion of a JAVA emulator +(although code has been edited extensively ever since). +I have tried contacting the author, but heard as yet nothing of him, +so I don't know if it all right with him, but after all -> he did +release the source, so hopefully everything will be fine (no his +name is not Marat). + +Note: naturally I have no PDP1, I have never seen one, nor have I any +programs for it. + +The first supported program was: + +SPACEWAR! + +The first Videogame EVER! + +When I saw the java emulator, running that game I was quite intrigued to +include a driver for MESS. +I think the historical value of SPACEWAR! is enormous. + +Two other programs are supported: Munching squares and LISP. + +Added Debugging and Disassembler... + + +Also: +ftp://minnie.cs.adfa.oz.au/pub/PDP-11/Sims/Supnik_2.3/software/lispswre.tar.gz +Is a packet which includes the original LISP as source and +binary form plus a macro assembler for PDP1 programs. + +For more documentation look at the source for the driver, +and the cpu/pdp1/pdp1.c file (information about the whereabouts of information +and the java source). + + +To load and play a game: +- Load a .rim file into the first tape reader +- Hold down Left Control, and press Enter. Let go. +- The lights will flash while the paper tape is being read. +- At the end, the game will start. + + + +*/ + +#include "emu.h" +#include "pdp1.h" + +#include "cpu/pdp1/pdp1.h" + +#include "screen.h" +#include "softlist_dev.h" + + +/* + * + * The loading storing OS... is not emulated (I haven't a clue where to + * get programs for the machine) + * + */ + + +void pdp1_state::pdp1_map(address_map &map) +{ + map(0x00000, 0x3ffff).ram(); +} + +static INPUT_PORTS_START( pdp1 ) + PORT_START("SPACEWAR") /* 0: spacewar controllers */ + PORT_BIT( ROTATE_LEFT_PLAYER1, IP_ACTIVE_HIGH, IPT_JOYSTICK_LEFT) PORT_NAME("Spin Left Player 1") PORT_CODE(KEYCODE_A) PORT_CODE(JOYCODE_X_LEFT_SWITCH) + PORT_BIT( ROTATE_RIGHT_PLAYER1, IP_ACTIVE_HIGH, IPT_JOYSTICK_RIGHT) PORT_NAME("Spin Right Player 1") PORT_CODE(KEYCODE_S) PORT_CODE(JOYCODE_X_RIGHT_SWITCH) + PORT_BIT( THRUST_PLAYER1, IP_ACTIVE_HIGH, IPT_BUTTON1) PORT_NAME("Thrust Player 1") PORT_CODE(KEYCODE_D) PORT_CODE(JOYCODE_BUTTON1) + PORT_BIT( FIRE_PLAYER1, IP_ACTIVE_HIGH, IPT_BUTTON2) PORT_NAME("Fire Player 1") PORT_CODE(KEYCODE_F) PORT_CODE(JOYCODE_BUTTON2) + PORT_BIT( ROTATE_LEFT_PLAYER2, IP_ACTIVE_HIGH, IPT_JOYSTICK_LEFT) PORT_NAME("Spin Left Player 2") PORT_CODE(KEYCODE_LEFT) PORT_CODE(JOYCODE_X_LEFT_SWITCH ) PORT_PLAYER(2) + PORT_BIT( ROTATE_RIGHT_PLAYER2, IP_ACTIVE_HIGH, IPT_JOYSTICK_RIGHT) PORT_NAME("Spin Right Player 2") PORT_CODE(KEYCODE_RIGHT) PORT_CODE(JOYCODE_X_RIGHT_SWITCH ) PORT_PLAYER(2) + PORT_BIT( THRUST_PLAYER2, IP_ACTIVE_HIGH, IPT_BUTTON1) PORT_NAME("Thrust Player 2") PORT_CODE(KEYCODE_UP) PORT_CODE(JOYCODE_BUTTON1 ) PORT_PLAYER(2) + PORT_BIT( FIRE_PLAYER2, IP_ACTIVE_HIGH, IPT_BUTTON2) PORT_NAME("Fire Player 2") PORT_CODE(KEYCODE_DOWN) PORT_CODE(JOYCODE_BUTTON2 ) PORT_PLAYER(2) + PORT_BIT( HSPACE_PLAYER1, IP_ACTIVE_HIGH, IPT_BUTTON3) PORT_NAME("Hyperspace Player 1") PORT_CODE(KEYCODE_Z) PORT_CODE(JOYCODE_BUTTON3) + PORT_BIT( HSPACE_PLAYER2, IP_ACTIVE_HIGH, IPT_BUTTON3) PORT_NAME("Hyperspace Player 2") PORT_CODE(KEYCODE_SLASH) PORT_CODE(JOYCODE_BUTTON3 ) PORT_PLAYER(2) + + PORT_START("CSW") /* 1: various pdp1 operator control panel switches */ + PORT_BIT(pdp1_control, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("control panel key") PORT_CODE(KEYCODE_LCONTROL) + PORT_BIT(pdp1_extend, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("extend") PORT_CODE(KEYCODE_TILDE) + PORT_BIT(pdp1_start_nobrk, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("start (sequence break disabled)") PORT_CODE(KEYCODE_U) + PORT_BIT(pdp1_start_brk, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("start (sequence break enabled)") PORT_CODE(KEYCODE_I) + PORT_BIT(pdp1_stop, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("stop") PORT_CODE(KEYCODE_O) + PORT_BIT(pdp1_continue, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("continue") PORT_CODE(KEYCODE_P) + PORT_BIT(pdp1_examine, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("examine") PORT_CODE(KEYCODE_OPENBRACE) + PORT_BIT(pdp1_deposit, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("deposit") PORT_CODE(KEYCODE_CLOSEBRACE) + PORT_BIT(pdp1_read_in, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("read in") PORT_CODE(KEYCODE_ENTER) + PORT_BIT(pdp1_reader, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("reader") + PORT_BIT(pdp1_tape_feed, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("tape feed") + PORT_BIT(pdp1_single_step, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("single step") PORT_CODE(KEYCODE_STOP) + PORT_BIT(pdp1_single_inst, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("single inst") PORT_CODE(KEYCODE_SLASH) + + PORT_START("SENSE") /* 2: operator control panel sense switches */ + PORT_DIPNAME( 040, 000, "Sense Switch 1") PORT_CODE(KEYCODE_1_PAD) + PORT_DIPSETTING( 000, DEF_STR( Off ) ) + PORT_DIPSETTING( 040, DEF_STR( On ) ) + PORT_DIPNAME( 020, 000, "Sense Switch 2") PORT_CODE(KEYCODE_2_PAD) + PORT_DIPSETTING( 000, DEF_STR( Off ) ) + PORT_DIPSETTING( 020, DEF_STR( On ) ) + PORT_DIPNAME( 010, 000, "Sense Switch 3") PORT_CODE(KEYCODE_3_PAD) + PORT_DIPSETTING( 000, DEF_STR( Off ) ) + PORT_DIPSETTING( 010, DEF_STR( On ) ) + PORT_DIPNAME( 004, 000, "Sense Switch 4") PORT_CODE(KEYCODE_4_PAD) + PORT_DIPSETTING( 000, DEF_STR( Off ) ) + PORT_DIPSETTING( 004, DEF_STR( On ) ) + PORT_DIPNAME( 002, 002, "Sense Switch 5") PORT_CODE(KEYCODE_5_PAD) + PORT_DIPSETTING( 000, DEF_STR( Off ) ) + PORT_DIPSETTING( 002, DEF_STR( On ) ) + PORT_DIPNAME( 001, 000, "Sense Switch 6") PORT_CODE(KEYCODE_6_PAD) + PORT_DIPSETTING( 000, DEF_STR( Off ) ) + PORT_DIPSETTING( 001, DEF_STR( On ) ) + + PORT_START("TSTADD") /* 3: operator control panel test address switches */ + PORT_BIT( 0100000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Extension Test Address Switch 3") PORT_CODE(KEYCODE_1) + PORT_BIT( 0040000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Extension Test Address Switch 4") PORT_CODE(KEYCODE_2) + PORT_BIT( 0020000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Extension Test Address Switch 5") PORT_CODE(KEYCODE_3) + PORT_BIT( 0010000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Extension Test Address Switch 6") PORT_CODE(KEYCODE_4) + PORT_BIT( 0004000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Test Address Switch 7") PORT_CODE(KEYCODE_5) + PORT_BIT( 0002000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Test Address Switch 8") PORT_CODE(KEYCODE_6) + PORT_BIT( 0001000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Test Address Switch 9") PORT_CODE(KEYCODE_7) + PORT_BIT( 0000400, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Test Address Switch 10") PORT_CODE(KEYCODE_8) + PORT_BIT( 0000200, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Test Address Switch 11") PORT_CODE(KEYCODE_9) + PORT_BIT( 0000100, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Test Address Switch 12") PORT_CODE(KEYCODE_0) + PORT_BIT( 0000040, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Test Address Switch 13") PORT_CODE(KEYCODE_MINUS) + PORT_BIT( 0000020, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Test Address Switch 14") PORT_CODE(KEYCODE_EQUALS) + PORT_BIT( 0000010, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Test Address Switch 15") PORT_CODE(KEYCODE_Q) + PORT_BIT( 0000004, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Test Address Switch 16") PORT_CODE(KEYCODE_W) + PORT_BIT( 0000002, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Test Address Switch 17") PORT_CODE(KEYCODE_E) + PORT_BIT( 0000001, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Test Address Switch 18") PORT_CODE(KEYCODE_R) + + PORT_START("TWDMSB") /* 4: operator control panel test word switches MSB */ + PORT_BIT( 0002, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Test Word Switch 1") PORT_CODE(KEYCODE_A) + PORT_BIT( 0001, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Test Word Switch 2") PORT_CODE(KEYCODE_S) + + PORT_START("TWDLSB") /* 5: operator control panel test word switches LSB */ + PORT_BIT( 0100000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Test Word Switch 3") PORT_CODE(KEYCODE_D) + PORT_BIT( 0040000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Test Word Switch 4") PORT_CODE(KEYCODE_F) + PORT_BIT( 0020000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Test Word Switch 5") PORT_CODE(KEYCODE_G) + PORT_BIT( 0010000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Test Word Switch 6") PORT_CODE(KEYCODE_H) + PORT_BIT( 0004000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Test Word Switch 7") PORT_CODE(KEYCODE_J) + PORT_BIT( 0002000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Test Word Switch 8") PORT_CODE(KEYCODE_K) + PORT_BIT( 0001000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Test Word Switch 9") PORT_CODE(KEYCODE_L) + PORT_BIT( 0000400, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Test Word Switch 10") PORT_CODE(KEYCODE_COLON) + PORT_BIT( 0000200, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Test Word Switch 11") PORT_CODE(KEYCODE_QUOTE) + PORT_BIT( 0000100, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Test Word Switch 12") PORT_CODE(KEYCODE_BACKSLASH) + PORT_BIT( 0000040, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Test Word Switch 13") PORT_CODE(KEYCODE_Z) + PORT_BIT( 0000020, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Test Word Switch 14") PORT_CODE(KEYCODE_X) + PORT_BIT( 0000010, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Test Word Switch 15") PORT_CODE(KEYCODE_C) + PORT_BIT( 0000004, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Test Word Switch 16") PORT_CODE(KEYCODE_V) + PORT_BIT( 0000002, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Test Word Switch 17") PORT_CODE(KEYCODE_B) + PORT_BIT( 0000001, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Test Word Switch 18") PORT_CODE(KEYCODE_N) + + /* + Note that I can see 2 additional keys whose purpose is unknown to me. + The caps look like "MAR REL" for the leftmost one and "MAR SET" for + rightmost one: maybe they were used to set the margin (I don't have the + manual for the typewriter). */ + + PORT_START("TWR.0") /* 6: typewriter codes 00-17 */ + PORT_BIT(0x0001, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("(Space)") PORT_CODE(KEYCODE_SPACE) + PORT_BIT(0x0002, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("1 \"") PORT_CODE(KEYCODE_1) + PORT_BIT(0x0004, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("2 '") PORT_CODE(KEYCODE_2) + PORT_BIT(0x0008, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("3 ~") PORT_CODE(KEYCODE_3) + PORT_BIT(0x0010, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("4 (implies)") PORT_CODE(KEYCODE_4) + PORT_BIT(0x0020, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("5 (or)") PORT_CODE(KEYCODE_5) + PORT_BIT(0x0040, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("6 (and)") PORT_CODE(KEYCODE_6) + PORT_BIT(0x0080, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("7 <") PORT_CODE(KEYCODE_7) + PORT_BIT(0x0100, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("8 >") PORT_CODE(KEYCODE_8) + PORT_BIT(0x0200, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("9 (up arrow)") PORT_CODE(KEYCODE_9) + + PORT_START("TWR.1") /* 7: typewriter codes 20-37 */ + PORT_BIT(0x0001, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("0 (right arrow)") PORT_CODE(KEYCODE_0) + PORT_BIT(0x0002, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("/ ?") PORT_CODE(KEYCODE_SLASH) + PORT_BIT(0x0004, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("S") PORT_CODE(KEYCODE_S) + PORT_BIT(0x0008, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("T") PORT_CODE(KEYCODE_T) + PORT_BIT(0x0010, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("U") PORT_CODE(KEYCODE_U) + PORT_BIT(0x0020, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("V") PORT_CODE(KEYCODE_V) + PORT_BIT(0x0040, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("W") PORT_CODE(KEYCODE_W) + PORT_BIT(0x0080, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("X") PORT_CODE(KEYCODE_X) + PORT_BIT(0x0100, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Y") PORT_CODE(KEYCODE_Y) + PORT_BIT(0x0200, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Z") PORT_CODE(KEYCODE_Z) + PORT_BIT(0x0800, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME(", =") PORT_CODE(KEYCODE_COMMA) + PORT_BIT(0x4000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Tab Key") PORT_CODE(KEYCODE_TAB) + + PORT_START("TWR.2") /* 8: typewriter codes 40-57 */ + PORT_BIT(0x0001, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("(non-spacing middle dot) _") PORT_CODE(KEYCODE_QUOTE) + PORT_BIT(0x0002, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("J") PORT_CODE(KEYCODE_J) + PORT_BIT(0x0004, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("K") PORT_CODE(KEYCODE_K) + PORT_BIT(0x0008, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("L") PORT_CODE(KEYCODE_L) + PORT_BIT(0x0010, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("M") PORT_CODE(KEYCODE_M) + PORT_BIT(0x0020, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("N") PORT_CODE(KEYCODE_N) + PORT_BIT(0x0040, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("O") PORT_CODE(KEYCODE_O) + PORT_BIT(0x0080, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("P") PORT_CODE(KEYCODE_P) + PORT_BIT(0x0100, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Q") PORT_CODE(KEYCODE_Q) + PORT_BIT(0x0200, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("R") PORT_CODE(KEYCODE_R) + PORT_BIT(0x1000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("- +") PORT_CODE(KEYCODE_COLON) + PORT_BIT(0x2000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME(") ]") PORT_CODE(KEYCODE_EQUALS) + PORT_BIT(0x4000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("(non-spacing overstrike) |") PORT_CODE(KEYCODE_OPENBRACE) + PORT_BIT(0x8000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("( [") PORT_CODE(KEYCODE_MINUS) + + PORT_START("TWR.3") /* 9: typewriter codes 60-77 */ + PORT_BIT(0x0002, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("A") PORT_CODE(KEYCODE_A) + PORT_BIT(0x0004, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("B") PORT_CODE(KEYCODE_B) + PORT_BIT(0x0008, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("C") PORT_CODE(KEYCODE_C) + PORT_BIT(0x0010, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("D") PORT_CODE(KEYCODE_D) + PORT_BIT(0x0020, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("E") PORT_CODE(KEYCODE_E) + PORT_BIT(0x0040, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("F") PORT_CODE(KEYCODE_F) + PORT_BIT(0x0080, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("G") PORT_CODE(KEYCODE_G) + PORT_BIT(0x0100, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("H") PORT_CODE(KEYCODE_H) + PORT_BIT(0x0200, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("I") PORT_CODE(KEYCODE_I) + PORT_BIT(0x0400, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Lower Case") PORT_CODE(KEYCODE_LSHIFT) + PORT_BIT(0x0800, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME(". (multiply)") PORT_CODE(KEYCODE_STOP) + PORT_BIT(0x1000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Upper case") PORT_CODE(KEYCODE_RSHIFT) + /* hack to support my macintosh which does not differentiate the Right Shift key */ + /* PORT_BIT(0x1000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Upper case") PORT_CODE(KEYCODE_CAPSLOCK) */ + PORT_BIT(0x2000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Backspace") PORT_CODE(KEYCODE_BACKSPACE) + PORT_BIT(0x8000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Return") PORT_CODE(KEYCODE_ENTER) + + PORT_START("CFG") /* 10: pseudo-input port with config */ + PORT_DIPNAME( 0x0003, 0x0002, "RAM size") + PORT_DIPSETTING( 0x0000, "4kw" ) + PORT_DIPSETTING( 0x0001, "32kw") + PORT_DIPSETTING( 0x0002, "64kw") + PORT_DIPNAME( 0x0004, 0x0000, "Hardware multiply") + PORT_DIPSETTING( 0x0000, DEF_STR( Off ) ) + PORT_DIPSETTING( 0x0004, DEF_STR( On ) ) + PORT_DIPNAME( 0x0008, 0x0000, "Hardware divide") + PORT_DIPSETTING( 0x0000, DEF_STR( Off ) ) + PORT_DIPSETTING( 0x0008, DEF_STR( On ) ) + PORT_DIPNAME( 0x0010, 0x0000, "Type 20 sequence break system") + PORT_DIPSETTING( 0x0000, DEF_STR( Off ) ) + PORT_DIPSETTING( 0x0010, DEF_STR( On ) ) + PORT_DIPNAME( 0x0020, 0x0000, "Type 32 light pen") PORT_CODE(KEYCODE_ENTER_PAD) + PORT_DIPSETTING( 0x0000, DEF_STR( Off ) ) + PORT_DIPSETTING( 0x0020, DEF_STR( On ) ) + + PORT_START("LIGHTPEN") /* 11: pseudo-input port with lightpen status */ + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("select larger light pen tip") PORT_CODE(KEYCODE_PLUS_PAD) + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("select smaller light pen tip") PORT_CODE(KEYCODE_MINUS_PAD) + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_BUTTON1) PORT_NAME("light pen down") + + PORT_START("LIGHTX") /* 12: lightpen - X AXIS */ + PORT_BIT( 0xff, 0x00, IPT_TRACKBALL_X) PORT_SENSITIVITY(100) PORT_KEYDELTA(0) PORT_PLAYER(1) PORT_RESET + + PORT_START("LIGHTY") /* 13: lightpen - Y AXIS */ + PORT_BIT( 0xff, 0x00, IPT_TRACKBALL_Y) PORT_SENSITIVITY(100) PORT_KEYDELTA(0) PORT_PLAYER(1) PORT_RESET +INPUT_PORTS_END + + +static const gfx_layout fontlayout = +{ + 6, 8, /* 6*8 characters */ + pdp1_charnum, /* 96+4 characters */ + 1, /* 1 bit per pixel */ + { 0 }, + { 0, 1, 2, 3, 4, 5, 6, 7 }, /* straightforward layout */ + { 0*8, 1*8, 2*8, 3*8, 4*8, 5*8, 6*8, 7*8 }, + 8*8 /* every char takes 8 consecutive bytes */ +}; + + +/* + The static palette only includes the pens for the control panel and + the typewriter, as the CRT palette is generated dynamically. + + The CRT palette defines various levels of intensity between white and + black. Grey levels follow an exponential law, so that decrementing the + color index periodically will simulate the remanence of a cathode ray tube. +*/ +static constexpr rgb_t pdp1_colors[] = +{ + {0x00, 0x00, 0x00 }, // black + {0xff, 0xff, 0xff }, // white + {0x00, 0xff, 0x00 }, // green + {0x00, 0x40, 0x00 }, // dark green + {0xff, 0x00, 0x00 }, // red + {0x80, 0x80, 0x80 } // light gray +}; + +static constexpr uint8_t pdp1_pens[] = +{ + pen_panel_bg, pen_panel_caption, + pen_typewriter_bg, pen_black, + pen_typewriter_bg, pen_red +}; + +static const uint8_t total_colors_needed = pen_crt_num_levels + sizeof(pdp1_colors) / 3; + +static GFXDECODE_START( gfx_pdp1 ) + GFXDECODE_ENTRY( "gfx1", 0, fontlayout, pen_crt_num_levels + sizeof(pdp1_colors) / 3, 3 ) +GFXDECODE_END + +/* Initialise the palette */ +void pdp1_state::pdp1_palette(palette_device &palette) const +{ + // rgb components for the two color emissions + constexpr double r1 = .1, g1 = .1, b1 = .924, r2 = .7, g2 = .7, b2 = .076; + // half period in seconds for the two color emissions + constexpr double half_period_1 = .05, half_period_2 = .20; + // refresh period in seconds + constexpr double update_period = 1./refresh_rate; + double decay_1, decay_2; + double cur_level_1, cur_level_2; + + // initialize CRT palette + + // compute the decay factor per refresh frame + decay_1 = pow(.5, update_period / half_period_1); + decay_2 = pow(.5, update_period / half_period_2); + + cur_level_1 = cur_level_2 = 255.; // start with maximum level + + for (int i = pen_crt_max_intensity; i>0; i--) + { + // compute the current color + int const r = int((r1*cur_level_1 + r2*cur_level_2) + .5); + int const g = int((g1*cur_level_1 + g2*cur_level_2) + .5); + int const b = int((b1*cur_level_1 + b2*cur_level_2) + .5); + // write color in palette + palette.set_indirect_color(i, rgb_t(r, g, b)); + // apply decay for next iteration + cur_level_1 *= decay_1; + cur_level_2 *= decay_2; + } + + palette.set_indirect_color(0, rgb_t(0, 0, 0)); + + // load static palette + for (int i = 0; i < 6; i++) + palette.set_indirect_color(pen_crt_num_levels + i, pdp1_colors[i]); + + // copy colortable to palette + for (int i = 0; i < total_colors_needed; i++) + palette.set_pen_indirect(i, i); + + // set up palette for text + for (int i = 0; i < 6; i++) + palette.set_pen_indirect(total_colors_needed + i, pdp1_pens[i]); +} + + +/* + pdp1 machine code + + includes emulation for I/O devices (with the IOT opcode) and control panel functions + + TODO: + * typewriter out should overwrite the typewriter buffer + * improve emulation of the internals of tape reader? + * improve puncher timing? +*/ + + +/* This flag makes the emulated pdp-1 trigger a sequence break request when a character has been +typed on the typewriter keyboard. It is useful in order to test sequence break, but we need +to emulate a connection box in which we can connect each wire to any interrupt line. Also, +we need to determine the exact relationship between the status register and the sequence break +system (both standard and type 20). */ +#define USE_SBS 0 + +#define LOG_IOT 0 +#define LOG_IOT_EXTRA 0 + +/* IOT completion may take much more than the 5us instruction time. A possible programming +error would be to execute an IOT before the last IOT of the same kind is over: such a thing +would confuse the targeted IO device, which might ignore the latter IOT, execute either +or both IOT incompletely, or screw up completely. I insist that such an error can be caused +by a pdp-1 programming error, even if there is no emulator error. */ +#define LOG_IOT_OVERLAP 0 + + +/* + devices which are known to generate a completion pulse (source: maintenance manual 9-??, + and 9-20, 9-21): + emulated: + * perforated tape reader + * perforated tape punch + * typewriter output + * CRT display + unemulated: + * card punch (pac: 43) + * line printer (lpr, lsp, but NOT lfb) + + This list should probably include additional optional devices (card reader comes to mind). +*/ + +/* IO status word */ + +/* defines for io_status bits */ +enum +{ + io_st_pen = 0400000, /* light pen: light has hit the pen */ + io_st_ptr = 0200000, /* perforated tape reader: reader buffer full */ + io_st_tyo = 0100000, /* typewriter out: device ready */ + io_st_tyi = 0040000, /* typewriter in: new character in buffer */ + io_st_ptp = 0020000 /* perforated tape punch: device ready */ +}; + + + + + + + +/* crt display timer */ + +/* light pen config */ + + + +#define PARALLEL_DRUM_WORD_TIME attotime::from_nsec(8500) +#define PARALLEL_DRUM_ROTATION_TIME attotime::from_nsec(8500*4096) + + +static pdp1_reset_param_t pdp1_reset_param = +{ + 0, /* extend mode support defined in input ports and pdp1_init_machine */ + 0, /* hardware multiply/divide support defined in input ports and pdp1_init_machine */ + 0 /* type 20 sequence break system support defined in input ports and pdp1_init_machine */ +}; + +void pdp1_state::machine_reset() +{ + int cfg = m_cfg->read(); + + pdp1_reset_param.extend_support = (cfg >> pdp1_config_extend_bit) & pdp1_config_extend_mask; + pdp1_reset_param.hw_mul_div = (cfg >> pdp1_config_hw_mul_div_bit) & pdp1_config_hw_mul_div_mask; + pdp1_reset_param.type_20_sbs = (cfg >> pdp1_config_type_20_sbs_bit) & pdp1_config_type_20_sbs_mask; + + /* reset device state */ + m_tape_reader->m_rcl = m_tape_reader->m_rc = 0; + m_io_status = io_st_tyo | io_st_ptp; + m_lightpen.active = m_lightpen.down = 0; + m_lightpen.x = m_lightpen.y = 0; + m_lightpen.radius = 10; /* ??? */ + pdp1_update_lightpen_state(&m_lightpen); +} + + +void pdp1_state::pdp1_machine_stop() +{ + /* the core will take care of freeing the timers, BUT we must set the variables + to NULL if we don't want to risk confusing the tape image init function */ + m_tape_reader->m_timer = m_tape_puncher->m_timer = m_typewriter->m_tyo_timer = m_dpy_timer = nullptr; +} + + +/* + driver init function + + Set up the pdp1_memory pointer, and generate font data. +*/ +void pdp1_state::machine_start() +{ + uint8_t *dst; + + static const unsigned char fontdata6x8[pdp1_fontdata_size] = + { /* ASCII characters */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x20,0x20,0x20,0x20,0x00,0x20,0x00, + 0x50,0x50,0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x50,0xf8,0x50,0xf8,0x50,0x00,0x00, + 0x20,0x70,0xc0,0x70,0x18,0xf0,0x20,0x00,0x40,0xa4,0x48,0x10,0x20,0x48,0x94,0x08, + 0x60,0x90,0xa0,0x40,0xa8,0x90,0x68,0x00,0x10,0x20,0x40,0x00,0x00,0x00,0x00,0x00, + 0x20,0x40,0x40,0x40,0x40,0x40,0x20,0x00,0x10,0x08,0x08,0x08,0x08,0x08,0x10,0x00, + 0x20,0xa8,0x70,0xf8,0x70,0xa8,0x20,0x00,0x00,0x20,0x20,0xf8,0x20,0x20,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x30,0x30,0x60,0x00,0x00,0x00,0xf8,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x30,0x30,0x00,0x00,0x08,0x10,0x20,0x40,0x80,0x00,0x00, + 0x70,0x88,0x88,0x88,0x88,0x88,0x70,0x00,0x10,0x30,0x10,0x10,0x10,0x10,0x10,0x00, + 0x70,0x88,0x08,0x10,0x20,0x40,0xf8,0x00,0x70,0x88,0x08,0x30,0x08,0x88,0x70,0x00, + 0x10,0x30,0x50,0x90,0xf8,0x10,0x10,0x00,0xf8,0x80,0xf0,0x08,0x08,0x88,0x70,0x00, + 0x70,0x80,0xf0,0x88,0x88,0x88,0x70,0x00,0xf8,0x08,0x08,0x10,0x20,0x20,0x20,0x00, + 0x70,0x88,0x88,0x70,0x88,0x88,0x70,0x00,0x70,0x88,0x88,0x88,0x78,0x08,0x70,0x00, + 0x00,0x00,0x30,0x30,0x00,0x30,0x30,0x00,0x00,0x00,0x30,0x30,0x00,0x30,0x30,0x60, + 0x10,0x20,0x40,0x80,0x40,0x20,0x10,0x00,0x00,0x00,0xf8,0x00,0xf8,0x00,0x00,0x00, + 0x40,0x20,0x10,0x08,0x10,0x20,0x40,0x00,0x70,0x88,0x08,0x10,0x20,0x00,0x20,0x00, + 0x70,0x88,0xb8,0xa8,0xb8,0x80,0x70,0x00,0x70,0x88,0x88,0xf8,0x88,0x88,0x88,0x00, + 0xf0,0x88,0x88,0xf0,0x88,0x88,0xf0,0x00,0x70,0x88,0x80,0x80,0x80,0x88,0x70,0x00, + 0xf0,0x88,0x88,0x88,0x88,0x88,0xf0,0x00,0xf8,0x80,0x80,0xf0,0x80,0x80,0xf8,0x00, + 0xf8,0x80,0x80,0xf0,0x80,0x80,0x80,0x00,0x70,0x88,0x80,0x98,0x88,0x88,0x70,0x00, + 0x88,0x88,0x88,0xf8,0x88,0x88,0x88,0x00,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x00, + 0x08,0x08,0x08,0x08,0x88,0x88,0x70,0x00,0x88,0x90,0xa0,0xc0,0xa0,0x90,0x88,0x00, + 0x80,0x80,0x80,0x80,0x80,0x80,0xf8,0x00,0x88,0xd8,0xa8,0x88,0x88,0x88,0x88,0x00, + 0x88,0xc8,0xa8,0x98,0x88,0x88,0x88,0x00,0x70,0x88,0x88,0x88,0x88,0x88,0x70,0x00, + 0xf0,0x88,0x88,0xf0,0x80,0x80,0x80,0x00,0x70,0x88,0x88,0x88,0x88,0x88,0x70,0x08, + 0xf0,0x88,0x88,0xf0,0x88,0x88,0x88,0x00,0x70,0x88,0x80,0x70,0x08,0x88,0x70,0x00, + 0xf8,0x20,0x20,0x20,0x20,0x20,0x20,0x00,0x88,0x88,0x88,0x88,0x88,0x88,0x70,0x00, + 0x88,0x88,0x88,0x88,0x88,0x50,0x20,0x00,0x88,0x88,0x88,0x88,0xa8,0xd8,0x88,0x00, + 0x88,0x50,0x20,0x20,0x20,0x50,0x88,0x00,0x88,0x88,0x88,0x50,0x20,0x20,0x20,0x00, + 0xf8,0x08,0x10,0x20,0x40,0x80,0xf8,0x00,0x30,0x20,0x20,0x20,0x20,0x20,0x30,0x00, + 0x40,0x40,0x20,0x20,0x10,0x10,0x08,0x08,0x30,0x10,0x10,0x10,0x10,0x10,0x30,0x00, + 0x20,0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfc, + 0x40,0x20,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x70,0x08,0x78,0x88,0x78,0x00, + 0x80,0x80,0xf0,0x88,0x88,0x88,0xf0,0x00,0x00,0x00,0x70,0x88,0x80,0x80,0x78,0x00, + 0x08,0x08,0x78,0x88,0x88,0x88,0x78,0x00,0x00,0x00,0x70,0x88,0xf8,0x80,0x78,0x00, + 0x18,0x20,0x70,0x20,0x20,0x20,0x20,0x00,0x00,0x00,0x78,0x88,0x88,0x78,0x08,0x70, + 0x80,0x80,0xf0,0x88,0x88,0x88,0x88,0x00,0x20,0x00,0x20,0x20,0x20,0x20,0x20,0x00, + 0x20,0x00,0x20,0x20,0x20,0x20,0x20,0xc0,0x80,0x80,0x90,0xa0,0xe0,0x90,0x88,0x00, + 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x00,0x00,0x00,0xf0,0xa8,0xa8,0xa8,0xa8,0x00, + 0x00,0x00,0xb0,0xc8,0x88,0x88,0x88,0x00,0x00,0x00,0x70,0x88,0x88,0x88,0x70,0x00, + 0x00,0x00,0xf0,0x88,0x88,0xf0,0x80,0x80,0x00,0x00,0x78,0x88,0x88,0x78,0x08,0x08, + 0x00,0x00,0xb0,0xc8,0x80,0x80,0x80,0x00,0x00,0x00,0x78,0x80,0x70,0x08,0xf0,0x00, + 0x20,0x20,0x70,0x20,0x20,0x20,0x18,0x00,0x00,0x00,0x88,0x88,0x88,0x98,0x68,0x00, + 0x00,0x00,0x88,0x88,0x88,0x50,0x20,0x00,0x00,0x00,0xa8,0xa8,0xa8,0xa8,0x50,0x00, + 0x00,0x00,0x88,0x50,0x20,0x50,0x88,0x00,0x00,0x00,0x88,0x88,0x88,0x78,0x08,0x70, + 0x00,0x00,0xf8,0x10,0x20,0x40,0xf8,0x00,0x08,0x10,0x10,0x20,0x10,0x10,0x08,0x00, + 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x40,0x20,0x20,0x10,0x20,0x20,0x40,0x00, + 0x00,0x68,0xb0,0x00,0x00,0x00,0x00,0x00,0x20,0x50,0x20,0x50,0xa8,0x50,0x00,0x00, + + /* non-spacing middle dot */ + 0x00, + 0x00, + 0x00, + 0x20, + 0x00, + 0x00, + 0x00, + 0x00, + /* non-spacing overstrike */ + 0x00, + 0x00, + 0x00, + 0x00, + 0xfc, + 0x00, + 0x00, + 0x00, + /* implies */ + 0x00, + 0x00, + 0x70, + 0x08, + 0x08, + 0x08, + 0x70, + 0x00, + /* or */ + 0x88, + 0x88, + 0x88, + 0x50, + 0x50, + 0x50, + 0x20, + 0x00, + /* and */ + 0x20, + 0x50, + 0x50, + 0x50, + 0x88, + 0x88, + 0x88, + 0x00, + /* up arrow */ + 0x20, + 0x70, + 0xa8, + 0x20, + 0x20, + 0x20, + 0x20, + 0x00, + /* right arrow */ + 0x00, + 0x20, + 0x10, + 0xf8, + 0x10, + 0x20, + 0x00, + 0x00, + /* multiply */ + 0x00, + 0x88, + 0x50, + 0x20, + 0x50, + 0x88, + 0x00, + 0x00, + }; + + /* set up our font */ + dst = memregion("gfx1")->base(); + memcpy(dst, fontdata6x8, pdp1_fontdata_size); + + machine().add_notifier(MACHINE_NOTIFY_EXIT, machine_notify_delegate(&pdp1_state::pdp1_machine_stop,this)); + + m_dpy_timer = timer_alloc(FUNC(pdp1_state::dpy_callback), this); +} + + +/* + perforated tape handling +*/ + +DEFINE_DEVICE_TYPE(PDP1_READTAPE, pdp1_readtape_image_device, "pdp1_readtape_image", "PDP-1 Tape Reader") + +pdp1_readtape_image_device::pdp1_readtape_image_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : paper_tape_reader_device(mconfig, PDP1_READTAPE, tag, owner, clock) + , m_maincpu(*this, "^maincpu") + , m_st_ptr(*this) + , m_timer(nullptr) +{ +} + +void pdp1_readtape_image_device::device_resolve_objects() +{ + m_st_ptr.resolve_safe(); +} + +void pdp1_readtape_image_device::device_start() +{ + m_timer = timer_alloc(FUNC(pdp1_readtape_image_device::reader_callback), this); + m_timer->adjust(attotime::zero, 0, attotime::from_hz(2500)); + m_timer->enable(0); +} + + +DEFINE_DEVICE_TYPE(PDP1_PUNCHTAPE, pdp1_punchtape_image_device, "pdp1_punchtape_image_device", "PDP-1 Tape Puncher") + +pdp1_punchtape_image_device::pdp1_punchtape_image_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : paper_tape_punch_device(mconfig, PDP1_PUNCHTAPE, tag, owner, clock) + , m_maincpu(*this, "^maincpu") + , m_st_ptp(*this) + , m_timer(nullptr) +{ +} + +void pdp1_punchtape_image_device::device_resolve_objects() +{ + m_st_ptp.resolve_safe(); +} + +void pdp1_punchtape_image_device::device_start() +{ + m_timer = timer_alloc(FUNC(pdp1_punchtape_image_device::puncher_callback), this); +} + + +DEFINE_DEVICE_TYPE(PDP1_TYPEWRITER, pdp1_typewriter_device, "pdp1_typewriter_image", "PDP-1 Typewriter") + +pdp1_typewriter_device::pdp1_typewriter_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : device_t(mconfig, PDP1_TYPEWRITER, tag, owner, clock) + , device_image_interface(mconfig, *this) + , m_maincpu(*this, "^maincpu") + , m_driver_state(*this, DEVICE_SELF_OWNER) + , m_twr(*this, "^TWR.%u", 0) + , m_st_tyo(*this) + , m_st_tyi(*this) + , m_tyo_timer(nullptr) +{ +} + +void pdp1_typewriter_device::device_resolve_objects() +{ + m_st_tyo.resolve_safe(); + m_st_tyi.resolve_safe(); +} + +void pdp1_typewriter_device::device_start() +{ + m_tyo_timer = timer_alloc(FUNC(pdp1_typewriter_device::tyo_callback), this); + + m_color = m_pos = m_case_shift = 0; +} + + +DEFINE_DEVICE_TYPE(PDP1_CYLINDER, pdp1_cylinder_image_device, "pdp1_cylinder_image", "PDP-1 Cylinder") + +pdp1_cylinder_image_device::pdp1_cylinder_image_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : device_t(mconfig, PDP1_CYLINDER, tag, owner, clock) + , device_image_interface(mconfig, *this) + , m_maincpu(*this, "^maincpu") +{ +} + +void pdp1_cylinder_image_device::device_start() +{ +} + +/* + Open a perforated tape image +*/ +image_init_result pdp1_readtape_image_device::call_load() +{ + // start motor + m_motor_on = 1; + + /* restart reader IO when necessary */ + /* note that this function may be called before pdp1_init_machine, therefore + before m_timer is allocated. It does not matter, as the clutch is never + down at power-up, but we must not call timer_enable with a nullptr parameter! */ + + if (m_timer) + { + if (m_motor_on && m_rcl) + { + m_timer->enable(1); + } + else + { + m_timer->enable(0); + } + } + + return image_init_result::PASS; +} + +void pdp1_readtape_image_device::call_unload() +{ + // stop motor + m_motor_on = 0; + + if (m_timer) + m_timer->enable(0); +} + +/* + Read a byte from perforated tape +*/ +int pdp1_readtape_image_device::tape_read(uint8_t *reply) +{ + if (is_loaded() && (fread(reply, 1) == 1)) + return 0; /* unit OK */ + else + return 1; /* unit not ready */ +} + + +/* + common code for tape read commands (RPA, RPB, and read-in mode) +*/ +void pdp1_readtape_image_device::begin_tape_read(int binary, int nac) +{ + m_rb = 0; + m_rcl = 1; + m_rc = (binary) ? 1 : 3; + m_rby = (binary) ? 1 : 0; + m_rcp = nac; + + if (LOG_IOT_OVERLAP) + { + if (m_timer->enable(0)) + logerror("Error: overlapped perforated tape reads (Read-in mode, RPA/RPB instruction)\n"); + } + /* set up delay if tape is advancing */ + if (m_motor_on && m_rcl) + { + /* delay is approximately 1/400s */ + m_timer->enable(1); + } + else + { + m_timer->enable(0); + } +} + +/* + timer callback to simulate reader IO +*/ +TIMER_CALLBACK_MEMBER(pdp1_readtape_image_device::reader_callback) +{ + if (m_rc) + { + uint8_t data; + int not_ready = tape_read(&data); + if (not_ready) + { + m_motor_on = 0; // let us stop the motor + } + else + { + if ((!m_rby) || (data & 0200)) + { + m_rb |= (m_rby) ? (data & 077) : data; + + if (m_rc != 3) + { + m_rb <<= 6; + } + + m_rc = (m_rc+1) & 3; + + if (m_rc == 0) + { // IO complete + m_rcl = 0; + if (m_rcp) + { + m_maincpu->set_state_int(PDP1_IO, m_rb); // transfer reader buffer to IO + m_maincpu->set_state_int(PDP1_IOS,1); + } + else + m_st_ptr(1); + } + } + } + } + + if (m_motor_on && m_rcl) + { + m_timer->enable(1); + } + else + { + m_timer->enable(0); + } +} + +/* + perforated tape reader iot callbacks +*/ + +/* + rpa iot callback + + op2: iot command operation (equivalent to mb & 077) + nac: nead a completion pulse + mb: contents of the MB register + io: pointer on the IO register + ac: contents of the AC register +*/ +/* + * Read Perforated Tape, Alphanumeric + * rpa Address 0001 + * + * This instruction reads one line of tape (all eight Channels) and transfers the resulting 8-bit code to + * the Reader Buffer. If bits 5 and 6 of the rpa function are both zero (720001), the contents of the + * Reader Buffer must be transferred to the IO Register by executing the rrb instruction. When the Reader + * Buffer has information ready to be transferred to the IO Register, Status Register Bit 1 is set to + * one. If bits 5 and 6 are different (730001 or 724001) the 8-bit code read from tape is automatically + * transferred to the IO Register via the Reader Buffer and appears as follows: + * + * IO Bits 10 11 12 13 14 15 16 17 + * TAPE CHANNELS 8 7 6 5 4 3 2 1 + */ +void pdp1_readtape_image_device::iot_rpa(int op2, int nac, int mb, int &io, int ac) +{ + if (LOG_IOT_EXTRA) + logerror("Warning, RPA instruction not fully emulated: mb=0%06o, (%s)\n", (unsigned) mb, machine().describe_context()); + + begin_tape_read(0, nac); +} + +/* + rpb iot callback +*/ +/* + * Read Perforated Tape, Binary rpb + * Address 0002 + * + * The instruction reads three lines of tape (six Channels per line) and assembles + * the resulting 18-bit word in the Reader Buffer. For a line to be recognized by + * this instruction Channel 8 must be punched (lines with Channel 8 not punched will + * be skipped over). Channel 7 is ignored. The instruction sub 5137, for example, + * appears on tape and is assembled by rpb as follows: + * + * Channel 8 7 6 5 4 | 3 2 1 + * Line 1 X X | X + * Line 2 X X X | X + * Line 3 X X X | X X X + * Reader Buffer 100 010 101 001 011 111 + * + * (Vertical dashed line indicates sprocket holes and the symbols "X" indicate holes + * punched in tape). + * + * If bits 5 and 6 of the rpb instruction are both zero (720002), the contents of + * the Reader Buffer must be transferred to the IO Register by executing + * a rrb instruction. When the Reader Buffer has information ready to be transferred + * to the IO Register, Status Register Bit 1 is set to one. If bits 5 and 6 are + * different (730002 or 724002) the 18-bit word read from tape is automatically + * transferred to the IO Register via the Reader Buffer. + * + * The rpb command pulse is also asserted for each word transfer in read-in mode. + */ +void pdp1_readtape_image_device::iot_rpb(int op2, int nac, int mb, int &io, int ac) +{ + if (LOG_IOT_EXTRA) + logerror("Warning, RPB instruction not fully emulated: mb=0%06o, (%s)\n", (unsigned) mb, machine().describe_context()); + + begin_tape_read(1, nac); +} + +/* + rrb iot callback +*/ +void pdp1_readtape_image_device::iot_rrb(int op2, int nac, int mb, int &io, int ac) +{ + if (LOG_IOT_EXTRA) + logerror("RRB instruction: mb=0%06o, (%s)\n", (unsigned) mb, machine().describe_context()); + + io = m_rb; + m_st_ptr(0); +} + + +image_init_result pdp1_punchtape_image_device::call_load() +{ + return image_init_result::PASS; +} + +void pdp1_punchtape_image_device::call_unload() +{ +} + +/* + Write a byte to perforated tape +*/ +void pdp1_punchtape_image_device::tape_write(uint8_t data) +{ + if (is_loaded()) + fwrite(&data, 1); +} + +/* + timer callback to generate punch completion pulse +*/ +TIMER_CALLBACK_MEMBER(pdp1_punchtape_image_device::puncher_callback) +{ + int nac = param; + m_st_ptp(1); + if (nac) + { + m_maincpu->set_state_int(PDP1_IOS,1); + } +} + +/* + perforated tape punch iot callbacks +*/ + +/* + ppa iot callback +*/ +/* + * Punch Perforated Tape, Alphanumeric + * ppa Address 0005 + * + * For each In-Out Transfer instruction one line of tape is punched. In-Out Register + * Bit 17 conditions Hole 1. Bit 16 conditions Hole 2, etc. Bit 10 conditions Hole 8 + */ +void pdp1_punchtape_image_device::iot_ppa(int op2, int nac, int mb, int &io, int ac) +{ + if (LOG_IOT_EXTRA) + logerror("PPA instruction: mb=0%06o, (%s)\n", (unsigned) mb, machine().describe_context()); + + tape_write(io & 0377); + m_st_ptp(0); + // delay is approximately 1/63.3 second + if (LOG_IOT_OVERLAP) + { + if (m_timer->enable(0)) + logerror("Error: overlapped PPA/PPB instructions: mb=0%06o, (%s)\n", (unsigned) mb, machine().describe_context()); + } + + m_timer->adjust(attotime::from_usec(15800), nac); +} + +/* + ppb iot callback +*/ +/* + * Punch Perforated Tape, Binary + * ppb Addres 0006 + * + * For each In-Out Transfer instruction one line of tape is punched. In-Out Register + * Bit 5 conditions Hole 1. Bit 4 conditions Hole 2, etc. Bit 0 conditions Hole 6. + * Hole 7 is left blank. Hole 8 is always punched in this mode. + */ +void pdp1_punchtape_image_device::iot_ppb(int op2, int nac, int mb, int &io, int ac) +{ + if (LOG_IOT_EXTRA) + logerror("PPB instruction: mb=0%06o, (%s)\n", (unsigned) mb, machine().describe_context()); + + tape_write((io >> 12) | 0200); + m_st_ptp(0); + /* delay is approximately 1/63.3 second */ + if (LOG_IOT_OVERLAP) + { + if (m_timer->enable(0)) + logerror("Error: overlapped PPA/PPB instructions: mb=0%06o, (%s)\n", (unsigned) mb, machine().describe_context()); + } + m_timer->adjust(attotime::from_usec(15800), nac); +} + + +/* + Typewriter handling + + The alphanumeric on-line typewriter is a standard device on pdp-1: it + can both handle keyboard input and print output text. +*/ + +/* + Open a file for typewriter output +*/ +image_init_result pdp1_typewriter_device::call_load() +{ + m_st_tyo(1); + + return image_init_result::PASS; +} + +void pdp1_typewriter_device::call_unload() +{ +} + +/* + Write a character to typewriter +*/ +void pdp1_typewriter_device::typewriter_out(uint8_t data) +{ + if (LOG_IOT_EXTRA) + logerror("typewriter output %o\n", data); + + drawchar(data); + if (is_loaded()) +#if 1 + fwrite(& data, 1); +#else + { + static const char ascii_table[2][64] = + { /* n-s = non-spacing */ + { /* lower case */ + ' ', '1', '2', '3', + '4', '5', '6', '7', + '8', '9', '*', '*', + '*', '*', '*', '*', + '0', '/', 's', 't', + 'u', 'v', 'w', 'x', + 'y', 'z', '*', ',', + '*',/*black*/ '*',/*red*/ '*',/*Tab*/ '*', + '\200',/*n-s middle dot*/'j', 'k', 'l', + 'm', 'n', 'o', 'p', + 'q', 'r', '*', '*', + '-', ')', '\201',/*n-s overstrike*/'(', + '*', 'a', 'b', 'c', + 'd', 'e', 'f', 'g', + 'h', 'i', '*',/*Lower Case*/ '.', + '*',/*Upper Case*/ '*',/*Backspace*/ '*', '*'/*Carriage Return*/ + }, + { /* upper case */ + ' ', '"', '\'', '~', + '\202',/*implies*/ '\203',/*or*/ '\204',/*and*/ '<', + '>', '\205',/*up arrow*/ '*', '*', + '*', '*', '*', '*', + '\206',/*right arrow*/'?', 'S', 'T', + 'U', 'V', 'W', 'X', + 'Y', 'Z', '*', '=', + '*',/*black*/ '*',/*red*/ '\t',/*Tab*/ '*', + '_',/*n-s???*/ 'J', 'K', 'L', + 'M', 'N', 'O', 'P', + 'Q', 'R', '*', '*', + '+', ']', '|',/*n-s???*/ '[', + '*', 'A', 'B', 'C', + 'D', 'E', 'F', 'G', + 'H', 'I', '*',/*Lower Case*/ '\207',/*multiply*/ + '*',/*Upper Case*/ '\b',/*Backspace*/ '*', '*'/*Carriage Return*/ + } + }; + + data &= 0x3f; + + switch (data) + { + case 034: + // Black: ignore + //color = color_typewriter_black; + { + static const char black[5] = { '\033', '[', '3', '0', 'm' }; + fwrite(black, sizeof(black)); + } + break; + + case 035: + // Red: ignore + //color = color_typewriter_red; + { + static const char red[5] = { '\033', '[', '3', '1', 'm' }; + fwrite(red, sizeof(red)); + } + break; + + case 072: + // Lower case + m_case_shift = 0; + break; + + case 074: + // Upper case + m_case_shift = 1; + break; + + case 077: + // Carriage Return + { + static const char line_end[2] = { '\r', '\n' }; + fwrite(line_end, sizeof(line_end)); + } + break; + + default: + // Any printable character... + + if ((data != 040) && (data != 056)) // 040 and 056 are non-spacing characters: don't try to print right now + /* print character (lookup ASCII equivalent in table) */ + fwrite(&ascii_table[m_case_shift][data], 1); + + break; + } + } +#endif +} + +/* + timer callback to generate typewriter completion pulse +*/ +TIMER_CALLBACK_MEMBER(pdp1_typewriter_device::tyo_callback) +{ + int nac = param; + m_st_tyo(1); + if (nac) + { + m_maincpu->set_state_int(PDP1_IOS,1); + } +} + +/* + tyo iot callback +*/ +void pdp1_typewriter_device::iot_tyo(int op2, int nac, int mb, int &io, int ac) +{ + if (LOG_IOT_EXTRA) + logerror("Warning, TYO instruction not fully emulated: mb=0%06o, (%s)\n", (unsigned) mb, machine().describe_context()); + + int ch = io & 077; + + typewriter_out(ch); + m_st_tyo(0); + + /* compute completion delay (source: maintenance manual 9-12, 9-13 and 9-14) */ + int delay; + switch (ch) + { + case 072: /* lower-case */ + case 074: /* upper-case */ + case 034: /* black */ + case 035: /* red */ + delay = 175; /* approximately 175ms (?) */ + break; + + case 077: /* carriage return */ + delay = 205; /* approximately 205ms (?) */ + break; + + default: + delay = 105; /* approximately 105ms */ + break; + } + if (LOG_IOT_OVERLAP) + { + if (m_tyo_timer->enable(0)) + logerror("Error: overlapped TYO instruction: mb=0%06o, (%s)\n", (unsigned) mb, machine().describe_context()); + } + + m_tyo_timer->adjust(attotime::from_msec(delay), nac); +} + +/* + tyi iot callback +*/ +/* When a typewriter key is struck, the code for the struck key is placed in the + * typewriter buffer, Program Flag 1 is set, and the type-in status bit is set to + * one. A program designed to accept typed-in data would periodically check + * Program Flag 1, and if found to be set, an In-Out Transfer Instruction with + * address 4 could be executed for the information to be transferred to the + * In-Out Register. This In-Out Transfer should not use the optional in-out wait. + * The information contained in the typewriter buffer is then transferred to the + * right six bits of the In-Out Register. The tyi instruction automatically + * clears the In-Out Register before transferring the information and also clears + * the type-in status bit. + */ +void pdp1_typewriter_device::iot_tyi(int op2, int nac, int mb, int &io, int ac) +{ + if (LOG_IOT_EXTRA) + logerror("Warning, TYI instruction not fully emulated: mb=0%06o, (%s)\n", (unsigned) mb, machine().describe_context()); + + io = m_tb; + if (! (m_driver_state->m_io_status & io_st_tyi)) + io |= 0100; + else + m_st_tyi(0); +} + + +/* + * PRECISION CRT DISPLAY (TYPE 30) + * + * This sixteen-inch cathode ray tube display is intended to be used as an on-line output device for the + * PDP-1. It is useful for high speed presentation of graphs, diagrams, drawings, and alphanumerical + * information. The unit is solid state, self-powered and completely buffered. It has magnetic focus and + * deflection. + * + * Display characteristics are as follows: + * + * Random point plotting + * Accuracy of points +/-3 per cent of raster size + * Raster size 9.25 by 9.25 inches + * 1024 by 1024 addressable locations + * Fixed origin at center of CRT + * Ones complement binary arithmetic + * Plots 20,000 points per second + * + * Resolution is such that 512 points along each axis are discernable on the face of the tube. + * + * One instruction is added to the PDP-1 with the installation of this display: + * + * Display One Point On CRT + * dpy Address 0007 + * + * This instruction clears the light pen status bit and displays one point using bits 0 through 9 of the + * AC to represent the (signed) X coordinate of the point and bits 0 through 9 of the IO as the (signed) + * Y coordinate. + * + * Many variations of the Type 30 Display are available. Some of these include hardware for line and + * curve generation. + */ + + +/* + timer callback to generate crt completion pulse +*/ +TIMER_CALLBACK_MEMBER(pdp1_state::dpy_callback) +{ + m_maincpu->set_state_int(PDP1_IOS,1); +} + + +/* + dpy iot callback + + Light on one pixel on CRT +*/ +void pdp1_state::iot_dpy(int op2, int nac, int mb, int &io, int ac) +{ + int x = ((ac+0400000) & 0777777) >> 8; + int y = ((io+0400000) & 0777777) >> 8; + pdp1_plot(x, y); + + /* light pen 32 support */ + m_io_status &= ~io_st_pen; + + if (m_lightpen.down && ((x-m_lightpen.x)*(x-m_lightpen.x)+(y-m_lightpen.y)*(y-m_lightpen.y) < m_lightpen.radius*m_lightpen.radius)) + { + m_io_status |= io_st_pen; + + m_maincpu->set_state_int(PDP1_PF3, 1); + } + + if (nac) + { + /* 50us delay */ + if (LOG_IOT_OVERLAP) + { + /* note that overlap detection is incomplete: it will only work if both DPY + instructions require a completion pulse */ + if (m_dpy_timer->enable(0)) + logerror("Error: overlapped DPY instruction: mb=0%06o, (%s)\n", (unsigned) mb, machine().describe_context()); + } + m_dpy_timer->adjust(attotime::from_usec(50)); + } +} + + + +/* + MIT parallel drum (variant of type 23) +*/ + +void pdp1_cylinder_image_device::set_il(int il) +{ + m_il = il; + + attotime il_phase = ((PARALLEL_DRUM_WORD_TIME * il) - m_rotation_timer->elapsed()); + if (il_phase < attotime::zero) + il_phase = il_phase + PARALLEL_DRUM_ROTATION_TIME; + m_il_timer->adjust(il_phase, 0, PARALLEL_DRUM_ROTATION_TIME); +} + +TIMER_CALLBACK_MEMBER(pdp1_cylinder_image_device::rotation_timer_callback) +{ +} + +TIMER_CALLBACK_MEMBER(pdp1_cylinder_image_device::il_timer_callback) +{ + if (m_dba) + { + /* set break request and status bit 5 */ + /* ... */ + } +} + +void pdp1_cylinder_image_device::parallel_drum_init() +{ + m_rotation_timer = timer_alloc(FUNC(pdp1_cylinder_image_device::rotation_timer_callback), this); + m_rotation_timer->adjust(PARALLEL_DRUM_ROTATION_TIME, 0, PARALLEL_DRUM_ROTATION_TIME); + + m_il_timer = timer_alloc(FUNC(pdp1_cylinder_image_device::il_timer_callback), this); + set_il(0); +} + +/* + Open a file for drum +*/ +image_init_result pdp1_cylinder_image_device::call_load() +{ + return image_init_result::PASS; +} + +void pdp1_cylinder_image_device::call_unload() +{ +} + +void pdp1_cylinder_image_device::iot_dia(int op2, int nac, int mb, int &io, int ac) +{ + m_wfb = (io & 0370000) >> 12; + set_il(io & 0007777); + + m_dba = 0; /* right? */ +} + +void pdp1_cylinder_image_device::iot_dba(int op2, int nac, int mb, int &io, int ac) +{ + m_wfb = (io & 0370000) >> 12; + set_il(io & 0007777); + + m_dba = 1; +} + +/* + Read a word from drum +*/ +uint32_t pdp1_cylinder_image_device::drum_read(int field, int position) +{ + int offset = (field*4096+position)*3; + uint8_t buf[3]; + + if (is_loaded() && (!fseek(offset, SEEK_SET)) && (fread(buf, 3) == 3)) + return ((buf[0] << 16) | (buf[1] << 8) | buf[2]) & 0777777; + + return 0; +} + +/* + Write a word to drum +*/ +void pdp1_cylinder_image_device::drum_write(int field, int position, uint32_t data) +{ + int offset = (field*4096+position)*3; + uint8_t buf[3]; + + if (is_loaded()) + { + buf[0] = data >> 16; + buf[1] = data >> 8; + buf[2] = data; + + fseek(offset, SEEK_SET); + fwrite(buf, 3); + } +} + +void pdp1_cylinder_image_device::iot_dcc(int op2, int nac, int mb, int &io, int ac) +{ + m_rfb = (io & 0370000) >> 12; + m_wc = - (io & 0007777); + + m_wcl = ac & 0177777/*0007777???*/; + + m_dba = 0; /* right? */ + /* clear status bit 5... */ + + /* do transfer */ + attotime delay = m_il_timer->remaining(); + int dc = m_il; + do + { + if ((m_wfb >= 1) && (m_wfb <= 22)) + { + drum_write(m_wfb-1, dc, (signed)m_maincpu->space(AS_PROGRAM).read_dword(m_wcl)); + } + + if ((m_rfb >= 1) && (m_rfb <= 22)) + { + m_maincpu->space(AS_PROGRAM).write_dword(m_wcl, drum_read(m_rfb-1, dc)); + } + + m_wc = (m_wc+1) & 07777; + m_wcl = (m_wcl+1) & 0177777/*0007777???*/; + dc = (dc+1) & 07777; + if (m_wc) + delay = delay + PARALLEL_DRUM_WORD_TIME; + } while (m_wc); + m_maincpu->adjust_icount(-m_maincpu->attotime_to_cycles(delay)); + /* if no error, skip */ + m_maincpu->set_state_int(PDP1_PC, m_maincpu->state_int(PDP1_PC)+1); +} + +void pdp1_cylinder_image_device::iot_dra(int op2, int nac, int mb, int &io, int ac) +{ + io = (m_rotation_timer->elapsed() * + (ATTOSECONDS_PER_SECOND / (PARALLEL_DRUM_WORD_TIME.as_attoseconds()))).seconds() & 0007777; + + /* set parity error and timing error... */ +} + + + +/* + iot 11 callback + + Read state of Spacewar! controllers + + Not documented, except a few comments in the Spacewar! source code: + it should leave the control word in the io as follows. + high order 4 bits, rotate ccw, rotate cw, (both mean hyperspace) + fire rocket, and fire torpedo. low order 4 bits, same for + other ship. routine is entered by jsp cwg. +*/ +void pdp1_state::iot_011(int op2, int nac, int mb, int &io, int ac) +{ + int key_state = m_spacewar->read(); + int reply; + + + reply = 0; + + if (key_state & ROTATE_RIGHT_PLAYER2) + reply |= 0400000; + if (key_state & ROTATE_LEFT_PLAYER2) + reply |= 0200000; + if (key_state & THRUST_PLAYER2) + reply |= 0100000; + if (key_state & FIRE_PLAYER2) + reply |= 0040000; + if (key_state & HSPACE_PLAYER2) + reply |= 0600000; + + if (key_state & ROTATE_RIGHT_PLAYER1) + reply |= 010; + if (key_state & ROTATE_LEFT_PLAYER1) + reply |= 004; + if (key_state & THRUST_PLAYER1) + reply |= 002; + if (key_state & FIRE_PLAYER1) + reply |= 001; + if (key_state & HSPACE_PLAYER1) + reply |= 014; + + io = reply; +} + + +/* + cks iot callback + + check IO status +*/ +void pdp1_state::iot_cks(int op2, int nac, int mb, int &io, int ac) +{ + if (LOG_IOT_EXTRA) + logerror("CKS instruction: mb=0%06o, (%s)\n", (unsigned) mb, machine().describe_context()); + + io = m_io_status; +} + +template +WRITE_LINE_MEMBER(pdp1_state::io_status_w) +{ + if (state) + m_io_status |= Mask; + else + m_io_status &= ~Mask; + + if (USE_SBS && Mask == io_st_tyi) + m_maincpu->set_input_line(0, state ? ASSERT_LINE : CLEAR_LINE); /* PDP1 - interrupt it, baby */ +} + + +/* + callback which is called when Start Clear is pulsed + + IO devices should reset +*/ +void pdp1_state::io_start_clear() +{ + m_tape_reader->m_rcl = m_tape_reader->m_rc = 0; + if (m_tape_reader->m_timer) + m_tape_reader->m_timer->enable(0); + + if (m_tape_puncher->m_timer) + m_tape_puncher->m_timer->enable(0); + + if (m_typewriter->m_tyo_timer) + m_typewriter->m_tyo_timer->enable(0); + + if (m_dpy_timer) + m_dpy_timer->enable(0); + + m_io_status = io_st_tyo | io_st_ptp; +} + + +/* + typewriter keyboard handler +*/ +void pdp1_typewriter_device::pdp1_keyboard() +{ + int i; + int j; + + int typewriter_keys[4]; + + int typewriter_transitions; + + + for (i=0; i<4; i++) + { + typewriter_keys[i] = m_twr[i]->read(); + } + + for (i=0; i<4; i++) + { + typewriter_transitions = typewriter_keys[i] & (~ m_old_typewriter_keys[i]); + if (typewriter_transitions) + { + for (j=0; (((typewriter_transitions >> j) & 1) == 0) /*&& (j<16)*/; j++) + ; + m_tb = (i << 4) + j; + m_st_tyi(1); + m_maincpu->set_state_int(PDP1_PF1, 1); + drawchar(m_tb); /* we want to echo input */ + break; + } + } + + for (i=0; i<4; i++) + m_old_typewriter_keys[i] = typewriter_keys[i]; +} + +void pdp1_state::pdp1_lightpen() +{ + int x_delta, y_delta; + int current_state = m_io_lightpen->read(); + + m_lightpen.active = (m_cfg->read() >> pdp1_config_lightpen_bit) & pdp1_config_lightpen_mask; + + /* update pen down state */ + m_lightpen.down = m_lightpen.active && (current_state & pdp1_lightpen_down); + + /* update size of pen tip hole */ + if ((current_state & ~m_old_lightpen) & pdp1_lightpen_smaller) + { + m_lightpen.radius --; + if (m_lightpen.radius < 0) + m_lightpen.radius = 0; + } + if ((current_state & ~m_old_lightpen) & pdp1_lightpen_larger) + { + m_lightpen.radius ++; + if (m_lightpen.radius > 32) + m_lightpen.radius = 32; + } + + m_old_lightpen = current_state; + + /* update pen position */ + x_delta = m_lightx->read(); + y_delta = m_lighty->read(); + + if (x_delta >= 0x80) + x_delta -= 0x100; + if (y_delta >= 0x80) + y_delta -= 256; + + m_lightpen.x += x_delta; + m_lightpen.y += y_delta; + + if (m_lightpen.x < 0) + m_lightpen.x = 0; + if (m_lightpen.x > 1023) + m_lightpen.x = 1023; + if (m_lightpen.y < 0) + m_lightpen.y = 0; + if (m_lightpen.y > 1023) + m_lightpen.y = 1023; + + pdp1_update_lightpen_state(&m_lightpen); +} + +/* + Not a real interrupt - just handle keyboard input +*/ +INTERRUPT_GEN_MEMBER(pdp1_state::pdp1_interrupt) +{ + int control_keys; + int tw_keys; + int ta_keys; + + int control_transitions; + int tw_transitions; + int ta_transitions; + + + m_maincpu->set_state_int(PDP1_SS, m_sense->read()); + + /* read new state of control keys */ + control_keys = m_csw->read(); + + if (control_keys & pdp1_control) + { + /* compute transitions */ + control_transitions = control_keys & (~ m_old_control_keys); + + if (control_transitions & pdp1_extend) + { + m_maincpu->set_state_int(PDP1_EXTEND_SW, ! m_maincpu->state_int(PDP1_EXTEND_SW)); + } + if (control_transitions & pdp1_start_nobrk) + { + m_maincpu->pulse_start_clear(); /* pulse Start Clear line */ + m_maincpu->set_state_int(PDP1_EXD, m_maincpu->state_int(PDP1_EXTEND_SW)); + m_maincpu->set_state_int(PDP1_SBM, (uint64_t)0); + m_maincpu->set_state_int(PDP1_OV, (uint64_t)0); + m_maincpu->set_state_int(PDP1_PC, m_maincpu->state_int(PDP1_TA)); + m_maincpu->set_state_int(PDP1_RUN, 1); + } + if (control_transitions & pdp1_start_brk) + { + m_maincpu->pulse_start_clear(); /* pulse Start Clear line */ + m_maincpu->set_state_int(PDP1_EXD, m_maincpu->state_int(PDP1_EXTEND_SW)); + m_maincpu->set_state_int(PDP1_SBM, 1); + m_maincpu->set_state_int(PDP1_OV, (uint64_t)0); + m_maincpu->set_state_int(PDP1_PC, m_maincpu->state_int(PDP1_TA)); + m_maincpu->set_state_int(PDP1_RUN, 1); + } + if (control_transitions & pdp1_stop) + { + m_maincpu->set_state_int(PDP1_RUN, (uint64_t)0); + m_maincpu->set_state_int(PDP1_RIM, (uint64_t)0); /* bug : we stop after reading an even-numbered word + (i.e. data), whereas a real pdp-1 stops after reading + an odd-numbered word (i.e. dio instruciton) */ + } + if (control_transitions & pdp1_continue) + { + m_maincpu->set_state_int(PDP1_RUN, 1); + } + if (control_transitions & pdp1_examine) + { + m_maincpu->pulse_start_clear(); /* pulse Start Clear line */ + m_maincpu->set_state_int(PDP1_PC, m_maincpu->state_int(PDP1_TA)); + m_maincpu->set_state_int(PDP1_MA, m_maincpu->state_int(PDP1_PC)); + m_maincpu->set_state_int(PDP1_IR, pdp1_device::LAC); /* this instruction is actually executed */ + + m_maincpu->set_state_int(PDP1_MB, (signed)m_maincpu->space(AS_PROGRAM).read_dword(PDP1_MA)); + m_maincpu->set_state_int(PDP1_AC, m_maincpu->state_int(PDP1_MB)); + } + if (control_transitions & pdp1_deposit) + { + m_maincpu->pulse_start_clear(); /* pulse Start Clear line */ + m_maincpu->set_state_int(PDP1_PC, m_maincpu->state_int(PDP1_TA)); + m_maincpu->set_state_int(PDP1_MA, m_maincpu->state_int(PDP1_PC)); + m_maincpu->set_state_int(PDP1_AC, m_maincpu->state_int(PDP1_TW)); + m_maincpu->set_state_int(PDP1_IR, pdp1_device::DAC); /* this instruction is actually executed */ + + m_maincpu->set_state_int(PDP1_MB, m_maincpu->state_int(PDP1_AC)); + m_maincpu->space(AS_PROGRAM).write_dword(m_maincpu->state_int(PDP1_MA), m_maincpu->state_int(PDP1_MB)); + } + if (control_transitions & pdp1_read_in) + { /* set cpu to read instructions from perforated tape */ + m_maincpu->pulse_start_clear(); /* pulse Start Clear line */ + m_maincpu->set_state_int(PDP1_PC, ( m_maincpu->state_int(PDP1_TA) & 0170000) + | (m_maincpu->state_int(PDP1_PC) & 0007777)); /* transfer ETA to EPC */ + /*m_maincpu->set_state_int(PDP1_MA, m_maincpu->state_int(PDP1_PC));*/ + m_maincpu->set_state_int(PDP1_EXD, m_maincpu->state_int(PDP1_EXTEND_SW)); + m_maincpu->set_state_int(PDP1_OV, (uint64_t)0); /* right??? */ + m_maincpu->set_state_int(PDP1_RUN, (uint64_t)0); + m_maincpu->set_state_int(PDP1_RIM, 1); + } + if (control_transitions & pdp1_reader) + { + } + if (control_transitions & pdp1_tape_feed) + { + } + if (control_transitions & pdp1_single_step) + { + m_maincpu->set_state_int(PDP1_SNGL_STEP, ! m_maincpu->state_int(PDP1_SNGL_STEP)); + } + if (control_transitions & pdp1_single_inst) + { + m_maincpu->set_state_int(PDP1_SNGL_INST, ! m_maincpu->state_int(PDP1_SNGL_INST)); + } + + /* remember new state of control keys */ + m_old_control_keys = control_keys; + + + /* handle test word keys */ + tw_keys = (m_twdmsb->read() << 16) | m_twdlsb->read(); + + /* compute transitions */ + tw_transitions = tw_keys & (~ m_old_tw_keys); + + if (tw_transitions) + m_maincpu->set_state_int(PDP1_TW, m_maincpu->state_int(PDP1_TW) ^ tw_transitions); + + /* remember new state of test word keys */ + m_old_tw_keys = tw_keys; + + + /* handle address keys */ + ta_keys = m_tstadd->read(); + + /* compute transitions */ + ta_transitions = ta_keys & (~ m_old_ta_keys); + + if (ta_transitions) + m_maincpu->set_state_int(PDP1_TA, m_maincpu->state_int(PDP1_TA) ^ ta_transitions); + + /* remember new state of test word keys */ + m_old_ta_keys = ta_keys; + + } + else + { + m_old_control_keys = 0; + m_old_tw_keys = 0; + m_old_ta_keys = 0; + + m_typewriter->pdp1_keyboard(); + } + + pdp1_lightpen(); +} + + +void pdp1_state::pdp1(machine_config &config) +{ + /* basic machine hardware */ + /* PDP1 CPU @ 200 kHz (no master clock, but the instruction and memory rate is 200 kHz) */ + PDP1(config, m_maincpu, 1000000); /* the CPU core uses microsecond counts */ + m_maincpu->set_reset_param(&pdp1_reset_param); + m_maincpu->set_addrmap(AS_PROGRAM, &pdp1_state::pdp1_map); + m_maincpu->set_vblank_int("screen", FUNC(pdp1_state::pdp1_interrupt)); /* dummy interrupt: handles input */ + /* external iot handlers. 00, 50 to 56 and 74 are internal to the cpu core. */ + /* I put a ? when the source is the handbook, since a) I have used the maintenance manual + as the primary source (as it goes more into details) b) the handbook and the maintenance + manual occasionally contradict each other. */ + /* (iot) rpa rpb tyo tyi ppa ppb dpy */ + /* spacewar */ + /* lag glf?/jsp? gpl?/gpr?/gcf? */ + /* rrb rcb? rcc? cks mcs mes mel */ + /* cad? rac? rbc? pac lpr/lfb/lsp swc/sci/sdf?/shr? scv? */ + /* (dsc) (asc) (isb) (cac) (lsm) (esm) (cbs) */ + /* icv? dia dba dcc dra mri|rlc? mrf/inr?/ccr? */ + /* mcb|dur? mwc|mtf? mrc|sfc?... msm|cgo? (eem/lem) mic muf */ + m_maincpu->set_iot_callback<001>(m_tape_reader, FUNC(pdp1_readtape_image_device::iot_rpa)); + m_maincpu->set_iot_callback<002>(m_tape_reader, FUNC(pdp1_readtape_image_device::iot_rpb)); + m_maincpu->set_iot_callback<003>(m_typewriter, FUNC(pdp1_typewriter_device::iot_tyo)); + m_maincpu->set_iot_callback<004>(m_typewriter, FUNC(pdp1_typewriter_device::iot_tyi)); + m_maincpu->set_iot_callback<005>(m_tape_puncher, FUNC(pdp1_punchtape_image_device::iot_ppa)); + m_maincpu->set_iot_callback<006>(m_tape_puncher, FUNC(pdp1_punchtape_image_device::iot_ppb)); + m_maincpu->set_iot_callback<007>(FUNC(pdp1_state::iot_dpy)); + m_maincpu->set_iot_callback<011>(FUNC(pdp1_state::iot_011)); + m_maincpu->set_iot_callback<030>(m_tape_reader, FUNC(pdp1_readtape_image_device::iot_rrb)); + m_maincpu->set_iot_callback<033>(FUNC(pdp1_state::iot_cks)); + /* dia, dba, dcc, dra are documented in MIT PDP-1 COMPUTER MODIFICATION + BULLETIN no. 2 (drumInstrWriteup.bin/drumInstrWriteup.txt), and are + similar to IOT documented in Parallel Drum Type 23 Instruction Manual. */ + m_maincpu->set_iot_callback<061>(m_parallel_drum, FUNC(pdp1_cylinder_image_device::iot_dia)); + m_maincpu->set_iot_callback<062>(m_parallel_drum, FUNC(pdp1_cylinder_image_device::iot_dba)); + m_maincpu->set_iot_callback<063>(m_parallel_drum, FUNC(pdp1_cylinder_image_device::iot_dcc)); + m_maincpu->set_iot_callback<064>(m_parallel_drum, FUNC(pdp1_cylinder_image_device::iot_dra)); + m_maincpu->set_io_sc_callback(FUNC(pdp1_state::io_start_clear)); + + /* video hardware (includes the control panel and typewriter output) */ + screen_device &screen(SCREEN(config, "screen", SCREEN_TYPE_RASTER)); + screen.set_refresh_hz(refresh_rate); + screen.set_vblank_time(ATTOSECONDS_IN_USEC(2500)); /* not accurate */ + screen.set_size(virtual_width, virtual_height); + screen.set_visarea(0, virtual_width-1, 0, virtual_height-1); + screen.set_screen_update(FUNC(pdp1_state::screen_update_pdp1)); + screen.screen_vblank().set(FUNC(pdp1_state::screen_vblank_pdp1)); + screen.set_palette(m_palette); + + CRT(config, m_crt, 0); + m_crt->set_num_levels(pen_crt_num_levels); + m_crt->set_offsets(crt_window_offset_x, crt_window_offset_y); + m_crt->set_size(crt_window_width, crt_window_height); + + PDP1_READTAPE(config, m_tape_reader); + m_tape_reader->st_ptr().set(FUNC(pdp1_state::io_status_w)); + + PDP1_PUNCHTAPE(config, m_tape_puncher); + m_tape_puncher->st_ptp().set(FUNC(pdp1_state::io_status_w)); + + PDP1_TYPEWRITER(config, m_typewriter); + m_typewriter->st_tyo().set(FUNC(pdp1_state::io_status_w)); + m_typewriter->st_tyi().set(FUNC(pdp1_state::io_status_w)); + + PDP1_CYLINDER(config, m_parallel_drum); + + GFXDECODE(config, m_gfxdecode, m_palette, gfx_pdp1); + PALETTE(config, m_palette, FUNC(pdp1_state::pdp1_palette), total_colors_needed + std::size(pdp1_pens), total_colors_needed); + + SOFTWARE_LIST(config, "ptp_list").set_original("pdp1_ptp"); +} + +/* + pdp1 can address up to 65336 18 bit words when extended (4096 otherwise). +*/ +ROM_START(pdp1) + ROM_REGION(pdp1_fontdata_size, "gfx1", ROMREGION_ERASEFF) + /* space filled with our font */ +ROM_END + +/*************************************************************************** + + Game driver(s) + +***************************************************************************/ + +// YEAR NAME PARENT COMPAT MACHINE INPUT CLASS INIT COMPANY FULLNAME FLAGS +COMP( 1961, pdp1, 0, 0, pdp1, pdp1, pdp1_state, empty_init, "Digital Equipment Corporation", "PDP-1", MACHINE_NO_SOUND_HW ) diff --git a/src/mame/dec/pdp1.h b/src/mame/dec/pdp1.h new file mode 100644 index 00000000000..203bee6e168 --- /dev/null +++ b/src/mame/dec/pdp1.h @@ -0,0 +1,484 @@ +// license:GPL-2.0+ +// copyright-holders:Raphael Nabet +/***************************************************************************** + * + * includes/pdp1.h + * + ****************************************************************************/ +#ifndef MAME_PDP1_PDP1_H +#define MAME_PDP1_PDP1_H + +#pragma once + +#include "mitcrt.h" + +#include "cpu/pdp1/pdp1.h" +#include "imagedev/papertape.h" +#include "emupal.h" + +/* defines for each bit and mask in input port "CSW" */ +enum +{ + /* bit numbers */ + pdp1_control_bit = 0, + + pdp1_extend_bit = 1, + pdp1_start_nobrk_bit= 2, + pdp1_start_brk_bit = 3, + pdp1_stop_bit = 4, + pdp1_continue_bit = 5, + pdp1_examine_bit = 6, + pdp1_deposit_bit = 7, + pdp1_read_in_bit = 8, + pdp1_reader_bit = 9, + pdp1_tape_feed_bit = 10, + pdp1_single_step_bit= 11, + pdp1_single_inst_bit= 12, + + /* masks */ + pdp1_control = (1 << pdp1_control_bit), + pdp1_extend = (1 << pdp1_extend_bit), + pdp1_start_nobrk = (1 << pdp1_start_nobrk_bit), + pdp1_start_brk = (1 << pdp1_start_brk_bit), + pdp1_stop = (1 << pdp1_stop_bit), + pdp1_continue = (1 << pdp1_continue_bit), + pdp1_examine = (1 << pdp1_examine_bit), + pdp1_deposit = (1 << pdp1_deposit_bit), + pdp1_read_in = (1 << pdp1_read_in_bit), + pdp1_reader = (1 << pdp1_reader_bit), + pdp1_tape_feed = (1 << pdp1_tape_feed_bit), + pdp1_single_step = (1 << pdp1_single_step_bit), + pdp1_single_inst = (1 << pdp1_single_inst_bit) +}; + +/* defines for each bit in input port pdp1_spacewar_controllers*/ +#define ROTATE_LEFT_PLAYER1 0x01 +#define ROTATE_RIGHT_PLAYER1 0x02 +#define THRUST_PLAYER1 0x04 +#define FIRE_PLAYER1 0x08 +#define ROTATE_LEFT_PLAYER2 0x10 +#define ROTATE_RIGHT_PLAYER2 0x20 +#define THRUST_PLAYER2 0x40 +#define FIRE_PLAYER2 0x80 +#define HSPACE_PLAYER1 0x100 +#define HSPACE_PLAYER2 0x200 + +/* defines for each field in input port pdp1_config */ +enum +{ + pdp1_config_extend_bit = 0, + pdp1_config_extend_mask = 0x3, /* 2 bits */ + pdp1_config_hw_mul_div_bit = 2, + pdp1_config_hw_mul_div_mask = 0x1, + /*pdp1_config_hw_obsolete_bit = 3, + pdp1_config_hw_obsolete_mask = 0x1,*/ + pdp1_config_type_20_sbs_bit = 4, + pdp1_config_type_20_sbs_mask = 0x1, + pdp1_config_lightpen_bit = 5, + pdp1_config_lightpen_mask = 0x1 +}; + +/* defines for each field in input port pdp1_lightpen_state */ +enum +{ + pdp1_lightpen_down_bit = 0, + pdp1_lightpen_smaller_bit = 1, + pdp1_lightpen_larger_bit = 2, + + pdp1_lightpen_down = (1 << pdp1_lightpen_down_bit), + pdp1_lightpen_smaller = (1 << pdp1_lightpen_smaller_bit), + pdp1_lightpen_larger = (1 << pdp1_lightpen_larger_bit) +}; + +/* defines for our font */ +enum +{ + pdp1_charnum = /*104*/128, /* ASCII set + 8 special characters */ + /* for whatever reason, 104 breaks some characters */ + + pdp1_fontdata_size = 8 * pdp1_charnum +}; + +enum +{ + /* size and position of crt window */ + crt_window_width = 512, + crt_window_height = 512, + crt_window_offset_x = 0, + crt_window_offset_y = 0, + /* size and position of operator control panel window */ + panel_window_width = 384, + panel_window_height = 128, + panel_window_offset_x = crt_window_width, + panel_window_offset_y = 0, + /* size and position of typewriter window */ + typewriter_window_width = 640, + typewriter_window_height = 160, + typewriter_window_offset_x = 0, + typewriter_window_offset_y = crt_window_height +}; + +enum +{ + total_width = crt_window_width + panel_window_width, + total_height = crt_window_height + typewriter_window_height, + + /* respect 4:3 aspect ratio to keep pixels square */ + virtual_width_1 = ((total_width+3)/4)*4, + virtual_height_1 = ((total_height+2)/3)*3, + virtual_width_2 = virtual_height_1*4/3, + virtual_height_2 = virtual_width_1*3/4, + virtual_width = (virtual_width_1 > virtual_width_2) ? virtual_width_1 : virtual_width_2, + virtual_height = (virtual_height_1 > virtual_height_2) ? virtual_height_1 : virtual_height_2 +}; + +enum +{ /* refresh rate in Hz: can be changed at will */ + refresh_rate = 60 +}; + +/* Color codes */ +enum +{ + /* first pen_crt_num_levels colors used for CRT (with remanence) */ + pen_crt_num_levels = 69, + pen_crt_max_intensity = pen_crt_num_levels-1, + + /* next colors used for control panel and typewriter */ + pen_black = pen_crt_num_levels, + pen_white, + pen_green, + pen_dk_green, + pen_red, + pen_lt_gray, + + /* color constants for control panel */ + pen_panel_bg = pen_black, + pen_panel_caption = pen_white, + color_panel_caption = 0, + pen_switch_nut = pen_lt_gray, + pen_switch_button = pen_white, + pen_lit_lamp = pen_green, + pen_unlit_lamp = pen_dk_green, + + /* color constants for typewriter */ + pen_typewriter_bg = pen_white, + color_typewriter_black = 1, + color_typewriter_red = 2, + + /* color constants used for light pen */ + pen_lightpen_nonpressed = pen_red, + pen_lightpen_pressed = pen_green +}; + +class pdp1_state; + +// tape reader device +class pdp1_readtape_image_device : public paper_tape_reader_device +{ +public: + // construction/destruction + pdp1_readtape_image_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock = 0U); + virtual const char *image_interface() const noexcept override { return "pdp1_ptp"; } + + auto st_ptr() { return m_st_ptr.bind(); } + + void iot_rpa(int op2, int nac, int mb, int &io, int ac); + void iot_rpb(int op2, int nac, int mb, int &io, int ac); + void iot_rrb(int op2, int nac, int mb, int &io, int ac); + +protected: + // device-level overrides + virtual void device_resolve_objects() override; + virtual void device_start() override; + + // image-level overrides + virtual const char *file_extensions() const noexcept override { return "tap,rim"; } + + virtual image_init_result call_load() override; + virtual void call_unload() override; + +public: + TIMER_CALLBACK_MEMBER(reader_callback); + + int tape_read(uint8_t *reply); + void begin_tape_read(int binary, int nac); + + required_device m_maincpu; + + devcb_write_line m_st_ptr; + + int m_motor_on; // 1-bit reader motor on + + int m_rb; // 18-bit reader buffer + int m_rcl; // 1-bit reader clutch + int m_rc; // 2-bit reader counter + int m_rby; // 1-bit reader binary mode flip-flop + int m_rcp; // 1-bit reader "need a completion pulse" flip-flop + + emu_timer *m_timer; // timer to simulate reader timing +}; + + + +// tape puncher device +class pdp1_punchtape_image_device : public paper_tape_punch_device +{ +public: + // construction/destruction + pdp1_punchtape_image_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock = 0U); + + auto st_ptp() { return m_st_ptp.bind(); } + + void iot_ppa(int op2, int nac, int mb, int &io, int ac); + void iot_ppb(int op2, int nac, int mb, int &io, int ac); + +protected: + // device-level overrides + virtual void device_resolve_objects() override; + virtual void device_start() override; + + // image-level overrides + virtual bool is_readable() const noexcept override { return false; } + virtual bool is_writeable() const noexcept override { return true; } + virtual bool is_creatable() const noexcept override { return true; } + virtual bool is_reset_on_load() const noexcept override { return false; } + virtual const char *file_extensions() const noexcept override { return "tap,rim"; } + + virtual image_init_result call_load() override; + virtual void call_unload() override; + +public: + TIMER_CALLBACK_MEMBER(puncher_callback); + + void tape_write(uint8_t data); + + required_device m_maincpu; + + devcb_write_line m_st_ptp; + + emu_timer *m_timer; // timer to generate completion pulses +}; + + + +// typewriter device +class pdp1_typewriter_device : public device_t, + public device_image_interface +{ +public: + // construction/destruction + pdp1_typewriter_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock = 0U); + + auto st_tyo() { return m_st_tyo.bind(); } + auto st_tyi() { return m_st_tyi.bind(); } + + void iot_tyo(int op2, int nac, int mb, int &io, int ac); + void iot_tyi(int op2, int nac, int mb, int &io, int ac); + +protected: + // device-level overrides + virtual void device_resolve_objects() override; + virtual void device_start() override; + + // image-level overrides + virtual bool is_readable() const noexcept override { return false; } + virtual bool is_writeable() const noexcept override { return true; } + virtual bool is_creatable() const noexcept override { return true; } + virtual bool is_reset_on_load() const noexcept override { return false; } + virtual bool support_command_line_image_creation() const noexcept override { return true; } + virtual const char *file_extensions() const noexcept override { return "typ"; } + virtual const char *image_type_name() const noexcept override { return "printout"; } + virtual const char *image_brief_type_name() const noexcept override { return "prin"; } + + virtual image_init_result call_load() override; + virtual void call_unload() override; + +public: + TIMER_CALLBACK_MEMBER(tyo_callback); + + void linefeed(); + void drawchar(int character); + void typewriter_out(uint8_t data); + + void pdp1_keyboard(); + + required_device m_maincpu; + required_device m_driver_state; + required_ioport_array<4> m_twr; + + devcb_write_line m_st_tyo; + devcb_write_line m_st_tyi; + + int m_tb; // typewriter buffer + + emu_timer *m_tyo_timer; // timer to generate completion pulses + + int m_old_typewriter_keys[4]; + int m_color; + bitmap_ind16 m_bitmap; + int m_pos; + int m_case_shift; +}; + +// MIT parallel drum (mostly similar to type 23) +class pdp1_cylinder_image_device : public device_t, + public device_image_interface +{ +public: + // construction/destruction + pdp1_cylinder_image_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock = 0U); + + void iot_dia(int op2, int nac, int mb, int &io, int ac); + void iot_dba(int op2, int nac, int mb, int &io, int ac); + void iot_dcc(int op2, int nac, int mb, int &io, int ac); + void iot_dra(int op2, int nac, int mb, int &io, int ac); + +protected: + // device-level overrides + virtual void device_start() override; + + // image-level overrides + virtual bool is_readable() const noexcept override { return true; } + virtual bool is_writeable() const noexcept override { return true; } + virtual bool is_creatable() const noexcept override { return true; } + virtual bool is_reset_on_load() const noexcept override { return false; } + virtual const char *file_extensions() const noexcept override { return "drm"; } + virtual const char *image_type_name() const noexcept override { return "cylinder"; } + virtual const char *image_brief_type_name() const noexcept override { return "cyln"; } + + + virtual image_init_result call_load() override; + virtual void call_unload() override; + +public: + void set_il(int il); + TIMER_CALLBACK_MEMBER(rotation_timer_callback); + TIMER_CALLBACK_MEMBER(il_timer_callback); + [[maybe_unused]] void parallel_drum_init(); + uint32_t drum_read(int field, int position); + void drum_write(int field, int position, uint32_t data); + + required_device m_maincpu; + + int m_il = 0; // initial location (12-bit) + int m_wc = 0; // word counter (12-bit) + int m_wcl = 0; // word core location counter (16-bit) + int m_rfb = 0; // read field buffer (5-bit) + int m_wfb = 0; // write field buffer (5-bit) + + int m_dba = 0; + + emu_timer *m_rotation_timer = nullptr;// timer called each time dc is 0 + emu_timer *m_il_timer = nullptr; // timer called each time dc is il +}; + + +struct lightpen_t +{ + char active; + char down; + short x, y; + short radius; +}; + + +class pdp1_state : public driver_device +{ +public: + pdp1_state(const machine_config &mconfig, device_type type, const char *tag) + : driver_device(mconfig, type, tag), + m_maincpu(*this, "maincpu"), + m_tape_reader(*this, "readt"), + m_tape_puncher(*this, "punch"), + m_typewriter(*this, "typewriter"), + m_parallel_drum(*this, "drum"), + m_dpy_timer(nullptr), + m_gfxdecode(*this, "gfxdecode"), + m_palette(*this, "palette"), + m_crt(*this, "crt"), + m_spacewar(*this, "SPACEWAR"), + m_csw(*this, "CSW"), + m_sense(*this, "SENSE"), + m_tstadd(*this, "TSTADD"), + m_twdmsb(*this, "TWDMSB"), + m_twdlsb(*this, "TWDLSB"), + m_cfg(*this, "CFG"), + m_io_lightpen(*this, "LIGHTPEN"), + m_lightx(*this, "LIGHTX"), + m_lighty(*this, "LIGHTY") + { } + + required_device m_maincpu; + required_device m_tape_reader; + required_device m_tape_puncher; + required_device m_typewriter; + required_device m_parallel_drum; + int m_io_status; + emu_timer *m_dpy_timer; + lightpen_t m_lightpen; + + virtual void machine_start() override; + virtual void machine_reset() override; + virtual void video_start() override; + void pdp1_palette(palette_device &palette) const; + uint32_t screen_update_pdp1(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect); + DECLARE_WRITE_LINE_MEMBER(screen_vblank_pdp1); + INTERRUPT_GEN_MEMBER(pdp1_interrupt); + TIMER_CALLBACK_MEMBER(dpy_callback); + void pdp1_machine_stop(); + inline void pdp1_plot_pixel(bitmap_ind16 &bitmap, int x, int y, uint32_t color); + void pdp1_plot(int x, int y); + void pdp1_draw_led(bitmap_ind16 &bitmap, int x, int y, int state); + void pdp1_draw_multipleled(bitmap_ind16 &bitmap, int x, int y, int value, int nb_bits); + void pdp1_draw_switch(bitmap_ind16 &bitmap, int x, int y, int state); + void pdp1_draw_multipleswitch(bitmap_ind16 &bitmap, int x, int y, int value, int nb_bits); + void pdp1_draw_char(bitmap_ind16 &bitmap, char character, int x, int y, int color); + void pdp1_draw_string(bitmap_ind16 &bitmap, const char *buf, int x, int y, int color); + void pdp1_draw_panel_backdrop(bitmap_ind16 &bitmap); + void pdp1_draw_panel(bitmap_ind16 &bitmap); + void pdp1_update_lightpen_state(const lightpen_t *new_state); + void pdp1_draw_circle(bitmap_ind16 &bitmap, int x, int y, int radius, int color_); + void pdp1_erase_lightpen(bitmap_ind16 &bitmap); + void pdp1_draw_lightpen(bitmap_ind16 &bitmap); + void pdp1_lightpen(); + + template DECLARE_WRITE_LINE_MEMBER(io_status_w); + + void pdp1(machine_config &config); + void pdp1_map(address_map &map); +private: + void iot_dpy(int op2, int nac, int mb, int &io, int ac); + + void iot_011(int op2, int nac, int mb, int &io, int ac); + + void iot_cks(int op2, int nac, int mb, int &io, int ac); + + void io_start_clear(); + + pdp1_reset_param_t m_reset_param; + int m_old_lightpen; + int m_old_control_keys; + int m_old_tw_keys; + int m_old_ta_keys; + bitmap_ind16 m_panel_bitmap; + lightpen_t m_lightpen_state; + lightpen_t m_previous_lightpen_state; + +public: + required_device m_gfxdecode; + required_device m_palette; + required_device m_crt; + required_ioport m_spacewar; + required_ioport m_csw; + required_ioport m_sense; + required_ioport m_tstadd; + required_ioport m_twdmsb; + required_ioport m_twdlsb; + required_ioport m_cfg; + required_ioport m_io_lightpen; + required_ioport m_lightx; + required_ioport m_lighty; +}; + +#endif // MAME_PDP1_PDP1_H diff --git a/src/mame/dec/pdp1_v.cpp b/src/mame/dec/pdp1_v.cpp new file mode 100644 index 00000000000..a80f52f06e7 --- /dev/null +++ b/src/mame/dec/pdp1_v.cpp @@ -0,0 +1,593 @@ +// license:GPL-2.0+ +// copyright-holders:Raphael Nabet +/* + video/pdp1.c + + PDP1 video emulation. + + We emulate three display devices: + * CRT screen + * control panel + * typewriter output + + For the actual emulation of these devices look at the machine/pdp1.c. This + file only includes the display routines. + + Raphael Nabet 2002-2004 + Based on earlier work by Chris Salomon +*/ + +#include "emu.h" +#include "cpu/pdp1/pdp1.h" +#include "pdp1.h" + +#include +#include + + + + +inline void pdp1_state::pdp1_plot_pixel(bitmap_ind16 &bitmap, int x, int y, uint32_t color) +{ + bitmap.pix(y, x) = color; +} + +/* + video init +*/ +void pdp1_state::video_start() +{ + m_typewriter->m_color = color_typewriter_black; + + /* alloc bitmaps for our private fun */ + m_panel_bitmap.allocate(panel_window_width, panel_window_height, BITMAP_FORMAT_IND16); + m_typewriter->m_bitmap.allocate(typewriter_window_width, typewriter_window_height, BITMAP_FORMAT_IND16); + + /* set up out bitmaps */ + pdp1_draw_panel_backdrop(m_panel_bitmap); + + const rectangle typewriter_bitmap_bounds(0, typewriter_window_width-1, 0, typewriter_window_height-1); + m_typewriter->m_bitmap.fill(pen_typewriter_bg, typewriter_bitmap_bounds); +} + + +WRITE_LINE_MEMBER(pdp1_state::screen_vblank_pdp1) +{ + // rising edge + if (state) + { + m_crt->eof(); + } +} + +/* + schedule a pixel to be plotted +*/ +void pdp1_state::pdp1_plot(int x, int y) +{ + /* compute pixel coordinates and plot */ + x = x*crt_window_width/01777; + y = y*crt_window_height/01777; + m_crt->plot(x, y); +} + + +/* + video_update_pdp1: effectively redraw the screen +*/ +uint32_t pdp1_state::screen_update_pdp1(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect) +{ + pdp1_erase_lightpen(bitmap); + m_crt->update(bitmap); + pdp1_draw_lightpen(bitmap); + + pdp1_draw_panel(m_panel_bitmap); + copybitmap(bitmap, m_panel_bitmap, 0, 0, panel_window_offset_x, panel_window_offset_y, cliprect); + + copybitmap(bitmap, m_typewriter->m_bitmap, 0, 0, typewriter_window_offset_x, typewriter_window_offset_y, cliprect); + return 0; +} + + + +/* + Operator control panel code +*/ + +enum +{ + x_panel_col1_offset = 8, + x_panel_col2_offset = x_panel_col1_offset+144+8, + x_panel_col3_offset = x_panel_col2_offset+96+8 +}; + +enum +{ + /* column 1: registers, test word, test address */ + y_panel_pc_offset = 0, + y_panel_ma_offset = y_panel_pc_offset+2*8, + y_panel_mb_offset = y_panel_ma_offset+2*8, + y_panel_ac_offset = y_panel_mb_offset+2*8, + y_panel_io_offset = y_panel_ac_offset+2*8, + y_panel_ta_offset = y_panel_io_offset+2*8, /* test address and extend switch */ + y_panel_tw_offset = y_panel_ta_offset+2*8, + + /* column 2: 1-bit indicators */ + y_panel_run_offset = 8, + y_panel_cyc_offset = y_panel_run_offset+8, + y_panel_defer_offset = y_panel_cyc_offset+8, + y_panel_hs_cyc_offset = y_panel_defer_offset+8, + y_panel_brk_ctr_1_offset = y_panel_hs_cyc_offset+8, + y_panel_brk_ctr_2_offset = y_panel_brk_ctr_1_offset+8, + y_panel_ov_offset = y_panel_brk_ctr_2_offset+8, + y_panel_rim_offset = y_panel_ov_offset+8, + y_panel_sbm_offset = y_panel_rim_offset+8, + y_panel_exd_offset = y_panel_sbm_offset+8, + y_panel_ioh_offset = y_panel_exd_offset+8, + y_panel_ioc_offset = y_panel_ioh_offset+8, + y_panel_ios_offset = y_panel_ioc_offset+8, + + /* column 3: power, single step, single inst, sense, flags, instr... */ + y_panel_power_offset = 8, + y_panel_sngl_step_offset = y_panel_power_offset+8, + y_panel_sngl_inst_offset = y_panel_sngl_step_offset+8, + y_panel_sep1_offset = y_panel_sngl_inst_offset+8, + y_panel_ss_offset = y_panel_sep1_offset+8, + y_panel_sep2_offset = y_panel_ss_offset+3*8, + y_panel_pf_offset = y_panel_sep2_offset+8, + y_panel_ir_offset = y_panel_pf_offset+2*8 +}; + +/* draw a small 8*8 LED (or is this a lamp? ) */ +void pdp1_state::pdp1_draw_led(bitmap_ind16 &bitmap, int x, int y, int state) +{ + int xx, yy; + + for (yy=1; yy<7; yy++) + for (xx=1; xx<7; xx++) + pdp1_plot_pixel(bitmap, x+xx, y+yy, state ? pen_lit_lamp : pen_unlit_lamp); +} + +/* draw nb_bits leds which represent nb_bits bits in value */ +void pdp1_state::pdp1_draw_multipleled(bitmap_ind16 &bitmap, int x, int y, int value, int nb_bits) +{ + while (nb_bits) + { + nb_bits--; + + pdp1_draw_led(bitmap, x, y, (value >> nb_bits) & 1); + + x += 8; + } +} + + +/* draw a small 8*8 switch */ +void pdp1_state::pdp1_draw_switch(bitmap_ind16 &bitmap, int x, int y, int state) +{ + int xx, yy; + int i; + + /* erase area */ + for (yy=0; yy<8; yy++) + for (xx=0; xx<8; xx++) + pdp1_plot_pixel(bitmap, x+xx, y+yy, pen_panel_bg); + + + /* draw nut (-> circle) */ + for (i=0; i<4;i++) + { + pdp1_plot_pixel(bitmap, x+2+i, y+1, pen_switch_nut); + pdp1_plot_pixel(bitmap, x+2+i, y+6, pen_switch_nut); + pdp1_plot_pixel(bitmap, x+1, y+2+i, pen_switch_nut); + pdp1_plot_pixel(bitmap, x+6, y+2+i, pen_switch_nut); + } + pdp1_plot_pixel(bitmap, x+2, y+2, pen_switch_nut); + pdp1_plot_pixel(bitmap, x+5, y+2, pen_switch_nut); + pdp1_plot_pixel(bitmap, x+2, y+5, pen_switch_nut); + pdp1_plot_pixel(bitmap, x+5, y+5, pen_switch_nut); + + /* draw button (->disc) */ + if (! state) + y += 4; + for (i=0; i<2;i++) + { + pdp1_plot_pixel(bitmap, x+3+i, y, pen_switch_button); + pdp1_plot_pixel(bitmap, x+3+i, y+3, pen_switch_button); + } + for (i=0; i<4;i++) + { + pdp1_plot_pixel(bitmap, x+2+i, y+1, pen_switch_button); + pdp1_plot_pixel(bitmap, x+2+i, y+2, pen_switch_button); + } +} + + +/* draw nb_bits switches which represent nb_bits bits in value */ +void pdp1_state::pdp1_draw_multipleswitch(bitmap_ind16 &bitmap, int x, int y, int value, int nb_bits) +{ + while (nb_bits) + { + nb_bits--; + + pdp1_draw_switch(bitmap, x, y, (value >> nb_bits) & 1); + + x += 8; + } +} + + +/* write a single char on screen */ +void pdp1_state::pdp1_draw_char(bitmap_ind16 &bitmap, char character, int x, int y, int color) +{ + m_gfxdecode->gfx(0)->transpen(bitmap,bitmap.cliprect(), character-32, color, 0, 0, + x+1, y, 0); +} + +/* write a string on screen */ +void pdp1_state::pdp1_draw_string(bitmap_ind16 &bitmap, const char *buf, int x, int y, int color) +{ + while (* buf) + { + pdp1_draw_char(bitmap, *buf, x, y, color); + + x += 8; + buf++; + } +} + + +/* + draw the operator control panel (fixed backdrop) +*/ +void pdp1_state::pdp1_draw_panel_backdrop(bitmap_ind16 &bitmap) +{ + /* fill with black */ + const rectangle panel_bitmap_bounds(0, panel_window_width-1, 0, panel_window_height-1); + m_panel_bitmap.fill(pen_panel_bg, panel_bitmap_bounds); + + /* column 1: registers, test word, test address */ + pdp1_draw_string(bitmap, "program counter", x_panel_col1_offset, y_panel_pc_offset, color_panel_caption); + pdp1_draw_string(bitmap, "memory address", x_panel_col1_offset, y_panel_ma_offset, color_panel_caption); + pdp1_draw_string(bitmap, "memory buffer", x_panel_col1_offset, y_panel_mb_offset, color_panel_caption); + pdp1_draw_string(bitmap, "accumulator", x_panel_col1_offset, y_panel_ac_offset, color_panel_caption); + pdp1_draw_string(bitmap, "in-out", x_panel_col1_offset, y_panel_io_offset, color_panel_caption); + pdp1_draw_string(bitmap, "extend address", x_panel_col1_offset, y_panel_ta_offset, color_panel_caption); + pdp1_draw_string(bitmap, "test word", x_panel_col1_offset, y_panel_tw_offset, color_panel_caption); + + /* column separator */ + bitmap.plot_box(x_panel_col2_offset-4, panel_window_offset_y+8, 1, 96, pen_panel_caption); + + /* column 2: 1-bit indicators */ + pdp1_draw_string(bitmap, "run", x_panel_col2_offset+8, y_panel_run_offset, color_panel_caption); + pdp1_draw_string(bitmap, "cycle", x_panel_col2_offset+8, y_panel_cyc_offset, color_panel_caption); + pdp1_draw_string(bitmap, "defer", x_panel_col2_offset+8, y_panel_defer_offset, color_panel_caption); + pdp1_draw_string(bitmap, "h. s. cycle", x_panel_col2_offset+8, y_panel_hs_cyc_offset, color_panel_caption); + pdp1_draw_string(bitmap, "brk. ctr. 1", x_panel_col2_offset+8, y_panel_brk_ctr_1_offset, color_panel_caption); + pdp1_draw_string(bitmap, "brk. ctr. 2", x_panel_col2_offset+8, y_panel_brk_ctr_2_offset, color_panel_caption); + pdp1_draw_string(bitmap, "overflow", x_panel_col2_offset+8, y_panel_ov_offset, color_panel_caption); + pdp1_draw_string(bitmap, "read in", x_panel_col2_offset+8, y_panel_rim_offset, color_panel_caption); + pdp1_draw_string(bitmap, "seq. break", x_panel_col2_offset+8, y_panel_sbm_offset, color_panel_caption); + pdp1_draw_string(bitmap, "extend", x_panel_col2_offset+8, y_panel_exd_offset, color_panel_caption); + pdp1_draw_string(bitmap, "i-o halt", x_panel_col2_offset+8, y_panel_ioh_offset, color_panel_caption); + pdp1_draw_string(bitmap, "i-o com'ds", x_panel_col2_offset+8, y_panel_ioc_offset, color_panel_caption); + pdp1_draw_string(bitmap, "i-o sync", x_panel_col2_offset+8, y_panel_ios_offset, color_panel_caption); + + /* column separator */ + bitmap.plot_box(x_panel_col3_offset-4, panel_window_offset_y+8, 1, 96, pen_panel_caption); + + /* column 3: power, single step, single inst, sense, flags, instr... */ + pdp1_draw_string(bitmap, "power", x_panel_col3_offset+16, y_panel_power_offset, color_panel_caption); + pdp1_draw_string(bitmap, "single step", x_panel_col3_offset+16, y_panel_sngl_step_offset, color_panel_caption); + pdp1_draw_string(bitmap, "single inst.", x_panel_col3_offset+16, y_panel_sngl_inst_offset, color_panel_caption); + /* separator */ + bitmap.plot_box(x_panel_col3_offset+8, y_panel_sep1_offset+4, 96, 1, pen_panel_caption); + pdp1_draw_string(bitmap, "sense switches", x_panel_col3_offset, y_panel_ss_offset, color_panel_caption); + /* separator */ + bitmap.plot_box(x_panel_col3_offset+8, y_panel_sep2_offset+4, 96, 1, pen_panel_caption); + pdp1_draw_string(bitmap, "program flags", x_panel_col3_offset, y_panel_pf_offset, color_panel_caption); + pdp1_draw_string(bitmap, "instruction", x_panel_col3_offset, y_panel_ir_offset, color_panel_caption); +} + +/* + draw the operator control panel (dynamic elements) +*/ +void pdp1_state::pdp1_draw_panel(bitmap_ind16 &bitmap) +{ + /* column 1: registers, test word, test address */ + pdp1_draw_multipleled(bitmap, x_panel_col1_offset+16, y_panel_pc_offset+8,m_maincpu->state_int(PDP1_PC), 16); + pdp1_draw_multipleled(bitmap, x_panel_col1_offset+16, y_panel_ma_offset+8,m_maincpu->state_int(PDP1_MA), 16); + pdp1_draw_multipleled(bitmap, x_panel_col1_offset, y_panel_mb_offset+8,m_maincpu->state_int(PDP1_MB), 18); + pdp1_draw_multipleled(bitmap, x_panel_col1_offset, y_panel_ac_offset+8,m_maincpu->state_int(PDP1_AC), 18); + pdp1_draw_multipleled(bitmap, x_panel_col1_offset, y_panel_io_offset+8,m_maincpu->state_int(PDP1_IO), 18); + pdp1_draw_switch(bitmap, x_panel_col1_offset, y_panel_ta_offset+8,m_maincpu->state_int(PDP1_EXTEND_SW)); + pdp1_draw_multipleswitch(bitmap, x_panel_col1_offset+16, y_panel_ta_offset+8,m_maincpu->state_int(PDP1_TA), 16); + pdp1_draw_multipleswitch(bitmap, x_panel_col1_offset, y_panel_tw_offset+8,m_maincpu->state_int(PDP1_TW), 18); + + /* column 2: 1-bit indicators */ + pdp1_draw_led(bitmap, x_panel_col2_offset, y_panel_run_offset,m_maincpu->state_int(PDP1_RUN)); + pdp1_draw_led(bitmap, x_panel_col2_offset, y_panel_cyc_offset,m_maincpu->state_int(PDP1_CYC)); + pdp1_draw_led(bitmap, x_panel_col2_offset, y_panel_defer_offset,m_maincpu->state_int(PDP1_DEFER)); + pdp1_draw_led(bitmap, x_panel_col2_offset, y_panel_hs_cyc_offset, 0); /* not emulated */ + pdp1_draw_led(bitmap, x_panel_col2_offset, y_panel_brk_ctr_1_offset,m_maincpu->state_int(PDP1_BRK_CTR) & 1); + pdp1_draw_led(bitmap, x_panel_col2_offset, y_panel_brk_ctr_2_offset,m_maincpu->state_int(PDP1_BRK_CTR) & 2); + pdp1_draw_led(bitmap, x_panel_col2_offset, y_panel_ov_offset,m_maincpu->state_int(PDP1_OV)); + pdp1_draw_led(bitmap, x_panel_col2_offset, y_panel_rim_offset,m_maincpu->state_int(PDP1_RIM)); + pdp1_draw_led(bitmap, x_panel_col2_offset, y_panel_sbm_offset,m_maincpu->state_int(PDP1_SBM)); + pdp1_draw_led(bitmap, x_panel_col2_offset, y_panel_exd_offset,m_maincpu->state_int(PDP1_EXD)); + pdp1_draw_led(bitmap, x_panel_col2_offset, y_panel_ioh_offset,m_maincpu->state_int(PDP1_IOH)); + pdp1_draw_led(bitmap, x_panel_col2_offset, y_panel_ioc_offset,m_maincpu->state_int(PDP1_IOC)); + pdp1_draw_led(bitmap, x_panel_col2_offset, y_panel_ios_offset,m_maincpu->state_int(PDP1_IOS)); + + /* column 3: power, single step, single inst, sense, flags, instr... */ + pdp1_draw_led(bitmap, x_panel_col3_offset, y_panel_power_offset, 1); /* always on */ + pdp1_draw_switch(bitmap, x_panel_col3_offset+8, y_panel_power_offset, 1); /* always on */ + pdp1_draw_led(bitmap, x_panel_col3_offset, y_panel_sngl_step_offset,m_maincpu->state_int(PDP1_SNGL_STEP)); + pdp1_draw_switch(bitmap, x_panel_col3_offset+8, y_panel_sngl_step_offset,m_maincpu->state_int(PDP1_SNGL_STEP)); + pdp1_draw_led(bitmap, x_panel_col3_offset, y_panel_sngl_inst_offset,m_maincpu->state_int(PDP1_SNGL_INST)); + pdp1_draw_switch(bitmap, x_panel_col3_offset+8, y_panel_sngl_inst_offset,m_maincpu->state_int(PDP1_SNGL_INST)); + pdp1_draw_multipleled(bitmap, x_panel_col3_offset, y_panel_ss_offset+8,m_maincpu->state_int(PDP1_SS), 6); + pdp1_draw_multipleswitch(bitmap, x_panel_col3_offset, y_panel_ss_offset+16,m_maincpu->state_int(PDP1_SS), 6); + pdp1_draw_multipleled(bitmap, x_panel_col3_offset, y_panel_pf_offset+8,m_maincpu->state_int(PDP1_PF), 6); + pdp1_draw_multipleled(bitmap, x_panel_col3_offset, y_panel_ir_offset+8,m_maincpu->state_int(PDP1_IR), 5); +} + + +/* + Typewriter code +*/ + + + + +enum +{ + typewriter_line_height = 8, + typewriter_write_offset_y = typewriter_window_height-typewriter_line_height, + typewriter_scroll_step = typewriter_line_height +}; + +enum +{ + tab_step = 8 +}; + + +void pdp1_typewriter_device::linefeed() +{ + uint8_t buf[typewriter_window_width]; + + assert(typewriter_window_width <= m_bitmap.width()); + assert(typewriter_window_height <= m_bitmap.height()); + for (int y=0; ym_palette->pens()); + } + + const rectangle typewriter_scroll_clear_window(0, typewriter_window_width-1, typewriter_window_height-typewriter_scroll_step, typewriter_window_height-1); + m_bitmap.fill(pen_typewriter_bg, typewriter_scroll_clear_window); +} + +void pdp1_typewriter_device::drawchar(int character) +{ + static const char ascii_table[2][64] = + { // n-s = non-spacing + { // lower case + ' ', '1', '2', '3', + '4', '5', '6', '7', + '8', '9', '*', '*', + '*', '*', '*', '*', + '0', '/', 's', 't', + 'u', 'v', 'w', 'x', + 'y', 'z', '*', ',', + '*',/*black*/ '*',/*red*/ '*',/*Tab*/ '*', + '\200',/*n-s middle dot*/'j', 'k', 'l', + 'm', 'n', 'o', 'p', + 'q', 'r', '*', '*', + '-', ')', '\201',/*n-s overstrike*/'(', + '*', 'a', 'b', 'c', + 'd', 'e', 'f', 'g', + 'h', 'i', '*',/*Lower Case*/ '.', + '*',/*Upper Case*/ '*',/*Backspace*/ '*', '*'/*Carriage Return*/ + }, + { // upper case + ' ', '"', '\'', '~', + '\202',/*implies*/ '\203',/*or*/ '\204',/*and*/ '<', + '>', '\205',/*up arrow*/ '*', '*', + '*', '*', '*', '*', + '\206',/*right arrow*/'?', 'S', 'T', + 'U', 'V', 'W', 'X', + 'Y', 'Z', '*', '=', + '*',/*black*/ '*',/*red*/ '*',/*Tab*/ '*', + '_',/*n-s???*/ 'J', 'K', 'L', + 'M', 'N', 'O', 'P', + 'Q', 'R', '*', '*', + '+', ']', '|',/*n-s???*/ '[', + '*', 'A', 'B', 'C', + 'D', 'E', 'F', 'G', + 'H', 'I', '*',/*Lower Case*/ '\207',/*multiply*/ + '*',/*Upper Case*/ '*',/*Backspace*/ '*', '*'/*Carriage Return*/ + } + }; + + + + character &= 0x3f; + + switch (character) + { + case 034: + // Black + m_color = color_typewriter_black; + break; + + case 035: + // Red + m_color = color_typewriter_red; + break; + + case 036: + // Tab + m_pos = m_pos + tab_step - (m_pos % tab_step); + break; + + case 072: + // Lower case + m_case_shift = 0; + break; + + case 074: + // Upper case + m_case_shift = 1; + break; + + case 075: + // Backspace + if (m_pos) + m_pos--; + break; + + case 077: + // Carriage Return + m_pos = 0; + linefeed(); + break; + + default: + // Any printable character... + + if (m_pos >= 80) + { // if past right border, wrap around. (Right???) + linefeed(); // next line + m_pos = 0; // return to start of line + } + + // print character (lookup ASCII equivalent in table) + m_driver_state->pdp1_draw_char(m_bitmap, ascii_table[m_case_shift][character], + 8*m_pos, typewriter_write_offset_y, + m_color); // print char + + if ((character!= 040) && (character!= 056)) // 040 and 056 are non-spacing characters + m_pos++; // step carriage forward + + break; + } +} + + + +/* + lightpen code +*/ + +void pdp1_state::pdp1_update_lightpen_state(const lightpen_t *new_state) +{ + m_lightpen_state = *new_state; +} + +#if 1 +void pdp1_state::pdp1_draw_circle(bitmap_ind16 &bitmap, int x, int y, int radius, int color_) +{ + int interval; + int a; + + x = x*crt_window_width/01777; + y = y*crt_window_width/01777; + radius = radius*crt_window_width/01777; + + interval = ceil(radius/sqrt(2.)); + + for (a=0; a<=interval; a++) + { + int b = sqrt((double)radius*radius-a*a) + .5; + + if ((x-a >= 0) && (y-b >= 0)) + pdp1_plot_pixel(bitmap, x-a, y-b, color_); + if ((x-a >= 0) && (y+b <= crt_window_height-1)) + pdp1_plot_pixel(bitmap, x-a, y+b, color_); + if ((x+a <= crt_window_width-1) && (y-b >= 0)) + pdp1_plot_pixel(bitmap, x+a, y-b, color_); + if ((x+a <= crt_window_width-1) && (y+b <= crt_window_height-1)) + pdp1_plot_pixel(bitmap, x+a, y+b, color_); + + if ((x-b >= 0) && (y-a >= 0)) + pdp1_plot_pixel(bitmap, x-b, y-a, color_); + if ((x-b >= 0) && (y+a <= crt_window_height-1)) + pdp1_plot_pixel(bitmap, x-b, y+a, color_); + if ((x+b <= crt_window_width-1) && (y-a >= 0)) + pdp1_plot_pixel(bitmap, x+b, y-a, color_); + if ((x+b <= crt_window_width-1) && (y+a <= crt_window_height-1)) + pdp1_plot_pixel(bitmap, x+b, y+a, color_); + } +} +#else +void pdp1_state::pdp1_draw_circle(bitmap_ind16 &bitmap, int x, int y, int radius, int color) +{ + float fx, fy; + float interval; + + + fx = (float)x*crt_window_width/01777; + fy = (float)y*crt_window_height/01777; + + interval = radius/sqrt(2.); + + for (x=/*ceil*/(fx-interval); x<=fx+interval; x++) + { + float dy = sqrt(radius*radius-(x-fx)*(x-fx)); + + if ((x >= 0) && (x <= crt_window_width-1) && (fy-dy >= 0)) + pdp1_plot_pixel(bitmap, x, fy-dy, color); + if ((x >= 0) && (x <= crt_window_width-1) && (y+dy <= crt_window_height-1)) + pdp1_plot_pixel(bitmap, x, fy+dy, color); + } + for (y=/*ceil*/(fy-interval); y<=fy+interval; y++) + { + float dx = sqrt(radius*radius-(y-fy)*(y-fy)); + + if ((fx-dx >= 0) && (y >= 0) && (y <= crt_window_height-1)) + pdp1_plot_pixel(bitmap, fx-dx, y, color); + if ((fx+dx <= crt_window_width-1) && (y >= 0) && (y <= crt_window_height-1)) + pdp1_plot_pixel(bitmap, fx+dx, y, color); + } +} +#endif + +void pdp1_state::pdp1_erase_lightpen(bitmap_ind16 &bitmap) +{ + if (m_previous_lightpen_state.active) + { +#if 0 + if (m_previous_lightpen_state.x>0) + pdp1_plot_pixel(bitmap, m_previous_lightpen_state.x/2-1, m_previous_lightpen_state.y/2, pen_black); + if (m_previous_lightpen_state.x<1023) + pdp1_plot_pixel(bitmap, m_previous_lightpen_state.x/2+1, m_previous_lightpen_state.y/2, pen_black); + if (m_previous_lightpen_state.y>0) + pdp1_plot_pixel(bitmap, m_previous_lightpen_state.x/2, m_previous_lightpen_state.y/2-1, pen_black); + if (m_previous_lightpen_state.y<1023) + pdp1_plot_pixel(bitmap, m_previous_lightpen_state.x/2, m_previous_lightpen_state.y/2+1, pen_black); +#endif + pdp1_draw_circle(bitmap, m_previous_lightpen_state.x, m_previous_lightpen_state.y, m_previous_lightpen_state.radius, pen_black); + } +} + +void pdp1_state::pdp1_draw_lightpen(bitmap_ind16 &bitmap) +{ + if (m_lightpen_state.active) + { + int color_ = m_lightpen_state.down ? pen_lightpen_pressed : pen_lightpen_nonpressed; +#if 0 + if (m_lightpen_state.x>0) + pdp1_plot_pixel(bitmap, m_lightpen_state.x/2-1, m_lightpen_state.y/2, color); + if (m_lightpen_state.x<1023) + pdp1_plot_pixel(bitmap, m_lightpen_state.x/2+1, m_lightpen_state.y/2, color); + if (m_lightpen_state.y>0) + pdp1_plot_pixel(bitmap, m_lightpen_state.x/2, m_lightpen_state.y/2-1, color); + if (m_lightpen_state.y<1023) + pdp1_plot_pixel(bitmap, m_lightpen_state.x/2, m_lightpen_state.y/2+1, color); +#endif + pdp1_draw_circle(bitmap, m_lightpen_state.x, m_lightpen_state.y, m_lightpen_state.radius, color_); + } + m_previous_lightpen_state = m_lightpen_state; +} diff --git a/src/mame/mame.lst b/src/mame/mame.lst index addbe98420a..1d571713ef2 100644 --- a/src/mame/mame.lst +++ b/src/mame/mame.lst @@ -34525,7 +34525,7 @@ tetriskr // (c) 1988? bootleg @source:amstrad/pda600.cpp pda600 // -@source:pdp1/pdp1.cpp +@source:dec/pdp1.cpp pdp1 // 1961 DEC PDP1 @source:dec/pdp11.cpp diff --git a/src/mame/mess.flt b/src/mame/mess.flt index b1d96421dfe..82425e4f341 100644 --- a/src/mame/mess.flt +++ b/src/mame/mess.flt @@ -198,6 +198,7 @@ dec/decstation.cpp dec/dectalk.cpp dec/decwritr.cpp dec/jensen.cpp +dec/pdp1.cpp dec/pdp11.cpp dec/rainbow.cpp dec/vax11.cpp @@ -592,7 +593,6 @@ pc/ps2.cpp pc/sis630.cpp pc/tandy1t.cpp pc/tosh1000.cpp -pdp1/pdp1.cpp philips/odyssey2.cpp philips/p2000t.cpp philips/vg5k.cpp diff --git a/src/mame/pdp1/pdp1.cpp b/src/mame/pdp1/pdp1.cpp deleted file mode 100644 index fd719ce63b0..00000000000 --- a/src/mame/pdp1/pdp1.cpp +++ /dev/null @@ -1,1849 +0,0 @@ -// license:GPL-2.0+ -// copyright-holders:Raphael Nabet -/* - -Driver for a PDP1 emulator. - - Digital Equipment Corporation - Brian Silverman (original Java Source) - Vadim Gerasimov (original Java Source) - Chris Salomon (MESS driver) - Raphael Nabet (MESS driver) - -Initially, this was a conversion of a JAVA emulator -(although code has been edited extensively ever since). -I have tried contacting the author, but heard as yet nothing of him, -so I don't know if it all right with him, but after all -> he did -release the source, so hopefully everything will be fine (no his -name is not Marat). - -Note: naturally I have no PDP1, I have never seen one, nor have I any -programs for it. - -The first supported program was: - -SPACEWAR! - -The first Videogame EVER! - -When I saw the java emulator, running that game I was quite intrigued to -include a driver for MESS. -I think the historical value of SPACEWAR! is enormous. - -Two other programs are supported: Munching squares and LISP. - -Added Debugging and Disassembler... - - -Also: -ftp://minnie.cs.adfa.oz.au/pub/PDP-11/Sims/Supnik_2.3/software/lispswre.tar.gz -Is a packet which includes the original LISP as source and -binary form plus a macro assembler for PDP1 programs. - -For more documentation look at the source for the driver, -and the cpu/pdp1/pdp1.c file (information about the whereabouts of information -and the java source). - - -To load and play a game: -- Load a .rim file into the first tape reader -- Hold down Left Control, and press Enter. Let go. -- The lights will flash while the paper tape is being read. -- At the end, the game will start. - - - -*/ - -#include "emu.h" -#include "pdp1.h" - -#include "cpu/pdp1/pdp1.h" - -#include "screen.h" -#include "softlist_dev.h" - - -/* - * - * The loading storing OS... is not emulated (I haven't a clue where to - * get programs for the machine) - * - */ - - -void pdp1_state::pdp1_map(address_map &map) -{ - map(0x00000, 0x3ffff).ram(); -} - -static INPUT_PORTS_START( pdp1 ) - PORT_START("SPACEWAR") /* 0: spacewar controllers */ - PORT_BIT( ROTATE_LEFT_PLAYER1, IP_ACTIVE_HIGH, IPT_JOYSTICK_LEFT) PORT_NAME("Spin Left Player 1") PORT_CODE(KEYCODE_A) PORT_CODE(JOYCODE_X_LEFT_SWITCH) - PORT_BIT( ROTATE_RIGHT_PLAYER1, IP_ACTIVE_HIGH, IPT_JOYSTICK_RIGHT) PORT_NAME("Spin Right Player 1") PORT_CODE(KEYCODE_S) PORT_CODE(JOYCODE_X_RIGHT_SWITCH) - PORT_BIT( THRUST_PLAYER1, IP_ACTIVE_HIGH, IPT_BUTTON1) PORT_NAME("Thrust Player 1") PORT_CODE(KEYCODE_D) PORT_CODE(JOYCODE_BUTTON1) - PORT_BIT( FIRE_PLAYER1, IP_ACTIVE_HIGH, IPT_BUTTON2) PORT_NAME("Fire Player 1") PORT_CODE(KEYCODE_F) PORT_CODE(JOYCODE_BUTTON2) - PORT_BIT( ROTATE_LEFT_PLAYER2, IP_ACTIVE_HIGH, IPT_JOYSTICK_LEFT) PORT_NAME("Spin Left Player 2") PORT_CODE(KEYCODE_LEFT) PORT_CODE(JOYCODE_X_LEFT_SWITCH ) PORT_PLAYER(2) - PORT_BIT( ROTATE_RIGHT_PLAYER2, IP_ACTIVE_HIGH, IPT_JOYSTICK_RIGHT) PORT_NAME("Spin Right Player 2") PORT_CODE(KEYCODE_RIGHT) PORT_CODE(JOYCODE_X_RIGHT_SWITCH ) PORT_PLAYER(2) - PORT_BIT( THRUST_PLAYER2, IP_ACTIVE_HIGH, IPT_BUTTON1) PORT_NAME("Thrust Player 2") PORT_CODE(KEYCODE_UP) PORT_CODE(JOYCODE_BUTTON1 ) PORT_PLAYER(2) - PORT_BIT( FIRE_PLAYER2, IP_ACTIVE_HIGH, IPT_BUTTON2) PORT_NAME("Fire Player 2") PORT_CODE(KEYCODE_DOWN) PORT_CODE(JOYCODE_BUTTON2 ) PORT_PLAYER(2) - PORT_BIT( HSPACE_PLAYER1, IP_ACTIVE_HIGH, IPT_BUTTON3) PORT_NAME("Hyperspace Player 1") PORT_CODE(KEYCODE_Z) PORT_CODE(JOYCODE_BUTTON3) - PORT_BIT( HSPACE_PLAYER2, IP_ACTIVE_HIGH, IPT_BUTTON3) PORT_NAME("Hyperspace Player 2") PORT_CODE(KEYCODE_SLASH) PORT_CODE(JOYCODE_BUTTON3 ) PORT_PLAYER(2) - - PORT_START("CSW") /* 1: various pdp1 operator control panel switches */ - PORT_BIT(pdp1_control, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("control panel key") PORT_CODE(KEYCODE_LCONTROL) - PORT_BIT(pdp1_extend, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("extend") PORT_CODE(KEYCODE_TILDE) - PORT_BIT(pdp1_start_nobrk, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("start (sequence break disabled)") PORT_CODE(KEYCODE_U) - PORT_BIT(pdp1_start_brk, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("start (sequence break enabled)") PORT_CODE(KEYCODE_I) - PORT_BIT(pdp1_stop, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("stop") PORT_CODE(KEYCODE_O) - PORT_BIT(pdp1_continue, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("continue") PORT_CODE(KEYCODE_P) - PORT_BIT(pdp1_examine, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("examine") PORT_CODE(KEYCODE_OPENBRACE) - PORT_BIT(pdp1_deposit, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("deposit") PORT_CODE(KEYCODE_CLOSEBRACE) - PORT_BIT(pdp1_read_in, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("read in") PORT_CODE(KEYCODE_ENTER) - PORT_BIT(pdp1_reader, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("reader") - PORT_BIT(pdp1_tape_feed, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("tape feed") - PORT_BIT(pdp1_single_step, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("single step") PORT_CODE(KEYCODE_STOP) - PORT_BIT(pdp1_single_inst, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("single inst") PORT_CODE(KEYCODE_SLASH) - - PORT_START("SENSE") /* 2: operator control panel sense switches */ - PORT_DIPNAME( 040, 000, "Sense Switch 1") PORT_CODE(KEYCODE_1_PAD) - PORT_DIPSETTING( 000, DEF_STR( Off ) ) - PORT_DIPSETTING( 040, DEF_STR( On ) ) - PORT_DIPNAME( 020, 000, "Sense Switch 2") PORT_CODE(KEYCODE_2_PAD) - PORT_DIPSETTING( 000, DEF_STR( Off ) ) - PORT_DIPSETTING( 020, DEF_STR( On ) ) - PORT_DIPNAME( 010, 000, "Sense Switch 3") PORT_CODE(KEYCODE_3_PAD) - PORT_DIPSETTING( 000, DEF_STR( Off ) ) - PORT_DIPSETTING( 010, DEF_STR( On ) ) - PORT_DIPNAME( 004, 000, "Sense Switch 4") PORT_CODE(KEYCODE_4_PAD) - PORT_DIPSETTING( 000, DEF_STR( Off ) ) - PORT_DIPSETTING( 004, DEF_STR( On ) ) - PORT_DIPNAME( 002, 002, "Sense Switch 5") PORT_CODE(KEYCODE_5_PAD) - PORT_DIPSETTING( 000, DEF_STR( Off ) ) - PORT_DIPSETTING( 002, DEF_STR( On ) ) - PORT_DIPNAME( 001, 000, "Sense Switch 6") PORT_CODE(KEYCODE_6_PAD) - PORT_DIPSETTING( 000, DEF_STR( Off ) ) - PORT_DIPSETTING( 001, DEF_STR( On ) ) - - PORT_START("TSTADD") /* 3: operator control panel test address switches */ - PORT_BIT( 0100000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Extension Test Address Switch 3") PORT_CODE(KEYCODE_1) - PORT_BIT( 0040000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Extension Test Address Switch 4") PORT_CODE(KEYCODE_2) - PORT_BIT( 0020000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Extension Test Address Switch 5") PORT_CODE(KEYCODE_3) - PORT_BIT( 0010000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Extension Test Address Switch 6") PORT_CODE(KEYCODE_4) - PORT_BIT( 0004000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Test Address Switch 7") PORT_CODE(KEYCODE_5) - PORT_BIT( 0002000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Test Address Switch 8") PORT_CODE(KEYCODE_6) - PORT_BIT( 0001000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Test Address Switch 9") PORT_CODE(KEYCODE_7) - PORT_BIT( 0000400, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Test Address Switch 10") PORT_CODE(KEYCODE_8) - PORT_BIT( 0000200, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Test Address Switch 11") PORT_CODE(KEYCODE_9) - PORT_BIT( 0000100, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Test Address Switch 12") PORT_CODE(KEYCODE_0) - PORT_BIT( 0000040, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Test Address Switch 13") PORT_CODE(KEYCODE_MINUS) - PORT_BIT( 0000020, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Test Address Switch 14") PORT_CODE(KEYCODE_EQUALS) - PORT_BIT( 0000010, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Test Address Switch 15") PORT_CODE(KEYCODE_Q) - PORT_BIT( 0000004, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Test Address Switch 16") PORT_CODE(KEYCODE_W) - PORT_BIT( 0000002, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Test Address Switch 17") PORT_CODE(KEYCODE_E) - PORT_BIT( 0000001, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Test Address Switch 18") PORT_CODE(KEYCODE_R) - - PORT_START("TWDMSB") /* 4: operator control panel test word switches MSB */ - PORT_BIT( 0002, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Test Word Switch 1") PORT_CODE(KEYCODE_A) - PORT_BIT( 0001, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Test Word Switch 2") PORT_CODE(KEYCODE_S) - - PORT_START("TWDLSB") /* 5: operator control panel test word switches LSB */ - PORT_BIT( 0100000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Test Word Switch 3") PORT_CODE(KEYCODE_D) - PORT_BIT( 0040000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Test Word Switch 4") PORT_CODE(KEYCODE_F) - PORT_BIT( 0020000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Test Word Switch 5") PORT_CODE(KEYCODE_G) - PORT_BIT( 0010000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Test Word Switch 6") PORT_CODE(KEYCODE_H) - PORT_BIT( 0004000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Test Word Switch 7") PORT_CODE(KEYCODE_J) - PORT_BIT( 0002000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Test Word Switch 8") PORT_CODE(KEYCODE_K) - PORT_BIT( 0001000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Test Word Switch 9") PORT_CODE(KEYCODE_L) - PORT_BIT( 0000400, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Test Word Switch 10") PORT_CODE(KEYCODE_COLON) - PORT_BIT( 0000200, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Test Word Switch 11") PORT_CODE(KEYCODE_QUOTE) - PORT_BIT( 0000100, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Test Word Switch 12") PORT_CODE(KEYCODE_BACKSLASH) - PORT_BIT( 0000040, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Test Word Switch 13") PORT_CODE(KEYCODE_Z) - PORT_BIT( 0000020, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Test Word Switch 14") PORT_CODE(KEYCODE_X) - PORT_BIT( 0000010, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Test Word Switch 15") PORT_CODE(KEYCODE_C) - PORT_BIT( 0000004, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Test Word Switch 16") PORT_CODE(KEYCODE_V) - PORT_BIT( 0000002, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Test Word Switch 17") PORT_CODE(KEYCODE_B) - PORT_BIT( 0000001, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Test Word Switch 18") PORT_CODE(KEYCODE_N) - - /* - Note that I can see 2 additional keys whose purpose is unknown to me. - The caps look like "MAR REL" for the leftmost one and "MAR SET" for - rightmost one: maybe they were used to set the margin (I don't have the - manual for the typewriter). */ - - PORT_START("TWR.0") /* 6: typewriter codes 00-17 */ - PORT_BIT(0x0001, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("(Space)") PORT_CODE(KEYCODE_SPACE) - PORT_BIT(0x0002, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("1 \"") PORT_CODE(KEYCODE_1) - PORT_BIT(0x0004, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("2 '") PORT_CODE(KEYCODE_2) - PORT_BIT(0x0008, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("3 ~") PORT_CODE(KEYCODE_3) - PORT_BIT(0x0010, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("4 (implies)") PORT_CODE(KEYCODE_4) - PORT_BIT(0x0020, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("5 (or)") PORT_CODE(KEYCODE_5) - PORT_BIT(0x0040, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("6 (and)") PORT_CODE(KEYCODE_6) - PORT_BIT(0x0080, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("7 <") PORT_CODE(KEYCODE_7) - PORT_BIT(0x0100, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("8 >") PORT_CODE(KEYCODE_8) - PORT_BIT(0x0200, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("9 (up arrow)") PORT_CODE(KEYCODE_9) - - PORT_START("TWR.1") /* 7: typewriter codes 20-37 */ - PORT_BIT(0x0001, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("0 (right arrow)") PORT_CODE(KEYCODE_0) - PORT_BIT(0x0002, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("/ ?") PORT_CODE(KEYCODE_SLASH) - PORT_BIT(0x0004, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("S") PORT_CODE(KEYCODE_S) - PORT_BIT(0x0008, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("T") PORT_CODE(KEYCODE_T) - PORT_BIT(0x0010, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("U") PORT_CODE(KEYCODE_U) - PORT_BIT(0x0020, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("V") PORT_CODE(KEYCODE_V) - PORT_BIT(0x0040, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("W") PORT_CODE(KEYCODE_W) - PORT_BIT(0x0080, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("X") PORT_CODE(KEYCODE_X) - PORT_BIT(0x0100, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Y") PORT_CODE(KEYCODE_Y) - PORT_BIT(0x0200, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Z") PORT_CODE(KEYCODE_Z) - PORT_BIT(0x0800, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME(", =") PORT_CODE(KEYCODE_COMMA) - PORT_BIT(0x4000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Tab Key") PORT_CODE(KEYCODE_TAB) - - PORT_START("TWR.2") /* 8: typewriter codes 40-57 */ - PORT_BIT(0x0001, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("(non-spacing middle dot) _") PORT_CODE(KEYCODE_QUOTE) - PORT_BIT(0x0002, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("J") PORT_CODE(KEYCODE_J) - PORT_BIT(0x0004, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("K") PORT_CODE(KEYCODE_K) - PORT_BIT(0x0008, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("L") PORT_CODE(KEYCODE_L) - PORT_BIT(0x0010, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("M") PORT_CODE(KEYCODE_M) - PORT_BIT(0x0020, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("N") PORT_CODE(KEYCODE_N) - PORT_BIT(0x0040, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("O") PORT_CODE(KEYCODE_O) - PORT_BIT(0x0080, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("P") PORT_CODE(KEYCODE_P) - PORT_BIT(0x0100, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Q") PORT_CODE(KEYCODE_Q) - PORT_BIT(0x0200, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("R") PORT_CODE(KEYCODE_R) - PORT_BIT(0x1000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("- +") PORT_CODE(KEYCODE_COLON) - PORT_BIT(0x2000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME(") ]") PORT_CODE(KEYCODE_EQUALS) - PORT_BIT(0x4000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("(non-spacing overstrike) |") PORT_CODE(KEYCODE_OPENBRACE) - PORT_BIT(0x8000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("( [") PORT_CODE(KEYCODE_MINUS) - - PORT_START("TWR.3") /* 9: typewriter codes 60-77 */ - PORT_BIT(0x0002, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("A") PORT_CODE(KEYCODE_A) - PORT_BIT(0x0004, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("B") PORT_CODE(KEYCODE_B) - PORT_BIT(0x0008, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("C") PORT_CODE(KEYCODE_C) - PORT_BIT(0x0010, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("D") PORT_CODE(KEYCODE_D) - PORT_BIT(0x0020, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("E") PORT_CODE(KEYCODE_E) - PORT_BIT(0x0040, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("F") PORT_CODE(KEYCODE_F) - PORT_BIT(0x0080, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("G") PORT_CODE(KEYCODE_G) - PORT_BIT(0x0100, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("H") PORT_CODE(KEYCODE_H) - PORT_BIT(0x0200, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("I") PORT_CODE(KEYCODE_I) - PORT_BIT(0x0400, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Lower Case") PORT_CODE(KEYCODE_LSHIFT) - PORT_BIT(0x0800, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME(". (multiply)") PORT_CODE(KEYCODE_STOP) - PORT_BIT(0x1000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Upper case") PORT_CODE(KEYCODE_RSHIFT) - /* hack to support my macintosh which does not differentiate the Right Shift key */ - /* PORT_BIT(0x1000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Upper case") PORT_CODE(KEYCODE_CAPSLOCK) */ - PORT_BIT(0x2000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Backspace") PORT_CODE(KEYCODE_BACKSPACE) - PORT_BIT(0x8000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Return") PORT_CODE(KEYCODE_ENTER) - - PORT_START("CFG") /* 10: pseudo-input port with config */ - PORT_DIPNAME( 0x0003, 0x0002, "RAM size") - PORT_DIPSETTING( 0x0000, "4kw" ) - PORT_DIPSETTING( 0x0001, "32kw") - PORT_DIPSETTING( 0x0002, "64kw") - PORT_DIPNAME( 0x0004, 0x0000, "Hardware multiply") - PORT_DIPSETTING( 0x0000, DEF_STR( Off ) ) - PORT_DIPSETTING( 0x0004, DEF_STR( On ) ) - PORT_DIPNAME( 0x0008, 0x0000, "Hardware divide") - PORT_DIPSETTING( 0x0000, DEF_STR( Off ) ) - PORT_DIPSETTING( 0x0008, DEF_STR( On ) ) - PORT_DIPNAME( 0x0010, 0x0000, "Type 20 sequence break system") - PORT_DIPSETTING( 0x0000, DEF_STR( Off ) ) - PORT_DIPSETTING( 0x0010, DEF_STR( On ) ) - PORT_DIPNAME( 0x0020, 0x0000, "Type 32 light pen") PORT_CODE(KEYCODE_ENTER_PAD) - PORT_DIPSETTING( 0x0000, DEF_STR( Off ) ) - PORT_DIPSETTING( 0x0020, DEF_STR( On ) ) - - PORT_START("LIGHTPEN") /* 11: pseudo-input port with lightpen status */ - PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("select larger light pen tip") PORT_CODE(KEYCODE_PLUS_PAD) - PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("select smaller light pen tip") PORT_CODE(KEYCODE_MINUS_PAD) - PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_BUTTON1) PORT_NAME("light pen down") - - PORT_START("LIGHTX") /* 12: lightpen - X AXIS */ - PORT_BIT( 0xff, 0x00, IPT_TRACKBALL_X) PORT_SENSITIVITY(100) PORT_KEYDELTA(0) PORT_PLAYER(1) PORT_RESET - - PORT_START("LIGHTY") /* 13: lightpen - Y AXIS */ - PORT_BIT( 0xff, 0x00, IPT_TRACKBALL_Y) PORT_SENSITIVITY(100) PORT_KEYDELTA(0) PORT_PLAYER(1) PORT_RESET -INPUT_PORTS_END - - -static const gfx_layout fontlayout = -{ - 6, 8, /* 6*8 characters */ - pdp1_charnum, /* 96+4 characters */ - 1, /* 1 bit per pixel */ - { 0 }, - { 0, 1, 2, 3, 4, 5, 6, 7 }, /* straightforward layout */ - { 0*8, 1*8, 2*8, 3*8, 4*8, 5*8, 6*8, 7*8 }, - 8*8 /* every char takes 8 consecutive bytes */ -}; - - -/* - The static palette only includes the pens for the control panel and - the typewriter, as the CRT palette is generated dynamically. - - The CRT palette defines various levels of intensity between white and - black. Grey levels follow an exponential law, so that decrementing the - color index periodically will simulate the remanence of a cathode ray tube. -*/ -static constexpr rgb_t pdp1_colors[] = -{ - {0x00, 0x00, 0x00 }, // black - {0xff, 0xff, 0xff }, // white - {0x00, 0xff, 0x00 }, // green - {0x00, 0x40, 0x00 }, // dark green - {0xff, 0x00, 0x00 }, // red - {0x80, 0x80, 0x80 } // light gray -}; - -static constexpr uint8_t pdp1_pens[] = -{ - pen_panel_bg, pen_panel_caption, - pen_typewriter_bg, pen_black, - pen_typewriter_bg, pen_red -}; - -static const uint8_t total_colors_needed = pen_crt_num_levels + sizeof(pdp1_colors) / 3; - -static GFXDECODE_START( gfx_pdp1 ) - GFXDECODE_ENTRY( "gfx1", 0, fontlayout, pen_crt_num_levels + sizeof(pdp1_colors) / 3, 3 ) -GFXDECODE_END - -/* Initialise the palette */ -void pdp1_state::pdp1_palette(palette_device &palette) const -{ - // rgb components for the two color emissions - constexpr double r1 = .1, g1 = .1, b1 = .924, r2 = .7, g2 = .7, b2 = .076; - // half period in seconds for the two color emissions - constexpr double half_period_1 = .05, half_period_2 = .20; - // refresh period in seconds - constexpr double update_period = 1./refresh_rate; - double decay_1, decay_2; - double cur_level_1, cur_level_2; - - // initialize CRT palette - - // compute the decay factor per refresh frame - decay_1 = pow(.5, update_period / half_period_1); - decay_2 = pow(.5, update_period / half_period_2); - - cur_level_1 = cur_level_2 = 255.; // start with maximum level - - for (int i = pen_crt_max_intensity; i>0; i--) - { - // compute the current color - int const r = int((r1*cur_level_1 + r2*cur_level_2) + .5); - int const g = int((g1*cur_level_1 + g2*cur_level_2) + .5); - int const b = int((b1*cur_level_1 + b2*cur_level_2) + .5); - // write color in palette - palette.set_indirect_color(i, rgb_t(r, g, b)); - // apply decay for next iteration - cur_level_1 *= decay_1; - cur_level_2 *= decay_2; - } - - palette.set_indirect_color(0, rgb_t(0, 0, 0)); - - // load static palette - for (int i = 0; i < 6; i++) - palette.set_indirect_color(pen_crt_num_levels + i, pdp1_colors[i]); - - // copy colortable to palette - for (int i = 0; i < total_colors_needed; i++) - palette.set_pen_indirect(i, i); - - // set up palette for text - for (int i = 0; i < 6; i++) - palette.set_pen_indirect(total_colors_needed + i, pdp1_pens[i]); -} - - -/* - pdp1 machine code - - includes emulation for I/O devices (with the IOT opcode) and control panel functions - - TODO: - * typewriter out should overwrite the typewriter buffer - * improve emulation of the internals of tape reader? - * improve puncher timing? -*/ - - -/* This flag makes the emulated pdp-1 trigger a sequence break request when a character has been -typed on the typewriter keyboard. It is useful in order to test sequence break, but we need -to emulate a connection box in which we can connect each wire to any interrupt line. Also, -we need to determine the exact relationship between the status register and the sequence break -system (both standard and type 20). */ -#define USE_SBS 0 - -#define LOG_IOT 0 -#define LOG_IOT_EXTRA 0 - -/* IOT completion may take much more than the 5us instruction time. A possible programming -error would be to execute an IOT before the last IOT of the same kind is over: such a thing -would confuse the targeted IO device, which might ignore the latter IOT, execute either -or both IOT incompletely, or screw up completely. I insist that such an error can be caused -by a pdp-1 programming error, even if there is no emulator error. */ -#define LOG_IOT_OVERLAP 0 - - -/* - devices which are known to generate a completion pulse (source: maintenance manual 9-??, - and 9-20, 9-21): - emulated: - * perforated tape reader - * perforated tape punch - * typewriter output - * CRT display - unemulated: - * card punch (pac: 43) - * line printer (lpr, lsp, but NOT lfb) - - This list should probably include additional optional devices (card reader comes to mind). -*/ - -/* IO status word */ - -/* defines for io_status bits */ -enum -{ - io_st_pen = 0400000, /* light pen: light has hit the pen */ - io_st_ptr = 0200000, /* perforated tape reader: reader buffer full */ - io_st_tyo = 0100000, /* typewriter out: device ready */ - io_st_tyi = 0040000, /* typewriter in: new character in buffer */ - io_st_ptp = 0020000 /* perforated tape punch: device ready */ -}; - - - - - - - -/* crt display timer */ - -/* light pen config */ - - - -#define PARALLEL_DRUM_WORD_TIME attotime::from_nsec(8500) -#define PARALLEL_DRUM_ROTATION_TIME attotime::from_nsec(8500*4096) - - -static pdp1_reset_param_t pdp1_reset_param = -{ - 0, /* extend mode support defined in input ports and pdp1_init_machine */ - 0, /* hardware multiply/divide support defined in input ports and pdp1_init_machine */ - 0 /* type 20 sequence break system support defined in input ports and pdp1_init_machine */ -}; - -void pdp1_state::machine_reset() -{ - int cfg = m_cfg->read(); - - pdp1_reset_param.extend_support = (cfg >> pdp1_config_extend_bit) & pdp1_config_extend_mask; - pdp1_reset_param.hw_mul_div = (cfg >> pdp1_config_hw_mul_div_bit) & pdp1_config_hw_mul_div_mask; - pdp1_reset_param.type_20_sbs = (cfg >> pdp1_config_type_20_sbs_bit) & pdp1_config_type_20_sbs_mask; - - /* reset device state */ - m_tape_reader->m_rcl = m_tape_reader->m_rc = 0; - m_io_status = io_st_tyo | io_st_ptp; - m_lightpen.active = m_lightpen.down = 0; - m_lightpen.x = m_lightpen.y = 0; - m_lightpen.radius = 10; /* ??? */ - pdp1_update_lightpen_state(&m_lightpen); -} - - -void pdp1_state::pdp1_machine_stop() -{ - /* the core will take care of freeing the timers, BUT we must set the variables - to NULL if we don't want to risk confusing the tape image init function */ - m_tape_reader->m_timer = m_tape_puncher->m_timer = m_typewriter->m_tyo_timer = m_dpy_timer = nullptr; -} - - -/* - driver init function - - Set up the pdp1_memory pointer, and generate font data. -*/ -void pdp1_state::machine_start() -{ - uint8_t *dst; - - static const unsigned char fontdata6x8[pdp1_fontdata_size] = - { /* ASCII characters */ - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x20,0x20,0x20,0x20,0x00,0x20,0x00, - 0x50,0x50,0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x50,0xf8,0x50,0xf8,0x50,0x00,0x00, - 0x20,0x70,0xc0,0x70,0x18,0xf0,0x20,0x00,0x40,0xa4,0x48,0x10,0x20,0x48,0x94,0x08, - 0x60,0x90,0xa0,0x40,0xa8,0x90,0x68,0x00,0x10,0x20,0x40,0x00,0x00,0x00,0x00,0x00, - 0x20,0x40,0x40,0x40,0x40,0x40,0x20,0x00,0x10,0x08,0x08,0x08,0x08,0x08,0x10,0x00, - 0x20,0xa8,0x70,0xf8,0x70,0xa8,0x20,0x00,0x00,0x20,0x20,0xf8,0x20,0x20,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x30,0x30,0x60,0x00,0x00,0x00,0xf8,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x30,0x30,0x00,0x00,0x08,0x10,0x20,0x40,0x80,0x00,0x00, - 0x70,0x88,0x88,0x88,0x88,0x88,0x70,0x00,0x10,0x30,0x10,0x10,0x10,0x10,0x10,0x00, - 0x70,0x88,0x08,0x10,0x20,0x40,0xf8,0x00,0x70,0x88,0x08,0x30,0x08,0x88,0x70,0x00, - 0x10,0x30,0x50,0x90,0xf8,0x10,0x10,0x00,0xf8,0x80,0xf0,0x08,0x08,0x88,0x70,0x00, - 0x70,0x80,0xf0,0x88,0x88,0x88,0x70,0x00,0xf8,0x08,0x08,0x10,0x20,0x20,0x20,0x00, - 0x70,0x88,0x88,0x70,0x88,0x88,0x70,0x00,0x70,0x88,0x88,0x88,0x78,0x08,0x70,0x00, - 0x00,0x00,0x30,0x30,0x00,0x30,0x30,0x00,0x00,0x00,0x30,0x30,0x00,0x30,0x30,0x60, - 0x10,0x20,0x40,0x80,0x40,0x20,0x10,0x00,0x00,0x00,0xf8,0x00,0xf8,0x00,0x00,0x00, - 0x40,0x20,0x10,0x08,0x10,0x20,0x40,0x00,0x70,0x88,0x08,0x10,0x20,0x00,0x20,0x00, - 0x70,0x88,0xb8,0xa8,0xb8,0x80,0x70,0x00,0x70,0x88,0x88,0xf8,0x88,0x88,0x88,0x00, - 0xf0,0x88,0x88,0xf0,0x88,0x88,0xf0,0x00,0x70,0x88,0x80,0x80,0x80,0x88,0x70,0x00, - 0xf0,0x88,0x88,0x88,0x88,0x88,0xf0,0x00,0xf8,0x80,0x80,0xf0,0x80,0x80,0xf8,0x00, - 0xf8,0x80,0x80,0xf0,0x80,0x80,0x80,0x00,0x70,0x88,0x80,0x98,0x88,0x88,0x70,0x00, - 0x88,0x88,0x88,0xf8,0x88,0x88,0x88,0x00,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x00, - 0x08,0x08,0x08,0x08,0x88,0x88,0x70,0x00,0x88,0x90,0xa0,0xc0,0xa0,0x90,0x88,0x00, - 0x80,0x80,0x80,0x80,0x80,0x80,0xf8,0x00,0x88,0xd8,0xa8,0x88,0x88,0x88,0x88,0x00, - 0x88,0xc8,0xa8,0x98,0x88,0x88,0x88,0x00,0x70,0x88,0x88,0x88,0x88,0x88,0x70,0x00, - 0xf0,0x88,0x88,0xf0,0x80,0x80,0x80,0x00,0x70,0x88,0x88,0x88,0x88,0x88,0x70,0x08, - 0xf0,0x88,0x88,0xf0,0x88,0x88,0x88,0x00,0x70,0x88,0x80,0x70,0x08,0x88,0x70,0x00, - 0xf8,0x20,0x20,0x20,0x20,0x20,0x20,0x00,0x88,0x88,0x88,0x88,0x88,0x88,0x70,0x00, - 0x88,0x88,0x88,0x88,0x88,0x50,0x20,0x00,0x88,0x88,0x88,0x88,0xa8,0xd8,0x88,0x00, - 0x88,0x50,0x20,0x20,0x20,0x50,0x88,0x00,0x88,0x88,0x88,0x50,0x20,0x20,0x20,0x00, - 0xf8,0x08,0x10,0x20,0x40,0x80,0xf8,0x00,0x30,0x20,0x20,0x20,0x20,0x20,0x30,0x00, - 0x40,0x40,0x20,0x20,0x10,0x10,0x08,0x08,0x30,0x10,0x10,0x10,0x10,0x10,0x30,0x00, - 0x20,0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfc, - 0x40,0x20,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x70,0x08,0x78,0x88,0x78,0x00, - 0x80,0x80,0xf0,0x88,0x88,0x88,0xf0,0x00,0x00,0x00,0x70,0x88,0x80,0x80,0x78,0x00, - 0x08,0x08,0x78,0x88,0x88,0x88,0x78,0x00,0x00,0x00,0x70,0x88,0xf8,0x80,0x78,0x00, - 0x18,0x20,0x70,0x20,0x20,0x20,0x20,0x00,0x00,0x00,0x78,0x88,0x88,0x78,0x08,0x70, - 0x80,0x80,0xf0,0x88,0x88,0x88,0x88,0x00,0x20,0x00,0x20,0x20,0x20,0x20,0x20,0x00, - 0x20,0x00,0x20,0x20,0x20,0x20,0x20,0xc0,0x80,0x80,0x90,0xa0,0xe0,0x90,0x88,0x00, - 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x00,0x00,0x00,0xf0,0xa8,0xa8,0xa8,0xa8,0x00, - 0x00,0x00,0xb0,0xc8,0x88,0x88,0x88,0x00,0x00,0x00,0x70,0x88,0x88,0x88,0x70,0x00, - 0x00,0x00,0xf0,0x88,0x88,0xf0,0x80,0x80,0x00,0x00,0x78,0x88,0x88,0x78,0x08,0x08, - 0x00,0x00,0xb0,0xc8,0x80,0x80,0x80,0x00,0x00,0x00,0x78,0x80,0x70,0x08,0xf0,0x00, - 0x20,0x20,0x70,0x20,0x20,0x20,0x18,0x00,0x00,0x00,0x88,0x88,0x88,0x98,0x68,0x00, - 0x00,0x00,0x88,0x88,0x88,0x50,0x20,0x00,0x00,0x00,0xa8,0xa8,0xa8,0xa8,0x50,0x00, - 0x00,0x00,0x88,0x50,0x20,0x50,0x88,0x00,0x00,0x00,0x88,0x88,0x88,0x78,0x08,0x70, - 0x00,0x00,0xf8,0x10,0x20,0x40,0xf8,0x00,0x08,0x10,0x10,0x20,0x10,0x10,0x08,0x00, - 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x40,0x20,0x20,0x10,0x20,0x20,0x40,0x00, - 0x00,0x68,0xb0,0x00,0x00,0x00,0x00,0x00,0x20,0x50,0x20,0x50,0xa8,0x50,0x00,0x00, - - /* non-spacing middle dot */ - 0x00, - 0x00, - 0x00, - 0x20, - 0x00, - 0x00, - 0x00, - 0x00, - /* non-spacing overstrike */ - 0x00, - 0x00, - 0x00, - 0x00, - 0xfc, - 0x00, - 0x00, - 0x00, - /* implies */ - 0x00, - 0x00, - 0x70, - 0x08, - 0x08, - 0x08, - 0x70, - 0x00, - /* or */ - 0x88, - 0x88, - 0x88, - 0x50, - 0x50, - 0x50, - 0x20, - 0x00, - /* and */ - 0x20, - 0x50, - 0x50, - 0x50, - 0x88, - 0x88, - 0x88, - 0x00, - /* up arrow */ - 0x20, - 0x70, - 0xa8, - 0x20, - 0x20, - 0x20, - 0x20, - 0x00, - /* right arrow */ - 0x00, - 0x20, - 0x10, - 0xf8, - 0x10, - 0x20, - 0x00, - 0x00, - /* multiply */ - 0x00, - 0x88, - 0x50, - 0x20, - 0x50, - 0x88, - 0x00, - 0x00, - }; - - /* set up our font */ - dst = memregion("gfx1")->base(); - memcpy(dst, fontdata6x8, pdp1_fontdata_size); - - machine().add_notifier(MACHINE_NOTIFY_EXIT, machine_notify_delegate(&pdp1_state::pdp1_machine_stop,this)); - - m_dpy_timer = timer_alloc(FUNC(pdp1_state::dpy_callback), this); -} - - -/* - perforated tape handling -*/ - -DEFINE_DEVICE_TYPE(PDP1_READTAPE, pdp1_readtape_image_device, "pdp1_readtape_image", "PDP-1 Tape Reader") - -pdp1_readtape_image_device::pdp1_readtape_image_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) - : paper_tape_reader_device(mconfig, PDP1_READTAPE, tag, owner, clock) - , m_maincpu(*this, "^maincpu") - , m_st_ptr(*this) - , m_timer(nullptr) -{ -} - -void pdp1_readtape_image_device::device_resolve_objects() -{ - m_st_ptr.resolve_safe(); -} - -void pdp1_readtape_image_device::device_start() -{ - m_timer = timer_alloc(FUNC(pdp1_readtape_image_device::reader_callback), this); - m_timer->adjust(attotime::zero, 0, attotime::from_hz(2500)); - m_timer->enable(0); -} - - -DEFINE_DEVICE_TYPE(PDP1_PUNCHTAPE, pdp1_punchtape_image_device, "pdp1_punchtape_image_device", "PDP-1 Tape Puncher") - -pdp1_punchtape_image_device::pdp1_punchtape_image_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) - : paper_tape_punch_device(mconfig, PDP1_PUNCHTAPE, tag, owner, clock) - , m_maincpu(*this, "^maincpu") - , m_st_ptp(*this) - , m_timer(nullptr) -{ -} - -void pdp1_punchtape_image_device::device_resolve_objects() -{ - m_st_ptp.resolve_safe(); -} - -void pdp1_punchtape_image_device::device_start() -{ - m_timer = timer_alloc(FUNC(pdp1_punchtape_image_device::puncher_callback), this); -} - - -DEFINE_DEVICE_TYPE(PDP1_TYPEWRITER, pdp1_typewriter_device, "pdp1_typewriter_image", "PDP-1 Typewriter") - -pdp1_typewriter_device::pdp1_typewriter_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) - : device_t(mconfig, PDP1_TYPEWRITER, tag, owner, clock) - , device_image_interface(mconfig, *this) - , m_maincpu(*this, "^maincpu") - , m_driver_state(*this, DEVICE_SELF_OWNER) - , m_twr(*this, "^TWR.%u", 0) - , m_st_tyo(*this) - , m_st_tyi(*this) - , m_tyo_timer(nullptr) -{ -} - -void pdp1_typewriter_device::device_resolve_objects() -{ - m_st_tyo.resolve_safe(); - m_st_tyi.resolve_safe(); -} - -void pdp1_typewriter_device::device_start() -{ - m_tyo_timer = timer_alloc(FUNC(pdp1_typewriter_device::tyo_callback), this); - - m_color = m_pos = m_case_shift = 0; -} - - -DEFINE_DEVICE_TYPE(PDP1_CYLINDER, pdp1_cylinder_image_device, "pdp1_cylinder_image", "PDP-1 Cylinder") - -pdp1_cylinder_image_device::pdp1_cylinder_image_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) - : device_t(mconfig, PDP1_CYLINDER, tag, owner, clock) - , device_image_interface(mconfig, *this) - , m_maincpu(*this, "^maincpu") -{ -} - -void pdp1_cylinder_image_device::device_start() -{ -} - -/* - Open a perforated tape image -*/ -image_init_result pdp1_readtape_image_device::call_load() -{ - // start motor - m_motor_on = 1; - - /* restart reader IO when necessary */ - /* note that this function may be called before pdp1_init_machine, therefore - before m_timer is allocated. It does not matter, as the clutch is never - down at power-up, but we must not call timer_enable with a nullptr parameter! */ - - if (m_timer) - { - if (m_motor_on && m_rcl) - { - m_timer->enable(1); - } - else - { - m_timer->enable(0); - } - } - - return image_init_result::PASS; -} - -void pdp1_readtape_image_device::call_unload() -{ - // stop motor - m_motor_on = 0; - - if (m_timer) - m_timer->enable(0); -} - -/* - Read a byte from perforated tape -*/ -int pdp1_readtape_image_device::tape_read(uint8_t *reply) -{ - if (is_loaded() && (fread(reply, 1) == 1)) - return 0; /* unit OK */ - else - return 1; /* unit not ready */ -} - - -/* - common code for tape read commands (RPA, RPB, and read-in mode) -*/ -void pdp1_readtape_image_device::begin_tape_read(int binary, int nac) -{ - m_rb = 0; - m_rcl = 1; - m_rc = (binary) ? 1 : 3; - m_rby = (binary) ? 1 : 0; - m_rcp = nac; - - if (LOG_IOT_OVERLAP) - { - if (m_timer->enable(0)) - logerror("Error: overlapped perforated tape reads (Read-in mode, RPA/RPB instruction)\n"); - } - /* set up delay if tape is advancing */ - if (m_motor_on && m_rcl) - { - /* delay is approximately 1/400s */ - m_timer->enable(1); - } - else - { - m_timer->enable(0); - } -} - -/* - timer callback to simulate reader IO -*/ -TIMER_CALLBACK_MEMBER(pdp1_readtape_image_device::reader_callback) -{ - if (m_rc) - { - uint8_t data; - int not_ready = tape_read(&data); - if (not_ready) - { - m_motor_on = 0; // let us stop the motor - } - else - { - if ((!m_rby) || (data & 0200)) - { - m_rb |= (m_rby) ? (data & 077) : data; - - if (m_rc != 3) - { - m_rb <<= 6; - } - - m_rc = (m_rc+1) & 3; - - if (m_rc == 0) - { // IO complete - m_rcl = 0; - if (m_rcp) - { - m_maincpu->set_state_int(PDP1_IO, m_rb); // transfer reader buffer to IO - m_maincpu->set_state_int(PDP1_IOS,1); - } - else - m_st_ptr(1); - } - } - } - } - - if (m_motor_on && m_rcl) - { - m_timer->enable(1); - } - else - { - m_timer->enable(0); - } -} - -/* - perforated tape reader iot callbacks -*/ - -/* - rpa iot callback - - op2: iot command operation (equivalent to mb & 077) - nac: nead a completion pulse - mb: contents of the MB register - io: pointer on the IO register - ac: contents of the AC register -*/ -/* - * Read Perforated Tape, Alphanumeric - * rpa Address 0001 - * - * This instruction reads one line of tape (all eight Channels) and transfers the resulting 8-bit code to - * the Reader Buffer. If bits 5 and 6 of the rpa function are both zero (720001), the contents of the - * Reader Buffer must be transferred to the IO Register by executing the rrb instruction. When the Reader - * Buffer has information ready to be transferred to the IO Register, Status Register Bit 1 is set to - * one. If bits 5 and 6 are different (730001 or 724001) the 8-bit code read from tape is automatically - * transferred to the IO Register via the Reader Buffer and appears as follows: - * - * IO Bits 10 11 12 13 14 15 16 17 - * TAPE CHANNELS 8 7 6 5 4 3 2 1 - */ -void pdp1_readtape_image_device::iot_rpa(int op2, int nac, int mb, int &io, int ac) -{ - if (LOG_IOT_EXTRA) - logerror("Warning, RPA instruction not fully emulated: mb=0%06o, (%s)\n", (unsigned) mb, machine().describe_context()); - - begin_tape_read(0, nac); -} - -/* - rpb iot callback -*/ -/* - * Read Perforated Tape, Binary rpb - * Address 0002 - * - * The instruction reads three lines of tape (six Channels per line) and assembles - * the resulting 18-bit word in the Reader Buffer. For a line to be recognized by - * this instruction Channel 8 must be punched (lines with Channel 8 not punched will - * be skipped over). Channel 7 is ignored. The instruction sub 5137, for example, - * appears on tape and is assembled by rpb as follows: - * - * Channel 8 7 6 5 4 | 3 2 1 - * Line 1 X X | X - * Line 2 X X X | X - * Line 3 X X X | X X X - * Reader Buffer 100 010 101 001 011 111 - * - * (Vertical dashed line indicates sprocket holes and the symbols "X" indicate holes - * punched in tape). - * - * If bits 5 and 6 of the rpb instruction are both zero (720002), the contents of - * the Reader Buffer must be transferred to the IO Register by executing - * a rrb instruction. When the Reader Buffer has information ready to be transferred - * to the IO Register, Status Register Bit 1 is set to one. If bits 5 and 6 are - * different (730002 or 724002) the 18-bit word read from tape is automatically - * transferred to the IO Register via the Reader Buffer. - * - * The rpb command pulse is also asserted for each word transfer in read-in mode. - */ -void pdp1_readtape_image_device::iot_rpb(int op2, int nac, int mb, int &io, int ac) -{ - if (LOG_IOT_EXTRA) - logerror("Warning, RPB instruction not fully emulated: mb=0%06o, (%s)\n", (unsigned) mb, machine().describe_context()); - - begin_tape_read(1, nac); -} - -/* - rrb iot callback -*/ -void pdp1_readtape_image_device::iot_rrb(int op2, int nac, int mb, int &io, int ac) -{ - if (LOG_IOT_EXTRA) - logerror("RRB instruction: mb=0%06o, (%s)\n", (unsigned) mb, machine().describe_context()); - - io = m_rb; - m_st_ptr(0); -} - - -image_init_result pdp1_punchtape_image_device::call_load() -{ - return image_init_result::PASS; -} - -void pdp1_punchtape_image_device::call_unload() -{ -} - -/* - Write a byte to perforated tape -*/ -void pdp1_punchtape_image_device::tape_write(uint8_t data) -{ - if (is_loaded()) - fwrite(&data, 1); -} - -/* - timer callback to generate punch completion pulse -*/ -TIMER_CALLBACK_MEMBER(pdp1_punchtape_image_device::puncher_callback) -{ - int nac = param; - m_st_ptp(1); - if (nac) - { - m_maincpu->set_state_int(PDP1_IOS,1); - } -} - -/* - perforated tape punch iot callbacks -*/ - -/* - ppa iot callback -*/ -/* - * Punch Perforated Tape, Alphanumeric - * ppa Address 0005 - * - * For each In-Out Transfer instruction one line of tape is punched. In-Out Register - * Bit 17 conditions Hole 1. Bit 16 conditions Hole 2, etc. Bit 10 conditions Hole 8 - */ -void pdp1_punchtape_image_device::iot_ppa(int op2, int nac, int mb, int &io, int ac) -{ - if (LOG_IOT_EXTRA) - logerror("PPA instruction: mb=0%06o, (%s)\n", (unsigned) mb, machine().describe_context()); - - tape_write(io & 0377); - m_st_ptp(0); - // delay is approximately 1/63.3 second - if (LOG_IOT_OVERLAP) - { - if (m_timer->enable(0)) - logerror("Error: overlapped PPA/PPB instructions: mb=0%06o, (%s)\n", (unsigned) mb, machine().describe_context()); - } - - m_timer->adjust(attotime::from_usec(15800), nac); -} - -/* - ppb iot callback -*/ -/* - * Punch Perforated Tape, Binary - * ppb Addres 0006 - * - * For each In-Out Transfer instruction one line of tape is punched. In-Out Register - * Bit 5 conditions Hole 1. Bit 4 conditions Hole 2, etc. Bit 0 conditions Hole 6. - * Hole 7 is left blank. Hole 8 is always punched in this mode. - */ -void pdp1_punchtape_image_device::iot_ppb(int op2, int nac, int mb, int &io, int ac) -{ - if (LOG_IOT_EXTRA) - logerror("PPB instruction: mb=0%06o, (%s)\n", (unsigned) mb, machine().describe_context()); - - tape_write((io >> 12) | 0200); - m_st_ptp(0); - /* delay is approximately 1/63.3 second */ - if (LOG_IOT_OVERLAP) - { - if (m_timer->enable(0)) - logerror("Error: overlapped PPA/PPB instructions: mb=0%06o, (%s)\n", (unsigned) mb, machine().describe_context()); - } - m_timer->adjust(attotime::from_usec(15800), nac); -} - - -/* - Typewriter handling - - The alphanumeric on-line typewriter is a standard device on pdp-1: it - can both handle keyboard input and print output text. -*/ - -/* - Open a file for typewriter output -*/ -image_init_result pdp1_typewriter_device::call_load() -{ - m_st_tyo(1); - - return image_init_result::PASS; -} - -void pdp1_typewriter_device::call_unload() -{ -} - -/* - Write a character to typewriter -*/ -void pdp1_typewriter_device::typewriter_out(uint8_t data) -{ - if (LOG_IOT_EXTRA) - logerror("typewriter output %o\n", data); - - drawchar(data); - if (is_loaded()) -#if 1 - fwrite(& data, 1); -#else - { - static const char ascii_table[2][64] = - { /* n-s = non-spacing */ - { /* lower case */ - ' ', '1', '2', '3', - '4', '5', '6', '7', - '8', '9', '*', '*', - '*', '*', '*', '*', - '0', '/', 's', 't', - 'u', 'v', 'w', 'x', - 'y', 'z', '*', ',', - '*',/*black*/ '*',/*red*/ '*',/*Tab*/ '*', - '\200',/*n-s middle dot*/'j', 'k', 'l', - 'm', 'n', 'o', 'p', - 'q', 'r', '*', '*', - '-', ')', '\201',/*n-s overstrike*/'(', - '*', 'a', 'b', 'c', - 'd', 'e', 'f', 'g', - 'h', 'i', '*',/*Lower Case*/ '.', - '*',/*Upper Case*/ '*',/*Backspace*/ '*', '*'/*Carriage Return*/ - }, - { /* upper case */ - ' ', '"', '\'', '~', - '\202',/*implies*/ '\203',/*or*/ '\204',/*and*/ '<', - '>', '\205',/*up arrow*/ '*', '*', - '*', '*', '*', '*', - '\206',/*right arrow*/'?', 'S', 'T', - 'U', 'V', 'W', 'X', - 'Y', 'Z', '*', '=', - '*',/*black*/ '*',/*red*/ '\t',/*Tab*/ '*', - '_',/*n-s???*/ 'J', 'K', 'L', - 'M', 'N', 'O', 'P', - 'Q', 'R', '*', '*', - '+', ']', '|',/*n-s???*/ '[', - '*', 'A', 'B', 'C', - 'D', 'E', 'F', 'G', - 'H', 'I', '*',/*Lower Case*/ '\207',/*multiply*/ - '*',/*Upper Case*/ '\b',/*Backspace*/ '*', '*'/*Carriage Return*/ - } - }; - - data &= 0x3f; - - switch (data) - { - case 034: - // Black: ignore - //color = color_typewriter_black; - { - static const char black[5] = { '\033', '[', '3', '0', 'm' }; - fwrite(black, sizeof(black)); - } - break; - - case 035: - // Red: ignore - //color = color_typewriter_red; - { - static const char red[5] = { '\033', '[', '3', '1', 'm' }; - fwrite(red, sizeof(red)); - } - break; - - case 072: - // Lower case - m_case_shift = 0; - break; - - case 074: - // Upper case - m_case_shift = 1; - break; - - case 077: - // Carriage Return - { - static const char line_end[2] = { '\r', '\n' }; - fwrite(line_end, sizeof(line_end)); - } - break; - - default: - // Any printable character... - - if ((data != 040) && (data != 056)) // 040 and 056 are non-spacing characters: don't try to print right now - /* print character (lookup ASCII equivalent in table) */ - fwrite(&ascii_table[m_case_shift][data], 1); - - break; - } - } -#endif -} - -/* - timer callback to generate typewriter completion pulse -*/ -TIMER_CALLBACK_MEMBER(pdp1_typewriter_device::tyo_callback) -{ - int nac = param; - m_st_tyo(1); - if (nac) - { - m_maincpu->set_state_int(PDP1_IOS,1); - } -} - -/* - tyo iot callback -*/ -void pdp1_typewriter_device::iot_tyo(int op2, int nac, int mb, int &io, int ac) -{ - if (LOG_IOT_EXTRA) - logerror("Warning, TYO instruction not fully emulated: mb=0%06o, (%s)\n", (unsigned) mb, machine().describe_context()); - - int ch = io & 077; - - typewriter_out(ch); - m_st_tyo(0); - - /* compute completion delay (source: maintenance manual 9-12, 9-13 and 9-14) */ - int delay; - switch (ch) - { - case 072: /* lower-case */ - case 074: /* upper-case */ - case 034: /* black */ - case 035: /* red */ - delay = 175; /* approximately 175ms (?) */ - break; - - case 077: /* carriage return */ - delay = 205; /* approximately 205ms (?) */ - break; - - default: - delay = 105; /* approximately 105ms */ - break; - } - if (LOG_IOT_OVERLAP) - { - if (m_tyo_timer->enable(0)) - logerror("Error: overlapped TYO instruction: mb=0%06o, (%s)\n", (unsigned) mb, machine().describe_context()); - } - - m_tyo_timer->adjust(attotime::from_msec(delay), nac); -} - -/* - tyi iot callback -*/ -/* When a typewriter key is struck, the code for the struck key is placed in the - * typewriter buffer, Program Flag 1 is set, and the type-in status bit is set to - * one. A program designed to accept typed-in data would periodically check - * Program Flag 1, and if found to be set, an In-Out Transfer Instruction with - * address 4 could be executed for the information to be transferred to the - * In-Out Register. This In-Out Transfer should not use the optional in-out wait. - * The information contained in the typewriter buffer is then transferred to the - * right six bits of the In-Out Register. The tyi instruction automatically - * clears the In-Out Register before transferring the information and also clears - * the type-in status bit. - */ -void pdp1_typewriter_device::iot_tyi(int op2, int nac, int mb, int &io, int ac) -{ - if (LOG_IOT_EXTRA) - logerror("Warning, TYI instruction not fully emulated: mb=0%06o, (%s)\n", (unsigned) mb, machine().describe_context()); - - io = m_tb; - if (! (m_driver_state->m_io_status & io_st_tyi)) - io |= 0100; - else - m_st_tyi(0); -} - - -/* - * PRECISION CRT DISPLAY (TYPE 30) - * - * This sixteen-inch cathode ray tube display is intended to be used as an on-line output device for the - * PDP-1. It is useful for high speed presentation of graphs, diagrams, drawings, and alphanumerical - * information. The unit is solid state, self-powered and completely buffered. It has magnetic focus and - * deflection. - * - * Display characteristics are as follows: - * - * Random point plotting - * Accuracy of points +/-3 per cent of raster size - * Raster size 9.25 by 9.25 inches - * 1024 by 1024 addressable locations - * Fixed origin at center of CRT - * Ones complement binary arithmetic - * Plots 20,000 points per second - * - * Resolution is such that 512 points along each axis are discernable on the face of the tube. - * - * One instruction is added to the PDP-1 with the installation of this display: - * - * Display One Point On CRT - * dpy Address 0007 - * - * This instruction clears the light pen status bit and displays one point using bits 0 through 9 of the - * AC to represent the (signed) X coordinate of the point and bits 0 through 9 of the IO as the (signed) - * Y coordinate. - * - * Many variations of the Type 30 Display are available. Some of these include hardware for line and - * curve generation. - */ - - -/* - timer callback to generate crt completion pulse -*/ -TIMER_CALLBACK_MEMBER(pdp1_state::dpy_callback) -{ - m_maincpu->set_state_int(PDP1_IOS,1); -} - - -/* - dpy iot callback - - Light on one pixel on CRT -*/ -void pdp1_state::iot_dpy(int op2, int nac, int mb, int &io, int ac) -{ - int x = ((ac+0400000) & 0777777) >> 8; - int y = ((io+0400000) & 0777777) >> 8; - pdp1_plot(x, y); - - /* light pen 32 support */ - m_io_status &= ~io_st_pen; - - if (m_lightpen.down && ((x-m_lightpen.x)*(x-m_lightpen.x)+(y-m_lightpen.y)*(y-m_lightpen.y) < m_lightpen.radius*m_lightpen.radius)) - { - m_io_status |= io_st_pen; - - m_maincpu->set_state_int(PDP1_PF3, 1); - } - - if (nac) - { - /* 50us delay */ - if (LOG_IOT_OVERLAP) - { - /* note that overlap detection is incomplete: it will only work if both DPY - instructions require a completion pulse */ - if (m_dpy_timer->enable(0)) - logerror("Error: overlapped DPY instruction: mb=0%06o, (%s)\n", (unsigned) mb, machine().describe_context()); - } - m_dpy_timer->adjust(attotime::from_usec(50)); - } -} - - - -/* - MIT parallel drum (variant of type 23) -*/ - -void pdp1_cylinder_image_device::set_il(int il) -{ - m_il = il; - - attotime il_phase = ((PARALLEL_DRUM_WORD_TIME * il) - m_rotation_timer->elapsed()); - if (il_phase < attotime::zero) - il_phase = il_phase + PARALLEL_DRUM_ROTATION_TIME; - m_il_timer->adjust(il_phase, 0, PARALLEL_DRUM_ROTATION_TIME); -} - -TIMER_CALLBACK_MEMBER(pdp1_cylinder_image_device::rotation_timer_callback) -{ -} - -TIMER_CALLBACK_MEMBER(pdp1_cylinder_image_device::il_timer_callback) -{ - if (m_dba) - { - /* set break request and status bit 5 */ - /* ... */ - } -} - -void pdp1_cylinder_image_device::parallel_drum_init() -{ - m_rotation_timer = timer_alloc(FUNC(pdp1_cylinder_image_device::rotation_timer_callback), this); - m_rotation_timer->adjust(PARALLEL_DRUM_ROTATION_TIME, 0, PARALLEL_DRUM_ROTATION_TIME); - - m_il_timer = timer_alloc(FUNC(pdp1_cylinder_image_device::il_timer_callback), this); - set_il(0); -} - -/* - Open a file for drum -*/ -image_init_result pdp1_cylinder_image_device::call_load() -{ - return image_init_result::PASS; -} - -void pdp1_cylinder_image_device::call_unload() -{ -} - -void pdp1_cylinder_image_device::iot_dia(int op2, int nac, int mb, int &io, int ac) -{ - m_wfb = (io & 0370000) >> 12; - set_il(io & 0007777); - - m_dba = 0; /* right? */ -} - -void pdp1_cylinder_image_device::iot_dba(int op2, int nac, int mb, int &io, int ac) -{ - m_wfb = (io & 0370000) >> 12; - set_il(io & 0007777); - - m_dba = 1; -} - -/* - Read a word from drum -*/ -uint32_t pdp1_cylinder_image_device::drum_read(int field, int position) -{ - int offset = (field*4096+position)*3; - uint8_t buf[3]; - - if (is_loaded() && (!fseek(offset, SEEK_SET)) && (fread(buf, 3) == 3)) - return ((buf[0] << 16) | (buf[1] << 8) | buf[2]) & 0777777; - - return 0; -} - -/* - Write a word to drum -*/ -void pdp1_cylinder_image_device::drum_write(int field, int position, uint32_t data) -{ - int offset = (field*4096+position)*3; - uint8_t buf[3]; - - if (is_loaded()) - { - buf[0] = data >> 16; - buf[1] = data >> 8; - buf[2] = data; - - fseek(offset, SEEK_SET); - fwrite(buf, 3); - } -} - -void pdp1_cylinder_image_device::iot_dcc(int op2, int nac, int mb, int &io, int ac) -{ - m_rfb = (io & 0370000) >> 12; - m_wc = - (io & 0007777); - - m_wcl = ac & 0177777/*0007777???*/; - - m_dba = 0; /* right? */ - /* clear status bit 5... */ - - /* do transfer */ - attotime delay = m_il_timer->remaining(); - int dc = m_il; - do - { - if ((m_wfb >= 1) && (m_wfb <= 22)) - { - drum_write(m_wfb-1, dc, (signed)m_maincpu->space(AS_PROGRAM).read_dword(m_wcl)); - } - - if ((m_rfb >= 1) && (m_rfb <= 22)) - { - m_maincpu->space(AS_PROGRAM).write_dword(m_wcl, drum_read(m_rfb-1, dc)); - } - - m_wc = (m_wc+1) & 07777; - m_wcl = (m_wcl+1) & 0177777/*0007777???*/; - dc = (dc+1) & 07777; - if (m_wc) - delay = delay + PARALLEL_DRUM_WORD_TIME; - } while (m_wc); - m_maincpu->adjust_icount(-m_maincpu->attotime_to_cycles(delay)); - /* if no error, skip */ - m_maincpu->set_state_int(PDP1_PC, m_maincpu->state_int(PDP1_PC)+1); -} - -void pdp1_cylinder_image_device::iot_dra(int op2, int nac, int mb, int &io, int ac) -{ - io = (m_rotation_timer->elapsed() * - (ATTOSECONDS_PER_SECOND / (PARALLEL_DRUM_WORD_TIME.as_attoseconds()))).seconds() & 0007777; - - /* set parity error and timing error... */ -} - - - -/* - iot 11 callback - - Read state of Spacewar! controllers - - Not documented, except a few comments in the Spacewar! source code: - it should leave the control word in the io as follows. - high order 4 bits, rotate ccw, rotate cw, (both mean hyperspace) - fire rocket, and fire torpedo. low order 4 bits, same for - other ship. routine is entered by jsp cwg. -*/ -void pdp1_state::iot_011(int op2, int nac, int mb, int &io, int ac) -{ - int key_state = m_spacewar->read(); - int reply; - - - reply = 0; - - if (key_state & ROTATE_RIGHT_PLAYER2) - reply |= 0400000; - if (key_state & ROTATE_LEFT_PLAYER2) - reply |= 0200000; - if (key_state & THRUST_PLAYER2) - reply |= 0100000; - if (key_state & FIRE_PLAYER2) - reply |= 0040000; - if (key_state & HSPACE_PLAYER2) - reply |= 0600000; - - if (key_state & ROTATE_RIGHT_PLAYER1) - reply |= 010; - if (key_state & ROTATE_LEFT_PLAYER1) - reply |= 004; - if (key_state & THRUST_PLAYER1) - reply |= 002; - if (key_state & FIRE_PLAYER1) - reply |= 001; - if (key_state & HSPACE_PLAYER1) - reply |= 014; - - io = reply; -} - - -/* - cks iot callback - - check IO status -*/ -void pdp1_state::iot_cks(int op2, int nac, int mb, int &io, int ac) -{ - if (LOG_IOT_EXTRA) - logerror("CKS instruction: mb=0%06o, (%s)\n", (unsigned) mb, machine().describe_context()); - - io = m_io_status; -} - -template -WRITE_LINE_MEMBER(pdp1_state::io_status_w) -{ - if (state) - m_io_status |= Mask; - else - m_io_status &= ~Mask; - - if (USE_SBS && Mask == io_st_tyi) - m_maincpu->set_input_line(0, state ? ASSERT_LINE : CLEAR_LINE); /* PDP1 - interrupt it, baby */ -} - - -/* - callback which is called when Start Clear is pulsed - - IO devices should reset -*/ -void pdp1_state::io_start_clear() -{ - m_tape_reader->m_rcl = m_tape_reader->m_rc = 0; - if (m_tape_reader->m_timer) - m_tape_reader->m_timer->enable(0); - - if (m_tape_puncher->m_timer) - m_tape_puncher->m_timer->enable(0); - - if (m_typewriter->m_tyo_timer) - m_typewriter->m_tyo_timer->enable(0); - - if (m_dpy_timer) - m_dpy_timer->enable(0); - - m_io_status = io_st_tyo | io_st_ptp; -} - - -/* - typewriter keyboard handler -*/ -void pdp1_typewriter_device::pdp1_keyboard() -{ - int i; - int j; - - int typewriter_keys[4]; - - int typewriter_transitions; - - - for (i=0; i<4; i++) - { - typewriter_keys[i] = m_twr[i]->read(); - } - - for (i=0; i<4; i++) - { - typewriter_transitions = typewriter_keys[i] & (~ m_old_typewriter_keys[i]); - if (typewriter_transitions) - { - for (j=0; (((typewriter_transitions >> j) & 1) == 0) /*&& (j<16)*/; j++) - ; - m_tb = (i << 4) + j; - m_st_tyi(1); - m_maincpu->set_state_int(PDP1_PF1, 1); - drawchar(m_tb); /* we want to echo input */ - break; - } - } - - for (i=0; i<4; i++) - m_old_typewriter_keys[i] = typewriter_keys[i]; -} - -void pdp1_state::pdp1_lightpen() -{ - int x_delta, y_delta; - int current_state = m_io_lightpen->read(); - - m_lightpen.active = (m_cfg->read() >> pdp1_config_lightpen_bit) & pdp1_config_lightpen_mask; - - /* update pen down state */ - m_lightpen.down = m_lightpen.active && (current_state & pdp1_lightpen_down); - - /* update size of pen tip hole */ - if ((current_state & ~m_old_lightpen) & pdp1_lightpen_smaller) - { - m_lightpen.radius --; - if (m_lightpen.radius < 0) - m_lightpen.radius = 0; - } - if ((current_state & ~m_old_lightpen) & pdp1_lightpen_larger) - { - m_lightpen.radius ++; - if (m_lightpen.radius > 32) - m_lightpen.radius = 32; - } - - m_old_lightpen = current_state; - - /* update pen position */ - x_delta = m_lightx->read(); - y_delta = m_lighty->read(); - - if (x_delta >= 0x80) - x_delta -= 0x100; - if (y_delta >= 0x80) - y_delta -= 256; - - m_lightpen.x += x_delta; - m_lightpen.y += y_delta; - - if (m_lightpen.x < 0) - m_lightpen.x = 0; - if (m_lightpen.x > 1023) - m_lightpen.x = 1023; - if (m_lightpen.y < 0) - m_lightpen.y = 0; - if (m_lightpen.y > 1023) - m_lightpen.y = 1023; - - pdp1_update_lightpen_state(&m_lightpen); -} - -/* - Not a real interrupt - just handle keyboard input -*/ -INTERRUPT_GEN_MEMBER(pdp1_state::pdp1_interrupt) -{ - int control_keys; - int tw_keys; - int ta_keys; - - int control_transitions; - int tw_transitions; - int ta_transitions; - - - m_maincpu->set_state_int(PDP1_SS, m_sense->read()); - - /* read new state of control keys */ - control_keys = m_csw->read(); - - if (control_keys & pdp1_control) - { - /* compute transitions */ - control_transitions = control_keys & (~ m_old_control_keys); - - if (control_transitions & pdp1_extend) - { - m_maincpu->set_state_int(PDP1_EXTEND_SW, ! m_maincpu->state_int(PDP1_EXTEND_SW)); - } - if (control_transitions & pdp1_start_nobrk) - { - m_maincpu->pulse_start_clear(); /* pulse Start Clear line */ - m_maincpu->set_state_int(PDP1_EXD, m_maincpu->state_int(PDP1_EXTEND_SW)); - m_maincpu->set_state_int(PDP1_SBM, (uint64_t)0); - m_maincpu->set_state_int(PDP1_OV, (uint64_t)0); - m_maincpu->set_state_int(PDP1_PC, m_maincpu->state_int(PDP1_TA)); - m_maincpu->set_state_int(PDP1_RUN, 1); - } - if (control_transitions & pdp1_start_brk) - { - m_maincpu->pulse_start_clear(); /* pulse Start Clear line */ - m_maincpu->set_state_int(PDP1_EXD, m_maincpu->state_int(PDP1_EXTEND_SW)); - m_maincpu->set_state_int(PDP1_SBM, 1); - m_maincpu->set_state_int(PDP1_OV, (uint64_t)0); - m_maincpu->set_state_int(PDP1_PC, m_maincpu->state_int(PDP1_TA)); - m_maincpu->set_state_int(PDP1_RUN, 1); - } - if (control_transitions & pdp1_stop) - { - m_maincpu->set_state_int(PDP1_RUN, (uint64_t)0); - m_maincpu->set_state_int(PDP1_RIM, (uint64_t)0); /* bug : we stop after reading an even-numbered word - (i.e. data), whereas a real pdp-1 stops after reading - an odd-numbered word (i.e. dio instruciton) */ - } - if (control_transitions & pdp1_continue) - { - m_maincpu->set_state_int(PDP1_RUN, 1); - } - if (control_transitions & pdp1_examine) - { - m_maincpu->pulse_start_clear(); /* pulse Start Clear line */ - m_maincpu->set_state_int(PDP1_PC, m_maincpu->state_int(PDP1_TA)); - m_maincpu->set_state_int(PDP1_MA, m_maincpu->state_int(PDP1_PC)); - m_maincpu->set_state_int(PDP1_IR, pdp1_device::LAC); /* this instruction is actually executed */ - - m_maincpu->set_state_int(PDP1_MB, (signed)m_maincpu->space(AS_PROGRAM).read_dword(PDP1_MA)); - m_maincpu->set_state_int(PDP1_AC, m_maincpu->state_int(PDP1_MB)); - } - if (control_transitions & pdp1_deposit) - { - m_maincpu->pulse_start_clear(); /* pulse Start Clear line */ - m_maincpu->set_state_int(PDP1_PC, m_maincpu->state_int(PDP1_TA)); - m_maincpu->set_state_int(PDP1_MA, m_maincpu->state_int(PDP1_PC)); - m_maincpu->set_state_int(PDP1_AC, m_maincpu->state_int(PDP1_TW)); - m_maincpu->set_state_int(PDP1_IR, pdp1_device::DAC); /* this instruction is actually executed */ - - m_maincpu->set_state_int(PDP1_MB, m_maincpu->state_int(PDP1_AC)); - m_maincpu->space(AS_PROGRAM).write_dword(m_maincpu->state_int(PDP1_MA), m_maincpu->state_int(PDP1_MB)); - } - if (control_transitions & pdp1_read_in) - { /* set cpu to read instructions from perforated tape */ - m_maincpu->pulse_start_clear(); /* pulse Start Clear line */ - m_maincpu->set_state_int(PDP1_PC, ( m_maincpu->state_int(PDP1_TA) & 0170000) - | (m_maincpu->state_int(PDP1_PC) & 0007777)); /* transfer ETA to EPC */ - /*m_maincpu->set_state_int(PDP1_MA, m_maincpu->state_int(PDP1_PC));*/ - m_maincpu->set_state_int(PDP1_EXD, m_maincpu->state_int(PDP1_EXTEND_SW)); - m_maincpu->set_state_int(PDP1_OV, (uint64_t)0); /* right??? */ - m_maincpu->set_state_int(PDP1_RUN, (uint64_t)0); - m_maincpu->set_state_int(PDP1_RIM, 1); - } - if (control_transitions & pdp1_reader) - { - } - if (control_transitions & pdp1_tape_feed) - { - } - if (control_transitions & pdp1_single_step) - { - m_maincpu->set_state_int(PDP1_SNGL_STEP, ! m_maincpu->state_int(PDP1_SNGL_STEP)); - } - if (control_transitions & pdp1_single_inst) - { - m_maincpu->set_state_int(PDP1_SNGL_INST, ! m_maincpu->state_int(PDP1_SNGL_INST)); - } - - /* remember new state of control keys */ - m_old_control_keys = control_keys; - - - /* handle test word keys */ - tw_keys = (m_twdmsb->read() << 16) | m_twdlsb->read(); - - /* compute transitions */ - tw_transitions = tw_keys & (~ m_old_tw_keys); - - if (tw_transitions) - m_maincpu->set_state_int(PDP1_TW, m_maincpu->state_int(PDP1_TW) ^ tw_transitions); - - /* remember new state of test word keys */ - m_old_tw_keys = tw_keys; - - - /* handle address keys */ - ta_keys = m_tstadd->read(); - - /* compute transitions */ - ta_transitions = ta_keys & (~ m_old_ta_keys); - - if (ta_transitions) - m_maincpu->set_state_int(PDP1_TA, m_maincpu->state_int(PDP1_TA) ^ ta_transitions); - - /* remember new state of test word keys */ - m_old_ta_keys = ta_keys; - - } - else - { - m_old_control_keys = 0; - m_old_tw_keys = 0; - m_old_ta_keys = 0; - - m_typewriter->pdp1_keyboard(); - } - - pdp1_lightpen(); -} - - -void pdp1_state::pdp1(machine_config &config) -{ - /* basic machine hardware */ - /* PDP1 CPU @ 200 kHz (no master clock, but the instruction and memory rate is 200 kHz) */ - PDP1(config, m_maincpu, 1000000); /* the CPU core uses microsecond counts */ - m_maincpu->set_reset_param(&pdp1_reset_param); - m_maincpu->set_addrmap(AS_PROGRAM, &pdp1_state::pdp1_map); - m_maincpu->set_vblank_int("screen", FUNC(pdp1_state::pdp1_interrupt)); /* dummy interrupt: handles input */ - /* external iot handlers. 00, 50 to 56 and 74 are internal to the cpu core. */ - /* I put a ? when the source is the handbook, since a) I have used the maintenance manual - as the primary source (as it goes more into details) b) the handbook and the maintenance - manual occasionally contradict each other. */ - /* (iot) rpa rpb tyo tyi ppa ppb dpy */ - /* spacewar */ - /* lag glf?/jsp? gpl?/gpr?/gcf? */ - /* rrb rcb? rcc? cks mcs mes mel */ - /* cad? rac? rbc? pac lpr/lfb/lsp swc/sci/sdf?/shr? scv? */ - /* (dsc) (asc) (isb) (cac) (lsm) (esm) (cbs) */ - /* icv? dia dba dcc dra mri|rlc? mrf/inr?/ccr? */ - /* mcb|dur? mwc|mtf? mrc|sfc?... msm|cgo? (eem/lem) mic muf */ - m_maincpu->set_iot_callback<001>(m_tape_reader, FUNC(pdp1_readtape_image_device::iot_rpa)); - m_maincpu->set_iot_callback<002>(m_tape_reader, FUNC(pdp1_readtape_image_device::iot_rpb)); - m_maincpu->set_iot_callback<003>(m_typewriter, FUNC(pdp1_typewriter_device::iot_tyo)); - m_maincpu->set_iot_callback<004>(m_typewriter, FUNC(pdp1_typewriter_device::iot_tyi)); - m_maincpu->set_iot_callback<005>(m_tape_puncher, FUNC(pdp1_punchtape_image_device::iot_ppa)); - m_maincpu->set_iot_callback<006>(m_tape_puncher, FUNC(pdp1_punchtape_image_device::iot_ppb)); - m_maincpu->set_iot_callback<007>(FUNC(pdp1_state::iot_dpy)); - m_maincpu->set_iot_callback<011>(FUNC(pdp1_state::iot_011)); - m_maincpu->set_iot_callback<030>(m_tape_reader, FUNC(pdp1_readtape_image_device::iot_rrb)); - m_maincpu->set_iot_callback<033>(FUNC(pdp1_state::iot_cks)); - /* dia, dba, dcc, dra are documented in MIT PDP-1 COMPUTER MODIFICATION - BULLETIN no. 2 (drumInstrWriteup.bin/drumInstrWriteup.txt), and are - similar to IOT documented in Parallel Drum Type 23 Instruction Manual. */ - m_maincpu->set_iot_callback<061>(m_parallel_drum, FUNC(pdp1_cylinder_image_device::iot_dia)); - m_maincpu->set_iot_callback<062>(m_parallel_drum, FUNC(pdp1_cylinder_image_device::iot_dba)); - m_maincpu->set_iot_callback<063>(m_parallel_drum, FUNC(pdp1_cylinder_image_device::iot_dcc)); - m_maincpu->set_iot_callback<064>(m_parallel_drum, FUNC(pdp1_cylinder_image_device::iot_dra)); - m_maincpu->set_io_sc_callback(FUNC(pdp1_state::io_start_clear)); - - /* video hardware (includes the control panel and typewriter output) */ - screen_device &screen(SCREEN(config, "screen", SCREEN_TYPE_RASTER)); - screen.set_refresh_hz(refresh_rate); - screen.set_vblank_time(ATTOSECONDS_IN_USEC(2500)); /* not accurate */ - screen.set_size(virtual_width, virtual_height); - screen.set_visarea(0, virtual_width-1, 0, virtual_height-1); - screen.set_screen_update(FUNC(pdp1_state::screen_update_pdp1)); - screen.screen_vblank().set(FUNC(pdp1_state::screen_vblank_pdp1)); - screen.set_palette(m_palette); - - CRT(config, m_crt, 0); - m_crt->set_num_levels(pen_crt_num_levels); - m_crt->set_offsets(crt_window_offset_x, crt_window_offset_y); - m_crt->set_size(crt_window_width, crt_window_height); - - PDP1_READTAPE(config, m_tape_reader); - m_tape_reader->st_ptr().set(FUNC(pdp1_state::io_status_w)); - - PDP1_PUNCHTAPE(config, m_tape_puncher); - m_tape_puncher->st_ptp().set(FUNC(pdp1_state::io_status_w)); - - PDP1_TYPEWRITER(config, m_typewriter); - m_typewriter->st_tyo().set(FUNC(pdp1_state::io_status_w)); - m_typewriter->st_tyi().set(FUNC(pdp1_state::io_status_w)); - - PDP1_CYLINDER(config, m_parallel_drum); - - GFXDECODE(config, m_gfxdecode, m_palette, gfx_pdp1); - PALETTE(config, m_palette, FUNC(pdp1_state::pdp1_palette), total_colors_needed + std::size(pdp1_pens), total_colors_needed); - - SOFTWARE_LIST(config, "ptp_list").set_original("pdp1_ptp"); -} - -/* - pdp1 can address up to 65336 18 bit words when extended (4096 otherwise). -*/ -ROM_START(pdp1) - ROM_REGION(pdp1_fontdata_size, "gfx1", ROMREGION_ERASEFF) - /* space filled with our font */ -ROM_END - -/*************************************************************************** - - Game driver(s) - -***************************************************************************/ - -// YEAR NAME PARENT COMPAT MACHINE INPUT CLASS INIT COMPANY FULLNAME FLAGS -COMP( 1961, pdp1, 0, 0, pdp1, pdp1, pdp1_state, empty_init, "Digital Equipment Corporation", "PDP-1", MACHINE_NO_SOUND_HW ) diff --git a/src/mame/pdp1/pdp1.h b/src/mame/pdp1/pdp1.h deleted file mode 100644 index 203bee6e168..00000000000 --- a/src/mame/pdp1/pdp1.h +++ /dev/null @@ -1,484 +0,0 @@ -// license:GPL-2.0+ -// copyright-holders:Raphael Nabet -/***************************************************************************** - * - * includes/pdp1.h - * - ****************************************************************************/ -#ifndef MAME_PDP1_PDP1_H -#define MAME_PDP1_PDP1_H - -#pragma once - -#include "mitcrt.h" - -#include "cpu/pdp1/pdp1.h" -#include "imagedev/papertape.h" -#include "emupal.h" - -/* defines for each bit and mask in input port "CSW" */ -enum -{ - /* bit numbers */ - pdp1_control_bit = 0, - - pdp1_extend_bit = 1, - pdp1_start_nobrk_bit= 2, - pdp1_start_brk_bit = 3, - pdp1_stop_bit = 4, - pdp1_continue_bit = 5, - pdp1_examine_bit = 6, - pdp1_deposit_bit = 7, - pdp1_read_in_bit = 8, - pdp1_reader_bit = 9, - pdp1_tape_feed_bit = 10, - pdp1_single_step_bit= 11, - pdp1_single_inst_bit= 12, - - /* masks */ - pdp1_control = (1 << pdp1_control_bit), - pdp1_extend = (1 << pdp1_extend_bit), - pdp1_start_nobrk = (1 << pdp1_start_nobrk_bit), - pdp1_start_brk = (1 << pdp1_start_brk_bit), - pdp1_stop = (1 << pdp1_stop_bit), - pdp1_continue = (1 << pdp1_continue_bit), - pdp1_examine = (1 << pdp1_examine_bit), - pdp1_deposit = (1 << pdp1_deposit_bit), - pdp1_read_in = (1 << pdp1_read_in_bit), - pdp1_reader = (1 << pdp1_reader_bit), - pdp1_tape_feed = (1 << pdp1_tape_feed_bit), - pdp1_single_step = (1 << pdp1_single_step_bit), - pdp1_single_inst = (1 << pdp1_single_inst_bit) -}; - -/* defines for each bit in input port pdp1_spacewar_controllers*/ -#define ROTATE_LEFT_PLAYER1 0x01 -#define ROTATE_RIGHT_PLAYER1 0x02 -#define THRUST_PLAYER1 0x04 -#define FIRE_PLAYER1 0x08 -#define ROTATE_LEFT_PLAYER2 0x10 -#define ROTATE_RIGHT_PLAYER2 0x20 -#define THRUST_PLAYER2 0x40 -#define FIRE_PLAYER2 0x80 -#define HSPACE_PLAYER1 0x100 -#define HSPACE_PLAYER2 0x200 - -/* defines for each field in input port pdp1_config */ -enum -{ - pdp1_config_extend_bit = 0, - pdp1_config_extend_mask = 0x3, /* 2 bits */ - pdp1_config_hw_mul_div_bit = 2, - pdp1_config_hw_mul_div_mask = 0x1, - /*pdp1_config_hw_obsolete_bit = 3, - pdp1_config_hw_obsolete_mask = 0x1,*/ - pdp1_config_type_20_sbs_bit = 4, - pdp1_config_type_20_sbs_mask = 0x1, - pdp1_config_lightpen_bit = 5, - pdp1_config_lightpen_mask = 0x1 -}; - -/* defines for each field in input port pdp1_lightpen_state */ -enum -{ - pdp1_lightpen_down_bit = 0, - pdp1_lightpen_smaller_bit = 1, - pdp1_lightpen_larger_bit = 2, - - pdp1_lightpen_down = (1 << pdp1_lightpen_down_bit), - pdp1_lightpen_smaller = (1 << pdp1_lightpen_smaller_bit), - pdp1_lightpen_larger = (1 << pdp1_lightpen_larger_bit) -}; - -/* defines for our font */ -enum -{ - pdp1_charnum = /*104*/128, /* ASCII set + 8 special characters */ - /* for whatever reason, 104 breaks some characters */ - - pdp1_fontdata_size = 8 * pdp1_charnum -}; - -enum -{ - /* size and position of crt window */ - crt_window_width = 512, - crt_window_height = 512, - crt_window_offset_x = 0, - crt_window_offset_y = 0, - /* size and position of operator control panel window */ - panel_window_width = 384, - panel_window_height = 128, - panel_window_offset_x = crt_window_width, - panel_window_offset_y = 0, - /* size and position of typewriter window */ - typewriter_window_width = 640, - typewriter_window_height = 160, - typewriter_window_offset_x = 0, - typewriter_window_offset_y = crt_window_height -}; - -enum -{ - total_width = crt_window_width + panel_window_width, - total_height = crt_window_height + typewriter_window_height, - - /* respect 4:3 aspect ratio to keep pixels square */ - virtual_width_1 = ((total_width+3)/4)*4, - virtual_height_1 = ((total_height+2)/3)*3, - virtual_width_2 = virtual_height_1*4/3, - virtual_height_2 = virtual_width_1*3/4, - virtual_width = (virtual_width_1 > virtual_width_2) ? virtual_width_1 : virtual_width_2, - virtual_height = (virtual_height_1 > virtual_height_2) ? virtual_height_1 : virtual_height_2 -}; - -enum -{ /* refresh rate in Hz: can be changed at will */ - refresh_rate = 60 -}; - -/* Color codes */ -enum -{ - /* first pen_crt_num_levels colors used for CRT (with remanence) */ - pen_crt_num_levels = 69, - pen_crt_max_intensity = pen_crt_num_levels-1, - - /* next colors used for control panel and typewriter */ - pen_black = pen_crt_num_levels, - pen_white, - pen_green, - pen_dk_green, - pen_red, - pen_lt_gray, - - /* color constants for control panel */ - pen_panel_bg = pen_black, - pen_panel_caption = pen_white, - color_panel_caption = 0, - pen_switch_nut = pen_lt_gray, - pen_switch_button = pen_white, - pen_lit_lamp = pen_green, - pen_unlit_lamp = pen_dk_green, - - /* color constants for typewriter */ - pen_typewriter_bg = pen_white, - color_typewriter_black = 1, - color_typewriter_red = 2, - - /* color constants used for light pen */ - pen_lightpen_nonpressed = pen_red, - pen_lightpen_pressed = pen_green -}; - -class pdp1_state; - -// tape reader device -class pdp1_readtape_image_device : public paper_tape_reader_device -{ -public: - // construction/destruction - pdp1_readtape_image_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock = 0U); - virtual const char *image_interface() const noexcept override { return "pdp1_ptp"; } - - auto st_ptr() { return m_st_ptr.bind(); } - - void iot_rpa(int op2, int nac, int mb, int &io, int ac); - void iot_rpb(int op2, int nac, int mb, int &io, int ac); - void iot_rrb(int op2, int nac, int mb, int &io, int ac); - -protected: - // device-level overrides - virtual void device_resolve_objects() override; - virtual void device_start() override; - - // image-level overrides - virtual const char *file_extensions() const noexcept override { return "tap,rim"; } - - virtual image_init_result call_load() override; - virtual void call_unload() override; - -public: - TIMER_CALLBACK_MEMBER(reader_callback); - - int tape_read(uint8_t *reply); - void begin_tape_read(int binary, int nac); - - required_device m_maincpu; - - devcb_write_line m_st_ptr; - - int m_motor_on; // 1-bit reader motor on - - int m_rb; // 18-bit reader buffer - int m_rcl; // 1-bit reader clutch - int m_rc; // 2-bit reader counter - int m_rby; // 1-bit reader binary mode flip-flop - int m_rcp; // 1-bit reader "need a completion pulse" flip-flop - - emu_timer *m_timer; // timer to simulate reader timing -}; - - - -// tape puncher device -class pdp1_punchtape_image_device : public paper_tape_punch_device -{ -public: - // construction/destruction - pdp1_punchtape_image_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock = 0U); - - auto st_ptp() { return m_st_ptp.bind(); } - - void iot_ppa(int op2, int nac, int mb, int &io, int ac); - void iot_ppb(int op2, int nac, int mb, int &io, int ac); - -protected: - // device-level overrides - virtual void device_resolve_objects() override; - virtual void device_start() override; - - // image-level overrides - virtual bool is_readable() const noexcept override { return false; } - virtual bool is_writeable() const noexcept override { return true; } - virtual bool is_creatable() const noexcept override { return true; } - virtual bool is_reset_on_load() const noexcept override { return false; } - virtual const char *file_extensions() const noexcept override { return "tap,rim"; } - - virtual image_init_result call_load() override; - virtual void call_unload() override; - -public: - TIMER_CALLBACK_MEMBER(puncher_callback); - - void tape_write(uint8_t data); - - required_device m_maincpu; - - devcb_write_line m_st_ptp; - - emu_timer *m_timer; // timer to generate completion pulses -}; - - - -// typewriter device -class pdp1_typewriter_device : public device_t, - public device_image_interface -{ -public: - // construction/destruction - pdp1_typewriter_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock = 0U); - - auto st_tyo() { return m_st_tyo.bind(); } - auto st_tyi() { return m_st_tyi.bind(); } - - void iot_tyo(int op2, int nac, int mb, int &io, int ac); - void iot_tyi(int op2, int nac, int mb, int &io, int ac); - -protected: - // device-level overrides - virtual void device_resolve_objects() override; - virtual void device_start() override; - - // image-level overrides - virtual bool is_readable() const noexcept override { return false; } - virtual bool is_writeable() const noexcept override { return true; } - virtual bool is_creatable() const noexcept override { return true; } - virtual bool is_reset_on_load() const noexcept override { return false; } - virtual bool support_command_line_image_creation() const noexcept override { return true; } - virtual const char *file_extensions() const noexcept override { return "typ"; } - virtual const char *image_type_name() const noexcept override { return "printout"; } - virtual const char *image_brief_type_name() const noexcept override { return "prin"; } - - virtual image_init_result call_load() override; - virtual void call_unload() override; - -public: - TIMER_CALLBACK_MEMBER(tyo_callback); - - void linefeed(); - void drawchar(int character); - void typewriter_out(uint8_t data); - - void pdp1_keyboard(); - - required_device m_maincpu; - required_device m_driver_state; - required_ioport_array<4> m_twr; - - devcb_write_line m_st_tyo; - devcb_write_line m_st_tyi; - - int m_tb; // typewriter buffer - - emu_timer *m_tyo_timer; // timer to generate completion pulses - - int m_old_typewriter_keys[4]; - int m_color; - bitmap_ind16 m_bitmap; - int m_pos; - int m_case_shift; -}; - -// MIT parallel drum (mostly similar to type 23) -class pdp1_cylinder_image_device : public device_t, - public device_image_interface -{ -public: - // construction/destruction - pdp1_cylinder_image_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock = 0U); - - void iot_dia(int op2, int nac, int mb, int &io, int ac); - void iot_dba(int op2, int nac, int mb, int &io, int ac); - void iot_dcc(int op2, int nac, int mb, int &io, int ac); - void iot_dra(int op2, int nac, int mb, int &io, int ac); - -protected: - // device-level overrides - virtual void device_start() override; - - // image-level overrides - virtual bool is_readable() const noexcept override { return true; } - virtual bool is_writeable() const noexcept override { return true; } - virtual bool is_creatable() const noexcept override { return true; } - virtual bool is_reset_on_load() const noexcept override { return false; } - virtual const char *file_extensions() const noexcept override { return "drm"; } - virtual const char *image_type_name() const noexcept override { return "cylinder"; } - virtual const char *image_brief_type_name() const noexcept override { return "cyln"; } - - - virtual image_init_result call_load() override; - virtual void call_unload() override; - -public: - void set_il(int il); - TIMER_CALLBACK_MEMBER(rotation_timer_callback); - TIMER_CALLBACK_MEMBER(il_timer_callback); - [[maybe_unused]] void parallel_drum_init(); - uint32_t drum_read(int field, int position); - void drum_write(int field, int position, uint32_t data); - - required_device m_maincpu; - - int m_il = 0; // initial location (12-bit) - int m_wc = 0; // word counter (12-bit) - int m_wcl = 0; // word core location counter (16-bit) - int m_rfb = 0; // read field buffer (5-bit) - int m_wfb = 0; // write field buffer (5-bit) - - int m_dba = 0; - - emu_timer *m_rotation_timer = nullptr;// timer called each time dc is 0 - emu_timer *m_il_timer = nullptr; // timer called each time dc is il -}; - - -struct lightpen_t -{ - char active; - char down; - short x, y; - short radius; -}; - - -class pdp1_state : public driver_device -{ -public: - pdp1_state(const machine_config &mconfig, device_type type, const char *tag) - : driver_device(mconfig, type, tag), - m_maincpu(*this, "maincpu"), - m_tape_reader(*this, "readt"), - m_tape_puncher(*this, "punch"), - m_typewriter(*this, "typewriter"), - m_parallel_drum(*this, "drum"), - m_dpy_timer(nullptr), - m_gfxdecode(*this, "gfxdecode"), - m_palette(*this, "palette"), - m_crt(*this, "crt"), - m_spacewar(*this, "SPACEWAR"), - m_csw(*this, "CSW"), - m_sense(*this, "SENSE"), - m_tstadd(*this, "TSTADD"), - m_twdmsb(*this, "TWDMSB"), - m_twdlsb(*this, "TWDLSB"), - m_cfg(*this, "CFG"), - m_io_lightpen(*this, "LIGHTPEN"), - m_lightx(*this, "LIGHTX"), - m_lighty(*this, "LIGHTY") - { } - - required_device m_maincpu; - required_device m_tape_reader; - required_device m_tape_puncher; - required_device m_typewriter; - required_device m_parallel_drum; - int m_io_status; - emu_timer *m_dpy_timer; - lightpen_t m_lightpen; - - virtual void machine_start() override; - virtual void machine_reset() override; - virtual void video_start() override; - void pdp1_palette(palette_device &palette) const; - uint32_t screen_update_pdp1(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect); - DECLARE_WRITE_LINE_MEMBER(screen_vblank_pdp1); - INTERRUPT_GEN_MEMBER(pdp1_interrupt); - TIMER_CALLBACK_MEMBER(dpy_callback); - void pdp1_machine_stop(); - inline void pdp1_plot_pixel(bitmap_ind16 &bitmap, int x, int y, uint32_t color); - void pdp1_plot(int x, int y); - void pdp1_draw_led(bitmap_ind16 &bitmap, int x, int y, int state); - void pdp1_draw_multipleled(bitmap_ind16 &bitmap, int x, int y, int value, int nb_bits); - void pdp1_draw_switch(bitmap_ind16 &bitmap, int x, int y, int state); - void pdp1_draw_multipleswitch(bitmap_ind16 &bitmap, int x, int y, int value, int nb_bits); - void pdp1_draw_char(bitmap_ind16 &bitmap, char character, int x, int y, int color); - void pdp1_draw_string(bitmap_ind16 &bitmap, const char *buf, int x, int y, int color); - void pdp1_draw_panel_backdrop(bitmap_ind16 &bitmap); - void pdp1_draw_panel(bitmap_ind16 &bitmap); - void pdp1_update_lightpen_state(const lightpen_t *new_state); - void pdp1_draw_circle(bitmap_ind16 &bitmap, int x, int y, int radius, int color_); - void pdp1_erase_lightpen(bitmap_ind16 &bitmap); - void pdp1_draw_lightpen(bitmap_ind16 &bitmap); - void pdp1_lightpen(); - - template DECLARE_WRITE_LINE_MEMBER(io_status_w); - - void pdp1(machine_config &config); - void pdp1_map(address_map &map); -private: - void iot_dpy(int op2, int nac, int mb, int &io, int ac); - - void iot_011(int op2, int nac, int mb, int &io, int ac); - - void iot_cks(int op2, int nac, int mb, int &io, int ac); - - void io_start_clear(); - - pdp1_reset_param_t m_reset_param; - int m_old_lightpen; - int m_old_control_keys; - int m_old_tw_keys; - int m_old_ta_keys; - bitmap_ind16 m_panel_bitmap; - lightpen_t m_lightpen_state; - lightpen_t m_previous_lightpen_state; - -public: - required_device m_gfxdecode; - required_device m_palette; - required_device m_crt; - required_ioport m_spacewar; - required_ioport m_csw; - required_ioport m_sense; - required_ioport m_tstadd; - required_ioport m_twdmsb; - required_ioport m_twdlsb; - required_ioport m_cfg; - required_ioport m_io_lightpen; - required_ioport m_lightx; - required_ioport m_lighty; -}; - -#endif // MAME_PDP1_PDP1_H diff --git a/src/mame/pdp1/pdp1_v.cpp b/src/mame/pdp1/pdp1_v.cpp deleted file mode 100644 index a80f52f06e7..00000000000 --- a/src/mame/pdp1/pdp1_v.cpp +++ /dev/null @@ -1,593 +0,0 @@ -// license:GPL-2.0+ -// copyright-holders:Raphael Nabet -/* - video/pdp1.c - - PDP1 video emulation. - - We emulate three display devices: - * CRT screen - * control panel - * typewriter output - - For the actual emulation of these devices look at the machine/pdp1.c. This - file only includes the display routines. - - Raphael Nabet 2002-2004 - Based on earlier work by Chris Salomon -*/ - -#include "emu.h" -#include "cpu/pdp1/pdp1.h" -#include "pdp1.h" - -#include -#include - - - - -inline void pdp1_state::pdp1_plot_pixel(bitmap_ind16 &bitmap, int x, int y, uint32_t color) -{ - bitmap.pix(y, x) = color; -} - -/* - video init -*/ -void pdp1_state::video_start() -{ - m_typewriter->m_color = color_typewriter_black; - - /* alloc bitmaps for our private fun */ - m_panel_bitmap.allocate(panel_window_width, panel_window_height, BITMAP_FORMAT_IND16); - m_typewriter->m_bitmap.allocate(typewriter_window_width, typewriter_window_height, BITMAP_FORMAT_IND16); - - /* set up out bitmaps */ - pdp1_draw_panel_backdrop(m_panel_bitmap); - - const rectangle typewriter_bitmap_bounds(0, typewriter_window_width-1, 0, typewriter_window_height-1); - m_typewriter->m_bitmap.fill(pen_typewriter_bg, typewriter_bitmap_bounds); -} - - -WRITE_LINE_MEMBER(pdp1_state::screen_vblank_pdp1) -{ - // rising edge - if (state) - { - m_crt->eof(); - } -} - -/* - schedule a pixel to be plotted -*/ -void pdp1_state::pdp1_plot(int x, int y) -{ - /* compute pixel coordinates and plot */ - x = x*crt_window_width/01777; - y = y*crt_window_height/01777; - m_crt->plot(x, y); -} - - -/* - video_update_pdp1: effectively redraw the screen -*/ -uint32_t pdp1_state::screen_update_pdp1(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect) -{ - pdp1_erase_lightpen(bitmap); - m_crt->update(bitmap); - pdp1_draw_lightpen(bitmap); - - pdp1_draw_panel(m_panel_bitmap); - copybitmap(bitmap, m_panel_bitmap, 0, 0, panel_window_offset_x, panel_window_offset_y, cliprect); - - copybitmap(bitmap, m_typewriter->m_bitmap, 0, 0, typewriter_window_offset_x, typewriter_window_offset_y, cliprect); - return 0; -} - - - -/* - Operator control panel code -*/ - -enum -{ - x_panel_col1_offset = 8, - x_panel_col2_offset = x_panel_col1_offset+144+8, - x_panel_col3_offset = x_panel_col2_offset+96+8 -}; - -enum -{ - /* column 1: registers, test word, test address */ - y_panel_pc_offset = 0, - y_panel_ma_offset = y_panel_pc_offset+2*8, - y_panel_mb_offset = y_panel_ma_offset+2*8, - y_panel_ac_offset = y_panel_mb_offset+2*8, - y_panel_io_offset = y_panel_ac_offset+2*8, - y_panel_ta_offset = y_panel_io_offset+2*8, /* test address and extend switch */ - y_panel_tw_offset = y_panel_ta_offset+2*8, - - /* column 2: 1-bit indicators */ - y_panel_run_offset = 8, - y_panel_cyc_offset = y_panel_run_offset+8, - y_panel_defer_offset = y_panel_cyc_offset+8, - y_panel_hs_cyc_offset = y_panel_defer_offset+8, - y_panel_brk_ctr_1_offset = y_panel_hs_cyc_offset+8, - y_panel_brk_ctr_2_offset = y_panel_brk_ctr_1_offset+8, - y_panel_ov_offset = y_panel_brk_ctr_2_offset+8, - y_panel_rim_offset = y_panel_ov_offset+8, - y_panel_sbm_offset = y_panel_rim_offset+8, - y_panel_exd_offset = y_panel_sbm_offset+8, - y_panel_ioh_offset = y_panel_exd_offset+8, - y_panel_ioc_offset = y_panel_ioh_offset+8, - y_panel_ios_offset = y_panel_ioc_offset+8, - - /* column 3: power, single step, single inst, sense, flags, instr... */ - y_panel_power_offset = 8, - y_panel_sngl_step_offset = y_panel_power_offset+8, - y_panel_sngl_inst_offset = y_panel_sngl_step_offset+8, - y_panel_sep1_offset = y_panel_sngl_inst_offset+8, - y_panel_ss_offset = y_panel_sep1_offset+8, - y_panel_sep2_offset = y_panel_ss_offset+3*8, - y_panel_pf_offset = y_panel_sep2_offset+8, - y_panel_ir_offset = y_panel_pf_offset+2*8 -}; - -/* draw a small 8*8 LED (or is this a lamp? ) */ -void pdp1_state::pdp1_draw_led(bitmap_ind16 &bitmap, int x, int y, int state) -{ - int xx, yy; - - for (yy=1; yy<7; yy++) - for (xx=1; xx<7; xx++) - pdp1_plot_pixel(bitmap, x+xx, y+yy, state ? pen_lit_lamp : pen_unlit_lamp); -} - -/* draw nb_bits leds which represent nb_bits bits in value */ -void pdp1_state::pdp1_draw_multipleled(bitmap_ind16 &bitmap, int x, int y, int value, int nb_bits) -{ - while (nb_bits) - { - nb_bits--; - - pdp1_draw_led(bitmap, x, y, (value >> nb_bits) & 1); - - x += 8; - } -} - - -/* draw a small 8*8 switch */ -void pdp1_state::pdp1_draw_switch(bitmap_ind16 &bitmap, int x, int y, int state) -{ - int xx, yy; - int i; - - /* erase area */ - for (yy=0; yy<8; yy++) - for (xx=0; xx<8; xx++) - pdp1_plot_pixel(bitmap, x+xx, y+yy, pen_panel_bg); - - - /* draw nut (-> circle) */ - for (i=0; i<4;i++) - { - pdp1_plot_pixel(bitmap, x+2+i, y+1, pen_switch_nut); - pdp1_plot_pixel(bitmap, x+2+i, y+6, pen_switch_nut); - pdp1_plot_pixel(bitmap, x+1, y+2+i, pen_switch_nut); - pdp1_plot_pixel(bitmap, x+6, y+2+i, pen_switch_nut); - } - pdp1_plot_pixel(bitmap, x+2, y+2, pen_switch_nut); - pdp1_plot_pixel(bitmap, x+5, y+2, pen_switch_nut); - pdp1_plot_pixel(bitmap, x+2, y+5, pen_switch_nut); - pdp1_plot_pixel(bitmap, x+5, y+5, pen_switch_nut); - - /* draw button (->disc) */ - if (! state) - y += 4; - for (i=0; i<2;i++) - { - pdp1_plot_pixel(bitmap, x+3+i, y, pen_switch_button); - pdp1_plot_pixel(bitmap, x+3+i, y+3, pen_switch_button); - } - for (i=0; i<4;i++) - { - pdp1_plot_pixel(bitmap, x+2+i, y+1, pen_switch_button); - pdp1_plot_pixel(bitmap, x+2+i, y+2, pen_switch_button); - } -} - - -/* draw nb_bits switches which represent nb_bits bits in value */ -void pdp1_state::pdp1_draw_multipleswitch(bitmap_ind16 &bitmap, int x, int y, int value, int nb_bits) -{ - while (nb_bits) - { - nb_bits--; - - pdp1_draw_switch(bitmap, x, y, (value >> nb_bits) & 1); - - x += 8; - } -} - - -/* write a single char on screen */ -void pdp1_state::pdp1_draw_char(bitmap_ind16 &bitmap, char character, int x, int y, int color) -{ - m_gfxdecode->gfx(0)->transpen(bitmap,bitmap.cliprect(), character-32, color, 0, 0, - x+1, y, 0); -} - -/* write a string on screen */ -void pdp1_state::pdp1_draw_string(bitmap_ind16 &bitmap, const char *buf, int x, int y, int color) -{ - while (* buf) - { - pdp1_draw_char(bitmap, *buf, x, y, color); - - x += 8; - buf++; - } -} - - -/* - draw the operator control panel (fixed backdrop) -*/ -void pdp1_state::pdp1_draw_panel_backdrop(bitmap_ind16 &bitmap) -{ - /* fill with black */ - const rectangle panel_bitmap_bounds(0, panel_window_width-1, 0, panel_window_height-1); - m_panel_bitmap.fill(pen_panel_bg, panel_bitmap_bounds); - - /* column 1: registers, test word, test address */ - pdp1_draw_string(bitmap, "program counter", x_panel_col1_offset, y_panel_pc_offset, color_panel_caption); - pdp1_draw_string(bitmap, "memory address", x_panel_col1_offset, y_panel_ma_offset, color_panel_caption); - pdp1_draw_string(bitmap, "memory buffer", x_panel_col1_offset, y_panel_mb_offset, color_panel_caption); - pdp1_draw_string(bitmap, "accumulator", x_panel_col1_offset, y_panel_ac_offset, color_panel_caption); - pdp1_draw_string(bitmap, "in-out", x_panel_col1_offset, y_panel_io_offset, color_panel_caption); - pdp1_draw_string(bitmap, "extend address", x_panel_col1_offset, y_panel_ta_offset, color_panel_caption); - pdp1_draw_string(bitmap, "test word", x_panel_col1_offset, y_panel_tw_offset, color_panel_caption); - - /* column separator */ - bitmap.plot_box(x_panel_col2_offset-4, panel_window_offset_y+8, 1, 96, pen_panel_caption); - - /* column 2: 1-bit indicators */ - pdp1_draw_string(bitmap, "run", x_panel_col2_offset+8, y_panel_run_offset, color_panel_caption); - pdp1_draw_string(bitmap, "cycle", x_panel_col2_offset+8, y_panel_cyc_offset, color_panel_caption); - pdp1_draw_string(bitmap, "defer", x_panel_col2_offset+8, y_panel_defer_offset, color_panel_caption); - pdp1_draw_string(bitmap, "h. s. cycle", x_panel_col2_offset+8, y_panel_hs_cyc_offset, color_panel_caption); - pdp1_draw_string(bitmap, "brk. ctr. 1", x_panel_col2_offset+8, y_panel_brk_ctr_1_offset, color_panel_caption); - pdp1_draw_string(bitmap, "brk. ctr. 2", x_panel_col2_offset+8, y_panel_brk_ctr_2_offset, color_panel_caption); - pdp1_draw_string(bitmap, "overflow", x_panel_col2_offset+8, y_panel_ov_offset, color_panel_caption); - pdp1_draw_string(bitmap, "read in", x_panel_col2_offset+8, y_panel_rim_offset, color_panel_caption); - pdp1_draw_string(bitmap, "seq. break", x_panel_col2_offset+8, y_panel_sbm_offset, color_panel_caption); - pdp1_draw_string(bitmap, "extend", x_panel_col2_offset+8, y_panel_exd_offset, color_panel_caption); - pdp1_draw_string(bitmap, "i-o halt", x_panel_col2_offset+8, y_panel_ioh_offset, color_panel_caption); - pdp1_draw_string(bitmap, "i-o com'ds", x_panel_col2_offset+8, y_panel_ioc_offset, color_panel_caption); - pdp1_draw_string(bitmap, "i-o sync", x_panel_col2_offset+8, y_panel_ios_offset, color_panel_caption); - - /* column separator */ - bitmap.plot_box(x_panel_col3_offset-4, panel_window_offset_y+8, 1, 96, pen_panel_caption); - - /* column 3: power, single step, single inst, sense, flags, instr... */ - pdp1_draw_string(bitmap, "power", x_panel_col3_offset+16, y_panel_power_offset, color_panel_caption); - pdp1_draw_string(bitmap, "single step", x_panel_col3_offset+16, y_panel_sngl_step_offset, color_panel_caption); - pdp1_draw_string(bitmap, "single inst.", x_panel_col3_offset+16, y_panel_sngl_inst_offset, color_panel_caption); - /* separator */ - bitmap.plot_box(x_panel_col3_offset+8, y_panel_sep1_offset+4, 96, 1, pen_panel_caption); - pdp1_draw_string(bitmap, "sense switches", x_panel_col3_offset, y_panel_ss_offset, color_panel_caption); - /* separator */ - bitmap.plot_box(x_panel_col3_offset+8, y_panel_sep2_offset+4, 96, 1, pen_panel_caption); - pdp1_draw_string(bitmap, "program flags", x_panel_col3_offset, y_panel_pf_offset, color_panel_caption); - pdp1_draw_string(bitmap, "instruction", x_panel_col3_offset, y_panel_ir_offset, color_panel_caption); -} - -/* - draw the operator control panel (dynamic elements) -*/ -void pdp1_state::pdp1_draw_panel(bitmap_ind16 &bitmap) -{ - /* column 1: registers, test word, test address */ - pdp1_draw_multipleled(bitmap, x_panel_col1_offset+16, y_panel_pc_offset+8,m_maincpu->state_int(PDP1_PC), 16); - pdp1_draw_multipleled(bitmap, x_panel_col1_offset+16, y_panel_ma_offset+8,m_maincpu->state_int(PDP1_MA), 16); - pdp1_draw_multipleled(bitmap, x_panel_col1_offset, y_panel_mb_offset+8,m_maincpu->state_int(PDP1_MB), 18); - pdp1_draw_multipleled(bitmap, x_panel_col1_offset, y_panel_ac_offset+8,m_maincpu->state_int(PDP1_AC), 18); - pdp1_draw_multipleled(bitmap, x_panel_col1_offset, y_panel_io_offset+8,m_maincpu->state_int(PDP1_IO), 18); - pdp1_draw_switch(bitmap, x_panel_col1_offset, y_panel_ta_offset+8,m_maincpu->state_int(PDP1_EXTEND_SW)); - pdp1_draw_multipleswitch(bitmap, x_panel_col1_offset+16, y_panel_ta_offset+8,m_maincpu->state_int(PDP1_TA), 16); - pdp1_draw_multipleswitch(bitmap, x_panel_col1_offset, y_panel_tw_offset+8,m_maincpu->state_int(PDP1_TW), 18); - - /* column 2: 1-bit indicators */ - pdp1_draw_led(bitmap, x_panel_col2_offset, y_panel_run_offset,m_maincpu->state_int(PDP1_RUN)); - pdp1_draw_led(bitmap, x_panel_col2_offset, y_panel_cyc_offset,m_maincpu->state_int(PDP1_CYC)); - pdp1_draw_led(bitmap, x_panel_col2_offset, y_panel_defer_offset,m_maincpu->state_int(PDP1_DEFER)); - pdp1_draw_led(bitmap, x_panel_col2_offset, y_panel_hs_cyc_offset, 0); /* not emulated */ - pdp1_draw_led(bitmap, x_panel_col2_offset, y_panel_brk_ctr_1_offset,m_maincpu->state_int(PDP1_BRK_CTR) & 1); - pdp1_draw_led(bitmap, x_panel_col2_offset, y_panel_brk_ctr_2_offset,m_maincpu->state_int(PDP1_BRK_CTR) & 2); - pdp1_draw_led(bitmap, x_panel_col2_offset, y_panel_ov_offset,m_maincpu->state_int(PDP1_OV)); - pdp1_draw_led(bitmap, x_panel_col2_offset, y_panel_rim_offset,m_maincpu->state_int(PDP1_RIM)); - pdp1_draw_led(bitmap, x_panel_col2_offset, y_panel_sbm_offset,m_maincpu->state_int(PDP1_SBM)); - pdp1_draw_led(bitmap, x_panel_col2_offset, y_panel_exd_offset,m_maincpu->state_int(PDP1_EXD)); - pdp1_draw_led(bitmap, x_panel_col2_offset, y_panel_ioh_offset,m_maincpu->state_int(PDP1_IOH)); - pdp1_draw_led(bitmap, x_panel_col2_offset, y_panel_ioc_offset,m_maincpu->state_int(PDP1_IOC)); - pdp1_draw_led(bitmap, x_panel_col2_offset, y_panel_ios_offset,m_maincpu->state_int(PDP1_IOS)); - - /* column 3: power, single step, single inst, sense, flags, instr... */ - pdp1_draw_led(bitmap, x_panel_col3_offset, y_panel_power_offset, 1); /* always on */ - pdp1_draw_switch(bitmap, x_panel_col3_offset+8, y_panel_power_offset, 1); /* always on */ - pdp1_draw_led(bitmap, x_panel_col3_offset, y_panel_sngl_step_offset,m_maincpu->state_int(PDP1_SNGL_STEP)); - pdp1_draw_switch(bitmap, x_panel_col3_offset+8, y_panel_sngl_step_offset,m_maincpu->state_int(PDP1_SNGL_STEP)); - pdp1_draw_led(bitmap, x_panel_col3_offset, y_panel_sngl_inst_offset,m_maincpu->state_int(PDP1_SNGL_INST)); - pdp1_draw_switch(bitmap, x_panel_col3_offset+8, y_panel_sngl_inst_offset,m_maincpu->state_int(PDP1_SNGL_INST)); - pdp1_draw_multipleled(bitmap, x_panel_col3_offset, y_panel_ss_offset+8,m_maincpu->state_int(PDP1_SS), 6); - pdp1_draw_multipleswitch(bitmap, x_panel_col3_offset, y_panel_ss_offset+16,m_maincpu->state_int(PDP1_SS), 6); - pdp1_draw_multipleled(bitmap, x_panel_col3_offset, y_panel_pf_offset+8,m_maincpu->state_int(PDP1_PF), 6); - pdp1_draw_multipleled(bitmap, x_panel_col3_offset, y_panel_ir_offset+8,m_maincpu->state_int(PDP1_IR), 5); -} - - -/* - Typewriter code -*/ - - - - -enum -{ - typewriter_line_height = 8, - typewriter_write_offset_y = typewriter_window_height-typewriter_line_height, - typewriter_scroll_step = typewriter_line_height -}; - -enum -{ - tab_step = 8 -}; - - -void pdp1_typewriter_device::linefeed() -{ - uint8_t buf[typewriter_window_width]; - - assert(typewriter_window_width <= m_bitmap.width()); - assert(typewriter_window_height <= m_bitmap.height()); - for (int y=0; ym_palette->pens()); - } - - const rectangle typewriter_scroll_clear_window(0, typewriter_window_width-1, typewriter_window_height-typewriter_scroll_step, typewriter_window_height-1); - m_bitmap.fill(pen_typewriter_bg, typewriter_scroll_clear_window); -} - -void pdp1_typewriter_device::drawchar(int character) -{ - static const char ascii_table[2][64] = - { // n-s = non-spacing - { // lower case - ' ', '1', '2', '3', - '4', '5', '6', '7', - '8', '9', '*', '*', - '*', '*', '*', '*', - '0', '/', 's', 't', - 'u', 'v', 'w', 'x', - 'y', 'z', '*', ',', - '*',/*black*/ '*',/*red*/ '*',/*Tab*/ '*', - '\200',/*n-s middle dot*/'j', 'k', 'l', - 'm', 'n', 'o', 'p', - 'q', 'r', '*', '*', - '-', ')', '\201',/*n-s overstrike*/'(', - '*', 'a', 'b', 'c', - 'd', 'e', 'f', 'g', - 'h', 'i', '*',/*Lower Case*/ '.', - '*',/*Upper Case*/ '*',/*Backspace*/ '*', '*'/*Carriage Return*/ - }, - { // upper case - ' ', '"', '\'', '~', - '\202',/*implies*/ '\203',/*or*/ '\204',/*and*/ '<', - '>', '\205',/*up arrow*/ '*', '*', - '*', '*', '*', '*', - '\206',/*right arrow*/'?', 'S', 'T', - 'U', 'V', 'W', 'X', - 'Y', 'Z', '*', '=', - '*',/*black*/ '*',/*red*/ '*',/*Tab*/ '*', - '_',/*n-s???*/ 'J', 'K', 'L', - 'M', 'N', 'O', 'P', - 'Q', 'R', '*', '*', - '+', ']', '|',/*n-s???*/ '[', - '*', 'A', 'B', 'C', - 'D', 'E', 'F', 'G', - 'H', 'I', '*',/*Lower Case*/ '\207',/*multiply*/ - '*',/*Upper Case*/ '*',/*Backspace*/ '*', '*'/*Carriage Return*/ - } - }; - - - - character &= 0x3f; - - switch (character) - { - case 034: - // Black - m_color = color_typewriter_black; - break; - - case 035: - // Red - m_color = color_typewriter_red; - break; - - case 036: - // Tab - m_pos = m_pos + tab_step - (m_pos % tab_step); - break; - - case 072: - // Lower case - m_case_shift = 0; - break; - - case 074: - // Upper case - m_case_shift = 1; - break; - - case 075: - // Backspace - if (m_pos) - m_pos--; - break; - - case 077: - // Carriage Return - m_pos = 0; - linefeed(); - break; - - default: - // Any printable character... - - if (m_pos >= 80) - { // if past right border, wrap around. (Right???) - linefeed(); // next line - m_pos = 0; // return to start of line - } - - // print character (lookup ASCII equivalent in table) - m_driver_state->pdp1_draw_char(m_bitmap, ascii_table[m_case_shift][character], - 8*m_pos, typewriter_write_offset_y, - m_color); // print char - - if ((character!= 040) && (character!= 056)) // 040 and 056 are non-spacing characters - m_pos++; // step carriage forward - - break; - } -} - - - -/* - lightpen code -*/ - -void pdp1_state::pdp1_update_lightpen_state(const lightpen_t *new_state) -{ - m_lightpen_state = *new_state; -} - -#if 1 -void pdp1_state::pdp1_draw_circle(bitmap_ind16 &bitmap, int x, int y, int radius, int color_) -{ - int interval; - int a; - - x = x*crt_window_width/01777; - y = y*crt_window_width/01777; - radius = radius*crt_window_width/01777; - - interval = ceil(radius/sqrt(2.)); - - for (a=0; a<=interval; a++) - { - int b = sqrt((double)radius*radius-a*a) + .5; - - if ((x-a >= 0) && (y-b >= 0)) - pdp1_plot_pixel(bitmap, x-a, y-b, color_); - if ((x-a >= 0) && (y+b <= crt_window_height-1)) - pdp1_plot_pixel(bitmap, x-a, y+b, color_); - if ((x+a <= crt_window_width-1) && (y-b >= 0)) - pdp1_plot_pixel(bitmap, x+a, y-b, color_); - if ((x+a <= crt_window_width-1) && (y+b <= crt_window_height-1)) - pdp1_plot_pixel(bitmap, x+a, y+b, color_); - - if ((x-b >= 0) && (y-a >= 0)) - pdp1_plot_pixel(bitmap, x-b, y-a, color_); - if ((x-b >= 0) && (y+a <= crt_window_height-1)) - pdp1_plot_pixel(bitmap, x-b, y+a, color_); - if ((x+b <= crt_window_width-1) && (y-a >= 0)) - pdp1_plot_pixel(bitmap, x+b, y-a, color_); - if ((x+b <= crt_window_width-1) && (y+a <= crt_window_height-1)) - pdp1_plot_pixel(bitmap, x+b, y+a, color_); - } -} -#else -void pdp1_state::pdp1_draw_circle(bitmap_ind16 &bitmap, int x, int y, int radius, int color) -{ - float fx, fy; - float interval; - - - fx = (float)x*crt_window_width/01777; - fy = (float)y*crt_window_height/01777; - - interval = radius/sqrt(2.); - - for (x=/*ceil*/(fx-interval); x<=fx+interval; x++) - { - float dy = sqrt(radius*radius-(x-fx)*(x-fx)); - - if ((x >= 0) && (x <= crt_window_width-1) && (fy-dy >= 0)) - pdp1_plot_pixel(bitmap, x, fy-dy, color); - if ((x >= 0) && (x <= crt_window_width-1) && (y+dy <= crt_window_height-1)) - pdp1_plot_pixel(bitmap, x, fy+dy, color); - } - for (y=/*ceil*/(fy-interval); y<=fy+interval; y++) - { - float dx = sqrt(radius*radius-(y-fy)*(y-fy)); - - if ((fx-dx >= 0) && (y >= 0) && (y <= crt_window_height-1)) - pdp1_plot_pixel(bitmap, fx-dx, y, color); - if ((fx+dx <= crt_window_width-1) && (y >= 0) && (y <= crt_window_height-1)) - pdp1_plot_pixel(bitmap, fx+dx, y, color); - } -} -#endif - -void pdp1_state::pdp1_erase_lightpen(bitmap_ind16 &bitmap) -{ - if (m_previous_lightpen_state.active) - { -#if 0 - if (m_previous_lightpen_state.x>0) - pdp1_plot_pixel(bitmap, m_previous_lightpen_state.x/2-1, m_previous_lightpen_state.y/2, pen_black); - if (m_previous_lightpen_state.x<1023) - pdp1_plot_pixel(bitmap, m_previous_lightpen_state.x/2+1, m_previous_lightpen_state.y/2, pen_black); - if (m_previous_lightpen_state.y>0) - pdp1_plot_pixel(bitmap, m_previous_lightpen_state.x/2, m_previous_lightpen_state.y/2-1, pen_black); - if (m_previous_lightpen_state.y<1023) - pdp1_plot_pixel(bitmap, m_previous_lightpen_state.x/2, m_previous_lightpen_state.y/2+1, pen_black); -#endif - pdp1_draw_circle(bitmap, m_previous_lightpen_state.x, m_previous_lightpen_state.y, m_previous_lightpen_state.radius, pen_black); - } -} - -void pdp1_state::pdp1_draw_lightpen(bitmap_ind16 &bitmap) -{ - if (m_lightpen_state.active) - { - int color_ = m_lightpen_state.down ? pen_lightpen_pressed : pen_lightpen_nonpressed; -#if 0 - if (m_lightpen_state.x>0) - pdp1_plot_pixel(bitmap, m_lightpen_state.x/2-1, m_lightpen_state.y/2, color); - if (m_lightpen_state.x<1023) - pdp1_plot_pixel(bitmap, m_lightpen_state.x/2+1, m_lightpen_state.y/2, color); - if (m_lightpen_state.y>0) - pdp1_plot_pixel(bitmap, m_lightpen_state.x/2, m_lightpen_state.y/2-1, color); - if (m_lightpen_state.y<1023) - pdp1_plot_pixel(bitmap, m_lightpen_state.x/2, m_lightpen_state.y/2+1, color); -#endif - pdp1_draw_circle(bitmap, m_lightpen_state.x, m_lightpen_state.y, m_lightpen_state.radius, color_); - } - m_previous_lightpen_state = m_lightpen_state; -} -- cgit v1.2.3