Jump to content

Open Club  ·  61 members

DASM
IGNORED

REPEAT-REPEND - Help!


JohnnyRockets

Recommended Posts

Hi all,

I'm REALLY trying to get my head around Pseudops, but having a hard time.  I am a newbie, so please take that into account.  :)

 

I found this definition of Pseudops online:  "Actually, a more formal name for a pseudo-op is assembler directive.   They are called pseudo-ops because they do not refer to operations that will be performed by the program during execution.  Rather,  the pseudo-op is strictly a message to the assembler to help the assembler in the assembly process."

 

But in the case of:
REPEAT-REPEND

 

Doesn't this construct (REPEAT-REPEND) actually perform a loop function?  It seems that it does, but above the definition is saying that pseudo-ops do not refer to actual operations.

 

I am specifically asking for clarification on this code:

 REPEAT 192; scanlines
    inx
    stx COLUBK
    sta WSYNC
REPEND

I'm sure you'll recognize this code from:  https://www.randomterrain.com/atari-2600-memories-tutorial-andrew-davie-08.html

 

I'm surely confused here, LOL!


Thanks to anyone that can help me!  AND if there is a better place for me to ask this kind of question, please accept my apologies and point me in right direction.

 

Thank you!


JR

Link to comment
Share on other sites

REPEAT/REPEND are processed by the assembler to create text to assemble.

They are not some sort of programming/branching structure.

The code in question merely puts 192 copies of the three lines shown into a buffer and then assembles the whole lot.

You get exactly the same effect by typing those 3 lines 192 times.

REPEAT/REPEND is therefore merely a convenience for the programmer to save having to type lots of repeating code.

Think of it as text substitution/processing. Only after the text is processed, then the whole resultant text (generated) is assembled.

To say what the example is NOT, it is not some sort of control to make the 6507 loop 192 times. Definitely not!

 

Link to comment
Share on other sites

The operations are the assembler code, the 6502 instructions. The REPEAT does not create a loop, it repeats the operations. In your case the result would be:

    inx
    stx COLUBK
    sta WSYNC
    inx
    stx COLUBK
    sta WSYNC
    inx
    stx COLUBK
    sta WSYNC
    inx
    stx COLUBK
    sta WSYNC
    inx
    stx COLUBK
    sta WSYNC
    inx
    stx COLUBK
    sta WSYNC
    ...

So REPEAT tells the assembler to create the code inside the REPEAT block 192-times.

Link to comment
Share on other sites

Wow guys!

 

I'm so thankful for your replies and I FINALLY understand it!  I never even thought to look at the assembly listing or that this was "just" a convenience to the programmer.  That is really, really cool and a nice feature that the curators/keepers of DASM have included at one point (I think I'm right in saying that).  It certainly makes coding easier and with significantly less typing it seems.

 

Thank you again, I was very sheepish to ask a question in this club and was really impressed that I received three replies from you guys SO fast.  I feel like a rookie on his first day on the job with you guys, so thank you for taking the time to help me and understanding my "rookie-ness".

 

The more I dabble with ASM programming for the 2600, the cooler it seems.

 

 

JR

Edited by JohnnyRockets
  • Like 1
Link to comment
Share on other sites

One thing I always do is have dasm generate a listing via the -l option.  That lets you see exactly what dasm did.

 

I had Kaboom! Deluxe! open, so dropped your REPEAT/REPEND example in it.  I assembled it using:

 

dasm kaboom_deluxe.asm -f3 -v0 -skaboom_deluxe.sym -lkaboom_deluxe.lst -okaboom_deluxe.bin
 

 

The listing is file kaboom_deluxe.lst which contains:

   2170  fc1f					      REPEAT	192	; scanlines
   2171  fc1f		       e8		      inx
   2172  fc20		       86 09		      stx	COLUBK
   2173  fc22		       85 02		      sta	WSYNC
   2170  fc22					      REPEND
   2171  fc24		       e8		      inx
   2172  fc25		       86 09		      stx	COLUBK
   2173  fc27		       85 02		      sta	WSYNC
   2170  fc27					      REPEND
...
   2171  ffda		       e8		      inx
   2172  ffdb		       86 09		      stx	COLUBK
   2173  ffdd		       85 02		      sta	WSYNC
   2174  ffdf					      REPEND


The columns in the listing are:

  • Source code line number
  • ROM address in the BIN
  • assembled values for the instructions, e8 is the opcode for inx, 86 for stx, 09 the address of COLUBK, etc.
  • the instructions

 

 

Dasm's -s option creates a symbol file.  Shows you all the symbols and their values, and whether or not they were referenced by your program.  Example from Kaboom! Deluxe!:
 

...
AUDV0                    0019              (R )
AUDV1                    001a                  
backgroundColor          0086              (R )
BCD2DigitPtrs            f79a                  
BLACK                    0000              (R )
Blank                    fb00              (R )
BLUE                     0080              (R )
BOMB_DROP_RATE           0001              (R )
BOMB_GROUP_MAX           0008              (R )
...


AUDV0 was referenced, AUDV1 was not as Kaboom! only uses audio channel 0.

Link to comment
Share on other sites

Hi Darrell,

 

The listing functionality will really help me as I learn, but honestly, it is probably important even for troubleshooting in general for most programmers, I would guess.

 

Thank you for the explanation of the columns, this helps a lot and I can see the 3 commands being repeated over and over as previously mentioned (192 times).

 

So the symbol file always shows ALL symbols?  Ahhh, got it now!  I see with the addition or omission of (R), now I get it! 

 

Last question (I think, for now, maybe):  The symbol values change of course from program to program(?).

 

 

Thanks!

 


JR

Link to comment
Share on other sites

Correct, the (R) means referenced.

Symbols will be specific to your program, such as Medieval Mayhem doesn't have bombs so BOMB_DROP_RATE doesn't exist in its symbol table, but most games for the Atari include the following line in their source:

   include vcs.h

 

So their symbol files will have all the TIA and RIOT symbols defined even if they don't use them all.

 

One thing that can be tricky is a symbol might be indirectly referenced. Take a look at PosObject:

PosObject:              ; A holds X value
        sec             ; 2  
        sta WSYNC       ; X holds object, 0=P0, 1=P1, 2=M0, 3=M1, 4=Ball
DivideLoop
        sbc #15         ; 2  
        bcs DivideLoop  ; 2  4
        eor #7          ; 2  6
        asl             ; 2  8
        asl             ; 2 10
        asl             ; 2 12
        asl             ; 2 14
        sta.wx HMP0,X   ; 5 19
        sta RESP0,X     ; 4 23 <- set object position
        dex             ; 2 25
        rts             ; 6 31


HMP0 and RESP0 are both referenced, but HMP1, HMM0, HMM1, HMBL, RESP1, RESM0, RESM1, and RESBL are not even though PosObject will use them (based on the value of the X register).  So if you positioned all objects, but only used PosObject to do so, your symbol file would show:

...
HMBL                     0024                  
HMCLR                    002b              (R )
HMM0                     0022                  
HMM1                     0023                  
HMP0                     0020              (R )
HMP1                     0021                  
...
RESBL                    0014                  
RESM0                    0012                  
RESM1                    0013                  
RESP0                    0010              (R )
RESP1                    0011                  
...




 

Link to comment
Share on other sites

Thank you!

 

I have to study this one a bit, but I'm getting there.

 

You guys have helped a ton!

 

So assuming that you have included vcs.h, you'll have all the TIA and RIOT commands PLUS the symbols that are "program specific" to your program and will exist only in the your program listing, correct?

 

JR

Link to comment
Share on other sites

Now you understand it, I thought sharing an example (from my Chess program in this case) might show how handy it can be...

 

    ALLOCATE FlipSquareIndex, 100

    .byte 0,0,0,0,0,0,0,0,0,0
    .byte 0,0,0,0,0,0,0,0,0,0

.SQBASE SET 90
    REPEAT 8
    .byte 0,0
.SQX SET 2
    REPEAT 8
    .byte (.SQBASE+.SQX)
.SQX SET .SQX + 1
    REPEND
.SQBASE SET .SQBASE - 10
    REPEND

"ALLOCATE" is a macro that does some magic to make sure the table being generated by the following (nested!) REPEAT loops doesn't cross a page boundary.  The above weirdness is creating a table using a bit of math, instead of me having to type it all in by hand.

