millfork icon indicating copy to clipboard operation
millfork copied to clipboard

a8 – cannot create a XEX file that launches from somewhere else than the start

Open zbyti opened this issue 5 years ago • 16 comments

java -jar /home/zbyti/Programs/Millfork/millfork.jar -Xr -t a8 mptplayer.mfk

XEX header: Screenshot_2020-10-05_12-13-17

XEX end Screenshot_2020-10-05_12-13-52

main routine address is $26b8, it isn't proper XEX file.

a8_mptmusic.zip

zbyti avatar Oct 05 '20 10:10 zbyti

At the moment, the Atari executable is defined as $FF,$FF,$E0,$02,$E1,$02,startaddr,startaddr,endaddr,allocated so the launch address is always the first byte of the output. I agree this is not ideal, as if you want to put something else near the beginning, it doesn't work.

There are several other platforms affected by the same issue:

  • CoCo, TRS-80, Z1013 and ZX Spectrum, like Atari, have both a load address and a launch address, and Millfork sets them to the same value

  • Commodore has a Basic stub that jumps to a fixed address; if main() is shifted elsewhere due to putting something else at that location, the code won't work

  • several platforms always launch the loaded file from the beginning; with those, the issue is not solvable in these cases

I think I should add a way to mark the launch address separately.

KarolS avatar Oct 05 '20 19:10 KarolS

As far as I know proper XEX may looks like:

header $ff,$ff,startaddr,endaddr end of binary runaddr

Ok. It's fine answer to my question :+1:

zbyti avatar Oct 05 '20 19:10 zbyti

I'm reopening it, as I want to solve the underlying deficiency, at least for those platforms where it is possible, like Atari.

KarolS avatar Oct 05 '20 20:10 KarolS

OK :] anyway this code works for me:

const word ADDRMUS = $a000
const word ADDRPLA = $b000

byte stop @ ADDRPLA + $62d

asm void comm(byte register(a) a, byte register(x) x, byte register(y) y) @ ADDRPLA extern
asm void takt() @ ADDRPLA+3 extern

void main(){
  comm(0,ADDRMUS.hi,0)
  comm(4,0,0)
  while os_CH == $ff {
    if antic_vcount == $10 {
      antic_wsync = $e
      gtia_colbk = $e
      takt()
      gtia_colbk = 0
    }
  }
  stop = 0
}

const array player @ ADDRPLA = file("data/mpt_player.obj", 6)
const array music @ ADDRMUS = file("data/bitter_reality_4.mpt", 6)

zbyti avatar Oct 05 '20 20:10 zbyti

FYI

OBJ files $ff,$ff,startaddr,endaddr OBX files $ff,$ff,startaddr,endaddr ended with runaddr

zbyti avatar Oct 05 '20 20:10 zbyti

I've read somewhere that Atari will launch the program if the start address is written to $02E0/$02E1, and this is what I'm doing.

KarolS avatar Oct 05 '20 20:10 KarolS

Most of the XEX I've seen has a short header and ended with run address.

zbyti avatar Oct 05 '20 20:10 zbyti

http://atariki.krap.pl/index.php/Binarny_plik_DOSu

http://atariki.krap.pl/index.php/COM

http://atariki.krap.pl/index.php/ATR

zbyti avatar Oct 05 '20 20:10 zbyti

I checked some XEX files I have and they all end with a chunk with the launch address: E0 02 E1 02 YY XX. Since it doesn't matter what order the chunks are in the file, I put that chunk first. I guess this is against the tradition, but it still works. Millfork currently creates two-chunk XEX files: one chunk for the launch address, one for the actual program. In other words:

  • The most common layout (SHSL: data start, EHEL: data end, RHRL: launch address):

      FF FF                   header
      SL SH EL EH  DD DD DD   chunk from:$SHSL to:$EHEL data:DDDDDD
      (sometimes more chunks)
      E0 02 E1 02  RL RH      chunk from:$02E0 to:$02E1 data:$RHRL
    
  • Millfork (with RHRL = SHSL):

      FF FF                   header
      E0 02 E1 02  RL RH      chunk from:$02E0 to:$02E1 data:$RHRL
      SL SH EL EH  DD DD DD   chunk from:$SHSL to:$EHEL data:DDDDDD
    

KarolS avatar Oct 05 '20 21:10 KarolS

My experience come from Atar800 emulator monitor:

WRITE [XEX] startaddr endaddr [runaddr] [file]
                               - Write memory block to a file (memdump.dat).
                                 With XEX, writes an Atari executable with
                                 optional run address (no init addr, sorry).
                                 [file] may begin with |, to pipe to a command

and XEX produced by Action! compiler https://github.com/zbyti/a8-action-playground and XEX produced by Mad Pascal compiler https://github.com/zbyti/a8-mad-pascal-playground

I do not know theory well ;)

zbyti avatar Oct 05 '20 21:10 zbyti

I asked a friend who is an experienced and longtime Atari800 programmer (including Sparta DOS) and he said that a short header $ff,$ff,startaddr,endaddr and binary ended with runaddr is sufficient for OBX aka XEX alias COM ;)

zbyti avatar Oct 06 '20 09:10 zbyti

some INIT vs. START discussion https://atariage.com/forums/topic/235338-creating-a-binary-file-with-an-init-address-from-mac65/

I don't agree that Sparta is wrong; it does handle the INIT address properly. The INIT address is to allow something to execute before the main program runs, either via $02E0 or jumping to the load address. It's a design mistake in Action! to have used $02E2 as the run address, since there is no initialization required for the Action! runtime code.

zbyti avatar Oct 08 '20 16:10 zbyti

@KarolS well now I understand what you want to achieve with long header :+1:

https://github.com/tebe6502/Mad-Assembler/issues/1#issuecomment-709283588

zbyti avatar Oct 29 '20 13:10 zbyti

https://atariage.com/forums/topic/313212-funkheld-kickc-questions/?do=findComment&comment=4675562

zbyti avatar Nov 12 '20 20:11 zbyti

Currently, Millfork always outputs contiguous memory ranges, so I guess the powers of the Atari exe format are underutilised. I'll think about outputting multiple non-contiguous chunk, as it might be useful, at least on platforms that support it.

KarolS avatar Nov 14 '20 00:11 KarolS

https://gitlab.com/jespergravgaard/kickass-plugin-atari-xex

I have also integrated the plugin into KickC.

So in the next release KickC will be able to create XEX-files where each memory block is stored as a seperate segment in the XEX-file.

This will help you to get smaller XEX-files if you for instance have some code in $1000 and some data in $3000 with an empty gap in between.

zbyti avatar Nov 15 '20 15:11 zbyti