IF macro for ca65

Discuss technical or other issues relating to programming the Nintendo Entertainment System, Famicom, or compatible systems. See the NESdev wiki for more information.

Moderator: Moderators

User avatar
Movax12
Posts: 541
Joined: Sun Jan 02, 2011 11:50 am

IF macro for ca65

Post by Movax12 »

I like NESHLA but it's too limiting, and so I moved on to ca65 for various reasons. The things I liked about NESHLA I figured I could do without or get close enough to the same functionality with macros. I decided to recreate the if functionality with macros and I think it is working well. If anyone is interested I'll post the code up somewhere. What I am able to do is stuff like:

Code: Select all


if {carry set}
   ; do code
endif

;or

if {equal}
 ; blah blah
endif

if {less}
 ; blah blah
endif

It should work with any number of nested ifs and should be easy enough to add your own keywords.
User avatar
Hamtaro126
Posts: 818
Joined: Thu Jan 19, 2006 5:08 pm

Re: IF macro for ca65

Post by Hamtaro126 »

Look at a 6502 manual, There are opcodes for specific operations like this!

They are Branching Instrucions!

EDIT:

IF Carry Set = BCS
IF Equal = BEQ
IF Less = BMI(?)
AKA SmilyMZX/AtariHacker.
User avatar
tokumaru
Posts: 12427
Joined: Sat Feb 12, 2005 9:43 pm
Location: Rio de Janeiro - Brazil

Re: IF macro for ca65

Post by tokumaru »

I'm sure he knows that Hamtaro, since he made the macros and all (and the macros do translate to branch instructions when assembled). Assembly typically lacks indentation and logical blocks, so it's understandable that some people prefer to use macros to make things a little bit less low-level.
User avatar
Movax12
Posts: 541
Joined: Sun Jan 02, 2011 11:50 am

Re: IF macro for ca65

Post by Movax12 »

