1 // license:BSD-3-Clause
2 // copyright-holders:Sven Schnelle
3 /***************************************************************************
4 
5   HP98643 LANIC Ethernet card
6 
7 ***************************************************************************/
8 
9 #include "emu.h"
10 #include "hp98643.h"
11 #include "machine/am79c90.h"
12 
13 //#define VERBOSE 1
14 #include "logmacro.h"
15 
16 DEFINE_DEVICE_TYPE_NS(HPDIO_98643, bus::hp_dio, dio16_98643_device, "dio98643", "HP98643A LANIC Ethernet card")
17 
18 namespace bus { namespace hp_dio {
19 
device_add_mconfig(machine_config & config)20 void dio16_98643_device::device_add_mconfig(machine_config &config)
21 {
22 	AM7990(config, m_lance, XTAL(20'000'000));
23 	m_lance->intr_out().set(FUNC(dio16_98643_device::lance_int_w));
24 	m_lance->dma_out().set(FUNC(dio16_98643_device::lance_dma_out));
25 	m_lance->dma_in().set(FUNC(dio16_98643_device::lance_dma_in));
26 }
27 
dio16_98643_device(const machine_config & mconfig,const char * tag,device_t * owner,uint32_t clock)28 dio16_98643_device::dio16_98643_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
29 	dio16_98643_device(mconfig, HPDIO_98643, tag, owner, clock)
30 {
31 }
32 
dio16_98643_device(const machine_config & mconfig,device_type type,const char * tag,device_t * owner,uint32_t clock)33 dio16_98643_device::dio16_98643_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock) :
34 	device_t(mconfig, type, tag, owner, clock),
35 	device_dio16_card_interface(mconfig, *this),
36 	m_lance(*this, "lance"),
37 	m_switches{*this, "switches"}
38 {
39 }
40 
41 static INPUT_PORTS_START(hp98643_port)
42 	PORT_START("switches")
43 	PORT_DIPNAME(REG_SWITCHES_REMOTE, 0x00, "Remote")
DEF_STR(Off)44 	PORT_DIPSETTING(0x00, DEF_STR(Off))
45 	PORT_DIPSETTING(REG_SWITCHES_REMOTE, DEF_STR(On))
46 
47 	PORT_DIPNAME(REG_SWITCHES_INT_LEVEL_MASK << REG_SWITCHES_INT_LEVEL_SHIFT, 0x02 << REG_SWITCHES_INT_LEVEL_SHIFT, "Interrupt level")
48 	PORT_DIPSETTING(0 << REG_SWITCHES_INT_LEVEL_SHIFT, "3")
49 	PORT_DIPSETTING(1 << REG_SWITCHES_INT_LEVEL_SHIFT, "4")
50 	PORT_DIPSETTING(2 << REG_SWITCHES_INT_LEVEL_SHIFT, "5")
51 	PORT_DIPSETTING(3 << REG_SWITCHES_INT_LEVEL_SHIFT, "6")
52 
53 	PORT_DIPNAME(REG_SWITCHES_SELECT_CODE_MASK << REG_SWITCHES_SELECT_CODE_SHIFT, 21 << REG_SWITCHES_SELECT_CODE_SHIFT, "Select code")
54 	PORT_DIPSETTING(0 << REG_SWITCHES_SELECT_CODE_SHIFT, "0")
55 	PORT_DIPSETTING(1 << REG_SWITCHES_SELECT_CODE_SHIFT, "1")
56 	PORT_DIPSETTING(2 << REG_SWITCHES_SELECT_CODE_SHIFT, "2")
57 	PORT_DIPSETTING(3 << REG_SWITCHES_SELECT_CODE_SHIFT, "3")
58 	PORT_DIPSETTING(4 << REG_SWITCHES_SELECT_CODE_SHIFT, "4")
59 	PORT_DIPSETTING(5 << REG_SWITCHES_SELECT_CODE_SHIFT, "5")
60 	PORT_DIPSETTING(6 << REG_SWITCHES_SELECT_CODE_SHIFT, "6")
61 	PORT_DIPSETTING(7 << REG_SWITCHES_SELECT_CODE_SHIFT, "7")
62 	PORT_DIPSETTING(8 << REG_SWITCHES_SELECT_CODE_SHIFT, "8")
63 	PORT_DIPSETTING(9 << REG_SWITCHES_SELECT_CODE_SHIFT, "9")
64 	PORT_DIPSETTING(10 << REG_SWITCHES_SELECT_CODE_SHIFT, "10")
65 	PORT_DIPSETTING(11 << REG_SWITCHES_SELECT_CODE_SHIFT, "11")
66 	PORT_DIPSETTING(12 << REG_SWITCHES_SELECT_CODE_SHIFT, "12")
67 	PORT_DIPSETTING(13 << REG_SWITCHES_SELECT_CODE_SHIFT, "13")
68 	PORT_DIPSETTING(14 << REG_SWITCHES_SELECT_CODE_SHIFT, "14")
69 	PORT_DIPSETTING(15 << REG_SWITCHES_SELECT_CODE_SHIFT, "15")
70 	PORT_DIPSETTING(16 << REG_SWITCHES_SELECT_CODE_SHIFT, "16")
71 	PORT_DIPSETTING(17 << REG_SWITCHES_SELECT_CODE_SHIFT, "17")
72 	PORT_DIPSETTING(18 << REG_SWITCHES_SELECT_CODE_SHIFT, "18")
73 	PORT_DIPSETTING(19 << REG_SWITCHES_SELECT_CODE_SHIFT, "19")
74 	PORT_DIPSETTING(20 << REG_SWITCHES_SELECT_CODE_SHIFT, "20")
75 	PORT_DIPSETTING(21 << REG_SWITCHES_SELECT_CODE_SHIFT, "21")
76 	PORT_DIPSETTING(22 << REG_SWITCHES_SELECT_CODE_SHIFT, "22")
77 	PORT_DIPSETTING(23 << REG_SWITCHES_SELECT_CODE_SHIFT, "23")
78 	PORT_DIPSETTING(24 << REG_SWITCHES_SELECT_CODE_SHIFT, "24")
79 	PORT_DIPSETTING(25 << REG_SWITCHES_SELECT_CODE_SHIFT, "25")
80 	PORT_DIPSETTING(26 << REG_SWITCHES_SELECT_CODE_SHIFT, "26")
81 	PORT_DIPSETTING(27 << REG_SWITCHES_SELECT_CODE_SHIFT, "27")
82 	PORT_DIPSETTING(28 << REG_SWITCHES_SELECT_CODE_SHIFT, "28")
83 	PORT_DIPSETTING(29 << REG_SWITCHES_SELECT_CODE_SHIFT, "29")
84 	PORT_DIPSETTING(30 << REG_SWITCHES_SELECT_CODE_SHIFT, "30")
85 	PORT_DIPSETTING(31 << REG_SWITCHES_SELECT_CODE_SHIFT, "31")
86 INPUT_PORTS_END
87 
88 ioport_constructor dio16_98643_device::device_input_ports() const
89 {
90 	return INPUT_PORTS_NAME(hp98643_port);
91 }
92 
device_start()93 void dio16_98643_device::device_start()
94 {
95 	save_item(NAME(m_sc));
96 	save_item(NAME(m_installed_io));
97 	save_item(NAME(m_ram));
98 	m_installed_io = false;
99 }
100 
device_reset()101 void dio16_98643_device::device_reset()
102 {
103 	if (!m_installed_io) {
104 		uint8_t code = (m_switches->read() >> REG_SWITCHES_SELECT_CODE_SHIFT)
105 					& REG_SWITCHES_SELECT_CODE_MASK;
106 
107 		uint32_t baseaddr = 0x600000 + (code << 16);
108 
109 		program_space().install_device(baseaddr, baseaddr + 0xffff,
110 			*this, &dio16_98643_device::addrmap);
111 		m_installed_io = true;
112 	}
113 	m_sc = REG_SC_REV;
114 	m_sc |= get_irq_line() << 4;
115 }
116 
WRITE_LINE_MEMBER(dio16_98643_device::lance_int_w)117 WRITE_LINE_MEMBER(dio16_98643_device::lance_int_w)
118 {
119 	if (state)
120 		m_sc &= ~REG_SC_IP;
121 	else
122 		m_sc |= REG_SC_IP;
123 	update_int();
124 }
125 
sc_w(uint16_t data)126 void dio16_98643_device::sc_w(uint16_t data)
127 {
128 	LOG("%s: %02x\n", __func__, data);
129 	data &= (REG_SC_LOCK|REG_SC_IE);
130 	m_sc &= ~(REG_SC_LOCK|REG_SC_IE);
131 
132 	if (data & REG_SC_LOCK)
133 		data |= REG_STATUS_ACK;
134 
135 	m_sc |= data;
136 	update_int();
137 }
138 
sc_r()139 uint16_t dio16_98643_device::sc_r()
140 {
141 	LOG("%s: %02x\n", __func__, m_sc);
142 	return m_sc;
143 }
144 
id_r()145 uint16_t dio16_98643_device::id_r()
146 {
147 	return (REG_ID | (m_switches->read() & REG_SWITCHES_REMOTE));
148 }
149 
id_w(uint16_t data)150 void dio16_98643_device::id_w(uint16_t data)
151 {
152 	reset();
153 }
novram_r(offs_t offset)154 uint16_t dio16_98643_device::novram_r(offs_t offset)
155 {
156 	return m_novram[offset];
157 }
158 
novram_w(offs_t offset,uint16_t data,uint16_t mem_mask)159 void dio16_98643_device::novram_w(offs_t offset, uint16_t data, uint16_t mem_mask)
160 {
161 	COMBINE_DATA(&m_novram[offset & 0x3f]);
162 }
163 
lance_dma_out(offs_t offset,uint16_t data,uint16_t mem_mask)164 void dio16_98643_device::lance_dma_out(offs_t offset, uint16_t data, uint16_t mem_mask)
165 {
166 	LOG("%s: offset=%04x, data=%d\n", __func__, offset, data);
167 	COMBINE_DATA(&m_ram[(offset >> 1) & 0x1fff]);
168 }
169 
lance_dma_in(offs_t offset)170 uint16_t dio16_98643_device::lance_dma_in(offs_t offset)
171 {
172 	uint16_t ret = m_ram[(offset >> 1) & 0x1fff];
173 
174 	LOG("%s: offset=%04x data %04x\n", __func__, offset, ret);
175 	return ret;
176 }
177 
get_irq_line()178 int dio16_98643_device::get_irq_line()
179 {
180 	return (m_switches->read() >> REG_SWITCHES_INT_LEVEL_SHIFT) & REG_SWITCHES_INT_LEVEL_MASK;
181 }
182 
update_int()183 void dio16_98643_device::update_int()
184 {
185 	const int line = get_irq_line() + 3;
186 	const bool state = (m_sc & (REG_SC_IE|REG_SC_IP)) == (REG_SC_IE|REG_SC_IP);
187 	LOG("%s: line %d, state %d\n", __func__, line, state);
188 	irq3_out(state && line == 3);
189 	irq4_out(state && line == 4);
190 	irq5_out(state && line == 5);
191 	irq6_out(state && line == 6);
192 }
193 
addrmap(address_map & map)194 void dio16_98643_device::addrmap(address_map &map)
195 {
196 	map(0x0000, 0x0001).rw(FUNC(dio16_98643_device::id_r), FUNC(dio16_98643_device::id_w));
197 	map(0x0002, 0x0003).rw(FUNC(dio16_98643_device::sc_r), FUNC(dio16_98643_device::sc_w));
198 	map(0x4000, 0x4003).lrw16(
199 			[this] (address_space &space, offs_t offset) -> u16 {
200 				m_sc |= REG_STATUS_ACK;
201 				return m_lance->regs_r(space, offset);
202 			}, "lance_r",
203 			[this] (offs_t offset, u16 data) {
204 				m_sc |= REG_STATUS_ACK;
205 				return m_lance->regs_w(offset, data);
206 			}, "lance_w");
207 
208 	map(0x8000, 0xbfff).lrw16(
209 			NAME([this] (offs_t offset) -> u16 { return m_ram[offset]; }),
210 			NAME([this] (offs_t offset, u16 data, u16 mem_mask) { COMBINE_DATA(&m_ram[offset]); }));
211 
212 	map(0xc000, 0xffff).rw(FUNC(dio16_98643_device::novram_r), FUNC(dio16_98643_device::novram_w));
213 }
214 
215 } // namespace bus::hp_dio
216 } // namespace bus
217