Jump to content
IGNORED

MADS Knowledge-Base


Recommended Posts

Got two bugs in MADS 1.9.8 that I can reproduce down to 1.9.2.

 

The first file reports branch too far, though the target (which is a PROC) is <127 bytes away.

Description Resource Path Location Type

Branch out of range by $0017 bytes AlienSwarm.asm /Atari800/Programming/2014/AlienSwarm line 848 Problem

Branch out of range by $00F7 bytes AlienSwarm.asm /Atari800/Programming/2014/AlienSwarm line 2374 Problem

 

 

In the second I've put a label before the PROC, so the branch works somehow.

But then the PROC generates wrong JSR addresses for a label therein.

 

00 137B L13AF

 

683 13C1 .proc l13f5

684 13C1 20 C1 13 jsr l13af ; SHOULD BE 20 7B 13

Link to comment
Share on other sites

JAC!, I was able to get AlienSwarm-Branch.asm to compile by removing the silly_disk_check .proc. Perhaps MADS gets confused by .proc's that are .if .def'd out? The AlienSwarm-Wrong-L13AF.lst file shows that all of the proc references seem to be off by one.

Link to comment
Share on other sites

Why does this produce a value range error?


	.extrn zp1,zp2,zp3,zp4 .byte
	.extrn BankIn .word
	.extrn BankOut .word

	.reloc

start
	lda #0
	sta zp1
	lda #2
	sta zp2
	lda #1
	sta zp1
	jsr BankIn
	lda #> BankIn ; value out of range
	rts
	
	blk update external
	blk update address

How do we generate '<' and '>' external symbol fixups if the above notation is illegal?

Link to comment
Share on other sites

Another question:

	.reloc

start
	lda #< Data
	lda #> Data
	rts
	
Data
	.byte 0
	

	blk update address

This code produces the following binary:

 

post-21964-0-02223000-1406233163_thumb.png

 

How do we deduce from the update block that the first relocated byte is the LSB and the second the MSB? :o The update block presents two byte ("B") offsets. Or have I missed something?

 

Note: I'm (finally) writing a relocating loader for MADS relocatable binaries as we speak. The job isn't too difficult, but I'm stuck until I understand the above issues.

 

Edit: what is relocation data type "E", which I also see in some of the compiled examples, but which is not mentioned in the manual? OK - I figured out that "E" describes ".DS" (empty space), said to be prohibited in the manual, but actually allowable. :)

 

Worse yet:

	.extrn zp1,zp2,zp3,zp4 .byte
	.extrn BankIn .word
	.extrn BankOut .word

	.reloc

start
	lda #< Data
	ldx #> Data
	jsr BankIn
	rts

Data

	blk update address
	blk update external

Produces:

 

post-21964-0-59603600-1406235410_thumb.png

 

No relocation information about the lo/hi references to "Data" whatsoever.

 

Edited by flashjazzcat
Link to comment
Share on other sites

There are a bunch of oddities in MADS relocatable mode. The main problem is that it requires unusual syntax to refer to relocatable symbols, i.e.:

lda <IrqHandler
sta vdslst
lda >IrqHandler
sta vdslst+1

Those LDA instructions assemble to LDA #imm instructions in a .RELOC block. I don't know why this is required, and it's a bit annoying. If you forget to do this and use regular #<sym and #>sym instead, you'll get the pseudo-addresses of the symbols hardcoded instead, which is definitely not wanted. MADS does not warn if an expression uses relocatable symbols in a form that can't be encoded and silently generates broken code instead.

 

As you might expect, this also means that the collapsed forms also require omitting the hash:

mva <IrqHandler vdslst
mva >IrqHandler vdslst+1

Where this gets ugly is that this does not carry over to word initialization. This copies the word at the symbol IrqHandler to VDSLST, which is wrong:

mwa IrqHandler vdslst ;AD/8D/AD/8D + 2x word reloc

Instead, the conventional form emits 2x LDA #imm + STA:

mwa #IrqHandler vdslst ;A9/8D/A9/8D + 1x low reloc + 1x high reloc

Additionally, some forms of initialization will silently turn a relocatable symbol into a hardcoded pseudoaddress. This does not work, and generates a JMP abs with no relocation:

jmp foo
foo = bar
.proc bar
rts
.endp

This, however, does:

jmp foo
.def foo = bar
.proc bar
rts
.endp

