1 line
No EOL
5.5 KiB
C
1 line
No EOL
5.5 KiB
C
/* ilo for System 6 / Mac 68k
|
|
Copyright (c) 2022, Charles Childers
|
|
|
|
Deriving from the ilo for MS-DOS, this makes use of
|
|
an internally segmented memory model.
|
|
|
|
The 68k CPU is big endian. Since the ilo images and
|
|
blocks are stored in little endian a fix() function
|
|
has been written and is used to convert between the
|
|
formats as needed.
|
|
|
|
As with all ilo systems, this needs an ilo.rom and
|
|
ilo.blocks. It's likely to crash if these are not
|
|
present.
|
|
|
|
I'm building this using Think C 5.0.2, using the ANSI
|
|
library. It's not tested with any other compiler on
|
|
68k.
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
|
|
#define SLICES 8
|
|
#define SLICESIZE 8192
|
|
|
|
long ip, sp, rp, data[32], address[256];
|
|
long *memory[SLICES];
|
|
|
|
#define TOS data[sp]
|
|
#define NOS data[sp-1]
|
|
#define TORS address[rp]
|
|
|
|
unsigned long fix(unsigned long v) {
|
|
return (((v & 0x000000FF) << 24)|
|
|
((v & 0x0000FF00) << 8) |
|
|
((v & 0x00FF0000) >> 8) |
|
|
((v & 0xFF000000) >> 24));
|
|
}
|
|
|
|
long pop() {
|
|
sp--;
|
|
return data[sp + 1];
|
|
}
|
|
|
|
void push(long value) {
|
|
sp++;
|
|
data[sp] = value;
|
|
}
|
|
|
|
void store(long a, long v) {
|
|
long slice = a / SLICESIZE;
|
|
long actual = a - (slice * SLICESIZE);
|
|
memory[slice][actual] = v;
|
|
}
|
|
|
|
long fetch(long a) {
|
|
long slice = a / SLICESIZE;
|
|
long actual = a - (slice * SLICESIZE);
|
|
return memory[slice][actual];
|
|
}
|
|
|
|
void prepare_vm() {
|
|
for (ip = 0; ip < 32; ip++) data[ip] = 0;
|
|
for (ip = 0; ip < 128; ip++) address[ip] = 0;
|
|
ip = sp = rp = 0;
|
|
}
|
|
|
|
void load_image() {
|
|
FILE *fp;
|
|
long x, y, z;
|
|
fp = fopen("ilo.rom", "rb");
|
|
for (y = 0; y < 65536; y++) {
|
|
x = 0;
|
|
fread(&x, 4, 1, fp);
|
|
store(y, fix(x));
|
|
}
|
|
fclose(fp);
|
|
prepare_vm();
|
|
}
|
|
|
|
void save_image() {
|
|
FILE *fp;
|
|
long i, x;
|
|
fp = fopen("ilo.rom", "wb");
|
|
for (i = 0; i < 65536; i++) {
|
|
x = fix(fetch(i));
|
|
fwrite(&x, 4, 1, fp);
|
|
}
|
|
fclose(fp);
|
|
}
|
|
|
|
void read_block() {
|
|
FILE *f;
|
|
long block, buffer, x, c;
|
|
buffer = pop();
|
|
block = pop();
|
|
f = fopen("ilo.blocks", "r+b");
|
|
fseek(f, 4096 * block, SEEK_SET);
|
|
for (x = 0; x < 1024; x++) {
|
|
c = 0;
|
|
fread(&c, 4, 1, f);
|
|
store(buffer + x, fix(c));
|
|
}
|
|
fclose(f);
|
|
}
|
|
|
|
void write_block() {
|
|
FILE *f;
|
|
long block, buffer, x, c;
|
|
buffer = pop();
|
|
block = pop();
|
|
f = fopen("ilo.blocks", "r+b");
|
|
fseek(f, 4096 * block, SEEK_SET);
|
|
for (x = 0; x < 1024; x++) {
|
|
c = fix(fetch(buffer + x));
|
|
fwrite(&c, 4, 1, f);
|
|
}
|
|
fclose(f);
|
|
}
|
|
|
|
void process(long o) {
|
|
long a, b, target, flag;
|
|
long src, dest, len;
|
|
switch (o) {
|
|
case 0: break;
|
|
case 1: ip++; push(fetch(ip)); break;
|
|
case 2: push(TOS); break;
|
|
case 3: data[sp] = 0; sp--; break;
|
|
case 4: a = TOS; TOS = NOS; NOS = a; break;
|
|
case 5: rp++; TORS = pop(); break;
|
|
case 6: push(TORS); rp--; break;
|
|
case 7: ip = pop() - 1; break;
|
|
case 8: rp++; TORS = ip; ip = pop() - 1; break;
|
|
case 9: target = pop(); flag = pop();
|
|
if (flag != 0) { rp++; TORS = ip; ip = target - 1; }
|
|
break;
|
|
case 10: target = pop(); flag = pop();
|
|
if (flag != 0) ip = target - 1; break;
|
|
case 11: ip = TORS; rp--; break;
|
|
case 12: NOS = (NOS == TOS) ? -1 : 0; sp--; break;
|
|
case 13: NOS = (NOS != TOS) ? -1 : 0; sp--; break;
|
|
case 14: NOS = (NOS < TOS) ? -1 : 0; sp--; break;
|
|
case 15: NOS = (NOS > TOS) ? -1 : 0; sp--; break;
|
|
case 16: TOS = fetch(TOS); break;
|
|
case 17: store(TOS, NOS); sp--; sp--; break;
|
|
case 18: NOS += TOS; sp--; break;
|
|
case 19: NOS -= TOS; sp--; break;
|
|
case 20: NOS *= TOS; sp--; break;
|
|
case 21: a = TOS; b = NOS; TOS = b / a; NOS = b % a; break;
|
|
case 22: NOS = TOS & NOS; sp--; break;
|
|
case 23: NOS = TOS | NOS; sp--; break;
|
|
case 24: NOS = TOS ^ NOS; sp--; break;
|
|
case 25: NOS = NOS << TOS; sp--; break;
|
|
case 26: NOS = NOS >> TOS; sp--; break;
|
|
case 27: len = pop(); dest = pop();
|
|
src = pop(); flag = -1;
|
|
while (len) {
|
|
if (fetch(dest) != fetch(src)) flag = 0;
|
|
len -= 1; src += 1; dest += 1;
|
|
}; push(flag); break;
|
|
case 28: len = pop(); dest = pop();
|
|
src = pop();
|
|
while (len) {
|
|
store(dest, fetch(src));
|
|
len -= 1; src += 1; dest += 1;
|
|
}; break;
|
|
case 29: switch (pop()) {
|
|
case 0: putc(pop(), stdout); break;
|
|
case 1: push(getc(stdin)); break;
|
|
case 2: read_block(); break;
|
|
case 3: write_block(); break;
|
|
case 4: save_image(); break;
|
|
case 5: load_image(); ip = -1; break;
|
|
case 6: ip = 65536; break;
|
|
case 7: push(sp); push(rp); break;
|
|
default: break;
|
|
} break;
|
|
default: break;
|
|
}
|
|
}
|
|
|
|
void execute(long address) {
|
|
long opcode, o;
|
|
ip = address;
|
|
while (ip < 65536) {
|
|
opcode = fetch(ip);
|
|
switch (opcode) {
|
|
case 0: break;
|
|
case 1793: ip = fetch(ip + 1) - 1; break;
|
|
case 2049: process(1); process(8); break;
|
|
case 67502597: push(NOS); break;
|
|
default:
|
|
o = opcode & 0xFF; if (o != 0) process(o);
|
|
o = (opcode >> 8) & 0xFF; if (o != 0) process(o);
|
|
o = (opcode >> 16) & 0xFF; if (o != 0) process(o);
|
|
o = (opcode >> 24) & 0xFF; if (o != 0) process(o);
|
|
break;
|
|
}
|
|
ip++;
|
|
}
|
|
}
|
|
|
|
void main(long argc, char **argv) {
|
|
long i;
|
|
for (i = 0; i < SLICES; i++)
|
|
memory[i] = malloc(SLICESIZE * sizeof(long));
|
|
load_image();
|
|
execute(0);
|
|
for (i = 0; i < SLICES; i++)
|
|
free(memory[i]);
|
|
for (i = 1; sp >= i; i++) printf(" %d", data[i]);
|
|
printf("\n");
|
|
}
|