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