aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDimitri Sokolyuk <demon@dim13.org>2018-01-15 00:06:40 +0100
committerDimitri Sokolyuk <demon@dim13.org>2018-01-15 00:06:40 +0100
commit4f07f821e0d04e0cb6ec62d1d5bc3999dd7ba89a (patch)
tree27b6e1124b247769b6650544f19cdd925285bd80
parent8a566444c4e3e75977bbb1629891b3fe594c3069 (diff)
use context for cancelation
-rw-r--r--console.go56
-rw-r--r--eval.go66
2 files changed, 71 insertions, 51 deletions
diff --git a/console.go b/console.go
index 5c63fbb..3b15a48 100644
--- a/console.go
+++ b/console.go
@@ -1,15 +1,61 @@
package j1
import (
+ "context"
+ "fmt"
"io"
"os"
)
-type Console struct {
- io.Reader
- io.Writer
+type console struct {
+ r io.Reader
+ w io.Writer
+ ich, och chan uint16
}
-func NewConsole() *Console {
- return &Console{Reader: os.Stdin, Writer: os.Stdout}
+func NewConsole(ctx context.Context) *console {
+ c := &console{
+ r: os.Stdin,
+ w: os.Stdout,
+ ich: make(chan uint16, 1),
+ och: make(chan uint16, 1),
+ }
+ go c.read(ctx)
+ go c.write(ctx)
+ return c
+}
+
+func (c *console) read(ctx context.Context) {
+ var v uint16
+ for {
+ fmt.Fscanf(c.r, "%c", &v)
+ select {
+ case <-ctx.Done():
+ return
+ case c.ich <- v:
+ }
+ }
+}
+
+func (c *console) write(ctx context.Context) {
+ for {
+ select {
+ case <-ctx.Done():
+ return
+ case v := <-c.och:
+ fmt.Fprintf(c.w, "%c", v)
+ }
+ }
+}
+
+func (c *console) Read() uint16 {
+ return <-c.ich
+}
+
+func (c *console) Write(v uint16) {
+ c.och <- v
+}
+
+func (c *console) Len() uint16 {
+ return uint16(len(c.ich))
}
diff --git a/eval.go b/eval.go
index b40af46..b22012f 100644
--- a/eval.go
+++ b/eval.go
@@ -2,14 +2,20 @@ package j1
import (
"bytes"
+ "context"
"encoding/binary"
"fmt"
- "io"
"io/ioutil"
)
const memSize = 0x4000
+type Console interface {
+ Read() uint16
+ Write(uint16)
+ Len() uint16
+}
+
// J1 Forth processor VM
type J1 struct {
memory [memSize]uint16 // 0..0x3fff main memory, 0x4000 .. 0x7fff mem-mapped i/o
@@ -17,18 +23,12 @@ type J1 struct {
st0 uint16 // top of data stack
d stack
r stack
- console io.ReadWriter
- done chan struct{}
- in, out chan uint16
+ console Console
+ cancel context.CancelFunc
}
func New() *J1 {
- return &J1{
- console: NewConsole(),
- done: make(chan struct{}),
- in: make(chan uint16, 1),
- out: make(chan uint16, 1),
- }
+ return new(J1)
}
// Reset VM
@@ -54,33 +54,14 @@ func (j1 *J1) LoadFile(fname string) error {
return j1.LoadBytes(data)
}
-func (j1 *J1) read() {
- var b uint16
- for {
- fmt.Fscanf(j1.console, "%c", &b)
- select {
- case <-j1.done:
- return
- case j1.in <- b:
- }
- }
-}
-
-func (j1 *J1) write() {
- for {
- select {
- case <-j1.done:
- return
- case b := <-j1.out:
- fmt.Fprintf(j1.console, "%c", b)
- }
- }
-}
-
-func (j1 *J1) run() {
+// Run evaluates content of memory
+func (j1 *J1) Run() {
+ ctx, cancel := context.WithCancel(context.Background())
+ j1.console = NewConsole(ctx)
+ j1.cancel = cancel
for {
select {
- case <-j1.done:
+ case <-ctx.Done():
return
default:
ins := Decode(j1.memory[j1.pc])
@@ -90,13 +71,6 @@ func (j1 *J1) run() {
}
}
-// Run evaluates content of memory
-func (j1 *J1) Run() {
- go j1.read()
- go j1.write()
- j1.run()
-}
-
func (j1 *J1) String() string {
s := fmt.Sprintf("\tPC=%0.4X ST=%0.4X\n", j1.pc, j1.st0)
s += fmt.Sprintf("\tD=%0.4X\n", j1.d.dump())
@@ -110,9 +84,9 @@ func (j1 *J1) writeAt(addr, value uint16) {
}
switch addr {
case 0xf000: // key
- j1.out <- value
+ j1.console.Write(value)
case 0xf002: // bye
- close(j1.done)
+ j1.cancel()
}
}
@@ -122,9 +96,9 @@ func (j1 *J1) readAt(addr uint16) uint16 {
}
switch addr {
case 0xf000: // tx!
- return <-j1.in
+ return j1.console.Read()
case 0xf001: // ?rx
- return uint16(len(j1.in))
+ return j1.console.Len()
}
return 0
}