Macro/Function Pseudo Instructions Everyone Should Use?
Macro/Function Pseudo Instructions Everyone Should Use?
When you write code for decently large projects in 6502 assembly (any dialect) what sorts of macros and functions are a "must" in your mind?
Personally, I created a simple not pseudo-instruction as an alias for eor #$ff as a purely stylistic preference. I just find it easier to read. Additionally, nand and nor followed. I'm not trying to go "macro crazy" or anything, but I have thought about different functions macros I could experiment with besides 1-2 instruction aliases.
Because 6502 is load/store based, I've played around with a few variations on the on "copy #counter $[source], $[target]" theme. I'm sure everyone else has too.
I thought about implementing a pair of multiply and divide instructions. But, that's not as simple as it sounds because of differing memory and performance characteristics as several articles made clear while I was researching the topic.
I've also tried to figure out how to (functionally) nop an odd number of cycles without resorting to an illegal opcode. I haven't come up with anything yet. I'm sure it will hit me eventually and seem "obvious" in hindsight.
Personally, I created a simple not pseudo-instruction as an alias for eor #$ff as a purely stylistic preference. I just find it easier to read. Additionally, nand and nor followed. I'm not trying to go "macro crazy" or anything, but I have thought about different functions macros I could experiment with besides 1-2 instruction aliases.
Because 6502 is load/store based, I've played around with a few variations on the on "copy #counter $[source], $[target]" theme. I'm sure everyone else has too.
I thought about implementing a pair of multiply and divide instructions. But, that's not as simple as it sounds because of differing memory and performance characteristics as several articles made clear while I was researching the topic.
I've also tried to figure out how to (functionally) nop an odd number of cycles without resorting to an illegal opcode. I haven't come up with anything yet. I'm sure it will hit me eventually and seem "obvious" in hindsight.
- GARTHWILSON
- Forum Moderator
- Posts: 8775
- Joined: 30 Aug 2002
- Location: Southern California
- Contact:
Re: Macro/Function Pseudo Instructions Everyone Should Use?
We've had some good macro topics here in the past:
assembler macros!
desirable assembler features
Passing a variable as an argument to a macro
ANN: HXA0.190 teamtempest's (Anton Treuenfels') topic on program structures in his HXA 65c02/816 assembler. It was an honor that he copied my structures here and implemented them in the assembler he provides.
A sensible macro engine In this one, enso proposes and explores the idea of a macro pre-processor that could then be used with various assemblers including ones with no macro capability.
And mentioned on the forum by HansO, is "Macross 6502, an assembler for people who hate assembly language," a very C-like macro assembler for the 6502 (NMOS only). (Note the two s's in "Macross.")
I use macros to form high-level program flow-control structures, and have an article about it, with source code, at http://wilsonminesco.com/StructureMacros/, and extended examples in the last 40% of the page at http://wilsonminesco.com/multitask/index.html, and more on how the macros do their job at http://wilsonminesco.com/stacks/pgmstruc.html .
assembler macros!
desirable assembler features
Passing a variable as an argument to a macro
ANN: HXA0.190 teamtempest's (Anton Treuenfels') topic on program structures in his HXA 65c02/816 assembler. It was an honor that he copied my structures here and implemented them in the assembler he provides.
A sensible macro engine In this one, enso proposes and explores the idea of a macro pre-processor that could then be used with various assemblers including ones with no macro capability.
And mentioned on the forum by HansO, is "Macross 6502, an assembler for people who hate assembly language," a very C-like macro assembler for the 6502 (NMOS only). (Note the two s's in "Macross.")
I use macros to form high-level program flow-control structures, and have an article about it, with source code, at http://wilsonminesco.com/StructureMacros/, and extended examples in the last 40% of the page at http://wilsonminesco.com/multitask/index.html, and more on how the macros do their job at http://wilsonminesco.com/stacks/pgmstruc.html .
http://WilsonMinesCo.com/ lots of 6502 resources
The "second front page" is http://wilsonminesco.com/links.html .
What's an additional VIA among friends, anyhow?
The "second front page" is http://wilsonminesco.com/links.html .
What's an additional VIA among friends, anyhow?
- barrym95838
- Posts: 2056
- Joined: 30 Jun 2013
- Location: Sacramento, CA, USA
Re: Macro/Function Pseudo Instructions Everyone Should Use?
Code: Select all
jmp $+3Code: Select all
php
plpGot a kilobyte lying fallow in your 65xx's memory map? Sprinkle some VTL02C on it and see how it grows on you!
Mike B. (about me) (learning how to github)
Mike B. (about me) (learning how to github)
Re: Macro/Function Pseudo Instructions Everyone Should Use?
BRA *+2 also takes three cycles (taken branch) and only two bytes. There is never a page-crossing penalty because the offset is zero.
BVC *+2 : BVS *+2 always takes 5 cycles (one taken branch, one fall-through), and works on NMOS as well as CMOS. You could use any other pair of complementary branches too.
On both NMOS and CMOS, but *not* the '816, opcode $44 is an undocumented 2-byte, 3-cycle NOP; it performs a zero-page access but does nothing with the result. On the '816 it is MVN, so be careful.
BVC *+2 : BVS *+2 always takes 5 cycles (one taken branch, one fall-through), and works on NMOS as well as CMOS. You could use any other pair of complementary branches too.
On both NMOS and CMOS, but *not* the '816, opcode $44 is an undocumented 2-byte, 3-cycle NOP; it performs a zero-page access but does nothing with the result. On the '816 it is MVN, so be careful.
Last edited by Chromatix on Fri Jun 19, 2020 6:02 am, edited 1 time in total.
- barrym95838
- Posts: 2056
- Joined: 30 Jun 2013
- Location: Sacramento, CA, USA
Re: Macro/Function Pseudo Instructions Everyone Should Use?
Chromatix wrote:
BVC *+2 : BVS *+2 always takes 5 cycles ...
Got a kilobyte lying fallow in your 65xx's memory map? Sprinkle some VTL02C on it and see how it grows on you!
Mike B. (about me) (learning how to github)
Mike B. (about me) (learning how to github)
-
White Flame
- Posts: 704
- Joined: 24 Jul 2012
Re: Macro/Function Pseudo Instructions Everyone Should Use?
If you want to delay for a runtime-determined number of cycles, I've used this:
Starting with the entry point of the last $EA taking 2 cycles (NOP), each consecutively prior entry address takes 1 more clock cycle. C9 is CMP #imm.
Code: Select all
delayJumpVectorInit:
cmp #$c9 ; 25 | 24 cycles
cmp #$c9 ; 23 | 22 cycles
cmp #$c9 ; 21 | 20 cycles
cmp #$c9 ; 19 | 18 cycles
cmp #$c9 ; 17 | 16 cycles
cmp #$c9 ; 15 | 14 cycles
cmp #$c9 ; 13 | 12 cycles
cmp #$c9 ; 11 | 10 cycles
cmp #$c9 ; 9 | 8 cycles
cmp #$c9 ; 7 | 6 cycles
cmp #$c9 ; 5 | 4 cycles
bit $ea ; 3 | 2 cycles
Re: Macro/Function Pseudo Instructions Everyone Should Use?
Since Bill Gates was writing 6502 code, it's been conventional to have a series of pseudo opcodes in the form JEQ, JNE, JCC, JCS, JVC, JVS, JMI, and JPL.
These pseudo-ops compile exactly to their B?? counterparts, unless the jump target is more than +/-128 bytes away, in which case they compile to a combination of the opposite branch type plus a jump.
So, a "JNE target" instruction can compile to:
BNE target
Or it can compile to:
BEQ branchnottaken
JMP target
.branchnottaken
Depending on the distance from the current program counter to target.
These pseudo-ops compile exactly to their B?? counterparts, unless the jump target is more than +/-128 bytes away, in which case they compile to a combination of the opposite branch type plus a jump.
So, a "JNE target" instruction can compile to:
BNE target
Or it can compile to:
BEQ branchnottaken
JMP target
.branchnottaken
Depending on the distance from the current program counter to target.
Re: Macro/Function Pseudo Instructions Everyone Should Use?
One assembler feature I've been wondering exists anywhere is using "{" as label to the next instance of "}", with the ability to nest them.
(It could be some other pair of demarcating characters, those are just the first I think of as a C guy)
This would save me from having to come up with unique label names, or avoid bugs that happen if i miscount bytes when writing BEQ *+n
Had this happen on my current project when I forgot that one of my named memory locations wasn't actually zero page. Oops!
(It could be some other pair of demarcating characters, those are just the first I think of as a C guy)
This would save me from having to come up with unique label names, or avoid bugs that happen if i miscount bytes when writing BEQ *+n
Had this happen on my current project when I forgot that one of my named memory locations wasn't actually zero page. Oops!
Re: Macro/Function Pseudo Instructions Everyone Should Use?
Agumander wrote:
One assembler feature I've been wondering exists anywhere is using "{" as label to the next instance of "}", with the ability to nest them.
(It could be some other pair of demarcating characters, those are just the first I think of as a C guy)
This would save me from having to come up with unique label names, or avoid bugs that happen if i miscount bytes when writing BEQ *+n
Had this happen on my current project when I forgot that one of my named memory locations wasn't actually zero page. Oops!
(It could be some other pair of demarcating characters, those are just the first I think of as a C guy)
This would save me from having to come up with unique label names, or avoid bugs that happen if i miscount bytes when writing BEQ *+n
Had this happen on my current project when I forgot that one of my named memory locations wasn't actually zero page. Oops!
Re: Macro/Function Pseudo Instructions Everyone Should Use?
Quote:
Because 6502 is load/store based, I've played around with a few variations on the on "copy #counter $[source], $[target]" theme. I'm sure everyone else has too.
Code: Select all
BYTE foo
WORD bar,baz
MOV #$1234,bar
MOV bar,foo
MOV foo,baz
;After expansion:
LDA #$34
STA bar,X
LDA #$12
STA bar+1,X
LDA bar,X
STA foo,X
LDA foo,X
STA baz,X
STZ baz+1,X- GARTHWILSON
- Forum Moderator
- Posts: 8775
- Joined: 30 Aug 2002
- Location: Southern California
- Contact:
Re: Macro/Function Pseudo Instructions Everyone Should Use?
Agumander wrote:
One assembler feature I've been wondering exists anywhere is using "{" as label to the next instance of "}", with the ability to nest them.
(It could be some other pair of demarcating characters, those are just the first I think of as a C guy)
This would save me from having to come up with unique label names, or avoid bugs that happen if i miscount bytes when writing BEQ *+n
Had this happen on my current project when I forgot that one of my named memory locations wasn't actually zero page. Oops!
(It could be some other pair of demarcating characters, those are just the first I think of as a C guy)
This would save me from having to come up with unique label names, or avoid bugs that happen if i miscount bytes when writing BEQ *+n
Had this happen on my current project when I forgot that one of my named memory locations wasn't actually zero page. Oops!
That's what my article on using macros to form nestable program flow control structures is about, at http://wilsonminesco.com/StructureMacros/ . I much prefer the natural-language characteristic over curly braces, and it should be implementable on any macro assembler with very few modifications needed to make it work. There are a few extended examples of the macro usage in the last 40% of the page at http://wilsonminesco.com/multitask/, and further explanation of the macros' inner workings in the relevant chapter of the 6502 stacks treatise, at http://wilsonminesco.com/stacks/pgmstruc.html .
Andrew Jacobs (forum name "BitWise") has published his free AS65 assembler that has a similar thing built in, at http://www.obelisk.me.uk/dev65/as65.html . Also, Anton Treuenfels (forum name "teamtempest") has his HXA assembler he wrote incorporating my program structures, at https://web.archive.org/web/20190208204 ... .net/~hxa/ .
http://WilsonMinesCo.com/ lots of 6502 resources
The "second front page" is http://wilsonminesco.com/links.html .
What's an additional VIA among friends, anyhow?
The "second front page" is http://wilsonminesco.com/links.html .
What's an additional VIA among friends, anyhow?
- BitWise
- In Memoriam
- Posts: 996
- Joined: 02 Mar 2004
- Location: Berkshire, UK
- Contact:
Re: Macro/Function Pseudo Instructions Everyone Should Use?
Who needs local labels when you have structure?
Ok. So I used one for the error handler.
'816 code with 16-bit index registers when called.
Code: Select all
; Process the string pointered to be Y extracting any initial line number and
; replacing any keywords with token codes.
TokenizeLine:
C0:00BE 201201 : jsr SkipSpaces ; Skip any spaces
C0:00C1 206300 : jsr IsDigit ; Found a line number?
C0:00C4 08 : php
C0:00C5 9042 : if cs
C0:00C7 6404 : stz LINENO+0 ; Zero the line number
C0:00C9 6405 : stz LINENO+1
repeat
C0:00CB 290F : and #$0f ; Extract digit value
C0:00CD 18 : clc ; .. and add into line number
C0:00CE 6504 : adc LINENO+0
C0:00D0 8504 : sta LINENO+0
C0:00D2 9004 : if cs
C0:00D4 E605 : inc LINENO+1
C0:00D6 F036 : beq .Failed
endif
C0:00D8 B90000 : lda !0,y ; Another digit?
C0:00DB C8 : iny
C0:00DC 206300 : jsr IsDigit
C0:00DF 9028 : break cc ; No. done
C0:00E1 48 : pha ; Yes, save it
C0:00E2 A505 : lda LINENO+1 ; Save x1
C0:00E4 48 : pha
C0:00E5 A504 : lda LINENO+0
C0:00E7 48 : pha
C0:00E8 0604 : asl LINENO+0 ; x2
C0:00EA 2605 : rol LINENO+1
C0:00EC B020 : bcs .Failed
C0:00EE 0604 : asl LINENO+0 ; x4
C0:00F0 2605 : rol LINENO+1
C0:00F2 B01A : bcs .Failed
C0:00F4 68 : pla ; Add x1 to x4 => x5
C0:00F5 6504 : adc LINENO+0
C0:00F7 8504 : sta LINENO+0
C0:00F9 68 : pla
C0:00FA 6505 : adc LINENO+1
C0:00FC 8505 : sta LINENO+1
C0:00FE B00E : bcs .Failed
C0:0100 0604 : asl LINENO+0 ; x10
C0:0102 2605 : rol LINENO+1
C0:0104 B008 : bcs .Failed
C0:0106 68 : pla ; Repeat for next digit
C0:0107 80C2 : forever
endif
C0:0109 201101 : jsr TokenizeCmd
C0:010C 28 : plp
C0:010D 60 : rts
C0:010E 4C1C02 : .Failed: jmp SyntaxError ; Syntax error if line number too big
'816 code with 16-bit index registers when called.
Andrew Jacobs
6502 & PIC Stuff - http://www.obelisk.me.uk/
Cross-Platform 6502/65C02/65816 Macro Assembler - http://www.obelisk.me.uk/dev65/
Open Source Projects - https://github.com/andrew-jacobs
6502 & PIC Stuff - http://www.obelisk.me.uk/
Cross-Platform 6502/65C02/65816 Macro Assembler - http://www.obelisk.me.uk/dev65/
Open Source Projects - https://github.com/andrew-jacobs
Re: Macro/Function Pseudo Instructions Everyone Should Use?
[Edit: Ah, got it. I was apparently blind when first looking at the listing ...]
Re: Macro/Function Pseudo Instructions Everyone Should Use?
My most commonly used macro is INCW to increment a word. Re-reading it also reminded me to be careful about the use of labels in macros: in Macroassembler AS a macro can close the scope of local symbols if you're not careful.
One I thought would be quite useful, but actually these days seems less so, is for "automatic" definition of storage in the zero page, called with code like:
Code: Select all
;--------------------------------------------------------------------------
; INCW macro to increment a word
;
; We must use only composed or named temporary symbols in macros because
; even a macro-internal non-temporary symbol will close the current
; composed/named temporary symbol scope and open a new one. (Nameless +/-
; temporary symbols also cannot be used because they generate a fresh
; non-temporary symbol.) The unit test takes care to cover this.
incw macro addr
inc addr
bne .nocarry
inc addr+1
.nocarry
endm
Code: Select all
temp1: zds 1
temp2: zds 1
bufSptr: zds 2 ; pointer to a buffer
bufSlen: zds 1 ; length of that buffer
buf0ptr: zds 2
buf0len: zds 1
Curt J. Sampson - github.com/0cjs
Re: Macro/Function Pseudo Instructions Everyone Should Use?
I've downloaded Andrew Jacob's Dev65 assembler, mentioned here. Despite the name, it copes with several 8-bit CPU families, which is what I need, and I really like the look of the structured programming aids. But I can't figure out how to run it!
I know very little about Java, but my understanding is that .java files are source files, compiled by 'full blown' Java / JDK, which creates compiled code (.class files?), which can be run by just the runtime, JRE.
The Dev65 that I've downloaded is packed with .java files, which suggests that they all need compiling. But this is in contrast to the instructions, which imply that the Java runtime (JRE) is sufficient to run it.
In fact, although Dev65 looks to be actively updated (last refresh ~ Oct 2020), the instructions for it may well be quite out of date, and I'm wondering if they still refer to a much older predecessor to it, called 65xx. I've downloaded that as well, and this looks quite different. There is a variety of compiled Java classes in a Zip file, with simple one-line Windows .bat scripts to get the assembler going.
I'm using Windows 10 64-bit, and have already installed the latest JRE. I've successfully done a quick test of the assembler in the much older 65xx package, and that runs OK, producing LST and OBJ files in no time. So I know the JRE is working.
But that older package is for the 65xx family only, and I really want the multi-CPU abilities of Dev65. I know several other assemblers can do that, and if I have to opt for them, then I will. But I'd really like to have a good try with Dev65, and exploit those structured programming tools.
Do I really have to download the 'full blown' Java / JDK (registration required now?) and compile the sources? If so, is there an easy way to compile the whole package in one go? Or have I completely got the wrong end of the stick?
I know very little about Java, but my understanding is that .java files are source files, compiled by 'full blown' Java / JDK, which creates compiled code (.class files?), which can be run by just the runtime, JRE.
The Dev65 that I've downloaded is packed with .java files, which suggests that they all need compiling. But this is in contrast to the instructions, which imply that the Java runtime (JRE) is sufficient to run it.
In fact, although Dev65 looks to be actively updated (last refresh ~ Oct 2020), the instructions for it may well be quite out of date, and I'm wondering if they still refer to a much older predecessor to it, called 65xx. I've downloaded that as well, and this looks quite different. There is a variety of compiled Java classes in a Zip file, with simple one-line Windows .bat scripts to get the assembler going.
I'm using Windows 10 64-bit, and have already installed the latest JRE. I've successfully done a quick test of the assembler in the much older 65xx package, and that runs OK, producing LST and OBJ files in no time. So I know the JRE is working.
But that older package is for the 65xx family only, and I really want the multi-CPU abilities of Dev65. I know several other assemblers can do that, and if I have to opt for them, then I will. But I'd really like to have a good try with Dev65, and exploit those structured programming tools.
Do I really have to download the 'full blown' Java / JDK (registration required now?) and compile the sources? If so, is there an easy way to compile the whole package in one go? Or have I completely got the wrong end of the stick?