Indie game storeFree gamesFun gamesHorror games
Game developmentAssetsComics
SalesBundles
Jobs
Tags
(+2)

Hey there,

I have a question regarding labels in Octo. I want to have a look-up table of labels that point to data:

: my-data
  image-1
  image-2
  image-3
: image-1
  0xFF 0x00 0xFF # Et cetera

I use this table to look up the address of the right image and load that in "i" with some self-modifying code that adds a 0xA0 (load i) prefix. And it seemed to be working quite well so far.

However, now that my program has passed the 3,5k mark I'm getting an error "Value '<much>' for label 'image-1' cannot not fit in 12 bits!" (there's a small spelling mistake in that error, by the way). This has lead me to realise that my table of labels doesn't really compile to a table of addresses, but to a table of call statements. And the fact that I AND those statements with the right nibble in my self-modifying code has kept that fact hidden from me.

So the question is... does Octo have a way to just put the address of a given label in the output binary? I looked through the manual, but didn't really find anything.

This example shows a table like this:

: table
  i := 0x123 ;
  i := 0x456 ;
  i := 0x789 ;
  i := 0xABC ;
  i := 0xDEF ;

Which would work with "i := long <label>;" too, I guess. But that would be six bytes per entry, instead of two. Seems like a waste :)

(+2)

If you want to work with a "raw" 16-bit address, you can use a pair of ":byte" statements:

:const foo 0x1234
...
:byte { foo >> 8 }
:byte { foo }

When I need to do this, I usually generalize it into a macro:

:macro pointer ADDRESS {
    :byte { ADDRESS >> 8 }
    :byte { ADDRESS }
}
...
pointer foo
(+2)

Ah, that's a neat trick! But does that only work with constants? Or can I use it with labels too? :)

(+2)

Yes- constants and labels are the same thing!

The only major limitation is that once you start operating on addresses with macros and doing compile-time calculations, you must declare those labels before referencing them in expressions. In some instances this may require you to use `:org` to assemble your program in a non-linear fashion.

(1 edit) (+2)

Ahh, so that's what's going wrong. That's pretty annoying :/ I have a shit-ton of data that I need to reference in this way. I guess the data is going to the top of the file, cluttering up the place, if there is no other way.

I was just getting used to the jump0 trick, until I realised that I have 48 entries in the table and 47 * 6 = 282, which is more than v0 can hold... So v0 is overflowing and giving me errors... o_0'

If I want to have the data before my code, can I do something like this?

:org end-of-code
  <data>
:org 200
: main
  <code>
: end-of-code

This particular code gives me an "Undefined name 'end-of-code'".

Edit: Never mind! I don't have to move all the code under the data, I just have to move the look-up table under the data. Problem solved! Thanks guys :)

(1 edit) (+2)

:org can't deal with a forward reference either. It would kinda require the assembler to contain a constraint solver to support that sort of thing in full generality.

For an XO-CHIP game, I'd recommend using a pair of macros something like the following:

:calc CODE_POS { 0x200  }
:calc DATA_POS { 0x1000 }
:macro to-code { :calc DATA_POS { HERE }  :org { CODE_POS } }
:macro to-data { :calc CODE_POS { HERE }  :org { DATA_POS } }

The idea is to reserve the low 4kb of RAM for code, and then position all of your data afterwards. By invoking these macros in turn, we can alternate between defining data and defining code, and thus keep related information together within our source code. Then it's easy enough to define "high RAM" addresses before we need to build pointers to them, for example.

: main
    jump draw-smile
to-data
: smile 0x50 0x00 0x88 0x70
to-code
: draw-smile
    i := long smile
    sprite v0 v0 4

This will often waste a bit of space in the gap between "code" and "data", but you can manually tweak the initial value of "DATA_POS" if things get really tight.

Make sense?

edit: And, yes, you're absolutely right: for your specific case you just have to put the lookup table in the right place. :)

(+1)

Thanks for the ideas! And the crazily quick replies! :)