Reimplementing 6502 syntax in ca65

Discuss technical or other issues relating to programming the Nintendo Entertainment System, Famicom, or compatible systems.

Moderator: Moderators

tepples
Posts: 21980
Joined: Sun Sep 19, 2004 11:12 pm
Location: NE Indiana, USA (NTSC)
Contact:

Reimplementing 6502 syntax in ca65

Post by tepples » Mon Nov 18, 2013 11:05 am

The ca65 assembler comes with a setting for no mnemonics (.setcpu "none") and a rich macro system. I plan to use this to reimplement 6502 instruction syntax the hard way, making each instruction a macro that outputs .byte and .word instructions. You might wonder why one would try this, given that ca65 already supports the 6502. I intend for it to act as an example of how ca65 would be adapted to other instruction sets, such as Z80, GBZ80, SPC700, and MC68000, without a recompile. Or 6502/65816 using x86-style mnemonics (hello nocash) or SPC700 or MC68000 using 6502-style mnemonics (hi byuu).

I started the project yesterday, and I've already got the ALU block (%xxxxxx01) done along with bits and pieces of the control block (%xxxxxx00) and the unofficial RMW+ALU combined block (%xxxxxx11). The biggest hurdle I've found so far is in branches, to determine whether the distance to a future label is more than 129 bytes. The long branch macro pack that comes with ca65 just punts on the issue, making all forward branches long.

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

Re: Reimplementing 6502 syntax in ca65

Post by Movax12 » Mon Nov 18, 2013 12:07 pm

ca65 normally chokes on branches that are too far. It is one-pass, so I don't think you can do much about that.

I was interested in .feature ubiquitous_idents documented here: http://www.cc65.org/snapshot-doc/ca65-11.html#ss11.42

It says it allows overloading, but it seems to do the same thing as .setcpu "none"
For your goal, maybe it is worth looking at the C source?

User avatar
Dwedit
Posts: 4309
Joined: Fri Nov 19, 2004 7:35 pm
Contact:

Re: Reimplementing 6502 syntax in ca65

Post by Dwedit » Mon Nov 18, 2013 12:43 pm

ASM6 was a three-pass assembler just because of the variable lengths of instructions. Variable length instructions screw over any assembler.
Here come the fortune cookies! Here come the fortune cookies! They're wearing paper hats!

User avatar
qbradq
Posts: 951
Joined: Wed Oct 15, 2008 11:50 am

Re: Reimplementing 6502 syntax in ca65

Post by qbradq » Mon Nov 18, 2013 1:19 pm

Wow, that certainly is meta Tepples :) I can see how with such a system in place you could develop a very tightly integrated HLA package.

tepples
Posts: 21980
Joined: Sun Sep 19, 2004 11:12 pm
Location: NE Indiana, USA (NTSC)
Contact:

Re: Reimplementing 6502 syntax in ca65

Post by tepples » Mon Nov 18, 2013 1:42 pm

Movax12 wrote:ca65 normally chokes on branches that are too far.
So if I'm coding a branch's signed relative operand as a .byte, how do I express to ca65 that it is a branch so that it can choke only when too far instead of choking with "Constant expression expected" on every forward branch? Remember that the branch opcodes in one or more of the CPUs that I plan to support aren't necessarily the same values as on a 6502. For example, how would I tell ca65 to range-check forward BBC and BBS (in the x3 column of the SPC700 opcode matrix) branches?
qbradq wrote:I can see how with such a system in place you could develop a very tightly integrated HLA package.
That's sort of what Movax12's IF macro package is supposed to do.

User avatar
blargg
Posts: 3715
Joined: Mon Sep 27, 2004 8:33 am
Location: Central Texas, USA
Contact:

Re: Reimplementing 6502 syntax in ca65

Post by blargg » Mon Nov 18, 2013 1:52 pm

Tepples, if I understand you right, you want to encode a signed byte containing the difference between two addresses, and want an error when the difference can't be represented in a signed byte. If so, can you just put a .if that checks this condition? As I remember, ca65 allows almost anything in a .if, and its evaluation is deferred until link time.

tepples
Posts: 21980
Joined: Sun Sep 19, 2004 11:12 pm
Location: NE Indiana, USA (NTSC)
Contact:

Re: Reimplementing 6502 syntax in ca65

Post by tepples » Mon Nov 18, 2013 2:52 pm

blargg wrote:Tepples, if I understand you right, you want to encode a signed byte containing the difference between two addresses, and want an error when the difference can't be represented in a signed byte.
Correct. An explicit check with .if works for backward references, but not for forward references. As far as I can tell, the only forward references that get range-checked in this way are the branch instructions of the assembler's predefined instruction sets.
As I remember, ca65 allows almost anything in a .if, and its evaluation is deferred until link time.
I thought .if required a constant expression. From the manual:
An expression used in the .IF command cannot reference a symbol defined later, because the decision about the .IF must be made at the point when it is read.

User avatar
thefox
Posts: 3141
Joined: Mon Jan 03, 2005 10:36 am
Location: Tampere, Finland
Contact:

Re: Reimplementing 6502 syntax in ca65

Post by thefox » Mon Nov 18, 2013 3:15 pm

