diff options
Diffstat (limited to 'src/mame/drivers/alfaskop41xx.cpp')
-rw-r--r-- | src/mame/drivers/alfaskop41xx.cpp | 481 |
1 files changed, 422 insertions, 59 deletions
diff --git a/src/mame/drivers/alfaskop41xx.cpp b/src/mame/drivers/alfaskop41xx.cpp index 9c41981c322..63d461631f8 100644 --- a/src/mame/drivers/alfaskop41xx.cpp +++ b/src/mame/drivers/alfaskop41xx.cpp @@ -5,7 +5,7 @@ Alfaskop 41 series This driver is a part of a revivel project for Alfaskop 41 series where -no known working system exists today because of the distributed nature. +no known working system exists today because of its distributed nature. All parts network boots over SS3 (SDLC) from a Floppy Disk unit and nothing works unless there is a floppy in that unit. These floppies are rare and many parts have been discarded because they are useless stand alone. @@ -25,18 +25,31 @@ Dansk Datahistorisk Forening - http://datamuseum.dk/ #include "cpu/m6800/m6800.h" #include "machine/6850acia.h" #include "machine/6821pia.h" +#include "machine/mc6854.h" +#include "machine/mc6844.h" +#include "machine/pla.h" #include "video/mc6845.h" #include "screen.h" +#include "machine/input_merger.h" +#include "machine/output_latch.h" +#include "machine/alfaskop_s41_kb.h" //#include "bus/rs232/rs232.h" -//#include "machine/clock.h" +#include "machine/clock.h" #define LOG_IO (1U << 1) #define LOG_NVRAM (1U << 2) #define LOG_MIC (1U << 3) #define LOG_DIA (1U << 4) - -//#define VERBOSE (LOG_IO|LOG_NVRAM|LOG_MIC|LOG_DIA) +#define LOG_DMA (1U << 5) +#define LOG_IRQ (1U << 6) +#define LOG_ADLC (1U << 7) +#define LOG_KBD (1U << 8) +#define LOG_AM (1U << 9) +#define LOG_LEDS (1U << 10) +#define LOG_BITS (1U << 11) + +//#define VERBOSE (LOG_MIC) //#define LOG_OUTPUT_STREAM std::cout #include "logmacro.h" @@ -45,6 +58,15 @@ Dansk Datahistorisk Forening - http://datamuseum.dk/ #define LOGNVRAM(...) LOGMASKED(LOG_NVRAM, __VA_ARGS__) #define LOGMIC(...) LOGMASKED(LOG_MIC, __VA_ARGS__) #define LOGDIA(...) LOGMASKED(LOG_DIA, __VA_ARGS__) +#define LOGDMA(...) LOGMASKED(LOG_DMA, __VA_ARGS__) +#define LOGIRQ(...) LOGMASKED(LOG_IRQ, __VA_ARGS__) +#define LOGADLC(...) LOGMASKED(LOG_ADLC, __VA_ARGS__) +#define LOGKBD(...) LOGMASKED(LOG_KBD, __VA_ARGS__) +#define LOGAM(...) LOGMASKED(LOG_AM, __VA_ARGS__) +#define LOGLEDS(...) LOGMASKED(LOG_LEDS, __VA_ARGS__) +#define LOGBITS(...) LOGMASKED(LOG_BITS, __VA_ARGS__) + +#define PLA1_TAG "ic50" class alfaskop4110_state : public driver_device { @@ -52,30 +74,96 @@ public: alfaskop4110_state(const machine_config &mconfig, device_type type, const char *tag) : driver_device(mconfig, type, tag) , m_maincpu(*this, "maincpu") - , m_kbdacia(*this, "kbdacia") - , m_micpia(*this, "micpia") - , m_diapia(*this, "diapia") + , m_kbd_acia(*this, "kbd_acia") + , m_mic_pia(*this, "mic_pia") + , m_dia_pia(*this, "dia_pia") , m_crtc(*this, "crtc") , m_screen(*this, "screen") , m_vram(*this, "vram") + , m_pla(*this, PLA1_TAG) + , m_kbd(*this, "keyboard") , m_chargen(*this, "chargen") + , m_tia_adlc(*this, "tia_adlc") + , m_tia_dma(*this, "tia_dma") + , m_irq(0) + , m_imsk(0) { } void alfaskop4110(machine_config &config); private: + virtual void machine_start() override; + virtual void machine_reset() override; + void mem_map(address_map &map); required_device<cpu_device> m_maincpu; - required_device<acia6850_device> m_kbdacia; - required_device<pia6821_device> m_micpia; - required_device<pia6821_device> m_diapia; + required_device<acia6850_device> m_kbd_acia; + required_device<pia6821_device> m_mic_pia; + required_device<pia6821_device> m_dia_pia; required_device<mc6845_device> m_crtc; required_device<screen_device> m_screen; required_shared_ptr<uint8_t> m_vram; + required_device<pls100_device> m_pla; + required_device<alfaskop_s41_keyboard_device> m_kbd; /* Video controller */ required_region_ptr<uint8_t> m_chargen; MC6845_UPDATE_ROW(crtc_update_row); + + /* TIA */ + required_device<mc6854_device> m_tia_adlc; + required_device<mc6844_device> m_tia_dma; + + /* Interrupt handling */ + template <unsigned N> DECLARE_WRITE_LINE_MEMBER(irq_w); + uint8_t m_irq; + uint8_t m_imsk; + + /* Kbd communications */ + uint8_t m_txd; + + /* Debug stuff */ + /* Timer */ + enum + { + TIMER_POLL_START, + TIMER_POLL_BIT + }; + void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override; + + // DEBUG stuff, will be removed when hooked up towards remote peer +#if 1 + /* zero extended SDLC poll message frame to feed into receiver as a test + 0 1 1 1 1 1 1 0 ; opening flag 0x7e + 0 0 0 0 0 0 0 0 ; 0x00 + 1 1 1 1 1 0 1 1 1 ; 0xff <- a zero needs to be inserted, done by test code + 0 0 0 0 0 0 1 1 ; 0xc0 + 0 0 0 0 0 1 0 1 ; 0xa0 + 1 0 1 1 0 0 0 1 ; CRC 0x8d + 1 0 1 0 1 0 1 0 ; CRC 0x55 + 0 1 1 1 1 1 1 0 ; closing flag 0x7e + */ + uint8_t txBuf[10] = {0x7e, 0x00, 0xff, 0xc0, 0xa0, 0x8d, 0x55, 0x7e}; + +#else // Alternative poll message body wih faulty CRC, CRC isn't checked yet by the ADLC + + /* zero extended SDLC poll message frame to feed into receiver as a test + 0 1 1 1 1 1 1 0 ; opening flag 0x7e + 0 0 0 0 0 0 0 0 ; 0x00 + 0 0 0 0 0 0 0 0 ; 0x00 + 1 1 1 1 1 0 1 1 0 ; 0xfe <- a zero needs to be inserted, done by test code + 1 1 1 0 1 0 0 1 ; 0xe9 + 1 0 1 1 0 0 0 1 ; CRC 0x8d - wrong + 1 0 1 0 1 0 1 0 ; CRC 0x55 - wrong + 0 1 1 1 1 1 1 0 ; closing flag 0x7e + */ + uint8_t txBuf[10] = {0x7e, 0x00, 0x00, 0xfe, 0xe9, 0x8d, 0x55, 0x7e}; +#endif + + int index = 0; + int pos = 0; + int ones = 0; + bool flank = false; }; class alfaskop4120_state : public driver_device @@ -84,8 +172,8 @@ public: alfaskop4120_state(const machine_config &mconfig, device_type type, const char *tag) : driver_device(mconfig, type, tag) , m_maincpu(*this, "maincpu") - , m_micpia(*this, "micpia") - , m_fdapia(*this, "diapia") + , m_mic_pia(*this, "mic_pia") + , m_fdapia(*this, "dia_pia") { } void alfaskop4120(machine_config &config); @@ -93,7 +181,7 @@ private: void mem_map(address_map &map); required_device<cpu_device> m_maincpu; - required_device<pia6821_device> m_micpia; + required_device<pia6821_device> m_mic_pia; required_device<pia6821_device> m_fdapia; }; @@ -103,7 +191,7 @@ public: alfaskop4101_state(const machine_config &mconfig, device_type type, const char *tag) : driver_device(mconfig, type, tag) , m_maincpu(*this, "maincpu") - , m_micpia(*this, "micpia") + , m_mic_pia(*this, "mic_pia") { } void alfaskop4101(machine_config &config); @@ -111,31 +199,77 @@ private: void mem_map(address_map &map); required_device<cpu_device> m_maincpu; - required_device<pia6821_device> m_micpia; + required_device<pia6821_device> m_mic_pia; }; void alfaskop4110_state::mem_map(address_map &map) { map.unmap_value_high(); map(0x0000, 0x7fff).ram(); - map(0x7800, 0x7fff).ram().share(m_vram); + map(0x7800, 0x7fff).ram().share(m_vram); // TODO: Video RAM base address is configurable via NVRAM - this is the default map(0x8000, 0xefff).ram(); - map(0xf600, 0xf6ff).lrw8(NAME([this](offs_t offset) -> uint8_t { LOGNVRAM("nvram_r %04x: %02x\n", offset, 0); return (uint8_t) 0; }),// TODO: Move to MRO board - NAME( [this](offs_t offset, uint8_t data) { LOGNVRAM("nvram_w %04x: %02x\n", offset, data); })); + // NVRAM + map(0xf600, 0xf6ff).lrw8(NAME([this](offs_t offset) -> uint8_t + { + LOGNVRAM("nvram_r %04x: %02x\n", offset, 0); return (uint8_t) 0; + }), + NAME([this](offs_t offset, uint8_t data) + { + LOGNVRAM("nvram_w %04x: %02x\n", offset, data); + })); + // TIA board + map(0xf700, 0xf71f).mirror(0x00).lrw8(NAME([this](offs_t offset) -> uint8_t { LOGDMA("TIA DMA_r %04x: %02x\n", offset, 0); return m_tia_dma->read(offset); }), + NAME([this](offs_t offset, uint8_t data) { LOGDMA("TIA DMA_w %04x: %02x\n", offset, data); m_tia_dma->write(offset, data); })); + map(0xf720, 0xf723).mirror(0x04).lrw8(NAME([this](offs_t offset) -> uint8_t { LOGADLC("TIA ADLC_r %04x: %02x\n", offset, 0); return m_tia_adlc->read(offset); }), + NAME([this](offs_t offset, uint8_t data) { LOGADLC("TIA ADLC_w %04x: %02x\n", offset, data); m_tia_adlc->write(offset, data); })); + + // Main PCB map(0xf7d9, 0xf7d9).mirror(0x06).lrw8(NAME([this](offs_t offset) -> uint8_t { LOGIO("CRTC reg r %04x: %02x\n", offset, 0); return m_crtc->register_r(); }), - NAME([this](offs_t offset, uint8_t data) { LOGIO("CRTC reg w %04x: %02x\n", offset, data); m_crtc->register_w(data);})); + NAME([this](offs_t offset, uint8_t data) { LOGIO("CRTC reg w %04x: %02x\n", offset, data); m_crtc->register_w(data);})); map(0xf7d8, 0xf7d8).mirror(0x06).lw8(NAME([this](offs_t offset, uint8_t data) { LOGIO("CRTC adr w %04x: %02x\n", offset, data); m_crtc->address_w(data); })); - map(0xf7d0, 0xf7d3).mirror(0x04).lrw8(NAME([this](offs_t offset) -> uint8_t { LOGIO("DIA pia_r %04x: %02x\n", offset, 0); return m_diapia->read(offset & 3); }), - NAME([this](offs_t offset, uint8_t data) { LOGIO("DIA pia_w %04x: %02x\n", offset, data); m_diapia->write(offset & 3, data); })); - map(0xf7c4, 0xf7c7).mirror(0x00).lrw8(NAME([this](offs_t offset) -> uint8_t { LOGIO("MIC pia_r %04x: %02x\n", offset, 0); return m_micpia->read(offset & 3); }), - NAME( [this](offs_t offset, uint8_t data) { LOGIO("MIC pia_w %04x: %02x\n", offset, data); m_micpia->write(offset & 3, data); })); - map(0xf7c0, 0xf7c1).mirror(0x02).lrw8(NAME([this](offs_t offset) -> uint8_t { LOGIO("KBD acia_r %04x: %02x\n", offset, 0); return m_kbdacia->read(offset & 1); }), - NAME( [this](offs_t offset, uint8_t data) { LOGIO("KBD acia_w %04x: %02x\n", offset, data); m_kbdacia->write(offset & 1, data); })); - - map(0xf7fc, 0xf7fc).mirror(0x00).lr8(NAME([this](offs_t offset) -> uint8_t { LOGIO("Address Switch 0-7\n"); return 0; })); - - map(0xf800, 0xffff).rom().region("roms", 0); + map(0xf7d0, 0xf7d3).mirror(0x04).lrw8(NAME([this](offs_t offset) -> uint8_t { LOGDIA("DIA pia_r %04x: %02x\n", offset, 0); return m_dia_pia->read(offset & 3); }), + NAME([this](offs_t offset, uint8_t data) { LOGDIA("DIA pia_w %04x: %02x\n", offset, data); m_dia_pia->write(offset & 3, data); })); + map(0xf7c4, 0xf7c7).mirror(0x00).lrw8(NAME([this](offs_t offset) -> uint8_t { uint8_t tmp = m_mic_pia->read(offset & 3); LOGMIC("\nMIC pia_r %04x: %02x\n", offset, tmp); return tmp; }), + NAME([this](offs_t offset, uint8_t data) { LOGMIC("\nMIC pia_w %04x: %02x\n", offset, data); m_mic_pia->write(offset & 3, data); })); + map(0xf7c0, 0xf7c1).mirror(0x02).lrw8(NAME([this](offs_t offset) -> uint8_t { LOGKBD("KBD acia_r %04x: %02x\n", offset, 0); return m_kbd_acia->read(offset & 1); }), + NAME([this](offs_t offset, uint8_t data) { LOGKBD("KBD acia_w %04x: %02x\n", offset, data); m_kbd_acia->write(offset & 1, data); })); + + map(0xf7fc, 0xf7fc).mirror(0x00).lr8(NAME([this](offs_t offset) -> uint8_t { LOGIO("Address Switch 0-7\n"); return 0; })); + + map(0xf800, 0xffe7).rom().region("roms", 0); + + // IRQ mask setting + map(0xffe8, 0xfff7).rom().lrw8( NAME([this](offs_t offset) -> uint8_t + { + if (!machine().side_effects_disabled()) LOGAM("AMSK read set %04x\n", offset >> 1); + m_imsk = (offset >> 1) & 7; + return ((uint8_t *) memregion("roms")->base() + 0x7e8)[offset]; + }), + NAME([this](offs_t offset, uint8_t data) + { + if (!machine().side_effects_disabled()) LOGAM("AMSK write set %04x\n", offset); + m_imsk = (offset >> 1) & 7; + })); + + // Address modification + map(0xfff8, 0xfff9).rom().lrw8( NAME([this](offs_t offset) -> uint8_t + { + uint16_t ploffs = (~m_irq & 0xff) | ((m_imsk & 0x07) << 8) | 0x000 | (0x18 << 11); + uint8_t tmp = ((uint8_t *) memregion("roms")->base())[0x7e0 | offset | ((m_pla->read(ploffs) & 0xf0) >> 3)]; + if (!machine().side_effects_disabled()) + { + LOGAM("AMOD read %04x: %02x\n", offset, tmp); + LOGAM("AMOD pla read %04x: %02x ==> %04x\n", ploffs, m_pla->read(ploffs), (0xffe0 | offset | ((m_pla->read(ploffs) & 0xf0) >> 3))); + } + return tmp; + }), + NAME([this](offs_t offset, uint8_t data) // TODO: Check what a write does if anything + { + if (!machine().side_effects_disabled()) LOGAM("AMOD write %04x\n", offset); + })); + + map(0xfffa, 0xffff).rom().region("roms", 0x7fa); } void alfaskop4120_state::mem_map(address_map &map) @@ -145,9 +279,9 @@ void alfaskop4120_state::mem_map(address_map &map) map(0xf600, 0xf6ff).lrw8(NAME([this](offs_t offset) -> uint8_t { LOGNVRAM("nvram_r %04x: %02x\n", offset, 0); return (uint8_t) 0; }), // TODO: Move to MRO board NAME([this](offs_t offset, uint8_t data) { LOGNVRAM("nvram_w %04x: %02x\n", offset, data); })); map(0xf740, 0xf743).mirror(0x0c).lrw8(NAME([this](offs_t offset) -> uint8_t { LOGIO("FDA pia_r %04x: %02x\n", offset, 0); return m_fdapia->read(offset & 3); }), - NAME([this](offs_t offset, uint8_t data) { LOGIO("FDA pia_w %04x: %02x\n", offset, data); m_fdapia->write(offset & 3, data); })); - map(0xf7c4, 0xf7c7).mirror(0x00).lrw8(NAME([this](offs_t offset) -> uint8_t { LOGIO("MIC pia_r %04x: %02x\n", offset, 0); return m_micpia->read(offset & 3); }), - NAME([this](offs_t offset, uint8_t data) { LOGIO("MIC pia_w %04x: %02x\n", offset, data); m_micpia->write(offset & 3, data); })); + NAME([this](offs_t offset, uint8_t data) { LOGIO("FDA pia_w %04x: %02x\n", offset, data); m_fdapia->write(offset & 3, data); })); + map(0xf7c4, 0xf7c7).mirror(0x00).lrw8(NAME([this](offs_t offset) -> uint8_t { LOGMIC("MIC pia_r %04x: %02x\n", offset, 0); return m_mic_pia->read(offset & 3); }), + NAME([this](offs_t offset, uint8_t data) { LOGMIC("MIC pia_w %04x: %02x\n", offset, data); m_mic_pia->write(offset & 3, data); })); map(0xf800, 0xffff).rom().region("roms", 0); } @@ -157,8 +291,8 @@ void alfaskop4101_state::mem_map(address_map &map) map(0x0000, 0xefff).ram(); map(0xf600, 0xf6ff).lrw8(NAME([this](offs_t offset) -> uint8_t { LOGNVRAM("nvram_r %04x: %02x\n", offset, 0); return (uint8_t) 0; }), NAME([this](offs_t offset, uint8_t data) { LOGNVRAM("nvram_w %04x: %02x\n", offset, data); })); - map(0xf7c4, 0xf7c7).mirror(0x00).lrw8(NAME([this](offs_t offset) -> uint8_t { LOGIO("MIC pia_r %04x: %02x\n", offset, 0); return m_micpia->read(offset & 3); }), - NAME([this](offs_t offset, uint8_t data) { LOGIO("MIC pia_w %04x: %02x\n", offset, data); m_micpia->write(offset & 3, data); })); + map(0xf7c4, 0xf7c7).mirror(0x00).lrw8(NAME([this](offs_t offset) -> uint8_t { LOGMIC("MIC pia_r %04x: %02x\n", offset, 0); return m_mic_pia->read(offset & 3); }), + NAME([this](offs_t offset, uint8_t data) { LOGMIC("MIC pia_w %04x: %02x\n", offset, data); m_mic_pia->write(offset & 3, data); })); map(0xf800, 0xffff).rom().region("roms", 0); } @@ -172,6 +306,14 @@ INPUT_PORTS_END static INPUT_PORTS_START( alfaskop4101 ) INPUT_PORTS_END +/* Interrupt handling - vector address modifyer, irq prioritizer and irq mask */ +template <unsigned N> WRITE_LINE_MEMBER( alfaskop4110_state::irq_w ) +{ + m_irq = (m_irq & ~(1 << N)) | ((state ? 1 : 0) << N); + LOGIRQ("4110 IRQ %d: %d ==> %02x\n", N, state, m_irq); + m_maincpu->set_input_line(M6800_IRQ_LINE, state); +} + /* Simplified chargen, no attributes or special formats/features yet */ MC6845_UPDATE_ROW( alfaskop4110_state::crtc_update_row ) { @@ -197,38 +339,256 @@ void alfaskop4110_state::alfaskop4110(machine_config &config) M6800(config, m_maincpu, XTAL(19'170'000) / 18); // Verified from service manual m_maincpu->set_addrmap(AS_PROGRAM, &alfaskop4110_state::mem_map); + // TTL-level serial keyboard callback + ALFASKOP_S41_KB(config, m_kbd); + m_kbd->txd_cb().set([this](bool state) + { + LOGBITS("KBD->4110: %d\n", state); + m_kbd_acia->write_rxd(state); + }); + m_kbd->leds_cb().set([this] (uint8_t data) + { + LOGLEDS("LEDS: write %02x to LEDs\n", data); + }); + + + /* Interrupt controller and address modifier PLA */ + /* + * 82S100 data sheet + * ----------------- + * + * The 82S100 is a bipolar, fuse-link programmable logic array. It uses the + * standard AND/OR/invert architecture to directly implement custom + * um-of-product logic equations. + * + * Each device consists of 16 dedicated inputs and 8 dedicated outputs. Each + * output is capable of being actively controlled by any or all of the 48 + * product terms. The true, complement, or don't care condition of each of the + * 16 inputs ANDed together comprise one P-Term. All 48 P-Terms are then OR-d + * to each output. The user must then only select which P-Terms will activate + * an output by disconnecting terms which do not affect the output. In addition, + * each output can be fused as active high or active low. + * + * The 82S100 is fully TTL compatible and includes chip-enable control for + * expansion of input variables and output inhibit. It features three state + * outputs. + * + * Field programmable Ni-Cr links + * 16 inputs + * 8 outputs + * 48 product terms + * Commercial verion - N82S100 - 50ns max address access time + * Power dissipation - 600mW typ + * Input loading - 100uA max + * Chip enable input + * Three state outputs + * + * + */ + /* _____ _____ + * nc FE 1 |* \_/ | 28 Vcc + * IRQ7 I7 2 | | 27 I8 mask 1 + * IRQ6 I6 3 | | 26 I9 mask 2 + * IRQ5 I5 4 | | 25 I10 mask 3 + * IRQ4 I4 5 | | 24 I11 Address &== 1111 1111 111x xxxx + * IRQ3 I3 6 | 82S100 | 23 I12 AI 1 A1 + * IRQ2 I2 7 | | 22 I13 AI 2 A2 + * IRQ1 I1 8 | IC50 | 21 I14 AI 3 A3 + * IRQ0 I0 9 | | 20 I15 AI 4 A4 + * P4 F7 10 | Interrupt | 19 _CE + * mask P3 F6 11 | Controller | 18 F0 IRQ + * mask P2 F5 12 | PLA | 17 F1 mask register + * mask P1 F4 13 | | 16 F2 interrupt latch + * GND 14 |_____________| 15 F3 nc + */ + PLS100(config, m_pla); + MC6845(config, m_crtc, XTAL(19'170'000) / 9); m_crtc->set_screen("screen"); m_crtc->set_show_border_area(false); m_crtc->set_char_width(8); m_crtc->set_update_row_callback(FUNC(alfaskop4110_state::crtc_update_row)); + // VSYNC should goto IRQ1 through some logic involving MIC PIA CRA bits 0 ( 1 == enable) & 1 (1 == positive edge) + //m_crtc->out_vsync_callback().set(FUNC(alfaskop4110_state::crtc_vsync); + //m_crtc->out_vsync_callback().set([this](bool state) { LOGIRQ("CRTC VSYNC: %d\n", state); }); + //m_crtc->out_vsync_callback().set("irq1", FUNC(input_merger_device::in_w<1>)); SCREEN(config, m_screen, SCREEN_TYPE_RASTER); m_screen->set_raw(19'170'000, 80 * 8, 0, 80 * 8, 400, 0, 400); m_screen->set_screen_update("crtc", FUNC(mc6845_device::screen_update)); - PIA6821(config, m_micpia, 0); // Main board PIA - m_micpia->readcb1_handler().set([this](offs_t offset) -> uint8_t { LOGMIC("MIC PIA: CB1_r\n"); return 0;}); - m_micpia->cb2_handler().set([this](offs_t offset, uint8_t data) { LOGMIC("MIC PIA: CB2_w\n"); }); - m_micpia->writepa_handler().set([this](offs_t offset, uint8_t data) { LOGMIC("MIC PIA: PA_w\n"); }); - m_micpia->writepb_handler().set([this](offs_t offset, uint8_t data) { LOGMIC("MIC PIA: PB_w\n"); }); - m_micpia->readpa_handler().set([this](offs_t offset) -> uint8_t { LOGMIC("MIC PIA: PA_r\n"); return 0;}); - m_micpia->readpb_handler().set([this](offs_t offset) -> uint8_t { LOGMIC("MIC PIA: PB_r\n"); return 0;}); - m_micpia->readca1_handler().set([this](offs_t offset) -> uint8_t { LOGMIC("MIC PIA: CA1_r\n"); return 0;}); - m_micpia->readca2_handler().set([this](offs_t offset) -> uint8_t { LOGMIC("MIC PIA: CA2_r\n"); return 0;}); - - PIA6821(config, m_diapia, 0); // Display PIA, controls how the CRTC accesses memory etc - m_diapia->readcb1_handler().set([this](offs_t offset) -> uint8_t { LOGDIA("DIA PIA: CB1_r\n"); return 0;}); - m_diapia->cb2_handler().set([this](offs_t offset, uint8_t data) { LOGDIA("DIA PIA: CB2_w\n"); }); - m_diapia->writepa_handler().set([this](offs_t offset, uint8_t data) { LOGDIA("DIA PIA: PA_w\n"); }); - m_diapia->writepb_handler().set([this](offs_t offset, uint8_t data) { LOGDIA("DIA PIA: PB_w\n"); }); - m_diapia->readpa_handler().set([this](offs_t offset) -> uint8_t { LOGDIA("DIA PIA: PA_r\n"); return 0;}); - m_diapia->readpb_handler().set([this](offs_t offset) -> uint8_t { LOGDIA("DIA PIA: PB_r\n"); return 0;}); - m_diapia->readca1_handler().set([this](offs_t offset) -> uint8_t { LOGDIA("DIA PIA: CA1_r\n"); return 0;}); - m_diapia->readca2_handler().set([this](offs_t offset) -> uint8_t { LOGDIA("DIA PIA: CA2_r\n"); return 0;}); - - ACIA6850(config, m_kbdacia, 0); - //CLOCK(config, "acia_clock", ACIA_CLOCK).signal_handler().set(FUNC(alfaskop4110_state::write_acia_clock)); + PIA6821(config, m_mic_pia, 0); // Main board PIA + m_mic_pia->readcb1_handler().set([this](offs_t offset) -> uint8_t { LOGMIC("<-MIC PIA: CB1 read\n"); return 0;}); + m_mic_pia->cb2_handler().set([this](offs_t offset, uint8_t data) { LOGMIC("->MIC PIA: CB2 write %d\n", data); }); + + /* + * MIC PIA interface + * + * Port A (DDRA=0x7a) + * 0 - PA0 input - not used + * 1 - PA1 output - KB reset P11 pin 23 at connector 1 == KB reset 0 == no KB reset + * 2 - PA2 input - MCP test mode 1 == no test mode 0 == in test mode, + * 3 - PA3 output - not used (in DTC) + * 4 - PA4 output - not used (in DTC) + * 5 - PA5 output - Interrupt enable 1 == Int. out on P1:7 0 == no Int. out + * 6 - PA6 output - I4 latch enable 1 == I4 will be latched 0 == no I4 latch + * 7 - PA7 input - Button/MCP NMI 1 == NMI from DU button 0 == NMI from MCP P4:1=low + * Note: At initialization a KB reset pulse will be sent as DDRA contains all zeros: PA I functions as a + * high impedance input: "active level" for KB reset generation. + * + * Port B (DDRB=0xff) + * 0 - PB0 output - Reset PC-error 1 == Reset PC error FF 0 == Memory PC used + * or PC not used + * 1 - PB1 output - VMAX/VMA 1 MPU 1 == VMAX gen by MPU 0 == VMA 1 gen by MPU + * 2 - PB2 output - VMAX/VMA 1 DMA 1 == VMAX gen by DMA 0 == VMA 1 gen by DMA + * 3 - PB3 output - Display Memory 1 == 4KB Display Memory 0 == 8KB Display Memory + * 4 - PB4 output - Option Character Generator 1 == Enabled to MIC bus 0 == Disabled from MIC bus + * 5 - PB5 output - MPU Addr 1 == Mode 1 0 == Mode 0 + * 6 - PB6 output - Reset 1 == Reset all but MPU 0 == No reset + * and MIC PIA + * 7 - PB7 output - not used + */ + m_mic_pia->writepa_handler().set([this](offs_t offset, uint8_t data) + { + LOGMIC("->MIC PIA: Port A write %02x\n", data); + LOGKBD(" PA1 - KBD reset %s\n", BIT(data, 1) ? "active" : "inactive"); + m_kbd->rst_line_w(BIT(data, 1) ? ASSERT_LINE : CLEAR_LINE); + LOGMIC(" PA5 - Int out %s\n", BIT(data, 5) ? "enabled": "disabled"); + LOGMIC(" PA6 - I4 latch %s\n", BIT(data, 6) ? "enabled": "disabled"); + }); + + m_mic_pia->writepb_handler().set([this](offs_t offset, uint8_t data) + { + LOGMIC("->MIC PIA: Port B write %02x\n", data); + LOGMIC(" PB0 - Reset PC-error %s\n", BIT(data, 0) ? "active" : "inactive"); + LOGMIC(" PB1 - %s generated by MPU\n", BIT(data, 1) ? "VMAX" : "VMA 1"); + LOGMIC(" PB2 - %s generated by DMA\n", BIT(data, 2) ? "VMAX" : "VMA 1"); + LOGMIC(" PB3 - %sKB Display Memory\n", BIT(data, 3) ? "4" : "8"); + LOGMIC(" PB4 - Option Char Generator %s\n", BIT(data, 4) ? "enabled" : "disabled"); + LOGMIC(" PB5 - MPU Address Mode %s\n", BIT(data, 5) ? "1" : "0"); + LOGMIC(" PB6 - Reset of devices %s\n", BIT(data, 6) ? "active" : "inactive"); + }); + + m_mic_pia->readpa_handler().set([this](offs_t offset) -> uint8_t + { + uint8_t data = (1U << 2); // MCU is not in test mode + LOGMIC("<-MIC PIA: Port A read\n"); + LOGMIC(" PA2 - MCU test mode %s\n", BIT(data, 2) ? "inactive" : "active"); + return 0; + }); + m_mic_pia->readpb_handler().set([this](offs_t offset) -> uint8_t { LOGMIC("<-MIC PIA: Port B read\n"); return 0;}); + m_mic_pia->readca1_handler().set([this](offs_t offset) -> uint8_t { LOGMIC("<-MIC PIA: CA1 read\n"); return 0;}); + m_mic_pia->readca2_handler().set([this](offs_t offset) -> uint8_t { LOGMIC("<-MIC PIA: CA2 read\n"); return 0;}); + + PIA6821(config, m_dia_pia, 0); // Display PIA, controls how the CRTC accesses memory etc + m_dia_pia->readcb1_handler().set([this](offs_t offset) -> uint8_t { LOGDIA("DIA PIA: CB1_r\n"); return 0;}); + m_dia_pia->cb2_handler().set([this](offs_t offset, uint8_t data) { LOGDIA("DIA PIA: CB2_w %d\n", data); }); + m_dia_pia->writepa_handler().set([this](offs_t offset, uint8_t data) { LOGDIA("DIA PIA: PA_w %02x\n", data); }); + m_dia_pia->writepb_handler().set([this](offs_t offset, uint8_t data) { LOGDIA("DIA PIA: PB_w %02x\n", data); }); + m_dia_pia->readpa_handler().set([this](offs_t offset) -> uint8_t { LOGDIA("DIA PIA: PA_r\n"); return 0;}); + m_dia_pia->readpb_handler().set([this](offs_t offset) -> uint8_t { LOGDIA("DIA PIA: PB_r\n"); return 0;}); + m_dia_pia->readca1_handler().set([this](offs_t offset) -> uint8_t { LOGDIA("DIA PIA: CA1_r\n"); return 0;}); + m_dia_pia->readca2_handler().set([this](offs_t offset) -> uint8_t { LOGDIA("DIA PIA: CA2_r\n"); return 0;}); + + /* The ACIA RxC and TxC are fed from the systemclock divided through a by 14 dividing 74163, from the tech manual: + "A clock of 76 kHz is provided for the ACIA by the timing logic. ACIA divides this clock by 64 (Bit transfer rate 1188 Hz) and + synchronizes internally to received data. Furthermore ACIA may provide interrupt (at level 3) when transmit register is empty, + receive register is full or an error has occured. */ + ACIA6850(config, m_kbd_acia, XTAL(19'170'000) / 18); + CLOCK(config, "acia_clock", (XTAL(19'170'000) / 18) / 14 ).signal_handler().set([this](int state) { m_kbd_acia->write_txc(state); m_kbd_acia->write_rxc(state); }); + m_kbd_acia->irq_handler().set("irq3", FUNC(input_merger_device::in_w<3>)); + m_kbd_acia->txd_handler().set([this](bool state) + { + if (m_txd != state) + { + LOGBITS("4110->KBD: %d\n", state); + m_txd = state; + m_kbd->rxd_w(m_txd); + } + }); + + MC6854(config, m_tia_adlc, XTAL(19'170'000) / 18); + m_tia_adlc->out_irq_cb().set("irq7", FUNC(input_merger_device::in_w<7>)); + m_tia_adlc->out_rdsr_cb().set([this](bool state){ LOGDMA("TIA ADLC RDSR: %d\n", state); m_tia_dma->dreq_w<1>(state); }); + m_tia_adlc->out_tdsr_cb().set([this](bool state){ LOGDMA("TIA ADLC TDSR: %d\n", state); m_tia_dma->dreq_w<0>(state); }); + + MC6844(config, m_tia_dma, XTAL(19'170'000) / 18); + //m_tia_dma->out_int_callback().set([this](bool state){ LOGDMA("TIA DMA IRQ: %d\n", state); }); // Used as DEND (end of dma) towards the ADLC through some logic + m_tia_dma->out_drq1_callback().set([this](bool state){ LOGDMA("TIA DMA DRQ1: %d\n", state); m_tia_dma->dgrnt_w(state); }); + //m_tia_dma->out_drq2_callback().set([this](bool state){ LOGDMA("TIA DMA DRQ2: %d\n", state); }); // Not connected + m_tia_dma->in_ior_callback<1>().set([this](offs_t offset) -> uint8_t { return m_tia_adlc->dma_r(); }); + m_tia_dma->out_memw_callback().set([this](offs_t offset, uint8_t data) { m_maincpu->space(AS_PROGRAM).write_byte(offset, data); }); + + /* 74LS273 latch inputs of interruptt sources */ + INPUT_MERGER_ANY_HIGH(config, "irq0").output_handler().set(FUNC(alfaskop4110_state::irq_w<0>)); + INPUT_MERGER_ANY_HIGH(config, "irq1").output_handler().set(FUNC(alfaskop4110_state::irq_w<1>)); + INPUT_MERGER_ANY_HIGH(config, "irq2").output_handler().set(FUNC(alfaskop4110_state::irq_w<2>)); + INPUT_MERGER_ANY_HIGH(config, "irq3").output_handler().set(FUNC(alfaskop4110_state::irq_w<3>)); + INPUT_MERGER_ANY_HIGH(config, "irq4").output_handler().set(FUNC(alfaskop4110_state::irq_w<4>)); + INPUT_MERGER_ANY_HIGH(config, "irq5").output_handler().set(FUNC(alfaskop4110_state::irq_w<5>)); + INPUT_MERGER_ANY_HIGH(config, "irq6").output_handler().set(FUNC(alfaskop4110_state::irq_w<6>)); + INPUT_MERGER_ANY_HIGH(config, "irq7").output_handler().set(FUNC(alfaskop4110_state::irq_w<7>)); +} + +void alfaskop4110_state::machine_start() +{ + save_item(NAME(m_irq)); + save_item(NAME(m_imsk)); + timer_set(attotime::from_msec(5000), TIMER_POLL_START); + + // Hard wired inputs + m_kbd_acia->write_cts(0); + m_kbd_acia->write_dcd(0); +} + +void alfaskop4110_state::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + // Debug feature, inserts a poll SDLC frame through the ADLC, it ends up at address 0x140 in RAM through DMA + switch (id) + { + case TIMER_POLL_START: + /* The serial transfer of 8 bits is complete. Now trigger INT7. */ + LOGADLC("Starting poll message\n"); + m_tia_adlc->set_rx(0); + timer_set(attotime::from_hz(300000), TIMER_POLL_BIT); + break; + case TIMER_POLL_BIT: + if (flank) + { + if (index != 0 && index != 7 && BIT(txBuf[index], (pos % 8)) && ones == 5) + { + LOGADLC("%d%c", 2, (pos % 8) == 7 ? '\n' : ' '); + m_tia_adlc->set_rx(0); + ones = 0; + } + else + { + LOGADLC("%d%c", BIT(txBuf[index], (pos % 8)), (pos % 8) == 7 ? '\n' : ' '); + m_tia_adlc->set_rx(BIT(txBuf[index], (pos % 8))); + if (index != 0 && index != 7 && BIT(txBuf[index], (pos % 8))) + ones++; + else + ones = 0; + pos++; + index = pos / 8; + } + } + m_tia_adlc->rxc_w(flank ? 1 : 0); + if (index < 8) + timer_set(attotime::from_hz(300000) / 2, TIMER_POLL_BIT); + flank = !flank; + break; + } +} + +void alfaskop4110_state::machine_reset() +{ + m_irq = 0x00; + m_kbd->rst_line_w(ASSERT_LINE); + + // Hard wired inputs + m_kbd_acia->write_cts(0); + m_kbd_acia->write_dcd(0); } void alfaskop4120_state::alfaskop4120(machine_config &config) @@ -237,7 +597,7 @@ void alfaskop4120_state::alfaskop4120(machine_config &config) M6800(config, m_maincpu, XTAL(19'170'000) / 18); // Verified from service manual m_maincpu->set_addrmap(AS_PROGRAM, &alfaskop4120_state::mem_map); - PIA6821(config, m_micpia, 0); // Main board PIA + PIA6821(config, m_mic_pia, 0); // Main Board PIA PIA6821(config, m_fdapia, 0); // Floppy Disk PIA } @@ -247,7 +607,7 @@ void alfaskop4101_state::alfaskop4101(machine_config &config) M6800(config, m_maincpu, XTAL(19'170'000) / 18); // Verified from service manual m_maincpu->set_addrmap(AS_PROGRAM, &alfaskop4101_state::mem_map); - PIA6821(config, m_micpia, 0); // Main board PIA + PIA6821(config, m_mic_pia, 0); // Main board PIA } /* ROM definitions */ @@ -257,6 +617,9 @@ ROM_START( alfaskop4110 ) // Display Unit ROM_REGION( 0x800, "chargen", ROMREGION_ERASEFF ) ROM_LOAD( "e3405972067500.bin", 0x0000, 0x0400, CRC(fb12b549) SHA1(53783f62c5e51320a53e053fbcf8b3701d8a805f)) ROM_LOAD( "e3405972067600.bin", 0x0400, 0x0400, CRC(c7069d65) SHA1(587efcbee036d4c0c5b936cc5d7b1f97b6fe6dba)) + ROM_REGION( 0xff, PLA1_TAG, 0 ) + //ROM_LOAD( "dtc_a_e34062_0100_ic50_e3405970303601_ml.bin", 0x00, 0xf5, CRC(b37395f2) SHA1(a00dc77d4bef084c0ddceef618986d83c69b1d65) ) // Signetics_N82S100N.bin MAXLOADER format + ROM_LOAD( "dtc_a_e34062_0100_ic50_e3405970303601.bin", 0x00, 0xfa, CRC(16339b7a) SHA1(9b313a7526460dc9bcedfda25bece91c924f0ddc) ) // Signetics_N82S100N.bin DATAIO format ROM_END ROM_START( alfaskop4120 ) // Flexible Disk Unit @@ -271,7 +634,7 @@ ROM_END /* Driver(S) */ -// Only 4101 may exist as a driver in the end making the 4110 and 4120 as slots devices on the SS3 bus, time will tell +// Only 4101 should exist as a driver in the end, making the 4110 and 4120 as slots devices on the SS3 bus, time will tell // YEAR NAME PARENT COMPAT MACHINE INPUT CLASS INIT COMPANY FULLNAME FLAGS COMP( 1984, alfaskop4110, 0, 0, alfaskop4110, alfaskop4110, alfaskop4110_state, empty_init, "Ericsson", "Alfaskop Display Unit 4110", MACHINE_IS_SKELETON) |