ZXSRC

Z80 ZX-Spectrum 

Sources Rough Collection

in progress...

Небольшой Блокнотик по программированию

 Z80 на компьютере ZX-SPECTRUM, 

и не только...

Математические операции

ADDITION

;a+hl unsigned slower

;4 bytes and 22 clock cycles

ld b,0 ;ld d,0 ;

ld c,a ;e,a ;

add hl,bc ;add hl,de ;





;a+hl faster unsigned from plutiedev

;5 bytes and 20 clock cycles

;but no other 16-bit register messed up

add a, l    ; A = A+L

ld l, a    ; L = A+L

adc a, h    ; A = A+L+H+carry

sub l       ; A = H+carry

ld h, a    ; H = H+carry





;a+hl fastest addAtoHL:

;5 bytes, 19/20 clock cycles

add a,l

ld l,a

jr nc, $+3

inc h



a+hl ADD A, L

LD L, A

RET NC

INC H

RET 






;a+hl signed from plutiedev

; If A is negative, we need to substract $100 from HL

; (since A's "upper byte" is $FF00)

or a

jp p, Positive

dec h

Positive: ; Then do addition as usual; (to handle the "lower byte")

add a, l

ld l, a

adc a, h

sub l

ld h, a







;(hl)=(hl)+a

add a,(hl)

ld (hl),a







;signed add

ld    e, a    ; DE = A

add   a, a

sbc   a

ld    d, a

add   hl, de  ; HL = HL+DE




ADD 16bits ;andreadrian.de

        LD HL,#1234        ; LOAD DECIMAL VALUE 12345 INTO REGISTER HL

        LD DE,#5           ; LOAD DECIMAL VALUE 7 INTO REGISTER DE

; ADD ROUTINE 16+16BIT=16BIT

; HL = HL + DE

ADD16 ADD HL,DE   ; 16-BIT ADD OF HL AND DE

;RESULT IS IN HL

        RET             ;RESULT IS IN HL





ADD 32bits ;andreadrian.de

        LD      HL,#1213      ; LOAD HEXADECIMAL 1213 TO HL (LOWER 16-BIT)

        LD      DE,#F000      ; LOAD HEXADECIMAL F000 TO DE (LOWER 16-BIT)

        EXX

        LD      HL,#1011      ; LOAD HEXADECIMAL 1011 TO H'L' (UPPER 16-BIT)

        LD      DE,#0          ; LOAD VALUE 0 TO D'E' (UPPER 16-BIT)

        EXX

; H'L'HL = H'L'HL + D'E'DE

ADD32   ADD     HL,DE   ; 16-BIT ADD OF HL AND DE

        EXX

        ADC     HL,DE   ; 16-BIT ADD OF HL AND DE WITH CARRY

        EXX

RET





Kot Ltd,  Кировск, 1996

     Эта процедура приращения регистровой пары HL на величину, заданную в 

регистре А, которая находится в пределах #00 - #FF.

        LD A, приращение           Это быстрее и короче,  

        ADD A,L                    чем:

        LD  L,A                          PUSH  BC

        ADC A,H                          LD  BC, #            

        SUB  L                           ADD HL, BC

        LD H,A                           POP BC 


SUBSTRACTION

;a-hl unsigned from plutiedev

; If A=0 do nothing Otherwise flip A's sign. 

Since the upper byte becomes -1, also

; substract 1 from H.

    neg

    jp    z, Skip

    dec   h

; Now add the low byte as usual

; Two's complement takes care of

; ensuring the result is correct

    add   a, l

    ld    l, a

    adc   a, h

    sub   l

    ld    h, a

Skip:





unsigned hl-de

ld    e, a    ; DE = A

    ld    d, 0

    or    a       ; Clear carry

    sbc   hl, de  ; HL = HL-DE

signed hl-de

ld    e, a    ; DE = A

    add   a, a

    sbc   a

    ld    d, a

    or    a       ; Clear carry

    sbc   hl, de  ; HL = HL-DE





;   Compute (HL)=(DE)-(HL)

SUBHL LD A,E ;compute difference.

SUB L

LD L,A ;store low byte.

LD A,D

SBC A,H

LD H,A ;and then high byte.

RET





;via calc84maniac "Optimized routine for HL=A-HL 

(the negate HL optimization can be derived 

from this by setting A=0 first)

  sub l

  ld l,a

  sbc a,a

  sub h

  ld h,a




;written by calc84maniac

;comment from calc84maniac:

;   To clarify why I did a cpl/scf/adc instead

 of a cpl/inc/add or neg/add,

;   is that it handles the case of A=0 properly. 

Typically, SUB N and

;   ADD A,-N give opposite carry outputs, 

but SUB 0 and ADD A,-0 both reset the

;   carry flag. On the other hand, SCF \ ADC A,255 

will set the carry flag like

;   we want it to.

;NOTE: This is an in-line routine-- there is no RET

  cpl

  scf

  adc a,c

  ld c,a

  jr c,$+3

  dec b

; Here is a callable routine:

  cpl

  scf

  adc a,c

  ld c,a

  ret c

  dec b

  ret


MULTIPLICATION

BC*2,4,8....

Умножить  регистровую пару на 2 (4,8...) можно так:

         AND   A

         RL    C

         RL    B  .


DE*2,4,8....

    sla e

    rl d



А если вам надо перемножить регистр HL,то

это лучше сделать командой сложения ADD :


         ADD   HL,HL      умножить на два

         ADD   HL,HL      на четыре

         ADD   HL,HL      на восемь

         ...........      и т.д.


Например:

HLx32 add hl,hl

HLx16 add hl,hl

HLx8 add hl,hl

HLx4 add hl,hl

HLx2 add hl,hl

ret













;B*2,4,8...

ld b,3        ; Multiply 3 with 4

sla b         ; *4

sla b         ; result: B = 12




;A*2,4,8...

   ld a,15       ; Multiply 15 with 8

    add a,a       ; *8

    add a,a

    add a,a       ; result: A =120




;A*20

    ld a,5       ; Multiply 5 with 20 (= A * 16 + A * 4)

    add a,a       ; *16

    add a,a

    ld b,a       ; Store value of A * 4 in B

    add a,a

    add a,a

    add a,b      ; Add A * 4 to A * 16, result: A = 100




A*15

    ld a,3        ; Multiply 3 with 15 (= A * 16 - A * 1)

    ld b,a        ; Store value of A * 1 in B

    add a,a       ; *16

    add a,a

    add a,a

    add a,a

    sub b        ; result: A = 45






HL = HL*A 

;5.MHLA  - умножение

;INPUT : HL <-- что A <-- на что

;OUTPUT: HL = HL*A;портятся  DE,HL,A

;FASTED bY CREATOR

MHLA    AND     A

        JR      Z,M1H

        EX      DE,HL

        LD      HL,0

M2H     SRL     A

        JP      NC,M3H

        ADD     HL,DE

M3H     SLA     E

        RL      D

        AND     A

        JP      NZ,M2H

        RET 

M1H     LD      H,A

        LD      L,A

        RET 





;a*12=hl a*3=hl a*12=hl (fast)

; Although this specific case 

could be even better as follows:

ld l,a

add a,a ; a*2

add a,l ; a*3

ld h,0

ld l,a ; hl=a*3

add hl,hl ; hl=a*6

add hl,hl ; hl=a*12

; 8 bytes, 45 clocks





;HL*10

Mult10HL

add hl,hl

push de

push hl

pop de

add hl,hl

add hl,hl

add hl,de

pop de





;HL=DE*A

MULT    LD      HL,0

        EX      DE,HL

DUP 8

        RRA 

        JR NC,$+5

        EX DE,HL

        ADD HL,DE

        EX DE,HL

        ADD HL,HL

EDUP 

        EX DE,HL

        RET 






; Multiply 8-bit values H*E ~Grauw

; In:  Multiply H with E

Out: HL = result

Mult8 ld d,0

ld l,d

ld b,8

Mult8_Loop add hl,hl

jr nc,Mult8_NoAdd

add hl,de

Mult8_NoAdd djnz Mult8_Loop

ret




; Multiply 8-bit value with a 16-bit value ~Grauw

; In: Multiply A*DE

Out: HL = result

Mult12:

    ld l,0

    ld b,8

Mult12_Loop:

    add hl,hl

    add a,a

    jr nc,Mult12_NoAdd

    add hl,de

Mult12_NoAdd:

    djnz Mult12_Loop

    ret




; Multiply 16-bit values (with 16-bit result) ~Grauw

; In: Multiply BC*DE

Out: HL = result

Mult16:

    ld a,b

    ld b,16

Mult16_Loop:

    add hl,hl

    sla c

    rla

    jr nc,Mult16_NoAdd

    add hl,de

Mult16_NoAdd:

    djnz Mult16_Loop

    ret




; Multiply 16-bit values (with 32-bit result)

; ~Grauw

; In: BC*DE

; Out: BCHL = result

Mult32:

    ld a,c

    ld c,b

    ld hl,0

    ld b,16

Mult32_Loop:

    add hl,hl

    rla

    rl c

    jr nc,Mult32_NoAdd

    add hl,de

    adc a,0

    jp nc,Mult32_NoAdd

    inc c

Mult32_NoAdd:

    djnz Mult32_Loop

    ld b,c

    ld c,a

    ret





; Multiply 8-bit value with a 16-bit 

value (right rotating) ~Grauw

; In: Multiply A*DE.  Put lowest value 

in A for most efficient calculation

; Out: HL = result

Mult12R:

    ld hl,0

Mult12R_Loop:

    srl a

    jr nc,Mult12R_NoAdd

    add hl,de

Mult12R_NoAdd:

    sla e

    rl d

    or a

    jp nz,Mult12R_Loop

    ret




; Multiply 8-bit value with a 

;16-bit value (unrolled) ~Grauw

; In: Multiply A*DE Out: HL = result

Mult12U:

    ld l,0

    add a,a

    jr nc,Mult12U_NoAdd0

    add hl,de

Mult12U_NoAdd0:

    add hl,hl

    add a,a

    jr nc,Mult12U_NoAdd1

    add hl,de

Mult12U_NoAdd1:

    add hl,hl

    add a,a

    jr nc,Mult12U_NoAdd2

    add hl,de

Mult12U_NoAdd2:

    add hl,hl

    add a,a

    jr nc,Mult12U_NoAdd3

    add hl,de

Mult12U_NoAdd3:

    add hl,hl

    add a,a

    jr nc,Mult12U_NoAdd4

    add hl,de

Mult12U_NoAdd4:

    add hl,hl

    add a,a

    jr nc,Mult12U_NoAdd5

    add hl,de

Mult12U_NoAdd5:

    add hl,hl

    add a,a

    jr nc,Mult12U_NoAdd6

    add hl,de

Mult12U_NoAdd6:

    add hl,hl

    add a,a

    ret nc

    add hl,de

    ret





;HL*6 Умножение HL на шесть :

ADD   HL,HL

LD    B,H

LD    C,L

ADD   HL,HL

ADD   HL,BC




;HL*40 умножение HL на сорок :

ADD   HL,HL

ADD   HL,HL

ADD   HL,HL

LD    B,H

LD    C,L

ADD   HL,HL

ADD   HL,HL

ADD   HL,BC




;by Axor

;HL=HL*128, 35 тактов

LD A,L 

RRC H

RRA

LD H,A

LD L,0

RR L




;MUL:   DE=DE*BC

MUL EX DE,HL

LD DE,0

LD A,16

MUL1 RR B

RR C

JR NC,MUL2

EX DE,HL

ADD HL,DE

EX DE,HL

MUL2 ADD HL,HL

DEC A

JR NZ,MUL1

RET 




Classic 8-bit * 8-bit Unsigned

;Input: 

H = Multiplier, 

E = Multiplicand, 

L = 0, D = 0

;Output: HL = Product

sla h ; optimised 1st iteration

jr nc,$+3

ld l,e

add hl,hl ; unroll 7 times

jr nc,$+3 ; ...

add hl,de ; ...




Classic 16-bit * 8-bit Unsigned

;Input: 

A = Multiplier, 

DE = Multiplicand, 

HL = 0, C = 0

;Output: A:HL = Product

add a,a ; optimised 1st iteration

jr nc,$+4

ld h,d

ld l,e

add hl,hl ; unroll 7 times

rla ; ...

jr nc,$+4 ; ...

add hl,de ; ...

adc a,c ; ...




Classic 16-bit * 16-bit Unsigned

;Input: 

DE = Multiplier, 

BC = Multiplicand, 

HL = 0

;Output: DE:HL = Product

sla e ; optimised 1st iteration

rl d

jr nc,$+4

ld h,b

ld l,c

add hl,hl ; unroll 15 times

rl e ; ...

rl d ; ...

jr nc,$+6 ; ...

add hl,bc ; ...

jr nc,$+3 ; ...

inc de ; ...




;MULTIPLY D*E=DE; 

;0<=result<65535

LD DE,#FEFF

CALL MULT

RET

MULT XOR A

LD B,8

MU1 RRA 

RR E

JR NC,MU0

ADD A,D

MU0 DJNZ MU1

RRA

RR E

LD D,A

RET




    Предлагаю вариант процедуры, 

который имеет большую длину,  

но работает быстрее  при  умножении

больших чисел (B>15) и не  имеет 

синдрома нулевой ошибки. Числа в  

комментариях  означают: 

числитель - длина  (байт),

знаменатель - время (тактов).

LD      L,C;     1/4

LD      D,B;     1/4

LD      H,0;     2/7

LD      E,0;     2/7

LD      B,8;     2/7

; ---------

; 8/29

;-----------------------------

LOOP LD      A,1;     2/7

AND     L;       1/4

JR      Z,PASS;  2/7

ADD     HL,DE;   1/11

PASS RR      H;       2/8

RR      L;       2/8

DJNZ    LOOP; 2/13+8

; ----------

; 12/472

; или (58*8+8)

;------------------------------

RET     ;        1/10

;          ИТОГО:        21/511

    При значении регистра B от 1 до 15 

процедура умножения способом многократного

сложения  (ZX96/4-5, стр.69) выполняется быстрее.




; Процедура знакового умножения D*E=HL

; На входе: DE=множители, BIT 7,D(E) знаковый

; На выходе: HL=результат, BIT 7,H знаковый

ORG #C000

MULTI LD A,D

XOR E

AND #80

EX AF,AF'

RES 7,D

RES 7,E

LD L,D

LD B,8

XOR A

RR L

L1 JR NC,$+3

ADD A,E

RRA

RRL

DJNZ L1

LD H,A

EX AF,AF'

OR H

LD H,A

RET




;from Neos

;chl=chl*b;length is 21 bytes

;maximal time is about 561 tact

_mul24_8 push ix

ex de,hl

xor a

ld l,a

ld h,a

ld xh,8

mul248_ add hl,hl

rla

rl b

jr nc,$+4

add hl,de

adc a,c

dec xh

jr nz,mul248_

ld c,a

pop ix

ret



;from Neos

; de*a=hl

FMULT   ld hl,0

ld b,8

add hl,hl

rlca

jr nc,$+3

add hl,de

djnz FMULT+5

ret




; байт*слово=слово

; Вход  - А-число 1, DE-число 2.

; Выход - HL-результат.


LD HL,0

DUP 8

    ADD HL,HL

  ADD A,A

JR NC,$+3

ADD HL,DE

EDUP


; слово*слово=слово

; Вход  - BC-число 1,DE-число 2.

; Выход - HL-результат.

        

        LD HL,0

LD A,B

DUP 8

   ADD HL,HL

ADD A,A

JR NC,$+3

ADD HL,DE

EDUP

LD A,C

DUP 8

ADD HL,HL

ADD A,A

JR NC,$+3

ADD HL,DE

EDUP


; слово*слово=двойное слово

; Вход  - 

BC-число 1,DE-число 2

; Выход - 

HL-младшая часть слова,

HL'-старшая часть слова.

        LD HL,0

EXX

LD HL,0

LD DE,0

EXX

LD A,B

DUP 8

ADD HL,HL

EXX

ADC HL,HL

EXX

ADD A,A

JR NC,$+6

ADD HL,DE

EXX

ADC HL,DE

EDUP

LD A,C

DUP 8

ADD HL,HL

EXX

ADC HL,HL

EXX

ADD A,A

JR NC,$+6

ADD HL,DE

EXX

ADC HL,DE

EXX

EDUP


; двойное слово*двойное слово=двойное слово

; Вход  - DE' DE-число 1, BC' BC-число 2

; Выход - HL' HL-результат

        LD HL,0

        EXX

        LD HL,0

        EXX

DUP 16

  ADD HL,HL

EXX

ADC HL,HL

EX DE,HL

ADD HL,HL

EX DE,HL

EXX

JR NC,$+6

ADD HL,BC

EXX

ADC HL,BC

EXX

EDUP

DUP 16

ADD HL,HL

EXX

ADC HL,HL

EXX

EX DE,HL

ADD HL,HL

EX DE,HL

JR NC,$+6

ADD HL,BC

EXX

ADC HL,BC

EDUP






;andreadrian.de

        LD      DE,#01213

        LD      BC,#3

        EXX

        LD      DE,#1011

        LD      BC,#0

        EXX

; MULTIPLY ROUTINE 32*32BIT=32BIT

; H'L'HL = B'C'BC * D'E'DE

; NEEDS REGISTER A, CHANGES FLAGS

MUL32

        AND     A        ; RESET CARRY FLAG

        SBC     HL,HL    ; LOWER RESULT = 0

        EXX

        SBC     HL,HL    ; HIGHER RESULT = 0

        LD      A,B      ; MPR IS AC'BC

        LD      B,32     ; INITIALIZE LOOP COUNTER

MUL32LOOP

        SRA     A        ; RIGHT SHIFT MPR

        RR      C

        EXX

        RR      B

        RR      C       ; LOWEST BIT INTO CARRY

        JR      NC,MUL32NOADD

        ADD     HL,DE   ; RESULT += MPD

        EXX

        ADC     HL,DE

        EXX

MUL32NOADD

        SLA     E      ; LEFT SHIFT MPD

        RL      D

        EXX

        RL      E

        RL      D

        DJNZ    MUL32LOOP

        EXX

; RESULT IN H'L'HL

        RET








ПРОЦЕДУРА УМНОЖЕНИЯ HL=B*C.

    (ZX РЕВЮ 96/4-5, стр.69).


    Предлагаю вариант процедуры,

который имеет большую длину,  но

работает быстрее  при  умножении

больших чисел (B>15) и не  имеет

синдрома нулевой ошибки.

    Числа в  комментариях  озна-

чают: числитель - длина  (байт),

знаменатель - время (тактов).


         LD      L,C;     1/4

         LD      D,B;     1/4

         LD      H,0;     2/7

         LD      E,0;     2/7

         LD      B,8;     2/7

;                   ---------

;                         8/29

;-----------------------------


LOOP     LD      A,1;     2/7

         AND     L;       1/4

         JR      Z,PASS;  2/7


         ADD     HL,DE;   1/11

PASS     RR      H;       2/8

         RR      L;       2/8

         DJNZ    LOOP; 2/13+8

;                   ----------

;                        12/472

;                  или (58*8+8)

;------------------------------

         RET     ;        1/10

; ==============================

;          ИТОГО:        21/511


    При значении регистра B от 1

до 15 процедура умножения спосо-

бом многократного  сложения  (ZX

96/4-5, стр.69) выполняется быс-

трее.

    Алгоритм умножения  способом

сложений  со  сдвигами  подробно

описан в книге Р.Токхейм  "Осно-

вы цифровой  электроники",  МИР,

1988г., стр. 238-240.

    Практическое применение про-

цедры  умножения  могут   найти,

например, при расчете адреса на-

чала строки двумерного массива.








   (С) Жильцов Алексей,

         Углич, 1995


   Хочу  предложить  несколько  своих  программ в раздел "Этюды". Это короткие

процедуры вычисления произведения HL=B*C.


Mul_1   LD      L,B

        LD      B,8

        XOR     A

        RR      L

L1      JR      NC,L2

        ADD     A,C

L2      RRA

        RR      L

        DJNZ    L1

        LD      H,A

        RET


Длина 16 байт, максимальная длительность выполнения Тм=328 м.т.


Mul_2   LD      L,B

        LD      B,9

        XOR     A

L1      RR      L

        DEC     B

        RET     Z

        JR      NC,L2

        ADD     A,C

L2      RRA

        LD      H,A

        JR      L1


Длина 15 байт, Тм=430 м.т. Короче предыдущей процедуры на 1 байт, зато медлен-

нее на 25%.


Mul_3   LD      L,0

        LD      H,B

        LD      B,L

        LD      A,8

L1      ADD     HL,HL

        JR      NC,L2

        ADD     HL,BC

L2      DEC     A

        JR      NZ,L1

        RET


Длина  14  байт, Тм=387 м.т. Реализован другой алгоритм по сравнению с Mul_1 и

Mul_2.

   И наконец, самая короткая процедура, занимающая всего 11 байт:


Mul_4   XOR     A

        SBC     HL,HL

        LD      D,A

        OR      B

        RET     Z

        LD      E,C

L1      ADD     HL,DE

        DJNZ    L1

        RET


Длина 11 байт, Тм=6161 м.т.


   Очевидно,  что последнюю процедуру не стоит использовать для активных мате-

матических  вычислений  вследствие  ее  низкого быстродействия. В некоторых же

случаях  (при  гарантии, что  B <= 8 - 10) скорость процедуры сравнима с тремя

другими.  При пониженных требованиях к быстродействию, эта процедура даже пред-

почтительней других по причине своей крайней примитивной простоты.












(С) Васильев Антон

(EARTH SOFTWARE)

HL= B*C

        LD      E,C

        LD      HL,0

        LD      D,0

L1      ADD     HL,DE

        DJNZ    L1

        RET



DIVISION

;деление А на 10 , C - результат      by koshi?

Div10   LD BC,#0AFF

Div     INC C

        SUB B

        RET C

        JP Div




BC/2,4,8....

Деление регистровoй пары на 2, 4, 8 и т.д.

         AND   A

         RR    B

         RR    C


DE/2,4,8

SRL D

RR E



;div A/8,4,2...  ????????????

ld a,153        ; Divide 153 by 8

and a,%11111000 ; Clear bits 0-2 (equals 256 - 8)

rrca            ; /8

rrca

rrca            ; result: a = 19




;hl/32 sam style ;ограничено max: #1fe0/#20

HLdiv32

ADD HL,HL

ADD HL,HL

ADD HL,HL

LD A,H

RET





;HL/A by Andrew Strikes Code

;Вход: HL - делимое, A - делитель

;Выход: HL - частное, A - остаток

DIV_21 NEG

LD C,A

LD B,#11

XOR A

DIV210 ADC A,A

ADD A,C

JR C,DIV211

SUB C

OR A

DIV211 ADC HL,HL

DJNZ DIV210

RET






BC/10 (in BC=-7fff)

bc_div10 ld a, c

sra b

rra

sra b

rra

sra b

rra

sra b

rra

ld c, a

ret








;by b2m

DIV32 ld a,10h ; DE = HLDE/BC, HL = HLDE%BC

DIV321 ex de,hl

add hl,hl

ex de,hl

adс hl,hl

jr c DIV322

push hl

sbс hl,bc

jr nc, DIV323

pop hl

jr DIV325

DIV322 ccf

sbс hl,bc

jr DIV324

DIV323 inc sp

inc sp

DIV324 inc de

DIV325 dec a

jr nz, DIV321

ret




;L=C/B, A=REST

DIVIS   XOR     A

DIVIS2  LD      L,1

D1      RL      C

        RLA 

        CP      B

        JR      C,ZER

        SUB     B

        SLI     L

        JR      NC,D1

        RET 

ZER     SLA     L

        JR      NC,D1

        RET 







;DIV:   BC=DE=DE/HL      

;from Perfect Commander

DIV LD BC,0

LD A,1

DIV1 BIT 7,H

JR NZ,DIV2

ADD HL,HL

INC A

JR DIV1

DIV2 EX DE,HL

DIV4 OR A

SBC HL,DE

CCF 

JR C,DIV3

ADD HL,DE

OR A

DIV RL C

RL B

RR D

RR E

DEC A

JR NZ,DIV4

LD E,C

LD D,B

RET


;DE/BC=DE,HL

;на входе: de-делимое; bc-делитель

;на выходе: de-частное hl-остаток

;by Virtual/bw

divide ld a,b    ;меняем

       cpl       ;

       ld b,a    ;знак

       ld a,c    ;

       cpl       ;у

       ld c,a    ;

       inc bc    ;делителя   t=30

       ld hl,0   ;обнулили новое делимое

       ld a,d    ;сначала двигаем

       rla       ;старший байт делимого ;t=18

       rl l      ;┐

       add hl,bc ;│

       jr c,$+4  ;│8 раз

       sbc hl,bc ;│

       rla       ;┘ t=8*45=360

       ld d,a    ;ст. байт результата

       ld a,e    ;теперь двигаем

       rla       ;младший байт  t=12

       adc hl,hl ;┐

       add hl,bc ;│

       jr c,$+4  ;│8 раз

       sbc hl,bc ;│

       rla       ;┘ t=8*52=416

       ld e,a    ;мл. байт результата ;hl-остаток от деления  ;t=4

;итого: 30+18+360+12+416+4=840 тактов

;если остаток не нужен, 

то конец процедуры должен выглядеть так:

       adc hl,hl ;┐

       add hl,bc ;│

       jr c,$+4  ;│7 раз

       sbc hl,bc ;│

       rla       ;┘ t=7*52=364

       adc hl,hl ;

       add hl,bc ;

       rla       ;

       ld e,a    ;  t=34

;итого: 30+18+360+12+364+34=818 тактов

;p.s.  если  будете  делить на ноль, то,

как  и следовало ожидать, частное будет

;равно  нулю, а остаток - делимому, т.е. 

в этом плане у процедуры глюков нет




; Divide 8-bit values ~Grauw

; In: Divide E by divider C  

Out: A = result, B = rest

Div8:

    xor a

    ld b,8

Div8_Loop:

    rl e

    rla

    sub c

    jr nc,Div8_NoAdd

    add a,c

Div8_NoAdd:

    djnz Div8_Loop

    ld b,a

    ld a,e

    rla

    cpl

    ret




; Divide 16-bit values (with 16-bit result)

;~Grauw

; In: Divide BC by divider DE  

;Out: BC = result, HL = rest

Div16:

    ld hl,0

    ld a,b

    ld b,8

Div16_Loop1:

    rla

    adc hl,hl

    sbc hl,de

    jr nc,Div16_NoAdd1

    add hl,de

Div16_NoAdd1:

    djnz Div16_Loop1

    rla

    cpl

    ld b,a

    ld a,c

    ld c,b

    ld b,8

Div16_Loop2:

    rla

    adc hl,hl

    sbc hl,de

    jr nc,Div16_NoAdd2

    add hl,de

Div16_NoAdd2:

    djnz Div16_Loop2

    rla

    cpl

    ld b,c

    ld c,a

    ret

;Thanks to Flyguille for the Div16 routine, 

taken from his MNBIOS source code.




;Classic 8-bit / 8-bit Unsigned

;Input: D = Dividend, E = Divisor, A = 0

;Output: D = Quotient, A = Remainder

sla d ; unroll 8 times

rla ; ...

cp e ; ...

jr c,$+4 ; ...

sub e ; ...

inc d ; ...




;Input: D = Dividend, E = Divisor, A = 0, Carry = 0

;Output: A = Quotient, E = Remainder

rl d ; unroll 8 times

rla ; ...

sub e ; ...

jr nc,$+3 ; ...

add a,e ; ...

ld e,a ; save remainder

ld a,d ; complement the result

cpl




Classic 16-bit / 8-bit Unsigned

;Input: HL = Dividend, C = Divisor, A = 0

;Output: HL = Quotient, A = Remainder (see note)

add hl,hl ; unroll 16 times

rla ; ...

cp c ; ...

jr c,$+4 ; ...

sub c ; ...

inc l ; ...




Classic 16-bit / 16-bit Unsigned

;Input: A:C = Dividend, DE = Divisor, HL = 0

;Output: A:C = Quotient, HL = Remainder

slia c ; unroll 16 times

rla ; ...

adc hl,hl ; ...

sbc hl,de ; ...

jr nc,$+4 ; ...

add hl,de ; ...

dec c ; ...




Classic 24-bit / 8-bit Unsigned

;Input: E:HL = Dividend, D = Divisor, A = 0

;Output: E:HL = Quotient, A = Remainder

add hl,hl ; unroll 24 times

rl e ; ...

rla ; ...

cp d ; ...

jr c,$+4 ; ...

sub d ; ...

inc l ; ...




Classic 24-bit / 16-bit Unsigned

;Input: A:BC = Dividend, DE = Divisor, HL = 0

;Output: A:BC = Quotient, HL = Remainder

slia c ; unroll 24 times

rl b ; ...

rla ; ...

adc hl,hl ; ...

sbc hl,de ; ...

jr nc,$+4 ; ...

add hl,de ; ...

dec c ; ...




Classic 32-bit / 8-bit Unsigned

;Input: DE:HL = Dividend, C = Divisor, A = 0

;Output: DE:HL = Quotient, A = Remainder

add hl,hl ; unroll 32 times

rl e ; ...

rl d ; ...

rla ; ...

cp c ; ...

jr c,$+4 ; ...

sub c ; ...

inc l ; ...




В  DE - делимое, в  C - делитель,

результат в HL, остаток в A.

;DIVIDE DE/C=HL

LD DE,768

LD C,3

CALL DIV

RET

DIV LD B,16

LD HL,0

LD A,H

DV1 RL E

RL D

RLA

SUB C

JR NC,DV2

ADD A,C

DV2 CCF 

RL L

RL H

DJNZ DV1

RET




Деление регистровoй пары 

на /2, /4, /8 и т.д. 

AND   A

RR    B

RR    C

При повторе данного примера N раз 

вы разделите число на 2 в степени N. 

Таким  методом возможно разделить и 

отдельные  регистры.




;A/6

деление A на шесть /6:

LD    A,делимое

LD    B,#00

LABEL SUB   #06 (делитель)

RET   C

INC   B

JR    LABEL 

на выходе этой  процедуры  частное  

будет находится в регистре B  

(не  забудте, что таким методом можно

выполнить только  целочисленное деление!).




;BC/DE Divides BC by DE. 

Gives result in BC, remainder in HL by hll

udiv16 ld a,d

or e

ret z ;Return NC if dividing by 0

ld hl,0

ld a,16

udiv1 scf

rl c

rl b

adc hl,hl

sbc hl,de

jr nc,udiv2

add hl,de

dec c

udiv2 dec a

jr nz,udiv1

scf

ret




C_Div_D:

;Inputs:     

C is the numerator     

D is the denominator

;Outputs:

A is the remainder

B is 0

C is the result of C/D

D,E,H,L are not changed

  ld b,8

  xor a

C_Div_D_loop:

  sla c

  rla

  cp d

  jr c,+_

  inc c

  sub d

_:

  djnz C_Div_D_loop

  ret




BC_Div_DE:   

BC/DE ==> BC, remainder in HL

;min: 1166cc     

;max: 1310cc      

;avg: 1238cc

;22 bytes

  ld hl,0

  ld a,b

  ld b,16

div_loop:

  ;shift the bits from BC into HL

  sla c \ rla

  adc hl,hl

  sbc hl,de

  jr nc,div_inc_acc

  add hl,de

  .db $FE     ;this begins the instruction 

;'cp *', so it eats the next byte.


div_inc_acc:

  inc c

div_loop_done:

  djnz div_loop

  ld b,a

  ret




;from action by vav

Вход:de-число1 (2 байта)/bc-65536-число2 (2 байта)            

Выход:a-остаток от деления:de=число1/число2                    

DELENIE ld      hl,0                      

        ld      a,e                       

        add     a,a                       

        rl      d                         

        adc     hl,hl                     

        add     hl,bc                     

        jr      c,NABA57                  

        sbc     hl,bc                     

NABA57  rla                               

        rl      d                         

NABA58  adc     hl,hl                     

        add     hl,bc                     

        jr      c,NABA60                  

NABA59  sbc     hl,bc                     

NABA60  rla                               

        rl      d                         

NABA61  adc     hl,hl                     

        add     hl,bc                     

        jr      c,NABA62                  

        sbc     hl,bc                     

NABA62  rla                               

        rl      d                         

        adc     hl,hl                     

        add     hl,bc                     

        jr      c,NABA63                  

        sbc     hl,bc                     

NABA63  rla                               

        rl      d                         

        adc     hl,hl                     

        add     hl,bc                     

        jr      c,NABA64                  

        sbc     hl,bc                     

NABA64  rla                               

        rl      d                         

        adc     hl,hl                     

        add     hl,bc                     

        jr      c,NABA65                  

        sbc     hl,bc                     

NABA65  rla                               

        rl      d                         

        adc     hl,hl                     

        add     hl,bc                     

        jr      c,NABA66                  

        sbc     hl,bc                     

NABA66  rla                               

        rl      d                         

        adc     hl,hl                     

        add     hl,bc                     

        jr      c,NABA67                  

        sbc     hl,bc                     

NABA67  rla                               

        rl      d                         

        adc     hl,hl                     

        add     hl,bc                     

        jr      c,NABA68                  

        sbc     hl,bc                     

NABA68  rla                               

        rl      d                         

        adc     hl,hl                     

        add     hl,bc                     

        jr      c,NABA69                  

        sbc     hl,bc                     

NABA69  rla                               

        rl      d                         

        adc     hl,hl                     

        add     hl,bc                     

        jr      c,NABA70                  

        sbc     hl,bc                     

NABA70  rla                               

        rl      d                         

        adc     hl,hl                     

        add     hl,bc                     

        jr      c,NABA71                  

        sbc     hl,bc                     

NABA71  rla                               

        rl      d                         

        adc     hl,hl                     

        add     hl,bc                     

        jr      c,NABA72                  

        sbc     hl,bc                     

NABA72  rla                               

        rl      d                         

        adc     hl,hl                     

        add     hl,bc                     

        jr      c,NABA73                  

        sbc     hl,bc                     

NABA73  rla                               

        rl      d                         

        adc     hl,hl                     

        add     hl,bc                     

        jr      c,NABA74                  

        sbc     hl,bc                     

NABA74  rla                               

        rl      d                         

        adc     hl,hl                     

        add     hl,bc                     

        jr      c,NABA75                  

        sbc     hl,bc                     

NABA75  rla                               

        rl      d                         

        ld      e,a                       

        ret                       




;from Neos

;chl=chl/d ;a-remainder ;length is 22 bytes

;maximal time is about 1200 tacts

_div24_8 xor a

sub d

ld d,a

xor a

ld b,24

div248_ adc hl,hl

rl c

rla

add a,d

jr c,$+3

sub d

djnz div248_

adc hl,hl

rl c

ret




;from Neos

; hl/d=a hl\d=l

FDIV xor a

ld e,a

ld b,8

fdiv1 rr d

rr e

sbc hl,de

jr nc,$+3

add hl,de

rla

djnz fdiv1

cpl

ret




;bc/de=bc,hl

;Divides BC by DE. 

;Gives result in BC, remainder in HL.

udiv16  ld      a,d    

        or      e

        ret     z       ;Return NC if dividing by 0

        ld      hl,0

        ld      a,16

udiv1   scf

        rl      c

        rl      b

        adc     hl,hl

        sbc     hl,de

        jr      nc,udiv2

        add     hl,de

        dec     c

udiv2   dec     a

        jr      nz,udiv1

        scf

        ret




; A,HL=(A,HL)/(B,DE)

DIVISIO  LD      C,A

        XOR     A

        EXX 

        LD      HL,1

        LD      B,H

        EXX 

DIV1    SLA     L

        RL      H

        RL      C

        RLA 

        CP      B

        JR      C,DIV2

        JR      NZ,DIV3

        EX      AF,AF'

        LD      A,C

        CP      D

        JR      C,DIV22

        JR      NZ,DIV32

        LD      A,H

        CP      E

        JR      C,DIV22

DIV32   EX      AF,AF'

DIV3    EX      AF,AF'

        LD      A,L

        LD      L,H

        LD      H,C

        AND     A

        SBC     HL,DE

        LD      C,H

        LD      H,L

        LD      L,A

        JR      NC,DIV33

        EX      AF,AF'

        SUB     B

        DEC     A

DIV34   EXX 

        SLI     L

        RL      H

        RL      B

        EXX 

        JP      NC,DIV1

        JP      DIVEXIT

DIV22   EX      AF,AF'

DIV2    EXX 

        SLA     L

        RL      H

        RL      B

        EXX 

        JP      NC,DIV1

DIVEXIT EXX 

        PUSH    HL

        LD      A,B

        EXX 

        POP     HL

        RET 

DIV33   EX      AF,AF'

        SUB     B

        JP      DIV34






;HL = HL/DE

;1.DIV - деление

;INPUT : HL <-- что   DE <-- на что

;OUTPUT: HL = HL/DE ;портятся  DE,HL,A

DIV     LD      A,D

        OR      E

        RET     Z

        PUSH    DE

        PUSH    BC

        LD      A,1

DIV_0   PUSH    HL

        SBC     HL,DE

        JP      C,HL0

        SBC     HL,DE

        JP      C,DIV_1

DIV_01  INC     A

        SLA     E

        RL      D

        POP     HL

        JP      DIV_0

DIV_1   POP     HL

        LD      BC,0

DIV_2   AND     A

        JP      NZ,DIV_3

        LD      H,B

        LD      L,C

        POP     BC

        POP     DE

        RET 

DIV_3   SBC     HL,DE

        JP      NC,DIV_4

        ADD     HL,DE

DIV_4   CCF 

        RL      C

        RL      B

        SRL     D

        RR      E

        DEC     A

        JP      DIV_2

HL0     CP      1

        JP      NZ,DIV_01

        POP     HL

        POP     BC

        POP     DE

        LD      HL,0

        RET 


REVERSAL


Posted by John Metcalf

Fast Z80 Bit Reversal

For years I've been using the following 

simple code to reverse the bits 

in the A register by rotating 

the bits left out of one register 

and right into another:


; reverse bits in A

; 8 bytes / 206 cycles

ld b,#08

ld l,a

revlp rl l

rra

djnz revlp

ret


; reverse bits in A

; 17 bytes / 66 cycles

ld l,a    ; A=76543210

rlca

rlca      ; A=54321076

xor l

and #AA

xor l     ; A=56341270

ld l,a

rlca

rlca

rlca      ; A=41270563

rrc l     ; L=05634127

xor l

and #66

xor l     ; A=01234567

ret

SIN, COS

;by SerzhSoft;

;вычисление синуса HL

;A=sin(HL)*255, CF=sign (NC=[+], C=[-])

SIN_HL

        dec     h

        jr      z,GOSIN2

        inc     h

        jr      nz,SIN360

        ld      h,SINTAB/256

        ld      a,l

        cp      180

        jr      nc,GOSIN1

        ld      a,(hl)

        and     a

        ret

GOSIN1  sub     180

        ld      l,a

        ld      a,(hl)

        scf

        ret

GOSIN2  ld      a,l

        cp      104

        jr      nc,GOSIN3

        ld      l,a

        ld      a,104

        sub     l

        ld      l,a

        ld      h,SINTAB/256

        ld      a,(hl)

        scf

        ret

GOSIN3  inc     h

SIN360  ld      bc,360

        and     a

LPSIN1  sbc     hl,bc

        jr      nc,LPSIN1

        add     hl,bc

        jp      SIN_HL

;-------

;вычисление косинуса HL

;A=cos(HL)*255, CF=sign (NC=[+], C=[-])

COS_HL

        dec     h

        jr      z,GOCOS3

        inc     h

        jr      nz,COS360

        ld      h,SINTAB/256

        ld      a,l

        cp      180

        jr      nc,GOCOS2

        sub     90

        jr      c,GOCOS1

        ld      l,a

        ld      a,(hl)

        scf

        ret

GOCOS1  add     a,180

        ld      l,a

        ld      a,(hl)

        and     a

        ret

GOCOS2  sub     90

        ld      l,a

        ld      a,(hl)

        scf

        ret

GOCOS3  ld      a,l

        cp      14

        jr      nc,GOCOS4

        add     a,166

        ld      l,a

        ld      h,SINTAB/256

        ld      a,(hl)

        scf

        ret

GOCOS4  cp      104

        jr      nc,GOCOS5

        sub     14

        ld      l,a

        ld      h,SINTAB/256

        ld      a,(hl)

        and     a

        ret

GOCOS5  inc     h

COS360  ld      bc,360

        and     a

LPCOS1  sbc     hl,bc

        jr      nc,LPCOS1

        add     hl,bc

        jp      COS_HL

;выравнивание на сегмент (граница 256)

        ds      $/256*256+256-$

SINTAB  ;insert  "sincos.d"

db #0D,#12,#16,#1B,#1F,#23,#28,#2C,#31,#35,#39,#3E,#42,#46,#4A,#4F

db #53,#57,#5B,#5F,#64,#68,#6C,#70,#74,#78,#7C,#7F,#83,#87,#8B,#8E

db #92,#96,#99,#9D,#A0,#A4,#A7,#AB,#AE,#B1,#B4,#B7,#BA,#BD,#C0,#C3

db #C6,#C9,#CC,#CE,#D1,#D3,#D6,#D8,#DA,#DD,#DF,#E1,#E3,#E5,#E7,#E9

db #EB,#EC,#EE,#F0,#F1,#F2,#F4,#F5,#F6,#F7,#F8,#F9,#FA,#FB,#FC,#FC

db #FD,#FE,#FE,#FE,#FF,#FF,#FF,#FF,#FF,#FF,#FF,#FE,#FE,#FE,#FD,#FC

db #FC,#FB,#FA,#F9,#F8,#F7,#F6,#F5,#F4,#F2,#F1,#F0,#EE,#EC,#EB,#E9

db #E7,#E5,#E3,#E1,#DF,#DD,#DA,#D8,#D6,#D3,#D1,#CE,#CC,#C9,#C6,#C3

db #C0,#BD,#BA,#B7,#B4,#B1,#AE,#AB,#A7,#A4,#A0,#9D,#99,#96,#92,#8E

db #8B,#87,#83,#7F,#7C,#78,#74,#70,#6C,#68,#64,#5F,#5B,#57,#53,#4F

db #4A,#46,#42,#3E,#39,#35,#31,#2C,#28,#23,#1F,#1B,#16,#12,#0D,#09

db #04






;--------------------------------------;

;     SIN-TABLE MAKING ALGORYTHMS      ;

; conception & code by Kolotov Sergey  ;

; (c) SerzhSoft, Shadrinsk, apr, 1998  ;

;--------------------------------------;

        ORG     #8000

;--------------------------------------;

STACK_A EQU     #2D28

FP_TO_A EQU     #2DD5

;

SIN_MAX EQU     #7F

SIN_ADD EQU     0

;

SINTBL1 EQU     #6000

SINTBL2 EQU     #6100

;--------------------------------------;

MAINPRG

        LD      C,SIN_MAX

        LD      B,SIN_ADD

        LD      DE,SINTBL1

        PUSH    BC

        CALL    SINCALC

        POP     BC

        LD      DE,SINTBL2

        CALL    SINMAKE

        RET

;--------------------------------------;

SINCALC

        PUSH    DE

        PUSH    BC

        PUSH    DE

        LD      A,C

        CALL    STACK_A

        POP     DE

        LD      A,E

        CALL    STACK_A

        RST     #28     ;calc

        DB      #A3     ;stk_pi/2

        DB      #34,#40,#B0,#00,#40 ;#40

        DB      #05     ;divide

        DB      #04     ;multiply

        DB      #1F     ;sin

        DB      #04     ;multiply

        DB      #38     ;endcalc

        CALL    FP_TO_A

        JR      Z,$+4   ;->

        NEG             ; |

        POP     BC      ;<-

        ADD     A,B

        POP     DE

        LD      (DE),A

        INC     E

        JR      NZ,SINCALC

        RET

;--------------------------------------;

SINMAKE

        INC     C

        LD      HL,SIN_DAT

        PUSH    BC

        LD      B,E

LP_SMK1 PUSH    HL

        LD      H,(HL)

        LD      L,B

        LD      A,#08

LP_SMK2 ADD     HL,HL

        JR      NC,$+3

        ADD     HL,BC

        DEC     A

        JR      NZ,LP_SMK2

        LD      A,H

        LD      (DE),A

        POP     HL

        INC     HL

        INC     E

        BIT     6,E

        JR      Z,LP_SMK1

        LD      H,D

        LD      L,E

        DEC     L

        LD      A,(HL)

        LD      (DE),A

        INC     E

LP_SMK3 LD      A,(HL)

        LD      (DE),A

        INC     E

        DEC     L

        JR      NZ,LP_SMK3

LP_SMK4 LD      A,(HL)

        NEG

        LD      (DE),A

        INC     L

        INC     E

        JR      NZ,LP_SMK4

        POP     BC

LP_SMK5 LD      A,(DE)

        ADD     A,B

        LD      (DE),A

        INC     E

        JR      NZ,LP_SMK5

        RET

;-------;

SIN_DAT

  DB  #00,#06,#0D,#13,#19,#1F,#25,#2C

  DB  #32,#38,#3E,#44,#4A,#50,#56,#5C

  DB  #62,#67,#6D,#73,#78,#7E,#83,#88

  DB  #8E,#93,#98,#9D,#A2,#A7,#AB,#B0

  DB  #B4,#B9,#BD,#C1,#C5,#C9,#CD,#D0

  DB  #D4,#D7,#DB,#DE,#E1,#E4,#E7,#E9

  DB  #EC,#EE,#F0,#F2,#F4,#F6,#F7,#F9

  DB  #FA,#FB,#FC,#FD,#FE,#FE,#FF,#FF

;--------------------------------------;






; sincos.z80

; CORDIC for sin() and cos() for the Zilog Z80 and Assembler Z80DT

; Author: Andre Adrian

; Version: 12apr2011

; length is 341 bytes


; LOAD TEST VALUES

    LD      DE,12AFH                ; Angle = -1.57079632679 (-90°)

    LD      BC,9B78H

    CALL    SINCOS

; expected sin = B'C'BC = 0C0000000H (-1.0)

; expected cos = D'E'DE = 000000000H (0.0)

; delivered sin = B'C'BC = 0BFFFFFFFH

; delivered cos = D'E'DE = 000000031H

    HALT


;==================================================

; Constants

;

CN:        EQU        22

CM:        EQU        8


;==================================================

; variable storage (RAM)

;

Angle:

    DEFW    0,0

Y:

    DEFW    0,0

X:

    DEFW    0,0

Yold:

    DEFW    0,0

pATR:

    DEFW    0

Step:

    DEFB    0


;==================================================

; constant storage (ROM)

;

ATR:

    DEFW 0F6A8H,03243H      ; atan(1)

    DEFW 06705H,01DACH      ; atan(1/2)

    DEFW 0BAFCH,00FADH      ; atan(1/4)

    DEFW 06EA6H,007F5H      ; atan(1/8)

    DEFW 0AB76H,003FEH      ; ...

    DEFW 0D55BH,001FFH

    DEFW 0FAAAH,000FFH

    DEFW 0FF55H,0007FH

    DEFW 0FFEAH,0003FH


;==================================================

; N BIT ARITHMETRIC SHIFT RIGHT ROUTINE 32BIT = 32BIT

; BCDE >>= A

; CHANGES FLAGS

;

SRBCDE:

    SUB     8               ; SET CARRY FLAG IF A < 8

    JR      C,SRBEBT        ; NO MORE BYTES TO SHIFT

    LD      E,D             ; SHIFT BITS 8..15 TO 7..0

    LD      D,C             ; SHIFT BITS 16..23 TO 8..15

    LD      C,B             ; SHIFT BITS 24..31 TO 16..23

    LD      B,0             ; ASSUME POSITIVE NUMBER

    BIT     7,C             ; SET ZERO FLAG IF BIT 7 == 0

    JR      Z,SRBEPS

    DEC     B                   ; CHANGE + TO - SIGN

SRBEPS:

    JR      SRBCDE

SRBEBT:

    ADD     A,8             ; UNDO SUB 8, SET ZERO FLAG IF A == 0

SRBELP:

    JR      Z,SRBERT        ; NO MORE BITS TO SHIFT

    SRA     B

    RR      C

    RR      D

    RR      E

    DEC     A               ; SET ZERO FLAG IF A == 0

    JR      SRBELP

SRBERT:

    RET                                                ; RESULT IS IN BCDE.


;==================================================

; SIN() COS() ROUTINE 2 * 32BIT = 32BIT

; B'C'BC, D'E'DE = f(BCDE)

; NEEDS REGISTERS A BC DE HL, CHANGES FLAGS

;

SINCOS:

    LD      (Angle),DE      ; store argument

    LD      (Angle+2),BC

    SUB     A               ; A = 0

    LD      (Step),A        ; i = 0

    LD      L,A

    LD      H,A

    LD      (Y),HL          ; y = 0;

    LD      (Y+2),HL

    LD      HL,03B6AH       ; x = FIXED(0.607252935..);

    LD      (X),HL

    LD      HL,026DDH

    LD      (X+2),HL

    LD      HL,ATR          ; pATR = ATR;

    LD      (pATR),HL

SNCSDO:                         ; do {

    LD      HL,(Y)          ;   yold = y;

    LD      (Yold),HL

    LD      HL,(Y+2)

    LD      (Yold+2),HL

                            ;   y += (angle >= 0)? x >> i: -(x >> i);

    LD      DE,(X)          ;   x >> i

    LD      BC,(X+2)

    LD      A,(Step)

    CALL    SRBCDE

    LD      A,(Angle+3)     ;   (angle >= 0)?

    RLA                     ;   Bit 7 to Carry

    LD      HL,(Y)

    JR      C,SNCSL1

    ADD     HL,DE           ;   y += x >> i

    LD      (Y),HL

    LD      HL,(Y+2)

    ADC     HL,BC

    JR      SNCSE1

SNCSL1:

    AND     A               ;   y -= x >> i

    SBC     HL,DE

    LD      (Y),HL

    LD      HL,(Y+2)

    SBC     HL,BC

SNCSE1:

    LD      (Y+2),HL

                            ;   x -= (angle >= 0)? yold >> i: -(yold >> i);

    LD      DE,(Yold)       ;   yold >> i

    LD      BC,(Yold+2)

    LD      A,(Step)

    CALL    SRBCDE

    LD      A,(Angle+3)     ;   (angle >= 0)?

    RLA

    LD      HL,(X)

    JR      C,SNCSL2

    AND     A               ;   x -= yold >> i

    SBC     HL,DE

    LD      (X),HL

    LD      HL,(X+2)

    SBC     HL,BC

    JR      SNCSE2

SNCSL2:

    ADD     HL,DE           ;   x += yold >> i

    LD      (X),HL

    LD      HL,(X+2)

    ADC     HL,BC

SNCSE2:

    LD      (X+2),HL

                           ;   a = (i < M+1)? *pATR++: atr_fixed[M] >> (i-M);

    LD      A,(Step)       ;   (i < M+1)?

    SUB     CM+1           ;   i-(M+1)

    JR      NC,SNCSL3

    LD      HL,(pATR)      ;   *pATR++

    LD      E,(HL)

    INC     HL

    LD      D,(HL)

    INC     HL

    LD      C,(HL)

    INC     HL

    LD      B,(HL)

    INC     HL

    LD      (pATR),HL

    JR      SNCSE3

SNCSL3:

    LD      DE,(ATR+32)     ;   atr[M] >> i-M

    LD      BC,(ATR+34)

    INC     A               ;   i-M

    CALL    SRBCDE

SNCSE3:

                            ;   angle -= (angle >= 0)? a: -a;

    LD      A,(Angle+3)     ;   (angle >= 0)?

    RLA

    LD      HL,(Angle)

    JR      C,SNCSL4

    AND     A               ;   angle -= a

    SBC     HL,DE

    LD      (Angle),HL

    LD      HL,(Angle+2)

    SBC     HL,BC

    JR      SNCSE4

SNCSL4:

    ADD     HL,DE           ;   angle += a

    LD      (Angle),HL

    LD      HL,(Angle+2)

    ADC     HL,BC

SNCSE4:

    LD      (Angle+2),HL

                            ; } while (++i <= N-1);

    LD      HL,Step         ; ++i

    INC     (HL)

    LD      A,CN-1          ; N-1 >= ++i

    CP      (HL)

    JP      NC,SNCSDO

                            ; RESULT IS IN MEM(X) AND MEM(Y)

    LD      DE,(X)

    LD      BC,(Y)

    EXX

    LD      DE,(X+2)

    LD      BC,(Y+2)

    EXX

    RET                     ; RESULT IS IN D'E'DE AND B'C'BC





SerzhSoft

          КАК СИHУС ЗАБАБАХАТЬ 

                    Лучше в pуках синица,

                   чем под кpоватью утка!

 

     Hастало  вpемя поговоpить о наболев-

шем,  а  конкpетнее  -  о синусах. Дело в

том,  что  во  многих мегадемных эффектах

используются  именно  синусные  таблички.

Это  может  быть  пpостенькая плазма, ка-

кое-нибудь  тело,  движущееся  по плавной

тpаектоpии,  полет над гоpами, тоннельчик

и  куча  еще  всего  дpугого, чего только

можно пожелать...

     Тpадиционно, да и удобно, of course,

создавать  синусную  табличку с pазмеpом,

кpатным  256  байт,  а  еще лучше - pовно

#0100!  : -) Пpи этом табличка должна на-

чинаться  с  адpеса, выpавненного на сег-

мент,  то  есть младший байт этого адpеса

pавен нолику (#?? 00).

     Создать пpостейшую sin-table можно с

помощью обыкновенного бейсика. К пpимеpу,

нам  необходима табличка, pасположенная с

адpеса  24576  (#6000),  длиной 256 байт,

амплитудой  (pазмахом)  синуса от -127 до

+127 и pазмеpом в один пеpиод. Получаем:

 

 10 FOR i=0 TO 255

 20 POKE 24576+i, SIN (PI/128*i)*127

 30 NEXT i

 

     Тепеpь сгенеpиpованную табличку мож-

но сохpанить на диске и встpаивать в свои

ассемблеpные  эффекты по INSERT, INCBIN и

т. д.

     Hо  вот  вы  pешили немного изменить

амплитуду,  скажем от -63 до +63, или вам

вдpуг  стукнуло в голову, что "сеpединной

точкой" должна быть не 0, а, скажем, 128.

То есть получить pазбpос значений таблич-

ки  от  128-63  до 128+63. Конечно, можно

снова "загpузить" BASIC и набpать немного

дpугую пpогpамму:

 

 10 FOR i=0 TO 255

 20 POKE 24576+i, SIN (PI/128*i)*63+128

 30 NEXT i

 

     Затем  опять сохpанить все на диске,

и  пpодолжать  кодить в асм'е. Hо, навеp-

ное,  даже  последнему лaмеpу стало ясно,

что  тут что-то не так. Hеэффективно, по-

теpя  вpемени, да еще место на диске вся-

кие  "левые" файлы занимают. Плюс, к тому

же, тоpмознутость компиляции пpи подгpуз-

ке по INCBIN'у. Да и хpанить целый синус-

ный пеpиод в памяти, когда можно обойтись

и четвеpью... Hет, с этим надо что-то де-

лать!

     И  выход, конечно же, есть. Hе уж то

нам  слабо  накодить  пpоцедуpу ГЕHЕPАЦИИ

синуса  на  ассемблеpе.  Да  pаз плюнуть!

Хлоп, и уже готова подпpогpамма с исполь-

зованием ПЗУ 'шного калькулятоpа. Похожая

вещь   пpисутствовала  в  Deja  Vu  #03 ,

статья  "Плавающие  атpибуты" .  Здесь же

пpиводится немного улучшенная пpоцедуpа:

 

STACK_A EQU     #2D28

FP_TO_A EQU     #2DD5

;

SINCALC

        PUSH    DE

        PUSH    BC

        PUSH    DE

        LD      A,C

        CALL    STACK_A

        POP     DE

        LD      A,E

        CALL    STACK_A

        RST     #28     ;calc

        DB      #A3     ;stk_pi/2

        DB      #34,#40,#B0,#00,#40 ;#40

        DB      #05     ;divide

        DB      #04     ;multiply

        DB      #1F     ;sin

        DB      #04     ;multiply

        DB      #38     ;endcalc

        CALL    FP_TO_A

        JR      Z,$+4   ;->

        NEG             ; |

        POP     BC      ;<-

        ADD     A,B

        POP     DE

        LD      (DE),A

        INC     E

        JR      NZ,SINCALC

        RET

 

     Hа входе в pегистpе C мы должны ука-

зать  "pазмах"  синуса  (амплитуда: -С...

+С),  в pегистpе B - центpальное значение

(сколько  пpибавлять), а pегистpовая паpа

DE  должна  содеpжать  адpес  буфеpа  под

табличку.  Пpичем, этот адpес обязательно

должен  быть кpатен 256 (выpавнен на сег-

мент).  И  вот, пpимеpно чеpез 15 секунд,

мы получим те заветные 256 байт!

     "Так до-о-олго!!!" - спpаведливо за-

метите Вы и будете пpавы. Hу а что вы еще

хотели  всего за 39 байт памяти, занимае-

мых  пpоцедуpой.  Hо,  конечно же, данный

пpимеp  был  пpиведен  лишь  для  полноты

каpтины,  а настоящую пpоцедуpу мы pазбе-

pем  именно  сейчас. Ведь не будете же вы

в  демке  писать  "Please, wait 15 sec...

Decrunching..." только pади какой-то таб-

лички  в 256 байт! И пpавильно! Итак, вот

скоpостной  аналог вышепpиведенной пpоце-

дуpы, pаботающий несpавненно быстpее, хо-

тя и занимающий уже 55 байт + 64 байта на

данные. Итого: 119 байт. Hо скоpость!

 

SINMAKE

        INC     C

        LD      HL,SIN_DAT

        PUSH    BC

        LD      B,E

LP_SMK1 PUSH    HL

        LD      H,(HL)

        LD      L,B

        LD      A,#08

LP_SMK2 ADD     HL,HL

        JR      NC,$+3

        ADD     HL,BC

        DEC     A

        JR      NZ,LP_SMK2

        LD      A,H

        LD      (DE),A

        POP     HL

        INC     HL

        INC     E

        BIT     6,E

        JR      Z,LP_SMK1

        LD      H,D

        LD      L,E

        DEC     L

        LD      A,(HL)

        LD      (DE),A

        INC     E

LP_SMK3 LD      A,(HL)

        LD      (DE),A

        INC     E

        DEC     L

        JR      NZ,LP_SMK3

LP_SMK4 LD      A,(HL)

        NEG

        LD      (DE),A

        INC     L

        INC     E

        JR      NZ,LP_SMK4

        POP     BC

LP_SMK5 LD      A,(DE)

        ADD     A,B

        LD      (DE),A

        INC     E

        JR      NZ,LP_SMK5

        RET

;

SIN_DAT

  DB  #00,#06,#0D,#13,#19,#1F,#25,#2C

  DB  #32,#38,#3E,#44,#4A,#50,#56,#5C

  DB  #62,#67,#6D,#73,#78,#7E,#83,#88

  DB  #8E,#93,#98,#9D,#A2,#A7,#AB,#B0

  DB  #B4,#B9,#BD,#C1,#C5,#C9,#CD,#D0

  DB  #D4,#D7,#DB,#DE,#E1,#E4,#E7,#E9

  DB  #EC,#EE,#F0,#F2,#F4,#F6,#F7,#F9

  DB  #FA,#FB,#FC,#FD,#FE,#FE,#FF,#FF

 

     Тепеpь  пpи  инсталляции какого-либо

вашего  FX'а достаточно вызвать SINMAKE с

нужными  паpаметpами,  и  спустя  секунду

табличка  уже готова! Можно генеpить нес-

колько  pазных  табличек...  Или одну, но

состоящую  из pазных синусных пеpиодов, с

pазными  амплитудами...  А затем, скажем,

пустить  по этой таблице scroller и отpы-

ваться на всю катушку...

     В пpиложении вы найдете ассемблеpный

исходник  с  двумя  этими пpоцедуpами.  И

помните:

 

         Лучше в пpогpамме синус,

         чем в мегадеме глюки!!!

 

     P.S.  А  ведь  можно  обойтись и без

таблички данных SIN_DAT! Кто догадается -

как? : -)


SQR

;извлечение    квадратного    корня   

;из регистровой    пары.  

;на входе HL-число из которого 

;необходимо извлечь квадратный корень

;на выходе A-квадратный корень из HL

;by Virtual/BW

sqrhl xor a     ;обнулили a;)

 ld de,64  ;этого требует алгоритм ;  t=14

sla h     ;берем два самых левых

adc a,a   ;бита аргумента

sla h     ;

adc a,a   ;

jr z,$+4  ;если они не равны

dec a     ;нулю, то увеличиваем

inc d     ;результат  ;   t=39

sla h     ;┐далее следуем

adc a,a   ;│алгоритму извлечения

sla h     ;│квадратного корня

adc a,a   ;│"столбиком", только

sla d     ;│

ld c,d    ;│3 раза

sli c     ;│

cp c      ;│

jr c,$+4  ;│

sub c     ;│

inc d     ;┘  t=63*3=189

sla l     ;┐проделываем похожую

adc a,a   ;│операцию с

sla l     ;│младшим байтом

adc a,a   ;│аргумента

sla d     ;│

ld c,d    ;│2 раза

sli c     ;│

cp c      ;│

jr c,$+4  ;│

sub c     ;│

inc d     ;┘  t=63*2=126

ld h,a    ;

or a      ;обнулили флаг переноса ;  t=8

sbc hl,de ;теперь нам не хватает

jr nc,$+3 ;одного регистра d для

add hl,de ;выполнения последних

ccf       ;двух циклов, придется

rl d      ;использовать более

add hl,hl ;медленные операции

add hl,hl ;с регистровыми парами  ;  t=67

sbc hl,de ;и последний раз

ccf       ;выполняем расчеты, не

ld a,d    ;восстанавливая hl

adc a,a   ;в a-результат ;  t=27

;итого: 14+39+189+126+8+67+27=470 тактов





;извлечение    квадратного    корня   

;из трехбайтового числа.

;На входе: dhl=d*65536+hl - само число

;На выходе: hl - тот самый квадратный корень

;by Virtual/BW

sqrdhl xor a    ;начало процедуры

ld bc,64 ;практически аналогично ;предыдущей  ;  t=14

sla d    ;

adc a,a  ;

sla d    ;

adc a,a  ;  t=39

jr z,$+4 ;

dec a    ;

inc b    ;

sla d    ;┐

adc a,a  ;│

sla d    ;│

adc a,a  ;│

sla b    ;│

ld e,b   ;│3 раза

sli e    ;│

cp e     ;│

jr c,$+4 ;│

sub e    ;│

inc b    ;┘ t=3*63=189

sla h    ;┐

adc a,a  ;│

sla h    ;│

adc a,a  ;│

sla b    ;│

ld e,b   ;│2 раза

sli e    ;│

cp e     ;│

jr c,$+4 ;│

sub e    ;│

inc b    ;┘ t=63*2=126

ld d,l   ;

ld l,h   ;

ld h,a   ;меняем регистры

or a     ;  t=16

sbc hl,bc;┐

jr nc,$+3;│

add hl,bc;│

ccf      ;│2 раза

rl b     ;│

add hl,hl;│

add hl,hl;┘ t=67*2=134

ld l,h   ;есть подозрение, что

ld h,0   ;этот блок и предыдущий

ld c,b   ;можно немного ускорить

ld b,h   ;

rl h     ;

ld a,d   ;  t=31

rla      ;┐да и этот блок мне

adc hl,hl;│не нравится.

rla      ;│очень вероятно, что

adc hl,hl;│его можно неплохо

sla c    ;│ускорить. Но как?

rl b     ;│

ld d,b   ;│

ld e c   ;│3 раза

sli e    ;│

rl d     ;│

sbc hl,de;│

 jr nc,$+4;│

add hl,de;│

dec c    ;│

inc c    ;┘ t=3*119=357 (!)  ;ужас! Думайте, как ;ускорить!

rla      ;этот блок аналогичен

adc hl,hl;предыдущему с

rla      ;небольшой разницей

adc hl,hl;в конце. Это сделано

ld d,b   ;ради повышения

ld e,c   ;скорости вычислений

sla e    ;

rl d     ;

sli e    ;

rl d     ;

sbc hl,de;

ccf      ;  t=97

ld h,b   ;

ld l,c   ;

adc hl,hl;в hl - результат                 ;  t=23

;итого: 14+39+189+126+16+134+31+357+97+23=1026




Square table generator is based on observation that 

differences between consecutive squares 

(0, 1, 4, 9, 16, 25, ...)

form a sequence of odd numbers. 

(1, 3, 5, 7, 9, ...). 

Thus, by adding successive odd numbers 

iteratively we generate integer squares.

ld hl,SqrTab; must be a multiple of 256

ld b,l

ld c,l ; BC holds odd numbers

ld d,l

ld e,l ; DE holds squares

SqrGen ld (hl),e

inc h

ld (hl),d ; store x^2

ld a,l

neg

ld l,a

ld (hl),d

dec h

ld (hl),e ; store -x^2

ex de,hl

inc c

add hl,bc ; add next odd number

inc c

ex de,hl

cpl ; one byte replacement for NEG, DEC A

ld l,a

rla

jr c,SqrGen






; Square root of 16-bit value 

;by Ricardo Bittencourt

; In:  HL = value

; Out:  D = result (rounded down) 

Sqr16 ld de,#0040

ld a,l

ld l,h

ld h,d

or a

ld b,8

Sqr16_Loop sbc hl,de

jr nc,Sqr16_Skip

add hl,de

Sqr16_Skip ccf

rl d

add a,a

adc hl,hl

add a,a

adc hl,hl

djnz Sqr16_Loop

ret





; Square Root (16 bit)  HL=number to find 

;square root of Returns result in A

SQR16 LD DE,1

XOR A

DEC A

SQ16 SBC HL,DE

INC DE

INC DE

INC A

JR NC,SQ16

RET




; Square Root (32 bit) BCDE=number to find 

;square root of. Returns result in DE

SQR32 LD A,B 

PUSH DE 

POP IX 

LD D,0

LD E,D 

LD H,D 

LD L,D

LD B,16 

SQ32A SUB #40 

SBC HL,DE 

JR NC,SQ32B

ADD A,#40

ADC HL,DE

SQ32B CCF 

RL

RL

ADD IX,IX 

RL

RLA 

ADC HL,HL 

DJNZ SQ32A

RET 





sqrt32:

;Input: HLDE

;Output: DE is the sqrt, AHL is the remainder

;speed: 238+{0,1}+{0,44}+sqrtHL+3*sqrt32sub_2+sqrt32_iter15

;min: 1260

;max: 1506

;avg: 1377.75

  push de

  call sqrtHL

  pop bc

  add a,a

  ld e,a

  jr nc,+_

  inc d

_:

  ld a,b

  call sqrt32sub_2

  call sqrt32sub_2

;Now we have four more iterations

;The first two are no problem

  ld a,c

  call sqrt32sub_2

;On the next iteration, HL might temporarily overflow by 1 bit

  call sqrt32_iter15

;On the next iteration, HL is allowed to overflow,

 DE could overflow with our current routine, 

but it needs to be shifted right at the end, anyways

sqrt32_iter16:

  add a,a

  ld b,a        ;either 0x00 or 0x80

  adc hl,hl

  rla

  adc hl,hl

  rla

;AHL - (DE+DE+1)

  sbc hl,de \ sbc a,b

  inc e

  or a

  sbc hl,de \ sbc a,b

  ret p

  add hl,de

  adc a,b

  dec e

  add hl,de

  adc a,b

  ret

sqrt32sub_2:

;min: 185cc

;max: 231cc

;avg: 208cc

  call +_

_:

;min: 84cc

;max: 107cc

;avg: 95.5cc

  sll e \ rl d

  add a,a \ adc hl,hl

  add a,a \ adc hl,hl

  sbc hl,de

  inc e

  ret nc

  dec e

  add hl,de

  dec e

  ret

sqrt32_iter15:

;91+{8,0+{0,23}}

;min: 91cc

;max: 114cc

;avg: 100.75cc

  sll e \ rl d      ;sla e \ rl d \ inc e

  add a,a

  adc hl,hl

  add a,a

  adc hl,hl       ;This might overflow!

  jr c,sqrt32_iter15_br0

  sbc hl,de

  inc e

  ret nc

  dec e

  add hl,de

  dec e

  ret

sqrt32_iter15_br0:

  or a

  sbc hl,de

  inc e

  ret






sqrtA: ;Written by Zeda

;Input: A

;Output: D is the squareroot, A is the remainder (input-D^2)

;Destroys: E

;speed: 118+{0,6}+{0,7}+{0,7}+{0,3}

;min: 118cc

;max: 141cc

;avg: 129.5cc

;38 bytes

  ld de,5040h       ; 10

  sub e             ; 4

  jr nc,sqrtA_skip1 ;\

  add a,e           ; | branch 1: 12cc

  ld d,10h          ; | branch 2: 18cc

sqrtA_skip1:        ;/

; ----------

  cp d              ; 4

  jr c,sqrtA_skip2  ;\

  sub d             ; | branch 1: 12cc

  set 5,d           ; | branch 2: 19cc

sqrtA_skip2:        ;/

; ----------

  res 4,d           ; 8

  srl d             ; 8

  set 2,d           ; 8

  cp d              ; 4

  jr c,sqrtA_skip3  ;\

  sub d             ; | branch 1: 12cc

  set 3,d           ; | branch 2: 19cc

sqrtA_skip3:        ;/

  srl d             ; 8

; ----------

  inc a             ; 4

  sub d             ; 4

  jr nc,sqrtA_skip4 ;\

  dec d             ; | branch 1: 12cc

  add a,d           ; | branch 2: 15cc

sqrtA_skip4:        ;/

  srl d             ; 8

  ret               ; 10





sqrtDE:;returns HL as the sqrt, DE as the remainder

;33 bytes;min: 928cc;max: 1120cc;avg: 1024cc;928+8{24,0}

  ld b,$80

  xor a

  ld h,a

  ld l,a

sqrt_loop:

  srl b

  rra

  ld c,a

  add hl,bc

  ex de,hl

  sbc hl,de

  jr nc,+_

  add hl,de

  ex de,hl

  or a

  sbc hl,bc

  .db $DA   ;start of jp c,** which is 10cc to skip the next two bytes.

_:

  ex de,hl

  add hl,bc

  srl h

  rr l

  srl b

  rra

  jr nc,sqrt_loop

  ret






sqrtfixed_88:

;Inputs: A.C

;Output: D.E contains the squareroot

;speed: 1482+12{0,17}

;min: 1482cc

;max: 1686cc

;avg: 1584cc 

;Adapted from Axe

;35 bytes

ld b,12

ld de,0

ld h,d

ld l,e

__Sqrt88Loop:

sub $40

sbc hl,de

jr nc,__Sqrt88Skip

add a,$40

adc hl,de

__Sqrt88Skip:

ccf

rl e

rl d

sla c

rla

adc hl,hl

sla c

rla

adc hl,hl

djnz __Sqrt88Loop

ret






sqrtfixed_88:

;Input: A.E ==> D.E

;Output: DE is the sqrt, AHL is the remainder

;Speed: 690+6{0,13}+{0,3+{0,18}}+{0,38}+sqrtA

;min: 855cc

;max: 1003cc

;avg: 924.5cc

;152 bytes

;Written by Zeda

  call sqrtA

  ld l,a

  ld a,e

  ld h,0

  ld e,d

  ld d,h

  sla e

  rl d

  sll e \ rl d

  add a,a \ adc hl,hl

  add a,a \ adc hl,hl

  sbc hl,de

  jr nc,+_

  add hl,de

  dec e

  .db $FE     ;start of `cp *`

_:

  inc e

  sll e \ rl d

  add a,a \ adc hl,hl

  add a,a \ adc hl,hl

  sbc hl,de

  jr nc,+_

  add hl,de

  dec e

  .db $FE     ;start of `cp *`

_:

  inc e

  sll e \ rl d

  add a,a \ adc hl,hl

  add a,a \ adc hl,hl

  sbc hl,de

  jr nc,+_

  add hl,de

  dec e

  .db $FE     ;start of `cp *`

_:

  inc e

  sll e \ rl d

  add a,a \ adc hl,hl

  add a,a \ adc hl,hl

  sbc hl,de

  jr nc,+_

  add hl,de

  dec e

  .db $FE     ;start of `cp *`

_:

  inc e

;Now we have four more iterations

;The first two are no problem

  sll e \ rl d

  add hl,hl

  add hl,hl

  sbc hl,de

  jr nc,+_

  add hl,de

  dec e

  .db $FE     ;start of `cp *`

_:

  inc e

  sll e \ rl d

  add hl,hl

  add hl,hl

  sbc hl,de

  jr nc,+_

  add hl,de

  dec e

  .db $FE     ;start of `cp *`

_:

  inc e

sqrtfixed_88_iter11:

;On the next iteration, HL might temporarily overflow by 1 bit

  sll e \ rl d      ;sla e \ rl d \ inc e

  add hl,hl

  add hl,hl

  jr c,sqrtfixed_88_iter11_br0

  sbc hl,de

  jr nc,+_

  add hl,de

  dec e

  jr sqrtfixed_88_iter12

sqrtfixed_88_iter11_br0:

  or a

  sbc hl,de

_:

  inc e

;On the next iteration, HL is allowed to overflow,

 DE could overflow with our current routine, 

 but it needs to be shifted right at the end, anyways

sqrtfixed_88_iter12:

  ld b,a      ;A is 0, so B is 0

  add hl,hl

  add hl,hl

  rla

;AHL - (DE+DE+1)

  sbc hl,de \ sbc a,b

  inc e

  or a

  sbc hl,de \ sbc a,b

  ret p

  add hl,de

  adc a,b

  dec e

  add hl,de

  adc a,b

  ret





;Adapted from Axe

sqrtHL:;Input: HL;Output: D is the square root, 

cH is the remainder (c being the c flag), 

A is 0, B is 0, L is 0

;speed: 758+8{0,6}

;min: 758cc;max: 806cc;avg: 782cc;26 bytes

p_Sqrt:

ld a,l

ld l,h

ld de,$0040

ld h,d

ld b,8

or a

__SqrtLoop:

sbc hl,de

jr nc,__SqrtSkip

add hl,de

__SqrtSkip:

ccf

rl d

add a,a

adc hl,hl

add a,a

adc hl,hl

djnz __SqrtLoop

ret




;written by Zeda

sqrtHL:;returns A as the sqrt, HL as the remainder, D = 0 fastest

;min: 352cc;max: 391cc;avg: 371.5cc

  ld de,05040h  ; 10

  ld a,h        ; 4

  sub e         ; 4

  jr nc,sq7     ;\

  add a,e       ; | branch 1: 12cc

  ld d,16       ; | branch 2: 18cc

sq7:            ;/

  cp d          ; 4

  jr c,sq6      ;\

  sub d         ; | branch 1: 12cc

  set 5,d       ; | branch 2: 19cc

sq6:            ;/

  res 4,d       ; 8

  srl d         ; 8

  set 2,d       ; 8

  cp d          ; 4

  jr c,sq5      ;\

  sub d         ; | branch 1: 12cc

  set 3,d       ; | branch 2: 19cc

sq5:            ;/

  srl d         ; 8

  inc a         ; 4

  sub d         ; 4

  jr nc,sq4     ;\

  dec d         ; | branch 1: 12cc

  add a,d       ; | branch 2: 19cc

  dec d         ; | <-- this resets the low bit of D, so `srl d` resets carry.

sq4:            ;/

  srl d         ; 8

  ld h,a        ; 4

  ld a,e        ; 4

  sbc hl,de     ; 15

  jr nc,sq3     ;\

  add hl,de     ; | 12cc or 18cc

sq3:            ;/

  ccf           ; 4

  rra           ; 4

  srl d         ; 8

  rra           ; 4

  ld e,a        ; 4

  sbc hl,de     ; 15

  jr c,sq2      ;\

  or 20h        ; | branch 1: 23cc

  db 254        ; |   <-- start of `cp *` which is 7cc to skip the next byte.

sq2:            ; | branch 2: 21cc

  add hl,de     ;/

  xor 18h       ; 7

  srl d         ; 8

  rra           ; 4

  ld e,a        ; 4

  sbc hl,de     ; 15

  jr c,sq1      ;\

  or 8          ; | branch 1: 23cc

  db 254        ; |   <-- start of `cp *` which is 7cc to skip the next byte.

sq1:            ; | branch 2: 21cc

  add hl,de     ;/

  xor 6         ; 7

  srl d         ; 8

  rra           ; 4

  ld e,a        ; 4

  sbc hl,de     ; 15

  jr nc,+_      ;    \

  add hl,de     ; 15  |

  srl d         ; 8   |

  rra           ; 4   | branch 1: 38cc

  ret           ; 10  | branch 2: 40cc

_:              ;     |

  inc a         ; 4   |

  srl d         ; 8   |

  rra           ; 4   |

  ret           ; 10 /





; fast 16-bit isqrt by Zeda Thomas; Feel free to use for whatever :) 

