Closed nww02 closed 4 years ago
Please, send me the source with the macro so that I can see it in its entirety!
Here ya go :)
If you move the str_to_pr and str_loc labels above the macro call, it works.
.model Spectrum48
.ent Start
.xent Start
.org 8000h
Start:
call Main
ret
get_attr_address:
.macro(XYCoordinate)
.if isreg16({{XYCoordinate}})
push {{XYCoordinate}}
pop de
.else
ld de,{{XYCoordinate}}
.endif
ld a,d
sra a
sra a
sra a
add a,58h
ld h,a
ld a,d
and 7
rrca
rrca
rrca
add a,e
ld l,a
.endm
ret
get_char_address:
.macro(XYCoordinate)
.if isreg16({{XYCoordinate}})
push {{XYCoordinate}}
pop de
.else
ld de,{{XYCoordinate}}
.endif
ld a,d
and 0f8h
add a,40h
ld h,a
ld a,d
and 7
rrca
rrca
rrca
add a,e
ld l,a
.endm
ret
halt
print_string:
.macro(XYCoordinate,StringLocation,Colour)
.if def({{StringLocation}})
.if isreg16({{StringLocation}})
push {{StringLocation}} ; get the address onto the stack
.endif
.endif
.if def({{XYCoordinate}})
.if isreg16({{XYCoordinate}})
push {{XYCoordinate}} ; get the coords onto the stack
.endif
.endif
.if def({{Colour}})
.if isreg8({{Colour}})
ld a,{{Colour}} ; get the colour into 'a'.
.endif
.if isexpr({{Colour}})
ld a,{{Colour}} ; same action
.endif
.else
ld a,(paramb1) ; colour attribute
.endif
.if def({{XYCoordinate}})
.if isreg16({{XYCoordinate}})
pop de
.endif
.if isexpr({{XYCoordinate}})
.if {{XYCoordinate}} > 0x3fff
ld de,({{XYCoordinate}})
.else
ld de,{{XYCoordinate}}
.endif
.endif
.else
ld de,(paramw1)
.endif
ld iyh,a ; store attrib in iyh
get_char_address(de) ; Calculate the screen address (in DE)
push hl
get_attr_address(de) ; Calculate the attribute address (in DE)
push hl
pop ix
pop de
.if def({{StringLocation}})
.if isreg16({{StringLocation}})
pop hl ; get the address into 'hl'
.endif
.if isexpr({{StringLocation}})
ld hl,{{StringLocation}}
.endif
.else
ld hl,(paramw2) ; get address of string
.endif
jp ps_nxtchar
.mend
ps_nxtchar: ld a,(hl) ; Fetch the character to print
inc hl ; Increase HL to the next character
cp 0x00 ; Compare with 0x00
ret z ; \0 terminates the string
push hl ; Push HL on stack
call INT_print_char ; Print the character
ld a,iyh ; get attib
ld (ix),a ; set the attib
inc ix ; go right one
pop hl ; Retrieve HL back off the stack
inc e ; Go to the next screen address
jr ps_nxtchar ; Loop back to print next character
ps_end: ret
halt
; Print Zero-terminated string data
; parameters: w1 = location (hi byte = x, lo byte = y - so if pre-loading from 16-bit reg, start out with them
; as YX e.g ld hl,1005# for at x=5, y=10)
; w2 = memory location of string
; b1 = colour attribute
; NOTE: This program will use the CHARS variable to choose the font.
; So, use the set_font command to choose a different font if you need to.
print_string_colour:
ld l,a
; A: Character to print
; DE: Screen address to print character at
;
INT_print_char:
ld hl,(0x5c36) ; get the font.
ld b,0 ; Set BC to A
ld c,a
and 0xff ; Clear the carry bit
rl c ; Multiply BC by 8 (shift left 3 times)
rl b
rl c
rl b
rl c
rl b
add hl,bc ; Get the character address in HL
ld c,8 ; Loop counter
push de
pc_nxtline: ld a,(hl) ; Get the byte from the ROM into A
ld (de),a ; Stick A onto the screen
inc d ; Goto next line on screen
inc l ; Goto next byte of character
dec c ; Decrease the loop counter
jr nz,pc_nxtline ; Loop around whilst it is Not Zero (NZ)
pop de
ret ; Return from the subroutine
Main:
print_string(str_loc,str_to_pr,ink(1) | paper(2))
ret
str_loc: defw 0x0a0a
str_to_pr: defn "Hi Istvan!"
Thanks, I will check it!
I checked this issue. Unfortunately, it is a feature. You can pass only known (evaluable immediately) values to macro parameters. The reason is this: When you pass a value to a macro, you may use it in conditional expressions within the macro, and conditions should be immediately evaluated. I know, with some analysis, the compiler could check if any conditional expression or statement is used. If not, such a construct (late evaluation) should be enabled. With the current compiler architecture, such an implementation is massive, nonetheless, I'll think of some quick solutions.
OK, I think I understand. I was wondering how I could do some "forward defines", so that I could have my data at the end of the program block and still use the macros... But everything I think of just ends up being more convoluted :)
I'll go back to putting all my defines data at the top of the program in a #included data.z80asm. That keeps it neat and out of the way :)
Thanks for looking! :)
I have good news for you :-). I managed to apply a little change that allows prolonging macro argument evaluation until the macro's body is compiled. It means, that you can pass future-evaluated expressions to you macros, just like in this sample:
.model Spectrum48
.ent Start
.xent Start
.org 8000h
Start:
call Main
ret
; Non-functional macro
print_string:
.macro(loc, ptr, value)
ld hl,{{loc}}
ld de,{{ptr}}
ld a,{{value}}
.endm
Main:
; Now, this works!
print_string(str_loc, str_to_pr, ink(1) | paper(2))
ret
str_loc: defw 0x0a0a
str_to_pr: defn "Hi Istvan!"
Of course, conditional statements still require immediately-evaluable expressions, so this still won't work:
.model Spectrum48
.ent Start
.xent Start
.org 8000h
Start:
call Main
ret
; Non-functional macro
print_string:
.macro(loc, ptr, value)
.if ({{loc}} > 0x3fff) ; This line will raise an error
ld hl,{{loc}}
.endif
ld de,{{ptr}}
ld a,{{value}}
.endm
Main:
; Now, this works!
print_string(str_loc, str_to_pr, ink(1) | paper(2))
ret
str_loc: defw 0x0a0a
str_to_pr: defn "Hi Istvan!"
Here is the private build with this fix:
I hope, it seems ok for you. If everything's ok, tomorrow I will release Preview 6.
I'll try to get it installed ASAP and give it a try :)
Thank you! You've been so busy with all these fixes and updates! I'm really enjoying working with SpectNetIDE.
Ah yes, I see now. Interesting that it cannot run the test on the late-bound variable. I suppose the compiler would need a further pass after the late macro binding to perform the if tests on the fixed up variable. OK, no problem, I can take a 15-or-so T-state hit in the setup to test it using code, or I can write two differently named entrypoints and jr into the main body... The test below works, so I'll use this for now :)
.if isexpr({{XYCoordinate}})
ld de,{{XYCoordinate}}
ld a,d
cp 0x40
jr c,ps_proceed
ld de,({{XYCoordinate}})
.endif
ps_proceed: ld iyh,a ; store attrib in iyh
get_char_address(de) ; Calculate the screen address
Thanks for this fix! It'll solve a lot of headaches with ordering #includes and will help with avoiding unncessary jumps to skip data blocks..
:)
Released in v2 Preview 6.
Thank you :)
Sample Code to print "Hi Istvan" at 5,5 in red and blue.
This breaks because the str_to_pr label is defined after the macro call.
If I put the label before the macro that makes it work.
Also, if I put the str_to_pr parameters in double-quotes, the parser catches the address properly on the second pass, and that also works.
Please can macro parameters be added to the fixup logic?