Oops, put an old version of SRELC2.DO, here's the one that matches the BA. On Tue, Mar 7, 2023 at 10:43 AM John R. Hogerhuis <jho...@pobox.com> wrote:
> George, there are multiple ways to do this, which I have been doing a deep > dive on recently for my "Supercharged BASIC" book in progress. Some > background first, but stay till the end, I have what should be a perfect > solution for you. > > First, there is the RELJMP.PDF that you may or may not have. Attached. You > need a 4 byte hidey hole. Probably somewhere in the RST 7 table would work. > Clobbers HL, DE, flags. Can do conditional/unconditional jumps. It's a a > "Call" in form but really it's a relative jump. You cannot use it directly > to do a subroutine. > > I think the real downside here is all the pushing and popping. Imagine a > loop that just copies bytes from one place to another. You probably need HL > and DE, plus the flags preserved across the jump, minimum. So you're going > to have to do all that. Every jump. > > Second, at 12777 in the Model 100 is the code XTHL / PCHL. This code > simply answers the question "Where Am I?" You can use this as a building > block to do a relative jump. Steve Adolph and I went down this rabbit hole > and it seems pretty expensive at least if you preserve registers. But it > also works. > > What came up from this collaboration is what I think is the perfect > technology for more BASIC embedded ML that requires branching. By the way, > there's a lot you can do to augment BASIC code without branching. If you > can, short sequential routines that optimize your code is the way to go. > > Anyway, the perfect solution... basically this idea is a 2-byte relative > branch or call encoded as data following a RST 7 / 197 instruction: > > RST 7 / .db 197 / opcode / signed 8-bit offset > > In the RST 7 / .db 197 table we put a small routine that rewrites the > whole 4 bytes as your opcode,the 8-bit signed offset converted to a fixed > address relative to the final position of the opcode, followed by a NOP. > > opcode / 2-byte target / nop > > Advantages? You can do jumps, calls, conditionals no limitations on the > opcode. It's fast, there's overhead the first time to rewrite the jump, but > after that it's at max speed, every iteration. Well, other than the NOP > that pads out to the 4 bytes. > > Disadvantages: it rewrites code. You cannot use this in literal strings > since it will corrupt your tokenized program text with control characters, > " and DEL. But all characters are allowed in dynamic strings... So > A$="BLAH" is no but A$="BLAH"+"" is OK. > > It might not be the best tech for a single branch. RELJMP, or CALL 12777 > may be best. But if you're looping over data, I think you're going to win > this way. > > I've attached a sample program with the RST7 self-relocator installer and > a test program that shows BASIC-only versus an ML CALL subroutine to print > the full M100 character set. > > The CALL string program does this: > > mvi a,33 > rst 4 > inr a > rz > mvi h,126 > inr h > cmp h > rst 7 / .db 197 / .db jz / .db -5 > rst 7 /.db 197 / .db jmp / .db -11 > > > My self-relocator installer source... note that this is specially crafted > code that is embedded in a BASIC literal string, so it doesn't use the full > 8085 instruction set. This means I can write it in a string without any > conversions, special construction +CHR$( or POKEs. If you list SRELC2.BA > you will see what I mean. > > rst 7 / index / rel-offset / opcode > > gets replaced with > > opcode / address / nop > > > ; store FIXUP @ ERRLIN (64415) - "hook 99" = postbyte 197 > ; Use CALL to the start of the string. > ; HL contains the address of the string body > > push h > lxi h,64415 > xthl ; stack the hook slot for later, hl gets the installer base > mvi a,-18 ; calculate the address of the rst 7 handler based on length of > installer > cma > mov e,a > xra a > mov d,a > call 0x21AC ; dad d / ret > ; now hl has the rst 7 handler to install > pop d ; get back the 64415 slot address > shli ; store the vector > ret > > 21 bytes > > > rst 7 ndx opcode rel-offset > > xthl ; save-hl, hl gets the return address (points at opcode) > push psw > push d > xchg > lhli ; fetch opcode & rel-offset to hl > xchg ; now opcode & rel-offset in de > dcx h ; now pointing where the jump target goes > push h ; save the jump-target position > dcx h ; hl points at start of instruction > mov m,e ; place jump/call opcode > mov a,d ; sign extend the 8-bit offset > mov e,a > add a > sbb a ; > mov d,a ; de now has sign-extended offset > mov a,e > ; dad d: hl = hl + de... now has the computed jump target > call 0x21AC ; main rom has DAD D/ RET. We need it since DAD D too low for > literal string > pop d ; retrieve the jump target position > shli ; instruction is complete, except for the NUL > xchg ; back into h > inx h > inx h > xra a ; nop code > mov m,a ; set nop > dcx h ; at nop, so 3 decrements to again point at opcode > dcx h > dcx h > pop d ; restore caller's de > pop psw ; restore caller's psw > xthl ; stack the patched-up instruction, restore caller's hl > ret ; invoke the patched-in jump/call > > > -- John. > > > > On Tue, Mar 7, 2023 at 4:45 AM grima...@gmail.com <grima...@gmail.com> > wrote: > >> Hi all, >> >> One of the things I struggled with in trying to build 8085 subroutines >> for BASIC program was the lack of a relative jump command. >> >> So far, the approach I have taken to embed ML programs into BASIC has >> been to poke them into arrays, thus allowing BASIC to manage the routines >> within memory. However, I then have to use BASIC to get VARPTR of the array >> and update all JMP locations before calling the subroutine, just in case >> BASIC has moved the array. >> >> The other thought I had was, can I have the ML program modify itself when >> it runs? I was racking my brain reading the Inten 8085 documentation, and >> as far as I can tell there is no easy way to read the program counter into >> any of the register pairs, which I would want to do in order to calculate >> offsets and update JMP locations. >> >> However I had one thought. It seems that both CALL and RST instructions >> push the program counter onto the stack. Is it possible to leverage either >> of these and then RET to return to my program, and then immediately >> decrement the stack pointer and to retrieve the previous value. >> >> Then I can use that value to calculate all the offsets and update the JMP >> locations. >> >> Does anyone have any constructive input here? >> >> -George >> >
SRELC2.DO
Description: Binary data