Page 1 of 1

XA: * manipulations

Posted: Fri Apr 14, 2017 6:35 pm
by christian
I'm trying to translate some macros from CA65 to XA.

One of them takes a string as parameter and puts the length of this string followed by the string:

Code: Select all

pstring "TEST"
is expanded:

Code: Select all

.byte 4,$54,$45,$53,$54
To do so, I write this XA macro:

Code: Select all

#define pstring(s) -_start=* : .byte 0,s : -_end=* : -_len=_end - _start -1 : *=_end

pstring("TEST")
But the object file is:

Code: Select all

00000000  00 54 45 53 54 04                                 |.TEST.|
With the length after the string...

Then, I'm writing the code below to trace the '*' pointer

Code: Select all

	* = $0400
#print *

_table_start:
	.byte $00,$00,$33,$44,$55

	; We are at $0405 (1029)
_table_end:
#print *

	; Back to start of program
	* = $400
_back:
#print *
	.word $2211
	; Now, we should have
	; 0400 11 22 33 44 55

	; * should be $0402 (1026)
#print *
_table2:

	; Forward to $0405 (1029)
	* = _table_end
#print *

	.byte $66,$77
	; Now, we should have
	; 0400 11 22 33 44 55 66 77

	; * should be $0407 (1031)
_end:
#print *

	; Should be
	; 0407 ad 02 04

	lda _table2
The xa -v -l out.l test2.s output is:

Code: Select all

Cross-Assembler 65xx V2.2.5 (No date available) 
(c) 1989-98 by A.Fachat
65816 opcodes and modes coded by Jolse Maginnis
Oric C adaptation and debugging by Mickael Pointier
Clean Linux port by Jean-Yves Lamoureux
Fri Apr 14 19:05:55 2017
xAss65: Pass 1: test2.s
*=*=1024
*=*=1029
*=*=1024
*=*=1026
*=*=1029
*=*=1031
xAss65: Pass 2:
Statistics:
        5 of     5000 label used
        0 of    40000 byte label-memory used
        0 of    10000 PP-defs used
        0 of  1000000 byte PP-memory used
      225 of   400000 byte buffer memory used
        0 blocks used
        0 seconds used
The '*' pointer's values are correct and the labels values are correct too:

Code: Select all

0400 _table_start
0405 _table_end
0400 _back
0402 _table2
0407 _end
So everything seems ok, but the object file is:

Code: Select all

00000000  00 00 33 44 55 11 22 66  77 ad 02 04              |..3DU."fw...|
Again, the 11 22 is after the 55.

Note the lda _table2 is correctly assembled as ad 02 04

So the value of the '*' is following all affectations, same for all labels, but the bytes are not at the right place.
Since I set '*' only to already used addresses, I thought I can do that.

Is there a way to write this kind of macro?

Re: XA: * manipulations

Posted: Fri Apr 14, 2017 10:59 pm
by iss
This definition:

Code: Select all

* = $400
#define pstring(s) .byte _end-_start : _start=* : .byte s : _end=*
pstring("TEST")
is assembled as:

Code: Select all

0x00000000: 04 54 45 53 54 -> .TEST
Is this what you are looking for?

Re: XA: * manipulations

Posted: Sat Apr 15, 2017 10:29 am
by Dbug
It's probably possible to use .( and .) in the macro to avoid the label redefinition error if pstring(s) is called multiple time :)

On a side note, while looking at the history of Defence Force today I discovered that Twilighte had used the wiki to document some issues he had in XA.
I guess I should check if they still happen, and if yes add them to the issue tracker: http://wiki.defence-force.org/doku.php? ... :osdk:main

Re: XA: * manipulations

Posted: Sat Apr 15, 2017 11:18 am
by iss
As described in XA man page:
To explicitly declare redefinition of a label, place a - (dash) before it
And this code is working for me:

Code: Select all

.text
* = $400
#define pstring(s)  -_start=* : .byte _len,s : -_end=* : -_len=_end - _start - 1
pstring("TEST1")
pstring("TEST2")
The result is:

Code: Select all

