prevent a possible overflow when adding in a 16-bit processor register

81 views

Андрей Никитин

Oct 12, 2021, 3:40:22 PM10/12/21
to
When adding an integer n to pointer2 (16-bit unsigned number) and comparing it to pointer1, the following z80 assembly code is used:

ld l, (ix+6)
ld h, (ix+7)
inc hl
ld a, l
and 0feh
ld l, a
ld a, h
ld (ix+6), l
ld (ix+7), h
ld de, (pointer2)
ex de, hl
ld hl, (pointer1)
call wrelop
jr nc, label1

Most likely this is done to prevent a possible overflow when adding in a 16-bit processor register.
Maybe someone has come across a similar one and knows how these actions can be programmed in C.

Andrey

fridtjof.ma...@gmail.com

Oct 12, 2021, 6:24:27 PM10/12/21
to
Andrey

Sure -- look at my am9511 emulator

https://github.com/ratboy666/am9511

and, in specific, file ova.c (overflow arithmetic). It shows how to do overflow checking on add, subtract, and multiply.

Have fun!
Fred Weigel

fridtjof.ma...@gmail.com

Oct 12, 2021, 8:57:16 PM10/12/21
to
On Tuesday, October 12, 2021 at 3:40:22 PM UTC-4, nikiti...@gmail.com wrote:
Andrey

Anyway, there is no overflow here at all -- what is the type of pointer2? Note that if p is a pointer, p+n
is numeric p + (n * sizeof(*p)): in other words, this calculation:

char *p2 = (char *)p;
p = p + (n * sizeof(*p));
p2 = (void *)p;

Now, it looks like ix+6 and ix+7 are the "n", appears to do n + 1, and then makes it an even number (and 0feh)
Can I see the C source for this production?

Note that ova.c that I pointed you at earlier does overflow detection for C arithmetic. And it works on both Hi-Tech C
on the Z80, and GCC on modern platforms. It is reasonably efficient on both of those. Note that carry is returned by the

FredW

Андрей Никитин

Oct 13, 2021, 7:10:23 AM10/13/21
to
среда, 13 октября 2021 г. в 03:57:16 UTC+3, fridtjof.ma...@gmail.com:
This is the memory allocation function:
The recreated C code is as follows:
char * alloc_mem (int size) {
char * l1;
register char * st;

if (word_707a <(word_7082 + (size = (size + 1) & 0xFE))) {
if ((word_7082 = sbrk (512)) == (char *) - 1)
pr_error ("Out of memory in% s", name_fun);
word_707a = sbrk (0);
}
st = word_7082;
word_7082 + = size;
l1 = st;
while (size--! = 0) * (l1 ++) = 0; // Clearing the allocated memory area
return st;
}
However, the first if statement in this function generates code that is different from the one in the executable image.
I cannot understand why these actions (size = (size + 1) & 0xFE) and how important they are.

Andrey

fridtjof.ma...@gmail.com

Oct 13, 2021, 10:56:00 AM10/13/21
to
Andrey

Ah... the first line is actually

if (word_707a < (word_7082 + (size = (size + 1) & 0xFFFE)))

Let us look at

size = (size + 1) &0xfffe

what this is doing is making size even: say, size is 13, 13 + 1 is 14 and 14 & 0xfffe is still 14. Say size is 14, 14 + 1 is 15, 15 & 0xfffe
is 14. So, size ends up being either size or the next higher even number. We then make sure the allocation fits into the already
allocated space. If it does we end up at st = word_7082. If not, we use sbrk() to add more memory,

How important? The code just ensures integer (16 bit) addressing -- so the least significant bit should always be zero on
allocated addresses.. may be important elsewhere (even+even = even -- but note that if address is odd, odd+even is odd --
if size is always even, the least significant bit will never change).

FredW

fridtjof.ma...@gmail.com

Oct 13, 2021, 10:59:55 AM10/13/21
to
On Wednesday, October 13, 2021 at 7:10:23 AM UTC-4, nikiti...@gmail.com wrote:
Andrey

Was the peephole optimizer used? It looks like a production was removed:

mov a,h
and 0ffh
mov h,a

is "missing" -- note that *if* the code were actually &0xFE, it should have been:

mov a,l
and 0feh
mov l,a
mov h,0

(or something along those lines)

or, the compiler code generator is smart enough to deal with converting word into byte as needed.

FredW