Subversion Repositories pentevo

Rev

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

  1. /* codescmp.c */
  2. /*****************************************************************************/
  3. /* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only                     */
  4. /*                                                                           */
  5. /* AS-Portierung                                                             */
  6. /*                                                                           */
  7. /* Codegenerator National SC/MP                                              */
  8. /*                                                                           */
  9. /*****************************************************************************/
  10.  
  11. #include "stdinc.h"
  12. #include <ctype.h>
  13. #include <string.h>
  14.  
  15. #include "nls.h"
  16. #include "strutil.h"
  17. #include "chunks.h"
  18. #include "asmdef.h"
  19. #include "asmsub.h"
  20. #include "asmpars.h"
  21. #include "asmitree.h"
  22. #include "asmallg.h"
  23. #include "onoff_common.h"
  24. #include "intpseudo.h"
  25. #include "codevars.h"
  26. #include "codepseudo.h"
  27. #include "errmsg.h"
  28.  
  29. #include "codescmp.h"
  30.  
  31. /*---------------------------------------------------------------------------*/
  32.  
  33. #define REG_PC 0
  34. #define REG_E 0x80
  35.  
  36. static CPUVar CPUSCMP;
  37.  
  38. /*---------------------------------------------------------------------------*/
  39.  
  40. /*!------------------------------------------------------------------------
  41.  * \fn     DecodeRegCore(const char *p_arg, tRegInt *p_result, tSymbolSize *p_size)
  42.  * \brief  check whether argument is a CPU register
  43.  * \param  p_arg source argument
  44.  * \param  p_result resulting register #
  45.  * \param  p_size register's size
  46.  * \return True if argument is a register
  47.  * ------------------------------------------------------------------------ */
  48.  
  49. static Boolean DecodeRegCore(const char *p_arg, tRegInt *p_result, tSymbolSize *p_size)
  50. {
  51.   int l = strlen(p_arg);
  52.  
  53.   switch (l)
  54.   {
  55.     case 2:
  56.       if (as_toupper(*p_arg) != 'P')
  57.         return False;
  58.       p_arg++;
  59.       switch (as_toupper(*p_arg))
  60.       {
  61.         case '0':
  62.         case '1':
  63.         case '2':
  64.         case '3':
  65.           *p_result = *p_arg - '0';
  66.           *p_size = eSymbolSize16Bit;
  67.           return True;
  68.         case 'C':
  69.           *p_result = REG_PC | REGSYM_FLAG_ALIAS;
  70.           *p_size = eSymbolSize16Bit;
  71.           return True;
  72.         default:
  73.           break;
  74.       }
  75.       break;
  76.     case 1:
  77.       if (as_toupper(*p_arg) == 'E')
  78.       {
  79.         *p_result = REG_E;
  80.         *p_size = eSymbolSize8Bit;
  81.         return True;
  82.       }
  83.       break;
  84.   }
  85.   return False;
  86. }
  87.  
  88. /*!------------------------------------------------------------------------
  89.  * \fn     DecodeReg(const tStrComp *p_arg, Byte *p_value, tSymbolSize *p_size, tSymbolSize req_size, Boolean must_be_reg)
  90.  * \brief  check whether argument is a CPU register
  91.  * \param  p_arg source argument
  92.  * \param  p_value resulting register # if yes
  93.  * \param  p_size resulting register's size
  94.  * \param  req_size size of requested register
  95.  * \param  must_be_reg is a register argument expected?
  96.  * \return eval result
  97.  * ------------------------------------------------------------------------ */
  98.  
  99. static Boolean ChkRegSize(tSymbolSize req_size, tSymbolSize act_size)
  100. {
  101.   return (req_size == eSymbolSizeUnknown)
  102.       || (req_size == act_size);
  103. }
  104.  
  105. static tRegEvalResult DecodeReg(const tStrComp *p_arg, Byte *p_value, tSymbolSize *p_size, tSymbolSize req_size, Boolean must_be_reg)
  106. {
  107.   tRegDescr reg_descr;
  108.   tEvalResult eval_result;
  109.   tRegEvalResult reg_eval_result;
  110.  
  111.   if (DecodeRegCore(p_arg->str.p_str, &reg_descr.Reg, &eval_result.DataSize))
  112.     reg_eval_result = eIsReg;
  113.   else
  114.     reg_eval_result = EvalStrRegExpressionAsOperand(p_arg, &reg_descr, &eval_result, eSymbolSizeUnknown, must_be_reg);
  115.  
  116.   if (reg_eval_result == eIsReg)
  117.   {
  118.     if (!ChkRegSize(req_size, eval_result.DataSize))
  119.     {
  120.       WrStrErrorPos(ErrNum_InvOpSize, p_arg);
  121.       reg_eval_result = must_be_reg ? eIsNoReg : eRegAbort;
  122.     }
  123.   }
  124.  
  125.   *p_value = reg_descr.Reg;
  126.   if (eval_result.DataSize == eSymbolSize16Bit)
  127.     *p_value &= ~REGSYM_FLAG_ALIAS;
  128.   if (p_size) *p_size = eval_result.DataSize;
  129.   return reg_eval_result;
  130. }
  131.  
  132. /*!------------------------------------------------------------------------
  133.  * \fn     decode_ptr_reg(const tStrComp *p_arg, Byte *p_result)
  134.  * \brief  parse pointer register expression
  135.  * \param  p_arg source argument
  136.  * \param  p_result result buffer
  137.  * \return eIsReg/eRegAbort
  138.  * ------------------------------------------------------------------------ */
  139.  
  140. static tRegEvalResult decode_ptr_reg(const tStrComp *p_arg, Byte *p_result)
  141. {
  142.   tRegEvalResult result = DecodeReg(p_arg, p_result, NULL, eSymbolSize16Bit, False);
  143.  
  144.   /* Pointer register may be named or plain number from 0..3: */
  145.  
  146.   if (eIsNoReg == result)
  147.   {
  148.     Boolean ok;
  149.  
  150.     *p_result = EvalStrIntExpression(p_arg, UInt2, &ok);
  151.     result = ok ? eIsReg : eRegAbort;
  152.   }
  153.  
  154.   return result;
  155. }
  156.  
  157. /*!------------------------------------------------------------------------
  158.  * \fn     DissectReg_SCMP(char *p_dest, size_t dest_dize, tRegInt value, tSymbolSize inp_size)
  159.  * \brief  dissect register symbols - SC/MP variant
  160.  * \param  p_dest destination buffer
  161.  * \param  dest_size destination buffer size
  162.  * \param  value numeric register value
  163.  * \param  inp_size register size
  164.  * ------------------------------------------------------------------------ */
  165.  
  166. static void DissectReg_SCMP(char *p_dest, size_t dest_size, tRegInt value, tSymbolSize inp_size)
  167. {
  168.   switch (inp_size)
  169.   {
  170.     case eSymbolSize8Bit:
  171.       if (value == REG_E)
  172.       {
  173.         strmaxcpy(p_dest, "E", dest_size);
  174.         break;
  175.       }
  176.       else
  177.         goto unknown;
  178.     case eSymbolSize16Bit:
  179.       if (value == (REG_PC | REGSYM_FLAG_ALIAS))
  180.         strmaxcpy(p_dest, "PC", dest_size);
  181.       else
  182.         as_snprintf(p_dest, dest_size, "P%u", (unsigned)value);
  183.       break;
  184.     unknown:
  185.     default:
  186.       as_snprintf(p_dest, dest_size, "%d-%u", (int)inp_size, (unsigned)value);
  187.   }
  188. }
  189.  
  190. /*!------------------------------------------------------------------------
  191.  * \fn     DecodeAdr(const tStrComp *pArg, Boolean MayInc, Byte PCDisp, Byte *Arg)
  192.  * \brief  decode address expression
  193.  * \param  pArg source argument
  194.  * \param  MayInc allow auto-increment?
  195.  * \param  PCDisp additional offset to take into account for PC-relative addressing
  196.  * \param  Arg returns m|ptr for opcode byte
  197.  * \return True if success
  198.  * ------------------------------------------------------------------------ */
  199.  
  200. static Boolean DecodeAdr(const tStrComp *pArg, Boolean MayInc, Byte PCDisp, Byte *Arg)
  201. {
  202.   Word Target;
  203.   Boolean OK;
  204.   int l, SplitPos;
  205.   tSymbolFlags Flags;
  206.   String ArgStr;
  207.   tStrComp ArgCopy;
  208.  
  209.   StrCompMkTemp(&ArgCopy, ArgStr, sizeof(ArgStr));
  210.   StrCompCopy(&ArgCopy, pArg);
  211.   if (((SplitPos = FindDispBaseSplit(ArgCopy.str.p_str, &l)) >= 0) && (l >= 4))
  212.   {
  213.     tStrComp Left, Right;
  214.  
  215.     StrCompSplitRef(&Left, &Right, &ArgCopy, ArgCopy.str.p_str + SplitPos);
  216.     StrCompShorten(&Right, 1);
  217.  
  218.     if (decode_ptr_reg(&Right, Arg) != eIsReg)
  219.       return False;
  220.  
  221.     if (*Left.str.p_str == '@')
  222.     {
  223.       if (!MayInc)
  224.       {
  225.         WrError(ErrNum_InvAddrMode);
  226.         return False;
  227.       }
  228.       StrCompIncRefLeft(&Left, 1);
  229.       *Arg += 4;
  230.     }
  231.     /* Programmer's manual says that 'Auto-indexing requires ..., and a pointer register (other than PC)...' : */
  232.     if (*Arg == (4 | REG_PC))
  233.     {
  234.       WrStrErrorPos(ErrNum_InvReg, &Right);
  235.       return False;
  236.     }
  237.     switch (DecodeReg(&Left, &BAsmCode[1], NULL, eSymbolSize8Bit, False))
  238.     {
  239.       case eIsReg:
  240.         /* 0x80 -> use E register only applies if pointer register is not P0(PC): */
  241.         if (*Arg == REG_PC)
  242.         {
  243.           WrStrErrorPos(ErrNum_InvAddrMode, &Left);
  244.           return False;
  245.         }
  246.         break;
  247.       case eRegAbort:
  248.         return False;
  249.       default:
  250.       {
  251.         tEvalResult result;
  252.         BAsmCode[1] = EvalStrIntExpressionWithResult(&Left, SInt8, &result);
  253.         if (!result.OK)
  254.           return False;
  255.         /* Depending on pointer register, valid range is -128...+127 or -127...+127: */
  256.         if ((*Arg != REG_PC) && (BAsmCode[1] == 0x80) && !mFirstPassUnknownOrQuestionable(result.Flags))
  257.           WrStrErrorPos(ErrNum_MeansE, &Left);
  258.       }
  259.     }
  260.     return True;
  261.   }
  262.  
  263.   /* no carry in PC from bit 11 to 12; additionally handle preincrement */
  264.  
  265.   Target = EvalStrIntExpressionWithFlags(pArg, UInt16, &OK, &Flags);
  266.   if (OK)
  267.   {
  268.     Word PCVal = (EProgCounter() & 0xf000) + ((EProgCounter() + 1 + PCDisp) & 0xfff);
  269.     Word Disp = (Target - PCVal) & 0xfff;
  270.  
  271.     if (mSymbolQuestionable(Flags))
  272.       Target = PCVal;
  273.  
  274.     if (!ChkSamePage(Target, PCVal, 12, Flags));
  275.  
  276.     /* Since the pointer register is P0(PC) in this case, a displacement of 0x80
  277.        (-128) does not signify usage of E register, and can be used at
  278.        this place: */
  279.  
  280.     else if ((Disp > 0x7f) && (Disp < 0xf80)) WrError(ErrNum_DistTooBig);
  281.     else
  282.     {
  283.       BAsmCode[1] = Disp & 0xff;
  284.       *Arg = REG_PC;
  285.       return True;
  286.     }
  287.   }
  288.   return False;
  289. }
  290.  
  291. static void ChkPage(void)
  292. {
  293.   if (((EProgCounter()) & 0xf000) != ((EProgCounter() + CodeLen) & 0xf000))
  294.     WrError(ErrNum_PageCrossing);
  295. }
  296.  
  297. /*---------------------------------------------------------------------------*/
  298.  
  299. static void DecodeFixed(Word Index)
  300. {
  301.   if (ChkArgCnt(0, 0))
  302.   {
  303.     BAsmCode[0] = Index; CodeLen = 1;
  304.   }
  305. }
  306.  
  307. static void DecodeImm(Word Index)
  308. {
  309.   if (ChkArgCnt(1, 1))
  310.   {
  311.     Boolean OK;
  312.  
  313.     BAsmCode[1] = EvalStrIntExpression(&ArgStr[1], Int8, &OK);
  314.     if (OK)
  315.     {
  316.       BAsmCode[0] = Index; CodeLen = 2; ChkPage();
  317.     }
  318.   }
  319. }
  320.  
  321. static void DecodeRegOrder(Word Index)
  322. {
  323.   if (!ChkArgCnt(1, 1));
  324.   else if (decode_ptr_reg(&ArgStr[1], BAsmCode + 0) != eIsReg) WrStrErrorPos(ErrNum_InvReg, &ArgStr[1]);
  325.   else
  326.   {
  327.     BAsmCode[0] |= Index; CodeLen = 1;
  328.   }
  329. }
  330.  
  331. static void DecodeMem(Word Index)
  332. {
  333.   if (ChkArgCnt(1, 1))
  334.   if (DecodeAdr(&ArgStr[1], True, 0, BAsmCode + 0))
  335.   {
  336.     BAsmCode[0] |= Index; CodeLen = 2; ChkPage();
  337.   }
  338. }
  339.  
  340. static void DecodeJmp(Word Index)
  341. {
  342.   if (ChkArgCnt(1, 1))
  343.   if (DecodeAdr(&ArgStr[1], False, 1, BAsmCode + 0))
  344.   {
  345.     BAsmCode[0] |= Index; CodeLen = 2; ChkPage();
  346.   }
  347. }
  348.  
  349. static void DecodeLD(Word Index)
  350. {
  351.   if (ChkArgCnt(1, 1))
  352.   if (DecodeAdr(&ArgStr[1], False, 0, BAsmCode + 0))
  353.   {
  354.     BAsmCode[0] |= Index; CodeLen = 2; ChkPage();
  355.   }
  356. }
  357.  
  358. /*---------------------------------------------------------------------------*/
  359.  
  360. static void AddFixed(const char *NName, Byte NCode)
  361. {
  362.   AddInstTable(InstTable, NName, NCode, DecodeFixed);
  363. }
  364.  
  365. static void AddImm(const char *NName, Byte NCode)
  366. {
  367.   AddInstTable(InstTable, NName, NCode, DecodeImm);
  368. }
  369.  
  370. static void AddReg(const char *NName, Byte NCode)
  371. {
  372.   AddInstTable(InstTable, NName, NCode, DecodeRegOrder);
  373. }
  374.  
  375. static void AddMem(const char *NName, Byte NCode)
  376. {
  377.   AddInstTable(InstTable, NName, NCode, DecodeMem);
  378. }
  379.  
  380. static void AddJmp(const char *NName, Byte NCode)
  381. {
  382.   AddInstTable(InstTable, NName, NCode, DecodeJmp);
  383. }
  384.  
  385. static void InitFields(void)
  386. {
  387.   InstTable = CreateInstTable(201);
  388.  
  389.   AddFixed("LDE" ,0x40); AddFixed("XAE" ,0x01); AddFixed("ANE" ,0x50);
  390.   AddFixed("ORE" ,0x58); AddFixed("XRE" ,0x60); AddFixed("DAE" ,0x68);
  391.   AddFixed("ADE" ,0x70); AddFixed("CAE" ,0x78); AddFixed("SIO" ,0x19);
  392.   AddFixed("SR"  ,0x1c); AddFixed("SRL" ,0x1d); AddFixed("RR"  ,0x1e);
  393.   AddFixed("RRL" ,0x1f); AddFixed("HALT",0x00); AddFixed("CCL" ,0x02);
  394.   AddFixed("SCL" ,0x03); AddFixed("DINT",0x04); AddFixed("IEN" ,0x05);
  395.   AddFixed("CSA" ,0x06); AddFixed("CAS" ,0x07); AddFixed("NOP" ,0x08);
  396.  
  397.   AddImm("LDI" , 0xc4); AddImm("ANI" , 0xd4); AddImm("ORI" , 0xdc);
  398.   AddImm("XRI" , 0xe4); AddImm("DAI" , 0xec); AddImm("ADI" , 0xf4);
  399.   AddImm("CAI" , 0xfc); AddImm("DLY" , 0x8f);
  400.  
  401.   AddReg("XPAL", 0x30); AddReg("XPAH", 0x34); AddReg("XPPC", 0x3c);
  402.  
  403.   AddMem("LD"  , 0xc0); AddMem("ST"  , 0xc8); AddMem("AND" , 0xd0);
  404.   AddMem("OR"  , 0xd8); AddMem("XOR" , 0xe0); AddMem("DAD" , 0xe8);
  405.   AddMem("ADD" , 0xf0); AddMem("CAD" , 0xf8);
  406.  
  407.   AddJmp("JMP" , 0x90); AddJmp("JP"  , 0x94); AddJmp("JZ"  , 0x98);
  408.   AddJmp("JNZ" , 0x9c);
  409.  
  410.   AddInstTable(InstTable, "ILD", 0xa8, DecodeLD);
  411.   AddInstTable(InstTable, "DLD", 0xb8, DecodeLD);
  412.   AddInstTable(InstTable, "REG" , 0, CodeREG);
  413. }
  414.  
  415. static void DeinitFields(void)
  416. {
  417.   DestroyInstTable(InstTable);
  418. }
  419.  
  420. /*---------------------------------------------------------------------------*/
  421.  
  422. /*!------------------------------------------------------------------------
  423.  * \fn     InternSymbol_SCMP(char *pArg, TempResult *pResult)
  424.  * \brief  handle built-in (register) symbols for SC/MP
  425.  * \param  pArg source argument
  426.  * \param  pResult result buffer
  427.  * ------------------------------------------------------------------------ */
  428.  
  429. static void InternSymbol_SCMP(char *pArg, TempResult *pResult)
  430. {
  431.   if (DecodeRegCore(pArg, &pResult->Contents.RegDescr.Reg, &pResult->DataSize))
  432.   {
  433.     pResult->Typ = TempReg;
  434.     pResult->Contents.RegDescr.Dissect = DissectReg_SCMP;
  435.     pResult->Contents.RegDescr.compare = NULL;
  436.   }
  437. }
  438.  
  439. static void MakeCode_SCMP(void)
  440. {
  441.   CodeLen = 0; DontPrint = False;
  442.  
  443.   /* zu ignorierendes */
  444.  
  445.   if (Memo("")) return;
  446.  
  447.   /* Pseudoanweisungen */
  448.  
  449.   if (DecodeIntelPseudo(TargetBigEndian)) return;
  450.  
  451.   if (!LookupInstTable(InstTable, OpPart.str.p_str))
  452.     WrStrErrorPos(ErrNum_UnknownInstruction, &OpPart);
  453. }
  454.  
  455. static Boolean IsDef_SCMP(void)
  456. {
  457.   return Memo("REG");
  458. }
  459.  
  460. static void SwitchTo_SCMP(void)
  461. {
  462.   TurnWords = False;
  463.   SetIntConstMode(eIntConstModeC);
  464.  
  465.   PCSymbol = "$"; HeaderID = 0x6e; NOPCode = 0x08;
  466.   DivideChars = ","; HasAttrs = False;
  467.  
  468.   ValidSegs = 1 << SegCode;
  469.   Grans[SegCode] = 1; ListGrans[SegCode] = 1; SegInits[SegCode] = 0;
  470.   SegLimits[SegCode] = 0xffff;
  471.  
  472.   MakeCode = MakeCode_SCMP; IsDef = IsDef_SCMP;
  473.   SwitchFrom = DeinitFields; InitFields();
  474.  
  475.   onoff_bigendian_add();
  476.  
  477.   QualifyQuote = QualifyQuote_SingleQuoteConstant;
  478.   DissectReg = DissectReg_SCMP;
  479.   InternSymbol = InternSymbol_SCMP;
  480.  
  481.   IntConstModeIBMNoTerm = True;
  482. }
  483.  
  484. void codescmp_init(void)
  485. {
  486.   CPUSCMP = AddCPU("SC/MP", SwitchTo_SCMP);
  487. }
  488.