--- /dev/null
+/*-------------------------------------------------------------------------
+ _mullong.c - routine for multiplication of 32 bit (unsigned) long
+
+ Written By - Jean Louis VERN jlvern@writeme.com (1999)
+ Written By - Sandeep Dutta . sandeep.dutta@usa.net (1999)
+
+ This library is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Library General Public License as published by the
+ Free Software Foundation; either version 2, or (at your option) any
+ later version.
+
+ This library 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 Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+ In other words, you are welcome to use, share and improve this program.
+ You are forbidden to forbid anyone else to use, share and improve
+ what you give them. Help stamp out software-hoarding!
+-------------------------------------------------------------------------*/
+
+/* Signed and unsigned multiplication are the same - as long as the output
+ has the same precision as the input.
+
+ Assembler-functions are provided for:
+ mcs51 small
+ mcs51 small stack-auto
+*/
+
+
+struct some_struct {
+ short a ;
+ char b;
+ long c ;};
+union bil {
+ struct {unsigned char b3,b2,b1,b0 ;} b;
+ struct {unsigned short hi,lo ;} i;
+ unsigned long l;
+ struct { unsigned char b3; unsigned short i12; unsigned char b0;} bi;
+} ;
+
+# define bcast(x) ((union bil *)&(x))
+
+/*
+ 3 2 1 0
+ X 3 2 1 0
+ ----------------------------
+ 0.3 0.2 0.1 0.0
+ 1.3 1.2 1.1 1.0
+ 2.3 2.2 2.1 2.0
+ 3.3 3.2 3.1 3.0
+ ----------------------------
+ |3.3|1.3|0.2|0.0| A
+ |2.3|0.3|0.1| B
+ |3.2|1.2|1.0| C
+ |2.2|1.1| D
+ |3.1|2.0| E
+ |2.1| F
+ |3.0| G
+ |-------> only this side 32 x 32 -> 32
+*/
+long
+_mullong (long a, long b)
+{
+ union bil t;
+
+ t.i.hi = bcast(a)->b.b0 * bcast(b)->b.b2; // A
+ t.i.lo = bcast(a)->b.b0 * bcast(b)->b.b0; // A
+ t.b.b3 += bcast(a)->b.b3 *
+ bcast(b)->b.b0; // G
+ t.b.b3 += bcast(a)->b.b2 *
+ bcast(b)->b.b1; // F
+ t.i.hi += bcast(a)->b.b2 * bcast(b)->b.b0; // E <- b lost in .lst
+ // bcast(a)->i.hi is free !
+ t.i.hi += bcast(a)->b.b1 * bcast(b)->b.b1; // D <- b lost in .lst
+
+ bcast(a)->bi.b3 = bcast(a)->b.b1 *
+ bcast(b)->b.b2;
+ bcast(a)->bi.i12 = bcast(a)->b.b1 *
+ bcast(b)->b.b0; // C
+
+ bcast(b)->bi.b3 = bcast(a)->b.b0 *
+ bcast(b)->b.b3;
+ bcast(b)->bi.i12 = bcast(a)->b.b0 *
+ bcast(b)->b.b1; // B
+ bcast(b)->bi.b0 = 0; // B
+ bcast(a)->bi.b0 = 0; // C
+ t.l += a;
+
+ return t.l + b;
+}
+
+#endif // _MULLONG_ASM
int
cl_hc08::inst_add(t_mem code, bool prefix)
{
- int result;
- uchar operand;
+ int result, operand1, operand2;
- operand = OPERAND(code, prefix);
- result = (regs.A + operand) & 0xff;
+ operand1 = regs.A;
+ operand2 = OPERAND(code, prefix);
+ result = operand1 + operand2;
FLAG_NZ (result);
- FLAG_ASSIGN (BIT_V, 0x80 & ((regs.A & operand & ~result)
- | (~regs.A & ~operand & result)));
- FLAG_ASSIGN (BIT_H, 0x08 & ((regs.A & operand)
- | (operand & ~result)
- | (~result & regs.A)));
- FLAG_ASSIGN (BIT_C, 0x80 & ((regs.A & operand)
- | (operand & ~result)
- | (~result & regs.A)));
-
-#if 0
- fprintf (stdout, "add 0x%02x + 0x%02x = 0x%02x ",regs.A, operand, result & 0xff);
- fprintf (stdout, "(V=%d, H=%d, C=%d, N=%d, Z=%d), ",
- (regs.P & BIT_V)!=0,
- (regs.P & BIT_H)!=0,
- (regs.P & BIT_C)!=0,
- (regs.P & BIT_N)!=0,
- (regs.P & BIT_Z)!=0);
-#endif
+ FLAG_ASSIGN (BIT_V, 0x80 & (operand1 ^ operand2 ^ result ^ (result >>1)));
+ FLAG_ASSIGN (BIT_C, 0x100 & result);
+ FLAG_ASSIGN (BIT_H, 0x10 & (operand1 ^ operand2 ^ result));
- regs.A = result;
+ regs.A = result & 0xff;
return(resGO);
}
int
cl_hc08::inst_adc(t_mem code, bool prefix)
{
- int result;
- uchar operand;
- int sresult;
- uchar carryin = (regs.P & BIT_C)!=0;
-
- operand = OPERAND(code, prefix);
- result = regs.A + operand + carryin;
- sresult = (signed char)regs.A + (signed char)operand + ((regs.P & BIT_C)!=0);
- FLAG_NZ (result & 0xff);
- FLAG_ASSIGN (BIT_V, (sresult<-128) || (sresult>127));
- /* 0x80 & ((regs.A & operand & ~result)
- | (~regs.A & ~operand & result))); */
- FLAG_ASSIGN (BIT_H, (result & 0xf) < (regs.A & 0xf));
- /* 0x10 & ((regs.A & operand)
- | (operand & ~result)
- | (~result & regs.A))); */
- FLAG_ASSIGN (BIT_C, result & 0x100);
- /* 0x80 & ((regs.A & operand)
- | (operand & ~result)
- | (~result & regs.A))); */
-
-#if 0
- fprintf (stdout, "adc 0x%02x + 0x%02x + %d = 0x%02x ",
- regs.A, operand, carryin, result & 0xff);
- fprintf (stdout, "(V=%d, H=%d, C=%d, N=%d, Z=%d), ",
- (regs.P & BIT_V)!=0,
- (regs.P & BIT_H)!=0,
- (regs.P & BIT_C)!=0,
- (regs.P & BIT_N)!=0,
- (regs.P & BIT_Z)!=0);
-#endif
-
+ int result, operand1, operand2;
+ int carryin = (regs.P & BIT_C)!=0;
+
+ operand1 = regs.A;
+ operand2 = OPERAND(code, prefix);
+ result = operand1 + operand2 + carryin;
+ FLAG_NZ (result);
+ FLAG_ASSIGN (BIT_V, 0x80 & (operand1 ^ operand2 ^ result ^ (result >>1)));
+ FLAG_ASSIGN (BIT_C, 0x100 & result);
+ FLAG_ASSIGN (BIT_H, 0x10 & (operand1 ^ operand2 ^ result));
+
regs.A = result & 0xff;
return(resGO);
}
int
cl_hc08::inst_sub(t_mem code, bool prefix)
{
- int result;
- uchar operand;
+ int result, operand1, operand2;
- operand = OPERAND(code, prefix);
- result = (regs.A - operand) & 0xff;
+ operand1 = regs.A;
+ operand2 = OPERAND(code, prefix);
+ result = operand1 - operand2;
FLAG_NZ (result);
- FLAG_ASSIGN (BIT_V, 0x80 & ((regs.A & ~operand & ~result)
- | (~regs.A & operand & result)));
- FLAG_ASSIGN (BIT_C, 0x80 & ((~regs.A & operand)
- | (operand & result)
- | (result & ~regs.A)));
-#if 0
- fprintf (stdout, "sub 0x%02x - 0x%02x = 0x%02x ",regs.A, operand, result & 0xff);
- fprintf (stdout, "(V=%d, H=%d, C=%d, N=%d, Z=%d), ",
- (regs.P & BIT_V)!=0,
- (regs.P & BIT_H)!=0,
- (regs.P & BIT_C)!=0,
- (regs.P & BIT_N)!=0,
- (regs.P & BIT_Z)!=0);
-#endif
- regs.A = result;
+ FLAG_ASSIGN (BIT_V, 0x80 & (operand1 ^ operand2 ^ result ^ (result >>1)));
+ FLAG_ASSIGN (BIT_C, 0x100 & result);
+
+ regs.A = result & 0xff;
return(resGO);
}
int
cl_hc08::inst_sbc(t_mem code, bool prefix)
{
- int result;
- uchar operand;
- uchar carryin = (regs.P & BIT_C)!=0;
+ int result, operand1, operand2;
+ int carryin = (regs.P & BIT_C)!=0;
- operand = OPERAND(code, prefix);
- result = (regs.A - operand - carryin) & 0xff;
+ operand1 = regs.A;
+ operand2 = OPERAND(code, prefix);
+ result = operand1 - operand2 - carryin;
FLAG_NZ (result);
- FLAG_ASSIGN (BIT_V, 0x80 & ((regs.A & ~operand & ~result)
- | (~regs.A & operand & result)));
- FLAG_ASSIGN (BIT_C, 0x80 & ((~regs.A & operand)
- | (operand & result)
- | (result & ~regs.A)));
-#if 0
- fprintf (stdout, "sbc 0x%02x - 0x%02x - %d = 0x%02x ",
- regs.A, operand, carryin, result & 0xff);
- fprintf (stdout, "(V=%d, H=%d, C=%d, N=%d, Z=%d), ",
- (regs.P & BIT_V)!=0,
- (regs.P & BIT_H)!=0,
- (regs.P & BIT_C)!=0,
- (regs.P & BIT_N)!=0,
- (regs.P & BIT_Z)!=0);
-#endif
- regs.A = result;
+ FLAG_ASSIGN (BIT_V, 0x80 & (operand1 ^ operand2 ^ result ^ (result >>1)));
+ FLAG_ASSIGN (BIT_C, 0x100 & result);
+
+ regs.A = result & 0xff;
return(resGO);
}
int
cl_hc08::inst_cmp(t_mem code, bool prefix)
{
- int result;
- uchar operand;
+ int result, operand1, operand2;
- operand = OPERAND(code, prefix);
- result = (regs.A - operand) & 0xff;
+ operand1 = regs.A;
+ operand2 = OPERAND(code, prefix);
+ result = operand1 - operand2;
FLAG_NZ (result);
- FLAG_ASSIGN (BIT_V, 0x80 & ((regs.A & ~operand & ~result)
- | (~regs.A & operand & result)));
- FLAG_ASSIGN (BIT_C, 0x80 & ((~regs.A & operand)
- | (operand & result)
- | (result & ~regs.A)));
+ FLAG_ASSIGN (BIT_V, 0x80 & (operand1 ^ operand2 ^ result ^ (result >>1)));
+ FLAG_ASSIGN (BIT_C, 0x100 & result);
+
return(resGO);
}
int
cl_hc08::inst_cpx(t_mem code, bool prefix)
{
- int result;
- uchar operand;
+ int result, operand1, operand2;
- operand = OPERAND(code, prefix);
- result = (regs.X - operand) & 0xff;
+ operand1 = regs.X;
+ operand2 = OPERAND(code, prefix);
+ result = operand1 - operand2;
FLAG_NZ (result);
- FLAG_ASSIGN (BIT_V, 0x80 & ((regs.X & ~operand & ~result)
- | (~regs.X & operand & result)));
- FLAG_ASSIGN (BIT_C, 0x80 & ((~regs.X & operand)
- | (operand & result)
- | (result & ~regs.X)));
+ FLAG_ASSIGN (BIT_V, 0x80 & (operand1 ^ operand2 ^ result ^ (result >>1)));
+ FLAG_ASSIGN (BIT_C, 0x100 & result);
+
return(resGO);
}
int
cl_hc08::inst_aix(t_mem code, bool prefix)
{
- regs.X = regs.X + (signed char)fetch();
+ int hx = (regs.H << 8) | (regs.X);
+ hx += (signed char)fetch();
+ regs.H = (hx >> 8) & 0xff;
+ regs.X = hx & 0xff;
return(resGO);
}
int
cl_hc08::inst_div(t_mem code, bool prefix)
{
- int dividend = (regs.H << 8) | regs.A;
- int quotient;
+ unsigned int dividend = (regs.H << 8) | regs.A;
+ unsigned int quotient;
if (regs.X) {
- quotient = dividend / regs.X;
+ quotient = dividend / (unsigned int)regs.X;
if (quotient<=0xff) {
regs.A = quotient;
regs.H = dividend % regs.X;
store1((ea+1) & 0xffff, regs.X);
FLAG_CLEAR(BIT_V);
- FLAG_ASSIGN(BIT_N, regs.X & 0x80);
- FLAG_ASSIGN(BIT_Z, !regs.X && !regs.A);
+ FLAG_ASSIGN(BIT_N, regs.H & 0x80);
+ FLAG_ASSIGN(BIT_Z, !regs.X && !regs.H);
return(resGO);
}
return(resHALT);
FLAG_CLEAR(BIT_V);
- FLAG_ASSIGN(BIT_N, regs.X & 0x80);
- FLAG_ASSIGN(BIT_Z, !regs.X && !regs.A);
+ FLAG_ASSIGN(BIT_N, regs.H & 0x80);
+ FLAG_ASSIGN(BIT_Z, !regs.X && !regs.H);
return(resGO);
}
return(resHALT);
hx = (regs.H << 8) | regs.X;
+ result = hx-operand;
- result = (hx-operand) & 0xffff;
-
- FLAG_ASSIGN (BIT_V, 0x8000 & ((hx & ~operand & ~result)
- | (~hx & operand & result)));
- FLAG_ASSIGN (BIT_C, 0x8000 & ((~hx & operand)
- | (operand & result)
- | (result & ~hx)));
+ FLAG_ASSIGN (BIT_V, 0x8000 & (hx ^ operand ^ result ^ (result>>1)));
+ FLAG_ASSIGN (BIT_C, 0x10000 & result);
FLAG_ASSIGN(BIT_N, result & 0x8000);
- FLAG_ASSIGN(BIT_Z, !result);
+ FLAG_ASSIGN(BIT_Z, !(result & 0xffff));
return(resGO);
}