147 lines
2.5 KiB
Z80 Assembly
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
|