ilo-vm/source/ilo-68k-mac.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");
}