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)