very fastest

sqrtHL:

;Input: HL;Output: A is the integer square root of HL

;Destroys: HL,DE (D is actually 0)

;min: 343cc

;max: 380cc

;avg: 361.5cc

;88 bytes

  ld de,05040h  ; 10

  ld a,h        ; 4

  sub e         ; 4

  jr nc,sq7     ;\

  add a,e       ; | branch 1: 12cc

  ld d,16       ; | branch 2: 18cc

sq7:            ;/

; ----------

  cp d          ; 4

  jr c,sq6      ;\

  sub d         ; | branch 1: 12cc

  set 5,d       ; | branch 2: 19cc

sq6:            ;/

; ----------

  res 4,d       ; 8

  srl d         ; 8

  set 2,d       ; 8

  cp d          ; 4

  jr c,sq5      ;\

  sub d         ; | branch 1: 12cc

  set 3,d       ; | branch 2: 19cc

sq5:            ;/

  srl d         ; 8

; ----------

  inc a         ; 4

  sub d         ; 4

  jr nc,sq4     ;\

  dec d         ; | branch 1: 12cc

  add a,d       ; | branch 2: 19cc

  dec d         ; | <-- this resets the low bit of D, so `srl d` resets carry.

sq4:            ;/

  srl d         ; 8

  ld h,a        ; 4

