1 // license:BSD-3-Clause
2 // copyright-holders:Robbbert
3 /******************************************************************************************************
4 
5 Ultim809 homebrew computer by Matthew Sarnoff, 2011
6 http://www.msarnoff.org/6809/
7 
8 Was developed during 2009-2011, but unknown if it was ever finished. Most of the claimed
9 features don't seem to be there or are inaccessible.
10 
11 2020-06-04 Skeleton [Robbbert]
12 
13 If someone knows more about the system, please update this source.
14 
15 
16 ToDo:
17 - Mirrors
18 - Video RAM has 2 banks of 0x4000 each. There's no way to select banks in the VDP code.
19 - Sound (hooked up, unable to test)
20 - FTDI connector
21 - Keyboard, PS/2 type from an older PC, connects to VIA PB7 and CA1.
22 - Joysticks (Sega gamepad, or Atari joystick only).
23 - Reset button, Run/Halt switch.
24 - Power LED, Bus status LEDs (2), User status LEDs (2).
25 - RTC type DS1307, connects to VIA PB0,PB1,PB6; xtal 32'768; battery CR2032.
26 - SD card slots and SPDI shift register (74595).
27 - Need software (some is supposed to exist; if found we could use a quickloader to get it in)
28 
29 Status:
30 - It ran into the weeds at 0x100, so memory is patched there to jump to the sign-on screen.
31 - When it says to press INTERRUPT, press F1. May need multiple presses to get over random errors.
32 - Various commands starting with k are supposed to be valid, but nothing is acceptable.
33 - If an error occurs it locks up and you have to press F1 again.
34 - Even though it is suggested to use a dumb terminal, nothing ever shows on it.
35 
36 ****************************************************************************************************/
37 
38 #include "emu.h"
39 #include "cpu/m6809/m6809.h"
40 #include "video/tms9928a.h"
41 #include "machine/6522via.h"
42 #include "sound/ay8910.h"
43 #include "machine/ins8250.h"
44 #include "bus/rs232/rs232.h"
45 #include "speaker.h"
46 
47 class ultim809_state : public driver_device
48 {
49 public:
ultim809_state(const machine_config & mconfig,device_type type,const char * tag)50 	ultim809_state(const machine_config &mconfig, device_type type, const char *tag)
51 		: driver_device(mconfig, type, tag)
52 		, m_maincpu(*this, "maincpu")
53 		, m_via(*this, "via")
54 		, m_crtc(*this, "crtc")
55 		, m_psg(*this, "psg")
56 		, m_uart(*this, "uart")
57 		, m_membank(0)
58 	{}
59 
60 	void ultim809(machine_config &config);
61 
62 	DECLARE_INPUT_CHANGED_MEMBER(nmi_button);
63 
64 private:
65 	void mem_map(address_map &map);
66 	virtual void machine_start() override;
67 	std::unique_ptr<u8[]> m_ram;
68 	required_device<cpu_device> m_maincpu;
69 	required_device<via6522_device> m_via;
70 	required_device<tms9918a_device> m_crtc;
71 	required_device<ay8910_device> m_psg;
72 	required_device<ns16550_device> m_uart;
73 	u8 m_membank;
74 };
75 
mem_map(address_map & map)76 void ultim809_state::mem_map(address_map &map)
77 {
78 	map.unmap_value_high();
79 	// main ram banks 0 and 1
80 	map(0x0000, 0x7fff).lrw8(NAME([this] (offs_t offset) { return m_ram[offset]; }), NAME([this] (offs_t offset, u8 data) { m_ram[offset] = data; } ));
81 	// main ram any bank
82 	map(0x8000, 0xbfff).lrw8(NAME([this] (offs_t offset) { return m_ram[offset | (m_membank << 14)]; }),
83 							 NAME([this] (offs_t offset, u8 data) { m_ram[offset | (m_membank << 14)] = data; } )); // u8
84 	// devices
85 	map(0xc000, 0xc00f).m(m_via, FUNC(via6522_device::map)); // u11
86 	map(0xc400, 0xc407).rw(m_uart, FUNC(ns16550_device::ins8250_r), FUNC(ns16550_device::ins8250_w));  // u16
87 	map(0xc800, 0xc800); //.r  chip enable 74595
88 	map(0xcc00, 0xcc00).rw(m_crtc, FUNC(tms9918a_device::vram_read), FUNC(tms9918a_device::vram_write));
89 	map(0xcc01, 0xcc01).rw(m_crtc, FUNC(tms9918a_device::register_read), FUNC(tms9918a_device::register_write));
90 	map(0xcc02, 0xcc03).rw(m_psg, FUNC(ay8910_device::data_r), FUNC(ay8910_device::address_data_w));
91 	map(0xcc04, 0xcc04); //.r  select lower 16k of VRAM
92 	map(0xcc06, 0xcc06); //.r  clear gamepad pin 7
93 	map(0xcc0c, 0xcc0c); //.r  select upper 16k of VRAM
94 	map(0xcc0e, 0xcc0e); //.r  set gamepad pin 7
95 	map(0xd000, 0xd3ff); // expansion slot 1 (not used)
96 	map(0xd400, 0xd7ff); // expansion slot 2 (not used)
97 	map(0xd800, 0xdbff); // expansion slot 3 (not used)
98 	map(0xdc00, 0xdfff); // expansion slot 4 (not used)
99 	// rom
100 	map(0xe000, 0xffff).rom().region("maincpu", 0); // u9
101 }
102 
103 
104 static INPUT_PORTS_START( ultim809 )
105 	PORT_START("RESET")
PORT_CODE(KEYCODE_F1)106 	PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Interrupt") PORT_CODE(KEYCODE_F1) PORT_CHANGED_MEMBER(DEVICE_SELF, ultim809_state, nmi_button, 0)
107 INPUT_PORTS_END
108 
109 INPUT_CHANGED_MEMBER(ultim809_state::nmi_button)
110 {
111 	m_maincpu->set_input_line(INPUT_LINE_NMI, newval ? ASSERT_LINE : CLEAR_LINE);
112 }
113 
machine_start()114 void ultim809_state::machine_start()
115 {
116 	m_ram = make_unique_clear<u8[]>(0x80000);
117 	save_pointer(NAME(m_ram), 0x80000);
118 	save_item(NAME(m_membank));
119 	// Send it to the sign-on instead of into the weeds
120 	m_ram[0x100] = 0x10;
121 	m_ram[0x101] = 0x3F;
122 }
123 
124 static DEVICE_INPUT_DEFAULTS_START( terminal )
125 	DEVICE_INPUT_DEFAULTS( "RS232_RXBAUD", 0xff, RS232_BAUD_38400 )
126 	DEVICE_INPUT_DEFAULTS( "RS232_TXBAUD", 0xff, RS232_BAUD_38400 )
127 DEVICE_INPUT_DEFAULTS_END
128 
ultim809(machine_config & config)129 void ultim809_state::ultim809(machine_config &config)
130 {
131 	// basic machine hardware
132 	MC6809E(config, m_maincpu, 8000000 / 4);  // 68B09E
133 	m_maincpu->set_addrmap(AS_PROGRAM, &ultim809_state::mem_map);
134 
135 	// video hardware
136 	TMS9918A(config, m_crtc, XTAL(10'738'635));
137 	m_crtc->set_screen("screen");
138 	m_crtc->set_vram_size(0x4000);    // actually 2 banks of 0x4000
139 	m_crtc->int_callback().set_inputline(m_maincpu, M6809_IRQ_LINE);
140 	SCREEN(config, "screen", SCREEN_TYPE_RASTER);
141 
142 	VIA6522(config, m_via, 8000000 / 4);
143 	// Memory banking: up to 32 banks with inbuilt U8, or replace it with external memory to get the full 4 MB
144 	m_via->writepa_handler().set([this] (u8 data) { m_membank = data & 0x1F; });   // memory banking
145 	//m_via->readpb_handler().set(FUNC(ultim809_state::portb_r));    // serial
146 	//m_via->writepb_handler().set(FUNC(ultim809_state::portb_w));   // serial
147 	m_via->irq_handler().set_inputline(m_maincpu, M6809_FIRQ_LINE);
148 
149 	// sound hardware
150 	SPEAKER(config, "mono").front_center();
151 	AY8910(config, m_psg, 8000000 / 4).add_route(ALL_OUTPUTS, "mono", 0.50);
152 	//m_psg->port_a_read_callback(FUNC(ultim809_state::...);  // joystick 1
153 	//m_psg->port_b_read_callback(FUNC(ultim809_state::...);  // joystick 2
154 
155 	NS16550(config, m_uart, XTAL(1'843'200));
156 	m_uart->out_tx_callback().set("rs232", FUNC(rs232_port_device::write_txd));
157 
158 	// there's no rs232 port, it uses FTDI, but we need to see what's going on
159 	rs232_port_device &rs232(RS232_PORT(config, "rs232", default_rs232_devices, "terminal"));
160 	rs232.rxd_handler().set(m_uart, FUNC(ins8250_uart_device::rx_w));
161 	rs232.set_option_device_input_defaults("terminal", DEVICE_INPUT_DEFAULTS_NAME(terminal)); // must be exactly here
162 }
163 
164 /* ROM definition */
165 ROM_START( ultim809 )
166 	ROM_REGION(0x2000, "maincpu", 0)
167 	ROM_LOAD( "ultim809.u9", 0x0000, 0x2000, CRC(b827aaf1) SHA1(64d9e94542d8ff13f64a4d787508eef7b64d4946) )
168 ROM_END
169 
170 /* Driver */
171 
172 //    YEAR  NAME      PARENT  COMPAT  MACHINE   INPUT     CLASS           INIT         COMPANY            FULLNAME     FLAGS
173 COMP( 2010, ultim809, 0,      0,      ultim809, ultim809, ultim809_state, empty_init, "Matthew Sarnoff", "Ultim809", MACHINE_IS_INCOMPLETE | MACHINE_IS_SKELETON | MACHINE_SUPPORTS_SAVE )
174