Subversion Repositories pentevo

Rev

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

  1. /* codepalm.c */
  2. /*****************************************************************************/
  3. /* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only                     */
  4. /*                                                                           */
  5. /* AS                                                                        */
  6. /*                                                                           */
  7. /* Code Generator PALM                                                       */
  8. /*                                                                           */
  9. /*****************************************************************************/
  10.  
  11. #include "stdinc.h"
  12. #include <string.h>
  13. #include "bpemu.h"
  14. #include "strutil.h"
  15.  
  16. #include "asmdef.h"
  17. #include "asmallg.h"
  18. #include "asmsub.h"
  19. #include "asmpars.h"
  20. #include "asmitree.h"
  21. #include "asmcode.h"
  22. #include "headids.h"
  23. #include "codevars.h"
  24. #include "intpseudo.h"
  25. #include "codepseudo.h"
  26. #include "onoff_common.h"
  27.  
  28. #define REG_PC 0
  29.  
  30. #define MODIFIER_0 8
  31.  
  32. typedef enum
  33. {
  34.   ModReg = 0,  /* Rn */
  35.   ModIReg = 1, /* (Rn), (Rn)-, (Rn)+ */
  36.   ModDir = 2,  /* nn */
  37.   ModImm = 3,  /* #nn, #nnnn */
  38.   ModImmP1 = 4, /* #nn -> nn+1 */
  39.   ModIO = 5,   /* n in I/O space */
  40.   ModNone = 0xff
  41. } adr_mode_t;
  42.  
  43. #define MModReg (1 << ModReg)
  44. #define MModIReg (1 << ModIReg)
  45. #define MModDir (1 << ModDir)
  46. #define MModImm (1 << ModImm)
  47. #define MModImmP1 (1 << ModImmP1)
  48. #define MModIO (1 << ModIO)
  49.  
  50. typedef struct
  51. {
  52.   adr_mode_t mode;
  53.   Word value;
  54. } adr_vals_t;
  55.  
  56. static CPUVar cpu_5100, cpu_5110, cpu_5120;
  57. static Boolean last_was_skip, this_was_skip;
  58.  
  59. /*--------------------------------------------------------------------------*/
  60. /* Register Aliases */
  61.  
  62. /*!------------------------------------------------------------------------
  63.  * \fn     decode_reg_core(const char *p_arg, Word *p_result, tSymbolSize *p_size)
  64.  * \brief  check whether argument is a CPU register
  65.  * \param  p_arg argument to check
  66.  * \param  p_result numeric register value if yes
  67.  * \param  p_size returns register size
  68.  * \return True if yes
  69.  * ------------------------------------------------------------------------ */
  70.  
  71. static Boolean decode_reg_core(const char *p_arg, Word *p_result, tSymbolSize *p_size)
  72. {
  73.   if (!as_strcasecmp(p_arg, "PC"))
  74.   {
  75.     *p_result = REG_PC | REGSYM_FLAG_ALIAS;
  76.     *p_size = eSymbolSize16Bit;
  77.     return True;
  78.   }
  79.  
  80.   if (as_toupper(*p_arg) != 'R')
  81.     return False;
  82.   p_arg++;
  83.  
  84.   *p_result = 0;
  85.   switch (strlen(p_arg))
  86.   {
  87.     case 2:
  88.       if (*p_arg != '1')
  89.         return False;
  90.       *p_result += 10;
  91.       p_arg++;
  92.       /* FALL-THRU */
  93.     case 1:
  94.       if (!as_isdigit(*p_arg))
  95.         return False;
  96.       *p_result += *p_arg - '0';
  97.       *p_size = eSymbolSize16Bit;
  98.       return *p_result <= 15;
  99.     default:
  100.       return False;
  101.   }
  102. }
  103.  
  104. /*!------------------------------------------------------------------------
  105.  * \fn     decode_reg(const tStrComp *p_arg, Word *p_result, Boolean must_be_reg)
  106.  * \brief  check whether argument is a CPU register or register alias
  107.  * \param  p_arg argument to check
  108.  * \param  p_result numeric register value if yes
  109.  * \param  must_be_reg argument is expected to be a register
  110.  * \return RegEvalResult
  111.  * ------------------------------------------------------------------------ */
  112.  
  113. static tRegEvalResult decode_reg(const tStrComp *p_arg, Word *p_result, Boolean must_be_reg)
  114. {
  115.   tRegDescr reg_descr;
  116.   tEvalResult eval_result;
  117.   tRegEvalResult reg_eval_result;
  118.  
  119.   if (decode_reg_core(p_arg->str.p_str, p_result, &eval_result.DataSize))
  120.   {
  121.     reg_descr.Reg = *p_result;
  122.     reg_eval_result = eIsReg;
  123.   }
  124.   else
  125.     reg_eval_result = EvalStrRegExpressionAsOperand(p_arg, &reg_descr, &eval_result, eSymbolSizeUnknown, must_be_reg);
  126.  
  127.   *p_result = reg_descr.Reg & ~REGSYM_FLAG_ALIAS;
  128.   return reg_eval_result;
  129. }
  130.  
  131. /*!------------------------------------------------------------------------
  132.  * \fn     dissect_reg_palm(char *p_dest, size_t dest_size, tRegInt value, tSymbolSize inp_size)
  133.  * \brief  dissect register symbols - PALM variant
  134.  * \param  p_dest destination buffer
  135.  * \param  dest_size destination buffer size
  136.  * \param  value numeric register value
  137.  * \param  inp_size register size
  138.  * ------------------------------------------------------------------------ */
  139.  
  140. static void dissect_reg_palm(char *p_dest, size_t dest_size, tRegInt value, tSymbolSize inp_size)
  141. {
  142.   switch (inp_size)
  143.   {
  144.     case eSymbolSize16Bit:
  145.       switch (value)
  146.       {
  147.         case REGSYM_FLAG_ALIAS | REG_PC:
  148.           as_snprintf(p_dest, dest_size, "PC");
  149.           break;
  150.         default:
  151.           as_snprintf(p_dest, dest_size, "R%u", (unsigned)(value & 15));
  152.       }
  153.       break;
  154.     default:
  155.       as_snprintf(p_dest, dest_size, "%d-%u", (int)inp_size, (unsigned)value);
  156.   }
  157. }
  158.  
  159. /*--------------------------------------------------------------------------*/
  160. /* Address Expression Decoders */
  161.  
  162. /*!------------------------------------------------------------------------
  163.  * \fn     decode_direct_word_address(const tStrComp *p_arg, Word *p_result)
  164.  * \brief  evaluate direct address, which must be halfword-aligned (0,2,4...510)
  165.  * \param  p_arg source argument
  166.  * \param  p_result encoded result
  167.  * \return True if successfully parsed
  168.  * ------------------------------------------------------------------------ */
  169.  
  170. static Boolean decode_direct_word_address(const tStrComp *p_arg, Word *p_result)
  171. {
  172.   tEvalResult eval_result;
  173.  
  174.   *p_result = EvalStrIntExpressionWithResult(p_arg, UInt9, &eval_result);
  175.   if (!eval_result.OK)
  176.     return False;
  177.   if (!mFirstPassUnknownOrQuestionable(eval_result.Flags) && (*p_result & 1))
  178.   {
  179.     WrStrErrorPos(ErrNum_AddrMustBeEven, p_arg);
  180.     return False;
  181.   }
  182.   *p_result = (*p_result >> 1) & 0xff;
  183.   return True;
  184. }
  185.  
  186. /*!------------------------------------------------------------------------
  187.  * \fn     decode_code_address(const tStrComp *p_arg, Word *p_result, tEvalResult *p_eval_result)
  188.  * \brief  evaluate code (instruction) address, which must be halfword-aligned (0,2,4...510)
  189.  * \param  p_arg source argument
  190.  * \param  p_result encoded result
  191.  * \param  p_eval_result additional evaluation flags
  192.  * \return True if successfully parsed
  193.  * ------------------------------------------------------------------------ */
  194.  
  195. static Boolean decode_code_address(const tStrComp *p_arg, Word *p_result, tEvalResult *p_eval_result)
  196. {
  197.   *p_result = EvalStrIntExpressionWithResult(p_arg, UInt16, p_eval_result);
  198.   if (!p_eval_result->OK)
  199.     return False;
  200.   ChkSpace(SegCode, p_eval_result->AddrSpaceMask);
  201.   if (!mFirstPassUnknownOrQuestionable(p_eval_result->Flags) && (*p_result & 1))
  202.   {
  203.     WrStrErrorPos(ErrNum_AddrMustBeEven, p_arg);
  204.     return False;
  205.   }
  206.   return True;
  207. }
  208.  
  209. /*!------------------------------------------------------------------------
  210.  * \fn     decode_io_address(const tStrComp *p_arg, Word *p_result)
  211.  * \brief  evaluate I/O address
  212.  * \param  p_arg source argument
  213.  * \param  p_result encoded result
  214.  * \return True if successfully parsed
  215.  * ------------------------------------------------------------------------ */
  216.  
  217. static Boolean decode_io_address(const tStrComp *p_arg, Word *p_result)
  218. {
  219.   tEvalResult eval_result;
  220.  
  221.   *p_result = EvalStrIntExpressionWithResult(p_arg, UInt4, &eval_result);
  222.   if (eval_result.OK)
  223.     ChkSpace(SegIO, eval_result.AddrSpaceMask);
  224.   return eval_result.OK;
  225. }
  226.  
  227. /*!------------------------------------------------------------------------
  228.  * \fn     decode_indirect_modifier(const tStrComp *p_arg, Word *p_result)
  229.  * \brief  decode auto-inc modifier (-4...+4)
  230.  * \param  p_arg source argument
  231.  * \param  p_result encoded result (0..8)
  232.  * ------------------------------------------------------------------------ */
  233.  
  234. static Boolean decode_indirect_modifier(const tStrComp *p_arg, Word *p_result)
  235. {
  236.   tEvalResult eval_result;
  237.   ShortInt dist;
  238.  
  239.   dist = EvalStrIntExpressionWithResult(p_arg, SInt4, &eval_result);
  240.   if (!eval_result.OK)
  241.     return False;
  242.  
  243.   if (!mFirstPassUnknownOrQuestionable(eval_result.Flags)
  244.    && !ChkRangePos(dist, -4, +4, p_arg))
  245.     return False;
  246.  
  247.   if (!dist)
  248.     *p_result = MODIFIER_0;
  249.   else if (dist > 0)
  250.     *p_result = (dist - 1) & 3;
  251.   else
  252.     *p_result = (-dist + 3) & 7;
  253.   return True;
  254. }
  255.  
  256. /*!------------------------------------------------------------------------
  257.  * \fn     decode_1_256(const tStrComp *p_arg, int offset, Word *p_result)
  258.  * \brief  decode argument in range 1..256
  259.  * \param  p_arg source argument
  260.  * \param  p_result encoded result
  261.  * ------------------------------------------------------------------------ */
  262.  
  263. static Boolean decode_1_256(const tStrComp *p_arg, int offset, Word *p_result)
  264. {
  265.   tEvalResult eval_result;
  266.  
  267.   *p_result = EvalStrIntExpressionOffsWithResult(p_arg, offset, UInt9, &eval_result);
  268.   if (!eval_result.OK)
  269.     return False;
  270.  
  271.   if (!mFirstPassUnknownOrQuestionable(eval_result.Flags)
  272.    && !ChkRangePos(*p_result, 1, 256, p_arg))
  273.     return False;
  274.  
  275.   *p_result = (*p_result - 1) & 0xff;
  276.   return True;
  277. }
  278.  
  279. /*!------------------------------------------------------------------------
  280.  * \fn     reset_adr_vals(adr_vals_t *p_vals)
  281.  * \brief  reset/clear decoded address expression
  282.  * \param  p_vals buffer to reset
  283.  * ------------------------------------------------------------------------ */
  284.  
  285. static void reset_adr_vals(adr_vals_t *p_vals)
  286. {
  287.   p_vals->mode = ModNone;
  288.   p_vals->value = 0;
  289. }
  290.  
  291. /*!------------------------------------------------------------------------
  292.  * \fn     chk_auto_increment(const tStrComp *p_arg, tSymbolSize op_size, adr_vals_t *p_result)
  293.  * \brief  iterate over all auto-increment/decrement modes
  294.  * \param  p_arg source argument
  295.  * \param  op_size operand size used in instruction
  296.  * \param  p_result returns decoded addressing mode if match
  297.  * \return eIsReg: match, eIsNoReg: no match, eRegAbort -> error during decoding
  298.  * ------------------------------------------------------------------------ */
  299.  
  300. static tRegEvalResult chk_auto_increment(const tStrComp *p_arg, tSymbolSize op_size, adr_vals_t *p_result)
  301. {
  302.   size_t arg_len = strlen(p_arg->str.p_str);
  303.   Word reg_num;
  304.   String reg_str;
  305.   tStrComp reg_comp;
  306.   int dir, n_half, n_full, pos;
  307.  
  308.   /* Expression is (reg)+...+{'} or (reg)-...-{~}
  309.      Check for opening parenthese and minimum plausible length: */
  310.  
  311.   if ((arg_len < 4) || (p_arg->str.p_str[0] != '('))
  312.     return eIsNoReg;
  313.  
  314.   /* Now walk backwards through string as a little state machine: */
  315.  
  316.   n_full = n_half = dir = 0;
  317.   for (pos = arg_len - 1; p_arg->str.p_str[pos] != ')'; pos--)
  318.   {
  319.     /* Latest pos for closing parenthese */
  320.     if (pos < 2)
  321.       return eIsNoReg;
  322.     switch (p_arg->str.p_str[pos])
  323.     {
  324.       case '\'':
  325.         if (dir)
  326.           return eIsNoReg;
  327.         dir = 1; n_half++;
  328.         break;
  329.       case '~':
  330.         if (dir)
  331.           return eIsNoReg;
  332.         dir = 2; n_half++;
  333.         break;
  334.       case '+':
  335.         if (dir == 2)
  336.           return eIsNoReg;
  337.         dir = 1; n_full++;
  338.         break;
  339.       case '-':
  340.         if (dir == 1)
  341.           return eIsNoReg;
  342.         dir = 2; n_full++;
  343.         break;
  344.       default:
  345.         return eIsNoReg;
  346.     }
  347.   }
  348.  
  349.   /* Impossible combinations: */
  350.  
  351.   switch (op_size)
  352.   {
  353.     case eSymbolSize8Bit:
  354.       if (n_half || (n_full > 4))
  355.         goto too_much;
  356.       break;
  357.     case eSymbolSize16Bit:
  358.       if (n_full > 2 - n_half)
  359.         goto too_much;
  360.       /* convert word to byte count */
  361.       n_full = (n_full * 2) + n_half;
  362.       break;
  363.     default:
  364.     too_much:
  365.       WrStrErrorPos(ErrNum_InvAddrMode, p_arg);
  366.       return eRegAbort;
  367.   }
  368.  
  369.   /* Encode found increment/decrement */
  370.  
  371.   p_result->value = n_full ? (((dir - 1) << 2) | (n_full - 1)) : 8;
  372.  
  373.   /* Test register */
  374.  
  375.   StrCompMkTemp(&reg_comp, reg_str, sizeof(reg_str));
  376.   StrCompCopySub(&reg_comp, p_arg, 1, pos - 1);
  377.   KillPrefBlanksStrComp(&reg_comp);
  378.   KillPostBlanksStrComp(&reg_comp);
  379.   switch (decode_reg(&reg_comp, &reg_num, False))
  380.   {
  381.     case eRegAbort:
  382.       return eRegAbort;
  383.     case eIsReg:
  384.       p_result->value |= reg_num << 4;
  385.       p_result->mode = ModIReg;
  386.       return eIsReg;
  387.     default:
  388.       return eIsNoReg;
  389.   }
  390. }
  391.  
  392. /*!------------------------------------------------------------------------
  393.  * \fn     decode_adr(tStrComp *p_arg, tSymbolSize op_size, unsigned mode_mask)
  394.  * \brief  decode address expression
  395.  * \param  p_arg source argument
  396.  * \param  op_size operand size (8/16 bit)
  397.  * \param  mode_mask bit mask of allowed modes
  398.  * \return register evaluation result: pattern match if eIsReg
  399.  * ------------------------------------------------------------------------ */
  400.  
  401. static adr_mode_t decode_adr(tStrComp *p_arg, tSymbolSize op_size, unsigned mode_mask, adr_vals_t *p_result)
  402. {
  403.   reset_adr_vals(p_result);
  404.  
  405.   /* Rn */
  406.  
  407.   switch (decode_reg(p_arg, &p_result->value, False))
  408.   {
  409.     case eIsReg:
  410.       p_result->mode = ModReg;
  411.       goto check_exit;
  412.     case eRegAbort:
  413.       return p_result->mode;
  414.     default:
  415.       break;
  416.   }
  417.  
  418.   /* #imm */
  419.  
  420.   if (*p_arg->str.p_str == '#')
  421.   {
  422.     tStrComp imm_arg;
  423.     Boolean ok;
  424.  
  425.     StrCompRefRight(&imm_arg, p_arg, 1);
  426.     switch (op_size)
  427.     {
  428.       case eSymbolSize16Bit:
  429.         p_result->value = EvalStrIntExpression(&imm_arg, Int16, &ok);
  430.         break;
  431.       case eSymbolSize8Bit:
  432.         if (mode_mask & MModImmP1)
  433.           ok = decode_1_256(&imm_arg, 0, &p_result->value);
  434.         else
  435.           p_result->value = EvalStrIntExpression(&imm_arg, Int8, &ok) & 0xff;
  436.         break;
  437.       default:
  438.         WrStrErrorPos(ErrNum_InvOpSize, p_arg);
  439.         ok = False;
  440.     }
  441.     if (ok)
  442.       p_result->mode = ModImm;
  443.     goto check_exit;
  444.   }
  445.  
  446.   /* Indirect with modifier: */
  447.  
  448.   switch (chk_auto_increment(p_arg, op_size, p_result))
  449.   {
  450.     case eRegAbort:
  451.       return p_result->mode;
  452.     case eIsReg:
  453.       goto check_exit;
  454.     default:
  455.       break;
  456.   }
  457.  
  458.   /* -> direct address, either 0,2,4 in memory or I/O address */
  459.  
  460.   if (mode_mask & MModIO)
  461.   {
  462.     if (decode_io_address(p_arg, &p_result->value))
  463.       p_result->mode = ModIO;
  464.   }
  465.   else
  466.   {
  467.     if (decode_direct_word_address(p_arg, &p_result->value))
  468.       p_result->mode = ModDir;
  469.   }
  470.  
  471. check_exit:
  472.   if ((p_result->mode != ModNone) && !((mode_mask >> p_result->mode) & 1))
  473.   {
  474.     WrStrErrorPos(ErrNum_InvAddrMode, p_arg);
  475.     reset_adr_vals(p_result);
  476.   }
  477.   return p_result->mode;
  478. }
  479.  
  480. /*!------------------------------------------------------------------------
  481.  * \fn     strip_indirect(tStrComp *p_dest, tStrComp *p_src)
  482.  * \brief  check whether argument is indirect ( '(...)' ) and strip parentheses if yes
  483.  * \param  p_dest where to put stripped argument if source was indirect
  484.  * \param  p_src argument to check
  485.  * \return True if argument was indirect
  486.  * ------------------------------------------------------------------------ */
  487.  
  488. static Boolean strip_indirect(tStrComp *p_dest, tStrComp *p_src)
  489. {
  490.   if (IsIndirect(p_src->str.p_str))
  491.   {
  492.     StrCompRefRight(p_dest, p_src, 1);
  493.     StrCompShorten(p_dest, 1);
  494.     KillPrefBlanksStrCompRef(p_dest);
  495.     KillPostBlanksStrComp(p_dest);
  496.     return True;
  497.   }
  498.   else
  499.     return False;
  500. }
  501.  
  502. /*--------------------------------------------------------------------------*/
  503. /* Decoder Helpers */
  504.  
  505. static void put_code(Word code)
  506. {
  507.   /* Skip instructions only skip the next halfword of code.  If the
  508.      previous instruction was a skip, and we are about to create an
  509.      instruction consisting of more than one halfword, warn about this.
  510.      Note this only happens for 'macro instructions' like JMP,
  511.      LWI or CALL, which are composed of more than one micro instruction: */
  512.  
  513.   if ((2 == CodeLen) && last_was_skip)
  514.     WrStrErrorPos(ErrNum_TrySkipMultiwordInstruction, &OpPart);
  515.  
  516.   WAsmCode[CodeLen / 2] = code;
  517.   CodeLen += 2;
  518. }
  519.  
  520. /*!------------------------------------------------------------------------
  521.  * \fn     check_bra_dist(LongInt dist, Boolean silent)
  522.  * \brief  check whether branch distance is valid for BRA instruction
  523.  * \param  dist distance to check
  524.  * \param  silent issue error messages if not?
  525.  * \return True if distance is OK
  526.  * ------------------------------------------------------------------------ */
  527.  
  528. static Boolean check_bra_dist(LongInt dist, Boolean silent)
  529. {
  530.   if ((dist > 256) || (dist < -256))
  531.   {
  532.     if (!silent) WrStrErrorPos(ErrNum_JmpDistTooBig, &ArgStr[1]);
  533.     return False;
  534.   }
  535.   else if (!dist)
  536.   {
  537.     if (!silent) WrStrErrorPos(ErrNum_JmpDistIsZero, &ArgStr[1]);
  538.     return False;
  539.   }
  540.   else
  541.     return True;
  542. }
  543.  
  544. /*!------------------------------------------------------------------------
  545.  * \fn     append_bra(LongInt dist)
  546.  * \brief  append BRA machine instruction with given distance
  547.  * \param  dist branch distance (must have been checked before)
  548.  * ------------------------------------------------------------------------ */
  549.  
  550. static void encode_bra(LongInt dist)
  551. {
  552.   if (dist > 0)
  553.     put_code(0xa000 | ((dist - 1) & 0xff));
  554.   else
  555.     put_code(0xf000 | ((-dist - 1) & 0xff));
  556. }
  557.  
  558. /*!------------------------------------------------------------------------
  559.  * \fn     put_bra(const tStrComp *p_arg, int pc_offset)
  560.  * \brief  append a relative branch to generated code
  561.  * \param  p_arg source argument of branch target address
  562.  * \param  pc_offset assumed PC offset to beginning of this instruction
  563.  * ------------------------------------------------------------------------ */
  564.  
  565. static Boolean put_bra(const tStrComp *p_arg, int pc_offset)
  566. {
  567.   Word address;
  568.   tEvalResult eval_result;
  569.  
  570.   if (decode_code_address(p_arg, &address, &eval_result))
  571.   {
  572.     LongInt dist = address - (EProgCounter() + pc_offset);
  573.  
  574.     if (!mFirstPassUnknownOrQuestionable(eval_result.Flags)
  575.      && !check_bra_dist(dist, False))
  576.         return False;
  577.  
  578.     encode_bra(dist);
  579.     return True;
  580.   }
  581.   else
  582.     return False;
  583. }
  584.  
  585.  
  586. /*--------------------------------------------------------------------------*/
  587. /* Instruction handlers/decoders */
  588.  
  589. /*!------------------------------------------------------------------------
  590.  * \fn     decode_fixed(Word Code)
  591.  * \brief  handle instructions without argument
  592.  * \param  code machine code
  593.  * ------------------------------------------------------------------------ */
  594.  
  595. static void decode_fixed(Word code)
  596. {
  597.   if (ChkArgCnt(0, 0))
  598.     put_code(code);
  599. }
  600.  
  601. /*!------------------------------------------------------------------------
  602.  * \fn     decode_basic_jump(Word Code)
  603.  * \brief  handle fundamental jumps (opcode group C)
  604.  * \param  code machine code
  605.  * ------------------------------------------------------------------------ */
  606.  
  607. static void decode_basic_jump(Word code)
  608. {
  609.   unsigned arg_cnt = Hi(code) & 0x0f;
  610.   Word data_reg, mask_reg = 0;
  611.  
  612.   if (ChkArgCnt(arg_cnt, arg_cnt)
  613.    && decode_reg(&ArgStr[1], &data_reg, True)
  614.    && ((arg_cnt < 2) || decode_reg(&ArgStr[2], &mask_reg, True)))
  615.   {
  616.     put_code((data_reg << 8) | (mask_reg << 4) | (code & 0xf00f));
  617.     this_was_skip = True;
  618.   }
  619. }
  620.  
  621. /*!------------------------------------------------------------------------
  622.  * \fn     decode_basic_arith(Word Code)
  623.  * \brief  handle fundamental arithmetic ops (opcode group 0)
  624.  * \param  code machine code
  625.  * ------------------------------------------------------------------------ */
  626.  
  627. static void decode_basic_arith(Word code)
  628. {
  629.   unsigned min_arg_cnt = Hi(code) & 0x0f;
  630.   Word reg2;
  631.  
  632.   if (ChkArgCnt(min_arg_cnt, 2)
  633.    && decode_reg(&ArgStr[1], &reg2, True))
  634.   {
  635.     Word reg1 = reg2;
  636.  
  637.     if ((ArgCnt == 1) || decode_reg(&ArgStr[2], &reg1, True))
  638.  
  639.     put_code((reg2 << 8) | (reg1 << 4) | (code & 0xf00f));
  640.   }
  641. }
  642.  
  643. /*!------------------------------------------------------------------------
  644.  * \fn     decode_add_sub(Word Code)
  645.  * \brief  handle ADD/SUB instructions
  646.  * \param  code machine code
  647.  * ------------------------------------------------------------------------ */
  648.  
  649. static void decode_add_sub(Word code)
  650. {
  651.   adr_vals_t dest_adr_vals, src_adr_vals;
  652.  
  653.   if (ChkArgCnt(2, 2))
  654.     switch (decode_adr(&ArgStr[1], eSymbolSize8Bit, MModReg, &dest_adr_vals))
  655.     {
  656.       case ModReg:
  657.         switch (decode_adr(&ArgStr[2], eSymbolSize8Bit, MModReg | MModImm | MModImmP1, &src_adr_vals))
  658.         {
  659.           case ModReg:
  660.             put_code(0x0000 | (dest_adr_vals.value << 8) | (src_adr_vals.value << 4) | (code & 0x000f));
  661.             break;
  662.           case ModImm:
  663.             put_code((code & 0xf000) | (dest_adr_vals.value << 8) | (src_adr_vals.value << 0));
  664.             break;
  665.           default:
  666.             break;
  667.         }
  668.         break;
  669.       default:
  670.         break;
  671.     }
  672. }
  673.  
  674. /*!------------------------------------------------------------------------
  675.  * \fn     decode_and_or(Word Code)
  676.  * \brief  handle AND/OR instructions
  677.  * \param  code machine code
  678.  * ------------------------------------------------------------------------ */
  679.  
  680. static void decode_and_or(Word code)
  681. {
  682.   adr_vals_t dest_adr_vals, src_adr_vals;
  683.  
  684.   if (ChkArgCnt(2, 2))
  685.     switch (decode_adr(&ArgStr[1], eSymbolSize8Bit, MModReg, &dest_adr_vals))
  686.     {
  687.       case ModReg:
  688.         switch (decode_adr(&ArgStr[2], eSymbolSize8Bit, MModReg | MModImm, &src_adr_vals))
  689.         {
  690.           case ModReg:
  691.             put_code(0x0000 | (dest_adr_vals.value << 8) | (src_adr_vals.value << 4) | (code & 0x000f));
  692.             break;
  693.           case ModImm:
  694.             /* AND Rn, #nn is CLRI Rn with complement of argument */
  695.             if ((code &= 0xf000) == 0x9000) src_adr_vals.value^= 0xff;
  696.             put_code(code | (dest_adr_vals.value << 8) | (src_adr_vals.value << 0));
  697.             break;
  698.           default:
  699.             break;
  700.         }
  701.         break;
  702.       default:
  703.         break;
  704.     }
  705. }
  706.  
  707. /*!------------------------------------------------------------------------
  708.  * \fn     decode_basic_io(Word Code)
  709.  * \brief  handle fundamental arithmetic ops with I/O address (opcode group 0)
  710.  * \param  code machine code
  711.  * ------------------------------------------------------------------------ */
  712.  
  713. static void decode_basic_io(Word code)
  714. {
  715.   Word reg1, address;
  716.  
  717.   if (ChkArgCnt(2, 2)
  718.    && decode_reg(&ArgStr[2], &reg1, True)
  719.    && decode_io_address(&ArgStr[1], &address))
  720.     put_code(0x0000 | (address << 8) | (reg1 << 4) | (code & 0x0f));
  721. }
  722.  
  723. /*!------------------------------------------------------------------------
  724.  * \fn     decode_shift_rotate(Word code)
  725.  * \brief  handle basic shift & rotate instructions
  726.  * \param  code machine code
  727.  * ------------------------------------------------------------------------ */
  728.  
  729. static void decode_shift_rotate(Word code)
  730. {
  731.   Word reg1;
  732.  
  733.   if (ChkArgCnt(1, 1)
  734.    && decode_reg(&ArgStr[1], &reg1, True))
  735.     put_code(code | (reg1 << 4));
  736. }
  737.  
  738. /*!------------------------------------------------------------------------
  739.  * \fn     decode_mem_direct(Word code)
  740.  * \brief  handle direct memory addressing instructions
  741.  * \param  code machine code
  742.  * ------------------------------------------------------------------------ */
  743.  
  744. static void decode_mem_direct(Word code)
  745. {
  746.   Word reg1, da;
  747.  
  748.   if (ChkArgCnt(2, 2)
  749.    && decode_reg(&ArgStr[1], &reg1, True)
  750.    && decode_direct_word_address(&ArgStr[2], &da))
  751.     put_code(code | (reg1 << 8) | (da & 0xff));
  752. }
  753.  
  754. /*!------------------------------------------------------------------------
  755.  * \fn     decode_mem_indirect(Word code)
  756.  * \brief  handle indirect memory addressing instructions
  757.  * \param  code machine code
  758.  * ------------------------------------------------------------------------ */
  759.  
  760. static void decode_mem_indirect(Word code)
  761. {
  762.   Word reg1, reg2, modifier = MODIFIER_0;
  763.  
  764.   if (ChkArgCnt(2, 3)
  765.    && decode_reg(&ArgStr[1], &reg1, True)
  766.    && decode_reg(&ArgStr[2], &reg2, True)
  767.    && ((ArgCnt < 3) || decode_indirect_modifier(&ArgStr[3], &modifier)))
  768.     put_code(code | (reg1 << 8) | (reg2 << 4) | modifier);
  769. }
  770.  
  771. /*!------------------------------------------------------------------------
  772.  * \fn     decode_reg_imm8(Word code)
  773.  * \brief  handle memory-to-immediate instructions
  774.  * \param  code machine code
  775.  * ------------------------------------------------------------------------ */
  776.  
  777. static void decode_reg_imm8(Word code)
  778. {
  779.   Word reg1;
  780.  
  781.   if (ChkArgCnt(2, 2)
  782.    && decode_reg(&ArgStr[1], &reg1, True))
  783.   {
  784.     Boolean ok;
  785.     Word imm_val = EvalStrIntExpressionOffs(&ArgStr[2], !!(ArgStr[2].str.p_str[0] == '#'), Int8, &ok);
  786.  
  787.     if (ok)
  788.       put_code(code | (reg1 << 8) | (imm_val & 0xff));
  789.   }
  790. }
  791.  
  792. /*!------------------------------------------------------------------------
  793.  * \fn     decode_reg_imm8p1(Word code)
  794.  * \brief  handle memory-to-immediate-plus-one instructions
  795.  * \param  code machine code
  796.  * ------------------------------------------------------------------------ */
  797.  
  798. static void decode_reg_imm8p1(Word code)
  799. {
  800.   Word reg1, imm_val;
  801.  
  802.   if (ChkArgCnt(2, 2)
  803.    && decode_reg(&ArgStr[1], &reg1, True)
  804.    && decode_1_256(&ArgStr[2], !!(ArgStr[2].str.p_str[0] == '#'), &imm_val))
  805.     put_code(code | (reg1 << 8) | (imm_val & 0xff));
  806. }
  807.  
  808. /*!------------------------------------------------------------------------
  809.  * \fn     decode_lwi(Word code)
  810.  * \brief  handle LWI instruction
  811.  * \param  code machine code
  812.  * ------------------------------------------------------------------------ */
  813.  
  814. static void decode_lwi(Word code)
  815. {
  816.   Word reg1;
  817.  
  818.   UNUSED(code);
  819.  
  820.   if (ChkArgCnt(2, 2)
  821.    && decode_reg(&ArgStr[1], &reg1, True))
  822.   {
  823.     Boolean ok;
  824.     Word imm_val = EvalStrIntExpressionOffs(&ArgStr[2], !!(ArgStr[2].str.p_str[0] == '#'), Int16, &ok);
  825.  
  826.     if (ok)
  827.     {
  828.       put_code(0xd001 | (reg1 << 8));
  829.       put_code(imm_val);
  830.     }
  831.   }
  832. }
  833.  
  834. /*!------------------------------------------------------------------------
  835.  * \fn     decode_ctl(Word code)
  836.  * \brief  handle CTL instruction
  837.  * \param  code machine code
  838.  * ------------------------------------------------------------------------ */
  839.  
  840. static void decode_ctl(Word code)
  841. {
  842.   Word address;
  843.  
  844.   if (ChkArgCnt(2, 2)
  845.     && decode_io_address(&ArgStr[1], &address))
  846.   {
  847.     Boolean ok;
  848.     Word command = EvalStrIntExpressionOffs(&ArgStr[2], !!(ArgStr[2].str.p_str[0] == '#'), Int8, &ok);
  849.  
  850.     if (ok)
  851.       put_code(code | (address << 8) | (command & 0xff));
  852.   }
  853. }
  854.  
  855. /*!------------------------------------------------------------------------
  856.  * \fn     decode_io_transfer(Word code)
  857.  * \brief  handle I/O transfer instructions
  858.  * \param  code machine code
  859.  * ------------------------------------------------------------------------ */
  860.  
  861. static void decode_io_transfer(Word code)
  862. {
  863.   Word address, reg1, modifier = MODIFIER_0;
  864.  
  865.   if (ChkArgCnt(2, 3)
  866.    && decode_io_address(&ArgStr[1], &address)
  867.    && decode_reg(&ArgStr[2], &reg1, True)
  868.    && ((ArgCnt < 3) || decode_indirect_modifier(&ArgStr[3], &modifier)))
  869.     put_code(code | (address << 8) | (reg1 << 4) | modifier);
  870. }
  871.  
  872. /*!------------------------------------------------------------------------
  873.  * \fn     decode_getrb(Word code)
  874.  * \brief  handle GETRB instruction
  875.  * \param  code machine code
  876.  * ------------------------------------------------------------------------ */
  877.  
  878. static void decode_getrb(Word code)
  879. {
  880.   Word address, reg1;
  881.  
  882.   if (ChkArgCnt(2, 2)
  883.    && decode_io_address(&ArgStr[1], &address)
  884.    && decode_reg(&ArgStr[2], &reg1, True))
  885.     put_code(code | (address << 8) | (reg1 << 4));
  886. }
  887.  
  888. /*!------------------------------------------------------------------------
  889.  * \fn     decode_stat(Word code)
  890.  * \brief  handle STAT instruction
  891.  * \param  code machine code
  892.  * ------------------------------------------------------------------------ */
  893.  
  894. static void decode_stat(Word code)
  895. {
  896.   Word address, reg1;
  897.  
  898.   if (ChkArgCnt(2, 2)
  899.    && decode_io_address(&ArgStr[2], &address)
  900.    && decode_reg(&ArgStr[1], &reg1, True))
  901.     put_code(code | (address << 8) | (reg1 << 4));
  902. }
  903.  
  904. /*!------------------------------------------------------------------------
  905.  * \fn     decode_getb(Word code)
  906.  * \brief  handle GETB instruction
  907.  * \param  code machine code
  908.  * ------------------------------------------------------------------------ */
  909.  
  910. static void decode_getb(Word code)
  911. {
  912.   UNUSED(code);
  913.  
  914.   /* The original IBM syntax is GETB ioaddr,Rn[,mod]
  915.      Corti unified all instructions to have the destination be the first argument: */
  916.  
  917.   switch (ArgCnt)
  918.   {
  919.     case 3: /* only IBM syntax with three args: GETB ioaddr,Rn,mod */
  920.       decode_io_transfer(0xe000);
  921.       break;
  922.     case 2:
  923.     {
  924.       adr_vals_t dest_adr_vals, src_adr_vals;
  925.  
  926.       switch (decode_adr(&ArgStr[1], eSymbolSize8Bit, MModIO | MModReg | MModIReg, &dest_adr_vals))
  927.       {
  928.         case ModIO: /* GETB ioaddr,... */
  929.           switch (decode_adr(&ArgStr[2], eSymbolSize8Bit, MModReg, &src_adr_vals))
  930.           {
  931.             case ModReg:
  932.               put_code(0xe000 | (dest_adr_vals.value << 8) | (src_adr_vals.value << 4) | MODIFIER_0);
  933.               break;
  934.             default:
  935.               break;
  936.           }
  937.           break;
  938.         case ModReg: /* GETB Rn,... */
  939.           switch (decode_adr(&ArgStr[2], eSymbolSize8Bit, MModIO, &src_adr_vals))
  940.           {
  941.             case ModIO:
  942.               put_code(0x000e | (src_adr_vals.value << 8) | (dest_adr_vals.value << 4));
  943.               break;
  944.             default:
  945.               break;
  946.           }
  947.           break;
  948.         case ModIReg: /* GETB (Rn)...,... */
  949.           switch (decode_adr(&ArgStr[2], eSymbolSize8Bit, MModIO, &src_adr_vals))
  950.           {
  951.             case ModIO:
  952.               put_code(0xe000 | (src_adr_vals.value << 8) | (dest_adr_vals.value << 0));
  953.               break;
  954.             default:
  955.               break;
  956.           }
  957.           break;
  958.         default:
  959.           break;
  960.       }
  961.       break;
  962.     }
  963.     default:
  964.       (void)ChkArgCnt(2, 3);
  965.   }
  966. }
  967.  
  968. /*!------------------------------------------------------------------------
  969.  * \fn     decode_putb(Word code)
  970.  * \brief  handle PUTB instruction
  971.  * \param  code machine code
  972.  * ------------------------------------------------------------------------ */
  973.  
  974. static void decode_putb(Word code)
  975. {
  976.   UNUSED(code);
  977.  
  978.   /* The original IBM syntax is PUTB ioaddr,Rn[,mod] with 2 or 3 arguments
  979.      'Corti' syntax puts modifier into second argument: */
  980.  
  981.   switch (ArgCnt)
  982.   {
  983.     case 3: /* only IBM syntax with three args: PUTB ioaddr,Rn[,mod] */
  984.       decode_io_transfer(0x4000);
  985.       break;
  986.     case 2:
  987.     {
  988.       Word address;
  989.       adr_vals_t src_adr_vals;
  990.  
  991.       if (decode_io_address(&ArgStr[1], &address))
  992.         switch (decode_adr(&ArgStr[2], eSymbolSize8Bit, MModReg | MModIReg, &src_adr_vals))
  993.         {
  994.           case ModReg:
  995.             put_code(0x4000 | (address << 8) | (src_adr_vals.value << 4) | MODIFIER_0);
  996.             break;
  997.           case ModIReg:
  998.             put_code(0x4000 | (address << 8) | (src_adr_vals.value << 0));
  999.             break;
  1000.           default:
  1001.             break;
  1002.         }
  1003.       break;
  1004.     }
  1005.     default:
  1006.       (void)ChkArgCnt(2, 3);
  1007.   }
  1008. }
  1009.  
  1010. /*!------------------------------------------------------------------------
  1011.  * \fn     decode_getadd(Word Code)
  1012.  * \brief  handle GETADD instruction
  1013.  * \param  code machine code
  1014.  * ------------------------------------------------------------------------ */
  1015.  
  1016. static void decode_getadd(Word code)
  1017. {
  1018.   Word reg, address;
  1019.  
  1020.   if (ChkArgCnt(2, 2)
  1021.    && decode_reg(&ArgStr[1], &reg, True)
  1022.    && decode_io_address(&ArgStr[2], &address))
  1023.     put_code(0x0000 | (address << 8) | (reg << 4) | (code & 0x0f));
  1024. }
  1025.  
  1026. /*!------------------------------------------------------------------------
  1027.  * \fn     decode_move(Word Code)
  1028.  * \brief  handle MOVE instruction
  1029.  * \param  code machine code
  1030.  * ------------------------------------------------------------------------ */
  1031.  
  1032. static void decode_move(Word code)
  1033. {
  1034.   adr_vals_t dest_adr_vals, src_adr_vals;
  1035.  
  1036.   UNUSED(code);
  1037.  
  1038.   if (ChkArgCnt(2, 2))
  1039.     switch (decode_adr(&ArgStr[1], eSymbolSize16Bit, MModDir | MModReg | MModIReg, &dest_adr_vals))
  1040.     {
  1041.       case ModReg: /* MOVE Rn,... */
  1042.         switch (decode_adr(&ArgStr[2], eSymbolSize16Bit, MModDir | MModReg | MModIReg | MModImm, &src_adr_vals))
  1043.         {
  1044.           case ModReg:
  1045.             put_code(0x0004 | (dest_adr_vals.value << 8) | (src_adr_vals.value << 4));
  1046.             break;
  1047.           case ModDir:
  1048.             put_code(0x2000 | (dest_adr_vals.value << 8) | (src_adr_vals.value << 0));
  1049.             break;
  1050.           case ModIReg:
  1051.             put_code(0xd000 | (dest_adr_vals.value << 8) | (src_adr_vals.value << 0));
  1052.             break;
  1053.           case ModImm:
  1054.             put_code(0xd001 | (dest_adr_vals.value << 8));
  1055.             put_code(src_adr_vals.value);
  1056.             break;
  1057.           default:
  1058.             break;
  1059.         }
  1060.         break;
  1061.       case ModIReg: /* MOVE (Rn),... */
  1062.         switch (decode_adr(&ArgStr[2], eSymbolSize16Bit, MModReg, &src_adr_vals))
  1063.         {
  1064.           case ModReg:
  1065.             put_code(0x5000 | (src_adr_vals.value << 8) | (dest_adr_vals.value << 0));
  1066.             break;
  1067.           default:
  1068.             break;
  1069.         }
  1070.         break;
  1071.       case ModDir: /* MOVE addr,... */
  1072.         switch (decode_adr(&ArgStr[2], eSymbolSize16Bit, MModReg, &src_adr_vals))
  1073.         {
  1074.           case ModReg:
  1075.             put_code(0x3000 | (src_adr_vals.value << 8) | (dest_adr_vals.value << 0));
  1076.             break;
  1077.           default:
  1078.             break;
  1079.         }
  1080.         break;
  1081.       default:
  1082.         break;
  1083.     }
  1084. }
  1085.  
  1086. /*!------------------------------------------------------------------------
  1087.  * \fn     decode_movb(Word Code)
  1088.  * \brief  handle MOVB instruction
  1089.  * \param  code machine code
  1090.  * ------------------------------------------------------------------------ */
  1091.  
  1092. static void decode_movb(Word code)
  1093. {
  1094.   adr_vals_t dest_adr_vals, src_adr_vals;
  1095.  
  1096.   UNUSED(code);
  1097.  
  1098.   if (ChkArgCnt(2, 2))
  1099.     switch (decode_adr(&ArgStr[1], eSymbolSize8Bit, MModReg | MModIReg, &dest_adr_vals))
  1100.     {
  1101.       case ModReg: /* MOVB Rn,... */
  1102.         switch (decode_adr(&ArgStr[2], eSymbolSize8Bit, MModIReg | MModImm, &src_adr_vals))
  1103.         {
  1104.           case ModIReg:
  1105.             put_code(0x6000 | (dest_adr_vals.value << 8) | (src_adr_vals.value << 0));
  1106.             break;
  1107.           case ModImm:
  1108.             put_code(0x8000 | (dest_adr_vals.value << 8) | (src_adr_vals.value << 0));
  1109.             break;
  1110.           default:
  1111.             break;
  1112.         }
  1113.         break;
  1114.       case ModIReg: /* MOVB (Rn)...,... */
  1115.         switch (decode_adr(&ArgStr[2], eSymbolSize8Bit, MModReg, &src_adr_vals))
  1116.         {
  1117.           case ModReg:
  1118.             put_code(0x7000 | (src_adr_vals.value << 8) | (dest_adr_vals.value << 0));
  1119.             break;
  1120.           default:
  1121.             break;
  1122.         }
  1123.         break;
  1124.       default:
  1125.         break;
  1126.     }
  1127. }
  1128.  
  1129. /*!------------------------------------------------------------------------
  1130.  * \fn     decode_bra(Word Code)
  1131.  * \brief  handle BRA instruction
  1132.  * \param  code machine code
  1133.  * ------------------------------------------------------------------------ */
  1134.  
  1135. static void decode_bra(Word code)
  1136. {
  1137.   UNUSED(code);
  1138.  
  1139.   if (ChkArgCnt(1, 1))
  1140.     put_bra(&ArgStr[1], 2);
  1141. }
  1142.  
  1143. /*!------------------------------------------------------------------------
  1144.  * \fn     decode_jmp(Word Code)
  1145.  * \brief  handle JMP instruction
  1146.  * \param  code machine code
  1147.  * ------------------------------------------------------------------------ */
  1148.  
  1149. static void decode_jmp(Word code)
  1150. {
  1151.   UNUSED(code);
  1152.  
  1153.   if (ChkArgCnt(1, 1))
  1154.   {
  1155.     tStrComp ind_comp;
  1156.     Word addr_or_reg;
  1157.     adr_vals_t adr_vals;
  1158.  
  1159.     /* Extra handling for auto-increment/deceement since it did not fit
  1160.        in here easily otherwise: */
  1161.  
  1162.     switch (chk_auto_increment(&ArgStr[1], eSymbolSize16Bit, &adr_vals))
  1163.     {
  1164.       case eRegAbort:
  1165.         return;
  1166.       case eIsReg: /* JMP (Rn)*** -> LDHI PC,Rn,*** */
  1167.         put_code(0xd000 | adr_vals.value);
  1168.         return;
  1169.       default:
  1170.         break;
  1171.     }
  1172.  
  1173.     if (strip_indirect(&ind_comp, &ArgStr[1]))
  1174.     {
  1175.       switch (decode_adr(&ind_comp, eSymbolSize16Bit, MModDir | MModReg, &adr_vals))
  1176.       {
  1177.         case ModDir: /* JMP (addr) -> LDHD PC, addr */
  1178.           put_code(0x2000 | adr_vals.value);
  1179.           break;
  1180.         case ModReg: /* JMP (Rn) -> LDHI PC, Rn */
  1181.           put_code(0xd008 | (adr_vals.value << 4));
  1182.           break;
  1183.         default:
  1184.           break;
  1185.       }
  1186.     }
  1187.  
  1188.     else switch (decode_reg(&ArgStr[1], &addr_or_reg, False))
  1189.     {
  1190.       case eIsNoReg:
  1191.       {
  1192.         tEvalResult eval_result;
  1193.         Boolean force_long = !!(*ArgStr[1].str.p_str == '>');
  1194.         tStrComp addr_comp;
  1195.  
  1196.         StrCompRefRight(&addr_comp, &ArgStr[1], force_long);
  1197.         if (decode_code_address(&addr_comp, &addr_or_reg, &eval_result))
  1198.         {
  1199.           LongInt dist = addr_or_reg - (EProgCounter() + 2);
  1200.  
  1201.           if (check_bra_dist(dist, True) && !force_long)
  1202.             /* JMP addr -> BRA addr */
  1203.             encode_bra(dist);
  1204.  
  1205.           else
  1206.           {
  1207.             /* JMP addr -> LDHI PC,PC,2 ; DW addr */
  1208.             put_code(0xd001);
  1209.             put_code(addr_or_reg);
  1210.           }
  1211.         }
  1212.         break;
  1213.       }
  1214.       case eIsReg:
  1215.         /* JMP Rn -> MOVE PC, Rn */
  1216.         put_code(0x0004 | (addr_or_reg << 4));
  1217.         break;
  1218.       default:
  1219.         break;
  1220.     }
  1221.   }
  1222. }
  1223.  
  1224. /*!------------------------------------------------------------------------
  1225.  * \fn     decode_call(Word Code)
  1226.  * \brief  handle CALL instruction
  1227.  * \param  code machine code
  1228.  * ------------------------------------------------------------------------ */
  1229.  
  1230. static void decode_call(Word code)
  1231. {
  1232.   Word link_reg;
  1233.  
  1234.   UNUSED(code);
  1235.  
  1236.   if (ChkArgCnt(2, 2)
  1237.    && decode_reg(&ArgStr[2], &link_reg, True))
  1238.   {
  1239.     tStrComp ind_comp;
  1240.     Word addr_or_reg;
  1241.  
  1242.     if (strip_indirect(&ind_comp, &ArgStr[1]))
  1243.     {
  1244.       adr_vals_t adr_vals;
  1245.  
  1246.       switch (decode_adr(&ind_comp, eSymbolSize16Bit, MModReg, &adr_vals))
  1247.       {
  1248.         case ModReg: /* CALL (Rn),Rl -> MVP2 Rl,PC ; LDHI PC, Rn */
  1249.           put_code(0x0003 | (link_reg << 8));
  1250.           put_code(0xd008 | (adr_vals.value << 4));
  1251.           break;
  1252.         default:
  1253.           break;
  1254.       }
  1255.     }
  1256.  
  1257.     else switch (decode_reg(&ArgStr[1], &addr_or_reg, False))
  1258.     {
  1259.       case eIsNoReg:
  1260.       {
  1261.         tEvalResult eval_result;
  1262.  
  1263.         if (decode_code_address(&ArgStr[1], &addr_or_reg, &eval_result))
  1264.         {
  1265.           /* CALL <addr>,Rl -> MVP2 Rl,PC ; LDHI PC,Rl,2 ; DW <addr> */
  1266.           put_code(0x0003 | (link_reg << 8));
  1267.           put_code(0xd001 | (link_reg << 4));
  1268.           put_code(addr_or_reg);
  1269.         }
  1270.         break;
  1271.       }
  1272.       case eIsReg:
  1273.         /* CALL Rn,Rl -> MVP2 Rl,PC ; MOVE PC,Rn */
  1274.         put_code(0x0003 | (link_reg << 8));
  1275.         put_code(0x0004 | (addr_or_reg << 4));
  1276.         break;
  1277.       default:
  1278.         break;
  1279.     }
  1280.   }
  1281. }
  1282.  
  1283. /*!------------------------------------------------------------------------
  1284.  * \fn     decode_rcall(Word Code)
  1285.  * \brief  handle RCALL instruction
  1286.  * \param  code machine code
  1287.  * ------------------------------------------------------------------------ */
  1288.  
  1289. static void decode_rcall(Word code)
  1290. {
  1291.   Word link_reg;
  1292.  
  1293.   UNUSED(code);
  1294.  
  1295.   if (ChkArgCnt(2, 2)
  1296.    && decode_reg(&ArgStr[2], &link_reg, True))
  1297.   {
  1298.     /* RCALL <addr>,Rl -> MVP2 Rl,PC ; BRA <addr> */
  1299.     put_code(0x0003 | (link_reg << 8));
  1300.     if (!put_bra(&ArgStr[1], 4))
  1301.       CodeLen = 0;
  1302.   }
  1303. }
  1304.  
  1305. /*!------------------------------------------------------------------------
  1306.  * \fn     decode_ret(Word Code)
  1307.  * \brief  handle RET instruction
  1308.  * \param  code machine code
  1309.  * ------------------------------------------------------------------------ */
  1310.  
  1311. static void decode_ret(Word code)
  1312. {
  1313.   Word link_reg;
  1314.  
  1315.   UNUSED(code);
  1316.  
  1317.   if (ChkArgCnt(1, 1)
  1318.    && decode_reg(&ArgStr[1], &link_reg, True))
  1319.     put_code(0x0004 | (link_reg << 4));
  1320. }
  1321.  
  1322. /*!------------------------------------------------------------------------
  1323.  * \fn     decode_pseudo(void)
  1324.  * \brief  handle pseudo instructions
  1325.  * \return True if handled
  1326.  * ------------------------------------------------------------------------ */
  1327.  
  1328. static Boolean decode_pseudo(void)
  1329. {
  1330.   if (Memo("REG"))
  1331.   {
  1332.     CodeREG(0);
  1333.     return True;
  1334.   }
  1335.  
  1336.   if (Memo("PORT"))
  1337.   {
  1338.     CodeEquate(SegIO, 0, SegLimits[SegIO]);
  1339.     return True;
  1340.   }
  1341.  
  1342.   return False;
  1343. }
  1344.  
  1345. /*--------------------------------------------------------------------------*/
  1346. /* Instruction Lookup Table */
  1347.  
  1348. /*!------------------------------------------------------------------------
  1349.  * \fn     init_fields(void)
  1350.  * \brief  create lookup table
  1351.  * ------------------------------------------------------------------------ */
  1352.  
  1353. static void init_fields(void)
  1354. {
  1355.   InstTable = CreateInstTable(201);
  1356.  
  1357.   AddInstTable(InstTable, "NOP"  , NOPCode, decode_fixed); /* C */
  1358.   AddInstTable(InstTable, "HALT" , 0x0000 , decode_fixed); /* C */
  1359.  
  1360.   AddInstTable(InstTable, "JLE"  , 0xc200, decode_basic_jump); /* I */
  1361.   AddInstTable(InstTable, "JLO"  , 0xc201, decode_basic_jump); /* I */
  1362.   AddInstTable(InstTable, "JEQ"  , 0xc202, decode_basic_jump); /* I */
  1363.   AddInstTable(InstTable, "JNO"  , 0xc103, decode_basic_jump); /* I */
  1364.   AddInstTable(InstTable, "JALL" , 0xc204, decode_basic_jump); /* I */
  1365.   AddInstTable(InstTable, "JALLM", 0xc205, decode_basic_jump); /* I */
  1366.   AddInstTable(InstTable, "JNOM" , 0xc206, decode_basic_jump); /* I */
  1367.   AddInstTable(InstTable, "JHAM" , 0xc207, decode_basic_jump); /* I */
  1368.   AddInstTable(InstTable, "JHI"  , 0xc208, decode_basic_jump); /* I */
  1369.   AddInstTable(InstTable, "JHE"  , 0xc209, decode_basic_jump); /* I */
  1370.   AddInstTable(InstTable, "JHL"  , 0xc20a, decode_basic_jump); /* I */
  1371.   AddInstTable(InstTable, "JSB"  , 0xc10b, decode_basic_jump); /* I */
  1372.   AddInstTable(InstTable, "JSN"  , 0xc20c, decode_basic_jump); /* I */
  1373.   AddInstTable(InstTable, "JSNM" , 0xc20d, decode_basic_jump); /* I */
  1374.   AddInstTable(InstTable, "JSM"  , 0xc20e, decode_basic_jump); /* I */
  1375.   AddInstTable(InstTable, "JHSNM", 0xc20f, decode_basic_jump); /* I */
  1376.  
  1377.   AddInstTable(InstTable, "SLE"  , 0xc200, decode_basic_jump); /* C */
  1378.   AddInstTable(InstTable, "SLT"  , 0xc201, decode_basic_jump); /* C */
  1379.   AddInstTable(InstTable, "SE"   , 0xc202, decode_basic_jump); /* C */
  1380.   AddInstTable(InstTable, "SZ"   , 0xc103, decode_basic_jump); /* C */
  1381.   AddInstTable(InstTable, "SS"   , 0xc104, decode_basic_jump); /* C */
  1382.   AddInstTable(InstTable, "SBS"  , 0xc205, decode_basic_jump); /* C */
  1383.   AddInstTable(InstTable, "SBC"  , 0xc206, decode_basic_jump); /* C */
  1384.   AddInstTable(InstTable, "SBSH" , 0xc207, decode_basic_jump); /* C */
  1385.   AddInstTable(InstTable, "SGT"  , 0xc208, decode_basic_jump); /* C */
  1386.   AddInstTable(InstTable, "SGE"  , 0xc209, decode_basic_jump); /* C */
  1387.   AddInstTable(InstTable, "SNE"  , 0xc20a, decode_basic_jump); /* C */
  1388.   AddInstTable(InstTable, "SNZ"  , 0xc10b, decode_basic_jump); /* C */
  1389.   AddInstTable(InstTable, "SNS"  , 0xc10c, decode_basic_jump); /* C */
  1390.   AddInstTable(InstTable, "SNBS" , 0xc20d, decode_basic_jump); /* C */
  1391.   AddInstTable(InstTable, "SNBC" , 0xc20e, decode_basic_jump); /* C */
  1392.   AddInstTable(InstTable, "SNBSH", 0xc20f, decode_basic_jump); /* C */
  1393.  
  1394.   AddInstTable(InstTable, "MVM2" , 0x0200, decode_basic_arith); /* I */
  1395.   AddInstTable(InstTable, "MVM1" , 0x0201, decode_basic_arith); /* I */
  1396.   AddInstTable(InstTable, "MVP1" , 0x0202, decode_basic_arith); /* I */
  1397.   AddInstTable(InstTable, "MVP2" , 0x0203, decode_basic_arith); /* I */
  1398.   AddInstTable(InstTable, "MOVE" , 0x0000, decode_move); /* I/C */
  1399.   AddInstTable(InstTable, "AND"  , 0x9005, decode_and_or); /* I/A */
  1400.   AddInstTable(InstTable, "OR"   , 0xb006, decode_and_or); /* I/A */
  1401.   AddInstTable(InstTable, "ORB"  , 0xb006, decode_and_or); /* I/A */
  1402.   AddInstTable(InstTable, "XOR"  , 0x0207, decode_basic_arith); /* I */
  1403.   AddInstTable(InstTable, "ADD"  , 0xa008, decode_add_sub); /* I/C */
  1404.   AddInstTable(InstTable, "SUB"  , 0xf009, decode_add_sub); /* I/C */
  1405.   AddInstTable(InstTable, "ADDS1", 0x020a, decode_basic_arith); /* I */
  1406.   AddInstTable(InstTable, "ADDS2", 0x020b, decode_basic_arith); /* I */
  1407.   AddInstTable(InstTable, "HTL"  , 0x020c, decode_basic_arith); /* I */
  1408.   AddInstTable(InstTable, "LTH"  , 0x020d, decode_basic_arith); /* I */
  1409.  
  1410.   AddInstTable(InstTable, "DEC2" , 0x0100, decode_basic_arith); /* C */
  1411.   AddInstTable(InstTable, "DEC"  , 0x0101, decode_basic_arith); /* C */
  1412.   AddInstTable(InstTable, "INC"  , 0x0102, decode_basic_arith); /* C */
  1413.   AddInstTable(InstTable, "INC2" , 0x0103, decode_basic_arith); /* C */
  1414.   AddInstTable(InstTable, "ADDH" , 0x020a, decode_basic_arith); /* C */
  1415.   AddInstTable(InstTable, "ADDH2", 0x020b, decode_basic_arith); /* C */
  1416.   AddInstTable(InstTable, "MHL"  , 0x020c, decode_basic_arith); /* C */
  1417.   AddInstTable(InstTable, "MLH"  , 0x020d, decode_basic_arith); /* C */
  1418.  
  1419.   AddInstTable(InstTable, "GETR" , 0x000e, decode_basic_io); /* I */
  1420.   AddInstTable(InstTable, "GETA" , 0x000f, decode_basic_io); /* I */
  1421.   AddInstTable(InstTable, "GETADD", 0x000f, decode_getadd); /* C */
  1422.  
  1423.   AddInstTable(InstTable, "SHFTR", 0xe00c, decode_shift_rotate); /* I */
  1424.   AddInstTable(InstTable, "ROTR" , 0xe00d, decode_shift_rotate); /* I */
  1425.   AddInstTable(InstTable, "SRR3" , 0xe00e, decode_shift_rotate); /* I */
  1426.   AddInstTable(InstTable, "SRR4" , 0xe00f, decode_shift_rotate); /* I */
  1427.   AddInstTable(InstTable, "SHR"  , 0xe00c, decode_shift_rotate); /* C */
  1428.   AddInstTable(InstTable, "ROR"  , 0xe00d, decode_shift_rotate); /* C */
  1429.   AddInstTable(InstTable, "ROR3" , 0xe00e, decode_shift_rotate); /* C */
  1430.   AddInstTable(InstTable, "SWAP" , 0xe00f, decode_shift_rotate); /* C */
  1431.  
  1432.   AddInstTable(InstTable, "LDHD" , 0x2000, decode_mem_direct); /* I */
  1433.   AddInstTable(InstTable, "STHD" , 0x3000, decode_mem_direct); /* I */
  1434.   AddInstTable(InstTable, "LDHI" , 0xd000, decode_mem_indirect); /* I */
  1435.   AddInstTable(InstTable, "STHI" , 0x5000, decode_mem_indirect); /* I */
  1436.   AddInstTable(InstTable, "LDBI" , 0x6000, decode_mem_indirect); /* I */
  1437.   AddInstTable(InstTable, "STBI" , 0x7000, decode_mem_indirect); /* I */
  1438.  
  1439.   AddInstTable(InstTable, "MOVB" , 0, decode_movb); /* C */
  1440.   AddInstTable(InstTable, "LWI"  , 0, decode_lwi); /* C */
  1441.  
  1442.   AddInstTable(InstTable, "EMIT" , 0x8000, decode_reg_imm8); /* I */
  1443.   AddInstTable(InstTable, "CLRI" , 0x9000, decode_reg_imm8); /* I */
  1444.   AddInstTable(InstTable, "CLR"  , 0x9000, decode_reg_imm8); /* C */
  1445.   AddInstTable(InstTable, "SETI" , 0xb000, decode_reg_imm8); /* I */
  1446.   AddInstTable(InstTable, "SET"  , 0xb000, decode_reg_imm8); /* C */
  1447.   AddInstTable(InstTable, "LBI"  , 0x8000, decode_reg_imm8); /* C */
  1448.   AddInstTable(InstTable, "ADDI" , 0xa000, decode_reg_imm8p1); /* I */
  1449.   AddInstTable(InstTable, "SUBI" , 0xf000, decode_reg_imm8p1); /* I */
  1450.  
  1451.   AddInstTable(InstTable, "CTL"  , 0x1000, decode_ctl); /* I */
  1452.   AddInstTable(InstTable, "CTRL" , 0x1000, decode_ctl); /* C */
  1453.  
  1454.   AddInstTable(InstTable, "PUTB" , 0, decode_putb); /* I/C */
  1455.   AddInstTable(InstTable, "GETB" , 0, decode_getb); /* I/C */
  1456.   AddInstTable(InstTable, "GETRB", 0xe00f, decode_getrb); /* I */
  1457.   AddInstTable(InstTable, "STAT" , 0xe00f, decode_stat); /* C */
  1458.   AddInstTable(InstTable, "BRA"  , 0, decode_bra); /* C */
  1459.   AddInstTable(InstTable, "JMP"  , 0, decode_jmp); /* C */
  1460.   AddInstTable(InstTable, "CALL" , 0, decode_call); /* C */
  1461.   AddInstTable(InstTable, "RCALL" , 0, decode_rcall); /* C */
  1462.   AddInstTable(InstTable, "RET"  , 0, decode_ret); /* C */
  1463. }
  1464.  
  1465. /*!------------------------------------------------------------------------
  1466.  * \fn     deinit_fields(void)
  1467.  * \brief  destroy/cleanup lookup table
  1468.  * ------------------------------------------------------------------------ */
  1469.  
  1470. static void deinit_fields(void)
  1471. {
  1472.   DestroyInstTable(InstTable);
  1473. }
  1474.  
  1475. /*--------------------------------------------------------------------------*/
  1476. /* Interface Functions */
  1477.  
  1478. /*!------------------------------------------------------------------------
  1479.  * \fn     intern_symbol_palm(char *pArg, TempResult *pResult)
  1480.  * \brief  handle built-in (register) symbols for PDP-11
  1481.  * \param  pArg source argument
  1482.  * \param  pResult result buffer
  1483.  * ------------------------------------------------------------------------ */
  1484.  
  1485. static void intern_symbol_palm(char *p_arg, TempResult *p_result)
  1486. {
  1487.   Word reg_num;
  1488.  
  1489.   if (decode_reg_core(p_arg, &reg_num, &p_result->DataSize))
  1490.   {
  1491.     p_result->Typ = TempReg;
  1492.     p_result->Contents.RegDescr.Reg = reg_num;
  1493.     p_result->Contents.RegDescr.Dissect = dissect_reg_palm;
  1494.     p_result->Contents.RegDescr.compare = NULL;
  1495.   }
  1496. }
  1497.  
  1498. /*!------------------------------------------------------------------------
  1499.  * \fn     make_code_palm(void)
  1500.  * \brief  encode machine instruction
  1501.  * ------------------------------------------------------------------------ */
  1502.  
  1503. static void make_code_palm(void)
  1504. {
  1505.   CodeLen = 0; DontPrint = False;
  1506.   this_was_skip = False;
  1507.  
  1508.   /* to be ignored */
  1509.  
  1510.   if (Memo(""))
  1511.   {
  1512.     this_was_skip = last_was_skip;
  1513.     goto func_exit;
  1514.   }
  1515.  
  1516.   /* Pseudo Instructions */
  1517.  
  1518.   if (decode_pseudo())
  1519.   {
  1520.     this_was_skip = last_was_skip;
  1521.     goto func_exit;
  1522.   }
  1523.   if (DecodeIntelPseudo(True))
  1524.     return;
  1525.  
  1526.   /* machine instructions may not begin on odd addresses */
  1527.  
  1528.   if (Odd(EProgCounter()))
  1529.   {
  1530.     if (DoPadding)
  1531.       InsertPadding(1, False);
  1532.     else
  1533.       WrError(ErrNum_AddrNotAligned);
  1534.   }
  1535.  
  1536.   if (!LookupInstTable(InstTable, OpPart.str.p_str))
  1537.     WrStrErrorPos(ErrNum_UnknownInstruction, &OpPart);
  1538. func_exit:
  1539.   last_was_skip = this_was_skip;
  1540. }
  1541.  
  1542. /*!------------------------------------------------------------------------
  1543.  * \fn     is_def_palm(void)
  1544.  * \brief  check whether insn makes own use of label
  1545.  * \return True if yes
  1546.  * ------------------------------------------------------------------------ */
  1547.  
  1548. static Boolean is_def_palm(void)
  1549. {
  1550.   return Memo("REG")
  1551.       || Memo("PORT");
  1552. }
  1553.  
  1554. /*!------------------------------------------------------------------------
  1555.  * \fn     qualify_quote_palm(const char *p_start, const char *p_quote_pos)
  1556.  * \brief  Treat special case of (Rn)' and (Rn)+' which is no quoting
  1557.  * \param  p_start start of string
  1558.  * \param  p_quote_pos position of quote
  1559.  * \return False if it's no quoting
  1560.  * ------------------------------------------------------------------------ */
  1561.  
  1562. static Boolean qualify_quote_palm(const char *p_start, const char *p_quote_pos)
  1563. {
  1564.   if (*p_quote_pos == '\'')
  1565.   {
  1566.     if ((p_quote_pos >= p_start + 1)
  1567.      && (*(p_quote_pos - 1) == ')'))
  1568.       return False;
  1569.     if ((p_quote_pos >= p_start + 2)
  1570.      && (*(p_quote_pos - 1) == '+')
  1571.      && (*(p_quote_pos - 2) == ')'))
  1572.       return False;
  1573.   }
  1574.   return True;
  1575. }
  1576.  
  1577. /*!------------------------------------------------------------------------
  1578.  * \fn     switch_from_palm(void)
  1579.  * \brief  deinitialize as target
  1580.  * ------------------------------------------------------------------------ */
  1581.  
  1582. static void switch_from_palm(void)
  1583. {
  1584.   deinit_fields();
  1585. }
  1586.  
  1587. static Boolean true_fnc(void)
  1588. {
  1589.   return True;
  1590. }
  1591.  
  1592. /*!------------------------------------------------------------------------
  1593.  * \fn     switch_to_palm(void)
  1594.  * \brief  prepare to assemble code for this target
  1595.  * ------------------------------------------------------------------------ */
  1596.  
  1597. static void switch_to_palm(void)
  1598. {
  1599.   const TFamilyDescr *p_descr = FindFamilyByName("PALM");
  1600.  
  1601.   TurnWords = True;
  1602.   SetIntConstMode(eIntConstModeIBM);
  1603.  
  1604.   PCSymbol = "*";
  1605.   HeaderID = p_descr->Id;
  1606.   NOPCode = 0x0004; /* = MOVE R0,R0 */
  1607.   DivideChars = ",";
  1608.  
  1609.   ValidSegs = (1 << SegCode) | (1 << SegIO);
  1610.   Grans[SegCode] = 1;
  1611.   ListGrans[SegCode] = 2;
  1612.   SegInits[SegCode] = 0;
  1613.   SegLimits[SegCode] = 0xffff;
  1614.   Grans[SegIO] = 1;
  1615.   ListGrans[SegIO] = 1;
  1616.   SegInits[SegIO] = 0;
  1617.   SegLimits[SegIO] = 0xf;
  1618.  
  1619.   MakeCode = make_code_palm;
  1620.   IsDef = is_def_palm;
  1621.   SwitchFrom = switch_from_palm;
  1622.   QualifyQuote = qualify_quote_palm;
  1623.   InternSymbol = intern_symbol_palm;
  1624.   DissectReg = dissect_reg_palm;
  1625.   SetIsOccupiedFnc = true_fnc;
  1626.  
  1627.   AddONOFF(DoPaddingName, &DoPadding, DoPaddingName, False);
  1628.   init_fields();
  1629.   last_was_skip = False;
  1630. }
  1631.  
  1632. /*!------------------------------------------------------------------------
  1633.  * \fn     codepalm_init(void)
  1634.  * \brief  register PALM target
  1635.  * ------------------------------------------------------------------------ */
  1636.  
  1637. void codepalm_init(void)
  1638. {
  1639.   cpu_5100 = AddCPU("IBM5100", switch_to_palm);
  1640.   cpu_5110 = AddCPU("IBM5110", switch_to_palm);
  1641.   cpu_5120 = AddCPU("IBM5120", switch_to_palm);
  1642. }
  1643.