Automatically translating ca65 code to ASM6 code

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

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

Automatically translating ca65 code to ASM6 code

Post by tepples »

I wrote a fairly complex library in ca65.* It spans two files containing assembly language code and three include files: one defining the public API, one defining the data formats and library-internal API, and one configuration file that determines which features shall and shall not be included in the library. The configuration file controls a lot of conditional assembly (.if blocks). It places variables in zero page and BSS, and it places code and data in two segments determined by the config file (which may or may not be CODE and RODATA).

I have received a request for a version of this library compatible with the ASM6 assembler. As I understand it, ASM6 does not have a counterpart to ca65 .res; all variable allocation is handled with equates. In addition, ASM6 does not have a counterpart to ca65 .segment; order of code in the output corresponds to order of code in the input. It does appear to have a counterpart to .scope as rept 1; this could be used to translate a .proc.

Is there a way to bridge this feature gap that is less complex than A. actually writing an assembler that fully parses ca65 code and evaluates its expressions and macros, or B. hand-translating each line from ca65 to ASM6 and finding some way to determine that the code produced by the ca65 version remains identical to the code produced by the ASM6 version even after I fix bugs in or add features to the ca65 version?


* The library is Pently, an audio driver.

EDIT: Yes, .segment. I've been doing too much programming for other platforms lately.
User avatar
rainwarrior
Posts: 8732
Joined: Sun Jan 22, 2012 12:03 pm
Location: Canada
Contact:

Re: Automatically translating ca65 code to ASM6 code

Post by rainwarrior »

A relatively low-tech workaround might be to just produce a binary blob that must reside at a fixed address? You'd only have to provide the blob and a set of entry point definitions instead. This could work with more or less every assembler, though, not just ASM6, which is maybe a bonus.
User avatar
tokumaru
Posts: 12427
Joined: Sat Feb 12, 2005 9:43 pm
Location: Rio de Janeiro - Brazil

Re: Automatically translating ca65 code to ASM6 code

Post by tokumaru »

tepples wrote:As I understand it, ASM6 does not have a counterpart to ca65 .res; all variable allocation is handled with equates.
.DSB and .DSW are the ASM6 equivalents of .RES. To prevent them from emitting data to the output file, you have to enclose them in .ENUM blocks.
In addition, ASM6 does not have a counterpart to ca65 .section; order of code in the output corresponds to order of code in the input.
Do you mean .SEGMENT? Yeah, AFAIK there's no way control the order of things, except for manipulating the order in which they appear in the source code. I personally never found this to be a significant disadvantage... in fact, I kinda prefer this linear philosophy. The only times I ever *needed* to write code out of order in ca65 was to get around the single-pass limitations.
It does appear to have a counterpart to .scope as rept 1; this could be used to translate a .proc.
Huh, using .REPT 1 as a makeshift .SCOPE is an interesting idea!
Is there a way to bridge this feature gap that is less complex than A. actually writing an assembler that fully parses ca65 code and evaluates its expressions and macros, or B. hand-translating each line from ca65 to ASM6 and finding some way to determine that the code produced by the ca65 version remains identical to the code produced by the ASM6 version even after I fix bugs in or add features to the ca65 version?
I honestly can't think of anything that would make this translation any simpler. I liked rainwarrior's idea of simply including a binary blob, but not only it has to be included in a fixed location, the location of all variables it uses need to be set in stone too, which might be undesirable.
User avatar
gauauu
Posts: 779
Joined: Sat Jan 09, 2016 9:21 pm
Location: Central Illinois, USA
Contact:

Re: Automatically translating ca65 code to ASM6 code

Post by gauauu »

rainwarrior wrote:A relatively low-tech workaround might be to just produce a binary blob that must reside at a fixed address? You'd only have to provide the blob and a set of entry point definitions instead. This could work with more or less every assembler, though, not just ASM6, which is maybe a bonus.
The problem with the binary blob is that you can't do the conditional compilation based on the configuration file, which I imagine reduces a lot of the flexibility of the library.
User avatar
tokumaru
Posts: 12427
Joined: Sat Feb 12, 2005 9:43 pm
Location: Rio de Janeiro - Brazil

Re: Automatically translating ca65 code to ASM6 code

Post by tokumaru »

I just thought of a way to simulate segments. I admit it's kinda dumb, but here it goes.

First you need a convenient method to reference the segments. You can use .ENUM to create constants that you can easily move around later if you want to change the order of the segments, without having to manually change any numbers. Something like this:

Code: Select all

;create constants for all the segments
.enum 0
	BANK0 .dsb 1
	BANK1 .dsb 1
	;(...)
	END_OF_SEGMENTS
.ende
Then you can wrap your segmented code in .IF blocks:

Code: Select all

;the following is equivalent to .segment "BANK1"
.if Segment = BANK1

	;stuff to output to segment "BANK1"

.endif ;except you need to close the block, of course

;the following is equivalent to .segment "BANK0"
.if Segment = BANK0

	;stuff to output to segment "BANK1"

.endif ;except you need to close the block, of course
Now you need to create a huge list of includes, containing all your source files:

Code: Select all

.include "source0.asm"
.include "source1.asm"
.include "source2.asm"
.include "source3.asm"
;(...)
Finally, in the main file, you just iterate over all segments and include the huge list of includes for each one:

Code: Select all

Segment = 0
.rept END_OF_SEGMENTS
	.include "includes.asm"
	Segment = Segment + 1
.endr
This is obviously not an exact recreation of the segment functionality, seeing as the code for a segment is completely ignored until it's time to output that segment, so you can't do other tasks not related to output (such as modify symbols) in the order the code is written.
User avatar
rainwarrior
Posts: 8732
Joined: Sun Jan 22, 2012 12:03 pm
Location: Canada
Contact:

Re: Automatically translating ca65 code to ASM6 code

Post by rainwarrior »

gauauu wrote:The problem with the binary blob is that you can't do the conditional compilation based on the configuration file, which I imagine reduces a lot of the flexibility of the library.
That's kind of a question of how many permutations are reasonable, but at least they could be automated.

Though on the other hand, maybe it'd be reasonable to provide CC65 / build script with it and just have them build the binary blob on their end. The problem should be only be that they're using ASM6 for their existing code, so it may be OK for them to just have CC65 make the blob. The address and everything else would remain fully configurable that way.

Technically, CC65 could even output the ASCII files with the entry points, if you want to avoid adding another tool for that.
Post Reply