Although all the weird macros I use make it a bit difficult to follow if you don't know what I'm doing here... here is the listing file of that table, showing the various REPEAT structures doing their stuff...

 

      0  604c					      ALLOCATE	FlipSquareIndex, 100
      0  604c					      OPTIONAL_PAGEBREAK	"Table", 100
     12  604c					      LIST	ON
      0  604c					      DEF	FlipSquareIndex
      1  604c				   BANK_FlipSquareIndex SET	_CURRENT_BANK
      2  604c				   FlipSquareIndex
      3  604c				   TEMPORARY_VAR SET	Overlay
      4  604c				   TEMPORARY_OFFSET SET	0
      5  604c				   VAR_BOUNDARY_FlipSquareIndex SET	TEMPORARY_OFFSET
      6  604c				   FUNCTION_NAME SET	FlipSquareIndex
      7  604c					      SUBROUTINE
    131  604c
    132  604c		       00 00 00 00*	      .byte.b	0,0,0,0,0,0,0,0,0,0
    133  6056		       00 00 00 00*	      .byte.b	0,0,0,0,0,0,0,0,0,0
    134  6060
    135  6060				   .SQBASE    SET	90
    136  6060					      REPEAT	8
    137  6060		       00 00		      .byte.b	0,0
    138  6060				   .SQX       SET	2
    139  6062					      REPEAT	8
    140  6062		       5c		      .byte.b	(.SQBASE+.SQX)
    141  6062				   .SQX       SET	.SQX + 1
    139  6062					      REPEND
    140  6063		       5d		      .byte.b	(.SQBASE+.SQX)
    141  6063				   .SQX       SET	.SQX + 1
    139  6063					      REPEND
    140  6064		       5e		      .byte.b	(.SQBASE+.SQX)
    141  6064				   .SQX       SET	.SQX + 1
    139  6064					      REPEND
    140  6065		       5f		      .byte.b	(.SQBASE+.SQX)
    141  6065				   .SQX       SET	.SQX + 1
    139  6065					      REPEND
    140  6066		       60		      .byte.b	(.SQBASE+.SQX)
    141  6066				   .SQX       SET	.SQX + 1
    139  6066					      REPEND
    140  6067		       61		      .byte.b	(.SQBASE+.SQX)
    141  6067				   .SQX       SET	.SQX + 1
    139  6067					      REPEND
    140  6068		       62		      .byte.b	(.SQBASE+.SQX)
    141  6068				   .SQX       SET	.SQX + 1
    139  6068					      REPEND
    140  6069		       63		      .byte.b	(.SQBASE+.SQX)
    141  6069				   .SQX       SET	.SQX + 1
    142  606a					      REPEND
    143  606a				   .SQBASE    SET	.SQBASE - 10
    136  606a					      REPEND
    137  606a		       00 00		      .byte.b	0,0
    138  606a				   .SQX       SET	2
    139  606c					      REPEAT	8
    140  606c		       52		      .byte.b	(.SQBASE+.SQX)
    141  606c				   .SQX       SET	.SQX + 1
    139  606c					      REPEND
    140  606d		       53		      .byte.b	(.SQBASE+.SQX)
    141  606d				   .SQX       SET	.SQX + 1
    139  606d					      REPEND
    140  606e		       54		      .byte.b	(.SQBASE+.SQX)
    141  606e				   .SQX       SET	.SQX + 1
    139  606e					      REPEND
    140  606f		       55		      .byte.b	(.SQBASE+.SQX)
    141  606f				   .SQX       SET	.SQX + 1
    139  606f					      REPEND
    140  6070		       56		      .byte.b	(.SQBASE+.SQX)
    141  6070				   .SQX       SET	.SQX + 1
    139  6070					      REPEND
    140  6071		       57		      .byte.b	(.SQBASE+.SQX)
    141  6071				   .SQX       SET	.SQX + 1
    139  6071					      REPEND
    140  6072		       58		      .byte.b	(.SQBASE+.SQX)
    141  6072				   .SQX       SET	.SQX + 1
    139  6072					      REPEND
    140  6073		       59		      .byte.b	(.SQBASE+.SQX)
    141  6073				   .SQX       SET	.SQX + 1
    142  6074					      REPEND
    143  6074				   .SQBASE    SET	.SQBASE - 10
    136  6074					      REPEND
    137  6074		       00 00		      .byte.b	0,0
    138  6074				   .SQX       SET	2
    139  6076					      REPEAT	8
    140  6076		       48		      .byte.b	(.SQBASE+.SQX)
    141  6076				   .SQX       SET	.SQX + 1
    139  6076					      REPEND
    140  6077		       49		      .byte.b	(.SQBASE+.SQX)
    141  6077				   .SQX       SET	.SQX + 1
    139  6077					      REPEND
    140  6078		       4a		      .byte.b	(.SQBASE+.SQX)
    141  6078				   .SQX       SET	.SQX + 1
    139  6078					      REPEND
    140  6079		       4b		      .byte.b	(.SQBASE+.SQX)
    141  6079				   .SQX       SET	.SQX + 1
    139  6079					      REPEND
    140  607a		       4c		      .byte.b	(.SQBASE+.SQX)
    141  607a				   .SQX       SET	.SQX + 1
    139  607a					      REPEND
    140  607b		       4d		      .byte.b	(.SQBASE+.SQX)
    141  607b				   .SQX       SET	.SQX + 1
    139  607b					      REPEND
    140  607c		       4e		      .byte.b	(.SQBASE+.SQX)
    141  607c				   .SQX       SET	.SQX + 1
    139  607c					      REPEND
    140  607d		       4f		      .byte.b	(.SQBASE+.SQX)
    141  607d				   .SQX       SET	.SQX + 1
    142  607e					      REPEND
    143  607e				   .SQBASE    SET	.SQBASE - 10
    136  607e					      REPEND
    137  607e		       00 00		      .byte.b	0,0
    138  607e				   .SQX       SET	2
    139  6080					      REPEAT	8
    140  6080		       3e		      .byte.b	(.SQBASE+.SQX)
    141  6080				   .SQX       SET	.SQX + 1
    139  6080					      REPEND
    140  6081		       3f		      .byte.b	(.SQBASE+.SQX)
    141  6081				   .SQX       SET	.SQX + 1
    139  6081					      REPEND
    140  6082		       40		      .byte.b	(.SQBASE+.SQX)
    141  6082				   .SQX       SET	.SQX + 1
    139  6082					      REPEND
    140  6083		       41		      .byte.b	(.SQBASE+.SQX)
    141  6083				   .SQX       SET	.SQX + 1
    139  6083					      REPEND
    140  6084		       42		      .byte.b	(.SQBASE+.SQX)
    141  6084				   .SQX       SET	.SQX + 1
    139  6084					      REPEND
    140  6085		       43		      .byte.b	(.SQBASE+.SQX)
    141  6085				   .SQX       SET	.SQX + 1
    139  6085					      REPEND
    140  6086		       44		      .byte.b	(.SQBASE+.SQX)
    141  6086				   .SQX       SET	.SQX + 1
    139  6086					      REPEND
    140  6087		       45		      .byte.b	(.SQBASE+.SQX)
    141  6087				   .SQX       SET	.SQX + 1
    142  6088					      REPEND
    143  6088				   .SQBASE    SET	.SQBASE - 10
    136  6088					      REPEND
    137  6088		       00 00		      .byte.b	0,0
    138  6088				   .SQX       SET	2
    139  608a					      REPEAT	8
    140  608a		       34		      .byte.b	(.SQBASE+.SQX)
    141  608a				   .SQX       SET	.SQX + 1
    139  608a					      REPEND
    140  608b		       35		      .byte.b	(.SQBASE+.SQX)
    141  608b				   .SQX       SET	.SQX + 1
    139  608b					      REPEND
    140  608c		       36		      .byte.b	(.SQBASE+.SQX)
    141  608c				   .SQX       SET	.SQX + 1
    139  608c					      REPEND
    140  608d		       37		      .byte.b	(.SQBASE+.SQX)
    141  608d				   .SQX       SET	.SQX + 1
    139  608d					      REPEND
    140  608e		       38		      .byte.b	(.SQBASE+.SQX)
    141  608e				   .SQX       SET	.SQX + 1
    139  608e					      REPEND
    140  608f		       39		      .byte.b	(.SQBASE+.SQX)
    141  608f				   .SQX       SET	.SQX + 1
    139  608f					      REPEND
    140  6090		       3a		      .byte.b	(.SQBASE+.SQX)
    141  6090				   .SQX       SET	.SQX + 1
    139  6090					      REPEND
    140  6091		       3b		      .byte.b	(.SQBASE+.SQX)
    141  6091				   .SQX       SET	.SQX + 1
    142  6092					      REPEND
    143  6092				   .SQBASE    SET	.SQBASE - 10
    136  6092					      REPEND
    137  6092		       00 00		      .byte.b	0,0
    138  6092				   .SQX       SET	2
    139  6094					      REPEAT	8
    140  6094		       2a		      .byte.b	(.SQBASE+.SQX)
    141  6094				   .SQX       SET	.SQX + 1
    139  6094					      REPEND
    140  6095		       2b		      .byte.b	(.SQBASE+.SQX)
    141  6095				   .SQX       SET	.SQX + 1
    139  6095					      REPEND
    140  6096		       2c		      .byte.b	(.SQBASE+.SQX)
    141  6096				   .SQX       SET	.SQX + 1
    139  6096					      REPEND
    140  6097		       2d		      .byte.b	(.SQBASE+.SQX)
    141  6097				   .SQX       SET	.SQX + 1
    139  6097					      REPEND
    140  6098		       2e		      .byte.b	(.SQBASE+.SQX)
    141  6098				   .SQX       SET	.SQX + 1
    139  6098					      REPEND
    140  6099		       2f		      .byte.b	(.SQBASE+.SQX)
    141  6099				   .SQX       SET	.SQX + 1
    139  6099					      REPEND
    140  609a		       30		      .byte.b	(.SQBASE+.SQX)
    141  609a				   .SQX       SET	.SQX + 1
    139  609a					      REPEND
    140  609b		       31		      .byte.b	(.SQBASE+.SQX)
    141  609b				   .SQX       SET	.SQX + 1
    142  609c					      REPEND
    143  609c				   .SQBASE    SET	.SQBASE - 10
    136  609c					      REPEND
    137  609c		       00 00		      .byte.b	0,0
    138  609c				   .SQX       SET	2
    139  609e					      REPEAT	8
    140  609e		       20		      .byte.b	(.SQBASE+.SQX)
    141  609e				   .SQX       SET	.SQX + 1
    139  609e					      REPEND
    140  609f		       21		      .byte.b	(.SQBASE+.SQX)
    141  609f				   .SQX       SET	.SQX + 1
    139  609f					      REPEND
    140  60a0		       22		      .byte.b	(.SQBASE+.SQX)
    141  60a0				   .SQX       SET	.SQX + 1
    139  60a0					      REPEND
    140  60a1		       23		      .byte.b	(.SQBASE+.SQX)
    141  60a1				   .SQX       SET	.SQX + 1
    139  60a1					      REPEND
    140  60a2		       24		      .byte.b	(.SQBASE+.SQX)
    141  60a2				   .SQX       SET	.SQX + 1
    139  60a2					      REPEND
    140  60a3		       25		      .byte.b	(.SQBASE+.SQX)
    141  60a3				   .SQX       SET	.SQX + 1
    139  60a3					      REPEND
    140  60a4		       26		      .byte.b	(.SQBASE+.SQX)
    141  60a4				   .SQX       SET	.SQX + 1
    139  60a4					      REPEND
    140  60a5		       27		      .byte.b	(.SQBASE+.SQX)
    141  60a5				   .SQX       SET	.SQX + 1
    142  60a6					      REPEND
    143  60a6				   .SQBASE    SET	.SQBASE - 10
    136  60a6					      REPEND
    137  60a6		       00 00		      .byte.b	0,0
    138  60a6				   .SQX       SET	2
    139  60a8					      REPEAT	8
    140  60a8		       16		      .byte.b	(.SQBASE+.SQX)
    141  60a8				   .SQX       SET	.SQX + 1
    139  60a8					      REPEND
    140  60a9		       17		      .byte.b	(.SQBASE+.SQX)
    141  60a9				   .SQX       SET	.SQX + 1
    139  60a9					      REPEND
    140  60aa		       18		      .byte.b	(.SQBASE+.SQX)
    141  60aa				   .SQX       SET	.SQX + 1
    139  60aa					      REPEND
    140  60ab		       19		      .byte.b	(.SQBASE+.SQX)
    141  60ab				   .SQX       SET	.SQX + 1
    139  60ab					      REPEND
    140  60ac		       1a		      .byte.b	(.SQBASE+.SQX)
    141  60ac				   .SQX       SET	.SQX + 1
    139  60ac					      REPEND
    140  60ad		       1b		      .byte.b	(.SQBASE+.SQX)
    141  60ad				   .SQX       SET	.SQX + 1
    139  60ad					      REPEND
    140  60ae		       1c		      .byte.b	(.SQBASE+.SQX)
    141  60ae				   .SQX       SET	.SQX + 1
    139  60ae					      REPEND
    140  60af		       1d		      .byte.b	(.SQBASE+.SQX)
    141  60af				   .SQX       SET	.SQX + 1
    142  60b0					      REPEND
    143  60b0				   .SQBASE    SET	.SQBASE - 10
    144  60b0					      REPEND
    145  60b0
    146  60b0


 

