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