-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
6 changed files
with
248 additions
and
16 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
pragma circom 2.1.0; | ||
|
||
include "./vm.circom" | ||
|
||
// MEM: memory size | ||
// LEN: code size | ||
// CLK: number of clock-cycles | ||
template Brainfuck(MEM, LEN, CLK) { | ||
signal input code[LEN]; | ||
|
||
component vm = VM(MEM); | ||
|
||
// reset pointers & memory | ||
vm.i <== 0; | ||
vm.p <== 0; | ||
|
||
// reset memory | ||
for (var i = 0; i < M; i++) { | ||
vm.m[i] <== 0; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
pragma circom 2.1.0; | ||
|
||
// Checks if two numbers are equal. | ||
// | ||
// Inputs: | ||
// - `in`: two numbers | ||
// | ||
// Outputs: | ||
// - `out`: 1 if `in[0] == in[1]`, 0 otherwise | ||
template IsEqual() { | ||
signal input in[2]; | ||
signal output {bool} out; | ||
|
||
out <== IsZero()(in[1] - in[0]); | ||
} | ||
|
||
// Checks if a number is zero. | ||
// | ||
// Inputs: | ||
// - `in`: a number | ||
// | ||
// Outputs: | ||
// - `out`: 1 if `in == 0`, 0 otherwise | ||
template IsZero() { | ||
signal input in; | ||
signal output {bool} out; | ||
|
||
signal inv <-- in != 0 ? (1 / in) : 0; | ||
|
||
out <== (-in * inv) + 1; | ||
in * out === 0; | ||
} | ||
|
||
// If-else branching. | ||
// | ||
// Inputs: | ||
// - `cond`: a boolean condition | ||
// - `ifTrue`: signal to be returned if condition is true | ||
// - `ifFalse`: signal to be returned if condition is false | ||
// | ||
// Outputs: | ||
// - `out`: equals `cond ? ifTrue : ifFalse` | ||
template IfElse() { | ||
signal input {bool} cond; | ||
signal input ifTrue; | ||
signal input ifFalse; | ||
signal output out; | ||
|
||
out <== cond * (ifTrue - ifFalse) + ifFalse; | ||
} | ||
|
||
// Swaps in[0] ~ in[1] if `cond` is true. | ||
// | ||
// Inputs: | ||
// - `cond`: a boolean condition | ||
// - `in`: two numbers | ||
// | ||
// Outputs: | ||
// - `out`: two numbers either swapped or not | ||
template Swap() { | ||
signal input {bool} cond; | ||
signal input in[2]; | ||
signal output out[2]; | ||
|
||
out[0] <== cond * (in[1] - in[0]) + in[0]; | ||
out[1] <== cond * (in[0] - in[1]) + in[1]; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,23 +1,17 @@ | ||
pragma circom 2.0.0; | ||
pragma circom 2.1.0; | ||
|
||
template Brainfuck(SIZE) { | ||
component vm = VM(SIZE); | ||
vm.i <== 0; | ||
vm.p <== 0; | ||
for (var i = 0; i < SIZE; i++) { | ||
vm.m[i] <== 0; | ||
} | ||
} | ||
|
||
template VM(SIZE) { | ||
template VM(MEM) { | ||
// previous state | ||
signal input i; | ||
signal input p; | ||
signal input m[SIZE]; | ||
signal input m[MEM]; | ||
|
||
// next state | ||
signal output _i; | ||
signal output _p; | ||
signal output _m[SIZE]; | ||
signal output _m[MEM]; | ||
|
||
// todo... | ||
|
||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
module vm | ||
|
||
go 1.20 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,133 @@ | ||
package main | ||
|
||
import ( | ||
"errors" | ||
"fmt" | ||
"log" | ||
) | ||
|
||
const MEM_SIZE = 126 | ||
const MAX_CLOCKS = 1 << 16 | ||
|
||
type MEM_TYPE = uint32 | ||
type OP_TYPE = uint32 | ||
|
||
const ( | ||
OP_INC_PTR = OP_TYPE(62) | ||
OP_DEC_PTR = OP_TYPE(60) | ||
OP_INC_MEM = OP_TYPE(43) | ||
OP_DEC_MEM = OP_TYPE(45) | ||
OP_INPUT = OP_TYPE(44) | ||
OP_OUTPUT = OP_TYPE(46) | ||
) | ||
|
||
// Compiles the brainfuck program. | ||
func compile(instructions string) ([]OP_TYPE, error) { | ||
code := make([]OP_TYPE, len(instructions)) | ||
for i, c := range instructions { | ||
switch c { | ||
case '>': | ||
code[i] = OP_INC_PTR | ||
case '<': | ||
code[i] = OP_DEC_PTR | ||
case '+': | ||
code[i] = OP_INC_MEM | ||
case '-': | ||
code[i] = OP_DEC_MEM | ||
case '.': | ||
code[i] = OP_INPUT | ||
case ',': | ||
code[i] = OP_OUTPUT | ||
case '[': | ||
j := i + 1 // j will point to the matching ] | ||
for ctr := 1; j < len(instructions); j++ { | ||
if instructions[j] == ']' { | ||
ctr-- | ||
if ctr == 0 { | ||
break | ||
} | ||
} else if instructions[j] == '[' { | ||
ctr++ | ||
} | ||
} | ||
|
||
if j < len(instructions) { | ||
code[i], code[j] = uint32(j)+1, uint32(i) | ||
} else { | ||
return nil, errors.New("missing ]") | ||
} | ||
case ']': | ||
if instructions[code[i]] != '[' { | ||
return nil, errors.New("missing [") | ||
} | ||
default: | ||
// ignore all else | ||
} | ||
} | ||
|
||
return code, nil | ||
} | ||
|
||
func run(code []OP_TYPE) error { | ||
clk := 0 // clock | ||
i := 0 // instruction pointer | ||
p := 0 // memory pointer | ||
mem := make([]MEM_TYPE, MEM_SIZE) // memory | ||
|
||
for ; clk < MAX_CLOCKS && i < len(code); clk++ { | ||
// execute code | ||
c := code[i] | ||
switch c { | ||
case OP_INC_PTR: | ||
if p == MEM_SIZE-1 { | ||
return errors.New("memory pointer overflow") | ||
} | ||
p++ | ||
i++ | ||
case OP_DEC_PTR: | ||
if p == 0 { | ||
return errors.New("memory pointer underflow") | ||
} | ||
p-- | ||
i++ | ||
|
||
case OP_INC_MEM: | ||
mem[p]++ | ||
i++ | ||
case OP_DEC_MEM: | ||
mem[p]-- | ||
i++ | ||
default: | ||
// TODO | ||
if mem[p] == 0 { | ||
|
||
} else { | ||
|
||
} | ||
|
||
} | ||
|
||
if i >= len(code) { | ||
return errors.New("instruction pointer overflow") | ||
} | ||
|
||
} | ||
|
||
if clk == MAX_CLOCKS { | ||
return errors.New("maximum clock cycles reached") | ||
} | ||
} | ||
|
||
func main() { | ||
instructions := "++[-[]++]" | ||
|
||
// compile code | ||
feltcode, err := compile(instructions) | ||
if err != nil { | ||
log.Fatal(err) | ||
} | ||
fmt.Println(feltcode) | ||
|
||
// execute | ||
|
||
} |