Hallo Besucher, der Thread wurde 4,2k mal aufgerufen und enthält 16 Antworten

letzter Beitrag von Snoopy am

Passing argument from Retro Assembler (Visual Studio Code) to Xemu

  • I am an absolutely beginner for XEMU and just installed it, but I would like to try out my first test in assembler, so I have setup Retro Assembler and the newest available Xemu. Though I do not expect my first program to work (I think I need some bank stuff), then I actually would expect that I would be able to pass my program from Retro Assembler (in Visual Studio Code) to Xemu and see it failing in there.


    This is the error I get in XEMU:



    And this is my assembler code where you can see how XEMU is launched:



    This is not for you to address my most likely not-working ASM, but maybe you have some hints to the "must start with -"? :-)


    EDIT AFTER FIRST POST


    The .setting is coming from the Retro Assembler Visual Studio Code extension documentation - quote:


    Build & Start utilizes the LaunchCommand setting entered into the source code file, by which you can launch the successfully compiled code file in an emulator. For example:

    .setting "LaunchCommand", "C:\\Emulator\\emulator.exe {0}"

  • Beauvais

    Hat den Titel des Themas von „Passing argument from Retro Assembler to Xemu“ zu „Passing argument from Retro Assembler (Visual Studio Code) to Xemu“ geändert.
  • Entweder (für reine .prg):

    -prg "$(RunFilename)" -besure

    Aghhh, yes of course. I don't know why it didn't cross my mind, that it was the parameters given to Xemu that was the problem, but thanks a lot for pointing it out :platsch:


    I get this error now, but I do expect this is because my ASM code is wrong and that I need to look in to grubi comment :-)


  • Plus, you will need to create a BASIC header in the PRG file to launch your assembler program, and the starting adress needs to be $2001 for it to work.


    BTW, your ASM looks good :thumbsup:

    Ha, yes - this is an overwhelming and complex code and only a trained eye can see through what it really does ;-)


    As mentioned then this is of course not for anyone to go in to specific code, but would you have any good reference for this initial basic loader and bank stuff? This is somehow confusing and some concrete examples would be nice (I like quick-and-dirty examples first and then the theory/details afterwards).

  • some concrete examples would be nice (I like quick-and-dirty examples first and then the theory/details afterwards).

    OK, here you go, quick and dirty:


    Code
    1. *=$2001
    2. .byte $11,$20,$0a,$00,$fe,$02,$20,$30,$3a,$9e,$20,$38,$32,$31,$31,$00,$00,$00
    3. lda #0
    4. sta $d020
    5. rts

    And now for the theory.


    When Xemu loads a .PRG file, it assumes it's a Basic program, loads it in memory, and tries to RUN it. So you need to provide it a Basic program.


    In order to run a machine code program, you must first provide a basic program that in turn calls the machine program using the SYS command. This is what the above .byte.... is. It's a Basic program in hexadecimal form. When you list it, it will read:

    Code
    1. 10 BANK 0:SYS 8211

    So it switches to bank 0, where your program is stored, and calls the machine program. Your machine program is located directly after the Basic program. Even if Basic memory starts at $2000, the location $2000 always contains a zero byte, and the actual program is loaded starting $2001. You have to match that with your *= statement, otherwise everything will be shifted by one byte and fail to run.


    So we just count bytes: The Basic program starts at $2001, which equals 8193. Then there are 18 bytes for the Basic program, so your first assembler statement (lda #0) will be located at 8193+18=8211.


    Keep in mind that I haven't tried out anything that I write here. It's pure theory. But If you're lucky, it will work :saint:

    And if not, people with higher IQ than me most likely will join in and correct my errors. That's the beauty of a forum like this one.

  • Keep in mind that I haven't tried out anything that I write here. It's pure theory. But If you're lucky, it will work :saint:

    And if not, people with higher IQ than me most likely will join in and correct my errors. That's the beauty of a forum like this one.

    Much appreciated and it made me understand the BASIC of it :D I will see if I can find some reference for what all these header-bytes actually mean, but your example works just fine.

  • Much appreciated and it made me understand the BASIC of it :D I will see if I can find some reference for what all these header-bytes actually mean, but your example works just fine.

    Glad it worked :puhh:


    I don't know a good reference for you, but I can explain if you're interested


    Let's look at it in Basic and hexadecimal again:


    10 BANK 0:SYS 8211

    11 20 0a 00 fe 02 20 30 3a 9e 20 38 32 31 31 00 00 00


    In Basic, every line starts with a zero byte. For the first line, this is already and always present at $2000, so not included in the bytes above.


    Then we continue with 11 20. This is a pointer to the next Basic line - more spcifically a pointer to the pointer part of the next line - (low byte and high byte), so the next Basic line would be located at $2011. When you count the bytes, you will find that this is the second byte of the 00 00 00 at the end. You see here that the next line starts with a zero byte again, and then the pointer to the next line is 00 00, which denotes the end of the program. So a Basic program always ends with three zero bytes.


    Now that we have looked at the first two and the last three bytes, this leaves us with the content of the Basic line:

    0a 00 fe 02 20 30 3a 9e 20 38 32 31 31


    The first two bytes is the line number (again, low and high byte) so the line number is $000a, which is 10.


    fe 02 20 30 is the "BANK 0" statement. $FE $02 is the BANK token, $20 is a space, and $30 is the number 0.


    3a is the colon (:) in the basic line.


    9e 20 38 32 31 31 means "SYS 8211". $9E is the Basic token for SYS, again $20 is a space, and 38 32 31 31 are the four digits 8211.


    That's all there is to it. Quite simple.


    How did I find out? I entered "10 BANK 0:SYS 8211" into my Mega65, entered Monitor and dumped the memory starting at $2000 :D

  • Much appreciated and it made me understand the BASIC of it :D I will see if I can find some reference for what all these header-bytes actually mean, but your example works just fine.

    In Basic, every line starts with a zero byte. For the first line, this is already and always present at $2000, so not included in the bytes above.

    Well, not exactly: every basic line ENDS with a zero byte.


    In BASIC every line starts with the (two bytes long) pointer to the next line unless there is no more lines, thus being '00 00' for the pointer in that case (and no more bytes at all then). Then two bytes long basic line number. Then the tokenized line itself, end of the basic line is marked with a zero byte. Yes the info of end of line marked with a zero byte, and the next line ptr stuff is kinda redundant but some BASIC functionality tend to use different methods to "walk" on lines. Also loading a BASIC program usually relinks the pointer structure anyway, thus it's possible to load a BASIC program written for another CBM machine with different loading address (in fact, that is the reason that loading the "$" - directory - from 1541 can't be used with ,8,1 and only with ,8 .... but that's a long story).


    So the reason the program ends with three zeros, is not because it marks the end of the program alone but: one zero just for the end of the current line, the two next would be the pointer for the next line, but there is no more, thus being two zeroes then. So in total you'll see, there are three zero bytes at the end of the program.


    And also a PRG file is special having and extra two bytes at the very beginning, that's the load address, and not part of the BASIC program itself.

  • Well, not exactly: every basic line ENDS with a zero byte.

    Thanks for clarifying :thumbsup:


    Seeing all those zero bytes between basic lines,, it's hard to interpret how they where meant to be, line starts or line ends...

    I always thought the zero byte at $2000 was part of the program, but just isn't saved to the file to save memory, since it's always zero anyway. But it seems my interpretation (that I had for the past 43 years) was wrong...


    And also a PRG file is special having and extra two bytes at the very beginning, that's the load address, and not part of the BASIC program itself.

    I'd like to add to this that - even if those two bytes are part of the PRG file - you don't have to put them into your assembler code, since the assembler will automatically write them to the PRG file. They're derived from your *=$2001 statement, so the first two bytes in the file will be $01 $20.


    But as LGB-Z stated, they're ignored when using LOAD or DLOAD, unless you use LOAD with ,8,1. But they're not ignored when loading with BLOAD.

  • Seeing all those zero bytes between basic lines,, it's hard to interpret how they where meant to be, line starts or line ends...

    I always thought the zero byte at $2000 was part of the program, but just isn't saved to the file to save memory, since it's always zero anyway. But it seems my interpretation (that I had for the past 43 years) was wrong...

    Well yes, hard to follow first time, but quite logical thinking about it this way: if you examine a PRG itself "on the disk" you can see the load address (first two bytes) is $2001 in our case. Thus, clearly $2000 is something else, not part of the program strictly speaking (since is one byte below the load address). For sure same applies to other configurations like in case of C64 saved BASIC programs would have $801 as load address (and not $800).

    Zitat

    I'd like to add to this that - even if those two bytes are part of the PRG file - you don't have to put them into your assembler code, since the assembler will automatically write them to the PRG file. They're derived from your *=$2001 statement, so the first two bytes in the file will be $01 $20.

    That is dependent though on the assembler, so indeed some must be very careful to check these things out first ;) Some assemblers purely uses the *=.... construct to change the relative address it emits addresses to but does not cause anything to "output" at all into the target file! Some assemblers can use that to "skip" bytes in the middle of program as well (filling up zeroes), some assemblers though, no filler bytes will produced just the assumed address for labels, etc to be referenced for. Honestly, I should admit, my English here is not well enough to express what I want to say, sorry about that .........

  • So what is then the role of the zero byte just before the start of the basic program? Mega65 seems to ignore it, but when you change that byte on any Commodore Machine (PET, VIC20, C64) Basic programs don't work any more. E.g. on a C64, write a Basic program, then POKE 2048,1, then RUN leads to Syntax Error. Somehow on those machines, the zero must be present.

    That is dependent though on the assembler, so indeed some must be very careful to check these things out first ;) Some assemblers purely uses the *=.... construct to change the relative address it emits addresses to but does not cause anything to "output" at all into the target file! Some assemblers can use that to "skip" bytes in the middle of program as well (filling up zeroes), some assemblers though, no filler bytes will produced just the assumed address for labels, etc to be referenced for. Honestly, I should admit, my English here is not well enough to express what I want to say, sorry about that .........

    I perfectly understand what you're saying. For that reason, in my own Assembler (Mega Assembler) I decided to combine the file output option with the *= command. When assembling to memory, you can change destination adress anywhere in between to whatever you like, while when outputting to a file (with *=<adress>,'<filename>') the file output goes on until the next *= statement, where output happens either to memory again or to another file that is specified (specifying the same file name overwrites the previous file). BTW, I also write the two adress bytes to the output files so they can easily be loaded to the right adress. So, no need to fill anything with zeros.

  • So what is then the role of the zero byte just before the start of the basic program? Mega65 seems to ignore it, but when you change that byte on any Commodore Machine (PET, VIC20, C64) Basic programs don't work any more. E.g. on a C64, write a Basic program, then POKE 2048,1, then RUN leads to Syntax Error. Somehow on those machines, the zero must be present.

    To be honest I have no idea. For example https://sta.c64.org/cbm64mem.html says:

    Code
    1. $0800 Unused. (Must contain a value of 0 so that the BASIC program can be RUN.)
    2. $0801-$9FFF Default BASIC area (38911 bytes).