JohnnyRockets Posted April 14, 2020 Share Posted April 14, 2020 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 More sharing options...
+Andrew Davie Posted April 14, 2020 Share Posted April 14, 2020 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 More sharing options...
Thomas Jentzsch Posted April 14, 2020 Share Posted April 14, 2020 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 More sharing options...
danwinslow Posted April 14, 2020 Share Posted April 14, 2020 hi. One thing to keep in mind is that Pseudops (assember directives) only operate DURING assembly. So that bit of code is not doing a program logic loop, but it is laying down that many blocks of identical code. If you look at the assembly listing, you will see 127 of those. Link to comment Share on other sites More sharing options...
JohnnyRockets Posted April 14, 2020 Author Share Posted April 14, 2020 (edited) 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 April 14, 2020 by JohnnyRockets 1 Link to comment Share on other sites More sharing options...
+SpiceWare Posted April 14, 2020 Share Posted April 14, 2020 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 More sharing options...
JohnnyRockets Posted April 14, 2020 Author Share Posted April 14, 2020 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 More sharing options...
+SpiceWare Posted April 14, 2020 Share Posted April 14, 2020 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 More sharing options...
JohnnyRockets Posted April 14, 2020 Author Share Posted April 14, 2020 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 More sharing options...
+SpiceWare Posted April 15, 2020 Share Posted April 15, 2020 Correct. Link to comment Share on other sites More sharing options...
+Andrew Davie Posted April 15, 2020 Share Posted April 15, 2020 (edited) 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 April 15, 2020 by Andrew Davie Link to comment Share on other sites More sharing options...
JohnnyRockets Posted April 15, 2020 Author Share Posted April 15, 2020 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 More sharing options...
+Andrew Davie Posted May 24, 2020 Share Posted May 24, 2020 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 More sharing options...
+Andrew Davie Posted September 7, 2020 Share Posted September 7, 2020 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 https://dasm-assembler.github.io/ 1 1 Link to comment Share on other sites More sharing options...
+Pat Brady Posted February 22, 2022 Share Posted February 22, 2022 "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. Link to comment Share on other sites More sharing options...
+Andrew Davie Posted February 22, 2022 Share Posted February 22, 2022 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 More sharing options...
Recommended Posts