Edited by Andrew Davie
Link to comment
Share on other sites

Hi Andrew,

According to the DASM documentation, the REPEAT-REPEND pseudop can be nested and this appears to be exactly how you are using it.

 

The "ALLOCATE" macro is a macro that you created, correct?  Thus a custom macro can literally have anything inside of it if I understand them correctly, they merely perform a function.  I can see where the use of macros would be very helpful to 2600 programmers, because it appears that the very nature of Assembly Programming can be (quite?) repetitive in nature (a novice observation).

 

Is the ALLOCATE macro then included into the source file at run time via it's "definition" within a "macro.h" type file that you include programmatically?


Thank you for providing that example, it is very helpful!

 

JR

Link to comment
Share on other sites

  • 1 month later...
On 4/15/2020 at 11:20 PM, JohnnyRockets said:

Hi Andrew,

According to the DASM documentation, the REPEAT-REPEND pseudop can be nested and this appears to be exactly how you are using it.

 

The "ALLOCATE" macro is a macro that you created, correct?  Thus a custom macro can literally have anything inside of it if I understand them correctly, they merely perform a function.  I can see where the use of macros would be very helpful to 2600 programmers, because it appears that the very nature of Assembly Programming can be (quite?) repetitive in nature (a novice observation).

 

Is the ALLOCATE macro then included into the source file at run time via it's "definition" within a "macro.h" type file that you include programmatically?


