Added eeprom.getData/setData for mutable persistent bios storage, replaces get/setBootAddress.

get/setData is wrapped by the default Lua bios into functions with these names to avoid breaking programs using them.
This commit is contained in:
Florian Nücke 2015-02-04 16:48:57 +01:00
parent 9e92ee508c
commit 2ac78463a1
8 changed files with 46 additions and 64 deletions

View File

@ -36,20 +36,6 @@ public interface Machine extends ManagedEnvironment, Context {
*/
Architecture architecture();
/**
* Get the address of the file system component from which to try to boot.
* <p/>
* The underlying architecture may choose to ignore this setting.
*/
String getBootAddress();
/**
* Set the address of the file system component from which to try to boot.
*
* @param value the new address to try to boot from.
*/
void setBootAddress(String value);
/**
* The list of components attached to this machine.
* <p/>

View File

@ -146,6 +146,9 @@ opencomputers {
# The maximum size of the byte array that can be stored on EEPROMs.
eepromSize: 4096
# The maximum size of the byte array that can be stored on EEPROMs.
eepromDataSize: 256
# The number of components the different CPU tiers support. This list
# must contain exactly three entries, or it will be ignored.
cpuComponentCount: [

View File

@ -1,11 +1,22 @@
local component_invoke = component.invoke
function boot_invoke(address, method, ...)
local result = table.pack(pcall(component.invoke, address, method, ...))
local result = table.pack(pcall(component_invoke, address, method, ...))
if not result[1] then
return nil, result[2]
else
return table.unpack(result, 2, result.n)
end
end
-- backwards compatibility, may remove later
local eeprom = component.list("eeprom")()
computer.getBootAddress = function()
return boot_invoke(eeprom, "getData")
end
computer.setBootAddress = function(address)
return boot_invoke(eeprom, "setData", address)
end
do
local screen = component.list("screen")()
local gpu = component.list("gpu")()
@ -27,7 +38,7 @@ local function tryLoadFrom(address)
buffer = buffer .. (data or "")
until not data
boot_invoke(address, "close", handle)
return load(buffer, "=init", "t", sandbox)
return load(buffer, "=init")
end
local init, reason
if computer.getBootAddress() then

View File

@ -58,6 +58,7 @@ class Settings(val config: Config) {
val timeout = config.getDouble("computer.timeout") max 0
val startupDelay = config.getDouble("computer.startupDelay") max 0.05
val eepromSize = config.getInt("computer.eepromSize") max 0
val eepromDataSize = config.getInt("computer.eepromDataSize") max 0
val cpuComponentSupport = Array(config.getIntList("computer.cpuComponentCount"): _*) match {
case Array(tier1, tier2, tier3) =>
Array(tier1: Int, tier2: Int, tier3: Int)

View File

@ -16,18 +16,20 @@ class EEPROM extends prefab.ManagedEnvironment {
withConnector().
create()
var data = Array.empty[Byte]
var codeData = Array.empty[Byte]
var volatileData = Array.empty[Byte]
var readonly = false
var label = "EEPROM"
def checksum = Hashing.crc32().hashBytes(data).toString
def checksum = Hashing.crc32().hashBytes(codeData).toString
// ----------------------------------------------------------------------- //
@Callback(direct = true, doc = """function():string -- Get the currently stored byte array.""")
def get(context: Context, args: Arguments): Array[AnyRef] = result(data)
def get(context: Context, args: Arguments): Array[AnyRef] = result(codeData)
@Callback(doc = """function(data:string) -- Overwrite the currently stored byte array.""")
def set(context: Context, args: Arguments): Array[AnyRef] = {
@ -37,9 +39,9 @@ class EEPROM extends prefab.ManagedEnvironment {
if (!node.tryChangeBuffer(-Settings.get.eepromWriteCost)) {
return result(Unit, "not enough energy")
}
val newData = args.checkByteArray(0)
val newData = args.optByteArray(0, Array.empty)
if (newData.length > Settings.get.eepromSize) throw new IllegalArgumentException("not enough space")
data = newData
codeData = newData
context.pause(2) // deliberately slow to discourage use as normal storage medium
null
}
@ -72,21 +74,41 @@ class EEPROM extends prefab.ManagedEnvironment {
else result(Unit, "incorrect checksum")
}
@Callback(direct = true, doc = """function():string -- Get the storage capacity of this EEPROM.""")
def getDataSize(context: Context, args: Arguments): Array[AnyRef] = result(Settings.get.eepromDataSize)
@Callback(direct = true, doc = """function():string -- Get the currently stored byte array.""")
def getData(context: Context, args: Arguments): Array[AnyRef] = result(volatileData)
@Callback(doc = """function(data:string) -- Overwrite the currently stored byte array.""")
def setData(context: Context, args: Arguments): Array[AnyRef] = {
if (!node.tryChangeBuffer(-Settings.get.eepromWriteCost)) {
return result(Unit, "not enough energy")
}
val newData = args.optByteArray(0, Array.empty)
if (newData.length > Settings.get.eepromDataSize) throw new IllegalArgumentException("not enough space")
volatileData = newData
context.pause(1) // deliberately slow to discourage use as normal storage medium
null
}
// ----------------------------------------------------------------------- //
override def load(nbt: NBTTagCompound) {
super.load(nbt)
data = nbt.getByteArray(Settings.namespace + "eeprom")
codeData = nbt.getByteArray(Settings.namespace + "eeprom")
if (nbt.hasKey(Settings.namespace + "label")) {
label = nbt.getString(Settings.namespace + "label")
}
readonly = nbt.getBoolean(Settings.namespace + "readonly")
volatileData = nbt.getByteArray(Settings.namespace + "userdata")
}
override def save(nbt: NBTTagCompound) {
super.save(nbt)
nbt.setByteArray(Settings.namespace + "eeprom", data)
nbt.setByteArray(Settings.namespace + "eeprom", codeData)
nbt.setString(Settings.namespace + "label", label)
nbt.setBoolean(Settings.namespace + "readonly", readonly)
nbt.setByteArray(Settings.namespace + "userdata", volatileData)
}
}

View File

@ -57,8 +57,6 @@ class Machine(val host: MachineHost) extends prefab.ManagedEnvironment with mach
var architecture: Architecture = _
private var bootAddress = ""
private[machine] val state = mutable.Stack(Machine.State.Stopped)
private val _components = mutable.Map.empty[String, String]
@ -142,10 +140,6 @@ class Machine(val host: MachineHost) extends prefab.ManagedEnvironment with mach
hasMemory = Option(architecture).fold(false)(_.recomputeMemory(components))
}
override def getBootAddress = bootAddress
override def setBootAddress(value: String) = bootAddress = Option(value).fold("")(_.take(36))
override def components = scala.collection.convert.WrapAsJava.mapAsJavaMap(_components)
def componentCount = (_components.foldLeft(0.0)((acc, entry) => entry match {
@ -649,8 +643,6 @@ class Machine(val host: MachineHost) extends prefab.ManagedEnvironment with mach
super.load(nbt)
bootAddress = nbt.getString("bootAddress")
state.pushAll(nbt.getIntArray("state").reverse.map(Machine.State(_)))
nbt.getTagList("users", NBT.TAG_STRING).foreach((tag: NBTTagString) => _users += tag.func_150285_a_())
if (nbt.hasKey("message")) {
@ -718,10 +710,6 @@ class Machine(val host: MachineHost) extends prefab.ManagedEnvironment with mach
super.save(nbt)
if (bootAddress != null) {
nbt.setString("bootAddress", bootAddress)
}
// Make sure the component list is up-to-date.
processAddedComponents()

View File

@ -37,23 +37,6 @@ class ComputerAPI(owner: NativeLuaArchitecture) extends NativeLuaAPI(owner) {
})
lua.setField(-2, "address")
// Get/set address of boot device.
lua.pushScalaFunction(lua => {
owner.machine.getBootAddress match {
case "" => lua.pushNil()
case address => lua.pushString(address)
}
1
})
lua.setField(-2, "getBootAddress")
lua.pushScalaFunction(lua => {
if (lua.isNoneOrNil(1)) owner.machine.setBootAddress("")
else owner.machine.setBootAddress(lua.checkString(1).take(36))
0
})
lua.setField(-2, "setBootAddress")
lua.pushScalaFunction(lua => {
// This is *very* unlikely, but still: avoid this getting larger than
// what we report as the total memory.

View File

@ -27,18 +27,6 @@ class ComputerAPI(owner: LuaJLuaArchitecture) extends LuaJAPI(owner) {
case _ => LuaValue.NIL
})
// Get/set address of boot device.
computer.set("getBootAddress", (_: Varargs) => owner.machine.getBootAddress match {
case "" => LuaValue.NIL
case address => LuaValue.valueOf(address)
})
computer.set("setBootAddress", (args: Varargs) => {
if (args.isnoneornil(1)) owner.machine.setBootAddress("")
else owner.machine.setBootAddress(args.checkjstring(1).take(36))
LuaValue.NIL
})
computer.set("freeMemory", (_: Varargs) => LuaValue.valueOf(owner.memory / 2))
computer.set("totalMemory", (_: Varargs) => LuaValue.valueOf(owner.memory))