Subversion Repositories pentevo

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
1186 savelij 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
  String l_str;
202
  int split_pos, arg_len;
203
  LongInt disp;
204
  LongWord addr;
205
  tEvalResult eval_result;
206
  Boolean force_pcrel = False, is_pcrel;
207
  Boolean base_ok, disp_ok;
208
 
209
  *p_result = 0x0000;
210
 
211
  StrCompRefRight(&arg, p_arg, 0);
212
  if (*arg.str.p_str == '@')
213
  {
214
    if (!allow_indirect)
215
    {
216
      WrStrErrorPos(ErrNum_InvAddrMode, p_arg);
217
      return False;
218
    }
219
    StrCompIncRefLeft(&arg, 1);
220
    *p_result |= 0x1000;
221
  }
222
 
223
  /* The (emulated) immediate mode: We use the common literal
224
     mechanism, and as soon as we have the literal's name, branch
225
     to the common code handling absolute addresses: */
226
 
227
  if (*arg.str.p_str == '#')
228
  {
229
    tEvalResult eval_result;
230
    Word value;
231
    Boolean critical;
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
  String l_str;
339
  int split_pos, arg_len;
340
  LongWord addr;
341
  LongInt disp;
342
  tEvalResult eval_result;
343
  Boolean force_pcrel = False, is_pcrel;
344
 
345
  *p_result = *p_disp = 0x0000;
346
 
347
  StrCompRefRight(&arg, p_arg, 0);
348
  if (*arg.str.p_str == '@')
349
  {
350
    WrStrErrorPos(ErrNum_InvAddrMode, p_arg);
351
    return False;
352
  }
353
 
354
  /* The (emulated) immediate mode: We use the common literal
355
     mechanism, and as soon as we have the literal's name, branch
356
     to the common code handling absolute addresses: */
357
 
358
  if (*arg.str.p_str == '#')
359
  {
360
    tEvalResult eval_result;
361
    Word value;
362
    Boolean critical;
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
  add_null_pseudo(InstTable);
1092
 
1093
  AddInstTable(InstTable, "HALT" , 0x0000, decode_none);
1094
  AddInstTable(InstTable, "PUSHF", is_pace ? 0x0c00 : 0x0080, decode_none);
1095
  AddInstTable(InstTable, "PULLF", is_pace ? 0x1000 : 0x0280, decode_none);
1096
  AddInstTable(InstTable, "NOP"  , NOPCode, decode_none);
1097
  AddInstTable(InstTable, "BOC"  , is_pace ? 0x4000 : 0x1000, decode_boc);
1098
  AddInstTable(InstTable, "JMP"  , is_pace ? 0x1a00 : 0x2010, decode_mem);
1099
  AddInstTable(InstTable, "JSR"  , is_pace ? 0x1600 : 0x2810, decode_mem);
1100
  AddInstTable(InstTable, "RADD" , is_pace ? 0x6800 : 0x3000, decode_reg_reg);
1101
  AddInstTable(InstTable, "RAND" , is_pace ? 0x5400 : 0x3083, decode_reg_reg);
1102
  AddInstTable(InstTable, "RXOR" , is_pace ? 0x5800 : 0x3082, decode_reg_reg);
1103
  AddInstTable(InstTable, "RXCH" , is_pace ? 0x6c00 : 0x3080, decode_reg_reg);
1104
  AddInstTable(InstTable, "RCPY" , is_pace ? 0x5c00 : 0x3081, decode_reg_reg);
1105
  AddInstTable(InstTable, "PUSH" , is_pace ? 0x6000 : 0x4000, decode_one_reg);
1106
  AddInstTable(InstTable, "PULL" , is_pace ? 0x6400 : 0x4400, decode_one_reg);
1107
  AddInstTable(InstTable, "AISZ" , (is_pace ? 0x7800 : 0x4800) | e_inst_flag_skip, decode_reg_imm);
1108
  AddInstTable(InstTable, "LI"   , is_pace ? 0x5000 : 0x4c00, decode_reg_imm);
1109
  AddInstTable(InstTable, "CAI"  , is_pace ? 0x7000 : 0x5000, decode_reg_imm);
1110
  AddInstTable(InstTable, "XCHRS", is_pace ? 0x1c00 : 0x5400, decode_one_reg);
1111
  AddInstTable(InstTable, "ISZ"  , (is_pace ? 0x8c00 : 0x7800) | e_inst_flag_skip, decode_mem);
1112
  AddInstTable(InstTable, "DSZ"  , (is_pace ? 0xac00 : 0x7c00) | e_inst_flag_skip, decode_mem);
1113
  AddInstTable(InstTable, "ADD"  , is_pace ? 0xe000 : 0xc000, decode_mem_reg);
1114
  AddInstTable(InstTable, "AND"  , is_pace ? (0xa800 | e_inst_flag_r0) : (0x6000 | e_inst_flag_r01), decode_mem_reg);
1115
  AddInstTable(InstTable, "OR"   , is_pace ? (0xa400 | e_inst_flag_r0) : (0x6800 | e_inst_flag_r01), decode_mem_reg);
1116
  AddInstTable(InstTable, "SKG"  , (is_pace ? (0x9c00 | e_inst_flag_r0) : 0xe000) | e_inst_flag_skip, decode_mem_reg);
1117
  AddInstTable(InstTable, "SKNE" , 0xf000 | e_inst_flag_skip, decode_mem_reg);
1118
  AddInstTable(InstTable, "SKAZ" , (is_pace ? (0xb800 | e_inst_flag_r0) : (0x7000 | e_inst_flag_r01)) | e_inst_flag_skip, decode_mem_reg);
1119
 
1120
  if (is_pace)
1121
  {
1122
    AddInstTable(InstTable, "LD"   , 0xc000, decode_ld_st);
1123
    AddInstTable(InstTable, "ST"   , 0xd000, decode_ld_st);
1124
    AddInstTable(InstTable, "RTI"  , 0x7c00, decode_imm8);
1125
    AddInstTable(InstTable, "RTS"  , 0x8000, decode_imm8);
1126
    AddInstTable(InstTable, "RADC" , 0x7400, decode_reg_reg);
1127
    AddInstTable(InstTable, "SUBB" , (0x9000 | e_inst_flag_r0), decode_mem_reg);
1128
    AddInstTable(InstTable, "DECA" , (0x8800 | e_inst_flag_r0), decode_mem_reg);
1129
    AddInstTable(InstTable, "LSEX" , (0xbc00 | e_inst_flag_r0), decode_mem_reg);
1130
    AddInstTable(InstTable, "CFR"  , 0x0400, decode_one_reg);
1131
    AddInstTable(InstTable, "CRF"  , 0x0800, decode_one_reg);
1132
    AddInstTable(InstTable, "ROL"  , 0x2000, decode_shift_pace);
1133
    AddInstTable(InstTable, "ROR"  , 0x2400, decode_shift_pace);
1134
    AddInstTable(InstTable, "SHL"  , 0x2800, decode_shift_pace);
1135
    AddInstTable(InstTable, "SHR"  , 0x2c00, decode_shift_pace);
1136
    AddInstTable(InstTable, "SFLG" , 0x3080, decode_sflg_pflg_pace);
1137
    AddInstTable(InstTable, "PFLG" , 0x3000, decode_sflg_pflg_pace);
1138
  }
1139
  else /* IMP-16 */
1140
  {
1141
    AddInstTable(InstTable, "LD"   , (0x8000 | e_inst_flag_allow_indirect), decode_mem_reg);
1142
    AddInstTable(InstTable, "ST"   , (0xa000 | e_inst_flag_allow_indirect), decode_mem_reg);
1143
    AddInstTable(InstTable, "RTI"  , 0x0100, decode_imm7);
1144
    AddInstTable(InstTable, "RTS"  , 0x0200, decode_imm7);
1145
    AddInstTable(InstTable, "JSRP" , 0x0300, decode_jsrp);
1146
    AddInstTable(InstTable, "JSRI" , 0x0380, decode_jsri);
1147
    AddInstTable(InstTable, "RIN"  , 0x0400, decode_imm7_io);
1148
    AddInstTable(InstTable, "ROUT" , 0x0600, decode_imm7_io);
1149
    AddInstTable(InstTable, "MPY"  , 0x0480, decode_long_mem);
1150
    AddInstTable(InstTable, "DIV"  , 0x0490, decode_long_mem);
1151
    AddInstTable(InstTable, "DADD" , 0x04a0, decode_long_mem);
1152
    AddInstTable(InstTable, "DSUB" , 0x04b0, decode_long_mem);
1153
    AddInstTable(InstTable, "LDB"  , 0x04c0, decode_long_mem);
1154
    AddInstTable(InstTable, "STB"  , 0x04d0, decode_long_mem);
1155
    AddInstTable(InstTable, "LLB"  , 0x04c0, decode_long_byte_mem);
1156
    AddInstTable(InstTable, "SLB"  , 0x04d0, decode_long_byte_mem);
1157
    AddInstTable(InstTable, "LRB"  , 0x04c1, decode_long_byte_mem);
1158
    AddInstTable(InstTable, "SRB"  , 0x04d1, decode_long_byte_mem);
1159
    AddInstTable(InstTable, "JMPP" , 0x0500, decode_jmpp_jint);
1160
    AddInstTable(InstTable, "ISCAN", 0x0510, decode_none_ext);
1161
    AddInstTable(InstTable, "JINT" , 0x0520, decode_jmpp_jint);
1162
    AddInstTable(InstTable, "SETST", 0x0701, decode_reg_bit);
1163
    AddInstTable(InstTable, "CLRST", 0x0711, decode_reg_bit);
1164
    AddInstTable(InstTable, "SETBIT",0x0720, decode_reg_bit);
1165
    AddInstTable(InstTable, "CLRBIT",0x0730, decode_reg_bit);
1166
    AddInstTable(InstTable, "SKSTF", 0x0741, decode_reg_bit);
1167
    AddInstTable(InstTable, "SKBIT", 0x0750, decode_reg_bit);
1168
    AddInstTable(InstTable, "CMPBIT",0x0760, decode_reg_bit);
1169
    AddInstTable(InstTable, "SUB"  , 0xd000, decode_mem_reg);
1170
    AddInstTable(InstTable, "ROL"  , 0x5800, decode_shift_imp16);
1171
    AddInstTable(InstTable, "ROR"  , 0x5880, decode_shift_imp16);
1172
    AddInstTable(InstTable, "SHL"  , 0x5c00, decode_shift_imp16);
1173
    AddInstTable(InstTable, "SHR"  , 0x5c80, decode_shift_imp16);
1174
    AddInstTable(InstTable, "SFLG" , 0x0800, decode_sflg_pflg_imp16);
1175
    AddInstTable(InstTable, "PFLG" , 0x0880, decode_sflg_pflg_imp16);
1176
  }
1177
 
1178
 
1179
  if (ValidSegs & (1 << SegIO))
1180
    AddInstTable(InstTable, "PORT" , 0, decode_port);
1181
  AddInstTable(InstTable, "ASCII" , eIntPseudoFlag_BigEndian | eIntPseudoFlag_AllowInt | eIntPseudoFlag_AllowString, DecodeIntelDB);
1182
  AddInstTable(InstTable, "WORD" , eIntPseudoFlag_LittleEndian | eIntPseudoFlag_AllowInt | eIntPseudoFlag_AllowString, DecodeIntelDW);
1183
  AddInstTable(InstTable, "LTORG", 0, decode_ltorg);
1184
  AddIntelPseudo(InstTable, eIntPseudoFlag_LittleEndian);
1185
 
1186
  InstrZ = 0;
1187
  add_condition("REQ0", 1);
1188
  add_condition("PSIGN", 2);
1189
  add_condition("BIT0", 3);
1190
  add_condition("BIT1", 4);
1191
  add_condition("NREQ0", 5);
1192
  add_condition("NSIGN", 11);
1193
  if (is_pace)
1194
  {
1195
    add_condition("STFL", 0);
1196
    add_condition("BIT2", 6);
1197
    add_condition("CONTIN", 7);
1198
    add_condition("LINK", 8);
1199
    add_condition("IEN", 9);
1200
    add_condition("CARRY", 10);
1201
    add_condition("OVF", 12);
1202
    add_condition("JC13", 13);
1203
    add_condition("JC14", 14);
1204
    add_condition("JC15", 15);
1205
  }
1206
  else
1207
  {
1208
    add_condition("INT", 0);
1209
    add_condition("CPINT", 6);
1210
    add_condition("START", 7);
1211
    add_condition("STFL", 8);
1212
    add_condition("INEN", 9);
1213
    add_condition("CY/OV", 10);
1214
    if (p_curr_cpu_props->flags & e_cpu_flag_imp16_ien_status)
1215
    {
1216
      add_condition("POA", 12);
1217
      add_condition("SEL", 13);
1218
    }
1219
  }
1220
  add_condition(NULL, 0);
1221
 
1222
  InstrZ = 0;
1223
  if (is_pace)
1224
  {
1225
    add_status_flag("IE1", 1);
1226
    add_status_flag("IE2", 2);
1227
    add_status_flag("IE3", 3);
1228
    add_status_flag("IE4", 4);
1229
    add_status_flag("IE5", 5);
1230
    add_status_flag("OV", 6);
1231
    add_status_flag("CY", 7);
1232
    add_status_flag("LINK", 8);
1233
    add_status_flag("IEN", 9);
1234
    add_status_flag("BYTE", 10);
1235
    add_status_flag("F11", 11);
1236
    add_status_flag("F12", 12);
1237
    add_status_flag("F13", 13);
1238
    add_status_flag("F14", 14);
1239
  }
1240
  else
1241
  {
1242
    add_status_flag("L", 15);
1243
    add_status_flag("OV", 14);
1244
    add_status_flag("CY", 13);
1245
    if (p_curr_cpu_props->flags & e_cpu_flag_imp16_ien_status)
1246
    {
1247
      add_status_flag("IEN3", 12);
1248
      add_status_flag("IEN2", 8);
1249
      add_status_flag("IEN1", 4);
1250
      add_status_flag("IEN0", 0);
1251
    }
1252
  }
1253
  add_status_flag(NULL, 0);
1254
}
1255
 
1256
/*!------------------------------------------------------------------------
1257
 * \fn     deinit_fields(void)
1258
 * \brief  clean up hash table
1259
 * ------------------------------------------------------------------------ */
1260
 
1261
static void deinit_fields(void)
1262
{
1263
  order_array_free(conditions);
1264
  order_array_free(status_flags);
1265
  DestroyInstTable(InstTable);
1266
}
1267
 
1268
/*---------------------------------------------------------------------------*/
1269
/* Semiglobal Functions */
1270
 
1271
/*!------------------------------------------------------------------------
1272
 * \fn     intern_symbol_imp16(char *pArg, TempResult *pResult)
1273
 * \brief  handle built-in (register) symbols for IMP-16
1274
 * \param  p_arg source argument
1275
 * \param  p_result result buffer
1276
 * ------------------------------------------------------------------------ */
1277
 
1278
static void intern_symbol_imp16(char *p_arg, TempResult *p_result)
1279
{
1280
  Word reg_num;
1281
 
1282
  if (decode_reg_core(p_arg, &reg_num, &p_result->DataSize))
1283
  {
1284
    p_result->Typ = TempReg;
1285
    p_result->Contents.RegDescr.Reg = reg_num;
1286
    p_result->Contents.RegDescr.Dissect = dissect_reg_imp16;
1287
    p_result->Contents.RegDescr.compare = NULL;
1288
  }
1289
}
1290
 
1291
/*!------------------------------------------------------------------------
1292
 * \fn     make_code_imp16(void)
1293
 * \brief  handle machine instuctions
1294
 * ------------------------------------------------------------------------ */
1295
 
1296
static void make_code_imp16(void)
1297
{
1298
  this_was_skip = False;
1299
 
1300
  if (!LookupInstTable(InstTable, OpPart.str.p_str))
1301
    WrStrErrorPos(ErrNum_UnknownInstruction, &OpPart);
1302
 
1303
  last_was_skip = this_was_skip;
1304
}
1305
 
1306
/*!------------------------------------------------------------------------
1307
 * \fn     is_def_imp16(void)
1308
 * \brief  does instruction consume label?
1309
 * ------------------------------------------------------------------------ */
1310
 
1311
static Boolean is_def_imp16(void)
1312
{
1313
  return (ValidSegs & (1 << SegIO)) ? Memo("PORT") : False;
1314
}
1315
 
1316
/*!------------------------------------------------------------------------
1317
 * \fn     switch_to_imp16(void *p_user)
1318
 * \brief  switch to target
1319
 * \param  properties descriptor
1320
 * ------------------------------------------------------------------------ */
1321
 
1322
static void switch_to_imp16(void *p_user)
1323
{
1324
  const TFamilyDescr *p_descr;
1325
  Boolean is_pace;
1326
 
1327
  p_curr_cpu_props = (cpu_props_t*)p_user;
1328
  is_pace = !!(p_curr_cpu_props->flags & e_cpu_flag_core_pace);
1329
  p_descr = FindFamilyByName(is_pace ? "IPC-16" : "IMP-16");
1330
 
1331
  TurnWords = False;
1332
  SetIntConstMode(eIntConstModeIBM);
1333
  IntConstModeIBMNoTerm = True;
1334
  QualifyQuote = QualifyQuote_SingleQuoteConstant;
1335
 
1336
  PCSymbol = ".";
1337
  HeaderID = p_descr->Id;
1338
  NOPCode = is_pace ? 0x5c00 : 0x3081; /* = RCPY AC0, AC0 */
1339
  DivideChars = ",";
1340
  HasAttrs = False;
1341
 
1342
  ValidSegs = 1 << SegCode;
1343
  Grans[SegCode] = 2; ListGrans[SegCode] = 2; SegInits[SegCode] = 0;
1344
  SegLimits[SegCode] = 0xffff;
1345
  if (is_pace)
1346
  {
1347
    static ASSUMERec assume_pace = { "BPS", &bps_val, 0, 1, 0, NULL };
1348
 
1349
    pASSUMERecs = &assume_pace;
1350
    ASSUMERecCnt = 1;
1351
  }
1352
  else
1353
  {
1354
    ValidSegs |= 1 << SegIO;
1355
    Grans[SegIO] = 2; ListGrans[SegIO] = 2; SegInits[SegIO] = 0;
1356
    SegLimits[SegIO] = 0x7f;
1357
  }
1358
 
1359
  MakeCode = make_code_imp16;
1360
  IsDef = is_def_imp16;
1361
  InternSymbol = intern_symbol_imp16;
1362
  SwitchFrom = deinit_fields;
1363
  init_fields(is_pace);
1364
}
1365
 
1366
/*!------------------------------------------------------------------------
1367
 * \fn     init_pass_pace(void)
1368
 * \brief  set internal variables to default upon start of pass
1369
 * ------------------------------------------------------------------------ */
1370
 
1371
static void init_pass_pace(void)
1372
{
1373
  bps_val = 0;
1374
}
1375
 
1376
/*!------------------------------------------------------------------------
1377
 * \fn     codeimp16_init(void)
1378
 * \brief  attach target
1379
 * ------------------------------------------------------------------------ */
1380
 
1381
static const cpu_props_t cpu_props[] =
1382
{
1383
  { "IMP-16C/200", e_cpu_flag_none },
1384
  { "IMP-16C/300", e_cpu_flag_imp16_ext_instr },
1385
  { "IMP-16P/200", e_cpu_flag_none },
1386
  { "IMP-16P/300", e_cpu_flag_imp16_ext_instr },
1387
  { "IMP-16L"    , e_cpu_flag_imp16_ext_instr | e_cpu_flag_imp16_ien_status },
1388
  { "IPC-16"     , e_cpu_flag_core_pace },
1389
  { "INS8900"    , e_cpu_flag_core_pace }
1390
};
1391
 
1392
void codeimp16_init(void)
1393
{
1394
  const cpu_props_t *p_prop;
1395
 
1396
  for (p_prop = cpu_props; p_prop < cpu_props + as_array_size(cpu_props); p_prop++)
1397
    (void)AddCPUUser(p_prop->p_name, switch_to_imp16, (void*)p_prop, NULL);
1398
  AddInitPassProc(init_pass_pace);
1399
}