dma.js 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181
  1. "use strict";
  2. /**
  3. * @constructor
  4. * @param {CPU} cpu
  5. */
  6. function DMA(cpu)
  7. {
  8. /** @const @type {CPU} */
  9. this.cpu = cpu;
  10. this.channel_addr = new Int32Array(4);
  11. this.channel_count = new Int32Array(4);
  12. this.lsb_msb_flipflop = 0;
  13. var io = cpu.io;
  14. io.register_write(0x04, this, this.port_write.bind(this, 0x04));
  15. io.register_write(0x05, this, this.port_write.bind(this, 0x05));
  16. io.register_write(0x0A, this, this.portA_write);
  17. io.register_write(0x0B, this, this.portB_write);
  18. io.register_write(0x0C, this, this.portC_write);
  19. io.register_write(0x81, this, this.port81_write);
  20. }
  21. DMA.prototype.get_state = function()
  22. {
  23. return [
  24. this.channel_addr,
  25. this.channel_count,
  26. this.lsb_msb_flipflop,
  27. ];
  28. };
  29. DMA.prototype.set_state = function(state)
  30. {
  31. this.channel_addr = state[0];
  32. this.channel_count = state[1];
  33. this.lsb_msb_flipflop = state[2];
  34. };
  35. DMA.prototype.port_write = function(port, data_byte)
  36. {
  37. dbg_log("port " + port + " write " + data_byte, LOG_DMA);
  38. if(port < 8)
  39. {
  40. var channel = port >> 1;
  41. if(port & 1)
  42. {
  43. this.channel_count[channel] = this.flipflop_get(this.channel_count[channel], data_byte);
  44. }
  45. else
  46. {
  47. this.channel_addr[channel] = this.flipflop_get(this.channel_addr[channel], data_byte);
  48. }
  49. }
  50. };
  51. DMA.prototype.port_read = function(port)
  52. {
  53. if(port < 8)
  54. {
  55. var channel = port >> 1;
  56. if(port & 1)
  57. {
  58. return this.channel_count[channel];
  59. }
  60. else
  61. {
  62. // Bug?
  63. return this.channel_addr[channel];
  64. }
  65. }
  66. else
  67. {
  68. dbg_log("port " + h(port) + " read", LOG_DMA);
  69. }
  70. };
  71. DMA.prototype.portA_write = function(data_byte)
  72. {
  73. dbg_log("port A write: " + h(data_byte), LOG_DMA);
  74. };
  75. DMA.prototype.portB_write = function(data_byte)
  76. {
  77. dbg_log("port B write: " + h(data_byte), LOG_DMA);
  78. };
  79. DMA.prototype.portC_write = function(data_byte)
  80. {
  81. this.lsb_msb_flipflop = 0;
  82. }
  83. DMA.prototype.port81_write = function(data_byte)
  84. {
  85. this.channel_addr[2] = this.channel_addr[2] & 0xFFFF | data_byte << 16;
  86. }
  87. // read data, write to memory
  88. DMA.prototype.do_read = function(buffer, start, len, channel, fn)
  89. {
  90. var read_count = this.channel_count[channel] + 1,
  91. addr = this.channel_addr[channel];
  92. dbg_log("DMA write channel " + channel, LOG_DMA);
  93. dbg_log("to " + h(addr) + " len " + h(read_count), LOG_DMA);
  94. if(len < read_count)
  95. {
  96. dbg_log("DMA should read more than provided: " + h(len) + " " + h(read_count), LOG_DMA);
  97. }
  98. if(start + read_count > buffer.byteLength)
  99. {
  100. dbg_log("DMA read outside of buffer", LOG_DMA);
  101. fn(true);
  102. }
  103. else
  104. {
  105. var cpu = this.cpu;
  106. this.channel_addr[channel] += read_count;
  107. buffer.get(start, read_count, function(data)
  108. {
  109. cpu.write_blob(data, addr);
  110. fn(false);
  111. });
  112. }
  113. };
  114. // write data, read memory
  115. DMA.prototype.do_write = function(buffer, start, len, channel, fn)
  116. {
  117. var read_count = this.channel_count[channel],
  118. addr = this.channel_addr[channel];
  119. dbg_log("DMA write channel " + channel, LOG_DMA);
  120. dbg_log("to " + h(addr) + " len " + h(read_count), LOG_DMA);
  121. if(len < read_count)
  122. {
  123. dbg_log("DMA should read more than provided", LOG_DMA);
  124. }
  125. if(start + read_count > buffer.byteLength)
  126. {
  127. dbg_log("DMA write outside of buffer", LOG_DMA);
  128. fn(true);
  129. }
  130. else
  131. {
  132. this.channel_addr[channel] += read_count;
  133. buffer.set(start,
  134. this.cpu.mem8.subarray(addr, addr + read_count + 1),
  135. function() {
  136. fn(false);
  137. }
  138. );
  139. }
  140. }
  141. DMA.prototype.flipflop_get = function(old_dword, new_byte)
  142. {
  143. this.lsb_msb_flipflop ^= 1;
  144. if(this.lsb_msb_flipflop)
  145. {
  146. // low byte
  147. return old_dword & ~0xFF | new_byte;
  148. }
  149. else
  150. {
  151. // high byte
  152. return old_dword & ~0xFF00 | new_byte << 8;
  153. }
  154. }