It is currently Mon Nov 20, 2017 12:06 pm

All times are UTC - 7 hours





Post new topic Reply to topic  [ 32 posts ]  Go to page 1, 2, 3  Next
Author Message
 Post subject: ca65 goodies
PostPosted: Sat Mar 22, 2014 2:42 pm 
Offline
User avatar

Joined: Mon Jan 03, 2005 10:36 am
Posts: 2981
Location: Tampere, Finland
Well, this is a bit random, but I came up with this ca65 macro for converting a nibble (number $0..$F) to its corresponding ASCII character code, when said nibble isn't a compile time constant, and thought I would share it. The main use case would be some sort of debugging. One could, for example, generate a textual log file similar to using .out, but without the limitations of .out.
Code:
.macro nibbleToHexAscii nibble
    .local x0, x1, x2, x3
    .local y0, y1, y2, y3, y4
   
    x3 = ( nibble >> 3 ) & 1
    x2 = ( nibble >> 2 ) & 1
    x1 = ( nibble >> 1 ) & 1
    x0 = ( nibble >> 0 ) & 1
   
    y4 = ( x3 & x1 ) | ( x3 & x2 )
    y3 = ( x3 & ~x2 & ~x1 )
    y2 = ( ~x3 & x2 ) | ( x2 & x0 ) | ( x2 & x1 )
    y1 = ( ~x3 & x1 ) | ( x1 & x0 ) | ( x3 & x2 & ~x1 & ~x0 )
    y0 = ( ~x3 & x0 ) | ( ~x2 & ~x1 & x0 ) | ( x3 & x1 & ~x0 ) | ( x3 & x2 & ~x0 )

    .byte <( ( y4 << 4 | y3 << 3 | y2 << 2 | y1 << 1 | y0 << 0 ) + '0' )
.endmacro

This macro can then be used to output a 16-bit number as a hex ASCII string:
Code:
.macro wordToHexAscii addr
    .repeat 4, i
        nibbleToHexAscii { (addr >> ( 4 * ( 3 - i ) ) ) & $F }
    .endrepeat
.endmacro

Usage example:
Code:
.byte "Current address is: "
wordToHexAscii *

I'd love to hear about other ca65 tips, tricks and workarounds like this.

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


Top
 Profile  
 
 Post subject: Re: ca65 goodies
PostPosted: Sat Mar 22, 2014 3:43 pm 
Offline

Joined: Sun Sep 19, 2004 11:12 pm
Posts: 19236
Location: NE Indiana, USA (NTSC)
Here's the number of days since a project started, and the percentage full:
Code:
;these variables are filled by the linker
.import __RODATA_LOAD__, __RODATA_SIZE__, __CODE_LOAD__, __CODE_SIZE__

ROMSIZE = __CODE_SIZE__ + __RODATA_SIZE__ + 6
ROMPCT = (1000 * ROMSIZE + 16384) / 32768
; started this project on Sun 2013-08-11
BUILDDAY = (.TIME / 86400) - 15928

title_txt:
  .byt .sprintf("Day %d: ROM ", BUILDDAY)
  .byt '0'|<(ROMPCT / 100 .MOD 10)
  .byt '0'|<(ROMPCT / 10 .MOD 10)
  .byt '.','0'|<(ROMPCT .MOD 10),"% full",LF,LF


Are you sure this still doesn't work?
Code:
.macro nibbleToHexAscii nibble
  .byte '0' + ('A'-'9'-1)*(nibble > 9) + nibble
.endmacro


Last edited by tepples on Sat Mar 22, 2014 5:10 pm, edited 1 time in total.
Thinko. My bad.


Top
 Profile  
 
 Post subject: Re: ca65 goodies
PostPosted: Sat Mar 22, 2014 4:51 pm 
Offline
User avatar

Joined: Mon Jan 03, 2005 10:36 am
Posts: 2981
Location: Tampere, Finland
tepples wrote:
Are you sure this doesn't work?
Code:
.macro nibbleToHexAscii nibble
  .byte '0' + ('A'-'9'-1)*(nibble > 9)
.endmacro

Already I'm glad I started this thread. :)

The thing you pasted doesn't work (didn't check why), but this one should. Same concept anyways, didn't occur to me that the boolean expressions evaluate to integers.
Code:
.macro nibbleToHexAscii nibble
  .byte (nibble + '0')*(nibble < 10) + (nibble - 10 + 'A')*(nibble >= 10)
