Subversion Repositories pentevo

Rev

Details | Last modification | View Log | RSS feed

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