News:

Printed Amstrad Addict magazine announced, check it out here!

Main Menu
avatar_NotFound

Page relocatable code in DATA

Started by NotFound, 18:17, 16 July 21

Previous topic - Next topic

0 Members and 1 Guest are viewing this topic.

NotFound

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.

Powered by SMFPacks Menu Editor Mod