; ----------

  ld a,e        ; 4

  sbc hl,de     ; 15

  jr nc,sq3     ;\

  add hl,de     ; | 12cc or 18cc

sq3:            ;/

  ccf           ; 4

  rra           ; 4

  srl d         ; 8

  rra           ; 4

; ----------

  ld e,a        ; 4

  sbc hl,de     ; 15

  jr c,sq2      ;\

  or 20h        ; | branch 1: 23cc

  db 254        ; |   <-- start of `cp *` which is 7cc to skip the next byte.

sq2:            ; | branch 2: 21cc

  add hl,de     ;/

  xor 18h       ; 7

  srl d         ; 8

  rra           ; 4

; ----------

  ld e,a        ; 4

  sbc hl,de     ; 15

  jr c,sq1      ;\

  or 8          ; | branch 1: 23cc

  db 254        ; |   <-- start of `cp *` which is 7cc to skip the next byte.

sq1:            ; | branch 2: 21cc

  add hl,de     ;/

  xor 6         ; 7

  srl d         ; 8

  rra           ; 4

; ----------

  ld e,a        ; 4

  sbc hl,de     ; 15

;This code would restore the square root

;   jr nc,sq0      ;\

;   add hl,de     ; | 12cc or 18cc

; sq0:            ;/

  sbc a,255     ; 7

  srl d         ; 8

  rra           ; 4

  ret           ; 10





