It is currently Mon Nov 20, 2017 5:02 am

All times are UTC - 7 hours



Forum rules


Related:



Post new topic Reply to topic  [ 43 posts ]  Go to page Previous  1, 2, 3
Author Message
PostPosted: Sat May 27, 2017 8:26 am 
Offline
User avatar

Joined: Tue Apr 05, 2016 5:25 pm
Posts: 145
Alright, I have a couple questions currently:

- How do I force 24-bit addressing? I need this for the SPC upload routines in order to support uploading data from different data banks while still having access to the upload src/dest/size variables.
- How is the checksum and complement computed? This page gives a basic description but since they're part of the file being checksummed, wouldn't that mess things up? I'd think at least the complement might cause the result of the checksum to differ based on its initial value?

_________________
SNES NTSC 2/1/3 1CHIP | serial number UN318588627


Top
 Profile  
 
PostPosted: Sat May 27, 2017 9:26 am 
Online
User avatar

Joined: Mon Jan 23, 2006 7:47 am
Posts: 75
Checksum + inverted checksum = 0

Just set both fields to zero, checksum the file, and set the fields.


Top
 Profile  
 
PostPosted: Sat May 27, 2017 1:30 pm 
Offline

Joined: Sun Sep 19, 2004 11:12 pm
Posts: 19233
Location: NE Indiana, USA (NTSC)
HihiDanni wrote:
- How do I force 24-bit addressing? I need this for the SPC upload routines in order to support uploading data from different data banks while still having access to the upload src/dest/size variables.

In ca65, use f:$2140. In any assembler, use $212140.

Quote:
- How is the checksum and complement computed? This page gives a basic description but since they're part of the file being checksummed, wouldn't that mess things up? I'd think at least the complement might cause the result of the checksum to differ based on its initial value?

The third byte of the checksum is always $FF minus the first byte, and The fourth byte is always $FF minus the second byte. Thus the four bytes will by definition always add to $1FE, as if the four bytes were 00 00 FF FF. So overwrite the checksum with those four bytes before calculating it.


Top
 Profile  
 
PostPosted: Sun May 28, 2017 12:44 pm 
Offline
User avatar

Joined: Tue Apr 05, 2016 5:25 pm
Posts: 145
Okay, I have successfully ported my engine over to ca65! Thanks for the help! Already this has several advantages:

- My project now has a proper structure with each source file being its own module, with all the modules linked together after assembly.
- I no longer need to maintain a spreadsheet of the WRAM layout to make sure I'm not overwriting variables from other modules
- While porting the engine to the new assembler I ended up fixing a few bugs that only cropped up due to the altered memory layout, and made the game actually run slightly faster in the process!
- I understand the memory layout as seen by the linker which makes it easier to move things around the different memory regions
- The size of the game object list can be easily changed at assembly time to be something other than 128 to adjust the tradeoff between max objects and memory usage/overhead.

However, I do have a couple small issues which I would like some advice on:

- When I ported the macros for transferring data to VRAM, etc., I made it so immediate addressing is no longer implicit (or required). However, now you have to write the macros like this:

Code:
Macro_LoadVRAM #.loword(Tileset), #<.bank(Tileset), #$0000, #$8000

Now I don't mind the need to specify # quite so much (although it's technically error-prone - if you forget the # you'll end up with different transfer addresses than intended). However, the use of .loword() and <.bank() is really ugly. Any suggestions on best practices to use here to make the syntax less painful to deal with?

- Additionally, it seems like you need to import/export each symbol or label individually, which wouldn't be so bad if I didn't also want to have things like sprite definition files with lots of labels that I really, really don't want to have to import/export one by one. That would be a nightmare. Surely there's a better way to deal with this, perhaps by grouping them so just a single import/export is needed?

_________________
SNES NTSC 2/1/3 1CHIP | serial number UN318588627


Top
 Profile  
 
PostPosted: Sun May 28, 2017 12:52 pm 
Offline
User avatar

Joined: Sat Jan 03, 2015 5:58 pm
Posts: 368
Location: ...
Why not just pass Tileset to the macro and then inside it use .bank and .loword?

Also, .global works wonders. Cuts imports and exports in half.


Top
 Profile  
 
PostPosted: Sun May 28, 2017 12:58 pm 
Offline
User avatar

Joined: Tue Apr 05, 2016 5:25 pm
Posts: 145
Passing Tileset to the macro was the previous way of doing things. Perhaps I should make two versions of macros, make the first one always use immediates, and the second one called Indirect.

But now that I think about it, all the macros are doing are setting a few register values before jumping to the subroutine that does the DMA transfer. So I may as well just make the macros immediate-only.

I'm hesitant to use .global, and it doesn't really address my issue. Mostly I don't want to have to list each label twice in my file (once for the definition and once again for the export).

_________________
SNES NTSC 2/1/3 1CHIP | serial number UN318588627


Top
 Profile  
 
PostPosted: Mon May 29, 2017 7:31 am 
Offline
User avatar

Joined: Mon Jan 03, 2005 10:36 am
Posts: 2981
Location: Tampere, Finland
HihiDanni wrote:
However, the use of .loword() and <.bank() is really ugly. Any suggestions on best practices to use here to make the syntax less painful to deal with?

