1 //
2 //		BUILD.C
3 //		Instruction Building Routines for 68000 Assembler
4 //
5 // Description: The functions in this file build instructions, that is,
6 //		they assemble the instruction word and its extension
7 //		words given the skeleton bit mask for the instruction
8 //		and opDescriptors for its operand(s). The instructions
9 //		that each routine builds are noted above it in a
10 //		comment. All the functions share the same calling
11 //		sequence (except zeroOp, which has no argument and
12 //		hence omits the operand descriptors), which is as
13 //		follows:
14 //
15 //		    general_name(mask, size, source, dest, errorPtr);
16 //		    int mask, size;
17 //		    opDescriptor *source, *dest;
18 //		    int *errorPtr;
19 //
20 //		except
21 //
22 //		    zeroOp(mask, size, errorPtr);
23 //		    int mask, size, *errorPtr;
24 //
25 //		The mask argument is the skeleton mask for the
26 //		instruction, i.e., the instruction word before the
27 //		addressing information has been filled in. The size
28 //		argument contains the size code that was specified with
29 //		the instruction (using the definitions in ASM.H) or 0
30 //		if no size code was specified. Arguments source and
31 //		dest are pointers to opDescriptors for the two
32 //		operands (only source is valid in some cases). The last
33 //		argument is used to return a status via the standard
34 //		mechanism.
35 //
36 //      Author: Paul McKee
37 //		ECE492    North Carolina State University
38 //
39 //        Date:	12/13/86
40 //
41 //   Copyright 1990-1991 North Carolina State University. All Rights Reserved.
42 //
43 
44 #include <stdio.h>
45 #include "asm.h"
46 
47 extern int loc;
48 extern char pass2;
49 
50 // Builds the MOVEQ instruction.
51 void
moveq(int mask,int size,opDescriptor * source,opDescriptor * dest,int * errorPtr)52 moveq(int mask, int size, opDescriptor *source, opDescriptor *dest, int *errorPtr)
53 {
54 	if (pass2) {
55 		output(mask | (dest->reg << 9) | (source->data & 0xFF), WORD);
56 		if (source->data < -128 || source->data > 127)
57 			NEWERROR(*errorPtr, INV_QUICK_CONST);
58 	}
59 	loc += 2;
60 }
61 
62 // Builds the MOVE and MOVEA instructions.
63 void
move(int mask,int size,opDescriptor * source,opDescriptor * dest,int * errorPtr)64 move(int mask, int size, opDescriptor * source, opDescriptor * dest, int *errorPtr)
65 {
66 	unsigned short moveMask;
67 	char destCode;
68 
69 	// Check whether the instruction can be assembled as MOVEQ
70 	if (source->mode == Immediate &&
71 	    source->backRef &&
72 	    size == LONG &&
73 	    dest->mode == DnDirect &&
74 	    source->data >= -128 &&
75 	    source->data <= 127) {
76 		moveq(0x7000, size, source, dest, errorPtr);
77 		return;
78 	}
79 
80 	// Otherwise assemble it as plain MOVE
81 	moveMask = mask | effAddr(source);
82 	destCode = effAddr(dest);
83 	moveMask |= (destCode & 0x38) << 3 | (destCode & 7) << 9;
84 	if (pass2)
85 		output(moveMask, WORD);
86 	loc += 2;
87 	extWords(source, size, errorPtr);
88 	extWords(dest, size, errorPtr);
89 }
90 
91 // Builds the following instructions:
92 //	 ILLEGAL
93 //	 NOP
94 //	 RESET
95 //	 RTE
96 //	 RTR
97 //	 RTS
98 //	 TRAPV
99 void
zeroOp(int mask,int size,int * errorPtr)100 zeroOp(int mask, int size, int *errorPtr)
101 {
102 	if (pass2)
103 		output(mask, WORD);
104 	loc += 2;
105 }
106 
107 // Builds the following instructions:
108 //	 ASd  <ea>
109 //	 CLR
110 //	 JMP
111 //	 JSR
112 //	 LSd  <ea>
113 //	 MOVE <ea>,CCR
114 //	 MOVE <ea>,SR
115 //	 NBCD
116 //	 NEG
117 //	 NEGX
118 //	 NOT
119 //	 PEA
120 //	 ROd  <ea>
121 //	 ROXd <ea>
122 //	 TAS
123 //	 TST
124 void
oneOp(int mask,int size,opDescriptor * source,opDescriptor * dest,int * errorPtr)125 oneOp(int mask, int size, opDescriptor *source, opDescriptor *dest, int *errorPtr)
126 {
127 	if (pass2)
128 		output(mask | effAddr(source), WORD);
129 	loc += 2;
130 	extWords(source, size, errorPtr);
131 }
132 
133 // Builds the following instructions:
134 //	 ADD <ea>,Dn
135 //	 ADDA
136 //	 AND <ea>,Dn
137 //	 CHK
138 //	 CMP
139 //	 CMPA
140 //	 DIVS
141 //	 DIVU
142 //	 LEA
143 //	 MULS
144 //	 MULU
145 //	 OR <ea>,Dn
146 //	 SUB <ea>,Dn
147 //	 SUBA
148 void
arithReg(int mask,int size,opDescriptor * source,opDescriptor * dest,int * errorPtr)149 arithReg(int mask, int size, opDescriptor *source, opDescriptor *dest, int *errorPtr)
150 {
151 	if (pass2)
152 		output(mask | effAddr(source) | (dest->reg << 9), WORD);
153 	loc += 2;
154 	extWords(source, size, errorPtr);
155 }
156 
157 // Builds the following instructions:
158 //	 ADD Dn,<ea>
159 //	 AND Dn,<ea>
160 //	 BCHG Dn,<ea>
161 //	 BCLR Dn,<ea>
162 //	 BSET Dn,<ea>
163 //	 BTST Dn,<ea>
164 //	 EOR
165 //	 OR Dn,<ea>
166 //	 SUB Dn,<ea>
167 void
arithAddr(int mask,int size,opDescriptor * source,opDescriptor * dest,int * errorPtr)168 arithAddr(int mask, int size, opDescriptor *source, opDescriptor *dest, int *errorPtr)
169 {
170 	if (pass2)
171 		output(mask | effAddr(dest) | (source->reg << 9), WORD);
172 	loc += 2;
173 	extWords(dest, size, errorPtr);
174 }
175 
176 // Builds the following instructions:
177 //	 ADDQ
178 //	 SUBQ
179 void
quickMath(int mask,int size,opDescriptor * source,opDescriptor * dest,int * errorPtr)180 quickMath(int mask, int size, opDescriptor * source, opDescriptor *dest, int *errorPtr)
181 {
182 	if (pass2) {
183 		output(mask | effAddr(dest) | ((source->data & 7) << 9), WORD);
184 		if (source->data < 1 || source->data > 8)
185 			NEWERROR(*errorPtr, INV_QUICK_CONST);
186 	}
187 	loc += 2;
188 	extWords(dest, size, errorPtr);
189 }
190 
191 // Builds the following instructions:
192 //	 ADDI
193 //	 ANDI
194 //	 CMPI
195 //	 EORI
196 //	 ORI
197 //	 SUBI
198 void
immedInst(int mask,int size,opDescriptor * source,opDescriptor * dest,int * errorPtr)199 immedInst(int mask, int size, opDescriptor *source, opDescriptor *dest, int *errorPtr)
200 {
201 	unsigned short type;
202 
203 	// Check whether the instruction is an immediate ADD or SUB
204 	// that can be assembled as ADDQ or SUBQ
205 	// Check the mask to determine the operation
206 	type = mask & 0xFF00;
207 	if ((type == 0x0600 || type == 0x0400) &&
208 	    source->backRef &&
209 	    source->data >= 1 &&
210 	    source->data <= 8)
211 	{
212 		if (type == 0x0600) {
213 			// Assemble as ADDQ
214 			quickMath(0x5000 | (mask & 0x00C0), size,
215 				  source, dest, errorPtr);
216 		} else {
217 			// Assemble as SUBQ
218 			quickMath(0x5100 | (mask & 0x00C0), size,
219 				  source, dest, errorPtr);
220 		}
221 		return;
222 	}
223 
224 	// Otherwise assemble as an ordinary instruction
225 	if (pass2)
226 		output(mask | effAddr(dest), WORD);
227 	loc += 2;
228 	extWords(source, size, errorPtr);
229 	extWords(dest, size, errorPtr);
230 }
231 
232 // Builds the MOVEP instruction.
233 void
movep(int mask,int size,opDescriptor * source,opDescriptor * dest,int * errorPtr)234 movep(int mask, int size, opDescriptor *source, opDescriptor *dest, int *errorPtr)
235 {
236 	if (!pass2) {
237 		loc += 4;
238 		return;
239 	}
240 	if (source->mode == DnDirect) {
241 		// Convert plain address register indirect to address
242 		// register indirect with displacement of 0
243 		if (dest->mode == AnInd) {
244 			dest->mode = AnIndDisp;
245 			dest->data = 0;
246 		}
247 		output(mask | (source->reg << 9) | (dest->reg), WORD);
248 		loc += 2;
249 		extWords(dest, size, errorPtr);
250 	} else {
251 		// Convert plain address register indirect to address
252 		// register indirect with displacement of 0
253 		if (source->mode == AnInd) {
254 			source->mode = AnIndDisp;
255 			source->data = 0;
256 		}
257 		output(mask | (dest->reg << 9) | (source->reg), WORD);
258 		loc += 2;
259 		extWords(source, size, errorPtr);
260 	}
261 }
262 
263 // Builds the MOVES instruction.
264 void
moves(int mask,int size,opDescriptor * source,opDescriptor * dest,int * errorPtr)265 moves(int mask, int size, opDescriptor *source, opDescriptor *dest, int *errorPtr)
266 {
267 	if (!pass2) {
268 		loc += 4;
269 		extWords((source->mode & (DnDirect | AnDirect)) ? dest : source,
270 			 size, errorPtr);
271 		return;
272 	}
273 	if (source->mode & (DnDirect | AnDirect)) {
274 		output(mask | effAddr(dest), WORD);
275 		loc += 2;
276 		if (source->mode == DnDirect)
277 			output(0x0800 | (source->reg << 12), WORD);
278 		else
279 			output(0x8800 | (source->reg << 12), WORD);
280 		loc += 2;
281 	} else {
282 		output(mask | effAddr(source), WORD);
283 		loc += 2;
284 		if (dest->mode == DnDirect)
285 			output(dest->reg << 12, WORD);
286 		else
287 			output(0x8000 | (dest->reg << 12), WORD);
288 		loc += 2;
289 	}
290 	extWords((source->mode & (DnDirect | AnDirect)) ? dest : source,
291 		 size, errorPtr);
292 }
293 
294 // Builds the following instructions:
295 //	 MOVE from CCR
296 //	 MOVE from SR
297 void
moveReg(int mask,int size,opDescriptor * source,opDescriptor * dest,int * errorPtr)298 moveReg(int mask, int size, opDescriptor * source, opDescriptor * dest,
299 	int *errorPtr)
300 {
301 	if (pass2) {
302 		output(mask | effAddr(dest), WORD);
303 	}
304 	loc += 2;
305 	extWords(dest, size, errorPtr);
306 }
307 
308 
309 // Builds the following instructions:
310 //	 BCHG #n,<ea>
311 //	 BCLR #n,<ea>
312 //	 BSET #n,<ea>
313 //	 BTST #n,<ea>
314 //
315 void
staticBit(int mask,int size,opDescriptor * source,opDescriptor * dest,int * errorPtr)316 staticBit(int mask, int size, opDescriptor *source, opDescriptor *dest, int *errorPtr)
317 {
318 	if (pass2) {
319 		output(mask | effAddr(dest), WORD);
320 		loc += 2;
321 		output(source->data & 0xFF, WORD);
322 		loc += 2;
323 	} else
324 		loc += 4;
325 	extWords(dest, size, errorPtr);
326 }
327 
328 
329 // Builds the MOVEC instruction.
330 void
movec(int mask,int size,opDescriptor * source,opDescriptor * dest,int * errorPtr)331 movec(int mask, int size, opDescriptor *source, opDescriptor *dest, int *errorPtr)
332 {
333 	unsigned short mask2;
334 	opDescriptor *regOp;
335 	int controlMode;
336 
337 	if (!pass2) {
338 		loc += 4;
339 		return;
340 	}
341 	output(mask, WORD);
342 	loc += 2;
343 	if (mask & 1) {
344 		regOp = source;
345 		controlMode = dest->mode;
346 	} else {
347 		regOp = dest;
348 		controlMode = source->mode;
349 	}
350 	mask2 = regOp->reg << 12;
351 	if (regOp->mode == AnDirect)
352 		mask2 |= 0x8000;
353 	switch (controlMode) {
354 	case SFCDirect:
355 		mask2 |= 0x000;
356 		break;
357 	case DFCDirect:
358 		mask2 |= 0x001;
359 		break;
360 	case USPDirect:
361 		mask2 |= 0x800;
362 		break;
363 	case VBRDirect:
364 		mask2 |= 0x801;
365 		break;
366 	}
367 	output(mask2, WORD);
368 	loc += 2;
369 }
370 
371 
372 // Builds the TRAP instruction.
373 void
trap(int mask,int size,opDescriptor * source,opDescriptor * dest,int * errorPtr)374 trap(int mask, int size, opDescriptor *source, opDescriptor *dest, int *errorPtr)
375 {
376 	if (pass2) {
377 		output(mask | (source->data & 0xF), WORD);
378 		if (source->data < 0 || source->data > 15)
379 			NEWERROR(*errorPtr, INV_VECTOR_NUM);
380 	}
381 	loc += 2;
382 }
383 
384 
385 // Builds the following instructions:
386 //	 BCC (BHS)   BGT	 BLT	     BRA
387 //	 BCS (BLO)   BHI	 BMI	     BSR
388 //	 BEQ	     BLE	 BNE         BVC
389 //	 BGE	     BLS	 BPL         BVS
390 void
branch(int mask,int size,opDescriptor * source,opDescriptor * dest,int * errorPtr)391 branch(int mask, int size, opDescriptor *source, opDescriptor *dest, int *errorPtr)
392 {
393 	char shortDisp;
394 	int disp;
395 
396 	disp = source->data - loc - 2;
397 	shortDisp = FALSE;
398 	if (size == SHORT ||
399 	    (size != LONG &&
400 	     source->backRef &&
401 	     disp >= -128 &&
402 	     disp <= 127 &&
403 	     disp != 0)) {
404 		shortDisp = TRUE;
405 	}
406 	if (!pass2) {
407 		loc += (shortDisp) ? 2 : 4;
408 		return;
409 	}
410 	if (shortDisp) {
411 		output(mask | (disp & 0xFF), WORD);
412 		loc += 2;
413 		if (disp < -128 || disp > 127 || !disp)
414 			NEWERROR(*errorPtr, INV_BRANCH_DISP);
415 	} else {
416 		output(mask, WORD);
417 		loc += 2;
418 		output(disp, WORD);
419 		loc += 2;
420 		if (disp < -32768 || disp > 32767)
421 			NEWERROR(*errorPtr, INV_BRANCH_DISP);
422 	}
423 }
424 
425 
426 // Builds the following instructions:
427 //	 ANDI to CCR
428 //	 EORI to CCR
429 //	 ORI to CCR
430 void
immedToCCR(int mask,int size,opDescriptor * source,opDescriptor * dest,int * errorPtr)431 immedToCCR(int mask, int size, opDescriptor *source, opDescriptor *dest, int *errorPtr)
432 {
433 	if (!pass2) {
434 		loc += 4;
435 		return;
436 	}
437 	output(mask, WORD);
438 	loc += 2;
439 	output(source->data & 0xFF, WORD);
440 	loc += 2;
441 	if ((source->data & 0xFF) != source->data)
442 		NEWERROR(*errorPtr, INV_8_BIT_DATA);
443 }
444 
445 
446 // Builds the following instructions:
447 //	 ANDI to SR
448 //	 EORI to SR
449 //	 ORI to SR
450 //	 RTD
451 //	 STOP
452 void
immedWord(int mask,int size,opDescriptor * source,opDescriptor * dest,int * errorPtr)453 immedWord(int mask, int size, opDescriptor *source, opDescriptor *dest, int *errorPtr)
454 {
455 	if (!pass2) {
456 		loc += 4;
457 		return;
458 	}
459 	output(mask, WORD);
460 	loc += 2;
461 	output(source->data & 0xFFFF, WORD);
462 	loc += 2;
463 	if (source->data < -32768 || source->data > 65535)
464 		NEWERROR(*errorPtr, INV_16_BIT_DATA);
465 }
466 
467 // Builds the following instructions:
468 //	 DBCC (DBHS)  DBGE	 DBLS	     DBPL
469 //	 DBCS (DBLO)  DBGT	 DBLT	     DBT
470 //	 DBEQ	      DBHI	 DBMI        DBVC
471 //	 DBF (DBRA)   DBLE	 DBNE	     DBVS
472 void
dbcc(int mask,int size,opDescriptor * source,opDescriptor * dest,int * errorPtr)473 dbcc(int mask, int size, opDescriptor *source, opDescriptor *dest, int *errorPtr)
474 {
475 	int disp;
476 
477 	disp = dest->data - loc - 2;
478 	if (!pass2) {
479 		loc += 4;
480 		return;
481 	}
482 	output(mask | source->reg, WORD);
483 	loc += 2;
484 	output(disp, WORD);
485 	loc += 2;
486 	if (disp < -32768 || disp > 32767)
487 		NEWERROR(*errorPtr, INV_BRANCH_DISP);
488 }
489 
490 // Builds the following instructions:
491 //	 SCC (SHS)   SGE 	 SLS	    SPL
492 //	 SCS (SLO)   SGT 	 SLT	    ST
493 //	 SEQ	     SHI 	 SMI        SVC
494 //	 SF	     SLE 	 SNE	    SVS
495 void
scc(int mask,int size,opDescriptor * source,opDescriptor * dest,int * errorPtr)496 scc(int mask, int size, opDescriptor *source, opDescriptor *dest, int *errorPtr)
497 {
498 	if (pass2)
499 		output(mask | effAddr(source), WORD);
500 	loc += 2;
501 	extWords(source, size, errorPtr);
502 }
503 
504 
505 // Builds the following instructions:
506 //	 ASd	Dx,Dy
507 //	 LSd	Dx,Dy
508 //	 ROd	Dx,Dy
509 //	 ROXd	Dx,Dy
510 //	 ASd	#<data>,Dy
511 //	 LSd	#<data>,Dy
512 //	 ROd	#<data>,Dy
513 //	 ROXd	#<data>,Dy
514 void
shiftReg(int mask,int size,opDescriptor * source,opDescriptor * dest,int * errorPtr)515 shiftReg(int mask, int size, opDescriptor * source, opDescriptor * dest, int *errorPtr)
516 {
517 	if (pass2) {
518 		mask |= dest->reg;
519 		if (source->mode == Immediate) {
520 			mask |= (source->data & 7) << 9;
521 			if (source->data < 1 || source->data > 8)
522 				NEWERROR(*errorPtr, INV_SHIFT_COUNT);
523 		} else
524 			mask |= source->reg << 9;
525 		output(mask, WORD);
526 	}
527 	loc += 2;
528 }
529 
530 // Builds the EXG instruction.
531 void
exg(int mask,int size,opDescriptor * source,opDescriptor * dest,int * errorPtr)532 exg(int mask, int size, opDescriptor *source, opDescriptor *dest, int *errorPtr)
533 {
534 	if (pass2) {
535 		// Are a data register and an address register being exchanged?
536 		if (source->mode != dest->mode) {
537 			// If so, the address register goes in bottom three bits
538 			if (source->mode == AnDirect)
539 				mask |= source->reg | (dest->reg << 9);
540 			else
541 				mask |= dest->reg | (source->reg << 9);
542 		} else {
543 			// Otherwise it doesn't matter which way they go
544 			mask |= dest->reg | (source->reg << 9);
545 		}
546 		output(mask, WORD);
547 	}
548 	loc += 2;
549 }
550 
551 // Builds the following instructions:
552 //	 ABCD
553 //	 ADDX
554 //	 CMPM
555 //	 SBCD
556 //	 SUBX
557 void
twoReg(int mask,int size,opDescriptor * source,opDescriptor * dest,int * errorPtr)558 twoReg(int mask, int size, opDescriptor *source, opDescriptor *dest, int *errorPtr)
559 {
560 	if (pass2) {
561 		output(mask | (dest->reg << 9) | source->reg, WORD);
562 	}
563 	loc += 2;
564 }
565 
566 
567 // Builds the following instructions:
568 //	 EXT
569 //	 SWAP
570 //	 UNLK
571 void
oneReg(int mask,int size,opDescriptor * source,opDescriptor * dest,int * errorPtr)572 oneReg(int mask, int size, opDescriptor *source, opDescriptor *dest, int *errorPtr)
573 {
574 	if (pass2) {
575 		output(mask | source->reg, WORD);
576 	}
577 	loc += 2;
578 }
579 
580 
581 // Builds the following instructions:
582 //	 MOVE	USP,An
583 //	 MOVE	An,USP
584 void
moveUSP(int mask,int size,opDescriptor * source,opDescriptor * dest,int * errorPtr)585 moveUSP(int mask, int size, opDescriptor *source, opDescriptor *dest, int *errorPtr)
586 {
587 	if (pass2) {
588 		if (source->mode == AnDirect)
589 			output(mask | source->reg, WORD);
590 		else
591 			output(mask | dest->reg, WORD);
592 	}
593 	loc += 2;
594 }
595 
596 // Builds the LINK instruction
597 void
link(int mask,int size,opDescriptor * source,opDescriptor * dest,int * errorPtr)598 link(int mask, int size, opDescriptor *source, opDescriptor *dest, int *errorPtr)
599 {
600 	if (!pass2) {
601 		loc += 4;
602 		return;
603 	}
604 	output(mask | source->reg, WORD);
605 	loc += 2;
606 	output(dest->data, WORD);
607 	loc += 2;
608 	if (dest->data < -32768 || dest->data > 32767)
609 		NEWERROR(*errorPtr, INV_16_BIT_DATA);
610 }
611