Good idea.
But would it work for larger M/C programs? That's partially how TASWORD works, it has a function dispatch table for the user-initiated functions. It then JPs to the function. However, for the many M/C subroutines it still uses regular CALLs without any table
The RELOCATOR program that Greg provided a link for suggests using "guard bytes" around the data sections
Relocatable Machine Code
Re: Relocatable Machine Code
I can see why Greg said the listing was illegible. On the other hand, Xav's type-in of it is excellent. I'm 90% certain it exactly matches the newsletter
I've started working through the code of RELOCATOR. A few things caught my attention
* JP (HL)
* LD HL,(801EH)
But neither of those lines are executed in the test run
Then there is this JP without a label:
Code: Select all
JP NC,4317H
Code: Select all
9199 REM ---------------------
Code: Select all
0/9270
Re: Relocatable Machine Code
Code: Select all
#RELOCATOR START ADDR:16514 LENGTH:452 11 MAY 85
1 REM [HEX:\
ED,4B,3F,40,C5,ED,4B,41,\
40,C5,ED,4B,45,40,C5,2A,\
3F,40,09,2B,22,43,40,3A,\
3E,40,D1,E1,C1,C5,E5,D5,\
AF,ED,42,22,3C,40,CA,40,\
42,C1,D1,E1,E5,D5,C5,D2,\
B8,40,ED,B0,18,08,09,2B,\
EB,09,2B,EB,ED,B8,3A,3E,\
40,FE,28,C2,40,42,C1,E1,\
E5,C5,0B,7E,FE,DD,CA,D7,\
40,FE,FD,20,48,23,0B,7E,\
FE,CB,CA,2C,42,FE,21,CA,\
2C,42,FE,22,CA,F2,41,FE,\
2A,CA,F2,41,FE,36,CA,2C,\
42,FE,09,28,25,FE,19,28,\
21,FE,29,28,1D,FE,39,28,\
19,FE,23,28,15,FE,2B,28,\
11,FE,E1,28,0D,FE,E3,28,\
09,FE,E5,28,05,FE,F9,C2,\
DE,41,C3,CB,41,FE,ED,28,\
08,FE,CB,CA,DE,41,C3,4A,\
41,23,0B,7E,FE,4B,28,15,\
FE,5B,28,11,FE,7B,28,0D,\
FE,43,28,09,FE,53,28,05,\
FE,73,C2,CB,41,C3,F2,41,\
FE,3F,DA,57,41,FE,C1,D2,\
57,41,C3,CB,41,FE,00,28,\
14,FE,02,28,10,FE,12,28,\
0C,FE,08,28,08,FE,0A,28,\
04,FE,1A,20,03,C3,CB,41,\
E6,0F,FE,02,CA,F2,41,FE,\
0A,CA,F2,41,FE,06,CA,DE,\
41,FE,0E,CA,DE,41,7E,FE,\
3F,D2,9F,41,E6,0F,FE,00,\
CA,DE,41,FE,01,CA,2C,42,\
FE,08,CA,DE,41,7E,FE,C3,\
CA,F2,41,FE,D3,CA,DE,41,\
FE,DB,CA,DE,41,FE,BF,D2,\
B7,41,C3,CB,41,E6,0F,FE,\
04,28,0B,FE,0C,25,07,FE,\
0D,28,03,C3,CB,41,C3,F2,\
41,23,E5,C5,E1,01,01,00,\
AF,ED,42,E5,C1,E1,D2,CD,\
40,C3,40,42,23,23,E5,C5,\
E1,01,02,00,AF,ED,42,E5,\
C1,E1,F2,CD,40,C3,40,42,\
23,E5,5E,23,56,2A,3F,40,\
AF,ED,52,D2,17,42,2A,43,\
40,AF,ED,52,DA,17,42,EB,\
5D,5B,3C,40,19,ED,E1,73,\
23,72,23,1C,03,E1,23,23,\
E5,C5,E1,01,03,00,AF,ED,\
42,E5,C1,E1,D2,FD,40,C3,\
40,42,23,23,23,1C,E9,2A,\
1E,80,23,22,16,40,7E,CD,\
D9,14,CD,A7,0E,C9,E1,E1,\
E1,C9,1B,1B,1B ]
9190 REM ---------------------
9191 REM RELOCATOR INTERFACE
9192 REM EXAMPLE (RELOCATES RELOCATOR ITSELF)
9193 REM START ADDR: 16514
9194 REM DEST ADDR: 28000
9195 REM BLOCK LENGTH: 452
9196 REM TYPE: CODE
9197 REM RELOCATOR ENTRY: 16514
9199 REM ---------------------
9200 POKE 16448,INT(16514/256)
9210 POKE 16447,16514-256*INT(16514/256)
9220 POKE 16450,INT(28000/256)
9230 POKE 16449,28000-256*INT (28000/256)
9240 POKE 16454,INT(452/256)
9250 POKE 16453,452-256*INT(452/256)
9255 POKE 16446,40
9260 RAND USR 16514
9270 PAUSE 100
Xavier ...on the Facebook groupe : "Zx81 France"(fr)
Re: Relocatable Machine Code
RELOCATOR works partially -- it moves the code, but does not appear to change the addresses. I'm going through it to figure out how it works
* The M/C variables are stored in PRBUFF
* It first moves the code to the destination address
* can either TRANSFER (move) the code, or RELOCATE it. Line 9255 has the POKE for this
* after moving the code, it exits, unless RELOCATE byte is set, then it does something and finally uses JP (HL) to run the moved copy of the code
Variables with labels added
The code referencing 801EH and making the two ROM calls appears to be orphan code
The real work of changing the addresses seems to be done where the "DATA" bytes (undocumented opcode) is. This is probably why it doesn't actually change the addresses. The preceding opcodes don't make sense to me either. LD E,E? LD B,B?
Typos due to illegible hex codes?
* The M/C variables are stored in PRBUFF
* It first moves the code to the destination address
* can either TRANSFER (move) the code, or RELOCATE it. Line 9255 has the POKE for this
* after moving the code, it exits, unless RELOCATE byte is set, then it does something and finally uses JP (HL) to run the moved copy of the code
Variables with labels added
Code: Select all
OFFSET equ $403C ;PRBUFF
CODE_OR_RELOC equ $403E ;PRBUFF+2 one byte
START_ADDR equ $403F ;PRBUFF+3
DEST_ADDR equ $4041 ;PRBUFF+5
END_ADDR equ $4043 ;PRBUFF+7
BLOCK_LEN equ $4045 ;PRBUFF+9
The real work of changing the addresses seems to be done where the "DATA" bytes (undocumented opcode) is. This is probably why it doesn't actually change the addresses. The preceding opcodes don't make sense to me either. LD E,E? LD B,B?
Typos due to illegible hex codes?
Code: Select all
5D LD E,L
5B LD E,E
3C INC A
40 LD B,B
19 ADD HL,DE
ED E1 DB 0EDH, 0E1H ; UNDOCUMENTED 8 T-STATE NOP
Re: Relocatable Machine Code
Try this...
ED5B3C40. LD DE(403C)
19 ADD HL,DE
EB EX DE,HL
E1 POP HL
ED5B3C40. LD DE(403C)
19 ADD HL,DE
EB EX DE,HL
E1 POP HL
Re: Relocatable Machine Code
that change makes eminently logical sense. Still no workee, unfortunately
I've been looking at the 4K Delphic Toolkit, which was advertised as being relocatable, and indeed it seems to work
What i've found so far is:
* Instead of a straight (non-relocatable) CALL it uses JUMPHL, which is explained in the Hoffman article in the first post. This means there are no vector tables or function lists to patch
* It makes extensive use of ROM calls, which are of course at known positions and so do not need to be relocatable. By my count there are 37 different ROM routines it uses
* The menu text and messages are all inline with the code, so there is no need for string pointers or string tables. The alternate registers (via EXX) contain the printing routine address in HL. So EXX followed by CALL JUMPHL will invoke the "Print Strings" code. This reads the string data and copies it to the screen. When the end-of-text marker is found it continues with code, treating the next byte as an executable instruction
The code is a bit awkward, but now that i'm wrapping my head around it, it seems logical
when using an assembler it is easy to automatically get the offsets. For example:
The subroutine offsets are added to the base address (the address of the TOOLKIT). When you invoke USR, this address is passed to your machine code in BC. The first thing the Toolkit does on running is copy the base address of the Toolkit (USR address) to mem-5 (within the MEMBOT System Variable) and thereafter uses HL=BASE+OFFSET before CALL JUMPHL
I've been looking at the 4K Delphic Toolkit, which was advertised as being relocatable, and indeed it seems to work
- Load the tape of "TOOLKIT" and it's ready to run at USR 16514
- Copy to 8K RAM block (such as the Hunter SRAM board) and then run at USR 8192
- or anywhere else, such as above RAMTOP
What i've found so far is:
* Instead of a straight (non-relocatable) CALL it uses JUMPHL, which is explained in the Hoffman article in the first post. This means there are no vector tables or function lists to patch
* It makes extensive use of ROM calls, which are of course at known positions and so do not need to be relocatable. By my count there are 37 different ROM routines it uses
* The menu text and messages are all inline with the code, so there is no need for string pointers or string tables. The alternate registers (via EXX) contain the printing routine address in HL. So EXX followed by CALL JUMPHL will invoke the "Print Strings" code. This reads the string data and copies it to the screen. When the end-of-text marker is found it continues with code, treating the next byte as an executable instruction
The code is a bit awkward, but now that i'm wrapping my head around it, it seems logical
when using an assembler it is easy to automatically get the offsets. For example:
Code: Select all
LD HL,GET_KEY-BASE ;calculate the offset to the GET_KEY routine
ADD HL,BC ;BASE+offset
CALL JUMPHL ;effectively, CALL GET_KEY
- Attachments
-
- P2A-TOOLKIT.asm
- Toolkit analysis
- (61.79 KiB) Downloaded 66 times