Makes things work better (worst commit message ever)
This commit is contained in:
parent
b69d1500bf
commit
55715ba55e
13
README.md
13
README.md
|
@ -1,10 +1,15 @@
|
|||
# bird, a vm
|
||||
|
||||
This is a learning project. Many mistakes are being made, but lots of fun is being had. Inspired by varvara/uxn, but without looking at their implementation details and mostly just taking my memory of their project as a point of inspiration.
|
||||
bird-vm is a mostly stack based vm. It uses 8-bit ops and 8-bit stacks, but has 16-bit addressing and the ability to do 16 bit math and work with the stacks in "long mode" (pop a high and low byte to work with 16-bit numbers).
|
||||
|
||||
This is a learning project. Many mistakes are being made, but lots of fun is being had. It is inspired by varvara/uxn, but without looking at their implementation details and mostly just taking my memory of their project as a point of inspiration. I do not expect it to be generally useful, or a particularly good design (it is my first time dipping a toe into writing a bytecode interpreter/vm).
|
||||
|
||||
Coming soon:
|
||||
|
||||
1. An assembler that produces bird bytecode
|
||||
2. More ops filled in within the vm
|
||||
3. A higher level language that compiles down to either the assembler or to bytecode
|
||||
- [X] An assembler that produces bird bytecode (see: [bird-asm](https://tildegit.org/sloum/bird-asm) )
|
||||
- [ ] A few string handling ops that will make working with null terminated strings more functional
|
||||
- [ ] A higher level language that compiles down to either the assembler or to bytecode
|
||||
- I am thinking about something vaguely Pascal-like
|
||||
|
||||
|
||||
|
||||
|
|
11
helpers.go
11
helpers.go
|
@ -48,26 +48,27 @@ func To8s(n uint16) (byte, byte) {
|
|||
return byte(n>>8), byte(n & uint16(0xFF))
|
||||
}
|
||||
|
||||
func LoadProg(b []byte) {
|
||||
func LoadProg(b []byte) int{
|
||||
for i := range b {
|
||||
vm.Prog[i] = b[i]
|
||||
}
|
||||
if len(b) < 2 {
|
||||
return
|
||||
return 0
|
||||
}
|
||||
vm.HP = To16(vm.Prog[0], vm.Prog[1])
|
||||
return len(b)
|
||||
}
|
||||
|
||||
func DumpVm() {
|
||||
func DumpVm(l int) {
|
||||
fmt.Fprintf(
|
||||
os.Stderr,
|
||||
"\n<%03d>Data : %v\n<%03d>Return: %v\nPC: %d\nData: %v",
|
||||
"\n<%03d>Data : %v\n<%03d>Return: %v\nPC: %d\nMemory: %v",
|
||||
vm.Data.pointer,
|
||||
vm.Data.data[:vm.Data.pointer],
|
||||
vm.Return.pointer,
|
||||
vm.Return.data[:vm.Return.pointer],
|
||||
vm.PC,
|
||||
vm.Prog[:vm.PC])
|
||||
vm.Prog[:l])
|
||||
}
|
||||
|
||||
|
||||
|
|
14
main.go
14
main.go
|
@ -8,8 +8,6 @@ import (
|
|||
|
||||
/*
|
||||
TODO
|
||||
- Change GCH and GST to RCH and RST (From G/Get to R/Read)
|
||||
- Remove PHX
|
||||
- Add SST (set string: move a string from the stack to memory)
|
||||
- Add a flag that lets the heap pointer move after the write?
|
||||
- If this isn't present then GST and RST have to add a length
|
||||
|
@ -28,7 +26,7 @@ var ops = []func(bool, *Stack){
|
|||
opAdd, opSub, opMul, opDiv, opInc, opDec, opNop,
|
||||
opAnd, opBor, opXor, opShr, opShl, opNop, opNop, // <-27
|
||||
opJmp, opCal, opJcd, opRet, opNop, opNop, opNop,
|
||||
opGch, opGst, opPut, opPst, opHlt, opNop, opNop,
|
||||
opRch, opRst, opPut, opPst, opHlt, opSst, opGst,
|
||||
opGrt, opLst, opGte, opLte, opEql, opNeq, opNop, //<-48
|
||||
opNop, opNop, opNop, opNop, opNop, opNop, opNop,
|
||||
opNop, opNop, opNop, opNop, opNop, opNop, opNop,
|
||||
|
@ -40,7 +38,7 @@ var ops = []func(bool, *Stack){
|
|||
opAdd, opSub, opMul, opDiv, opInc, opDec, opNop,
|
||||
opAnd, opBor, opXor, opShr, opShl, opNop, opNop,
|
||||
opJmp, opCal, opJcd, opRet, opNop, opNop, opNop,
|
||||
opGch, opGst, opPut, opPst, opHlt, opNop, opNop,
|
||||
opRch, opRst, opPut, opPst, opHlt, opSst, opGst,
|
||||
opGrt, opLst, opGte, opLte, opEql, opNeq, opNop, //<-112
|
||||
opNop, opNop, opNop, opNop, opNop, opNop, opNop,
|
||||
opNop, opNop, opNop, opNop, opNop, opNop, opNop,
|
||||
|
@ -52,7 +50,7 @@ var ops = []func(bool, *Stack){
|
|||
opAdd, opSub, opMul, opDiv, opInc, opDec, opNop,
|
||||
opAnd, opBor, opXor, opShr, opShl, opNop, opNop,
|
||||
opJmp, opCal, opJcd, opRet, opNop, opNop, opNop,
|
||||
opGch, opGst, opPut, opPst, opHlt, opNop, opNop,
|
||||
opRch, opRst, opPut, opPst, opHlt, opSst, opGst,
|
||||
opGrt, opLst, opGte, opLte, opEql, opNeq, opNop, //<-176
|
||||
opNop, opNop, opNop, opNop, opNop, opNop, opNop,
|
||||
opNop, opNop, opNop, opNop, opNop, opNop, opNop,
|
||||
|
@ -64,7 +62,7 @@ var ops = []func(bool, *Stack){
|
|||
opAdd, opSub, opMul, opDiv, opInc, opDec, opNop,
|
||||
opAnd, opBor, opXor, opShr, opShl, opNop, opNop,
|
||||
opJmp, opCal, opJcd, opRet, opNop, opNop, opNop,
|
||||
opGch, opGst, opPut, opPst, opHlt, opNop, opNop,
|
||||
opRch, opRst, opPut, opPst, opHlt, opSst, opGst,
|
||||
opGrt, opLst, opGte, opLte, opEql, opNeq, opNop, //<-176
|
||||
opNop, opNop, opNop, opNop, opNop, opNop, opNop,
|
||||
opNop, opNop, opNop, opNop, opNop, opNop, opNop,
|
||||
|
@ -96,7 +94,7 @@ func main() {
|
|||
os.Exit(1)
|
||||
}
|
||||
|
||||
LoadProg(in)
|
||||
l := LoadProg(in)
|
||||
vm.PC = 2
|
||||
|
||||
// Loop
|
||||
|
@ -120,7 +118,7 @@ func main() {
|
|||
halt = 9
|
||||
}
|
||||
if dumpVmData {
|
||||
DumpVm()
|
||||
DumpVm(l)
|
||||
}
|
||||
os.Exit(halt)
|
||||
}
|
||||
|
|
89
ops.go
89
ops.go
|
@ -1,6 +1,7 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"os"
|
||||
"strconv"
|
||||
|
@ -12,13 +13,13 @@ func opNop(longOp bool, s *Stack){}
|
|||
|
||||
// ( [val] val high low -- )
|
||||
func opSet(longOp bool, s *Stack) {
|
||||
addr := PopAddress()
|
||||
addr := s.PopLong()
|
||||
if longOp {
|
||||
h, l := vm.Data.Pop2()
|
||||
h, l := s.Pop2()
|
||||
vm.Mem.Write2(addr, h, l)
|
||||
return
|
||||
}
|
||||
vm.Mem.Write(addr, vm.Data.Pop())
|
||||
vm.Mem.Write(addr, s.Pop())
|
||||
}
|
||||
|
||||
// ( high low -- val [val] )
|
||||
|
@ -318,7 +319,7 @@ func opRet(longOp bool, s *Stack){
|
|||
}
|
||||
|
||||
// ( -- ch )
|
||||
func opGch(longOp bool, s *Stack) {
|
||||
func opRch(longOp bool, s *Stack) {
|
||||
oldTerm, err := term.MakeRaw(int(os.Stdin.Fd()))
|
||||
if err != nil {
|
||||
vm.Data.Push(byte(0))
|
||||
|
@ -338,16 +339,26 @@ func opGch(longOp bool, s *Stack) {
|
|||
vm.Data.Push(b[0])
|
||||
}
|
||||
|
||||
// Get string placeholder
|
||||
// Maybe use scanline instead?
|
||||
func opGst(longOp bool, s *Stack){
|
||||
b := make([]byte, 1)
|
||||
_, err := os.Stdin.Read(b)
|
||||
// Read a string from stdin until delim byte
|
||||
// ( delim -- 0 [b ...] hiLen loLen)
|
||||
func opRst(longOp bool, s *Stack){
|
||||
delim := s.Pop()
|
||||
|
||||
reader := bufio.NewReader(os.Stdin)
|
||||
text, err := reader.ReadString(delim)
|
||||
if err != nil {
|
||||
vm.Data.Push(0)
|
||||
return
|
||||
}
|
||||
vm.Data.Push(b[0])
|
||||
length := len(text)+1
|
||||
s.Push(0)
|
||||
for i := len(text)-2; i >= 0; i-- {
|
||||
if text[i] > 255 {
|
||||
s.Push(byte('?'))
|
||||
}
|
||||
s.Push(byte(text[i]))
|
||||
}
|
||||
s.PushLong(uint16(length))
|
||||
}
|
||||
|
||||
func opPut(longOp bool, s *Stack) {
|
||||
|
@ -379,6 +390,21 @@ func opPut(longOp bool, s *Stack) {
|
|||
}
|
||||
|
||||
func opPst(longOp bool, s *Stack){
|
||||
st := make([]byte, 0)
|
||||
dest := s.Pop()
|
||||
d := os.Stdout
|
||||
if dest == 2 {
|
||||
d = os.Stderr
|
||||
}
|
||||
var b byte
|
||||
for {
|
||||
b = s.Pop()
|
||||
if b == 0 {
|
||||
break
|
||||
}
|
||||
st = append(st, b)
|
||||
}
|
||||
d.Write(st)
|
||||
}
|
||||
|
||||
// Halt execution
|
||||
|
@ -387,6 +413,49 @@ func opHlt(longOp bool, s *Stack){
|
|||
halt = int(vm.Data.Pop())
|
||||
}
|
||||
|
||||
// Set string (set a string to a memory address)
|
||||
// Reads from the stack until a zero bye has been
|
||||
// reached and added to the string in memory.
|
||||
//
|
||||
// Memory space should be created in advance.
|
||||
// ( b ... -- )
|
||||
func opSst(longOp bool, s *Stack) {
|
||||
addr := s.PopLong()
|
||||
var b byte
|
||||
for {
|
||||
b = s.Pop()
|
||||
vm.Prog[addr] = b
|
||||
if b == 0 {
|
||||
break
|
||||
}
|
||||
addr++
|
||||
}
|
||||
}
|
||||
|
||||
// Get a string from memory onto a stack. Leaves
|
||||
// the memory intact (does not clear it).
|
||||
//
|
||||
// ( hi lo -- b ... hi lo )
|
||||
// | addr | | data | | len |
|
||||
//
|
||||
// The len will include the zero byte. This allows
|
||||
// allot to use the len to fill memory space to make
|
||||
// a copy
|
||||
func opGst(longOp bool, s *Stack) {
|
||||
start := s.PopLong()
|
||||
end := start
|
||||
for {
|
||||
if vm.Prog[end] == 0 {
|
||||
break
|
||||
}
|
||||
end++
|
||||
}
|
||||
for i := end; i >= start; i-- {
|
||||
s.Push(vm.Prog[i])
|
||||
}
|
||||
s.PushLong(uint16(end-start+1))
|
||||
}
|
||||
|
||||
func opGrt(longOp bool, s *Stack){
|
||||
if longOp {
|
||||
l := s.PopLong()
|
||||
|
|
Loading…
Reference in New Issue