hlorenzi / customasm

💻 An assembler for custom, user-defined instruction sets! https://hlorenzi.github.io/customasm/web/
Apache License 2.0
720 stars 56 forks source link

using variables before declaring them #100

Closed ProxyPlayerHD closed 3 years ago

ProxyPlayerHD commented 3 years ago

I'm running into this issue where i have a header of data at the start of a program that has to contain the size of the program following it.

long story short i made a Serial Bootloader for a 65C02 Computer so it needs to know how large a program is before actually loading it.

so how exactly would i implement this? or is it just completely impossible without having the assembler run twice through the program?

parasyte commented 3 years ago

customasm already does multiple passes to resolve lables. And AFAICT, this works as expected:

size:
#d16 end - start ; Output the size of the following data

start:
#d8 0xff, 0xff, 0xff, 0xff
#d8 0xff, 0xff, 0xff, 0xff
end:
hlorenzi commented 3 years ago

Hmm, yeah, I think you can do something like parasyte suggested. Since their code is using #d16 (as in, explicit size given), I don't think the assembler will have to do a second pass on this. I'll check soon.

ProxyPlayerHD commented 3 years ago

hmm, here is the exact format i'm using:

#INCLUDE "CPU_65C02.CPU"

; Address in Memory where the Program should be loaded to
PRG_START       = 0x0200

; Header required to be loaded with the Serial Bootloader.
#D16 0x6502     ; Magic Numbers
#D16 PRG_START      ; Address in Memory where the Program should be loaded to
#D16 PRG_SIZE       ; Amount of Bytes
#D16 INIT       ; Address in Memory where execution continues after loading the Program

#BANKDEF RAM
{
    #addr PRG_START
    #size PRG_SIZE
    #outp 0x0040
}

INIT:
; Code goes here

; Other end of the Header, used to calculate the total size of the Program
PRG_END:
PRG_SIZE = PRG_END - PRG_START

Bankdef is required for Absolute Addressing to work, though i could technically get around it by adding PRG_START to every instruction that uses Absolute Addressing, that would obviously be very annoying to do and hurts readability as well.

hlorenzi commented 3 years ago

Hmm, I see, using it inside the #bankdef might be trickier. You may do it like this, without specifying a #size to the bank:

; Address in Memory where the Program should be loaded to
PRG_START       = 0x0200

#BANKDEF Header
{
    #addr 0
    #size 0x8
    #outp 0
}

; Header required to be loaded with the Serial Bootloader.
#D16 0x6502     ; Magic Numbers
#D16 PRG_START      ; Address in Memory where the Program should be loaded to
#D16 PRG_SIZE       ; Amount of Bytes
#D16 INIT       ; Address in Memory where execution continues after loading the Program

#BANKDEF RAM
{
    #addr PRG_START
    #outp 0x0040
}

INIT:
; Code goes here

#d8 0xaa, 0xbb, 0xcc, 0xdd ; some random data

; Other end of the Header, used to calculate the total size of the Program
PRG_END:
PRG_SIZE = PRG_END - PRG_START
ProxyPlayerHD commented 3 years ago

i did not know you can just omit the "size" parameter. i assume it works the same as if you were to set it to the calculated size of the program?

though some more changes had to be done so it actually lines up with the start of the program instead of treating the header as the start

#BANKDEF RAM
{
    #addr PRG_START
    #outp 0x0040
}

changed into:

#BANKDEF RAM
{
    #addr PRG_START - 8
    #outp 0x0000
}

and it seems to work fine.

hlorenzi commented 3 years ago

Ah, yes! If you omit the #size, the assembler considers it to be infinite, and won't add any padding to the output. But I think this might only work for a single bank in your entire codebase. So if you need to get around that, I think you'll have to decide on a static size for your banks that doesn't depend on any content.