Jump to content

Photo

Session 16: Letting the Assembler do the Work


17 replies to this topic

#1 Andrew Davie OFFLINE  

Andrew Davie

    Stargunner

  • 1,574 posts
  • Dr.Boo
  • Location:Tasmania

Posted Mon Jun 16, 2003 9:11 PM

This session we're going to have a brief look at how DASM (our assembler) builds up the binary ROM file, and how we can use DASM to help us organise our RAM.

As we've discovered, DASM keeps a list of all symbols and as it is assembling our code, it assigns values (= numbers, or addresses) to those symbols. When it is creating the binary ROM image, it replaces opcodes (=instructions) with appropriate values representing the opcode, and it replaces symbols with the value of the symbol from its internal symbol table.

OK, that basic process should be clear by now. When we view our symbol table (which is output when we use the -v5 switch on our command-line when assembling a file), we will see that there are some symbols which are unused (the used ones have (R ) after them, in the symbol table output). We can see, then, that it is not necessary for a symbol to actually be in the ROM binary file for it to have a value. There are several reasons why we'd want to have a symbol with a value, but not have that symbol "do anything" or relate to anything in the binary.

For example, we could use a symbol as a switch to tell the compiler which section of code to compile. A symbol could be used as a value to tell us how many scanlines to draw... eg:


SCANLINES = 312; PAL






;...later



    iny

    cpy #SCANLINES   ; at the end?

    bne AnotherLine     ; do another line




We can even implement a compile-time PAL/NTSC switch something like this...


PAL = 0

NTSC = 1



SYSTEM = PAL   ; change this to PAL or NTSC





#if SYSTEM = PAL

   ; insert PAL-only code here

#endif



#if SYSTEM = NTSC

   ; insert NTSC-only code here

#endif




This sort of use of symbols to drive the DASM assembly process can be quite useful when you want various sections of code to behave differently - for whatever reason. You might have a test bit of code which you can conditionally compile by defining a symbol as in the above example.

Now that we're comfortable with DASM's use of symbols as part of the compilation process, let's have a look at how we've been managing our RAM so far...


VARIABLE = $80    ; variable using the 1st byte of RAM

VAR2 = $81          ; another variable using the 2nd byte of RAM 

VAR3 = $82         ;etc


That's perfectly fine - and as we already know, lines like this will add the symbols to DASM's internal symbol table, and whenever DASM sees those symbols it will instead use the associated value. Consider the following example...


VARIABLE = $80  ; variable using 1st TWO bytes of RAM

VAR2 = $82         ; another variable must start after the 1st var's space


In this case we've created a 2-byte variable starting at the beginning of RAM. So the second variable has to start at $82 instead of $81 - because the first variable requires locations $80 and $81. The above will work fine - but there's no clear correspondence between the variable declaration (which is really just assigning a number/address to a symbol) and the amount of space required for the variable. Furthermore, if we later decided that we really needed 4 bytes (instead of 2) for VARIABLE, then we'd have to "shift down" all following variables - that is, VAR2 would have to be changed to $84, etc.. This is not only extremely annoying and time-consuming, it is a disaster waiting to happen - because you humans are fallible.

What we really want to do is let DASM manage the calculation of the variable/symbol addresses, and simply say "here's a variable, and it's this big". And fortunately, we can do that.

First, let's consider "normal code"


    ORG $8000

LABEL1    .byte 1,34,12,3

LABEL2    .byte 0


