How do you know if your code is structured well enough?

This is an archive of a topic from NESdev BBS, taken in mid-October 2019 before a server upgrade.
View original topic
How do you know if your code is structured well enough?
by on (#151618)
I always have this problem where I don't know if my code is structured properly. Does anybody have advice for code structure?

I'll post my source code after fixing a couple of misleadingly named asm-files, so you could give me some feedback on what I should fix.
Re: How do you know if your code is structured well enough?
by on (#151621)
I think it being "structured well enough" depends on what it is. There's usually a best way to do things, and that depends on what you're trying to do, so we can't really help you until we see what it is. (And unfortunately, I probably won't really be able to help you because of my moderate lack of experience.)
Re: How do you know if your code is structured well enough?
by on (#151623)
I just had to change "object.txt" to "plasma grinch.txt"
Re: How do you know if your code is structured well enough?
by on (#151626)
Well dang, I don't think I'll be able to understand this at all. One reason it's hard to know how your code works is because instead of writing something like

Code:
vram_finder_loop:

you write:

Code:
+

So you have to meticulously look through the whole thing.
Re: How do you know if your code is structured well enough?
by on (#151627)
Sometimes I'll use the anonymous labels in ca65 (the : labels), but never for a loop longer than 25 lines. Once the other end of a loop is more than 10 lines away, it's time to think of a name if at all possible.
Re: How do you know if your code is structured well enough?
by on (#151629)
psycopathicteen wrote:
I always have this problem where I don't know if my code is structured properly. Does anybody have advice for code structure?


Trying to read through that code is problematic.

The main issue I'm having is trying to determine the context of the various variables and routines.

For example; timer. I'm guessing (by its location in defines.txt) that its an animation frame timer for the metasprite subsystem, but its name suggests it could also be; a global level timer, an attack cool-down timer, etc.


I would recommend you come up with some system to remove that ambiguity.

I personally prefix all my variables and labels by module/type (ie, EntityPhysics__, z:EntityPhysicsStruct::, etc) which makes it a lot easier to determine the context of the variable. It does mean more typing, but it was the first form of structuring I did with assembly and has been extremely helpful in understanding code past-me wrote.


The second thing I recommend is writing some comments about the parameters/state of each routine. That way you don't have to search through the code to find the JSR that calls it and manually derive the parameters and CPU state. For example:
Code:
; IN: X = xpos, Y = ypos
; OUT: A = color
; A16, I16, DB=$7E
PixelBuffer__GetPixel:


Espozo wrote:
you write: +

So you have to meticulously look through the whole thing.

I personally have no problem with +/- labels and do use them with them with other processors. I'm not using them in my SNES projects because ca65 doesn't fully support them.
Re: How do you know if your code is structured well enough?
by on (#151635)
Ugh! This looks harder than I thought.
Re: How do you know if your code is structured well enough?
by on (#151636)
When writing code you'll know what's going on so you can write something that isn't very easy to follow for someone else. But then if a lot of time passes, you might find yourself wondering what is going on when you come back to it.

So you definitely want to be sure that there are either well named functions and variables that no explanation is needed or you should have sufficient comments to explain what is going on in each section with any necessary details. It always helps to have comments written when you write the code to describe what you're doing, how, and why.
Re: How do you know if your code is structured well enough?
by on (#151644)
I could move the level map and level enemy list into another file, and name it level data.
Re: How do you know if your code is structured well enough?
by on (#151646)
UnDisbeliever wrote:
I personally have no problem with +/- labels and do use them with them with other processors. I'm not using them in my SNES projects because ca65 doesn't fully support them.

Out of curiousity: what do you miss from ca65's implementation of unnamed labels?
Re: How do you know if your code is structured well enough?
by on (#151653)
Might as well throw in an opinion. I never use +/- labels myself, but they're good for short local branches. Coming up with a unique appropriate name for every label is time consuming and I've gotten used to calling things whatever nonsense pops into my mind first, which results in some real gems like "_BCDScrnotNineCollP2CollCalc". Not terribly useful for telling what's going on. It's also a pain when copying similar pieces of code to meticulously rename everything, when relative labels like +/- would remain correct.

I've introduced a lot of bugs into my code simply by forgetting to change the label on a jump instruction and jumping to the wrong place. I'm actually grateful branches only reach 128 bytes - I catch tons of errors simply because branching to the incorrect label is usually too far away.

As for the rest, all I would suggest is a bit more commenting along the way. I tend to overdo it, to the point where MOST lines of code have a comment next to them, which is probably a bad thing: It's painstaking to ensure my comments remain correct as I edit my code. Sometimes I'm misled because a comment says one thing and the code says another. Still, coming back to a routine months later, I never have to wonder what I was thinking when I wrote it. I try to keep it down to only commenting on things that are not immediately obvious by reading the code itself.

One habit I like is putting a header at the top of each file/subroutine to briefly explain what it does and to keep all the relevant information in one place. For example, I'll list any prerequisites for calling it (must be 16-bit AXY, JoyXRaw must be in register X, etc...), and even reference information so I don't have to keep looking it up (eg/ Tilemap Entries are vhop ppcc cccc cccc).

I also keep my code one indent in from the labels, just because it's easier for me to read that way. Personal preference.

Unless you plan on other people needing to read your source code, I would say it's entirely up to you so long as you'll be able to understand it when you come back later.
Re: How do you know if your code is structured well enough?
by on (#151658)
The best way to learn about good code structure is to read a lot of code written by other people, and also write a lot of code yourself. You will learn a lot by reading other code.

Writing good code takes experience. I don't think someone can give you tips or tell you how to do it. Telling you how to do it for a specific case is pretty much the same job as writing the code itself. Doing it in the general case requires critical thinking in response to the situation.

Keep working, keep learning, and it will come to you.

I suppose the only way to measure how good your code is, is to work with other peoples' code and compare them to your own?
Re: How do you know if your code is structured well enough?
by on (#151665)
Comparing it with someone else's code sounds like a good idea. Maybe I can look at somebody's v-blank routine, and compare it with mine.
Re: How do you know if your code is structured well enough?
by on (#151666)
Well psychopathicteen, I'd be able to compare my code with yours when I've done more, since we seem to be doing the same general thing. You've even used some of the ideas I've came up with, which I'm fine with me because I wouldn't have said them if I wanted them to be secret. You know, how many people are doing stuff for SNESDev? Here's a list of people I can think of:

93143 (Do you know what that number is even from, if anything?)
Espozo (I'm trying, at least)
Khaz (I think?)
Psychopathicteen
Ramsis
Undisbeliever
Re: How do you know if your code is structured well enough?
by on (#151671)
I think of dforce3000 (N-Warp Daisauksen) and mukunda (Skipp and Friends), actually, when I think of source code.

I have my own v-blank routines, but it's under construction (and currently abandoned). It's functional enough that it can make graphics appear on the screen, but I haven't been able to do a real benchmark yet.
Re: How do you know if your code is structured well enough?
by on (#151683)
One more tiny structural habit that just occured to me that I wonder if others do: I put an empty line following every branch instruction. I find it makes it easier to see how the program flows at a glance, and helps to not miss a label when renaming all my branches as per my last post.
Espozo wrote:
Khaz (I think?)

Depends on your definition of "for SNESDev". I've tried to share my methods and any tools I come up with along the way, and I very much enjoy helping others with whatever problems they may have. The game I'm developing is explicitly for me, though. I may try to sell it, I may post it up for free, I have no idea yet... But I'm reserving all rights and being very paranoid about the source code and detailed plans (and the tiny few graphical assets I've actually put work into) right now, because I'm a very paranoid person by nature.

I might post up a demo ROM at some point in the nearish future, once I have the game engine complete and after I've taken the requisite copyright precautions just in case.

If/when the game is done and "published" in whatever way is appropriate I'll probably release the full source code too. Mostly because my collision calculation routine could easily be used to FINALLY make a proper Sonic port on SNES. Just don't hold your breath, that's a long way off...

I'd gladly post up a relevant piece of code just to show what it looks like, but I dunno about my vBlank routine, it's a mess at the moment.
Re: How do you know if your code is structured well enough?
by on (#151689)
Khaz wrote:
a proper Sonic port on SNES

I'm still amazed that this hasn't been done yet. Also, don't forget to add a debug mode. :wink:
Re: How do you know if your code is structured well enough?
by on (#151692)
Either you put space before your instructions, or you don't. Maybe that's just me.
Re: How do you know if your code is structured well enough?
by on (#153219)
Khaz wrote:
One habit I like is putting a header at the top of each file/subroutine to briefly explain what it does and to keep all the relevant information in one place. For example, I'll list any prerequisites for calling it

Those're called the preconditions of a function; what must be true before it begins executing. The postconditions of a function are, similarly, what must be true after it finishes.
Khaz wrote:
Unless you plan on other people needing to read your source code, I would say it's entirely up to you so long as you'll be able to understand it when you come back later.
One generally is another person by the time you "come back later".
Re: How do you know if your code is structured well enough?
by on (#153220)
Myask wrote:
One generally is another person by the time you "come back later".

I went back to some code I made I hadn't touched for over a month and I read it just fine. Maybe I just structure everything really well or something. Then again, it looks like this:

Code:
look_for_16x16_vram:
   cpy #$0080            ;128, because there are 128 slots for sprites
   beq vram_finder_done         ;no space left for sprite
   lda VramTable,y   
   beq slot_found         ;there is space for another sprite
   iny
   bra look_for_16x16_vram      ;look again if the space is already occupied

look_for_32x32_vram:
   cpy  #$0080                  ;128, because there are 128 slots for sprites
   beq  vram_finder_done            ;no space left for sprite
   lda  VramTable,y               ;upper lefthand corner of square
   bne  prepare_for_look_for_32x32_vram   ;look again if the space is already occupied
   lda  VramTable+1,y               ;upper righthand corner of square
   bne  prepare_for_look_for_32x32_vram   ;look again if the space is already occupied
   lda  VramTable+8,y               ;lower lefthand corner of square
   bne  prepare_for_look_for_32x32_vram   ;look again if the space is already occupied
   lda  VramTable+9,y               ;lower righthand corner of square
   bne  prepare_for_look_for_32x32_vram   ;look again if the space is already occupied
   bra  32x32_slot_found            ;there is space for another sprite
Re: How do you know if your code is structured well enough?
by on (#153221)
I'm a bit curious as to why you'd write:
Code:
cpy #$0080 ; 128

instead of just:
Code:
cpy #128
Re: How do you know if your code is structured well enough?
by on (#153224)
I think it had something to do with the bits for the DMA controller, in that the number 128 isn't important, only that the high bit is set. I do things like that when I'm dealing with video hardware and stuff. I'm not too sure why I wrote the 128 side note though, because thinking in terms of numbers isn't very important here like I said.
Re: How do you know if your code is structured well enough?
by on (#153225)
Espozo: Because it's densely-commented (perhaps a little too-densely) and the labels/variable names are verbose.

rainwarrior: hmm. If I did it it'd be to imply to the reader that it's a 16-bit operation (even if it's the province of processor flags as to whether that's how it executes).
Re: How do you know if your code is structured well enough?
by on (#153227)
Actually, never mind about me writing #$80 instead of 128. I though that was talking about something else, but it's really just talking about how many sprites there are, so I also don't have a clue.

Myask wrote:
Because it's densely-commented (perhaps a little too-densely)

It doesn't look as clustered in notepad for whatever reason.

Myask wrote:
the labels/variable names are verbose.

I don't see how you'd really use less. Anyway, what I wrote works just fine for me.
Re: How do you know if your code is structured well enough?
by on (#153236)
Personally I prefer being verbose with labels (as well as function names, properties and what-not in high level languages). I left short cryptic names behind when I left the C64 with Turbo Assembler (fitting the editor/assembler and the code produced on the same 64KB machine sounds like complete madness today but worked surprisingly well).

Espozo: Your "look_for_16x16_vram" routine (if not just an example of coding style) could use a quicker look-up algorithm. Looping through up to 128 entries to find an empty slot (or returning a failed allocation) will eat up your frame time quickly!
Re: How do you know if your code is structured well enough?
by on (#153246)
Optiroc wrote:
Espozo: Your "look_for_16x16_vram" routine (if not just an example of coding style) could use a quicker look-up algorithm. Looping through up to 128 entries to find an empty slot (or returning a failed allocation) will eat up your frame time quickly!

This is actually my older code that I just came back to to fix. I had recently thought of the idea of having 2 128 entry tables, where one table is for 16x16 sized sprites, and the other is for 32x32 sized sprites, with each entry being 3 words instead of 4 because I don't need to say the size anymore, so it will look like this:

Table in Rom:

Sprite / Transfer Size = 0
BankNumber = 2
TileAdress = 4

Table in Ram:

VramAdress = 0 (I obviously don't know the vram address when in rom, and the size has been sorted)
BankNumber = 2
TileAdress = 4

The reason I'm doing this is because although there is a little extra processing to sort things into different tables, I don't need to check the sprite / transfer size for every sprite, and only need to look at the request counter for 16x16 sized sprites, and then move to 32x32 sized sprites which isn't any more in terms of processing to just check one big request counter like I had originally. However, the main advantage to this is that in the vram finder code, If I'm only doing 16x16, and then 32x32, I won't need to jump back to the beginning of the table, because I know it's filled out as much as it can be because it's originally all 16x16's, which can fit anywhere, unlike 32x32's which can only work if 4 spaces are clear. However, if I see myself running out of space in vram, I could have it to where all 32x32's go first, and 16x16's go second, but start at the beginning of the table unlike if 16x16's went first because there are plenty of spots where 16x16's fit and 32x32's don't, unlike the other way around. This would ensure that the 16x16's don't take a spot where a 32x32 could be when there's enough space for them that won't affect 32x32's like a spot that already has a 16x16 left from a previous frame.
Re: How do you know if your code is structured well enough?
by on (#153257)
I think this is better

Code:
VramAdress = 0
Size = 0
BankNumber = 2
TileAdress = 4



start_vram_finder:
  rep  #$30   ; A=16, X/Y=16
  stz  32x32ColumnSkipperCounter
  ldx  #$0000
  ldy  #$0000
  cpx  32x32TileRequestCounter
  beq  16x16_vram_finder_start

look_for_32x32_vram:
  cpy  #$0080               ;128, because there are 128 slots for sprites
  beq  vram_finder_done            ;no space left for sprite
  lda  VramTable,y            ;upper lefthand corner of square
  bne  prepare_for_look_for_32x32_vram      ;look again if the space is already occupied
  lda  VramTable+1,y            ;upper righthand corner of square   
  bne  prepare_for_look_for_32x32_vram      ;look again if the space is already occupied
  lda  VramTable+8,y            ;lower lefthand corner of square
  bne  prepare_for_look_for_32x32_vram      ;look again if the space is already occupied
  lda  VramTable+9,y            ;lower righthand corner of square
  bne  prepare_for_look_for_32x32_vram      ;look again if the space is already occupied

32x32_slot_found:
  lda  #$01
  sta  VramTable,y      ;say that four of the slots are now taken
  sta  VramTable+1,y
  sta  VramTable+8,y
  sta  VramTable+9,y
  sty  32x32TileRequestTable+VramAdress,x
  cpx  32x32TileRequestCounter
  beq  16x16_vram_finder_start
  inx
  inx
  inx
  inx
  bra  look_for_32x32_vram     

prepare_for_look_for_32x32_vram:
  inc  32x32ColumnSkipperCounter
  cmp  #$08
  beq  next_row
  iny
  iny
  bra  look_for_32x32_vram

next_row:
  tya            ;If this is done right, this should skip every other row of tiles
  adc  #$08
  tay
  bra  look_for_32x32_vram


32x32_vram_finder_start:
  ldx  #$0000
  ldy  #$0000
  cpx  32x32TileRequestCounter
  beq  16x16_vram_finder_start

look_for_16x16_vram:
  cpy  #$0080         ;128, because there are 128 slots for sprites
  beq  vram_finder_done      ;no space left for sprite
  lda  VramTable,y   
  beq  slot_found      ;there is space for another sprite
  iny
  bra  look_for_16x16_vram   ;look again if the space is already occupied

16x16_slot_found:
  inc  VramTable,y      ;say that one of the slots is now taken
  sty  16x16TileRequestTable+VramAdress,x
  cpx  16x16TileRequestCounter
  beq  vram_finder_done
  inx
  inx
  inx
  inx
  bra  look_for_16x16_vram

vram_finder_done:
  rts

One thing that still needs to be done is the figured out address for the 16x16 tiles needs to be converted into and address to work with 8x8 tiles, but I've been holding off on it because I don't even think I'll have it to where 1 entire byte represents a 16x16 area. If it's the fastest way, I'll keep it, but if it isn't, I'll change it. What are you doing, psychopathicteen?
Re: How do you know if your code is structured well enough?
by on (#153275)
I have it so each byte represents 4 16x16s or 1 32x32.
Re: How do you know if your code is structured well enough?
by on (#153281)
I figured I'd do it too, as it takes less space and it's only one check for 32x32 sized sprites instead of four, but I ran into a problem: How do you translate it to where it's the tile number? Also, I guess you don't need to do anything special with 32x32 sprites every 8 of them (which is normally where the next row starts)? :oops:

Edit: Hey, I actually thought of one thing, if this makes a difference. When checking the byte for a spot out of the 4 that the sprite will fit, instead of doing this:

Code:
  lda  VramTable,y
  bit  #$11000000
  bne  16x16_slot_found
  bit  #$00110000
  bne  16x16_slot_found
  bit  #$00001100
  bne  16x16_slot_found
  bit  #$00000011
  bne  16x16_slot_found

You could have each one have its own code that it jumps to, like this:

Code:
  lda  VramTable,y
  bit  #$11000000
  bne  16x16_slot1_found
  bit  #$00110000
  bne  16x16_slot2_found
  bit  #$00001100
  bne  16x16_slot3_found
  bit  #$00000011
  bne  16x16_slot4_found

That way, you shouldn't have to worry about any of the bits in the byte, only the address of the byte.
Re: How do you know if your code is structured well enough?
by on (#153283)
Please tell me there's a simpler way to doing it than what I just devised: (I'd only bothered with 32x32 sprites so far)

Code:
  rep #$30   ; A=16, X/Y=16
  tya
  and #$FFFC
  asl
  asl
  asl
  asl
  sta IDoNotKnowWhatToNameThisYet

  tya
  and #$0003
  asl
  asl
  adc IDoNotKnowWhatToNameThisYet
  sta 32x32TileRequestTable+VramAdress,x
  sep #$20   ; A=8

If I'm not mistaken, these numbers:

1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15

Would be converted into these numbers:

0, 4, 8, 16, 64, 68, 72, 76, 128, 132, 136, 140, 192, 196, 200, 204



Wait a minute, wouldn't it be a lot easier to use a lookup table? It would only have to be 64 bytes long and would save a lot of processing.
Re: How do you know if your code is structured well enough?
by on (#153288)
You could use a LUT if the X register is free. But assuming that by 0, 4, 8, 16 you mean 0, 4, 8, 12, prepare to expand your mind.

You can think of asl instruction as standing for Add to SeLf. If you mask off the bits you don't want to shift, you can add the rest of the number to itself to shift only the bits you haven't masked.
Code:
  ; assuming 8-bit A, we have 22 cycles
  and #$0F     ; 0000dcba
  asl a        ; 000dcba0
  asl a        ; 00dcba00
  sta tmpbits
  and #$F0     ; 00dc0000
  adc tmpbits  ; 0dc0ba00
  sta tmpbits
  and #$F0     ; 0dc00000
  adc tmpbits  ; dc00ba00

I do this in 8x16 text printing routines in some situations, shifting bits 6-4 of the character code to bits 7-5 of the tile number while preserving bits 3-0.
Re: How do you know if your code is structured well enough?
by on (#153289)
tepples wrote:
You could use a LUT if the X register is free

Y is free, and it's convenient here because it's already the number of the byte.

This is what I have now:

Code:
VramAdress = 0
Size = 0
BankNumber = 2
TileAdress = 4



start_vram_finder:
  rep  #$30   ; A=16, X/Y=16
  sep #$20   ; A=8

  stz  32x32ColumnSkipperCounter
  ldx  #$0000
  ldy  #$0000
  cpx  32x32TileRequestCounter
  beq  16x16_vram_finder_start

look_for_32x32_vram:
  cpy  #$0020               ;128, because there are 128 slots for sprites
  beq  vram_finder_done            ;no space left for sprite
  lda  VramTable,y
  beq  32x32_slot_found
  iny
  bra  look_for_32x32_vram

32x32_slot_found:
  lda  #$FF
  sta  VramTable,y      ;say that four of the slots are now taken

  rep  #$30   ; A=16, X/Y=16
  lda  VramAdressConverterTable,y
  sta  32x32TileRequestTable,x
  sep  #$20   ; A=8

  cpx  32x32TileRequestCounter
  beq  16x16_vram_finder_start
  inx
  inx
  inx
  inx
  inx
  inx
  bra  look_for_32x32_vram






32x32_vram_finder_start:
  ldx  #$0000
  ldy  #$0000
  cpx  32x32TileRequestCounter
  beq  16x16_vram_finder_start

look_for_16x16_vram:
  cpy  #$0020         ;128, because there are 128 slots for sprites
  beq  vram_finder_done      ;no space left for sprite
  lda  VramTable,y
  bit  #$11000000
  bne  16x16_slot0_found   ;there is space for another sprite
  bit  #$00110000
  bne  16x16_slot1_found   ;there is space for another sprite
  bit  #$00001100
  bne  16x16_slot2_found   ;there is space for another sprite
  bit  #$00000011
  bne  16x16_slot3_found   ;there is space for another sprite
  iny
  bra  look_for_16x16_vram   ;look again if the space is already occupied


16x16_slot0_found:
  inc  VramTable,y      ;say that one of the slots is now taken

  rep  #$30   ; A=16, X/Y=16
  lda  VramAdressConverterTable,y
  sta  16x16TileRequestTable,x
  sep  #$20   ; A=8

  cpx  16x16TileRequestCounter
  beq  vram_finder_done
  inx
  inx
  inx
  inx
  inx
  inx
  bra  look_for_16x16_vram


16x16_slot1_found:
  inc  VramTable,y      ;say that one of the slots is now taken

  rep  #$30   ; A=16, X/Y=16
  lda  VramAdressConverterTable,y
  clc
  adc  #$0002
  sta  16x16TileRequestTable,x
  sep  #$20   ; A=8

  cpx  16x16TileRequestCounter
  beq  vram_finder_done
  inx
  inx
  inx
  inx
  inx
  inx
  bra  look_for_16x16_vram


16x16_slot2_found:
  inc  VramTable,y      ;say that one of the slots is now taken

  rep  #$30   ; A=16, X/Y=16
  lda  VramAdressConverterTable,y
  clc
  adc  #$0020
  sta  16x16TileRequestTable,x
  sep  #$20   ; A=8

  cpx  16x16TileRequestCounter
  beq  vram_finder_done
  inx
  inx
  inx
  inx
  inx
  inx
  bra  look_for_16x16_vram


16x16_slot3_found:
  inc  VramTable,y      ;say that one of the slots is now taken

  rep  #$30   ; A=16, X/Y=16
  lda  VramAdressConverterTable,y
  clc
  adc  #$0022
  sta  16x16TileRequestTable,x
  sep  #$20   ; A=8

  cpx  16x16TileRequestCounter
  beq  vram_finder_done
  inx
  inx
  inx
  inx
  inx
  inx
  bra  look_for_16x16_vram


vram_finder_done:
  rts



VramAdressConverterTable:
  .word 0,4,8,12,64,68,72,76,128,132,136,140,192,196,200,204
  .word 256,260,264,268,320,324,328,332,384,388,392,396,448,452,456,460
Re: How do you know if your code is structured well enough?
by on (#153356)
Man... you guys need some macros ;>_>


Also, you could get rid of those INXs. A nice txa, clc, adc #const, tax would cut some cycles out, but it'd also make the listing more compact. I mean, doesn't look like the contents of Acc matter for the inx area.


When you start writing tens of thousands of lines of asm code per "include" bank/file/whatever, things get messy to read or scroll through. Macros are great for code clarity, a compact the listing, and usually proves to be less work for making changes. I also do a lot more leading white space now for asm, as well as different levels of indents to keep track of certain instructions (makes them easier to see/pick up); the more to the right de-emphasizes the instruction, and more to the left emphasizes it. I usually add a lot of title bars (different kinds) to help separate code segments as well as ending lines (usually dots/segments). Some are more pronounced than others.
Re: How do you know if your code is structured well enough?
by on (#153357)
tomaitheous wrote:
Also, you could get rid of those INXs. A nice txa, clc, adc #const, tax would cut some cycles out, but it'd also make the listing more compact.

Yeah, I really don't know what I was doing there...

Edit: Actually, wait, I know what I was doing there. I didn't want to have to change the accumulator size to 16 bit just for that, because it would really be:

rep #$30, txa, clc, adc #const, tax, sep #$20

Anyway, I don't really want to deal with the hassle of setting up macros though.
Re: How do you know if your code is structured well enough?
by on (#153366)
Am I the only one with a weird habit of intentionally avoiding macros? I just don't like them, because when first starting out with assembly people got onto me for being too macro-heavy (since it made my code have no subroutines and therefore be redundant).
Re: How do you know if your code is structured well enough?
by on (#153370)
nicklausw wrote:
Am I the only one with a weird habit of intentionally avoiding macros?

I just about try to avoid them too.
Re: How do you know if your code is structured well enough?
by on (#153376)
I actually attempted macros on WLA DX. I partially abandoned them as a result of me attempting some magic that ended up failing quite horribly.
Re: How do you know if your code is structured well enough?
by on (#153377)
KungFuFurby wrote:
I actually attempted macros on WLA DX.

Eeyup. Not the greatest idea.
Re: How do you know if your code is structured well enough?
by on (#153394)
nicklausw wrote:
when first starting out with assembly people got onto me for being too macro-heavy (since it made my code have no subroutines and therefore be redundant).

I'd have thought that would only be bad if you cared about code size. Macros are faster and just as easy to maintain.

Unrolled loops are by no means as easy to maintain as regular loops, yet they're still considered good practice if speed is important...
Re: How do you know if your code is structured well enough?
by on (#153398)
What exactly is an "unrolled loop"? :oops: I've probably done them several times, but I just don't know what it is and I've heard it several times.
Re: How do you know if your code is structured well enough?
by on (#153401)
Hopefully somebody will correct me if I'm wrong, but I believe it's when, instead of creating a loop that performs a repeated task multiple times for multiple pieces of data, you essentially lay out each cycle of the loop as it's own step. This takes a lot more space, is a lot less maintainable, is uglier, but ultimately it can save you a few CPU cycles by not performing excess tests for the exit conditions of your loop.
Re: How do you know if your code is structured well enough?
by on (#153403)
If you're willing to use macros or other assembler help, unrolled loops are only "takes a lot more space".

For example, ca65 supports the ".repeat / .endrep" command:
Code:
 .repeat 16, count
  lda $0200+count
  sta $2007
 .endrep
Re: How do you know if your code is structured well enough?
by on (#153404)
Here's two examples...unrolled loops

Code:
LDA buffer
Sta $2007
LDA buffer + 1
Sta $2007
LDA buffer + 2
Sta $2007
Etc... until all PPU updates done


Or the more efficient...
Code:
Pla
Sta $2007
Pla
Sta $2007
Pla
Sta $2007
Etc... until all PPU updates done


Edit. They use the same # of cycles.
Re: How do you know if your code is structured well enough?
by on (#153406)
How is "PLA" a substitute for "LDA buffer", unless you said "LDA buffer, PHA" a bunch of times, which is even slower?
Re: How do you know if your code is structured well enough?
by on (#153407)
PLA means pull value from stack into accumulator, so I'm guessing that example would have involved pushing (PHA) the values onto the stack first.

I just have to ask because this example made me wonder. You're pulling values from the stack and writing them to the PPU, so you're inside of NMI, however, when you go into NMI it pushes the return address to the stack, so do you then pull that back and store it and then push it before RTI, or something else?

I'm wondering because I know it's nonsense example code but I got the sense that you do something like it because you chose that example. I've considered using the stack for things like preloading background tiles, but just the fact that I'd have to pull the return address off and store it made me reconsider trying the stack route on that.
Re: How do you know if your code is structured well enough?
by on (#153408)
darryl.revok wrote:
PLA means pull value from stack into accumulator

I know, it's that those values would have needed to be pushed on the stack to begin with, which at the end of it all, is needlessly more complicated and slower than just "LDA buffer".
Re: How do you know if your code is structured well enough?
by on (#153409)
You would (outside of vblank) store the stack pointer, change it to maybe #$80, PHA all your updates, change the the stack pointer back to original. Wait for vblank. Store the stack pointer. Change it to #$80 - # of updates, the do the PLA, STA bit. When done, change it back.

Well, that sounds like a pain in the ass, doesn't it? I originally thought it would be more efficient cycle-wise, but it's not.
Re: How do you know if your code is structured well enough?
by on (#153411)
Isn't that just a tradeoff between VBlank time and non VBlank time? I think that example would do more harm than good.

Quote:
I originally thought it would be more efficient cycle-wise, but it's not.

Yeah.
Re: How do you know if your code is structured well enough?
by on (#153413)
You don't need to use PHA to assemble the loop. You could use absolute,X addressing, for example.

The nice thing about a stack-sourced blitter is that it's general purpose, and could be reused for multiple different buffers. The entry point and value of S when you start exactly determine which and how many bytes.

PLA / STA $2007 is 4 bytes, so calculating the entry point is even pretty easy.
Re: How do you know if your code is structured well enough?
by on (#153415)
lidnariq wrote:
You don't need to use PHA to assemble the loop. You could use absolute,X addressing, for example.

The nice thing about a stack-sourced blitter is that it's general purpose, and could be reused for multiple different buffers. The entry point and value of S when you start exactly determine which and how many bytes.

PLA / STA $2007 is 4 bytes, so calculating the entry point is even pretty easy.


This went over my head a bit, but I'm pretty curious as to what you mean so I hope you don't mind if I ask a couple questions.

First, the term blitter is a new one for me. I see from Wikipedia:

Quote:
In a computer system, a blitter is a circuit, sometimes as a coprocessor or a logic block on a microprocessor, that is dedicated to the rapid movement and modification of data within that computer's memory.


So in this instance, you just mean kind of like a buffer or place to store data that will be written and loaded often?

I used the stack to store collisions that have taken place in a frame, the owners and angle, and then I pull those and assign the data to it's owner after the collision routine. The stack concept is new to me but it seemed like an elegant way to address that issue because the number of collisions will vary and I didn't want to assign specific memory addresses to the max number of collisions possible, or deal with assigning the collision data to object behavior during my collision detection routine.

So, I thought about using the stack to preload tiles as well, but then I ran into the issue I mentioned about the return address. I actually just modified the way I stored map data which made the way tiles were located much simpler, but I'm still curious. I figured I could pull two bytes from the stack, store them somewhere, then push them back onto the stack before leaving.

I'm confused though when you say to calculate the entry point. Are you saying to count the number of bytes your code takes from when you first pulled from the stack? Why would you want to do this? The address it's going to pull at RTI is the address you need, right?

Sorry, I'm totally n00bing out, but I'm intrigued by the concept.
Re: How do you know if your code is structured well enough?
by on (#153417)
(Using ca65 syntax) Say you had something like
Code:
.proc do_xfer
 .repeat 16
  pla
  sta $2007
 .endrep
  txs
  rts
.endproc


To transfer the 14 bytes starting at $158, you'd TSX / STX save / LDX #$58 / TXS / LDX save / JMP do_xfer+(16-14)*4
Re: How do you know if your code is structured well enough?
by on (#153419)
Which takes about the same number of cycles as
Code:
  .repeat 16, I
    lda $0100+I,x
    sta $2007
  .endrepeat

Both a pull and an indexed load that doesn't cross page boundaries take 4 cycles.
Re: How do you know if your code is structured well enough?
by on (#153421)
Have we finally decided that it's much easier to just load and store than to pull and push and do a bunch of other nonsense?
Re: How do you know if your code is structured well enough?
by on (#153422)
Espozo wrote:
Have we finally decided that it's much easier to just load and store than to pull and push and do a bunch of other nonsense?

To my n00bish understanding I believe it's situational. There are benefits to using the stack and downsides. There are times when the stack is the best option for doing something, like when you need first in, last out order.

tepples wrote:
Which takes about the same number of cycles as
Code:
Code:
  .repeat 16, I
    lda $0100+I,x
    sta $2007
  .endrepeat


That assembles as an unrolled loop, right?
Re: How do you know if your code is structured well enough?
by on (#153426)
Yes, as I explained elsewhere.
Re: How do you know if your code is structured well enough?
by on (#153432)
nicklausw wrote:
Am I the only one with a weird habit of intentionally avoiding macros? I just don't like them, because when first starting out with assembly people got onto me for being too macro-heavy (since it made my code have no subroutines and therefore be redundant).

Um..huh? I think you're referring to in-line function/subroutines? I just talking about general macros.

Like this:
Code:
;##########################################################################
;..........................................................................
;
; Note: Needs to be called after LoadScreen or LoadSideScreen
;
;
LoadNextScreenAttribs:

         MOVE.w      screen_attrib_pointer,<A0
         MAPBANK.2   screen_attrib_bank,$6000

         ;load player position
         MOVE.b      [A0],YXstart
         INC.w         <A0
         
         ;check for NPCs
         MOVE.b      [A0],ScreenNPC.next
         INC.w         <A0
         clx
         cly
.load_Exitqueue
         MOVE.b      [A0], Exitqueue,x
         INC.w         <A0
         inx
         MOVE.b      [A0], Exitqueue,x
         INC.w         <A0
         MOVE.b      [A0], ExitArea,y
         ADD.w         #$02, <A0
         iny
         inx
         cpx #$10
      bcc .load_Exitqueue