ide.js 57 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092
  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. this.push_irq();
  1161. }
  1162. else
  1163. {
  1164. if(this.current_command === 0xC4 || this.current_command === 0x29)
  1165. {
  1166. var sector_count = Math.min(this.sectors_per_drq,
  1167. (this.data_length - this.data_end) / 512);
  1168. dbg_assert(sector_count % 1 === 0);
  1169. }
  1170. else
  1171. {
  1172. dbg_assert(this.current_command === 0x20 || this.current_command === 0x24);
  1173. var sector_count = 1;
  1174. }
  1175. this.ata_advance(this.current_command, sector_count);
  1176. this.data_end += 512 * sector_count;
  1177. this.status = 0x58;
  1178. this.push_irq();
  1179. }
  1180. }
  1181. };
  1182. IDEInterface.prototype.write_data_port = function(data, length)
  1183. {
  1184. dbg_assert(this.data_pointer % length === 0);
  1185. if(this.data_pointer >= this.data_end)
  1186. {
  1187. dbg_log("Redundant write to data port: " + h(data) + " count=" + h(this.data_end) +
  1188. " cur=" + h(this.data_pointer), LOG_DISK);
  1189. }
  1190. else
  1191. {
  1192. var align = (this.data_end & 0xFFF) === 0 ? 0xFFF : 0xFF;
  1193. if((this.data_pointer + length & align) === 0 || this.data_end < 20)
  1194. {
  1195. dbg_log("Data port: " + h(data >>> 0) + " count=" + h(this.data_end) +
  1196. " cur=" + h(this.data_pointer), LOG_DISK);
  1197. }
  1198. if(length === 1)
  1199. {
  1200. this.data[this.data_pointer++] = data;
  1201. }
  1202. else if(length === 2)
  1203. {
  1204. this.data16[this.data_pointer >>> 1] = data;
  1205. this.data_pointer += 2;
  1206. }
  1207. else
  1208. {
  1209. this.data32[this.data_pointer >>> 2] = data;
  1210. this.data_pointer += 4;
  1211. }
  1212. dbg_assert(this.data_pointer <= this.data_end);
  1213. if(this.data_pointer === this.data_end)
  1214. {
  1215. this.write_end();
  1216. }
  1217. }
  1218. };
  1219. IDEInterface.prototype.write_data_port8 = function(data)
  1220. {
  1221. this.write_data_port(data, 1);
  1222. };
  1223. IDEInterface.prototype.write_data_port16 = function(data)
  1224. {
  1225. this.write_data_port(data, 2);
  1226. };
  1227. IDEInterface.prototype.write_data_port32 = function(data)
  1228. {
  1229. this.write_data_port(data, 4);
  1230. };
  1231. IDEInterface.prototype.write_end = function()
  1232. {
  1233. if(this.current_command === 0xA0)
  1234. {
  1235. this.atapi_handle();
  1236. }
  1237. else
  1238. {
  1239. dbg_log("write_end data_pointer=" + h(this.data_pointer) +
  1240. " data_length=" + h(this.data_length), LOG_DISK);
  1241. if(this.data_pointer >= this.data_length)
  1242. {
  1243. this.do_write();
  1244. }
  1245. else
  1246. {
  1247. dbg_assert(this.current_command === 0x30 ||
  1248. this.current_command === 0x34 ||
  1249. this.current_command === 0xC5,
  1250. "Unexpected command: " + h(this.current_command));
  1251. // XXX: Should advance here, but do_write does all the advancing
  1252. //this.ata_advance(this.current_command, 1);
  1253. this.status = 0x58;
  1254. this.data_end += 512;
  1255. this.push_irq();
  1256. }
  1257. }
  1258. };
  1259. IDEInterface.prototype.ata_advance = function(cmd, sectors)
  1260. {
  1261. dbg_log("Advance sectors=" + sectors + " old_bytecount=" + this.bytecount, LOG_DISK);
  1262. this.bytecount -= sectors;
  1263. if(cmd === 0x24 || cmd === 0x29 || cmd === 0x34 || cmd === 0x39 ||
  1264. cmd === 0x25 || cmd === 0x35)
  1265. {
  1266. var new_sector = sectors + this.get_lba48();
  1267. this.sector = new_sector & 0xFF | new_sector >> 16 & 0xFF00;
  1268. this.cylinder_low = new_sector >> 8 & 0xFF;
  1269. this.cylinder_high = new_sector >> 16 & 0xFF;
  1270. }
  1271. else if(this.is_lba)
  1272. {
  1273. var new_sector = sectors + this.get_lba28();
  1274. this.sector = new_sector & 0xFF;
  1275. this.cylinder_low = new_sector >> 8 & 0xFF;
  1276. this.cylinder_high = new_sector >> 16 & 0xFF;
  1277. this.head = this.head & ~0xF | new_sector & 0xF;
  1278. }
  1279. else // chs
  1280. {
  1281. var new_sector = sectors + this.get_chs();
  1282. var c = new_sector / (this.head_count * this.sectors_per_track) | 0;
  1283. this.cylinder_low = c & 0xFF;
  1284. this.cylinder_high = c >> 8 & 0xFF;
  1285. this.head = (new_sector / this.sectors_per_track | 0) % this.head_count & 0xF;
  1286. this.sector = (new_sector % this.sectors_per_track + 1) & 0xFF;
  1287. dbg_assert(new_sector === this.get_chs());
  1288. }
  1289. };
  1290. IDEInterface.prototype.ata_read_sectors = function(cmd)
  1291. {
  1292. var is_lba48 = cmd === 0x24 || cmd === 0x29;
  1293. var count = this.get_count(is_lba48);
  1294. var lba = this.get_lba(is_lba48);
  1295. var is_single = cmd === 0x20 || cmd === 0x24;
  1296. var byte_count = count * this.sector_size;
  1297. var start = lba * this.sector_size;
  1298. dbg_log("ATA read cmd=" + h(cmd) +
  1299. " mode=" + (this.is_lba ? "lba" : "chs") +
  1300. " lba=" + h(lba) +
  1301. " lbacount=" + h(count) +
  1302. " bytecount=" + h(byte_count), LOG_DISK);
  1303. if(start + byte_count > this.buffer.byteLength)
  1304. {
  1305. dbg_assert(false, "ATA read: Outside of disk", LOG_DISK);
  1306. this.status = 0xFF;
  1307. this.push_irq();
  1308. }
  1309. else
  1310. {
  1311. this.status = 0x80 | 0x40;
  1312. this.report_read_start();
  1313. this.read_buffer(start, byte_count, (data) =>
  1314. {
  1315. //setTimeout(() => {
  1316. dbg_log("ata_read: Data arrived", LOG_DISK);
  1317. this.data_set(data);
  1318. this.status = 0x58;
  1319. this.data_end = is_single ? 512 : Math.min(byte_count, this.sectors_per_drq * 512);
  1320. this.ata_advance(cmd, is_single ? 1 : Math.min(count, this.sectors_per_track));
  1321. this.push_irq();
  1322. this.report_read_end(byte_count);
  1323. //}, 10);
  1324. });
  1325. }
  1326. };
  1327. IDEInterface.prototype.ata_read_sectors_dma = function(cmd)
  1328. {
  1329. var is_lba48 = cmd === 0x25;
  1330. var count = this.get_count(is_lba48);
  1331. var lba = this.get_lba(is_lba48);
  1332. var byte_count = count * this.sector_size;
  1333. var start = lba * this.sector_size;
  1334. dbg_log("ATA DMA read lba=" + h(lba) +
  1335. " lbacount=" + h(count) +
  1336. " bytecount=" + h(byte_count), LOG_DISK);
  1337. if(start + byte_count > this.buffer.byteLength)
  1338. {
  1339. dbg_assert(false, "ATA read: Outside of disk", LOG_DISK);
  1340. this.status = 0xFF;
  1341. this.push_irq();
  1342. return;
  1343. }
  1344. this.status = 0x58;
  1345. this.device.dma_status |= 1;
  1346. };
  1347. IDEInterface.prototype.do_ata_read_sectors_dma = function()
  1348. {
  1349. var cmd = this.current_command;
  1350. var is_lba48 = cmd === 0x25;
  1351. var count = this.get_count(is_lba48);
  1352. var lba = this.get_lba(is_lba48);
  1353. var byte_count = count * this.sector_size;
  1354. var start = lba * this.sector_size;
  1355. dbg_assert(lba < this.buffer.byteLength);
  1356. this.report_read_start();
  1357. var orig_prdt_start = this.device.prdt_addr;
  1358. this.read_buffer(start, byte_count, (data) =>
  1359. {
  1360. //setTimeout(function() {
  1361. dbg_log("do_ata_read_sectors_dma: Data arrived", LOG_DISK);
  1362. var prdt_start = this.device.prdt_addr;
  1363. var offset = 0;
  1364. dbg_assert(orig_prdt_start === prdt_start);
  1365. do {
  1366. var prd_addr = this.cpu.read32s(prdt_start);
  1367. var prd_count = this.cpu.read16(prdt_start + 4);
  1368. var end = this.cpu.read8(prdt_start + 7) & 0x80;
  1369. if(!prd_count)
  1370. {
  1371. prd_count = 0x10000;
  1372. dbg_log("dma: prd count was 0", LOG_DISK);
  1373. }
  1374. dbg_log("dma read transfer dest=" + h(prd_addr) +
  1375. " prd_count=" + h(prd_count), LOG_DISK);
  1376. this.cpu.write_blob(data.subarray(offset, offset + prd_count), prd_addr);
  1377. offset += prd_count;
  1378. prdt_start += 8;
  1379. }
  1380. while(!end);
  1381. dbg_assert(offset === byte_count);
  1382. this.ata_advance(this.current_command, count);
  1383. this.status = 0x50;
  1384. this.device.dma_status &= ~1;
  1385. this.current_command = -1;
  1386. this.push_irq();
  1387. this.report_read_end(byte_count);
  1388. //}.bind(this), 10);
  1389. });
  1390. };
  1391. IDEInterface.prototype.ata_write_sectors = function(cmd)
  1392. {
  1393. var is_lba48 = cmd === 0x34 || cmd === 0x39;
  1394. var count = this.get_count(is_lba48);
  1395. var lba = this.get_lba(is_lba48);
  1396. var is_single = cmd === 0x30 || cmd === 0x34;
  1397. var byte_count = count * this.sector_size;
  1398. var start = lba * this.sector_size;
  1399. dbg_log("ATA write lba=" + h(lba) +
  1400. " mode=" + (this.is_lba ? "lba" : "chs") +
  1401. " lbacount=" + h(count) +
  1402. " bytecount=" + h(byte_count), LOG_DISK);
  1403. if(start + byte_count > this.buffer.byteLength)
  1404. {
  1405. dbg_assert(false, "ATA write: Outside of disk", LOG_DISK);
  1406. this.status = 0xFF;
  1407. this.push_irq();
  1408. }
  1409. else
  1410. {
  1411. this.status = 0x58;
  1412. this.data_allocate_noclear(byte_count);
  1413. this.data_end = is_single ? 512 : Math.min(byte_count, this.sectors_per_drq * 512);
  1414. this.write_dest = start;
  1415. }
  1416. };
  1417. IDEInterface.prototype.ata_write_sectors_dma = function(cmd)
  1418. {
  1419. var is_lba48 = cmd === 0x35;
  1420. var count = this.get_count(is_lba48);
  1421. var lba = this.get_lba(is_lba48);
  1422. var byte_count = count * this.sector_size;
  1423. var start = lba * this.sector_size;
  1424. dbg_log("ATA DMA write lba=" + h(lba) +
  1425. " lbacount=" + h(count) +
  1426. " bytecount=" + h(byte_count), LOG_DISK);
  1427. if(start + byte_count > this.buffer.byteLength)
  1428. {
  1429. dbg_assert(false, "ATA DMA write: Outside of disk", LOG_DISK);
  1430. this.status = 0xFF;
  1431. this.push_irq();
  1432. return;
  1433. }
  1434. this.status = 0x58;
  1435. this.device.dma_status |= 1;
  1436. };
  1437. IDEInterface.prototype.do_ata_write_sectors_dma = function()
  1438. {
  1439. var cmd = this.current_command;
  1440. var is_lba48 = cmd === 0x35;
  1441. var count = this.get_count(is_lba48);
  1442. var lba = this.get_lba(is_lba48);
  1443. var byte_count = count * this.sector_size;
  1444. var start = lba * this.sector_size;
  1445. var prdt_start = this.device.prdt_addr;
  1446. var offset = 0;
  1447. dbg_log("prdt addr: " + h(prdt_start, 8), LOG_DISK);
  1448. const buffer = new Uint8Array(byte_count);
  1449. do {
  1450. var prd_addr = this.cpu.read32s(prdt_start);
  1451. var prd_count = this.cpu.read16(prdt_start + 4);
  1452. var end = this.cpu.read8(prdt_start + 7) & 0x80;
  1453. if(!prd_count)
  1454. {
  1455. prd_count = 0x10000;
  1456. dbg_log("dma: prd count was 0", LOG_DISK);
  1457. }
  1458. dbg_log("dma write transfer dest=" + h(prd_addr) + " prd_count=" + h(prd_count), LOG_DISK);
  1459. var slice = this.cpu.mem8.subarray(prd_addr, prd_addr + prd_count);
  1460. dbg_assert(slice.length === prd_count);
  1461. buffer.set(slice, offset);
  1462. //if(DEBUG)
  1463. //{
  1464. // dbg_log(hex_dump(slice), LOG_DISK);
  1465. //}
  1466. offset += prd_count;
  1467. prdt_start += 8;
  1468. }
  1469. while(!end);
  1470. dbg_assert(offset === buffer.length);
  1471. this.buffer.set(start, buffer, () =>
  1472. {
  1473. dbg_log("dma write completed", LOG_DISK);
  1474. this.ata_advance(this.current_command, count);
  1475. this.status = 0x50;
  1476. this.push_irq();
  1477. this.device.dma_status &= ~1;
  1478. this.current_command = -1;
  1479. });
  1480. this.report_write(byte_count);
  1481. };
  1482. IDEInterface.prototype.get_chs = function()
  1483. {
  1484. var c = this.cylinder_low & 0xFF | this.cylinder_high << 8 & 0xFF00;
  1485. var h = this.head;
  1486. var s = this.sector & 0xFF;
  1487. dbg_log("get_chs: c=" + c + " h=" + h + " s=" + s, LOG_DISK);
  1488. return (c * this.head_count + h) * this.sectors_per_track + s - 1;
  1489. };
  1490. IDEInterface.prototype.get_lba28 = function()
  1491. {
  1492. return this.sector & 0xFF |
  1493. this.cylinder_low << 8 & 0xFF00 |
  1494. this.cylinder_high << 16 & 0xFF0000 |
  1495. (this.head & 0xF) << 24;
  1496. };
  1497. IDEInterface.prototype.get_lba48 = function()
  1498. {
  1499. // Note: Bits over 32 missing
  1500. return (this.sector & 0xFF |
  1501. this.cylinder_low << 8 & 0xFF00 |
  1502. this.cylinder_high << 16 & 0xFF0000 |
  1503. (this.sector >> 8) << 24 & 0xFF000000) >>> 0;
  1504. };
  1505. IDEInterface.prototype.get_lba = function(is_lba48)
  1506. {
  1507. if(is_lba48)
  1508. {
  1509. return this.get_lba48();
  1510. }
  1511. else if(this.is_lba)
  1512. {
  1513. return this.get_lba28();
  1514. }
  1515. else
  1516. {
  1517. return this.get_chs();
  1518. }
  1519. };
  1520. IDEInterface.prototype.get_count = function(is_lba48)
  1521. {
  1522. if(is_lba48)
  1523. {
  1524. var count = this.bytecount;
  1525. if(count === 0) count = 0x10000;
  1526. return count;
  1527. }
  1528. else
  1529. {
  1530. var count = this.bytecount & 0xFF;
  1531. if(count === 0) count = 0x100;
  1532. return count;
  1533. }
  1534. };
  1535. IDEInterface.prototype.create_identify_packet = function()
  1536. {
  1537. // http://bochs.sourceforge.net/cgi-bin/lxr/source/iodev/harddrv.cc#L2821
  1538. if(this.drive_head & 0x10)
  1539. {
  1540. // slave
  1541. this.data_allocate(0);
  1542. return;
  1543. }
  1544. for(var i = 0; i < 512; i++)
  1545. {
  1546. this.data[i] = 0;
  1547. }
  1548. var cylinder_count = Math.min(16383, this.cylinder_count);
  1549. this.data_set([
  1550. 0x40, this.is_atapi ? 0x85 : 0,
  1551. // 1 cylinders
  1552. cylinder_count, cylinder_count >> 8,
  1553. 0, 0,
  1554. // 3 heads
  1555. this.head_count, this.head_count >> 8,
  1556. this.sectors_per_track / 512, this.sectors_per_track / 512 >> 8,
  1557. // 5
  1558. 0, 512 >> 8,
  1559. // sectors per track
  1560. this.sectors_per_track, this.sectors_per_track >> 8,
  1561. 0, 0, 0, 0, 0, 0,
  1562. // 10-19 serial number
  1563. 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  1564. // 15
  1565. 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  1566. // 20
  1567. 3, 0,
  1568. 0, 2,
  1569. 4, 0,
  1570. // 23-26 firmware revision
  1571. 0, 0, 0, 0, 0, 0, 0, 0,
  1572. // 27 model number
  1573. 56, 118, 32, 54, 68, 72, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
  1574. 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
  1575. // 47 max value for set multiple mode
  1576. 0x80, 0,
  1577. 1, 0,
  1578. //0, 3, // capabilities, 2: Only LBA / 3: LBA and DMA
  1579. 0, 2, // capabilities, 2: Only LBA / 3: LBA and DMA
  1580. // 50
  1581. 0, 0,
  1582. 0, 2,
  1583. 0, 2,
  1584. 7, 0,
  1585. // 54 cylinders
  1586. cylinder_count, cylinder_count >> 8,
  1587. // 55 heads
  1588. this.head_count, this.head_count >> 8,
  1589. // 56 sectors per track
  1590. this.sectors_per_track, 0,
  1591. // capacity in sectors
  1592. this.sector_count & 0xFF, this.sector_count >> 8 & 0xFF,
  1593. this.sector_count >> 16 & 0xFF, this.sector_count >> 24 & 0xFF,
  1594. 0, 0,
  1595. // 60
  1596. this.sector_count & 0xFF, this.sector_count >> 8 & 0xFF,
  1597. this.sector_count >> 16 & 0xFF, this.sector_count >> 24 & 0xFF,
  1598. 0, 0,
  1599. // 63, dma supported mode, dma selected mode
  1600. this.current_command === 0xA0 ? 0 : 7, this.current_command === 0xA0 ? 0 : 4,
  1601. //0, 0, // no DMA
  1602. 0, 0,
  1603. // 65
  1604. 30, 0, 30, 0, 30, 0, 30, 0, 0, 0,
  1605. // 70
  1606. 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  1607. // 75
  1608. 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  1609. // 80
  1610. 0x7E, 0, 0, 0, 0, 0, 0, 0x74, 0, 0x40,
  1611. // 85
  1612. 0, 0x40, 0, 0x74, 0, 0x40, 0, 0, 0, 0,
  1613. // 90
  1614. 0, 0, 0, 0, 0, 0, 1, 0x60, 0, 0,
  1615. // 95
  1616. 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  1617. // 100
  1618. this.sector_count & 0xFF, this.sector_count >> 8 & 0xFF,
  1619. this.sector_count >> 16 & 0xFF, this.sector_count >> 24 & 0xFF,
  1620. ]);
  1621. this.data_length = 512;
  1622. this.data_end = 512;
  1623. };
  1624. IDEInterface.prototype.data_allocate = function(len)
  1625. {
  1626. this.data_allocate_noclear(len);
  1627. for(var i = 0; i < (len + 3 >> 2); i++)
  1628. {
  1629. this.data32[i] = 0;
  1630. }
  1631. };
  1632. IDEInterface.prototype.data_allocate_noclear = function(len)
  1633. {
  1634. if(this.data.length < len)
  1635. {
  1636. this.data = new Uint8Array(len + 3 & ~3);
  1637. this.data16 = new Uint16Array(this.data.buffer);
  1638. this.data32 = new Int32Array(this.data.buffer);
  1639. }
  1640. this.data_length = len;
  1641. this.data_pointer = 0;
  1642. };
  1643. IDEInterface.prototype.data_set = function(data)
  1644. {
  1645. this.data_allocate_noclear(data.length);
  1646. this.data.set(data);
  1647. };
  1648. IDEInterface.prototype.report_read_start = function()
  1649. {
  1650. this.stats.loading = true;
  1651. this.bus.send("ide-read-start");
  1652. };
  1653. IDEInterface.prototype.report_read_end = function(byte_count)
  1654. {
  1655. this.stats.loading = false;
  1656. var sector_count = byte_count / this.sector_size | 0;
  1657. this.stats.sectors_read += sector_count;
  1658. this.stats.bytes_read += byte_count;
  1659. this.bus.send("ide-read-end", [this.nr, byte_count, sector_count]);
  1660. };
  1661. IDEInterface.prototype.report_write = function(byte_count)
  1662. {
  1663. var sector_count = byte_count / this.sector_size | 0;
  1664. this.stats.sectors_written += sector_count;
  1665. this.stats.bytes_written += byte_count;
  1666. this.bus.send("ide-write-end", [this.nr, byte_count, sector_count]);
  1667. };
  1668. IDEInterface.prototype.read_buffer = function(start, length, callback)
  1669. {
  1670. const id = this.last_io_id++;
  1671. this.in_progress_io_ids.add(id);
  1672. this.buffer.get(start, length, data =>
  1673. {
  1674. if(this.cancelled_io_ids.delete(id))
  1675. {
  1676. dbg_assert(!this.in_progress_io_ids.has(id));
  1677. return;
  1678. }
  1679. const removed = this.in_progress_io_ids.delete(id);
  1680. dbg_assert(removed);
  1681. callback(data);
  1682. });
  1683. };
  1684. IDEInterface.prototype.cancel_io_operations = function()
  1685. {
  1686. for(const id of this.in_progress_io_ids)
  1687. {
  1688. this.cancelled_io_ids.add(id);
  1689. }
  1690. this.in_progress_io_ids.clear();
  1691. };
  1692. IDEInterface.prototype.get_state = function()
  1693. {
  1694. var state = [];
  1695. state[0] = this.bytecount;
  1696. state[1] = this.cylinder_count;
  1697. state[2] = this.cylinder_high;
  1698. state[3] = this.cylinder_low;
  1699. state[4] = this.data_pointer;
  1700. state[5] = 0;
  1701. state[6] = 0;
  1702. state[7] = 0;
  1703. state[8] = 0;
  1704. state[9] = this.drive_head;
  1705. state[10] = this.error;
  1706. state[11] = this.head;
  1707. state[12] = this.head_count;
  1708. state[13] = this.is_atapi;
  1709. state[14] = this.is_lba;
  1710. state[15] = this.lba_count;
  1711. state[16] = this.data;
  1712. state[17] = this.data_length;
  1713. state[18] = this.sector;
  1714. state[19] = this.sector_count;
  1715. state[20] = this.sector_size;
  1716. state[21] = this.sectors_per_drq;
  1717. state[22] = this.sectors_per_track;
  1718. state[23] = this.status;
  1719. state[24] = this.write_dest;
  1720. state[25] = this.current_command;
  1721. state[26] = this.data_end;
  1722. state[27] = this.current_atapi_command;
  1723. state[28] = this.buffer;
  1724. return state;
  1725. };
  1726. IDEInterface.prototype.set_state = function(state)
  1727. {
  1728. this.bytecount = state[0];
  1729. this.cylinder_count = state[1];
  1730. this.cylinder_high = state[2];
  1731. this.cylinder_low = state[3];
  1732. this.data_pointer = state[4];
  1733. this.drive_head = state[9];
  1734. this.error = state[10];
  1735. this.head = state[11];
  1736. this.head_count = state[12];
  1737. this.is_atapi = state[13];
  1738. this.is_lba = state[14];
  1739. this.lba_count = state[15];
  1740. this.data = state[16];
  1741. this.data_length = state[17];
  1742. this.sector = state[18];
  1743. this.sector_count = state[19];
  1744. this.sector_size = state[20];
  1745. this.sectors_per_drq = state[21];
  1746. this.sectors_per_track = state[22];
  1747. this.status = state[23];
  1748. this.write_dest = state[24];
  1749. this.current_command = state[25];
  1750. this.data_end = state[26];
  1751. this.current_atapi_command = state[27];
  1752. this.data16 = new Uint16Array(this.data.buffer);
  1753. this.data32 = new Int32Array(this.data.buffer);
  1754. this.buffer && this.buffer.set_state(state[28]);
  1755. };