check in the source files, binaries, and update README & LICENSE

This commit is contained in:
crc 2024-05-23 15:32:54 +02:00
parent 8a784593c4
commit 35d1a33e25
63 changed files with 15419 additions and 7 deletions

32
LICENSE
View file

@ -1,8 +1,30 @@
ISC License:
================================================================
Copyright (c) 2004-2010 by Internet Systems Consortium, Inc. ("ISC")
Copyright (c) 1995-2003 by Internet Software Consortium
_ ___ ____ _____ _ _ ____ _____
| | |_ _/ ___| ____| \ | / ___|| ____|
| | | | | | _| | \| \___ \| _|
| |___ | | |___| |___| |\ |___) | |___
|_____|___\____|_____|_| \_|____/|_____|
Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies.
Konilo & ilo
THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
Copyright (c) Charles Childers
================================================================
Permission to use, copy, modify, and/or distribute this
software for any purpose with or without fee is hereby
granted, provided that the copyright notice and this
permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS
ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO
EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
OF THIS SOFTWARE.
================================================================

View file

@ -1,3 +1,37 @@
# ilo-vm
================================================================
The ilo virtual computer. This is mostly used with Konilo, a Forth based computing system.
crc's _ _
(_) | ___
| | |/ _ \ a tiny virtual computer
| | | (_) | 64kw RAM, 32-bit, Dual Stack, MISC
|_|_|\___/ (c) charles childers
================================================================
# Welcome!
This is ilo, a little virtual computer. ilo is mostly used with
Konilo, a personal computing system written in Forth.
A brief overview:
- 65,536 memory locations ("cells")
- 32 bits per cell
- block storage device
- stack based architecture
- minimal instruction set (30 instructions)
- easy to implement and exend
This supports a variety of host architectures. Precompiled
(mostly static) binaries are included for Linux, OpenBSD,
NetBSD, FreeBSD, MS-DOS, macOS, Haiku, Classic Mac Systems 5-7,
and Windows. It has been tested and confirmed to work on x86
(8088+), amd64, arm64, and 68000 processors. Physical RAM
requirements are around 384K.
In addition to the provided binaries, many implementations of
ilo are included. These include Assembly, C, C++, C#, Common
Lisp, D, Go, Hare, JavaScript, Kotlin, Lua, Nim, Python,
RetroForth, Rust, Swift, and TypeScript.
================================================================

BIN
binaries/CWSDPMI.exe Normal file

Binary file not shown.

BIN
binaries/ilo-68k-mac.bin Normal file

Binary file not shown.

BIN
binaries/ilo-aarch64-linux Executable file

Binary file not shown.

BIN
binaries/ilo-amd64-dragonfly Executable file

Binary file not shown.

BIN
binaries/ilo-amd64-freebsd Executable file

Binary file not shown.

BIN
binaries/ilo-amd64-haiku Executable file

Binary file not shown.

BIN
binaries/ilo-amd64-linux Executable file

Binary file not shown.

BIN
binaries/ilo-amd64-netbsd Executable file

Binary file not shown.

BIN
binaries/ilo-amd64-openbsd Executable file

Binary file not shown.

Binary file not shown.

BIN
binaries/ilo-arm64-darwin Executable file

Binary file not shown.

BIN
binaries/ilo-dotnet-windows.exe Executable file

Binary file not shown.

BIN
binaries/ilo-ipad-ish Executable file

Binary file not shown.

BIN
binaries/ilo-luna88k-openbsd Executable file

Binary file not shown.

BIN
binaries/ilo-pmax-netbsd Executable file

Binary file not shown.

4230
binaries/ilo-teensy41.hex Normal file

File diff suppressed because it is too large Load diff

BIN
binaries/ilo-universal-darwin Executable file

Binary file not shown.

Binary file not shown.

BIN
binaries/ilo-x86-dos.exe Normal file

Binary file not shown.

BIN
binaries/ilo-x86-freebsd Executable file

Binary file not shown.

BIN
binaries/ilo-x86-linux Executable file

Binary file not shown.

BIN
binaries/ilo-x86-netbsd Normal file

Binary file not shown.

BIN
binaries/ilo-x86-openbsd Executable file

Binary file not shown.

Binary file not shown.

BIN
binaries/ilo.jar Normal file

Binary file not shown.

1
source/ilo-68k-mac.c Normal file

File diff suppressed because one or more lines are too long

1120
source/ilo-aarch64-linux.s Normal file

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,422 @@
/* AMD64 ilo, (c) 2023 Christopher Leonard, MIT License */
/* cc -c ilo-amd64-freebsd.s -o ilo.o
ld -nostdlib ilo.o -o ilo
*/
.global _start
/* rax: top of stack */
/* rbx: data stack */
/* rbp: jump table address */
/* r12: address stack */
/* r13: instruction pointer */
/* r14: opcode shift register */
/* r15: memory */
.bss
.align 8
blocks: .skip 8 /* name of blocks file (ilo.blocks) */
rom: .skip 8 /* name of image (ilo.rom) */
dstack: .skip 32*4
astack: .skip 256*4
a: .skip 4 /* other variables for misc. purposes */
b: .skip 4
f: .skip 4
s: .skip 4
d: .skip 4
l: .skip 4
memory: .skip 65536*4
.section .rodata
default_blocks:
.asciz "ilo.blocks"
default_rom:
.asciz "ilo.rom"
io_table:
.byte 0
.byte iob-ioa
.byte ioc-ioa
.byte iod-ioa
.byte ioe-ioa
.byte iof-ioa
.byte iog-ioa
.byte ioh-ioa
.text
dosys: push %r8
push %r9
push %r10
push %r11
push %rdx
syscall
pop %rdx
pop %r11
pop %r10
pop %r9
pop %r8
ret
rdonly: mov $5, %eax /* sys_open */
xor %esi, %esi /* O_RDONLY */
mov $0666, %edx
call dosys
mov %eax, %edi
ret
wronly: mov $5, %eax /* sys_open */
mov $1, %esi /* O_WRONLY */
mov $0666, %edx
call dosys
mov %eax, %edi
ret
close: mov $6, %eax /* sys_close */
call dosys
ret
load_image:
mov rom(%rip), %rdi
call rdonly
or %eax, %eax
jz 1f
mov %r15, %rsi
mov $65536 * 4, %edx
mov $3, %eax /* sys_read */
call dosys
call close
xor %eax, %eax
lea dstack-4(%rip), %rbx
lea astack-4(%rip), %r12
xor %r13d, %r13d
1: ret
save_image:
push %rax
mov rom(%rip), %rdi
call wronly
or %eax, %eax
jz 1f
mov %r15, %rsi
mov $65536 * 4, %edx
mov $4, %eax
call dosys
call close
1: pop %rax
ret
block_common:
mov $199, %eax /* sys_lseek */
mov (%rbx), %edx
shl $12, %edx
//xor %edx, %edx /* SEEK_SET */
call dosys
mov $3, %eax /* sys_read */
or %r10b, %r10b
jz 1f
mov $4, %al /* sys_write */
1: lea (%r15,%r8,4), %rsi
mov $4096, %edx
call dosys
mov -4(%rbx), %esi
sub $8, %rbx
ret
.align 32
table: ret
.align 32
li: add $4, %rbx
inc %r13d
mov %eax, (%rbx)
mov (%r15,%r13,4), %eax
ret
.align 32
du: add $4, %rbx
mov %eax, (%rbx)
ret
.align 32
dr: mov (%rbx), %eax
sub $4, %rbx
ret
.align 32
sw: xchg (%rbx), %eax
ret
.align 32
pu: add $4, %r12
mov %eax, (%r12)
mov (%rbx), %eax
sub $4, %rbx
ret
.align 32
po: add $4, %rbx
mov %eax, (%rbx)
mov (%r12), %eax
sub $4, %r12
ret
.align 32
ju: lea -1(%eax), %r13d
mov (%rbx), %eax
sub $4, %rbx
ret
.align 32
ca: add $4, %r12
mov %r13d, (%r12)
lea -1(%eax), %r13d
mov (%rbx), %eax
sub $4, %rbx
ret
.align 32
cc: cmpl $0, (%rbx)
jz 1f
add $4, %r12
mov %r13d, (%r12)
lea -1(%eax), %r13d
1: mov -4(%rbx), %eax
sub $8, %rbx
ret
.align 32
cj: cmpl $0, (%rbx)
jz 1f
lea -1(%eax), %r13d
1: mov -4(%rbx), %eax
sub $8, %rbx
ret
.align 32
re: mov (%r12), %r13d
sub $4, %r12
ret
.align 32
eq: cmp %eax, (%rbx)
sete %al
movzbl %al, %eax
neg %eax
sub $4, %rbx
ret
.align 32
ne: cmp %eax, (%rbx)
setne %al
movzbl %al, %eax
neg %eax
sub $4, %rbx
ret
.align 32
lt: cmp %eax, (%rbx)
setl %al
movzbl %al, %eax
neg %eax
sub $4, %rbx
ret
.align 32
gt: cmp %eax, (%rbx)
setg %al
movzbl %al, %eax
neg %eax
sub $4, %rbx
ret
.align 32
fe: mov (%r15,%rax,4), %eax
ret
.align 32
st: mov (%rbx), %ecx
mov %ecx, (%r15,%rax,4)
mov -4(%rbx), %eax
sub $8, %rbx
ret
.align 32
ad: add (%rbx), %eax
sub $4, %rbx
ret
.align 32
su: sub (%rbx), %eax
neg %eax
sub $4, %rbx
ret
.align 32
mu: mull (%rbx)
sub $4, %rbx
ret
.align 32
di: mov %eax, %ecx
mov (%rbx), %eax
cdq
idiv %ecx
mov %edx, (%rbx)
ret
.align 32
an: and (%rbx), %eax
sub $4, %rbx
ret
.align 32
or: or (%rbx), %eax
sub $4, %rbx
ret
.align 32
xo: xor (%rbx), %eax
sub $4, %rbx
ret
.align 32
sl: mov %eax, %ecx
mov (%rbx), %eax
sub $4, %rbx
shl %cl, %eax
ret
.align 32
sr: mov %eax, %ecx
mov (%rbx), %eax
sub $4, %rbx
sar %cl, %eax
ret
.align 32
cp: mov %eax, %ecx
mov (%rbx), %edi
mov -4(%rbx), %esi
sub $8, %rbx
lea (%r15,%rdi,4), %rdi
lea (%r15,%rsi,4), %rsi
cmp %eax, %eax
.byte 0xF3, 0xA7 /* repe cmpsd */
sete %al
movzbl %al, %eax
neg %eax
ret
.align 32
cy: mov %eax, %ecx
mov (%rbx), %edi
mov -4(%rbx), %esi
mov -8(%rbx), %eax
sub $12, %rbx
lea (%r15,%rdi,4), %rdi
lea (%r15,%rsi,4), %rsi
repe movsd
ret
.align 32
io: mov %eax, %ecx
mov (%rbx), %eax
sub $4, %rbx
cmp $7, %ecx
ja 1f
lea io_table(%rip), %rdx
movzbl (%rdx,%rcx), %ecx
lea ioa(%rip), %rdx
add %rdx, %rcx
jmp *%rcx
1: ret
ioa: push %rax
mov $4, %eax /* sys_write */
mov $1, %edi
mov %rsp, %rsi
mov $1, %edx
call dosys
pop %rax
mov (%rbx), %eax
sub $4, %rbx
ret
iob: add $4, %rbx
mov %eax, (%rbx)
mov $3, %eax /* sys_read */
push %rax
xor %edi, %edi
mov %rsp, %rsi
mov $1, %edx
call dosys
pop %rax
ret
ioc: mov %eax, %r8d
mov blocks(%rip), %rdi
call rdonly
xor %r10d, %r10d
call block_common
call close
mov %esi, %eax
ret
iod: mov %eax, %r8d
mov blocks(%rip), %rdi
call wronly
mov $1, %r10b
call block_common
call close
mov %esi, %eax
ret
ioe: jmp save_image
iof: call load_image
xor %rax, %rax
xor %r13, %r13
jmp _execute
iog: mov $65536, %r13d
ret
ioh: add $8, %rbx
mov %eax, -4(%rbx)
lea astack-4(%rip), %rdx
neg %edx
lea 4*32-8(%rbx,%rdx), %rax
shr $2, %eax
mov %eax, (%rbx)
lea (%r12,%rdx), %rax
shr $2, %eax
ret
_start: xor %eax, %eax
add $8, %rsp
lea memory(%rip), %r15
lea dstack-4(%rip), %rbx
lea astack-4(%rip), %r12
xor %r13d, %r13d
lea table(%rip), %rbp
mov 8(%rsp), %rcx
or %rcx, %rcx
jz 1f
mov 16(%rsp), %rcx
or %rcx, %rcx
jz 1f
mov %rcx, blocks(%rip)
mov 24(%rsp), %rcx
or %rcx, %rcx
jz 2f
mov %rcx, rom(%rip)
jmp 3f
1: lea default_blocks(%rip), %rcx
mov %rcx, blocks(%rip)
2: lea default_rom(%rip), %rcx
mov %rcx, rom(%rip)
3: call load_image
_execute:
jmp 3f
.align 64
2: mov (%r15,%r13,4), %r14d
movzbl %r14b, %edi
shr $8, %r14d
cmp $29, %edi
ja 1f
shl $5, %edi
add %rbp, %rdi
call *%rdi
1: movzbl %r14b, %edi
shr $8, %r14d
cmp $29, %edi
ja 1f
shl $5, %edi
add %rbp, %rdi
call *%rdi
1: movzbl %r14b, %edi
shr $8, %r14d
cmp $29, %edi
ja 1f
shl $5, %edi
add %rbp, %rdi
call *%rdi
1: mov %r14d, %edi
cmp $29, %edi
ja 1f
shl $5, %edi
add %rbp, %rdi
call *%rdi
1: inc %r13
3: cmp $65536, %r13
jl 2b
mov $1, %eax /* sys_exit */
xor %edi, %edi
call dosys

420
source/ilo-amd64-freebsd.s Normal file
View file

@ -0,0 +1,420 @@
/* AMD64 ilo, (c) 2023 Christopher Leonard, MIT License */
/* cc -c ilo-amd64-freebsd.s -o ilo.o
ld -nostdlib ilo.o -o ilo
*/
.global _start
/* rax: top of stack */
/* rbx: data stack */
/* rbp: jump table address */
/* r12: address stack */
/* r13: instruction pointer */
/* r14: opcode shift register */
/* r15: memory */
.bss
.align 8
blocks: .skip 8 /* name of blocks file (ilo.blocks) */
rom: .skip 8 /* name of image (ilo.rom) */
dstack: .skip 32*4
astack: .skip 256*4
a: .skip 4 /* other variables for misc. purposes */
b: .skip 4
f: .skip 4
s: .skip 4
d: .skip 4
l: .skip 4
memory: .skip 65536*4
.section .rodata
default_blocks:
.asciz "ilo.blocks"
default_rom:
.asciz "ilo.rom"
io_table:
.byte 0
.byte iob-ioa
.byte ioc-ioa
.byte iod-ioa
.byte ioe-ioa
.byte iof-ioa
.byte iog-ioa
.byte ioh-ioa
.text
dosys: push %r8
push %r9
push %r10
push %rdx
syscall
pop %rdx
pop %r10
pop %r9
pop %r8
ret
rdonly: mov $5, %eax /* sys_open */
xor %esi, %esi /* O_RDONLY */
mov $0666, %edx
call dosys
mov %eax, %edi
ret
wronly: mov $5, %eax /* sys_open */
mov $1, %esi /* O_WRONLY */
mov $0666, %edx
call dosys
mov %eax, %edi
ret
close: mov $6, %eax /* sys_close */
call dosys
ret
load_image:
mov rom(%rip), %rdi
call rdonly
or %eax, %eax
jz 1f
mov %r15, %rsi
mov $65536 * 4, %edx
mov $3, %eax /* sys_read */
call dosys
call close
xor %eax, %eax
lea dstack-4(%rip), %rbx
lea astack-4(%rip), %r12
xor %r13d, %r13d
1: ret
save_image:
push %rax
mov rom(%rip), %rdi
call wronly
or %eax, %eax
jz 1f
mov %r15, %rsi
mov $65536 * 4, %edx
mov $4, %eax
call dosys
call close
1: pop %rax
ret
block_common:
mov $0x1DE, %eax /* sys_lseek */
mov (%rbx), %esi
shl $12, %esi
xor %edx, %edx /* SEEK_SET */
call dosys
mov $3, %eax /* sys_read */
or %r10b, %r10b
jz 1f
mov $4, %al /* sys_write */
1: lea (%r15,%r8,4), %rsi
mov $4096, %edx
call dosys
mov -4(%rbx), %esi
sub $8, %rbx
ret
.align 32
table: ret
.align 32
li: add $4, %rbx
inc %r13d
mov %eax, (%rbx)
mov (%r15,%r13,4), %eax
ret
.align 32
du: add $4, %rbx
mov %eax, (%rbx)
ret
.align 32
dr: mov (%rbx), %eax
sub $4, %rbx
ret
.align 32
sw: xchg (%rbx), %eax
ret
.align 32
pu: add $4, %r12
mov %eax, (%r12)
mov (%rbx), %eax
sub $4, %rbx
ret
.align 32
po: add $4, %rbx
mov %eax, (%rbx)
mov (%r12), %eax
sub $4, %r12
ret
.align 32
ju: lea -1(%eax), %r13d
mov (%rbx), %eax
sub $4, %rbx
ret
.align 32
ca: add $4, %r12
mov %r13d, (%r12)
lea -1(%eax), %r13d
mov (%rbx), %eax
sub $4, %rbx
ret
.align 32
cc: cmpl $0, (%rbx)
jz 1f
add $4, %r12
mov %r13d, (%r12)
lea -1(%eax), %r13d
1: mov -4(%rbx), %eax
sub $8, %rbx
ret
.align 32
cj: cmpl $0, (%rbx)
jz 1f
lea -1(%eax), %r13d
1: mov -4(%rbx), %eax
sub $8, %rbx
ret
.align 32
re: mov (%r12), %r13d
sub $4, %r12
ret
.align 32
eq: cmp %eax, (%rbx)
sete %al
movzbl %al, %eax
neg %eax
sub $4, %rbx
ret
.align 32
ne: cmp %eax, (%rbx)
setne %al
movzbl %al, %eax
neg %eax
sub $4, %rbx
ret
.align 32
lt: cmp %eax, (%rbx)
setl %al
movzbl %al, %eax
neg %eax
sub $4, %rbx
ret
.align 32
gt: cmp %eax, (%rbx)
setg %al
movzbl %al, %eax
neg %eax
sub $4, %rbx
ret
.align 32
fe: mov (%r15,%rax,4), %eax
ret
.align 32
st: mov (%rbx), %ecx
mov %ecx, (%r15,%rax,4)
mov -4(%rbx), %eax
sub $8, %rbx
ret
.align 32
ad: add (%rbx), %eax
sub $4, %rbx
ret
.align 32
su: sub (%rbx), %eax
neg %eax
sub $4, %rbx
ret
.align 32
mu: mull (%rbx)
sub $4, %rbx
ret
.align 32
di: mov %eax, %ecx
mov (%rbx), %eax
cdq
idiv %ecx
mov %edx, (%rbx)
ret
.align 32
an: and (%rbx), %eax
sub $4, %rbx
ret
.align 32
or: or (%rbx), %eax
sub $4, %rbx
ret
.align 32
xo: xor (%rbx), %eax
sub $4, %rbx
ret
.align 32
sl: mov %eax, %ecx
mov (%rbx), %eax
sub $4, %rbx
shl %cl, %eax
ret
.align 32
sr: mov %eax, %ecx
mov (%rbx), %eax
sub $4, %rbx
sar %cl, %eax
ret
.align 32
cp: mov %eax, %ecx
mov (%rbx), %edi
mov -4(%rbx), %esi
sub $8, %rbx
lea (%r15,%rdi,4), %rdi
lea (%r15,%rsi,4), %rsi
cmp %eax, %eax
.byte 0xF3, 0xA7 /* repe cmpsd */
sete %al
movzbl %al, %eax
neg %eax
ret
.align 32
cy: mov %eax, %ecx
mov (%rbx), %edi
mov -4(%rbx), %esi
mov -8(%rbx), %eax
sub $12, %rbx
lea (%r15,%rdi,4), %rdi
lea (%r15,%rsi,4), %rsi
repe movsd
ret
.align 32
io: mov %eax, %ecx
mov (%rbx), %eax
sub $4, %rbx
cmp $7, %ecx
ja 1f
lea io_table(%rip), %rdx
movzbl (%rdx,%rcx), %ecx
lea ioa(%rip), %rdx
add %rdx, %rcx
jmp *%rcx
1: ret
ioa: push %rax
mov $4, %eax /* sys_write */
mov $1, %edi
mov %rsp, %rsi
mov $1, %edx
call dosys
pop %rax
mov (%rbx), %eax
sub $4, %rbx
ret
iob: add $4, %rbx
mov %eax, (%rbx)
mov $3, %eax /* sys_read */
push %rax
xor %edi, %edi
mov %rsp, %rsi
mov $1, %edx
call dosys
pop %rax
ret
ioc: mov %eax, %r8d
mov blocks(%rip), %rdi
call rdonly
xor %r10d, %r10d
call block_common
call close
mov %esi, %eax
ret
iod: mov %eax, %r8d
mov blocks(%rip), %rdi
call wronly
mov $1, %r10b
call block_common
call close
mov %esi, %eax
ret
ioe: jmp save_image
iof: call load_image
xor %rax, %rax
xor %r13, %r13
jmp _execute
iog: mov $65536, %r13d
ret
ioh: add $8, %rbx
mov %eax, -4(%rbx)
lea astack-4(%rip), %rdx
neg %edx
lea 4*32-8(%rbx,%rdx), %rax
shr $2, %eax
mov %eax, (%rbx)
lea (%r12,%rdx), %rax
shr $2, %eax
ret
_start: xor %eax, %eax
add $8, %rsp
lea memory(%rip), %r15
lea dstack-4(%rip), %rbx
lea astack-4(%rip), %r12
xor %r13d, %r13d
lea table(%rip), %rbp
mov 8(%rsp), %rcx
or %rcx, %rcx
jz 1f
mov 16(%rsp), %rcx
or %rcx, %rcx
jz 1f
mov %rcx, blocks(%rip)
mov 24(%rsp), %rcx
or %rcx, %rcx
jz 2f
mov %rcx, rom(%rip)
jmp 3f
1: lea default_blocks(%rip), %rcx
mov %rcx, blocks(%rip)
2: lea default_rom(%rip), %rcx
mov %rcx, rom(%rip)
3: call load_image
_execute:
jmp 3f
.align 64
2: mov (%r15,%r13,4), %r14d
movzbl %r14b, %edi
shr $8, %r14d
cmp $29, %edi
ja 1f
shl $5, %edi
add %rbp, %rdi
call *%rdi
1: movzbl %r14b, %edi
shr $8, %r14d
cmp $29, %edi
ja 1f
shl $5, %edi
add %rbp, %rdi
call *%rdi
1: movzbl %r14b, %edi
shr $8, %r14d
cmp $29, %edi
ja 1f
shl $5, %edi
add %rbp, %rdi
call *%rdi
1: mov %r14d, %edi
cmp $29, %edi
ja 1f
shl $5, %edi
add %rbp, %rdi
call *%rdi
1: inc %r13
3: cmp $65536, %r13
jl 2b
mov $1, %eax /* sys_exit */
xor %edi, %edi
call dosys

405
source/ilo-amd64-linux.s Normal file
View file

@ -0,0 +1,405 @@
/* AMD64 ilo, (c) 2023 Christopher Leonard, MIT License */
.global _start
/* rax: top of stack */
/* rbx: data stack */
/* rbp: jump table address */
/* r12: address stack */
/* r13: instruction pointer */
/* r14: opcode shift register */
/* r15: memory */
.bss
.align 8
blocks: .skip 8 /* name of blocks file (ilo.blocks) */
rom: .skip 8 /* name of image (ilo.rom) */
dstack: .skip 32*4
astack: .skip 256*4
a: .skip 4 /* other variables for misc. purposes */
b: .skip 4
f: .skip 4
s: .skip 4
d: .skip 4
l: .skip 4
memory: .skip 65536*4
.section .rodata
default_blocks:
.asciz "ilo.blocks"
default_rom:
.asciz "ilo.rom"
io_table:
.byte 0
.byte iob-ioa
.byte ioc-ioa
.byte iod-ioa
.byte ioe-ioa
.byte iof-ioa
.byte iog-ioa
.byte ioh-ioa
.text
rdonly: mov $2, %eax /* sys_open */
xor %esi, %esi /* O_RDONLY */
mov $0666, %edx
syscall
mov %eax, %edi
ret
wronly: mov $2, %eax /* sys_open */
mov $1, %esi /* O_WRONLY */
mov $0666, %edx
syscall
mov %eax, %edi
ret
close: mov $3, %eax /* sys_close */
syscall
ret
load_image:
mov rom(%rip), %rdi
call rdonly
or %eax, %eax
jz 1f
mov %r15, %rsi
mov $65536 * 4, %edx
xor %eax, %eax /* sys_read */
syscall
call close
xor %eax, %eax
lea dstack-4(%rip), %rbx
lea astack-4(%rip), %r12
xor %r13d, %r13d
1: ret
save_image:
push %rax
mov rom(%rip), %rdi
call wronly
or %eax, %eax
jz 1f
mov %r15, %rsi
mov $65536 * 4, %edx
mov $1, %eax
syscall
call close
1: pop %rax
ret
block_common:
mov $8, %eax /* sys_lseek */
mov (%rbx), %esi
shl $12, %esi
xor %edx, %edx /* SEEK_SET */
syscall
xor %eax, %eax /* sys_read */
or %r10b, %r10b
jz 1f
mov $1, %al /* sys_write */
1: lea (%r15,%r8,4), %rsi
mov $4096, %edx
syscall
mov -4(%rbx), %esi
sub $8, %rbx
ret
.align 32
table: ret
.align 32
li: add $4, %rbx
inc %r13d
mov %eax, (%rbx)
mov (%r15,%r13,4), %eax
ret
.align 32
du: add $4, %rbx
mov %eax, (%rbx)
ret
.align 32
dr: mov (%rbx), %eax
sub $4, %rbx
ret
.align 32
sw: xchg (%rbx), %eax
ret
.align 32
pu: add $4, %r12
mov %eax, (%r12)
mov (%rbx), %eax
sub $4, %rbx
ret
.align 32
po: add $4, %rbx
mov %eax, (%rbx)
mov (%r12), %eax
sub $4, %r12
ret
.align 32
ju: lea -1(%eax), %r13d
mov (%rbx), %eax
sub $4, %rbx
ret
.align 32
ca: add $4, %r12
mov %r13d, (%r12)
lea -1(%eax), %r13d
mov (%rbx), %eax
sub $4, %rbx
ret
.align 32
cc: cmpl $0, (%rbx)
jz 1f
add $4, %r12
mov %r13d, (%r12)
lea -1(%eax), %r13d
1: mov -4(%rbx), %eax
sub $8, %rbx
ret
.align 32
cj: cmpl $0, (%rbx)
jz 1f
lea -1(%eax), %r13d
1: mov -4(%rbx), %eax
sub $8, %rbx
ret
.align 32
re: mov (%r12), %r13d
sub $4, %r12
ret
.align 32
eq: cmp %eax, (%rbx)
sete %al
movzbl %al, %eax
neg %eax
sub $4, %rbx
ret
.align 32
ne: cmp %eax, (%rbx)
setne %al
movzbl %al, %eax
neg %eax
sub $4, %rbx
ret
.align 32
lt: cmp %eax, (%rbx)
setl %al
movzbl %al, %eax
neg %eax
sub $4, %rbx
ret
.align 32
gt: cmp %eax, (%rbx)
setg %al
movzbl %al, %eax
neg %eax
sub $4, %rbx
ret
.align 32
fe: mov (%r15,%rax,4), %eax
ret
.align 32
st: mov (%rbx), %ecx
mov %ecx, (%r15,%rax,4)
mov -4(%rbx), %eax
sub $8, %rbx
ret
.align 32
ad: add (%rbx), %eax
sub $4, %rbx
ret
.align 32
su: sub (%rbx), %eax
neg %eax
sub $4, %rbx
ret
.align 32
mu: mull (%rbx)
sub $4, %rbx
ret
.align 32
di: mov %eax, %ecx
mov (%rbx), %eax
cdq
idiv %ecx
mov %edx, (%rbx)
ret
.align 32
an: and (%rbx), %eax
sub $4, %rbx
ret
.align 32
or: or (%rbx), %eax
sub $4, %rbx
ret
.align 32
xo: xor (%rbx), %eax
sub $4, %rbx
ret
.align 32
sl: mov %eax, %ecx
mov (%rbx), %eax
sub $4, %rbx
shl %cl, %eax
ret
.align 32
sr: mov %eax, %ecx
mov (%rbx), %eax
sub $4, %rbx
sar %cl, %eax
ret
.align 32
cp: mov %eax, %ecx
mov (%rbx), %edi
mov -4(%rbx), %esi
sub $8, %rbx
lea (%r15,%rdi,4), %rdi
lea (%r15,%rsi,4), %rsi
cmp %eax, %eax
repe cmpsd
sete %al
movzbl %al, %eax
neg %eax
ret
.align 32
cy: mov %eax, %ecx
mov (%rbx), %edi
mov -4(%rbx), %esi
mov -8(%rbx), %eax
sub $12, %rbx
lea (%r15,%rdi,4), %rdi
lea (%r15,%rsi,4), %rsi
repe movsd
ret
.align 32
io: mov %eax, %ecx
mov (%rbx), %eax
sub $4, %rbx
cmp $7, %ecx
ja 1f
lea io_table(%rip), %rdx
movzbl (%rdx,%rcx), %ecx
lea ioa(%rip), %rdx
add %rdx, %rcx
jmp *%rcx
1: ret
ioa: push %rax
mov $1, %eax /* sys_write */
mov %eax, %edi
mov %rsp, %rsi
mov $1, %edx
syscall
pop %rax
mov (%rbx), %eax
sub $4, %rbx
ret
iob: add $4, %rbx
mov %eax, (%rbx)
xor %eax, %eax /* sys_read */
push %rax
xor %edi, %edi
mov %rsp, %rsi
mov $1, %edx
syscall
pop %rax
ret
ioc: mov %eax, %r8d
mov blocks(%rip), %rdi
call rdonly
xor %r10d, %r10d
call block_common
call close
mov %esi, %eax
ret
iod: mov %eax, %r8d
mov blocks(%rip), %rdi
call wronly
mov $1, %r10b
call block_common
call close
mov %esi, %eax
ret
ioe: jmp save_image
iof: call load_image
xor %rax, %rax
xor %r13, %r13
jmp _execute
iog: mov $65536, %r13d
ret
ioh: add $8, %rbx
mov %eax, -4(%rbx)
lea astack-4(%rip), %rdx
neg %edx
lea 4*32-8(%rbx,%rdx), %rax
shr $2, %eax
mov %eax, (%rbx)
lea (%r12,%rdx), %rax
shr $2, %eax
ret
_start: xor %eax, %eax
lea memory(%rip), %r15
lea dstack-4(%rip), %rbx
lea astack-4(%rip), %r12
xor %r13d, %r13d
lea table(%rip), %rbp
mov 8(%rsp), %rcx
or %rcx, %rcx
jz 1f
mov 16(%rsp), %rcx
or %rcx, %rcx
jz 1f
mov %rcx, blocks(%rip)
mov 24(%rsp), %rcx
or %rcx, %rcx
jz 2f
mov %rcx, rom(%rip)
jmp 3f
1: lea default_blocks(%rip), %rcx
mov %rcx, blocks(%rip)
2: lea default_rom(%rip), %rcx
mov %rcx, rom(%rip)
3: call load_image
_execute:
jmp 3f
.align 64
2: mov (%r15,%r13,4), %r14d
movzbl %r14b, %edi
shr $8, %r14d
cmp $29, %edi
ja 1f
shl $5, %edi
add %rbp, %rdi
call *%rdi
1: movzbl %r14b, %edi
shr $8, %r14d
cmp $29, %edi
ja 1f
shl $5, %edi
add %rbp, %rdi
call *%rdi
1: movzbl %r14b, %edi
shr $8, %r14d
cmp $29, %edi
ja 1f
shl $5, %edi
add %rbp, %rdi
call *%rdi
1: mov %r14d, %edi
cmp $29, %edi
ja 1f
shl $5, %edi
add %rbp, %rdi
call *%rdi
1: inc %r13
3: cmp $65536, %r13
jl 2b
mov $60, %eax /* sys_exit */
xor %edi, %edi
syscall

414
source/ilo-amd64-netbsd.s Normal file
View file

@ -0,0 +1,414 @@
/* AMD64 ilo, (c) 2023 Christopher Leonard, MIT License */
.global _start
/* rax: top of stack */
/* rbx: data stack */
/* rbp: jump table address */
/* r12: address stack */
/* r13: instruction pointer */
/* r14: opcode shift register */
/* r15: memory */
.section ".note.netbsd.ident", "a"
.long 2f-1f
.long 4f-3f
.long 1
1: .asciz "NetBSD"
2: .p2align 2
3: .long 199905
4: .p2align 2
.bss
.align 8
blocks: .skip 8 /* name of blocks file (ilo.blocks) */
rom: .skip 8 /* name of image (ilo.rom) */
dstack: .skip 32*4
astack: .skip 256*4
a: .skip 4 /* other variables for misc. purposes */
b: .skip 4
f: .skip 4
s: .skip 4
d: .skip 4
l: .skip 4
memory: .skip 65536*4
.section .rodata
default_blocks:
.asciz "ilo.blocks"
default_rom:
.asciz "ilo.rom"
io_table:
.byte 0
.byte iob-ioa
.byte ioc-ioa
.byte iod-ioa
.byte ioe-ioa
.byte iof-ioa
.byte iog-ioa
.byte ioh-ioa
.text
rdonly: mov $5, %eax /* sys_open */
xor %esi, %esi /* O_RDONLY */
mov $0666, %edx
syscall
mov %eax, %edi
ret
wronly: mov $5, %eax /* sys_open */
mov $1, %esi /* O_WRONLY */
mov $0666, %edx
syscall
mov %eax, %edi
ret
close: mov $6, %eax /* sys_close */
syscall
ret
load_image:
mov rom(%rip), %rdi
call rdonly
or %eax, %eax
jz 1f
mov %r15, %rsi
mov $65536 * 4, %edx
mov $3, %eax /* sys_read */
syscall
call close
xor %eax, %eax
lea dstack-4(%rip), %rbx
lea astack-4(%rip), %r12
xor %r13d, %r13d
1: ret
save_image:
push %rax
mov rom(%rip), %rdi
call wronly
or %eax, %eax
jz 1f
mov %r15, %rsi
mov $65536 * 4, %edx
mov $4, %eax
syscall
call close
1: pop %rax
ret
block_common:
mov $19, %eax /* sys_lseek */
mov (%rbx), %esi
shl $12, %esi
xor %edx, %edx /* SEEK_SET */
syscall
mov $3, %eax /* sys_read */
or %r10b, %r10b
jz 1f
mov $4, %al /* sys_write */
1: lea (%r15,%r8,4), %rsi
mov $4096, %edx
syscall
mov -4(%rbx), %esi
sub $8, %rbx
ret
.align 32
table: ret
.align 32
li: add $4, %rbx
inc %r13d
mov %eax, (%rbx)
mov (%r15,%r13,4), %eax
ret
.align 32
du: add $4, %rbx
mov %eax, (%rbx)
ret
.align 32
dr: mov (%rbx), %eax
sub $4, %rbx
ret
.align 32
sw: xchg (%rbx), %eax
ret
.align 32
pu: add $4, %r12
mov %eax, (%r12)
mov (%rbx), %eax
sub $4, %rbx
ret
.align 32
po: add $4, %rbx
mov %eax, (%rbx)
mov (%r12), %eax
sub $4, %r12
ret
.align 32
ju: lea -1(%eax), %r13d
mov (%rbx), %eax
sub $4, %rbx
ret
.align 32
ca: add $4, %r12
mov %r13d, (%r12)
lea -1(%eax), %r13d
mov (%rbx), %eax
sub $4, %rbx
ret
.align 32
cc: cmpl $0, (%rbx)
jz 1f
add $4, %r12
mov %r13d, (%r12)
lea -1(%eax), %r13d
1: mov -4(%rbx), %eax
sub $8, %rbx
ret
.align 32
cj: cmpl $0, (%rbx)
jz 1f
lea -1(%eax), %r13d
1: mov -4(%rbx), %eax
sub $8, %rbx
ret
.align 32
re: mov (%r12), %r13d
sub $4, %r12
ret
.align 32
eq: cmp %eax, (%rbx)
sete %al
movzbl %al, %eax
neg %eax
sub $4, %rbx
ret
.align 32
ne: cmp %eax, (%rbx)
setne %al
movzbl %al, %eax
neg %eax
sub $4, %rbx
ret
.align 32
lt: cmp %eax, (%rbx)
setl %al
movzbl %al, %eax
neg %eax
sub $4, %rbx
ret
.align 32
gt: cmp %eax, (%rbx)
setg %al
movzbl %al, %eax
neg %eax
sub $4, %rbx
ret
.align 32
fe: mov (%r15,%rax,4), %eax
ret
.align 32
st: mov (%rbx), %ecx
mov %ecx, (%r15,%rax,4)
mov -4(%rbx), %eax
sub $8, %rbx
ret
.align 32
ad: add (%rbx), %eax
sub $4, %rbx
ret
.align 32
su: sub (%rbx), %eax
neg %eax
sub $4, %rbx
ret
.align 32
mu: mull (%rbx)
sub $4, %rbx
ret
.align 32
di: mov %eax, %ecx
mov (%rbx), %eax
cdq
idiv %ecx
mov %edx, (%rbx)
ret
.align 32
an: and (%rbx), %eax
sub $4, %rbx
ret
.align 32
or: or (%rbx), %eax
sub $4, %rbx
ret
.align 32
xo: xor (%rbx), %eax
sub $4, %rbx
ret
.align 32
sl: mov %eax, %ecx
mov (%rbx), %eax
sub $4, %rbx
shl %cl, %eax
ret
.align 32
sr: mov %eax, %ecx
mov (%rbx), %eax
sub $4, %rbx
sar %cl, %eax
ret
.align 32
cp: mov %eax, %ecx
mov (%rbx), %edi
mov -4(%rbx), %esi
sub $8, %rbx
lea (%r15,%rdi,4), %rdi
lea (%r15,%rsi,4), %rsi
cmp %eax, %eax
repe cmpsd
sete %al
movzbl %al, %eax
neg %eax
ret
.align 32
cy: mov %eax, %ecx
mov (%rbx), %edi
mov -4(%rbx), %esi
mov -8(%rbx), %eax
sub $12, %rbx
lea (%r15,%rdi,4), %rdi
lea (%r15,%rsi,4), %rsi
repe movsd
ret
.align 32
io: mov %eax, %ecx
mov (%rbx), %eax
sub $4, %rbx
cmp $7, %ecx
ja 1f
lea io_table(%rip), %rdx
movzbl (%rdx,%rcx), %ecx
lea ioa(%rip), %rdx
add %rdx, %rcx
jmp *%rcx
1: ret
ioa: push %rax
mov $4, %eax /* sys_write */
mov $1, %edi
mov %rsp, %rsi
mov $1, %edx
syscall
pop %rax
mov (%rbx), %eax
sub $4, %rbx
ret
iob: add $4, %rbx
mov %eax, (%rbx)
mov $3, %eax /* sys_read */
push %rax
xor %edi, %edi
mov %rsp, %rsi
mov $1, %edx
syscall
pop %rax
ret
ioc: mov %eax, %r8d
mov blocks(%rip), %rdi
call rdonly
xor %r10d, %r10d
call block_common
call close
mov %esi, %eax
ret
iod: mov %eax, %r8d
mov blocks(%rip), %rdi
call wronly
mov $1, %r10b
call block_common
call close
mov %esi, %eax
ret
ioe: jmp save_image
iof: call load_image
xor %rax, %rax
xor %r13, %r13
jmp _execute
iog: mov $65536, %r13d
ret
ioh: add $8, %rbx
mov %eax, -4(%rbx)
lea astack-4(%rip), %rdx
neg %edx
lea 4*32-8(%rbx,%rdx), %rax
shr $2, %eax
mov %eax, (%rbx)
lea (%r12,%rdx), %rax
shr $2, %eax
ret
_start: xor %eax, %eax
lea memory(%rip), %r15
lea dstack-4(%rip), %rbx
lea astack-4(%rip), %r12
xor %r13d, %r13d
lea table(%rip), %rbp
mov 8(%rsp), %rcx
or %rcx, %rcx
jz 1f
mov 16(%rsp), %rcx
or %rcx, %rcx
jz 1f
mov %rcx, blocks(%rip)
mov 24(%rsp), %rcx
or %rcx, %rcx
jz 2f
mov %rcx, rom(%rip)
jmp 3f
1: lea default_blocks(%rip), %rcx
mov %rcx, blocks(%rip)
2: lea default_rom(%rip), %rcx
mov %rcx, rom(%rip)
3: call load_image
_execute:
jmp 3f
.align 64
2: mov (%r15,%r13,4), %r14d
movzbl %r14b, %edi
shr $8, %r14d
cmp $29, %edi
ja 1f
shl $5, %edi
add %rbp, %rdi
call *%rdi
1: movzbl %r14b, %edi
shr $8, %r14d
cmp $29, %edi
ja 1f
shl $5, %edi
add %rbp, %rdi
call *%rdi
1: movzbl %r14b, %edi
shr $8, %r14d
cmp $29, %edi
ja 1f
shl $5, %edi
add %rbp, %rdi
call *%rdi
1: mov %r14d, %edi
cmp $29, %edi
ja 1f
shl $5, %edi
add %rbp, %rdi
call *%rdi
1: inc %r13
3: cmp $65536, %r13
jl 2b
mov $1, %eax /* sys_exit */
xor %edi, %edi
syscall

439
source/ilo-amd64-openbsd.s Normal file
View file

@ -0,0 +1,439 @@
/* AMD64 ilo, (c) 2023 Christopher Leonard, MIT License */
.global _start
/* rax: top of stack */
/* rbx: data stack */
/* rbp: jump table address */
/* r12: address stack */
/* r13: instruction pointer */
/* r14: opcode shift register */
/* r15: memory */
.section ".note.openbsd.ident", "a"
.p2align 2
.long 0x8
.long 0x4
.long 0x1
.ascii "OpenBSD\0"
.long 0x0
.p2align 2
.section ".openbsd.syscalls"
.long rd0
.long $5
.long rd1
.long $5
.long rd2
.long $6
.long rd3
.long $3
.long rd4
.long $4
.long rd5
.long $0xA6
.long rd6
.long $3
.long rd6
.long $4
.long rd7
.long $4
.long rd8
.long $3
.long rd9
.long $1
.bss
.align 8
blocks: .skip 8 /* name of blocks file (ilo.blocks) */
rom: .skip 8 /* name of image (ilo.rom) */
dstack: .skip 32*4
astack: .skip 256*4
a: .skip 4 /* other variables for misc. purposes */
b: .skip 4
f: .skip 4
s: .skip 4
d: .skip 4
l: .skip 4
memory: .skip 65536*4
.section .rodata
default_blocks:
.asciz "ilo.blocks"
default_rom:
.asciz "ilo.rom"
io_table:
.byte 0
.byte iob-ioa
.byte ioc-ioa
.byte iod-ioa
.byte ioe-ioa
.byte iof-ioa
.byte iog-ioa
.byte ioh-ioa
.text
rdonly: mov $5, %eax /* sys_open */
xor %esi, %esi /* O_RDONLY */
mov $0666, %edx
rd0: syscall
mov %eax, %edi
ret
wronly: mov $5, %eax /* sys_open */
mov $1, %esi /* O_WRONLY */
mov $0666, %edx
rd1: syscall
mov %eax, %edi
ret
close: mov $6, %eax /* sys_close */
rd2: syscall
ret
load_image:
mov rom(%rip), %rdi
call rdonly
or %eax, %eax
jz 1f
mov %r15, %rsi
mov $65536 * 4, %edx
mov $3, %eax /* sys_read */
rd3: syscall
call close
xor %eax, %eax
lea dstack-4(%rip), %rbx
lea astack-4(%rip), %r12
xor %r13d, %r13d
1: ret
save_image:
push %rax
mov rom(%rip), %rdi
call wronly
or %eax, %eax
jz 1f
mov %r15, %rsi
mov $65536 * 4, %edx
mov $4, %eax
rd4: syscall
call close
1: pop %rax
ret
block_common:
mov $0xA6, %eax /* sys_lseek */
mov (%rbx), %esi
shl $12, %esi
xor %edx, %edx /* SEEK_SET */
rd5: syscall
mov $3, %eax /* sys_read */
or %r10b, %r10b
jz 1f
mov $4, %al /* sys_write */
1: lea (%r15,%r8,4), %rsi
mov $4096, %edx
rd6: syscall
mov -4(%rbx), %esi
sub $8, %rbx
ret
.align 32
table: ret
.align 32
li: add $4, %rbx
inc %r13d
mov %eax, (%rbx)
mov (%r15,%r13,4), %eax
ret
.align 32
du: add $4, %rbx
mov %eax, (%rbx)
ret
.align 32
dr: mov (%rbx), %eax
sub $4, %rbx
ret
.align 32
sw: xchg (%rbx), %eax
ret
.align 32
pu: add $4, %r12
mov %eax, (%r12)
mov (%rbx), %eax
sub $4, %rbx
ret
.align 32
po: add $4, %rbx
mov %eax, (%rbx)
mov (%r12), %eax
sub $4, %r12
ret
.align 32
ju: lea -1(%eax), %r13d
mov (%rbx), %eax
sub $4, %rbx
ret
.align 32
ca: add $4, %r12
mov %r13d, (%r12)
lea -1(%eax), %r13d
mov (%rbx), %eax
sub $4, %rbx
ret
.align 32
cc: cmpl $0, (%rbx)
jz 1f
add $4, %r12
mov %r13d, (%r12)
lea -1(%eax), %r13d
1: mov -4(%rbx), %eax
sub $8, %rbx
ret
.align 32
cj: cmpl $0, (%rbx)
jz 1f
lea -1(%eax), %r13d
1: mov -4(%rbx), %eax
sub $8, %rbx
ret
.align 32
re: mov (%r12), %r13d
sub $4, %r12
ret
.align 32
eq: cmp %eax, (%rbx)
sete %al
movzbl %al, %eax
neg %eax
sub $4, %rbx
ret
.align 32
ne: cmp %eax, (%rbx)
setne %al
movzbl %al, %eax
neg %eax
sub $4, %rbx
ret
.align 32
lt: cmp %eax, (%rbx)
setl %al
movzbl %al, %eax
neg %eax
sub $4, %rbx
ret
.align 32
gt: cmp %eax, (%rbx)
setg %al
movzbl %al, %eax
neg %eax
sub $4, %rbx
ret
.align 32
fe: mov (%r15,%rax,4), %eax
ret
.align 32
st: mov (%rbx), %ecx
mov %ecx, (%r15,%rax,4)
mov -4(%rbx), %eax
sub $8, %rbx
ret
.align 32
ad: add (%rbx), %eax
sub $4, %rbx
ret
.align 32
su: sub (%rbx), %eax
neg %eax
sub $4, %rbx
ret
.align 32
mu: mull (%rbx)
sub $4, %rbx
ret
.align 32
di: mov %eax, %ecx
mov (%rbx), %eax
cdq
idiv %ecx
mov %edx, (%rbx)
ret
.align 32
an: and (%rbx), %eax
sub $4, %rbx
ret
.align 32
or: or (%rbx), %eax
sub $4, %rbx
ret
.align 32
xo: xor (%rbx), %eax
sub $4, %rbx
ret
.align 32
sl: mov %eax, %ecx
mov (%rbx), %eax
sub $4, %rbx
shl %cl, %eax
ret
.align 32
sr: mov %eax, %ecx
mov (%rbx), %eax
sub $4, %rbx
sar %cl, %eax
ret
.align 32
cp: mov %eax, %ecx
mov (%rbx), %edi
mov -4(%rbx), %esi
sub $8, %rbx
lea (%r15,%rdi,4), %rdi
lea (%r15,%rsi,4), %rsi
cmp %eax, %eax
repe cmpsd
sete %al
movzbl %al, %eax
neg %eax
ret
.align 32
cy: mov %eax, %ecx
mov (%rbx), %edi
mov -4(%rbx), %esi
mov -8(%rbx), %eax
sub $12, %rbx
lea (%r15,%rdi,4), %rdi
lea (%r15,%rsi,4), %rsi
repe movsd
ret
.align 32
io: mov %eax, %ecx
mov (%rbx), %eax
sub $4, %rbx
cmp $7, %ecx
ja 1f
lea io_table(%rip), %rdx
movzbl (%rdx,%rcx), %ecx
lea ioa(%rip), %rdx
add %rdx, %rcx
jmp *%rcx
1: ret
ioa: push %rax
mov $4, %eax /* sys_write */
mov $1, %edi
mov %rsp, %rsi
mov $1, %edx
rd7: syscall
pop %rax
mov (%rbx), %eax
sub $4, %rbx
ret
iob: add $4, %rbx
mov %eax, (%rbx)
mov $3, %eax /* sys_read */
push %rax
xor %edi, %edi
mov %rsp, %rsi
mov $1, %edx
rd8: syscall
pop %rax
ret
ioc: mov %eax, %r8d
mov blocks(%rip), %rdi
call rdonly
xor %r10d, %r10d
call block_common
call close
mov %esi, %eax
ret
iod: mov %eax, %r8d
mov blocks(%rip), %rdi
call wronly
mov $1, %r10b
call block_common
call close
mov %esi, %eax
ret
ioe: jmp save_image
iof: call load_image
xor %rax, %rax
xor %r13, %r13
jmp _execute
iog: mov $65536, %r13d
ret
ioh: add $8, %rbx
mov %eax, -4(%rbx)
lea astack-4(%rip), %rdx
neg %edx
lea 4*32-8(%rbx,%rdx), %rax
shr $2, %eax
mov %eax, (%rbx)
lea (%r12,%rdx), %rax
shr $2, %eax
ret
_start: xor %eax, %eax
lea memory(%rip), %r15
lea dstack-4(%rip), %rbx
lea astack-4(%rip), %r12
xor %r13d, %r13d
lea table(%rip), %rbp
mov 8(%rsp), %rcx
or %rcx, %rcx
jz 1f
mov 16(%rsp), %rcx
or %rcx, %rcx
jz 1f
mov %rcx, blocks(%rip)
mov 24(%rsp), %rcx
or %rcx, %rcx
jz 2f
mov %rcx, rom(%rip)
jmp 3f
1: lea default_blocks(%rip), %rcx
mov %rcx, blocks(%rip)
2: lea default_rom(%rip), %rcx
mov %rcx, rom(%rip)
3: call load_image
_execute:
jmp 3f
.align 64
2: mov (%r15,%r13,4), %r14d
movzbl %r14b, %edi
shr $8, %r14d
cmp $29, %edi
ja 1f
shl $5, %edi
add %rbp, %rdi
call *%rdi
1: movzbl %r14b, %edi
shr $8, %r14d
cmp $29, %edi
ja 1f
shl $5, %edi
add %rbp, %rdi
call *%rdi
1: movzbl %r14b, %edi
shr $8, %r14d
cmp $29, %edi
ja 1f
shl $5, %edi
add %rbp, %rdi
call *%rdi
1: mov %r14d, %edi
cmp $29, %edi
ja 1f
shl $5, %edi
add %rbp, %rdi
call *%rdi
1: inc %r13
3: cmp $65536, %r13
jl 2b
mov $1, %eax /* sys_exit */
xor %edi, %edi
rd9: syscall

205
source/ilo-banked.c Normal file
View file

@ -0,0 +1,205 @@
/***************************************************************
crc's _ _
(_) | ___
| | |/ _ \ a tiny virtual computer
| | | (_) | 64kw RAM, 32-bit, Dual Stack, MISC
|_|_|\___/ ilo.c (c) charles childers
**************************************************************/
/* This implementation uses memory separated into multiple
banks. This makes it easier to run on systems with less
RAM. */
#include <stdio.h>
#include <stdlib.h>
#define SLICES 64
#define SLICESIZE (65536/SLICES)
int ip, sp, rp, data[33], address[257];
char *blocks, *rom;
#ifdef MALLOC
int *memory[SLICES];
#else
int memory[SLICES][SLICESIZE];
#endif
#define TOS data[sp]
#define NOS data[sp-1]
#define TORS address[rp]
int stack_pop() {
sp--;
return data[sp + 1];
}
void stack_push(int value) {
sp++;
data[sp] = value;
}
void store(int a, int v) {
int slice = a / SLICESIZE;
int actual = a - (slice * SLICESIZE);
memory[slice][actual] = v;
}
int fetch(int a) {
int slice = a / SLICESIZE;
int 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;
int x, y;
fp = fopen(rom, "rb");
for (y = 0; y < 65536; y++) {
x = 0;
fread(&x, 4, 1, fp);
store(y, x);
}
fclose(fp);
prepare_vm();
}
void save_image() {
FILE *fp;
int i;
fp = fopen(rom, "wb");
for (i = 0; i < SLICES; i++)
fwrite(&memory[i], sizeof(int), SLICESIZE, fp);
fclose(fp);
}
void read_block() {
FILE *f;
int block, buffer, x, c;
buffer = stack_pop();
block = stack_pop();
f = fopen(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, c);
}
fclose(f);
}
void write_block() {
FILE *f;
int block, buffer, x, c;
buffer = stack_pop();
block = stack_pop();
f = fopen(blocks, "r+b");
fseek(f, 4096 * block, SEEK_SET);
for (x = 0; x < 1024; x++) {
c = fetch(buffer + x);
fwrite(&c, 4, 1, f);
}
fclose(f);
}
void process(int o) {
int a, b, target, flag;
int src, dest, len;
switch (o) {
case 0: break;
case 1: ip++; stack_push(fetch(ip)); break;
case 2: stack_push(TOS); break;
case 3: data[sp] = 0; sp--; break;
case 4: a = TOS; TOS = NOS; NOS = a; break;
case 5: rp++; TORS = stack_pop(); break;
case 6: stack_push(TORS); rp--; break;
case 7: ip = stack_pop() - 1; break;
case 8: rp++; TORS = ip; ip = stack_pop() - 1; break;
case 9: target = stack_pop(); flag = stack_pop();
if (flag != 0) { rp++; TORS = ip; ip = target - 1; }
break;
case 10: target = stack_pop(); flag = stack_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 = stack_pop(); dest = stack_pop();
src = stack_pop(); flag = -1;
while (len) {
if (fetch(dest) != fetch(src)) flag = 0;
len -= 1; src += 1; dest += 1;
}; stack_push(flag); break;
case 28: len = stack_pop(); dest = stack_pop();
src = stack_pop();
while (len) {
store(dest, fetch(src));
len -= 1; src += 1; dest += 1;
}; break;
case 29: switch (stack_pop()) {
case 0: putc(stack_pop(), stdout); break;
case 1: stack_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: stack_push(sp); stack_push(rp); break;
default: break;
} break;
default: break;
}
}
void process_opcode_bundle(int opcode) {
process(opcode & 0xFF);
process((opcode >> 8) & 0xFF);
process((opcode >> 16) & 0xFF);
process((opcode >> 24) & 0xFF);
}
void execute(int address) {
ip = address;
while (ip < 65536) {
process_opcode_bundle(fetch(ip));
ip++;
}
}
int main(int argc, char **argv) {
int i;
blocks = (argc > 1) ? argv[1] : "ilo.blocks";
rom = (argc > 2) ? argv[2] : "ilo.rom";
#ifdef MALLOC
for (i = 0; i < SLICES; i++)
memory[i] = malloc(SLICESIZE * sizeof(int));
#endif
load_image();
execute(0);
#ifdef MALLOC
for (i = 0; i < SLICES; i++)
free(memory[i]);
#endif
for (i = 1; sp >= i; i++) printf(" %d", data[i]);
printf("\n");
}

215
source/ilo-be.c Normal file
View file

@ -0,0 +1,215 @@
/***************************************************************
crc's _ _
(_) | ___
| | |/ _ \ a tiny virtual computer
| | | (_) | 64kw RAM, 32-bit, Dual Stack, MISC
|_|_|\___/ ilo-be.c (c) charles childers
ilo was developed on little endian hosts, and both the ROM and
blocks are stored in little endian. This implementation adds
alternative ROM & block functions to handle the byteswapping
needed on big endian hosts.
**************************************************************/
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#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 V void
#define I int
#define C char
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) */
/* the other variables are used by the various
functions for misc. purposes */
I a, b, f, s, d, l;
C i[1];
unsigned long byteswap(unsigned long v) {
return (((v & 0x000000FF) << 24)|
((v & 0x0000FF00) << 8) |
((v & 0x00FF0000) >> 8) |
((v & 0xFF000000) >> 24));
}
V push(I v) { ds[sp + 1] = v; sp += 1; }
I pop() { sp -= 1; return ds[sp + 1]; }
V load_image() {
FILE *fp;
long x, y, z;
fp = fopen(rom, "rb");
for (y = 0; y < 65536; y++) {
x = 0;
fread(&x, 4, 1, fp);
m[y] = byteswap(x);
}
fclose(fp);
ip = sp = rp = 0;
}
V save_image() {
FILE *fp;
long i, x;
fp = fopen(rom, "wb");
for (i = 0; i < 65536; i++) {
x = byteswap(m[i]);
fwrite(&x, 4, 1, fp);
}
fclose(fp);
}
V read_block() {
FILE *f;
long block, buffer, x, c;
buffer = pop();
block = pop();
f = fopen(blocks, "r+b");
fseek(f, 4096 * block, SEEK_SET);
for (x = 0; x < 1024; x++) {
c = 0;
fread(&c, 4, 1, f);
m[buffer + x] = byteswap(c);
}
fclose(f);
}
V write_block() {
FILE *f;
long block, buffer, x, c;
buffer = pop();
block = pop();
f = fopen(blocks, "r+b");
fseek(f, 4096 * block, SEEK_SET);
for (x = 0; x < 1024; x++) {
c = byteswap(m[buffer + x]);
fwrite(&c, 4, 1, f);
}
fclose(f);
}
V save_ip() { rp += 1; R = ip; }
V symmetric() { if (b >= 0 && N < 0) { T += 1; N -= b; } }
V li() { ip += 1; push(m[ip]); }
V du() { push(T); }
V dr() { ds[sp] = 0; sp -= 1; }
V sw() { a = T; T = N; N = a; }
V pu() { rp += 1; R = pop(); }
V po() { push(R); rp -= 1; }
V ju() { ip = pop() - 1; }
V ca() { save_ip(); ip = pop() - 1; }
V cc() { a = pop(); if (pop()) { save_ip(); ip = a - 1; } }
V cj() { a = pop(); if (pop()) { ip = a - 1; } }
V re() { ip = R; rp -= 1; }
V eq() { N = (N == T) ? -1 : 0; sp -= 1; }
V ne() { N = (N != T) ? -1 : 0; sp -= 1; }
V lt() { N = (N < T) ? -1 : 0; sp -= 1; }
V gt() { N = (N > T) ? -1 : 0; sp -= 1; }
V fe() { T = m[T]; }
V st() { m[T] = N; sp -= 2; }
V ad() { N += T; sp -= 1; }
V su() { N -= T; sp -= 1; }
V mu() { N *= T; sp -= 1; }
V di() { a = T; b = N; T = b / a; N = b % a; symmetric(); }
V an() { N = T & N; sp -= 1; }
V or() { N = T | N; sp -= 1; }
V xo() { N = T ^ N; sp -= 1; }
V sl() { N = N << T; sp -= 1; }
V sr() { N = N >> T; sp -= 1; }
V cp() { l = pop(); d = pop(); s = T; T = -1;
while (l) { if (m[d] != m[s]) { T = 0; }
l -= 1; s += 1; d += 1; } }
V cy() { l = pop(); d = pop(); s = pop();
while (l) { m[d] = m[s]; l -= 1; s += 1; d += 1; } }
V ioa() { i[0] = (char)pop(); write(1, &i, 1); }
V iob() { read(0, &i, 1); push(i[0]); }
V ioc() { read_block(); }
V iod() { write_block(); }
V ioe() { save_image(); }
V iof() { load_image(); ip = -1; }
V iog() { ip = 65536; }
V ioh() { push(sp); push(rp); }
V io() {
switch (pop()) {
case 0: ioa(); break; case 1: iob(); break;
case 2: ioc(); break; case 3: iod(); break;
case 4: ioe(); break; case 5: iof(); break;
case 6: iog(); break; case 7: ioh(); break;
default: break;
}
}
/* Using a switch here instead of a jump table to avoid */
/* some issues w/relocation stuff when building w/o libc */
V process(I o) {
switch (o) {
case 0: break; case 1: li(); break;
case 2: du(); break; case 3: dr(); break;
case 4: sw(); break; case 5: pu(); break;
case 6: po(); break; case 7: ju(); break;
case 8: ca(); break; case 9: cc(); break;
case 10: cj(); break; case 11: re(); break;
case 12: eq(); break; case 13: ne(); break;
case 14: lt(); break; case 15: gt(); break;
case 16: fe(); break; case 17: st(); break;
case 18: ad(); break; case 19: su(); break;
case 20: mu(); break; case 21: di(); break;
case 22: an(); break; case 23: or(); break;
case 24: xo(); break; case 25: sl(); break;
case 26: sr(); break; case 27: cp(); break;
case 28: cy(); break; case 29: io(); break;
default: break;
}
}
V process_bundle(I opcode) {
process(opcode & 0xFF);
process((opcode >> 8) & 0xFF);
process((opcode >> 16) & 0xFF);
process((opcode >> 24) & 0xFF);
}
V execute() {
while (ip < 65536) {
process_bundle(m[ip]);
ip += 1;
}
}
#ifndef NOSTDLIB
I main(I argc, C **argv) {
blocks = (argc > 1) ? argv[1] : "ilo.blocks";
rom = (argc > 2) ? argv[2] : "ilo.rom";
load_image();
execute();
for (; sp > 0; sp -= 1) printf(" %d", ds[sp]); printf("\n");
return 0;
}
#else
I main(I argc, C **argv) {
blocks = "ilo.blocks";
rom = "ilo.rom";
load_image();
execute();
return 0;
}
#endif

191
source/ilo-dos.c Normal file
View file

@ -0,0 +1,191 @@
/***************************************************************
crc's _ _
(_) | ___
| | |/ _ \ a tiny virtual computer
| | | (_) | 64kw RAM, 32-bit, Dual Stack, MISC
|_|_|\___/ ilo.c (c) charles childers
**************************************************************/
/* This implementation uses memory separated into multiple
banks. This makes it easier to run on systems with less
RAM. */
#include <stdio.h>
#include <stdlib.h>
#define SLICES 8
#define SLICESIZE 8192
long ip, sp, rp, data[33], address[257];
long *memory[SLICES];
#define TOS data[sp]
#define NOS data[sp-1]
#define TORS address[rp]
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;
fp = fopen("ilo.rom", "rb");
for (y = 0; y < 65536; y++) {
x = 0;
fread(&x, 4, 1, fp);
store(y, x);
}
fclose(fp);
prepare_vm();
}
void save_image() {
FILE *fp;
long i;
fp = fopen("ilo.rom", "wb");
for (i = 0; i < SLICES; i++)
fwrite(&memory[i], sizeof(long), SLICESIZE, fp);
fclose(fp);
}
void read_block() {
FILE *f;
long block, buffer, x, c;
buffer = pop();
block = pop();
f = fopen("ilo.blo", "r+b");
fseek(f, 4096 * block, SEEK_SET);
for (x = 0; x < 1024; x++) {
c = 0;
fread(&c, 4, 1, f);
store(buffer + x, c);
}
fclose(f);
}
void write_block() {
FILE *f;
long block, buffer, x, c;
buffer = pop();
block = pop();
f = fopen("ilo.blo", "r+b");
fseek(f, 4096 * block, SEEK_SET);
for (x = 0; x < 1024; x++) {
c = 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 process_opcode_bundle(long opcode) {
process(opcode & 0xFF);
process((opcode >> 8) & 0xFF);
process((opcode >> 16) & 0xFF);
process((opcode >> 24) & 0xFF);
}
void execute(long address) {
ip = address;
while (ip < 65536) {
process_opcode_bundle(fetch(ip));
ip++;
}
}
int 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");
}

701
source/ilo-js.html Normal file
View file

@ -0,0 +1,701 @@
<!DOCTYPE html>
<html lang="en">
<head>
<title>ilo.js :: Konilo in the Browser</title>
<meta charset="utf-8">
<script>
// LocalData, (c) 2016 Pawel; MIT Licensed
(function() {
var win = typeof window !== 'undefined' ? window : {}
var indexedDB = win.indexedDB || win.mozIndexedDB || win.webkitIndexedDB || win.msIndexedDB;
if (typeof window !== 'undefined' && !indexedDB) {
console.error('indexDB not supported');
return;
}
var db,
request = indexedDB.open('ldb', 1);
request.onsuccess = function(evt) {
db = this.result;
};
request.onerror = function(event) {
console.error('indexedDB request error');
console.log(event);
};
request.onupgradeneeded = function(event) {
db = null;
var store = event.target.result.createObjectStore('s', {
keyPath: 'k'
});
store.transaction.oncomplete = function (e){
db = e.target.db;
};
};
// if using proxy mode comment this
var ldb = {
ready: false,
get: function(key, callback) {
if (!db) {
setTimeout(function () { ldb.get(key, callback); }, 50);
return;
}
db.transaction('s').objectStore('s').get(key).onsuccess = function(event) {
var result = (event.target.result && event.target.result['v']) || null;
callback(result);
};
},
set: function(key, value, callback) {
if (!db) {
setTimeout(function () { ldb.set(key, value, callback); }, 50);
return;
}
let txn = db.transaction('s', 'readwrite');
txn.oncomplete = function(event) {
var toString$ = {}.toString;
if (toString$.call(callback).slice(8, -1) === 'Function') {
callback();
}
}
txn.objectStore('s').put({
'k': key,
'v': value,
});
txn.commit();
},
delete: function(key, callback) {
if (!db) {
setTimeout(function () { ldb.delete(key, callback); }, 50);
return;
}
db.transaction('s', 'readwrite').objectStore('s').delete(key).onsuccess = function(event) {
if (callback) callback();
};
},
list: function(callback) {
if (!db) {
setTimeout(function () { ldb.list(callback); }, 50);
return;
}
db.transaction('s').objectStore('s').getAllKeys().onsuccess = function(event) {
var result = (event.target.result) || null;
callback(result);
};
},
getAll: function(callback) {
if (!db) {
setTimeout(function () { ldb.getAll(callback); }, 50);
return;
}
db.transaction('s').objectStore('s').getAll().onsuccess = function(event) {
var result = (event.target.result) || null;
callback(result);
};
},
clear: function(callback) {
if (!db) {
setTimeout(function () { ldb.clear(callback); }, 50);
return;
}
db.transaction('s', 'readwrite').objectStore('s').clear().onsuccess = function(event) {
if (callback) callback();
};
},
}
const exported = {
'get': ldb.get,
'set': ldb.set,
'delete': ldb.delete,
'list': ldb.list,
'getAll': ldb.getAll,
'clear': ldb.clear,
};
win['ldb'] = exported
if (typeof module !== 'undefined') {
module.exports = exported;
}
})();
</script>
<script>
let m = new Int32Array(65536);
let blocks = new Int32Array(1024*1024);
var ds = new Int32Array(33);
var as = new Int32Array(257);
var ip = 0;
var sp = 0;
var rp = 0;
var input = "";
function push(v) {
ds[sp + 1] = v;
sp += 1;
}
function pop() {
sp -= 1;
return ds[sp + 1];
}
function download_blocks(int32Array, filename) {
var uint8Array = new Uint8Array(int32Array.buffer);
var blob = new Blob([uint8Array], { type: 'application/octet-stream' });
var link = document.createElement('a');
link.href = URL.createObjectURL(blob);
link.download = filename;
link.click();
URL.revokeObjectURL(link.href);
}
function get_file(f, target) {
fetch(f)
.then(response => response.arrayBuffer())
.then(buffer => {
const dataView = new DataView(buffer);
for (let i = 0; i < target.length; i++) {
target[i] = dataView.getInt32(i * 4, true);
}
})
.catch(error => {
console.error('Error loading the file:', error);
});
}
function upload(file, target) {
var reader = new FileReader();
reader.onload = function(event) {
var arrayBuffer = event.target.result;
var dataView = new Int32Array(arrayBuffer);
target.set(dataView);
};
reader.readAsArrayBuffer(file);
}
function enforce32BitSignedInteger(value) {
const int32Max = Math.pow(2, 31) - 1;
const int32Min = -Math.pow(2, 31);
value = value | 0;
value = ((value - int32Min) % (int32Max - int32Min + 1)) + int32Min;
return value;
}
function guard() {
ds[sp] = enforce32BitSignedInteger(ds[sp]);
if (sp >= 2) {
ds[sp - 1] = enforce32BitSignedInteger(ds[sp - 1]);
}
}
function save_ip() {
rp += 1;
as[rp] = ip;
}
var max_lines = 256;
var cycles = 25000;
function limit_output_lines() {
const display = document.getElementById('display');
const lines = display.value.split('\n').slice(-(1+max_lines));
let k = '';
let i = '';
for (i in lines) {
k = k.concat(lines[i], '\n');
}
display.value = k.substring(0, k.length - 1);
}
async function sleep(ms) {
const display = document.getElementById("display")
display.scrollTop = display.scrollHeight;
console.log('sleep()');
limit_output_lines();
return new Promise((resolve) => setTimeout(resolve, ms));
}
function no() { }
function li() {
ip += 1;
push(m[ip]);
}
function du() {
push(ds[sp]);
}
function dr() {
ds[sp] = 0;
sp -= 1;
}
function sw() {
const a = ds[sp];
ds[sp] = ds[sp - 1];
ds[sp - 1] = a;
}
function pu() {
rp += 1;
as[rp] = pop();
}
function po() {
push(as[rp]);
rp -= 1;
}
function ju() {
ip = pop() - 1;
}
function ca() {
save_ip();
ip = pop() - 1;
}
function cc() {
var a = pop();
if (pop()) {
save_ip();
ip = a - 1;
}
}
function cj() {
var a = pop();
if (pop()) {
ip = a - 1;
}
}
function re() {
ip = as[rp];
rp -= 1;
}
function eq() {
ds[sp - 1] = (ds[sp - 1] == ds[sp]) ? -1 : 0;
sp -= 1;
}
function ne() {
ds[sp - 1] = (ds[sp - 1] != ds[sp]) ? -1 : 0;
sp -= 1;
}
function lt() {
ds[sp - 1] = (ds[sp - 1] < ds[sp]) ? -1 : 0;
sp -= 1;
}
function gt() {
ds[sp - 1] = (ds[sp - 1] > ds[sp]) ? -1 : 0;
sp -= 1;
}
function fe() {
ds[sp] = m[ds[sp]];
}
function st() {
m[ds[sp]] = ds[sp - 1];
sp -= 2;
}
function ad() {
ds[sp - 1] += ds[sp];
sp -= 1;
}
function su() {
ds[sp - 1] -= ds[sp];
sp -= 1;
}
function mu() {
ds[sp - 1] *= ds[sp];
sp -= 1;
}
function di() {
const a = ds[sp];
const b = ds[sp - 1];
ds[sp] = Math.floor(b / a);
ds[sp - 1] = b % a;
if (b >= 0 && ds[sp - 1] < 0) {
ds[sp] += 1;
ds[sp - 1] -= b;
}
}
function an() {
ds[sp - 1] = ds[sp] & ds[sp - 1];
sp -= 1;
}
function or() {
ds[sp - 1] = ds[sp] | ds[sp - 1];
sp -= 1;
}
function xo() {
ds[sp - 1] = ds[sp] ^ ds[sp - 1];
sp -= 1;
}
function sl() {
ds[sp - 1] = ds[sp - 1] << ds[sp];
sp -= 1;
}
function sr() {
ds[sp - 1] = ds[sp - 1] >> ds[sp];
sp -= 1;
}
function cp() {
let l = pop();
let d = pop();
let s = ds[sp];
ds[sp] = -1;
while (l) {
if (m[d] !== m[s]) {
ds[sp] = 0;
}
l -= 1;
s += 1;
d += 1;
}
}
function cy() {
let l = pop();
let d = pop();
let s = pop();
while (l) {
m[d] = m[s];
l -= 1;
s += 1;
d += 1;
}
}
function ioa() {
const a = String.fromCharCode(pop());
document.getElementById("display").value += a;
}
function iob() {
const a = input.charCodeAt(0);
input = input.slice(1);
push(a);
}
function ioc() {
const buf = pop();
const blk = pop();
let i = 0;
while (i < 1024) {
m[buf + i] = blocks[(blk * 1024) + i];
i += 1;
}
}
function iod() {
const buf = pop();
const blk = pop();
let i = 0;
while (i < 1024) {
blocks[(blk * 1024) + i] = m[buf + i];
i += 1;
}
}
function ioe() { }
function iof() {
ip = -1; sp = 0; rp = 0;
get_file('ilo.rom', m);
}
function iog() {
ip = 65536;
input = "";
}
function ioh() {
push(sp); push(rp);
}
function io() {
var dev = pop();
switch (dev) {
case 0: ioa(); break;
case 1: iob(); break;
case 2: ioc(); break;
case 3: iod(); break;
case 4: ioe(); break;
case 5: iof(); break;
case 6: iog(); break;
case 7: ioh(); break;
default: console.log("wtf? " + dev); break;
}
}
const instructions = [
no, li, du, dr, sw,
pu, po, ju, ca, cc,
cj, re, eq, ne, lt,
gt, fe, st, ad, su,
mu, di, an, or, xo,
sl, sr, cp, cy, io
];
function process(o) {
if (o >= 0 && o < instructions.length) {
instructions[o]();
}
guard();
}
async function execute() {
input += " " + document.getElementById("input").value + " \n";
document.getElementById("input").value = "";
let ticks = 0;
while ((ip < 65536) && input.length >= 1 && !isNaN(ip)) {
var o = m[ip];
process(o & 0xff);
process((o >> 8) & 0xff);
process((o >> 16) & 0xff);
process((o >> 24) & 0xff);
ip = ip + 1;
ticks += 1;
if (ticks % cycles === 0) {
ticks = 0;
await sleep(0);
}
}
await sleep(0);
console.log("done");
document.getElementById("display").scrollTop =
document.getElementById("display").scrollHeight;
}
function use_default() {
ip = -1; sp = 0; rp = 0;
execute();
}
async function startup() {
load_prefs();
var load_rom = document.getElementById("rom-file");
load_rom.addEventListener("change", function(event) {
var file = event.target.files[0];
upload(file, m);
});
var load_blocks = document.getElementById("block-file");
load_blocks.addEventListener("change", function(event) {
var file = event.target.files[0];
upload(file, blocks);
});
var enter = document.getElementById("input").addEventListener('keypress', function(event) {
if (event.key === 'Enter') {
execute();
}
});
get_file('ilo.rom', m);
get_file('ilo.blocks', blocks);
await sleep(5000);
use_default();
}
</script>
<style>
:root {
--bg:#050505;
--fg:#ffd;
}
table {
border: 0;
width: 100%;
}
td {
width: 50%;
vertical-align: top;
}
* {
font-family: "Anonymous Pro", "Go Mono", monospace;
padding: 3px;
background: #111;
color: #ffd;
outline-width: 1px;
outline-color: #000;
outline-style: outset;
margin: 2px;
font-size: min(2vh, 2vw);
}
body {
background: #111;
color: #fec;
outline-style: none;
}
textarea {
background: var(--bg);
color: var(--fg);
display: block;
margin-left: auto;
margin-right: auto;
width: min(90vh,90vw);
height: min(55vh,55vw);
font-size: min(2vh, 2vw);
}
input, button {
background: #3b3b3b;
color: #fafada;
}
hr,br {
background: #fff;
margin-bottom: .3vh;
padding-bottom:.005vh;
}
#settings {
display: none;
}
td {
vertical-align: top;
}
</style>
<script>
function localLoad(key, defaultValue) {
const storedValue = localStorage.getItem(key);
return storedValue !== null ? storedValue : defaultValue;
}
function load_prefs() {
let a = localLoad('fg', '#ffb000');
let b = localLoad('bg', '#050505');
document.querySelector(':root').style.setProperty('--fg', a);
document.querySelector(':root').style.setProperty('--bg', b);
cycles = parseInt(localLoad('cycles', 25000));
max_lines = parseInt(localLoad('max_lines', 256));
document.getElementById('input_cycles').value = cycles;
document.getElementById('input_max_lines').value = max_lines;
}
function save_prefs() {
let a = document.querySelector(':root').style.getPropertyValue('--fg');
let b = document.querySelector(':root').style.getPropertyValue('--bg');
localStorage.setItem('fg', a);
localStorage.setItem('bg', b);
localStorage.setItem('cycles', cycles);
localStorage.setItem('max_lines', max_lines);
}
function toggle(x) {
const e = document.getElementById(x);
e.style.display = e.style.display == "block" ? "none" : "block";
}
function default_colors() {
document.querySelector(':root').style.setProperty('--fg', '#ffb000');
document.querySelector(':root').style.setProperty('--bg', '#050505');
}
function green_colors() {
document.querySelector(':root').style.setProperty('--fg', '#33ff33');
document.querySelector(':root').style.setProperty('--bg', '#050505');
}
function cyan_colors() {
document.querySelector(':root').style.setProperty('--fg', '#80ffd5');
document.querySelector(':root').style.setProperty('--bg', '#050505');
}
function plasma_colors() {
document.querySelector(':root').style.setProperty('--fg', '#fe3d14');
document.querySelector(':root').style.setProperty('--bg', '#400f15');
}
function dark_colors() {
document.querySelector(':root').style.setProperty('--fg', '#ffd');
document.querySelector(':root').style.setProperty('--bg', '#050505');
}
function light_colors() {
document.querySelector(':root').style.setProperty('--fg', '#050505');
document.querySelector(':root').style.setProperty('--bg', '#ffd');
}
</script>
</head>
<body onload="startup()"> <!-- startup -->
<button type="button" id="b_settings" onclick="toggle('settings')">Settings</button>
<button type="button" id="boot" onclick="use_default()">
Start Konilo</button> (using default image &amp; blocks)
<hr>
<div id="settings">
<table>
<tr><td>
Use your own image &amp; blocks.<br> <hr> <br>
ROM :::: <input type="file" id="rom-file" style="width:30vw"> <br>
Blocks : <input type="file" id="block-file" style="width:30vw"> <br>
<button type="button" id="b_boot_user" onclick="execute()">Boot</button> <hr>
<button type="button" id="getblocks" onclick="download_blocks(blocks,'ilo.blocks')">Save Blocks to Device</button>
</td><td>
--CONFIG-- <br> <hr> <br>
Max lines :::::::::::::: <input type="number" id="input_max_lines" min="1"
value="256" onchange="max_lines=parseInt(this.value)" style="width:15vw"> <br>
Cycles Between Updates : <input type="number" id="input_cycles" min="1"
value="25000" onchange="cycles=parseInt(this.value)" style="width:15vw"> <br>
<hr> COLORS
<button type="button" id="b_default" onclick="default_colors()">default</button>
<button type="button" id="b_green" onclick="green_colors()">green</button>
<button type="button" id="b_cyan" onclick="cyan_colors()">cyan</button>
<button type="button" id="b_plasma" onclick="plasma_colors()">plasma</button>
<button type="button" id="b_light" onclick="light_colors()">light</button>
<button type="button" id="b_dark" onclick="dark_colors()">dark</button>
<button type="button" id="b_save_prefs" onclick="save_prefs()">Save Prefrrences</button>
</td></tr>
</table>
<hr>
</div>
<textarea rows="24" cols="80" id="display" readonly></textarea>
<hr>
<input type="text" style="width: 80vw" id="input">
<button type="button" id="enter" onclick="execute()">Enter</button>
</body>
<!-- TODO
add custom themes
add indicator for reading/writing blocks
add indicator for processing + animation
-->
<!-- CHANGELOG
Change default cycles value.
Added ability to save config + auto loading on page load.
Amber is now default, previous default under 'dark'.
Modified cyan.
-->
</html>

71
source/ilo-min.c Normal file
View file

@ -0,0 +1,71 @@
/* ilo-min.c (c) charles childers */
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#define V void
#define I int
#define C char
#define T s[sp]
#define N s[sp-1]
#define R r[rp]
#define G s[(--sp)+1]
#define D sp--
#define P(x) s[++sp]=x
#define F(x,y) f=open(rf,x,0666);y;close(f)
#define B(x,y) f=open(bf,x,0666);b_s();y;close(f)
#define W(x) while(c){x;c--;a++;b++;}
#define X(x) inst[(o>>x)&0xFF]()
#define RUN while(ip<65536)
#define DR "ilo.rom"
#define DB "ilo.blocks"
I ip,sp,rp,s[33],r[257],m[65536],a,b,c,f,o; C *bf,*rf;
V rst() {ip=sp=rp=0;}
V i_l() {F(O_RDONLY,read(f,&m,262144)); rst();}
V i_w() {F(O_WRONLY,write(f,&m,262144));}
V b_s() {a=G; b=G; lseek(f,4096*b,SEEK_SET);}
V b_l() {B(O_RDONLY,read(f,m+a,4096));}
V b_w() {B(O_WRONLY,write(f,m+a,4096));}
V p() {c=G; b=G; a=G;}
V no() {}
V li() {ip++; P(m[ip]);}
V du() {a=T; P(a);}
V dr() {s[sp]=0; D;}
V sw() {a=T; T=N; N=a;}
V pu() {rp++; R=G;}
V po() {P(R); rp--;}
V ju() {ip=G-1;}
V ca() {rp++; R=ip; ip=G-1;}
V cc() {a=G; if (G != 0) {rp++; R=ip; ip=a-1;}}
V cj() {a=G; if (G != 0) ip=a-1;}
V re() {ip=R; rp--;}
V eq() {N=(N == T) ? -1 : 0; D;}
V ne() {N=(N != T) ? -1 : 0; D;}
V lt() {N=(N < T) ? -1 : 0; D;}
V gt() {N=(N > T) ? -1 : 0; D;}
V fe() {T = m[T];}
V st() {m[T]=N; D; D;}
V ad() {N += T; D;}
V su() {N -= T; D;}
V mu() {N *= T; D;}
V di() {a=T; b=N; T=b/a; N=b%a;}
V an() {N=T & N; D;}
V or() {N=T | N; D;}
V xo() {N=T ^ N; D;}
V sl() {N=T << N; D;}
V sr() {N=T >> N; D;}
V cp() {p(); P(-1); W(if(m[b]!=m[a])T=0);}
V cy() {p(); W(m[b]=m[a])}
V i0() {putc(G,stdout);}
V i1() {P(getc(stdin));}
V i5() {i_l(); ip=-1;}
V i6() {ip=65536;}
V i7() {a=sp; P(a); P(rp);}
V (*ix[8])() = {i0, i1, b_l, b_w, i_w, i5, i6, i7};
V io() {ix[G]();}
V (*inst[30])()={
no, li, du, dr, sw, pu, po, ju, ca, cc, cj, re, eq, ne, lt,
gt, fe, st, ad, su, mu, di, an, or, xo, sl, sr, cp, cy, io};
V execute() {RUN{o=m[ip]; X(0); X(8); X(16); X(24); ip++;}}
V ds() {for (;sp>0;D) printf("#%d: %d\n", sp, s[sp]);}
V run() {i_l(); execute(); ds();}
I main(I n, C **v) {bf=(n>1)?v[1]:DB; rf=(n>2)?v[2]:DR; run();}

205
source/ilo-plan9.c Normal file
View file

@ -0,0 +1,205 @@
/***********************************
ilo-plan9.c (C) Jim Taylor
Example compilation (amd64):
6c ilo-plan9.c
6l -o ilo ilo-plan9.6
May want to run it with vt.
***********************************/
#include <u.h>
#include <libc.h>
#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 INST(c_name); void c_name(void) /* Shorthand for VM INSTructions */
int ip, /* instruction pointer */
sp, /* data stack pointer */
rp, /* address stack pointer */
ds[33], /* data stack */
as[257], /* address stack */
m[65536]; /* memory */
char *blocks, /* name of block file (ilo.blocks) */
*rom; /* name of image (ilo.rom) */
int a, b, fd, s, d, l;
char i[1];
void
push(int v)
{
ds[sp+1] = v;
sp += 1;
}
int
pop(void)
{
sp -= 1;
return ds[sp+1];
}
void
load_image(void)
{
fd = open(rom, OREAD);
if(!fd)
return;
read(fd, &m, 65536*4);
close(fd);
ip = sp = rp = 0;
}
void
save_image(void)
{
fd = open(rom, OWRITE);
write(fd, &m, 65536*4);
close(fd);
}
void
block_common(void)
{
b = pop(); /* block buffer */
a = pop(); /* block number */
seek(fd, 4096*a, 0);
}
void
read_block(void)
{
fd = open(blocks, OREAD);
block_common();
read(fd, m+b, 4096);
close(fd);
}
void
write_block(void)
{
fd = open(blocks, OWRITE);
block_common();
write(fd, m+b, 4096);
close(fd);
}
void save_ip(void) { rp += 1; R = ip; }
void symmetric(void) { if (b >= 0 && N < 0) { T += 1; N -= b; } }
INST(li) { ip += 1; push(m[ip]); }
INST(du) { push(T); }
INST(dr) { ds[sp] = 0; sp -= 1; }
INST(sw) { a = T; T = N; N = a; }
INST(pu) { rp += 1; R = pop(); }
INST(po) { push(R); rp -= 1; }
INST(ju) { ip = pop() - 1; }
INST(ca) { save_ip(); ip = pop() - 1; }
INST(cc) { a = pop(); if (pop()) { save_ip(); ip = a - 1; } }
INST(cj) { a = pop(); if (pop()) { ip = a - 1; } }
INST(re) { ip = R; rp -= 1; }
INST(eq) { N = (N == T) ? -1 : 0; sp -= 1; }
INST(ne) { N = (N != T) ? -1 : 0; sp -= 1; }
INST(lt) { N = (N < T) ? -1 : 0; sp -= 1; }
INST(gt) { N = (N > T) ? -1 : 0; sp -= 1; }
INST(fe) { T = m[T]; }
INST(st) { m[T] = N; sp -= 2; }
INST(ad) { N += T; sp -= 1; }
INST(su) { N -= T; sp -= 1; }
INST(mu) { N *= T; sp -= 1; }
INST(di) { a = T; b = N; T = b / a; N = b % a; symmetric(); }
INST(an) { N = T & N; sp -= 1; }
INST(or) { N = T | N; sp -= 1; }
INST(xo) { N = T ^ N; sp -= 1; }
INST(sl) { N = N << T; sp -= 1; }
INST(sr) { N = N >> T; sp -= 1; }
INST(cp)
{
l = pop(); d = pop();
s = T; T = -1;
while(l) {
if (m[d] != m[s])
T = 0;
l -= 1; s += 1; d += 1;
}
}
INST(cy)
{
l = pop(); d = pop(); s = pop();
while(l) {
m[d] = m[s]; l -= 1; s += 1; d += 1;
}
}
INST(ioa) { i[0] = (char)pop(); write(1, &i, 1); }
INST(iob) { read(0, &i, 1); push(i[0]); }
INST(ioc) { read_block(); }
INST(iod) { write_block(); }
INST(ioe) { save_image(); }
INST(iof) { load_image(); ip = -1; }
INST(iog) { ip = 65536; }
INST(ioh) { push(sp); push(rp); }
INST(io)
{
switch (pop()) {
case 0: ioa(); break; case 1: iob(); break;
case 2: ioc(); break; case 3: iod(); break;
case 4: ioe(); break; case 5: iof(); break;
case 6: iog(); break; case 7: ioh(); break;
default: break;
}
}
void
process(int o)
{
switch (o) {
case 0: break; case 1: li(); break;
case 2: du(); break; case 3: dr(); break;
case 4: sw(); break; case 5: pu(); break;
case 6: po(); break; case 7: ju(); break;
case 8: ca(); break; case 9: cc(); break;
case 10: cj(); break; case 11: re(); break;
case 12: eq(); break; case 13: ne(); break;
case 14: lt(); break; case 15: gt(); break;
case 16: fe(); break; case 17: st(); break;
case 18: ad(); break; case 19: su(); break;
case 20: mu(); break; case 21: di(); break;
case 22: an(); break; case 23: or(); break;
case 24: xo(); break; case 25: sl(); break;
case 26: sr(); break; case 27: cp(); break;
case 28: cy(); break; case 29: io(); break;
default: break;
}
}
void
process_bundle(int opcode)
{
process(opcode & 0xFF);
process((opcode >> 8) & 0xFF);
process((opcode >> 16) & 0xFF);
process((opcode >> 24) & 0xFF);
}
void
execute(void)
{
while(ip < 65536) {
process_bundle(m[ip]);
ip += 1;
}
}
void
main()
{
blocks = "ilo.blocks";
rom = "ilo.rom";
load_image();
execute();
exits(nil);
}

183
source/ilo-pthread.c Normal file
View file

@ -0,0 +1,183 @@
/***************************************************************
crc's _ _
(_) | ___
| | |/ _ \ a tiny virtual computer
| | | (_) | 64kw RAM, 32-bit, Dual Stack, MISC
|_|_|\___/ ilo.c (c) charles childers
**************************************************************/
/* cc -lpthread ilo-pthread.c -o ilo */
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <pthread.h>
#include <stdlib.h>
int ip, sp, rp, data[33], address[257], memory[65536];
int a, b, t, fp, block, buffer, src, dest, len;
char *blocks, *rom, iob[2];
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
#define T data[sp]
#define N data[sp-1]
#define R address[rp]
#define V void
int pop() { return data[(--sp) + 1]; }
V push(int value) { data[++sp] = value; }
V prepare_vm() { ip = sp = rp = 0; }
V load_image() {
fp = open(rom, O_RDONLY, 0666);
if (!fp) { return; };
read(fp, &memory, 65536 * 4);
close(fp);
prepare_vm();
}
V save_image() {
fp = open(rom, O_WRONLY, 0666);
write(fp, &memory, 65536 * 4);
close(fp);
}
V read_block() {
buffer = pop();
block = pop();
fp = open(blocks, O_RDONLY, 0666);
lseek(fp, 4096 * block, SEEK_SET);
read(fp, memory + buffer, 4096);
close(fp);
}
V write_block() {
buffer = pop();
block = pop();
fp = open(blocks, O_WRONLY, 0666);
lseek(fp, 4096 * block, SEEK_SET);
write(fp, memory + buffer, 4096);
close(fp);
}
V li() { ip++; push(memory[ip]); }
V du() { push(T); }
V dr() { data[sp] = 0; sp--; }
V sw() { a = T; T = N; N = a; }
V pu() { rp++; R = pop(); }
V po() { push(R); rp--; }
V ju() { ip = pop() - 1; }
V ca() { rp++; R = ip; ip = pop() - 1; }
V cc() { t = pop(); if (pop()) { rp++; R = ip; ip = t - 1; } }
V cj() { t = pop(); if (pop()) { ip = t - 1; } }
V re() { ip = R; rp--; }
V eq() { N = (N == T) ? -1 : 0; sp--; }
V ne() { N = (N != T) ? -1 : 0; sp--; }
V lt() { N = (N < T) ? -1 : 0; sp--; }
V gt() { N = (N > T) ? -1 : 0; sp--; }
V fe() { T = memory[T]; }
V st() { memory[T] = N; sp--; sp--; }
V ad() { N += T; sp--; }
V su() { N -= T; sp--; }
V mu() { N *= T; sp--; }
V di() { a = T; b = N; T = b / a; N = b % a; }
V an() { N = T & N; sp--; }
V or() { N = T | N; sp--; }
V xo() { N = T ^ N; sp--; }
V sl() { N = N << T; sp--; }
V sr() { N = N >> T; sp--; }
V cp() { len = pop(); dest = pop(); src = pop(); push(-1);
while (len) {
if (memory[dest] != memory[src]) T = 0;
len -= 1; src += 1; dest += 1;
}
}
V cy() { len = pop(); dest = pop(); src = pop();
while (len) {
memory[dest] = memory[src];
len -= 1; src += 1; dest += 1;
}
}
V io() {
switch (pop()) {
case 0:
iob[0] = pop(); write(1, &iob, 1);
break;
case 1: push(getchar()); 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; exit(0); break;
case 7: push(sp); push(rp); break;
default: break;
}
}
V process(int o) {
switch (o) {
case 0: break; case 1: li(); break;
case 2: du(); break; case 3: dr(); break;
case 4: sw(); break; case 5: pu(); break;
case 6: po(); break; case 7: ju(); break;
case 8: ca(); break; case 9: cc(); break;
case 10: cj(); break; case 11: re(); break;
case 12: eq(); break; case 13: ne(); break;
case 14: lt(); break; case 15: gt(); break;
case 16: fe(); break; case 17: st(); break;
case 18: ad(); break; case 19: su(); break;
case 20: mu(); break; case 21: di(); break;
case 22: an(); break; case 23: or(); break;
case 24: xo(); break; case 25: sl(); break;
case 26: sr(); break; case 27: cp(); break;
case 28: cy(); break; case 29: io(); break;
default: break;
}
}
V process_bundle(int opcode) {
process(opcode & 0xFF);
process((opcode >> 8) & 0xFF);
process((opcode >> 16) & 0xFF);
process((opcode >> 24) & 0xFF);
}
V *execute(V *unused) {
while (ip < 65536) {
pthread_mutex_lock(&mutex);
process_bundle(memory[ip]);
ip++;
pthread_mutex_unlock(&mutex);
pthread_yield();
}
return 0;
}
V *guard(V *unused) {
while (1) {
if (sp < 0) { printf("E: data stack underflow\n"); exit(1); }
if (sp > 31) { printf("E: data stack overflow\n"); exit(2); }
if (rp < 0) { printf("E: address stack underflow\n"); exit(3); }
if (rp > 255) { printf("E: address stack overflow\n"); exit(4); }
pthread_yield();
}
return 0;
}
int main(int argc, char **argv) {
blocks = (argc > 1) ? argv[1] : "ilo.blocks";
rom = (argc > 2) ? argv[2] : "ilo.rom";
load_image();
pthread_t cpu, stack_guard;
int e1 = pthread_create(&cpu, NULL, execute, NULL);
int e2 = pthread_create(&stack_guard, NULL, guard, NULL);
// while(1) {pthread_yield();};
if (!e2) {
pthread_join(stack_guard, NULL);
pthread_join(cpu, NULL);
}
}