When assembled, DASM will assign $8000 as the value of the symbol LABEL1, and $8004 as the value of the symbol LABEL2 (that is, it assembles the code, and starting at location $8000 (which is also the value of LABEL1) we will see 4 bytes (1, 34, 12, 3) and then another byte (0) which is at $8004 - the value of the symbol LABEL2.

Note, the ".byte" instruction (actually it's called a pseudo-op, as it's an instruction to the assembler, not an actual 6502 instruction) is just a way of telling DASM to put particular byte values in the ROM at that location.

Remember when we wrote "NOP" to insert a no-operation instruction - which causes the 6502 to execute a 2 cycle delay? When we looked at the listing file, we saw that the NOP was replaced in the ROM image by the value $EA. Well, instead of letting DASM work out what the op-code's value is, we can actually just put that value in ourselves, using a .byte instruction to DASM. Example...


    .byte $EA   ; a NOP instruction!


Now, this isn't often done - but there are extremely rare cases where you might want to do this (typically with extremely obscure and highly godlike optimisations). We won't worry about that for now. But it's important to understand that just like DASM - which simply replaces a list of instructions with their values, we can just as easily do the same thing and put the values there ourselves.

Now it's easy to see how DASM gets its values for the labels from the address of the data it is currently assembling - in the earlier example, we started assembly (the ORG pseudo-op) at $8000, and then DASM encountered the label LAB1 - which was given the value $8000, etc. We then inserted 4 bytes with the ".byte" pseudo-op. Instead of ".byte" which places specific values into the output binary file, we could have used the "ds" pseudo-op - which stands for "define space". For example, the following would give the same two addresses to LAB1 and LAB2 as the above example, but the data put into the binary would differ...


    ORG $8000

LAB1 ds 4

LAB2 ds 1


Typically, the "ds" pseudo-op will place 0's in the ROM - as many bytes as specified in the value after the "ds". In the above example, we'll see 4 0's starting at $8000 followed by another at $8004.

Now let's consider our RAM... which starts at $80. What would we have if we did something like this...?


    ORG $80 ; start of RAM

VARIABLE  ds 3  ; define 3 bytes of space for this variable

VAR2  ds 1     ; define 1 byte of space for this one

VAR3  ds 2     ; define 2 etc..


Now that's much nicer, isn't it! It won't work, though :) The problem is, DASM will quite happily assemble this - and it will correctly assign values $80 to VARIABLE, $83 to VAR2 and $84 to VAR3 - but it will ALSO generate a binary ROM image containing data at locations $80-$85. That's RAM, not ROM - and it most definitely doesn't belong in a ROM binary. In fact, our ROM would now also be HUGE - because DASM would figure that it needs to create an image from location $80 - $FFFF (ie: it will be about 64K, not 4K).

What we need to do is tell DASM that we're really just using this code-writing-style to calculate the values of the symbols, and not actually creating binary data for our ROM. And we can do that. Let's plunge right in...


    SEG.U variables

    ORG $80

VARIABLE  ds 3  ; define 3 bytes of space for this variable

VAR2  ds 1     ; define 1 byte of space for this one

VAR3  ds 2     ; define 2 etc..


The addition is the "SEG.U" pseudo-op, followed by a segment name. This is telling DASM that all the following code (until a next "SEG" pseudo-op is encountered) is an uninitialised segment. When it encounters a "segment" defined like this, DASM will not generate actual binary data in the ROM - but it will still correctly calculate the address data for the symbols.

Note: It is important to give the segment a name (though this parameter is optional, you should choose a unique name for each segment). Naming segments assists the assembler in keeping track of exactly which parts of your code are initialised and uninitialised.

If you now go back and have a close look at the vcs.h file, you may begin to understand exactly how the values for all of the TIA registers are actually defined/calculated. Yes, they're defined as an uninitialised segment starting at a specific location. Typically this start-location is 0, and each register is assigned one byte. We keep the register symbols in the correct order and let DASM work out the addresses for us. There's a reason for this - to do with bankswitching cartrige formats - but the general lesson here is that it's nice to let DASM do the work for us - particularly when defining variables - and let it worry about the actual addresses of stuff - we just tell it the size.

One final word on the SEG pseudo-op. Though it is not strictly necessary, all of our code uses it. Without the .U extension, SEG will create binary data for our ROM. With the .U, SEG just allows DASM to populate its symbol table with names/values.

So from now on, let's define variables "the proper way". We'll use an uninitialised segment starting at $80, and give each variable a size using the "ds" pseudo-op. And don't forget after our variable definitions to place another "SEG" which will effectively tell DASM to start generating binary ROM data. Here's an example...


    SEG.U vars ; the label "vars" will appear in our symbol table's segment list

    ORG $80   ; start of RAM

Variable ds 1  ; a 1-byte variable





    SEG    ; end of uninitialised segment - start of ROM binary

    ORG $F000
; code....



That will do nicely for this session - see you next time!

#2 dew2050 OFFLINE  

dew2050

    Space Invader

  • 32 posts

Posted Wed Jun 18, 2003 11:44 AM

   ORG $8000  
LAB1 ds 4  
.
.
.
Typically, the "ds" pseudo-op will place 0's in the ROM - as many as the value after the "ds". In the above example, we'll see 4 0's starting at$8000 followed by another at $8004.
.
.
.
VARIABLE  ds 3   ; define 3 bytes of space for this variable  


I am confused. Does "ds" defines bytes or bits?


Another question: When I tried for the time to use unitialized segment command, I forgot to declare the label name right after the seg.u command, like this:

SEG.U    ;<---- Notice no label here

	ORG $80



PFColor	ds 1

PFTemp	ds 1



	SEG

This compiled fine but the binary file inflated to 64K. When I noticed the label was missing, I put it there and the file shrinked to 4K. Why did DASM did this? Isn't the "seg.u" command enough for it to know?

#3 Happy_Dude OFFLINE  

Happy_Dude

    River Patroller

  • 4,212 posts
  • Forum Slacker
  • Location:Sydney, Australia

Posted Wed Jun 18, 2003 11:52 AM

From what I gather .ds defines "bytes". As in Variable A starts at $80.
it's defined as A ds 2, and Variable B then starts at $82. meaning A is 2 bytes long.

As for your second question ...... Indentation. Anything in the leftmost
column is a lable. No if's, and's or but's. I don't beleive Dasm has reserved
words like a C compiler so a lable can be anything, even SEG.U ;)

