2024-05-23 15:32:54 +02:00
|
|
|
/***************************************************************
|
|
|
|
crc's _ _ ___ _ __
|
|
|
|
_ __ ___ _ _| | |_ / (_) | ___ / /_ __
|
|
|
|
| '_ ` _ \| | | | | __| / /| | |/ _ \ / /\ \/ /
|
|
|
|
| | | | | | |_| | | |_ / / | | | (_) / / > <
|
|
|
|
|_| |_| |_|\__,_|_|\__/_/ |_|_|\___/_/ /_/\_\
|
|
|
|
(c) charles childers
|
|
|
|
|
2024-07-04 19:41:05 +02:00
|
|
|
This is a special implementation of my ilo computer, with
|
|
|
|
multiple copies of ilo running under a single host process.
|
|
|
|
Using this you can quickly switch between ilo instances.
|
|
|
|
|
|
|
|
User Interface
|
|
|
|
|
|
|
|
This implementation runs on X11 and provides a visual display
|
|
|
|
of the terminal with a set of buttons below the display. These
|
|
|
|
can be used to switch between ilo instances. Closing the window
|
|
|
|
will terminate the system.
|
|
|
|
|
|
|
|
Keyboard Shortcuts
|
|
|
|
|
|
|
|
+--------+-----------------------------+
|
|
|
|
| CTRL+n | Switch to the next ilo |
|
|
|
|
| CTRL+p | Switch to the previous ilo |
|
|
|
|
| CTRL+c | Restart the current ilo |
|
|
|
|
| CTRL+a | Shut down the system |
|
|
|
|
+--------+-----------------------------+
|
|
|
|
|
|
|
|
Additional Functionality
|
|
|
|
|
|
|
|
This implementation supports the basic Graphica (Level 0) and
|
|
|
|
pointer extensions. These are assigned to I/O devices 12 & 13.
|
|
|
|
|
|
|
|
Notes
|
2024-05-23 15:32:54 +02:00
|
|
|
|
|
|
|
- `bye` will act like `restart` on the current computer
|
|
|
|
- switching can only be done when the system is waiting for
|
|
|
|
input
|
|
|
|
|
2024-07-04 19:41:05 +02:00
|
|
|
Building
|
|
|
|
|
|
|
|
I use this to build it:
|
|
|
|
|
|
|
|
cc -O2 -s `pkg-config --cflags --libs x11` mix.c -o mix
|
|
|
|
|
|
|
|
It'll probably also work with -O3 and might be slightly faster
|
|
|
|
|
2024-05-23 15:32:54 +02:00
|
|
|
**************************************************************/
|
|
|
|
|
2024-07-04 19:41:05 +02:00
|
|
|
/* Configuration ============================================ */
|
|
|
|
|
|
|
|
#define BLOCKS "ilo.blocks" /* default data storage */
|
|
|
|
#define ROM "ilo.rom" /* default ilo rom */
|
|
|
|
#define FONT "ilo.fnt" /* default font */
|
|
|
|
|
|
|
|
#define FONT_H 16 /* font height */
|
|
|
|
#define FONT_W 8 /* font width */
|
|
|
|
|
|
|
|
/* colors are 0xRRGGBB */
|
|
|
|
#define FG 0xFFC000 /* foreground color, amber */
|
|
|
|
#define BG 0x000000 /* background color, black */
|
|
|
|
#define CURSOR 0x663999 /* cursor color, purple */
|
|
|
|
|
|
|
|
#define FW 640 /* terminal width */
|
|
|
|
#define FH 384 /* terminal height */
|
|
|
|
|
|
|
|
#define BUTTON_HEIGHT 30 /* height for button row */
|
|
|
|
|
|
|
|
#define CENTER_WINDOW /* center window on start */
|
|
|
|
|
|
|
|
#define ILOS 3 /* number of instances */
|
|
|
|
char *ButtonLabels[ILOS] = {"Instance 0", "Instance 1",
|
|
|
|
"Instance 2"};
|
|
|
|
|
|
|
|
/* ========================================================== */
|
|
|
|
|
|
|
|
#include <fcntl.h>
|
|
|
|
#include <signal.h>
|
2024-05-23 15:32:54 +02:00
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
2024-07-04 19:41:05 +02:00
|
|
|
#include <string.h>
|
2024-05-23 15:32:54 +02:00
|
|
|
#include <unistd.h>
|
|
|
|
#include <X11/Xlib.h>
|
|
|
|
#include <X11/Xutil.h>
|
|
|
|
|
|
|
|
#define V void
|
|
|
|
#define I int
|
|
|
|
#define C char
|
|
|
|
|
2024-07-04 19:41:05 +02:00
|
|
|
#define DS v->ds /* data stack */
|
|
|
|
#define AS v->as /* address stack pointer */
|
|
|
|
#define SP v->sp /* data stack pointer */
|
|
|
|
#define RP v->rp /* address ("return") stack pointer */
|
|
|
|
#define IP v->ip /* instruction pointer */
|
|
|
|
#define M v->m /* memory */
|
|
|
|
#define T DS[SP] /* top of data stack */
|
|
|
|
#define N DS[SP-1] /* next on data stack */
|
|
|
|
#define R AS[RP] /* top of address stack */
|
|
|
|
#define A v->a /* internal use by instructions */
|
|
|
|
#define B v->b /* internal use by instructions */
|
|
|
|
#define S v->s /* internal use by instructions */
|
|
|
|
#define D v->d /* internal use by instructions */
|
|
|
|
#define L v->l /* internal use by instructions */
|
|
|
|
#define F v->f /* used to track block file pointer */
|
|
|
|
#define RESTART iof(v) /* restart ilo instance on error */
|
|
|
|
#define OK v->ok /* ok to process further instructions? */
|
|
|
|
|
|
|
|
#define FAILED if (F == -1)
|
|
|
|
|
|
|
|
#define CTRL_A 1 /* CTRL+a, shut down mult/ilo/x */
|
|
|
|
#define CTRL_C 3 /* CTRL+c, restart instance */
|
|
|
|
#define CTRL_N 14 /* CTRL+n, switch to next instance */
|
|
|
|
#define CTRL_P 16 /* CTRL+p, switch to prior instance */
|
|
|
|
|
|
|
|
#define ROWS ((FH/FONT_H) - 1)
|
|
|
|
#define COLS ((FW/FONT_W) - 1)
|
2024-05-23 15:32:54 +02:00
|
|
|
|
|
|
|
typedef struct ilo ilo;
|
|
|
|
struct ilo {
|
2024-07-04 19:41:05 +02:00
|
|
|
I ip, /* instruction pointer */
|
|
|
|
sp, /* data stack pointer */
|
|
|
|
rp, /* address stack pointer */
|
|
|
|
ds[33], /* data stack */
|
|
|
|
as[257], /* address stack */
|
|
|
|
m[65536]; /* memory */
|
|
|
|
C *blocks, /* name of block file (ilo.blocks) */
|
|
|
|
*rom; /* name of image (ilo.rom) */
|
2024-05-23 15:32:54 +02:00
|
|
|
I a, b, f, s, d, l, ok;
|
|
|
|
C i[1];
|
|
|
|
};
|
2024-07-04 19:41:05 +02:00
|
|
|
struct ilo systems[ILOS]; /* ilo session data */
|
|
|
|
I cur; /* track current session */
|
2024-05-23 15:32:54 +02:00
|
|
|
|
2024-07-04 19:41:05 +02:00
|
|
|
#define BUTTON_WIDTH (FW / ILOS)
|
|
|
|
#define WINDOW_HEIGHT (FH + BUTTON_HEIGHT)
|
|
|
|
#define WINDOW_WIDTH (FW)
|
2024-05-23 15:32:54 +02:00
|
|
|
|
|
|
|
I frame[(FW * FH)/32]; /* frame buffer for display */
|
|
|
|
I font[4096]; /* font bitmap */
|
|
|
|
I tx, ty; /* text cursor location */
|
|
|
|
|
|
|
|
/* variables for Arland's DEC subset */
|
|
|
|
I acc[32], acc_i = 0, ground = 0, on = 0;
|
|
|
|
|
|
|
|
/* variables for X11 stuff */
|
|
|
|
Display *disp;
|
|
|
|
Window win;
|
|
|
|
GC gc;
|
|
|
|
XEvent event;
|
2024-07-04 19:41:05 +02:00
|
|
|
Window Buttons[ILOS];
|
|
|
|
|
|
|
|
V update_labels() {
|
|
|
|
unsigned long white;
|
|
|
|
white = WhitePixel(disp, DefaultScreen(disp));
|
|
|
|
XSetForeground(disp, gc, white);
|
|
|
|
for (I i = 0; i < ILOS; i++) {
|
|
|
|
XClearWindow(disp, Buttons[i]);
|
|
|
|
XDrawString(disp, Buttons[i], gc, 20, 20, ButtonLabels[i],
|
|
|
|
strlen(ButtonLabels[i]));
|
|
|
|
if (cur == i) {
|
|
|
|
XDrawString(disp, Buttons[i], gc, 10, 20, "*", 1);
|
|
|
|
}
|
|
|
|
// XSetForeground(disp, gc, white);
|
|
|
|
XDrawLine(disp, Buttons[i], gc, 0, 0, FW, 0);
|
|
|
|
}
|
|
|
|
}
|
2024-05-23 15:32:54 +02:00
|
|
|
|
|
|
|
V dputc(I);
|
2024-07-04 19:41:05 +02:00
|
|
|
V term_putc(I c);
|
2024-05-23 15:32:54 +02:00
|
|
|
V redraw();
|
|
|
|
|
|
|
|
V iof(ilo *);
|
|
|
|
|
2024-07-04 19:41:05 +02:00
|
|
|
V p(C *s) { while(*s) dputc(*s++); }
|
|
|
|
V e(ilo *v, C *s) { p("E:"); p(s); p("\n"); OK = 1; RESTART; }
|
2024-05-23 15:32:54 +02:00
|
|
|
V dso(ilo *v) { if ((SP + 1) > 32) { e(v, "DSO"); } }
|
|
|
|
V dsu(ilo *v) { if ((SP - 1) < 0) { e(v, "DSU"); } }
|
|
|
|
V rso(ilo *v) { if ((RP + 1) > 256) { e(v, "RSO"); } }
|
|
|
|
V rsu(ilo *v) { if ((RP - 1) < 0) { e(v, "RSU"); } }
|
|
|
|
V dbz(ilo *v) { if (T == 0) { e(v, "DBZ"); } }
|
|
|
|
V mem(ilo *v) { if (T < 0 || T > 65535) { e(v, "MEM"); } }
|
2024-07-04 19:41:05 +02:00
|
|
|
V uli(ilo *v) { e(v, "ULI"); }
|
|
|
|
V ulf(ilo *v) { e(v, "ULF"); }
|
|
|
|
V usi(ilo *v) { e(v, "URI"); }
|
|
|
|
V urb(ilo *v) { e(v, "URB"); }
|
|
|
|
V uwb(ilo *v) { e(v, "UWB"); }
|
2024-05-23 15:32:54 +02:00
|
|
|
|
|
|
|
V push(ilo *v, I n) { dso(v); DS[SP + 1] = n; SP += 1; }
|
|
|
|
I pop(ilo *v) { dsu(v); SP -= 1; return DS[SP + 1]; }
|
|
|
|
|
2024-07-04 19:41:05 +02:00
|
|
|
/* display & terminal emulation ============================= */
|
|
|
|
|
|
|
|
V add_buttons() {
|
|
|
|
for (I i = 0; i < ILOS; i++) {
|
|
|
|
Buttons[i] = XCreateSimpleWindow(disp, win, i*BUTTON_WIDTH,
|
|
|
|
FH, BUTTON_WIDTH,
|
|
|
|
BUTTON_HEIGHT, 1, 0, 0);
|
|
|
|
XSelectInput(disp, Buttons[i],
|
|
|
|
ButtonPressMask | ExposureMask);
|
|
|
|
XMapWindow(disp, Buttons[i]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
V initialize_display() {
|
|
|
|
disp = XOpenDisplay(NULL);
|
|
|
|
win = XCreateSimpleWindow(disp, RootWindow(disp, 0),
|
|
|
|
0, 0, WINDOW_WIDTH, WINDOW_HEIGHT,
|
|
|
|
0, 0x0, 0x0);
|
|
|
|
XSelectInput(disp, win, ExposureMask | KeyPressMask |
|
|
|
|
ButtonPressMask | ButtonReleaseMask);
|
|
|
|
XStoreName(disp, win, "mult/ilo");
|
|
|
|
gc = DefaultGC(disp, DefaultScreen(disp));
|
|
|
|
add_buttons();
|
|
|
|
XMapWindow(disp, win);
|
|
|
|
XFlush(disp);
|
|
|
|
}
|
|
|
|
|
|
|
|
V cleanup_display() {
|
|
|
|
XUnmapWindow(disp, win);
|
|
|
|
XDestroyWindow(disp, win);
|
|
|
|
XCloseDisplay(disp);
|
|
|
|
}
|
|
|
|
|
2024-05-23 15:32:54 +02:00
|
|
|
V cursor() {
|
|
|
|
XSetForeground(disp, gc, CURSOR);
|
|
|
|
XFillRectangle(disp, win, gc, tx, ty, FONT_W, FONT_H);
|
|
|
|
XFlush(disp);
|
|
|
|
}
|
|
|
|
|
2024-07-04 19:41:05 +02:00
|
|
|
V sel(I n) { cur = n; }
|
|
|
|
|
|
|
|
I handle_keypress() {
|
|
|
|
C text[255];
|
|
|
|
KeySym key = XLookupKeysym(&event.xkey, 0);
|
|
|
|
XLookupString(&event.xkey, text, 255, &key, 0);
|
|
|
|
if (text[0] == 13) text[0] = 10;
|
|
|
|
if (text[0] != 0) return (I) text[0];
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
V handle_expose() { redraw(); update_labels(); cursor(); }
|
|
|
|
|
|
|
|
I handle_button() {
|
|
|
|
for (I i = 0; i < ILOS; i++) {
|
|
|
|
if (event.xbutton.window == Buttons[i]) { sel(i); }
|
|
|
|
}
|
|
|
|
update_labels();
|
|
|
|
return 32;
|
|
|
|
}
|
|
|
|
|
2024-05-23 15:32:54 +02:00
|
|
|
I wait_key() {
|
2024-07-04 19:41:05 +02:00
|
|
|
I k = 0;
|
|
|
|
while (k == 0) {
|
|
|
|
XNextEvent(disp, &event);
|
|
|
|
if (event.type == KeyPress) { k = handle_keypress(); }
|
|
|
|
if (event.type == Expose) { handle_expose(); }
|
|
|
|
if (event.type == ButtonPress) { k = handle_button(); }
|
|
|
|
}
|
|
|
|
return k;
|
2024-05-23 15:32:54 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
V load_font(ilo *v) {
|
2024-07-04 19:41:05 +02:00
|
|
|
F = open(FONT, O_RDONLY, 0666); FAILED { ulf(v); return; }
|
2024-05-23 15:32:54 +02:00
|
|
|
read(F, &font, 4096);
|
|
|
|
close(F);
|
|
|
|
}
|
|
|
|
|
|
|
|
V pixel(I x, I y, I c) {
|
|
|
|
I index = y * FW + x;
|
|
|
|
if (c == 0) {
|
|
|
|
frame[(index / 32)] &= ~(1 << (31 - index % 32));
|
|
|
|
XSetForeground(disp, gc, BG);
|
|
|
|
} else {
|
|
|
|
frame[(index / 32)] |= 1 << (31 - index % 32);
|
|
|
|
XSetForeground(disp, gc, FG);
|
|
|
|
}
|
|
|
|
XDrawPoint(disp, win, gc, x, y);
|
|
|
|
}
|
|
|
|
|
|
|
|
I get_pixel(I x, I y) {
|
|
|
|
I index = y * FW + x;
|
|
|
|
I bit_pos = 31 - index % 32;
|
|
|
|
I mask = 1 << bit_pos;
|
|
|
|
return (frame[(index / 32)] & mask) >> bit_pos;
|
|
|
|
}
|
|
|
|
|
|
|
|
V redraw() {
|
|
|
|
for (I x = 0; x < FW; x++) {
|
|
|
|
for (I y = 0; y < FH; y++) {
|
|
|
|
XSetForeground(disp, gc, get_pixel(x, y) ? FG : BG);
|
|
|
|
XDrawPoint(disp, win, gc, x, y);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
V scroll() {
|
|
|
|
I memsize = (FH * FW) / 32;
|
|
|
|
I last_row = (FW * FONT_H) / 32;
|
|
|
|
for (I i = 0; i < memsize - last_row; i++) {
|
|
|
|
frame[i] = frame[i + last_row];
|
|
|
|
}
|
|
|
|
for (I i = memsize - last_row; i < memsize; i++) {
|
|
|
|
frame[i] = 0;
|
|
|
|
}
|
|
|
|
redraw();
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned C reverse(unsigned C b) {
|
2024-07-04 19:41:05 +02:00
|
|
|
b = (b & 0xF0) >> 4 | (b & 0x0F) << 4;
|
|
|
|
b = (b & 0xCC) >> 2 | (b & 0x33) << 2;
|
|
|
|
b = (b & 0xAA) >> 1 | (b & 0x55) << 1;
|
|
|
|
return b;
|
|
|
|
}
|
|
|
|
|
|
|
|
V special_backspace() {
|
|
|
|
if (tx - FONT_W >= 0) {
|
|
|
|
tx -= FONT_W ; dputc(' '); tx -= FONT_W;
|
|
|
|
}
|
2024-05-23 15:32:54 +02:00
|
|
|
}
|
|
|
|
|
2024-07-04 19:41:05 +02:00
|
|
|
V special_tab() {
|
|
|
|
I ts = tx / FONT_W;
|
|
|
|
for (I i = ts; i < ((ts + 7) / 8) * 8; i++) { dputc(' '); }
|
|
|
|
}
|
|
|
|
|
|
|
|
V special_crlf() { ty += FONT_H; tx = 0; }
|
|
|
|
|
2024-05-23 15:32:54 +02:00
|
|
|
V handle_special_character(I c) {
|
2024-07-04 19:41:05 +02:00
|
|
|
switch (c) {
|
|
|
|
case 8:
|
|
|
|
case 127: special_backspace(); break;
|
|
|
|
case 9: special_tab(); break;
|
|
|
|
case 10:
|
|
|
|
case 13: special_crlf(); break;
|
2024-05-23 15:32:54 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
V handle_regular_character(C *bitmap) {
|
|
|
|
I x, y, set;
|
|
|
|
for (x = 0; x < FONT_H; x++) {
|
|
|
|
for (y = 0; y < FONT_W; y++) {
|
|
|
|
set = reverse(bitmap[x]) & 1 << y;
|
|
|
|
pixel(tx + y, ty + x, set ? 1 : 0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
tx += FONT_W;
|
|
|
|
}
|
|
|
|
|
|
|
|
V advance_cursor_and_scroll() {
|
|
|
|
if (tx >= FW) { tx = 0; ty += FONT_H; }
|
|
|
|
if (ty > (FH - FONT_H)) { ty -= FONT_H; scroll(); }
|
|
|
|
}
|
|
|
|
|
2024-07-04 19:41:05 +02:00
|
|
|
#define NORMAL !(c < 32 || c == 127)
|
|
|
|
|
2024-05-23 15:32:54 +02:00
|
|
|
V dputc(I c) {
|
|
|
|
C *bitmap = (C *)font + (c * ((FONT_H * FONT_W) / 8));
|
|
|
|
handle_special_character(c);
|
2024-07-04 19:41:05 +02:00
|
|
|
if (NORMAL) { handle_regular_character(bitmap); }
|
2024-05-23 15:32:54 +02:00
|
|
|
advance_cursor_and_scroll();
|
|
|
|
}
|
|
|
|
|
|
|
|
I acc_pop() {
|
|
|
|
I k = acc_i;
|
|
|
|
if (acc_i > 0) {
|
|
|
|
acc_i -= 1;
|
|
|
|
if (acc_i == -1) {
|
|
|
|
acc_i = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return acc[k];
|
|
|
|
}
|
|
|
|
|
|
|
|
V acc_reset() {
|
|
|
|
for (I x = 0; x < 32; x++) { acc[x] = 0; }
|
|
|
|
ground = on = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
V gt_up(I n) { ty -= FONT_H; if (ty < 0) ty = 0; }
|
2024-07-04 19:41:05 +02:00
|
|
|
V gt_down(I n) { ty += FONT_H; if (ty > ROWS * FONT_H) ty = ROWS * FONT_H; }
|
2024-05-23 15:32:54 +02:00
|
|
|
V gt_left(I n) { tx -= FONT_W; if (tx < 0) tx = 0; }
|
2024-07-04 19:41:05 +02:00
|
|
|
V gt_right(I n) { tx += FONT_W; if (tx > COLS * FONT_W) ty = COLS * FONT_W; }
|
2024-05-23 15:32:54 +02:00
|
|
|
V gt_move_cursor() {
|
|
|
|
if (acc_i >= 1) {
|
|
|
|
I a = (acc_pop() - 1) * FONT_W;
|
|
|
|
I b = (acc_pop() - 1) * FONT_H;
|
2024-07-04 19:41:05 +02:00
|
|
|
ty = b; if (ty < 0) ty = 0; if (ty > FONT_H * ROWS) ty = FONT_H * ROWS;
|
|
|
|
tx = a; if (tx < 0) tx = 0; if (tx > FONT_W * COLS) tx = FONT_W * COLS;
|
2024-05-23 15:32:54 +02:00
|
|
|
acc_reset();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
/* home */
|
|
|
|
tx = 0; ty = 0;
|
|
|
|
acc_reset();
|
|
|
|
}
|
|
|
|
|
|
|
|
V gt_reset() { acc_reset(); }
|
|
|
|
V gt_next() { acc_i += 1; acc[acc_i] = 0; }
|
|
|
|
V gt_clear() {
|
|
|
|
acc_reset();
|
|
|
|
for (I x = 0; x < (FW * FH) / 32; x++) frame[x] = 0;
|
|
|
|
tx = ty = 0;
|
|
|
|
redraw();
|
|
|
|
}
|
|
|
|
V gt_set_attr() { acc_reset(); }
|
|
|
|
|
|
|
|
V term_putc(I c) {
|
2024-07-04 19:41:05 +02:00
|
|
|
if (c == 27) { on = -2; return; }
|
2024-05-23 15:32:54 +02:00
|
|
|
switch (on) {
|
|
|
|
case 0:
|
|
|
|
dputc(c);
|
|
|
|
return;
|
|
|
|
case -2:
|
|
|
|
if (c == '[') {
|
|
|
|
on = -1;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
on = 0;
|
|
|
|
dputc(c);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (c >= '0' && c <= '9') {
|
|
|
|
acc[acc_i] *= 10;
|
|
|
|
acc[acc_i] += c - 48;
|
|
|
|
if (c == '3') {
|
|
|
|
ground = 0;
|
|
|
|
}
|
|
|
|
if (c == '4') {
|
|
|
|
ground = 1;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
switch (c) {
|
|
|
|
case 'A': gt_up(acc_pop()); break;
|
|
|
|
case 'B': gt_down(acc_pop()); break;
|
|
|
|
case 'C': gt_left(acc_pop()); break;
|
|
|
|
case 'D': gt_right(acc_pop()); break;
|
|
|
|
case 'm': gt_set_attr(); break;
|
|
|
|
case ';': gt_next(); break;
|
|
|
|
case 'H': gt_move_cursor(); break;
|
|
|
|
case 'J': gt_clear(); break;
|
|
|
|
default: on = 0;
|
|
|
|
dputc(c);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-07-04 19:41:05 +02:00
|
|
|
/* graphica, level 0 ======================================== */
|
|
|
|
|
|
|
|
I p0, p0x, p0y, pcolor = FG;
|
|
|
|
I px(I p) { return p >> 16; }
|
|
|
|
I py(I p) { return p & 65535; }
|
|
|
|
|
|
|
|
V gra0(ilo *v) { push(v, 0); }
|
|
|
|
V gra1(ilo *v) { push(v, 2); }
|
|
|
|
V gra2(ilo *v) { push(v, FONT_H); push(v, FONT_W); }
|
|
|
|
V gra3(ilo *v) { push(v, FH); push(v, FW); }
|
|
|
|
V gra4(ilo *v) { pcolor = (pop(v) != 0) ? FG : BG; }
|
|
|
|
V gra5(ilo *v) { p0 = pop(v); p0x = px(p0); p0y = py(p0);
|
|
|
|
pixel(p0x, p0y, pcolor); }
|
|
|
|
V gra6(ilo *v) { p0 = pop(v); p0x = px(p0); p0y = py(p0);
|
|
|
|
push(v, get_pixel(p0x, p0y)); }
|
|
|
|
V gra(ilo *v) {
|
|
|
|
switch (pop(v)) {
|
|
|
|
case 0: gra0(v); break; case 1: gra1(v); break;
|
|
|
|
case 2: gra2(v); break; case 3: gra3(v); break;
|
|
|
|
case 4: gra4(v); break; case 5: gra5(v); break;
|
|
|
|
case 6: gra6(v); break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* pointer device =========================================== */
|
|
|
|
/* returns x, y, button state */
|
|
|
|
|
|
|
|
V ptr(ilo *v) {
|
|
|
|
I x, y, wx, wy;
|
|
|
|
unsigned I mask;
|
|
|
|
Window w;
|
|
|
|
XQueryPointer(disp, win, &w, &w, &x, &y, &wx, &wy, &mask);
|
|
|
|
push(v, x);
|
|
|
|
push(v, y);
|
|
|
|
if (mask & Button1Mask) push(v, -1); else push(v, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* the ilo cpu ============================================== */
|
|
|
|
|
2024-05-23 15:32:54 +02:00
|
|
|
V load_image(ilo *v) {
|
2024-07-04 19:41:05 +02:00
|
|
|
F = open(v->rom, O_RDONLY, 0666); FAILED { uli(v); return; }
|
2024-05-23 15:32:54 +02:00
|
|
|
read(F, &M, 65536 * 4);
|
|
|
|
close(F);
|
|
|
|
IP = SP = RP = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
V save_image(ilo *v) {
|
2024-07-04 19:41:05 +02:00
|
|
|
F = open(v->rom, O_WRONLY, 0666); FAILED { usi(v); return; }
|
|
|
|
write(F, &M, 65536 * 4);
|
|
|
|
close(F);
|
2024-05-23 15:32:54 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
V block_common(ilo *v) {
|
|
|
|
B = pop(v); /* block buffer */
|
|
|
|
A = pop(v); /* block number */
|
2024-07-04 19:41:05 +02:00
|
|
|
lseek(F, 4096 * A, SEEK_SET);
|
2024-05-23 15:32:54 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
V read_block(ilo *v) {
|
2024-07-04 19:41:05 +02:00
|
|
|
F = open(v->blocks, O_RDONLY, 0666); FAILED { urb(v); return; }
|
2024-05-23 15:32:54 +02:00
|
|
|
block_common(v);
|
2024-07-04 19:41:05 +02:00
|
|
|
read(F, M + B, 4096);
|
|
|
|
close(F);
|
2024-05-23 15:32:54 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
V write_block(ilo *v) {
|
2024-07-04 19:41:05 +02:00
|
|
|
F = open(v->blocks, O_WRONLY, 0666); FAILED { uwb(v); return; }
|
2024-05-23 15:32:54 +02:00
|
|
|
block_common(v);
|
2024-07-04 19:41:05 +02:00
|
|
|
write(F, M + B, 4096);
|
|
|
|
close(F);
|
2024-05-23 15:32:54 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
V save_ip(ilo *v) { RP += 1; R = IP; }
|
2024-07-04 19:41:05 +02:00
|
|
|
V symmetric(ilo *v) { if (B >= 0 && N < 0) { T += 1; N -= B; } }
|
2024-05-23 15:32:54 +02:00
|
|
|
|
|
|
|
V li(ilo *v) { IP += 1; push(v, M[IP]); }
|
|
|
|
V du(ilo *v) { push(v, T); }
|
|
|
|
V dr(ilo *v) { DS[SP] = 0; SP -= 1; }
|
|
|
|
V sw(ilo *v) { A = T; T = N; N = A; }
|
|
|
|
V pu(ilo *v) { RP += 1; R = pop(v); }
|
|
|
|
V po(ilo *v) { push(v, R); RP -= 1; }
|
|
|
|
V ju(ilo *v) { IP = pop(v) - 1; }
|
|
|
|
V ca(ilo *v) { save_ip(v); IP = pop(v) - 1; }
|
|
|
|
V cc(ilo *v) { A = pop(v);
|
|
|
|
if (pop(v)) { save_ip(v);
|
|
|
|
IP = A - 1; } }
|
|
|
|
V cj(ilo *v) { A = pop(v);
|
|
|
|
if (pop(v)) { IP = A - 1; } }
|
|
|
|
V re(ilo *v) { IP = R; RP -= 1; }
|
|
|
|
V eq(ilo *v) { N = (N == T) ? -1 : 0; SP -= 1; }
|
|
|
|
V ne(ilo *v) { N = (N != T) ? -1 : 0; SP -= 1; }
|
|
|
|
V lt(ilo *v) { N = (N < T) ? -1 : 0; SP -= 1; }
|
|
|
|
V gt(ilo *v) { N = (N > T) ? -1 : 0; SP -= 1; }
|
|
|
|
V fe(ilo *v) { T = M[T]; }
|
|
|
|
V st(ilo *v) { M[T] = N; SP -= 2; }
|
|
|
|
V ad(ilo *v) { N += T; SP -= 1; }
|
|
|
|
V su(ilo *v) { N -= T; SP -= 1; }
|
|
|
|
V mu(ilo *v) { N *= T; SP -= 1; }
|
|
|
|
V di(ilo *v) { A = T; B = N;
|
2024-07-04 19:41:05 +02:00
|
|
|
if (A == 0) { dbz(v); OK = 1; RESTART; return; }
|
2024-05-23 15:32:54 +02:00
|
|
|
T = B / A; N = B % A;
|
|
|
|
symmetric(v); }
|
|
|
|
V an(ilo *v) { N = T & N; SP -= 1; }
|
|
|
|
V or(ilo *v) { N = T | N; SP -= 1; }
|
|
|
|
V xo(ilo *v) { N = T ^ N; SP -= 1; }
|
|
|
|
V sl(ilo *v) { N = N << T; SP -= 1; }
|
|
|
|
V sr(ilo *v) { N = N >> T; SP -= 1; }
|
|
|
|
V cp(ilo *v) { L = pop(v); D = pop(v); S = T; T = -1;
|
|
|
|
while (L) {
|
|
|
|
if (M[D] != M[S]) { T = 0; }
|
|
|
|
L -= 1; S += 1; D += 1; } }
|
|
|
|
V cy(ilo *v) { L = pop(v); D = pop(v); S = pop(v);
|
|
|
|
while (L) {
|
|
|
|
M[D] = M[S];
|
|
|
|
L -= 1; S += 1; D += 1; } }
|
|
|
|
|
2024-07-04 19:41:05 +02:00
|
|
|
V pre(V) { cur -= 1; if (cur < 0) cur = ILOS - 1; update_labels(); }
|
|
|
|
V nxt(V) { cur += 1; if (cur > (ILOS - 1)) cur = 0; update_labels(); }
|
2024-05-23 15:32:54 +02:00
|
|
|
|
|
|
|
V ioa(ilo *v) { term_putc(pop(v)); }
|
|
|
|
V iob(ilo *v) { redraw(); cursor();
|
|
|
|
v->i[0] = wait_key(); push(v, v->i[0]); term_putc(T);
|
2024-07-04 19:41:05 +02:00
|
|
|
if (v->i[0] == CTRL_N) { T = 32; nxt(); }
|
|
|
|
if (v->i[0] == CTRL_P) { T = 32; pre(); }
|
|
|
|
if (v->i[0] == CTRL_C) { T = 32; RESTART;
|
|
|
|
OK = 1; }
|
|
|
|
if (v->i[0] == CTRL_A) { T = 32; exit(0); } }
|
2024-05-23 15:32:54 +02:00
|
|
|
V ioc(ilo *v) { read_block(v); }
|
|
|
|
V iod(ilo *v) { write_block(v); }
|
|
|
|
V ioe(ilo *v) { save_image(v); }
|
|
|
|
V iof(ilo *v) { load_image(v); IP = -1; }
|
2024-07-04 19:41:05 +02:00
|
|
|
V iog(ilo *v) { RESTART; }
|
2024-05-23 15:32:54 +02:00
|
|
|
V ioh(ilo *v) { push(v, SP); push(v, RP); }
|
|
|
|
|
|
|
|
V io(ilo *v) {
|
|
|
|
switch (pop(v)) {
|
|
|
|
case 0: ioa(v); break; case 1: iob(v); break;
|
|
|
|
case 2: ioc(v); break; case 3: iod(v); break;
|
|
|
|
case 4: ioe(v); break; case 5: iof(v); break;
|
|
|
|
case 6: iog(v); break; case 7: ioh(v); break;
|
2024-07-04 19:41:05 +02:00
|
|
|
/* optional extensions after this point */
|
|
|
|
case 12: gra(v); break; case 13: ptr(v); break;
|
2024-05-23 15:32:54 +02:00
|
|
|
default: break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
V process(ilo *v, I o) {
|
|
|
|
switch (o) {
|
|
|
|
case 0: break; case 1: li(v); break;
|
|
|
|
case 2: du(v); break; case 3: dr(v); break;
|
|
|
|
case 4: sw(v); break; case 5: pu(v); break;
|
|
|
|
case 6: po(v); break; case 7: ju(v); break;
|
|
|
|
case 8: ca(v); break; case 9: cc(v); break;
|
|
|
|
case 10: cj(v); break; case 11: re(v); break;
|
|
|
|
case 12: eq(v); break; case 13: ne(v); break;
|
|
|
|
case 14: lt(v); break; case 15: gt(v); break;
|
|
|
|
case 16: fe(v); break; case 17: st(v); break;
|
|
|
|
case 18: ad(v); break; case 19: su(v); break;
|
|
|
|
case 20: mu(v); break; case 21: di(v); break;
|
|
|
|
case 22: an(v); break; case 23: or(v); break;
|
|
|
|
case 24: xo(v); break; case 25: sl(v); break;
|
|
|
|
case 26: sr(v); break; case 27: cp(v); break;
|
|
|
|
case 28: cy(v); break; case 29: io(v); break;
|
|
|
|
default: break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-07-04 19:41:05 +02:00
|
|
|
/* This is used to help skip processing NOP operations and */
|
|
|
|
/* abort on errors */
|
|
|
|
|
|
|
|
#define VALID(n) (OK == 0) && ((opcode >> n) & 0xFF)
|
2024-05-23 15:32:54 +02:00
|
|
|
|
|
|
|
V execute() {
|
|
|
|
I opcode;
|
|
|
|
ilo *v = &systems[cur];
|
|
|
|
while (IP < 65536) {
|
|
|
|
opcode = M[IP];
|
2024-07-04 19:41:05 +02:00
|
|
|
OK = 0;
|
2024-05-23 15:32:54 +02:00
|
|
|
if (VALID(0)) process(v, opcode & 0xFF);
|
|
|
|
if (VALID(8)) process(v, (opcode >> 8) & 0xFF);
|
|
|
|
if (VALID(16)) process(v, (opcode >> 16) & 0xFF);
|
|
|
|
if (VALID(24)) process(v, (opcode >> 24) & 0xFF);
|
|
|
|
IP += 1;
|
|
|
|
v = &systems[cur];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-07-04 19:41:05 +02:00
|
|
|
/* main entry point ========================================= */
|
2024-05-23 15:32:54 +02:00
|
|
|
|
|
|
|
I main(I argc, C **argv) {
|
|
|
|
ilo *v;
|
|
|
|
I i;
|
|
|
|
|
2024-07-04 19:41:05 +02:00
|
|
|
/* setup each session */
|
2024-05-23 15:32:54 +02:00
|
|
|
for (i = 0; i < ILOS; i++) {
|
|
|
|
v = &systems[i];
|
|
|
|
v->blocks = (argc > 1) ? argv[1] : BLOCKS;
|
|
|
|
v->rom = (argc > 2) ? argv[2] : ROM;
|
|
|
|
load_image(v);
|
|
|
|
}
|
|
|
|
|
2024-07-04 19:41:05 +02:00
|
|
|
/* load the font data */
|
2024-05-23 15:32:54 +02:00
|
|
|
load_font(&systems[0]);
|
2024-07-04 19:41:05 +02:00
|
|
|
initialize_display();
|
2024-05-23 15:32:54 +02:00
|
|
|
|
2024-07-04 19:41:05 +02:00
|
|
|
#ifdef CENTER_WINDOW
|
2024-05-23 15:32:54 +02:00
|
|
|
XMoveWindow(disp, win, (DisplayWidth(disp, DefaultScreen(disp)) - FW) / 2,
|
2024-07-04 19:41:05 +02:00
|
|
|
(DisplayHeight(disp, DefaultScreen(disp)) - FH - BUTTON_HEIGHT) / 2);
|
|
|
|
#endif
|
2024-05-23 15:32:54 +02:00
|
|
|
|
2024-07-04 19:41:05 +02:00
|
|
|
cur = 0;
|
2024-05-23 15:32:54 +02:00
|
|
|
execute();
|
|
|
|
|
2024-07-04 19:41:05 +02:00
|
|
|
cleanup_display();
|
2024-05-23 15:32:54 +02:00
|
|
|
return 0;
|
|
|
|
}
|