Login

Subversion Repositories NedoOS

Rev

Blame | Last modification | View Log | Download | RSS feed

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
;Arithmetic operations:
;
;neg* : Calculate 2's complement of a 16-bit register
;abs* : Ensure a 16-bit register is +ve
;
abshl:  bit     7,h
        ret     z
neghl:  push    af
        ld      a,h     ;To ones complement
        cpl
        ld      h,a
        ld      a,l
        cpl
        ld      l,a
        inc     hl      ;To twos complement
        pop     af
        ret
;
absde:  bit     7,d
        ret     z
negde:  push    af
        ld      a,d     ;To ones complement
        cpl
        ld      d,a
        ld      a,e
        cpl
        ld      e,a
        inc     de      ;To twos complement
        pop     af
        ret
;
absbc:  bit     7,b
        ret     z
negbc:  push    af
        ld      a,b     ;To ones complement
        cpl
        ld      b,a
        ld      a,c
        cpl
        ld      c,a
        inc     bc      ;To twos complement
        pop     af
        ret
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
;Signed 16-bit comparison
;
cpsign:
;
;IF HL < DE, return Carry set. IF HL >= DE, return Carry clear. IF HL=DE
;return Zero set.
;
;Check if one is -ve and the other positive
;
        ld      a,h
        xor     d       ;IF the sign bits were different, bit 7 of A is set
        bit     7,a
        jr      nz,dsign
;
;Signs are the same.
;
; << v1.01 Do not reverse the comparison if both values are negative.
;         (In 2s-complement, 0FFFFh (-1) > 0FFFDh (-3) )
;
;        So just fall through to the unsigned comparison.
; >>
;
cphlde:
cpusgn: ld      a,h
        cp      d
        ret     nz
        ld      a,l
        cp      e
        ret
;
cpdebc: ld      a,d
        cp      b
        ret     nz
        ld      a,e
        cp      c
        ret
;
dsign:  bit     7,h     ;Is HL the negative one?
        scf
        ret     nz      ;IF so, HL < DE. Return NZ C
ncnz:   xor     a
        inc     a       ;Force NZ
        ret             ;Otherwise, HL >= DE. Return NZ NC
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
;Signed 16-bit multiplication, BC * DE -> DE
;
mult16: push    af
        push    bc
        push    hl
        call    m16w
        pop     hl
        pop     bc
        pop     af
        ret
;
m16w:   ld      a,b
        xor     d
        bit     7,a     ;Negative * positive
        jr      nz,mixmult
        call    absde
        call    absbc
        jr      umult16
;
mixmult:
        call    absde
        call    absbc
        call    umult16
        jp      negde
;
;Unsigned 16-bit multiplication, HLDE := BC * DE
;
umult16:
        ld      hl,0
        ld      a,16    ;16-bit multiplication
umulta: bit     0,e
        jr      z,umultb
        add     hl,bc
umultb: srl     h
        rr      l
        rr      d
        rr      e
        dec     a
        jr      nz,umulta
        ret
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
;Compute BC mod DE, returns result in HL.
;
smod16: push    de
        push    bc
        call    mo16w
        pop     bc
        pop     de
        ret
;
mo16w:  call    absde   ;a mod (-b) == a mod b
        bit     7,b     ;(-a) mod b == - (a mod b)
        jr      z,udiv16
        call    absbc
        call    udiv16
        jp      neghl

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
;Divide BC by DE, returns result in BC.
;
sdiv16: push    de
        push    hl
        call    d16w
        pop     hl
        pop     de
        ret
;
d16w:   ld      a,b             ;Same sign, or opposite signs?
        xor     d
        bit     7,a
        jr      nz,mixdiv
        call    absde
        call    absbc
        jr      udiv16

mixdiv: call    absde
        call    absbc
        call    udiv16
        ret     nc
        call    negbc
        scf
        ret
;
udiv16: ld      a,d     ;Divides BC by DE. Gives result in BC, remainder in HL.
        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
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;<< v0.03 overhauled
;
;
;Random number generator...
;
rmode:  defb    0       ;0: pseudo-random  1:counting 1-n
rseed:  defw    0
rlast:  defw    0
;
;Seed with a randomish number
;
srandr: call    ZXRNDI  ;Get some randomish number
        ld      a,r
        xor     d
        ld      d,a     ;DE = randomish number
        ld      (rseed),de
        xor     a
        ld      (rmode),a
        ld      (rlast),de
        ret
;
;Seed with a fixed number (-HL)
;
srand:  call    abshl
        ld      (rseed),hl
        ld      de,1000
        call    cphlde
        ld      a,1
        jr      c,srand1
        inc     a
srand1: ld      (rmode),a
        ld      hl,0
        ld      (rlast),hl
        ret
;
random: bit     7,h             ;IF HL negative, set predictable mode
        jr      nz,srand        ;
        ld      a,h             ;IF HL 0, seed from random number
        or      l
        jr      z,srandr
        ld      a,(rmode)       ;Mode 1: Generate random number by stepping
        dec     a
        jr      z,steprnd
;
;Conventional pseudo-random-number generator
;
;Using the algorithm: ADD 1; multiply by 75; extract MOD 65537; subtract 1
;                     and 32-bit arithmetic
;
        push    hl              ;HL = max value (0 < result <= HL)
        ld      hl,(rseed)
pred0:  ld      de,0            ;DEHL = value
;
;ADD 1 to DEHL.
;
        inc     hl
        ld      a,h
        or      l
        jr      nz,pred1
        inc     de
pred1:
;
;Multiply by 75. 75 = 64+8+2+1...
;
        push    de
        push    hl      ;1xDEHL
        call    dblhde  ;*2
        push    de
        push    hl      ;2xDEHL
        call    dblhde  ;*4
        call    dblhde  ;*8
        push    de
        push    hl      ;8xDEHL
        call    dblhde  ;*16
        call    dblhde  ;*32
        call    dblhde  ;*64
        call    addpop  ;+X*8 = X*72
        call    addpop  ;+X*2 = X*74
        call    addpop  ;+X   = X*75
;
;Extract modulo 65537 (0x10001).
;
modlp:  ld      a,e
        cp      1
        jr      c,end655        ;IF it's under 0x10000, it's under 0x10001
        jr      nz,sub655       ;IF it's above 0x1FFFF, it's above 0x10001
        ld      a,h             ;0x10000 <= DEHL <= 0x1FFFF
        or      a
        jr      nz,sub655       ;IF it's above 0x100FF, it's above 0x10001
        ld      a,l             ;0x10000 <= DEHL <= 0x100FF
        cp      2
        jr      c,end655        ;IF it's <= 0x10001, return
;
;Subtract 65537 from DEHL...
;
sub655: dec     de
        dec     hl
        jr      modlp
;
end655:
;
;Subtract 1
;
        dec     hl
        ld      (rseed),hl
        ld      b,h
        ld      c,l
;
;BC = number (16-bit). Reduce modulo parameter
;
        res     7,b
        pop     de
        call    smod16
        inc     hl              ;<<v0.03>> value is 0 < n <= max
                                ;          not      0 <=n < max
        scf
        ret                     ;Return value in HL.



steprnd:
        push    hl
        ld      bc,(rlast)      ;Stepping 1,2, ... seed
        inc     bc
;
;BC = number candidate
;
        ld      de,(rseed)
        call    smod16          ;BC := BC mod (seed)
        ld      (rlast),hl
        pop     de
        ld      b,h
        ld      c,l
        res     7,b
        call    smod16          ;Reduce mod parameter
        inc     hl              ;0 < x <= param
        scf
        ret
;
;Double DEHL
;
dblhde: sla     l
        rl      h
        rl      e
        rl      d
        ret
;
addpop: pop     bc      ;return address
        ld      (apret+1),bc
        pop     bc      ;To add to the low word
        add     hl,bc
        pop     bc      ;To add to the high word
        ex      de,hl
        adc     hl,bc
        ex      de,hl
apret:  jp      0
;

; >> v0.03