// license:BSD-3-Clause // copyright-holders:Curt Coder /*************************************************************************** Beta Computer http://retro.hansotten.nl/index.php?page=beta-computer When first started, press G to begin. Pasting: 0-F : as is M (inc) : ^ AD : - DA : = GO : X Test Paste: X-0011=11^22^33^44^55^66^77^88^99^-0011 Now press M to confirm the data has been entered. ****************************************************************************/ /* TODO: - verify whether feeding a 0xff-filled 2K binary file as cart allows to write back correctly EPROM or not */ #include "emu.h" #include "cpu/m6502/m6502.h" #include "machine/mos6530n.h" #include "machine/ram.h" #include "sound/spkrdev.h" #include "bus/generic/slot.h" #include "bus/generic/carts.h" #include "speaker.h" #include "beta.lh" #define SCREEN_TAG "screen" #define M6502_TAG "m6502" #define M6532_TAG "m6532" #define EPROM_TAG "eprom" //#define SPEAKER_TAG "b237" class beta_state : public driver_device { public: beta_state(const machine_config &mconfig, device_type type, const char *tag) : driver_device(mconfig, type, tag), m_maincpu(*this, M6502_TAG), m_speaker(*this, "speaker"), m_eprom(*this, EPROM_TAG), m_q(*this, "Q%u", 6U), m_digits(*this, "digit%u", 0U), m_leds(*this, "led%u", 0U) { } DECLARE_INPUT_CHANGED_MEMBER( trigger_reset ); void beta(machine_config &config); protected: virtual void machine_start() override; DECLARE_READ8_MEMBER( riot_pa_r ); DECLARE_WRITE8_MEMBER( riot_pa_w ); DECLARE_READ8_MEMBER( riot_pb_r ); DECLARE_WRITE8_MEMBER( riot_pb_w ); DECLARE_DEVICE_IMAGE_LOAD_MEMBER( beta_eprom ); DECLARE_DEVICE_IMAGE_UNLOAD_MEMBER( beta_eprom ); TIMER_CALLBACK_MEMBER(led_refresh); void beta_mem(address_map &map); private: required_device m_maincpu; required_device m_speaker; required_device m_eprom; required_ioport_array<4> m_q; output_finder<6> m_digits; output_finder<2> m_leds; /* EPROM state */ int m_eprom_oe; int m_eprom_ce; uint16_t m_eprom_addr; uint8_t m_eprom_data; uint8_t m_old_data; std::vector m_eprom_rom; /* display state */ uint8_t m_ls145_p; uint8_t m_segment; emu_timer *m_led_refresh_timer; }; /* Memory Maps */ void beta_state::beta_mem(address_map &map) { map(0x0000, 0x007f).mirror(0x7f00).m(M6532_TAG, FUNC(mos6532_new_device::ram_map)); map(0x0080, 0x00ff).mirror(0x7f00).m(M6532_TAG, FUNC(mos6532_new_device::io_map)); map(0x8000, 0x87ff).mirror(0x7800).rom(); } /* Input Ports */ INPUT_CHANGED_MEMBER( beta_state::trigger_reset ) { m_maincpu->set_input_line(INPUT_LINE_RESET, newval ? CLEAR_LINE : ASSERT_LINE); } static INPUT_PORTS_START( beta ) PORT_START("Q6") PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_A) PORT_CHAR('A') PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_1) PORT_CHAR('1') PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_4) PORT_CHAR('4') PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_7) PORT_CHAR('7') PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("GO") PORT_CODE(KEYCODE_G) PORT_CODE(KEYCODE_X) PORT_CHAR('X') PORT_BIT( 0xe0, IP_ACTIVE_LOW, IPT_UNUSED ) PORT_START("Q7") PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_0) PORT_CHAR('0') PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_2) PORT_CHAR('2') PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_5) PORT_CHAR('5') PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_8) PORT_CHAR('8') PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_M) PORT_CODE(KEYCODE_UP) PORT_CHAR('^') PORT_BIT( 0xe0, IP_ACTIVE_LOW, IPT_UNUSED ) PORT_START("Q8") PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_B) PORT_CHAR('B') PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_3) PORT_CHAR('3') PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_6) PORT_CHAR('6') PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_9) PORT_CHAR('9') PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("DA") PORT_CODE(KEYCODE_EQUALS) PORT_CHAR('=') PORT_BIT( 0xe0, IP_ACTIVE_LOW, IPT_UNUSED ) PORT_START("Q9") PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_C) PORT_CHAR('C') PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_D) PORT_CHAR('D') PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_E) PORT_CHAR('E') PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_F) PORT_CHAR('F') PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("AD") PORT_CODE(KEYCODE_MINUS) PORT_CHAR('-') PORT_BIT( 0xe0, IP_ACTIVE_LOW, IPT_UNUSED ) PORT_START("SPECIAL") PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("RESET") PORT_CODE(KEYCODE_R) PORT_CHANGED_MEMBER(DEVICE_SELF, beta_state, trigger_reset, 0) INPUT_PORTS_END /* M6532 Interface */ TIMER_CALLBACK_MEMBER(beta_state::led_refresh) { if (m_ls145_p < 6) m_digits[m_ls145_p] = m_segment; } READ8_MEMBER( beta_state::riot_pa_r ) { /* bit description PA0 2716 D0, segment D, key bit 0 PA1 2716 D1, segment E, key bit 1 PA2 2716 D2, segment C, key bit 2 PA3 2716 D3, segment G, key bit 3 PA4 2716 D4, segment F, key bit 4 PA5 2716 D5, segment B PA6 2716 D6, segment A PA7 2716 D7 */ uint8_t data = 0xff; switch (m_ls145_p) { case 6: case 7: case 8: case 9: data &= m_q[m_ls145_p - 6]->read(); break; default: if (!m_eprom_oe && !m_eprom_ce) { data = m_eprom_rom[m_eprom_addr & 0x7ff]; popmessage("EPROM read %04x = %02x\n", m_eprom_addr & 0x7ff, data); } } return data; } WRITE8_MEMBER( beta_state::riot_pa_w ) { /* bit description PA0 2716 D0, segment D, key bit 0 PA1 2716 D1, segment E, key bit 1 PA2 2716 D2, segment C, key bit 2 PA3 2716 D3, segment G, key bit 3 PA4 2716 D4, segment F, key bit 4 PA5 2716 D5, segment B PA6 2716 D6, segment A PA7 2716 D7 */ // logerror("PA %02x\n", data); /* display */ m_segment = bitswap<8>(data, 7, 3, 4, 1, 0, 2, 5, 6) & 0x7f; m_led_refresh_timer->adjust(attotime::from_usec(70)); /* EPROM data */ m_eprom_data = data; } READ8_MEMBER( beta_state::riot_pb_r ) { return 0; } WRITE8_MEMBER( beta_state::riot_pb_w ) { /* bit description PB0 74LS145 P0 PB1 74LS145 P1 PB2 74LS145 P2 PB3 74LS145 P3, 74LS164 D PB4 loudspeaker, data led PB5 address led, 74LS164 CP PB6 2716 _OE PB7 2716 _CE */ //logerror("PB %02x %02x\n", data, olddata); /* display */ m_ls145_p = data & 0x0f; /* speaker */ m_speaker->level_w(!BIT(data, 4)); /* address led */ m_leds[0] = BIT(data, 5); /* data led */ m_leds[1] = !BIT(data, 5); /* EPROM address shift */ if (!BIT(m_old_data, 5) && BIT(data, 5)) { m_eprom_addr <<= 1; m_eprom_addr |= BIT(m_old_data, 3); } /* EPROM output enable */ m_eprom_oe = BIT(data, 6); /* EPROM chip enable */ m_eprom_ce = BIT(data, 7); if (BIT(data, 6) && (!BIT(m_old_data, 7) && BIT(data, 7))) { popmessage("EPROM write %04x = %02x\n", m_eprom_addr & 0x7ff, m_eprom_data); m_eprom_rom[m_eprom_addr & 0x7ff] &= m_eprom_data; } m_old_data = data; } /* EPROM socket */ DEVICE_IMAGE_LOAD_MEMBER( beta_state, beta_eprom ) { uint32_t size = m_eprom->common_get_size("rom"); if (size != 0x800) { image.seterror(IMAGE_ERROR_UNSPECIFIED, "Unsupported cartridge size"); return image_init_result::FAIL; } m_eprom->rom_alloc(size, GENERIC_ROM8_WIDTH, ENDIANNESS_LITTLE); m_eprom->common_load_rom(m_eprom->get_rom_base(), size, "rom"); return image_init_result::PASS; } DEVICE_IMAGE_UNLOAD_MEMBER( beta_state, beta_eprom ) { if (!image.loaded_through_softlist()) image.fwrite(&m_eprom_rom[0], 0x800); } /* Machine Initialization */ void beta_state::machine_start() { m_digits.resolve(); m_leds.resolve(); m_led_refresh_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(beta_state::led_refresh),this)); m_eprom_rom.resize(0x800); if (!m_eprom->exists()) memset(&m_eprom_rom[0], 0xff, 0x800); else { std::string region_tag; memcpy(&m_eprom_rom[0], memregion(region_tag.assign(m_eprom->tag()).append(GENERIC_ROM_REGION_TAG).c_str())->base(), 0x800); } // state saving save_item(NAME(m_eprom_oe)); save_item(NAME(m_eprom_ce)); save_item(NAME(m_eprom_addr)); save_item(NAME(m_eprom_data)); save_item(NAME(m_old_data)); save_item(NAME(m_eprom_rom)); save_item(NAME(m_ls145_p)); save_item(NAME(m_segment)); } /* Machine Driver */ MACHINE_CONFIG_START(beta_state::beta) /* basic machine hardware */ MCFG_DEVICE_ADD(M6502_TAG, M6502, XTAL(4'000'000)/4) MCFG_DEVICE_PROGRAM_MAP(beta_mem) /* video hardware */ MCFG_DEFAULT_LAYOUT( layout_beta ) /* sound hardware */ SPEAKER(config, "mono").front_center(); MCFG_DEVICE_ADD("speaker", SPEAKER_SOUND) MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.25) /* devices */ MCFG_DEVICE_ADD(M6532_TAG, MOS6532_NEW, XTAL(4'000'000)/4) MCFG_MOS6530n_IN_PA_CB(READ8(*this, beta_state, riot_pa_r)) MCFG_MOS6530n_OUT_PA_CB(WRITE8(*this, beta_state, riot_pa_w)) MCFG_MOS6530n_IN_PB_CB(READ8(*this, beta_state, riot_pb_r)) MCFG_MOS6530n_OUT_PB_CB(WRITE8(*this, beta_state, riot_pb_w)) MCFG_MOS6530n_IRQ_CB(INPUTLINE(M6502_TAG, M6502_IRQ_LINE)) /* EPROM socket */ MCFG_GENERIC_CARTSLOT_ADD(EPROM_TAG, generic_plain_slot, nullptr) MCFG_GENERIC_EXTENSIONS("bin,rom") MCFG_GENERIC_LOAD(beta_state, beta_eprom) MCFG_GENERIC_UNLOAD(beta_state, beta_eprom) /* internal ram */ MCFG_RAM_ADD(RAM_TAG) MCFG_RAM_DEFAULT_SIZE("256") MACHINE_CONFIG_END /* ROMs */ ROM_START( beta ) ROM_REGION( 0x10000, M6502_TAG, 0 ) ROM_LOAD( "beta.rom", 0x8000, 0x0800, CRC(d42fdb17) SHA1(595225a0cd43dd76c46b2aff6c0f27d5991cc4f0)) ROM_END /* System Drivers */ // YEAR NAME PARENT COMPAT MACHINE INPUT CLASS INIT COMPANY FULLNAME FLAGS COMP( 1984, beta, 0, 0, beta, beta, beta_state, empty_init, "Pitronics", "Beta", MACHINE_SUPPORTS_SAVE )