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