diff options
-rw-r--r-- | src/devices/cpu/pdp1/pdp1.cpp | 90 | ||||
-rw-r--r-- | src/devices/cpu/pdp1/pdp1.h | 33 | ||||
-rw-r--r-- | src/devices/cpu/pdp1/pdp1dasm.cpp | 4 | ||||
-rw-r--r-- | src/devices/cpu/pdp8/pdp8.cpp | 2 | ||||
-rw-r--r-- | src/devices/cpu/pdp8/pdp8dasm.cpp | 4 | ||||
-rw-r--r-- | src/mame/drivers/pdp1.cpp | 709 | ||||
-rw-r--r-- | src/mame/includes/pdp1.h | 264 | ||||
-rw-r--r-- | src/mame/video/pdp1.cpp | 66 | ||||
-rw-r--r-- | src/tools/unidasm.cpp | 2 |
9 files changed, 583 insertions, 591 deletions
diff --git a/src/devices/cpu/pdp1/pdp1.cpp b/src/devices/cpu/pdp1/pdp1.cpp index a8704ad29d3..389c2fa75e3 100644 --- a/src/devices/cpu/pdp1/pdp1.cpp +++ b/src/devices/cpu/pdp1/pdp1.cpp @@ -348,8 +348,8 @@ #define LOG_EXTRA 0 #define LOG_IOT_EXTRA 0 -#define READ_PDP_18BIT(A) ((signed)m_program->read_dword((A)<<2)) -#define WRITE_PDP_18BIT(A,V) (m_program->write_dword((A)<<2,(V))) +#define READ_PDP_18BIT(A) ((signed)m_program->read_dword(A)) +#define WRITE_PDP_18BIT(A,V) (m_program->write_dword((A),(V))) #define PC m_pc @@ -378,12 +378,15 @@ #define PREVIOUS_PC ((PC & ADDRESS_EXTENSION_MASK) | ((PC-1) & BASE_ADDRESS_MASK)) -DEFINE_DEVICE_TYPE(PDP1, pdp1_device, "pdp1_cpu", "DEC PDP1") +DEFINE_DEVICE_TYPE(PDP1, pdp1_device, "pdp1_cpu", "DEC PDP-1 Central Processor") pdp1_device::pdp1_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : cpu_device(mconfig, PDP1, tag, owner, clock) - , m_program_config("program", ENDIANNESS_BIG, 32, 18, 0) + , m_program_config("program", ENDIANNESS_BIG, 32, 18, -2) // data is actually 18 bits wide + , m_extern_iot(64, iot_delegate(*this)) + , m_read_binary_word(*this) + , m_io_sc_callback(*this) { m_program_config.m_is_octal = true; } @@ -405,16 +408,9 @@ void pdp1_device::device_config_complete() // or initialize to defaults if none provided else { - memset(&read_binary_word, 0, sizeof(read_binary_word)); - memset(&io_sc_callback, 0, sizeof(io_sc_callback)); extend_support = 0; hw_mul_div = 0; type_20_sbs = 0; - - for (auto & elem : extern_iot) - { - memset(&elem, 0, sizeof(elem)); - } } } @@ -495,34 +491,6 @@ void pdp1_device::execute_set_input(int irqline, int state) } -static void null_iot(device_t *device, int op2, int nac, int mb, int *io, int ac) -{ - pdp1_device *pdp1 = dynamic_cast<pdp1_device*>(device); - - pdp1->pdp1_null_iot(op2, nac, mb, io, ac); -} - -static void lem_eem_iot(device_t *device, int op2, int nac, int mb, int *io, int ac) -{ - pdp1_device *pdp1 = dynamic_cast<pdp1_device*>(device); - - pdp1->pdp1_lem_eem_iot(op2, nac, mb, io, ac); -} - -static void sbs_iot(device_t *device, int op2, int nac, int mb, int *io, int ac) -{ - pdp1_device *pdp1 = dynamic_cast<pdp1_device*>(device); - - pdp1->pdp1_sbs_iot(op2, nac, mb, io, ac); -} - -static void type_20_sbs_iot(device_t *device, int op2, int nac, int mb, int *io, int ac) -{ - pdp1_device *pdp1 = dynamic_cast<pdp1_device*>(device); - - pdp1->pdp1_type_20_sbs_iot(op2, nac, mb, io, ac); -} - void pdp1_device::device_start() { int i; @@ -569,12 +537,12 @@ void pdp1_device::device_start() /* set up params and callbacks */ for (i=0; i<64; i++) { - m_extern_iot[i] = (extern_iot[i]) - ? extern_iot[i] - : null_iot; + m_extern_iot[i].resolve(); + if (m_extern_iot[i].isnull()) + m_extern_iot[i] = iot_delegate(*this, FUNC(pdp1_device::null_iot)); } - m_read_binary_word = read_binary_word; - m_io_sc_callback = io_sc_callback; + m_read_binary_word.resolve(); + m_io_sc_callback.resolve(); m_extend_support = extend_support; m_hw_mul_div = hw_mul_div; m_type_20_sbs = type_20_sbs; @@ -599,13 +567,13 @@ void pdp1_device::device_start() if (m_extend_support) { - m_extern_iot[074] = lem_eem_iot; + m_extern_iot[074] = iot_delegate(*this, FUNC(pdp1_device::lem_eem_iot)); } - m_extern_iot[054] = m_extern_iot[055] = m_extern_iot[056] = sbs_iot; + m_extern_iot[054] = m_extern_iot[055] = m_extern_iot[056] = iot_delegate(*this, FUNC(pdp1_device::sbs_iot)); if (m_type_20_sbs) { m_extern_iot[050] = m_extern_iot[051] = m_extern_iot[052] = m_extern_iot[053] - = type_20_sbs_iot; + = iot_delegate(*this, FUNC(pdp1_device::type_20_sbs_iot)); } state_add( PDP1_PC, "PC", m_pc).formatstr("%06O"); @@ -796,9 +764,6 @@ void pdp1_device::execute_run() { do { - debugger_instruction_hook(PC); - - /* ioh should be cleared at the end of the instruction cycle, and ios at the start of next instruction cycle, but who cares? */ if (m_ioh && m_ios) @@ -815,8 +780,8 @@ void pdp1_device::execute_run() { case 0: /* read first word as instruction */ - if (m_read_binary_word) - (*m_read_binary_word)(this); /* data will be transferred to IO register */ + if (!m_read_binary_word.isnull()) + m_read_binary_word(); /* data will be transferred to IO register */ m_rim_step = 1; m_ios = 0; break; @@ -860,8 +825,8 @@ void pdp1_device::execute_run() case 2: /* read second word as data */ - if (m_read_binary_word) - (*m_read_binary_word)(this); /* data will be transferred to IO register */ + if (!m_read_binary_word.isnull()) + m_read_binary_word(); /* data will be transferred to IO register */ m_rim_step = 3; m_ios = 0; break; @@ -940,6 +905,7 @@ void pdp1_device::execute_run() if (! m_cycle) { /* no instruction in progress: time to fetch a new instruction, I guess */ + debugger_instruction_hook(PC); MB = READ_PDP_18BIT(MA = PC); INCREMENT_PC; IR = MB >> 13; /* basic opcode */ @@ -1564,7 +1530,7 @@ void pdp1_device::execute_instruction() { /* IOT with IO wait */ if (m_ioc) { /* the iot command line is pulsed only if ioc is asserted */ - (*m_extern_iot[MB & 0000077])(this, MB & 0000077, (MB & 0004000) == 0, MB, &IO, AC); + m_extern_iot[MB & 0000077](MB & 0000077, (MB & 0004000) == 0, MB, IO, AC); m_ioh = 1; /* enable io wait */ @@ -1587,7 +1553,7 @@ void pdp1_device::execute_instruction() } else { /* IOT with no IO wait */ - (*m_extern_iot[MB & 0000077])(this, MB & 0000077, (MB & 0004000) != 0, MB, &IO, AC); + m_extern_iot[MB & 0000077](MB & 0000077, (MB & 0004000) != 0, MB, IO, AC); } break; case OPR: /* Operate Instruction Group */ @@ -1639,7 +1605,7 @@ no_fetch: /* Handle unimplemented IOT */ -void pdp1_device::pdp1_null_iot(int op2, int nac, int mb, int *io, int ac) +void pdp1_device::null_iot(int op2, int nac, int mb, int &io, int ac) { /* Note that the dummy IOT 0 is used to wait for the completion pulse generated by the a pending IOT (IOT with completion pulse but no IO wait) */ @@ -1661,7 +1627,7 @@ void pdp1_device::pdp1_null_iot(int op2, int nac, int mb, int *io, int ac) IOT 74: LEM/EEM */ -void pdp1_device::pdp1_lem_eem_iot(int op2, int nac, int mb, int *io, int ac) +void pdp1_device::lem_eem_iot(int op2, int nac, int mb, int &io, int ac) { if (! m_extend_support) /* extend mode supported? */ { @@ -1684,7 +1650,7 @@ void pdp1_device::pdp1_lem_eem_iot(int op2, int nac, int mb, int *io, int ac) IOT 55: esm IOT 56: cbs */ -void pdp1_device::pdp1_sbs_iot(int op2, int nac, int mb, int *io, int ac) +void pdp1_device::sbs_iot(int op2, int nac, int mb, int &io, int ac) { switch (op2) { @@ -1727,7 +1693,7 @@ void pdp1_device::pdp1_sbs_iot(int op2, int nac, int mb, int *io, int ac) IOT 52: isb IOT 53: cac */ -void pdp1_device::pdp1_type_20_sbs_iot(int op2, int nac, int mb, int *io, int ac) +void pdp1_device::type_20_sbs_iot(int op2, int nac, int mb, int &io, int ac) { int channel, mask; if (! m_type_20_sbs) /* type 20 sequence break system supported? */ @@ -1820,6 +1786,6 @@ void pdp1_device::pulse_start_clear() field_interrupt(); /* now, we kindly ask IO devices to reset, too */ - if (m_io_sc_callback) - (*m_io_sc_callback)(this); + if (!m_io_sc_callback.isnull()) + m_io_sc_callback(); } diff --git a/src/devices/cpu/pdp1/pdp1.h b/src/devices/cpu/pdp1/pdp1.h index 1c2d5c7eea3..570f8afab4d 100644 --- a/src/devices/cpu/pdp1/pdp1.h +++ b/src/devices/cpu/pdp1/pdp1.h @@ -20,20 +20,8 @@ enum }; -typedef void (*pdp1_extern_iot_func)(device_t *device, int op2, int nac, int mb, int *io, int ac); -typedef void (*pdp1_read_binary_word_func)(device_t *device); -typedef void (*pdp1_io_sc_func)(device_t *device); - - struct pdp1_reset_param_t { - /* callbacks for iot instructions (required for any I/O) */ - pdp1_extern_iot_func extern_iot[64]; - /* read a word from the perforated tape reader (required for read-in mode) */ - pdp1_read_binary_word_func read_binary_word; - /* callback called when sc is pulsed: IO devices should reset */ - pdp1_io_sc_func io_sc_callback; - /* 0: no extend support, 1: extend with 15-bit address, 2: extend with 16-bit address */ int extend_support; /* 1 to use hardware multiply/divide (MUL, DIV) instead of MUS, DIS */ @@ -49,6 +37,10 @@ class pdp1_device : public cpu_device , public pdp1_reset_param_t { public: + typedef device_delegate<void (int op2, int nac, int mb, int &io, int ac)> iot_delegate; + typedef device_delegate<void ()> read_binary_word_delegate; + typedef device_delegate<void ()> io_sc_delegate; + enum opcode { AND = 001, @@ -83,14 +75,17 @@ public: // construction/destruction pdp1_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); + template <int I, typename... T> void set_iot_callback(T &&... args) { m_extern_iot[I].set(std::forward<T>(args)...); } + template <typename... T> void set_read_binary_word(T &&... args) { m_read_binary_word.set(std::forward<T>(args)...); } + template <typename... T> void set_io_sc_callback(T &&... args) { m_io_sc_callback.set(std::forward<T>(args)...); } void set_reset_param(const pdp1_reset_param_t *param) { m_reset_param = param; } void pulse_start_clear(); void io_complete() { m_ios = 1; } - void pdp1_null_iot(int op2, int nac, int mb, int *io, int ac); - void pdp1_lem_eem_iot(int op2, int nac, int mb, int *io, int ac); - void pdp1_sbs_iot(int op2, int nac, int mb, int *io, int ac); - void pdp1_type_20_sbs_iot(int op2, int nac, int mb, int *io, int ac); + void null_iot(int op2, int nac, int mb, int &io, int ac); + void lem_eem_iot(int op2, int nac, int mb, int &io, int ac); + void sbs_iot(int op2, int nac, int mb, int &io, int ac); + void type_20_sbs_iot(int op2, int nac, int mb, int &io, int ac); protected: // device-level overrides @@ -167,11 +162,11 @@ private: int m_no_sequence_break; /* disable sequence break recognition for one cycle */ /* callbacks for iot instructions (required for any I/O) */ - pdp1_extern_iot_func m_extern_iot[64]; + std::vector<iot_delegate> m_extern_iot; /* read a word from the perforated tape reader (required for read-in mode) */ - pdp1_read_binary_word_func m_read_binary_word; + read_binary_word_delegate m_read_binary_word; /* callback called when sc is pulsed: IO devices should reset */ - pdp1_io_sc_func m_io_sc_callback; + io_sc_delegate m_io_sc_callback; /* 0: no extend support, 1: extend with 15-bit address, 2: extend with 16-bit address */ int m_extend_support; diff --git a/src/devices/cpu/pdp1/pdp1dasm.cpp b/src/devices/cpu/pdp1/pdp1dasm.cpp index 9b04c91ec87..0c3286a9257 100644 --- a/src/devices/cpu/pdp1/pdp1dasm.cpp +++ b/src/devices/cpu/pdp1/pdp1dasm.cpp @@ -19,7 +19,7 @@ inline void pdp1_disassembler::ea() u32 pdp1_disassembler::opcode_alignment() const { - return 4; + return 1; } offs_t pdp1_disassembler::disassemble(std::ostream &stream, offs_t pc, const data_buffer &opcodes, const data_buffer ¶ms) @@ -290,5 +290,5 @@ offs_t pdp1_disassembler::disassemble(std::ostream &stream, offs_t pc, const dat //etime = 5; break; } - return 4; + return 1; } diff --git a/src/devices/cpu/pdp8/pdp8.cpp b/src/devices/cpu/pdp8/pdp8.cpp index 3084c1bb29d..e8090c8dfde 100644 --- a/src/devices/cpu/pdp8/pdp8.cpp +++ b/src/devices/cpu/pdp8/pdp8.cpp @@ -51,7 +51,7 @@ DEFINE_DEVICE_TYPE(PDP8, pdp8_device, "pdp8_cpu", "DEC PDP8") pdp8_device::pdp8_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : cpu_device(mconfig, PDP8, tag, owner, clock), - m_program_config("program", ENDIANNESS_BIG, 12, 12), + m_program_config("program", ENDIANNESS_BIG, 12, 12, -1), m_pc(0), m_ac(0), m_mb(0), diff --git a/src/devices/cpu/pdp8/pdp8dasm.cpp b/src/devices/cpu/pdp8/pdp8dasm.cpp index 389cf11fda7..8c2e57573b5 100644 --- a/src/devices/cpu/pdp8/pdp8dasm.cpp +++ b/src/devices/cpu/pdp8/pdp8dasm.cpp @@ -11,7 +11,7 @@ u32 pdp8_disassembler::opcode_alignment() const { - return 2; + return 1; } offs_t pdp8_disassembler::disassemble(std::ostream &stream, offs_t pc, const data_buffer &opcodes, const data_buffer ¶ms) @@ -164,5 +164,5 @@ offs_t pdp8_disassembler::disassemble(std::ostream &stream, offs_t pc, const dat } } - return 2 | SUPPORTED; + return 1 | SUPPORTED | (opcode == 4 ? STEP_OVER : 0); } diff --git a/src/mame/drivers/pdp1.cpp b/src/mame/drivers/pdp1.cpp index 72861de561b..5be34e9984b 100644 --- a/src/mame/drivers/pdp1.cpp +++ b/src/mame/drivers/pdp1.cpp @@ -382,29 +382,6 @@ or both IOT incompletely, or screw up completely. I insist that such an error c by a pdp-1 programming error, even if there is no emulator error. */ #define LOG_IOT_OVERLAP 0 -static void pdp1_tape_read_binary(device_t *device); -static void pdp1_io_sc_callback(device_t *device); - -static void iot_rpa(device_t *device, int op2, int nac, int mb, int *io, int ac); -static void iot_rpb(device_t *device, int op2, int nac, int mb, int *io, int ac); -static void iot_rrb(device_t *device, int op2, int nac, int mb, int *io, int ac); -static void iot_ppa(device_t *device, int op2, int nac, int mb, int *io, int ac); -static void iot_ppb(device_t *device, int op2, int nac, int mb, int *io, int ac); - -static void iot_tyo(device_t *device, int op2, int nac, int mb, int *io, int ac); -static void iot_tyi(device_t *device, int op2, int nac, int mb, int *io, int ac); - -static void iot_dpy(device_t *device, int op2, int nac, int mb, int *io, int ac); - -static void iot_dia(device_t *device, int op2, int nac, int mb, int *io, int ac); -static void iot_dba(device_t *device, int op2, int nac, int mb, int *io, int ac); -static void iot_dcc(device_t *device, int op2, int nac, int mb, int *io, int ac); -static void iot_dra(device_t *device, int op2, int nac, int mb, int *io, int ac); - -static void iot_011(device_t *device, int op2, int nac, int mb, int *io, int ac); - -static void iot_cks(device_t *device, int op2, int nac, int mb, int *io, int ac); - /* devices which are known to generate a completion pulse (source: maintenance manual 9-??, @@ -451,33 +428,6 @@ enum static pdp1_reset_param_t pdp1_reset_param = { - { /* external iot handlers. NULL means that the iot is unimplemented, unless there are - parentheses around the iot name, in which case the iot is 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 occasionnally contradict each other. */ - /* 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. */ - /* (iot) rpa rpb tyo tyi ppa ppb dpy */ - nullptr, iot_rpa, iot_rpb, iot_tyo, iot_tyi, iot_ppa, iot_ppb, iot_dpy, - /* spacewar */ - nullptr, iot_011, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, - /* lag glf?/jsp? gpl?/gpr?/gcf? */ - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, - /* rrb rcb? rcc? cks mcs mes mel */ - iot_rrb, nullptr, nullptr, iot_cks, nullptr, nullptr, nullptr, nullptr, - /* cad? rac? rbc? pac lpr/lfb/lsp swc/sci/sdf?/shr? scv? */ - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, - /* (dsc) (asc) (isb) (cac) (lsm) (esm) (cbs) */ - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, - /* icv? dia dba dcc dra mri|rlc? mrf/inr?/ccr? */ - nullptr, iot_dia, iot_dba, iot_dcc, iot_dra, nullptr, nullptr, nullptr, - /* mcb|dur? mwc|mtf? mrc|sfc?... msm|cgo? (eem/lem) mic muf */ - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, - }, - pdp1_tape_read_binary, - pdp1_io_sc_callback, 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 */ @@ -492,7 +442,7 @@ void pdp1_state::machine_reset() 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.rcl = m_tape_reader.rc = 0; + 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; @@ -505,7 +455,7 @@ 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.timer = m_tape_puncher.timer = m_typewriter.tyo_timer = m_dpy_timer = nullptr; + m_tape_reader->m_timer = m_tape_puncher->m_timer = m_typewriter->m_tyo_timer = m_dpy_timer = nullptr; } @@ -649,12 +599,7 @@ void pdp1_state::machine_start() machine().add_notifier(MACHINE_NOTIFY_EXIT, machine_notify_delegate(&pdp1_state::pdp1_machine_stop,this)); - m_tape_reader.timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(pdp1_state::reader_callback),this)); - m_tape_puncher.timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(pdp1_state::puncher_callback),this)); - m_typewriter.tyo_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(pdp1_state::tyo_callback),this)); m_dpy_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(pdp1_state::dpy_callback),this)); - m_tape_reader.timer->adjust(attotime::zero, 0, attotime::from_hz(2500)); - m_tape_reader.timer->enable(0); } @@ -662,136 +607,85 @@ void pdp1_state::machine_start() perforated tape handling */ -class pdp1_readtape_image_device : public device_t, - public device_image_interface -{ -public: - // construction/destruction - pdp1_readtape_image_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); - - // image-level overrides - virtual iodevice_t image_type() const noexcept override { return IO_PUNCHTAPE; } - - virtual bool is_readable() const noexcept override { return true; } - virtual bool is_writeable() const noexcept override { return false; } - virtual bool is_creatable() const noexcept override { return false; } - virtual bool must_be_loaded() const noexcept override { return false; } - 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; - -protected: - // device-level overrides - virtual void device_start() override { } -}; - -DEFINE_DEVICE_TYPE(PDP1_READTAPE, pdp1_readtape_image_device, "pdp1_readtape_image", "PDP1 Tape Reader") +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) : device_t(mconfig, PDP1_READTAPE, tag, owner, clock) , device_image_interface(mconfig, *this) + , m_maincpu(*this, "^maincpu") + , m_st_ptr(*this) { } -class pdp1_punchtape_image_device : public device_t, - public device_image_interface +void pdp1_readtape_image_device::device_resolve_objects() { -public: - // construction/destruction - pdp1_punchtape_image_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); - - // image-level overrides - virtual iodevice_t image_type() const noexcept override { return IO_PUNCHTAPE; } - - 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 must_be_loaded() const noexcept override { return false; } - 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; - -protected: - // device-level overrides - virtual void device_start() override { } -}; + m_st_ptr.resolve_safe(); +} + +void pdp1_readtape_image_device::device_start() +{ + m_timer = machine().scheduler().timer_alloc(timer_expired_delegate(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", "PDP1 Tape Puncher") +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) : device_t(mconfig, PDP1_PUNCHTAPE, tag, owner, clock) , device_image_interface(mconfig, *this) + , m_maincpu(*this, "^maincpu") + , m_st_ptp(*this) { } +void pdp1_punchtape_image_device::device_resolve_objects() +{ + m_st_ptp.resolve_safe(); +} -class pdp1_printer_image_device : public device_t, - public device_image_interface +void pdp1_punchtape_image_device::device_start() { -public: - // construction/destruction - pdp1_printer_image_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); - - // image-level overrides - virtual iodevice_t image_type() const noexcept override { return IO_PRINTER; } - - 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 must_be_loaded() const noexcept override { return false; } - virtual bool is_reset_on_load() const noexcept override { return false; } - virtual const char *file_extensions() const noexcept override { return "typ"; } - - virtual image_init_result call_load() override; - virtual void call_unload() override; - -protected: - // device-level overrides - virtual void device_start() override { } -}; + m_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(pdp1_punchtape_image_device::puncher_callback),this)); +} -DEFINE_DEVICE_TYPE(PDP1_PRINTER, pdp1_printer_image_device, "pdp1_printer_image", "PDP1 Typewriter") -pdp1_printer_image_device::pdp1_printer_image_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) - : device_t(mconfig, PDP1_PRINTER, tag, owner, clock) +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) { } -class pdp1_cylinder_image_device : public device_t, - public device_image_interface +void pdp1_typewriter_device::device_resolve_objects() { -public: - // construction/destruction - pdp1_cylinder_image_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); - - // image-level overrides - virtual iodevice_t image_type() const noexcept override { return IO_CYLINDER; } - - 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 must_be_loaded() const noexcept override { return false; } - virtual bool is_reset_on_load() const noexcept override { return false; } - virtual const char *file_extensions() const noexcept override { return "drm"; } - - virtual image_init_result call_load() override; - virtual void call_unload() override; - -protected: - // device-level overrides - virtual void device_start() override { } -}; + m_st_tyo.resolve_safe(); + m_st_tyi.resolve_safe(); +} -DEFINE_DEVICE_TYPE(PDP1_CYLINDER, pdp1_cylinder_image_device, "pdp1_cylinder_image", "PDP1 Cylinder") +void pdp1_typewriter_device::device_start() +{ + m_tyo_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(pdp1_typewriter_device::tyo_callback),this)); +} + + +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() { } @@ -800,28 +694,23 @@ pdp1_cylinder_image_device::pdp1_cylinder_image_device(const machine_config &mco */ image_init_result pdp1_readtape_image_device::call_load() { - pdp1_state *state = machine().driver_data<pdp1_state>(); - - /* reader unit */ - state->m_tape_reader.fd = this; - - /* start motor */ - state->m_tape_reader.motor_on = 1; + // start motor + m_motor_on = 1; /* restart reader IO when necessary */ /* note that this function may be called before pdp1_init_machine, therefore - before state->m_tape_reader.timer is allocated. It does not matter, as the clutch is never + 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 (state->m_tape_reader.timer) + if (m_timer) { - if (state->m_tape_reader.motor_on && state->m_tape_reader.rcl) + if (m_motor_on && m_rcl) { - state->m_tape_reader.timer->enable(1); + m_timer->enable(1); } else { - state->m_tape_reader.timer->enable(0); + m_timer->enable(0); } } @@ -830,24 +719,19 @@ image_init_result pdp1_readtape_image_device::call_load() void pdp1_readtape_image_device::call_unload() { - pdp1_state *state = machine().driver_data<pdp1_state>(); - - /* reader unit */ - state->m_tape_reader.fd = nullptr; - - /* stop motor */ - state->m_tape_reader.motor_on = 0; + // stop motor + m_motor_on = 0; - if (state->m_tape_reader.timer) - state->m_tape_reader.timer->enable(0); + if (m_timer) + m_timer->enable(0); } /* Read a byte from perforated tape */ -int pdp1_state::tape_read(uint8_t *reply) +int pdp1_readtape_image_device::tape_read(uint8_t *reply) { - if (m_tape_reader.fd && (m_tape_reader.fd->fread(reply, 1) == 1)) + if (is_loaded() && (fread(reply, 1) == 1)) return 0; /* unit OK */ else return 1; /* unit not ready */ @@ -857,91 +741,88 @@ int pdp1_state::tape_read(uint8_t *reply) /* common code for tape read commands (RPA, RPB, and read-in mode) */ -void pdp1_state::begin_tape_read( int binary, int nac) +void pdp1_readtape_image_device::begin_tape_read(int binary, int nac) { - m_tape_reader.rb = 0; - m_tape_reader.rcl = 1; - m_tape_reader.rc = (binary) ? 1 : 3; - m_tape_reader.rby = (binary) ? 1 : 0; - m_tape_reader.rcp = 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_tape_reader.timer->enable(0)) + 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_tape_reader.motor_on && m_tape_reader.rcl) + if (m_motor_on && m_rcl) { /* delay is approximately 1/400s */ - m_tape_reader.timer->enable(1); + m_timer->enable(1); } else { - m_tape_reader.timer->enable(0); + m_timer->enable(0); } } /* timer callback to simulate reader IO */ -TIMER_CALLBACK_MEMBER(pdp1_state::reader_callback) +TIMER_CALLBACK_MEMBER(pdp1_readtape_image_device::reader_callback) { - int not_ready; - uint8_t data; - - if (m_tape_reader.rc) + if (m_rc) { - not_ready = tape_read(& data); + uint8_t data; + int not_ready = tape_read(&data); if (not_ready) { - m_tape_reader.motor_on = 0; /* let us stop the motor */ + m_motor_on = 0; // let us stop the motor } else { - if ((! m_tape_reader.rby) || (data & 0200)) + if ((!m_rby) || (data & 0200)) { - m_tape_reader.rb |= (m_tape_reader.rby) ? (data & 077) : data; + m_rb |= (m_rby) ? (data & 077) : data; - if (m_tape_reader.rc != 3) + if (m_rc != 3) { - m_tape_reader.rb <<= 6; + m_rb <<= 6; } - m_tape_reader.rc = (m_tape_reader.rc+1) & 3; + m_rc = (m_rc+1) & 3; - if (m_tape_reader.rc == 0) - { /* IO complete */ - m_tape_reader.rcl = 0; - if (m_tape_reader.rcp) + if (m_rc == 0) + { // IO complete + m_rcl = 0; + if (m_rcp) { - m_maincpu->set_state_int(PDP1_IO, m_tape_reader.rb); /* transfer reader buffer to IO */ + m_maincpu->set_state_int(PDP1_IO, m_rb); // transfer reader buffer to IO m_maincpu->set_state_int(PDP1_IOS,1); } else - m_io_status |= io_st_ptr; + m_st_ptr(1); } } } } - if (m_tape_reader.motor_on && m_tape_reader.rcl) + if (m_motor_on && m_rcl) { - m_tape_reader.timer->enable(1); + m_timer->enable(1); } else { - m_tape_reader.timer->enable(0); + m_timer->enable(0); } } /* Initiate read of a 18-bit word in binary format from tape (used in read-in mode) */ -void pdp1_tape_read_binary(device_t *device) +void pdp1_readtape_image_device::tape_read_binary() { - pdp1_state *state = device->machine().driver_data<pdp1_state>(); - state->begin_tape_read(1, 1); + begin_tape_read(1, 1); } /* @@ -971,13 +852,12 @@ void pdp1_tape_read_binary(device_t *device) * IO Bits 10 11 12 13 14 15 16 17 * TAPE CHANNELS 8 7 6 5 4 3 2 1 */ -static void iot_rpa(device_t *device, int op2, int nac, int mb, int *io, int ac) +void pdp1_readtape_image_device::iot_rpa(int op2, int nac, int mb, int &io, int ac) { - pdp1_state *state = device->machine().driver_data<pdp1_state>(); if (LOG_IOT_EXTRA) - device->logerror("Warning, RPA instruction not fully emulated: mb=0%06o, (%s)\n", (unsigned) mb, device->machine().describe_context()); + logerror("Warning, RPA instruction not fully emulated: mb=0%06o, (%s)\n", (unsigned) mb, machine().describe_context()); - state->begin_tape_read(0, nac); + begin_tape_read(0, nac); } /* @@ -1009,63 +889,52 @@ static void iot_rpa(device_t *device, int op2, int nac, int mb, int *io, int ac) * different (730002 or 724002) the 18-bit word read from tape is automatically * transferred to the IO Register via the Reader Buffer. */ -static void iot_rpb(device_t *device, int op2, int nac, int mb, int *io, int ac) +void pdp1_readtape_image_device::iot_rpb(int op2, int nac, int mb, int &io, int ac) { - pdp1_state *state = device->machine().driver_data<pdp1_state>(); if (LOG_IOT_EXTRA) - device->logerror("Warning, RPB instruction not fully emulated: mb=0%06o, (%s)\n", (unsigned) mb, device->machine().describe_context()); + logerror("Warning, RPB instruction not fully emulated: mb=0%06o, (%s)\n", (unsigned) mb, machine().describe_context()); - state->begin_tape_read(1, nac); + begin_tape_read(1, nac); } /* rrb iot callback */ -static void iot_rrb(device_t *device, int op2, int nac, int mb, int *io, int ac) +void pdp1_readtape_image_device::iot_rrb(int op2, int nac, int mb, int &io, int ac) { - pdp1_state *state = device->machine().driver_data<pdp1_state>(); if (LOG_IOT_EXTRA) - device->logerror("RRB instruction: mb=0%06o, (%s)\n", (unsigned) mb, device->machine().describe_context()); + logerror("RRB instruction: mb=0%06o, (%s)\n", (unsigned) mb, machine().describe_context()); - *io = state->m_tape_reader.rb; - state->m_io_status &= ~io_st_ptr; + io = m_rb; + m_st_ptr(0); } image_init_result pdp1_punchtape_image_device::call_load() { - pdp1_state *state = machine().driver_data<pdp1_state>(); - - /* punch unit */ - state->m_tape_puncher.fd = this; - return image_init_result::PASS; } void pdp1_punchtape_image_device::call_unload() { - pdp1_state *state = machine().driver_data<pdp1_state>(); - - /* punch unit */ - state->m_tape_puncher.fd = nullptr; } /* Write a byte to perforated tape */ -void pdp1_state::tape_write(uint8_t data) +void pdp1_punchtape_image_device::tape_write(uint8_t data) { - if (m_tape_puncher.fd) - m_tape_puncher.fd->fwrite(& data, 1); + if (is_loaded()) + fwrite(&data, 1); } /* timer callback to generate punch completion pulse */ -TIMER_CALLBACK_MEMBER(pdp1_state::puncher_callback) +TIMER_CALLBACK_MEMBER(pdp1_punchtape_image_device::puncher_callback) { int nac = param; - m_io_status |= io_st_ptp; + m_st_ptp(1); if (nac) { m_maincpu->set_state_int(PDP1_IOS,1); @@ -1086,22 +955,21 @@ TIMER_CALLBACK_MEMBER(pdp1_state::puncher_callback) * 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 */ -static void iot_ppa(device_t *device, int op2, int nac, int mb, int *io, int ac) +void pdp1_punchtape_image_device::iot_ppa(int op2, int nac, int mb, int &io, int ac) { - pdp1_state *state = device->machine().driver_data<pdp1_state>(); if (LOG_IOT_EXTRA) - device->logerror("PPA instruction: mb=0%06o, (%s)\n", (unsigned) mb, device->machine().describe_context()); + logerror("PPA instruction: mb=0%06o, (%s)\n", (unsigned) mb, machine().describe_context()); - state->tape_write(*io & 0377); - state->m_io_status &= ~io_st_ptp; - /* delay is approximately 1/63.3 second */ + tape_write(io & 0377); + m_st_ptp(0); + // delay is approximately 1/63.3 second if (LOG_IOT_OVERLAP) { - if (state->m_tape_puncher.timer->enable(0)) - device->logerror("Error: overlapped PPA/PPB instructions: mb=0%06o, (%s)\n", (unsigned) mb, device->machine().describe_context()); + if (m_timer->enable(0)) + logerror("Error: overlapped PPA/PPB instructions: mb=0%06o, (%s)\n", (unsigned) mb, machine().describe_context()); } - state->m_tape_puncher.timer->adjust(attotime::from_usec(15800), nac); + m_timer->adjust(attotime::from_usec(15800), nac); } /* @@ -1115,21 +983,20 @@ static void iot_ppa(device_t *device, int op2, int nac, int mb, int *io, int ac) * 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. */ -static void iot_ppb(device_t *device, int op2, int nac, int mb, int *io, int ac) +void pdp1_punchtape_image_device::iot_ppb(int op2, int nac, int mb, int &io, int ac) { - pdp1_state *state = device->machine().driver_data<pdp1_state>(); if (LOG_IOT_EXTRA) - device->logerror("PPB instruction: mb=0%06o, (%s)\n", (unsigned) mb, device->machine().describe_context()); + logerror("PPB instruction: mb=0%06o, (%s)\n", (unsigned) mb, machine().describe_context()); - state->tape_write((*io >> 12) | 0200); - state->m_io_status &= ~io_st_ptp; + tape_write((io >> 12) | 0200); + m_st_ptp(0); /* delay is approximately 1/63.3 second */ if (LOG_IOT_OVERLAP) { - if (state->m_tape_puncher.timer->enable(0)) - device->logerror("Error: overlapped PPA/PPB instructions: mb=0%06o, (%s)\n", (unsigned) mb, device->machine().describe_context()); + if (m_timer->enable(0)) + logerror("Error: overlapped PPA/PPB instructions: mb=0%06o, (%s)\n", (unsigned) mb, machine().describe_context()); } - state->m_tape_puncher.timer->adjust(attotime::from_usec(15800), nac); + m_timer->adjust(attotime::from_usec(15800), nac); } @@ -1143,35 +1010,29 @@ static void iot_ppb(device_t *device, int op2, int nac, int mb, int *io, int ac) /* Open a file for typewriter output */ -image_init_result pdp1_printer_image_device::call_load() +image_init_result pdp1_typewriter_device::call_load() { - pdp1_state *state = machine().driver_data<pdp1_state>(); - /* open file */ - state->m_typewriter.fd = this; - - state->m_io_status |= io_st_tyo; + m_st_tyo(1); return image_init_result::PASS; } -void pdp1_printer_image_device::call_unload() +void pdp1_typewriter_device::call_unload() { - pdp1_state *state = machine().driver_data<pdp1_state>(); - state->m_typewriter.fd = nullptr; } /* Write a character to typewriter */ -void pdp1_state::typewriter_out(uint8_t data) +void pdp1_typewriter_device::typewriter_out(uint8_t data) { if (LOG_IOT_EXTRA) logerror("typewriter output %o\n", data); - pdp1_typewriter_drawchar(data); - if (m_typewriter.fd) + drawchar(data); + if (is_loaded()) #if 1 - m_typewriter.fd->fwrite(& data, 1); + fwrite(& data, 1); #else { static const char ascii_table[2][64] = @@ -1219,47 +1080,47 @@ void pdp1_state::typewriter_out(uint8_t data) switch (data) { case 034: - /* Black: ignore */ + // Black: ignore //color = color_typewriter_black; { static const char black[5] = { '\033', '[', '3', '0', 'm' }; - image_fwrite(m_typewriter.fd, black, sizeof(black)); + fwrite(black, sizeof(black)); } break; case 035: - /* Red: ignore */ + // Red: ignore //color = color_typewriter_red; { static const char red[5] = { '\033', '[', '3', '1', 'm' }; - image_fwrite(m_typewriter.fd, red, sizeof(red)); + fwrite(red, sizeof(red)); } break; case 072: - /* Lower case */ + // Lower case m_case_shift = 0; break; case 074: - /* Upper case */ + // Upper case m_case_shift = 1; break; case 077: - /* Carriage Return */ + // Carriage Return { static const char line_end[2] = { '\r', '\n' }; - image_fwrite(m_typewriter.fd, line_end, sizeof(line_end)); + fwrite(line_end, sizeof(line_end)); } break; default: - /* Any printable character... */ + // Any printable character... - if ((data != 040) && (data != 056)) /* 040 and 056 are non-spacing characters: don't try to print right now */ + 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) */ - image_fwrite(m_typewriter.fd, & ascii_table[m_case_shift][data], 1); + fwrite(&ascii_table[m_case_shift][data], 1); break; } @@ -1270,10 +1131,10 @@ void pdp1_state::typewriter_out(uint8_t data) /* timer callback to generate typewriter completion pulse */ -TIMER_CALLBACK_MEMBER(pdp1_state::tyo_callback) +TIMER_CALLBACK_MEMBER(pdp1_typewriter_device::tyo_callback) { int nac = param; - m_io_status |= io_st_tyo; + m_st_tyo(1); if (nac) { m_maincpu->set_state_int(PDP1_IOS,1); @@ -1283,20 +1144,18 @@ TIMER_CALLBACK_MEMBER(pdp1_state::tyo_callback) /* tyo iot callback */ -static void iot_tyo(device_t *device, int op2, int nac, int mb, int *io, int ac) +void pdp1_typewriter_device::iot_tyo(int op2, int nac, int mb, int &io, int ac) { - pdp1_state *state = device->machine().driver_data<pdp1_state>(); - int ch, delay; - if (LOG_IOT_EXTRA) - device->logerror("Warning, TYO instruction not fully emulated: mb=0%06o, (%s)\n", (unsigned) mb, device->machine().describe_context()); + logerror("Warning, TYO instruction not fully emulated: mb=0%06o, (%s)\n", (unsigned) mb, machine().describe_context()); - ch = (*io) & 077; + int ch = io & 077; - state->typewriter_out(ch); - state->m_io_status &= ~io_st_tyo; + 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 */ @@ -1316,11 +1175,11 @@ static void iot_tyo(device_t *device, int op2, int nac, int mb, int *io, int ac) } if (LOG_IOT_OVERLAP) { - if (state->m_typewriter.tyo_timer->enable(0)) - device->logerror("Error: overlapped TYO instruction: mb=0%06o, (%s)\n", (unsigned) mb, device->machine().describe_context()); + if (m_tyo_timer->enable(0)) + logerror("Error: overlapped TYO instruction: mb=0%06o, (%s)\n", (unsigned) mb, machine().describe_context()); } - state->m_typewriter.tyo_timer->adjust(attotime::from_msec(delay), nac); + m_tyo_timer->adjust(attotime::from_msec(delay), nac); } /* @@ -1337,21 +1196,16 @@ static void iot_tyo(device_t *device, int op2, int nac, int mb, int *io, int ac) * clears the In-Out Register before transferring the information and also clears * the type-in status bit. */ -static void iot_tyi(device_t *device, int op2, int nac, int mb, int *io, int ac) +void pdp1_typewriter_device::iot_tyi(int op2, int nac, int mb, int &io, int ac) { - pdp1_state *state = device->machine().driver_data<pdp1_state>(); if (LOG_IOT_EXTRA) - device->logerror("Warning, TYI instruction not fully emulated: mb=0%06o, (%s)\n", (unsigned) mb, device->machine().describe_context()); + logerror("Warning, TYI instruction not fully emulated: mb=0%06o, (%s)\n", (unsigned) mb, machine().describe_context()); - *io = state->m_typewriter.tb; - if (! (state->m_io_status & io_st_tyi)) - *io |= 0100; + io = m_tb; + if (! (m_driver_state->m_io_status & io_st_tyi)) + io |= 0100; else - { - state->m_io_status &= ~io_st_tyi; - if (USE_SBS) - state->m_maincpu->set_input_line(0, CLEAR_LINE); /* PDP1 - interrupt it, baby */ - } + m_st_tyi(0); } @@ -1403,25 +1257,20 @@ TIMER_CALLBACK_MEMBER(pdp1_state::dpy_callback) Light on one pixel on CRT */ -static void iot_dpy(device_t *device, int op2, int nac, int mb, int *io, int ac) +void pdp1_state::iot_dpy(int op2, int nac, int mb, int &io, int ac) { - pdp1_state *state = device->machine().driver_data<pdp1_state>(); - int x; - int y; - - - x = ((ac+0400000) & 0777777) >> 8; - y = (((*io)+0400000) & 0777777) >> 8; - state->pdp1_plot(x, y); + int x = ((ac+0400000) & 0777777) >> 8; + int y = ((io+0400000) & 0777777) >> 8; + pdp1_plot(x, y); /* light pen 32 support */ - state->m_io_status &= ~io_st_pen; + m_io_status &= ~io_st_pen; - if (state->m_lightpen.down && ((x-state->m_lightpen.x)*(x-state->m_lightpen.x)+(y-state->m_lightpen.y)*(y-state->m_lightpen.y) < state->m_lightpen.radius*state->m_lightpen.radius)) + 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)) { - state->m_io_status |= io_st_pen; + m_io_status |= io_st_pen; - state->m_maincpu->set_state_int(PDP1_PF3, 1); + m_maincpu->set_state_int(PDP1_PF3, 1); } if (nac) @@ -1431,10 +1280,10 @@ static void iot_dpy(device_t *device, int op2, int nac, int mb, int *io, int ac) { /* note that overlap detection is incomplete: it will only work if both DPY instructions require a completion pulse */ - if (state->m_dpy_timer->enable(0)) - device->logerror("Error: overlapped DPY instruction: mb=0%06o, (%s)\n", (unsigned) mb, device->machine().describe_context()); + if (m_dpy_timer->enable(0)) + logerror("Error: overlapped DPY instruction: mb=0%06o, (%s)\n", (unsigned) mb, machine().describe_context()); } - state->m_dpy_timer->adjust(attotime::from_usec(50)); + m_dpy_timer->adjust(attotime::from_usec(50)); } } @@ -1444,35 +1293,33 @@ static void iot_dpy(device_t *device, int op2, int nac, int mb, int *io, int ac) MIT parallel drum (variant of type 23) */ -void pdp1_state::parallel_drum_set_il(int il) +void pdp1_cylinder_image_device::set_il(int il) { - attotime il_phase; + m_il = il; - m_parallel_drum.il = il; - - il_phase = ((PARALLEL_DRUM_WORD_TIME * il) - m_parallel_drum.rotation_timer->elapsed()); + 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_parallel_drum.il_timer->adjust(il_phase, 0, PARALLEL_DRUM_ROTATION_TIME); + m_il_timer->adjust(il_phase, 0, PARALLEL_DRUM_ROTATION_TIME); } #ifdef UNUSED_FUNCTION -TIMER_CALLBACK_MEMBER(pdp1_state::il_timer_callback) +TIMER_CALLBACK_MEMBER(pdp1_cylinder_image_device::il_timer_callback) { - if (m_parallel_drum.dba) + if (m_dba) { /* set break request and status bit 5 */ /* ... */ } } -void pdp1_state::parallel_drum_init(pdp1_state *state) +void pdp1_cylinder_image_device::parallel_drum_init(pdp1_state *state) { - m_parallel_drum.rotation_timer = machine().scheduler().timer_alloc(); - m_parallel_drum.rotation_timer->adjust(PARALLEL_DRUM_ROTATION_TIME, 0, PARALLEL_DRUM_ROTATION_TIME); + m_rotation_timer = machine().scheduler().timer_alloc(); + m_rotation_timer->adjust(PARALLEL_DRUM_ROTATION_TIME, 0, PARALLEL_DRUM_ROTATION_TIME); - m_parallel_drum.il_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(pdp1_state::il_timer_callback),this)); - parallel_drum_set_il(0); + m_il_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(pdp1_cylinder_image_device::il_timer_callback),this)); + set_il(0); } #endif @@ -1481,46 +1328,38 @@ void pdp1_state::parallel_drum_init(pdp1_state *state) */ image_init_result pdp1_cylinder_image_device::call_load() { - pdp1_state *state = machine().driver_data<pdp1_state>(); - /* open file */ - state->m_parallel_drum.fd = this; - return image_init_result::PASS; } void pdp1_cylinder_image_device::call_unload() { - pdp1_state *state = machine().driver_data<pdp1_state>(); - state->m_parallel_drum.fd = nullptr; } -static void iot_dia(device_t *device, int op2, int nac, int mb, int *io, int ac) +void pdp1_cylinder_image_device::iot_dia(int op2, int nac, int mb, int &io, int ac) { - pdp1_state *state = device->machine().driver_data<pdp1_state>(); - state->m_parallel_drum.wfb = ((*io) & 0370000) >> 12; - state->parallel_drum_set_il((*io) & 0007777); + m_wfb = (io & 0370000) >> 12; + set_il(io & 0007777); - state->m_parallel_drum.dba = 0; /* right? */ + m_dba = 0; /* right? */ } -static void iot_dba(device_t *device, int op2, int nac, int mb, int *io, int ac) +void pdp1_cylinder_image_device::iot_dba(int op2, int nac, int mb, int &io, int ac) { - pdp1_state *state = device->machine().driver_data<pdp1_state>(); - state->m_parallel_drum.wfb = ((*io) & 0370000) >> 12; - state->parallel_drum_set_il((*io) & 0007777); + m_wfb = (io & 0370000) >> 12; + set_il(io & 0007777); - state->m_parallel_drum.dba = 1; + m_dba = 1; } /* Read a word from drum */ -uint32_t pdp1_state::drum_read(int field, int position) +uint32_t pdp1_cylinder_image_device::drum_read(int field, int position) { int offset = (field*4096+position)*3; uint8_t buf[3]; - if (m_parallel_drum.fd && (!m_parallel_drum.fd->fseek(offset, SEEK_SET)) && (m_parallel_drum.fd->fread( buf, 3) == 3)) + if (is_loaded() && (!fseek(offset, SEEK_SET)) && (fread(buf, 3) == 3)) return ((buf[0] << 16) | (buf[1] << 8) | buf[2]) & 0777777; return 0; @@ -1529,67 +1368,62 @@ uint32_t pdp1_state::drum_read(int field, int position) /* Write a word to drum */ -void pdp1_state::drum_write(int field, int position, uint32_t data) +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 (m_parallel_drum.fd) + if (is_loaded()) { buf[0] = data >> 16; buf[1] = data >> 8; buf[2] = data; - m_parallel_drum.fd->fseek(offset, SEEK_SET); - m_parallel_drum.fd->fwrite( buf, 3); + fseek(offset, SEEK_SET); + fwrite(buf, 3); } } -static void iot_dcc(device_t *device, int op2, int nac, int mb, int *io, int ac) +void pdp1_cylinder_image_device::iot_dcc(int op2, int nac, int mb, int &io, int ac) { - pdp1_state *state = device->machine().driver_data<pdp1_state>(); - attotime delay; - int dc; + m_rfb = (io & 0370000) >> 12; + m_wc = - (io & 0007777); - state->m_parallel_drum.rfb = ((*io) & 0370000) >> 12; - state->m_parallel_drum.wc = - ((*io) & 0007777); + m_wcl = ac & 0177777/*0007777???*/; - state->m_parallel_drum.wcl = ac & 0177777/*0007777???*/; - - state->m_parallel_drum.dba = 0; /* right? */ + m_dba = 0; /* right? */ /* clear status bit 5... */ /* do transfer */ - delay = state->m_parallel_drum.il_timer->remaining(); - dc = state->m_parallel_drum.il; + attotime delay = m_il_timer->remaining(); + int dc = m_il; do { - if ((state->m_parallel_drum.wfb >= 1) && (state->m_parallel_drum.wfb <= 22)) + if ((m_wfb >= 1) && (m_wfb <= 22)) { - state->drum_write(state->m_parallel_drum.wfb-1, dc, (signed)state->m_maincpu->space(AS_PROGRAM).read_dword(state->m_parallel_drum.wcl<<2)); + drum_write(m_wfb-1, dc, (signed)m_maincpu->space(AS_PROGRAM).read_dword(m_wcl)); } - if ((state->m_parallel_drum.rfb >= 1) && (state->m_parallel_drum.rfb <= 22)) + if ((m_rfb >= 1) && (m_rfb <= 22)) { - state->m_maincpu->space(AS_PROGRAM).write_dword(state->m_parallel_drum.wcl<<2, state->drum_read(state->m_parallel_drum.rfb-1, dc)); + m_maincpu->space(AS_PROGRAM).write_dword(m_wcl, drum_read(m_rfb-1, dc)); } - state->m_parallel_drum.wc = (state->m_parallel_drum.wc+1) & 07777; - state->m_parallel_drum.wcl = (state->m_parallel_drum.wcl+1) & 0177777/*0007777???*/; + m_wc = (m_wc+1) & 07777; + m_wcl = (m_wcl+1) & 0177777/*0007777???*/; dc = (dc+1) & 07777; - if (state->m_parallel_drum.wc) + if (m_wc) delay = delay + PARALLEL_DRUM_WORD_TIME; - } while (state->m_parallel_drum.wc); - state->m_maincpu->adjust_icount(-state->m_maincpu->attotime_to_cycles(delay)); + } while (m_wc); + m_maincpu->adjust_icount(-m_maincpu->attotime_to_cycles(delay)); /* if no error, skip */ - state->m_maincpu->set_state_int(PDP1_PC, state->m_maincpu->state_int(PDP1_PC)+1); + m_maincpu->set_state_int(PDP1_PC, m_maincpu->state_int(PDP1_PC)+1); } -static void iot_dra(device_t *device, int op2, int nac, int mb, int *io, int ac) +void pdp1_cylinder_image_device::iot_dra(int op2, int nac, int mb, int &io, int ac) { - pdp1_state *state = device->machine().driver_data<pdp1_state>(); - (*io) = (state->m_parallel_drum.rotation_timer->elapsed() * - (ATTOSECONDS_PER_SECOND / (PARALLEL_DRUM_WORD_TIME.as_attoseconds()))).seconds() & 0007777; + io = (m_rotation_timer->elapsed() * + (ATTOSECONDS_PER_SECOND / (PARALLEL_DRUM_WORD_TIME.as_attoseconds()))).seconds() & 0007777; /* set parity error and timing error... */ } @@ -1607,9 +1441,9 @@ static void iot_dra(device_t *device, int op2, int nac, int mb, int *io, int ac) fire rocket, and fire torpedo. low order 4 bits, same for other ship. routine is entered by jsp cwg. */ -static void iot_011(device_t *device, int op2, int nac, int mb, int *io, int ac) +void pdp1_state::iot_011(int op2, int nac, int mb, int &io, int ac) { - int key_state = device->machine().driver_data<pdp1_state>()->read_spacewar(); + int key_state = m_spacewar->read(); int reply; @@ -1637,7 +1471,7 @@ static void iot_011(device_t *device, int op2, int nac, int mb, int *io, int ac) if (key_state & HSPACE_PLAYER1) reply |= 014; - *io = reply; + io = reply; } @@ -1646,13 +1480,24 @@ static void iot_011(device_t *device, int op2, int nac, int mb, int *io, int ac) check IO status */ -static void iot_cks(device_t *device, int op2, int nac, int mb, int *io, int ac) +void pdp1_state::iot_cks(int op2, int nac, int mb, int &io, int ac) { - pdp1_state *state = device->machine().driver_data<pdp1_state>(); if (LOG_IOT_EXTRA) - device->logerror("CKS instruction: mb=0%06o, (%s)\n", (unsigned) mb, device->machine().describe_context()); + logerror("CKS instruction: mb=0%06o, (%s)\n", (unsigned) mb, machine().describe_context()); - *io = state->m_io_status; + io = m_io_status; +} + +template <int Mask> +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 */ } @@ -1661,30 +1506,29 @@ static void iot_cks(device_t *device, int op2, int nac, int mb, int *io, int ac) IO devices should reset */ -void pdp1_io_sc_callback(device_t *device) +void pdp1_state::io_state_clear() { - pdp1_state *state = device->machine().driver_data<pdp1_state>(); - state->m_tape_reader.rcl = state->m_tape_reader.rc = 0; - if (state->m_tape_reader.timer) - state->m_tape_reader.timer->enable(0); + 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 (state->m_tape_puncher.timer) - state->m_tape_puncher.timer->enable(0); + if (m_tape_puncher->m_timer) + m_tape_puncher->m_timer->enable(0); - if (state->m_typewriter.tyo_timer) - state->m_typewriter.tyo_timer->enable(0); + if (m_typewriter->m_tyo_timer) + m_typewriter->m_tyo_timer->enable(0); - if (state->m_dpy_timer) - state->m_dpy_timer->enable(0); + if (m_dpy_timer) + m_dpy_timer->enable(0); - state->m_io_status = io_st_tyo | io_st_ptp; + m_io_status = io_st_tyo | io_st_ptp; } /* typewriter keyboard handler */ -void pdp1_state::pdp1_keyboard() +void pdp1_typewriter_device::pdp1_keyboard() { int i; int j; @@ -1706,13 +1550,10 @@ void pdp1_state::pdp1_keyboard() { for (j=0; (((typewriter_transitions >> j) & 1) == 0) /*&& (j<16)*/; j++) ; - m_typewriter.tb = (i << 4) + j; - m_io_status |= io_st_tyi; - #if USE_SBS - m_maincpu->set_input_line(0, ASSERT_LINE); /* PDP1 - interrupt it, baby */ - #endif + m_tb = (i << 4) + j; + m_st_tyi(1); m_maincpu->set_state_int(PDP1_PF1, 1); - pdp1_typewriter_drawchar(m_typewriter.tb); /* we want to echo input */ + drawchar(m_tb); /* we want to echo input */ break; } } @@ -1835,7 +1676,7 @@ INTERRUPT_GEN_MEMBER(pdp1_state::pdp1_interrupt) 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<<2)); + 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) @@ -1847,7 +1688,7 @@ INTERRUPT_GEN_MEMBER(pdp1_state::pdp1_interrupt) 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)<<2, m_maincpu->state_int(PDP1_MB)); + 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 */ @@ -1911,7 +1752,7 @@ INTERRUPT_GEN_MEMBER(pdp1_state::pdp1_interrupt) m_old_tw_keys = 0; m_old_ta_keys = 0; - pdp1_keyboard(); + m_typewriter->pdp1_keyboard(); } pdp1_lightpen(); @@ -1926,6 +1767,37 @@ void pdp1_state::pdp1(machine_config &config) 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 occasionnally 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_read_binary_word(m_tape_reader, FUNC(pdp1_readtape_image_device::tape_read_binary)); + m_maincpu->set_io_sc_callback(FUNC(pdp1_state::io_state_clear)); /* video hardware (includes the control panel and typewriter output) */ screen_device &screen(SCREEN(config, "screen", SCREEN_TYPE_RASTER)); @@ -1942,10 +1814,17 @@ void pdp1_state::pdp1(machine_config &config) 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, "readt", 0); - PDP1_PUNCHTAPE(config, "punch", 0); - PDP1_PRINTER(config, "typewriter", 0); - PDP1_CYLINDER(config, "drum", 0); + PDP1_READTAPE(config, m_tape_reader); + m_tape_reader->st_ptr().set(FUNC(pdp1_state::io_status_w<io_st_ptr>)); + + PDP1_PUNCHTAPE(config, m_tape_puncher); + m_tape_puncher->st_ptp().set(FUNC(pdp1_state::io_status_w<io_st_ptp>)); + + PDP1_TYPEWRITER(config, m_typewriter); + m_typewriter->st_tyo().set(FUNC(pdp1_state::io_status_w<io_st_tyo>)); + m_typewriter->st_tyi().set(FUNC(pdp1_state::io_status_w<io_st_tyi>)); + + 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 + ARRAY_LENGTH(pdp1_pens), total_colors_needed); diff --git a/src/mame/includes/pdp1.h b/src/mame/includes/pdp1.h index 102554eb438..2d237290b81 100644 --- a/src/mame/includes/pdp1.h +++ b/src/mame/includes/pdp1.h @@ -168,59 +168,216 @@ enum pen_lightpen_pressed = pen_green }; -/* tape reader registers */ -struct tape_reader_t +class pdp1_state; + +// tape reader device +class pdp1_readtape_image_device : public device_t, + public device_image_interface { - device_image_interface *fd; /* file descriptor of tape image */ +public: + // construction/destruction + pdp1_readtape_image_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock = 0U); + + 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); + + void tape_read_binary(); + +protected: + // device-level overrides + virtual void device_resolve_objects() override; + virtual void device_start() override; - int motor_on; /* 1-bit reader motor on */ + // image-level overrides + virtual iodevice_t image_type() const noexcept override { return IO_PUNCHTAPE; } - int rb; /* 18-bit reader buffer */ - int rcl; /* 1-bit reader clutch */ - int rc; /* 2-bit reader counter */ - int rby; /* 1-bit reader binary mode flip-flop */ - int rcp; /* 1-bit reader "need a completion pulse" flip-flop */ + virtual bool is_readable() const noexcept override { return true; } + virtual bool is_writeable() const noexcept override { return false; } + virtual bool is_creatable() const noexcept override { return false; } + virtual bool must_be_loaded() const noexcept override { return false; } + virtual bool is_reset_on_load() const noexcept override { return false; } + virtual const char *file_extensions() const noexcept override { return "tap,rim"; } - emu_timer *timer; /* timer to simulate reader timing */ + 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<pdp1_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 registers */ -struct tape_puncher_t +// tape puncher device +class pdp1_punchtape_image_device : public device_t, + public device_image_interface { - device_image_interface *fd; /* file descriptor of tape image */ +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 iodevice_t image_type() const noexcept override { return IO_PUNCHTAPE; } - emu_timer *timer; /* timer to generate completion pulses */ + 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 must_be_loaded() const noexcept override { return false; } + 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<pdp1_device> m_maincpu; + + devcb_write_line m_st_ptp; + + emu_timer *m_timer; // timer to generate completion pulses }; -/* typewriter registers */ -struct typewriter_t +// typewriter device +class pdp1_typewriter_device : public device_t, + public device_image_interface { - device_image_interface *fd; /* file descriptor of output image */ +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 iodevice_t image_type() const noexcept override { return IO_PRINTER; } + + 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 must_be_loaded() const noexcept override { return false; } + virtual bool is_reset_on_load() const noexcept override { return false; } + virtual const char *file_extensions() const noexcept override { return "typ"; } + + 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); - int tb; /* typewriter buffer */ + void pdp1_keyboard(); + + required_device<pdp1_device> m_maincpu; + required_device<pdp1_state> 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 *tyo_timer;/* timer to generate completion pulses */ + 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) */ -struct parallel_drum_t +// MIT parallel drum (mostly similar to type 23) +class pdp1_cylinder_image_device : public device_t, + public device_image_interface { - device_image_interface *fd; /* file descriptor of drum image */ +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); - int il; /* initial location (12-bit) */ - int wc; /* word counter (12-bit) */ - int wcl; /* word core location counter (16-bit) */ - int rfb; /* read field buffer (5-bit) */ - int wfb; /* write field buffer (5-bit) */ +protected: + // device-level overrides + virtual void device_start() override; - int dba; + // image-level overrides + virtual iodevice_t image_type() const noexcept override { return IO_CYLINDER; } - emu_timer *rotation_timer; /* timer called each time dc is 0 */ - emu_timer *il_timer; /* timer called each time dc is il */ + 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 must_be_loaded() const noexcept override { return false; } + virtual bool is_reset_on_load() const noexcept override { return false; } + virtual const char *file_extensions() const noexcept override { return "drm"; } + + virtual image_init_result call_load() override; + virtual void call_unload() override; + +public: + void set_il(int il); + uint32_t drum_read(int field, int position); + void drum_write(int field, int position, uint32_t data); + + required_device<pdp1_device> m_maincpu; + + int m_il; // initial location (12-bit) + int m_wc; // word counter (12-bit) + int m_wcl; // word core location counter (16-bit) + int m_rfb; // read field buffer (5-bit) + int m_wfb; // write field buffer (5-bit) + + int m_dba; + + emu_timer *m_rotation_timer;// timer called each time dc is 0 + emu_timer *m_il_timer; // timer called each time dc is il }; @@ -239,6 +396,10 @@ 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_gfxdecode(*this, "gfxdecode"), m_palette(*this, "palette"), m_crt(*this, "crt"), @@ -248,21 +409,20 @@ public: m_tstadd(*this, "TSTADD"), m_twdmsb(*this, "TWDMSB"), m_twdlsb(*this, "TWDLSB"), - m_twr(*this, "TWR.%u", 0), m_cfg(*this, "CFG"), m_io_lightpen(*this, "LIGHTPEN"), m_lightx(*this, "LIGHTX"), m_lighty(*this, "LIGHTY") { } + required_device<pdp1_device> m_maincpu; + required_device<pdp1_readtape_image_device> m_tape_reader; + required_device<pdp1_punchtape_image_device> m_tape_puncher; + required_device<pdp1_typewriter_device> m_typewriter; + required_device<pdp1_cylinder_image_device> m_parallel_drum; int m_io_status; - tape_reader_t m_tape_reader; - tape_puncher_t m_tape_puncher; - typewriter_t m_typewriter; emu_timer *m_dpy_timer; lightpen_t m_lightpen; - parallel_drum_t m_parallel_drum; - required_device<pdp1_device> m_maincpu; virtual void machine_start() override; virtual void machine_reset() override; @@ -271,9 +431,6 @@ public: 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(reader_callback); - TIMER_CALLBACK_MEMBER(puncher_callback); - TIMER_CALLBACK_MEMBER(tyo_callback); TIMER_CALLBACK_MEMBER(dpy_callback); void pdp1_machine_stop(); inline void pdp1_plot_pixel(bitmap_ind16 &bitmap, int x, int y, uint32_t color); @@ -286,39 +443,35 @@ public: 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_typewriter_linefeed(); - void pdp1_typewriter_drawchar(int character); 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); - int tape_read(uint8_t *reply); - void begin_tape_read(int binary, int nac); - void tape_write(uint8_t data); - void typewriter_out(uint8_t data); - void parallel_drum_set_il(int il); - uint32_t drum_read(int field, int position); - void drum_write(int field, int position, uint32_t data); - void pdp1_keyboard(); void pdp1_lightpen(); - int read_spacewar() { return m_spacewar->read(); } + + template <int Mask> 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_state_clear(); + pdp1_reset_param_t m_reset_param; - int m_old_typewriter_keys[4]; int m_old_lightpen; int m_old_control_keys; int m_old_tw_keys; int m_old_ta_keys; - int m_typewriter_color; bitmap_ind16 m_panel_bitmap; - bitmap_ind16 m_typewriter_bitmap; lightpen_t m_lightpen_state; lightpen_t m_previous_lightpen_state; - int m_pos; - int m_case_shift; + +public: required_device<gfxdecode_device> m_gfxdecode; required_device<palette_device> m_palette; required_device<crt_device> m_crt; @@ -328,7 +481,6 @@ private: required_ioport m_tstadd; required_ioport m_twdmsb; required_ioport m_twdlsb; - required_ioport_array<4> m_twr; required_ioport m_cfg; required_ioport m_io_lightpen; required_ioport m_lightx; diff --git a/src/mame/video/pdp1.cpp b/src/mame/video/pdp1.cpp index 6f2462196a6..793f9ea5a56 100644 --- a/src/mame/video/pdp1.cpp +++ b/src/mame/video/pdp1.cpp @@ -37,17 +37,17 @@ inline void pdp1_state::pdp1_plot_pixel(bitmap_ind16 &bitmap, int x, int y, uint */ void pdp1_state::video_start() { - m_typewriter_color = color_typewriter_black; + 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_bitmap.allocate(typewriter_window_width, typewriter_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_bitmap.fill(pen_typewriter_bg, typewriter_bitmap_bounds); + m_typewriter->m_bitmap.fill(pen_typewriter_bg, typewriter_bitmap_bounds); } @@ -84,7 +84,7 @@ uint32_t pdp1_state::screen_update_pdp1(screen_device &screen, bitmap_ind16 &bit 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_bitmap, 0, 0, typewriter_window_offset_x, typewriter_window_offset_y, cliprect); + copybitmap(bitmap, m_typewriter->m_bitmap, 0, 0, typewriter_window_offset_x, typewriter_window_offset_y, cliprect); return 0; } @@ -353,28 +353,28 @@ enum }; -void pdp1_state::pdp1_typewriter_linefeed() +void pdp1_typewriter_device::linefeed() { uint8_t buf[typewriter_window_width]; int y; - assert(typewriter_window_width <= m_typewriter_bitmap.width()); - assert(typewriter_window_height <= m_typewriter_bitmap.height()); + assert(typewriter_window_width <= m_bitmap.width()); + assert(typewriter_window_height <= m_bitmap.height()); for (y=0; y<typewriter_window_height-typewriter_scroll_step; y++) { - std::copy_n(&m_typewriter_bitmap.pix16(y+typewriter_scroll_step, 0), typewriter_window_width, buf); - draw_scanline8(m_typewriter_bitmap, 0, y, typewriter_window_width, buf, m_palette->pens()); + std::copy_n(&m_bitmap.pix16(y+typewriter_scroll_step, 0), typewriter_window_width, buf); + draw_scanline8(m_bitmap, 0, y, typewriter_window_width, buf, m_driver_state->m_palette->pens()); } const rectangle typewriter_scroll_clear_window(0, typewriter_window_width-1, typewriter_window_height-typewriter_scroll_step, typewriter_window_height-1); - m_typewriter_bitmap.fill(pen_typewriter_bg, typewriter_scroll_clear_window); + m_bitmap.fill(pen_typewriter_bg, typewriter_scroll_clear_window); } -void pdp1_state::pdp1_typewriter_drawchar(int character) +void pdp1_typewriter_device::drawchar(int character) { static const char ascii_table[2][64] = - { /* n-s = non-spacing */ - { /* lower case */ + { // n-s = non-spacing + { // lower case ' ', '1', '2', '3', '4', '5', '6', '7', '8', '9', '*', '*', @@ -392,7 +392,7 @@ void pdp1_state::pdp1_typewriter_drawchar(int character) 'h', 'i', '*',/*Lower Case*/ '.', '*',/*Upper Case*/ '*',/*Backspace*/ '*', '*'/*Carriage Return*/ }, - { /* upper case */ + { // upper case ' ', '"', '\'', '~', '\202',/*implies*/ '\203',/*or*/ '\204',/*and*/ '<', '>', '\205',/*up arrow*/ '*', '*', @@ -419,58 +419,58 @@ void pdp1_state::pdp1_typewriter_drawchar(int character) switch (character) { case 034: - /* Black */ - m_typewriter_color = color_typewriter_black; + // Black + m_color = color_typewriter_black; break; case 035: - /* Red */ - m_typewriter_color = color_typewriter_red; + // Red + m_color = color_typewriter_red; break; case 036: - /* Tab */ + // Tab m_pos = m_pos + tab_step - (m_pos % tab_step); break; case 072: - /* Lower case */ + // Lower case m_case_shift = 0; break; case 074: - /* Upper case */ + // Upper case m_case_shift = 1; break; case 075: - /* Backspace */ + // Backspace if (m_pos) m_pos--; break; case 077: - /* Carriage Return */ + // Carriage Return m_pos = 0; - pdp1_typewriter_linefeed(); + linefeed(); break; default: - /* Any printable character... */ + // Any printable character... if (m_pos >= 80) - { /* if past right border, wrap around. (Right???) */ - pdp1_typewriter_linefeed(); /* next line */ - m_pos = 0; /* return to start of line */ + { // 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) */ - pdp1_draw_char(m_typewriter_bitmap, ascii_table[m_case_shift][character], + // 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_typewriter_color); /* print char */ + m_color); // print char - if ((character!= 040) && (character!= 056)) /* 040 and 056 are non-spacing characters */ - m_pos++; /* step carriage forward */ + if ((character!= 040) && (character!= 056)) // 040 and 056 are non-spacing characters + m_pos++; // step carriage forward break; } diff --git a/src/tools/unidasm.cpp b/src/tools/unidasm.cpp index 1c6c9b1a160..e1e3cc7b7b1 100644 --- a/src/tools/unidasm.cpp +++ b/src/tools/unidasm.cpp @@ -483,7 +483,7 @@ static const dasm_table_entry dasm_table[] = { "nsc8105", be, 0, []() -> util::disasm_interface * { return new m680x_disassembler(8105); } }, { "pace", le, -1, []() -> util::disasm_interface * { return new pace_disassembler; } }, { "patinho_feio", le, 0, []() -> util::disasm_interface * { return new patinho_feio_disassembler; } }, - { "pdp1", be, 0, []() -> util::disasm_interface * { return new pdp1_disassembler; } }, + { "pdp1", be, -2, []() -> util::disasm_interface * { return new pdp1_disassembler; } }, { "pdp8", be, 0, []() -> util::disasm_interface * { return new pdp8_disassembler; } }, { "pic16", le, -1, []() -> util::disasm_interface * { return new pic16_disassembler; } }, { "pic16c5x", le, -1, []() -> util::disasm_interface * { return new pic16c5x_disassembler; } }, |