sqrtHLIX:

;Input: HLIX;Output: DE is the sqrt, AHL is the remainder

;speed: 751+6{0,6}+{0,3+{0,18}}+{0,38}+sqrtHL

;min: 1103;max: 1237;avg: 1165.5;166 bytes

  call sqrtHL   ;expects returns A as sqrt, HL as remainder, D = 0

  add a,a

  ld e,a

  rl d

  ld a,ixh

  sll e \ rl d

  add a,a \ adc hl,hl

  add a,a \ adc hl,hl

  sbc hl,de

  jr nc,+_

  add hl,de

  dec e

  .db $FE     ;start of `cp *`

_:

  inc e

  sll e \ rl d

  add a,a \ adc hl,hl

  add a,a \ adc hl,hl

  sbc hl,de

  jr nc,+_

  add hl,de

  dec e

  .db $FE     ;start of `cp *`

_:

  inc e

  sll e \ rl d

  add a,a \ adc hl,hl

  add a,a \ adc hl,hl

  sbc hl,de

  jr nc,+_

  add hl,de

  dec e

  .db $FE     ;start of `cp *`

_:

  inc e

  sll e \ rl d

  add a,a \ adc hl,hl

  add a,a \ adc hl,hl

  sbc hl,de

  jr nc,+_

  add hl,de

  dec e

  .db $FE     ;start of `cp *`