.endmacro

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


Top
 Profile  
 
 Post subject: Re: ca65 goodies
PostPosted: Sat Mar 22, 2014 5:01 pm 
Offline
User avatar

Joined: Mon Feb 07, 2011 12:46 pm
Posts: 932
tepples wrote:
Are you sure this doesn't work?
Code:
.macro nibbleToHexAscii nibble
  .byte '0' + ('A'-'9'-1)*(nibble > 9)
.endmacro
I wouldn't expect that to work; I think you would need also + nibble isn't it?

_________________
.


Top
 Profile  
 
 Post subject: Re: ca65 goodies
PostPosted: Sat Mar 22, 2014 5:09 pm 
Offline

Joined: Sun Sep 19, 2004 11:12 pm
Posts: 19236
Location: NE Indiana, USA (NTSC)
Oops, my bad. It's hard to test certain things without creating a new project.


Top
 Profile  
 
 Post subject: Re: ca65 goodies
PostPosted: Sun Mar 23, 2014 1:07 am 
Offline
User avatar

Joined: Sun Jan 02, 2011 11:50 am
Posts: 522
thefox wrote:
didn't occur to me that the boolean expressions evaluate to integers.


Yes. The assembler evaluates true to 1 and false to 0. Non zero values are true.

Code:
 flag .set (.xmatch(.mid(0,1, {express}) , C)) * 1 + (.xmatch(.mid(0,1, {express}) , Z)) * 2 + (.xmatch(.mid(0,1,{express}) , N)) * 3 + (.xmatch(.mid(0,1,{express}) , V)) * 4 + (.xmatch(.mid(0,1,{express}) , G)) * 5


Without the context it might not be clear, but some members are familiar with my high-level macro code - that's a line from the flag evaluation: I abuse the boolean values to return a value from 1 to 5. A value of zero is an error.

Edit:Now you got me thinking though.. I might be able to simulate an array with .ident() and .sprintf(), but too tired at the moment.


Top
 Profile  
 
 Post subject: Re: ca65 goodies
PostPosted: Sun Mar 23, 2014 5:08 am 
Offline
User avatar

Joined: Mon Jan 03, 2005 10:36 am
Posts: 2981
Location: Tampere, Finland
tepples wrote:
Oops, my bad. It's hard to test certain things without creating a new project.

I usually test small things like this by making a new file with whatever I want to test...
Code:
.byte "test"

...and then: cl65 -t none foo.s

The default configuration (not sure which one it uses, actually) tends to be fine for this type of platform-independent tests.

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


Top
 Profile  
 
 Post subject: Re: ca65 goodies
PostPosted: Sun Mar 23, 2014 7:27 am 
Offline

Joined: Sun Sep 19, 2004 11:12 pm
Posts: 19236
Location: NE Indiana, USA (NTSC)
Then I must have an installation problem:
Code:
$ cl65 -t none n2ha.s
ld65: Error: Cannot find config file `none.cfg'


Top
 Profile  
 
 Post subject: Re: ca65 goodies
PostPosted: Sun Mar 23, 2014 10:40 pm 
Offline
User avatar

Joined: Mon Feb 07, 2011 12:46 pm
Posts: 932
tepples wrote:
Oops, my bad. It's hard to test certain things without creating a new project.
That is one reason why some people don't use ca65. (I don't use ca65 either, but I can understand some of things you write in here, some of which might help people using any system, I suppose.)

Movax12 wrote:
Without the context it might not be clear, but some members are familiar with my high-level macro code - that's a line from the flag evaluation: I abuse the boolean values to return a value from 1 to 5. A value of zero is an error.
O, I "abuse" boolean values like that a lot...

_________________
.


Top
 Profile  
 
 Post subject: Re: ca65 goodies
PostPosted: Sun Mar 23, 2014 11:42 pm 
Offline
User avatar

Joined: Sun Jan 02, 2011 11:50 am
Posts: 522
tepples wrote:
Then I must have an installation problem:
Code:
$ cl65 -t none n2ha.s
ld65: Error: Cannot find config file `none.cfg'


Guessing a bit, but if you specify a -t none you should also have a -C config.cfg. If cl65 is going to be assembling, it doesn't matter, but if it is going to be linking, you have to use -C


Top
 Profile  
 
 Post subject: Re: ca65 goodies
PostPosted: Mon Mar 24, 2014 4:06 am 
Offline
User avatar

