Log inRegister an accountBrowse CSDbHelp & documentationFacts & StatisticsThe forumsAvailable RSS-feeds on CSDbSupport CSDb Commodore 64 Scene Database
You are not logged in - nap
CSDb User Forums


Forums > C64 Coding > 64tass: labels inside FOR ... NEXT loops
2016-12-01 15:45
ready.

Registered: Feb 2003
Posts: 441
64tass: labels inside FOR ... NEXT loops

hello,
does 64tass have the possibility to use indexed labels, like inside a FOR...NEXT loop?

Something like:
.FOR X=0, X<X_MAX-1, X=X+1
LABEL(X)
LDA #ABC
STA ZXY
.NEXT
so to have X_MAX labels.

Unrolled:

LABEL1
LDA #ABC
STA ZXY
LABEL2
LDA #ABC
STA ZXY
.....
2016-12-01 16:21
iAN CooG

Registered: May 2002
Posts: 3128
The generated code length is constant so something like this should work, use a calc to access to label+offset

	*=$1000
X_MAX=6
.FOR X=0, X<X_MAX, X=X+1
.if X == 0
label
.fi
 	LDA #X
 	STA $8000+X
.if X == 0
endcode
.fi
.NEXT
size=endcode-label

	rts

	.word label+0*size
	.word label+1*size
	.word label+5*size


generated listing
=6						X_MAX=6
.1000						label
.1000		 a9 00		lda #$00	 	LDA #X
.1002		 8d 00 80	sta $8000	 	STA $8000+X
.1005						endcode
.1005		 a9 01		lda #$01	 	LDA #X
.1007		 8d 01 80	sta $8001	 	STA $8000+X
.100a		 a9 02		lda #$02	 	LDA #X
.100c		 8d 02 80	sta $8002	 	STA $8000+X
.100f		 a9 03		lda #$03	 	LDA #X
.1011		 8d 03 80	sta $8003	 	STA $8000+X
.1014		 a9 04		lda #$04	 	LDA #X
.1016		 8d 04 80	sta $8004	 	STA $8000+X
.1019		 a9 05		lda #$05	 	LDA #X
.101b		 8d 05 80	sta $8005	 	STA $8000+X
=5						size=endcode-label
.101e		 60		rts			rts
>101f		 00 10					.word label+0*size
>1021		 05 10					.word label+1*size
>1023		 19 10					.word label+5*size
2016-12-01 16:22
Oswald

Registered: Apr 2002
Posts: 5007
its not much more complicated natively, if you gen the code to loc zp:

lda zplo
sta labelslo,x
lda zphi
sta labelshi,x

or if the distance is constant just a 16 bit add in the other speedcode gen.
2016-12-01 17:05
Hein

Registered: Apr 2004
Posts: 933
It used to work in older versions, but seems broken in the new version.

old version:
mymacro .macro

label\1 lda #\1

        .endm

        .for i=0,i<8,i=i+1
        #mymacro ^i
        .next

then
        lda #0
        sta label0+1
        sta label1+1

etc.

I tried it in the new version with:
        .for i=0,i<8,i=i+1
        #mymacro i
        .next

but the i isn't passed on to labels, but it is to the value.. :/
2016-12-01 22:54
soci

Registered: Sep 2003
Posts: 472
The "^" prefix for macro parameters is gone since r98. It did an expression evaluation and the result was converted to a decimal string which in turn was used for textual replacement. Similar to the "^" operator.

While it could be resurrected I'd like to see it dead and buried. Unfortunately the non-macro operator variant of this can't go away that easy due to it's common use in basic start lines. The sad thing is there's no other useful use of it at all. It should have been assigned as the bank byte operator but it couldn't due to it's 1.3x legacy.

As macro parameters are text replacements you're out of luck to use the value of the loop variable this way.

The alternative to numbered labels is lists. Simplest is to collect addresses into a list:
        *= $1000

lista   := []        ; empty
        .for i=0,i<8,i=i+1
lista   ..= [*]      ; collect
        lda #i
        .if i>3
        nop
        .fi
        .next

        .word lista   ;all
        .word lista[4];5th
