1 /*
2  * @ingroup   lib_emu68
3  * @file      emu68/inl68_arithmetic.h
4  * @brief     68k arithmetical instruction inlines.
5  * @author    Benjamin Gerard
6  * @date      2009/05/18
7  */
8 
9 /* Copyright (c) 1998-2015 Benjamin Gerard */
10 
11 #ifndef INL68_ARITHMETIC_H
12 #define INL68_ARITHMETIC_H
13 
14 static inline
inl_add68(emu68_t * const emu68,int68_t s,int68_t d,int68_t c)15 int68_t inl_add68(emu68_t * const emu68, int68_t s, int68_t d, int68_t c)
16 {
17   /*
18     Official version from 68K RPM :
19     V = (s & d & ~r) | (~s & ~d & r);  // MSBit only
20     C = (s & d) | (~r & d) | (s & ~r); // MSBit only
21     X = C;
22     Z = !r;
23     N = r;                             // MSBit only
24   */
25   const int68_t r = ( c += s + d );
26   c  = ( ( r >> SIGN_BIT ) & ( SR_V | SR_C | SR_X | SR_N ) ) ^ SR_V;
27   s  = ( ( s >> SIGN_BIT ) & ( SR_V | SR_C | SR_X ) ) ^ c;
28   d  = ( ( d >> SIGN_BIT ) & ( SR_V | SR_C | SR_X ) ) ^ c;
29   c &= ~SR_N;
30   c |= SR_V | ( !r << SR_Z_BIT );
31   c ^= s | d;
32   REG68.sr = ( REG68.sr & 0xFF00 ) | c;
33   return r;
34 }
35 
36 static inline
inl_sub68(emu68_t * const emu68,int68_t s,int68_t d,int68_t c)37 int68_t inl_sub68(emu68_t * const emu68, int68_t s, int68_t d, int68_t c)
38 {
39   /*
40     Official version from 68K RPM :
41     V = (~s & d & ~r) | (s & ~d & r);   // MSBit only
42     C = (s & ~d) | (r & ~d) | (s & r);  // MSBit only
43     X = C
44     Z = !r;
45     N = r;                              // MSBit only
46   */
47   const int68_t r = d - s - c;
48   REG68.sr = ( REG68.sr & 0xFF00 )
49     | (!r << SR_Z_BIT)
50     | (( r >> SIGN_BIT ) & SR_N)
51     | (((((d ^ ~r) & (s ^ r)) ^ r) >> SIGN_BIT) & (SR_C|SR_X))
52     | ((((d ^ r) & (~s ^ r)) >> SIGN_BIT) & SR_V)
53     ;
54   return r;
55 }
56 
57 static inline
inl_cmp68(emu68_t * const emu68,int68_t s,int68_t d)58 void inl_cmp68(emu68_t * const emu68, int68_t s, int68_t d)
59 {
60   /* Like SUB but X is not taken into account nor affected. */
61   const int68_t r = d - s;
62   REG68.sr = ( REG68.sr & ( 0xFF00 | SR_X ) )
63     | (!r << SR_Z_BIT)
64     | (( r >> SIGN_BIT ) & SR_N)
65     | (((((d ^ ~r) & (s ^ r)) ^ r) >> SIGN_BIT) & SR_C)
66     | ((((d ^ r) & (~s ^ r)) >> SIGN_BIT) & SR_V)
67     ;
68 }
69 
70 static inline
inl_neg68(emu68_t * const emu68,int68_t d,int68_t c)71 int68_t inl_neg68(emu68_t * const emu68, int68_t d, int68_t c)
72 {
73   /*
74     Official version from 68K RPM :
75     V = (d & r)                         // MSBit only
76     C = (d | r)                         // MSBit only
77     X = C
78     Z = !r;
79     N = r;                              // MSBit only
80   */
81   int sr = REG68.sr & 0xFF00;
82   const int68_t r = ( c = -d - c );
83   sr |= !r << SR_Z_BIT;
84   d >>= SIGN_BIT;
85   c >>= SIGN_BIT;
86   sr |= c & SR_N;
87   sr |= ( d | c ) & (SR_C|SR_X);
88   sr |= ( d & c ) & SR_V;
89   REG68.sr = sr;
90   return r;
91 }
92 
93 
94 static inline
inl_muls68(emu68_t * const emu68,int68_t s,int68_t d)95 int68_t inl_muls68(emu68_t * const emu68, int68_t s, int68_t d)
96 {
97   d        = ( d >> WORD_FIX ) * ( s >> WORD_FIX );
98   REG68.sr = ( REG68.sr & ( 0xFF00 | SR_X ) )
99     | ( !d << SR_Z_BIT )
100     | ( (d >> (31 - SR_N_BIT)) & SR_N );
101   return d << LONG_FIX;
102 }
103 
104 static inline
inl_mulu68(emu68_t * const emu68,uint68_t s,uint68_t d)105 int68_t inl_mulu68(emu68_t * const emu68, uint68_t s, uint68_t d)
106 {
107   d        = ( d >> WORD_FIX ) * ( s >> WORD_FIX );
108   REG68.sr = ( REG68.sr & ( 0xFF00 | SR_X ) )
109     | ( !d << SR_Z_BIT )
110     | ( (d >> (31 - SR_N_BIT)) & SR_N );
111   return d << LONG_FIX;
112 }
113 
114 static inline
inl_divs68(emu68_t * const emu68,int68_t s,int68_t d)115 int68_t inl_divs68(emu68_t * const emu68, int68_t s, int68_t d)
116 {
117   int sr = REG68.sr & (0xFF00 | SR_X);  /* X unaffected; C cleared */
118   if ( s >>= WORD_FIX ) {
119     int68_t res, rem;
120     d >>= LONG_FIX;
121     res = d / s;
122     rem = d % s;
123 
124     if ( (s16)res != res )
125       sr |= SR_V;                       /* V on overflow */
126     else
127       d = ( (int68_t) (u16) res ) | ( (int68_t) (u16) rem << 16 );
128     sr |= !res << SR_Z_BIT;                    /* Z */
129     sr |= ( res >> ( 15 - SR_N_BIT ) ) & SR_N; /* N */
130     REG68.sr = sr;
131     d <<= LONG_FIX;
132   } else {
133     /* Divide by zero */
134     REG68.sr = sr;
135     inl_exception68(emu68, DIVIDE_VECTOR, -1);
136   }
137   return d;
138 }
139 
140 static inline
inl_divu68(emu68_t * const emu68,uint68_t s,uint68_t d)141 int68_t inl_divu68(emu68_t * const emu68, uint68_t s, uint68_t d)
142 {
143   int sr = REG68.sr & (0xFF00 | SR_X);  /* X unaffected; C cleared */
144   if ( s >>= WORD_FIX ) {
145     uint68_t res, rem;
146     d >>= LONG_FIX;
147     res = d / s;
148     rem = d % s;
149 
150     if ( (u16)res != res )
151       sr |= SR_V;                       /* V on overflow */
152     else
153       d = ( res ) | ( rem << 16 );
154     sr |= !res << SR_Z_BIT;                    /* Z */
155     sr |= ( res >> ( 15 - SR_N_BIT ) ) & SR_N; /* N */
156     REG68.sr = sr;
157     d <<= LONG_FIX;
158   } else {
159     /* Divide by zero */
160     REG68.sr = sr;
161     inl_exception68(emu68, DIVIDE_VECTOR, -1);
162   }
163   return d;
164 }
165 
166 static inline
inl_clr68(emu68_t * const emu68)167 int68_t inl_clr68(emu68_t * const emu68)
168 {
169   REG68.sr = ( REG68.sr & ( 0xFF00 | SR_X ) ) | SR_Z;
170   return 0;
171 }
172 
173 #endif
174