-
Notifications
You must be signed in to change notification settings - Fork 4
/
csr.c
349 lines (310 loc) · 11.1 KB
/
csr.c
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
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
/*
Simulation of the Control/Status Register (CSR) memory space.
*/
/*
SPDX-License-Identifier: MIT
Copyright (c) 2024 Sprite_tm <[email protected]>
*/
#include <stdlib.h>
#include <stdint.h>
#include <stdio.h>
#include <assert.h>
#include "csr.h"
#include "emu.h"
#include "log.h"
#include "scsi.h"
#include "int.h"
// Debug logging
#define CSR_LOG(msg_level, format_and_args...) \
log_printf(LOG_SRC_CSR, msg_level, format_and_args)
#define CSR_LOG_DEBUG(format_and_args...) CSR_LOG(LOG_DEBUG, format_and_args)
#define CSR_LOG_INFO(format_and_args...) CSR_LOG(LOG_INFO, format_and_args)
#define CSR_LOG_WARN(format_and_args...) CSR_LOG(LOG_WARNING, format_and_args)
//csr: usr/include/sys/mtpr.h, note we're Robin
#define CSR_O_RSEL 0x00 /* reset selection , see below */
#define CSR_I_PERR1 0x00 /* parity error latch */
#define CSR_I_PERR2 0x02 /* parity error latch */
#define CSR_I_MBERR 0x04 /* latches address on multibus error */
#define CSR_O_SC_C 0x06 /* scsi byte count */
#define CSR_I_SC_C 0x06 /* scsi byte count */
#define CSR_O_SC_P 0x0A /* scsi pointer register */
#define CSR_I_SC_P 0x0A /* scsi pointer register */
#define CSR_O_SC_R 0x0E /* scsi register */
#define CSR_I_SC_R 0x0E /* scsi register */
#define CSR_O_LEDS 0x10 /* led register */
#define CSR_I_LEDS 0x10 /* led register */
#define CSR_I_USRT 0x12 /* usart register */
#define CSR_I_ERR 0x14 /* error reporting */
#define CSR_O_MISC 0x16 /* misc. functions */
#define CSR_I_MISC 0x16 /* misc. functions */
#define CSR_O_KILL 0x18 /* kill job / dma cpu */
#define CSR_I_KILL 0x18 /* kill job / dma cpu */
#define CSR_O_TRCE 0x1A /* rce/ tce for usarts */
#define CSR_I_TRCE 0x1A /* rce/ tce for usarts */
#define CSR_O_INTE 0x1C /* interupt register */
#define CSR_I_INTE 0x1C /* interupt register */
#define CSR_O_MAPID 0x1E /* user id register */
#define CSR_I_USER 0x1E /* user number */
#define MISC_UINTEN 0x1 /* enable ups interrupt */
#define MISC_TINTEN 0x2 /* enable temperature interrupt */
#define MISC_CINTJEN 0x4 /* enable job's clock interrupt */
#define MISC_CINTDEN 0x8 /* enable dma's clock interrupt */
#define MISC_RESMB 0x10 /* reset multibus ACTIVE LOW */
#define MISC_HOLDMBUS 0x20 /* hold multibus */
#define MISC_DIAGUART 0x40 /* disable output to ttys */
#define MISC_TBUSY 0x80 /* READ only */
#define MISC_ENMAP 0x100 /* enable mapping (active low) */
#define MISC_DISMAP 0x100 /* disables map (active hi ) */
#define MISC_DIAGMB 0x200 /* put multibus into diagnostic mode */
#define MISC_DIAGPESC 0x400 /* force parity scsi parity error */
#define MISC_DIAGPL 0x800 /* force parity error low byte */
#define MISC_DIAGPH 0x1000 /* force parity error hi byte */
#define MISC_SCSIDL 0x2000 /* enable diag latch (ACTIVE LOW) */
#define MISC_BOOTJOB 0x4000 /* force job's A23 high (ACTIVE LOW ) */
#define MISC_BOOTDMA 0x8000 /* force dma's A23 high (ACTIVE LOW ) */
#define KILL_KILL_DMA 0x1
#define KILL_NKILL_JOB 0x2
#define KILL_INT_DMA 0x4
#define KILL_INT_JOB 0x8
#define KILL_JKPD 0x40 //job control protection disable
#define KILL_CUR_IS_JOB 0x80
#define RESET_MULTERR 0x020 /* reset multibus interface error flag */
#define RESET_SCSI_PFLG 0x040 /* reset scsi parity error flag */
#define RESET_CLR_JOBINT 0x060 /* reset job processor software int */
#define RESET_SET_JOBINT 0x080 /* set job processor software int */
#define RESET_CLR_DMAINT 0x0a0 /* reset dma processor software int */
#define RESET_SET_DMAINT 0x0c0 /* set dma processor int */
#define RESET_CINTJ 0x0e0 /* reset job clock interrupt */
#define RESET_CINTD 0x100 /* reset dma clock int */
#define RESET_JBERR 0x120 /* reset job bus error flag */
#define RESET_DBERR 0x140 /* reset dma bus error flag */
#define RESET_MPERR 0x160 /* reset memory parity err flag SET ON RESET*/
#define RESET_SWINT 0x180 /* reset switch interrupt */
#define RESET_SCSIBERR 0x1a0 /* reset scsi bus error flag */
#define ERR_AS26 0x8000 //deadman timer for all DMA transfers
#define ERR_SOOPS 0x4000 //Any DMA access of multibus or map
#define ERR_UBE_DMA 0x1000 //User ID mismatch
#define ERR_ABE_DMA 0x0800 //Privilege violation
#define ERR_EN_BLK 0x0400
#define ERR_EN_DMA 0x0200
#define ERR_EN_JOB 0x0100
#define ERR_AERR_JOB 0x0080 //User in system space
#define ERR_DERR_JOB 0x0040 //Generated when job CPU accesses DMA bus
#define ERR_MBTO 0x0020 //Multibus timeout
#define ERR_UBE_JOB 0x0010 //User ID mismatch
#define ERR_ABE_JOB 0x0008 //Privilege violation
#define ERR_EN_JOB2 0x0004 //duplicate with 0x100?
#define ERR_EN_BLK2 0x0002 //duplicate with 0x200?
#define ERR_EN_MBUS 0x0001
//note other defines are in scsi.c
#define I_NSCPERR 0x2000
#define I_NSCBERR 0x1000
struct csr_t {
uint16_t reg[0x10];
scsi_t *scsi;
};
int csr_cpu_is_reset(csr_t *csr, int cpu) {
int r=csr->reg[CSR_O_KILL/2] & (1<<cpu);
if (cpu==1) r=!r; //job kill is low active (dma kill is high active)
return r;
}
int csr_get_rtc_int_ena(csr_t *csr, int cpu) {
if (cpu==0) {
return (csr->reg[CSR_O_MISC/2]&MISC_CINTDEN);
} else {
return (csr->reg[CSR_O_MISC/2]&MISC_CINTJEN);
}
}
int csr_try_mbus_held(csr_t *csr) {
if (csr->reg[CSR_O_MISC/2]&MISC_HOLDMBUS) {
csr->reg[CSR_O_MISC/2]|=MISC_TBUSY;
return 0;
}
return 1;
}
void csr_set_access_error(csr_t *csr, int cpu, int type, int addr, int is_write) {
int v=0;
if (cpu==0) {
if (type&ACCESS_ERROR_U) v|=ERR_UBE_DMA;
if (type&ACCESS_ERROR_A) v|=ERR_ABE_DMA;
} else {
if (type&ACCESS_ERROR_U) v|=ERR_UBE_JOB;
if (type&ACCESS_ERROR_A) v|=ERR_ABE_JOB;
if (type&ACCESS_ERROR_AJOB) v|=ERR_AERR_JOB;
}
if (type&ACCESS_ERROR_MBTO) {
v|=ERR_MBTO;
if (emu_get_mb_diag()) {
csr->reg[CSR_I_MBERR/2]=(addr>>11)&0xfe;
if (!is_write) csr->reg[CSR_I_MBERR/2]|=0x1;
}
}
csr->reg[CSR_I_ERR/2]|=v;
}
void csr_set_parity_error(csr_t *c, int hl) {
c->reg[CSR_I_PERR1/2]&=~((1<<12)|(1<<13));
if (hl&2) c->reg[CSR_I_PERR1/2]|=(1<<12);
if (hl&1) c->reg[CSR_I_PERR1/2]|=(1<<13);
}
static void update_scsi_regs(csr_t *c) {
int b=scsi_get_bytecount(c->scsi);
c->reg[CSR_O_SC_C/2]=b>>16;
c->reg[CSR_O_SC_C/2+1]=b;
b=scsi_get_pointer(c->scsi);
c->reg[CSR_O_SC_P/2]=b>>16;
c->reg[CSR_O_SC_P/2+1]=b;
}
void csr_write16(void *obj, unsigned int a, unsigned int val) {
csr_t *c=(csr_t*)obj;
update_scsi_regs(c);
if (a==CSR_I_PERR1) return; //ro
if (a==CSR_O_RSEL) {
CSR_LOG_DEBUG("csr write16 0x%X (reset sel) val 0x%X\n", a, val);
} else if (a==CSR_O_SC_C || a==CSR_O_SC_C+2) {
c->reg[a/2]=val;
scsi_set_bytecount(c->scsi, ((c->reg[CSR_O_SC_C/2]<<16)+c->reg[CSR_O_SC_C/2+1])&0xffffff);
} else if (a==CSR_O_SC_P || a==CSR_O_SC_P+2) {
c->reg[a/2]=val;
scsi_set_pointer(c->scsi, ((c->reg[CSR_O_SC_P/2]<<16)+c->reg[CSR_O_SC_P/2+1])&0xffffff);
} else if (a==CSR_O_SC_R) {
scsi_set_scsireg(c->scsi, val);
} else if (a==CSR_O_MISC) {
emu_enable_mapper(!(val&MISC_ENMAP));
if ((val&MISC_HOLDMBUS)==0) {
val&=~MISC_TBUSY;
} else {
val|=MISC_TBUSY;
}
int v=0;
if ((val&MISC_SCSIDL)==0) v|=SCSI_DIAG_LATCH;
if ((val&MISC_DIAGPESC)) v|=SCSI_DIAG_PARITY;
scsi_set_diag(c->scsi, v);
v=0;
if (!(val&MISC_BOOTDMA)) v|=1;
if (!(val&MISC_BOOTJOB)) v|=2;
emu_set_force_a23(v);
v=0;
if (val&MISC_DIAGPL) v|=1;
if (val&MISC_DIAGPH) v|=2;
emu_set_force_parity_error(v);
emu_set_mb_diag(val&MISC_DIAGMB);
} else if (a==CSR_O_KILL) { //kill
CSR_LOG_DEBUG("csr write16 0x%X (kill) val 0x%X\n", a, val);
assert((val&0x40)==0); //we don't support this bit yet but sw doesn't seem to use it
val&=0x43; //rest is set elsewhere
} else if (a==CSR_I_ERR) {
CSR_LOG_DEBUG("csr write16 0x%X (err) val 0x%X - reg is RO?\n", a, val);
val=c->reg[a/2];
} else if (a==CSR_O_MAPID) {
emu_set_cur_mapid(val);
} else {
CSR_LOG_DEBUG("csr write16 0x%X val 0x%X\n", a, val);
}
c->reg[a/2]=val;
}
void csr_write32(void *obj, unsigned int a, unsigned int val) {
csr_write16(obj, a, val>>16);
csr_write16(obj, a+2, val&0xffff);
}
void csr_write8(void *obj, unsigned int a, unsigned int val) {
CSR_LOG_DEBUG("csr write8 %x val %x\n", a, val);
//fake with a csr write16
if (a&1) {
csr_write16(obj, a-1, val);
} else {
csr_write16(obj, a, val<<8);
}
}
unsigned int csr_read16(void *obj, unsigned int a) {
csr_t *c=(csr_t*)obj;
update_scsi_regs(c);
unsigned int ret=c->reg[a/2];
if (a==CSR_O_KILL) {
//note: return 0x80 if we are the job cpu
if (emu_get_cur_cpu()) ret|=0x80;
} else if (a==CSR_O_SC_R) {
return scsi_get_scsireg(c->scsi);
} else {
CSR_LOG_DEBUG("csr read16 0x%X -> 0x%X\n", a, ret);
}
return ret;
}
unsigned int csr_read32(void *obj, unsigned int a) {
return (csr_read16(obj, a)<<16)+csr_read16(obj, a+2);
}
unsigned int csr_read8(void *obj, unsigned int a) {
//fake using read16
if (a&1) {
return csr_read16(obj, a-1)&0xff;
} else {
return csr_read16(obj, a)>>8;
}
}
//Note: Most of these have been checked against the schematic.
void csr_write16_mmio(void *obj, unsigned int a, unsigned int val) {
csr_t *c=(csr_t*)obj;
//note: a has the start of MMIO as base, but RESET_* has the base of CSR,
//so we adjust the address here.
a=a+0x20;
if (a==RESET_MULTERR) {
//Note: this doesn't really seem to do anything except allow
//the multibus error address register to accept a new address.
CSR_LOG_DEBUG("CSR: Reset mbus error\n");
// c->reg[CSR_O_MISC/2]&=~MISC_TBUSY;
emu_raise_int(INT_VECT_MB_IF_ERR, 0, 0);
emu_raise_int(INT_VECT_MB_IF_ERR, 0, 1);
} else if (a==RESET_SCSI_PFLG) {
c->reg[CSR_O_SC_R/2] |= I_NSCPERR;
emu_raise_int(INT_VECT_SCSI_PARITY, 0, 0);
} else if (a==RESET_CLR_JOBINT) {
CSR_LOG_DEBUG("CSR: Clear job int\n");
c->reg[CSR_O_KILL/2] &= ~KILL_INT_JOB;
emu_raise_int(INT_VECT_JOB, 0, 1);
} else if (a==RESET_SET_JOBINT) {
CSR_LOG_DEBUG("CSR: Set job int\n");
c->reg[CSR_O_KILL/2] |= KILL_INT_JOB;
emu_raise_int(INT_VECT_JOB, INT_LEVEL_JOB, 1);
} else if (a==RESET_CLR_DMAINT) {
CSR_LOG_DEBUG("CSR: Clear dma int\n");
c->reg[CSR_O_KILL/2] &= ~KILL_INT_DMA;
emu_raise_int(INT_VECT_DMA, 0, 0);
} else if (a==RESET_SET_DMAINT) {
CSR_LOG_DEBUG("CSR: Set dma int\n");
c->reg[CSR_O_KILL/2] |= KILL_INT_DMA;
emu_raise_int(INT_VECT_DMA, INT_LEVEL_DMA, 0);
} else if (a==RESET_CINTJ) {
emu_raise_int(INT_VECT_CLOCK, 0, 1);
} else if (a==RESET_CINTD) {
emu_raise_int(INT_VECT_CLOCK, 0, 0);
} else if (a==RESET_JBERR) {
CSR_LOG_DEBUG("CSR: Reset job bus error\n");
c->reg[CSR_I_ERR/2]&=~(ERR_UBE_JOB|ERR_ABE_JOB|ERR_MBTO|ERR_DERR_JOB|ERR_AERR_JOB);
} else if (a==RESET_DBERR) {
CSR_LOG_DEBUG("CSR: Reset dma bus error\n");
c->reg[CSR_I_ERR/2]&=~(ERR_UBE_DMA|ERR_ABE_DMA|ERR_AS26|ERR_SOOPS);
} else if (a==RESET_MPERR) {
CSR_LOG_DEBUG("CSR: Reset parity error\n");
emu_raise_int(INT_VECT_PARITY_ERR, 0, 0);
emu_raise_int(INT_VECT_PARITY_ERR, 0, 1);
// c->reg[CSR_I_PERR1/2]&=~((1<<13)|(1<<12));
} else if (a==RESET_SWINT) {
//SWitch INTerrupt
//not implemented yet
} else if (a==RESET_SCSIBERR) {
c->reg[CSR_O_SC_R/2] |= I_NSCBERR;
for (int i=0; i<16; i++) {
if (i!=4) emu_raise_int(INT_VECT_SCSI_SPURIOUS+i, 0, 0);
}
} else {
CSR_LOG_DEBUG("Unhandled MMIO write 0x%x\n", a);
}
}
unsigned int csr_read16_mmio(void *obj, unsigned int a) {
csr_write16_mmio(obj, a, 0);
return 0;
}
csr_t *csr_new(scsi_t *scsi) {
csr_t *ret=calloc(sizeof(csr_t), 1);
ret->scsi=scsi;
return ret;
}