I ended up finding enough issues in investigation to abort and go back to the way I've been generating relocatable code, which is to fixed assemble at three different addresses and compare the binaries. It's slower, but it imposes few restrictions on how the code is written.

 

  • Like 2
Link to comment
Share on other sites

There are a bunch of oddities in MADS relocatable mode. The main problem is that it requires unusual syntax to refer to relocatable symbols, i.e.:

lda <IrqHandler
sta vdslst
lda >IrqHandler
sta vdslst+1
Those LDA instructions assemble to LDA #imm instructions in a .RELOC block. I don't know why this is required, and it's a bit annoying. If you forget to do this and use regular #<sym and #>sym instead, you'll get the pseudo-addresses of the symbols hardcoded instead, which is definitely not wanted. MADS does not warn if an expression uses relocatable symbols in a form that can't be encoded and silently generates broken code instead.

 

Thanks so much Avery - I really appreciate your rapid response. I had come across this strange notation before (a long time ago), but it had completely slipped my mind.

 

As you might expect, this also means that the collapsed forms also require omitting the hash:

mva <IrqHandler vdslst
mva >IrqHandler vdslst+1
Where this gets ugly is that this does not carry over to word initialization. This copies the word at the symbol IrqHandler to VDSLST, which is wrong:

mwa IrqHandler vdslst ;AD/8D/AD/8D + 2x word reloc
Instead, the conventional form emits 2x LDA #imm + STA:

mwa #IrqHandler vdslst ;A9/8D/A9/8D + 1x low reloc + 1x high reloc

 

This methodology almost appears designed to subvert the goal of bug-free code. The requirement to omit '#' is puzzling, since 'LDA < label' normally means "load the contents of the memory location pointed to by the MSB of LABEL's address". While not exactly a common requirement, this operation becomes impossible if '<' without '#' means '< #'. And the '.def' example should just about catch everyone out.

 

I ended up finding enough issues in investigation to abort and go back to the way I've been generating relocatable code, which is to fixed assemble at three different addresses and compare the binaries. It's slower, but it imposes few restrictions on how the code is written.

I've also considered this method recently, such is my frustration. I had previously thought of writing a loader for SDX binaries, since they appear to be more predictable than native MADS relocatable binaries, but the SDX format is a bit more quirky and I have only a chunk of fragmented source code from an SDX 4.20 disassembly adorned with Polish commentary which Drac030 sent me a year or two back. A disadvantage of the SDX format is no lo/hi addressing (which we know how to get around, of course), but other than that it covers all the bases. However, writing the loader is a bigger undertaking for me.

 

What both formats offer is the facility for external symbols, which I could have gotten by without until I realized they'd be a perfect way to deal with page zero allocation. If each program defines PZ1, PZ2, etc, as external BYTE references, the loader can dole out page zero RAM from a pool and we thereby cut out page zero copying altogether when performing context switches. Having already just about gotten rid of stack copying, this solution would seem to address both 6502 limitations with regard to multitasking. Using the 'two binaries compiled at different addresses and compared' tactic would not permit this method of page zero relocation, however (BTW: I lost the article I found on that relocation method some time ago. What's the best offset to use? I recall offsetting the origin by a page didn't work since it wouldn't flag #< operands. Was it 257 bytes? And have you written your own tool to generate the relocation table from the comparison of two binaries assembled at different addresses?).

 

After a year or more of requesting augmentations to the relocation format, it doesn't look as if Tebe feels like making any changes (at least not to cater for the requirements of a project still in the development stage). Short of writing my own assembler (again, and in any case the proposition is horrifying), there are some important decisions to make. Looks like some more studying of the SDX loader is in order...

Edited by flashjazzcat
Link to comment
Share on other sites

I forgot that the SDX format does not permit the definition of an 8-bit external symbol reference.

PZ1 SMB 'PZ1'

	blk reloc main
	lda pz1
	lda (pz1),y ; addressing error
	rts

The assembler assumes that all external labels are 16-bits addresses [sigh]. So this is not really useful for what we have in mind regarding page zero allocation...

Link to comment
Share on other sites

The distinction betwee "#>" and ">" actually existed before the explict .RELOC blocks. When you explictly use different compile & run address (e.g. PROC name, adr) you will sometimes need the distinction. For example when you have a procedure compiler to ROM but intended to run from the RAM later.

 

