check in the source files, binaries, and update README & LICENSE
This commit is contained in:
parent
8a784593c4
commit
35d1a33e25
63 changed files with 15419 additions and 7 deletions
32
LICENSE
32
LICENSE
|
@ -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.
|
||||
|
||||
================================================================
|
||||
|
|
38
README.md
38
README.md
|
@ -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
BIN
binaries/CWSDPMI.exe
Normal file
Binary file not shown.
BIN
binaries/ilo-68k-mac.bin
Normal file
BIN
binaries/ilo-68k-mac.bin
Normal file
Binary file not shown.
BIN
binaries/ilo-aarch64-linux
Executable file
BIN
binaries/ilo-aarch64-linux
Executable file
Binary file not shown.
BIN
binaries/ilo-amd64-dragonfly
Executable file
BIN
binaries/ilo-amd64-dragonfly
Executable file
Binary file not shown.
BIN
binaries/ilo-amd64-freebsd
Executable file
BIN
binaries/ilo-amd64-freebsd
Executable file
Binary file not shown.
BIN
binaries/ilo-amd64-haiku
Executable file
BIN
binaries/ilo-amd64-haiku
Executable file
Binary file not shown.
BIN
binaries/ilo-amd64-linux
Executable file
BIN
binaries/ilo-amd64-linux
Executable file
Binary file not shown.
BIN
binaries/ilo-amd64-netbsd
Executable file
BIN
binaries/ilo-amd64-netbsd
Executable file
Binary file not shown.
BIN
binaries/ilo-amd64-openbsd
Executable file
BIN
binaries/ilo-amd64-openbsd
Executable file
Binary file not shown.
BIN
binaries/ilo-amd64-windows.exe
Normal file
BIN
binaries/ilo-amd64-windows.exe
Normal file
Binary file not shown.
BIN
binaries/ilo-arm64-darwin
Executable file
BIN
binaries/ilo-arm64-darwin
Executable file
Binary file not shown.
BIN
binaries/ilo-dotnet-windows.exe
Executable file
BIN
binaries/ilo-dotnet-windows.exe
Executable file
Binary file not shown.
BIN
binaries/ilo-ipad-ish
Executable file
BIN
binaries/ilo-ipad-ish
Executable file
Binary file not shown.
BIN
binaries/ilo-luna88k-openbsd
Executable file
BIN
binaries/ilo-luna88k-openbsd
Executable file
Binary file not shown.
BIN
binaries/ilo-pmax-netbsd
Executable file
BIN
binaries/ilo-pmax-netbsd
Executable file
Binary file not shown.
4230
binaries/ilo-teensy41.hex
Normal file
4230
binaries/ilo-teensy41.hex
Normal file
File diff suppressed because it is too large
Load diff
BIN
binaries/ilo-universal-darwin
Executable file
BIN
binaries/ilo-universal-darwin
Executable file
Binary file not shown.
BIN
binaries/ilo-x86-dos-32bit.exe
Normal file
BIN
binaries/ilo-x86-dos-32bit.exe
Normal file
Binary file not shown.
BIN
binaries/ilo-x86-dos.exe
Normal file
BIN
binaries/ilo-x86-dos.exe
Normal file
Binary file not shown.
BIN
binaries/ilo-x86-freebsd
Executable file
BIN
binaries/ilo-x86-freebsd
Executable file
Binary file not shown.
BIN
binaries/ilo-x86-linux
Executable file
BIN
binaries/ilo-x86-linux
Executable file
Binary file not shown.
BIN
binaries/ilo-x86-netbsd
Normal file
BIN
binaries/ilo-x86-netbsd
Normal file
Binary file not shown.
BIN
binaries/ilo-x86-openbsd
Executable file
BIN
binaries/ilo-x86-openbsd
Executable file
Binary file not shown.
BIN
binaries/ilo-x86-windows.exe
Normal file
BIN
binaries/ilo-x86-windows.exe
Normal file
Binary file not shown.
BIN
binaries/ilo.jar
Normal file
BIN
binaries/ilo.jar
Normal file
Binary file not shown.
1
source/ilo-68k-mac.c
Normal file
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
1120
source/ilo-aarch64-linux.s
Normal file
File diff suppressed because it is too large
Load diff
422
source/ilo-amd64-dragonfly.s
Normal file
422
source/ilo-amd64-dragonfly.s
Normal 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
420
source/ilo-amd64-freebsd.s
Normal 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
405
source/ilo-amd64-linux.s
Normal 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
414
source/ilo-amd64-netbsd.s
Normal 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
439
source/ilo-amd64-openbsd.s
Normal 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
205
source/ilo-banked.c
Normal 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
215
source/ilo-be.c
Normal 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
191
source/ilo-dos.c
Normal 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
701
source/ilo-js.html
Normal 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 & blocks)
|
||||
<hr>
|
||||
|
||||
<div id="settings">
|
||||
<table>
|
||||
<tr><td>
|
||||
Use your own image & 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
71
source/ilo-min.c
Normal 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
205
source/ilo-plan9.c
Normal 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
183
source/ilo-pthread.c
Normal 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
197
source/ilo-safer.c
Normal 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
267
source/ilo-teensy41.ino
Normal 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
141
source/ilo-windows.c
Normal 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
184
source/ilo.c
Normal 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
327
source/ilo.cl
Normal 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
161
source/ilo.cs
Normal 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
187
source/ilo.cxx
Normal 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
232
source/ilo.d
Normal 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
BIN
source/ilo.fnt
Normal file
Binary file not shown.
193
source/ilo.go
Normal file
193
source/ilo.go
Normal 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
239
source/ilo.ha
Normal 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
280
source/ilo.kt
Normal 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
343
source/ilo.lua
Normal 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
241
source/ilo.nim
Normal 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
515
source/ilo.py
Normal 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
181
source/ilo.retro
Normal 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
368
source/ilo.rs
Normal 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
310
source/ilo.swift
Normal 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
516
source/ilo.ts
Normal 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
264
source/mult-ilo.c
Normal 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
466
source/x11-ilo.c
Normal 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
522
source/x11-mult-ilo.c
Normal 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;
|
||||
}
|
Loading…
Reference in a new issue