36#if defined(_MSC_VER) && !defined(__clang__)
37#define TMS9900_INLINE_HOT static __forceinline
39#define TMS9900_INLINE_HOT static inline __attribute__((always_inline))
44#if defined(TMS9900_PERSONALITY)
45#define F18A_ACTIVE TMS9900_PERSONALITY
46#define run9900_budget_c TMS9900_VARIANT_ENTRY
48#define F18A_ACTIVE (cpu->f18aMemory)
63static const uint8_t byte_flags[256] = {
64 0x20, 0xC4, 0xC4, 0xC0, 0xC4, 0xC0, 0xC0, 0xC4,
65 0xC4, 0xC0, 0xC0, 0xC4, 0xC0, 0xC4, 0xC4, 0xC0,
66 0xC4, 0xC0, 0xC0, 0xC4, 0xC0, 0xC4, 0xC4, 0xC0,
67 0xC0, 0xC4, 0xC4, 0xC0, 0xC4, 0xC0, 0xC0, 0xC4,
68 0xC4, 0xC0, 0xC0, 0xC4, 0xC0, 0xC4, 0xC4, 0xC0,
69 0xC0, 0xC4, 0xC4, 0xC0, 0xC4, 0xC0, 0xC0, 0xC4,
70 0xC0, 0xC4, 0xC4, 0xC0, 0xC4, 0xC0, 0xC0, 0xC4,
71 0xC4, 0xC0, 0xC0, 0xC4, 0xC0, 0xC4, 0xC4, 0xC0,
72 0xC4, 0xC0, 0xC0, 0xC4, 0xC0, 0xC4, 0xC4, 0xC0,
73 0xC0, 0xC4, 0xC4, 0xC0, 0xC4, 0xC0, 0xC0, 0xC4,
74 0xC0, 0xC4, 0xC4, 0xC0, 0xC4, 0xC0, 0xC0, 0xC4,
75 0xC4, 0xC0, 0xC0, 0xC4, 0xC0, 0xC4, 0xC4, 0xC0,
76 0xC0, 0xC4, 0xC4, 0xC0, 0xC4, 0xC0, 0xC0, 0xC4,
77 0xC4, 0xC0, 0xC0, 0xC4, 0xC0, 0xC4, 0xC4, 0xC0,
78 0xC4, 0xC0, 0xC0, 0xC4, 0xC0, 0xC4, 0xC4, 0xC0,
79 0xC0, 0xC4, 0xC4, 0xC0, 0xC4, 0xC0, 0xC0, 0xC4,
80 0x84, 0x80, 0x80, 0x84, 0x80, 0x84, 0x84, 0x80,
81 0x80, 0x84, 0x84, 0x80, 0x84, 0x80, 0x80, 0x84,
82 0x80, 0x84, 0x84, 0x80, 0x84, 0x80, 0x80, 0x84,
83 0x84, 0x80, 0x80, 0x84, 0x80, 0x84, 0x84, 0x80,
84 0x80, 0x84, 0x84, 0x80, 0x84, 0x80, 0x80, 0x84,
85 0x84, 0x80, 0x80, 0x84, 0x80, 0x84, 0x84, 0x80,
86 0x84, 0x80, 0x80, 0x84, 0x80, 0x84, 0x84, 0x80,
87 0x80, 0x84, 0x84, 0x80, 0x84, 0x80, 0x80, 0x84,
88 0x80, 0x84, 0x84, 0x80, 0x84, 0x80, 0x80, 0x84,
89 0x84, 0x80, 0x80, 0x84, 0x80, 0x84, 0x84, 0x80,
90 0x84, 0x80, 0x80, 0x84, 0x80, 0x84, 0x84, 0x80,
91 0x80, 0x84, 0x84, 0x80, 0x84, 0x80, 0x80, 0x84,
92 0x84, 0x80, 0x80, 0x84, 0x80, 0x84, 0x84, 0x80,
93 0x80, 0x84, 0x84, 0x80, 0x84, 0x80, 0x80, 0x84,
94 0x80, 0x84, 0x84, 0x80, 0x84, 0x80, 0x80, 0x84,
95 0x84, 0x80, 0x80, 0x84, 0x80, 0x84, 0x84, 0x80};
100static inline void set_flags_word(
Tms9900Cpu* cpu, uint16_t v)
103 int16_t sv = (int16_t)v;
106 cpu->st |= TMS_ST_EQ;
111 cpu->st |= (TMS_ST_LGT | TMS_ST_AGT);
115 cpu->st |= TMS_ST_LGT;
119static inline void set_flags_byte(
Tms9900Cpu* cpu, uint8_t v)
122 cpu->st = (uint16_t)((cpu->st & ~(TMS_ST_LGT | TMS_ST_AGT | TMS_ST_EQ | TMS_ST_P))
150static const uint16_t gpu_window_base[16] = {0x0000, 0x0000, 0x0000, 0x0000, 0x4000, 0x5000, 0x6000, 0x7000,
151 0x8000, 0x0000, 0xB00E, 0xB002, 0x0000, 0x0000, 0x0000, 0x0000};
153static const uint16_t gpu_window_mask[16] = {0x3FFF, 0x3FFF, 0x3FFF, 0x3FFF, 0x07FF, 0x007F, 0x003F, 0x0001,
154 0x000F, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000};
157#define GPU_WINDOW_READS 0x05FFu
158#define GPU_WINDOW_WRITES 0x097Fu
160static inline uint32_t gpu_addr(uint16_t a)
162 const uint32_t w = a >> 12;
163 return gpu_window_base[w] | (a & gpu_window_mask[w]);
166static inline uint8_t rd8(
Tms9900Cpu* cpu, uint16_t a)
168 if (!F18A_ACTIVE)
return cpu->mem[a];
169 if (!((GPU_WINDOW_READS >> (a >> 12)) & 1))
return 0;
170 return cpu->mem[gpu_addr(a)];
173static inline void wr8(
Tms9900Cpu* cpu, uint16_t a, uint8_t v)
180 if (!((GPU_WINDOW_WRITES >> (a >> 12)) & 1))
return;
181 const uint32_t at = gpu_addr(a);
184 cpu->mem[at] = (at == 0xB002) ? (uint8_t)((v & 0x7F) | (cpu->mem[at] & 0x80)) : v;
187static inline uint16_t rd16(
Tms9900Cpu* cpu, uint16_t a)
189 return (uint16_t)((rd8(cpu, a) << 8) | rd8(cpu, (uint16_t)(a + 1)));
192static inline void wr16(
Tms9900Cpu* cpu, uint16_t a, uint16_t v)
194 wr8(cpu, a, (uint8_t)(v >> 8));
195 wr8(cpu, (uint16_t)(a + 1), (uint8_t)(v & 0xFF));
201#if defined(TMS9900_WATCH_WRITES)
202static inline void watch_write(
Tms9900Cpu* cpu, uint32_t addr)
204 if (!cpu->onWrite)
return;
206 const uint32_t at = F18A_ACTIVE ? gpu_addr((uint16_t)addr) : addr;
207 if ((at & cpu->onWriteMask) == cpu->onWriteMatch) cpu->onWrite(cpu->mem, at);
210#define watch_write(cpu, addr) ((void)0)
215static inline uint32_t wp_addr(
Tms9900Cpu* cpu, uint8_t r)
217 return (uint32_t)cpu->wp + ((uint32_t)r << 1);
222#if (defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) \
223 || (defined(_MSC_VER) && !defined(__clang__))
224#define TMS9900_SWAP_WORKSPACE 1
227static inline uint16_t get_reg(
Tms9900Cpu* cpu, uint8_t r)
229 uint32_t a = wp_addr(cpu, r);
230#if defined(TMS9900_SWAP_WORKSPACE)
232 memcpy(&w, cpu->mem + a,
sizeof w);
233 return (uint16_t)((w >> 8) | (w << 8));
235 return (uint16_t)((cpu->mem[a] << 8) | cpu->mem[a + 1]);
239static inline void set_reg(
Tms9900Cpu* cpu, uint8_t r, uint16_t v)
241 uint32_t a = wp_addr(cpu, r);
242#if defined(TMS9900_SWAP_WORKSPACE)
243 uint16_t w = (uint16_t)((v >> 8) | (v << 8));
244 memcpy(cpu->mem + a, &w,
sizeof w);
246 cpu->mem[a] = (uint8_t)(v >> 8);
247 cpu->mem[a + 1] = (uint8_t)(v & 0xFF);
263 uint16_t a = (uint16_t)cpu->pc;
264 cpu->pc = (a + 2) & 0xFFFF;
270TMS9900_INLINE_HOT
Operand decode_field(
Tms9900Cpu* cpu, uint8_t field, uint8_t is_byte,
274 o.mode = (field >> 4) & 0x3;
281 if (is_byte) o.addr = (uint16_t)wp_addr(cpu, o.reg);
282 if (load) o.val = is_byte ? cpu->mem[wp_addr(cpu, o.reg)] : get_reg(cpu, o.reg);
285 o.addr = get_reg(cpu, o.reg);
286 if (!is_byte) o.addr &= 0xFFFE;
287 if (load) o.val = is_byte ? rd8(cpu, o.addr) : rd16(cpu, o.addr);
291 uint16_t offset = fetchw(cpu);
296 ea = (uint16_t)(get_reg(cpu, o.reg) + offset);
297 o.addr = is_byte ? ea : (ea & 0xFFFE);
298 if (load) o.val = is_byte ? rd8(cpu, o.addr) : rd16(cpu, o.addr);
304 uint16_t raw = get_reg(cpu, o.reg);
305 uint16_t inc = is_byte ? 1u : 2u;
306 set_reg(cpu, o.reg, (uint16_t)(raw + inc));
307 o.addr = is_byte ? raw : (raw & 0xFFFE);
308 if (load) o.val = is_byte ? rd8(cpu, o.addr) : rd16(cpu, o.addr);
315TMS9900_INLINE_HOT
Operand decode_operand(
Tms9900Cpu* cpu, uint8_t field, uint8_t is_byte)
317 return decode_field(cpu, field, is_byte, 1);
322TMS9900_INLINE_HOT
Operand decode_addr(
Tms9900Cpu* cpu, uint8_t field, uint8_t is_byte)
324 return decode_field(cpu, field, is_byte, 0);
327TMS9900_INLINE_HOT
void store_operand(
Tms9900Cpu* cpu,
const Operand* o, uint16_t v)
333 cpu->mem[wp_addr(cpu, o->reg)] = (uint8_t)v;
337 set_reg(cpu, o->reg, v);
344 wr8(cpu, o->addr, (uint8_t)v);
348 wr16(cpu, o->addr, v);
350 watch_write(cpu, o->addr);
355static inline uint16_t add16(
Tms9900Cpu* cpu, uint16_t a, uint16_t b)
357 uint32_t res = (uint32_t)a + (uint32_t)b;
358 uint16_t r16 = (uint16_t)res;
360 if (res & 0x10000) cpu->st |= TMS_ST_C;
363 if ((uint16_t)(~(a ^ b) & (a ^ r16)) & 0x8000) cpu->st |= TMS_ST_OV;
364 set_flags_word(cpu, r16);
368static inline uint16_t sub16(
Tms9900Cpu* cpu, uint16_t a, uint16_t b)
370 uint32_t res = (uint32_t)a - (uint32_t)b;
371 uint16_t r16 = (uint16_t)res;
375 if (a >= b) cpu->st |= TMS_ST_C;
378 if ((uint16_t)((a ^ b) & (a ^ r16)) & 0x8000) cpu->st |= TMS_ST_OV;
379 set_flags_word(cpu, r16);
383static inline uint8_t add8(
Tms9900Cpu* cpu, uint8_t a, uint8_t b)
385 uint16_t res = (uint16_t)a + (uint16_t)b;
386 uint8_t r8 = (uint8_t)res;
388 if (res & 0x100) cpu->st |= TMS_ST_C;
389 if ((uint8_t)(~(a ^ b) & (a ^ r8)) & 0x80) cpu->st |= TMS_ST_OV;
390 set_flags_byte(cpu, r8);
394static inline uint8_t sub8(
Tms9900Cpu* cpu, uint8_t a, uint8_t b)
396 uint16_t res = (uint16_t)a - (uint16_t)b;
397 uint8_t r8 = (uint8_t)res;
401 if (a >= b) cpu->st |= TMS_ST_C;
402 if ((uint8_t)((a ^ b) & (a ^ r8)) & 0x80) cpu->st |= TMS_ST_OV;
403 set_flags_byte(cpu, r8);
411static inline void cmp16(
Tms9900Cpu* cpu, uint16_t first, uint16_t second)
417 cpu->st |= TMS_ST_EQ;
420 if (first > second) cpu->st |= TMS_ST_LGT;
421 if ((int16_t)first > (int16_t)second) cpu->st |= TMS_ST_AGT;
424static inline void cmp8(
Tms9900Cpu* cpu, uint8_t src, uint8_t dst)
427 cpu->st = (uint16_t)((cpu->st & 0x1A) | (byte_flags[src] & TMS_ST_P));
430 cpu->st |= TMS_ST_EQ;
433 if (src > dst) cpu->st |= TMS_ST_LGT;
434 if ((int8_t)src > (int8_t)dst) cpu->st |= TMS_ST_AGT;
437static inline uint16_t slx16(
Tms9900Cpu* cpu, uint16_t v, uint8_t count)
440 if (count == 0) count = 16;
444 uint32_t wide = (uint32_t)(int32_t)(int16_t)v << count;
445 uint16_t r = (uint16_t)wide;
447 if (wide & 0x10000u) cpu->st |= TMS_ST_C;
448 if (wide != (uint32_t)(int32_t)(int16_t)r) cpu->st |= TMS_ST_OV;
449 set_flags_word(cpu, r);
453static inline uint16_t sra16(
Tms9900Cpu* cpu, uint16_t v, uint8_t count)
457 if (count == 0) count = 16;
460 uint32_t wide = (uint32_t)(int32_t)(int16_t)v;
461 if ((wide >> (count - 1u)) & 1u) cpu->st |= TMS_ST_C;
462 uint16_t r = (uint16_t)(wide >> count);
463 set_flags_word(cpu, r);
467static inline uint16_t srl16(
Tms9900Cpu* cpu, uint16_t v, uint8_t count)
471 if (count == 0) count = 16;
474 if ((wide >> (count - 1u)) & 1u) cpu->st |= TMS_ST_C;
475 uint16_t r = (uint16_t)(wide >> count);
476 set_flags_word(cpu, r);
480static inline uint16_t src16(
Tms9900Cpu* cpu, uint16_t v, uint8_t count)
484 if (count == 0) count = 16;
488 uint16_t r = (uint16_t)((vv >> count) | (vv << (16u - count)));
489 uint16_t carry = (uint16_t)((vv >> (count - 1u)) & 1u);
490 if (carry) cpu->st |= TMS_ST_C;
491 set_flags_word(cpu, r);
495static inline uint16_t slc16(
Tms9900Cpu* cpu, uint16_t v, uint8_t count)
499 if (count == 0) count = 16;
502 uint32_t rot = (vv << count) | (vv >> (16 - count));
503 uint16_t r = (uint16_t)rot;
506 uint16_t carry = (uint16_t)((vv << (count - 1)) & 0x8000u);
507 if (carry) cpu->st |= TMS_ST_C;
508 set_flags_word(cpu, r);
513static inline void handle_two_operand(
Tms9900Cpu* cpu, uint16_t inst);
514static inline void handle_format9(
Tms9900Cpu* cpu, uint16_t inst);
515static inline int handle_branch_group(
Tms9900Cpu* cpu, uint16_t inst);
516static inline void handle_shift_rotate(
Tms9900Cpu* cpu, uint16_t inst);
517static inline void handle_f18a_stack(
Tms9900Cpu* cpu, uint16_t inst);
523static inline int handle_immediate_system(
Tms9900Cpu* cpu, uint16_t inst)
526 uint8_t sub = (uint8_t)((inst >> 5) & 0x1F);
527 uint8_t dest_reg = inst & 0xF;
533 uint16_t imm = fetchw(cpu);
534 set_reg(cpu, dest_reg, imm);
536 set_flags_word(cpu, imm);
541 uint16_t imm = fetchw(cpu);
542 uint16_t res = add16(cpu, get_reg(cpu, dest_reg), imm);
543 set_reg(cpu, dest_reg, res);
548 uint16_t imm = fetchw(cpu);
549 uint16_t res = get_reg(cpu, dest_reg) & imm;
550 set_reg(cpu, dest_reg, res);
552 set_flags_word(cpu, res);
557 uint16_t imm = fetchw(cpu);
558 uint16_t res = get_reg(cpu, dest_reg) | imm;
559 set_reg(cpu, dest_reg, res);
561 set_flags_word(cpu, res);
566 uint16_t imm = fetchw(cpu);
567 cmp16(cpu, get_reg(cpu, dest_reg), imm);
570 case 0x15: set_reg(cpu, dest_reg, cpu->wp);
break;
572 set_reg(cpu, dest_reg, (uint16_t)cpu->st << 8);
574 case 0x17: cpu->wp = fetchw(cpu) & 0xFFFE;
break;
582 uint32_t owp = (uint32_t)cpu->wp;
583 cpu->st = cpu->mem[owp + 30];
584 cpu->pc = (uint16_t)((cpu->mem[owp + 28] << 8) | cpu->mem[owp + 29]) & 0xFFFE;
585 cpu->wp = (uint16_t)((cpu->mem[owp + 26] << 8) | cpu->mem[owp + 27]) & 0xFFFE;
601static inline void handle_jump_single(
Tms9900Cpu* cpu, uint16_t inst)
603 uint8_t sub = (inst >> 6) & 0x1F;
608 Operand s = decode_operand(cpu, inst & 0x3F, 0);
609 uint32_t src_addr = wp_addr(cpu, inst & 0xF);
610 uint16_t new_wp = s.val & 0xFFFE;
611 uint16_t old_wp = cpu->wp;
612 uint16_t old_pc = cpu->pc;
613 uint16_t old_st = cpu->st;
617 wr16(cpu, (uint16_t)(new_wp + 26), old_wp);
618 wr16(cpu, (uint16_t)(new_wp + 28), old_pc);
619 wr16(cpu, (uint16_t)(new_wp + 30), (uint16_t)old_st << 8);
620 cpu->pc = (s.mode == 0) ? (uint16_t)((cpu->mem[src_addr + 2] << 8) | cpu->mem[src_addr + 3]) & 0xFFFE
621 : rd16(cpu, (uint16_t)(s.addr + 2)) & 0xFFFE;
628 Operand s = decode_addr(cpu, inst & 0x3F, 0);
629 uint32_t target = (s.mode == 0) ? wp_addr(cpu, inst & 0xF) : (uint32_t)s.addr;
630 cpu->pc = target & 0xFFFE;
635 Operand s = decode_operand(cpu, inst & 0x3F, 0);
636 uint16_t x_inst = s.val;
639 uint8_t x_hi = (uint8_t)(x_inst >> 8);
641 handle_two_operand(cpu, x_inst);
642 else if (x_hi >= 0x20)
643 handle_format9(cpu, x_inst);
644 else if (x_hi >= 0x10)
645 handle_branch_group(cpu, x_inst);
646 else if (x_hi >= 0x0C)
649 handle_shift_rotate(cpu, x_inst);
651 handle_f18a_stack(cpu, x_inst);
653 else if (x_hi >= 0x08)
654 handle_shift_rotate(cpu, x_inst);
655 else if (x_hi >= 0x04)
656 handle_jump_single(cpu, x_inst);
658 handle_immediate_system(cpu, x_inst);
663 Operand d = decode_addr(cpu, inst & 0x3F, 0);
664 store_operand(cpu, &d, 0);
669 Operand d = decode_operand(cpu, inst & 0x3F, 0);
671 if (d.val == 0x8000u)
673 cpu->st |= TMS_ST_OV;
674 set_flags_word(cpu, d.val);
678 uint16_t res = (uint16_t)(0u - d.val);
679 if (res == 0) cpu->st |= TMS_ST_C;
680 store_operand(cpu, &d, res);
681 set_flags_word(cpu, res);
687 Operand d = decode_operand(cpu, inst & 0x3F, 0);
688 uint16_t res = (uint16_t)~d.val;
689 store_operand(cpu, &d, res);
691 set_flags_word(cpu, res);
696 Operand d = decode_operand(cpu, inst & 0x3F, 0);
697 uint16_t res = add16(cpu, d.val, 1);
698 store_operand(cpu, &d, res);
703 Operand d = decode_operand(cpu, inst & 0x3F, 0);
704 uint16_t res = add16(cpu, d.val, 2);
705 store_operand(cpu, &d, res);
710 Operand d = decode_operand(cpu, inst & 0x3F, 0);
711 uint16_t res = sub16(cpu, d.val, 1);
712 store_operand(cpu, &d, res);
717 Operand d = decode_operand(cpu, inst & 0x3F, 0);
718 uint16_t res = sub16(cpu, d.val, 2);
719 store_operand(cpu, &d, res);
724 Operand s = decode_addr(cpu, inst & 0x3F, 0);
725 set_reg(cpu, 11, (uint16_t)cpu->pc);
726 uint32_t target = (s.mode == 0) ? wp_addr(cpu, inst & 0xF) : (uint32_t)s.addr;
727 cpu->pc = target & 0xFFFE;
732 Operand d = decode_operand(cpu, inst & 0x3F, 0);
733 uint16_t res = (uint16_t)((d.val << 8) | (d.val >> 8));
734 store_operand(cpu, &d, res);
739 Operand d = decode_addr(cpu, inst & 0x3F, 0);
740 store_operand(cpu, &d, 0xFFFF);
745 Operand d = decode_operand(cpu, inst & 0x3F, 0);
746 int16_t sv = (int16_t)d.val;
750 if (d.val == 0x8000u)
753 cpu->st |= TMS_ST_OV;
754 set_flags_word(cpu, d.val);
758 uint16_t res = (uint16_t)(0u - d.val);
759 store_operand(cpu, &d, res);
760 set_flags_word(cpu, d.val);
765 set_flags_word(cpu, d.val);
781static inline int handle_branch_group(
Tms9900Cpu* cpu, uint16_t inst)
783 int16_t disp = (int16_t)((int8_t)(inst & 0xFF)) * 2;
784 uint8_t cond = (inst >> 8) & 0xF;
793 cpu->pc = (cpu->pc - 2) & 0xFFFF;
796 cpu->pc = (cpu->pc + disp) & 0xFFFF;
799 if ((cpu->st & (TMS_ST_AGT | TMS_ST_EQ)) == 0) cpu->pc = (cpu->pc + disp) & 0xFFFF;
802 if (!(cpu->st & TMS_ST_LGT) || (cpu->st & TMS_ST_EQ)) cpu->pc = (cpu->pc + disp) & 0xFFFF;
805 if (cpu->st & TMS_ST_EQ) cpu->pc = (cpu->pc + disp) & 0xFFFF;
808 if (cpu->st & (TMS_ST_LGT | TMS_ST_EQ)) cpu->pc = (cpu->pc + disp) & 0xFFFF;
811 if (cpu->st & TMS_ST_AGT) cpu->pc = (cpu->pc + disp) & 0xFFFF;
814 if (!(cpu->st & TMS_ST_EQ)) cpu->pc = (cpu->pc + disp) & 0xFFFF;
817 if (!(cpu->st & TMS_ST_C)) cpu->pc = (cpu->pc + disp) & 0xFFFF;
820 if (cpu->st & TMS_ST_C) cpu->pc = (cpu->pc + disp) & 0xFFFF;
823 if (!(cpu->st & TMS_ST_OV)) cpu->pc = (cpu->pc + disp) & 0xFFFF;
826 if (!(cpu->st & (TMS_ST_LGT | TMS_ST_EQ))) cpu->pc = (cpu->pc + disp) & 0xFFFF;
829 if ((cpu->st & TMS_ST_LGT) && !(cpu->st & TMS_ST_EQ)) cpu->pc = (cpu->pc + disp) & 0xFFFF;
832 if (cpu->st & TMS_ST_P) cpu->pc = (cpu->pc + disp) & 0xFFFF;
836 case 0xF: cpu->st &= ~TMS_ST_EQ;
break;
846static inline void handle_shift_rotate(
Tms9900Cpu* cpu, uint16_t inst)
848 uint8_t sub = (inst >> 8) & 0xF;
849 uint8_t count = (inst >> 4) & 0xF;
850 uint8_t reg = inst & 0xF;
854 count = get_reg(cpu, 0) & 0xF;
855 if (count == 0) count = 16;
857 uint16_t v = get_reg(cpu, reg);
861 case 0x8: res = sra16(cpu, v, count);
break;
862 case 0x9: res = srl16(cpu, v, count);
break;
863 case 0xA: res = slx16(cpu, v, count);
break;
864 case 0xB: res = src16(cpu, v, count);
break;
865 case 0xE: res = slc16(cpu, v, count);
break;
868 set_reg(cpu, reg, res);
872static inline void handle_format9(
Tms9900Cpu* cpu, uint16_t inst)
875 uint8_t opcode = (uint8_t)((inst >> 10) & 0xF);
878 uint8_t dreg = (inst >> 6) & 0xF;
879 Operand src = decode_operand(cpu, inst & 0x3F, 0);
885 uint16_t d = get_reg(cpu, dreg);
886 if ((d & src.val) == src.val)
887 cpu->st |= TMS_ST_EQ;
889 cpu->st &= (uint16_t)~TMS_ST_EQ;
894 uint16_t d = get_reg(cpu, dreg);
895 if ((d & src.val) == 0)
896 cpu->st |= TMS_ST_EQ;
898 cpu->st &= (uint16_t)~TMS_ST_EQ;
903 uint16_t res = get_reg(cpu, dreg) ^ src.val;
904 set_reg(cpu, dreg, res);
906 set_flags_word(cpu, res);
912 uint16_t flags = get_reg(cpu, dreg);
913 uint16_t xy = src.val;
914 uint8_t x = (uint8_t)(xy >> 8);
915 uint8_t y = (uint8_t)(xy & 0xFF);
920 uint16_t r = (uint16_t)(((uint16_t)y << 5) | y);
921 r &= (uint16_t)~0xF8;
922 r |= (uint16_t)(x & 0xF8);
924 uint8_t vr04 = cpu->mem[0x6004];
925 r |= (uint16_t)((vr04 & 0x04) << 11);
927 set_reg(cpu, dreg, r);
931 uint8_t vr35 = cpu->mem[0x6023];
934 uint16_t stride = (uint16_t)((uint8_t)(vr35 - 1u) >> 2) + 1u;
935 uint8_t vr32 = cpu->mem[0x6020];
936 uint16_t a = (uint16_t)((((uint16_t)vr32 << 6) + y * stride + (x >> 2)) & 0x3FFF);
940 set_reg(cpu, dreg, a);
944 unsigned shift = 6u - 2u * (x & 3u);
945 uint8_t mask = (uint8_t)(3u << shift);
946 uint8_t b = cpu->mem[a];
947 uint8_t pixv = (uint8_t)((b >> shift) & 3u);
951 if (!(flags & 0x0400))
953 if (!(flags & 0x0200))
959 uint8_t pp_cmp = (uint8_t)((flags >> 4) & 0x03);
962 if (pixv == pp_cmp) do_write = 1;
966 if (pixv != pp_cmp) do_write = 1;
973 uint8_t pp_wr = (uint8_t)(flags & 0x03);
974 b = (uint8_t)((b & (uint8_t)~mask) | (pp_wr << shift));
981 flags = (uint16_t)((flags & ~0x03) | pixv);
982 set_reg(cpu, dreg, flags);
989 uint32_t prod = (uint32_t)get_reg(cpu, dreg) * (uint32_t)src.val;
990 set_reg(cpu, dreg, (uint16_t)(prod >> 16));
991 set_reg(cpu, (uint8_t)(dreg + 1), (uint16_t)(prod & 0xFFFF));
996 uint32_t dividend = ((uint32_t)get_reg(cpu, dreg) << 16) | get_reg(cpu, (uint8_t)(dreg + 1));
999 if ((dividend >> 16) >= src.val)
1001 cpu->st |= TMS_ST_OV;
1004 uint16_t quo = (uint16_t)(dividend / src.val);
1005 uint16_t rem = (uint16_t)(dividend % src.val);
1006 set_reg(cpu, dreg, quo);
1007 set_reg(cpu, (uint8_t)(dreg + 1), rem);
1008 cpu->st &= (uint16_t)~TMS_ST_OV;
1016static inline void handle_f18a_stack(
Tms9900Cpu* cpu, uint16_t inst)
1018 uint8_t hi = (inst >> 8) & 0xF;
1026 Operand s = decode_addr(cpu, inst & 0x3F, 0);
1027 uint16_t old_sp = get_reg(cpu, 15) & 0xFFFE;
1028 uint16_t new_sp = (uint16_t)(old_sp - 2);
1029 set_reg(cpu, 15, new_sp);
1030 wr16(cpu, old_sp, (uint16_t)cpu->pc);
1031 uint32_t target = (s.mode == 0) ? wp_addr(cpu, inst & 0xF) : (uint32_t)s.addr;
1032 cpu->pc = target & 0xFFFE;
1038 uint16_t sp = get_reg(cpu, 15) & 0xFFFE;
1039 cpu->pc = rd16(cpu, (uint16_t)(sp + 2)) & 0xFFFE;
1040 set_reg(cpu, 15, (uint16_t)(sp + 2));
1047 Operand s = decode_operand(cpu, inst & 0x3F, 0);
1048 uint16_t old_sp = get_reg(cpu, 15) & 0xFFFE;
1049 set_reg(cpu, 15, (uint16_t)(old_sp - 2));
1050 wr16(cpu, old_sp, s.val);
1056 Operand d = decode_addr(cpu, inst & 0x3F, 0);
1057 uint16_t old_sp = get_reg(cpu, 15) & 0xFFFE;
1058 uint16_t new_sp = (uint16_t)(old_sp + 2);
1059 set_reg(cpu, 15, new_sp);
1060 uint16_t v = rd16(cpu, new_sp);
1061 store_operand(cpu, &d, v);
1069static inline void handle_two_operand(
Tms9900Cpu* cpu, uint16_t inst)
1071 uint8_t opcode = (uint8_t)((inst >> 12) & 0xF);
1072 uint8_t byte_op = opcode & 1;
1073 Operand src = decode_operand(cpu, (uint8_t)(inst & 0x3F), byte_op);
1076 if ((opcode & 0xE) == 0xC)
1078 Operand dst = decode_addr(cpu, (uint8_t)((inst >> 6) & 0x3F), byte_op);
1081 uint8_t res = (uint8_t)src.val;
1082 store_operand(cpu, &dst, res);
1084 set_flags_byte(cpu, res);
1088 store_operand(cpu, &dst, src.val);
1090 set_flags_word(cpu, src.val);
1095 Operand dst = decode_operand(cpu, (uint8_t)((inst >> 6) & 0x3F), byte_op);
1104 uint8_t res = (uint8_t)dst.val & (uint8_t)~src.val;
1105 store_operand(cpu, &dst, res);
1107 set_flags_byte(cpu, res);
1111 uint16_t res = dst.val & (uint16_t)~src.val;
1112 store_operand(cpu, &dst, res);
1114 set_flags_word(cpu, res);
1120 uint16_t res = sub16(cpu, dst.val, src.val);
1121 store_operand(cpu, &dst, res);
1126 uint8_t res = sub8(cpu, (uint8_t)dst.val, (uint8_t)src.val);
1127 store_operand(cpu, &dst, res);
1132 cmp16(cpu, src.val, dst.val);
1137 cmp8(cpu, (uint8_t)src.val, (uint8_t)dst.val);
1142 uint16_t res = add16(cpu, dst.val, src.val);
1143 store_operand(cpu, &dst, res);
1148 uint8_t res = add8(cpu, (uint8_t)dst.val, (uint8_t)src.val);
1149 store_operand(cpu, &dst, res);
1154 uint16_t res = dst.val | src.val;
1155 store_operand(cpu, &dst, res);
1157 set_flags_word(cpu, res);
1162 uint8_t res = (uint8_t)dst.val | (uint8_t)src.val;
1163 store_operand(cpu, &dst, res);
1165 set_flags_byte(cpu, res);
1172#if !defined(TMS9900_PERSONALITY) || TMS9900_PERSONALITY == 0
1173void tms9900_init(
Tms9900Cpu* cpu, uint8_t* mem, uint8_t* regx38, uint16_t pc, uint16_t wp)
1176 cpu->regx38 = regx38;
1180 cpu->f18aMemory =
false;
1181#if defined(TMS9900_WATCH_WRITES)
1182 cpu->onWrite = NULL;
1183 cpu->onWriteMask = 0;
1184 cpu->onWriteMatch = 0;
1186#if defined(TMS9900_STEP_HOOK)
1188 cpu->onStepData = NULL;
1194#if !defined(TMS9900_PERSONALITY)
1197 return run9900_budget_c(cpu, 0, NULL);
1201uint16_t run9900_budget_c(
Tms9900Cpu* cpu, uint32_t budget,
bool* outOfBudget)
1203 const int limited = budget != 0;
1204 if (outOfBudget) *outOfBudget =
false;
1205 while ((*cpu->regx38 & 1u) != 0)
1207 if (limited && budget-- == 0)
1209 if (outOfBudget) *outOfBudget =
true;
1212#if defined(TMS9900_STEP_HOOK)
1213 if (cpu->onStep && !cpu->onStep(cpu))
1215 if (outOfBudget) *outOfBudget =
true;
1219 uint16_t inst = fetchw(cpu);
1220 uint8_t op_hi = (uint8_t)(inst >> 8);
1225 handle_two_operand(cpu, inst);
1227 else if (op_hi >= 0x20)
1230 handle_format9(cpu, inst);
1232 else if (op_hi >= 0x10)
1235 if (!handle_branch_group(cpu, inst))
return cpu->pc;
1237 else if (op_hi >= 0x0C)
1241 handle_shift_rotate(cpu, inst);
1243 handle_f18a_stack(cpu, inst);
1245 else if (op_hi >= 0x08)
1248 handle_shift_rotate(cpu, inst);
1250 else if (op_hi >= 0x04)
1253 handle_jump_single(cpu, inst);
1258 if (!handle_immediate_system(cpu, inst))
return cpu->pc;
pico9918-core - TMS9900 CPU interpreter (portable C)