#4 dew2050 OFFLINE  

dew2050

    Space Invader

  • 32 posts

Posted Wed Jun 18, 2003 12:15 PM

The code snippet lost the format during the cut and pasting of the post. In my program is properly tabbed, like this:


	SEG.U VARS

	ORG $80



PFColor	ds 1

PFTemp	ds 1



	SEG

In this case there is a label after "seg.u". When compiling using the standard format we have been following so far, the file is 4K. However, if I omit the label "VARS" DASM creates a 64K file. As I understood it, Davie's lesson seems to say that the only thing you need to avoid such * huge * file (when declaring variables) is the SEG.U command without anything added to it.

#5 Andrew Davie OFFLINE  

Andrew Davie

    Stargunner

  • Topic Starter
  • 1,574 posts
  • Dr.Boo
  • Location:Tasmania

Posted Wed Jun 18, 2003 5:59 PM

The code snippet lost the format during the cut and pasting of the post. In my program is properly tabbed, like this:


	SEG.U VARS

	ORG $80



PFColor	ds 1

PFTemp	ds 1



	SEG

In this case there is a label after "seg.u". When compiling using the standard format we have been following so far, the file is 4K. However, if I omit the label "VARS" DASM creates a 64K file. As I understood it, Davie's lesson seems to say that the only thing you need to avoid such * huge * file (when declaring variables) is the SEG.U command without anything added to it.



I checked this out, and although I see different behaviour than dew2050 (my output file is 0 bytes long), he is essentially correct. If you have a look at the symbol data output by DASM (if you're using the switch -v5), you will see a list of segments just before the symbol table. Each segment is named. There are some default ones used by the assembler, and when you place a name alongside a SEG pseudo-op, you will see this segment there, too.

I haven't had time to check out DASM's source code to see exactly what it is doing, but my theory is that the information about if a segment is initialised or not (and thus if it appears in the final binary or not) is saved in a list, and when we define a new segment (with SEG), the assembler first checks to see if that segment is already defined - and if so, just modifies the information it holds.

So, where you have an un-named segment and you use SEG.U and SEG in your program, you either get (depending on luck?) a 0-byte file (which would be where the assembler thinks the segment should not be initialised) or a whacking great huge file (where the assembler thinks the segment should be initialised).

The solution is, as dew suggested, to name your segments. It is clearly important, then, to give your segments meaningful and unique names. I'll correct the session information to reflect this.

Thanks
A

#6 Andrew Davie OFFLINE  

Andrew Davie

    Stargunner

  • Topic Starter
  • 1,574 posts
  • Dr.Boo
  • Location:Tasmania

Posted Wed Jun 18, 2003 6:14 PM

I am confused. Does "ds" defines bytes or bits?



'ds' defines space in bytes. If you re-read the session, and closely follow the addresses of the labels that were mentioned, you should be able to see exactly how many bytes are between each :)

#7 dew2050 OFFLINE  

dew2050

    Space Invader

  • 32 posts

Posted Thu Jun 19, 2003 2:56 PM

Thank you Andrew. It's all clear now.

#8 kisrael OFFLINE  

kisrael

    HMBL 2600 coder

  • 3,970 posts
  • Location:Boston Burbs, MA

Posted Sat Sep 6, 2003 3:45 PM

