Advertisement
Guest User

Chip8 Emulator by Gamax92

a guest
Nov 11th, 2012
100
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 16.75 KB | None | 0 0
  1. local function pad(str, tolen) return string.rep("0", math.max(tolen - str:len(),0)) .. str end
  2. local function binary(num)
  3.     local bin = {}
  4.     num = math.floor(num)
  5.     repeat
  6.     table.insert(bin, num%2)
  7.     num = math.floor(num/2)
  8.     until num == 0
  9.     return table.concat(bin):reverse()
  10. end
  11. local tArgs = { ... }
  12. if #tArgs < 2 then
  13.     print("Usage: chip8 <rom> <side> [debug]")
  14.     return
  15. end
  16.  
  17. local rFile = shell.resolve(tArgs[1])
  18. local eSide = tArgs[2]
  19. local mDebug = not (tArgs[3] == nil)
  20.  
  21. if mDebug then print("Checking if rom exists ...") end
  22. if not fs.exists(rFile) then
  23.     print("Rom file " .. rFile .. " does not exist.")
  24.     return
  25. end
  26. if mDebug then print("Checking if rom is a directory ...") end
  27. if fs.isDir(rFile) then
  28.     print("Rom file " .. rFile .. " is a directory.")
  29.     return
  30. end
  31. if mDebug then print("Checking if side is monitor ...") end
  32. if not peripheral.getType(eSide) == "monitor" then
  33.     print("Peripheral on side " .. eSide .. " is not a monitor.")
  34.     return
  35. end
  36. if mDebug then print("Attempting to wrap monitor ...") end
  37. local mon = peripheral.wrap(eSide)
  38. if mon == nil then
  39.     print("Failed to wrap monitor on side " .. eSide)
  40.     return
  41. end
  42. mon.setTextScale(0.5)
  43. mon.clear()
  44. local w,h = mon.getSize()
  45. if mDebug then print("Checking if monitor is big enough ...") end
  46. if w < 64 or h < 32 then
  47.     print("The monitor on side " .. eSide .. " is too small.")
  48.     print("Expected 64x32+\nGot " .. tostring(w) .. "x" .. tostring(h))
  49.     return
  50. end
  51. if mDebug then print("Protection passed!\n") end
  52.  
  53. local chip8_keystate = {}
  54. local chip8_keytrans = {}
  55. local chip8_display = {}
  56. for i = 0,63,1 do
  57.     chip8_display[i] = {}
  58.     for j = 0,31,1 do
  59.         chip8_display[i][j] = 0
  60.     end
  61. end
  62. local chip8_memory = {}
  63. for i = 0, 4095, 1 do chip8_memory[i] = 0 end
  64. local chip8_register = {}
  65. for i = 0, 15, 1 do chip8_register[i] = 0 end
  66. chip8_register["I"] = 512
  67. chip8_register["PC"] = 512
  68. chip8_register["DC"] = 0
  69. chip8_register["SC"] = 0
  70. local chip8_stack = {}
  71. chip8_stack[0] = 0
  72. local chip8_skip = 2
  73. chip8_fontset = {
  74. 0xF0, 0x90, 0x90, 0x90, 0xF0,
  75. 0x20, 0x60, 0x20, 0x20, 0x70,
  76. 0xF0, 0x10, 0xF0, 0x80, 0xF0,
  77. 0xF0, 0x10, 0xF0, 0x10, 0xF0,
  78. 0x90, 0x90, 0xF0, 0x10, 0x10,
  79. 0xF0, 0x80, 0xF0, 0x10, 0xF0,
  80. 0xF0, 0x80, 0xF0, 0x90, 0xF0,
  81. 0xF0, 0x10, 0x20, 0x40, 0x40,
  82. 0xF0, 0x90, 0xF0, 0x90, 0xF0,
  83. 0xF0, 0x90, 0xF0, 0x10, 0xF0,
  84. 0xF0, 0x90, 0xF0, 0x90, 0x90,
  85. 0xE0, 0x90, 0xE0, 0x90, 0xE0,
  86. 0xF0, 0x80, 0x80, 0x80, 0xF0,
  87. 0xE0, 0x90, 0x90, 0x90, 0xE0,
  88. 0xF0, 0x80, 0xF0, 0x80, 0xF0,
  89. 0xF0, 0x80, 0xF0, 0x80, 0x80}
  90. print("Loading fontset ...")
  91. for i = 1,80,1 do
  92.     chip8_memory[i-1] = chip8_fontset[i]
  93. end
  94.  
  95. chip8_keystate["0"] = 0
  96. chip8_keystate["1"] = 0
  97. chip8_keystate["2"] = 0
  98. chip8_keystate["3"] = 0
  99. chip8_keystate["4"] = 0
  100. chip8_keystate["5"] = 0
  101. chip8_keystate["6"] = 0
  102. chip8_keystate["7"] = 0
  103. chip8_keystate["8"] = 0
  104. chip8_keystate["9"] = 0
  105. chip8_keystate["A"] = 0
  106. chip8_keystate["B"] = 0
  107. chip8_keystate["C"] = 0
  108. chip8_keystate["D"] = 0
  109. chip8_keystate["E"] = 0
  110. chip8_keystate["F"] = 0
  111. chip8_keystate["END"] = 0
  112.  
  113. chip8_keytrans[45] = "0"
  114. chip8_keytrans[2] = "1"
  115. chip8_keytrans[3] = "2"
  116. chip8_keytrans[4] = "3"
  117. chip8_keytrans[16] = "4"
  118. chip8_keytrans[17] = "5"
  119. chip8_keytrans[18] = "6"
  120. chip8_keytrans[30] = "7"
  121. chip8_keytrans[31] = "8"
  122. chip8_keytrans[32] = "9"
  123. chip8_keytrans[44] = "A"
  124. chip8_keytrans[46] = "B"
  125. chip8_keytrans[5] = "C"
  126. chip8_keytrans[19] = "D"
  127. chip8_keytrans[33] = "E"
  128. chip8_keytrans[47] = "F"
  129. chip8_keytrans[59] = "END"
  130.  
  131. function chip8_loadrom()
  132.     local rRom = fs.open(rFile,"rb")
  133.     local index = 512
  134.     local size = 0
  135.     while true do
  136.         byte = rRom.read()
  137.         if byte == nil then break end
  138.         chip8_memory[index] = byte
  139.         index = index + 1
  140.         size = size + 1
  141.     end
  142.     rRom.close()
  143.     return size
  144. end
  145.  
  146. function chip8_updatekeys()
  147.     for i = 48,57,1 do
  148.         chip8_keystate[string.char(i)] = chip8_keystate[string.char(i)] - 1
  149.         if chip8_keystate[string.char(i)] < 0 then chip8_keystate[string.char(i)] = 0 end
  150.     end
  151.     for i = 65,70,1 do
  152.         chip8_keystate[string.char(i)] = chip8_keystate[string.char(i)] - 1
  153.         if chip8_keystate[string.char(i)] < 0 then chip8_keystate[string.char(i)] = 0 end
  154.     end
  155.     os.queueEvent("key","","done")
  156.     while true do
  157.         event,param1,param2 = os.pullEvent("key")
  158.         if param2 == "done" then break end
  159.         if not (chip8_keytrans[param1] == nil) then
  160.             chip8_keystate[chip8_keytrans[param1]] = 4
  161.             if mDebug then print("Pressed " .. chip8_keytrans[param1]) end
  162.         end
  163.     end
  164.     return
  165. end
  166.  
  167. function chip8_keywait()
  168.     while true do
  169.         for i = 48,57,1 do
  170.             chip8_keystate[string.char(i)] = chip8_keystate[string.char(i)] - 1
  171.             if chip8_keystate[string.char(i)] < 0 then chip8_keystate[string.char(i)] = 0 end
  172.         end
  173.         for i = 65,70,1 do
  174.             chip8_keystate[string.char(i)] = chip8_keystate[string.char(i)] - 1
  175.             if chip8_keystate[string.char(i)] < 0 then chip8_keystate[string.char(i)] = 0 end
  176.         end
  177.         os.queueEvent("key","","done")
  178.         while true do
  179.             event,param1,param2 = os.pullEvent("key")
  180.             if param2 == "done" then break end
  181.             if not (chip8_keytrans[param1] == nil) then
  182.                 chip8_keystate[chip8_keytrans[param1]] = 4
  183.                 if mDebug then print("Pressed " .. chip8_keytrans[param1]) end
  184.                 return tonumber(chip8_keytrans[param1],16)
  185.             end
  186.         end
  187.         if pressed then break end
  188.         sleep(0)
  189.     end
  190. end
  191.  
  192. function chip8_getkey(key)
  193.     return chip8_keystate[key] > 0
  194. end
  195.  
  196. function chip8_emulatecode()
  197.     local l
  198.     local opcode = pad(string.format("%X",chip8_memory[chip8_register["PC"]]),2) .. pad(string.format("%X",chip8_memory[chip8_register["PC"]+1]),2)
  199.     local opcfst = string.sub(opcode,1,1)
  200.     if mDebug then
  201.         print("PC:" .. pad(string.format("%X",chip8_register["PC"]),4) .. "|I:" .. pad(string.format("%X",chip8_register["I"]),4) .. " - " .. opcode)
  202.         curX,curY = term.getCursorPos()
  203.         for i = 0,15,1 do
  204.             term.setCursorPos(46,i+2) print("V" .. pad(string.format("%X",i),1) .. ":" .. pad(string.format("%X",chip8_register[i]),2))
  205.         end
  206.         term.setCursorPos(curX,curY)
  207.     end
  208.     for i = 0,15,1 do
  209.         if chip8_register[i] > 255 then error("ERR1") end
  210.         if chip8_register[i] < 0 then error("ERR2") end
  211.     end
  212.     chip8_register["PC"] = chip8_register["PC"] + 2
  213.     if opcfst == "0" then
  214.         if string.sub(opcode,2,4) == "0E0" then
  215.             mon.clear()
  216.             mon.setCursorPos(1,1)
  217.             for i = 0,63,1 do
  218.                 for j = 0,31,1 do
  219.                     chip8_display[i][j] = 0
  220.                 end
  221.             end
  222.         elseif string.sub(opcode,2,4) == "0EE" then
  223.             chip8_register["PC"] = chip8_stack[chip8_stack[0]]
  224.             chip8_stack[0] = chip8_stack[0] - 1
  225.         end
  226.     elseif opcfst == "1" then
  227.         chip8_register["PC"] = tonumber(string.sub(opcode,2,4),16)
  228.     elseif opcfst == "2" then
  229.         chip8_stack[0] = chip8_stack[0] + 1
  230.         chip8_stack[chip8_stack[0]] = chip8_register["PC"]
  231.         chip8_register["PC"] = tonumber(string.sub(opcode,2,4),16)
  232.     elseif opcfst == "3" then
  233.         if chip8_register[tonumber(string.sub(opcode,2,2),16)] == tonumber(string.sub(opcode,3,4),16) then
  234.             chip8_register["PC"] = chip8_register["PC"] + 2
  235.         end
  236.     elseif opcfst == "4" then
  237.         if chip8_register[tonumber(string.sub(opcode,2,2),16)] ~= tonumber(string.sub(opcode,3,4),16) then
  238.             chip8_register["PC"] = chip8_register["PC"] + 2
  239.         end
  240.     elseif opcfst == "5" then
  241.         if chip8_register[tonumber(string.sub(opcode,2,2),16)] == chip8_register[tonumber(string.sub(opcode,3,3),16)] then
  242.             chip8_register["PC"] = chip8_register["PC"] + 2
  243.         end
  244.     elseif opcfst == "6" then
  245.         chip8_register[tonumber(string.sub(opcode,2,2),16)] = tonumber(string.sub(opcode,3,4),16)
  246.     elseif opcfst == "7" then
  247.         chip8_register[tonumber(string.sub(opcode,2,2),16)] = math.fmod(chip8_register[tonumber(string.sub(opcode,2,2),16)] + tonumber(string.sub(opcode,3,4),16),255)
  248.     elseif opcfst == "8" then
  249.         if string.sub(opcode,4,4) == "0" then
  250.             chip8_register[tonumber(string.sub(opcode,2,2),16)] = chip8_register[tonumber(string.sub(opcode,3,3),16)]
  251.         elseif string.sub(opcode,4,4) == "1" then
  252.             chip8_register[tonumber(string.sub(opcode,2,2),16)] = bit.bor(chip8_register[tonumber(string.sub(opcode,2,2),16)],chip8_register[tonumber(string.sub(opcode,3,3),16)])
  253.         elseif string.sub(opcode,4,4) == "2" then
  254.             chip8_register[tonumber(string.sub(opcode,2,2),16)] = bit.band(chip8_register[tonumber(string.sub(opcode,2,2),16)],chip8_register[tonumber(string.sub(opcode,3,3),16)])
  255.         elseif string.sub(opcode,4,4) == "3" then
  256.             chip8_register[tonumber(string.sub(opcode,2,2),16)] = bit.bxor(chip8_register[tonumber(string.sub(opcode,2,2),16)],chip8_register[tonumber(string.sub(opcode,3,3),16)])
  257.         elseif string.sub(opcode,4,4) == "4" then
  258.             chip8_register[15] = 0
  259.             chip8_register[tonumber(string.sub(opcode,2,2),16)] = chip8_register[tonumber(string.sub(opcode,2,2),16)] + chip8_register[tonumber(string.sub(opcode,3,3),16)]
  260.             if chip8_register[tonumber(string.sub(opcode,2,2),16)] > 255 then
  261.                 chip8_register[15] = 1
  262.                 chip8_register[tonumber(string.sub(opcode,2,2),16)] = math.fmod(chip8_register[tonumber(string.sub(opcode,2,2),16)],256)
  263.             end
  264.         elseif string.sub(opcode,4,4) == "5" then
  265.             chip8_register[15] = 1
  266.             chip8_register[tonumber(string.sub(opcode,2,2),16)] = chip8_register[tonumber(string.sub(opcode,2,2),16)] - chip8_register[tonumber(string.sub(opcode,3,3),16)]
  267.             if chip8_register[tonumber(string.sub(opcode,2,2),16)] < 0 then
  268.                 chip8_register[15] = 0
  269.                 chip8_register[tonumber(string.sub(opcode,2,2),16)] = chip8_register[tonumber(string.sub(opcode,2,2),16)] + 256
  270.             end
  271.         elseif string.sub(opcode,4,4) == "6" then
  272.             chip8_register[15] = math.fmod(chip8_register[tonumber(string.sub(opcode,3,3),16)],2)
  273.             chip8_register[tonumber(string.sub(opcode,2,2),16)] = bit.brshift(chip8_register[tonumber(string.sub(opcode,3,3),16)],1)
  274.         elseif string.sub(opcode,4,4) == "7" then
  275.             chip8_register[15] = 1
  276.             chip8_register[tonumber(string.sub(opcode,2,2),16)] = chip8_register[tonumber(string.sub(opcode,3,3),16)] - chip8_register[tonumber(string.sub(opcode,2,2),16)]
  277.             if chip8_register[tonumber(string.sub(opcode,2,2),16)] < 0 then
  278.                 chip8_register[15] = 0
  279.                 chip8_register[tonumber(string.sub(opcode,2,2),16)] = chip8_register[tonumber(string.sub(opcode,2,2),16)] + 256
  280.             end
  281.         elseif string.sub(opcode,4,4) == "E" then
  282.             chip8_register[15] = math.floor(chip8_register[tonumber(string.sub(opcode,3,3),16)] / 128)
  283.             chip8_register[tonumber(string.sub(opcode,2,2),16)] = math.fmod(bit.blshift(chip8_register[tonumber(string.sub(opcode,3,3),16)],1),256)
  284.         end
  285.     elseif opcfst == "9" then
  286.         if not (chip8_register[tonumber(string.sub(opcode,2,2),16)] == chip8_register[tonumber(string.sub(opcode,3,3),16)]) then
  287.             chip8_register["PC"] = chip8_register["PC"] + 2
  288.         end
  289.     elseif opcfst == "A" then
  290.         chip8_register["I"] = tonumber(string.sub(opcode,2,4),16)
  291.     elseif opcfst == "B" then
  292.         chip8_register["PC"] = tonumber(string.sub(opcode,2,4),16) + chip8_register[0]
  293.     elseif opcfst == "C" then
  294.         chip8_register[tonumber(string.sub(opcode,2,2),16)] = bit.band(math.random(0,255),tonumber(string.sub(opcode,3,4),16))
  295.     elseif opcfst == "D" then
  296.         chip8_register[15] = 0
  297.         local x = chip8_register[tonumber(string.sub(opcode,2,2),16)]
  298.         local y = chip8_register[tonumber(string.sub(opcode,3,3),16)]
  299.         local h = tonumber(string.sub(opcode,4,4),16)
  300.         local dLine = ""
  301.         local s = ""
  302.         for i = 0,h-1,1 do
  303.             dLine = ""
  304.             s = pad(binary(chip8_memory[chip8_register["I"]+i]),8)
  305.             for d = 0,7,1 do dLine = dLine .. tostring(chip8_display[math.fmod(x+d,64)][math.min(y+i,31)]) end
  306.             line = pad(binary(bit.bxor(tonumber(s,2),tonumber(dLine,2))),8)
  307.             for p = 1,8,1 do
  308.                 if not (x+p-1 > 63 or y+i > 31) then
  309.                     mon.setCursorPos(x+p,y+i+1)
  310.                     if string.sub(line,p,p) == "1" then
  311.                         mon.setBackgroundColor(1)
  312.                         mon.write("#")
  313.                         mon.setBackgroundColor(32768)
  314.                         chip8_display[math.fmod(x+p-1,64)][y+i] = 1
  315.                     else
  316.                         mon.write(" ")
  317.                         if chip8_display[math.fmod(x+p-1,64)][y+i] == 1 then chip8_register[15] = 1 end
  318.                         chip8_display[math.fmod(x+p-1,64)][y+i] = 0
  319.                     end
  320.                 end
  321.             end
  322.         end
  323.         if not mDebug then chip8_updatedisplay() end
  324.     elseif opcfst == "E" then
  325.         if string.sub(opcode,3,4) == "9E" then
  326.             if chip8_getkey(string.format("%X",chip8_register[tonumber(string.sub(opcode,2,2),16)])) then
  327.                 chip8_register["PC"] = chip8_register["PC"] + 2
  328.             end
  329.         elseif string.sub(opcode,3,4) == "A1" then
  330.             if not (chip8_getkey(string.format("%X",chip8_register[tonumber(string.sub(opcode,2,2),16)]))) then
  331.                 chip8_register["PC"] = chip8_register["PC"] + 2
  332.             end
  333.         end
  334.     elseif opcfst == "F" then
  335.         if string.sub(opcode,3,4) == "07" then
  336.             chip8_register[tonumber(string.sub(opcode,2,2),16)] = chip8_register["DC"]
  337.         elseif string.sub(opcode,3,4) == "0A" then
  338.             chip8_register[tonumber(string.sub(opcode,2,2),16)] = chip8_keywait()
  339.         elseif string.sub(opcode,3,4) == "15" then
  340.             chip8_register["DC"] = chip8_register[tonumber(string.sub(opcode,2,2),16)]
  341.         elseif string.sub(opcode,3,4) == "18" then
  342.             chip8_register["SC"] = chip8_register[tonumber(string.sub(opcode,2,2),16)]
  343.         elseif string.sub(opcode,3,4) == "1E" then
  344.             chip8_register[15] = 0
  345.             chip8_register["I"] = chip8_register["I"] + chip8_register[tonumber(string.sub(opcode,2,2),16)]
  346.             if chip8_register["I"] > 4095 then
  347.                 chip8_register[15] = 1
  348.                 chip8_register["I"] = math.fmod(chip8_register["I"],256)
  349.             end
  350.         elseif string.sub(opcode,3,4) == "29" then
  351.             chip8_register["I"] = chip8_register[tonumber(string.sub(opcode,2,2),16)] * 5
  352.         elseif string.sub(opcode,3,4) == "33" then
  353.             local bcd = pad(tostring(chip8_register[tonumber(string.sub(opcode,2,2),16)]),3)
  354.             chip8_memory[chip8_register["I"]] = tonumber(string.sub(bcd,1,1))
  355.             chip8_memory[chip8_register["I"]+1] = tonumber(string.sub(bcd,2,2))
  356.             chip8_memory[chip8_register["I"]+2] = tonumber(string.sub(bcd,3,3))
  357.         elseif string.sub(opcode,3,4) == "55" then
  358.             for i = 0,tonumber(string.sub(opcode,2,2),16),1 do
  359.                 chip8_memory[chip8_register["I"]+i] = chip8_register[i]
  360.             end
  361.             chip8_register["I"] = chip8_register["I"] + tonumber(string.sub(opcode,2,2),16) + 1
  362.         elseif string.sub(opcode,3,4) == "65" then
  363.             for i = 0,tonumber(string.sub(opcode,2,2),16),1 do
  364.                 chip8_register[i] = chip8_memory[chip8_register["I"]+i]
  365.             end
  366.             chip8_register["I"] = chip8_register["I"] + tonumber(string.sub(opcode,2,2),16) + 1
  367.         end
  368.     end
  369.     return
  370. end
  371.  
  372. function chip8_updatedisplay()
  373.     term.clear()
  374.     for y = 0,31,1 do
  375.         for x = 0,63,1 do
  376.             term.setCursorPos(x*(50/64)+1,y*(18/32)+1)
  377.             if chip8_display[x][y] == 1 then
  378.                 term.setBackgroundColor(1)
  379.                 term.write("#")
  380.                 term.setBackgroundColor(32768)
  381.             end
  382.         end
  383.     end
  384.     return
  385. end
  386.  
  387. function chip8_delay()
  388.     if chip8_register["DC"] > 0 then chip8_register["DC"] = chip8_register["DC"] - 1 end
  389.     if chip8_register["SC"] > 0 then chip8_register["SC"] = chip8_register["SC"] - 1 end
  390. --    chip8_skip = chip8_skip - 1
  391. --    if chip8_skip == 0 then sleep(0.05) chip8_skip = 3 end
  392.     return
  393. end
  394.  
  395. print("Loading rom into memory ...")
  396. size = chip8_loadrom()
  397. print("Loaded " .. tostring(size) .. " bytes!")
  398.  
  399. print("Starting emulation, press F1 to end ...")
  400. if not mDebug then sleep(1.5) term.clear() end
  401.  
  402. while true do
  403.     chip8_updatekeys()
  404.     if chip8_getkey("END") then break end
  405.     chip8_emulatecode()
  406.     chip8_delay()
  407. end
  408.  
  409. print("Emulation ended.")
  410. return
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement