home *** CD-ROM | disk | FTP | other *** search
-
- /*
- 9900.C
- ======
-
- 9900 emulator. "execute" executes one instruction at (PC,WP).
-
- Define GNU_X86_ASM to implement some instructions in GCC x86 assembly.
- These implement shift, add, multiply, divide, and other
- instructions in assembly to avoid complicated work re-calculating
- status bits.
- Define FAST_X86_STATUS to implement status register in
- terms of x86 flags register. This avoids setting lastval/lastcmp.
- */
-
- /*
- Updated 7/99 with iffy list of clock speeds per instruction.
- Updated 8/99 with better info from http://www.stanford.edu/~thierry1/ti99/
- 11/99: clock timings are WAY TOO SLOW! Can't possibly be right.
- Whoops, the IS_PE_MEM macro was reversed.... ;)
- */
-
- #define __9900__
-
- #if __MWERKS__
- #pragma optimization_level 4
- //#pragma auto_inline on
- //#pragma inline_depth 8
- #endif
-
- #include "v9t9_common.h"
- #include "cru.h"
- #include "memory.h"
- #include "emulate.h"
- #include "debugger.h"
- #include "log.h"
- #include "9900.h"
-
- #define _L LOG_CPU | LOG_INFO
- #include "9900st.h"
- #include "9900asm.h"
- #include "opcode_callbacks.h"
-
- void execute(uop op);
-
- uaddr pc, wp;
- u16 *wpptr;
- uword status;
-
-
- s16 lastcmp,lastval;
-
- u8 intlevel9900;
- u8 intpins9900;
-
- extern long instcycles; // # cycles estimated per instruction
-
- /* Penalties for accessing memory other than scratch pad or ROMs. */
-
- static int _is_pe_mem[] = {
- 0, // 0x0000
- 4, // 0x2000
- 4, // 0x4000
- 2, // 0x6000
- 0, // 0x8000
- 4, // 0xa000
- 4, // 0xc000
- 4, // 0xe000
- };
- #define IS_PE_MEM(x) _is_pe_mem[((x) >> 13) & 7]
- //#define IS_PE_MEM(x) (((x) & 0xe000) != 0)*4
-
-
- /* In the following, instcycles is incremented first by
- the number of cycles taken to execute the instruction,
- then by the number of cycles needed to read the instruction
- from memory -- it looks like the 9900 reads the instruction
- word several times for decoding!
-
- Time is taken for the instruction read by 'fetch'.
- Time is taken for argument decoding by 'decipheraddr'.
- Instructions also have added time for the transfer of
- arguments to and from memory, which is added in along
- with the execution time.
- */
-
- // Use this before reading the instruction, unless it
- // doesn't matter much that pc is pc+2 by now
- #define CYCLES(base,mem) (base) + (mem) * IS_PE_MEM(pc)
-
-
- #if defined(GNU_X86_ASM) || defined(FAST_X86_STATUS)
-
- /*
- LAE bits maintained in lastcmp/lastval.
-
- ALWAYS, lastcmp is 0<=lastcmp<=0xffff.
- ALWAYS, status has 0xf mask for interrupt level, ST_X for XOP, etc.
- */
- u16 statusto9900(void)
- {
- status=(status&~(ST_L|ST_E|ST_A)) |
- ( (u16)lastval > (u16)lastcmp ? ST_L : 0) |
- ( (s16)lastval > (s16)lastcmp ? ST_A : 0) |
- (lastval==lastcmp ? ST_E : 0);
- return status;
- }
-
- void T9900tostatus(u16 stat)
- {
- lastval=lastcmp=0;
- status=stat;
- if (!(status&ST_E)) {
- if (!(status&(ST_L|ST_A)))
- lastcmp++;
- else {
- lastval++;
- if (!(status&ST_L))
- lastcmp=0xffff;
- else
- if (!(status&ST_A))
- lastval=(-lastval)&0xffff;
- }
- }
-
- }
-
- #else
-
- u8 st_o, st_c, st_p;
-
- /*
- LAE bits maintained in lastcmp/lastval.
-
- ALWAYS, lastcmp is 0<=lastcmp<=0xffff.
- ALWAYS, status has 0xf mask for interrupt level, ST_X for XOP, etc.
- st_o, st_c, and st_p maintain those bits.
- */
- u16 statusto9900(void)
- {
- status= ( status & ~(ST_C|ST_O|ST_P|ST_L|ST_A|ST_E)) |
- ( st_o ? ST_O : 0 ) |
- ( st_c ? ST_C : 0 ) |
- ( st_p ? ST_P : 0 ) |
- ( (u16)lastval > (u16)lastcmp ? ST_L : 0) |
- ( (s16)lastval > (s16)lastcmp ? ST_A : 0) |
- (lastval==lastcmp ? ST_E : 0);
- return status;
- }
-
- void T9900tostatus(u16 stat)
- {
- lastval=lastcmp=0;
- status=stat;
- if (!(status&ST_E)) {
- if (!(status&(ST_L|ST_A)))
- lastcmp++;
- else {
- lastval++;
- if (!(status&ST_L))
- lastcmp=0xffff;
- else
- if (!(status&ST_A))
- lastval=(-lastval)&0xffff;
- }
- }
- st_o = (status & ST_O) != 0;
- st_c = (status & ST_C) != 0;
- st_p = (status & ST_P) != 0;
- }
-
- #endif
-
-
- /**************************************************************************/
-
- void
- hold9900pin(u8 mask)
- {
- intpins9900 |= mask;
- stateflag |= ST_INTERRUPT;
- }
-
- void
- change9900intmask(u16 mask)
- {
- intlevel9900 = mask & 0xf;
- }
-
-
- u16
- fetch(void)
- {
- register u16 op = memory_read_word(pc);
-
- instcycles += IS_PE_MEM(pc);
- pc = (pc + 2) & 0xfffe;
- return op;
- }
-
- bool
- verifywp(uaddr addr)
- {
- return true; //(HAS_RAM_ACCESS(md_cpu, addr) && HAS_RAM_ACCESS(md_cpu, addr + 31));
- }
-
- void
- setandverifywp(uaddr addr)
- {
- static u16 zero16[16];
- wp = addr & 0xfffe;
- wpptr = registerptr(0);
- if (wpptr < (u16 *)0x10000) wpptr = zero16;
-
- if (!verifywp(wp)) {
- logger(_L | LOG_USER, "Illegal workspace pointer set (>%04X)\n",
- wp);
- command_parse_text("Interactive on\n");
- }
- }
-
- bool
- verifypc(uaddr addr)
- {
- return true; //(HAS_ROM_ACCESS(md_cpu, pc) || (pc >= 0x4000 && pc < 0x6000));
- }
-
- void
- setandverifypc(uaddr addr)
- {
- pc = addr & 0xfffe;
- if (!verifypc(pc)) {
- logger(_L | LOG_USER, "Invalid program counter set (>%04X), aborting\n",
- pc);
- command_parse_text("Interactive on\n");
- }
- }
-
- void
- contextswitch(uaddr addr)
- {
- u16 oldwp, oldpc, newwp, newpc;
- u16 *rptr;
-
- // instcycles += CYCLES(14,4);
- oldwp = wp;
- oldpc = pc;
- newwp = memory_read_word(addr);
- newpc = memory_read_word(addr + 2);
-
- if (oldwp == newwp && addr) {
- logger(_L, "*** BLWP'ing to same workspace, may be hosed\n");
- // debugger_enable();
- }
- setandverifywp(newwp);
- setandverifypc(newpc);
- rptr = wpptr + 13;
- *rptr++ = oldwp;
- *rptr++ = oldpc;
- *rptr = statusto9900();
-
- if (addr == 0) {
- /* this mimics the behavior
- where holding down fctn-quit
- keeps the program going */
- trigger9901int(M_INT_VDP);
- hold9900pin(INTPIN_INTREQ);
- }
- }
-
- /*
- thierry times for address decodes:
- "memory access" means if the memory is over the PE box link;
- this is four cycles each!
-
- Address mode Clock cycles Memory access
- Rx 0 0
- *Rx 4 1
- *Rx+ (byte) 6 2
- (word) 8 2
- @>xxxx 8 1
- @>xxxx(Rx) 8 2
-
- */
-
-
- u16 INLINE
- decipheraddr(uop op, int regmask, int tmask, int shiftright)
- {
- register uword reg = (op & regmask) >> shiftright;
- uword ts = ((op & tmask) >> shiftright);
- register u16 imm;
- uword addr;
-
- if (ts == 0) {
- addr = (wp + reg + reg) & 0xffff;
- instcycles += 0 * 4;
- } else if (ts == 0x10) {
- addr = memory_read_word((wp + reg + reg) & 0xffff);
- instcycles += 4 + IS_PE_MEM((wp + reg + reg) & 0xffff) * 1;
- } else if (ts == 0x20) {
- imm = fetch();
- if (reg) {
- addr =
- (memory_read_word((wp + reg + reg) & 0xffff) + imm) & 0xffff;
- instcycles += 8 + IS_PE_MEM((wp + reg + reg) & 0xffff) * 2;
- } else {
- addr = imm;
- instcycles += 8 + IS_PE_MEM(imm) * 1;
- }
- } else {
- register u16 *regval = wpptr + reg;
-
- addr = *regval;
- (*regval) += 2;
- instcycles += 8 + IS_PE_MEM((wp + reg + reg) & 0xffff) * 2;
-
- }
-
- return addr;
-
- }
-
-
- u16 INLINE
- decipheraddrbyte(uop op, int regmask, int tmask, int shiftright)
- {
- register uword reg = (op & regmask) >> shiftright;
- uword ts = ((op & tmask) >> shiftright);
- register u16 imm;
- uaddr addr;
-
- if (ts == 0) {
- addr = (wp + reg + reg) & 0xffff;
- instcycles += 0 * 4;
- } else if (ts == 0x10) {
- addr = memory_read_word((wp + reg + reg) & 0xffff);
- instcycles += 4 + IS_PE_MEM((wp + reg + reg) & 0xffff) * 1;
- } else if (ts == 0x20) {
- imm = fetch();
- instcycles += 2;
- if (reg) {
- addr =
- (memory_read_word((wp + reg + reg) & 0xffff) + imm) & 0xffff;
- instcycles += 8 + IS_PE_MEM((wp + reg + reg) & 0xffff) * 2;
- } else {
- addr = imm;
- instcycles += 8 + IS_PE_MEM(imm) * 1;
- }
- } else {
- register u16 *regval = wpptr + reg;
-
- addr = *regval;
- (*regval)++;
- instcycles += 6 + IS_PE_MEM((wp + reg + reg) & 0xffff) * 2;
-
- }
-
- return addr;
-
- }
-
-
-
- /*************************************************************************/
-
- /*
- ;==========================================================================
- ; Data instructions, >0000->01FF
- ;==========================================================================
- */
- void INLINE
- h0000(uop op)
- {
- instcycles += CYCLES(6, 1);
- }
-
-
- /*
- ;==========================================================================
- ; Immediate, Control instructions, >0200->03FF
- ;--------------------------------------------------------------------------
- ;
- ; 0 1 2 3-4 5 6 7+8 9 A B-C D E F LI, AI, ANDI, ORI,
- ; ---------------------------------- CI, STWP, STST,
- ; | o p c o d e |0| reg # | LIMI, LWPI, IDLE,
- ; ---------------------------------- RSET, RTWP, CKON,
- ; CKOF, LREX
- ;==========================================================================
- */
- void INLINE
- h0200(uop op)
- {
- register int reg = op & 0xf;
- register int imm;
-
- switch ((op & 0x1e0) >> 5) {
- case 0: /* LI */
- instcycles += CYCLES(12, 3);
- imm = fetch();
- register (reg) = imm;
-
- setst_lae(imm);
-
- break;
- case 1: /* AI */
- instcycles += CYCLES(14, 4);
- imm = fetch();
- radd(reg, imm);
- break;
- case 2: /* ANDI */
- instcycles += CYCLES(14, 4);
- imm = fetch();
- rchange(reg,, &, imm, setst_lae);
- break;
- case 3: /* ORI */
- instcycles += CYCLES(14, 4);
- imm = fetch();
- rchange(reg,, |, imm, setst_lae);
- break;
- case 4: /* CI */
- instcycles += CYCLES(14, 3);
- lastval = register (reg);
-
- lastcmp = fetch();
- break;
- case 5: /* STWP */
- instcycles += CYCLES(8, 2);
- register (reg) = wp;
-
- break;
- case 6: /* STST */
- instcycles += CYCLES(8, 2);
- register (reg) = statusto9900();
-
- break;
- case 7: /* LWPI */
- instcycles += CYCLES(10, 2);
- imm = fetch();
- setandverifywp(imm);
- break;
- case 8: /* LIMI */
- instcycles += CYCLES(16, 2);
- imm = fetch();
- status = (status & ~0xf) | (imm & 0xf);
- change9900intmask(imm);
- logger(LOG_CPU | L_2, "*** LIMI %d\n", imm);
- break;
- case 10: /* IDLE */
- instcycles += CYCLES(12, 1);
- /* should activate CRUCLK */
- break;
- case 11: /* RSET */
- instcycles += CYCLES(12, 1);
- change9900intmask(0);
- /* should activate CRUCLK */
- break;
- case 12: /* RTWP */
- {
- u16 *rptr;
-
- instcycles += CYCLES(14, 4);
- rptr = wpptr + 15;
- T9900tostatus(*rptr--);
- pc = *rptr--;
- setandverifywp(*rptr);
- //intlevel9900 = (status & 0xf); // moved to emulate.c
- break;
- }
- case 13: /* CKON */
- case 14: /* CKOF */
- case 15: /* LREX */
- instcycles += CYCLES(12, 1);
- /* should activate CRUCLK */
- break;
- }
- }
-
- /*
- ;==========================================================================
- ; Single-operand instructions, >0400->07FF
- ;--------------------------------------------------------------------------
- ;
- ; 0 1 2 3-4 5 6 7+8 9 A B-C D E F BLWP, B, X, CLR,
- ; ---------------------------------- NEG, INV, INC, INCT,
- ; | o p c o d e |TS | S | DEC, DECT, BL, SWPB,
- ; ---------------------------------- SETO, ABS
- ;
- ; Inputs: SI=opcode
- ; Outputs: SI=address of operand
- ; AX,BX,CX destroyed
- ;
- ;==========================================================================
- */
-
-
- static void
- h0400(uop op)
- {
- register uaddr addr;
-
- addr = decipheraddr(op, 0xf, 0x30, 0);
-
- switch ((op & 0x3c0) >> 6) {
- case 0: /* BLWP */
- instcycles += CYCLES(26, 6);
- contextswitch(addr);
- break;
-
- case 1: /* B */
- instcycles += CYCLES(8, 2);
- pc = addr;
- break;
-
- case 2: /* X */
- instcycles += CYCLES(8, 2);
- op = memory_read_word(addr);
- execute(op);
- break;
-
- case 3: /* CLR */
- instcycles += CYCLES(10, 3);
- memory_write_word(addr, 0);
- break;
-
- case 4: /* NEG */
- instcycles += CYCLES(12, 3);
- wchange(addr, -,,, setst_laeo);
- break;
-
- case 5: /* INV */
- instcycles += CYCLES(10, 3);
- wchange(addr, ~,,, setst_lae);
- break;
-
- case 6: /* INC */
- instcycles += CYCLES(10, 3);
- wadd(addr, 1);
- break;
-
- case 7: /* INCT */
- instcycles += CYCLES(10, 3);
- wadd(addr, 2);
- break;
-
- case 8: /* DEC */
- instcycles += CYCLES(10, 3);
- wadd(addr, 0xffff);
- break;
-
- case 9: /* DECT */
- instcycles += CYCLES(10, 3);
- wadd(addr, 0xfffe);
- break;
-
- case 10: /* BL */
- instcycles += CYCLES(12, 3);
- register(11) = pc;
-
- pc = addr;
- break;
-
- case 11: /* SWPB */
- instcycles += CYCLES(10, 3);
- wchange(addr, swpb,,,);
- break;
-
- case 12: /* SETO */
- instcycles += CYCLES(10, 3);
- memory_write_word(addr, 0xffff);
- break;
-
- case 13: /* ABS */
- {
- u16 val;
-
- instcycles += CYCLES(12, 2);
-
- val = memory_read_word(addr);
- setst_lae(val);
- if (val >= 0x8000) {
- memory_write_word(addr, -setst_o(val));
- instcycles += CYCLES(2, 1);
- }
- break;
- }
-
- }
- }
-
- /*
- ;==========================================================================
- ; Shift instructions, >0800->0BFF
- ; AND my own instructions, >0C00->0FFF
- ;--------------------------------------------------------------------------
- ;
- ; 0 1 2 3-4 5 6 7+8 9 A B-C D E F SRA, SRL, SLA, SRC
- ; ---------------------------------- ------------------
- ; | o p c o d e | C | W | DSR, KEYS, SPRI,
- ; ---------------------------------- TRAN, INT1, BRK,
- ; TIDSR, KEYSLOW,
- ; Inputs: SI=opcode SCREEN, DBG, -DBG
- ; Outputs: SI=address of operand
- ; CL=shift count
- ; Destroys BX
- ;
- ;==========================================================================
- */
-
-
- static void
- h0800(uop op)
- {
- register u32 reg = (op & 0xf);
- register u32 cnt = (op & 0xf0) >> 4;
- u16 *rptr = wpptr + reg;
-
- if (cnt == 0) {
- cnt = register (0) & 0xf;
-
- if (cnt == 0)
- cnt = 16; // whoops! archiver-3 needs this
- instcycles += CYCLES(20, 3);
- } else {
- instcycles += CYCLES(12, 4);
- }
-
- instcycles += cnt * 2;
-
- /* ONLY shift now */
- switch ((op & 0x700) >> 8) {
- case 0: /* SRA */
- *rptr = setst_sra_laec(*rptr, cnt);
- break;
-
- case 1: /* SRL */
- *rptr = setst_srl_laec(*rptr, cnt);
- break;
-
- case 2: /* SLA */
- *rptr = setst_sla_laeco(*rptr, cnt);
- break;
-
- case 3: /* SRC */
- *rptr = setst_src_laec(*rptr, cnt);
- break;
-
- default:
- switch ((op & 0x3e0) >> 5) {
- // 0xc00
- case 0: /* DSR, OP_DSR */
- emulate_dsr();
- break;
-
- // 0xd80
- case 10: /* KEYSLOW */
- emulate_keyslow();
- break;
-
- // 0xdc0
- case 14: /* EMITCHAR */
- if ((*rptr >> 8) == 0xd)
- printf("\n");
- else
- printf("%c", (*rptr) >> 0x8);
- break;
-
- // 0xde0
- case 15: /* DBG, -DBG */
- debugger_enable(!(op & 0xf));
- if (!(op & 0xf))
- execution_pause(1);
- break;
- default:
- logger(LOG_CPU | L_1,
- "unhandled extended opcode >%04X at >%04X [%d]\n", op, pc,
- (op & 0x3e0) >> 5);
- break;
- }
- break;
- }
- }
-
- /*
- ;==========================================================================
- ; Jump, CRU bit instructions, >1000->1FFF
- ;--------------------------------------------------------------------------
- ;
- ; 0 1 2 3-4 5 6 7+8 9 A B-C D E F JMP, JLT, JLE, JEQ,
- ; ---------------------------------- JHE, JGT, JNE, JNC,
- ; | o p c o d e | signed offset | JOC, JNO, JL,JH,JOP
- ; ---------------------------------- ---------------------
- ; SBO, SBZ, TB
- ; Inputs: SI=opcode
- ; Outputs: AX=signed word offset
- ; Destroys SI
- ;
- ;==========================================================================
- */
- static void
- h1000(uop op)
- {
- register s32 offs = (s8) (op) << 1;
-
- if (op < 0x1D00) /* jumps */
- instcycles = CYCLES(8, 1);
- else
- instcycles = CYCLES(12, 2);
-
- switch ((op & 0xf00) >> 8) {
- case 0: /* JMP */
- setandverifypc(pc + offs);
- instcycles += 2;
- break;
- case 1: /* JLT */
- if ((s16) lastval < (s16) lastcmp) {
- setandverifypc(pc + offs);
- instcycles += 2;
- }
-
- break;
- case 2: /* JLE */
- if ((u16) lastval <= (u16) lastcmp) {
- setandverifypc(pc + offs);
- instcycles += 2;
- }
- break;
- case 3: /* JEQ */
- if (lastval == lastcmp) {
- setandverifypc(pc + offs);
- instcycles += 2;
- }
- break;
- case 4: /* JHE */
- if ((u16) lastval >= (u16) lastcmp) {
- setandverifypc(pc + offs);
- instcycles += 2;
- }
- break;
- case 5: /* JGT */
- if ((s16) lastval > (s16) lastcmp) {
- setandverifypc(pc + offs);
- instcycles += 2;
- }
- break;
- case 6: /* JNE */
- if (lastval != lastcmp) {
- setandverifypc(pc + offs);
- instcycles += 2;
- }
- break;
- case 7: /* JNC */
- #if defined(FAST_X86_STATUS) || defined(GNU_X86_ASM)
- if ((status & ST_C) == 0) {
- setandverifypc(pc + offs);
- instcycles += 2;
- }
- #else
- if (!st_c) {
- setandverifypc(pc + offs);
- instcycles += 2;
- }
- #endif
- break;
- case 8: /* JOC */
- #if defined(FAST_X86_STATUS) || defined(GNU_X86_ASM)
- if (status & ST_C) {
- setandverifypc(pc + offs);
- instcycles += 2;
- }
- #else
- if (st_c) {
- setandverifypc(pc + offs);
- instcycles += 2;
- }
- #endif
- break;
- case 9: /* JNO */
- #if defined(FAST_X86_STATUS) || defined(GNU_X86_ASM)
- if ((status & ST_O) == 0) {
- setandverifypc(pc + offs);
- instcycles += 2;
- }
- #else
- if (!st_o) {
- setandverifypc(pc + offs);
- instcycles += 2;
- }
- #endif
- break;
- case 10: /* JL */
- if ((u16) lastval < (u16) lastcmp) {
- setandverifypc(pc + offs);
- instcycles += 2;
- }
- break;
- case 11: /* JH */
- if ((u16) lastval > (u16) lastcmp) {
- setandverifypc(pc + offs);
- instcycles += 2;
- }
- break;
- case 12: /* JOP */
- #if defined(FAST_X86_STATUS) || defined(GNU_X86_ASM)
- if (status & ST_P) {
- setandverifypc(pc + offs);
- instcycles += 2;
- }
- #else
- if (st_p) {
- setandverifypc(pc + offs);
- instcycles += 2;
- }
- #endif
- break;
-
- case 13: /* SBO */
- cruwrite(register (12) + offs, 1, 1);
-
- break;
- case 14: /* SBZ */
- cruwrite(register (12) + offs, 0, 1);
-
- break;
- case 15: /* TB */
- {
- u8 ans = cruread(register (12) + offs, 1);
-
- setst_e(ans & 1, 1);
- }
- break;
- }
- }
-
- /*
- ;==========================================================================
- ; General and One-Register instructions >2000->3FFF
- ;--------------------------------------------------------------------------
- ;
- ; 0 1 2 3-4 5 6 7+8 9 A B-C D E F COC, CZC, XOR,
- ; ---------------------------------- LDCR, STCR, XOP,
- ; | opcode | D |TS | S | MPY, DIV
- ; ----------------------------------
- ;
- ; Inputs: SI=opcode
- ; Outputs: BX=source address (S)
- ; SI=destination register offset (D)
- ;
- ;==========================================================================
- */
-
-
- static void
- h2000(uop op)
- {
- register u32 reg = (op & 0x3c0) >> 6;
- register u32 src;
- register u16 val;
- u16 *rptr;
-
- if (op < 0x3000 || op >= 0x3800) {
- src = decipheraddr(op, 0xf, 0x30, 0);
- } else {
- // CRU instructions: 'reg' is treated
- // as # of bits, where 0 == 16. 0-7 bits
- // causes a byte operation, 8-16 causes a word
- // operation.
-
- if (reg == 0)
- reg = 16;
- if (reg <= 8)
- src = decipheraddrbyte(op, 0xf, 0x30, 0);
- else
- src = decipheraddr(op, 0xf, 0x30, 0);
- }
-
- switch ((op & 0x1c00) >> 10) {
- case 0: /* COC */
- val = memory_read_word(src);
- setst_e(val & register (reg), val);
-
- instcycles += CYCLES(14, 3);
- break;
-
- case 1: /* CZC */
- val = memory_read_word(src);
- setst_e(val & (~register (reg)), val);
-
- instcycles += CYCLES(14, 3);
- break;
-
- case 2: /* XOR */
- rptr = wpptr + reg;
- *rptr = setst_lae((*rptr) ^ memory_read_word(src));
-
- instcycles += CYCLES(14, 4);
- break;
-
- case 3: /* XOP */
- contextswitch(0x40 + reg * 4);
- status |= ST_X; // done here so it is reset on rtwp
- register (11) = src;
-
- instcycles += CYCLES(36, 8);
- break;
-
- case 4: /* LDCR */
- cruwrite(register (12),
- (reg <= 8 ? setst_byte_laep(memory_read_byte(src)) :
- setst_lae(memory_read_word(src))), reg);
-
- instcycles += CYCLES(20 + 2 * reg, 3);
- break;
-
- case 5: /* STCR */
- if (reg <= 8)
- memory_write_byte(src,
-
- setst_byte_laep(cruread(register (12), reg)));
- else
- memory_write_word(src, setst_lae(cruread(register (12), reg)));
-
- instcycles +=
- CYCLES(reg <= 7 ? 42 : reg == 8 ? 44 : reg <= 15 ? 58 : 60, 4);
- break;
-
- case 6: /* MPY */
- {
- // oops, egcs fucks it up
- #if 0 && defined GNU_X86_ASM
- register u16 a asm("ax");
- register u16 b asm("dx");
- register u16 *r asm("ebx");
- a = register (reg);
-
- b = memory_read_word(src);
- r = wpptr + reg;
- asm("\tmulw %1\n" "\tmovw %1,(%2)\n" "\tmovw %0,2(%2)\n":
- :"r"(a), "r"(b), "r"(r)
- :"ax", "dx");
- #else
-
- u32 prod;
-
- rptr = wpptr + reg;
- prod = *rptr * memory_read_word(src);
- *rptr++ = prod >> 16;
- *rptr = prod & 0xffff;
-
- #endif
-
-
- instcycles += CYCLES(52, 5);
- }
- break;
-
- case 7: /* DIV */
- {
- // oops, egcs fucks this up
- #if 0 && defined( GNU_X86_ASM)
- register u16 hi asm("dx");
- register u16 lo asm("ax");
- register u16 d;
- register u16 *r; // asm ("ebx");
-
- d = memory_read_word(src);
- hi = wpptr[reg];
- lo = wpptr[reg+1];
- r = wpptr + reg;
- if (d <= hi) {
- status |= ST_O;
- instcycles += CYCLES(16, 3);
- } else {
- asm("\tdivw %2,%0\n" "\tmovw %0,(%3)\n" "\tmovw %1,2(%3)\n":
- :"r"(lo), "r"(hi), "g"(d), "r"(r)
- :"ax", "dx");
- status &= ~ST_O;
- instcycles += CYCLES(124, 6);
- }
-
- #else
-
- u16 hi, lo;
- u32 dividend;
- u16 d;
-
- rptr = wpptr + reg;
- hi = *rptr++;
- lo = *rptr;
- dividend = ((u32) hi << 16) | lo;
- d = memory_read_word(src);
-
- if (d <= hi) {
- #if defined(FAST_X86_STATUS) || defined(GNU_X86_ASM)
- status |= ST_O;
- #else
- st_o = 1;
- #endif
- instcycles += CYCLES(16, 3);
- } else {
- *rptr-- = dividend % d;
- *rptr = dividend / d;
-
- #if defined(FAST_X86_STATUS) || defined(GNU_X86_ASM)
- status &= ~ST_O;
- #else
- st_o = 0;
- #endif
- instcycles += CYCLES(124, 6); // assume avg case (92-124)
- }
- #endif
- }
- }
- }
-
- /*
- ;==========================================================================
- ; Two-Register instructions >4000->FFFF
- ;--------------------------------------------------------------------------
- ;
- ; 0 1 2 3-4 5 6 7+8 9 A B-C D E F SZC, SZCB, S, SB,
- ; ---------------------------------- C, CB, A, AB, MOV,
- ; |opcode|B|TD | D |TS | S | MOVB, SOC, SOCB
- ; ----------------------------------
- ;
- ; Inputs: SI=opcode
- ; Outputs: SI=address of source (S)
- ; BX=address of destination (D)
- ;
- ;==========================================================================
- */
- static void
- h4000(uop op)
- {
- register u32 src;
- register u32 dest;
-
- if (op & 0x1000) {
- src = decipheraddrbyte(op, 0xf, 0x30, 0);
- dest = decipheraddrbyte(op, 0x3c0, 0xc00, 6);
- } else {
- src = decipheraddr(op, 0xf, 0x30, 0);
- dest = decipheraddr(op, 0x3c0, 0xc00, 6);
- }
-
- switch ((op & 0xf000) >> 12) {
- case 4: /* SZC */
- memory_write_word(dest,
- setst_lae(memory_read_word(dest) &
- ~memory_read_word(src)));
- instcycles += CYCLES(14, 4);
- break;
- case 5: /* SZCB */
- memory_write_byte(dest,
- setst_byte_laep(memory_read_byte(dest) &
- ~memory_read_byte(src)));
- instcycles += CYCLES(14, 4);
- break;
-
- case 6: /* S */
- memory_write_word(dest,
- setst_sub_laeco(memory_read_word(dest),
- memory_read_word(src)));
- instcycles += CYCLES(14, 4);
- break;
- case 7: /* SB */
- memory_write_byte(dest,
- setst_subbyte_laecop(memory_read_byte(dest),
- memory_read_byte(src)));
- instcycles += CYCLES(14, 4);
- break;
-
- case 8: /* C */
- lastval = memory_read_word(src);
- lastcmp = memory_read_word(dest);
- instcycles += CYCLES(14, 3);
- break;
- case 9: /* CB */
- lastval = (s8) memory_read_byte(src);
- lastcmp = (s8) memory_read_byte(dest);
- instcycles += CYCLES(14, 3);
- break;
-
- case 10: /* A */
- memory_write_word(dest,
- setst_add_laeco(memory_read_word(dest),
- memory_read_word(src)));
- instcycles += CYCLES(14, 4);
- break;
- case 11: /* AB */
- memory_write_byte(dest,
- setst_addbyte_laecop(memory_read_byte(dest),
- memory_read_byte(src)));
- instcycles += CYCLES(14, 4);
- break;
-
- case 12: /* MOV */
- memory_write_word(dest, setst_lae(memory_read_word(src)));
- instcycles += CYCLES(14, 4);
- break;
- case 13: /* MOVB */
- memory_write_byte(dest, setst_byte_laep(memory_read_byte(src)));
- instcycles += CYCLES(14, 4);
- break;
-
- case 14: /* SOC */
- memory_write_word(dest,
- setst_lae(memory_read_word(dest) |
- memory_read_word(src)));
- instcycles += CYCLES(14, 4);
- break;
- case 15: /* SOCB */
- memory_write_byte(dest,
- setst_byte_laep(memory_read_byte(dest) |
- memory_read_byte(src)));
- instcycles += CYCLES(14, 4);
- break;
- }
- }
-
- void
- execute(uop op)
- {
- static void (*jumptable[]) (uop) = {
- &h0000, &h0200, &h0400, &h0400, &h0800, &h0800, &h0800, &h0800,
- &h1000, &h1000, &h1000, &h1000, &h1000, &h1000, &h1000, &h1000,
- &h2000, &h2000, &h2000, &h2000, &h2000, &h2000, &h2000, &h2000,
- &h2000, &h2000, &h2000, &h2000, &h2000, &h2000, &h2000, &h2000,
- &h4000, &h4000, &h4000, &h4000, &h4000, &h4000, &h4000, &h4000,
- &h4000, &h4000, &h4000, &h4000, &h4000, &h4000, &h4000, &h4000,
- &h4000, &h4000, &h4000, &h4000, &h4000, &h4000, &h4000, &h4000,
- &h4000, &h4000, &h4000, &h4000, &h4000, &h4000, &h4000, &h4000,
- &h4000, &h4000, &h4000, &h4000, &h4000, &h4000, &h4000, &h4000,
- &h4000, &h4000, &h4000, &h4000, &h4000, &h4000, &h4000, &h4000,
- &h4000, &h4000, &h4000, &h4000, &h4000, &h4000, &h4000, &h4000,
- &h4000, &h4000, &h4000, &h4000, &h4000, &h4000, &h4000, &h4000,
- &h4000, &h4000, &h4000, &h4000, &h4000, &h4000, &h4000, &h4000,
- &h4000, &h4000, &h4000, &h4000, &h4000, &h4000, &h4000, &h4000,
- &h4000, &h4000, &h4000, &h4000, &h4000, &h4000, &h4000, &h4000,
- &h4000, &h4000, &h4000, &h4000, &h4000, &h4000, &h4000, &h4000
- };
-
- (jumptable[op >> 9]) (op);
- }
-
- void
- init9900(void)
- {
- #if defined(FAST_X86_STATUS)
- setup_status();
- #endif
- wpptr = registerptr(0);
- }
-