One bit of advice: I've been reluctant to use this kind of "variable definition" because I was paranoid about running out of RAM space. Though with Debro's suggestion of a well placed echo...
echo ($100 - *) , "bytes of RAM left"
(after all varialbes are stored) can put my mind at ease.
The only trouble is the message shows up once per pass.
And is in hex, which isn't what I tend to think in (I know, shame on me)

#9 Happy_Dude OFFLINE  

Happy_Dude

    River Patroller

  • 4,212 posts
  • Forum Slacker
  • Location:Sydney, Australia

Posted Sun Sep 7, 2003 4:24 AM

One  bit of advice: I've been reluctant to use this kind of "variable definition" because I was paranoid about running out of RAM space.  

I don't see that at all.
You have a bunch of "ds" definitions with exactly how many bytes each uses.

somevariable     ds 1

anothervariable  ds 1

lastvariable     ds 5

looks like that uses 7 bytes. No need for compiler tricks ;)

#10 kisrael OFFLINE  

kisrael

    HMBL 2600 coder

  • 3,970 posts
  • Location:Boston Burbs, MA

Posted Sun Sep 7, 2003 7:51 AM

One  bit of advice: I've been reluctant to use this kind of "variable definition" because I was paranoid about running out of RAM space.  

I don't see that at all.
You have a bunch of "ds" definitions with exactly how many bytes each uses.
looks like that uses 7 bytes. No need for compiler tricks ;)

No, it's not more wasteful of space or anything, it's just that if I manually assigned each variable, starting with

somevariable = $80

anothervariable = $81

....

and then I kept going and had something like

yetanotherfrigginvariable = $FD

okonemorevariable = $FE

Well, then I'd be painfully aware of how much trouble I was in...or even if it didn't get to that point, I'd have an idea of how I was doing RAM wise. But now my compiler trick (or rather my variation on Debro's) tells me directly, so I can use this cleaner method without adding up all the "ds" values by hand.

#11 Andrew Davie OFFLINE  

Andrew Davie

    Stargunner

  • Topic Starter
  • 1,574 posts
  • Dr.Boo
  • Location:Tasmania

Posted Sun Sep 7, 2003 8:26 AM

Well, then I'd be painfully aware of how much trouble I was in...or even if it didn't get to that point, I'd have an idea of how I was doing RAM wise.  But now my compiler trick (or rather my variation on Debro's) tells me directly, so I can use this cleaner method without adding up all the "ds" values by hand.



This is as good a place as any to mention variable overlays. This is a handy 'trick' you can use to re-use RAM by assigning different usage (=meaning) to RAM locations based on the premise that some RAM locations are only needed for some parts of a game, and some for others. If you have two variables which do not clash in terms of the area in the code they are used, then there's no real reason why those variables can't use the same RAM location.

Here's my original post to the stella list on this issue (7/Feb/2001)

As I'm trying to optimise RAM usage, I'd been using a general scratchpad
variable ("temp") and using that in the code wherever I need to. I managed the allocation and meaning of the variables manually. That is, I might know that "temp+1" is the variable for the line #, etc., etc. It works, but it is prone to error.

So, I was thinking of a better way, and came up with this...


    org $80   ; start of our overlay section

temp        ds 8           ; general area for variable overlays

   ; other RAM variable declarations here....




; and now come the 'overlays'... these effectively use the 'temp' RAM

location, referenced by other names...



   ; overlay section 1

    org temp                           ; <--- this is the bit that is the

trick

overlayvar1    ds 1               ; effectively 'temp'

overlayvar2    ds 2               ; effectively 'temp+1'

overlayvar3    ds 2               ; effectively 'temp+3'



   ; overlay section 2

    org temp                           ; ANOTHER overlay on the 'temp'

variable

linecounter    ds 1           ; effectively 'temp'

indirect        ds 2               ; effectively 'temp+1'

   ; etc...



   ; overlay section 3

    org temp

sect3var        ds 8

   ; can't add more in this overlay (#3) as it's already used all of

'temp's size


This all works fine... as long as you remember that when you are using variables in overlays, you can't use two different overlays at the same time. That is, the same routine (or section of code) CANNOT use variables in overlay section 1 AND overlay section 2. It's not that much of a restriction, and allows you to use nice variable names throughout your code.

Just be careful your overlays don't get bigger than the general area allocated for each section.