Joined: Mon Jan 03, 2005 10:36 am
Posts: 2981
Location: Tampere, Finland
Movax12 wrote:
Guessing a bit, but if you specify a -t none you should also have a -C config.cfg. If cl65 is going to be assembling, it doesn't matter, but if it is going to be linking, you have to use -C

Not sure why it works here without -C, then. I can't easily check what configuration it defaults to, either, but it doesn't seem to be the C64 config (which is otherwise the default).

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


Top
 Profile  
 
 Post subject: Re: ca65 goodies
PostPosted: Mon Mar 24, 2014 7:01 am 
Offline
Formerly ~J-@D!~
User avatar

Joined: Sun Mar 12, 2006 12:36 am
Posts: 445
Location: Rive nord de Montréal
zzo38 wrote:
tepples wrote:
Oops, my bad. It's hard to test certain things without creating a new project.
That is one reason why some people don't use ca65. (I don't use ca65 either, but I can understand some of things you write in here, some of which might help people using any system, I suppose.)

I don't know why tepples talks about creating a project: there's no notion of "project" with cl65, and if he's talking about NESICIDE projects, it's unnecessary to use it to test those macros, as the shell is sufficient and the simplest way to test simple things like the macros of this thread.

Besides, an important information for troubleshooting is lacking: version information of cl65.

Here's my full test session:
Code:
$ cl65 --version
cl65 V2.13.9 - (C) Copyright 1998-2011 Ullrich von Bassewitz
cl65: No input files
$ cat foo.s
cat: foo.s: No such file or directory
$ touch foo.s
$ cl65 -t none foo.s
$ xxd foo
$ echo '.byte $42' > foo.s
$ cl65 -t none foo.s
$ xxd foo
0000000: 42                                       B
$ cat thefox.s
.macro nibbleToHexAscii nibble
    .local x0, x1, x2, x3
    .local y0, y1, y2, y3, y4

    x3 = ( nibble >> 3 ) & 1
    x2 = ( nibble >> 2 ) & 1
    x1 = ( nibble >> 1 ) & 1
    x0 = ( nibble >> 0 ) & 1

    y4 = ( x3 & x1 ) | ( x3 & x2 )
    y3 = ( x3 & ~x2 & ~x1 )
    y2 = ( ~x3 & x2 ) | ( x2 & x0 ) | ( x2 & x1 )
    y1 = ( ~x3 & x1 ) | ( x1 & x0 ) | ( x3 & x2 & ~x1 & ~x0 )
    y0 = ( ~x3 & x0 ) | ( ~x2 & ~x1 & x0 ) | ( x3 & x1 & ~x0 ) | ( x3 & x2 & ~x0 )

    .byte <( ( y4 << 4 | y3 << 3 | y2 << 2 | y1 << 1 | y0 << 0 ) + '0' )
.endmacro

.macro wordToHexAscii addr
    .repeat 4, i
        nibbleToHexAscii { (addr >> ( 4 * ( 3 - i ) ) ) & $F }
    .endrepeat
.endmacro

.byte "Current address is: "
wordToHexAscii *
$ cl65 -t none thefox.s
$ xxd thefox
0000000: 4375 7272 656e 7420 6164 6472 6573 7320  Current address
0000010: 6973 3a20 3032 3137                      is: 0217
$ cl65 -t none --start-addr 0x8000 thefox.s
$ xxd thefox
0000000: 4375 7272 656e 7420 6164 6472 6573 7320  Current address
0000010: 6973 3a20 3830 3137                      is: 8017

tl;dr -t none works for me too without giving a config file. Mind that the default start address is $200, that's why the first example gives 0217.

I use the latest available version of the debian repo available here. Note that the latest version available in the github repo is ~2.14 at the time of writing.

Nifty macro btw.


Top
 Profile  
 
 Post subject: Re: ca65 goodies
PostPosted: Mon Mar 24, 2014 7:57 am 
Offline
User avatar

Joined: Mon Jan 03, 2005 10:36 am
Posts: 2981
Location: Tampere, Finland
Jarhmander wrote:
Besides, an important information for troubleshooting is lacking: version information of cl65.

Unfortunately there are a lot of "snapshot builds" of cc65 out in the wild with the same version numbers and nothing to distinguish each other. It looks like the recent snapshot versions do include the first 7 characters of the Git revision hash, though, which is good.

