1 /* codemsp.c */
2 /*****************************************************************************/
3 /* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only                     */
4 /*                                                                           */
5 /* AS-Portierung                                                             */
6 /*                                                                           */
7 /* Codegenerator MSP430                                                      */
8 /*                                                                           */
9 /*****************************************************************************/
10 
11 #include "stdinc.h"
12 
13 #include <ctype.h>
14 #include <string.h>
15 
16 #include "nls.h"
17 #include "endian.h"
18 #include "strutil.h"
19 #include "bpemu.h"
20 #include "chunks.h"
21 #include "errmsg.h"
22 #include "asmdef.h"
23 #include "asmsub.h"
24 #include "asmcode.h"
25 #include "asmpars.h"
26 #include "asmallg.h"
27 #include "asmitree.h"
28 #include "codepseudo.h"
29 #include "codevars.h"
30 
31 #define OneOpCount 6
32 
33 typedef struct
34 {
35   Boolean MayByte;
36   Word Code;
37 } OneOpOrder;
38 
39 typedef enum
40 {
41   eModeReg = 0,
42   eModeRegDisp = 1,
43   eModeIReg = 2,
44   eModeIRegAutoInc = 3,
45   eModeNone = 0xff
46 } tMode;
47 
48 #define MModeReg (1 << eModeReg)
49 #define MModeRegDisp (1 << eModeRegDisp)
50 #define MModeIReg (1 << eModeIReg)
51 #define MModeIRegAutoInc (1 << eModeIRegAutoInc)
52 #define MModeAs 15
53 #define MModeAd 3
54 
55 typedef enum
56 {
57   eExtModeNo = 0,
58   eExtModeYes = 1
59 } tExtMode;
60 
61 typedef enum
62 {
63   eOpSizeB = 0,
64   eOpSizeW = 1,
65   eOpSizeA = 2,
66   eOpSizeCnt,
67   eOpSizeDefault = eOpSizeW
68 } tOpSize;
69 
70 #define RegPC 0
71 #define RegSP 1
72 #define RegSR 2
73 #define RegCG1 2
74 #define RegCG2 3
75 
76 #define REG_PC 0
77 #define REG_SP 1
78 #define REG_SR 2
79 #define REG_MARK 16 /* internal mark to differentiate PC<->R0, SP<->R1, and SR<->R2 */
80 
81 typedef struct
82 {
83   Word Mode, Part, Cnt;
84   LongWord Val;
85   Boolean WasImm, WasAbs;
86 } tAdrParts;
87 
88 /*  float exp (8bit bias 128) sign mant (impl. norm.)
89    double exp (8bit bias 128) sign mant (impl. norm.) */
90 
91 static CPUVar CPUMSP430, CPUMSP430X;
92 
93 static OneOpOrder *OneOpOrders;
94 
95 static tOpSize OpSize;
96 static Word PCDist, MultPrefix;
97 static IntType AdrIntType, DispIntType;
98 static const IntType OpSizeIntTypes[eOpSizeCnt] = { Int8, Int16, Int20 };
99 
100 /*-------------------------------------------------------------------------*/
101 
ResetAdr(tAdrParts * pAdrParts)102 static void ResetAdr(tAdrParts *pAdrParts)
103 {
104   pAdrParts->Mode = eModeNone;
105   pAdrParts->Part = 0;
106   pAdrParts->Cnt = 0;
107   pAdrParts->WasImm =
108   pAdrParts->WasAbs = False;
109 }
110 
ChkAdr(Byte Mask,tAdrParts * pAdrParts)111 static Boolean ChkAdr(Byte Mask, tAdrParts *pAdrParts)
112 {
113   if ((pAdrParts->Mode != 0xff) && ((Mask & (1 << pAdrParts->Mode)) == 0))
114   {
115     ResetAdr(pAdrParts);
116     WrError(ErrNum_InvAddrMode);
117     return False;
118   }
119   return True;
120 }
121 
122 /*!------------------------------------------------------------------------
123  * \fn     DecodeRegCore(const char *pArg, Word *pResult)
124  * \brief  check whether argument is a CPU register
125  * \param  pArg argument to check
126  * \param  pResult numeric register value if yes
127  * \return True if yes
128  * ------------------------------------------------------------------------ */
129 
DecodeRegCore(const char * pArg,Word * pResult)130 static Boolean DecodeRegCore(const char *pArg, Word *pResult)
131 {
132   if (!as_strcasecmp(pArg, "PC"))
133   {
134     *pResult = REG_MARK | REG_PC; return True;
135   }
136   else if (!as_strcasecmp(pArg,"SP"))
137   {
138     *pResult = REG_MARK | REG_SP; return True;
139   }
140   else if (!as_strcasecmp(pArg, "SR"))
141   {
142     *pResult = REG_MARK | REG_SR; return True;
143   }
144   if ((as_toupper(*pArg) == 'R') && (strlen(pArg) >= 2) && (strlen(pArg) <= 3))
145   {
146     Boolean OK;
147 
148     *pResult = ConstLongInt(pArg + 1, &OK, 10);
149     return OK && (*pResult < 16);
150   }
151 
152   return False;
153 }
154 
155 /*!------------------------------------------------------------------------
156  * \fn     DissectReg_MSP(char *pDest, size_t DestSize, tRegInt Value, tSymbolSize InpSize)
157  * \brief  dissect register symbols - MSP variant
158  * \param  pDest destination buffer
159  * \param  DestSize destination buffer size
160  * \param  Value numeric register value
161  * \param  InpSize register size
162  * ------------------------------------------------------------------------ */
163 
DissectReg_MSP(char * pDest,size_t DestSize,tRegInt Value,tSymbolSize InpSize)164 static void DissectReg_MSP(char *pDest, size_t DestSize, tRegInt Value, tSymbolSize InpSize)
165 {
166   switch (InpSize)
167   {
168     case eSymbolSize8Bit:
169       switch (Value)
170       {
171         case REG_MARK | REG_PC:
172           as_snprintf(pDest, DestSize, "PC");
173           break;
174         case REG_MARK | REG_SP:
175           as_snprintf(pDest, DestSize, "SP");
176           break;
177         case REG_MARK | REG_SR:
178           as_snprintf(pDest, DestSize, "SR");
179           break;
180         default:
181           as_snprintf(pDest, DestSize, "R%u", (unsigned)Value);
182       }
183       break;
184     default:
185       as_snprintf(pDest, DestSize, "%d-%u", (int)InpSize, (unsigned)Value);
186   }
187 }
188 
189 /*!------------------------------------------------------------------------
190  * \fn     DecodeReg(const tStrComp *pArg, Word *pResult, Boolean MustBeReg)
191  * \brief  check whether argument is a CPU register or register alias
192  * \param  pArg argument to check
193  * \param  pResult numeric register value if yes
194  * \param  MustBeReg excpecting register as arg
195  * \return True if yes
196  * ------------------------------------------------------------------------ */
197 
DecodeReg(const tStrComp * pArg,Word * pResult,Boolean MustBeReg)198 static Boolean DecodeReg(const tStrComp *pArg, Word *pResult, Boolean MustBeReg)
199 {
200   tRegDescr RegDescr;
201   tEvalResult EvalResult;
202   tRegEvalResult RegEvalResult;
203 
204   if (DecodeRegCore(pArg->Str, pResult))
205   {
206     *pResult &= ~REG_MARK;
207     return True;
208   }
209 
210   RegEvalResult = EvalStrRegExpressionAsOperand(pArg, &RegDescr, &EvalResult, eSymbolSize8Bit, MustBeReg);
211   *pResult = RegDescr.Reg & ~REG_MARK;
212   return (RegEvalResult == eIsReg);
213 }
214 
FillAdrPartsImm(tAdrParts * pAdrParts,LongWord Value,Boolean ForceLong)215 static void FillAdrPartsImm(tAdrParts *pAdrParts, LongWord Value, Boolean ForceLong)
216 {
217   ResetAdr(pAdrParts);
218   pAdrParts->WasImm = True;
219   pAdrParts->Val = Value;
220 
221   /* assume no usage of constant generators */
222 
223   pAdrParts->Part = RegPC;
224 
225   /* constant generators allowed at all? */
226 
227   if (!ForceLong)
228   {
229     /* special treatment for -1 since it depends on the operand size: */
230 
231     if ((Value == 0xffffffff)
232      || ((OpSize == eOpSizeB) && (Value == 0xff))
233      || ((OpSize == eOpSizeW) && (Value == 0xffff))
234      || ((OpSize == eOpSizeA) && (Value == 0xfffff)))
235     {
236       pAdrParts->Cnt = 0;
237       pAdrParts->Part = RegCG2;
238       pAdrParts->Mode = eModeIRegAutoInc;
239     }
240     else switch (Value)
241     {
242       case 0:
243         pAdrParts->Part = RegCG2;
244         pAdrParts->Mode = eModeReg;
245         break;
246       case 1:
247         pAdrParts->Part = RegCG2;
248         pAdrParts->Mode = eModeRegDisp;
249         break;
250       case 2:
251         pAdrParts->Part = RegCG2;
252         pAdrParts->Mode = eModeIReg;
253         break;
254       case 4:
255         pAdrParts->Part = RegCG1;
256         pAdrParts->Mode = eModeIReg;
257         break;
258       case 8:
259         pAdrParts->Part = RegCG1;
260         pAdrParts->Mode = eModeIRegAutoInc;
261         break;
262       default:
263         break;
264     }
265   }
266 
267   /* constant generators not used, in one or the other way -> use
268      @PC++ to dispose constant */
269 
270   if (pAdrParts->Part == RegPC)
271   {
272     pAdrParts->Cnt = 1;
273     pAdrParts->Mode = eModeIRegAutoInc;
274   }
275 }
276 
DecodeAdr(const tStrComp * pArg,tExtMode ExtMode,Byte Mask,Boolean MayImm,tAdrParts * pAdrParts)277 static Boolean DecodeAdr(const tStrComp *pArg, tExtMode ExtMode, Byte Mask, Boolean MayImm, tAdrParts *pAdrParts)
278 {
279   LongWord AdrWord, CurrPC;
280   Word Reg;
281   Boolean OK;
282   char *p;
283   IntType ThisAdrIntType = (ExtMode == eExtModeYes) ? AdrIntType : UInt16;
284   IntType ThisDispIntType = (ExtMode == eExtModeYes) ? DispIntType : Int16;
285   int ArgLen;
286 
287   ResetAdr(pAdrParts);
288 
289   /* immediate */
290 
291   if (*pArg->Str == '#')
292   {
293     if (!MayImm) WrError(ErrNum_InvAddrMode);
294     else
295     {
296       int ForceLong = (pArg->Str[1] == '>') ? 1 : 0;
297 
298       AdrWord = EvalStrIntExpressionOffs(pArg, 1 + ForceLong, OpSizeIntTypes[OpSize], &OK);
299       if (OK)
300       {
301         FillAdrPartsImm(pAdrParts, AdrWord, ForceLong);
302       }
303     }
304     return ChkAdr(Mask, pAdrParts);
305   }
306 
307   /* absolut */
308 
309   if (*pArg->Str == '&')
310   {
311     pAdrParts->Val = EvalStrIntExpressionOffs(pArg, 1, ThisAdrIntType, &OK);
312     if (OK)
313     {
314       pAdrParts->WasAbs = True;
315       pAdrParts->Mode = eModeRegDisp;
316       pAdrParts->Part = RegCG1; /* == 0 with As/Ad=1 */
317       pAdrParts->Cnt = 1;
318     }
319     return ChkAdr(Mask, pAdrParts);
320   }
321 
322   /* Register */
323 
324   switch (DecodeReg(pArg, &Reg, False))
325   {
326     case eIsReg:
327       if (Reg == RegCG2) WrStrErrorPos(ErrNum_InvReg, pArg);
328       else
329       {
330         pAdrParts->Mode = eModeReg;
331         pAdrParts->Part = Reg;
332       }
333       return ChkAdr(Mask, pAdrParts);
334     case eIsNoReg:
335       break;
336     case eRegAbort:
337       return False;
338   }
339 
340   /* Displacement */
341 
342   ArgLen = strlen(pArg->Str);
343   if ((*pArg->Str) && (pArg->Str[ArgLen - 1] == ')'))
344   {
345     tStrComp Arg = *pArg;
346 
347     StrCompShorten(&Arg, 1);
348     p = RQuotPos(Arg.Str, '(');
349     if (p)
350     {
351       tStrComp RegComp, OffsComp;
352       char Save;
353 
354       Save = StrCompSplitRef(&OffsComp, &RegComp, &Arg, p);
355       if (DecodeReg(&RegComp, &Reg, True) == eIsReg)
356       {
357         pAdrParts->Val = EvalStrIntExpression(&OffsComp, ThisDispIntType, &OK);
358         if (OK)
359         {
360           if ((Reg == 2) || (Reg == 3)) WrStrErrorPos(ErrNum_InvReg, &RegComp);
361           else if ((pAdrParts->Val == 0) && ((Mask & 4) != 0))
362           {
363             pAdrParts->Part = Reg;
364             pAdrParts->Mode = eModeIReg;
365           }
366           else
367           {
368             pAdrParts->Part = Reg;
369             pAdrParts->Cnt = 1;
370             pAdrParts->Mode = eModeRegDisp;
371           }
372         }
373       }
374       *p = Save;
375     }
376     pArg->Str[ArgLen - 1] = ')';
377 
378     if (pAdrParts->Mode != eModeNone)
379       return ChkAdr(Mask, pAdrParts);
380   }
381 
382   /* indirekt mit/ohne Autoinkrement */
383 
384   if ((*pArg->Str == '@') || (*pArg->Str == '*'))
385   {
386     Boolean AutoInc = False;
387     tStrComp Arg;
388 
389     StrCompRefRight(&Arg, pArg, 1);
390     ArgLen = strlen(Arg.Str);
391     if (Arg.Str[ArgLen - 1] == '+')
392     {
393       AutoInc = True;
394       StrCompShorten(&Arg, 1);
395     }
396     if (DecodeReg(&Arg, &Reg, True) != eIsReg);
397     else if ((Reg == 2) || (Reg == 3)) WrStrErrorPos(ErrNum_InvReg, &Arg);
398     else if (!AutoInc && ((Mask & MModeIReg) == 0))
399     {
400       pAdrParts->Part = Reg;
401       pAdrParts->Val = 0;
402       pAdrParts->Cnt = 1;
403       pAdrParts->Mode = eModeRegDisp;
404     }
405     else
406     {
407       pAdrParts->Part = Reg;
408       pAdrParts->Mode = AutoInc ? eModeIRegAutoInc : eModeIReg;
409     }
410     return ChkAdr(Mask, pAdrParts);
411   }
412 
413   /* bleibt PC-relativ aka 'symbolic mode': */
414 
415   if (!PCDist)
416   {
417     fprintf(stderr, "internal error: PCDist not set for '%s'\n", OpPart.Str);
418     exit(10);
419   }
420   CurrPC = EProgCounter() + PCDist;
421 
422   /* extended instruction (on 430X): use the full 20 bit displacement: */
423 
424   if (ExtMode == eExtModeYes)
425   {
426     AdrWord = (EvalStrIntExpression(pArg, UInt20, &OK) - CurrPC) & 0xfffff;
427   }
428 
429   /* non-extended instruction on 430X: if the current PC is within the
430      first 64K, bits 16..19 will be cleared after addition, i.e. the
431      target address must also be within the first 64K: */
432 
433   else if (MomCPU >= CPUMSP430X)
434   {
435     if (CurrPC <= 0xffff)
436     {
437       AdrWord = (EvalStrIntExpression(pArg, UInt16, &OK) - CurrPC) & 0xffff;
438     }
439     else
440     {
441       AdrWord = (EvalStrIntExpression(pArg, UInt20, &OK) - CurrPC) & 0xfffff;
442       if ((AdrWord > 0x7fff) && (AdrWord < 0xf8000))
443       {
444         WrError(ErrNum_OverRange);
445         OK = False;
446       }
447     }
448   }
449 
450   /* non-extended instruction on 430: all within 64K with wraparound */
451 
452   else
453   {
454     AdrWord = (EvalStrIntExpression(pArg, UInt16, &OK) - CurrPC) & 0xffff;
455   }
456 
457   if (OK)
458   {
459     pAdrParts->Part = RegPC;
460     pAdrParts->Mode = eModeRegDisp;
461     pAdrParts->Cnt = 1;
462     pAdrParts->Val = AdrWord;
463   }
464 
465   return ChkAdr(Mask, pAdrParts);
466 }
467 
GetBW(void)468 static Word GetBW(void)
469 {
470   return (OpSize == eOpSizeB) || (OpSize == eOpSizeA) ? 0x0040 : 0x0000;
471 }
472 
GetAL(void)473 static Word GetAL(void)
474 {
475   return (OpSize == eOpSizeW) || (OpSize == eOpSizeB) ? 0x0040 : 0x0000;
476 }
477 
GetMult(const tStrComp * pArg,Boolean * pOK)478 static Word GetMult(const tStrComp *pArg, Boolean *pOK)
479 {
480   Word Result = 0x0000;
481 
482   switch (DecodeReg(pArg, &Result, False))
483   {
484     case eIsReg:
485       *pOK = True;
486       return Result | 0x0080;
487       break;
488     case eIsNoReg:
489       break;
490     case eRegAbort:
491       *pOK = False;
492       return 0;
493   }
494 
495   if (*pArg->Str == '#')
496   {
497     tSymbolFlags Flags;
498 
499     Result = EvalStrIntExpressionOffsWithFlags(pArg, 1, UInt5, pOK, &Flags);
500     if (*pOK)
501     {
502       if (mFirstPassUnknown(Flags))
503         Result = 1;
504       if (!ChkRange(Result, 1, 16))
505         *pOK = False;
506       else
507         Result--;
508     }
509   }
510   else
511     *pOK = False;
512   return Result;
513 }
514 
515 /*-------------------------------------------------------------------------*/
516 
PutByte(Word Value)517 static void PutByte(Word Value)
518 {
519   if (CodeLen & 1)
520     WAsmCode[CodeLen >> 1] = (Value << 8) | BAsmCode[CodeLen - 1];
521   else
522     BAsmCode[CodeLen] = Value;
523   CodeLen++;
524 }
525 
ConstructTwoOp(Word Code,const tAdrParts * pSrcParts,const tAdrParts * pDestParts)526 static void ConstructTwoOp(Word Code, const tAdrParts *pSrcParts, const tAdrParts *pDestParts)
527 {
528   WAsmCode[CodeLen >> 1] = Code | (pSrcParts->Part << 8) | (pDestParts->Mode << 7)
529                          | GetBW() | (pSrcParts->Mode << 4) | pDestParts->Part;
530   CodeLen += 2;
531   memcpy(WAsmCode + (CodeLen >> 1), &pSrcParts->Val, pSrcParts->Cnt << 1); CodeLen += pSrcParts->Cnt << 1;
532   memcpy(WAsmCode + (CodeLen >> 1), &pDestParts->Val, pDestParts->Cnt << 1); CodeLen += pDestParts->Cnt << 1;
533 }
534 
ConstructTwoOpX(Word Code,const tAdrParts * pSrcParts,const tAdrParts * pDestParts)535 static void ConstructTwoOpX(Word Code, const tAdrParts *pSrcParts, const tAdrParts *pDestParts)
536 {
537   Word Prefix = 0x1800 | GetAL();
538 
539   if ((eModeReg != pSrcParts->Mode) || (eModeReg != pDestParts->Mode))
540   {
541     if (pSrcParts->Cnt)
542       Prefix |= ((pSrcParts->Val >> 16) & 15) << 7;
543     if (pDestParts->Cnt)
544       Prefix |= ((pDestParts->Val >> 16) & 15);
545   }
546 
547   /* take over multiply prefix for register<->register ops only */
548 
549   else
550   {
551     Prefix |= MultPrefix;
552     MultPrefix = 0;
553   }
554   WAsmCode[CodeLen >> 1] = Prefix; CodeLen += 2;
555   ConstructTwoOp(Code, pSrcParts, pDestParts);
556 }
557 
DecodeFixed(Word Code)558 static void DecodeFixed(Word Code)
559 {
560   if (!ChkArgCnt(0, 0));
561   else if (*AttrPart.Str) WrError(ErrNum_UseLessAttr);
562   else if (OpSize != eOpSizeDefault) WrError(ErrNum_InvOpSize);
563   else
564   {
565     if (Odd(EProgCounter())) WrError(ErrNum_AddrNotAligned);
566     WAsmCode[0] = Code; CodeLen = 2;
567   }
568 }
569 
DecodeTwoOp(Word Code)570 static void DecodeTwoOp(Word Code)
571 {
572   tAdrParts SrcParts, DestParts;
573 
574   if (!ChkArgCnt(2, 2));
575   else if (OpSize > eOpSizeW) WrError(ErrNum_InvOpSize);
576   else
577   {
578     PCDist = 2;
579     if (DecodeAdr(&ArgStr[1], eExtModeNo, 15, True, &SrcParts))
580     {
581       PCDist += SrcParts.Cnt << 1;
582       if (DecodeAdr(&ArgStr[2], eExtModeNo, 3, False, &DestParts))
583       {
584         if (Odd(EProgCounter())) WrError(ErrNum_AddrNotAligned);
585         ConstructTwoOp(Code, &SrcParts, &DestParts);
586       }
587     }
588   }
589 }
590 
DecodeTwoOpX(Word Code)591 static void DecodeTwoOpX(Word Code)
592 {
593   tAdrParts SrcParts, DestParts;
594 
595   Code &= ~1;
596 
597   if (!ChkArgCnt(2, 2))
598     return;
599 
600   PCDist = 4;
601   if (DecodeAdr(&ArgStr[1], eExtModeYes, MModeAs, True, &SrcParts))
602   {
603     PCDist += SrcParts.Cnt << 1;
604     if (DecodeAdr(&ArgStr[2], eExtModeYes, MModeAd, False, &DestParts))
605     {
606       if (Odd(EProgCounter())) WrError(ErrNum_AddrNotAligned);
607       ConstructTwoOpX(Code, &SrcParts, &DestParts);
608     }
609   }
610 }
611 
DecodeEmulOneToTwo(Word Code)612 static void DecodeEmulOneToTwo(Word Code)
613 {
614   Byte SrcSpec;
615   tAdrParts SrcParts, DestParts;
616 
617   /* separate src spec & opcode */
618 
619   SrcSpec = Lo(Code);
620   Code &= 0xff00;
621 
622   if (!ChkArgCnt(1, 1))
623     return;
624 
625   if (OpSize > eOpSizeW)
626   {
627     WrError(ErrNum_InvOpSize);
628     return;
629   }
630 
631   /* Decode operand:
632       - Ad modes always allowed
633       - for Src == Dest, also allow @Rn+: */
634 
635   PCDist = 2;
636   if (!DecodeAdr(&ArgStr[1], eExtModeNo, MModeAd | ((SrcSpec == 0xaa) ? MModeIRegAutoInc : 0), False, &DestParts))
637     return;
638 
639   /* filter immediate out separately (we get it as d(PC): */
640 
641   if (DestParts.WasImm)
642   {
643     WrError(ErrNum_InvAddrMode);
644     return;
645   }
646 
647   /* deduce src operand: 0xaa = special value for Src == Dest: */
648 
649   if (SrcSpec == 0xaa)
650   {
651     /* default assumption: */
652 
653     SrcParts = DestParts;
654 
655     /* @Rn+: is transformed to @Rn+,-opsize(Rn): */
656 
657     if (SrcParts.Mode == eModeIRegAutoInc)
658     {
659       static const Byte MemLen[3] = { 1, 2, 4 };
660 
661       DestParts.Mode = eModeRegDisp;
662       DestParts.Val = (0 - MemLen[OpSize]) & 0xffff;
663       DestParts.Cnt = 1;
664     }
665 
666     /* for PC-relative addressing, fix up destination displacement and
667        complain on displacement overflow: */
668 
669     else if ((DestParts.Mode == eModeRegDisp) && (DestParts.Part == RegPC))
670     {
671       LongWord NewDist = DestParts.Val - 2;
672 
673       if ((NewDist & 0x8000) != (DestParts.Val & 0x8000))
674       {
675         WrError(ErrNum_DistTooBig);
676         return;
677       }
678       DestParts.Val = NewDist;
679     }
680 
681     /* transform 0(Rn) as Dest back to @Rn as Src: */
682 
683     else if ((SrcParts.Mode == eModeRegDisp) && (DestParts.Val == 0))
684     {
685       SrcParts.Mode = eModeIReg;
686       SrcParts.Cnt = 0;
687     }
688   }
689 
690   /* Src == other (constant) value: 0xff means -1: */
691 
692   else
693     FillAdrPartsImm(&SrcParts, SrcSpec == 0xff ? 0xffffffff : SrcSpec, False);
694 
695   /* assemble like 2-op instruction: */
696 
697   ConstructTwoOp(Code, &SrcParts, &DestParts);
698 }
699 
DecodeBR(Word Code)700 static void DecodeBR(Word Code)
701 {
702   tAdrParts DstParts, SrcParts;
703 
704   PCDist = 2;
705   if (!ChkArgCnt(1, 1));
706   else if (*AttrPart.Str) WrError(ErrNum_UseLessAttr);
707   else if (DecodeAdr(&ArgStr[1], eExtModeNo, MModeAs, True, &SrcParts))
708   {
709     if (Odd(EProgCounter())) WrError(ErrNum_AddrNotAligned);
710     ResetAdr(&DstParts);
711     DstParts.Mode = eModeReg;
712     DstParts.Part = RegPC;
713     ConstructTwoOp(Code, &SrcParts, &DstParts);
714   }
715 }
716 
DecodeEmulOneToTwoX(Word Code)717 static void DecodeEmulOneToTwoX(Word Code)
718 {
719   Byte SrcSpec;
720   tAdrParts SrcParts, DestParts;
721 
722   /* separate src spec & opcode */
723 
724   SrcSpec = Lo(Code);
725   Code &= 0xff00;
726 
727   if (!ChkArgCnt(1, 1))
728     return;
729 
730   /* Decode operand:
731       - Ad modes always allowed
732       - for Src == Dest, also allow @Rn+: */
733 
734   PCDist = 4;
735   if (!DecodeAdr(&ArgStr[1], eExtModeYes, MModeAd | ((SrcSpec == 0xaa) ? MModeIRegAutoInc : 0), False, &DestParts))
736     return;
737 
738   /* filter immediate out separately (we get it as d(PC): */
739 
740   if (DestParts.WasImm)
741   {
742     WrError(ErrNum_InvAddrMode);
743     return;
744   }
745 
746   /* deduce src operand: 0xaa = special value for Src == Dest: */
747 
748   if (SrcSpec == 0xaa)
749   {
750     /* default assumption: */
751 
752     SrcParts = DestParts;
753 
754     /* @Rn+: is transformed to @Rn+,-opsize(Rn): */
755 
756     if (SrcParts.Mode == eModeIRegAutoInc)
757     {
758       static const Byte MemLen[3] = { 1, 2, 4 };
759 
760       DestParts.Mode = eModeRegDisp;
761       DestParts.Val = (0 - MemLen[OpSize]) & 0xfffff;
762       DestParts.Cnt = 1;
763     }
764 
765     /* for PC-relative addressing, fix up destination displacement and
766        complain on displacement overflow: */
767 
768     else if ((DestParts.Mode == eModeRegDisp) && (DestParts.Part == RegPC))
769     {
770       LongWord NewDist = DestParts.Val - 2;
771 
772       if ((NewDist & 0x8000) != (DestParts.Val & 0x8000))
773       {
774         WrError(ErrNum_DistTooBig);
775         return;
776       }
777       DestParts.Val = NewDist;
778     }
779 
780     /* transform 0(Rn) as Dest back to @Rn as Src: */
781 
782     else if ((SrcParts.Mode == eModeRegDisp) && (DestParts.Val == 0))
783     {
784       SrcParts.Mode = eModeIReg;
785       SrcParts.Cnt = 0;
786     }
787   }
788 
789   /* Src == other (constant) value: 0xff means -1: */
790 
791   else
792     FillAdrPartsImm(&SrcParts, SrcSpec == 0xff ? 0xffffffff : SrcSpec, False);
793 
794   /* assemble like 2-op instruction: */
795 
796   ConstructTwoOpX(Code, &SrcParts, &DestParts);
797 }
798 
DecodePOP(Word Code)799 static void DecodePOP(Word Code)
800 {
801   tAdrParts DstParts, SrcParts;
802 
803   PCDist = 2;
804   if (ChkArgCnt(1, 1)
805    && DecodeAdr(&ArgStr[1], eExtModeNo, MModeAd, True, &DstParts))
806   {
807     if (Odd(EProgCounter())) WrError(ErrNum_AddrNotAligned);
808     ResetAdr(&SrcParts);
809     SrcParts.Mode = eModeIRegAutoInc;
810     SrcParts.Part = RegSP;
811     ConstructTwoOp(Code, &SrcParts, &DstParts);
812   }
813 }
814 
DecodePOPX(Word Code)815 static void DecodePOPX(Word Code)
816 {
817   tAdrParts DstParts, SrcParts;
818 
819   PCDist = 4;
820   if (ChkArgCnt(1, 1)
821    && DecodeAdr(&ArgStr[1], eExtModeYes, MModeAd, True, &DstParts))
822   {
823     if (Odd(EProgCounter())) WrError(ErrNum_AddrNotAligned);
824     ResetAdr(&SrcParts);
825     SrcParts.Mode = eModeIRegAutoInc;
826     SrcParts.Part = RegSP;
827     ConstructTwoOpX(Code, &SrcParts, &DstParts);
828   }
829 }
830 
DecodeOneOp(Word Index)831 static void DecodeOneOp(Word Index)
832 {
833   const OneOpOrder *pOrder = OneOpOrders + Index;
834 
835   if (!ChkArgCnt(1, 1));
836   else if (OpSize > eOpSizeW) WrError(ErrNum_InvOpSize);
837   else if ((OpSize == eOpSizeB) && (!pOrder->MayByte)) WrError(ErrNum_InvOpSize);
838   else
839   {
840     tAdrParts AdrParts;
841 
842     PCDist = 2;
843     if (DecodeAdr(&ArgStr[1], eExtModeNo, 15, True, &AdrParts))
844     {
845       if (Odd(EProgCounter())) WrError(ErrNum_AddrNotAligned);
846       WAsmCode[0] = pOrder->Code | GetBW() | (AdrParts.Mode << 4) | AdrParts.Part;
847       memcpy(WAsmCode + 1, &AdrParts.Val, AdrParts.Cnt << 1);
848       CodeLen = (1 + AdrParts.Cnt) << 1;
849     }
850   }
851 }
852 
DecodeOneOpX(Word Index)853 static void DecodeOneOpX(Word Index)
854 {
855   const OneOpOrder *pOrder = OneOpOrders + Index;
856 
857   if (!ChkArgCnt(1, 1));
858   else if ((OpSize == eOpSizeB) && (!pOrder->MayByte)) WrError(ErrNum_InvOpSize);
859   else
860   {
861     tAdrParts AdrParts;
862 
863     PCDist = 4;
864     if (DecodeAdr(&ArgStr[1], eExtModeYes, 15, True, &AdrParts))
865     {
866       /* B/W for 20 bit size is 0 instead of 1 for SXT/SWPB */
867 
868       Word ActBW = pOrder->MayByte ? GetBW() : 0;
869 
870       if (Odd(EProgCounter())) WrError(ErrNum_AddrNotAligned);
871       WAsmCode[0] = 0x1800 | GetAL();
872 
873       /* put bits 16:19 of operand into bits 0:3 or 7:10 of extension word? */
874 
875       if (AdrParts.Cnt)
876         WAsmCode[0] |= (((AdrParts.Val >> 16) & 15) << 7);
877 
878       /* repeat only supported for register op */
879 
880       if (AdrParts.Mode == eModeReg)
881       {
882         WAsmCode[0] |= MultPrefix;
883         MultPrefix = 0;
884       }
885       WAsmCode[1] = pOrder->Code | ActBW | (AdrParts.Mode << 4) | AdrParts.Part;
886       memcpy(WAsmCode + 2, &AdrParts.Val, AdrParts.Cnt << 1);
887       CodeLen = (2 + AdrParts.Cnt) << 1;
888     }
889   }
890 }
891 
DecodeMOVA(Word Code)892 static void DecodeMOVA(Word Code)
893 {
894   tAdrParts AdrParts;
895 
896   UNUSED(Code);
897 
898   OpSize = eOpSizeA;
899   if (!ChkArgCnt(2, 2));
900   else if (*AttrPart.Str) WrError(ErrNum_UseLessAttr);
901   else
902   {
903     PCDist = 2;
904     DecodeAdr(&ArgStr[2], eExtModeYes, 15, False, &AdrParts);
905     if (AdrParts.WasAbs)
906     {
907       if (DecodeReg(&ArgStr[1], &WAsmCode[0], True) == eIsReg)
908       {
909         if (Odd(EProgCounter())) WrError(ErrNum_AddrNotAligned);
910         WAsmCode[0] = 0x0060 | (WAsmCode[0] << 8) | ((AdrParts.Val >> 16) & 0x0f);
911         WAsmCode[1] = AdrParts.Val & 0xffff;
912         CodeLen = 4;
913       }
914     }
915     else switch (AdrParts.Mode)
916     {
917       case eModeReg:
918         WAsmCode[0] = AdrParts.Part;
919         DecodeAdr(&ArgStr[1], eExtModeYes, 15, True, &AdrParts);
920         if (AdrParts.WasImm)
921         {
922           if (Odd(EProgCounter())) WrError(ErrNum_AddrNotAligned);
923           WAsmCode[0] |= ((AdrParts.Val >> 8) & 0x0f00) | 0x0080;
924           WAsmCode[1] = AdrParts.Val & 0xffff;
925           CodeLen = 4;
926         }
927         else if (AdrParts.WasAbs)
928         {
929           if (Odd(EProgCounter())) WrError(ErrNum_AddrNotAligned);
930           WAsmCode[0] |= ((AdrParts.Val >> 8) & 0x0f00) | 0x0020;
931           WAsmCode[1] = AdrParts.Val & 0xffff;
932           CodeLen = 4;
933         }
934         else switch (AdrParts.Mode)
935         {
936           case eModeReg:
937            if (Odd(EProgCounter())) WrError(ErrNum_AddrNotAligned);
938             WAsmCode[0] |= (AdrParts.Part << 8) | 0x00c0;
939             CodeLen = 2;
940             break;
941           case eModeIReg:
942             if (Odd(EProgCounter())) WrError(ErrNum_AddrNotAligned);
943             WAsmCode[0] |= (AdrParts.Part << 8) | 0x0000;
944             CodeLen = 2;
945             break;
946           case eModeIRegAutoInc:
947             if (Odd(EProgCounter())) WrError(ErrNum_AddrNotAligned);
948             WAsmCode[0] |= (AdrParts.Part << 8) | 0x0010;
949             CodeLen = 2;
950             break;
951           case eModeRegDisp:
952             if (ChkRange(AdrParts.Val, 0, 0xffff))
953             {
954               if (Odd(EProgCounter())) WrError(ErrNum_AddrNotAligned);
955               WAsmCode[0] |= (AdrParts.Part << 8) | 0x0030;
956               WAsmCode[1] = AdrParts.Val & 0xffff;
957               CodeLen = 4;
958             }
959             break;
960         }
961         break;
962       case eModeRegDisp:
963         if (ChkRange(AdrParts.Val, 0, 0xffff)
964          && (DecodeReg(&ArgStr[1], &WAsmCode[0], True) == eIsReg))
965         {
966           if (Odd(EProgCounter())) WrError(ErrNum_AddrNotAligned);
967           WAsmCode[0] = 0x0070 | (WAsmCode[0] << 8) | AdrParts.Part;
968           WAsmCode[1] = AdrParts.Val & 0xffff;
969           CodeLen = 4;
970         }
971         break;
972     }
973   }
974 }
975 
DecodeBRA(Word Code)976 static void DecodeBRA(Word Code)
977 {
978   if (ChkArgCnt(1, 1))
979   {
980     IncArgCnt();
981     strcpy(ArgStr[ArgCnt].Str, "PC");
982     DecodeMOVA(Code);
983   }
984 }
985 
DecodeCLRA(Word Code)986 static void DecodeCLRA(Word Code)
987 {
988   if (ChkArgCnt(1, 1)
989    && (DecodeReg(&ArgStr[1], &WAsmCode[0], True) == eIsReg))
990   {
991     WAsmCode[0] |= Code;
992     CodeLen = 2;
993   }
994 }
995 
DecodeTSTA(Word Code)996 static void DecodeTSTA(Word Code)
997 {
998   if (ChkArgCnt(1, 1)
999    && (DecodeReg(&ArgStr[1], &WAsmCode[0], True) == eIsReg))
1000   {
1001     WAsmCode[0] |= Code;
1002     WAsmCode[1] = 0x0000;
1003     CodeLen = 4;
1004   }
1005 }
1006 
DecodeDECDA_INCDA(Word Code)1007 static void DecodeDECDA_INCDA(Word Code)
1008 {
1009   if (ChkArgCnt(1, 1)
1010    && (DecodeReg(&ArgStr[1], &WAsmCode[0], True) == eIsReg))
1011   {
1012     WAsmCode[0] |= Code;
1013     WAsmCode[1] = 2;
1014     CodeLen = 4;
1015   }
1016 }
1017 
DecodeADDA_SUBA_CMPA(Word Code)1018 static void DecodeADDA_SUBA_CMPA(Word Code)
1019 {
1020   OpSize = eOpSizeA;
1021 
1022   if (!ChkArgCnt(2, 2));
1023   else if (*AttrPart.Str) WrError(ErrNum_UseLessAttr);
1024   else if (DecodeReg(&ArgStr[2], &WAsmCode[0], False) == eIsReg)
1025   {
1026     tAdrParts AdrParts;
1027 
1028     DecodeAdr(&ArgStr[1], eExtModeYes, 15, True, &AdrParts);
1029     if (AdrParts.WasImm)
1030     {
1031       if (Odd(EProgCounter())) WrError(ErrNum_AddrNotAligned);
1032       WAsmCode[0] |= Code | ((AdrParts.Val >> 8) & 0xf00);
1033       WAsmCode[1] = AdrParts.Val & 0xffff;
1034       CodeLen = 4;
1035     }
1036     else if (eModeReg == AdrParts.Mode)
1037     {
1038       if (Odd(EProgCounter())) WrError(ErrNum_AddrNotAligned);
1039       WAsmCode[0] |= Code | 0x0040 | (AdrParts.Part << 8);
1040       CodeLen = 2;
1041     }
1042     else
1043       WrError(ErrNum_InvOpSize);
1044   }
1045 }
1046 
DecodeRxM(Word Code)1047 static void DecodeRxM(Word Code)
1048 {
1049   if (!ChkArgCnt(2, 2));
1050   else if (OpSize == eOpSizeB) WrError(ErrNum_InvOpSize);
1051   else if (DecodeReg(&ArgStr[2], &WAsmCode[0], True) != eIsReg);
1052   else if (ArgStr[1].Str[0] != '#') WrError(ErrNum_OnlyImmAddr);
1053   else
1054   {
1055     Word Mult;
1056     tSymbolFlags Flags;
1057     Boolean OK;
1058 
1059     Mult = EvalStrIntExpressionOffsWithFlags(&ArgStr[1], 1, UInt3, &OK, &Flags);
1060     if (OK)
1061     {
1062       if (mFirstPassUnknown(Flags))
1063         Mult = 1;
1064       if (ChkRange(Mult, 1, 4))
1065       {
1066         if (Odd(EProgCounter())) WrError(ErrNum_AddrNotAligned);
1067         WAsmCode[0] |= Code | ((Mult - 1) << 10) | (GetAL() >> 2);
1068         CodeLen = 2;
1069       }
1070     }
1071   }
1072 }
1073 
DecodeCALLA(Word Code)1074 static void DecodeCALLA(Word Code)
1075 {
1076   tAdrParts AdrParts;
1077 
1078   UNUSED(Code);
1079 
1080   OpSize = eOpSizeA;
1081   PCDist = 2;
1082   if (!ChkArgCnt(1, 1));
1083   else if (*AttrPart.Str) WrError(ErrNum_UseLessAttr);
1084   else if (DecodeAdr(&ArgStr[1], eExtModeYes, 15, True, &AdrParts))
1085   {
1086     if (AdrParts.WasImm)
1087     {
1088       WAsmCode[0] = 0x13b0 | ((AdrParts.Val >> 16) & 15);
1089       WAsmCode[1] = AdrParts.Val & 0xffff;
1090       CodeLen = 4;
1091     }
1092     else if (AdrParts.WasAbs)
1093     {
1094       WAsmCode[0] = 0x1380 | ((AdrParts.Val >> 16) & 15);
1095       WAsmCode[1] = AdrParts.Val & 0xffff;
1096       CodeLen = 4;
1097     }
1098     else if ((AdrParts.Mode == eModeRegDisp) && (AdrParts.Part == RegPC))
1099     {
1100       WAsmCode[0] = 0x1390 | ((AdrParts.Val >> 16) & 15);
1101       WAsmCode[1] = AdrParts.Val & 0xffff;
1102       CodeLen = 4;
1103     }
1104     else if ((AdrParts.Mode == eModeRegDisp) && (((AdrParts.Val & 0xfffff) > 0x7fff) && ((AdrParts.Val & 0xfffff) < 0xf8000))) WrError(ErrNum_OverRange);
1105     else
1106     {
1107       WAsmCode[0] = 0x1340 | (AdrParts.Mode << 4) | (AdrParts.Part);
1108       memcpy(WAsmCode + 1, &AdrParts.Val, AdrParts.Cnt << 1);
1109       CodeLen = (1 + AdrParts.Cnt) << 1;
1110     }
1111   }
1112 }
1113 
DecodePUSHM_POPM(Word Code)1114 static void DecodePUSHM_POPM(Word Code)
1115 {
1116   if (!ChkArgCnt(2, 2));
1117   else if (OpSize == 0) WrError(ErrNum_InvOpSize);
1118   else if (DecodeReg(&ArgStr[2], &WAsmCode[0], True) != eIsReg);
1119   else if (ArgStr[1].Str[0] != '#') WrError(ErrNum_OnlyImmAddr);
1120   else
1121   {
1122     Boolean OK;
1123     Word Cnt;
1124     tSymbolFlags Flags;
1125 
1126     Cnt = EvalStrIntExpressionOffsWithFlags(&ArgStr[1], 1, UInt5, &OK, &Flags);
1127     if (mFirstPassUnknown(Flags))
1128       Cnt = 1;
1129     if (OK && ChkRange(Cnt, 1, 16))
1130     {
1131       Cnt--;
1132       if (Code & 0x0200)
1133         WAsmCode[0] = (WAsmCode[0] - Cnt) & 15;
1134       WAsmCode[0] |= Code | (Cnt << 4) | (GetAL() << 2);
1135       CodeLen = 2;
1136     }
1137   }
1138 }
1139 
DecodeJmp(Word Code)1140 static void DecodeJmp(Word Code)
1141 {
1142   Integer AdrInt;
1143   tSymbolFlags Flags;
1144   Boolean OK;
1145 
1146   if (!ChkArgCnt(1, 1));
1147   else if (OpSize != eOpSizeDefault) WrError(ErrNum_InvOpSize);
1148   {
1149     AdrInt = EvalStrIntExpressionWithFlags(&ArgStr[1], UInt16, &OK, &Flags) - (EProgCounter() + 2);
1150     if (OK)
1151     {
1152       if (Odd(AdrInt)) WrError(ErrNum_DistIsOdd);
1153       else if (!mSymbolQuestionable(Flags) && ((AdrInt < -1024) || (AdrInt > 1022))) WrError(ErrNum_JmpDistTooBig);
1154       else
1155       {
1156         if (Odd(EProgCounter())) WrError(ErrNum_AddrNotAligned);
1157         WAsmCode[0] = Code | ((AdrInt >> 1) & 0x3ff);
1158         CodeLen = 2;
1159       }
1160     }
1161   }
1162 }
1163 
DecodeBYTE(Word Index)1164 static void DecodeBYTE(Word Index)
1165 {
1166   Boolean OK;
1167   int z;
1168   TempResult t;
1169 
1170   UNUSED(Index);
1171 
1172   if (ChkArgCnt(1, ArgCntMax))
1173   {
1174     z = 1; OK = True;
1175     do
1176     {
1177       KillBlanks(ArgStr[z].Str);
1178       EvalStrExpression(&ArgStr[z], &t);
1179       switch (t.Typ)
1180       {
1181         case TempInt:
1182           if (mFirstPassUnknown(t.Flags)) t.Contents.Int &= 0xff;
1183           if (!RangeCheck(t.Contents.Int, Int8)) WrError(ErrNum_OverRange);
1184           else if (SetMaxCodeLen(CodeLen + 1))
1185           {
1186             WrError(ErrNum_CodeOverflow); OK = False;
1187           }
1188           else PutByte(t.Contents.Int);
1189           break;
1190         case TempString:
1191         {
1192           unsigned l = t.Contents.Ascii.Length;
1193 
1194           if (SetMaxCodeLen(l + CodeLen))
1195           {
1196             WrError(ErrNum_CodeOverflow); OK = False;
1197           }
1198           else
1199           {
1200             char *pEnd = t.Contents.Ascii.Contents + l, *p;
1201 
1202             TranslateString(t.Contents.Ascii.Contents, l);
1203             for (p = t.Contents.Ascii.Contents; p < pEnd; PutByte(*(p++)));
1204           }
1205           break;
1206         }
1207         case TempFloat:
1208           WrStrErrorPos(ErrNum_StringOrIntButFloat, &ArgStr[z]);
1209           /* fall-through */
1210         default:
1211           OK = False;
1212           break;
1213       }
1214       z++;
1215     }
1216     while ((z <= ArgCnt) && (OK));
1217     if (!OK) CodeLen = 0;
1218   }
1219 }
1220 
DecodeWORD(Word Index)1221 static void DecodeWORD(Word Index)
1222 {
1223   int z;
1224   Word HVal16;
1225   Boolean OK;
1226 
1227   UNUSED(Index);
1228 
1229   if (ChkArgCnt(1, ArgCntMax))
1230   {
1231     z = 1; OK = True;
1232     do
1233     {
1234       HVal16 = EvalStrIntExpression(&ArgStr[z], Int16, &OK);
1235       if (OK)
1236       {
1237         WAsmCode[CodeLen >> 1] = HVal16;
1238         CodeLen += 2;
1239       }
1240       z++;
1241     }
1242     while ((z <= ArgCnt) && (OK));
1243     if (!OK) CodeLen = 0;
1244   }
1245 }
1246 
DecodeBSS(Word Index)1247 static void DecodeBSS(Word Index)
1248 {
1249   Word HVal16;
1250   Boolean OK;
1251 
1252   UNUSED(Index);
1253 
1254   if (ChkArgCnt(1, 1))
1255   {
1256     tSymbolFlags Flags;
1257 
1258     HVal16 = EvalStrIntExpressionWithFlags(&ArgStr[1], Int16, &OK, &Flags);
1259     if (mFirstPassUnknown(Flags)) WrError(ErrNum_FirstPassCalc);
1260     else if (OK)
1261     {
1262       if (!HVal16) WrError(ErrNum_NullResMem);
1263       DontPrint = True; CodeLen = HVal16;
1264       BookKeeping();
1265     }
1266   }
1267 }
1268 
DecodeRPT(Word Code)1269 static void DecodeRPT(Word Code)
1270 {
1271   char *pOpPart, *pArgPart1, *pAttrPart;
1272   Boolean OK;
1273 
1274   /* fundamentals */
1275 
1276   if (!ChkArgCnt(1, ArgCntMax))
1277     return;
1278   if (*AttrPart.Str != '\0')
1279   {
1280     WrError(ErrNum_UseLessAttr);
1281     return;
1282   }
1283 
1284   /* multiplier argument */
1285 
1286   pOpPart = FirstBlank(ArgStr[1].Str);
1287   if (!pOpPart)
1288   {
1289     WrError(ErrNum_CannotSplitArg);
1290     return;
1291   }
1292   *pOpPart++ = '\0';
1293   MultPrefix = Code | GetMult(&ArgStr[1], &OK);
1294   if (!OK)
1295     return;
1296 
1297   /* new OpPart: */
1298 
1299   KillPrefBlanks(pOpPart);
1300   pArgPart1 = FirstBlank(pOpPart);
1301   if (!pArgPart1)
1302   {
1303     WrError(ErrNum_CannotSplitArg);
1304     return;
1305   }
1306   *pArgPart1++ = '\0';
1307   strcpy(OpPart.Str, pOpPart);
1308   UpString(OpPart.Str);
1309   KillPrefBlanks(pArgPart1);
1310   strmov(ArgStr[1].Str, pArgPart1);
1311 
1312   /* split off new attribute part: */
1313 
1314   pAttrPart = strrchr(OpPart.Str, '.');
1315   if (pAttrPart)
1316   {
1317     AttrPart.Pos.Len = strmemcpy(AttrPart.Str, STRINGSIZE, pAttrPart + 1, strlen(pAttrPart + 1));
1318     *pAttrPart = '\0';
1319   }
1320   else
1321     StrCompReset(&AttrPart);
1322 
1323   /* prefix 0x0000 is rptc #1 and effectively a NOP prefix: */
1324 
1325   MakeCode();
1326   if (MultPrefix)
1327   {
1328     WrError(ErrNum_NotRepeatable);
1329     CodeLen = 0;
1330   }
1331 }
1332 
1333 /*-------------------------------------------------------------------------*/
1334 
1335 #define AddFixed(NName, NCode) \
1336         AddInstTable(InstTable, NName, NCode, DecodeFixed)
1337 
AddTwoOp(const char * NName,Word NCode)1338 static void AddTwoOp(const char *NName, Word NCode)
1339 {
1340   AddInstTable(InstTable, NName, NCode, DecodeTwoOp);
1341   if (MomCPU >= CPUMSP430X)
1342   {
1343     char XName[20];
1344 
1345     as_snprintf(XName, sizeof(XName), "%sX", NName);
1346     AddInstTable(InstTable, XName, NCode, DecodeTwoOpX);
1347   }
1348 }
1349 
AddEmulOneToTwo(const char * NName,Word NCode)1350 static void AddEmulOneToTwo(const char *NName, Word NCode)
1351 {
1352   AddInstTable(InstTable, NName, NCode, DecodeEmulOneToTwo);
1353 }
1354 
AddEmulOneToTwoX(const char * NName,Word NCode)1355 static void AddEmulOneToTwoX(const char *NName, Word NCode)
1356 {
1357   AddInstTable(InstTable, NName, NCode, DecodeEmulOneToTwoX);
1358 }
1359 
AddOneOp(const char * NName,Boolean NMay,Boolean AllowX,Word NCode)1360 static void AddOneOp(const char *NName, Boolean NMay, Boolean AllowX, Word NCode)
1361 {
1362   if (InstrZ >= OneOpCount) exit(255);
1363   OneOpOrders[InstrZ].MayByte = NMay;
1364   OneOpOrders[InstrZ].Code = NCode;
1365   AddInstTable(InstTable, NName, InstrZ, DecodeOneOp);
1366   if ((MomCPU >= CPUMSP430X) && AllowX)
1367   {
1368     char XName[20];
1369 
1370     as_snprintf(XName, sizeof(XName), "%sX", NName);
1371     AddInstTable(InstTable, XName, InstrZ, DecodeOneOpX);
1372   }
1373   InstrZ++;
1374 }
1375 
1376 #define AddJmp(NName, NCode) \
1377         AddInstTable(InstTable, NName, NCode, DecodeJmp)
1378 
InitFields(void)1379 static void InitFields(void)
1380 {
1381   InstTable = CreateInstTable(207);
1382   SetDynamicInstTable(InstTable);
1383 
1384   AddFixed("RETI", 0x1300);
1385   AddFixed("CLRC", 0xc312);
1386   AddFixed("CLRN", 0xc222);
1387   AddFixed("CLRZ", 0xc322);
1388   AddFixed("DINT", 0xc232);
1389   AddFixed("EINT", 0xd232);
1390   AddFixed("NOP" , NOPCode);
1391   AddFixed("RET" , 0x4130);
1392   AddFixed("SETC", 0xd312);
1393   AddFixed("SETN", 0xd222);
1394   AddFixed("SETZ", 0xd322);
1395 
1396   AddTwoOp("MOV" , 0x4000); AddTwoOp("ADD" , 0x5000);
1397   AddTwoOp("ADDC", 0x6000); AddTwoOp("SUBC", 0x7000);
1398   AddTwoOp("SUB" , 0x8000); AddTwoOp("CMP" , 0x9000);
1399   AddTwoOp("DADD", 0xa000); AddTwoOp("BIT" , 0xb000);
1400   AddTwoOp("BIC" , 0xc000); AddTwoOp("BIS" , 0xd000);
1401   AddTwoOp("XOR" , 0xe000); AddTwoOp("AND" , 0xf000);
1402 
1403   AddEmulOneToTwo("ADC" , 0x6000); /* ADDC #0, dst */
1404   AddInstTable(InstTable, "BR", 0x4000, DecodeBR); /* MOV dst, PC */
1405   AddEmulOneToTwo("CLR" , 0x4000); /* MOV #0, dst */
1406   AddEmulOneToTwo("DADC", 0xa000); /* DADD #0, dst */
1407   AddEmulOneToTwo("DEC" , 0x8001); /* SUB #1, dst */
1408   AddEmulOneToTwo("DECD", 0x8002); /* SUB #2, dst */
1409   AddEmulOneToTwo("INC" , 0x5001); /* ADD #1, dst */
1410   AddEmulOneToTwo("INCD", 0x5002); /* ADD #2, dst */
1411   AddEmulOneToTwo("INV" , 0xe0ff); /* XOR #-1, dst */
1412   AddInstTable(InstTable, "POP", 0x4000, DecodePOP); /* MOV @SP+,dst */
1413   AddEmulOneToTwo("RLA" , 0x50aa); /* ADD dst, dst */
1414   AddEmulOneToTwo("RLC" , 0x60aa); /* ADDC dst, dst */
1415   AddEmulOneToTwo("SBC" , 0x7000); /* SUBC #0, dst */
1416   AddEmulOneToTwo("TST" , 0x9000); /* CMP #0, dst */
1417 
1418   OneOpOrders = (OneOpOrder *) malloc(sizeof(OneOpOrder) * OneOpCount); InstrZ = 0;
1419   AddOneOp("RRC" , True , True , 0x1000); AddOneOp("RRA" , True , True , 0x1100);
1420   AddOneOp("PUSH", True , True , 0x1200); AddOneOp("SWPB", False, True , 0x1080);
1421   AddOneOp("CALL", False, False, 0x1280); AddOneOp("SXT" , False, True , 0x1180);
1422 
1423   if (MomCPU >= CPUMSP430X)
1424   {
1425     /* what about  RRUX? */
1426 
1427     AddInstTable(InstTable, "MOVA", 0x0000, DecodeMOVA);
1428     AddInstTable(InstTable, "ADDA", 0x00a0, DecodeADDA_SUBA_CMPA);
1429     AddInstTable(InstTable, "CMPA", 0x0090, DecodeADDA_SUBA_CMPA);
1430     AddInstTable(InstTable, "SUBA", 0x00b0, DecodeADDA_SUBA_CMPA);
1431 
1432     AddInstTable(InstTable, "RRCM", 0x0040, DecodeRxM);
1433     AddInstTable(InstTable, "RRAM", 0x0140, DecodeRxM);
1434     AddInstTable(InstTable, "RLAM", 0x0240, DecodeRxM);
1435     AddInstTable(InstTable, "RRUM", 0x0340, DecodeRxM);
1436 
1437     AddInstTable(InstTable, "CALLA", 0x0000, DecodeCALLA);
1438 
1439     AddInstTable(InstTable, "PUSHM", 0x1400, DecodePUSHM_POPM);
1440     AddInstTable(InstTable, "POPM",  0x1600, DecodePUSHM_POPM);
1441 
1442     AddEmulOneToTwoX("ADCX", 0x6000); /* ADDCX #0, dst */
1443     AddInstTable(InstTable, "BRA", 0x4000, DecodeBRA); /* MOVA dst, PC */
1444     AddFixed("RETA", 0x0110); /* MOVA @SP+,PC */
1445     AddInstTable(InstTable, "CLRA", 0x4300, DecodeCLRA); /* MOV #0,Rdst */
1446     AddEmulOneToTwoX("CLRX", 0x4000); /* MOVX #0, dest */
1447     AddEmulOneToTwoX("DADCX", 0xa000); /* DADDX #0, dst */
1448     AddEmulOneToTwoX("DECX" , 0x8001); /* SUBX #1, dst */
1449     AddInstTable(InstTable, "DECDA", 0x00b0, DecodeDECDA_INCDA); /* SUBA #2,Rdst */
1450     AddEmulOneToTwoX("DECDX", 0x8002); /* SUBX #2, dst */
1451     AddEmulOneToTwoX("INCX" , 0x5001); /* SUBX #1, dst */
1452     AddInstTable(InstTable, "INCDA", 0x00a0, DecodeDECDA_INCDA); /* SUBA #2,Rdst */
1453     AddEmulOneToTwoX("INCDX", 0x5002); /* SUBX #2, dst */
1454     AddEmulOneToTwoX("INVX" , 0xe0ff); /* XORX #-1, dst */
1455     AddEmulOneToTwoX("RLAX" , 0x50aa); /* ADDX dst, dst */
1456     AddEmulOneToTwoX("RLCX" , 0x60aa); /* ADDCX dst, dst */
1457     AddEmulOneToTwoX("SBCX" , 0x7000); /* SUBCX #0, dst */
1458     AddInstTable(InstTable, "TSTA" , 0x0090, DecodeTSTA); /* CMPA #0,Rdst */
1459     AddEmulOneToTwoX("TSTX" , 0x9000); /* CMPX #0, dst */
1460     AddInstTable(InstTable, "POPX", 0x4000, DecodePOPX); /* MOVX @SP+,dst */
1461 
1462     AddInstTable(InstTable, "RPTC", 0x0000, DecodeRPT);
1463     AddInstTable(InstTable, "RPTZ", 0x0100, DecodeRPT);
1464   }
1465 
1466   AddJmp("JNE" , 0x2000); AddJmp("JNZ" , 0x2000);
1467   AddJmp("JE"  , 0x2400); AddJmp("JZ"  , 0x2400);
1468   AddJmp("JNC" , 0x2800); AddJmp("JC"  , 0x2c00);
1469   AddJmp("JN"  , 0x3000); AddJmp("JGE" , 0x3400);
1470   AddJmp("JL"  , 0x3800); AddJmp("JMP" , 0x3C00);
1471   AddJmp("JEQ" , 0x2400); AddJmp("JLO" , 0x2800);
1472   AddJmp("JHS" , 0x2c00);
1473 
1474   AddInstTable(InstTable, "WORD", 0, DecodeWORD);
1475 
1476   AddInstTable(InstTable, "REG", 0, CodeREG);
1477 }
1478 
DeinitFields(void)1479 static void DeinitFields(void)
1480 {
1481   free(OneOpOrders);
1482 
1483   DestroyInstTable(InstTable);
1484 }
1485 
1486 /*-------------------------------------------------------------------------*/
1487 
1488 /*!------------------------------------------------------------------------
1489  * \fn     InternSymbol_MSP(char *pArg, TempResult *pResult)
1490  * \brief  handle built-in (register) symbols for MSP
1491  * \param  pArg source argument
1492  * \param  pResult result buffer
1493  * ------------------------------------------------------------------------ */
1494 
InternSymbol_MSP(char * pArg,TempResult * pResult)1495 static void InternSymbol_MSP(char *pArg, TempResult *pResult)
1496 {
1497   Word RegNum;
1498 
1499   if (DecodeRegCore(pArg, &RegNum))
1500   {
1501     pResult->Typ = TempReg;
1502     pResult->DataSize = eSymbolSize8Bit;
1503     pResult->Contents.RegDescr.Reg = RegNum;
1504     pResult->Contents.RegDescr.Dissect = DissectReg_MSP;
1505   }
1506 }
1507 
DecodeAttrPart_MSP(void)1508 static Boolean DecodeAttrPart_MSP(void)
1509 {
1510   if (strlen(AttrPart.Str) > 1)
1511   {
1512     WrStrErrorPos(ErrNum_UndefAttr, &AttrPart);
1513     return False;
1514   }
1515   switch (as_toupper(*AttrPart.Str))
1516   {
1517     case '\0':
1518       break;
1519     case 'B':
1520       AttrPartOpSize = eSymbolSize8Bit;
1521       break;
1522     case 'W':
1523       AttrPartOpSize = eSymbolSize16Bit;
1524       break;
1525     case 'A':
1526       if (MomCPU >= CPUMSP430X)
1527       {
1528         AttrPartOpSize = eSymbolSize24Bit; /* TODO: should be 20 bits */
1529         break;
1530       }
1531       /* else fall-through */
1532     default:
1533       WrStrErrorPos(ErrNum_UndefAttr, &AttrPart);
1534       return False;
1535   }
1536   return True;
1537 }
1538 
MakeCode_MSP(void)1539 static void MakeCode_MSP(void)
1540 {
1541   CodeLen = 0; DontPrint = False; PCDist = 0;
1542 
1543   /* to be ignored: */
1544 
1545   if (Memo("")) return;
1546 
1547   /* process attribute */
1548 
1549   switch (AttrPartOpSize)
1550   {
1551     case eSymbolSize24Bit:
1552       OpSize = eOpSizeA;
1553       break;
1554     case eSymbolSize16Bit:
1555       OpSize = eOpSizeW;
1556       break;
1557     case eSymbolSize8Bit:
1558       OpSize = eOpSizeB;
1559       break;
1560     default:
1561       OpSize = eOpSizeDefault;
1562       break;
1563   }
1564 
1565   /* insns not requiring word alignment */
1566 
1567   if (Memo("BYTE"))
1568   {
1569     DecodeBYTE(0);
1570     return;
1571   }
1572   if (Memo("BSS"))
1573   {
1574     DecodeBSS(0);
1575     return;
1576   }
1577 
1578   /* For all other (pseudo) instructions, optionally pad to even */
1579 
1580   if (Odd(EProgCounter()))
1581   {
1582     if (DoPadding)
1583       InsertPadding(1, False);
1584     else
1585       WrError(ErrNum_AddrNotAligned);
1586   }
1587 
1588   /* all the rest from table */
1589 
1590   if (!LookupInstTable(InstTable, OpPart.Str))
1591     WrStrErrorPos(ErrNum_UnknownInstruction, &OpPart);
1592 }
1593 
IsDef_MSP(void)1594 static Boolean IsDef_MSP(void)
1595 {
1596   return Memo("REG");
1597 }
1598 
SwitchFrom_MSP(void)1599 static void SwitchFrom_MSP(void)
1600 {
1601   DeinitFields();
1602   ClearONOFF();
1603 }
1604 
SwitchTo_MSP(void)1605 static void SwitchTo_MSP(void)
1606 {
1607   TurnWords = False; ConstMode = ConstModeIntel;
1608 
1609   PCSymbol = "$"; HeaderID = 0x4a; NOPCode = 0x4303; /* = MOV #0,#0 */
1610   DivideChars = ","; HasAttrs = True; AttrChars = ".";
1611 
1612   ValidSegs = 1 << SegCode;
1613   Grans[SegCode] = 1; ListGrans[SegCode] = 2; SegInits[SegCode] = 0;
1614   AdrIntType = (MomCPU == CPUMSP430X) ? UInt20 : UInt16;
1615   DispIntType = (MomCPU == CPUMSP430X) ? Int20 : Int16;
1616   SegLimits[SegCode] = IntTypeDefs[AdrIntType].Max;
1617 
1618   AddONOFF("PADDING", &DoPadding, DoPaddingName, False);
1619 
1620   DecodeAttrPart = DecodeAttrPart_MSP;
1621   MakeCode = MakeCode_MSP;
1622   IsDef = IsDef_MSP;
1623   InternSymbol = InternSymbol_MSP;
1624   DissectReg = DissectReg_MSP;
1625   SwitchFrom = SwitchFrom_MSP; InitFields();
1626 
1627   MultPrefix = 0x0000;
1628 }
1629 
codemsp_init(void)1630 void codemsp_init(void)
1631 {
1632   CPUMSP430 = AddCPU("MSP430", SwitchTo_MSP);
1633   CPUMSP430X = AddCPU("MSP430X", SwitchTo_MSP);
1634 }
1635