As for the general problem with relocation: You will always hit the wall sooner or later when you write code to relocation just the same way you would write without relocation. Esp. any kind of address arithmethic will by definition fail if it becomes more complex than adding a fixed offset. In the case of ">" and "<" adding can still work in most cases (provided you differentiate between equate and labels), but if you think about .ALIGN (for a display list) or "MOD/DIV" it'll fail. If you are careful compiling to different addresses does the job pretty well. I had that idea in the 90ies (for sure not as the first person in the world, but hey, I had it myself) and I had my Amiga as a cross-dev system. I used $201 as offset, so I could find the change high-bytes (+$02) and low bytes (+$01). So you could simply compile twice (no matter with which compiler, no matter if on Atari or on Amiga) and feed the two files into this too to get a self-relocating XEX.

post-17404-0-29620700-1406305862_thumb.png

Edited by JAC!
  • Like 2
Link to comment
Share on other sites

The distinction betwee "#>" and ">" actually existed before the explict .RELOC blocks.

Without doubt. It's the inability to explicitly distinguish between them which arrived with MADS's proprietary relocation format.

 

As for the general problem with relocation: You will always hit the wall sooner or later when you write code to relocation just the same way you would write without relocation. Esp. any kind of address arithmethic will by definition fail if it becomes more complex than adding a fixed offset. In the case of ">" and "<" adding can still work in most cases (provided you differentiate between equate and labels), but if you think about .ALIGN (for a display list) or "MOD/DIV" it'll fail.

I've written quite a few SDX relocatable programs and as long as you avoid the caveats, things work OK. The biggest pain was having to do:

 


	lda p_buffer
	ldx p_buffer+1

...

p_buffer
	.word buffer
Even that's hardly debilitating, though. The SDX format has one key advantage: namely multiple relocation blocks in the same code. You can, for example, have a driver with an INIT section which loads at a fixed address (and is later jettisoned), a main module which installs at MEMLO, and another segment which exists in extended RAM. All three modules get fixed up so they can see all the labels in the other segments. This would have been handy in the GUI if one wanted to use a similar driver structure, or have an application which spanned more than one extended bank. MADS' own format (currently) only allows a single relocatable block (I have wondered aloud for a year or more whether this limitation could be lifted), although this is fairly reasonable if all you want to do is link up the resulting modules with the assembler's linker. It's fairly clear that the proprietary format was never really intended to create application binaries - hence the limitations I'm running into now.

 

If you are careful compiling to different addresses does the job pretty well. I had that idea in the 90ies (for sure not as the first person in the world, but hey, I had it myself) and I had my Amiga as a cross-dev system. I used $201 as offset, so I could find the change high-bytes (+$02) and low bytes (+$01). So you could simply compile twice (no matter with which compiler, no matter if on Atari or on Amiga) and feed the two files into this too to get a self-relocating XEX.

I'm hearing more and more about this technique, and it's no less flexible than MADS relocatables with one exception: provision for external references. Were it not for the need to divvy out page zero locations on loading, compiling to different addresses is the method I'd run with for the moment. This would at least encourage a broader demographic to actually write applications. But I think getting rid of page zero copying is also pretty compelling, and it seems this can only be done with a compiler which produces external reference fix-ups.

 

Still: a loader for MADS binaries is pretty simple to code up (easier than for SDX code, with its compression tokens, etc), so I'll run with that for the moment. If any developers take an interest later on and they're unhappy with the development restrictions, they're more than welcome to write an assembler which works the way they want. :)

Link to comment
Share on other sites

> The biggest pain was having to do:

Plus it wastes space any even more important cycles at runtime.

 

>Were it not for the need to divvy out page zero locations on loading

The ZP rewriting parts could as well be address with generating 2 compile steps. If you now that all that has changed between the 2 files is the ZP base addres (.def ZP_BASE=$00/$80) of your ZP variable space, you can final up to 128 different locations in one go. So maybe combining MADS format with this simple step can be a reasonable approach.

  • Like 1
Link to comment
Share on other sites

The ZP rewriting parts could as well be address with generating 2 compile steps. If you now that all that has changed between the 2 files is the ZP base addres (.def ZP_BASE=$00/$80) of your ZP variable space, you can final up to 128 different locations in one go. So maybe combining MADS format with this simple step can be a reasonable approach.

