1 // license:BSD-3-Clause
2 // copyright-holders:AJR
3 /***********************************************************************************************************************************
4 
5     The Visual 500 and 550 are the graphical members of the third series of display terminals released by Visual Technology.
6     While they appear to use the same character generators as the text-mode-only Visual 300 and 330 and have similar detachable
7     keyboards, they uniquely feature high-definition green-screen (P39 phosphor) monitors and support Tektronix 4010/4014-
8     compatible graphics at a resolution of 768 x 555 pixels.
9 
10     The VT100-compatible Visual 550 was released first, and conforms to the ANSI X3.64 standard (like the Visual 300).
11     The Visual 500 instead emulates the ADM3A, D200, Hazeltine 1500 and VT52 terminals (like the Visual 330).
12 
13 ***********************************************************************************************************************************/
14 
15 #include "emu.h"
16 //include "bus/rs232/rs232.h"
17 #include "cpu/z80/z80.h"
18 #include "machine/com8116.h"
19 #include "machine/input_merger.h"
20 #include "machine/nvram.h"
21 #include "machine/i8251.h"
22 #include "machine/i8255.h"
23 #include "machine/v102_kbd.h"
24 #include "machine/z80sio.h"
25 #include "video/scn2674.h"
26 #include "video/upd7220.h"
27 #include "screen.h"
28 
29 class v550_state : public driver_device
30 {
31 public:
v550_state(const machine_config & mconfig,device_type type,const char * tag)32 	v550_state(const machine_config &mconfig, device_type type, const char *tag)
33 		: driver_device(mconfig, type, tag)
34 		, m_maincpu(*this, "maincpu")
35 		, m_screen(*this, "screen")
36 		, m_chargen(*this, "chargen")
37 		, m_usart(*this, "usart")
38 	{ }
39 
40 	void v550(machine_config &config);
41 
42 private:
screen_update(screen_device & screen,bitmap_rgb32 & bitmap,const rectangle & cliprect)43 	u32 screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect) { return 0; }
44 
45 	void mem_map(address_map &map);
46 	void io_map(address_map &map);
47 	void pvtc_char_map(address_map &map);
48 	void pvtc_attr_map(address_map &map);
49 
50 	virtual void machine_start() override;
51 
52 	required_device<cpu_device> m_maincpu;
53 	required_device<screen_device> m_screen;
54 	required_region_ptr<u8> m_chargen;
55 	required_device<i8251_device> m_usart;
56 };
57 
58 
mem_map(address_map & map)59 void v550_state::mem_map(address_map &map)
60 {
61 	map(0x0000, 0x7bff).rom().region("maincpu", 0);
62 	map(0x7c00, 0x7fff).ram().share("nvram"); // actually 4 bits wide
63 	map(0x8000, 0x87ff).ram();
64 }
65 
io_map(address_map & map)66 void v550_state::io_map(address_map &map)
67 {
68 	map.global_mask(0xff);
69 	map(0x00, 0x01).rw("gdc", FUNC(upd7220_device::read), FUNC(upd7220_device::write));
70 	map(0x10, 0x10).w("brg1", FUNC(com8116_device::stt_str_w));
71 	map(0x20, 0x23).rw("ppi", FUNC(i8255_device::read), FUNC(i8255_device::write));
72 	map(0x30, 0x31).rw(m_usart, FUNC(i8251_device::read), FUNC(i8251_device::write));
73 	map(0x40, 0x40).rw("mpsc", FUNC(upd7201_device::da_r), FUNC(upd7201_device::da_w));
74 	map(0x41, 0x41).rw("mpsc", FUNC(upd7201_device::ca_r), FUNC(upd7201_device::ca_w));
75 	map(0x48, 0x48).rw("mpsc", FUNC(upd7201_device::db_r), FUNC(upd7201_device::db_w));
76 	map(0x49, 0x49).rw("mpsc", FUNC(upd7201_device::cb_r), FUNC(upd7201_device::cb_w));
77 	map(0x50, 0x50).w("brg2", FUNC(com8116_device::stt_str_w));
78 	map(0x60, 0x67).rw("pvtc", FUNC(scn2672_device::read), FUNC(scn2672_device::write));
79 	map(0x70, 0x70).rw("pvtc", FUNC(scn2672_device::buffer_r), FUNC(scn2672_device::buffer_w));
80 	map(0x71, 0x71).rw("pvtc", FUNC(scn2672_device::attr_buffer_r), FUNC(scn2672_device::attr_buffer_w));
81 }
82 
pvtc_char_map(address_map & map)83 void v550_state::pvtc_char_map(address_map &map)
84 {
85 	map(0x0000, 0x0fff).ram();
86 }
87 
pvtc_attr_map(address_map & map)88 void v550_state::pvtc_attr_map(address_map &map)
89 {
90 	map(0x0000, 0x0fff).ram();
91 }
92 
93 
INPUT_PORTS_START(v550)94 INPUT_PORTS_START(v550)
95 INPUT_PORTS_END
96 
97 
98 void v550_state::machine_start()
99 {
100 	m_usart->write_cts(0);
101 }
102 
v550(machine_config & config)103 void v550_state::v550(machine_config &config)
104 {
105 	Z80(config, m_maincpu, 34.846_MHz_XTAL / 16); // NEC D780C (2.177875 MHz verified)
106 	m_maincpu->set_addrmap(AS_PROGRAM, &v550_state::mem_map);
107 	m_maincpu->set_addrmap(AS_IO, &v550_state::io_map);
108 
109 	NVRAM(config, "nvram", nvram_device::DEFAULT_ALL_0); // NEC D444C-2 + battery
110 
111 	upd7220_device &gdc(UPD7220(config, "gdc", 34.846_MHz_XTAL / 16)); // NEC D7220D (2.177875 MHz verified)
112 	gdc.set_screen("screen");
113 
114 	I8255(config, "ppi"); // NEC D8255AC-5
115 
116 	I8251(config, m_usart, 34.846_MHz_XTAL / 16); // NEC D8251AC
117 	m_usart->txd_handler().set("keyboard", FUNC(v550_keyboard_device::write_rxd));
118 	m_usart->rxrdy_handler().set("mainint", FUNC(input_merger_device::in_w<1>));
119 
120 	upd7201_device& mpsc(UPD7201(config, "mpsc", 34.846_MHz_XTAL / 16)); // NEC D7201C
121 	mpsc.out_int_callback().set("mainint", FUNC(input_merger_device::in_w<0>));
122 
123 	INPUT_MERGER_ANY_HIGH(config, "mainint").output_handler().set_inputline(m_maincpu, INPUT_LINE_IRQ0);
124 
125 	com8116_device &brg1(COM8116_020(config, "brg1", 1.8432_MHz_XTAL)); // SMC COM8116T-020
126 	brg1.ft_handler().set("mpsc", FUNC(upd7201_device::txcb_w));
127 	brg1.ft_handler().append("mpsc", FUNC(upd7201_device::rxcb_w));
128 	brg1.fr_handler().set("usart", FUNC(i8251_device::write_txc));
129 	brg1.fr_handler().append("usart", FUNC(i8251_device::write_rxc));
130 
131 	com8116_device &brg2(COM8116_020(config, "brg2", 1.8432_MHz_XTAL)); // SMC COM8116T-020
132 	brg2.ft_handler().set("mpsc", FUNC(upd7201_device::txca_w));
133 	brg2.fr_handler().set("mpsc", FUNC(upd7201_device::rxca_w));
134 
135 	v550_keyboard_device &keyboard(V550_KEYBOARD(config, "keyboard"));
136 	keyboard.txd_callback().set(m_usart, FUNC(i8251_device::write_rxd));
137 
138 	SCREEN(config, m_screen, SCREEN_TYPE_RASTER);
139 	m_screen->set_raw(34.846_MHz_XTAL, 19 * 102, 0, 19 * 80, 295, 0, 272);
140 	m_screen->set_screen_update(FUNC(v550_state::screen_update));
141 
142 	scn2672_device &pvtc(SCN2672(config, "pvtc", 34.846_MHz_XTAL / 19));
143 	pvtc.set_addrmap(0, &v550_state::pvtc_char_map);
144 	pvtc.set_addrmap(1, &v550_state::pvtc_attr_map);
145 	pvtc.set_character_width(19);
146 	pvtc.intr_callback().set_inputline(m_maincpu, INPUT_LINE_NMI);
147 	pvtc.set_screen("screen");
148 	// SCB2673 clock verified at 17.423 MHz
149 }
150 
151 
152 ROM_START( v550 )
153 	// Silkscreened on bottom left of PCB: "PA016-A REV B"
154 
155 	ROM_REGION(0x8000, "maincpu", 0)
156 	ROM_LOAD("e244-001_r07_u42.bin", 0x0000, 0x2000, CRC(d18a8b62) SHA1(7faf8a9f1ae3148adacbff960a2663793710cef2))
157 	ROM_LOAD("e244-002_r07_u43.bin", 0x2000, 0x2000, CRC(1b62db47) SHA1(7ad69aea6088545d843c2e95737895f81c269ccc))
158 	ROM_LOAD("e244-003_r07_u44.bin", 0x4000, 0x2000, CRC(f6d6f734) SHA1(a9efa8ebe86addb77872dbe9863ea7f75b33a2b9))
159 	ROM_LOAD("e244-017_r07_u45.bin", 0x6000, 0x2000, CRC(b0dcd535) SHA1(9237723d01a720217f50f756bb55c7e5ed05a594))
160 
161 	ROM_REGION(0x1000, "chargen", 0)
162 	ROM_LOAD("e242-085_r03_u97.bin", 0x0000, 0x1000, CRC(8a491cee) SHA1(d8a9546a7dd2ffc0a5e54524ee16068dde56975c))
163 ROM_END
164 
165 COMP( 1982, v550, 0, 0, v550, v550, v550_state, empty_init, "Visual Technology", "Visual 550", MACHINE_IS_SKELETON )
166