Subversion Repositories pentevo

Rev

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

  1. /* codepps4.c */
  2. /*****************************************************************************/
  3. /* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only                     */
  4. /*                                                                           */
  5. /* AS                                                                        */
  6. /*                                                                           */
  7. /* Code Generator Rockwell PPS-4                                             */
  8. /*                                                                           */
  9. /*****************************************************************************/
  10.  
  11. #include "stdinc.h"
  12.  
  13. #include <string.h>
  14. #include <ctype.h>
  15.  
  16. #include "bpemu.h"
  17. #include "asmdef.h"
  18. #include "asmsub.h"
  19. #include "asmpars.h"
  20. #include "headids.h"
  21. #include "asmitree.h"
  22. #include "codevars.h"
  23. #include "asmerr.h"
  24. #include "errmsg.h"
  25. #include "fourpseudo.h"
  26.  
  27. #include "codepps4.h"
  28.  
  29. /*---------------------------------------------------------------------------*/
  30. /* Instruction Decoders */
  31.  
  32. /*!------------------------------------------------------------------------
  33.  * \fn     decode_fixed(Word code)
  34.  * \brief  handle instructions with no argument
  35.  * \param  code machine code
  36.  * ------------------------------------------------------------------------ */
  37.  
  38. static void decode_fixed(Word code)
  39. {
  40.   if (ChkArgCnt(0, 0))
  41.   {
  42.     BAsmCode[0] = code;
  43.     CodeLen = 1;
  44.   }
  45. }
  46.  
  47. /*!------------------------------------------------------------------------
  48.  * \fn     decode_adi(Word code)
  49.  * \brief  handle ADI instruction
  50.  * \param  code machine code
  51.  * ------------------------------------------------------------------------ */
  52.  
  53. static void decode_adi(Word code)
  54. {
  55.   if (ChkArgCnt(1, 1))
  56.   {
  57.     tEvalResult eval_result;
  58.     Byte value = EvalStrIntExpressionWithResult(&ArgStr[1], Int4, &eval_result);
  59.  
  60.     if (eval_result.OK)
  61.     {
  62.       /* I am not 100% sure I have to insert one's complement of the
  63.          value into the instruction.  But this way, it makes most sense: */
  64.  
  65.       if (mFirstPassUnknownOrQuestionable(eval_result.Flags))
  66.         value = 15;
  67.       value = ~value & 15;
  68.       if ((value == 15) || (value == 5))
  69.         WrStrErrorPos(ErrNum_InvArg, &ArgStr[1]);
  70.       else
  71.       {
  72.         BAsmCode[0] = code | value;
  73.         CodeLen = 1;
  74.       }
  75.     }
  76.   }
  77. }
  78.  
  79. /*!------------------------------------------------------------------------
  80.  * \fn     decode_imm_3(Word code)
  81.  * \brief  handle instructions with 3 bit immediate operand
  82.  * \param  code machine code
  83.  * ------------------------------------------------------------------------ */
  84.  
  85. static void decode_imm_3(Word code)
  86. {
  87.   if (ChkArgCnt(1, 1))
  88.   {
  89.     Boolean ok;
  90.  
  91.     BAsmCode[0] = EvalStrIntExpression(&ArgStr[1], UInt3, &ok);
  92.     if (ok)
  93.     {
  94.       BAsmCode[0] = code | (BAsmCode[0] & 0x07);
  95.       CodeLen = 1;
  96.     }
  97.   }
  98. }
  99.  
  100. /*!------------------------------------------------------------------------
  101.  * \fn     decode_imm_4(Word code)
  102.  * \brief  handle instructions with 4 bit immediate operand
  103.  * \param  code machine code
  104.  * ------------------------------------------------------------------------ */
  105.  
  106. static void decode_imm_4(Word code)
  107. {
  108.   if (ChkArgCnt(1, 1))
  109.   {
  110.     Boolean ok;
  111.  
  112.     BAsmCode[0] = EvalStrIntExpression(&ArgStr[1], UInt4, &ok);
  113.     if (ok)
  114.     {
  115.       BAsmCode[0] = code | (BAsmCode[0] & 0x0f);
  116.       CodeLen = 1;
  117.     }
  118.   }
  119. }
  120.  
  121. /*!------------------------------------------------------------------------
  122.  * \fn     decode_imm_8(Word code)
  123.  * \brief  handle instructions with 8 bit immediate operand
  124.  * \param  code machine code
  125.  * ------------------------------------------------------------------------ */
  126.  
  127. static void decode_imm_8(Word code)
  128. {
  129.   if (ChkArgCnt(1, 1))
  130.   {
  131.     Boolean ok;
  132.  
  133.     BAsmCode[1] = EvalStrIntExpression(&ArgStr[1], Int8, &ok);
  134.     if (ok)
  135.     {
  136.       BAsmCode[0] = code;
  137.       CodeLen = 2;
  138.     }
  139.   }
  140. }
  141.  
  142. /*!------------------------------------------------------------------------
  143.  * \fn     decode_t(Word code)
  144.  * \brief  handle T instruction
  145.  * \param  code machine code
  146.  * ------------------------------------------------------------------------ */
  147.  
  148. static void decode_t(Word code)
  149. {
  150.   if (ChkArgCnt(1, 1))
  151.   {
  152.     tEvalResult eval_result;
  153.     Word address = EvalStrIntExpressionWithResult(&ArgStr[1], UInt12, &eval_result);
  154.  
  155.     if (eval_result.OK
  156.      && ChkSamePage(EProgCounter(), address, 6, eval_result.Flags))
  157.     {
  158.       ChkSpace(SegCode, eval_result.AddrSpaceMask);
  159.       BAsmCode[0] = code | (address & 63);
  160.       CodeLen = 1;
  161.     }
  162.   }
  163. }
  164.  
  165. /*!------------------------------------------------------------------------
  166.  * \fn     decode_tm(Word code)
  167.  * \brief  handle TM instruction
  168.  * \param  code machine code
  169.  * ------------------------------------------------------------------------ */
  170.  
  171. static void decode_tm(Word code)
  172. {
  173.   if (ChkArgCnt(1, 1))
  174.   {
  175.     tEvalResult eval_result;
  176.     Word address = EvalStrIntExpressionWithResult(&ArgStr[1], UInt12, &eval_result);
  177.  
  178.     /* A lower address byte fron locations 0xd0...0xff is accessed, with
  179.        bits 11:8 set to 0x1. We check for a correct vector address: */
  180.  
  181.     if (eval_result.OK)
  182.     {
  183.       ChkSpace(SegCode, eval_result.AddrSpaceMask);
  184.       if (mFirstPassUnknownOrQuestionable(eval_result.Flags))
  185.         address = (address & 0x00f) | 0x0d0;
  186.       if (ChkRange(address, 0xd0, 0xff))
  187.       {
  188.         BAsmCode[0] = code | (address & 0x3f);
  189.         CodeLen = 1;
  190.       }
  191.     }
  192.   }
  193. }
  194.  
  195. /*!------------------------------------------------------------------------
  196.  * \fn     decode_tl(Word code)
  197.  * \brief  handle TL instruction
  198.  * \param  code machine code
  199.  * ------------------------------------------------------------------------ */
  200.  
  201. static void decode_tl(Word code)
  202. {
  203.   if (ChkArgCnt(1, 1))
  204.   {
  205.     tEvalResult eval_result;
  206.     Word address = EvalStrIntExpressionWithResult(&ArgStr[1], UInt12, &eval_result);
  207.  
  208.     if (eval_result.OK)
  209.     {
  210.       ChkSpace(SegCode, eval_result.AddrSpaceMask);
  211.       BAsmCode[0] = code | (Hi(address) & 15);
  212.       BAsmCode[1] = Lo(address);
  213.       CodeLen = 2;
  214.     }
  215.   }
  216. }
  217.  
  218. /*!------------------------------------------------------------------------
  219.  * \fn     decode_tml(Word code)
  220.  * \brief  handle TML instruction
  221.  * \param  code machine code
  222.  * ------------------------------------------------------------------------ */
  223.  
  224. static void decode_tml(Word code)
  225. {
  226.   if (ChkArgCnt(1, 1))
  227.   {
  228.     tEvalResult eval_result;
  229.     Word address = EvalStrIntExpressionWithResult(&ArgStr[1], UInt12, &eval_result);
  230.  
  231.     if (eval_result.OK)
  232.     {
  233.       ChkSpace(SegCode, eval_result.AddrSpaceMask);
  234.       if (mFirstPassUnknownOrQuestionable(eval_result.Flags))
  235.         address = (address & 0x0ff) | 0x100;
  236.       if (ChkRange(address, 0x100, 0x3ff))
  237.       {
  238.         BAsmCode[0] = code | (Hi(address) & 0x03);
  239.         BAsmCode[1] = Lo(address);
  240.         CodeLen = 2;
  241.       }
  242.     }
  243.   }
  244. }
  245.  
  246. /*!------------------------------------------------------------------------
  247.  * \fn     decode_data_pps4(Word code)
  248.  * \brief  handle DATA instruction
  249.  * ------------------------------------------------------------------------ */
  250.  
  251. static void decode_data_pps4(Word code)
  252. {
  253.   UNUSED(code);
  254.  
  255.   DecodeDATA(Int8, Int4);
  256. }
  257.  
  258. /*---------------------------------------------------------------------------*/
  259. /* Code Table Handling */
  260.  
  261. /*!------------------------------------------------------------------------
  262.  * \fn     init_fields(void)
  263.  * \brief  build up instruction hash table
  264.  * ------------------------------------------------------------------------ */
  265.  
  266. static void init_fields(void)
  267. {
  268.   InstTable = CreateInstTable(101);
  269.  
  270.   AddInstTable(InstTable, "AD"   , 0x0b, decode_fixed);
  271.   AddInstTable(InstTable, "ADC"  , 0x0a, decode_fixed);
  272.   AddInstTable(InstTable, "ADSK" , 0x09, decode_fixed);
  273.   AddInstTable(InstTable, "ADCSK", 0x08, decode_fixed);
  274.   AddInstTable(InstTable, "DC"   , 0x65, decode_fixed);
  275.   AddInstTable(InstTable, "AND"  , 0x0d, decode_fixed);
  276.   AddInstTable(InstTable, "OR"   , 0x0f, decode_fixed);
  277.   AddInstTable(InstTable, "EOR"  , 0x0c, decode_fixed);
  278.   AddInstTable(InstTable, "COMP" , 0x0e, decode_fixed);
  279.   AddInstTable(InstTable, "SC"   , 0x20, decode_fixed);
  280.   AddInstTable(InstTable, "RC"   , 0x24, decode_fixed);
  281.   AddInstTable(InstTable, "SF1"  , 0x22, decode_fixed);
  282.   AddInstTable(InstTable, "RF1"  , 0x26, decode_fixed);
  283.   AddInstTable(InstTable, "SF2"  , 0x21, decode_fixed);
  284.   AddInstTable(InstTable, "RF2"  , 0x25, decode_fixed);
  285.   AddInstTable(InstTable, "LAX"  , 0x12, decode_fixed);
  286.   AddInstTable(InstTable, "LXA"  , 0x1b, decode_fixed);
  287.   AddInstTable(InstTable, "LABL" , 0x11, decode_fixed);
  288.   AddInstTable(InstTable, "LBMX" , 0x10, decode_fixed);
  289.   AddInstTable(InstTable, "LBUA" , 0x04, decode_fixed);
  290.   AddInstTable(InstTable, "XABL" , 0x19, decode_fixed);
  291.   AddInstTable(InstTable, "XBMX" , 0x18, decode_fixed);
  292.   AddInstTable(InstTable, "XAX"  , 0x1a, decode_fixed);
  293.   AddInstTable(InstTable, "XS"   , 0x06, decode_fixed);
  294.   AddInstTable(InstTable, "CYS"  , 0x6f, decode_fixed);
  295.   AddInstTable(InstTable, "INCB" , 0x17, decode_fixed);
  296.   AddInstTable(InstTable, "DECB" , 0x1f, decode_fixed);
  297.   AddInstTable(InstTable, "SKC"  , 0x15, decode_fixed);
  298.   AddInstTable(InstTable, "SKZ"  , 0x1e, decode_fixed);
  299.   AddInstTable(InstTable, "SKF1" , 0x16, decode_fixed);
  300.   AddInstTable(InstTable, "SKF2" , 0x14, decode_fixed);
  301.   AddInstTable(InstTable, "RTN"  , 0x05, decode_fixed);
  302.   AddInstTable(InstTable, "RTNSK", 0x07, decode_fixed);
  303.   AddInstTable(InstTable, "DIA"  , 0x27, decode_fixed);
  304.   AddInstTable(InstTable, "DIB"  , 0x23, decode_fixed);
  305.   AddInstTable(InstTable, "DOA"  , 0x1d, decode_fixed);
  306.   AddInstTable(InstTable, "SAG"  , 0x13, decode_fixed);
  307.  
  308.   AddInstTable(InstTable, "ADI"  , 0x60, decode_adi);
  309.   AddInstTable(InstTable, "LD"   , 0x30, decode_imm_3);
  310.   AddInstTable(InstTable, "EX"   , 0x38, decode_imm_3);
  311.   AddInstTable(InstTable, "EXD"  , 0x28, decode_imm_3);
  312.   AddInstTable(InstTable, "LDI"  , 0x70, decode_imm_4);
  313.   AddInstTable(InstTable, "LB"   , 0xc0, decode_imm_4);
  314.   AddInstTable(InstTable, "LBL"  , 0x00, decode_imm_8);
  315.   AddInstTable(InstTable, "SKBI" , 0x40, decode_imm_4);
  316.   AddInstTable(InstTable, "IOL"  , 0x1c, decode_imm_8);
  317.  
  318.   AddInstTable(InstTable, "T"    , 0x80, decode_t);
  319.   AddInstTable(InstTable, "TM"   , 0xc0, decode_tm);
  320.   AddInstTable(InstTable, "TL"   , 0x50, decode_tl);
  321.   AddInstTable(InstTable, "TML"  , 0x00, decode_tml);
  322.  
  323.   AddInstTable(InstTable, "RES",  0, DecodeRES);
  324.   AddInstTable(InstTable, "DS",   0, DecodeRES);
  325.   AddInstTable(InstTable, "DATA", 0, decode_data_pps4);
  326. }
  327.  
  328. /*!------------------------------------------------------------------------
  329.  * \fn     deinit_fields(void)
  330.  * \brief  tear down instruction hash table
  331.  * ------------------------------------------------------------------------ */
  332.  
  333. static void deinit_fields(void)
  334. {
  335.   DestroyInstTable(InstTable);
  336. }
  337.  
  338. /*---------------------------------------------------------------------------*/
  339. /* Interface Functions */
  340.  
  341. /*!------------------------------------------------------------------------
  342.  * \fn     make_code_pps4(void)
  343.  * \brief  machine instruction dispatcher
  344.  * ------------------------------------------------------------------------ */
  345.  
  346. static void make_code_pps4(void)
  347. {
  348.   CodeLen = 0; DontPrint = False;
  349.  
  350.   /* to be ignored */
  351.  
  352.   if (Memo("")) return;
  353.  
  354.   /* pseudo instructions */
  355.  
  356.   if (!LookupInstTable(InstTable, OpPart.str.p_str))
  357.     WrStrErrorPos(ErrNum_UnknownInstruction, &OpPart);
  358. }
  359.  
  360. /*!------------------------------------------------------------------------
  361.  * \fn     switch_from_pps4(void)
  362.  * \brief  cleanups after switch from target
  363.  * ------------------------------------------------------------------------ */
  364.  
  365. static void switch_from_pps4(void)
  366. {
  367.   deinit_fields();
  368. }
  369.  
  370. /*!------------------------------------------------------------------------
  371.  * \fn     is_def_cp_pps4(void)
  372.  * \brief  does instruction use label field?
  373.  * ------------------------------------------------------------------------ */
  374.  
  375. static Boolean is_def_pps4(void)
  376. {
  377.   return False;
  378. }
  379.  
  380. /*!------------------------------------------------------------------------
  381.  * \fn     switch_to_pps4(void)
  382.  * \brief  prepare to assemble code for this target
  383.  * ------------------------------------------------------------------------ */
  384.  
  385. static void switch_to_pps4(void)
  386. {
  387.   const TFamilyDescr *p_descr = FindFamilyByName("PPS-4");
  388.  
  389.   TurnWords = False;
  390.   SetIntConstMode(eIntConstModeIntel);
  391.  
  392.   PCSymbol = "$";
  393.   HeaderID = p_descr->Id;
  394.   NOPCode = 0x00;
  395.   DivideChars = ",";
  396.   HasAttrs = False;
  397.  
  398.   ValidSegs = (1 << SegCode) | (1 << SegData);
  399.   Grans[SegCode] = 1; ListGrans[SegCode] = 1; SegLimits[SegCode] = 0xfff;
  400.   Grans[SegData] = 1; ListGrans[SegData] = 1; SegLimits[SegData] = 0xfff;
  401.  
  402.   MakeCode = make_code_pps4;
  403.   SwitchFrom = switch_from_pps4;
  404.   IsDef = is_def_pps4;
  405.   init_fields();
  406. }
  407.  
  408. /*!------------------------------------------------------------------------
  409.  * \fn     codepps4_init(void)
  410.  * \brief  register PPS-4 target
  411.  * ------------------------------------------------------------------------ */
  412.  
  413. void codepps4_init(void)
  414. {
  415.   (void)AddCPU("PPS-4"    , switch_to_pps4);
  416. }
  417.