ack/mach/z80/libem/cii.s

152 lines
3.1 KiB
ArmAsm

.define .cii
.define .cuu
.sect .text
.sect .rom
.sect .data
.sect .bss
.sect .text
! cii: convert integer to integer
! parameters:
! stack: destination size
! source size
! source
! stack: result (out)
! This code is also used by cuu.
! The contents of the a-register determines
! if we're doing a cii (a=0) or a cuu (a=1),
! so be very careful with this register!
.cii:
pop ix ! return address
pop hl ! destination size
pop de ! source size
ld b,h ! bc := destination size
ld c,l
xor a ! watch it, this is dirty!
! Besides clearing the carry
! this instruction sets a-reg.
! to 0, to indicate this is
! a cii and not a cuu.
sbc hl,de ! hl := destination size
! - source size
jr z,1f ! equal, return
jp p,2f ! larger, expand
! smaller, shrink
! The most significant part of the source
! is removed. As the least sign. part is
! on top of the stack, we have to move an
! entire data block.
9:
add hl,sp ! note that hl < 0
! (also come here via cuu)
add hl,de
dec hl ! now hl points to most
! significant byte of what
! will be left over of source
ex de,hl
add hl,sp
ex de,hl
dec de ! now de points to highest
! byte of source
lddr ! move 'destination size'
! bytes upwards (i.e. away
! from top of stack)
inc de
ex de,hl
ld sp,hl ! adjust stackpointer
1:
jp (ix) ! return
2:
! larger, expand
! A number of bytes (containing the signbits
! of the source) is inserted before the most
! significant byte of the source.
! As this byte is somewhere in the middle of
! the stack, the entire source must first be
! moved downwards (in the direction of the
! top)
8:
ld b,d ! bc := source size
! (also come here via cuu)
ld c,e
ex de,hl ! de := difference (> 0)
ld hl,0
add hl,sp ! hl := sp
dec de ! if difference = 1, don't adjust stack pointer
jr nz, 4f
inc de
jr 5f
4:
inc de
push hl
or a
sbc hl,de
ex de,hl ! de := sp - difference
pop hl ! hl := sp
ex de,hl ! adjust sp
ld sp,hl
ex de,hl
ldir ! move source upwards,
! creating a 'hole'
! inside the stack
! now we will fill the hole with bytes
! containing either 0 or -1, depending
! on the signbit of the source.
or a
sbc hl,de
ex de,hl ! de := difference
dec hl ! now hl points to
! most significant byte
! of the source
5:
or a ! see if we're doing
! a 'cii' or a 'cuu'
jr nz,3f ! cuu, expand with zeroes
bit 7,(hl) ! test signbit
jr z,3f
dec b ! b := -1 (was 0 after ldir)
3:
inc hl
ld (hl),b ! either 0 or -1
dec de
ld a,d
or e
jr nz,3b
jp (ix) ! return
! cuu: convert unsigned to unsigned
! parameters:
! stack: destination size
! source size
! source
! stack: result (out)
! The only difference between a cuu and a cii is:
! if the destination is larger than the source,
! the former extends with zeroes and the latter
! extends with sign bits
! cuu uses the code of cii. In this case it puts
! a '1' in the accumulator to indicate this is
! a cuu.
.cuu:
pop ix
pop hl
pop de
ld b,h
ld c,l
xor a ! clear carry
sbc hl,de
jr z,1b ! equal, return
jp m,9b ! smaller, shrink
inc a ! a := 1
jr 8b ! larger, expand