commit
3af961ac7b
56
README.md
56
README.md
@ -8,29 +8,43 @@ Memory access in this mod occurs over digilines, with the channel as the prefix
|
|||||||
|A | 1 | 4 | A1 | 4 |
|
|A | 1 | 4 | A1 | 4 |
|
||||||
|Default| 15 | get | DefaultF | get |
|
|Default| 15 | get | DefaultF | get |
|
||||||
|
|
||||||
## T400
|
## T408
|
||||||
The T400 is a 12-bit stack machine operating at 1Hz (due to ABMs only running once per second). It has a 16-word stack, 0 registers and a very simple instruction set.
|
The T400 is an 8-bit stack machine operating at 1Hz (due to ABMs only running once per second). It has a 16-word stack, 0 registers and a very simple instruction set.
|
||||||
### Instructions
|
### Instructions
|
||||||
There are 8 instructions for the T400. Any values encountered by the processor that are not instructions are treated as data and pushed to the stack. While this does make both the code for the emulator and the code for the emulated computer simple, it has the downside that if you really do want the value 4095 you have to add two things together.
|
Any words encountered that aren't instructions are pushed to the stack. This makes very compact simple program code.
|
||||||
|
|
||||||
| ins | function | mnemonic |
|
| ins | function | mnemonic |
|
||||||
|--------|----------------------------------------------|---------------|
|
|-------|-----------------------------------------------|---------------|
|
||||||
|4095 | push program counter | ppc |
|
| 255 | push program counter | ppc |
|
||||||
|4094 | swap TOS | swp |
|
| 254 | swap TOS | swp |
|
||||||
|4093 | read memory from TOS | read |
|
| 253 | read memory from TOS | read |
|
||||||
|4092 | write to memory from TOS | write |
|
| 252 | write to memory from TOS | write |
|
||||||
|4091 | add TOS | add |
|
| 251 | add TOS | add |
|
||||||
|4090 | suptract TOS | sub |
|
| 250 | suptract TOS | sub |
|
||||||
|4089 | jump to TOS | jmp |
|
| 249 | jump to TOS | jmp |
|
||||||
|4088 | skip if TOS = zero | sez |
|
| 248 | skip if TOS = zero | sez |
|
||||||
|4087 | jump if TOS = zero | jez |
|
| 247 | jump if TOS = zero | jez |
|
||||||
|4086 | jump to subroutine, push pc to retstack | jsr |
|
| 246 | jump to subroutine, push pc to retstack | jsr |
|
||||||
|4085 | return from subroutine, PC = top of retstack | ret |
|
| 245 | return from subroutine, PC = top of retstack | ret |
|
||||||
|4084 | duplicate TOS | dup |
|
| 244 | duplicate TOS | dup |
|
||||||
|4083 | drop TOS | drop |
|
| 243 | drop TOS | drop |
|
||||||
|
| 242 | halt processor | hlt |
|
||||||
|
| 241 | pre-read address at TOS | prd |
|
||||||
|
|
||||||
## T410
|
### I/O
|
||||||
The T410, is, in essence, the write instruction in a block. You put in an address and a value and it tries to write the value to that address.
|
The T408 uses memory-mapped I/O. This may seem like a stupid idea on a machine with 8-bit addressing but port-based I/O isn't hugely sane.
|
||||||
|
|
||||||
|
Address 224 to 239 (16 words) are used for access to external devices. In Minetest you need to execute the **prd** instruction first, though in an emulator that is treated as a no-op.
|
||||||
|
|
||||||
|
### Examples
|
||||||
|
Counts upwards from zero, writing the result to address 224 (<prefix>0)
|
||||||
|
```
|
||||||
|
1 -- push 1
|
||||||
|
251 -- add
|
||||||
|
244 -- dup
|
||||||
|
224 -- push 224
|
||||||
|
252 -- write result to 224
|
||||||
|
1 -- push 1
|
||||||
|
249 -- jump to 1
|
||||||
|
```
|
||||||
|
|
||||||
## T416
|
|
||||||
The T416 is a 16-word memory. It stores 16 ints and is accessed as described in the Memory access section.
|
|
||||||
|
@ -1,214 +0,0 @@
|
|||||||
local MEMSIZE=16
|
|
||||||
local SHUTUP = false
|
|
||||||
if not digiline then
|
|
||||||
print("Digilines not found.")
|
|
||||||
return
|
|
||||||
end
|
|
||||||
local path = minetest.get_modpath(minetest.get_current_modname())
|
|
||||||
local oldprint=print
|
|
||||||
local function print(...)
|
|
||||||
if SHUTUP then return end
|
|
||||||
for k,v in ipairs({...}) do
|
|
||||||
oldprint("[Test3D:T400] "..tostring(v))
|
|
||||||
end
|
|
||||||
end
|
|
||||||
print("Loading.")
|
|
||||||
|
|
||||||
local function pos2string(pos)
|
|
||||||
return tostring(pos.x)..","..tostring(pos.y)..","..tostring(pos.z)
|
|
||||||
end
|
|
||||||
|
|
||||||
local function push(pos,val)
|
|
||||||
local meta = minetest.get_meta(pos)
|
|
||||||
local sstring = ""
|
|
||||||
local sstab = string.split(meta:get_string("stack"),"\n")
|
|
||||||
sstab[#sstab+1] = tostring(tonumber(val) % 4096)
|
|
||||||
if #sstab > MEMSIZE then
|
|
||||||
table.remove(sstab,1)
|
|
||||||
end
|
|
||||||
for k,v in ipairs(sstab) do
|
|
||||||
sstring = sstring .. v .. "\n"
|
|
||||||
end
|
|
||||||
meta:set_string("stack",sstring)
|
|
||||||
end
|
|
||||||
local function pop(pos)
|
|
||||||
local meta = minetest.get_meta(pos)
|
|
||||||
local sstring = ""
|
|
||||||
local sstab = string.split(meta:get_string("stack"),"\n")
|
|
||||||
local sval = table.remove(sstab,#sstab)
|
|
||||||
for k,v in ipairs(sstab) do
|
|
||||||
sstring = sstring .. v .. "\n"
|
|
||||||
end
|
|
||||||
meta:set_string("stack",sstring)
|
|
||||||
if not sval then sval = 0 end
|
|
||||||
return tonumber(sval) % 4096
|
|
||||||
end
|
|
||||||
|
|
||||||
local function t400_digiline_receive(pos, node, channel, msg)
|
|
||||||
print("Digiline: "..tostring(pos.x)..","..tostring(pos.y)..","..tostring(pos.z).."; Channel: "..tostring(channel).."; Message: "..tostring(msg))
|
|
||||||
local meta = minetest.get_meta(pos)
|
|
||||||
print(meta:get_string("state").." "..meta:get_string("waitingfor"))
|
|
||||||
if meta:get_string("state") == "waitingdat" and meta:get_string("waitingfor") == channel then
|
|
||||||
print("got data")
|
|
||||||
push(pos,tonumber(msg))
|
|
||||||
meta:set_int("pc",meta:get_int("pc")+1)
|
|
||||||
meta:set_string("state","running")
|
|
||||||
print("finished getting data")
|
|
||||||
elseif meta:get_string("state") == "waitingins" and meta:get_string("waitingfor") == channel then
|
|
||||||
meta:set_int("ci",tonumber(msg))
|
|
||||||
meta:set_string("state","running")
|
|
||||||
end
|
|
||||||
end
|
|
||||||
print("Created T400 digiline function")
|
|
||||||
|
|
||||||
local function t400_set_meta(pos)
|
|
||||||
local meta = minetest.get_meta(pos)
|
|
||||||
local ms = ""
|
|
||||||
for i = 1, MEMSIZE do
|
|
||||||
ms = ms .. "0\n"
|
|
||||||
end
|
|
||||||
meta:set_string("stack",ms)
|
|
||||||
meta:set_string("retstack",ms)
|
|
||||||
meta:set_string("channel","Default")
|
|
||||||
meta:set_string("state","running")
|
|
||||||
meta:set_string("waitingfor","")
|
|
||||||
meta:set_int("pc",0)
|
|
||||||
meta:set_int("ci",0)
|
|
||||||
meta:set_string("formspec","size[5,5]\nlabel[0.4,0.5;T400 Execution Node]\nfield[0.5,2;4,1;channel;Channel prefix;${channel}]\nfield[0.5,3;4,1;pc;Program Counter;${pc}]field[0.5,4;4,1;state;State;${state}]")
|
|
||||||
end
|
|
||||||
minetest.register_node("test3d_t400:t400", {
|
|
||||||
description = "T400 Execution Node",
|
|
||||||
tiles = {
|
|
||||||
{
|
|
||||||
image="t400.png",
|
|
||||||
animation={
|
|
||||||
type = "vertical_frames",
|
|
||||||
aspect_w=16,
|
|
||||||
aspect_h=16,
|
|
||||||
length=18,
|
|
||||||
length=1.8,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
on_construct = t400_set_meta,
|
|
||||||
groups = {snappy=1,choppy=2,oddly_breakable_by_hand=2,flammable=3},
|
|
||||||
digiline = {
|
|
||||||
receptor = {},
|
|
||||||
effector = {
|
|
||||||
action = t400_digiline_receive
|
|
||||||
}
|
|
||||||
},
|
|
||||||
on_receive_fields = function(pos,_,fields,sender)
|
|
||||||
if fields.channel == nil then return end
|
|
||||||
local meta = minetest.get_meta(pos)
|
|
||||||
fields.channel = fields.channel or ""
|
|
||||||
meta:set_string("channel",fields.channel)
|
|
||||||
meta:set_string("pc",fields.pc)
|
|
||||||
meta:set_string("state",fields.state)
|
|
||||||
end
|
|
||||||
})
|
|
||||||
print("T400 node registered")
|
|
||||||
|
|
||||||
minetest.register_abm({
|
|
||||||
nodenames={"test3d_t400:t400"},
|
|
||||||
interval=0.1,
|
|
||||||
chance=1,
|
|
||||||
action = function(pos)
|
|
||||||
local meta = minetest.get_meta(pos)
|
|
||||||
local nins = 1
|
|
||||||
if meta:get_string("state") == "running" then
|
|
||||||
local skipnext = false
|
|
||||||
print("Attempting to run T400 node at "..pos2string(pos))
|
|
||||||
local ci = meta:get_int("ci")
|
|
||||||
if ci == 4095 then -- ppc
|
|
||||||
push(pos,meta:get_int("pc"))
|
|
||||||
elseif ci == 4094 then -- swp - why do I have this?
|
|
||||||
local a = pop(pos)
|
|
||||||
local b = pop(pos)
|
|
||||||
print("Swapping "..tostring(a).." for "..tostring(b))
|
|
||||||
push(pos,b)
|
|
||||||
push(pos,a)
|
|
||||||
elseif ci == 4093 then -- read
|
|
||||||
skipnext = true
|
|
||||||
local addr = pop(pos)
|
|
||||||
meta:set_string("state","waitingdat")
|
|
||||||
meta:set_string("waitingfor",meta:get_string("channel")..string.format("%X",addr))
|
|
||||||
meta:set_int("pc",meta:get_int("pc")+nins)
|
|
||||||
digiline:receptor_send(pos,digiline.rules.default,meta:get_string("channel")..string.format("%X",addr),"get")
|
|
||||||
return
|
|
||||||
elseif ci == 4092 then -- write
|
|
||||||
local addr = pop(pos)
|
|
||||||
local dat = pop(pos)
|
|
||||||
print("Writing "..tostring(dat).." to address "..addr)
|
|
||||||
digiline:receptor_send(pos,digiline.rules.default,meta:get_string("channel")..string.format("%X",addr),dat)
|
|
||||||
elseif ci == 4091 then -- add
|
|
||||||
print("Adding stuff")
|
|
||||||
push(pos,pop(pos)+pop(pos))
|
|
||||||
elseif ci == 4090 then -- sub
|
|
||||||
push(pos,pop(pos)-pop(pos))
|
|
||||||
elseif ci == 4089 then -- jmp
|
|
||||||
local npc = pop(pos)
|
|
||||||
print("Jumping to "..tostring(npc))
|
|
||||||
meta:set_int("pc",npc)
|
|
||||||
nins=0
|
|
||||||
elseif ci == 4088 then -- sez
|
|
||||||
local val = pop(pos)
|
|
||||||
print(val,type(val))
|
|
||||||
if val == 0 then
|
|
||||||
print("Skipping because "..tostring(val).." = 0")
|
|
||||||
nins=nins+1
|
|
||||||
end
|
|
||||||
elseif ci == 4087 then -- jez
|
|
||||||
local addr = pop(pos)
|
|
||||||
local val = pop(pos)
|
|
||||||
if val == 0 then
|
|
||||||
print("Jumping to "..addr.." because "..val.." = 0")
|
|
||||||
meta:set_int("pc",addr)
|
|
||||||
nins=0
|
|
||||||
end
|
|
||||||
elseif ci == 4086 then -- jsr
|
|
||||||
local sstring = ""
|
|
||||||
local sstab = string.split(meta:get_string("retstack"),"\n")
|
|
||||||
sstab[#sstab+1] = tostring(tonumber(meta:get_int("pc")) % 4096)
|
|
||||||
if #sstab > MEMSIZE then
|
|
||||||
table.remove(sstab,1)
|
|
||||||
end
|
|
||||||
for k,v in ipairs(sstab) do
|
|
||||||
sstring = sstring .. v .. "\n"
|
|
||||||
end
|
|
||||||
meta:set_string("retstack",sstring)
|
|
||||||
meta:set_int("pc",pop(pos))
|
|
||||||
nins=0
|
|
||||||
elseif ci == 4085 then -- ret
|
|
||||||
local sstring = ""
|
|
||||||
local sstab = string.split(meta:get_string("retstack"),"\n")
|
|
||||||
local sval = tonumber(table.remove(sstab,#sstab))
|
|
||||||
for k,v in ipairs(sstab) do
|
|
||||||
sstring = sstring .. v .. "\n"
|
|
||||||
end
|
|
||||||
meta:set_string("retstack",sstring)
|
|
||||||
if not sval then sval = 0 end
|
|
||||||
meta:set_int("pc",sval)
|
|
||||||
elseif ci == 4084 then -- dup
|
|
||||||
local v = pop(pos)
|
|
||||||
push(pos,v)
|
|
||||||
push(pos,v)
|
|
||||||
print("Duplicating "..v)
|
|
||||||
elseif ci == 4083 then -- drop
|
|
||||||
print("Dropping stuff")
|
|
||||||
pop(pos)
|
|
||||||
else
|
|
||||||
print("Pushing "..ci.." to "..pos2string(pos))
|
|
||||||
push(pos,ci)
|
|
||||||
end
|
|
||||||
if not skipnext then
|
|
||||||
meta:set_int("pc",meta:get_int("pc")+nins)
|
|
||||||
meta:set_string("state","waitingins")
|
|
||||||
meta:set_string("waitingfor",meta:get_string("channel")..string.format("%X",meta:get_int("pc")))
|
|
||||||
digiline:receptor_send(pos, digiline.rules.default, meta:get_string("channel")..string.format("%X",meta:get_int("pc")), "get")
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
})
|
|
||||||
print("T400 ABM registered")
|
|
||||||
print("T400 init finished")
|
|
58
test3d_t408/emut408.lua
Normal file
58
test3d_t408/emut408.lua
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
stab = {}
|
||||||
|
stab.stack = {}
|
||||||
|
stab.pc = 1
|
||||||
|
stab.cins = 0
|
||||||
|
mem = {}
|
||||||
|
t408 = require "t408"
|
||||||
|
|
||||||
|
while true do
|
||||||
|
io.write("*> ")
|
||||||
|
i=io.read()
|
||||||
|
it = {}
|
||||||
|
for s in i:gmatch("%S+") do it[#it+1] = s end
|
||||||
|
if it[1] == "quit" then
|
||||||
|
break
|
||||||
|
elseif it[1] == "peek" then
|
||||||
|
print(mem[tonumber(it[2])])
|
||||||
|
elseif it[1] == "poke" then
|
||||||
|
mem[tonumber(it[2])] = tonumber(it[3])
|
||||||
|
elseif it[1] == "push" then
|
||||||
|
stab.stack[#stab.stack+1] = tonumber(it[2])
|
||||||
|
elseif it[1] == "dumpstack" then
|
||||||
|
for k,v in ipairs(stab.stack) do print(k,v) end
|
||||||
|
elseif it[1] == "ppc" then
|
||||||
|
print(stab.pc)
|
||||||
|
elseif it[1] == "spc" then
|
||||||
|
stab.pc=tonumber(it[2])
|
||||||
|
elseif it[1] == "step" then
|
||||||
|
local scount = tonumber(it[2]) or 1
|
||||||
|
for i = 1, scount do
|
||||||
|
stab.cins = mem[stab.pc]
|
||||||
|
stab,rw,addr,val=t408.run(stab)
|
||||||
|
--print(rw,addr,val)
|
||||||
|
if rw == "halt" then print("Halted at "..tostring(stab.pc) )break end
|
||||||
|
if rw == "read" then
|
||||||
|
stab.stack[#stab.stack+1] = mem[addr]
|
||||||
|
elseif rw == "write" then
|
||||||
|
mem[addr] = val
|
||||||
|
if addr == 0 then io.write(string.char(val)) end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
elseif it[1] == "debug" then
|
||||||
|
print(not t408.debug)
|
||||||
|
t408.debug = not t408.debug
|
||||||
|
elseif it[1] == "load" then
|
||||||
|
local f,e = io.open(it[2])
|
||||||
|
if f == nil then
|
||||||
|
print("Error: "..e)
|
||||||
|
else
|
||||||
|
local n = tonumber(it[3]) or 0
|
||||||
|
local c = f:read("*a")
|
||||||
|
f:close()
|
||||||
|
for v in c:gmatch("%d+") do
|
||||||
|
mem[n] = tonumber(v) or 0
|
||||||
|
n = n + 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
198
test3d_t408/init.lua
Normal file
198
test3d_t408/init.lua
Normal file
@ -0,0 +1,198 @@
|
|||||||
|
local MEMSIZE=16
|
||||||
|
local path = minetest.get_modpath(minetest.get_current_modname())
|
||||||
|
local t408_mem, t408_stab = {},{}
|
||||||
|
print("Looking for memory file at "..path.."/mem.dat")
|
||||||
|
local f=io.open(path.."/mem.dat","rb")
|
||||||
|
if f ~= nil then
|
||||||
|
local c = f:read("*a")
|
||||||
|
print("Found T408 memory file.")
|
||||||
|
-- rawset(_G,"t408_mem",minetest.deserialize(c))
|
||||||
|
t408_mem = minetest.deserialize(c)
|
||||||
|
print("Contents: "..c)
|
||||||
|
f:close()
|
||||||
|
end
|
||||||
|
print("Looking for metadata file at "..path.."/stab.dat")
|
||||||
|
local f=io.open(path.."/stab.dat","rb")
|
||||||
|
if f ~= nil then
|
||||||
|
print("Found T408 metadata file.")
|
||||||
|
local c = f:read("*a")
|
||||||
|
t408_stab = minetest.deserialize(c)
|
||||||
|
print("Contents: "..c)
|
||||||
|
f:close()
|
||||||
|
end
|
||||||
|
local t408 = dofile(path.."/t408.lua")
|
||||||
|
t408.debug = true
|
||||||
|
print(type(_G.t408_mem))
|
||||||
|
if not digiline then
|
||||||
|
print("Digilines not found.")
|
||||||
|
return
|
||||||
|
end
|
||||||
|
local oldprint=print
|
||||||
|
local function print(...)
|
||||||
|
for k,v in ipairs({...}) do
|
||||||
|
oldprint("[Test3D:T408] "..tostring(v))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
print("Loading.")
|
||||||
|
|
||||||
|
local function t408_digiline_receive(pos, node, channel, msg)
|
||||||
|
local meta = minetest.get_meta(pos)
|
||||||
|
local nid = minetest.pos_to_string(pos)
|
||||||
|
local prea,preb = string.find(channel,meta:get_string("channel"))
|
||||||
|
print("Start channel: "..prea,"End channel: "..preb)
|
||||||
|
print("Recieved (pre)"..tostring(msg).." from "..tostring(channel).." (device channel: "..tostring(meta:get_string("channel"))..")")
|
||||||
|
if prea == 1 then
|
||||||
|
--if string.sub(channel,1,meta:get_string("channel"):len()) == meta:get_string("channel") then
|
||||||
|
-- local addr = tonumber(msg:sub(meta:get_string("channel"):len()+1))
|
||||||
|
-- local addr = tonumber(channel)
|
||||||
|
print("Correct channel.")
|
||||||
|
local addr = tonumber(string.sub(channel,preb+1))
|
||||||
|
print(addr)
|
||||||
|
if addr > -1 and addr < 16 then
|
||||||
|
print("Recieved "..tostring(msg).." from "..tostring(channel).." for "..tostring(addr).." (device channel: "..tostring(meta:get_string("channel"))..")")
|
||||||
|
t408_mem[nid][addr+224] = tonumber(msg)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
--end
|
||||||
|
end
|
||||||
|
print("Created T408 digiline function")
|
||||||
|
|
||||||
|
local function t408_read(pos,addr)
|
||||||
|
if t408_mem[pos] == nil then return false end
|
||||||
|
print("Read: "..tostring(pos).." "..tostring(addr)..": "..tostring(t408_mem[pos][addr]))
|
||||||
|
return t408_mem[pos][addr] or 0
|
||||||
|
end
|
||||||
|
local function t408_write(pos,addr,val)
|
||||||
|
print(tostring(pos).." "..tostring(addr).." "..tostring(val))
|
||||||
|
if t408_mem[pos] == nil then return false end
|
||||||
|
t408_mem[pos][tonumber(addr)] = (tonumber(val)%256)
|
||||||
|
print("Write: "..tostring(pos).." "..tostring(addr)..": "..tostring(t408_mem[pos][addr]).." = "..tostring(val))
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
local function t408_set_meta(pos)
|
||||||
|
local meta = minetest.get_meta(pos)
|
||||||
|
meta:set_string("channel","")
|
||||||
|
meta:set_string("state","running")
|
||||||
|
t408_mem[minetest.pos_to_string(pos)] = {}
|
||||||
|
t408_stab[minetest.pos_to_string(pos)] = {["ci"]=1,["pc"]=1,["stack"]={},["rstack"]={}}
|
||||||
|
print("Created T408 memory table with ID "..minetest.pos_to_string(pos))
|
||||||
|
end
|
||||||
|
minetest.register_node("test3d_t408:t408", {
|
||||||
|
description = "T408 Memory Node",
|
||||||
|
tiles = {{image="t408.png",animation={type="vertical_frames",aspect_w=16,aspect_h=16,length=1.8}}},
|
||||||
|
on_construct = t408_set_meta,
|
||||||
|
groups = {snappy=1,choppy=2,oddly_breakable_by_hand=2,flammable=3},
|
||||||
|
digiline = {
|
||||||
|
receptor = {},
|
||||||
|
effector = {
|
||||||
|
action = function (a,b,c,d) pcall(t408_digiline_receive,a,b,c,d) end
|
||||||
|
}
|
||||||
|
},
|
||||||
|
on_punch = function(pos,_,fields,sender)
|
||||||
|
-- if fields.channel == nil then return end
|
||||||
|
local meta = minetest.get_meta(pos)
|
||||||
|
-- fields.channel = fields.channel or ""
|
||||||
|
-- meta:set_string("channel",fields.channel)
|
||||||
|
if meta:get_string("state") == "running" then
|
||||||
|
meta:set_string("state","halted")
|
||||||
|
else
|
||||||
|
meta:set_string("state","running")
|
||||||
|
end
|
||||||
|
print(meta:get_string("state"))
|
||||||
|
end
|
||||||
|
})
|
||||||
|
minetest.register_chatcommand("test3d-t408-read", {
|
||||||
|
params = "<node ID> <address>",
|
||||||
|
description = "Read the memory in a T408 node",
|
||||||
|
func = function(name,str)
|
||||||
|
local tArg = {}
|
||||||
|
for s in str:gmatch("%S+") do
|
||||||
|
tArg[#tArg+1] = s
|
||||||
|
end
|
||||||
|
local nid,addr = tArg[1],tArg[2]
|
||||||
|
print(nid,addr)
|
||||||
|
minetest.chat_send_player(name,tostring(t408_read(nid,tonumber(addr))))
|
||||||
|
end
|
||||||
|
})
|
||||||
|
minetest.register_chatcommand("test3d-t408-write", {
|
||||||
|
params = "<node ID> <address> <new value>",
|
||||||
|
description = "Read the memory in a T408 node",
|
||||||
|
func = function(name,str)
|
||||||
|
local tArg = {}
|
||||||
|
for s in str:gmatch("%S+") do
|
||||||
|
tArg[#tArg+1] = s
|
||||||
|
end
|
||||||
|
local nid,addr,val = tArg[1],tArg[2],tArg[3]
|
||||||
|
print(nid,addr,val)
|
||||||
|
minetest.chat_send_player(name,tostring(t408_write(nid,tonumber(addr),tostring(val))))
|
||||||
|
end
|
||||||
|
})
|
||||||
|
minetest.register_chatcommand("test3d-t408-set", {
|
||||||
|
params = "<node ID> <variable> <new value>",
|
||||||
|
description = "Set T408 variables.",
|
||||||
|
func = function(name,str)
|
||||||
|
local tArg = {}
|
||||||
|
for s in str:gmatch("%S+") do
|
||||||
|
tArg[#tArg+1] = s
|
||||||
|
end
|
||||||
|
local nid,addr,val = tArg[1],tArg[2],tArg[3]
|
||||||
|
local meta = minetest.get_meta(minetest.string_to_pos(nid))
|
||||||
|
meta:set_string(addr,tArg[3] or "")
|
||||||
|
print("Set "..nid.."'s "..addr.." to "..(tArg[3] or ""))
|
||||||
|
end
|
||||||
|
})
|
||||||
|
minetest.register_chatcommand("test3d-t408-dump", {
|
||||||
|
params = "<node ID> <address> <new value>",
|
||||||
|
description = "Read the memory in a T408 node",
|
||||||
|
func = function(name,nid,addr,val)
|
||||||
|
for k,v in ipairs(t408_mem) do
|
||||||
|
print(k,v)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
})
|
||||||
|
|
||||||
|
print("T408 node registered")
|
||||||
|
|
||||||
|
minetest.register_abm({
|
||||||
|
nodenames={"test3d_t408:t408"},
|
||||||
|
interval=1,
|
||||||
|
chance=1,
|
||||||
|
action = function(pos)
|
||||||
|
local meta = minetest.get_meta(pos)
|
||||||
|
if meta:get_string("state") == "running" then
|
||||||
|
local nid = minetest.pos_to_string(pos)
|
||||||
|
local stab,rw,addr,val = t408_stab[nid],nil,0,0
|
||||||
|
stab.cins = t408_mem[nid][stab.pc]
|
||||||
|
stab,rw,addr,val = t408.run(stab)
|
||||||
|
if rw == "read" then
|
||||||
|
stab.stack[#stab.stack+1] = t408_mem[nid][addr]
|
||||||
|
elseif rw == "preread" then
|
||||||
|
if addr > 223 and addr < 240 then
|
||||||
|
digiline:receptor_send(pos,digiline.rules.default,meta:get_string("channel")..string.format("%X",tonumber(addr)-224),"get")
|
||||||
|
end
|
||||||
|
elseif rw == "write" then
|
||||||
|
t408_mem[nid][addr] = tonumber(val)
|
||||||
|
print("Writing "..tostring(val).." to "..tostring(addr))
|
||||||
|
if addr > 223 and addr < 240 then
|
||||||
|
digiline:receptor_send(pos,digiline.rules.default,meta:get_string("channel")..string.format("%X",tonumber(addr)-224),tonumber(val))
|
||||||
|
print(string.char(val))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
t408_stab[nid] = stab
|
||||||
|
end
|
||||||
|
end
|
||||||
|
})
|
||||||
|
|
||||||
|
minetest.register_on_shutdown(function()
|
||||||
|
local f=io.open(path.."/mem.dat","wb")
|
||||||
|
if f then
|
||||||
|
f:write(minetest.serialize(t408_mem))
|
||||||
|
f:close()
|
||||||
|
end
|
||||||
|
local f=io.open(path.."/stab.dat","wb")
|
||||||
|
if f then
|
||||||
|
f:write(minetest.serialize(t408_stab))
|
||||||
|
f:close()
|
||||||
|
end
|
||||||
|
end)
|
@ -1,3 +1,4 @@
|
|||||||
|
local MAXADDR = 255
|
||||||
local t = {}
|
local t = {}
|
||||||
-- internal state
|
-- internal state
|
||||||
--- program counter (pc)
|
--- program counter (pc)
|
||||||
@ -8,16 +9,19 @@ local function pop(s)
|
|||||||
end
|
end
|
||||||
local function push(s,v)
|
local function push(s,v)
|
||||||
v=v or 0
|
v=v or 0
|
||||||
s[#s+1] = v%4096
|
s[#s+1] = v%256
|
||||||
if #s > 16 then
|
if #s > 16 then
|
||||||
table.remove(s,1)
|
table.remove(s,1)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function t.run(stab)
|
function t.run(stab,ov)
|
||||||
-- variables
|
-- variables
|
||||||
local pc = stab.pc or 1
|
local pc = stab.pc or 1
|
||||||
local ci = stab.cins or 0
|
local ci = stab.cins or 0
|
||||||
|
if ov then
|
||||||
|
ci = tonumber(ov) or 0
|
||||||
|
end
|
||||||
local stack = stab.stack or {}
|
local stack = stab.stack or {}
|
||||||
local rstack = stab.rstack or {}
|
local rstack = stab.rstack or {}
|
||||||
local pci = 1
|
local pci = 1
|
||||||
@ -25,60 +29,68 @@ function t.run(stab)
|
|||||||
local addr = 0
|
local addr = 0
|
||||||
local dat = 0
|
local dat = 0
|
||||||
-- instruction processing
|
-- instruction processing
|
||||||
if ci == 4095 then -- ppc
|
if ci == 255 then -- ppc
|
||||||
push(stack,pc)
|
push(stack,pc)
|
||||||
elseif ci == 4094 then -- swp
|
elseif ci == 254 then -- swp
|
||||||
a=pop(stack)
|
a=pop(stack)
|
||||||
b=pop(stack)
|
b=pop(stack)
|
||||||
push(stack,a)
|
push(stack,a)
|
||||||
pusk(stack,b)
|
push(stack,b)
|
||||||
elseif ci == 4093 then -- read
|
elseif ci == 253 then -- read
|
||||||
rw = "read" -- terrible IPC
|
rw = "read" -- terrible IPC
|
||||||
addr = pop(stack)
|
addr = pop(stack)
|
||||||
elseif ci == 4092 then -- write
|
elseif ci == 252 then -- write
|
||||||
rw = "write"
|
rw = "write"
|
||||||
addr = pop(stack)
|
addr = pop(stack)
|
||||||
dat = pop(stack)
|
dat = pop(stack)
|
||||||
elseif ci == 4091 then -- add
|
--print("writing "..tostring(dat).." to "..tostring(addr))
|
||||||
|
elseif ci == 251 then -- add
|
||||||
push(stack,pop(stack)+pop(stack))
|
push(stack,pop(stack)+pop(stack))
|
||||||
elseif ci == 4090 then -- sub
|
elseif ci == 250 then -- sub
|
||||||
push(stack,pop(stack)+pop(stack))
|
push(stack,pop(stack)+pop(stack))
|
||||||
elseif ci == 4089 then -- jmp
|
elseif ci == 249 then -- jmp
|
||||||
pc = pop(stack)
|
pc = pop(stack)
|
||||||
pci = 0
|
pci = 0
|
||||||
elseif ci == 4088 then -- sez
|
elseif ci == 248 then -- sez
|
||||||
if pop(stack) == 0 then
|
if pop(stack) == 0 then
|
||||||
pci = pci + 1
|
pci = pci + 1
|
||||||
end
|
end
|
||||||
elseif ci == 4087 then -- jez
|
elseif ci == 247 then -- jez
|
||||||
local a = pop(stack)
|
local a = pop(stack)
|
||||||
if pop(stack) == 0 then
|
if pop(stack) == 0 then
|
||||||
pc = a
|
pc = a
|
||||||
pci = 0
|
pci = 0
|
||||||
end
|
end
|
||||||
elseif ci == 4086 then -- jsr
|
elseif ci == 246 then -- jsr
|
||||||
push(rstack,pc)
|
push(rstack,pc)
|
||||||
pc = pop(stack)
|
pc = pop(stack)
|
||||||
pci = 0
|
pci = 0
|
||||||
elseif ci == 4085 then -- ret
|
elseif ci == 245 then -- ret
|
||||||
pc = pop(rstack)
|
pc = pop(rstack)
|
||||||
elseif ci == 4084 then -- dup
|
elseif ci == 244 then -- dup
|
||||||
local v = pop(stack)
|
local v = pop(stack)
|
||||||
push(stack,v)
|
push(stack,v)
|
||||||
push(stack,v)
|
push(stack,v)
|
||||||
elseif ci == 4083 then -- drop
|
elseif ci == 243 then -- drop
|
||||||
pop(stack)
|
pop(stack)
|
||||||
elseif ci == 4082 then -- hlt
|
elseif ci == 242 then -- hlt
|
||||||
rw = "halt"
|
rw = "halt"
|
||||||
|
elseif ci == 241 then -- prd
|
||||||
|
rw = "preread"
|
||||||
|
addr = pop(stack)
|
||||||
else
|
else
|
||||||
push(stack,ci)
|
push(stack,ci)
|
||||||
end
|
end
|
||||||
-- return stuff
|
-- return stuff
|
||||||
stab = {}
|
stab = {}
|
||||||
stab.pc = pc + pci -- increment pc
|
stab.pc = pc + pci -- increment pc
|
||||||
|
if stab.pc > MAXADDR then
|
||||||
|
stab.pc = 0
|
||||||
|
end
|
||||||
stab.cins = 0
|
stab.cins = 0
|
||||||
stab.stack = stack
|
stab.stack = stack
|
||||||
stab.rstack = rstack
|
stab.rstack = rstack
|
||||||
|
if t.debug then print("t408: pc: "..tostring(stab.pc),"cins: "..tostring(ci),"tos: "..tostring(stab.stack[1]).." #s: "..tostring(#stab.stack),stab.rw,stab.addr,stab.dat) end
|
||||||
return stab, rw, addr, dat
|
return stab, rw, addr, dat
|
||||||
end
|
end
|
||||||
|
|
Before Width: | Height: | Size: 778 B After Width: | Height: | Size: 778 B |
@ -1,2 +0,0 @@
|
|||||||
default
|
|
||||||
digilines
|
|
@ -1,30 +0,0 @@
|
|||||||
if not digiline then
|
|
||||||
print("Digilines not found.")
|
|
||||||
return
|
|
||||||
end
|
|
||||||
local oldprint=print
|
|
||||||
local function print(...)
|
|
||||||
for k,v in ipairs({...}) do
|
|
||||||
oldprint("[Test3D:T410] "..tostring(v))
|
|
||||||
end
|
|
||||||
end
|
|
||||||
print("Loading.")
|
|
||||||
|
|
||||||
local function t410_set_meta(pos)
|
|
||||||
minetest.get_meta(pos):set_string("formspec","size[2,4]\nfield[0,1;2.9,1;addr;Address;]\nfield[0,2;2.9,1;data;Data;]\nbutton[0,3;2,1;write;Write]")
|
|
||||||
end
|
|
||||||
minetest.register_node("test3d_t410:t410", {
|
|
||||||
description = "T410 Memory Access Console",
|
|
||||||
tiles = {"t416-top.png","t416-top.png","t416-side.png","t416-side.png","t416-side.png","t416-side.png"},
|
|
||||||
on_construct = t410_set_meta,
|
|
||||||
groups = {snappy=1,choppy=2,oddly_breakable_by_hand=2,flammable=3},
|
|
||||||
on_receive_fields = function(pos,_,fields,sender)
|
|
||||||
if fields.addr == nil then return end
|
|
||||||
digiline:receptor_send(pos, digiline.rules.default, fields.addr, tonumber(fields.data) or 0)
|
|
||||||
print("Set "..fields.addr.." to "..fields.data)
|
|
||||||
end,
|
|
||||||
digiline = {
|
|
||||||
receptor = {},
|
|
||||||
},
|
|
||||||
})
|
|
||||||
print("T410 node registered")
|
|
Binary file not shown.
Before Width: | Height: | Size: 217 B |
Binary file not shown.
Before Width: | Height: | Size: 301 B |
@ -1,2 +0,0 @@
|
|||||||
default
|
|
||||||
digilines
|
|
@ -1,68 +0,0 @@
|
|||||||
local MEMSIZE=16
|
|
||||||
if not digiline then
|
|
||||||
print("Digilines not found.")
|
|
||||||
return
|
|
||||||
end
|
|
||||||
local oldprint=print
|
|
||||||
local function print(...)
|
|
||||||
for k,v in ipairs({...}) do
|
|
||||||
oldprint("[Test3D:T416] "..tostring(v))
|
|
||||||
end
|
|
||||||
end
|
|
||||||
print("Loading.")
|
|
||||||
|
|
||||||
local function t416_digiline_receive(pos, node, channel, msg)
|
|
||||||
--print("Digiline: "..tostring(pos.x)..","..tostring(pos.y)..","..tostring(pos.z).."; Channel: "..tostring(channel).."; Message: "..tostring(msg))
|
|
||||||
local meta = minetest.get_meta(pos)
|
|
||||||
local mem = string.split(meta:get_string("mem"),"\n")
|
|
||||||
local ms = ""
|
|
||||||
local chan = meta:get_string("channel")
|
|
||||||
local memoffset = meta:get_int("startaddr")
|
|
||||||
if channel:sub(1,#chan) == chan and tonumber(channel:sub(#chan+1),16)+1-memoffset <= MEMSIZE and tonumber(channel:sub(#chan+1),16)+1-memoffset > 0 then
|
|
||||||
local memaddr = tonumber(channel:sub(#chan+1),16)+1-memoffset
|
|
||||||
if tostring(msg):lower() == "get" then
|
|
||||||
digiline:receptor_send(pos, digiline.rules.default, channel, tonumber(mem[memaddr] or 0))
|
|
||||||
print("Reading address "..tostring(memaddr)..": "..tostring(mem[memaddr]))
|
|
||||||
else
|
|
||||||
mem[memaddr] = tonumber(msg) or 0
|
|
||||||
for k,v in ipairs(mem) do
|
|
||||||
ms = ms .. tostring(v) .. "\n"
|
|
||||||
end
|
|
||||||
meta:set_string("mem",ms)
|
|
||||||
print("Set address "..tostring(memaddr).." to "..tostring(tonumber(msg)))
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
print("Created T416 digiline function")
|
|
||||||
|
|
||||||
local function t416_set_meta(pos)
|
|
||||||
local meta = minetest.get_meta(pos)
|
|
||||||
local ms = ""
|
|
||||||
for i = 1, MEMSIZE do
|
|
||||||
ms = ms .. "0\n"
|
|
||||||
end
|
|
||||||
meta:set_string("mem",ms)
|
|
||||||
meta:set_string("channel","Default")
|
|
||||||
meta:set_int("startaddr",0)
|
|
||||||
meta:set_string("formspec","size[5,12]\nlabel[0.4,0.5;T416 Memory Node (16 words)]\nfield[0.5,2;4,1;channel;Channel prefix;${channel}]\nfield[0.5,3;4,1;startaddr;Starting address;${startaddr}]\ntextarea[0.5,4;4,8;mem;Memory contents;${mem}]")
|
|
||||||
end
|
|
||||||
minetest.register_node("test3d_t416:t416", {
|
|
||||||
description = "T416 Memory Node",
|
|
||||||
tiles = {"t416-top.png","t416-top.png","t416-side.png","t416-side.png","t416-side.png","t416-side.png"},
|
|
||||||
on_construct = t416_set_meta,
|
|
||||||
groups = {snappy=1,choppy=2,oddly_breakable_by_hand=2,flammable=3},
|
|
||||||
digiline = {
|
|
||||||
receptor = {},
|
|
||||||
effector = {
|
|
||||||
action = function (a,b,c,d) pcall(t416_digiline_receive,a,b,c,d) end
|
|
||||||
}
|
|
||||||
},
|
|
||||||
on_receive_fields = function(pos,_,fields,sender)
|
|
||||||
if fields.channel == nil then return end
|
|
||||||
local meta = minetest.get_meta(pos)
|
|
||||||
fields.channel = fields.channel or ""
|
|
||||||
meta:set_string("channel",fields.channel)
|
|
||||||
meta:set_int("startaddr",tonumber(fields.startaddr))
|
|
||||||
end
|
|
||||||
})
|
|
||||||
print("T416 node registered")
|
|
Binary file not shown.
Before Width: | Height: | Size: 217 B |
Binary file not shown.
Before Width: | Height: | Size: 301 B |
Loading…
Reference in New Issue
Block a user