Gives:
.1000   a9 00           lda #$00                lda #i
.1002   a9 01           lda #$01                lda #i
.1004   a9 02           lda #$02                lda #i
.1006   a9 03           lda #$03                lda #i
.1008   a9 04           lda #$04                lda #i
.100a   ea              nop                     nop
.100b   a9 05           lda #$05                lda #i
.100d   ea              nop                     nop
.100e   a9 06           lda #$06                lda #i
.1010   ea              nop                     nop
.1011   a9 07           lda #$07                lda #i
.1013   ea              nop                     nop
>1014   00 10 02 10 04 10 06 10                 .word lista   ;all
>101c   08 10 0b 10 0e 10 11 10
>1024   08 10                                   .word lista[4];5th

Something similar can be done a bit more complicated using a list of anonymous scopes (not exactly the same as above):
        *= $1000

lista   := []
        .for i=0,i<8,i=i+1
lista   ..= [+]
+       .block
label   lda #i
        .if i>3
lbl2    nop
        .fi
        .bend
        .next

        .word lista.label
        .word lista[4].lbl2

Results in:
.1000   a9 00           lda #$00        label   lda #i
.1002   a9 01           lda #$01        label   lda #i
.1004   a9 02           lda #$02        label   lda #i
.1006   a9 03           lda #$03        label   lda #i
.1008   a9 04           lda #$04        label   lda #i
.100a   ea              nop             lbl2    nop
.100b   a9 05           lda #$05        label   lda #i
.100d   ea              nop             lbl2    nop
.100e   a9 06           lda #$06        label   lda #i
.1010   ea              nop             lbl2    nop
.1011   a9 07           lda #$07        label   lda #i
.1013   ea              nop             lbl2    nop
>1014   00 10 02 10 04 10 06 10                 .word lista.label
>101c   08 10 0b 10 0e 10 11 10
>1024   0a 10                                   .word lista[4].lbl2

This has an advantage that proper referencable labels can be used for each instance of code using only one list.

I think I've showed Oswald once in private message how to prototype 25 parametrized IRQs with a for loop generator so that each of them sets the vector to the next one and the last one back to the first. With on-demand high byte update to spare cycles/bytes (variable length instances) and initial setup. It used this latter anonymous scope+list method.
2016-12-02 05:23
Oswald

Registered: Apr 2002
Posts: 5007
for the record:

*= $801
.word +, 2016
.null $9e, ^start
+ .word 0

start
sei
lda #<irqlist[0].addr ; elso cim
sta $314
lda #>irqlist[0].addr
sta $315
lda #irqlist[0].raster ; elso pozicio
sta $d012
lda $d011
and #~$80
sta $d011
lda #1
sta $dc0d
sta $d01a
bit $dc0d
sta $d019
cli
rts

irqlist2 := [] ; ures lista a rutinoknak

.for this = 0, this < 50, this = this + 1; 50 db

irqlist2 ..= [+] ; aktualis irq rutin listaba rakasa
+ .block ; irq rutin blokk
addr = * ; cim
raster = (this & 1) == 0 ? (this/2)*8+53 : (this/2)*8+55; raster pozicio effekthez
nextirq = irqlist[len(irqlist2) % len(irqlist)];a kovetkezo irq rutin

lda #this & 15 ; hogy legyen valami effekt is
sta $d020
lda #nextirq.raster ; kovetkezo pozicio
sta $d012
inc $d019
lda #<nextirq.addr ; kovetkezo cim
sta $314
.if (>nextirq.addr) != (>addr); csak ha kell
lda #>nextirq.addr
sta $315
.fi
jmp this == 49 ? $ea31 : $ea81; hogy lehessen gepelni ;)
.bend

.next

irqlist = irqlist2 ; hogy lehessen hasznalni fent
2016-12-02 06:45
soci

Registered: Sep 2003
Posts: 472
Thanks! Next time I'll comment in English, one can never know ;)
2016-12-02 07:56
Radiant

Registered: Sep 2004
Posts: 639
Parenthetical: A great example of why code comments and symbols always should be in English - you never know who is going to read the code down the line.

