Subversion Repositories pentevo

Rev

Blame | Last modification | View Log | Download | RSS feed | ?url?

  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. }
  579.