It also looks like some older versions included the SVN revision as well, but only for the C compiler (cc65):
Code:
C:\Users\f>cc65 --version
cc65 V2.13.9
SVN version: 5963

C:\Users\f>ld65 --version
ld65 V2.13.9 - (C) Copyright 1998-2009, Ullrich von Bassewitz
ld65.exe: Error: No object files to link

C:\Users\f>ca65 --version
ca65 V2.13.9 - (C) Copyright 1998-2011 Ullrich von Bassewitz
ca65.exe: No input files

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


Top
 Profile  
 
 Post subject: Re: ca65 goodies
PostPosted: Mon Mar 24, 2014 8:09 am 
Offline

Joined: Sun Sep 19, 2004 11:12 pm
Posts: 19236
Location: NE Indiana, USA (NTSC)
Jarhmander wrote:
there's no notion of "project" with cl65

I used "project" to refer to a folder containing at least one source code file and at least one linker configuration file. My copy of cl65 2.14.0 cannot link with -t none.

thefox wrote:
Unfortunately there are a lot of "snapshot builds" of cc65 out in the wild with the same version numbers and nothing to distinguish each other.

That's why I made the macro: so I could make an automatic tool to distinguish builds of my own projects by their build date.


Top
 Profile  
 
 Post subject: Re: ca65 goodies
PostPosted: Thu Mar 27, 2014 9:54 am 
Offline
User avatar

Joined: Mon Jan 03, 2005 10:36 am
Posts: 2981
Location: Tampere, Finland
Here's a little something.

I made some macros to make parameter passing just a little bit easier to manage. I call it xparam. I used this quite a lot in STREEMERZ.

Here's how you declare a function (in a header file):
Code:
; Function declaration.
xdecl testFunc
    ; Function parameters.
    foo     .byte
    bar     .word
    ; Parameters/locals can be structs too (testStruct is declared elsewhere)
    xxx     .tag testStruct
   
    ; Local variables of the function.
    xlocals
        xyzzy   .dword
        dog     .byte
    endxlocals
endxdecl

Function parameters and local variables can be accessed in the function:
Code:
xproc testFunc
    lda param foo
    sta local dog   
    rts
endxproc

Here's how you would call an xparam function:
Code:
ldx #111
xinvoke testFunc, foo: x, bar: #$5566, xxx: structInMemory

Inputs can be registers, immediate values or memory addresses. Everything is stored on the zero page. See README.txt in ZIP for caveats/more info. :)

Also note that build.cmd in the ZIP file requires that the ZEROPAGE segment is at least 32 bytes big (it uses the "none" configuration, which by default for some strange reason only has $1F bytes of zero page). To fix it, modify none.cfg in your ca65 installation directory.

Here's a commented disassembly of the binary produced by the files in the ZIP:
Code:
        .setcpu "6502"

L0226           := $0226
L024E           := $024E
        ldx     #$6F
       
        ; testFunc invocation (in test.s)
        ; x is directly stored at $00 (foo)
        stx     $00
        ; $5566 is loaded at $01 (bar)
        lda     #$66
        sta     $01
        lda     #$55
        sta     $02
        ; The struct (3 bytes) is loaded from memory
        lda     $0223
        sta     $03
        lda     $0224
        sta     $04
        lda     $0225
        sta     $05
        ; The actual function call to testFunc.
        jsr     L0226
       
        ; "xparam" macro demonstrations (to access parameter "bar").
        lda     $01
        lda     $02
        .byte   111 ; byteInMemory
        .byte   123 ; structInMemory
        .word   $DEA
       
        ; testFunc (test-module.s):
        lda     $00
        lda     $01
        lda     $02
        lda     $03
        lda     $04
        lda     $05
        ; testFunc local variable accesses:
        lda     #$7B
        sta     $10
        sta     $11
        sta     $12
        sta     $13
        sta     $14
        ; testFunc invokes nestedFunc:
        lda     #$7B
        sta     $06
        lda     #$67
        sta     $07
        lda     #$45
        sta     $08
        jsr     L024E
        rts

        ; nestedFunc (nested-module.s):
        lda     $06
        lda     $07
        rts


Attachments:
xparam-1.zip [4.97 KiB]
Downloaded 109 times

_________________
Download STREEMERZ for NES from fauxgame.com! — Some other stuff I've done: kkfos.aspekt.fi
Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 32 posts ]  Go to page 1, 2, 3  Next

All times are UTC - 7 hours


Who is online

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