Subversion Repositories pentevo

Rev

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

  1. /* codeimp16.c */
  2. /*****************************************************************************/
  3. /* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only                     */
  4. /*                                                                           */
  5. /* AS                                                                        */
  6. /*                                                                           */
  7. /* Codegenerator National IMP-16/PACE                                        */
  8. /*                                                                           */
  9. /*****************************************************************************/
  10.  
  11. #include "stdinc.h"
  12. #include "bpemu.h"
  13. #include <ctype.h>
  14. #include <string.h>
  15.  
  16. #include "strutil.h"
  17. #include "asmdef.h"
  18. #include "asmsub.h"
  19. #include "asmpars.h"
  20. #include "asmallg.h"
  21. #include "asmitree.h"
  22. #include "codevars.h"
  23. #include "codepseudo.h"
  24. #include "intpseudo.h"
  25. #include "headids.h"
  26. #include "literals.h"
  27.  
  28. #include "codeimp16.h"
  29.  
  30. /*-------------------------------------------------------------------------*/
  31. /* Types */
  32.  
  33. typedef struct
  34. {
  35.   const char *p_name;
  36.   Word code;
  37. } symbol_t;
  38.  
  39. typedef enum
  40. {
  41.   e_cpu_flag_none = 0,
  42.   e_cpu_flag_core_pace = 1 << 0,
  43.   e_cpu_flag_imp16_ext_instr = 1 << 1,
  44.   e_cpu_flag_imp16_ien_status = 1 << 2
  45. } cpu_flags_t;
  46.  
  47. /* NOTE: Only 4 bits are available for flags in the encoded machine code
  48.    for decode_mem().  Do NOT add more flags here! */
  49.  
  50. typedef enum
  51. {
  52.   e_inst_flag_allow_indirect = 1 << 0,
  53.   e_inst_flag_r01 = 1 << 1,
  54.   e_inst_flag_r0 = 1 << 2,
  55.   e_inst_flag_skip = 1 << 3,
  56.   e_inst_flag_all = 0x0f
  57. } inst_flag_t;
  58.  
  59. typedef struct
  60. {
  61.   const char *p_name;
  62.   cpu_flags_t flags;
  63. } cpu_props_t;
  64.  
  65. #ifdef __cplusplus
  66. # include "codeimp16.hpp"
  67. #endif
  68.  
  69. /*-------------------------------------------------------------------------*/
  70. /* Locals */
  71.  
  72. static symbol_t *conditions, *status_flags;
  73.  
  74. static const cpu_props_t *p_curr_cpu_props;
  75. static Boolean last_was_skip, this_was_skip;
  76. static LongInt bps_val;
  77.  
  78. /*-------------------------------------------------------------------------*/
  79. /* Register Symbols */
  80.  
  81. /*!------------------------------------------------------------------------
  82.  * \fn     decode_reg_core(const char *p_arg, Word *p_result, tSymbolSize *p_size)
  83.  * \brief  check whether argument is a CPU register
  84.  * \param  p_arg argument to check
  85.  * \param  p_result numeric register value if yes
  86.  * \param  p_size returns register size
  87.  * \return True if yes
  88.  * ------------------------------------------------------------------------ */
  89.  
  90. static Boolean decode_reg_core(const char *p_arg, Word *p_result, tSymbolSize *p_size)
  91. {
  92.   switch (strlen(p_arg))
  93.   {
  94.     case 3:
  95.       if ((as_toupper(*p_arg) == 'A')
  96.        && (as_toupper(p_arg[1]) == 'C')
  97.        && isdigit(p_arg[2])
  98.        && (p_arg[2] < '4'))
  99.       {
  100.         *p_result = p_arg[2] - '0';
  101.         *p_size = eSymbolSize16Bit;
  102.         return True;
  103.       }
  104.       break;
  105.     default:
  106.       break;
  107.   }
  108.   return False;
  109. }
  110.  
  111. /*!------------------------------------------------------------------------
  112.  * \fn     dissect_reg_imp16(char *p_dest, size_t dest_size, tRegInt value, tSymbolSize inp_size)
  113.  * \brief  dissect register symbols - IMP-16 variant
  114.  * \param  p_dest destination buffer
  115.  * \param  dest_size destination buffer size
  116.  * \param  value numeric register value
  117.  * \param  inp_size register size
  118.  * ------------------------------------------------------------------------ */
  119.  
  120. static void dissect_reg_imp16(char *p_dest, size_t dest_size, tRegInt value, tSymbolSize inp_size)
  121. {
  122.   switch (inp_size)
  123.   {
  124.     case eSymbolSize16Bit:
  125.       as_snprintf(p_dest, dest_size, "AC%u", (unsigned)(value & 3));
  126.       break;
  127.     default:
  128.       as_snprintf(p_dest, dest_size, "%d-%u", (int)inp_size, (unsigned)value);
  129.   }
  130. }
  131.  
  132. /*!------------------------------------------------------------------------
  133.  * \fn     decode_reg(const tStrComp *p_arg, Word *p_result)
  134.  * \brief  check whether argument is a CPU register or register alias
  135.  * \param  p_arg argument to check
  136.  * \param  p_result numeric register value if yes
  137.  * \param  must_be_reg argument is expected to be a register
  138.  * ------------------------------------------------------------------------ */
  139.  
  140. static tRegEvalResult decode_reg(const tStrComp *p_arg, Word *p_result)
  141. {
  142.   tRegDescr reg_descr;
  143.   tEvalResult eval_result;
  144.   tRegEvalResult reg_eval_result;
  145.  
  146.   /* built-in register */
  147.  
  148.   if (decode_reg_core(p_arg->str.p_str, p_result, &eval_result.DataSize))
  149.   {
  150.     reg_descr.Reg = *p_result;
  151.     reg_eval_result = eIsReg;
  152.     eval_result.DataSize = eSymbolSize16Bit;
  153.   }
  154.  
  155.   /* (register) symbol */
  156.  
  157.   else
  158.   {
  159.     reg_eval_result = EvalStrRegExpressionAsOperand(p_arg, &reg_descr, &eval_result, eSymbolSizeUnknown, False);
  160.  
  161.     /* always try numeric value for register */
  162.  
  163.     if (eIsNoReg == reg_eval_result)
  164.     {
  165.       Boolean ok;
  166.  
  167.       reg_descr.Reg = EvalStrIntExpression(p_arg, UInt2, &ok);
  168.       reg_eval_result = ok ? eIsReg : eRegAbort;
  169.       if (ok) eval_result.DataSize = eSymbolSize16Bit;
  170.     }
  171.   }
  172.  
  173.   if (reg_eval_result == eIsReg)
  174.   {
  175.     if (eval_result.DataSize != eSymbolSize16Bit)
  176.     {
  177.       WrStrErrorPos(ErrNum_InvOpSize, p_arg);
  178.       reg_eval_result = eIsNoReg;
  179.     }
  180.   }
  181.  
  182.   *p_result = reg_descr.Reg & ~REGSYM_FLAG_ALIAS;
  183.   return reg_eval_result;
  184. }
  185.  
  186. /*---------------------------------------------------------------------------*/
  187. /* Address Parsing */
  188.  
  189. /*!------------------------------------------------------------------------
  190.  * \fn     decode_mem_arg(const tStrComp *p_arg, Word *p_result, Boolean allow_indirect)
  191.  * \brief  decode memory argument
  192.  * \param  p_arg source argument
  193.  * \param  p_result encoded addressing mode (one word mode)
  194.  * \param  allow_indirect indirect mode (@) allowed?
  195.  * \return True if success
  196.  * ------------------------------------------------------------------------ */
  197.  
  198. static Boolean decode_mem_arg(const tStrComp *p_arg, Word *p_result, Boolean allow_indirect)
  199. {
  200.   tStrComp arg;
  201.   int split_pos, arg_len;
  202.   LongInt disp;
  203.   LongWord addr;
  204.   tEvalResult eval_result;
  205.   Boolean force_pcrel = False, is_pcrel;
  206.   Boolean base_ok, disp_ok;
  207.  
  208.   *p_result = 0x0000;
  209.  
  210.   StrCompRefRight(&arg, p_arg, 0);
  211.   if (*arg.str.p_str == '@')
  212.   {
  213.     if (!allow_indirect)
  214.     {
  215.       WrStrErrorPos(ErrNum_InvAddrMode, p_arg);
  216.       return False;
  217.     }
  218.     StrCompIncRefLeft(&arg, 1);
  219.     *p_result |= 0x1000;
  220.   }
  221.  
  222.   /* The (emulated) immediate mode: We use the common literal
  223.      mechanism, and as soon as we have the literal's name, branch
  224.      to the common code handling absolute addresses: */
  225.  
  226.   if (*arg.str.p_str == '#')
  227.   {
  228.     tEvalResult eval_result;
  229.     Word value;
  230.     Boolean critical;
  231.     String l_str;
  232.  
  233.     value = EvalStrIntExpressionOffsWithResult(&arg, 1, Int16, &eval_result);
  234.     if (!eval_result.OK)
  235.       return False;
  236.     critical = mFirstPassUnknown(eval_result.Flags) || mUsesForwards(eval_result.Flags);
  237.  
  238.     StrCompMkTemp(&arg, l_str, sizeof(l_str));    
  239.     literal_make(&arg, NULL, value, eSymbolSize16Bit, critical);
  240.     force_pcrel = True;
  241.     goto parse_abs;
  242.   }
  243.  
  244.   split_pos = FindDispBaseSplitWithQualifier(arg.str.p_str, &arg_len, NULL, "()");
  245.   if (split_pos >= 0)
  246.   {
  247.     tStrComp reg_arg;
  248.     Word xreg;
  249.  
  250.     StrCompSplitRef(&arg, &reg_arg, &arg, &arg.str.p_str[split_pos]);
  251.     KillPostBlanksStrComp(&arg);
  252.     KillPrefBlanksStrCompRef(&reg_arg);
  253.     StrCompShorten(&reg_arg, 1);
  254.     KillPostBlanksStrComp(&reg_arg);
  255.  
  256.     /* Allow addr(pc) to explicitly force PC-relative addressing */
  257.  
  258.     if (!as_strcasecmp(reg_arg.str.p_str, "PC"))
  259.     {
  260.       force_pcrel = True;
  261.       goto parse_abs;
  262.     }
  263.     if (!decode_reg(&reg_arg, &xreg)
  264.       || (xreg < 2))
  265.       return False;
  266.     if (!*arg.str.p_str)
  267.     {
  268.       disp = 0;
  269.       eval_result.OK = True;
  270.     }
  271.     else
  272.       disp = EvalStrIntExpression(&arg, SInt8, &eval_result.OK);
  273.     if (!eval_result.OK)
  274.       return False;
  275.  
  276.     *p_result |= (xreg << 8) | (disp & 0xff);
  277.     return True;
  278.   }
  279.  
  280. parse_abs:
  281.   addr = EvalStrIntExpressionWithResult(&arg, UInt16, &eval_result);
  282.   if (!eval_result.OK)
  283.     return False;
  284.   disp = addr - (EProgCounter() + 1);
  285.   disp_ok = (disp >= -128) && (disp < 127);
  286.   base_ok = bps_val
  287.           ? ((addr <= 127) || (addr >= 0xff80u))
  288.           : (addr < 256);
  289.  
  290.   /* For addresses in the CODE segment, preferrably use PC-relative
  291.      addressing.  For all other addresses/values, preferrably use
  292.      absolute addressing: */
  293.  
  294.   if (force_pcrel)
  295.     is_pcrel = True;
  296.   else if (eval_result.AddrSpaceMask & (1 << SegCode))
  297.     is_pcrel = disp_ok || !base_ok;
  298.   else
  299.     is_pcrel = !base_ok;
  300.  
  301.   if (is_pcrel)
  302.   {
  303.     if (!mFirstPassUnknownOrQuestionable(eval_result.Flags)
  304.      && !ChkRangePos(disp, -128, 127, &arg))
  305.       return False;
  306.  
  307.     *p_result |= (1 << 8) | (disp & 0xff);
  308.   }
  309.   else
  310.   {
  311.     if (!mFirstPassUnknownOrQuestionable(eval_result.Flags)
  312.      && !ChkRangePos(addr,
  313.                      bps_val ? ((addr & 0x8000ul) ? 0xff80ul : 0) : 0,
  314.                      bps_val ? ((addr & 0x8000ul) ? 0xfffful : 127) : 255,
  315.                      &arg))
  316.           return False;
  317.  
  318.     *p_result |= (0 << 8) | (addr & 0xff);
  319.   }
  320.  
  321.   return True;
  322. }
  323.  
  324. /*!------------------------------------------------------------------------
  325.  * \fn     decode_long_mem_arg(const tStrComp *p_arg, Word *p_result, Word *p_disp, IntType mem_type, Boolean allow_pcrel)
  326.  * \brief  decode long (two word) memory argument
  327.  * \param  p_arg source argument
  328.  * \param  p_result encoded addressing mode (two word mode)
  329.  * \param  p_disp displacement word
  330.  * \param  mem_type address range for absolute addresses
  331.  * \param  allow_pcrel allow PC-relative addressing?
  332.  * \return True if success
  333.  * ------------------------------------------------------------------------ */
  334.  
  335. static Boolean decode_long_mem_arg(const tStrComp *p_arg, Word *p_result, Word *p_disp, IntType mem_type, Boolean allow_pcrel)
  336. {
  337.   tStrComp arg;
  338.   int split_pos, arg_len;
  339.   LongWord addr;
  340.   LongInt disp;
  341.   tEvalResult eval_result;
  342.   Boolean force_pcrel = False, is_pcrel;
  343.  
  344.   *p_result = *p_disp = 0x0000;
  345.  
  346.   StrCompRefRight(&arg, p_arg, 0);
  347.   if (*arg.str.p_str == '@')
  348.   {
  349.     WrStrErrorPos(ErrNum_InvAddrMode, p_arg);
  350.     return False;
  351.   }
  352.  
  353.   /* The (emulated) immediate mode: We use the common literal
  354.      mechanism, and as soon as we have the literal's name, branch
  355.      to the common code handling absolute addresses: */
  356.  
  357.   if (*arg.str.p_str == '#')
  358.   {
  359.     tEvalResult eval_result;
  360.     Word value;
  361.     Boolean critical;
  362.     String l_str;
  363.  
  364.     if (!allow_pcrel)
  365.     {
  366.       WrStrErrorPos(ErrNum_InvAddrMode, &arg);
  367.       return False;
  368.     }
  369.  
  370.     value = EvalStrIntExpressionOffsWithResult(&arg, 1, Int16, &eval_result);
  371.     if (!eval_result.OK)
  372.       return False;
  373.     critical = mFirstPassUnknown(eval_result.Flags) || mUsesForwards(eval_result.Flags);
  374.  
  375.     StrCompMkTemp(&arg, l_str, sizeof(l_str));    
  376.     literal_make(&arg, NULL, value, eSymbolSize16Bit, critical);
  377.     force_pcrel = True;
  378.     goto parse_abs;
  379.   }
  380.  
  381.   split_pos = FindDispBaseSplitWithQualifier(arg.str.p_str, &arg_len, NULL, "()");
  382.   if (split_pos >= 0)
  383.   {
  384.     tStrComp reg_arg;
  385.     Word xreg;
  386.  
  387.     StrCompSplitRef(&arg, &reg_arg, &arg, &arg.str.p_str[split_pos]);
  388.     KillPostBlanksStrComp(&arg);
  389.     KillPrefBlanksStrCompRef(&reg_arg);
  390.     StrCompShorten(&reg_arg, 1);
  391.     KillPostBlanksStrComp(&reg_arg);
  392.  
  393.     if (!as_strcasecmp(reg_arg.str.p_str, "PC"))
  394.     {
  395.       if (!allow_pcrel)
  396.       {
  397.         WrStrErrorPos(ErrNum_InvAddrMode, p_arg);
  398.         return False;
  399.       }
  400.       force_pcrel = True;
  401.       goto parse_abs;
  402.     }
  403.     if (!decode_reg(&reg_arg, &xreg)
  404.       || (xreg < 2))
  405.       return False;
  406.     if (!*arg.str.p_str)
  407.     {
  408.       *p_disp = 0;
  409.       eval_result.OK = True;
  410.     }
  411.     else
  412.       *p_disp = EvalStrIntExpression(&arg, (IntType)(mem_type + 1), &eval_result.OK);
  413.     if (!eval_result.OK)
  414.       return False;
  415.  
  416.     *p_result |= (xreg << 8);
  417.     return True;
  418.   }
  419.  
  420. parse_abs:
  421.   addr = EvalStrIntExpressionWithResult(&arg, mem_type, &eval_result);
  422.   if (!eval_result.OK)
  423.     return False;
  424.   is_pcrel = force_pcrel || (eval_result.AddrSpaceMask & (1 << SegCode));
  425.  
  426.   if (is_pcrel)
  427.   {
  428.     disp = addr - (EProgCounter() + 1);
  429.  
  430.     *p_result |= (1 << 8);
  431.     *p_disp = disp & 0xffff;
  432.     return True;
  433.   }
  434.   else
  435.   {
  436.     *p_result |= (0 << 8);
  437.     *p_disp = addr & 0xffff;
  438.     return True;
  439.   }
  440. }
  441.  
  442. /*!------------------------------------------------------------------------
  443.  * \fn     decode_symbol(const tStrComp *p_arg, Word *p_code, const symbol_t *p_symbols)
  444.  * \brief  handle condition or status flag
  445.  * \param  p_arg source argument
  446.  * \param  p_code resulting code
  447.  * \param  p_symbols array of available symbols
  448.  * \return True if success
  449.  * ------------------------------------------------------------------------ */
  450.  
  451. static Boolean decode_symbol(const tStrComp *p_arg, Word *p_code, const symbol_t *p_symbols)
  452. {
  453.   for (*p_code = 0; p_symbols[*p_code].p_name; (*p_code)++)
  454.   {
  455.     if (!as_strcasecmp(p_symbols[*p_code].p_name, p_arg->str.p_str))
  456.     {
  457.       *p_code = p_symbols[*p_code].code;
  458.       return True;
  459.     }
  460.   }
  461.   return False;
  462. }
  463.  
  464. #define decode_condition(p_arg, p_code) decode_symbol(p_arg, p_code, conditions)
  465. #define decode_status_flag(p_arg, p_code) decode_symbol(p_arg, p_code, status_flags)
  466.  
  467. /*---------------------------------------------------------------------------*/
  468. /* Coding Helpers */
  469.  
  470. /*!------------------------------------------------------------------------
  471.  * \fn     put_code(Word code)
  472.  * \brief  append one more word of machine code
  473.  * \param  code machine code word to append
  474.  * ------------------------------------------------------------------------ */
  475.  
  476. static void put_code(Word code)
  477. {
  478.   /* Skip instructions only skip the next word of code.  If the
  479.      previous instruction was a skip, and we are about to create an
  480.      instruction consisting of more than one word, warn about this: */
  481.  
  482.   if ((1 == CodeLen) && last_was_skip)
  483.     WrStrErrorPos(ErrNum_TrySkipMultiwordInstruction, &OpPart);
  484.  
  485.   WAsmCode[CodeLen++] = code;
  486. }
  487.  
  488. /*!------------------------------------------------------------------------
  489.  * \fn     check_imp16_ext_instr(void)
  490.  * \brief  check whether extended IMP-16 instructions are allowed and complain if not
  491.  * \return True if nothing to complain
  492.  * ------------------------------------------------------------------------ */
  493.  
  494. static Boolean check_imp16_ext_instr(void)
  495. {
  496.   if (!(p_curr_cpu_props->flags & e_cpu_flag_imp16_ext_instr))
  497.   {
  498.     WrStrErrorPos(ErrNum_InstructionNotSupported, &OpPart);
  499.     return False;
  500.   }
  501.   return True;
  502. }
  503.  
  504. /*---------------------------------------------------------------------------*/
  505. /* Instruction Decoders */
  506.  
  507. /*!------------------------------------------------------------------------
  508.  * \fn     decode_ld_st(Word code)
  509.  * \brief  handle load/store instructions on PACE
  510.  * \param  code instruction machine code
  511.  * ------------------------------------------------------------------------ */
  512.  
  513. static void decode_ld_st(Word code)
  514. {
  515.   Word reg, mem, reg_max;
  516.  
  517.   if (!ChkArgCnt(2, 2))
  518.     return;
  519.  
  520.   if (!decode_mem_arg(&ArgStr[2], &mem, True))
  521.     return;
  522.  
  523.   if (mem & 0x1000)
  524.   {
  525.     reg_max = 0;
  526.     code -= 0x2000;
  527.   }
  528.   else
  529.     reg_max = 3;
  530.  
  531.   if ((decode_reg(&ArgStr[1], &reg) != eIsReg)
  532.    || (reg > reg_max))
  533.   {
  534.     WrStrErrorPos(ErrNum_InvReg, &ArgStr[1]);
  535.     return;
  536.   }
  537.  
  538.   put_code(code | (reg << 10) | (mem & 0x3ff));
  539. }
  540.  
  541. /*!------------------------------------------------------------------------
  542.  * \fn     decode_mem_reg(Word code)
  543.  * \brief  handle instructions with register and memory argument
  544.  * \param  code instruction machine code
  545.  * ------------------------------------------------------------------------ */
  546.  
  547. static void decode_mem_reg(Word code)
  548. {
  549.   Word reg, mem;
  550.  
  551.   if (!ChkArgCnt(2, 2))
  552.     return;
  553.  
  554.   if ((decode_reg(&ArgStr[1], &reg) != eIsReg)
  555.    || ((code & e_inst_flag_r01) && (reg >= 2))
  556.    || ((code & e_inst_flag_r0) && (reg != 0)))
  557.   {
  558.     WrStrErrorPos(ErrNum_InvReg, &ArgStr[1]);
  559.     return;
  560.   }
  561.  
  562.   if (decode_mem_arg(&ArgStr[2], &mem, !!(code & e_inst_flag_allow_indirect)))
  563.     put_code((code & ~e_inst_flag_all) | (reg << 10) | (mem & 0x13ff));
  564.   this_was_skip = !!(code & e_inst_flag_skip);
  565. }
  566.  
  567. /*!------------------------------------------------------------------------
  568.  * \fn     decode_mem(Word code)
  569.  * \brief  handle instructions with one memory reference
  570.  * \param  code instruction machine code
  571.  * ------------------------------------------------------------------------ */
  572.  
  573. static void decode_mem(Word code)
  574. {
  575.   Word mem,
  576.        opcode = (code >> 10) & 0x3f,
  577.        i_opcode_xor = (code >> 4) & 0x3f;
  578.  
  579.   if (!ChkArgCnt(1, 1))
  580.     return;
  581.  
  582.   if (decode_mem_arg(&ArgStr[1], &mem, !!i_opcode_xor))
  583.     put_code(((opcode ^ ((mem & 0x1000) ? i_opcode_xor : 0x00)) << 10) | (mem & 0x3ff));
  584.   this_was_skip = !!(code & e_inst_flag_skip);
  585. }
  586.  
  587. /*!------------------------------------------------------------------------
  588.  * \fn     decode_long_mem(Word code)
  589.  * \brief  handle instructions with one long memory reference
  590.  * \param  code instruction machine code
  591.  * ------------------------------------------------------------------------ */
  592.  
  593. static void decode_long_mem(Word code)
  594. {
  595.   Word mem, ext;
  596.  
  597.   if (!ChkArgCnt(1, 1)
  598.    || !check_imp16_ext_instr())
  599.     return;
  600.  
  601.   if (decode_long_mem_arg(&ArgStr[1], &mem, &ext, UInt16, code < 0x04c0))
  602.   {
  603.     put_code(code | mem);
  604.     put_code(ext);
  605.   }
  606. }
  607.  
  608. /*!------------------------------------------------------------------------
  609.  * \fn     decode_long_byte_mem(Word code)
  610.  * \brief  handle instructions with one long byte memory reference
  611.  * \param  code instruction machine code
  612.  * ------------------------------------------------------------------------ */
  613.  
  614. static void decode_long_byte_mem(Word code)
  615. {
  616.   Word mem, ext;
  617.  
  618.   if (!ChkArgCnt(1, 1)
  619.    || !check_imp16_ext_instr())
  620.     return;
  621.  
  622.   if (decode_long_mem_arg(&ArgStr[1], &mem, &ext, UInt15, False))
  623.   {
  624.     put_code((code & ~1) | mem);
  625.     put_code((ext << 1) | (code & 1));
  626.   }
  627. }
  628.  
  629. /*!------------------------------------------------------------------------
  630.  * \fn     decode_one_reg(Word code)
  631.  * \brief  handle instructions having one register as argument
  632.  * \param  code instruction machine code
  633.  * ------------------------------------------------------------------------ */
  634.  
  635. static void decode_one_reg(Word code)
  636. {
  637.   Word reg;
  638.  
  639.   if (!ChkArgCnt(1, 1))
  640.     return;
  641.  
  642.   if (decode_reg(&ArgStr[1], &reg) != eIsReg)
  643.   {
  644.     WrStrErrorPos(ErrNum_InvReg, &ArgStr[1]);
  645.     return;
  646.   }
  647.  
  648.   put_code(code | (reg << 8));
  649. }
  650.  
  651. /*!------------------------------------------------------------------------
  652.  * \fn     decode_reg_imm(Word code)
  653.  * \brief  handle instructions having one register and one immediate argument
  654.  * \param  code instruction machine code
  655.  * ------------------------------------------------------------------------ */
  656.  
  657. static void decode_reg_imm(Word code)
  658. {
  659.   Word reg, imm_value;
  660.   Boolean ok;
  661.  
  662.   if (!ChkArgCnt(2, 2))
  663.     return;
  664.  
  665.   if (decode_reg(&ArgStr[1], &reg) != eIsReg)
  666.   {
  667.     WrStrErrorPos(ErrNum_InvReg, &ArgStr[1]);
  668.     return;
  669.   }
  670.  
  671.   imm_value = EvalStrIntExpression(&ArgStr[2], Int8, &ok);
  672.   if (ok)
  673.     put_code((code & ~e_inst_flag_all) | (reg << 8) | (imm_value & 0xff));
  674.   this_was_skip = !!(code & e_inst_flag_skip);
  675. }
  676.  
  677. /*!------------------------------------------------------------------------
  678.  * \fn     decode_reg_reg(Word code)
  679.  * \brief  handle instructions having two register arguments
  680.  * \param  code instruction machine code
  681.  * ------------------------------------------------------------------------ */
  682.  
  683. static void decode_reg_reg(Word code)
  684. {
  685.   Word reg1, reg2;
  686.  
  687.   if (!ChkArgCnt(2, 2))
  688.     return;
  689.  
  690.   if (decode_reg(&ArgStr[1], &reg1) != eIsReg)
  691.   {
  692.     WrStrErrorPos(ErrNum_InvReg, &ArgStr[1]);
  693.     return;
  694.   }
  695.   if (decode_reg(&ArgStr[2], &reg2) != eIsReg)
  696.   {
  697.     WrStrErrorPos(ErrNum_InvReg, &ArgStr[2]);
  698.     return;
  699.   }
  700.  
  701.   if (p_curr_cpu_props->flags & e_cpu_flag_core_pace)
  702.     put_code(code | (reg1 << 6) | (reg2 << 8));
  703.   else
  704.     put_code(code | (reg1 << 10) | (reg2 << 8));
  705. }
  706.  
  707. /*!------------------------------------------------------------------------
  708.  * \fn     decode_none(Word code)
  709.  * \brief  handle instructions having no argument
  710.  * \param  code instruction machine code
  711.  * ------------------------------------------------------------------------ */
  712.  
  713. static void decode_none(Word code)
  714. {
  715.   if (ChkArgCnt(0, 0))
  716.     put_code(code);
  717. }
  718.  
  719. /*!------------------------------------------------------------------------
  720.  * \fn     decode_none_ext(Word code)
  721.  * \brief  handle extended instructions having no argument
  722.  * \param  code instruction machine code
  723.  * ------------------------------------------------------------------------ */
  724.  
  725. static void decode_none_ext(Word code)
  726. {
  727.   if (ChkArgCnt(0, 0)
  728.    || check_imp16_ext_instr())
  729.     put_code(code);
  730. }
  731.  
  732. /*!------------------------------------------------------------------------
  733.  * \fn     decode_imm7(Word code)
  734.  * \brief  handle instructions having one 7 bit immediate argument
  735.  * \param  code instruction machine code
  736.  * ------------------------------------------------------------------------ */
  737.  
  738. static void decode_imm7(Word code)
  739. {
  740.   Boolean ok;
  741.   Word imm_value;
  742.  
  743.   if (!ChkArgCnt(1, 1))
  744.     return;
  745.  
  746.   imm_value = EvalStrIntExpression(&ArgStr[1], UInt7, &ok);
  747.   if (ok)
  748.     put_code(code | (imm_value & 0x7f));
  749. }
  750.  
  751. /*!------------------------------------------------------------------------
  752.  * \fn     decode_imm8(Word code)
  753.  * \brief  handle instructions having one 8 bit immediate argument
  754.  * \param  code instruction machine code
  755.  * ------------------------------------------------------------------------ */
  756.  
  757. static void decode_imm8(Word code)
  758. {
  759.   Boolean ok;
  760.   Word imm_value;
  761.  
  762.   if (!ChkArgCnt(1, 1))
  763.     return;
  764.  
  765.   imm_value = EvalStrIntExpression(&ArgStr[1], UInt8, &ok);
  766.   if (ok)
  767.     put_code(code | (imm_value & 0xff));
  768. }
  769.  
  770. /*!------------------------------------------------------------------------
  771.  * \fn     decode_sflg_pflg_imp16(Word code)
  772.  * \brief  handle PFLG/SFLG instructions - IMP-16 version
  773.  * \param  code instruction machine code
  774.  * ------------------------------------------------------------------------ */
  775.  
  776. static void decode_sflg_pflg_imp16(Word code)
  777. {
  778.   tEvalResult eval_result;
  779.   Word bit_num, imm_value;
  780.  
  781.   if (!ChkArgCnt(2, 2))
  782.     return;
  783.  
  784.   bit_num = EvalStrIntExpressionWithResult(&ArgStr[1], UInt4, &eval_result);
  785.   if (!eval_result.OK)
  786.     return;
  787.   if (!mFirstPassUnknownOrQuestionable(eval_result.Flags)
  788.    && !ChkRangePos(bit_num, 8, 15, &ArgStr[1]))
  789.     return;
  790.  
  791.   imm_value = EvalStrIntExpressionWithResult(&ArgStr[2], UInt7, &eval_result);
  792.   if (eval_result.OK)
  793.     put_code(code | ((bit_num & 7) << 8) | (imm_value & 0x7f));
  794. }
  795.  
  796. /*!------------------------------------------------------------------------
  797.  * \fn     decode_sflg_pflg_pace(Word code)
  798.  * \brief  handle PFLG/SFLG instructions - PACE version
  799.  * \param  code instruction machine code
  800.  * ------------------------------------------------------------------------ */
  801.  
  802. static void decode_sflg_pflg_pace(Word code)
  803. {
  804.   Word bit_num;
  805.  
  806.   if (ChkArgCnt(1, 1)
  807.    && decode_status_flag(&ArgStr[1], &bit_num))
  808.     put_code(code | ((bit_num & 15) << 8));
  809. }
  810.  
  811. /*!------------------------------------------------------------------------
  812.  * \fn     decode_imm7_io(Word code)
  813.  * \brief  handle instructions having one 7 bit immediate argument as I/O address
  814.  * \param  code instruction machine code
  815.  * ------------------------------------------------------------------------ */
  816.  
  817. static void decode_imm7_io(Word code)
  818. {
  819.   tEvalResult eval_result;
  820.   Word imm_value;
  821.  
  822.   if (!ChkArgCnt(1, 1))
  823.     return;
  824.  
  825.   imm_value = EvalStrIntExpressionWithResult(&ArgStr[1], UInt7, &eval_result);
  826.   if (eval_result.OK)
  827.   {
  828.     ChkSpace(SegIO, eval_result.AddrSpaceMask);
  829.     put_code(code | (imm_value & 0x7f));
  830.   }
  831. }
  832.  
  833. /*!------------------------------------------------------------------------
  834.  * \fn     decode_jsri(Word code)
  835.  * \brief  handle JSRI instruction
  836.  * \param  code instruction machine code
  837.  * ------------------------------------------------------------------------ */
  838.  
  839. static void decode_jsri(Word code)
  840. {
  841.   tEvalResult eval_result;
  842.   Word address;
  843.  
  844.   if (!ChkArgCnt(1, 1))
  845.     return;
  846.  
  847.   address = EvalStrIntExpressionWithResult(&ArgStr[1], UInt16, &eval_result);
  848.   if (eval_result.OK)
  849.   {
  850.     if (mFirstPassUnknownOrQuestionable(eval_result.Flags))
  851.       address &= 0x7f;
  852.     if ((address >= 0x80) && (address < 0xff80))
  853.       WrStrErrorPos(ErrNum_UnderRange, &ArgStr[1]);
  854.     else
  855.       put_code(code | (address & 0x7f));
  856.   }
  857. }
  858.  
  859. /*!------------------------------------------------------------------------
  860.  * \fn     decode_jsrp(Word code)
  861.  * \brief  handle JSRP instruction
  862.  * \param  code instruction machine code
  863.  * ------------------------------------------------------------------------ */
  864.  
  865. static void decode_jsrp(Word code)
  866. {
  867.   tEvalResult eval_result;
  868.   Word address;
  869.  
  870.   if (!ChkArgCnt(1, 1)
  871.    || !check_imp16_ext_instr())
  872.     return;
  873.  
  874.   address = EvalStrIntExpressionWithResult(&ArgStr[1], UInt9, &eval_result);
  875.   if (eval_result.OK)
  876.   {
  877.     if (mFirstPassUnknownOrQuestionable(eval_result.Flags))
  878.       address &= ~0x80;
  879.     if (address & 0x80)
  880.       WrStrErrorPos(ErrNum_OverRange, &ArgStr[1]);
  881.     else
  882.       put_code(code | (address & 0x7f));
  883.   }
  884. }
  885.  
  886. /*!------------------------------------------------------------------------
  887.  * \fn     decode_shift_imp(Word code)
  888.  * \brief  handle shift instructions - IMP-16 variant
  889.  * \param  code instruction machine code
  890.  * ------------------------------------------------------------------------ */
  891.  
  892. static void decode_shift_imp16(Word code)
  893. {
  894.   Word reg, count;
  895.   Boolean ok;
  896.  
  897.   if (!ChkArgCnt(2, 2))
  898.     return;
  899.  
  900.   if (decode_reg(&ArgStr[1], &reg) != eIsReg)
  901.   {
  902.     WrStrErrorPos(ErrNum_InvReg, &ArgStr[1]);
  903.     return;
  904.   }
  905.  
  906.   count = EvalStrIntExpression(&ArgStr[2], UInt7, &ok);
  907.   if (ok)
  908.   {
  909.     if (code & 0x0080)
  910.       count = ~count + 1;
  911.     put_code((code & 0xfc00) | (reg << 8) | (count & 0xff));
  912.   }
  913. }
  914.  
  915. /*!------------------------------------------------------------------------
  916.  * \fn     decode_shift_pace(Word code)
  917.  * \brief  handle shift instructions - PACE variant
  918.  * \param  code instruction machine code
  919.  * ------------------------------------------------------------------------ */
  920.  
  921. static void decode_shift_pace(Word code)
  922. {
  923.   Word reg, count, link = 0;
  924.   Boolean ok;
  925.  
  926.   if (!ChkArgCnt(2, 3))
  927.     return;
  928.  
  929.   if (decode_reg(&ArgStr[1], &reg) != eIsReg)
  930.   {
  931.     WrStrErrorPos(ErrNum_InvReg, &ArgStr[1]);
  932.     return;
  933.   }
  934.  
  935.   count = EvalStrIntExpression(&ArgStr[2], UInt7, &ok);
  936.   if (!ok)
  937.     return;
  938.  
  939.   if (3 == ArgCnt)
  940.   {
  941.     link = EvalStrIntExpression(&ArgStr[3], UInt1, &ok);
  942.     if (!ok)
  943.       return;
  944.   }
  945.  
  946.   put_code(code | (reg << 8) | (count << 1) | link);
  947. }
  948.  
  949. /*!------------------------------------------------------------------------
  950.  * \fn     decode_boc(Word code)
  951.  * \brief  handle BOC instruction
  952.  * \param  code instruction machine code
  953.  * ------------------------------------------------------------------------ */
  954.  
  955. static void decode_boc(Word code)
  956. {
  957.   LongInt dist;
  958.   tEvalResult eval_result;
  959.   Word cond;
  960.  
  961.   if (!ChkArgCnt(2, 2)
  962.    || !decode_condition(&ArgStr[1], &cond))
  963.     return;
  964.  
  965.   dist = EvalStrIntExpressionWithResult(&ArgStr[2], UInt16, &eval_result) - (EProgCounter() + 1);
  966.   if (eval_result.OK)
  967.   {
  968.     if (!mFirstPassUnknownOrQuestionable(eval_result.Flags) && !RangeCheck(dist, SInt8))
  969.       WrStrErrorPos(ErrNum_JmpDistTooBig, &ArgStr[2]);
  970.     else
  971.       put_code(code | (cond << 8) | (dist & 0xff));
  972.   }
  973. }
  974.  
  975. /*!------------------------------------------------------------------------
  976.  * \fn     decode_reg_bit(Word code)
  977.  * \brief  handle instructions with bit position as argument
  978.  * \param  code machine code
  979.  * ------------------------------------------------------------------------ */
  980.  
  981. static void decode_reg_bit(Word code)
  982. {
  983.   Word bit_pos;
  984.  
  985.   if (!ChkArgCnt(1, 1)
  986.    || !check_imp16_ext_instr())
  987.     return;
  988.  
  989.   if (!(code & 0x0001)
  990.    || !decode_status_flag(&ArgStr[1], &bit_pos))
  991.   {
  992.     Boolean ok;
  993.  
  994.     bit_pos = EvalStrIntExpression(&ArgStr[1], UInt4, &ok);
  995.     if (!ok)
  996.       return;
  997.   }
  998.  
  999.   put_code((code & 0xfffe) | (bit_pos & 0x000f));
  1000. }
  1001.  
  1002. /*!------------------------------------------------------------------------
  1003.  * \fn     decode_jmpp_jint(Word code)
  1004.  * \brief  handle JMPP and JINT instructions
  1005.  * \param  code machine code
  1006.  * ------------------------------------------------------------------------ */
  1007.  
  1008. static void decode_jmpp_jint(Word code)
  1009. {
  1010.   Word address;
  1011.   tEvalResult eval_result;
  1012.  
  1013.   if (!ChkArgCnt(1, 1)
  1014.    || !check_imp16_ext_instr())
  1015.     return;
  1016.  
  1017.   address = EvalStrIntExpressionWithResult(&ArgStr[1], UInt16, &eval_result);
  1018.   if (!eval_result.OK)
  1019.     return;
  1020.  
  1021.   if (mFirstPassUnknownOrQuestionable(eval_result.Flags))
  1022.     address &= 15;
  1023.   if (address < 16);
  1024.   else if (!ChkRangePos(address, code & 0x1f0, (code & 0x1f0) + 15, &ArgStr[1]))
  1025.     return;
  1026.  
  1027.   put_code(code | (address & 15));
  1028. }
  1029.  
  1030. /*!------------------------------------------------------------------------
  1031.  * \fn     decode_port(Word code)
  1032.  * \brief  handle PORT instruction
  1033.  * ------------------------------------------------------------------------ */
  1034.  
  1035. static void decode_port(Word code)
  1036. {
  1037.   UNUSED(code);
  1038.   CodeEquate(SegIO, 0, SegLimits[SegIO]);
  1039. }
  1040.  
  1041. /*!------------------------------------------------------------------------
  1042.  * \fn     decode_ltorg(Word code)
  1043.  * \brief  handle LTORG instruction
  1044.  * ------------------------------------------------------------------------ */
  1045.  
  1046. static LargeInt ltorg_16(const as_literal_t *p_lit, struct sStrComp *p_name)
  1047. {
  1048.   LargeInt ret;
  1049.  
  1050.   SetMaxCodeLen((CodeLen + 1) * 2);
  1051.   ret = EProgCounter() + CodeLen;
  1052.   EnterIntSymbol(p_name, ret, ActPC, False);
  1053.   put_code(p_lit->value & 0xffff);
  1054.   return ret;
  1055. }
  1056.  
  1057. static void decode_ltorg(Word code)
  1058. {
  1059.   UNUSED(code);
  1060.  
  1061.   if (ChkArgCnt(0, 0))
  1062.     literals_dump(ltorg_16, eSymbolSize16Bit, MomSectionHandle, False);
  1063. }
  1064.  
  1065. /*---------------------------------------------------------------------------*/
  1066. /* Code Table Handling */
  1067.  
  1068. /*!------------------------------------------------------------------------
  1069.  * \fn     init_fields(void)
  1070.  * \brief  construct instruction hash table
  1071.  * ------------------------------------------------------------------------ */
  1072.  
  1073. static void add_condition(const char *p_name, Word code)
  1074. {
  1075.   order_array_rsv_end(conditions, symbol_t);
  1076.   conditions[InstrZ].p_name = p_name;
  1077.   conditions[InstrZ++].code = code;
  1078. }
  1079.  
  1080. static void add_status_flag(const char *p_name, Word code)
  1081. {
  1082.   order_array_rsv_end(status_flags, symbol_t);
  1083.   status_flags[InstrZ].p_name = p_name;
  1084.   status_flags[InstrZ++].code = code;
  1085. }
  1086.  
  1087. static void init_fields(Boolean is_pace)
  1088. {
  1089.   InstTable = CreateInstTable(103);
  1090.  
  1091.   AddInstTable(InstTable, "HALT" , 0x0000, decode_none);
  1092.   AddInstTable(InstTable, "PUSHF", is_pace ? 0x0c00 : 0x0080, decode_none);
  1093.   AddInstTable(InstTable, "PULLF", is_pace ? 0x1000 : 0x0280, decode_none);
  1094.   AddInstTable(InstTable, "NOP"  , NOPCode, decode_none);
  1095.   AddInstTable(InstTable, "BOC"  , is_pace ? 0x4000 : 0x1000, decode_boc);
  1096.   AddInstTable(InstTable, "JMP"  , is_pace ? 0x1a00 : 0x2010, decode_mem);
  1097.   AddInstTable(InstTable, "JSR"  , is_pace ? 0x1600 : 0x2810, decode_mem);
  1098.   AddInstTable(InstTable, "RADD" , is_pace ? 0x6800 : 0x3000, decode_reg_reg);
  1099.   AddInstTable(InstTable, "RAND" , is_pace ? 0x5400 : 0x3083, decode_reg_reg);
  1100.   AddInstTable(InstTable, "RXOR" , is_pace ? 0x5800 : 0x3082, decode_reg_reg);
  1101.   AddInstTable(InstTable, "RXCH" , is_pace ? 0x6c00 : 0x3080, decode_reg_reg);
  1102.   AddInstTable(InstTable, "RCPY" , is_pace ? 0x5c00 : 0x3081, decode_reg_reg);
  1103.   AddInstTable(InstTable, "PUSH" , is_pace ? 0x6000 : 0x4000, decode_one_reg);
  1104.   AddInstTable(InstTable, "PULL" , is_pace ? 0x6400 : 0x4400, decode_one_reg);
  1105.   AddInstTable(InstTable, "AISZ" , (is_pace ? 0x7800 : 0x4800) | e_inst_flag_skip, decode_reg_imm);
  1106.   AddInstTable(InstTable, "LI"   , is_pace ? 0x5000 : 0x4c00, decode_reg_imm);
  1107.   AddInstTable(InstTable, "CAI"  , is_pace ? 0x7000 : 0x5000, decode_reg_imm);
  1108.   AddInstTable(InstTable, "XCHRS", is_pace ? 0x1c00 : 0x5400, decode_one_reg);
  1109.   AddInstTable(InstTable, "ISZ"  , (is_pace ? 0x8c00 : 0x7800) | e_inst_flag_skip, decode_mem);
  1110.   AddInstTable(InstTable, "DSZ"  , (is_pace ? 0xac00 : 0x7c00) | e_inst_flag_skip, decode_mem);
  1111.   AddInstTable(InstTable, "ADD"  , is_pace ? 0xe000 : 0xc000, decode_mem_reg);
  1112.   AddInstTable(InstTable, "AND"  , is_pace ? (0xa800 | e_inst_flag_r0) : (0x6000 | e_inst_flag_r01), decode_mem_reg);
  1113.   AddInstTable(InstTable, "OR"   , is_pace ? (0xa400 | e_inst_flag_r0) : (0x6800 | e_inst_flag_r01), decode_mem_reg);
  1114.   AddInstTable(InstTable, "SKG"  , (is_pace ? (0x9c00 | e_inst_flag_r0) : 0xe000) | e_inst_flag_skip, decode_mem_reg);
  1115.   AddInstTable(InstTable, "SKNE" , 0xf000 | e_inst_flag_skip, decode_mem_reg);
  1116.   AddInstTable(InstTable, "SKAZ" , (is_pace ? (0xb800 | e_inst_flag_r0) : (0x7000 | e_inst_flag_r01)) | e_inst_flag_skip, decode_mem_reg);
  1117.  
  1118.   if (is_pace)
  1119.   {
  1120.     AddInstTable(InstTable, "LD"   , 0xc000, decode_ld_st);
  1121.     AddInstTable(InstTable, "ST"   , 0xd000, decode_ld_st);
  1122.     AddInstTable(InstTable, "RTI"  , 0x7c00, decode_imm8);
  1123.     AddInstTable(InstTable, "RTS"  , 0x8000, decode_imm8);
  1124.     AddInstTable(InstTable, "RADC" , 0x7400, decode_reg_reg);
  1125.     AddInstTable(InstTable, "SUBB" , (0x9000 | e_inst_flag_r0), decode_mem_reg);
  1126.     AddInstTable(InstTable, "DECA" , (0x8800 | e_inst_flag_r0), decode_mem_reg);
  1127.     AddInstTable(InstTable, "LSEX" , (0xbc00 | e_inst_flag_r0), decode_mem_reg);
  1128.     AddInstTable(InstTable, "CFR"  , 0x0400, decode_one_reg);
  1129.     AddInstTable(InstTable, "CRF"  , 0x0800, decode_one_reg);
  1130.     AddInstTable(InstTable, "ROL"  , 0x2000, decode_shift_pace);
  1131.     AddInstTable(InstTable, "ROR"  , 0x2400, decode_shift_pace);
  1132.     AddInstTable(InstTable, "SHL"  , 0x2800, decode_shift_pace);
  1133.     AddInstTable(InstTable, "SHR"  , 0x2c00, decode_shift_pace);
  1134.     AddInstTable(InstTable, "SFLG" , 0x3080, decode_sflg_pflg_pace);
  1135.     AddInstTable(InstTable, "PFLG" , 0x3000, decode_sflg_pflg_pace);
  1136.   }
  1137.   else /* IMP-16 */
  1138.   {
  1139.     AddInstTable(InstTable, "LD"   , (0x8000 | e_inst_flag_allow_indirect), decode_mem_reg);
  1140.     AddInstTable(InstTable, "ST"   , (0xa000 | e_inst_flag_allow_indirect), decode_mem_reg);
  1141.     AddInstTable(InstTable, "RTI"  , 0x0100, decode_imm7);
  1142.     AddInstTable(InstTable, "RTS"  , 0x0200, decode_imm7);
  1143.     AddInstTable(InstTable, "JSRP" , 0x0300, decode_jsrp);
  1144.     AddInstTable(InstTable, "JSRI" , 0x0380, decode_jsri);
  1145.     AddInstTable(InstTable, "RIN"  , 0x0400, decode_imm7_io);
  1146.     AddInstTable(InstTable, "ROUT" , 0x0600, decode_imm7_io);
  1147.     AddInstTable(InstTable, "MPY"  , 0x0480, decode_long_mem);
  1148.     AddInstTable(InstTable, "DIV"  , 0x0490, decode_long_mem);
  1149.     AddInstTable(InstTable, "DADD" , 0x04a0, decode_long_mem);
  1150.     AddInstTable(InstTable, "DSUB" , 0x04b0, decode_long_mem);
  1151.     AddInstTable(InstTable, "LDB"  , 0x04c0, decode_long_mem);
  1152.     AddInstTable(InstTable, "STB"  , 0x04d0, decode_long_mem);
  1153.     AddInstTable(InstTable, "LLB"  , 0x04c0, decode_long_byte_mem);
  1154.     AddInstTable(InstTable, "SLB"  , 0x04d0, decode_long_byte_mem);
  1155.     AddInstTable(InstTable, "LRB"  , 0x04c1, decode_long_byte_mem);
  1156.     AddInstTable(InstTable, "SRB"  , 0x04d1, decode_long_byte_mem);
  1157.     AddInstTable(InstTable, "JMPP" , 0x0500, decode_jmpp_jint);
  1158.     AddInstTable(InstTable, "ISCAN", 0x0510, decode_none_ext);
  1159.     AddInstTable(InstTable, "JINT" , 0x0520, decode_jmpp_jint);
  1160.     AddInstTable(InstTable, "SETST", 0x0701, decode_reg_bit);
  1161.     AddInstTable(InstTable, "CLRST", 0x0711, decode_reg_bit);
  1162.     AddInstTable(InstTable, "SETBIT",0x0720, decode_reg_bit);
  1163.     AddInstTable(InstTable, "CLRBIT",0x0730, decode_reg_bit);
  1164.     AddInstTable(InstTable, "SKSTF", 0x0741, decode_reg_bit);
  1165.     AddInstTable(InstTable, "SKBIT", 0x0750, decode_reg_bit);
  1166.     AddInstTable(InstTable, "CMPBIT",0x0760, decode_reg_bit);
  1167.     AddInstTable(InstTable, "SUB"  , 0xd000, decode_mem_reg);
  1168.     AddInstTable(InstTable, "ROL"  , 0x5800, decode_shift_imp16);
  1169.     AddInstTable(InstTable, "ROR"  , 0x5880, decode_shift_imp16);
  1170.     AddInstTable(InstTable, "SHL"  , 0x5c00, decode_shift_imp16);
  1171.     AddInstTable(InstTable, "SHR"  , 0x5c80, decode_shift_imp16);
  1172.     AddInstTable(InstTable, "SFLG" , 0x0800, decode_sflg_pflg_imp16);
  1173.     AddInstTable(InstTable, "PFLG" , 0x0880, decode_sflg_pflg_imp16);
  1174.   }
  1175.  
  1176.  
  1177.   if (ValidSegs & (1 << SegCode))
  1178.     AddInstTable(InstTable, "PORT" , 0, decode_port);
  1179.   AddInstTable(InstTable, "ASCII" , eIntPseudoFlag_AllowInt | eIntPseudoFlag_AllowString | eIntPseudoFlag_BigEndian, DecodeIntelDB);
  1180.   AddInstTable(InstTable, "WORD" , eIntPseudoFlag_AllowInt | eIntPseudoFlag_AllowString, DecodeIntelDW);
  1181.   AddInstTable(InstTable, "LTORG", 0, decode_ltorg);
  1182.  
  1183.   InstrZ = 0;
  1184.   add_condition("REQ0", 1);
  1185.   add_condition("PSIGN", 2);
  1186.   add_condition("BIT0", 3);
  1187.   add_condition("BIT1", 4);
  1188.   add_condition("NREQ0", 5);
  1189.   add_condition("NSIGN", 11);
  1190.   if (is_pace)
  1191.   {
  1192.     add_condition("STFL", 0);
  1193.     add_condition("BIT2", 6);
  1194.     add_condition("CONTIN", 7);
  1195.     add_condition("LINK", 8);
  1196.     add_condition("IEN", 9);
  1197.     add_condition("CARRY", 10);
  1198.     add_condition("OVF", 12);
  1199.     add_condition("JC13", 13);
  1200.     add_condition("JC14", 14);
  1201.     add_condition("JC15", 15);
  1202.   }
  1203.   else
  1204.   {
  1205.     add_condition("INT", 0);
  1206.     add_condition("CPINT", 6);
  1207.     add_condition("START", 7);
  1208.     add_condition("STFL", 8);
  1209.     add_condition("INEN", 9);
  1210.     add_condition("CY/OV", 10);
  1211.     if (p_curr_cpu_props->flags & e_cpu_flag_imp16_ien_status)
  1212.     {
  1213.       add_condition("POA", 12);
  1214.       add_condition("SEL", 13);
  1215.     }
  1216.   }
  1217.   add_condition(NULL, 0);
  1218.  
  1219.   InstrZ = 0;
  1220.   if (is_pace)
  1221.   {
  1222.     add_status_flag("IE1", 1);
  1223.     add_status_flag("IE2", 2);
  1224.     add_status_flag("IE3", 3);
  1225.     add_status_flag("IE4", 4);
  1226.     add_status_flag("IE5", 5);
  1227.     add_status_flag("OV", 6);
  1228.     add_status_flag("CY", 7);
  1229.     add_status_flag("LINK", 8);
  1230.     add_status_flag("IEN", 9);
  1231.     add_status_flag("BYTE", 10);
  1232.     add_status_flag("F11", 11);
  1233.     add_status_flag("F12", 12);
  1234.     add_status_flag("F13", 13);
  1235.     add_status_flag("F14", 14);
  1236.   }
  1237.   else
  1238.   {
  1239.     add_status_flag("L", 15);
  1240.     add_status_flag("OV", 14);
  1241.     add_status_flag("CY", 13);
  1242.     if (p_curr_cpu_props->flags & e_cpu_flag_imp16_ien_status)
  1243.     {
  1244.       add_status_flag("IEN3", 12);
  1245.       add_status_flag("IEN2", 8);
  1246.       add_status_flag("IEN1", 4);
  1247.       add_status_flag("IEN0", 0);
  1248.     }
  1249.   }
  1250.   add_status_flag(NULL, 0);
  1251. }
  1252.  
  1253. /*!------------------------------------------------------------------------
  1254.  * \fn     deinit_fields(void)
  1255.  * \brief  clean up hash table
  1256.  * ------------------------------------------------------------------------ */
  1257.  
  1258. static void deinit_fields(void)
  1259. {
  1260.   order_array_free(conditions);
  1261.   order_array_free(status_flags);
  1262.   DestroyInstTable(InstTable);
  1263. }
  1264.  
  1265. /*---------------------------------------------------------------------------*/
  1266. /* Semiglobal Functions */
  1267.  
  1268. /*!------------------------------------------------------------------------
  1269.  * \fn     intern_symbol_imp16(char *pArg, TempResult *pResult)
  1270.  * \brief  handle built-in (register) symbols for IMP-16
  1271.  * \param  p_arg source argument
  1272.  * \param  p_result result buffer
  1273.  * ------------------------------------------------------------------------ */
  1274.  
  1275. static void intern_symbol_imp16(char *p_arg, TempResult *p_result)
  1276. {
  1277.   Word reg_num;
  1278.  
  1279.   if (decode_reg_core(p_arg, &reg_num, &p_result->DataSize))
  1280.   {
  1281.     p_result->Typ = TempReg;
  1282.     p_result->Contents.RegDescr.Reg = reg_num;
  1283.     p_result->Contents.RegDescr.Dissect = dissect_reg_imp16;
  1284.     p_result->Contents.RegDescr.compare = NULL;
  1285.   }
  1286. }
  1287.  
  1288. /*!------------------------------------------------------------------------
  1289.  * \fn     make_code_imp16(void)
  1290.  * \brief  handle machine instuctions
  1291.  * ------------------------------------------------------------------------ */
  1292.  
  1293. static void make_code_imp16(void)
  1294. {
  1295.   CodeLen = 0; DontPrint = False;
  1296.   this_was_skip = False;
  1297.  
  1298.   /* to be ignored */
  1299.  
  1300.   if (Memo(""))
  1301.     goto func_exit;
  1302.  
  1303.   /* pseudo instructions */
  1304.  
  1305.   if (DecodeIntelPseudo(False))
  1306.     goto func_exit;
  1307.  
  1308.   if (!LookupInstTable(InstTable, OpPart.str.p_str))
  1309.     WrStrErrorPos(ErrNum_UnknownInstruction, &OpPart);
  1310.  
  1311. func_exit:
  1312.   last_was_skip = this_was_skip;
  1313. }
  1314.  
  1315. /*!------------------------------------------------------------------------
  1316.  * \fn     is_def_imp16(void)
  1317.  * \brief  does instruction consume label?
  1318.  * ------------------------------------------------------------------------ */
  1319.  
  1320. static Boolean is_def_imp16(void)
  1321. {
  1322.   return (ValidSegs & (1 << SegCode)) ? Memo("PORT") : False;
  1323. }
  1324.  
  1325. /*!------------------------------------------------------------------------
  1326.  * \fn     switch_to_imp16(void *p_user)
  1327.  * \brief  switch to target
  1328.  * \param  properties descriptor
  1329.  * ------------------------------------------------------------------------ */
  1330.  
  1331. static void switch_to_imp16(void *p_user)
  1332. {
  1333.   const TFamilyDescr *p_descr;
  1334.   Boolean is_pace;
  1335.  
  1336.   p_curr_cpu_props = (cpu_props_t*)p_user;
  1337.   is_pace = !!(p_curr_cpu_props->flags & e_cpu_flag_core_pace);
  1338.   p_descr = FindFamilyByName(is_pace ? "IPC-16" : "IMP-16");
  1339.  
  1340.   TurnWords = False;
  1341.   SetIntConstMode(eIntConstModeIBM);
  1342.   IntConstModeIBMNoTerm = True;
  1343.   QualifyQuote = QualifyQuote_SingleQuoteConstant;
  1344.  
  1345.   PCSymbol = ".";
  1346.   HeaderID = p_descr->Id;
  1347.   NOPCode = is_pace ? 0x5c00 : 0x3081; /* = RCPY AC0, AC0 */
  1348.   DivideChars = ",";
  1349.   HasAttrs = False;
  1350.  
  1351.   ValidSegs = 1 << SegCode;
  1352.   Grans[SegCode] = 2; ListGrans[SegCode] = 2; SegInits[SegCode] = 0;
  1353.   SegLimits[SegCode] = 0xffff;
  1354.   if (is_pace)
  1355.   {
  1356.     static ASSUMERec assume_pace = { "BPS", &bps_val, 0, 1, 0, NULL };
  1357.  
  1358.     pASSUMERecs = &assume_pace;
  1359.     ASSUMERecCnt = 1;
  1360.   }
  1361.   else
  1362.   {
  1363.     ValidSegs |= 1 << SegIO;
  1364.     Grans[SegIO] = 2; ListGrans[SegIO] = 2; SegInits[SegCode] = 0;
  1365.     SegLimits[SegIO] = 0x7f;
  1366.   }
  1367.  
  1368.   MakeCode = make_code_imp16;
  1369.   IsDef = is_def_imp16;
  1370.   InternSymbol = intern_symbol_imp16;
  1371.   SwitchFrom = deinit_fields;
  1372.   init_fields(is_pace);
  1373. }
  1374.  
  1375. /*!------------------------------------------------------------------------
  1376.  * \fn     init_pass_pace(void)
  1377.  * \brief  set internal variables to default upon start of pass
  1378.  * ------------------------------------------------------------------------ */
  1379.  
  1380. static void init_pass_pace(void)
  1381. {
  1382.   bps_val = 0;
  1383. }
  1384.  
  1385. /*!------------------------------------------------------------------------
  1386.  * \fn     codeimp16_init(void)
  1387.  * \brief  attach target
  1388.  * ------------------------------------------------------------------------ */
  1389.  
  1390. static const cpu_props_t cpu_props[] =
  1391. {
  1392.   { "IMP-16C/200", e_cpu_flag_none },
  1393.   { "IMP-16C/300", e_cpu_flag_imp16_ext_instr },
  1394.   { "IMP-16P/200", e_cpu_flag_none },
  1395.   { "IMP-16P/300", e_cpu_flag_imp16_ext_instr },
  1396.   { "IMP-16L"    , e_cpu_flag_imp16_ext_instr | e_cpu_flag_imp16_ien_status },
  1397.   { "IPC-16"     , e_cpu_flag_core_pace },
  1398.   { "INS8900"    , e_cpu_flag_core_pace }
  1399. };
  1400.  
  1401. void codeimp16_init(void)
  1402. {
  1403.   const cpu_props_t *p_prop;
  1404.  
  1405.   for (p_prop = cpu_props; p_prop < cpu_props + as_array_size(cpu_props); p_prop++)
  1406.     (void)AddCPUUser(p_prop->p_name, switch_to_imp16, (void*)p_prop, NULL);
  1407.   AddInitPassProc(init_pass_pace);
  1408. }
  1409.