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