_:

  inc e

;Now we have four more iterations

;The first two are no problem

  ld a,ixl

  sll e \ rl d

  add a,a \ adc hl,hl

  add a,a \ adc hl,hl

  sbc hl,de

  jr nc,+_

  add hl,de

  dec e

  .db $FE     ;start of `cp *`

_:

  inc e

  sll e \ rl d

  add a,a \ adc hl,hl

  add a,a \ adc hl,hl

  sbc hl,de

  jr nc,+_

  add hl,de

  dec e

  .db $FE     ;start of `cp *`

_:

  inc e

sqrt32_iter15:

;On the next iteration, HL might temporarily overflow by 1 bit

  sll e \ rl d      ;sla e \ rl d \ inc e

  add a,a

  adc hl,hl

  add a,a

  adc hl,hl       ;This might overflow!

  jr c,sqrt32_iter15_br0

  sbc hl,de

  jr nc,+_

  add hl,de

  dec e

  jr sqrt32_iter16

sqrt32_iter15_br0:

  or a

  sbc hl,de

_:

  inc e

;On the next iteration, HL is allowed to overflow, 

DE could overflow with our current routine, 

but it needs to be shifted right at the end, anyways

sqrt32_iter16:

  add a,a

  ld b,a        ;either 0x00 or 0x80

  adc hl,hl

  rla

  adc hl,hl

  rla

;AHL - (DE+DE+1)

  sbc hl,de \ sbc a,b

  inc e

  or a

  sbc hl,de \ sbc a,b

  ret p

  add hl,de

  adc a,b

  dec e

  add hl,de

  adc a,b

  ret





SqrtL:

;Inputs:;     L is the value to find the square root of

;Outputs:

;      C is the result

;      B,L are 0

;      DE is not changed

;      H is how far away it is from the next smallest perfect square

;      L is 0

;      z flag set if it was a perfect square;Destroyed:      A

     ld bc,400h       ; 10    10

     ld h,c           ; 4      4

sqrt8Loop:            ;

     add hl,hl        ;11     44

     add hl,hl        ;11     44

     rl c             ; 8     32

     ld a,c           ; 4     16

     rla              ; 4     16

     sub a,h          ; 4     16

     jr nc,$+5        ;12|19  48+7x

       inc c

       cpl

       ld h,a

     djnz sqrt8Loop   ;13|8   47

     ret              ;10     10

;287+7x, x is the number of bits in the result;min: 287;max: 315;19 bytes




L_sqrd:

;Input: L;Output: L*L->A

;147 t-states;36 bytes

    ld b,l

;First iteration, get the lowest 3 bits of -x^2

    sla l

    rrc b

    sbc a,a

    or l

    ld c,a

;second iteration, get the next 2 bits of -x^2

    rrc b

    sbc a,a

    xor l

    and $F8

    add a,c

    ld c,a

;third iteration, get the next 2 bits of -x^2

    sla l

    rrc b

    sbc a,a

    xor l

    and $E0

    add a,c

    ld c,a

;fourth iteration, get the eight bit of x^2

    sla l

    rrc b

    sbc a,a

    xor l

    and $80

    sub c

    ret




sqrA:

;A*A->A

;Destroys: HL

;76cc or 79cc or 82cc

;Avg: 79cc;51 bytes

    add a,a

    add a,a

    jr nc,$+4

    neg

    rrca

    rrca

    ld l,a

    srl l

    ld h,sqrLUT/256

    jr c,$+4

    neg

    add a,(hl)

    ret

sqrLUT:

;MUST BE ALIGNED to a 256-byte boundary.

;Can use:

;  #if 0!=$&255

;  .fill 256-($&255),0

;  #endif

.db $00,$06,$14,$2A,$48,$6E,$9C,$D2

.db $10,$56,$A4,$FA,$58,$BE,$2C,$A2

.db $20,$A6,$34,$CA,$68,$0E,$BC,$72

.db $30,$F6,$C4,$9A,$78,$5E,$4C,$42





;|HL = SQR (HL)

;4.RAS - квадратный корень

;INPUT : HL <-- из чего

;OUTPUT: HL = SQR (HL)

;портятся  DE,HL,BC,A

RAS     LD      A,H

        OR      L

        JR      Z,RAS_4

RAS1     LD      A,H

        AND     A

        JP      NZ,RAS11

        LD      A,L

        CP      1

        JP      NZ,RAS11

        LD      HL,1

        RET 

RAS11   LD      B,H

        LD      C,L

        SRL     B

        RR      C

RAS_1   PUSH    HL

        LD      D,B

        LD      E,C

        CALL    DIV

        ADD     HL,BC

        SRL     H

        RR      L

        PUSH    HL

        LD      D,B

        LD      E,C

        SBC     HL,DE

        JP      NC,RES_10

        ADD     HL,DE

        EX      DE,HL

        SBC     HL,DE

RES_10  LD      A,H

        AND     A

        JP      NZ,RAS_0

        LD      A,L

        CP      2

        JP      NC,RAS_0

        POP     HL

        POP     BC

        RET 

RAS_0   POP     BC

        POP     HL

        JP      RAS_1

RAS_4   LD      HL,0

        RET 


SQR     OR A

        LD A,L

        LD L,H

        LD DE,64

        LD H,D

        LD B,7

SQR0    SBC HL,DE

        JR NC,$+3

        ADD HL,DE

        CCF 

        RL D

        RLA 

        ADC HL,HL

       JP C,0

        RLA 

        ADC HL,HL

       JP C,0

        DJNZ SQR0

        SBC HL,DE

       ;JR NC,$+3

       ;ADD HL,DE

        CCF 

        RL D

       ;RLA

       ;ADC HL,HL

       ;RLA

       ;ADC HL,HL

        RET 






;sqr hl (from Inferno 4)

;HL=аргумент N

    OR A

    LD A,L

    LD L,H

    LD DE,64

    LD H,D

    LD B,8

sqr0    SBC HL,DE

    JR NC,$+3

    ADD HL,DE

    CCF

    RL D

    ADD A,A

    ADC HL,HL

    ADD A,A

    ADC HL,HL

    DJNZ sqr0

;D=результат







Posted by John Metcalf

; 16-bit integer square root

; 34 bytes, 1005-1101 cycles (average 1053)

; call with de = number to square root

; returns  hl = square root

; corrupts bc, de

ld bc,#8000

ld h,c

ld l,c

sqrlp srl b

rr c

add hl,bc

ex de,hl

sbc hl,de

jr c,sqrbit

ex de,hl

add hl,bc

jr sqrfi

sqrbit add hl,de

ex de,hl

or a

sbc hl,bc

sqrfi srl h

rr l

srl b

rr c

jr nc,sqrlp

ret


;

;

;


Posted by John Metcalf

; fast 16-bit integer square root

; 92 bytes, 344-379 cycles (average 362)

; v2 - 3 t-state optimization spotted by Russ McNulty

; call with hl = number to square root

; returns a = square root

; corrupts hl, de

  ld a,h

  ld de,#B0C0

  add a,e

  jr c,sq7

  ld a,h

  ld d,#F0

sq7

  add a,d

  jr nc,sq6

  res 5,d

  db 254

sq6   sub d

  sra d

  set 2,d

  add a,d

  jr nc,sq5

  res 3,d

  db 254

sq5   sub d

  sra d

  inc d

  add a,d

  jr nc,sq4

  res 1,d

  db 254

sq4   sub d

  sra d

  ld h,a

  add hl,de

  jr nc,sq3

  ld e,#40

  db 210

sq3   sbc hl,de

  sra d

  ld a,e

  rra

  or #10

  ld e,a

  add hl,de

  jr nc,sq2

  and #DF

  db 218

sq2   sbc hl,de

  sra d

  rra

  or #04

  ld e,a

  add hl,de

  jr nc,sq1

  and #F7

  db 218

sq1   sbc hl,de

  sra d

  rra

  inc a

  ld e,a

  add hl,de

  jr nc,sq0

  and #FD

sq0   sra d

  rra

  cpl

  ret

NEG

neghl   xor a

        sub l

        ld l,a

        sbc a,h;a,a

        sub l

        ld h,a

        ret



negde   xor a

        sub e

        ld e,a

        sbc a,d ;a,a

        sub e

        ld d,a

        ret



RANDOM

;by DDp

;in:    HL', DE'   out:   A, HL', DE'

RANDOM

EXX

LD      C,L

LD      A,H

RL      C

RLA

RL      C

RLA

LD      B,A

RL      C

RLA

RL      C

RLA

RL      C

RLA

XOR     B

LD      H,L

LD      L,D

LD      D,E

LD      E,A

EXX

RET



Процедура jtn’а для двухбайтного рандома, с сидом. 

Для однобайтного можно брать любой байт из двух:

rnd16

    ld de,seed

    ld a,d,h,e,l,253

    or a:sbc hl,de,a,0,hl,de

    ld d,0:sbc a,d:ld e,a:sbc hl,de

    jr nc,rnd:inc hl

rnd ld (rnd16+1),hl

    ret




random_color

ld a,r

and 7

or a

jr z,random_color

ret



Xorshift

Xorshift is a class of pseudorandom number generators 

discover by George Marsaglia and detailed in his 

2003 paper, Xorshift RNGs.

; 16-bit xorshift pseudorandom number generator 

by John Metcalf, 20 bytes, 86 cycles (excluding ret)

; returns   hl = pseudorandom number; corrupts a

; generates 16-bit pseudorandom numbers 

with a period of 65535

; using the xorshift method: 

hl ^= hl << 7; hl ^= hl >> 9; hl ^= hl << 8

; some alternative shift triplets which also 

perform well are: 6, 7, 13; 7, 9, 13; 9, 7, 13.

xornd ld hl,1       ; seed must not be 0

ld a,h

rra

ld a,l

rra

xor h

ld h,a

ld a,l

rra

ld a,h

rra

xor l

ld l,a

xor h

ld h,a

ld (xornd+1),hl

ret




;You may use this routine, just be sure to 

credit John Metcalf! Written by John Metcalf

;http://www.retroprogramming.com/2017/07/xorshift-pseudorandom-numbers-in-z80.html

; Annotated by Zeda Thomas, 

fixed typo (86 cycles==> 82 cycles)

;Note: uses SMC 16-bit xorshift pseudorandom 

number generator

; 20 bytes, 82 cycles (excluding ret)

; returns   hl = pseudorandom number

; corrupts   a

xorrnd

  ld hl,1         ; Init the seed, must not be 0

  ld a,h          ;\

  rra             ; | Get the top bits of xs<<7 and xor with the top byte of HL

  ld a,l          ; |        abcdefgh ijklmnop

  rra             ; |       ^hijklmno 00000000

  xor h           ; | Note that we still need to xor the 'p' with the top byte of l

  ld h,a          ;/

  ld a,l          ;\

  rra             ; | we get 'p' in the carry flag, now shift that in when we do xs>>9

  ld a,h          ; |        abcdefgh ijklmnop   (new value)

  rra             ; |       ^00000000 pabcdefg

  xor l           ; | the 'p' is leftover from the first step, so now Step 1 and 2 are done

  ld l,a          ;/

  xor h           ;\ Finally, xor the bottom byte with the top byte for step 3

  ld h,a          ;/

  ld (xorrnd+1),hl  ; write back the new value as the next seed

  ret




;Dean Belfield

; 16 bit random number routine I found on the web

; Returns a pseudo-random number in the HL register

RND16_SEED: EQU 12345

RND16: LD DE,RND16_SEED

LD A,D

LD H,E

LD L,253

OR A

SBC HL,DE

SBC A,0

SBC HL,DE

LD D,0

SBC A,D

LD E,A

SBC HL,DE

JR NC,1F

INC HL

1f LD (RND16+1),HL

RET





RND_32  LD    HL,(SEED)

        CALL  RND

RND     LD    A,H

        ADD   HL,HL

        XOR   H

        ADD   HL,HL

        ADD   HL,HL

        ADD   HL,HL

        XOR   H

        ADD   HL,HL

        ADD   HL,HL

        XOR   H

        ADD   HL,HL

        ADD   HL,HL

        LD    L,A

        LD    (SEED),HL

        RET 

SEED    DEFW  #FFFF ; НЕ НОЛЬ!






Следующая процедура является генератором RND. 

На выходе из процедуры в

регистровой паре HL будет число от 0 до 65535.


 10         ORG     40000

 20 BEGIN   LD      HL,(TEMP)

 30         LD      C,16

 40 S1      LD      A,H

 50         ADD     HL,HL

 60         AND     255

 70         JP      PE,S2

 80         INC     HL

 90 S2      DEC     C

100         JR      NZ,S1

110         LD      (TEMP),HL

120 TEMP    DEFB    1,0






from Pplayers (Saracen)

RANDOM LD DE,(SEED)

LD H,E

LD L,253

LD A,D

OR A

LD B,0

SBC HL,DE

SBC A,B

SBC HL,DE

SBC A,B

LD E,A

LD D,B

SBC HL,DE

JP NC,RANDOM2

INC HL

RANDOM2 LD (SEED),HL

RET



by Baze

RANDOM    

ld a,SEED ;SEED is usually 0

    ld b,a

    add a,a

    add a,a

    add a,b

    inc a ;you may try also ADD A,7

    ld (RANDOM+1),a

    ret




 8-bit Xor-Shift random number generator.

;Created by Patrik Rak in 2008 and revised in 2011/2012.

;http://www.worldofspectrum.org/forums/showthread.php?t=23070


        org 40000


        call rnd        ; BASIC driver

        ld   c,a

        ld   b,0

        ret


xsrnd   ld  hl,0xA280   ; yw -> zt

        ld  de,0xC0DE   ; xz -> yw

        ld  (rnd+4),hl  ; x = y, z = w

        ld  a,l         ; w = w ^ ( w << 3 )

        add a,a

        add a,a

        add a,a

        xor l

        ld  l,a

        ld  a,d         ; t = x ^ (x << 1)

        add a,a

        xor d

        ld  h,a

        rra             ; t = t ^ (t >> 1) ^ w

        xor h

        xor l

        ld  h,e         ; y = z

        ld  l,a         ; w = t

        ld  (xsrnd+1),hl

        ret 





pentis by tony raugas (далеко не самый лучший вариант)

; ;---

; ld      a, r ;рандом но он раскидан 

; dec     a ;

; adc     a, 1

; ld      (random_var), a ;

; ld      hl, (random_var);теперь объеденил и рандом заработал как надо

; ld      b, 5   ;раньше выдавал первую фигуру в тетрисе Т в  петрисе L в пентисе Y (не суть)

; frn1 sla     l

; rl      h ;ВНИМАНИЯ-ВНИМАНЬЯ! рандом в самый первый раз НАДО ВЫЗВАТЬ ДВАЖДЫ!!!

; ld      a, #C0 ;что в принципе и сделано

; and     h ;зато после удаления фигур и режимов петриса и пентиса - заглючило опять

; jp      pe, frn2

; inc     l

; frn2 djnz    frn1

; ld      (random_var), hl







8-bit Random Number Generator

This is a very simple linear congruential generator.

The formula is x[i + 1] = (5 * x[i] + 1) mod 256.

Its only advantage is small size and simplicity.

Due to nature of such generators only a couple 

of higher bits should be considered random.

Input: none ,

Output: A = pseudo-random number, period 256

Rand8 ld a,Seed ; Seed is usually 0

ld b,a

add a,a

add a,a

add a,b

inc a ; another possibility is ADD A,7

ld (Rand8+1),a

ret




;This code snippet is 9 bytes and 43cc

;Inputs:;   HL is the input seed and must be non-zero

;Outputs:;   A is the 8-bit pseudo-random number

;   HL is the new seed value (will be non-zero)

;opcode cc

    add hl,hl     ; 29    11

    sbc a,a       ; 9F     4

    and %00101101 ; E62D   7

    xor l         ; AD     4

    ld l,a        ; 6F     4

    ld a,r        ; ED5F   9

    add a,h       ; 84     4

;Technical details:

;   The concept behind this routine is to combine an LFSR (poor RNG) with a

; counter. The counter improves the RNG quality, while also extending the period

; length.

;   For this routine, I took advantage of the Z80's built-in counter, the `r`

; register. This means that we don't need to store the counter anywhere, and it

; is pretty fast to access!

;   Some caveats:

;     * r is a 7-bit counter

;     * r will increment some number of times between runs of the RNG. In most

;       cases, this will be constant, but if it increments an even number each

;       time, then the bottom bit is always the same, weakening the effect of

;       the counter. In the worst case, it increments a multiple of 128 times,

;       effectively making your RNG just as good/bad as the LFSR. Ideally, you

;       want `r` to increment an odd number of times between runs.

;     * In the best case, the bottom 7 bits have 50/50 chance of being 0 or 1.

;       The top bit is 1 with probability 1/2 + 1/(2^17-2) ~ .5000076295

;     * In the event that your main loop waits for user input between calls,

;       then congatulations, you might have a True RNG :)





Fast quality CMWC random number generator for Z80 

I have created to weed out the crap RNGs out there. 

32+10 bytes, 146..149 T cycles, period 253*2^59, 

which is more than 2^66 or 10^20.

cmwc.asm

; 8-bit Complementary-Multiply-With-Carry (CMWC) 

random number generator.

; Created by Patrik Rak in 2012, and revised in 2014/2015,

; with optimization contribution 

from Einar Saukas and Alan Albrecht.

;http://www.worldofspectrum.org/forums/showthread.php?t=39632

        org 40000

        call rnd    ; BASIC driver

        ld   c,a

        ld   b,0

        ret

rnd     ld   hl,table

        ld   a,(hl) ; i = ( i & 7 ) + 1

        and  7

        inc  a

        ld   (hl),a

        inc  l      ; hl = &cy

        ld   d,h    ; de = &q[i]

        add  a,l

        ld   e,a

        ld   a,(de) ; y = q[i]

        ld   b,a

        ld   c,a

        ld   a,(hl) ; ba = 256 * y + cy

        sub  c      ; ba = 255 * y + cy

        jr   nc,$+3

        dec  b

        sub  c      ; ba = 254 * y + cy

        jr   nc,$+3

        dec  b

        sub  c      ; ba = 253 * y + cy

        jr   nc,$+3

        dec  b

        ld   (hl),b ; cy = ba >> 8, x = ba & 255

        cpl         ; x = (b-1) - x = -x - 1 = ~x + 1 - 1 = ~x

        ld   (de),a ; q[i] = x

        ret

table   db   0,0,82,97,120,111,102,116,20,15

        if   (table/256)-((table+9)/256)

        error "whole table must be within single 256 byte block"

        endif






4.2 16-bit Random Number Generator

This generator is based on similar method but

gives much better results. 

It was taken from an old ZX Spectrum 

game and slightly optimised.

Input: none

Output: HL = pseudo-random number, period 65536

Rand16 ld de,Seed ; Seed is usually 0

ld a,d

ld h,e

ld l,253

or a

sbc hl,de

sbc a,0

sbc hl,de

ld d,0

sbc a,d

ld e,a

sbc hl,de

jr nc,Rand

inc hl

Rand ld (Rand16+1),hl

ret





Z80 Psuedo-random number generator

ZX Spectrum Random Numbers

LD A,R ; Load the A register with the refresh register

