Data commit
This commit is contained in:
parent
7387c8f97b
commit
cb5bb5e222
199093 changed files with 3378972 additions and 0 deletions
268
Task/Execute-Computer-Zero/Go/execute-computer-zero.go
Normal file
268
Task/Execute-Computer-Zero/Go/execute-computer-zero.go
Normal file
|
|
@ -0,0 +1,268 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"io"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
const (
|
||||
NOP = iota
|
||||
LDA
|
||||
STA
|
||||
ADD
|
||||
SUB
|
||||
BRZ
|
||||
JMP
|
||||
STP
|
||||
)
|
||||
|
||||
var opcodes = map[string]int{
|
||||
"NOP": NOP,
|
||||
"LDA": LDA,
|
||||
"STA": STA,
|
||||
"ADD": ADD,
|
||||
"SUB": SUB,
|
||||
"BRZ": BRZ,
|
||||
"JMP": JMP,
|
||||
"STP": STP,
|
||||
}
|
||||
|
||||
var reIns = regexp.MustCompile(
|
||||
`\s*(?:(\w+):)?\s*` + // label
|
||||
`(NOP|LDA|STA|ADD|SUB|BRZ|JMP|STP)?\s*` + // opcode
|
||||
`(\w+)?\s*` + // argument
|
||||
`(?:;([\w\s]+))?`) // comment
|
||||
|
||||
type ByteCode [32]int
|
||||
|
||||
type instruction struct {
|
||||
Label string
|
||||
Opcode string
|
||||
Arg string
|
||||
}
|
||||
|
||||
type Program struct {
|
||||
Instructions []instruction
|
||||
Labels map[string]int
|
||||
}
|
||||
|
||||
func newInstruction(line string) (*instruction, error) {
|
||||
match := reIns.FindStringSubmatch(line)
|
||||
if match == nil {
|
||||
return nil, fmt.Errorf("syntax error: '%s'", line)
|
||||
}
|
||||
return &instruction{Label: match[1], Opcode: match[2], Arg: match[3]}, nil
|
||||
}
|
||||
|
||||
func Parse(asm io.Reader) (*Program, error) {
|
||||
var p Program
|
||||
p.Labels = make(map[string]int, 32)
|
||||
scanner := bufio.NewScanner(asm)
|
||||
lineNumber := 0
|
||||
|
||||
for scanner.Scan() {
|
||||
if instruction, err := newInstruction(scanner.Text()); err != nil {
|
||||
return &p, err
|
||||
} else {
|
||||
if instruction.Label != "" {
|
||||
p.Labels[instruction.Label] = lineNumber
|
||||
}
|
||||
p.Instructions = append(p.Instructions, *instruction)
|
||||
lineNumber++
|
||||
}
|
||||
}
|
||||
|
||||
if err := scanner.Err(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &p, nil
|
||||
}
|
||||
|
||||
func (p *Program) Compile() (ByteCode, error) {
|
||||
var bytecode ByteCode
|
||||
var arg int
|
||||
for i, ins := range p.Instructions {
|
||||
if ins.Arg == "" {
|
||||
arg = 0
|
||||
} else if addr, err := strconv.Atoi(ins.Arg); err == nil {
|
||||
arg = addr
|
||||
} else if addr, ok := p.Labels[ins.Arg]; ok {
|
||||
arg = addr
|
||||
} else {
|
||||
return bytecode, fmt.Errorf("unknown label %v", ins.Arg)
|
||||
}
|
||||
|
||||
if opcode, ok := opcodes[ins.Opcode]; ok {
|
||||
bytecode[i] = opcode<<5 | arg
|
||||
} else {
|
||||
bytecode[i] = arg
|
||||
}
|
||||
}
|
||||
return bytecode, nil
|
||||
}
|
||||
|
||||
func floorMod(a, b int) int {
|
||||
return ((a % b) + b) % b
|
||||
}
|
||||
|
||||
func Run(bytecode ByteCode) (int, error) {
|
||||
acc := 0
|
||||
pc := 0
|
||||
mem := bytecode
|
||||
|
||||
var op int
|
||||
var arg int
|
||||
|
||||
loop:
|
||||
for pc < 32 {
|
||||
op = mem[pc] >> 5
|
||||
arg = mem[pc] & 31
|
||||
pc++
|
||||
|
||||
switch op {
|
||||
case NOP:
|
||||
continue
|
||||
case LDA:
|
||||
acc = mem[arg]
|
||||
case STA:
|
||||
mem[arg] = acc
|
||||
case ADD:
|
||||
acc = floorMod(acc+mem[arg], 256)
|
||||
case SUB:
|
||||
acc = floorMod(acc-mem[arg], 256)
|
||||
case BRZ:
|
||||
if acc == 0 {
|
||||
pc = arg
|
||||
}
|
||||
case JMP:
|
||||
pc = arg
|
||||
case STP:
|
||||
break loop
|
||||
default:
|
||||
return acc, fmt.Errorf("runtime error: %v %v", op, arg)
|
||||
}
|
||||
}
|
||||
|
||||
return acc, nil
|
||||
}
|
||||
|
||||
func Execute(asm string) (int, error) {
|
||||
program, err := Parse(strings.NewReader(asm))
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("assembly error: %v", err)
|
||||
}
|
||||
|
||||
bytecode, err := program.Compile()
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("compilation error: %v", err)
|
||||
}
|
||||
|
||||
result, err := Run(bytecode)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func main() {
|
||||
examples := []string{
|
||||
`LDA x
|
||||
ADD y ; accumulator = x + y
|
||||
STP
|
||||
x: 2
|
||||
y: 2`,
|
||||
`loop: LDA prodt
|
||||
ADD x
|
||||
STA prodt
|
||||
LDA y
|
||||
SUB one
|
||||
STA y
|
||||
BRZ done
|
||||
JMP loop
|
||||
done: LDA prodt ; to display it
|
||||
STP
|
||||
x: 8
|
||||
y: 7
|
||||
prodt: 0
|
||||
one: 1`,
|
||||
`loop: LDA n
|
||||
STA temp
|
||||
ADD m
|
||||
STA n
|
||||
LDA temp
|
||||
STA m
|
||||
LDA count
|
||||
SUB one
|
||||
BRZ done
|
||||
STA count
|
||||
JMP loop
|
||||
done: LDA n ; to display it
|
||||
STP
|
||||
m: 1
|
||||
n: 1
|
||||
temp: 0
|
||||
count: 8 ; valid range: 1-11
|
||||
one: 1`,
|
||||
`start: LDA load
|
||||
ADD car ; head of list
|
||||
STA ldcar
|
||||
ADD one
|
||||
STA ldcdr ; next CONS cell
|
||||
ldcar: NOP
|
||||
STA value
|
||||
ldcdr: NOP
|
||||
BRZ done ; 0 stands for NIL
|
||||
STA car
|
||||
JMP start
|
||||
done: LDA value ; CAR of last CONS
|
||||
STP
|
||||
load: LDA 0
|
||||
value: 0
|
||||
car: 28
|
||||
one: 1
|
||||
; order of CONS cells
|
||||
; in memory
|
||||
; does not matter
|
||||
6
|
||||
0 ; 0 stands for NIL
|
||||
2 ; (CADR ls)
|
||||
26 ; (CDDR ls) -- etc.
|
||||
5
|
||||
20
|
||||
3
|
||||
30
|
||||
1 ; value of (CAR ls)
|
||||
22 ; points to (CDR ls)
|
||||
4
|
||||
24`,
|
||||
`LDA 3
|
||||
SUB 4
|
||||
STP 0
|
||||
0
|
||||
255`,
|
||||
`LDA 3
|
||||
SUB 4
|
||||
STP 0
|
||||
0
|
||||
1`,
|
||||
`LDA 3
|
||||
ADD 4
|
||||
STP 0
|
||||
1
|
||||
255`,
|
||||
}
|
||||
|
||||
for _, asm := range examples {
|
||||
if result, err := Execute(asm); err == nil {
|
||||
fmt.Println(result)
|
||||
} else {
|
||||
fmt.Println(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue