1 /* codemic8.c */
2 /*****************************************************************************/
3 /* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only                     */
4 /*                                                                           */
5 /* AS-Portierung                                                             */
6 /*                                                                           */
7 /* Codegenerator LatticeMico8                                                */
8 /*                                                                           */
9 /*****************************************************************************/
10 
11 #include "stdinc.h"
12 #include <stdio.h>
13 #include <string.h>
14 #include <ctype.h>
15 
16 #include "nls.h"
17 #include "strutil.h"
18 #include "bpemu.h"
19 #include "asmdef.h"
20 #include "asmsub.h"
21 #include "asmpars.h"
22 #include "asmitree.h"
23 #include "asmallg.h"
24 #include "intpseudo.h"
25 #include "codevars.h"
26 #include "headids.h"
27 #include "errmsg.h"
28 #include "codepseudo.h"
29 
30 #include "codemic8.h"
31 
32 #define ALUOrderCnt 14
33 #define FixedOrderCnt 9
34 #define ShortBranchOrderCnt 8
35 #define LongBranchOrderCnt 10
36 #define MemOrderCnt 6
37 #define RegOrderCnt 2
38 
39 /* define as needed by address space */
40 
41 #define CodeAddrInt UInt12
42 #define DataAddrInt UInt5
43 
44 typedef struct
45 {
46   LongWord Code;
47 } FixedOrder;
48 
49 typedef struct
50 {
51   LongWord Code;
52   Boolean MayImm;
53 } ALUOrder;
54 
55 typedef struct
56 {
57   LongWord Code;
58   Byte Space;
59 } MemOrder;
60 
61 static FixedOrder *FixedOrders, *ShortBranchOrders, *RegOrders, *LongBranchOrders;
62 static MemOrder *MemOrders;
63 static ALUOrder *ALUOrders;
64 
65 static CPUVar CPUMico8_05, CPUMico8_V3, CPUMico8_V31;
66 
67 /*--------------------------------------------------------------------------
68  * Address Expression Parsing
69  *--------------------------------------------------------------------------*/
70 
71 /*!------------------------------------------------------------------------
72  * \fn     IsWRegCore(const char *pArg, LongWord *pValue)
73  * \brief  check whether argument is a CPU register
74  * \param  pArg argument to check
75  * \param  pValue register number if it is a register
76  * \return True if it is a register
77  * ------------------------------------------------------------------------ */
78 
IsWRegCore(const char * pArg,LongWord * pValue)79 static Boolean IsWRegCore(const char *pArg, LongWord *pValue)
80 {
81   Boolean OK;
82 
83   if ((strlen(pArg) < 2) || (as_toupper(*pArg) != 'R'))
84     return False;
85 
86   *pValue = ConstLongInt(pArg + 1, &OK, 10);
87   if (!OK)
88     return False;
89 
90   return (*pValue < 32);
91 }
92 
93 /*!------------------------------------------------------------------------
94  * \fn     DissectReg_Mico8(char *pDest, size_t DestSize, tRegInt Value, tSymbolSize InpSize)
95  * \brief  dissect register symbols - MICO8 variant
96  * \param  pDest destination buffer
97  * \param  DestSize destination buffer size
98  * \param  Value numeric register value
99  * \param  InpSize register size
100  * ------------------------------------------------------------------------ */
101 
DissectReg_Mico8(char * pDest,size_t DestSize,tRegInt Value,tSymbolSize InpSize)102 static void DissectReg_Mico8(char *pDest, size_t DestSize, tRegInt Value, tSymbolSize InpSize)
103 {
104   switch (InpSize)
105   {
106     case eSymbolSize8Bit:
107       as_snprintf(pDest, DestSize, "R%u", (unsigned)Value);
108       break;
109     default:
110       as_snprintf(pDest, DestSize, "%d-%u", (int)InpSize, (unsigned)Value);
111   }
112 }
113 
114 /*!------------------------------------------------------------------------
115  * \fn     IsWReg(const tStrComp *pArg, LongWord *pValue, Boolean MustBeReg)
116  * \brief  check whether argument is a CPU register or register alias
117  * \param  pArg argument to check
118  * \param  pValue register number if it is a register
119  * \param  MustBeReg expecting register as arg?
120  * \return register parse result
121  * ------------------------------------------------------------------------ */
122 
IsWReg(const tStrComp * pArg,LongWord * pValue,Boolean MustBeReg)123 static tRegEvalResult IsWReg(const tStrComp *pArg, LongWord *pValue, Boolean MustBeReg)
124 {
125   tRegDescr RegDescr;
126   tEvalResult EvalResult;
127   tRegEvalResult RegEvalResult;
128 
129   if (IsWRegCore(pArg->Str, pValue))
130     return eIsReg;
131 
132   RegEvalResult = EvalStrRegExpressionAsOperand(pArg, &RegDescr, &EvalResult, eSymbolSize8Bit, MustBeReg);
133   *pValue = RegDescr.Reg;
134   return RegEvalResult;
135 }
136 
137 /*--------------------------------------------------------------------------
138  * Code Handlers
139  *--------------------------------------------------------------------------*/
140 
DecodePort(Word Index)141 static void DecodePort(Word Index)
142 {
143   UNUSED(Index);
144 
145   CodeEquate(SegIO, 0, SegLimits[SegIO]);
146 }
147 
DecodeFixed(Word Index)148 static void DecodeFixed(Word Index)
149 {
150   FixedOrder *pOrder = FixedOrders + Index;
151 
152   if (ChkArgCnt(0, 0))
153   {
154     DAsmCode[0] = pOrder->Code;
155     CodeLen = 1;
156   }
157 }
158 
DecodeALU(Word Index)159 static void DecodeALU(Word Index)
160 {
161   ALUOrder *pOrder = ALUOrders + Index;
162   LongWord Src, DReg;
163 
164   if (ChkArgCnt(2, 2)
165    && IsWReg(&ArgStr[1], &DReg, True))
166     switch (IsWReg(&ArgStr[2], &Src, True))
167     {
168       case eIsReg:
169         DAsmCode[0] = pOrder->Code | (DReg << 8) | (Src << 3);
170         CodeLen = 1;
171         break;
172       case eIsNoReg:
173         if (!pOrder->MayImm) WrStrErrorPos(ErrNum_InvAddrMode, &ArgStr[2]);
174         else
175         {
176           Boolean OK;
177 
178           Src = EvalStrIntExpression(&ArgStr[2], Int8, &OK);
179           if (OK)
180           {
181             DAsmCode[0] = pOrder->Code | (1 << 13) | (DReg << 8) | (Src & 0xff);
182            CodeLen = 1;
183           }
184         }
185         break;
186       default:
187         break;
188     }
189 }
190 
DecodeALUI(Word Index)191 static void DecodeALUI(Word Index)
192 {
193   ALUOrder *pOrder = ALUOrders + Index;
194   LongWord Src, DReg;
195   Boolean OK;
196 
197   if (ChkArgCnt(2, 2)
198    && IsWReg(&ArgStr[1], &DReg, True))
199   {
200     Src = EvalStrIntExpression(&ArgStr[2], Int8, &OK);
201     if (OK)
202     {
203       DAsmCode[0] = pOrder->Code | (1 << 13) | (DReg << 8) | (Src & 0xff);
204       CodeLen = 1;
205     }
206   }
207 }
208 
DecodeShortBranch(Word Index)209 static void DecodeShortBranch(Word Index)
210 {
211   FixedOrder *pOrder = ShortBranchOrders + Index;
212   LongInt Dest;
213   Boolean OK;
214   tSymbolFlags Flags;
215 
216   if (ChkArgCnt(1, 1))
217   {
218     Dest = EvalStrIntExpressionWithFlags(&ArgStr[1], CodeAddrInt, &OK, &Flags);
219     if (OK)
220     {
221       Dest -= EProgCounter();
222       if (((Dest < -512) || (Dest > 511)) && !mSymbolQuestionable(Flags)) WrError(ErrNum_JmpDistTooBig);
223       else
224       {
225         DAsmCode[0] = pOrder->Code | (Dest & 0x3ff);
226         CodeLen = 1;
227       }
228     }
229   }
230 }
231 
DecodeLongBranch(Word Index)232 static void DecodeLongBranch(Word Index)
233 {
234   FixedOrder *pOrder = LongBranchOrders + Index;
235   LongInt Dest;
236   Boolean OK;
237   tSymbolFlags Flags;
238 
239   if (ChkArgCnt(1, 1))
240   {
241     Dest = EvalStrIntExpressionWithFlags(&ArgStr[1], CodeAddrInt, &OK, &Flags);
242     if (OK)
243     {
244       Dest -= EProgCounter();
245       if (((Dest < -2048) || (Dest > 2047)) && !mSymbolQuestionable(Flags)) WrError(ErrNum_JmpDistTooBig);
246       else
247       {
248         DAsmCode[0] = pOrder->Code | (Dest & 0xfff);
249         CodeLen = 1;
250       }
251     }
252   }
253 }
254 
DecodeMem(Word Index)255 static void DecodeMem(Word Index)
256 {
257   MemOrder *pOrder = MemOrders + Index;
258   LongWord DReg, Src;
259 
260   if (ChkArgCnt(2, 2)
261    && IsWReg(&ArgStr[1], &DReg, True))
262     switch (IsWReg(&ArgStr[2], &Src, False))
263     {
264       case eIsReg:
265         DAsmCode[0] = pOrder->Code | (DReg << 8) | ((Src & 0x1f) << 3) | 2;
266         CodeLen = 1;
267         break;
268       case eIsNoReg:
269       {
270         tEvalResult EvalResult;
271 
272         Src = EvalStrIntExpressionWithResult(&ArgStr[2], DataAddrInt, &EvalResult);
273         if (EvalResult.OK)
274         {
275           ChkSpace(pOrder->Space, EvalResult.AddrSpaceMask);
276           DAsmCode[0] = pOrder->Code | (DReg << 8) | ((Src & 0x1f) << 3);
277           CodeLen = 1;
278         }
279         break;
280       }
281       default:
282         break;
283     }
284 }
285 
DecodeMemI(Word Index)286 static void DecodeMemI(Word Index)
287 {
288   MemOrder *pOrder = MemOrders + Index;
289   LongWord DReg, SReg;
290 
291   if (ChkArgCnt(2, 2)
292    && IsWReg(&ArgStr[1], &DReg, True)
293    && IsWReg(&ArgStr[2], &SReg, True))
294   {
295     DAsmCode[0] = pOrder->Code | (DReg << 8) | (SReg << 3) | 2;
296     CodeLen = 1;
297   }
298 }
299 
DecodeReg(Word Index)300 static void DecodeReg(Word Index)
301 {
302   FixedOrder *pOrder = RegOrders + Index;
303   LongWord Reg = 0;
304 
305   if (!ChkArgCnt(1, 1));
306   else if (IsWReg(&ArgStr[1], &Reg, True))
307   {
308     DAsmCode[0] = pOrder->Code | (Reg << 8);
309     CodeLen = 1;
310   }
311 }
312 
313 /*--------------------------------------------------------------------------
314  * Instruction Table Handling
315  *--------------------------------------------------------------------------*/
316 
AddFixed(const char * NName,LongWord NCode)317 static void AddFixed(const char *NName, LongWord NCode)
318 {
319   if (InstrZ >= FixedOrderCnt)
320     exit(255);
321 
322   FixedOrders[InstrZ].Code = NCode;
323   AddInstTable(InstTable, NName, InstrZ++, DecodeFixed);
324 }
325 
AddALU(const char * NName,const char * NImmName,LongWord NCode)326 static void AddALU(const char *NName, const char *NImmName, LongWord NCode)
327 {
328   if (InstrZ >= ALUOrderCnt)
329     exit(255);
330 
331   ALUOrders[InstrZ].Code = NCode;
332   AddInstTable(InstTable, NName, InstrZ, DecodeALU);
333   ALUOrders[InstrZ].MayImm = NImmName != NULL;
334   if (ALUOrders[InstrZ].MayImm)
335     AddInstTable(InstTable, NImmName, InstrZ, DecodeALUI);
336   InstrZ++;
337 }
338 
AddShortBranch(const char * NName,LongWord NCode)339 static void AddShortBranch(const char *NName, LongWord NCode)
340 {
341   if (InstrZ >= ShortBranchOrderCnt)
342     exit(255);
343 
344   ShortBranchOrders[InstrZ].Code = NCode;
345   AddInstTable(InstTable, NName, InstrZ++, DecodeShortBranch);
346 }
347 
AddLongBranch(const char * NName,LongWord NCode)348 static void AddLongBranch(const char *NName, LongWord NCode)
349 {
350   if (InstrZ >= LongBranchOrderCnt)
351     exit(255);
352 
353   LongBranchOrders[InstrZ].Code = NCode;
354   AddInstTable(InstTable, NName, InstrZ++, DecodeLongBranch);
355 }
356 
AddMem(const char * NName,const char * NImmName,LongWord NCode,Byte NSpace)357 static void AddMem(const char *NName, const char *NImmName, LongWord NCode, Byte NSpace)
358 {
359   if (InstrZ >= MemOrderCnt)
360     exit(255);
361 
362   MemOrders[InstrZ].Code = NCode;
363   MemOrders[InstrZ].Space = NSpace;
364   AddInstTable(InstTable, NName, InstrZ, DecodeMem);
365   AddInstTable(InstTable, NImmName, InstrZ, DecodeMemI);
366   InstrZ++;
367 }
368 
AddReg(const char * NName,LongWord NCode)369 static void AddReg(const char *NName, LongWord NCode)
370 {
371   if (InstrZ >= RegOrderCnt)
372     exit(255);
373 
374   RegOrders[InstrZ].Code = NCode;
375   AddInstTable(InstTable, NName, InstrZ++, DecodeReg);
376 }
377 
InitFields(void)378 static void InitFields(void)
379 {
380   InstTable = CreateInstTable(97);
381 
382   InstrZ = 0;
383   FixedOrders = (FixedOrder*) malloc(sizeof(FixedOrder) * FixedOrderCnt);
384   AddFixed("CLRC"  , 0x2c000);
385   AddFixed("SETC"  , 0x2c001);
386   AddFixed("CLRZ"  , 0x2c002);
387   AddFixed("SETZ"  , 0x2c003);
388   AddFixed("CLRI"  , 0x2c004);
389   AddFixed("SETI"  , 0x2c005);
390   if (MomCPU == CPUMico8_05)
391   {
392     AddFixed("RET"   , 0x3a000);
393     AddFixed("IRET"  , 0x3a001);
394   }
395   else if (MomCPU == CPUMico8_V3)
396   {
397     AddFixed("RET"   , 0x38000);
398     AddFixed("IRET"  , 0x39000);
399   }
400   else if (MomCPU == CPUMico8_V31)
401   {
402     AddFixed("RET"   , 0x39000);
403     AddFixed("IRET"  , 0x3a000);
404   }
405   AddFixed("NOP"   , 0x10000);
406 
407   InstrZ = 0;
408   ALUOrders = (ALUOrder*) malloc(sizeof(ALUOrder) * ALUOrderCnt);
409   AddALU("ADD"    , "ADDI"  ,   2UL << 14);
410   AddALU("ADDC"   , "ADDIC" ,   3UL << 14);
411   AddALU("SUB"    , "SUBI"  ,   0UL << 14);
412   AddALU("SUBC"   , "SUBIC" ,   1UL << 14);
413   AddALU("MOV"    , "MOVI"  ,   4UL << 14);
414   AddALU("AND"    , "ANDI"  ,   5UL << 14);
415   AddALU("OR"     , "ORI"   ,   6UL << 14);
416   AddALU("XOR"    , "XORI"  ,   7UL << 14);
417   AddALU("CMP"    , "CMPI"  ,   8UL << 14);
418   AddALU("TEST"   , "TESTI" ,   9UL << 14);
419   AddALU("ROR"    , NULL    , (10UL << 14) | 0); /* Note: The User guide (Feb '08) differs  */
420   AddALU("ROL"    , NULL    , (10UL << 14) | 1); /* from the actual implementation in */
421   AddALU("RORC"   , NULL    , (10UL << 14) | 2); /* decoding the last 3 bits of the Rotate */
422   AddALU("ROLC"   , NULL    , (10UL << 14) | 3); /* instructions. These values are correct. */
423 
424   InstrZ = 0;
425   RegOrders = (FixedOrder*) malloc(sizeof(FixedOrder) * RegOrderCnt);
426   AddReg("INC"    , (2UL << 14)  | (1UL << 13) | 1);
427   AddReg("DEC"    , (0UL << 14)  | (1UL << 13) | 1);
428 
429   InstrZ = 0;
430   ShortBranchOrders = (FixedOrder*) malloc(sizeof(FixedOrder) * ShortBranchOrderCnt);
431   if (MomCPU != CPUMico8_V31)
432   {
433     AddShortBranch("BZ"    , 0x32000);
434     AddShortBranch("BNZ"   , 0x32400);
435     AddShortBranch("BC"    , 0x32800);
436     AddShortBranch("BNC"   , 0x32c00);
437     AddShortBranch("CALLZ" , 0x36000);
438     AddShortBranch("CALLNZ", 0x36400);
439     AddShortBranch("CALLC" , 0x36800);
440     AddShortBranch("CALLNC", 0x36c00);
441   }
442 
443   /* AcQ/MA: a group for unconditional branches, which can support
444    *         larger branches then the conditional branches (not supported
445    *         in the earliest versions of the Mico8 processor). The branch
446    *         range is +2047 to -2048 instead of +511 to -512. */
447   InstrZ = 0;
448   LongBranchOrders = (FixedOrder*) malloc(sizeof(FixedOrder) * LongBranchOrderCnt);
449   if (MomCPU != CPUMico8_05)
450   {
451     if (MomCPU == CPUMico8_V31)
452     {
453       AddLongBranch("BZ"    , 0x30000);
454       AddLongBranch("BNZ"   , 0x31000);
455       AddLongBranch("BC"    , 0x32000);
456       AddLongBranch("BNC"   , 0x33000);
457       AddLongBranch("CALLZ" , 0x34000);
458       AddLongBranch("CALLNZ", 0x35000);
459       AddLongBranch("CALLC" , 0x36000);
460       AddLongBranch("CALLNC", 0x37000);
461       AddLongBranch("CALL"  , 0x38000);
462       AddLongBranch("B"     , 0x3b000);
463     }
464     else
465     {
466       AddLongBranch("B"     , 0x33000);
467       AddLongBranch("CALL"  , 0x37000);
468     }
469   }
470 
471   InstrZ = 0;
472   MemOrders = (MemOrder*) malloc(sizeof(MemOrder) * MemOrderCnt);
473   if (MomCPU == CPUMico8_V31)
474   {
475     AddMem("INP"    , "INPI"   , (23UL << 13) | 1, SegIO);
476     AddMem("IMPORT" , "IMPORTI", (23UL << 13) | 1, SegIO);
477     AddMem("OUTP"   , "OUTPI"  , (23UL << 13) | 0, SegIO);
478     AddMem("EXPORT" , "EXPORTI", (23UL << 13) | 0, SegIO);
479     AddMem("LSP"    , "LSPI"   , (23UL << 13) | 5, SegData);
480     AddMem("SSP"    , "SSPI"   , (23UL << 13) | 4, SegData);
481   }
482   else
483   {
484     if (MomCPU == CPUMico8_V3)
485     {
486       AddMem("INP"    , "INPI"   , (15UL << 14) | 1, SegIO);
487       AddMem("OUTP"   , "OUTPI"  , (15UL << 14) | 0, SegIO);
488     }
489     AddMem("IMPORT" , "IMPORTI", (15UL << 14) | 1, SegIO);
490     AddMem("EXPORT" , "EXPORTI", (15UL << 14) | 0, SegIO);
491     AddMem("LSP"    , "LSPI"   , (15UL << 14) | 5, SegData);
492     AddMem("SSP"    , "SSPI"   , (15UL << 14) | 4, SegData);
493   }
494 
495   AddInstTable(InstTable, "REG", 0, CodeREG);
496   AddInstTable(InstTable, "PORT", 0, DecodePort);
497 }
498 
DeinitFields(void)499 static void DeinitFields(void)
500 {
501   DestroyInstTable(InstTable);
502   free(FixedOrders);
503   free(ALUOrders);
504   free(LongBranchOrders);
505   free(ShortBranchOrders);
506   free(MemOrders);
507   free(RegOrders);
508 }
509 
510 /*--------------------------------------------------------------------------
511  * Semipublic Functions
512  *--------------------------------------------------------------------------*/
513 
514 /*!------------------------------------------------------------------------
515  * \fn     InternSymbol_Mico8(char *pArg, TempResult *pResult)
516  * \brief  handle built-in (register) symbols for MICO8
517  * \param  pArg source argument
518  * \param  pResult result buffer
519  * ------------------------------------------------------------------------ */
520 
InternSymbol_Mico8(char * pArg,TempResult * pResult)521 static void InternSymbol_Mico8(char *pArg, TempResult *pResult)
522 {
523   LongWord RegNum;
524 
525   if (IsWRegCore(pArg, &RegNum))
526   {
527     pResult->Typ = TempReg;
528     pResult->DataSize = eSymbolSize8Bit;
529     pResult->Contents.RegDescr.Reg = RegNum;
530     pResult->Contents.RegDescr.Dissect = DissectReg_Mico8;
531   }
532 }
533 
IsDef_Mico8(void)534 static Boolean IsDef_Mico8(void)
535 {
536    return (Memo("REG")) || (Memo("PORT"));
537 }
538 
SwitchFrom_Mico8(void)539 static void SwitchFrom_Mico8(void)
540 {
541    DeinitFields();
542 }
543 
MakeCode_Mico8(void)544 static void MakeCode_Mico8(void)
545 {
546   CodeLen = 0; DontPrint = False;
547 
548   /* zu ignorierendes */
549 
550    if (Memo("")) return;
551 
552    /* Pseudoanweisungen */
553 
554    if (DecodeIntelPseudo(True)) return;
555 
556    if (!LookupInstTable(InstTable, OpPart.Str))
557      WrStrErrorPos(ErrNum_UnknownInstruction, &OpPart);
558 }
559 
SwitchTo_Mico8(void)560 static void SwitchTo_Mico8(void)
561 {
562    PFamilyDescr FoundDescr;
563 
564    FoundDescr = FindFamilyByName("Mico8");
565 
566    TurnWords = True; ConstMode = ConstModeC;
567 
568    PCSymbol = "$"; HeaderID = FoundDescr->Id;
569 
570    /* NOP = mov R0,R0 */
571 
572    NOPCode = 0x10000;
573    DivideChars = ","; HasAttrs = False;
574 
575    ValidSegs = (1 << SegCode) | (1 << SegData) | (1 << SegXData) | (1 << SegIO);
576    Grans[SegCode] = 4; ListGrans[SegCode] = 4; SegInits[SegCode] = 0;
577    SegLimits[SegCode] = IntTypeDefs[CodeAddrInt].Max;
578    Grans[SegData] = 1; ListGrans[SegData] = 1; SegInits[SegData] = 0;
579    SegLimits[SegData] = IntTypeDefs[DataAddrInt].Max;
580    Grans[SegXData] = 1; ListGrans[SegXData] = 1; SegInits[SegXData] = 0;
581    SegLimits[SegXData] = 0xff;
582    Grans[SegIO] = 1; ListGrans[SegIO] = 1; SegInits[SegIO] = 0;
583    SegLimits[SegIO] = 0xff;
584 
585    MakeCode = MakeCode_Mico8;
586    IsDef = IsDef_Mico8;
587    InternSymbol = InternSymbol_Mico8;
588    DissectReg = DissectReg_Mico8;
589    SwitchFrom = SwitchFrom_Mico8; InitFields();
590 }
591 
592 /*--------------------------------------------------------------------------
593  * Initialization
594  *--------------------------------------------------------------------------*/
595 
codemico8_init(void)596 void codemico8_init(void)
597 {
598    CPUMico8_05  = AddCPU("Mico8_05" , SwitchTo_Mico8);
599    CPUMico8_V3  = AddCPU("Mico8_V3" , SwitchTo_Mico8);
600    CPUMico8_V31 = AddCPU("Mico8_V31", SwitchTo_Mico8);
601 }
602