I've been thinking about the easier way to put relocatable code in POKEable DATA.
Page relocatable code has several advantages:
- No problems with using the HI and LOW bytes of relocatable addresses.
- There are tools that can assemble/compile to it, using the Digital Research PRL format for example.
- Also, it's easy to create with other tools, by doing two assemblies with the ORG 256 bytes apart and checking the differences.
The only disadvantage I can think of is a loss of up to 255 bytes in the worst case.
The PRL format marks the addresses that need relocation with a bit map. One simple and readable way to do the same with DATA is to put a mark in the bytes.
This is a way to do it:
10 REM Page relocatable machine code
20 SYMBOL AFTER 256
30 READ size
40 REM Reserve space for the code,
50 REM aligned to 256 byte page.
60 h = HIMEM - size
70 page = INT(h / 256)
80 h = page * 256
90 REM PRL start is at &100
100 REM so substract one page
110 reloc = page - 1
120 MEMORY h - 1
130 FOR i = 0 TO size - 1
140 READ code$
150 IF INSTR(code$, "*") = 1 THEN c = VAL("&" + MID$(code$, 2)) + reloc : ELSE c = VAL("&" + code$)
160 REM PRINT HEX$(c, 2); " ";
170 POKE h + i, c
180 NEXT
500 CALL h
900 REM Relocatable code:
910 REM First data is code length in decimal
920 REM Then the code in hex, prefixed
930 REM with "*" in relocate positions
1000 DATA 28
1010 DATA 16,FF,CD,0C,*01,15,7A,B7,C2,02,*01,C9,21,00,C0,01
1020 DATA 00,40,7A,77,23,0B,78,B1,C2,12,*01,C9
This is the source used:
; Test filling the Amstrad CPC screen
start:
ld d, 255
again:
call fill_screen
dec d
ld a, d
or a
jp nz, again
ret
fill_screen:
ld hl, 0C000h
ld bc, 04000h
loop:
ld a, d
ld [hl], a
inc hl
dec bc
ld a, b
or c
jp nz, loop
ret
end start
Assemble it with pasmo:
pasmo --prl test.asm test.prl
Now we need a way to generate the Basic DATA from the PRL. This is what I used:
// prl2data
// Generate a Basic program with DATA statements
// from a Digital Research page relocatable PRL file
#include <iostream>
#include <iomanip>
#include <fstream>
#include <string>
using std::cout;
using std::cerr;
using std::dec;
using std::hex;
using std::setfill;
using std::setw;
using std::right;
using std::uppercase;
using std::ifstream;
using std::ofstream;
using std::streampos;
using std::ios_base;
using std::string;
static const int
STARTLINE = 1000, // First line number to generate
INCLINE = 10; // Line number increment
void fail (const string msg)
{
cerr << msg << '\n';
exit(1);
}
int main(int arg, char * * argv)
{
const string infilename = argv[1];
const string outfilename = argv[2];
if (infilename == "" || outfilename == "")
fail("Usage: prldata prlfilename basicfilename");
ifstream infile(infilename, ios_base::in | ios_base::binary);
infile.seekg(0, ios_base::end);
const streampos length = infile.tellg();
cout << "File size: " << length << '\n';
if (length <= 256)
fail("Invalid input file");
infile.seekg(0, ios_base::beg);
unsigned char * const content = new unsigned char [length];
infile.read((char *)content, length);
if (infile.gcount() != length)
fail("Error reading input file");
int codelen = content[1] + 256 * content[2];
cout << "Code size: " << codelen << '\n';
const unsigned char * code = content + 256;
const unsigned char * reldata = content + 256 + codelen;
ofstream outfile(outfilename, ios_base::out | ios_base::trunc);
int linenum = STARTLINE;
outfile << dec << linenum << " DATA " << codelen;
linenum += INCLINE;
int relocations = 0;
for (int i = 0; i < codelen; ++i)
{
if ( (i % 16) == 0)
{
outfile << dec << "\r\n" << linenum << " DATA ";
linenum += INCLINE;
}
else
outfile << ',';
bool isrel = ((reldata[i / 8] ) >> (7 - (i % 8) ) & 1;
if (isrel)
{
outfile << '*';
++relocations;
}
outfile << hex << right <<
setw(2) << setfill('0') << uppercase << int(code[i]);
}
outfile << "\r\n";
outfile.close();
cout << "Relocations: " << relocations << '\n';
}
// End
(If compiling in windows you'll probaly need to delete the \r codes)
Compile it:
g++ -o prl2data prl2data.cxx
And use it:
./prl2data test.prl test.bas
Now we can merge test.bas with the Basic from above, and that's all.