Page 1 of 1

High level macros

Posted: Sat Sep 14, 2013 3:33 pm
by Movax12
Hi,

I'd like to let everyone here know about the macros I have been working on for high-level like coding with the 6502. My target is NES, so no 65c02 or better features are targeted. Maybe in the future they will be.

I've been working on and using these macros for some time. I use them often and they have been somewhat tested by others. Anyone who already uses ca65 will have no trouble giving them a try as only two files are needed and only one file needs to be included in your source module:

Code: Select all

.include "ca65hl.h"
There is no library code and no memory used. The syntax is quite flexible, and logical structures can of course be nested as much as you would like. You can also create your own custom macros to work with the logical conditions, which act like boolean functions. The resulting code can look very high-level, but still maintains an almost 1:1 relationship to the underlying assembly in almost every case.

The only possible downside is that for very large projects it can be slow to build, but if you are utilizing that fact that ca65 has a linker, your code can (in my opinion, should) be separated into modules, which will eliminate this issue.

I am currently working on some sample code, and updating the wiki: https://www.assembla.com/spaces/ca65hl/wiki

Thanks!

Re: High level macros

Posted: Sat Sep 14, 2013 6:49 pm
by GARTHWILSON
I'm glad to see the interest in this growing! You're the fourth one here so far (that I know of) to be doing this-- or maybe third, since BitWise's aren't macros. He built the capability into his assembler so in that respect it's partly a compiler, not just an assembler; but the end result is the same. It also chooses which instructions to use based on whether a branch distance is outside the -128 to +127 range (which would be a really big program structure, but it can happen, especially with a CASE statement).

Re: High level macros

Posted: Sat Sep 14, 2013 8:17 pm
by enso
assemblia.com link is not working!

Re: High level macros

Posted: Sat Sep 14, 2013 8:21 pm
by GARTHWILSON
It works for me. Maybe it was down briefly?

Re: High level macros

Posted: Sat Sep 14, 2013 8:45 pm
by Movax12
GARTHWILSON wrote:
I'm glad to see the interest in this growing!
:)
Quote:
It also chooses which instructions to use based on whether a branch distance is outside the -128 to +127 range (which would be a really big program structure, but it can happen, especially with a CASE statement).
ca65 will stop with an error if a branch is too far, at which time the user can add the macro directive setLongBranch + before the offending statement to invert all branch logic and use absolute jmp instructions. I plan to finish implementing a warning when you have a long branch where it is not needed, but that is not properly implemented at the moment.

Unfortunately (in this case), ca65 is a one pass assembler, and can't figure out if a branch is too far until it is too late to fix automatically with macro code.

I haven't really looked at adding a CASE, but I've looked at adding FOR, but am hesitant due to wanting to stick to a C like syntax, and the C FOR loop being more like a while <> do, meaning an inefficient jmp back to the top of the while to test the condition on the last iteration. I guess a FOR loop doesn't have to stick to that structure though.

Re: High level macros

Posted: Sat Sep 14, 2013 10:20 pm
by GARTHWILSON
Quote:
I haven't really looked at adding a CASE, but I've looked at adding FOR, but am hesitant due to wanting to stick to a C like syntax, and the C FOR loop being more like a while <> do, meaning an inefficient jmp back to the top of the while to test the condition on the last iteration. I guess a FOR loop doesn't have to stick to that structure though.
I modeled my structures mosly after Forth's standard ones (I say "standard" because Forth lets you make your own, in fact you can even define your own operators in Forth) but I figured BASIC's FOR...NEXT kind of syntax would be more readily accepted than Forth's simple but unusual DO...LOOP sytax (if you can even call it syntax, as Forth hardly has any syntax) by non-Forth-speaking people. In DO...LOOP, the internal compiled by DO only runs once, at the beginning of the loop, to prepare the stack, and then the internal compiled by LOOP (at the end of the loop) is what determines whether to go back to the top or not, similar to assembly language. The FOR...NEXT macros assemble the same thing you would do by hand, with for example:

Code: Select all

    FOR_X 8, DOWN_TO, 0
        <loop contents>
        <actions, actions>
        <yada yada>
    NEXT_X
which assembles:

Code: Select all

        LDX  #8
TOP:        <loop contents>
            <actions, actions>
            <yada yada>
        DEX
        BNE  TOP
The loop does not get run for the counter value equal to 0 like it would in BASIC, but it's a better transfer to/from assembly where we're subconsciously thinking of the DEX BNE here.

