Created
June 13, 2017 12:38
-
-
Save Rami-Sabbagh/1a1532dc57ab0f2e5c2cd4dde81b4c82 to your computer and use it in GitHub Desktop.
PowderToy Micro Lua Proccessors
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
--Creating the elements-- | |
local elem_group = "MLUA" | |
local elem_names = { "LMPU", "LCBL", "LPIN", "LMRC", "LROM" } --The names of the elements to allocate | |
local elem_id = {} --A table containing the ids of every name in elem_names, [name] = id. | |
local elem_name = {} --A table to get the name from the id | |
--Allocate the elements | |
for k, name in ipairs(elem_names) do | |
if elements[elem_group.."_PT_"..name] then elements.free(elements[elem_group.."_PT_"..name]) end --Incase the script errored | |
local id = elements.allocate(elem_group, name) | |
if id == -1 then --(It failed) | |
error("Failed to allocate an element, please disable some elements scripts !") | |
return --Abort the script | |
else | |
elem_id[name] = id | |
elem_name[id] = name | |
end | |
end | |
local elem_clone = { --New elements properties; _Parent is a special key that clones properties from a default elements before applying the changes. | |
["LMPU"] = { | |
_Parent = "METL", | |
Name = "LMPU", | |
Description = "Lua Microprocessor Unit, used for advanced electornics", | |
Color = 0x000080, --The color of the Lua logo ;) | |
MenuSection = elements.SC_POWERED | |
}, | |
["LCBL"] = { | |
_Parent = "INSL", | |
Name = "LCBL", | |
Description = "Lua Cable, used for connecting peripherals with LMPU", | |
Flammable = 0, --UnFlammable | |
MenuSection = elements.SC_POWERED | |
}, | |
["LPIN"] = { | |
_Parent = "METL", | |
Name = "LPIN", | |
Description = "Lua Pin, Connects as GPIO pin peripheral. TMP as id", | |
Color = 0xE0E0E0, | |
MenuSection = elements.SC_POWERED | |
}, | |
["LMRC"] = { | |
_Parent = "METL", | |
Name = "LMRC", | |
Description = "Lua Memory Reading Controller peripheral. Speciallized in reading LROM", | |
Color = 0xF4BC42, | |
MenuSection = elements.SC_POWERED | |
}, | |
["LROM"] = { | |
_Parent = "IRON", | |
Name = "LROM", | |
Description = "Lua Read Only Memory, Stores 8 Bytes (8 Ascii Characters)", | |
Color = 0xFFFFFF, --White | |
Properties = bit.bor(elements.TYPE_SOLID,elements.PROP_HOT_GLOW), | |
MenuSection = elements.SC_POWERED | |
} | |
} | |
--Applying the properties | |
for name, props in pairs(elem_clone) do | |
if not elem_id[name] then error("Un-allocated element: "..name..", report this to the developer !") end | |
if props._Parent then elements.element(elem_id[name],elements.element(elements["DEFAULT_PT_"..props._Parent])); props._Parent = nil end --Do the clonning | |
elements.element(elem_id[name],props) --Set the properties | |
end | |
local elem_peripherals = {[ elem_id["LPIN"] ] = true, [ elem_id["LMRC"] ] = true} --Use elem_id (for easier programming) | |
--SC (self call) is a special argument, don't use it ! | |
local mappedIndexes, mappedPeripherals = {}, {} | |
local function mapCables(x,y, sc) | |
if not sc then mappedIndexes, mappedPeripherals = {}, {} end --Reset the maps | |
mappedIndexes[simulation.partID(x,y)] = true --Set the current part as mapped. | |
local parts = simulation.partNeighbors(x,y, 2) --Scan the around parts. | |
for _, index in ipairs(parts) do | |
if not mappedIndexes[index] then | |
local px, py = simulation.partPosition(index) | |
local ptype = simulation.partProperty(index,simulation.FIELD_TYPE) | |
if elem_peripherals[ptype] then --It's a peripheral ! | |
mappedIndexes[index] = true --So don't double detect the peripheral | |
if not mappedPeripherals[elem_name[ptype]] then mappedPeripherals[elem_name[ptype]] = {} end | |
table.insert(mappedPeripherals[elem_name[ptype]],index) | |
elseif elem_id["LCBL"] == ptype then --It's a cable | |
mapCables(px,py, true) | |
end | |
end | |
end | |
if not sc then return mappedPeripherals end | |
end | |
local function mapROM(x,y) | |
--X, Y should be the position of the top-left corner. | |
local mi = {} --Mapped Indexes | |
local cy = 0 | |
while true do | |
local ypid = simulation.partID(x,y+cy) | |
if not ypid then break end | |
if simulation.partProperty(ypid, simulation.FIELD_TYPE) ~= elem_id["LROM"] then break end --The end of rom block | |
local cx = 0 | |
while true do | |
local pid = simulation.partID(x+cx,y+cy) | |
if not pid then break end --No Part | |
if simulation.partProperty(pid, simulation.FIELD_TYPE) ~= elem_id["LROM"] then break end --The end of rom line | |
table.insert(mi,pid) | |
cx = cx + 1 | |
end | |
cy = cy + 1 | |
end | |
return mi | |
end | |
--Reads the ROM string, must provide the mappedIndexes array (That can be obtained by mapROM(x,y)) | |
local function readROM(mi) | |
local data = "" | |
for _, index in ipairs(mi) do | |
local ctype = simulation.partProperty(index, simulation.FIELD_CTYPE) --1 byte | |
local dcolor = simulation.partProperty(index, simulation.FIELD_DCOLOUR) --4 bytes | |
local life = simulation.partProperty(index, simulation.FIELD_LIFE) --1 byte | |
local tmp = simulation.partProperty(index, simulation.FIELD_TMP) --1 byte | |
local tmp2 = simulation.partProperty(index, simulation.FIELD_TMP2) --1 byte | |
ctype = string.char(ctype) | |
local cola = string.char(bit.band(dcolor,255)) | |
local colr = string.char(bit.band(bit.rshift(dcolor,8),255)) | |
local colg = string.char(bit.band(bit.rshift(dcolor,16),255)) | |
local colb = string.char(bit.band(bit.rshift(dcolor,24),255)) | |
life = string.char(life) | |
tmp = string.char(tmp) | |
tmp2 = string.char(tmp2) | |
data = data .. ctype..cola..colr..colg..colb..life..tmp..tmp2 | |
end | |
return data | |
end | |
--Writes the ROM string, must provide the mappedIndexes arrays (That can be obtained by mapROM(x,y)) and the data string. | |
local function flushROM(mi,data) | |
local dataBytes = {} | |
for i=1,data:len() do | |
table.insert(dataBytes,string.byte(data:sub(i,i+1))) | |
end | |
local curByte = 0 | |
local function nextByte() | |
if #dataBytes == curByte then return 0 end | |
curByte = curByte + 1 | |
return dataBytes[curByte] | |
end | |
for _, index in ipairs(mi) do | |
simulation.partProperty(index, simulation.FIELD_CTYPE, nextByte()) --1 bytes | |
local cola = nextByte() | |
local colr = bit.lshift(nextByte(),8) | |
local colg = bit.lshift(nextByte(),16) | |
local colb = bit.lshift(nextByte(),24) | |
local dcolor = bit.bor(cola,colr,colg,colb) | |
simulation.partProperty(index, simulation.FIELD_DCOLOUR, dcolor) --4 bytes | |
simulation.partProperty(index, simulation.FIELD_LIFE, nextByte()) --1 byte | |
simulation.partProperty(index, simulation.FIELD_TMP, nextByte()) --1 byte | |
simulation.partProperty(index, simulation.FIELD_TMP2, nextByte()) --1 byte | |
end | |
end | |
local MPU_Data = {} | |
--Elements Update | |
elements.property( elem_id["LMPU"], "Update", function(index, x, y, surround_space, nt) | |
local flags = simulation.partProperty(index, simulation.FIELD_FLAGS) | |
--Check if the processor did boot yet or not. | |
--I found that it's safe to use the second byte of FLAGS | |
--And why I'm using flags because it's not saved ;) | |
--The first bit will be the boot state, 0 = off, 1 = booted. | |
if bit.band(flags, 256) == 0 then --It did not boot yet ! | |
MPU_Data[index] = {} --Override the old one if exists. | |
MPU_Data[index].peripherals = mapCables(x,y) | |
if MPU_Data[index].peripherals.LMRC then | |
print("Detected Memory Reading Chip, Starting Demo") | |
local index = MPU_Data[index].peripherals.LMRC[1] | |
local x,y = simulation.partPosition(index) | |
local rom = mapROM(x+1,y+1) | |
--print("Will Flash some data") | |
--flushROM(rom, "TEST DATA, LET'S SEE12345678901234567890") | |
--print("Flashed Rom") | |
local data = readROM(rom) | |
print("ROM: "..tostring(data)) | |
end | |
simulation.partProperty(index, simulation.FIELD_FLAGS, bit.bor(flags,256)) --Flag as booted | |
else --It booted before, tick now. | |
end | |
end) | |
--Console Tools | |
micro = {} --The MicroLua API | |
--Read data from a file and flushs it to a LMRC at a given index. | |
function micro.flushMRC(index,filepath) | |
--Usage message | |
if not (index and filepath) then | |
print([[USAGE: micro.flushMRC(<index>,<filepath>) | |
Reads data from a file and flushs it to a LMRC at a given index. | |
<index>: The LMRC part index. | |
<filepath>: The path to the file to read from.]]) | |
return | |
end | |
--Arguments type verification | |
if type(index) ~= "number" then return error("Index must be a number, provided: "..type(index)) end | |
if type(filepath) ~= "string" then return error("Filepath must be a string, provided: "..type(filepath)) end | |
--Part verification | |
local controllerType = simulation.partProperty(index, simulation.FIELD_TYPE) | |
if not controllerType then return error("No part exists with id #"..index) end | |
if controllerType ~= elem_id["LMRC"] then return error("The given part is not a LMRC, instead it's: "..controllerType) end | |
--File verification | |
local file, ferr = io.open(filepath, "rb") | |
if not file then return error("Failed to open the file: "..tostring(ferr)) end | |
--Load file data | |
local data = file:read("*a") | |
file:close() | |
--Map the ROM indexes | |
local cx, cy = simulation.partPosition(index) --Controller position. | |
local mi = mapROM(cx+1,cy+1) | |
--Check data size | |
local maxSize = #mi*8 --Every part can hold 8 bytes | |
if data:len() > maxSize then return error("Data too large to flash ("..data:len().." byte), max: "..maxSize.." byte") end | |
--Flush the data | |
flushROM(mi, data) | |
print("Flushed data successully") | |
end | |
--Read data from a LMRC at a given index, and save it into a given file. | |
function micro.dumpMRC(index,filepath) | |
--Usage message | |
if not (index and filepath) then | |
print([[USAGE: micro.dumpMRC(<index>,<filepath>) | |
Read data from a LMRC at a given index, and save it into a given file. | |
<index>: The LMRC part index. | |
<filepath>: The path to the file to save to.]]) | |
return | |
end | |
--Arguments type verification | |
if type(index) ~= "number" then return error("Index must be a number, provided: "..type(index)) end | |
if type(filepath) ~= "string" then return error("Filepath must be a string, provided: "..type(filepath)) end | |
--Part verification | |
local controllerType = simulation.partProperty(index, simulation.FIELD_TYPE) | |
if not controllerType then return error("No part exists with id #"..index) end | |
if controllerType ~= elem_id["LMRC"] then return error("The given part is not a LMRC, instead it's: "..controllerType) end | |
--File creation | |
local file, ferr = io.open(filepath, "wb") | |
if not file then return error("Failed to open the file: "..tostring(ferr)) end | |
--Map the ROM indexes | |
local cx, cy = simulation.partPosition(index) --Controller position. | |
local mi = mapROM(cx+1,cy+1) | |
--Get ROM data | |
local data = readROM(cx+1,cy+1) | |
--Save the data on the file | |
file:write(data) | |
file:flush() | |
file:close() | |
print("Dumped data successully") | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment