Skip to content

Commit

Permalink
General fixes and improvements
Browse files Browse the repository at this point in the history
  • Loading branch information
rodrigo-pino committed Aug 8, 2023
1 parent a32e9a8 commit 9cd63b6
Show file tree
Hide file tree
Showing 3 changed files with 71 additions and 23 deletions.
59 changes: 48 additions & 11 deletions pkg/vm/memory/memory.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,23 +6,40 @@ import (
f "github.com/consensys/gnark-crypto/ecc/stark-curve/fp"
)

const (
programSegment = iota
executionSegment
userSegment
)

// Represents a write-once Memory Cell
type Cell struct {
Value *MemoryValue
Accessed bool
}

type Segment struct {
Data map[f.Element]Cell
Data []Cell
}

func EmptySegment() *Segment {
return &Segment{
Data: make([]Cell, 0),
}
}

func EmptySegment() Segment {
func EmptySegmentWithCapacity(capacity int) Segment {
return Segment{
Data: make(map[f.Element]Cell),
Data: make([]Cell, 0, capacity),
}
}

func (segment *Segment) Write(index f.Element, value *MemoryValue) error {
func EmptySegmentWithLength(length int) Segment {
return Segment{
Data: make([]Cell, length),
}
}
func (segment *Segment) Write(index uint64, value *MemoryValue) error {
cell := segment.Data[index]
if cell.Accessed {
return fmt.Errorf("rewriting cell at %d, old value: %d new value: %d", index, &cell.Value, &value)
Expand All @@ -32,7 +49,7 @@ func (segment *Segment) Write(index f.Element, value *MemoryValue) error {
return nil
}

func (segment *Segment) Read(index f.Element) *MemoryValue {
func (segment *Segment) Read(index uint64) *MemoryValue {
cell := segment.Data[index]
cell.Accessed = true
return cell.Value
Expand All @@ -41,17 +58,30 @@ func (segment *Segment) Read(index f.Element) *MemoryValue {
// todo(rodro): Check out temprary segments
// Represents the whole VM memory divided into segments
type Memory struct {
Segments []Segment
Segments []*Segment
}

// todo(rodro): can the amount of segments be known before hand?
func InitializeEmptyMemory() Memory {
return Memory{
func InitializeEmptyMemory() *Memory {
return &Memory{
// size 4 should be enough for the minimum amount of segments
Segments: make([]Segment, 4),
Segments: make([]*Segment, 4),
}
}

func (memory *Memory) LoadBytecode(bytecode *[]f.Element) error {
bytecodeSegment := EmptySegmentWithLength(len(*bytecode))
for i := range *bytecode {
memVal := MemoryValueFromFieldElement(&(*bytecode)[i])
err := bytecodeSegment.Write(uint64(i), memVal)
if err != nil {
return fmt.Errorf("cannot load bytecode: %w", err)
}
}
memory.Segments[programSegment] = &bytecodeSegment
return nil
}

// Allocates a new segment and returns its index
func (memory *Memory) AllocateNewSegment() int {
memory.Segments = append(memory.Segments, EmptySegment())
Expand All @@ -62,13 +92,20 @@ func (memory *Memory) Write(address *MemoryAddress, value *MemoryValue) error {
if address.SegmentIndex > uint64(len(memory.Segments)) {
return fmt.Errorf("writing to unallocated segment %d", address.SegmentIndex)
}
if !address.Offset.IsUint64() {
return fmt.Errorf("writing index is too big: %s", address.Offset.String())
}

return memory.Segments[address.SegmentIndex].Write(*address.Offset, value)
return memory.Segments[address.SegmentIndex].Write(address.Offset.Uint64(), value)
}

func (memory *Memory) Read(address *MemoryAddress) (*MemoryValue, error) {
if address.SegmentIndex > uint64(len(memory.Segments)) {
return nil, fmt.Errorf("reading from unallocated segment %d", address.SegmentIndex)
}
return memory.Segments[address.SegmentIndex].Read(*address.Offset), nil
if !address.Offset.IsUint64() {
return nil, fmt.Errorf("reading index is too big: %s", address.Offset.String())
}

return memory.Segments[address.SegmentIndex].Read(address.Offset.Uint64()), nil
}
20 changes: 12 additions & 8 deletions pkg/vm/memory/memory_segment.go
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
package memory

import (
"fmt"

f "github.com/consensys/gnark-crypto/ecc/stark-curve/fp"
)

type MemoryManager struct {
Memory Memory
Memory *Memory
// where the program byte code is stored
// ProgramSegment *MemorySegment
//// stores the function callstack (fp, ap, local variables)
Expand All @@ -16,13 +18,15 @@ type MemoryManager struct {
// BuiltinSegments *[]MemorySegment
}

func CreateMemoryManager(programBytecode *[]f.Element) MemoryManager {
// memory := InitializeEmptyMemory()
func CreateMemoryManager(programBytecode *[]f.Element) (*MemoryManager, error) {
memory := InitializeEmptyMemory()

return MemoryManager{
//ProgramSegment: &MemorySegment{Cells: *programBytecode},
//ExecutionSegment: nil,
//UserSegment: nil,
//BuiltinSegments: nil,
err := memory.LoadBytecode(programBytecode)
if err != nil {
return nil, fmt.Errorf("error creating MemoryManager: %w", err)
}

return &MemoryManager{
Memory: memory,
}, nil
}
15 changes: 11 additions & 4 deletions pkg/vm/vm.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package vm

import (
"fmt"

mem "github.com/NethermindEth/cairo-vm-go/pkg/vm/memory"
f "github.com/consensys/gnark-crypto/ecc/stark-curve/fp"
)
Expand All @@ -19,17 +21,22 @@ type VirtualMachineConfig struct {

type VirtualMachine struct {
Context Context
MemoryManager mem.MemoryManager
MemoryManager *mem.MemoryManager
Config VirtualMachineConfig
}

// NewVirtualMachine creates a VM from the program bytecode using a specified config.
func NewVirtualMachine(programBytecode *[]f.Element, config VirtualMachineConfig) *VirtualMachine {
func NewVirtualMachine(programBytecode *[]f.Element, config VirtualMachineConfig) (*VirtualMachine, error) {
manager, err := mem.CreateMemoryManager(programBytecode)
if err != nil {
return nil, fmt.Errorf("error creating new virtual machine: %w", err)
}

return &VirtualMachine{
Context{Fp: 0, Ap: 0, Pc: 0},
mem.CreateMemoryManager(programBytecode),
manager,
config,
}
}, nil
}

// RunInstructionFrom executes the program starting at the specified Program Counter.
Expand Down

0 comments on commit 9cd63b6

Please sign in to comment.