Mercurial > repos > blastem
comparison m68k_util.c @ 2587:e04c7e753bf6
Implement divs and divu in new CPU core
author | Michael Pavone <pavone@retrodev.com> |
---|---|
date | Sat, 08 Feb 2025 20:04:18 -0800 |
parents | 939b818df589 |
children | e602dbf776d8 |
comparison
equal
deleted
inserted
replaced
2586:6c58cadeabe1 | 2587:e04c7e753bf6 |
---|---|
7 } | 7 } |
8 | 8 |
9 void m68k_read_16(m68k_context *context) | 9 void m68k_read_16(m68k_context *context) |
10 { | 10 { |
11 context->cycles += 4 * context->opts->gen.clock_divider; | 11 context->cycles += 4 * context->opts->gen.clock_divider; |
12 uint32_t tmp = context->scratch1; | |
12 context->scratch1 = read_word(context->scratch1, context->mem_pointers, &context->opts->gen, context); | 13 context->scratch1 = read_word(context->scratch1, context->mem_pointers, &context->opts->gen, context); |
13 } | 14 } |
14 | 15 |
15 void m68k_write_8(m68k_context *context) | 16 void m68k_write_8(m68k_context *context) |
16 { | 17 { |
26 | 27 |
27 void m68k_sync_cycle(m68k_context *context, uint32_t target_cycle) | 28 void m68k_sync_cycle(m68k_context *context, uint32_t target_cycle) |
28 { | 29 { |
29 context->sync_cycle = target_cycle; //why? | 30 context->sync_cycle = target_cycle; //why? |
30 context->sync_components(context, 0); | 31 context->sync_components(context, 0); |
32 } | |
33 | |
34 static void divu(m68k_context *context, uint32_t dividend_reg, uint32_t divisor) | |
35 { | |
36 uint32_t dividend = context->dregs[dividend_reg]; | |
37 uint32_t divisor_shift = divisor << 16; | |
38 uint16_t quotient = 0; | |
39 uint8_t force = 0; | |
40 uint16_t bit = 0; | |
41 uint32_t cycles = 2; | |
42 if (divisor_shift < dividend) { | |
43 context->nflag = 128; | |
44 context->zflag = 0; | |
45 context->vflag = 128; | |
46 context->cycles += 6 * context->opts->gen.clock_divider; | |
47 return; | |
48 } | |
49 for (int i = 0; i < 16; i++) | |
50 { | |
51 force = dividend >> 31; | |
52 quotient = quotient << 1 | bit; | |
53 dividend = dividend << 1; | |
54 | |
55 if (force || dividend >= divisor_shift) { | |
56 dividend -= divisor_shift; | |
57 cycles += force ? 4 : 6; | |
58 bit = 1; | |
59 } else { | |
60 bit = 0; | |
61 cycles += 8; | |
62 } | |
63 } | |
64 cycles += force ? 6 : bit ? 4 : 2; | |
65 context->cycles += cycles * context->opts->gen.clock_divider; | |
66 quotient = quotient << 1 | bit; | |
67 context->dregs[dividend_reg] = dividend | quotient; | |
68 context->vflag = 0; | |
69 context->nflag = quotient >> 8 & 128; | |
70 context->zflag = quotient == 0; | |
71 } | |
72 | |
73 static void divs(m68k_context *context, uint32_t dividend_reg, uint32_t divisor) | |
74 { | |
75 uint32_t dividend = context->dregs[dividend_reg]; | |
76 uint32_t divisor_shift = divisor << 16; | |
77 uint32_t orig_divisor = divisor_shift, orig_dividend = dividend; | |
78 if (divisor_shift & 0x80000000) { | |
79 divisor_shift = 0 - divisor_shift; | |
80 } | |
81 | |
82 uint32_t cycles = 8; | |
83 if (dividend & 0x80000000) { | |
84 //dvs10 | |
85 dividend = 0 - dividend; | |
86 cycles += 2; | |
87 } | |
88 if (divisor_shift <= dividend) { | |
89 context->vflag = 128; | |
90 context->nflag = 128; | |
91 context->zflag = 0; | |
92 cycles += 4; | |
93 context->cycles += cycles * context->opts->gen.clock_divider; | |
94 return; | |
95 } | |
96 uint16_t quotient = 0; | |
97 uint16_t bit = 0; | |
98 for (int i = 0; i < 15; i++) | |
99 { | |
100 quotient = quotient << 1 | bit; | |
101 dividend = dividend << 1; | |
102 | |
103 if (dividend >= divisor_shift) { | |
104 dividend -= divisor_shift; | |
105 cycles += 6; | |
106 bit = 1; | |
107 } else { | |
108 bit = 0; | |
109 cycles += 8; | |
110 } | |
111 } | |
112 quotient = quotient << 1 | bit; | |
113 dividend = dividend << 1; | |
114 if (dividend >= divisor_shift) { | |
115 dividend -= divisor_shift; | |
116 quotient = quotient << 1 | 1; | |
117 } else { | |
118 quotient = quotient << 1; | |
119 } | |
120 cycles += 4; | |
121 | |
122 context->vflag = 0; | |
123 if (orig_divisor & 0x80000000) { | |
124 cycles += 16; //was 10 | |
125 if (orig_dividend & 0x80000000) { | |
126 if (quotient & 0x8000) { | |
127 context->vflag = 128; | |
128 context->nflag = 128; | |
129 context->zflag = 0; | |
130 context->cycles += cycles * context->opts->gen.clock_divider; | |
131 return; | |
132 } else { | |
133 dividend = -dividend; | |
134 } | |
135 } else { | |
136 quotient = -quotient; | |
137 if (quotient && !(quotient & 0x8000)) { | |
138 context->vflag = 128; | |
139 } | |
140 } | |
141 } else if (orig_dividend & 0x80000000) { | |
142 cycles += 18; // was 12 | |
143 quotient = -quotient; | |
144 if (quotient && !(quotient & 0x8000)) { | |
145 context->vflag = 128; | |
146 } else { | |
147 dividend = -dividend; | |
148 } | |
149 } else { | |
150 cycles += 14; //was 10 | |
151 if (quotient & 0x8000) { | |
152 context->vflag= 128; | |
153 } | |
154 } | |
155 if (context->vflag) { | |
156 context->nflag = 128; | |
157 context->zflag = 0; | |
158 context->cycles += cycles * context->opts->gen.clock_divider; | |
159 return; | |
160 } | |
161 context->nflag = (quotient & 0x8000) ? 128 : 0; | |
162 context->zflag = quotient == 0; | |
163 //V was cleared above, C is cleared by the generated machine code | |
164 context->cycles += cycles * context->opts->gen.clock_divider; | |
165 context->dregs[dividend_reg] = dividend | quotient; | |
31 } | 166 } |
32 | 167 |
33 static sync_fun *sync_comp_tmp; | 168 static sync_fun *sync_comp_tmp; |
34 static int_ack_fun int_ack_tmp; | 169 static int_ack_fun int_ack_tmp; |
35 void init_m68k_opts(m68k_options *opts, memmap_chunk * memmap, uint32_t num_chunks, uint32_t clock_divider, sync_fun *sync_components, int_ack_fun int_ack) | 170 void init_m68k_opts(m68k_options *opts, memmap_chunk * memmap, uint32_t num_chunks, uint32_t clock_divider, sync_fun *sync_components, int_ack_fun int_ack) |