Following a simple approach just place your code
- on a C64 somewhere between $C000 and $CFFF, this RAM area is unused by BASIC and always visible to the CPU
- on a C128 somewhere between $1300 and $17FF, this RAM area is unused by BASIC and visible to the CPU in Banks 0 and 15 (but not 1)
If you want to go under ROM, on both systems, C64 and C128 you would still need at least a stub that is visible when the jump vector is called. Since this is usually done by Kernal or BASIC and since the normal target of the jump vector goes into the Kernal you can assume that
- on a C64, at least Kernal is banked in
- on a C128, that you have Bank 15 enabled (RAM from Bank 0 until $3FFF, above that all ROM and I/O)
So, a natural place to put your stub would be
- on a C64 somewhere between $C000 and $CFFF
- on a C128 somewhere between $1300 and $17FF
there are also some other usable holes in the memory map like the cassette buffer, but at least on the C64 this is also a frequent place for putting sprites or machine code. Moreover, data gets erased there after a datasette operation.
The safest part probably is towards the end of this memory area, but for $C000 and $CFFF some people place the screen memory to $CC00-$CFE8 when setting the VIC to use the highest 16K.
Moreover, if you place only a stub there and hide the larger parts of your code under ROM, the safest place is probably
- on a C64 under the char ROM/IO-area $D000-$DFFF, which is one of the least used memory areas - for a reason: if your code needs to access VIC registers or the color ROM, being in this area is a big disadvantage since you need bank switching code from outside to access this area. In this case, the better place is under the Kernal ROM, but even this could be overwritten if somebody puts a bitmap there. The area under the BASIC ROM is more often used by programs, for example cc65 compiled programs use this area at default setting
- on a C128 I would recommend to shorten the BASIC code area a bit via pointer $39/$3A and then put the code beneath the Kernal somewhere between $E000 and $FEFF.
For pure BASIC programs this approach would be safe, even for those programs placing sprites into the cassette buffer and putting some machine code to the beginning of $C000 (on a C128 that would be $1300 respectively)
On the other hand, there is always a risk of a conflict with another program. A bitmap or screen placed on the page with your code immediately kills it and of course, somebody could have a similar idea of using the end of a memory area to place their code. Some BASIC extensions offer two memory areas, asking if they want to be installed in memory area 1 or memory area 2 at set up. This would be a way to go: a normal BASIC user just uses the default setting and somebody using exotic memory areas would get the possibility to select the memory area for installation that does not interfere with their code and data.