The advantages of this system are that you can CLEARLY see what your variables are, and you only have to change sizes/declarations/usage in a
single place (the RAM overlay declaration)... not hunt through your code
when you decide to change usage.

/end of posting to stella

To summariase, we declare one 'variable' which is a block of RAM which is used for sharing RAM. This is our overlay section. We then declare each of our Overlays by setting the origin to the start of the overlay section and define new variables. This works because the assembler is generating an UNINITIALISED segment for our RAM variables. What that means is that we're just using the assembler to assign values to labels (to its symbols), but not actually generating ROM data. So each overlay section starts in the same spot, and defines variables (ie: assigns addresses to labels) starting at that spot. We essentially share RAM locations for those variables, with other variables which are also defined the same way.

I've used this technique now for many demos. It can give the effect of dramatically increasing available RAM. Just have to be careful that you don't try and use two variables sharing the same location at any time. With a bit of careful management it comes naturally.

Here's a generic 'shell' with comments I use for overlay RAM variables...


       ; This overlay variable is used for the overlay variables.  That's OK.

       ; However, it is positioned at the END of the variables so, if on the off chance we're overlapping

       ; stack space and variable, it is LIKELY that that won't be a problem, as the temp variables

       ; (especially the latter ones) are only used in rare occasions.



       ; FOR SAFETY, DO NOT USE THIS AREA DIRECTLY (ie: NEVER reference 'Overlay' in the code)

       ; ADD AN OVERLAY FOR EACH ROUTINE'S USE, SO CLASHES CAN BE EASILY CHECKED



Overlay         ds 0;      ;--> overlay (share) variables (make sure this is as big as the biggest overlay subsection)




;------------------------------------------------------------------------------
; OVERLAYS!
; These variables are overlays, and should be managed with care
; That is, variables are ALREADY DEFINED, and we're reusing RAM for other purposes


; EACH OF THESE ARE VARIABLES (TEMPORARY) USED BY ONE ROUTINE (AND IT'S SUBROUTINES)
; THAT IS, LOCAL VARIABLES.  USE 'EM FREELY, THEY COST NOTHING


; TOTAL SPACE USED BY ANY OVERLAY GROUP SHOULD BE <= SIZE OF 'Overlay'


;------------------------------------------------------------------------------



                org Overlay



   ; ANIMATION/LOGIC SYSTEM

   ; place variables here


;------------------------------------------------------------------------------



                org Overlay



   ; DRAWING SYSTEM

   ; place variables here



   ; etc





Hope that's clear enough.

#12 Happy_Dude OFFLINE  

Happy_Dude

    River Patroller

  • 4,212 posts
  • Forum Slacker
  • Location:Sydney, Australia

Posted Sun Sep 7, 2003 8:30 AM

No, it's not more wasteful of space or anything

I just thought that mabye you thought that ;)

I usualy keep track of variables when I add them anyway

first    ds 1;$80

second    ds 1;$81

third    ds 1;$82

fourth    ds 1;$83



just out of curiosity, how does the "echo" thing work ?

#13 kisrael OFFLINE  

kisrael

    HMBL 2600 coder

  • 3,970 posts
  • Location:Boston Burbs, MA

Posted Sun Sep 7, 2003 8:47 AM

I usualy keep track of variables when I add them anyway


first    ds 1;$80

second    ds 1;$81

third    ds 1;$82

fourth    ds 1;$83

Heh, to me, keeping track of the memory location in a comment misses the whole point...though it is a bit of an improvement because if you mess up or change the order of stuff, only the comments are wrong.

just out of curiosity, how does the "echo" thing work ?

