diff --git a/PolkaVM/Sources/PolkaVM/Instructions.swift b/PolkaVM/Sources/PolkaVM/Instructions.swift index e5241120..166eff37 100644 --- a/PolkaVM/Sources/PolkaVM/Instructions.swift +++ b/PolkaVM/Sources/PolkaVM/Instructions.swift @@ -187,7 +187,7 @@ public enum Instructions { public let offset: UInt32 public init(data: Data) throws { - register = try Registers.Index(data.at(relative: 0)) + register = try Registers.Index(ra: data.at(relative: 0)) offset = try Instructions.decodeImmediate(data.at(relative: 1...)) } @@ -207,7 +207,7 @@ public enum Instructions { public let value: UInt32 public init(data: Data) throws { - register = try Registers.Index(data.at(relative: 0)) + register = try Registers.Index(ra: data.at(relative: 0)) value = try Instructions.decodeImmediate(data.at(relative: 1...)) } @@ -224,7 +224,7 @@ public enum Instructions { public let address: UInt32 public init(data: Data) throws { - register = try Registers.Index(data.at(relative: 0)) + register = try Registers.Index(ra: data.at(relative: 0)) address = try Instructions.decodeImmediate(data.at(relative: 1...)) } @@ -242,7 +242,7 @@ public enum Instructions { public let address: UInt32 public init(data: Data) throws { - register = try Registers.Index(data.at(relative: 0)) + register = try Registers.Index(ra: data.at(relative: 0)) address = try Instructions.decodeImmediate(data.at(relative: 1...)) } @@ -260,7 +260,7 @@ public enum Instructions { public let address: UInt32 public init(data: Data) throws { - register = try Registers.Index(data.at(relative: 0)) + register = try Registers.Index(ra: data.at(relative: 0)) address = try Instructions.decodeImmediate(data.at(relative: 1...)) } @@ -281,7 +281,7 @@ public enum Instructions { public let address: UInt32 public init(data: Data) throws { - register = try Registers.Index(data.at(relative: 0)) + register = try Registers.Index(ra: data.at(relative: 0)) address = try Instructions.decodeImmediate(data.at(relative: 1...)) } @@ -302,7 +302,7 @@ public enum Instructions { public let address: UInt32 public init(data: Data) throws { - register = try Registers.Index(data.at(relative: 0)) + register = try Registers.Index(ra: data.at(relative: 0)) address = try Instructions.decodeImmediate(data.at(relative: 1...)) } @@ -323,7 +323,7 @@ public enum Instructions { public let address: UInt32 public init(data: Data) throws { - register = try Registers.Index(data.at(relative: 0)) + register = try Registers.Index(ra: data.at(relative: 0)) address = try Instructions.decodeImmediate(data.at(relative: 1...)) } @@ -341,7 +341,7 @@ public enum Instructions { public let address: UInt32 public init(data: Data) throws { - register = try Registers.Index(data.at(relative: 0)) + register = try Registers.Index(ra: data.at(relative: 0)) address = try Instructions.decodeImmediate(data.at(relative: 1...)) } @@ -359,7 +359,7 @@ public enum Instructions { public let address: UInt32 public init(data: Data) throws { - register = try Registers.Index(data.at(relative: 0)) + register = try Registers.Index(ra: data.at(relative: 0)) address = try Instructions.decodeImmediate(data.at(relative: 1...)) } @@ -380,7 +380,7 @@ public enum Instructions { public let value: UInt8 public init(data: Data) throws { - register = try Registers.Index(data.at(relative: 0)) + register = try Registers.Index(ra: data.at(relative: 0)) let (x, y) = try Instructions.decodeImmediate2(data, divideBy: 16) address = x value = UInt8(truncatingIfNeeded: y) @@ -400,7 +400,7 @@ public enum Instructions { public let value: UInt16 public init(data: Data) throws { - register = try Registers.Index(data.at(relative: 0)) + register = try Registers.Index(ra: data.at(relative: 0)) let (x, y) = try Instructions.decodeImmediate2(data, divideBy: 16) address = x value = UInt16(truncatingIfNeeded: y) @@ -420,7 +420,7 @@ public enum Instructions { public let value: UInt32 public init(data: Data) throws { - register = try Registers.Index(data.at(relative: 0)) + register = try Registers.Index(ra: data.at(relative: 0)) let (x, y) = try Instructions.decodeImmediate2(data, divideBy: 16) address = x value = y @@ -442,7 +442,7 @@ public enum Instructions { public let offset: UInt32 public init(data: Data) throws { - register = try Registers.Index(data.at(relative: 0)) + register = try Registers.Index(ra: data.at(relative: 0)) (value, offset) = try Instructions.decodeImmediate2(data, divideBy: 16) } @@ -559,6 +559,45 @@ public enum Instructions { var offset: UInt32 public init(data: Data) throws { (register, value, offset) = try Self.parse(data: data) } } + + // MARK: Instructions with Arguments of Two Registers (5.8) + + public struct MoveReg: Instruction { + public static var opcode: UInt8 { 82 } + + public let src: Registers.Index + public let dest: Registers.Index + + public init(data: Data) throws { + dest = try Registers.Index(ra: data.at(relative: 0)) + src = try Registers.Index(rb: data.at(relative: 0)) + } + + public func _executeImpl(state: VMState) -> ExecOutcome { + state.writeRegister(dest, state.readRegister(src)) + return .continued + } + } + + public struct Sbrk: Instruction { + public static var opcode: UInt8 { 87 } + + public let src: Registers.Index + public let dest: Registers.Index + + public init(data: Data) throws { + dest = try Registers.Index(ra: data.at(relative: 0)) + src = try Registers.Index(rb: data.at(relative: 0)) + } + + public func _executeImpl(state: VMState) throws -> ExecOutcome { + let increment = state.readRegister(src) + let startAddr = try state.sbrk(increment) + state.writeRegister(dest, startAddr) + + return .continued + } + } } // MARK: Branch Helpers @@ -584,7 +623,7 @@ protocol BranchInstructionBase: Instruction { extension BranchInstructionBase { public static func parse(data: Data) throws -> (Registers.Index, UInt32, UInt32) { - let register = try Registers.Index(data.at(relative: 0)) + let register = try Registers.Index(ra: data.at(relative: 0)) let (value, offset) = try Instructions.decodeImmediate2(data, divideBy: 16) return (register, value, offset) } diff --git a/PolkaVM/Sources/PolkaVM/Memory.swift b/PolkaVM/Sources/PolkaVM/Memory.swift index 41a5ee54..1871ef31 100644 --- a/PolkaVM/Sources/PolkaVM/Memory.swift +++ b/PolkaVM/Sources/PolkaVM/Memory.swift @@ -4,6 +4,7 @@ public class Memory { public enum Error: Swift.Error { case pageFault(UInt32) case notWritable(UInt32) + case outOfMemory(UInt32) public var address: UInt32 { switch self { @@ -11,6 +12,8 @@ public class Memory { address case let .notWritable(address): address + case let .outOfMemory(address): + address } } } @@ -129,6 +132,27 @@ public class Memory { } throw Error.notWritable(address) } + + public func sbrk(_ increment: UInt32) throws -> UInt32 { + // TODO: update after memory layout details are implemented + var curHeapEnd: UInt32 = 0 + + if let lastChunk = chunks.last { + curHeapEnd = lastChunk.address + UInt32(lastChunk.data.count) + } + + for page in pageMap { + let pageEnd = page.address + page.length + if page.writable, curHeapEnd >= page.address, curHeapEnd + increment < pageEnd { + let newChunk = (address: curHeapEnd, data: Data(repeating: 0, count: Int(increment))) + chunks.append(newChunk) + + return curHeapEnd + } + } + + throw Error.outOfMemory(curHeapEnd) + } } extension Memory { diff --git a/PolkaVM/Sources/PolkaVM/Registers.swift b/PolkaVM/Sources/PolkaVM/Registers.swift index 8ea35a29..dd9a047f 100644 --- a/PolkaVM/Sources/PolkaVM/Registers.swift +++ b/PolkaVM/Sources/PolkaVM/Registers.swift @@ -1,8 +1,12 @@ public struct Registers: Equatable { public struct Index { public let value: UInt8 - public init(_ value: UInt8) { - self.value = min(value & 0b1111, 12) + public init(ra: UInt8) { + value = min(ra & 0b1111, 12) + } + + public init(rb: UInt8) { + value = min(rb >> 4, 12) } } diff --git a/PolkaVM/Sources/PolkaVM/VMState.swift b/PolkaVM/Sources/PolkaVM/VMState.swift index 646c73e8..01d68aa1 100644 --- a/PolkaVM/Sources/PolkaVM/VMState.swift +++ b/PolkaVM/Sources/PolkaVM/VMState.swift @@ -45,6 +45,10 @@ public class VMState { try memory.write(address: address, values: values) } + public func sbrk(_ increment: UInt32) throws -> UInt32 { + try memory.sbrk(increment) + } + public func consumeGas(_ amount: UInt64) { // TODO: use saturating subtraction gas -= Int64(amount)