There are so many possible ways to do a FOR...LOOP in assembly thought that I originally thought it would not be feasible, so FOR...NEXT was added a long time after I did the others, and the FOR...NEXT macros are very long for the little code they lay down (which is usually only two or three bytes), because of the many options the macros have to sort out to decide what code to lay down.

I consider the CASE statement to be very valuable, but I have never run into a situation where I've had to nest CASE statements. CASE and my 16-bit FOR...NEXT (which is separate from FOR_X|FOR_Y...NEXT_X|NEXT_Y which are always 8-bit for 6502) are the only ones I have not made nestable.

Re: High level macros

Posted: Mon Oct 14, 2013 4:03 pm
by Movax12
My macros now feature support for parentheses in expressions! Although I am confident everything is working I would consider this untested, beta code.

https://www.assembla.com/code/ca65hl/git/nodes/devel

Following the same rules as the previous version, you can test 'expressions' that represent or result in a CPU flag being set/clear and branch appropriately. The latest code allows parentheses to create more complex logical conditions, as well as a negate operator that can distribute across parenthesis. The code generated aims to be efficient and will short circuit as soon as the outcome can be determined.

The only limitation is that all OR logic must be before all AND logic in the same parentheses set. ( Add parentheses to work around this.)

Some poor nonsensical examples:

Code: Select all

 ; branch to label:
    * = 8000
    
    foo = $00
    bar = $01
    baz = $03
    myLabel = * + $50
    
    if ( ( foo >= #$03 && ! bar ) || ((zero && negative) || baz = #1)) goto myLabel

    ; code output:    
    8000   A5 00      LDA $00
    8002   C9 03      CMP #$03
    8004   90 04      BCC $800A
    8006   A5 01      LDA $01
    8008   F0 46      BEQ $8050
    800A   D0 02      BNE $800E
    800C   30 42      BMI $8050
    800E   A5 03      LDA $03
    8010   C9 01      CMP #$01
    8012   F0 3C      BEQ $8050

; if-endif ( else supported )

    * = 8000    
    
    foo = $00
    bar = $01
    baz = $03
    
    if (  !( bar & #$03 && baz == N set ) || (( V set || baz < #$10 ) || foo = #1) )
        nop
    endif

    ; code output:
    8000   A5 01      LDA $01
    8002   29 03      AND #$03
    8004   F0 12      BEQ $8018
    8006   A5 03      LDA $03
    8008   10 0E      BPL $8018
    800A   70 0C      BVS $8018
    800C   A5 03      LDA $03
    800E   C9 10      CMP #$10
    8010   90 06      BCC $8018
    8012   A5 00      LDA $00
    8014   C9 01      CMP #$01
    8016   D0 01      BNE $8019
    8018   EA         NOP
    8019

Re: High level macros

Posted: Wed Oct 16, 2013 4:51 pm
by Movax12
Implemented FOR; devel branch on assembla will be updated in the next few days.

http://i.imgur.com/KkUbyEA.png

Re: High level macros

Posted: Wed Oct 16, 2013 6:44 pm
by GARTHWILSON
with step size too. I didn't get that far on mine.

Re: High level macros

Posted: Wed Oct 23, 2013 2:20 am
by Movax12
FOR added to the devel branch: https://www.assembla.com/code/ca65hl/git/nodes/devel

I changed how it works from the first example I posted.

1)C-style of loop:
for ( <thing to do 1st>, <Flag to test - continue while true >, <stuff to do at end of loop> )

Example:

Code: Select all

for ( x := #$3, not negative, dex )
; code
next

; more complex:

for ( x := foo, (x > #10) && (foo <> #1), dex:dex)
    ; some code
next

2) BASIC-style syntax:

This actually tries to optimize some, and will break if you mess with your counter register or variable without thinking:

Code: Select all

for x := #$AA to #$10 step -3
    ;some code
next
It will loop until your counter hits the first invalid (for the loop) value. If possible it will skip CMP and use BPL/BMI or a lone BNE. 'step' can be omitted and a step of -1 or 1 decided on if possible. You can use variables rather than immediate values, but no optimizations are possible.

Re: High level macros

Posted: Mon Nov 04, 2013 5:18 pm
by Movax12
Hi,

It may need some polish, but I updated the documentation on the wiki for ca65hl:

https://www.assembla.com/spaces/ca65hl/wiki