Hamtaro126 wrote:
IF Carry Set = BCS
IF Equal = BEQ
IF Less = BMI(?)
The macro would actually change carry set to BCC and equal to BNE since I want to enter the block of code if the flag is set.
In normal 6502 assembly Less is BCC, greater or equal is BCS (after a CMP instruction). That is how I implement it in the macro at least - NESHLA used the N flag >:(
User avatar
tokumaru
Posts: 12427
Joined: Sat Feb 12, 2005 9:43 pm
Location: Rio de Janeiro - Brazil

Re: IF macro for ca65

Post by tokumaru »

Movax12 wrote:NESHLA used the N flag >:(
Which is OK if you're dealing with signed numbers. The carry flag can be used for unsigned comparisons, while N and V should be used for signed numbers.
User avatar
Movax12
Posts: 541
Joined: Sun Jan 02, 2011 11:50 am

Re: IF macro for ca65

Post by Movax12 »

I think my brain would think about that better in terms of "is the result negative or not?" rather than less or greater, but I see your point.

So far I have:

Code: Select all

; carry set
; carry clear
; no carry
; not carry
; C
; not C
; C set
; C clear
; less
; not less
; greater_equal
; not greater_equal
; zero
; zero clear
; zero set
; not zero
; equal
; not equal
; Z
; not Z
; Z set
; Z clear
; plus
; not plus
; positive
; not positive
; minus
; negative
; not minus
; not negative
; N
; not N
; N set
; N clear
; bit7
; bit7 set
; bit7 clear
; not bit7
; V
; overflow
; overflow set
; overflow clear
; not overflow
; V
; V set
; V clear
; not V
; bit6
; bit6 clear
; bit6 set
; not bit6
I'm not sure if I am implementing the macro as well as possible, but as long as I stick to the above formats I'm certain it will work. The code is here: http://sharetext.org/dDge
tepples
Posts: 22705
Joined: Sun Sep 19, 2004 11:12 pm
Location: NE Indiana, USA (NTSC)
Contact:

Re: IF macro for ca65

Post by tepples »

tokumaru wrote:The carry flag can be used for unsigned comparisons, while N and V should be used for signed numbers.
Is there a standard test on 6502 for whether unsigned + signed (e.g. position + change) has overflowed unsigned?

Would it be hard to make macros for greater, not greater, less_equal, not less_equal, that use a branch on Z that jumps over a branch on C?

Would "else" be hard?
User avatar
Movax12
Posts: 541
Joined: Sun Jan 02, 2011 11:50 am

Re: IF macro for ca65

Post by Movax12 »

tepples wrote: Would it be hard to make macros for greater, not greater, less_equal, not less_equal, that use a branch on Z that jumps over a branch on C?
Not hard at all. It also wouldn't be hard to implement do-while loops, or repeat-until.
Would "else" be hard?
I briefly thought about that, it might not be too hard.. I'll think about it.
User avatar
Movax12
Posts: 541
Joined: Sun Jan 02, 2011 11:50 am

Re: IF macro for ca65

Post by Movax12 »

So I was implementing ELSE and I realized that trying to track IF/ENDIF pairs with numbers and math doesn't work. It may work most of the time, but it doesn't work all the time. The only proper way to do it is a stack, and actually it's much easier.

So ELSE is working and IF / ENDIF should be 100% reliable as far as matching up the code blocks properly.

http://shorttext.com/f3qe4k
User avatar
Movax12
Posts: 541
Joined: Sun Jan 02, 2011 11:50 am

Re: IF macro for ca65

Post by Movax12 »

I added greater and not greater. I also made some the flag checks more restrictive, like a flag name (Z for example) has to be followed by 'set' or 'clear'. I may add a do while loop and get back to actually coding some 6502. If anyone uses this and needs the code to be relocatable, change the jmp in the else macro to clv/bvc.

http://pastebin.com/PKjw89u8
EDIT: small changes: http://pastebin.com/Hvfr4EQh
User avatar
Movax12
Posts: 541
Joined: Sun Jan 02, 2011 11:50 am

Re: IF macro for ca65

Post by Movax12 »

I've polished this up quite a bit, there is some information here: http://mynesdev.blogspot.ca/2012/09/ca6 ... acros.html

The expression evaluation code has gone from a huge pile of .IFs down to this:

Code: Select all

.macro process_expression_FLAGS flagtest, flag, flagisset

; Find a value for which flag we are checking and return:
	
	_n_ .set  (  (.xmatch(.left(1, {flagtest}) , no)) .or (.xmatch(.left(1, {flagtest}) , not))  ) ; not or no prefix
	
	flag .set (.xmatch(.mid(_n_,1, {flagtest}) , C)) * 1 + (.xmatch(.mid(_n_,1, {flagtest}) , Z)) * 2 + (.xmatch(.mid(_n_,1,{flagtest}) , N)) * 3 + (.xmatch(.mid(_n_,1,{flagtest}) , V)) * 4 + (.xmatch(.mid(_n_,1,{flagtest}) , G)) * 5
	
	flag_set_default .set (.xmatch(.mid(_n_+1,1, {flagtest}), set)) * 1 + (.xmatch(.mid(_n_+1,1, {flagtest}), clear)) *  -1

	.ifnblank .mid(_n_+2,1, {flagtest}) ; user added clear or set, also accept 'do' from "while <exp> do" syntax
		invert_flag			 .set .xmatch(.mid(_n_+2,1, {flagtest}), clear) *  -1  + .xmatch(.mid(_n_+2,1, {flagtest}), set) * 1 + .xmatch(.mid(_n_+2,1, {flagtest}), do) * 1
	.else
		invert_flag 			.set 1 ; no clear or set added, that's okay make it a 1
	.endif
	invert_flag 				.set invert_flag * (_n_ * -2 + 1)
	
	.if ( (flag = 0) .or (flag_set_default = 0) .or (invert_flag =0))
		.error "Unknow expression in flag test."
		.fatal ""
	.endif
	
	 flagisset .set ((flag_set_default * invert_flag) > 0) ; This will always result in a negative or positive, positive being flag is being tested for
	 
.endmacro
It's working well I think, I'll publish all the code soon.

Updated! I am done for now - I'm going to try to actually use it in code. Any feedback welcomed. Code is available at the blog link I posted.
Bananmos
Posts: 552
Joined: Wed Mar 09, 2005 9:08 am
Contact:

Re: IF macro for ca65

Post by Bananmos »

I'm trying out your macro package, and it seems it can't handle local labels within the conditions like in the following snippet:

Code: Select all

    cmp #JOY_A
    if equal
        jmp @Freeze
    endif

    cmp #JOY_B
    if equal
        jmp @Melt
    endif
    lda #0
    rts
Removing the '@' from my label names works fine. While I realize that your macros are supposed to reduce the need for local labels, it would be nice if it didn't disable their usage in this way. Do you think it would be possible to make your macro package support this?...
User avatar
thefox
Posts: 3134
Joined: Mon Jan 03, 2005 10:36 am
Location: 🇫🇮
Contact:

Re: IF macro for ca65

Post by thefox »

Bananmos wrote:Do you think it would be possible to make your macro package support this?...
As far as I know, it's not possible. The macros need to generate labels, and they'll always mess with the local (@) labels. I thought it might be possible to fix this by generating the label inside a scope, but looks like the @ labels don't care about scopes, so they'll get invalidated when any normal label comes. Then I thought it might be possible to generate the label using "foo = *" or "foo := *", but that also invalidates the local labels. As does "foo .set 123". That's all the possible workarounds I can think of...

P.S. Movax, why are you using .error followed by .fatal "", and not only .fatal?
Download STREEMERZ for NES from fauxgame.com! — Some other stuff I've done: fo.aspekt.fi
User avatar
Movax12
Posts: 541
Joined: Sun Jan 02, 2011 11:50 am

Re: IF macro for ca65

Post by Movax12 »

.error outputs a line number with the string.
.fatal stops the assembly, but doesn't give a line number.

There are some minor issues with this too, but the worst error is if the branch is too far, ca65 won't tell you were the problem is in the main code, just in the macro. The branch generation could be changed to always use a jmp with a branch over and I've added an option to do that which isn't too complicated if anyone wants. It's too bad there is no way to decide if the branch is long or not in the macro code.

I don't see a way to use cheap local labels due to the generation of normal labels from the if macro(s)
tepples
Posts: 22705
Joined: Sun Sep 19, 2004 11:12 pm
Location: NE Indiana, USA (NTSC)
Contact:

Re: Converting a Lorom pcb cart to a hirom pcb cart

Post by tepples »

Is there a reason why you're not using macro-local labels?

I also have a bit of a problem with the Creative Commons license, which isn't really meant for code. One of the technicalities making it incompatible with some other licenses is the provision for requiring downstream users to remove credits. I'd have gone with this one.
Post Reply