6502.org Forum  Projects  Code  Documents  Tools  Forum
It is currently Fri Nov 22, 2024 7:14 pm

All times are UTC




Post new topic Reply to topic  [ 16 posts ]  Go to page 1, 2  Next
Author Message
PostPosted: Sun May 24, 2020 12:57 pm 
Offline

Joined: Fri Nov 16, 2018 8:55 pm
Posts: 71
So, I'm building a cartridge header file in 64tass for a project I'm working on, and it's not quite doing what I expect. If do something like this:

Code:
   *=$0000
   (cart header bytes)

   *=$8000
   .addr start            ; Start of execution
   .addr reset            ; <RUN/STOP> + <RESTORE>
   .text "CBM80"            ; Autostart "Magic Number"


Everything past the cartridge header is filled with $00's. Obviously, my desired output is for the assembler to not produce any intervening null bytes. I've tried using the -n flag to suppress this behavior and it's not working. Perhaps I'm using the wrong flag, or there is an assembler directive I've missed in the documentation.

The exact flags I'm using are:

Code:
64tass -a -n -b --m6502 infile.asm -o outfile.bin


I've worked around the problem by building the cartridge header and the main program separately. I then use the oldest Linux/Unix trick in the book: cat header.bin program.bin > program.crt. This works, and that's what my Makefile is doing now, but I feel like I've missed a more appropriate solution and it's bugging me. Suggestions?

FYI, I'm deliberately not using VICE's cartconv program for this purpose, because it's not quite fine-grained enough for what I want. So, for my purposes, building it directly in the assembler is the correct approach.


Top
 Profile  
Reply with quote  
PostPosted: Sun May 24, 2020 1:14 pm 
Offline

Joined: Sat Jun 04, 2016 10:22 pm
Posts: 483
Location: Australia
Is the cartridge header supposed to be at address $0000, as seen by the 6502? Because that's what you're telling the assembler to set up there.
Or have I entirely missed what this header data is actually for?


Top
 Profile  
Reply with quote  
PostPosted: Sun May 24, 2020 1:26 pm 
Offline

Joined: Fri Nov 16, 2018 8:55 pm
Posts: 71
DerTrueForce wrote:
Is the cartridge header supposed to be at address $0000, as seen by the 6502? Because that's what you're telling the assembler to set up there.
Or have I entirely missed what this header data is actually for?


That was a point of confusion for me too, at first. Starting at offset $0000 is correct.

The CPU never sees the header bytes, they're entirely for the benefit of the emulator. Without a header, the emulator will not know how to treat the cartridge hardware itself. Here is a tutorial with examples targeting a different assembler. Note the header bytes start at $0000 and the ROM part, including the "CBM80" auto-start signature, start at $8000 which is what the CPU actually sees.

That tutorial shows what I'm trying to do, I just can't get it to work the way I expect in 64tass.


Top
 Profile  
Reply with quote  
PostPosted: Sun May 24, 2020 1:54 pm 
Offline

Joined: Sat Jun 04, 2016 10:22 pm
Posts: 483
Location: Australia
By the looks of that tutorial, the value of the program counter is entirely irrelevant to the header itself. Those examples look to me like they're using a behaviour of their assemblers that is not standardized.
The most assembler-agnostic method of doing that(while still keeping it within the assembler) is to set the program counter once, to $8000 minus however many bytes the header requires, so that the start of the rom contents starts with the program counter at $8000.
All that said, I think you are probably already doing it in the most correct manner. The cartridge contents and that header data are logically seperate entities, so I think generating them separately and then combining them is probably more correct than doing both in the one source file.


Top
 Profile  
Reply with quote  
PostPosted: Sun May 24, 2020 4:08 pm 
Online
User avatar

Joined: Fri Aug 30, 2002 9:02 pm
Posts: 1748
Location: Sacramento, CA
I believe what you are looking for is the .logical directive.

You source will look something like this:

Code:
   *= $0000
   .text "C64 CARTRIDGE   "
   .byte $00,$00 ;header length
   .byte $00,$40 ;header length
   .word $0001 ;version
   .word $0000 ;crt type
   .byte $00 ;exrom line
   .byte $01 ;game line
   .byte $00,$00,$00,$00,$00,$00 ;unused
   .text "CRT TITLE"
   .fill $0040 - *, $00 ; pad title with $00
   ;chip packets
   .text "CHIP" 
   .byte $00,$00,$20,$10 ;chip length
   .byte $00,$00 ;chip type
   .byte $00,$00 ;bank
   .byte $80,$00 ;address
   .byte $20,$00 ;length

;ROM part - this will be loaded at address $8000 so all label and branch targets need to start at $8000
   .logical $8000
   (begin source)


