; ZXZVM: Z-Code interpreter for the Z80 processor ; Copyright (C) 1998-9,2006,2016 John Elliott ; ; This program is free software; you can redistribute it and/or modify ; it under the terms of the GNU General Public License as published by ; the Free Software Foundation; either version 2 of the License, or ; (at your option) any later version. ; ; This program is distributed in the hope that it will be useful, ; but WITHOUT ANY WARRANTY; without even the implied warranty of ; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ; GNU General Public License for more details. ; ; You should have received a copy of the GNU General Public License ; along with this program; if not, write to the Free Software ; Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; ;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 ;<> 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