ilo-vm/source/ilo.kt

280 lines
6.1 KiB
Kotlin

// -------------------------------------------------------------
// 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
}
}