197
source/ilo-safer.c Normal file
View file

@ -0,0 +1,197 @@
/***************************************************************
crc's _ _
(_) | ___
| | |/ _ \ a tiny virtual computer
| | | (_) | 64kw RAM, 32-bit, Dual Stack, MISC
|_|_|\___/ ilo.c (c) charles childers
**************************************************************/
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#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 V void
#define I int
#define C char
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) */
/* the other variables are used by the various
functions for misc. purposes */
I a, b, f, s, d, l;
C i[1];
V p(char *s) { while(*s) putchar(*s++); }
V e(char *s) { p("E:"); p(s); p("\n"); exit(1); }
V dso() { if ((sp + 1) > 32) { e("DSO"); } }
V dsu() { if ((sp - 1) < 0) { e("DSU"); } }
V rso() { if ((rp + 1) > 256) { e("RSO"); } }
V rsu() { if ((rp - 1) < 0) { e("RSU"); } }
V dbz() { if (T == 0) { e("DBZ"); } }
V mem() { if (T < 0 || T > 65535) { e("MEM"); } }
V uli() { if (f == -1) { e("ULI"); } }
V usi() { if (f == -1) { e("URI"); } }
V urb() { if (f == -1) { e("URB"); } }
V uwb() { if (f == -1) { e("UWB"); } }
V push(I v) { dso(); ds[sp + 1] = v; sp += 1; }
I pop() { dsu(); sp -= 1; return ds[sp + 1]; }
V load_image() {
f = open(rom, O_RDONLY, 0666);
uli();
read(f, &m, 65536 * 4);
close(f);
ip = sp = rp = 0;
}
V save_image() {
f = open(rom, O_WRONLY, 0666);
usi();
write(f, &m, 65536 * 4);
close(f);
}
V block_common() {
b = pop(); /* block buffer */
a = pop(); /* block number */
lseek(f, 4096 * a, SEEK_SET);
}
V read_block() {
f = open(blocks, O_RDONLY, 0666);
urb();
block_common();
read(f, m + b, 4096);
close(f);
}
V write_block() {
f = open(blocks, O_WRONLY, 0666);
uwb();
block_common();
write(f, m + b, 4096);
close(f);
}
V save_ip() { rso(); rp += 1; R = ip; }
V symmetric() { if (b >= 0 && N < 0) { T += 1; N -= b; } }
V li() { ip += 1; push(m[ip]); }
V du() { push(T); }
V dr() { ds[sp] = 0; sp -= 1; }
V sw() { a = T; T = N; N = a; }
V pu() { rso(); rp += 1; R = pop(); }
V po() { rsu(); push(R); rp -= 1; }
V ju() { ip = pop() - 1; }
V ca() { save_ip(); ip = pop() - 1; }
V cc() { a = pop(); if (pop()) { save_ip(); ip = a - 1; } }
V cj() { a = pop(); if (pop()) { ip = a - 1; } }
V re() { rsu(); ip = R; rp -= 1; }
V eq() { N = (N == T) ? -1 : 0; sp -= 1; }
V ne() { N = (N != T) ? -1 : 0; sp -= 1; }
V lt() { N = (N < T) ? -1 : 0; sp -= 1; }
V gt() { N = (N > T) ? -1 : 0; sp -= 1; }
V fe() { mem(); T = m[T]; }
V st() { mem(); m[T] = N; sp -= 2; }
V ad() { N += T; sp -= 1; }
V su() { N -= T; sp -= 1; }
V mu() { N *= T; sp -= 1; }
V di() { dbz();
a = T; b = N; T = b / a; N = b % a; symmetric(); }
V an() { N = T & N; sp -= 1; }
V or() { N = T | N; sp -= 1; }
V xo() { N = T ^ N; sp -= 1; }
V sl() { N = N << T; sp -= 1; }
V sr() { N = N >> T; sp -= 1; }
V cp() { l = pop(); d = pop(); s = T; T = -1;
while (l) { if (m[d] != m[s]) { T = 0; }
l -= 1; s += 1; d += 1; } }
V cy() { l = pop(); d = pop(); s = pop();
while (l) { m[d] = m[s]; l -= 1; s += 1; d += 1; } }
V ioa() { i[0] = (char)pop(); write(1, &i, 1); }
V iob() { read(0, &i, 1); push(i[0]); }
V ioc() { read_block(); }
V iod() { write_block(); }
V ioe() { save_image(); }
V iof() { load_image(); ip = -1; }
V iog() { ip = 65536; }
V ioh() { push(sp); push(rp); }
V io() {
switch (pop()) {
case 0: ioa(); break; case 1: iob(); break;
case 2: ioc(); break; case 3: iod(); break;
case 4: ioe(); break; case 5: iof(); break;
case 6: iog(); break; case 7: ioh(); break;
default: break;
}
}
/* Using a switch here instead of a jump table to avoid */
/* some issues w/relocation stuff when building w/o libc */
V process(I o) {
switch (o) {
case 0: break; case 1: li(); break;
case 2: du(); break; case 3: dr(); break;
case 4: sw(); break; case 5: pu(); break;
case 6: po(); break; case 7: ju(); break;
case 8: ca(); break; case 9: cc(); break;
case 10: cj(); break; case 11: re(); break;
case 12: eq(); break; case 13: ne(); break;
case 14: lt(); break; case 15: gt(); break;
case 16: fe(); break; case 17: st(); break;
case 18: ad(); break; case 19: su(); break;
case 20: mu(); break; case 21: di(); break;
case 22: an(); break; case 23: or(); break;
case 24: xo(); break; case 25: sl(); break;
case 26: sr(); break; case 27: cp(); break;
case 28: cy(); break; case 29: io(); break;
default: break;
}
}
#define INST(n) ((opcode >> n) & 0xFF) != 0
V process_bundle(I opcode) {
if (INST(0)) process(opcode & 0xFF);
if (INST(8)) process((opcode >> 8) & 0xFF);
if (INST(16)) process((opcode >> 16) & 0xFF);
if (INST(24)) process((opcode >> 24) & 0xFF);
}
V execute() {
while (ip < 65536) {
process_bundle(m[ip]);
ip += 1;
}
}
V add_restrictions() {
#ifdef __OpenBSD__
unveil(blocks, "rw");
unveil(rom, "rw");
pledge("stdio rpath wpath", NULL);
#endif
}
I main(I argc, C **argv) {
blocks = (argc > 1) ? argv[1] : "ilo.blocks";
rom = (argc > 2) ? argv[2] : "ilo.rom";
add_restrictions();
load_image();
execute();
return 0;
}

267
source/ilo-teensy41.ino Normal file
View file

@ -0,0 +1,267 @@
// =============================================================
// crc's _ _
// (_) | ___
// | | |/ _ \ a tiny virtual computer
// | | | (_) | 64kw RAM, 32-bit, Dual Stack, MISC
// |_|_|\___/ ilo-teensy41.ino (c) charles childers
// ============================================================
// This is an ilo for the Teensy 4.1. It derives from the
// ilo-banked.c, as with the DOS & Mac System 5/6/7 ports.
//
// Requirements:
//
// - Teensy 4.1
// - FAT formatted SD card containing these files:
// - ilo.rom (the system image)
// - ilo.blo (the data blocks)
// - A serial terminal interface
//
// ============================================================
#include <SD.h>
#include <TimeLib.h>
#define VERBOSE
#define SLICES 64
#define SLICESIZE (65536/SLICES)
int ip, sp, rp, data[33], address[257];
char *blocks, *rom;
extern int image[];
int *memory[SLICES];
#define TOS data[sp]
#define NOS data[sp-1]
#define TORS address[rp]
#define I int
#define V void
I pop() { sp--; return data[sp + 1]; }
V push(int value) { sp++; data[sp] = value; }
V store(int a, int v) {
int slice = a / SLICESIZE;
int actual = a - (slice * SLICESIZE);
memory[slice][actual] = v;
}
int fetch(int a) {
int slice = a / SLICESIZE;
int actual = a - (slice * SLICESIZE);
return memory[slice][actual];
}
V xlog(const char *s, int eol) {
#ifdef VERBOSE
if (eol)
Serial.println(s);
else
Serial.print(s);
#endif
}
V load_image() {
File rom = SD.open("ilo.rom", FILE_READ);
int data;
xlog("ilo: load rom", 1);
for (int x = 0; x < 65536; x++) {
data = 0;
rom.read(&data, 4);
store(x, data);
if ((x % 1024) == 0) xlog(".", 0);
}
rom.close();
delay(10);
xlog("\nilo: rom loaded", 1);
}
V prepare_vm() {
for (ip = 0; ip < 32; ip++) data[ip] = 0;
for (ip = 0; ip < 128; ip++) address[ip] = 0;
ip = sp = rp = 0;
}
V read_block() {
File blocks = SD.open("ilo.blo", FILE_READ);
int data;
int buf = pop();
int blk = pop();
blocks.seek(4096 * blk);
for (int x = 0; x < 1024; x++) {
data = 0;
blocks.read(&data, 4);
store(buf + x, data);
}
blocks.close();
delay(10);
}
V write_block() {
File blocks = SD.open("ilo.blo", FILE_WRITE);
int data;
int buf = pop();
int blk = pop();
blocks.seek(4096 * blk);
for (int x = 0; x < 1024; x++) {
data = fetch(buf + x);
blocks.write(&data, 4);
}
blocks.close();
delay(10);
}
int led = 13;
V teensy_io() {
int a, b, c, d, e, f;
switch (pop()) {
case 1: digitalWrite(pop(), HIGH);
break;
case 2: digitalWrite(pop(), LOW);
break;
case 3: a = pop();
b = pop();
pinMode(b, a);
break;
case 4: digitalRead(pop()) ? push(-1) : push(0);
break;
case 10: delay(pop());
break;
case 11: delayMicroseconds(pop());
break;
case 12: delayNanoseconds(pop());
break;
case 20: push(hour());
break;
case 21: push(minute());
break;
case 22: push(second());
break;
case 23: push(day());
break;
case 24: push(month());
break;
case 25: push(year());
break;
}
}
V process(int o) {
int a, b, target, flag;
int src, dest, len, kkk;
char outstr[2] = {'a', 0};
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: outstr[0] = pop(); Serial.print(outstr);
if (outstr[0] == 10) { outstr[0] = 13; Serial.print(outstr); } break;
case 1: kkk = 0; while (kkk <= 0) { kkk = Serial.read(); }
outstr[0] = kkk; Serial.print(outstr);
if (kkk == 13) { kkk = 10; }
push(kkk); break;
case 2: read_block(); break;
case 3: write_block(); break;
case 4: break;
case 5: ip = -1; break;
case 6: ip = 65536; break;
case 7: push(sp); push(rp); break;
case 100: teensy_io(); break;
default: break;
} break;
default: break;
}
}
V execute() {
int opcode, o;
ip = 0;
while (ip < 65536) {
opcode = fetch(ip);
o = opcode & 0xFF; if (o) process(o);
o = (opcode >> 8) & 0xFF; if (o) process(o);
o = (opcode >> 16) & 0xFF; if (o) process(o);
o = (opcode >> 24) & 0xFF; if (o) process(o);
ip++;
}
}
// the setup routine runs once when you press reset:
V setup() {
Serial.begin(9600);
xlog("ilo: prepare memory", 1);
int i;
for (i = 0; i < SLICES; i++)
memory[i] = (int *)malloc(SLICESIZE * sizeof(int));
xlog("ilo: prepare i/o pins", 1);
pinMode(led, OUTPUT);
xlog("ilo: check for SD card", 1);
if (!SD.begin(BUILTIN_SDCARD)) {
xlog("!!!! card failed, or not present; check SD card and restart", 1);
while (1);
}
xlog("ilo: check for ilo.rom", 1);
if (!SD.exists("ilo.rom")) {
xlog("!!!! missing ilo.rom; check SD card and restart", 1);
while (1);
}
xlog("ilo: check for ilo.blo", 1);
if (!SD.exists("ilo.blo")) {
xlog("!!!! missing ilo.blo; check SD card and restart", 1);
while (1);
}
}
// the loop routine runs over and over again forever:
V loop() {
prepare_vm();
load_image();
execute();
}

141
source/ilo-windows.c Normal file
View file

