summaryrefslogtreecommitdiffstatshomepage
path: root/src/mame/drivers/ptcsol.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/mame/drivers/ptcsol.cpp')
-rw-r--r--src/mame/drivers/ptcsol.cpp824
1 files changed, 0 insertions, 824 deletions
diff --git a/src/mame/drivers/ptcsol.cpp b/src/mame/drivers/ptcsol.cpp
deleted file mode 100644
index 17f7a8055ce..00000000000
--- a/src/mame/drivers/ptcsol.cpp
+++ /dev/null
@@ -1,824 +0,0 @@
-// license:BSD-3-Clause
-// copyright-holders:Robbbert
-/***************************************************************************
-
- Processor Technology Corp. SOL-20
-
- 07/2009 Skeleton driver.
-
- Info from: http://www.sol20.org/
-
- The Sol Terminal Computer was the first complete S-100 microcomputer
- with a built-in keyboard and video output. However, its internal
- architecture resembles a video display terminal more than anything else.
-
- Note that the SOLOS dump comes from the Solace emu. Confirmed as ok.
-
- The roms DPMON and CONSOL are widely available on the net as ENT files,
- which can be loaded into memory with the Paste option, then exported to
- binary files with the debugger. They are working, however the ENT files
- do not indicate the values of unused rom space. Therefore they are marked
- as BAD_DUMP.
-
- Note that the CONSOL rom is basically a dumb terminal program and doesn't
- do anything useful unless the MODE key (whatever that is) is pressed.
-
- CUTER is a relocatable cassette-based alternative to SOLOS. According
- to the manual, it should work if the sense switches are set to on. But,
- it continuously reads port 00 and does nothing.
-
- Need original dumps of all roms.
-
- The character roms are built by a script from the Solace source, then the
- characters moved back to the original 7x9 matrix positions, as shown in
- the manual. Although they look exactly the same, I've marked them as
- BAD_DUMP until properly verified.
-
- Other roms needed:
- - Dump of U18 in the keyboard
-
- Hardware variants (ever shipped?):
- - SOL-10, i.e. a stripped down version without expansion backplane and
- numeric keypad
- - SOL-PC, i.e. the single board version, basically it consisted of the
- SOL-20 board only
-
- Similarity to Exidy Sorcerer:
- - Some hardware is the same design (parallel ports, serial ports, 2
- tape players, the cassette circuits)
- - The cassette format is totally identical, in fact tapes from one
- machine can be loaded on the other natively. They won't run of course.
- - Sorcerer monitor commands are almost identical to the SOLOS ones.
- example: to change tape speed to 300 baud:
- SE T=1 (sorcerer) SE TA 1 (SOLOS)
- Most other commands are identical. The EN command (enter bytes into
- memory) is rather primitive in SOLOS, better on Sorcerer.
- - Sol20 has "personality modules" where you could plug a new OS into
- a special socket on the motherboard. Sorcerer improved upon this by
- being the first computer to use cartridges.
- - Some circuits are completely different... the video and keyboard are
- notable examples, while the addresses of ram and bios on the basic
- machines is another major difference.
-
- ToDo:
- - connect up half/full duplex dipswitch function
- - connect up the remaining functions of port FE
- - keyboard (using terminal keyboard for now)
- - optional floppy disk support and CP/M
- - parallel i/o and handshake lines
- - connect serial i/o to something
- - support for loading the various file formats
-
- File Formats:
- - Most files are simple ascii which can be loaded via the Paste handler.
- These are ASC, ENT, BAS, ROM, BS5 and ECB. Most files require that the
- correct version of BASIC be loaded first. Paste works, but it is very
- very slow. Perhaps we need something faster such as what Solace has.
- - SVT (Solace Virtual Tape) files are a representation of a cassette,
- usually holding about 4 games, just like a multifile tape. This format
- is partially supported.
- - HEX files appear to be the standard Intel format, and can be loaded
- by Solace.
- - The remaining formats (OPN, PL, PRN, SMU, SOL, ASM and LIB) appear
- at first glance to be more specialised, and probably not worth being
- supported.
-
- System Setup (to play games etc).
- - In the Dipswitches (not the Configuration), turn cursor flashing OFF.
- - Loading via wav files works, so load a tape image in the file manager
- - In UPPER CASE, enter XE press enter, cassette will load.
- - At the end, the program will start by itself.
- - When it says use 2,4,6,8 keys, you can use the keyboard arrow keys.
-
- Monitor Commands:
- - TE - return to terminal mode
- - DU - dump memory
- - EN - modify memory
- - EX - Go (execute)
- - CU - Insert or remove a custom command
- - SE - Set parameters (eg tape speed)
- - SA - Save
- - GE - Load
- - XE - Load and run
- - CA - List the files on a tape
-
- How to use the music system:
- 1. Choose the "music" item from the software list
- 2. Type XEQ press Enter
- 3. When the program starts, press R, you are back in the monitor
- 4. Type GET press Enter
- 5. When this finishes loading, type EX 0 press Enter, there's no response
- 6. Press F, wait for numbers to appear
- 7. Press S, wait for numbers to appear
- 8. Press P, music will be heard (it isn't very loud)
-
-****************************************************************************/
-
-#include "emu.h"
-
-#include "cpu/i8085/i8085.h"
-#include "bus/rs232/rs232.h"
-//#include "bus/s100/s100.h"
-#include "imagedev/cassette.h"
-#include "machine/ay31015.h"
-#include "machine/clock.h"
-#include "machine/keyboard.h"
-#include "sound/spkrdev.h"
-
-#include "emupal.h"
-#include "screen.h"
-#include "softlist.h"
-#include "speaker.h"
-
-#include "formats/sol_cas.h"
-
-
-struct cass_data_t {
- struct {
- int length; /* time cassette level is at input.level */
- int level; /* cassette level */
- int bit; /* bit being read */
- } input;
- struct {
- int length; /* time cassette level is at output.level */
- int level; /* cassette level */
- int bit; /* bit to output */
- } output;
-};
-
-class sol20_state : public driver_device
-{
-public:
- sol20_state(const machine_config &mconfig, device_type type, const char *tag)
- : driver_device(mconfig, type, tag)
- , m_maincpu(*this, "maincpu")
- , m_screen(*this, "screen")
- , m_cass1(*this, "cassette")
- , m_cass2(*this, "cassette2")
- , m_uart(*this, "uart")
- , m_uart_s(*this, "uart_s")
- , m_uart_clock(*this, "uart_clock")
- , m_uart_s_clock(*this, "uart_s_clock")
- , m_rs232(*this, "rs232")
- , m_p_videoram(*this, "videoram")
- , m_p_chargen(*this, "chargen")
- , m_iop_arrows(*this, "ARROWS")
- , m_iop_config(*this, "CONFIG")
- , m_iop_s1(*this, "S1")
- , m_iop_s2(*this, "S2")
- , m_iop_s3(*this, "S3")
- , m_iop_s4(*this, "S4")
- { }
-
- void sol20(machine_config &config);
-
- void init_sol20();
-
-private:
- enum
- {
- TIMER_SOL20_CASSETTE_TC,
- TIMER_SOL20_BOOT
- };
-
- DECLARE_READ8_MEMBER( sol20_f8_r );
- DECLARE_READ8_MEMBER( sol20_fa_r );
- DECLARE_READ8_MEMBER( sol20_fc_r );
- DECLARE_READ8_MEMBER( sol20_fd_r );
- DECLARE_WRITE8_MEMBER( sol20_f8_w );
- DECLARE_WRITE8_MEMBER( sol20_fa_w );
- DECLARE_WRITE8_MEMBER( sol20_fd_w );
- DECLARE_WRITE8_MEMBER( sol20_fe_w );
- void kbd_put(u8 data);
- TIMER_CALLBACK_MEMBER(sol20_cassette_tc);
- TIMER_CALLBACK_MEMBER(sol20_boot);
- uint32_t screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect);
-
- void sol20_io(address_map &map);
- void sol20_mem(address_map &map);
-
- virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
- uint8_t m_sol20_fa;
- virtual void machine_reset() override;
- virtual void machine_start() override;
- uint8_t m_sol20_fc;
- uint8_t m_sol20_fe;
- uint8_t m_framecnt;
- cass_data_t m_cass_data;
- emu_timer *m_cassette_timer;
- cassette_image_device *cassette_device_image();
- required_device<i8080a_cpu_device> m_maincpu;
- required_device<screen_device> m_screen;
- required_device<cassette_image_device> m_cass1;
- required_device<cassette_image_device> m_cass2;
- required_device<ay31015_device> m_uart;
- required_device<ay31015_device> m_uart_s;
- required_device<clock_device> m_uart_clock;
- required_device<clock_device> m_uart_s_clock;
- required_device<rs232_port_device> m_rs232;
- required_shared_ptr<uint8_t> m_p_videoram;
- required_region_ptr<u8> m_p_chargen;
- required_ioport m_iop_arrows;
- required_ioport m_iop_config;
- required_ioport m_iop_s1;
- required_ioport m_iop_s2;
- required_ioport m_iop_s3;
- required_ioport m_iop_s4;
-};
-
-
-/* timer to read cassette waveforms */
-
-
-cassette_image_device *sol20_state::cassette_device_image()
-{
- if (m_sol20_fa & 0x40)
- return m_cass2;
- else
- return m_cass1;
-}
-
-
-void sol20_state::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
-{
- switch (id)
- {
- case TIMER_SOL20_CASSETTE_TC:
- sol20_cassette_tc(ptr, param);
- break;
- case TIMER_SOL20_BOOT:
- sol20_boot(ptr, param);
- break;
- default:
- throw emu_fatalerror("Unknown id in sol20_state::device_timer");
- }
-}
-
-
-// identical to sorcerer
-TIMER_CALLBACK_MEMBER(sol20_state::sol20_cassette_tc)
-{
- uint8_t cass_ws = 0;
- switch (m_sol20_fa & 0x20)
- {
- case 0x20: /* Cassette 300 baud */
-
- /* loading a tape - this is basically the same as the super80.
- We convert the 1200/2400 Hz signal to a 0 or 1, and send it to the uart. */
-
- m_cass_data.input.length++;
-
- cass_ws = ((cassette_device_image())->input() > +0.02) ? 1 : 0;
-
- if (cass_ws != m_cass_data.input.level)
- {
- m_cass_data.input.level = cass_ws;
- m_cass_data.input.bit = ((m_cass_data.input.length < 0x6) || (m_cass_data.input.length > 0x20)) ? 1 : 0;
- m_cass_data.input.length = 0;
- m_uart->write_si(m_cass_data.input.bit);
- }
-
- /* saving a tape - convert the serial stream from the uart, into 1200 and 2400 Hz frequencies.
- Synchronisation of the frequency pulses to the uart is extremely important. */
-
- m_cass_data.output.length++;
- if (!(m_cass_data.output.length & 0x1f))
- {
- cass_ws = m_uart->so_r();
- if (cass_ws != m_cass_data.output.bit)
- {
- m_cass_data.output.bit = cass_ws;
- m_cass_data.output.length = 0;
- }
- }
-
- if (!(m_cass_data.output.length & 3))
- {
- if (!((m_cass_data.output.bit == 0) && (m_cass_data.output.length & 4)))
- {
- m_cass_data.output.level ^= 1; // toggle output this, except on 2nd half of low bit
- cassette_device_image()->output(m_cass_data.output.level ? -1.0 : +1.0);
- }
- }
- return;
-
- case 0x00: /* Cassette 1200 baud */
- /* loading a tape */
- m_cass_data.input.length++;
-
- cass_ws = ((cassette_device_image())->input() > +0.02) ? 1 : 0;
-
- if (cass_ws != m_cass_data.input.level || m_cass_data.input.length == 10)
- {
- m_cass_data.input.bit = ((m_cass_data.input.length < 10) || (m_cass_data.input.length > 0x20)) ? 1 : 0;
- if ( cass_ws != m_cass_data.input.level )
- {
- m_cass_data.input.length = 0;
- m_cass_data.input.level = cass_ws;
- }
- m_uart->write_si(m_cass_data.input.bit);
- }
-
- /* saving a tape - convert the serial stream from the uart, into 600 and 1200 Hz frequencies. */
-
- m_cass_data.output.length++;
- if (!(m_cass_data.output.length & 7))
- {
- cass_ws = m_uart->so_r();
- if (cass_ws != m_cass_data.output.bit)
- {
- m_cass_data.output.bit = cass_ws;
- m_cass_data.output.length = 0;
- }
- }
-
- if (!(m_cass_data.output.length & 7))
- {
- if (!((m_cass_data.output.bit == 0) && (m_cass_data.output.length & 8)))
- {
- m_cass_data.output.level ^= 1; // toggle output this, except on 2nd half of low bit
- cassette_device_image()->output(m_cass_data.output.level ? -1.0 : +1.0);
- }
- }
- return;
- }
-}
-
-READ8_MEMBER( sol20_state::sol20_f8_r )
-{
-// d7 - TBMT; d6 - DAV; d5 - CTS; d4 - OE; d3 - PE; d2 - FE; d1 - DSR; d0 - CD
- uint8_t data = 0;
-
- m_uart_s->write_swe(0);
- data |= m_uart_s->tbmt_r() ? 0x80 : 0;
- data |= m_uart_s->dav_r( ) ? 0x40 : 0;
- data |= m_rs232->cts_r( ) ? 0x20 : 0;
- data |= m_uart_s->or_r( ) ? 0x10 : 0;
- data |= m_uart_s->pe_r( ) ? 0x08 : 0;
- data |= m_uart_s->fe_r( ) ? 0x04 : 0;
- data |= m_rs232->dsr_r( ) ? 0x02 : 0;
- data |= m_rs232->dcd_r( ) ? 0x01 : 0;
- m_uart_s->write_swe(1);
-
- return data;
-}
-
-READ8_MEMBER( sol20_state::sol20_fa_r )
-{
- /* set unused bits high */
- uint8_t data = 0x26;
-
- m_uart->write_swe(0);
- data |= m_uart->tbmt_r() ? 0x80 : 0;
- data |= m_uart->dav_r( ) ? 0x40 : 0;
- data |= m_uart->or_r( ) ? 0x10 : 0;
- data |= m_uart->fe_r( ) ? 0x08 : 0;
- m_uart->write_swe(1);
-
- bool arrowkey = m_iop_arrows->read() ? 0 : 1;
- bool keydown = m_sol20_fa & 1;
-
- return data | (arrowkey & keydown);
-}
-
-READ8_MEMBER( sol20_state::sol20_fc_r )
-{
- uint8_t data = m_iop_arrows->read();
- if (BIT(data, 0)) return 0x32;
- if (BIT(data, 1)) return 0x34;
- if (BIT(data, 2)) return 0x36;
- if (BIT(data, 3)) return 0x38;
-
- m_sol20_fa |= 1;
- return m_sol20_fc;
-}
-
-READ8_MEMBER( sol20_state::sol20_fd_r )
-{
-// Return a byte from parallel interface
- return 0;
-}
-
-WRITE8_MEMBER( sol20_state::sol20_f8_w )
-{
-// The only function seems to be to send RTS from bit 4
- m_rs232->write_rts(BIT(data, 4));
-}
-
-WRITE8_MEMBER( sol20_state::sol20_fa_w )
-{
- m_sol20_fa &= 1;
- m_sol20_fa |= (data & 0xf0);
-
- /* cassette 1 motor */
- m_cass1->change_state(
- (BIT(data,7)) ? CASSETTE_MOTOR_ENABLED : CASSETTE_MOTOR_DISABLED, CASSETTE_MASK_MOTOR);
-
- /* cassette 2 motor */
- m_cass2->change_state(
- (BIT(data,6)) ? CASSETTE_MOTOR_ENABLED : CASSETTE_MOTOR_DISABLED, CASSETTE_MASK_MOTOR);
-
- if (data & 0xc0)
- m_cassette_timer->adjust(attotime::zero, 0, attotime::from_hz(19200));
- else
- m_cassette_timer->adjust(attotime::zero);
-
- // bit 5 baud rate */
- m_uart_clock->set_unscaled_clock(BIT(data, 5) ? 4800 : 19200);
-}
-
-WRITE8_MEMBER( sol20_state::sol20_fd_w )
-{
-// Output a byte to parallel interface
-}
-
-WRITE8_MEMBER( sol20_state::sol20_fe_w )
-{
- m_sol20_fe = data;
-}
-
-void sol20_state::sol20_mem(address_map &map)
-{
- map(0x0000, 0x07ff).bankrw("boot");
- map(0x0800, 0xbfff).ram(); // optional s100 ram
- map(0xc000, 0xc7ff).rom();
- map(0xc800, 0xcbff).ram(); // system ram
- map(0xcc00, 0xcfff).ram().share("videoram");
- map(0xd000, 0xffff).ram(); // optional s100 ram
-}
-
-void sol20_state::sol20_io(address_map &map)
-{
- map.unmap_value_high();
- map.global_mask(0xff);
- map(0xf8, 0xf8).rw(FUNC(sol20_state::sol20_f8_r), FUNC(sol20_state::sol20_f8_w));
- map(0xf9, 0xf9).rw(m_uart_s, FUNC(ay51013_device::receive), FUNC(ay51013_device::transmit));
- map(0xfa, 0xfa).rw(FUNC(sol20_state::sol20_fa_r), FUNC(sol20_state::sol20_fa_w));
- map(0xfb, 0xfb).rw(m_uart, FUNC(ay51013_device::receive), FUNC(ay51013_device::transmit));
- map(0xfc, 0xfc).r(FUNC(sol20_state::sol20_fc_r));
- map(0xfd, 0xfd).rw(FUNC(sol20_state::sol20_fd_r), FUNC(sol20_state::sol20_fd_w));
- map(0xfe, 0xfe).w(FUNC(sol20_state::sol20_fe_w));
- map(0xff, 0xff).portr("S2");
-/* map(0xf8, 0xf8) serial status in (bit 6=data av, bit 7=tmbe)
- map(0xf9, 0xf9) serial data in, out
- map(0xfa, 0xfa) general status in (bit 0=keyb data av, bit 1=parin data av, bit 2=parout ready)
- map(0xfb, 0xfb) tape
- map(0xfc, 0xfc) keyboard data in
- map(0xfd, 0xfd) parallel data in, out
- map(0xfe, 0xfe) scroll register
- map(0xff, 0xff) sense switches */
-}
-
-/* Input ports */
-static INPUT_PORTS_START( sol20 )
- PORT_START("ARROWS")
- PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_DOWN)
- PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_LEFT)
- PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_RIGHT)
- PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_UP)
- PORT_BIT( 0xf0, IP_ACTIVE_HIGH, IPT_UNUSED)
-
- PORT_START("S1")
- PORT_DIPNAME( 0x04, 0x00, "Ctrl Chars")
- PORT_DIPSETTING( 0x04, DEF_STR(Off))
- PORT_DIPSETTING( 0x00, DEF_STR(On))
- PORT_DIPNAME( 0x08, 0x00, "Polarity")
- PORT_DIPSETTING( 0x00, DEF_STR( Normal ))
- PORT_DIPSETTING( 0x08, "Inverse")
- PORT_DIPNAME( 0x30, 0x10, "Cursor Type")
- PORT_DIPSETTING( 0x10, "Blinking")
- PORT_DIPSETTING( 0x20, "Solid")
- PORT_DIPSETTING( 0x30, DEF_STR(None))
-
- PORT_START("S2") // Sense Switches
- PORT_DIPNAME( 0x01, 0x01, "FF bit 0")
- PORT_DIPSETTING( 0x01, DEF_STR(Off))
- PORT_DIPSETTING( 0x00, DEF_STR(On))
- PORT_DIPNAME( 0x02, 0x02, "FF bit 1")
- PORT_DIPSETTING( 0x02, DEF_STR(Off))
- PORT_DIPSETTING( 0x00, DEF_STR(On))
- PORT_DIPNAME( 0x04, 0x04, "FF bit 2")
- PORT_DIPSETTING( 0x04, DEF_STR(Off))
- PORT_DIPSETTING( 0x00, DEF_STR(On))
- PORT_DIPNAME( 0x08, 0x08, "FF bit 3")
- PORT_DIPSETTING( 0x08, DEF_STR(Off))
- PORT_DIPSETTING( 0x00, DEF_STR(On))
- PORT_DIPNAME( 0x10, 0x10, "FF bit 4")
- PORT_DIPSETTING( 0x10, DEF_STR(Off))
- PORT_DIPSETTING( 0x00, DEF_STR(On))
- PORT_DIPNAME( 0x20, 0x20, "FF bit 5")
- PORT_DIPSETTING( 0x20, DEF_STR(Off))
- PORT_DIPSETTING( 0x00, DEF_STR(On))
- PORT_DIPNAME( 0x40, 0x40, "FF bit 6")
- PORT_DIPSETTING( 0x40, DEF_STR(Off))
- PORT_DIPSETTING( 0x00, DEF_STR(On))
- PORT_DIPNAME( 0x80, 0x80, "FF bit 7")
- PORT_DIPSETTING( 0x80, DEF_STR(Off))
- PORT_DIPSETTING( 0x00, DEF_STR(On))
-
- PORT_START("S3")
- PORT_DIPNAME( 0xff, 0x08, "Baud Rate")
- PORT_DIPSETTING( 0x01, "75")
- PORT_DIPSETTING( 0x02, "110")
- PORT_DIPSETTING( 0x04, "180")
- PORT_DIPSETTING( 0x08, "300")
- PORT_DIPSETTING( 0x10, "600")
- PORT_DIPSETTING( 0x20, "1200")
- PORT_DIPSETTING( 0x40, "2400")
- PORT_DIPSETTING( 0x80, "4800/9600")
-
- PORT_START("S4")
- PORT_DIPNAME( 0x11, 0x10, "Parity")
- PORT_DIPSETTING( 0x00, "Even")
- PORT_DIPSETTING( 0x01, "Odd")
- PORT_DIPSETTING( 0x10, DEF_STR(None))
- PORT_DIPNAME( 0x06, 0x06, "Data Bits")
- PORT_DIPSETTING( 0x00, "5")
- PORT_DIPSETTING( 0x02, "6")
- PORT_DIPSETTING( 0x04, "7")
- PORT_DIPSETTING( 0x06, "8")
- PORT_DIPNAME( 0x08, 0x08, "Stop Bits")
- PORT_DIPSETTING( 0x00, "1")
- PORT_DIPSETTING( 0x08, "2")
- PORT_DIPNAME( 0x20, 0x00, "Duplex")
- PORT_DIPSETTING( 0x00, "Half")
- PORT_DIPSETTING( 0x20, "Full")
-
- PORT_START("CONFIG")
- PORT_CONFNAME( 0x01, 0x01, "High Baud Rate") // jumper on the board
- PORT_CONFSETTING( 0x00, "4800")
- PORT_CONFSETTING( 0x01, "9600")
- PORT_CONFNAME( 0x02, 0x00, "Character Rom")
- PORT_CONFSETTING( 0x00, "6574")
- PORT_CONFSETTING( 0x02, "6575")
- PORT_CONFNAME( 0x04, 0x04, "Field Rate") // modification described on page III-40 of Sol Systems Manual
- PORT_CONFSETTING( 0x00, "50 Hz")
- PORT_CONFSETTING( 0x04, "60 Hz")
- PORT_CONFNAME( 0x18, 0x18, "CPU Clock")
- PORT_CONFSETTING( 0x18, "2.04 MHz (8080A)")
- PORT_CONFSETTING( 0x10, "2.36 MHz (8080A-2)")
- PORT_CONFSETTING( 0x08, "2.86 MHz (8080A-1)")
-INPUT_PORTS_END
-
-
-/* after the first 4 bytes have been read from ROM, switch the ram back in */
-TIMER_CALLBACK_MEMBER(sol20_state::sol20_boot)
-{
- membank("boot")->set_entry(0);
-}
-
-void sol20_state::machine_start()
-{
- m_cassette_timer = timer_alloc(TIMER_SOL20_CASSETTE_TC);
-}
-
-void sol20_state::machine_reset()
-{
- uint8_t data = 0, s_count = 0;
- int s_clock;
- const uint16_t s_bauds[8]={ 75, 110, 180, 300, 600, 1200, 2400, 4800 };
- m_sol20_fe=0;
- m_sol20_fa=1;
-
- // set hard-wired uart pins
- m_uart->write_cs(0);
- m_uart->write_nb1(1);
- m_uart->write_nb2(1);
- m_uart->write_tsb(1);
- m_uart->write_eps(1);
- m_uart->write_np(1);
- m_uart->write_cs(1);
-
- // set switched uart pins
- data = m_iop_s4->read();
- m_uart_s->write_cs(0);
- m_uart_s->write_nb1(BIT(data, 1));
- m_uart_s->write_nb2(BIT(data, 2));
- m_uart_s->write_tsb(BIT(data, 3));
- m_uart_s->write_eps(BIT(data, 0));
- m_uart_s->write_np(BIT(data, 4));
- m_uart_s->write_cs(1);
-
- // set rs232 baud rate
- data = m_iop_s3->read();
-
- if (data > 1)
- do
- {
- s_count++;
- data >>= 1;
- }
- while (!(data & 1) && (s_count < 7)); // find which switch is used
-
- if ( (s_count == 7) & BIT(m_iop_config->read(), 0) ) // if highest, look at jumper
- s_clock = 9600 << 4;
- else
- s_clock = s_bauds[s_count] << 4;
-
- // these lines could be commented out for now if you want better performance
- m_uart_s_clock->set_unscaled_clock(s_clock);
-
- // boot-bank
- membank("boot")->set_entry(1);
- timer_set(attotime::from_usec(9), TIMER_SOL20_BOOT);
-
- m_rs232->write_dtr(0);
- m_rs232->write_rts(1);
-
- int lines = BIT(m_iop_config->read(), 2) ? 260 : 312;
- m_screen->configure(918, lines, m_screen->visible_area(), attotime::from_ticks(918 * lines, 14.318181_MHz_XTAL).as_attoseconds());
-
- // set CPU speed (TODO: also present on bus pin 49)
- double freq = (14.318181_MHz_XTAL / (4 + ((m_iop_config->read() >> 3) & 3))).dvalue();
- m_maincpu->set_unscaled_clock(freq);
-}
-
-void sol20_state::init_sol20()
-{
- uint8_t *RAM = memregion("maincpu")->base();
- membank("boot")->configure_entries(0, 2, &RAM[0x0000], 0xc000);
-}
-
-uint32_t sol20_state::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
-{
-// Visible screen is 64 x 16, with start position controlled by scroll register.
-// Each character is 9 pixels wide (blank ones at the right) and 13 lines deep.
-// Note on blinking characters:
-// any character with bit 7 set will blink. With DPMON, do DA C000 C2FF to see what happens
- uint16_t which = (m_iop_config->read() & 2) << 10;
- uint8_t s1 = m_iop_s1->read();
- uint8_t y,ra,chr,gfx;
- uint16_t sy=0,ma,x,inv;
- uint8_t polarity = (s1 & 8) ? 0xff : 0;
-
- bool cursor_inv = false;
- if (((s1 & 0x30) == 0x20) || (((s1 & 0x30) == 0x10) && (m_framecnt & 0x08)))
- cursor_inv = true;
-
- m_framecnt++;
-
- ma = m_sol20_fe << 6; // scroll register
-
- for (y = 0; y < 16; y++)
- {
- for (ra = 0; ra < 13; ra++)
- {
- uint16_t *p = &bitmap.pix16(sy++);
-
- for (x = ma; x < ma + 64; x++)
- {
- inv = polarity;
- chr = m_p_videoram[x & 0x3ff];
-
- // cursor
- if (BIT(chr, 7) && cursor_inv)
- inv ^= 0xff;
-
- chr &= 0x7f;
-
- if ((ra == 0) || ((s1 & 4) && (chr < 0x20)))
- gfx = inv;
- else
- if ((chr==0x2C) || (chr==0x3B) || (chr==0x67) || (chr==0x6A) || (chr==0x70) || (chr==0x71) || (chr==0x79))
- {
- if (ra < 4)
- gfx = inv;
- else
- gfx = m_p_chargen[which | (chr<<4) | (ra-4) ] ^ inv;
- }
- else
- {
- if (ra < 10)
- gfx = m_p_chargen[which | (chr<<4) | (ra-1) ] ^ inv;
- else
- gfx = inv;
- }
-
- /* Display a scanline of a character */
- *p++ = BIT(gfx, 7);
- *p++ = BIT(gfx, 6);
- *p++ = BIT(gfx, 5);
- *p++ = BIT(gfx, 4);
- *p++ = BIT(gfx, 3);
- *p++ = BIT(gfx, 2);
- *p++ = BIT(gfx, 1);
- *p++ = BIT(gfx, 0);
- *p++ = BIT(inv, 0);
- }
- }
- ma+=64;
- }
- return 0;
-}
-
-/* F4 Character Displayer */
-static const gfx_layout sol20_charlayout =
-{
- 7, 9, /* 7 x 9 characters */
- 128*2, /* 128 characters per rom */
- 1, /* 1 bits per pixel */
- { 0 }, /* no bitplanes */
- /* x offsets */
- { 0, 1, 2, 3, 4, 5, 6 },
- /* y offsets */
- { 0*8, 1*8, 2*8, 3*8, 4*8, 5*8, 6*8, 7*8, 8*8 },
- 8*16 /* every char takes 16 bytes */
-};
-
-static GFXDECODE_START( gfx_sol20 )
- GFXDECODE_ENTRY( "chargen", 0x0000, sol20_charlayout, 0, 1 )
-GFXDECODE_END
-
-void sol20_state::kbd_put(u8 data)
-{
- if (data)
- {
- m_sol20_fa &= 0xfe;
- m_sol20_fc = data;
- }
-}
-
-void sol20_state::sol20(machine_config &config)
-{
- /* basic machine hardware */
- I8080A(config, m_maincpu, 14.318181_MHz_XTAL / 7); // divider selectable as 5, 6 or 7 through jumpers
- m_maincpu->set_addrmap(AS_PROGRAM, &sol20_state::sol20_mem);
- m_maincpu->set_addrmap(AS_IO, &sol20_state::sol20_io);
- m_maincpu->out_inte_func().set("speaker", FUNC(speaker_sound_device::level_w));
-
- /* video hardware */
- SCREEN(config, m_screen, SCREEN_TYPE_RASTER);
- m_screen->set_raw(14.318181_MHz_XTAL, 918, 0, 576, 260, 0, 208);
- m_screen->set_screen_update(FUNC(sol20_state::screen_update));
- m_screen->set_palette("palette");
-
- GFXDECODE(config, "gfxdecode", "palette", gfx_sol20);
- PALETTE(config, "palette", palette_device::MONOCHROME);
-
- /* sound hardware */
- SPEAKER(config, "mono").front_center();
- SPEAKER_SOUND(config, "speaker").add_route(ALL_OUTPUTS, "mono", 2.00); // music board
-
- // devices
- CASSETTE(config, m_cass1).set_formats(sol20_cassette_formats);
- m_cass1->set_default_state(CASSETTE_PLAY | CASSETTE_MOTOR_ENABLED | CASSETTE_SPEAKER_ENABLED);
- m_cass1->add_route(ALL_OUTPUTS, "mono", 0.05); // cass1 speaker
- m_cass1->set_interface("sol20_cass");
-
- CASSETTE(config, m_cass2).set_formats(sol20_cassette_formats);
- m_cass2->set_default_state(CASSETTE_PLAY | CASSETTE_MOTOR_ENABLED | CASSETTE_SPEAKER_ENABLED);
- m_cass2->add_route(ALL_OUTPUTS, "mono", 0.05); // cass2 speaker
- m_cass2->set_interface("sol20_cass");
-
- AY51013(config, m_uart); // TMS6011NC
- m_uart->set_auto_rdav(true); // ROD (pin 4) tied to RDD (pin 18)
-
- CLOCK(config, m_uart_clock, 4800);
- m_uart_clock->signal_handler().set(m_uart, FUNC(ay51013_device::write_rcp));
- m_uart_clock->signal_handler().append(m_uart, FUNC(ay51013_device::write_tcp));
-
- RS232_PORT(config, m_rs232, default_rs232_devices, nullptr);
-
- AY51013(config, m_uart_s); // TMS6011NC
- m_uart_s->read_si_callback().set(m_rs232, FUNC(rs232_port_device::rxd_r));
- m_uart_s->write_so_callback().set(m_rs232, FUNC(rs232_port_device::write_txd));
- m_uart_s->set_auto_rdav(true); // ROD (pin 4) tied to RDD (pin 18)
-
- CLOCK(config, m_uart_s_clock, 4800);
- m_uart_s_clock->signal_handler().set(m_uart_s, FUNC(ay51013_device::write_rcp));
- m_uart_s_clock->signal_handler().append(m_uart_s, FUNC(ay51013_device::write_tcp));
-
- generic_keyboard_device &keyboard(GENERIC_KEYBOARD(config, "keyboard", 0));
- keyboard.set_keyboard_callback(FUNC(sol20_state::kbd_put));
-
- SOFTWARE_LIST(config, "cass_list").set_original("sol20_cass");
-}
-
-/* ROM definition */
-ROM_START( sol20 )
- ROM_REGION( 0x10000, "maincpu", 0 )
- ROM_SYSTEM_BIOS(0, "solos", "SOLOS")
- ROMX_LOAD( "solos.bin", 0xc000, 0x0800, CRC(4d0af383) SHA1(ac4510c3380ed4a31ccf4f538af3cb66b76701ef), ROM_BIOS(0) ) // from solace emu
- ROM_SYSTEM_BIOS(1, "dpmon", "DPMON")
- ROMX_LOAD( "dpmon.bin", 0xc000, 0x0800, BAD_DUMP CRC(2a84f099) SHA1(60ff6e38082c50afcf0f40707ef65668a411008b), ROM_BIOS(1) )
- ROM_SYSTEM_BIOS(2, "consol", "CONSOL")
- ROMX_LOAD( "consol.bin", 0xc000, 0x0400, BAD_DUMP CRC(80bf6d85) SHA1(84b81c60bb08a3a5435ec1be56a67aa695bce099), ROM_BIOS(2) )
- ROM_SYSTEM_BIOS(3, "solos2", "Solos Patched")
- ROMX_LOAD( "solos2.bin", 0xc000, 0x0800, CRC(7776cc7d) SHA1(c4739a9ea7e8146ce7ae3305ed526b6045efa9d6), ROM_BIOS(3) ) // from Nama
- ROM_SYSTEM_BIOS(4, "bootload", "BOOTLOAD")
- ROMX_LOAD( "bootload.bin", 0xc000, 0x0800, BAD_DUMP CRC(4261ac71) SHA1(4752408ac85d88857e8e9171c7f42bd623c9271e), ROM_BIOS(4) ) // from Nama
-// This one doesn't work
- ROM_SYSTEM_BIOS(5, "cuter", "CUTER")
- ROMX_LOAD( "cuter.bin", 0xc000, 0x0800, BAD_DUMP CRC(39cca901) SHA1(33725d6da63e295552ee13f0a735d33aee8f0d17), ROM_BIOS(5) ) // from Nama
-
- ROM_REGION( 0x1000, "chargen", 0 )
- ROM_LOAD( "6574.bin", 0x0000, 0x0800, BAD_DUMP CRC(fd75df4f) SHA1(4d09aae2f933478532b7d3d1a2dee7123d9828ca) )
- ROM_LOAD( "6575.bin", 0x0800, 0x0800, BAD_DUMP CRC(cfdb76c2) SHA1(ab00798161d13f07bee3cf0e0070a2f0a805591f) )
-
- ROM_REGION( 0x100, "keyboard", 0 )
- ROM_LOAD( "8574.u18", 0x000, 0x100, NO_DUMP ) // 256x4 bipolar PROM or mask ROM; second half unused
-ROM_END
-
-/* Driver */
-// YEAR NAME PARENT COMPAT MACHINE INPUT CLASS INIT COMPANY FULLNAME FLAGS
-COMP( 1976, sol20, 0, 0, sol20, sol20, sol20_state, init_sol20, "Processor Technology Corporation", "Sol-20 Terminal Computer", 0 )