diff --git a/scripts/src/bus.lua b/scripts/src/bus.lua index 7341724f85c7f..b536bc012c18d 100644 --- a/scripts/src/bus.lua +++ b/scripts/src/bus.lua @@ -5809,3 +5809,17 @@ if (BUSES["HEATH_TLB_CONNECTOR"]~=null) then MAME_DIR .. "src/devices/bus/heathzenith/h19/tlb.h", } end + +--------------------------------------------------- +-- +--@src/devices/bus/super8008/super8008.h,BUSES["SUPER8008"] = true +--------------------------------------------------- + +if (BUSES["SUPER8008"]~=null) then + files { + MAME_DIR .. "src/devices/bus/super8008/super8008.cpp", + MAME_DIR .. "src/devices/bus/super8008/super8008.h", + MAME_DIR .. "src/devices/bus/super8008/super8008_blaster.cpp", + MAME_DIR .. "src/devices/bus/super8008/super8008_blaster.h", + } +end diff --git a/src/devices/bus/super8008/super8008.cpp b/src/devices/bus/super8008/super8008.cpp new file mode 100644 index 0000000000000..0928004b06b38 --- /dev/null +++ b/src/devices/bus/super8008/super8008.cpp @@ -0,0 +1,196 @@ +// license:BSD-3-Clause +// copyright-holders:Jeremy English +/********************************************************************** + + 8008-Super Bus Device aka ThunderDome + + Scott's 8008 Supercomputer a.k.a. Master Blaster + by Dr. Scott M. Baker + +**********************************************************************/ + +#include "emu.h" +#include "super8008.h" + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +DEFINE_DEVICE_TYPE(SUPER8008_BUS, super8008_bus_device, "super8008_bus", "super8008 bus") +DEFINE_DEVICE_TYPE(SUPER8008_SLOT, super8008_slot_device, "super8008_slot", "super8008 slot") + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// device_super8008_card_interface - constructor +//------------------------------------------------- + +device_super8008_card_interface::device_super8008_card_interface(const machine_config &mconfig, device_t &device) : + device_interface(device, "super8008bus"), + m_bus(nullptr) +{ +} + +void device_super8008_card_interface::interface_pre_start() +{ + if (!m_bus) + throw device_missing_dependencies(); +} + + +//------------------------------------------------- +// super8008_slot_device - constructor +//------------------------------------------------- +super8008_slot_device::super8008_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : + device_t(mconfig, SUPER8008_SLOT, tag, owner, clock), + device_single_card_slot_interface(mconfig, *this), + m_bus(*this, DEVICE_SELF_OWNER) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void super8008_slot_device::device_start() +{ + device_super8008_card_interface *const dev = get_card_device(); + if (dev) + m_bus->add_card(*dev); + +} + + +//------------------------------------------------- +// super8008_bus_device - constructor +//------------------------------------------------- + +super8008_bus_device::super8008_bus_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : + device_t(mconfig, SUPER8008_BUS, tag, owner, clock) +{ + m_ext_take = 0; +} + +super8008_bus_device::~super8008_bus_device() +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void super8008_bus_device::device_start() +{ +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void super8008_bus_device::device_reset() +{ +} + +void super8008_bus_device::device_post_load() +{ +} + +//------------------------------------------------- +// add_card - add card +//------------------------------------------------- + +void super8008_bus_device::add_card(device_super8008_card_interface &card) +{ + card.m_bus = this; + m_device_list.emplace_back(card); +} + +void super8008_bus_device::ext_write(offs_t offset, uint8_t data) +{ + //ext_cs is pulled high through a 10k resistor and is active low + if (m_ext_cs) + { + return; + } + + for (device_super8008_card_interface &entry : m_device_list) + { + entry.ext_write(offset, data); + } +} + +uint8_t super8008_bus_device::ext_read(offs_t offset) +{ + uint8_t data = 0; + + if (m_ext_cs) + { + return data; + } + + for (device_super8008_card_interface &entry : m_device_list) + { + data |= entry.ext_read(offset); + } + + return data; +} + +void super8008_bus_device::ext_take(int state) +{ + for (device_super8008_card_interface &entry : m_device_list) + { + entry.ext_take(state); + } + m_ext_take = state; +} + +void super8008_bus_device::ext_int() +{ + for (device_super8008_card_interface &entry : m_device_list) + { + entry.ext_int(); + } +} + +void super8008_bus_device::ext_reset() +{ + for (device_super8008_card_interface &entry : m_device_list) + { + entry.ext_reset(); + } +} + +void super8008_bus_device::ext_req() +{ + for (device_super8008_card_interface &entry : m_device_list) + { + entry.ext_req(); + } +} + +uint8_t super8008_bus_device::ext_run() +{ + uint8_t run_status = 0; + for (device_super8008_card_interface &entry : m_device_list) + { + run_status |= entry.ext_run(); + } + return run_status; +} + + +//Cards +#include "super8008_blaster.h" +void super8008_bus_devices(device_slot_interface &device) +{ + device.option_add("super8008_blaster", SUPER8008_BLASTER); +} diff --git a/src/devices/bus/super8008/super8008.h b/src/devices/bus/super8008/super8008.h new file mode 100644 index 0000000000000..9d049735b1860 --- /dev/null +++ b/src/devices/bus/super8008/super8008.h @@ -0,0 +1,186 @@ +// license:BSD-3-Clause +// copyright-holders:Jeremy English +/*************************************************************************** + + 8008-Super Bus Device aka ThunderDome + + + Scott's 8008 Supercomputer a.k.a. Master Blaster + by Dr. Scott M. Baker + + Schematics: + https://github.com/sbelectronics/8008-super + + ROM Source Code: + https://github.com/sbelectronics/h8/tree/master/h8-8008 + + Demo: + https://youtu.be/wurKTPdPhrI?si=aerTbgHIFm_8YwU2 + + Write up: + https://www.smbaker.com/master-blaster-an-8008-supercomputer + + MAME driver for Jim Loos 8008-SBC + src/mame/homebrew/sbc8008.cpp + + This computer is based on Jim Loos 8008-SBC: + https://github.com/jim11662418/8008-SBC + +============================================================================ + + 1 GND 2 NCO + 3 EXT_A0 4 EXT_TAKE0 + 5 EXT_A1 6 EXT_TAKE1 + 7 EXT_A2 8 EXT_TAKE2 + 9 EXT_A3 10 EXT_TAKE3 + 11 EXT_A4 12 EXT_TAKE4 + 13 EXT_A5 14 EXT_TAKE5 + 15 EXT_A6 16 EXT_TAKE6 + 17 EXT_A7 18 EXT_TAKE7 + 19 EXT_A8 20 EXT_RUN0 + 21 EXT_A9 22 EXT_RUN1 + 23 EXT_A10 24 EXT_RUN2 + 25 EXT_A11 26 EXT_RUN3 + 27 EXT_A12 28 EXT_RUN4 + 29 EXT_A13 30 EXT_RUN5 + 31 GND 32 EXT_RUN6 + 33 EXT_D0 34 EXT_RUN7 + 35 EXT_D1 36 EXT_REQ0 + 37 EXT_D2 38 EXT_REQ1 + 39 EXT_D3 40 EXT_REQ2 + 41 EXT_D4 42 EXT_REQ3 + 43 EXT_D5 44 EXT_REQ4 + 45 EXT_D6 46 EXT_REQ5 + 47 EXT_D7 48 EXT_REQ6 + 49 GND 50 EXT_REQ7 + 51 EXT_CS 52 EXT_INT0 + 53 EXT_RD 54 EXT_INT1 + 55 EXT_WR 56 EXT_INT2 + 57 EXT_RESET 58 EXT_INT3 + 59 EXT_BUSDIR 60 EXT_INT4 + 61 EXT_WRP 62 EXT_INT5 + 63 EXT_TAKEW 64 EXT_INT6 + 65 NC 66 EXT_INT7 + 67 +8V 68 NC + + +***************************************************************************/ + +#ifndef MAME_BUS_SUPER8008_SUPER8008_H +#define MAME_BUS_SUPER8008_SUPER8008_H + +#pragma once + +#include +#include + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +class super8008_bus_device; + +// ======================> device_super8008_card_interface + +class device_super8008_card_interface : public device_interface +{ + friend class super8008_bus_device; + +public: + + virtual void ext_write( offs_t offset, uint8_t data) {} + virtual uint8_t ext_read(offs_t offset) {return 0;} + virtual void ext_int(){} + virtual void ext_reset(){} + virtual void ext_req(){} + virtual void ext_take(int state) { } + virtual uint8_t ext_run() {return 0;} + + +protected: + // construction/destruction + device_super8008_card_interface(const machine_config &mconfig, device_t &device); + + virtual void interface_pre_start() override; + + super8008_bus_device *m_bus; + +}; + + + +// ======================> super8008_bus_device + +class super8008_bus_device : public device_t +{ +public: + // construction/destruction + super8008_bus_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); + ~super8008_bus_device(); + + void add_card(device_super8008_card_interface &card); + + virtual void ext_write( offs_t offset, uint8_t data); + virtual uint8_t ext_read(offs_t offset); + void ext_take(int state); + void ext_cs(uint8_t state){ m_ext_cs = state;} + void ext_int(); + void ext_reset(); + void ext_req(); + uint8_t ext_run(); + +protected: + virtual void device_start() override; + virtual void device_reset() override; + virtual void device_post_load() override; + + +private: + using card_vector = std::vector >; + + card_vector m_device_list; + + uint8_t m_ext_take; + uint8_t m_ext_cs; +}; + + +// ======================> super8008_slot_device + +class super8008_slot_device : public device_t, public device_single_card_slot_interface +{ +public: + // construction/destruction + template + super8008_slot_device(machine_config const &mconfig, char const *tag, device_t *owner, T &&opts, char const *dflt) + : super8008_slot_device(mconfig, tag, owner, DERIVED_CLOCK(1, 1)) + { + option_reset(); + opts(*this); + set_default_option(dflt); + set_fixed(false); + } + super8008_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); + + template void set_bus(T &&tag) { m_bus.set_tag(std::forward(tag)); } + +protected: + // device-level overrides + virtual void device_start() override; + +private: + required_device m_bus; +}; + + + +// device type definition +DECLARE_DEVICE_TYPE(SUPER8008_BUS, super8008_bus_device) +DECLARE_DEVICE_TYPE(SUPER8008_SLOT, super8008_slot_device) + +void super8008_bus_devices(device_slot_interface &device); + + +#endif // MAME_BUS_super8008_super8008_H diff --git a/src/devices/bus/super8008/super8008_blaster.cpp b/src/devices/bus/super8008/super8008_blaster.cpp new file mode 100644 index 0000000000000..6b1a5a18a1cd7 --- /dev/null +++ b/src/devices/bus/super8008/super8008_blaster.cpp @@ -0,0 +1,341 @@ +// license:BSD-3-Clause +// copyright-holders:Jeremy English +/********************************************************************* + + Blaster for Scott's 8008 Supercomputer a.k.a. Master Blaster + by Dr. Scott M. Baker + + Schematics: + https://github.com/sbelectronics/8008-super + + ROM Source Code: + https://github.com/sbelectronics/h8/tree/master/h8-8008 + + Demo: + https://youtu.be/wurKTPdPhrI?si=aerTbgHIFm_8YwU2 + + Write up: + https://www.smbaker.com/master-blaster-an-8008-supercomputer + + This computer is based on Jim Loos 8008-SBC: + https://github.com/jim11662418/8008-SBC + +*********************************************************************/ + +#include "emu.h" +#include "cpu/i8008/i8008.h" +#include "machine/clock.h" +#include "machine/ram.h" +#include "super8008_blaster.h" +#include "string.h" + +class super8008_blaster_device : public device_t, public device_super8008_card_interface +{ +public: + // construction/destruction + super8008_blaster_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock); + + + +protected: + + // I did not see another way to get the S0, S1 and S2 pins from the 8008. + // These pins are used to identify the CPUs running states such as stopped. + // + // In the blaster pld, this state is the "running" output pin which goes to + // the set of ext_run jumpers and then on to the bus. + // + // I am including the enums from the 8008 here so that I'm able to access + // the stopped signal. + + enum + { + I8008_PC, + I8008_A,I8008_B,I8008_C,I8008_D,I8008_E,I8008_H,I8008_L, + I8008_ADDR1,I8008_ADDR2,I8008_ADDR3,I8008_ADDR4,I8008_ADDR5,I8008_ADDR6,I8008_ADDR7,I8008_ADDR8, + I8008_STOPPED + }; + + // device-level overrides + virtual void device_start() override; + virtual void device_reset() override; + virtual void device_post_load() override; + virtual ioport_constructor device_input_ports() const override; + virtual void device_add_mconfig(machine_config &config) override; + + virtual void ext_write( offs_t offset, uint8_t data) override; + virtual uint8_t ext_read(offs_t offset) override; + virtual void ext_int() override; + virtual void ext_reset() override; + virtual void ext_req() override; + virtual void ext_take(int state) override; + virtual uint8_t ext_run() override; + + uint8_t blaster_memory_read(offs_t offset); + void blaster_memory_write(offs_t offset, uint8_t data); + void blaster_mem(address_map &map); + void blaster_io(address_map &map); + + int handle_irq(device_t &device, int data); + +private: + + uint8_t take_state; + required_device m_maincpu; + required_device m_ram; + + required_ioport m_ext_take; + required_ioport m_ext_run; + required_ioport m_ext_req; + required_ioport m_ext_int; + + //TODO(jhe) I'm not sure how to dynamically bind these based on the + //jumpers. I'm binding all of them for now and setting values based on the + //TAKE jumper. + output_finder<8, 8> m_leds; + + + void serial_leds(uint8_t data); + void debug_leds(int bank, int data); +}; + +DEFINE_DEVICE_TYPE_PRIVATE(SUPER8008_BLASTER, device_super8008_card_interface, super8008_blaster_device, "super8008_blaster", "Blaster Card") + +super8008_blaster_device::super8008_blaster_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) + : device_t(mconfig, SUPER8008_BLASTER, tag, owner, clock) + , device_super8008_card_interface(mconfig, *this) + , m_maincpu(*this, "blaster_cpu") + , m_ram(*this, "ram") + , m_ext_take(*this, "EXT_TAKE") + , m_ext_run(*this, "EXT_RUN") + , m_ext_req(*this, "EXT_REQ") + , m_ext_int(*this, "EXT_INT") + , m_leds(*this, "led%u_%u", 0U, 0U) //First index is the blaster number, second is the individual led +{ +} + +void super8008_blaster_device::device_start() +{ + m_leds.resolve(); +} + +void super8008_blaster_device::ext_int() +{ + m_maincpu->set_input_line(0, HOLD_LINE); +} + +void super8008_blaster_device::device_reset() +{ + //Power-on-reset triggers the interrupt + ext_int(); +} + +void super8008_blaster_device::device_post_load() +{ + //Power-on-reset triggers the interrupt + ext_int(); +} + + +//The /Take signal controls which buffer on blaster has access to the 16kb of +//ram. If an internal read happens, while blaster is taken, the local 8008 +//will get back 0 since the data lines will be tied low. This will HALT the +//internal CPU. + +uint8_t super8008_blaster_device::blaster_memory_read(offs_t offset) +{ +#if 1 + int jumper = m_ext_take->read(); + if (BIT(take_state, jumper) && 0 <= offset && offset < m_ram->size()){ + uint8_t data = m_ram->pointer()[offset]; + return data; + } else { + //Selected when the ext_take line is low + return 0x0; + } +#else + return m_ram->pointer()[offset]; +#endif +} + + +void super8008_blaster_device::blaster_memory_write(offs_t offset, uint8_t data) +{ + int jumper = m_ext_take->read(); + //Only allow writes when the correct buffer is activated. + if (BIT(take_state, jumper) && 0 <= offset && offset < m_ram->size()){ + m_ram->pointer()[offset] = data; + } +} + +void super8008_blaster_device::blaster_mem(address_map &map) +{ + map(0x0000, 0x3fff).rw( + FUNC(super8008_blaster_device::blaster_memory_read), + FUNC(super8008_blaster_device::blaster_memory_write)); +} + +IRQ_CALLBACK_MEMBER(super8008_blaster_device::handle_irq) +{ + m_maincpu->set_input_line(0, CLEAR_LINE); + return 0xC0;//return a NOP +} + +void super8008_blaster_device::device_add_mconfig(machine_config &config) +{ + + I8008(config, m_maincpu, XTAL(1'000'000)/2); + + m_maincpu->set_addrmap(AS_PROGRAM, &super8008_blaster_device::blaster_mem); + m_maincpu->set_irq_acknowledge_callback(FUNC(super8008_blaster_device::handle_irq)); + m_maincpu->set_addrmap(AS_IO, &super8008_blaster_device::blaster_io); + + RAM(config, m_ram).set_default_size("32K"); +} + +static INPUT_PORTS_START( super8008_blaster_jumpers ) + PORT_START("EXT_TAKE") + PORT_CONFNAME( 0xff, 0, "External Take" ) + PORT_CONFSETTING( 0, "0" ) + PORT_CONFSETTING( 1, "1" ) + PORT_CONFSETTING( 2, "2" ) + PORT_CONFSETTING( 3, "3" ) + PORT_CONFSETTING( 4, "4" ) + PORT_CONFSETTING( 5, "5" ) + PORT_CONFSETTING( 6, "6" ) + PORT_START("EXT_RUN") + PORT_CONFNAME( 0xff, 0, "External Run" ) + PORT_CONFSETTING( 0, "0" ) + PORT_CONFSETTING( 1, "1" ) + PORT_CONFSETTING( 2, "2" ) + PORT_CONFSETTING( 3, "3" ) + PORT_CONFSETTING( 4, "4" ) + PORT_CONFSETTING( 5, "5" ) + PORT_CONFSETTING( 6, "6" ) + PORT_START("EXT_REQ") + PORT_CONFNAME( 0xff, 0, "External Request" ) + PORT_CONFSETTING( 0, "0" ) + PORT_CONFSETTING( 1, "1" ) + PORT_CONFSETTING( 2, "2" ) + PORT_CONFSETTING( 3, "3" ) + PORT_CONFSETTING( 4, "4" ) + PORT_CONFSETTING( 5, "5" ) + PORT_CONFSETTING( 6, "6" ) + PORT_START("EXT_INT") + PORT_CONFNAME( 0xff, 0, "External Interrupt" ) + PORT_CONFSETTING( 0, "0" ) + PORT_CONFSETTING( 1, "1" ) + PORT_CONFSETTING( 2, "2" ) + PORT_CONFSETTING( 3, "3" ) + PORT_CONFSETTING( 4, "4" ) + PORT_CONFSETTING( 5, "5" ) + PORT_CONFSETTING( 6, "6" ) +INPUT_PORTS_END + +ioport_constructor super8008_blaster_device::device_input_ports() const +{ + return INPUT_PORTS_NAME( super8008_blaster_jumpers ); +} + +// The /takew signal can be setup based on a jumper on blaster. The jumper allows +// for either the ext_take7 line or LED7 line to set /takew. +// +// From the blog post: +// "For example, I can set TAKE=1 and assert /TAKEW. This will cause a read to +// come from Blaster#1, but a write to go out to all Blasters." +// +// TODO: Add a configurable jumper. I don't need it now since the demo code is written +// for the jumper to be in the EXT_TAKE7 configuration. + +void super8008_blaster_device::ext_write(offs_t offset, uint8_t data) +{ + int jumper = m_ext_take->read(); + + if (!BIT(take_state, jumper) || !BIT(take_state, 7)) + { + if (0 <= offset && offset < m_ram->size()) + { + m_ram->pointer()[offset] = data; + } + } +} + +uint8_t super8008_blaster_device::ext_read(offs_t offset) +{ + int jumper = m_ext_take->read(); + //Selected when the ext_take line is low + if (!BIT(take_state, jumper) && 0 <= offset && offset < m_ram->size()) + { + return m_ram->pointer()[offset]; + } + return 0; +} + +void super8008_blaster_device::debug_leds(int bank, int data) +{ + int id = bank; + if (0 <= id && id < 8) { + for(int i = 0; i < 8; i++){ + m_leds[id][i] = BIT(data, 7-i); + } + } +} + +//From the IO PLD +// /* memory and I/O strobes */ +// MEMRD = (t3 & (pci # pcr) & SYNC) # (TAKEN & EXT_RD); +// MEMWR = (t3 & pcw & !SYNC & PHASE2) # (TAKEN & EXT_WR); +// TAKEN = (EXT_CS & EXT_TAKEOVER) # (EXT_CS & TAKEW); + +void super8008_blaster_device::ext_take(int state) +{ + take_state = state; +} + +void super8008_blaster_device::serial_leds(uint8_t data) +{ + int id = m_ext_take->read(); + if (0 <= id && id < 8) { + for(int i = 0; i < 8; i++){ + m_leds[id][i] = BIT(data, 7-i); + } + } +} + +uint8_t super8008_blaster_device::ext_run() +{ + //This is shifted by the ext_run jumper + int id = m_ext_run->read(); + return m_maincpu->state_int(I8008_STOPPED) << id; +} + +void super8008_blaster_device::blaster_io(address_map &map) +{ + // Description of IO ports from monitor.asm + // + // serial I/O at 2400 bps N-8-1 + // + // INPORT equ 0 ; serial input port address + // OUTPORT equ 08H ; serial output port address + // + // out 10 ; clear the EPROM bank switch address outputs A13 and A14 + // out 09 ; turn off orange LEDs + // out 08 ; set serial output high (mark) + // in 1 ; reset the bootstrap flip-flop internal to GAL22V10 #2 + + + map.global_mask(0xff); // use 8-bit ports + map.unmap_value_high(); // unmapped addresses return 0xff + map(0x08, 0x08).w(FUNC(super8008_blaster_device::serial_leds)); +} + +void super8008_blaster_device::ext_reset() +{ + m_maincpu->reset(); +} + +void super8008_blaster_device::ext_req() +{ + +} + diff --git a/src/devices/bus/super8008/super8008_blaster.h b/src/devices/bus/super8008/super8008_blaster.h new file mode 100644 index 0000000000000..86ebf050b84f7 --- /dev/null +++ b/src/devices/bus/super8008/super8008_blaster.h @@ -0,0 +1,38 @@ +// license:BSD-3-Clause +// copyright-holders:Jeremy English +/********************************************************************* + + Blaster for Scott's 8008 Supercomputer a.k.a. Master Blaster + by Dr. Scott M. Baker + + Schematics: + https://github.com/sbelectronics/8008-super + + ROM Source Code: + https://github.com/sbelectronics/h8/tree/master/h8-8008 + + Demo: + https://youtu.be/wurKTPdPhrI?si=aerTbgHIFm_8YwU2 + + Write up: + https://www.smbaker.com/master-blaster-an-8008-supercomputer + + MAME driver for Jim Loos 8008-SBC + src/mame/homebrew/sbc8008.cpp + + This computer is based on Jim Loos 8008-SBC: + https://github.com/jim11662418/8008-SBC + +*********************************************************************/ + +#ifndef MAME_BUS_SUPER8008_SUPER8008_BLASTER_H +#define MAME_BUS_SUPER8008_SUPER8008_BLASTER_H + +#pragma once + +#include "super8008.h" + +// device type declaration +DECLARE_DEVICE_TYPE(SUPER8008_BLASTER, device_super8008_card_interface); + +#endif // MAME_BUS_SUPER8008_SUPER8008_BLASTER_H diff --git a/src/devices/cpu/i8008/i8008.cpp b/src/devices/cpu/i8008/i8008.cpp index 2c997f30c4fc1..394e6a0906868 100644 --- a/src/devices/cpu/i8008/i8008.cpp +++ b/src/devices/cpu/i8008/i8008.cpp @@ -94,6 +94,8 @@ void i8008_device::device_start() for (int addrnum = 0; addrnum < 8; addrnum++) state_add(I8008_ADDR1 + addrnum, string_format("ADDR%d", addrnum + 1).c_str(), m_ADDR[addrnum].w.l).mask(0xfff); + state_add(I8008_STOPPED, "STOPPED", m_HALT); + init_tables(); } diff --git a/src/devices/cpu/i8008/i8008.h b/src/devices/cpu/i8008/i8008.h index 2e6701306a4bc..ae0f7e9a49ed3 100644 --- a/src/devices/cpu/i8008/i8008.h +++ b/src/devices/cpu/i8008/i8008.h @@ -21,7 +21,8 @@ class i8008_device : public cpu_device { I8008_PC, I8008_A,I8008_B,I8008_C,I8008_D,I8008_E,I8008_H,I8008_L, - I8008_ADDR1,I8008_ADDR2,I8008_ADDR3,I8008_ADDR4,I8008_ADDR5,I8008_ADDR6,I8008_ADDR7,I8008_ADDR8 + I8008_ADDR1,I8008_ADDR2,I8008_ADDR3,I8008_ADDR4,I8008_ADDR5,I8008_ADDR6,I8008_ADDR7,I8008_ADDR8, + I8008_STOPPED }; // device-level overrides diff --git a/src/mame/homebrew/sbc8008.cpp b/src/mame/homebrew/sbc8008.cpp new file mode 100644 index 0000000000000..25ebd02def3fd --- /dev/null +++ b/src/mame/homebrew/sbc8008.cpp @@ -0,0 +1,252 @@ +// license:BSD-3-Clause copyright-holders:Jeremy English +// +// MAME driver for Jim Loos's 8008-SBC +// https://github.com/jim11662418/8008-SBC +// +// The SBC contains: +// +// 8008 CPU at 1 Mhz / 4 +// 2 x G22V10 PLDs for logic +// Winbond W27E257 EEPROM +// 6264 RAM +// MAX233 for bit banged serial at 2400 bps N-8-1 +// and a handful of TTL chips +// +// From the PLD file: +// When START is high (on power-up and reset), ROMA14 and ROMA13 are low to +// force the SBC to execute code in the first 8K segment of the EPROM. when +// START is low, ROMA14 and ROMA13 are controlled by the Q3 and Q2 inputs from +// port 10 allowing any one of the four 8K sections of the EPROM to be selected +// for code. +// +// TODO get file transfer working for both hex and binary +// TODO what are outputs 1,2,3,4,5,6,7 doing? +// TODO test importing from other ports + + +#include "emu.h" +#include "cpu/i8008/i8008.h" +#include "machine/ram.h" +#include "bus/rs232/rs232.h" + +#include "sbc8008.lh" + + +namespace +{ + +#define SBC8008_ROM_SIZE (0x2000) + +// State class - derives from driver_device +class sbc8008_state : public driver_device +{ +public: + sbc8008_state(const machine_config &mconfig, device_type type, const char *tag) + : driver_device(mconfig, type, tag) + , m_maincpu(*this, "maincpu") + , m_ram(*this, "ram") + , m_rom(*this, "rom") + , m_rom_bank(*this, "bank") + , m_rs232(*this, "rs232") + , m_leds(*this, "led%u", 0U) + , m_run_led(*this, "run_led") + , m_txd_led(*this, "txd_led") + , m_rxd_led(*this, "rxd_led") + , m_view(*this, "bootview") +{ } + + // This function sets up the machine configuration + void sbc8008(machine_config &config); + +protected: + // address maps for program memory and io memory + void sbc8008_mem(address_map &map); + void sbc8008_io(address_map &map); + + required_device m_maincpu; + required_device m_ram; + required_memory_region m_rom; + required_memory_bank m_rom_bank; + required_device m_rs232; + output_finder<8> m_leds; + output_finder<> m_run_led; + output_finder<> m_txd_led; + output_finder<> m_rxd_led; + memory_view m_view; + + uint8_t bitbang_read(); + void bitbang_write(uint8_t data); + uint8_t port_1_read(); + void port_9_write(uint8_t data); + void port_10_write(uint8_t data); + + virtual void machine_start() override; +}; + +void sbc8008_state::machine_start() +{ + m_leds.resolve(); + m_run_led.resolve(); + m_txd_led.resolve(); + m_rxd_led.resolve(); + + m_run_led = 1; + + m_rom_bank->configure_entry(0, m_rom->base() + 0x2000); + m_rom_bank->configure_entry(1, m_rom->base() + 0x4000); + + m_rom_bank->set_entry(0); + m_view.select(0); +} + +uint8_t sbc8008_state::bitbang_read() +{ + uint8_t result = m_rs232->rxd_r(); + m_rxd_led = BIT(result, 0); + return result; +} + +void sbc8008_state::bitbang_write(uint8_t data) +{ + m_txd_led = BIT(data, 0); + m_rs232->write_txd(BIT(data, 0)); +} + +// Comment from the PLD file: +// +// simulated SR flip-flop made up of cross-connected NAND gates. +// the flip-flop is set when the reset signal from the DS1233 goes low +// (power-on-reset) and cleared when input port 1 is accessed. +// when set, the flip-flop forces all memory accesses to select the +// EPROM. when reset, the flip-flop permits the normal memory map. + +uint8_t sbc8008_state::port_1_read() +{ + m_view.select(1); + return 0; +} + +void sbc8008_state::port_9_write(uint8_t data) +{ + for(int i = 0; i < 8; i++) + { + m_leds[i] = BIT(data, 7-i); + } +} + +void sbc8008_state::port_10_write(uint8_t data) +{ + if (data < 2) + { + m_rom_bank->set_entry(data); + } +} + +void sbc8008_state::sbc8008_mem(address_map &map) +{ + // Comment from monitor.asm + // + // when the reset pushbutton is pressed, the flip-flop is set which generates an interrupt + // and clears the address latches. thus, the first instruction is thus always fetched from + // address 0. the instruction at address 0 must be a single byte transfer instruction in + // order to set the program counter. i.e., it must be one of the RST opcodes. + // + + map(0x0000, 0x3fff).view(m_view); + m_view[0](0x0000, 0x1fff).bankr("bank").mirror(0x2000); + m_view[1](0x0000, 0x1fff).ram(); + m_view[1](0x2000, 0x3fff).bankr("bank"); +} + +void sbc8008_state::sbc8008_io(address_map &map) +{ + // Description of IO ports from monitor.asm + // + // serial I/O at 2400 bps N-8-1 + // + // INPORT equ 0 ; serial input port address + // OUTPORT equ 08H ; serial output port address + // + // out 10 ; clear the EPROM bank switch address outputs A13 and A14 + // out 09 ; turn off orange LEDs + // out 08 ; set serial output high (mark) + // in 1 ; reset the bootstrap flip-flop internal to GAL22V10 #2 + + + map.global_mask(0xff); // use 8-bit ports + map.unmap_value_high(); // unmapped addresses return 0xff + map(0x00, 0x00).r(FUNC(sbc8008_state::bitbang_read)); + map(0x01, 0x01).r(FUNC(sbc8008_state::port_1_read)); + map(0x08, 0x08).w(FUNC(sbc8008_state::bitbang_write)); + map(0x09, 0x09).w(FUNC(sbc8008_state::port_9_write)); + map(0x0A, 0x0A).w(FUNC(sbc8008_state::port_10_write)); +} + +static DEVICE_INPUT_DEFAULTS_START( terminal ) + DEVICE_INPUT_DEFAULTS( "RS232_RXBAUD", 0xff, RS232_BAUD_2400 ) + DEVICE_INPUT_DEFAULTS( "RS232_TXBAUD", 0xff, RS232_BAUD_2400 ) + DEVICE_INPUT_DEFAULTS( "RS232_DATABITS", 0xff, RS232_DATABITS_8 ) + DEVICE_INPUT_DEFAULTS( "RS232_PARITY", 0xff, RS232_PARITY_NONE ) + DEVICE_INPUT_DEFAULTS( "RS232_STOPBITS", 0xff, RS232_STOPBITS_1 ) + DEVICE_INPUT_DEFAULTS( "TERM_CONF", 0x080, 0x080 ) // Auto LF on CR +DEVICE_INPUT_DEFAULTS_END + +void sbc8008_state::sbc8008(machine_config &config) +{ + // The original 1 Mhz crystal goes to a flip-flop which divides by two and then that feeds a PLD which + // produces phase 1 and 2 signals. Simluating the logic gives me this timing diagram. Dividing by 4 provides + // the correct timing for the monitor to bitbang rs232 successfully. + // + // + // +--+ +--+ +--+ +--+ +--+ +--+ +--+ +--+ +--+ + // | | | | | | | | | | | | | | | | | | + // clk : + +--+ +--+ +--+ +--+ +--+ +--+ +--+ +--+ +-- + // +--+ +--+ +--+ +--+ + // | | | | | | | | + // phase1: ---------+ +--------+ +--------+ +--------+ +----- + // +--+ +--+ +--+ +--+ +-- + // | | | | | | | | | + // phase2: ---+ +--------+ +--------+ +--------+ +--------+ + + + I8008(config, m_maincpu, XTAL(1'000'000)/4); + m_maincpu->set_addrmap(AS_PROGRAM, &sbc8008_state::sbc8008_mem); + m_maincpu->set_addrmap(AS_IO, &sbc8008_state::sbc8008_io); + + config.set_default_layout(layout_sbc8008); + + // To provide a console, configure a "default terminal" to connect to the serial port + RS232_PORT(config, m_rs232, default_rs232_devices, "terminal"); + // must be below the DEVICE_INPUT_DEFAULTS_START block + m_rs232->set_option_device_input_defaults("terminal", DEVICE_INPUT_DEFAULTS_NAME(terminal)); + + RAM(config, m_ram).set_default_size("8K"); +} + +// These are the ROM files from Jim Loos's github page +// +// The combinded eprom is not used since we can load the monitor and basic to different areas using the mapper. +// +// 067c016c +// a9b87bc2322404ecbb97842a4fc74c07c9b5535f eprom.bin +// +// 0f3aa663 +// 27679a370b45050b504a2c8f640d20e39afd78d6 monitor.bin +// +// 3d25b65a +// e1db1ba610ed0103d142f889a1995a5d95883c79 scelbal-in-eprom.bin + +ROM_START(sbc8008) + //For the addresses to makes since, setup a huge rom chip and load the roms to the cooresponding machine addresses + ROM_REGION(0x10000, "rom",0) + // Name offset Length hash + ROM_LOAD("monitor.bin", 0x2000, SBC8008_ROM_SIZE, CRC(0f3aa663) SHA1(27679a370b45050b504a2c8f640d20e39afd78d6)) + ROM_LOAD("scelbal-in-eprom.bin", 0x4000, SBC8008_ROM_SIZE, CRC(3d25b65a) SHA1(e1db1ba610ed0103d142f889a1995a5d95883c79)) +ROM_END + +} // anonymous namespace + + +// This ties everything together +// YEAR NAME PARENT COMPAT MACHINE INPUT CLASS INIT COMPANY FULLNAME FLAGS +COMP( 2024, sbc8008, 0, 0, sbc8008, 0, sbc8008_state, empty_init, "Jim Loos", "8008-SBC", MACHINE_NO_SOUND_HW ) diff --git a/src/mame/homebrew/super8008.cpp b/src/mame/homebrew/super8008.cpp new file mode 100644 index 0000000000000..148b96acdd33a --- /dev/null +++ b/src/mame/homebrew/super8008.cpp @@ -0,0 +1,487 @@ +// license:BSD-3-Clause copyright-holders:Jeremy English +// +// Scott's 8008 Supercomputer a.k.a. Master Blaster +// by Dr. Scott M. Baker +// +// Schematics: +// https://github.com/sbelectronics/8008-super +// +// ROM Source Code: +// https://github.com/sbelectronics/h8/tree/master/h8-8008 +// +// Demo: +// https://youtu.be/wurKTPdPhrI?si=aerTbgHIFm_8YwU2 +// +// Write up: +// https://www.smbaker.com/master-blaster-an-8008-supercomputer +// +// MAME driver for Jim Loos 8008-SBC +// https://github.com/jim11662418/8008-SBC +// +// +// This computer is based on Jim Loos 8008-SBC: +// https://github.com/jim11662418/8008-SBC +// +// The Mame driver for the 8008-SBC is named sbc8008. + +#include "emu.h" +#include "cpu/i8008/i8008.h" +#include "machine/clock.h" +#include "machine/i8251.h" +#include "machine/ram.h" +#include "bus/rs232/rs232.h" +#include "bus/super8008/super8008.h" + +#include "super8008.lh" + + +namespace +{ + +const uint8_t NUM_BLASTERS = 7; +const uint8_t MMAP_MASK = 3; + +#define SUPER8008_BUS_TAG "master_blaster" + +struct memory_map_info +{ + uint8_t mmap_index; + uint8_t mmap_value; + uint8_t ra12; + uint8_t ra13; + uint8_t ext_cs; + uint8_t rom_cs; + uint16_t address; +}; + + +// State class - derives from driver_device +class super8008_state : public driver_device +{ +public: + super8008_state(const machine_config &mconfig, device_type type, const char *tag) + : driver_device(mconfig, type, tag) + , m_maincpu(*this, "maincpu") + , m_ram(*this, "ram") + , m_rom(*this, "rom") + , m_rs232(*this, "rs232") + , m_leds(*this, "led%u", 0U) + , m_run_led(*this, "run_led") + , m_txd_led(*this, "txd_led")//TODO(JHE) Remove this + , m_rxd_led(*this, "rxd_led")//TODO(JHE) Remove this + , m_uart(*this, "uart") + , m_bus(*this, SUPER8008_BUS_TAG) + , m_slots(*this, SUPER8008_BUS_TAG ":%u", 1U) + { } + + // This function sets up the machine configuration + void super8008(machine_config &config); + +protected: + //TODO(jhe): Do we have another way to get the S0, S1 and S2 so we know when the PC has been halted? + + // address maps for program memory and io memory + void super8008_mem(address_map &map); + void super8008_io(address_map &map); + + required_device m_maincpu; + required_device m_ram; + required_memory_region m_rom; + required_device m_rs232; + output_finder<8> m_leds; + output_finder<> m_run_led; + output_finder<> m_txd_led; + output_finder<> m_rxd_led; + required_device m_uart; + uint8_t mmap[4] = {0}; //used to simulate the 74670 4x4 memory mapper + //TODO So i'll need 7 of these and I need a way to set the jumpers in the code + optional_device m_bus; + optional_device_array m_slots; + + uint8_t port_1_read(); + void serial_leds(uint8_t data); + + virtual void machine_start() override; + + bool start = true; + uint8_t take_state = 0; + + uint8_t memory_read(offs_t offset); + void memory_write(offs_t offset, uint8_t data); + + void memory_mapper_w(offs_t offset, uint8_t data); + memory_map_info get_mmap_info(offs_t offset); + void log_mmap_info(std::string context, std::string message, offs_t offset, memory_map_info *mmap_info); + + void super8008_blaster1_mem(address_map &map); + void super8008_blaster1_io(address_map &map); + uint8_t blaster_memory_read(offs_t offset); + void blaster_memory_write(offs_t offset, uint8_t data); + + uint8_t ext_stat_r(offs_t offset); + void ext_stat_w(offs_t offset, uint8_t data); + uint8_t blaster1_ext_req(offs_t offset); + void blaster1_serial_leds(offs_t offset, uint8_t data); + + int blaster_irq_callback(device_t &device, int irqlines); +}; + + +void super8008_state::machine_start() +{ + save_item(NAME(start)); + m_leds.resolve(); + m_run_led.resolve(); + m_txd_led.resolve(); + m_rxd_led.resolve(); + + m_run_led = 1; +} + +//TODO I have internal debates about where to put this. The 74670 with this logic is on master but ext_cs is a bus signal. +// I'm keeping it here for now and setting the bus signal. + +memory_map_info super8008_state::get_mmap_info(offs_t offset) +{ + memory_map_info mmap_info; + + mmap_info.mmap_index = (BIT(offset, 13) << 1) | BIT(offset, 12); + mmap_info.mmap_value = mmap[mmap_info.mmap_index & MMAP_MASK]; + mmap_info.ra12 = BIT(mmap_info.mmap_value, 0); + mmap_info.ra13 = BIT(mmap_info.mmap_value, 1); + mmap_info.ext_cs = BIT(mmap_info.mmap_value, 2); + mmap_info.rom_cs = BIT(mmap_info.mmap_value, 3); + mmap_info.address= (offset & 0x0FFF) | ((mmap_info.ra13 << 13) | (mmap_info.ra12 << 12)); + + m_bus->ext_cs(mmap_info.ext_cs); + + return mmap_info; +} + +void super8008_state::log_mmap_info(std::string context, std::string message, offs_t offset, memory_map_info *mmap_info) +{ + logerror("%s:%s ($%04X) mmap_index %X mmap_value %X, ra12 %d, ra13 %d, ext_cs %d, rom_cs %d address %04X\n", + context, + message, + offset, + mmap_info->mmap_index, + mmap_info->mmap_value, + mmap_info->ra12, + mmap_info->ra13, + mmap_info->ext_cs, + mmap_info->rom_cs, + mmap_info->address); +} + +uint8_t super8008_state::memory_read(offs_t offset) +{ + memory_map_info mmap_info = get_mmap_info(offset); + if (start) + { + //Move this into a constant + //A13 and A12 are pulled low during start + return ((uint8_t*)m_rom->base())[offset & 0x0fff]; + } + else if (!mmap_info.ext_cs) + { + //log_mmap_info(machine().describe_context(), "ext_cs read", offset, &mmap_info); + return m_bus->ext_read(mmap_info.address); + } + else + { + if (!mmap_info.rom_cs && 0 <= mmap_info.address && mmap_info.address < m_ram->size()) + { + return ((uint8_t*)m_rom->base())[mmap_info.address]; + } + else + { + if (0 <= mmap_info.address && mmap_info.address < m_ram->size()) + { + return m_ram->pointer()[mmap_info.address]; + } + else + { + return 0; + } + } + } +} + +//Does takew also write to master's memory? That is the only way the conway code would work. +// +// The PLD has the following: +// +// /* RAM is selected if not ROM and not EXTERNAL, +// * ... or if EXTERN and TAKEW and we're about to write +// */ +// RAMCS = (!ROMCS & !EXTCS) # (EXTCS & TAKEW & EXT_WRP); +// +// One thing to be aware of, the input for EXTCS, TAKEW is inverted. +// +// Notes about EXT_WRP from the IO PLD: +// +// /* Set EXT_WRP ahead of the eventual MEMWR that will occur. This is used +// * by blaster when we want to take all blasters on write. It will be gated by +// * blaster by EXT_CS, so there's no need to factor in EXT_CS here. +// * +// * Write cycle occurs during T3 and PCW when SYNC is low. MW is toggled during +// * this cycle when the O2 clock is high. EXT_WRP should come on before the O2 +// * clock +// */ +// + + +void super8008_state::memory_write(offs_t offset, uint8_t data) +{ + memory_map_info mmap_info = get_mmap_info(offset); + if (!mmap_info.rom_cs) + { + log_mmap_info(machine().describe_context(), "ERROR writing to ROM", offset, &mmap_info); + } + else if (!mmap_info.ext_cs){ //Do I need to check the rom_cs here? External is always ram. + //log_mmap_info(machine().describe_context(), "ext_cs write", offset, &mmap_info); + m_bus->ext_write(mmap_info.address, data); + + //TAKEW logic + if (!BIT(take_state, 7) && 0 <= mmap_info.address && mmap_info.address < m_ram->size()) + { + m_ram->pointer()[mmap_info.address] = data; + } + } + else + { + if (0 <= mmap_info.address && mmap_info.address < m_ram->size()) + { + m_ram->pointer()[mmap_info.address] = data; + } + } +} + + +// Comment from the PLD file: +// +// simulated SR flip-flop made up of cross-connected NAND gates. +// the flip-flop is set when the reset signal from the DS1233 goes low +// (power-on-reset) and cleared when input port 1 is accessed. +// when set, the flip-flop forces all memory accesses to select the +// EPROM. when reset, the flip-flop permits the normal memory map. + +uint8_t super8008_state::port_1_read() +{ + start = false;//This is required! + return m_bus->ext_run(); +} + +void super8008_state::serial_leds(uint8_t data) +{ + for(int i = 0; i < 8; i++) + { + m_leds[i] = BIT(data, 7-i); + } +} + +// take, int and req are tied to one of the seven blasters +// reset is shared between all blasters +// +// reset - boostrap all of the blasters +// run - check to see if blaster is running or halted +// int - interrupt the blaster out of the halted state to the running state +// take - connect blasters memory to the bus +// req - ask blaster to go into the halt state (not used in the demos) +// +// reset, run, and int are routed to blaster's cpu +// take is routed to buffers around blasters's 16K of RAM +// ext_cs from the memory mapper is routed to blaster's 16K RAM's cs + +void super8008_state::super8008_state::ext_stat_w(offs_t offset, uint8_t data) +{ + switch(offset) + { + case 0: + //logerror("ext_stat_w %04X take data %02X\n", offset, data); + take_state = data; + m_bus->ext_take(data); + break;//take + case 1: + //logerror("ext_stat_w %04X int data %02X\n", offset, data); + m_bus->ext_int(); + break;//int + case 2: + //logerror("ext_stat_w %04X req data %02X\n", offset, data); + m_bus->ext_req(); + break;//req + case 3: + //logerror("ext_stat_w %04X reset data %02X\n", offset, data); + m_bus->ext_reset(); + break;//reset + + default: + logerror("ext_stat_w INVALID %04X data %02X\n", offset, data);break; + } +} + +void super8008_state::memory_mapper_w(offs_t offset, uint8_t data) +{ + uint8_t index = offset & MMAP_MASK; + mmap[index] = data & 0xff; + //logerror("super-8008 memory mapper write ($%04X) masked ($%04X) data %04X \n", offset, index, mmap[index]); +} + +void super8008_state::super8008_mem(address_map &map) +{ + // Comment from monitor.asm + // + // when the reset pushbutton is pressed, the flip-flop is set which generates an interrupt + // and clears the address latches. thus, the first instruction is thus always fetched from + // address 0. the instruction at address 0 must be a single byte transfer instruction in + // order to set the program counter. i.e., it must be one of the RST opcodes. + // + + map(0x0000, 0x3fff).rw(FUNC(super8008_state::memory_read), FUNC(super8008_state::memory_write)); +} + + +//For checking the status master performs a read (IN) on port 0 with device 0 or 1 and it is a read. This is the same +//interupt that will take use out of start. +//and device 0 is for dipswitches +// device 1 is the external status reuquest +// this triggers a buffer that sets the run byte on the bus +// +// On master the run byte on the bus will set running based on the jumper (board 0 jumped and ext_run0 low => running low) +// running also sets the running led on blaster +// running is set from the pld that is monitoring the state flag. + +//TODO(jhe) once all of this is working sort these +void super8008_state::super8008_io(address_map &map) +{ + + // Description of IO ports from monitor.asm + // + // serial I/O at 2400 bps N-8-1 + // + // INPORT equ 0 ; serial input port address + // OUTPORT equ 08H ; serial output port address + // + // out 10 ; clear the EPROM bank switch address outputs A13 and A14 + // out 09 ; turn off orange LEDs + // out 08 ; set serial output high (mark) + // in 1 ; reset the bootstrap flip-flop internal to GAL22V10 #2 + + + map.global_mask(0xff); // use 8-bit ports + map.unmap_value_high(); // unmapped addresses return 0xff + + map(0x01, 0x01).r(FUNC(super8008_state::port_1_read));//Signals start (come out of the start state) + map(0x02, 0x02).r(m_uart, FUNC(i8251_device::read)); + map(0x03, 0x03).r(m_uart, FUNC(i8251_device::status_r)); + map(0x08, 0x08).w(FUNC(super8008_state::serial_leds)); + map(0x12, 0x12).w(m_uart, FUNC(i8251_device::write)); + map(0x13, 0x13).w(m_uart, FUNC(i8251_device::control_w)); + + //A 74670 4x4 register file is used for the memory mapper + //When not in start mode, address lines A12 and A13 are used + //to reference which of the 4 registers contains the A12 and A13 + //lines of the ram or rom. The ram and rom cs are the high bit + //and bit 3 is used for issuing an external chip select. + map(0x0C, 0x0F).w(FUNC(super8008_state::memory_mapper_w)); + + //This are all output ports + // 14 EXT_STAT_WR - take + // 15 EXT_STAT_WR - int + // 16 EXT_STAT_WR - REQ + // 17 EXT_STAT_WR - RESET + map(0x14, 0x17).w(FUNC(super8008_state::ext_stat_w)); +} + +static DEVICE_INPUT_DEFAULTS_START( terminal ) + DEVICE_INPUT_DEFAULTS( "RS232_RXBAUD" , 0xff, RS232_BAUD_9600 ) + DEVICE_INPUT_DEFAULTS( "RS232_TXBAUD" , 0xff, RS232_BAUD_9600 ) + DEVICE_INPUT_DEFAULTS( "RS232_DATABITS", 0xff, RS232_DATABITS_8 ) + DEVICE_INPUT_DEFAULTS( "RS232_PARITY" , 0xff, RS232_PARITY_NONE ) + DEVICE_INPUT_DEFAULTS( "RS232_STOPBITS", 0xff, RS232_STOPBITS_1 ) + //DEVICE_INPUT_DEFAULTS( "TERM_CONF", 0x080, 0x080 ) // Auto LF on CR +DEVICE_INPUT_DEFAULTS_END + +#define SUPER8008_SETUP_BLASTER_JUMPERS(_num) \ + DEVICE_INPUT_DEFAULTS_START(blaster_input_ ##_num) \ + DEVICE_INPUT_DEFAULTS("EXT_TAKE", 0xff, _num) \ + DEVICE_INPUT_DEFAULTS("EXT_RUN" , 0xff, _num) \ + DEVICE_INPUT_DEFAULTS("EXT_REQ" , 0xff, _num) \ + DEVICE_INPUT_DEFAULTS("EXT_INT" , 0xff, _num) \ + DEVICE_INPUT_DEFAULTS_END + +SUPER8008_SETUP_BLASTER_JUMPERS(0) +SUPER8008_SETUP_BLASTER_JUMPERS(1) +SUPER8008_SETUP_BLASTER_JUMPERS(2) +SUPER8008_SETUP_BLASTER_JUMPERS(3) +SUPER8008_SETUP_BLASTER_JUMPERS(4) +SUPER8008_SETUP_BLASTER_JUMPERS(5) +SUPER8008_SETUP_BLASTER_JUMPERS(6) + + +void super8008_state::super8008(machine_config &config) +{ + //500khz + I8008(config, m_maincpu, XTAL(1'000'000)/2); + m_maincpu->set_addrmap(AS_PROGRAM, &super8008_state::super8008_mem); + m_maincpu->set_addrmap(AS_IO, &super8008_state::super8008_io); + + config.set_default_layout(layout_super8008); + + i8251_device &uart(I8251(config, m_uart, 0)); + + //Schematic says our clock is 4.9152 / 4 + // + //Kludge to get the terminal to work at 9600 baud. The monitor configures + //for 16x so 16*9600hz = 153.600 khz + clock_device &uart_clock(CLOCK(config, "uart_clock", 153600));//4.9152_MHz_XTAL / 4)); + uart_clock.signal_handler().set(m_uart, FUNC(i8251_device::write_txc)); + uart_clock.signal_handler().append(m_uart, FUNC(i8251_device::write_rxc)); + + uart.txd_handler().set(m_rs232, FUNC(rs232_port_device::write_txd)); + uart.dtr_handler().set(m_rs232, FUNC(rs232_port_device::write_dtr)); + uart.rts_handler().set(m_rs232, FUNC(rs232_port_device::write_rts)); + + // To provide a console, configure a "default terminal" to connect to the serial port + RS232_PORT(config, m_rs232, default_rs232_devices, "terminal"); + m_rs232->rxd_handler().set(m_uart, FUNC(i8251_device::write_rxd)); + m_rs232->dsr_handler().set(m_uart, FUNC(i8251_device::write_dsr)); + m_rs232->cts_handler().set(m_uart, FUNC(i8251_device::write_cts)); + m_rs232->set_option_device_input_defaults("terminal", DEVICE_INPUT_DEFAULTS_NAME(terminal)); // must be below the DEVICE_INPUT_DEFAULTS_START block + + + RAM(config, m_ram).set_default_size("32K"); + + SUPER8008_BUS(config, m_bus, 153600); + + SUPER8008_SLOT(config, m_slots[0], super8008_bus_devices, "super8008_blaster"); + SUPER8008_SLOT(config, m_slots[1], super8008_bus_devices, "super8008_blaster"); + SUPER8008_SLOT(config, m_slots[2], super8008_bus_devices, "super8008_blaster"); + SUPER8008_SLOT(config, m_slots[3], super8008_bus_devices, "super8008_blaster"); + SUPER8008_SLOT(config, m_slots[4], super8008_bus_devices, "super8008_blaster"); + SUPER8008_SLOT(config, m_slots[5], super8008_bus_devices, "super8008_blaster"); + SUPER8008_SLOT(config, m_slots[6], super8008_bus_devices, "super8008_blaster"); + + m_slots[0]->set_option_device_input_defaults("super8008_blaster", DEVICE_INPUT_DEFAULTS_NAME(blaster_input_0)); + m_slots[1]->set_option_device_input_defaults("super8008_blaster", DEVICE_INPUT_DEFAULTS_NAME(blaster_input_1)); + m_slots[2]->set_option_device_input_defaults("super8008_blaster", DEVICE_INPUT_DEFAULTS_NAME(blaster_input_2)); + m_slots[3]->set_option_device_input_defaults("super8008_blaster", DEVICE_INPUT_DEFAULTS_NAME(blaster_input_3)); + m_slots[4]->set_option_device_input_defaults("super8008_blaster", DEVICE_INPUT_DEFAULTS_NAME(blaster_input_4)); + m_slots[5]->set_option_device_input_defaults("super8008_blaster", DEVICE_INPUT_DEFAULTS_NAME(blaster_input_5)); + m_slots[6]->set_option_device_input_defaults("super8008_blaster", DEVICE_INPUT_DEFAULTS_NAME(blaster_input_6)); + +} + +ROM_START(super8008) + ROM_REGION(0x10000, "rom",0) //For the addresses to makes since, setup a huge rom chip and load the roms to the cooresponding machine addresses + // Name offset Length hash + ROM_LOAD("monitor-8251-master.bin", 0x0000, 0x14b5, CRC(8cfd849e) SHA1(ea40b0066823df6c1dd896e5425285dddd3432e3)) + ROM_LOAD("scelbal-8251-master.bin", 0x2000, 0x2000, CRC(51f98937) SHA1(83705305c24313cd81e14d1e3cefb3422a9e8118)) +ROM_END + +} // anonymous namespace + + +// This ties everything together +// YEAR NAME PARENT COMPAT MACHINE INPUT CLASS INIT COMPANY FULLNAME FLAGS +COMP( 2024, super8008, 0, 0, super8008, 0, super8008_state, empty_init, "Dr. Scott M. Baker", "8008-Super", MACHINE_NO_SOUND_HW ) diff --git a/src/mame/layout/sbc8008.lay b/src/mame/layout/sbc8008.lay new file mode 100644 index 0000000000000..4e2c79eb5d95c --- /dev/null +++ b/src/mame/layout/sbc8008.lay @@ -0,0 +1,90 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/mame/layout/super8008.lay b/src/mame/layout/super8008.lay new file mode 100644 index 0000000000000..a715e209feed6 --- /dev/null +++ b/src/mame/layout/super8008.lay @@ -0,0 +1,180 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/mame/mame.lst b/src/mame/mame.lst index 664ecc464f7ea..feb65ff264eb2 100644 --- a/src/mame/mame.lst +++ b/src/mame/mame.lst @@ -19910,10 +19910,16 @@ sc203 // SC203 - Modular Z180 Computer @source:homebrew/sbc6510.cpp sbc6510 // +@source:homebrew/sbc8008.cpp +sbc8008 // Jim Loos - 8008-SBC + @source:homebrew/sitcom.cpp sitcom // sitcomtmr // +@source:homebrew/super8008.cpp +super8008 // Dr. Scott M. Baker - 8008-Super + @source:homebrew/test_t400.cpp test410 // test420 //