You can handle it at the macro side (where appropriate, as discussed), or .define your own macro aliases to simplify the syntax. For example:
Code:
.define lw(v) .loword(v)
.define bank(v) .lobyte(.bank(v))
Macro_LoadVRAM #lw Tileset, #bank Tileset, #$0000, #$8000

(YMMV whether this is actually any better.)

HihiDanni wrote:
Passing Tileset to the macro was the previous way of doing things. Perhaps I should make two versions of macros, make the first one always use immediates, and the second one called Indirect.

But now that I think about it, all the macros are doing are setting a few register values before jumping to the subroutine that does the DMA transfer. So I may as well just make the macros immediate-only.

Quote:
Mostly I don't want to have to list each label twice in my file (once for the definition and once again for the export).

You can use export foo := * instead of .export foo + foo:. (Or, you can make your own macro to simplify the export.)

With .global, you would have .global foo in your module header (e.g., module.inc), and the definition (e.g., module.s) would simply have foo:.

_________________
Download STREEMERZ for NES from fauxgame.com! — Some other stuff I've done: kkfos.aspekt.fi


Top
 Profile  
 
PostPosted: Mon May 29, 2017 8:06 am 
Offline
User avatar

Joined: Tue Apr 05, 2016 5:25 pm
Posts: 145
thefox wrote:
Code:
.define lw(v) .loword(v)
.define bank(v) .lobyte(.bank(v))
Macro_LoadVRAM #lw Tileset, #bank Tileset, #$0000, #$8000

(YMMV whether this is actually any better.)

It's surprisingly elegant!

Quote:
You can use export foo := * instead of .export foo + foo:. (Or, you can make your own macro to simplify the export.)

With .global, you would have .global foo in your module header (e.g., module.inc), and the definition (e.g., module.s) would simply have foo:.

What's the definition of foo here? Does foo become a namespace? In that case, how is the import done, and what's the syntax for referencing the labels from the import?

_________________
SNES NTSC 2/1/3 1CHIP | serial number UN318588627


Top
 Profile  
 
PostPosted: Mon May 29, 2017 9:08 am 
Offline
User avatar

Joined: Sat Jan 03, 2015 5:58 pm
Posts: 368
Location: ...
foo is just a label, not a namespace.

If you had foo.s:
Code:
.include "foo.inc"
.code
foo:


foo.inc:
Code:
.global foo


And main.s:
Code:
.include "foo.inc"
.code
main: jmp foo


This would work without error. (.code is short for .segment "CODE").

Edit, forgot to mention that you could do what thefox said and change foo: to .export foo := * and .global foo to .import foo and take out the include for foo.s and that would also work. Not sure why you'd want to do that.


Top
 Profile  
 
PostPosted: Mon May 29, 2017 9:29 am 
Offline
User avatar

Joined: Tue Apr 05, 2016 5:25 pm
Posts: 145
The use of ".export foo := *" implies there is some kind of wildcard here, hence I assumed it to be some kind of namespace. Which is really what I want - the ability to mass export/import labels for definition files.

At this rate the best thing I can think of is to put ROM data definitions inside an include file and somehow find a way to ensure that it's only written to ROM once even if included from multiple locations.

Edit: Or better yet, a more concrete example of using ".export foo := *" with a large number of labels. I'd prefer all these labels being declared once if possible.

_________________
SNES NTSC 2/1/3 1CHIP | serial number UN318588627


Top
 Profile  
 
PostPosted: Mon May 29, 2017 9:37 am 
Offline
User avatar

Joined: Sun Jan 22, 2012 12:03 pm
Posts: 5822
Location: Canada
.scope foo creates a namespace, but not a label.
.proc foo creates both at once, a label that also encloses a namespace.
.global foo import and/or exports a symbol, it doesn't create foo by itself.
.export foo only exports a symbol, its definition will be elsewhere.
.export foo := * apparently exports and defines foo in one line (compound of assignment and export into one statement).
* is not a wildcard, it is the current PC location in the code.

Just to clarify that last one, * works like other labels, it just happens to change its value on every line:
.export foo := bar exports and defines foo as equal to another label.
.export foo = 25 exports and defines foo as the number 25.

HihiDanni wrote:
Which is really what I want - the ability to mass export/import labels for definition files.

Each label/symbol you want to import or export must be explicitly mentioned in an .import/.export/.global statement. You can't import an entire namespace in one step, by itself...

However, if you want to create groups of these, you can put a collection of .global statements in a separate "header" file and .include that header in files that need them. The include allows you to hide a bunch of code in another file via in a single line, at least?


Top
 Profile  
 
PostPosted: Mon May 29, 2017 9:55 am 
Offline

Joined: Sun Sep 19, 2004 11:12 pm
Posts: 19233
Location: NE Indiana, USA (NTSC)
Speaking of * and namespaces, I filed feature request #346 for prefix exports and imports.


Top
 Profile  
 
PostPosted: Mon May 29, 2017 9:58 am 
Offline
User avatar

Joined: Tue Apr 05, 2016 5:25 pm
Posts: 145
Thanks for the clarification. Thinking about this some more, I might wrap some of this stuff into a macro which would be both human- and tool-friendly.

_________________
SNES NTSC 2/1/3 1CHIP | serial number UN318588627


Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 43 posts ]  Go to page Previous  1, 2, 3

All times are UTC - 7 hours


Who is online

Users browsing this forum: No registered users and 9 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:  
Powered by phpBB® Forum Software © phpBB Group