1 // license:BSD-3-Clause
2 // copyright-holders:AJR
3 /****************************************************************************
4 
5     Skeleton driver for Ampro Little Board/PC.
6 
7     This is unusual among PC/XT-compatible machines in that many standard
8     peripheral functions, including the interrupt and refresh controllers,
9     are integrated into the V40 CPU itself, with some software assistance
10     to compensate for DMAC incompatibilities. Two Vadem SDIP64 ASICs and a
11     standard FDC and UART provide most other PC-like hardware features. The
12     BIOS also supports the onboard SCSI controller.
13 
14 ****************************************************************************/
15 
16 #include "emu.h"
17 #include "bus/isa/isa.h"
18 #include "bus/isa/isa_cards.h"
19 #include "bus/nscsi/devices.h"
20 #include "bus/rs232/rs232.h"
21 #include "cpu/nec/v5x.h"
22 #include "machine/ins8250.h"
23 #include "machine/ncr5380n.h"
24 #include "machine/upd765.h"
25 #include "sound/spkrdev.h"
26 #include "speaker.h"
27 
28 class lbpc_state : public driver_device
29 {
30 public:
lbpc_state(const machine_config & mconfig,device_type type,const char * tag)31 	lbpc_state(const machine_config &mconfig, device_type type, const char *tag)
32 		: driver_device(mconfig, type, tag)
33 		, m_maincpu(*this, "maincpu")
34 		, m_expbus(*this, "expbus")
35 		, m_speaker(*this, "speaker")
36 		, m_port61(0xff)
37 		, m_speaker_data(false)
38 	{
39 	}
40 
41 	void lbpc(machine_config &config);
42 
43 protected:
44 	virtual void machine_start() override;
45 	virtual void machine_reset() override;
46 
47 private:
48 	u8 exp_dack1_r();
49 	void exp_dack1_w(u8 data);
50 	DECLARE_WRITE_LINE_MEMBER(iochck_w);
51 	u8 port61_r();
52 	void port61_w(u8 data);
53 	DECLARE_WRITE_LINE_MEMBER(out2_w);
54 
55 	void mem_map(address_map &map);
56 	void io_map(address_map &map);
57 
58 	required_device<v40_device> m_maincpu;
59 	required_device<isa8_device> m_expbus;
60 	required_device<speaker_sound_device> m_speaker;
61 
62 	u8 m_port61;
63 	bool m_speaker_data;
64 };
65 
66 
machine_start()67 void lbpc_state::machine_start()
68 {
69 	save_item(NAME(m_port61));
70 	save_item(NAME(m_speaker_data));
71 }
72 
machine_reset()73 void lbpc_state::machine_reset()
74 {
75 	port61_w(0);
76 }
77 
78 
exp_dack1_r()79 u8 lbpc_state::exp_dack1_r()
80 {
81 	return m_expbus->dack_r(0);
82 }
83 
exp_dack1_w(u8 data)84 void lbpc_state::exp_dack1_w(u8 data)
85 {
86 	m_expbus->dack_w(0, data);
87 }
88 
WRITE_LINE_MEMBER(lbpc_state::iochck_w)89 WRITE_LINE_MEMBER(lbpc_state::iochck_w)
90 {
91 	// TODO
92 }
93 
port61_r()94 u8 lbpc_state::port61_r()
95 {
96 	return m_port61;
97 }
98 
port61_w(u8 data)99 void lbpc_state::port61_w(u8 data)
100 {
101 	if (BIT(m_port61, 1) && !BIT(data, 1))
102 		m_speaker->level_w(0);
103 	else if (!BIT(m_port61, 1) && BIT(data, 1))
104 		m_speaker->level_w(m_speaker_data);
105 	m_maincpu->tctl2_w(BIT(data, 0));
106 
107 	m_port61 = data;
108 }
109 
WRITE_LINE_MEMBER(lbpc_state::out2_w)110 WRITE_LINE_MEMBER(lbpc_state::out2_w)
111 {
112 	m_speaker_data = state;
113 	if (BIT(m_port61, 1))
114 		m_speaker->level_w(state);
115 }
116 
mem_map(address_map & map)117 void lbpc_state::mem_map(address_map &map)
118 {
119 	map(0x00000, 0x9ffff).ram(); // 256K, 512K or 768K DRAM
120 	// 0xE0000–0xEFFFF: empty socket
121 	// 0xF0000-0xF7FFF: empty socket
122 	map(0xf8000, 0xfffff).rom().region("bios", 0);
123 }
124 
io_map(address_map & map)125 void lbpc_state::io_map(address_map &map)
126 {
127 	map(0x0061, 0x0061).rw(FUNC(lbpc_state::port61_r), FUNC(lbpc_state::port61_w));
128 	map(0x0330, 0x0337).rw("scsi:7:ncr", FUNC(ncr53c80_device::read), FUNC(ncr53c80_device::write));
129 	map(0x0370, 0x0377).m("fdc", FUNC(wd37c65c_device::map));
130 	map(0x03f8, 0x03ff).rw("com", FUNC(ins8250_device::ins8250_r), FUNC(ins8250_device::ins8250_w));
131 }
132 
133 
INPUT_PORTS_START(lbpc)134 static INPUT_PORTS_START(lbpc)
135 INPUT_PORTS_END
136 
137 
138 void lbpc_state::lbpc(machine_config &config)
139 {
140 	V40(config, m_maincpu, 14.318181_MHz_XTAL); // 7.16 MHz operating frequency
141 	m_maincpu->set_addrmap(AS_PROGRAM, &lbpc_state::mem_map);
142 	m_maincpu->set_addrmap(AS_IO, &lbpc_state::io_map);
143 	m_maincpu->set_tclk(14.318181_MHz_XTAL / 12); // generated by ASIC1
144 	m_maincpu->out_handler<2>().set(FUNC(lbpc_state::out2_w));
145 	m_maincpu->out_hreq_cb().set_inputline(m_maincpu, INPUT_LINE_HALT);
146 	m_maincpu->out_hreq_cb().append(m_maincpu, FUNC(v40_device::hack_w));
147 	m_maincpu->in_memr_cb().set([this] (offs_t offset) { return m_maincpu->space(AS_PROGRAM).read_byte(offset); });
148 	m_maincpu->out_memw_cb().set([this] (offs_t offset, u8 data) { m_maincpu->space(AS_PROGRAM).write_byte(offset, data); });
149 	m_maincpu->in_ior_cb<0>().set(FUNC(lbpc_state::exp_dack1_r));
150 	m_maincpu->out_iow_cb<0>().set(FUNC(lbpc_state::exp_dack1_w));
151 	m_maincpu->in_ior_cb<1>().set("fdc", FUNC(wd37c65c_device::dma_r));
152 	m_maincpu->out_iow_cb<1>().set("fdc", FUNC(wd37c65c_device::dma_w));
153 	m_maincpu->in_ior_cb<2>().set("scsi:7:ncr", FUNC(ncr53c80_device::dma_r));
154 	m_maincpu->out_iow_cb<2>().set("scsi:7:ncr", FUNC(ncr53c80_device::dma_w));
155 
156 	SPEAKER(config, "mono").front_center();
157 	SPEAKER_SOUND(config, m_speaker).add_route(ALL_OUTPUTS, "mono", 0.5);
158 
159 	ins8250_device &com(INS8250(config, "com", 1.8432_MHz_XTAL)); // NS8250AV
160 	com.out_int_callback().set_inputline(m_maincpu, INPUT_LINE_IRQ4);
161 	com.out_rts_callback().set("serial", FUNC(rs232_port_device::write_rts)); // J3 pin 4
162 	com.out_tx_callback().set("serial", FUNC(rs232_port_device::write_txd)); // J3 pin 5
163 	com.out_dtr_callback().set("serial", FUNC(rs232_port_device::write_dtr)); // J3 pin 7
164 
165 	wd37c65c_device &fdc(WD37C65C(config, "fdc", 16_MHz_XTAL, 9.6_MHz_XTAL)); // WD37C65BJM
166 	fdc.intrq_wr_callback().set_inputline(m_maincpu, INPUT_LINE_IRQ6);
167 	fdc.drq_wr_callback().set(m_maincpu, FUNC(v40_device::dreq_w<1>));
168 
169 	NSCSI_BUS(config, "scsi");
170 	NSCSI_CONNECTOR(config, "scsi:0", default_scsi_devices, nullptr);
171 	NSCSI_CONNECTOR(config, "scsi:1", default_scsi_devices, nullptr);
172 	NSCSI_CONNECTOR(config, "scsi:2", default_scsi_devices, nullptr);
173 	NSCSI_CONNECTOR(config, "scsi:3", default_scsi_devices, nullptr);
174 	NSCSI_CONNECTOR(config, "scsi:4", default_scsi_devices, nullptr);
175 	NSCSI_CONNECTOR(config, "scsi:5", default_scsi_devices, nullptr);
176 	NSCSI_CONNECTOR(config, "scsi:6", default_scsi_devices, nullptr);
177 	NSCSI_CONNECTOR(config, "scsi:7").option_set("ncr", NCR53C80).machine_config([this] (device_t *device) {
178 		downcast<ncr5380n_device &>(*device).drq_handler().set(m_maincpu, FUNC(v40_device::dreq_w<2>));
179 	});
180 
181 	rs232_port_device &serial(RS232_PORT(config, "serial", default_rs232_devices, nullptr));
182 	serial.dcd_handler().set("com", FUNC(ins8250_device::dcd_w)); // J3 pin 1
183 	serial.dsr_handler().set("com", FUNC(ins8250_device::dsr_w)); // J3 pin 2
184 	serial.rxd_handler().set("com", FUNC(ins8250_device::rx_w)); // J3 pin 3
185 	serial.cts_handler().set("com", FUNC(ins8250_device::cts_w)); // J3 pin 6
186 	serial.ri_handler().set("com", FUNC(ins8250_device::ri_w)); // J3 pin 8
187 
188 	ISA8(config, m_expbus, 14.318181_MHz_XTAL / 2);
189 	m_expbus->set_memspace(m_maincpu, AS_PROGRAM);
190 	m_expbus->set_iospace(m_maincpu, AS_IO);
191 	m_expbus->drq1_callback().set(m_maincpu, FUNC(v40_device::dreq_w<0>));
192 	m_expbus->irq2_callback().set_inputline(m_maincpu, INPUT_LINE_IRQ2);
193 	m_expbus->irq3_callback().set_inputline(m_maincpu, INPUT_LINE_IRQ3);
194 	m_expbus->irq5_callback().set_inputline(m_maincpu, INPUT_LINE_IRQ5);
195 	m_expbus->iochck_callback().set(FUNC(lbpc_state::iochck_w));
196 
197 	ISA8_SLOT(config, "exp", 0, m_expbus, pc_isa8_cards, "ega", false);
198 }
199 
200 
201 ROM_START(lbpc)
202 	ROM_REGION(0x8000, "bios", 0)
203 	// "Firmware Version 1.0H  03/08/89"
204 	ROM_LOAD("lbpc-bio.rom", 0x0000, 0x8000, CRC(47bddf8b) SHA1(8a04fe34502f9f3bfe1e233762bbd5bbdd1c455d))
205 ROM_END
206 
207 
208 COMP(1989, lbpc, 0, 0, lbpc, lbpc, lbpc_state, empty_init, "Ampro Computers", "Little Board/PC", MACHINE_NOT_WORKING)
209