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
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
|
// license:BSD-3-Clause
// copyright-holders:Juergen Buchmueller
/**********************************************************
* Xerox AltoII disassembler
*
**********************************************************/
#include "alto2cpu.h"
#define loc_DASTART 0000420 // display list header
#define loc_DVIBITS 0000421 // display vertical field interrupt bitword
#define loc_ITQUAN 0000422 // interval timer stored quantity
#define loc_ITBITS 0000423 // interval timer bitword
#define loc_MOUSEX 0000424 // mouse X coordinate
#define loc_MOUSEY 0000425 // mouse Y coordinate
#define loc_CURSORX 0000426 // cursor X coordinate
#define loc_CURSORY 0000427 // cursor Y coordinate
#define loc_RTC 0000430 // real time clock
#define loc_CURMAP 0000431 // cursor bitmap (16 words up to 00450)
#define loc_WW 0000452 // interrupt wakeups waiting
#define loc_ACTIVE 0000453 // active interrupt bitword
#define loc_MASKTAB 0000460 // mask table for convert
#define loc_PCLOC 0000500 // saved interrupt PC
#define loc_INTVEC 0000501 // interrupt transfer vector (15 words up to 00517)
#define loc_KBLK 0000521 // disk command block address
#define loc_KSTAT 0000522 // disk status at start of current sector
#define loc_KADDR 0000523 // disk address of latest disk command
#define loc_KSIBITS 0000524 // sector interrupt bit mask
#define loc_ITTIME 0000525 // interval timer timer
#define loc_TRAPPC 0000527 // trap saved PC
#define loc_TRAPVEC 0000530 // trap vectors (up to 0567)
#define loc_TIMERDATA 0000570 // timer data (OS; up to 0577)
#define loc_EPLOC 0000600 // ethernet post location
#define loc_EBLOC 0000601 // ethernet interrupt bitmask
#define loc_EELOC 0000602 // ethernet ending count
#define loc_ELLOC 0000603 // ethernet load location
#define loc_EICLOC 0000604 // ethernet input buffer count
#define loc_EIPLOC 0000605 // ethernet input buffer pointer
#define loc_EOCLOC 0000606 // ethernet output buffer count
#define loc_EOPLOC 0000607 // ethernet output buffer pointer
#define loc_EHLOC 0000610 // ethernet host address
#define loc_ERSVD 0000611 // reserved for ethernet expansion (up to 00612)
#define loc_ALTOV 0000613 // Alto I/II indication that microcode caninterrogate (0 = Alto I, -1 = Alto II)
#define loc_DCBR 0000614 // posted by parity task (main memory parity error)
#define loc_KNMAR 0000615 // -"-
#define loc_DWA 0000616 // -"-
#define loc_CBA 0000617 // -"-
#define loc_PC 0000620 // -"-
#define loc_SAD 0000621 // -"-
#define loc_SWATR 0000700 // saved registers (Swat; up to 00707)
#define loc_UTILOUT 0177016 // printer output (up to 177017)
#define loc_XBUS 0177020 // untility input bus (up to 177023)
#define loc_MEAR 0177024 // memory error address register
#define loc_MESR 0177025 // memory error status register
#define loc_MECR 0177026 // memory error control register
#define loc_UTILIN 0177030 // printer status, mouse keyset
#define loc_KBDAD 0177034 // undecoded keyboard (up to 177037)
#define loc_BANKREGS 0177740 // extended memory option bank registers
/**
* @brief Microcode and constants PROM size
*/
#define MCODE_PAGE 1024
#define MCODE_SIZE (2*MCODE_PAGE) /* Alto II may have 2 pages (or even 4?) */
#define MCODE_MASK (MCODE_SIZE - 1)
#define PROM_SIZE 256
/**
* @brief short names for the 16 tasks
*/
static const char *taskname[16] = {
"EMU", // emulator task
"T01",
"T02",
"T03",
"DSC", // disk sector task
"T05",
"T06",
"ETH", // ethernet task
"MRT", // memory refresh task
"DWT", // display word task
"CUR", // cursor task
"DHT", // display horizontal task
"DVT", // display vertical task
"PAR", // parity task
"DWD", // disk word task
"T17"
};
/**
* @brief names for the 32 R registers
*/
static const char *regname[32] = {
"AC(3)", // emulator accu 3
"AC(2)", // emulator accu 2
"AC(1)", // emulator accu 1
"AC(0)", // emulator accu 0
"R04",
"R05",
"PC", // emulator program counter
"R07",
"R10",
"R11",
"R12",
"R13",
"R14",
"R15",
"R16",
"R17",
"R20",
"R21",
"CBA", // address of the currently active DCB+1
"AECL", // address of end of current scanline's bitmap
"SLC", // scan line count
"HTAB", // number of tab words remaining on current scanline
"DWA", // address of the bit map double word being fetched
"MTEMP", // temporary cell
"R30",
"R31",
"R32",
"R33",
"R34",
"R35",
"R36",
"R37"
};
//! for ALUF which is the value loaded into T, if t flags is set
static const char* t_bus_alu[16] = {
"ALU",
"BUS",
"ALU",
"BUS",
"BUS",
"ALU",
"ALU",
"BUS",
"BUS",
"BUS",
"ALU",
"ALU",
"ALU",
"BUS",
"BUS",
"BUS",
};
/**
* @brief copy of the constant PROM, which this disassembler may not have access to
*/
static uint16_t const_prom[PROM_SIZE] = {
/* 0000 */ 0x0000, 0x0001, 0x0002, 0xfffe, 0xffff, 0xffff, 0x000f, 0xffff,
/* 0008 */ 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, 0x0008, 0xfff8, 0xfff8,
/* 0010 */ 0x0010, 0x001f, 0x0020, 0x003f, 0x0040, 0x007f, 0x0080, 0x0007,
/* 0018 */ 0x00ff, 0xff00, 0x0400, 0x0100, 0x0110, 0x0151, 0x0114, 0x000f,
/* 0020 */ 0x0116, 0x0118, 0x0ffa, 0xf000, 0x4000, 0xfffc, 0xfff6, 0xffeb,
/* 0028 */ 0x4800, 0x6c00, 0x0800, 0x1000, 0xfe00, 0x7fff, 0x7fe0, 0x7f00,
/* 0030 */ 0xffbd, 0x0f00, 0x0f0f, 0xf0f0, 0x6048, 0x3000, 0x7159, 0x2109,
/* 0038 */ 0x6a3c, 0x4213, 0xa5a5, 0xfe1c, 0x3f00, 0xffc0, 0x012a, 0x0140,
/* 0040 */ 0x8000, 0xffe0, 0x00bf, 0xfff9, 0xfff0, 0xfffd, 0x0970, 0x5d20,
/* 0048 */ 0x3844, 0x6814, 0xfc00, 0xfe20, 0xfe22, 0x0083, 0x00f0, 0xff80,
/* 0050 */ 0xf800, 0xe000, 0xc000, 0x01ff, 0x03ff, 0x07ff, 0x0fff, 0x1fff,
/* 0058 */ 0x3fff, 0x0200, 0x2000, 0xfff1, 0x0156, 0x0157, 0x0138, 0x0c00,
/* 0060 */ 0x0130, 0x1813, 0x0180, 0x0181, 0x0182, 0x0183, 0x0184, 0x0185,
/* 0068 */ 0x0186, 0x0187, 0x0188, 0x018a, 0x0112, 0x0113, 0x0102, 0xfff0,
/* 0070 */ 0x0153, 0x0154, 0xffef, 0xffe4, 0xfffb, 0x000a, 0xffc1, 0x001f,
/* 0078 */ 0x0e00, 0x007e, 0xff7e, 0x0018, 0x000d, 0x03f8, 0x83f9, 0xffe0,
/* 0080 */ 0xfbff, 0x0009, 0x000b, 0x000c, 0x000e, 0x0030, 0x01fe, 0xff7f,
/* 0088 */ 0x81ff, 0xffbf, 0xffcc, 0x0557, 0x0041, 0x0198, 0x0199, 0x01a2,
/* 0090 */ 0xfe72, 0xfe58, 0x0012, 0x0014, 0x00dd, 0x02ff, 0x0101, 0x0001,
/* 0098 */ 0x0401, 0x0011, 0x0013, 0x0015, 0x0016, 0x0017, 0x0019, 0x0003,
/* 00a0 */ 0x03bd, 0x01de, 0xfe50, 0x00c0, 0x0c01, 0x6200, 0x6300, 0x0008,
/* 00a8 */ 0x6400, 0x6500, 0x6e00, 0x6700, 0x6900, 0x6d00, 0x6600, 0x000c,
/* 00b0 */ 0x6b00, 0x6b01, 0x6b02, 0x6b03, 0x6b04, 0x6b05, 0x6b06, 0x0010,
/* 00b8 */ 0x6b07, 0x6b08, 0x6b09, 0x6b0a, 0x6b0b, 0x6b0c, 0x6b0d, 0x0020,
/* 00c0 */ 0x6b0e, 0x6b0f, 0xfff3, 0xfe14, 0xfe15, 0xfe16, 0x0ffc, 0x0040,
/* 00c8 */ 0x04ff, 0x05ff, 0x06ff, 0x013f, 0x017e, 0xfe7d, 0xffff, 0x0080,
/* 00d0 */ 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0x00c0,
/* 00d8 */ 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0x00ff,
/* 00e0 */ 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
/* 00e8 */ 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
/* 00f0 */ 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
/* 00f8 */ 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff
};
/**
* @brief print a symbolic name for an mpc address
*
* @param a microcode address (mpc)
* @return pointer to const string with the address or symbolic name
*/
static const char *addrname(int a)
{
static char buffer[4][32];
static int which = 0;
char *dst;
which = (which + 1) % 4;
dst = buffer[which];
if (a < 020) {
// start value for mpc per task is the task number
snprintf(dst, sizeof(buffer[0]), "*%s", taskname[a]);
} else {
snprintf(dst, sizeof(buffer[0]), "%04o", a);
}
return dst;
}
offs_t alto2_cpu_device::disasm_disassemble(std::ostream &main_stream, offs_t pc, const uint8_t *oprom, const uint8_t *opram, uint32_t options)
{
std::ostringstream stream;
size_t len = 128;
uint32_t mir = (static_cast<uint32_t>(oprom[0]) << 24) |
(static_cast<uint32_t>(oprom[1]) << 16) |
(static_cast<uint32_t>(oprom[2]) << 8) |
(static_cast<uint32_t>(oprom[3]) << 0);
int rsel = (mir >> 27) & 31;
int aluf = (mir >> 23) & 15;
int bs = (mir >> 20) & 7;
int f1 = (mir >> 16) & 15;
int f2 = (mir >> 12) & 15;
int t = (mir >> 11) & 1;
int l = (mir >> 10) & 1;
offs_t next = mir & 1023;
const uint8_t* src = oprom - 4 * pc + 4 * next;
uint32_t next2 = (static_cast<uint32_t>(src[0]) << 24) |
(static_cast<uint32_t>(src[1]) << 16) |
(static_cast<uint32_t>(src[2]) << 8) |
(static_cast<uint32_t>(src[3]) << 0);
uint16_t prefetch = next2 & 1023;
offs_t result = 1 | DASMFLAG_SUPPORTED;
uint8_t pa;
if (next != pc + 1)
result |= DASMFLAG_STEP_OUT;
if (t)
util::stream_format(stream, "T<-%s ", t_bus_alu[aluf]);
if (l)
util::stream_format(stream, "L<- ");
if (bs == 1)
util::stream_format(stream, "%s<- ", regname[rsel]);
switch (aluf) {
case 0: // T?: BUS
// this is somehow redundant and just wasting space
// util::stream_format(stream, "ALUF(BUS) ");
break;
case 1: // : T
util::stream_format(stream, "T ");
break;
case 2: // T?: BUS OR T
util::stream_format(stream, "BUS|T ");
break;
case 3: // : BUS AND T
util::stream_format(stream, "BUS&T ");
break;
case 4: // : BUS XOR T
util::stream_format(stream, "BUS^T ");
break;
case 5: // T?: BUS + 1
util::stream_format(stream, "BUS+1 ");
break;
case 6: // T?: BUS - 1
util::stream_format(stream, "BUS-1 ");
break;
case 7: // : BUS + T
util::stream_format(stream, "BUS+T ");
break;
case 8: // : BUS - T
util::stream_format(stream, "BUS-T ");
break;
case 9: // : BUS - T - 1
util::stream_format(stream, "BUS-T-1 ");
break;
case 10: // T?: BUS + T + 1
util::stream_format(stream, "BUS+T+1 ");
break;
case 11: // T?: BUS + SKIP
util::stream_format(stream, "BUS+SKIP ");
break;
case 12: // T?: BUS, T (AND)
util::stream_format(stream, "BUS,T ");
break;
case 13: // : BUS AND NOT T
util::stream_format(stream, "BUS&~T ");
break;
case 14: // : undefined
util::stream_format(stream, "*BUS ");
break;
case 15: // : undefined
util::stream_format(stream, "*BUS ");
break;
}
switch (bs) {
case 0: // read R
util::stream_format(stream, "BUS<-%s ", regname[rsel]);
break;
case 1: // load R from shifter output
// util::stream_format(stream, "; %s<-", regname[rsel]);
break;
case 2: // enables no source to the BUS, leaving it all ones
util::stream_format(stream, "BUS<-177777 ");
break;
case 3: // performs different functions in different tasks
util::stream_format(stream, "BUS<-BS3 ");
break;
case 4: // performs different functions in different tasks
util::stream_format(stream, "BUS<-BS4 ");
break;
case 5: // memory data
util::stream_format(stream, "BUS<-MD ");
break;
case 6: // BUS[3-0] <- MOUSE; BUS[15-4] <- -1
util::stream_format(stream, "BUS<-MOUSE ");
break;
case 7: // IR[7-0], possibly sign extended
util::stream_format(stream, "BUS<-DISP ");
break;
}
switch (f1) {
case 0: // no operation
break;
case 1: // load MAR from ALU output; start main memory reference
util::stream_format(stream, "MAR<-ALU ");
break;
case 2: // switch tasks if higher priority wakeup is pending
util::stream_format(stream, "TASK ");
break;
case 3: // disable the current task until re-enabled by a hardware-generated condition
util::stream_format(stream, "BLOCK ");
break;
case 4: // SHIFTER output will be L shifted left one place
util::stream_format(stream, "SHIFTER<-L(LSH1) ");
break;
case 5: // SHIFTER output will be L shifted right one place
util::stream_format(stream, "SHIFTER<-L(RSH1) ");
break;
case 6: // SHIFTER output will be L rotated left 8 places
util::stream_format(stream, "SHIFTER<-L(LCY8) ");
break;
case 7: // put the constant from PROM (RSELECT,BS) on the bus
pa = (rsel << 3) | bs;
util::stream_format(stream, "BUS<-%05o ", const_prom[pa]);
break;
default:
util::stream_format(stream, "F1_%02o ", f1);
break;
}
switch (f2) {
case 0: // no operation
break;
case 1: // NEXT <- NEXT OR (BUS==0 ? 1 : 0)
util::stream_format(stream, "[BUS==0 ? %s:%s] ",
addrname((prefetch | 1) & MCODE_MASK), addrname(prefetch & MCODE_MASK));
break;
case 2: // NEXT <- NEXT OR (SHIFTER==0 ? 1 : 0)
util::stream_format(stream, "[SH==0 ? %s:%s] ",
addrname((prefetch | 1) & MCODE_MASK), addrname(prefetch & MCODE_MASK));
break;
case 3: // NEXT <- NEXT OR (SHIFTER<0 ? 1 : 0)
util::stream_format(stream, "[SH<0 ? %s:%s] ",
addrname((prefetch | 1) & MCODE_MASK), addrname(prefetch & MCODE_MASK));
break;
case 4: // NEXT <- NEXT OR BUS
util::stream_format(stream, "NEXT<-BUS ");
break;
case 5: // NEXT <- NEXT OR ALUC0. ALUC0 is the carry produced by last L loading microinstruction.
util::stream_format(stream, "[ALUC0 ? %s:%s] ",
addrname((prefetch | 1) & MCODE_MASK), addrname(prefetch & MCODE_MASK));
break;
case 6: // write BUS data to memory
util::stream_format(stream, "MD<-BUS ");
break;
case 7: // put the constant from PROM (RSELECT,BS) on the bus
if (f1 != 7) {
pa = 8 * rsel + bs;
util::stream_format(stream, "BUS<-%05o", const_prom[pa]);
}
break;
default:
util::stream_format(stream, "BUS<-F2_%02o ", f2);
break;
}
// need to trim last space
std::string output = stream.str();
if (output.length() > 0 && output[output.length() - 1] == ' ')
output.resize(output.length() - 1);
main_stream << output;
return result;
}
offs_t alto2_cpu_device::disasm_disassemble(char *buffer, offs_t pc, const uint8_t *oprom, const uint8_t *opram, uint32_t options)
{
std::ostringstream stream;
offs_t result = disasm_disassemble(stream, pc, oprom, opram, options);
std::string stream_str = stream.str();
strcpy(buffer, stream_str.c_str());
return result;
}
|