Subversion Repositories pentevo

Rev

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

  1. /* codepdp11.c */
  2. /*****************************************************************************/
  3. /* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only                     */
  4. /*                                                                           */
  5. /* AS                                                                        */
  6. /*                                                                           */
  7. /* Code Generator VAX                                                        */
  8. /*                                                                           */
  9. /*****************************************************************************/
  10.  
  11. #include "stdinc.h"
  12. #include <string.h>
  13.  
  14. #include "bpemu.h"
  15. #include "strutil.h"
  16. #include "headids.h"
  17. #include "asmdef.h"
  18. #include "asmsub.h"
  19. #include "asmpars.h"
  20. #include "asmallg.h"
  21. #include "asmcode.h"
  22. #include "asmitree.h"
  23. #include "codevars.h"
  24. #include "codepseudo.h"
  25. #include "errmsg.h"
  26. #include "decfloat.h"
  27. #include "codepdp11.h"
  28.  
  29. typedef struct
  30. {
  31.   char name[15];
  32. } cpu_props_t;
  33.  
  34. typedef struct
  35. {
  36.   Word code;
  37.   tSymbolSize op_size;
  38. } order_t;
  39.  
  40. typedef enum
  41. {
  42.   ModNone = -1,
  43.   ModReg = 0,
  44.   ModImm = 1,
  45.   ModMem = 2
  46. } adr_mode_t;
  47.  
  48. #define MModReg (1 << ModReg)
  49. #define MModImm (1 << ModImm)
  50. #define MModMem (1 << ModMem)
  51.  
  52. typedef struct
  53. {
  54.   adr_mode_t mode;
  55.   unsigned count;
  56.   Byte vals[20];
  57. } adr_vals_t;
  58.  
  59. static const cpu_props_t *p_curr_cpu_props;
  60. static tSymbolSize op_size;
  61. static order_t *two_op_orders, *three_op_orders;
  62.  
  63. /*-------------------------------------------------------------------------*/
  64. /* Register Symbols */
  65.  
  66. /*!------------------------------------------------------------------------
  67.  * \fn     decode_reg_core(const char *p_arg, Word *p_result, tSymbolSize *p_size)
  68.  * \brief  check whether argument is a CPU register
  69.  * \param  p_arg argument to check
  70.  * \param  p_result numeric register value if yes
  71.  * \param  p_size returns register size
  72.  * \return True if yes
  73.  * ------------------------------------------------------------------------ */
  74.  
  75. #define REG_AP 12
  76. #define REG_FP 13
  77. #define REG_SP 14
  78. #define REG_PC 15
  79.  
  80. static const char xtra_reg_names[8] =
  81. {
  82.   'A','P',
  83.   'F','P',
  84.   'S','P',
  85.   'P','C'
  86. };
  87.  
  88. static Boolean decode_reg_core(const char *p_arg, Byte *p_result, tSymbolSize *p_size)
  89. {
  90.   switch (strlen(p_arg))
  91.   {
  92.     case 2:
  93.     {
  94.       int z;
  95.  
  96.       for (z = 0; z < 8; z += 2)
  97.         if ((as_toupper(p_arg[0]) == xtra_reg_names[z + 0])
  98.          && (as_toupper(p_arg[1]) == xtra_reg_names[z + 1]))
  99.       {
  100.         *p_result = ((z / 2) + REG_AP) | REGSYM_FLAG_ALIAS;
  101.         *p_size = eSymbolSize32Bit;
  102.         return True;
  103.       }
  104.       if ((as_toupper(*p_arg) == 'R')
  105.        && isdigit(p_arg[1]))
  106.       {
  107.         *p_result = p_arg[1] - '0';
  108.         *p_size = eSymbolSize32Bit;
  109.         return True;
  110.       }
  111.       break;
  112.     }
  113.     case 3:
  114.       if ((as_toupper(*p_arg) == 'R')
  115.        && (as_toupper(p_arg[1]) == '1')
  116.        && isdigit(p_arg[2])
  117.        && (p_arg[2] < '6'))
  118.       {
  119.         *p_result = 10 + p_arg[2] - '0';
  120.         *p_size = eSymbolSize32Bit;
  121.         return True;
  122.       }
  123.       break;
  124.     default:
  125.       break;
  126.   }
  127.   return False;
  128. }
  129.  
  130. /*!------------------------------------------------------------------------
  131.  * \fn     dissect_reg_vax(char *p_dest, size_t dest_size, tRegInt value, tSymbolSize inp_size)
  132.  * \brief  dissect register symbols - PDP-11 variant
  133.  * \param  p_dest destination buffer
  134.  * \param  dest_size destination buffer size
  135.  * \param  value numeric register value
  136.  * \param  inp_size register size
  137.  * ------------------------------------------------------------------------ */
  138.  
  139. static void dissect_reg_vax(char *p_dest, size_t dest_size, tRegInt value, tSymbolSize inp_size)
  140. {
  141.   switch (inp_size)
  142.   {
  143.     case eSymbolSize32Bit:
  144.     {
  145.       unsigned r_num = value & 15;
  146.  
  147.       if ((value & REGSYM_FLAG_ALIAS) && (r_num >= REG_AP))
  148.         as_snprintf(p_dest, dest_size, "%2.2s", &xtra_reg_names[(r_num - REG_AP) * 2]);
  149.       else
  150.         as_snprintf(p_dest, dest_size, "R%u", r_num);
  151.       break;
  152.     }
  153.     default:
  154.       as_snprintf(p_dest, dest_size, "%d-%u", (int)inp_size, (unsigned)value);
  155.   }
  156. }
  157.  
  158. /*--------------------------------------------------------------------------*/
  159. /* Address Decoding */
  160.  
  161. static tRegEvalResult decode_reg(const tStrComp *p_arg, Byte *p_result, Boolean must_be_reg)
  162. {
  163.   tRegDescr reg_descr;
  164.   tEvalResult eval_result;
  165.   tRegEvalResult reg_eval_result;
  166.  
  167.   if (decode_reg_core(p_arg->str.p_str, p_result, &eval_result.DataSize))
  168.   {
  169.     reg_descr.Reg = *p_result;
  170.     reg_eval_result = eIsReg;
  171.   }
  172.   else
  173.     reg_eval_result = EvalStrRegExpressionAsOperand(p_arg, &reg_descr, &eval_result, eSymbolSizeUnknown, must_be_reg);
  174.  
  175.   *p_result = reg_descr.Reg & ~REGSYM_FLAG_ALIAS;
  176.   return reg_eval_result;
  177. }
  178.  
  179. /*!------------------------------------------------------------------------
  180.  * \fn     reset_adr_vals(adr_vals_t *p_vals)
  181.  * \brief  reset encoded addressing
  182.  * \param  p_vals buffer to reset
  183.  * \return constant False for convenience
  184.  * ------------------------------------------------------------------------ */
  185.  
  186. static Boolean reset_adr_vals(adr_vals_t *p_vals)
  187. {
  188.   p_vals->mode = ModNone;
  189.   p_vals->count = 0;
  190.   return False;
  191. }
  192.  
  193. /*!------------------------------------------------------------------------
  194.  * \fn     append_adr_vals_int(adr_vals_t *p_vals, LargeWord int_value, tSymbolSize size)
  195.  * \brief  append integer value to encoded address value
  196.  * \param  p_vals where to append
  197.  * \param  int_value value to append
  198.  * \param  size integer size
  199.  * \return
  200.  * ------------------------------------------------------------------------ */
  201.  
  202. static void append_adr_vals_int(adr_vals_t *p_vals, LargeWord int_value, tSymbolSize size)
  203. {
  204.   unsigned num_iter = GetSymbolSizeBytes(size), z;
  205.  
  206.   for (z = 0; z < num_iter; z++)
  207.   {
  208.     p_vals->vals[p_vals->count++] = int_value & 0xff;
  209.     int_value >>= 8;
  210.   }
  211. }
  212.  
  213. /*!------------------------------------------------------------------------
  214.  * \fn     decode_adr(tStrComp *p_arg, adr_vals_t *p_result, Word pc_value, unsigned mode_mask)
  215.  * \brief  parse address expression
  216.  * \param  p_arg source argument
  217.  * \param  p_result parsed result
  218.  * \param  pc_value value of PC to be used in PC-relative calculation
  219.  * \param  mode_mask bit mask of allowed addressing modes
  220.  * \return True if success
  221.  * ------------------------------------------------------------------------ */
  222.  
  223. static Boolean check_mode_mask(unsigned mode_mask, unsigned act_mask, tStrComp *p_arg, adr_vals_t *p_result)
  224. {
  225.   if (!(mode_mask & act_mask))
  226.   {
  227.     WrStrErrorPos(ErrNum_InvAddrMode, p_arg);
  228.     return reset_adr_vals(p_result);
  229.   }
  230.   else
  231.     return True;
  232. }
  233.  
  234. static Boolean is_pre_decrement(const tStrComp *p_arg, Byte *p_result, tRegEvalResult *p_reg_eval_result)
  235. {
  236.   String reg;
  237.   tStrComp reg_comp;
  238.   size_t arg_len = strlen(p_arg->str.p_str);
  239.  
  240.   if ((arg_len < 4)
  241.    || (p_arg->str.p_str[0] != '-')
  242.    || (p_arg->str.p_str[1] != '(')
  243.    || (p_arg->str.p_str[arg_len - 1] != ')'))
  244.     return False;
  245.   StrCompMkTemp(&reg_comp, reg, sizeof(reg));
  246.   StrCompCopySub(&reg_comp, p_arg, 2, arg_len - 3);
  247.   KillPrefBlanksStrComp(&reg_comp);
  248.   KillPostBlanksStrComp(&reg_comp);
  249.   *p_reg_eval_result = decode_reg(&reg_comp, p_result, False);
  250.   return (*p_reg_eval_result != eIsNoReg);
  251. }
  252.  
  253. static Boolean is_post_increment(const tStrComp *p_arg, Byte *p_result, tRegEvalResult *p_reg_eval_result)
  254. {
  255.   String reg;
  256.   tStrComp reg_comp;
  257.   size_t arg_len = strlen(p_arg->str.p_str);
  258.  
  259.   if ((arg_len < 4)
  260.    || (p_arg->str.p_str[0] != '(')
  261.    || (p_arg->str.p_str[arg_len - 2] != ')')
  262.    || (p_arg->str.p_str[arg_len - 1] != '+'))
  263.     return False;
  264.   StrCompMkTemp(&reg_comp, reg, sizeof(reg));
  265.   StrCompCopySub(&reg_comp, p_arg, 1, arg_len - 3);
  266.   KillPrefBlanksStrComp(&reg_comp);
  267.   KillPostBlanksStrComp(&reg_comp);
  268.   *p_reg_eval_result = decode_reg(&reg_comp, p_result, False);
  269.   return (*p_reg_eval_result != eIsNoReg);
  270. }
  271.  
  272. static Boolean decode_abs(const tStrComp *p_arg, adr_vals_t *p_result)
  273. {
  274.   Boolean ok;
  275.   LongWord address = EvalStrIntExpression(p_arg, UInt32, &ok);
  276.  
  277.   if (ok)
  278.     append_adr_vals_int(p_result, address, eSymbolSize32Bit);
  279.  
  280.   return ok;
  281. }
  282.  
  283. static int index_qualifier(const char *p_arg, int next_non_blank_pos, int split_pos)
  284. {
  285.   /* extra check for post increment: good enough? */
  286.  
  287.   int ret = ((next_non_blank_pos >= 4)
  288.        && (p_arg[0] == '(')
  289.        && (p_arg[next_non_blank_pos - 1] == ')')
  290.        && (p_arg[next_non_blank_pos] == '+'))
  291.    ? split_pos : -1;
  292.   return ret;
  293. }
  294.  
  295. static Boolean decode_adr(tStrComp *p_arg, adr_vals_t *p_result, LongWord pc_value, unsigned mode_mask)
  296. {
  297.   tStrComp arg, len_spec_arg;
  298.   Boolean deferred;
  299.   Byte reg, index_reg;
  300.   tEvalResult eval_result;
  301.   tRegEvalResult reg_eval_result;
  302.   int arg_len, split_pos;
  303.   char len_spec, ch;
  304.  
  305.   reset_adr_vals(p_result);
  306.  
  307.   /* split off deferred flag? */
  308.  
  309.   deferred = (p_arg->str.p_str[0] == '@');
  310.   StrCompRefRight(&arg, p_arg, deferred);
  311.   if (deferred)
  312.     KillPrefBlanksStrCompRef(&arg);
  313.  
  314.   /* Split off index register (which must not be PC): */
  315.  
  316.   split_pos = FindDispBaseSplitWithQualifier(arg.str.p_str, &arg_len, index_qualifier, "[]");
  317.   if (split_pos > 0)
  318.   {
  319.     String reg_str;
  320.     tStrComp reg_comp;
  321.  
  322.     StrCompMkTemp(&reg_comp, reg_str, sizeof(reg_str));
  323.     StrCompCopySub(&reg_comp, &arg, split_pos + 1, arg_len - split_pos - 2);
  324.     KillPostBlanksStrComp(&reg_comp);
  325.     KillPrefBlanksStrComp(&reg_comp);
  326.     switch (decode_reg(&reg_comp, &index_reg, False))
  327.     {
  328.       case eRegAbort:
  329.         return False;
  330.       case eIsReg:
  331.         StrCompShorten(&arg, arg_len - split_pos);
  332.         p_result->vals[p_result->count++] = (index_reg |= 0x40);
  333.         pc_value++;
  334.         break;
  335.       default:
  336.         break;
  337.     }
  338.   }
  339.   else
  340.     index_reg = 0;
  341.  
  342.   /* Plain register? */
  343.  
  344.   switch (decode_reg(&arg, &reg, False))
  345.   {
  346.     case eIsReg:
  347.       if (index_reg && !deferred)
  348.       {
  349.         WrStrErrorPos(ErrNum_InvAddrMode, p_arg);
  350.         return reset_adr_vals(p_result);
  351.       }
  352.       p_result->vals[p_result->count++] = reg | (deferred ? 0x60 : 0x50);
  353.       return check_mode_mask(mode_mask, deferred ? MModMem : MModReg, p_arg, p_result);
  354.     case eRegAbort:
  355.       return reset_adr_vals(p_result);
  356.     default:
  357.       break;
  358.   }
  359.  
  360.   /* Split off length specifier (BWLIS)^... */
  361.  
  362.   if ((strlen(arg.str.p_str) > 2)
  363.    && ('^' == arg.str.p_str[1])
  364.    && strchr("BWLIS", (ch = as_toupper(arg.str.p_str[0]))))
  365.   {
  366.     StrCompSplitRef(&len_spec_arg, &arg, &arg, &arg.str.p_str[1]);
  367.     len_spec = ch;
  368.     KillPrefBlanksStrCompRef(&arg);
  369.   }
  370.   else
  371.   {
  372.     len_spec = '\0';
  373.     LineCompReset(&len_spec_arg.Pos);
  374.   }
  375.  
  376.   /* #imm, @#abs */
  377.  
  378.   if (*arg.str.p_str == '#')
  379.   {
  380.     tStrComp imm_arg;
  381.  
  382.     StrCompRefRight(&imm_arg, &arg, 1);
  383.  
  384.     /* @#abs */
  385.  
  386.     if (deferred)
  387.     {
  388.       p_result->vals[p_result->count++] = 0x90 | REG_PC;
  389.       eval_result.OK = decode_abs(&imm_arg, p_result);
  390.       return eval_result.OK
  391.              ? check_mode_mask(mode_mask, MModMem, p_arg, p_result)
  392.              : reset_adr_vals(p_result);
  393.     }
  394.     else
  395.     {
  396.       LargeInt value;
  397.       IntType eval_int_type;
  398.       Byte *p_specifier;
  399.  
  400.       if (index_reg)
  401.       {
  402.         WrStrErrorPos(ErrNum_InvAddrMode, p_arg);
  403.         return reset_adr_vals(p_result);
  404.       }
  405.  
  406.       p_specifier = &p_result->vals[p_result->count]; p_result->count++;
  407.  
  408.       /* TODO: regard ranges for floating point */
  409.  
  410.       if (len_spec == 'S')
  411.         eval_int_type = UInt6;
  412.       else if (!len_spec || (len_spec == 'I'))
  413.       {
  414.         switch (op_size)
  415.         {
  416.           case eSymbolSize8Bit:
  417.             eval_int_type = Int8;
  418.             break;
  419.           case eSymbolSize16Bit:
  420.             eval_int_type = Int16;
  421.             break;
  422.           case eSymbolSize64Bit:
  423.           case eSymbolSize128Bit:
  424. #ifdef HAS64
  425.             eval_int_type = Int64;
  426.             break;
  427. #endif
  428.           case eSymbolSize32Bit:
  429.             eval_int_type = Int32;
  430.             break;
  431.           default:
  432.             WrStrErrorPos(ErrNum_InvOpSize, &imm_arg);
  433.             return reset_adr_vals(p_result);
  434.         }
  435.       }
  436.       else
  437.       {
  438.         WrStrErrorPos(ErrNum_UndefAttr, &len_spec_arg);
  439.         return reset_adr_vals(p_result);
  440.       }
  441.  
  442.       value = EvalStrIntExpressionWithResult(&imm_arg, eval_int_type, &eval_result);
  443.       if (!eval_result.OK)
  444.         return reset_adr_vals(p_result);
  445.  
  446.       if (!len_spec)
  447.         len_spec = (RangeCheck(value, UInt6)) ? 'S' : 'I';
  448.  
  449.       if (len_spec == 'S')
  450.         *p_specifier = value & 63;
  451.       else
  452.       {
  453.         *p_specifier = 0x80 | REG_PC;
  454.         append_adr_vals_int(p_result, (LargeWord)value, op_size);
  455.       }
  456.       return check_mode_mask(mode_mask, MModImm, p_arg, p_result);
  457.     }
  458.   }
  459.  
  460.   /* (Rn)+, @(Rn)+ */
  461.  
  462.   if (is_post_increment(&arg, &reg, &reg_eval_result))
  463.   {
  464.     if (eRegAbort == reg_eval_result)
  465.       return reset_adr_vals(p_result);
  466.     else if (len_spec)
  467.     {
  468.       WrStrErrorPos(ErrNum_InvAddrMode, p_arg);
  469.       return reset_adr_vals(p_result);
  470.     }
  471.     if (index_reg && (reg == (index_reg & 0xf)))
  472.       WrStrErrorPos(ErrNum_Unpredictable,p_arg);
  473.     p_result->vals[p_result->count++] = reg | (deferred ? 0x90 : 0x80);
  474.     return check_mode_mask(mode_mask, MModMem, p_arg, p_result);
  475.   }
  476.  
  477.   /* -(Rn), @-(Rn) (not supported on VAX) */
  478.  
  479.   if (is_pre_decrement(&arg, &reg, &reg_eval_result))
  480.   {
  481.     if (eRegAbort == reg_eval_result)
  482.       return reset_adr_vals(p_result);
  483.     else if (deferred || len_spec)
  484.     {
  485.       WrStrErrorPos(ErrNum_InvAddrMode, p_arg);
  486.       return reset_adr_vals(p_result);
  487.     }
  488.     if (index_reg && (reg == (index_reg & 0xf)))
  489.       WrStrErrorPos(ErrNum_Unpredictable,p_arg);
  490.     p_result->vals[p_result->count++] = reg | 0x70;
  491.     return check_mode_mask(mode_mask, MModMem, p_arg, p_result);
  492.   }
  493.  
  494.   /* (Rn), X(Rn) */
  495.  
  496.   split_pos = FindDispBaseSplitWithQualifier(arg.str.p_str, &arg_len, NULL, "()");
  497.   if (split_pos >= 0)
  498.   {
  499.     tStrComp disp_arg, reg_arg;
  500.  
  501.     StrCompSplitRef(&disp_arg, &reg_arg, &arg, &arg.str.p_str[split_pos]);
  502.     KillPostBlanksStrComp(&disp_arg);
  503.     KillPrefBlanksStrCompRef(&reg_arg);
  504.     StrCompShorten(&reg_arg, 1);
  505.     KillPostBlanksStrComp(&reg_arg);
  506.  
  507.     if (decode_reg(&reg_arg, &reg, True) != eIsReg)
  508.     {
  509.       WrStrErrorPos(ErrNum_InvReg, &reg_arg);
  510.       return reset_adr_vals(p_result);
  511.     }
  512.  
  513.     /* (Rn) */
  514.  
  515.     if (!*disp_arg.str.p_str && !deferred)
  516.     {
  517.       if (len_spec)
  518.       {
  519.         WrStrErrorPos(ErrNum_InvAddrMode, p_arg);
  520.         return reset_adr_vals(p_result);
  521.       }
  522.       p_result->vals[p_result->count++] = reg | 0x60;
  523.     }
  524.  
  525.     /* X(Rn) */
  526.  
  527.     else
  528.     {
  529.       LongInt disp;
  530.       tSymbolSize size = eSymbolSizeUnknown;
  531.       IntType eval_int_type;
  532.  
  533.       switch (len_spec)
  534.       {
  535.         case 'B':
  536.           eval_int_type = SInt8;
  537.           size = eSymbolSize8Bit;
  538.           break;
  539.         case 'W':
  540.           eval_int_type = SInt16;
  541.           size = eSymbolSize16Bit;
  542.           break;
  543.         case 'L':
  544.           size = eSymbolSize32Bit;
  545.           /* FALL-THRU */
  546.         case '\0':
  547.           eval_int_type = SInt32;
  548.           break;
  549.         default: /* I,S not allowed here */
  550.           WrStrErrorPos(ErrNum_UndefAttr, &len_spec_arg);
  551.           return reset_adr_vals(p_result);
  552.       }
  553.       disp = EvalStrIntExpressionWithResult(&disp_arg, eval_int_type, &eval_result);
  554.       if (!eval_result.OK)
  555.         return reset_adr_vals(p_result);
  556.  
  557.       /* deduce displacement size */
  558.  
  559.       if (eSymbolSizeUnknown == size)
  560.       {
  561.         if (RangeCheck(disp, SInt8))
  562.           size = eSymbolSize8Bit;
  563.         else if (RangeCheck(disp, SInt16))
  564.           size = eSymbolSize16Bit;
  565.         else
  566.           size = eSymbolSize32Bit;
  567.       }
  568.  
  569.       /* write out addressing mode */
  570.  
  571.       switch (size)
  572.       {
  573.         case eSymbolSize32Bit:
  574.           p_result->vals[p_result->count++] = reg | (deferred ? 0xf0 : 0xe0);
  575.           break;
  576.         case eSymbolSize16Bit:
  577.           p_result->vals[p_result->count++] = reg | (deferred ? 0xd0 : 0xc0);
  578.           break;
  579.         default:
  580.           p_result->vals[p_result->count++] = reg | (deferred ? 0xb0 : 0xa0);
  581.       }
  582.       append_adr_vals_int(p_result, disp, size);
  583.     }
  584.     return check_mode_mask(mode_mask, MModMem, p_arg, p_result);
  585.   }
  586.  
  587.   {
  588.     LongInt dist;
  589.     tSymbolSize dist_size;
  590.  
  591.     /* Remains: rel, @rel
  592.        PC value is the PC value after displacement was loaded,
  593.        which is the 'current PC' within the instruction we got as
  594.        argument, plus the specifier and optional index byte,
  595.        plus 1, 2, or 4 bytes for the displacement itself: */
  596.  
  597.     dist = EvalStrIntExpressionWithResult(&arg, UInt32, &eval_result) - pc_value;
  598.     if (!eval_result.OK)
  599.       return False;
  600.  
  601.     if (!len_spec)
  602.     {
  603.       if (RangeCheck(dist - 2, SInt8))
  604.         len_spec = 'B';
  605.       else if (RangeCheck(dist - 3, SInt16))
  606.         len_spec = 'W';
  607.       else
  608.         len_spec = 'L';
  609.     }
  610.     switch (len_spec)
  611.     {
  612.       case 'B':
  613.         p_result->vals[p_result->count++] = REG_PC | (deferred ? 0xb0 : 0xa0);
  614.         dist -= 2;
  615.         if (!mFirstPassUnknownOrQuestionable(eval_result.Flags) && !ChkRangeByType(dist, SInt8, &arg))
  616.           return reset_adr_vals(p_result);
  617.         dist_size = eSymbolSize8Bit;
  618.         break;
  619.       case 'W':
  620.         p_result->vals[p_result->count++] = REG_PC | (deferred ? 0xd0 : 0xc0);
  621.         dist -= 3;
  622.         if (!mFirstPassUnknownOrQuestionable(eval_result.Flags) && !ChkRangeByType(dist, SInt16, &arg))
  623.           return reset_adr_vals(p_result);
  624.         dist_size = eSymbolSize16Bit;
  625.         break;
  626.       case 'L':
  627.         p_result->vals[p_result->count++] = REG_PC | (deferred ? 0xf0 : 0xe0);
  628.         dist -= 5;
  629.         dist_size = eSymbolSize32Bit;
  630.         break;
  631.       default:
  632.         WrStrErrorPos(ErrNum_UndefAttr, &len_spec_arg);
  633.         return reset_adr_vals(p_result);
  634.     }
  635.     append_adr_vals_int(p_result, (LongWord)dist, dist_size);
  636.     return check_mode_mask(mode_mask, MModMem, p_arg, p_result);
  637.   }
  638. }
  639.  
  640. /*!------------------------------------------------------------------------
  641.  * \fn     append_adr_vals(const adr_vals_t *p_vals)
  642.  * \brief  append addressing mode values to instruction stream
  643.  * \param  p_vals values to append
  644.  * ------------------------------------------------------------------------ */
  645.  
  646. static void append_adr_vals(const adr_vals_t *p_vals)
  647. {
  648.   SetMaxCodeLen(CodeLen + p_vals->count);
  649.   memcpy(&BAsmCode[CodeLen], p_vals->vals, p_vals->count);
  650.   CodeLen += p_vals->count;
  651. }
  652.  
  653. /*--------------------------------------------------------------------------*/
  654. /* Instruction Handler Helpers */
  655.  
  656. /*!------------------------------------------------------------------------
  657.  * \fn     code_len(Word op_code)
  658.  * \brief  check whether opcode is one or two byte opcode
  659.  * \param  op_code opcode
  660.  * \return 1 or 2
  661.  * ------------------------------------------------------------------------ */
  662.  
  663. static int code_len(Word op_code)
  664. {
  665.   return 1 + !!Hi(op_code);
  666. }
  667.  
  668. /*!------------------------------------------------------------------------
  669.  * \fn     append_opcode(Word op_code)
  670.  * \brief  append opcode to instruction stream
  671.  * \param  op_code opcode to append
  672.  * ------------------------------------------------------------------------ */
  673.  
  674. static void append_opcode(Word op_code)
  675. {
  676.   SetMaxCodeLen(CodeLen + code_len(op_code));
  677.  
  678.   BAsmCode[CodeLen++] = Lo(op_code);
  679.   if (Hi(op_code))
  680.     BAsmCode[CodeLen++] = Hi(op_code);
  681. }
  682.  
  683. /*--------------------------------------------------------------------------*/
  684. /* Instruction Handlers */
  685.  
  686. /*!------------------------------------------------------------------------
  687.  * \fn     decode_fixed(Word code)
  688.  * \brief  handle instructions without argument
  689.  * \param  code machine code
  690.  * ------------------------------------------------------------------------ */
  691.  
  692. static void decode_fixed(Word code)
  693. {
  694.   if (ChkArgCnt(0, 0))
  695.     append_opcode(code);
  696. }
  697.  
  698. /*!------------------------------------------------------------------------
  699.  * \fn     decode_two_op(Word index)
  700.  * \brief  handle instructions with two generic operands
  701.  * \param  index index into instruction table
  702.  * ------------------------------------------------------------------------ */
  703.  
  704. static void decode_two_op(Word index)
  705. {
  706.   const order_t *p_order = &two_op_orders[index];
  707.   adr_vals_t src_adr_vals, dest_adr_vals;
  708.  
  709.   op_size = p_order->op_size;
  710.   if (ChkArgCnt(2, 2)
  711.    && decode_adr(&ArgStr[1], &src_adr_vals, EProgCounter() + code_len(p_order->code), MModImm | MModMem | MModReg)
  712.    && decode_adr(&ArgStr[2], &dest_adr_vals, EProgCounter() + code_len(p_order->code) + src_adr_vals.count, MModMem | MModReg))
  713.   {
  714.     append_opcode(p_order->code);
  715.     append_adr_vals(&src_adr_vals);
  716.     append_adr_vals(&dest_adr_vals);
  717.   }
  718. }
  719.  
  720. /*!------------------------------------------------------------------------
  721.  * \fn     decode_three_op(Word index)
  722.  * \brief  handle instructions with three generic operands
  723.  * \param  index index into instruction table
  724.  * ------------------------------------------------------------------------ */
  725.  
  726. static void decode_three_op(Word index)
  727. {
  728.   const order_t *p_order = &three_op_orders[index];
  729.   adr_vals_t src1_adr_vals, src2_adr_vals, dest_adr_vals;
  730.  
  731.   op_size = p_order->op_size;
  732.   if (ChkArgCnt(3, 3)
  733.    && decode_adr(&ArgStr[1], &src1_adr_vals, EProgCounter() + code_len(p_order->code), MModImm | MModMem | MModReg)
  734.    && decode_adr(&ArgStr[2], &src2_adr_vals, EProgCounter() + code_len(p_order->code) + src1_adr_vals.count, MModImm | MModMem | MModReg)
  735.    && decode_adr(&ArgStr[3], &dest_adr_vals, EProgCounter() + code_len(p_order->code) + src1_adr_vals.count + src2_adr_vals.count, MModMem | MModReg))
  736.   {
  737.     append_opcode(p_order->code);
  738.     append_adr_vals(&src1_adr_vals);
  739.     append_adr_vals(&src2_adr_vals);
  740.     append_adr_vals(&dest_adr_vals);
  741.   }
  742. }
  743.  
  744. /*--------------------------------------------------------------------------*/
  745. /* Instruction Lookup Table */
  746.  
  747. /*!------------------------------------------------------------------------
  748.  * \fn     init_fields_wd16(void)
  749.  * \brief  create lookup table
  750.  * ------------------------------------------------------------------------ */
  751.  
  752. static void add_two_op(const char *p_name, tSymbolSize op_size, Word code)
  753. {
  754.   order_array_rsv_end(two_op_orders, order_t);
  755.   two_op_orders[InstrZ].op_size = op_size;
  756.   two_op_orders[InstrZ].code = code;
  757.   AddInstTable(InstTable, p_name, InstrZ++, decode_two_op);
  758. }
  759.  
  760. static void add_three_op(const char *p_name, tSymbolSize op_size, Word code)
  761. {
  762.   order_array_rsv_end(three_op_orders, order_t);
  763.   three_op_orders[InstrZ].op_size = op_size;
  764.   three_op_orders[InstrZ].code = code;
  765.   AddInstTable(InstTable, p_name, InstrZ++, decode_three_op);
  766. }
  767.  
  768. static void init_fields(void)
  769. {
  770.   InstTable = CreateInstTable(201);
  771.  
  772.   AddInstTable(InstTable, "HALT",  0x00   , decode_fixed);
  773.   AddInstTable(InstTable, "NOP",   NOPCode, decode_fixed);
  774.  
  775.   InstrZ = 0;
  776.   add_two_op("MOVB", eSymbolSize8Bit, 0x90);
  777.   add_two_op("MOVW", eSymbolSize16Bit, 0xb0);
  778.   add_two_op("MOVD", eSymbolSize32Bit, 0x70);
  779.   add_two_op("MOVL", eSymbolSize64Bit, 0xd0);
  780.   add_two_op("MOVO", eSymbolSize128Bit, 0x7dfd);
  781.   add_two_op("ADDB2", eSymbolSize8Bit, 0x80);
  782.   add_two_op("ADDW2", eSymbolSize16Bit, 0xa0);
  783.   add_two_op("ADDL2", eSymbolSize32Bit, 0xc0);
  784.   add_two_op("SUBB2", eSymbolSize8Bit, 0x82);
  785.   add_two_op("SUBW2", eSymbolSize16Bit, 0xa2);
  786.   add_two_op("SUBL2", eSymbolSize32Bit, 0xc2);
  787.   add_two_op("MULB2", eSymbolSize8Bit, 0x84);
  788.   add_two_op("MULW2", eSymbolSize16Bit, 0xa4);
  789.   add_two_op("MULL2", eSymbolSize32Bit, 0xc4);
  790.   add_two_op("DIVB2", eSymbolSize8Bit, 0x86);
  791.   add_two_op("DIVW2", eSymbolSize16Bit, 0xa6);
  792.   add_two_op("DIVL2", eSymbolSize32Bit, 0xc6);
  793.  
  794.   InstrZ = 0;
  795.   add_three_op("ADDB3", eSymbolSize8Bit, 0x81);
  796.   add_three_op("ADDW3", eSymbolSize16Bit, 0xa1);
  797.   add_three_op("ADDL3", eSymbolSize32Bit, 0xc1);
  798.   add_three_op("SUBB3", eSymbolSize8Bit, 0x83);
  799.   add_three_op("SUBW3", eSymbolSize16Bit, 0xa3);
  800.   add_three_op("SUBL3", eSymbolSize32Bit, 0xc3);
  801.   add_three_op("MULB3", eSymbolSize8Bit, 0x85);
  802.   add_three_op("MULW3", eSymbolSize16Bit, 0xa5);
  803.   add_three_op("MULL3", eSymbolSize32Bit, 0xc5);
  804.   add_three_op("DIVB3", eSymbolSize8Bit, 0x87);
  805.   add_three_op("DIVW3", eSymbolSize16Bit, 0xa7);
  806.   add_three_op("DIVL3", eSymbolSize32Bit, 0xc7);
  807. }
  808.  
  809. /*!------------------------------------------------------------------------
  810.  * \fn     deinit_fields(void)
  811.  * \brief  destroy/cleanup lookup table
  812.  * ------------------------------------------------------------------------ */
  813.  
  814. static void deinit_fields(void)
  815. {
  816.   order_array_free(two_op_orders);
  817.   order_array_free(three_op_orders);
  818.   DestroyInstTable(InstTable);
  819. }
  820.  
  821. /*--------------------------------------------------------------------------*/
  822. /* Interface Functions */
  823.  
  824. /*!------------------------------------------------------------------------
  825.  * \fn     intern_symbol_vax(char *pArg, TempResult *pResult)
  826.  * \brief  handle built-in (register) symbols for VAX
  827.  * \param  p_arg source argument
  828.  * \param  p_result result buffer
  829.  * ------------------------------------------------------------------------ */
  830.  
  831. static void intern_symbol_vax(char *p_arg, TempResult *p_result)
  832. {
  833.   Byte reg_num;
  834.   (void)p_arg; (void)p_result;
  835.  
  836.   if (decode_reg_core(p_arg, &reg_num, &p_result->DataSize))
  837.   {
  838.     p_result->Typ = TempReg;
  839.     p_result->Contents.RegDescr.Reg = reg_num;
  840.     p_result->Contents.RegDescr.Dissect = dissect_reg_vax;
  841.     p_result->Contents.RegDescr.compare = NULL;
  842.   }
  843. }
  844.  
  845. /*!------------------------------------------------------------------------
  846.  * \fn     make_code_vax(void)
  847.  * \brief  encode machine instruction
  848.  * ------------------------------------------------------------------------ */
  849.  
  850. static void make_code_vax(void)
  851. {
  852.   CodeLen = 0;
  853.   DontPrint = False;
  854.   op_size = eSymbolSizeUnknown;
  855.  
  856.   /* to be ignored */
  857.  
  858.   if (Memo("")) return;
  859.  
  860.   /* Pseudo Instructions */
  861.  
  862.   if (!LookupInstTable(InstTable, OpPart.str.p_str))
  863.     WrStrErrorPos(ErrNum_UnknownInstruction, &OpPart);
  864. }
  865.  
  866. /*!------------------------------------------------------------------------
  867.  * \fn     is_def_vax(void)
  868.  * \brief  check whether insn makes own use of label
  869.  * \return True if yes
  870.  * ------------------------------------------------------------------------ */
  871.  
  872. static Boolean is_def_vax(void)
  873. {
  874.   return Memo("REG");
  875. }
  876.  
  877. /*!------------------------------------------------------------------------
  878.  * \fn     switch_from_vax(void)
  879.  * \brief  deinitialize as target
  880.  * ------------------------------------------------------------------------ */
  881.  
  882. static void switch_from_vax(void)
  883. {
  884.   deinit_fields();
  885.   p_curr_cpu_props = NULL;
  886. }
  887.  
  888. /*!------------------------------------------------------------------------
  889.  * \fn     switch_to_vax(void *p_user)
  890.  * \brief  prepare to assemble code for this target
  891.  * ------------------------------------------------------------------------ */
  892.  
  893. static void switch_to_vax(void *p_user)
  894. {
  895.   const TFamilyDescr *p_descr;
  896.  
  897.   p_curr_cpu_props = (const cpu_props_t*)p_user;
  898.   p_descr = FindFamilyByName("VAX");
  899.   SetIntConstMode(eIntConstModeC);
  900.  
  901.   PCSymbol = "*";
  902.   HeaderID = p_descr->Id;
  903.   NOPCode = 0x01;
  904.   DivideChars = ",";
  905.  
  906.   ValidSegs = 1 << SegCode;
  907.   Grans[SegCode] = 1;
  908.   ListGrans[SegCode] = 1;
  909.   SegInits[SegCode] = 0;
  910.   SegLimits[SegCode] = IntTypeDefs[UInt32].Max;
  911.  
  912.   MakeCode = make_code_vax;
  913.   IsDef = is_def_vax;
  914.   SwitchFrom = switch_from_vax;
  915.   InternSymbol = intern_symbol_vax;
  916. #if 0
  917.   DissectReg = dissect_reg_vax;
  918. #endif
  919.   multi_char_le = True;
  920.  
  921.   init_fields();
  922. }
  923.  
  924. /*!------------------------------------------------------------------------
  925.  * \fn     codevax_init(void)
  926.  * \brief  register VAX target
  927.  * ------------------------------------------------------------------------ */
  928.  
  929. static const cpu_props_t cpu_props[] =
  930. {
  931.   {      "VAX-11/750"  },
  932.   {      "VAX-11/780"  },
  933. };
  934.  
  935. void codevax_init(void)
  936. {
  937.   const cpu_props_t *p_prop;
  938.  
  939.   for (p_prop = cpu_props; p_prop < cpu_props + as_array_size(cpu_props); p_prop++)
  940.     (void)AddCPUUserWithArgs(p_prop->name, switch_to_vax, (void*)p_prop, NULL, NULL);
  941. }
  942.