6502.org Forum  Projects  Code  Documents  Tools  Forum
It is currently Wed Sep 25, 2024 5:23 am

All times are UTC




Post new topic Reply to topic  [ 31 posts ]  Go to page 1, 2, 3  Next
Author Message
PostPosted: Fri Jun 19, 2020 12:19 am 
Offline

Joined: Fri Nov 16, 2018 8:55 pm
Posts: 71
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.


Top
 Profile  
Reply with quote  
PostPosted: Fri Jun 19, 2020 1:48 am 
Offline
User avatar

Joined: Fri Aug 30, 2002 1:09 am
Posts: 8517
Location: Southern California
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 .

_________________
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?


Top
 Profile  
Reply with quote  
PostPosted: Fri Jun 19, 2020 4:44 am 
Offline
User avatar

Joined: Sun Jun 30, 2013 10:26 pm
Posts: 1948
Location: Sacramento, CA, USA
Code:
     jmp  $+3
takes three cycles, and
Code:
     php
     plp
takes seven.

_________________
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)


Top
 Profile  
Reply with quote  
PostPosted: Fri Jun 19, 2020 5:21 am 
Offline

Joined: Mon May 21, 2018 8:09 pm
Posts: 1462
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.


Last edited by Chromatix on Fri Jun 19, 2020 6:02 am, edited 1 time in total.

Top
 Profile  
Reply with quote  
PostPosted: Fri Jun 19, 2020 5:31 am 
Offline
User avatar

Joined: Sun Jun 30, 2013 10:26 pm
Posts: 1948
Location: Sacramento, CA, USA
Chromatix wrote:
BVC *+2 : BVS *+2 always takes 5 cycles ...

I like it!

_________________
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)


Top
 Profile  
Reply with quote  
PostPosted: Sat Jul 18, 2020 12:49 am 
Offline

Joined: Tue Jul 24, 2012 2:27 am
Posts: 674
If you want to delay for a runtime-determined number of cycles, I've used this:

Code:
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


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.

_________________
WFDis Interactive 6502 Disassembler
AcheronVM: A Reconfigurable 16-bit Virtual CPU for the 6502 Microprocessor


Top
 Profile  
Reply with quote  
PostPosted: Mon Jul 20, 2020 10:13 pm 
Offline

Joined: Mon May 01, 2017 7:13 am
Posts: 83
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.


Top
 Profile  
Reply with quote  
PostPosted: Tue Jul 21, 2020 1:26 am 
Offline
User avatar

Joined: Tue Jul 17, 2018 9:58 am
Posts: 106
Location: Long Island, NY
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!


Top
 Profile  
Reply with quote  
PostPosted: Tue Jul 21, 2020 2:29 am 
Offline

Joined: Thu Mar 12, 2020 10:04 pm
Posts: 702
Location: North Tejas
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!


Personally, I like local labels. I talk about it here: viewtopic.php?p=76604#p76604


Top
 Profile  
Reply with quote  
PostPosted: Tue Jul 21, 2020 3:00 am 
Offline
User avatar

Joined: Mon May 12, 2014 6:18 pm
Posts: 365
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.
I find that kind of macro really useful. It took some effort to get it working right, but this saved me a lot of time:
Code:
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
The key is that the macro remembers whether a variable is 8 or 16 bits and outputs the correct assembly even when the source and destination are different sizes. Type awareness is really handy for other macros as well.


Top
 Profile  
Reply with quote  
PostPosted: Tue Jul 21, 2020 3:34 am 
Offline
User avatar

Joined: Fri Aug 30, 2002 1:09 am
Posts: 8517
Location: Southern California
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!

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?


Top
 Profile  
Reply with quote  
PostPosted: Tue Jul 21, 2020 10:18 am 
Offline
User avatar

Joined: Tue Mar 02, 2004 8:55 am
Posts: 996
Location: Berkshire, UK
Who needs local labels when you have structure?
Code:
                             ; 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

Ok. So I used one for the error handler.

'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


Top
 Profile  
Reply with quote  
PostPosted: Tue Jul 21, 2020 11:17 am 
Offline
User avatar

Joined: Wed Jul 01, 2020 6:15 pm
Posts: 79
Location: Germany
[Edit: Ah, got it. I was apparently blind when first looking at the listing ...]


Top
 Profile  
Reply with quote  
PostPosted: Thu Jul 23, 2020 2:34 am 
Offline
User avatar

Joined: Sat Dec 01, 2018 1:53 pm
Posts: 727
Location: Tokyo, Japan
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.
Code:
;--------------------------------------------------------------------------
;   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

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:
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


Top
 Profile  
Reply with quote  
PostPosted: Sun Jan 24, 2021 10:58 am 
Offline

Joined: Wed Jan 13, 2021 5:05 pm
Posts: 7
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?


Top
 Profile  
Reply with quote  
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 31 posts ]  Go to page 1, 2, 3  Next

All times are UTC


Who is online

Users browsing this forum: No registered users and 5 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to: