diff 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
line wrap: on
line diff
--- a/m68k_util.c	Sat Feb 08 16:41:20 2025 -0800
+++ b/m68k_util.c	Sat Feb 08 20:04:18 2025 -0800
@@ -9,6 +9,7 @@
 void m68k_read_16(m68k_context *context)
 {
 	context->cycles += 4 * context->opts->gen.clock_divider;
+	uint32_t tmp = context->scratch1;
 	context->scratch1 = read_word(context->scratch1, context->mem_pointers, &context->opts->gen, context);
 }
 
@@ -30,6 +31,140 @@
 	context->sync_components(context, 0);
 }
 
+static void divu(m68k_context *context, uint32_t dividend_reg, uint32_t divisor)
+{
+	uint32_t dividend = context->dregs[dividend_reg];
+	uint32_t divisor_shift = divisor << 16;
+	uint16_t quotient = 0;
+	uint8_t force = 0;
+	uint16_t bit = 0;
+	uint32_t cycles = 2;
+	if (divisor_shift < dividend) {
+		context->nflag = 128;
+		context->zflag = 0;
+		context->vflag = 128;
+		context->cycles += 6 * context->opts->gen.clock_divider;
+		return;
+	}
+	for (int i = 0; i < 16; i++)
+	{
+		force = dividend >> 31;
+		quotient = quotient << 1 | bit;
+		dividend = dividend << 1;
+
+		if (force || dividend >= divisor_shift) {
+			dividend -= divisor_shift;
+			cycles += force ? 4 : 6;
+			bit = 1;
+		} else {
+			bit = 0;
+			cycles += 8;
+		}
+	}
+	cycles += force ? 6 : bit ? 4 : 2;
+	context->cycles += cycles * context->opts->gen.clock_divider;
+	quotient = quotient << 1 | bit;
+	context->dregs[dividend_reg] = dividend | quotient;
+	context->vflag = 0;
+	context->nflag = quotient >> 8 & 128;
+	context->zflag = quotient == 0;
+}
+
+static void divs(m68k_context *context, uint32_t dividend_reg, uint32_t divisor)
+{
+	uint32_t dividend = context->dregs[dividend_reg];
+	uint32_t divisor_shift = divisor << 16;
+	uint32_t orig_divisor = divisor_shift, orig_dividend = dividend;
+	if (divisor_shift & 0x80000000) {
+		divisor_shift = 0 - divisor_shift;
+	}
+
+	uint32_t cycles = 8;
+	if (dividend & 0x80000000) {
+		//dvs10
+		dividend = 0 - dividend;
+		cycles += 2;
+	}
+	if (divisor_shift <= dividend) {
+		context->vflag = 128;
+		context->nflag = 128;
+		context->zflag = 0;
+		cycles += 4;
+		context->cycles += cycles * context->opts->gen.clock_divider;
+		return;
+	}
+	uint16_t quotient = 0;
+	uint16_t bit = 0;
+	for (int i = 0; i < 15; i++)
+	{
+		quotient = quotient << 1 | bit;
+		dividend = dividend << 1;
+
+		if (dividend >= divisor_shift) {
+			dividend -= divisor_shift;
+			cycles += 6;
+			bit = 1;
+		} else {
+			bit = 0;
+			cycles += 8;
+		}
+	}
+	quotient = quotient << 1 | bit;
+	dividend = dividend << 1;
+	if (dividend >= divisor_shift) {
+		dividend -= divisor_shift;
+		quotient = quotient << 1 | 1;
+	} else {
+		quotient = quotient << 1;
+	}
+	cycles += 4;
+
+	context->vflag = 0;
+	if (orig_divisor & 0x80000000) {
+		cycles += 16; //was 10
+		if (orig_dividend & 0x80000000) {
+			if (quotient & 0x8000) {
+				context->vflag = 128;
+				context->nflag = 128;
+				context->zflag = 0;
+				context->cycles += cycles * context->opts->gen.clock_divider;
+				return;
+			} else {
+				dividend = -dividend;
+			}
+		} else {
+			quotient = -quotient;
+			if (quotient && !(quotient & 0x8000)) {
+				context->vflag = 128;
+			}
+		}
+	} else if (orig_dividend & 0x80000000) {
+		cycles += 18; // was 12
+		quotient = -quotient;
+		if (quotient && !(quotient & 0x8000)) {
+			context->vflag = 128;
+		} else {
+			dividend = -dividend;
+		}
+	} else {
+		cycles += 14; //was 10
+		if (quotient & 0x8000) {
+			context->vflag= 128;
+		}
+	}
+	if (context->vflag) {
+		context->nflag = 128;
+		context->zflag = 0;
+		context->cycles += cycles * context->opts->gen.clock_divider;
+		return;
+	}
+	context->nflag = (quotient & 0x8000) ? 128 : 0;
+	context->zflag = quotient == 0;
+	//V was cleared above, C is cleared by the generated machine code
+	context->cycles += cycles * context->opts->gen.clock_divider;
+	context->dregs[dividend_reg] = dividend | quotient;
+}
+
 static sync_fun *sync_comp_tmp;
 static int_ack_fun int_ack_tmp;
 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)