ceremonyclient/bedlam/compiler/circuits/wire.go
Cassandra Heart e51992f3e8
OT
2025-03-23 21:11:16 -05:00

197 lines
3.9 KiB
Go

//
// Copyright (c) 2019-2024 Markku Rossi
//
// All rights reserved.
//
package circuits
import (
"fmt"
"math"
"source.quilibrium.com/quilibrium/monorepo/bedlam/circuit"
)
const (
// UnassignedID identifies an unassigned wire ID.
UnassignedID circuit.Wire = math.MaxUint32
outputMask = 0b10000000000000000000000000000000
valueMask = 0b01100000000000000000000000000000
numMask = 0b00011111111111111111111111111111
valueShift = 29
)
// Wire implements a wire connecting binary gates.
type Wire struct {
ovnum uint32
id circuit.Wire
// The gates[0] is the input gate, gates[1:] are the output gates.
gates []*Gate
}
// WireValue defines wire values.
type WireValue uint8
// Possible wire values.
const (
Unknown WireValue = iota
Zero
One
)
func (v WireValue) String() string {
switch v {
case Zero:
return "0"
case One:
return "1"
default:
return "?"
}
}
// Reset resets the wire with the new ID.
func (w *Wire) Reset(id circuit.Wire) {
w.SetOutput(false)
w.SetValue(Unknown)
w.SetID(id)
w.SetInput(nil)
w.DisconnectOutputs()
}
// ID returns the wire ID.
func (w *Wire) ID() circuit.Wire {
return w.id
}
// SetID sets the wire ID.
func (w *Wire) SetID(id circuit.Wire) {
w.id = id
}
// Assigned tests if the wire is assigned with an unique ID.
func (w *Wire) Assigned() bool {
return w.id != UnassignedID
}
// Output tests if the wire is an output wire.
func (w *Wire) Output() bool {
return w.ovnum&outputMask != 0
}
// SetOutput sets the wire output flag.
func (w *Wire) SetOutput(output bool) {
if output {
w.ovnum |= outputMask
} else {
w.ovnum &^= outputMask
}
}
// Value returns the wire value.
func (w *Wire) Value() WireValue {
return WireValue((w.ovnum & valueMask) >> valueShift)
}
// SetValue sets the wire value.
func (w *Wire) SetValue(value WireValue) {
w.ovnum &^= valueMask
w.ovnum |= (uint32(value) << valueShift) & valueMask
}
// NumOutputs returns the number of output gates assigned to the wire.
func (w *Wire) NumOutputs() uint32 {
return w.ovnum & numMask
}
// SetNumOutputs sets the number of output gates assigned to the wire.
func (w *Wire) SetNumOutputs(num uint32) {
if num > numMask {
panic("too big circuit, wire outputs overflow")
}
w.ovnum &^= numMask
w.ovnum |= num
}
// DisconnectOutputs disconnects wire from its output gates.
func (w *Wire) DisconnectOutputs() {
w.SetNumOutputs(0)
if len(w.gates) > 1 {
w.gates = w.gates[0:1]
}
}
func (w *Wire) String() string {
return fmt.Sprintf("Wire{%x, Input:%s, Value:%s, Outputs:%v, Output=%v}",
w.ID(), w.Input(), w.Value(), w.gates[1:], w.Output())
}
// Assign assings wire ID.
func (w *Wire) Assign(cc *Compiler) {
if w.Output() {
return
}
if !w.Assigned() {
w.id = cc.NextWireID()
}
w.ForEachOutput(func(gate *Gate) {
gate.Visit(cc)
})
}
// Input returns the wire's input gate.
func (w *Wire) Input() *Gate {
if len(w.gates) == 0 {
return nil
}
return w.gates[0]
}
// SetInput sets the wire's input gate.
func (w *Wire) SetInput(gate *Gate) {
if gate == nil {
if len(w.gates) > 0 {
w.gates[0] = nil
}
} else {
if len(w.gates) == 0 {
w.gates = append(w.gates, gate)
} else {
if w.gates[0] != nil {
panic("wire input gate already set")
}
w.gates[0] = gate
}
}
}
// IsInput tests if the wire is an input wire.
func (w *Wire) IsInput() bool {
return w.Input() == nil
}
// ForEachOutput calls the argument function for each output gate of
// the wire.
func (w *Wire) ForEachOutput(f func(gate *Gate)) {
if len(w.gates) > 1 {
for _, gate := range w.gates[1:] {
f(gate)
}
}
}
// AddOutput adds gate to the wire's output gates.
func (w *Wire) AddOutput(gate *Gate) {
if len(w.gates) == 0 {
w.gates = append(w.gates, nil)
}
w.gates = append(w.gates, gate)
w.SetNumOutputs(w.NumOutputs() + 1)
}
// RemoveOutput removes gate from the wire's output gates.
func (w *Wire) RemoveOutput(gate *Gate) {
w.SetNumOutputs(w.NumOutputs() - 1)
}