Hmmm... I never thought to adjust the ZP base between compilations. ;) This would have to be done as yet a third compilation, so we get a second table pertaining solely to page zero references. We then reckon up how many page zero locations are referenced, allocate them from the system pool, and relocate accordingly. Interesting!

 

No need to combine this with the MADS format though, since the format inherently provides for easy PZ allocation (through external symbols; although one could combine the compile/compare method with the SDX format for the ultimate in flexibility). However, all I need is a tool which builds a table of the differences between two binaries and I can see an ideal situation: support for BOTH the MADS format, and for the relocate/compare method. :)

Edited by flashjazzcat
Link to comment
Share on other sites

I've written a loader for MADS relocatable binaries (which turned out to be pretty easy), so that should suffice until further problems and limitations are encountered. ;)

 

Note: regarding the other relocation method, I found that Windows' FC tool outputs a list of hex differences. I suppose it shouldn't be too hard to write a custom tool which outputs a binary blob of 16-bit values.

Edited by flashjazzcat
  • Like 1
Link to comment
Share on other sites

The relocatable code I did was for the 6502-based 850 R: handler in recent Altirra 2.50 test releases -- it's handler.s for the relocatable code itself, relocator.s for the relocator, and makereloc.cpp for the converter. The relocator itself is not too big -- 145 bytes including the code to issue the SIO download.

 

Slight mistake -- it actually takes four assembles: one at $2800, one at $2801, one at $a800, and a special hi-lo build at $2800. The hi-lo build swaps around high byte only relocs to emit the low byte offset. This means that any references to the high byte only require a macro, annoyingly. The plus side is that arbitrary offsets from any relocatable symbol are allowed in this scheme, even with high-byte or low-byte extraction.

 

I'd much prefer having the assembler deal with this, as it would allow for fully natural syntax and also be able to flag any disallowed address arithmetic. Supposedly CA65 does this, as it always goes from relocatable code to fixed code instead of the other way around as MADS does. I've gotten a bit too used to MADS's shortcuts, though.

Link to comment
Share on other sites

The relocatable code I did was for the 6502-based 850 R: handler in recent Altirra 2.50 test releases -- it's handler.s for the relocatable code itself, relocator.s for the relocator, and makereloc.cpp for the converter. The relocator itself is not too big -- 145 bytes including the code to issue the SIO download.

I haven't checked the size of my relocator yet (and it's unoptimised), but it ain't big. It handles external symbol references as well, although I've yet to code up the linked list internal symbol table. I might add support for public symbol declarations in modules as well. At least the mystique has gone out of it. :)

 

I'd much prefer having the assembler deal with this, as it would allow for fully natural syntax and also be able to flag any disallowed address arithmetic. Supposedly CA65 does this, as it always goes from relocatable code to fixed code instead of the other way around as MADS does. I've gotten a bit too used to MADS's shortcuts, though.

This is more or less what's stopping me changing assemblers. I have become heavily dependent on enumerated variables, structs, local blocks (and encapsulated labels within them), and the built-in macros, and am heavily entrenched in MADS' syntax.

Edited by flashjazzcat
Link to comment
Share on other sites

Can you please tell me how to output a number -1 or any other signed number below zero.

Nobody answered yet how to represent signed numbers with Mads package. We know it is done with carry flag set, but do I have to make my own routine to use it to show signed number, or is there easy solution to this in Mads? The types and print routines do not allow it anyway.

Link to comment
Share on other sites

Hi. Found two issues with MADS 1.9.9.

Issue 1: Error location for macro usages.
If ".error" occurs in a macro, MADS reports the defining position of the macro as error location, instead of the location where the macro is used. This make it very hard to find the real error.

 

Code in "CartMenu-Kernel-Equates.asm":

.macro m_assert_same_1k ;For Display Lists
.if :1 / $400 <> (:1 + .len :1 - 1) / $400
.if .def alignment_mode
.error ":1 crosses 1k boundary between ", :1, " - ", :1 + .len :1 - 1
.else
.print ":1 crosses 1k boundary between ", :1, " - ", :1 + .len :1 - 1
.endif
.else
.print ":1 within 1k boundary between ", :1 , " - ", :1 + [.len :1 ] - 1
.endif
.endm



Compiling: "TheMenu-Visualization.asm.asm"

