Posted: Tue 12 Jun, 2007 5:56 pm
You could also PUSH and POP BC, that will be faster for long strings, inc BC would be faster for short ones
Code: Select all
_strcpy:
xor a
cp (hl)
ldi
jr nz,_strcpy+1
ret
_strncpy:
ld c,b ; ensure that LDI doesn't change B
xor a
cp (hl)
jr z,pad
ldi
djnz _strncpy+2
ret
pad: ld (de),a
inc de
djnz pad
ret
Code: Select all
_strcpy:
xor a
cp (hl)
ldi
jp pe,_strcpy+1
ret
Code: Select all
.module misc
;; === misc.fadestep ===
;;
;; Changes the contrast 1 closer to the specified value
;;
;; Pre:
;; c = Contrast to fade to
;;
;; Post:
;; c-flag = reset if (contrast)=c, set otherwise
;; af, b destroyed
;;
;; SeeAlso:
;; misc.fade
;;
;; Warning:
;; Providing an invalid contrast causes random values to be send to the lcd.
;; This error is caught if DEBUG is defined
;;
fadestep:
ld a, (contrast)
ld b, a
cp c
ret z ; c-flag is reset
sbc a, a ; Determ the direction of fading
or 1
add a, b
ld (contrast), a
add a, %11011000
ASSERT(nc) ; If carry is set then the contrast is invalid
out ($10), a
scf
ret ; c-flag is set
;; === misc.fade ===
;;
;; Fades the contrast to the specified value
;;
;; Post:
;; Contrast is faded to specified value
;; Interrupts are enabled
;; af, bc destroyed
;;
;; SeeAlso:
;; misc.fadestep
;;
;; Warning:
;; Speed depends on the isr timer, change the number of halts if needed
;;
fadelight:
ld c, 0
jr fade
fadedark:
ld c, 39
fade:
ei
halt
halt
call fadestep
jr c, fade
ret
.endmodule
Code: Select all
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; alUMulByFraction:
;;
;; HL = HL * DE / BC
;;
;; This routine multiplies HL by proper fraction DE/BC.
;;
;; HL is treated as unsigned.
;; BC must be non-zero
;; BC must be < 32768
;; DE must be <= BC
;;
;; INPUTS:
;;
;; HL - multiplicand
;; DE - numerator
;; BC - denominator
;;
;; OUTPUTS:
;; HL - quotient of HL * DE / BC
;; DE - remainder of HL * DE / BC
;;
;; DESTROYED:
;; AF
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
alUMulByFraction:
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; This initial block of code is used to return the output in more
;; convenient registers. It may be removed, in which case the
;; output will be returned as followed:
;;
;; IX - quotient
;; HL - remainder
;; DE - numerator (unchanged)
;; BC - denominator (unchanged)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
push ix ; [15] preserve IX
call _mainRtn ; [17] run main code.
ex (sp), ix ; [23] quotient <-> preserved IX
ex de, hl ; [4] remainder <-> numerator
pop hl ; [10] pop quotient
ret ; [10]
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; The actual routine starts here.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
_mainRtn: ld ix, $0000 ; [14] initial quotient
ld a, h ; [4]
or a ; [4]
jr z, _highZero ; [12/7] jump if high byte is zero.
ld h, l ; [4] push contents of L to stack so
push hl ; [11] we can pop it into A later on.
ld hl, $0000 ; [10] initial remainder
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Skip to first significant bit to avoid useless work. We also
;; set the low bit of A to act as a marker bit for the main loop.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
scf ; [4] for marker bit
_findHiBit: adc a, a ; [4] searching for first significant
jp nc, _findHiBit ; [10] bit to avoid useless work.
call _mainLoop ; [*] process high byte.
pop af ; [10] pop low byte
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Now process the low byte.
;;
;; Here we duplicate a small part of the the main loop. This is
;; because we need to run this code, but we want to shift a 1
;; into the accumulator instead of a 0.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
add ix, ix ; [15] quotient * 2
add hl, hl ; [11] remainder * 2
sbc hl, bc ; [15] remainder -= denominator
jr nc, _nc3 ; [12/7]
add hl, bc ; [11] remainder += denominator
jp _rotMul2 ; [10]
_nc3: inc ix ; [10] quotient + 1
_rotMul2: sl1 a ; [8]
jp _mainLoop ; [10]
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; High byte was zero.
;; Go straight to low byte. Do not collect $200.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
_highZero: ld a, l ; [4] load low byte
ld hl, $0000 ; [10] initial remainder
or a ; [4]
ret z ; [11/5] return if multiplicand zero
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Search for first significant bit to avoid useless work. We also
;; set the low bit of A to act as a marker bit for the main loop.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
scf ; [4] for marker bit
_findLoBit: adc a, a ; [4] searching for first significant
jp nc, _findLoBit ; [10] bit to avoid useless work.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Main processing loop. We loop here for each significant bit
;; of the multiplicand (hence, small multiplicands are fast).
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
_mainLoop: jr nc, _loopTail ; [12/7]
add hl, de ; [11] remainder += numerator
sbc hl, bc ; [15] remainder -= denominator
jr nc, _nc2 ; [12/7]
add hl, bc ; [11] remainder += denominator
jp _loopTail ; [10]
_nc2: inc ix ; [10]
_loopTail: cp $80 ; [7] once only the marker bit is
ret z ; [10] left we end the loop
add ix, ix ; [15] quotient * 2
add hl, hl ; [11] remainder * 2
sbc hl, bc ; [15] remainder -= denominator
jr nc, _nc1 ; [12/7]
add hl, bc ; [11] remainder += denominator
jp _rotMulBit ; [10]
_nc1: inc ix ; [10] quotient + 1
_rotMulBit: add a, a ; [4] shift next bit and loop
jp _mainLoop ; [10]
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; End of alUMulByFraction
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
Code: Select all
;@doc:routine
;
; === alDPFixSin ===
;
; Returns sin(BC). BC is an integer angle with 1024 degrees to the circle.
;
; Since a sin(X) == cos(X + 90), this routine can be used to calculate a cosine
; by incrementing the high byte of the angle (B) by one before calling.
;
; INPUTS:
;
; REGISTERS:
; * BC - Angle to calculate sine of.
;
; OUTPUTS:
;
; REGISTERS
; * HL - sin(BC)
;
; DESTROYED:
;
; REGISTERS:
; * AF
;
;@doc:end
alDPFixSin:
; The high byte of the angle indicates which quadrant of the sine
; wave we are interested in indexing
ld a, c ; [4]
bit 0, b ; [8] if the angle is [256..511, 768..1023]
jr z, _noNegate ; [12/8] negate the low byte.
neg ; [8]
jr z, _forceTo1 ; [12/8]
_noNegate: ld l, a
ld h, g_alTrigTable ; [7]
ld a, (hl) ; [7]
inc h ; [4]
ld h, (hl) ; [7]
ld l, a ; [4]
bit 1, b ; [8]
ret z ; [?] negate result if angle >= 512
cpl ; [4]
ld l, a ; [4]
ld a, h ; [4]
cpl ; [4]
ld h, a ; [4]
inc hl ; [6]
ret ; [10]
; If the angle was 256 or 768, we manually force it to +/-1
_forceTo1: bit 1, b ; [8]
jr nz, _forceToN1 ; [12/8]
ld hl, 16384 ; [10] replace this with your value for +1
ret ; [10]
_forceToN1: ld hl, -16384 ; [10]
ret ; [10] replace this with your value for -1
Code: Select all
; === xFadeLCD ===
;
; Cross-fades the LCD between the current image (HL) and the image in (DE).
;
; INPUTS:
;
; REGISTERS
; * IX - Buffer for crossfade data (768 bytes)
; * HL - Buffer containing LCD contents (768 bytes)
; * DE - Target image (768 bytes)
Wouldn’t it be more efficient to do it like this:qarnos wrote:It's not as fast as I would like - an image which needs every pixel changed takes a couple of seconds - but it's good enough to be used in games for nice transitions between static screens.
It probably would be. The main motivation for this method is I want to avoid the possibility of "getting stuck" if we go through a few loops and are unlucky enough to keep getting bad random numbers.CoBB wrote:Wouldn’t it be more efficient to do it like this:
Couldn't you simple use the refresh register?qarnos wrote:I found the reason why my routine is slow and the CoBB version is jerky - irandom is slow, slow, slooooooowww.
I'll play around with some other RNGs.