Skip to content

Commit

Permalink
feat: Add an initial memory layout (#11)
Browse files Browse the repository at this point in the history
* Relocate memory script to its own dir

* Rename Relocatable to MemoryAddress

* Revamped relocatable code

* Improve memory segment management

* Remove printlns

* Rename scripts: relocatable -> memory_value

* General fixes and improvements

* Change memory address and value logic

Changed MemoryAddress offset from felt to uint64, this caused that the
current implementation of MemoryValue made no sense, so it was updated
as well to include a pointer its two possible data types:

- a field element
- a memory address

* Readability improvements

* renamed: memory_segment.go -> memory_manager.go

* Add function descriptions

* Add felt X felt arithmetic ops for memory values
  • Loading branch information
rodrigo-pino authored Aug 11, 2023
1 parent 366d700 commit b6572d4
Show file tree
Hide file tree
Showing 10 changed files with 585 additions and 271 deletions.
2 changes: 1 addition & 1 deletion pkg/vm/instruction.go
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ func DecodeInstruction(rawInstruction *f.Element) (*Instruction, error) {
}
off0Enc, off1Enc, off2Enc, flags := decodeInstructionValues(rawInstruction.Uint64())

// Create empty struction
// Create empty instruction
instruction := new(Instruction)

// Add unsigned offsets as signed ones
Expand Down
31 changes: 0 additions & 31 deletions pkg/vm/memory.go

This file was deleted.

108 changes: 108 additions & 0 deletions pkg/vm/memory/memory.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
package memory

import (
"fmt"

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

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

type Segment struct {
Data []Cell
}

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

func EmptySegmentWithCapacity(capacity int) Segment {
return Segment{
Data: make([]Cell, 0, capacity),
}
}

func EmptySegmentWithLength(length int) Segment {
return Segment{
Data: make([]Cell, length),
}
}

// Writes a new memory value to a specified offset, errors in case of overwriting an existing cell
func (segment *Segment) Write(offset uint64, value *MemoryValue) error {
cell := segment.Data[offset]
if cell.Accessed {
return fmt.Errorf("rewriting cell at %d, old value: %d new value: %d", offset, &cell.Value, &value)
}
cell.Accessed = true
cell.Value = value
return nil
}

// Reads a memory value from a specified offset at the segment
func (segment *Segment) Read(offset uint64) *MemoryValue {
cell := segment.Data[offset]
cell.Accessed = true
return cell.Value
}

// todo(rodro): Check out temprary segments
// Represents the whole VM memory divided into segments
type Memory struct {
Segments []*Segment
}

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

// Allocates a new segment providing its initial data and returns its index
func (memory *Memory) AllocateSegment(data *[]f.Element) (int, error) {
newSegment := EmptySegmentWithLength(len(*data))
for i := range *data {
memVal := MemoryValueFromFieldElement(&(*data)[i])
err := newSegment.Write(uint64(i), memVal)
if err != nil {
return 0, fmt.Errorf("cannot allocate new segment: %w", err)
}
}
memory.Segments = append(memory.Segments, &newSegment)
return len(memory.Segments), nil
}

// Allocates an empty segment and returns its index
func (memory *Memory) AllocateEmptySegment() int {
memory.Segments = append(memory.Segments, EmptySegment())
return len(memory.Segments) - 1
}

// Writes to a memory address a new memory value. Errors if writing to an unallocated
// space or if rewriting a specific cell
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)
}

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

// Reads a memory value from a memory address. Errors if reading from an unallocated
// space. If reading a cell which hasn't been accesed before, it is initalized with
// its default zero 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
}
13 changes: 13 additions & 0 deletions pkg/vm/memory/memory_manager.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package memory

type MemoryManager struct {
Memory *Memory
}

func CreateMemoryManager() (*MemoryManager, error) {
memory := InitializeEmptyMemory()

return &MemoryManager{
Memory: memory,
}, nil
}
Loading

0 comments on commit b6572d4

Please sign in to comment.