diff options
| -rw-r--r-- | documentation.json | 2 | ||||
| -rw-r--r-- | mesecons/textures/jeija_microcontroller_LED_A.png (renamed from mesecons_microcontroller/textures/jeija_microcontroller_LED_A.png) | bin | 1240 -> 1240 bytes | |||
| -rw-r--r-- | mesecons/textures/jeija_microcontroller_LED_B.png (renamed from mesecons_microcontroller/textures/jeija_microcontroller_LED_B.png) | bin | 1239 -> 1239 bytes | |||
| -rw-r--r-- | mesecons/textures/jeija_microcontroller_LED_C.png (renamed from mesecons_microcontroller/textures/jeija_microcontroller_LED_C.png) | bin | 1240 -> 1240 bytes | |||
| -rw-r--r-- | mesecons/textures/jeija_microcontroller_LED_D.png (renamed from mesecons_microcontroller/textures/jeija_microcontroller_LED_D.png) | bin | 1239 -> 1239 bytes | |||
| -rw-r--r-- | mesecons_fpga/depends.txt | 1 | ||||
| -rw-r--r-- | mesecons_fpga/doc/fpga/description.html | 5 | ||||
| -rw-r--r-- | mesecons_fpga/doc/fpga/preview.png | bin | 0 -> 21329 bytes | |||
| -rw-r--r-- | mesecons_fpga/doc/fpga/recipe.png | bin | 0 -> 3210 bytes | |||
| -rw-r--r-- | mesecons_fpga/doc/programmer/description.html | 3 | ||||
| -rw-r--r-- | mesecons_fpga/doc/programmer/preview.png | bin | 0 -> 598 bytes | |||
| -rw-r--r-- | mesecons_fpga/doc/programmer/recipe.png | bin | 0 -> 1908 bytes | |||
| -rw-r--r-- | mesecons_fpga/init.lua | 374 | ||||
| -rw-r--r-- | mesecons_fpga/logic.lua | 210 | ||||
| -rw-r--r-- | mesecons_fpga/textures/jeija_fpga_programmer.png | bin | 0 -> 311 bytes | |||
| -rw-r--r-- | mesecons_fpga/textures/jeija_fpga_sides.png | bin | 0 -> 536 bytes | |||
| -rw-r--r-- | mesecons_fpga/textures/jeija_fpga_top.png | bin | 0 -> 816 bytes | |||
| -rw-r--r-- | mesecons_fpga/tool.lua | 62 | 
18 files changed, 657 insertions, 0 deletions
| diff --git a/documentation.json b/documentation.json index 711f7d2..f318501 100644 --- a/documentation.json +++ b/documentation.json @@ -42,6 +42,8 @@  	},  	"Logic" : {  		"Luacontroller" : "mesecons_luacontroller/doc/luacontroller", +		"FPGA" : "mesecons_fpga/doc/fpga", +		"FPGA Programmer" : "mesecons_fpga/doc/programmer",  		"Torch" : "mesecons_torch/doc/torch",  		"Delayer" : "mesecons_delayer/doc/delayer",  		"Gates" : { diff --git a/mesecons_microcontroller/textures/jeija_microcontroller_LED_A.png b/mesecons/textures/jeija_microcontroller_LED_A.pngBinary files differ index 64526cf..64526cf 100644 --- a/mesecons_microcontroller/textures/jeija_microcontroller_LED_A.png +++ b/mesecons/textures/jeija_microcontroller_LED_A.png diff --git a/mesecons_microcontroller/textures/jeija_microcontroller_LED_B.png b/mesecons/textures/jeija_microcontroller_LED_B.pngBinary files differ index 1f7b451..1f7b451 100644 --- a/mesecons_microcontroller/textures/jeija_microcontroller_LED_B.png +++ b/mesecons/textures/jeija_microcontroller_LED_B.png diff --git a/mesecons_microcontroller/textures/jeija_microcontroller_LED_C.png b/mesecons/textures/jeija_microcontroller_LED_C.pngBinary files differ index 399cc2c..399cc2c 100644 --- a/mesecons_microcontroller/textures/jeija_microcontroller_LED_C.png +++ b/mesecons/textures/jeija_microcontroller_LED_C.png diff --git a/mesecons_microcontroller/textures/jeija_microcontroller_LED_D.png b/mesecons/textures/jeija_microcontroller_LED_D.pngBinary files differ index 506389c..506389c 100644 --- a/mesecons_microcontroller/textures/jeija_microcontroller_LED_D.png +++ b/mesecons/textures/jeija_microcontroller_LED_D.png diff --git a/mesecons_fpga/depends.txt b/mesecons_fpga/depends.txt new file mode 100644 index 0000000..acaa924 --- /dev/null +++ b/mesecons_fpga/depends.txt @@ -0,0 +1 @@ +mesecons diff --git a/mesecons_fpga/doc/fpga/description.html b/mesecons_fpga/doc/fpga/description.html new file mode 100644 index 0000000..be6bd65 --- /dev/null +++ b/mesecons_fpga/doc/fpga/description.html @@ -0,0 +1,5 @@ +FPGAs can be used to chain multiple logic gates together in a compact manner. +They come with 4 I/O ports and 10 internal registers, +which can then be connected with eachother to form logic circuits.<br /> +Supported gate types: <b>AND</b>, <b>OR</b>, <b>NOT</b>, <b>XOR</b>, <b>NAND</b>, <b>XNOR</b>, <b>Buffer</b> (=)<br /> +I/O ports: <b>A B C D</b>; Registers: numbered <b>0</b> to <b>9</b> diff --git a/mesecons_fpga/doc/fpga/preview.png b/mesecons_fpga/doc/fpga/preview.pngBinary files differ new file mode 100644 index 0000000..c156321 --- /dev/null +++ b/mesecons_fpga/doc/fpga/preview.png diff --git a/mesecons_fpga/doc/fpga/recipe.png b/mesecons_fpga/doc/fpga/recipe.pngBinary files differ new file mode 100644 index 0000000..1140bfa --- /dev/null +++ b/mesecons_fpga/doc/fpga/recipe.png diff --git a/mesecons_fpga/doc/programmer/description.html b/mesecons_fpga/doc/programmer/description.html new file mode 100644 index 0000000..39e2374 --- /dev/null +++ b/mesecons_fpga/doc/programmer/description.html @@ -0,0 +1,3 @@ +The FPGA programmer can be used to copy gate configurations from one FPGA to another.<br /> +Shift+Right-Click an FPGA to read its configuration and "remember" it. +Left-click (punch) FPGAs to write the saved configuration to them. diff --git a/mesecons_fpga/doc/programmer/preview.png b/mesecons_fpga/doc/programmer/preview.pngBinary files differ new file mode 100644 index 0000000..7437d39 --- /dev/null +++ b/mesecons_fpga/doc/programmer/preview.png diff --git a/mesecons_fpga/doc/programmer/recipe.png b/mesecons_fpga/doc/programmer/recipe.pngBinary files differ new file mode 100644 index 0000000..778ec5f --- /dev/null +++ b/mesecons_fpga/doc/programmer/recipe.png diff --git a/mesecons_fpga/init.lua b/mesecons_fpga/init.lua new file mode 100644 index 0000000..03beafc --- /dev/null +++ b/mesecons_fpga/init.lua @@ -0,0 +1,374 @@ +local plg = {} +plg.rules = {} + +local lcore = dofile(minetest.get_modpath(minetest.get_current_modname()) .. "/logic.lua") +dofile(minetest.get_modpath(minetest.get_current_modname()) .. "/tool.lua")(plg) + + +plg.register_nodes = function(template) +	-- each loop is for one of the 4 IO ports +	for a = 0, 1 do +	for b = 0, 1 do +	for c = 0, 1 do +	for d = 0, 1 do +		local ndef = table.copy(template) +		local nodename = "mesecons_fpga:fpga" +				.. tostring(d) .. tostring(c) .. tostring(b) .. tostring(a) + +		-- build top texture string +		local texture = "jeija_fpga_top.png" +		if a == 1 then texture = texture .. "^jeija_microcontroller_LED_A.png" end +		if b == 1 then texture = texture .. "^jeija_microcontroller_LED_B.png" end +		if c == 1 then texture = texture .. "^jeija_microcontroller_LED_C.png" end +		if d == 1 then texture = texture .. "^jeija_microcontroller_LED_D.png" end +		ndef.tiles[1] = texture +		ndef.inventory_image = texture + +		if (a + b + c + d) > 0 then +			ndef.groups["not_in_creative_inventory"] = 1 +		end + +		-- interaction with mesecons (input / output) +		local rules_out = {} +		if a == 1 then table.insert(rules_out, {x = -1, y = 0, z =  0}) end +		if b == 1 then table.insert(rules_out, {x =  0, y = 0, z =  1}) end +		if c == 1 then table.insert(rules_out, {x =  1, y = 0, z =  0}) end +		if d == 1 then table.insert(rules_out, {x =  0, y = 0, z = -1}) end +		plg.rules[nodename] = rules_out + +		local rules_in = {} +		if a == 0 then table.insert(rules_in, {x = -1, y = 0, z =  0}) end +		if b == 0 then table.insert(rules_in, {x =  0, y = 0, z =  1}) end +		if c == 0 then table.insert(rules_in, {x =  1, y = 0, z =  0}) end +		if d == 0 then table.insert(rules_in, {x =  0, y = 0, z = -1}) end +		ndef.mesecons.effector.rules = rules_in + +		if (a + b + c + d) > 0 then +			ndef.mesecons.receptor = { +				state = mesecon.state.on, +				rules = rules_out, +			} +		end + +		minetest.register_node(nodename, ndef) +	end +	end +	end +	end +end + +plg.register_nodes({ +	description = "FPGA", +	drawtype = "nodebox", +	tiles = { +		"", -- replaced later +		"jeija_microcontroller_bottom.png", +		"jeija_fpga_sides.png", +		"jeija_fpga_sides.png", +		"jeija_fpga_sides.png", +		"jeija_fpga_sides.png" +	}, +	inventory_image = "", -- replaced later +	sunlight_propagates = true, +	paramtype = "light", +	walkable = true, +	groups = {dig_immediate = 2, mesecon = 3}, +	drop = "mesecons_fpga:fpga0000", +	selection_box = { +		type = "fixed", +		fixed = { -8/16, -8/16, -8/16, 8/16, -5/16, 8/16 }, +	}, +	node_box = { +		type = "fixed", +		fixed = { +			{ -8/16, -8/16, -8/16, 8/16, -7/16, 8/16 }, -- bottom slab +			{ -5/16, -7/16, -5/16, 5/16, -6/16, 5/16 }, -- circuit board +			{ -3/16, -6/16, -3/16, 3/16, -5/16, 3/16 }, -- IC +		} +	}, +	on_construct = function(pos) +		local meta = minetest.get_meta(pos) +		local is = { {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {} } + +		meta:set_string("instr", lcore.serialize(is)) +		meta:set_int("valid", 0) +		meta:set_string("formspec", plg.to_formspec_string(is)) +		meta:set_string("infotext", "FPGA") +	end, +	on_receive_fields = function(pos, formname, fields, sender) +		if fields.program == nil then return end -- we only care when the user clicks "Program" +		local meta = minetest.get_meta(pos) +		local is = plg.from_formspec_fields(fields) + +		meta:set_string("instr", lcore.serialize(is)) +		plg.update_formspec(pos, is) +	end, +	sounds = default.node_sound_stone_defaults(), +	mesecons = { +		effector = { +			rules = {}, -- replaced later +			action_change = function(pos, node, rule, newstate) +				plg.ports_changed(pos, rule, newstate) +				plg.update(pos) +			end +		} +	}, +	after_dig_node = function(pos, node) +		mesecon.receptor_off(pos, plg.rules[node.name]) +	end, +}) + + +plg.to_formspec_string = function(is) +	local function dropdown_op(x, y, name, val) +		local s = "dropdown[" .. tostring(x) .. "," .. tostring(y) .. ";" +				.. "0.75,0.5;" .. name .. ";" -- the height seems to be ignored? +		s = s .. " ,A,B,C,D,0,1,2,3,4,5,6,7,8,9;" +		if val == nil then +			s = s .. "0" -- actually selects no field at all +		elseif val.type == "io" then +			local mapping = { +				["A"] = 1, +				["B"] = 2, +				["C"] = 3, +				["D"] = 4, +			} +			s = s .. tostring(1 + mapping[val.port]) +		else -- "reg" +			s = s .. tostring(6 + val.n) +		end +		return s .. "]" +	end +	local function dropdown_action(x, y, name, val) +		local s = "dropdown[" .. tostring(x) .. "," .. tostring(y) .. ";" +				.. "1.125,0.5;" .. name .. ";" -- the height seems to be ignored? +		s = s .. " , AND, OR, NOT, XOR,NAND,   =,XNOR;" +		if val == nil then +			return s .. "0]" -- actually selects no field at all +		end +		local mapping = { +			["and"] = 1, +			["or"] = 2, +			["not"] = 3, +			["xor"] = 4, +			["nand"] = 5, +			["buf"] = 6, +			["xnor"] = 7, +		} +		return s .. tostring(1 + mapping[val]) .. "]" +	end +	local s = "size[9,9]".. +		"label[3.4,-0.15;FPGA gate configuration]".. +		"button_exit[7,7.5;2,2.5;program;Program]".. +		"box[4.2,0.5;0.03,7;#ffffff]".. +		"label[0.25,0.25;op. 1]".. +		"label[1.0,0.25;gate type]".. +		"label[2.125,0.25;op. 2]".. +		"label[3.15,0.25;dest]".. +		"label[4.5,0.25;op. 1]".. +		"label[5.25,0.25;gate type]".. +		"label[6.375,0.25;op. 2]".. +		"label[7.4,0.25;dest]" +	local x = 1 - 0.75 +	local y = 1 - 0.25 +	for i = 1, 14 do +		local cur = is[i] +		s = s .. dropdown_op    (x      , y, tostring(i).."op1", cur.op1) +		s = s .. dropdown_action(x+0.75 , y, tostring(i).."act", cur.action) +		s = s .. dropdown_op    (x+1.875, y, tostring(i).."op2", cur.op2) +		s = s .. "label[" .. tostring(x+2.625) .. "," .. tostring(y+0.1) .. "; ->]" +		s = s .. dropdown_op    (x+2.9  , y, tostring(i).."dst", cur.dst) +		y = y + 1 + +		if i == 7 then +			x = 4.5 +			y = 1 - 0.25 +		end +	end +	return s +end + +plg.from_formspec_fields = function(fields) +	local function read_op(s) +		if s == nil or s == " " then +			return nil +		elseif s == "A" or s == "B" or s == "C" or s == "D" then +			return {type = "io", port = s} +		else +			return {type = "reg", n = tonumber(s)} +		end +	end +	local function read_action(s) +		if s == nil or s == " " then +			return nil +		end +		local mapping = { +			[" AND"] = "and", +			["  OR"] = "or", +			[" NOT"] = "not", +			[" XOR"] = "xor", +			["NAND"] = "nand", +			["   ="] = "buf", +			["XNOR"] = "xnor", +		} +		return mapping[s] +	end +	local is = {} +	for i = 1, 14 do +		local cur = {} +		cur.op1 = read_op(fields[tonumber(i) .. "op1"]) +		cur.action = read_action(fields[tonumber(i) .. "act"]) +		cur.op2 = read_op(fields[tonumber(i) .. "op2"]) +		cur.dst = read_op(fields[tonumber(i) .. "dst"]) +		is[#is + 1] = cur +	end +	return is +end + +plg.update_formspec = function(pos, is) +	if type(is) == "string" then -- serialized string +		is = lcore.deserialize(is) +	end +	local meta = minetest.get_meta(pos) +	local form = plg.to_formspec_string(is) + +	local err = lcore.validate(is) +	if err == nil then +		meta:set_int("valid", 1) +		meta:set_string("infotext", "FPGA (functional)") +	else +		meta:set_int("valid", 0) +		meta:set_string("infotext", "FPGA") +		local fmsg = minetest.colorize("#ff0000", minetest.formspec_escape(err.msg)) +		form = form .. plg.red_box_around(err.i) .. +			"label[0.25,8.25;The gate configuration is erroneous in the marked area:]".. +			"label[0.25,8.5;" .. fmsg .. "]" +	end + +	meta:set_string("formspec", form) + +	-- reset ports and run programmed logic +	plg.setports(pos, false, false, false, false) +	plg.update(pos) +end + +plg.red_box_around = function(i) +	local x, y +	if i > 7 then +		x = 4.5 +		y = 0.75 + (i - 8) +	else +		x = 0.25 +		y = 0.75 + (i - 1) +	end +	return string.format("box[%f,%f;3.8,0.8;#ff0000]", x-0.1, y-0.05) +end + + +plg.update = function(pos) +	local meta = minetest.get_meta(pos) +	if meta:get_int("valid") ~= 1 then +		return +	end + +	local is = lcore.deserialize(meta:get_string("instr")) +	local A, B, C, D = plg.getports(pos) +	A, B, C, D = lcore.interpret(is, A, B, C, D) +	plg.setports(pos, A, B, C, D) +end + +plg.ports_changed = function(pos, rule, newstate) +	if rule == nil then return end +	local meta = minetest.get_meta(pos) +	local states + +	local s = meta:get_string("portstates") +	if s == nil then +		states = {false, false, false, false} +	else +		states = { +			s:sub(1, 1) == "1", +			s:sub(2, 2) == "1", +			s:sub(3, 3) == "1", +			s:sub(4, 4) == "1", +		} +	end + +	-- trick to transform rules (see register_node) into port number +	local portno = ({4, 1, nil, 3, 2})[3 + rule.x + 2*rule.z] +	states[portno] = (newstate == "on") + +	meta:set_string("portstates", +			(states[1] and "1" or "0") .. (states[2] and "1" or "0") .. +			(states[3] and "1" or "0") .. (states[4] and "1" or "0") +	) +end + +plg.getports = function(pos) -- gets merged states of INPUT & OUTPUT +	local sin, sout + +	local s = minetest.get_meta(pos):get_string("portstates") +	if s == nil then +		sin = {false, false, false, false} +	else +		sin = { +			s:sub(1, 1) == "1", +			s:sub(2, 2) == "1", +			s:sub(3, 3) == "1", +			s:sub(4, 4) == "1", +		} +	end + +	local name = minetest.get_node(pos).name +	assert(name:find("mesecons_fpga:fpga") == 1) +	local off = #"mesecons_fpga:fpga" +	sout = { +		name:sub(off+4, off+4) == "1", +		name:sub(off+3, off+3) == "1", +		name:sub(off+2, off+2) == "1", +		name:sub(off+1, off+1) == "1", +	} + +	return unpack({ +		sin[1] or sout[1], +		sin[2] or sout[2], +		sin[3] or sout[3], +		sin[4] or sout[4], +	}) +end + +plg.setports = function(pos, A, B, C, D) -- sets states of OUTPUT +	local base = "mesecons_fpga:fpga" + +	local name = base +			.. (D and "1" or "0") .. (C and "1" or "0") +			.. (B and "1" or "0") .. (A and "1" or "0") +	minetest.swap_node(pos, {name = name, param2 = minetest.get_node(pos).param2}) + +	if A ~= nil then +		local ru = plg.rules[base .. "0001"] +		if A then mesecon.receptor_on(pos, ru) else mesecon.receptor_off(pos, ru) end +	end +	if B ~= nil then +		local ru = plg.rules[base .. "0010"] +		if B then mesecon.receptor_on(pos, ru) else mesecon.receptor_off(pos, ru) end +	end +	if C ~= nil then +		local ru = plg.rules[base .. "0100"] +		if C then mesecon.receptor_on(pos, ru) else mesecon.receptor_off(pos, ru) end +	end +	if D ~= nil then +		local ru = plg.rules[base .. "1000"] +		if D then mesecon.receptor_on(pos, ru) else mesecon.receptor_off(pos, ru) end +	end +end + + +minetest.register_craft({ +	output = "mesecons_fpga:fpga0000 2", +	recipe = { +		{'group:mesecon_conductor_craftable', 'group:mesecon_conductor_craftable'}, +		{'mesecons_materials:silicon', 'mesecons_materials:silicon'}, +		{'group:mesecon_conductor_craftable', 'group:mesecon_conductor_craftable'}, +	} +}) diff --git a/mesecons_fpga/logic.lua b/mesecons_fpga/logic.lua new file mode 100644 index 0000000..3dca154 --- /dev/null +++ b/mesecons_fpga/logic.lua @@ -0,0 +1,210 @@ +local lg = {} + +-- (de)serialize +lg.serialize = function(t) +	local function _op(t) +		if t == nil then +			return " " +		elseif t.type == "io" then +			return t.port +		else -- t.type == "reg" +			return tostring(t.n) +		end +	end +	local function _action(s) +		if s == nil then +			return " " +		end +		local mapping = { +			["and"] = "&", +			["or"] = "|", +			["not"] = "~", +			["xor"] = "^", +			["nand"] = "?", --dunno +			["buf"] = "_", +			["xnor"] = "=", +		} +		return mapping[s] +	end + +	local s = "" +	for i = 1, 14 do +		local cur = t[i] +		if next(cur) ~= nil then +			s = s .. _op(cur.op1) .. _action(cur.action) .. _op(cur.op2) .. _op(cur.dst) +		end +		s = s .. "/" +	end +	return s +end + +lg.deserialize = function(s) +	local function _op(c) +		if c == "A" or c == "B" or c == "C" or c == "D" then +			return {type = "io", port = c} +		elseif c == " " then +			return nil +		else +			return {type = "reg", n = tonumber(c)} +		end +	end +	local function _action(c) +		local mapping = { +			["&"] = "and", +			["|"] = "or", +			["~"] = "not", +			["^"] = "xor", +			["?"] = "nand", +			["_"] = "buf", +			["="] = "xnor", +			[" "] = nil, +		} +		return mapping[c] +	end + +	local ret = {} +	for part in s:gmatch("(.-)/") do +		local parsed +		if part == "" then +			parsed = {} +		else +			parsed = { +				action = _action( part:sub(2,2) ), +				op1 = _op( part:sub(1,1) ), +				op2 = _op( part:sub(3,3) ), +				dst = _op( part:sub(4,4) ), +			} +		end +		ret[#ret + 1] = parsed +	end +	-- More than 14 instructions (write to all 10 regs + 4 outputs) +	-- will not pass the write-once requirement of the validator +	assert(#ret == 14) +	return ret +end + +-- validation +lg.validate_single = function(t, i) +	local function is_reg_written_to(t, n, max) +		for i = 1, max-1 do +			if next(t[i]) ~= nil +					and t[i].dst and t[i].dst.type == "reg" +					and t[i].dst.n == n then +				return true +			end +		end +		return false +	end +	local function compare_op(t1, t2, allow_same_io) +		if t1 == nil or t2 == nil then +			return false +		elseif t1.type ~= t2.type then +			return false +		end +		if t1.type == "reg" and t1.n == t2.n then +			return true +		elseif t1.type == "io" and t1.port == t2.port then +			return not allow_same_io +		end +		return false +	end +	local elem = t[i] +	-- check for completeness +	if elem.action == nil then +		return {i = i, msg = "Gate type required"} +	elseif elem.action == "not" or elem.action == "buf" then +		if elem.op1 ~= nil or elem.op2 == nil or elem.dst == nil then +			return {i = i, msg = "Second operand (only) and destination required"} +		end +	else +		if elem.op1 == nil or elem.op2 == nil or elem.dst == nil then +			return {i = i, msg = "Operands and destination required"} +		end +	end +	-- check whether operands/destination are identical +	if compare_op(elem.op1, elem.op2) then +		return {i = i, msg = "Operands cannot be identical"} +	end +	if compare_op(elem.op1, elem.dst, true) or compare_op(elem.op2, elem.dst, true) then +		return {i = i, msg = "Destination and operands must be different"} +	end +	-- check whether operands point to defined registers +	if elem.op1 ~= nil and elem.op1.type == "reg" +			and not is_reg_written_to(t, elem.op1.n, i) then +		return {i = i, msg = "First operand is undefined register"} +	end +	if elem.op2.type == "reg" and not is_reg_written_to(t, elem.op2.n, i) then +		return {i = i, msg = "Second operand is undefined register"} +	end +	-- check whether destination points to undefined register +	if elem.dst.type == "reg" and is_reg_written_to(t, elem.dst.n, i) then +		return {i = i, msg = "Destination is already used register"} +	end + +	return nil +end + +lg.validate = function(t) +	for i = 1, 14 do +		if next(t[i]) ~= nil then +			local r = lg.validate_single(t, i) +			if r ~= nil then +				return r +			end +		end +	end +	return nil +end + +-- interpreter +lg.interpret = function(t, a, b, c, d) +	local function _action(s, v1, v2) +		if s == "and" then +			return v1 and v2 +		elseif s == "or" then +			return v1 or v2 +		elseif s == "not" then +			return not v2 +		elseif s == "xor" then +			return v1 ~= v2 +		elseif s == "nand" then +			return not (v1 and v2) +		elseif s == "buf" then +			return v2 +		else -- s == "xnor" +			return v1 == v2 +		end +	end +	local function _op(t, regs, io_in) +		if t.type == "reg" then +			return regs[t.n] +		else -- t.type == "io" +			return io_in[t.port] +		end +	end + +	local io_in = {A=a, B=b, C=c, D=d} +	local regs = {} +	local io_out = {} +	for i = 1, 14 do +		local cur = t[i] +		if next(cur) ~= nil then +			local v1, v2 +			if cur.op1 ~= nil then +				v1 = _op(cur.op1, regs, io_in) +			end +			v2 = _op(cur.op2, regs, io_in) + +			local result = _action(cur.action, v1, v2) + +			if cur.dst.type == "reg" then +				regs[cur.dst.n] = result +			else -- cur.dst.type == "io" +				io_out[cur.dst.port] = result +			end +		end +	end +	return io_out.A, io_out.B, io_out.C, io_out.D +end + +return lg diff --git a/mesecons_fpga/textures/jeija_fpga_programmer.png b/mesecons_fpga/textures/jeija_fpga_programmer.pngBinary files differ new file mode 100644 index 0000000..9c0ba8f --- /dev/null +++ b/mesecons_fpga/textures/jeija_fpga_programmer.png diff --git a/mesecons_fpga/textures/jeija_fpga_sides.png b/mesecons_fpga/textures/jeija_fpga_sides.pngBinary files differ new file mode 100644 index 0000000..e2d8e15 --- /dev/null +++ b/mesecons_fpga/textures/jeija_fpga_sides.png diff --git a/mesecons_fpga/textures/jeija_fpga_top.png b/mesecons_fpga/textures/jeija_fpga_top.pngBinary files differ new file mode 100644 index 0000000..eaf1a1c --- /dev/null +++ b/mesecons_fpga/textures/jeija_fpga_top.png diff --git a/mesecons_fpga/tool.lua b/mesecons_fpga/tool.lua new file mode 100644 index 0000000..26ab49e --- /dev/null +++ b/mesecons_fpga/tool.lua @@ -0,0 +1,62 @@ +return function(plg) + + +minetest.register_tool("mesecons_fpga:programmer", { +	description = "FPGA Programmer", +	inventory_image = "jeija_fpga_programmer.png", +	stack_max = 1, +	on_place = function(itemstack, placer, pointed_thing) +		if pointed_thing.type ~= "node" then +			return itemstack +		end + +		local pos = pointed_thing.under +		if minetest.get_node(pos).name:find("mesecons_fpga:fpga") ~= 1 then +			return itemstack +		end + +		local meta = minetest.get_meta(pos) +		if meta:get_string("instr") == "//////////////" then +			minetest.chat_send_player(placer:get_player_name(), "This FPGA is unprogrammed.") +			return itemstack +		end +		itemstack:set_metadata(meta:get_string("instr")) +		minetest.chat_send_player(placer:get_player_name(), "FPGA gate configuration was successfully copied!") +		 +		return itemstack +	end, +	on_use = function(itemstack, user, pointed_thing) +		if pointed_thing.type ~= "node" then +			return itemstack +		end + +		local pos = pointed_thing.under +		if minetest.get_node(pos).name:find("mesecons_fpga:fpga") ~= 1 then +			return itemstack +		end + +		local imeta = itemstack:get_metadata() +		if imeta == "" then +			minetest.chat_send_player(user:get_player_name(), "Use shift+right-click to copy a gate configuration first.") +			return itemstack +		end + +		local meta = minetest.get_meta(pos) +		meta:set_string("instr", imeta) +		plg.update_formspec(pos, imeta) +		minetest.chat_send_player(user:get_player_name(), "Gate configuration was successfully written to FPGA!") + +		return itemstack +	end +}) + +minetest.register_craft({ +	output = "mesecons_fpga:programmer", +	recipe = { +		{'group:mesecon_conductor_craftable'}, +		{'mesecons_materials:silicon'}, +	} +}) + + +end | 
