aboutsummaryrefslogtreecommitdiff
path: root/parse.go
blob: 97d1c24dee321bfaf39a677cf8420f1f8a762323 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
package j1

import "fmt"

// Decode instruction
func Decode(v uint16) Instruction {
	switch {
	case v&(1<<15) != 0:
		return newLit(v)
	case v&(7<<13) == 0:
		return newJump(v)
	case v&(7<<13) == 1<<13:
		return newCond(v)
	case v&(7<<13) == 1<<14:
		return newCall(v)
	case v&(7<<13) == 3<<13:
		return newALU(v)
	}
	return nil
}

// Instruction interface
type Instruction interface {
	isInstruction()
}

// Lit is a literal
type Lit uint16

func newLit(v uint16) Lit    { return Lit(v &^ uint16(1<<15)) }
func (v Lit) String() string { return fmt.Sprintf("LIT %0.4X", uint16(v)) }
func (v Lit) isInstruction() {}

// Jump is an unconditional branch
type Jump uint16

func newJump(v uint16) Jump   { return Jump(v &^ uint16(7<<13)) }
func (v Jump) String() string { return fmt.Sprintf("UBRANCH %0.4X", uint16(v<<1)) }
func (v Jump) isInstruction() {}

// Cond is a conditional branch
type Cond uint16

func newCond(v uint16) Cond   { return Cond(v &^ uint16(7<<13)) }
func (v Cond) String() string { return fmt.Sprintf("0BRANCH %0.4X", uint16(v<<1)) }
func (v Cond) isInstruction() {}

// Call procedure
type Call uint16

func newCall(v uint16) Call   { return Call(v &^ uint16(7<<13)) }
func (v Call) String() string { return fmt.Sprintf("CALL %0.4X", uint16(v<<1)) }
func (v Call) isInstruction() {}

// ALU instruction
type ALU struct {
	Opcode uint16
	RtoPC  bool
	TtoN   bool
	TtoR   bool
	NtoAtT bool
	Rdir   int8
	Ddir   int8
}

func newALU(v uint16) ALU {
	return ALU{
		Opcode: (v >> 8) & 15,
		RtoPC:  v&(1<<12) != 0,
		TtoN:   v&(1<<7) != 0,
		TtoR:   v&(1<<6) != 0,
		NtoAtT: v&(1<<5) != 0,
		Rdir:   expand((v >> 2) & 3),
		Ddir:   expand(v & 3),
	}
}

func (v ALU) isInstruction() {}

func expand(v uint16) int8 {
	if v&2 != 0 {
		v |= 0xfc
	}
	return int8(v)
}

var opcodes = []string{
	"T", "N", "T+N", "T&N", "T|N", "T^N", "~T", "N==T",
	"N<T", "N>>T", "T-1", "R", "[T]", "N<<T", "depth", "Nu<T",
}

func (v ALU) String() string {
	s := "ALU " + opcodes[v.Opcode]
	if v.RtoPC {
		s += " R→PC"
	}
	if v.TtoN {
		s += " T→N"
	}
	if v.TtoR {
		s += " T→R"
	}
	if v.NtoAtT {
		s += " N→[T]"
	}
	if v.Rdir != 0 {
		s += fmt.Sprintf(" r%+d", v.Rdir)
	}
	if v.Ddir != 0 {
		s += fmt.Sprintf(" d%+d", v.Ddir)
	}
	return s
}