LD L,A ; Copy register A into register L

AND %00111111 ; This masking prevents the address we are forming from accessing RAM

LD H,A ; Copy register A into register H

LD A,(HL) ; Load the pseudo-random value into A

; HOW THIS WORKS

; The refresh register in the Z80 is highly 

unpredictable since it is incremented every cycle.

; Because it may be at any value when this 

routine is called, it is very good for random numbers.

; This routine increases the randomness of the 

number since it forms an address based on the

; refresh counter's current status and accesses 

the memory at that address.

; It can also be modified to get a sixteen-bit 

pseudo-random number by changing line 5 to LD D,(HL)

; and adding these two lines to the end:

; INC L

; LD E,(HL)

; This routine was written for the ZX Spectrum 

which has a 16KB ROM. If you plan to use this routine

; on another Z80 system, change the binary value at 

the AND instruction. For example, if you had a

; Z80 computer with an 8KB ROM, you would change the 

binary value to %00011111.






; Fast RND

; An 8-bit pseudo-random number generator,

; using a similar method to the Spectrum ROM,

; - without the overhead of the Spectrum ROM.

; R = random number seed

; an integer in the range [1, 256]

; R -> (33*R) mod 257

; S = R - 1

; an 8-bit unsigned integer

 ld a, (seed)

 ld b, a 

 rrca ; multiply by 32

 rrca

 rrca

 xor #1f

 add a, b

 sbc a, 255 ; carry

 ld (seed), a

 ret





This is a short peice of code that generates a maximal length,

8 bit, pseudo random number sequence. 

It was originally used to switch off and on all the LED's in a 8x30 matrix 

in a good random looking order (the un-needed values being skipped).

It's shorter, but slower, than using a lookup table and a counter.

; returns pseudo random 8 bit number in A. Only affects A.

; (r_seed) is the byte from which the number is generated and MUST be

; initialised to a non zero value or this function will always return

; zero. Also r_seed must be in RAM, you can see why......

rand_8 LD A,(r_seed) ; get seed

AND #B8h ; mask non feedback bits

SCF ; set carry

JP PO,no_clr ; skip clear if odd

CCF ; complement carry (clear it)

no_clr LD A,(r_seed) ; get seed back

RLA ; rotate carry into byte

LD (r_seed),A ; save back for next prn

RET ; done

r_seed DB 1 ; prng seed byte (must not be zero)






Ion Random

This is based off the tried and true pseudorandom 

number generator featured in Ion by Joe Wingbermuehle

;-----> Generate a random number

; output a=answer 0<=a<=255

; all registers are preserved except: af

random:

        push    hl

        push    de

        ld      hl,(randData)

        ld      a,r

        ld      d,a

        ld      e,(hl)

        add     hl,de

        add     a,l

        xor     h

        ld      (randData),hl

        pop     de

        pop     hl

        ret

randData dw 12345 ;here must be a 2 byte seed located in ram. 

While this is a fast generator, 

it's generally not considered very good 

in terms of randomness.





Linear Feedback Shift Register

This particular prng is based on Linear 

feedback shift register.

It uses a 64bit seed and generates 8 new 

bits at every call. 

LFSRSeed must be an 8 byte seed located in ram.

;------LFSR------

;James Montelongo

;optimized by Spencer Putt

;out: a = 8 bit random number

RandLFSR ld hl,LFSRSeed+4

        ld e,(hl)

        inc hl

        ld d,(hl)

        inc hl

        ld c,(hl)

        inc hl

        ld a,(hl)

        ld b,a

        rl e \ rl d

        rl c \ rla

        rl e \ rl d

        rl c \ rla

        rl e \ rl d

        rl c \ rla

        ld h,a

        rl e \ rl d

        rl c \ rla

        xor b

        rl e \ rl d

        xor h

        xor c

        xor d

        ld hl,LFSRSeed+6

        ld de,LFSRSeed+7

        ld bc,7

        lddr

        ld (de),a

        ret

While this may produces better numbers, 

it is slower, larger and requires a bigger seed

than ionrandom. Assuming theres is a good seed to start,

it should generate ~2^56 bytes before repeating. However if t

here is not a good seed(0 for example), then the numbers crea

ted will not be adequate. Unlike Ionrandom and its use of the 

r register, starting with the same seed the same numbers will 

be generated. With Ionrandom 

the code running may have an impact on the number generated. 

This means this method requires more initialization.

You can initialize with TI-OS's seeds, stored at 

seed1 and seed2, both are ti-floats but will serve the purpose.






Combined LFSR/LCG, 16-bit seeds

This is a very fast, quality pseudo-random number generator. 

It combines a

16-bit Linear Feedback Shift Register 

and a 16-bit LCG.

prng16:

;Inputs:

;   (seed1) contains a 16-bit seed value

;   (seed2) contains a NON-ZERO 16-bit seed value

;Outputs:

;   HL is the result

;   BC is the result of the LCG, so not that great of quality

;   DE is preserved

;Destroys:

;   AF

;cycle: 4,294,901,760 (almost 4.3 billion)

;160cc

;26 bytes

    ld hl,(seed1)

    ld b,h

    ld c,l

    add hl,hl

    add hl,hl

    inc l

    add hl,bc

    ld (seed1),hl

    ld hl,(seed2)

    add hl,hl

    sbc a,a

    and %00101101

    xor l

    ld l,a

    ld (seed2),hl

    add hl,bc

    ret

On their own, LCGs and LFSRs don't pr

oduce great results and are generally

 very cyclical, but they are very fast 

to compute. The 16-bit LCG in the above 

example will bounce around and reach each

 number from 0 to 65535, but the lower bits 

are far more predictable than the upper bits. Th

e LFSR mixes up the predictability of a given bit'

s state, but it hits every number except 0, meanin

g there is a slightly higher chance of any given b

it in the result being a 1 instead of a 0. It turn

s out that by adding together the outputs of these 

two generators, we can lose the predictability of a

 bit's state, while ensuring it has a 50% chance of

 being 0 or 1. As well, since the periods, 

65536 and 65535 are coprime, then the overall period of 

the generator is 65535*65536, which is over 4 billion.







Combined LFSR/LCG, 32-bit seeds

This is similar to the one above, except that it use

s 32-bit seeds (and still returns a 16-bit result). 

An advantage here is that they've been tested and 

passed randomness tests (all of thee ones offered 

by CAcert labs). As well, it is still very fast.

rand32:

;Inputs:

;   (seed1_0) holds the lower 16 bits of the first seed

;   (seed1_1) holds the upper 16 bits of the first seed

;   (seed2_0) holds the lower 16 bits of the second seed

;   (seed2_1) holds the upper 16 bits of the second seed

;   **NOTE: seed2 must be non-zero

;Outputs:

;   HL is the result

;   BC,DE can be used as lower quality values, 

;   but are not independent of HL.

;Destroys:

;   AF

;Tested and passes all CAcert tests

;Uses a very simple 32-bit LCG and 32-bit LFSR

;it has a period of 18,446,744,069,414,584,320

;roughly 18.4 quintillion.

;LFSR taps: 0,2,6,7  = 11000101

;291cc

seed1_0=$+1

    ld hl,12345

seed1_1=$+1

    ld de,6789

    ld b,h

    ld c,l

    add hl,hl \ rl e \ rl d

    add hl,hl \ rl e \ rl d

    inc l

    add hl,bc

    ld (seed1_0),hl

    ld hl,(seed1_1)

    adc hl,de

    ld (seed1_1),hl

    ex de,hl

seed2_0=$+1

    ld hl,9876

seed2_1=$+1

    ld bc,54321

    add hl,hl \ rl c \ rl b

    ld (seed2_1),bc

    sbc a,a

    and %11000101

    xor l

    ld l,a

    ld (seed2_0),hl

    ex de,hl

    add hl,bc

    ret





rand32:

;Tested and passes all CAcert tests

;Uses a very simple 32-bit LCG and 32-bit LFSR

;it has a period of 18,446,744,069,414,584,320

;roughly 18.4 quintillion.

;LFSR taps: 0,2,6,7  = 11000101

;291cc

;Thanks to Runer112 for his help on optimizing the LCG 

and suggesting to try the much simpler LCG. On their own,

 the two are terrible, but together they are great.

;58 bytes

seed1_0=$+1

    ld hl,12345

seed1_1=$+1

    ld de,6789

    ld b,h

    ld c,l

    add hl,hl \ rl e \ rl d

    add hl,hl \ rl e \ rl d

    inc l

    add hl,bc

    ld (seed1_0),hl

    ld hl,(seed1_1)

    adc hl,de

    ld (seed1_1),hl

    ex de,hl

;;lfsr

seed2_0=$+1

    ld hl,9876

seed2_1=$+1

    ld bc,54321

    add hl,hl \ rl c \ rl b

    ld (seed2_1),bc

    sbc a,a

    and %11000101

    xor l

    ld l,a

    ld (seed2_0),hl

    ex de,hl

    add hl,bc

    ret





rand24:

;;219cc

#ifdef smc

seed1_0=$+1

    ld hl,12345

seed1_1=$+1

    ld a,67

#else

    ld hl,(seed1_0)

    ld a,(seed1_1)

#endif

    ld b,h

    ld c,l

    ld d,a

    add hl,hl \ rla

    add hl,hl \ rla

    inc l

    add hl,bc \ adc a,0

    ld (seed1_0),hl

    ld (seed1_1),a

    ld c,b

    ld b,a

#ifdef smc

seed2_0=$+1

    ld hl,65432

seed2_1=$+1

    ld a,10

#else

    ld hl,(seed2_0)

    ld a,(seed2_1)

#endif

    add hl,hl

    rla

    ld (seed2_1),a

    sbc a,a

    and %10000111

    xor l

    ld l,a

    ld (seed2_0),hl

    add hl,bc

    ret





;#define smc ;uncomment if you are using SMC

rand16:

;collaboration by Zeda with Runer112

;160cc or 148cc if using SMC

;26 bytes

;cycle: 4,294,901,760 (almost 4.3 billion)

#ifdef smc

seed1=$+1

ld hl,9999

#else

    ld hl,(seed1)

#endif

    ld b,h

    ld c,l

    add hl,hl

    add hl,hl

    inc l

    add hl,bc

    ld (seed1),hl

#ifdef smc

seed2=$+1

ld hl,9999

#else

    ld hl,(seed2)

#endif

    add hl,hl

    sbc a,a

    and %00101101

    xor l

    ld l,a

    ld (seed2),hl

    add hl,bc

    ret




rand10:

;Returns A as a random integer on [0,9]

;Destroys: All

  call rand5

  sla h

  rla

  ret


rand5:

;Returns A on [0,4]

;Destroys: All

;Notes:

; This is a non-standard approach to generating random integers on [0,4].

; If you have a truly random number generator that generates bits (0 or 1)

; with equal probability, then standard approaches will still cause a slight

; bias. ("Standard": "rand mod 5" or int(5*rand)). For example, suppose we

; generate a 4-bit number. Then "rand mod 5" will cause 0 to be chosen

; 4/16 times, while 1, 2, 3, and 4 will be chosen 3/16 times (on average).

; A similar problem exists with int(5*rand). One way to mitigate this issue

; is just generating infintely many bits, but apparently that is impractical,

; so I came up with a compromise.

; My approach basically looks at the binary expansion of 1/5, 2/5, 3/5, and 4/5.

;   1/5 = .0011001100110011...

;   2/5 = .0110011001100110...

;   3/5 = .1001100110011001...

;   4/5 = .1100110011001100...

; So if I generate random bits and I get .001100, then a 0, then I know

; that no matter what all of the rest of the bits are, the number is less than

; 1/5, and so int(5*rand) is 0.

; By applying similar logic to the rest of the values, I can guarantee a uniform

; distribution on [0,4]. But there are four cases where this process might

; continue forever, specifically the cases that are like ...00110011...., but

; lucky for us, this happens 4/inf= 0% of the time. In fact, on average it

; takes 3 to 4 bits before the algorithm can assert which value to return.

; The one caveat is that on the Z80, we generally don't have truly random

; numbers :| On the otherhand, it is easy enough to generate pseudo-random

; bits with equal probability :)

  call rand

  ld a,h

  and $C0

  push af    ;save the original value

  ld c,a

rand5_start:

  push bc

  call rand

  pop bc

  ld b,15    ;I set this to 15 because I like to guarantee a bit is available for rand10.

rand5_loop:

  ld a,h

  xor c

  jp p,rand5_end

  add hl,hl

  sla c

  jr c,$+4

  set 6,c

  djnz rand5_loop

  jr rand5_start

rand5_end:

  pop af

  rlca

  rlca

  sla h

  adc a,0

  ret





lfsr64:

;;Output: A is an 8-bit pseudo-random number.

    ld hl,seed

    sla (hl) \ inc hl

    rl (hl) \ inc hl

    rl (hl) \ inc hl

    rl (hl) \ inc hl

    rl (hl) \ inc hl

    rl (hl) \ inc hl

    rl (hl) \ inc hl

    rl (hl)

    ret nc

    ld a,(seed)

    xor %000011011

    ld (seed),a

    ret




lehmer:

;Input:

;  (seed) has the seed value of the RNG

;Output:

;  (seed) is updated, HL is the result

;Destroys:

;  A,DE,BC

;Timing:

;  if seed>0        231cc or 232cc, condition dependent

;  if seed=0        91cc

;  if SMC defined   subtract 6cc

;Size: 44 bytes

;Notes:

;    Uses the Lehmer RNG used by the Sinclair ZX81

;    75x mod 65537 -> x

#ifndef SMC

    ld hl,(seed)

#else

seed = $+1

    ld hl,0

#endif

;multiply by 75

    ld c,l

    ld b,h

    xor a

    adc hl,hl \ jr z,special \ ld d,a \ rla

    add hl,hl \ rla

    add hl,hl \ rla \ add hl,bc \ adc a,d

    add hl,hl \ rla

    add hl,hl \ rla \ add hl,bc \ adc a,d

    add hl,hl \ rla \ add hl,bc

;modulo 65537, see note below on how this works

    ld e,a

    sbc hl,de       ;No need to reset the c flag since it is already

    jr nc,$+3

    inc hl

    ld (seed),hl

    ret

special:

;In the case that HL=0, 

this should be interpreted 

as 65536 = -1 mod 65537, 

so return -75 mod 65537 = -74 mod 65536 in HL

    ld hl,-74

    ld (seed),hl

    ret

;mod by 2^16 + 1 (a prime)

;current form is A*2^16+HL

;need:

;  (A*2^16+HL) mod (2^16+1)

;add 0 as +1-1

;  (A*(2^16+1-1)+HL) mod (2^16+1)

;distribute

;  (A*(2^16+1)-A+HL) mod (2^16+1)

;A*(2^16+1) mod 2^16+1 = 0, so remove

;  (-A+HL) mod (2^16+1)

;Oh hey, that's easy! :P

;I use this trick everywhere, you should, too.





(из zx-review):

RND LD HL,0

LD A,H

ADD A,#77

LD H,A

RLС L

ADD A,L

LD L,A

LD (RND+1),HL




;rnd from Dave Perry's games

PUSH HL

PUSH HL

LD DE,(SEED)

LD H, E

LD L, #FD

LD A, D

AND A

SBC HL, DE

SBC A,0

SBC HL, DE

SBC A,0

LD E,A

LD D,0

SBC HL, DE

JR NC,$+3

INC HL

LD (SEED),HL

POP DE

POP HL

RET

SEED DW 0

А и B SEED останется RND



;from EXOLON by Rafaelle Cecco

;return A-random number

RND push hl

push de

push bc

ld hl, (rndSEED)

ld de, 7

add hl, de

ld e, l

ld d, h

add hl, hl

add hl, hl

ld c, l

ld b, h

add hl, hl

add hl, bc

add hl, de

ld (rndSEED), hl

xor h

pop bc

pop de

pop hl

ret

rndSEED dw 8EAAh





;from Lop Ears game by Players

 RANDOM LD DE,(SEED)

LD H,E

LD L,253

LD A,D

OR A

LD B,0

SBC HL,DE

  SBC A,B

  SBC HL,DE

  SBC A,B

  LD E,A

LD D,B

SBC HL,DE

  JP NC,RANDOM2

  INC HL

RANDOM2 LD (SEED),HL

  RET




Posted by John Metcalf

; 16-bit xorshift pseudorandom number generator

; 20 bytes, 86 cycles (excluding ret)

; returns   hl = pseudorandom number

; corrupts   a

xs16rnd

ld hl,1       ;must not be Zero

ld a,h

rra

ld a,l

rra

xor h

ld h,a

ld a,l

rra

ld a,h

rra

xor l

ld l,a

xor h

ld h,a

ld (xs16rnd+1),hl

ret

HEX, DEC, BIN, ASCII...

;a=0-3 bit of hex

or #f0

daa

add a,#a0

adc a,#40

;out A=ascii code of hex digit to print


;a=0-#0f

add a,#90

daa

adc a,#40

daa

;out A=ascii code of hex digit to print





;зажигает нужный бит в 16-разрядном регистре by Destr

;например:

;На входе A = 5

;На выходе HL = %0000000000100000

; SET A,HL

LD HL,0

RLA

RLA

CP #20

RLA

OR #C4

LD ($+4),A

DW #CBCB


;Или чуть медленней, но уже с игнором старшего полубайта А

; SET A,HL

LD HL,0

SLI A

SLA A

CP #20

RLA

OR #C4

LD ($+4),A

DW #CBCB




;from Fast Tracker

Decimal65535max ex de,hl

push hl

ld l,c

ld h,b

ld bc,#2710 ;10000

call decdigg

jr hd4096

Decimal4096max EX  DE, HL

PUSH HL

LD L, C

LD H, B

hd4096 LD BC, #3E8 ;1000

CALL decdigg

LD BC, #64 ;100

CALL decdigg

LD BC, #A ;10

CALL decdigg

LD A, L

ADD A, #30

LD (DE), A

INC DE

POP HL

EX  DE, HL

RET

decdigg LD A, #2F

OR  A

decdigj INC A

SBC HL, BC

JR NC, decdigj

ADD HL, BC

LD (DE), A

INC DE

RET






;hex to Ascii из Fast Tracker

HexDigitToAsciiCode_X0 RRCA

RRCA

RRCA

RRCA

HexDigitToAsciiCode_0X AND #F

ADD A,#90;hex to ascii

DAA 

ADC A,#40

DAA 

CP #30 ;если ascii код это Ноль

RET NZ ;то

LD A,".";печатаем точки

RET






Библиотечка печати в различных системах счисления.

;------ PDES LIB ------

;Printing in Different Evaluation Systems LIBrary

;(c) SerzhSoft, Shadrinsk, V,3 1997

_NULL   EQU     0   ;используется в изменяемых командах

;--- print in DEC system ---

PDEC_B  ;Печать десятичного числа в A3 (000..255)

        LD      L,A           ;поместили

        LD      H,#00         ; число в HL

        LD      DE,DECTB_W+4  ;адрес в таблице, начиная с сотни

        LD      B,#03         ;макс. возможное кол-во цифр - три

        JR      LP_PDW1       ;переход на цикл печати

;

PDEC_W  ;Печать десятичного числа в HL3 (00000..65535)

        PUSH    HL            ;закинули печатаемое число на стек

        LD      HL,DECTB_W    ;адрес таблицы степеней десятки

        LD      B,#05         ;макс. возможное количество цифр

LP_PDW1 LD      E,(HL)        ;взяли текущую степень

        INC     HL            ; десятки из таблицы

        LD      D,(HL)        ; и поместили в DE

        INC     HL            ;перешли к след. элементу таблицы

        EX      (SP),HL       ;адрес эл-та <-> печатаемое число

        XOR     A             ;обнулили счетчик и флаг C для SBC

LP_PDW2 INC     A             ;увеличиваем счетчик

        SBC     HL,DE         ;вычитаем текущую степень десятки

        JR      NC,LP_PDW2    ;повторяем пока HL>=0

        ADD     HL,DE         ;HL=HL mod DE; A=HL div DE

        ADD     A,"0"-1       ;перевод A в ASCII-код ("0".."9")

        RST     #10           ;печать десятичной цифры

        EX      (SP),HL       ;HL=адрес эл-та, число -> на стек

        DJNZ    LP_PDW1       ;цикл по цифрам

        POP     HL            ;убрали оставшийся ноль со стека

        RET                   ;выход из процедуры