0x00000000: 05 54 45 53 54 31 05 54 45 53 54 32 ->  .TEST1.TEST2
@christian: I think there is no way to force XA to go back and to "patch" the zero value in '.byte 0,s' with the calculated length value. If I correctly understand your idea... ;)

Re: XA: * manipulations

Posted: Sat Apr 15, 2017 5:40 pm
by christian
@iss: yes, it's the idea

I've already tried something like your macro but it's not really working:

Code: Select all

#define pstring(s) -_start=* : .byte _len,s : -_end=* : -_len=_end - _start -1

pstring("TEST")
pstring("TEST2")
pstring("TEST33")
The result is

Code: Select all

----------\/-------------\/-----------------\/
00000000  06 54 45 53 54 04 54 45  53 54 32 05 54 45 53 54  |.TEST.TEST2.TEST|
00000010  33 33                                             |33|
Note the first byte, it's 06 but should be 04, the 6th is 04 but should be 05 and the 12th is 05 but should be 06

Re: XA: * manipulations

Posted: Sat Apr 15, 2017 5:54 pm
by christian
@Dbug: Yes it works :D

Code: Select all

#define pstring(s) .( : -_start=* : .byte _len,s : len=* - _start -1 : .)

pstring("TEST")
pstring("TEST2")
pstring("TEST33")
Result

Code: Select all

----------\/-------------\/-----------------\/
00000000  04 54 45 53 54 05 54 45  53 54 32 06 54 45 53 54  |.TEST.TEST2.TEST|
00000010  33 33                                             |33|
Thank you all

Re: XA: * manipulations

Posted: Sat Apr 15, 2017 9:56 pm
by christian
For those interested, here is the final code for this macro (header). Its purpose is to create a header for a Forth's word

Code: Select all

; __lfa need to be defined BEFORE the first use of the macro for 2 reasons:
; 	1) Fisrt LFA must be 0
; 	2) If not defined, all LFA point to the its own NFA
;
__lfa=0
#define header(name,lastc,mode,label) .( : __nfa=* : .byte __len|mode,name,lastc|$80 : __len=* - __nfa -1 : .word __lfa : -__lfa=__nfa : .) : +label = *
;               ^     ^    ^     ^
;               |     |    |     +----> Label (CFA)
;               |     |    +----------> Mode: _NORMAL | _IMMEDIATE
;               |     +---------------> Last character of the NFA
;               +---------------------> NFA (except last character)
;
;
;         .byte mode|lenght(name+lastc)  ;\ NFA
;         .byte name, $80|lastc          ;/
;         .word link to previous NFA     ;  LFA
;
; label:                                 ;  CFA
;

;
; Tools
;
#define code(name,lastc,mode,label) header(name,lastc,mode,label) : .word *+2

; #define word(name,lastc,mode,label) header(name,lastc,mode,label) : .word DOCOLON

#define constant(name,lastc,value,mode,label) header(name,lastc,mode,label) : .word DOCONS : .word value
#define variable(name,lastc,value,mode,label) header(name,lastc,mode,label) : .word DOVAR : .word value
#define user(name,lastc,offset,mode,label) header(name,lastc,mode,label) : .word DOUSER : .byte offset

;
; Modes
;
_NORMAL = $80
_IMMEDIATE = $C0

;
; Tests
;

* = $0400

header("TES","T"  , _NORMAL   ,TEST  )
header("TEST","2" , _IMMEDIATE,TEST2 )
header("TEST3","3", _NORMAL   ,TEST33)

header("","I",_NORMAL,I)

code("COD","E",_NORMAL,CODE)

.word TEST,TEST2,TEST33,CODE

And the result:

Code: Select all

00000000  84 54 45 53 d4 00 00 c5  54 45 53 54 b2 00 04 86  |.TES....TEST....|
00000010  54 45 53 54 33 b3 07 04  81 c9 0f 04 84 43 4f 44  |TEST3........COD|
00000020  c5 18 04 25 04 07 04 0f  04 18 04 23 04           |...%.......#.|
It's more tricky than with CA65 and I think I can't convert all macros from CA65 to XA, but I'll try...