Log inRegister an accountBrowse CSDbHelp & documentationFacts & StatisticsThe forumsAvailable RSS-feeds on CSDbSupport CSDb Commodore 64 Scene Database
 Welcome to our latest new user psenough ! (Registered 2024-05-21) You are not logged in - nap
CSDb User Forums


Forums > C64 Coding > Want to understand this way of looping through a table
2023-10-13 21:16
Flashback

Registered: Dec 2009
Posts: 4
Want to understand this way of looping through a table

Hi,

I would like some explanation about this way of looping a colour table:

colourcycle.asm

Basically it's this section I can't wrap my head around:
...
txa     ; select next colour index
adc #01
and #07 ; loop colour index
tax
...
colours  .byte 09, 08, 05, 13, 01, 13, 05, 08 ; colour table


As far as I understand, the start color is saved in a ZP address (startcol) which will is changed each frame. This is done by txa/ adc #$01 I guess. (BTW, why is there no clc before adc here?) But why do we need the and #$07?

Regards
2023-10-13 21:23
chatGPZ

Registered: Dec 2001
Posts: 11147
Quote:
BTW, why is there no clc before adc here?

To answer this first: it's a bug. It should be there :)

As for the AND... ANDing with any value that is (2^n)-1 will limit the value to 0...(2^n)-1. You basically throw away the upper bits.
2023-10-13 22:07
Flashback

Registered: Dec 2009
Posts: 4
Ok, so by ANDing with #$07 (%00000111) I delete bits 3-7, correct? So my result can't be > 7 as well.

Is this because I only have 8 entries in my colour table? So if I wanted to have more colours, I also would have to change this part?
2023-10-13 22:23
rosettif

Registered: Apr 2016
Posts: 10
Obviously, the author assumes C=0 for sure when entering the code, so it is just not needed (the CLC). Nevertheless, it would be better in this way (one byte shorter):

inx
txa
and #$07
tax

As long as you are thinking in power of two, it can be easily modified without the need of comparing (e.g. when having 16 colours instead of 8, the #$07 is replaced with #$0f).
2023-10-13 23:13
Copyfault

Registered: Dec 2001
Posts: 467
I'd also assume carry is taken care of somewhere in the code before that extracted section - but tbh, I did not check that asm yet.

So this is some index handling to get x = 0..7. In case one can live with an offset of 1, i.e. having the table starting at 1 instead of 0 of a page, the unintended sbx-opcode helps getting it even smaller:
lda #$07
sbx #$ff

This effetively slides through the values x = 1..8, with a footprint of 4 bytes and 4 cycles.
2023-10-14 10:04
Flashback

Registered: Dec 2009
Posts: 4
Thank you guys. Never used this approach, I would rather do something like

ldx tabindex
lda coltab,x
...
inx
cpx maxlength
bne skip
ldx #0
skip:
stx tabindex


Better understandable but of course longer ;)
2023-10-14 10:20
Oswald

Registered: Apr 2002
Posts: 5028
its a rule of thumb that when you get better in coding you write shorter more elegant and faster code, you need to move away from human thinking and think like the machine.
2023-10-14 11:28
chatGPZ

Registered: Dec 2001
Posts: 11147
Quote:
Obviously, the author assumes C=0 for sure when entering the code, so it is just not needed (the CLC).

Nothing in the source implies that :) It can only work correctly, if the main loop never sets C=1 (which is kinda unlikely :))
2023-10-16 10:33
Bitbreaker

Registered: Oct 2002
Posts: 501
i'd favour using sbx aswell when it is about incrementing x by any number and pplying an and operation.

Another option is to move the end condition of the loop into the table, and wrap the index depending on that. Color-register writes usually only need the lownibble.

        ...
        lda tab,x
        bpl +
        ldx #$ff
+
        inx
        ...

tab     !byte 9,8,5,13,1,13,5,$f8
2023-10-16 12:10
chatGPZ

Registered: Dec 2001
Posts: 11147
Or just count the index backwards :)
2023-10-16 13:06
Gordian

Registered: May 2022
Posts: 36
Another approach:

ldx index
...
lda #7
inx
sax index
2023-10-16 14:46
Copyfault

Registered: Dec 2001
Posts: 467
I'd say it won't get any shorter than doing it via sbx...