tepples wrote:
blargg wrote:Tepples, if I understand you right, you want to encode a signed byte containing the difference between two addresses, and want an error when the difference can't be represented in a signed byte.
Correct. An explicit check with .if works for backward references, but not for forward references. As far as I can tell, the only forward references that get range-checked in this way are the branch instructions of the assembler's predefined instruction sets.
As I remember, ca65 allows almost anything in a .if, and its evaluation is deferred until link time.
I thought .if required a constant expression. From the manual:
An expression used in the .IF command cannot reference a symbol defined later, because the decision about the .IF must be made at the point when it is read.
Try using .assert. If needed, its evaluation will be deferred until link time.
Download STREEMERZ for NES from fauxgame.com! — Some other stuff I've done: fo.aspekt.fi

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

Re: Reimplementing 6502 syntax in ca65

Post by Movax12 » Mon Nov 18, 2013 3:22 pm

Yes; if you are looking to output friendly errors, rather than solve forward branching, you can do so with an .assert statement.

User avatar
blargg
Posts: 3715
Joined: Mon Sep 27, 2004 8:33 am
Location: Central Texas, USA
Contact:

Re: Reimplementing 6502 syntax in ca65

Post by blargg » Mon Nov 18, 2013 3:39 pm

I'm having a lapse because I'm not imagining the problem with this:

Code: Select all

.byte target-*
...
target:
That encodes the branch offset, then you use an assert to verify that it's in range.

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

Re: Reimplementing 6502 syntax in ca65

Post by Movax12 » Mon Nov 18, 2013 4:13 pm

I think that should work.

tepples
Posts: 21980
Joined: Sun Sep 19, 2004 11:12 pm
Location: NE Indiana, USA (NTSC)
Contact:

Re: Reimplementing 6502 syntax in ca65

Post by tepples » Mon Nov 18, 2013 5:43 pm

Thanks Movax12 and blargg. This is what I came up with so far for branches:

Code: Select all

.macro NONE02_branch inst, target
  .local distance
  distance = (target) - (* + 2)
  .assert distance >= -128 && distance <= 127, error, "branch out of range"
  .byte inst, <distance
.endmacro

.macro bpl target
  NONE02_branch $10, {target}
.endmacro

.macro bmi target
  NONE02_branch $30, {target}
.endmacro
Right now I'm 25% of the way through the opcode matrix. I'll upload it for all of you to bang on once I reach ISC $FFFF,x.
Last edited by tepples on Mon Nov 18, 2013 7:33 pm, edited 2 times in total.
Reason: 75%

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

Re: Reimplementing 6502 syntax in ca65

Post by Movax12 » Mon Nov 18, 2013 5:51 pm

I was considering doing this with my macro code, since I like to represent code like this:

Code: Select all

lda foo+$10,x
as:

Code: Select all

lda foo[ $10 + x]
So I would be interested to know what the performance ends up being like when building a large project. I might look into doing the same thing. Or borrowing your code, tepples. I felt this would be better implemented in source code as an alternative branch of ca65, but if performance is okay, there is no need.

tepples
Posts: 21980
Joined: Sun Sep 19, 2004 11:12 pm
Location: NE Indiana, USA (NTSC)
Contact:

Sun++

Post by tepples » Mon Nov 18, 2013 8:25 pm

I started this project for at least two reasons.

One is that I wanted to see what other 8- and 16-bit assembly languages would look like in 6502 drag. I have an idea of how to do 68K, and it starts by renaming D0-D7 to A-H and A0-A7 to Z-S. This preserves Y (A1) and X (A2) as performing indexing-related operations, and S is conveniently the stack pointer.

The other is that I'm following up on my promise from two years ago. I didn't want to have to require people who build on my libraries to install both ca65 and bass for Super NES projects, and I thought there'd be resistance to implementing other 8- and 16-bit CPUs' assembly languages directly in the source code of ca65. I found a bunch of mentions of a Sunplus CPU whose instruction set is "proprietary and confidential". SPC doesn't stand for "Sunplus chip", does it? Did Sony and Sunplus collaborate?
Attachments
ca65none.s.zip
(3.28 KiB) Downloaded 312 times

User avatar
blargg
Posts: 3715
Joined: Mon Sep 27, 2004 8:33 am
Location: Central Texas, USA
Contact:

Re: Reimplementing 6502 syntax in ca65

Post by blargg » Mon Nov 18, 2013 9:43 pm

Wow, this is going to be real. I had taken a stab a while back at gb-z80 but got hung up on the foundation macros. I hope we can get gb-z80 and spc-700 into this. No more assembler cocktail.

Code: Select all

.macro nop
  .byte $EA  ; If it's in the game, it's in the game.
.endmacro
Took me a moment. When I was little and saw $EA in disassemblies on the Apple //, I thought it was because it was an EA game and they plastered their initials in unused areas of memory.

EDIT: gave this a try and it assembled its test opcodes so well I had to try it on my library code and a test. After lots of fixes it assembled it as-is and ran fine. It looks like the only issue was that variables in the .zp segment used absolute addressing. I'm seeing whether there is a way to determine this in a macro.

A few places needed an additional .const condition to avoid trying to compare a non-constant.

Many places needed @ prefixes on the .local symbols (you'd think that .local was enough), otherwise they broke @ symbols in the using code. I only changed those needed to compile my code, so there are more (I tried a global search-and-replace, but got some weird errors so backed off).

Very impressed!
Attachments
ca65none.s.zip
Partly fixed, removed opcode tests so it was usable in real code
(2.16 KiB) Downloaded 313 times
Last edited by blargg on Mon Nov 18, 2013 10:33 pm, edited 1 time in total.

Post Reply