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