RosettaCodeData/Task/Hailstone-sequence/Z80-Assembly/hailstone-sequence.z80
2023-07-01 13:44:08 -04:00

147 lines
2.5 KiB
Z80 Assembly

;;;;;;;;;;;;;;;;;;; HEADER ;;;;;;;;;;;;;;;;;;;
read "\SrcCPC\winape_macros.asm"
read "\SrcCPC\MemoryMap.asm"
read "\SrcALL\winapeBuildCompat.asm"
;;;;;;;;;;;;;;;;;;; PROGRAM ;;;;;;;;;;;;;;;;;;;
org &8000
ld de,27
call doHailstone
;returns length of sequence, and writes each entry in the sequence
; to RAM
;print the sequence length (in hex)
ld a,h
call ShowHex
ld a,l
ld (memdump_smc),a
;just to prove I didn't need to know the sequence length at
; compile time, I'll store the calculated length as the operand
; of "doMemDump" which normally takes a constant embedded after
; it as the number of bytes to display.
; If that doesn't make sense, don't worry.
; This has nothing to do with calculating the hailstone sequence, just showing the results.
call ShowHex
call NewLine ;prints CRLF
call NewLine
call doMemDump
memdump_smc:
byte 0 ;operand of "doMemDump" (gets overwritten with the sequence length)
word HailstoneBuffer ;operand of "doMemDump"
ret
;;;;;;;;;;;;;;;;;;; LIBRARY ;;;;;;;;;;;;;;;;;;;
read "\SrcCPC\winape_stringop.asm"
read "\SrcCPC\winape_showhex.asm"
doHailstone:
;you need the proper input for the function "hailstone"
;returns addr. of last element in IX.
call hailstone
ld de,HailstoneBuffer
or a ;clear carry
push ix
pop hl ;returns element count in HL.
sbc hl,de ;subtract the two to get the length of the array.
SRL H
RR L ;divide array size by 2, since each entry is 2 bytes.
INC L
ret nz ;if no carry, don't increment H.
INC H
ret
hailstone:
;input - de = n
ld ix,HailstoneBuffer
ld a,d
or e
ret z ;zero is not allowed.
loop_hailstone:
ld (IX+0),e
ld (IX+1),d
ld a,e
cp 1
jr nz,continue_hailstone
ld a,d
or a
ret z ;if de = 1, stop.
continue_hailstone:
bit 0,e
jr z,DE_IS_EVEN
;de is odd
push de
pop hl ;ld hl,de
SLA E
RL D
add hl,de ;hl = de*3
ld de,1
add hl,de
push hl
pop de ;ld de,hl
inc ix
inc ix
jr loop_hailstone
DE_IS_EVEN:
SRL D ;A/2
RR E
inc ix
inc ix
jr loop_hailstone
doMemDump:
;show the hailstone sequence to the screen. This is just needed to display the data, if you don't care about that
;you can stop reading here.
pop hl ;get PC
ld b,(hl) ;get byte count
inc hl
ld e,(hl) ;get low byte of start addr.
inc hl
ld d,(hl) ;get high byte of start addr.
inc hl
push hl ;now when we return we'll skip the data block.
ex de,hl
call NewLine
;we'll dump 8 words per line.
ld c,8
loop_doMemDump:
inc hl
ld a,(hl)
call ShowHex
dec hl
ld a,(hl)
call ShowHex
ld a,' '
call PrintChar
inc hl
inc hl
dec c
ld a,c
and %00001111
jr nz,continueMemdump
ld c,8
continueMemdump:
djnz loop_doMemDump
ret
HailstoneBuffer:
ds 512,0