DECTB_W DW      10000,1000,100,10,1    ;Таблица степеней десятки



;--- print in HEX system ---

PHEX_W  ;Печать шестнадцатеричного числа в HL3 (0000..FFFF)

        LD      A,H           ;печать старшего байта числа

        CALL    PHEX_B        ;вызов процедуры HEX-печати байта

        LD      A,L           ;печать младшего байта числа

PHEX_B  ;Печать шестнадцатеричного числа в A3 (00..FF)

        CALL    PHEX_HB       ;печать по полубайтам

PHEX_HB ;Печать старшего полубайта в A3 (0..F)

        RRCA                  ;меняем

        RRCA                  ; местами

        RRCA                  ; старший

        RRCA                  ; и младший полубайты

PHEX_LB ;Печать младшего полубайта в A3 (0..F)

        PUSH    AF            ;сохранили A на стеке

        AND     #0F           ;отбросили лишние старшие биты

        CP      #0A           ;если A<10,

        JR      C,GO_PHL      ; то перепрыгнули

        ADD     A,"A"-"9"-1   ;корректировка: после "9" идет "A"

GO_PHL  ADD     A,"0"         ;перевод в ASCII-код

        RST     #10           ;печать HEX-цифры ("0".."F")

        POP     AF            ;восстановили A со стека

        RET                   ;выход из процедуры




;--- print in BIN system ---

PBIN_W  ;Печать двоичного числа в HL (16 разрядов 0/1)

        LD      A,H           ;печать старшего байта числа

        CALL    PBIN_B        ;вызов процедуры BIN-печати байта

        LD      A,L           ;печать младшего байта числа

PBIN_B  ;Печать двоичного числа в A (8 разрядов 0/1)

        LD      B,#08         ;в байте - 8 битов

LP_PBB  RLCA                  ;поочередно 'выдвигаем' биты в CF

        PUSH    AF            ;сохранить A на стеке

        LD      A,#18         ;в зависимости от флага C:

        RLA                   ; A="0" или A="1"

        RST     #10           ;печать очередного бита

        POP     AF            ;восстановить A со стека

        DJNZ    LP_PBB        ;поразрядный цикл

        RET                   ;выход из процедуры

;



Listing 1. Процедура печати байта в десятичной системе.

PDEC_B  ;Печать десятичного числа в аккумуляторе3 (000..255)

        LD      HL,DECTB_B    ;адрес таблицы степеней десятки

        LD      B,#03         ;макс. возможное количество цифр

LP_PDB1 LD      C,"0"-1       ;инициализация счетчика

LP_PDB2 INC     C             ;увеличиваем счетчик

        SUB     (HL)          ;вычитаем текущую степень десятки

        JR      NC,LP_PDB2    ;повторять, пока A>=0

        ADD     A,(HL)        ;A=A mod (HL); C=STR$(A div (HL))

        PUSH    AF            ;сохранить A на стеке

        LD      A,C           ;текущая цифра

        RST     #10           ;печать цифры

        POP     AF            ;восстановление аккумулятора

        INC     HL            ;переход к след. степени десятки

        DJNZ    LP_PDB1       ;закрутили цикл по цифрам

        RET                   ;выход из процедуры

DECTB_B DB      100,10,1      ;Таблица степеней3 10-ки для byte





;--------------------------------------------------------------;

;     Printing in Different Evaluation Systems LIBrary v2.0    ;

;          (c) SerzhSoft, Shadrinsk, august, 1997              ;

;--------------------------------------------------------------;

_NULL   EQU     0   ;используется в изменяемых командах

;--------------------------------------------------------------;

;                   print in DEC system:                       ;

;--------------------------------------------------------------;

PDEC_3B ;Печать десятичного числа в AHL (00000000..16777215)

        LD      DE,34464      ;DE=100000-65536

        LD      BC,#FF01      ;B=-1 - счетчик сотен тысяч; C=1

LP_PD31 INC     B             ;увеличиваем счетчик сотен тысяч

        AND     A             ;сбpасываем флаг пеpеноса для SUB

        SBC     HL,DE         ;уменьшаем тpехбайтное число AHL

        SBC     A,C           ; на одну сотню тысяч

        JR      NC,LP_PD31    ;повтоpяем пока нет пеpеполнения

        ADD     HL,DE         ;восстанавливаем положительное

        ADC     A,C           ; значение у AHL; AHL<100000

        PUSH    AF            ;сохpаняем на стеке нужные нам

        PUSH    HL            ; впоследствии pегистpы A, HL

        LD      A,B           ;количество сотен тысяч в числе

        CALL    PDEC_B        ;печатаем это значение

        POP     HL            ;восстанавливаем со стека

        POP     AF            ; pегистpы A, HL

        DEC     A             ;если остаток<65536,

        JR      NZ,PDEC_W     ; то пеpеходим на печать 0..65535

        LD      DE,5536       ;иначе - число 65536..99999

        ADD     HL,DE         ;пpибавляем остаток от десятков

        ADC     A,6           ; тысяч, и их сами - отдельно

        PUSH    HL            ;---------------------------------

        LD      HL,DECTB_W    ; Обходимый фpагмент пp-pы PDEC_W

        LD      B,#05         ;---------------------------------

        JR      LP_PDW1+1     ;пpыжок чеpез обнуление дес. тысяч

;--------------------------------------------------------------;

PDEC_B  ;Печать десятичного числа в A (000..255)

        LD      L,A           ;поместили

        LD      H,#00         ; число в HL

        PUSH    HL            ;закинули печатаемое число на стек

        LD      HL,DECTB_W+4  ;адрес в таблице, начиная с сотни

        LD      B,#03         ;макс. возможное кол-во цифр - три

        JR      LP_PDW1       ;переход на цикл печати

;--------------------------------------------------------------;

PDEC_W  ;Печать десятичного числа в HL (00000..65535)

        PUSH    HL            ;закинули печатаемое число на стек

        LD      HL,DECTB_W    ;адрес таблицы степеней десятки

        LD      B,#05         ;макс. возможное количество цифр

LP_PDW1 XOR     A             ;обнулили счетчик и флаг C для SBC

        LD      E,(HL)        ;взяли текущую степень

        INC     HL            ; десятки из таблицы

        LD      D,(HL)        ; и поместили в DE

        INC     HL            ;перешли к след. элементу таблицы

        EX      (SP),HL       ;адрес эл-та <-> печатаемое число

LP_PDW2 INC     A             ;увеличиваем счетчик

        SBC     HL,DE         ;вычитаем текущую степень десятки

        JR      NC,LP_PDW2    ;повторяем пока HL>=0

        ADD     HL,DE         ;HL=HL mod DE; A=HL div DE

        ADD     A,"0"-1       ;перевод A в ASCII-код ("0".."9")

        RST     #10           ;печать десятичной цифры

        EX      (SP),HL       ;HL=адрес эл-та, число -> на стек

        DJNZ    LP_PDW1       ;цикл по цифрам

        POP     HL            ;убрали оставшийся ноль со стека

        RET                   ;выход из процедуры

;--------------------------------------------------------------;

DECTB_W DW      10000,1000,100,10,1  ;Таблица степеней десятки ;

;--------------------------------------------------------------;

;                   print in HEX system:                       ;

;--------------------------------------------------------------;

PHEX_W  ;Печать шестнадцатеричного числа в HL (0000..FFFF)

        LD      A,H           ;печать старшего байта числа

        CALL    PHEX_B        ;вызов процедуры HEX-печати байта

        LD      A,L           ;печать младшего байта числа

;--------------------------------------------------------------;

PHEX_B  ;Печать шестнадцатеричного числа в A (00..FF)

        CALL    PHEX_HB       ;печать по полубайтам

;--------------------------------------------------------------;

PHEX_HB ;Печать старшего полубайта в A (0..F)

        RRCA                  ;меняем

        RRCA                  ; местами

        RRCA                  ; старший

        RRCA                  ; и младший полубайты

;--------------------------------------------------------------;

PHEX_LB ;Печать младшего полубайта в A (0..F)

        PUSH    AF            ;сохранили A на стеке

        AND     #0F           ;отбросили лишние старшие биты

        CP      #0A           ;если A<10,

        JR      C,GO_PHL      ; то перепрыгнули

        ADD     A,"A"-"9"-1   ;корректировка: после "9" идет "A"

GO_PHL  ADD     A,"0"         ;перевод в ASCII-код

        RST     #10           ;печать HEX-цифры ("0".."F")

        POP     AF            ;восстановили A со стека

        RET                   ;выход из процедуры

;--------------------------------------------------------------;

;                    print in BIN system:                      ;

;--------------------------------------------------------------;

PBIN_W  ;Печать двоичного числа в HL (16 разрядов 0/1)

        LD      A,H           ;печать старшего байта числа

        CALL    PBIN_B        ;вызов процедуры BIN-печати байта

        LD      A,L           ;печать младшего байта числа

;--------------------------------------------------------------;

PBIN_B  ;Печать двоичного числа в A (8 разрядов 0/1)

        LD      B,#08         ;в байте - 8 битов

LP_PBB  RLCA                  ;поочередно 'выдвигаем' биты в CF

        PUSH    AF            ;сохранить A на стеке

        LD      A,#18         ;в зависимости от флага C:

        RLA                   ; A="0" или A="1"

        RST     #10           ;печать очередного бита

        POP     AF            ;восстановить A со стека

        DJNZ    LP_PBB        ;поразрядный цикл

        RET                   ;выход из процедуры

;--------------------------------------------------------------;

;                   print in USER system:                      ;

;--------------------------------------------------------------;

PUSE_W  ;Печать числа в установленной MKUSETB системе сч-я в HL

        PUSH    HL            ;закинули печатаемое число на стек

HL_PUW  LD      HL,_NULL      ;адрес конца таблицы степеней

LP_PUW1 DEC     HL            ;загружаем в DE очередную

        LD      D,(HL)        ; степень числа

        DEC     HL            ; из таблицы,

        LD      E,(HL)        ; двигаясь 'сверху-вниз'

        EX      (SP),HL       ;адрес таблицы <-> печат-е число

        XOR     A             ;обнуление A и сброс флага C

LP_PUW2 INC     A             ;вычисляем очередной

        SBC     HL,DE         ; разряд числа и результат

        JR      NC,LP_PUW2    ; помещаем в A (A=1+(HL div DE))

        ADD     HL,DE         ;восстанавливаем (+) значение

        ADD     A,"0"-1       ;переводим A в ASCII-код

        CP      "9"+1         ;если код меньше "9",

        JR      C,GO_PUW1     ; то переход на печать

        ADD     A,"A"-"9"-1   ;коррекция (после "9" идет "A")

GO_PUW1 RST     #10           ;печать очередной цифры числа

        EX      (SP),HL       ;HL=адрес таблицы, число -> стек

        DEC     DE            ;если степень

        LD      A,D           ; числа не равна единице

        OR      E             ; (самый первый элемент таблицы),

        JR      NZ,LP_PUW1    ; то продолжаем работу

        POP     HL            ;убираем со стека ненужный 0

        RET                   ;выход из процедуры

;--------------------------------------------------------------;

MKUSETB ;Создание таблицы степеней с основанием в A

        LD      HL,USE_TBL    ;адрес создаваемой таблицы

        LD      DE,#0001      ;инициализация счетчика степени

LP_MUT1 LD      (HL),E        ;запись текущего

        INC     HL            ; значения степени

        LD      (HL),D        ; в таблицу и переход

        INC     HL            ; к ее следующей ячейке

        PUSH    HL            ;сохраняем адрес на стеке

        LD      B,A           ;осн-е степени -> в счетчик цикла

        LD      HL,#0000      ;обнуление результата

LP_MUT2 ADD     HL,DE         ;подсчитываем результат

        JR      C,GO_MUT      ;если HL>65535, то прерываем счет

        DJNZ    LP_MUT2       ;повторяем <основание> раз

        EX      DE,HL         ;результат -> в DE (новая степень)

GO_MUT  POP     HL            ;восстанавливаем адрес таблицы

        JR      NC,LP_MUT1    ;если не прерывались, то повторяем

        LD      (HL_PUW+1),HL ;адрес конца таблицы -> в PUSE_W

        RET                   ;выход из процедуры

;--------------------------------------------------------------;

USE_TBL DS      32   ;Таблица степеней текущей системы счисления

;--------------------------------------------------------------;

;                    print in RIM system:                      ;

;--------------------------------------------------------------;

PRIM_B  ;Печать числа в римской записи в A (I..CCLV)

        LD      L,A           ;скопировать

        LD      H,#00         ; A в HL

;--------------------------------------------------------------;

PRIM_W  ;Печать числа в римской записи в HL (I..MMMCMXCIX)

        PUSH    HL            ;закинули печатаемое число на стек

        LD      HL,RIM_TBL    ;адрес таблицы знаков

        DB      #DD           ;работаем с половинкой регистра IX

        LD      L,#07         ;LD XL,число знаков в р. счислении

LP_PRW1 LD      E,(HL)        ;считываем из таблицы значение

        INC     HL            ; очередного знака римской системы

        LD      D,(HL)        ; счисления и помещаем в DE

        INC     HL            ;затем в регистр C считываем

        LD      C,(HL)        ; ASCII-код знака

        INC     HL            ;переход к следующему знаку

        LD      (HL_PRW+1),HL ;сохранили адрес следующего знака

        EX      (SP),HL       ;адрес -> на стек, HL=печат. число

        XOR     A             ;обнуление счетчика и сброс CF

LP_PRW2 INC     A             ;в цикле производим

        SBC     HL,DE         ; деление HL на DE (вычитаем,

        JR      NC,LP_PRW2    ; пока нет переполнения)

        ADD     HL,DE         ;восстанавливаем (+) значение

        DEC     A             ;т.к. A на 1 больше  HL div DE,

        JR      Z,GO_PRW1     ; то если A=1 - ничего не печатаем

        LD      B,A           ;количество печатаемых символов

LP_PRW3 LD      A,C           ;код знака

        RST     #10           ;печатаем его

        DJNZ    LP_PRW3       ;сколько надо - столько и печатаем

GO_PRW1 DB      #DD           ;работаем с половинкой регистра IX

        LD      A,L           ;LD A,XL - номер текущего знака

        DEC     A             ;если это последний знак (I), то

        JR      Z,GO_PRW4     ; двухбуквенного сочетания нет

        EX      (SP),HL       ;HL=адрес след. знака, число->стек

        RRA                   ;если номер текущего знака четный,

        JR      C,GO_PRW2     ; то сочетание с следующим знаком

        INC     HL            ;иначе - перепрыгнуть через один

        INC     HL            ; знак. В результате получим адрес

        INC     HL            ; знака, для получения двойного

GO_PRW2 LD      A,C           ; знакосочетания (IV,CM,XL...)

        LD      C,(HL)        ;взяли из таблицы значение для

        INC     HL            ; этого знака и получили

        LD      B,(HL)        ; разность между значением

        INC     HL            ; основного и этим значением.

        EX      DE,HL         ; Например, для основного знака X

        AND     A             ; дополнительным будет I, а их

        SBC     HL,BC         ; разность соответственно:

        EX      DE,HL         ; 10-1=9, т.е. IX

        LD      C,A           ;код основного знака

        LD      A,(HL)        ;код дополнительного знака

        EX      (SP),HL       ;HL=печатаемое число

        SBC     HL,DE         ;если оно < дополнительного

        JR      C,GO_PRW3     ; значения, то не печатаем

        RST     #10           ;печать дополнительного знака

        LD      A,C           ;основной знак

        RST     #10           ;печать

        JR      GO_PRW4       ;результат - двухбукв. сочетание

GO_PRW3 ADD     HL,DE         ;восстановили (+) у числа

GO_PRW4 EX      (SP),HL       ;число -> на стек

HL_PRW  LD      HL,_NULL      ;адрес следующего знака в таблице

        DB      #DD           ;работаем с половинкой регистра IX

        DEC     L             ;DEC XL - уменьшаем счетчик знаков

        JR      NZ,LP_PRW1    ;крутим цикл, пока есть еще знаки

        POP     HL            ;сняли ненужный уже ноль со стека

        RET                   ;выход из процедуры

;--------------------------------------------------------------;

RIM_TBL ;Таблица значимости букв в написании римских чисел

        DW      1000

        DB      "M"           ;M=1000 ;CM=900

        DW      500

        DB      "D"           ;D=500  ;CD=400

        DW      100

        DB      "C"           ;C=100  ;XC=90

        DW      50

        DB      "L"           ;L=50   ;XL=40

        DW      10

        DB      "X"           ;X=10   ;IX=9

        DW      5

        DB      "V"           ;V=5    ;IV=4

        DW      1

        DB      "I"           ;I=1    ;-nop-

;--------------------------------------------------------------;

;                  end of PDES LIB 2.0                         ;

;--------------------------------------------------------------;







Эта программа распечатывает двухбайтовое

шестнадцатиричное

