1 |
49 |
arniml |
/****************************************************************************
|
2 |
|
|
* Intel 8039 Portable Emulator *
|
3 |
|
|
* *
|
4 |
|
|
* Copyright (C) 1997 by Mirko Buffoni *
|
5 |
|
|
* Based on the original work (C) 1997 by Dan Boris, an 8048 emulator *
|
6 |
|
|
* You are not allowed to distribute this software commercially *
|
7 |
|
|
* Please, notify me, if you make any changes to this file *
|
8 |
|
|
* *
|
9 |
|
|
* Adapted for the T48 uController project, 2004 by Arnim Laeuger *
|
10 |
|
|
* See http://www.opencores.org/projects.cgi/web/t48/overview *
|
11 |
|
|
* *
|
12 |
124 |
arniml |
* $Id: i8039.c,v 1.6 2004-07-03 14:38:11 arniml Exp $
|
13 |
49 |
arniml |
* *
|
14 |
|
|
* **** Change Log **** *
|
15 |
|
|
* *
|
16 |
|
|
* TLP (19-Jun-2001) *
|
17 |
|
|
* - Changed Ports 1 and 2 to quasi bidirectional output latched ports *
|
18 |
|
|
* - Added the Port 1 & 2 output latch data to the debugger window *
|
19 |
|
|
* TLP (02-Jan-2002) *
|
20 |
|
|
* - External IRQs no longer go pending (sampled as a level state) *
|
21 |
|
|
* - Timer IRQs do not go pending if Timer interrupts are disabled *
|
22 |
|
|
* - Timer IRQs made pending, were incorrectly being cleared if the *
|
23 |
|
|
* external interrupt was being serviced *
|
24 |
|
|
* - External interrupts now take precedence when simultaneous *
|
25 |
|
|
* internal and external interrupt requests occur *
|
26 |
|
|
* - 'DIS TCNTI' now removes pending timer IRQs *
|
27 |
|
|
* - Nested IRQs of any sort are no longer allowed *
|
28 |
|
|
* - T_flag was not being set in the right place of execution, which *
|
29 |
|
|
* could have lead to it being incorrectly set after being cleared *
|
30 |
|
|
* - Counter overflows now also set the T_flag *
|
31 |
|
|
* - Added the Timer/Counter register to the debugger window *
|
32 |
|
|
* TLP (09-Jan-2002) *
|
33 |
|
|
* - Changed Interrupt system to instant servicing *
|
34 |
|
|
* - The Timer and Counter can no longer be 'on' simultaneously *
|
35 |
|
|
* - Added Save State *
|
36 |
|
|
* TLP (15-Feb-2002) *
|
37 |
|
|
* - Corrected Positive signal edge sensing (used on the T1 input) *
|
38 |
|
|
****************************************************************************/
|
39 |
|
|
|
40 |
|
|
|
41 |
|
|
#include <stdio.h>
|
42 |
|
|
#include <string.h>
|
43 |
|
|
#include <stdlib.h>
|
44 |
|
|
|
45 |
|
|
#include "i8039.h"
|
46 |
|
|
|
47 |
|
|
|
48 |
|
|
/*** Cycle times for the jump on condition instructions, are unusual.
|
49 |
|
|
Condition is tested during the first cycle, so if condition is not
|
50 |
|
|
met, second address fetch cycle may not really be taken. For now we
|
51 |
|
|
just use the cycle counts as listed in the i8048 user manual.
|
52 |
|
|
***/
|
53 |
|
|
|
54 |
|
|
#if 0
|
55 |
|
|
#define ADJUST_CYCLES { inst_cycles -= 1; } /* Possible real cycles setting */
|
56 |
|
|
#else
|
57 |
|
|
#define ADJUST_CYCLES { } /* User Manual cycles setting */
|
58 |
|
|
#endif
|
59 |
|
|
|
60 |
|
|
|
61 |
|
|
|
62 |
|
|
/* HJB 01/05/99 changed to positive values to use pending_irq as a flag */
|
63 |
|
|
#define I8039_NO_INT 0 /* No Interrupts pending or executing */
|
64 |
|
|
#define I8039_EXTERNAL_INT 1 /* Execute a normal external interrupt */
|
65 |
|
|
#define I8039_TIMCNT_INT 2 /* Execute a Timer/Counter interrupt */
|
66 |
|
|
|
67 |
|
|
|
68 |
|
|
/* Layout of the registers in the debugger */
|
69 |
|
|
static UINT8 i8039_reg_layout[] = {
|
70 |
|
|
I8039_PC, I8039_SP, I8039_PSW, I8039_A, I8039_TC, I8039_P1, I8039_P2, -1,
|
71 |
|
|
I8039_R0, I8039_R1, I8039_R2, I8039_R3, I8039_R4, I8039_R5, I8039_R6, I8039_R7, 0
|
72 |
|
|
};
|
73 |
|
|
|
74 |
|
|
/* Layout of the debugger windows x,y,w,h */
|
75 |
|
|
static UINT8 i8039_win_layout[] = {
|
76 |
|
|
0, 0,80, 2, /* register window (top rows) */
|
77 |
|
|
0, 3,24,19, /* disassembler window (left colums) */
|
78 |
|
|
25, 3,55, 9, /* memory #1 window (right, upper middle) */
|
79 |
|
|
25,13,55, 9, /* memory #2 window (right, lower middle) */
|
80 |
|
|
0,23,80, 1, /* command line window (bottom rows) */
|
81 |
|
|
};
|
82 |
|
|
|
83 |
|
|
|
84 |
|
|
static int Ext_IRQ(void);
|
85 |
|
|
static int Timer_IRQ(void);
|
86 |
|
|
|
87 |
|
|
#define M_RDMEM(A) I8039_RDMEM(A)
|
88 |
|
|
#define M_RDOP(A) I8039_RDOP(A)
|
89 |
|
|
#define M_RDOP_ARG(A) I8039_RDOP_ARG(A)
|
90 |
|
|
#define M_IN(A) I8039_In(A)
|
91 |
|
|
#define M_OUT(A,V) I8039_Out(A,V)
|
92 |
|
|
|
93 |
|
|
#define port_r(A) I8039_In(I8039_p0 + A)
|
94 |
|
|
#define port_w(A,V) I8039_Out(I8039_p0 + A,V)
|
95 |
|
|
#define test_r(A) I8039_In(I8039_t0 + A)
|
96 |
|
|
#define test_w(A,V) I8039_Out(I8039_t0 + A,V)
|
97 |
|
|
#define bus_r() I8039_In(I8039_bus)
|
98 |
|
|
#define bus_w(V) I8039_Out(I8039_bus,V)
|
99 |
|
|
|
100 |
|
|
#define C_FLAG 0x80
|
101 |
|
|
#define A_FLAG 0x40
|
102 |
|
|
#define F_FLAG 0x20
|
103 |
|
|
#define B_FLAG 0x10
|
104 |
|
|
|
105 |
|
|
typedef struct
|
106 |
|
|
{
|
107 |
|
|
PAIR PREVPC; /* previous program counter */
|
108 |
|
|
PAIR PC; /* program counter */
|
109 |
|
|
UINT8 A, SP, PSW;
|
110 |
|
|
UINT8 RAM[256];
|
111 |
|
|
UINT8 bus, f1; /* Bus data, and flag1 */
|
112 |
|
|
UINT8 P1, P2; /* Internal Port 1 and 2 latched outputs */
|
113 |
|
|
|
114 |
|
|
UINT8 pending_irq, irq_executing, masterClock, regPtr;
|
115 |
|
|
UINT8 t_flag, timer, timerON, countON, xirq_en, tirq_en;
|
116 |
|
|
UINT16 A11, A11ff;
|
117 |
|
|
UINT8 irq_state, irq_extra_cycles;
|
118 |
|
|
int (*irq_callback)(int irqline);
|
119 |
|
|
} I8039_Regs;
|
120 |
|
|
|
121 |
|
|
static I8039_Regs R;
|
122 |
|
|
int i8039_ICount;
|
123 |
|
|
int inst_cycles;
|
124 |
|
|
static UINT8 Old_T1;
|
125 |
|
|
|
126 |
|
|
/* The opcode table now is a combination of cycle counts and function pointers */
|
127 |
|
|
typedef struct {
|
128 |
|
|
unsigned cycles;
|
129 |
|
|
void (*function) (void);
|
130 |
|
|
} s_opcode;
|
131 |
|
|
|
132 |
|
|
#define POSITIVE_EDGE_T1 (( (int)(T1-Old_T1) > 0) ? 1 : 0)
|
133 |
|
|
#define NEGATIVE_EDGE_T1 (( (int)(Old_T1-T1) > 0) ? 1 : 0)
|
134 |
|
|
|
135 |
|
|
#define M_Cy ((R.PSW & C_FLAG) >> 7)
|
136 |
|
|
#define M_Cn (!M_Cy)
|
137 |
|
|
#define M_Ay ((R.PSW & A_FLAG))
|
138 |
|
|
#define M_An (!M_Ay)
|
139 |
|
|
#define M_F0y ((R.PSW & F_FLAG))
|
140 |
|
|
#define M_F0n (!M_F0y)
|
141 |
|
|
#define M_By ((R.PSW & B_FLAG))
|
142 |
|
|
#define M_Bn (!M_By)
|
143 |
|
|
|
144 |
|
|
#define intRAM R.RAM
|
145 |
|
|
#define regPTR R.regPtr
|
146 |
|
|
|
147 |
|
|
#define R0 intRAM[regPTR ]
|
148 |
|
|
#define R1 intRAM[regPTR+1]
|
149 |
|
|
#define R2 intRAM[regPTR+2]
|
150 |
|
|
#define R3 intRAM[regPTR+3]
|
151 |
|
|
#define R4 intRAM[regPTR+4]
|
152 |
|
|
#define R5 intRAM[regPTR+5]
|
153 |
|
|
#define R6 intRAM[regPTR+6]
|
154 |
|
|
#define R7 intRAM[regPTR+7]
|
155 |
|
|
|
156 |
|
|
|
157 |
|
|
INLINE void CLR (UINT8 flag) { R.PSW &= ~flag; }
|
158 |
|
|
INLINE void SET (UINT8 flag) { R.PSW |= flag; }
|
159 |
|
|
|
160 |
|
|
|
161 |
|
|
/* Get next opcode argument and increment program counter */
|
162 |
|
|
INLINE unsigned M_RDMEM_OPCODE (void)
|
163 |
|
|
{
|
164 |
|
|
unsigned retval;
|
165 |
|
|
retval=M_RDOP_ARG(R.PC.w.l);
|
166 |
|
|
R.PC.w.l++;
|
167 |
|
|
return retval;
|
168 |
|
|
}
|
169 |
|
|
|
170 |
|
|
INLINE void push(UINT8 d)
|
171 |
|
|
{
|
172 |
|
|
intRAM[8+R.SP++] = d;
|
173 |
|
|
R.SP = R.SP & 0x0f;
|
174 |
|
|
R.PSW = R.PSW & 0xf8;
|
175 |
|
|
R.PSW = R.PSW | (R.SP >> 1);
|
176 |
|
|
}
|
177 |
|
|
|
178 |
|
|
INLINE UINT8 pull(void) {
|
179 |
|
|
R.SP = (R.SP + 15) & 0x0f; /* if (--R.SP < 0) R.SP = 15; */
|
180 |
|
|
R.PSW = R.PSW & 0xf8;
|
181 |
|
|
R.PSW = R.PSW | (R.SP >> 1);
|
182 |
|
|
/* regPTR = ((M_By) ? 24 : 0); regPTR should not change */
|
183 |
|
|
return intRAM[8+R.SP];
|
184 |
|
|
}
|
185 |
|
|
|
186 |
|
|
INLINE void daa_a(void)
|
187 |
|
|
{
|
188 |
|
|
if ((R.A & 0x0f) > 0x09 || (R.PSW & A_FLAG))
|
189 |
|
|
R.A += 0x06;
|
190 |
|
|
if ((R.A & 0xf0) > 0x90 || (R.PSW & C_FLAG))
|
191 |
|
|
{
|
192 |
|
|
R.A += 0x60;
|
193 |
|
|
SET(C_FLAG);
|
194 |
|
|
} else CLR(C_FLAG);
|
195 |
|
|
}
|
196 |
|
|
|
197 |
|
|
INLINE void M_ADD(UINT8 dat)
|
198 |
|
|
{
|
199 |
|
|
UINT16 temp;
|
200 |
|
|
|
201 |
|
|
CLR(C_FLAG | A_FLAG);
|
202 |
|
|
if ((R.A & 0xf) + (dat & 0xf) > 0xf) SET(A_FLAG);
|
203 |
|
|
temp = R.A + dat;
|
204 |
|
|
if (temp > 0xff) SET(C_FLAG);
|
205 |
|
|
R.A = temp & 0xff;
|
206 |
|
|
}
|
207 |
|
|
|
208 |
|
|
INLINE void M_ADDC(UINT8 dat)
|
209 |
|
|
{
|
210 |
|
|
UINT16 temp;
|
211 |
|
|
|
212 |
|
|
CLR(A_FLAG);
|
213 |
|
|
if ((R.A & 0xf) + (dat & 0xf) + M_Cy > 0xf) SET(A_FLAG);
|
214 |
|
|
temp = R.A + dat + M_Cy;
|
215 |
|
|
CLR(C_FLAG);
|
216 |
|
|
if (temp > 0xff) SET(C_FLAG);
|
217 |
|
|
R.A = temp & 0xff;
|
218 |
|
|
}
|
219 |
|
|
|
220 |
|
|
INLINE void M_CALL(UINT16 addr)
|
221 |
|
|
{
|
222 |
|
|
push(R.PC.b.l);
|
223 |
|
|
push((R.PC.b.h & 0x0f) | (R.PSW & 0xf0));
|
224 |
|
|
R.PC.w.l = addr;
|
225 |
|
|
|
226 |
|
|
}
|
227 |
|
|
|
228 |
|
|
INLINE void M_XCHD(UINT8 addr)
|
229 |
|
|
{
|
230 |
|
|
UINT8 dat = R.A & 0x0f;
|
231 |
|
|
R.A &= 0xf0;
|
232 |
|
|
R.A |= intRAM[addr] & 0x0f;
|
233 |
|
|
intRAM[addr] &= 0xf0;
|
234 |
|
|
intRAM[addr] |= dat;
|
235 |
|
|
}
|
236 |
|
|
|
237 |
|
|
|
238 |
|
|
INLINE void M_ILLEGAL(void)
|
239 |
|
|
{
|
240 |
|
|
logerror("I8039: PC = %04x, Illegal opcode = %02x\n", R.PC.w.l-1, M_RDMEM(R.PC.w.l-1));
|
241 |
|
|
}
|
242 |
|
|
|
243 |
|
|
INLINE void M_UNDEFINED(void)
|
244 |
|
|
{
|
245 |
|
|
logerror("I8039: PC = %04x, Unimplemented opcode = %02x\n", R.PC.w.l-1, M_RDMEM(R.PC.w.l-1));
|
246 |
|
|
}
|
247 |
|
|
|
248 |
|
|
#define INT_RAM_MASK 0xff
|
249 |
|
|
|
250 |
|
|
static void illegal(void) { M_ILLEGAL(); }
|
251 |
|
|
|
252 |
|
|
static void add_a_n(void) { M_ADD(M_RDMEM_OPCODE()); }
|
253 |
|
|
static void add_a_r0(void) { M_ADD(R0); }
|
254 |
|
|
static void add_a_r1(void) { M_ADD(R1); }
|
255 |
|
|
static void add_a_r2(void) { M_ADD(R2); }
|
256 |
|
|
static void add_a_r3(void) { M_ADD(R3); }
|
257 |
|
|
static void add_a_r4(void) { M_ADD(R4); }
|
258 |
|
|
static void add_a_r5(void) { M_ADD(R5); }
|
259 |
|
|
static void add_a_r6(void) { M_ADD(R6); }
|
260 |
|
|
static void add_a_r7(void) { M_ADD(R7); }
|
261 |
|
|
static void add_a_xr0(void) { M_ADD(intRAM[R0 & INT_RAM_MASK]); }
|
262 |
|
|
static void add_a_xr1(void) { M_ADD(intRAM[R1 & INT_RAM_MASK]); }
|
263 |
|
|
static void adc_a_n(void) { M_ADDC(M_RDMEM_OPCODE()); }
|
264 |
|
|
static void adc_a_r0(void) { M_ADDC(R0); }
|
265 |
|
|
static void adc_a_r1(void) { M_ADDC(R1); }
|
266 |
|
|
static void adc_a_r2(void) { M_ADDC(R2); }
|
267 |
|
|
static void adc_a_r3(void) { M_ADDC(R3); }
|
268 |
|
|
static void adc_a_r4(void) { M_ADDC(R4); }
|
269 |
|
|
static void adc_a_r5(void) { M_ADDC(R5); }
|
270 |
|
|
static void adc_a_r6(void) { M_ADDC(R6); }
|
271 |
|
|
static void adc_a_r7(void) { M_ADDC(R7); }
|
272 |
|
|
static void adc_a_xr0(void) { M_ADDC(intRAM[R0 & INT_RAM_MASK]); }
|
273 |
|
|
static void adc_a_xr1(void) { M_ADDC(intRAM[R1 & INT_RAM_MASK]); }
|
274 |
|
|
static void anl_a_n(void) { R.A &= M_RDMEM_OPCODE(); }
|
275 |
|
|
static void anl_a_r0(void) { R.A &= R0; }
|
276 |
|
|
static void anl_a_r1(void) { R.A &= R1; }
|
277 |
|
|
static void anl_a_r2(void) { R.A &= R2; }
|
278 |
|
|
static void anl_a_r3(void) { R.A &= R3; }
|
279 |
|
|
static void anl_a_r4(void) { R.A &= R4; }
|
280 |
|
|
static void anl_a_r5(void) { R.A &= R5; }
|
281 |
|
|
static void anl_a_r6(void) { R.A &= R6; }
|
282 |
|
|
static void anl_a_r7(void) { R.A &= R7; }
|
283 |
|
|
static void anl_a_xr0(void) { R.A &= intRAM[R0 & INT_RAM_MASK]; }
|
284 |
|
|
static void anl_a_xr1(void) { R.A &= intRAM[R1 & INT_RAM_MASK]; }
|
285 |
|
|
static void anl_bus_n(void) { bus_w( bus_r() & M_RDMEM_OPCODE() ); }
|
286 |
|
|
static void anl_p1_n(void) { R.P1 &= M_RDMEM_OPCODE(); port_w( 1, R.P1 ); }
|
287 |
|
|
static void anl_p2_n(void) { R.P2 &= M_RDMEM_OPCODE(); port_w( 2, R.P2 ); }
|
288 |
|
|
static void anld_p4_a(void) { port_w( 4, port_r(4) & M_RDMEM_OPCODE() ); }
|
289 |
|
|
static void anld_p5_a(void) { port_w( 5, port_r(5) & M_RDMEM_OPCODE() ); }
|
290 |
|
|
static void anld_p6_a(void) { port_w( 6, port_r(6) & M_RDMEM_OPCODE() ); }
|
291 |
|
|
static void anld_p7_a(void) { port_w( 7, port_r(7) & M_RDMEM_OPCODE() ); }
|
292 |
|
|
static void call(void) { UINT8 i=M_RDMEM_OPCODE(); M_CALL(i | R.A11); }
|
293 |
|
|
static void call_1(void) { UINT8 i=M_RDMEM_OPCODE(); M_CALL(i | 0x100 | R.A11); }
|
294 |
|
|
static void call_2(void) { UINT8 i=M_RDMEM_OPCODE(); M_CALL(i | 0x200 | R.A11); }
|
295 |
|
|
static void call_3(void) { UINT8 i=M_RDMEM_OPCODE(); M_CALL(i | 0x300 | R.A11); }
|
296 |
|
|
static void call_4(void) { UINT8 i=M_RDMEM_OPCODE(); M_CALL(i | 0x400 | R.A11); }
|
297 |
|
|
static void call_5(void) { UINT8 i=M_RDMEM_OPCODE(); M_CALL(i | 0x500 | R.A11); }
|
298 |
|
|
static void call_6(void) { UINT8 i=M_RDMEM_OPCODE(); M_CALL(i | 0x600 | R.A11); }
|
299 |
|
|
static void call_7(void) { UINT8 i=M_RDMEM_OPCODE(); M_CALL(i | 0x700 | R.A11); }
|
300 |
|
|
static void clr_a(void) { R.A=0; }
|
301 |
|
|
static void clr_c(void) { CLR(C_FLAG); }
|
302 |
|
|
static void clr_f0(void) { CLR(F_FLAG); }
|
303 |
|
|
static void clr_f1(void) { R.f1 = 0; }
|
304 |
|
|
static void cpl_a(void) { R.A ^= 0xff; }
|
305 |
|
|
static void cpl_c(void) { R.PSW ^= C_FLAG; }
|
306 |
|
|
static void cpl_f0(void) { R.PSW ^= F_FLAG; }
|
307 |
|
|
static void cpl_f1(void) { R.f1 ^= 1; }
|
308 |
|
|
static void dec_a(void) { R.A--; }
|
309 |
|
|
static void dec_r0(void) { R0--; }
|
310 |
|
|
static void dec_r1(void) { R1--; }
|
311 |
|
|
static void dec_r2(void) { R2--; }
|
312 |
|
|
static void dec_r3(void) { R3--; }
|
313 |
|
|
static void dec_r4(void) { R4--; }
|
314 |
|
|
static void dec_r5(void) { R5--; }
|
315 |
|
|
static void dec_r6(void) { R6--; }
|
316 |
|
|
static void dec_r7(void) { R7--; }
|
317 |
|
|
static void dis_i(void) { R.xirq_en = 0; }
|
318 |
|
|
static void dis_tcnti(void) { R.tirq_en = 0; R.pending_irq &= ~I8039_TIMCNT_INT; }
|
319 |
|
|
static void djnz_r0(void) { UINT8 i=M_RDMEM_OPCODE(); R0--; if (R0 != 0) { R.PC.w.l = ((R.PC.w.l-1) & 0xf00) | i; } else ADJUST_CYCLES }
|
320 |
|
|
static void djnz_r1(void) { UINT8 i=M_RDMEM_OPCODE(); R1--; if (R1 != 0) { R.PC.w.l = ((R.PC.w.l-1) & 0xf00) | i; } else ADJUST_CYCLES }
|
321 |
|
|
static void djnz_r2(void) { UINT8 i=M_RDMEM_OPCODE(); R2--; if (R2 != 0) { R.PC.w.l = ((R.PC.w.l-1) & 0xf00) | i; } else ADJUST_CYCLES }
|
322 |
|
|
static void djnz_r3(void) { UINT8 i=M_RDMEM_OPCODE(); R3--; if (R3 != 0) { R.PC.w.l = ((R.PC.w.l-1) & 0xf00) | i; } else ADJUST_CYCLES }
|
323 |
|
|
static void djnz_r4(void) { UINT8 i=M_RDMEM_OPCODE(); R4--; if (R4 != 0) { R.PC.w.l = ((R.PC.w.l-1) & 0xf00) | i; } else ADJUST_CYCLES }
|
324 |
|
|
static void djnz_r5(void) { UINT8 i=M_RDMEM_OPCODE(); R5--; if (R5 != 0) { R.PC.w.l = ((R.PC.w.l-1) & 0xf00) | i; } else ADJUST_CYCLES }
|
325 |
|
|
static void djnz_r6(void) { UINT8 i=M_RDMEM_OPCODE(); R6--; if (R6 != 0) { R.PC.w.l = ((R.PC.w.l-1) & 0xf00) | i; } else ADJUST_CYCLES }
|
326 |
|
|
static void djnz_r7(void) { UINT8 i=M_RDMEM_OPCODE(); R7--; if (R7 != 0) { R.PC.w.l = ((R.PC.w.l-1) & 0xf00) | i; } else ADJUST_CYCLES }
|
327 |
|
|
static void en_i(void) { R.xirq_en = 1; if (R.irq_state == I8039_EXTERNAL_INT) { R.irq_extra_cycles += Ext_IRQ(); } }
|
328 |
|
|
static void en_tcnti(void) { R.tirq_en = 1; }
|
329 |
|
|
static void ento_clk(void) { M_UNDEFINED(); }
|
330 |
|
|
static void in_a_p1(void) { R.A = port_r(1) & R.P1; }
|
331 |
|
|
static void in_a_p2(void) { R.A = port_r(2) & R.P2; }
|
332 |
|
|
static void ins_a_bus(void) { R.A = bus_r(); }
|
333 |
|
|
static void inc_a(void) { R.A++; }
|
334 |
|
|
static void inc_r0(void) { R0++; }
|
335 |
|
|
static void inc_r1(void) { R1++; }
|
336 |
|
|
static void inc_r2(void) { R2++; }
|
337 |
|
|
static void inc_r3(void) { R3++; }
|
338 |
|
|
static void inc_r4(void) { R4++; }
|
339 |
|
|
static void inc_r5(void) { R5++; }
|
340 |
|
|
static void inc_r6(void) { R6++; }
|
341 |
|
|
static void inc_r7(void) { R7++; }
|
342 |
|
|
static void inc_xr0(void) { intRAM[R0 & INT_RAM_MASK]++; }
|
343 |
|
|
static void inc_xr1(void) { intRAM[R1 & INT_RAM_MASK]++; }
|
344 |
|
|
|
345 |
|
|
/* static void jmp(void) { UINT8 i=M_RDOP(R.PC.w.l); R.PC.w.l = i | R.A11; }
|
346 |
|
|
*/
|
347 |
|
|
|
348 |
|
|
static void jmp(void)
|
349 |
|
|
{
|
350 |
|
|
UINT8 i=M_RDOP(R.PC.w.l);
|
351 |
|
|
UINT16 oldpc,newpc;
|
352 |
|
|
|
353 |
|
|
oldpc = R.PC.w.l-1;
|
354 |
|
|
R.PC.w.l = i | R.A11;
|
355 |
|
|
newpc = R.PC.w.l;
|
356 |
|
|
if (newpc == oldpc) { if (i8039_ICount > 0) i8039_ICount = 0; } /* speed up busy loop */
|
357 |
|
|
else if (newpc == oldpc-1 && M_RDOP(newpc) == 0x00) /* NOP - Gyruss */
|
358 |
|
|
{ if (i8039_ICount > 0) i8039_ICount = 0; }
|
359 |
|
|
}
|
360 |
|
|
|
361 |
|
|
static void jmp_1(void) { UINT8 i=M_RDOP(R.PC.w.l); R.PC.w.l = i | 0x100 | R.A11; }
|
362 |
|
|
static void jmp_2(void) { UINT8 i=M_RDOP(R.PC.w.l); R.PC.w.l = i | 0x200 | R.A11; }
|
363 |
|
|
static void jmp_3(void) { UINT8 i=M_RDOP(R.PC.w.l); R.PC.w.l = i | 0x300 | R.A11; }
|
364 |
|
|
static void jmp_4(void) { UINT8 i=M_RDOP(R.PC.w.l); R.PC.w.l = i | 0x400 | R.A11; }
|
365 |
|
|
static void jmp_5(void) { UINT8 i=M_RDOP(R.PC.w.l); R.PC.w.l = i | 0x500 | R.A11; }
|
366 |
|
|
static void jmp_6(void) { UINT8 i=M_RDOP(R.PC.w.l); R.PC.w.l = i | 0x600 | R.A11; }
|
367 |
|
|
static void jmp_7(void) { UINT8 i=M_RDOP(R.PC.w.l); R.PC.w.l = i | 0x700 | R.A11; }
|
368 |
|
|
static void jmpp_xa(void) { UINT16 addr = (R.PC.w.l & 0xf00) | R.A; R.PC.w.l = (R.PC.w.l & 0xf00) | M_RDMEM(addr); }
|
369 |
|
|
static void jb_0(void) { UINT8 i=M_RDMEM_OPCODE(); if (R.A & 0x01) { R.PC.w.l = ((R.PC.w.l-1) & 0xf00) | i; } else ADJUST_CYCLES }
|
370 |
|
|
static void jb_1(void) { UINT8 i=M_RDMEM_OPCODE(); if (R.A & 0x02) { R.PC.w.l = ((R.PC.w.l-1) & 0xf00) | i; } else ADJUST_CYCLES }
|
371 |
|
|
static void jb_2(void) { UINT8 i=M_RDMEM_OPCODE(); if (R.A & 0x04) { R.PC.w.l = ((R.PC.w.l-1) & 0xf00) | i; } else ADJUST_CYCLES }
|
372 |
|
|
static void jb_3(void) { UINT8 i=M_RDMEM_OPCODE(); if (R.A & 0x08) { R.PC.w.l = ((R.PC.w.l-1) & 0xf00) | i; } else ADJUST_CYCLES }
|
373 |
|
|
static void jb_4(void) { UINT8 i=M_RDMEM_OPCODE(); if (R.A & 0x10) { R.PC.w.l = ((R.PC.w.l-1) & 0xf00) | i; } else ADJUST_CYCLES }
|
374 |
|
|
static void jb_5(void) { UINT8 i=M_RDMEM_OPCODE(); if (R.A & 0x20) { R.PC.w.l = ((R.PC.w.l-1) & 0xf00) | i; } else ADJUST_CYCLES }
|
375 |
|
|
static void jb_6(void) { UINT8 i=M_RDMEM_OPCODE(); if (R.A & 0x40) { R.PC.w.l = ((R.PC.w.l-1) & 0xf00) | i; } else ADJUST_CYCLES }
|
376 |
|
|
static void jb_7(void) { UINT8 i=M_RDMEM_OPCODE(); if (R.A & 0x80) { R.PC.w.l = ((R.PC.w.l-1) & 0xf00) | i; } else ADJUST_CYCLES }
|
377 |
|
|
static void jf0(void) { UINT8 i=M_RDMEM_OPCODE(); if (M_F0y) { R.PC.w.l = ((R.PC.w.l-1) & 0xf00) | i; } else ADJUST_CYCLES }
|
378 |
|
|
static void jf1(void) { UINT8 i=M_RDMEM_OPCODE(); if (R.f1) { R.PC.w.l = ((R.PC.w.l-1) & 0xf00) | i; } else ADJUST_CYCLES }
|
379 |
|
|
static void jnc(void) { UINT8 i=M_RDMEM_OPCODE(); if (M_Cn) { R.PC.w.l = ((R.PC.w.l-1) & 0xf00) | i; } else ADJUST_CYCLES }
|
380 |
|
|
static void jc(void) { UINT8 i=M_RDMEM_OPCODE(); if (M_Cy) { R.PC.w.l = ((R.PC.w.l-1) & 0xf00) | i; } else ADJUST_CYCLES }
|
381 |
|
|
static void jni(void) { UINT8 i=M_RDMEM_OPCODE(); if (R.irq_state == I8039_EXTERNAL_INT) { R.PC.w.l = ((R.PC.w.l-1) & 0xf00) | i; } else ADJUST_CYCLES }
|
382 |
|
|
static void jnt_0(void) { UINT8 i=M_RDMEM_OPCODE(); if (!test_r(0)) { R.PC.w.l = ((R.PC.w.l-1) & 0xf00) | i; } else ADJUST_CYCLES }
|
383 |
|
|
static void jt_0(void) { UINT8 i=M_RDMEM_OPCODE(); if (test_r(0)) { R.PC.w.l = ((R.PC.w.l-1) & 0xf00) | i; } else ADJUST_CYCLES }
|
384 |
|
|
static void jnt_1(void) { UINT8 i=M_RDMEM_OPCODE(); if (!test_r(1)) { R.PC.w.l = ((R.PC.w.l-1) & 0xf00) | i; } else ADJUST_CYCLES }
|
385 |
|
|
static void jt_1(void) { UINT8 i=M_RDMEM_OPCODE(); if (test_r(1)) { R.PC.w.l = ((R.PC.w.l-1) & 0xf00) | i; } else ADJUST_CYCLES }
|
386 |
|
|
static void jnz(void) { UINT8 i=M_RDMEM_OPCODE(); if (R.A != 0) { R.PC.w.l = ((R.PC.w.l-1) & 0xf00) | i; } else ADJUST_CYCLES }
|
387 |
|
|
static void jz(void) { UINT8 i=M_RDMEM_OPCODE(); if (R.A == 0) { R.PC.w.l = ((R.PC.w.l-1) & 0xf00) | i; } else ADJUST_CYCLES }
|
388 |
|
|
static void jtf(void) { UINT8 i=M_RDMEM_OPCODE(); if (R.t_flag) { R.PC.w.l = ((R.PC.w.l-1) & 0xf00) | i; R.t_flag = 0; } else ADJUST_CYCLES }
|
389 |
|
|
|
390 |
|
|
static void mov_a_n(void) { R.A = M_RDMEM_OPCODE(); }
|
391 |
|
|
static void mov_a_r0(void) { R.A = R0; }
|
392 |
|
|
static void mov_a_r1(void) { R.A = R1; }
|
393 |
|
|
static void mov_a_r2(void) { R.A = R2; }
|
394 |
|
|
static void mov_a_r3(void) { R.A = R3; }
|
395 |
|
|
static void mov_a_r4(void) { R.A = R4; }
|
396 |
|
|
static void mov_a_r5(void) { R.A = R5; }
|
397 |
|
|
static void mov_a_r6(void) { R.A = R6; }
|
398 |
|
|
static void mov_a_r7(void) { R.A = R7; }
|
399 |
52 |
arniml |
static void mov_a_psw(void) { R.A = R.PSW | 0x08; }
|
400 |
49 |
arniml |
static void mov_a_xr0(void) { R.A = intRAM[R0 & INT_RAM_MASK]; }
|
401 |
|
|
static void mov_a_xr1(void) { R.A = intRAM[R1 & INT_RAM_MASK]; }
|
402 |
|
|
static void mov_r0_a(void) { R0 = R.A; }
|
403 |
|
|
static void mov_r1_a(void) { R1 = R.A; }
|
404 |
|
|
static void mov_r2_a(void) { R2 = R.A; }
|
405 |
|
|
static void mov_r3_a(void) { R3 = R.A; }
|
406 |
|
|
static void mov_r4_a(void) { R4 = R.A; }
|
407 |
|
|
static void mov_r5_a(void) { R5 = R.A; }
|
408 |
|
|
static void mov_r6_a(void) { R6 = R.A; }
|
409 |
|
|
static void mov_r7_a(void) { R7 = R.A; }
|
410 |
52 |
arniml |
static void mov_psw_a(void) { R.PSW = R.A | 0x08; regPTR = ((M_By) ? 24 : 0); R.SP = (R.PSW & 7) << 1; }
|
411 |
49 |
arniml |
static void mov_r0_n(void) { R0 = M_RDMEM_OPCODE(); }
|
412 |
|
|
static void mov_r1_n(void) { R1 = M_RDMEM_OPCODE(); }
|
413 |
|
|
static void mov_r2_n(void) { R2 = M_RDMEM_OPCODE(); }
|
414 |
|
|
static void mov_r3_n(void) { R3 = M_RDMEM_OPCODE(); }
|
415 |
|
|
static void mov_r4_n(void) { R4 = M_RDMEM_OPCODE(); }
|
416 |
|
|
static void mov_r5_n(void) { R5 = M_RDMEM_OPCODE(); }
|
417 |
|
|
static void mov_r6_n(void) { R6 = M_RDMEM_OPCODE(); }
|
418 |
|
|
static void mov_r7_n(void) { R7 = M_RDMEM_OPCODE(); }
|
419 |
|
|
static void mov_a_t(void) { R.A = R.timer; }
|
420 |
|
|
static void mov_t_a(void) { R.timer = R.A; }
|
421 |
|
|
static void mov_xr0_a(void) { intRAM[R0 & INT_RAM_MASK] = R.A; }
|
422 |
|
|
static void mov_xr1_a(void) { intRAM[R1 & INT_RAM_MASK] = R.A; }
|
423 |
|
|
static void mov_xr0_n(void) { intRAM[R0 & INT_RAM_MASK] = M_RDMEM_OPCODE(); }
|
424 |
|
|
static void mov_xr1_n(void) { intRAM[R1 & INT_RAM_MASK] = M_RDMEM_OPCODE(); }
|
425 |
|
|
static void movd_a_p4(void) { R.A = port_r(4); }
|
426 |
|
|
static void movd_a_p5(void) { R.A = port_r(5); }
|
427 |
|
|
static void movd_a_p6(void) { R.A = port_r(6); }
|
428 |
|
|
static void movd_a_p7(void) { R.A = port_r(7); }
|
429 |
|
|
static void movd_p4_a(void) { port_w(4, R.A); }
|
430 |
|
|
static void movd_p5_a(void) { port_w(5, R.A); }
|
431 |
|
|
static void movd_p6_a(void) { port_w(6, R.A); }
|
432 |
|
|
static void movd_p7_a(void) { port_w(7, R.A); }
|
433 |
|
|
static void movp_a_xa(void) { R.A = M_RDMEM((R.PC.w.l & 0x0f00) | R.A); }
|
434 |
|
|
static void movp3_a_xa(void) { R.A = M_RDMEM(0x300 | R.A); }
|
435 |
|
|
static void movx_a_xr0(void) { R.A = M_IN(R0); }
|
436 |
|
|
static void movx_a_xr1(void) { R.A = M_IN(R1); }
|
437 |
|
|
static void movx_xr0_a(void) { M_OUT(R0, R.A); }
|
438 |
|
|
static void movx_xr1_a(void) { M_OUT(R1, R.A); }
|
439 |
|
|
static void nop(void) { }
|
440 |
|
|
static void orl_a_n(void) { R.A |= M_RDMEM_OPCODE(); }
|
441 |
|
|
static void orl_a_r0(void) { R.A |= R0; }
|
442 |
|
|
static void orl_a_r1(void) { R.A |= R1; }
|
443 |
|
|
static void orl_a_r2(void) { R.A |= R2; }
|
444 |
|
|
static void orl_a_r3(void) { R.A |= R3; }
|
445 |
|
|
static void orl_a_r4(void) { R.A |= R4; }
|
446 |
|
|
static void orl_a_r5(void) { R.A |= R5; }
|
447 |
|
|
static void orl_a_r6(void) { R.A |= R6; }
|
448 |
|
|
static void orl_a_r7(void) { R.A |= R7; }
|
449 |
|
|
static void orl_a_xr0(void) { R.A |= intRAM[R0 & INT_RAM_MASK]; }
|
450 |
|
|
static void orl_a_xr1(void) { R.A |= intRAM[R1 & INT_RAM_MASK]; }
|
451 |
|
|
static void orl_bus_n(void) { bus_w( bus_r() | M_RDMEM_OPCODE() ); }
|
452 |
|
|
static void orl_p1_n(void) { R.P1 |= M_RDMEM_OPCODE(); port_w(1, R.P1); }
|
453 |
|
|
static void orl_p2_n(void) { R.P2 |= M_RDMEM_OPCODE(); port_w(2, R.P2); }
|
454 |
|
|
static void orld_p4_a(void) { port_w(4, port_r(4) | R.A ); }
|
455 |
|
|
static void orld_p5_a(void) { port_w(5, port_r(5) | R.A ); }
|
456 |
|
|
static void orld_p6_a(void) { port_w(6, port_r(6) | R.A ); }
|
457 |
|
|
static void orld_p7_a(void) { port_w(7, port_r(7) | R.A ); }
|
458 |
|
|
static void outl_bus_a(void) { bus_w(R.A); }
|
459 |
|
|
static void outl_p1_a(void) { port_w(1, R.A); R.P1 = R.A; }
|
460 |
|
|
static void outl_p2_a(void) { port_w(2, R.A); R.P2 = R.A; }
|
461 |
|
|
static void ret(void) { R.PC.w.l = ((pull() & 0x0f) << 8); R.PC.w.l |= pull(); }
|
462 |
|
|
|
463 |
|
|
static void retr(void)
|
464 |
|
|
{
|
465 |
|
|
UINT8 i=pull();
|
466 |
|
|
R.PC.w.l = ((i & 0x0f) << 8) | pull();
|
467 |
|
|
R.PSW = (R.PSW & 0x0f) | (i & 0xf0); /* Stack is already changed by pull */
|
468 |
|
|
regPTR = ((M_By) ? 24 : 0);
|
469 |
|
|
|
470 |
|
|
R.irq_executing = I8039_NO_INT;
|
471 |
|
|
|
472 |
124 |
arniml |
R.A11 = R.A11ff;
|
473 |
|
|
|
474 |
49 |
arniml |
/* Take an interrupt if a request is still being made */
|
475 |
|
|
if (R.irq_state == I8039_EXTERNAL_INT) {
|
476 |
|
|
R.irq_extra_cycles += Ext_IRQ(); /* Service External IRQ */
|
477 |
|
|
}
|
478 |
|
|
else if (R.pending_irq == I8039_TIMCNT_INT) {
|
479 |
|
|
R.irq_extra_cycles += Timer_IRQ(); /* Service pending Timer/Counter IRQ */
|
480 |
|
|
}
|
481 |
|
|
}
|
482 |
|
|
static void rl_a(void) { UINT8 i=R.A & 0x80; R.A <<= 1; if (i) R.A |= 0x01; else R.A &= 0xfe; }
|
483 |
|
|
/* NS990113 */
|
484 |
|
|
static void rlc_a(void) { UINT8 i=M_Cy; if (R.A & 0x80) SET(C_FLAG); else CLR(C_FLAG); R.A <<= 1; if (i) R.A |= 0x01; else R.A &= 0xfe; }
|
485 |
|
|
static void rr_a(void) { UINT8 i=R.A & 1; R.A >>= 1; if (i) R.A |= 0x80; else R.A &= 0x7f; }
|
486 |
|
|
/* NS990113 */
|
487 |
|
|
static void rrc_a(void) { UINT8 i=M_Cy; if (R.A & 1) SET(C_FLAG); else CLR(C_FLAG); R.A >>= 1; if (i) R.A |= 0x80; else R.A &= 0x7f; }
|
488 |
|
|
static void sel_mb0(void) { R.A11 = 0; R.A11ff = 0; }
|
489 |
88 |
arniml |
static void sel_mb1(void) { R.A11ff = 0x800; R.A11 = 0x800; }
|
490 |
49 |
arniml |
static void sel_rb0(void) { CLR(B_FLAG); regPTR = 0; }
|
491 |
|
|
static void sel_rb1(void) { SET(B_FLAG); regPTR = 24; }
|
492 |
|
|
static void stop_tcnt(void) { R.timerON = R.countON = 0; }
|
493 |
|
|
static void strt_cnt(void) { R.countON = 1; R.timerON = 0; Old_T1 = test_r(1); } /* NS990113 */
|
494 |
|
|
static void strt_t(void) { R.timerON = 1; R.countON = 0; R.masterClock = 0; } /* NS990113 */
|
495 |
|
|
static void swap_a(void) { UINT8 i=R.A >> 4; R.A <<= 4; R.A |= i; }
|
496 |
|
|
static void xch_a_r0(void) { UINT8 i=R.A; R.A=R0; R0=i; }
|
497 |
|
|
static void xch_a_r1(void) { UINT8 i=R.A; R.A=R1; R1=i; }
|
498 |
|
|
static void xch_a_r2(void) { UINT8 i=R.A; R.A=R2; R2=i; }
|
499 |
|
|
static void xch_a_r3(void) { UINT8 i=R.A; R.A=R3; R3=i; }
|
500 |
|
|
static void xch_a_r4(void) { UINT8 i=R.A; R.A=R4; R4=i; }
|
501 |
|
|
static void xch_a_r5(void) { UINT8 i=R.A; R.A=R5; R5=i; }
|
502 |
|
|
static void xch_a_r6(void) { UINT8 i=R.A; R.A=R6; R6=i; }
|
503 |
|
|
static void xch_a_r7(void) { UINT8 i=R.A; R.A=R7; R7=i; }
|
504 |
|
|
static void xch_a_xr0(void) { UINT8 i=R.A; R.A=intRAM[R0 & INT_RAM_MASK]; intRAM[R0 & INT_RAM_MASK]=i; }
|
505 |
|
|
static void xch_a_xr1(void) { UINT8 i=R.A; R.A=intRAM[R1 & INT_RAM_MASK]; intRAM[R1 & INT_RAM_MASK]=i; }
|
506 |
|
|
static void xchd_a_xr0(void) { M_XCHD(R0 & INT_RAM_MASK); }
|
507 |
|
|
static void xchd_a_xr1(void) { M_XCHD(R1 & INT_RAM_MASK); }
|
508 |
|
|
static void xrl_a_n(void) { R.A ^= M_RDMEM_OPCODE(); }
|
509 |
|
|
static void xrl_a_r0(void) { R.A ^= R0; }
|
510 |
|
|
static void xrl_a_r1(void) { R.A ^= R1; }
|
511 |
|
|
static void xrl_a_r2(void) { R.A ^= R2; }
|
512 |
|
|
static void xrl_a_r3(void) { R.A ^= R3; }
|
513 |
|
|
static void xrl_a_r4(void) { R.A ^= R4; }
|
514 |
|
|
static void xrl_a_r5(void) { R.A ^= R5; }
|
515 |
|
|
static void xrl_a_r6(void) { R.A ^= R6; }
|
516 |
|
|
static void xrl_a_r7(void) { R.A ^= R7; }
|
517 |
|
|
static void xrl_a_xr0(void) { R.A ^= intRAM[R0 & INT_RAM_MASK]; }
|
518 |
|
|
static void xrl_a_xr1(void) { R.A ^= intRAM[R1 & INT_RAM_MASK]; }
|
519 |
|
|
|
520 |
|
|
static s_opcode opcode_main[256]=
|
521 |
|
|
{
|
522 |
|
|
{1, nop },{0, illegal },{2, outl_bus_a },{2, add_a_n },{2, jmp },{1, en_i },{0, illegal },{1, dec_a },
|
523 |
|
|
{2, ins_a_bus },{2, in_a_p1 },{2, in_a_p2 },{0, illegal },{2, movd_a_p4 },{2, movd_a_p5 },{2, movd_a_p6 },{2, movd_a_p7 },
|
524 |
|
|
{1, inc_xr0 },{1, inc_xr1 },{2, jb_0 },{2, adc_a_n },{2, call },{1, dis_i },{2, jtf },{1, inc_a },
|
525 |
|
|
{1, inc_r0 },{1, inc_r1 },{1, inc_r2 },{1, inc_r3 },{1, inc_r4 },{1, inc_r5 },{1, inc_r6 },{1, inc_r7 },
|
526 |
|
|
{1, xch_a_xr0 },{1, xch_a_xr1 },{0, illegal },{2, mov_a_n },{2, jmp_1 },{1, en_tcnti },{2, jnt_0 },{1, clr_a },
|
527 |
|
|
{1, xch_a_r0 },{1, xch_a_r1 },{1, xch_a_r2 },{1, xch_a_r3 },{1, xch_a_r4 },{1, xch_a_r5 },{1, xch_a_r6 },{1, xch_a_r7 },
|
528 |
|
|
{1, xchd_a_xr0 },{1, xchd_a_xr1 },{2, jb_1 },{0, illegal },{2, call_1 },{1, dis_tcnti },{2, jt_0 },{1, cpl_a },
|
529 |
|
|
{0, illegal },{2, outl_p1_a },{2, outl_p2_a },{0, illegal },{2, movd_p4_a },{2, movd_p5_a },{2, movd_p6_a },{2, movd_p7_a },
|
530 |
|
|
{1, orl_a_xr0 },{1, orl_a_xr1 },{1, mov_a_t },{2, orl_a_n },{2, jmp_2 },{1, strt_cnt },{2, jnt_1 },{1, swap_a },
|
531 |
|
|
{1, orl_a_r0 },{1, orl_a_r1 },{1, orl_a_r2 },{1, orl_a_r3 },{1, orl_a_r4 },{1, orl_a_r5 },{1, orl_a_r6 },{1, orl_a_r7 },
|
532 |
|
|
{1, anl_a_xr0 },{1, anl_a_xr1 },{2, jb_2 },{2, anl_a_n },{2, call_2 },{1, strt_t },{2, jt_1 },{1, daa_a },
|
533 |
|
|
{1, anl_a_r0 },{1, anl_a_r1 },{1, anl_a_r2 },{1, anl_a_r3 },{1, anl_a_r4 },{1, anl_a_r5 },{1, anl_a_r6 },{1, anl_a_r7 },
|
534 |
|
|
{1, add_a_xr0 },{1, add_a_xr1 },{1, mov_t_a },{0, illegal },{2, jmp_3 },{1, stop_tcnt },{0, illegal },{1, rrc_a },
|
535 |
|
|
{1, add_a_r0 },{1, add_a_r1 },{1, add_a_r2 },{1, add_a_r3 },{1, add_a_r4 },{1, add_a_r5 },{1, add_a_r6 },{1, add_a_r7 },
|
536 |
|
|
{1, adc_a_xr0 },{1, adc_a_xr1 },{2, jb_3 },{0, illegal },{2, call_3 },{1, ento_clk },{2, jf1 },{1, rr_a },
|
537 |
|
|
{1, adc_a_r0 },{1, adc_a_r1 },{1, adc_a_r2 },{1, adc_a_r3 },{1, adc_a_r4 },{1, adc_a_r5 },{1, adc_a_r6 },{1, adc_a_r7 },
|
538 |
|
|
{2, movx_a_xr0 },{2, movx_a_xr1 },{0, illegal },{2, ret },{2, jmp_4 },{1, clr_f0 },{2, jni },{0, illegal },
|
539 |
|
|
{2, orl_bus_n },{2, orl_p1_n },{2, orl_p2_n },{0, illegal },{2, orld_p4_a },{2, orld_p5_a },{2, orld_p6_a },{2, orld_p7_a },
|
540 |
|
|
{2, movx_xr0_a },{2, movx_xr1_a },{2, jb_4 },{2, retr },{2, call_4 },{1, cpl_f0 },{2, jnz },{1, clr_c },
|
541 |
|
|
{2, anl_bus_n },{2, anl_p1_n },{2, anl_p2_n },{0, illegal },{2, anld_p4_a },{2, anld_p5_a },{2, anld_p6_a },{2, anld_p7_a },
|
542 |
|
|
{1, mov_xr0_a },{1, mov_xr1_a },{0, illegal },{2, movp_a_xa },{2, jmp_5 },{1, clr_f1 },{0, illegal },{1, cpl_c },
|
543 |
|
|
{1, mov_r0_a },{1, mov_r1_a },{1, mov_r2_a },{1, mov_r3_a },{1, mov_r4_a },{1, mov_r5_a },{1, mov_r6_a },{1, mov_r7_a },
|
544 |
|
|
{2, mov_xr0_n },{2, mov_xr1_n },{2, jb_5 },{2, jmpp_xa },{2, call_5 },{1, cpl_f1 },{2, jf0 },{0, illegal },
|
545 |
|
|
{2, mov_r0_n },{2, mov_r1_n },{2, mov_r2_n },{2, mov_r3_n },{2, mov_r4_n },{2, mov_r5_n },{2, mov_r6_n },{2, mov_r7_n },
|
546 |
|
|
{0, illegal },{0, illegal },{0, illegal },{0, illegal },{2, jmp_6 },{1, sel_rb0 },{2, jz },{1, mov_a_psw },
|
547 |
|
|
{1, dec_r0 },{1, dec_r1 },{1, dec_r2 },{1, dec_r3 },{1, dec_r4 },{1, dec_r5 },{1, dec_r6 },{1, dec_r7 },
|
548 |
|
|
{1, xrl_a_xr0 },{1, xrl_a_xr1 },{2, jb_6 },{2, xrl_a_n },{2, call_6 },{1, sel_rb1 },{0, illegal },{1, mov_psw_a },
|
549 |
|
|
{1, xrl_a_r0 },{1, xrl_a_r1 },{1, xrl_a_r2 },{1, xrl_a_r3 },{1, xrl_a_r4 },{1, xrl_a_r5 },{1, xrl_a_r6 },{1, xrl_a_r7 },
|
550 |
|
|
{0, illegal },{0, illegal },{0, illegal },{2, movp3_a_xa },{2, jmp_7 },{1, sel_mb0 },{2, jnc },{1, rl_a },
|
551 |
|
|
{2, djnz_r0 },{2, djnz_r1 },{2, djnz_r2 },{2, djnz_r3 },{2, djnz_r4 },{2, djnz_r5 },{2, djnz_r6 },{2, djnz_r7 },
|
552 |
|
|
{1, mov_a_xr0 },{1, mov_a_xr1 },{2, jb_7 },{0, illegal },{2, call_7 },{1, sel_mb1 },{2, jc },{1, rlc_a },
|
553 |
|
|
{1, mov_a_r0 },{1, mov_a_r1 },{1, mov_a_r2 },{1, mov_a_r3 },{1, mov_a_r4 },{1, mov_a_r5 },{1, mov_a_r6 },{1, mov_a_r7 }
|
554 |
|
|
};
|
555 |
|
|
|
556 |
|
|
|
557 |
|
|
/****************************************************************************
|
558 |
|
|
* Reset registers to their initial values
|
559 |
|
|
****************************************************************************/
|
560 |
|
|
void i8039_reset (void *param)
|
561 |
|
|
{
|
562 |
|
|
R.PC.w.l = 0;
|
563 |
|
|
R.SP = 0;
|
564 |
|
|
R.A = 0;
|
565 |
|
|
R.PSW = 0x08; /* Start with Carry SET, Bit 4 is always SET */
|
566 |
|
|
memset(R.RAM, 0x0, 128);
|
567 |
|
|
R.P1 = 0xff;
|
568 |
|
|
R.P2 = 0xff;
|
569 |
|
|
R.bus = 0;
|
570 |
|
|
R.irq_executing = I8039_NO_INT;
|
571 |
|
|
R.pending_irq = I8039_NO_INT;
|
572 |
|
|
|
573 |
|
|
R.A11ff = R.A11 = 0;
|
574 |
|
|
R.tirq_en = R.xirq_en = 0;
|
575 |
|
|
R.timerON = R.countON = 0;
|
576 |
|
|
R.timerON = 1; /* Mario Bros. doesn't work without this */
|
577 |
|
|
R.irq_extra_cycles = 0;
|
578 |
|
|
R.masterClock = 0;
|
579 |
|
|
|
580 |
|
|
/* print dump header */
|
581 |
|
|
printf(" Addr | Instruction | PC Accu SP PSW BUS F1 P1 P2 A11 RAM\n");
|
582 |
|
|
printf(" ------+--------------------+---------------------------------------\n");
|
583 |
|
|
}
|
584 |
|
|
|
585 |
|
|
|
586 |
|
|
/****************************************************************************
|
587 |
|
|
* Shut down CPU emulation
|
588 |
|
|
****************************************************************************/
|
589 |
|
|
static void i8039_exit (void)
|
590 |
|
|
{
|
591 |
|
|
/* nothing to do ? */
|
592 |
|
|
}
|
593 |
|
|
|
594 |
|
|
/****************************************************************************
|
595 |
|
|
* Issue an interrupt if necessary
|
596 |
|
|
****************************************************************************/
|
597 |
|
|
static int Ext_IRQ(void)
|
598 |
|
|
{
|
599 |
|
|
int extra_cycles = 0;
|
600 |
|
|
|
601 |
|
|
if (R.xirq_en) {
|
602 |
|
|
if (R.irq_executing == I8039_NO_INT) {
|
603 |
|
|
/* logerror("I8039: EXT INTERRUPT being serviced\n"); */
|
604 |
|
|
R.irq_executing = I8039_EXTERNAL_INT;
|
605 |
|
|
push(R.PC.b.l);
|
606 |
|
|
push((R.PC.b.h & 0x0f) | (R.PSW & 0xf0));
|
607 |
|
|
R.PC.w.l = 0x03;
|
608 |
|
|
R.A11ff = R.A11;
|
609 |
|
|
R.A11 = 0;
|
610 |
|
|
|
611 |
|
|
extra_cycles = 2; /* 2 clock cycles used */
|
612 |
|
|
|
613 |
|
|
if (R.timerON) /* NS990113 */
|
614 |
|
|
R.masterClock += extra_cycles;
|
615 |
|
|
if (R.irq_callback) (*R.irq_callback)(0);
|
616 |
|
|
}
|
617 |
|
|
}
|
618 |
|
|
|
619 |
|
|
return extra_cycles;
|
620 |
|
|
}
|
621 |
|
|
|
622 |
|
|
static int Timer_IRQ(void)
|
623 |
|
|
{
|
624 |
|
|
int extra_cycles = 0;
|
625 |
|
|
|
626 |
|
|
if (R.tirq_en) {
|
627 |
|
|
if (R.irq_executing == I8039_NO_INT) {
|
628 |
|
|
/* logerror("I8039: TIMER/COUNTER INTERRUPT\n"); */
|
629 |
|
|
R.irq_executing = I8039_TIMCNT_INT;
|
630 |
|
|
R.pending_irq &= ~I8039_TIMCNT_INT;
|
631 |
|
|
push(R.PC.b.l);
|
632 |
|
|
push((R.PC.b.h & 0x0f) | (R.PSW & 0xf0));
|
633 |
|
|
R.PC.w.l = 0x07;
|
634 |
|
|
R.A11ff = R.A11;
|
635 |
|
|
R.A11 = 0;
|
636 |
|
|
|
637 |
|
|
extra_cycles = 2; /* 2 clock cycles used */
|
638 |
|
|
|
639 |
|
|
if (R.timerON) /* NS990113 */
|
640 |
|
|
R.masterClock += extra_cycles;
|
641 |
|
|
}
|
642 |
|
|
else {
|
643 |
|
|
if (R.irq_executing == I8039_EXTERNAL_INT) {
|
644 |
|
|
R.pending_irq |= I8039_TIMCNT_INT;
|
645 |
|
|
}
|
646 |
|
|
}
|
647 |
|
|
}
|
648 |
|
|
|
649 |
|
|
R.t_flag = 1;
|
650 |
|
|
|
651 |
|
|
return extra_cycles;
|
652 |
|
|
}
|
653 |
|
|
|
654 |
|
|
|
655 |
|
|
static void dump_machine_state(void)
|
656 |
|
|
{
|
657 |
|
|
int i;
|
658 |
|
|
|
659 |
52 |
arniml |
printf(" | %04X %02X %02X %02X", (UINT32)R.PC.w.l, (UINT32)R.A, (UINT32)(R.SP >> 1), (UINT32)R.PSW);
|
660 |
49 |
arniml |
printf(" %02X %X %02X %02X", (UINT32)R.bus, (UINT32)R.f1, (UINT32)R.P1, (UINT32)R.P2);
|
661 |
|
|
printf(" %X ", (UINT32)(R.A11 >> 11));
|
662 |
|
|
|
663 |
|
|
for (i = 0; i < 256; i++)
|
664 |
|
|
printf(" %02X", R.RAM[i]);
|
665 |
|
|
|
666 |
|
|
printf("\n");
|
667 |
|
|
}
|
668 |
|
|
|
669 |
|
|
|
670 |
|
|
enum {ACCU_IDLE, ACCU_HAS_AA, ACCU_HAS_55, ACCU_PASS, ACCU_FAIL};
|
671 |
|
|
|
672 |
|
|
/****************************************************************************
|
673 |
|
|
* Execute cycles CPU cycles. Return number of cycles really executed
|
674 |
|
|
****************************************************************************/
|
675 |
|
|
int i8039_execute(int cycles, int dump)
|
676 |
|
|
{
|
677 |
|
|
unsigned opcode, T1;
|
678 |
|
|
int count, i;
|
679 |
|
|
char buffer[64];
|
680 |
|
|
char string[32];
|
681 |
|
|
|
682 |
|
|
static int accu = 0;
|
683 |
|
|
static int accu_state = ACCU_IDLE;
|
684 |
|
|
|
685 |
|
|
i8039_ICount = (cycles - R.irq_extra_cycles);
|
686 |
|
|
R.irq_extra_cycles = 0;
|
687 |
|
|
|
688 |
|
|
if ((accu_state == ACCU_PASS) || (accu_state == ACCU_FAIL)) {
|
689 |
|
|
printf("End of simulation detected\n");
|
690 |
|
|
|
691 |
|
|
return(accu_state == ACCU_PASS ? 0 : -1);
|
692 |
|
|
}
|
693 |
|
|
|
694 |
|
|
do
|
695 |
|
|
{
|
696 |
|
|
R.PREVPC = R.PC;
|
697 |
|
|
|
698 |
|
|
|
699 |
|
|
opcode=M_RDOP(R.PC.w.l);
|
700 |
|
|
|
701 |
|
|
buffer[0] = '\0';
|
702 |
|
|
Dasm8039(buffer, R.PC.w.l);
|
703 |
|
|
sprintf(string, " %04X : %s", R.PC.w.l, buffer);
|
704 |
|
|
for (i = strlen(string); i < 26; i++)
|
705 |
|
|
string[i] = ' ';
|
706 |
|
|
string[i <= 31 ? i : 31] = '\0';
|
707 |
|
|
printf("%s", string);
|
708 |
|
|
|
709 |
|
|
/* logerror("I8039: PC = %04x, opcode = %02x\n", R.PC.w.l, opcode); */
|
710 |
|
|
|
711 |
|
|
R.PC.w.l++;
|
712 |
|
|
inst_cycles = opcode_main[opcode].cycles;
|
713 |
|
|
(*(opcode_main[opcode].function))();
|
714 |
|
|
i8039_ICount -= inst_cycles; /*/ */
|
715 |
|
|
|
716 |
|
|
if (dump == 1) {
|
717 |
|
|
/* dump machine state information */
|
718 |
|
|
dump_machine_state();
|
719 |
|
|
} else
|
720 |
|
|
printf("\n");
|
721 |
|
|
|
722 |
|
|
/* end-of-simulation check */
|
723 |
|
|
if (accu != R.A) {
|
724 |
|
|
accu = R.A;
|
725 |
|
|
|
726 |
|
|
switch (accu_state) {
|
727 |
|
|
case ACCU_IDLE:
|
728 |
|
|
accu_state = accu == 0xaa ? ACCU_HAS_AA : ACCU_IDLE;
|
729 |
|
|
break;
|
730 |
|
|
|
731 |
|
|
case ACCU_HAS_AA:
|
732 |
|
|
accu_state = accu == 0x55 ? ACCU_HAS_55 : ACCU_IDLE;
|
733 |
|
|
break;
|
734 |
|
|
|
735 |
|
|
case ACCU_HAS_55:
|
736 |
74 |
arniml |
switch (accu) {
|
737 |
|
|
case 0x01:
|
738 |
|
|
accu_state = ACCU_PASS;
|
739 |
|
|
break;
|
740 |
|
|
case 0x00:
|
741 |
|
|
accu_state = ACCU_FAIL;
|
742 |
|
|
break;
|
743 |
|
|
default:
|
744 |
|
|
accu_state = ACCU_IDLE;
|
745 |
|
|
break;
|
746 |
|
|
}
|
747 |
49 |
arniml |
break;
|
748 |
|
|
|
749 |
|
|
case ACCU_PASS:
|
750 |
|
|
case ACCU_FAIL:
|
751 |
|
|
break;
|
752 |
|
|
|
753 |
|
|
default:
|
754 |
|
|
accu_state = ACCU_IDLE;
|
755 |
|
|
break;
|
756 |
|
|
}
|
757 |
|
|
}
|
758 |
|
|
|
759 |
|
|
|
760 |
|
|
|
761 |
|
|
|
762 |
|
|
if (R.countON) /* NS990113 */
|
763 |
|
|
{
|
764 |
|
|
for ( ; inst_cycles > 0; inst_cycles-- )
|
765 |
|
|
{
|
766 |
|
|
T1 = test_r(1);
|
767 |
|
|
if (POSITIVE_EDGE_T1)
|
768 |
|
|
{
|
769 |
|
|
R.timer++;
|
770 |
|
|
if (R.timer == 0) {
|
771 |
|
|
count = Timer_IRQ(); /* Handle Counter IRQ */
|
772 |
|
|
i8039_ICount -= count;
|
773 |
|
|
}
|
774 |
|
|
}
|
775 |
|
|
Old_T1 = T1;
|
776 |
|
|
}
|
777 |
|
|
}
|
778 |
|
|
|
779 |
|
|
if (R.timerON) {
|
780 |
|
|
R.masterClock += opcode_main[opcode].cycles;
|
781 |
|
|
if (R.masterClock >= 32) { /* NS990113 */
|
782 |
|
|
R.masterClock -= 32;
|
783 |
|
|
R.timer++;
|
784 |
|
|
if (R.timer == 0) {
|
785 |
|
|
count = Timer_IRQ(); /* Handle Timer IRQ */
|
786 |
|
|
i8039_ICount -= count;
|
787 |
|
|
}
|
788 |
|
|
}
|
789 |
|
|
}
|
790 |
|
|
} while (i8039_ICount > 0 && accu_state != ACCU_PASS && accu_state != ACCU_FAIL);
|
791 |
|
|
|
792 |
|
|
i8039_ICount -= R.irq_extra_cycles;
|
793 |
|
|
R.irq_extra_cycles = 0;
|
794 |
|
|
|
795 |
|
|
return cycles - i8039_ICount;
|
796 |
|
|
}
|
797 |
|
|
|
798 |
|
|
/****************************************************************************
|
799 |
|
|
* Get all registers in given buffer
|
800 |
|
|
****************************************************************************/
|
801 |
|
|
static void i8039_get_context (void *dst)
|
802 |
|
|
{
|
803 |
|
|
if( dst )
|
804 |
|
|
*(I8039_Regs*)dst = R;
|
805 |
|
|
}
|
806 |
|
|
|
807 |
|
|
|
808 |
|
|
/****************************************************************************
|
809 |
|
|
* Set all registers to given values
|
810 |
|
|
****************************************************************************/
|
811 |
|
|
static void i8039_set_context (void *src)
|
812 |
|
|
{
|
813 |
|
|
if( src )
|
814 |
|
|
{
|
815 |
|
|
R = *(I8039_Regs*)src;
|
816 |
|
|
regPTR = ((M_By) ? 24 : 0);
|
817 |
|
|
R.SP = (R.PSW << 1) & 0x0f;
|
818 |
|
|
}
|
819 |
|
|
/* Handle forced Interrupts throught the Debugger */
|
820 |
|
|
if (R.irq_state != I8039_NO_INT) {
|
821 |
|
|
R.irq_extra_cycles += Ext_IRQ(); /* Handle External IRQ */
|
822 |
|
|
}
|
823 |
|
|
if (R.timer == 0) {
|
824 |
|
|
R.irq_extra_cycles += Timer_IRQ(); /* Handle Timer IRQ */
|
825 |
|
|
}
|
826 |
|
|
}
|
827 |
|
|
|
828 |
|
|
|
829 |
|
|
/****************************************************************************
|
830 |
|
|
* Set IRQ line state
|
831 |
|
|
****************************************************************************/
|
832 |
58 |
arniml |
void set_irq_line(int irqline, int state)
|
833 |
49 |
arniml |
{
|
834 |
|
|
if (state != CLEAR_LINE) {
|
835 |
|
|
R.irq_state = I8039_EXTERNAL_INT;
|
836 |
|
|
R.irq_extra_cycles += Ext_IRQ(); /* Handle External IRQ */
|
837 |
|
|
}
|
838 |
|
|
else {
|
839 |
|
|
R.irq_state = I8039_NO_INT;
|
840 |
|
|
}
|
841 |
|
|
}
|