Treat i more like a pointer. You can advance it to get to another memory location. https://johnearnest.github.io/Octo/docs/Manual.html#statements
It’s easy enough to load it (using self modifying code)… but you can’t ever retrieve it’s value (that’s hidden inside the emulator)… so if you need that type of indirection then you manually need to use your OWN external pointer and track it’s value, loading it into i
when necessary… which of course is slower.
Try reading here, search for load and look at the examples how they are used: https://github.com/JohnEarnest/Octo/blob/gh-pages/docs/Chip8%20Programming.md
First, the simplest case: you have a single byte in memory and you want to load it into a register:
: data 0xAB ... i := data # set i to the base address load v0 # load from i into v0
Slightly more complex: you have an array of up to 256 bytes, and you want to load one by index into a register:
: data 1 1 2 3 5 8 11 ... i := data # set i to the base address i += v1 # add an offset (in this case, the value in v1) load v0 # load data[v1] into v0
Same as before, but now we want 2 bytes:
i := data # set i to the base address i += v1 # add an offset. items are two bytes wide... i += v1 # (we alternatively could have pre-doubled v1.) load v1 # v0=data[2*v1], v1=data[(2*v1)+1]
Are those cases clear?