<< Previous Message Main Index Next Message >>
<< Previous Message in Thread This Month Next Message in Thread >>
Date   : Fri, 26 Jan 1996 13:25:59 +0000 (GMT)
From   : jkb@...
Subject: Re: Would this work?

Steven Flintham wrote:

[...]
>jump to the language entry point. Instead of making the emulation good
>enough to run the BBC OS, I would trap all jumps to code above &BFFF
>and implement the operating system routines required (e.g. OSWRCH,
>OSFILE etc) in C. Would this be sufficient to get BASIC working
>properly?

No. The OS is more than a collection of OSWRCH type calls. However you don't
have to emulate all the hardware to get the OS to work - far from it. It's
possible to emulate only the 6502 and still get the OS+BASIC working. The
method I used for this, during early development stages, was to add an extra
opcode (idea taken from an Apple emulator converted to the beeb by Ian
Stephenson). My opcode for D4 (normall unimplemented) simply called a
function
"unix_call()" instead of doing a nop.

The unix_call() function took the first byte after the D4 opcode as it's
operation. Thus:

void unix_call() {
    byte op;
    extern int debug;

    PC += 2;
    switch (op = readb(PC - 1)) {
    case 0x00:
        debug = 0;
        break;
    case 0x01:
        debug = 1;
        break;
    case 0x66: {
        int fd = open("data/new.bbc", O_RDWR | O_TRUNC | O_CREAT, 0666);
        write(fd, mem, 65536); 
        close(fd);
    }
    case 0xdd:
        osfile();
        break;
    case 0x1e:
        osfsc();
        break;
    case 0xee:
        /* oswrch */
        write_char(A);
        break;
    case 0xe0:
        /* osrdch */
        A = read_char();
        if (A == '\n')
            A = '\r';
        break;
    case 0xf1:
        /* osword */
        osword();
        break;
    case 0xfe:
        PC = readw(0x206);
        break;
    case 0xff:
        writew(0xfd, readw(SP + 0x102));
        A  = readb(0xfc);
        PC = readw(0x202);
        printf("0x%04x -> 0xfd, 0x%02x -> A, 0x%04x -> PC",
               readw(0xfd), A, PC);
        break;
    default:
        printf("Unknown unix_call %d\n", op);
        break;
    }

This also allows for useful things such as turning debugging on and off from
within the emulator, which is also very useful during development. Ie I'd do
"!&900=&006001D4:CALL &900".

Hooks were then added (once more, exact locations stolen from Ian Stephenson)
in the memory setup code:

    /* osfsc */
    mem[0xf1b1] = 0xd4;
    mem[0xf1b2] = 0x1e;
    mem[0xf1b3] = 0x60;

    /* osfile */
    mem[0xf27d] = 0xd4;
    mem[0xf27e] = 0xdd;
    mem[0xf27f] = 0x60;
    
    /* oswrch */
    mem[0xe0a4] = 0xd4;
    mem[0xe0a5] = 0xee;
    mem[0xe0a6] = 0x60;
    /* osrdch */
    mem[0xdec5] = 0xd4;
    mem[0xdec6] = 0xe0;
    mem[0xdec7] = 0x60;

    /* osbyte
     * mem[0xe772] = 0xd4;
     * mem[0xe773] = 0xf4;
     * mem[0xe774] = 0x60;
     */

    /* osword
     * mem[0xe7eb] = 0xd4;
     * mem[0xe7ec] = 0xf1;
     * mem[0xe7ed] = 0x60;
     */

    /* irq1
     * mem[0xdc93] = 0xd4;
     * mem[0xdc94] = 0xfe;
     * mem[0xdc95] = 0x60;
     */

    /* irq2
     * mem[0xde89] = 0xd4;
     * mem[0xde8a] = 0xff;
     * mem[0xde8b] = 0x40;
     */

    /* interrupt address
     * mem[0xfffe] = 0x02;
     * mem[0xffff] = 0xb4;
     */

I can't remember what was needed and what wasn't - it appears I was commenting
out the traps as the emulation progressed in complexity.

Of the things to trap - the most important are ofile osword0 (fgets),
oswrch()
and osrdch(). The code for handling such things needs to use the A, X and Y
registers in the same way the OS would expect them. So osword 0 for
instance A is the osword number (0) and X+Y*256 gives the memory address to
look up the rest of the data.

Sorry this mail is so long winded. Anyway, good luck.

	James

<< Previous Message Main Index Next Message >>
<< Previous Message in Thread This Month Next Message in Thread >>