URL
https://opencores.org/ocsvn/t48/t48/trunk
Subversion Repositories t48
Compare Revisions
- This comparison shows the changes necessary to convert path
/t48/tags/rel_1_1/sw/i8039emu
- from Rev 289 to Rev 292
- ↔ Reverse comparison
Rev 289 → Rev 292
/i8039.c
0,0 → 1,841
/**************************************************************************** |
* Intel 8039 Portable Emulator * |
* * |
* Copyright (C) 1997 by Mirko Buffoni * |
* Based on the original work (C) 1997 by Dan Boris, an 8048 emulator * |
* You are not allowed to distribute this software commercially * |
* Please, notify me, if you make any changes to this file * |
* * |
* Adapted for the T48 uController project, 2004 by Arnim Laeuger * |
* See http://www.opencores.org/projects.cgi/web/t48/overview * |
* * |
* $Id: i8039.c,v 1.7 2004-07-04 12:06:53 arniml Exp $ |
* * |
* **** Change Log **** * |
* * |
* TLP (19-Jun-2001) * |
* - Changed Ports 1 and 2 to quasi bidirectional output latched ports * |
* - Added the Port 1 & 2 output latch data to the debugger window * |
* TLP (02-Jan-2002) * |
* - External IRQs no longer go pending (sampled as a level state) * |
* - Timer IRQs do not go pending if Timer interrupts are disabled * |
* - Timer IRQs made pending, were incorrectly being cleared if the * |
* external interrupt was being serviced * |
* - External interrupts now take precedence when simultaneous * |
* internal and external interrupt requests occur * |
* - 'DIS TCNTI' now removes pending timer IRQs * |
* - Nested IRQs of any sort are no longer allowed * |
* - T_flag was not being set in the right place of execution, which * |
* could have lead to it being incorrectly set after being cleared * |
* - Counter overflows now also set the T_flag * |
* - Added the Timer/Counter register to the debugger window * |
* TLP (09-Jan-2002) * |
* - Changed Interrupt system to instant servicing * |
* - The Timer and Counter can no longer be 'on' simultaneously * |
* - Added Save State * |
* TLP (15-Feb-2002) * |
* - Corrected Positive signal edge sensing (used on the T1 input) * |
****************************************************************************/ |
|
|
#include <stdio.h> |
#include <string.h> |
#include <stdlib.h> |
|
#include "i8039.h" |
|
|
/*** Cycle times for the jump on condition instructions, are unusual. |
Condition is tested during the first cycle, so if condition is not |
met, second address fetch cycle may not really be taken. For now we |
just use the cycle counts as listed in the i8048 user manual. |
***/ |
|
#if 0 |
#define ADJUST_CYCLES { inst_cycles -= 1; } /* Possible real cycles setting */ |
#else |
#define ADJUST_CYCLES { } /* User Manual cycles setting */ |
#endif |
|
|
|
/* HJB 01/05/99 changed to positive values to use pending_irq as a flag */ |
#define I8039_NO_INT 0 /* No Interrupts pending or executing */ |
#define I8039_EXTERNAL_INT 1 /* Execute a normal external interrupt */ |
#define I8039_TIMCNT_INT 2 /* Execute a Timer/Counter interrupt */ |
|
|
/* Layout of the registers in the debugger */ |
static UINT8 i8039_reg_layout[] = { |
I8039_PC, I8039_SP, I8039_PSW, I8039_A, I8039_TC, I8039_P1, I8039_P2, -1, |
I8039_R0, I8039_R1, I8039_R2, I8039_R3, I8039_R4, I8039_R5, I8039_R6, I8039_R7, 0 |
}; |
|
/* Layout of the debugger windows x,y,w,h */ |
static UINT8 i8039_win_layout[] = { |
0, 0,80, 2, /* register window (top rows) */ |
0, 3,24,19, /* disassembler window (left colums) */ |
25, 3,55, 9, /* memory #1 window (right, upper middle) */ |
25,13,55, 9, /* memory #2 window (right, lower middle) */ |
0,23,80, 1, /* command line window (bottom rows) */ |
}; |
|
|
static int Ext_IRQ(void); |
static int Timer_IRQ(void); |
|
#define M_RDMEM(A) I8039_RDMEM(A) |
#define M_RDOP(A) I8039_RDOP(A) |
#define M_RDOP_ARG(A) I8039_RDOP_ARG(A) |
#define M_IN(A) I8039_In(A) |
#define M_OUT(A,V) I8039_Out(A,V) |
|
#define port_r(A) I8039_In(I8039_p0 + A) |
#define port_w(A,V) I8039_Out(I8039_p0 + A,V) |
#define test_r(A) I8039_In(I8039_t0 + A) |
#define test_w(A,V) I8039_Out(I8039_t0 + A,V) |
#define bus_r() I8039_In(I8039_bus) |
#define bus_w(V) I8039_Out(I8039_bus,V) |
|
#define C_FLAG 0x80 |
#define A_FLAG 0x40 |
#define F_FLAG 0x20 |
#define B_FLAG 0x10 |
|
typedef struct |
{ |
PAIR PREVPC; /* previous program counter */ |
PAIR PC; /* program counter */ |
UINT8 A, SP, PSW; |
UINT8 RAM[256]; |
UINT8 bus, f1; /* Bus data, and flag1 */ |
UINT8 P1, P2; /* Internal Port 1 and 2 latched outputs */ |
|
UINT8 pending_irq, irq_executing, masterClock, regPtr; |
UINT8 t_flag, timer, timerON, countON, xirq_en, tirq_en; |
UINT16 A11, A11ff; |
UINT8 irq_state, irq_extra_cycles; |
int (*irq_callback)(int irqline); |
} I8039_Regs; |
|
static I8039_Regs R; |
int i8039_ICount; |
int inst_cycles; |
static UINT8 Old_T1; |
|
/* The opcode table now is a combination of cycle counts and function pointers */ |
typedef struct { |
unsigned cycles; |
void (*function) (void); |
} s_opcode; |
|
#define POSITIVE_EDGE_T1 (( (int)(T1-Old_T1) > 0) ? 1 : 0) |
#define NEGATIVE_EDGE_T1 (( (int)(Old_T1-T1) > 0) ? 1 : 0) |
|
#define M_Cy ((R.PSW & C_FLAG) >> 7) |
#define M_Cn (!M_Cy) |
#define M_Ay ((R.PSW & A_FLAG)) |
#define M_An (!M_Ay) |
#define M_F0y ((R.PSW & F_FLAG)) |
#define M_F0n (!M_F0y) |
#define M_By ((R.PSW & B_FLAG)) |
#define M_Bn (!M_By) |
|
#define intRAM R.RAM |
#define regPTR R.regPtr |
|
#define R0 intRAM[regPTR ] |
#define R1 intRAM[regPTR+1] |
#define R2 intRAM[regPTR+2] |
#define R3 intRAM[regPTR+3] |
#define R4 intRAM[regPTR+4] |
#define R5 intRAM[regPTR+5] |
#define R6 intRAM[regPTR+6] |
#define R7 intRAM[regPTR+7] |
|
|
INLINE void CLR (UINT8 flag) { R.PSW &= ~flag; } |
INLINE void SET (UINT8 flag) { R.PSW |= flag; } |
|
|
/* Get next opcode argument and increment program counter */ |
INLINE unsigned M_RDMEM_OPCODE (void) |
{ |
unsigned retval; |
retval=M_RDOP_ARG(R.PC.w.l); |
R.PC.w.l++; |
return retval; |
} |
|
INLINE void push(UINT8 d) |
{ |
intRAM[8+R.SP++] = d; |
R.SP = R.SP & 0x0f; |
R.PSW = R.PSW & 0xf8; |
R.PSW = R.PSW | (R.SP >> 1); |
} |
|
INLINE UINT8 pull(void) { |
R.SP = (R.SP + 15) & 0x0f; /* if (--R.SP < 0) R.SP = 15; */ |
R.PSW = R.PSW & 0xf8; |
R.PSW = R.PSW | (R.SP >> 1); |
/* regPTR = ((M_By) ? 24 : 0); regPTR should not change */ |
return intRAM[8+R.SP]; |
} |
|
INLINE void daa_a(void) |
{ |
if ((R.A & 0x0f) > 0x09 || (R.PSW & A_FLAG)) |
R.A += 0x06; |
if ((R.A & 0xf0) > 0x90 || (R.PSW & C_FLAG)) |
{ |
R.A += 0x60; |
SET(C_FLAG); |
} else CLR(C_FLAG); |
} |
|
INLINE void M_ADD(UINT8 dat) |
{ |
UINT16 temp; |
|
CLR(C_FLAG | A_FLAG); |
if ((R.A & 0xf) + (dat & 0xf) > 0xf) SET(A_FLAG); |
temp = R.A + dat; |
if (temp > 0xff) SET(C_FLAG); |
R.A = temp & 0xff; |
} |
|
INLINE void M_ADDC(UINT8 dat) |
{ |
UINT16 temp; |
|
CLR(A_FLAG); |
if ((R.A & 0xf) + (dat & 0xf) + M_Cy > 0xf) SET(A_FLAG); |
temp = R.A + dat + M_Cy; |
CLR(C_FLAG); |
if (temp > 0xff) SET(C_FLAG); |
R.A = temp & 0xff; |
} |
|
INLINE void M_CALL(UINT16 addr) |
{ |
push(R.PC.b.l); |
push((R.PC.b.h & 0x0f) | (R.PSW & 0xf0)); |
R.PC.w.l = addr; |
|
} |
|
INLINE void M_XCHD(UINT8 addr) |
{ |
UINT8 dat = R.A & 0x0f; |
R.A &= 0xf0; |
R.A |= intRAM[addr] & 0x0f; |
intRAM[addr] &= 0xf0; |
intRAM[addr] |= dat; |
} |
|
|
INLINE void M_ILLEGAL(void) |
{ |
logerror("I8039: PC = %04x, Illegal opcode = %02x\n", R.PC.w.l-1, M_RDMEM(R.PC.w.l-1)); |
} |
|
INLINE void M_UNDEFINED(void) |
{ |
logerror("I8039: PC = %04x, Unimplemented opcode = %02x\n", R.PC.w.l-1, M_RDMEM(R.PC.w.l-1)); |
} |
|
#define INT_RAM_MASK 0xff |
|
static void illegal(void) { M_ILLEGAL(); } |
|
static void add_a_n(void) { M_ADD(M_RDMEM_OPCODE()); } |
static void add_a_r0(void) { M_ADD(R0); } |
static void add_a_r1(void) { M_ADD(R1); } |
static void add_a_r2(void) { M_ADD(R2); } |
static void add_a_r3(void) { M_ADD(R3); } |
static void add_a_r4(void) { M_ADD(R4); } |
static void add_a_r5(void) { M_ADD(R5); } |
static void add_a_r6(void) { M_ADD(R6); } |
static void add_a_r7(void) { M_ADD(R7); } |
static void add_a_xr0(void) { M_ADD(intRAM[R0 & INT_RAM_MASK]); } |
static void add_a_xr1(void) { M_ADD(intRAM[R1 & INT_RAM_MASK]); } |
static void adc_a_n(void) { M_ADDC(M_RDMEM_OPCODE()); } |
static void adc_a_r0(void) { M_ADDC(R0); } |
static void adc_a_r1(void) { M_ADDC(R1); } |
static void adc_a_r2(void) { M_ADDC(R2); } |
static void adc_a_r3(void) { M_ADDC(R3); } |
static void adc_a_r4(void) { M_ADDC(R4); } |
static void adc_a_r5(void) { M_ADDC(R5); } |
static void adc_a_r6(void) { M_ADDC(R6); } |
static void adc_a_r7(void) { M_ADDC(R7); } |
static void adc_a_xr0(void) { M_ADDC(intRAM[R0 & INT_RAM_MASK]); } |
static void adc_a_xr1(void) { M_ADDC(intRAM[R1 & INT_RAM_MASK]); } |
static void anl_a_n(void) { R.A &= M_RDMEM_OPCODE(); } |
static void anl_a_r0(void) { R.A &= R0; } |
static void anl_a_r1(void) { R.A &= R1; } |
static void anl_a_r2(void) { R.A &= R2; } |
static void anl_a_r3(void) { R.A &= R3; } |
static void anl_a_r4(void) { R.A &= R4; } |
static void anl_a_r5(void) { R.A &= R5; } |
static void anl_a_r6(void) { R.A &= R6; } |
static void anl_a_r7(void) { R.A &= R7; } |
static void anl_a_xr0(void) { R.A &= intRAM[R0 & INT_RAM_MASK]; } |
static void anl_a_xr1(void) { R.A &= intRAM[R1 & INT_RAM_MASK]; } |
static void anl_bus_n(void) { bus_w( bus_r() & M_RDMEM_OPCODE() ); } |
static void anl_p1_n(void) { R.P1 &= M_RDMEM_OPCODE(); port_w( 1, R.P1 ); } |
static void anl_p2_n(void) { R.P2 &= M_RDMEM_OPCODE(); port_w( 2, R.P2 ); } |
static void anld_p4_a(void) { port_w( 4, port_r(4) & M_RDMEM_OPCODE() ); } |
static void anld_p5_a(void) { port_w( 5, port_r(5) & M_RDMEM_OPCODE() ); } |
static void anld_p6_a(void) { port_w( 6, port_r(6) & M_RDMEM_OPCODE() ); } |
static void anld_p7_a(void) { port_w( 7, port_r(7) & M_RDMEM_OPCODE() ); } |
static void call(void) { UINT8 i=M_RDMEM_OPCODE(); M_CALL(i | R.A11); } |
static void call_1(void) { UINT8 i=M_RDMEM_OPCODE(); M_CALL(i | 0x100 | R.A11); } |
static void call_2(void) { UINT8 i=M_RDMEM_OPCODE(); M_CALL(i | 0x200 | R.A11); } |
static void call_3(void) { UINT8 i=M_RDMEM_OPCODE(); M_CALL(i | 0x300 | R.A11); } |
static void call_4(void) { UINT8 i=M_RDMEM_OPCODE(); M_CALL(i | 0x400 | R.A11); } |
static void call_5(void) { UINT8 i=M_RDMEM_OPCODE(); M_CALL(i | 0x500 | R.A11); } |
static void call_6(void) { UINT8 i=M_RDMEM_OPCODE(); M_CALL(i | 0x600 | R.A11); } |
static void call_7(void) { UINT8 i=M_RDMEM_OPCODE(); M_CALL(i | 0x700 | R.A11); } |
static void clr_a(void) { R.A=0; } |
static void clr_c(void) { CLR(C_FLAG); } |
static void clr_f0(void) { CLR(F_FLAG); } |
static void clr_f1(void) { R.f1 = 0; } |
static void cpl_a(void) { R.A ^= 0xff; } |
static void cpl_c(void) { R.PSW ^= C_FLAG; } |
static void cpl_f0(void) { R.PSW ^= F_FLAG; } |
static void cpl_f1(void) { R.f1 ^= 1; } |
static void dec_a(void) { R.A--; } |
static void dec_r0(void) { R0--; } |
static void dec_r1(void) { R1--; } |
static void dec_r2(void) { R2--; } |
static void dec_r3(void) { R3--; } |
static void dec_r4(void) { R4--; } |
static void dec_r5(void) { R5--; } |
static void dec_r6(void) { R6--; } |
static void dec_r7(void) { R7--; } |
static void dis_i(void) { R.xirq_en = 0; } |
static void dis_tcnti(void) { R.tirq_en = 0; R.pending_irq &= ~I8039_TIMCNT_INT; } |
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 } |
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 } |
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 } |
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 } |
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 } |
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 } |
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 } |
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 } |
static void en_i(void) { R.xirq_en = 1; if (R.irq_state == I8039_EXTERNAL_INT) { R.irq_extra_cycles += Ext_IRQ(); } } |
static void en_tcnti(void) { R.tirq_en = 1; } |
static void ento_clk(void) { M_UNDEFINED(); } |
static void in_a_p1(void) { R.A = port_r(1) & R.P1; } |
static void in_a_p2(void) { R.A = port_r(2) & R.P2; } |
static void ins_a_bus(void) { R.A = bus_r(); } |
static void inc_a(void) { R.A++; } |
static void inc_r0(void) { R0++; } |
static void inc_r1(void) { R1++; } |
static void inc_r2(void) { R2++; } |
static void inc_r3(void) { R3++; } |
static void inc_r4(void) { R4++; } |
static void inc_r5(void) { R5++; } |
static void inc_r6(void) { R6++; } |
static void inc_r7(void) { R7++; } |
static void inc_xr0(void) { intRAM[R0 & INT_RAM_MASK]++; } |
static void inc_xr1(void) { intRAM[R1 & INT_RAM_MASK]++; } |
|
/* static void jmp(void) { UINT8 i=M_RDOP(R.PC.w.l); R.PC.w.l = i | R.A11; } |
*/ |
|
static void jmp(void) |
{ |
UINT8 i=M_RDOP(R.PC.w.l); |
UINT16 oldpc,newpc; |
|
oldpc = R.PC.w.l-1; |
R.PC.w.l = i | R.A11; |
newpc = R.PC.w.l; |
if (newpc == oldpc) { if (i8039_ICount > 0) i8039_ICount = 0; } /* speed up busy loop */ |
else if (newpc == oldpc-1 && M_RDOP(newpc) == 0x00) /* NOP - Gyruss */ |
{ if (i8039_ICount > 0) i8039_ICount = 0; } |
} |
|
static void jmp_1(void) { UINT8 i=M_RDOP(R.PC.w.l); R.PC.w.l = i | 0x100 | R.A11; } |
static void jmp_2(void) { UINT8 i=M_RDOP(R.PC.w.l); R.PC.w.l = i | 0x200 | R.A11; } |
static void jmp_3(void) { UINT8 i=M_RDOP(R.PC.w.l); R.PC.w.l = i | 0x300 | R.A11; } |
static void jmp_4(void) { UINT8 i=M_RDOP(R.PC.w.l); R.PC.w.l = i | 0x400 | R.A11; } |
static void jmp_5(void) { UINT8 i=M_RDOP(R.PC.w.l); R.PC.w.l = i | 0x500 | R.A11; } |
static void jmp_6(void) { UINT8 i=M_RDOP(R.PC.w.l); R.PC.w.l = i | 0x600 | R.A11; } |
static void jmp_7(void) { UINT8 i=M_RDOP(R.PC.w.l); R.PC.w.l = i | 0x700 | R.A11; } |
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); } |
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 } |
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 } |
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 } |
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 } |
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 } |
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 } |
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 } |
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 } |
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 } |
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 } |
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 } |
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 } |
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 } |
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 } |
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 } |
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 } |
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 } |
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 } |
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 } |
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 } |
|
static void mov_a_n(void) { R.A = M_RDMEM_OPCODE(); } |
static void mov_a_r0(void) { R.A = R0; } |
static void mov_a_r1(void) { R.A = R1; } |
static void mov_a_r2(void) { R.A = R2; } |
static void mov_a_r3(void) { R.A = R3; } |
static void mov_a_r4(void) { R.A = R4; } |
static void mov_a_r5(void) { R.A = R5; } |
static void mov_a_r6(void) { R.A = R6; } |
static void mov_a_r7(void) { R.A = R7; } |
static void mov_a_psw(void) { R.A = R.PSW | 0x08; } |
static void mov_a_xr0(void) { R.A = intRAM[R0 & INT_RAM_MASK]; } |
static void mov_a_xr1(void) { R.A = intRAM[R1 & INT_RAM_MASK]; } |
static void mov_r0_a(void) { R0 = R.A; } |
static void mov_r1_a(void) { R1 = R.A; } |
static void mov_r2_a(void) { R2 = R.A; } |
static void mov_r3_a(void) { R3 = R.A; } |
static void mov_r4_a(void) { R4 = R.A; } |
static void mov_r5_a(void) { R5 = R.A; } |
static void mov_r6_a(void) { R6 = R.A; } |
static void mov_r7_a(void) { R7 = R.A; } |
static void mov_psw_a(void) { R.PSW = R.A | 0x08; regPTR = ((M_By) ? 24 : 0); R.SP = (R.PSW & 7) << 1; } |
static void mov_r0_n(void) { R0 = M_RDMEM_OPCODE(); } |
static void mov_r1_n(void) { R1 = M_RDMEM_OPCODE(); } |
static void mov_r2_n(void) { R2 = M_RDMEM_OPCODE(); } |
static void mov_r3_n(void) { R3 = M_RDMEM_OPCODE(); } |
static void mov_r4_n(void) { R4 = M_RDMEM_OPCODE(); } |
static void mov_r5_n(void) { R5 = M_RDMEM_OPCODE(); } |
static void mov_r6_n(void) { R6 = M_RDMEM_OPCODE(); } |
static void mov_r7_n(void) { R7 = M_RDMEM_OPCODE(); } |
static void mov_a_t(void) { R.A = R.timer; } |
static void mov_t_a(void) { R.timer = R.A; } |
static void mov_xr0_a(void) { intRAM[R0 & INT_RAM_MASK] = R.A; } |
static void mov_xr1_a(void) { intRAM[R1 & INT_RAM_MASK] = R.A; } |
static void mov_xr0_n(void) { intRAM[R0 & INT_RAM_MASK] = M_RDMEM_OPCODE(); } |
static void mov_xr1_n(void) { intRAM[R1 & INT_RAM_MASK] = M_RDMEM_OPCODE(); } |
static void movd_a_p4(void) { R.A = port_r(4); } |
static void movd_a_p5(void) { R.A = port_r(5); } |
static void movd_a_p6(void) { R.A = port_r(6); } |
static void movd_a_p7(void) { R.A = port_r(7); } |
static void movd_p4_a(void) { port_w(4, R.A); } |
static void movd_p5_a(void) { port_w(5, R.A); } |
static void movd_p6_a(void) { port_w(6, R.A); } |
static void movd_p7_a(void) { port_w(7, R.A); } |
static void movp_a_xa(void) { R.A = M_RDMEM((R.PC.w.l & 0x0f00) | R.A); } |
static void movp3_a_xa(void) { R.A = M_RDMEM(0x300 | R.A); } |
static void movx_a_xr0(void) { R.A = M_IN(R0); } |
static void movx_a_xr1(void) { R.A = M_IN(R1); } |
static void movx_xr0_a(void) { M_OUT(R0, R.A); } |
static void movx_xr1_a(void) { M_OUT(R1, R.A); } |
static void nop(void) { } |
static void orl_a_n(void) { R.A |= M_RDMEM_OPCODE(); } |
static void orl_a_r0(void) { R.A |= R0; } |
static void orl_a_r1(void) { R.A |= R1; } |
static void orl_a_r2(void) { R.A |= R2; } |
static void orl_a_r3(void) { R.A |= R3; } |
static void orl_a_r4(void) { R.A |= R4; } |
static void orl_a_r5(void) { R.A |= R5; } |
static void orl_a_r6(void) { R.A |= R6; } |
static void orl_a_r7(void) { R.A |= R7; } |
static void orl_a_xr0(void) { R.A |= intRAM[R0 & INT_RAM_MASK]; } |
static void orl_a_xr1(void) { R.A |= intRAM[R1 & INT_RAM_MASK]; } |
static void orl_bus_n(void) { bus_w( bus_r() | M_RDMEM_OPCODE() ); } |
static void orl_p1_n(void) { R.P1 |= M_RDMEM_OPCODE(); port_w(1, R.P1); } |
static void orl_p2_n(void) { R.P2 |= M_RDMEM_OPCODE(); port_w(2, R.P2); } |
static void orld_p4_a(void) { port_w(4, port_r(4) | R.A ); } |
static void orld_p5_a(void) { port_w(5, port_r(5) | R.A ); } |
static void orld_p6_a(void) { port_w(6, port_r(6) | R.A ); } |
static void orld_p7_a(void) { port_w(7, port_r(7) | R.A ); } |
static void outl_bus_a(void) { bus_w(R.A); } |
static void outl_p1_a(void) { port_w(1, R.A); R.P1 = R.A; } |
static void outl_p2_a(void) { port_w(2, R.A); R.P2 = R.A; } |
static void ret(void) { R.PC.w.l = ((pull() & 0x0f) << 8); R.PC.w.l |= pull(); } |
|
static void retr(void) |
{ |
UINT8 i=pull(); |
R.PC.w.l = ((i & 0x0f) << 8) | pull(); |
R.PSW = (R.PSW & 0x0f) | (i & 0xf0); /* Stack is already changed by pull */ |
regPTR = ((M_By) ? 24 : 0); |
|
R.irq_executing = I8039_NO_INT; |
|
R.A11 = R.A11ff; |
|
/* Take an interrupt if a request is still being made */ |
if (R.irq_state == I8039_EXTERNAL_INT) { |
R.irq_extra_cycles += Ext_IRQ(); /* Service External IRQ */ |
} |
else if (R.pending_irq == I8039_TIMCNT_INT) { |
R.irq_extra_cycles += Timer_IRQ(); /* Service pending Timer/Counter IRQ */ |
} |
} |
static void rl_a(void) { UINT8 i=R.A & 0x80; R.A <<= 1; if (i) R.A |= 0x01; else R.A &= 0xfe; } |
/* NS990113 */ |
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; } |
static void rr_a(void) { UINT8 i=R.A & 1; R.A >>= 1; if (i) R.A |= 0x80; else R.A &= 0x7f; } |
/* NS990113 */ |
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; } |
static void sel_mb0(void) { R.A11 = 0; R.A11ff = 0; } |
static void sel_mb1(void) { R.A11ff = 0x800; R.A11 = 0x800; } |
static void sel_rb0(void) { CLR(B_FLAG); regPTR = 0; } |
static void sel_rb1(void) { SET(B_FLAG); regPTR = 24; } |
static void stop_tcnt(void) { R.timerON = R.countON = 0; } |
static void strt_cnt(void) { R.countON = 1; R.timerON = 0; Old_T1 = test_r(1); } /* NS990113 */ |
static void strt_t(void) { R.timerON = 1; R.countON = 0; R.masterClock = 0; } /* NS990113 */ |
static void swap_a(void) { UINT8 i=R.A >> 4; R.A <<= 4; R.A |= i; } |
static void xch_a_r0(void) { UINT8 i=R.A; R.A=R0; R0=i; } |
static void xch_a_r1(void) { UINT8 i=R.A; R.A=R1; R1=i; } |
static void xch_a_r2(void) { UINT8 i=R.A; R.A=R2; R2=i; } |
static void xch_a_r3(void) { UINT8 i=R.A; R.A=R3; R3=i; } |
static void xch_a_r4(void) { UINT8 i=R.A; R.A=R4; R4=i; } |
static void xch_a_r5(void) { UINT8 i=R.A; R.A=R5; R5=i; } |
static void xch_a_r6(void) { UINT8 i=R.A; R.A=R6; R6=i; } |
static void xch_a_r7(void) { UINT8 i=R.A; R.A=R7; R7=i; } |
static void xch_a_xr0(void) { UINT8 i=R.A; R.A=intRAM[R0 & INT_RAM_MASK]; intRAM[R0 & INT_RAM_MASK]=i; } |
static void xch_a_xr1(void) { UINT8 i=R.A; R.A=intRAM[R1 & INT_RAM_MASK]; intRAM[R1 & INT_RAM_MASK]=i; } |
static void xchd_a_xr0(void) { M_XCHD(R0 & INT_RAM_MASK); } |
static void xchd_a_xr1(void) { M_XCHD(R1 & INT_RAM_MASK); } |
static void xrl_a_n(void) { R.A ^= M_RDMEM_OPCODE(); } |
static void xrl_a_r0(void) { R.A ^= R0; } |
static void xrl_a_r1(void) { R.A ^= R1; } |
static void xrl_a_r2(void) { R.A ^= R2; } |
static void xrl_a_r3(void) { R.A ^= R3; } |
static void xrl_a_r4(void) { R.A ^= R4; } |
static void xrl_a_r5(void) { R.A ^= R5; } |
static void xrl_a_r6(void) { R.A ^= R6; } |
static void xrl_a_r7(void) { R.A ^= R7; } |
static void xrl_a_xr0(void) { R.A ^= intRAM[R0 & INT_RAM_MASK]; } |
static void xrl_a_xr1(void) { R.A ^= intRAM[R1 & INT_RAM_MASK]; } |
|
static s_opcode opcode_main[256]= |
{ |
{1, nop },{0, illegal },{2, outl_bus_a },{2, add_a_n },{2, jmp },{1, en_i },{0, illegal },{1, dec_a }, |
{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 }, |
{1, inc_xr0 },{1, inc_xr1 },{2, jb_0 },{2, adc_a_n },{2, call },{1, dis_i },{2, jtf },{1, inc_a }, |
{1, inc_r0 },{1, inc_r1 },{1, inc_r2 },{1, inc_r3 },{1, inc_r4 },{1, inc_r5 },{1, inc_r6 },{1, inc_r7 }, |
{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 }, |
{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 }, |
{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 }, |
{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 }, |
{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 }, |
{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 }, |
{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 }, |
{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 }, |
{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 }, |
{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 }, |
{1, adc_a_xr0 },{1, adc_a_xr1 },{2, jb_3 },{0, illegal },{2, call_3 },{1, ento_clk },{2, jf1 },{1, rr_a }, |
{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 }, |
{2, movx_a_xr0 },{2, movx_a_xr1 },{0, illegal },{2, ret },{2, jmp_4 },{1, clr_f0 },{2, jni },{0, illegal }, |
{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 }, |
{2, movx_xr0_a },{2, movx_xr1_a },{2, jb_4 },{2, retr },{2, call_4 },{1, cpl_f0 },{2, jnz },{1, clr_c }, |
{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 }, |
{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 }, |
{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 }, |
{2, mov_xr0_n },{2, mov_xr1_n },{2, jb_5 },{2, jmpp_xa },{2, call_5 },{1, cpl_f1 },{2, jf0 },{0, illegal }, |
{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 }, |
{0, illegal },{0, illegal },{0, illegal },{0, illegal },{2, jmp_6 },{1, sel_rb0 },{2, jz },{1, mov_a_psw }, |
{1, dec_r0 },{1, dec_r1 },{1, dec_r2 },{1, dec_r3 },{1, dec_r4 },{1, dec_r5 },{1, dec_r6 },{1, dec_r7 }, |
{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 }, |
{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 }, |
{0, illegal },{0, illegal },{0, illegal },{2, movp3_a_xa },{2, jmp_7 },{1, sel_mb0 },{2, jnc },{1, rl_a }, |
{2, djnz_r0 },{2, djnz_r1 },{2, djnz_r2 },{2, djnz_r3 },{2, djnz_r4 },{2, djnz_r5 },{2, djnz_r6 },{2, djnz_r7 }, |
{1, mov_a_xr0 },{1, mov_a_xr1 },{2, jb_7 },{0, illegal },{2, call_7 },{1, sel_mb1 },{2, jc },{1, rlc_a }, |
{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 } |
}; |
|
|
/**************************************************************************** |
* Reset registers to their initial values |
****************************************************************************/ |
void i8039_reset (void *param) |
{ |
R.PC.w.l = 0; |
R.SP = 0; |
R.A = 0; |
R.PSW = 0x08; /* Start with Carry SET, Bit 4 is always SET */ |
memset(R.RAM, 0x0, 128); |
R.P1 = 0xff; |
R.P2 = 0xff; |
R.bus = 0; |
R.irq_executing = I8039_NO_INT; |
R.pending_irq = I8039_NO_INT; |
|
R.A11ff = R.A11 = 0; |
R.tirq_en = R.xirq_en = 0; |
R.timerON = R.countON = 0; |
R.timerON = 1; /* Mario Bros. doesn't work without this */ |
R.irq_extra_cycles = 0; |
R.masterClock = 0; |
|
/* print dump header */ |
printf(" Addr | Instruction | PC Accu SP PSW BUS F1 P1 P2 A11 RAM\n"); |
printf(" ------+--------------------+---------------------------------------\n"); |
} |
|
|
/**************************************************************************** |
* Shut down CPU emulation |
****************************************************************************/ |
static void i8039_exit (void) |
{ |
/* nothing to do ? */ |
} |
|
/**************************************************************************** |
* Issue an interrupt if necessary |
****************************************************************************/ |
static int Ext_IRQ(void) |
{ |
int extra_cycles = 0; |
|
if (R.xirq_en) { |
if (R.irq_executing == I8039_NO_INT) { |
/* logerror("I8039: EXT INTERRUPT being serviced\n"); */ |
R.irq_executing = I8039_EXTERNAL_INT; |
push(R.PC.b.l); |
push((R.PC.b.h & 0x0f) | (R.PSW & 0xf0)); |
R.PC.w.l = 0x03; |
R.A11ff = R.A11; |
R.A11 = 0; |
|
extra_cycles = 2; /* 2 clock cycles used */ |
|
if (R.timerON) /* NS990113 */ |
R.masterClock += extra_cycles; |
if (R.irq_callback) (*R.irq_callback)(0); |
} |
} |
|
return extra_cycles; |
} |
|
static int Timer_IRQ(void) |
{ |
int extra_cycles = 0; |
|
if (R.tirq_en) { |
if (R.irq_executing == I8039_NO_INT) { |
/* logerror("I8039: TIMER/COUNTER INTERRUPT\n"); */ |
R.irq_executing = I8039_TIMCNT_INT; |
R.pending_irq &= ~I8039_TIMCNT_INT; |
push(R.PC.b.l); |
push((R.PC.b.h & 0x0f) | (R.PSW & 0xf0)); |
R.PC.w.l = 0x07; |
R.A11ff = R.A11; |
R.A11 = 0; |
|
extra_cycles = 2; /* 2 clock cycles used */ |
|
if (R.timerON) /* NS990113 */ |
R.masterClock += extra_cycles; |
} |
else { |
if (R.irq_executing == I8039_EXTERNAL_INT) { |
R.pending_irq |= I8039_TIMCNT_INT; |
} |
} |
} |
|
R.t_flag = 1; |
|
return extra_cycles; |
} |
|
|
static void dump_machine_state(void) |
{ |
int i; |
|
printf(" | %04X %02X %02X %02X", (UINT32)R.PC.w.l, (UINT32)R.A, (UINT32)(R.SP >> 1), (UINT32)R.PSW); |
printf(" %02X %X %02X %02X", (UINT32)R.bus, (UINT32)R.f1, (UINT32)R.P1, (UINT32)R.P2); |
printf(" %X ", (UINT32)(R.A11ff >> 11)); |
|
for (i = 0; i < 256; i++) |
printf(" %02X", R.RAM[i]); |
|
printf("\n"); |
} |
|
|
enum {ACCU_IDLE, ACCU_HAS_AA, ACCU_HAS_55, ACCU_PASS, ACCU_FAIL}; |
|
/**************************************************************************** |
* Execute cycles CPU cycles. Return number of cycles really executed |
****************************************************************************/ |
int i8039_execute(int cycles, int dump) |
{ |
unsigned opcode, T1; |
int count, i; |
char buffer[64]; |
char string[32]; |
|
static int accu = 0; |
static int accu_state = ACCU_IDLE; |
|
i8039_ICount = (cycles - R.irq_extra_cycles); |
R.irq_extra_cycles = 0; |
|
if ((accu_state == ACCU_PASS) || (accu_state == ACCU_FAIL)) { |
printf("End of simulation detected\n"); |
|
return(accu_state == ACCU_PASS ? 0 : -1); |
} |
|
do |
{ |
R.PREVPC = R.PC; |
|
|
opcode=M_RDOP(R.PC.w.l); |
|
buffer[0] = '\0'; |
Dasm8039(buffer, R.PC.w.l); |
sprintf(string, " %04X : %s", R.PC.w.l, buffer); |
for (i = strlen(string); i < 26; i++) |
string[i] = ' '; |
string[i <= 31 ? i : 31] = '\0'; |
printf("%s", string); |
|
/* logerror("I8039: PC = %04x, opcode = %02x\n", R.PC.w.l, opcode); */ |
|
R.PC.w.l++; |
inst_cycles = opcode_main[opcode].cycles; |
(*(opcode_main[opcode].function))(); |
i8039_ICount -= inst_cycles; /*/ */ |
|
if (dump == 1) { |
/* dump machine state information */ |
dump_machine_state(); |
} else |
printf("\n"); |
|
/* end-of-simulation check */ |
if (accu != R.A) { |
accu = R.A; |
|
switch (accu_state) { |
case ACCU_IDLE: |
accu_state = accu == 0xaa ? ACCU_HAS_AA : ACCU_IDLE; |
break; |
|
case ACCU_HAS_AA: |
accu_state = accu == 0x55 ? ACCU_HAS_55 : ACCU_IDLE; |
break; |
|
case ACCU_HAS_55: |
switch (accu) { |
case 0x01: |
accu_state = ACCU_PASS; |
break; |
case 0x00: |
accu_state = ACCU_FAIL; |
break; |
default: |
accu_state = ACCU_IDLE; |
break; |
} |
break; |
|
case ACCU_PASS: |
case ACCU_FAIL: |
break; |
|
default: |
accu_state = ACCU_IDLE; |
break; |
} |
} |
|
|
|
|
if (R.countON) /* NS990113 */ |
{ |
for ( ; inst_cycles > 0; inst_cycles-- ) |
{ |
T1 = test_r(1); |
if (NEGATIVE_EDGE_T1) |
{ |
R.timer++; |
if (R.timer == 0) { |
count = Timer_IRQ(); /* Handle Counter IRQ */ |
i8039_ICount -= count; |
} |
} |
Old_T1 = T1; |
} |
} |
|
if (R.timerON) { |
R.masterClock += opcode_main[opcode].cycles; |
if (R.masterClock >= 32) { /* NS990113 */ |
R.masterClock -= 32; |
R.timer++; |
if (R.timer == 0) { |
count = Timer_IRQ(); /* Handle Timer IRQ */ |
i8039_ICount -= count; |
} |
} |
} |
} while (i8039_ICount > 0 && accu_state != ACCU_PASS && accu_state != ACCU_FAIL); |
|
i8039_ICount -= R.irq_extra_cycles; |
R.irq_extra_cycles = 0; |
|
return cycles - i8039_ICount; |
} |
|
/**************************************************************************** |
* Get all registers in given buffer |
****************************************************************************/ |
static void i8039_get_context (void *dst) |
{ |
if( dst ) |
*(I8039_Regs*)dst = R; |
} |
|
|
/**************************************************************************** |
* Set all registers to given values |
****************************************************************************/ |
static void i8039_set_context (void *src) |
{ |
if( src ) |
{ |
R = *(I8039_Regs*)src; |
regPTR = ((M_By) ? 24 : 0); |
R.SP = (R.PSW << 1) & 0x0f; |
} |
/* Handle forced Interrupts throught the Debugger */ |
if (R.irq_state != I8039_NO_INT) { |
R.irq_extra_cycles += Ext_IRQ(); /* Handle External IRQ */ |
} |
if (R.timer == 0) { |
R.irq_extra_cycles += Timer_IRQ(); /* Handle Timer IRQ */ |
} |
} |
|
|
/**************************************************************************** |
* Set IRQ line state |
****************************************************************************/ |
void set_irq_line(int irqline, int state) |
{ |
if (state != CLEAR_LINE) { |
R.irq_state = I8039_EXTERNAL_INT; |
R.irq_extra_cycles += Ext_IRQ(); /* Handle External IRQ */ |
} |
else { |
R.irq_state = I8039_NO_INT; |
} |
} |
/main.c
0,0 → 1,128
/* |
* $Id: main.c,v 1.3 2004-07-03 14:37:12 arniml Exp $ |
* |
* Copyright (c) 2004, Arnim Laeuger (arniml@opencores.org) |
* |
* All rights reserved |
* |
* This program is free software; you can redistribute it and/or modify |
* it under the terms of the GNU General Public License as published by |
* the Free Software Foundation; either version 2 of the License, or |
* (at your option) any later version. See also the file COPYING which |
* came with this application. |
* |
* This program is distributed in the hope that it will be useful, |
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
* GNU General Public License for more details. |
* |
* You should have received a copy of the GNU General Public License |
* along with this program; if not, write to the Free Software |
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
* |
*/ |
|
#include <stdio.h> |
#include <unistd.h> |
#include <string.h> |
|
#include "types.h" |
#include "memory.h" |
#include "i8039.h" |
|
|
void logerror(char *msg, UINT16 address, UINT8 opcode) |
{ |
} |
|
|
void print_usage(void) { |
printf("Usage:\n"); |
printf(" i8039 -f <hex file> [-x <hex file>] [-d] [-h]\n"); |
printf(" -f : Name of hex file for internal ROM\n"); |
printf(" -x : Name of hex file for external ROM (optional)\n"); |
printf(" -d : Dump machine state\n"); |
printf(" -h : Print this help\n"); |
} |
|
|
int main(int argc, char *argv[]) |
{ |
int do_cycles, real_cycles, total_cycles; |
char *hex_file = ""; |
char *ext_hex_file = ""; |
int c; |
int dump = 0; |
|
/* process options */ |
while ((c = getopt(argc, argv, "df:hx:")) != -1) { |
switch (c) { |
case 'd': |
dump = 1; |
break; |
|
case 'f': |
hex_file = optarg; |
break; |
|
case 'x': |
ext_hex_file = optarg; |
break; |
|
case 'h': |
/* fallthrough */ |
|
default: |
print_usage(); |
return(0); |
break; |
} |
} |
|
/* check options */ |
if (strlen(hex_file) == 0) { |
print_usage(); |
return(1); |
} |
|
/* read hex file for internal ROM */ |
printf("Reading %s\n", hex_file); |
if (!read_hex_file(hex_file, 0)) { |
printf("Error reading file!\n"); |
return(1); |
} |
|
/* read hex fiel for external ROM */ |
if (strlen(ext_hex_file) > 0) { |
printf("Reading %s\n", ext_hex_file); |
if (!read_hex_file(ext_hex_file, 0x800)) { |
printf("Error reading file!\n"); |
return(1); |
} |
} |
|
printf("Resetting 8039\n"); |
i8039_reset(NULL); |
|
do_cycles = 52; |
|
total_cycles = 0; |
|
do { |
real_cycles = i8039_execute(do_cycles, dump); |
|
/* activate interrupt */ |
set_irq_line(0, HOLD_LINE); |
/* hold interrupt for 3 machine cycles */ |
real_cycles += i8039_execute(3, dump); |
set_irq_line(0, CLEAR_LINE); |
|
if (real_cycles > 0) |
total_cycles += real_cycles; |
} while (real_cycles > 0); |
|
printf("Emulated %i cycles\n", total_cycles); |
printf("Simulation Result: %s\n", real_cycles == 0 ? "PASS" : "FAIL"); |
|
return(0); |
} |
/memory.c
0,0 → 1,149
/* |
* $Id: memory.c,v 1.3 2004-07-03 14:35:52 arniml Exp $ |
* |
* Copyright (c) 2004, Arnim Laeuger (arniml@opencores.org) |
* |
* All rights reserved |
* |
* This program is free software; you can redistribute it and/or modify |
* it under the terms of the GNU General Public License as published by |
* the Free Software Foundation; either version 2 of the License, or |
* (at your option) any later version. See also the file COPYING which |
* came with this application. |
* |
* This program is distributed in the hope that it will be useful, |
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
* GNU General Public License for more details. |
* |
* You should have received a copy of the GNU General Public License |
* along with this program; if not, write to the Free Software |
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
* |
*/ |
|
#include <stdio.h> |
#include <string.h> |
|
#include "memory.h" |
#include "i8039.h" |
|
|
static UINT8 code_mem[4096]; |
|
|
static UINT8 port1 = 0xff, port2 = 0xff; |
|
|
UINT8 program_read_byte_8(UINT16 address) |
{ |
return(code_mem[address]); |
} |
|
UINT8 cpu_readop(UINT16 address) |
{ |
return(code_mem[address]); |
} |
|
UINT8 cpu_readop_arg(UINT16 address) |
{ |
return(code_mem[address]); |
} |
|
|
UINT8 io_read_byte_8(UINT8 address) |
{ |
UINT8 data; |
|
switch (0x100 | address) { |
case I8039_p1: |
data = port1; |
break; |
|
case I8039_p2: |
data = port2; |
break; |
|
case I8039_t0: |
/* connect T0 to P1[0] */ |
data = port1 & 0x01; |
break; |
|
case I8039_t1: |
/* connect T1 to P1[1] */ |
data = (port1 & 0x02) >> 1; |
break; |
|
default: |
data = 0; |
break; |
} |
|
|
return(data); |
} |
|
|
void io_write_byte_8(UINT8 address, UINT8 data) |
{ |
switch (0x100 | address) { |
case I8039_p1: |
port1 = data; |
break; |
|
case I8039_p2: |
port2 = data; |
break; |
|
default: |
break; |
} |
} |
|
|
int read_hex_file(char *filename, UINT16 file_offset) |
{ |
FILE *hex_file; |
UINT16 record_len, offset, record_type; |
UINT16 byte; |
char line[540]; |
char *payload, *idx; |
int result = 0; |
|
record_len = offset = record_type = 0; |
hex_file = fopen(filename, "r"); |
if (hex_file != NULL) { |
|
while (fgets(line, 539, hex_file)) { |
if (sscanf(line, ":%2hx%4hx%2hx", &record_len, &offset, &record_type) == 3) { |
/* strip off newline */ |
idx = (char *)strchr(line, '\n'); |
if (idx != NULL) |
*idx = '\0'; |
/* extract payload */ |
payload = &(line[9]); |
/* strip of checksum */ |
if (strlen(payload) > 2) |
payload[strlen(payload) - 2] = '\0'; |
|
/* read payload to array */ |
if (record_type == 0) { |
while (strlen(payload) >= 2) { |
if (sscanf(payload, "%2hx", &byte) == 1) |
code_mem[file_offset + offset++] = byte; |
|
payload++; |
payload++; |
} |
} |
|
} |
} |
|
result = 1; |
|
fclose(hex_file); |
} |
|
return(result); |
} |
/memory.h
0,0 → 1,26
/* |
* $Id: memory.h,v 1.2 2004-07-03 14:35:52 arniml Exp $ |
* |
*/ |
|
#ifndef _MEMORY_H_ |
#define _MEMORY_H_ |
|
#include "types.h" |
|
typedef UINT32 offs_t; |
|
|
UINT8 program_read_byte_8(UINT16); |
|
UINT8 cpu_readop(UINT16); |
|
UINT8 cpu_readop_arg(UINT16); |
|
UINT8 io_read_byte_8(UINT8); |
|
void io_write_byte_8(UINT8, UINT8); |
|
int read_hex_file(char *, UINT16); |
|
#endif |
/i8039.h
0,0 → 1,107
/************************************************************************** |
* Intel 8039 Portable Emulator * |
* * |
* Copyright (C) 1997 by Mirko Buffoni * |
* Based on the original work (C) 1997 by Dan Boris, an 8048 emulator * |
* You are not allowed to distribute this software commercially * |
* Please, notify me, if you make any changes to this file * |
* * |
* Adapted for the T48 uController project, 2004 by Arnim Laeuger * |
* See http://www.opencores.org/projects.cgi/web/t48/overview * |
* * |
* $Id: i8039.h,v 1.2 2004-04-15 22:03:53 arniml Exp $ |
**************************************************************************/ |
|
#ifndef _I8039_H |
#define _I8039_H |
|
#ifndef INLINE |
#define INLINE static inline |
#endif |
|
#include "types.h" |
|
|
/************************************************************************** |
Internal Clock divisor |
|
External Clock is divided internally by 3 to produce the machine state |
generator. This is then divided by 5 for the instruction cycle times. |
(Each instruction cycle passes through 5 machine states). |
*/ |
|
#define I8039_CLOCK_DIVIDER (3*5) |
|
|
|
enum { I8039_PC=1, I8039_SP, I8039_PSW, I8039_A, I8039_TC, |
I8039_P1, I8039_P2, I8039_R0, I8039_R1, I8039_R2, |
I8039_R3, I8039_R4, I8039_R5, I8039_R6, I8039_R7 |
}; |
|
/* This handling of special I/O ports should be better for actual MAME |
* architecture. (i.e., define access to ports { I8039_p1, I8039_p1, dkong_out_w }) |
*/ |
|
#define I8039_p0 0x100 /* Not used */ |
#define I8039_p1 0x101 |
#define I8039_p2 0x102 |
#define I8039_p4 0x104 |
#define I8039_p5 0x105 |
#define I8039_p6 0x106 |
#define I8039_p7 0x107 |
#define I8039_t0 0x110 |
#define I8039_t1 0x111 |
#define I8039_bus 0x120 |
|
|
#include "memory.h" |
|
/* |
* Input a UINT8 from given I/O port |
*/ |
#define I8039_In(Port) ((UINT8)io_read_byte_8((UINT8)Port)) |
|
|
/* |
* Output a UINT8 to given I/O port |
*/ |
#define I8039_Out(Port,Value) (io_write_byte_8((UINT8)Port,(UINT8)Value)) |
|
|
/* |
* Read a UINT8 from given memory location |
*/ |
#define I8039_RDMEM(A) ((unsigned)program_read_byte_8(A)) |
|
|
/* |
* Write a UINT8 to given memory location |
*/ |
#define I8039_WRMEM(A,V) (program_write_byte_8(A,V)) |
|
|
/* |
* I8039_RDOP() is identical to I8039_RDMEM() except it is used for reading |
* opcodes. In case of system with memory mapped I/O, this function can be |
* used to greatly speed up emulation |
*/ |
#define I8039_RDOP(A) ((unsigned)cpu_readop(A)) |
|
|
/* |
* I8039_RDOP_ARG() is identical to I8039_RDOP() except it is used for reading |
* opcode arguments. This difference can be used to support systems that |
* use different encoding mechanisms for opcodes and opcode arguments |
*/ |
#define I8039_RDOP_ARG(A) ((unsigned)cpu_readop_arg(A)) |
|
int Dasm8039(char *dst, unsigned pc); |
|
void i8039_reset(void *); |
int i8039_execute(int, int); |
void set_irq_line(int, int); |
|
void logerror(char *, UINT16, UINT8); |
|
#endif /* _I8039_H */ |
/8039dasm.c
0,0 → 1,289
/**************************************************************************** |
* |
* mcs48 disassembler |
* |
* This file is Copyright 1996 Michael Cuddy, Fen's Ende Sofware. |
* Redistribution is allowed in source and binary form as long as both |
* forms are distributed together with the file 'README'. This copyright |
* notice must also accompany the files. |
* |
* This software should be considered a small token to all of the |
* emulator authors for thier dilligence in preserving our Arcade and |
* Computer history. |
* |
* Michael Cuddy, Fen's Ende Software. |
* 11/25/1996 |
* |
* Adapted by Andrea Mazzoleni for use with MAME |
* |
***************************************************************************/ |
|
#include <stdio.h> |
#include <stdlib.h> |
#include <string.h> |
#include <ctype.h> |
|
#include "memory.h" |
|
typedef unsigned char byte; |
|
#define FMT(a,b) a, b |
#define PTRS_PER_FORMAT 2 |
|
const char *Formats[] = { |
FMT("00000011dddddddd", "add a, #%X"), |
FMT("01101rrr", "add a, %R"), |
FMT("0110000r", "add a, @%R"), |
FMT("00010011dddddddd", "adc a, #%X"), |
FMT("01111rrr", "adc a, %R"), |
FMT("0111000r", "adc a, @%R"), |
FMT("01010011dddddddd", "anl a, #%X"), |
FMT("01011rrr", "anl a, %R"), |
FMT("0101000r", "anl a, @%R"), |
FMT("10011000dddddddd", "anl bus, #%X"), |
FMT("10011001dddddddd", "anl p1, #%X"), |
FMT("10011010dddddddd", "anl p2, #%X"), |
FMT("100111pp", "anld %P, a"), |
FMT("aaa10100aaaaaaaa", "call %A"), |
FMT("00100111", "clr a"), |
FMT("10010111", "clr c"), |
FMT("10100101", "clr f1"), |
FMT("10000101", "clr f0"), |
FMT("00110111", "cpl a"), |
FMT("10100111", "cpl c"), |
FMT("10010101", "cpl f0"), |
FMT("10110101", "cpl f1"), |
FMT("01010111", "da a"), |
FMT("00000111", "dec a"), |
FMT("11001rrr", "dec %R"), |
FMT("00010101", "dis i"), |
FMT("00110101", "dis tcnti"), |
FMT("11101rrraaaaaaaa", "djnz %R, %J"), |
FMT("00000101", "en i"), |
FMT("00100101", "en tcnti"), |
FMT("01110101", "ent0 clk"), |
FMT("00001001", "in a, p1"), |
FMT("00001010", "in a, p2"), |
FMT("00010111", "inc a"), |
FMT("00011rrr", "inc %R"), |
FMT("0001000r", "inc @%R"), |
FMT("00001000", "ins a,bus"), |
FMT("0001 0110aaaaaaaa", "jtf %J"), |
FMT("0010 0110aaaaaaaa", "jnt0 %J"), |
FMT("0011 0110aaaaaaaa", "jt0 %J"), |
FMT("0100 0110aaaaaaaa", "jnt1 %J"), |
FMT("0101 0110aaaaaaaa", "jt1 %J"), |
FMT("0111 0110aaaaaaaa", "jf1 %J"), |
FMT("1000 0110aaaaaaaa", "jni %J"), |
FMT("1001 0110aaaaaaaa", "jnz %J"), |
FMT("1011 0110aaaaaaaa", "jf0 %J"), |
FMT("1100 0110aaaaaaaa", "jz %J"), |
FMT("1110 0110aaaaaaaa", "jnc %J"), |
FMT("1111 0110aaaaaaaa", "jc %J"), |
FMT("bbb10010aaaaaaaa", "jb%B %J"), |
FMT("aaa00100aaaaaaaa", "jmp %A"), |
FMT("10110011", "jmpp @a"), |
FMT("00100011dddddddd", "mov a, #%X"), |
FMT("11111rrr", "mov a, %R"), |
FMT("1111000r", "mov a, @%R"), |
FMT("11000111", "mov a, psw"), |
FMT("10111rrrdddddddd", "mov %R, #%X"), |
FMT("10101rrr", "mov %R, a"), |
FMT("1010000r", "mov @%R, a"), |
FMT("1011000rdddddddd", "mov @%R, #%X"), |
FMT("11010111", "mov psw, a"), |
FMT("000011pp", "movd a, %P"), |
FMT("001111pp", "movd %P, a"), |
FMT("01000010", "mov a, t"), |
FMT("01100010", "mov t, a"), |
FMT("11100011", "movp3 a, @a"), |
FMT("10100011", "movp a, @a"), |
FMT("1000000r", "movx a, @%R"), |
FMT("1001000r", "movx @%R, a"), |
FMT("0100 1rrr", "orl a, %R"), |
FMT("0100 000r", "orl a, @%R"), |
FMT("0100 0011dddddddd", "orl a, #%X"), |
FMT("1000 1000dddddddd", "orl bus, #%X"), |
FMT("1000 1001dddddddd", "orl p1, #%X"), |
FMT("1000 1010dddddddd", "orl p2, #%X"), |
FMT("1000 11pp", "orld %P, a"), |
FMT("00000010", "outl bus, a"), |
FMT("001110pp", "outl %P, a"), |
FMT("10000011", "ret"), |
FMT("10010011", "retr"), |
FMT("11100111", "rl a"), |
FMT("11110111", "rlc a"), |
FMT("01110111", "rr a"), |
FMT("01100111", "rrc a"), |
FMT("11100101", "sel mb0"), |
FMT("11110101", "sel mb1"), |
FMT("11000101", "sel rb0"), |
FMT("11010101", "sel rb1"), |
FMT("01100101", "stop tcnt"), |
FMT("01000101", "strt cnt"), |
FMT("01010101", "strt t"), |
FMT("01000111", "swap a"), |
FMT("00101rrr", "xch a, %R"), |
FMT("0010000r", "xch a, @%R"), |
FMT("0011000r", "xchd a, @%R"), |
FMT("1101 0011dddddddd", "xrl a, #%X"), |
FMT("1101 1rrr", "xrl a, %R"), |
FMT("1101 000r", "xrl a, @%R"), |
FMT("00000000", "nop"), |
NULL |
}; |
|
#define MAX_OPS (((sizeof(Formats) / sizeof(Formats[0])) - 1) / PTRS_PER_FORMAT) |
|
typedef struct opcode { |
byte mask; /* instruction mask */ |
byte bits; /* constant bits */ |
char extcode; /* value that gets extension code */ |
const char *parse; /* how to parse bits */ |
const char *fmt; /* instruction format */ |
} M48Opcode; |
|
static M48Opcode Op[MAX_OPS+1]; |
static int OpInizialized = 0; |
|
static void InitDasm8039(void) |
{ |
const char *p, **ops; |
byte mask, bits; |
int bit; |
int i; |
|
ops = Formats; i = 0; |
while (*ops) { |
p = *ops; |
mask = 0; bits = 0; bit = 7; |
while (*p && bit >= 0) { |
switch (*p++) { |
case '1': mask |= 1<<bit; bits |= 1<<bit; bit--; break; |
case '0': mask |= 1<<bit; bit--; break; |
case ' ': break; |
case 'b': |
case 'a': case 'r': case 'd': case 'p': |
bit --; |
break; |
default: |
printf("Invalid instruction encoding '%s %s'\n", ops[0],ops[1]); |
exit(1); |
} |
} |
if (bit != -1 ) { |
printf("not enough bits in encoding '%s %s' %d\n", ops[0],ops[1],bit); |
exit(1); |
} |
while (isspace(*p)) p++; |
if (*p) Op[i].extcode = *p; |
Op[i].bits = bits; |
Op[i].mask = mask; |
Op[i].fmt = ops[1]; |
Op[i].parse = ops[0]; |
|
ops += PTRS_PER_FORMAT; |
i++; |
} |
|
OpInizialized = 1; |
} |
|
int Dasm8039(char *buffer, unsigned pc) |
{ |
int b, a, d, r, p; /* these can all be filled in by parsing an instruction */ |
int i; |
int op; |
int cnt = 1; |
int code, bit; |
const char *cp; |
|
if (!OpInizialized) InitDasm8039(); |
|
code = cpu_readop(pc); |
op = -1; /* no matching opcode */ |
for ( i = 0; i < MAX_OPS; i++) |
{ |
if( (code & Op[i].mask) == Op[i].bits ) |
{ |
if (op != -1) |
{ |
fprintf(stderr, "Error: opcode %02X matches %d (%s) and %d (%s)\n", |
code,i,Op[i].fmt,op,Op[op].fmt); |
} |
op = i; |
} |
} |
|
if (op == -1) |
{ |
sprintf(buffer,"db %2.2x",code); |
return cnt; |
} |
|
if (Op[op].extcode) |
{ |
cnt++; |
code <<= 8; |
code |= cpu_readop_arg((pc+1)&0xffff); |
bit = 15; |
} |
else |
{ |
bit = 7; |
} |
|
/* shift out operands */ |
cp = Op[op].parse; |
b = a = d = r = p = 0; |
|
while (bit >= 0) |
{ |
/* printf("{%c/%d}",*cp,bit); */ |
switch(*cp) |
{ |
case 'a': a <<=1; a |= ((code & (1<<bit)) ? 1 : 0); bit--; break; |
case 'b': b <<=1; b |= ((code & (1<<bit)) ? 1 : 0); bit--; break; |
case 'd': d <<=1; d |= ((code & (1<<bit)) ? 1 : 0); bit--; break; |
case 'r': r <<=1; r |= ((code & (1<<bit)) ? 1 : 0); bit--; break; |
case 'p': p <<=1; p |= ((code & (1<<bit)) ? 1 : 0); bit--; break; |
case ' ': break; |
case '1': case '0': bit--; break; |
case '\0': printf("premature end of parse string, opcode %x, bit = %d\n",code,bit); exit(1); |
} |
cp++; |
} |
|
/* now traverse format string */ |
cp = Op[op].fmt; |
while (*cp) |
{ |
if (*cp == '%') |
{ |
char num[10], *q; |
cp++; |
switch (*cp++) |
{ |
case 'A': sprintf(num,"0%04XH",a); break; |
case 'J': sprintf(num,"0%04XH",((pc+1) & 0xf00) | a); break; |
case 'B': sprintf(num,"%d",b); break; |
case 'D': sprintf(num,"%d",d); break; |
case 'X': sprintf(num,"0%02XH",d); break; |
case 'R': sprintf(num,"r%d",r); break; |
case 'P': sprintf(num,"p%d",p); break; |
default: |
printf("illegal escape character in format '%s'\n",Op[op].fmt); |
exit(1); |
} |
q = num; while (*q) *buffer++ = *q++; |
*buffer = '\0'; |
} |
else |
{ |
*buffer++ = *cp++; |
*buffer = '\0'; |
} |
} |
|
return cnt; |
} |
/types.h
0,0 → 1,58
/* |
* $Id: types.h,v 1.1.1.1 2004-04-09 19:20:53 arniml Exp $ |
* |
*/ |
|
#ifndef _TYPES_H_ |
#define _TYPES_H_ |
|
typedef unsigned char UINT8; |
typedef unsigned short UINT16; |
typedef unsigned int UINT32; |
|
|
#define LSB_FIRST |
|
/****************************************************************************** |
* Union of UINT8, UINT16 and UINT32 in native endianess of the target |
* This is used to access bytes and words in a machine independent manner. |
* The upper bytes h2 and h3 normally contain zero (16 bit CPU cores) |
* thus PAIR.d can be used to pass arguments to the memory system |
* which expects 'int' really. |
******************************************************************************/ |
typedef union { |
#ifdef LSB_FIRST |
struct { UINT8 l,h,h2,h3; } b; |
struct { UINT16 l,h; } w; |
#else |
struct { UINT8 h3,h2,h,l; } b; |
struct { UINT16 h,l; } w; |
#endif |
UINT32 d; |
} PAIR; |
|
|
/************************************* |
* |
* Interrupt line constants |
* |
*************************************/ |
|
enum |
{ |
/* line states */ |
CLEAR_LINE = 0, /* clear (a fired, held or pulsed) line */ |
ASSERT_LINE, /* assert an interrupt immediately */ |
HOLD_LINE, /* hold interrupt line until acknowledged */ |
PULSE_LINE, /* pulse interrupt line for one instruction */ |
|
/* internal flags (not for use by drivers!) */ |
INTERNAL_CLEAR_LINE = 100 + CLEAR_LINE, |
INTERNAL_ASSERT_LINE = 100 + ASSERT_LINE, |
|
/* interrupt parameters */ |
MAX_IRQ_LINES = 32+1, /* maximum number of IRQ lines per CPU */ |
IRQ_LINE_NMI = MAX_IRQ_LINES - 1 /* IRQ line for NMIs */ |
}; |
|
#endif |
/Makefile
0,0 → 1,25
|
CFLAGS = -Wall |
|
.PHONY: all |
all: i8039 |
|
i8039: i8039.o memory.o main.o 8039dasm.o |
gcc -s -o i8039 main.o i8039.o memory.o 8039dasm.o |
|
i8039.o: i8039.h i8039.c types.h memory.h |
gcc $(CFLAGS) -O -c i8039.c |
|
8039dasm.o: 8039dasm.c |
gcc $(CFLAGS) -O -c 8039dasm.c |
|
memory.o: memory.c memory.h types.h |
gcc $(CFLAGS) -O -c memory.c |
|
main.o: main.c memory.h types.h i8039.h |
gcc $(CFLAGS) -O -c main.c |
|
|
.PHONY: clean |
clean: |
rm -f *.o *~ i8039 log |