I take it one step further and keep all design documents, Trello boards et cetera in English as well, even though at the moment everyone in the group speaks Swedish.
2016-12-02 08:54
Oswald

Registered: Apr 2002
Posts: 5007
*= $801
.word +, 2016
.null $9e, ^start
+ .word 0

start
sei
lda #<irqlist[0].addr ; first adress
sta $314
lda #>irqlist[0].addr
sta $315
lda #irqlist[0].raster ; first raster pos
sta $d012
lda $d011
and #~$80
sta $d011
lda #1
sta $dc0d
sta $d01a
bit $dc0d
sta $d019
cli
rts

irqlist2 := [] ; empty list for the routines

.for this = 0, this < 50, this = this + 1; 50 pcs

irqlist2 ..= [+] ;put current irq routine into list
+ .block ; irq routine block
addr = * ; address
raster = (this & 1) == 0 ? (this/2)*8+53 : (this/2)*8+55; raster position for effect
nextirq = irqlist[len(irqlist2) % len(irqlist)];the next irq routine

lda #this & 15 ; so some effect is shown
sta $d020
lda #nextirq.raster ; next position
sta $d012
inc $d019
lda #<nextirq.addr ; next adress
sta $314
.if (>nextirq.addr) != (>addr); only if needed
lda #>nextirq.addr
sta $315
.fi
jmp this == 49 ? $ea31 : $ea81; so you can type ;)
.bend

.next

irqlist = irqlist2 ; so it is possible to use up there
2016-12-02 17:58
chatGPZ

Registered: Dec 2001
Posts: 11088
Quote:
A great example of why code comments and symbols always should be in English

come on.... at least its not japanese :)
2016-12-02 18:42
Hein

Registered: Apr 2004
Posts: 933
Quoting soci
        *= $1000

lista   := []        ; empty
        .for i=0,i<8,i=i+1
lista   ..= [*]      ; collect
        lda #i
        .if i>3
        nop
        .fi
        .next

        .word lista   ;all
        .word lista[4];5th

Thanks, will try that.
2016-12-02 20:19
Oswald

Registered: Apr 2002
Posts: 5007
soci, could you explain the ..= operator?
2016-12-02 20:37
Flavioweb

Registered: Nov 2011
Posts: 442
Quote: soci, could you explain the ..= operator?

http://tass64.sourceforge.net/#compound
2016-12-02 21:12
soci

Registered: Sep 2003
Posts: 472
Yes, "..=" is the compound assignment version of the concatenate operator "..".

So "a ..= b" is the shorter form of "a := a .. b" or "a .var a .. b". Just like "a += b" is "a := a + b".

Btw. compound assignments for ".for" loops are only available since r1245. The last release was r1237 which is the reason I still used "i = i + 1" instead of the shorter "i += 1" in the example.
2016-12-03 14:56
Compyx

Registered: Jan 2005
Posts: 631
Quoting soci
The "^" prefix for macro parameters is gone since r98. It did an expression evaluation and the result was converted to a decimal string which in turn was used for textual replacement. Similar to the "^" operator.

While it could be resurrected I'd like to see it dead and buried. Unfortunately the non-macro operator variant of this can't go away that easy due to it's common use in basic start lines. The sad thing is there's no other useful use of it at all. It should have been assigned as the bank byte operator but it couldn't due to it's 1.3x legacy.


Why not remove it, with an error message when people use it. I'm sure I can change ^2016 to .text "2061" or something like it in my sources if 64tass borks and prints a clear message.
2016-12-03 16:07
soci

Registered: Sep 2003
Posts: 472
Normally it isn't used as '^2061' directly, but more as '^start'. An equivalent replacement is 'format("%d", start)' as that's what it does.

Possibly I can make a deprecation warning which directs to the use of format function instead.

It can't be changed to mean the bank byte immediately as it will compile without error if ".text $9e, ^start" was used. For ".null $9e, ^start" of course not as the result is likely 0 which is an error.

So there needs to be at least one release with the warning before it could change. And then the current "`" bank byte operator needs be there for even longer as an alias. But that's not a big problem as it's like the old "//" alias for modulo (now "%") and there's no plan to reuse it for something else yet.

