05-31-2010, 11:02 AM
There's already such a function in attr.asm library, but this one uses a different approach:
Please check which one is faster (I'm not sure): This function takes 102 T-States (RET Included), your takes 67 (RET Included). With the commented optimization it will take 99 T-States.
The problem here is __ATTR_ADDR is taking into account a configurable SCREEN_ADDRESS variable (previously discussed here). So if you want your program to work in a variable screen address, you should work considering 0 offset an adding (SCREEN_ADDRESS) at the end, so should change it this way:
So this function, adapted for a configurable screen address is 8 T-states faster than the original in ZX Basic (only 5 if the commented optimization is done) :?:
Code:
__ATTR_ADDR:
; calc start address in DE (as (32 * d) + e)
; Contributed by Santiago Romero at http://www.speccy.org
ld h, 0
ld l, d
add hl, hl ; HL = HL*2
add hl, hl ; HL = HL*4
add hl, hl ; HL = HL*8
add hl, hl ; HL = HL*16
add hl, hl ; HL = HL*32
;; Note: *THIS IS WRONG*
; the addition of 6144 could be optimized to
; ld a, 18h
; add a, h
; ld h, a
; this saves 3 T-States (The above calculation misses E register)
;; adds 6144 for attribute start
ld d, 18h ; DE = 6144 + E. Note: 6144 is the screen size (before attr zone)
add hl, de
ld de, (SCREEN_ADDR) ; Adds the screen address
add hl, de
; Return current screen address in HL
ret
The problem here is __ATTR_ADDR is taking into account a configurable SCREEN_ADDRESS variable (previously discussed here). So if you want your program to work in a variable screen address, you should work considering 0 offset an adding (SCREEN_ADDRESS) at the end, so should change it this way:
Code:
FUNCTION FASTCALL attrAddress(x as uByte, y as uByte) as Uinteger : REM Will issue a Warning
asm
; This function returns the address into HL of the screen address
; x,y in character grid notation.
; Original code was extracted by BloodBaz - Adapted for ZX BASiC by Britlion from Na_TH_AN's fourspriter
ld e, a ; X comes in A register (fastcall). Saves X in E register
pop hl ; ret Address
pop af ; Get Y in A [F not used]
ld d, a ; Saves Y in D register, So DE register stores YX coords.
push hl ; Put RET address back in the Stack
;; 39 T-States up to here, but we don't count this to be fair with the above
;; So 0 T-States. Start counting them from here
;; At this point, A already has Y coord
rrca
rrca
rrca ; Multiply by 32
ld l,a ; Pass to L
and 3 ; Mask with 00000011
;; 23 T-States up to here
;; The following must be changed, start form 0 and add (SCREEN_ADDRESS) later
; add a,88 ; 88 * 256 = 22528 - start of attributes.
add a,24 ; 24 * 256 = 6144 - start of attributes from address 0x0000h
ld h,a ; Put it in the High Byte
ld a,l ; We get y value *32
and 224 ; Mask with 11100000
;; The following can be optimized ???
; ld l,a ; Put it in L
; ld a,d ; xpos
; add a,l ; Add it to the Low byte
add a, e ; add xpos
ld l,a ; Put it back in L, and we're done. HL=Address.
;; 53 T-States up to here
ld de, (SCREEN_ADDRESS)
add hl, de ;; Total T-States = 84 T-States
;; (implicit RET) + 10 T-States = 94 T-States
end asm
END FUNCTION