-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmain.go
153 lines (143 loc) · 3.28 KB
/
main.go
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
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
package main
import (
"encoding/binary"
"fmt"
"io"
"math"
"os"
)
var (
// 8 registers
reg = make([]uint32, 8)
// execution finger
ef = uint32(0)
// collection of array of platters, init with 100 arrays
col = make([][]uint32, 10, 100)
// Create stack structure
stack = memStack{}
)
type memStack []uint32
func (s *memStack) isEmpty() bool {
return len(*s) == 0
}
func (s *memStack) push(x uint32) {
*s = append(*s, x)
}
func (s *memStack) pop() (uint32, error) {
if s.isEmpty() {
return 0, fmt.Errorf("stack is empty")
} else {
index := len(*s) - 1
element := (*s)[index]
*s = (*s)[:index]
return element, nil
}
}
func main() {
if len(os.Args) < 2 {
fmt.Println("You need to specify path to input program")
os.Exit(1)
}
data, err := os.ReadFile(os.Args[1])
if err != nil {
fmt.Println("Something went wrong while reading file!")
os.Exit(1)
}
// let's see what our data holds, and cast it to uint32 and change endian
col[0] = make([]uint32, len(data)/4)
for i := 0; i < len(col[0]); i++ {
col[0][i] = binary.BigEndian.Uint32(data[i*4 : (i+1)*4])
}
for {
instruction := col[0][ef]
// move instruction finger
ef++
// decode
opCode := instruction >> (32 - 4)
if opCode == 13 {
A := (instruction >> 25) & 0x7
// 0x 01 ff ff ff
// (1 << 25) - 1
reg[A] = instruction & 0x1ffffff
} else {
// Fetch register values from platter
A := (instruction >> 6) & 0x7
B := (instruction >> 3) & 0x7
C := (instruction >> 0) & 0x7
switch opCode {
case 0:
if reg[C] != 0 {
reg[A] = reg[B]
}
case 1:
reg[A] = col[reg[B]][reg[C]]
case 2:
col[reg[A]][reg[B]] = reg[C]
case 3:
// this won't overflow in golang
reg[A] = reg[B] + reg[C]
case 4:
reg[A] = reg[B] * reg[C]
case 5:
if reg[C] != 0 {
reg[A] = reg[B] / reg[C]
}
case 6:
reg[A] = ^(reg[B] & reg[C])
case 7:
os.Exit(0)
case 8:
// create empty array
emptyArr := make([]uint32, reg[C])
// pop from stack
sId, err := stack.pop()
if err != nil {
col = append(col, emptyArr)
reg[B] = uint32(len(col)) - 1
} else {
col[sId] = emptyArr
reg[B] = sId
}
case 9:
// Remove array from memory
col[reg[C]] = make([]uint32, 0)
// push array identifier on stack
stack.push(reg[C])
case 10:
// print ascii char
if reg[C] <= 255 {
// This was my first real "idk what is actually happening" problem
// Figuring out that fmt.Printf and terminal somehow additionaly encode data
// So I couldn't unpack codex.umz properly, but sandmark was passing and everything else
// was working as expected
// Thanks @ALPHA-60
os.Stdout.Write([]byte{byte(reg[C])})
} else {
fmt.Println("Printing char > 255. Exiting")
os.Exit(1)
}
case 11:
// Input from console
bRead := make([]byte, 1)
_, err := os.Stdin.Read(bRead)
if err == io.EOF {
// if we hit EOF, MaxUint32
reg[C] = math.MaxUint32
}
// else
reg[C] = uint32(bRead[0])
case 12:
// free array at 0 and create it to be of size col[reg[B]]
if reg[B] != 0 {
col[0] = make([]uint32, len(col[reg[B]]))
// copy array to col[0]
copy(col[0], col[reg[B]])
}
ef = reg[C]
default:
fmt.Println("Not in spec")
os.Exit(1)
}
}
}
}