Edit: It seems I have more than ~450 instances of ^xxx of which only ~50 or so is ^year, ^revision and such, rest is ^start. Oh well...
2016-12-03 18:29
Compyx

Registered: Jan 2005
Posts: 631
Sorry, I meant ^start of course.

Personally I'd rather break stuff now than later if it makes sense. Keeping old cruft around doesn't make maintaining things easier.
Deprecation warnings only serve to have people think "I'll fix that later", which they only do when stuff actually breaks.
2016-12-03 20:49
soci

Registered: Sep 2003
Posts: 472
It's not a maintenance issue as the code implementing it was refactored a few times already and is not much.

The concern is that the de facto standard notation for bank bytes still can't be used while there was a 100% replacement for years to create the exact same strings (and more).

I've added the warning for now as it helps to identify what needs to be changed and how. Especially that the breakage is hard to spot in some cases. Then sometime next year or so "^xxx" will be changed to calculate the bank bytes instead.
2016-12-03 20:52
chatGPZ

Registered: Dec 2001
Posts: 11088
Quote:
Keeping old cruft around doesn't make maintaining things easier.

you only say that because you don't like it =P
2019-02-21 14:22
ready.

Registered: Feb 2003
Posts: 441
How could I use the same list feature but in a matrix way, so that lista is a matrix and no just a vector?
2019-02-21 20:14
soci

Registered: Sep 2003
Posts: 472
Matrixes are just nested lists.
m = [[1,2],[3,4]]

lda #m[0,0]
2019-02-21 20:27
soci

Registered: Sep 2003
Posts: 472
Btw. in 1.54 I've added scoped loop directives. Now the second example in post #5 can be simplified to:
        *= $1000

lista   .bfor i = 0, i < 8, i += 1
label   lda #i
        .if i > 3
lbl2    nop
        .fi
        .next

        .word lista.label ; all labels
        .word lista[4].lbl2 ; the one from the 5th run
2019-02-22 07:27
oziphantom

Registered: Oct 2014
Posts: 478
This new feature is handy for avoiding the "I used a" trap ;)

aka

.for a = 0, a < 10 , a += 2

then later

lsr a

.warning Invalid addressing mode
2019-02-22 08:48
soci

Registered: Sep 2003
Posts: 472
The loop related calculations are not scoped. This is so you can update an existing variable created somewhere above and that the loop variable is available later for checks/further continuation loops.

Such unfortunate name choices should be avoided. Using -Wshadow can help with that.
2019-10-02 15:54
ready.

Registered: Feb 2003
Posts: 441
thanks for the replies, they've been really useful.
Now I take it to an even further level.
Let's say I need a multiple index label, so far I only need a vector of labels, thus: LABEL[0], LABEL[1], LABEL[2]....
But how can I implement a matrix of labels, thus
LABEL[0][0], LABEL[0][1],....
LABEL[1][0], LABEL[1][1],...
LABEL[2][0], LABEL[2][1],...
Somthing like:
FRAME := [][][]
.FOR FRAME=0,FRAME<=6,FRAME=FRAME+2
.FOR ZOOM=1,ZOOM<=3,ZOOM=ZOOM+1
FRAME .= [FRAME],[ZOOM]
.binary .....
.NEXT
.NEXT
2019-10-02 17:12
soci

Registered: Sep 2003
Posts: 472
You need to nest them. For the exact style you want:
FRAMES := []
.FOR FRAME=0, FRAME<=6, FRAME += 2
 ZOOMS := []
 .FOR ZOOM=1, ZOOM<=3, ZOOM += 1
  - .binary .....
  ZOOMS ..= [-] ; collect in zooms
 .NEXT
 FRAMES ..= [ZOOMS] ; collect zooms in frames
.NEXT

lda #<FRAMES[2][0]
ldx #>FRAMES[2][0]
However I would do this instead:
FRAMES .BFOR FRAME IN RANGE(0, 7, 2)
 ZOOMS .BFOR ZOOM IN RANGE(1, 4)
  .binary .....
 .NEXT
