Lua 5.3 didn't need an x86 emulator. But now, it has one regardless.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

pit.lua 3.4KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142
  1. -- 8253 PIT
  2. -- TODO: Actually emulate it. Tough, as we only get 20 "ticks" a second on OpenComputers.
  3. -- Maybe it's not worth to accurately emulate it?
  4. pit_osc_freq = 1.193182
  5. local channels = {nil, nil, nil}
  6. function pit_channel(c)
  7. return channels[c]
  8. end
  9. local function pit_init(c,first)
  10. channels[c] = {
  11. mode=3,
  12. addr_mode=3,
  13. reload=0x10000,
  14. reload_set_lo=false,
  15. reload_set_hi=false,
  16. bcd=false,
  17. paused=false,
  18. count=0
  19. }
  20. end
  21. -- THIS IS REALLY INACCURATE OKAY
  22. -- but that is fine as we're not using it right now anyway
  23. local pit_last_tick = -1
  24. function pit_tick(curr_t)
  25. if pit_last_tick == -1 then
  26. pit_last_tick = curr_t
  27. return
  28. end
  29. local osc_count = math.floor((curr_t - pit_last_tick) * 1000000 * pit_osc_freq)
  30. pit_last_tick = curr_t
  31. for c=1,3 do
  32. local trig=0
  33. local ch=channels[c]
  34. local ch_ready=(not ch.paused) and ch.reload_set_lo and ch.reload_set_hi
  35. if ch_ready then
  36. emu_debug(2, "PIT tick " .. c .. " mode " .. ch.mode)
  37. end
  38. if ch.reload == 0 then
  39. ch.reload = 0x10000
  40. end
  41. if (ch.mode == 0 or ch.mode == 4) and ch_ready then
  42. if ch.count == 0 then ch.count = ch.reload end
  43. ch.count = ch.count - osc_count
  44. if ch.count < 1 then
  45. trig = 1
  46. ch.count = 0
  47. ch.paused = true
  48. end
  49. elseif (ch.mode == 2 or ch.mode == 3 or ch.mode == 6 or ch.mode == 7) and ch_ready then
  50. emu_debug(2, "PIT " .. ch.count .. " -> " .. (ch.count - osc_count))
  51. ch.count = ch.count - osc_count
  52. while ch.count < 0 do
  53. ch.count = ch.count + ch.reload
  54. trig = trig + 1
  55. end
  56. end
  57. for i=1,trig do
  58. if c == 1 and pic_interrupt_enabled(PIC_INTERRUPT_TIMER) then
  59. cpu_emit_interrupt(0x08, false)
  60. end
  61. end
  62. end
  63. end
  64. local access_lohi = false
  65. local function pit_data(n) return function(cond, val)
  66. local ch = channels[n]
  67. if not val then
  68. emu_debug(2, "PIT read data " .. n .. " mode " .. ch.addr_mode)
  69. if (ch.addr_mode == 3) or (ch.addr_mode == 0) then
  70. access_lohi = not access_lohi
  71. if access_lohi then
  72. return ch.count & 0xFF
  73. else
  74. return (ch.count >> 8) & 0xFF
  75. end
  76. elseif ch.addr_mode == 1 then
  77. return ch.count & 0xFF
  78. elseif ch.addr_mode == 2 then
  79. return (ch.count >> 8) & 0xFF
  80. elseif ch.addr_mode == 0 then
  81. return 0x00 -- TODO
  82. end
  83. else
  84. emu_debug(2, "PIT write data " .. n .. " mode " .. ch.addr_mode)
  85. if ch.addr_mode == 3 then
  86. access_lohi = not access_lohi
  87. if access_lohi then
  88. ch.reload = (ch.reload & 0xFF00) | val
  89. ch.reload_set_lo = true
  90. ch.reload_set_hi = false
  91. else
  92. ch.reload = (ch.reload & 0xFF) | (val << 8)
  93. ch.reload_set_hi = true
  94. end
  95. elseif ch.addr_mode == 1 then
  96. ch.reload = (ch.reload & 0xFF00) | val
  97. ch.reload_set_lo = true
  98. elseif ch.addr_mode == 2 then
  99. ch.reload = (ch.reload & 0xFF) | (val << 8)
  100. ch.reload_set_hi = true
  101. end
  102. end
  103. end end
  104. cpu_port_set(0x40, pit_data(1))
  105. cpu_port_set(0x41, pit_data(2))
  106. cpu_port_set(0x42, pit_data(3))
  107. cpu_port_set(0x43, function(cond, val)
  108. if val then
  109. emu_debug(2, "PIT write control " .. val)
  110. pit_tick(os.clock())
  111. local c = (val >> 6) + 1
  112. if c < 4 then
  113. pit_init(c,false)
  114. channels[c].addr_mode = (val >> 4) & 0x03
  115. if channels[c].addr_mode ~= 0 then
  116. channels[c].mode = (val >> 1) & 0x07
  117. channels[c].bcd = (val & 1) and true or false
  118. channels[c].paused = false
  119. end
  120. access_lohi = false
  121. end
  122. else
  123. emu_debug(2, "PIT read control")
  124. return 0xFF
  125. end
  126. end)
  127. pit_init(1,true)
  128. pit_init(2,true)
  129. pit_init(3,true)
  130. channels[1].reload_set_lo = true
  131. channels[1].reload_set_hi = true