Hmm, maybe your table values allow for getting rid of that "lda #$07", but this only works for specific values, just as Bitbreaker mentioned in his post above.
2023-10-16 15:03
Gordian

Registered: May 2022
Posts: 36
Yes, not shorter, just another solution.
If accumulator is utilized before LDA or it's just not needed anymore, there are no cons.
Or LDY is used for getting values.
2023-10-16 15:55
Frostbyte

Registered: Aug 2003
Posts: 174
If you need to persist the value, is Gordian's solution then the shortest?

ldx zp_val	// 3
lda #$07	// 2
sbx #$ff	// 2
stx zp_val	// 3
// ...		// X = 1 to 8 here
// 8b, 10c

vs.
ldx zp_val	// 3
// ...		// X = 0 to 7 here
lda #$07	// 2
inx		// 2
sax zp_val	// 3
// ...		// X = 1 to 8 here
// 7b, 10c
2023-10-16 18:16
Copyfault

Registered: Dec 2001
Posts: 467
Quoting Frostbyte
If you need to persist the value, is Gordian's solution then the shortest?

ldx zp_val	// 3
lda #$07	// 2
sbx #$ff	// 2
stx zp_val	// 3
// ...		// X = 1 to 8 here
// 8b, 10c

vs.
ldx zp_val	// 3
// ...		// X = 0 to 7 here
lda #$07	// 2
inx		// 2
sax zp_val	// 3
// ...		// X = 1 to 8 here
// 7b, 10c
Yes, it's one byte shorter when you take the store commands to some temporary register into account. My thinking was about a loop that does not change X in its inner part, thus without any need for storing it inbetween.
2023-10-16 19:47
Gordian

Registered: May 2022
Posts: 36
Hi!

As I wrote above, lda #$07 can be moved outside inner loop:

lda #$07

ldx zp_val
;ldy table_value,x
;sty somewhere
inx
sax zp_val


So we have 2b and 2c shorter version.
2023-10-16 23:25
Copyfault

Registered: Dec 2001
Posts: 467
Quoting Gordian
Hi!

As I wrote above, lda #$07 can be moved outside inner loop:

lda #$07

ldx zp_val
;ldy table_value,x
;sty somewhere
inx
sax zp_val


So we have 2b and 2c shorter version.
In some rare cases, this might be possible, but usually accu is needed in an inner loop. I still think it'd be more feasible to get rid of the ldx/stx-opcodes (not saying that this is easier than to avoid usage of the accu in the inner loop). In the end, it all depends on what your loop is actually needed for.
2023-10-17 09:04
Rastah Bar

Registered: Oct 2012
Posts: 336
A bit similar to what Bitbreaker and chatGPZ said, but X is not cluttered and it works for values other than colors too:

	dec get_number:+1	;6
	bpl get_number:		;2/3
	lda #max_index		;2
	sta get_number:+1	;4

get_number:
	lda table

;table at page boundary
table
 BYTE number1, number2, …


- Works for any table size < 130;
- Uses ((tabel size-1)*9 + 14)/(table size) cycles on average, which is smaller than 10 cycles for tables with more than 5 elements;
- X (and Y) is not cluttered.
2023-10-23 10:10
Rastah Bar

Registered: Oct 2012
Posts: 336
About 1 cycle faster for sufficiently long tables is

	dec get_number:+1	;6
	bmi set_maxsize:	;2/3
get_number:
	lda table
        ...
        jmp $ea31

set_maxsize:
        lda #max_size           ;2
        sta get_number:+1       ;4
        jmp get_number:         ;3

;table at page boundary
table
 BYTE number1, number2, …
2023-10-23 15:11
Oswald

Registered: Apr 2002
Posts: 5028
Quote: A bit similar to what Bitbreaker and chatGPZ said, but X is not cluttered and it works for values other than colors too:

	dec get_number:+1	;6
	bpl get_number:		;2/3
	lda #max_index		;2
	sta get_number:+1	;4

get_number:
	lda table

;table at page boundary
table
 BYTE number1, number2, …


- Works for any table size < 130;
- Uses ((tabel size-1)*9 + 14)/(table size) cycles on average, which is smaller than 10 cycles for tables with more than 5 elements;
- X (and Y) is not cluttered.


this label: is horrible :P
2023-10-23 15:18
Rastah Bar

Registered: Oct 2012
Posts: 336
Sorry! Especially in the code, right? Like DEC get_number:+1
I use CBM Program Studio and the label in the code has to be exactly equal to the defined one.
2023-10-23 15:20
chatGPZ

Registered: Dec 2001
Posts: 11147
Seriously? Wow
2023-10-23 16:42
Frostbyte

Registered: Aug 2003
Posts: 174
I guess C64 studio syntax doesn't require to end the label definition with a colon like e.g. KickAssembler does, thus if you have one it just becomes part of the label string? So instead of "get_number" your label is actually "get_number:". :)

(sorry, drifting a bit off-topic here)
2023-10-23 16:55
Rastah Bar

Registered: Oct 2012
Posts: 336
Yes, it becomes part of the label string. But there must be better alternatives, a different character than a colon, or perhaps put the colon before the label name.
2023-10-23 17:31
Frostbyte

Registered: Aug 2003
Posts: 174
Why do you put the colon or other special char there in the first place? Wouldn't this work?
	dec get_number+1
	; ...

get_number
	lda table
2023-10-23 17:41
Rastah Bar

Registered: Oct 2012
Posts: 336
Yes, that would work, but now you don't see the difference between a label and a memory address. I could, for example, have given some zeropage address the name "get_number". In general, I like to see the difference between them.
2023-10-23 19:25
ws

Registered: Apr 2012
Posts: 229
Sorry for jumping in here, but i also use CBMprg Studio and not loosing track of what is what is actually a thing that bothered me too, so it boils down to a personal naming convention..
any functions/subroutines get for example named
does_thisthing

branches get named
loop1 or repeat1 ... or whatever, just using a number to identify them

and memory adresses get a descriptive functional name like
framekeep or tablpointr or something like that.

for me personally it worked so far. - other naming conventions might be much more practical, it is just an example.

but then again, for the fun of it, i normally lose any discipline in naming and formatting my code after 75% is done and the rest is then the most terrible spaghetti code ever with unreadable and confusing inserts here and there, add a little overdocumentation and the mess is complete

once i had a terrible mix up bug that i almost didn't find, because my comments stated like ";load tablepointer in x", while it actually contained a LDA
2023-10-23 20:51
Rastah Bar

Registered: Oct 2012
Posts: 336
Everytime I start a new project I become more disciplined. When you just keep going till the project is finished, it often goes well, but if you stop for a while and want to finish it some time later, then it can take a long time to unravel the mess.
2023-10-24 11:59
TheRyk

Registered: Mar 2009
Posts: 2085
@Rastah Bar yeah... and more often than not - after spending hours or evenings of cleaning up the mess that once went through as good code for your past self, you just regret not having started from scratch again (which might have even saved time and a bunch of bugs resulting only from messing around with old messy code) :)
2023-10-24 13:13
Rastah Bar

Registered: Oct 2012
Posts: 336
Recoding part of it can definitely help. Instead of looking at the screen and trying to figure it out, recoding may tell you quicker what you were doing and perhaps show some bugs, too.
2023-10-25 10:18
Krill

Registered: Apr 2002
Posts: 2854
Quoting Oswald
this label: is horrible :P
Indeed.

The point of a colon after a label definition is to tell it apart from references to that label.

So you can easily search for that label while conveniently not having to skip over all the references to that label.

Having to add the colon to all references as well is pointless, could just as well have everything without colons, like the OG Turbo Assembler did. =)
2023-10-25 10:47
Oswald

Registered: Apr 2002
Posts: 5028
Quote: Quoting Oswald
this label: is horrible :P
Indeed.

The point of a colon after a label definition is to tell it apart from references to that label.

So you can easily search for that label while conveniently not having to skip over all the references to that label.

Having to add the colon to all references as well is pointless, could just as well have everything without colons, like the OG Turbo Assembler did. =)


ah I didnt know this! finally colon makes sense, but one clever text editor could just show the label without any preceeding characters, I prefer turbo asm way till death :)
2023-10-25 10:51
Krill

Registered: Apr 2002
Posts: 2854
Quoting Oswald
ah I didnt know this! finally colon makes sense, but one clever text editor could just show the label without any preceeding characters, I prefer turbo asm way till death :)
You'll quickly end up with an IDE again, and i love me my not-too-smart text editors (like KATE aka KEdit). :)
2023-10-25 12:15
Rastah Bar

