1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
|
// license:BSD-3-Clause
// copyright-holders:Brice Onken,Tsubai Masanari,Olivier Galibert
// thanks-to:Patrick Mackinlay
/*
* HP 1TV3-0302 SPIFI3-SE SCSI controller
*
* Datasheets for this seem to be impossible to find - the only avaliable implementation to reference that I have
* found is the Sony NEWS APBus NetBSD driver. Hopefully a datasheet will turn up eventually.
* Based on internet research, it seems some HP PA-RISC systems also used the SPIFI3, including the E55.
*
* Because this driver was developed to work with NetBSD, NEWS-OS, and the NWS-5000 monitor ROM, only
* the features and flows that Sony used are implemented. Emulating non-Sony designs using this chip will likely
* require similar RE work to determine the exact SPIFI features used and add support for them into this driver.
* In its current state, this driver is unlikely to work out of the box with any other machines.
*
* Register definitions were derived from the NetBSD source code, copyright (c) 2000 Tsubai Masanari.
* SCSI state machine code was derived from the MAME NCR53C90 driver, copyright (c) Olivier Galibert
*
* References:
* - https://github.com/NetBSD/src/blob/trunk/sys/arch/newsmips/apbus/spifireg.h
* - https://github.com/NetBSD/src/blob/trunk/sys/arch/newsmips/apbus/spifi.c
* - https://github.com/mamedev/mame/blob/master/src/devices/machine/ncr53c90.cpp
*/
#ifndef MAME_MACHINE_SPIFI3_H
#define MAME_MACHINE_SPIFI3_H
#pragma once
#include "machine/nscsi_bus.h"
class spifi3_device
: public nscsi_device,
public nscsi_slot_card_interface
{
public:
spifi3_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock);
void map(address_map &map) ATTR_COLD;
auto irq_handler_cb() { return m_irq_handler.bind(); }
auto drq_handler_cb() { return m_drq_handler.bind(); }
uint8_t dma_r();
void dma_w(uint8_t val);
protected:
virtual void device_start() override ATTR_COLD;
virtual void scsi_ctrl_changed() override;
private:
static constexpr int FIFO_SIZE = 8;
enum scsi_mode : uint8_t
{
MODE_D, // Disconnected
MODE_T, // Target
MODE_I // Initiator
};
enum scsi_data_target : uint8_t
{
COMMAND_BUFFER,
FIFO
};
enum dma_direction : uint8_t
{
DMA_NONE,
DMA_IN,
DMA_OUT
};
struct spifi_cmd_entry
{
// NetBSD has these mapped as uint32_t to align the accesses and such
// in reality, these are all 8-bit values that are mapped, in typical NWS-5000 series
// fashion, to be 32-bit word aligned.
// the same probably applies to the register file.
uint8_t cdb[12] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
uint8_t quecode = 0;
uint8_t quetag = 0;
uint8_t idmsg = 0;
uint8_t status = 0;
};
struct register_file
{
uint32_t spstat = 0;
uint32_t cmlen = 0;
uint32_t cmdpage = 0;
// count_hi, count_mid, count_low
uint32_t svptr_hi = 0;
uint32_t svptr_mid = 0;
uint32_t svptr_low = 0;
uint32_t intr = 0;
uint32_t imask = 0;
uint32_t prctrl = 0;
uint32_t prstat = 0;
uint32_t init_status = 0;
uint32_t fifoctrl = 0;
uint32_t fifodata = 0;
uint32_t config = 0;
uint32_t data_xfer = 0;
uint32_t autocmd = 0;
uint32_t autostat = 0;
uint32_t resel = 0;
uint32_t select = 0;
// prcmd, which is used to trigger commands
uint32_t auxctrl = 0;
uint32_t autodata = 0;
uint32_t loopctrl = 0;
uint32_t loopdata = 0;
uint32_t identify = 0;
uint32_t complete = 0;
uint32_t scsi_status = 0x1; // Must be 0x1 for SPIFI to be recognized at boot
uint32_t data = 0;
uint32_t icond = 0;
uint32_t fastwide = 0;
uint32_t exctrl = 0;
uint32_t exstat = 0;
uint32_t test = 0;
uint32_t quematch = 0;
uint32_t quecode = 0;
uint32_t quetag = 0;
uint32_t quepage = 0;
spifi_cmd_entry cmbuf[8];
} spifi_reg;
template<typename T>
class spifi_queue
{
public:
uint32_t head;
uint32_t tail;
uint32_t size;
T fifo[FIFO_SIZE];
spifi_queue() { clear_queue(); }
uint32_t get_size() { return size; }
bool empty() { return size == 0; }
bool full() { return size == FIFO_SIZE; }
void clear_queue()
{
head = 0;
tail = 0;
size = 0;
for (int i = 0; i < FIFO_SIZE; ++i)
{
fifo[i] = 0;
}
}
void push(T value)
{
if(size == FIFO_SIZE)
{
fatalerror("spifi3: FIFO overflow!");
}
fifo[tail] = value;
tail = (tail + 1) % FIFO_SIZE;
++size;
}
T pop()
{
if (size == 0)
{
fatalerror("spifi3: FIFO underflow!");
}
const T removed_value = fifo[head];
head = (head + 1) % FIFO_SIZE;
--size;
return removed_value;
}
};
// State tracking variables
dma_direction dma_dir;
scsi_mode mode;
scsi_data_target xfr_data_source;
uint32_t state;
uint32_t xfr_phase;
uint32_t command_pos;
bool irq = false;
bool drq = false;
uint32_t tcounter;
uint8_t sync_period = 5; // TODO: appropriate value for SPIFI
uint8_t clock_conv = 2; // TODO: appropriate value for SPIFI
uint32_t bus_id;
spifi_queue<uint8_t> m_even_fifo;
spifi_queue<uint8_t> m_odd_fifo;
emu_timer *tm;
// I/O ports
devcb_write_line m_irq_handler;
devcb_write_line m_drq_handler;
// State-related methods
TIMER_CALLBACK_MEMBER(tick);
void step(bool timeout);
void check_irq();
void check_drq();
void reset_disconnect();
void send_byte(scsi_data_target data_source);
void recv_byte();
void function_complete();
void function_bus_complete();
void bus_complete();
void dma_set(dma_direction dir);
void decrement_tcounter(uint32_t count = 1);
bool transfer_count_zero();
void delay(uint32_t cycles);
void delay_cycles(uint32_t cycles);
void arbitrate();
void clear_fifo();
void auto_phase_transfer(uint32_t new_phase);
void start_autodata(uint32_t data_phase);
void start_autostat();
void start_automsg(uint32_t msg_phase);
void start_autocmd();
dma_direction dma_setting(uint32_t target_id);
// Register processing methods
uint32_t get_target_id();
bool autodata_active(uint32_t target_id);
bool autodata_in(uint32_t target_id);
bool autodata_out(uint32_t target_id);
void autostat_done(uint32_t target_id);
bool autostat_active(uint32_t target_id);
bool automsg_active();
bool autocmd_active();
// Register accessors
uint32_t spstat_r();
uint32_t cmlen_r();
void cmlen_w(uint32_t data);
uint32_t cmdpage_r();
void cmdpage_w(uint32_t data);
uint32_t count_r(offs_t offset);
void count_w(offs_t offset, uint32_t data);
uint32_t intr_r();
void intr_w(uint32_t data);
uint32_t imask_r();
void imask_w(uint32_t data);
uint32_t prstat_r();
uint32_t init_status_r();
uint32_t fifoctrl_r();
void fifoctrl_w(uint32_t data);
uint32_t data_xfer_r();
void data_xfer_w(uint32_t data);
uint32_t autocmd_r();
void autocmd_w(uint32_t data);
uint32_t autostat_r();
void autostat_w(uint32_t data);
uint32_t select_r();
void select_w(uint32_t data);
void prcmd_w(uint32_t data);
uint32_t auxctrl_r();
void auxctrl_w(uint32_t data);
uint32_t autodata_r();
void autodata_w(uint32_t data);
uint32_t identify_r();
void identify_w(uint32_t data);
uint32_t scsi_status_r();
void scsi_status_w(uint32_t data);
uint32_t icond_r();
void icond_w(uint32_t data);
uint32_t fastwide_r();
void fastwide_w(uint32_t data);
uint32_t exctrl_r();
void exctrl_w(uint32_t data);
// Command buffer accessors
uint8_t cmd_buf_r(offs_t offset);
void cmd_buf_w(offs_t offset, uint8_t data);
// Data helpers
bool dma_command(dma_direction current_direction) const
{
return current_direction != DMA_NONE;
}
};
DECLARE_DEVICE_TYPE(SPIFI3, spifi3_device)
#endif // MAME_MACHINE_SPIFI3_H
|