.local dl
.byte $60,$46,a(header),$80+$60
...
.endl


m_assert_same_1k dl

Output:

m_assert_same_1k dl
C:\Users\D025328\Documents\Eclipse\workspace.jac\com.wudsn.productions.atari800.thecartstudio\asm\thecart-menu\CartMenu-Kernel-Equates.asm (237) ERROR: DL crosses 1k boundary between $1BF9 - $1C37


Issue 2: Virtual bank numbers in .lab file
I have added a parser the read the information from the MADS .lab file to display it in a structured way. According to the documentation there are these virtual banks
$FFF9 label for parameter in procedure defined by .PROC
$FFFA label for array defined by .ARRAY
$FFFB label for structured data defined by the pseudo-command DTA STRUCT_LABEL
$FFFC label for SpartaDOS X symbol defined by SMB
$FFFD label for macro defined by .MACRO directive
$FFFE label for structure defined by .STRUCT directive
$FFFF label for procedure defined by .PROC directive

But when I compile this:

; Reference source file for MADS symbols

org $2000

.macro m_macro
m_label1
lda #1
.endm

equate1 = 1
equate2 = equate1+1

label1 lda #1
label2 sta $80


// $FFF9 label for parameter in procedure defined by .PROC
// TODO: Missing in .lab file
.proc parameter_procedure( .byte byte1 .word word1 ) .var
.var inner_var .byte
.endp

// $FFFA label for array defined by .ARRAY
// TODO: Actually results in $FFF8 instead in .lab file
array1 .array
.enda

// $FFFB label for structured data defined by the pseudo-command DTA STRUCT_LABEL
structure_data dta inner_structure [12]

// $FFFC label for SpartaDOS X symbol defined by SMB
// Actually results in $FFFB instead in .lab file
smb_symbol smb

// $FFFD label for macro defined by .MACRO directive
m_macro

// $FFFE label for structure defined by .STRUCT directive
.struct inner_structure
x .word
y .word
.ends

.struct outer_structure
structure inner_structure
.ends


// $FFFF label for procedure defined by .PROC directive
.local outer_local
.local inner_local
.byte 0
.endl
.byte 0
.endl

.proc outer_procedure
.proc inner_procedure
rts
.endp
rts
.endp


I get this result. ARRAY is $FFF8 instead of $FFFA. STRUCTURE_DATA is $FFF9 instead of $FFFB. And the procedures and their parameters have no virtual bank at all.

mads 1.9.9 build 23 (22 Jun 14)
Label table:
00 0001 EQUATE1
00 0002 EQUATE2
00 2000 LABEL1
00 2002 LABEL2
00 2004 PARAMETER_PROCEDURE
00 2004 PARAMETER_PROCEDURE.INNER_VAR
FFF8 0001 ARRAY1
FFF9 0006 STRUCTURE_DATA
FFFB 0000 SMB_SYMBOL
00 2039 M_MACRO0.M_LABEL1
FFFE 0000 INNER_STRUCTURE
FFFE 0003 OUTER_STRUCTURE
00 203B OUTER_LOCAL
00 203B OUTER_LOCAL.INNER_LOCAL
00 203D OUTER_PROCEDURE
00 203D OUTER_PROCEDURE.INNER_PROCEDURE

 

Side note: I never used the MADS printf stuff, so no tips there.

MADS.zip

Link to comment
Share on other sites

Just reading the stuff about relocation... as mentioned the cc65 includes relocatable/loadable module support. Info is here:

http://www.6502.org/users/andre/o65/fileformat.html

 

Might be useful, but I suspect it relies heavily on the way that the cc65 suite creates object files.

Yep, thanks: I looked into that one as well a while ago, but as you say, it looks pretty closely tied to the CC65 suite.

 

Nobody answered yet how to represent signed numbers with Mads package. We know it is done with carry flag set, but do I have to make my own routine to use it to show signed number, or is there easy solution to this in Mads? The types and print routines do not allow it anyway.

I think Gury wants to output signed numbers using the supplied printf routine, rather than write Delphi code? Anyway: if that's the case, you'll need a better printf routine. I'm sure there's a "light" printf routine in the CC65 library, hopefully written in 6502. I've written several but none of them handle floats or negative numbers, since I never had any need. Nevertheless, if you want the source, you're welcome to it.

 

Apologies if I've totally misread the question. ;)

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...