1 /*
2
3 Copyright 2021, dettus@dettus.net
4
5 Redistribution and use in source and binary forms, with or without modification,
6 are permitted provided that the following conditions are met:
7
8 1. Redistributions of source code must retain the above copyright notice, this
9 list of conditions and the following disclaimer.
10
11 2. Redistributions in binary form must reproduce the above copyright notice,
12 this list of conditions and the following disclaimer in the documentation
13 and/or other materials provided with the distribution.
14
15 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
16 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
19 FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
21 SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
22 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
23 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25
26
27 */
28
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include "vm68k.h"
32 #include "vm68k_decode.h"
33 #include "vm68k_datatypes.h"
34 #include "vm68k_macros.h"
35 #include "vm68k_loadstore.h"
36
37
38
39
vm68k_getbytesize(tVM68k_types size)40 int vm68k_getbytesize(tVM68k_types size)
41 {
42 switch(size)
43 {
44 case VM68K_BYTE: return 1;break;
45 case VM68K_WORD: return 2;break;
46 case VM68K_LONG: return 4;break;
47 default: return 0;
48 }
49 return 0;
50 }
51 // the way addresses are stored here is that memory addresses are >=0. <=0 addresses the registers.
52
vm68k_resolve_ea(tVM68k * pVM68k,tVM68k_next * pNext,tVM68k_types size,tVM68k_addrmodes addrmode,tVM68k_ubyte reg,tVM68k_uword legal,tVM68k_slong * ea)53 int vm68k_resolve_ea(tVM68k* pVM68k,tVM68k_next *pNext,tVM68k_types size,
54 tVM68k_addrmodes addrmode,tVM68k_ubyte reg,
55 tVM68k_uword legal,tVM68k_slong* ea)
56 {
57 tVM68k_sbyte bytesize;
58 int retval;
59 retval=VM68K_NOK_UNKNOWN_INSTRUCTION;
60 bytesize=vm68k_getbytesize(size);
61 if (addrmode==VM68K_AM_EXT)
62 {
63 switch ((tVM68k_addrmode_ext)reg)
64 {
65 case VM68K_AMX_W: if (legal&VM68K_LEGAL_AMX_W)
66 {
67 *ea=(tVM68k_sword)READEXTENSIONWORD(pVM68k,pNext);
68 retval=VM68K_OK;
69 }
70 break;
71 case VM68K_AMX_L: if (legal&VM68K_LEGAL_AMX_L)
72 {
73 *ea=(tVM68k_slong)READEXTENSIONLONG(pVM68k,pNext);
74 retval=VM68K_OK;
75 }
76 break;
77 case VM68K_AMX_data: if (legal&VM68K_LEGAL_AMX_DATA)
78 {
79 *ea=pNext->pcr;
80 retval=VM68K_OK;
81 switch (size)
82 {
83 case VM68K_BYTE: *ea+=1;pNext->pcr+=2;break;
84 case VM68K_WORD: pNext->pcr+=2;break;
85 case VM68K_LONG: pNext->pcr+=4;break;
86 default: retval=VM68K_NOK_UNKNOWN_INSTRUCTION;
87 }
88 }
89 break;
90 case VM68K_AMX_PC: if (legal&VM68K_LEGAL_AMX_PC)
91 {
92 *ea=READEXTENSIONWORD(pVM68k,pNext);
93 *ea=(tVM68k_sword)(*ea)+pVM68k->pcr;
94 retval=VM68K_OK;
95 }
96 break;
97 case VM68K_AMX_INDEX_PC: if (legal&VM68K_LEGAL_AMX_INDEX_PC)
98 {
99 *ea=READEXTENSIONWORD(pVM68k,pNext);
100 *ea=*ea+pVM68k->pcr;
101 *ea=*ea+pVM68k->a[reg]*bytesize; // TODO: data or addrreg?
102 retval=VM68K_NOK_UNKNOWN_INSTRUCTION; // TODO: lets decide when we stumble upon this mode
103 }
104 break;
105 }
106 } else {
107 switch (addrmode)
108 {
109 case VM68K_AM_DATAREG: if (legal&VM68K_LEGAL_AM_DATAREG)
110 {
111 *ea=DATAREGADDR(reg);
112 retval=VM68K_OK;
113 }
114 break;
115 case VM68K_AM_ADDRREG: if (legal&VM68K_LEGAL_AM_ADDRREG)
116 {
117 *ea=ADDRREGADDR(reg);
118 retval=VM68K_OK;
119 }
120 break;
121 case VM68K_AM_INDIR: if (legal&VM68K_LEGAL_AM_INDIR)
122 {
123 *ea=(pVM68k->a[reg])%pVM68k->memsize;
124 retval=VM68K_OK;
125 }
126 break;
127 case VM68K_AM_POSTINC: if (legal&VM68K_LEGAL_AM_POSTINC)
128 {
129 *ea=pVM68k->a[reg];
130 pNext->a[reg]+=bytesize;
131 retval=VM68K_OK;
132 }
133 break;
134 case VM68K_AM_PREDEC: if (legal&VM68K_LEGAL_AM_PREDEC)
135 {
136 pNext->a[reg]-=bytesize;
137 *ea=pNext->a[reg];
138 retval=VM68K_OK;
139 }
140 break;
141 case VM68K_AM_DISP16: if (legal&VM68K_LEGAL_AM_DISP16)
142 {
143 *ea=(tVM68k_sword)READEXTENSIONWORD(pVM68k,pNext);
144 *ea=(*ea)+pVM68k->a[reg];
145 retval=VM68K_OK;
146 }
147 break;
148 case VM68K_AM_INDEX: if (legal&VM68K_LEGAL_AM_INDEX)
149 {
150 tVM68k_uword extword;
151 // bit 15: =0 data, =1 addr reg
152 // bit 14..12: regnum
153 // bit 11: =0 index register is a signed word
154 // =1 index register is a signed long
155 // bit 10..8: UNKNOWN
156 // bit 7..0: displacement, signed byte
157 tVM68k_ubyte regX;
158 tVM68k_sbyte displacement1;
159 tVM68k_slong displacement2l;
160 tVM68k_sword displacement2w;
161
162 extword=(tVM68k_uword)READEXTENSIONWORD(pVM68k,pNext);
163 regX=(extword>>12)&0x7;
164 displacement1=(extword&0xff);
165 if ((extword>>15)&1)
166 {
167 displacement2l=pVM68k->a[regX];
168 displacement2w=(pVM68k->a[regX]&0xffff);
169 } else {
170 displacement2l=pVM68k->d[regX];
171 displacement2w=(pVM68k->d[regX]&0xffff);
172 }
173 *ea=displacement1+(((extword>>11)&1)?displacement2l:displacement2w);
174 *ea=(*ea)+pVM68k->a[reg];
175 retval=VM68K_OK;
176
177 }
178 break;
179 default: retval=VM68K_NOK_INVALID_PTR;break;
180 }
181 }
182 return retval;
183 }
184
185 // the way addresses are stored here is that memory addresses are >=0. <=0 addresses the registers.
vm68k_fetchoperand(tVM68k * pVM68k,tVM68k_bool extendsign,tVM68k_types size,tVM68k_slong ea,tVM68k_ulong * operand)186 int vm68k_fetchoperand(tVM68k* pVM68k,tVM68k_bool extendsign,tVM68k_types size,tVM68k_slong ea,tVM68k_ulong* operand)
187 {
188 int retval;
189 tVM68k_ulong op;
190 op=0;
191 if (ea>=0) // memory address
192 {
193 ea%=pVM68k->memsize; // just to be safe...
194 retval=VM68K_OK;
195 switch (size)
196 {
197 case VM68K_BYTE: op= READ_INT8BE(pVM68k->pMem,ea);break;
198 case VM68K_WORD: op=READ_INT16BE(pVM68k->pMem,ea);break;
199 case VM68K_LONG: op=READ_INT32BE(pVM68k->pMem,ea);break;
200 default: retval=VM68K_NOK_INVALID_PTR;break;
201 }
202 } else { // register address
203 if (ea>=DATAREGADDR(7) && ea<=DATAREGADDR(0))
204 {
205 op=pVM68k->d[-ea+DATAREGADDR(0)];
206 retval=VM68K_OK;
207 }
208 else if (ea>=ADDRREGADDR(7) && ea<=ADDRREGADDR(0))
209 {
210 op=pVM68k->a[-ea+ADDRREGADDR(0)];
211 retval=VM68K_OK;
212 }
213 else retval=VM68K_NOK_UNKNOWN_INSTRUCTION;
214 }
215 switch (size)
216 {
217 case VM68K_BYTE: op&= 0xff;if (extendsign) op=(tVM68k_slong)((tVM68k_sbyte)op);break;
218 case VM68K_WORD: op&=0xffff;if (extendsign) op=(tVM68k_slong)((tVM68k_sword)op);break;
219 default:
220 break;
221 }
222 *operand=op;
223 return retval;
224 }
vm68k_calculateflags(tVM68k_next * pNext,tVM68k_ubyte flagmask,tVM68k_types size,tVM68k_ulong operand1,tVM68k_ulong operand2,tVM68k_uint64 result)225 int vm68k_calculateflags(tVM68k_next* pNext,tVM68k_ubyte flagmask,tVM68k_types size,tVM68k_ulong operand1,tVM68k_ulong operand2,tVM68k_uint64 result)
226 {
227 tVM68k_ubyte msb;
228 tVM68k_ulong mask;
229 tVM68k_sint64 maxval,minval;
230 tVM68k_sint64 res;
231 int retval;
232
233 retval=VM68K_OK;
234 mask=0;
235 msb=0;
236 maxval=0;
237 minval=0;
238 res=0;
239 switch (size)
240 {
241 case VM68K_BYTE: msb= 8;mask= 0xff;maxval= 0x7fll;minval= -0x80ll;res=((tVM68k_sint64)((tVM68k_sbyte)(result& 0xff)));break;
242 case VM68K_WORD: msb=16;mask= 0xffff;maxval= 0x7fffll;minval= -0x8000ll;res=((tVM68k_sint64)((tVM68k_sbyte)(result& 0xffff)));break;
243 case VM68K_LONG: msb=32;mask=0xffffffff;maxval=0x7fffffffll;minval=-0x80000000ll;res=((tVM68k_sint64)((tVM68k_sbyte)(result&0xffffffff)));break;
244 default: retval=VM68K_NOK_INVALID_PTR;break;
245 }
246 if (flagmask&FLAGC) pNext->cflag=((operand2^result)>>msb)&1;
247 if (flagmask&FLAGZ) pNext->zflag=((result&mask)==0);
248 if (flagmask&FLAGN) pNext->nflag=(result>>(msb-1))&1;
249 // if (flagmask&FLAGV) pNext->vflag=((operand1^operand2^result)>>(msb-1))&1;
250 //if (flagmask&FLAGV) pNext->vflag=((~(operand1^operand2)^result)>>(msb-1))&1;
251 if (flagmask&FLAGV) pNext->vflag=((res>maxval)||(res<minval));
252 if (flagmask&FLAGX) pNext->xflag=pNext->cflag;
253 if (flagmask&FLAGCZCLR) {pNext->cflag=0;pNext->vflag=0;}
254
255 return retval;
256 }
vm68k_calculateflags2(tVM68k_next * pNext,tVM68k_ubyte flagmask,tVM68k_instruction instruction,tVM68k_types datatype,tVM68k_ulong operand1,tVM68k_ulong operand2,tVM68k_uint64 result)257 int vm68k_calculateflags2(tVM68k_next* pNext,tVM68k_ubyte flagmask,tVM68k_instruction instruction,tVM68k_types datatype,tVM68k_ulong operand1,tVM68k_ulong operand2,tVM68k_uint64 result)
258 {
259 tVM68k_bool msb1,msb2,msbres;
260 int retval=VM68K_OK;
261 msb1=msb2=msbres=0;
262 switch(datatype)
263 {
264 case VM68K_BYTE: msb1=(operand1>> 7)&1;msb2=(operand2>> 7)&1;msbres=(result>> 7)&1;break;
265 case VM68K_WORD: msb1=(operand1>>15)&1;msb2=(operand2>>15)&1;msbres=(result>>15)&1;break;
266 case VM68K_LONG: msb1=(operand1>>31)&1;msb2=(operand2>>31)&1;msbres=(result>>31)&1;break;
267 default: retval=VM68K_NOK_INVALID_PTR;break;
268 }
269 pNext->zflag=(result==0);
270 pNext->nflag=(msbres);
271 switch (instruction)
272 {
273 case VM68K_INST_ADD:
274 case VM68K_INST_ADDA:
275 case VM68K_INST_ADDI:
276 case VM68K_INST_ADDQ:
277 case VM68K_INST_ADDX:
278 // sr[0] <= (`Sm & `Dm) | (~`Rm & `Dm) | (`Sm & ~`Rm);
279 // sr[1] <= (`Sm & `Dm & ~`Rm) | (~`Sm & ~`Dm & `Rm);
280 pNext->cflag=(msb1&msb2)|((!msbres)&msb2)|(msb1&(!msbres));
281 pNext->xflag=pNext->cflag;
282 pNext->vflag=(msb1&msb2&(!msbres))|((!msb1)&(!msb2)&msbres);
283 break;
284 case VM68K_INST_SUB:
285 case VM68K_INST_SUBA:
286 case VM68K_INST_SUBI:
287 case VM68K_INST_SUBQ:
288 case VM68K_INST_SUBX:
289 // sr[0] <= (`Sm & ~`Dm) | (`Rm & ~`Dm) | (`Sm & `Rm);
290 // sr[1] <= (~`Sm & `Dm & ~`Rm) | (`Sm & ~`Dm & `Rm);
291 pNext->cflag=(msb1&(!msb2))|(msbres&(!msb2))|(msb1&msbres);
292 pNext->xflag=pNext->cflag;
293 pNext->vflag=((!msb1)&msb2&(!msbres))|(msb1&(!msb2)&msbres);
294 break;
295
296 case VM68K_INST_CMP:
297 case VM68K_INST_CMPA:
298 case VM68K_INST_CMPI:
299 case VM68K_INST_CMPM:
300 // sr[0] <= (`Sm & ~`Dm) | (`Rm & ~`Dm) | (`Sm & `Rm);
301 // sr[1] <= (~`Sm & `Dm & ~`Rm) | (`Sm & ~`Dm & `Rm);
302 pNext->cflag=(msb1&(!msb2))|(msbres&(!msb2))|(msb1&msbres);
303 pNext->vflag=((!msb1)&msb2&(!msbres))|(msb1&(!msb2)&msbres);
304 break;
305
306 case VM68K_INST_AND:
307 case VM68K_INST_EOR:
308 case VM68K_INST_OR:
309 case VM68K_INST_ANDI:
310 case VM68K_INST_EORI:
311 case VM68K_INST_ORI:
312 default:
313 pNext->cflag=0;
314 pNext->vflag=0;
315 break;
316
317 }
318 return retval;
319 }
vm68k_storeresult(tVM68k * pVM68k,tVM68k_next * pNext,tVM68k_types size,tVM68k_slong ea,tVM68k_ulong result)320 int vm68k_storeresult(tVM68k* pVM68k,tVM68k_next* pNext,tVM68k_types size,tVM68k_slong ea,tVM68k_ulong result)
321 {
322 int retval;
323 tVM68k_ulong uppermask;
324 tVM68k_ulong lowermask;
325
326 retval=VM68K_NOK_UNKNOWN_INSTRUCTION;
327 switch (size)
328 {
329 case VM68K_BYTE:uppermask=0xffffff00;lowermask=~uppermask;break;
330 case VM68K_WORD:uppermask=0xffff0000;lowermask=~uppermask;break;
331 case VM68K_LONG:uppermask=0x00000000;lowermask=~uppermask;break;
332 default: return 0;
333 }
334 if (ea>=0) // memory address
335 {
336 retval=VM68K_OK;
337 ea%=pVM68k->memsize; // just to be safe...
338 pNext->mem_size=size;
339 pNext->mem_addr[pNext->mem_we]=ea;
340 pNext->mem_value[pNext->mem_we]=result&lowermask;
341 pNext->mem_we++;
342 } else { // register address
343 if (ea>=DATAREGADDR(7) && ea<=DATAREGADDR(0))
344 {
345 int reg;
346 reg=-ea+DATAREGADDR(0);
347 pNext->d[reg]&=uppermask;
348 pNext->d[reg]|=(result&lowermask);
349 retval=VM68K_OK;
350 }
351 else if (ea>=ADDRREGADDR(7) && ea<=ADDRREGADDR(0))
352 {
353 int reg;
354 reg=-ea+ADDRREGADDR(0);
355 pNext->a[reg]&=uppermask;
356 pNext->a[reg]|=(result&lowermask);
357 retval=VM68K_OK;
358 }
359 else retval=VM68K_NOK_UNKNOWN_INSTRUCTION;
360 }
361 return retval;
362 }
363