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, ®_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, ®_arg, &arg, &arg.str.p_str[split_pos]); |
||
251 | KillPostBlanksStrComp(&arg); |
||
252 | KillPrefBlanksStrCompRef(®_arg); |
||
253 | StrCompShorten(®_arg, 1); |
||
254 | KillPostBlanksStrComp(®_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(®_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, ®_arg, &arg, &arg.str.p_str[split_pos]); |
||
388 | KillPostBlanksStrComp(&arg); |
||
389 | KillPrefBlanksStrCompRef(®_arg); |
||
390 | StrCompShorten(®_arg, 1); |
||
391 | KillPostBlanksStrComp(®_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(®_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], ®) != 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], ®) != 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], ®) != 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], ®) != 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], ®1) != eIsReg) |
||
691 | { |
||
692 | WrStrErrorPos(ErrNum_InvReg, &ArgStr[1]); |
||
693 | return; |
||
694 | } |
||
695 | if (decode_reg(&ArgStr[2], ®2) != 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], ®) != 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], ®) != 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, ®_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 | } |