38static const uint8_t parity_tbl[256] = {
39 0, 4, 4, 0, 4, 0, 0, 4, 4, 0, 0, 4, 0, 4, 4, 0, 4, 0, 0, 4, 0, 4, 4, 0, 0, 4, 4, 0, 4, 0, 0, 4,
40 4, 0, 0, 4, 0, 4, 4, 0, 0, 4, 4, 0, 4, 0, 0, 4, 0, 4, 4, 0, 4, 0, 0, 4, 4, 0, 0, 4, 0, 4, 4, 0,
41 4, 0, 0, 4, 0, 4, 4, 0, 0, 4, 4, 0, 4, 0, 0, 4, 0, 4, 4, 0, 4, 0, 0, 4, 4, 0, 0, 4, 0, 4, 4, 0,
42 0, 4, 4, 0, 4, 0, 0, 4, 4, 0, 0, 4, 0, 4, 4, 0, 4, 0, 0, 4, 0, 4, 4, 0, 0, 4, 4, 0, 4, 0, 0, 4,
43 4, 0, 0, 4, 0, 4, 4, 0, 0, 4, 4, 0, 4, 0, 0, 4, 0, 4, 4, 0, 4, 0, 0, 4, 4, 0, 0, 4, 0, 4, 4, 0,
44 0, 4, 4, 0, 4, 0, 0, 4, 4, 0, 0, 4, 0, 4, 4, 0, 4, 0, 0, 4, 0, 4, 4, 0, 0, 4, 4, 0, 4, 0, 0, 4,
45 0, 4, 4, 0, 4, 0, 0, 4, 4, 0, 0, 4, 0, 4, 4, 0, 4, 0, 0, 4, 0, 4, 4, 0, 0, 4, 4, 0, 4, 0, 0, 4,
46 4, 0, 0, 4, 0, 4, 4, 0, 0, 4, 4, 0, 4, 0, 0, 4, 0, 4, 4, 0, 4, 0, 0, 4, 4, 0, 0, 4, 0, 4, 4, 0};
51static inline void set_flags_word(
Tms9900Cpu* cpu, uint16_t v)
54 int16_t sv = (int16_t)v;
62 cpu->st |= (TMS_ST_LGT | TMS_ST_AGT);
66 cpu->st |= TMS_ST_LGT;
70static inline void set_flags_byte(
Tms9900Cpu* cpu, uint8_t v)
73 cpu->st = (uint16_t)((cpu->st & ~(TMS_ST_LGT | TMS_ST_AGT | TMS_ST_EQ | TMS_ST_P)) | parity_tbl[v]);
74 int8_t sv = (int8_t)v;
81 cpu->st |= (TMS_ST_LGT | TMS_ST_AGT);
83 cpu->st |= TMS_ST_LGT;
110static const uint16_t gpu_window_base[16] = {0x0000, 0x0000, 0x0000, 0x0000, 0x4000, 0x5000, 0x6000, 0x7000,
111 0x8000, 0x0000, 0xB00E, 0xB002, 0x0000, 0x0000, 0x0000, 0x0000};
113static const uint16_t gpu_window_mask[16] = {0x3FFF, 0x3FFF, 0x3FFF, 0x3FFF, 0x07FF, 0x007F, 0x003F, 0x0001,
114 0x000F, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000};
117#define GPU_WINDOW_READS 0x05FFu
118#define GPU_WINDOW_WRITES 0x097Fu
120static inline uint32_t gpu_addr(uint16_t a)
122 const uint32_t w = a >> 12;
123 return gpu_window_base[w] | (a & gpu_window_mask[w]);
126static inline uint8_t rd8(
Tms9900Cpu* cpu, uint16_t a)
128 if (!cpu->f18aMemory)
return cpu->mem[a];
129 if (!((GPU_WINDOW_READS >> (a >> 12)) & 1))
return 0;
130 return cpu->mem[gpu_addr(a)];
133static inline void wr8(
Tms9900Cpu* cpu, uint16_t a, uint8_t v)
135 if (!cpu->f18aMemory)
140 if (!((GPU_WINDOW_WRITES >> (a >> 12)) & 1))
return;
141 const uint32_t at = gpu_addr(a);
144 cpu->mem[at] = (at == 0xB002) ? (uint8_t)((v & 0x7F) | (cpu->mem[at] & 0x80)) : v;
147static inline uint16_t rd16(
Tms9900Cpu* cpu, uint16_t a)
149 return (uint16_t)((rd8(cpu, a) << 8) | rd8(cpu, (uint16_t)(a + 1)));
152static inline void wr16(
Tms9900Cpu* cpu, uint16_t a, uint16_t v)
154 wr8(cpu, a, (uint8_t)(v >> 8));
155 wr8(cpu, (uint16_t)(a + 1), (uint8_t)(v & 0xFF));
161#if defined(TMS9900_WATCH_WRITES)
162static inline void watch_write(
Tms9900Cpu* cpu, uint32_t addr)
164 if (cpu->onWrite) cpu->onWrite(cpu->mem, cpu->f18aMemory ? gpu_addr((uint16_t)addr) : addr);
167#define watch_write(cpu, addr) ((void)0)
172static inline uint32_t wp_addr(
Tms9900Cpu* cpu, uint8_t r)
174 return (uint32_t)cpu->wp + ((uint32_t)r << 1);
177static inline uint16_t get_reg(
Tms9900Cpu* cpu, uint8_t r)
179 uint32_t a = wp_addr(cpu, r);
180 return (uint16_t)((cpu->mem[a] << 8) | cpu->mem[a + 1]);
183static inline void set_reg(
Tms9900Cpu* cpu, uint8_t r, uint16_t v)
185 uint32_t a = wp_addr(cpu, r);
186 cpu->mem[a] = (uint8_t)(v >> 8);
187 cpu->mem[a + 1] = (uint8_t)(v & 0xFF);
202 uint16_t a = (uint16_t)cpu->pc;
203 cpu->pc = (a + 2) & 0xFFFF;
210 o.mode = (field >> 4) & 0x3;
217 if (is_byte) o.addr = (uint16_t)wp_addr(cpu, o.reg);
218 o.val = is_byte ? cpu->mem[wp_addr(cpu, o.reg)] : get_reg(cpu, o.reg);
221 o.addr = get_reg(cpu, o.reg);
222 if (!is_byte) o.addr &= 0xFFFE;
223 o.val = is_byte ? rd8(cpu, o.addr) : rd16(cpu, o.addr);
227 uint16_t offset = fetchw(cpu);
232 ea = (uint16_t)(get_reg(cpu, o.reg) + offset);
233 o.addr = is_byte ? ea : (ea & 0xFFFE);
234 o.val = is_byte ? rd8(cpu, o.addr) : rd16(cpu, o.addr);
240 uint16_t raw = get_reg(cpu, o.reg);
241 uint16_t inc = is_byte ? 1u : 2u;
242 set_reg(cpu, o.reg, (uint16_t)(raw + inc));
243 o.addr = is_byte ? raw : (raw & 0xFFFE);
244 o.val = is_byte ? rd8(cpu, o.addr) : rd16(cpu, o.addr);
257 cpu->mem[wp_addr(cpu, o->reg)] = (uint8_t)v;
261 set_reg(cpu, o->reg, v);
268 wr8(cpu, o->addr, (uint8_t)v);
272 wr16(cpu, o->addr, v);
274 watch_write(cpu, o->addr);
279static inline uint16_t add16(
Tms9900Cpu* cpu, uint16_t a, uint16_t b)
281 uint32_t res = (uint32_t)a + (uint32_t)b;
282 uint16_t r16 = (uint16_t)res;
284 if (res & 0x10000) cpu->st |= TMS_ST_C;
287 if (((a ^ b) & 0x8000) == 0 && ((a ^ r16) & 0x8000)) cpu->st |= TMS_ST_OV;
288 set_flags_word(cpu, r16);
292static inline uint16_t sub16(
Tms9900Cpu* cpu, uint16_t a, uint16_t b)
294 uint32_t res = (uint32_t)a - (uint32_t)b;
295 uint16_t r16 = (uint16_t)res;
299 if (b == 0 || a >= r16) cpu->st |= TMS_ST_C;
302 if (((a ^ b) & 0x8000) && ((a ^ r16) & 0x8000)) cpu->st |= TMS_ST_OV;
303 set_flags_word(cpu, r16);
307static inline uint8_t add8(
Tms9900Cpu* cpu, uint8_t a, uint8_t b)
309 uint16_t res = (uint16_t)a + (uint16_t)b;
310 uint8_t r8 = (uint8_t)res;
312 if (res & 0x100) cpu->st |= TMS_ST_C;
313 if (((a ^ b) & 0x80) == 0 && ((a ^ r8) & 0x80)) cpu->st |= TMS_ST_OV;
314 set_flags_byte(cpu, r8);
318static inline uint8_t sub8(
Tms9900Cpu* cpu, uint8_t a, uint8_t b)
320 uint16_t res = (uint16_t)a - (uint16_t)b;
321 uint8_t r8 = (uint8_t)res;
325 if (b == 0 || a >= r8) cpu->st |= TMS_ST_C;
326 if (((a ^ b) & 0x80) && ((a ^ r8) & 0x80)) cpu->st |= TMS_ST_OV;
327 set_flags_byte(cpu, r8);
335static inline void cmp16(
Tms9900Cpu* cpu, uint16_t first, uint16_t second)
341 cpu->st |= TMS_ST_EQ;
344 if (first > second) cpu->st |= TMS_ST_LGT;
345 if ((int16_t)first > (int16_t)second) cpu->st |= TMS_ST_AGT;
348static inline void cmp8(
Tms9900Cpu* cpu, uint8_t src, uint8_t dst)
351 cpu->st = (uint16_t)((cpu->st & 0x1A) | parity_tbl[src]);
354 cpu->st |= TMS_ST_EQ;
357 if (src > dst) cpu->st |= TMS_ST_LGT;
358 if ((int8_t)src > (int8_t)dst) cpu->st |= TMS_ST_AGT;
361static inline uint16_t slx16(
Tms9900Cpu* cpu, uint16_t v, uint8_t count)
364 if (count == 0) count = 16;
365 uint32_t vv = (uint32_t)v;
366 uint32_t mask_change = 0;
369 for (uint8_t i = 0; i < count; ++i)
371 uint32_t msb = vv & 0x8000;
373 if (msb != (vv & 0x8000)) mask_change = 1;
375 if (vv & 0x10000) cpu->st |= TMS_ST_C;
376 uint16_t r = (uint16_t)vv;
377 if (mask_change) cpu->st |= TMS_ST_OV;
378 set_flags_word(cpu, r);
382static inline uint16_t sra16(
Tms9900Cpu* cpu, uint16_t v, uint8_t count)
386 if (count == 0) count = 16;
387 int32_t vv = (int32_t)(int16_t)v;
389 for (uint8_t i = 0; i < count; ++i)
391 carry = (uint16_t)((uint32_t)vv & 1u);
394 if (carry) cpu->st |= TMS_ST_C;
395 uint16_t r = (uint16_t)vv;
396 set_flags_word(cpu, r);
400static inline uint16_t srl16(
Tms9900Cpu* cpu, uint16_t v, uint8_t count)
404 if (count == 0) count = 16;
407 for (uint8_t i = 0; i < count; ++i)
409 carry = (uint16_t)(vv & 1u);
412 if (carry) cpu->st |= TMS_ST_C;
413 uint16_t r = (uint16_t)vv;
414 set_flags_word(cpu, r);
418static inline uint16_t src16(
Tms9900Cpu* cpu, uint16_t v, uint8_t count)
422 if (count == 0) count = 16;
426 uint16_t r = (uint16_t)((vv >> count) | (vv << (16u - count)));
427 uint16_t carry = (uint16_t)((vv >> (count - 1u)) & 1u);
428 if (carry) cpu->st |= TMS_ST_C;
429 set_flags_word(cpu, r);
433static inline uint16_t slc16(
Tms9900Cpu* cpu, uint16_t v, uint8_t count)
437 if (count == 0) count = 16;
440 uint32_t rot = (vv << count) | (vv >> (16 - count));
441 uint16_t r = (uint16_t)rot;
444 uint16_t carry = (uint16_t)((vv << (count - 1)) & 0x8000u);
445 if (carry) cpu->st |= TMS_ST_C;
446 set_flags_word(cpu, r);
450static inline uint16_t src_through_c(
Tms9900Cpu* cpu, uint16_t v, uint8_t count)
453 if (count == 0) count = 16;
454 uint32_t vv = ((uint32_t)v << 1) | ((cpu->st & TMS_ST_C) ? 1u : 0u);
455 for (uint8_t i = 0; i < count; ++i)
457 uint32_t c = vv & 1u;
459 if (c) vv |= 0x8000u;
460 cpu->st = (cpu->st & ~TMS_ST_C) | (c ? TMS_ST_C : 0);
462 uint16_t r = (uint16_t)vv;
463 set_flags_word(cpu, r);
468static inline void handle_two_operand(
Tms9900Cpu* cpu, uint16_t inst);
469static inline void handle_format9(
Tms9900Cpu* cpu, uint16_t inst);
470static inline int handle_branch_group(
Tms9900Cpu* cpu, uint16_t inst);
471static inline void handle_shift_rotate(
Tms9900Cpu* cpu, uint16_t inst);
472static inline void handle_f18a_stack(
Tms9900Cpu* cpu, uint16_t inst);
478static inline int handle_immediate_system(
Tms9900Cpu* cpu, uint16_t inst)
481 uint8_t sub = (uint8_t)((inst >> 5) & 0x1F);
482 uint8_t dest_reg = inst & 0xF;
488 uint16_t imm = fetchw(cpu);
489 set_reg(cpu, dest_reg, imm);
491 set_flags_word(cpu, imm);
496 uint16_t imm = fetchw(cpu);
497 uint16_t res = add16(cpu, get_reg(cpu, dest_reg), imm);
498 set_reg(cpu, dest_reg, res);
503 uint16_t imm = fetchw(cpu);
504 uint16_t res = get_reg(cpu, dest_reg) & imm;
505 set_reg(cpu, dest_reg, res);
507 set_flags_word(cpu, res);
512 uint16_t imm = fetchw(cpu);
513 uint16_t res = get_reg(cpu, dest_reg) | imm;
514 set_reg(cpu, dest_reg, res);
516 set_flags_word(cpu, res);
521 uint16_t imm = fetchw(cpu);
522 cmp16(cpu, get_reg(cpu, dest_reg), imm);
525 case 0x15: set_reg(cpu, dest_reg, cpu->wp);
break;
527 set_reg(cpu, dest_reg, (uint16_t)cpu->st << 8);
529 case 0x17: cpu->wp = fetchw(cpu) & 0xFFFE;
break;
537 uint32_t owp = (uint32_t)cpu->wp;
538 cpu->st = cpu->mem[owp + 30];
539 cpu->pc = (uint16_t)((cpu->mem[owp + 28] << 8) | cpu->mem[owp + 29]) & 0xFFFE;
540 cpu->wp = (uint16_t)((cpu->mem[owp + 26] << 8) | cpu->mem[owp + 27]) & 0xFFFE;
556static inline void handle_jump_single(
Tms9900Cpu* cpu, uint16_t inst)
558 uint8_t sub = (inst >> 6) & 0x1F;
563 Operand s = decode_operand(cpu, inst & 0x3F, 0);
564 uint32_t src_addr = wp_addr(cpu, inst & 0xF);
565 uint16_t new_wp = (s.mode == 0) ? (uint16_t)((cpu->mem[src_addr] << 8) | cpu->mem[src_addr + 1]) & 0xFFFE
566 : rd16(cpu, s.addr) & 0xFFFE;
567 uint16_t old_wp = cpu->wp;
568 uint16_t old_pc = cpu->pc;
569 uint16_t old_st = cpu->st;
573 wr16(cpu, (uint16_t)(new_wp + 26), old_wp);
574 wr16(cpu, (uint16_t)(new_wp + 28), old_pc);
575 wr16(cpu, (uint16_t)(new_wp + 30), (uint16_t)old_st << 8);
576 cpu->pc = (s.mode == 0) ? (uint16_t)((cpu->mem[src_addr + 2] << 8) | cpu->mem[src_addr + 3]) & 0xFFFE
577 : rd16(cpu, (uint16_t)(s.addr + 2)) & 0xFFFE;
584 Operand s = decode_operand(cpu, inst & 0x3F, 0);
585 uint32_t target = (s.mode == 0) ? wp_addr(cpu, inst & 0xF) : (uint32_t)s.addr;
586 cpu->pc = target & 0xFFFE;
591 Operand s = decode_operand(cpu, inst & 0x3F, 0);
592 uint16_t x_inst = (s.mode == 0) ? s.val : rd16(cpu, s.addr);
595 uint8_t x_hi = (uint8_t)(x_inst >> 8);
597 handle_two_operand(cpu, x_inst);
598 else if (x_hi >= 0x20)
599 handle_format9(cpu, x_inst);
600 else if (x_hi >= 0x10)
601 handle_branch_group(cpu, x_inst);
602 else if (x_hi >= 0x0C)
605 handle_shift_rotate(cpu, x_inst);
607 handle_f18a_stack(cpu, x_inst);
609 else if (x_hi >= 0x08)
610 handle_shift_rotate(cpu, x_inst);
611 else if (x_hi >= 0x04)
612 handle_jump_single(cpu, x_inst);
614 handle_immediate_system(cpu, x_inst);
619 Operand d = decode_operand(cpu, inst & 0x3F, 0);
620 store_operand(cpu, &d, 0);
625 Operand d = decode_operand(cpu, inst & 0x3F, 0);
627 if (d.val == 0x8000u)
629 cpu->st |= TMS_ST_OV;
630 set_flags_word(cpu, d.val);
634 uint16_t res = (uint16_t)(0u - d.val);
635 if (res == 0) cpu->st |= TMS_ST_C;
636 store_operand(cpu, &d, res);
637 set_flags_word(cpu, res);
643 Operand d = decode_operand(cpu, inst & 0x3F, 0);
644 uint16_t res = (uint16_t)~d.val;
645 store_operand(cpu, &d, res);
647 set_flags_word(cpu, res);
652 Operand d = decode_operand(cpu, inst & 0x3F, 0);
653 uint16_t res = add16(cpu, d.val, 1);
654 store_operand(cpu, &d, res);
659 Operand d = decode_operand(cpu, inst & 0x3F, 0);
660 uint16_t res = add16(cpu, d.val, 2);
661 store_operand(cpu, &d, res);
666 Operand d = decode_operand(cpu, inst & 0x3F, 0);
667 uint16_t res = sub16(cpu, d.val, 1);
668 store_operand(cpu, &d, res);
673 Operand d = decode_operand(cpu, inst & 0x3F, 0);
674 uint16_t res = sub16(cpu, d.val, 2);
675 store_operand(cpu, &d, res);
680 Operand s = decode_operand(cpu, inst & 0x3F, 0);
681 set_reg(cpu, 11, (uint16_t)cpu->pc);
682 uint32_t target = (s.mode == 0) ? wp_addr(cpu, inst & 0xF) : (uint32_t)s.addr;
683 cpu->pc = target & 0xFFFE;
688 Operand d = decode_operand(cpu, inst & 0x3F, 0);
689 uint16_t res = (uint16_t)((d.val << 8) | (d.val >> 8));
690 store_operand(cpu, &d, res);
695 Operand d = decode_operand(cpu, inst & 0x3F, 0);
696 store_operand(cpu, &d, 0xFFFF);
701 Operand d = decode_operand(cpu, inst & 0x3F, 0);
702 int16_t sv = (int16_t)d.val;
706 if (d.val == 0x8000u)
709 cpu->st |= TMS_ST_OV;
710 set_flags_word(cpu, d.val);
714 uint16_t res = (uint16_t)(0u - d.val);
715 store_operand(cpu, &d, res);
716 set_flags_word(cpu, d.val);
721 set_flags_word(cpu, d.val);
737static inline int handle_branch_group(
Tms9900Cpu* cpu, uint16_t inst)
739 int16_t disp = (int16_t)((int8_t)(inst & 0xFF)) * 2;
740 uint8_t cond = (inst >> 8) & 0xF;
749 cpu->pc = (cpu->pc - 2) & 0xFFFF;
752 cpu->pc = (cpu->pc + disp) & 0xFFFF;
755 if ((cpu->st & (TMS_ST_AGT | TMS_ST_EQ)) == 0) cpu->pc = (cpu->pc + disp) & 0xFFFF;
758 if (!(cpu->st & TMS_ST_LGT) || (cpu->st & TMS_ST_EQ)) cpu->pc = (cpu->pc + disp) & 0xFFFF;
761 if (cpu->st & TMS_ST_EQ) cpu->pc = (cpu->pc + disp) & 0xFFFF;
764 if (cpu->st & (TMS_ST_LGT | TMS_ST_EQ)) cpu->pc = (cpu->pc + disp) & 0xFFFF;
767 if (cpu->st & TMS_ST_AGT) cpu->pc = (cpu->pc + disp) & 0xFFFF;
770 if (!(cpu->st & TMS_ST_EQ)) cpu->pc = (cpu->pc + disp) & 0xFFFF;
773 if (!(cpu->st & TMS_ST_C)) cpu->pc = (cpu->pc + disp) & 0xFFFF;
776 if (cpu->st & TMS_ST_C) cpu->pc = (cpu->pc + disp) & 0xFFFF;
779 if (!(cpu->st & TMS_ST_OV)) cpu->pc = (cpu->pc + disp) & 0xFFFF;
782 if (!(cpu->st & (TMS_ST_LGT | TMS_ST_EQ))) cpu->pc = (cpu->pc + disp) & 0xFFFF;
785 if ((cpu->st & TMS_ST_LGT) && !(cpu->st & TMS_ST_EQ)) cpu->pc = (cpu->pc + disp) & 0xFFFF;
788 if (cpu->st & TMS_ST_P) cpu->pc = (cpu->pc + disp) & 0xFFFF;
792 case 0xF: cpu->st &= ~TMS_ST_EQ;
break;
802static inline void handle_cru_single_bit(
void) {}
808static inline void handle_shift_rotate(
Tms9900Cpu* cpu, uint16_t inst)
810 uint8_t sub = (inst >> 8) & 0xF;
811 uint8_t count = (inst >> 4) & 0xF;
812 uint8_t reg = inst & 0xF;
816 count = get_reg(cpu, 0) & 0xF;
817 if (count == 0) count = 16;
819 uint16_t v = get_reg(cpu, reg);
823 case 0x8: res = sra16(cpu, v, count);
break;
824 case 0x9: res = srl16(cpu, v, count);
break;
825 case 0xA: res = slx16(cpu, v, count);
break;
826 case 0xB: res = src16(cpu, v, count);
break;
827 case 0xE: res = slc16(cpu, v, count);
break;
830 set_reg(cpu, reg, res);
834static inline void handle_format9(
Tms9900Cpu* cpu, uint16_t inst)
837 uint8_t opcode = (uint8_t)((inst >> 10) & 0xF);
840 uint8_t dreg = (inst >> 6) & 0xF;
841 Operand src = decode_operand(cpu, inst & 0x3F, 0);
847 uint16_t d = get_reg(cpu, dreg);
848 if ((d & src.val) == src.val)
849 cpu->st |= TMS_ST_EQ;
851 cpu->st &= (uint16_t)~TMS_ST_EQ;
856 uint16_t d = get_reg(cpu, dreg);
857 if ((d & src.val) == 0)
858 cpu->st |= TMS_ST_EQ;
860 cpu->st &= (uint16_t)~TMS_ST_EQ;
865 uint16_t res = get_reg(cpu, dreg) ^ src.val;
866 set_reg(cpu, dreg, res);
868 set_flags_word(cpu, res);
873 static const uint8_t pix_mask[] = {0xC0, 0x30, 0x0C, 0x03};
874 static const uint8_t pix_shift[] = {6, 4, 2, 0};
876 uint16_t flags = get_reg(cpu, dreg);
877 uint16_t xy = src.val;
878 uint8_t x = (uint8_t)(xy >> 8);
879 uint8_t y = (uint8_t)(xy & 0xFF);
884 uint16_t r = (uint16_t)(((uint16_t)y << 5) | y);
885 r &= (uint16_t)~0xF8;
886 r |= (uint16_t)(x & 0xF8);
888 uint8_t vr04 = cpu->mem[0x6004];
889 r |= (uint16_t)((vr04 & 0x04) << 11);
891 set_reg(cpu, dreg, r);
895 uint8_t vr35 = cpu->mem[0x6023];
896 uint16_t width = (vr35 == 0) ? 256u : (uint16_t)vr35;
899 uint16_t stride = (uint16_t)((width + 3) >> 2);
900 uint8_t vr32 = cpu->mem[0x6020];
901 uint16_t a = (uint16_t)((((uint16_t)vr32 << 6) + y * stride + (x >> 2)) & 0x3FFF);
905 set_reg(cpu, dreg, a);
909 uint8_t s = (uint8_t)(x & 0x03);
910 uint8_t b = cpu->mem[a];
911 uint8_t pixv = (uint8_t)((b & pix_mask[s]) >> pix_shift[s]);
915 if (!(flags & 0x0400))
917 if (!(flags & 0x0200))
923 uint8_t pp_cmp = (uint8_t)((flags >> 4) & 0x03);
926 if (pixv == pp_cmp) do_write = 1;
930 if (pixv != pp_cmp) do_write = 1;
937 uint8_t pp_wr = (uint8_t)(flags & 0x03);
938 b = (uint8_t)((b & ~pix_mask[s]) | (pp_wr << pix_shift[s]));
945 flags = (uint16_t)((flags & ~0x03) | pixv);
946 set_reg(cpu, dreg, flags);
953 uint32_t prod = (uint32_t)get_reg(cpu, dreg) * (uint32_t)src.val;
954 set_reg(cpu, dreg, (uint16_t)(prod >> 16));
955 set_reg(cpu, (uint8_t)(dreg + 1), (uint16_t)(prod & 0xFFFF));
960 uint32_t dividend = ((uint32_t)get_reg(cpu, dreg) << 16) | get_reg(cpu, (uint8_t)(dreg + 1));
961 if (src.val == 0 || (dividend >> 16) >= src.val)
963 cpu->st |= TMS_ST_OV;
966 uint16_t quo = (uint16_t)(dividend / src.val);
967 uint16_t rem = (uint16_t)(dividend % src.val);
968 set_reg(cpu, dreg, quo);
969 set_reg(cpu, (uint8_t)(dreg + 1), rem);
970 cpu->st &= (uint16_t)~TMS_ST_OV;
978static inline void handle_f18a_stack(
Tms9900Cpu* cpu, uint16_t inst)
980 uint8_t hi = (inst >> 8) & 0xF;
988 Operand s = decode_operand(cpu, inst & 0x3F, 0);
989 uint16_t old_sp = get_reg(cpu, 15) & 0xFFFE;
990 uint16_t new_sp = (uint16_t)(old_sp - 2);
991 set_reg(cpu, 15, new_sp);
992 wr16(cpu, old_sp, (uint16_t)cpu->pc);
993 uint32_t target = (s.mode == 0) ? wp_addr(cpu, inst & 0xF) : (uint32_t)s.addr;
994 cpu->pc = target & 0xFFFE;
1000 uint16_t sp = get_reg(cpu, 15) & 0xFFFE;
1001 cpu->pc = rd16(cpu, (uint16_t)(sp + 2)) & 0xFFFE;
1002 set_reg(cpu, 15, (uint16_t)(sp + 2));
1009 Operand s = decode_operand(cpu, inst & 0x3F, 0);
1010 uint16_t old_sp = get_reg(cpu, 15) & 0xFFFE;
1011 set_reg(cpu, 15, (uint16_t)(old_sp - 2));
1012 wr16(cpu, old_sp, s.val);
1018 Operand d = decode_operand(cpu, inst & 0x3F, 0);
1019 uint16_t old_sp = get_reg(cpu, 15) & 0xFFFE;
1020 uint16_t new_sp = (uint16_t)(old_sp + 2);
1021 set_reg(cpu, 15, new_sp);
1022 uint16_t v = rd16(cpu, new_sp);
1023 store_operand(cpu, &d, v);
1031static inline void handle_two_operand(
Tms9900Cpu* cpu, uint16_t inst)
1033 uint8_t opcode = (uint8_t)((inst >> 12) & 0xF);
1034 uint8_t byte_op = opcode & 1;
1035 Operand src = decode_operand(cpu, (uint8_t)(inst & 0x3F), byte_op);
1036 Operand dst = decode_operand(cpu, (uint8_t)((inst >> 6) & 0x3F), byte_op);
1045 uint8_t res = (uint8_t)dst.val & (uint8_t)~src.val;
1046 store_operand(cpu, &dst, res);
1048 set_flags_byte(cpu, res);
1052 uint16_t res = dst.val & (uint16_t)~src.val;
1053 store_operand(cpu, &dst, res);
1055 set_flags_word(cpu, res);
1061 uint16_t res = sub16(cpu, dst.val, src.val);
1062 store_operand(cpu, &dst, res);
1067 uint8_t res = sub8(cpu, (uint8_t)dst.val, (uint8_t)src.val);
1068 store_operand(cpu, &dst, res);
1073 cmp16(cpu, src.val, dst.val);
1078 cmp8(cpu, (uint8_t)src.val, (uint8_t)dst.val);
1083 uint16_t res = add16(cpu, dst.val, src.val);
1084 store_operand(cpu, &dst, res);
1089 uint8_t res = add8(cpu, (uint8_t)dst.val, (uint8_t)src.val);
1090 store_operand(cpu, &dst, res);
1095 store_operand(cpu, &dst, src.val);
1097 set_flags_word(cpu, src.val);
1102 uint8_t res = (uint8_t)src.val;
1103 store_operand(cpu, &dst, res);
1105 set_flags_byte(cpu, res);
1110 uint16_t res = dst.val | src.val;
1111 store_operand(cpu, &dst, res);
1113 set_flags_word(cpu, res);
1118 uint8_t res = (uint8_t)dst.val | (uint8_t)src.val;
1119 store_operand(cpu, &dst, res);
1121 set_flags_byte(cpu, res);
1127void tms9900_init(
Tms9900Cpu* cpu, uint8_t* mem, uint8_t* regx38, uint16_t pc, uint16_t wp)
1130 cpu->regx38 = regx38;
1134 cpu->f18aMemory =
false;
1135#if defined(TMS9900_WATCH_WRITES)
1136 cpu->onWrite = NULL;
1142 return run9900_budget_c(cpu, 0, NULL);
1145uint16_t run9900_budget_c(
Tms9900Cpu* cpu, uint32_t budget,
bool* outOfBudget)
1147 const int limited = budget != 0;
1148 if (outOfBudget) *outOfBudget =
false;
1149 while ((*cpu->regx38 & 1u) != 0)
1151 if (limited && budget-- == 0)
1153 if (outOfBudget) *outOfBudget =
true;
1156 uint16_t inst = fetchw(cpu);
1157 uint8_t op_hi = (uint8_t)(inst >> 8);
1162 handle_two_operand(cpu, inst);
1164 else if (op_hi >= 0x20)
1167 handle_format9(cpu, inst);
1169 else if (op_hi >= 0x10)
1172 if (!handle_branch_group(cpu, inst))
return cpu->pc;
1174 else if (op_hi >= 0x0C)
1178 handle_shift_rotate(cpu, inst);
1180 handle_f18a_stack(cpu, inst);
1182 else if (op_hi >= 0x08)
1185 handle_shift_rotate(cpu, inst);
1187 else if (op_hi >= 0x04)
1190 handle_jump_single(cpu, inst);
1195 if (!handle_immediate_system(cpu, inst))
return cpu->pc;
pico9918-core - TMS9900 CPU interpreter (portable C)