You may need to tweak this a little, but it should get you where you want to be.

Daryl

_________________
Please visit my website -> https://sbc.rictor.org/


Top
 Profile  
Reply with quote  
PostPosted: Sun May 24, 2020 7:25 pm 
Offline

Joined: Fri Nov 16, 2018 8:55 pm
Posts: 71
8BIT wrote:
I believe what you are looking for is the .logical directive.


Based upon the documentation, that appears to be the case!

8BIT wrote:
Code:
   .text "CRT TITLE"
   .fill $0040 - *, $00 ; pad title with $00



I was fighting with .text format / fill, too. You accidentally solved a second issue I was having with the null padded cart title field. Thanks!


Top
 Profile  
Reply with quote  
PostPosted: Sun May 24, 2020 7:54 pm 
Online
User avatar

Joined: Fri Aug 30, 2002 9:02 pm
Posts: 1748
Location: Sacramento, CA
I'm happy I could help.

Best of luck with your project!

Daryl

_________________
Please visit my website -> https://sbc.rictor.org/


Top
 Profile  
Reply with quote  
PostPosted: Tue May 26, 2020 3:56 pm 
Offline

Joined: Tue Dec 03, 2019 11:39 am
Posts: 9
8BIT wrote:
Code:
   .text "CRT TITLE"
   .fill $0040 - *, $00 ; pad title with $00
That's interesting because I thought I was being innovative with my own assembler. This is my variation on the same directive/code.
Code:
.byte ("CRT TITLE") pad $40; for space padded ..pad $40($20)
That pads after the text, use -$40 to pad before the text. Alternatively for the lazy person who can't count and overruns the text field, "trunc" can be substituted for "pad".


Top
 Profile  
Reply with quote  
PostPosted: Tue May 26, 2020 4:49 pm 
Offline

Joined: Fri Nov 16, 2018 8:55 pm
Posts: 71
beethead wrote:
8BIT wrote:
Code:
   .text "CRT TITLE"
   .fill $0040 - *, $00 ; pad title with $00
That's interesting because I thought I was being innovative with my own assembler. This is my variation on the same directive/code.
Code:
.byte ("CRT TITLE") pad $40; for space padded ..pad $40($20)
That pads after the text, use -$40 to pad before the text. Alternatively for the lazy person who can't count and overruns the text field, "trunc" can be substituted for "pad".


Oh, neat. Hmm... @8BIT, by "my own assembler" do you mean "my own code [in 6502 assembly]" in 64tass or otherwise, or have you written your own assembler proper as well as code for it? If so, which one? I'd like to have a look at it.

Yeah, I got the padding to work just fine. After some testing, it seems the .logical directive has screwed up the way at least some of my labels are computed. I'm sure it's the right approach generally and that I'm just doing something wrong. I'll circle back to it, there are other issues I'm working through with the codebase I'm disassembling and working through.


Top
 Profile  
Reply with quote  
PostPosted: Tue May 26, 2020 6:46 pm 
Online
User avatar

Joined: Fri Aug 30, 2002 9:02 pm
Posts: 1748
Location: Sacramento, CA
load81 wrote:
Oh, neat. Hmm... @8BIT, by "my own assembler" do you mean "my own code [in 6502 assembly]" in 64tass or otherwise, or have you written your own assembler proper as well as code for it? If so, which one? I'd like to have a look at it.

I think you meant this for Beethead.

Quote:
Yeah, I got the padding to work just fine. After some testing, it seems the .logical directive has screwed up the way at least some of my labels are computed. I'm sure it's the right approach generally and that I'm just doing something wrong. I'll circle back to it, there are other issues I'm working through with the codebase I'm disassembling and working through.

My understanding is any label you define will keep that definition. This is good for zero page and system calls. Any label assigned an address by the assembler (from its internal PC), should get assigned the logical address. That way JSR/JMP works within the assembled code. Branches use offsets so they are not affected. Also, if you put data tables in your code, then do not use the *= directive to place your table(s). If you need page aligned tables, then you'll need to figure out a way to do that. 64TASS might have a .page align type directive.

If you need more help, please post some code examples. I do not use 64TASS, but I used to use the original TASS, which is similar.

Daryl

_________________
Please visit my website -> https://sbc.rictor.org/


Top
 Profile  
Reply with quote  
PostPosted: Wed May 27, 2020 2:22 am 
Offline

Joined: Fri Nov 16, 2018 8:55 pm
Posts: 71
Quote:
I think you meant this for Beethead.


Yep, I did. I was tired. My bad.

Here is what I've come up with and my trial and error process that got me there...

