Subversion Repositories pentevo

Rev

Details | Last modification | View Log | RSS feed

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