Registered: Oct 2012
Posts: 336
Quote: Quoting Oswald
this label: is horrible :P
Indeed.

The point of a colon after a label definition is to tell it apart from references to that label.

So you can easily search for that label while conveniently not having to skip over all the references to that label.

Having to add the colon to all references as well is pointless, could just as well have everything without colons, like the OG Turbo Assembler did. =)


If you want to make clear the difference between labels and memory addresses, how do yo do that? For example, labels all in lowercase letters and memory addresses start with a capital?
2023-10-25 12:33
chatGPZ

Registered: Dec 2001
Posts: 11147
but labels are memory addresses?

*runs*
2023-10-25 12:35
Krill

Registered: Apr 2002
Posts: 2854
Quoting Rastah Bar
If you want to make clear the difference between labels and memory addresses, how do yo do that? For example, labels all in lowercase letters and memory addresses start with a capital?
Yes, by convention, if need be. It's nothing that needs to be enforced by the toolchain.

My personal convention is all-lower-case for regular labels and allcaps for labels with literally assigned addresses (either by asm source or via linker script). The latter are constants, after all.
2023-10-25 14:06
Rastah Bar

Registered: Oct 2012
Posts: 336
@chatGPZ: yes, that's true, but I find code a bit easier to read when I see immediately what everything is. But maybe it does not matter in this case.

@Krill: thanks, I will try out some naming conventions.
2023-10-25 22:25
Frostbyte

Registered: Aug 2003
Posts: 174
This discussion should really be under its own topic (maybe moderators can move it?), but anyway, my 2 eurocents. I've tried a few naming conventions in KickAssembler, and pretty much settled with the following.

Address pointers (i.e. labels), variables and constants are all lowercase, words separated by underscore. E.g.
      jsr reticulate_splines
      ......

  reticulate_splines:
      lda #next_spline_to_reticulate


Zero page labels are wrapped under "zp" namespace:
  .namespace zp {
      .label current_player_state = $02
      .label spline_tbl_ptr       = $03
  }

      .......
      lda #0
      sta zp.current_player_state

I use namespaces (even recursive ones) for other special addresses too, e.g. sid and vic and other fixed addresses. This allows me to use dot notation, which imho is very readable, e.g.
      lda freq_table_lo, y
      sta sid.ch1.freqlo

For macros I use PascalCasing:
      MoveCursorTo(15, 13)

...and that's about it. Very simple, really. Namespaces are a godsend, I can easily assign the same context to a bunch of labels or values, and while using them, dot notation separates them clearly from the usual labels or variable names. I don't know how many other dialects have namespaces or a similar concept, unfortunately. Some dialects probably allow adding dots to label names, making naming nearly as neat as using namespaces.

Earlier I tried using all uppercase for ZP variables, constants etc., but ditched it later as it made the code messier to read.
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
Asphodel
Acidchild/Padua
Slajerek/Samar
rambo/Therapy/ Resou..
A3/AFL
WVL/Xenon
Guests online: 117
Top Demos
1 Next Level  (9.8)
2 13:37  (9.7)
3 Coma Light 13  (9.7)
4 Edge of Disgrace  (9.6)
5 Mojo  (9.6)
6 Comaland 100%  (9.6)
7 Uncensored  (9.6)
8 No Bounds  (9.6)
9 Bromance  (9.5)
10 Wonderland XII  (9.5)
Top onefile Demos
1 Layers  (9.6)
2 Cubic Dream  (9.6)
3 Party Elk 2  (9.6)
4 Copper Booze  (9.6)
5 TRSAC, Gabber & Pebe..  (9.5)
6 Rainbow Connection  (9.5)
7 It's More Fun to Com..  (9.5)
8 Dawnfall V1.1  (9.5)
9 Quadrants  (9.5)
10 Daah, Those Acid Pil..  (9.5)
Top Groups
1 Oxyron  (9.3)
2 Booze Design  (9.3)
3 Censor Design  (9.3)
4 Crest  (9.3)
5 Performers  (9.3)
Top Coders
1 Axis  (9.8)
2 Graham  (9.8)
3 Lft  (9.8)
4 Crossbow  (9.8)
5 HCL  (9.8)

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