First Commit of my working state
[simh.git] / ALTAIR / altair_cpu.c
CommitLineData
196ba1fc
PH
1/* altair_cpu.c: MITS Altair Intel 8080 CPU simulator\r
2\r
3 Copyright (c) 1997-2005, Charles E. Owen\r
4\r
5 Permission is hereby granted, free of charge, to any person obtaining a\r
6 copy of this software and associated documentation files (the "Software"),\r
7 to deal in the Software without restriction, including without limitation\r
8 the rights to use, copy, modify, merge, publish, distribute, sublicense,\r
9 and/or sell copies of the Software, and to permit persons to whom the\r
10 Software is furnished to do so, subject to the following conditions:\r
11\r
12 The above copyright notice and this permission notice shall be included in\r
13 all copies or substantial portions of the Software.\r
14\r
15 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r
16 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\r
17 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL\r
18 ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\r
19 IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
20 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\r
21\r
22 Except as contained in this notice, the name of Charles E. Owen shall not be\r
23 used in advertising or otherwise to promote the sale, use or other dealings\r
24 in this Software without prior written authorization from Charles E. Owen.\r
25\r
26 cpu 8080 CPU\r
27\r
28 08-Oct-02 RMS Tied off spurious compiler warnings\r
29\r
30 The register state for the 8080 CPU is:\r
31\r
32 A<0:7> Accumulator\r
33 BC<0:15> BC Register Pair\r
34 DE<0:15> DE Register Pair\r
35 HL<0:15> HL Register Pair \r
36 C carry flag\r
37 Z zero flag\r
38 S Sign bit\r
39 AC Aux carry\r
40 P Parity bit\r
41 PC<0:15> program counter\r
42 SP<0:15> Stack Pointer\r
43\r
44 The 8080 is an 8-bit CPU, which uses 16-bit registers to address\r
45 up to 64KB of memory.\r
46\r
47 The 78 basic instructions come in 1, 2, and 3-byte flavors.\r
48\r
49 This routine is the instruction decode routine for the 8080.\r
50 It is called from the simulator control program to execute\r
51 instructions in simulated memory, starting at the simulated PC.\r
52 It runs until 'reason' is set non-zero.\r
53\r
54 General notes:\r
55\r
56 1. Reasons to stop. The simulator can be stopped by:\r
57\r
58 HALT instruction\r
59 I/O error in I/O simulator\r
60 Invalid OP code (if ITRAP is set on CPU)\r
61\r
62 2. Interrupts.\r
63 There are 8 possible levels of interrupt, and in effect they\r
64 do a hardware CALL instruction to one of 8 possible low\r
65 memory addresses.\r
66\r
67 3. Non-existent memory. On the 8080, reads to non-existent memory\r
68 return 0377, and writes are ignored. In the simulator, the\r
69 largest possible memory is instantiated and initialized to zero.\r
70 Thus, only writes need be checked against actual memory size.\r
71\r
72 4. Adding I/O devices. These modules must be modified:\r
73\r
74 altair_cpu.c add I/O service routines to dev_table\r
75 altair_sys.c add pointer to data structures in sim_devices\r
76*/\r
77\r
78\r
79#include <stdio.h>\r
80\r
81#include "altair_defs.h"\r
82\r
83#define UNIT_V_OPSTOP (UNIT_V_UF) /* Stop on Invalid OP? */\r
84#define UNIT_OPSTOP (1 << UNIT_V_OPSTOP)\r
85#define UNIT_V_CHIP (UNIT_V_UF+1) /* 8080 or Z80 */\r
86#define UNIT_CHIP (1 << UNIT_V_CHIP)\r
87#define UNIT_V_MSIZE (UNIT_V_UF+2) /* Memory Size */\r
88#define UNIT_MSIZE (1 << UNIT_V_MSIZE)\r
89\r
90unsigned char M[MAXMEMSIZE]; /* memory */\r
91int32 A = 0; /* accumulator */\r
92int32 BC = 0; /* BC register pair */\r
93int32 DE = 0; /* DE register pair */\r
94int32 HL = 0; /* HL register pair */\r
95int32 SP = 0; /* Stack pointer */\r
96int32 C = 0; /* carry flag */\r
97int32 Z = 0; /* Zero flag */\r
98int32 AC = 0; /* Aux carry */\r
99int32 S = 0; /* sign flag */\r
100int32 P = 0; /* parity flag */\r
101int32 saved_PC = 0; /* program counter */\r
102int32 SR = 0; /* switch register */\r
103int32 INTE = 0; /* Interrupt Enable */\r
104int32 int_req = 0; /* Interrupt request */\r
105int32 chip = 0; /* 0 = 8080 chip, 1 = z80 chip */\r
106\r
107int32 PCX; /* External view of PC */\r
108\r
109extern int32 sim_int_char;\r
110extern int32 sim_brk_types, sim_brk_dflt, sim_brk_summ; /* breakpoint info */\r
111\r
112/* function prototypes */\r
113\r
114t_stat cpu_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw);\r
115t_stat cpu_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw);\r
116t_stat cpu_reset (DEVICE *dptr);\r
117t_stat cpu_set_size (UNIT *uptr, int32 val, char *cptr, void *desc);\r
118void setarith(int32 reg);\r
119void setlogical(int32 reg);\r
120void setinc(int32 reg);\r
121int32 getreg(int32 reg);\r
122void putreg(int32 reg, int32 val);\r
123int32 getpair(int32 reg);\r
124int32 getpush(int32 reg);\r
125void putpush(int32 reg, int32 data);\r
126void putpair(int32 reg, int32 val);\r
127void parity(int32 reg);\r
128int32 cond(int32 con);\r
129\r
130extern int32 sio0s(int32 io, int32 data);\r
131extern int32 sio0d(int32 io, int32 data);\r
132extern int32 sio1s(int32 io, int32 data);\r
133extern int32 sio1d(int32 io, int32 data);\r
134extern int32 dsk10(int32 io, int32 data);\r
135extern int32 dsk11(int32 io, int32 data);\r
136extern int32 dsk12(int32 io, int32 data);\r
137int32 nulldev(int32 io, int32 data);\r
138\r
139/* This is the I/O configuration table. There are 255 possible\r
140device addresses, if a device is plugged to a port it's routine\r
141address is here, 'nulldev' means no device is available\r
142*/\r
143struct idev {\r
144 int32 (*routine)();\r
145};\r
146struct idev dev_table[256] = {\r
147{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 000 */\r
148{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 004 */\r
149{&dsk10}, {&dsk11}, {&dsk12}, {&nulldev}, /* 010 */\r
150{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 014 */\r
151{&sio0s}, {&sio0d}, {&sio1s}, {&sio1d}, /* 020 */\r
152{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 024 */\r
153{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 030 */\r
154{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 034 */\r
155{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 040 */\r
156{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 044 */\r
157{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 050 */\r
158{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 054 */\r
159{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 060 */\r
160{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 064 */\r
161{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 070 */\r
162{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 074 */\r
163{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 100 */\r
164{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 104 */\r
165{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 110 */\r
166{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 114 */\r
167{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 120 */\r
168{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 124 */\r
169{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 130 */\r
170{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 134 */\r
171{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 140 */\r
172{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 144 */\r
173{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 150 */\r
174{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 154 */\r
175{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 160 */\r
176{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 164 */\r
177{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 170 */\r
178{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 174 */\r
179{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 200 */\r
180{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 204 */\r
181{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 210 */\r
182{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 214 */\r
183{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 220 */\r
184{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 224 */\r
185{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 230 */\r
186{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 234 */\r
187{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 240 */\r
188{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 244 */\r
189{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 250 */\r
190{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 254 */\r
191{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 260 */\r
192{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 264 */\r
193{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 270 */\r
194{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 274 */\r
195{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 300 */\r
196{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 304 */\r
197{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 310 */\r
198{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 314 */\r
199{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 320 */\r
200{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 324 */\r
201{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 330 */\r
202{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 334 */\r
203{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 340 */\r
204{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 344 */\r
205{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 350 */\r
206{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 354 */\r
207{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 360 */\r
208{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 364 */\r
209{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 370 */\r
210{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev} /* 374 */\r
211};\r
212\r
213/* Altair MITS standard BOOT EPROM, fits in upper 256K of memory */\r
214\r
215int32 bootrom[256] = {\r
216 0041, 0000, 0114, 0021, 0030, 0377, 0016, 0346,\r
217 0032, 0167, 0023, 0043, 0015, 0302, 0010, 0377,\r
218 0303, 0000, 0114, 0000, 0000, 0000, 0000, 0000,\r
219 0363, 0061, 0142, 0115, 0257, 0323, 0010, 0076, /* 46000 */\r
220 0004, 0323, 0011, 0303, 0031, 0114, 0333, 0010, /* 46010 */\r
221 0346, 0002, 0302, 0016, 0114, 0076, 0002, 0323, /* 46020 */\r
222 0011, 0333, 0010, 0346, 0100, 0302, 0016, 0114,\r
223 0021, 0000, 0000, 0006, 0000, 0333, 0010, 0346,\r
224 0004, 0302, 0045, 0114, 0076, 0020, 0365, 0325,\r
225 0305, 0325, 0021, 0206, 0200, 0041, 0324, 0114,\r
226 0333, 0011, 0037, 0332, 0070, 0114, 0346, 0037,\r
227 0270, 0302, 0070, 0114, 0333, 0010, 0267, 0372,\r
228 0104, 0114, 0333, 0012, 0167, 0043, 0035, 0312,\r
229 0132, 0114, 0035, 0333, 0012, 0167, 0043, 0302,\r
230 0104, 0114, 0341, 0021, 0327, 0114, 0001, 0200,\r
231 0000, 0032, 0167, 0276, 0302, 0301, 0114, 0200,\r
232 0107, 0023, 0043, 0015, 0302, 0141, 0114, 0032,\r
233 0376, 0377, 0302, 0170, 0114, 0023, 0032, 0270,\r
234 0301, 0353, 0302, 0265, 0114, 0361, 0361, 0052,\r
235 0325, 0114, 0325, 0021, 0000, 0377, 0315, 0316,\r
236 0114, 0321, 0332, 0276, 0114, 0315, 0316, 0114,\r
237 0322, 0256, 0114, 0004, 0004, 0170, 0376, 0040,\r
238 0332, 0054, 0114, 0006, 0001, 0312, 0054, 0114,\r
239 0333, 0010, 0346, 0002, 0302, 0240, 0114, 0076,\r
240 0001, 0323, 0011, 0303, 0043, 0114, 0076, 0200,\r
241 0323, 0010, 0303, 0000, 0000, 0321, 0361, 0075,\r
242 0302, 0056, 0114, 0076, 0103, 0001, 0076, 0117,\r
243 0001, 0076, 0115, 0107, 0076, 0200, 0323, 0010,\r
244 0170, 0323, 0001, 0303, 0311, 0114, 0172, 0274,\r
245 0300, 0173, 0275, 0311, 0204, 0000, 0114, 0044,\r
246 0026, 0126, 0026, 0000, 0000, 0000, 0000, 0000\r
247};\r
248\r
249/* CPU data structures\r
250\r
251 cpu_dev CPU device descriptor\r
252 cpu_unit CPU unit descriptor\r
253 cpu_reg CPU register list\r
254 cpu_mod CPU modifiers list\r
255*/\r
256\r
257UNIT cpu_unit = { UDATA (NULL, UNIT_FIX + UNIT_BINK, MAXMEMSIZE) };\r
258\r
259REG cpu_reg[] = {\r
260 { ORDATA (PC, saved_PC, 16) },\r
261 { ORDATA (A, A, 8) },\r
262 { ORDATA (BC, BC, 16) },\r
263 { ORDATA (DE, DE, 16) },\r
264 { ORDATA (HL, HL, 16) },\r
265 { ORDATA (SP, SP, 16) },\r
266 { FLDATA (C, C, 16) },\r
267 { FLDATA (Z, Z, 16) },\r
268 { FLDATA (AC, AC, 16) },\r
269 { FLDATA (S, S, 16) },\r
270 { FLDATA (P, P, 16) },\r
271 { FLDATA (INTE, INTE, 16) },\r
272 { ORDATA (SR, SR, 16) },\r
273 { ORDATA (WRU, sim_int_char, 8) },\r
274 { NULL }\r
275};\r
276\r
277MTAB cpu_mod[] = {\r
278 { UNIT_CHIP, UNIT_CHIP, "Z80", "Z80", NULL },\r
279 { UNIT_CHIP, 0, "8080", "8080", NULL },\r
280 { UNIT_OPSTOP, UNIT_OPSTOP, "ITRAP", "ITRAP", NULL },\r
281 { UNIT_OPSTOP, 0, "NOITRAP", "NOITRAP", NULL },\r
282 { UNIT_MSIZE, 4096, NULL, "4K", &cpu_set_size },\r
283 { UNIT_MSIZE, 8192, NULL, "8K", &cpu_set_size },\r
284 { UNIT_MSIZE, 12288, NULL, "12K", &cpu_set_size },\r
285 { UNIT_MSIZE, 16384, NULL, "16K", &cpu_set_size },\r
286 { UNIT_MSIZE, 20480, NULL, "20K", &cpu_set_size },\r
287 { UNIT_MSIZE, 24576, NULL, "24K", &cpu_set_size },\r
288 { UNIT_MSIZE, 28672, NULL, "28K", &cpu_set_size },\r
289 { UNIT_MSIZE, 32768, NULL, "32K", &cpu_set_size },\r
290 { UNIT_MSIZE, 49152, NULL, "48K", &cpu_set_size },\r
291 { UNIT_MSIZE, 65535, NULL, "64K", &cpu_set_size },\r
292 { 0 }\r
293};\r
294\r
295DEVICE cpu_dev = {\r
296 "CPU", &cpu_unit, cpu_reg, cpu_mod,\r
297 1, 8, 16, 1, 8, 8,\r
298 &cpu_ex, &cpu_dep, &cpu_reset,\r
299 NULL, NULL, NULL\r
300};\r
301\r
302int32 sim_instr (void)\r
303{\r
304 extern int32 sim_interval;\r
305 int32 PC, IR, OP, DAR, reason, hi, lo, carry, i;\r
306\r
307 PC = saved_PC & ADDRMASK; /* load local PC */\r
308 C = C & 0200000;\r
309 reason = 0;\r
310\r
311 /* Main instruction fetch/decode loop */\r
312\r
313 while (reason == 0) { /* loop until halted */\r
314 if (sim_interval <= 0) { /* check clock queue */\r
315 if (reason = sim_process_event ()) break;\r
316 }\r
317\r
318 if (int_req > 0) { /* interrupt? */\r
319\r
320 /* 8080 interrupts not implemented yet. None were used,\r
321 on a standard Altair 8800. All I/O is programmed. */\r
322\r
323 } /* end interrupt */\r
324\r
325 if (sim_brk_summ &&\r
326 sim_brk_test (PC, SWMASK ('E'))) { /* breakpoint? */\r
327 reason = STOP_IBKPT; /* stop simulation */\r
328 break;\r
329 }\r
330\r
331 if (PC == 0177400) { /* BOOT PROM address */\r
332 for (i = 0; i < 250; i++) {\r
333 M[i + 0177400] = bootrom[i] & 0xFF;\r
334 }\r
335 }\r
336\r
337 PCX = PC;\r
338\r
339 IR = OP = M[PC]; /* fetch instruction */\r
340\r
341 PC = (PC + 1) & ADDRMASK; /* increment PC */\r
342\r
343 sim_interval--;\r
344\r
345 if (OP == 0166) { /* HLT Instruction*/\r
346 reason = STOP_HALT;\r
347 PC--;\r
348 continue;\r
349 }\r
350\r
351 /* Handle below all operations which refer to registers or\r
352 register pairs. After that, a large switch statement\r
353 takes care of all other opcodes */\r
354\r
355 if ((OP & 0xC0) == 0x40) { /* MOV */\r
356 DAR = getreg(OP & 0x07);\r
357 putreg((OP >> 3) & 0x07, DAR);\r
358 continue;\r
359 }\r
360 if ((OP & 0xC7) == 0x06) { /* MVI */\r
361 putreg((OP >> 3) & 0x07, M[PC]);\r
362 PC++;\r
363 continue;\r
364 }\r
365 if ((OP & 0xCF) == 0x01) { /* LXI */\r
366 DAR = M[PC] & 0x00ff;\r
367 PC++;\r
368 DAR = DAR | (M[PC] <<8) & 0xFF00;;\r
369 putpair((OP >> 4) & 0x03, DAR);\r
370 PC++;\r
371 continue;\r
372 }\r
373 if ((OP & 0xEF) == 0x0A) { /* LDAX */\r
374 DAR = getpair((OP >> 4) & 0x03);\r
375 putreg(7, M[DAR]);\r
376 continue;\r
377 }\r
378 if ((OP & 0xEF) == 0x02) { /* STAX */\r
379 DAR = getpair((OP >> 4) & 0x03);\r
380 M[DAR] = getreg(7);\r
381 continue;\r
382 }\r
383\r
384 if ((OP & 0xF8) == 0xB8) { /* CMP */\r
385 DAR = A & 0xFF;\r
386 DAR -= getreg(OP & 0x07);\r
387 setarith(DAR);\r
388 continue;\r
389 }\r
390 if ((OP & 0xC7) == 0xC2) { /* JMP <condition> */\r
391 if (cond((OP >> 3) & 0x07) == 1) {\r
392 lo = M[PC];\r
393 PC++;\r
394 hi = M[PC];\r
395 PC++;\r
396 PC = (hi << 8) + lo;\r
397 } else {\r
398 PC += 2;\r
399 }\r
400 continue;\r
401 }\r
402 if ((OP & 0xC7) == 0xC4) { /* CALL <condition> */\r
403 if (cond((OP >> 3) & 0x07) == 1) {\r
404 lo = M[PC];\r
405 PC++;\r
406 hi = M[PC];\r
407 PC++;\r
408 SP--;\r
409 M[SP] = (PC >> 8) & 0xff;\r
410 SP--;\r
411 M[SP] = PC & 0xff;\r
412 PC = (hi << 8) + lo;\r
413 } else {\r
414 PC += 2;\r
415 }\r
416 continue;\r
417 }\r
418 if ((OP & 0xC7) == 0xC0) { /* RET <condition> */\r
419 if (cond((OP >> 3) & 0x07) == 1) {\r
420 PC = M[SP];\r
421 SP++;\r
422 PC |= (M[SP] << 8) & 0xff00;\r
423 SP++;\r
424 }\r
425 continue;\r
426 }\r
427 if ((OP & 0xC7) == 0xC7) { /* RST */\r
428 SP--;\r
429 M[SP] = (PC >> 8) & 0xff;\r
430 SP--;\r
431 M[SP] = PC & 0xff;\r
432 PC = OP & 0x38;\r
433 continue;\r
434 }\r
435\r
436 if ((OP & 0xCF) == 0xC5) { /* PUSH */\r
437 DAR = getpush((OP >> 4) & 0x03);\r
438 SP--;\r
439 M[SP] = (DAR >> 8) & 0xff;\r
440 SP--;\r
441 M[SP] = DAR & 0xff;\r
442 continue;\r
443 }\r
444 if ((OP & 0xCF) == 0xC1) { /*POP */\r
445 DAR = M[SP];\r
446 SP++;\r
447 DAR |= M[SP] << 8;\r
448 SP++;\r
449 putpush((OP >> 4) & 0x03, DAR);\r
450 continue;\r
451 }\r
452 if ((OP & 0xF8) == 0x80) { /* ADD */\r
453 A += getreg(OP & 0x07);\r
454 setarith(A);\r
455 A = A & 0xFF;\r
456 continue;\r
457 }\r
458 if ((OP & 0xF8) == 0x88) { /* ADC */\r
459 carry = 0;\r
460 if (C) carry = 1;\r
461 A += getreg(OP & 0x07);\r
462 A += carry;\r
463 setarith(A);\r
464 A = A & 0xFF;\r
465 continue;\r
466 }\r
467 if ((OP & 0xF8) == 0x90) { /* SUB */\r
468 A -= getreg(OP & 0x07);\r
469 setarith(A);\r
470 A = A & 0xFF;\r
471 continue;\r
472 }\r
473 if ((OP & 0xF8) == 0x98) { /* SBB */\r
474 carry = 0;\r
475 if (C) carry = 1;\r
476 A -= (getreg(OP & 0x07)) + carry ;\r
477 setarith(A);\r
478 A = A & 0xFF;\r
479 continue;\r
480 }\r
481 if ((OP & 0xC7) == 0x04) { /* INR */\r
482 DAR = getreg((OP >> 3) & 0x07);\r
483 DAR++;\r
484 setinc(DAR);\r
485 DAR = DAR & 0xFF;\r
486 putreg((OP >> 3) & 0x07, DAR);\r
487 continue;\r
488 }\r
489 if ((OP & 0xC7) == 0x05) { /* DCR */\r
490 DAR = getreg((OP >> 3) & 0x07);\r
491 DAR--;\r
492 setinc(DAR);\r
493 DAR = DAR & 0xFF;\r
494 putreg((OP >> 3) & 0x07, DAR);\r
495 continue;\r
496 }\r
497 if ((OP & 0xCF) == 0x03) { /* INX */\r
498 DAR = getpair((OP >> 4) & 0x03);\r
499 DAR++;\r
500 DAR = DAR & 0xFFFF;\r
501 putpair((OP >> 4) & 0x03, DAR);\r
502 continue;\r
503 }\r
504 if ((OP & 0xCF) == 0x0B) { /* DCX */\r
505 DAR = getpair((OP >> 4) & 0x03);\r
506 DAR--;\r
507 DAR = DAR & 0xFFFF;\r
508 putpair((OP >> 4) & 0x03, DAR);\r
509 continue;\r
510 }\r
511 if ((OP & 0xCF) == 0x09) { /* DAD */\r
512 HL += getpair((OP >> 4) & 0x03);\r
513 C = 0;\r
514 if (HL & 0x10000)\r
515 C = 0200000;\r
516 HL = HL & 0xFFFF;\r
517 continue;\r
518 }\r
519 if ((OP & 0xF8) == 0xA0) { /* ANA */\r
520 A &= getreg(OP & 0x07);\r
521 C = 0;\r
522 setlogical(A);\r
523 A &= 0xFF;\r
524 continue;\r
525 }\r
526 if ((OP & 0xF8) == 0xA8) { /* XRA */\r
527 A ^= getreg(OP & 0x07);\r
528 C = 0;\r
529 setlogical(A);\r
530 A &= 0xFF;\r
531 continue;\r
532 }\r
533 if ((OP & 0xF8) == 0xB0) { /* ORA */\r
534 A |= getreg(OP & 0x07);\r
535 C = 0;\r
536 setlogical(A);\r
537 A &= 0xFF;\r
538 continue;\r
539 }\r
540\r
541\r
542\r
543 /* The Big Instruction Decode Switch */\r
544\r
545 switch (IR) {\r
546\r
547 /* Logical instructions */\r
548\r
549 case 0376: { /* CPI */\r
550 DAR = A & 0xFF;\r
551 DAR -= M[PC];\r
552 PC++;\r
553 setarith(DAR);\r
554 break;\r
555 }\r
556 case 0346: { /* ANI */\r
557 A &= M[PC];\r
558 PC++;\r
559 C = AC = 0;\r
560 setlogical(A);\r
561 A &= 0xFF;\r
562 break;\r
563 }\r
564 case 0356: { /* XRI */\r
565 A ^= M[PC];\r
566 PC++;\r
567 C = AC = 0;\r
568 setlogical(A);\r
569 A &= 0xFF;\r
570 break;\r
571 }\r
572 case 0366: { /* ORI */\r
573 A |= M[PC];\r
574 PC++;\r
575 C = AC = 0;\r
576 setlogical(A);\r
577 A &= 0xFF;\r
578 break;\r
579 }\r
580\r
581 /* Jump instructions */\r
582\r
583 case 0303: { /* JMP */\r
584 lo = M[PC];\r
585 PC++;\r
586 hi = M[PC];\r
587 PC++;\r
588 PC = (hi << 8) + lo;\r
589 break;\r
590 }\r
591 case 0351: { /* PCHL */\r
592 PC = HL;\r
593 break;\r
594 }\r
595 case 0315: { /* CALL */\r
596 lo = M[PC];\r
597 PC++;\r
598 hi = M[PC];\r
599 PC++;\r
600 SP--;\r
601 M[SP] = (PC >> 8) & 0xff;\r
602 SP--;\r
603 M[SP] = PC & 0xff;\r
604 PC = (hi << 8) + lo;\r
605 break;\r
606 }\r
607 case 0311: { /* RET */\r
608 PC = M[SP];\r
609 SP++;\r
610 PC |= (M[SP] << 8) & 0xff00;\r
611 SP++;\r
612 break;\r
613 }\r
614\r
615 /* Data Transfer Group */\r
616\r
617 case 062: { /* STA */\r
618 lo = M[PC];\r
619 PC++;\r
620 hi = M[PC];\r
621 PC++;\r
622 DAR = (hi << 8) + lo;\r
623 M[DAR] = A;\r
624 break;\r
625 }\r
626 case 072: { /* LDA */\r
627 lo = M[PC];\r
628 PC++;\r
629 hi = M[PC];\r
630 PC++;\r
631 DAR = (hi << 8) + lo;\r
632 A = M[DAR];\r
633 break;\r
634 }\r
635 case 042: { /* SHLD */\r
636 lo = M[PC];\r
637 PC++;\r
638 hi = M[PC];\r
639 PC++;\r
640 DAR = (hi << 8) + lo;\r
641 M[DAR] = HL;\r
642 DAR++;\r
643 M[DAR] = (HL >>8) & 0x00ff;\r
644 break;\r
645 }\r
646 case 052: { /* LHLD */\r
647 lo = M[PC];\r
648 PC++;\r
649 hi = M[PC];\r
650 PC++;\r
651 DAR = (hi << 8) + lo;\r
652 HL = M[DAR];\r
653 DAR++;\r
654 HL = HL | (M[DAR] <<8);\r
655 break;\r
656 }\r
657 case 0353: { /* XCHG */\r
658 DAR = HL;\r
659 HL = DE;\r
660 DE = DAR;\r
661 break;\r
662 }\r
663\r
664 /* Arithmetic Group */\r
665\r
666 case 0306: { /* ADI */\r
667 A += M[PC];\r
668 PC++;\r
669 setarith(A);\r
670 A = A & 0xFF;\r
671 break;\r
672 }\r
673 case 0316: { /* ACI */\r
674 carry = 0;\r
675 if (C) carry = 1;\r
676 A += M[PC];\r
677 A += carry;\r
678 PC++;\r
679 setarith(A);\r
680 A = A & 0xFF;\r
681 break;\r
682 }\r
683 case 0326: { /* SUI */\r
684 A -= M[PC];\r
685 PC++;\r
686 setarith(A);\r
687 A = A & 0xFF;\r
688 break;\r
689 }\r
690 case 0336: { /* SBI */\r
691 carry = 0;\r
692 if (C) carry = 1;\r
693 A -= (M[PC] + carry);\r
694 PC++;\r
695 setarith(A);\r
696 A = A & 0xFF;\r
697 break;\r
698 }\r
699 case 047: { /* DAA */\r
700 DAR = A & 0x0F;\r
701 if (DAR > 9 || AC > 0) {\r
702 DAR += 6;\r
703 A &= 0xF0;\r
704 A |= DAR & 0x0F;\r
705 if (DAR & 0x10)\r
706 AC = 0200000;\r
707 else\r
708 AC = 0;\r
709 }\r
710 DAR = (A >> 4) & 0x0F;\r
711 if (DAR > 9 || AC > 0) {\r
712 DAR += 6;\r
713 if (AC) DAR++;\r
714 A &= 0x0F;\r
715 A |= (DAR << 4);\r
716 }\r
717 if ((DAR << 4) & 0x100)\r
718 C = 0200000;\r
719 else\r
720 C = 0;\r
721 if (A & 0x80) {\r
722 S = 0200000;\r
723 } else {\r
724 S = 0;\r
725 }\r
726 if ((A & 0xff) == 0)\r
727 Z = 0200000;\r
728 else\r
729 Z = 0;\r
730 parity(A);\r
731 A = A & 0xFF;\r
732 break;\r
733 }\r
734 case 07: { /* RLC */\r
735 C = 0;\r
736 C = (A << 9) & 0200000;\r
737 A = (A << 1) & 0xFF;\r
738 if (C)\r
739 A |= 0x01;\r
740 break;\r
741 }\r
742 case 017: { /* RRC */\r
743 C = 0;\r
744 if ((A & 0x01) == 1)\r
745 C |= 0200000;\r
746 A = (A >> 1) & 0xFF;\r
747 if (C)\r
748 A |= 0x80;\r
749 break;\r
750 }\r
751 case 027: { /* RAL */\r
752 DAR = C;\r
753 C = 0;\r
754 C = (A << 9) & 0200000;\r
755 A = (A << 1) & 0xFF;\r
756 if (DAR)\r
757 A |= 1;\r
758 else\r
759 A &= 0xFE;\r
760 break;\r
761 }\r
762 case 037: { /* RAR */\r
763 DAR = C;\r
764 C = 0;\r
765 if ((A & 0x01) == 1)\r
766 C |= 0200000;\r
767 A = (A >> 1) & 0xFF;\r
768 if (DAR)\r
769 A |= 0x80;\r
770 else\r
771 A &= 0x7F;\r
772 break;\r
773 }\r
774 case 057: { /* CMA */\r
775 A = ~ A;\r
776 A &= 0xFF;\r
777 break;\r
778 }\r
779 case 077: { /* CMC */\r
780 C = ~ C;\r
781 C &= 0200000;\r
782 break;\r
783 }\r
784 case 067: { /* STC */\r
785 C = 0200000;\r
786 break;\r
787 }\r
788\r
789 /* Stack, I/O & Machine Control Group */\r
790\r
791 case 0: { /* NOP */\r
792 break;\r
793 }\r
794 case 0343: { /* XTHL */\r
795 lo = M[SP];\r
796 hi = M[SP + 1];\r
797 M[SP] = HL & 0xFF;\r
798 M[SP + 1] = (HL >> 8) & 0xFF;\r
799 HL = (hi << 8) + lo;\r
800 break;\r
801 }\r
802 case 0371: { /* SPHL */\r
803 SP = HL;\r
804 break;\r
805 }\r
806 case 0373: { /* EI */\r
807 INTE = 0200000;\r
808 break;\r
809 }\r
810 case 0363: { /* DI */\r
811 INTE = 0;\r
812 break;\r
813 }\r
814 case 0333: { /* IN */\r
815 DAR = M[PC] & 0xFF;\r
816 PC++;\r
817 if (DAR == 0xFF) {\r
818 A = (SR >> 8) & 0xFF;\r
819 } else {\r
820 A = dev_table[DAR].routine(0, 0);\r
821 }\r
822 break;\r
823 }\r
824 case 0323: { /* OUT */\r
825 DAR = M[PC] & 0xFF;\r
826 PC++;\r
827 dev_table[DAR].routine(1, A);\r
828 break;\r
829 }\r
830\r
831 default: {\r
832 if (cpu_unit.flags & UNIT_OPSTOP) {\r
833 reason = STOP_OPCODE;\r
834 PC--;\r
835 }\r
836 break;\r
837 }\r
838 }\r
839}\r
840\r
841/* Simulation halted */\r
842\r
843saved_PC = PC;\r
844return reason;\r
845}\r
846\r
847/* Test an 8080 flag condition and return 1 if true, 0 if false */\r
848int32 cond(int32 con)\r
849{\r
850 switch (con) {\r
851 case 0:\r
852 if (Z == 0) return (1);\r
853 break;\r
854 case 1:\r
855 if (Z != 0) return (1);\r
856 break;\r
857 case 2:\r
858 if (C == 0) return (1);\r
859 break;\r
860 case 3:\r
861 if (C != 0) return (1);\r
862 break;\r
863 case 4:\r
864 if (P == 0) return (1);\r
865 break;\r
866 case 5:\r
867 if (P != 0) return (1);\r
868 break;\r
869 case 6:\r
870 if (S == 0) return (1);\r
871 break;\r
872 case 7:\r
873 if (S != 0) return (1);\r
874 break;\r
875 default:\r
876 break;\r
877 }\r
878 return (0);\r
879}\r
880\r
881/* Set the <C>arry, <S>ign, <Z>ero and <P>arity flags following\r
882 an arithmetic operation on 'reg'.\r
883*/\r
884\r
885void setarith(int32 reg)\r
886{\r
887 int32 bc = 0;\r
888\r
889 if (reg & 0x100)\r
890 C = 0200000;\r
891 else\r
892 C = 0;\r
893 if (reg & 0x80) {\r
894 bc++;\r
895 S = 0200000;\r
896 } else {\r
897 S = 0;\r
898 }\r
899 if ((reg & 0xff) == 0)\r
900 Z = 0200000;\r
901 else\r
902 Z = 0;\r
903 AC = 0;\r
904 if (cpu_unit.flags & UNIT_CHIP) {\r
905 P = 0; /* parity is zero for *all* arith ops on Z80 */\r
906 } else {\r
907 parity(reg);\r
908 }\r
909}\r
910\r
911/* Set the <C>arry, <S>ign, <Z>ero amd <P>arity flags following\r
912 a logical (bitwise) operation on 'reg'.\r
913*/\r
914\r
915void setlogical(int32 reg)\r
916{\r
917 C = 0;\r
918 if (reg & 0x80) {\r
919 S = 0200000;\r
920 } else {\r
921 S = 0;\r
922 }\r
923 if ((reg & 0xff) == 0)\r
924 Z = 0200000;\r
925 else\r
926 Z = 0;\r
927 AC = 0;\r
928 parity(reg);\r
929}\r
930\r
931/* Set the Parity (P) flag based on parity of 'reg', i.e., number\r
932 of bits on even: P=0200000, else P=0\r
933*/\r
934\r
935void parity(int32 reg)\r
936{\r
937 int32 bc = 0;\r
938\r
939 if (reg & 0x01) bc++;\r
940 if (reg & 0x02) bc++;\r
941 if (reg & 0x04) bc++;\r
942 if (reg & 0x08) bc++;\r
943 if (reg & 0x10) bc++;\r
944 if (reg & 0x20) bc++;\r
945 if (reg & 0x40) bc++;\r
946 if (reg & 0x80) bc++;\r
947 P = ~(bc << 16);\r
948 P &= 0200000;\r
949}\r
950\r
951/* Set the <S>ign, <Z>ero amd <P>arity flags following\r
952 an INR/DCR operation on 'reg'.\r
953*/\r
954\r
955void setinc(int32 reg)\r
956{\r
957 int32 bc = 0;\r
958\r
959 if (reg & 0x80) {\r
960 bc++;\r
961 S = 0200000;\r
962 } else {\r
963 S = 0;\r
964 }\r
965 if ((reg & 0xff) == 0)\r
966 Z = 0200000;\r
967 else\r
968 Z = 0;\r
969 if (cpu_unit.flags & UNIT_CHIP) {\r
970 P = 0; /* parity is zero for *all* arith ops on Z80 */\r
971 } else {\r
972 parity(reg);\r
973 }\r
974}\r
975\r
976/* Get an 8080 register and return it */\r
977int32 getreg(int32 reg)\r
978{\r
979 switch (reg) {\r
980 case 0:\r
981 return ((BC >>8) & 0x00ff);\r
982 case 1:\r
983 return (BC & 0x00FF);\r
984 case 2:\r
985 return ((DE >>8) & 0x00ff);\r
986 case 3:\r
987 return (DE & 0x00ff);\r
988 case 4:\r
989 return ((HL >>8) & 0x00ff);\r
990 case 5:\r
991 return (HL & 0x00ff);\r
992 case 6:\r
993 return (M[HL]);\r
994 case 7:\r
995 return (A);\r
996 default:\r
997 break;\r
998 }\r
999 return 0;\r
1000}\r
1001\r
1002/* Put a value into an 8080 register from memory */\r
1003void putreg(int32 reg, int32 val)\r
1004{\r
1005 switch (reg) {\r
1006 case 0:\r
1007 BC = BC & 0x00FF;\r
1008 BC = BC | (val <<8);\r
1009 break;\r
1010 case 1:\r
1011 BC = BC & 0xFF00;\r
1012 BC = BC | val;\r
1013 break;\r
1014 case 2:\r
1015 DE = DE & 0x00FF;\r
1016 DE = DE | (val <<8);\r
1017 break;\r
1018 case 3:\r
1019 DE = DE & 0xFF00;\r
1020 DE = DE | val;\r
1021 break;\r
1022 case 4:\r
1023 HL = HL & 0x00FF;\r
1024 HL = HL | (val <<8);\r
1025 break;\r
1026 case 5:\r
1027 HL = HL & 0xFF00;\r
1028 HL = HL | val;\r
1029 break;\r
1030 case 6:\r
1031 M[HL] = val & 0xff;\r
1032 break;\r
1033 case 7:\r
1034 A = val & 0xff;\r
1035 default:\r
1036 break;\r
1037 }\r
1038}\r
1039\r
1040/* Return the value of a selected register pair */\r
1041int32 getpair(int32 reg)\r
1042{\r
1043 switch (reg) {\r
1044 case 0:\r
1045 return (BC);\r
1046 case 1:\r
1047 return (DE);\r
1048 case 2:\r
1049 return (HL);\r
1050 case 3:\r
1051 return (SP);\r
1052 default:\r
1053 break;\r
1054 }\r
1055 return 0;\r
1056}\r
1057\r
1058/* Return the value of a selected register pair, in PUSH\r
1059 format where 3 means A& flags, not SP */\r
1060int32 getpush(int32 reg)\r
1061{\r
1062 int32 stat;\r
1063\r
1064 switch (reg) {\r
1065 case 0:\r
1066 return (BC);\r
1067 case 1:\r
1068 return (DE);\r
1069 case 2:\r
1070 return (HL);\r
1071 case 3:\r
1072 stat = A << 8;\r
1073 if (S) stat |= 0x80;\r
1074 if (Z) stat |= 0x40;\r
1075 if (AC) stat |= 0x10;\r
1076 if (P) stat |= 0x04;\r
1077 stat |= 0x02;\r
1078 if (C) stat |= 0x01;\r
1079 return (stat);\r
1080 default:\r
1081 break;\r
1082 }\r
1083 return 0;\r
1084}\r
1085\r
1086\r
1087/* Place data into the indicated register pair, in PUSH\r
1088 format where 3 means A& flags, not SP */\r
1089void putpush(int32 reg, int32 data)\r
1090{\r
1091 switch (reg) {\r
1092 case 0:\r
1093 BC = data;\r
1094 break;\r
1095 case 1:\r
1096 DE = data;\r
1097 break;\r
1098 case 2:\r
1099 HL = data;\r
1100 break;\r
1101 case 3:\r
1102 A = (data >> 8) & 0xff;\r
1103 S = Z = AC = P = C = 0;\r
1104 if (data & 0x80) S = 0200000;\r
1105 if (data & 0x40) Z = 0200000;\r
1106 if (data & 0x10) AC = 0200000;\r
1107 if (data & 0x04) P = 0200000;\r
1108 if (data & 0x01) C = 0200000;\r
1109 break;\r
1110 default:\r
1111 break;\r
1112 }\r
1113}\r
1114\r
1115\r
1116/* Put a value into an 8080 register pair */\r
1117void putpair(int32 reg, int32 val)\r
1118{\r
1119 switch (reg) {\r
1120 case 0:\r
1121 BC = val;\r
1122 break;\r
1123 case 1:\r
1124 DE = val;\r
1125 break;\r
1126 case 2:\r
1127 HL = val;\r
1128 break;\r
1129 case 3:\r
1130 SP = val;\r
1131 break;\r
1132 default:\r
1133 break;\r
1134 }\r
1135}\r
1136\r
1137\r
1138/* Reset routine */\r
1139\r
1140t_stat cpu_reset (DEVICE *dptr)\r
1141{\r
1142C = 0;\r
1143Z = 0;\r
1144saved_PC = 0;\r
1145int_req = 0;\r
1146sim_brk_types = sim_brk_dflt = SWMASK ('E');\r
1147return SCPE_OK;\r
1148}\r
1149\r
1150/* Memory examine */\r
1151\r
1152t_stat cpu_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw)\r
1153{\r
1154if (addr >= MEMSIZE) return SCPE_NXM;\r
1155if (vptr != NULL) *vptr = M[addr] & 0377;\r
1156return SCPE_OK;\r
1157}\r
1158\r
1159/* Memory deposit */\r
1160\r
1161t_stat cpu_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw)\r
1162{\r
1163 if (addr >= MEMSIZE) return SCPE_NXM;\r
1164 M[addr] = val & 0377;\r
1165 return SCPE_OK;\r
1166}\r
1167\r
1168t_stat cpu_set_size (UNIT *uptr, int32 val, char *cptr, void *desc)\r
1169{\r
1170int32 mc = 0;\r
1171uint32 i;\r
1172\r
1173if ((val <= 0) || (val > MAXMEMSIZE) || ((val & 07777) != 0))\r
1174 return SCPE_ARG;\r
1175for (i = val; i < MEMSIZE; i++) mc = mc | M[i];\r
1176if ((mc != 0) && (!get_yn ("Really truncate memory [N]?", FALSE)))\r
1177 return SCPE_OK;\r
1178MEMSIZE = val;\r
1179for (i = MEMSIZE; i < MAXMEMSIZE; i++) M[i] = 0;\r
1180return SCPE_OK;\r
1181}\r
1182\r
1183int32 nulldev(int32 flag, int32 data)\r
1184{\r
1185 if (flag == 0)\r
1186 return (0377);\r
1187 return 0;\r
1188}\r
1189\r