Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

PDP-11: unsigned long multiplication is incorrect #324

Open
kwhr0 opened this issue Feb 28, 2025 · 0 comments
Open

PDP-11: unsigned long multiplication is incorrect #324

kwhr0 opened this issue Feb 28, 2025 · 0 comments

Comments

@kwhr0
Copy link

kwhr0 commented Feb 28, 2025

When you compile and run the source below, 0xc0000000 is displayed, but the correct value is 0x40000000.

#include <stdio.h>
int main(void) {
	unsigned long a = 0x8000L, b = 0x8000L;
	printf("0x%lx\n", a * b);
	return 0;
}

Since PDP-11 only has signed multiplication instruction, replacing mach/pdp/libem/mlu4.s with something equivalent to the code below will work correctly, but it is large and slow.

uint32_t mlu4(uint32_t x, uint32_t y) {
	int16_t a0 = x, a1 = x >> 16, b0 = y, b1 = y >> 16; 
	int16_t a0l = a0 & 0x7fff, a0m = a0 < 0;
	int16_t a1l = a1 & 0x7fff, a1m = a1 < 0;
	int16_t b0l = b0 & 0x7fff, b0m = b0 < 0;
	int16_t b1l = b1 & 0x7fff, b1m = b1 < 0;
	uint32_t r = (int32_t)a0l * b0l;
	if (a0m) r += (int32_t)b0l << 15;
	if (b0m) r += (int32_t)a0l << 15;
	if (a0m && b0m) r += 0x40000000U;
	r += (int32_t)a1l * b0l << 16;
	if (a1m && b0l & 1) r += 0x80000000U;
	if (b0m && a1l & 1) r += 0x80000000U;
	r += (int32_t)a0l * b1l << 16;
	if (a0m && b1l & 1) r += 0x80000000U;
	if (b1m && a0l & 1) r += 0x80000000U;
	return r;
}

Is there a better way?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant