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