Here's the relevant verbose listing for its current state, sans definitions. They're there, way above.
Line 38: .byte cur_adr - stk_lvl_1 lays down a #$01 byte right there, despite the previous .base statement. I've also tried .org, that doesn't work. It's like the variables are treated as local, even though they are defined outside and before the macros, or that .base can't reach outside the macro. I'm just guessing at worst case scenarios here, really, for lack of better insight.
Code:
E4 2D CPX goal
IF_EQ
D0 FE BNE $ ; Lay down the BNE op code plus a placekeeper for the operand,
.include "STAKPUSH.ASM" ; and push a cell on the stack.
;.enum $ ; --commented out as to get full view of the output
stk_lvl_20 = stk_lvl_19
stk_lvl_19 = stk_lvl_18
stk_lvl_18 = stk_lvl_17
stk_lvl_17 = stk_lvl_16
stk_lvl_16 = stk_lvl_15
stk_lvl_15 = stk_lvl_14
stk_lvl_14 = stk_lvl_13
stk_lvl_13 = stk_lvl_12
stk_lvl_12 = stk_lvl_11
stk_lvl_11 = stk_lvl_10
stk_lvl_10 = stk_lvl_9
stk_lvl_9 = stk_lvl_8
stk_lvl_8 = stk_lvl_7
stk_lvl_7 = stk_lvl_6
stk_lvl_6 = stk_lvl_5
stk_lvl_5 = stk_lvl_4
stk_lvl_4 = stk_lvl_3
stk_lvl_3 = stk_lvl_2
stk_lvl_2 = stk_lvl_1
;.ende
stk_lvl_1 = $ ; Put the addr of that operand in that top-of-stack cell.
else_flag = 0
CA dex
ELSE_
; Lay down the VBS (should be JMP in final; originally BRA) op code plus a placekeeper.
cur_adr = $ ; Keep the current address to restore below.
$ = stk_lvl_1 - 1 ; Go back to the place for the .if's Bxx's operand, to fill it in now.
01 .byte cur_adr - stk_lvl_1 ; Let's use .byte because most assemblers seem to recognise it
$ = cur_adr ; Now after completing .if's Bxx's operand, come back to resume assembling new code.
70 FE BVS $ ; --TEMPORARY!! should be JMP in the final version, but for now...
stk_lvl_1 = $ ; reusing the same stack level. If the program had worked it'd been free from duty by now.
else_flag = 1 ; Set flag for END_IF to know if it should fill in a one-byte BNE operand or two-byte JMP
E8 inx
END_IF
cur_adr = $ ; Save the current address, needed because we're going back a bit!
$ = stk_lvl_1 - 1 ;go back to previous macro's branch (or jump) to prepare for overwriting the placeholder.
.if else_flag == 1
;.dl stk_lvl_1 ;--this is for filling in the JMP (now BVS) operand. Probably doesn't work like this.
;.dh stk_lvl_1 ;--but that's a later problem. Current problem: get it in place.
01 .byte cur_adr - stk_lvl_1 ;-- and this is for the BVS surrogate..
else_flag = 0
.else
.byte cur_adr - stk_lvl_1 ;this is for filling in the Bxx operand in the if-clause.
.endif
.include "STACKPOP.ASM" ; We're done with this stack level now, so we can drop it.
stk_lvl_1 = stk_lvl_2 ; As with the push list, but in reverse
stk_lvl_2 = stk_lvl_3
stk_lvl_3 = stk_lvl_4
stk_lvl_4 = stk_lvl_5
stk_lvl_5 = stk_lvl_6
stk_lvl_6 = stk_lvl_7
stk_lvl_7 = stk_lvl_8
stk_lvl_8 = stk_lvl_9
stk_lvl_9 = stk_lvl_10
stk_lvl_10 = stk_lvl_11
stk_lvl_11 = stk_lvl_12
stk_lvl_12 = stk_lvl_13
stk_lvl_13 = stk_lvl_14
stk_lvl_14 = stk_lvl_15
stk_lvl_15 = stk_lvl_16
stk_lvl_16 = stk_lvl_17
stk_lvl_17 = stk_lvl_18
stk_lvl_18 = stk_lvl_19
stk_lvl_19 = stk_lvl_20
$ = cur_adr ; restore program counter
And here's Garth:s PM reply
Quote:
It looks like certain things are working right, like the first $, so BNE's operand was put in the right place, but it's just the wrong value. It has the BNE branching back to the BNE itself. But for the next $, the JMP should have worked, unless your assembler uses $ differently from what I've seen in others. Or, maybe the JMP was originally laid down correctly, but the .byte in END_IF somehow came up with something that couldn't fit in 16 bits, like it if uses a 32-bit number and it was negative, and was also trying to overwrite the JMP op code itself rather than the operand. It might be time to consult its manual. Can you view the relevant part of the list (*.lst) file and include it in the next message? That will tell a lot more of what went on internally. Without it, I think we'll just be guessing.
It looks like if you have the NMOS 6502 without the BRA instruction, END_IF will have to be different for using the ELSE versus not using ELSE. This is because with only IF, END_IF fills in a one-byte relative-branch operand, wheres with the ELSE, it needs to fill in a two-byte absolute JMP operand. They're different. (With CMOS, it was the single-byte relative-branch operand both ways.) One way to have it do it would be to have a flag variable in the assembler (maybe call it ELSE_FLAG) which any IF clears, and ELSE sets, and then the END_IF uses that flag to conditionally assemble the right thing, whether for the JMP in ELSE, or the B__ in IF. The pain about that though is that then you have to stack that too, otherwise you can't have nested IF structures! (Myself, I think I would still do it. Using a separate stack for ELSE_FLAGs might make it easier; but I haven't tried it yet to say for sure.) An easier way up front, but which would lead to more errors later is to have a separate END_IF, like maybe follow it with an _ like END_IF_, and then if you've used and ELSE, use END_IF_ instead of END_IF. You can see that using the wrong one would lead to bugs, like if you start with IF...END_IF, then later decide to insert an ELSE and forget to change to END_IF_, or just use the wrong one the first time.
The END_IF shouldn't lay down any new code at the end, only fix the operand of ELSE's JMP, or, if you don't have the ELSE, fix the operand of the IF's B__.
To which i replied:
Quote:
Unfortunately, it seems the first BNEs operand wasn't put in place at all - even if i comment out the rest, that's the value i get, meaning that must be the placeholder's value (which makes sense since it is branching back on itself).
I've modified the code some more, including slight reordering, changing .org for .base, letting go of the to_push variable since asm6 doesn't seem to have that bug. Also, it seems to accept nested macros, which may open to some possibilities, but i think the includes are tidy enough for now. Either way, the output is the same.
(...)