/* ======================================================================= C50LIB.C - Library of routines for building TMS320C50 simulators Copyright (C) 1996 Will Ware 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. 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., 675 Mass Ave, Cambridge, MA 02139, USA. ======================================================================= */ #include "stdio.h" #include "stdlib.h" #include "string.h" #include "c50lib.h" /* ======================================================================= */ /* #define statements */ /* ======================================================================= */ #ifndef QUASISTATIC #define QUASISTATIC static #endif #define NUM_OPCODES (sizeof(opcodes) / sizeof(opcodes[0])) #define read_bit(var, bit) ((int) (((var) >> (bit)) & 1)) #define set_bit(var, flag, bit) \ var = (var & ~(1 << bit)) | (flag ? (1 << bit) : 0) #define SIGN_BIT 0x80000000L #define SIGN32(n) ((n) & SIGN_BIT) typedef void (*voidfunc) (void); typedef struct { voidfunc f; char *opname; int andmask, pattern; voidfunc rpt_prep; } instruction_format; enum PHASE { FETCH = 0, DECODE = 1, OPERAND = 2, EXECUTE = 3 }; typedef struct { char valid; int instruction; voidfunc f; uint operand_address, spare_arg; long int operand, old_accum; } pipeline_layer; QUASISTATIC pipeline_layer pipeline[4]; /* ======================================================================= */ /* Static Functions */ /* ======================================================================= */ static int on_chip_ram (int a); static int get_operand_address (enum PHASE); static long int sign_extend (long int x, int n); static void sign_extend_operand (void); static void get_operand (void); static int check_ar_lock (int arx); static int bcnd_helper (int instruc); static int detect_overflow (long number_added); static void saturate_overflow (long number_added); static void add_operand (int c_in); static void sub_operand (int c_in); static long int shifted_p (void); static void repeat_instruction (void); static int c50_hardware_pop (void); static void c50_hardware_push (int d); static void check_dmov_okay (int addr, char *instruc_name); static int lookup (int instruc); static void service_pending_interrupts (void); static void Blkd_rpt_prep (void); static void Tblr_rpt_prep (void); static void Abs (void); static void Add1 (void); static void Add2 (void); static void Add3 (void); static void Add4 (void); static void Addc (void); static void Addb (void); static void Adds (void); static void Addt (void); static void Adrk (void); static void And1 (void); static void And2 (void); static void And3 (void); static void Andb (void); static void Apac (void); static void Apl1 (void); static void Apl2 (void); static void B (void); static void Bd (void); static void Bacc (void); static void Baccd (void); static void Banz (void); static void Banzd (void); static void Bcnd (void); static void Bcndd (void); static void Bit (void); static void Bitt (void); static void Bldd1 (void); static void Bldd2 (void); static void Bldd3 (void); static void Bldd4 (void); static void Bldp (void); static void Blpd1 (void); static void Blpd2 (void); static void Cala (void); static void Calad (void); static void Call (void); static void Calld (void); static void Cc (void); static void Ccd (void); static void Clrc_ovm (void); static void Clrc_sxm (void); static void Clrc_hm (void); static void Clrc_tc (void); static void Clrc_c (void); static void Clrc_cnf (void); static void Clrc_intm (void); static void Clrc_xf (void); static void Cmpl (void); static void Cmpr (void); static void Cpl1 (void); static void Cpl2 (void); static void Crgt (void); static void Crlt (void); static void Dmov (void); static void Exar (void); static void Idle (void); static void Idle2 (void); static void In (void); static void Intr (void); static void Lacb (void); static void Lacc1 (void); static void Lacc2 (void); static void Lacc3 (void); static void Lacl1 (void); static void Lacl2 (void); static void Lact (void); static void Lamm (void); static void Lar1 (void); static void Lar2 (void); static void Lar3 (void); static void Ldp1 (void); static void Ldp2 (void); static void Lmmr (void); static void Lph (void); static void Lst1 (void); static void Lst2 (void); static void Lt (void); static void Lta (void); static void Ltd (void); static void Ltp (void); static void Lts (void); static void Mac (void); static void Macd (void); static void Madd (void); static void Mads (void); static void Mar (void); static void Mpy1 (void); static void Mpy2 (void); static void Mpy3 (void); static void Mpya (void); static void Mpys (void); static void Mpyu (void); static void Neg (void); static void Nmi (void); static void Nop (void); static void Norm (void); static void Opl1 (void); static void Opl2 (void); static void Or1 (void); static void Or2 (void); static void Or3 (void); static void Orb (void); static void Out (void); static void Pac (void); static void Pop (void); static void Popd (void); static void Pshd (void); static void Push (void); static void Ret (void); static void Retd (void); static void Retc (void); static void Retcd (void); static void Rete (void); static void Reti (void); static void Rol (void); static void Rolb (void); static void Ror (void); static void Rorb (void); static void Rpt1 (void); static void Rpt2 (void); static void Rpt3 (void); static void Rptb (void); static void Rptz (void); static void Sacb (void); static void Sach (void); static void Sacl (void); static void Samm (void); static void Sar (void); static void Sath (void); static void Satl (void); static void Sbb (void); static void Sbbb (void); static void Sbrk (void); static void Setc_ovm (void); static void Setc_sxm (void); static void Setc_hm (void); static void Setc_tc (void); static void Setc_c (void); static void Setc_cnf (void); static void Setc_intm (void); static void Setc_xf (void); static void Sfl (void); static void Sflb (void); static void Sfr (void); static void Sfrb (void); static void Smmr (void); static void Spac (void); static void Sph (void); static void Spl (void); static void Splk (void); static void Spm (void); static void Sqra (void); static void Sqrs (void); static void Sst1 (void); static void Sst2 (void); static void Sub1 (void); static void Sub2 (void); static void Sub3 (void); static void Sub4 (void); static void Subb (void); static void Subc (void); static void Subs (void); static void Subt (void); static void Tblr (void); static void Tblw (void); static void Xc (void); static void Xor1 (void); static void Xor2 (void); static void Xor3 (void); static void Xorb (void); static void Xpl1 (void); static void Xpl2 (void); static void Zalr (void); static void Zap (void); static void Zpr (void); /* ======================================================================= */ /* Public Variables */ /* ======================================================================= */ /* Registers */ int program_ram, ovly; int arp, ov, ovm, intm, dp; /* st0 */ int arb, cnf, tc, sxm, c, hm, fsm, xf, fo, txm, pm; /* st1 */ long int accumulator, accb, p_register; uint pc; int dbmr, treg0, treg1, treg2, trm, _stack[8], _sp, ar[8], arcr; int mp_mc_mode; int bio; int drr, dxr, tim, prd, imr, greg; /* Registers that didn't appear in the C25 */ int ifr, pmst, rptc, brcr, pasr, paer, indx, cbsr1, cber1, cbsr2, cber2; int cbcr, bmar, spc, tcr, pdwsr, iowsr, cwsr; int trcv, tdxr, tspc, tcsr, trta, trad; /* What the hell is braf? */ int braf; unsigned long int steps_taken, cycles; char error_string[100]; /* ======================================================================= */ /* Static Variables */ /* ======================================================================= */ static int ar_lock[8], program_memory_accesses, saram_accesses, daram_accesses, io_port_accesses, pending_interrupts, idle_mode = 0, pfc, repeating; static enum PHASE processor_phase; static instruction_format opcodes[] = { {Abs, "Abs", 0xFFFF, 0xBE00, NULL}, {Add1, "Add1", 0xF000, 0x2000, NULL}, {Add2, "Add2", 0xFF00, 0xB800, NULL}, {Add3, "Add3", 0xFFF0, 0xBF90, NULL}, {Add4, "Add4", 0xFF00, 0x6100, NULL}, {Addb, "Addb", 0xFFFF, 0xBE10, NULL}, {Addc, "Addc", 0xFF00, 0x6000, NULL}, {Adds, "Adds", 0xFF00, 0x6200, NULL}, {Addt, "Addt", 0xFF00, 0x6300, NULL}, {Adrk, "Adrk", 0xFF00, 0x7800, NULL}, {And1, "And1", 0xFF00, 0x6E00, NULL}, {And2, "And2", 0xFFF0, 0xBFB0, NULL}, {And3, "And3", 0xFFFF, 0xBE81, NULL}, {Andb, "Andb", 0xFFFF, 0xBE12, NULL}, {Apac, "Apac", 0xFFFF, 0xBE04, NULL}, {Apl1, "Apl1", 0xFF00, 0x5A00, NULL}, {Apl2, "Apl2", 0xFF00, 0x5E00, NULL}, {B, "B", 0xFF80, 0x7980, NULL}, {Bd, "Bd", 0xFF80, 0x7D80, NULL}, {Bacc, "Bacc", 0xFFFF, 0xBE20, NULL}, {Baccd, "Baccd", 0xFFFF, 0xBE21, NULL}, {Banz, "Banz", 0xFF80, 0x7B80, NULL}, {Banzd, "Banzd", 0xFF80, 0x7F80, NULL}, {Bcnd, "Bcnd", 0xFC00, 0xE000, NULL}, {Bcndd, "Bcndd", 0xFC00, 0xF000, NULL}, {Bit, "Bit", 0xF000, 0x4000, NULL}, {Bitt, "Bitt", 0xFF00, 0x6F00, NULL}, /* need implementing */ {Bldd1, "Bldd1", 0xFF00, 0xA800, Blkd_rpt_prep}, {Bldd2, "Bldd2", 0xFF00, 0xA900, Blkd_rpt_prep}, {Bldd3, "Bldd3", 0xFF00, 0xAC00, Blkd_rpt_prep}, {Bldd4, "Bldd4", 0xFF00, 0xAD00, Blkd_rpt_prep}, {Bldp, "Bldp", 0xFF00, 0x5700, Blkd_rpt_prep}, {Blpd1, "Blpd1", 0xFF00, 0xA500, Blkd_rpt_prep}, {Blpd2, "Blpd2", 0xFF00, 0xA400, Blkd_rpt_prep}, {Cala, "Cala", 0xFFFF, 0xBE30, NULL}, {Calad, "Calad", 0xFFFF, 0xBE3D, NULL}, {Call, "Call", 0xFF00, 0x7A00, NULL}, {Calld, "Calld", 0xFF00, 0x7E00, NULL}, {Cc, "Cc", 0xFC00, 0xE800, NULL}, {Ccd, "Ccd", 0xFC00, 0xF800, NULL}, {Clrc_ovm, "Clrc_ovm", 0xFFFF, 0xBE42, NULL}, {Clrc_sxm, "Clrc_sxm", 0xFFFF, 0xBE46, NULL}, {Clrc_hm, "Clrc_hm", 0xFFFF, 0xBE48, NULL}, {Clrc_tc, "Clrc_tc", 0xFFFF, 0xBE4A, NULL}, {Clrc_c, "Clrc_c", 0xFFFF, 0xBE4E, NULL}, {Clrc_cnf, "Clrc_cnf", 0xFFFF, 0xBE44, NULL}, {Clrc_intm, "Clrc_intm", 0xFFFF, 0xBE40, NULL}, {Clrc_xf, "Clrc_xf", 0xFFFF, 0xBE4C, NULL}, {Cmpl, "Cmpl", 0xFFFF, 0xBE01, NULL}, {Cmpr, "Cmpr", 0xFFFC, 0xBE44, NULL}, {Cpl1, "Cpl1", 0xFF00, 0x5B00, NULL}, {Cpl2, "Cpl2", 0xFF00, 0x5F00, NULL}, {Crgt, "Crgt", 0xFFFF, 0xBE1B, NULL}, /* one of these is a typo in */ {Crlt, "Crlt", 0xFFFF, 0xBE1B, NULL}, /* the TI data book */ {Dmov, "Dmov", 0xFF00, 0x7700, NULL}, {Exar, "Exar", 0xFFFF, 0xBE1D, NULL}, {Idle, "Idle", 0xFFFF, 0xBE22, NULL}, {Idle2, "Idle2", 0xFF00, 0xBE23, NULL}, {In, "In", 0xFF00, 0xAF00, NULL}, {Intr, "Intr", 0xFFE0, 0xBE60, NULL}, {Lacb, "Lacb", 0xFFFF, 0xBE1F, NULL}, {Lacc1, "Lacc1", 0xF000, 0x1000, NULL}, {Lacc2, "Lacc2", 0xFFF0, 0xBF80, NULL}, {Lacc3, "Lacc3", 0xFF00, 0x6A00, NULL}, {Lacl1, "Lacl1", 0xFF00, 0x6900, NULL}, {Lacl2, "Lacl2", 0xFF00, 0xB900, NULL}, {Lact, "Lact", 0xFF00, 0x6B00, NULL}, {Lamm, "Lamm", 0xFF00, 0x0800, NULL}, {Lar1, "Lar1", 0xF800, 0x0000, NULL}, {Lar2, "Lar2", 0xF800, 0xB000, NULL}, {Lar3, "Lar3", 0xFFF8, 0xBF08, NULL}, {Ldp1, "Ldp1", 0xFF00, 0x0D00, NULL}, {Ldp2, "Ldp2", 0xFE00, 0xBC00, NULL}, {Lmmr, "Lmmr", 0xFF00, 0x8900, NULL}, {Lph, "Lph", 0xFF00, 0x7500, NULL}, {Lst1, "Lst1", 0xFF00, 0x0E00, NULL}, {Lst2, "Lst2", 0xFF00, 0x0F00, NULL}, {Lt, "Lt", 0xFF00, 0x7300, NULL}, {Lta, "Lta", 0xFF00, 0x7000, NULL}, {Ltd, "Ltd", 0xFF00, 0x7200, NULL}, {Ltp, "Ltp", 0xFF00, 0x7100, NULL}, {Lts, "Lts", 0xFF00, 0x7400, NULL}, {Mac, "Mac", 0xFF00, 0xA200, NULL}, {Macd, "Macd", 0xFF00, 0xA300, NULL}, {Madd, "Madd", 0xFF00, 0xAB00, NULL}, {Mads, "Mads", 0xFF00, 0xAA00, NULL}, /* Nop comes early in the table, otherwise it's decoded as Mar. * Functionally it doesn't matter, but it makes listings more confusing. */ {Nop, "Nop", 0xFFFF, 0x8B00, NULL}, {Mar, "Mar", 0xFF00, 0x8B00, NULL}, {Mpy1, "Mpy1", 0xFF00, 0x5400, NULL}, {Mpy2, "Mpy2", 0xE000, 0xC000, NULL}, {Mpy3, "Mpy3", 0xFFFF, 0xBE80, NULL}, {Mpya, "Mpya", 0xFF00, 0x5000, NULL}, {Mpys, "Mpys", 0xFF00, 0x5100, NULL}, {Mpyu, "Mpyu", 0xFF00, 0x5500, NULL}, {Neg, "Neg", 0xFFFF, 0xBE02, NULL}, {Nmi, "Nmi", 0xFFFF, 0xBE52, NULL}, {Norm, "Norm", 0xFF80, 0xA080, NULL}, {Opl1, "Opl1", 0xFF00, 0x5900, NULL}, {Opl2, "Opl2", 0xFF00, 0x5D00, NULL}, {Or1, "Or1", 0xFF00, 0x6D00, NULL}, {Or2, "Or2", 0xFFF0, 0xBFC0, NULL}, {Or3, "Or3", 0xFFFF, 0xBE82, NULL}, {Orb, "Orb", 0xFFFF, 0xBE13, NULL}, {Out, "Out", 0xFF00, 0x0C00, NULL}, {Pac, "Pac", 0xFFFF, 0xBE03, NULL}, {Pop, "Pop", 0xFFFF, 0xBE32, NULL}, {Popd, "Popd", 0xFF00, 0x8A00, NULL}, {Pshd, "Pshd", 0xFF00, 0x7600, NULL}, {Push, "Push", 0xFFFF, 0xBE3C, NULL}, {Ret, "Ret", 0xFFFF, 0xEF00, NULL}, {Retd, "Retd", 0xFFFF, 0xFF00, NULL}, {Retc, "Retc", 0xFC00, 0xEE00, NULL}, {Retcd, "Retcd", 0xFC00, 0xFE00, NULL}, {Rete, "Rete", 0xFFFF, 0xBE3A, NULL}, {Reti, "Reti", 0xFFFF, 0xBE38, NULL}, {Rol, "Rol", 0xFF00, 0xBE0C, NULL}, {Rolb, "Rolb", 0xFF00, 0xBE14, NULL}, {Ror, "Ror", 0xFF00, 0xBE0D, NULL}, {Rorb, "Rorb", 0xFF00, 0xBE15, NULL}, {Rpt1, "Rpt1", 0xFF00, 0x0B00, NULL}, {Rpt2, "Rpt2", 0xFFFF, 0xBEC4, NULL}, {Rpt3, "Rpt3", 0xFF00, 0xBB00, NULL}, {Rptb, "Rptb", 0xFF00, 0xBEC6, NULL}, {Rptz, "Rptz", 0xFF00, 0xBEC5, NULL}, {Sacb, "Sacb", 0xFF00, 0xBE1E, NULL}, {Sach, "Sach", 0xF800, 0x9800, NULL}, {Sacl, "Sacl", 0xF800, 0x9000, NULL}, {Samm, "Samm", 0xFF00, 0x8800, NULL}, {Sar, "Sar", 0xF800, 0x8000, NULL}, {Sath, "Sath", 0xFFFF, 0xBE5A, NULL}, /* another pair of typos in */ {Satl, "Satl", 0xFFFF, 0xBE5A, NULL}, /* the TI data book */ {Sbb, "Sbb", 0xFFFF, 0xBE18, NULL}, {Sbbb, "Sbbb", 0xFFFF, 0xBE19, NULL}, {Sbrk, "Sbrk", 0xFF00, 0x7C00, NULL}, {Setc_ovm, "Setc_ovm", 0xFFFF, 0xBE43, NULL}, {Setc_sxm, "Setc_sxm", 0xFFFF, 0xBE47, NULL}, {Setc_hm, "Setc_hm", 0xFFFF, 0xBE49, NULL}, {Setc_tc, "Setc_tc", 0xFFFF, 0xBE4B, NULL}, {Setc_c, "Setc_c", 0xFFFF, 0xBE4F, NULL}, {Setc_cnf, "Setc_cnf", 0xFFFF, 0xBE4D, NULL}, {Setc_intm, "Setc_intm", 0xFFFF, 0xBE45, NULL}, {Setc_xf, "Setc_xf", 0xFFFF, 0xBE41, NULL}, {Sfl, "Sfl", 0xFFFF, 0xBE09, NULL}, {Sflb, "Sflb", 0xFFFF, 0xBE16, NULL}, {Sfr, "Sfr", 0xFFFF, 0xBE0A, NULL}, {Sfrb, "Sfrb", 0xFFFF, 0xBE17, NULL}, {Smmr, "Smmr", 0xFF00, 0x0900, NULL}, {Spac, "Spac", 0xFFFF, 0xBE05, NULL}, {Sph, "Sph", 0xFF00, 0x8D00, NULL}, {Spl, "Spl", 0xFF00, 0x8C00, NULL}, {Splk, "Splk", 0xFF00, 0xAE00, NULL}, {Spm, "Spm", 0xFFFC, 0xBF00, NULL}, {Sqra, "Sqra", 0xFF00, 0x5200, NULL}, {Sqrs, "Sqrs", 0xFF00, 0x5300, NULL}, {Sst1, "Sst1", 0xFF00, 0x8E00, NULL}, {Sst2, "Sst2", 0xFF00, 0x8F00, NULL}, {Sub1, "Sub1", 0xF000, 0x3000, NULL}, {Sub2, "Sub2", 0xFF00, 0x6500, NULL}, {Sub3, "Sub3", 0xFF00, 0xBA00, NULL}, {Sub4, "Sub4", 0xFFF0, 0xBFA0, NULL}, {Subb, "Subb", 0xFF00, 0x6400, NULL}, {Subc, "Subc", 0xFF00, 0x0A00, NULL}, {Subs, "Subs", 0xFF00, 0x6600, NULL}, {Subt, "Subt", 0xFF00, 0x6700, NULL}, {Tblr, "Tblr", 0xFF00, 0xA600, NULL}, {Tblw, "Tblw", 0xFF00, 0xA700, NULL}, {Xc, "Xc", 0xEC00, 0xE400, NULL}, {Xor1, "Xor1", 0xFF00, 0x6C00, NULL}, {Xor2, "Xor2", 0xFFF0, 0xBFD0, NULL}, {Xor3, "Xor3", 0xFFFF, 0xBE83, NULL}, {Xorb, "Xorb", 0xFFFF, 0xBE1A, NULL}, {Xpl1, "Xpl1", 0xFF00, 0x5800, NULL}, {Xpl2, "Xpl2", 0xFF00, 0x5C00, NULL}, {Zalr, "Zalr", 0xFF00, 0x6800, NULL}, {Zap, "Zap", 0xFFFF, 0xBE59, NULL}, {Zpr, "Zpr", 0xFFFF, 0xBE58, NULL} }; /* ======================================================================= */ /* Accessing Memory */ /* ======================================================================= */ /* Some memory blocks are internal to the C50 */ static int on_chip_rom[0x800]; static int on_chip_saram[0x2400]; /* single-access-per-cycle SRAM */ static int on_chip_daram_b0[0x100]; /* double-access-per-cycle SRAM */ static int on_chip_daram_b1[0x200]; static int on_chip_daram_b2[0x20]; void write_program_memory (uint a, int d) { if (!mp_mc_mode && a < 0x800) { on_chip_rom[a] = d; program_memory_accesses++; return; } if (a >= 0x800 && a < 0x2C00 && program_ram) { on_chip_saram[a - 0x800] = d; return; } if (cnf && a >= 0xFE00) { on_chip_daram_b0[a - 0xFE00] = d; return; } write_program_off_chip (a, d); } int read_program_memory (uint a) { if (!mp_mc_mode && a < 0x800) { program_memory_accesses++; return on_chip_rom[a]; } if (a >= 0x800 && a < 0x2C00 && program_ram) { return on_chip_saram[a - 0x800]; saram_accesses++; } if (cnf && a >= 0xFE00) { return on_chip_daram_b0[a - 0xFE00]; daram_accesses++; } return read_program_off_chip (a); } static int memory_mapped_oops; static int * memory_mapped_stuff (uint addr) { switch (addr) { case 0x04: /* Processor registers */ return &imr; case 0x05: return &greg; case 0x06: return 𝔦 case 0x07: return &pmst; case 0x08: return &rptc; case 0x09: return &brcr; case 0x0A: return &pasr; case 0x0B: return &paer; case 0x0C: return &treg0; case 0x0D: return &treg1; case 0x0E: return &treg2; case 0x0F: return &dbmr; case 0x10: return &ar[0]; case 0x11: return &ar[1]; case 0x12: return &ar[2]; case 0x13: return &ar[3]; case 0x14: return &ar[4]; case 0x15: return &ar[5]; case 0x16: return &ar[6]; case 0x17: return &ar[7]; case 0x18: return &indx; case 0x19: return &arcr; case 0x1A: return &cbsr1; case 0x1B: return &cber1; case 0x1C: return &cbsr2; case 0x1D: return &cber2; case 0x1E: return &cbcr; case 0x1F: return &bmar; case 0x20: /* Peripheral registers */ return &drr; case 0x21: return &dxr; case 0x22: return &spc; case 0x24: return &tim; case 0x25: return &prd; case 0x26: return &tcr; case 0x28: return &pdwsr; case 0x29: return &iowsr; case 0x2A: return &cwsr; case 0x30: return &trcv; case 0x31: return &tdxr; case 0x32: return &tspc; case 0x33: return &tcsr; case 0x34: return &trta; case 0x35: return &trad; } sprintf (error_string, "Undefined memory-mapped address %04X", addr); handle_error (); return &memory_mapped_oops; } void write_data_memory (uint a, int d) { if (a < 0x50) { *memory_mapped_stuff (a) = d; return; } if (a >= 0x50 && a < 0x60) { io_port_accesses++; write_io_port (a, d); return; } if (a >= 0x60 && a < 0x80) { daram_accesses++; on_chip_daram_b2[a - 0x60] = d; return; } if (a >= 0x80 && a < 0x100) { sprintf (error_string, "Attempt to write to reserved data memory at %04X", a); handle_error (); return; } if (a >= 0x100 && a < 0x300) { if (!cnf) { daram_accesses++; on_chip_daram_b0[a - 0x100] = d; } else { sprintf (error_string, "Attempt to write to reserved data memory at %04X", a); handle_error (); } return; } if (a >= 0x300 && a < 0x500) { daram_accesses++; on_chip_daram_b1[a - 0x300] = d; return; } if (a >= 0x500 && a < 0x800) { sprintf (error_string, "Attempt to write to reserved data memory at %04X", a); handle_error (); return; } if (a >= 0x800 && a < 0x2C00 && ovly) { saram_accesses++; on_chip_saram[a - 0x800] = d; return; } write_data_off_chip (a, d); } int read_data_memory (uint a) { if (a < 0x50) return *memory_mapped_stuff (a); if (a >= 0x50 && a < 0x60) { io_port_accesses++; return read_io_port (a); } if (a >= 0x60 && a < 0x80) { daram_accesses++; return on_chip_daram_b2[a - 0x60]; } if (a >= 0x80 && a < 0x100) { sprintf (error_string, "Attempt to write to reserved data memory at %04X", a); handle_error (); return 0; } if (a >= 0x100 && a < 0x300) { if (!cnf) { daram_accesses++; return on_chip_daram_b0[a - 0x100]; } else { sprintf (error_string, "Attempt to write to reserved data memory at %04X", a); handle_error (); } return 0; } if (a >= 0x300 && a < 0x500) { daram_accesses++; return on_chip_daram_b1[a - 0x300]; } if (a >= 0x500 && a < 0x800) { sprintf (error_string, "Attempt to write to reserved data memory at %04X", a); handle_error (); return 0; } if (a >= 0x800 && a < 0x2C00 && ovly) { saram_accesses++; return on_chip_saram[a - 0x800]; } return read_data_off_chip (a); } /* ======================================================================= */ /* Instruction helpers */ /* ======================================================================= */ static int on_chip_ram (int a) { if (a < 0x80) return 1; if (a >= 0x100 && a < 0x300) return !cnf; if (a >= 0x300 && a < 0x500) return 1; if (a >= 0x800 && a < 0x2C00) return ovly; return 0; } static int get_operand_address (enum PHASE ph) { int i, mask, r, s, carry; if ((pipeline[ph].instruction & 0x80) == 0) r = ((dp << 7) & 0xFF80) | (pipeline[ph].instruction & 0x7F); else { /* handle updates to AR(ARP) and ARP */ r = ar[arp]; s = ar[0]; switch ((pipeline[ph].instruction >> 4) & 7) { case 0: break; case 1: ar[arp]--; ar_lock[arp] = 1; break; case 2: ar[arp]++; ar_lock[arp] = 1; break; case 3: sprintf (error_string, "Bad addressing mode in instruction at %04X", pc); handle_error (); break; case 4: carry = 0; for (i = 0; i < 16; i++) { mask = 1 << (15 - i); carry = ((ar[arp] & mask) ? 1 : 0) - ((s & mask) ? 1 : 0) - carry; ar[arp] = (ar[arp] & ~mask) + ((carry & 1) ? mask : 0); carry = (carry >> 1) & 1; } ar_lock[arp] = 1; break; case 5: ar[arp] -= ar[0]; ar_lock[arp] = 1; break; case 6: ar[arp] += ar[0]; ar_lock[arp] = 1; break; case 7: carry = 0; for (i = 0; i < 16; i++) { mask = 1 << (15 - i); carry += ((ar[arp] & mask) ? 1 : 0) + ((s & mask) ? 1 : 0); ar[arp] = (ar[arp] & ~mask) + ((carry & 1) ? mask : 0); carry = (carry >> 1) & 1; } ar_lock[arp] = 1; break; } if (pipeline[ph].instruction & 8) { arb = arp; arp = (pipeline[ph].instruction & 7); } } pipeline[ph].operand_address = r; return r; } static int check_ar_lock (int arx) { if ((ar_lock[0] && arx == 0) || (ar_lock[1] && arx == 1) || (ar_lock[2] && arx == 2) || (ar_lock[3] && arx == 3) || (ar_lock[4] && arx == 4) || (ar_lock[5] && arx == 5) || (ar_lock[6] && arx == 6) || (ar_lock[7] && arx == 7)) return 1; return 0; } static long int sign_extend (long int x, int n) { long int y; y = ((long int) 1) << (n - 1); if (x & y) x |= -y; else x &= y - 1; return x; } static void sign_extend_operand (void) { if (sxm) pipeline[EXECUTE].operand = sign_extend (pipeline[EXECUTE].operand, 16); } static int bcnd_helper (int instruc) { int m = 0, mask; /* check the TP bits */ switch (instruc & 0x300) { case 0x000: return !bio; case 0x100: return tc; case 0x200: return !tc; case 0x300: /* we're not testing TP, fall thru to flags */ break; } /* check the ZLVC bits */ mask = instruc & 0x0F; if (c) m |= 1; if (ov) m |= 2; if (accumulator < 0) m |= 4; if (accumulator == 0) m |= 8; return (m & mask) == ((instruc >> 4) & mask); } static void get_operand (void) { pipeline[OPERAND].old_accum = accumulator; pipeline[OPERAND].operand = read_data_memory (pipeline[OPERAND].operand_address); } static int detect_overflow (long number_added) { if (!SIGN32 (number_added)) if (!SIGN32 (pipeline[EXECUTE].old_accum) && SIGN32 (accumulator)) return 1; if (SIGN32 (number_added)) if (SIGN32 (pipeline[EXECUTE].old_accum) && !SIGN32 (accumulator)) return 1; return 0; } static void saturate_overflow (long number_added) { if (!SIGN32 (number_added)) accumulator = ~SIGN_BIT; else accumulator = SIGN_BIT; } static void add_operand (int c_in) { int i; long mask; pipeline[EXECUTE].old_accum = accumulator; for (i = 0, mask = SIGN_BIT; i < 32; i++, mask >>= 1) { if ((accumulator & pipeline[EXECUTE].operand) & mask) { c = 1; goto c_done; } if ((~accumulator & ~pipeline[EXECUTE].operand) & mask) { c = 0; goto c_done; } } c = c_in; c_done: if (c_in) pipeline[EXECUTE].operand++; accumulator += pipeline[EXECUTE].operand; if (detect_overflow (pipeline[EXECUTE].operand)) { ov = 1; if (ovm) saturate_overflow (pipeline[EXECUTE].operand); } } static void sub_operand (int c_in) { if (c_in) pipeline[EXECUTE].operand++; pipeline[EXECUTE].operand = -pipeline[EXECUTE].operand; add_operand (0); } static long int shifted_p (void) { long int shp; switch (pm) { case 0: return p_register; case 1: return p_register << 1; case 2: return p_register << 4; default: shp = p_register >> 6; if (p_register & SIGN_BIT) shp |= 0xFC000000L; return shp; } } /* ? ? ? ? */ static void repeat_instruction (void) { #if 0 voidfunc g; int i, init_rptc; instruction = read_program_memory (pc++); i = lookup (instruction); if (i == -1) { sprintf (error_string, "Trying to repeat unknown opcode at address %04X", pc - 1); handle_error (); return; } repeating = 1; g = opcodes[i].rpt_prep; if (g != NULL) (*g) (); g = opcodes[i].f; init_rptc = rptc; while (rptc >= 0) { (*g) (); rptc--; } burn_cycles (opcodes[i].cycle_type, init_rptc + 1); repeating = 0; rptc = 0; #endif /* I haven't given a lot of thought yet to how to do repeat * instructions for the C50. */ } static int c50_hardware_pop (void) { _sp = (_sp - 1) & 7; return _stack[_sp]; } static void c50_hardware_push (int d) { _stack[_sp] = d; _sp = (_sp + 1) & 7; } static void check_dmov_okay (int addr, char *instruc_name) { /* For the instructions DMOV, LTD, and MACD, both addr and addr+1 must be in on-chip ram for the data move to work. */ if (on_chip_ram (addr) && on_chip_ram (addr + 1)) return; sprintf (error_string, "Instruction %s at %04X using non-internal " "data memory at address %04X", instruc_name, pc, addr); handle_error (); } /* ======================================================================= */ /* Lookup table, advance */ /* ======================================================================= */ static int lookup (int instruc) { int i; for (i = 0; i < NUM_OPCODES; i++) if ((instruc & opcodes[i].andmask) == opcodes[i].pattern) return i; return -1; } char * disassemble (int instruc) { int i; if ((i = lookup (instruc)) != -1) return opcodes[i].opname; return "ILLEGAL"; } void advance (void) { int i; service_pending_interrupts (); if (idle_mode) { /* the whole pipeline stands still */ cycles++; if (idle_mode < 2) { tim--; if (tim == 0) c50_interrupt (TINT); } return; } /* Move the whole pipeline down one */ memcpy (&pipeline[EXECUTE], &pipeline[OPERAND], sizeof (pipeline_layer)); memcpy (&pipeline[OPERAND], &pipeline[DECODE], sizeof (pipeline_layer)); /* Clear all memory access counts */ program_memory_accesses = 0; saram_accesses = 0; daram_accesses = 0; io_port_accesses = 0; /* Fetch an instruction (unless repeating) */ if (rptc == 0) { memcpy (&pipeline[DECODE], &pipeline[FETCH], sizeof (pipeline_layer)); pipeline[FETCH].instruction = read_program_memory (pc++); i = lookup (pipeline[FETCH].instruction); if (i != -1) { pipeline[FETCH].valid = 1; pipeline[FETCH].f = opcodes[i].f; } else pipeline[FETCH].valid = 0; } /* Do the stuff currently in pipeline */ for (i = 0; i < 8; i++) ar_lock[i] = 0; processor_phase = DECODE; if (pipeline[DECODE].valid) (*pipeline[DECODE].f) (); processor_phase = OPERAND; if (pipeline[OPERAND].valid) (*pipeline[OPERAND].f) (); processor_phase = EXECUTE; if (pipeline[EXECUTE].valid) (*pipeline[EXECUTE].f) (); while (daram_accesses > 0 || saram_accesses > 0 || program_memory_accesses > 0 || io_port_accesses > 0) { cycles++; daram_accesses -= 2; saram_accesses--; program_memory_accesses--; io_port_accesses--; } steps_taken++; if (rptc != 0) rptc--; } void c50_reset (void) { int i; pipeline[EXECUTE].valid = 0; pipeline[OPERAND].valid = 0; pipeline[DECODE].valid = 0; pipeline[FETCH].valid = 0; pc = 0; _sp = 0; rptc = 0; for (i = 0; i < 8; i++) { _stack[i] = 0; ar[i] = 0; } ov = 0; intm = 1; cnf = 0; sxm = 1; c = 1; hm = 1; fsm = 1; xf = 1; fo = 0; txm = 0; pm = 0; tim = 0xFFFF; prd = 0xFFFF; greg = 0; repeating = 0; idle_mode = 0; steps_taken = 0; cycles = 0; } /* ======================================================================= */ /* Interrupts */ /* ======================================================================= */ void c50_interrupt (enum int_type n) { switch (n) { case RS: c50_reset (); return; case INT0: pending_interrupts |= 1; return; case INT1: pending_interrupts |= 2; return; case INT2: pending_interrupts |= 4; return; case TINT: tim += prd; pending_interrupts |= 8; return; case RINT: pending_interrupts |= 0x10; return; case XINT: pending_interrupts |= 0x20; return; case TRAP: c50_hardware_push (pc); pc = 0x001E; intm = 1; idle_mode = 0; return; default: sprintf (error_string, "Illegal interrupt"); handle_error (); break; } } static int try_interrupt_bit (int n, int addr) { if (read_bit (imr & pending_interrupts, n)) { pending_interrupts &= ~(1 << n); c50_hardware_push (pc); pc = addr; intm = 1; idle_mode = 0; return 1; } return 0; } static void service_pending_interrupts (void) { if (intm) return; if (try_interrupt_bit (0, 0x0002)) return; if (try_interrupt_bit (1, 0x0004)) return; if (try_interrupt_bit (2, 0x0006)) return; if (try_interrupt_bit (3, 0x0018)) return; if (try_interrupt_bit (4, 0x001A)) return; if (try_interrupt_bit (5, 0x001C)) return; } /* ======================================================================= */ /* C50 instructions */ /* ======================================================================= */ /* Ancillary Functions */ static void Blkd_rpt_prep (void) { pfc = read_program_memory (pc++); } static void Tblr_rpt_prep (void) { pfc = (int) accumulator; } /* Real C50 Instructions */ static void Abs (void) { switch (processor_phase) { case DECODE: break; case OPERAND: break; case EXECUTE: /* exceptional case for 0x80000000, depending on OVF flag */ if (accumulator == 0x80000000L) { if (ovm) accumulator = ~SIGN_BIT; ov = 1; } else if (accumulator & SIGN_BIT) accumulator = -accumulator; break; } } static void Add1 (void) { switch (processor_phase) { case DECODE: get_operand_address (DECODE); break; case OPERAND: get_operand (); break; case EXECUTE: sign_extend_operand (); pipeline[EXECUTE].operand <<= (pipeline[EXECUTE].instruction >> 8) & 0x0F; add_operand (0); break; } } static void Add2 (void) { switch (processor_phase) { case DECODE: break; case OPERAND: break; case EXECUTE: pipeline[EXECUTE].operand = pipeline[EXECUTE].instruction & 0xFF; add_operand (0); break; } } static void Add3 (void) { switch (processor_phase) { case DECODE: /* The next fetched word is an argument for this operation * so mark it as an invalid instruction, so we don't try to * execute it later. */ pipeline[FETCH].valid = 0; break; case OPERAND: break; case EXECUTE: pipeline[EXECUTE].operand = pipeline[OPERAND].instruction; sign_extend_operand (); pipeline[EXECUTE].operand <<= (pipeline[EXECUTE].instruction & 0x0F); add_operand (0); break; } } static void Add4 (void) { switch (processor_phase) { case DECODE: get_operand_address (DECODE); break; case OPERAND: get_operand (); break; case EXECUTE: pipeline[EXECUTE].operand <<= 16; add_operand (0); break; } } static void Addb (void) { switch (processor_phase) { case DECODE: break; case OPERAND: break; case EXECUTE: pipeline[EXECUTE].operand = accb; add_operand (c); break; } } static void Addc (void) { switch (processor_phase) { case DECODE: get_operand_address (DECODE); break; case OPERAND: get_operand (); break; case EXECUTE: add_operand (c); break; } } static void Adds (void) { switch (processor_phase) { case DECODE: get_operand_address (DECODE); break; case OPERAND: get_operand (); break; case EXECUTE: pipeline[EXECUTE].operand &= 0xFFFF; add_operand (0); break; } } static void Addt (void) { int shift; switch (processor_phase) { case DECODE: get_operand_address (DECODE); break; case OPERAND: get_operand (); break; case EXECUTE: shift = treg1 & 15; pipeline[EXECUTE].operand <<= shift; add_operand (0); break; } } static void Adrk (void) { switch (processor_phase) { case DECODE: break; case OPERAND: break; case EXECUTE: if (!ar_lock[arp]) ar[arp] += pipeline[EXECUTE].instruction & 0xFF; break; } } static void And1 (void) { switch (processor_phase) { case DECODE: get_operand_address (DECODE); break; case OPERAND: get_operand (); break; case EXECUTE: accumulator &= pipeline[EXECUTE].operand; break; } } static void And2 (void) { switch (processor_phase) { case DECODE: /* The next fetched word is an argument for this operation * so mark it as an invalid instruction, so we don't try to * execute it later. */ pipeline[FETCH].valid = 0; pipeline[DECODE].operand = pipeline[FETCH].instruction & 0xFFFF; break; case OPERAND: break; case EXECUTE: accumulator &= pipeline[EXECUTE].operand; break; } } static void And3 (void) { switch (processor_phase) { case DECODE: /* The next fetched word is an argument for this operation * so mark it as an invalid instruction, so we don't try to * execute it later. */ pipeline[FETCH].valid = 0; pipeline[DECODE].operand = pipeline[FETCH].instruction << 16; break; case OPERAND: break; case EXECUTE: accumulator &= pipeline[EXECUTE].operand; break; } } static void Andb (void) { switch (processor_phase) { case DECODE: break; case OPERAND: break; case EXECUTE: accumulator &= accb; break; } } static void Apac (void) { switch (processor_phase) { case DECODE: break; case OPERAND: break; case EXECUTE: pipeline[EXECUTE].operand = shifted_p (); add_operand (0); break; } } static void Apl1 (void) { switch (processor_phase) { case DECODE: get_operand_address (DECODE); break; case OPERAND: get_operand (); break; case EXECUTE: write_data_memory (pipeline[EXECUTE].operand_address, pipeline[EXECUTE].operand & dbmr); break; } } static void Apl2 (void) { switch (processor_phase) { case DECODE: pipeline[FETCH].valid = 0; pipeline[DECODE].spare_arg = pipeline[FETCH].instruction; get_operand_address (DECODE); break; case OPERAND: get_operand (); break; case EXECUTE: write_data_memory (pipeline[EXECUTE].operand_address, pipeline[EXECUTE].operand & pipeline[EXECUTE].spare_arg); break; } } static void B (void) { switch (processor_phase) { case DECODE: pipeline[FETCH].valid = 0; get_operand_address (DECODE); break; case OPERAND: pipeline[FETCH].valid = 0; break; case EXECUTE: pipeline[FETCH].valid = 0; pc = pipeline[OPERAND].instruction; break; } } static void Bd (void) { switch (processor_phase) { case DECODE: pipeline[FETCH].valid = 0; get_operand_address (DECODE); break; case OPERAND: break; case EXECUTE: pc = pipeline[OPERAND].instruction; break; } } static void Bacc (void) { switch (processor_phase) { case DECODE: pc = (int) accumulator; break; case OPERAND: break; case EXECUTE: break; } } static void Baccd (void) { switch (processor_phase) { case DECODE: break; case OPERAND: break; case EXECUTE: pc = (int) accumulator; break; } } static void Banz (void) { switch (processor_phase) { case DECODE: pipeline[FETCH].valid = 0; if (ar[arp]) pc = pipeline[FETCH].instruction; break; case OPERAND: break; case EXECUTE: break; } } static void Banzd (void) { switch (processor_phase) { case DECODE: pipeline[FETCH].valid = 0; pipeline[DECODE].spare_arg = pipeline[FETCH].instruction; break; case OPERAND: break; case EXECUTE: if (ar[arp]) pc = pipeline[EXECUTE].spare_arg; break; } } static void Bcnd (void) { switch (processor_phase) { case DECODE: pipeline[FETCH].valid = 0; if (bcnd_helper (pipeline[DECODE].instruction)) pc = pipeline[FETCH].instruction; break; case OPERAND: break; case EXECUTE: break; } } static void Bcndd (void) { switch (processor_phase) { case DECODE: pipeline[FETCH].valid = 0; pipeline[DECODE].spare_arg = pipeline[FETCH].instruction; break; case OPERAND: break; case EXECUTE: if (bcnd_helper (pipeline[EXECUTE].instruction)) pc = pipeline[EXECUTE].spare_arg; break; } } static void Bit (void) { int shift; switch (processor_phase) { case DECODE: get_operand_address (DECODE); break; case OPERAND: get_operand (); break; case EXECUTE: shift = 15 - ((pipeline[EXECUTE].instruction >> 8) & 15); tc = (int) ((pipeline[EXECUTE].operand >> shift) & 1); break; } } static void Bitt (void) { int shift; switch (processor_phase) { case DECODE: get_operand_address (DECODE); break; case OPERAND: get_operand (); break; case EXECUTE: shift = 15 - (treg1 & 15); tc = (int) ((pipeline[EXECUTE].operand >> shift) & 1); break; } } /* they're c50-ish, but they don't do anything yet */ static void Bldd1 (void) { switch (processor_phase) { case DECODE: break; case OPERAND: break; case EXECUTE: break; } } static void Bldd2 (void) { switch (processor_phase) { case DECODE: break; case OPERAND: break; case EXECUTE: break; } } static void Bldd3 (void) { switch (processor_phase) { case DECODE: break; case OPERAND: break; case EXECUTE: break; } } static void Bldd4 (void) { switch (processor_phase) { case DECODE: break; case OPERAND: break; case EXECUTE: break; } } static void Bldp (void) { switch (processor_phase) { case DECODE: break; case OPERAND: break; case EXECUTE: break; } } static void Blpd1 (void) { switch (processor_phase) { case DECODE: break; case OPERAND: break; case EXECUTE: break; } } static void Blpd2 (void) { switch (processor_phase) { case DECODE: break; case OPERAND: break; case EXECUTE: break; } } static void Cala (void) { switch (processor_phase) { case DECODE: c50_hardware_push (pc); pc = (int) accumulator; break; case OPERAND: break; case EXECUTE: break; } } static void Calad (void) { switch (processor_phase) { case DECODE: break; case OPERAND: break; case EXECUTE: c50_hardware_push (pc); pc = (int) accumulator; break; } } static void Call (void) { switch (processor_phase) { case DECODE: pipeline[FETCH].valid = 0; get_operand_address (DECODE); break; case OPERAND: pipeline[FETCH].valid = 0; break; case EXECUTE: pipeline[FETCH].valid = 0; c50_hardware_push (pc); pc = pipeline[OPERAND].instruction; break; } } static void Calld (void) { switch (processor_phase) { case DECODE: pipeline[FETCH].valid = 0; get_operand_address (DECODE); break; case OPERAND: break; case EXECUTE: c50_hardware_push (pc); pc = pipeline[OPERAND].instruction; break; } } static void Cc (void) { switch (processor_phase) { case DECODE: pipeline[FETCH].valid = 0; get_operand_address (DECODE); pipeline[DECODE].spare_arg = bcnd_helper (pipeline[DECODE].instruction); break; case OPERAND: if (pipeline[OPERAND].spare_arg) pipeline[FETCH].valid = 0; break; case EXECUTE: if (pipeline[EXECUTE].spare_arg) { pipeline[FETCH].valid = 0; c50_hardware_push (pc); pc = pipeline[OPERAND].spare_arg; } break; } } static void Ccd (void) { switch (processor_phase) { case DECODE: pipeline[FETCH].valid = 0; get_operand_address (DECODE); break; case OPERAND: break; case EXECUTE: if (bcnd_helper (pipeline[EXECUTE].instruction)) { c50_hardware_push (pc); pc = pipeline[OPERAND].instruction; } break; } } static void Clrc_ovm (void) { switch (processor_phase) { case DECODE: break; case OPERAND: break; case EXECUTE: ovm = 0; break; } } static void Clrc_sxm (void) { switch (processor_phase) { case DECODE: break; case OPERAND: break; case EXECUTE: sxm = 0; break; } } static void Clrc_hm (void) { switch (processor_phase) { case DECODE: break; case OPERAND: break; case EXECUTE: hm = 0; break; } } static void Clrc_tc (void) { switch (processor_phase) { case DECODE: break; case OPERAND: break; case EXECUTE: tc = 0; break; } } static void Clrc_c (void) { switch (processor_phase) { case DECODE: break; case OPERAND: break; case EXECUTE: c = 0; break; } } static void Clrc_cnf (void) { switch (processor_phase) { case DECODE: break; case OPERAND: break; case EXECUTE: cnf = 0; break; } } static void Clrc_intm (void) { switch (processor_phase) { case DECODE: break; case OPERAND: break; case EXECUTE: intm = 0; break; } } static void Clrc_xf (void) { switch (processor_phase) { case DECODE: break; case OPERAND: break; case EXECUTE: xf = 0; break; } } static void Cmpl (void) { switch (processor_phase) { case DECODE: break; case OPERAND: break; case EXECUTE: accumulator = ~accumulator; break; } } static void Cmpr (void) { unsigned u, v; switch (processor_phase) { case DECODE: break; case OPERAND: break; case EXECUTE: u = ar[arp]; v = arcr; switch (pipeline[EXECUTE].instruction & 3) { case 0: tc = (u == v); break; case 1: tc = (u < v); break; case 2: tc = (u > v); break; case 3: tc = (u != v); break; } break; } } static void Cpl1 (void) { switch (processor_phase) { case DECODE: get_operand_address (DECODE); break; case OPERAND: get_operand (); break; case EXECUTE: if (pipeline[EXECUTE].operand == dbmr) tc = 1; else tc = 0; break; } } static void Cpl2 (void) { switch (processor_phase) { case DECODE: pipeline[FETCH].valid = 0; pipeline[DECODE].spare_arg = pipeline[FETCH].instruction; break; case OPERAND: break; case EXECUTE: if (pipeline[EXECUTE].spare_arg == dbmr) tc = 1; else tc = 0; break; } } static void Crgt (void) { switch (processor_phase) { case DECODE: break; case OPERAND: break; case EXECUTE: if ((long int) accumulator < (long int) accb) { accumulator = accb; c = 0; } else { accb = accumulator; c = 1; } break; } } static void Crlt (void) { switch (processor_phase) { case DECODE: break; case OPERAND: break; case EXECUTE: if ((long int) accumulator < (long int) accb) { accb = accumulator; c = 1; } else { accumulator = accb; c = 0; } break; } } static void Dmov (void) { uint x; switch (processor_phase) { case DECODE: get_operand_address (DECODE); break; case OPERAND: break; case EXECUTE: check_dmov_okay (pipeline[EXECUTE].operand_address, "DMOV"); x = read_data_memory (pipeline[EXECUTE].operand_address); pipeline[EXECUTE].operand_address++; write_data_memory (pipeline[EXECUTE].operand_address, x); break; } } static void Exar (void) { long int x; switch (processor_phase) { case DECODE: break; case OPERAND: break; case EXECUTE: x = accumulator; accumulator = accb; accb = x; break; } } static void Idle (void) { switch (processor_phase) { case DECODE: break; case OPERAND: break; case EXECUTE: intm = 0; idle_mode = 1; break; } } static void Idle2 (void) { switch (processor_phase) { case DECODE: break; case OPERAND: break; case EXECUTE: intm = 0; idle_mode = 2; break; } } static void In (void) { int port_addr; switch (processor_phase) { case DECODE: pipeline[FETCH].valid = 0; get_operand_address (DECODE); break; case OPERAND: break; case EXECUTE: port_addr = pipeline[DECODE].instruction; if (rptc != 0) while (rptc != 0) { write_data_memory (pipeline[EXECUTE].operand_address, read_io_port (port_addr)); port_addr++; rptc--; if (rptc != 0) get_operand_address (EXECUTE); } else write_data_memory (pipeline[EXECUTE].operand_address, read_io_port (port_addr)); break; } } /* do this later */ static void Intr (void) { switch (processor_phase) { case DECODE: break; case OPERAND: break; case EXECUTE: break; } } static void Lacb (void) { switch (processor_phase) { case DECODE: break; case OPERAND: break; case EXECUTE: accumulator = accb; break; } } static void Lacc1 (void) { switch (processor_phase) { case DECODE: get_operand_address (DECODE); break; case OPERAND: get_operand (); break; case EXECUTE: sign_extend_operand (); accumulator = (pipeline[EXECUTE].operand << ((pipeline[EXECUTE].instruction >> 8) & 0x0F)); break; } } static void Lacc2 (void) { switch (processor_phase) { case DECODE: pipeline[FETCH].valid = 0; pipeline[DECODE].operand = pipeline[FETCH].instruction; break; case OPERAND: break; case EXECUTE: sign_extend_operand (); accumulator = (pipeline[EXECUTE].operand << (pipeline[EXECUTE].instruction & 0x0F)); break; } } static void Lacc3 (void) { switch (processor_phase) { case DECODE: get_operand_address (DECODE); break; case OPERAND: get_operand (); break; case EXECUTE: accumulator = pipeline[EXECUTE].operand << 16; break; } } static void Lacl1 (void) { switch (processor_phase) { case DECODE: get_operand_address (DECODE); break; case OPERAND: get_operand (); break; case EXECUTE: accumulator = pipeline[EXECUTE].operand & 0xFFFF; break; } } static void Lacl2 (void) { switch (processor_phase) { case DECODE: break; case OPERAND: break; case EXECUTE: accumulator = pipeline[EXECUTE].instruction & 0xFF; break; } } static void Lact (void) { int shift; switch (processor_phase) { case DECODE: get_operand_address (DECODE); break; case OPERAND: get_operand (); break; case EXECUTE: shift = treg1 & 15; sign_extend_operand (); pipeline[EXECUTE].operand <<= shift; accumulator = pipeline[EXECUTE].operand; break; } } static void Lamm (void) { switch (processor_phase) { case DECODE: get_operand_address (DECODE); pipeline[DECODE].operand_address &= 0x7F; break; case OPERAND: get_operand (); break; case EXECUTE: accumulator = pipeline[EXECUTE].operand; break; } } static void Lar1 (void) { int arx; switch (processor_phase) { case DECODE: get_operand_address (DECODE); break; case OPERAND: get_operand (); break; case EXECUTE: arx = (pipeline[EXECUTE].instruction >> 8) & 0x07; if (pipeline[EXECUTE].instruction & 0x80) if (check_ar_lock (arx)) return; ar[arx] = (int) pipeline[EXECUTE].operand; break; } } static void Lar2 (void) { int arx; switch (processor_phase) { case DECODE: break; case OPERAND: break; case EXECUTE: arx = (pipeline[EXECUTE].instruction >> 8) & 0x07; ar[arx] = (int) pipeline[EXECUTE].instruction & 0xFF; break; } } static void Lar3 (void) { int arx; switch (processor_phase) { case DECODE: pipeline[FETCH].valid = 0; pipeline[DECODE].operand = pipeline[FETCH].instruction; break; case OPERAND: break; case EXECUTE: arx = pipeline[EXECUTE].instruction & 0x07; ar[arx] = (int) pipeline[EXECUTE].operand; break; } } static void Ldp1 (void) { switch (processor_phase) { case DECODE: get_operand_address (DECODE); break; case OPERAND: get_operand (); break; case EXECUTE: dp = pipeline[EXECUTE].operand & 0x1FF; break; } } static void Ldp2 (void) { switch (processor_phase) { case DECODE: break; case OPERAND: break; case EXECUTE: dp = pipeline[EXECUTE].instruction & 0x1FF; break; } } /* do this later */ static void Lmmr (void) { switch (processor_phase) { case DECODE: get_operand_address (DECODE); break; case OPERAND: get_operand (); break; case EXECUTE: break; } } static void Lph (void) { switch (processor_phase) { case DECODE: get_operand_address (DECODE); break; case OPERAND: get_operand (); break; case EXECUTE: p_register = (p_register & 0xFFFFL) | ((pipeline[EXECUTE].operand << 16) & 0xFFFF0000L); break; } } static void Lst1 (void) { switch (processor_phase) { case DECODE: break; case OPERAND: break; case EXECUTE: break; } } static void Lst2 (void) { switch (processor_phase) { case DECODE: break; case OPERAND: break; case EXECUTE: break; } } static void Lt (void) { switch (processor_phase) { case DECODE: get_operand_address (DECODE); break; case OPERAND: get_operand (); break; case EXECUTE: treg0 = (int) pipeline[EXECUTE].operand; if (!trm) { treg1 = treg0; treg2 = treg0; } break; } } static void Lta (void) { switch (processor_phase) { case DECODE: get_operand_address (DECODE); break; case OPERAND: get_operand (); break; case EXECUTE: treg0 = (int) pipeline[EXECUTE].operand; if (!trm) { treg1 = treg0; treg2 = treg0; } pipeline[EXECUTE].operand = shifted_p (); add_operand (0); break; } } static void Ltd (void) { switch (processor_phase) { case DECODE: get_operand_address (DECODE); break; case OPERAND: pipeline[OPERAND].operand = read_data_memory (pipeline[OPERAND].operand_address); break; case EXECUTE: check_dmov_okay (pipeline[EXECUTE].operand_address, "LTD"); treg0 = pipeline[EXECUTE].operand; if (!trm) { treg1 = treg0; treg2 = treg0; } write_data_memory (pipeline[EXECUTE].operand_address + 1, pipeline[EXECUTE].operand); pipeline[EXECUTE].operand = shifted_p (); add_operand (0); break; } } static void Ltp (void) { switch (processor_phase) { case DECODE: get_operand_address (DECODE); break; case OPERAND: get_operand (); break; case EXECUTE: treg0 = (int) pipeline[EXECUTE].operand; if (!trm) { treg1 = treg0; treg2 = treg0; } accumulator = shifted_p (); } } static void Lts (void) { switch (processor_phase) { case DECODE: break; case OPERAND: break; case EXECUTE: treg0 = (int) pipeline[EXECUTE].operand; if (!trm) { treg1 = treg0; treg2 = treg0; } pipeline[EXECUTE].operand = shifted_p (); sub_operand (0); break; } } static void Mac (void) { switch (processor_phase) { case DECODE: break; case OPERAND: break; case EXECUTE: if (!repeating) pfc = read_program_memory (pc++); pipeline[EXECUTE].operand = shifted_p (); add_operand (0); treg0 = (int) pipeline[EXECUTE].operand; if (!trm) { treg1 = treg0; treg2 = treg0; } p_register = treg0; p_register *= read_program_memory (pfc++); break; } } static void Macd (void) { int a; switch (processor_phase) { case DECODE: break; case OPERAND: break; case EXECUTE: if (!repeating) pfc = read_program_memory (pc++); pipeline[EXECUTE].operand = shifted_p (); add_operand (0); a = get_operand_address (DECODE); check_dmov_okay (a, "MACD"); treg0 = read_data_memory (a); if (!trm) { treg1 = treg0; treg2 = treg0; } p_register = treg0; p_register *= read_program_memory (pfc++); write_data_memory (a + 1, read_data_memory (a)); return; } } /* do this later */ static void Madd (void) { switch (processor_phase) { case DECODE: break; case OPERAND: break; case EXECUTE: break; } } /* do this later */ static void Mads (void) { switch (processor_phase) { case DECODE: break; case OPERAND: break; case EXECUTE: break; } } static void Mar (void) { switch (processor_phase) { case DECODE: get_operand_address (DECODE); break; case OPERAND: break; case EXECUTE: break; } } static void Mpy1 (void) { switch (processor_phase) { case DECODE: get_operand_address (DECODE); break; case OPERAND: get_operand (); break; case EXECUTE: p_register = pipeline[EXECUTE].operand * treg0; break; } } static void Mpy2 (void) { long int x; switch (processor_phase) { case DECODE: break; case OPERAND: break; case EXECUTE: x = pipeline[EXECUTE].instruction & 0x1FFF; if (x & 0x1000) x |= 0xFFFFF000L; p_register = x * treg0; break; } } static void Mpy3 (void) { switch (processor_phase) { case DECODE: pipeline[FETCH].valid = 0; pipeline[DECODE].operand = pipeline[FETCH].instruction; break; case OPERAND: break; case EXECUTE: p_register = treg0 * pipeline[EXECUTE].operand; break; } } static void Mpya (void) { long int x; switch (processor_phase) { case DECODE: get_operand_address (DECODE); break; case OPERAND: get_operand (); break; case EXECUTE: x = pipeline[EXECUTE].operand; pipeline[EXECUTE].operand = shifted_p (); add_operand (0); pipeline[EXECUTE].operand = x; p_register = pipeline[EXECUTE].operand * treg0; break; } } static void Mpys (void) { long int x; switch (processor_phase) { case DECODE: get_operand_address (DECODE); break; case OPERAND: get_operand (); break; case EXECUTE: x = pipeline[EXECUTE].operand; pipeline[EXECUTE].operand = shifted_p (); sub_operand (0); pipeline[EXECUTE].operand = x; p_register = pipeline[EXECUTE].operand * treg0; break; } } static void Mpyu (void) { unsigned long t, d; switch (processor_phase) { case DECODE: get_operand_address (DECODE); break; case OPERAND: get_operand (); break; case EXECUTE: d = pipeline[EXECUTE].operand; t = treg1; p_register = d * t; break; } } static void Neg (void) { switch (processor_phase) { case DECODE: break; case OPERAND: break; case EXECUTE: c = (accumulator == 0L); if (accumulator == SIGN_BIT) { if (ovm) accumulator = ~SIGN_BIT; ov = 1; } else accumulator = -accumulator; break; } } static void Nmi (void) { switch (processor_phase) { case DECODE: break; case OPERAND: break; case EXECUTE: break; } } static void Nop (void) { switch (processor_phase) { case DECODE: break; case OPERAND: break; case EXECUTE: /* fine just like this */ break; } } static void Norm (void) { switch (processor_phase) { case DECODE: break; case OPERAND: break; case EXECUTE: if (accumulator == 0) tc = 1; else { if (read_bit (accumulator, 31) == read_bit (accumulator, 30)) { tc = 0; accumulator <<= 1; get_operand_address (EXECUTE); } else tc = 1; } break; } } static void Opl1 (void) { switch (processor_phase) { case DECODE: get_operand_address (DECODE); break; case OPERAND: get_operand (); break; case EXECUTE: write_data_memory (pipeline[EXECUTE].operand_address, pipeline[EXECUTE].operand | dbmr); break; } } static void Opl2 (void) { switch (processor_phase) { case DECODE: pipeline[FETCH].valid = 0; get_operand_address (DECODE); break; case OPERAND: get_operand (); break; case EXECUTE: write_data_memory (pipeline[EXECUTE].operand_address, pipeline[EXECUTE].operand | pipeline[OPERAND].instruction); break; } } static void Or1 (void) { switch (processor_phase) { case DECODE: get_operand_address (DECODE); break; case OPERAND: get_operand (); break; case EXECUTE: accumulator |= (pipeline[EXECUTE].operand & 0xFFFF); break; } } static void Or2 (void) { switch (processor_phase) { case DECODE: pipeline[FETCH].valid = 0; break; case OPERAND: break; case EXECUTE: accumulator |= ((long int) pipeline[OPERAND].instruction) << (pipeline[EXECUTE].instruction & 0x0F); break; } } static void Or3 (void) { switch (processor_phase) { case DECODE: pipeline[FETCH].valid = 0; break; case OPERAND: break; case EXECUTE: accumulator |= ((long int) pipeline[OPERAND].instruction) << 16; break; } } static void Orb (void) { switch (processor_phase) { case DECODE: break; case OPERAND: break; case EXECUTE: accumulator |= accb; break; } } static void Out (void) { int port_addr; switch (processor_phase) { case DECODE: pipeline[FETCH].valid = 0; get_operand_address (DECODE); break; case OPERAND: get_operand (); break; case EXECUTE: port_addr = pipeline[DECODE].instruction; if (rptc != 0) while (rptc != 0) { write_io_port (port_addr, pipeline[EXECUTE].operand); port_addr++; rptc--; if (rptc != 0) { get_operand_address (EXECUTE); get_operand (); } } else write_io_port (port_addr, pipeline[EXECUTE].operand); break; } } static void Pac (void) { switch (processor_phase) { case DECODE: break; case OPERAND: break; case EXECUTE: accumulator = shifted_p (); break; } } static void Pop (void) { switch (processor_phase) { case DECODE: break; case OPERAND: break; case EXECUTE: accumulator = c50_hardware_pop (); break; } } static void Popd (void) { switch (processor_phase) { case DECODE: get_operand_address (DECODE); break; case OPERAND: break; case EXECUTE: write_data_memory (pipeline[EXECUTE].operand_address, c50_hardware_pop ()); break; } } static void Pshd (void) { switch (processor_phase) { case DECODE: get_operand_address (DECODE); break; case OPERAND: get_operand (); break; case EXECUTE: c50_hardware_push ((int) pipeline[EXECUTE].operand); break; } } static void Push (void) { switch (processor_phase) { case DECODE: break; case OPERAND: break; case EXECUTE: c50_hardware_push ((int) accumulator); break; } } static void Ret (void) { switch (processor_phase) { case DECODE: pipeline[FETCH].valid = 0; break; case OPERAND: pipeline[FETCH].valid = 0; break; case EXECUTE: pipeline[FETCH].valid = 0; pc = c50_hardware_pop (); break; } } static void Retd (void) { switch (processor_phase) { case DECODE: break; case OPERAND: break; case EXECUTE: pipeline[FETCH].valid = 0; pc = c50_hardware_pop (); break; } } static void Retc (void) { switch (processor_phase) { case DECODE: /* If we test the flags here, is that meaningful? But if we don't * test the flags here, we won't know that we should bomb the next * three instructions until it's too late. Some of them might try * to do ARAU operations in the meanwhile. * * One solution is to maintain multiple sets of registers to * represent the different ways the processor could go over 3 or 4 * instructions. There can't really be 8 or 16 sets of registers. * * We'll face the same dilemma with the Cc instruction, or any * other conditional non-delayed thing. */ pipeline[DECODE].spare_arg = bcnd_helper (pipeline[DECODE].instruction); if (pipeline[DECODE].spare_arg) pipeline[FETCH].valid = 0; break; case OPERAND: if (pipeline[OPERAND].spare_arg) pipeline[FETCH].valid = 0; break; case EXECUTE: if (pipeline[EXECUTE].spare_arg) { pipeline[FETCH].valid = 0; pc = c50_hardware_pop (); } break; } } static void Retcd (void) { switch (processor_phase) { case DECODE: break; case OPERAND: break; case EXECUTE: if (bcnd_helper (pipeline[EXECUTE].instruction)) { pipeline[FETCH].valid = 0; pc = c50_hardware_pop (); } break; } } /* do this later */ static void Rete (void) { switch (processor_phase) { case DECODE: break; case OPERAND: break; case EXECUTE: break; } } /* do this later */ static void Reti (void) { switch (processor_phase) { case DECODE: break; case OPERAND: break; case EXECUTE: break; } } static void Rol (void) { switch (processor_phase) { case DECODE: break; case OPERAND: break; case EXECUTE: if (accumulator & SIGN_BIT) { accumulator = (accumulator << 1) + c; c = 1; } else { accumulator = (accumulator << 1) + c; c = 0; } break; } } static void Rolb (void) { switch (processor_phase) { case DECODE: break; case OPERAND: break; case EXECUTE: if (accumulator & SIGN_BIT) { if (accb & SIGN_BIT) { accb = (accb << 1) + c; accumulator = (accumulator << 1) + 1; } else { accb = (accb << 1) + c; accumulator = (accumulator << 1); } c = 1; } else { if (accb & SIGN_BIT) { accb = (accb << 1) + c; accumulator = (accumulator << 1) + 1; } else { accb = (accb << 1) + c; accumulator = (accumulator << 1); } c = 0; } break; } } static void Ror (void) { switch (processor_phase) { case DECODE: break; case OPERAND: break; case EXECUTE: if (accumulator & 1) { accumulator = (accumulator >> 1) + (c ? SIGN_BIT : 0); c = 1; } else { accumulator = (accumulator >> 1) + (c ? SIGN_BIT : 0); c = 0; } break; } } static void Rorb (void) { switch (processor_phase) { case DECODE: break; case OPERAND: break; case EXECUTE: if (accb & 1) { if (accumulator & 1) { accumulator = (accumulator >> 1) + (c ? SIGN_BIT : 0); accb = (accb >> 1) + 1; } else { accumulator = (accumulator >> 1) + (c ? SIGN_BIT : 0); accb = (accb >> 1) + 0; } c = 1; } else { if (accumulator & 1) { accumulator = (accumulator >> 1) + (c ? SIGN_BIT : 0); accb = (accb >> 1) + 1; } else { accumulator = (accumulator >> 1) + (c ? SIGN_BIT : 0); accb = (accb >> 1) + 0; } c = 0; } break; } } static void Rpt1 (void) { switch (processor_phase) { case DECODE: get_operand_address (DECODE); break; case OPERAND: get_operand (); rptc = (int) pipeline[OPERAND].operand + 1; repeating = 1; break; case EXECUTE: break; } } static void Rpt2 (void) { switch (processor_phase) { case DECODE: pipeline[FETCH].valid = 0; break; case OPERAND: rptc = pipeline[DECODE].instruction + 1; repeating = 1; break; case EXECUTE: break; } } static void Rpt3 (void) { switch (processor_phase) { case DECODE: break; case OPERAND: rptc = (pipeline[OPERAND].instruction & 0xFF) + 1; repeating = 1; break; case EXECUTE: break; } } static void Rptb (void) { switch (processor_phase) { case DECODE: pipeline[FETCH].valid = 0; break; case OPERAND: pipeline[OPERAND].spare_arg = pc; break; case EXECUTE: braf = 1; /* what the hell is braf?? */ pasr = pipeline[EXECUTE].spare_arg; paer = pipeline[OPERAND].instruction; break; } } static void Rptz (void) { switch (processor_phase) { case DECODE: pipeline[FETCH].valid = 0; break; case OPERAND: break; case EXECUTE: accumulator = 0; p_register = 0; rptc = pipeline[OPERAND].instruction; repeating = 1; break; } } static void Sacb (void) { switch (processor_phase) { case DECODE: break; case OPERAND: break; case EXECUTE: accb = accumulator; break; } } static void Sach (void) { switch (processor_phase) { case DECODE: break; case OPERAND: break; case EXECUTE: pipeline[EXECUTE].operand = accumulator; pipeline[EXECUTE].operand <<= (pipeline[EXECUTE].instruction >> 8) & 7; write_data_memory (pipeline[EXECUTE].operand_address, (int) (pipeline[EXECUTE].operand >> 16)); break; } } static void Sacl (void) { switch (processor_phase) { case DECODE: break; case OPERAND: break; case EXECUTE: pipeline[EXECUTE].operand = accumulator; pipeline[EXECUTE].operand <<= (pipeline[EXECUTE].instruction >> 8) & 7; write_data_memory (pipeline[EXECUTE].operand_address, (int) pipeline[EXECUTE].operand); break; } } static void Samm (void) { switch (processor_phase) { case DECODE: get_operand_address (DECODE); pipeline[DECODE].operand_address &= 0x7F; break; case OPERAND: break; case EXECUTE: if (check_ar_lock (pipeline[EXECUTE].operand_address - 0x10)) return; write_data_memory (pipeline[EXECUTE].operand_address, (int) accumulator); break; } } static void Sar (void) { switch (processor_phase) { case DECODE: get_operand_address (DECODE); break; case OPERAND: break; case EXECUTE: write_data_memory (pipeline[EXECUTE].operand_address, ar[(pipeline[EXECUTE].instruction >> 8) & 7]); break; } } static void Sath (void) { switch (processor_phase) { case DECODE: break; case OPERAND: break; case EXECUTE: if (treg1 & 0x10) accumulator <<= 16; break; } } static void Satl (void) { switch (processor_phase) { case DECODE: break; case OPERAND: break; case EXECUTE: accumulator <<= (treg1 & 0x0F); break; } } static void Sbb (void) { switch (processor_phase) { case DECODE: break; case OPERAND: break; case EXECUTE: pipeline[EXECUTE].operand = accb; sub_operand (0); break; } } static void Sbbb (void) { switch (processor_phase) { case DECODE: break; case OPERAND: break; case EXECUTE: pipeline[EXECUTE].operand = accb; sub_operand (c); break; } } static void Sbrk (void) { switch (processor_phase) { case DECODE: break; case OPERAND: break; case EXECUTE: if (!ar_lock[arp]) ar[arp] -= pipeline[EXECUTE].instruction & 0xFF; break; } } static void Setc_ovm (void) { switch (processor_phase) { case DECODE: break; case OPERAND: break; case EXECUTE: ovm = 1; break; } } static void Setc_sxm (void) { switch (processor_phase) { case DECODE: break; case OPERAND: break; case EXECUTE: sxm = 1; break; } } static void Setc_hm (void) { switch (processor_phase) { case DECODE: break; case OPERAND: break; case EXECUTE: hm = 1; break; } } static void Setc_tc (void) { switch (processor_phase) { case DECODE: break; case OPERAND: break; case EXECUTE: tc = 1; break; } } static void Setc_c (void) { switch (processor_phase) { case DECODE: break; case OPERAND: break; case EXECUTE: c = 1; break; } } static void Setc_cnf (void) { switch (processor_phase) { case DECODE: break; case OPERAND: break; case EXECUTE: cnf = 1; break; } } static void Setc_intm (void) { switch (processor_phase) { case DECODE: break; case OPERAND: break; case EXECUTE: intm = 1; break; } } static void Setc_xf (void) { switch (processor_phase) { case DECODE: break; case OPERAND: break; case EXECUTE: xf = 1; break; } } static void Sfl (void) { switch (processor_phase) { case DECODE: break; case OPERAND: break; case EXECUTE: c = (accumulator * SIGN_BIT) ? 1 : 0; accumulator <<= 1; break; } } static void Sflb (void) { int x; switch (processor_phase) { case DECODE: break; case OPERAND: break; case EXECUTE: x = (accb * SIGN_BIT) ? 1 : 0; accb <<= 1; c = (accumulator * SIGN_BIT) ? 1 : 0; accumulator = (accumulator << 1) + x; break; } } static void Sfr (void) { switch (processor_phase) { case DECODE: break; case OPERAND: break; case EXECUTE: c = accumulator & 1; if (sxm && (accumulator & SIGN_BIT)) accumulator = SIGN_BIT | (accumulator >> 1); else accumulator >>= 1; break; } } static void Sfrb (void) { int x; switch (processor_phase) { case DECODE: break; case OPERAND: break; case EXECUTE: x = accumulator & 1; if (sxm && (accumulator & SIGN_BIT)) accumulator = SIGN_BIT | (accumulator >> 1); else accumulator >>= 1; c = accb & 1; accb = (accumulator >> 1) + (x ? SIGN_BIT : 0); break; } } static void Smmr (void) { switch (processor_phase) { case DECODE: break; case OPERAND: break; case EXECUTE: break; } } static void Spac (void) { switch (processor_phase) { case DECODE: break; case OPERAND: break; case EXECUTE: pipeline[EXECUTE].operand = shifted_p (); sub_operand (0); break; } } static void Sph (void) { switch (processor_phase) { case DECODE: break; case OPERAND: break; case EXECUTE: pipeline[EXECUTE].operand = shifted_p (); write_data_memory (pipeline[EXECUTE].operand_address, (int) (pipeline[EXECUTE].operand >> 16)); break; } } static void Spl (void) { switch (processor_phase) { case DECODE: break; case OPERAND: break; case EXECUTE: pipeline[EXECUTE].operand = shifted_p (); write_data_memory (pipeline[EXECUTE].operand_address, (int) pipeline[EXECUTE].operand); break; } } static void Splk (void) { switch (processor_phase) { case DECODE: pipeline[FETCH].valid = 0; get_operand_address (DECODE); break; case OPERAND: break; case EXECUTE: write_data_memory (pipeline[EXECUTE].operand_address, pipeline[OPERAND].instruction); break; } } static void Spm (void) { switch (processor_phase) { case DECODE: break; case OPERAND: break; case EXECUTE: pm = pipeline[EXECUTE].instruction & 3; break; } } static void Sqra (void) { long int x; switch (processor_phase) { case DECODE: get_operand_address (DECODE); break; case OPERAND: get_operand (); break; case EXECUTE: x = pipeline[EXECUTE].operand; pipeline[EXECUTE].operand = shifted_p (); add_operand (0); treg1 = (int) x; p_register = treg1; p_register *= p_register; break; } } static void Sqrs (void) { long int x; switch (processor_phase) { case DECODE: get_operand_address (DECODE); break; case OPERAND: get_operand (); break; case EXECUTE: x = pipeline[EXECUTE].operand; pipeline[EXECUTE].operand = shifted_p (); sub_operand (0); treg1 = (int) x; p_register = treg1; p_register *= p_register; break; } } static void Sst1 (void) { switch (processor_phase) { case DECODE: break; case OPERAND: break; case EXECUTE: break; } } static void Sst2 (void) { switch (processor_phase) { case DECODE: break; case OPERAND: break; case EXECUTE: break; } } static void Sub1 (void) { switch (processor_phase) { case DECODE: get_operand_address (DECODE); break; case OPERAND: get_operand (); break; case EXECUTE: sign_extend_operand (); pipeline[EXECUTE].operand <<= (pipeline[EXECUTE].instruction >> 8) & 0x0F; sub_operand (0); break; } } static void Sub2 (void) { switch (processor_phase) { case DECODE: get_operand_address (DECODE); break; case OPERAND: get_operand (); break; case EXECUTE: pipeline[EXECUTE].operand <<= 16; add_operand (0); break; } } static void Sub3 (void) { switch (processor_phase) { case DECODE: break; case OPERAND: break; case EXECUTE: pipeline[EXECUTE].operand = pipeline[EXECUTE].instruction & 0xFF; sub_operand (0); break; } } static void Sub4 (void) { switch (processor_phase) { case DECODE: pipeline[FETCH].valid = 0; break; case OPERAND: break; case EXECUTE: pipeline[EXECUTE].operand = pipeline[OPERAND].instruction; sign_extend_operand (); pipeline[EXECUTE].operand <<= (pipeline[EXECUTE].instruction & 0x0F); add_operand (0); break; } } static void Subb (void) { switch (processor_phase) { case DECODE: get_operand_address (DECODE); break; case OPERAND: get_operand (); break; case EXECUTE: sub_operand (c); break; } } static void Subc (void) { long int alu_out; switch (processor_phase) { case DECODE: get_operand_address (DECODE); break; case OPERAND: get_operand (); break; case EXECUTE: sign_extend_operand (); pipeline[EXECUTE].operand <<= 15; alu_out = accumulator - pipeline[EXECUTE].operand; if (alu_out >= 0) accumulator = (alu_out << 1) + 1; else accumulator <<= 1; break; } } static void Subs (void) { switch (processor_phase) { case DECODE: get_operand_address (DECODE); break; case OPERAND: get_operand (); break; case EXECUTE: sub_operand (0); break; } } static void Subt (void) { int shift; switch (processor_phase) { case DECODE: get_operand_address (DECODE); break; case OPERAND: get_operand (); break; case EXECUTE: shift = treg1 & 15; pipeline[EXECUTE].operand <<= shift; sub_operand (0); break; } } static void Tblr (void) { int mcs; switch (processor_phase) { case DECODE: get_operand_address (DECODE); break; case OPERAND: break; case EXECUTE: mcs = pfc; pfc = accumulator & 0xFF; if (rptc != 0) while (rptc != 0) { write_data_memory (pipeline[EXECUTE].operand_address, read_program_memory (pfc)); pfc++; rptc--; if (rptc != 0) get_operand_address (EXECUTE); } else write_data_memory (pipeline[EXECUTE].operand_address, read_program_memory (pfc)); pfc = mcs; break; } } static void Tblw (void) { int mcs; switch (processor_phase) { case DECODE: get_operand_address (DECODE); break; case OPERAND: break; case EXECUTE: mcs = pfc; pfc = accumulator & 0xFF; if (rptc != 0) while (rptc != 0) { write_program_memory (pfc, read_data_memory (pipeline[EXECUTE].operand_address)); pfc++; rptc--; if (rptc != 0) get_operand_address (EXECUTE); } else write_program_memory (pfc, read_data_memory (pipeline[EXECUTE].operand_address)); pfc = mcs; break; } } static void Xc (void) { switch (processor_phase) { case DECODE: break; case OPERAND: break; case EXECUTE: break; } } static void Xor1 (void) { switch (processor_phase) { case DECODE: get_operand_address (DECODE); break; case OPERAND: get_operand (); break; case EXECUTE: accumulator ^= (pipeline[EXECUTE].operand & 0xFFFF); break; } } static void Xor2 (void) { switch (processor_phase) { case DECODE: pipeline[FETCH].valid = 0; break; case OPERAND: break; case EXECUTE: accumulator ^= (pipeline[EXECUTE].operand << (pipeline[OPERAND].instruction & 0x03)); break; } } static void Xor3 (void) { switch (processor_phase) { case DECODE: pipeline[FETCH].valid = 0; break; case OPERAND: break; case EXECUTE: accumulator ^= pipeline[EXECUTE].operand << 16; break; } } static void Xorb (void) { switch (processor_phase) { case DECODE: break; case OPERAND: break; case EXECUTE: accumulator ^= accb; break; } } static void Xpl1 (void) { switch (processor_phase) { case DECODE: get_operand_address (DECODE); break; case OPERAND: get_operand (); break; case EXECUTE: write_data_memory (pipeline[EXECUTE].operand_address, pipeline[EXECUTE].operand ^ dbmr); break; } } static void Xpl2 (void) { switch (processor_phase) { case DECODE: pipeline[FETCH].valid = 0; get_operand_address (DECODE); break; case OPERAND: get_operand (); break; case EXECUTE: write_data_memory (pipeline[EXECUTE].operand_address, pipeline[EXECUTE].operand ^ pipeline[EXECUTE].instruction); break; } } static void Zalr (void) { switch (processor_phase) { case DECODE: get_operand_address (DECODE); break; case OPERAND: get_operand (); break; case EXECUTE: accumulator = (pipeline[EXECUTE].operand << 16) + 0x8000L; break; } } static void Zap (void) { switch (processor_phase) { case DECODE: break; case OPERAND: break; case EXECUTE: accumulator = 0; p_register = 0; break; } } static void Zpr (void) { switch (processor_phase) { case DECODE: break; case OPERAND: break; case EXECUTE: p_register = 0; break; } }