Thank you for providing that example, it is very helpful!

 

JR

 

Sorry for the delay; I did not have "notify me of replies" turned on.

Yes, your understanding is basically correct. Macros are just text substitution before assembly, just like REPEAT/REPEND is.

The ALLOCATE macro effectively, virtually,  "writes into" the source file before the resultant file is assembled.

macro.h is just a filename, like any other. By convention ".h" is a header file, with generic stuff. But I cold have called it "macro.asm" or "fred.txt" and it still would have worked. The "macro.h" contents are also virtually "added to" the source file before the resultant whole lot is assembled.

 

 

 

Link to comment
Share on other sites

  • 3 months later...

For those who like to necro-read, I just wanted to comment that DASM has a totally new manual, available from DASM's homepage.

It deals with the REPEAT/REPEND stuff, with examples. Whoever wrote it did a splendid job. Gets my A+ rating :P
 

https://dasm-assembler.github.io/

 

  • Thanks 1
  • Haha 1
Link to comment
Share on other sites

  • 1 year later...
6 minutes ago, Pat Brady said:

"This looks like a loop, but it isn’t."


I have read that sentence many times. I think I finally understand it. In fact it *is* a loop, but it is a loop that occurs at build-time, not at run-time. It's equivalent to a loop in template metaprogramming.

That is an OK interpretation, and not incorrect. I made the distinction to avoid people thinking it was a loop at runtime. The specified number of copies of the block of text inside the REPEAT/REPEND are simply text-substituted directly into the code to be assembled, at that point where the REPEAT/REPEND occurs. I always thought of it as a nifty "text substitution engine" which allowed you to build up source code for later assembly, and save a lot of typing. The dasm manual gives a few examples of usage. 

Link to comment
Share on other sites

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...