@ -0,0 +1,141 @@
/* ilo-windows.c (c) 2022, charles childers */
#include <stdio.h>
#include <fcntl.h>
int ip, sp, rp, data[33], address[257], memory[65536];
char *blocks, *rom;
#define T data[sp]
#define N data[sp-1]
#define R address[rp]
int pop() { return data[(--sp) + 1]; }
void push(int value) { data[++sp] = value; }
void prepare_vm() { ip = sp = rp = 0; }
void load_image() {
int fp;
fp = open(rom, O_RDONLY, 0666);
if (!fp) return;
read(fp, &memory, 65536 * sizeof(int));
close(fp);
prepare_vm();
}
void save_image() {
int fp;
fp = open(rom, O_WRONLY, 0666);
write(fp, &memory, 65536 * sizeof(int));
close(fp);
}
void read_block() {
int f, block, buffer;
buffer = pop();
block = pop();
f = open(blocks, O_RDONLY, 0666);
lseek(f, 4096 * block, SEEK_SET);
read(f, memory + buffer, 1024 * 4);
close(f);
}
void write_block() {
int f, block, buffer;
buffer = pop();
block = pop();
f = open(blocks, O_WRONLY, 0666);
lseek(f, 4096 * block, SEEK_SET);
write(f, memory + buffer, 4096);
close(f);
}
void process(int o) {
int a, b, target, src, dest, len;
switch (o) {
case 0: break;
case 1: ip++; push(memory[ip]); break;
case 2: push(T); break;
case 3: data[sp] = 0; sp--; break;
case 4: a = T; T = N; N = a; break;
case 5: rp++; R = pop(); break;
case 6: push(R); rp--; break;
case 7: ip = pop() - 1; break;
case 8: rp++; R = ip; ip = pop() - 1; break;
case 9: target = pop();
if (pop() != 0) { rp++; R = ip; ip = target - 1; }
break;
case 10: target = pop();
if (pop() != 0) ip = target - 1; break;
case 11: ip = R; rp--; break;
case 12: N = (N == T) ? -1 : 0; sp--; break;
case 13: N = (N != T) ? -1 : 0; sp--; break;
case 14: N = (N < T) ? -1 : 0; sp--; break;
case 15: N = (N > T) ? -1 : 0; sp--; break;
case 16: T = memory[T]; break;
case 17: memory[T] = N; sp--; sp--; break;
case 18: N += T; sp--; break;
case 19: N -= T; sp--; break;
case 20: N *= T; sp--; break;
case 21: a = T; b = N; T = b / a; N = b % a; break;
case 22: N = T & N; sp--; break;
case 23: N = T | N; sp--; break;
case 24: N = T ^ N; sp--; break;
case 25: N = N << T; sp--; break;
case 26: N = N >> T; sp--; break;
case 27: len = pop(); dest = pop();
src = pop(); push(-1);
while (len) {
if (memory[dest] != memory[src]) T = 0;
len -= 1; src += 1; dest += 1;
}
break;
case 28: len = pop(); dest = pop();
src = pop();
while (len) {
memory[dest] = memory[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 process_bundle(int opcode) {
process(opcode & 0xFF);
process((opcode >> 8) & 0xFF);
process((opcode >> 16) & 0xFF);
process((opcode >> 24) & 0xFF);
}
void execute() {
while (ip < 65536) {
process_bundle(memory[ip]);
ip++;
}
}
void dump_stack() {
for (; sp > 0; sp--) printf(" %d", data[sp]); printf("\n");
}
int main(int argc, char **argv) {
blocks = (argc > 1) ? argv[1] : "ilo.blocks";
rom = (argc > 2) ? argv[2] : "ilo.rom";
load_image();
execute();
dump_stack();
}

184
source/ilo.c Normal file
View file

@ -0,0 +1,184 @@
/***************************************************************
crc's _ _
(_) | ___
| | |/ _ \ a tiny virtual computer
| | | (_) | 64kw RAM, 32-bit, Dual Stack, MISC
|_|_|\___/ ilo.c (c) charles childers
**************************************************************/
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#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 V void
#define I int
#define C char
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) */
/* the other variables are used by the various
functions for misc. purposes */
I a, b, f, s, d, l;
C i[1];
V push(I v) { ds[sp + 1] = v; sp += 1; }
I pop() { sp -= 1; return ds[sp + 1]; }
V load_image() {
f = open(rom, O_RDONLY, 0666);
if (!f) { return; };
read(f, &m, 65536 * 4);
close(f);
ip = sp = rp = 0;
}
V save_image() {
f = open(rom, O_WRONLY, 0666);
write(f, &m, 65536 * 4);
close(f);
}
V block_common() {
b = pop(); /* block buffer */
a = pop(); /* block number */
lseek(f, 4096 * a, SEEK_SET);
}
V read_block() {
f = open(blocks, O_RDONLY, 0666);
block_common();
read(f, m + b, 4096);
close(f);
}
V write_block() {
f = open(blocks, O_WRONLY, 0666);
block_common();
write(f, m + b, 4096);
close(f);
}
V save_ip() { rp += 1; R = ip; }
V symmetric() { if (b >= 0 && N < 0) { T += 1; N -= b; } }
V li() { ip += 1; push(m[ip]); }
V du() { push(T); }
V dr() { ds[sp] = 0; sp -= 1; }
V sw() { a = T; T = N; N = a; }
V pu() { rp += 1; R = pop(); }
V po() { push(R); rp -= 1; }
V ju() { ip = pop() - 1; }
V ca() { save_ip(); ip = pop() - 1; }
V cc() { a = pop(); if (pop()) { save_ip(); ip = a - 1; } }
V cj() { a = pop(); if (pop()) { ip = a - 1; } }
V re() { ip = R; rp -= 1; }
V eq() { N = (N == T) ? -1 : 0; sp -= 1; }
V ne() { N = (N != T) ? -1 : 0; sp -= 1; }
V lt() { N = (N < T) ? -1 : 0; sp -= 1; }
V gt() { N = (N > T) ? -1 : 0; sp -= 1; }
V fe() { T = m[T]; }
V st() { m[T] = N; sp -= 2; }
V ad() { N += T; sp -= 1; }
V su() { N -= T; sp -= 1; }
V mu() { N *= T; sp -= 1; }
V di() { a = T; b = N; T = b / a; N = b % a; symmetric(); }
V an() { N = T & N; sp -= 1; }
V or() { N = T | N; sp -= 1; }
V xo() { N = T ^ N; sp -= 1; }
V sl() { N = N << T; sp -= 1; }
V sr() { N = N >> T; sp -= 1; }
V cp() { l = pop(); d = pop(); s = T; T = -1;
while (l) { if (m[d] != m[s]) { T = 0; }
l -= 1; s += 1; d += 1; } }
V cy() { l = pop(); d = pop(); s = pop();
while (l) { m[d] = m[s]; l -= 1; s += 1; d += 1; } }
V ioa() { i[0] = (char)pop(); write(1, &i, 1); }
V iob() { read(0, &i, 1); push(i[0]); }
V ioc() { read_block(); }
V iod() { write_block(); }
V ioe() { save_image(); }
V iof() { load_image(); ip = -1; }
V iog() { ip = 65536; }
V ioh() { push(sp); push(rp); }
V io() {
switch (pop()) {
case 0: ioa(); break; case 1: iob(); break;
case 2: ioc(); break; case 3: iod(); break;
case 4: ioe(); break; case 5: iof(); break;
case 6: iog(); break; case 7: ioh(); break;
default: break;
}
}
/* Using a switch here instead of a jump table to avoid */
/* some issues w/relocation stuff when building w/o libc */
V process(I o) {
switch (o) {
case 0: break; case 1: li(); break;
case 2: du(); break; case 3: dr(); break;
case 4: sw(); break; case 5: pu(); break;
case 6: po(); break; case 7: ju(); break;
case 8: ca(); break; case 9: cc(); break;
case 10: cj(); break; case 11: re(); break;
case 12: eq(); break; case 13: ne(); break;
case 14: lt(); break; case 15: gt(); break;
case 16: fe(); break; case 17: st(); break;
case 18: ad(); break; case 19: su(); break;
case 20: mu(); break; case 21: di(); break;
case 22: an(); break; case 23: or(); break;
case 24: xo(); break; case 25: sl(); break;
case 26: sr(); break; case 27: cp(); break;
case 28: cy(); break; case 29: io(); break;
default: break;
}
}
V process_bundle(I opcode) {
process(opcode & 0xFF);
process((opcode >> 8) & 0xFF);
process((opcode >> 16) & 0xFF);
process((opcode >> 24) & 0xFF);
}
V execute() {
while (ip < 65536) {
process_bundle(m[ip]);
ip += 1;
}
}
#ifndef NOSTDLIB
I main(I argc, C **argv) {
blocks = (argc > 1) ? argv[1] : "ilo.blocks";
rom = (argc > 2) ? argv[2] : "ilo.rom";
load_image();
execute();
for (; sp > 0; sp -= 1) printf(" %d", ds[sp]); printf("\n");
return 0;
}
#else
I main(I argc, C **argv) {
blocks = "ilo.blocks";
rom = "ilo.rom";
load_image();
execute();
return 0;
}
#endif

327
source/ilo.cl Normal file
View file

@ -0,0 +1,327 @@
;; *************************************************************
;; crc's _ _
;; (_) | ___
;; | | |/ _ \ a tiny virtual computer
;; | | | (_) | 64kw RAM, 32-bit, Dual Stack, MISC
;; |_|_|\___/ ilo.cl (c) charles childers
;; *************************************************************
(declaim (optimize (speed 3) (space 0) (safety 0) (debug 0)))
(defvar ip 0) ; instruction pointer
(defvar sp 0) ; data stack pointer
(defvar rp 0) ; address stack pointer
(defvar ds (make-array 33)) ; data stack
(defvar as (make-array 257)) ; address stack
(defvar m (make-array 65536)) ; memory
(defvar blk (make-array 1024)) ; block buffer (i/o)
(defvar blocks "ilo.blocks") ; block file name
(defvar rom "ilo.rom") ; rom file name
(defvar a 0)
(defvar b 0)
(defvar f 0)
(defvar s 0)
(defvar d 0)
(defvar l 0)
(defvar i (make-array 4))
(defvar z 0)
(defun fixint (n)
(let* ((max-value (expt 2 31))
(unsigned-n (logand n #xffffffff)))
(cond ((> unsigned-n max-value)
(- unsigned-n (* max-value 2)))
((< unsigned-n (- max-value))
(+ unsigned-n (* max-value 2)))
(t unsigned-n))))
(defun _push (v)
(setf (aref ds (1+ sp)) (fixint v))
(incf sp))
(defun _pop ()
(decf sp)
(aref ds (1+ sp)))
(defun read-integers-into-array (array filename offset)
(with-open-file (stream filename
:element-type '(unsigned-byte 8)
:direction :input)
(file-position stream offset)
(loop for i below (length array)
do (setf (svref array i)
(let ((bytes (make-array 4
:element-type '(unsigned-byte 8))))
(read-sequence bytes stream)
(fixint (logior (ash (aref bytes 0) 0)
(ash (aref bytes 1) 8)
(ash (aref bytes 2) 16)
(ash (aref bytes 3) 24))))))))
(defun load-image ()
(read-integers-into-array m rom 0))
(defun save-image ())
(defun read-block ()
(setq b (_pop)
a (_pop))
(read-integers-into-array blk blocks (* 4096 a))
(replace m blk :start1 b :end1 (+ b 1024)))
(defun copy-block-from-m (org start-index)
(let ((end-index (+ start-index 1024)))
(copy-seq (subseq org start-index end-index))))
(defun little-endian (integer)
(let ((bytes (make-array 4
:element-type '(unsigned-byte 8))))
(setf (aref bytes 0) (ldb (byte 8 0) integer))
(setf (aref bytes 1) (ldb (byte 8 8) integer))
(setf (aref bytes 2) (ldb (byte 8 16) integer))
(setf (aref bytes 3) (ldb (byte 8 24) integer))
bytes))
(defun write-block ()
(setq b (_pop)
a (_pop))
(with-open-file
(out-stream blocks
:direction :output
:if-exists :append
:element-type '(unsigned-byte 8))
(file-position out-stream (* 4096 a))
(loop for integer across (copy-block-from-m m b) do
(write-sequence (little-endian integer) out-stream))))
(defun save-ip ()
(incf rp)
(setf (aref as rp) ip))
(defun symmetric ()
(when (and (>= b 0) (< (aref ds (1- sp)) 0))
(progn
(incf (aref ds sp))
(decf (aref ds (1- sp)) b))))
(defun li ()
(incf ip)
(_push (aref m ip)))
(defun du ()
(_push (aref ds sp)))
(defun dr ()
(setf (aref ds sp) 0)
(decf sp))
(defun sw ()
(setq a (aref ds sp))
(setf (aref ds sp) (aref ds (1- sp))
(aref ds (1- sp)) a))
(defun pu ()
(incf rp)
(setf (aref as rp) (_pop)))
(defun po ()
(_push (aref as rp))
(decf rp))
(defun ju ()
(setq ip (- (_pop) 1)))
(defun ca ()
(save-ip)
(setq ip (- (_pop) 1)))
(defun cc ()
(setq a (_pop))
(when (not (zerop (_pop)))
(save-ip)
(setq ip (- a 1))))
(defun cj ()
(setq a (_pop))
(when (not (zerop (_pop)))
(setq ip (- a 1))))
(defun re ()
(setq ip (aref as rp))
(decf rp))
(defun _eq ()
(setf (aref ds (1- sp)) (if (= (aref ds (1- sp)) (aref ds sp)) -1 0))
(decf sp))
(defun ne ()
(setf (aref ds (1- sp)) (if (/= (aref ds (1- sp)) (aref ds sp)) -1 0))
(decf sp))
(defun lt ()
(setf (aref ds (1- sp)) (if (< (aref ds (1- sp)) (aref ds sp)) -1 0))
(decf sp))
(defun gt ()
(setf (aref ds (1- sp)) (if (> (aref ds (1- sp)) (aref ds sp)) -1 0))
(decf sp))
(defun fe ()
(setf (aref ds sp) (aref m (aref ds sp))))
(defun st ()
(setf (aref m (aref ds sp)) (aref ds (1- sp)))
(decf sp 2))
(defun ad ()
(setf (aref ds (1- sp)) (fixint (+ (aref ds (1- sp)) (aref ds sp))))
(decf sp))
(defun su ()
(setf (aref ds (1- sp)) (fixint (- (aref ds (1- sp)) (aref ds sp))))
(decf sp))
(defun mu ()
(setf (aref ds (1- sp)) (fixint (* (aref ds (1- sp)) (aref ds sp))))
(decf sp))
(defun di ()
(setf a (aref ds sp)
b (aref ds (1- sp))
(aref ds sp) (fixint (floor b a))
(aref ds (1- sp)) (fixint (mod b a)))
(symmetric))
(defun an ()
(setf (aref ds (1- sp)) (fixint (logand (aref ds (1- sp)) (aref ds sp))))
(decf sp))
(defun _or ()
(setf (aref ds (1- sp)) (fixint (logior (aref ds (1- sp)) (aref ds sp))))
(decf sp))
(defun xo ()
(setf (aref ds (1- sp)) (fixint (logxor (aref ds (1- sp)) (aref ds sp))))
(decf sp))
(defun sl ()
(setf (aref ds (1- sp)) (fixint (ash (aref ds (1- sp)) (aref ds sp))))
(decf sp))
(defun sr ()
(setf (aref ds (1- sp)) (fixint (ash (aref ds (1- sp)) (- (aref ds sp)))))
(decf sp))
(defun cp ()
(setf l (_pop)
d (_pop)
s (aref ds sp)
(aref ds sp) -1)
(loop repeat l do
(when (not (= (aref m d) (aref m s)))
(setf (aref ds sp) 0))
(decf l)
(decf s)
(decf d)))
(defun cy ()
(setf l (_pop)
d (_pop)
s (_pop))
(loop repeat l do
(setf (aref m d) (aref m s))
(incf d)
(incf s)))
(defun ioa ()
(setf d (_pop))
(write-char (code-char d) *standard-output*))
(defun iob ()
(setf d (read-char *standard-input*))
(_push (char-code d)))
(defun ioc ()
(read-block))
(defun iod ()
(write-block))
(defun ioe ()
(save-image))
(defun iof ()
(load-image)
(setf ip -1))
(defun iog ()
(setf ip 65536))
(defun ioh ()
(_push sp)
(_push rp))
(defun io ()
(case (_pop)
(0 (ioa))
(1 (iob))
(2 (ioc))
(3 (iod))
(4 (ioe))
(5 (iof))
(6 (iog))
(7 (ioh))))
(defun process (o)
(case o
(0)
(1 (li))
(2 (du))
(3 (dr))
(4 (sw))
(5 (pu))
(6 (po))
(7 (ju))
(8 (ca))
(9 (cc))
(10 (cj))
(11 (re))
(12 (_eq))
(13 (ne))
(14 (lt))
(15 (gt))
(16 (fe))
(17 (st))
(18 (ad))
(19 (su))
(20 (mu))
(21 (di))
(22 (an))
(23 (_or))
(24 (xo))
(25 (sl))
(26 (sr))
(27 (cp))
(28 (cy))
(29 (io))
(otherwise nil)))
(defun process-bundle (opcode)
(process (logand opcode #xFF))
(process (logand (ash opcode -8) #xFF))
(process (logand (ash opcode -16) #xFF))
(process (logand (ash opcode -24) #xFF)))
(defun _execute ()
(loop while (< ip 65536) do
(process-bundle (aref m ip))
(incf ip)))
(defun main ()
(load-image)
(_execute))
(main)
(quit)

161
source/ilo.cs Normal file
View file

@ -0,0 +1,161 @@
// ilo.cs, (c) charles childers
using System;
using System.IO;
using System.Text;
namespace ilo {
class VM {
public int sp, rp, ip;
public int[] d, a, m;
public VM() {
sp = 0;
rp = 0;
ip = 0;
d = new int[33];
a = new int[257];
m = new int[65536];
load_rom();
}
public void load_rom() {
int i = 0;
if (!File.Exists("ilo.rom")) {
Console.Write("ilo.rom missing");
Environment.Exit(1);
}
BinaryReader rom = new BinaryReader(File.Open("ilo.rom", FileMode.Open));
while (i < 65536) { m[i] = rom.ReadInt32(); i++; }
rom.Close();
}
public void read_block() {
int buffer = d[sp]; sp--;
int block = d[sp]; sp--;
int i = 0;
BinaryReader blocks = new BinaryReader(File.Open("ilo.blocks", FileMode.Open));
blocks.BaseStream.Seek(4096 * block, SeekOrigin.Begin);
while (i < 1024) { m[buffer + i] = blocks.ReadInt32(); i++; }
blocks.Close();
}
public void write_block() {
int buffer = d[sp]; sp--;
int block = d[sp]; sp--;
int i = 0;
BinaryWriter blocks = new BinaryWriter(File.Open("ilo.blocks", FileMode.Open, FileAccess.ReadWrite));
blocks.BaseStream.Seek(4096 * block, SeekOrigin.Begin);
while (i < 1024) { blocks.Write(m[buffer + i]); i++; }
blocks.Close();
}
public void push(int x) { sp++; d[sp] = x; }
public int pop() { sp--; return d[sp + 1]; }
public void no() { }
public void li() { ip++; sp++; d[sp] = m[ip]; }
public void du() { sp++; d[sp] = d[sp - 1]; }
public void dr() { sp--; }
public void sw() { int x = d[sp], y = d[sp - 1]; d[sp] = y; d[sp - 1] = x; }
public void pu() { rp++; a[rp] = d[sp]; sp--; }
public void po() { sp++; d[sp] = a[rp]; rp--; }
public void ju() { ip = d[sp] - 1; sp--; }
public void ca() { rp++; a[rp] = ip; ju(); }
public void cc() { if (d[sp - 1] != 0) { rp++; a[rp] = ip; ip = d[sp] - 1; } sp -= 2; }
public void cj() { if (d[sp - 1] != 0) { ip = d[sp] - 1; } sp -= 2; }
public void re() { ip = a[rp]; rp--; }
public void eq() { d[sp - 1] = (d[sp - 1] == d[sp]) ? -1 : 0; sp--; }
public void ne() { d[sp - 1] = (d[sp - 1] != d[sp]) ? -1 : 0; sp--; }
public void lt() { d[sp - 1] = (d[sp - 1] < d[sp]) ? -1 : 0; sp--; }
public void gt() { d[sp - 1] = (d[sp - 1] > d[sp]) ? -1 : 0; sp--; }
public void fe() { d[sp] = m[d[sp]]; }
public void st() { m[d[sp]] = d[sp - 1]; sp -= 2; }
public void ad() { d[sp - 1] += d[sp]; sp--; }
public void su() { d[sp - 1] -= d[sp]; sp--; }
public void mu() { d[sp - 1] *= d[sp]; sp--; }
public void di() { int x = d[sp], y = d[sp - 1]; d[sp] = y / x; d[sp - 1] = y % x; }
public void an() { d[sp - 1] = d[sp] & d[sp - 1]; sp--; }
public void or() { d[sp - 1] = d[sp] | d[sp - 1]; sp--; }
public void xo() { d[sp - 1] = d[sp] ^ d[sp - 1]; sp--; }
public void sl() { d[sp - 1] = d[sp] << d[sp - 1]; sp--; }
public void sr() { d[sp - 1] = d[sp] >>= d[sp - 1]; sp--; }
public void cp() {
int len = d[sp]; sp--;
int dest = d[sp]; sp--;
int src = d[sp]; sp--;
sp++; d[sp] = -1;
while (len > 0) {
if (m[dest] != m[src]) { d[sp] = 0; }
len -= 1; src += 1; dest += 1;
}
}
public void cy() {
int len = d[sp]; sp--;
int dest = d[sp]; sp--;
int src = d[sp]; sp--;
while (len > 0) {
m[dest] = m[src];
len -= 1; src += 1; dest += 1;
}
}
public void iowr() { Console.Write((char)d[sp]); sp--; }
public void iord() { ConsoleKeyInfo x = Console.ReadKey(); sp++; d[sp] = (int)x.KeyChar; if (d[sp] == 13) { d[sp] = 10; } }
public void iorb() { read_block(); }
public void iowb() { write_block(); }
public void iosi() { }
public void ioli() { load_rom(); ip = -1; }
public void ioen() { ip = 65536; }
public void iost() { sp++; d[sp] = sp - 1; sp++; d[sp] = rp; }
public void io() {
int act = d[sp]; sp--;
switch (act) {
case 0: iowr(); break; case 1: iord(); break;
case 2: iorb(); break; case 3: iowb(); break;
case 4: iosi(); break; case 5: ioli(); break;
case 6: ioen(); break; case 7: iost(); break;
}
}
public void process(int o) {
switch(o) {
case 0: no(); break; case 1: li(); break;
case 2: du(); break; case 3: dr(); break;
case 4: sw(); break; case 5: pu(); break;
case 6: po(); break; case 7: ju(); break;
case 8: ca(); break; case 9: cc(); break;
case 10: cj(); break; case 11: re(); break;
case 12: eq(); break; case 13: ne(); break;
case 14: lt(); break; case 15: gt(); break;
case 16: fe(); break; case 17: st(); break;
case 18: ad(); break; case 19: su(); break;
case 20: mu(); break; case 21: di(); break;
case 22: an(); break; case 23: or(); break;
case 24: xo(); break; case 25: sl(); break;
case 26: sr(); break; case 27: cp(); break;
case 28: cy(); break; case 29: io(); break;
}
}
public void execute() {
int raw = 0;
ip = 0;
while (ip < 65536) {
raw = m[ip];
for (int i = 0; i < 4; i++) {
process(raw & 0xFF);
raw = raw >> 8;
}
ip++;
}
}
public static void Main(string[] args) {
VM ilo = new VM();
ilo.execute();
}
}
}

187
source/ilo.cxx Normal file
View file

@ -0,0 +1,187 @@
/***************************************************************
crc's _ _
(_) | ___
| | |/ _ \ a tiny virtual computer
| | | (_) | 64kw RAM, 32-bit, Dual Stack, MISC
|_|_|\___/ ilo.cxx (c) charles childers
**************************************************************/
#include <iostream>
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
/* ip instruction pointer
sp data stack pointer
rp address stack pointer
ds data stack (32 values)
as address stack (256 values)
m memory (65,536 values)
rom name of image (default to ilo.rom)
blocks name of block file (default to ilo.blocks)
the other variables are used by the various functions for
misc. purposes
*/
int ip, sp, rp, ds[33], as[257], m[65536];
int a, b, t, fp, block, buffer, src, dest, len;
char *blocks, *rom, iob[2];
/* T is top of stack
N is next on stack
R is top of address stack
V is void
*/
#define T ds[sp]
#define N ds[sp-1]
#define R as[rp]
#define V void
int pop() { sp -= 1; return ds[sp + 1]; }
V push(int value) { sp += 1; ds[sp] = value; }
V prepare_vm() { ip = sp = rp = 0; }
V load_image() {
fp = open(rom, O_RDONLY, 0666);
if (!fp) { return; };
read(fp, &m, 65536 * 4);
close(fp);
prepare_vm();
}
V save_image() {
fp = open(rom, O_WRONLY, 0666);
write(fp, &m, 65536 * 4);
close(fp);
}
V block_common() {
buffer = pop();
block = pop();
lseek(fp, 4096 * block, SEEK_SET);
}
V read_block() {
fp = open(blocks, O_RDONLY, 0666);
block_common();
read(fp, m + buffer, 4096);
close(fp);
}
V write_block() {
fp = open(blocks, O_WRONLY, 0666);
block_common();
write(fp, m + buffer, 4096);
close(fp);
}
V save_ip() { rp += 1; R = ip; }
V symmetric() { if (b >= 0 && N < 0) { T++; N -= b; } }
V li() { ip += 1; push(m[ip]); }
V du() { push(T); }
V dr() { ds[sp] = 0; sp -= 1; }
V sw() { a = T; T = N; N = a; }
V pu() { rp += 1; R = pop(); }
V po() { push(R); rp -= 1; }
V ju() { ip = pop() - 1; }
V ca() { save_ip(); ip = pop() - 1; }
V cc() { t = pop(); if (pop()) { save_ip(); ip = t - 1; } }
V cj() { t = pop(); if (pop()) { ip = t - 1; } }
V re() { ip = R; rp -= 1; }
V eq() { N = (N == T) ? -1 : 0; sp -= 1; }
V ne() { N = (N != T) ? -1 : 0; sp -= 1; }
V lt() { N = (N < T) ? -1 : 0; sp -= 1; }
V gt() { N = (N > T) ? -1 : 0; sp -= 1; }
V fe() { T = m[T]; }
V st() { m[T] = N; sp -= 2; }
V ad() { N += T; sp -= 1; }
V su() { N -= T; sp -= 1; }
V mu() { N *= T; sp -= 1; }
V di() { a = T; b = N; T = b / a; N = b % a; symmetric(); }
V an() { N = T & N; sp -= 1; }
V or_() { N = T | N; sp -= 1; }
V xo() { N = T ^ N; sp -= 1; }
V sl() { N = N << T; sp -= 1; }
V sr() { N = N >> T; sp -= 1; }
V cp() { len = pop(); dest = pop(); src = pop(); push(-1);
while (len) {
if (m[dest] != m[src]) { T = 0; }
len -= 1; src += 1; dest += 1;
}
}
V cy() { len = pop(); dest = pop(); src = pop();
while (len) {
m[dest] = m[src];
len -= 1; src += 1; dest += 1;
}
}
V iowr() { iob[0] = pop(); write(1, &iob, 1); }
V iord() { read(0, &iob, 1); push(iob[0]); }
V iorb() { read_block(); }
V iowb() { write_block(); }
V iosi() { save_image(); }
V ioli() { load_image(); ip = -1; }
V ioen() { ip = 65536; }
V iost() { push(sp); push(rp); }
V io() {
switch (pop()) {
case 0: iowr(); break; case 1: iord(); break;
case 2: iorb(); break; case 3: iowb(); break;
case 4: iosi(); break; case 5: ioli(); break;
case 6: ioen(); break; case 7: iost(); break;
default: break;
}
}
/* Using a switch here instead of a jump table to avoid */
/* some issues w/relocation stuff when building w/o libc */
V process(int o) {
switch (o) {
case 0: break; case 1: li(); break;
case 2: du(); break; case 3: dr(); break;
case 4: sw(); break; case 5: pu(); break;
case 6: po(); break; case 7: ju(); break;
case 8: ca(); break; case 9: cc(); break;
case 10: cj(); break; case 11: re(); break;
case 12: eq(); break; case 13: ne(); break;
case 14: lt(); break; case 15: gt(); break;
case 16: fe(); break; case 17: st(); break;
case 18: ad(); break; case 19: su(); break;
case 20: mu(); break; case 21: di(); break;
case 22: an(); break; case 23: or_(); break;
case 24: xo(); break; case 25: sl(); break;
case 26: sr(); break; case 27: cp(); break;
case 28: cy(); break; case 29: io(); break;
default: break;
}
}
V process_bundle(int opcode) {
process(opcode & 0xFF);
process((opcode >> 8) & 0xFF);
process((opcode >> 16) & 0xFF);
process((opcode >> 24) & 0xFF);
}
V execute() {
while (ip < 65536) {
process_bundle(m[ip]);
ip += 1;
}
}
int main(int argc, char **argv) {
blocks = (argc > 1) ? argv[1] : (char *)"ilo.blocks";
rom = (argc > 2) ? argv[2] : (char *)"ilo.rom";
load_image();
execute();
for (; sp > 0; sp -= 1)
std::cout << ds[sp] << ' ';
std::cout << '\n';
return 0;
}

232
source/ilo.d Normal file
View file

@ -0,0 +1,232 @@
/***************************************************************
crc's _ _
(_) | ___
| | |/ _ \ a tiny virtual computer
| | | (_) | 64kw RAM, 32-bit, Dual Stack, MISC
|_|_|\___/ ilo.d (c) charles childers
**************************************************************/
import std.stdio;
Stack data, addr; /* data & address stacks */
RAM memory; /* system memory */
int ip; /* instruction pointer */
string blocks; /* name of block file (ilo.blocks) */
string rom; /* name of image (ilo.rom) */
void load_image() {
data = new Stack(33);
addr = new Stack(257);
memory = new RAM();
FILE *file = fopen(rom.ptr, "rb");
if (file is null) { return; }
fread(memory.pointer(), 1, 65536 * 4, file);
fclose(file);
ip = 0;
}
void save_image() {
FILE *file = fopen(rom.ptr, "wb");
fwrite(memory.pointer(), 1, 65536 * 4, file);
fclose(file);
}
void read_block() {
int[1024] block;
FILE *file = fopen(blocks.ptr, "rb");
if (file is null) { return; }
int b = data.pop(); /* block buffer */
int a = data.pop(); /* block number */
fseek(file, 4096 * a, SEEK_SET);
fread(block.ptr, 1, 4096, file);
foreach(i; 0 .. 1024) { memory.store(b + i, block[i]); }
fclose(file);
}
void write_block() {
int[1024] block;
FILE *file = fopen(blocks.ptr, "r+b");
if (file is null) { return; }
int b = data.pop(); /* block buffer */
int a = data.pop(); /* block number */
fseek(file, 4096 * a, SEEK_SET);
foreach(i; 0 .. 1024) { block[i] = memory.fetch(b + i); }
fwrite(block.ptr, 1, 4096, file);
fclose(file);
}
void li() { ip += 1; data.push(memory.fetch(ip)); }
void du() { data.dup(); }
void dr() { data.pop(); }
void sw() { data.swap(); }
void pu() { addr.push(data.pop()); }
void po() { data.push(addr.pop()); }
void ju() { ip = data.pop() - 1; }
void ca() { addr.push(ip); ip = data.pop() - 1; }
void cc() { int a = data.pop(); if (data.pop()) { addr.push(ip); ip = a - 1; } }
void cj() { int a = data.pop(); if (data.pop()) { ip = a - 1; } }
void re() { ip = addr.pop(); }
void eq() { data.swap(); data.push((data.pop() == data.pop()) ? -1 : 0); }
void ne() { data.swap(); data.push((data.pop() != data.pop()) ? -1 : 0); }
void lt() { data.swap(); data.push((data.pop() < data.pop()) ? -1 : 0); }
void gt() { data.swap(); data.push((data.pop() > data.pop()) ? -1 : 0); }
void fe() { data.push(memory.fetch(data.pop())); }
void st() { int a = data.pop(); memory.store(a, data.pop()); }
void ad() { data.swap(); data.push(data.pop() + data.pop()); }
void su() { data.swap(); data.push(data.pop() - data.pop()); }
void mu() { data.swap(); data.push(data.pop() * data.pop()); }
void di() { int a = data.pop(); int b = data.pop(); data.push(b % a); data.push(b / a); }
void an() { data.push(data.pop() & data.pop()); }
void or() { data.push(data.pop() | data.pop()); }
void xo() { data.push(data.pop() ^ data.pop()); }
void sl() { data.swap(); data.push(data.pop() << data.pop()); }
void sr() { data.swap(); data.push(data.pop() >> data.pop()); }
void cp() { int l = data.pop(); int d = data.pop(); int s = data.pop(); data.push(-1);
while (l) { if (memory.fetch(d) != memory.fetch(s)) { data.pop(); data.push(0); }
l -= 1; s += 1; d += 1; } }
void cy() { int l = data.pop(); int d = data.pop(); int s = data.pop();
while (l) { memory.store(d, memory.fetch(s)); l -= 1; s += 1; d += 1; } }
void ioa() { writef("%c", cast(char)data.pop()); }
void iob() { data.push(getchar()); }
void ioc() { read_block(); }
void iod() { write_block(); }
void ioe() { save_image(); }
void iof() { load_image(); ip = -1; }
void iog() { ip = 65536; }
void ioh() { data.push(data.depth()); data.push(addr.depth()); }
void io() {
switch (data.pop()) {
case 0: ioa(); break; case 1: iob(); break;
case 2: ioc(); break; case 3: iod(); break;
case 4: ioe(); break; case 5: iof(); break;
case 6: iog(); break; case 7: ioh(); break;
default: break;
}
}
void process(int o) {
switch (o) {
case 0: break; case 1: li(); break;
case 2: du(); break; case 3: dr(); break;
case 4: sw(); break; case 5: pu(); break;
case 6: po(); break; case 7: ju(); break;
case 8: ca(); break; case 9: cc(); break;
case 10: cj(); break; case 11: re(); break;
case 12: eq(); break; case 13: ne(); break;
case 14: lt(); break; case 15: gt(); break;
case 16: fe(); break; case 17: st(); break;
case 18: ad(); break; case 19: su(); break;
case 20: mu(); break; case 21: di(); break;
case 22: an(); break; case 23: or(); break;
case 24: xo(); break; case 25: sl(); break;
case 26: sr(); break; case 27: cp(); break;
case 28: cy(); break; case 29: io(); break;
default: break;
}
}
void process_bundle(int opcode) {
process(opcode & 0xFF);
process((opcode >> 8) & 0xFF);
process((opcode >> 16) & 0xFF);
process((opcode >> 24) & 0xFF);
}
void execute() {
while (ip < 65536) {
process_bundle(memory.fetch(ip));
ip += 1;
}
}
void main(string[] args) {
blocks = "ilo.blocks";
rom = "ilo.rom";
load_image();
execute();
data.print();
writef("\n");
}
class RAM {
private int[65536] data;
this() {
}
int fetch(int a) {
if (a < 0 || a > 65535)
throw new Exception("Invalid memory access");
return data[a];
}
void store(int a, int v) {
if (a < 0 || a > 65535)
throw new Exception("Invalid memory access");
data[a] = v;
}
int* pointer() {
return data.ptr;
}
}
class Stack {
private int[] stack;
private int top;
private int capacity;
this(int capacity) {
this.capacity = capacity;
stack = new int[capacity];
top = -1;
}
bool isEmpty() {
return top == -1;
}
bool isFull() {
return top == capacity - 1;
}
void push(int value) {
if (isFull())
throw new Exception("Stack overflow");
stack[++top] = value;
}
int pop() {
if (isEmpty())
throw new Exception("Stack underflow");
return stack[top--];
}
void dup() {
if (isEmpty())
throw new Exception("Stack is empty");
if (isFull())
throw new Exception("Stack overflow");
push(stack[top]);
}
void swap() {
if (top < 1)
throw new Exception("Insufficient elements to swap");
int temp = stack[top];
stack[top] = stack[top - 1];
stack[top - 1] = temp;
}
int depth() {
return top + 1;
}
void print() {
for (int i = top; i >= 0; i--) {
writeln(stack[i]);
}
}
}

BIN
source/ilo.fnt Normal file

Binary file not shown.

193
source/ilo.go Normal file
View file

@ -0,0 +1,193 @@
// ilo.go, (c) charles childers
package main
import (
"encoding/binary"
"fmt"
"os"
)
var d [33]int32
var a [257]int32
var m [65536]int32
var sp = 0
var rp = 0
var ip = 0
func pop() int32 { sp--; return d[sp + 1] }
func push(x int32) { sp++; d[sp] = x }
func prepare_vm() { ip = 0; sp = 0; rp = 0; }
func load_image() {
f, err := os.OpenFile("ilo.rom", os.O_RDONLY, 0)
if err != nil {
return
}
defer f.Close()
buf := make([]byte, 4)
var i int = 0
for i < 65536 {
f.Read(buf)
m[i] = int32(binary.LittleEndian.Uint32(buf[:4]))
i++
}
prepare_vm()
}
func save_image() {
}
func read_block() {
var buffer = pop()
var block = pop()
var blocks = "ilo.blocks"
if f, err := os.OpenFile(blocks, os.O_RDWR, 0666); err == nil {
f.Seek(int64(block * 4096), 0)
buf := make([]byte, 4)
var i int = 0
for i < 1024 {
f.Read(buf)
m[int(buffer) + i] = int32(binary.LittleEndian.Uint32(buf[:4]))
i++
}
f.Close()
}
}
func write_block() {
var buffer = pop()
var block = pop()
var blocks = "ilo.blocks"
if f, err := os.OpenFile(blocks, os.O_RDWR, 0666); err == nil {
f.Seek(int64(block * 4096), 0)
var buf = m[buffer:buffer+1024]
binary.Write(f, binary.LittleEndian, buf)
f.Close()
}
}
func no() { }
func li() { ip++; push(m[ip]) }
func du() { push(d[sp]) }
func dr() { sp-- }
func sw() { var y = pop(); var x = pop(); push(y); push(x); }
func pu() { rp++; a[rp] = pop() }
func po() { push(a[rp]); rp-- }
func ju() { ip = int(pop() - 1) }
func ca() { rp++; a[rp] = int32(ip); ju() }
func cc() { sw(); if (pop() != 0) { ca() } else { dr() } }
func cj() { sw(); if (pop() != 0) { ju() } else { dr() } }
func re() { ip = int(a[rp]); rp-- }
func eq() { var y = pop(); var x = pop(); if (x == y) { push(-1) } else { push(0) } }
func ne() { var y = pop(); var x = pop(); if (x != y) { push(-1) } else { push(0) } }
func lt() { var y = pop(); var x = pop(); if (x < y) { push(-1) } else { push(0) } }
func gt() { var y = pop(); var x = pop(); if (x > y) { push(-1) } else { push(0) } }
func fe() { var t = pop(); push(m[t]) }
func st() { var t = pop(); m[t] = pop() }
func ad() { var y = pop(); var x = pop(); push(x + y) }
func su() { var y = pop(); var x = pop(); push(x - y) }
func mu() { var y = pop(); var x = pop(); push(x * y) }
func di() { var y = pop(); var x = pop(); push(x % y); push(x / y) }
func an() { var y = pop(); var x = pop(); push(x & y) }
func or() { var y = pop(); var x = pop(); push(x | y) }
func xo() { var y = pop(); var x = pop(); push(x ^ y) }
func sl() { var y = pop(); var x = pop(); push(x << y) }
func sr() { var y = pop(); var x = pop(); push(x >> y) }
func cp() {
var len = pop()
var dest = pop()
var src = pop()
push(-1)
for len > 0 {
if m[dest] != m[src] { d[sp] = 0 }
len--; src++; dest++
}
}
func cy() {
var len = pop()
var dest = pop()
var src = pop()
for len > 0 {
m[dest] = m[src]
len--; src++; dest++
}
}
func iowr() { fmt.Printf("%c", pop()) }
func iord() {
var b []byte = make([]byte, 1)
os.Stdin.Read(b)
var c int = int(b[0])
push(int32(c))
}
func iorb() { read_block() }
func iowb() { write_block() }
func iosi() { save_image() }
func ioli() { load_image(); ip = -1 }
func ioen() { ip = 65536 }
func iost() { push(int32(sp)); push(int32(rp)) }
func io() {
var o = pop()
if o == 0 { iowr() }
if o == 1 { iord() }
if o == 2 { iorb() }
if o == 3 { iowb() }
if o == 4 { iosi() }
if o == 5 { ioli() }
if o == 6 { ioen() }
if o == 7 { iost() }
}
func process(o int32) {
if o == 0 { no() }
if o == 1 { li() }
if o == 2 { du() }
if o == 3 { dr() }
if o == 4 { sw() }
if o == 5 { pu() }
if o == 6 { po() }
if o == 7 { ju() }
if o == 8 { ca() }
if o == 9 { cc() }
if o == 10 { cj() }
if o == 11 { re() }
if o == 12 { eq() }
if o == 13 { ne() }
if o == 14 { lt() }
if o == 15 { gt() }
if o == 16 { fe() }
if o == 17 { st() }
if o == 18 { ad() }
if o == 19 { su() }
if o == 20 { mu() }
if o == 21 { di() }
if o == 22 { an() }
if o == 23 { or() }
if o == 24 { xo() }
if o == 25 { sl() }
if o == 26 { sr() }
if o == 27 { cp() }
if o == 28 { cy() }
if o == 29 { io() }
}
func process_bundle(o int32) {
process(o & 0xFF)
process((o >> 8) & 0xFF)
process((o >> 16) & 0xFF)
process((o >> 24) & 0xFF)
}
func execute() {
for ip < 65536 {
process_bundle(m[ip])
ip++
}
}
func main() {
load_image()
execute()
}

239
source/ilo.ha Normal file
View file

@ -0,0 +1,239 @@
// ilo.ha, an ilo in hare
use bufio;
use fmt;
use fs;
use io;
use math;
use os;
let ds: [33]i32 = [0...];
let rs: [257]i32 = [0...];
let m: [65536]i32 = [0...];
let sp: i32 = 0;
let rp: i32 = 0;
let ip: i32 = 0;
let a: i32 = 0;
let b: i32 = 0;
let c: i32 = 0;
fn initialize() void = {
sp = 0;
rp = 0;
ip = 0;
load();
};
fn load() void = {
const input = match (os::open("ilo.rom")) {
case let file: io::file =>
yield file;
case let err: fs::error =>
fmt::fatalf("Error opening {}: {}",
os::args[1], fs::strerror(err));
};
defer io::close(input)!;
let rdbuf: [os::BUFSZ]u8 = [0...];
let input = &bufio::init(input, rdbuf, []);
let i = 0;
let buf: [4]u8 = [0, 0, 0, 0];
for (!(io::read(input, buf)! is io::EOF)) {
let x: u32 = m[i]:u32;
x = x + (buf[3]:u32 << 24);
x = x + (buf[2]:u32 << 16);
x = x + (buf[1]:u32 << 8);
x = x + (buf[0]:u32 << 0);
m[i] = x:i32;
i = i + 1;
};
};
fn read_block(block:i32, buffer:i32) void = {
const block_store = match (os::open("ilo.blocks")) {
case let file: io::file =>
yield file;
case let err: fs::error =>
fmt::fatalf("Error opening {}: {}",
"ilo.blocks", fs::strerror(err));
};
defer io::close(block_store)!;
let rdbuf: [os::BUFSZ]u8 = [0...];
let block_store = &bufio::init(block_store, rdbuf, []);
let i: i32 = 0;
let buf: [4096]u8 = [0...];
// this is not an optimal way, need to figure out
// io::seek
// io::seek(block_store, block * 4096, io::whence::SET)!;
let za:i32 = 0;
for (za < block) {
io::read(block_store, buf)!;
za = za + 1;
};
let cell: [4]u8 = [0...];
// read in the block
for (i < 1024) {
io::read(block_store, cell)!;
let x: u32 = 0;
x = x + (cell[3]:u32 << 24);
x = x + (cell[2]:u32 << 16);
x = x + (cell[1]:u32 << 8);
x = x + (cell[0]:u32 << 0);
let t:i32 = buffer + i;
m[t] = x:i32;
i = i + 1;
};
};
fn write_block(block:i32, buffer:i32) void = {
const block_store = match (os::open("ilo.blocks", fs::flag::RDWR)) {
case let file: io::file =>
yield file;
case let err: fs::error =>
fmt::fatalf("Error opening {}: {}",
"ilo.blocks", fs::strerror(err));
};
defer io::close(block_store)!;
let rdbuf: [os::BUFSZ]u8 = [0...];
let wrbuf: [os::BUFSZ]u8 = [0...];
let block_store = &bufio::init(block_store, rdbuf, wrbuf);
let i: i32 = 0;
let buf: [4096]u8 = [0...];
let za:i32 = 0;
for (za < block) {
io::read(block_store, buf)!;
za = za + 1;
};
let cell: [4]u8 = [0...];
// read in the block
for (i < 1024) {
let t:i32 = buffer + i;
let x: u32 = m[t]:u32;
cell[3] = ((x >> 24) & 0xFF):u8;
cell[2] = ((x >> 16) & 0xFF):u8;
cell[1] = ((x >> 8) & 0xFF):u8;
cell[0] = ((x >> 0) & 0xFF):u8;
io::write(block_store, cell)!;
i = i + 1;
};
io::close(block_store)!;
};
fn push(v: i32) void = { sp = sp + 1; ds[sp] = v; };
fn pop() i32 = { sp = sp - 1; return ds[sp + 1]; };
fn save_ip() void = { rp = rp + 1; rs[rp] = ip; };
fn no() void = { return; };
fn li() void = { ip = ip + 1; push(m[ip]); };
fn du() void = { push(ds[sp]); };
fn dr() void = { pop(); };
fn sw() void = { a = pop(); b = pop(); push(a); push(b); };
fn pu() void = { rp = rp + 1; rs[rp] = pop(); };
fn po() void = { push(rs[rp]); rp = rp - 1; };
fn ju() void = { ip = pop() - 1; };
fn ca() void = { save_ip(); ip = pop() - 1; };
fn cc() void = { a = pop(); if (pop() != 0) { save_ip(); ip = a - 1; }; };
fn cj() void = { a = pop(); if (pop() != 0) { ip = a - 1; }; };
fn re() void = { ip = rs[rp]; rp = rp - 1; };
fn eq() void = { a = pop(); b = pop();
if (a == b) { push(-1); } else { push(0); }; };
fn ne() void = { a = pop(); b = pop();
if (a != b) { push(-1); } else { push(0); }; };
fn lt() void = { a = pop(); b = pop();
if (b < a) { push(-1); } else { push(0); }; };
fn gt() void = { a = pop(); b = pop();
if (b > a) { push(-1); } else { push(0); }; };
fn fe() void = { ds[sp] = m[ds[sp]]; };
fn st() void = { m[ds[sp]] = ds[sp - 1]; sp = sp - 2; };
fn ad() void = { ds[sp - 1] = ds[sp - 1] + ds[sp]; pop(); };
fn su() void = { ds[sp - 1] = ds[sp - 1] - ds[sp]; pop(); };
fn mu() void = { ds[sp - 1] = ds[sp - 1] * ds[sp]; pop(); };
fn di() void = { a = ds[sp]; b = ds[sp - 1];
ds[sp] = b / a; ds[sp - 1] = b % a; };
fn an() void = { ds[sp - 1] = ds[sp - 1] & ds[sp]; pop(); };
fn or() void = { ds[sp - 1] = ds[sp - 1] | ds[sp]; pop(); };
fn xo() void = { ds[sp - 1] = ds[sp - 1] ^ ds[sp]; pop(); };
fn sl() void = { ds[sp - 1] = ds[sp - 1] << ds[sp]; pop(); };
fn sr() void = { ds[sp - 1] = ds[sp - 1] >> ds[sp]; pop(); };
fn cp() void = {
a = pop(); b = pop(); c = pop(); push(-1);
for (a > 0; a = a - 1) {
if (m[b] != m[c]) { ds[sp] = 0; };
b = b + 1;
c = c + 1;
};
};
fn cy() void = {
a = pop(); b = pop(); c = pop();
for (a > 0; a = a - 1) {
m[b] = m[c];
b = b + 1;
c = c + 1;
};
};
fn io() void = {
switch (pop()) {
case => return;
case 0 => fmt::printf("{}", pop():rune)!; return;
case 1 => let buf: [1]u8 = [0];
io::read(os::stdin, buf)!;
let z:i32 = buf[0]:i32;
push(z); return;
case 2 => let buf = pop(); let blk = pop();
read_block(blk, buf);
return;
case 3 => let buf = pop(); let blk = pop();
write_block(blk, buf);
return;
case 4 => return;
case 5 => initialize(); ip = -1; return;
case 6 => fmt::fatal("BYE!");
case 7 => push(sp); push(rp); return;
};
};
fn process(o: i32) void = {
switch (o) {
case => return;
case 0 => return; case 1 => return li();
case 2 => return du(); case 3 => return dr();
case 4 => return sw(); case 5 => return pu();
case 6 => return po(); case 7 => return ju();
case 8 => return ca(); case 9 => return cc();
case 10 => return cj(); case 11 => return re();
case 12 => return eq(); case 13 => return ne();
case 14 => return lt(); case 15 => return gt();
case 16 => return fe(); case 17 => return st();
case 18 => return ad(); case 19 => return su();
case 20 => return mu(); case 21 => return di();
case 22 => return an(); case 23 => return or();
case 24 => return xo(); case 25 => return sl();
case 26 => return sr(); case 27 => return cp();
case 28 => return cy(); case 29 => return io();
};
};
fn execute() void = {
for (ip < 65536) {
let opcode = m[ip];
process(opcode & 0xFF);
process((opcode >> 8) & 0xFF);
process((opcode >> 16) & 0xFF);
process((opcode >> 24) & 0xFF);
ip = ip + 1;
};
};
export fn main() void = {
initialize();
execute();
};

280
source/ilo.kt Normal file
View file

@ -0,0 +1,280 @@
// -------------------------------------------------------------
// ilo.kt, (c) charles childers
//
// build:
//
// kotlinc ilo.kt -include-runtime -d ilo.jar
//
// run:
//
// kotlin ilo.jar
// -------------------------------------------------------------
import java.io.File
var blocks = IntArray(1024*1024*4)
var input = ""
var ip = 0
var m = IntArray(65536)
var d = Stack()
var a = Stack()
fun ino() {}
fun ili() { ip++; d.push(m[ip]) }
fun idu() { d.push(d.tos()) }
fun idr() { d.pop() }
fun isw() { var x = d.pop(); var y = d.pop(); d.push(x); d.push(y) }
fun ipu() { a.push(d.pop()) }
fun ipo() { d.push(a.pop()) }
fun iju() { ip = d.pop() - 1 }
fun ica() { a.push(ip); iju() }
fun icc() { val t = d.pop(); if (d.pop() != 0) { a.push(ip); ip = t - 1 } }
fun icj() { val t = d.pop(); if (d.pop() != 0) { ip = t - 1 } }
fun ire() { ip = a.pop() }
fun ieq() { val x = d.pop(); val y = d.pop(); if (y == x) { d.push(-1) } else { d.push(0) } }
fun ine() { val x = d.pop(); val y = d.pop(); if (y != x) { d.push(-1) } else { d.push(0) } }
fun ilt() { val x = d.pop(); val y = d.pop(); if (y < x) { d.push(-1) } else { d.push(0) } }
fun igt() { val x = d.pop(); val y = d.pop(); if (y > x) { d.push(-1) } else { d.push(0) } }
fun ife() { val t = d.pop(); d.push(m[t]) }
fun ist() { val t = d.pop(); m[t] = d.pop() }
fun iad() { val x = d.pop(); val y = d.pop(); d.push(y + x) }
fun isu() { val x = d.pop(); val y = d.pop(); d.push(y - x) }
fun imu() { val x = d.pop(); val y = d.pop(); d.push(y * x) }
fun idi() { val x = d.pop(); val y = d.pop(); d.push(y % x); d.push(y / x) }
fun ian() { val x = d.pop(); val y = d.pop(); d.push(y and x) }
fun ior() { val x = d.pop(); val y = d.pop(); d.push(y or x) }
fun ixo() { val x = d.pop(); val y = d.pop(); d.push(y xor x) }
fun isl() { val x = d.pop(); val y = d.pop(); d.push(y shl x) }
fun isr() { val x = d.pop(); val y = d.pop(); d.push(y shr x) }
fun icp() {
var l = d.pop()
var t = d.pop()
var s = d.pop()
d.push(-1)
while (l > 0) {
if (m[t] != m[s]) { d.pop(); d.push(0) }
t++; s++; l--
}
}
fun icy() {
var l = d.pop()
var t = d.pop()
var s = d.pop()
while (l > 0) {
m[t] = m[s]
t++; s++; l--
}
}
fun iio() {
when (d.pop()) {
0 -> io_co()
1 -> io_ci()
2 -> io_rb()
3 -> io_wb()
4 -> io_si()
5 -> io_pc()
6 -> io_of()
7 -> io_sd()
}
}
fun io_co() { print(d.pop().toChar()) }
fun io_ci() {
if (input.length > 0) {
val c = input.first()
val v = c.code
d.push(v)
input = input.drop(1)
} else {
d.push(32)
}
}
fun io_rb() { read_block() }
fun io_wb() { write_block() }
fun io_si() { }
fun io_pc() { boot(); ip = -1 }
fun io_of() { ip = 65536 }
fun io_sd() { d.push(d.depth()); d.push(a.depth()) }
// -------------------------------------------------------------
// -------------------------------------------------------------
fun load_blocks() {
val bs = File("./ilo.blocks")
val bytes:ByteArray = bs.readBytes()
var i = 0
var o = 0
while (i < (1024*1024)) {
val x = (bytes[o++].toInt() and 0xff shl 24) or
(bytes[o++].toInt() and 0xff shl 16) or
(bytes[o++].toInt() and 0xff shl 8) or
(bytes[o++].toInt() and 0xff)
blocks[i] = fix(x.toLong())
i++
}
}
fun read_block() {
load_blocks()
val buffer = d.pop()
val block = d.pop()
var i = 0
while (i < 1024) {
m[buffer + i] = blocks[(block * 1024) + i]
i++
}
}
fun write_block() {
val buffer = d.pop()
val block = d.pop()
// update `blocks` cache
var i = 0
while (i < 1024) {
blocks[(block * 1024) + i] = m[buffer + i]
i++
}
// write `blocks` cache back to disk
val bs = File("./ilo.blocks")
var dump: ByteArray = ByteArray(1024*1024*4)
i = 0
var o = 0
while (i < (1024*1024)) {
val cell = fix(blocks[i].toLong())
dump[o++] = ((cell shr 24) and 0xFF).toByte()
dump[o++] = ((cell shr 16) and 0xFF).toByte()
dump[o++] = ((cell shr 8) and 0xFF).toByte()
dump[o++] = (cell and 0xFF).toByte()
i++
}
bs.writeBytes(dump)
}
fun process_instruction(op: Int) {
when (op) {
0 -> ino()
1 -> ili()
2 -> idu()
3 -> idr()
4 -> isw()
5 -> ipu()
6 -> ipo()
7 -> iju()
8 -> ica()
9 -> icc()
10 -> icj()
11 -> ire()
12 -> ieq()
13 -> ine()
14 -> ilt()
15 -> igt()
16 -> ife()
17 -> ist()
18 -> iad()
19 -> isu()
20 -> imu()
21 -> idi()
22 -> ian()
23 -> ior()
24 -> ixo()
25 -> isl()
26 -> isr()
27 -> icp()
28 -> icy()
29 -> iio()
else -> {
println("Invalid instruction!")
print("IP:")
print(ip)
print(" OC:")
println(op)
}
}
}
fun process() {
while (input.length > 0 && ip < 65536) {
val cur = ip
process_instruction(m[cur] and 0xFF)
process_instruction((m[cur] shr 8) and 0xFF)
process_instruction((m[cur] shr 16) and 0xFF)
process_instruction((m[cur] shr 24) and 0xFF)
ip++
}
}
fun boot() {
load_image()
load_blocks()
ip = 0
d.empty()
a.empty()
input = " "
process()
}
fun load_image() {
val bs = File("./ilo.rom")
val bytes:ByteArray = bs.readBytes()
var i = 0
var o = 0
while (i < 65536) {
val x = (bytes[o++].toInt() and 0xff shl 24) or
(bytes[o++].toInt() and 0xff shl 16) or
(bytes[o++].toInt() and 0xff shl 8) or
(bytes[o++].toInt() and 0xff)
m[i] = fix(x.toLong())
i++
}
}
// The JVM is a big endian system. ilo stores data & rom in
// little endian. This routine converts the data between these
// when necessary.
fun fix(v: Long): Int {
return (((v and 0x000000FF) shl 24) or
((v and 0x0000FF00) shl 8) or
((v and 0x00FF0000) shr 8) or
((v and 0xFF000000) shr 24)).toInt()
}
fun main(args: Array<String>) {
boot()
while (ip < 65536) {
input = readln()
input = " " + input + " \n"
process()
}
}
class Stack {
var sp = 0
var data = IntArray(256)
fun push(v: Int) {
sp++
data[sp] = v
}
fun pop(): Int {
sp--
return data[sp + 1]
}
fun tos(): Int {
return data[sp]
}
fun empty() {
sp = 0
}
fun depth(): Int {
return sp
}
}

343
source/ilo.lua Normal file
View file

@ -0,0 +1,343 @@
-- ilo.lua
-- Partially derived from Ngaro in Lua
-- Copyright (c) 2010 - 2023, Charles Childers
--
-- This is only tested on Lua 5.4 and requires 32-bit
-- integers. (set `#define LUA_32BITS 1` in luaconf.h when
-- building Lua)
-- Variables
local ip = 0 -- instruction pointer
local sp = 0 -- stack pointer
local rp = 0 -- return pointer
local stack = {} -- data stack
local address = {} -- return stack
local memory = {} -- simulated ram
-- Support Code
local function file_size(filename)
local fh = assert(io.open(filename, 'rb'))
local len = assert(fh:seek('end'))
fh:close()
return len
end
local function constrain(n)
return (n > 0x7FFFFFFF) and (n - 0x100000000) or n
end
local function save_image()
local image = io.open('ilo.rom', 'wb')
local i = 0
while i < 65536 do
image:write(string.pack('<i4', memory[i]))
i = i + 1
end
image:close()
end
local function read_block()
local blocks = io.open('ilo.blocks', 'rb')
local buffer = stack[sp]
local block = stack[sp - 1]
sp = sp - 2
local i = 0
blocks:seek('set', block * 4096)
while i < 1024 do
memory[buffer] = string.unpack('<i4', blocks:read(4))
buffer = buffer + 1
i = i + 1
end
blocks:close()
end
local function write_block()
local blocks = io.open('ilo.blocks', 'r+b')
local buffer = stack[sp]
local block = stack[sp - 1]
sp = sp - 2
local i = 0
blocks:seek('set', block * 4096)
while i < 1024 do
local x = memory[buffer + i]
local b4=string.char(x%256) x=(x-x%256)/256
local b3=string.char(x%256) x=(x-x%256)/256
local b2=string.char(x%256) x=(x-x%256)/256
local b1=string.char(x%256) x=(x-x%256)/256
blocks:write(b4,b3,b2,b1)
i = i + 1
end
blocks:close()
end
local opcodes = {
[0] = function() end, -- no (nop)
[1] = function() -- li (lit)
sp = sp + 1
ip = ip + 1
stack[sp] = memory[ip]
end,
[2] = function() -- du (dup)
sp = sp + 1
stack[sp] = stack[sp - 1]
end,
[3] = function() -- dr (drop)
sp = sp - 1
end,
[4] = function() -- sw (swap)
local a = stack[sp]
stack[sp] = stack[sp - 1]
stack[sp - 1] = a
end,
[5] = function() -- pu (push)
rp = rp + 1
address[rp] = stack[sp]
sp = sp - 1
end,
[6] = function() -- po (pop)
sp = sp + 1
stack[sp] = address[rp]
rp = rp - 1
end,
[7] = function() -- ju (jump)
ip = stack[sp] - 1
sp = sp - 1
end,
[8] = function() -- ca (call)
rp = rp + 1
address[rp] = ip
ip = stack[sp] - 1
sp = sp - 1
end,
[9] = function() -- cc (cond. call)
if stack[sp - 1] ~= 0 then
rp = rp + 1
address[rp] = ip
ip = stack[sp] - 1
end
sp = sp - 2
end,
[10] = function() -- cj (cond. jump)
if stack[sp - 1] ~= 0 then
ip = stack[sp] - 1
end
sp = sp - 2
end,
[11] = function() -- re (return)
ip = address[rp]
rp = rp - 1
end,
[12] = function() -- eq (equality)
if stack[sp - 1] == stack[sp] then
stack[sp - 1] = -1
else
stack[sp - 1] = 0
end
sp = sp - 1
end,
[13] = function() -- ne (inequality)
if stack[sp - 1] == stack[sp] then
stack[sp - 1] = 0
else
stack[sp - 1] = -1
end
sp = sp - 1
end,
[14] = function() -- lt (less than)
if stack[sp - 1] < stack[sp] then
stack[sp - 1] = -1
else
stack[sp - 1] = 0
end
sp = sp - 1
end,
[15] = function() -- gt (greater than)
if stack[sp - 1] > stack[sp] then
stack[sp - 1] = -1
else
stack[sp - 1] = 0
end
sp = sp - 1
end,
[16] = function() -- fe (fetch)
stack[sp] = memory[stack[sp]]
end,
[17] = function() -- st (store)
memory[stack[sp]] = stack[sp - 1]
sp = sp - 2
end,
[18] = function() -- ad (add)
stack[sp - 1] = stack[sp - 1] + stack[sp]
sp = sp - 1
end,
[19] = function() -- su (subtract)
stack[sp - 1] = stack[sp - 1] - stack[sp]
sp = sp - 1
end,
[20] = function() -- mu (multiply)
stack[sp - 1] = stack[sp - 1] * stack[sp]
sp = sp - 1
end,
[21] = function() -- di (divide & remainder)
local b = stack[sp]
local a = stack[sp - 1]
local x = math.abs(b)
local y = math.abs(a)
local q = constrain(y // x)
local r = constrain(y % x)
if a < 0 and b < 0 then
r = r * -1
elseif a > 0 and b < 0 then
q = q * -1
elseif a < 0 and b > 0 then
r = r * -1
q = q * -1
end
stack[sp] = q
stack[sp - 1] = r
end,
[22] = function() -- an (and)
stack[sp - 1] = stack[sp - 1] & stack[sp]
sp = sp - 1
end,
[23] = function() -- or (or)
stack[sp - 1] = stack[sp - 1] | stack[sp]
sp = sp - 1
end,
[24] = function() -- xo (xor)
stack[sp - 1] = stack[sp - 1] ~ stack[sp]
sp = sp - 1
end,
[25] = function() -- sl (shift left)
stack[sp - 1] = stack[sp - 1] << stack[sp]
sp = sp - 1
end,
[26] = function() -- sr (shift right)
stack[sp - 1] = stack[sp - 1] >> stack[sp]
sp = sp - 1
end,
[27] = function() -- cp (compare)
local a = stack[sp] -- length
local b = stack[sp - 1] -- dest
local c = stack[sp - 2] -- source
local d = -1 -- flag
sp = sp - 3
while a > 0 do
if memory[b] ~= memory[c] then
d = 0
end
a = a - 1
b = b + 1
c = c + 1
end
sp = sp + 1
stack[sp] = d
end,
[28] = function() -- cy (copy)
local a = stack[sp] -- length
local b = stack[sp - 1] -- dest
local c = stack[sp - 2] -- source
sp = sp - 3
while a > 0 do
memory[b] = memory[c]
a = a - 1
b = b + 1
c = c + 1
end
end,
[29] = function() -- io
local d = stack[sp]
sp = sp - 1
if d == 0 then
io.write(string.char(stack[sp]))
sp = sp - 1
elseif d == 1 then
sp = sp + 1
stack[sp] = string.byte(io.read(1))
elseif d == 2 then
read_block()
elseif d == 3 then
write_block()
elseif d == 4 then
save_image()
elseif d == 5 then
load_image("ilo.rom")
ip = -1
sp = 0
rp = 0
elseif d == 6 then
ip = 65536
elseif d == 7 then
sp = sp + 1
stack[sp] = sp - 1
sp = sp + 1
stack[sp] = rp
end
end
}
-- -------------------------------------------------------------
-- process opcodes
local function process_opcode(opcode)
if opcode == 0 then return end -- skip NOP instructions
local op_fn = opcodes[opcode]
if op_fn then op_fn() end
end
local function process_opcodes()
local opcode = memory[ip]
process_opcode(opcode & 0xFF)
process_opcode(opcode>>8 & 0xFF)
process_opcode(opcode>>16 & 0xFF)
process_opcode(opcode>>24 & 0xFF)
end
-- Load image into memory
-- \ cells = size of image file (in cells)
-- \ image = pointer to retroImage file
local function load_image(file)
local cells = file_size(file) / 4
local image = io.open(file, 'rb')
local i = 0
while i < cells do
memory[i] = string.unpack('<i4', image:read(4))
i = i + 1
end
image:close()
while i < 65536 do
memory[i] = 0
i = i + 1
end
i = 0
while i < 33 do
stack[i] = 0
address[i] = 0
i = i + 1
end
while i < 257 do
address[i] = 0
i = i + 1
end
end
local function dump_stack()
while sp > 0 do
print(stack[sp])
sp = sp - 1
end
end
local function process_instructions()
while ip < 65536 do
process_opcodes()
ip = ip + 1
end
end
local function main()
load_image("ilo.rom")
process_instructions()
dump_stack()
end
main()

241
source/ilo.nim Normal file
View file

@ -0,0 +1,241 @@
# **************************************************************
# crc's _ _
# (_) | ___
# | | |/ _ \ a tiny virtual computer
# | | | (_) | 64kw RAM, 32-bit, Dual Stack, MISC
# |_|_|\___/ ilo.nim (c) charles childers
# **************************************************************
# nim c -r vm/ilo.nim
{.push overflowChecks: off.}
var
ip, sp, rp: int32
s: array[33, int32]
r: array[257, int32]
m: array[65536, int32]
let
rom = "ilo.rom"
blocks = "ilo.blocks"
proc load_image() =
let f = open(rom)
defer: f.close()
discard f.readBuffer(addr m[0], sizeof(m))
proc read_block() =
let f = open(blocks)
let buf = s[sp]
let blk = s[sp - 1]
sp = sp - 2
defer: f.close()
f.setFilePos(blk * 4096)
discard f.readBuffer(addr m[buf], 4096)
proc write_block() =
let f = open(blocks, fmReadWriteExisting)
let buf = s[sp]
let blk = s[sp - 1]
sp = sp - 2
defer: f.close()
f.setFilePos(blk * 4096)
discard f.writeBuffer(addr m[buf], 4096)
proc save_image() =
return
proc opcode(o: int32) =
case o:
of 0: # ..
return
of 1: # li
ip = ip + 1
sp = sp + 1
s[sp] = m[ip]
of 2: # du
sp = sp + 1
s[sp] = s[sp - 1]
of 3: # dr
sp = sp - 1
of 4: # sw
let a = s[sp]
let b = s[sp - 1]
s[sp] = b
s[sp - 1] = a
of 5: # pu
rp = rp + 1
r[rp] = s[sp]
sp = sp - 1
of 6: # po
sp = sp + 1
s[sp] = r[rp]
rp = rp - 1
of 7: # ju
ip = s[sp] - 1
sp = sp - 1
of 8: # ca
rp = rp + 1
r[rp] = ip
ip = s[sp] - 1
sp = sp - 1
of 9: # cc
let target = s[sp]
let flag = s[sp - 1]
sp = sp - 2
if flag != 0:
rp = rp + 1
r[rp] = ip
ip = target - 1
of 10: # cj
let target = s[sp]
let flag = s[sp - 1]
sp = sp - 2
if flag != 0:
ip = target - 1
of 11: # re
ip = r[rp]
rp = rp - 1
of 12: # eq
let b = s[sp]
let a = s[sp - 1]
sp = sp - 1
if a == b:
s[sp] = -1
else:
s[sp] = 0
of 13: # ne
let b = s[sp]
let a = s[sp - 1]
sp = sp - 1
if a != b:
s[sp] = -1
else:
s[sp] = 0
of 14: # lt
let b = s[sp]
let a = s[sp - 1]
sp = sp - 1
if a < b:
s[sp] = -1
else:
s[sp] = 0
of 15: # gt
let b = s[sp]
let a = s[sp - 1]
sp = sp - 1
if a > b:
s[sp] = -1
else:
s[sp] = 0
of 16: # fe
s[sp] = m[s[sp]]
of 17: # st
m[s[sp]] = s[sp - 1]
sp = sp - 2
of 18: # ad
s[sp - 1] = s[sp - 1] + s[sp]
sp = sp - 1
of 19: # su
s[sp - 1] = s[sp - 1] - s[sp]
sp = sp - 1
of 20: # mu
s[sp - 1] = s[sp - 1] * s[sp]
sp = sp - 1
of 21: # di
let b = s[sp]
let a = s[sp - 1]
s[sp] = a div b
s[sp - 1] = a mod b
of 22: # an
s[sp - 1] = s[sp - 1] and s[sp]
sp = sp - 1
of 23: # or
s[sp - 1] = s[sp - 1] or s[sp]
sp = sp - 1
of 24: # xo
s[sp - 1] = s[sp - 1] xor s[sp]
sp = sp - 1
of 25: # sl
s[sp - 1] = s[sp - 1] shl s[sp]
sp = sp - 1
of 26: # sr
s[sp - 1] = s[sp - 1] shr s[sp]
sp = sp - 1
of 27: # cp
var length: int32 = s[sp]
var dest: int32 = s[sp - 1]
var src: int32 = s[sp - 2]
var flag: int32 = -1
sp = sp - 2
while length != 0:
if m[dest] != m[src]:
flag = 0
dest = dest + 1
src = src + 1
length = length - 1
s[sp] = flag
of 28: # cy
var length: int32 = s[sp]
var dest: int32 = s[sp - 1]
var src: int32 = s[sp - 2]
sp = sp - 3
while length != 0:
m[dest] = m[src]
dest = dest + 1
src = src + 1
length = length - 1
of 29: # io
let dev = s[sp]
sp = sp - 1
case dev:
of 0:
if s[sp] != 0:
stdout.write $(char(s[sp]))
sp = sp - 1
of 1:
var buf: array[1, byte]
discard stdin.readBytes(buf, 0, 1)
sp = sp + 1
s[sp] = int32(buf[0])
of 2:
read_block()
of 3:
write_block()
of 4:
echo "save_image()"
of 5:
load_image()
ip = 0
sp = 0
rp = 0
of 6:
ip = 65536
of 7:
sp = sp + 1
s[sp] = sp - 1
sp = sp + 1
s[sp] = rp
else:
echo "unsupported io:", dev
else:
echo "wtf?"
proc process() =
while ip < 65536:
let a = m[ip] and 255
let b = (m[ip] shr 8) and 255
let c = (m[ip] shr 16) and 255
let d = (m[ip] shr 24) and 255
opcode(a)
opcode(b)
opcode(c)
opcode(d)
ip = ip + 1
ip = 0
sp = 0
rp = 0
load_image()
process()

515
source/ilo.py Normal file
View file

@ -0,0 +1,515 @@
# **************************************************************
# crc's _ _
# (_) | ___
# | | |/ _ \ a tiny virtual computer
# | | | (_) | 64kw RAM, 32-bit, Dual Stack, MISC
# |_|_|\___/ ilo.py (c) charles childers
# (c) arland childers
# **************************************************************
#Ilo.py v2.2b
#Changes:
# Split debug modes:
# 'instrs': Counts overall time, and counts each instruction/bundle.
# 'timing': Just gives elapsed time.
# 'cProfile': Using cProfile, measure time & time for all instructions+overhead. Does not count time for unoptimised bundles.
# Added more optimised instruction bundles, focusing on DTC.
# Optimised many instructions, removing uneeded vars. Added raw_lit to not limit it when it is not needed.
# Faster block unpacking. The uncached blocks seem to only be ~1.7x slower instead of ~2x, now.
# Sorted some of the instructions listing, in the hopes it may make an improvement. It did not seem to.
# Added calls to limit the rom and blocks as they get put into memory.
#--- CONFIG
BLOCK_FILE = 'ilo.blocks'
ROM_FILE = 'ilo.rom'
BLOCK_CACHE = True
DEBUG = False
# False for nothing
# 'timing' just gives elapsed time. Negligible time loss
# 'Instrs' counts instructions & bundles, but ~2.3x slower
# 'cProfile' for cProfile, but ~3.25x slower
#--- ILO
import os
def limit(val):
val &= 0xffffffff
if val & 0x80000000:
val -= 0x100000000
return val
def div_mod(a, b):
x = abs(a)
y = abs(b)
q, r = divmod(x, y)
if a < 0 and b < 0:
r *= -1
elif a > 0 and b < 0:
q *= -1
elif a < 0 and b > 0:
r *= -1
q *= -1
return q, r
class Stack:
def __init__(self, size):
self.sp = 0
self.data = [0] * size
self.max = size
def lit(self, val):
self.sp += 1
self.data[self.sp] = ((val & 0xffffffff)-0x100000000) if val & 0x80000000 else (val & 0xffffffff)
def raw_lit(self, val):
self.sp += 1
self.data[self.sp] = val
def pop(self):
self.sp -= 1
return self.data[self.sp + 1]
def top(self):
return self.data[self.sp]
def second(self):
return self.data[self.sp - 1]
def depth(self):
return self.sp
class BlockTools_NoCache:
def __init__(self, block_file, rom_file, data_stack, memory):
self.BLOCK_FILE = block_file
self.ROM_FILE = rom_file
self.data_stack = data_stack
self.memory = memory
def block_unpack(self, block):
return [(limit(block[i] | (block[i + 1] << 8) | (block[i + 2] << 16) | (block[i + 3] << 24))) for i in range(0, len(block), 4)]
def block_pack(self, *values):
return b''.join(val.to_bytes(4, 'little', signed=True) for val in values)
def read_block(self):
buffer = self.data_stack.pop()
block = self.data_stack.pop()
with open(self.BLOCK_FILE, 'r+b') as f:
f.seek(4096 * block)
self.memory[buffer: buffer + 1024] = list(self.block_unpack(f.read(4096)))
def block_write(self):
buffer = self.data_stack.pop()
block = self.data_stack.pop()
with open(self.BLOCK_FILE, 'r+b') as f:
f.seek(4096 * block)
f.write(self.block_pack(*self.memory[buffer: buffer + 1024]))
def load_image(self):
with open(self.ROM_FILE, 'rb') as f:
raw_data = f.read(4 * 65536)
self.memory[:] = [limit(int.from_bytes(raw_data[i:i + 4], 'little')) for i in range(0, len(raw_data), 4)]
def save_image(self):
with open(self.ROM_FILE, 'wb') as f:
for value in self.memory[:65536]:
f.write(value.to_bytes(4, 'little'))
class BlockTools(BlockTools_NoCache): # caches blocks.
def __init__(self, block_file, rom_file, data_stack, memory):
self.BLOCK_FILE = block_file
self.ROM_FILE = rom_file
self.data_stack = data_stack
self.memory = memory
self.block_time = os.path.getmtime(block_file)
self.blocks = []
def read_block(self):
if self.block_time != os.path.getmtime(self.BLOCK_FILE):
self.read_all_blocks()
self.block_time = os.path.getmtime(self.BLOCK_FILE)
buffer = self.data_stack.pop()
self.memory[buffer: buffer + 1024] = self.blocks[self.data_stack.pop()]
def read_all_blocks(self):
with open(self.BLOCK_FILE, 'rb') as f:
all_block_data = f.read()
self.blocks = [list(self.block_unpack(all_block_data[i:i+4096])) for i in range(0, len(all_block_data), 4096)]
return self.blocks
class ilo:
def __init__(self, block_file='ilo.blocks', rom_file='ilo.rom', cache_blocks=False):
self.ip = 0
self.memory = [0]
self.input_buffer = []
self.data = Stack(33)
self.address = Stack(257)
if cache_blocks:
self.block_tools = BlockTools(block_file, rom_file, self.data, self.memory)
else:
self.block_tools = BlockTools_NoCache(block_file, rom_file, self.data, self.memory)
self.instructions = {
1: self.i01,
4: self.i04,
11: self.i11,
6: self.i06,
2: self.i02,
5: self.i05,
18: self.i18,
2049: self.i2049,
2832: self.i2832,
10: self.i10,
68288770: self.i68288770,
8: self.i08,
17563906: self.i17563906,
7: self.i07,
524545: self.i524545,
3: self.i03,
459014: self.i459014,
9: self.i09,
12: self.i12,
13: self.i13,
14: self.i14,
15: self.i15,
16: self.i16,
17: self.i17,
19: self.i19,
20: self.i20,
21: self.i21,
22: self.i22,
23: self.i23,
24: self.i24,
25: self.i25,
26: self.i26,
27: self.i27,
28: self.i28,
29: self.i29,
1793: self.i1793,
459009: self.i459009,
67502597: self.i67502597,
100926722: self.i100926722,
302059522: self.i302059522,
2818: self.i2818,
219156993: self.i219156993,
33689603: self.i33689603,
167840769: self.i167840769,
525572: self.i525572,
134284806: self.i134284806
}
def i00(self): # nop
pass
def i01(self): # lit
self.ip += 1
self.data.lit(self.memory[self.ip])
def i02(self): # dup
self.data.raw_lit(self.data.top())
def i03(self): # drop
self.data.pop()
def i04(self): # swap
a = self.data.pop()
b = self.data.pop()
self.data.raw_lit(a)
self.data.raw_lit(b)
def i05(self): # push
self.address.raw_lit(self.data.pop())
def i06(self): # pop
self.data.raw_lit(self.address.pop())
def i07(self): # jump
self.ip = self.data.pop() - 1
def i08(self): # call
self.address.raw_lit(self.ip)
self.ip = self.data.pop() - 1
def i09(self): # ccall
target = self.data.pop()
flag = self.data.pop()
if flag != 0:
self.address.raw_lit(self.ip)
self.ip = target - 1
def i10(self): # cjump
target = self.data.pop()
flag = self.data.pop()
if flag != 0:
self.ip = target - 1
def i11(self): # return
self.ip = self.address.pop()
def i12(self): # equal
self.data.raw_lit(-(self.data.pop() == self.data.pop()))
def i13(self): # not equal
self.data.raw_lit(-(self.data.pop() != self.data.pop()))
def i14(self): # less than
b = self.data.pop()
a = self.data.pop()
self.data.raw_lit(-(a < b))
def i15(self): # greater than
b = self.data.pop()
a = self.data.pop()
self.data.raw_lit(-(a > b))
def i16(self): # fetch
self.data.raw_lit(self.memory[self.data.pop()])
def i17(self): # store
a = self.data.pop()
self.memory[a] = self.data.pop()
def i18(self): # add
self.data.lit(self.data.pop() + self.data.pop())
def i19(self): # subtract
b = self.data.pop()
self.data.lit(self.data.pop() - b)
def i20(self): # multiply
self.data.lit(self.data.pop() * self.data.pop())
def i21(self): # divmod
a = self.data.pop()
a, b = div_mod(self.data.pop(), a)
self.data.raw_lit(b)
self.data.raw_lit(a)
def i22(self): # and
self.data.raw_lit(self.data.pop() & self.data.pop())
def i23(self): # or
self.data.raw_lit(self.data.pop() | self.data.pop())
def i24(self): # xor
self.data.raw_lit(self.data.pop() ^ self.data.pop())
def i25(self): # shift left
b = self.data.pop()
self.data.lit(self.data.pop() << b)
def i26(self): # shift right
b = self.data.pop()
self.data.raw_lit(self.data.pop() >> b)
def i27(self): # compare memory
l = self.data.pop()
dest = self.data.pop()
src = self.data.pop()
self.data.raw_lit(-(self.memory[dest: dest + l] == self.memory[src: src + l]))
def i28(self): # copy memory
l = self.data.pop()
dest = self.data.pop()
src = self.data.pop()
self.memory[dest: dest + l] = self.memory[src: src + l]
def i29(self): # io
i = self.data.pop()
if i == 0:
print(chr(self.data.pop()), end='')
elif i == 1:
if not len(self.input_buffer):
self.input_buffer = ['\n'] + list(input())[::-1]
self.data.lit(ord(self.input_buffer.pop()))
elif i == 2:
self.block_tools.read_block()
elif i == 3:
self.block_tools.block_write()
elif i == 4:
self.block_tools.save_image()
elif i == 5:
self.block_tools.load_image()
self.ip = -1
elif i == 6:
self.ip = 65535
elif i == 7:
self.data.lit(self.data.depth())
self.data.lit(self.address.depth())
def i2049(self): # lica....
self.address.lit(self.ip + 1)
self.ip = self.memory[self.ip + 1] - 1
def i1793(self): # liju....
self.ip = self.memory[self.ip + 1] - 1
def i524545(self): # lilica..
self.data.lit(self.memory[self.ip + 1])
self.address.lit(self.ip + 2)
self.ip = self.memory[self.ip + 2] - 1
def i459009(self): # liliju..
self.data.lit(self.memory[self.ip + 1])
self.ip = self.memory[self.ip + 2] - 1
def i67502597(self): # puduposw 'over'
self.data.lit(self.data.second())
def i17563906(self): # dulieqli
self.data.lit(-(self.memory[self.ip + 1] == self.data.top()))
self.data.lit(self.memory[self.ip + 2])
self.ip += 2
def i100926722(self): # dupuswpo 'tuck'
a = self.data.pop()
b = self.data.pop()
self.data.lit(a)
self.data.lit(b)
self.data.lit(a)
def i302059522(self): # dufeliad
self.data.lit(self.memory[self.data.top()] + self.memory[self.ip + 1])
self.ip += 1
def i2818(self): # dure....
self.data.raw_lit(self.data.top())
self.ip = self.address.pop()
def i219156993(self): # liadfene
self.ip += 1
self.data.lit(-(limit(self.memory[self.memory[self.ip] + self.data.pop()]) != self.data.pop()))
def i33689603(self): # drfedudu
self.data.pop()
m = self.memory[self.data.pop()]
self.data.lit(m)
self.data.lit(m)
self.data.lit(m)
def i167840769(self): # lieqlicj
self.ip += 2
if -(self.memory[self.ip-1] == self.data.pop()) != 0:
self.ip = self.memory[self.ip] - 1
def i2832(self): # fere....
self.data.raw_lit(self.memory[self.data.pop()])
self.ip = self.address.pop()
def i68288770(self): #duliadsw
self.data.raw_lit(self.data.top())
self.ip += 1
self.data.lit(limit(self.memory[self.ip]) + self.data.pop())
a = self.data.pop()
b = self.data.pop()
self.data.raw_lit(a)
self.data.raw_lit(b)
def i525572(self): # swpuca..
a = self.data.pop()
self.address.raw_lit(self.data.pop())
self.data.raw_lit(a)
self.address.raw_lit(self.ip)
self.ip = self.data.pop() - 1
def i459014(self): # poliju..
self.data.raw_lit(self.address.pop())
self.ip = self.memory[self.ip+1] - 1
def i134284806(self): # popolica
self.data.raw_lit(self.address.pop())
self.data.raw_lit(self.address.pop())
self.ip += 1
self.address.lit(self.ip)
self.ip = self.memory[self.ip] - 1
def print_opcode_bundle(self, opcode):
print(opcode & 0xFF, end=' ')
print((opcode >> 8) & 0xFF, end=' ')
print((opcode >> 16) & 0xFF, end=' ')
print((opcode >> 24) & 0xFF, end=': ')
def process(self, c):
if c in self.instructions:
self.instructions[c]()
def execute(self, start):
self.ip = start
while self.ip < 65536:
m = self.memory[self.ip]
if m in self.instructions:
self.instructions[m]()
else:
self.process(m & 0xFF)
self.process((m >> 8) & 0xFF)
self.process((m >> 16) & 0xFF)
self.process((m >> 24) & 0xFF)
self.ip += 1
def debug_execute(self, start):
data = {}
self.ip = start
while self.ip < 65536:
m = self.memory[self.ip]
if m in self.instructions:
self.instructions[m]()
else:
self.process(m & 0xFF)
self.process((m >> 8) & 0xFF)
self.process((m >> 16) & 0xFF)
self.process((m >> 24) & 0xFF)
data[str(m & 0xFF)] = data.get(str(m & 0xFF), 0) + 1
data[str((m >> 8) & 0xFF)] = data.get(str((m >> 8) & 0xFF), 0) + 1
data[str((m >> 16) & 0xFF)] = data.get(str((m >> 16) & 0xFF), 0) + 1
data[str((m >> 24) & 0xFF)] = data.get(str((m >> 24) & 0xFF), 0) + 1
data[str(m)] = data.get(str(m), 0) + 1
self.ip += 1
return data
def main(self, debug=False):
self.block_tools.load_image()
if BLOCK_CACHE:
self.block_tools.read_all_blocks()
if debug:
return self.debug_execute(0)
else:
self.execute(0)
def sort_dict(input_dict):
sorted_items = sorted(input_dict.items(), key=lambda x: x[1], reverse=True)
sorted_dict = dict(sorted_items)
return sorted_dict
if __name__ == '__main__':
if DEBUG:
if DEBUG.lower() == 'instrs':
import time
start_time = time.time()
k = ilo(BLOCK_FILE, ROM_FILE, BLOCK_CACHE)
data = k.main(True)
end_time = time.time()
print(str(sort_dict(data)).replace(',', '\n').strip('{}'))
print('\nElapsed Time: ', end_time - start_time)
elif DEBUG.lower() == 'timing':
import time
start_time = time.time()
ilo(BLOCK_FILE, ROM_FILE, BLOCK_CACHE).main()
end_time = time.time()
print('\nElapsed Time: ', end_time - start_time)
elif DEBUG.lower() == 'cprofile':
import cProfile
cProfile.run('ilo(BLOCK_FILE, ROM_FILE, BLOCK_CACHE).main()', sort='tottime')
else:
print('Unknown debug mode')
else:
ilo(BLOCK_FILE, ROM_FILE, BLOCK_CACHE).main()

181
source/ilo.retro Normal file
View file

@ -0,0 +1,181 @@
This is an implementation of the ilo computer. It's written in
RetroForth. I wrote this mostly to satisfy a personal desire to
run Konilo under RetroForth.
The ilo computer is quite similar to the nga computer that Retro
runs on. Both are dual stack minimal instruction set computers
with similar instruction sets. But ilo is, by design, a smaller,
simpler system.
ilo presents the following:
- 65,5536 cells of memory
- 32-bit cells are the only addressable memory unit
- data stack of 32 values
- address stack of 256 addresses
- keyboard input
- serial display
- block storage
- blocks are 1,024 cells in size
- 30 instructions
# Memory And Loading The ROM
A standard ilo system will provide exactly 65,536 cells of RAM.
I create a label pointing to this and allocate the space.
~~~
'IMAGE d:create #65536 allot
~~~
On startup, ilo loads a ROM (typically named "ilo.rom") into
memory. This will always be a full memory image, so the size
will be 65,536 cells. Loading this takes advantage of Retro's
`block:` vocabulary, reading in the ROM as a series of 64 1K
blocks. Doing this is significantly faster than reading the
ROM in byte by byte and assembling the bytes into cells.
~~~
:load-image (s-)
block:set-file
#64 [ I IMAGE I #1024 * + block:read ] indexed-times ;
'ilo.rom load-image
~~~
# Stacks & Registers
I create labels and allocate space for the two stacks. And also
create registers for the stack pointers and instruction pointer.
Using these, I then implement several words for moving values
to and from these. The `>s` and `s>` operate on the data stack
whereas `>r` and `r>` operate on the address stack.
It'd be faster to just use the RetroForth stacks directly, but
this is cleaner and less error prone. It also makes debugging
easier as the ilo stacks are now separate entities.
The last thing I define here is `[IP]`, which returns the value
in memory at the instruction pointer. This is strictly for
readability and could be inlined in the two places it's used.
~~~
'DataStack d:create #33 allot
'ReturnStack d:create #257 allot
'SP var
'RP var
'IP var
:>s (n-) &DataStack @SP + store &SP v:inc ;
:s> (-n) &SP v:dec &DataStack @SP + fetch ;
:>r (n-) &ReturnStack @RP + store &RP v:inc ;
:r> (-n) &RP v:dec &ReturnStack @RP + fetch ;
:[IP] IMAGE @IP + fetch ;
~~~
# A Utility Word
RetroForth doesn't have a word to directly compare two blocks
of memory. Until I rectify this, I define one here.
~~~
:compare (sdl-f)
#-1 swap
[ [ dup-pair &fetch bi@ eq? ] dip and [ &n:inc bi@ ] dip ]
times &drop-pair dip ;
~~~
# The ilo Instructions
Now I'm ready to implement the ilo instruction set. I chose to
follow my (very) similar approach from retro-extend(1) and the
Autopsy debugger. This creates one word per instruction and then
fills in a jump table of pointers.
If you are familiar with Retro, it should be pretty easy to
follow these. Mostly just move values onto the RetroForth stack,
do an operation, then put results back.
The longest one of these is the I/O instruction, which has 8
possible actions. I implemented this using a `case` structure.
~~~
:i:no ;
:i:li &IP v:inc [IP] >s ;
:i:du s> dup >s >s ;
:i:dr s> drop ;
:i:sw s> s> swap >s >s ;
:i:pu s> >r ;
:i:po r> >s ;
:i:ju s> n:dec !IP ;
:i:ca @IP >r i:ju ;
:i:cc s> s> [ >s i:ca ] &drop choose ;
:i:cj s> s> [ >s i:ju ] &drop choose ;
:i:re r> !IP ;
:i:eq s> s> eq? >s ;
:i:ne s> s> -eq? >s ;
:i:lt s> s> swap lt? >s ;
:i:gt s> s> swap gt? >s ;
:i:fe s> IMAGE + fetch >s ;
:i:st s> s> swap IMAGE + store ;
:i:ad s> s> + >s ;
:i:su s> s> swap - >s ;
:i:mu s> s> * >s ;
:i:di s> s> swap /mod swap >s >s ;
:i:an s> s> and >s ;
:i:or s> s> or >s ;
:i:xo s> s> xor >s ;
:i:sl s> s> swap n:abs n:negate shift >s ;
:i:sr s> s> swap n:abs shift >s ;
:i:cp s> s> s> [ IMAGE + ] bi@ 'abc 'cba reorder compare >s ;
:i:cy s> s> s> [ IMAGE + ] bi@ 'abc 'cba reorder copy ;
:i:io s>
#0 [ s> c:put ] case
#1 [ c:get >s ] case
#2 [ s> s> swap IMAGE + block:read ] case
#3 [ s> s> swap IMAGE + block:write ] case
#4 [ dump-stack ] case
#5 [ #-1 !IP ] case
#6 [ #65536 !IP ] case
#7 [ @SP >s @RP >s ] case
drop ;
'Instructions d:create
&i:no , &i:li , &i:du , &i:dr , &i:sw , &i:pu ,
&i:po , &i:ju , &i:ca , &i:cc , &i:cj , &i:re ,
&i:eq , &i:ne , &i:lt , &i:gt , &i:fe , &i:st ,
&i:ad , &i:su , &i:mu , &i:di , &i:an , &i:or ,
&i:xo , &i:sl , &i:sr , &i:cp , &i:cy , &i:io ,
~~~
# Instruction Processor
~~~
{{
:mask #255 and ;
:next #8 shift ;
---reveal---
:unpack (n-dcba)
dup mask swap next
dup mask swap next
dup mask swap next
'abcd 'dcba reorder ;
}}
:process-opcodes (n-)
unpack
&Instructions + fetch call
&Instructions + fetch call
&Instructions + fetch call
&Instructions + fetch call ;
:process (-)
[ [IP] process-opcodes &IP v:inc @IP #0 #65535 n:between? ] while ;
'ilo.blocks block:set-file
process
~~~

368
source/ilo.rs Normal file
View file

@ -0,0 +1,368 @@
// ilo.rs, (c) charles childers, (c) 2024 Matt Keeter
use std::convert::TryInto;
use std::fs::{File, OpenOptions};
use std::io;
use std::io::{Read, Seek, SeekFrom, Write};
struct Ilo {
/// memory
memory: [i32; 65536],
/// data stack
data: [i32; 33],
/// address stack
addr: [i32; 257],
/// data stack pointer
sp: usize,
/// address stack pointer
rp: usize,
/// instruction pointer
ip: usize,
}
impl Default for Ilo {
fn default() -> Self {
Self {
memory: [0; 65536],
data: [0; 33],
addr: [0; 257],
sp: 0,
rp: 0,
ip: 0,
}
}
}
impl Ilo {
fn load_image(&mut self) {
match std::fs::read("ilo.rom") {
Ok(image) => {
for (i, c) in image.chunks(4).enumerate() {
self.store(i32::from_le_bytes(c.try_into().unwrap()), i);
}
}
Err(e) => {
panic!("could not load 'ilo.rom': {}", e);
}
}
}
fn read_block(&mut self, block: i32, buffer: i32) -> io::Result<()> {
let mut f = File::open("ilo.blocks")?;
let mut data = [0; 4096];
f.seek(SeekFrom::Start(4096 * (block as u64)))?;
f.read_exact(&mut data)?;
for (i, c) in data.chunks(4).enumerate() {
let x = c[0] as i32;
self.store(x, (buffer as usize) + i);
}
Ok(())
}
fn write_block(&self, block: i32, buffer: i32) -> io::Result<()> {
let mut f = OpenOptions::new()
.read(true)
.write(true)
.open("ilo.blocks")?;
let mut data = [0; 4096];
for x in 0..1024 {
let v = self.fetch((buffer as usize) + x);
data[(x * 4)..][..4].copy_from_slice(&v.to_le_bytes());
}
f.seek(SeekFrom::Start(4096 * (block as u64)))?;
f.write_all(&data)?;
Ok(())
}
fn push(&mut self, x: i32) {
self.sp += 1;
self.data[self.sp] = x;
}
fn pop(&mut self) -> i32 {
self.sp -= 1;
self.data[self.sp + 1]
}
fn fetch(&self, a: usize) -> i32 {
self.memory[a]
}
fn store(&mut self, v: i32, a: usize) {
self.memory[a] = v;
}
fn reset(&mut self) {
self.ip = 0;
self.sp = 0;
self.rp = 0;
}
fn next(&mut self) {
self.ip += 1;
}
fn li(&mut self) {
self.next();
self.push(self.fetch(self.here()));
}
fn du(&mut self) {
self.push(self.data[self.sp]);
}
fn dr(&mut self) {
self.pop();
}
fn sw(&mut self) {
let x = self.pop();
let y = self.pop();
self.push(x);
self.push(y);
}
fn pu(&mut self) {
self.rp += 1;
self.addr[self.rp] = self.pop();
}
fn po(&mut self) {
self.push(self.addr[self.rp]);
self.rp -= 1;
}
fn ju(&mut self) {
self.ip = (self.pop() - 1) as usize;
}
fn ca(&mut self) {
self.rp += 1;
self.addr[self.rp] = (self.ip) as i32;
self.ip = (self.pop() - 1) as usize;
}
fn cc(&mut self) {
let t = self.pop();
if self.pop() != 0 {
self.push(t);
self.ca();
}
}
fn cj(&mut self) {
let t = self.pop();
if self.pop() != 0 {
self.push(t);
self.ju();
}
}
fn re(&mut self) {
self.ip = (self.addr[self.rp]) as usize;
self.rp -= 1;
}
fn eq(&mut self) {
let y = self.pop();
let x = self.pop();
self.push(if x == y { -1 } else { 0 });
}
fn ne(&mut self) {
let y = self.pop();
let x = self.pop();
self.push(if x != y { -1 } else { 0 });
}
fn lt(&mut self) {
let y = self.pop();
let x = self.pop();
self.push(if x < y { -1 } else { 0 });
}
fn gt(&mut self) {
let y = self.pop();
let x = self.pop();
self.push(if x > y { -1 } else { 0 });
}
fn fe(&mut self) {
let x = self.pop() as usize;
self.push(self.fetch(x));
}
fn st(&mut self) {
let x = self.pop() as usize;
let v = self.pop();
self.store(v, x);
}
fn ad(&mut self) {
let y = self.pop();
let x = self.pop();
self.push(x.wrapping_add(y));
}
fn su(&mut self) {
let y = self.pop();
let x = self.pop();
self.push(x.wrapping_sub(y));
}
fn mu(&mut self) {
let y = self.pop();
let x = self.pop();
self.push(x.wrapping_mul(y));
}
fn di(&mut self) {
let y = self.pop();
let x = self.pop();
self.push(x.wrapping_rem(y));
self.push(x.wrapping_div(y));
}
fn an(&mut self) {
let y = self.pop();
let x = self.pop();
self.push(x & y);
}
fn or(&mut self) {
let y = self.pop();
let x = self.pop();
self.push(x | y);
}
fn xo(&mut self) {
let y = self.pop();
let x = self.pop();
self.push(x ^ y);
}
fn sl(&mut self) {
let y = self.pop();
let x = self.pop();
self.push(x.wrapping_shl(y.try_into().unwrap()));
}
fn sr(&mut self) {
let y = self.pop();
let x = self.pop();
self.push(x.wrapping_shr(y.try_into().unwrap()));
}
fn cp(&mut self) {
let len = self.pop() as usize;
let dest = self.pop() as usize;
let src = self.pop() as usize;
let slice1 = &self.memory[src..(src + len)];
let slice2 = &self.memory[dest..(dest + len)];
if slice1 == slice2 {
self.push(-1);
} else {
self.push(0);
}
}
fn cy(&mut self) {
let mut len = self.pop();
let mut dest = self.pop() as usize;
let mut src = self.pop() as usize;
while len > 0 {
self.store(self.fetch(src), dest);
len -= 1;
src += 1;
dest += 1;
}
}
fn io(&mut self) {
let dev = self.pop();
match dev {
0 => {
let mut c = self.pop();
if c == 0 {
c = 32;
}
let mut stdout = std::io::stdout().lock();
stdout.write_all(&[c as u8]).unwrap();
stdout.flush().unwrap();
}
1 => match std::io::stdin().lock().bytes().next().unwrap() {
Ok(127) => self.push(8),
Ok(val) => self.push(val as i32),
Err(_) => std::process::exit(1),
},
2 => {
let buffer = self.pop();
let block = self.pop();
if let Err(e) = self.read_block(block, buffer) {
panic!("could not read 'ilo.blocks': {}", e);
}
}
3 => {
let buffer = self.pop();
let block = self.pop();
if let Err(e) = self.write_block(block, buffer) {
panic!("could not write 'ilo.blocks': {}", e);
}
}
4 => {}
5 => {
self.load_image();
self.ip = 70000;
}
6 => {
self.ip = 65536;
}
7 => {
self.push(self.sp as i32);
self.push(self.rp as i32);
}
_ => (),
}
}
fn process(&mut self, inst: u8) {
match inst {
0 => (), // nop
1 => self.li(),
2 => self.du(),
3 => self.dr(),
4 => self.sw(),
5 => self.pu(),
6 => self.po(),
7 => self.ju(),
8 => self.ca(),
9 => self.cc(),
10 => self.cj(),
11 => self.re(),
12 => self.eq(),
13 => self.ne(),
14 => self.lt(),
15 => self.gt(),
16 => self.fe(),
17 => self.st(),
18 => self.ad(),
19 => self.su(),
20 => self.mu(),
21 => self.di(),
22 => self.an(),
23 => self.or(),
24 => self.xo(),
25 => self.sl(),
26 => self.sr(),
27 => self.cp(),
28 => self.cy(),
29 => self.io(),
_ => (),
}
}
fn not_done(&self) -> bool {
self.ip < 65536
}
fn here(&self) -> usize {
self.ip
}
fn execute(&mut self) {
self.reset();
while self.not_done() {
let opcode = self.fetch(self.here());
for op in opcode.to_le_bytes() {
self.process(op);
}
if self.here() == 70000 {
self.reset();
} else {
self.next();
}
}
}
fn dump_stack(&mut self) {
while self.sp > 0 {
let x = self.pop();
println!("{x}");
}
}
}
fn main() {
let mut ilo = Ilo::default();
ilo.load_image();
ilo.execute();
ilo.dump_stack();
}

310
source/ilo.swift Normal file
View file

@ -0,0 +1,310 @@
// -------------------------------------------------------------
// ilo.swift, (c) charles childers
// -------------------------------------------------------------
// compile with:
//
// swiftc -O vm/ilo.swift -o ilo
// -------------------------------------------------------------
import Foundation
// -------------------------------------------------------------
// Configuration
// -------------------------------------------------------------
let imageSize: Int = 65536
let stackSize: Int = 33
let addressSize: Int = 257
// -------------------------------------------------------------
// Globals
// -------------------------------------------------------------
// +----------+------------------------------------------------+
// | Name | Contains |
// +==========+================================================+
// | input | input buffer ("keyboard") |
// | ip | instruction pointer |
// | memory | random access memory |
// | data | data stack |
// | address | address stack |
// +----------+------------------------------------------------+
var input: String = ""
var ip: Int = 0
var memory = [Int32](repeating: 0, count: imageSize)
var data = Stack(stackSize)
var address = Stack(addressSize)
// -------------------------------------------------------------
// Support Functions
// -------------------------------------------------------------
func getInt32FromData(data: NSData, offset: Int) -> Int32 {
let raw = NSRange(location: offset * 4, length: 4)
var i = [Int32](repeating: 0, count: 1)
data.getBytes(&i, range: raw)
return Int32(i[0])
}
// -------------------------------------------------------------
// Instructions
// -------------------------------------------------------------
func inst_no() { }
func inst_li() { ip += 1; data.push(memory[ip]) }
func inst_du() { data.push(data.tos()) }
func inst_dr() { data.drop() }
func inst_sw() { data.swap() }
func inst_pu() { address.push(data.pop()) }
func inst_po() { data.push(address.pop()) }
func inst_ju() { ip = Int(data.pop() - 1) }
func inst_ca() { address.push(Int32(ip)); ip = Int(data.pop() - 1) }
func inst_cc() { let dest = data.pop(); if (data.pop() != 0) { address.push(Int32(ip)); ip = Int(dest - 1) } }
func inst_cj() { let dest = data.pop(); if (data.pop() != 0) { ip = Int(dest - 1) } }
func inst_re() { ip = Int(address.pop()) }
func inst_eq() { let tos = data.pop(), nos = data.pop(); data.push((nos == tos) ? -1 : 0) }
func inst_ne() { let tos = data.pop(), nos = data.pop(); data.push((nos != tos) ? -1 : 0) }
func inst_lt() { let tos = data.pop(), nos = data.pop(); data.push((nos < tos) ? -1 : 0) }
func inst_gt() { let tos = data.pop(), nos = data.pop(); data.push((nos > tos) ? -1 : 0) }
func inst_fe() { let target = Int(data.pop()); data.push(memory[target]) }
func inst_st() { let addr = data.pop(), value = data.pop(); memory[Int(addr)] = value }
func inst_ad() { let tos = data.pop(), nos = data.pop(); data.push(nos &+ tos) }
func inst_su() { let tos = data.pop(), nos = data.pop(); data.push(nos &- tos) }
func inst_mu() { let tos = data.pop(), nos = data.pop(); data.push(nos &* tos) }
func inst_di() { let a = data.pop(), b = data.pop(); data.push(b % a); data.push(b / a) }
func inst_an() { let tos = data.pop(), nos = data.pop(); data.push(tos & nos) }
func inst_or() { let tos = data.pop(), nos = data.pop(); data.push(nos | tos) }
func inst_xo() { let tos = data.pop(), nos = data.pop(); data.push(nos ^ tos) }
func inst_sl() { let tos = data.pop(), nos = data.pop(); data.push(nos << tos) }
func inst_sr() { let tos = data.pop(), nos = data.pop(); data.push(nos >> tos) }
func inst_cp() {
var len = Int(data.pop())
var dest = Int(data.pop())
var src = Int(data.pop())
while (len != 0) {
if (memory[dest] != memory[src]) { data.push(0); return }
len -= 1
dest += 1
src += 1
}
data.push(-1)
}
func inst_cy() {
var len = Int(data.pop())
var dest = Int(data.pop())
var src = Int(data.pop())
while (len != 0) {
memory[dest] = memory[src]
len -= 1
dest += 1
src += 1
}
}
func inst_io() {
let device = Int(data.pop())
let devices: [(()->Void)] = [
io_cput, io_cget, io_rb, io_wb,
io_si, io_pc, io_of, io_sd]
if device < 0 || device > 7 { return }
devices[device]()
}
// -------------------------------------------------------------
// I/O Operations
// -------------------------------------------------------------
// +----------+------------------------------------------------+
// | Function | Action |
// +==========+================================================+
// | io_cput | Display a character to standard output |
// | io_cget | Read character from standard input source |
// | io_rb | Read block from storage |
// | io_wb | Write block to storage |
// | io_si | Save image (not implemented) |
// | io_pc | Reset ilo to default state, restarting |
// | io_of | Power off (exit) ilo |
// | is_sd | Return stack depths |
// +----------+------------------------------------------------+
func io_cput() {
let v = UnicodeScalar(Int(data.pop())) ?? UnicodeScalar(32)
print(Character(v!), terminator: "")
}
func io_cget() {
if (input.count > 0) {
let c = input.first!
guard let v = c.asciiValue else { return }
data.push(Int32(v))
input = String(input.dropFirst())
} else {
data.push(32)
}
}
func io_rb() {
let buffer = data.pop(), block = data.pop()
load_block(Int(block), to: Int(buffer))
}
func io_wb() {
let buffer = data.pop(), block = data.pop()
write_block(Int(block), to: Int(buffer))
}
func io_si() { }
func io_pc() {
load_image()
data.empty()
address.empty()
ip = -1
}
func io_of() { ip = 65536; exit(0) }
func io_sd() {
data.push(Int32(data.depth()))
data.push(Int32(address.depth()))
}
// -------------------------------------------------------------
// Block I/O
// -------------------------------------------------------------
func blocks() -> URL {
return URL(fileURLWithPath: "./ilo.blocks")
}
func load_block(_ block: Int, to: Int) {
let storage = blocks()
let fd = try! FileHandle(forReadingFrom: storage)
fd.seek(toFileOffset: UInt64(block * 4096))
let data = fd.readData(ofLength: 4096) as NSData
for i in 0 ... 1023 {
memory[to + i] = getInt32FromData(data: data, offset: i)
}
fd.closeFile()
}
func write_block(_ block: Int, to: Int) {
let storage = blocks()
let fd = try! FileHandle(forUpdating: storage)
fd.seek(toFileOffset: UInt64(block * 4096))
for i in 0 ... 1023 {
let word = Data(bytes: &memory[to + i], count: 4)
fd.write(word)
}
fd.closeFile()
}
// -------------------------------------------------------------
// Instruction Processing
// -------------------------------------------------------------
func process_instruction(opcode: Int32) {
let instructions: [(()->Void)] = [
inst_no, inst_li, inst_du, inst_dr, inst_sw,
inst_pu, inst_po, inst_ju, inst_ca, inst_cc,
inst_cj, inst_re, inst_eq, inst_ne, inst_lt,
inst_gt, inst_fe, inst_st, inst_ad, inst_su,
inst_mu, inst_di, inst_an, inst_or, inst_xo,
inst_sl, inst_sr, inst_cp, inst_cy, inst_io]
// skip `no` and invalid opcodes
if opcode < 1 || opcode > 29 { return }
instructions[Int(opcode)]()
}
func process() {
while input.count > 0 {
for inst in memory[ip].bytes {
process_instruction(opcode: Int32(inst))
}
ip += 1
}
}
// -------------------------------------------------------------
// Initialization
// -------------------------------------------------------------
func load_image() {
let fileURL = URL(fileURLWithPath: "./ilo.rom")
let data = NSData(contentsOf: fileURL)!
var i: Int = 0
while (i < 65536) {
memory[i] = getInt32FromData(data: data, offset: i)
i += 1
}
}
func bootstrap() {
if memory[0] == 0 {
load_image()
ip = 0
data.empty()
address.empty()
}
input = " "
process()
}
// -------------------------------------------------------------
// Stacks
// -------------------------------------------------------------
class Stack {
private var limit: Int
private var data: [Int32]
private var sp: Int = 0
init(_ size: Int) {
data = [Int32](repeating: 0, count: size)
limit = size
}
public func tos() -> Int32 { return data[sp] }
public func nos() -> Int32 { return data[sp - 1] }
public func push(_ n: Int32) { sp += 1; data[sp] = n }
public func pop() -> Int32 { sp -= 1; return data[sp + 1] }
public func drop() { sp -= 1 }
public func swap() { let a = data[sp]; let b = data[sp - 1]; data[sp] = b; data[sp - 1] = a }
public func depth() -> Int { return sp }
public func item(_ n: Int) -> Int32 { return data[n] }
public func empty() { sp = 0 }
}
// -------------------------------------------------------------
// Extensions to Existing Classes
// -------------------------------------------------------------
extension FixedWidthInteger where Self: SignedInteger {
var bytes: [Int8] {
var _endian = littleEndian
let bytePtr = withUnsafePointer(to: &_endian) {
$0.withMemoryRebound(to: Int8.self, capacity: MemoryLayout<Self>.size) {
UnsafeBufferPointer(start: $0, count: MemoryLayout<Self>.size)
}
}
return [Int8](bytePtr)
}
}
// -------------------------------------------------------------
// Top-level System
// -------------------------------------------------------------
func main() {
bootstrap()
while ip < 65535 {
input = readLine() ?? ""
input = " \(input) \n"
process()
}
}
main()

516
source/ilo.ts Normal file
View file

@ -0,0 +1,516 @@
/* ilo.ts, an ilo in TypeScript. (c) Rick Carlino */
/* Run via `npx ts-node ilo.ts`.
If you get errors, try running `npx tsc --init` first. */
type OutputCallback = (char: string) => void;
function enforce32BitSignedInteger(value: number) {
const int32Max = Math.pow(2, 31) - 1;
const int32Min = -Math.pow(2, 31);
value = value | 0;
value = ((value - int32Min) % (int32Max - int32Min + 1)) + int32Min;
return value;
}
export class Konilo {
private m: Int32Array;
private blocks: Int32Array;
private ds: Int32Array;
private as: Int32Array;
private ip: number;
private sp: number;
private rp: number;
private a: number;
private b: number;
private f: number;
private s: number;
private d: number;
private l: number;
private cycles: number;
private input: string;
private outputHandler: OutputCallback;
constructor(public romURL: string, public blockURL: string) {
this.m = new Int32Array(65536);
this.blocks = new Int32Array(1024 * 1024);
this.ds = new Int32Array(33);
this.as = new Int32Array(257);
this.ip = 0;
this.sp = 0;
this.rp = 0;
this.a = 0;
this.b = 0;
this.f = 0;
this.s = 0;
this.d = 0;
this.l = 0;
this.cycles = 25000;
this.input = "";
this.outputHandler = (char: string) => {};
}
async initialize(): Promise<void> {
await Promise.all([
this.loadFile(this.romURL, this.m),
this.loadFile(this.blockURL, this.blocks),
]);
}
async loadFile(url: string, target: Int32Array): Promise<void> {
await fetch(url)
.then((response) => response.arrayBuffer())
.then((buffer) => {
const dataView = new DataView(buffer);
for (let i = 0; i < target.length; i++) {
target[i] = dataView.getInt32(i * 4, true);
}
})
.catch((error) => {
console.error("Error loading the file:", error);
});
}
async execute(): Promise<void> {
console.log("Hello from Konilo!");
let ticks = 0;
while (this.ip < 65536 && this.input.length >= 1 && !isNaN(this.ip)) {
const o = this.m[this.ip];
this.process(o & 0xff);
this.process((o >> 8) & 0xff);
this.process((o >> 16) & 0xff);
this.process((o >> 24) & 0xff);
this.ip = this.ip + 1;
ticks += 1;
if (ticks % this.cycles === 0) {
ticks = 0;
await this.sleep(0);
}
}
await this.sleep(0);
console.log("Goodbye from Konilo!");
}
async sleep(ms: number): Promise<void> {
return new Promise((resolve) => setTimeout(resolve, ms));
}
loadROM(): void {
this.loadFile(this.romURL, this.m);
}
loadBlocks(): void {
this.loadFile(this.blockURL, this.blocks);
}
setOutputHandler(callback: OutputCallback): void {
this.outputHandler = callback;
}
send(str: string): void {
this.input += str;
}
process(o: number) {
switch (o) {
case 0:
break;
case 1:
this.li();
break;
case 2:
this.du();
break;
case 3:
this.dr();
break;
case 4:
this.sw();
break;
case 5:
this.pu();
break;
case 6:
this.po();
break;
case 7:
this.ju();
break;
case 8:
this.ca();
break;
case 9:
this.cc();
break;
case 10:
this.cj();
break;
case 11:
this.re();
break;
case 12:
this.eq();
break;
case 13:
this.ne();
break;
case 14:
this.lt();
break;
case 15:
this.gt();
break;
case 16:
this.fe();
break;
case 17:
this.st();
break;
case 18:
this.ad();
break;
case 19:
this.su();
break;
case 20:
this.mu();
break;
case 21:
this.di();
break;
case 22:
this.an();
break;
case 23:
this.or();
break;
case 24:
this.xo();
break;
case 25:
this.sl();
break;
case 26:
this.sr();
break;
case 27:
this.cp();
break;
case 28:
this.cy();
break;
case 29:
this.io();
break;
default:
break;
}
this.guard();
}
guard() {
this.ds[this.sp] = enforce32BitSignedInteger(this.ds[this.sp]);
if (this.sp >= 2) {
this.ds[this.sp - 1] = enforce32BitSignedInteger(this.ds[this.sp - 1]);
}
}
save_ip() {
this.rp += 1;
this.as[this.rp] = this.ip;
}
pop() {
this.sp -= 1;
return this.ds[this.sp + 1];
}
push(v: number) {
this.ds[this.sp + 1] = v;
this.sp += 1;
}
symmetric() {
if (this.b >= 0 && this.ds[this.sp - 1] < 0) {
this.ds[this.sp] += 1;
this.ds[this.sp - 1] -= this.b;
}
}
li() {
this.ip += 1;
this.push(this.m[this.ip]);
}
du() {
this.push(this.ds[this.sp]);
}
dr() {
this.ds[this.sp] = 0;
this.sp -= 1;
}
sw() {
const a = this.ds[this.sp];
this.ds[this.sp] = this.ds[this.sp - 1];
this.ds[this.sp - 1] = a;
}
pu() {
this.rp += 1;
this.as[this.rp] = this.pop();
}
po() {
this.push(this.as[this.rp]);
this.rp -= 1;
}
ju() {
this.ip = this.pop() - 1;
}
ca() {
this.save_ip();
this.ip = this.pop() - 1;
}
cc() {
const a = this.pop();
if (this.pop()) {
this.save_ip();
this.ip = a - 1;
}
}
cj() {
const a = this.pop();
if (this.pop()) {
this.ip = a - 1;
}
}
re() {
this.ip = this.as[this.rp];
this.rp -= 1;
}
eq() {
this.ds[this.sp - 1] = this.ds[this.sp - 1] == this.ds[this.sp] ? -1 : 0;
this.sp -= 1;
}
ne() {
this.ds[this.sp - 1] = this.ds[this.sp - 1] != this.ds[this.sp] ? -1 : 0;
this.sp -= 1;
}
lt() {
this.ds[this.sp - 1] = this.ds[this.sp - 1] < this.ds[this.sp] ? -1 : 0;
this.sp -= 1;
}
gt() {
this.ds[this.sp - 1] = this.ds[this.sp - 1] > this.ds[this.sp] ? -1 : 0;
this.sp -= 1;
}
fe() {
this.ds[this.sp] = this.m[this.ds[this.sp]];
}
st() {
this.m[this.ds[this.sp]] = this.ds[this.sp - 1];
this.sp -= 2;
}
ad() {
this.ds[this.sp - 1] += this.ds[this.sp];
this.sp -= 1;
}
su() {
this.ds[this.sp - 1] -= this.ds[this.sp];
this.sp -= 1;
}
mu() {
this.ds[this.sp - 1] *= this.ds[this.sp];
this.sp -= 1;
}
di() {
this.a = this.ds[this.sp];
this.b = this.ds[this.sp - 1];
this.ds[this.sp] = Math.floor(this.b / this.a);
this.ds[this.sp - 1] = this.b % this.a;
this.symmetric();
}
an() {
this.ds[this.sp - 1] = this.ds[this.sp] & this.ds[this.sp - 1];
this.sp -= 1;
}
or() {
this.ds[this.sp - 1] = this.ds[this.sp] | this.ds[this.sp - 1];
this.sp -= 1;
}
xo() {
this.ds[this.sp - 1] = this.ds[this.sp] ^ this.ds[this.sp - 1];
this.sp -= 1;
}
sl() {
this.ds[this.sp - 1] = this.ds[this.sp - 1] << this.ds[this.sp];
this.sp -= 1;
}
sr() {
this.ds[this.sp - 1] = this.ds[this.sp - 1] >> this.ds[this.sp];
this.sp -= 1;
}
cp() {
let l = this.pop();
let d = this.pop();
let s = this.ds[this.sp];
this.ds[this.sp] = -1;
while (l) {
if (this.m[d] !== this.m[s]) {
this.ds[this.sp] = 0;
}
l -= 1;
s += 1;
d += 1;
}
}
io() {
const dev = this.pop();
switch (dev) {
case 0:
this.ioa();
break;
case 1:
this.iob();
break;
case 2:
this.ioc();
break;
case 3:
this.iod();
break;
case 4:
this.ioe();
break;
case 5:
this.iof();
break;
case 6:
this.iog();
break;
case 7:
this.ioh();
break;
default:
console.log("wtf? " + dev);
break;
}
}
cy() {
let l = this.pop();
let d = this.pop();
let s = this.pop();
while (l) {
this.m[d] = this.m[s];
l -= 1;
s += 1;
d += 1;
}
}
ioa() {
const c = String.fromCharCode(this.pop());
this.outputHandler(c);
}
iob() {
this.a = this.input.charCodeAt(0);
this.input = this.input.slice(1);
this.push(this.a);
}
ioc() {
const buf = this.pop();
const blk = this.pop();
let i = 0;
while (i < 1024) {
this.m[buf + i] = this.blocks[blk * 1024 + i];
i += 1;
}
}
iod() {
const buf = this.pop();
const blk = this.pop();
let i = 0;
while (i < 1024) {
this.blocks[blk * 1024 + i] = this.m[buf + i];
i += 1;
}
}
ioe() {}
iof() {
this.ip = -1;
this.sp = 0;
this.rp = 0;
this.loadFile(this.romURL, this.m);
}
iog() {
this.ip = 65536;
this.input = "";
}
ioh() {
this.push(this.sp);
this.push(this.rp);
}
}
(async () => {
const vm = new Konilo(
"http://forth.works/demo/ilo.rom",
"http://forth.works/demo/ilo.blocks"
);
let outputBuffer = "";
vm.setOutputHandler((char: string) => {
if (char === "\n") {
console.log(outputBuffer);
outputBuffer = "";
} else {
outputBuffer += char;
}
});
await vm.initialize();
vm.send("list\n\n");
vm.execute();
})();

264
source/mult-ilo.c Normal file
View file

@ -0,0 +1,264 @@
/***************************************************************
crc's _ _ ___ _
_ __ ___ _ _| | |_ / (_) | ___
| '_ ` _ \| | | | | __| / /| | |/ _ \
| | | | | | |_| | | |_ / / | | | (_) |
|_| |_| |_|\__,_|_|\__/_/ |_|_|\___/
(c) charles childers
This is a special implementation of my ilo computer, with many
copies of ilo running under a single process. Under this you
can quickly switch between ilo instances.
- `bye` will act like `restart` on the current computer
- ctrl+c restarts the current computer
- ctrl+n switches to the next ilo
- ctrl+p switches to the previous ilo
- ctrl+a shuts down mult/ilo
- switching can only be done when the system is waiting for
input
**************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <signal.h>
#include <termios.h>
#define V void
#define I int
#define C char
#define ILOS 5
struct termios old_term, new_term;
typedef struct ilo ilo;
struct ilo {
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) */
I a, b, f, s, d, l;
C i[1];
};
struct ilo systems[ILOS];
I cur, cancel;
#define DS v->ds
#define AS v->as
#define SP v->sp
#define RP v->rp
#define IP v->ip
#define M v->m
#define A v->a
#define B v->b
#define S v->s
#define D v->d
#define L v->l
#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 */
V iof(ilo *);
V push(ilo *v, I n) { DS[SP + 1] = n; SP += 1; }
I pop(ilo *v) { SP -= 1; return DS[SP + 1]; }
V load_image(ilo *v) {
v->f = open(v->rom, O_RDONLY, 0666);
if (!v->f) { return; };
read(v->f, &M, 65536 * 4);
close(v->f);
v->i[0] = 32;
IP = SP = RP = 0;
}
V save_image(ilo *v) {
v->f = open(v->rom, O_WRONLY, 0666);
write(v->f, &M, 65536 * 4);
close(v->f);
}
V block_common(ilo *v) {
B = pop(v); /* block buffer */
A = pop(v); /* block number */
lseek(v->f, 4096 * A, SEEK_SET);
}
V read_block(ilo *v) {
v->f = open(v->blocks, O_RDONLY, 0666);
block_common(v);
read(v->f, M + B, 4096);
close(v->f);
}
V write_block(ilo *v) {
v->f = open(v->blocks, O_WRONLY, 0666);
block_common(v);
write(v->f, M + B, 4096);
close(v->f);
}
V save_ip(ilo *v) { RP += 1; R = IP; }
V symmetric(ilo *v) {
if (B >= 0 && N < 0) { T += 1; N -= B; } }
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;
if (A == 0) { cancel = 1; iof(v); return; }
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; } }
V pre(V) { cur -= 1; if (cur < 0) cur = ILOS - 1; }
V nxt(V) { cur += 1; if (cur > (ILOS - 1)) cur = 0; }
V msgs(V) { printf("\n*** SWITCH TO %d ***\n", cur); }
V msgx(V) { printf("\n*** SHUTDOWN REQUESTED ***\n");
tcsetattr(STDIN_FILENO,TCSANOW, &old_term);
exit(1); }
V msgr(V) { printf("\n*** RESTART %d ***\n", cur); }
V ioa(ilo *v) { v->i[0] = (char)pop(v); write(1, &v->i, 1); }
V iob(ilo *v) { read(0, &v->i, 1); push(v, v->i[0]);
if (v->i[0] == 14) { T = 32; nxt(); msgs(); }
if (v->i[0] == 16) { T = 32; pre(); msgs(); }
if (v->i[0] == 3) { T = 32; msgr(); iof(v);
cancel = 1; }
if (v->i[0] == 1) { T = 32; msgx(); }
if (v->i[0] == 8 || v->i[0] == 127) {
v->i[0] = '\b'; write(1, &v->i, 1);
v->i[0] = ' '; write(1, &v->i, 1);
v->i[0] = '\b'; write(1, &v->i, 1);
} else { write(1, &v->i, 1); } }
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; }
V iog(ilo *v) { iof(v); }
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;
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;
}
}
V process_bundle(ilo *v, I opcode) {
if (cancel) return; process(v, opcode & 0xFF);
if (cancel) return; process(v, (opcode >> 8) & 0xFF);
if (cancel) return; process(v, (opcode >> 16) & 0xFF);
if (cancel) return; process(v, (opcode >> 24) & 0xFF);
}
V execute(V) {
ilo *v = &systems[cur];
while (IP < 65536) {
cancel = 0;
process_bundle(v, M[IP]);
IP += 1;
v = &systems[cur];
}
}
V handle_sigint(I sig) {
printf("\n*** SIGINT (%d) : RESTARTING %d ***\n", sig, cur);
cancel = 1;
iof(&systems[cur]);
}
I main(I argc, C **argv) {
ilo *v;
I i;
cur = 0;
for (i = 0; i < ILOS; i++) {
v = &systems[i];
v->blocks = (argc > 1) ? argv[1] : "ilo.blocks";
v->rom = (argc > 2) ? argv[2] : "ilo.rom";
load_image(v);
}
if (signal(SIGINT, handle_sigint) == SIG_ERR) {
perror("signal");
return 1;
}
tcgetattr(STDIN_FILENO, &old_term);
new_term = old_term;
new_term.c_lflag &=(~ICANON & ~ECHO);
tcsetattr(STDIN_FILENO, TCSANOW, &new_term);
execute();
tcsetattr(STDIN_FILENO, TCSANOW, &old_term);
return 0;
}

466
source/x11-ilo.c Normal file
View file

@ -0,0 +1,466 @@
/***************************************************************
crc's _ _ __
(_) | ___ / /_ __
| | |/ _ \ / /\ \/ / a tiny virtual computer
| | | (_) / / > < 64kw RAM, 32-bit, Dual Stack, MISC
|_|_|\___/_/ /_/\_\ ilo-x.c (c) charles childers
**************************************************************/
/* cc -o ilo-x vm/ilo-x.c `pkg-config --cflags x11 --libs` */
/* Local Configuration */
#define BLOCKS "ilo.blocks"
#define ROM "ilo.rom"
#define FONT "ilo.fnt"
#define FG 0xFFFFFF
#define BG 0x000000
#define CURSOR 0x00FFFF
#define FW 640
#define FH 384
#define FONT_H 16
#define FONT_W 8
#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#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 V void
#define I int
#define C char
I ip, /* instruction pointer */
sp, /* data stack pointer */
rp, /* address stack pointer */
ds[33], /* data stack */
as[257], /* address stack */
m[65536], /* memory */
ok;
C *blocks, /* name of block file (ilo.blocks) */
*rom; /* name of image (ilo.rom) */
I a, b, f, s, d, l; /* these others are used */
C i[1]; /* for misc. purposes */
#define TERM_W (FW / FONT_W)
#define TERM_H (FH / FONT_H)
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;
C text[255];
V dputc(I);
V redraw();
V iof();
V p(char *s) { while(*s) dputc(*s++); }
V e(char *s) { p("E:"); p(s); p("\n"); ok = 1; iof(); }
V dso() { if ((sp + 1) > 32) { e("DSO"); } }
V dsu() { if ((sp - 1) < 0) { e("DSU"); } }
V rso() { if ((rp + 1) > 256) { e("RSO"); } }
V rsu() { if ((rp - 1) < 0) { e("RSU"); } }
V dbz() { if (T == 0) { e("DBZ"); } }
V mem() { if (T < 0 || T > 65535) { e("MEM"); } }
V uli() { if (f == -1) { e("ULI"); } }
V ulf() { if (f == -1) { e("ULF"); } }
V usi() { if (f == -1) { e("URI"); } }
V urb() { if (f == -1) { e("URB"); } }
V uwb() { if (f == -1) { e("UWB"); } }
V push(I v) { dso(); ds[sp + 1] = v; sp += 1; }
I pop() { dsu(); sp -= 1; return ds[sp + 1]; }
V cursor() {
XSetForeground(disp, gc, CURSOR);
XFillRectangle(disp, win, gc, tx, ty, FONT_W, FONT_H);
XFlush(disp);
}
I wait_key() {
while (1) {
XNextEvent(disp, &event);
if (event.type == KeyPress) {
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];
}
if (event.type == Expose) { redraw(); }
}
}
V load_font() {
f = open(FONT, O_RDONLY, 0666);
ulf();
if (!f) { return; };
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);
}
}
cursor();
}
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) {
b = (b & 0xF0) >> 4 | (b & 0x0F) << 4;
b = (b & 0xCC) >> 2 | (b & 0x33) << 2;
b = (b & 0xAA) >> 1 | (b & 0x55) << 1;
return b;
}
V handle_special_character(I c) {
if (c == 8 || c == 127) { /* BACKSPACE/DELETE */
if (tx - FONT_W >= 0) {
tx -= FONT_W ;
dputc(' ');
tx -= FONT_W;
redraw();
}
} else if (c == 9) { /* TAB */
I ts = tx / FONT_W;
for (I i = ts; i < ((ts + 7) / 8) * 8; i++) { dputc(' '); }
} else if (c == 10 || c == 13) { /* CR or LF */
ty += FONT_H;
tx = 0;
redraw();
}
}
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(); }
}
V dputc(I c) {
C *bitmap = (C *)font + (c * ((FONT_H * FONT_W) / 8));
handle_special_character(c);
if (!(c == 8 || c == 127 || c == 9 || c == 10 || c == 13)) {
handle_regular_character(bitmap);
}
advance_cursor_and_scroll();
cursor();
}
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; }
V gt_down(I n) { ty += FONT_H; if (ty > 24 * FONT_H) ty = 24 * FONT_H; }
V gt_left(I n) { tx -= FONT_W; if (tx < 0) tx = 0; }
V gt_right(I n) { tx += FONT_W; if (tx > 79 * FONT_W) ty = 79 * FONT_W; }
V gt_move_cursor() {
if (acc_i >= 1) {
I a = (acc_pop() - 1) * FONT_W;
I b = (acc_pop() - 1) * FONT_H;
ty = b; if (ty < 0) ty = 0; if (ty > FONT_H * 24) ty = FONT_H * 24;
tx = a; if (tx < 0) tx = 0; if (tx > FONT_W * 79) tx = FONT_W * 79;
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) {
if (c == 27) {
on = -2;
return;
}
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);
}
}
}
V load_image() {
f = open(rom, O_RDONLY, 0666);
uli();
if (!f) { return; };
read(f, &m, 65536 * 4);
close(f);
ip = sp = rp = 0;
}
V save_image() {
f = open(rom, O_WRONLY, 0666);
usi();
write(f, &m, 65536 * 4);
close(f);
}
V block_common() {
b = pop(); /* block buffer */
a = pop(); /* block number */
lseek(f, 4096 * a, SEEK_SET);
}
V read_block() {
f = open(blocks, O_RDONLY, 0666);
urb();
block_common();
read(f, m + b, 4096);
close(f);
}
V write_block() {
f = open(blocks, O_WRONLY, 0666);
uwb();
block_common();
write(f, m + b, 4096);
close(f);
}
V save_ip() { rso(); rp += 1; R = ip; }
V symmetric() { if (b >= 0 && N < 0) { T += 1; N -= b; } }
V li() { ip += 1; push(m[ip]); }
V du() { push(T); }
V dr() { pop(); }
V sw() { a = T; T = N; N = a; }
V pu() { rp += 1; R = pop(); }
V po() { push(R); rp -= 1; }
V ju() { ip = pop() - 1; }
V ca() { save_ip(); ip = pop() - 1; }
V cc() { a = pop(); if (pop()) { save_ip(); ip = a - 1; } }
V cj() { a = pop(); if (pop()) { ip = a - 1; } }
V re() { ip = R; rp -= 1; }
V eq() { N = (N == T) ? -1 : 0; sp -= 1; }
V ne() { N = (N != T) ? -1 : 0; sp -= 1; }
V lt() { N = (N < T) ? -1 : 0; sp -= 1; }
V gt() { N = (N > T) ? -1 : 0; sp -= 1; }
V fe() { mem(); T = m[T]; }
V st() { mem(); m[T] = N; sp -= 2; }
V ad() { N += T; sp -= 1; }
V su() { N -= T; sp -= 1; }
V mu() { N *= T; sp -= 1; }
V di() { dbz();
a = T; b = N; T = b / a; N = b % a; symmetric(); }
V an() { N = T & N; sp -= 1; }
V or() { N = T | N; sp -= 1; }
V xo() { N = T ^ N; sp -= 1; }
V sl() { N = N << T; sp -= 1; }
V sr() { N = N >> T; sp -= 1; }
V cp() { l = pop(); d = pop(); s = T; T = -1;
while (l) { if (m[d] != m[s]) { T = 0; }
l -= 1; s += 1; d += 1; } }
V cy() { l = pop(); d = pop(); s = pop();
while (l) { m[d] = m[s]; l -= 1; s += 1; d += 1; } }
V ioa() { term_putc(pop()); }
V iob() { push(wait_key()); term_putc(T); }
V ioc() { read_block(); }
V iod() { write_block(); }
V ioe() { save_image(); }
V iof() { load_image(); ip = -1; }
V iog() { ip = 65536; }
V ioh() { push(sp); push(rp); }
V iox() { I c = pop(); I y = pop(); I x = pop();
pixel(x, y, c); }
V ioy() { I y = pop(); I x = pop(); push(get_pixel(x, y)); }
V ioz() { I x, y, wx, wy, mask; Window w;
XQueryPointer(disp, win, &w, &w, &x, &y, &wx, &wy, &mask);
push(x); push(y); if (mask & Button1Mask) push(-1); else push(0); }
V io() {
switch (pop()) {
case 0: ioa(); break; case 1: iob(); break;
case 2: ioc(); break; case 3: iod(); break;
case 4: ioe(); break; case 5: iof(); break;
case 6: iog(); break; case 7: ioh(); break;
case 33: iox(); break; case 34: ioy(); break;
case 35: ioz(); break;
default: break;
}
}
V process(I o) {
switch (o) {
case 0: break; case 1: li(); break;
case 2: du(); break; case 3: dr(); break;
case 4: sw(); break; case 5: pu(); break;
case 6: po(); break; case 7: ju(); break;
case 8: ca(); break; case 9: cc(); break;
case 10: cj(); break; case 11: re(); break;
case 12: eq(); break; case 13: ne(); break;
case 14: lt(); break; case 15: gt(); break;
case 16: fe(); break; case 17: st(); break;
case 18: ad(); break; case 19: su(); break;
case 20: mu(); break; case 21: di(); break;
case 22: an(); break; case 23: or(); break;
case 24: xo(); break; case 25: sl(); break;
case 26: sr(); break; case 27: cp(); break;
case 28: cy(); break; case 29: io(); break;
default: break;
}
}
#define VALID(n) (ok == 0) && ((opcode >> n) & 0xFF)
V execute() {
I opcode;
while (ip < 65536) {
opcode = m[ip];
ok = 0;
if (VALID(0)) process(opcode & 0xFF);
if (VALID(8)) process((opcode >> 8) & 0xFF);
if (VALID(16)) process((opcode >> 16) & 0xFF);
if (VALID(24)) process((opcode >> 24) & 0xFF);
ip += 1;
}
}
I main(I argc, C **argv) {
blocks = (argc > 1) ? argv[1] : BLOCKS;
rom = (argc > 2) ? argv[2] : ROM;
ok = 0;
/*
#ifdef __OpenBSD__
pledge("stdio rpath wpath unix video", NULL);
#endif
*/
load_image();
load_font();
disp = XOpenDisplay(NULL);
win = XCreateSimpleWindow(disp, RootWindow(disp, 0),
0, 0, FW, FH, 0, 0x0, 0x0);
XSelectInput(disp, win, ExposureMask | KeyPressMask | ButtonPressMask | ButtonReleaseMask);
XStoreName(disp, win, "x/ilo");
gc = DefaultGC(disp, DefaultScreen(disp));
XMapWindow(disp, win);
XFlush(disp);
XMoveWindow(disp, win, (DisplayWidth(disp, DefaultScreen(disp)) - FW) / 2,
(DisplayHeight(disp, DefaultScreen(disp)) - FH) / 2);
execute();
XUnmapWindow(disp, win);
XDestroyWindow(disp, win);
XCloseDisplay(disp);
return 0;
}

522
source/x11-mult-ilo.c Normal file
View file

@ -0,0 +1,522 @@
/***************************************************************
crc's _ _ ___ _ __
_ __ ___ _ _| | |_ / (_) | ___ / /_ __
| '_ ` _ \| | | | | __| / /| | |/ _ \ / /\ \/ /
| | | | | | |_| | | |_ / / | | | (_) / / > <
|_| |_| |_|\__,_|_|\__/_/ |_|_|\___/_/ /_/\_\
(c) charles childers
This is a special implementation of my ilo computer, with many
copies of ilo running under a single process. Under this you
can quickly switch between ilo instances.
- `bye` will act like `restart` on the current computer
- ctrl+c restarts the current computer
- ctrl+n switches to the next ilo
- ctrl+p switches to the previous ilo
- ctrl+a shuts down mult/ilo
- switching can only be done when the system is waiting for
input
**************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <signal.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#define BLOCKS "ilo.blocks"
#define ROM "ilo.rom"
#define FONT "ilo.fnt"
#define FG 0xFFFFFF
#define BG 0x000000
/* Orange = 0xFFAA00, Red = 0xFF0000, Cyan = 0x00FFFF */
#define CURSOR 0xFFAA00
#define FW 640
#define FH 384
#define FONT_H 16
#define FONT_W 8
#define V void
#define I int
#define C char
#define ILOS 3
typedef struct ilo ilo;
struct ilo {
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) */
I a, b, f, s, d, l, ok;
C i[1];
};
#define TERM_W (FW / FONT_W)
#define TERM_H (FH / FONT_H)
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;
C text[255];
V dputc(I);
V redraw();
struct ilo systems[ILOS];
I cur;
#define DS v->ds
#define AS v->as
#define SP v->sp
#define RP v->rp
#define IP v->ip
#define M v->m
#define A v->a
#define B v->b
#define S v->s
#define D v->d
#define L v->l
#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 F v->f
V iof(ilo *);
V p(char *s) { while(*s) dputc(*s++); }
V e(ilo *v, char *s) { p("E:"); p(s); p("\n"); v->ok = 1; iof(v); }
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"); } }
V uli(ilo *v) { if (F == -1) { e(v, "ULI"); } }
V ulf(ilo *v) { if (F == -1) { e(v, "ULF"); } }
V usi(ilo *v) { if (F == -1) { e(v, "URI"); } }
V urb(ilo *v) { if (F == -1) { e(v, "URB"); } }
V uwb(ilo *v) { if (F == -1) { e(v, "UWB"); } }
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]; }
V cursor() {
XSetForeground(disp, gc, CURSOR);
XFillRectangle(disp, win, gc, tx, ty, FONT_W, FONT_H);
XFlush(disp);
}
I wait_key() {
while (1) {
XNextEvent(disp, &event);
if (event.type == KeyPress) {
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];
}
if (event.type == Expose) { redraw(); cursor(); }
}
}
V load_font(ilo *v) {
F = open(FONT, O_RDONLY, 0666);
ulf(v);
if (!F) { return; };
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) {
b = (b & 0xF0) >> 4 | (b & 0x0F) << 4;
b = (b & 0xCC) >> 2 | (b & 0x33) << 2;
b = (b & 0xAA) >> 1 | (b & 0x55) << 1;
return b;
}
V handle_special_character(I c) {
if (c == 8 || c == 127) { /* BACKSPACE/DELETE */
if (tx - FONT_W >= 0) {
tx -= FONT_W ;
dputc(' ');
tx -= FONT_W;
}
} else if (c == 9) { /* TAB */
I ts = tx / FONT_W;
for (I i = ts; i < ((ts + 7) / 8) * 8; i++) { dputc(' '); }
} else if (c == 10 || c == 13) { /* CR or LF */
ty += FONT_H;
tx = 0;
}
}
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(); }
}
V dputc(I c) {
C *bitmap = (C *)font + (c * ((FONT_H * FONT_W) / 8));
handle_special_character(c);
if (!(c == 8 || c == 127 || c == 9 || c == 10 || c == 13)) {
handle_regular_character(bitmap);
}
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; }
V gt_down(I n) { ty += FONT_H; if (ty > 24 * FONT_H) ty = 24 * FONT_H; }
V gt_left(I n) { tx -= FONT_W; if (tx < 0) tx = 0; }
V gt_right(I n) { tx += FONT_W; if (tx > 79 * FONT_W) ty = 79 * FONT_W; }
V gt_move_cursor() {
if (acc_i >= 1) {
I a = (acc_pop() - 1) * FONT_W;
I b = (acc_pop() - 1) * FONT_H;
ty = b; if (ty < 0) ty = 0; if (ty > FONT_H * 24) ty = FONT_H * 24;
tx = a; if (tx < 0) tx = 0; if (tx > FONT_W * 79) tx = FONT_W * 79;
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) {
if (c == 27) {
on = -2;
return;
}
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);
}
}
}
V load_image(ilo *v) {
F = open(v->rom, O_RDONLY, 0666);
if (!F) { return; };
read(F, &M, 65536 * 4);
close(F);
IP = SP = RP = 0;
}
V save_image(ilo *v) {
v->f = open(v->rom, O_WRONLY, 0666);
write(v->f, &M, 65536 * 4);
close(v->f);
}
V block_common(ilo *v) {
B = pop(v); /* block buffer */
A = pop(v); /* block number */
lseek(v->f, 4096 * A, SEEK_SET);
}
V read_block(ilo *v) {
v->f = open(v->blocks, O_RDONLY, 0666);
block_common(v);
read(v->f, M + B, 4096);
close(v->f);
}
V write_block(ilo *v) {
v->f = open(v->blocks, O_WRONLY, 0666);
block_common(v);
write(v->f, M + B, 4096);
close(v->f);
}
V save_ip(ilo *v) { RP += 1; R = IP; }
V symmetric(ilo *v) {
if (B >= 0 && N < 0) { T += 1; N -= B; } }
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;
if (A == 0) { v->ok = 1; iof(v); return; }
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; } }
V pre(V) { cur -= 1; if (cur < 0) cur = ILOS - 1; }
V nxt(V) { cur += 1; if (cur > (ILOS - 1)) cur = 0; }
V msgs(V) { printf("\n*** SWITCH TO %d ***\n", cur); }
V msgx(V) { printf("\n*** SHUTDOWN REQUESTED ***\n");
exit(1); }
V msgr(V) { printf("\n*** RESTART %d ***\n", cur); }
V term_putc(I c);
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);
if (v->i[0] == 14) { T = 32; nxt(); msgs(); }
if (v->i[0] == 16) { T = 32; pre(); msgs(); }
if (v->i[0] == 3) { T = 32; msgr(); iof(v);
v->ok = 1; }
if (v->i[0] == 1) { T = 32; msgx(); } }
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; }
V iog(ilo *v) { iof(v); }
V ioh(ilo *v) { push(v, SP); push(v, RP); }
V iox(ilo *v) { I c = pop(v); I y = pop(v); I x = pop(v);
pixel(x, y, c); }
V ioy(ilo *v) { I y = pop(v); I x = pop(v); push(v, get_pixel(x, y)); }
V ioz(ilo *v) { I x, y, wx, wy, 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); }
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;
case 33: iox(v); break; case 34: ioy(v); break;
case 35: ioz(v); break;
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;
}
}
#define VALID(n) (v->ok == 0) && ((opcode >> n) & 0xFF)
V execute() {
I opcode;
ilo *v = &systems[cur];
while (IP < 65536) {
opcode = M[IP];
v->ok = 0;
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];
}
}
V load_font(ilo *);
I main(I argc, C **argv) {
ilo *v;
I i;
cur = 0;
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);
}
load_font(&systems[0]);
disp = XOpenDisplay(NULL);
win = XCreateSimpleWindow(disp, RootWindow(disp, 0),
0, 0, FW, FH, 0, 0x0, 0x0);
XSelectInput(disp, win, ExposureMask | KeyPressMask | ButtonPressMask | ButtonReleaseMask);
XStoreName(disp, win, "x/ilo");
gc = DefaultGC(disp, DefaultScreen(disp));
XMapWindow(disp, win);
XFlush(disp);
XMoveWindow(disp, win, (DisplayWidth(disp, DefaultScreen(disp)) - FW) / 2,
(DisplayHeight(disp, DefaultScreen(disp)) - FH) / 2);
execute();
XUnmapWindow(disp, win);
XDestroyWindow(disp, win);
XCloseDisplay(disp);
return 0;
}