I dispensed with *=$0000 and switched to .logical instead. At first, it didn't work. The 64tass documentation shows the two directives used together. That didn't work. I tried it in a few places, right after the .logical keyword for starters, then at the end of my code. Nothing worked. The resulting file was larger than expected, but not by a ton. Even a simple jsr [label to absolute address] wouldn't work.

This is what I tried was:

Code:
*=$0000
(cartridge header)
(chip packet)
.logical $8000
.word start       ; $8000
.word nmi_reset   ; $8074
.text "CBM80"     ; auto-start signature
(main code)
.here


Eventually, I hit on abandoning *=$8000 entirely, and just went with .logical $0000 and .logical $8000, that did work as long as I placed the .here statements at the end of the segments.

The idea of named sections of code appealed to me. I'm reverse engineering a game after all. I have only a rough idea where the code ends and where sprite and bitmap data begin. When I figure out the dividing line, it will be nice to be able to mark it as data; if only as an aid to the reader.

What I ended up with, after some trial and error was...

Code:
cart_header=$0000
.dsection cart_header
;.cerror * > $50, "Header too large."

main=$8000
.desection main

.section cart_header
.logical cart_header
(cartridge header)
(chip packet)
.here

.section main
.logical main
.word start
.word nmi_reset
.addr start      ;$8009
.addr nmi_reset  ;$8074
.text "CBM80"    ;auto-start signature

(program code and data)
.here


Maybe that's redundant, or I am otherwise "doing it wrong." I'm open to criticism. Eventually, I want to work out a generic macro to handle cartridge headers and chip packets. I'll add a section for data to clearly demark it from the main program when I get that far.


Top
 Profile  
Reply with quote  
PostPosted: Wed May 27, 2020 12:34 pm 
Offline

Joined: Fri Nov 16, 2018 8:55 pm
Posts: 71
Now I more fully understand why I ran into the issue I was hitting, from Section 4.1 of the 64tass manual:
Quote:
Two counters are used while assembling. The compile offset is where the data and code ends up in memory (or in image file). The program counter is what labels get set to and what the special star label refers to

I was failing to fully appreciate the distinction between .logical and the *= assembler directives.


Top
 Profile  
Reply with quote  
PostPosted: Wed May 27, 2020 1:18 pm 
Offline
User avatar

Joined: Tue Mar 02, 2004 8:55 am
Posts: 996
Location: Berkshire, UK
If the output is a binary file which consists of a 80 byte cartridge header followed by the ROM image then you could start with the origin set to $8000-$50 (*=$7FB0).

_________________
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: Wed May 27, 2020 10:54 pm 
Online
User avatar

Joined: Fri Aug 30, 2002 9:02 pm
Posts: 1748
Location: Sacramento, CA
BitWise wrote:
If the output is a binary file which consists of a 80 byte cartridge header followed by the ROM image then you could start with the origin set to $8000-$50 (*=$7FB0).


That would certainly follow the KISS mantra. Nice solution!

Daryl

_________________
Please visit my website -> https://sbc.rictor.org/


Top
 Profile  
Reply with quote  
PostPosted: Fri May 29, 2020 11:58 pm 
Offline

Joined: Fri Nov 16, 2018 8:55 pm
Posts: 71
I worked out a series of generic macros for handling cartridge headers and chip packets. I'm sure both of them could stand improvement, but I have a sold working first draft. I have some lookup tables and error flags, but this is the "meat" of the macro.

Code:
cart_header   .macro title="", hardware="generic", exrom=false, game=false
            .include "encodings.s"               ; defines ASCII

            .enc "ascii"
            .text "C64 CARTRIDGE   "             ; Magic value
            .enc "none"

            .word >< $0000                        ; Cartridge header length, >< not needed but it matches the rest.
            .word >< $0040                        ; ""
            .word CRT_FORMAT_VER[1.0]             ; Version of the .crt file format.
            .word CARTRIDGE_HARDWARE[\hardware]   ; cartridge hardware
            .byte \exrom                          ; EXROM line
            .byte \game                           ; GAME line
            .fill 6,0                             ; "reserved for future use"

            .enc "none"
            .text \title
         
            .fill $0040 - *, $00               ; Pad title with null-bytes.
         .endm


Now, I just invoke cart_header in and pass parameters and the cartridge header gets built exactly the way I want it to. I'm sure there are about a dozen ways this macro could be improved. The only "gotcha" is, when I turn -Wall on (enable all warnings) I get the following warning...

Quote:
note: original location in an expanded macro was herecan't get integer value of bool 'false' -Wstrict-bool


This is strange, because boolean values are just aliases for 1/0 true and false. Even after having read the -Wstrict-bool flag details, I'm not sure why this happening. Can someone comment on this?


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

All times are UTC


Who is online

Users browsing this forum: No registered users and 24 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: