/* * Simulator of microcontrollers (inst.cc) * * stm8 code base from Vaclav Peroutka vaclavpe@users.sourceforge.net * and Valentin Dudouyt valentin.dudouyt@gmail.com * * Copyright (C) 1999,99 Drotos Daniel, Talker Bt. * * To contact author send email to drdani@mazsola.iit.uni-miskolc.hu * */ /* This file is part of microcontroller simulator: ucsim. UCSIM 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. UCSIM 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 UCSIM; see the file COPYING. If not, write to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /*@1@*/ #include "ddconfig.h" #include "stdio.h" #include // local #include "stm8cl.h" #include "regsstm8.h" #include "stm8mac.h" int cl_stm8::fetchea(t_mem code, unsigned char prefix) { int ftc; switch ((code >> 4) & 0x0f) { case 0x1: return (unsigned char)fetch()+regs.SP; // SP indexed case 0xb: return fetch(); // direct short case 0xc: if ( 0 == prefix) { // direct long return fetch2(); } else if ( 0x72 == prefix) { // long pointer ftc = fetch2(); return get2(ftc); } else if ( 0x92 == prefix) { // short pointer ftc = fetch(); return get2(ftc); } else { printf("************* bad prefix !!!!\n"); return (resHALT); } case 0xd: if ( 0 == prefix) { // long offset with X reg return fetch2()+regs.X; } else if ( 0x72 == prefix) { // long pointer to offset with X reg ftc = fetch2(); return get2(ftc)+regs.X; } else if ( 0x90 == prefix) { // long offset with Y reg return fetch2()+regs.Y; } else if ( 0x91 == prefix) { // short pointer to offset with Y reg ftc = fetch(); return get2(ftc)+regs.Y; } else if ( 0x92 == prefix) { // short pointer to offset with X reg ftc = fetch(); return get2(ftc)+regs.X; } else { return( resHALT); } case 0xe: if ( 0 == prefix) { // short offset with X reg return fetch()+regs.X; } else if ( 0x90 == prefix) { // short offset with Y reg return fetch()+regs.Y; } else { return( resHALT); } case 0xf: if ( 0 == prefix) { // X index return regs.X; } else if ( 0x90 == prefix) { // Y index return regs.Y; } else { return( resHALT); } default: return(resHALT); } } int cl_stm8::get_dest(t_mem code, unsigned char prefix) { int resaddr, ftc; switch ((code >> 4) & 0x0f) { case 0x0: if ( 0 == prefix) { // short offset with SP resaddr = fetch()+regs.SP; } else { resaddr = ( resHALT); } break; case 0x3: if ( 0 == prefix) { // short direct resaddr = fetch(); } else if ( 0x72 == prefix) { // long indirect - pointer ftc = fetch2(); resaddr = get2(ftc); } else if ( 0x92 == prefix) { // short indirect - pointer ftc = fetch(); resaddr = get2(ftc); } else { resaddr = ( resHALT); } break; case 0x4: if ( 0x72 == prefix) { // long offset with X ftc = fetch2(); resaddr = ftc + regs.X; } else if ( 0x90 == prefix) { // long offset with Y ftc = fetch2(); resaddr = ftc + regs.Y; } else { resaddr = ( resHALT); } break; case 0x5: if ( 0x72 == prefix) { // long direct resaddr = fetch2(); } else { resaddr = ( resHALT); } break; case 0x6: if ( 0 == prefix) { // short offset with X resaddr = (fetch()+regs.X); } else if ( 0x72 == prefix) { // long pointer to offset with X ftc = fetch2(); resaddr = (get2(ftc)+regs.X); } else if ( 0x90 == prefix) { // short offset with Y resaddr = (fetch()+regs.Y); } else if ( 0x91 == prefix) { // short pointer to offset with Y ftc = fetch(); resaddr = (get2(ftc)+regs.Y); } else if ( 0x92 == prefix) { // short pointer to offset with X ftc = fetch(); resaddr = (get2(ftc)+regs.X); } else { resaddr =( resHALT); } break; case 0x7: if ( 0 == prefix) { // X index resaddr = regs.X; } else if ( 0x90 == prefix) { // Y index resaddr = regs.Y; } else { resaddr =( resHALT); } break; default: resaddr =(resHALT); break; } return resaddr; } void cl_stm8::flag_cvh(int x, int m, int r, bool byte, bool add, int mask) { bool xt, xs, xh, mt, ms, mh, rt, rs, rh; if (byte) { xt = !!(x & 0x80); xs = !!(x & 0x40); xh = !!(x & 0x08); mt = !!(m & 0x80); ms = !!(m & 0x40); mh = !!(m & 0x08); rt = !!(r & 0x80); rs = !!(r & 0x40); rh = !!(r & 0x08); } else { xt = !!(x & 0x8000); xs = !!(x & 0x4000); xh = !!(x & 0x0080); mt = !!(m & 0x8000); ms = !!(m & 0x4000); mh = !!(m & 0x0080); rt = !!(r & 0x8000); rs = !!(r & 0x4000); rh = !!(r & 0x0080); } if (add) { if (mask & BIT_V) FLAG_ASSIGN (BIT_V, ((xt && mt) || (mt && !rt) || (!rt && xt)) ^ ((xs && ms) || (ms && !rs) || (!rs && xs))); if (mask & BIT_C) FLAG_ASSIGN (BIT_C, (xt && mt) || (mt && !rt) || (!rt && xt)); if (mask & BIT_H) FLAG_ASSIGN (BIT_H, (xh && mh) || (mh && !rh) || (!rh && xh)); } else { if (mask & BIT_V) FLAG_ASSIGN (BIT_V, ((!xt && mt) || (!xt && rt) || (xt && mt && rt)) ^ ((!xs && ms) || (!xs && rs) || (xs && ms && rs))); if (mask & BIT_H) FLAG_ASSIGN (BIT_H, (!xh && mh) || (!xh && rh) || (xh && mh && rh)); if (mask & BIT_C) FLAG_ASSIGN (BIT_C, (!xt && mt) || (!xt && rt) || (xt && mt && rt)); } } #define FLAG_CVH_BYTE_ADD(x, m, r, mask) flag_cvh(x, m, r, true, true, mask) #define FLAG_CVH_BYTE_SUB(x, m, r, mask) flag_cvh(x, m, r, true, false, mask) #define FLAG_CVH_WORD_ADD(x, m, r, mask) flag_cvh(x, m, r, false, true, mask) #define FLAG_CVH_WORD_SUB(x, m, r, mask) flag_cvh(x, m, r, false, false, mask) int cl_stm8::inst_adc(t_mem code, unsigned char prefix) { int result, operand1, operand2; int carryin = !!(regs.CC & BIT_C); operand1 = regs.A; operand2 = OPERAND(code, prefix); result = operand1 + operand2 + carryin; FLAG_NZ (result); FLAG_CVH_BYTE_ADD(operand1, operand2, result, BIT_C | BIT_V | BIT_H); regs.A = result & 0xff; return(resGO); } int cl_stm8::inst_add(t_mem code, unsigned char prefix) { FLAG_CLEAR(BIT_C); return inst_adc(code, prefix); } int cl_stm8::get_1(unsigned int addr) { vc.rd++; return ram->read((t_addr) (addr)); } int cl_stm8::get2(unsigned int addr) { vc.rd+= 2; return((ram->read((t_addr) (addr)) << 8) | ram->read((t_addr) (addr+1))); } int cl_stm8::get3(unsigned int addr) { vc.rd+= 3; return((ram->read((t_addr) (addr)) << 16) | (ram->read((t_addr) (addr+1)) << 8) |ram->read((t_addr) (addr+2))); } int cl_stm8::inst_addw(t_mem code, unsigned char prefix) { long int result, operand1, operand2, nibble_high, nibble_low; u16_t *dest_ptr; bool sub; nibble_high = (code >> 4) & 0x0f; nibble_low = code & 0x0f; dest_ptr = nibble_low == 0x09 || nibble_low == 0x02 ? ®s.Y : ®s.X; operand1 = *dest_ptr; switch(nibble_high) { case 0x1: case 0xa: operand2 = fetch2(); break; // Immediate case 0xb: operand2 = get2(fetch2()); break; // Long case 0xf: operand2 = get2(regs.SP + fetch()); break; // sp-indexed default: return(resHALT); } switch(nibble_low) { case 0x0: case 0x2: case 0xd: sub = true; break; case 0x9: case 0xb: case 0xc: sub = false; break; default: return(resHALT); } if (sub) result = operand1 - operand2; else result = operand1 + operand2; FLAG_ASSIGN (BIT_N, 0x8000 & result); FLAG_ASSIGN (BIT_Z, (result & 0xffff) == 0); if (sub) FLAG_CVH_WORD_SUB(operand1, operand2, result, BIT_C | BIT_H | BIT_V); else FLAG_CVH_WORD_ADD(operand1, operand2, result, BIT_C | BIT_H | BIT_V); *dest_ptr = result & 0xffff; return(resGO); } int cl_stm8::inst_and(t_mem code, unsigned char prefix) { int result, operand1, operand2; operand1 = regs.A; operand2 = OPERAND(code, prefix); result = operand1 & operand2; FLAG_NZ (result); regs.A = result & 0xff; return(resGO); } int cl_stm8::inst_bccmbcpl(t_mem code, unsigned char prefix) { int ea = fetch2(); unsigned char dbyte; dbyte= get1( ea); if (code & 0x01) { // bccm char pos = (code - 0x11) >> 1; dbyte = dbyte & (~(1<> 1; dbyte = dbyte ^ (1<> 1; dbyte = dbyte & (~(1<> 1; dbyte = dbyte | (1<> 1; if(!( dbyte & (1<> 1; if ( dbyte & (1<> 4) { /* clr */ case 0x004: regs.A = 0; return(resGO); case 0x003: opaddr = fetch(); break; case 0x725: opaddr = fetch2(); break; case 0x007: opaddr = regs.X; break; case 0x006: opaddr = regs.X + fetch(); break; case 0x724: opaddr = regs.X + fetch2(); break; case 0x907: opaddr = regs.Y; break; case 0x906: opaddr = regs.Y + fetch(); break; case 0x904: opaddr = regs.Y + fetch2(); break; case 0x000: opaddr = regs.SP + fetch(); break; case 0x923: opaddr = get2(fetch()); break; // short indirect case 0x723: opaddr = get2(fetch2()); break; // long indirect case 0x926: opaddr = get2(fetch()) + regs.X; break; // short x-indexed indirect case 0x726: opaddr = get2(fetch2()) + regs.X; break; // long x-indexed indirect case 0x916: opaddr = get2(fetch()) + regs.Y; break; // short y-indexed indirect /* clrw */ case 0x005: regs.X = 0; return(resGO); case 0x905: regs.Y = 0; return(resGO); default: return(resHALT); } store1(opaddr, 0); return(resGO); } int cl_stm8::inst_cp(t_mem code, unsigned char prefix) { int result, operand1, operand2; operand1 = regs.A; operand2 = OPERAND(code, prefix); result = (operand1 - operand2) & 0xff; FLAG_NZ (result); FLAG_CVH_BYTE_SUB(operand1, operand2, result, BIT_C | BIT_V); return(resGO); } int cl_stm8::inst_cpw(t_mem code, unsigned char prefix) { long int operand1, operand2, result; int reversed = 0; operand1 = prefix == 0x90 ? regs.Y : regs.X; operand2 = prefix == 0x90 ? regs.X : regs.Y; switch((code & 0xf0) >> 4) { case 0xa: operand2 = fetch2(); break; // Immediate case 0xb: operand2 = get2(fetch()); break; // Short case 0xc: switch (prefix) { case 0x00: case 0x90: operand2 = get2(fetch2()); break; // Long direct case 0x92: operand2 = get2(get2(fetch())); break; // short indirect case 0x72: operand2 = get2(get2(fetch2())); break; // long indirect case 0x91: operand2 = get2(get2(fetch())); operand1 = regs.Y; break; // short indirect default: return(resHALT); } break; case 0x1: operand2 = get2(regs.SP + fetch()); break; // SP-indexed case 0xf: operand1 = get2(operand1); reversed = 1; break; // cpw X|Y, (Y|X) case 0xe: operand1 = get2(operand1 + fetch()); reversed = 1; break; // short indexed direct case 0xd: switch (prefix) { case 0x00: case 0x90: operand1 = get2(operand1 + fetch2()); break; // short indexed direct case 0x91: operand1 = get2(regs.Y + get2(fetch())); operand2 = regs.X; break; // short y-indexed indirect case 0x92: operand1 = get2(operand1 + get2(fetch())); break; // short x-indexed indirect case 0x72: operand1 = get2(operand1 + get2(fetch2())); break; // long x-indexed indirect default: return(resHALT); } reversed = 1; break; default: return(resHALT); } if (!reversed) result = (operand1 - operand2) & 0xffff; else result = (operand2 - operand1) & 0xffff; FLAG_ASSIGN (BIT_Z, (result & 0xffff) == 0); FLAG_ASSIGN (BIT_N, 0x8000 & result); if (!reversed) FLAG_CVH_WORD_SUB(operand1, operand2, result, BIT_C | BIT_V); else FLAG_CVH_WORD_SUB(operand2, operand1, result, BIT_C | BIT_V); return(resGO); } int cl_stm8::inst_cpl(t_mem code, unsigned char prefix) { long int operand; unsigned int opaddr = 0; if (((code&0xf0)==0x40) &&(prefix == 0x00)) { operand = regs.A; } else if (((code&0xf0)==0x50) &&(prefix == 0x00)) { operand = regs.X; } else if (((code&0xf0)==0x50) &&(prefix == 0x90)) { operand = regs.Y; } else { opaddr = get_dest(code,prefix); operand = get1(opaddr); } operand ^= 0xffff; FLAG_SET (BIT_C); if (((code&0xf0)==0x40) &&(prefix == 0x00)) { regs.A = operand&0xff; FLAG_ASSIGN (BIT_Z, (operand & 0xff) == 0); FLAG_ASSIGN (BIT_N, 0x80 & operand); } else if (((code&0xf0)==0x50) &&(prefix == 0x00)) { regs.X = operand & 0xffff; FLAG_ASSIGN (BIT_Z, (operand & 0xffff) == 0); FLAG_ASSIGN (BIT_N, 0x8000 & operand); } else if (((code&0xf0)==0x50) &&(prefix == 0x90)) { regs.Y = operand & 0xffff; FLAG_ASSIGN (BIT_Z, (operand & 0xffff) == 0); FLAG_ASSIGN (BIT_N, 0x8000 & operand); } else { store1(opaddr, operand &0xff); FLAG_ASSIGN (BIT_Z, (operand & 0xff) == 0); FLAG_ASSIGN (BIT_N, 0x80 & operand); } return(resGO); } int cl_stm8::inst_dec(t_mem code, unsigned char prefix) { long int operand, resval; unsigned int opaddr = 0; if (((code&0xf0)==0x40) &&(prefix == 0x00)) { operand = regs.A; } else if (((code&0xf0)==0x50) &&(prefix == 0x00)) { operand = regs.X; } else if (((code&0xf0)==0x50) &&(prefix == 0x90)) { operand = regs.Y; } else { opaddr = get_dest(code,prefix); operand = get1(opaddr); } resval = operand - 1; if (((code&0xf0)==0x40) &&(prefix == 0x00)) { regs.A = resval&0xff; FLAG_ASSIGN (BIT_Z, (resval & 0xff) == 0); FLAG_ASSIGN (BIT_N, 0x80 & resval); FLAG_CVH_BYTE_ADD(operand, 0xff, resval, BIT_V); } else if (((code&0xf0)==0x50) &&(prefix == 0x00)) { regs.X = resval & 0xffff; FLAG_ASSIGN (BIT_Z, (resval & 0xffff) == 0); FLAG_ASSIGN (BIT_N, 0x8000 & resval); FLAG_CVH_WORD_ADD(operand, 0xffff, resval, BIT_V); } else if (((code&0xf0)==0x50) &&(prefix == 0x90)) { regs.Y = resval & 0xffff; FLAG_ASSIGN (BIT_Z, (resval & 0xffff) == 0); FLAG_ASSIGN (BIT_N, 0x8000 & resval); FLAG_CVH_WORD_ADD(operand, 0xffff, resval, BIT_V); } else { store1(opaddr, resval &0xff); FLAG_ASSIGN (BIT_Z, (resval & 0xff) == 0); FLAG_ASSIGN (BIT_N, 0x80 & resval); FLAG_CVH_BYTE_ADD(operand, 0xff, resval, BIT_V); } return(resGO); } int cl_stm8::inst_div(t_mem code, unsigned char prefix) { unsigned int quot, remi; FLAG_CLEAR(BIT_N); FLAG_CLEAR(BIT_H); FLAG_CLEAR(BIT_V); if( code == 0x65) { // divw if (regs.Y == 0x00) { FLAG_SET(BIT_C); } else { FLAG_CLEAR(BIT_C); quot = regs.X / regs.Y; remi = regs.X % regs.Y; regs.X = quot; regs.Y = remi; FLAG_ASSIGN (BIT_Z, (quot & 0xffff) == 0); } } else { //div if (regs.A == 0x00) { FLAG_SET(BIT_C); } else { FLAG_CLEAR(BIT_C); if (prefix == 0x00) { quot = regs.X / regs.A; remi = regs.X % regs.A; regs.X = quot; regs.A = remi; } else if (prefix == 0x90) { quot = regs.Y / regs.A; remi = regs.Y % regs.A; regs.Y = quot; regs.A = remi; } else { return (resHALT); } FLAG_ASSIGN (BIT_Z, (quot & 0xffff) == 0); } } return(resGO); } int cl_stm8::inst_inc(t_mem code, unsigned char prefix) { long int operand, resval; unsigned int opaddr = 0; if (((code&0xf0)==0x40) &&(prefix == 0x00)) { operand = regs.A; } else if (((code&0xf0)==0x50) &&(prefix == 0x00)) { operand = regs.X; } else if (((code&0xf0)==0x50) &&(prefix == 0x90)) { operand = regs.Y; } else { opaddr = get_dest(code,prefix); operand = get1(opaddr); } resval = operand + 1; if (((code&0xf0)==0x40) &&(prefix == 0x00)) { regs.A = resval&0xff; FLAG_ASSIGN (BIT_Z, (resval & 0xff) == 0); FLAG_ASSIGN (BIT_N, 0x80 & resval); FLAG_CVH_BYTE_ADD(operand, 0x01, resval, BIT_V); } else if (((code&0xf0)==0x50) &&(prefix == 0x00)) { regs.X = resval & 0xffff; FLAG_ASSIGN (BIT_Z, (resval & 0xffff) == 0); FLAG_ASSIGN (BIT_N, 0x8000 & resval); FLAG_CVH_WORD_ADD(operand, 0x0001, resval, BIT_V); } else if (((code&0xf0)==0x50) &&(prefix == 0x90)) { regs.Y = resval & 0xffff; FLAG_ASSIGN (BIT_Z, (resval & 0xffff) == 0); FLAG_ASSIGN (BIT_N, 0x8000 & resval); FLAG_CVH_WORD_ADD(operand, 0x0001, resval, BIT_V); } else { store1(opaddr, resval &0xff); FLAG_ASSIGN (BIT_Z, (resval & 0xff) == 0); FLAG_ASSIGN (BIT_N, 0x80 & resval); FLAG_CVH_BYTE_ADD(operand, 0x01, resval, BIT_V); } return(resGO); } int cl_stm8::inst_jp(t_mem code, unsigned char prefix) { t_addr newPC = (PC & 0xff0000ul) + fetchea(code, prefix); PC = newPC; return(resGO); } int cl_stm8::inst_jr(t_mem code, unsigned char prefix) { bool taken; signed char ofs; unsigned char bz, bn, bv; if (prefix ==0x00) { switch ((code>>1) & 7) { case 0: // JRT - JRA (20) / JRF (21) taken = 1; break; case 1: // JRUGT (22) / JRULE (23) taken = !(regs.CC & (BIT_C | BIT_Z)); break; case 2: // JRUGE (24) / JRULT (25) taken = !(regs.CC & BIT_C); break; case 3: // JRNE (26) / JREQ (27) taken = !(regs.CC & BIT_Z); break; case 4: // JRNV (28) / JRV (29) taken = !(regs.CC & BIT_V); break; case 5: // JRPL (2A) / JRMI (2B) taken = !(regs.CC & BIT_N); break; case 6: // JRSGT (2C) - Z or (N xor V) = 0 / JRSLE (2D) - Z or (N xor V) = 1 bz = !!(regs.CC & BIT_Z); bn = !!(regs.CC & BIT_N); bv = !!(regs.CC & BIT_V); taken = !(bz | (bn ^ bv)); break; case 7: // JRSGE (2E) - N xor V = 0 / / JRSLT(2F) N xor V = 1 bn = !!(regs.CC & BIT_N); bv = !!(regs.CC & BIT_V); taken = !(bn ^ bv); break; default: return(resHALT); } } else if (prefix==0x90) { switch ((code>>1) & 7) { case 4: // JRNH (28) / JRH (29) taken = !(regs.CC & BIT_H); break; case 6: // JRNM (2C) / JRM (2D) taken = !(regs.CC & (BIT_I1|BIT_I0)); break; case 7: // JRIL (2E) / JRIH (2F), no means to test this ??? taken = 0; default: return(resHALT); } } else return(resHALT); if (code & 1) taken = ! taken; ofs = fetch(); if (taken) { PC += ofs; tick(1); } return(resGO); } int cl_stm8::inst_lda(t_mem code, unsigned char prefix) { int operand; operand = OPERAND(code, prefix); FLAG_NZ (operand); regs.A = operand; return(resGO); } int cl_stm8::operandw(t_mem code, unsigned char prefix) { if(EA_IMM(code)) { return(fetch2()); } else { int addr = fetchea(code,prefix); int result = get2(addr); return(result); } } int cl_stm8::inst_ldxy(t_mem code, unsigned char prefix) { unsigned int operand; u16_t *dest_ptr; tick(1); dest_ptr = (prefix == 0x90) ? ®s.Y : ®s.X; if((prefix == 0x00 && code == 0x16) || (prefix == 0x91 && code == 0xce) || (prefix == 0x91 && code == 0xde)) dest_ptr = ®s.Y; switch((code & 0xf0) >> 4) { case 0xa: operand = fetch2(); break; // Immediate case 0xb: operand = get2(fetch()); break; // Short case 0xc: switch (prefix) { case 0x90: case 0x00: operand = get2(fetch2()); // Long direct break; case 0x92: case 0x91: operand = get2(get2(fetch())); // short indirect break; case 0x72: operand = get2(get2(fetch2())); // long indirect break; default: return(resHALT); } break; case 0xf: operand = get2(*dest_ptr); break; case 0xe: operand = get2(*dest_ptr + fetch()); break; case 0xd: switch (prefix) { case 0x90: case 0x00: operand = get2(*dest_ptr + fetch2()); // Long x/y-indexed direct break; case 0x92: case 0x91: operand = get2(*dest_ptr + get2(fetch())); // short x/y-indexed indirect break; case 0x72: operand = get2(*dest_ptr + get2(fetch2())); // long x-indexed indirect break; default: return(resHALT); } break; case 0x1: operand = get2(regs.SP + fetch()); break; default: return(resHALT); } if ((code & 0xf0) != 0x90) { FLAG_ASSIGN (BIT_Z, (operand & 0xffff) == 0); FLAG_ASSIGN (BIT_N, 0x8000 & operand); } *dest_ptr = operand; return(resGO); } int cl_stm8::inst_lddst(t_mem code, unsigned char prefix) { unsigned int opaddr; opaddr = fetchea(code,prefix); FLAG_ASSIGN (BIT_Z, (regs.A & 0xff) == 0); FLAG_ASSIGN (BIT_N, 0x80 & regs.A); store1(opaddr, regs.A); return(resGO); } int cl_stm8::inst_ldxydst(t_mem code, unsigned char prefix) { /* ldw dst, REG */ unsigned int opaddr, operand; tick(1); switch ((((code & 0xf0) | (prefix << 8)) >> 4) & 0xfff) { case 0x00b: case 0x00c: case 0x92c: case 0x72c: case 0x90f: case 0x90e: case 0x90d: case 0x91d: operand = regs.X; break; case 0x00f: case 0x00e: case 0x00d: case 0x92d: case 0x72d: case 0x90b: case 0x90c: case 0x91c: operand = regs.Y; break; case 0x001: switch (code) { case 0x17: operand = regs.Y; break; case 0x1f: operand = regs.X; break; default: return resHALT; } break; default: return resHALT; } switch((code & 0xf0) >> 4) { case 0x1: opaddr = regs.SP + fetch(); break; case 0xb: opaddr = fetch(); break; case 0xc: switch (prefix) { case 0x00: case 0x90: opaddr = fetch2(); // long direct break; case 0x91: case 0x92: opaddr = get2(fetch()); // short indirect break; case 0x72: opaddr = get2(fetch2()); // long indirect break; default: return (resHALT); } break; case 0xf: opaddr = (prefix == 0x90) ? regs.Y : regs.X; break; case 0xe: opaddr = ((prefix == 0x90) ? regs.Y : regs.X) + fetch(); break; case 0xd: switch (prefix) { case 0x90: opaddr = regs.Y + fetch2(); // long y-indexed direct break; case 0x00: opaddr = regs.X + fetch2(); // long x-indexed direct break; case 0x92: opaddr = regs.X + get2(fetch()); // short x-indexed indirect break; case 0x91: opaddr = regs.Y + get2(fetch()); // short y-indexed indirect break; case 0x72: opaddr = regs.X + get2(fetch2()); // long x-indexed indirect break; default: return (resHALT); } break; default: return(resHALT); } FLAG_ASSIGN (BIT_Z, (operand & 0xffff) == 0); FLAG_ASSIGN (BIT_N, 0x8000 & operand); store2(opaddr, operand); return(resGO); } int cl_stm8::inst_neg(t_mem code, unsigned char prefix) { long int operand, resval; unsigned int opaddr = 0; if (((code&0xf0)==0x40) &&(prefix == 0x00)) { operand = regs.A; } else if (((code&0xf0)==0x50) &&(prefix == 0x00)) { operand = regs.X; } else if (((code&0xf0)==0x50) &&(prefix == 0x90)) { operand = regs.Y; } else { opaddr = get_dest(code,prefix); operand = get1(opaddr); } resval = 0 - operand; if (((code&0xf0)==0x40) &&(prefix == 0x00)) { regs.A = resval&0xff; FLAG_ASSIGN (BIT_Z, (resval & 0xff) == 0); FLAG_ASSIGN (BIT_N, 0x80 & resval); FLAG_ASSIGN (BIT_V, (0x80 == operand)); FLAG_ASSIGN (BIT_C, 0x100 & resval); } else if (((code&0xf0)==0x50) &&(prefix == 0x00)) { regs.X = resval&0xffff; FLAG_ASSIGN (BIT_Z, (resval & 0xffff) == 0); FLAG_ASSIGN (BIT_N, 0x8000 & resval); FLAG_ASSIGN (BIT_V, (0x8000 == operand)); FLAG_ASSIGN (BIT_C, 0x10000 & resval); } else if (((code&0xf0)==0x50) &&(prefix == 0x90)) { regs.Y = resval&0xffff; FLAG_ASSIGN (BIT_Z, (resval & 0xffff) == 0); FLAG_ASSIGN (BIT_N, 0x8000 & resval); FLAG_ASSIGN (BIT_V, (0x8000 == operand)); FLAG_ASSIGN (BIT_C, 0x10000 & resval); } else { store1(opaddr, resval &0xff); FLAG_ASSIGN (BIT_Z, (resval & 0xff) == 0); FLAG_ASSIGN (BIT_N, 0x80 & resval); FLAG_ASSIGN (BIT_V, (0x80 == operand)); FLAG_ASSIGN (BIT_C, 0x100 & resval); } return(resGO); } int cl_stm8::inst_or(t_mem code, unsigned char prefix) { int result, operand1, operand2; operand1 = regs.A; operand2 = OPERAND(code, prefix); result = (operand1 | operand2) & 0xff; FLAG_NZ (result); regs.A = result & 0xff; return(resGO); } int cl_stm8::inst_rlc(t_mem code, unsigned char prefix) { long int operand, resval; unsigned int opaddr = 0; if (((code&0xf0)==0x40) && (prefix == 0x00)) { operand = regs.A; } else if (((code&0xf0)==0x50) && (prefix == 0x00)) { operand = regs.X; } else if (((code&0xf0)==0x50) && (prefix == 0x90)) { operand = regs.Y; } else { opaddr = get_dest (code, prefix); operand = get1 (opaddr); } resval = operand << 0x1; if (regs.CC & BIT_C) { resval++; } if (((code&0xf0)==0x40) &&(prefix == 0x00)) { regs.A = resval&0xff; FLAG_ASSIGN (BIT_Z, (resval & 0xff) == 0); FLAG_ASSIGN (BIT_N, 0x80 & resval); FLAG_ASSIGN (BIT_C, (resval & 0x100)); } else if (((code&0xf0)==0x50) &&(prefix == 0x00)) { regs.X = resval & 0xffff; FLAG_ASSIGN (BIT_Z, (resval & 0xffff) == 0); FLAG_ASSIGN (BIT_N, 0x8000 & resval); FLAG_ASSIGN (BIT_C, (resval & 0x10000)); } else if (((code&0xf0)==0x50) &&(prefix == 0x90)) { regs.Y = resval & 0xffff; FLAG_ASSIGN (BIT_Z, (resval & 0xffff) == 0); FLAG_ASSIGN (BIT_N, 0x8000 & resval); FLAG_ASSIGN (BIT_C, (resval & 0x10000)); } else { store1(opaddr, resval &0xff); FLAG_ASSIGN (BIT_Z, (resval & 0xff) == 0); FLAG_ASSIGN (BIT_N, 0x80 & resval); FLAG_ASSIGN (BIT_C, (resval & 0x100)); } return (resGO); } int cl_stm8::inst_rrc(t_mem code, unsigned char prefix) { long int operand, resval; unsigned int opaddr = 0; if (((code&0xf0)==0x40) &&(prefix == 0x00)) { operand = regs.A; } else if (((code&0xf0)==0x50) &&(prefix == 0x00)) { operand = regs.X; } else if (((code&0xf0)==0x50) &&(prefix == 0x90)) { operand = regs.Y; } else { opaddr = get_dest(code,prefix); operand = get1(opaddr); } resval = operand >> 1; if (((code&0xf0)==0x40) &&(prefix == 0x00)) { if (regs.CC & BIT_C) { resval |= 0x80; } regs.A = resval&0xff; FLAG_ASSIGN (BIT_Z, (resval & 0xff) == 0); FLAG_ASSIGN (BIT_N, 0x80 & resval); FLAG_ASSIGN (BIT_C, (operand & 0x1)); } else if (((code&0xf0)==0x50) &&(prefix == 0x00)) { if (regs.CC & BIT_C) { resval |= 0x8000; } regs.X = resval & 0xffff; FLAG_ASSIGN (BIT_Z, (resval & 0xffff) == 0); FLAG_ASSIGN (BIT_N, 0x8000 & resval); FLAG_ASSIGN (BIT_C, (operand & 0x1)); } else if (((code&0xf0)==0x50) &&(prefix == 0x90)) { if (regs.CC & BIT_C) { resval |= 0x8000; } regs.Y = resval & 0xffff; FLAG_ASSIGN (BIT_Z, (resval & 0xffff) == 0); FLAG_ASSIGN (BIT_N, 0x8000 & resval); FLAG_ASSIGN (BIT_C, (operand & 0x1)); } else { if (regs.CC & BIT_C) { resval |= 0x80; } store1(opaddr, resval &0xff); FLAG_ASSIGN (BIT_Z, (resval & 0xff) == 0); FLAG_ASSIGN (BIT_N, 0x80 & resval); FLAG_ASSIGN (BIT_C, (operand & 0x1)); } return(resGO); } int cl_stm8::inst_sbc(t_mem code, unsigned char prefix) { int result, operand1, operand2; int carryin = !!(regs.CC & BIT_C); operand1 = regs.A; operand2 = OPERAND(code, prefix); result = (operand1 - operand2 - carryin) & 0xff; FLAG_NZ (result); FLAG_CVH_BYTE_SUB(operand1, operand2, result, BIT_C | BIT_V); regs.A = result; return(resGO); } int cl_stm8::inst_sll(t_mem code, unsigned char prefix) { long int operand, resval; unsigned int opaddr = 0; if (((code&0xf0)==0x40) &&(prefix == 0x00)) { operand = regs.A; } else if (((code&0xf0)==0x50) &&(prefix == 0x00)) { operand = regs.X; } else if (((code&0xf0)==0x50) &&(prefix == 0x90)) { operand = regs.Y; } else { opaddr = get_dest(code,prefix); operand = get1(opaddr); } resval = operand << 0x1; if (((code&0xf0)==0x40) &&(prefix == 0x00)) { regs.A = resval&0xff; FLAG_ASSIGN (BIT_Z, (resval & 0xff) == 0); FLAG_ASSIGN (BIT_N, 0x80 & resval); FLAG_ASSIGN (BIT_C, (resval & 0x100)); } else if (((code&0xf0)==0x50) &&(prefix == 0x00)) { regs.X = resval & 0xffff; FLAG_ASSIGN (BIT_Z, (resval & 0xffff) == 0); FLAG_ASSIGN (BIT_N, 0x8000 & resval); FLAG_ASSIGN (BIT_C, (resval & 0x10000)); } else if (((code&0xf0)==0x50) &&(prefix == 0x90)) { regs.Y = resval & 0xffff; FLAG_ASSIGN (BIT_Z, (resval & 0xffff) == 0); FLAG_ASSIGN (BIT_N, 0x8000 & resval); FLAG_ASSIGN (BIT_C, (resval & 0x10000)); } else { store1(opaddr, resval &0xff); FLAG_ASSIGN (BIT_Z, (resval & 0xff) == 0); FLAG_ASSIGN (BIT_N, 0x80 & resval); FLAG_ASSIGN (BIT_C, (resval & 0x100)); } return(resGO); } int cl_stm8::inst_sra(t_mem code, unsigned char prefix) { long int operand, resval; unsigned int opaddr = 0; if (((code&0xf0)==0x40) &&(prefix == 0x00)) { operand = regs.A; } else if (((code&0xf0)==0x50) &&(prefix == 0x00)) { operand = regs.X; } else if (((code&0xf0)==0x50) &&(prefix == 0x90)) { operand = regs.Y; } else { opaddr = get_dest(code,prefix); operand = get1(opaddr); } resval = operand >> 1; if (((code&0xf0)==0x40) &&(prefix == 0x00)) { if (operand & 0x80) { resval |= 0x80; } regs.A = resval&0xff; FLAG_ASSIGN (BIT_Z, (resval & 0xff) == 0); FLAG_ASSIGN (BIT_N, 0x80 & resval); FLAG_ASSIGN (BIT_C, (operand & 0x1)); } else if (((code&0xf0)==0x50) &&(prefix == 0x00)) { if (operand & 0x8000) { resval |= 0x8000; } regs.X = resval & 0xffff; FLAG_ASSIGN (BIT_Z, (resval & 0xffff) == 0); FLAG_ASSIGN (BIT_N, 0x8000 & resval); FLAG_ASSIGN (BIT_C, (operand & 0x1)); } else if (((code&0xf0)==0x50) &&(prefix == 0x90)) { if (operand & 0x8000) { resval |= 0x8000; } regs.Y = resval & 0xffff; FLAG_ASSIGN (BIT_Z, (resval & 0xffff) == 0); FLAG_ASSIGN (BIT_N, 0x8000 & resval); FLAG_ASSIGN (BIT_C, (operand & 0x1)); } else { if (operand & 0x80) { resval |= 0x80; } store1(opaddr, resval &0xff); FLAG_ASSIGN (BIT_Z, (resval & 0xff) == 0); FLAG_ASSIGN (BIT_N, 0x80 & resval); FLAG_ASSIGN (BIT_C, (operand & 0x1)); } return(resGO); } int cl_stm8::inst_srl(t_mem code, unsigned char prefix) { long int operand, resval; unsigned int opaddr = 0; if (((code&0xf0)==0x40) &&(prefix == 0x00)) { operand = regs.A; } else if (((code&0xf0)==0x50) &&(prefix == 0x00)) { operand = regs.X; } else if (((code&0xf0)==0x50) &&(prefix == 0x90)) { operand = regs.Y; } else { opaddr = get_dest(code,prefix); operand = get1(opaddr); } resval = operand >> 1; if (((code&0xf0)==0x40) &&(prefix == 0x00)) { regs.A = resval&0xff; FLAG_ASSIGN (BIT_Z, (resval & 0xff) == 0); FLAG_ASSIGN (BIT_N, 0x80 & resval); FLAG_ASSIGN (BIT_C, (operand & 0x1)); } else if (((code&0xf0)==0x50) &&(prefix == 0x00)) { regs.X = resval & 0xffff; FLAG_ASSIGN (BIT_Z, (resval & 0xffff) == 0); FLAG_ASSIGN (BIT_N, 0x8000 & resval); FLAG_ASSIGN (BIT_C, (operand & 0x1)); } else if (((code&0xf0)==0x50) &&(prefix == 0x90)) { regs.Y = resval & 0xffff; FLAG_ASSIGN (BIT_Z, (resval & 0xffff) == 0); FLAG_ASSIGN (BIT_N, 0x8000 & resval); FLAG_ASSIGN (BIT_C, (operand & 0x1)); } else { store1(opaddr, resval &0xff); FLAG_ASSIGN (BIT_Z, (resval & 0xff) == 0); FLAG_ASSIGN (BIT_N, 0x80 & resval); FLAG_ASSIGN (BIT_C, (operand & 0x1)); } return(resGO); } int cl_stm8::inst_sub(t_mem code, unsigned char prefix) { FLAG_CLEAR(BIT_C); return inst_sbc(code, prefix); } int cl_stm8::inst_swap(t_mem code, unsigned char prefix) { long int operand, resval; unsigned int opaddr = 0; if (((code&0xf0)==0x40) &&(prefix == 0x00)) { operand = regs.A; resval = (operand << 4) | (operand >> 4); regs.A = resval&0xff; FLAG_ASSIGN (BIT_Z, (resval & 0xff) == 0); FLAG_ASSIGN (BIT_N, 0x80 & resval); } else if (((code&0xf0)==0x50) &&(prefix == 0x00)) { operand = regs.X; resval = (operand << 8) | (operand >> 8); regs.X = resval&0xffff; FLAG_ASSIGN (BIT_Z, (resval & 0xffff) == 0); FLAG_ASSIGN (BIT_N, 0x8000 & resval); } else if (((code&0xf0)==0x50) &&(prefix == 0x90)) { operand = regs.Y; resval = (operand << 8) | (operand >> 8); regs.Y = resval&0xffff; FLAG_ASSIGN (BIT_Z, (resval & 0xffff) == 0); FLAG_ASSIGN (BIT_N, 0x8000 & resval); } else { opaddr = get_dest(code,prefix); operand = get1(opaddr); resval = (operand << 4) | (operand >> 4); store1(opaddr, resval &0xff); FLAG_ASSIGN (BIT_Z, (resval & 0xff) == 0); FLAG_ASSIGN (BIT_N, 0x80 & resval); } return(resGO); } int cl_stm8::inst_tnz(t_mem code, unsigned char prefix) { unsigned int resval; unsigned int opaddr = 0; if (((code&0xf0)==0x40) &&(prefix == 0x00)) { resval = regs.A; FLAG_ASSIGN (BIT_Z, (resval & 0xff) == 0); FLAG_ASSIGN (BIT_N, 0x80 & resval); } else if (((code&0xf0)==0x50) &&(prefix == 0x00)) { resval = regs.X; FLAG_ASSIGN (BIT_Z, (resval & 0xffff) == 0); FLAG_ASSIGN (BIT_N, 0x8000 & resval); } else if (((code&0xf0)==0x50) &&(prefix == 0x90)) { resval = regs.Y; FLAG_ASSIGN (BIT_Z, (resval & 0xffff) == 0); FLAG_ASSIGN (BIT_N, 0x8000 & resval); } else { opaddr = get_dest(code,prefix); resval = get1(opaddr); FLAG_ASSIGN (BIT_Z, (resval & 0xff) == 0); FLAG_ASSIGN (BIT_N, 0x80 & resval); } return(resGO); } int cl_stm8::inst_xor(t_mem code, unsigned char prefix) { int result, operand1, operand2; operand1 = regs.A; operand2 = OPERAND(code, prefix); result = operand1 ^ operand2; FLAG_NZ (result); regs.A = result & 0xff; return(resGO); } /* End of stm8.src/inst.cc */