Looking at instruction set but cannot find. I would be interested in supported instructions/methods.
Login or register to post comments
Looking at instruction set but cannot find. I would be interested in supported instructions/methods.
PC is set by instructions like JP
, JR
, CALL
or RET
.
The PC value at the point you want to check it is always the address of the instruction at the point you want to check it.
What do you want to achieve exactly?
call pc_on_stack pc_on_stack: pop hl ; pc in hl
The assembler/linker will typically know where the PC is at all times so you can just load it directly to hl:
addr: ld hl, addr
or
ld hl, $
The fun thing with sjoerds version is that it can be put in a function that you can call:
; returns callers program counter in hl get_pc: pop hl jp (hl)
@bore yes I though about using $, but that is at compile time.
Maybe I had to expose the case: it is for a chunk of code that will be moved, it only uses relative jumps and has some part like this:
if content of some address != 0 then call it, if not continue.
As the code is going to be moved, it was necessary something to return from an indirect call.
The method posted by @sjoerd looks interesting.
I think it can be solved in a fast way putting in somewhere in a fixed memory location:
somewhere_hook: jp 0x0000
Somewhere_hook is a fixed location and followed by the address to check.
Then in the code that is going to be moved:
“check” (the 2 bytes at somewhere_hook + 1) call nz, somewhere_hook
Then after the execution of that indirect call it will return to the right location.
on ZX Spectrum you can sometimes write those two instructions `pop hl : jp (hl)` to VRAM at fixed address like 0x4000, and `call 0x4000` will load HL with following address -> this way you can figure out your running PC even if you don't know where your code was loaded and who started it from where. If you have similar two-byte buffer on MSX which is usually free and can be overwritten and called, you can use the sjoerd's code for runtime detection. (And then for example relocate rest of your code accordingly, for example something like in this ZX example (it expect starting address in BC as the ZX Basic provides it, but you can patch it to use the sjoerd's trick and use value from HL): https://github.com/z00m128/sjasmplus/blob/master/examples/re...
It's not possible to write completely relative [non trivial] code with Z80, eventually you need some `call` or `jp`, only 8bit -126..+129 range is covered by `jr/djnz` relative jumps, so usually everyone does place code at fixed position and assembles it like that, but you can use the relocation trick with table data to patch existing code.
if content of some address != 0 then call it, if not continue.
As the code is going to be moved, it was necessary something to return from an indirect call.
A different approach:
JP_HL: jp (hl) (...) ld hl, somewhere_hook ld a, h or l call nz, JP_HL (...)
Or this, slighly slower but smaller if you use it in more than a couple of places:
JP_HL_IF_NOT_ZERO: ld a, h or l ret z JP_HL: jp (hl) (...) ld hl, somewhere_hook call JP_HL_IF_NOT_ZERO (...)
Call getpc ;returns pc in hl Getpc: Pop hl Push hl Ret
Yep the good is that code like that is rellocatable on any place so only requires a very small ammount of space in a fixed area.
About rellocatable code, relative jumps of more than 120 bytes are not bad, and if required larger can use trampolines (that are just another JR) that you skip (with another JR) in a normal execution (not reached by a condition that required that trampoline).
So we can make good pieces of code to be allocated in stack when required to be visible from any slot/page/segment combination (like ISR) or for meta-programming.
Don't you have an account yet? Become an MSX-friend and register an account!