Subversion Repositories pentevo

Rev

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

  1. /* code4004.c */
  2. /*****************************************************************************/
  3. /* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only                     */
  4. /*                                                                           */
  5. /* AS-Portierung                                                             */
  6. /*                                                                           */
  7. /* Codegenerator Intel 4004                                                  */
  8. /*                                                                           */
  9. /*****************************************************************************/
  10.  
  11. #include "stdinc.h"
  12. #include <ctype.h>
  13. #include <string.h>
  14.  
  15. #include "bpemu.h"
  16. #include "strutil.h"
  17. #include "asmdef.h"
  18. #include "asmsub.h"
  19. #include "asmpars.h"
  20. #include "asmitree.h"
  21. #include "asmallg.h"
  22. #include "codevars.h"
  23. #include "headids.h"
  24. #include "fourpseudo.h"
  25. #include "errmsg.h"
  26.  
  27. #include "code4004.h"
  28.  
  29. /*---------------------------------------------------------------------------*/
  30. /* Variablen */
  31.  
  32. static CPUVar CPU4004, CPU4040;
  33.  
  34. /*---------------------------------------------------------------------------*/
  35. /* Parser */
  36.  
  37. /*!------------------------------------------------------------------------
  38.  * \fn     RegVal(const char *pInp, int l)
  39.  * \brief  decode numeric part of register name - either single hex digit or two dec digits
  40.  * \param  pInp numberic value from argument
  41.  * \param  length of numberic value from argument
  42.  * \return register number or 0xff if invalid
  43.  * ------------------------------------------------------------------------ */
  44.  
  45. static Byte RegVal(const char *pInp, int l)
  46. {
  47.   switch (l)
  48.   {
  49.     case 1:
  50.     {
  51.       char ch = as_toupper(*pInp);
  52.       if ((ch >='0') && (ch <= '9'))
  53.         return ch - '0';
  54.       else if ((ch >='A') && (ch <= 'F'))
  55.         return ch - 'A' + 10;
  56.       else
  57.         return 0xff;
  58.     }
  59.     case 2:
  60.     {
  61.       unsigned Acc = 0, z;
  62.  
  63.       for (z = 0; z < 2; z++)
  64.       {
  65.         if (!isdigit(pInp[z]))
  66.           return 0xff;
  67.         Acc = (Acc * 10) + (pInp[z] - '0');
  68.       }
  69.       return (Acc <= 15) ? Acc : 0xff;
  70.     }
  71.     default:
  72.       return 0xff;
  73.   }
  74. }
  75.  
  76. /*!------------------------------------------------------------------------
  77.  * \fn     DecodeRegCore(const char *pArg, Byte *pValue, int l)
  78.  * \brief  decode 4 bit register
  79.  * \param  pArg potential register argument
  80.  * \param  pValue register # if it's a register
  81.  * \param  l length of argument
  82.  * \return True if it's a register
  83.  * ------------------------------------------------------------------------ */
  84.  
  85. static Boolean DecodeRegCore(const char *pAsc, Byte *pErg, int l)
  86. {
  87.   if ((l < 2) || (l > 3) || (as_toupper(*pAsc) != 'R'))
  88.     return False;
  89.  
  90.   *pErg = RegVal(pAsc + 1, l - 1);
  91.   return (*pErg != 0xff);
  92. }
  93.  
  94. /*!------------------------------------------------------------------------
  95.  * \fn     DecodeRRegCore(const char *pArg, Byte *pValue)
  96.  * \brief  decode 8 bit register pair
  97.  * \param  pArg ASCII argument of potential register
  98.  * \param  pValue register # if it's a register
  99.  * \return True if it's a register
  100.  * ------------------------------------------------------------------------ */
  101.  
  102. static Boolean DecodeRRegCore(const char *pArg, Byte *pValue)
  103. {
  104.   Byte UpperValue;
  105.   const char *pPair;
  106.   int l;
  107.  
  108.   l = strlen(pArg);
  109.  
  110.   /* syntax RnP: */
  111.  
  112.   if ((l >= 3) && (l <= 4)
  113.    && (as_toupper(pArg[l -1]) == 'P')
  114.    && DecodeRegCore(pArg, pValue, l - 1))
  115.   {
  116.     if (*pValue > 7)
  117.       return False;
  118.     *pValue <<= 1;
  119.     return True;
  120.   }
  121.  
  122.   /* syntax RnRn+1 */
  123.  
  124.   if ((l < 4) || (l > 6) || (as_toupper(*pArg) != 'R'))
  125.     return False;
  126.  
  127.   for (pPair = pArg + 1; *pPair; pPair++)
  128.     if (as_toupper(*pPair) == 'R')
  129.       break;
  130.   if ((!*pPair) || (pPair - pArg < 2) || (pPair - pArg >= l - 1))
  131.     return False;
  132.  
  133.   *pValue = RegVal(pArg + 1, pPair - pArg - 1);
  134.   UpperValue = RegVal(pPair + 1, l - (pPair - pArg + 1));
  135.   return (*pValue != 0xff) && (UpperValue != 0xff) && Odd(UpperValue) && (*pValue + 1 == UpperValue);
  136. }
  137.  
  138. /*!------------------------------------------------------------------------
  139.  * \fn     DissectReg_4004(char *pDest, size_t DestSize, tRegInt Value, tSymbolSize InpSize)
  140.  * \brief  dissect register symbols - 4004 variant
  141.  * \param  pDest destination buffer
  142.  * \param  DestSize destination buffer size
  143.  * \param  Value numeric register value
  144.  * \param  InpSize register size
  145.  * ------------------------------------------------------------------------ */
  146.  
  147. static void DissectReg_4004(char *pDest, size_t DestSize, tRegInt Value, tSymbolSize InpSize)
  148. {
  149.   switch (InpSize)
  150.   {
  151.     case eSymbolSize8Bit:
  152.       as_snprintf(pDest, DestSize, "R%u", (unsigned)Value);
  153.       break;
  154.     case eSymbolSize16Bit:
  155.       as_snprintf(pDest, DestSize, "R%uP", (unsigned)(Value >> 1));
  156.       break;
  157.     default:
  158.       as_snprintf(pDest, DestSize, "%d-%u", (int)InpSize, (unsigned)Value);
  159.   }
  160. }
  161.  
  162. /*!------------------------------------------------------------------------
  163.  * \fn     DecodeReg(const tStrComp *pArg, Byte *pValue)
  164.  * \brief  decode 4 bit register, including register aliases
  165.  * \param  pArg potential register argument
  166.  * \param  pValue register # if it's a register
  167.  * \return True if it's a register
  168.  * ------------------------------------------------------------------------ */
  169.  
  170. static Boolean DecodeReg(const tStrComp *pArg, Byte *pValue)
  171. {
  172.   tRegDescr RegDescr;
  173.   tEvalResult EvalResult;
  174.   tRegEvalResult RegEvalResult;
  175.  
  176.   if (DecodeRegCore(pArg->str.p_str, pValue, strlen(pArg->str.p_str)))
  177.     return True;
  178.  
  179.   RegEvalResult = EvalStrRegExpressionAsOperand(pArg, &RegDescr, &EvalResult, eSymbolSize8Bit, True);
  180.   *pValue = RegDescr.Reg;
  181.   return (RegEvalResult == eIsReg);
  182. }
  183.  
  184. /*!------------------------------------------------------------------------
  185.  * \fn     DecodeRReg(const tStrComp *pArg, Byte *pValue)
  186.  * \brief  decode 8 bit register pair, including register aliases
  187.  * \param  pArg potential register argument
  188.  * \param  pValue register # if it's a register
  189.  * \return True if it's a register
  190.  * ------------------------------------------------------------------------ */
  191.  
  192. static Boolean DecodeRReg(const tStrComp *pArg, Byte *pValue)
  193. {
  194.   tRegDescr RegDescr;
  195.   tEvalResult EvalResult;
  196.   tRegEvalResult RegEvalResult;
  197.  
  198.   if (DecodeRRegCore(pArg->str.p_str, pValue))
  199.     return True;
  200.  
  201.   RegEvalResult = EvalStrRegExpressionAsOperand(pArg, &RegDescr, &EvalResult, eSymbolSize16Bit, True);
  202.   *pValue = RegDescr.Reg;
  203.   return (RegEvalResult == eIsReg);
  204. }
  205.  
  206. /*---------------------------------------------------------------------------*/
  207. /* Hilfsdekoder */
  208.  
  209. static void DecodeFixed(Word Code)
  210. {
  211.   CPUVar MinCPU = CPU4004 + (CPUVar)Hi(Code);
  212.  
  213.   if (ChkArgCnt(0, 0)
  214.    && ChkMinCPU(MinCPU))
  215.   {
  216.     BAsmCode[0] = Lo(Code);
  217.     CodeLen = 1;
  218.   }
  219. }
  220.  
  221. static void DecodeOneReg(Word Code)
  222. {
  223.   Byte Erg;
  224.  
  225.   if (!ChkArgCnt(1, 1));
  226.   else if (DecodeReg(&ArgStr[1], &Erg))
  227.   {
  228.     BAsmCode[0] = Lo(Code) + Erg;
  229.     CodeLen = 1;
  230.   }
  231. }
  232.  
  233. static void DecodeOneRReg(Word Code)
  234. {
  235.   Byte Erg;
  236.  
  237.   if (!ChkArgCnt(1, 1));
  238.   else if (DecodeRReg(&ArgStr[1], &Erg))
  239.   {
  240.     BAsmCode[0] = Lo(Code) + Erg;
  241.     CodeLen = 1;
  242.   }
  243. }
  244.  
  245. static void DecodeAccReg(Word Code)
  246. {
  247.   Byte Erg;
  248.  
  249.   if (!ChkArgCnt(1, 2));
  250.   else if ((ArgCnt == 2) && (as_strcasecmp(ArgStr[1].str.p_str, "A"))) WrError(ErrNum_InvAddrMode);
  251.   else if (DecodeReg(&ArgStr[ArgCnt], &Erg))
  252.   {
  253.     BAsmCode[0] = Lo(Code) + Erg;
  254.     CodeLen = 1;
  255.   }
  256. }
  257.  
  258. static void DecodeImm4(Word Code)
  259. {
  260.   Boolean OK;
  261.  
  262.   if (ChkArgCnt(1, 1))
  263.   {
  264.     BAsmCode[0] = EvalStrIntExpression(&ArgStr[1], UInt4, &OK);
  265.     if (OK)
  266.     {
  267.       BAsmCode[0] += Lo(Code);
  268.       CodeLen = 1;
  269.     }
  270.   }
  271. }
  272.  
  273. static void DecodeFullJmp(Word Index)
  274. {
  275.   Word Adr;
  276.   Boolean OK;
  277.  
  278.   if (ChkArgCnt(1, 1))
  279.   {
  280.     Adr = EvalStrIntExpression(&ArgStr[1], UInt12, &OK);
  281.     if (OK)
  282.     {
  283.       BAsmCode[0] = 0x40 + (Index << 4) + Hi(Adr);
  284.       BAsmCode[1] = Lo(Adr);
  285.       CodeLen = 2;
  286.     }
  287.   }
  288. }
  289.  
  290. static void DecodeISZ(Word Index)
  291. {
  292.   Word Adr;
  293.   Boolean OK;
  294.   tSymbolFlags Flags;
  295.   Byte Erg;
  296.   UNUSED(Index);
  297.  
  298.   if (!ChkArgCnt(2, 2));
  299.   else if (DecodeReg(&ArgStr[1], &Erg))
  300.   {
  301.     Adr = EvalStrIntExpressionWithFlags(&ArgStr[2], UInt12, &OK, &Flags);
  302.     if (OK && ChkSamePage(EProgCounter() + 1, Adr, 8, Flags))
  303.     {
  304.       BAsmCode[0] = 0x70 + Erg;
  305.       BAsmCode[1] = Lo(Adr);
  306.       CodeLen = 2;
  307.     }
  308.   }
  309. }
  310.  
  311. static void DecodeJCN(Word Index)
  312. {
  313.   UNUSED(Index);
  314.  
  315.   if (ChkArgCnt(2, 2))
  316.   {
  317.     Boolean OK = True;
  318.     char *pCond;
  319.  
  320.     BAsmCode[0] = 0;
  321.     for (pCond = ArgStr[1].str.p_str; *pCond; pCond++)
  322.       switch (as_toupper(*pCond))
  323.       {
  324.         case 'Z': BAsmCode[0] |= 4; break;
  325.         case 'C': BAsmCode[0] |= 2; break;
  326.         case 'T': BAsmCode[0] |= 1; break;
  327.         case 'N': BAsmCode[0] |= 8; break;
  328.         default: OK = False;
  329.       }
  330.     if (!OK)
  331.       BAsmCode[0] = EvalStrIntExpression(&ArgStr[1], UInt4, &OK);
  332.  
  333.     if (OK)
  334.     {
  335.       Word AdrInt;
  336.       tSymbolFlags Flags;
  337.  
  338.       AdrInt = EvalStrIntExpressionWithFlags(&ArgStr[2], UInt12, &OK, &Flags);
  339.       if (OK)
  340.       {
  341.         if (!mSymbolQuestionable(Flags) && (Hi(EProgCounter() + 2) != Hi(AdrInt))) WrError(ErrNum_JmpDistTooBig);
  342.         else
  343.         {
  344.           BAsmCode[0] |= 0x10;
  345.           BAsmCode[1] = Lo(AdrInt);
  346.           CodeLen = 2;
  347.         }
  348.       }
  349.     }
  350.   }
  351. }
  352.  
  353. static void DecodeFIM(Word Index)
  354. {
  355.   Boolean OK;
  356.   UNUSED(Index);
  357.  
  358.   if (!ChkArgCnt(2, 2));
  359.   else if (DecodeRReg(&ArgStr[1], BAsmCode))
  360.   {
  361.     BAsmCode[1] = EvalStrIntExpression(&ArgStr[2], Int8, &OK);
  362.     if (OK)
  363.     {
  364.       BAsmCode[0] |= 0x20;
  365.       CodeLen = 2;
  366.     }
  367.   }
  368. }
  369.  
  370. static void DecodeDATA_4004(Word Code)
  371. {
  372.   UNUSED(Code);
  373.  
  374.   DecodeDATA(Int8, Int4);
  375. }
  376.  
  377. /*---------------------------------------------------------------------------*/
  378. /* Codetabellenverwaltung */
  379.  
  380. static void AddFixed(const char *NName, Word NCode, CPUVar NMin)
  381. {
  382.   NCode |= ((Word)(NMin - CPU4004)) << 8;
  383.   AddInstTable(InstTable, NName, NCode, DecodeFixed);
  384. }
  385.  
  386. static void AddOneReg(const char *NName, Byte NCode)
  387. {
  388.   AddInstTable(InstTable, NName, NCode, DecodeOneReg);
  389. }
  390.  
  391. static void AddOneRReg(const char *NName, Byte NCode)
  392. {
  393.   AddInstTable(InstTable, NName, NCode, DecodeOneRReg);
  394. }
  395.  
  396. static void AddAccReg(const char *NName, Byte NCode)
  397. {
  398.   AddInstTable(InstTable, NName, NCode, DecodeAccReg);
  399. }
  400.  
  401. static void AddImm4(const char *NName, Byte NCode)
  402. {
  403.   AddInstTable(InstTable, NName, NCode, DecodeImm4);
  404. }
  405.  
  406. static void InitFields(void)
  407. {
  408.   InstTable = CreateInstTable(101);
  409.  
  410.   AddFixed("NOP" , 0x00, CPU4004); AddFixed("WRM" , 0xe0, CPU4004);
  411.   AddFixed("WMP" , 0xe1, CPU4004); AddFixed("WRR" , 0xe2, CPU4004);
  412.   AddFixed("WPM" , 0xe3, CPU4004); AddFixed("WR0" , 0xe4, CPU4004);
  413.   AddFixed("WR1" , 0xe5, CPU4004); AddFixed("WR2" , 0xe6, CPU4004);
  414.   AddFixed("WR3" , 0xe7, CPU4004); AddFixed("SBM" , 0xe8, CPU4004);
  415.   AddFixed("RDM" , 0xe9, CPU4004); AddFixed("RDR" , 0xea, CPU4004);
  416.   AddFixed("ADM" , 0xeb, CPU4004); AddFixed("RD0" , 0xec, CPU4004);
  417.   AddFixed("RD1" , 0xed, CPU4004); AddFixed("RD2" , 0xee, CPU4004);
  418.   AddFixed("RD3" , 0xef, CPU4004); AddFixed("CLB" , 0xf0, CPU4004);
  419.   AddFixed("CLC" , 0xf1, CPU4004); AddFixed("IAC" , 0xf2, CPU4004);
  420.   AddFixed("CMC" , 0xf3, CPU4004); AddFixed("CMA" , 0xf4, CPU4004);
  421.   AddFixed("RAL" , 0xf5, CPU4004); AddFixed("RAR" , 0xf6, CPU4004);
  422.   AddFixed("TCC" , 0xf7, CPU4004); AddFixed("DAC" , 0xf8, CPU4004);
  423.   AddFixed("TCS" , 0xf9, CPU4004); AddFixed("STC" , 0xfa, CPU4004);
  424.   AddFixed("DAA" , 0xfb, CPU4004); AddFixed("KBP" , 0xfc, CPU4004);
  425.   AddFixed("DCL" , 0xfd, CPU4004); AddFixed("AD0" , 0xec, CPU4004);
  426.   AddFixed("AD1" , 0xed, CPU4004); AddFixed("AD2" , 0xee, CPU4004);
  427.   AddFixed("AD3" , 0xef, CPU4004);
  428.  
  429.   AddFixed("HLT" , 0x01, CPU4040); AddFixed("BBS" , 0x02, CPU4040);
  430.   AddFixed("LCR" , 0x03, CPU4040); AddFixed("OR4" , 0x04, CPU4040);
  431.   AddFixed("OR5" , 0x05, CPU4040); AddFixed("AN6" , 0x06, CPU4040);
  432.   AddFixed("AN7" , 0x07, CPU4040); AddFixed("DB0" , 0x08, CPU4040);
  433.   AddFixed("DB1" , 0x09, CPU4040); AddFixed("SB0" , 0x0a, CPU4040);
  434.   AddFixed("SB1" , 0x0b, CPU4040); AddFixed("EIN" , 0x0c, CPU4040);
  435.   AddFixed("DIN" , 0x0d, CPU4040); AddFixed("RPM" , 0x0e, CPU4040);
  436.  
  437.   AddOneReg("INC" , 0x60);
  438.  
  439.   AddOneRReg("SRC" , 0x21);
  440.   AddOneRReg("FIN" , 0x30);
  441.   AddOneRReg("JIN" , 0x31);
  442.  
  443.   AddAccReg("ADD" , 0x80); AddAccReg("SUB" , 0x90);
  444.   AddAccReg("LD"  , 0xa0); AddAccReg("XCH" , 0xb0);
  445.  
  446.   AddImm4("BBL" , 0xc0); AddImm4("LDM" , 0xd0);
  447.  
  448.   AddInstTable(InstTable,"JCN", 0, DecodeJCN);
  449.   AddInstTable(InstTable,"JCM", 0, DecodeJCN);
  450.   AddInstTable(InstTable,"JUN", 0, DecodeFullJmp);
  451.   AddInstTable(InstTable,"JMS", 1, DecodeFullJmp);
  452.   AddInstTable(InstTable,"ISZ", 0, DecodeISZ);
  453.   AddInstTable(InstTable,"FIM", 0, DecodeFIM);
  454.  
  455.   AddInstTable(InstTable, "DS", 0, DecodeRES);
  456.   AddInstTable(InstTable, "DATA", 0, DecodeDATA_4004);
  457.   AddInstTable(InstTable, "REG", 0, CodeREG);
  458. }
  459.  
  460. static void DeinitFields(void)
  461. {
  462.   DestroyInstTable(InstTable);
  463. }
  464.  
  465. /*---------------------------------------------------------------------------*/
  466. /* Callbacks */
  467.  
  468. /*!------------------------------------------------------------------------
  469.  * \fn     InternSymbol_4004
  470.  * \brief  Built-in symbols for 4004
  471.  * \param  pArg source argument
  472.  * \param  pResult buffer for result
  473.  * ------------------------------------------------------------------------ */
  474.  
  475. static void InternSymbol_4004(char *pArg, TempResult *pResult)
  476. {
  477.   Byte RegValue;
  478.  
  479.   if (DecodeRegCore(pArg, &RegValue, strlen(pArg)))
  480.   {
  481.     pResult->Typ = TempReg;
  482.     pResult->DataSize = eSymbolSize8Bit;
  483.     pResult->Contents.RegDescr.Reg = RegValue;
  484.     pResult->Contents.RegDescr.Dissect = DissectReg_4004;
  485.     pResult->Contents.RegDescr.compare = NULL;
  486.   }
  487.   else if (DecodeRRegCore(pArg, &RegValue))
  488.   {
  489.     pResult->Typ = TempReg;
  490.     pResult->DataSize = eSymbolSize16Bit;
  491.     pResult->Contents.RegDescr.Reg = RegValue;
  492.     pResult->Contents.RegDescr.Dissect = DissectReg_4004;
  493.     pResult->Contents.RegDescr.compare = NULL;
  494.   }
  495. }
  496.  
  497. static void MakeCode_4004(void)
  498. {
  499.   CodeLen = 0;
  500.   DontPrint = False;
  501.  
  502.   /* zu ignorierendes */
  503.  
  504.   if (Memo(""))
  505.     return;
  506.  
  507.   if (!LookupInstTable(InstTable, OpPart.str.p_str))
  508.     WrStrErrorPos(ErrNum_UnknownInstruction, &OpPart);
  509. }
  510.  
  511. static Boolean IsDef_4004(void)
  512. {
  513.   return Memo("REG");
  514. }
  515.  
  516. static void SwitchFrom_4004(void)
  517. {
  518.   DeinitFields();
  519. }
  520.  
  521. static void SwitchTo_4004(void)
  522. {
  523.   const TFamilyDescr *FoundDescr;
  524.  
  525.   FoundDescr = FindFamilyByName("4004/4040");
  526.  
  527.   TurnWords = False;
  528.   SetIntConstMode(eIntConstModeIntel);
  529.  
  530.   PCSymbol = "$";
  531.   HeaderID = FoundDescr->Id;
  532.   NOPCode = 0x00;
  533.   DivideChars = ",";
  534.   HasAttrs = False;
  535.  
  536.   ValidSegs = (1 << SegCode) | (1 << SegData);
  537.   Grans[SegCode ] = 1; ListGrans[SegCode ] = 1; SegInits[SegCode ] = 0;
  538.   SegLimits[SegCode] = 0xfff;
  539.   Grans[SegData ] = 1; ListGrans[SegData ] = 1; SegInits[SegData ] = 0;
  540.   SegLimits[SegData] = 0xff;
  541.  
  542.   MakeCode = MakeCode_4004;
  543.   IsDef = IsDef_4004;
  544.   InternSymbol = InternSymbol_4004;
  545.   DissectReg = DissectReg_4004;
  546.   SwitchFrom = SwitchFrom_4004;
  547.  
  548.   InitFields();
  549. }
  550.  
  551. /*---------------------------------------------------------------------------*/
  552. /* Initialisierung */
  553.  
  554. void code4004_init(void)
  555. {
  556.   CPU4004 = AddCPU("4004", SwitchTo_4004);
  557.   CPU4040 = AddCPU("4040", SwitchTo_4004);
  558. }
  559.