число   (#0000...#FFFF),  

которое задается в регистре HL на входе в

процедуру. Печать выполняется при 

помощи RST 16,  поэтому перед  ее

использованием должен быть открыт 

канал печати

(для экрана: LD A,2:CALL #1601)

PRH LD   C,#04       

PH0 LD   B,#04       

XOR  A           

PH1 RL   L           

RL   H           

RLA              

DJNZ PH1         

CP   #0A         

JR   C,PH2       

ADD  A,#07       

PH2    ADD  A,#30       

RST  16          

DEC  C           

JR   NZ,PH0      

RET     



As this is one of the most typical tasks, 

why not to do it tricky way? 

The code snippet here takes a byte from (HL) and prints it. 

Note that it uses another (shorter) DAA trick as we know that 

Half Carry is cleared before DAA. 

Input: HL = address of data ; Output: memory dump 

Note: You'll have to replace the PRINT_CHAR macro by actual 

platform-specific code. 

Don't forget to preserve the contents of HL! 

xor a

rld

call Nibble

Nibble push af

daa

add a,F0h

adc a,40h


PRINT_CHAR ; prints ASCII character in A


pop af

rld

ret






; Convert single byte in A to two Ascii characters in B and C

TO_HEX  LD   B,A                ; Save the byte original value

AND  $0F        ; Strip off the high order nybble

CP   $0A        ; 0-9 at this point?

JR   C,TOHX01   ; We only need to add $30 then, or

ADD  A,$07      ; Seven more if it's in the A-F range

TOHX01  ADD  A,$30              ; Take the value on up to ASCII

LD   C,A        ; Store the converted lo order character to C

LD   A,B        ; Get the original value back

RRCA            ; Rotate it to the right

RRCA

RRCA

RRCA

AND  $0F        ; Mask off the upper trash

CP   $0A        ; 0-9 (< $0A)?

JR   C,TOHX02   ; Only add $30 then

ADD  A,$07      ; And add it 7 if it's in the A-F range

TOHX02  ADD  A,$30              ; Finish the conversion to ASCII

LD   B,A              ; Load the finished hi order character to B

RET





;Number in hl to decimal ASCII

;Thanks to z80 Bits

;inputs: hl = number to ASCII

;example: hl=300 outputs '00300'

;destroys: af, bc, hl, de used

DispHL ld bc,-10000

call Num1

ld bc,-1000

call Num1

ld bc,-100

call Num1

ld c,-10

call Num1

ld c,-1

Num1: ld a,'0'-1

Num2: inc a

add hl,bc

jr c,Num2

sbc hl,bc

call prt

ret 

;adaptable for a DispA routine 

or any other 8-bit register

DispA ld h,0

ld l,a

jp DispHL




;Display a 16- or 8-bit number in hex.

DispHLhex:

; Input: HL

   ld  c,h

   call  OutHex8

   ld  c,l

OutHex8:

; Input: C

   ld  a,c

   rra

   rra

   rra

   rra

   call  Conv

   ld  a,c

Conv:

   and  $0F

   add  a,$90

   daa

   adc  a,$40

   daa

   call prt

   ret

 







;ASCII to DEC

;HL-адрес числа

;Выход:DE-число

        LD HL,TXT

        CALL MakeNumber

        RET 

MakeNumber

        LD DE,0

MkNum1  LD A,(HL)

        CALL isdigit

        RET NC

        EX DE,HL

        ADD HL,HL

        LD B,H

        LD C,L

        ADD HL,HL

        ADD HL,HL

        ADD HL,BC

        LD B,0

        SUB "0"

        LD C,A

        ADD HL,BC

        EX DE,HL

        INC HL

        JR MkNum1

isdigit CP      "0"

        CCF 

        RET     NC

        CP      "9"+1

        RET 

TXT     DB "768QWEIUSO"




Hexadecimal conversion operates directly 

on nibbles and takes advantage of nifty DAA trick. 

Input: 

HL = number to convert, 

DE = location of ASCII string 

Output: 

ASCII string at (DE) 

Num2Hex ld a,h

call Num1

ld a,h

call Num2

ld a,l

call Num1

ld a,l

jr Num2

Num1 rra

rra

rra

rra

Num2 or F0h

daa

add a,A0h

adc a,40h

ld (de),a

inc de

ret






NUMBUFF DEFB "00000"

A2DEC8 ld hl,NUMBUFF

ld (hl),#2f

inc (hl)

sub 100

jr nc,$-3

add a,100

inc hl

ld (hl),#2f

inc (hl)

sub 10

jr nc,$-3

add a,10

inc hl

add a,"0"

ld (hl),a

ret





;Write a Hex number in BCHL, CHL, HL or A 

;to memory at DE.

sphex8: ld a,b;Big multidecker fall-through...

call sphex2

sphex6: ld a,c

call sphex2

sphex4: ld      a,h

        call    sphex2

        ld      a,l

sphex2: push    af

        rrca

        rrca

        rrca

        rrca

        call    sphex1

        pop     af

sphex1: and     0fh

        cp      0ah

        jr      c,sph1a

        add     a,7

sph1a:  add     a,'0'

        ld      (de),a

        inc     de

        ret







;Write decimal numbers in HL to memory at DE

cphlbc: push hl

and a

sbc hl,bc

pop hl

ret

spdec: ld bc,10000

call cphlbc

jr nc,spdec5

ld bc,1000

call cphlbc

jr nc,spdec4

ld bc,100

call cphlbc

jr nc,spdec3

ld a,l

cp 10

jr nc,spdec2 ;>=10

jr spdec1

spdec5: ld bc,10000

call dodec

spdec4: ld bc,1000

call dodec

spdec3: ld bc,100

call dodec

spdec2: ld bc,10

call dodec

spdec1: ld a,l

add a,'0'

ld (de),a

inc de

ret

dodec: ld a,'0'

ddlp: inc a

and a

sbc hl,bc

jr nc,ddlp

dec a

add hl,bc

ld (de),a

inc de

ret

;






;by GRAND, 1999 

;Печ.числа (0...65535) 

;с незн нулями 

;Вх.: HL - число.

PR16D XOR A

  LD DE,10000

  SBC HL,DE

  INC A

  JR NC,$-3

  ADD A,"0"-1

CALL PRINTA

  ADD HL,DE

  XOR A

LD DE,1000

SBC HL,DE

  INC A

  JR NC,$-3

  ADD A,"0"-1

  CALL PRINTA

  ADD HL,DE

;Печ.числа (0...255) с незн нулями

;Вх.: HL - число.

PR8D XOR A

LD DE,100

SBC HL,DE

INC A

JR NC,$-3

ADD A,"0"-1

CALL PRINTA

ADD HL,DE

;Печ.числа (0...99) с незн нулями

;Вх.: HL - число.

LD A,L

LD B,"0"-1

INC B

SUB 10

JR NC,$-3

ADD A,"0"+10

LD C,A

LD A,B

CALL PRINTA

LD A,C

PRINTA.....print proc here




; Routine for converting a 24-bit binary number to decimal

; In: E:HL = 24-bit binary number (0-16777215)

; Out: DE:HL = 8 digit decimal form (packed BCD)

; Changes: AF, BC, DE, HL & IX

; by Alwin Henseler

                 LD C,E

                 PUSH HL

                 POP IX          ; input value in C:IX

                 LD HL,1

                 LD D,H

                 LD E,H          ; start value corresponding with 1st 1-bit

                 LD B,24         ; bitnr. being processed + 1

FIND1:           ADD IX,IX

                 RL C            ; shift bit 23-0 from C:IX into carry

                 JR C,NEXTBIT

                 DJNZ FIND1      ; find highest 1-bit

; All bits 0:

                 RES 0,L         ; least significant bit not 1 after all ..

                 RET

DBLLOOP:         LD A,L

                 ADD A,A

                 DAA

                 LD L,A

                 LD A,H

                 ADC A,A

                 DAA

                 LD H,A

                 LD A,E

                 ADC A,A

                 DAA

                 LD E,A

                 LD A,D

                 ADC A,A

                 DAA

                 LD D,A          ; double the value found so far

                 ADD IX,IX

                 RL C            ; shift next bit from C:IX into carry

                 JR NC,NEXTBIT   ; bit = 0 -> don't add 1 to the number

                 SET 0,L         ; bit = 1 -> add 1 to the number

NEXTBIT:         DJNZ DBLLOOP

                 RET




ПРЕОБРАЗОВАНИЕ ДВОИЧНОГО ЧИСЛА В ДВОИЧНО-ДЕСЯТИЧНОЕ.

   Для  отображения  результатов вычислений   необходимо числа

привести в  удобный  для  вывода вид, т.е. преобразовать число  в

десятичный код. Например, двоичное число 00001111 (#0F)  удобно

представить  в  виде  0001  0101(#15), т.е. преобразовать его  в

двоично-десятичную  форму.  Этим занимается следующая подпрограмма.

; BCD2B- подпрограмма перевода 2-х байтного числа.

; Двоичное число должно быть в регистре 'HL'.

; Результат :

;           в 'A' - десятки тысяч;

;           в 'B' - тысячи и сотни;

;           в 'C' - десятки и единицы.

; Во время работы вызывается процедура CONV из

; подпрограммы BCD1B - перевод однобайтного числа,

; в которой;

; в 'H' - число для перевода , 'L'=0

; Результат работы: в 'A' - разряды сотен;

;                   в 'B' - десятки и единицы

; Вход в процедуру преобразования 2-х байтного числа:

BCD2B   LD E,17     ; счетчик 1-го цикла

        CALL CONV   ; вычислить младший BCD байт

        LD C,A      ; сохранить в 'C'

        LD E,17     ; счетчик 2-го цикла

        JR PRODOL   ; переход на вычисление

; процедура для преобразования 1-байтного числа

BCD1B   LD E,9      ; цикл для 1-байтного числа

PRODOL  CALL CONV   ; вычислить два старших байта

        LD B,A      ; сохранить средний байт

        LD A,L      ; старший байт

        RET         ; выйти вообще

;-----

CONV    XOR A       ; очистить

SBIT    DEC E       ; уменьшим счетчик цикла

        RET Z       ; цикл весь - выйти

        ADD HL,HL   ; сдвинем старшие разряды в перенос

        ADC A,A

        DAA         ; скорректируем

        JR NC,SBIT  ; результат больше 99 ?

        INC HL      ; да - увеличим на 1

        JR SBIT     ; вернемся в вычисления




from PENTIS by Tony Raugas print DEC

print_digits    exx

                ld      hl, txt_00000

                ld      b, 5

prd1            ld      (hl), #30

                inc     hl

                djnz    prd1

                exx

                ld      b, #10

prd2            exx

                ld      hl,  txt_00000+4

                ld      bc, #500

prd3            ld      a, (hl)

                add     a, a

                add     a, c

                sub     #30 

                cp      #3A 

                jr      c, prd4

                sub     #A

                ld      c, 1

                jr      prd5

prd4            ld      c, 0

prd5            ld      (hl), a

                dec     hl

                djnz    prd3

                exx

                add     hl, hl

                exx

                jr      nc, prd7

                ld      hl,  txt_00000+4

                ld      b, 5

prd6            ld      a, (hl)

                inc     a

                ld      (hl), a

                cp      #3A

                jr      c, prd7

                ld      (hl), #30

                dec     hl

                djnz    prd6

prd7            exx

                djnz    prd2

                ld      hl, txt_00000

jp prtpz

txt_00000       db "00000",0





Печать десятичных чисел без нуля. 59 байт. print DEC w/o zeros

        LD IX,Буфер 5 байт

        LD HL,Число

        LD BC,0

        LD DE,0-10000

        CALL num

        LD DE,0-1000

        CALL num

        LD DE,0-100

        CALL num

        LD DE,0-10

        CALL num

        LD A,L

        JR num2

num       ADD HL,DE

        INC B

        JR C,$-2

        DEC B

        SBC HL,DE

        LD A,B

        OR C

        RET Z

        LD C,A

        LD A,B

num2    ADD A,48

        LD (IX),A

        INC IX

        LD B,0

        RET





CISLO           ld      de,-10000       ;rad desetitisicu

                call    CIFRA

                ld      de,-1000        ;rad tisicu

                call    CIFRA

                ld      de,-100         ;rad stovek

                call    CIFRA

                ld      de,-10          ;rad desitek

                call    CIFRA

                ld      de,-1           ;rad jednicek

CIFRA           ld      a,'0'-1         ;do A znak 0 zmenseny o 1

CIFRA1          add     hl,de           ;pricti zaporny rad

                inc     a               ;zvys pocitadlo

                jr      c,CIFRA1        ;jeste jsme jej neprekrocili

                sbc     hl,de           ;pokud ano, oprav cislo

          ;      call    ZNAK            ;a vytiskni pocitadlo

                ret






NUM2DEC:        ld      e,' '

                ld      bc,-10000

                call    NUM1

                ld      bc,-1000

                call    NUM1

                ld      bc,-100

                call    NUM1

                ld      c,-10

                call    NUM1

                ld      e,'0'

                ld      c,b

NUM1:           ld      a,'0'-1

NUM2:           inc     a

                add     hl,bc

                jr      c,NUM2

                sbc     hl,bc

                cp      '0'

                jr      nz,NUM4

                ld      a,e

NUM3:           jp      ZNAK2

NUM4:           ld      e,'0'

                jr      NUM3




Input: HL = number to convert, DE = location of ASCII string

Output: ASCII string at (DE) ; Num2Dec ld bc,-10000

call Num1

ld bc,-1000

call Num1

ld bc,-100

call Num1

ld c,-10

call Num1

ld c,b

Num1 ld a,'0'-1

Num2 inc a

add hl,bc

jr c,Num2

sbc hl,bc

ld (de),a

inc de

ret







;in: HL

DECWORD LD      IY,DECWTAB

        XOR     A

        LD      B,4

DECW3   LD      E,(IY)

        INC     IY

        LD      D,(IY)

        INC     IY

DECW2   OR      A

        SBC     HL,DE

        JR      C,DECW1

        INC     A

        JR      DECW2

DECW1   ADD     HL,DE

        CALL    DECWPC

        DJNZ    DECW3

        LD      A,L

        OR      A,#30

        JR      PRCHAR

DECWPC  OR      A

        RET     Z

        PUSH    HL

        PUSH    BC

        OR      #30

        CALL    PRCHAR

        LD      A,#30

        POP     BC

        POP     HL

        RET

DECWTAB DEFW    10000,1000,100,10



;in:    HL

HEXWORD PUSH    HL

        LD      A,H

        CALL    HEXBYTE

        POP     HL

        LD      A,L

;in:    A

HEXBYTE PUSH    AF

        RRCA

        RRCA

        RRCA

        RRCA

        CALL    HEXHALF

        POP     AF

HEXHALF AND     #0F

        CP      #0A

        JR      C,HEXH1

        ADD     A,#07

HEXH1   ADD     A,#30

;  CALL PRCHAR




; Convert HEX ASCII characters in B C registers to a byte value in A

HEX2BIN LD   A,B                ; Move the hi order byte to A

SUB  $30                ; Take it down from Ascii

CP   $0A                ; Are we in the 0-9 range here?

JR   C,HX2B01           ; If so, get the next nybble

SUB  $07                ; But if A-F, take it down some more

HX2B01  RLCA                    ; Rotate the nybble from low to high

RLCA                    ; One bit at a time

RLCA                    ; Until we

RLCA                    ; Get there with it

LD   B,A                ; Save the converted high nybble

LD   A,C                ; Now get the low order byte

SUB  $30                ; Convert it down from Ascii

CP   $0A                ; 0-9 at this point?

JR   C,HX2B02           ; Good enough then, but

SUB  $07                ; Take off 7 more if it's A-F

HX2B02  ADD  A,B                ; Add in the high order nybble

RET


; Convert single byte in A to two Ascii characters in B and C

TO_HEX  LD   B,A                ; Save the byte original value

AND  $0F                ; Strip off the high order nybble

CP   $0A                ; 0-9 at this point?

JR   C,TOHX01           ; We only need to add $30 then, or

ADD  A,$07              ; Seven more if it's in the A-F range

TOHX01  ADD  A,$30              ; Take the value on up to ASCII

LD   C,A                ; Store the converted lo order character to C

LD   A,B                ; Get the original value back

RRCA                    ; Rotate it to the right

RRCA

RRCA

RRCA

AND  $0F                ; Mask off the upper trash

CP   $0A                ; 0-9 (< $0A)?

JR   C,TOHX02           ; Only add $30 then

ADD  A,$07              ; And add it 7 if it's in the A-F range

TOHX02  ADD  A,$30              ; Finish the conversion to ASCII

LD   B,A                ; Load the finished hi order character to B

RET                     ;





;CLCN32 -> Converts 32Bit-Value in ASCII-String (terminated by 0)

;Input      DE,IX=32bit value, IY=destination address

;Output     IY=last char in destination string

;Destroyed AF,BC,DE,HL,IX

clcn32t dw 1,0,     10,0,     100,0,     1000,0,     10000,0

        dw #86a0,1, #4240,#f, #9680,#98, #e100,#5f5, #ca00,#3b9a

clcn32z ds 4

clcn32  ld (clcn32z),ix

        ld (clcn32z+2),de

        ld ix,clcn32t+36

        ld b,9

        ld c,0

clcn321 ld a,"0"

        or a

clcn322 ld e,(ix+0):ld d,(ix+1):ld hl,(clcn32z):  sbc hl,de:ld (clcn32z),hl

        ld e,(ix+2):ld d,(ix+3):ld hl,(clcn32z+2):sbc hl,de:ld (clcn32z+2),hl

        jr c,clcn325

        inc c

        inc a

        jr clcn322

clcn325 ld e,(ix+0):ld d,(ix+1):ld hl,(clcn32z):  add hl,de:ld (clcn32z),hl

        ld e,(ix+2):ld d,(ix+3):ld hl,(clcn32z+2):adc hl,de:ld (clcn32z+2),hl

        ld de,-4

        add ix,de

        inc c

        dec c

        jr z,clcn323

        ld (iy+0),a

        inc iy

clcn323 djnz clcn321

        ld a,(clcn32z)

        add "0"

        ld (iy+0),a

        ld (iy+1),0

        ret





; Combined routine for conversion of different sized binary numbers into

; directly printable ASCII(Z)-string

; Input value in registers, number size and -related to that- registers to fill

; is selected by calling the correct entry:

;  entry  inputregister(s)  decimal value 0 to:

;   B2D8             A                    255  (3 digits)

;   B2D16           HL                  65535   5   "

;   B2D24         E:HL               16777215   8   "

;   B2D32        DE:HL             4294967295  10   "

;   B2D48     BC:DE:HL        281474976710655  15   "

;   B2D64  IX:BC:DE:HL   18446744073709551615  20   "

; The resulting string is placed into a small buffer attached to this routine,

; this buffer needs no initialization and can be modified as desired.

; The number is aligned to the right, and leading 0's are replaced with spaces.

; On exit HL points to the first digit, (B)C = number of decimals

; This way any re-alignment / postprocessing is made easy.

; Changes: AF,BC,DE,HL,IX

; P.S. some examples below

; by Alwin Henseler

B2D8:    LD H,0

         LD L,A

B2D16:   LD E,0

B2D24:   LD D,0

B2D32:   LD BC,0

B2D48:   LD IX,0          ; zero all non-used bits

B2D64:   LD (B2DINV),HL

         LD (B2DINV+2),DE

         LD (B2DINV+4),BC

         LD (B2DINV+6),IX ; place full 64-bit input value in buffer

         LD HL,B2DBUF

         LD DE,B2DBUF+1

         LD (HL)," "

B2DFILC: EQU $-1         ; address of fill-character

         LD BC,18

         LDIR            ; fill 1st 19 bytes of buffer with spaces

         LD (B2DEND-1),BC ;set BCD value to "0" & place terminating 0

         LD E,1          ; no. of bytes in BCD value

         LD HL,B2DINV+8  ; (address MSB input)+1

         LD BC,#0909

         XOR A

B2DSKP0: DEC B

         JR Z,B2DSIZ     ; all 0: continue with postprocessing

         DEC HL

         OR (HL)         ; find first byte <>0

         JR Z,B2DSKP0

B2DFND1: DEC C

         RLA

         JR NC,B2DFND1   ; determine no. of most significant 1-bit

         RRA

         LD D,A          ; byte from binary input value

B2DLUS2: PUSH HL

         PUSH BC

B2DLUS1: LD HL,B2DEND-1  ; address LSB of BCD value

         LD B,E          ; current length of BCD value in bytes

         RL D            ; highest bit from input value -> carry

B2DLUS0: LD A,(HL)

         ADC A,A

         DAA

         LD (HL),A       ; double 1 BCD byte from intermediate result

         DEC HL

         DJNZ B2DLUS0    ; and go on to double entire BCD value (+carry!)

         JR NC,B2DNXT

         INC E           ; carry at MSB -> BCD value grew 1 byte larger

         LD (HL),1       ; initialize new MSB of BCD value

B2DNXT:  DEC C

         JR NZ,B2DLUS1   ; repeat for remaining bits from 1 input byte

         POP BC          ; no. of remaining bytes in input value

         LD C,8          ; reset bit-counter

         POP HL          ; pointer to byte from input value

         DEC HL

         LD D,(HL)       ; get next group of 8 bits

         DJNZ B2DLUS2    ; and repeat until last byte from input value

B2DSIZ:  LD HL,B2DEND    ; address of terminating 0

         LD C,E          ; size of BCD value in bytes

         OR A

         SBC HL,BC       ; calculate address of MSB BCD

         LD D,H

         LD E,L

         SBC HL,BC

         EX DE,HL        ; HL=address BCD value, DE=start of decimal value

         LD B,C          ; no. of bytes BCD

         SLA C           ; no. of bytes decimal (possibly 1 too high)

         LD A,"0"

         RLD             ; shift bits 4-7 of (HL) into bit 0-3 of A

         CP "0"          ; (HL) was > 9h?

         JR NZ,B2DEXPH   ; if yes, start with recording high digit

         DEC C           ; correct number of decimals

         INC DE          ; correct start address

         JR B2DEXPL      ; continue with converting low digit

B2DEXP:  RLD             ; shift high digit (HL) into low digit of A

B2DEXPH: LD (DE),A       ; record resulting ASCII-code

         INC DE

B2DEXPL: RLD

         LD (DE),A

         INC DE

         INC HL          ; next BCD-byte

         DJNZ B2DEXP     ; and go on to convert each BCD-byte into 2 ASCII

         SBC HL,BC       ; return with HL pointing to 1st decimal

         RET

B2DINV:  DS 8            ; space for 64-bit input value (LSB first)

B2DBUF:  DS 20           ; space for 20 decimal digits

B2DEND:  DS 1            ; space for terminating 0

         END


     EXAMPLES

(In these examples, it is assumed there exists a subroutine PRINT, that

prints a string (terminated by a 0-byte) starting at address [HL] )

Print 1 byte, as follows:

 20

  7

145  etc.

by:   LD A,byte

      CALL B2D8

      LD HL,B2DEND-3

      CALL PRINT

Print a 24-bit value, as follows:

9345

76856366

534331

by:   LD E,bit23-16

      LD HL,bit15-0

      CALL B2D24

      CALL PRINT

Print a 48-bit value, like

    14984366484

             49

123456789012345

        3155556 etc.

by:

      LD BC,bit47-32

      LD DE,bi