DEBRO mentioned it in a different thread (don't feel like digging for it now) as well as the stella list. In general, echo lets you print stuff out during the assembly process. the "*" seems to be kind of like a variable that is the current memory position in the ROM. So since I know my variables need to end at $100 , ($100 - *) tells me how many bytes I have left.

#14 kisrael OFFLINE  

kisrael

    HMBL 2600 coder

  • 3,970 posts
  • Location:Boston Burbs, MA

Posted Sun Sep 7, 2003 8:55 AM

Andrew, re: overlays...

Can't you get similar results more simply on a "variable by variable" basis by giving multiple names to the same spot in RAM, without grouping them?

Something like

	SEG.U VARS 

	ORG $80

sect1var1

sect2var1

	ds 1

sect1var2

sectvar2

	ds 1

The only disadvantage I see is that you keep track of the grouping yourself, rather than calling a group an overlay. But you can still get your variable names to be very descriptive, not "Tempvar+1" etc.

#15 Andrew Davie OFFLINE  

Andrew Davie

    Stargunner

  • Topic Starter
  • 1,574 posts
  • Dr.Boo
  • Location:Tasmania

Posted Sun Sep 7, 2003 6:58 PM

Andrew, re: overlays...

Can't you get similar results more simply on a "variable by variable" basis by giving multiple names to the same spot in RAM, without grouping them?

Something like  


	SEG.U VARS 

	ORG $80

sect1var1

sect2var1

	ds 1

sect1var2

sectvar2

	ds 1

The only disadvantage I see is that you keep track of the grouping yourself, rather than calling a group an overlay.  But you can still get your variable names to be very descriptive, not "Tempvar+1" etc.



You missed the points.

1) The variable names I used were exemplary only. Of course you use meaningful names in actual usage.

2) Variables are not always the same size; your example requires them to be, or requires careful and complex management. For example, what if the first variable was used as a single-byte variable in one place, and as a three-byte buffer in another, and in yet another as a 16 byte buffer. How would you use your method to define these?

3) Using the overlay method, you can segment your variables into groups of variables which are used together.

eg:




    org $80 ; start of RAM

   ; some non-overlay variable definitions

nonOverlays    ds 30  ; example

Overlay           ds 10  ; 10 bytes reserved for overlays





    org Overlay

   ; these variables used in routine A but not routine B

   ; Note: this overlay uses all 10 available bytes

Buffer             ds 8   ; an 8-byte buffer

Vector            ds 2     ; zp vector



    org Overlay

   ; these variables used in routine B, but not routine A

   ; Note, this overlay uses 8 of the 10 bytes available

NamePtr         ds 2

WordVector    ds 6


Hope that's clear.

#16 kisrael OFFLINE  

kisrael

    HMBL 2600 coder

  • 3,970 posts
  • Location:Boston Burbs, MA

Posted Sun Sep 7, 2003 10:30 PM

You missed the points.

Well, I think I kinda got most of the points...I just wanted to point it out as an alternative option...it's not quite as functional, but it does let you reuse RAM space while still keeping intelligent variable names...it might be better if you were in too much of a hurry to group things into logical template groups.

Also, thanks for the help on stella re: there IS no (indirect),x addressing mode...maybe it would be a nice thing to footnote on the Addressing Modes page, because there you do talk about their not being a zeropage,y mode...

I guess it is funny DASM doesn't pick up on that, like you said.

Actually, I was trying to make a batch file that tested DASM's return value, but it seems like only certain kind of errors are enough to make it return an ERRORLEVEL of 1...

#17 Happy_Dude OFFLINE  

Happy_Dude

    River Patroller

  • 4,212 posts
  • Forum Slacker
  • Location:Sydney, Australia

Posted Sun Sep 7, 2003 11:34 PM

I'm already using overlays to reuse ram ;)

Just think of it like "local" and "Global" variables.
define your globals at the top of your code (with the last being the overlay
area) and when you need to define local's, do so at the top of the required
section/routine/function/whatever :wink:

#18 Thomas Jentzsch OFFLINE  

Thomas Jentzsch

    Thrust, Jammed, SWOOPS!, Boulder Dash

  • 18,727 posts
  • Always left from right here!
  • Location:Düsseldorf, Germany

Posted Mon Sep 8, 2003 1:34 AM

Just think of it like "local" and "Global" variables.
define your globals at the top of your code (with the last being the overlay  
area) and when you need to define local's, do so at the top of the required  
section/routine/function/whatever :wink:

For real local variables (and lables) you can prefix the name with '.'. Together with using SUBROUTINE, you can create local namespaces that way.
MySub1 SUBROUTINE; start a new local namespace

.xPos = Overlay

.yPos = Overlay+1



  lda #200

  sta .yPos

  ldx #10

.loop:

  dex

  bne .loop

  ...



MySub2 SUBROUTINE; the start of the next local namespace
This adds no code overhead, just makes programming a little bit easier, especially when you are lazy finding new variable and label names. :)

BTW: SUBROUTINE is not limited to subroutines (JSR/RTS). If you have large chunks of spaghetti code, you can group it with SUBROUTINE too.




0 user(s) are browsing this forum

0 members, 0 guests, 0 anonymous users