ide.js 57 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091
  1. "use strict";
  2. /** @const */
  3. var CDROM_SECTOR_SIZE = 2048;
  4. /** @const */
  5. var HD_SECTOR_SIZE = 512;
  6. /**
  7. * @constructor
  8. * @param {CPU} cpu
  9. * @param {boolean} is_cd
  10. * @param {number} nr
  11. * @param {BusConnector} bus
  12. * */
  13. function IDEDevice(cpu, master_buffer, slave_buffer, is_cd, nr, bus)
  14. {
  15. this.master = new IDEInterface(this, cpu, master_buffer, is_cd, nr, 0, bus);
  16. this.slave = new IDEInterface(this, cpu, slave_buffer, false, nr, 1, bus);
  17. this.current_interface = this.master;
  18. this.cpu = cpu;
  19. // gets set via PCI in seabios, likely doesn't matter
  20. if(nr === 0)
  21. {
  22. this.ata_port = 0x1F0;
  23. this.irq = 14;
  24. this.pci_id = 0x1E << 3;
  25. }
  26. else if(nr === 1)
  27. {
  28. this.ata_port = 0x170;
  29. this.irq = 15;
  30. this.pci_id = 0x1F << 3;
  31. }
  32. else
  33. {
  34. dbg_assert(false, "IDE device with nr " + nr + " ignored", LOG_DISK);
  35. }
  36. // alternate status, starting at 3f4/374
  37. /** @type {number} */
  38. this.ata_port_high = this.ata_port | 0x204;
  39. /** @type {number} */
  40. this.master_port = 0xB400;
  41. this.pci_space = [
  42. 0x86, 0x80, 0x10, 0x70, 0x05, 0x00, 0xA0, 0x02,
  43. 0x00, 0x80, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00,
  44. this.ata_port & 0xFF | 1, this.ata_port >> 8, 0x00, 0x00,
  45. this.ata_port_high & 0xFF | 1, this.ata_port_high >> 8, 0x00, 0x00,
  46. 0x00, 0x00, 0x00, 0x00, // second device
  47. 0x00, 0x00, 0x00, 0x00, // second device
  48. this.master_port & 0xFF | 1, this.master_port >> 8, 0x00, 0x00,
  49. 0x00, 0x00, 0x00, 0x00,
  50. 0x00, 0x00, 0x00, 0x00,
  51. 0x43, 0x10, 0xD4, 0x82,
  52. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  53. 0x00, 0x00, 0x00, 0x00, this.irq, 0x01, 0x00, 0x00,
  54. // 0x40
  55. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  56. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  57. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  58. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  59. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  60. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  61. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  62. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  63. // 0x80
  64. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  65. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  66. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  67. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  68. ];
  69. this.pci_bars = [
  70. {
  71. size: 8,
  72. },
  73. {
  74. size: 4,
  75. },
  76. undefined,
  77. undefined,
  78. {
  79. size: 0x10,
  80. },
  81. ];
  82. this.name = "ide" + nr;
  83. /** @type {number} */
  84. this.device_control = 2;
  85. // status
  86. cpu.io.register_read(this.ata_port | 7, this, function() {
  87. dbg_log("lower irq", LOG_DISK);
  88. this.cpu.device_lower_irq(this.irq);
  89. return this.read_status();
  90. });
  91. cpu.io.register_read(this.ata_port_high | 2, this, this.read_status);
  92. cpu.io.register_write(this.ata_port_high | 2, this, this.write_control);
  93. cpu.io.register_read(this.ata_port | 0, this, function()
  94. {
  95. return this.current_interface.read_data(1);
  96. }, function()
  97. {
  98. return this.current_interface.read_data(2);
  99. }, function()
  100. {
  101. return this.current_interface.read_data(4);
  102. });
  103. cpu.io.register_read(this.ata_port | 1, this, function()
  104. {
  105. dbg_log("Read error: " + h(this.current_interface.error & 0xFF) +
  106. " slave=" + (this.current_interface === this.slave), LOG_DISK);
  107. return this.current_interface.error & 0xFF;
  108. });
  109. cpu.io.register_read(this.ata_port | 2, this, function()
  110. {
  111. dbg_log("Read bytecount: " + h(this.current_interface.bytecount & 0xFF), LOG_DISK);
  112. return this.current_interface.bytecount & 0xFF;
  113. });
  114. cpu.io.register_read(this.ata_port | 3, this, function()
  115. {
  116. dbg_log("Read sector: " + h(this.current_interface.sector & 0xFF), LOG_DISK);
  117. return this.current_interface.sector & 0xFF;
  118. });
  119. cpu.io.register_read(this.ata_port | 4, this, function()
  120. {
  121. dbg_log("Read 1F4: " + h(this.current_interface.cylinder_low & 0xFF), LOG_DISK);
  122. return this.current_interface.cylinder_low & 0xFF;
  123. });
  124. cpu.io.register_read(this.ata_port | 5, this, function()
  125. {
  126. dbg_log("Read 1F5: " + h(this.current_interface.cylinder_high & 0xFF), LOG_DISK);
  127. return this.current_interface.cylinder_high & 0xFF;
  128. });
  129. cpu.io.register_read(this.ata_port | 6, this, function()
  130. {
  131. dbg_log("Read 1F6", LOG_DISK);
  132. return this.current_interface.drive_head & 0xFF;
  133. });
  134. cpu.io.register_write(this.ata_port | 0, this, function(data)
  135. {
  136. this.current_interface.write_data_port8(data);
  137. }, function(data)
  138. {
  139. this.current_interface.write_data_port16(data);
  140. }, function(data)
  141. {
  142. this.current_interface.write_data_port32(data);
  143. });
  144. cpu.io.register_write(this.ata_port | 1, this, function(data)
  145. {
  146. dbg_log("1F1/lba_count: " + h(data), LOG_DISK);
  147. this.master.lba_count = (this.master.lba_count << 8 | data) & 0xFFFF;
  148. this.slave.lba_count = (this.slave.lba_count << 8 | data) & 0xFFFF;
  149. });
  150. cpu.io.register_write(this.ata_port | 2, this, function(data)
  151. {
  152. dbg_log("1F2/bytecount: " + h(data), LOG_DISK);
  153. this.master.bytecount = (this.master.bytecount << 8 | data) & 0xFFFF;
  154. this.slave.bytecount = (this.slave.bytecount << 8 | data) & 0xFFFF;
  155. });
  156. cpu.io.register_write(this.ata_port | 3, this, function(data)
  157. {
  158. dbg_log("1F3/sector: " + h(data), LOG_DISK);
  159. this.master.sector = (this.master.sector << 8 | data) & 0xFFFF;
  160. this.slave.sector = (this.slave.sector << 8 | data) & 0xFFFF;
  161. });
  162. cpu.io.register_write(this.ata_port | 4, this, function(data)
  163. {
  164. dbg_log("1F4/sector low: " + h(data), LOG_DISK);
  165. this.master.cylinder_low = (this.master.cylinder_low << 8 | data) & 0xFFFF;
  166. this.slave.cylinder_low = (this.slave.cylinder_low << 8 | data) & 0xFFFF;
  167. });
  168. cpu.io.register_write(this.ata_port | 5, this, function(data)
  169. {
  170. dbg_log("1F5/sector high: " + h(data), LOG_DISK);
  171. this.master.cylinder_high = (this.master.cylinder_high << 8 | data) & 0xFFFF;
  172. this.slave.cylinder_high = (this.slave.cylinder_high << 8 | data) & 0xFFFF;
  173. });
  174. cpu.io.register_write(this.ata_port | 6, this, function(data)
  175. {
  176. var slave = data & 0x10;
  177. var mode = data & 0xE0;
  178. dbg_log("1F6/drive: " + h(data, 2), LOG_DISK);
  179. if(slave)
  180. {
  181. dbg_log("Slave", LOG_DISK);
  182. this.current_interface = this.slave;
  183. }
  184. else
  185. {
  186. this.current_interface = this.master;
  187. }
  188. this.master.drive_head = data;
  189. this.slave.drive_head = data;
  190. this.master.is_lba = this.slave.is_lba = data >> 6 & 1;
  191. this.master.head = this.slave.head = data & 0xF;
  192. });
  193. /** @type {number} */
  194. this.prdt_addr = 0;
  195. /** @type {number} */
  196. this.dma_status = 0;
  197. /** @type {number} */
  198. this.dma_command = 0;
  199. cpu.io.register_write(this.ata_port | 7, this, function(data)
  200. {
  201. dbg_log("lower irq", LOG_DISK);
  202. this.cpu.device_lower_irq(this.irq);
  203. this.current_interface.ata_command(data);
  204. });
  205. cpu.io.register_read(this.master_port | 4, this, undefined, undefined, this.dma_read_addr);
  206. cpu.io.register_write(this.master_port | 4, this, undefined, undefined, this.dma_set_addr);
  207. cpu.io.register_read(this.master_port, this,
  208. this.dma_read_command8, undefined, this.dma_read_command);
  209. cpu.io.register_write(this.master_port, this,
  210. this.dma_write_command8, undefined, this.dma_write_command);
  211. cpu.io.register_read(this.master_port | 2, this, this.dma_read_status);
  212. cpu.io.register_write(this.master_port | 2, this, this.dma_write_status);
  213. cpu.io.register_read(this.master_port | 0x8, this, function() {
  214. dbg_log("DMA read 0x8", LOG_DISK); return 0;
  215. });
  216. cpu.io.register_read(this.master_port | 0xA, this, function() {
  217. dbg_log("DMA read 0xA", LOG_DISK); return 0;
  218. });
  219. cpu.devices.pci.register_device(this);
  220. DEBUG && Object.seal(this);
  221. }
  222. IDEDevice.prototype.read_status = function()
  223. {
  224. if(this.current_interface.buffer)
  225. {
  226. var ret = this.current_interface.status;
  227. dbg_log("ATA read status: " + h(ret, 2), LOG_DISK);
  228. return ret;
  229. }
  230. else
  231. {
  232. return 0;
  233. }
  234. };
  235. IDEDevice.prototype.write_control = function(data)
  236. {
  237. dbg_log("set device control: " + h(data, 2) + " interrupts " +
  238. ((data & 2) ? "disabled" : "enabled"), LOG_DISK);
  239. if(data & 4)
  240. {
  241. dbg_log("Reset via control port", LOG_DISK);
  242. this.cpu.device_lower_irq(this.irq);
  243. this.master.device_reset();
  244. this.slave.device_reset();
  245. }
  246. this.device_control = data;
  247. };
  248. IDEDevice.prototype.dma_read_addr = function()
  249. {
  250. dbg_log("dma get address: " + h(this.prdt_addr, 8), LOG_DISK);
  251. return this.prdt_addr;
  252. };
  253. IDEDevice.prototype.dma_set_addr = function(data)
  254. {
  255. dbg_log("dma set address: " + h(data, 8), LOG_DISK);
  256. this.prdt_addr = data;
  257. };
  258. IDEDevice.prototype.dma_read_status = function()
  259. {
  260. dbg_log("DMA read status: " + h(this.dma_status), LOG_DISK);
  261. return this.dma_status;
  262. };
  263. IDEDevice.prototype.dma_write_status = function(value)
  264. {
  265. dbg_log("DMA set status: " + h(value), LOG_DISK);
  266. this.dma_status &= ~(value & 6);
  267. };
  268. IDEDevice.prototype.dma_read_command = function()
  269. {
  270. return this.dma_read_command8() | this.dma_read_status() << 16;
  271. };
  272. IDEDevice.prototype.dma_read_command8 = function()
  273. {
  274. dbg_log("DMA read command: " + h(this.dma_command), LOG_DISK);
  275. return this.dma_command;
  276. };
  277. IDEDevice.prototype.dma_write_command = function(value)
  278. {
  279. dbg_log("DMA write command: " + h(value), LOG_DISK);
  280. this.dma_write_command8(value & 0xFF);
  281. this.dma_write_status(value >> 16 & 0xFF);
  282. };
  283. IDEDevice.prototype.dma_write_command8 = function(value)
  284. {
  285. dbg_log("DMA write command8: " + h(value), LOG_DISK);
  286. let old_command = this.dma_command;
  287. this.dma_command = value & 0x9;
  288. if((old_command & 1) === (value & 1))
  289. {
  290. return;
  291. }
  292. if((value & 1) === 0)
  293. {
  294. this.dma_status &= ~1;
  295. return;
  296. }
  297. this.dma_status |= 1;
  298. switch(this.current_interface.current_command)
  299. {
  300. case 0x25:
  301. case 0xC8:
  302. this.current_interface.do_ata_read_sectors_dma();
  303. break;
  304. case 0xCA:
  305. case 0x35:
  306. this.current_interface.do_ata_write_sectors_dma();
  307. break;
  308. case 0xA0:
  309. this.current_interface.do_atapi_dma();
  310. break;
  311. default:
  312. dbg_log("Spurious dma command write, current command: " +
  313. h(this.current_interface.current_command), LOG_DISK);
  314. dbg_assert(false);
  315. }
  316. };
  317. IDEDevice.prototype.push_irq = function()
  318. {
  319. if((this.device_control & 2) === 0)
  320. {
  321. dbg_log("push irq", LOG_DISK);
  322. this.dma_status |= 4;
  323. this.cpu.device_raise_irq(this.irq);
  324. }
  325. };
  326. IDEDevice.prototype.get_state = function()
  327. {
  328. var state = [];
  329. state[0] = this.master;
  330. state[1] = this.slave;
  331. state[2] = this.ata_port;
  332. state[3] = this.irq;
  333. state[4] = this.pci_id;
  334. state[5] = this.ata_port_high;
  335. state[6] = this.master_port;
  336. state[7] = this.name;
  337. state[8] = this.device_control;
  338. state[9] = this.prdt_addr;
  339. state[10] = this.dma_status;
  340. state[11] = this.current_interface === this.master;
  341. state[12] = this.dma_command;
  342. return state;
  343. };
  344. IDEDevice.prototype.set_state = function(state)
  345. {
  346. this.master.set_state(state[0]);
  347. this.slave.set_state(state[1]);
  348. this.ata_port = state[2];
  349. this.irq = state[3];
  350. this.pci_id = state[4];
  351. this.ata_port_high = state[5];
  352. this.master_port = state[6];
  353. this.name = state[7];
  354. this.device_control = state[8];
  355. this.prdt_addr = state[9];
  356. this.dma_status = state[10];
  357. this.current_interface = state[11] ? this.master : this.slave;
  358. this.dma_command = state[12];
  359. };
  360. /**
  361. * @constructor
  362. */
  363. function IDEInterface(device, cpu, buffer, is_cd, device_nr, interface_nr, bus)
  364. {
  365. this.device = device;
  366. /** @const @type {BusConnector} */
  367. this.bus = bus;
  368. /**
  369. * @const
  370. * @type {number}
  371. */
  372. this.nr = device_nr;
  373. /** @const @type {CPU} */
  374. this.cpu = cpu;
  375. this.buffer = buffer;
  376. /** @type {number} */
  377. this.sector_size = is_cd ? CDROM_SECTOR_SIZE : HD_SECTOR_SIZE;
  378. /** @type {boolean} */
  379. this.is_atapi = is_cd;
  380. /** @type {number} */
  381. this.sector_count = 0;
  382. /** @type {number} */
  383. this.head_count = 0;
  384. /** @type {number} */
  385. this.sectors_per_track = 0;
  386. /** @type {number} */
  387. this.cylinder_count = 0;
  388. if(this.buffer)
  389. {
  390. this.sector_count = this.buffer.byteLength / this.sector_size;
  391. if(this.sector_count !== (this.sector_count | 0))
  392. {
  393. dbg_log("Warning: Disk size not aligned with sector size", LOG_DISK);
  394. this.sector_count = Math.ceil(this.sector_count);
  395. }
  396. if(is_cd)
  397. {
  398. this.head_count = 1;
  399. this.sectors_per_track = 0;
  400. }
  401. else
  402. {
  403. // "default" values: 16/63
  404. // common: 255, 63
  405. this.head_count = 16;
  406. this.sectors_per_track = 63;
  407. }
  408. this.cylinder_count = this.sector_count / this.head_count / this.sectors_per_track;
  409. if(this.cylinder_count !== (this.cylinder_count | 0))
  410. {
  411. dbg_log("Warning: Rounding up cylinder count. Choose different head number", LOG_DISK);
  412. this.cylinder_count = Math.floor(this.cylinder_count);
  413. //this.sector_count = this.cylinder_count * this.head_count *
  414. // this.sectors_per_track * this.sector_size;
  415. }
  416. //if(this.cylinder_count > 16383)
  417. //{
  418. // this.cylinder_count = 16383;
  419. //}
  420. // disk translation: lba
  421. var rtc = cpu.devices.rtc;
  422. // master
  423. rtc.cmos_write(CMOS_BIOS_DISKTRANSFLAG,
  424. rtc.cmos_read(CMOS_BIOS_DISKTRANSFLAG) | 1 << this.nr * 4);
  425. rtc.cmos_write(CMOS_DISK_DATA, rtc.cmos_read(CMOS_DISK_DATA) & 0x0F | 0xF0);
  426. var reg = CMOS_DISK_DRIVE1_CYL;
  427. rtc.cmos_write(reg + 0, this.cylinder_count & 0xFF);
  428. rtc.cmos_write(reg + 1, this.cylinder_count >> 8 & 0xFF);
  429. rtc.cmos_write(reg + 2, this.head_count & 0xFF);
  430. rtc.cmos_write(reg + 3, 0xFF);
  431. rtc.cmos_write(reg + 4, 0xFF);
  432. rtc.cmos_write(reg + 5, 0xC8);
  433. rtc.cmos_write(reg + 6, this.cylinder_count & 0xFF);
  434. rtc.cmos_write(reg + 7, this.cylinder_count >> 8 & 0xFF);
  435. rtc.cmos_write(reg + 8, this.sectors_per_track & 0xFF);
  436. //rtc.cmos_write(CMOS_BIOS_DISKTRANSFLAG,
  437. // rtc.cmos_read(CMOS_BIOS_DISKTRANSFLAG) | 1 << (nr * 4 + 2)); // slave
  438. }
  439. /** @const */
  440. this.stats = {
  441. sectors_read: 0,
  442. sectors_written: 0,
  443. bytes_read: 0,
  444. bytes_written: 0,
  445. loading: false,
  446. };
  447. this.buffer = buffer;
  448. /** @type {number} */
  449. this.is_lba = 0;
  450. /** @type {number} */
  451. this.bytecount = 0;
  452. /** @type {number} */
  453. this.sector = 0;
  454. /** @type {number} */
  455. this.lba_count = 0;
  456. /** @type {number} */
  457. this.cylinder_low = 0;
  458. /** @type {number} */
  459. this.cylinder_high = 0;
  460. /** @type {number} */
  461. this.head = 0;
  462. /** @type {number} */
  463. this.drive_head = 0;
  464. /** @type {number} */
  465. this.status = 0x50;
  466. /** @type {number} */
  467. this.sectors_per_drq = 0x80;
  468. /** @type {number} */
  469. this.error = 0;
  470. /** @type {number} */
  471. this.data_pointer = 0;
  472. this.data = new Uint8Array(64 * 1024);
  473. this.data16 = new Uint16Array(this.data.buffer);
  474. this.data32 = new Int32Array(this.data.buffer);
  475. /** @type {number} */
  476. this.data_length = 0;
  477. /** @type {number} */
  478. this.data_end = 0;
  479. /** @type {number} */
  480. this.current_command = -1;
  481. /** @type {number} */
  482. this.current_atapi_command = -1;
  483. /** @type {number} */
  484. this.write_dest = 0;
  485. // cancellation support
  486. this.last_io_id = 0;
  487. this.in_progress_io_ids = new Set();
  488. this.cancelled_io_ids = new Set();
  489. Object.seal(this);
  490. }
  491. IDEInterface.prototype.device_reset = function()
  492. {
  493. if(this.is_atapi)
  494. {
  495. this.status = 0;
  496. this.bytecount = 1;
  497. this.error = 1;
  498. this.sector = 1; // lba_low
  499. this.cylinder_low = 0x14; // lba_mid
  500. this.cylinder_high = 0xEB; // lba_high
  501. }
  502. else
  503. {
  504. this.status = 0x50 | 1;
  505. this.bytecount = 1;
  506. this.error = 1;
  507. this.sector = 1; // lba_low
  508. // 0, 0 needed by bochs bios
  509. this.cylinder_low = 0; // lba_mid
  510. this.cylinder_high = 0; // lba_high
  511. }
  512. this.cancel_io_operations();
  513. };
  514. IDEInterface.prototype.push_irq = function()
  515. {
  516. this.device.push_irq();
  517. };
  518. IDEInterface.prototype.ata_command = function(cmd)
  519. {
  520. dbg_log("ATA Command: " + h(cmd) + " slave=" + (this.drive_head >> 4 & 1), LOG_DISK);
  521. if(!this.buffer)
  522. {
  523. dbg_log("abort: No buffer", LOG_DISK);
  524. this.error = 4;
  525. this.status = 0x41;
  526. this.push_irq();
  527. return;
  528. }
  529. this.current_command = cmd;
  530. this.error = 0;
  531. switch(cmd)
  532. {
  533. case 0x08:
  534. dbg_log("ATA device reset", LOG_DISK);
  535. this.data_pointer = 0;
  536. this.data_end = 0;
  537. this.data_length = 0;
  538. this.device_reset();
  539. this.push_irq();
  540. break;
  541. case 0x10:
  542. // calibrate drive
  543. this.status = 0x50;
  544. this.cylinder_low = 0;
  545. this.push_irq();
  546. break;
  547. case 0xF8:
  548. // read native max address
  549. this.status = 0x50;
  550. var last_sector = this.sector_count - 1;
  551. this.sector = last_sector & 0xFF;
  552. this.cylinder_low = last_sector >> 8 & 0xFF;
  553. this.cylinder_high = last_sector >> 16 & 0xFF;
  554. this.drive_head = this.drive_head & 0xF0 | last_sector >> 24 & 0x0F;
  555. this.push_irq();
  556. break;
  557. case 0x27:
  558. // read native max address ext
  559. this.status = 0x50;
  560. var last_sector = this.sector_count - 1;
  561. this.sector = last_sector & 0xFF;
  562. this.cylinder_low = last_sector >> 8 & 0xFF;
  563. this.cylinder_high = last_sector >> 16 & 0xFF;
  564. this.sector |= last_sector >> 24 << 8 & 0xFF00;
  565. this.push_irq();
  566. break;
  567. case 0x20:
  568. case 0x24:
  569. case 0x29:
  570. case 0xC4:
  571. // 0x20 read sectors
  572. // 0x24 read sectors ext
  573. // 0xC4 read multiple
  574. // 0x29 read multiple ext
  575. this.ata_read_sectors(cmd);
  576. break;
  577. case 0x30:
  578. case 0x34:
  579. case 0x39:
  580. case 0xC5:
  581. // 0x30 write sectors
  582. // 0x34 write sectors ext
  583. // 0xC5 write multiple
  584. // 0x39 write multiple ext
  585. this.ata_write_sectors(cmd);
  586. break;
  587. case 0x90:
  588. // execute device diagnostic
  589. this.push_irq();
  590. this.error = 0x101;
  591. this.status = 0x50;
  592. break;
  593. case 0x91:
  594. // initialize device parameters
  595. this.status = 0x50;
  596. this.push_irq();
  597. break;
  598. case 0xA0:
  599. // ATA packet
  600. if(this.is_atapi)
  601. {
  602. this.status = 0x58;
  603. this.data_allocate(12);
  604. this.data_end = 12;
  605. this.bytecount = 1;
  606. this.push_irq();
  607. }
  608. break;
  609. case 0xA1:
  610. dbg_log("ATA identify packet device", LOG_DISK);
  611. if(this.is_atapi)
  612. {
  613. this.create_identify_packet();
  614. this.status = 0x58;
  615. this.cylinder_low = 0x14;
  616. this.cylinder_high = 0xEB;
  617. this.push_irq();
  618. }
  619. else
  620. {
  621. this.status = 0x41;
  622. this.push_irq();
  623. }
  624. break;
  625. case 0xC6:
  626. // set multiple mode
  627. // Logical sectors per DRQ Block in word 1
  628. dbg_log("Logical sectors per DRQ Block: " + h(this.bytecount & 0xFF), LOG_DISK);
  629. this.sectors_per_drq = this.bytecount & 0xFF;
  630. this.status = 0x50;
  631. this.push_irq();
  632. break;
  633. case 0x25: // read dma ext
  634. case 0xC8: // read dma
  635. this.ata_read_sectors_dma(cmd);
  636. break;
  637. case 0x35: // write dma ext
  638. case 0xCA: // write dma
  639. this.ata_write_sectors_dma(cmd);
  640. break;
  641. case 0x40:
  642. dbg_log("read verify sectors", LOG_DISK);
  643. this.status = 0x50;
  644. this.push_irq();
  645. break;
  646. case 0xDA:
  647. dbg_log("Unimplemented: get media status", LOG_DISK);
  648. this.status = 0x41;
  649. this.error = 4;
  650. this.push_irq();
  651. break;
  652. case 0xE0:
  653. dbg_log("ATA standby immediate", LOG_DISK);
  654. this.status = 0x50;
  655. this.push_irq();
  656. break;
  657. case 0xE1:
  658. dbg_log("ATA idle immediate", LOG_DISK);
  659. this.status = 0x50;
  660. this.push_irq();
  661. break;
  662. case 0xE7:
  663. dbg_log("ATA flush cache", LOG_DISK);
  664. this.status = 0x50;
  665. this.push_irq();
  666. break;
  667. case 0xEC:
  668. dbg_log("ATA identify device", LOG_DISK);
  669. if(this.is_atapi)
  670. {
  671. this.status = 0x41;
  672. this.error = 4;
  673. this.push_irq();
  674. return;
  675. }
  676. this.create_identify_packet();
  677. this.status = 0x58;
  678. this.push_irq();
  679. break;
  680. case 0xEA:
  681. dbg_log("flush cache ext", LOG_DISK);
  682. this.status = 0x50;
  683. this.push_irq();
  684. break;
  685. case 0xEF:
  686. dbg_log("set features: " + h(this.bytecount & 0xFF), LOG_DISK);
  687. this.status = 0x50;
  688. this.push_irq();
  689. break;
  690. case 0xDE:
  691. // obsolete
  692. this.status = 0x50;
  693. this.push_irq();
  694. break;
  695. case 0xF5:
  696. dbg_log("security freeze lock", LOG_DISK);
  697. this.status = 0x50;
  698. this.push_irq();
  699. break;
  700. case 0xF9:
  701. dbg_log("Unimplemented: set max address", LOG_DISK);
  702. this.status = 0x41;
  703. this.error = 4;
  704. break;
  705. default:
  706. dbg_assert(false, "New ATA cmd on 1F7: " + h(cmd), LOG_DISK);
  707. this.status = 0x41;
  708. // abort bit set
  709. this.error = 4;
  710. }
  711. };
  712. IDEInterface.prototype.atapi_handle = function()
  713. {
  714. dbg_log("ATAPI Command: " + h(this.data[0]) +
  715. " slave=" + (this.drive_head >> 4 & 1), LOG_DISK);
  716. this.data_pointer = 0;
  717. this.current_atapi_command = this.data[0];
  718. switch(this.current_atapi_command)
  719. {
  720. case 0x00:
  721. dbg_log("test unit ready", LOG_DISK);
  722. // test unit ready
  723. this.data_allocate(0);
  724. this.data_end = this.data_length;
  725. this.status = 0x50;
  726. break;
  727. case 0x03:
  728. // request sense
  729. this.data_allocate(this.data[4]);
  730. this.data_end = this.data_length;
  731. this.status = 0x58;
  732. this.data[0] = 0x80 | 0x70;
  733. this.data[2] = 5; // illegal request
  734. this.data[7] = 8;
  735. break;
  736. case 0x12:
  737. // inquiry
  738. var length = this.data[4];
  739. this.status = 0x58;
  740. dbg_log("inquiry: " + h(this.data[1], 2) + " length=" + length, LOG_DISK);
  741. // http://www.t10.org/ftp/x3t9.2/document.87/87-106r0.txt
  742. //this.data_allocate(36);
  743. this.data.set([
  744. 0x05, 0x80, 0x01, 0x31,
  745. // additional length
  746. 31,
  747. 0, 0, 0,
  748. // 8
  749. 0x53, 0x4F, 0x4E, 0x59,
  750. 0x20, 0x20, 0x20, 0x20,
  751. // 16
  752. 0x43, 0x44, 0x2D, 0x52,
  753. 0x4F, 0x4D, 0x20, 0x43,
  754. 0x44, 0x55, 0x2D, 0x31,
  755. 0x30, 0x30, 0x30, 0x20,
  756. // 32
  757. 0x31, 0x2E, 0x31, 0x61,
  758. ]);
  759. this.data_end = this.data_length = Math.min(36, length);
  760. break;
  761. case 0x1A:
  762. // mode sense (6)
  763. this.data_allocate(this.data[4]);
  764. this.data_end = this.data_length;
  765. this.status = 0x58;
  766. break;
  767. case 0x1E:
  768. // prevent/allow medium removal
  769. this.data_allocate(0);
  770. this.data_end = this.data_length;
  771. this.status = 0x50;
  772. break;
  773. case 0x25:
  774. // read capacity
  775. var count = this.sector_count - 1;
  776. this.data_set(new Uint8Array([
  777. count >> 24 & 0xFF,
  778. count >> 16 & 0xFF,
  779. count >> 8 & 0xFF,
  780. count & 0xFF,
  781. 0,
  782. 0,
  783. this.sector_size >> 8 & 0xFF,
  784. this.sector_size & 0xFF,
  785. ]));
  786. this.data_end = this.data_length;
  787. this.status = 0x58;
  788. break;
  789. case 0x28:
  790. // read
  791. if(this.lba_count & 1)
  792. {
  793. this.atapi_read_dma(this.data);
  794. }
  795. else
  796. {
  797. this.atapi_read(this.data);
  798. }
  799. break;
  800. case 0x42:
  801. var length = this.data[8];
  802. this.data_allocate(Math.min(8, length));
  803. this.data_end = this.data_length;
  804. dbg_log("read q subcode: length=" + length, LOG_DISK);
  805. this.status = 0x58;
  806. break;
  807. case 0x43:
  808. // read toc
  809. var length = this.data[8] | this.data[7] << 8;
  810. var format = this.data[9] >> 6;
  811. this.data_allocate(length);
  812. this.data_end = this.data_length;
  813. dbg_log("read toc: " + h(format, 2) +
  814. " length=" + length +
  815. " " + (this.data[1] & 2) +
  816. " " + h(this.data[6]), LOG_DISK);
  817. if(format === 0)
  818. {
  819. var sector_count = this.sector_count;
  820. this.data.set(new Uint8Array([
  821. 0, 18, // length
  822. 1, 1, // first and last session
  823. 0,
  824. 0x14,
  825. 1, // track number
  826. 0,
  827. 0, 0, 0, 0,
  828. 0,
  829. 0x16,
  830. 0xAA, // track number
  831. 0,
  832. sector_count >> 24,
  833. sector_count >> 16 & 0xFF,
  834. sector_count >> 8 & 0xFF,
  835. sector_count & 0xFF,
  836. ]));
  837. }
  838. else if(format === 1)
  839. {
  840. this.data.set(new Uint8Array([
  841. 0, 10, // length
  842. 1, 1, // first and last session
  843. 0, 0,
  844. 0, 0,
  845. 0, 0,
  846. 0, 0,
  847. ]));
  848. }
  849. else
  850. {
  851. dbg_assert(false, "Unimplemented format: " + format);
  852. }
  853. this.status = 0x58;
  854. break;
  855. case 0x46:
  856. // get configuration
  857. var length = this.data[8] | this.data[7] << 8;
  858. length = Math.min(length, 32);
  859. this.data_allocate(length);
  860. this.data_end = this.data_length;
  861. this.data[0] = length - 4 >> 24 & 0xFF;
  862. this.data[1] = length - 4 >> 16 & 0xFF;
  863. this.data[2] = length - 4 >> 8 & 0xFF;
  864. this.data[3] = length - 4 & 0xFF;
  865. this.data[6] = 0x08;
  866. this.data[10] = 3;
  867. this.status = 0x58;
  868. break;
  869. case 0x51:
  870. // read disk information
  871. this.data_allocate(0);
  872. this.data_end = this.data_length;
  873. this.status = 0x50;
  874. break;
  875. case 0x52:
  876. dbg_log("Unimplemented ATAPI command: " + h(this.data[0]), LOG_DISK);
  877. this.status = 0x51;
  878. this.data_length = 0;
  879. this.error = 5 << 4;
  880. break;
  881. case 0x5A:
  882. // mode sense
  883. var length = this.data[8] | this.data[7] << 8;
  884. var page_code = this.data[2];
  885. dbg_log("mode sense: " + h(page_code) + " length=" + length, LOG_DISK);
  886. if(page_code === 0x2A)
  887. {
  888. this.data_allocate(Math.min(30, length));
  889. }
  890. this.data_end = this.data_length;
  891. this.status = 0x58;
  892. break;
  893. case 0xBD:
  894. // mechanism status
  895. this.data_allocate(this.data[9] | this.data[8] << 8);
  896. this.data_end = this.data_length;
  897. this.data[5] = 1;
  898. this.status = 0x58;
  899. break;
  900. case 0x4A:
  901. this.status = 0x51;
  902. this.data_length = 0;
  903. this.error = 5 << 4;
  904. dbg_log("Unimplemented ATAPI command: " + h(this.data[0]), LOG_DISK);
  905. break;
  906. case 0xBE:
  907. // Hiren's boot CD
  908. dbg_log("Unimplemented ATAPI command: " + h(this.data[0]), LOG_DISK);
  909. this.data_allocate(0);
  910. this.data_end = this.data_length;
  911. this.status = 0x50;
  912. break;
  913. default:
  914. this.status = 0x51;
  915. this.data_length = 0;
  916. this.error = 5 << 4;
  917. dbg_log("Unimplemented ATAPI command: " + h(this.data[0]), LOG_DISK);
  918. dbg_assert(false);
  919. }
  920. this.bytecount = this.bytecount & ~7 | 2;
  921. if((this.status & 0x80) === 0)
  922. {
  923. this.push_irq();
  924. }
  925. if((this.status & 0x80) === 0 && this.data_length === 0)
  926. {
  927. this.bytecount |= 1;
  928. this.status &= ~8;
  929. }
  930. };
  931. IDEInterface.prototype.do_write = function()
  932. {
  933. this.status = 0x50;
  934. dbg_assert(this.data_length <= this.data.length);
  935. var data = this.data.subarray(0, this.data_length);
  936. //dbg_log(hex_dump(data), LOG_DISK);
  937. dbg_assert(this.data_length % 512 === 0);
  938. this.ata_advance(this.current_command, this.data_length / 512);
  939. this.push_irq();
  940. this.buffer.set(this.write_dest, data, function()
  941. {
  942. });
  943. this.report_write(this.data_length);
  944. };
  945. IDEInterface.prototype.atapi_read = function(cmd)
  946. {
  947. // Note: Big Endian
  948. var lba = cmd[2] << 24 | cmd[3] << 16 | cmd[4] << 8 | cmd[5];
  949. var count = cmd[7] << 8 | cmd[8];
  950. var flags = cmd[1];
  951. var byte_count = count * this.sector_size;
  952. var start = lba * this.sector_size;
  953. dbg_log("CD read lba=" + h(lba) +
  954. " lbacount=" + h(count) +
  955. " bytecount=" + h(byte_count) +
  956. " flags=" + h(flags), LOG_DISK);
  957. this.data_length = 0;
  958. var req_length = this.cylinder_high << 8 & 0xFF00 | this.cylinder_low & 0xFF;
  959. dbg_log(h(this.cylinder_high, 2) + " " + h(this.cylinder_low, 2), LOG_DISK);
  960. this.cylinder_low = this.cylinder_high = 0; // oak technology driver (windows 3.0)
  961. if(req_length === 0xFFFF)
  962. req_length--;
  963. if(req_length > byte_count)
  964. {
  965. req_length = byte_count;
  966. }
  967. if(start >= this.buffer.byteLength)
  968. {
  969. dbg_assert(false, "CD read: Outside of disk end=" + h(start + byte_count) +
  970. " size=" + h(this.buffer.byteLength), LOG_DISK);
  971. this.status = 0xFF;
  972. this.push_irq();
  973. }
  974. else if(byte_count === 0)
  975. {
  976. this.status = 0x50;
  977. this.data_pointer = 0;
  978. //this.push_irq();
  979. }
  980. else
  981. {
  982. byte_count = Math.min(byte_count, this.buffer.byteLength - start);
  983. this.status = 0x50 | 0x80;
  984. this.report_read_start();
  985. this.read_buffer(start, byte_count, (data) =>
  986. {
  987. //setTimeout(() => {
  988. dbg_log("cd read: data arrived", LOG_DISK);
  989. this.data_set(data);
  990. this.status = 0x58;
  991. this.bytecount = this.bytecount & ~7 | 2;
  992. this.push_irq();
  993. req_length &= ~3;
  994. this.data_end = req_length;
  995. if(this.data_end > this.data_length)
  996. {
  997. this.data_end = this.data_length;
  998. }
  999. this.cylinder_low = this.data_end & 0xFF;
  1000. this.cylinder_high = this.data_end >> 8 & 0xFF;
  1001. this.report_read_end(byte_count);
  1002. //}, 10);
  1003. });
  1004. }
  1005. };
  1006. IDEInterface.prototype.atapi_read_dma = function(cmd)
  1007. {
  1008. // Note: Big Endian
  1009. var lba = cmd[2] << 24 | cmd[3] << 16 | cmd[4] << 8 | cmd[5];
  1010. var count = cmd[7] << 8 | cmd[8];
  1011. var flags = cmd[1];
  1012. var byte_count = count * this.sector_size;
  1013. var start = lba * this.sector_size;
  1014. dbg_log("CD read DMA lba=" + h(lba) +
  1015. " lbacount=" + h(count) +
  1016. " bytecount=" + h(byte_count) +
  1017. " flags=" + h(flags), LOG_DISK);
  1018. if(start >= this.buffer.byteLength)
  1019. {
  1020. dbg_assert(false, "CD read: Outside of disk end=" + h(start + byte_count) +
  1021. " size=" + h(this.buffer.byteLength), LOG_DISK);
  1022. this.status = 0xFF;
  1023. this.push_irq();
  1024. }
  1025. else
  1026. {
  1027. this.status = 0x50 | 0x80;
  1028. this.report_read_start();
  1029. this.read_buffer(start, byte_count, (data) =>
  1030. {
  1031. dbg_log("atapi_read_dma: Data arrived");
  1032. this.report_read_end(byte_count);
  1033. this.status = 0x58;
  1034. this.bytecount = this.bytecount & ~7 | 2;
  1035. this.data_set(data);
  1036. this.do_atapi_dma();
  1037. });
  1038. }
  1039. };
  1040. IDEInterface.prototype.do_atapi_dma = function()
  1041. {
  1042. if((this.device.dma_status & 1) === 0)
  1043. {
  1044. dbg_log("do_atapi_dma: Status not set", LOG_DISK);
  1045. return;
  1046. }
  1047. if((this.status & 0x8) === 0)
  1048. {
  1049. dbg_log("do_atapi_dma: DRQ not set", LOG_DISK);
  1050. return;
  1051. }
  1052. dbg_log("atapi dma transfer len=" + this.data_length, LOG_DISK);
  1053. var prdt_start = this.device.prdt_addr;
  1054. var offset = 0;
  1055. var data = this.data;
  1056. do {
  1057. var addr = this.cpu.read32s(prdt_start);
  1058. var count = this.cpu.read16(prdt_start + 4);
  1059. var end = this.cpu.read8(prdt_start + 7) & 0x80;
  1060. if(!count)
  1061. {
  1062. count = 0x10000;
  1063. }
  1064. dbg_log("dma read dest=" + h(addr) + " count=" + h(count) + " datalen=" + h(this.data_length), LOG_DISK);
  1065. this.cpu.write_blob(data.subarray(offset, Math.min(offset + count, this.data_length)), addr);
  1066. offset += count;
  1067. prdt_start += 8;
  1068. if(offset >= this.data_length && !end)
  1069. {
  1070. dbg_log("leave early end=" + (+end) +
  1071. " offset=" + h(offset) +
  1072. " data_length=" + h(this.data_length) +
  1073. " cmd=" + h(this.current_command), LOG_DISK);
  1074. break;
  1075. }
  1076. }
  1077. while(!end);
  1078. dbg_log("end offset=" + offset, LOG_DISK);
  1079. this.status = 0x50;
  1080. this.device.dma_status &= ~1;
  1081. this.bytecount = this.bytecount & ~7 | 3;
  1082. this.push_irq();
  1083. };
  1084. IDEInterface.prototype.read_data = function(length)
  1085. {
  1086. if(this.data_pointer < this.data_end)
  1087. {
  1088. dbg_assert(this.data_pointer + length - 1 < this.data_end);
  1089. dbg_assert(this.data_pointer % length === 0, h(this.data_pointer) + " " + length);
  1090. if(length === 1)
  1091. {
  1092. var result = this.data[this.data_pointer];
  1093. }
  1094. else if(length === 2)
  1095. {
  1096. var result = this.data16[this.data_pointer >>> 1];
  1097. }
  1098. else
  1099. {
  1100. var result = this.data32[this.data_pointer >>> 2];
  1101. }
  1102. this.data_pointer += length;
  1103. var align = (this.data_end & 0xFFF) === 0 ? 0xFFF : 0xFF;
  1104. if((this.data_pointer & align) === 0)
  1105. {
  1106. dbg_log("Read 1F0: " + h(this.data[this.data_pointer], 2) +
  1107. " cur=" + h(this.data_pointer) +
  1108. " cnt=" + h(this.data_length), LOG_DISK);
  1109. }
  1110. if(this.data_pointer >= this.data_end)
  1111. {
  1112. this.read_end();
  1113. }
  1114. return result;
  1115. }
  1116. else
  1117. {
  1118. dbg_log("Read 1F0: empty", LOG_DISK);
  1119. this.data_pointer += length;
  1120. return 0;
  1121. }
  1122. };
  1123. IDEInterface.prototype.read_end = function()
  1124. {
  1125. dbg_log("read_end cmd=" + h(this.current_command) + " data_pointer=" + h(this.data_pointer) +
  1126. " end=" + h(this.data_end) + " length=" + h(this.data_length), LOG_DISK);
  1127. if(this.current_command === 0xA0)
  1128. {
  1129. if(this.data_end === this.data_length)
  1130. {
  1131. this.status = 0x50;
  1132. this.bytecount = this.bytecount & ~7 | 3;
  1133. this.push_irq();
  1134. }
  1135. else
  1136. {
  1137. this.status = 0x58;
  1138. this.bytecount = this.bytecount & ~7 | 2;
  1139. this.push_irq();
  1140. var byte_count = this.cylinder_high << 8 & 0xFF00 | this.cylinder_low & 0xFF;
  1141. if(this.data_end + byte_count > this.data_length)
  1142. {
  1143. this.cylinder_low = (this.data_length - this.data_end) & 0xFF;
  1144. this.cylinder_high = (this.data_length - this.data_end) >> 8 & 0xFF;
  1145. this.data_end = this.data_length;
  1146. }
  1147. else
  1148. {
  1149. this.data_end += byte_count;
  1150. }
  1151. dbg_log("data_end=" + h(this.data_end), LOG_DISK);
  1152. }
  1153. }
  1154. else
  1155. {
  1156. this.error = 0;
  1157. if(this.data_pointer >= this.data_length)
  1158. {
  1159. this.status = 0x50;
  1160. }
  1161. else
  1162. {
  1163. if(this.current_command === 0xC4 || this.current_command === 0x29)
  1164. {
  1165. var sector_count = Math.min(this.sectors_per_drq,
  1166. (this.data_length - this.data_end) / 512);
  1167. dbg_assert(sector_count % 1 === 0);
  1168. }
  1169. else
  1170. {
  1171. dbg_assert(this.current_command === 0x20 || this.current_command === 0x24);
  1172. var sector_count = 1;
  1173. }
  1174. this.ata_advance(this.current_command, sector_count);
  1175. this.data_end += 512 * sector_count;
  1176. this.status = 0x58;
  1177. this.push_irq();
  1178. }
  1179. }
  1180. };
  1181. IDEInterface.prototype.write_data_port = function(data, length)
  1182. {
  1183. dbg_assert(this.data_pointer % length === 0);
  1184. if(this.data_pointer >= this.data_end)
  1185. {
  1186. dbg_log("Redundant write to data port: " + h(data) + " count=" + h(this.data_end) +
  1187. " cur=" + h(this.data_pointer), LOG_DISK);
  1188. }
  1189. else
  1190. {
  1191. var align = (this.data_end & 0xFFF) === 0 ? 0xFFF : 0xFF;
  1192. if((this.data_pointer + length & align) === 0 || this.data_end < 20)
  1193. {
  1194. dbg_log("Data port: " + h(data >>> 0) + " count=" + h(this.data_end) +
  1195. " cur=" + h(this.data_pointer), LOG_DISK);
  1196. }
  1197. if(length === 1)
  1198. {
  1199. this.data[this.data_pointer++] = data;
  1200. }
  1201. else if(length === 2)
  1202. {
  1203. this.data16[this.data_pointer >>> 1] = data;
  1204. this.data_pointer += 2;
  1205. }
  1206. else
  1207. {
  1208. this.data32[this.data_pointer >>> 2] = data;
  1209. this.data_pointer += 4;
  1210. }
  1211. dbg_assert(this.data_pointer <= this.data_end);
  1212. if(this.data_pointer === this.data_end)
  1213. {
  1214. this.write_end();
  1215. }
  1216. }
  1217. };
  1218. IDEInterface.prototype.write_data_port8 = function(data)
  1219. {
  1220. this.write_data_port(data, 1);
  1221. };
  1222. IDEInterface.prototype.write_data_port16 = function(data)
  1223. {
  1224. this.write_data_port(data, 2);
  1225. };
  1226. IDEInterface.prototype.write_data_port32 = function(data)
  1227. {
  1228. this.write_data_port(data, 4);
  1229. };
  1230. IDEInterface.prototype.write_end = function()
  1231. {
  1232. if(this.current_command === 0xA0)
  1233. {
  1234. this.atapi_handle();
  1235. }
  1236. else
  1237. {
  1238. dbg_log("write_end data_pointer=" + h(this.data_pointer) +
  1239. " data_length=" + h(this.data_length), LOG_DISK);
  1240. if(this.data_pointer >= this.data_length)
  1241. {
  1242. this.do_write();
  1243. }
  1244. else
  1245. {
  1246. dbg_assert(this.current_command === 0x30 ||
  1247. this.current_command === 0x34 ||
  1248. this.current_command === 0xC5,
  1249. "Unexpected command: " + h(this.current_command));
  1250. // XXX: Should advance here, but do_write does all the advancing
  1251. //this.ata_advance(this.current_command, 1);
  1252. this.status = 0x58;
  1253. this.data_end += 512;
  1254. this.push_irq();
  1255. }
  1256. }
  1257. };
  1258. IDEInterface.prototype.ata_advance = function(cmd, sectors)
  1259. {
  1260. dbg_log("Advance sectors=" + sectors + " old_bytecount=" + this.bytecount, LOG_DISK);
  1261. this.bytecount -= sectors;
  1262. if(cmd === 0x24 || cmd === 0x29 || cmd === 0x34 || cmd === 0x39 ||
  1263. cmd === 0x25 || cmd === 0x35)
  1264. {
  1265. var new_sector = sectors + this.get_lba48();
  1266. this.sector = new_sector & 0xFF | new_sector >> 16 & 0xFF00;
  1267. this.cylinder_low = new_sector >> 8 & 0xFF;
  1268. this.cylinder_high = new_sector >> 16 & 0xFF;
  1269. }
  1270. else if(this.is_lba)
  1271. {
  1272. var new_sector = sectors + this.get_lba28();
  1273. this.sector = new_sector & 0xFF;
  1274. this.cylinder_low = new_sector >> 8 & 0xFF;
  1275. this.cylinder_high = new_sector >> 16 & 0xFF;
  1276. this.head = this.head & ~0xF | new_sector & 0xF;
  1277. }
  1278. else // chs
  1279. {
  1280. var new_sector = sectors + this.get_chs();
  1281. var c = new_sector / (this.head_count * this.sectors_per_track) | 0;
  1282. this.cylinder_low = c & 0xFF;
  1283. this.cylinder_high = c >> 8 & 0xFF;
  1284. this.head = (new_sector / this.sectors_per_track | 0) % this.head_count & 0xF;
  1285. this.sector = (new_sector % this.sectors_per_track + 1) & 0xFF;
  1286. dbg_assert(new_sector === this.get_chs());
  1287. }
  1288. };
  1289. IDEInterface.prototype.ata_read_sectors = function(cmd)
  1290. {
  1291. var is_lba48 = cmd === 0x24 || cmd === 0x29;
  1292. var count = this.get_count(is_lba48);
  1293. var lba = this.get_lba(is_lba48);
  1294. var is_single = cmd === 0x20 || cmd === 0x24;
  1295. var byte_count = count * this.sector_size;
  1296. var start = lba * this.sector_size;
  1297. dbg_log("ATA read cmd=" + h(cmd) +
  1298. " mode=" + (this.is_lba ? "lba" : "chs") +
  1299. " lba=" + h(lba) +
  1300. " lbacount=" + h(count) +
  1301. " bytecount=" + h(byte_count), LOG_DISK);
  1302. if(start + byte_count > this.buffer.byteLength)
  1303. {
  1304. dbg_assert(false, "ATA read: Outside of disk", LOG_DISK);
  1305. this.status = 0xFF;
  1306. this.push_irq();
  1307. }
  1308. else
  1309. {
  1310. this.status = 0x80 | 0x40;
  1311. this.report_read_start();
  1312. this.read_buffer(start, byte_count, (data) =>
  1313. {
  1314. //setTimeout(() => {
  1315. dbg_log("ata_read: Data arrived", LOG_DISK);
  1316. this.data_set(data);
  1317. this.status = 0x58;
  1318. this.data_end = is_single ? 512 : Math.min(byte_count, this.sectors_per_drq * 512);
  1319. this.ata_advance(cmd, is_single ? 1 : Math.min(count, this.sectors_per_track));
  1320. this.push_irq();
  1321. this.report_read_end(byte_count);
  1322. //}, 10);
  1323. });
  1324. }
  1325. };
  1326. IDEInterface.prototype.ata_read_sectors_dma = function(cmd)
  1327. {
  1328. var is_lba48 = cmd === 0x25;
  1329. var count = this.get_count(is_lba48);
  1330. var lba = this.get_lba(is_lba48);
  1331. var byte_count = count * this.sector_size;
  1332. var start = lba * this.sector_size;
  1333. dbg_log("ATA DMA read lba=" + h(lba) +
  1334. " lbacount=" + h(count) +
  1335. " bytecount=" + h(byte_count), LOG_DISK);
  1336. if(start + byte_count > this.buffer.byteLength)
  1337. {
  1338. dbg_assert(false, "ATA read: Outside of disk", LOG_DISK);
  1339. this.status = 0xFF;
  1340. this.push_irq();
  1341. return;
  1342. }
  1343. this.status = 0x58;
  1344. this.device.dma_status |= 1;
  1345. };
  1346. IDEInterface.prototype.do_ata_read_sectors_dma = function()
  1347. {
  1348. var cmd = this.current_command;
  1349. var is_lba48 = cmd === 0x25;
  1350. var count = this.get_count(is_lba48);
  1351. var lba = this.get_lba(is_lba48);
  1352. var byte_count = count * this.sector_size;
  1353. var start = lba * this.sector_size;
  1354. dbg_assert(lba < this.buffer.byteLength);
  1355. this.report_read_start();
  1356. var orig_prdt_start = this.device.prdt_addr;
  1357. this.read_buffer(start, byte_count, (data) =>
  1358. {
  1359. //setTimeout(function() {
  1360. dbg_log("do_ata_read_sectors_dma: Data arrived", LOG_DISK);
  1361. var prdt_start = this.device.prdt_addr;
  1362. var offset = 0;
  1363. dbg_assert(orig_prdt_start === prdt_start);
  1364. do {
  1365. var prd_addr = this.cpu.read32s(prdt_start);
  1366. var prd_count = this.cpu.read16(prdt_start + 4);
  1367. var end = this.cpu.read8(prdt_start + 7) & 0x80;
  1368. if(!prd_count)
  1369. {
  1370. prd_count = 0x10000;
  1371. dbg_log("dma: prd count was 0", LOG_DISK);
  1372. }
  1373. dbg_log("dma read transfer dest=" + h(prd_addr) +
  1374. " prd_count=" + h(prd_count), LOG_DISK);
  1375. this.cpu.write_blob(data.subarray(offset, offset + prd_count), prd_addr);
  1376. offset += prd_count;
  1377. prdt_start += 8;
  1378. }
  1379. while(!end);
  1380. dbg_assert(offset === byte_count);
  1381. this.ata_advance(this.current_command, count);
  1382. this.status = 0x50;
  1383. this.device.dma_status &= ~1;
  1384. this.current_command = -1;
  1385. this.push_irq();
  1386. this.report_read_end(byte_count);
  1387. //}.bind(this), 10);
  1388. });
  1389. };
  1390. IDEInterface.prototype.ata_write_sectors = function(cmd)
  1391. {
  1392. var is_lba48 = cmd === 0x34 || cmd === 0x39;
  1393. var count = this.get_count(is_lba48);
  1394. var lba = this.get_lba(is_lba48);
  1395. var is_single = cmd === 0x30 || cmd === 0x34;
  1396. var byte_count = count * this.sector_size;
  1397. var start = lba * this.sector_size;
  1398. dbg_log("ATA write lba=" + h(lba) +
  1399. " mode=" + (this.is_lba ? "lba" : "chs") +
  1400. " lbacount=" + h(count) +
  1401. " bytecount=" + h(byte_count), LOG_DISK);
  1402. if(start + byte_count > this.buffer.byteLength)
  1403. {
  1404. dbg_assert(false, "ATA write: Outside of disk", LOG_DISK);
  1405. this.status = 0xFF;
  1406. this.push_irq();
  1407. }
  1408. else
  1409. {
  1410. this.status = 0x58;
  1411. this.data_allocate_noclear(byte_count);
  1412. this.data_end = is_single ? 512 : Math.min(byte_count, this.sectors_per_drq * 512);
  1413. this.write_dest = start;
  1414. }
  1415. };
  1416. IDEInterface.prototype.ata_write_sectors_dma = function(cmd)
  1417. {
  1418. var is_lba48 = cmd === 0x35;
  1419. var count = this.get_count(is_lba48);
  1420. var lba = this.get_lba(is_lba48);
  1421. var byte_count = count * this.sector_size;
  1422. var start = lba * this.sector_size;
  1423. dbg_log("ATA DMA write lba=" + h(lba) +
  1424. " lbacount=" + h(count) +
  1425. " bytecount=" + h(byte_count), LOG_DISK);
  1426. if(start + byte_count > this.buffer.byteLength)
  1427. {
  1428. dbg_assert(false, "ATA DMA write: Outside of disk", LOG_DISK);
  1429. this.status = 0xFF;
  1430. this.push_irq();
  1431. return;
  1432. }
  1433. this.status = 0x58;
  1434. this.device.dma_status |= 1;
  1435. };
  1436. IDEInterface.prototype.do_ata_write_sectors_dma = function()
  1437. {
  1438. var cmd = this.current_command;
  1439. var is_lba48 = cmd === 0x35;
  1440. var count = this.get_count(is_lba48);
  1441. var lba = this.get_lba(is_lba48);
  1442. var byte_count = count * this.sector_size;
  1443. var start = lba * this.sector_size;
  1444. var prdt_start = this.device.prdt_addr;
  1445. var offset = 0;
  1446. dbg_log("prdt addr: " + h(prdt_start, 8), LOG_DISK);
  1447. const buffer = new Uint8Array(byte_count);
  1448. do {
  1449. var prd_addr = this.cpu.read32s(prdt_start);
  1450. var prd_count = this.cpu.read16(prdt_start + 4);
  1451. var end = this.cpu.read8(prdt_start + 7) & 0x80;
  1452. if(!prd_count)
  1453. {
  1454. prd_count = 0x10000;
  1455. dbg_log("dma: prd count was 0", LOG_DISK);
  1456. }
  1457. dbg_log("dma write transfer dest=" + h(prd_addr) + " prd_count=" + h(prd_count), LOG_DISK);
  1458. var slice = this.cpu.mem8.subarray(prd_addr, prd_addr + prd_count);
  1459. dbg_assert(slice.length === prd_count);
  1460. buffer.set(slice, offset);
  1461. //if(DEBUG)
  1462. //{
  1463. // dbg_log(hex_dump(slice), LOG_DISK);
  1464. //}
  1465. offset += prd_count;
  1466. prdt_start += 8;
  1467. }
  1468. while(!end);
  1469. dbg_assert(offset === buffer.length);
  1470. this.buffer.set(start, buffer, () =>
  1471. {
  1472. dbg_log("dma write completed", LOG_DISK);
  1473. this.ata_advance(this.current_command, count);
  1474. this.status = 0x50;
  1475. this.push_irq();
  1476. this.device.dma_status &= ~1;
  1477. this.current_command = -1;
  1478. });
  1479. this.report_write(byte_count);
  1480. };
  1481. IDEInterface.prototype.get_chs = function()
  1482. {
  1483. var c = this.cylinder_low & 0xFF | this.cylinder_high << 8 & 0xFF00;
  1484. var h = this.head;
  1485. var s = this.sector & 0xFF;
  1486. dbg_log("get_chs: c=" + c + " h=" + h + " s=" + s, LOG_DISK);
  1487. return (c * this.head_count + h) * this.sectors_per_track + s - 1;
  1488. };
  1489. IDEInterface.prototype.get_lba28 = function()
  1490. {
  1491. return this.sector & 0xFF |
  1492. this.cylinder_low << 8 & 0xFF00 |
  1493. this.cylinder_high << 16 & 0xFF0000 |
  1494. (this.head & 0xF) << 24;
  1495. };
  1496. IDEInterface.prototype.get_lba48 = function()
  1497. {
  1498. // Note: Bits over 32 missing
  1499. return (this.sector & 0xFF |
  1500. this.cylinder_low << 8 & 0xFF00 |
  1501. this.cylinder_high << 16 & 0xFF0000 |
  1502. (this.sector >> 8) << 24 & 0xFF000000) >>> 0;
  1503. };
  1504. IDEInterface.prototype.get_lba = function(is_lba48)
  1505. {
  1506. if(is_lba48)
  1507. {
  1508. return this.get_lba48();
  1509. }
  1510. else if(this.is_lba)
  1511. {
  1512. return this.get_lba28();
  1513. }
  1514. else
  1515. {
  1516. return this.get_chs();
  1517. }
  1518. };
  1519. IDEInterface.prototype.get_count = function(is_lba48)
  1520. {
  1521. if(is_lba48)
  1522. {
  1523. var count = this.bytecount;
  1524. if(count === 0) count = 0x10000;
  1525. return count;
  1526. }
  1527. else
  1528. {
  1529. var count = this.bytecount & 0xFF;
  1530. if(count === 0) count = 0x100;
  1531. return count;
  1532. }
  1533. };
  1534. IDEInterface.prototype.create_identify_packet = function()
  1535. {
  1536. // http://bochs.sourceforge.net/cgi-bin/lxr/source/iodev/harddrv.cc#L2821
  1537. if(this.drive_head & 0x10)
  1538. {
  1539. // slave
  1540. this.data_allocate(0);
  1541. return;
  1542. }
  1543. for(var i = 0; i < 512; i++)
  1544. {
  1545. this.data[i] = 0;
  1546. }
  1547. var cylinder_count = Math.min(16383, this.cylinder_count);
  1548. this.data_set([
  1549. 0x40, this.is_atapi ? 0x85 : 0,
  1550. // 1 cylinders
  1551. cylinder_count, cylinder_count >> 8,
  1552. 0, 0,
  1553. // 3 heads
  1554. this.head_count, this.head_count >> 8,
  1555. this.sectors_per_track / 512, this.sectors_per_track / 512 >> 8,
  1556. // 5
  1557. 0, 512 >> 8,
  1558. // sectors per track
  1559. this.sectors_per_track, this.sectors_per_track >> 8,
  1560. 0, 0, 0, 0, 0, 0,
  1561. // 10-19 serial number
  1562. 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  1563. // 15
  1564. 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  1565. // 20
  1566. 3, 0,
  1567. 0, 2,
  1568. 4, 0,
  1569. // 23-26 firmware revision
  1570. 0, 0, 0, 0, 0, 0, 0, 0,
  1571. // 27 model number
  1572. 56, 118, 32, 54, 68, 72, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
  1573. 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
  1574. // 47 max value for set multiple mode
  1575. 0x80, 0,
  1576. 1, 0,
  1577. //0, 3, // capabilities, 2: Only LBA / 3: LBA and DMA
  1578. 0, 2, // capabilities, 2: Only LBA / 3: LBA and DMA
  1579. // 50
  1580. 0, 0,
  1581. 0, 2,
  1582. 0, 2,
  1583. 7, 0,
  1584. // 54 cylinders
  1585. cylinder_count, cylinder_count >> 8,
  1586. // 55 heads
  1587. this.head_count, this.head_count >> 8,
  1588. // 56 sectors per track
  1589. this.sectors_per_track, 0,
  1590. // capacity in sectors
  1591. this.sector_count & 0xFF, this.sector_count >> 8 & 0xFF,
  1592. this.sector_count >> 16 & 0xFF, this.sector_count >> 24 & 0xFF,
  1593. 0, 0,
  1594. // 60
  1595. this.sector_count & 0xFF, this.sector_count >> 8 & 0xFF,
  1596. this.sector_count >> 16 & 0xFF, this.sector_count >> 24 & 0xFF,
  1597. 0, 0,
  1598. // 63, dma supported mode, dma selected mode
  1599. this.current_command === 0xA0 ? 0 : 7, this.current_command === 0xA0 ? 0 : 4,
  1600. //0, 0, // no DMA
  1601. 0, 0,
  1602. // 65
  1603. 30, 0, 30, 0, 30, 0, 30, 0, 0, 0,
  1604. // 70
  1605. 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  1606. // 75
  1607. 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  1608. // 80
  1609. 0x7E, 0, 0, 0, 0, 0, 0, 0x74, 0, 0x40,
  1610. // 85
  1611. 0, 0x40, 0, 0x74, 0, 0x40, 0, 0, 0, 0,
  1612. // 90
  1613. 0, 0, 0, 0, 0, 0, 1, 0x60, 0, 0,
  1614. // 95
  1615. 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  1616. // 100
  1617. this.sector_count & 0xFF, this.sector_count >> 8 & 0xFF,
  1618. this.sector_count >> 16 & 0xFF, this.sector_count >> 24 & 0xFF,
  1619. ]);
  1620. this.data_length = 512;
  1621. this.data_end = 512;
  1622. };
  1623. IDEInterface.prototype.data_allocate = function(len)
  1624. {
  1625. this.data_allocate_noclear(len);
  1626. for(var i = 0; i < (len + 3 >> 2); i++)
  1627. {
  1628. this.data32[i] = 0;
  1629. }
  1630. };
  1631. IDEInterface.prototype.data_allocate_noclear = function(len)
  1632. {
  1633. if(this.data.length < len)
  1634. {
  1635. this.data = new Uint8Array(len + 3 & ~3);
  1636. this.data16 = new Uint16Array(this.data.buffer);
  1637. this.data32 = new Int32Array(this.data.buffer);
  1638. }
  1639. this.data_length = len;
  1640. this.data_pointer = 0;
  1641. };
  1642. IDEInterface.prototype.data_set = function(data)
  1643. {
  1644. this.data_allocate_noclear(data.length);
  1645. this.data.set(data);
  1646. };
  1647. IDEInterface.prototype.report_read_start = function()
  1648. {
  1649. this.stats.loading = true;
  1650. this.bus.send("ide-read-start");
  1651. };
  1652. IDEInterface.prototype.report_read_end = function(byte_count)
  1653. {
  1654. this.stats.loading = false;
  1655. var sector_count = byte_count / this.sector_size | 0;
  1656. this.stats.sectors_read += sector_count;
  1657. this.stats.bytes_read += byte_count;
  1658. this.bus.send("ide-read-end", [this.nr, byte_count, sector_count]);
  1659. };
  1660. IDEInterface.prototype.report_write = function(byte_count)
  1661. {
  1662. var sector_count = byte_count / this.sector_size | 0;
  1663. this.stats.sectors_written += sector_count;
  1664. this.stats.bytes_written += byte_count;
  1665. this.bus.send("ide-write-end", [this.nr, byte_count, sector_count]);
  1666. };
  1667. IDEInterface.prototype.read_buffer = function(start, length, callback)
  1668. {
  1669. const id = this.last_io_id++;
  1670. this.in_progress_io_ids.add(id);
  1671. this.buffer.get(start, length, data =>
  1672. {
  1673. if(this.cancelled_io_ids.delete(id))
  1674. {
  1675. dbg_assert(!this.in_progress_io_ids.has(id));
  1676. return;
  1677. }
  1678. const removed = this.in_progress_io_ids.delete(id);
  1679. dbg_assert(removed);
  1680. callback(data);
  1681. });
  1682. };
  1683. IDEInterface.prototype.cancel_io_operations = function()
  1684. {
  1685. for(const id of this.in_progress_io_ids)
  1686. {
  1687. this.cancelled_io_ids.add(id);
  1688. }
  1689. this.in_progress_io_ids.clear();
  1690. };
  1691. IDEInterface.prototype.get_state = function()
  1692. {
  1693. var state = [];
  1694. state[0] = this.bytecount;
  1695. state[1] = this.cylinder_count;
  1696. state[2] = this.cylinder_high;
  1697. state[3] = this.cylinder_low;
  1698. state[4] = this.data_pointer;
  1699. state[5] = 0;
  1700. state[6] = 0;
  1701. state[7] = 0;
  1702. state[8] = 0;
  1703. state[9] = this.drive_head;
  1704. state[10] = this.error;
  1705. state[11] = this.head;
  1706. state[12] = this.head_count;
  1707. state[13] = this.is_atapi;
  1708. state[14] = this.is_lba;
  1709. state[15] = this.lba_count;
  1710. state[16] = this.data;
  1711. state[17] = this.data_length;
  1712. state[18] = this.sector;
  1713. state[19] = this.sector_count;
  1714. state[20] = this.sector_size;
  1715. state[21] = this.sectors_per_drq;
  1716. state[22] = this.sectors_per_track;
  1717. state[23] = this.status;
  1718. state[24] = this.write_dest;
  1719. state[25] = this.current_command;
  1720. state[26] = this.data_end;
  1721. state[27] = this.current_atapi_command;
  1722. state[28] = this.buffer;
  1723. return state;
  1724. };
  1725. IDEInterface.prototype.set_state = function(state)
  1726. {
  1727. this.bytecount = state[0];
  1728. this.cylinder_count = state[1];
  1729. this.cylinder_high = state[2];
  1730. this.cylinder_low = state[3];
  1731. this.data_pointer = state[4];
  1732. this.drive_head = state[9];
  1733. this.error = state[10];
  1734. this.head = state[11];
  1735. this.head_count = state[12];
  1736. this.is_atapi = state[13];
  1737. this.is_lba = state[14];
  1738. this.lba_count = state[15];
  1739. this.data = state[16];
  1740. this.data_length = state[17];
  1741. this.sector = state[18];
  1742. this.sector_count = state[19];
  1743. this.sector_size = state[20];
  1744. this.sectors_per_drq = state[21];
  1745. this.sectors_per_track = state[22];
  1746. this.status = state[23];
  1747. this.write_dest = state[24];
  1748. this.current_command = state[25];
  1749. this.data_end = state[26];
  1750. this.current_atapi_command = state[27];
  1751. this.data16 = new Uint16Array(this.data.buffer);
  1752. this.data32 = new Int32Array(this.data.buffer);
  1753. this.buffer && this.buffer.set_state(state[28]);
  1754. };