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