.NEXT

lda #<FRAMES[2].ZOOMS[0]
ldx #>FRAMES[2].ZOOMS[0]
2020-01-25 22:09
ready.

Registered: Feb 2003
Posts: 441
thanks I got it working, very useful stuff. However I spotted a possible bug with 64TASS 1.54.1900
This is compiles ok:
FRAMES := []
.FOR FRAME=0, FRAME<=6, FRAME += 2
ZOOMS := []
.FOR ZOOM=1, ZOOM<=3, ZOOM += 1
- .binary .....
ZOOMS ..= [-] ; collect in zooms
.NEXT
FRAMES ..= [ZOOMS] ; collect zooms in frames
.NEXT

lda #<FRAMES[2][0]
ldx #>FRAMES[2][0]

while this complains "error: not defined ident 'FRAMES'"
lda #<FRAMES[2][0]
ldx #>FRAMES[2][0]

FRAMES := []
.FOR FRAME=0, FRAME<=6, FRAME += 2
ZOOMS := []
.FOR ZOOM=1, ZOOM<=3, ZOOM += 1
- .binary .....
ZOOMS ..= [-] ; collect in zooms
.NEXT
FRAMES ..= [ZOOMS] ; collect zooms in frames
.NEXT

so basically I am forced to declare the labels in RAM before they are actually used. In my program I call the labels in upper RAM but store the tables with labels definition much further down.
2020-01-25 22:14
ready.

Registered: Feb 2003
Posts: 441
ok just found a workaround which compiles fine:
lda #<support_label
ldx #>support_label

FRAMES := []
.FOR FRAME=0, FRAME<=6, FRAME += 2
ZOOMS := []
.FOR ZOOM=1, ZOOM<=3, ZOOM += 1
- .binary .....
ZOOMS ..= [-] ; collect in zooms
.NEXT
FRAMES ..= [ZOOMS] ; collect zooms in frames
.NEXT

support_label = FRAMES[2][0]

I guess I can live with that :)
2020-01-26 06:17
oziphantom

Registered: Oct 2014
Posts: 478
variables that are defined as := are defined in linear order and reset on each pass. So := before usage is required. By doing
x = variable

x is now a permanent value that remains across passes and hence the assembler can sub it in on the next pass for you.
RefreshSubscribe to this thread:

You need to be logged in to post in the forum.

Search the forum:
Search   for   in  
All times are CET.
Search CSDb
Advanced
Users Online
Kojote/Speckdrumm
Hero/ILLUSION
iAN CooG/HVSC
DeMOSic/HF^MS^BCC^LSD
Krill/Plush
Acidchild/Padua
Logiker/VCC
Zoid
Zorch
Shake/Role
t0m3000/ibex-crew
Exile/Anubis
Guests online: 291
Top Demos
1 Next Level  (9.8)
2 Mojo  (9.7)
3 Coma Light 13  (9.7)
4 Edge of Disgrace  (9.6)
5 No Bounds  (9.6)
6 Comaland 100%  (9.6)
7 Uncensored  (9.6)
8 The Ghost  (9.6)
9 Wonderland XIV  (9.6)
10 Bromance  (9.6)
Top onefile Demos
1 Party Elk 2  (9.7)
2 Cubic Dream  (9.6)
3 Copper Booze  (9.5)
4 Rainbow Connection  (9.5)
5 TRSAC, Gabber & Pebe..  (9.5)
6 Onscreen 5k  (9.5)
7 Dawnfall V1.1  (9.5)
8 Quadrants  (9.5)
9 Daah, Those Acid Pil..  (9.5)
10 Birth of a Flower  (9.5)
Top Groups
1 Booze Design  (9.3)
2 Nostalgia  (9.3)
3 Oxyron  (9.3)
4 Censor Design  (9.3)
5 Crest  (9.3)
Top Webmasters
1 Slaygon  (9.7)
2 Perff  (9.6)
3 Morpheus  (9.5)
4 Sabbi  (9.5)
5 CreaMD  (9.1)

Home - Disclaimer
Copyright © No Name 2001-2024
Page generated in: 0.072 sec.