RAM.lua 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339
  1. --[[
  2. Layout (96 KB)
  3. --------------
  4. 0x0000 Meta Data (736 Bytes)
  5. 0x02E0 SpriteMap (12 KB)
  6. 0x32E0 Flags Data (288 Bytes)
  7. 0x3400 MapData (18 KB)
  8. 0x7C00 Sound Tracks (13 KB)
  9. 0xB000 Compressed Lua Code (20 KB)
  10. 0x10000 Persistant Data (2 KB)
  11. 0x10800 GPIO (128 Bytes)
  12. 0x10880 Reserved (768 Bytes)
  13. 0x10B80 Draw State (64 Bytes)
  14. 0x10BC0 Reserved (64 Bytes)
  15. 0x10C00 Free Space (1 KB)
  16. 0x11000 Reserved (4 KB)
  17. 0x12000 Label Image (12 KBytes)
  18. 0x15000 VRAM (12 KBytes)
  19. 0x18000 End of memory (Out of range)
  20. Meta Data (1 KB)
  21. ----------------
  22. 0x0000 Data Length (6 Bytes)
  23. 0x0006 LIKO-12 Header (7 Bytes)
  24. 0x000D Color Palette (64 Bytes)
  25. 0x004D Disk Version (1 Byte)
  26. 0x004E Disk Meta (1 Byte)
  27. 0x004F Screen Width (2 Bytes)
  28. 0x0051 Screen Hight (2 Bytes)
  29. 0x0053 Reserved (1 Byte)
  30. 0x0054 SpriteMap Address (4 Bytes)
  31. 0x0058 MapData Address (4 Bytes)
  32. 0x005C Instruments Data Address (4 Bytes)
  33. 0x0060 Tracks Data Address (4 Bytes)
  34. 0x0064 Tracks Orders Address (4 Bytes)
  35. 0x0068 Compressed Lua Code Address (4 Bytes)
  36. 0x006C Author Name (16 Bytes)
  37. 0x007C Game Name (16 Bytes)
  38. 0x008C SpriteSheet Width (2 Bytes)
  39. 0x008E SpriteSheet Height (2 Bytes)
  40. 0x0090 Map Width (1 Byte)
  41. 0x0091 Map height (1 Byte)
  42. 0x0093 Reserved (594 Bytes)
  43. Disk META:
  44. --------------
  45. 1. Auto event loop.
  46. 2. Activate controllers.
  47. 3. Keyboad Only.
  48. 4. Mobile Friendly.
  49. 5. Static Resolution.
  50. 6. Compatibilty Mode.
  51. 7. Write Protection.
  52. 8. Licensed Under CC0.
  53. ]]
  54. local coreg = require("Engine.coreg") --Require the coroutine registry.
  55. return function(config)
  56. local ramsize = 0 --The current size of the ram
  57. local ram = {} --The RAM table (Only affected by the default handler)
  58. local handlers = {} --The active ram handlers system
  59. local layout = config.layout or {{88*1024}} --Defaults to a 88KB RAM.
  60. local devkit = {} --The devkit of the RAM
  61. --function to convert a number into a hex string.
  62. local function tohex(a) return string.format("0x%X",a or 0) end
  63. function devkit.addHandler(startAddress, endAddress, handler)
  64. if type(startAddress) ~= "number" then return error("Start address must be a number, provided: "..type(startAddress)) end
  65. if type(endAddress) ~= "number" then return error("End address must be a number, provided: "..type(endAddress)) end
  66. if type(handler) ~= "function" then return error("Handler must be a function, provided: "..type(handler)) end
  67. table.insert(handlers,{startAddr = startAddress, endAddr = endAddress, handler = handler})
  68. end
  69. --A binary handler.
  70. function devkit.defaultHandler(mode,startAddress,...)
  71. local args = {...}
  72. if mode == "poke" then
  73. local address, value = unpack(args)
  74. ram[address] = value
  75. elseif mode == "poke4" then
  76. local address4, value = unpack(args)
  77. local address = math.floor(address4 / 2)
  78. local byte = ram[address]
  79. if address4 % 2 == 0 then --left nibble
  80. byte = bit.band(byte,0x0F)
  81. value = bit.rshift(value,4)
  82. byte = bit.bor(byte,value)
  83. else --right nibble
  84. byte = bit.band(byte,0xF0)
  85. byte = bit.bor(byte,value)
  86. end
  87. ram[address] = byte
  88. elseif mode == "peek" then
  89. local address = args[1]
  90. return ram[address]
  91. elseif mode == "peek4" then
  92. local address4 = args[1]
  93. local address = math.floor(address4 / 2)
  94. local byte = ram[address]
  95. if address4 % 2 == 0 then --left nibble
  96. byte = bit.lshift(byte,4)
  97. else --right nibble
  98. byte = bit.band(byte,0x0F)
  99. end
  100. return byte
  101. elseif mode == "memcpy" then
  102. local from, to, len = unpack(args)
  103. for i=0,len-1 do
  104. ram[to+i] = ram[from+i]
  105. end
  106. elseif mode == "memset" then
  107. local address, value = unpack(args)
  108. local len = value:len()
  109. for i=0,len-1 do
  110. ram[address+i] = string.byte(value,i+1)
  111. end
  112. elseif mode == "memget" then
  113. local address, len = unpack(args)
  114. local subtable,nextid = {}, 1
  115. for i=address,address+len-1 do
  116. subtable[nextid] = ram[i]
  117. nextid = nextid + 1
  118. end
  119. if len > 255 then
  120. for i=1,nextid-1 do
  121. subtable[i] = string.char(subtable[i])
  122. end
  123. return table.concat(subtable)
  124. else
  125. return string.char(unpack(subtable))
  126. end
  127. end
  128. end
  129. --Build the layout.
  130. for k, section in ipairs(layout) do
  131. local size = section[1]
  132. local handler = section[2] or devkit.defaultHandler
  133. local startAddress = ramsize
  134. ramsize = ramsize + size
  135. local endAddress = ramsize-1
  136. print("Layout ["..k.."]: "..tohex(startAddress).." -> ".. tohex(endAddress))
  137. devkit.addHandler(startAddress,endAddress,handler)
  138. --Extend the ram table
  139. for i=#ram, #ram+size do
  140. ram[i] = 0
  141. end
  142. end
  143. ram[#ram] = nil --Remove the last address.
  144. local lastaddr = string.format("0x%X",ramsize-1) --The last accessible ram address.
  145. local lastaddr4 = string.format("0x%X",(ramsize-1)*2) --The last accessible ram address for peek4 and poke4.
  146. local function Verify(value,name,etype,allowNil)
  147. if type(value) ~= etype then
  148. if allowNil then
  149. error(name.." should be a "..etype.." or a nil, provided: "..type(value),3)
  150. else
  151. error(name.." should be a "..etype..", provided: "..type(value),3)
  152. end
  153. end
  154. if etype == "number" then
  155. return math.floor(value)
  156. end
  157. end
  158. local api, yapi = {}, {}
  159. --API Start
  160. function api.poke4(address,value)
  161. address = Verify(address,"Address","number")
  162. value = Verify(value,"Value","number")
  163. if address < 0 or address > (ramsize-1)*2 then return error("Address out of range ("..tohex(address*2).."), must be in range [0x0,"..lastaddr4.."]") end
  164. if value < 0 or value > 15 then return error("Value out of range ("..value..") must be in range [0,15]") end
  165. for k,h in ipairs(handlers) do
  166. if address <= h.endAddr*2+1 then
  167. h.handler("poke4",h.startAddr*2,address,value)
  168. return
  169. end
  170. end
  171. end
  172. function api.poke(address,value)
  173. address = Verify(address,"Address","number")
  174. value = Verify(value,"Value","number")
  175. if address < 0 or address > ramsize-1 then return error("Address out of range ("..tohex(address).."), must be in range [0x0,"..lastaddr.."]") end
  176. if value < 0 or value > 255 then return error("Value out of range ("..value..") must be in range [0,255]") end
  177. for k,h in ipairs(handlers) do
  178. if address <= h.endAddr then
  179. h.handler("poke",h.startAddr,address,value)
  180. return
  181. end
  182. end
  183. end
  184. function api.peek4(address)
  185. address = Verify(address,"Address","number")
  186. if address < 0 or address > (ramsize-1)*2 then return error("Address out of range ("..tohex(address*2).."), must be in range [0x0,"..lastaddr4.."]") end
  187. for k,h in ipairs(handlers) do
  188. if address <= h.endAddr*2+1 then
  189. local v = h.handler("peek4",h.startAddr*2,address)
  190. return v --It ran successfully
  191. end
  192. end
  193. return 0 --No handler is found
  194. end
  195. function api.peek(address)
  196. address = Verify(address,"Address","number")
  197. if address < 0 or address > ramsize-1 then return error("Address out of range ("..tohex(address).."), must be in range [0x0,"..lastaddr.."]") end
  198. for k,h in ipairs(handlers) do
  199. if address <= h.endAddr then
  200. local v = h.handler("peek",h.startAddr,address)
  201. return v --It ran successfully
  202. end
  203. end
  204. return 0 --No handler is found
  205. end
  206. function api.memget(address,length)
  207. address = Verify(address,"Address","number")
  208. length = Verify(length,"Length","number")
  209. if address < 0 or address > ramsize-1 then return error("Address out of range ("..tohex(address).."), must be in range [0x0,"..lastaddr.."]") end
  210. if length <= 0 then return error("Length must be bigger than 0") end
  211. if address+length > ramsize then return error("Length out of range ("..length..")") end
  212. local endAddress = address+length-1
  213. local str = ""
  214. for k,h in ipairs(handlers) do
  215. if endAddress >= h.startAddr then
  216. if address <= h.endAddr then
  217. local sa, ea = address, endAddress
  218. if sa < h.startAddr then sa = h.startAddr end
  219. if ea > h.endAddr then ea = h.endAddr end
  220. local data = h.handler("memget",h.startAddr,sa,ea-sa+1)
  221. str = str .. data
  222. end
  223. end
  224. end
  225. return str
  226. end
  227. function api.memset(address,data)
  228. address = Verify(address,"Address","number")
  229. Verify(data,"Data","string")
  230. if address < 0 or address > ramsize-1 then return error("Address out of range ("..tohex(address).."), must be in range [0x0,"..lastaddr.."]") end
  231. local length = data:len()
  232. if length == 0 then return error("Cannot set empty string") end
  233. if address+length > ramsize then return error("Data too long to fit in the memory ("..length.." character)") end
  234. local endAddress = address+length-1
  235. for k,h in ipairs(handlers) do
  236. if endAddress >= h.startAddr then
  237. if address <= h.endAddr then
  238. local sa, ea, d = address, endAddress, data
  239. if sa < h.startAddr then sa = h.startAddr end
  240. if ea > h.endAddr then ea = h.endAddr end
  241. d = data:sub(sa-address+1,ea-address+1)
  242. h.handler("memset",h.startAddr,sa,d)
  243. end
  244. end
  245. end
  246. end
  247. function api.memcpy(from_address,to_address,length)
  248. from_address = Verify(from_address,"Source Address","number")
  249. to_address = Verify(to_address,"Destination Address","number")
  250. length = Verify(length,"Length","number")
  251. if from_address < 0 or from_address > ramsize-1 then return error("Source Address out of range ("..tohex(from_address).."), must be in range [0x0,"..tohex(ramsize-2).."]") end
  252. if to_address < 0 or to_address > ramsize then return error("Destination Address out of range ("..tohex(to_address).."), must be in range [0x0,"..lastaddr.."]") end
  253. if length <= 0 then return error("Length should be bigger than 0") end
  254. if from_address+length > ramsize then return error("Length out of range ("..length..")") end
  255. if to_address+length > ramsize then length = ramsize-to_address end
  256. local from_end = from_address+length-1
  257. local to_end = to_address+length-1
  258. for k1,h1 in ipairs(handlers) do
  259. if from_end >= h1.startAddr and from_address <= h1.endAddr then
  260. local sa1, ea1 = from_address, from_end
  261. if sa1 < h1.startAddr then sa1 = h1.startAddr end
  262. if ea1 > h1.endAddr then ea1 = h1.endAddr end
  263. local to_address = to_address + (sa1 - from_address)
  264. local to_end = to_end + (ea1 - from_end)
  265. for k2,h2 in ipairs(handlers) do
  266. if to_end >= h2.startAddr and to_address <= h2.endAddr then
  267. local sa2, ea2 = to_address, to_end
  268. if sa2 < h2.startAddr then sa2 = h2.startAddr end
  269. if ea2 > h2.endAddr then ea2 = h2.endAddr end
  270. local sa1 = sa1 + (sa2 - to_address)
  271. local ea1 = sa1 + (ea2 - to_end)
  272. if h1.handler == h2.handler then --Direct Copy
  273. h1.handler("memcpy",h1.startAddr,sa1,sa2,ea2-sa2+1)
  274. else --InDirect Copy
  275. local d = h1.handler("memget",h1.startAddr,sa1,ea2-sa2+1)
  276. h2.handler("memset",h2.startAddr,sa2,d)
  277. end
  278. end
  279. end
  280. end
  281. end
  282. end
  283. devkit.ramsize = ramsize
  284. devkit.ram = ram
  285. devkit.tohex = tohex
  286. devkit.layout = layout
  287. devkit.handlers = handlers
  288. devkit.api = api
  289. return api, yapi, devkit
  290. end