From fbf36a4fa52d34fa284651c26c30d6a9b2ef7c50 Mon Sep 17 00:00:00 2001 From: Rupert Hausberger Date: Fri, 15 Jul 2016 19:44:16 +0200 Subject: [PATCH] update 0.9.0 --- disass.htm | 90 + disass.js | 202 + images/logo.png | Bin 0 -> 3016 bytes index.css | 425 +- index.htm | 2397 ++-- index.js | 3782 ++++--- readme.htm | 1249 ++- sae/amiga.js | 984 +- sae/audio.js | 2441 ++-- sae/autoconf.js | 727 ++ sae/blitter.js | 5657 ++++++---- sae/cia.js | 1500 ++- sae/config.js | 2597 ++++- sae/constants.js | 366 - sae/copper.js | 1114 +- sae/cpu.js | 14059 +++++++++++++++-------- sae/custom.js | 1524 +-- sae/disassembler.js | 58 + sae/disk.js | 5305 +++++++-- sae/dms.js | 1308 +++ sae/events.js | 1145 +- sae/expansion.js | 1685 ++- sae/filesys.js | 179 + sae/gayle.js | 1586 +++ sae/hardfile.js | 1339 +++ sae/ide.js | 1499 +++ sae/input.js | 742 +- sae/m68k.js | 519 + sae/memory.js | 3445 ++++-- sae/playfield.js | 25242 ++++++++++++++++++++++++++++++++---------- sae/prototypes.js | 78 + sae/roms.js | 723 ++ sae/rtc.js | 466 +- sae/serial.js | 368 +- sae/utils.js | 1299 ++- sae/video.js | 2846 ++++- 36 files changed, 66426 insertions(+), 22520 deletions(-) create mode 100644 disass.htm create mode 100644 disass.js create mode 100644 images/logo.png create mode 100644 sae/autoconf.js delete mode 100644 sae/constants.js create mode 100644 sae/disassembler.js create mode 100644 sae/dms.js create mode 100644 sae/filesys.js create mode 100644 sae/gayle.js create mode 100644 sae/hardfile.js create mode 100644 sae/ide.js create mode 100644 sae/m68k.js create mode 100644 sae/prototypes.js create mode 100644 sae/roms.js diff --git a/disass.htm b/disass.htm new file mode 100644 index 0000000..b12b0cf --- /dev/null +++ b/disass.htm @@ -0,0 +1,90 @@ + + + + SAE - Scripted Amiga Emulator + + + + + + + + + + +
+ +
+ Here you can use the internal disassembler. Code-types are from 68000-68030, no FPU, no MMU.
+ Note: No files or informations about files are transferred to the internet. Disassembling is done in the browser, using javascript. +
+ + + + + +
File + <unset> (required) + + +
+
+ + + + + + + + + + +
+ Offset $ + Limit instructions + +
+ Radix + + Hex-prefix + + Hex-width + + Relocate +
+ Show + Address + Code/Memory + Upper-case +
+
+ +
+
+ +
+ + diff --git a/disass.js b/disass.js new file mode 100644 index 0000000..dbd0534 --- /dev/null +++ b/disass.js @@ -0,0 +1,202 @@ +/*------------------------------------------------------------------------- +| SAE - Scripted Amiga Emulator +| https://github.com/naTmeg/ScriptedAmigaEmulator +| +| Copyright (C) 2012-2016 Rupert Hausberger +| +| This program is free software; you can redistribute it and/or +| modify it under the terms of the GNU General Public License +| as published by the Free Software Foundation; either version 2 +| of the License, or (at your option) any later version. +| +| This program is distributed in the hope that it will be useful, +| but WITHOUT ANY WARRANTY; without even the implied warranty of +| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +| GNU General Public License for more details. +| +| Note: This file does not contain any emulator-code. +-------------------------------------------------------------------------*/ + +var sda = null; /* SDA instance */ +var cfg = null; /* reference to the config-object */ + + +var filesize = 0; + +var showAddr = true; +var showCode = true; +var upperCase = false; + +var result = []; + +/*---------------------------------*/ + +function isHex(str) { + var str_uc = str.toUpperCase(); + for (var i = 0; i < str_uc.length; i++) { + var chr = str_uc.charCodeAt(i); + if (!((chr >= 48 && chr <= 57) || (chr >= 65 && chr <= 70))) + return false; + } + return true; +} + +/*---------------------------------*/ + +function getSelectValue(id) { + var e = document.getElementById(id); + for (var i = 0; i < e.length; i++) { + if (e[i].selected) return e[i].value; + } + return false; +} + +/*---------------------------------*/ + +function loadFile(e, callback) { + var reader = new FileReader(); + reader.onload = callback; + reader.readAsBinaryString(e); +} + +/*---------------------------------*/ + +function result2text() { + var i, j, text = ""; + for (i = 0; i < result.length; i++) { + var addr = result[i][0]; + var code = result[i][1]; + var words = result[i][2]; + var inst = result[i][3]; + + if (showAddr) + text += sprintf(upperCase ? "$%06X " : "$%06x ", addr); + if (showCode) { + for (j = 0; j < words; j++) text += sprintf(upperCase ? "%04X " : "%04x ", code[j]); + //for (j = words; j < 5; j++) text += "     "; + for (j = words; j < 5; j++) text += " "; + } + text += upperCase ? inst.toUpperCase() : inst; + //text += "
"; + text += "\n"; + + if (addr + words*2 >= filesize) break; + } + return text; +} + +/*---------------------------------*/ + +function init() { + try { + sda = new ScriptedDisAssembler(); + cfg = sda.getConfig(); /* reference to config */ + //console.log(cfg); + } catch(e) { + throw e; + } +} + +function disass() { + try { + result = sda.disassemble(); + //console.log(result); + + document.getElementById("disass_code").value = result2text(); + document.getElementById("disass_cfg").style.display = "table"; + document.getElementById("disass_code").style.display = "inline"; + } catch(e) { + throw e; + } +} + +/*---------------------------------*/ + +function updFile() { + var e = document.getElementById("cfg_file").files[0]; + if (!e) return; + + loadFile(e, function (event) { + cfg.code = event.target.result; + cfg.offset = 0; + + filesize = event.target.result.length; + + var fn = document.getElementById("cfg_filename"); + fn.className = ""; + fn.innerHTML = e.name; + document.getElementById("cfg_offset").value = "0"; + + disass(); + }); +} + +function updOffset() { + var offset = document.getElementById("cfg_offset"); + if (isHex(offset.value)) { + var newoffset = parseInt(offset.value, 16); + + if (newoffset < filesize) { + cfg.offset = newoffset; + disass(); + } else { + alert(sprintf("The value at 'Offset' is behing the file-size. (max $%x)", filesize - 1)); + offset.focus(); + } + } else { + alert("The value at 'Offset' in not a hexadecimal number."); + offset.focus(); + } +} + +function updLimit() { + var limit = document.getElementById("cfg_limit"); + //if (isDec(limit.value)) { + cfg.limit = parseInt(limit.value); + disass(); + /*} else { + alert("The value at "Limit" in not a decimal number."); + limit.focus(); + }*/ +} + +function updNext() { + var addr = result[result.length - 1][0]; + var words = result[result.length - 1][2]; + + cfg.offset = addr + words*2; + document.getElementById("cfg_offset").value = sprintf("%x", cfg.offset); + disass(); +} + +function updRadix() { + cfg.radix = parseInt(getSelectValue("cfg_radix")); + disass(); +} +function updPrefx() { + cfg.prefx = parseInt(getSelectValue("cfg_prefx")) == 1 ? "$" : "0x"; + disass(); +} +function updWidth() { + cfg.width = parseInt(getSelectValue("cfg_width")); + disass(); +} + +function updCase() { + upperCase = document.getElementById("cfg_case").checked; + disass(); +} + +function updReloc() { + cfg.reloc = document.getElementById("cfg_reloc").checked; + disass(); +} + +function updShowAddr() { + showAddr = document.getElementById("cfg_showAddr").checked; + disass(); +} +function updShowCode() { + showCode = document.getElementById("cfg_showCode").checked; + disass(); +} diff --git a/images/logo.png b/images/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..231a3afca647b40e5071f995152c4e8ea811683c GIT binary patch literal 3016 zcmV;(3pezMP)0015c0ssI2#UsE600001b5ch_0Itp) z=>Px#1ZP1_K>z@;j|==^1poj5AY({UO#lFTCIA3{ga82g0001h=l}q9FaQARU;qF* zm;eA5aGbhPJOBU-MoC0LRCr$PTq|!}ITW7#J)=rd6;S0j3@IonSWpl&sHmtUC_yPJ zD;h0JSVCLa!bn9!g2P8DyKA3g`#gQG?<7^HkuTbv+_BH&`_9Xr{`2eCuSI{l1-b>E zr3C`L`_nDZE$}QYuy~eQb)~umx&>lket=fEImJ5Z^kx_iP`oZux4_?GfrF#>_VR?9 zpw;JxgJk$XQl4CHdkp$p(7vafIo~XTv-e!$4}Hz2_fQlfs-;{S{}LhnTQEH^-o%|( z=U;z5>}{DLs}V%sdlB_TZJ6bH^YzF5ZpQjjN2fy3Mo2CYaisDN6gFc&Woov zLEjb^Pij#!cvU=Svh|0{H^YMD?7gw{I{-N@jHb6oY-9MN^(I1k2BsS=qI@6N{U~}T zE=I5Xe0TzB9cTs-XPQEkCyO9k5KYKdK%nftI;S{NaT99l#O4$$v#7N#*p9ec)o7Di z)ahLj&!M+toJJr$$!k(a%r^5vxe_CL?a2T+sivT}1WhCtJ)8BiI3S2O6VsD&loy8W z#Y@;I+90xfPg*hrKh`TG+pyhkci-NVCFTYo%d6%3N+tie$?*LHZIbK`rA)Mjn*h;V zUjzQ`?ANm^V$t=0V2c>7MU~!GyDU1$&t(W0XkE4)V6)y7&Q7d6AV5y) zLiBbrXM_`bcK4rF2(^jOKDq1o3&ZaIM}q2ZzompOkMoKSz{BqDqD%*7hv8gLEO~?o zp;GU%+g;;)aY=7tE{pU|tE^VZ9hg|KjDV+nodRWcrASGMSj^3YXI?D$9SV~T5z*)@ zM?4ZeN`HTqbIF`#8+V`en&@BVS86;l&`jw`0ohudo5TWhE&XiIj&e`TDmSN#^ZIkD z4nkMOaK?LMIkb{hD;ufH!ioCQvDVIrq;t@?%oy2DPETp}H?J;Wwb?ll6Ig44NYZb) zTG>E=VlUTgv51JpazL3H2%WegZwq3fx3Ax(>d7sg+O=qGzcXuaVeml_B7_ZQ9DyH+ zxdI^x3~#i-2W1(<{97E2yq-l?a-~d*baGO#k+IYcNZW9^Gouy~6(OtHo3}zRuqhAb z)>OHTcX97vrq$BveKs9q9$J}d(rMD-M{lnu_9_bokxW}v7JYeO=6=3z4T5U zj*H_o#-7|Um@edFWpmMcZ!ZaSK8YmJ)t0H$lO5b`C;>*KPum2reu$7_5Bb^qdhQrm z8U*#AaecU@L4j!OfC655%3HqGCn$0Sq)LOz_v7(mvgAvD=x5ca6 zAB)ACFWA;eFG2LQAY?{kzLp`|{=stF#Rfy~6d<*;pfBa+-TQB@{Dz?z{sqJJ&wiA z1}oXu66j={Z)`Zrw$vi?4M1+M>I<*)Jij_m{}-3}1SND~_jK}>QBvE*_F-U2URKQ2 zqDt?PWLy)A<~|8LsjFa0m07H$ata?&KM6uVf3TD;z>;HmP^tkNGTw?&h|-XIg=r7~ zN$D;noM{qG(mO~G#kUw>YMw*EV^TzJ<49nLYl#-V8hMBY-{nIqR-}Pr*gQ*)k<_}d zoANoUKux67@dyLY?HRvY!>3ku>B+pU0O15p(|+g9J9c~jr8|5P);LRp3V@5KInkKB zMP**09B=<7N@Q<{;2LM7nA2ql1sx~Bs%XuuAY&(+FW4enEy5dYKT)|5(lt|^!%9OP zDoT|0a4iI)Sini-7w5PbzmyXPm^i<7m>v%-c*UgqxUwNNcgj7^`JoAx6NQ%L7nl0za zGSrCfp+(IyHv1KfRci{jB&-E;ol1)P{1{Pfu)Ws}yFF~^C{+bymED@jNc(9L`SdPl zEurtUUI|RkM`EQK{PE?TK*2~Kr@Fyf%jyS9Q&LOQd7i8UdR3Y0Mn4_#M?F-?U<0UX zlQumiE-hNVOCZJu&{pKJ4Nu-?u7ve{IyVC)8j^RUw{E?K$6^B{ot)cSgm3q=CXV)0&SvRX4-0ib-tBmyKvM!H>I^Mrj?GcH%(>!$7a#9T zaWP6vl}cpjYfawC5iQBPij8{d$?V>QH1Iimsewe5?9IOV`iqmmZB4>@LWkZ#54CIUzvMG5OGIsAwv@7i^^+GOFLefQ^FKvaY7#6&q~=lZJ$$_3RgIHm$QND zTrGPBR~8`}137>6M&>5W94*?$=A!U`Ir-1;^8SbMsm$=D2Ad?koT`q$ZpP#EdOJ3} z6fGOeSWnPd70Z!+f8Ro)8olMbBcHZqSn!rL56mQ3VA=)`Nr59cm8g=XlpJQ-8E6^L zxYUaIAXL?BI1oc7E0E@sVhlF22BCX9By$LE8VIsHrD=6sdRzSokuU__datu7>V@Yw zO#al7lRKU|9^`LthE~n%-dR00kAJ*UC5z_=9`2`3JxMH;`u$ykb)4`Y$(HT6Y z=7{dJZNmP z`0Cv^lyYWdbgZ^KIt#$e3I*{t@9{#ue&S`E>cxlf$0Fe{G#q_qoV%8s*5Z}_ zgTjX499JvFGMz~MrnoxBfW9;o-sUsOPzjK?(vkutQ}^Us<0&n2YmLT4!TW_ z+n5~*`l3+@NhrP%eJlL0MK%hOh!86Wb8f@@Oc2 z7GMV_ram46V`pJw5|H8^7FwXtEd#QVM1FCOpO)*U;lH5~l24VE=3VpVz+b8Vgqu#| zaOapu?P>VE6wRpx^g8Cae-Hwty==sx1HLRxu~ITkMHeFg=>q{sE^I7qMt=A{nALF% z$zS=Sdkksb1zqx|Sa!K`CWDV?QM>I^lif7{U&O_a6hOeh1yZ=9qumEKH6Owyj9vU( z836E@uKLWvMgt&?srMxjhw;JvYb}anUQfQ~FY+cUnf^kzz%#SJ!P8robR)k~d}fa6 z>U0Y{-U5e9@9IcGPW2yeg1$nxz;m_00n@uWaGd?`A3ay+b-lU;#w~ET^p1m#(J@kY zZMQ(Tz+X)7?!0b+Zh^;G;GnbjV-)M(?H1@3==AOw=oWak7Wf}95sLG})nNz#0000< KMNUMnLSTaQvASgd literal 0 HcmV?d00001 diff --git a/index.css b/index.css index 47196c9..15fec9c 100644 --- a/index.css +++ b/index.css @@ -1,65 +1,108 @@ +/*------------------------------------------------------------------------- +| SAE - Scripted Amiga Emulator +| https://github.com/naTmeg/ScriptedAmigaEmulator +| +| Copyright (C) 2012-2016 Rupert Hausberger +| +| This program is free software; you can redistribute it and/or +| modify it under the terms of the GNU General Public License +| as published by the Free Software Foundation; either version 2 +| of the License, or (at your option) any later version. +| +| This program is distributed in the hope that it will be useful, +| but WITHOUT ANY WARRANTY; without even the implied warranty of +| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +| GNU General Public License for more details. +-------------------------------------------------------------------------*/ -a:link { color:#2040c0; text-decoration:none; } -a:visited { color:#2040c0; text-decoration:none; } -a:hover { color:#2040c0; text-decoration:underline; } - -.alt { text-align:left; vertical-align:top; } -.alm { text-align:left; vertical-align:middle; } -.almsg { text-align:left; vertical-align:middle; font-size:x-small; color:gray; } -.alb { text-align:left; vertical-align:bottom; } - -.act { text-align:center; vertical-align:top; } -.acm { text-align:center; vertical-align:middle; } -.acmsb { text-align:center; vertical-align:middle; font-size:x-small; font-weight:bold; } -.acmsg { text-align:center; vertical-align:middle; font-size:x-small; color:gray; } -.acb { text-align:center; vertical-align:bottom; } - -.art { text-align:right; vertical-align:top; } -.arm { text-align:right; vertical-align:middle; } -.armb { text-align:right; vertical-align:middle; font-weight:bold; } -.arms { text-align:right; vertical-align:middle; font-size:x-small; } -.armsb { text-align:right; vertical-align:middle; font-size:x-small; font-weight:bold; } -.armsg { text-align:right; vertical-align:middle; font-size:x-small; color:gray; } -.arb { text-align:right; vertical-align:bottom; } - -.fsxs { font-size:x-small; } -.fsl { font-size:large; } -.fwb { font-weight:bold; } - -.info { - font-size:x-small; - color:gray; - vertical-align:text-top; -} - -.gray { color:gray; } -.green { color:green; } -.red { color:red; } +a:link { color:#24c; text-decoration:none; } +a:visited { color:#24c; text-decoration:none; } +a:hover { color:#24c; text-decoration:underline; } body { top:0; left:0; margin:0; padding:0; - font-family:verdana,serif; - font-size:small; - background-color:#fff; + font-family:Verdana; + font-size:13px; + background-color:#f8f8f8; + -webkit-touch-callout:none; + -webkit-user-select:none; + -khtml-user-select:none; + -moz-user-select:none; + -ms-user-select:none; + user-select:none; +} + +table { + white-space:nowrap; +} +td { + text-align:left; + vertical-align:top; +} + +textarea { + resize:none; + font-size:13px; + font-family:monospace; + border-left:1px solid #ccc; + border-top:1px solid #ccc; + border-right:1px solid #fff; + border-bottom:1px solid #fff; +} + +input[type=text] { + font-size:13px; + border-left:1px solid #ccc; + border-top:1px solid #ccc; + border-right:1px solid #fff; + border-bottom:1px solid #fff; +} + +/*---------------------------------*/ + +.gray { color:gray; } +.green { color:green; } +.orange { color:orange; } +.red { color:red; } + +.alt { text-align:left; vertical-align:top; } +.alm { text-align:left; vertical-align:middle; } +.alb { text-align:left; vertical-align:bottom; } + +.act { text-align:center; vertical-align:top; } +.acm { text-align:center; vertical-align:middle; } +.acb { text-align:center; vertical-align:bottom; } + +.art { text-align:right; vertical-align:top; } +.arm { text-align:right; vertical-align:middle; } +.arb { text-align:right; vertical-align:bottom; } + +.label { + font-size:11px; + font-weight:bold; + color:#333; +} +.info { + font-size:11px; + color:dimgray; +} +.warn { + font-size:11px; + color:red; } .noscript { margin:auto; padding:4px; + font-size:17px; font-weight:bold; - font-size:medium; text-align:center; color:red; } -.hr { - width:100%; - border-top:1px solid #ccc; -} - .head { width:100%; margin:auto; @@ -69,123 +112,195 @@ body { .foot { width:100%; margin:auto; + font-size:11px; text-align:center; - font-size:x-small; } -#config_simple { - width:780px; - padding:10px; - margin:auto; - border:1px solid #ccc; - background-color:#fcfcfc; -} -.config_simple_hof { - width:380px; - margin:auto; - padding:10px; - border:1px solid #ccc; - background-color:#f8f8f8; -} -#cfg_info td { - padding:2px; -} - -#config_advanced { - width:780px; - margin:auto; - padding:10px; - border:1px solid #ccc; - background-color:#f8f8f8; - display:none; -} -#config_advanced table { +.linehoriz { width:100%; - line-height:20px; + border-top:1px solid #bbb; } -#config .tl { - border-top:1px solid #ccc; +.text { + border-left:1px solid #bbb; + border-top:1px solid #bbb; + border-right:1px solid #fff; + border-bottom:1px solid #fff; + background-color:#fff; + -webkit-touch-callout:text; + -webkit-user-select:text; + -khtml-user-select:text; + -moz-user-select:text; + -ms-user-select:text; + user-select:text; } -#config .bl { - border-bottom:1px solid #ccc; -} -#config .wauto { - width:auto; + +/*---------------------------------*/ + +#myVideo { + margin:auto; } + +/*---------------------------------*/ + #config select { - border:1px solid #ccc; + border-left:2px solid #fff; + border-top:2px solid #fff; + border-right:1px solid #bbb; + border-bottom:1px solid #bbb; + background-color:#f8f8f8; } #config .button { - width:100px; - border:1px solid #ccc; - background-color:#fff; + width:75px; + border-left:1px solid #fff; + border-top:1px solid #fff; + border-right:1px solid #bbb; + border-bottom:1px solid #bbb; + background-color:#f8f8f8; } #config .button:hover { - background-color:#eee; + background-color:#e8e8e8; } #config .sbutton { width:100px; padding:2px; - font-weight:bold; - border:1px solid #ccc; - background-color:#fff; + border-left:1px solid #fff; + border-top:1px solid #fff; + border-right:1px solid #bbb; + border-bottom:1px solid #bbb; + background-color:#f8f8f8; } #config .sbutton:hover { - background-color:#eee; + background-color:#e8e8e8; } -#cfg_demo, #cfg_game { - width:100%; + +#config_database { + width:720px; + padding:10px; + margin:auto; + border-left:1px solid #fff; + border-top:1px solid #fff; + border-right:1px solid #bbb; + border-bottom:1px solid #bbb; + background-color:#f0f0f0; } +#config_database_hof { + width:75%; + margin:auto; + padding:10px; + border-left:1px solid #bbb; + border-top:1px solid #bbb; + border-right:1px solid #fff; + border-bottom:1px solid #fff; + background-color:#e8e8e8; +} +#config_database_hof .ctrl { + padding:2px; + margin:0; + border-left:1px solid #bbb; + border-top:1px solid #bbb; + border-right:1px solid #fff; + border-bottom:1px solid #fff; + background-color:#f0f0f0; +} + +#config_advanced { + width:720px; + margin:auto; + padding:10px; + border-left:1px solid #fff; + border-top:1px solid #fff; + border-right:1px solid #bbb; + border-bottom:1px solid #bbb; + background-color:#f0f0f0; + display:none; +} +#config_advanced table { + width:100%; +} + +#config_advanced .menu { + padding:10px; + border-left:1px solid #ccc; + border-top:1px solid #ccc; + border-right:1px solid #fff; + border-bottom:1px solid #fff; + background-color:#e8e8e8; +} +#config_advanced .menu a:link { + font-size:13px; + color:#000; + text-decoration:none; +} +#config_advanced .menu a:hover { + color:#888; + text-decoration:none; +} + +#config_advanced .page { + padding:10px; + border-left:1px solid #ccc; + border-top:1px solid #ccc; + border-right:1px solid #fff; + border-bottom:1px solid #fff; + background-color:#e8e8e8; + display:none; +} +#cfg_page_video input[type="text"] { + width:60px; +} + +/*---------------------------------*/ #emul { display:none; } -#status { - width:720px; - margin:auto; - padding:2px; - text-align:center; - font-size:x-small; - color:#888; - background-color:#000; -} -#status table { - margin:auto; -} -#dskchg, #dskchg_simple { - display:none; - width:720px; - margin:auto; - padding:2px; - text-align:center; - font-size:x-small; - color:#888; - background-color:#000; -} -#dskchg, #dskchg_simple table { - margin:auto; -} - -.dbutton { +#emul button { width:64px; - font-size:x-small; + font-size:11px; + font-weight:bold; color:#888; border:1px solid #888; background-color:#000; } -.dbutton:hover { +#emul button:hover { color:#ccc; border:1px solid #ccc; } +#controls_status { + margin:auto; + color:#888; + font-size:9px; + font-weight:bold; +} + +#dskchg_database, #dskchg_advanced { + display:none; +} +#dskchg_database table, #dskchg_advanced table { + margin:auto; +} +#dskchg_database select, #dskchg_advanced select { + font-size:11px; + font-weight:bold; + color:#888; + border:1px solid #888; + background-color:#000; +} + +/*---------------------------------*/ + .readme { - width:1004px; + width:1080px; margin:auto; padding:10px; - border:1px solid #ccc; - background-color:#fcfcfc; + border-left:1px solid #fff; + border-top:1px solid #fff; + border-right:1px solid #bbb; + border-bottom:1px solid #bbb; + background-color:#f0f0f0; } .readme table { width:100%; @@ -193,15 +308,57 @@ body { .readme table td { vertical-align:top; } - -/*div.float_box { - overflow: hidden; - width: 100%; +.readme li { + padding:1px; } -div.float_item { - float: left; -} -div.float_clear { - clear: both; -}*/ +/*---------------------------------*/ + +#disass { + width:720px; + padding:10px; + margin:auto; + border-left:1px solid #fff; + border-top:1px solid #fff; + border-right:1px solid #bbb; + border-bottom:1px solid #bbb; + background-color:#f0f0f0; +} +#disass select { + border-left:1px solid #fff; + border-top:1px solid #fff; + border-right:1px solid #bbb; + border-bottom:1px solid #bbb; +} +#disass input { + border-left:1px solid #bbb; + border-top:1px solid #bbb; + border-right:1px solid #fff; + border-bottom:1px solid #fff; +} + +#disass .button { + width:100px; + border-left:1px solid #fff; + border-top:1px solid #fff; + border-right:1px solid #bbb; + border-bottom:1px solid #bbb; + background-color:#f8f8f8; +} +#disass .button:hover { + background-color:#e8e8e8; +} + +#disass_cfg { + border-left:1px solid #bbb; + border-top:1px solid #bbb; + border-right:1px solid #fff; + border-bottom:1px solid #fff; + background-color:#e8e8e8; + display:none; +} + +#disass_code { + width:100%; + display:none; +} diff --git a/index.htm b/index.htm index 2643bdf..dc94e41 100644 --- a/index.htm +++ b/index.htm @@ -1,660 +1,1737 @@ - - - - SAE - Scripted Amiga Emulator - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - -
-
-

Welcome!

- This site is the homepage of the project SAE, - an experimental Amiga emulator in pure JavaScript and HTML5.
- SAE is based on WinUAE and does use the AROS-kickstart replacement. - For more details, please see the description.
-
- Below you find a collection of pre-installed games and demos to play and test. Press the 'Config'-button to use your own roms or file-images, with advanced options.
-
-
- - - - - - - - - - - - - - - - - - - - - - - -
- -
- -
Audio/Video
Frameskip(25 instead of 50 fps)
Extra scale(double video-size via hardware)
-
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Name
Year
Developer
Publisher
License
Controls
Loading
-
-
- - -
-
-
- - Your game or demo online
- If you want to have your game or demo on this site, please contact me. - It would be published under a free license, with a link to your homepage and would be free to play for everyone. - This is a non-profit site and an open-source project. -
-
-
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
CPU - Speed - -
Chipset - Type -
- Collisions - - -
- NTSC
- A1000 OCS Agnus (8361/8367)
- Blit immediate -
RAM - - - - - - - - - - - - - -
Chip: - - kb -
Slow: - - kb (pseudo-fast, bogomem) -
Fast: - - kb (real-fast, commodore a2058 in zorro2) -
-
ROM - - - - - - - - - - - - - - - - - - - -
Kickstart:unset (required)
Extended:unset (optional)
Ext. addr: - -
-
Floppy - - - - - - - - - - - - - - - - - -
DF0 - - - - - - - - -
- - empty (optional)
-
DF1 - - - - - - - - -
- - empty (optional)
-
DF2 - - - - - - - - -
- - empty (optional)
-
DF3 - - - - - - - - -
- - empty (optional)
-
- Speed: - - ('Turbo' mode is fastest, but not always compatible. All other modes are very slow) -
Audio - Enabled - - - - - - - - - -
Mode: - - Channels: - - Lowpass-filter:
-
Video - Enabled -
- - Frameskip (25 instead of 50 fps)
- Extra scale (double video-size via hardware) -
-
Keyboard - - Enabled (joysticks does always work) -
- - Map L/R-Shift to L/R-Arrows (team17 pinball games) -
-
Port 0 - - Enabled - - - - - Move - - Fire 1 - - Fire 2 - - -
Port 1 - - Enabled - - - Move - - Fire 1 - - Fire 2 - - -
Serial - - Enabled -
-
-
- -
-
-
-
- -
- -
-
- - - - - - - - - - - - - - - -
pwrdf0df1df2df3fpscpu
-
-
- - - - - -
- -
-
-
- - - - - - - - -
- -
-
-
-
-
- - - - + + + + SAE - Scripted Amiga Emulator + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ Welcome!
+
+ This site is the home- and demopage of the SAE, + an Amiga emulator in pure HTML5 and JavaScript.
+ It is heavily based on WinUAE and does use the AROS-Kickstart replacement. + For more informations,
please see the description.
+
+ Select an item to 'Start' from the database, or press 'Config' for an advanced setup... +
+
+
+ + + + + + + + + + + + + + +
Game + + Demo + +
Tool + + AGA-Demo + +
+
+
+
+
+
+ + +
+
+
+ + + + + + +
+ + +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Model ?CPUChipsetKickstartYears
+ + 68000 ?OCS ?0.x-1.11985-87
+ + 68000OCS/ECS Agnus1.2-1.31987-91
Amiga 2000 (default)68000ECS Agnus1.2-2.041987-92
+ + 68000ECS ?2.041991-92
+ + 68000ECS2.051992
+ + 68020 ?AGA ?3.0-3.11992-96
Amiga 3000 (no FPU and SCSI)68030 ?ECS1.3-2.041990-92
Amiga 4000/030 (no FPU)68030AGA3.01992-94
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ModelSpeed
68000 (fake prefetching)Original
68010 (fake prefetching)Maximum
68020
68030 (fake MMU)
Options
Compatible (enable prefetching and caches, slower but more compatible)
32bit address-space (required for Zorro3-memory or A3000/A4000 roms)
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeRegion
Original Chip Set (OCS)PAL (50 Hz)
+ + NTSC (60 Hz)
Advanced Graphics Architecture (AGA)
CollisionsBlitter ?
Mode + + Immediate
Waiting + +
Features
Model + +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Gayle?RTC?
Onboard IDE + + Type + +
PCMCIA slot (A600/A1200)
CIA?Misc
TOD source + + A1000 Agnus (8361/8367)
TOD bugMirror ROM at $A80000
Overlay ROMMirror ROM at $E00000
A1000 Velvet-CIA (6526)ZorroIII (A3000/A4000)
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
OnboardRAMSEY + (A3000/A4000) + ? +
Chip + + Onboard Fast + (Low) +
Slow + (Bogo) + CPU-board Fast + (High) +
ZorroII?ZorroIII + (A3000/A4000) + ? +
Fast + + Fast + +
AutoConfig™ ?Mapping + +
+
+
+ Use the AROS kickstart-replacement +
+ + + + + + + + + + + + + + + + + + + +
Kickstart + + + + + + + + + +
+ + + + + + Patch for 'ShapeShifter' + ? +
<unset> (required)
+
Extended + + + + + + + + +
+ + + + +
<unset>
+
Keyfile
(Cloanto)
+ + + + + + + + +
+ + + + +
<unset>
+
Macintosh
(AMAX)
+ + + + + + + + +
+ + + + +
<unset>
+
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ImageFile
TypeSize
VersionCRC-32
EncrytionChecksum
System
ModelsCPN
CPUs
+
+
+ +
+
+
+ + + + + + + + + + + + + + + + + + +
Disk Floppies
DF0 + + + + + + + + + +
+ + + + + + + RO +
<empty>
+
DF1 + + + + + + + + + +
+ + + + + + + RO +
<empty>
+
DF2 + + + + + + + + + +
+ + + + + + + RO +
<empty>
+
DF3 + + + + + + + + + +
+ + + + + + + RO +
<empty>
+
+
+ + + + + + + + + + +
Options
Speed + + ('Turbo' mode is fastest, but not always compatible) +
Auto convert to ADF-EXT2
+
+
Note: Supported types are uncompressed ADF, DMS, IMG, EXE and SCP files.
+
+
+
+
+ Insert an entry from the database: +
+ + + + + + + +
+ + + + + + + +
+
+
+
+
+
+ Create a standard or custom (EXT2) disk-image: +
+ + + Label + + FFS + Bootable + + +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
DiskFile
LabelSize
TypeCRC-32
Bootblock
TypeChecksum
Data
+
+
+ +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Onboard IDE (A600/A1200/A4000)
IDE0 + + + + + + + + + +
+ + + + + + Media + + ATA + + RO +
<empty>
+
IDE1 + + + + + + + + + +
+ + + + + + Media + + ATA + + RO +
<empty>
+
IDE2 + + + + + + + + + +
+ + + + + + Media + + ATA + + RO +
<empty>
+
IDE3 + + + + + + + + + +
+ + + + + + Media + + ATA + + RO +
<empty>
+
PCMCIA slot (A600/A1200)
SRAM + + + + + + + + + +
+ + + + + RO +
<empty>
+
HD + + + + + + + + + +
+ + + +
<empty>
+
+
+
Note: Supported types are uncompressed HDF and VHD files.
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
DrivePartition
SurfacesName
SectorsReserved
BlocksizeBootpri
+
+
+ + +
+
+
+ Enabled +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Driver
Mode + + +
Antialias (WebGL only)
ResolutionCentering
Horizontal + + Horizontal
Vertical + + Vertical
Interlace + +
ColorsAlpha(RGBA-modes only)
Brightness (-1000 to 1000)Background + (#rrggbb) ? +
Contrast (-1000 to 1000)Blend (0 to 255)
Gamma (-1000 to 1000)
Blacker than black
MiscDebug
FrameskipRefresh-indicator
+ +
+ +
+
+ Enabled +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Driver
Buffer + frames
+ (you may experiment with this value) +
BasicLowpass filter
Mode + + Mode + +
Frequency + + Model + +
Channels + +
Stereo mixingInterpolation
Separation + + Type + +
Delay + +
+ +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Mouse + + +
+ Move + + Fire 1 + + Fire 2 + +
+
Game + + +
+ Move + + Fire 1 + + Fire 2 + +
+
Keyboard
Enabled (joystick-emulation does always work)
Serial
Enabled (output to developer-console)
+
+
+
+
+ +
+
+
+
+ +
+
+ + + + + +
+
+ + + + + + + + +
+
+
+
+
+ + + + + + + + + + + +
PWRHD
+
+
+
+ + + + + +
+ +
+
+
+ + + + + + + + +
+ +
+
+
+
+
+ + diff --git a/index.js b/index.js index e53bc38..8a25aad 100644 --- a/index.js +++ b/index.js @@ -1,1445 +1,2577 @@ -/************************************************************************** -* SAE - Scripted Amiga Emulator -* -* 2012-2015 Rupert Hausberger -* -* https://github.com/naTmeg/ScriptedAmigaEmulator -* -*************************************************************************** -* Note: This file does not contain any emulator-code. -* It is just for the SAE-calls and some GUI-stuff... -* -**************************************************************************/ +/*------------------------------------------------------------------------- +| SAE - Scripted Amiga Emulator +| https://github.com/naTmeg/ScriptedAmigaEmulator +| +| Copyright (C) 2012-2016 Rupert Hausberger +| +| This program is free software; you can redistribute it and/or +| modify it under the terms of the GNU General Public License +| as published by the Free Software Foundation; either version 2 +| of the License, or (at your option) any later version. +| +| This program is distributed in the hope that it will be useful, +| but WITHOUT ANY WARRANTY; without even the implied warranty of +| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +| GNU General Public License for more details. +| +| Note: This file does not contain any emulator-code. +-------------------------------------------------------------------------*/ -const URL_TEAM_HOI = 'Team Hoi'; -const URL_RETROGURU = 'retroguru'; -const URL_LOEWENSTEIN = 'Richard Löwenstein'; +const URL_DATABASE = "http://"+window.location.hostname+"/db"; +const URL_DATABASE_GAMES = URL_DATABASE+"/games"; +const URL_DATABASE_DEMOS = URL_DATABASE+"/demos"; +const URL_DATABASE_DEMOS_AGA = URL_DATABASE+"/demos_aga"; +const URL_DATABASE_TOOLS = URL_DATABASE+"/tools"; + +/*---------------------------------*/ + +/* dbEntry types */ +const DBT_GAME = 1; +const DBT_DEMO = 2; +const DBT_DAGA = 3; +const DBT_TOOL = 4; + +/* dbEntry flags */ +const DBF_MDC = 1; /* require manual disk-change by user */ +const DBF_NOT = 2; /* disable turbo-mode for floppies */ +const DBF_COL = 4; /* enable collision-detection */ +const DBF_BIM = 8; /* enable immediate blitter */ +const DBF_ECS = 16; /* ECS required */ +const DBF_AGA = 32; /* AGA required */ +const DBF_030 = 64; /* 68030 enabled */ + +function dbEntry(t,nd, n,d,p,l,y, f,no) { + this.id = Math.random() * 0xffffffff >>> 0; + + this.type = t; + this.numdisks = nd; + + this.name = n; + this.developer = d; + this.publisher = p; + this.license = l; + this.year = y; + + this.flags = f; + this.notes = no; +} + +const DB_IDS = [[ + "cfg_game", + "cfg_demo", + "cfg_demo_aga", + "cfg_tool" +], [ + "cfg_floppy_select_game", + "cfg_floppy_select_demo", + "cfg_floppy_select_demo_aga", + "cfg_floppy_select_tool" +]]; +const DB_URLS = [ + URL_DATABASE_GAMES, + URL_DATABASE_DEMOS, + URL_DATABASE_DEMOS_AGA, + URL_DATABASE_TOOLS +]; + +/*---------------------------------*/ + +function mkA(url, name) { return ''+name+''; } + +const URL_ENABLE_SOFTWARE = mkA("http://blockyskies.com", "Enable Software"); +const URL_TEAM_HOI = mkA("http://www.sevensheaven.nl", "Team Hoi"); +const URL_RETROGURU = mkA("http://www.retroguru.com", "retroguru"); +const URL_LOEWENSTEIN = mkA("http://www.richard-loewenstein.de", "Richard Löwenstein"); +const URL_HECKMECK = mkA("http://heckmeck.de", "Alexander Grupe"); + +const URL_AROS = mkA("http://aros.org", "aros.org"); +const URL_AROS_LIC = mkA("http://aros.org/license.html", "APL"); +const URL_SYSINFO = mkA("http://sysinfo.d0.se", "Nic Wilson"); const db = [ - /* name company year [disks] [change, turbo] [en,f1,f2,map] load [keys] immediate */ - [ - ['Air Ace II', ['SEUCK', '-', 'Public Domain'], '1989', - ['Air Ace II.adf', false, false, false], [false, true], - [true, 16, 17, false], ['...takes very long.'], [], false - ], - ['Asteroids', ['Vertical Developments', '-', 'Public Domain'], '1979', - ['Asteroids.adf', false, false, false], [false, true], - [true, 16, 17, false], [], [], false - ], - ['Crazy Sue', ['Jumpshoe, Hironymous', '-', 'Public Domain'], '1991', - ['Crazy Sue.adf', false, false, false], [false, true], - [true, 16, 17, false], ['...can take some time.'], [], false - ], - ['Deluxe Galaga 2.4', ['Edgar Vigdal', '-', 'Freeware'], '1994', - ['Deluxe Galaga.adf', false, false, false], [false, true], - [true, 16, 17, false], [], [], false - ], - ['Hoi', [URL_TEAM_HOI, 'Hollyware', 'Freeware'], '1992', - ['Hoi (Disk 1).adf', - 'Hoi (Disk 2).adf', false, false], [true, true], - [true, 16, 17, false], ['Press the LMB to skip the intro and insert the 2nd disk manually.

'+ - 'Cheat (move mouse-over)'], [], false - ], - ['Norse Gods', [URL_LOEWENSTEIN, '-', 'Freeware'], '1991', - ['Norse Gods.adf', false, false, false], [false, true], - [true, 16, 17, false], [], [], false - ], - ['Pollymorf', ['Andrew Campbell', '-', 'Public Domain'], '1993', - ['Pollymorf.adf', false, false, false], [false, true], - [true, 16, 17, false], ['...takes some time, just wait.'], [], false - ], - /*['Rectum', ['Mathias Olsson', '-', 'Freeware'], '1992', - ['Rectum.adf', false, false, false], [false, true], - [true, 16, 17, false], ['Press the LMB to skip the intro...'], [], false - ],*/ - ['Sqrxz', [URL_RETROGURU, '-', 'Freeware'], '2012', - ['sqrxz.adf', false, false, false], [false, true], - [true, 16, 17, false], ['The color-stripes are normal, just wait...'], [], false - ], - ['Sqrxz 2', [URL_RETROGURU, '-', 'Freeware'], '2012', - ['sqrxz2.adf', false, false, false], [false, true], - [true, 16, 17, false], ['After the start, click the RMB for the trainer menu.
The color-stripes are normal, just wait...'], [], false - ], - ['Super Obliteration', ['David Papworth', '-', 'Freeware'], '1993', - ['Super Obliteration.adf', false, false, false], [false, true], - [true, 16, 17, false], [], [], false - ], - ['Tanx', ['Robertz Gaz', '-', 'Public Domain'], '1991', - ['Tanx.adf', false, false, false], [false, true], - [true, 16, 17, false], [], [], false - ] - ], - [ - ['242', 'Virtual Dreams', '1992', - ['242.adf',false,false,false], [false, true], - [true, 16, 17, false], [], [], false - ], - ['9 Fingers', 'Spaceballs', '1993', - ['9 Fingers (Disk 1).adf', - '9 Fingers (Disk 2).adf',false,false], [false, false], - [true, 16, 17, false], [], [], false - ], - ['Alpha and Omega', 'Pure Metal Coders', '1991', - ['Alpha and Omega.adf', - false,false,false], [false, false], - [true, 16, 17, false], [], [], false - ], - ['Copper Master', 'Angels', '1990', - ['Copper Master.adf',false,false,false], [false, true], - [true, 16, 17, false], [], [], false - ], - ['Deja Vu', 'Anarchy', '1992', - ['Deja Vu.adf',false,false,false], [false, true], - [true, 16, 17, false], [], [], false - ], - ['Elysium', 'Sanity', '1991', - ['Elysium.adf',false,false,false], [false, true], - [true, 16, 17, false], [], [], false - ], - /*crash ['Ecliptica', 'TRSI', '1991', - ['Ecliptica.adf',false,false,false], [false, true], - [true, 16, 17, false], [], [], false - ],*/ - ['Enigma', 'Phenomena', '1991', - ['Enigma.adf',false,false,false], [false, true], - [true, 16, 17, false], [], [], false - ], - ['Global Trash', 'Silents', '1992', - ['Global Trash.adf',false,false,false], [false, true], - [true, 16, 17, false], [], [], false - ], - ['Hardwired', 'Crionics, Silents', '1992', - ['Hardwired (Disk 1).adf', - 'Hardwired (Disk 2).adf', - false,false], [true, true], - [true, 16, 17, false], - ['Insert the 2nd disk manually and
click the RMB when done.'], [], true - ], - ['HipHop Hater', 'Mathias Olsson', '1991', - ['HipHop Hater.adf',false,false,false], [false, true], - [true, 16, 17, false], [], [], false - ], - ['Ice', 'Silents', '1991', - ['Ice.adf',false,false,false], [false, true], - [true, 16, 17, false], ['Press LMB at the intro-screen'], [], false - ], - ['Lost World', 'Balance DK', '1992', - ['Lost World.adf',false,false,false], [false, true], - [true, 16, 17, false], ['Press LMB at the intro-screen'], [], false - ], - ['Mental Hangover', 'Scoopex', '1992', - ['Mental Hangover.adf',false,false,false], [false, true], - [true, 16, 17, false], [], [], false - ], - ['Multica', 'Andromeda', '1992', - ['Multica.adf',false,false,false], [false, true], - [true, 16, 17, false], ['Press LMB at the intro-screen'], [], false - ], - ['Project-X (demo rolling)', 'Team 17', '1992', - ['Project-X (demo-rolling).adf',false,false,false], [false, true], - [true, 16, 17, false], [], [['Skip level','Fire']], false - ], - ['Rampage', 'TEK', '1994', - ['Rampage.adf',false,false,false], [false, false], - [true, 16, 17, false], ['Press LMB at the intro-screen'], [], false - ], - ['State of the Art', 'Spaceballs', '1992', - ['State of the Art.adf',false,false,false], [false, true], - [true, 16, 17, false], [], [], false - ], - ['Static Chaos', 'Silents', '1992', - ['Static Chaos.adf',false,false,false], [false, true], - [true, 16, 17, false], [], [], false - ], - ['Technological Death', 'Mad Elks', '1993', - ['Technological Death.adf',false,false,false], [false, true], - [true, 16, 17, false], [], [], true - ], - ['Total Destruction', 'Crionics', '1990', - ['Total Destruction.adf',false,false,false], [false, true], - [true, 16, 17, false], [], [], false - ], - ['Wayfarer', 'Spaceballs', '1992', - ['Wayfarer.adf',false,false,false], [false, true], - [true, 16, 17, false], [], [], false - ], - ['World of Commodore', 'Sanity', '1992', - ['World of Commodore.adf',false,false,false], [false, true], - [true, 16, 17, false], [], [], false - ] - ] + new dbEntry(DBT_GAME,1, "Air Ace II", "SEUCK","","PD", "1989", 0, "Loading takes very long."), + new dbEntry(DBT_GAME,1, "Asteroids", "Vertical Developments","","PD", "1979", 0, ""), + new dbEntry(DBT_GAME,1, "BlockySkies", URL_ENABLE_SOFTWARE,"","FW", "2016", 0, ""), + new dbEntry(DBT_GAME,1, "Crazy Sue", "Jumpshoe,Hironymous","","PD", "1991", 0, "Loading can take some time."), + new dbEntry(DBT_GAME,1, "Deluxe Galaga 2.4", "Edgar Vigdal","","FW", "1994", DBF_COL, ""), + new dbEntry(DBT_GAME,2, "Hoi", URL_TEAM_HOI,"Hollyware","FW", "1992", DBF_MDC, "Press the LMB to skip the intro and insert the 2nd disk manually.

Cheat (move mouse-over)"), + new dbEntry(DBT_GAME,1, "Norse Gods", URL_LOEWENSTEIN,"","FW", "1991", 0, ""), + new dbEntry(DBT_GAME,1, "Pollymorf", "Andrew Campbell","","PD", "1993", 0, "Loading takes some time, just wait."), + new dbEntry(DBT_GAME,1, "Sqrxz", URL_RETROGURU,"","FW", "2012", 0, "The color-stripes are normal, just wait..."), + new dbEntry(DBT_GAME,1, "Sqrxz 2", URL_RETROGURU,"","FW", "2012", 0, "After the start, click the RMB for the trainer menu. The color-stripes are normal, just wait..."), + new dbEntry(DBT_GAME,1, "Super Obliteration", "David Papworth","","FW", "1993", 0, ""), + new dbEntry(DBT_GAME,1, "Tanx", "Robertz Gaz","","PD", "1991", 0, ""), + new dbEntry(DBT_GAME,1, "Zerosphere", URL_HECKMECK,"","FW", "2015", 0, ""), + + new dbEntry(DBT_DEMO,1, "242", "Virtual Dreams","","", "1992", 0, ""), + new dbEntry(DBT_DEMO,2, "9 Fingers", "Spaceballs","","", "1993", DBF_NOT, ""), + new dbEntry(DBT_DEMO,1, "Alpha and Omega", "Pure Metal Coders","","", "1991", DBF_NOT, ""), + new dbEntry(DBT_DEMO,1, "Copper Master", "Angels","","", "1990", 0, ""), + new dbEntry(DBT_DEMO,1, "Deja Vu", "Anarchy","","", "1992", 0, ""), + new dbEntry(DBT_DEMO,1, "Ecliptica", "TRSI","","", "1991", DBF_ECS, "The blue flashing in the beginning is normal. Just wait..."), + new dbEntry(DBT_DEMO,1, "Elysium", "Sanity","","", "1991", 0, ""), + new dbEntry(DBT_DEMO,1, "Enigma", "Phenomena","","", "1991", 0, ""), + new dbEntry(DBT_DEMO,1, "Global Trash", "Silents","","", "1992", 0, ""), + new dbEntry(DBT_DEMO,2, "Hardwired", "Crionics, Silents","","", "1992", DBF_MDC|DBF_BIM, "Insert the 2nd disk manually and click the RMB when done."), + new dbEntry(DBT_DEMO,1, "HipHop Hater", "Mathias Olsson","","", "1991", 0, ""), + new dbEntry(DBT_DEMO,1, "Ice", "Silents","","", "1991", 0, "Press the LMB at the intro-screen."), + new dbEntry(DBT_DEMO,1, "Lost World", "Balance DK","","", "1992", 0, "Press the LMB at the intro-screen."), + new dbEntry(DBT_DEMO,1, "Mental Hangover", "Scoopex","","", "1992", 0, ""), + new dbEntry(DBT_DEMO,1, "Multica", "Andromeda","","", "1992", 0, "Press the LMB at the intro-screen."), + new dbEntry(DBT_DEMO,1, "Project-X (demo rolling)", "Team 17","","", "1992", 0, "Press 'Fire' to skip to the 2nd level anytime."), + new dbEntry(DBT_DEMO,1, "Rampage", "TEK","","", "1994", DBF_NOT, "Press the LMB at the intro-screen."), + new dbEntry(DBT_DEMO,1, "State of the Art", "Spaceballs","","", "1992", 0, ""), + new dbEntry(DBT_DEMO,1, "Static Chaos", "Silents","","", "1992", 0, ""), + new dbEntry(DBT_DEMO,1, "Technological Death","Mad Elks","","", "1993", DBF_BIM, ""), + new dbEntry(DBT_DEMO,1, "Total Destruction", "Crionics","","", "1990", 0, ""), + new dbEntry(DBT_DEMO,1, "Wayfarer", "Spaceballs","","", "1992", 0, ""), + new dbEntry(DBT_DEMO,1, "World of Commodore", "Sanity","","", "1992", 0, ""), + + new dbEntry(DBT_DAGA,1, "Atome", "Skarla","","", "1996", DBF_AGA|DBF_030, ""), + new dbEntry(DBT_DAGA,2, "Burning Chrome", "Haujobb","","", "1996", DBF_AGA|DBF_030, "Open the disk AC1: by double-click and then double-click 'BurningChrome' once."), + new dbEntry(DBT_DAGA,1, "C42", "Case, Groo, Juliet","","", "1995", DBF_AGA|DBF_030, ""), + new dbEntry(DBT_DAGA,2, "Control", "Oxygene","","", "1995", DBF_AGA|DBF_030|DBF_MDC, "When asked, insert the 2nd disk manually."), + new dbEntry(DBT_DAGA,1, "Crazy Sexy Cool", "Essence","","", "1995", DBF_AGA|DBF_030, ""), + new dbEntry(DBT_DAGA,2, "Deep", "CNCD & Parallax","","", "1995", DBF_AGA, ""), + new dbEntry(DBT_DAGA,1, "Friday at Eight", "Polka Brothers","","", "1994", DBF_AGA, ""), + new dbEntry(DBT_DAGA,1, "Full Moon", "Virtual Dreams, Fairlight","","", "1993", DBF_AGA, ""), + new dbEntry(DBT_DAGA,1, "Gevalia", "Polka Brothers","","", "1994", DBF_AGA, ""), + new dbEntry(DBT_DAGA,1, "Nexus 7", "Andromeda","","", "1994", DBF_AGA|DBF_030, ""), + new dbEntry(DBT_DAGA,1, "Not Again", "Sanity, Complex, Avena, Lego","","", "1992", DBF_AGA, "Press the RMB to get to the next section anytime."), + new dbEntry(DBT_DAGA,2, "Origin", "Complex","","", "1993", DBF_AGA|DBF_NOT, ""), + new dbEntry(DBT_DAGA,1, "Real", "Complex","","", "1994", DBF_AGA|DBF_NOT, "In the last 3d-scene, hold the LMB to rotate and the RMB to walk around. (the scene which does have graphics errors)"), + new dbEntry(DBT_DAGA,1, "Roots", "Sanity","","", "1994", DBF_AGA, ""), + new dbEntry(DBT_DAGA,2, "Switchback", "Rebels","","", "1994", DBF_AGA|DBF_030, ""), /* 68030 */ + new dbEntry(DBT_DAGA,4, "Twisted", "Polka Brothers","","", "1994", DBF_AGA, ""), + new dbEntry(DBT_DAGA,2, "Vision", "Oxygene","","", "1995", DBF_AGA, ""), + new dbEntry(DBT_DAGA,4, "Wild", "Anadune, Nah Color","","", "1996", DBF_MDC|DBF_AGA, "When asked, change the disks manually."), + + new dbEntry(DBT_TOOL,1, "AROS Bootdisk", URL_AROS,"",URL_AROS_LIC, "2016", 0, "Press 'Cancel' when asked for a Live-CD."), + new dbEntry(DBT_TOOL,1, "AIBB 6.5", "Peter LaMonte Koop","","FW", "1993", 0, "Type 'aibb' at the console. Be very patient at the 'Evaluating System...' screen."), + new dbEntry(DBT_TOOL,1, "SysInfo 4.0", URL_SYSINFO,"","FW", "2012", 0, "Type 'sysinfo' (y=z) at the console."), + new dbEntry(DBT_TOOL,1, "X-Copy 2.0", "Cachet","","FW", "1989", 0, "") ]; + +var dbUrl = ""; var dbGrp = 0; var dbNum = 0; - -const aros_rom_file = 'aros-amiga-m68k-rom.bin'; -const aros_rom_url = 'http://'+window.location.hostname+'/db/'+aros_rom_file; -const aros_rom_size = 0x80000; -const aros_rom_crc = 0xbe091f38; //0x48dfadd; //0xea48b4d1 -const aros_ext_file = 'aros-amiga-m68k-ext.bin'; -const aros_ext_url = 'http://'+window.location.hostname+'/db/'+aros_ext_file; -const aros_ext_size = 0x80000; -const aros_ext_crc = 0x3f3fdce0; //0xaaf211d6; //0x60871435 +/*---------------------------------*/ -var mode = 0; -var paused = false; -var dskchg = false; -var dskchgList = []; +const AROS_ROM_FILE = "aros-amiga-m68k-rom.bin"; +const AROS_ROM_CRC = 0xE8A40832; /* also edit roms.js on change */ +const AROS_EXT_FILE = "aros-amiga-m68k-ext.bin"; +const AROS_EXT_CRC = 0x5C39D820; -var cache = null; -var info = null; -var config = null; +/*---------------------------------*/ -/*-----------------------------------------------------------------------*/ +const MAX_FILENAME = 40; -function urldecode(url) { - return decodeURIComponent(url.replace(/\+/g, ' ')); -} +const MODE_Database = 0; +const MODE_Advanced = 1; +var mode = MODE_Database; /* current mode */ -function dechex(dec) { - return dec.toString(16); -} - -function Cache() { - var roms = [null,null]; - var disks = []; +/* page-ids in the advanced-mode */ +const PID_None = 0; +const PID_Model = 1; +const PID_CPU = 2; +const PID_Chipset = 3; +const PID_RAM = 4; +const PID_ROM = 5; +const PID_ROM_Info = 6; +const PID_Floppy = 7; +const PID_Floppy_Info = 8; +const PID_Mount = 9; +const PID_Mount_Setup = 10; +const PID_Video = 11; +const PID_Audio = 12; +const PID_Ports = 13; +var page = PID_None; /* current page in the advanced-config */ - this.loadRom = function (num) { - if (roms[num]) { - console.log('loadRom.loadRom() %d is cached', num); - return roms[num]; - } - console.log('loadRom.loadRom() downloading %d', num); +var useAROS = false; /* use AROS in the advanced-config */ +var romNum = -1; /* current rom-id if rom-info is shown */ +var defRomInfo = null; /* kickstart rom-info */ +var defRomEncrypted = null; /* kickstart-rom is encrypted */ +var extRomInfo = null; /* extended rom-info */ +var extRomEncrypted = null; /* extended-rom is encrypted */ +var romKeyInfo = null; /* romkey-info */ +var amaxInfo = null; /* amax rom-info */ +var floppyNum = -1; /* current floppy-unit if floppy-info is shown */ +var mountConfigNum = -1; /* current mount-unit if mount-info is shown */ +var paused = false; /* is the emualtion currently paused? */ - var url, size, crc; - switch (num) { - case 0: - url = aros_rom_url; - size = aros_rom_size; - crc = aros_rom_crc; - break; - case 1: - url = aros_ext_url; - size = aros_ext_size; - crc = aros_ext_crc; - break; - } - var data = loadRemoteSync(url); - if (typeof(data) == 'number') { - alert('Can\'t download ' + url + ' (http status: ' + data + ')'); - } else { - if (data.length == size) { - //console.log(dechex(crc32(data))); - if (crc32(data) == crc) { - roms[num] = data; - return data; - } else - alert('Wrong checksum for ' + url + ' (is $' + dechex(crc32(data)) + ', should $' + dechex(crc) + ')\n\nFlush the browser-cache with "Ctrl+Shift+Del" and press F5 to reload...'); - } else - alert('Wrong file-length for ' + url + ' (' + size + ')'); - } - return null; - }; - - this.loadDisk = function(url) { - for (var i = 0; i < disks.length; i++) { - if (disks[i][0] == url) { - console.log('Cache.loadDisk() %s is cached', url); - return disks[i][1]; - } - } - console.log('Cache.loadDisk() downloading %s', url); +var dskchg = false; /* disk-change requester in database-mode */ +var dskchgList = []; /* list of floppies to change, created dynamicaly */ - var size = 0xdc000, crc = false; - var data = loadRemoteSync(url); - if (typeof(data) == 'number') { - alert('Can\'t download '+url+' (http status: '+data+')'); - } else { - if (data.length == size) { - if (crc === false || crc32(data) == crc) { - disks.push([url, data]); - return data; - } else - alert('Wrong checksum for '+url+' (is $'+dechex(crc32(data))+', should $'+dechex(crc)+')'); - } else - alert('Wrong file-length for '+url+' ('+size+')'); - } - return null; - } -} +var cache = null; /* asynchronous file-cache */ + +/*---------------------------------*/ + +var sae = null; /* SAE instance */ +var cfg = null; /* reference to the config-object */ +var inf = null; /* reference to the info-object */ /*-----------------------------------------------------------------------*/ /* utils */ - -/*function dump(obj) { - var out = ''; - if (obj) { - for (var i in obj) { - out += i + ': ' + obj[i] + '\n'; - } - } - alert(out); + +function decodeURL(url) { + return decodeURIComponent(url.replace(/\+/g, " ")); +} +/*function addItemToURL() { + if (mode == MODE_Database) { + var dbe = dbNum > 0 ? db[dbNum - 1] : null; + if (dbe !== null) { + var name = dbe.name; + while (true) { + var tmp = name.replace(" ", "_"); + if (tmp == name) break; + name = tmp; + } + window.location.hash = name; + } else + window.location.hash = ""; + } else + window.location.hash = ""; }*/ -function crc32(str, crc) { +/*---------------------------------*/ +/* CRC-32 checksumming */ - const tab = - '00000000 77073096 EE0E612C 990951BA 076DC419 706AF48F E963A535 9E6495A3 '+ - '0EDB8832 79DCB8A4 E0D5E91E 97D2D988 09B64C2B 7EB17CBD E7B82D07 90BF1D91 '+ - '1DB71064 6AB020F2 F3B97148 84BE41DE 1ADAD47D 6DDDE4EB F4D4B551 83D385C7 '+ - '136C9856 646BA8C0 FD62F97A 8A65C9EC 14015C4F 63066CD9 FA0F3D63 8D080DF5 '+ - '3B6E20C8 4C69105E D56041E4 A2677172 3C03E4D1 4B04D447 D20D85FD A50AB56B '+ - '35B5A8FA 42B2986C DBBBC9D6 ACBCF940 32D86CE3 45DF5C75 DCD60DCF ABD13D59 '+ - '26D930AC 51DE003A C8D75180 BFD06116 21B4F4B5 56B3C423 CFBA9599 B8BDA50F '+ - '2802B89E 5F058808 C60CD9B2 B10BE924 2F6F7C87 58684C11 C1611DAB B6662D3D '+ - '76DC4190 01DB7106 98D220BC EFD5102A 71B18589 06B6B51F 9FBFE4A5 E8B8D433 '+ - '7807C9A2 0F00F934 9609A88E E10E9818 7F6A0DBB 086D3D2D 91646C97 E6635C01 '+ - '6B6B51F4 1C6C6162 856530D8 F262004E 6C0695ED 1B01A57B 8208F4C1 F50FC457 '+ - '65B0D9C6 12B7E950 8BBEB8EA FCB9887C 62DD1DDF 15DA2D49 8CD37CF3 FBD44C65 '+ - '4DB26158 3AB551CE A3BC0074 D4BB30E2 4ADFA541 3DD895D7 A4D1C46D D3D6F4FB '+ - '4369E96A 346ED9FC AD678846 DA60B8D0 44042D73 33031DE5 AA0A4C5F DD0D7CC9 '+ - '5005713C 270241AA BE0B1010 C90C2086 5768B525 206F85B3 B966D409 CE61E49F '+ - '5EDEF90E 29D9C998 B0D09822 C7D7A8B4 59B33D17 2EB40D81 B7BD5C3B C0BA6CAD '+ - 'EDB88320 9ABFB3B6 03B6E20C 74B1D29A EAD54739 9DD277AF 04DB2615 73DC1683 '+ - 'E3630B12 94643B84 0D6D6A3E 7A6A5AA8 E40ECF0B 9309FF9D 0A00AE27 7D079EB1 '+ - 'F00F9344 8708A3D2 1E01F268 6906C2FE F762575D 806567CB 196C3671 6E6B06E7 '+ - 'FED41B76 89D32BE0 10DA7A5A 67DD4ACC F9B9DF6F 8EBEEFF9 17B7BE43 60B08ED5 '+ - 'D6D6A3E8 A1D1937E 38D8C2C4 4FDFF252 D1BB67F1 A6BC5767 3FB506DD 48B2364B '+ - 'D80D2BDA AF0A1B4C 36034AF6 41047A60 DF60EFC3 A867DF55 316E8EEF 4669BE79 '+ - 'CB61B38C BC66831A 256FD2A0 5268E236 CC0C7795 BB0B4703 220216B9 5505262F '+ - 'C5BA3BBE B2BD0B28 2BB45A92 5CB36A04 C2D7FFA7 B5D0CF31 2CD99E8B 5BDEAE1D '+ - '9B64C2B0 EC63F226 756AA39C 026D930A 9C0906A9 EB0E363F 72076785 05005713 '+ - '95BF4A82 E2B87A14 7BB12BAE 0CB61B38 92D28E9B E5D5BE0D 7CDCEFB7 0BDBDF21 '+ - '86D3D2D4 F1D4E242 68DDB3F8 1FDA836E 81BE16CD F6B9265B 6FB077E1 18B74777 '+ - '88085AE6 FF0F6A70 66063BCA 11010B5C 8F659EFF F862AE69 616BFFD3 166CCF45 '+ - 'A00AE278 D70DD2EE 4E048354 3903B3C2 A7672661 D06016F7 4969474D 3E6E77DB '+ - 'AED16A4A D9D65ADC 40DF0B66 37D83BF0 A9BCAE53 DEBB9EC5 47B2CF7F 30B5FFE9 '+ - 'BDBDF21C CABAC28A 53B39330 24B4A3A6 BAD03605 CDD70693 54DE5729 23D967BF '+ - 'B3667A2E C4614AB8 5D681B02 2A6F2B94 B40BBE37 C30C8EA1 5A05DF1B 2D02EF8D'; +const crc32Table = (function() { + var table = new Uint32Array(256); + var n, c, k; - if (crc == window.undefined) crc = 0; + for (n = 0; n < 256; n++) { + c = n; + for (k = 0; k < 8; k++) + c = ((c >>> 1) ^ (c & 1 ? 0xedb88320 : 0)) >>> 0; + table[n] = c; + } + return table; +})(); - crc = crc ^ (-1); - for (var i = 0, len = str.length; i < len; i++) - crc = (crc >>> 8) ^ parseInt(tab.substr(((crc ^ str.charCodeAt(i)) & 0xff) * 9, 8), 16); - crc = crc ^ (-1); - - return crc < 0 ? crc + 0x100000000 : crc; +function crc32(data) { + var length = data.length; + var offset = 0; + var crc = 0xffffffff; + + while (length-- > 0) + crc = crc32Table[(crc ^ data.charCodeAt(offset++)) & 0xff] ^ (crc >>> 8); + + return (crc ^ 0xffffffff) >>> 0; } -function getSelectValue(e) { +if (crc32("The quick brown fox jumps over the lazy dog") != 0x414fa339) + alert("CRC32-hash testing failed. SAE will not work. This is an internal bug!?"); + +/*---------------------------------*/ + +function isDecKey(event, signed) { + if (signed === true) + return (event.charCode >= 48 && event.charCode <= 57) || event.charCode == 45; + else + return event.charCode >= 48 && event.charCode <= 57; +} + +function isHexKey(event) { + return ( + (event.charCode >= 48 && event.charCode <= 57) || //0-9 + (event.charCode >= 65 && event.charCode <= 70) || //A-F + (event.charCode >= 97 && event.charCode <= 102) //a-f + ); +} + +function setDisabled(id, d) { + document.getElementById(id).disabled = d; +} +function setInnerHTML(id, t) { + document.getElementById(id).innerHTML = t; +} + +/*---------------------------------*/ +/* checkbox-input */ + +function getCheckbox(id) { + return document.getElementById(id).checked; +} +function setCheckbox(id, checked) { + document.getElementById(id).checked = checked; +} + +/*---------------------------------*/ +/* select-input */ + +function getSelect(id, asString) { + if (typeof asString == "undefined") asString = false; + var e = document.getElementById(id); for (var i = 0; i < e.length; i++) { - if (e[i].selected) return e[i].value; + if (e[i].selected) + return asString ? e[i].value : Number(e[i].value); } + //alert(sprintf("getSelect() ERROR id '%s'", id)); return false; } -function unselect(e) { - for (var i = 0; i < e.length; i++) { + +function setSelect(id, v) { + var e = document.getElementById(id); + /*for (var i = 0; i < e.length; i++) { if (e[i].selected) { e[i].selected = false; break; } + }*/ + var vs = String(v); + for (var i = 0; i < e.length; i++) { + if (e[i].value === vs) { + e[i].selected = true; + //break; + return; + } } + //alert(sprintf("setSelect() ERROR id '%s', value '%s'", id, vs)); } - + +/*---------------------------------*/ +/* radio-input */ + +function getRadio(name, asString) { + if (typeof asString == "undefined") asString = false; + var e = document.getElementsByName(name); + for (var i = 0; i < e.length; i++) { + if (e[i].checked) + return asString ? e[i].value : Number(e[i].value); + } + //alert(sprintf("getRadio() ERROR name '%s'", name)); + return false; +} + +function setRadio(name, v) { + var e = document.getElementsByName(name); + for (var i = 0; i < e.length; i++) { + if (e[i].checked) + e[i].checked = false; + } + var vs = String(v); + for (var i = 0; i < e.length; i++) { + if (e[i].value === vs) { + e[i].checked = true; + return; + } + } + //alert(sprintf("setRadio() ERROR name '%s', value '%s'", name, vs)); +} + +/*---------------------------------*/ +/* text-input */ + +function getText(id, asString) { + if (typeof asString == "undefined") asString = false; + var e = document.getElementById(id); + return asString ? e.value : Number(e.value); +} + +function setText(id, v) { + document.getElementById(id).value = typeof v === "string" ? v : String(v); +} + +function setText2(id, v) { + document.getElementById(id).innerHTML = typeof v === "string" ? v : String(v); +} + +/*---------------------------------*/ +/* style-display */ + function styleDisplayBlock(id, show) { var e = document.getElementById(id); - e.style.display = show ? 'block' : 'none'; -} + e.style.display = show ? "block" : "none"; +} function styleDisplayInline(id, show) { var e = document.getElementById(id); - e.style.display = show ? 'inline' : 'none'; -} + e.style.display = show ? "inline" : "none"; +} function styleDisplayTable(id, show) { var e = document.getElementById(id); - e.style.display = show ? 'table' : 'none'; -} + e.style.display = show ? "table" : "none"; +} function styleDisplayTableRow(id, show) { var e = document.getElementById(id); - e.style.display = show ? 'table-row' : 'none'; -} -function disabled(id, d) { - document.getElementById(id).disabled = d ? 'disabled' : ''; -} - -/*function toggleFullScreen() { - if ((document.fullScreenElement && document.fullScreenElement !== null) || // alternative standard method - (!document.mozFullScreenElement && !document.webkitFullScreenElement)) { // current working methods - if (document.documentElement.requestFullScreen) { - document.documentElement.requestFullScreen(); - } else if (document.documentElement.mozRequestFullScreen) { - document.documentElement.mozRequestFullScreen(); - } else if (document.documentElement.webkitRequestFullScreen) { - document.documentElement.webkitRequestFullScreen(Element.ALLOW_KEYBOARD_INPUT); - } - } else { - if (document.cancelFullScreen) { - document.cancelFullScreen(); - } else if (document.mozCancelFullScreen) { - document.mozCancelFullScreen(); - } else if (document.webkitCancelFullScreen) { - document.webkitCancelFullScreen(); - } - } -}*/ - -/*function loadLocalId(id, callback) { - var e = document.getElementById(id).files[0]; - var reader = new FileReader(); - reader.onload = callback; - reader.readAsBinaryString(e); -}*/ -function loadLocal(e, callback) { - var reader = new FileReader(); - reader.onload = callback; - reader.readAsBinaryString(e); + e.style.display = show ? "table-row" : "none"; } - -/*function loadRemote(url, size, crc, callback) { - var req = new XMLHttpRequest(); - req.open('GET', url, true); - req.overrideMimeType('text\/plain; charset=x-user-defined'); - req.onreadystatechange = function (e) { - if (req.readyState == 4) { - if (req.status == 200) { - if (req.responseText.length == size) { - if (crc === false || crc32(req.responseText) == crc) - callback(0, req.responseText); - else - callback(1, crc32(req.responseText)); - } else - callback(2, req.responseText.length); - } else - callback(3, req.status); - } - }; - req.send(null); -}*/ -function loadRemoteSync(url) { - var req = new XMLHttpRequest(); - req.open('GET', url, false); - req.overrideMimeType('text\/plain; charset=x-user-defined'); - req.send(null); - return req.status == 200 ? req.responseText : parseInt(req.status); -} - -/*-----------------------------------------------------------------------*/ -/* simple config */ - -function setSimpleConfig() { - //document.getElementById('info_name').innerHTML = info.browser_name+' '+info.browser_version+' ('+info.os+')'; - /*var e = document.getElementById('info_video'); - if (info.video) { - var t = ''; - if (info.video & SAEI_Video_WebGL) t += 'WebGL, '; - if (info.video & SAEI_Video_Canvas2D) t += 'Canvas, '; - e.innerHTML = t.substr(0, t.length - 2); - e.style.color = (info.video & SAEI_Video_WebGL) ? 'green' : 'orange'; - } else { - e.innerHTML = 'None'; - e.style.color = 'orange'; - } - e = document.getElementById('info_audio'); - if (info.audio) { - var t = ''; - if (info.audio & SAEI_Audio_Webkit) t += 'Webkit, '; - if (info.audio & SAEI_Audio_Mozilla) t += 'Mozilla, '; - e.innerHTML = t.substr(0, t.length - 2); - e.style.color = 'green'; - } else { - e.innerHTML = 'None'; - e.style.color = 'orange'; - } - e = document.getElementById('info_version').innerHTML = info.version;*/ - - - var s = document.getElementById('cfg_game'); - if (s.length == 1) { - for (var i = 0; i < db[0].length; i++) { - var e = document.createElement('option'); - e.value = String(1 + i); - e.text = db[0][i][0]; - s.add(e, null); - } - } - s = document.getElementById('cfg_demo'); - if (s.length == 1) { - for (var i = 0; i < db[1].length; i++) { - var e = document.createElement('option'); - e.value = String(1 + i); - e.text = db[1][i][0]; - s.add(e, null); - } - } - styleDisplayBlock('config_simple', 1); - document.getElementById('cfg_audio_enabled_1').checked = config.audio.enabled; - document.getElementById('cfg_video_enabled_1').checked = config.video.enabled; - document.getElementById('cfg_video_skip_1').checked = config.video.framerate != 1; - document.getElementById('cfg_video_scale_1').checked = false; - unselect(document.getElementById('cfg_demo')); - unselect(document.getElementById('cfg_game')); - styleDisplayTable('cfg_info', 0); - - styleDisplayInline('dskchg_grp', 0); -} - -function getSimpleFloppy() { - //console.log('loadDisks() %d %d', dbGrp, dbNum); - - if (dbNum == 0) { /* nothing selected */ - config.floppy.drive[0].type = SAEV_Config_Floppy_Type_35_DD; - config.floppy.drive[0].name = null; - config.floppy.drive[0].data = null; - config.floppy.drive[1].type = SAEV_Config_Floppy_Type_None; - config.floppy.drive[1].name = null; - config.floppy.drive[1].data = null; - config.floppy.drive[2].type = SAEV_Config_Floppy_Type_None; - config.floppy.drive[2].name = null; - config.floppy.drive[2].data = null; - config.floppy.drive[3].type = SAEV_Config_Floppy_Type_None; - config.floppy.drive[3].name = null; - config.floppy.drive[3].data = null; - config.floppy.speed = SAEV_Config_Floppy_Speed_Original; - return true; - } - - if (db[dbGrp - 1][dbNum - 1] == window.undefined) { - //alert('bug!'); - return false; - } - var item = db[dbGrp - 1][dbNum - 1]; - var baseUrl = 'http://'+window.location.hostname+'/db/'; - if (dbGrp == 1) baseUrl += 'games/'; - else if (dbGrp == 2) baseUrl += 'demos/'; - - - dskchgList = []; - if (item[4][0]) { - var i, filename, url; - - for (i = 0; i < 4; i++) { - filename = item[3][i]; - if (filename !== false) { - filename = filename.substr(0, filename.search('.adf')); - dskchgList.push(filename); - } - } - filename = item[3][0]; - url = baseUrl + filename; - if ((config.floppy.drive[0].data = cache.loadDisk(url)) !== null) { - config.floppy.drive[0].type = SAEV_Config_Floppy_Type_35_DD; - config.floppy.drive[0].name = filename; - } else - return false; - - for (i = 1; i < 4; i++) { - filename = item[3][i]; - if (filename !== false) { - url = baseUrl + filename; - if (cache.loadDisk(url) === null) - return false; - } - config.floppy.drive[i].type = SAEV_Config_Floppy_Type_None; - config.floppy.drive[i].name = null; - config.floppy.drive[i].data = null; - } - } else { - for (var i = 0; i < 4; i++) { - var filename = item[3][i]; - if (filename !== false) { - var url = baseUrl + filename; - if ((config.floppy.drive[i].data = cache.loadDisk(url)) !== null) { - config.floppy.drive[i].type = SAEV_Config_Floppy_Type_35_DD; - config.floppy.drive[i].name = filename; - } else - return false; - } else { - config.floppy.drive[i].type = SAEV_Config_Floppy_Type_None; - config.floppy.drive[i].name = null; - config.floppy.drive[i].data = null; - } - } - } - config.floppy.speed = item[4][1] ? SAEV_Config_Floppy_Speed_Turbo : SAEV_Config_Floppy_Speed_Original; - - return true; -} -function getSimpleConfig() { - var item = dbNum > 0 ? db[dbGrp - 1][dbNum - 1] : null; - - config.cpu.speed = SAEV_Config_CPU_Speed_Original; - config.cpu.compatible = true; - - config.chipset.mask = SAEV_Config_Chipset_Mask_OCS; - config.chipset.agnus_dip = false; /* A1000 */ - config.chipset.collision_level = (item !== null && item[0] == 'Deluxe Galaga 2.4') ? SAEV_Config_Chipset_ColLevel_Sprite_Playfield : SAEV_Config_Chipset_ColLevel_None; - - config.blitter.immediate = (item !== null && item[8]) ? true : false; - config.blitter.waiting = config.blitter.immediate ? 0 : 1; - - config.ram.chip.size = SAEV_Config_RAM_Chip_Size_512K; - config.ram.slow.size = SAEV_Config_RAM_Slow_Size_512K; - config.ram.fast.size = SAEV_Config_RAM_Fast_Size_1M; - - config.rom.name = aros_rom_file; - config.rom.size = SAEV_Config_ROM_Size_512K; - if ((config.rom.data = cache.loadRom(0)) === null) - return false; - - config.ext.name = aros_ext_file; - config.ext.size = SAEV_Config_EXT_Size_512K; - config.ext.addr = SAEV_Config_EXT_Addr_E0; - if ((config.ext.data = cache.loadRom(1)) === null) - return false; - - if (!getSimpleFloppy()) - return false; - - config.audio.enabled = document.getElementById('cfg_audio_enabled_1').checked ? true : false; - if (config.audio.enabled) { - config.audio.mode = SAEV_Config_Audio_Mode_Play_Best; - config.audio.channels = SAEV_Config_Audio_Channels_Stereo; - } - /*if (info.audio == 0) { - config.audio.enabled = false; - document.getElementById('cfg_audio_enabled_1').checked = config.audio.enabled; - }*/ - - config.video.id = 'myVideo'; - config.video.enabled = document.getElementById('cfg_video_enabled_1').checked ? true : false; - config.video.scale = document.getElementById('cfg_video_scale_1').checked ? true : false; - config.video.framerate = document.getElementById('cfg_video_skip_1').checked ? 2 : 1; - config.video.ntsc = false; - - config.keyboard.enabled = true; - config.keyboard.mapShift = (item !== null && item[5][3]) ? true : false; - - config.ports[0].type = SAEV_Config_Ports_Type_Mouse; - /*config.ports[0].type = SAEV_Config_Ports_Type_Joy0; - config.ports[0].move = ; - config.ports[0].fire[0] = ; - config.ports[0].fire[1] = ;*/ - if (item !== null && item[5][0]) { - config.ports[1].type = SAEV_Config_Ports_Type_Joy1; - config.ports[1].move = SAEV_Config_Ports_Move_Arrows; - config.ports[1].fire[0] = item[5][1]; - config.ports[1].fire[1] = item[5][2]; - } else { - config.ports[1].type = SAEV_Config_Ports_Type_None; - config.ports[1].move = SAEV_Config_Ports_Move_None; - config.ports[1].fire[0] = SAEV_Config_Ports_Fire_None; - config.ports[1].fire[1] = SAEV_Config_Ports_Fire_None; - } - config.serial.enabled = false; - - config.hooks.error = hooks_error; - config.hooks.power_led = hooks_power_led; - config.hooks.floppy_motor = hooks_floppy_motor; - config.hooks.floppy_step = hooks_floppy_step; - config.hooks.fps = hooks_fps; - config.hooks.cpu = hooks_cpu; - - return true; -} - -/*-----------------------------------------------------------------------*/ -/* advanced config */ - -function setRomName(name) { - document.getElementById('cfg_rom_name').className = name === null ? 'red' : ''; - document.getElementById('cfg_rom_name').innerHTML = name === null ? 'unset (required)' : name; -} -function setExtName(name) { - document.getElementById('cfg_ext_name').className = name === null ? 'gray' : ''; - document.getElementById('cfg_ext_name').innerHTML = name === null ? 'unset (optional)' : name; -} -function setFloppyName(n, name) { - document.getElementById('cfg_df'+n+'_name').className = name === null ? 'gray' : ''; - document.getElementById('cfg_df'+n+'_name').innerHTML = name === null ? 'unset (optional)' : name; -} - -function setFireButton(id, fire) { +function styleDisplayTableCell(id, show) { var e = document.getElementById(id); - switch (fire) { - case 0: e[0].selected = true; break; - case 16: e[1].selected = true; break; - case 17: e[2].selected = true; break; - case 13: e[3].selected = true; break; - case 32: e[4].selected = true; break; - case 8: e[5].selected = true; break; - case 96: e[6].selected = true; break; - case 106: e[7].selected = true; break; - case 107: e[8].selected = true; break; - case 109: e[9].selected = true; break; - case 110: e[10].selected = true; break; - case 111: e[11].selected = true; break; - case 46: e[12].selected = true; break; - case 45: e[13].selected = true; break; - case 34: e[14].selected = true; break; - case 33: e[15].selected = true; break; - case 35: e[16].selected = true; break; - case 36: e[17].selected = true; break; - case 19: e[18].selected = true; break; - case 144: e[19].selected = true; break; - case 145: e[20].selected = true; break; - case 49: e[21].selected = true; break; - case 50: e[22].selected = true; break; + e.style.display = show ? "table-cell" : "none"; +} + +/*---------------------------------*/ + +function freezeButtons(f, l) { + if (f) { + if (mode == MODE_Database) { + setDisabled("cfg_database_start", 1); + setInnerHTML("cfg_database_start", "Loading..."); + setDisabled("cfg_database_config", 1); + } else { + setDisabled("cfg_start", 1); + if (l) setInnerHTML("cfg_start", "Loading..."); + //setDisabled("cfg_back", 1); + } + } else { + if (mode == MODE_Database) { + setDisabled("cfg_database_start", 0); + setInnerHTML("cfg_database_start", "Start"); + setDisabled("cfg_database_config", 0); + } else { + setDisabled("cfg_start", 0); + if (l) setInnerHTML("cfg_start", "Start"); + //setDisabled("cfg_back", 0); + } } } +function switchPauseResume(p) { + var e = document.getElementById("controls_pr"); + if (p) { + e.innerHTML = "Resume"; + e.onclick = function() { pause(false); }; + } else { + e.innerHTML = "Pause"; + e.onclick = function() { pause(true); }; + } +} + +function switchBaseEmul(emul) { + if (emul) { + document.body.style.backgroundColor = "#000000"; + styleDisplayBlock("base", 0); + styleDisplayBlock("emul", 1); + } else { + styleDisplayBlock("emul", 0); + styleDisplayBlock("base", 1); + document.body.style.backgroundColor = "#f8f8f8"; + } +} + +/*---------------------------------*/ + function fireButtonName(fire) { switch (fire) { - case 0: return 'None'; - case 16: return 'Shift'; - case 17: return 'Ctrl'; - case 13: return 'Enter'; - case 32: return 'Space'; - case 8: return 'Backspace'; - case 96: return 'Numpad 0'; - case 106: return 'Numpad *'; - case 107: return 'Numpad '; - case 109: return 'Numpad -'; - case 110: return 'Numpad .'; - case 111: return 'Numpad /'; - case 46: return 'Delete'; - case 45: return 'Insert'; - case 34: return 'Page down'; - case 33: return 'Page up'; - case 35: return 'End'; - case 36: return 'Home'; - case 19: return 'Pause'; - case 144: return 'Num lock'; - case 145: return 'Scroll lock'; - case 49: return '1'; - case 50: return '2'; - default: return 'ERROR'; + case 0: return "None"; + case 16: return "Shift"; + case 17: return "Ctrl"; + case 13: return "Enter"; + case 32: return "Space"; + case 8: return "Backspace"; + case 96: return "Numpad 0"; + case 106: return "Numpad *"; + case 107: return "Numpad "; + case 109: return "Numpad -"; + case 110: return "Numpad ."; + case 111: return "Numpad /"; + case 46: return "Delete"; + case 45: return "Insert"; + case 34: return "Page down"; + case 33: return "Page up"; + case 35: return "End"; + case 36: return "Home"; + case 19: return "Pause"; + case 144: return "Num lock"; + case 145: return "Scroll lock"; + case 49: return "1"; + case 50: return "2"; + default: return "ERROR"; } } -function setFloppy(n) { - if (config.floppy.drive[n].type != SAEV_Config_Floppy_Type_None) { - document.getElementById('cfg_df'+n+'_enabled').checked = true; - switch (config.floppy.drive[n].type) { - case SAEV_Config_Floppy_Type_35_DD: document.getElementById('cfg_df'+n+'_type')[0].selected = true; break; - case SAEV_Config_Floppy_Type_35_HD: document.getElementById('cfg_df'+n+'_type')[1].selected = true; break; - case SAEV_Config_Floppy_Type_525_SD: document.getElementById('cfg_df'+n+'_type')[2].selected = true; break; +/*---------------------------------*/ + +function saee2text(err) { + switch (err) { + case SAEE_NotRunning: return "The emulator is not running."; + case SAEE_NoTimer: return "No timing-functions avail. Please upgrade your browser."; + case SAEE_NoMemory: return "Out of memory."; + case SAEE_Internal: return "Internal emulator error."; + case SAEE_Config_Invalid: return "Invalid configuration."; + case SAEE_CPU_Internal: return "Internal CPU-error."; + case SAEE_CPU_Requires68020: return "The selected kickstart-rom does require a 68020 and 32bit address-space"; + case SAEE_CPU_Requires680EC20: return "The selected kickstart-rom does require a 68020."; + case SAEE_CPU_Requires68030: return "The selected kickstart-rom does require a 68030."; + case SAEE_CPU_Requires68040: return "The selected kickstart-rom does require a 68040/68060."; + case SAEE_Memory_NoKickstartRom: return "The kickstart-rom is missing."; + case SAEE_Memory_NoExtendedRom: return "An extended-rom is required but missing.\n\nGo to the ROM-page and select a rom from disk..."; + case SAEE_Memory_RomSize: return "The kickstart- or extended-rom does have an invalid size."; + case SAEE_Memory_RomKey: return "A ROM-keyfile is required. (Cloanto)"; + case SAEE_Memory_RomDecode: return "Invalid ROM-keyfile. (Cloanto)"; + case SAEE_Memory_RomChecksum: return "Checksum-error at the kickstart- or extended-rom."; + case SAEE_Memory_RomUnknown: return "Unknown ROM."; + case SAEE_Video_ElementNotFound: return "Video DIV-element not found. Check 'cfg.video.id'"; + case SAEE_Video_RequiresCanvas: return "This browser does not support 'Canvas'. Please upgrade to an actual version."; + case SAEE_Video_RequiresWegGl: return "This browser does not support 'WebGL'. Please upgrade to an actual version."; + case SAEE_Video_ComphileShader: return "Can not compile the required shader-program."; + case SAEE_Video_LinkShader: return "Can not link the required shader-program."; + case SAEE_Audio_RequiresWebAudio: return "This browser does not support 'WebAudio'. Please upgrade to an actual version."; + default: return "("+err+")"; + } +} + +/*-----------------------------------------------------------------------*/ +/* database */ + +function dbInit() { + function addOption(select, text, value) { + var option = document.createElement("option"); + if (text.length) + option.text = text; + option.value = String(value); + if (value == 0) { + option.style.fontWeight = "bold"; + option.disabled = "disabled"; } - if (config.floppy.drive[n].name) { - setFloppyName(n, config.floppy.drive[n].name); - styleDisplayInline('cfg_df'+n+'_eject', 1); - } else { - setFloppyName(n, null); - styleDisplayInline('cfg_df'+n+'_eject', 0); + select.add(option, null); + } + for (var dbt = 1; dbt <= 4; dbt++) { + var s = document.getElementById(DB_IDS[0][dbt - 1]); + for (var i = 0; i < db.length; i++) { + if (db[i].type == dbt) + addOption(s, db[i].name, 1 + i); } - styleDisplayInline('cfg_df'+n+'_grp', 1); - } else { - document.getElementById('cfg_df'+n+'_enabled').checked = false; - styleDisplayInline('cfg_df'+n+'_grp', 0); - } - switch (config.floppy.speed) { - case SAEV_Config_Floppy_Speed_Turbo: document.getElementById('cfg_floppy_speed')[0].selected = true; break; - case SAEV_Config_Floppy_Speed_Original: document.getElementById('cfg_floppy_speed')[1].selected = true; break; - case 200: document.getElementById('cfg_floppy_speed')[2].selected = true; break; - case 500: document.getElementById('cfg_floppy_speed')[3].selected = true; break; - case 1000: document.getElementById('cfg_floppy_speed')[4].selected = true; break; } -} - -function setConfig() { - var e = document.getElementById('cfg_cpu_speed'); - switch (config.cpu.speed) { - case SAEV_Config_CPU_Speed_Original: e[0].selected = true; break; - case SAEV_Config_CPU_Speed_Maximum: e[1].selected = true; break; - } - - e = document.getElementById('cfg_chipset_type'); - switch (config.chipset.mask) { - case SAEV_Config_Chipset_Mask_OCS: e[0].selected = true; break; - case SAEV_Config_Chipset_Mask_ECS_AGNUS: e[1].selected = true; break; - case SAEV_Config_Chipset_Mask_ECS_DENISE: e[2].selected = true; break - } - document.getElementById('cfg_chipset_cl_enabled').checked = config.chipset.collision_level != SAEV_Config_Chipset_ColLevel_None; - switch (config.chipset.collision_level) { - case SAEV_Config_Chipset_ColLevel_Sprite_Sprite: document.getElementById('cfg_chipset_cl')[0].selected = true; break; - case SAEV_Config_Chipset_ColLevel_Sprite_Playfield: document.getElementById('cfg_chipset_cl')[1].selected = true; break; - case SAEV_Config_Chipset_ColLevel_Full: document.getElementById('cfg_chipset_cl')[2].selected = true; break; - } - document.getElementById('cfg_chipset_agnus_dip').checked = config.chipset.agnus_dip != 0; - document.getElementById('cfg_blitter_immediate').checked = config.blitter.immediate != 0; - styleDisplayInline('cfg_chipset_cl_grp', config.chipset.collision_level != SAEV_Config_Chipset_ColLevel_None); - - var e = document.getElementById('cfg_mem_chip'); - switch (config.ram.chip.size) { - case SAEV_Config_RAM_Chip_Size_256K: e[0].selected = true; break; - case SAEV_Config_RAM_Chip_Size_512K: e[1].selected = true; break; - case SAEV_Config_RAM_Chip_Size_1M: e[2].selected = true; break; - case SAEV_Config_RAM_Chip_Size_2M: e[3].selected = true; break; - } - e = document.getElementById('cfg_mem_slow'); - switch (config.ram.slow.size) { - case SAEV_Config_RAM_Slow_Size_None: e[0].selected = true; break; - case SAEV_Config_RAM_Slow_Size_256K: e[1].selected = true; break; - case SAEV_Config_RAM_Slow_Size_512K: e[2].selected = true; break; - case SAEV_Config_RAM_Slow_Size_1M: e[3].selected = true; break; - case SAEV_Config_RAM_Slow_Size_1536K: e[4].selected = true; break; - } - e = document.getElementById('cfg_mem_fast'); - switch (config.ram.fast.size) { - case SAEV_Config_RAM_Fast_Size_None: e[0].selected = true; break; - case SAEV_Config_RAM_Fast_Size_512K: e[1].selected = true; break; - case SAEV_Config_RAM_Fast_Size_1M: e[2].selected = true; break; - case SAEV_Config_RAM_Fast_Size_2M: e[3].selected = true; break; - case SAEV_Config_RAM_Fast_Size_4M: e[4].selected = true; break; - case SAEV_Config_RAM_Fast_Size_8M: e[5].selected = true; break; - } - - setRomName(config.rom.size ? config.rom.name : null); - - if (config.ext.size) { - setExtName(config.ext.name); - styleDisplayInline('cfg_ext_remove', 1); - switch (config.ext.addr) { - case SAEV_Config_EXT_Addr_E0: document.getElementById('cfg_ext_addr')[0].selected = true; break; - case SAEV_Config_EXT_Addr_F0: document.getElementById('cfg_ext_addr')[1].selected = true; break; + for (var dbt = 1; dbt <= 4; dbt++) { + var s = document.getElementById(DB_IDS[1][dbt - 1]); + for (var i = 0; i < db.length; i++) { + if (db[i].type == dbt) { + if (!(db[i].flags & DBF_MDC)) /* skip items that require manual disk-change */ + addOption(s, db[i].name, 1 + i); + } } - styleDisplayTableRow('cfg_ext_addr_grp', 1); - } else { - setExtName(null); - styleDisplayInline('cfg_ext_remove', 0); - styleDisplayTableRow('cfg_ext_addr_grp', 0); - } - - for (var i = 0; i < 4; i++) - setFloppy(i); - - document.getElementById('cfg_audio_enabled').checked = config.audio.enabled; - switch (config.audio.mode) { - case SAEV_Config_Audio_Mode_Emul: document.getElementById('cfg_audio_mode')[0].selected = true; break; - case SAEV_Config_Audio_Mode_Play: document.getElementById('cfg_audio_mode')[1].selected = true; break; - case SAEV_Config_Audio_Mode_Play_Best: document.getElementById('cfg_audio_mode')[2].selected = true; break; - } - switch (config.audio.channels) { - case SAEV_Config_Audio_Channels_Mono: document.getElementById('cfg_audio_channels')[0].selected = true; break; - case SAEV_Config_Audio_Channels_Stereo: document.getElementById('cfg_audio_channels')[1].selected = true; break; - } - document.getElementById('cfg_audio_filter').checked = config.audio.filter != 0; - styleDisplayTable('cfg_audio_grp', config.audio.enabled); - - document.getElementById('cfg_video_enabled').checked = config.video.enabled != 0; - document.getElementById('cfg_video_scale').checked = config.video.scale; - document.getElementById('cfg_video_ntsc').checked = config.video.ntsc != 0; - document.getElementById('cfg_video_skip').checked = config.video.framerate != 1; - styleDisplayBlock('cfg_video_grp', config.video.enabled != 0); - - document.getElementById('cfg_keyborad_enabled').checked = config.keyboard.enabled != 0; - document.getElementById('cfg_keyborad_mapshift').checked = config.keyboard.mapShift != 0; - styleDisplayBlock('cfg_keyborad_grp', config.keyboard.enabled != 0); - - document.getElementById('cfg_ports_0_enabled').checked = config.ports[0].type != SAEV_Config_Ports_Type_None; - switch (config.ports[0].type) { - case SAEV_Config_Ports_Type_Mouse: document.getElementById('cfg_ports_0')[0].selected = true; break; - case SAEV_Config_Ports_Type_Joy0: document.getElementById('cfg_ports_0')[1].selected = true; break; - } - switch (config.ports[0].move) { - case SAEV_Config_Ports_Move_Arrows: document.getElementById('cfg_ports_0_move')[0].selected = true; break; - case SAEV_Config_Ports_Move_Numpad: document.getElementById('cfg_ports_0_move')[1].selected = true; break; - case SAEV_Config_Ports_Move_WASD: document.getElementById('cfg_ports_0_move')[2].selected = true; break; - } - setFireButton('cfg_ports_0_fire_1', config.ports[0].fire[0]); - setFireButton('cfg_ports_0_fire_2', config.ports[0].fire[1]); - styleDisplayInline('cfg_ports_0_grp', config.ports[0].type != SAEV_Config_Ports_Type_None); - styleDisplayInline('cfg_ports_0_grp2', config.ports[0].type == SAEV_Config_Ports_Type_Joy0); - - document.getElementById('cfg_ports_1_enabled').checked = config.ports[1].type != SAEV_Config_Ports_Type_None; - switch (config.ports[1].type) { - case SAEV_Config_Ports_Type_Joy1: document.getElementById('cfg_ports_1')[0].selected = true; break; - } - switch (config.ports[1].move) { - case SAEV_Config_Ports_Move_Arrows: document.getElementById('cfg_ports_1_move')[0].selected = true; break; - case SAEV_Config_Ports_Move_Numpad: document.getElementById('cfg_ports_1_move')[1].selected = true; break; - case SAEV_Config_Ports_Move_WASD: document.getElementById('cfg_ports_1_move')[2].selected = true; break; - } - setFireButton('cfg_ports_1_fire_1', config.ports[1].fire[0]); - setFireButton('cfg_ports_1_fire_2', config.ports[1].fire[1]); - styleDisplayInline('cfg_ports_1_grp', config.ports[1].type == SAEV_Config_Ports_Type_Joy1); - - document.getElementById('cfg_serial_enabled').checked = config.serial.enabled != 0; - - styleDisplayInline('dskchg_grp', 1); -} - -function getMask(type) { - switch (type) { - case SAEV_Config_Chipset_Type_OCS: return SAEV_Config_Chipset_Mask_OCS; - case SAEV_Config_Chipset_Type_ECS_AGNUS: return SAEV_Config_Chipset_Mask_ECS_AGNUS; - case SAEV_Config_Chipset_Type_ECS_DENISE: return SAEV_Config_Chipset_Mask_ECS_DENISE; - default: return SAEV_Config_Chipset_Mask_OCS; } } -function getConfig() { - var e; +function dbFindTypeNamePos(type, name) { + for (var i = 0; i < db.length; i++) { + if (db[i].type == type && db[i].name == name) + return i; + } + return -1; +} - e = document.getElementById('cfg_cpu_speed'); - config.cpu.speed = parseInt(getSelectValue(e)); - - e = document.getElementById('cfg_chipset_type'); - config.chipset.mask = getMask(parseInt(getSelectValue(e))); - e = document.getElementById('cfg_chipset_cl_enabled'); - if (e.checked) { - e = document.getElementById('cfg_chipset_cl'); - config.chipset.collision_level = parseInt(getSelectValue(e)); - } else - config.chipset.collision_level = SAEV_Config_Chipset_ColLevel_None; - config.chipset.agnus_dip = document.getElementById('cfg_chipset_agnus_dip').checked ? true : false; - config.blitter.immediate = document.getElementById('cfg_blitter_immediate').checked ? true : false; - config.blitter.waiting = config.blitter.immediate ? 0: 1; - - e = document.getElementById('cfg_mem_chip'); - config.ram.chip.size = parseInt(getSelectValue(e)); - e = document.getElementById('cfg_mem_slow'); - config.ram.slow.size = parseInt(getSelectValue(e)); - e = document.getElementById('cfg_mem_fast'); - config.ram.fast.size = parseInt(getSelectValue(e)); +function dbFindId(id) { + for (var i = 0; i < db.length; i++) { + if (db[i].id == id) + return db[i]; + } + return null; +} - if (!config.rom.name) { - alert('No Kickstart ROM.'); +/*-----------------------------------------------------------------------*/ +/* asynchronous file cache */ + +const S_PENDING = 1; +const S_ERROR = 2; +const S_VALID = 3; + +function CacheItem(url) { + this.state = S_PENDING; + this.url = url; + //this.path = ""; + this.name = ""; + this.data = ""; + this.size = 0; + this.crc32 = 0; +} +function Cache() { + var items = []; + + function find(url) { + for (var i = 0; i < items.length; i++) { + if (items[i].url == url) + return items[i]; + } return false; } - e = document.getElementById('cfg_ext_addr'); - config.ext.addr = parseInt(getSelectValue(e)); - e = document.getElementById('cfg_floppy_speed'); - config.floppy.speed = parseInt(getSelectValue(e)); - - config.audio.enabled = document.getElementById('cfg_audio_enabled').checked ? true : false; - if (config.audio.enabled) { - e = document.getElementById('cfg_audio_mode'); - config.audio.mode = parseInt(getSelectValue(e)); - e = document.getElementById('cfg_audio_channels'); - config.audio.channels = parseInt(getSelectValue(e)); - config.audio.filter = document.getElementById('cfg_audio_filter').checked ? true : false; + function load(url, handler) { + var client = new XMLHttpRequest(); + client.onload = handler; + client.open("GET", url); + client.overrideMimeType("text\/plain; charset=x-user-defined"); /* we want binary data */ + client.send(); } - config.video.id = 'myVideo'; - config.video.enabled = document.getElementById('cfg_video_enabled').checked ? true : false; - config.video.scale = document.getElementById('cfg_video_scale').checked ? true : false; - config.video.ntsc = document.getElementById('cfg_video_ntsc').checked ? true : false; - config.video.framerate = document.getElementById('cfg_video_skip').checked ? 2 : 1; + this.req = function(path, name, size, crc, dst) { + var url = path + "/" + name; + var item = null; - config.keyboard.enabled = document.getElementById('cfg_keyborad_enabled').checked ? true : false; - config.keyboard.mapShift = document.getElementById('cfg_keyborad_mapshift').checked ? true : false; + if (dst !== false) + dst.clr(); - e = document.getElementById('cfg_ports_0'); - config.ports[0].type = parseInt(getSelectValue(e)); - if (config.ports[0].type == SAEV_Config_Ports_Type_Joy0) { - e = document.getElementById('cfg_ports_0_move'); - config.ports[0].move = parseInt(getSelectValue(e)); - e = document.getElementById('cfg_ports_0_fire_1'); - config.ports[0].fire[0] = parseInt(getSelectValue(e)); - e = document.getElementById('cfg_ports_0_fire_2'); - config.ports[0].fire[1] = parseInt(getSelectValue(e)); - if (config.ports[0].fire[0] != SAEV_Config_Ports_Fire_None && config.ports[0].fire[0] == config.ports[0].fire[1]) { - alert('Fire-button 1/2 on port 0 can\'t be the same.'); + if ((item = find(url)) !== false) { + if (dst !== false) { + //dst.path = item.path; + dst.name = item.name; + dst.data = item.data; + dst.size = item.size; + dst.crc32 = item.crc32; + } + //console.log("cache.req() '"+url+"' is cached."); + return true; + } + item = new CacheItem(url); + items.push(item); + + //console.log("cache.req() start downloading '"+url+"'..."); + + load(url, function() { + if (this.status == 200) { + if (this.responseText.length == size) { + /*if (crc !== false) { + var hash = crc32(this.responseText); + if (hash != crc) { + item.state = S_ERROR; + alert(sprintf("Wrong checksum for '%s'\n\n(should be $%08x, but is $%08x)\n\nTry to flush the browser-cache with 'Ctrl+Shift+Del' and press F5 to reload...", url, crc, hash)); + return; + } + }*/ + //item.path = path; + item.name = name; + item.data = this.responseText; + item.size = size; + item.crc32 = crc; + item.state = S_VALID; + if (dst !== false) { + //dst.path = item.path; + dst.name = item.name; + dst.data = item.data; + dst.size = item.size; + dst.crc32 = item.crc32; + } + //console.log("cache.req() downloaded of '"+url+"' done."); + } else { + item.state = S_ERROR; + alert(sprintf("Wrong file-length for '%s'\n\n(should be %d, but is %d)", url, size, this.responseText.length)); + } + } else { + item.state = S_ERROR; + alert(sprintf("Error while downloading '%s' (http status: %d)", url, this.status)); + } + }); + return false; + } + + this.state = function() { + for (var i = 0; i < items.length; i++) { + if (items[i].state != S_VALID) + return items[i].state; + } + return S_VALID; + } +} + +/*---------------------------------*/ + +function loadFile(e, callback) { + var reader = new FileReader(); + reader.onload = callback; + reader.readAsBinaryString(e); +} + +/*-----------------------------------------------------------------------*/ +/* database cfg */ + +function setDatabaseConfig() { + //setSelect("cfg_video_resolution_1", cfg.video.hresolution); + //setCheckbox("cfg_video_skip_1", cfg.video.framerate != 1); + + styleDisplayBlock("config_database", 1); + styleDisplayTableCell("controls_disk", 0); +} + +function getDatabaseEntryFilename(dbe, disk, adf) { + if (dbe.numdisks == 1) + return dbe.name + (adf ? ".adf" : ""); + else + return dbe.name + " (Disk "+String(disk+1)+")" + (adf ? ".adf" : ""); +} +function getDatabaseFloppy() { + if (dbNum == 0) { /* nothing selected */ + for (var i = 0; i < 4; i++) { + cfg.floppy.drive[i].type = i == 0 ? SAEC_Config_Floppy_Type_35_DD : SAEC_Config_Floppy_Type_None; + cfg.floppy.drive[i].file.clr(); + } + cfg.floppy.speed = SAEC_Config_Floppy_Speed_Original; + return true; + } + + if (typeof db[dbNum - 1] == "undefined") { + //alert("bug!"); + return false; + } + var dbe = db[dbNum - 1]; + + dskchgList = []; + if (dbe.flags & DBF_MDC) { /* manual disk-change required */ + if (dbe.numdisks == 1) + dskchgList.push(dbe.name); + else { + for (var n = 0; n < dbe.numdisks; n++) + dskchgList.push(getDatabaseEntryFilename(dbe, n, false)); + } + + /* request DF0 immediately */ + cfg.floppy.drive[0].type = SAEC_Config_Floppy_Type_35_DD; + var filename = getDatabaseEntryFilename(dbe, 0, true); + cache.req(dbUrl, filename, 0xdc000, false, cfg.floppy.drive[0].file); + + /* precache DF1-DF3 for later */ + for (var n = 1; n < dbe.numdisks; n++) { + cfg.floppy.drive[n].type = SAEC_Config_Floppy_Type_None; /* disable for now. will be enabled when a disk is inserted */ + cfg.floppy.drive[n].file.clr(); + + filename = getDatabaseEntryFilename(dbe, n, true); + cache.req(dbUrl, filename, 0xdc000, false, false); + } + } else { /* request all disks immediately */ + for (var n = 0; n < dbe.numdisks; n++) { + var filename = getDatabaseEntryFilename(dbe, n, true); + cfg.floppy.drive[n].type = SAEC_Config_Floppy_Type_35_DD; + cache.req(dbUrl, filename, 0xdc000, false, cfg.floppy.drive[n].file); + } + for (var n = dbe.numdisks; n < 4; n++) { + cfg.floppy.drive[n].type = SAEC_Config_Floppy_Type_None; + cfg.floppy.drive[n].file.clr(); + } + } + cfg.floppy.speed = (dbe.flags & DBF_NOT) == 0 ? SAEC_Config_Floppy_Speed_Turbo : SAEC_Config_Floppy_Speed_Original; + return true; +} + +function getDatabaseConfig() { + var dbe = dbNum > 0 ? db[dbNum - 1] : null; + + if (dbe !== null) { + if (dbe.flags & DBF_AGA) + sae.setModel(SAEC_Model_A1200, 0); /* set an A1200 for AGA */ + else if (dbe.flags & DBF_ECS) + sae.setModel(SAEC_Model_A500P, 0); /* set an A500+ for ECS */ + else + sae.setModel(SAEC_Model_A500, 0); /* set an A500 for OCS */ + + if (dbe.flags & DBF_030) + cfg.cpu.model = SAEC_Config_CPU_Model_68030; + + cfg.memory.z2FastSize = 4 << 20; /* give 4MB Zorro2 memory */ + + cfg.chipset.colLevel = SAEC_Config_Chipset_ColLevel_None; + if (dbe.flags & DBF_COL) + cfg.chipset.colLevel = SAEC_Config_Chipset_ColLevel_Sprite_Playfield; /* enable collision-detection */ + + if (dbe.flags & DBF_BIM) + cfg.chipset.blitter.immediate = true; + } else { + sae.setModel(SAEC_Model_A500, 0); + + cfg.memory.z2FastSize = 4 << 20; /* give 4MB Zorro2 memory */ + } + cache.req(URL_DATABASE, AROS_ROM_FILE, 0x80000, AROS_ROM_CRC, cfg.memory.rom); + cache.req(URL_DATABASE, AROS_EXT_FILE, 0x80000, AROS_EXT_CRC, cfg.memory.extRom); + + if (!getDatabaseFloppy()) + return false; + + cfg.video.id = "myVideo"; /* html-div element to add video-output */ + + /*cfg.video.hresolution = getSelect("cfg_video_resolution_1"); + if (cfg.video.hresolution == SAEC_Config_Video_HResolution_LoRes) + cfg.video.vresolution = SAEC_Config_Video_VResolution_NonDouble; + else + cfg.video.vresolution = SAEC_Config_Video_VResolution_Double; + + cfg.video.framerate = getCheckbox("cfg_video_skip_1") ? 2 : 1;*/ + + //cfg.video.size_win.width = SAEC_Video_DEF_AMIGA_WIDTH << cfg.video.hresolution; + //cfg.video.size_win.height = SAEC_Video_DEF_AMIGA_HEIGHT << cfg.video.hresolution; + + setHooks(); + return true; +} + +/*-----------------------------------------------------------------------*/ +/* advanced cfg */ + +function setRomName() { + var e = document.getElementById("cfg_rom_name"); + if (cfg.memory.rom.name.length) { + if (defRomInfo !== null) { + var name = defRomInfo.name; + e.className = (defRomInfo.type & SAEC_RomType_ALL_KICK) ? "green" : "orange"; + setDisabled("cfg_rom_info", 0); + } else { + var name = cfg.memory.rom.name; + e.className = "orange"; + setDisabled("cfg_rom_info", 1); + } + e.innerHTML = name.length > MAX_FILENAME ? name.substr(0, MAX_FILENAME)+" [...]" : name; + + styleDisplayInline("cfg_rom_remove", 1); + styleDisplayInline("cfg_rom_info", 1); + } else { + e.className = "red"; + e.innerHTML = "<unset> (required)"; + styleDisplayInline("cfg_rom_remove", 0); + styleDisplayInline("cfg_rom_info", 0); + document.getElementById("cfg_rom_file").value = ""; + } +} + +function setExtName() { + var e = document.getElementById("cfg_ext_name"); + if (cfg.memory.extRom.name.length) { + if (extRomInfo !== null) { + var name = extRomInfo.name; + e.className = (extRomInfo.type & SAEC_RomType_ALL_EXT) ? "green" : "orange"; + setDisabled("cfg_ext_info", 0); + } else { + var name = cfg.memory.extRom.name; + e.className = "orange"; + setDisabled("cfg_ext_info", 1); + } + e.innerHTML = name.length > MAX_FILENAME ? name.substr(0, MAX_FILENAME)+" [...]" : name; + + styleDisplayInline("cfg_ext_remove", 1); + styleDisplayInline("cfg_ext_info", 1); + } else { + e.className = "gray"; + e.innerHTML = "<unset>"; + styleDisplayInline("cfg_ext_remove", 0); + styleDisplayInline("cfg_ext_info", 0); + document.getElementById("cfg_ext_file").value = ""; + } +} + +function setKeyName() { + var e = document.getElementById("cfg_key_name"); + if (cfg.memory.romKey.name.length) { + if (romKeyInfo !== null) { + var name = romKeyInfo.name; + e.className = (romKeyInfo.type & SAEC_RomType_KEY) ? "green" : "orange"; + setDisabled("cfg_key_info", 0); + } else { + var name = cfg.memory.romKey.name; + e.className = "orange"; + setDisabled("cfg_key_info", 1); + } + e.innerHTML = name.length > MAX_FILENAME ? name.substr(0, MAX_FILENAME)+" [...]" : name; + + styleDisplayInline("cfg_key_remove", 1); + styleDisplayInline("cfg_key_info", 1); + } else { + if (defRomEncrypted || extRomEncrypted) { + e.className = "red"; + e.innerHTML = "<unset> (required)"; + } else { + e.className = "gray"; + e.innerHTML = "<unset>"; + } + styleDisplayInline("cfg_key_remove", 0); + styleDisplayInline("cfg_key_info", 0); + document.getElementById("cfg_key_file").value = ""; + } +} + +function setAMaxName() { + var e = document.getElementById("cfg_amax_name"); + if (cfg.memory.amaxRom.name.length) { + if (amaxInfo !== null) { + var name = amaxInfo.name; + e.className = (amaxInfo.type & SAEC_RomType_AMAX) ? "green" : "orange"; + setDisabled("cfg_amax_info", 0); + } else { + var name = cfg.memory.amaxRom.name; + e.className = "orange"; + setDisabled("cfg_amax_info", 1); + } + e.innerHTML = name.length > MAX_FILENAME ? name.substr(0, MAX_FILENAME)+" [...]" : name; + + styleDisplayInline("cfg_amax_remove", 1); + styleDisplayInline("cfg_amax_info", 1); + } else { + e.className = "gray"; + e.innerHTML = "<unset>"; + styleDisplayInline("cfg_amax_remove", 0); + styleDisplayInline("cfg_amax_info", 0); + document.getElementById("cfg_amax_file").value = ""; + } +} + +function setFloppyName(n) { + var e = document.getElementById("cfg_df"+n+"_name"); + if (cfg.floppy.drive[n].file.size) { + e.className = ""; + if (cfg.floppy.drive[n].file.name.length > MAX_FILENAME) + e.innerHTML = cfg.floppy.drive[n].file.name.substr(0, MAX_FILENAME)+" [...]"; + else + e.innerHTML = cfg.floppy.drive[n].file.name; + styleDisplayInline("cfg_df"+n+"_eject", 1); + styleDisplayInline("cfg_df"+n+"_info", 1); + } else { + e.className = "gray"; + e.innerHTML = "<unset>"; + styleDisplayInline("cfg_df"+n+"_eject", 0); + styleDisplayInline("cfg_df"+n+"_info", 0); + } +} + +function setMountName(n) { + var ci = cfg.mount.config[n].ci; + var e = document.getElementById("cfg_mount_"+n+"_name"); + + if (ci.file.name.length) { + e.className = ""; + if (ci.file.name.length > MAX_FILENAME) + e.innerHTML = ci.file.name.substr(0, MAX_FILENAME)+" [...]"; + else + e.innerHTML = ci.file.name; + + styleDisplayInline("cfg_mount_"+n+"_remove", 1); + if (n < 4) styleDisplayInline("cfg_mount_"+n+"_setup", 1); + } else { + e.className = "gray"; + e.innerHTML = "<unset>"; + styleDisplayInline("cfg_mount_"+n+"_remove", 0); + if (n < 4) styleDisplayInline("cfg_mount_"+n+"_setup", 0); + } +} + +function setAdvandedFloppy(n) { + if (cfg.floppy.drive[n].type != SAEC_Config_Floppy_Type_None) { + setCheckbox("cfg_df"+n+"_enabled", true); + setSelect("cfg_df"+n+"_type", cfg.floppy.drive[n].type); + setCheckbox("cfg_df"+n+"_wp", cfg.floppy.drive[n].file.prot); + setFloppyName(n); + styleDisplayInline("cfg_df"+n+"_grp", 1); + } else { + setCheckbox("cfg_df"+n+"_enabled", false); + styleDisplayInline("cfg_df"+n+"_grp", 0); + } +} + +function setAdvandedMount(n) { + var ci = cfg.mount.config[n].ci; + if (ci.controller_type != 0) { + if (ci.controller_type == SAEC_Config_Mount_Controller_Type_MB_IDE) { + setSelect("cfg_mount_"+n+"_controller_media", ci.controller_media_type); + setSelect("cfg_mount_"+n+"_controller_level", ci.unit_feature_level); + } + if (ci.controller_type != SAEC_Config_Mount_Controller_Type_PCMCIA_IDE) + setCheckbox("cfg_mount_"+n+"_readonly", ci.readonly); + + setMountName(n); + setCheckbox("cfg_mount_"+n+"_enabled", true); + styleDisplayInline("cfg_mount_"+n+"_grp", 1); + } else { + setCheckbox("cfg_mount_"+n+"_enabled", false); + styleDisplayInline("cfg_mount_"+n+"_grp", 0); + } +} + +function fixAdvandedConfig() { + /* video */ + if (cfg.video.enabled) { + if (!inf.video.canvas && !inf.video.webGL) + cfg.video.enabled = false; + else if (SAEV_config.video.api == SAEC_Config_Video_API_WebGL && !inf.video.webGL) + SAEV_config.video.api = SAEC_Config_Video_API_Canvas; + } + /* audio */ + if (cfg.audio.mode >= SAEC_Config_Audio_Mode_On) { + if (!inf.audio.webAudio) + cfg.audio.mode = SAEC_Config_Audio_Mode_Off_Emul; + } +} + +function setAdvandedConfig() { + fixAdvandedConfig(); + + /* cpu */ + setRadio("cfg_cpu_model", cfg.cpu.model); + setRadio("cfg_cpu_speed", cfg.cpu.speed); + setCheckbox("cfg_cpu_compatible", cfg.cpu.compatible); + setCheckbox("cfg_cpu_address_space_32", cfg.cpu.addressSpace24 == false); + + /* chipset */ + if (cfg.chipset.mask & SAEC_Config_Chipset_Mask_AGA) + setRadio("cfg_chipset_mask", 3); + else if ((cfg.chipset.mask & SAEC_Config_Chipset_Mask_ECS_AGNUS) && (cfg.chipset.mask & SAEC_Config_Chipset_Mask_ECS_DENISE)) { + setRadio("cfg_chipset_mask", 2); + setSelect("cfg_chipset_mask_ecs", 3); + } else if (cfg.chipset.mask & SAEC_Config_Chipset_Mask_ECS_AGNUS) { + setRadio("cfg_chipset_mask", 2); + setSelect("cfg_chipset_mask_ecs", 1); + } else if (cfg.chipset.mask & SAEC_Config_Chipset_Mask_ECS_DENISE) { + setRadio("cfg_chipset_mask", 2); + setSelect("cfg_chipset_mask_ecs", 2); + } else + setRadio("cfg_chipset_mask", 1); + + setRadio("cfg_chipset_ntsc", cfg.chipset.ntsc ? 1 : 0); + + setSelect("cfg_chipset_cl", cfg.chipset.colLevel); + + setRadio("cfg_blitter_immediate", cfg.chipset.blitter.immediate ? 0 : 1); + setSelect("cfg_blitter_waiting", cfg.chipset.blitter.waiting); + + /* chipset features */ + //setSelect("cfg_chipset_features", cfg.chipset.compatible); + switch (cfg.chipset.compatible) { + case SAEC_Config_Chipset_Compatible_Generic: setSelect("cfg_chipset_features", "generic"); break; + case SAEC_Config_Chipset_Compatible_A500: setSelect("cfg_chipset_features", "A500"); break; + case SAEC_Config_Chipset_Compatible_A500P: setSelect("cfg_chipset_features", "A500P"); break; + case SAEC_Config_Chipset_Compatible_A600: setSelect("cfg_chipset_features", "A600"); break; + case SAEC_Config_Chipset_Compatible_A1000: setSelect("cfg_chipset_features", "A1000"); break; + case SAEC_Config_Chipset_Compatible_A1000V: setSelect("cfg_chipset_features", "A1000V"); break; + case SAEC_Config_Chipset_Compatible_A1200: setSelect("cfg_chipset_features", "A1200"); break; + case SAEC_Config_Chipset_Compatible_A2000: setSelect("cfg_chipset_features", "A2000"); break; + case SAEC_Config_Chipset_Compatible_A3000: setSelect("cfg_chipset_features", "A3000"); break; + case SAEC_Config_Chipset_Compatible_A4000: setSelect("cfg_chipset_features", "A4000"); break; + //case SAEC_Config_Chipset_Compatible_A4000T: setSelect("cfg_chipset_features", "A4000T"); break; + //case SAEC_Config_Chipset_Compatible_CDTV: setSelect("cfg_chipset_features", "CDTV"); break; + //case SAEC_Config_Chipset_Compatible_CDTVCR: setSelect("cfg_chipset_features", "CDTVCR"); break; + //case SAEC_Config_Chipset_Compatible_CD32: setSelect("cfg_chipset_features", "CD32"); break; + case SAEC_Config_Chipset_Compatible_Manual: setSelect("cfg_chipset_features", "manual"); break; + } + styleDisplayBlock("cfg_chipset_features_grp", cfg.chipset.compatible == SAEC_Config_Chipset_Compatible_Manual); + { + setSelect("cfg_chipset_cia_tod", cfg.chipset.cia.tod); + setCheckbox("cfg_chipset_cia_todbug", cfg.chipset.cia.todBug); + setCheckbox("cfg_chipset_cia_overlay", cfg.chipset.cia.overlay); + setCheckbox("cfg_chipset_cia_type6526", cfg.chipset.cia.type6526); + + setSelect("cfg_chipset_rtc_type", cfg.chipset.rtc.type); + + setSelect("cfg_chipset_ide", cfg.chipset.ide == -1 ? 0 : cfg.chipset.ide); + setCheckbox("cfg_chipset_pcmcia", cfg.chipset.pcmcia); + + setCheckbox("cfg_chipset_agnus_dip", cfg.chipset.agnusDIP); + + setCheckbox("cfg_rom_mirror_a8", cfg.chipset.mirrorA8); + setCheckbox("cfg_rom_mirror_e0", cfg.chipset.mirrorE0); + + setCheckbox("cfg_chipset_z3autoconfig", cfg.chipset.z3AutoConfig); + } + + /* ram */ + setSelect("cfg_mem_chip", cfg.memory.chipSize >> 10); + setSelect("cfg_mem_slow", cfg.memory.bogoSize >> 10); + setSelect("cfg_mem_ramsey_low", cfg.memory.ramsey.lowSize >> 10); + setSelect("cfg_mem_ramsey_high", cfg.memory.ramsey.highSize >> 10); + setSelect("cfg_mem_z2fast", cfg.memory.z2FastSize >> 10); + setCheckbox("cfg_mem_z2fastautoconfig", cfg.memory.z2FastAutoConfig); + setSelect("cfg_mem_z3fast", cfg.memory.z3FastSize >> 10); + setSelect("cfg_mem_z3mapping", cfg.memory.z3Mapping); + + /* rom */ + setCheckbox("cfg_rom_use_aros", useAROS); + styleDisplayBlock("cfg_rom_grp", useAROS ? false : true); + if (!useAROS) { + setRomName(); + setExtName(); + setKeyName(); + setAMaxName(); + } + setCheckbox("cfg_rom_kickshifter", cfg.memory.kickShifter); + + /* floppy */ + for (var i = 0; i < 4; i++) + setAdvandedFloppy(i); + setSelect("cfg_floppy_speed", cfg.floppy.speed); + setCheckbox("cfg_floppy_autoext2", cfg.floppy.autoEXT2 != 0); + + /* mount */ + for (var i = 0; i < 6; i++) + setAdvandedMount(i); + + /* video */ + setCheckbox("cfg_video_enabled", cfg.video.enabled); + setDisabled("cfg_video_enabled", !inf.video.canvas && !inf.video.webGL); + //if (cfg.video.enabled) + { + setSelect("cfg_video_api", cfg.video.api); + setDisabled("cfg_video_api", inf.video.webGL == false); + setSelect("cfg_video_color_mode", cfg.video.colorMode); + setCheckbox("cfg_video_antialias", cfg.video.antialias); + //setRadio("cfg_video_fs", cfg.video.apmode[0].gfx_fullscreen); + //setText("cfg_video_win_width", cfg.video.size_win.width); + //setText("cfg_video_win_height", cfg.video.size_win.height); + //setText("cfg_video_fs_width", cfg.video.size_fs.width); + //setText("cfg_video_fs_height", cfg.video.size_fs.height); + setSelect("cfg_video_resolution", cfg.video.hresolution); + setSelect("cfg_video_linemode", cfg.video.pscanlines == 1 ? 2 : cfg.video.vresolution); + setSelect("cfg_video_interlace", cfg.video.iscanlines); + setDisabled("cfg_video_interlace", cfg.video.vresolution == SAEC_Config_Video_VResolution_NonDouble); + setCheckbox("cfg_video_skip", cfg.video.framerate != 1); + setCheckbox("cfg_video_xcenter", cfg.video.xcenter != 0); + setCheckbox("cfg_video_ycenter", cfg.video.ycenter != 0); + setText("cfg_video_brightness", cfg.video.luminance); + setText("cfg_video_contrast", cfg.video.contrast); + setText("cfg_video_gamma", cfg.video.gamma); + setText("cfg_video_alpha", cfg.video.alpha); + setDisabled("cfg_video_alpha", cfg.video.colorMode < 5); + setText("cfg_video_background", sprintf("%06X", cfg.video.backgroundColor)); + setDisabled("cfg_video_background", cfg.video.colorMode < 5); + setCheckbox("cfg_video_blackerthanblack", cfg.video.blackerThanBlack); + setCheckbox("cfg_video_refreshindicator", cfg.video.refreshIndicator); + styleDisplayBlock("cfg_video_error_webgl", inf.video.webGL == false); + } + styleDisplayBlock("cfg_video_grp", cfg.video.enabled != 0); + styleDisplayBlock("cfg_video_error_canvas", inf.video.canvas == false && inf.video.webGL == false); + + /* audio */ + setCheckbox("cfg_audio_enabled", cfg.audio.mode != SAEC_Config_Audio_Mode_Off); + setSelect("cfg_audio_buffer_frames", cfg.audio.bufferFrames); + setSelect("cfg_audio_mode", cfg.audio.mode); + setDisabled("cfg_audio_mode", inf.audio.webAudio == false); + setSelect("cfg_audio_filter", cfg.audio.filter); + setSelect("cfg_audio_filtertype", cfg.audio.filterType); + setSelect("cfg_audio_freq", cfg.audio.freq); + setSelect("cfg_audio_separation", cfg.audio.stereoSeparation); + setSelect("cfg_audio_delay", cfg.audio.stereoDelay); + setSelect("cfg_audio_channels", cfg.audio.channels); + setSelect("cfg_audio_interpolation", cfg.audio.interpol); + styleDisplayBlock("cfg_audio_grp", cfg.audio.mode != SAEC_Config_Audio_Mode_Off); + styleDisplayBlock("cfg_audio_error", inf.audio.webAudio == false); + + /* ports */ + setSelect("cfg_ports_0", cfg.ports[0].type); + setSelect("cfg_ports_0_move", cfg.ports[0].move); + setSelect("cfg_ports_0_fire_1", cfg.ports[0].fire[0]); + setSelect("cfg_ports_0_fire_2", cfg.ports[0].fire[1]); + styleDisplayInline("cfg_ports_0_grp", cfg.ports[0].type == SAEC_Config_Ports_Type_Joy0); + + setSelect("cfg_ports_1", cfg.ports[1].type); + setSelect("cfg_ports_1_move", cfg.ports[1].move); + setSelect("cfg_ports_1_fire_1", cfg.ports[1].fire[0]); + setSelect("cfg_ports_1_fire_2", cfg.ports[1].fire[1]); + styleDisplayInline("cfg_ports_1_grp", cfg.ports[1].type == SAEC_Config_Ports_Type_Joy1); + + setCheckbox("cfg_keyborad_enabled", cfg.keyboard.enabled); + + setCheckbox("cfg_serial_enabled", cfg.serial.enabled); + + styleDisplayTableCell("controls_disk", 1); +} + +function getAdvandedFloppy() { + for (var n = 0; n < 4; n++) { + if (getCheckbox("cfg_df"+n+"_enabled")) { + cfg.floppy.drive[n].type = getSelect("cfg_df"+n+"_type"); + cfg.floppy.drive[n].file.prot = getCheckbox("cfg_df"+n+"_wp"); + } + } + cfg.floppy.speed = getSelect("cfg_floppy_speed"); + cfg.floppy.autoEXT2 = getCheckbox("cfg_floppy_autoext2") ? 1 : 0; +} +function getAdvandedMount() { + for (var n = 0; n < 6; n++) { + var ci = cfg.mount.config[n].ci; + if (getCheckbox("cfg_mount_"+n+"_enabled")) { + if (n < 4) { + ci.controller_type = SAEC_Config_Mount_Controller_Type_MB_IDE; + ci.controller_unit = n; + ci.controller_media_type = getSelect("cfg_mount_"+n+"_controller_media"); + ci.unit_feature_level = getSelect("cfg_mount_"+n+"_controller_level"); + } else if (n == 4) + ci.controller_type = SAEC_Config_Mount_Controller_Type_PCMCIA_SRAM; + else + ci.controller_type = SAEC_Config_Mount_Controller_Type_PCMCIA_IDE; + if (n != 5) + ci.readonly = getCheckbox("cfg_mount_"+n+"_readonly"); + } else + ci.controller_type = 0; + } +} +function getAdvandedConfig() { + /* cpu */ + cfg.cpu.model = getRadio("cfg_cpu_model"); + cfg.cpu.speed = getRadio("cfg_cpu_speed"); + cfg.cpu.compatible = getCheckbox("cfg_cpu_compatible"); + cfg.cpu.addressSpace24 = getCheckbox("cfg_cpu_address_space_32") ? false : true; + + /* chipset */ + cfg.chipset.mask = SAEC_Config_Chipset_Mask_OCS; + switch (getRadio("cfg_chipset_mask")) { + case 1: break; + case 2: { + switch (getSelect("cfg_chipset_mask_ecs")) { + case 1: cfg.chipset.mask |= SAEC_Config_Chipset_Mask_ECS_AGNUS; break; + case 2: cfg.chipset.mask |= SAEC_Config_Chipset_Mask_ECS_DENISE; break; + case 3: cfg.chipset.mask |= (SAEC_Config_Chipset_Mask_ECS_AGNUS | SAEC_Config_Chipset_Mask_ECS_DENISE); break; + } + break; + } + case 3: cfg.chipset.mask |= (SAEC_Config_Chipset_Mask_ECS_AGNUS | SAEC_Config_Chipset_Mask_ECS_DENISE | SAEC_Config_Chipset_Mask_AGA); break; + } + cfg.chipset.ntsc = getRadio("cfg_chipset_ntsc") == 1; + + cfg.chipset.colLevel = getSelect("cfg_chipset_cl"); + + cfg.chipset.blitter.immediate = getRadio("cfg_blitter_immediate") == 0; + cfg.chipset.blitter.waiting = getSelect("cfg_blitter_waiting"); + + //cfg.chipset.compatible = getSelect("cfg_chipset_features"); + switch (getSelect("cfg_chipset_features", true)) { + case "generic": cfg.chipset.compatible = SAEC_Config_Chipset_Compatible_Generic; break; + case "A500": cfg.chipset.compatible = SAEC_Config_Chipset_Compatible_A500; break; + case "A500P": cfg.chipset.compatible = SAEC_Config_Chipset_Compatible_A500P; break; + case "A600": cfg.chipset.compatible = SAEC_Config_Chipset_Compatible_A600; break; + case "A1000": cfg.chipset.compatible = SAEC_Config_Chipset_Compatible_A1000; break; + case "A1000V": cfg.chipset.compatible = SAEC_Config_Chipset_Compatible_A1000V; break; + case "A1200": cfg.chipset.compatible = SAEC_Config_Chipset_Compatible_A1200; break; + case "A2000": cfg.chipset.compatible = SAEC_Config_Chipset_Compatible_A2000; break; + case "A3000": cfg.chipset.compatible = SAEC_Config_Chipset_Compatible_A3000; break; + case "A4000": cfg.chipset.compatible = SAEC_Config_Chipset_Compatible_A4000; break; + //case "A4000T": cfg.chipset.compatible = SAEC_Config_Chipset_Compatible_A4000T; break; + //case "CDTV": cfg.chipset.compatible = SAEC_Config_Chipset_Compatible_CDTV; break; + //case "CDTVCR": cfg.chipset.compatible = SAEC_Config_Chipset_Compatible_CDTVCR; break; + //case "CD32": cfg.chipset.compatible = SAEC_Config_Chipset_Compatible_CD32; break; + case "manual": cfg.chipset.compatible = SAEC_Config_Chipset_Compatible_Manual; break; + } + if (cfg.chipset.compatible == SAEC_Config_Chipset_Compatible_Manual) { + cfg.chipset.cia.tod = getSelect("cfg_chipset_cia_tod"); + cfg.chipset.cia.todBug = getCheckbox("cfg_chipset_cia_todbug"); + cfg.chipset.cia.overlay = getCheckbox("cfg_chipset_cia_overlay"); + cfg.chipset.cia.type6526 = getCheckbox("cfg_chipset_cia_type6526"); + + cfg.chipset.rtc.type = getSelect("cfg_chipset_rtc_type"); + + cfg.chipset.ide = getSelect("cfg_chipset_ide"); + cfg.chipset.pcmcia = getCheckbox("cfg_chipset_pcmcia"); + + cfg.chipset.agnusDIP = getCheckbox("cfg_chipset_agnus_dip"); + cfg.chipset.mirrorA8 = getCheckbox("cfg_rom_mirror_a8"); + cfg.chipset.mirrorE0 = getCheckbox("cfg_rom_mirror_e0"); + + cfg.chipset.z3AutoConfig = getCheckbox("cfg_chipset_z3autoconfig"); + } + + /* ram */ + cfg.memory.chipSize = getSelect("cfg_mem_chip") << 10; + cfg.memory.bogoSize = getSelect("cfg_mem_slow") << 10; + cfg.memory.ramsey.lowSize = getSelect("cfg_mem_ramsey_low") << 10; + cfg.memory.ramsey.highSize = getSelect("cfg_mem_ramsey_high") << 10; + cfg.memory.z2FastSize = getSelect("cfg_mem_z2fast") << 10; + cfg.memory.z2FastAutoConfig = getCheckbox("cfg_mem_z2fastautoconfig"); + cfg.memory.z3FastSize = getSelect("cfg_mem_z3fast") << 10; + cfg.memory.z3Mapping = getSelect("cfg_mem_z3mapping"); + + /* rom */ + useAROS = getCheckbox("cfg_rom_use_aros"); + if (useAROS) { + cache.req(URL_DATABASE, AROS_ROM_FILE, 0x80000, AROS_ROM_CRC, cfg.memory.rom); + cache.req(URL_DATABASE, AROS_EXT_FILE, 0x80000, AROS_EXT_CRC, cfg.memory.extRom); + cfg.memory.romKey.clr(); + } else { + if (cfg.memory.rom.size == 0) { + alert(saee2text(SAEE_Memory_NoKickstartRom)); + changePage(PID_ROM); return false; } } - e = document.getElementById('cfg_ports_1'); - config.ports[1].type = parseInt(getSelectValue(e)); - if (config.ports[1].type == SAEV_Config_Ports_Type_Joy1) { - e = document.getElementById('cfg_ports_1_move'); - config.ports[1].move = parseInt(getSelectValue(e)); - e = document.getElementById('cfg_ports_1_fire_1'); - config.ports[1].fire[0] = parseInt(getSelectValue(e)); - e = document.getElementById('cfg_ports_1_fire_2'); - config.ports[1].fire[1] = parseInt(getSelectValue(e)); - if (config.ports[1].fire[0] != SAEV_Config_Ports_Fire_None && config.ports[1].fire[0] == config.ports[1].fire[1]) { - alert('Fire-button 1/2 on port 1 can\'t be the same.'); + cfg.memory.kickShifter = getCheckbox("cfg_rom_kickshifter"); + + /* floppy */ + getAdvandedFloppy(); + + /* mount */ + getAdvandedMount() + + /* video */ + cfg.video.id = "myVideo"; + cfg.video.enabled = getCheckbox("cfg_video_enabled"); + if (cfg.video.enabled) { + cfg.video.api = getSelect("cfg_video_api"); + cfg.video.colorMode = getSelect("cfg_video_color_mode"); + cfg.video.antialias = getCheckbox("cfg_video_antialias"); + //cfg.video.apmode[0].gfx_fullscreen = getRadio("cfg_video_fs"); + //cfg.video.size_win.width = getText("cfg_video_win_width"); + //cfg.video.size_win.height = getText("cfg_video_win_height"); + //cfg.video.size_fs.width = getText("cfg_video_fs_width"); + //cfg.video.size_fs.height = getText("cfg_video_fs_height"); + cfg.video.hresolution = getSelect("cfg_video_resolution"); + switch (getSelect("cfg_video_linemode")) { + case 0: + cfg.video.vresolution = SAEC_Config_Video_VResolution_NonDouble; + cfg.video.pscanlines = 0; + cfg.video.iscanlines = 0; + break; + case 1: + cfg.video.vresolution = SAEC_Config_Video_VResolution_Double; + cfg.video.pscanlines = 0; + cfg.video.iscanlines = getSelect("cfg_video_interlace"); + break; + case 2: + cfg.video.vresolution = SAEC_Config_Video_VResolution_Double; + cfg.video.pscanlines = 1; + cfg.video.iscanlines = getSelect("cfg_video_interlace"); + break; + } + cfg.video.framerate = getCheckbox("cfg_video_skip") ? 2 : 1; + cfg.video.xcenter = getCheckbox("cfg_video_xcenter") ? 2 : 0; + cfg.video.ycenter = getCheckbox("cfg_video_ycenter") ? 2 : 0; + cfg.video.luminance = getText("cfg_video_brightness"); + cfg.video.contrast = getText("cfg_video_contrast"); + cfg.video.gamma = getText("cfg_video_gamma"); + cfg.video.backgroundColor = Number("0x"+getText("cfg_video_background", true)); + cfg.video.alpha = getText("cfg_video_alpha"); + cfg.video.blackerThanBlack = getCheckbox("cfg_video_blackerthanblack"); + cfg.video.refreshIndicator = getCheckbox("cfg_video_refreshindicator"); + cfg.video.size_win.width = SAEC_Video_DEF_AMIGA_WIDTH << cfg.video.hresolution; + cfg.video.size_win.height = SAEC_Video_DEF_AMIGA_HEIGHT << cfg.video.vresolution; + } + + /* audio */ + if (getCheckbox("cfg_audio_enabled")) + cfg.audio.mode = getSelect("cfg_audio_mode"); + else + cfg.audio.mode = SAEC_Config_Audio_Mode_Off; + + if (cfg.audio.mode != SAEC_Config_Audio_Mode_Off) { + cfg.audio.bufferFrames = getSelect("cfg_audio_buffer_frames"); + cfg.audio.filter = getSelect("cfg_audio_filter"); + cfg.audio.filterType = getSelect("cfg_audio_filtertype"); + cfg.audio.freq = getSelect("cfg_audio_freq"); + cfg.audio.stereoSeparation = getSelect("cfg_audio_separation"); + cfg.audio.stereoDelay = getSelect("cfg_audio_delay"); + cfg.audio.channels = getSelect("cfg_audio_channels"); + cfg.audio.interpol = getSelect("cfg_audio_interpolation"); + } + + /* ports */ + cfg.ports[0].type = getSelect("cfg_ports_0"); + if (cfg.ports[0].type == SAEC_Config_Ports_Type_Joy0) { + cfg.ports[0].move = getSelect("cfg_ports_0_move"); + cfg.ports[0].fire[0] = getSelect("cfg_ports_0_fire_1"); + cfg.ports[0].fire[1] = getSelect("cfg_ports_0_fire_2"); + if (cfg.ports[0].fire[0] != SAEC_Config_Ports_Fire_None && cfg.ports[0].fire[0] == cfg.ports[0].fire[1]) { + alert("Fire-button 1/2 on port 0 can\"t be the same."); return false; } - } + } + cfg.ports[1].type = getSelect("cfg_ports_1"); + if (cfg.ports[1].type == SAEC_Config_Ports_Type_Joy1) { + cfg.ports[1].move = getSelect("cfg_ports_1_move"); + cfg.ports[1].fire[0] = getSelect("cfg_ports_1_fire_1"); + cfg.ports[1].fire[1] = getSelect("cfg_ports_1_fire_2"); + if (cfg.ports[1].fire[0] != SAEC_Config_Ports_Fire_None && cfg.ports[1].fire[0] == cfg.ports[1].fire[1]) { + alert("Fire-button 1/2 on port 1 can\"t be the same."); + return false; + } + } - config.serial.enabled = document.getElementById('cfg_serial_enabled').checked ? true : false; + cfg.keyboard.enabled = getCheckbox("cfg_keyborad_enabled"); - config.hooks.error = hooks_error; - config.hooks.power_led = hooks_power_led; - config.hooks.floppy_motor = hooks_floppy_motor; - config.hooks.floppy_step = hooks_floppy_step; - config.hooks.fps = hooks_fps; - config.hooks.cpu = hooks_cpu; - - if (config.chipset.mask != SAEV_Config_Chipset_Mask_OCS) - config.chipset.agnus_dip = false; + cfg.serial.enabled = getCheckbox("cfg_serial_enabled"); - return true; -} + /* hooks */ + setHooks(); + return true; +} /*-----------------------------------------------------------------------*/ /* main */ -function init() { - cache = new Cache(); - - SAE({cmd:'init'}); - - info = SAE({cmd:'getInfo'}); - config = SAE({cmd:'getConfig'}); - //console.log(info); - //console.log(config); - - setSimpleConfig(); - - if (window.location.hash.length > 1) { - var start = false; - var name = urldecode(window.location.hash.substr(1)); - while (true) { - var tmp = name.replace('_', ' '); - if (tmp == name) break; - name = tmp; - } - for (var i = 0; i < db[0].length; i++) { - if (db[0][i][0] == name) { - document.getElementById('cfg_game')[i+1].selected = true; - preSelect(1); - start = true; - break; - } - } - if (!start) { - for (var i = 0; i < db[1].length; i++) { - if (db[1][i][0] == name) { - document.getElementById('cfg_demo')[i+1].selected = true; - preSelect(2); - start = true; - break; - } - } - } - if (start) - simpleStart(); - } -} - -function mainStart() { - return SAE({cmd: 'start'}); -} function start() { - document.body.style.backgroundColor = '#000'; - styleDisplayBlock('base', 0); - styleDisplayBlock('emul', 1); - - if (mode == 0) { - var item = dbNum > 0 ? db[dbGrp - 1][dbNum - 1] : null; - if (item) { - var name = item[0]; - while (true) { - var tmp = name.replace(' ', '_'); - if (tmp == name) break; - name = tmp; - } - window.location.hash = name; - } else - window.location.hash = ''; - } else - window.location.hash = ''; - - //SAE({cmd:'setConfig',data:config}); - /*var result = SAE({cmd:'start'}); - if (result.error != SAEE_None) { - stop(); - alert(result.message); - }*/ + var s = cache.state(); + if (s == S_VALID) { /* all files are downloaded or cached, go! */ + freezeButtons(false, true); + switchBaseEmul(true); - if (BrowserDetect.browser == 'Firefox') { /* Thanks 'dmcoles' */ - console.log('Enabling audio-start delay for Firefox...'); - setTimeout(mainStart, 50); - } else - mainStart(); -} - -function simpleStart2() { - if (getSimpleConfig()) - start(); - else { - disabled('cfg_simple_start', 0); - document.getElementById('cfg_simple_start').innerHTML = 'Play'; + var err = sae.start(); /* this does start the emulator */ + if (err != SAEE_None) { + switchBaseEmul(false); + alert(saee2text(err)); + } + } + else if (s == S_PENDING) { /* files are still downloading, wait... */ + setTimeout(start, 250); + } + else /*if (s == S_ERROR)*/ { /* XMLHttpRequest-error */ + freezeButtons(false, true); } } -function simpleStart() { - disabled('cfg_simple_start', 1); - document.getElementById('cfg_simple_start').innerHTML = 'Loading...'; - setTimeout('simpleStart2()', 1); +/*function delayedStart() { + if (SAEC_Info.browser.id == SAEC_Info_Brower_ID_Firefox) { // Thanks "dmcoles" + console.log("delayedStart() enabling audio-start delay for Firefox..."); + setTimeout(start, 50); + } else + start(); +}*/ + +function databaseStart() { + if (getDatabaseConfig()) { + freezeButtons(true, true); + //addItemToURL(); + //delayedStart(); + start(); + } } -function advandedStart2() { - if (getConfig()) - start(); - else { - disabled('cfg_start', 0); - document.getElementById('cfg_start').innerHTML = 'Start'; - } -} function advandedStart() { - disabled('cfg_start', 1); - document.getElementById('cfg_start').innerHTML = 'Loading...'; - setTimeout('advandedStart2()', 1); -} - + if (getAdvandedConfig()) { + freezeButtons(true, true); + //delayedStart(); + start(); + } +} + function stop() { - SAE({cmd:'stop'}); + sae.stop(); if (paused) { - var e = document.getElementById('status_pr'); - e.value = 'pause'; - e.onclick = function () { - pause(1); - }; paused = false; + switchPauseResume(paused); } if (dskchg) dskchgClose(); - disabled('cfg_simple_start', 0); - disabled('cfg_start', 0); - document.getElementById('cfg_simple_start').innerHTML = 'Play'; - document.getElementById('cfg_start').innerHTML = 'Start'; + if (mode == MODE_Advanced) + setAdvandedConfig(); - if (mode == 1) - setConfig(); - - styleDisplayBlock('emul', 0); - styleDisplayBlock('base', 1); - document.body.style.backgroundColor = '#fff'; -} + switchBaseEmul(false); +} function reset() { - SAE({cmd:'reset'}); -} + sae.reset(); + + if (paused) { + paused = false; + switchPauseResume(paused); + } + if (dskchg) + dskchgClose(); +} function pause(p) { - var e = document.getElementById('status_pr'); - e.innerHTML = p ? 'Resume' : 'Pause'; - e.onclick = function () { - pause(1 - p); - }; - + switchPauseResume(p); paused = p; - SAE({cmd:'pause',state:p}); -} - -/*-----------------------------------------------------------------------*/ -/* config */ - -function switchCfg(m) -{ - styleDisplayBlock('config_advanced', m == 1); - styleDisplayBlock('config_simple', m != 1); - if (m == 0) - setSimpleConfig(); - else - setConfig(); - - mode = m; + sae.pause(p); /* true == pause, false == resume */ } -/*-----------------------------------------------------------------------*/ -/* simple config */ +/*---------------------------------*/ -function preSelect(grp) -{ - var num; - if (grp == 1) { - num = parseInt(getSelectValue(document.getElementById('cfg_game'))); - unselect(document.getElementById('cfg_demo')); - } else { - unselect(document.getElementById('cfg_game')); - num = parseInt(getSelectValue(document.getElementById('cfg_demo'))); - } - dbGrp = grp; - dbNum = num; +function init() { + cache = new Cache(); - if (num == 0) { - styleDisplayTable('cfg_info', 0); - return; - } - var item = db[grp - 1][num - 1]; - - document.getElementById('cfg_info_name').innerHTML = item[0]; - if (typeof(item[1]) == 'object') { - document.getElementById('cfg_info_comp').innerHTML = item[1][0]; - document.getElementById('cfg_info_publ').innerHTML = item[1][1]; - document.getElementById('cfg_info_lic').innerHTML = item[1][2]; - } else { - document.getElementById('cfg_info_comp').innerHTML = item[1]; - document.getElementById('cfg_info_publ').innerHTML = '-'; - document.getElementById('cfg_info_lic').innerHTML = '-'; - } - document.getElementById('cfg_info_year').innerHTML = item[2]; - styleDisplayTable('cfg_info', 1); - styleDisplayInline('dskchg_grp', item[4][0] ? 1 : 0); + sae = new ScriptedAmigaEmulator(); /* create emulator */ + inf = sae.getInfo(); /* reference to cfg */ + cfg = sae.getConfig(); /* reference to cfg */ - if (item[6].length) { - document.getElementById('cfg_info_load').innerHTML = item[6]; - styleDisplayTableRow('cfg_info_load_grp', 1); - } else - styleDisplayTableRow('cfg_info_load_grp', 0); - - if (grp == 2) { - styleDisplayTableRow('cfg_info_ctrl_grp', 0); - } else { - var keys = []; - if (item[5][0]) { - var input = [ - ['Movement','Arrows'], - ['Fire 1',fireButtonName(item[5][1])], - ['Fire 2',fireButtonName(item[5][2])] - ]; - keys = keys.concat(input); + //console.log(inf); + //console.log(cfg); + + initHooks(); + + dbInit(); + setDatabaseConfig(); + + if (window.location.hash.length > 1) { + var start = false; + var name = decodeURL(window.location.hash.substr(1)); + while (true) { + var tmp = name.replace("_", " "); + if (tmp == name) break; + name = tmp; } - if (item[7].length) - keys = keys.concat(item[7]); - - var ctrl = ''; - for (var i = 0; i < keys.length; i++) - ctrl += keys[i][0]+': '+keys[i][1]+'
'; - - var ctrl = ''; - for (var i = 0; i < keys.length; i++) - ctrl += ''; - ctrl += '
'+keys[i][0]+':'+keys[i][1]+'
'; - - document.getElementById('cfg_info_ctrl').innerHTML = ctrl; - styleDisplayTableRow('cfg_info_ctrl_grp', 1); + var pos; + if ((pos = dbFindTypeNamePos(DBT_GAME, name)) != -1) { + setSelect("cfg_game", pos+1); + preSelect(DBT_GAME); + start = true; + } + if (!start) { + if ((pos = dbFindTypeNamePos(DBT_DEMO, name)) != -1) { + setSelect("cfg_demo", pos+1); + preSelect(DBT_DEMO); + start = true; + } + } + if (!start) { + if ((pos = dbFindTypeNamePos(DBT_DAGA, name)) != -1) { + setSelect("cfg_demo_aga", pos+1); + preSelect(DBT_DAGA); + start = true; + } + } + if (!start) { + if ((pos = dbFindTypeNamePos(DBT_TOOL, name)) != -1) { + //document.getElementById("cfg_tool")[pos+1].selected = true; + setSelect("cfg_tool", pos+1); + preSelect(DBT_TOOL); + start = true; + } + } + if (start) + databaseStart(); } } /*-----------------------------------------------------------------------*/ -/* advanced config */ +/*-----------------------------------------------------------------------*/ +/*-----------------------------------------------------------------------*/ -function romAROS() { - //document.getElementById('cfg_rom_aros').innerHTML = 'Loading...'; - disabled('cfg_rom_aros', 1); - - config.rom.name = aros_rom_file; - config.rom.size = SAEV_Config_ROM_Size_512K; - if ((config.rom.data = cache.loadRom(0)) === null) - return false; - - config.ext.name = aros_ext_file; - config.ext.size = SAEV_Config_EXT_Size_512K; - config.ext.addr = SAEV_Config_EXT_Addr_E0; - if ((config.ext.data = cache.loadRom(1)) === null) - return false; +function switchCfg(m) { + if (m == MODE_Database) { + if (mode == MODE_Advanced) { + if (!confirm("Going back to the database will reset the current configuration.\n\nAre you sure?")) + return; + } else { + alert("Click this logo in the advanced-config, if you want to return here."); + return; + } + } + mode = m; - /*document.getElementById('cfg_rom_aros').style.visibility = 'hidden';*/ + styleDisplayBlock("config_database", m == MODE_Database); + styleDisplayBlock("config_advanced", m == MODE_Advanced); - setRomName(config.rom.name); - setExtName(config.ext.name); - document.getElementById('cfg_ext_addr')[0].selected = true; - styleDisplayInline('cfg_ext_remove', 1); - styleDisplayTableRow('cfg_ext_addr_grp', 1); - disabled('cfg_rom_aros', 0); - return true; + sae.setDefaults(); + + if (m == MODE_Database) { + if (page == PID_Floppy_Info && floppyNum != -1) + floppyCloseInfo(); + else if (page == PID_Mount_Setup && mountConfigNum != -1) + mountCloseSetup(false); + + setDatabaseConfig(); + changePage(PID_None); + } else /*if (m == MODE_Advanced)*/ { + preSelect(0); + + setAdvandedConfig(); + if (page == PID_None) + changePage(PID_Model); + } +} + +/*-----------------------------------------------------------------------*/ +/* database cfg */ + +function preSelect(grp) { + function insertRow1(table, item) { + var row = table.insertRow(-1); + var cell = row.insertCell(-1); + cell.innerHTML = item; + cell.colSpan = 4; + } + function insertRow2(table, item) { + var row = table.insertRow(-1); + var cell1 = row.insertCell(-1); + var cell2 = row.insertCell(-1); + cell1.className = "arm"; + cell1.innerHTML = ''+item[0]+''; + cell2.className = "alm"; + cell2.innerHTML = item[1]; + cell2.colSpan = 3; + cell2.style.width = "100%"; + } + function insertRow4(table, item1, item2) { + var row = table.insertRow(-1); + var cell1 = row.insertCell(-1); + var cell2 = row.insertCell(-1); + if (item1 !== false) { + cell1.className = "arm"; + cell1.innerHTML = ''+item1[0]+''; + cell2.className = "alm"; + cell2.innerHTML = item1[1]; + } + cell1 = row.insertCell(-1); + cell2 = row.insertCell(-1); + cell2.style.width = "50%"; + if (item2 !== false) { + cell1.className = "arm"; + cell1.innerHTML = ''+item2[0]+''; + cell2.className = "alm"; + cell2.innerHTML = item2[1]; + } + } + + /* remove old box */ + var div = document.getElementById("config_database_info"); + var table = document.getElementById("config_database_info_content"); + if (table) + div.removeChild(table); + + var id = ""; + if (dbGrp > 0 && dbGrp != grp) { + id = DB_IDS[0][dbGrp - 1]; + setSelect(id, 0); + } + + if (grp > 0) { + id = DB_IDS[0][grp - 1]; + dbUrl = DB_URLS[grp - 1]; + dbGrp = grp; + dbNum = getSelect(id); + } else { + dbGrp = 0; + dbNum = 0; + dbUrl = ""; + return; /* no group selected */ + } + if (dbNum == 0) /* no entry selected */ + return; + + /* create new box */ + var dbe = db[dbNum - 1]; + + styleDisplayTableCell("controls_disk", (dbe.flags & DBF_MDC) != 0); + + var href = dbe.name; + while (true) { + var tmp = href.replace(" ", "_"); + if (tmp == href) break; + href = tmp; + } + href = "http://" + window.location.hostname + "/#" + href; + var nameLink = dbe.name+" (share)"; + + var license = ""; + if (dbe.license.length) { + if (dbe.license == "PD") license = "Public Domain"; + else if (dbe.license == "FW") license = "Freeware"; + else license = dbe.license; + } + + if (grp == DBT_GAME) { + var keys = [ + ["Movement","Arrows"], + ["Fire", fireButtonName(16)], + ["Alt-fire", fireButtonName(17)] + ]; + var ctrl = ""; + for (var i = 0; i < keys.length; i++) + ctrl += keys[i][0]+": "+keys[i][1]+"
"; + + var ctrl = ""; + for (var i = 0; i < keys.length; i++) + ctrl += ""; + ctrl += "
"+keys[i][0]+":"+keys[i][1]+"
"; + } + + table = document.createElement("table"); + table.id = "config_database_info_content"; + table.style.width = "100%"; + table.style.whiteSpace = "normal"; + + insertRow1(table, "
"); + insertRow1(table, "
"); + insertRow1(table, "
"); + + insertRow4(table, ["Name", nameLink], dbe.license.length ? ["License", license] : false); + insertRow4(table, ["Developer", dbe.developer], dbe.publisher.length ? ["Publisher", dbe.publisher] : false); + insertRow2(table, ["Year", dbe.year]); + if (grp == DBT_GAME) + insertRow2(table, ["Controls", ctrl]); + if (dbe.notes.length) + insertRow2(table, ["Notes", dbe.notes]); + + div.appendChild(table); +} + +/*-----------------------------------------------------------------------*/ +/* advanced cfg */ + +function getPageElementID(pid) { + switch (pid) { + case PID_Model: return "cfg_page_model"; + case PID_CPU: return "cfg_page_cpu"; + case PID_Chipset: return "cfg_page_chipset"; + case PID_RAM: return "cfg_page_ram"; + case PID_ROM: return "cfg_page_rom"; + case PID_ROM_Info: return "cfg_page_rom_info"; + case PID_Floppy: return "cfg_page_floppy"; + case PID_Floppy_Info: return "cfg_page_floppy_info"; + case PID_Mount: return "cfg_page_mount"; + case PID_Mount_Setup: return "cfg_page_mount_setup"; + case PID_Video: return "cfg_page_video"; + case PID_Audio: return "cfg_page_audio"; + case PID_Ports: return "cfg_page_ports"; + } +} +function changePage(pid) { + if (page != PID_None && page == pid) + return; + if (page != PID_None) { + if (page == PID_ROM_Info && romNum != -1) + closeRomInfo(); + else if (page == PID_Floppy_Info && floppyNum != -1) + floppyCloseInfo(); + else if (page == PID_Mount_Setup && mountConfigNum != -1) + mountCloseSetup(false); + + var id = getPageElementID(page); + styleDisplayBlock(id, false); + } + page = pid; + if (page != PID_None) { + var id = getPageElementID(page); + styleDisplayBlock(id, true); + } +} + +/*---------------------------------*/ + +function selectModel() { + var v = getRadio("cfg_model", true); + if (v === false) + alert("Please select a model."); + else { + var model, modelConfig = 0; + var e = document.getElementById("cfg_model_select"); + e.disabled = "disabled"; + e.innerHTML = "DONE"; + + switch (v) { + case "A500": model = SAEC_Model_A500; modelConfig = getSelect("cfg_model_a500"); break; + case "A500P": model = SAEC_Model_A500P; modelConfig = getSelect("cfg_model_a500p"); break; + case "A600": model = SAEC_Model_A600; modelConfig = getSelect("cfg_model_a600"); break; + case "A1000": model = SAEC_Model_A1000; modelConfig = getSelect("cfg_model_a1000"); break; + case "A1200": model = SAEC_Model_A1200; modelConfig = getSelect("cfg_model_a1200"); break; + case "A2000": model = SAEC_Model_A2000; break; + case "A3000": model = SAEC_Model_A3000; break; + case "A4000": model = SAEC_Model_A4000; break; + //case "A4000T": model = SAEC_Model_A4000T; break; + //case "CDTV": model = SAEC_Model_CDTV; break; modelConfig = getSelect("cfg_model_cdtv"); break; + //case "CD32": model = SAEC_Model_CD32; break; + default: return; + } + sae.setModel(model, modelConfig); + setAdvandedConfig(); + setTimeout(selectModelDone, 250); + } +} +function selectModelUpdate(model) { + setRadio("cfg_model", model); +} +function selectModelDone() { + var e = document.getElementById("cfg_model_select"); + e.disabled = ""; + e.innerHTML = "Set"; +} + +/*---------------------------------*/ + +function featuresUpdate() { + var manual = getSelect("cfg_chipset_features", true) == "manual"; + styleDisplayBlock("cfg_chipset_features_grp", manual); +} + +function immediateUpdate(imm) { + if (imm) { + setSelect("cfg_blitter_waiting", 0); + setDisabled("cfg_blitter_waiting", true); + } else + setDisabled("cfg_blitter_waiting", false); +} + +/*---------------------------------*/ + +function romUpdate() { + var aros = getCheckbox("cfg_rom_use_aros"); + + styleDisplayBlock("cfg_rom_grp", aros ? false : true); + if (!aros) { + cfg.memory.rom.clr(); + cfg.memory.extRom.clr(); + cfg.memory.romKey.clr(); + cfg.memory.amaxRom.clr(); + + setRomName(); + setExtName(); + setKeyName(); + setAMaxName(); + } +} + +function getRomType(ri) { + var type = ""; + + if (ri.type & SAEC_RomType_ALL_KICK) + type = "Kickstart"; + else if (ri.type & SAEC_RomType_ALL_EXT) + type = "Extended"; + else if (ri.type & SAEC_RomType_ALL_CART) + type = "Cartridge"; + else if (ri.type & SAEC_RomType_KEY) + type = "Keyfile"; + else if (ri.type & SAEC_RomType_AMAX) + type = "Macintosh"; + + return type; +} + +function openRomInfo(ri) { + const NA = "<na>"; + const NONE = "<none>"; + function span(cn, str) { + return ''+str+''; + } + //sprintf("%08X%08X%08X%08X%08X", ri.sha1[0], ri.sha1[1], ri.sha1[2], ri.sha1[3], ri.sha1[4]) + var isKey = (ri.type & SAEC_RomType_KEY) != 0; + + if (isKey) { + //setText2("cfg_rom_info_name", ri.name); + setText2("cfg_rom_info_models", "All"); + + setText2("cfg_rom_info_size", sprintf("%d (%dK)", ri.size, ri.size >> 10)); + setText2("cfg_rom_info_crc32", sprintf("%08X", ri.crc32)); + + setText2("cfg_rom_info_checksum", span("gray", NA)); + + setText2("cfg_rom_info_version", span("gray", NA)); + setText2("cfg_rom_info_encrytion", "Cloanto"); + + setText2("cfg_rom_info_type", getRomType(ri)); + setText2("cfg_rom_info_cpu", span("gray", NA)); + + setText2("cfg_rom_info_partnumber", span("gray", NA)); + } else { + var cpu = String(ri.cpu); + if (ri.cpu == 68020 && ri.addressSpace24) + cpu = "68EC020"; + else if (ri.cpu == 68000) + cpu = "All"; + else { + if (ri.cpuExact) + cpu += " only"; + else + cpu += " minimum"; + if (!ri.addressSpace24) + cpu += " / 32bit"; + } + //setText2("cfg_rom_info_name", ri.name); + setText2("cfg_rom_info_models", ri.models); + + setText2("cfg_rom_info_size", sprintf("%d (%dK)", ri.size, ri.size >> 10)); + setText2("cfg_rom_info_crc32", sprintf("%08X", ri.crc32)); + + if (ri.checksum !== false) + setText2("cfg_rom_info_checksum", sprintf("%08X (%s)", ri.checksum, ri.checksumValid ? span("green", "valid") : span("orange", "invalid"))); + else + setText2("cfg_rom_info_checksum", span("gray", NA)); + + if (ri.type & SAEC_RomType_AMAX) + setText2("cfg_rom_info_version", sprintf("%03x %04x %04x", ri.ver, ri.rev, ri.subVer)); + else if (ri.type & SAEC_RomType_ALL_KICK) + setText2("cfg_rom_info_version", sprintf("%d.%d (exec.library %d.%d)", ri.ver, ri.rev, ri.subVer, ri.subRev)); + else + setText2("cfg_rom_info_version", sprintf("%d.%d (%d.%d)", ri.ver, ri.rev, ri.subVer, ri.subRev)); + + setText2("cfg_rom_info_encrytion", ri.cloanto ? "Cloanto" : span("gray", NONE)); + + setText2("cfg_rom_info_type", getRomType(ri)); + setText2("cfg_rom_info_cpu", cpu); + + setText2("cfg_rom_info_partnumber", ri.partNumber.length ? ri.partNumber : span("gray", NA)); + } + romNum = 0; + freezeButtons(true, false); + changePage(PID_ROM_Info); +} +function closeRomInfo() { + romNum = -1; + changePage(PID_ROM); + freezeButtons(false, false); } function romSelect() { - var e = document.getElementById('cfg_rom_file').files[0]; - if (!e) return; - if (!(e.size == 0x40000 || e.size == 0x80000)) { - alert('Invalid rom-size, 256 or 512kb.'); - return; - } - loadLocal(e, function (event) { - /* - document.getElementById('cfg_rom_aros').style.visibility = 'visible'; - document.getElementById('cfg_rom_aros').innerHTML = 'Set AROS'; - disabled('cfg_rom_aros', 0);*/ - config.rom.name = e.name; - config.rom.size = e.size == 0x40000 ? SAEV_Config_ROM_Size_256K : SAEV_Config_ROM_Size_512K; - config.rom.data = event.target.result; - setRomName(config.rom.name); - }); -} + var e = document.getElementById("cfg_rom_file").files[0]; + if (e) { + loadFile(e, function (event) { + //cfg.memory.rom.path = e.path; + cfg.memory.rom.name = e.name; + cfg.memory.rom.data = event.target.result; + cfg.memory.rom.size = e.size; + cfg.memory.rom.crc32 = crc32(event.target.result); -function extSelect() { - var e = document.getElementById('cfg_ext_file').files[0]; - if (!e) return; - if (!(e.size == 0x40000 || e.size == 0x80000)) { - alert('Invalid extended rom-size, 256 or 512kb.'); - return; + defRomInfo = new SAEO_RomInfo(); + var err = sae.getRomInfo(defRomInfo, cfg.memory.rom); + if (err == SAEE_None) { + defRomEncrypted = defRomInfo.cloanto; + if (!(defRomInfo.type & SAEC_RomType_ALL_KICK)) + alert("A 'Kickstart'-ROM is required, but you selected a/an '"+getRomType(defRomInfo)+"'-ROM."); + } else { + defRomInfo = null; + if (err != SAEE_Memory_RomUnknown) { + if (err == SAEE_Memory_RomKey || err == SAEE_Memory_RomDecode) { + defRomEncrypted = true; + setKeyName(); + if (err == SAEE_Memory_RomDecode) + alert(saee2text(err)); + } + } + } + setRomName(); + }); } - loadLocal(e, function (event) { - /*document.getElementById('cfg_rom_aros').style.visibility = 'visible'; - document.getElementById('cfg_rom_aros').innerHTML = 'Set AROS'; - disabled('cfg_rom_aros', 0);*/ - config.ext.name = e.name; - config.ext.size = e.size == 0x40000 ? SAEV_Config_EXT_Size_256K : SAEV_Config_EXT_Size_512K; - config.ext.data = event.target.result; - setExtName(config.ext.name); - styleDisplayInline('cfg_ext_remove', 1); - styleDisplayTableRow('cfg_ext_addr_grp', 1); - }); -} - -function extRemove() { - /*document.getElementById('cfg_rom_aros').style.visibility = 'visible'; - document.getElementById('cfg_rom_aros').innerHTML = 'Set AROS'; - disabled('cfg_rom_aros', 0);*/ - config.ext.name = null; - config.ext.size = SAEV_Config_EXT_Size_None; - config.ext.data = null; - setExtName(config.ext.name); - styleDisplayInline('cfg_ext_remove', 0); - styleDisplayTableRow('cfg_ext_addr_grp', 0); +} +function romRemove() { + cfg.memory.rom.clr(); + setRomName(); + if (defRomEncrypted) { + defRomEncrypted = false; + setKeyName(); + } +} +function romOpenInfo() { + if (defRomInfo !== null) + openRomInfo(defRomInfo); } -function floppyUpdate(n) { - if (document.getElementById('cfg_df'+n+'_enabled').checked) { - styleDisplayInline('cfg_df'+n+'_grp', 1); - - var e = document.getElementById('cfg_df'+n+'_type'); - config.floppy.drive[n].type = parseInt(getSelectValue(e)); - floppyEject(n); - } else { - styleDisplayInline('cfg_df'+n+'_grp', 0); - floppyEject(n); - config.floppy.drive[n].type = SAEV_Config_Floppy_Type_None; +function extSelect() { + var e = document.getElementById("cfg_ext_file").files[0]; + if (e) { + loadFile(e, function (event) { + //cfg.memory.extRom.path = e.path; + cfg.memory.extRom.name = e.name; + cfg.memory.extRom.data = event.target.result; + cfg.memory.extRom.size = e.size; + cfg.memory.extRom.crc32 = crc32(event.target.result); + + extRomInfo = new SAEO_RomInfo(); + var err = sae.getRomInfo(extRomInfo, cfg.memory.extRom); + if (err == SAEE_None) { + extRomEncrypted = extRomInfo.cloanto; + if (!(extRomInfo.type & SAEC_RomType_ALL_EXT)) + alert("A 'Extended'-ROM is required, but you selected a/an '"+getRomType(extRomInfo)+"'-ROM."); + } else { + extRomInfo = null; + if (err != SAEE_Memory_RomUnknown) { + if (err == SAEE_Memory_RomKey || err == SAEE_Memory_RomDecode) { + extRomEncrypted = true; + setKeyName(); + if (err == SAEE_Memory_RomDecode) + alert(saee2text(err)); + } + } + } + setExtName(); + }); } } +function extRemove() { + cfg.memory.extRom.clr(); + setExtName(); + if (extRomEncrypted) { + extRomEncrypted = false; + setKeyName(); + } +} +function extOpenInfo() { + if (extRomInfo !== null) + openRomInfo(extRomInfo); +} + +function keySelect() { + var e = document.getElementById("cfg_key_file").files[0]; + if (e) { + loadFile(e, function (event) { + //cfg.memory.romKey.path = e.path; + cfg.memory.romKey.name = e.name; + cfg.memory.romKey.data = event.target.result; + cfg.memory.romKey.size = e.size; + cfg.memory.romKey.crc32 = crc32(event.target.result); + + romKeyInfo = new SAEO_RomInfo(); + var err = sae.getRomInfo(romKeyInfo, cfg.memory.romKey); + if (err != SAEE_None) + romKeyInfo = null; + + setKeyName(); + + if (cfg.memory.rom.size && defRomEncrypted) { + defRomInfo = new SAEO_RomInfo(); + var err = sae.getRomInfo(defRomInfo, cfg.memory.rom); + if (err != SAEE_None) { + defRomInfo = null; + if (err != SAEE_Memory_RomUnknown) + alert(saee2text(err)); + } + setRomName(); + } + if (cfg.memory.extRom.size && extRomEncrypted) { + extRomInfo = new SAEO_RomInfo(); + var err = sae.getRomInfo(extRomInfo, cfg.memory.extRom); + if (err != SAEE_None) { + extRomInfo = null; + if (err != SAEE_Memory_RomUnknown) + alert(saee2text(err)); + } + setExtName(); + } + }); + } +} +function keyRemove() { + cfg.memory.romKey.clr(); + setKeyName(); + + if (defRomInfo !== null && defRomEncrypted) { + defRomInfo = null; + setRomName(); + } + if (extRomInfo !== null && extRomEncrypted) { + extRomInfo = null; + setExtName(); + } +} +function keyOpenInfo() { + if (romKeyInfo !== null) + openRomInfo(romKeyInfo); +} + +function amaxSelect() { + var e = document.getElementById("cfg_amax_file").files[0]; + if (e) { + loadFile(e, function (event) { + //cfg.memory.amaxRom.path = e.path; + cfg.memory.amaxRom.name = e.name; + cfg.memory.amaxRom.data = event.target.result; + cfg.memory.amaxRom.size = e.size; + cfg.memory.amaxRom.crc32 = crc32(event.target.result); + + amaxInfo = new SAEO_RomInfo(); + var err = sae.getRomInfo(amaxInfo, cfg.memory.amaxRom); + if (err == SAEE_None) { + if (!(amaxInfo.type & SAEC_RomType_AMAX)) + alert("A 'Macintosh'-ROM is required, but you selected a/an '"+getRomType(amaxInfo)+"'-ROM."); + } else + amaxInfo = null; + + setAMaxName(); + }); + } +} +function amaxRemove() { + cfg.memory.amaxRom.clr(); + amaxInfo = null; + setAMaxName(); +} +function amaxOpenInfo() { + if (amaxInfo !== null) + openRomInfo(amaxInfo); +} + +/*---------------------------------*/ + +function floppyEnable(n) { + if (getCheckbox("cfg_df"+n+"_enabled")) { + styleDisplayInline("cfg_df"+n+"_grp", 1); + cfg.floppy.drive[n].type = getSelect("cfg_df"+n+"_type"); + cfg.floppy.drive[n].file.prot = getCheckbox("cfg_df"+n+"_wp"); + } else { + styleDisplayInline("cfg_df"+n+"_grp", 0); + cfg.floppy.drive[n].type = SAEC_Config_Floppy_Type_None; + cfg.floppy.drive[n].file.prot = false; + } + floppyEject(n); +} + +function floppyIsUsed(n) { + return ( + cfg.floppy.drive[n].type != SAEC_Config_Floppy_Type_None && + cfg.floppy.drive[n].file.size + ); +} +function floppyWaitSelect() { + var s = cache.state(); + if (s == S_VALID) { /* all files are downloaded or cached, go! */ + for (var n = 0; n < 4; n++) { + if (floppyIsUsed(n)) + setFloppyName(n); + } + freezeButtons(false, false); + } + else if (s == S_PENDING) { /* files are still downloading, wait... */ + setTimeout(floppyWaitSelect, 250); + } + else /*if (s == S_ERROR)*/ { /* XMLHttpRequest-error */ + for (var n = 0; n < 4; n++) { + if (cfg.floppy.drive[n].type == SAEC_Config_Floppy_Type_None) + floppyEject(n); + } + freezeButtons(false, false); + } +} +function floppySelect(grp) { + var id = DB_IDS[1][grp - 1]; + var url = DB_URLS[grp - 1]; + var num = getSelect(id); + var dbe = db[num - 1]; + + for (var n = 0; n < 4; n++) { + if (floppyIsUsed(n)) + floppyEject(n); + } + for (n = 0; n < dbe.numdisks; n++) { + if (cfg.floppy.drive[n].type == SAEC_Config_Floppy_Type_None) { + setCheckbox("cfg_df"+n+"_enabled", true); + floppyEnable(n); + } + + var filename = getDatabaseEntryFilename(dbe, n, true); + cfg.floppy.drive[n].type = SAEC_Config_Floppy_Type_35_DD; + cache.req(url, filename, 0xdc000, false, cfg.floppy.drive[n].file); + + var e = document.getElementById("cfg_df"+n+"_name"); + e.className = "orange"; + e.innerHTML = "<Downloading, please wait...>"; + } + cfg.floppy.speed = (dbe.flags & DBF_NOT) == 0 ? SAEC_Config_Floppy_Speed_Turbo : SAEC_Config_Floppy_Speed_Original; + setSelect("cfg_floppy_speed", cfg.floppy.speed); + + setSelect(id, 0); + freezeButtons(true, false); + floppyWaitSelect(); +} function floppyInsert(n) { - var e = document.getElementById('cfg_df'+n+'_file').files[0]; - var ok = true; //false; - - if (!e) return; - /*if (e.size == 0xDC000) { - if (AMIGA.config.floppy.drive[n].type == SAEV_Config_Floppy_Type_35_DD) - ok = true; - else - alert('DF'+n+' is configured as HD-drive (1760kb), but you selected a DD-diskimage (880kb).'); - } - else if (e.size == 0x1B8000) { - if (AMIGA.config.floppy.drive[n].type == SAEV_Config_Floppy_Type_35_HD) - ok = true; - else - alert('DF'+n+' is configured as DD-drive (880kb), but you selected a HD-diskimage (1760kb).'); - } else - alert('Invalid diskimage-size, 880 or 1460 kb.'); - */ - - if (ok) - loadLocal(e, function (event) { - config.floppy.drive[n].name = e.name; - config.floppy.drive[n].data = event.target.result; - setFloppyName(n, config.floppy.drive[n].name); - styleDisplayInline('cfg_df'+n+'_eject', 1); + var e = document.getElementById("cfg_df"+n+"_file").files[0]; + if (e) { + loadFile(e, function(event) { + var file = cfg.floppy.drive[n].file; + //file.path = e.path; + file.name = e.name; + file.data = event.target.result; + file.size = e.size; + file.crc32 = crc32(event.target.result); + setFloppyName(n); }); + } } function floppyEject(n) { - config.floppy.drive[n].name = null; - config.floppy.drive[n].data = null; - setFloppyName(n, null); - styleDisplayInline('cfg_df'+n+'_eject', 0); + cfg.floppy.drive[n].file.clr(); + setFloppyName(n); + document.getElementById("cfg_df"+n+"_file").value = ""; } -function audioUpdate() { - styleDisplayTable('cfg_audio_grp', document.getElementById('cfg_audio_enabled').checked); +/*function floppyInfo(n) { + var file = cfg.floppy.drive[n].file; + if (file.size != 0) { + var di = sae.info(n); + var txt = ""; + var i, j; + + //txt += "Disk is: " + (di.unreadable ? "Unreadable" : "Ready") + "\n"; + txt += "Label: " + (di.diskname.length ? "'"+di.diskname+"'" : "") + "\n"; + txt += "Disksize: " + String(file.size) + " ("+String(file.size >> 10)+"K)\n"; + txt += "Disktype: " + (di.hd ? "High Density (HD)" : "Double Density (DD)") + "\n"; + txt += "Bootblock checksum: " + (di.bootblockChecksumValid ? "Valid" : "Invalid") + "\n"; + txt += "Bootblock type: " + (di.bootblockType == 0 ? "Custom" : (di.bootblockType == 1 ? "Standard 1.x" : "Standard 2.x+")) + "\n"; + txt += sprintf("CRC32: 0x%08x\n", di.crc32); + txt += "\n"; + txt += "Press F12 if you want to see the bootblock in the developer-console..."; + + var bb = "Bootblock of '"+file.name+"' in DF"+String(n)+":\n"; + for (j = 0; j < 32; j++) { + for (i = 0; i < 32; i++) { + var chr = di.bootblock[j * 32 + i]; + bb += sprintf("%02X", chr); + } + bb += " "; + for (i = 0; i < 32; i++) { + var chr = di.bootblock[j * 32 + i]; + if (chr >= 32 && chr <= 126) + bb += String.fromCharCode(chr); + else + bb += "."; + } + bb += "\n"; + } + console.log(bb); + + alert(txt); + } +}*/ + +function floppyOpenInfo(n) { + const NA = "<na>"; + function span(cn, str) { + return ''+str+''; + } + var file = cfg.floppy.drive[n].file; + var di = new SAEO_DiskInfo(); + var err = sae.getDiskInfo(di, n); + if (err != SAEE_None) + alert(saee2text(err)); + + floppyNum = n; + + setText2("cfg_floppy_info_label", di.diskname.length ? di.diskname : span("gray", NA)); + setText2("cfg_floppy_info_size", sprintf("%d (%dK)", file.size, file.size >> 10)); + setText2("cfg_floppy_info_disktype", di.hd ? "High Density (HD)" : "Double Density (DD)"); + + if (di.bootblockChecksum !== false && di.bootblockChecksum !== 0) + setText2("cfg_floppy_info_checksum", sprintf("%08X (%s)", di.bootblockChecksum, di.bootblockChecksumValid ? span("green", "valid") : span("orange", "invalid"))); + else + setText2("cfg_floppy_info_checksum", span("gray", NA)); + + setText2("cfg_floppy_info_boottype", di.bootblockType == 0 ? "Custom" : (di.bootblockType == 1 ? span("green", "Standard 1.x") : span("green", "Standard 2.x+"))); + setText2("cfg_floppy_info_crc32", sprintf("%08X", di.crc32)); + + var bb = ""; + for (j = 0; j < 42; j++) { + for (i = 0; i < 24; i++) { + var chr = di.bootblock[j * 24 + i]; + bb += sprintf("%02X", chr); + } + bb += " "; + for (i = 0; i < 24; i++) { + var chr = di.bootblock[j * 24 + i]; + if (chr >= 32 && chr <= 126) + bb += String.fromCharCode(chr); + else + bb += "."; + } + bb += "\n"; + } + setText("cfg_floppy_info_bootblock", bb); + if (inf.browser.id != SAEC_Info_Brower_ID_Chrome) + document.getElementById("cfg_floppy_info_bootblock").style.fontSize = "12px"; + + freezeButtons(true, false); + changePage(PID_Floppy_Info); } -function videoUpdate() { - styleDisplayBlock('cfg_video_grp', document.getElementById('cfg_video_enabled').checked); +function floppyCloseInfo() { + floppyNum = -1; + changePage(PID_Floppy); + freezeButtons(false, false); } -function spritesUpdate() { - styleDisplayInline('cfg_chipset_cl_grp', document.getElementById('cfg_chipset_cl_enabled').checked); +function floppyUpdate() { + var v = getSelect("fc_type"); + var dis = v > SAEC_Disk_Create_Type_35_HD; + if (dis) { + document.getElementById("fc_label").value = ""; + setCheckbox("fc_ffs", false); + setCheckbox("fc_bootable", false); + } + setDisabled("fc_label", dis); + setDisabled("fc_ffs", dis); + setDisabled("fc_bootable", dis); +} +function floppyCreate(mode) { + var n = getSelect("fc_unit"); + var type = getSelect("fc_type"); + var label = document.getElementById("fc_label").value; + var ffs = getCheckbox("fc_ffs"); + var bootable = getCheckbox("fc_bootable"); + + var name = label.length ? label : "empty"+String(n); + name = name.split(' ').join('_'); + name = name.toLowerCase(); + name += (type == SAEC_Disk_Create_Type_35_DD_PC || type == SAEC_Disk_Create_Type_35_HD_PC ? ".img" : ".adf"); + + if (sae.createDisk(n, name, mode, type, label, ffs, bootable) == SAEE_None) + setAdvandedFloppy(n); } -function keyboradUpdate() { - styleDisplayBlock('cfg_keyborad_grp', document.getElementById('cfg_keyborad_enabled').checked); +/*---------------------------------*/ + +function mountEnable(n) { + var ci = cfg.mount.config[n].ci; + if (getCheckbox("cfg_mount_"+n+"_enabled")) { + SAER.setMountInfoDefaults(n); + + if (n < 4) { + ci.controller_type = SAEC_Config_Mount_Controller_Type_MB_IDE; + ci.controller_unit = n; + setSelect("cfg_mount_"+n+"_controller_media", ci.controller_media_type); + setSelect("cfg_mount_"+n+"_controller_level", ci.unit_feature_level); + } else if (n == 4) { + ci.controller_type = SAEC_Config_Mount_Controller_Type_PCMCIA_SRAM; + ci.controller_unit = 0; + } else { + ci.controller_type = SAEC_Config_Mount_Controller_Type_PCMCIA_IDE; + ci.controller_unit = 0; + } + setMountName(n); + styleDisplayInline("cfg_mount_"+n+"_grp", 1); + } else { + ci.controller_type = 0; + mountRemove(n); + styleDisplayInline("cfg_mount_"+n+"_grp", 0); + } + //setAdvandedMount(n); } -function portUpdate(n) { - var v = document.getElementById('cfg_ports_'+n+'_enabled').checked; - styleDisplayInline('cfg_ports_'+n+'_grp', v); - if (n == 0) { - if (v) - portUpdate2(); - else - styleDisplayInline('cfg_ports_0_grp2', 0); +function mountSelect(n) { + var e = document.getElementById("cfg_mount_"+n+"_file").files[0]; + if (e) { + loadFile(e, function(event) { + var ci = cfg.mount.config[n].ci; + + var ok = true; + if (e.size < 512) { + alert("The selected hard-file is too small. (512 bytes minimum)") + ok = false; + } + if (ci.controller_type == SAEC_Config_Mount_Controller_Type_PCMCIA_SRAM && e.size > 4 * 1024 * 1024) { + alert("The selected hard-file is too large for a PCMCIA SRAM-card. (4096K maximum)") + ok = false; + } + if (ok) { + ci.file.name = e.name; + ci.file.data = event.target.result; + ci.file.size = e.size; + ci.file.crc32 = false; + + if (n < 4) { + var haveRDB = ci.file.data.substr(0, 4) == "RDSK"; + if (haveRDB) + ;//queryRDB(ci); + else { + var blocks = Math.floor(ci.file.size / ci.blocksize); + ci.highcyl = Math.floor(blocks / (ci.surfaces * ci.sectors)); + ci.devname = "IDE"+String(n); + } + setDisabled("cfg_mount_"+n+"_setup", haveRDB); + } + setMountName(n); + } else + document.getElementById("cfg_mount_"+n+"_file").value = ""; + }); } } -function portUpdate2() { - var e = document.getElementById('cfg_ports_0'); - var v = parseInt(getSelectValue(e)); - styleDisplayInline('cfg_ports_0_grp2', v == 2); + +function mountRemove(n) { + cfg.mount.config[n].ci.file.clr(); + setMountName(n); + document.getElementById("cfg_mount_"+n+"_file").value = ""; +} + +function mountOpenSetup(n) { + mountConfigNum = n; + var ci = cfg.mount.config[n].ci; + setText("cfg_mount_surfaces", ci.surfaces); + setText("cfg_mount_sectors", ci.sectors); + setText("cfg_mount_blocksize", ci.blocksize); + //setText("cfg_mount_highcyl", ci.highcyl); + setText("cfg_mount_reserved", ci.reserved); + setText("cfg_mount_bootpri", ci.bootpri); + setText("cfg_mount_devname", ci.devname); + + freezeButtons(true, false); + changePage(PID_Mount_Setup); +} + +function mountCloseSetup(use) { + if (use) { + var ci = cfg.mount.config[mountConfigNum].ci; + var surfaces = getText("cfg_mount_surfaces"); + var sectors = getText("cfg_mount_sectors"); + var blocksize = getText("cfg_mount_blocksize"); + var reserved = getText("cfg_mount_reserved"); + var bootpri = getText("cfg_mount_bootpri"); + var devname = getText("cfg_mount_devname", true); + + if (blocksize < 512 || blocksize > 65536 || (blocksize & 511) != 0) { + alert("'Blocksize' must be smaller or equal 65536 and a multiple of 512."); + document.getElementById("cfg_mount_blocksize").focus(); + return; + } + var blocks = Math.floor(ci.file.size / blocksize); + if (reserved >= blocks) { + alert("Number of 'Reserved'-blocks is beyond the disk-size."); + document.getElementById("cfg_mount_reserved").focus(); + return; + } + if (isNaN(bootpri)) { + alert("The value at 'Bootpri' is not a number."); + document.getElementById("cfg_mount_bootpri").focus(); + return; + } + else if (bootpri < -128 || bootpri > 127) { + alert("'Bootpri' must between -128 and 127."); + document.getElementById("cfg_mount_bootpri").focus(); + return; + } + if (devname.length == 0) { + alert("'Name' is empty."); + document.getElementById("cfg_mount_devname").focus(); + return; + } + ci.surfaces = surfaces; + ci.sectors = sectors; + ci.blocksize = blocksize; + //ci.highcyl = Math.floor(blocks / (surfaces * sectors)); + ci.reserved = reserved; + ci.bootpri = bootpri; + ci.devname = devname; + } + mountConfigNum = -1; + changePage(PID_Mount); + freezeButtons(false, false); +} + +/*---------------------------------*/ + +function videoUpdate() { + styleDisplayBlock("cfg_video_grp", getCheckbox("cfg_video_enabled")); +} +function videoUpdateAPI() { + if (getSelect("cfg_video_api") == SAEC_Config_Video_API_WebGL) { + setDisabled("cfg_video_color_mode", false); + setDisabled("cfg_video_antialias", false); + } else { + setSelect("cfg_video_color_mode", 5); + setDisabled("cfg_video_color_mode", true); + setDisabled("cfg_video_antialias", true); + } + videoUpdateCM(); +} +function videoUpdateCM() { + if (getSelect("cfg_video_color_mode") < 5) { + setDisabled("cfg_video_background", true); + setDisabled("cfg_video_alpha", true); + } else { + setDisabled("cfg_video_background", false); + setDisabled("cfg_video_alpha", false); + } +} +function videoUpdateLineMode() { + setDisabled("cfg_video_interlace", getSelect("cfg_video_linemode") == SAEC_Config_Video_VResolution_NonDouble); +} + +/*---------------------------------*/ + +function audioUpdate() { + styleDisplayBlock("cfg_audio_grp", getCheckbox("cfg_audio_enabled")); +} + +function filterUpdate() { + var v = getSelect("cfg_audio_filter"); + document.getElementById("cfg_audio_filtertype").disabled = v == 0; +} + +function channelsUpdate() { + var v = getSelect("cfg_audio_channels"); + document.getElementById("cfg_audio_separation").disabled = v == 1; + document.getElementById("cfg_audio_delay").disabled = v == 1; +} + +/*---------------------------------*/ + +function portUpdate(n) { + var v = getSelect("cfg_ports_"+n); + if (n == 0) + styleDisplayInline("cfg_ports_0_grp", v == SAEC_Config_Ports_Type_Joy0); + else + styleDisplayInline("cfg_ports_1_grp", v == SAEC_Config_Ports_Type_Joy1); } /*-----------------------------------------------------------------------*/ /* status hooks */ -function hooks_error(err, msg) { +function hook_log_error(err, msg) { stop(); - if (msg !== null) + if (msg.length) alert(msg); -} +} -function hooks_power_led(on) { - var e = document.getElementById('led_pwr'); - if (e) e.style.color = on ? '#8c8' : '#888'; +const COL_GRAY = "#888"; +const COL_GREEN = "#8C8"; +const COL_RED = "#E88"; +const COL_ORANGE = "#CC8"; + +var e_led_power = null; +var e_led_hd = null; +var e_led_df = [null,null,null,null]; +var e_led_fps = null; +var e_led_cpu = null; + +function hook_led_power(on) { + e_led_power.style.color = on ? COL_GREEN : COL_GRAY; } -function hooks_floppy_motor(unit, on) { - var e; - switch (unit) { - case 0: e = document.getElementById('led_df0'); break; - case 1: e = document.getElementById('led_df1'); break; - case 2: e = document.getElementById('led_df2'); break; - case 3: e = document.getElementById('led_df3'); break; - } - if (e) e.style.color = on ? '#8c8' : '#888'; +function hook_led_hd(rw) { + e_led_hd.style.color = rw == 1 ? COL_GREEN : (rw == 2 ? COL_RED : COL_GRAY); } -function hooks_floppy_step(unit, cyl) { - var e; - switch (unit) { - case 0: e = document.getElementById('led_df0'); break; - case 1: e = document.getElementById('led_df1'); break; - case 2: e = document.getElementById('led_df2'); break; - case 3: e = document.getElementById('led_df3'); break; +function hook_led_df(unit, dis, cyl, side, rw) { + if (dis) { + e_led_df[unit].innerHTML = "-"; + e_led_df[unit].style.color = COL_GRAY; + } else { + //e_led_df[unit].innerHTML = sprintf("%02d", cyl); + //e_led_df[unit].innerHTML = String(80 * side + cyl); + //e_led_df[unit].innerHTML = String(cyl)+"'"+String(side); + e_led_df[unit].innerHTML = String(cyl); + e_led_df[unit].style.color = rw == 1 ? COL_GREEN : (rw == 2 ? COL_RED : COL_GRAY); } - if (e) e.innerHTML = cyl; } -function hooks_fps(fps) { - var e = document.getElementById('led_fps'); - if (e) e.innerHTML = fps;//+'/'+(config.video.ntsc?'60.0':'50.0'); -} -function hooks_cpu(usage) { - var e = document.getElementById('led_cpu'); - if (e) { - e.style.color = usage <= 100 ? '#8c8' : (usage > 100 && usage < 120 ? '#cc8' : '#d88'); - e.innerHTML = usage+'%'; +function hook_led_fps(fps, paused) { + if (paused) { + e_led_fps.innerHTML = "0.0"; //"PAUSE"; + } else { + //e_led_fps.innerHTML = sprintf("%.1f", fps); + e_led_fps.innerHTML = fps.toFixed(1); } -} - + e_led_fps.style.color = COL_GRAY; +} +function hook_led_cpu(usage, paused) { + if (paused) { + e_led_cpu.innerHTML = "0%"; //"PAUSE"; + e_led_cpu.style.color = COL_GRAY; + } else { + //e_led_cpu.innerHTML = sprintf("%.0f", usage) + "%"; + e_led_cpu.innerHTML = usage.toFixed(0) + "%"; + if (usage < 90) + e_led_cpu.style.color = COL_GREEN; + else if (usage < 110) + e_led_cpu.style.color = COL_ORANGE; + else + e_led_cpu.style.color = COL_RED; + } +} + +function initHooks() { + e_led_power = document.getElementById("status_led_power"); + e_led_hd = document.getElementById("status_led_hd"); + e_led_df[0] = document.getElementById("status_led_df0"); + e_led_df[1] = document.getElementById("status_led_df1"); + e_led_df[2] = document.getElementById("status_led_df2"); + e_led_df[3] = document.getElementById("status_led_df3"); + e_led_fps = document.getElementById("status_led_fps"); + e_led_cpu = document.getElementById("status_led_cpu"); +} +function setHooks() { + cfg.hook.log.error = hook_log_error; + + cfg.hook.led.power = hook_led_power; + cfg.hook.led.hd = hook_led_hd; + cfg.hook.led.df = hook_led_df; + cfg.hook.led.fps = hook_led_fps; + cfg.hook.led.cpu = hook_led_cpu; +} + /*-----------------------------------------------------------------------*/ /* disk change */ function dskchgOpen() { if (!dskchg) { - if (mode == 0) { - var s = document.getElementById('cfg_dskchg_select'); + if (mode == MODE_Database) { + var s = document.getElementById("dskchg_select"); for (var i = 0; i < dskchgList.length; i++) { var filename = dskchgList[i]; - var e = document.createElement('option'); + var e = document.createElement("option"); e.value = filename; e.text = filename; s.add(e, null); } - styleDisplayBlock('dskchg_simple', 1); + styleDisplayBlock("dskchg_database", 1); } else - styleDisplayBlock('dskchg', 1); - + styleDisplayBlock("dskchg_advanced", 1); + dskchg = true; } else dskchgClose(); @@ -1447,88 +2579,58 @@ function dskchgOpen() { function dskchgClose() { if (dskchg) { - if (mode == 0) { - styleDisplayBlock('dskchg_simple', 0); - var s = document.getElementById('cfg_dskchg_select'); + if (mode == MODE_Database) { + styleDisplayBlock("dskchg_database", 0); + var s = document.getElementById("dskchg_select"); for (var i = s.length - 1; i > 0; i--) s.remove(i); } else - styleDisplayBlock('dskchg', 0); - + styleDisplayBlock("dskchg_advanced", 0); + dskchg = false; } } function dskchgEject() { if (dskchg) { - var n = getSelectValue(document.getElementById('cfg_dskchg_unit')); - dskchgClose(); - - SAE({cmd:'eject',unit:n}); + var n = getSelect("dskchg_unit"); + dskchgClose(); + floppyEject(n); + sae.eject(n); } } function dskchgInsert() { - if (!dskchg) return; - var n = getSelectValue(document.getElementById('cfg_dskchg_unit')); - var e = document.getElementById('cfg_dskchg_file').files[0]; - var ok = true; //false; + if (dskchg) { + var e = document.getElementById("dskchg_file").files[0]; + if (e) { + loadFile(e, function(event) { + var n = getSelect("dskchg_unit"); - if (!e) return; - /*if (e.size == 0xDC000) { - if (AMIGA.config.floppy.drive[n].type == SAEV_Config_Floppy_Type_35_DD) - ok = true; - else - alert('DF'+n+' is configured as HD-drive (1760kb), but you selected a DD-diskimage (880kb).'); - } else if (e.size == 0x1B8000) { - if (AMIGA.config.floppy.drive[n].type == SAEV_Config_Floppy_Type_35_HD) - ok = true; - else - alert('DF'+n+' is configured as DD-drive (880kb), but you selected a HD-diskimage (1760kb).'); - } else - alert('Invalid diskimage-size, 880 or 1460 kb.'); - */ - if (ok) { - loadLocal(e, function (event) { - dskchgClose(); - - setFloppyName(n, e.name); - styleDisplayInline('cfg_df'+n+'_eject', 1); - - config.floppy.drive[n].type = SAEV_Config_Floppy_Type_35_DD; - config.floppy.drive[n].name = e.name; - config.floppy.drive[n].data = event.target.result; + dskchgClose(); - /*SAE({ - cmd:'insert', - unit:n, - name:e.name, - data:event.target.result - });*/ - SAE({ - cmd:'insert', - unit:n - }); - }); - } -} - -function dskchgSelect() { - if (!dskchg) return; - var filename = getSelectValue(document.getElementById('cfg_dskchg_select')); - var url = 'http://'+window.location.hostname+'/db/' + (dbGrp == 1 ? 'games/' : 'demos/') + filename + '.adf'; - var n = 0; - - if ((config.floppy.drive[n].data = cache.loadDisk(url)) !== null) { - dskchgClose(); - config.floppy.drive[n].type = SAEV_Config_Floppy_Type_35_DD; - config.floppy.drive[n].name = filename; - - SAE({ - cmd:'insert', - unit:n - }); + cfg.floppy.drive[n].type = SAEC_Config_Floppy_Type_35_DD; + var file = cfg.floppy.drive[n].file; + //file.path = e.path; + file.name = e.name; + file.data = event.target.result; + file.size = e.size; + file.crc32 = crc32(event.target.result); + sae.insert(n); + }); + } } } +function dskchgSelect() { + if (dskchg) { + var filename = getSelect("dskchg_select", true) + ".adf"; + var n = 0; /* DF0 */ + + dskchgClose(); + + if (cache.req(dbUrl, filename, 0xdc000, false, cfg.floppy.drive[n].file)) + sae.insert(n); + } +} diff --git a/readme.htm b/readme.htm index 42b5cda..273d604 100644 --- a/readme.htm +++ b/readme.htm @@ -1,405 +1,844 @@ - - - - SAE - Scripted Amiga Emulator - - - - - -
- -
- Scripted Amiga Emulator -
-
-
    -
  • Requirements -
      -
    • A very fast computer
    • -
    • A browser capable of HTML5 with: -
        -
      • WegGL or Canvas 2D (optional)
      • -
      • WebAudio (optional)
      • -
      • FileReader (GUI)
      • -
      • Typed arrays
      • -
      -
    • -
    • A ROM: -
        -
      • Amiga Kickstart 1.0-2.05 (not included for copyright reasons)
      • -
      • AROS Kickstart (included)
      • -
      -
    • -

    • -
    • And a bunch of ADF-files to test (optional)
    • -
    -
  • -
-
    -
  • Goals -
      -
    • Make Amiga Classic Emulation available for browsers.
    • -
    • Easy integration into websites.
    • -
    • API for control from background, useful e.g. for a demo-player.
    • -
    • Browsers-plugins should not be required, just HTML5 and javascript.
    • -
    -
  • -
-
    -
  • Possible usage -
      -
    • Demo/Intro/Mod-player
    • -
    • Playing games
    • -
    • Browser benchmark
    • -
    -
  • -
-
    -
  • Usage/Hints -
      -
    • Press F11 for fullscreen. Most browsers support that.
    • -
    • If something does crash, try another memory setting or a different ROM.
      - The original kickstart (1.3) does work best.
    • -
    -
  • -
-
    -
  • Known bugs/problems -
      -
    • Blinking sprites are not shown if "Frameskip" is active.
    • -
    • There may be short and heavy speed-fluctuations in the beginning of the emulation.
    • -
    • Left/right shift/alt/ctrl are the same. That's a browser "feature" and can't be fixed.
    • -
    -
  • -
- - -
    -
  • License - -
  • -
- -
    -
  • Some stats -
      -
    • About 5 months development time for the first public version. (0.5)
    • -
    • About the half of the first version was written from scratch, the rest was ported from various UAE-sources.
    • -
    • The first version had ~13.000 lines of code, currently ~23.500, most new code is ported from WinUAE.
    • -
    -
  • -
-
    -
  • History -
      -
    • 0.8.3 (22.03.2015) -
        -
      • Audio -
          -
        • Fixed a heavy bug i added myself around v0.6-0.7 on the seek for other bugs. Big thanks to 'Ralf Sommer'.
        • -
        • Dropped usage of the ring-buffer and wrote a new and faster queue-buffer.
        • -
        • The audio-data is now first sampled at 15.65KHz and then resampled to
          - the rate of the soundcard. This does reduce internal CPU-usage.
        • -
        • Removed 'Audio/Samplerate' in the GUI, because it's no longer used.
          -
        -
      • -
      • Events -
          -
        • Fixed a bug in combination with frameskip.
        • -
        • Frameskip is now disabled by default.
        • -
        -
      • -
      • Common -
          -
        • Updated AROS-ROMs to actual version SVN50213.
        • -
        -
      • -
      -
    • -

    • -
    • 0.8.2 (10.01.2015) -
        -
      • Audio -
          -
        • Fixed 'WebAudio'-output. All other dropped. Thanks 'dmcoles'.
        • -
        • Some speed optimizations.
        • -
        -
      • -
      • CPU -
          -
        • Fixed a bug in the DIVS-function in combination with negative numbers. Thanks 'dmcoles'.
        • -
        -
      • -
      • Common -
          -
        • Removed old copyright statements in the source files. Thanks 'swinkamor12'.
        • -
        -
      • -
      -
    • -

    • -
    • 0.8.1 (19.01.2013): -
        -
      • Common -
          -
        • The license of the project is now GPL.
        • -
        • Changed and updated front-end.
        • -
        • Removed the drivers-info box. I did'nt like it that way.
        • -
        -
      • -
      -
    • -

    • -
    • 0.8.0 (16.01.2013): -
        -
      • Display -
          -
        • Ported and optimized playfield-code from WinUAE.
          - This adds ECS and AGA support and fixes graphics-errors.
          - The AGA part is commented out, because there is no 68020 yet.
        • -
        • Added support for drawing via 'Canvas 2D' if 'WebGL' is not avail.
        • -
        • Added support for auto-driver detection.
        • -
        -
      • -
      • Audio -
          -
        • While disk access, audio performance is much better now.
        • -
        • Added support for the A500 lowpass-filter. Not enabled by default.
        • -
        • Added support for auto-driver detection.
        • -
        -
      • -
      • Memory -
          -
        • To gain speed, all memory is now accessed directly and not via functions.
          - So, don't care for a possible illegal memory access.
        • -
        • Fixed bug, where kickstart 1.2 failed to load.
        • -
        • Fixed incorrect extended-address bug.
        • -
        -
      • -
      • CPU -
          -
        • Splitted address-types of ADDQ/SUBQ into separate functions for more speed.
        • -
        • Added bus-read/write cycles tables. For internal use only.
        • -
        -
      • -
      • CIA -
          -
        • I decided to port the latest cia-code from WinUAE while i was trying to find a bug.
          - Well, the bug is still there. Let's keep the code nevertheless.
        • -
        -
      • -
      • GUI -
          -
        • Added info box of supported drivers.
        • -
        • Added a 'Chipset'-section and various options.
        • -
        • Packed the main GUI.
        • -
        -
      • -
      • Common -
          -
        • Added support for easy URL sharing. E.g. to show the Multica-demo to a friend,
          - one may send the link "http://scriptedamigaemulator.net/#Multica"
          - and the demo will start immediately. (thanks mrdoob)
        • -
        • Many small optimizations.
        • -
        -
      • -
      -
    • -

    • -
    • 0.7.0 (24.12.2012): -
        -
      • Common -
          -
        • Chaned the project-name from 'Janus' to 'SAE' (Scripted Amiga Emulator).
          - This step is necessary because i did'nt enough research before the initial release.
          - There is already a project with that name in it. (janus-uae) - I'm sorry for that, that was kinda stupid :)
        • -
        • Separated the GUI form the core and rewrote most of it.
        • -
        • Simplified the whole code. This means, that functions are called faster.
        • -
        • Ported new Copper-, Blitter-, Audio-, Disk- and event-handling code from WinUAE 2.5.0
        • -
        • Moved all "beam-functions" to events.js, for faster access.
        • -
        • Added "CPU-usage" to the GUI.
        • -
        • Added "Hall of Fame".
        • -
        -
      • -
      • CPU -
          -
        • Added support for exact cycling. The CPU have now 7.09 MHz on PAL and 7.16 MHz on NTSC resp.
        • -
        • Added option for "Original"- and "Maximum"-speed.
        • -
        -
      • -
      • Audio -
          -
        • Added a ring-buffer before output. No more "bagpipe"-like audio.
        • -
        • Added a option to just emulate the hardware, but not to play any sound,
          - e.g. "Agony" was not starting, if audio was disabled.
        • -
        -
      • -
      • Display -
          -
        • Switched from the RGB to the 565 texture-format-encoding in WebGL, which gives a little more speed.
        • -
        • Added support and a option for 4x scaling.
        • -
        • Fixed screen-draging in lo-/hires-modes.
        • -
        • Added a option to disable the output. Can be used to better play music-demos.
        • -
        -
      • -
      • Disk -
          -
        • Added support for different speed-modes.
        • -
        • Added support for extended ADF-files.
        • -
        • Enabled write support. (to memory)
        • -
        -
      • -
      • Input -
          -
        • The F-keys does work normaly now, i.e F5 does'nt reload the emulator, backspace does'nt go to the last page, etc...
        • -
        • Fixed bug in the joystick-emulation.
        • -
        -
      • -
      -
    • -

    • -
    • 0.6.1 (05.11.2012): -
        -
      • CPU -
          -
        • Added missing TAS command. ('Wings of Death' game does use it)
        • -
        -
      • -
      • ROM -
          -
        • Added a crc32-checksum test after download. (AROS)
        • -
        • Changed transfer-mode from syncronous to asyncronous. (AROS)
        • -
        -
      • -
      • Display -
          -
        • Optimized the line-drawing code of the blitter.
        • -
        • Fixed decision whether the resulting image is scaled or not. ('Agony' game)
        • -
        • Disabled 'Framedrop' in interlace-mode.
        • -
        -
      • -
      • Misc -
          -
        • Fixed HTML5 doctype.
        • -
        • Added ver/rev to the title.
        • -
        • Changed revision to 3 digits.
        • -
        -
      • -
      -
    • -

    • -
    • 0.6 (25.10.2012): -
        -
      • ROM -
          -
        • Added support for extended-roms.
        • -
        • AROS kickstart replacement is now the default-rom, and will be downloaded and used on the fly.
        • -
        -
      • -
      • RAM -
          -
        • Changed internal memory alignment from 8 to 16 bit.
        • -
        • Added fast-ram support, through a emulated Commodore A2058 in Zorro2-mode.
        • -
        • Removed the D8DC-memory-option from the GUI. This memory space is now always allocated.
        • -
        • Sorted access of the memory-routines by priority.
        • -
        -
      • -
      • CPU -
          -
        • Fixed sign-extension for memory to address-register transfers in MOVEM.
        • -
        • Fixed sign-extension for absolute-word addresses in exEA.
        • -
        • Fixed wrong address when writing a byte to the stack in ldEA.
        • -
        • Fixed 32bit calculations for address-regsiters in ADDQ/SUBQ.
        • -
        • Fixed remainder calculation in DIVU.
        • -
        • Optimized integer-arithmetic functions. Size depending calcalations are now used.
        • -
        • Improved exception 2/3 handling.
        • -
        • More small cleanups not listed here.
        • -
        -
      • -
      • Disk -
          -
        • Ported latest disk-code from WinUAE. Disk-based problems should be gone now, e.g. floopy shown as BAD or read errors.
        • -
        • Diskchange does now work.
        • -
        • Drives can be disabled now.
        • -
        • DD/HD types are now supported.
        • -
        -
      • -
      • Display -
          -
        • Added missing support for HAM6.
        • -
        • Fixed horizontal and vertical screen-centering.
        • -
        • Fixed screen-draging, almost, read the "Known bugs" section.
        • -
        • Added better screen-scrolling.
        • -
        -
      • -
      • Input -
          -
        • Fixed key-mapping to the amiga key-layout, at least in Chrome. Firefox does not like "öäü", it seems.
        • -
        • Added support for individual configurations of joystick-movement and fire-buttons.
        • -
        • Fixed bug, that made the fire 1 button on joystick 0 not working.
        • -
        • Fixed bug in the mouse-movement function, that calculates the wrong coordinates in some cases.
        • -
        -
      • -
      • GUI -
          -
        • Added eject-button in the disk-change requester.
        • -
        • Removed the CPU and OCS/ECS options. They are useless so far.
        • -
        • The "Pause" and "Resume" buttons are once now.
        • -
        • Made some options to only apear when selected.
        • -
        • Did some cosmetics.
        • -
        -
      • -
      • Misc -
          -
        • Added support for Zorro2-expansion cards.
        • -
        • Added a more precise event-handling. This makes the audio-output a little smoother.
        • -
        • Changed the ratio of CPU-/Chipset-time from 1:8 to 1:4
        • -
        • Fixed a bug in the RTC. "Year" is now calculated correctly.
        • -
        • Fixed incorrect response of serial.device. Now crashed programms does reset (and show the guru), instead of idle.
        • -
        • Any output on the serial.device is now redirected to the debug-log. (dev only)
        • -
        • Kickstart/Workbench 2.04 and AROS does now work.
        • -
        • Overall about 10-30% more speed, as long as the blitter is not used too much.
        • -
        -
      • -
      -
    • -

    • -
    • 0.5 (01.09.2012): -
        -
      • Initial.
      • -
      -
    • -
    -
  • -
-
-
- - - + + + + SAE - Scripted Amiga Emulator + + + + + +
+
+ Scripted Amiga Emulator +
+
+ +
    +
  • Goals +
      +
    • Make 'Amiga Classic' Emulation available for browsers.
    • +
    • Browser-plugins or 3rd-party scripts must not be required, just HTML5 and javascript.
    • +
    • Abstraction and API for easy integration to +
        +
      • play demos, intros or mods.
      • +
      • play games.
      • +
      • or maybe benchmark the browser.
      • +
      +
    • +
    +
  • +
+
    +
  • Requirements +
      +
    • A fast computer in general and a super-computer for (most) AGA-stuff in real-time.
    • +
    • A modern browser capable of HTML5 with: +
        +
      • WegGL/Canvas2D- and WebAudio-extensions.
      • +
      • Typed-arrays and FileReader-extension.
      • +
      • The browser should support compilation of javascript-code to native-code. (JIT)
      • +
      • The browser should be able to use multiple cpu-cores on a single thread/tab.
      • +
      • Memory-requirements are between 200MB to 1.5GB depending on configuration and browser.
      • +
      +
    • +
    • A ROM: +
        +
      • Amiga Kickstart 1.0-3.1 (not included for copyright reasons)
      • +
      • AROS Kickstart (included)
      • +
      +
    • +
    • A bunch of floppy- or hardfile-images for the advanced-mode.
    • +
    +
  • +
+
    +
  • Features (new = new in latest version 0.9.0) +
      +
    • Models +
        +
      • A1000/A1000-Velvet (new)
      • +
      • A500/A2000
      • +
      • A500+
      • +
      • A600 (new)
      • +
      • A1200 (new)
      • +
      • A3000 (partial, new)
      • +
      • A4000/030 (partial, new)
      • +
      +
    • +
    • CPUs +
        +
      • 68000
      • +
      • 68010 (new)
      • +
      • 68020/68030 (new) +
          +
        • 32-bit support.
        • +
        • Cache support.
        • +
        • Prefetch support.
        • +
        +
      • +
      • Variable speeds.
      • +
      +
    • +
    • Chipset +
        +
      • Original-Chip-Set (OCS) +
          +
        • A1000-Agnus (8361 PAL, 8367 NTSC) emulation. (new)
        • +
        +
      • +
      • Enhanced-Chip-Set (ECS) +
          +
        • Partial (Agnus/Denise only) or full emulation. (new)
        • +
        +
      • +
      • Advanced Graphics Architecture. (AGA) (new)
      • +
      • PAL/NTSC-regions.
      • +
      • Sprites-only or full collision-detection.
      • +
      • Full blitter support.
      • +
      • Full copper support.
      • +
      • Full gayle support (A600/A1200) (new) +
          +
        • IDE
        • +
        • PCMCIA
        • +
        +
      • +
      • Real-Time-Clock (RTC) types +
          +
        • MSM6242B
        • +
        • RF5C01A
        • +
        +
      • +
      • Complex-Interlace-Adapter (CIA): +
          +
        • Different Time-Of-Day (TOD) sources. (Vertical Sync/Power Supply) (new)
        • +
        • ROM overlay emulation. (maps ROM from e.g. 0xf80000 to 0x000000 at reset) (new)
        • +
        • A1000 Velvet prototype CIA (6526) emulation. (new)
        • +
        +
      • +
      +
    • +
    • RAM +
        +
      • 256-2048K Chip-ram. (0x000000)
      • +
      • Up to 1536K Slow-/Bogo-ram. (0xC00000)
      • +
      • Up to 64M onboard Fast-ram for A3000/A4000. (new)
      • +
      • Up to 8M Zorro2 expansion Fast-ram. (0x200000)
      • +
      • Up to 8M Zorro3 Chip-ram. (new)
      • +
      • Up to 1024M (1G) Zorro3 expansion Fast-ram. (new)
      • +
      • 512K Chip-/512K Bogo-ram to 1024K Chip-ram aliasing. (new)
      • +
      • 24-/32-bit support. (32-bit memory is required for original A3000/4000-roms and emulation) (new)
      • +
      +
    • +
    • ROM +
        +
      • All kinds of standard and extended kickstart roms.
      • +
      • Support for encrypted Cloanto-roms. (Amiga Forever) (new)
      • +
      • Special A1000 kickstart handling. (new)
      • +
      • ROM-patcher, which does remove unneeded resident libraries. (new)
      • +
      • ROM-mirroring. (mirrors ROM to 0xA80000 or 0xE00000) (new)
      • +
      • ShapeShifter-support. (new)
      • +
      • AMAX-support. (Mac emulator) (new)
      • +
      • ROM-info from internal database. (new)
      • +
      +
    • +
    • Floppy +
        +
      • Supported diskimage-types +
          +
        • Standard ADF, read/write (*.adf)
        • +
        • Extended ADF (EXT1/EXT2), read/write (*.adf) (new)
        • +
        • PCDOS, read/write (*.img) (new)
        • +
        • DMS (DiskMasher), read only (*.dms) (new)
        • +
        • SCP (SuperCardPro), read-only (*.scp) (new)
        • +
        • EXE, read-only (*.exe) (new)
        • +
        +
      • +
      • Up to 4 Double-/High-density drives. (DF0-DF3)
      • +
      • Variable drive-speeds. (Original-Turbo).
      • +
      • Drives are write-protectable. (new)
      • +
      • Diskimage creation feature. (new)
      • +
      +
    • +
    • Mount (new) +
        +
      • Supported hardfile-types +
          +
        • Standard, read/write (*.hdf)
        • +
        • Virtual, read/write (*.vhd)
        • +
        +
      • +
      • Up to 4 Onboard-IDE units (IDE0-IDE3) with supported ATA-modes +
          +
        • ATA 1
        • +
        • ATA 2
        • +
        • ATA 2 Strict
        • +
        +
      • +
      • PCMCIA-slots, configurable as +
          +
        • SRAM
        • +
        • HDD
        • +
        +
      • +
      • Units are write-protectable.
      • +
      +
    • +
    • Video +
        +
      • HTML5 WegGL- or Canvas2D-rendering.
      • +
      • 2/4 bits-per-pixel modes. (new)
      • +
      • Lores-/Hires-/Superhires-types.
      • +
      • Doublescan-types.
      • +
      • Frameskip. (renders every 2nd frame only)
      • +
      • Centering. (new)
      • +
      +
    • +
    • Audio +
        +
      • HTML5 WegAudio-processing.
      • +
      • Samplerates from 11025-48000 Hz.
      • +
      • Mono or Stereo.
      • +
      • Lowpass filter for A500/A1200. (A1200 new)
      • +
      • Variable Stereo-channel separation. (new)
      • +
      • Different interpolation modes (Anti, RH, Crux) (Anti new)
      • +
      +
    • +
    • Ports +
        +
      • HTML5 mouse-position and buttons import.
      • +
      • HTML5 keyboard import.
      • +
      • Joystick emulation via keyboard.
      • +
      • Mapping of some special keys for pinball-games.
      • +
      • Serial-port. (output to developer-console)
      • +
      +
    • +
    +
  • +
+
    +
  • Limits +
      +
    • CPUs +
        +
      • 68000/68010 +
          +
        • Prefetch is fake.
        • +
        • BKPT is not implemented.
        • +
        +
      • +
      • 68020 +
          +
        • CALLM/RTM is not implemented.
        • +
        • Execution-times of instruction and interrupts are not fully correct.
        • +
        +
      • +
      • 68030 +
          +
        • MMU is fake.
        • +
        • Execution-times of instruction and interrupts are not fully correct.
        • +
        +
      • +
      • Exceptions 2 and 3 are not fully implemented.
      • +
      • Traps are not fully implemented.
      • +
      +
    • +
    • Autoconf +
        +
      • Zorro2-autoconfig is limited to RAM-devices only.
      • +
      +
    • +
    • Floppy +
        +
      • No support for compressed floppy-images like ADZ.
      • +
      • No FDI-/IPF-image support.
      • +
      +
    • +
    • Mount +
        +
      • No onboard-SCSI for the A3000/4000.
      • +
      • No support for compressed hardfile-images like HDZ.
      • +
      +
    • +
    +
  • +
+
    +
  • +
+
    +
  • Usage/Hints +
      +
    • Press F11 for fullscreen. Most browsers support that.
    • +
    • If something does crash or freeze +
        +
      • Try another Amiga-model. A500+ for OCS/ECS and A1200 for AGA does work best.
      • +
      • Use the right rom. Selecting a wrong rom may freeze the emulation. If possible use original kickstart-roms.
      • +
      • If you are using original A3000/4000 kickstart-roms, make sure to enable "32bit address-space" in the CPU-page.
      • +
      • If you are using the AROS kickstart-replacement, you should also give some fast-ram.
      • +
      • Try to enable "Compatible" in the CPU-page.
      • +
      • Try another memory setting or give more memory.
      • +
      • Try to set the floppy-speed back to 1x. Some stuff does not load if "Turbo" is selected.
      • +
      +
    • +
    • If hardfiles did not get recognized +
        +
      • Select an A600/A1200 at the "Defaults"-page.
      • +
      • Or, go to "Chipset/Features/Manual" and select "Onboard-IDE" or "PCMCIA-slot" manually.
      • +
      +
    • +
    +
  • +
+
    +
  • Safety +
      +
    • Whatever you do, you can't harm your computer or change local-files.
    • +
    • Everything is running enclosed in the memory of the browser.
    • +
    • Changes to floppy-/hardfile-images are not stored physically, but to memory only.
      + Reloading the window/tab (e.g. press F5) does reset all altered floppy-/hardfile-images and configurations.
    • +
    • No Amiga-virus (on floppy-/hardfile-images) can infect your real computer or device.
      + If you close the window/tab of SAE, all possible viruses will die peacefully.
    • +
    +
  • +
+
    +
  • Privacy +
      +
    • No files or informations about files, that you are selecting from your computer, are transferred to the internet.
      + (Note that this may not be the case for other sites, which are using this project.)
    • +
    • This site is using google-analytics for visitor-statistics. Other scripts are not used.
    • +
    +
  • +
+
    +
  • +
+
    +
  • Your game or demo +
      +
    • If you want to have your game or demo on this site, please contact me.
    • +
    • Your contribution would be published under a free license, with a link to your homepage and would be free to play for everyone.
    • +
    +
  • +
+
    +
  • +
+ +
    +
  • Thanks +
      +
    • WinUAE team, especially Toni Wilen.
    • +
    • Bernd Schmidt, the father of amiga-emulation.
    • +
    • AROS team
    • +
    • All people who contributed their games. Thanks for your support!
    • +
    +
  • +
+
    +
  • Stats +
      +
    • First public version (0.5) +
        +
      • 5 months development time.
      • +
      • About the half was written from scratch, the rest was ported from various UAE-sources.
      • +
      • ~13.000 lines of code.
      • +
      +
    • +
    • Versions (0.6 - 0.8.3) +
        +
      • Most code was ported from WinUAE 2.5.0
      • +
      • ~33.000 lines of code.
      • +
      +
    • +
    • Current version (0.9.0) +
        +
      • 3 months development time.
      • +
      • ~15% was re-written.
      • +
      • ~70% was re-ported from WinUAE 3.2.x
      • +
      • ~60.000 lines of code.
      • +
      +
    • +
    +
  • +
+
    +
  • +
+
    +
  • History +
      +
    • 0.9.0 (15.07.2016) +
        +
      • CPU +
          +
        • Completely rewrote the core.
        • +
        • Added support for the 68010. (5 instructions, 3 registers)
        • +
        • Added support for the 68020. (27 instructions, 2 registers)
        • +
        • Added support for the 68030. (4 instructions)
        • +
        • Exploded each instruction to it's own size-form and sometimes additionally to it's type form.
        • +
        • For faster access, each instruction does now have it's customized parameter-object.
        • +
        • Effective-address access and decoding are now done via 6+1 highspeed function-tables, each 64 entries long.
          + This does save up to 12 (3*2*2) switch statements per instruction.
        • +
        • Condition-code checking is now done via a 16 entries long function-table instead of a switch-function with 16 entries.
        • +
        • Optimized condition-code calculations.
        • +
        • Fixed/removed DIVU-remainder calculation, also new and faster DIVS.
        • +
        • New and faster versions of ABCD, NBCD, SBCD, ASL, ASR, LSL, LSR, ROL, ROXL, ROR, ROXR.
        • +
        • Fixed MOVEP instruction.
        • +
        • Fixed all 68000/68010 execution-time calculations.
        • +
        • Program-counter calculations are not hardcoded any more.
        • +
        • Ported high-level functions from actual WinUAE.
        • +
        +
      • +
      • General +
          +
        • Re-ported and optimized the following parts from actual WinUAE:
          + Audio, Blitter, CIA, Config, Copper, CPU-highlevel, Custom, Disk, Drawing, Events,
          + Expansion, Filesys, Gayle, Hardfile, IDE, Memory, Roms, Playfield, RTC and Serial
        • +
        +
      • +
      • Chipset +
          +
        • Custom-chip registers are now accessed via a 256 entries long function-table instead of a switch-function with 256 entries.
        • +
        • Added support for the A1000-Agnus.
        • +
        +
      • +
      • CIA +
          +
        • Added support for different TOD sources.
        • +
        • Added support for ROM overlay.
        • +
        • Added support for A1000 Velvet prototype.
        • +
        +
      • +
      • Blitter +
          +
        • Minterms are now calculated via a 256 entries long function-table instead of a switch-function with 256 entries.
        • +
        +
      • +
      • RAM +
          +
        • Added Zorro3 and 32bit support.
        • +
        • Added support for chip-/bogo-ram aliasing.
        • +
        • Access is now done via function-tables (banks) instead of area-selecting switch-functions.
        • +
        +
      • +
      • ROM +
          +
        • Added support for encrypted Cloanto-roms. (Amiga Forever)
        • +
        • Added special A1000 kickstart handling.
        • +
        • Added ROM-patcher, which does remove unneeded resident libraries.
        • +
        • Added support for ROM-mirroring.
        • +
        • Added ShapeShifter-support.
        • +
        • Added a ROM-info page.
        • +
        • Updated AROS-ROMs to actual version SVN52764.
        • +
        +
      • +
      • Floppy +
          +
        • Added 3.5" DD ESCOM and 3.5" DD/HD PC only drive-types.
        • +
        • Added support for the diskspare-format.
        • +
        • Added support for PCDOS-images.
        • +
        • Added support for DMS-images. (DiskMasher)
        • +
        • Added support for SCP-images. (SuperCardPro)
        • +
        • Added support for EXE-images.
        • +
        • Disk can now be inserted from the database.
        • +
        • Drives are now write-protectable.
        • +
        • Added a disk-info page.
        • +
        +
      • +
      • Mount +
          +
        • Added support for hardfiles. (*.hdf/*.vhd)
        • +
        • Added support for Onboard-IDE (A600/A1200)
        • +
        • Added support for PCMCIA-slots (A600/A1200)
        • +
        • Units are write-protectable.
        • +
        +
      • +
      • Playfield +
          +
        • Added AGA-support.
        • +
        • Added support for 16 bits-per-pixel (R5G6B5) rendering.
        • +
        • Got rid of an internal temp-buffer. So in WebGL-mode, we render to the texture directly now.
        • +
        • Added options for video-centering.
        • +
        +
      • +
      • Video +
          +
        • The output-driver is now selectable.
        • +
        • Added support and options for brightness, contrast and gamma.
        • +
        • Added alpha-channel support.
        • +
        • Added line-change indicator. (debug)
        • +
        +
      • +
      • Audio +
          +
        • Added "Anti"-samplehandler.
        • +
        • Added A1200 lowpass-filter.
        • +
        • Added support for stereo-channel separation.
        • +
        • Rewrote handling of WebAudio-stuff.
        • +
        +
      • +
      • Events +
          +
        • If supported by the browser, timing-functions does use performance.now() instead of Date.now(),
          + which increases the precision by the factor of 1000.
        • +
        • Optimized switching between pause/run. Thanks 'majcherek2048'.
        • +
        +
      • +
      • Input +
          +
        • Added distinction between left/right shift/alt keys. The config-entry "Map L/R-Shift to L/R-Arrows" is gone.
        • +
        +
      • +
      • Config +
          +
        • Completely reworked the advanced config page.
        • +
        • Changed all SAEV_Config_* to SAEC_Config_* to match the new namespace. Sorry for that :/
        • +
        • Many new options. Not listed here, see sae/config.js for details.
        • +
        +
      • +
      • API +
          +
        • Deprecated and removed the old API function "SAE()". We're on javascript, so let's use: (new API)
          + "var sae = new ScriptedAmigaEmulator(); [...] var error = sae.start(); [...]" See index.js for details.
        • +
        • Reworked error-handling for API-calls. Now an error-code (SAEE_*) is returned on any API-call.
        • +
        +
      • +
      • Common +
          +
        • Introduced global functions, references, variables and constants for more speed. See sae/amiga.js for details.
        • +
        • Moved all entries from constants.js to their specific place and renamed them to match the new global name-space.
        • +
        • Updated asynchronous file-transfers to latest standards.
        • +
        • Added proper GPL-header to the source-files.
        • +
        • Moved the "Your game and demo..."-section from the main-site to the readme.
        • +
        • Fixed linkage to contributors websites.
        • +
        • Added SAE-specific-links to the info-box in the main-page.
        • +
        • Added an disassembler tool.
          + "var sda = new ScriptedDisAssembler(); [...] var result = sda.disassemble();" See disass.js for details.
        • +
        +
      • +
      +
    • +

    • +
    • 0.8.3 (22.03.2015) +
        +
      • Audio +
          +
        • Fixed a heavy bug i added myself around v0.6-0.7 on the seek for other bugs. Big thanks to 'Ralf Sommer'.
        • +
        • Dropped usage of the ring-buffer and wrote a new and faster queue-buffer.
        • +
        • The audio-data is now first sampled at 15.65KHz and then resampled to
          + the rate of the soundcard. This does reduce internal CPU-usage.
        • +
        • Removed 'Audio/Samplerate' in the GUI, because it's no longer used.
          +
        +
      • +
      • Events +
          +
        • Fixed a bug in combination with frameskip.
        • +
        • Frameskip is now disabled by default.
        • +
        +
      • +
      • Common +
          +
        • Updated AROS-ROMs to actual version SVN50213.
        • +
        +
      • +
      +
    • +

    • +
    • 0.8.2 (10.01.2015) +
        +
      • Audio +
          +
        • Fixed 'WebAudio'-output. All other dropped. Thanks 'dmcoles'.
        • +
        • Some speed optimizations.
        • +
        +
      • +
      • CPU +
          +
        • Fixed a bug in the DIVS-function in combination with negative numbers. Thanks 'dmcoles'.
        • +
        +
      • +
      • Common +
          +
        • Removed old copyright statements in the source files. Thanks 'swinkamor12'.
        • +
        +
      • +
      +
    • +

    • +
    • 0.8.1 (19.01.2013): +
        +
      • Common +
          +
        • The license of the project is now GPL.
        • +
        • Changed and updated front-end.
        • +
        • Removed the drivers-info box. I did'nt like it that way.
        • +
        +
      • +
      +
    • +

    • +
    • 0.8.0 (16.01.2013): +
        +
      • Display +
          +
        • Ported and optimized playfield-code from WinUAE.
          + This adds ECS and AGA support and fixes graphics-errors.
          + The AGA part is commented out, because there is no 68020 yet.
        • +
        • Added support for drawing via 'Canvas 2D' if 'WebGL' is not avail.
        • +
        • Added support for auto-driver detection.
        • +
        +
      • +
      • Audio +
          +
        • While disk access, audio performance is much better now.
        • +
        • Added support for the A500 lowpass-filter. Not enabled by default.
        • +
        • Added support for auto-driver detection.
        • +
        +
      • +
      • Memory +
          +
        • To gain speed, all memory is now accessed directly and not via functions.
          + So, don't care for a possible illegal memory access.
        • +
        • Fixed bug, where kickstart 1.2 failed to load.
        • +
        • Fixed incorrect extended-address bug.
        • +
        +
      • +
      • CPU +
          +
        • Splitted address-types of ADDQ/SUBQ into separate functions for more speed.
        • +
        • Added bus-read/write cycles tables. For internal use only.
        • +
        +
      • +
      • CIA +
          +
        • I decided to port the latest cia-code from WinUAE while i was trying to find a bug.
          + Well, the bug is still there. Let's keep the code nevertheless.
        • +
        +
      • +
      • GUI +
          +
        • Added info box of supported drivers.
        • +
        • Added a 'Chipset'-section and various options.
        • +
        • Packed the main GUI.
        • +
        +
      • +
      • Common +
          +
        • Added support for easy URL sharing. E.g. to show the Multica-demo to a friend,
          + one may send the link "http://scriptedamigaemulator.net/#Multica"
          + and the demo will start immediately. (thanks mrdoob)
        • +
        • Many small optimizations.
        • +
        +
      • +
      +
    • +

    • +
    • 0.7.0 (24.12.2012): +
        +
      • Common +
          +
        • Chaned the project-name from 'Janus' to 'SAE' (Scripted Amiga Emulator).
          + This step is necessary because i did'nt enough research before the initial release.
          + There is already a project with that name in it. (janus-uae) + I'm sorry for that, that was kinda stupid :)
        • +
        • Separated the GUI form the core and rewrote most of it.
        • +
        • Simplified the whole code. This means, that functions are called faster.
        • +
        • Ported new Copper-, Blitter-, Audio-, Disk- and event-handling code from WinUAE 2.5.0
        • +
        • Moved all "beam-functions" to events.js, for faster access.
        • +
        • Added "CPU-usage" to the GUI.
        • +
        • Added "Hall of Fame".
        • +
        +
      • +
      • CPU +
          +
        • Added support for exact cycling. The CPU have now 7.09 MHz on PAL and 7.16 MHz on NTSC resp.
        • +
        • Added option for "Original"- and "Maximum"-speed.
        • +
        +
      • +
      • Audio +
          +
        • Added a ring-buffer before output. No more "bagpipe"-like audio.
        • +
        • Added a option to just emulate the hardware, but not to play any sound,
          + e.g. "Agony" was not starting, if audio was disabled.
        • +
        +
      • +
      • Display +
          +
        • Switched from the RGB to the 565 texture-format-encoding in WebGL, which gives a little more speed.
        • +
        • Added support and a option for 4x scaling.
        • +
        • Fixed screen-draging in lo-/hires-modes.
        • +
        • Added a option to disable the output. Can be used to better play music-demos.
        • +
        +
      • +
      • Disk +
          +
        • Added support for different speed-modes.
        • +
        • Added support for extended ADF-files.
        • +
        • Enabled write support. (to memory)
        • +
        +
      • +
      • Input +
          +
        • The F-keys does work normaly now, i.e F5 does'nt reload the emulator, backspace does'nt go to the last page, etc...
        • +
        • Fixed bug in the joystick-emulation.
        • +
        +
      • +
      +
    • +

    • +
    • 0.6.1 (05.11.2012): +
        +
      • CPU +
          +
        • Added missing TAS command. ('Wings of Death' game does use it)
        • +
        +
      • +
      • ROM +
          +
        • Added a crc32-checksum test after download. (AROS)
        • +
        • Changed transfer-mode from syncronous to asyncronous. (AROS)
        • +
        +
      • +
      • Display +
          +
        • Optimized the line-drawing code of the blitter.
        • +
        • Fixed decision whether the resulting image is scaled or not. ('Agony' game)
        • +
        • Disabled 'Framedrop' in interlace-mode.
        • +
        +
      • +
      • Misc +
          +
        • Fixed HTML5 doctype.
        • +
        • Added ver/rev to the title.
        • +
        • Changed revision to 3 digits.
        • +
        +
      • +
      +
    • +

    • +
    • 0.6 (25.10.2012): +
        +
      • ROM +
          +
        • Added support for extended-roms.
        • +
        • AROS kickstart replacement is now the default-rom, and will be downloaded and used on the fly.
        • +
        +
      • +
      • RAM +
          +
        • Changed internal memory alignment from 8 to 16 bit.
        • +
        • Added fast-ram support, through a emulated Commodore A2058 in Zorro2-mode.
        • +
        • Removed the D8DC-memory-option from the GUI. This memory space is now always allocated.
        • +
        • Sorted access of the memory-routines by priority.
        • +
        +
      • +
      • CPU +
          +
        • Fixed sign-extension for memory to address-register transfers in MOVEM.
        • +
        • Fixed sign-extension for absolute-word addresses in exEA.
        • +
        • Fixed wrong address when writing a byte to the stack in ldEA.
        • +
        • Fixed 32bit calculations for address-regsiters in ADDQ/SUBQ.
        • +
        • Fixed remainder calculation in DIVU.
        • +
        • Optimized integer-arithmetic functions. Size depending calcalations are now used.
        • +
        • Improved exception 2/3 handling.
        • +
        • More small cleanups not listed here.
        • +
        +
      • +
      • Disk +
          +
        • Ported latest disk-code from WinUAE. Disk-based problems should be gone now, e.g. floopy shown as BAD or read errors.
        • +
        • Diskchange does now work.
        • +
        • Drives can be disabled now.
        • +
        • DD/HD types are now supported.
        • +
        +
      • +
      • Display +
          +
        • Added missing support for HAM6.
        • +
        • Fixed horizontal and vertical screen-centering.
        • +
        • Fixed screen-draging, almost, read the "Known bugs" section.
        • +
        • Added better screen-scrolling.
        • +
        +
      • +
      • Input +
          +
        • Fixed key-mapping to the amiga key-layout, at least in Chrome. Firefox does not like "öäü", it seems.
        • +
        • Added support for individual configurations of joystick-movement and fire-buttons.
        • +
        • Fixed bug, that made the fire 1 button on joystick 0 not working.
        • +
        • Fixed bug in the mouse-movement function, that calculates the wrong coordinates in some cases.
        • +
        +
      • +
      • GUI +
          +
        • Added eject-button in the disk-change requester.
        • +
        • Removed the CPU and OCS/ECS options. They are useless so far.
        • +
        • The "Pause" and "Resume" buttons are once now.
        • +
        • Made some options to only apear when selected.
        • +
        • Did some cosmetics.
        • +
        +
      • +
      • Misc +
          +
        • Added support for Zorro2-expansion cards.
        • +
        • Added a more precise event-handling. This makes the audio-output a little smoother.
        • +
        • Changed the ratio of CPU-/Chipset-time from 1:8 to 1:4
        • +
        • Fixed a bug in the RTC. "Year" is now calculated correctly.
        • +
        • Fixed incorrect response of serial.device. Now crashed programms does reset (and show the guru), instead of idle.
        • +
        • Any output on the serial.device is now redirected to the debug-log. (dev only)
        • +
        • Kickstart/Workbench 2.04 and AROS does now work.
        • +
        • Overall about 10-30% more speed, as long as the blitter is not used too much.
        • +
        +
      • +
      +
    • +

    • +
    • 0.5 (01.09.2012): +
        +
      • Initial.
      • +
      +
    • +
    +
  • +
+
+
+ +
+ + + diff --git a/sae/amiga.js b/sae/amiga.js index c9c8736..ce8f860 100644 --- a/sae/amiga.js +++ b/sae/amiga.js @@ -1,426 +1,582 @@ -/************************************************************************** -* SAE - Scripted Amiga Emulator -* -* 2012-2015 Rupert Hausberger -* -* https://github.com/naTmeg/ScriptedAmigaEmulator -* -**************************************************************************/ +/*------------------------------------------------------------------------- +| SAE - Scripted Amiga Emulator +| https://github.com/naTmeg/ScriptedAmigaEmulator +| +| Copyright (C) 2012-2016 Rupert Hausberger +| +| This program is free software; you can redistribute it and/or +| modify it under the terms of the GNU General Public License +| as published by the Free Software Foundation; either version 2 +| of the License, or (at your option) any later version. +| +| This program is distributed in the hope that it will be useful, +| but WITHOUT ANY WARRANTY; without even the implied warranty of +| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +| GNU General Public License for more details. +| +| Notes on the global-namespace +| ----------------------------- +| Global object: +| function SAEO_() {} +| +| Global error constant: +| const SAEE__; +| +| Global constant: +| const SAEC__; +| +| Global variable: +| var SAEV__; +| +| Global function: +| function SAEF__() {} +| +| Global reference (pointer) to another object: +| var SAER__; +| +| +| Tags that may appear in comments (use full-word, case-sensitive text-search) +| -------------------------------- +| OWN Own code added. +| ATT Attention, possible source of error or problem. +| FIX Need to be fixed or implemented. +| OPT Need or can be optimized. +| ORG Original code, e.g. something required to be disabled. +| SECT Code section. +-------------------------------------------------------------------------*/ -function set_special(x) { AMIGA.spcflags |= x; } -function clr_special(x) { AMIGA.spcflags &= ~x; } - -function Amiga() { - this.info = { - version: SAEV_Version+'.'+SAEV_Revision+'.'+SAEV_Revision_Sub, - browser_name: BrowserDetect.browser, - browser_version: BrowserDetect.version, - os: BrowserDetect.OS, - video:0, - audio:0 - }; - this.config = new Config(); - this.mem = new Memory(); - this.expansion = new Expansion(); - this.input = new Input(); - this.serial = new Serial(); - this.events = new Events(); - this.disk = new Disk(); - this.cia = new CIA(); - this.rtc = new RTC(); - this.custom = new Custom(); - this.blitter = new Blitter(); - this.copper = new Copper(); - this.playfield = new Playfield(); - this.video = new Vide0(); - this.audio = new Audi0(); - this.cpu = new CPU(); +const SAEC_Version = 0; +const SAEC_Revision = 9; +const SAEC_Patch = 0; - this.state = ST_STOP; - this.delay = 0; - this.spcflags = 0; - //this.loading = 0; - - this.intena = 0; - this.intreq = 0; - this.dmacon = 0; - this.adkcon = 0; - - this.info.video = this.video.available; - this.info.audio = this.audio.available; - - /*---------------------------------*/ +/*---------------------------------*/ +/* errors */ - this.setup = function () { - this.mem.setup(); - this.expansion.setup(); - this.events.setup(); - this.playfield.setup(); - this.video.setup(); - this.cia.setup(); - this.rtc.setup(); - this.input.setup(); - this.disk.setup(); - this.audio.setup(); - this.custom.setup(); - this.cpu.setup(); - }; - - this.cleanup = function () { - this.audio.cleanup(); - this.video.cleanup(); - this.playfield.cleanup(); - this.input.cleanup(); - }; - - this.reset = function () { - BUG.info('Amiga.reset()'); - - this.delay = 0; - this.spcflags = 0; - //this.loading = 0; - - this.intena = 0; - this.intreq = 0; - this.dmacon = 0; - this.adkcon = 0; - - this.expansion.reset(); - this.events.reset(); - this.playfield.reset(); - this.cia.reset(); - this.disk.reset(); - this.input.reset(); - this.serial.reset(); - this.blitter.reset(); - this.copper.reset(); - this.audio.reset(); - this.custom.reset(); - this.cpu.reset(this.mem.rom.lower); - }; - - this.dump = function () { - this.cpu.dump(); - //this.cia.dump(); - }; - - /*---------------------------------*/ - - /*this.waitForStart = function() { - if (this.loading) - setTimeout('AMIGA.waitForStart()', 10); - else { - this.reset(); - this.state = ST_CYCLE; - setTimeout('AMIGA.cycle()', 0); - } - } - this.start = function() { - this.setup(); - this.waitForStart(); - }*/ - - - this.start = function () { - if (this.state == ST_STOP) { - this.setup(); - this.reset(); - this.state = ST_CYCLE; - setTimeout('AMIGA.cycle()', 0); - } - }; - - this.stop = function () { - if (this.state != ST_STOP) { - this.state = ST_STOP; - this.cleanup(); - } - }; - - this.pause = function (state) { - if (this.state != ST_STOP) { - this.state = state ? ST_PAUSE : ST_CYCLE; - this.audio.pauseResume(state); - } - }; - - /*this.insert = function(unit, name, data) { - //this.disk.insert_data(unit, data); - this.disk.insert(unit, name, data); - this.config.floppy.drive[unit].name = name; - } - this.eject = function(unit) { - if (this.config.floppy.drive[unit].name) { - this.disk.eject(unit); - //this.disk.eject_data(unit); - this.config.floppy.drive[unit].name = null; - BUG.info('amiga.eject() DF%d ejected', unit); - } else - BUG.info('amiga.eject() DF%d in empty', unit); - } - */ - - this.insert = function (unit) { - if (this.state != ST_STOP) - this.disk.insert(unit); - }; - - this.eject = function (unit) { - if (this.state != ST_STOP) - this.disk.eject(unit); - }; - - /*---------------------------------*/ - /* mainloop */ - - this.cycle = function () { - try { - this.cpu.cycle(); - } catch (e) { - if (e instanceof VSync) { - //console.log(e.error, e.message); - this.state = ST_IDLE; - } else if (e instanceof FatalError) { - this.state = ST_STOP; - this.stop(); - this.config.hooks.error(e.error, e.message); - } else /* normal exception */ { - this.state = ST_STOP; - this.stop(); - console.log(e); - } - } - if (this.state == ST_IDLE) { - this.state = ST_CYCLE; - setTimeout('AMIGA.cycle()', this.delay); - } - else if (this.state == ST_PAUSE) - AMIGA.cyclePause(); - else - AMIGA.cycleExit(); - }; - - this.cyclePause = function () { - if (this.state == ST_CYCLE) - setTimeout('AMIGA.cycle()', 0); - else if (this.state == ST_PAUSE) - setTimeout('AMIGA.cyclePause()', 500); - else - AMIGA.cycleExit(); - }; - - this.cycleExit = function () { - this.dump(); - //this.cia.dump(); - }; - - /*---------------------------------*/ - - this.dmaen = function (dmamask) { - return ((this.dmacon & DMAF_DMAEN) != 0 && (this.dmacon & dmamask) != 0); - }; - - this.DMACONR = function (hpos) { - this.playfield.decide_line(hpos); - this.playfield.decide_fetch(hpos); - this.dmacon &= ~(0x4000 | 0x2000); - var iz = this.blitter.getIntZero(); - this.dmacon |= ((iz[0] ? 0 : 0x4000) | (iz[1] ? 0x2000 : 0)); - return this.dmacon; - }; - - this.DMACON = function (v, hpos) { - var oldcon = this.dmacon; - - this.playfield.decide_line(hpos); - this.playfield.decide_fetch(hpos); - - if (v & INTF_SETCLR) - this.dmacon |= v & ~INTF_SETCLR; - else - this.dmacon &= ~v; - - this.dmacon &= 0x1fff; - - var changed = this.dmacon ^ oldcon; - - var oldcop = (oldcon & DMAF_COPEN) != 0 && (oldcon & DMAF_DMAEN) != 0; - var newcop = (this.dmacon & DMAF_COPEN) != 0 && (this.dmacon & DMAF_DMAEN) != 0; - if (oldcop != newcop) { - if (newcop && !oldcop) { - this.copper.compute_spcflag_copper(this.events.hpos()); - } else if (!newcop) { - this.copper.enabled_thisline = false; - clr_special(SPCFLAG_COPPER); - } - } - if ((this.dmacon & DMAF_BLTPRI) > (oldcon & DMAF_BLTPRI) && this.blitter.getState() != BLT_done) - set_special(SPCFLAG_BLTNASTY); - if (this.dmaen(DMAF_BLTEN) && this.blitter.getState() == BLT_init) - this.blitter.setState(BLT_work); - if ((this.dmacon & (DMAF_BLTPRI | DMAF_BLTEN | DMAF_DMAEN)) != (DMAF_BLTPRI | DMAF_BLTEN | DMAF_DMAEN)) - clr_special(SPCFLAG_BLTNASTY); - - if (changed & (DMAF_DMAEN | 0x0f)) - this.audio.state_machine(); - - if (changed & (DMAF_DMAEN | DMAF_BPLEN)) { - this.playfield.update_ddf_change(); - if (this.dmaen(DMAF_BPLEN)) - this.playfield.maybe_start_bpl_dma(hpos); - } - this.events.schedule(); - }; - - /*---------------------------------*/ - - this.ADKCONR = function () { - return this.adkcon; - }; - - this.ADKCON = function (v, hpos) { - if (this.config.audio.enabled) - this.audio.update(); - - this.disk.update(hpos); - this.disk.update_adkcon(v); - - if (v & INTF_SETCLR) - this.adkcon |= v & ~INTF_SETCLR; - else - this.adkcon &= ~v; - - this.audio.update_adkmasks(); - }; - - /*---------------------------------*/ - - this.INTENAR = function () { - return this.intena; - }; - - this.INTENA = function (v) { - if (v & INTF_SETCLR) - this.intena |= v & ~INTF_SETCLR; - else - this.intena &= ~v; - - if (v & INTF_SETCLR) - this.doint(); - }; - - /*---------------------------------*/ - - this.INTREQR = function () { - return this.intreq; - }; - - this.INTREQ_0 = function (v) { - var old = this.intreq; - - if (v & INTF_SETCLR) - this.intreq |= v & ~INTF_SETCLR; - else - this.intreq &= ~v; - - if ((v & INTF_SETCLR) && this.intreq != old) - this.doint(); - }; - - this.INTREQ = function (v) { - this.INTREQ_0(v); - this.cia.rethink(); - }; - - /*---------------------------------*/ - - this.intlev = function () { - var imask = this.intreq & this.intena; - - if (imask && (this.intena & INTF_INTEN)) { - if (imask & 0x2000) return 6; - if (imask & 0x1800) return 5; - if (imask & 0x0780) return 4; - if (imask & 0x0070) return 3; - if (imask & 0x0008) return 2; - if (imask & 0x0007) return 1; - } - return -1; - }; - - this.doint = function() { - if (AMIGA.config.cpu.compatible) - set_special(SPCFLAG_INT); - else - set_special(SPCFLAG_DOINT); - } +function SAEO_Error(err, msg) { + this.err = err; + this.msg = msg; } +SAEO_Error.prototype = new Error; + +const SAEE_None = 0; + +const SAEE_AlreadyRunning = 1; +const SAEE_NotRunning = 2; +const SAEE_NoTimer = 3; +const SAEE_NoMemory = 4; +const SAEE_Assert = 5; +const SAEE_Internal = 6; + +const SAEE_Config_Invalid = 10; + +const SAEE_CPU_Internal = 20; +const SAEE_CPU_Requires68020 = 21; +const SAEE_CPU_Requires680EC20 = 22; +const SAEE_CPU_Requires68030 = 23; +const SAEE_CPU_Requires68040 = 24; + +const SAEE_Memory_NoKickstartRom = 30; +const SAEE_Memory_NoExtendedRom = 31; +const SAEE_Memory_RomSize = 32; +const SAEE_Memory_RomKey = 33; +const SAEE_Memory_RomDecode = 34; +const SAEE_Memory_RomChecksum = 35; +const SAEE_Memory_RomUnknown = 36; + +const SAEE_Video_ElementNotFound = 40; +const SAEE_Video_RequiresCanvas = 41; +const SAEE_Video_RequiresWegGl = 42; +const SAEE_Video_ComphileShader = 43; +const SAEE_Video_LinkShader = 44; + +const SAEE_Audio_RequiresWebAudio = 50; /*-----------------------------------------------------------------------*/ -/* This API will change in the future. */ +/* global references */ -var BUG = null; -var AMIGA = null; +var SAER = null; -function SAE(x) { - try { - switch (x.cmd) { - case 'init': - BUG = new Debug(); - BUG.info('API.init() SEA %d.%d.%d', SAEV_Version, SAEV_Revision, SAEV_Revision_Sub); +/*---------------------------------*/ +/* global constants */ - AMIGA = new Amiga(); - //return AMIGA.config; - break; - case 'reset': - BUG.info('API.reset()'); - AMIGA.reset(); - break; - case 'start': - BUG.info('API.start()'); - AMIGA.start(); - break; - case 'stop': - BUG.info('API.stop()'); - AMIGA.stop(); - break; - case 'pause': - BUG.info('API.pause() %d', x.state); - AMIGA.pause(x.state); - break; - /*case 'insert': - BUG.info('API.insert() DF%d, name "%s", length %d', x.unit, x.name, x.data.length); - AMIGA.insert(x.unit, x.name, x.data); - break;*/ - case 'insert': - BUG.info('API.insert() DF%d', x.unit); - AMIGA.insert(x.unit); - break; - case 'eject': - BUG.info('API.eject() DF%d', x.unit); - AMIGA.eject(x.unit); - break; - case 'getInfo': - BUG.info('API.getInfo()'); - return AMIGA.info; - case 'getConfig': - BUG.info('API.getConfig()'); - return AMIGA.config; - /*case 'setConfig': - BUG.info('API.setConfig() size '+x.data.ext.size); - AMIGA.config = x.data; - break;*/ - } - } catch (e) { - if (e instanceof FatalError) { - AMIGA.stop(); - //return { error:e.error, message:e.message }; - AMIGA.config.hooks.error(e.error, e.message); - } else - console.log(e); +const SAEC_spcflag_STOP = 2; +const SAEC_spcflag_COPPER = 4; +const SAEC_spcflag_INT = 8; +const SAEC_spcflag_BRK = 16; +//const SAEC_spcflag_UAEINT = 32; +const SAEC_spcflag_TRACE = 64; +const SAEC_spcflag_DOTRACE = 128; +const SAEC_spcflag_DOINT = 256; +const SAEC_spcflag_BLTNASTY = 512; +//const SAEC_spcflag_EXEC = 1024; +//const SAEC_spcflag_ACTION_REPLAY = 2048; +//const SAEC_spcflag_TRAP = 4096; /* enforcer-hack */ +const SAEC_spcflag_MODE_CHANGE = 8192; +const SAEC_spcflag_CHECK = 32768; + +const SAEC_command_Quit = 1; +const SAEC_command_Reset = 2; +const SAEC_command_KeyboardReset = 3; +const SAEC_command_HardReset = 4; +const SAEC_command_Pause = 5; +const SAEC_command_Resume = 6; + +/*---------------------------------*/ + +const SAEC_Info_Brower_ID_Unknown = 0; +const SAEC_Info_Brower_ID_Chrome = 1; +const SAEC_Info_Brower_ID_Safari = 2; +const SAEC_Info_Brower_ID_Opera = 3; +const SAEC_Info_Brower_ID_Firefox = 4; +const SAEC_Info_Brower_ID_InternetExplorer = 5; + +const SAEC_info = (function() { + var info = { + browser: { + id: SAEC_Info_Brower_ID_Unknown, + name: "Unknown", + plat: "Unknown", + lang: "en" + }, + memory: { + maxSize: 0 + }, + audio: { + webAudio: false + }, + video: { + canvas: false, + webGL: false + } + }; + + /* browser */ + if (navigator.userAgent.indexOf("Chrome") > -1) { + info.browser.id = SAEC_Info_Brower_ID_Chrome; + info.browser.name = "Google Chrome"; } - //return SAEE_None; - //return { error:SAEE_None, message:'' }; - return 0; + else if (navigator.userAgent.indexOf("Safari") > -1) { + info.browser.id = SAEC_Info_Brower_ID_Safari; + info.browser.name = "Apple Safari"; + } + else if (navigator.userAgent.indexOf("Opera") > -1) { + info.browser.id = SAEC_Info_Brower_ID_Opera; + info.browser.name = "Opera"; + } + else if (navigator.userAgent.indexOf("Firefox") > -1) { + info.browser.id = SAEC_Info_Brower_ID_Firefox; + info.browser.name = "Mozilla Firefox"; + } + else if (navigator.userAgent.indexOf("MSIE") > -1) { + info.browser.id = SAEC_Info_Brower_ID_InternetExplorer; + info.browser.name = "Microsoft Internet Explorer"; + } + info.browser.plat = navigator.platform; + info.browser.lang = navigator.language; + + /* max memory */ + if (0) { + var size = 1048576; + while (true) { + try { + var data = new Uint8Array(size); + delete data; + info.memory.maxSize = size; + } catch (e) { + break; + } + size *= 2; + } + } else + info.memory.maxSize = 1073741824; //1G + + /* audio */ + var audioContext = null; + try { + var audioContextDriver = window.AudioContext || window.webkitAudioContext; + audioContext = new audioContextDriver(); + var audioProcessor = audioContext.createScriptProcessor(1024, 2, 2); + + info.audio.webAudio = true; + + if (audioContext.close) audioContext.close().then(function() {}); + audioContext = null; + } catch (e) { + if (audioContext) { + if (audioContext.close) audioContext.close().then(function() {}); + audioContext = null; + } + } + + /* video */ + var canvas = document.createElement("canvas"); + if (canvas && canvas.getContext) { + try { + var ctx = canvas.getContext("2d"); + var imageData = ctx.createImageData(16, 16); + info.video.canvas = true; + try { + const glParams = { + alpha: false, + depth: true, + stencil: false, + antialias: false, + premultipliedAlpha: false, + preserveDrawingBuffer: true, + failIfMajorPerformanceCaveat: false + }; + ctx = canvas.getContext("webgl", glParams) || canvas.getContext("experimental-webgl", glParams); + info.video.webGL = true; + } catch(e) {} + } catch(e) {} + } + + return info; +})(); + +/*---------------------------------*/ +/* global variables */ + +var SAEV_spcflags = 0; +var SAEV_command = 0; + +/*---------------------------------*/ +/* global functions */ + +function SAEF_setSpcFlags(x) { SAEV_spcflags |= x; }; +function SAEF_clrSpcFlags(x) { SAEV_spcflags &= ~x; }; + +/*---------------------------------*/ + +function SAEF_now() { + return Math.floor(performance.now() * 1000); /* micro-seconds since page-load */ +} +function SAEF_sleep(ms) { + var start = performance.now(); + while ((performance.now() - start) < ms) {} /* pretty nasty */ } +/*---------------------------------*/ +/* debug */ + +function SAEF_log() { + if (SAEV_config.debug.level >= SAEC_Config_Debug_Level_Log && arguments.length) { + var str = sprintf.apply(this, arguments); + if (console.log) console.log(str); + } +} +function SAEF_info() { + if (SAEV_config.debug.level >= SAEC_Config_Debug_Level_Info && arguments.length) { + var str = sprintf.apply(this, arguments); + if (console.info) console.info(str); + } +} +function SAEF_warn() { + if (SAEV_config.debug.level >= SAEC_Config_Debug_Level_Warn && arguments.length) { + var str = sprintf.apply(this, arguments); + if (console.warn) console.warn(str); + + } +} +function SAEF_error() { + if (SAEV_config.debug.level >= SAEC_Config_Debug_Level_Error && arguments.length) { + var str = sprintf.apply(this, arguments); + if (console.error) console.error(str); + } +} +function SAEF_fatal() { + var argumentsArray = Array.prototype.slice.call(arguments); + var err = argumentsArray[0]; + var str = sprintf.apply(this, argumentsArray.slice(1)); + if (console.error) console.error(str); + throw new SAEO_Error(err, str); +} + +function SAEF_assert(cond) { + if (!cond) { + var err = SAEE_Assert; + var str = "Assertion failed. This is a bug in SAE."; + if (console.error) console.error(str); + throw new SAEO_Error(err, str); + } +} + +/*---------------------------------*/ + +function ScriptedAmigaEmulator() { + SAER = this; + + this.autoconf = new SAEO_AutoConf(); + this.audio = new SAEO_Audio(); + this.blitter = new SAEO_Blitter(); + this.cia = new SAEO_CIA(); + this.config = new SAEO_Configuration(); + this.copper = new SAEO_Copper(); + this.cpu = new SAEO_CPU(); + this.custom = new SAEO_Custom(); + this.devices = new SAEO_Devices(); + this.disk = new SAEO_Disk(); + this.events = new SAEO_Events(); + this.expansion = new SAEO_Expansion(); + this.filesys = new SAEO_Filesys(); + this.gayle = new SAEO_Gayle(); + this.gui = new SAEO_GUI(); + this.hardfile = new SAEO_Hardfile(); + this.ide = new SAEO_IDE(); + this.input = new SAEO_Input(); + this.m68k = new SAEO_M68K(); + this.memory = new SAEO_Memory(); + this.playfield = new SAEO_Playfield(); + this.roms = new SAEO_Roms(); + this.rtc = new SAEO_RTC(); + this.serial = new SAEO_Serial(); + this.video = new SAEO_Video(); + + /*---------------------------------*/ + + this.running = false; + this.paused = false; + + /*-----------------------------------------------------------------------*/ + + this.dump = function () { + this.m68k.dump(); + //this.memory.dump(); + //this.cia.dump(); + }; + + /*-----------------------------------------------------------------------*/ + + this.do_start_program = function() { + if (SAEV_command >= 0) + SAEV_command = SAEC_command_Reset; + + this.m68k.m68k_go(true); + } + + this.do_leave_program = function() { + //sampler_free(); + this.video.cleanup(); + this.input.cleanup(); + this.disk.cleanup(); + this.audio.cleanup(); + //dump_counts(); + this.serial.cleanup(); + /*#ifdef CDTV + cdtv_free(); + cdtvcr_free(); + #endif + #ifdef CD32 + akiko_free(); + cd32_fmv_free(); + #endif*/ + //this.gui.cleanup(); //empty + //#ifdef AUTOCONFIG + this.expansion.cleanup(); + //#endif + //#ifdef FILESYS + this.filesys.cleanup(); + //#endif + this.gayle.cleanup(); + /*idecontroller_free(); + device_func_reset(); + #ifdef WITH_TOCCATA + sndboard_free(); + #endif*/ + this.memory.cleanup(); + //free_shm(); + this.autoconf.cleanup(); + } + + this.start_program = function() { + this.do_start_program(); + } + + this.leave_program = function() { + this.dump(); + this.do_leave_program(); + } + + this.pause_program = function(p) { + this.audio.pauseResume(p); + this.events.pauseResume(p); + } + + /*---------------------------------*/ + /* API */ + + this.getVersion = function(str) { + if (str) + return sprintf("%d.%d.%d", SAEC_Version, SAEC_Revision, SAEC_Patch); + else + return [SAEC_Version, SAEC_Revision, SAEC_Patch]; + } + this.getInfo = function() { + return SAEC_info; + } + this.getConfig = function() { + return SAEV_config; + } + + this.setDefaults = function() { + return this.config.setDefaults(); + } + this.setModel = function(model, config) { + return this.config.setModel(model, config); + } + + this.setMountInfoDefaults = function(num) { + var ci = SAEV_config.mount.config[num].ci; + this.filesys.uci_set_defaults(ci, false); + } + + this.start = function() { + if (SAER.running) { + SAEF_warn("sae.start() emulation already running"); + return SAEE_AlreadyRunning; + } + SAEF_info("sae.start() starting..."); + + var err; + if ((err = this.config.setup()) != SAEE_None) + return err; + if ((err = this.video.obtain()) != SAEE_None) + return err; + if ((err = this.audio.obtain()) != SAEE_None) + return err; + + this.input.setup(); //inputdevice_init(); + + if ((err = this.gui.setup()) != SAEE_None) + return err; + + /*#ifdef PICASSO96 + picasso_reset(); + #endif*/ + + //this.config.fixup_prefs(currprefs, true); + //SAEV_config.audio.mode = 0; /* force sound settings change */ + + this.memory.hardreset(2); + if ((err = this.memory.reset(true)) == SAEE_None) + { + /*#ifdef AUTOCONFIG + native2amiga_install(); + #endif*/ + this.custom.setup(); //OWN + this.blitter.setup(); //OWN + this.playfield.setup(); //custom_init(); + this.serial.setup(); + this.disk.setup(); + + this.events.reset_frame_rate_hack(); + if ((err = this.m68k.setup()) == SAEE_None) /* m68k_init() must come after reset_frame_rate_hack() */ + { + //this.gui.update(); //empty + if ((err = this.video.setup(true)) == SAEE_None) + { + if ((err = this.audio.setup()) == SAEE_None) + { + this.start_program(); + SAEF_info("sae.start() ...done"); + return SAEE_None; + } + this.video.cleanup(); + } + } + } + this.input.cleanup(); + SAEF_error("sae.start() ...error %d", err); + return err; + } + + this.stop = function() { //uae_quit() + if (this.running) { + SAEF_info("sae.stop()"); + if (SAEV_command != -SAEC_command_Quit) + SAEV_command = -SAEC_command_Quit; + + return SAEE_None; + } else { + SAEF_warn("sae.stop() emulation not running"); + return SAEE_NotRunning; + } + }; + + this.reset = function(hardreset, keyboardreset) { //uae_reset(hardreset, keyboardreset) + if (typeof hardreset == "undefined") var hardreset = 1; + if (typeof keyboardreset == "undefined") var keyboardreset = 0; + if (this.running) { + SAEF_info("sae.reset() hard %d, keyboard %d", hardreset, keyboardreset); + if (SAEV_command == 0) { + SAEV_command = -SAEC_command_Reset; + if (keyboardreset) + SAEV_command = -SAEC_command_KeyboardReset; + if (hardreset) + SAEV_command = -SAEC_command_HardReset; + } + return SAEE_None; + } else { + SAEF_warn("sae.reset() emulation not running"); + return SAEE_NotRunning; + } + }; + + this.pause = function(pause) { + if (this.running) { + if (!this.paused && pause) { + SAEF_info("sae.pause() pausing emulation"); + SAEV_command = SAEC_command_Pause; + } + else if (this.paused && !pause) { + SAEF_info("sae.pause() resuming emulation"); + SAEV_command = SAEC_command_Resume; + } + return SAEE_None; + } else { + SAEF_warn("sae.pause() emulation not running"); + return SAEE_NotRunning; + } + }; + + this.insert = function(unit) { + if (this.running) { + var file = SAEV_config.floppy.drive[unit].file; + this.disk.insert(unit, file); + SAEF_info("sae.insert() unit %d inserted, name '%s', size %d, protected %d", unit, file.name, file.size, file.prot?1:0); + return SAEE_None; + } else { + SAEF_warn("sae.insert() emulation not running"); + return SAEE_NotRunning; + } + }; + + this.eject = function(unit) { + if (this.running) { + this.disk.eject(unit); + SAEF_info("sae.eject() unit %d ejected", unit); + return SAEE_None; + } else { + SAEF_warn("sae.eject() emulation not running"); + return SAEE_NotRunning; + } + }; + + this.getRomInfo = function(ri, file) { + return this.roms.examine(ri, file); + }; + + this.getDiskInfo = function(di, unit) { + return this.disk.examine(di, unit); + }; + + this.createDisk = function(unit, name, mode, type, label, ffs, bootable) { + if (!this.disk.create(unit, name, mode, type, label, ffs, bootable)) + return SAEE_NoMemory; + return SAEE_None; + }; + + /*---------------------------------*/ + + SAEF_info("SAE %d.%d.%d", SAEC_Version, SAEC_Revision, SAEC_Patch); +} diff --git a/sae/audio.js b/sae/audio.js index 0af87e1..a366dee 100644 --- a/sae/audio.js +++ b/sae/audio.js @@ -1,1075 +1,1688 @@ -/************************************************************************** -* SAE - Scripted Amiga Emulator -* -* 2012-2015 Rupert Hausberger -* -* https://github.com/naTmeg/ScriptedAmigaEmulator -* -*************************************************************************** -* Notes: Ported from WinUAE 2.5.0 -* -**************************************************************************/ +/*------------------------------------------------------------------------- +| SAE - Scripted Amiga Emulator +| https://github.com/naTmeg/ScriptedAmigaEmulator +| +| Copyright (C) 2012-2016 Rupert Hausberger +| +| This program is free software; you can redistribute it and/or +| modify it under the terms of the GNU General Public License +| as published by the Free Software Foundation; either version 2 +| of the License, or (at your option) any later version. +| +| This program is distributed in the hope that it will be useful, +| but WITHOUT ANY WARRANTY; without even the implied warranty of +| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +| GNU General Public License for more details. +| +| Note: ported from WinUAE 3.2.x +-------------------------------------------------------------------------*/ +/* global variables */ -/*const DEBUG_CHANNEL_MASK = 15 -function debugchannel(ch) { - return ((1 << ch) & DEBUG_CHANNEL_MASK) != 0; -}*/ +var SAEV_Audio_vsynctimebase_orig = 0; -function Filter() { - const DENORMAL_OFFSET = 1E-10; +/*---------------------------------*/ +/* global references */ - this.on = false; - this.led_filter_on = false; +var SAER_Audio_deactivate = null; - var filter_state = [ - { rc1:0,rc2:0,rc3:0,rc4:0,rc5:0 }, - { rc1:0,rc2:0,rc3:0,rc4:0,rc5:0 }, - { rc1:0,rc2:0,rc3:0,rc4:0,rc5:0 }, - { rc1:0,rc2:0,rc3:0,rc4:0,rc5:0 } - ]; - var filter1_a0 = 0; - var filter2_a0 = 0; - var filter_a0 = 0; +/*---------------------------------*/ - function calc(sample_rate, cutoff_freq) { - if (cutoff_freq >= sample_rate / 2) - return 1.0; +function SAEO_Audio() { + const PAULA_FREQ_PAL = SAEC_Playfield_CLOCK_PAL / 123; + const PAULA_FREQ_NTSC = SAEC_Playfield_CLOCK_NTSC / 124; - var omega = 2 * Math.PI * cutoff_freq / sample_rate; - omega = Math.tan(omega / 2) * 2; - return 1 / (1 + 1 / omega); - } - - this.setup = function (on, sample_rate) { - this.on = on; - filter1_a0 = calc(sample_rate, 6200); - filter2_a0 = calc(sample_rate, 20000); - filter_a0 = calc(sample_rate, 7000); - /*console.log(sample_rate); - console.log(filter1_a0); - console.log(filter2_a0); - console.log(filter_a0);*/ + var driver = { + context:null, + processor:null, + connected:false }; - this.reset = function () { - filter_state = [ - { rc1: 0, rc2: 0, rc3: 0, rc4: 0, rc5: 0 }, - { rc1: 0, rc2: 0, rc3: 0, rc4: 0, rc5: 0 }, - { rc1: 0, rc2: 0, rc3: 0, rc4: 0, rc5: 0 }, - { rc1: 0, rc2: 0, rc3: 0, rc4: 0, rc5: 0 } - ]; + const CACHE_FRAMES_MULT = 16; + var cache = { + frames:0, + buffer:null, + readoffset:0, + writeoffset:0, + wait:false + }; + const SCALE_FRAMES_MULT = 4; + var scale = { + frames:0, + buffer:null }; - this.filter = function(input, state) { - //if (!this.on) return input; - var o, fs = filter_state[state]; + const SOUND_SYNC_MULTIPLIER = 1.0; + var scaled_sample_evtime_orig = 0.0; - fs.rc1 = filter1_a0 * input + (1 - filter1_a0) * fs.rc1 + DENORMAL_OFFSET; - fs.rc2 = filter2_a0 * fs.rc1 + (1 - filter2_a0) * fs.rc2; - var no = fs.rc2; + var paused = false; + var have_sound = false; + var sound_available = false; - if (this.led_filter_on) { - fs.rc3 = filter_a0 * no + (1 - filter_a0) * fs.rc3; - fs.rc4 = filter_a0 * fs.rc3 + (1 - filter_a0) * fs.rc4; - fs.rc5 = filter_a0 * fs.rc4 + (1 - filter_a0) * fs.rc5; - o = Math.floor(fs.rc5); - } else - o = Math.floor(no); + //var avg_correct = 0.0; + //var cnt_correct = 0.0; - return o > 32767 ? 32767 : (o < -32768 ? -32768 : o); + var used_freq = 0; //OWN + + /*-----------------------------------------------------------------------*/ + + this.update_sound = function(clk) { + if (have_sound) { + scaled_sample_evtime_orig = clk * SAEC_Events_CYCLE_UNIT * SOUND_SYNC_MULTIPLIER / used_freq; + scaled_sample_evtime = scaled_sample_evtime_orig; + SAEF_log("audio.update_sound() freq %f Hz, scaled sample eventtime %f cycles", used_freq, scaled_sample_evtime * SAEC_Events_CYCLE_UNIT_INV); + } } -} -function Channel(num) { - this.num = num; - this.enabled = false; - this.evtime = 0; - this.dmaenstore = false; - this.intreq = false; - this.dr = false; - this.dsr = false; - this.pbufldl = false; - this.dat_written = false; - this.state = 0; - this.lc = 0; - this.pt = 0; - this.per = 0; - this.vol = 0; - this.len = 0; - this.wlen = 0; - this.dat = 0; - this.dat2 = 0; - this.current_sample = 0; - this.last_sample = 0; - this.ptx = 0; - this.ptx_written = false; - this.ptx_tofetch = false; - - this.reset = function () { + /*-----------------------------------------------------------------------*/ + + /*const ADJUST_LIMIT = 6; + const ADJUST_LIMIT2 = 1; + + //->SAEV_Audio_vsynctimebase_orig var vsynctimebase_orig = 0; //int + + function sound_setadjust(v) { + if (v < -ADJUST_LIMIT) v = -ADJUST_LIMIT; + else if (v > ADJUST_LIMIT) v = ADJUST_LIMIT; + + vsynctimebase = (SAEV_Audio_vsynctimebase_orig * (1000.0 + v) / 1000.0) >>> 0; + scaled_sample_evtime = scaled_sample_evtime_orig; + } + + var tfprev = 0; //fix reset + function docorrection(s, sndbuf, sync, granulaty) { + //static int tfprev; + + avg_correct += sync; + cnt_correct++; + + if (granulaty < 10) + granulaty = 10; + + if (tfprev != SAEV_Events_timeframes) { + var avg = avg_correct / cnt_correct; + + var skipmode = sync / 100.0; + var avgskipmode = avg / (10000.0 / granulaty); + + if ((tfprev % 10) == 0) + SAEF_log("%+05d S=%.1f AVG=%.1f (IMM=%.1f + AVG=%.1f = %.1f)", sndbuf, sync, avg, skipmode, avgskipmode, skipmode + avgskipmode); + + SAER.gui.data.sndbuf = sndbuf; + + if (skipmode > ADJUST_LIMIT2) + skipmode = ADJUST_LIMIT2; + if (skipmode < -ADJUST_LIMIT2) + skipmode = -ADJUST_LIMIT2; + + sound_setadjust(skipmode + avgskipmode); + tfprev = SAEV_Events_timeframes; + } + }*/ + + /*---------------------------------*/ + + function cachediff(write, read) { + var diff = write - read; + if (diff > cache.frames >> 1) + diff = cache.frames - write + read; + else if (diff < -cache.frames >> 1) + diff = cache.frames - read + write; + return diff; + } + + function cachewrite(buffer, frames) { + var diff = cachediff(cache.writeoffset, cache.readoffset); + if (diff > cache.frames >> 2) { + SAEF_warn("audio.cachewrite() full %d", diff + frames); + return false; + } + + if (cache.writeoffset + frames > cache.frames) { + var partsize = cache.frames - cache.writeoffset; + if (partsize) { + //SAEF_log("audio.cachewrite() write0 %d %d", cache.writeoffset, partsize); + for (var j = 0; j < SAEV_config.audio.channels; j++) { + //for (var i = 0; i < partsize; i++) cache.buffer[j][cache.writeoffset + i] = buffer[j][i]; + cache.buffer[j].set(buffer[j].subarray(0, partsize), cache.writeoffset); + } + } + if (frames - partsize) { + //SAEF_log("audio.cachewrite() write1 %d %d", 0, frames - partsize); + for (var j = 0; j < SAEV_config.audio.channels; j++) { + //for (var i = 0; i < frames - partsize; i++) cache.buffer[j][i] = buffer[j][partsize + i]; + cache.buffer[j].set(buffer[j].subarray(partsize, partsize + (frames - partsize))); + } + } + cache.writeoffset = frames - partsize; + } else { + //SAEF_log("audio.cachewrite() write2 %d %d", cache.writeoffset, frames); + for (var j = 0; j < SAEV_config.audio.channels; j++) { + //for (var i = 0; i < frames; i++) cache.buffer[j][cache.writeoffset + i] = buffer[j][i]; + cache.buffer[j].set(buffer[j].subarray(0, frames), cache.writeoffset); + } + cache.writeoffset += frames; + } + return true; + } + + function cacheread(buffer, frames) { + var diff = cachediff(cache.writeoffset, cache.readoffset + frames); + if (diff < 0) { + //SAEF_log("audio.cacheread() clr %d", frames); + for (var j = 0; j < SAEV_config.audio.channels; j++) { + //SAEF_memset(buffer[j],0, 0, frames); + for (var i = 0; i < frames; i++) buffer[j][i] = 0; + } + frames -= -diff; + } + if (frames > 0) { + if (cache.readoffset + frames > cache.frames) { + var partsize = cache.frames - cache.readoffset; + if (partsize) { + //SAEF_log("audio.cacheread() read0 %d %d", cache.readoffset, partsize); + for (var j = 0; j < SAEV_config.audio.channels; j++) { + //for (var i = 0; i < partsize; i++) buffer[j][i] = cache.buffer[j][cache.readoffset + i]; + buffer[j].set(cache.buffer[j].subarray(cache.readoffset, cache.readoffset + partsize)); + } + } + if (frames - partsize) { + //SAEF_log("audio.cacheread() read1 %d %d", 0, frames - partsize); + for (var j = 0; j < SAEV_config.audio.channels; j++) { + //for (var i = 0; i < frames - partsize; i++) buffer[j][partsize + i] = cache.buffer[j][i]; + buffer[j].set(cache.buffer[j].subarray(0, frames - partsize), partsize); + } + } + cache.readoffset = frames - partsize; + } else { + //SAEF_log("audio.cacheread() read2 %d %d", cache.readoffset, frames); + for (var j = 0; j < SAEV_config.audio.channels; j++) { + //for (var i = 0; i < frames; i++) buffer[j][i] = cache.buffer[j][cache.readoffset + i]; + buffer[j].set(cache.buffer[j].subarray(cache.readoffset, cache.readoffset + frames)); + } + cache.readoffset += frames; + } + return true; + } else if (frames < 0) + SAEF_warn("audio.cacheread() empty %d", frames); + + return false; + } + + /*---------------------------------*/ + + const INV32768 = 1.0 / 32768; /* mul is always fasten than div */ + + function scaleplay(e, buffer, frames) { + /*if (driver.context.sampleRate != used_freq) { + } else*/ { + var step = frames / e.outputBuffer.length; + + for (var ch = 0; ch < SAEV_config.audio.channels; ch++) { + var data = e.outputBuffer.getChannelData(ch); + for (var i = 0, j = 0.0; i < e.outputBuffer.length; i++, j += step) + data[i] = buffer[ch][j >>> 0] * INV32768; + } + } + } + + function process_sound_buffer_webaudio(e) { + if (paused || cache.wait || paula.currrent == 0) + var scale_frames = paula.frames; + else + var scale_frames = paula.average.set(paula.currrent); + + //SAEF_log("audio.process_sound_buffer_webaudio() %d %d", paula.currrent, scale_frames); + paula.currrent = 0; + + cacheread(scale.buffer, scale_frames); + scaleplay(e, scale.buffer, scale_frames); + } + + function finish_sound_buffer_webaudio(buffer, frames) { + if (!paused && have_sound) { + cachewrite(buffer, frames); + cache.wait = false; + } + } + + /*-----------------------------------------------------------------------*/ + + function pause_sound() { + //SAER.gui.data.sndbuf_status = 0; + //SAER.gui.data.sndbuf = 0; + if (!paused && have_sound) { + SAEF_log("audio.pause_sound()"); + + paused = true; + //disconnect_sound(); + //driver.context.suspend().then(function() { SAEF_log("audio.pause_sound() ...done"); }); + } + } + + function resume_sound() { + if (paused && have_sound) { + SAEF_log("audio.resume_sound()"); + + //connect_sound(); + //driver.context.resume().then(function() { SAEF_log("audio.resume_sound() ...done"); }); + paused = false; + cache.wait = true; + } + } + + /*-----------------------------------------------------------------------*/ + + function connect_sound() { + if (!driver.connected) { + driver.processor.onaudioprocess = process_sound_buffer_webaudio; + driver.processor.connect(driver.context.destination); + driver.connected = true; + } + } + + function disconnect_sound() { + if (driver.connected) { + driver.processor.disconnect(driver.context.destination); + driver.processor.onaudioprocess = function(e) {}; + driver.connected = false; + } + } + + function open_sound() { + driver.context = null; + try { + var AudioContextDriver = window.AudioContext || window.webkitAudioContext; + driver.context = new AudioContextDriver(); + driver.processor = driver.context.createScriptProcessor(paula.frames, SAEV_config.audio.channels, SAEV_config.audio.channels); + } catch (e) { + if (driver.context) driver.context.close().then(function() {}); + return false; + } + + if (SAEV_config.audio.freq == SAEC_Config_Audio_Freq_Auto) + used_freq = driver.context.sampleRate; + else + used_freq = SAEV_config.audio.freq; + + if (cache.buffer === null) { + cache.frames = paula.frames * CACHE_FRAMES_MULT; + cache.buffer = new Array(2); + for (var j = 0; j < cache.buffer.length; j++) + cache.buffer[j] = new Int16Array(cache.frames); + } + if (scale.buffer === null) { + scale.frames = paula.frames * SCALE_FRAMES_MULT; + scale.buffer = new Array(2); + for (var j = 0; j < scale.buffer.length; j++) + scale.buffer[j] = new Int16Array(scale.frames); + } + + connect_sound(); + have_sound = true; + + SAEF_info("sae.audio() %d channels, frequency %d/%d Hz, %d frames", SAEV_config.audio.channels, used_freq, driver.context.sampleRate, paula.frames); + return true; + } + + function close_sound() { + //SAER.gui.data.sndbuf_status = 3; + //SAER.gui.data.sndbuf = 0; + if (have_sound) { + SAEF_log("audio.close_sound() initialised..."); + + disconnect_sound(); + if (driver.context.close) { + driver.context.close().then(function() { + driver.context = null; + SAEF_log("audio.close_sound() ...done"); + }); + } + paused = false; + have_sound = false; + } + } + + /*-----------------------------------------------------------------------*/ + + function obtain_sound() { //setup_sound() + if (SAEV_config.audio.mode >= SAEC_Config_Audio_Mode_On) { + if (SAEC_info.audio.webAudio) + sound_available = true; + else { + /*if (confirm("'WebAudio' is not supported by this browser.\n\nContinue without audio-playback?")) + SAEV_config.audio.mode = SAEC_Config_Audio_Mode_Off_Emul; + else*/ + return SAEE_Audio_RequiresWebAudio; + } + } + return SAEE_None; + } + + function setup_sound() { //init_sound() + //SAER.gui.data.sndbuf_status = 3; + //SAER.gui.data.sndbuf = 0; + if (!have_sound) + return open_sound(); + + return true; + } + + function cleanup_sound() { //OWN + close_sound(); + } + + function reset_sound() { //reset_sound() + cache.readoffset = 0; + cache.writeoffset = 0; + cache.wait = true; + + paula.average.clr(); + } + + /*-----------------------------------------------------------------------*/ + /*-----------------------------------------------------------------------*/ + /*-----------------------------------------------------------------------*/ + + const MAX_EV = SAEC_Events_CYCLE_MAX; + + const PERIOD_MIN = 4; + const PERIOD_MIN_NONCE = 60; + const PERIOD_MAX = SAEC_Events_CYCLE_MAX; + + const AUDIO_CHANNELS_PAULA = 4; + const AUDIO_CHANNELS_MAX = 4; //8 + + const SOUND_MAX_DELAY_BUFFER = 1024; + const MIXED_STEREO_MAX = 16; + const MIXED_STEREO_SCALE = 32; + + function audio_channel_data() { this.enabled = false; - this.evtime = CYCLE_MAX; + //this.adk_mask = 0; //uint + this.evtime = 0; //uint this.dmaenstore = false; - this.intreq = false; + this.intreq2 = false; this.dr = false; this.dsr = false; this.pbufldl = false; + this.drhpos = 0; this.dat_written = false; + this.lc = 0; this.pt = 0; //uaecptr + this.current_sample = 0; + this.last_sample = 0; this.state = 0; - this.lc = 0; - this.pt = 0; - this.per = PERIOD_MAX - 1; + this.per = 0; this.vol = 0; this.len = 0; this.wlen = 0; - this.dat = 0; - this.dat2 = 0; - this.current_sample = 0; - this.last_sample = 0; - this.ptx = 0; + this.dat = 0; this.dat2 = 0; //u16 + //Anti + this.sample_accum = 0; + this.sample_accum_time = 0; + //too fast cpu fixes + this.ptx = 0; //uaecptr this.ptx_written = false; this.ptx_tofetch = false; - }; - - //const audio_channel_mask = 15; - this.newsample = function (sample) { - //if (debugchannel(this.num)) BUG.info('Audio.channel[%d].newsample() %02x', nr, sample); - //if (!(audio_channel_mask & (1 << this.num))) sample = 0; - if (sample & 0x80) sample -= 0x100; - this.last_sample = this.current_sample; - this.current_sample = sample; - }; - - this.isirq = function () { - return (AMIGA.INTREQR() & (0x80 << this.num)) != 0; + this.dmaofftime_active = false; + + this.clr = function() { + this.enabled = false; + //this.adk_mask = 0 + this.evtime = 0; + this.dmaenstore = false; + this.intreq2 = false; + this.dr = false; + this.dsr = false; + this.pbufldl = false; + this.drhpos = 0; + this.dat_written = false; + this.lc = this.pt = 0; + this.current_sample = 0; + this.last_sample = 0; + this.state = 0; + this.per = 0; + this.vol = 0; + this.len = 0; + this.wlen = 0; + this.dat = this.dat2 = 0; + //Anti + this.sample_accum = 0; + this.sample_accum_time = 0; + //too fast cpu fixes + this.ptx = 0; + this.ptx_written = false; + this.ptx_tofetch = false; + this.dmaofftime_active = false; + }; + } + var audio_channel = new Array(AUDIO_CHANNELS_MAX); + for (var vi = 0; vi < AUDIO_CHANNELS_MAX; vi++) + audio_channel[vi] = new audio_channel_data(); + + var audio_channel_mask = 15; //global + var audio_channel_count = AUDIO_CHANNELS_PAULA; + var audio_work_to_do = 0; + + var sample_handler = function() {}; + var sample_prehandler = null; + + var sample_evtime = 0.0; //global + var scaled_sample_evtime = 0.0; + + var last_cycles = 0; + var next_sample_evtime = 0.0; + + //var paula_buffer = null; //u16 * + //var paula_pointer = null; //u16 * + //var paula_size = 0; + var paula = { //OWN + frames: 0, + buffer: null, + pointer: 0, + currrent: 0, + average: new SAEO_MAvg(10) }; - this.setirq = function (which) { - //if (debugchannel(this.num) && this.wlen > 1) BUG.info('Audio.channel[%d].setirq() %d, %d', this.num, which, this.isirq() ? 1 : 0); - AMIGA.INTREQ_0(INTF_SETCLR | (0x80 << this.num)); - }; + var datas = new Int16Array(AUDIO_CHANNELS_PAULA); - this.zerostate = function () { - //if (debugchannel(this.num)) BUG.info('Audio.channel[%d].zerostate()', this.num); - this.state = 0; - this.evtime = CYCLE_MAX; - this.intreq = false; - this.dmaenstore = false; - }; - - this.setdr = function () { - //if (debugchannel(this.num) && this.dr) BUG.info('Audio.channel[%d].setdr() DR already active (STATE %d)', this.num, this.state); - this.dr = true; - if (this.wlen == 1) { - this.dsr = true; - //if (debugchannel(this.num) && this.wlen > 1) BUG.info('Audio.channel[%d].setdr() DSR on, pt %08x', this.num, this.pt); + var right_word_saved = new Int16Array(SOUND_MAX_DELAY_BUFFER); //u32 [SOUND_MAX_DELAY_BUFFER] + var left_word_saved = new Int16Array(SOUND_MAX_DELAY_BUFFER); + var saved_ptr = 0; + var mixed_on = 0, mixed_stereo_size = 0, mixed_mul1 = 0, mixed_mul2 = 0; + + var usehacks = false; + + /*-----------------------------------------------------------------------*/ + + var led_filter_forced = 0, sound_use_filter = 0, led_filter_on = 0; + + /* denormals are very small floating point numbers that force FPUs into slow + mode. All lowpass filters using floats are suspectible to denormals unless + a small offset is added to avoid very small floating point numbers. */ + const DENORMAL_OFFSET = 1E-10; + + function filter_state() { + this.rc1 = 0.0; + this.rc2 = 0.0; + this.rc3 = 0.0; + this.rc4 = 0.0; + this.rc5 = 0.0; + + this.clr = function() { + this.rc1 = 0.0; + this.rc2 = 0.0; + this.rc3 = 0.0; + this.rc4 = 0.0; + this.rc5 = 0.0; } - }; + } + var sound_filter_state = new Array(AUDIO_CHANNELS_PAULA); + for (var vi = 0; vi < AUDIO_CHANNELS_PAULA; vi++) + sound_filter_state[vi] = new filter_state(); - this.loaddat = function (modper) { - var audav = (AMIGA.adkcon & (0x01 << this.num)) != 0; - var audap = (AMIGA.adkcon & (0x10 << this.num)) != 0; - if (audav || (modper && audap)) { - if (this.num >= 3) - return; - if (modper && audap) { - if (this.dat == 0) - AMIGA.audio.channel[this.num + 1].per = PERIOD_MAX; - else if (this.dat > PERIOD_MIN) - AMIGA.audio.channel[this.num + 1].per = this.dat * CYCLE_UNIT; - else - AMIGA.audio.channel[this.num + 1].per = PERIOD_MIN * CYCLE_UNIT; - } else if (audav) { - AMIGA.audio.channel[this.num + 1].vol = this.dat; - AMIGA.audio.channel[this.num + 1].vol &= 127; - if (AMIGA.audio.channel[this.num + 1].vol > 64) - AMIGA.audio.channel[this.num + 1].vol = 64; + var a500e_filter1_a0 = 0.0; + var a500e_filter2_a0 = 0.0; + var filter_a0 = 0.0; /* a500 and a1200 use the same */ + + const FILTER_NONE = 0; + const FILTER_MODEL_A500 = 1; + const FILTER_MODEL_A1200 = 2; + + /* Amiga has two separate filtering circuits per channel, a static RC filter + * on A500 and the LED filter. This code emulates both. + * + * The Amiga filtering circuitry depends on Amiga model. Older Amigas seem + * to have a 6 dB/oct RC filter with cutoff frequency such that the -6 dB + * point for filter is reached at 6 kHz, while newer Amigas have no filtering. + * + * The LED filter is complicated, and we are modelling it with a pair of + * RC filters, the other providing a highboost. The LED starts to cut + * into signal somewhere around 5-6 kHz, and there"s some kind of highboost + * in effect above 12 kHz. Better measurements are required. + * + * The current filtering should be accurate to 2 dB with the filter on, + * and to 1 dB with the filter off. */ + + function filter(input, fs) { + var normal_output, led_output, output; + + //input = (uae_s16)input; //ORG + //if (input & 0x8000) input -= 0x10000; //OWN + + switch (sound_use_filter) { + case FILTER_MODEL_A500: { + fs.rc1 = a500e_filter1_a0 * input + (1 - a500e_filter1_a0) * fs.rc1 + DENORMAL_OFFSET; + fs.rc2 = a500e_filter2_a0 * fs.rc1 + (1 - a500e_filter2_a0) * fs.rc2; + normal_output = fs.rc2; + + fs.rc3 = filter_a0 * normal_output + (1 - filter_a0) * fs.rc3; + fs.rc4 = filter_a0 * fs.rc3 + (1 - filter_a0) * fs.rc4; + fs.rc5 = filter_a0 * fs.rc4 + (1 - filter_a0) * fs.rc5; + + led_output = fs.rc5; + break; } - } else { - //if (debugchannel(this.num)) BUG.info('Audio.channel[%d].loaddat() new %04x, old %04x', this.num, this.dat, this.dat2); - this.dat2 = this.dat; + case FILTER_MODEL_A1200: { + normal_output = input; + + fs.rc2 = filter_a0 * normal_output + (1 - filter_a0) * fs.rc2 + DENORMAL_OFFSET; + fs.rc3 = filter_a0 * fs.rc2 + (1 - filter_a0) * fs.rc3; + fs.rc4 = filter_a0 * fs.rc3 + (1 - filter_a0) * fs.rc4; + + led_output = fs.rc4; + break; + } + case FILTER_NONE: + default: + return input; } - }; - this.loadper = function () { - this.evtime = this.per; - if (this.evtime < CYCLE_UNIT) - BUG.info('Audio.channel[%d].loadper() bug %d', this.num, this.evtime); - }; - - this.state_channel = function (perfin) { - this.state_channel2(perfin); - this.dat_written = false; - }; + if (led_filter_on) + output = ~~led_output; + else + output = ~~normal_output; - this.state_channel2 = function(perfin) { - var chan_ena = ((AMIGA.dmacon & DMAF_DMAEN) && (AMIGA.dmacon & (1 << this.num))) ? true : false; - var old_dma = this.dmaenstore; - var audav = (AMIGA.adkcon & (0x01 << this.num)) != 0; - var audap = (AMIGA.adkcon & (0x10 << this.num)) != 0; + if (output > 32767) + output = 32767; + else if (output < -32768) + output = -32768; + + return output; + //return output < 0 ? output + 0x10000 : output; //OWN + } + + this.led_filter_audio = function() { + led_filter_on = 0; + if (led_filter_forced > 0 || (SAER.gui.data.powerled && led_filter_forced >= 0)) + led_filter_on = 1; + } + + /*-----------------------------------------------------------------------*/ + + function clear_sound_buffers() { + //if (!have_sound) return; + + //memset(paula_sndbuffer, 0, paula_size); + for (var i = 0; i < paula.buffer.length; i++) + SAEF_memset(paula.buffer[i],0, 0, paula.frames); + + //paula_pointer = paula_buffer; + paula.pointer = 0; + paula.currrent = 0; + } + + function finish_sound_buffer() { + //paula_pointer = paula_buffer; + paula.pointer = 0; + + //if (currprefs.turbo_emulation) return; + //if (!have_sound) return; + + //if (SAER.gui.data.sndbuf_status == 3) + // SAER.gui.data.sndbuf_status = 0; + + //if (!paused) + finish_sound_buffer_webaudio(paula.buffer, paula.frames); + } + + function check_sound_buffers() { + //if ((uae_u8*)paula_pointer - (uae_u8*)paula_buffer >= paula_size) + if (paula.pointer >= paula.frames) + finish_sound_buffer(); + } + + /*-----------------------------------------------------------------------*/ + + //#define PUT_SOUND_WORD(b) do { *(uae_u16 *)paula_pointer = b; paula_pointer = (uae_u16 *)(((uae_u8 *)paula_pointer) + 2); } while (0) + //#define PUT_SOUND_WORD_MONO(b) PUT_SOUND_WORD(b) + + /* Always put the right word before the left word. */ + function put_sound_word_right(w) { //u32 + if (mixed_on) + right_word_saved[saved_ptr] = w; + else + //PUT_SOUND_WORD(w); + paula.buffer[1][paula.pointer] = w; + } + + function put_sound_word_left(w) { + if (mixed_on) { + left_word_saved[saved_ptr] = w; + + var lnew = w; + var rnew = right_word_saved[saved_ptr]; + + saved_ptr = (saved_ptr + 1) & mixed_stereo_size; + + var lold = left_word_saved[saved_ptr]; + var tmp = ~~((rnew * mixed_mul2 + lold * mixed_mul1) / MIXED_STEREO_SCALE); + + var rold = right_word_saved[saved_ptr]; + w = ~~((lnew * mixed_mul2 + rold * mixed_mul1) / MIXED_STEREO_SCALE); + + //PUT_SOUND_WORD(w); + //PUT_SOUND_WORD(tmp); + paula.buffer[1][paula.pointer] = w; + paula.buffer[0][paula.pointer] = tmp; + } else + //PUT_SOUND_WORD(w); + paula.buffer[0][paula.pointer] = w; + } + + /*---------------------------------*/ + + function anti_prehandler(best_evtime) { + for (var i = 0; i < audio_channel_count; i++) { + var acd = audio_channel[i]; + //var output = (acd.current_sample * acd.vol) & acd.adk_mask; + var output = acd.enabled ? acd.current_sample * acd.vol: 0; + acd.sample_accum += output * best_evtime; + acd.sample_accum_time += best_evtime; + } + } + + function samplexx_anti_handler(datasp, ch_start, ch_num) { + for (var i = ch_start, j = 0; j < ch_num; i++, j++) { + datasp[j] = audio_channel[i].sample_accum_time ? Math.floor(audio_channel[i].sample_accum / audio_channel[i].sample_accum_time) : 0; + audio_channel[i].sample_accum = 0; + audio_channel[i].sample_accum_time = 0; + } + } + + /*---------------------------------*/ + /* Mono */ + + function sample16_mono_handler() { + var data0 = audio_channel[0].enabled ? audio_channel[0].current_sample * audio_channel[0].vol : 0; + var data1 = audio_channel[1].enabled ? audio_channel[1].current_sample * audio_channel[1].vol : 0; + var data2 = audio_channel[2].enabled ? audio_channel[2].current_sample * audio_channel[2].vol : 0; + var data3 = audio_channel[3].enabled ? audio_channel[3].current_sample * audio_channel[3].vol : 0; + + data0 += data1; + data0 += data2; + data0 += data3; + + var data = data0; + if (SAEV_config.audio.filter) data = filter(data, sound_filter_state[0]); + + //PUT_SOUND_WORD_MONO(data); + paula.buffer[0][paula.pointer++] = data; + paula.currrent++; + check_sound_buffers(); + } + + function sample16i_anti_mono_handler() { + samplexx_anti_handler(datas, 0, AUDIO_CHANNELS_PAULA); + var data1 = datas[0] + datas[3] + datas[1] + datas[2]; + + if (SAEV_config.audio.filter) data1 = filter(data1, sound_filter_state[0]); + + //PUT_SOUND_WORD_MONO(data1); + paula.buffer[0][paula.pointer++] = data1; + paula.currrent++; + check_sound_buffers(); + } + + function sample16i_rh_mono_handler() { + var data0, data1, data2, data3, data0p, data1p, data2p, data3p; + var delta, ratio; //ulong + if (audio_channel[0].enabled) { + data0 = audio_channel[0].current_sample * audio_channel[0].vol; + data0p = audio_channel[0].last_sample * audio_channel[0].vol; + } else data0 = data0p = 0; + if (audio_channel[1].enabled) { + data1 = audio_channel[1].current_sample * audio_channel[1].vol; + data1p = audio_channel[1].last_sample * audio_channel[1].vol; + } else data1 = data1p = 0; + if (audio_channel[2].enabled) { + data2 = audio_channel[2].current_sample * audio_channel[2].vol; + data2p = audio_channel[2].last_sample * audio_channel[2].vol; + } else data2 = data2p = 0; + if (audio_channel[3].enabled) { + data3 = audio_channel[3].current_sample * audio_channel[3].vol; + data3p = audio_channel[3].last_sample * audio_channel[3].vol; + } else data3 = data3p = 0; + + delta = audio_channel[0].per; + ratio = ~~(((audio_channel[0].evtime % delta) << 8) / delta); + data0 = (data0 * (256 - ratio) + data0p * ratio) >> 8; + delta = audio_channel[1].per; + ratio = ~~(((audio_channel[1].evtime % delta) << 8) / delta); + data0 += (data1 * (256 - ratio) + data1p * ratio) >> 8; + delta = audio_channel[2].per; + ratio = ~~(((audio_channel[2].evtime % delta) << 8) / delta); + data0 += (data2 * (256 - ratio) + data2p * ratio) >> 8; + delta = audio_channel[3].per; + ratio = ~~(((audio_channel[3].evtime % delta) << 8) / delta); + data0 += (data3 * (256 - ratio) + data3p * ratio) >> 8; + + var data = data0; + + if (SAEV_config.audio.filter) data = filter(data, sound_filter_state[0]); + + //PUT_SOUND_WORD_MONO(data); + paula.buffer[0][paula.pointer++] = data; + paula.currrent++; + check_sound_buffers(); + } + + function sample16i_crux_mono_handler() { + var data0, data1, data2, data3, data0p, data1p, data2p, data3p; + if (audio_channel[0].enabled) { + data0 = audio_channel[0].current_sample * audio_channel[0].vol; + data0p = audio_channel[0].last_sample * audio_channel[0].vol; + } else data0 = data0p = 0; + if (audio_channel[1].enabled) { + data1 = audio_channel[1].current_sample * audio_channel[1].vol; + data1p = audio_channel[1].last_sample * audio_channel[1].vol; + } else data1 = data1p = 0; + if (audio_channel[2].enabled) { + data2 = audio_channel[2].current_sample * audio_channel[2].vol; + data2p = audio_channel[2].last_sample * audio_channel[2].vol; + } else data2 = data2p = 0; + if (audio_channel[3].enabled) { + data3 = audio_channel[3].current_sample * audio_channel[3].vol; + data3p = audio_channel[3].last_sample * audio_channel[3].vol; + } else data3 = data3p = 0; + + { + var cdp, ratio, ratio1; + var INTERVAL = scaled_sample_evtime * 3; + + cdp = audio_channel[0]; + ratio1 = cdp.per - cdp.evtime; + ratio = ~~((ratio1 << 12) / INTERVAL); + if (cdp.evtime < scaled_sample_evtime || ratio1 >= INTERVAL) + ratio = 4096; + data0 = (data0 * ratio + data0p * (4096 - ratio)) >> 12; + + cdp = audio_channel[1]; + ratio1 = cdp.per - cdp.evtime; + ratio = ~~((ratio1 << 12) / INTERVAL); + if (cdp.evtime < scaled_sample_evtime || ratio1 >= INTERVAL) + ratio = 4096; + data1 = (data1 * ratio + data1p * (4096 - ratio)) >> 12; + + cdp = audio_channel[2]; + ratio1 = cdp.per - cdp.evtime; + ratio = ~~((ratio1 << 12) / INTERVAL); + if (cdp.evtime < scaled_sample_evtime || ratio1 >= INTERVAL) + ratio = 4096; + data2 = (data2 * ratio + data2p * (4096 - ratio)) >> 12; + + cdp = audio_channel[3]; + ratio1 = cdp.per - cdp.evtime; + ratio = ~~((ratio1 << 12) / INTERVAL); + if (cdp.evtime < scaled_sample_evtime || ratio1 >= INTERVAL) + ratio = 4096; + data3 = (data3 * ratio + data3p * (4096 - ratio)) >> 12; + } + data1 += data2; + data0 += data3; + data0 += data1; + var data = data0; + + if (SAEV_config.audio.filter) data = filter(data, sound_filter_state[0]); + + //PUT_SOUND_WORD_MONO (data); + paula.buffer[0][paula.pointer++] = data; + paula.currrent++; + check_sound_buffers(); + } + + /*---------------------------------*/ + /* Stereo */ + + function sample16s_handler() { + var data0 = audio_channel[0].enabled ? audio_channel[0].current_sample * audio_channel[0].vol : 0; + var data1 = audio_channel[1].enabled ? audio_channel[1].current_sample * audio_channel[1].vol : 0; + var data2 = audio_channel[2].enabled ? audio_channel[2].current_sample * audio_channel[2].vol : 0; + var data3 = audio_channel[3].enabled ? audio_channel[3].current_sample * audio_channel[3].vol : 0; + + data0 += data3; + data1 += data2; + data2 = data0 << 1; + data3 = data1 << 1; + + if (SAEV_config.audio.filter) { + data2 = filter(data2, sound_filter_state[0]); + data3 = filter(data3, sound_filter_state[1]); + } + + put_sound_word_right(data2); + put_sound_word_left(data3); + paula.pointer++; + paula.currrent++; + check_sound_buffers(); + } + + function sample16si_anti_handler() { + samplexx_anti_handler(datas, 0, AUDIO_CHANNELS_PAULA); + var data1 = datas[0] + datas[3]; + var data2 = datas[1] + datas[2]; + data1 = data1 << 1; + data2 = data2 << 1; + + if (SAEV_config.audio.filter) { + data1 = filter(data1, sound_filter_state[0]); + data2 = filter(data2, sound_filter_state[1]); + } + + put_sound_word_right(data1); + put_sound_word_left(data2); + paula.pointer++; + paula.currrent++; + check_sound_buffers(); + } + + function sample16si_rh_handler() { + var data0, data1, data2, data3, data0p, data1p, data2p, data3p; + var delta, ratio; //ulong + if (audio_channel[0].enabled) { + data0 = audio_channel[0].current_sample * audio_channel[0].vol; + data0p = audio_channel[0].last_sample * audio_channel[0].vol; + } else data0 = data0p = 0; + if (audio_channel[1].enabled) { + data1 = audio_channel[1].current_sample * audio_channel[1].vol; + data1p = audio_channel[1].last_sample * audio_channel[1].vol; + } else data1 = data1p = 0; + if (audio_channel[2].enabled) { + data2 = audio_channel[2].current_sample * audio_channel[2].vol; + data2p = audio_channel[2].last_sample * audio_channel[2].vol; + } else data2 = data2p = 0; + if (audio_channel[3].enabled) { + data3 = audio_channel[3].current_sample * audio_channel[3].vol; + data3p = audio_channel[3].last_sample * audio_channel[3].vol; + } else data3 = data3p = 0; + + delta = audio_channel[0].per; + ratio = ~~(((audio_channel[0].evtime % delta) << 8) / delta); + data0 = (data0 * (256 - ratio) + data0p * ratio) >> 8; + delta = audio_channel[1].per; + ratio = ~~(((audio_channel[1].evtime % delta) << 8) / delta); + data1 = (data1 * (256 - ratio) + data1p * ratio) >> 8; + delta = audio_channel[2].per; + ratio = ~~(((audio_channel[2].evtime % delta) << 8) / delta); + data1 += (data2 * (256 - ratio) + data2p * ratio) >> 8; + delta = audio_channel[3].per; + ratio = ~~(((audio_channel[3].evtime % delta) << 8) / delta); + data0 += (data3 * (256 - ratio) + data3p * ratio) >> 8; + data2 = data0; + data2 = data2 << 1; + data3 = data1; + data3 = data3 << 1; + + if (SAEV_config.audio.filter) { + data2 = filter(data2, sound_filter_state[0]); + data3 = filter(data3, sound_filter_state[1]); + } + + put_sound_word_right(data2); + put_sound_word_left(data3); + paula.pointer++; + paula.currrent++; + check_sound_buffers(); + } + + function sample16si_crux_handler() { + var data0, data1, data2, data3, data0p, data1p, data2p, data3p; + if (audio_channel[0].enabled) { + data0 = audio_channel[0].current_sample * audio_channel[0].vol; + data0p = audio_channel[0].last_sample * audio_channel[0].vol; + } else data0 = data0p = 0; + if (audio_channel[1].enabled) { + data1 = audio_channel[1].current_sample * audio_channel[1].vol; + data1p = audio_channel[1].last_sample * audio_channel[1].vol; + } else data1 = data1p = 0; + if (audio_channel[2].enabled) { + data2 = audio_channel[2].current_sample * audio_channel[2].vol; + data2p = audio_channel[2].last_sample * audio_channel[2].vol; + } else data2 = data2p = 0; + if (audio_channel[3].enabled) { + data3 = audio_channel[3].current_sample * audio_channel[3].vol; + data3p = audio_channel[3].last_sample * audio_channel[3].vol; + } else data3 = data3p = 0; + + { + var cdp, ratio, ratio1; + var INTERVAL = scaled_sample_evtime * 3; + + cdp = audio_channel[0]; + ratio1 = cdp.per - cdp.evtime; + ratio = ~~((ratio1 << 12) / INTERVAL); + if (cdp.evtime < scaled_sample_evtime || ratio1 >= INTERVAL) + ratio = 4096; + data0 = (data0 * ratio + data0p * (4096 - ratio)) >> 12; + + cdp = audio_channel[1]; + ratio1 = cdp.per - cdp.evtime; + ratio = ~~((ratio1 << 12) / INTERVAL); + if (cdp.evtime < scaled_sample_evtime || ratio1 >= INTERVAL) + ratio = 4096; + data1 = (data1 * ratio + data1p * (4096 - ratio)) >> 12; + + cdp = audio_channel[2]; + ratio1 = cdp.per - cdp.evtime; + ratio = ~~((ratio1 << 12) / INTERVAL); + if (cdp.evtime < scaled_sample_evtime || ratio1 >= INTERVAL) + ratio = 4096; + data2 = (data2 * ratio + data2p * (4096 - ratio)) >> 12; + + cdp = audio_channel[3]; + ratio1 = cdp.per - cdp.evtime; + ratio = ~~((ratio1 << 12) / INTERVAL); + if (cdp.evtime < scaled_sample_evtime || ratio1 >= INTERVAL) + ratio = 4096; + data3 = (data3 * ratio + data3p * (4096 - ratio)) >> 12; + } + data1 += data2; + data0 += data3; + data2 = data0; + data2 = data2 << 1; + data3 = data1; + data3 = data3 << 1; + + if (SAEV_config.audio.filter) { + data2 = filter(data2, sound_filter_state[0]); + data3 = filter(data3, sound_filter_state[1]); + } + + put_sound_word_right(data2); + put_sound_word_left(data3); + paula.pointer++; + paula.currrent++; + check_sound_buffers(); + } + + /*-----------------------------------------------------------------------*/ + + function zerostate(nr) { + var cdp = audio_channel[nr]; + cdp.state = 0; + cdp.evtime = MAX_EV; + cdp.intreq2 = 0; + cdp.dmaenstore = false; + cdp.dmaofftime_active = false; + } + + function schedule_audio() { + var best = MAX_EV; + + SAER_Events_eventtab[SAEC_Events_EV_AUDIO].active = false; + SAER_Events_eventtab[SAEC_Events_EV_AUDIO].oldcycles = SAEV_Events_currcycle; + for (var i = 0; i < audio_channel_count; i++) { + var cdp = audio_channel[i]; + if (cdp.evtime != MAX_EV) { + if (best > cdp.evtime) { + best = cdp.evtime; + SAER_Events_eventtab[SAEC_Events_EV_AUDIO].active = true; + } + } + } + SAER_Events_eventtab[SAEC_Events_EV_AUDIO].evtime = SAEV_Events_currcycle + best; + } + + function audio_event_reset() { + last_cycles = SAEV_Events_currcycle; + next_sample_evtime = scaled_sample_evtime; + + for (var i = 0; i < AUDIO_CHANNELS_PAULA; i++) + zerostate(i); + + schedule_audio(); + SAER.events.schedule(); + } + + function audio_deactivate() { + //SAER.gui.data.sndbuf_status = 3; + //SAER.gui.data.sndbuf = 0; + audio_work_to_do = 0; + //pause_sound_buffer(); + clear_sound_buffers(); + audio_event_reset(); + } + SAER_Audio_deactivate = audio_deactivate; /* used by cpu.cpu_halt() */ + + function audio_activate() { + var ret = false; + + if (audio_work_to_do == 0) { + //restart_sound_buffer(); + audio_event_reset(); + + cache.wait = true; + ret = true; + } + audio_work_to_do = 4 * SAER.playfield.get_maxvpos_nom() * 50; + return ret; + } + + /*-----------------------------------------------------------------------*/ + /* DMAL */ + + this.getpt = function(nr, reset) { //audio_getpt() + var cdp = audio_channel[nr]; + var p = cdp.pt; + cdp.pt += 2; + if (reset) + cdp.pt = cdp.lc; + cdp.ptx_tofetch = false; + return p; + } + this.dmal = function() { //audio_dmal() + var dmal = 0; + for (var nr = 0; nr < AUDIO_CHANNELS_PAULA; nr++) { + var cdp = audio_channel[nr]; + if (cdp.dr) dmal |= 1 << (nr * 2); + if (cdp.dsr) dmal |= 1 << (nr * 2 + 1); + cdp.dr = cdp.dsr = false; + } + return dmal; + } + + /*-----------------------------------------------------------------------*/ + + function isirq(nr) { + //return (SAER.custom.INTREQR() & (0x80 << nr)) != 0; + return (SAEV_Custom_intreq & (0x80 << nr)) != 0; + } + + function setirq(nr, which) { + SAER.custom.INTREQ_0(SAEC_Custom_INTF_SETCLR | (0x80 << nr)); + } + + function newsample(nr, sample) { + var cdp = audio_channel[nr]; + //if (!(audio_channel_mask & (1 << nr))) sample = 0; + if (sample & 0x80) sample -= 0x100; //OWN + cdp.last_sample = cdp.current_sample; + cdp.current_sample = sample; + } + + function setdr(nr) { + var cdp = audio_channel[nr]; + cdp.drhpos = SAER.events.current_hpos(); + cdp.dr = true; + if (cdp.wlen == 1) + cdp.dsr = true; + } + + function loaddat(nr, modper) { + var cdp = audio_channel[nr]; + var audav = SAEV_Custom_adkcon & (0x01 << nr); + var audap = SAEV_Custom_adkcon & (0x10 << nr); + if (audav || (modper && audap)) { + if (nr >= 3) + return; + var cdp1 = audio_channel[nr + 1]; //OWN + if (modper && audap) { + if (cdp.dat == 0) + cdp1.per = 65536 * SAEC_Events_CYCLE_UNIT; + else if (cdp.dat > PERIOD_MIN) + cdp1.per = cdp.dat * SAEC_Events_CYCLE_UNIT; + else + cdp1.per = PERIOD_MIN * SAEC_Events_CYCLE_UNIT; + } else if (audav) { + cdp1.vol = cdp.dat; + cdp1.vol &= 127; + if (cdp1.vol > 64) + cdp1.vol = 64; + } + } else + cdp.dat2 = cdp.dat; + } + + function loadper(nr) { + var cdp = audio_channel[nr]; + + cdp.evtime = cdp.per; + if (cdp.evtime < SAEC_Events_CYCLE_UNIT) + SAEF_error("audio.LOADPER%d bug %d", nr, cdp.evtime); + } + + function audio_state_channel2(nr, perfin) { + var cdp = audio_channel[nr]; + var chan_ena = (SAEV_Custom_dmacon & SAEC_Custom_DMAF_DMAEN) != 0 && (SAEV_Custom_dmacon & (1 << nr)) != 0; + var old_dma = cdp.dmaenstore; + var audav = SAEV_Custom_adkcon & (0x01 << nr); + var audap = SAEV_Custom_adkcon & (0x10 << nr); var napnav = (!audav && !audap) || audav; - this.dmaenstore = chan_ena; + var hpos = SAER.events.current_hpos(); - if (!AMIGA.config.audio.enabled) { - this.zerostate(); + cdp.dmaenstore = chan_ena; + + if (SAEV_config.audio.mode == SAEC_Config_Audio_Mode_Off) { + zerostate(nr); return; } - AMIGA.audio.activate(); + audio_activate(); - if ((this.state == 2 || this.state == 3) && AMIGA.config.cpu.speed == SAEV_Config_CPU_Speed_Maximum && !chan_ena && old_dma) { - //if (debugchannel(this.num)) BUG.info('Audio.channel[%d].state_channel2() INSTADMAOFF', this.num); - this.newsample(this.dat2 & 0xff); - if (napnav) - this.setirq(91); - this.zerostate(); - return; + if ((cdp.state == 2 || cdp.state == 3) && usehacks) { + if (!chan_ena && old_dma) { + // DMA switched off, state=2/3 and "too fast CPU": set flag + cdp.dmaofftime_active = true; + } + if (cdp.dmaofftime_active && !old_dma && chan_ena) { + // We are still in state=2/3 and program is going to re-enable + // DMA. Force state to zero to prevent CPU timed DMA wait + // routines in common tracker players to lose notes. + newsample(nr, cdp.dat2 & 0xff); + /*#if 0 + if (napnav) setirq(nr, 91); + #endif*/ + zerostate (nr); + } } - //if (debugchannel(this.num) && old_dma != chan_ena) BUG.info('Audio.channel[%d].state_channel2() DMA %d, IRQ %d', this.num, chan_ena ? 1 : 0, this.isirq() ? 1 : 0); - - switch (this.state) { + switch (cdp.state) { case 0: { if (chan_ena) { - this.evtime = CYCLE_MAX; - this.state = 1; - this.dr = true; - this.wlen = this.len; - this.ptx_written = false; - if (this.wlen > 2) - this.ptx_tofetch = true; - this.dsr = true; - //if (debugchannel(this.num)) BUG.info('Audio.channel[%d].state_channel2() 0>1, LEN %d', this.num, this.wlen); - } else if (this.dat_written && !this.isirq()) { - this.state = 2; - this.setirq(0); - this.loaddat(false); - if (AMIGA.config.cpu.speed == SAEV_Config_CPU_Speed_Maximum && this.per < 10 * CYCLE_UNIT) { - this.newsample(this.dat2 & 0xff); - this.zerostate(); + cdp.evtime = MAX_EV; + cdp.state = 1; + cdp.dr = true; + cdp.drhpos = hpos; + cdp.wlen = cdp.len; + cdp.ptx_written = false; + /* Some programs first start short empty sample and then later switch to + * real sample, we must not enable the hack in this case */ + if (cdp.wlen > 2) + cdp.ptx_tofetch = true; + cdp.dsr = true; + } else if (cdp.dat_written && !isirq(nr)) { + cdp.state = 2; + setirq(nr, 0); + loaddat(nr, false); + if (usehacks && cdp.per < 10 * SAEC_Events_CYCLE_UNIT) { + // make sure audio.device AUDxDAT startup returns to idle state before DMA is enabled + newsample(nr, cdp.dat2 & 0xff); + zerostate(nr); } else { - this.pbufldl = true; - this.state_channel2(false); + cdp.pbufldl = true; + audio_state_channel2(nr, false); } } else { - this.zerostate(); + zerostate(nr); } break; } case 1: { - this.evtime = CYCLE_MAX; + cdp.evtime = MAX_EV; if (!chan_ena) { - this.zerostate(); + zerostate(nr); return; } - if (!this.dat_written) + if (!cdp.dat_written) return; - this.setirq(10); - this.setdr(); - if (this.wlen != 1) { - //this.wlen = (this.wlen - 1) & 0xffff; - if ((--this.wlen) < 0) this.wlen = 0xffff; - } - this.state = 5; + + setirq(nr, 10); + setdr(nr); + if (cdp.wlen != 1) + cdp.wlen = ((cdp.wlen - 1) >>> 0) & 0xffff; + cdp.state = 5; break; } case 5: { - this.evtime = CYCLE_MAX; + cdp.evtime = MAX_EV; if (!chan_ena) { - this.zerostate(); + zerostate(nr); return; } - if (!this.dat_written) + if (!cdp.dat_written) return; - //if (debugchannel(this.num)) BUG.info('Audio.channel[%d].state_channel2() >5, LEN %d', this.num, this.wlen); - if (this.ptx_written) { - this.ptx_written = false; - this.lc = this.ptx; + + if (cdp.ptx_written) { + cdp.ptx_written = 0; + cdp.lc = cdp.ptx; } - this.loaddat(false); + loaddat(nr, false); if (napnav) - this.setdr(); - this.state = 2; - this.loadper(); - this.pbufldl = true; - this.intreq = false; - this.state_channel2(false); + setdr(nr); + cdp.state = 2; + loadper(nr); + cdp.pbufldl = true; + cdp.intreq2 = 0; + audio_state_channel2(nr, false); break; } case 2: { - if (this.pbufldl) { - this.newsample((this.dat2 >> 8) & 0xff); - this.loadper(); - this.pbufldl = false; + if (cdp.pbufldl) { + newsample(nr, (cdp.dat2 >> 8) & 0xff); + loadper(nr); + cdp.pbufldl = false; } if (!perfin) return; if (audap) - this.loaddat(true); + loaddat(nr, true); if (chan_ena) { if (audap) - this.setdr(); - if (this.intreq && audap) - this.setirq(21); + setdr(nr); + if (cdp.intreq2 && audap) + setirq(nr, 21); } else { if (audap) - this.setirq(22); + setirq(nr, 22); } - this.pbufldl = true; - this.state = 3; - this.state_channel2(false); + cdp.pbufldl = true; + cdp.state = 3; + audio_state_channel2(nr, false); break; } case 3: { - if (this.pbufldl) { - this.newsample((this.dat2 >> 0) & 0xff); - this.loadper(); - this.pbufldl = false; + if (cdp.pbufldl) { + newsample(nr, cdp.dat2 & 0xff); + loadper(nr); + cdp.pbufldl = false; } if (!perfin) return; if (chan_ena) { - this.loaddat(false); - if (this.intreq && napnav) - this.setirq(31); + loaddat(nr, false); + if (cdp.intreq2 && napnav) + setirq(nr, 31); if (napnav) - this.setdr(); + setdr(nr); } else { - if (this.isirq()) { - //if (debugchannel(this.num)) BUG.info('Audio.channel[%d].state_channel2() IDLE', this.num); - this.zerostate(); + if (isirq(nr)) { + zerostate(nr); return; } - this.loaddat(false); + loaddat(nr, false); if (napnav) - this.setirq(32); + setirq(nr, 32); } - this.intreq = false; - this.pbufldl = true; - this.state = 2; - this.state_channel2(false); + cdp.intreq2 = 0; + cdp.pbufldl = true; + cdp.state = 2; + audio_state_channel2(nr, false); break; } } } -} - -function Audi0() { - const SAMPLE_BUFFER_SIZE = 8192; - this.available = 0; - - var channel = null; - - var last_cycles = 0; - var next_sample_evtime = 0; - var scaled_sample_evtime_orig = 0; - var scaled_sample_evtime = 0; - - var amiga_sample_rate = 0; - - var work_to_do = 0; - var prevcon = -1; - - var driver = { - ctx: null, - node: null, - paused:false - }; - var sampleBuffer = { - size: 0, - data: { - left: null, - right: null - }, - pos: 0 - }; - var resampleBuffer = { - size: 0, - data: { - left: null, - right: null - }, - len: 0 - }; - var queueBuffer = { - size: 0, - data: { - left: null, - right: null - }, - usage: 0 - }; - var outputBuffer = { - size: 0, - data: { - left: null, - right: null - }, - len: 0 - }; - - this.filter = new Filter(); - - /*---------------------------------*/ - - //this.init = function() - { - var test; - - try { - test = new AudioContext(); - if (test && (test.createJavaScriptNode || test.createScriptProcessor)) - this.available |= SAEI_Audio_WebAudio; - test = null; - } catch (e) {} - - //console.log(this.available); - } - - /*---------------------------------*/ - - /*this.calc_sample_evtime = function (hz, longframe, linetoggle) { - var lines = AMIGA.playfield.maxvpos_nom; - var hpos = AMIGA.playfield.maxhpos_short; - - if (Math.abs(hz-50) < 2) - amiga_sample_rate = CHIPSET_CLOCK_PAL / 123; - else - amiga_sample_rate = CHIPSET_CLOCK_NTSC / 124; - - if (linetoggle) { - hpos += 0.5; - lines += 0.5; - } else { - if (longframe < 0) - lines += 0.5; - else if (longframe > 0) - lines += 1.0; - } - scaled_sample_evtime_orig = hpos * lines * hz / amiga_sample_rate * CYCLE_UNIT; - scaled_sample_evtime = scaled_sample_evtime_orig; - - BUG.info('Audio.calc_sample_evtime() hmax %d, vmax %d, hz %f, rate %f | scaled_sample_evtime %f', hpos, lines, hz, amiga_sample_rate, scaled_sample_evtime * CYCLE_UNIT_INV); - };*/ - - this.calc_sample_evtime = function (hz, longframe, linetoggle) { - if (Math.abs(hz - 50.0) <= 1.5) { - amiga_sample_rate = CHIPSET_CLOCK_PAL / 123; - scaled_sample_evtime_orig = 123 * CYCLE_UNIT; - BUG.info('Audio.calc_sample_evtime() PAL mode, rate %f, scaled_sample_evtime %f', amiga_sample_rate, scaled_sample_evtime_orig * CYCLE_UNIT_INV); - } else { - amiga_sample_rate = CHIPSET_CLOCK_NTSC / 124; - scaled_sample_evtime_orig = 124 * CYCLE_UNIT; - BUG.info('Audio.calc_sample_evtime() NTSC mode, rate %f, scaled_sample_evtime %f', amiga_sample_rate, scaled_sample_evtime_orig * CYCLE_UNIT_INV); - } - scaled_sample_evtime = scaled_sample_evtime_orig; - - this.filter.setup(AMIGA.config.audio.filter, amiga_sample_rate); /* A500 lowpass-filter */ - }; - - this.setup = function () { - if (channel === null) { - channel = []; - for (var i = 0; i < 4; i++) - channel[i] = new Channel(i); + function audio_state_channel(nr, perfin) { + var cdp = audio_channel[nr]; + if (nr < AUDIO_CHANNELS_PAULA) { + audio_state_channel2(nr, perfin); + cdp.dat_written = false; } - if (!AMIGA.config.audio.enabled || AMIGA.config.audio.mode == SAEV_Config_Audio_Mode_Emul) - return; + } - if (driver.ctx === null) { - if (this.available & SAEI_Audio_WebAudio) - driver.ctx = new AudioContext(); - } - if (driver.ctx === null) { - if (confirm('Can\'t initialise WebAudio. Continue without audio-playback?')) { - AMIGA.config.audio.mode = SAEV_Config_Audio_Mode_Emul; - return; - } else - Fatal(SAEE_Audio_WebAudio_Not_Avail, null); - } - - this.calc_sample_evtime(AMIGA.config.video.ntsc ? 60 : 50, 1, AMIGA.config.video.ntsc); - - sampleBuffer.size = SAMPLE_BUFFER_SIZE * 2; - sampleBuffer.data.left = new Float32Array(sampleBuffer.size); - if (AMIGA.config.audio.channels == SAEV_Config_Audio_Channels_Stereo) - sampleBuffer.data.right = new Float32Array(sampleBuffer.size); - - resampleBuffer.size = SAMPLE_BUFFER_SIZE * 2; - resampleBuffer.data.left = new Float32Array(resampleBuffer.size); - if (AMIGA.config.audio.channels == SAEV_Config_Audio_Channels_Stereo) - resampleBuffer.data.right = new Float32Array(resampleBuffer.size); - - queueBuffer.size = SAMPLE_BUFFER_SIZE * 8; - queueBuffer.data.left = new Float32Array(queueBuffer.size); - if (AMIGA.config.audio.channels == SAEV_Config_Audio_Channels_Stereo) - queueBuffer.data.right = new Float32Array(queueBuffer.size); - - outputBuffer.size = SAMPLE_BUFFER_SIZE; - outputBuffer.data.left = new Float32Array(outputBuffer.size); - if (AMIGA.config.audio.channels == SAEV_Config_Audio_Channels_Stereo) - outputBuffer.data.right = new Float32Array(outputBuffer.size); - - if (this.available & SAEI_Audio_WebAudio) { - if (driver.ctx.createJavaScriptNode) - driver.node = driver.ctx.createJavaScriptNode(SAMPLE_BUFFER_SIZE, 1, AMIGA.config.audio.channels); - else if (driver.ctx.createScriptProcessor) - driver.node = driver.ctx.createScriptProcessor(SAMPLE_BUFFER_SIZE, 1, AMIGA.config.audio.channels); - - if (driver.node) { - driver.node.onaudioprocess = audioProcess; - driver.node.connect(driver.ctx.destination); - } - } - }; - - this.cleanup = function () { - if (driver.ctx !== null) { - if (this.available & SAEI_Audio_WebAudio) { - if (driver.node) { - driver.node.disconnect(driver.ctx.destination); - driver.node.onaudioprocess = null; - driver.node = null; - } - } - } - }; - - this.pauseResume = function (pause) { - if (!AMIGA.config.audio.enabled || AMIGA.config.audio.mode == SAEV_Config_Audio_Mode_Emul) return; - - if (driver.ctx !== null) { - if (this.available & SAEI_Audio_WebAudio) { - if (driver.node) { - if (pause && !driver.paused) { - driver.node.disconnect(driver.ctx.destination); - driver.node.onaudioprocess = null; - driver.paused = true; - } else if (!pause && driver.paused) { - driver.node.onaudioprocess = audioProcess; - driver.node.connect(driver.ctx.destination); - driver.paused = false; - } - } - } - } - }; - - this.reset = function () { - for (var i = 0; i < 4; i++) - channel[i].reset(); - - last_cycles = AMIGA.events.currcycle; - next_sample_evtime = scaled_sample_evtime; - this.schedule(); - AMIGA.events.schedule(); - - work_to_do = 0; - prevcon = 0; - - sampleBuffer.pos = 0; - queueBuffer.usage = 0; - - this.filter.reset(); - }; - - /*---------------------------------*/ - - this.event_reset = function () { - for (var i = 0; i < 4; i++) - channel[i].zerostate(); - - last_cycles = AMIGA.events.currcycle; - next_sample_evtime = scaled_sample_evtime; - this.schedule(); - AMIGA.events.schedule(); - }; - - this.activate = function () { - //BUG.info('Audio.activate()'); - var ret = 0; - - if (!work_to_do) { - this.pauseResume(0); - ret = 1; - this.event_reset(); - } - work_to_do = 4 * AMIGA.playfield.maxvpos_nom * 50; - return ret; - }; - - this.deactivate = function () { - //BUG.info('Audio.deactivate()'); - this.pauseResume(1); - sampleBuffer.pos = 0; - queueBuffer.usage = 0; - this.event_reset(); - }; - - this.state_machine = function () { + this.state_machine = function() { //audio_state_machine() called in SAER.custom.DMACON() this.update(); - for (var i = 0; i < 4; i++) - channel[i].state_channel(false); + for (var nr = 0; nr < AUDIO_CHANNELS_PAULA; nr++) { + var cdp = audio_channel[nr]; + audio_state_channel2(nr, false); + cdp.dat_written = false; + } + schedule_audio(); + SAER.events.schedule(); + } - this.schedule(); - AMIGA.events.schedule(); - }; + /*-----------------------------------------------------------------------*/ - this.schedule = function () { - var best = CYCLE_MAX; + this.obtain = function() { + return obtain_sound(); + } - AMIGA.events.eventtab[EV_AUDIO].active = false; - AMIGA.events.eventtab[EV_AUDIO].oldcycles = AMIGA.events.currcycle; + /* This computes the 1st order low-pass filter term b0. + The a1 term is 1.0 - b0. The center frequency marks the -3 dB point. */ + function rc_calculate_a0(sample_rate, cutoff_freq) { + var omega; + /* The BLT correction formula below blows up if the cutoff is above nyquist. */ + if (cutoff_freq >= sample_rate >> 1) + return 1.0; - for (var i = 0; i < 4; i++) { - if (channel[i].evtime != CYCLE_MAX) { - if (best > channel[i].evtime) { - best = channel[i].evtime; - AMIGA.events.eventtab[EV_AUDIO].active = true; - } + omega = 2 * Math.PI * cutoff_freq / sample_rate; + /* Compensate for the bilinear transformation. This allows us to specify the stop + frequency more exactly, but the filter becomes less steep further from stopband. */ + omega = Math.tan(omega / 2) * 2; + return 1.0 / (1.0 + 1.0 / omega); + } + + /*this.check_prefs_changed_audio = function() { + if (sound_available) { + var ch = 1; + //if (ch > 0) clear_sound_buffers(); + if (ch) { + this.set_audio(); + audio_activate(); } } - AMIGA.events.eventtab[EV_AUDIO].evtime = AMIGA.events.currcycle + best; - }; + }*/ - this.update = function () { - if (!AMIGA.config.audio.enabled || !work_to_do) { - last_cycles = AMIGA.events.currcycle; + this.setup = function() { //set_audio() + usehacks = SAEV_config.cpu.model >= SAEC_Config_CPU_Model_68020 || SAEV_config.cpu.speed != SAEC_Config_CPU_Speed_Original;// || (currprefs.cs_hacks & 4); + + //used_freq = SAEV_config.chipset.ntsc ? PAULA_FREQ_NTSC : PAULA_FREQ_PAL; + used_freq = SAEC_Config_Audio_Freq_44100; + + paula.frames = SAEV_config.audio.bufferFrames; + paula.buffer = new Array(2); //max channels + for (var j = 0; j < paula.buffer.length; j++) + paula.buffer[j] = new Int16Array(paula.frames); + + //paula_size = SAEV_config.audio.bufferFrames * SAEV_config.audio.channels * 2; + //paula_pointer = paula_buffer; + paula.pointer = 0; + paula.currrent = 0; + + if (SAEV_config.audio.mode >= SAEC_Config_Audio_Mode_On) { + if (!setup_sound()) + return SAEE_Audio_RequiresWebAudio; //can't happen cos we fail on audio.obtain() + } + + next_sample_evtime = scaled_sample_evtime; + last_cycles = SAEV_Events_currcycle; + //SAER.playfield.compute_vsynctime_ext(); //OWN unused SAEV_Audio_vsynctimebase_orig + + var sep = SAEV_config.audio.stereoSeparation * 3 >> 1; + if (sep >= 15) sep = 16; + mixed_mul1 = (MIXED_STEREO_SCALE >> 1) - sep; + mixed_mul2 = (MIXED_STEREO_SCALE >> 1) + sep; + + var delay = SAEV_config.audio.stereoDelay; + mixed_stereo_size = delay > 0 ? (1 << delay) - 1 : 0; + + mixed_on = sep < MIXED_STEREO_MAX || mixed_stereo_size > 0; + if (mixed_on) { + SAEF_log("audio.setup() mixing enabled"); + saved_ptr = 0; + SAEF_memset(right_word_saved,0, 0, SOUND_MAX_DELAY_BUFFER); + } + + led_filter_forced = -1; // always off + sound_use_filter = 0; + if (SAEV_config.audio.filter) { + if (SAEV_config.audio.filter == SAEC_Config_Audio_Filter_On) + led_filter_forced = 1; + if (SAEV_config.audio.filter == SAEC_Config_Audio_Filter_Emul) + led_filter_forced = 0; + if (SAEV_config.audio.filterType == SAEC_Config_Audio_FilterType_A500) + sound_use_filter = FILTER_MODEL_A500; + else if (SAEV_config.audio.filterType == SAEC_Config_Audio_FilterType_A1200) + sound_use_filter = FILTER_MODEL_A1200; + } + a500e_filter1_a0 = rc_calculate_a0(used_freq, 6200); + a500e_filter2_a0 = rc_calculate_a0(used_freq, 20000); + filter_a0 = rc_calculate_a0(used_freq, 7000); + this.led_filter_audio(); + + switch (SAEV_config.audio.interpol) { + case SAEC_Config_Audio_Interpol_None: { + switch (SAEV_config.audio.channels) { + case SAEC_Config_Audio_Channels_Mono: sample_handler = sample16_mono_handler; break; + case SAEC_Config_Audio_Channels_Stereo: sample_handler = sample16s_handler; break; + } + break; + } + case SAEC_Config_Audio_Interpol_Anti: { + switch (SAEV_config.audio.channels) { + case SAEC_Config_Audio_Channels_Mono: sample_handler = sample16i_anti_mono_handler; break; + case SAEC_Config_Audio_Channels_Stereo: sample_handler = sample16si_anti_handler; break; + } + break; + } + case SAEC_Config_Audio_Interpol_RH: { + switch (SAEV_config.audio.channels) { + case SAEC_Config_Audio_Channels_Mono: sample_handler = sample16i_rh_mono_handler; break; + case SAEC_Config_Audio_Channels_Stereo: sample_handler = sample16si_rh_handler; break; + } + break; + } + case SAEC_Config_Audio_Interpol_Crux: { + switch (SAEV_config.audio.channels) { + case SAEC_Config_Audio_Channels_Mono: sample_handler = sample16i_crux_mono_handler; break; + case SAEC_Config_Audio_Channels_Stereo: sample_handler = sample16si_crux_handler; break; + } + break; + } + } + sample_prehandler = null; + if (SAEV_config.audio.interpol == SAEC_Config_Audio_Interpol_Anti) + sample_prehandler = anti_prehandler; + + if (SAEV_config.audio.mode == SAEC_Config_Audio_Mode_Off) { + SAER_Events_eventtab[SAEC_Events_EV_AUDIO].active = false; + SAER.events.schedule(); + } else { + audio_activate(); + //schedule_audio(); //OWN makes no sense + //SAER.events.schedule(); + } + return SAEE_None; + } + + this.cleanup = function() { + cleanup_sound(); + } + + this.reset = function() { + var i; + + reset_sound(); + + for (i = 0; i < sound_filter_state.length; i++) + sound_filter_state[i].clr(); + + for (i = 0; i < AUDIO_CHANNELS_MAX; i++) { + var cdp = audio_channel[i]; + cdp.clr(); + cdp.per = PERIOD_MAX - 1; + cdp.vol = 0; + cdp.evtime = MAX_EV; + } + + last_cycles = SAEV_Events_currcycle; + next_sample_evtime = scaled_sample_evtime; + schedule_audio(); + SAER.events.schedule(); + + prevcon = -1; //OWN + } + + this.pauseResume = function(pause) { + if (pause) + pause_sound(); + else + resume_sound(); + } + + /*-----------------------------------------------------------------------*/ + + var prevcon = -1; + this.update_adkmasks = function() { + //static int prevcon = -1; + var t = SAEV_Custom_adkcon | (SAEV_Custom_adkcon >> 4); + + /*audio_channel[0].adk_mask = (((t >> 0) & 1) - 1) >>> 0; + audio_channel[1].adk_mask = (((t >> 1) & 1) - 1) >>> 0; + audio_channel[2].adk_mask = (((t >> 2) & 1) - 1) >>> 0; + audio_channel[3].adk_mask = (((t >> 3) & 1) - 1) >>> 0;*/ + audio_channel[0].enabled = (t & 1) == 0; + audio_channel[1].enabled = (t & 3) == 0; + audio_channel[2].enabled = (t & 7) == 0; + audio_channel[3].enabled = (t & 15) == 0; + + if ((prevcon & 0xff) != (SAEV_Custom_adkcon & 0xff)) { + audio_activate(); + prevcon = SAEV_Custom_adkcon; + } + } + + this.update = function() { + var n_cycles = 0; + + if (SAEV_config.audio.mode == SAEC_Config_Audio_Mode_Off || audio_work_to_do == 0) { + last_cycles = SAEV_Events_currcycle; return; } - var n_cycles = AMIGA.events.currcycle - last_cycles; + n_cycles = SAEV_Events_currcycle - last_cycles; while (n_cycles > 0) { var best_evtime = n_cycles + 1; - var i, rounded; + var rounded; + var i; - for (i = 0; i < 4; i++) { - if (channel[i].evtime != CYCLE_MAX && best_evtime > channel[i].evtime) - best_evtime = channel[i].evtime; + for (i = 0; i < audio_channel_count; i++) { + if (audio_channel[i].evtime != MAX_EV && best_evtime > audio_channel[i].evtime) + best_evtime = audio_channel[i].evtime; } - rounded = Math.floor(next_sample_evtime); + /* next_sample_evtime >= 0 so floor() behaves as expected + rounded = floor(next_sample_evtime); if ((next_sample_evtime - rounded) >= 0.5) - rounded++; + rounded++; */ + rounded = Math.round(next_sample_evtime); - if (AMIGA.config.audio.mode != SAEV_Config_Audio_Mode_Emul && best_evtime > rounded) + if (SAEV_config.audio.mode > SAEC_Config_Audio_Mode_Off_Emul && best_evtime > rounded) best_evtime = rounded; if (best_evtime > n_cycles) best_evtime = n_cycles; + /* Decrease time-to-wait counters */ next_sample_evtime -= best_evtime; - - /*if (AMIGA.config.audio.mode != SAEV_Config_Audio_Mode_Emul) { - if (sample_prehandler) - sample_prehandler (best_evtime / CYCLE_UNIT); - }*/ - - for (i = 0; i < 4; i++) { - if (channel[i].evtime != CYCLE_MAX) - channel[i].evtime -= best_evtime; + if (SAEV_config.audio.mode > SAEC_Config_Audio_Mode_Off_Emul) { + if (sample_prehandler !== null) + sample_prehandler(Math.floor(best_evtime * SAEC_Events_CYCLE_UNIT_INV)); } + + for (i = 0; i < audio_channel_count; i++) { + if (audio_channel[i].evtime != MAX_EV) + audio_channel[i].evtime -= best_evtime; + } + n_cycles -= best_evtime; - if (AMIGA.config.audio.mode != SAEV_Config_Audio_Mode_Emul) { + if (SAEV_config.audio.mode > SAEC_Config_Audio_Mode_Off_Emul) { + /* Test if new sample needs to be outputted */ if (rounded == best_evtime) { + /* Before the following addition, next_sample_evtime is in range [-0.5, 0.5) */ next_sample_evtime += scaled_sample_evtime; - this.sample_handler_def(); - //this.sample_handler_crux(); - //this.sample_handler_rh(); + sample_handler(); } } - for (i = 0; i < 4; i++) { - if (channel[i].evtime == 0) { - channel[i].state_channel(true); - if (channel[i].evtime == 0) { - BUG.info('Audio.update() sound bug in channel %d (evtime == 0)', i); - channel[i].evtime = CYCLE_MAX; + for (i = 0; i < audio_channel_count; i++) { + if (audio_channel[i].evtime == 0) { + audio_state_channel(i, true); + if (audio_channel[i].evtime == 0) { + SAEF_error("audio.update() evtime == 0 (channel %d)", i); + audio_channel[i].evtime = MAX_EV; } } } } - last_cycles = AMIGA.events.currcycle - n_cycles; - }; + last_cycles = SAEV_Events_currcycle - n_cycles; + } - this.update_adkmasks = function () { - var t = AMIGA.adkcon | (AMIGA.adkcon >> 4); - - channel[0].enabled = ((t >> 0) & 1) == 0; - channel[1].enabled = ((t >> 1) & 1) == 0; - channel[2].enabled = ((t >> 2) & 1) == 0; - channel[3].enabled = ((t >> 3) & 1) == 0; - - if ((prevcon & 0xff) != (AMIGA.adkcon & 0xff)) { - this.activate(); - prevcon = AMIGA.adkcon; - } - }; - - this.handler = function () { + this.handler = function() { //audio_evhandler() this.update(); - this.schedule(); - }; + schedule_audio(); + } - this.hsync = function () { - if (work_to_do > 0) { - if (--work_to_do == 0) - this.deactivate(); + this.hsync = function() { //audio_hsync() + //if (SAEV_config.audio.mode == SAEC_Config_Audio_Mode_Off) return; //OWN done in custom/devices_hsync() + if (audio_work_to_do > 0) { + audio_work_to_do--; + if (audio_work_to_do == 0) + audio_deactivate(); } this.update(); - }; - - this.vsync = function () { - }; - - /*---------------------------------*/ + } - this.AUDxDAT = function (nr, v) { - //BUG.info('AUD%dDAT %x', nr, v); - channel[nr].dat = v; - channel[nr].dat_written = true; - if (channel[nr].state == 2 || channel[nr].state == 3) { - var chan_ena = ((AMIGA.dmacon & DMAF_DMAEN) && (AMIGA.dmacon & (1 << nr))) ? true : false; + this.vsync = function() { //audio_vsync() + + } + + this.AUDxDAT = function(nr, v) { + var cdp = audio_channel[nr]; + var chan_ena = (SAEV_Custom_dmacon & SAEC_Custom_DMAF_DMAEN) != 0 && (SAEV_Custom_dmacon & (1 << nr)) != 0; + + cdp.dat = v; + cdp.dat_written = true; + if (cdp.state == 2 || cdp.state == 3) { if (chan_ena) { - if (channel[nr].wlen == 1) { - channel[nr].wlen = channel[nr].len; - channel[nr].intreq = true; - } else { - //channel[nr].wlen = (channel[nr].wlen - 1) & 0xffff; - if ((--channel[nr].wlen) < 0) channel[nr].wlen = 0xffff; - } + if (cdp.wlen == 1) { + cdp.wlen = cdp.len; + cdp.intreq2 = true; + } else + cdp.wlen = ((cdp.wlen - 1) >>> 0) & 0xffff; } } else { - this.activate(); + audio_activate(); this.update(); - channel[nr].state_channel(false); - this.schedule(); - AMIGA.events.schedule(); + audio_state_channel(nr, false); + schedule_audio(); + SAER.events.schedule(); } - channel[nr].dat_written = false; - }; + cdp.dat_written = false; + } - this.AUDxPER = function (nr, v) { - this.activate(); + this.AUDxLCH = function(nr, v) { + var cdp = audio_channel[nr]; + audio_activate(); this.update(); - var per = v * CYCLE_UNIT; + v = v & (SAEV_config.chipset.mask == SAEC_Config_Chipset_Mask_OCS ? 7 : 31); //OWN + + /* Someone wants to update PT but DSR has not yet been processed. + Too fast CPU and some tracker players: enable DMA, CPU delay, update AUDxPT with loop position*/ + if (usehacks && ((cdp.ptx_tofetch && cdp.state == 1) || cdp.ptx_written)) { + cdp.ptx = cdp.lc; + cdp.ptx_written = true; + } else + cdp.lc = ((v << 16) | (cdp.lc & 0x0000ffff)) >>> 0; + } + + this.AUDxLCL = function(nr, v) { + var cdp = audio_channel[nr]; + audio_activate(); + this.update(); + if (usehacks && ((cdp.ptx_tofetch && cdp.state == 1) || cdp.ptx_written)) { + cdp.ptx = cdp.lc; + cdp.ptx_written = true; + } else + cdp.lc = ((cdp.lc & 0xffff0000) | (v & 0xFFFE)) >>> 0; + } + + this.AUDxPER = function(nr, v) { + var cdp = audio_channel[nr]; + + audio_activate(); + this.update(); + + var per = v * SAEC_Events_CYCLE_UNIT; if (per == 0) per = PERIOD_MAX - 1; - if (per < PERIOD_MIN * CYCLE_UNIT) - per = PERIOD_MIN * CYCLE_UNIT; - if (per < PERIOD_MIN_NONCE * CYCLE_UNIT && channel[nr].dmaenstore) - per = PERIOD_MIN_NONCE * CYCLE_UNIT; + if (per < PERIOD_MIN * SAEC_Events_CYCLE_UNIT) + per = PERIOD_MIN * SAEC_Events_CYCLE_UNIT; + if (per < PERIOD_MIN_NONCE * SAEC_Events_CYCLE_UNIT && cdp.dmaenstore) + per = PERIOD_MIN_NONCE * SAEC_Events_CYCLE_UNIT; - if (channel[nr].per == PERIOD_MAX - 1 && per != PERIOD_MAX - 1) { - channel[nr].evtime = CYCLE_UNIT; - if (AMIGA.config.audio.enabled) { - this.schedule(); - AMIGA.events.schedule(); + if (cdp.per == PERIOD_MAX - 1 && per != PERIOD_MAX - 1) { + cdp.evtime = SAEC_Events_CYCLE_UNIT; + if (SAEV_config.audio.mode != SAEC_Config_Audio_Mode_Off) { + schedule_audio(); + SAER.events.schedule(); } } - channel[nr].per = per; - //if (debugchannel(nr)) BUG.info('AUD%dPER() %x', nr, v); - }; + cdp.per = per; + } - this.AUDxLEN = function (nr, v) { - this.activate(); + this.AUDxLEN = function(nr, v) { + audio_activate(); this.update(); - channel[nr].len = v; - //if (debugchannel(nr)) BUG.info('AUD%dLEN() %x', nr, v); - }; + audio_channel[nr].len = v; + } - this.AUDxVOL = function (nr, v) { + this.AUDxVOL = function(nr, v) { v &= 127; if (v > 64) v = 64; - this.activate(); + audio_activate(); this.update(); - channel[nr].vol = v; - //if (debugchannel(nr)) BUG.info('AUD%dVOL() %x', nr, v); - }; - - this.AUDxLCH = function (nr, v) { - this.activate(); - this.update(); - - if (AMIGA.config.cpu.speed == SAEV_Config_CPU_Speed_Maximum && ((channel[nr].ptx_tofetch && channel[nr].state == 1) || channel[nr].ptx_written)) { - channel[nr].ptx = channel[nr].lc; - channel[nr].ptx_written = true; - } else - channel[nr].lc = ((channel[nr].lc & 0xffff) | (v << 16)) >>> 0; - }; - - this.AUDxLCL = function (nr, v) { - this.activate(); - this.update(); - - if (AMIGA.config.cpu.speed == SAEV_Config_CPU_Speed_Maximum && ((channel[nr].ptx_tofetch && channel[nr].state == 1) || channel[nr].ptx_written)) { - channel[nr].ptx = channel[nr].lc; - channel[nr].ptx_written = true; - } else - channel[nr].lc = ((channel[nr].lc & ~0xffff) | (v & 0xfffe)) >>> 0; - }; - - /*---------------------------------*/ - - this.getpt = function (nr, reset) { - var p = channel[nr].pt; - channel[nr].pt += 2; - if (reset) - channel[nr].pt = channel[nr].lc; - channel[nr].ptx_tofetch = false; - return p; - }; - - this.dmal = function () { - var dmal = 0; - for (var nr = 0; nr < 4; nr++) { - if (channel[nr].dr) - dmal |= (1 << (nr * 2)); - if (channel[nr].dsr) - dmal |= (1 << (nr * 2 + 1)); - channel[nr].dr = channel[nr].dsr = false; - } - //if (dmal) BUG.info('Audio.dmal() %d', dmal); - return dmal; - }; - - /*---------------------------------*/ - - const inv32768 = 1.0 / 32768; - - this.sample_handler_def = function () { - var data0 = channel[0].enabled ? (channel[0].current_sample * channel[0].vol) : 0; - var data1 = channel[1].enabled ? (channel[1].current_sample * channel[1].vol) : 0; - var data2 = channel[2].enabled ? (channel[2].current_sample * channel[2].vol) : 0; - var data3 = channel[3].enabled ? (channel[3].current_sample * channel[3].vol) : 0; - - data0 += data3; - data1 += data2; - data2 = data0 << 1; - data3 = data1 << 1; - if (AMIGA.config.audio.filter) { - data2 = this.filter.filter(data2, 0); - data3 = this.filter.filter(data3, 1); - } - - if (sampleBuffer.pos < sampleBuffer.size) { - if (AMIGA.config.audio.channels == SAEV_Config_Audio_Channels_Stereo) { - sampleBuffer.data.left[sampleBuffer.pos] = inv32768 * data2; - sampleBuffer.data.right[sampleBuffer.pos] = inv32768 * data3; - sampleBuffer.pos++; - } else - sampleBuffer.data.left[sampleBuffer.pos++] = inv32768 * ((data2 + data3) * 0.5); - } //else - //BUG.info('Audio.sample_handler() audio buffer over-run!'); - }; - - this.sample_handler_crux = function () { - var data0 = channel[0].enabled ? (channel[0].current_sample * channel[0].vol) : 0; - var data1 = channel[1].enabled ? (channel[1].current_sample * channel[1].vol) : 0; - var data2 = channel[2].enabled ? (channel[2].current_sample * channel[2].vol) : 0; - var data3 = channel[3].enabled ? (channel[3].current_sample * channel[3].vol) : 0; - - var data0p = channel[0].enabled ? (channel[0].last_sample * channel[0].vol) : 0; - var data1p = channel[1].enabled ? (channel[1].last_sample * channel[1].vol) : 0; - var data2p = channel[2].enabled ? (channel[2].last_sample * channel[2].vol) : 0; - var data3p = channel[3].enabled ? (channel[3].last_sample * channel[3].vol) : 0; - - { - const INTERVAL = scaled_sample_evtime * 3; - var ratio, ratio1; - - ratio1 = channel[0].per - channel[0].evtime; - ratio = Math.floor((ratio1 << 12) / INTERVAL); - if (channel[0].evtime < scaled_sample_evtime || ratio1 >= INTERVAL) - ratio = 4096; - data0 = (data0 * ratio + data0p * (4096 - ratio)) >> 12; - - ratio1 = channel[1].per - channel[1].evtime; - ratio = Math.floor((ratio1 << 12) / INTERVAL); - if (channel[1].evtime < scaled_sample_evtime || ratio1 >= INTERVAL) - ratio = 4096; - data1 = (data1 * ratio + data1p * (4096 - ratio)) >> 12; - - ratio1 = channel[2].per - channel[2].evtime; - ratio = Math.floor((ratio1 << 12) / INTERVAL); - if (channel[2].evtime < scaled_sample_evtime || ratio1 >= INTERVAL) - ratio = 4096; - data2 = (data2 * ratio + data2p * (4096 - ratio)) >> 12; - - ratio1 = channel[3].per - channel[3].evtime; - ratio = Math.floor((ratio1 << 12) / INTERVAL); - if (channel[3].evtime < scaled_sample_evtime || ratio1 >= INTERVAL) - ratio = 4096; - data3 = (data3 * ratio + data3p * (4096 - ratio)) >> 12; - } - data0 += data3; - data1 += data2; - data2 = data0 << 1; - data3 = data1 << 1; - if (AMIGA.config.audio.filter) { - data2 = this.filter.filter(data2, 0); - data3 = this.filter.filter(data3, 1); - } - - if (sampleBuffer.pos < sampleBuffer.size) { - if (AMIGA.config.audio.channels == SAEV_Config_Audio_Channels_Stereo) { - sampleBuffer.data.left[sampleBuffer.pos] = inv32768 * data2; - sampleBuffer.data.right[sampleBuffer.pos] = inv32768 * data3; - sampleBuffer.pos++; - } else - sampleBuffer.data.left[sampleBuffer.pos++] = inv32768 * ((data2 + data3) * 0.5); - } //else - //BUG.info('Audio.sample_handler_crux() audio buffer over-run!'); - }; - - this.sample_handler_rh = function () { - var data0 = channel[0].enabled ? (channel[0].current_sample * channel[0].vol) : 0; - var data1 = channel[1].enabled ? (channel[1].current_sample * channel[1].vol) : 0; - var data2 = channel[2].enabled ? (channel[2].current_sample * channel[2].vol) : 0; - var data3 = channel[3].enabled ? (channel[3].current_sample * channel[3].vol) : 0; - var data0p = channel[0].enabled ? (channel[0].last_sample * channel[0].vol) : 0; - var data1p = channel[1].enabled ? (channel[1].last_sample * channel[1].vol) : 0; - var data2p = channel[2].enabled ? (channel[2].last_sample * channel[2].vol) : 0; - var data3p = channel[3].enabled ? (channel[3].last_sample * channel[3].vol) : 0; - - { - var delta, ratio; - - delta = channel[0].per; - ratio = Math.floor(((channel[0].evtime % delta) << 8) / delta); - data0 = (data0 * (256 - ratio) + data0p * ratio) >> 8; - delta = channel[1].per; - ratio = Math.floor(((channel[1].evtime % delta) << 8) / delta); - data1 = (data1 * (256 - ratio) + data1p * ratio) >> 8; - delta = channel[2].per; - ratio = Math.floor(((channel[2].evtime % delta) << 8) / delta); - data1 += (data2 * (256 - ratio) + data2p * ratio) >> 8; - delta = channel[3].per; - ratio = Math.floor(((channel[3].evtime % delta) << 8) / delta); - data0 += (data3 * (256 - ratio) + data3p * ratio) >> 8; - } - - data2 = data0 << 1; - data3 = data1 << 1; - if (AMIGA.config.audio.filter) { - data2 = this.filter.filter(data2, 0); - data3 = this.filter.filter(data3, 1); - } - - if (sampleBuffer.pos < sampleBuffer.size) { - if (AMIGA.config.audio.channels == SAEV_Config_Audio_Channels_Stereo) { - sampleBuffer.data.left[sampleBuffer.pos] = inv32768 * data2; - sampleBuffer.data.right[sampleBuffer.pos] = inv32768 * data3; - sampleBuffer.pos++; - } else - sampleBuffer.data.left[sampleBuffer.pos++] = inv32768 * ((data2 + data3) * 0.5); - } //else - //BUG.info('Audio.sample_handler_rh() audio buffer over-run!'); - }; - - /*---------------------------------*/ - - function queuePush() { - if (queueBuffer.usage + resampleBuffer.len >= queueBuffer.size) - return; - - if (AMIGA.config.audio.channels == SAEV_Config_Audio_Channels_Stereo) { - for (var i = 0; i < resampleBuffer.len; i++) { - queueBuffer.data.left[queueBuffer.usage + i] = resampleBuffer.data.left[i]; - queueBuffer.data.right[queueBuffer.usage + i] = resampleBuffer.data.right[i]; - } - } else { - for (var i = 0; i < resampleBuffer.len; i++) - queueBuffer.data.left[queueBuffer.usage + i] = resampleBuffer.data.left[i]; - } - queueBuffer.usage += resampleBuffer.len; - if (queueBuffer.usage > SAMPLE_BUFFER_SIZE * 4) - queueBuffer.usage = 0; + audio_channel[nr].vol = v; } - - function queuePop(bytes) { - if (queueBuffer.usage - bytes < 0) - bytes = queueBuffer.usage; - if (bytes <= 0) { - outputBuffer.len = 0; - return; - } - - if (AMIGA.config.audio.channels == SAEV_Config_Audio_Channels_Stereo) { - for (var i = 0; i < bytes; i++) { - outputBuffer.data.left[i] = queueBuffer.data.left[i]; - outputBuffer.data.right[i] = queueBuffer.data.right[i]; - } - } else { - for (var i = 0; i < bytes; i++) - outputBuffer.data.left[i] = queueBuffer.data.left[i]; - } - outputBuffer.len = bytes; - - queueBuffer.usage -= bytes; - - if (AMIGA.config.audio.channels == SAEV_Config_Audio_Channels_Stereo) { - for (var i = 0; i < queueBuffer.usage; i++) { - queueBuffer.data.left[i] = queueBuffer.data.left[bytes + i]; - queueBuffer.data.right[i] = queueBuffer.data.right[bytes + i]; - } - } else { - for (var i = 0; i < queueBuffer.usage; i++) - queueBuffer.data.left[i] = queueBuffer.data.left[bytes + i]; - } - } - - function resample() { - var step = amiga_sample_rate / driver.ctx.sampleRate; - - resampleBuffer.len = Math.floor(sampleBuffer.pos / step); - - if (AMIGA.config.audio.channels == SAEV_Config_Audio_Channels_Stereo) { - for (var i = 0, j = 0.0; i < resampleBuffer.len; i++, j += step) { - resampleBuffer.data.left[i] = sampleBuffer.data.left[j >> 0]; - resampleBuffer.data.right[i] = sampleBuffer.data.right[j >> 0]; - } - } else { - for (var i = 0, j = 0.0; i < resampleBuffer.len; i++, j += step) - resampleBuffer.data.left[i] = sampleBuffer.data.left[j >> 0]; - } - sampleBuffer.pos = 0; - } - - function audioProcess(e) { - if (sampleBuffer.pos == 0) - return; - - //var _pos = sampleBuffer.pos; - - resample(); - - queuePush(); - queuePop(SAMPLE_BUFFER_SIZE); - - //console.log(_pos, resampleBuffer.len, queueBuffer.usage, outputBuffer.len); - - if (outputBuffer.len == 0) - return; - - var step = outputBuffer.len / SAMPLE_BUFFER_SIZE; - - if (AMIGA.config.audio.channels == SAEV_Config_Audio_Channels_Stereo) { - var data1 = e.outputBuffer.getChannelData(0); - var data2 = e.outputBuffer.getChannelData(1); - - for (var i = 0, j = 0.0; i < SAMPLE_BUFFER_SIZE; i++, j += step) { - data1[i] = outputBuffer.data.left[j >> 0]; - data2[i] = outputBuffer.data.right[j >> 0]; - } - } else { - var data = e.outputBuffer.getChannelData(0); - - for (var i = 0, j = 0.0; i < SAMPLE_BUFFER_SIZE; i++, j += step) - data[i] = outputBuffer.data.left[j >> 0]; - } - } } - diff --git a/sae/autoconf.js b/sae/autoconf.js new file mode 100644 index 0000000..64e9c03 --- /dev/null +++ b/sae/autoconf.js @@ -0,0 +1,727 @@ +/*------------------------------------------------------------------------- +| SAE - Scripted Amiga Emulator +| https://github.com/naTmeg/ScriptedAmigaEmulator +| +| Copyright (C) 2012-2016 Rupert Hausberger +| +| This program is free software; you can redistribute it and/or +| modify it under the terms of the GNU General Public License +| as published by the Free Software Foundation; either version 2 +| of the License, or (at your option) any later version. +| +| This program is distributed in the hope that it will be useful, +| but WITHOUT ANY WARRANTY; without even the implied warranty of +| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +| GNU General Public License for more details. +| +| Note: ported from WinUAE 3.2.x +-------------------------------------------------------------------------*/ +/* global references */ + +var SAER_AutoConf_bank = null; + +/*---------------------------------*/ +/* global constants */ + +const SAEC_AutoConf_RTS = 0x4e75; +//const SAEC_AutoConf_RTE = 0x4e73; + +/*---------------------------------*/ +/* global variables */ + +var SAEV_AutoConf_base = 0xf00000; //RTAREA_DEFAULT; + +var SAEV_AutoConf_boot_rom_type = 0; +var SAEV_AutoConf_boot_rom_size = 0; + +/*---------------------------------*/ + +function SAEO_AutoConf() { + const RTAREA_DEFAULT = 0xf00000; + const RTAREA_BACKUP = 0xef0000; + const RTAREA_BACKUP_2 = 0xdb0000; + const RTAREA_SIZE = 0x10000; + + const RTAREA_TRAPS = 0x3000; + const RTAREA_RTG = 0x3800; + const RTAREA_TRAMPOLINE = 0x3b00; + const RTAREA_DATAREGION = 0xF000; + + const RTAREA_FSBOARD = 0xFFEC; + const RTAREA_HEARTBEAT = 0xFFF0; + const RTAREA_TRAPTASK = 0xFFF4; + const RTAREA_EXTERTASK = 0xFFF8; + const RTAREA_INTREQ = 0xFFFC; + + const RTAREA_TRAP_DATA = 0x4000; + const RTAREA_TRAP_DATA_SIZE = 0x8000; + const RTAREA_TRAP_DATA_SLOT_SIZE = 0x2000; // 8192 + const RTAREA_TRAP_DATA_SECOND = 80; + const RTAREA_TRAP_DATA_TASKWAIT = (RTAREA_TRAP_DATA_SECOND - 4); + const RTAREA_TRAP_DATA_EXTRA = 144; + const RTAREA_TRAP_DATA_EXTRA_SIZE = (RTAREA_TRAP_DATA_SLOT_SIZE - RTAREA_TRAP_DATA_EXTRA); + + const RTAREA_TRAP_SEND_DATA = 0xc0000; + const RTAREA_TRAP_SEND_DATA_SIZE = 0x2000; + + const RTAREA_TRAP_STATUS = 0xF000; + const RTAREA_TRAP_STATUS_SIZE = 8; + const RTAREA_TRAP_STATUS_SECOND = 4; + + const RTAREA_TRAP_SEND_STATUS = 0xF100; + + const RTAREA_SYSBASE = 0x3FFC; + + const RTAREA_TRAP_DATA_NUM = (RTAREA_TRAP_DATA_SIZE / RTAREA_TRAP_DATA_SLOT_SIZE); + + + + /* Commonly used autoconfig strings */ + //var EXPANSION_explibname = 0, EXPANSION_doslibname = 0, EXPANSION_uaeversion = 0; + //var EXPANSION_uaedevname, EXPANSION_explibbase = 0; + //var EXPANSION_bootcode = 0, EXPANSION_nullfunc = 0; + + /* ROM tag area memory access */ + //var rtarea_base = RTAREA_DEFAULT; --> SAEV_AutoConf_base + var hardware_trap_event = new Array(RTAREA_TRAP_DATA_SIZE / RTAREA_TRAP_DATA_SLOT_SIZE); //HANDLE + + var rt_trampoline_ptr = 0, trap_entry = 0; + //var hwtrap_waiting = 0; //extern volatile uae_atomic, in traps + var filesystem_state = 0; //extern int + + //var uae_boot_rom_type = 0; -> SAEV_AutoConf_boot_rom_type + //var uae_boot_rom_size = 0; -> SAEV_AutoConf_boot_rom_size + + var uae_int_requested = 0; //volatile uae_atomic + + /*-----------------------------------------------------------------------*/ + + function check_boot_rom(p) { + var b = RTAREA_DEFAULT; + + /*if (currprefs.uaeboard > 1) { + p.type = 2; + return 0x00eb0000; // fixme! + } + p.type = 0; + if (currprefs.boot_rom == 1) + return 0;*/ + p.type = 1; + /*if (currprefs.cs_cdtvcd || currprefs.cs_cdtvscsi || currprefs.uae_hide > 1) + b = RTAREA_BACKUP;*/ + if (SAEV_config.chipset.mbdmac == 1)// || currprefs.cpuboard_type) + b = RTAREA_BACKUP; + // CSPPC enables MMU at boot and remaps 0xea0000->0xeffff. + /*if (ISCPUBOARD(BOARD_BLIZZARD, BOARD_BLIZZARD_SUB_PPC)) + b = RTAREA_BACKUP_2;*/ + var ab = SAER_Memory_getBank(RTAREA_DEFAULT); + if (ab !== null) { + if (SAER_Memory_check(RTAREA_DEFAULT, 65536)) + b = RTAREA_BACKUP; + } + /*if (nr_directory_units(NULL)) + return b; + if (nr_directory_units(&currprefs)) + return b; + if (currprefs.socket_emu) + return b; + if (currprefs.uaeserial) + return b; + if (currprefs.scsi == 1) //uaescsi.device + return b; + if (currprefs.sana2) + return b; + if (currprefs.input_tablet > 0) + return b; + if (currprefs.rtgmem_size && currprefs.rtgmem_type < GFXBOARD_HARDWARE) + return b; + if (currprefs.win32_automount_removable) + return b;*/ + if (SAEV_config.memory.chipSize > 2 * 1024 * 1024) + return b; + /*if (currprefs.z3chipmem_size) + return b; + if (currprefs.boot_rom >= 3) + return b; + if (currprefs.boot_rom == 2 && b == 0xf00000) { + p.type = -1; + return b; + }*/ + p.type = 0; + return 0; + } + + this.need_uae_boot_rom = function() { + var p = { type:0 }; + var v = check_boot_rom(p); + SAEV_AutoConf_boot_rom_type = p.type; + SAEF_log("autoconf.need_uae_boot_rom() type %d", SAEV_AutoConf_boot_rom_type); + if (!SAEV_AutoConf_base) { + v = 0; + SAEV_AutoConf_boot_rom_type = 0; + } + return v; + } + + /*-----------------------------------------------------------------------*/ + + /*static bool istrapwait(void) { + for (int i = 0; i < RTAREA_TRAP_DATA_NUM; i++) { + uae_u8 *data = rtarea_bank.baseaddr + RTAREA_TRAP_DATA + i * RTAREA_TRAP_DATA_SLOT_SIZE; + uae_u8 *status = rtarea_bank.baseaddr + RTAREA_TRAP_STATUS + i * RTAREA_TRAP_STATUS_SIZE; + if (get_long_host(data + RTAREA_TRAP_DATA_TASKWAIT) && status[3] && status[2] >= 0x80) { + return true; + } + } + return false; + }*/ + this.rethink_traps = function() { + return false; + /*if (currprefs.uaeboard < 2) + return false; + if (istrapwait()) { + atomic_or(&uae_int_requested, 0x4000); + set_special_exter(SPCFLAG_UAEINT); + return true; + } + atomic_and(&uae_int_requested, ~0x4000); + return false;*/ + } + + /*-----------------------------------------------------------------------*/ + + const RTAREA_WRITEOFFSET = 0xfff0; + + function hwtrap_check_int() { + if (hwtrap_waiting == 0) { + atomic_and(uae_int_requested, ~0x2000); + } else { + atomic_or(uae_int_requested, 0x2000); + set_special_exter(SPCFLAG_UAEINT); + } + } + + function rtarea_trap_data(addr) { + if (addr >= RTAREA_TRAP_DATA && addr < RTAREA_TRAP_DATA + RTAREA_TRAP_DATA_SIZE) + return true; + return false; + } + + function rtarea_trap_status(addr) { + if (addr >= RTAREA_TRAP_STATUS && addr < RTAREA_TRAP_STATUS + RTAREA_TRAP_DATA_NUM * RTAREA_TRAP_STATUS_SIZE) + return true; + return false; + } + + /*---------------------------------*/ + + function rtarea_get32(addr) { + addr &= 0xFFFF; + return ((rtarea_bank.baseaddr[addr] << 24) | (rtarea_bank.baseaddr[addr + 1] << 16) | (rtarea_bank.baseaddr[addr + 2] << 8) | rtarea_bank.baseaddr[addr + 3]) >>> 0; + } + function rtarea_get16(addr) { + addr &= 0xFFFF; + return (rtarea_bank.baseaddr[addr] << 8) + rtarea_bank.baseaddr[addr + 1]; + } + function rtarea_get8(addr) { + addr &= 0xFFFF; + + if (rtarea_trap_status(addr)) { + var addr2 = addr - RTAREA_TRAP_STATUS; + var trap_offset = addr2 & (RTAREA_TRAP_STATUS_SIZE - 1); + var trap_slot = Math.floor(addr2 / RTAREA_TRAP_STATUS_SIZE); + if (trap_offset == 0) { + // 0 = busy wait, 1 = Wait() + rtarea_bank.baseaddr[addr] = filesystem_state ? 1 : 0; + } + } else if (addr == RTAREA_INTREQ + 0) { + rtarea_bank.baseaddr[addr] = atomic_bit_test_and_reset(uae_int_requested, 0); + //SAEF_log("autoconf.rtarea_get8() %s", rtarea_bank.baseaddr[addr] ? "+" : "-"); + } else if (addr == RTAREA_INTREQ + 1) { + rtarea_bank.baseaddr[addr] = hwtrap_waiting != 0; + } else if (addr == RTAREA_INTREQ + 2) { + /*if (SAER.autoconf.rethink_traps()) //OWN empty + rtarea_bank.baseaddr[addr] = 1; + else*/ + rtarea_bank.baseaddr[addr] = 0; + } + hwtrap_check_int(); + return rtarea_bank.baseaddr[addr]; + } + + function rtarea_write(addr) { + if (addr >= RTAREA_WRITEOFFSET) + return true; + if (addr >= RTAREA_SYSBASE && addr < RTAREA_SYSBASE + 4) + return true; + return rtarea_trap_data(addr) || rtarea_trap_status(addr); + } + function rtarea_put8(addr, value) { + addr &= 0xffff; + if (!rtarea_write(addr)) + return; + rtarea_bank.baseaddr[addr] = value; + if (!rtarea_trap_status(addr)) + return; + addr -= RTAREA_TRAP_STATUS; + var trap_offset = addr & (RTAREA_TRAP_STATUS_SIZE - 1); + var trap_slot = Math.floor(addr / RTAREA_TRAP_STATUS_SIZE); + if (trap_offset == RTAREA_TRAP_STATUS_SECOND + 3) { + var v = value; + if (v != 0xff && v != 0xfe && v != 0x01 && v != 02) + SAEF_log("autoconf.rtarea_put8() TRAP %d (%02x)", trap_slot, v); + if (v == 0xfe) + atomic_dec(hwtrap_waiting); + if (v == 0x01) + atomic_dec(hwtrap_waiting); + if (v == 0x01 || v == 0x02) { + // signal call_hardware_trap_back() + // FIXME: OS specific code! + SetEvent(hardware_trap_event[trap_slot]); + } + } + } + function rtarea_put16(addr, value) { + addr &= 0xffff; + value &= 0xffff; + if (!rtarea_write(addr)) + return; + rtarea_put8(addr, value >> 8); + rtarea_put8(addr + 1, value & 0xff); + if (!rtarea_trap_status(addr)) + return; + addr -= RTAREA_TRAP_STATUS; + var trap_offset = addr & (RTAREA_TRAP_STATUS_SIZE - 1); + var trap_slot = Math.floor(addr / RTAREA_TRAP_STATUS_SIZE); + if (trap_offset == 0) { + SAEF_log("autoconf.rtarea_put16() TRAP %d (%04x)", trap_slot, value); + call_hardware_trap(rtarea_bank.baseaddr, SAEV_AutoConf_base, trap_slot); + } + } + function rtarea_put32(addr, value) { + addr &= 0xffff; + if (!rtarea_write(addr)) + return; + rtarea_bank.baseaddr[addr + 0] = value >>> 24; + rtarea_bank.baseaddr[addr + 1] = (value >>> 16) & 0xff; + rtarea_bank.baseaddr[addr + 2] = (value >>> 8) & 0xff; + rtarea_bank.baseaddr[addr + 3] = value & 0xff; + } + + function rtarea_xlate(addr) { + addr &= 0xFFFF; + //return rtarea_bank.baseaddr + addr; + return addr; + } + function rtarea_check(addr, size) { + addr &= 0xFFFF; + return (addr + size) <= 0xFFFF; + } + + var rtarea_bank = new SAEO_Memory_addrbank( + rtarea_get32, rtarea_get16, rtarea_get8, + rtarea_put32, rtarea_put16, rtarea_put8, + rtarea_xlate, rtarea_check, null, "rtarea", "UAE Boot ROM", + rtarea_get32, rtarea_get16, + SAEC_Memory_addrbank_flag_ROMIN | SAEC_Memory_addrbank_flag_PPCIOSPACE//, S_READ, S_WRITE + ); + SAER_AutoConf_bank = rtarea_bank; + + /*-----------------------------------------------------------------------*/ + + this.reset = function() { //rtarea_reset() + //memset(rtarea_bank.baseaddr + RTAREA_TRAP_DATA, 0, RTAREA_TRAP_DATA_SIZE); + //memset(rtarea_bank.baseaddr + RTAREA_TRAP_STATUS, 0, RTAREA_TRAP_STATUS_SIZE * RTAREA_TRAP_DATA_NUM); + SAEF_memset(rtarea_bank.baseaddr,RTAREA_TRAP_DATA, 0, RTAREA_TRAP_DATA_SIZE); + SAEF_memset(rtarea_bank.baseaddr,RTAREA_TRAP_STATUS, 0, RTAREA_TRAP_STATUS_SIZE * RTAREA_TRAP_DATA_NUM); + } + + /*-----------------------------------------------------------------------*/ + /* some quick & dirty code to fill in the rt area and save me a lot of scratch paper */ + + var rt_addr = 0; + var rt_straddr = 0; + + function addr(ptr) { + //SAEF_log("autoconf.addr() %08x", ptr + SAEV_AutoConf_base); + //return (uae_u32)ptr + SAEV_AutoConf_base; + return ptr + SAEV_AutoConf_base; + } + this.db = function(data) { + //SAEF_log("autoconf.db() %02x", data); + rtarea_bank.baseaddr[rt_addr++] = data; + } + this.dw = function(data) { + //SAEF_log("autoconf.dw() %04x", data); + rtarea_bank.baseaddr[rt_addr++] = data >> 8; + rtarea_bank.baseaddr[rt_addr++] = data & 0xff; + } + this.dl = function(data) { + //SAEF_log("autoconf.dl() %08x", data); + rtarea_bank.baseaddr[rt_addr++] = data >> 24; + rtarea_bank.baseaddr[rt_addr++] = (data >> 16) & 0xff; + rtarea_bank.baseaddr[rt_addr++] = (data >> 8) & 0xff; + rtarea_bank.baseaddr[rt_addr++] = data & 0xff; + } + + /*this.dbg = function(addr) { + addr -= SAEV_AutoConf_base; + return rtarea_bank.baseaddr[addr]; + }*/ + + /* store strings starting at the end of the rt area and working backward. store pointer at current address */ + /*uae_u32 ds_ansi (const uae_char *str) { + int len; + + if (!str) + return addr (rt_straddr); + len = strlen (str) + 1; + rt_straddr -= len; + strcpy ((uae_char*)rtarea_bank.baseaddr + rt_straddr, str); + return addr (rt_straddr); + } + uae_u32 ds (const TCHAR *str) { + char *s = ua (str); + uae_u32 v = ds_ansi (s); + xfree (s); + return v; + } + uae_u32 ds_bstr_ansi (const uae_char *str) { + int len; + + len = strlen (str) + 2; + rt_straddr -= len; + while (rt_straddr & 3) + rt_straddr--; + rtarea_bank.baseaddr[rt_straddr] = len - 2; + strcpy ((uae_char*)rtarea_bank.baseaddr + rt_straddr + 1, str); + return addr (rt_straddr) >> 2; + }*/ + + this.calltrap = function(n) { + /*if (currprefs.uaeboard > 2) { + this.dw(0x4eb9); // JSR rt_trampoline_ptr + this.dl(rt_trampoline_ptr); + uaecptr a = this.here(); + this.org(rt_trampoline_ptr); + this.dw(0x3f3c); // MOVE.W #n,-(SP) + this.dw(n); + this.dw(0x4ef9); // JMP rt_trampoline_entry + this.dl(trap_entry); + this.org(a); + rt_trampoline_ptr += 3 * 2 + 1 * 4; + } else*/ + this.dw(0xA000 + n); + } + + this.org = function(a) { + if (((a & 0xffff0000) >>> 0 != 0x00f00000) && ((a & 0xffff0000) >>> 0 != SAEV_AutoConf_base)) + SAEF_warn("autoconf.org() corrupt address %08X", a); + rt_addr = a & 0xffff; + } + + this.here = function() { + return addr(rt_addr); + } + + /*this.align = function(b) { + rt_addr = (rt_addr + b - 1) & ~(b - 1); + }*/ + + /*-----------------------------------------------------------------------*/ + + function mapped_malloc(ab) { + ab.startmask = ab.start; + try { + //ab.baseaddr = xcalloc(uae_u8, ab.allocated + 4); + ab.baseaddr = new Uint8Array(ab.allocated + 4); + return true; + } catch (e) { + ab.baseaddr = null; + return false; + } + } + function mapped_free(ab) { + //xfree(ab.baseaddr); + ab.baseaddr = null; + } + + /*static uae_u32 REGPARAM2 nullfunc (TrapContext *ctx) { + write_log (_T("Null function called\n")); + return 0; + } + static uae_u32 REGPARAM2 getchipmemsize (TrapContext *ctx) { + trap_set_dreg(ctx, 1, z3chipmem_bank.allocated); + trap_set_areg(ctx, 1, z3chipmem_bank.start); + return chipmem_bank.allocated; + } + static uae_u32 REGPARAM2 uae_puts (TrapContext *ctx) { + puts ((char*)get_real_address(trap_get_areg(ctx, 0))); + return 0; + }*/ + + /* OPT inline ok + function rtarea_init_mem() { + if (SAER.autoconf.need_uae_boot_rom()) + rtarea_bank.flags &= ~SAEC_Memory_addrbank_flag_ALLOCINDIRECT; + else + rtarea_bank.flags |= SAEC_Memory_addrbank_flag_ALLOCINDIRECT; + + rtarea_bank.allocated = RTAREA_SIZE; + if (!mapped_malloc(rtarea_bank)) { + SAEF_fatal(SAEE_NoMemory, "autoconf.init_mem() memory exhausted"); + //abort(); + } + }*/ + this.setup = function() { //rtarea_init() + rt_straddr = 0xFF00 - 2; + rt_addr = 0; + + rt_trampoline_ptr = SAEV_AutoConf_base + RTAREA_TRAMPOLINE; + trap_entry = 0; + + this.init_traps(); + + //rtarea_init_mem(); + { + if (this.need_uae_boot_rom()) + rtarea_bank.flags &= ~SAEC_Memory_addrbank_flag_ALLOCINDIRECT; + else + rtarea_bank.flags |= SAEC_Memory_addrbank_flag_ALLOCINDIRECT; + + rtarea_bank.allocated = RTAREA_SIZE; + if (!mapped_malloc(rtarea_bank)) { + SAEF_fatal(SAEE_NoMemory, "autoconf.init_mem() memory exhausted"); + //abort(); + } + } + //memset(rtarea_bank.baseaddr, 0, RTAREA_SIZE); + SAEF_memset(rtarea_bank.baseaddr,0, 0, RTAREA_SIZE); + + /*var uaever = sprintf("uae-%d.%d.%d", UAEMAJOR, UAEMINOR, UAESUBREV); + var saever = sprintf("sae-%d.%d.%d", SAEC_Version, SAEC_Revision, SAEC_Patch); + EXPANSION_uaeversion = ds(saever); + EXPANSION_explibname = ds("expansion.library"); + EXPANSION_doslibname = ds("dos.library"); + EXPANSION_uaedevname = ds("uae.device");*/ + + this.dw(0); + this.dw(0); + + /*#ifdef FILESYS + filesys_install_code(); + + trap_entry = filesys_get_entry(10); + write_log(_T("TRAP_ENTRY = %08x\n"), trap_entry); + + for (int i = 0; i < RTAREA_TRAP_DATA_SIZE / RTAREA_TRAP_DATA_SLOT_SIZE; i++) { + hardware_trap_event[i] = CreateEvent(NULL, FALSE, FALSE, NULL); + } + #endif*/ + + this.define_trap(null, 0, "null"); /* Generic emulator trap */ + + /*var a = this.here(); + // Dummy trap - removing this breaks the filesys emulation. + this.org(SAEV_AutoConf_base + 0xFF00); + this.calltrap(deftrap2(nullfunc, TRAPFLAG_NO_RETVAL, "")); + + this.org(SAEV_AutoConf_base + 0xFF80); + this.calltrap(deftrapres(getchipmemsize, TRAPFLAG_DORET, "getchipmemsize")); + this.dw(SAEC_AutoConf_RTS); + + this.org(SAEV_AutoConf_base + 0xFF10); + this.calltrap(deftrapres(uae_puts, TRAPFLAG_NO_RETVAL, "uae_puts")); + this.dw(SAEC_AutoConf_RTS); + + this.org(a);*/ + + SAEV_AutoConf_boot_rom_size = this.here() - SAEV_AutoConf_base; + SAEF_log("autoconf.setup() boot_rom_size %d/%d", SAEV_AutoConf_boot_rom_size, RTAREA_TRAPS); + if (SAEV_AutoConf_boot_rom_size >= RTAREA_TRAPS) { + SAEF_fatal(SAEE_NoMemory, "autoconf.setup() RTAREA_TRAPS needs to be increased!"); + //abort(); + } + + /*#ifdef PICASSO96 + uaegfx_install_code(SAEV_AutoConf_base + RTAREA_RTG); + #endif*/ + + this.org(RTAREA_TRAPS | SAEV_AutoConf_base); + this.init_extended_traps(); + } + + this.cleanup = function() { //rtarea_free() + mapped_free(rtarea_bank); + this.free_traps(); + } + + this.init = function() { //rtarea_setup() + var base = this.need_uae_boot_rom(); + if (base) { + SAEF_log("autoconf.init() RTAREA located at %08X", base); + SAEV_AutoConf_base = base; + } + } + + /*-----------------------------------------------------------------------*/ + + this.makedatatable = function(resid, resname, type, priority, ver, rev) { + var datatable = this.here(); + this.dw(0xE000); /* INITBYTE */ + this.dw(0x0008); /* LN_TYPE */ + this.dw(type << 8); + this.dw(0xE000); /* INITBYTE */ + this.dw(0x0009); /* LN_PRI */ + this.dw(priority << 8); + this.dw(0xC000); /* INITLONG */ + this.dw(0x000A); /* LN_NAME */ + this.dl(resname); + this.dw(0xE000); /* INITBYTE */ + this.dw(0x000E); /* LIB_FLAGS */ + this.dw(0x0600); /* LIBF_SUMUSED | LIBF_CHANGED */ + this.dw(0xD000); /* INITWORD */ + this.dw(0x0014); /* LIB_VERSION */ + this.dw(ver); + this.dw(0xD000); /* INITWORD */ + this.dw(0x0016); /* LIB_REVISION */ + this.dw(rev); + this.dw(0xC000); /* INITLONG */ + this.dw(0x0018); /* LIB_IDSTRING */ + this.dl(resid); + this.dw(0x0000); /* end of table */ + return datatable; + } + + /*-----------------------------------------------------------------------*/ + /* SECT Traps */ + /*-----------------------------------------------------------------------*/ + + const TRAPFLAG_NO_REGSAVE = 1; + const TRAPFLAG_NO_RETVAL = 2; + const TRAPFLAG_EXTRA_STACK = 4; + const TRAPFLAG_DORET = 8; + const TRAPFLAG_UAERES = 16; + + function Trap() { + this.handler = null; /* Handler function to be invoked for this trap */ + this.flags = 0; /* Trap attributes */ + this.name = ""; /* For debugging purposes */ + this.addr = 0; + }; + const MAX_TRAPS = 16; //4096; + + var trap_count = 1; + var traps = new Array(MAX_TRAPS); + for (var vi = 0; vi < MAX_TRAPS; vi++) + traps[vi] = new Trap(); + + var hwtrap_waiting = 0; //volatile uae_atomic + + const trace_traps = true; + + /*-----------------------------------------------------------------------*/ + + this.find_trap = function(name) { + for (var i = 0; i < trap_count; i++) { + var trap = traps[i]; + if ((trap.flags & TRAPFLAG_UAERES) && trap.name.length && trap.name == name) + return trap.addr; + } + return 0; + } + + /* + * Define an emulator trap + * + * handler_func = host function that will be invoked to handle this trap + * flags = trap attributes + * name = name for debugging purposes + * + * returns trap number of defined trap + */ + this.define_trap = function(handler_func, flags, name) { + if (trap_count == MAX_TRAPS) { + SAEF_fatal(SAEE_Internal, "define_trap() Ran out of emulator traps. (increase MAX_TRAPS)"); + //abort(); + //return -1; + } else { + var addr = this.here(); + + for (var i = 0; i < trap_count; i++) { + if (addr == traps[i].addr) + return i; + } + + var trap_num = trap_count++; + var trap = traps[trap_num]; + + trap.handler = handler_func; + trap.flags = flags; + trap.name = name; + trap.addr = addr; + + return trap_num; + } + } + + /* + * This function is called by the 68k interpreter to handle an emulator trap. + * + * trap_num = number of trap to invoke + * regs = current 68k state + */ + this.m68k_handle_trap = function(trap_num) { + var trap = traps[trap_num]; + var retval = 0; + + var has_retval = (trap.flags & TRAPFLAG_NO_RETVAL) == 0; + var implicit_rts = (trap.flags & TRAPFLAG_DORET) != 0; + + if (trap.name.length && trace_traps) + SAEF_log("m68k_handle_trap() TRAP '%s'", trap.name); + + if (trap_num < trap_count) { + if (trap.flags & TRAPFLAG_EXTRA_STACK) { + /* Handle an extended trap. + * Note: the return value of this trap is passed back to 68k + * space via a separate, dedicated simple trap which the trap + * handler causes to be invoked when it is done. + */ + //trap_HandleExtendedTrap(trap.handler, has_retval); //FIX implement extended-traps + SAEF_fatal(SAEE_Internal, "m68k_handle_trap() Extended-traps are not implemented."); + } else { + /* Handle simple trap */ + //retval = (trap.handler)(null); + retval = trap.handler(null); + + if (has_retval) { + SAER_CPU_regs.d[0] = retval; + SAEF_log("m68k_handle_trap() D0 = %d", retval); + } + if (implicit_rts) { + //m68k_do_rts(); { + var newpc = SAER_Memory_get32(SAER_CPU_regs.a[7]); + SAER_CPU_setPC(newpc); + SAER_CPU_regs.a[7] += 4; + //} + SAER_CPU_fill_prefetch(); + } + } + } else + SAEF_warn("m68k_handle_trap() illegal emulator trap"); + } + + /*-----------------------------------------------------------------------*/ + + this.init_traps = function() { + trap_count = 0; + hwtrap_waiting = 0; + } + this.free_traps = function() { + + } + this.init_extended_traps = function() { + + } +} diff --git a/sae/blitter.js b/sae/blitter.js index 69d5db8..4d7698b 100644 --- a/sae/blitter.js +++ b/sae/blitter.js @@ -1,160 +1,248 @@ -/************************************************************************** -* SAE - Scripted Amiga Emulator -* -* 2012-2015 Rupert Hausberger -* -* https://github.com/naTmeg/ScriptedAmigaEmulator -* -*************************************************************************** -* Notes: Ported from WinUAE 2.5.0 -* -**************************************************************************/ +/*------------------------------------------------------------------------- +| SAE - Scripted Amiga Emulator +| https://github.com/naTmeg/ScriptedAmigaEmulator +| +| Copyright (C) 2012-2016 Rupert Hausberger +| +| This program is free software; you can redistribute it and/or +| modify it under the terms of the GNU General Public License +| as published by the Free Software Foundation; either version 2 +| of the License, or (at your option) any later version. +| +| This program is distributed in the hope that it will be useful, +| but WITHOUT ANY WARRANTY; without even the implied warranty of +| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +| GNU General Public License for more details. +| +| Note: ported from WinUAE 3.2.x +-------------------------------------------------------------------------*/ +/* global references */ -function Blitter() { - const FAST = true; - const BLITTER_MAX_WORDS = 2048; +var SAER_Blitter_blt_info = null; + +/*---------------------------------*/ +/* global constants */ + +const SAEC_Blitter_bltstate_DONE = 0; +const SAEC_Blitter_bltstate_INIT = 1; +const SAEC_Blitter_bltstate_READ = 2; +const SAEC_Blitter_bltstate_WORK = 3; +const SAEC_Blitter_bltstate_WRITE = 4; +const SAEC_Blitter_bltstate_NEXT = 5; + +/*---------------------------------*/ +/* global variables */ + +var SAEV_Blitter_bltstate = SAEC_Blitter_bltstate_DONE; +var SAEV_Blitter_interrupt = false; +var SAEV_Blitter_dangerous = false; + +/*---------------------------------*/ + +function SAEO_Blitter() { + //const BLITTER_DEBUG = 0; + // 1 = logging + // 2 = no wait detection + // 4 = no D + // 8 = instant + // 16 = activate debugger if weird things + /*var log_blitter; + if (BLITTER_DEBUG) + log_blitter = 1 | 16; + else + log_blitter = 0;*/ const blit_cycle_diagram = [ - [2, 0,0, 0,0 ], /* 0 -- */ - [2, 0,0, 0,4 ], /* 1 -D */ - [2, 0,3, 0,3 ], /* 2 -C */ - [3, 0,3,0, 0,3,4 ], /* 3 -CD */ - [3, 0,2,0, 0,2,0 ], /* 4 -B- */ - [3, 0,2,0, 0,2,4 ], /* 5 -BD */ - [3, 0,2,3, 0,2,3 ], /* 6 -BC */ - [4, 0,2,3,0, 0,2,3,4], /* 7 -BCD */ - [2, 1,0, 1,0 ], /* 8 A- */ - [2, 1,0, 1,4 ], /* 9 AD */ - [2, 1,3, 1,3 ], /* A AC */ - [3, 1,3,0, 1,3,4 ], /* B ACD */ - [3, 1,2,0, 1,2,0 ], /* C AB- */ - [3, 1,2,0, 1,2,4 ], /* D ABD */ - [3, 1,2,3, 1,2,3 ], /* E ABC */ - [4, 1,2,3,0, 1,2,3,4] /* F ABCD */ + [ 2, 0,0, 0,0 ], /* 0 -- */ + [ 2, 0,0, 0,4 ], /* 1 -D */ + [ 2, 0,3, 0,3 ], /* 2 -C */ + [ 3, 0,3,0, 0,3,4 ], /* 3 -CD */ + [ 3, 0,2,0, 0,2,0 ], /* 4 -B- */ + [ 3, 0,2,0, 0,2,4 ], /* 5 -BD */ + [ 3, 0,2,3, 0,2,3 ], /* 6 -BC */ + [ 4, 0,2,3,0, 0,2,3,4 ], /* 7 -BCD */ + [ 2, 1,0, 1,0 ], /* 8 A- */ + [ 2, 1,0, 1,4 ], /* 9 AD */ + [ 2, 1,3, 1,3 ], /* A AC */ + [ 3, 1,3,0, 1,3,4, ], /* B ACD */ + [ 3, 1,2,0, 1,2,0 ], /* C AB- */ + [ 3, 1,2,0, 1,2,4 ], /* D ABD */ + [ 3, 1,2,3, 1,2,3 ], /* E ABC */ + [ 4, 1,2,3,0, 1,2,3,4 ] /* F ABCD */ ]; const blit_cycle_diagram_fill = [ - [0 ], /* 0 */ - [3, 0,0,0, 0,4,0 ], /* 1 */ - [0 ], /* 2 */ - [0 ], /* 3 */ - [0 ], /* 4 */ - [4, 0,2,0,0, 0,2,4,0], /* 5 */ - [0 ], /* 6 */ - [0 ], /* 7 */ - [0 ], /* 8 */ - [3, 1,0,0, 1,4,0 ], /* 9 */ - [0 ], /* A */ - [0 ], /* B */ - [0 ], /* C */ - [4, 1,2,0,0, 1,2,4,0], /* D */ - [0 ], /* E */ - [0 ] /* F */ + [ 0 ], /* 0 */ + [ 3, 0,0,0, 0,4,0 ], /* 1 */ + [ 0 ], /* 2 */ + [ 0 ], /* 3 */ + [ 0 ], /* 4 */ + [ 4, 0,2,0,0, 0,2,4,0 ], /* 5 */ + [ 0 ], /* 6 */ + [ 0 ], /* 7 */ + [ 0 ], /* 8 */ + [ 3, 1,0,0, 1,4,0 ], /* 9 */ + [ 0 ], /* A */ + [ 0 ], /* B */ + [ 0 ], /* C */ + [ 4, 1,2,0,0, 1,2,4,0 ], /* D */ + [ 0 ], /* E */ + [ 0 ], /* F */ ]; - const blit_cycle_diagram_line = [4, 0,3,5,4, 0,3,5,4]; - //const blit_cycle_diagram_finald = [2, 0,4, 0,4]; - //const blit_cycle_diagram_finalld = [2, 0,0, 0,0]; - - var blit_filltable = []; - var blit_masktable = []; - var blit_interrupt = true; - var blit_ch = 0; - var blit_slowdown = 0; - var blit_stuck = 0; - var blit_cyclecounter = 0; - var blit_firstline_cycles = 0; - var blit_first_cycle = 0; - var blit_last_cycle = 0, blit_dmacount = 0, blit_dmacount2 = 0; - var blit_nod = 0; - var blit_diag = []; - var blit_faulty = 0; - var original_ch = 0, original_fill = 0, original_line = 0; - - var bltstate = BLT_done; + const blit_cycle_diagram_line = [4, 0,3,5,4, 0,3,5,4]; + const blit_cycle_diagram_finald = [2, 0,4, 0,4]; + const blit_cycle_diagram_finalld = [2, 0,0, 0,0]; - var bltcon0 = 0; - var bltcon1 = 0; - var bltapt = 0; - var bltapt_line = null; - var bltbpt = 0; - var bltcpt = 0; - var bltdpt = 0; + const DT_NONE = 0, DT_BLOCK = 1, DT_BLOCKFILL = 2, DT_LINE = 3; //OWN + + function blitter_info() { + this.blitzero = 0; //all int + this.blitashift = 0; + this.blitbshift = 0; + this.blitdownashift = 0; + this.blitdownbshift = 0; + this.bltadat = 0; //all u16 + this.bltbdat = 0; + this.bltcdat = 0; + this.bltddat = 0; + this.bltahold = 0; + this.bltbhold = 0; + this.bltafwm = 0; + this.bltalwm = 0; + this.vblitsize = 0; //all int + this.hblitsize = 0; + this.bltamod = 0; + this.bltbmod = 0; + this.bltcmod = 0; + this.bltdmod = 0; + this.got_cycle = 0; + }; + var blt_info = new blitter_info(); + SAER_Blitter_blt_info = blt_info; + + var blitter_cycle_exact = false; + var immediate_blits = false; + var blt_statefile_type = 0; + + var bltcon0 = 0, bltcon1 = 0; //global u16 + var bltapt = 0, bltbpt = 0, bltcpt = 0, bltdpt = 0; //global u32 + var bltptx = 0; //global u32 + var bltptxpos = 0, bltptxc = 0; //global + var blitter_nasty = 0; //global + //var blitter_dangerous_bpl = false; ->SAEV_Blitter_dangerous + + var original_ch = 0, original_fill = 0, original_line = 0; var blinea_shift = 0; - var blinea = 0, blineb = 0; + var blinea = 0, blineb = 0; //u16 var blitline = 0, blitfc = 0, blitfill = 0, blitife = 0, blitsing = 0, blitdesc = 0; - var blitonedot = 0, blitsign = 0, blitlinepixel = 0; + var blitline_started = 0; + var blitonedot = 0, blitsign = false, blitlinepixel = 0; + var blit_add = 0; + var blit_modadda = 0, blit_modaddb = 0, blit_modaddc = 0, blit_modaddd = 0; + var blit_ch = 0; + var blitter_dontdo = 0; + var blitter_delayed_debug = 0; + + var blit_func_tab = null; //OWN + var blit_filltable = null; //u8 [256][4][2] + var blit_masktable = null; //global u32 [BLITTER_MAX_WORDS] + //var bltstate = 0; -> SAEV_Blitter_bltstate + //var blit_interrupt = false; -> SAEV_Blitter_interrupt + + var blit_cyclecounter = 0, blit_waitcyclecounter = 0; + var blit_maxcyclecounter = 0, blit_slowdown = 0, blit_totalcyclecounter = 0; + var blit_startcycles = 0, blit_misscyclecounter = 0; + + var blit_firstline_cycles = 0; //long + var blit_first_cycle = 0; //long + var blit_last_cycle = 0, blit_dmacount = 0, blit_dmacount2 = 0; + var blit_linecycles = 0, blit_extracycles = 0, blit_nod = 0; + var blit_diag = null; //int * + var blit_diag_type = 0; //OWN + var blit_frozen = 0, blit_faulty = 0; + var blit_final = 0; + var blt_delayed_irq = 0; + var ddat1 = 0, ddat2 = 0; //u16 var ddat1use = 0, ddat2use = 0; + + var preva = 0, prevb = 0; //u32 + var last_blitter_hpos = 0; - - var blt_info = { - blitzero:0, - blitashift:0, blitbshift:0, blitdownashift:0, blitdownbshift:0, - bltadat:0, bltbdat:0, bltcdat:0, bltddat:0, - bltahold:0, bltbhold:0, bltafwm:0, bltalwm:0, - vblitsize:0, hblitsize:0, - bltamod:0, bltbmod:0, bltcmod:0, bltdmod:0, - got_cycle:0 - }; - //function build_blitfilltable() - { - blit_masktable = new Uint16Array(BLITTER_MAX_WORDS); - for (var i = 0; i < BLITTER_MAX_WORDS; i++) - blit_masktable[i] = 0xffff; + const BLITTER_STARTUP_CYCLES = 2; - blit_filltable = []; - for (var d = 0; d < 256; d++) { - blit_filltable[d] = []; - for (var i = 0; i < 4; i++) { - var fc = (i & 1) == 1; - var data = d; - blit_filltable[d][i] = []; - for (var fillmask = 1; fillmask != 0x100; fillmask <<= 1) { - var tmp = data; - if (fc) { - if (i & 2) - data |= fillmask; - else - data ^= fillmask; - } - if (tmp & fillmask) fc = !fc; - } - blit_filltable[d][i][0] = data; - blit_filltable[d][i][1] = fc; - } - } + var blitter_cyclecounter = 0; + var blitter_hcounter1 = 0, blitter_hcounter2 = 0; + var blitter_vcounter1 = 0, blitter_vcounter2 = 0; + + var blitter_stuck = 0; + + var oddfstrt = 0, oddfstop = 0, ototal = 0, ofree = 0, slow = 0; + + var changetable = new Uint8Array(32 * 32); + var freezes = 10; + var warned1 = 10; + var warned2 = 10; + + /*-----------------------------------------------------------------------*/ + + this.setup = function() { + build_blitfilltable(); + build_blitfunctable(); + return SAEE_None; } - /*---------------------------------*/ + this.reset = function() { //blitter_reset() + bltptxpos = -1; + blit_diag_type = DT_NONE; - this.reset = function () { - bltstate = BLT_done; - blit_interrupt = true; - blit_stuck = 0; - }; + preva = 0, prevb = 0; //blitter_doblit() + + for (var i = 0; i < changetable.length; i++) changetable[i] = 0; //blit_bltset() + freezes = 10; + + warned1 = 10; //waitingblits() + warned2 = 10; //maybe_blit() + + blitter_cyclecounter = 0; //blitter_dodma() + blitter_hcounter1 = blitter_hcounter2 = 0; + blitter_vcounter1 = blitter_vcounter2 = 0; + + blitter_stuck = 0; //handler() + + oddfstrt = oddfstop = ototal = ofree = slow = 0; //blitter_slowdown() + } /*function blitter_dump() { - BUG.info('PT A=%08X B=%08X C=%08X D=%08X', bltapt, bltbpt, bltcpt, bltdpt); - BUG.info('CON0=%04X CON1=%04X DAT A=%04X B=%04X C=%04X', bltcon0, bltcon1, blt_info.bltadat, blt_info.bltbdat, blt_info.bltcdat); - //BUG.info('AFWM=%04X ALWM=%04X MOD A=%04X B=%04X C=%04X D=%04X', blt_info.bltafwm, blt_info.bltalwm, blt_info.bltamod & 0xffff, blt_info.bltbmod & 0xffff, blt_info.bltcmod & 0xffff, blt_info.bltdmod & 0xffff); - BUG.info('AFWM=%04X ALWM=%04X MOD A=%04X B=%04X C=%04X D=%04X', blt_info.bltafwm, blt_info.bltalwm, blt_info.bltamod, blt_info.bltbmod, blt_info.bltcmod, blt_info.bltdmod); + var chipsize = SAEV_config.memory.chipSize; + SAEF_log("PT A=%08X B=%08X C=%08X D=%08X", bltapt, bltbpt, bltcpt, bltdpt); + SAEF_log("CON0=%04X CON1=%04X DAT A=%04X B=%04X C=%04X", bltcon0, bltcon1, blt_info.bltadat, blt_info.bltbdat, blt_info.bltcdat); + SAEF_log("AFWM=%04X ALWM=%04X MOD A=%04X B=%04X C=%04X D=%04X", blt_info.bltafwm, blt_info.bltalwm, blt_info.bltamod & 0xffff, blt_info.bltbmod & 0xffff, blt_info.bltcmod & 0xffff, blt_info.bltdmod & 0xffff); + SAEF_log("PC=%08X DMA=%d", SAER_CPU_getPC(), SAEF_Custom_dmaen(SAEC_Custom_DMAF_BLTEN)); + if (((bltcon0 & 0x800) && bltapt >= chipsize) || ((bltcon0 & 0x400) && bltbpt >= chipsize) || ((bltcon0 & 0x200) && bltcpt >= chipsize) || ((bltcon0 & 0x100) && bltdpt >= chipsize)) + SAEF_log("PT outside of chipram"); }*/ - function castWord(v) { - return (v & 0x8000) ? (v - 0x10000) : v; - } + /*-----------------------------------------------------------------------*/ - function get_ch() { + function get_ch() { //int * if (blit_faulty) { - console.log('get_ch() blit_faulty'); - return blit_cycle_diagram[0]; //&blit_diag[0]; - } + //return &blit_diag[0]; //ORG + switch (blit_diag_type) { + case DT_BLOCK: return blit_cycle_diagram[0]; + case DT_BLOCKFILL: return blit_cycle_diagram_fill[0]; + case DT_LINE: return blit_cycle_diagram_line; + default: return blit_cycle_diagram[0]; + } + } + if (blit_final) + return blitline || blit_nod ? blit_cycle_diagram_finalld : blit_cycle_diagram_finald; + return blit_diag; } function channel_state(cycles) { - //console.log('channel_state()', cycles); if (cycles < 0) return 0; var diag = get_ch(); @@ -164,1861 +252,99 @@ function Blitter() { cycles %= diag[0]; return diag[1 + diag[0] + cycles]; } - - /*function channel_pos(cycles) { + function channel_pos(cycles) { if (cycles < 0) return 0; - var diag = get_ch(); + var diag = get_ch(); if (cycles < diag[0]) return cycles; cycles -= diag[0]; cycles %= diag[0]; return cycles; + } + /*this.blitter_channel_state = function() { + return channel_state(blit_cyclecounter); }*/ - function blitter_interrupt() { - if (blit_interrupt) + function canblit(hpos) { + if (!SAEF_Custom_dmaen(SAEC_Custom_DMAF_BLTEN)) + return -1; + if (SAER.playfield.is_bitplane_dma(hpos)) + return 0; + /*if (SAER_Events_cycle_line[hpos] & SAEC_Events_cycle_line_MASK) { + #if 0 + if ((SAEV_Custom_dmacon & SAEC_Custom_DMAF_BLTPRI) && SAER_Events_cycle_line[hpos] == SAEC_Events_cycle_line_CPU) + SAEF_warn("blitter.canblit() CPU stole cycle from blitter without nasty!?"); + #endif + return 0; + }*/ + return 1; + } + + function reset_channel_mods() { + if (bltptxpos < 0) return; - blit_interrupt = true; - AMIGA.INTREQ_0(INT_BLIT); + bltptxpos = -1; + switch (bltptxc) { + case 1: bltapt = bltptx; break; + case 2: bltbpt = bltptx; break; + case 3: bltcpt = bltptx; break; + case 4: bltdpt = bltptx; break; + } + } + function check_channel_mods(hpos, ch) { + if (bltptxpos != hpos) + return; + if (ch == bltptxc) { + bltptxpos = -1; + SAEF_warn("blitter.check_channel_mods() %08x write to %d ignored!", bltptx, ch); + } + } + + // blitter interrupt is set (and busy bit cleared) when + // last "main" cycle has been finished, any non-linedraw + // D-channel blit still needs 2 more cycles before final + // D is written (idle cycle, final D write) + // + // line draw interrupt triggers when last D is written + // (or cycle where last D write would have been if + // ONEDOT was active) + + function blitter_interrupt(hpos, done) { + if (SAEV_Blitter_interrupt) + return; + if (!done && (!blitter_cycle_exact || immediate_blits || SAEV_config.cpu.speed < 0 || SAEV_config.cpu.model >= SAEC_Config_CPU_Model_68030)) + return; + SAEV_Blitter_interrupt = true; + SAER.custom.send_interrupt(SAEC_Custom_INTF_BLIT, 4 * SAEC_Events_CYCLE_UNIT); } function blitter_done(hpos) { ddat1use = ddat2use = 0; - bltstate = BLT_done; - blitter_interrupt(); - AMIGA.copper.blitter_done_notify(hpos); - AMIGA.events.remevent(EV2_BLITTER); - clr_special(SPCFLAG_BLTNASTY); + SAEV_Blitter_bltstate = blit_startcycles == 0 || !blitter_cycle_exact || immediate_blits ? SAEC_Blitter_bltstate_DONE : SAEC_Blitter_bltstate_INIT; + blitter_interrupt(hpos, 1); + SAER.copper.blitter_done_notify(hpos); + SAER.events.event2_remevent(SAEC_Events_EV2_BLITTER); + SAEF_clrSpcFlags(SAEC_spcflag_BLTNASTY); + //if (log_blitter & 1) SAEF_log("blitter.blitter_done() cycles %d, missed %d, total %d", blit_totalcyclecounter, blit_misscyclecounter, blit_totalcyclecounter + blit_misscyclecounter); + SAEV_Blitter_dangerous = false; } - - /*---------------------------------*/ - /* ~1500 lines of auto-generated functions are follwing... */ - /*---------------------------------*/ - - function blitdofast_0(pta, ptb, ptc, ptd, b) { - var i,j; - var totald = 0; - var dstd = 0; - var dstp = 0; - for (j = 0; j < b.vblitsize; j++) { - for (i = 0; i < b.hblitsize; i++) { - var bltadat, srca; - if (dstp) AMIGA.mem.chip.data[dstp >>> 1] = dstd; - dstd = (0) & 0xffff; - totald |= dstd; - if (ptd) { dstp = ptd; ptd += 2; } - } - if (ptd) ptd += b.bltdmod; + /*OWN opt inline + function chipmem_agnus_wput2(addr, w) { + //SAEV_Custom_last_value = w; blitter writes are not stored + //if (!(log_blitter & 4)) + { + //SAER_Memory_chipPut16_indirect(addr, w); + SAER_Memory_chipData[addr] = w >> 8; + SAER_Memory_chipData[addr+1] = w & 0xff; } - if (dstp) AMIGA.mem.chip.data[dstp >>> 1] = dstd; - if (totald != 0) b.blitzero = 0; - } + }*/ - function blitdofast_desc_0(pta, ptb, ptc, ptd, b) { - var totald = 0; - var i,j; - var dstd = 0; - var dstp = 0; - for (j = 0; j < b.vblitsize; j++) { - for (i = 0; i < b.hblitsize; i++) { - var bltadat, srca; - if (dstp) AMIGA.mem.chip.data[dstp >>> 1] = dstd; - dstd = (0) & 0xffff; - totald |= dstd; - if (ptd) { dstp = ptd; ptd -= 2; } - } - if (ptd) ptd -= b.bltdmod; - } - if (dstp) AMIGA.mem.chip.data[dstp >>> 1] = dstd; - if (totald != 0) b.blitzero = 0; - } - - function blitdofast_a(pta, ptb, ptc, ptd, b) { - var i,j; - var totald = 0; - var preva = 0; - var srcc = b.bltcdat; - var dstd = 0; - var dstp = 0; - for (j = 0; j < b.vblitsize; j++) { - for (i = 0; i < b.hblitsize; i++) { - var bltadat, srca; - - if (ptc) { srcc = AMIGA.mem.chip.data[ptc >>> 1]; ptc += 2; } - if (pta) { bltadat = blt_info.bltadat = AMIGA.mem.chip.data[pta >>> 1]; pta += 2; } else { bltadat = blt_info.bltadat; } - bltadat &= blit_masktable[i]; - srca = ((((preva << 16) | bltadat) >>> 0) >>> b.blitashift) & 0xffff; - preva = bltadat; - if (dstp) AMIGA.mem.chip.data[dstp >>> 1] = dstd; - dstd = ((~srca & srcc)) & 0xffff; - totald |= dstd; - if (ptd) { dstp = ptd; ptd += 2; } - } - if (pta) pta += b.bltamod; - if (ptc) ptc += b.bltcmod; - if (ptd) ptd += b.bltdmod; - } - b.bltcdat = srcc; - if (dstp) AMIGA.mem.chip.data[dstp >>> 1] = dstd; - if (totald != 0) b.blitzero = 0; - } - - function blitdofast_desc_a(pta, ptb, ptc, ptd, b) { - var totald = 0; - var i,j; - var preva = 0; - var srcc = b.bltcdat; - var dstd = 0; - var dstp = 0; - for (j = 0; j < b.vblitsize; j++) { - for (i = 0; i < b.hblitsize; i++) { - var bltadat, srca; - if (ptc) { srcc = AMIGA.mem.chip.data[ptc >>> 1]; ptc -= 2; } - if (pta) { bltadat = blt_info.bltadat = AMIGA.mem.chip.data[pta >>> 1]; pta -= 2; } else { bltadat = blt_info.bltadat; } - bltadat &= blit_masktable[i]; - srca = ((((bltadat << 16) | preva) >>> 0) >>> b.blitdownashift) & 0xffff; - preva = bltadat; - if (dstp) AMIGA.mem.chip.data[dstp >>> 1] = dstd; - dstd = ((~srca & srcc)) & 0xffff; - totald |= dstd; - if (ptd) { dstp = ptd; ptd -= 2; } - } - if (pta) pta -= b.bltamod; - if (ptc) ptc -= b.bltcmod; - if (ptd) ptd -= b.bltdmod; - } - b.bltcdat = srcc; - if (dstp) AMIGA.mem.chip.data[dstp >>> 1] = dstd; - if (totald != 0) b.blitzero = 0; - } - - function blitdofast_2a(pta, ptb, ptc, ptd, b) { - var i,j; - var totald = 0; - var preva = 0; - var prevb = 0, srcb = b.bltbhold; - var srcc = b.bltcdat; - var dstd = 0; - var dstp = 0; - for (j = 0; j < b.vblitsize; j++) { - for (i = 0; i < b.hblitsize; i++) { - var bltadat, srca; - - if (ptc) { srcc = AMIGA.mem.chip.data[ptc >>> 1]; ptc += 2; } - if (ptb) { - var bltbdat = blt_info.bltbdat = AMIGA.mem.chip.data[ptb >>> 1]; ptb += 2; - srcb = ((((prevb << 16) | bltbdat) >>> 0) >>> b.blitbshift) & 0xffff; - prevb = bltbdat; - } - if (pta) { bltadat = blt_info.bltadat = AMIGA.mem.chip.data[pta >>> 1]; pta += 2; } else { bltadat = blt_info.bltadat; } - bltadat &= blit_masktable[i]; - srca = ((((preva << 16) | bltadat) >>> 0) >>> b.blitashift) & 0xffff; - preva = bltadat; - if (dstp) AMIGA.mem.chip.data[dstp >>> 1] = dstd; - dstd = ((srcc & ~(srca & srcb))) & 0xffff; - totald |= dstd; - if (ptd) { dstp = ptd; ptd += 2; } - } - if (pta) pta += b.bltamod; - if (ptb) ptb += b.bltbmod; - if (ptc) ptc += b.bltcmod; - if (ptd) ptd += b.bltdmod; - } - b.bltbhold = srcb; - b.bltcdat = srcc; - if (dstp) AMIGA.mem.chip.data[dstp >>> 1] = dstd; - if (totald != 0) b.blitzero = 0; - } - - function blitdofast_desc_2a(pta, ptb, ptc, ptd, b) { - var totald = 0; - var i,j; - var preva = 0; - var prevb = 0, srcb = b.bltbhold; - var srcc = b.bltcdat; - var dstd = 0; - var dstp = 0; - for (j = 0; j < b.vblitsize; j++) { - for (i = 0; i < b.hblitsize; i++) { - var bltadat, srca; - if (ptc) { srcc = AMIGA.mem.chip.data[ptc >>> 1]; ptc -= 2; } - if (ptb) { - var bltbdat = blt_info.bltbdat = AMIGA.mem.chip.data[ptb >>> 1]; ptb -= 2; - srcb = ((((bltbdat << 16) | prevb) >>> 0) >>> b.blitdownbshift) & 0xffff; - prevb = bltbdat; - } - if (pta) { bltadat = blt_info.bltadat = AMIGA.mem.chip.data[pta >>> 1]; pta -= 2; } else { bltadat = blt_info.bltadat; } - bltadat &= blit_masktable[i]; - srca = ((((bltadat << 16) | preva) >>> 0) >>> b.blitdownashift) & 0xffff; - preva = bltadat; - if (dstp) AMIGA.mem.chip.data[dstp >>> 1] = dstd; - dstd = ((srcc & ~(srca & srcb))) & 0xffff; - totald |= dstd; - if (ptd) { dstp = ptd; ptd -= 2; } - } - if (pta) pta -= b.bltamod; - if (ptb) ptb -= b.bltbmod; - if (ptc) ptc -= b.bltcmod; - if (ptd) ptd -= b.bltdmod; - } - b.bltbhold = srcb; - b.bltcdat = srcc; - if (dstp) AMIGA.mem.chip.data[dstp >>> 1] = dstd; - if (totald != 0) b.blitzero = 0; - } - - function blitdofast_30(pta, ptb, ptc, ptd, b) { - var i,j; - var totald = 0; - var preva = 0; - var prevb = 0, srcb = b.bltbhold; - var dstd = 0; - var dstp = 0; - for (j = 0; j < b.vblitsize; j++) { - for (i = 0; i < b.hblitsize; i++) { - var bltadat, srca; - - if (ptb) { - var bltbdat = blt_info.bltbdat = AMIGA.mem.chip.data[ptb >>> 1]; ptb += 2; - srcb = ((((prevb << 16) | bltbdat) >>> 0) >>> b.blitbshift) & 0xffff; - prevb = bltbdat; - } - if (pta) { bltadat = blt_info.bltadat = AMIGA.mem.chip.data[pta >>> 1]; pta += 2; } else { bltadat = blt_info.bltadat; } - bltadat &= blit_masktable[i]; - srca = ((((preva << 16) | bltadat) >>> 0) >>> b.blitashift) & 0xffff; - preva = bltadat; - if (dstp) AMIGA.mem.chip.data[dstp >>> 1] = dstd; - dstd = ((srca & ~srcb)) & 0xffff; - totald |= dstd; - if (ptd) { dstp = ptd; ptd += 2; } - } - if (pta) pta += b.bltamod; - if (ptb) ptb += b.bltbmod; - if (ptd) ptd += b.bltdmod; - } - b.bltbhold = srcb; - if (dstp) AMIGA.mem.chip.data[dstp >>> 1] = dstd; - if (totald != 0) b.blitzero = 0; - } - - function blitdofast_desc_30(pta, ptb, ptc, ptd, b) { - var totald = 0; - var i,j; - var preva = 0; - var prevb = 0, srcb = b.bltbhold; - var dstd = 0; - var dstp = 0; - for (j = 0; j < b.vblitsize; j++) { - for (i = 0; i < b.hblitsize; i++) { - var bltadat, srca; - if (ptb) { - var bltbdat = blt_info.bltbdat = AMIGA.mem.chip.data[ptb >>> 1]; ptb -= 2; - srcb = ((((bltbdat << 16) | prevb) >>> 0) >>> b.blitdownbshift) & 0xffff; - prevb = bltbdat; - } - if (pta) { bltadat = blt_info.bltadat = AMIGA.mem.chip.data[pta >>> 1]; pta -= 2; } else { bltadat = blt_info.bltadat; } - bltadat &= blit_masktable[i]; - srca = ((((bltadat << 16) | preva) >>> 0) >>> b.blitdownashift) & 0xffff; - preva = bltadat; - if (dstp) AMIGA.mem.chip.data[dstp >>> 1] = dstd; - dstd = ((srca & ~srcb)) & 0xffff; - totald |= dstd; - if (ptd) { dstp = ptd; ptd -= 2; } - } - if (pta) pta -= b.bltamod; - if (ptb) ptb -= b.bltbmod; - if (ptd) ptd -= b.bltdmod; - } - b.bltbhold = srcb; - if (dstp) AMIGA.mem.chip.data[dstp >>> 1] = dstd; - if (totald != 0) b.blitzero = 0; - } - - function blitdofast_3a(pta, ptb, ptc, ptd, b) { - var i,j; - var totald = 0; - var preva = 0; - var prevb = 0, srcb = b.bltbhold; - var srcc = b.bltcdat; - var dstd = 0; - var dstp = 0; - for (j = 0; j < b.vblitsize; j++) { - for (i = 0; i < b.hblitsize; i++) { - var bltadat, srca; - - if (ptc) { srcc = AMIGA.mem.chip.data[ptc >>> 1]; ptc += 2; } - if (ptb) { - var bltbdat = blt_info.bltbdat = AMIGA.mem.chip.data[ptb >>> 1]; ptb += 2; - srcb = ((((prevb << 16) | bltbdat) >>> 0) >>> b.blitbshift) & 0xffff; - prevb = bltbdat; - } - if (pta) { bltadat = blt_info.bltadat = AMIGA.mem.chip.data[pta >>> 1]; pta += 2; } else { bltadat = blt_info.bltadat; } - bltadat &= blit_masktable[i]; - srca = ((((preva << 16) | bltadat) >>> 0) >>> b.blitashift) & 0xffff; - preva = bltadat; - if (dstp) AMIGA.mem.chip.data[dstp >>> 1] = dstd; - dstd = ((srcb ^ (srca | (srcb ^ srcc)))) & 0xffff; - totald |= dstd; - if (ptd) { dstp = ptd; ptd += 2; } - } - if (pta) pta += b.bltamod; - if (ptb) ptb += b.bltbmod; - if (ptc) ptc += b.bltcmod; - if (ptd) ptd += b.bltdmod; - } - b.bltbhold = srcb; - b.bltcdat = srcc; - if (dstp) AMIGA.mem.chip.data[dstp >>> 1] = dstd; - if (totald != 0) b.blitzero = 0; - } - - function blitdofast_desc_3a(pta, ptb, ptc, ptd, b) { - var totald = 0; - var i,j; - var preva = 0; - var prevb = 0, srcb = b.bltbhold; - var srcc = b.bltcdat; - var dstd = 0; - var dstp = 0; - for (j = 0; j < b.vblitsize; j++) { - for (i = 0; i < b.hblitsize; i++) { - var bltadat, srca; - if (ptc) { srcc = AMIGA.mem.chip.data[ptc >>> 1]; ptc -= 2; } - if (ptb) { - var bltbdat = blt_info.bltbdat = AMIGA.mem.chip.data[ptb >>> 1]; ptb -= 2; - srcb = ((((bltbdat << 16) | prevb) >>> 0) >>> b.blitdownbshift) & 0xffff; - prevb = bltbdat; - } - if (pta) { bltadat = blt_info.bltadat = AMIGA.mem.chip.data[pta >>> 1]; pta -= 2; } else { bltadat = blt_info.bltadat; } - bltadat &= blit_masktable[i]; - srca = ((((bltadat << 16) | preva) >>> 0) >>> b.blitdownashift) & 0xffff; - preva = bltadat; - if (dstp) AMIGA.mem.chip.data[dstp >>> 1] = dstd; - dstd = ((srcb ^ (srca | (srcb ^ srcc)))) & 0xffff; - totald |= dstd; - if (ptd) { dstp = ptd; ptd -= 2; } - } - if (pta) pta -= b.bltamod; - if (ptb) ptb -= b.bltbmod; - if (ptc) ptc -= b.bltcmod; - if (ptd) ptd -= b.bltdmod; - } - b.bltbhold = srcb; - b.bltcdat = srcc; - if (dstp) AMIGA.mem.chip.data[dstp >>> 1] = dstd; - if (totald != 0) b.blitzero = 0; - } - - function blitdofast_3c(pta, ptb, ptc, ptd, b) { - var i,j; - var totald = 0; - var preva = 0; - var prevb = 0, srcb = b.bltbhold; - var dstd = 0; - var dstp = 0; - for (j = 0; j < b.vblitsize; j++) { - for (i = 0; i < b.hblitsize; i++) { - var bltadat, srca; - - if (ptb) { - var bltbdat = blt_info.bltbdat = AMIGA.mem.chip.data[ptb >>> 1]; ptb += 2; - srcb = ((((prevb << 16) | bltbdat) >>> 0) >>> b.blitbshift) & 0xffff; - prevb = bltbdat; - } - if (pta) { bltadat = blt_info.bltadat = AMIGA.mem.chip.data[pta >>> 1]; pta += 2; } else { bltadat = blt_info.bltadat; } - bltadat &= blit_masktable[i]; - srca = ((((preva << 16) | bltadat) >>> 0) >>> b.blitashift) & 0xffff; - preva = bltadat; - if (dstp) AMIGA.mem.chip.data[dstp >>> 1] = dstd; - dstd = ((srca ^ srcb)) & 0xffff; - totald |= dstd; - if (ptd) { dstp = ptd; ptd += 2; } - } - if (pta) pta += b.bltamod; - if (ptb) ptb += b.bltbmod; - if (ptd) ptd += b.bltdmod; - } - b.bltbhold = srcb; - if (dstp) AMIGA.mem.chip.data[dstp >>> 1] = dstd; - if (totald != 0) b.blitzero = 0; - } - - function blitdofast_desc_3c(pta, ptb, ptc, ptd, b) { - var totald = 0; - var i,j; - var preva = 0; - var prevb = 0, srcb = b.bltbhold; - var dstd = 0; - var dstp = 0; - for (j = 0; j < b.vblitsize; j++) { - for (i = 0; i < b.hblitsize; i++) { - var bltadat, srca; - if (ptb) { - var bltbdat = blt_info.bltbdat = AMIGA.mem.chip.data[ptb >>> 1]; ptb -= 2; - srcb = ((((bltbdat << 16) | prevb) >>> 0) >>> b.blitdownbshift) & 0xffff; - prevb = bltbdat; - } - if (pta) { bltadat = blt_info.bltadat = AMIGA.mem.chip.data[pta >>> 1]; pta -= 2; } else { bltadat = blt_info.bltadat; } - bltadat &= blit_masktable[i]; - srca = ((((bltadat << 16) | preva) >>> 0) >>> b.blitdownashift) & 0xffff; - preva = bltadat; - if (dstp) AMIGA.mem.chip.data[dstp >>> 1] = dstd; - dstd = ((srca ^ srcb)) & 0xffff; - totald |= dstd; - if (ptd) { dstp = ptd; ptd -= 2; } - } - if (pta) pta -= b.bltamod; - if (ptb) ptb -= b.bltbmod; - if (ptd) ptd -= b.bltdmod; - } - b.bltbhold = srcb; - if (dstp) AMIGA.mem.chip.data[dstp >>> 1] = dstd; - if (totald != 0) b.blitzero = 0; - } - - function blitdofast_4a(pta, ptb, ptc, ptd, b) { - var i,j; - var totald = 0; - var preva = 0; - var prevb = 0, srcb = b.bltbhold; - var srcc = b.bltcdat; - var dstd = 0; - var dstp = 0; - for (j = 0; j < b.vblitsize; j++) { - for (i = 0; i < b.hblitsize; i++) { - var bltadat, srca; - - if (ptc) { srcc = AMIGA.mem.chip.data[ptc >>> 1]; ptc += 2; } - if (ptb) { - var bltbdat = blt_info.bltbdat = AMIGA.mem.chip.data[ptb >>> 1]; ptb += 2; - srcb = ((((prevb << 16) | bltbdat) >>> 0) >>> b.blitbshift) & 0xffff; - prevb = bltbdat; - } - if (pta) { bltadat = blt_info.bltadat = AMIGA.mem.chip.data[pta >>> 1]; pta += 2; } else { bltadat = blt_info.bltadat; } - bltadat &= blit_masktable[i]; - srca = ((((preva << 16) | bltadat) >>> 0) >>> b.blitashift) & 0xffff; - preva = bltadat; - if (dstp) AMIGA.mem.chip.data[dstp >>> 1] = dstd; - dstd = ((srcc ^ (srca & (srcb | srcc)))) & 0xffff; - totald |= dstd; - if (ptd) { dstp = ptd; ptd += 2; } - } - if (pta) pta += b.bltamod; - if (ptb) ptb += b.bltbmod; - if (ptc) ptc += b.bltcmod; - if (ptd) ptd += b.bltdmod; - } - b.bltbhold = srcb; - b.bltcdat = srcc; - if (dstp) AMIGA.mem.chip.data[dstp >>> 1] = dstd; - if (totald != 0) b.blitzero = 0; - } - - function blitdofast_desc_4a(pta, ptb, ptc, ptd, b) { - var totald = 0; - var i,j; - var preva = 0; - var prevb = 0, srcb = b.bltbhold; - var srcc = b.bltcdat; - var dstd = 0; - var dstp = 0; - for (j = 0; j < b.vblitsize; j++) { - for (i = 0; i < b.hblitsize; i++) { - var bltadat, srca; - if (ptc) { srcc = AMIGA.mem.chip.data[ptc >>> 1]; ptc -= 2; } - if (ptb) { - var bltbdat = blt_info.bltbdat = AMIGA.mem.chip.data[ptb >>> 1]; ptb -= 2; - srcb = ((((bltbdat << 16) | prevb) >>> 0) >>> b.blitdownbshift) & 0xffff; - prevb = bltbdat; - } - if (pta) { bltadat = blt_info.bltadat = AMIGA.mem.chip.data[pta >>> 1]; pta -= 2; } else { bltadat = blt_info.bltadat; } - bltadat &= blit_masktable[i]; - srca = ((((bltadat << 16) | preva) >>> 0) >>> b.blitdownashift) & 0xffff; - preva = bltadat; - if (dstp) AMIGA.mem.chip.data[dstp >>> 1] = dstd; - dstd = ((srcc ^ (srca & (srcb | srcc)))) & 0xffff; - totald |= dstd; - if (ptd) { dstp = ptd; ptd -= 2; } - } - if (pta) pta -= b.bltamod; - if (ptb) ptb -= b.bltbmod; - if (ptc) ptc -= b.bltcmod; - if (ptd) ptd -= b.bltdmod; - } - b.bltbhold = srcb; - b.bltcdat = srcc; - if (dstp) AMIGA.mem.chip.data[dstp >>> 1] = dstd; - if (totald != 0) b.blitzero = 0; - } - - function blitdofast_6a(pta, ptb, ptc, ptd, b) { - var i,j; - var totald = 0; - var preva = 0; - var prevb = 0, srcb = b.bltbhold; - var srcc = b.bltcdat; - var dstd = 0; - var dstp = 0; - for (j = 0; j < b.vblitsize; j++) { - for (i = 0; i < b.hblitsize; i++) { - var bltadat, srca; - - if (ptc) { srcc = AMIGA.mem.chip.data[ptc >>> 1]; ptc += 2; } - if (ptb) { - var bltbdat = blt_info.bltbdat = AMIGA.mem.chip.data[ptb >>> 1]; ptb += 2; - srcb = ((((prevb << 16) | bltbdat) >>> 0) >>> b.blitbshift) & 0xffff; - prevb = bltbdat; - } - if (pta) { bltadat = blt_info.bltadat = AMIGA.mem.chip.data[pta >>> 1]; pta += 2; } else { bltadat = blt_info.bltadat; } - bltadat &= blit_masktable[i]; - srca = ((((preva << 16) | bltadat) >>> 0) >>> b.blitashift) & 0xffff; - preva = bltadat; - if (dstp) AMIGA.mem.chip.data[dstp >>> 1] = dstd; - dstd = ((srcc ^ (srca & srcb))) & 0xffff; - totald |= dstd; - if (ptd) { dstp = ptd; ptd += 2; } - } - if (pta) pta += b.bltamod; - if (ptb) ptb += b.bltbmod; - if (ptc) ptc += b.bltcmod; - if (ptd) ptd += b.bltdmod; - } - b.bltbhold = srcb; - b.bltcdat = srcc; - if (dstp) AMIGA.mem.chip.data[dstp >>> 1] = dstd; - if (totald != 0) b.blitzero = 0; - } - - function blitdofast_desc_6a(pta, ptb, ptc, ptd, b) { - var totald = 0; - var i,j; - var preva = 0; - var prevb = 0, srcb = b.bltbhold; - var srcc = b.bltcdat; - var dstd = 0; - var dstp = 0; - for (j = 0; j < b.vblitsize; j++) { - for (i = 0; i < b.hblitsize; i++) { - var bltadat, srca; - if (ptc) { srcc = AMIGA.mem.chip.data[ptc >>> 1]; ptc -= 2; } - if (ptb) { - var bltbdat = blt_info.bltbdat = AMIGA.mem.chip.data[ptb >>> 1]; ptb -= 2; - srcb = ((((bltbdat << 16) | prevb) >>> 0) >>> b.blitdownbshift) & 0xffff; - prevb = bltbdat; - } - if (pta) { bltadat = blt_info.bltadat = AMIGA.mem.chip.data[pta >>> 1]; pta -= 2; } else { bltadat = blt_info.bltadat; } - bltadat &= blit_masktable[i]; - srca = ((((bltadat << 16) | preva) >>> 0) >>> b.blitdownashift) & 0xffff; - preva = bltadat; - if (dstp) AMIGA.mem.chip.data[dstp >>> 1] = dstd; - dstd = ((srcc ^ (srca & srcb))) & 0xffff; - totald |= dstd; - if (ptd) { dstp = ptd; ptd -= 2; } - } - if (pta) pta -= b.bltamod; - if (ptb) ptb -= b.bltbmod; - if (ptc) ptc -= b.bltcmod; - if (ptd) ptd -= b.bltdmod; - } - b.bltbhold = srcb; - b.bltcdat = srcc; - if (dstp) AMIGA.mem.chip.data[dstp >>> 1] = dstd; - if (totald != 0) b.blitzero = 0; - } - - function blitdofast_8a(pta, ptb, ptc, ptd, b) { - var i,j; - var totald = 0; - var preva = 0; - var prevb = 0, srcb = b.bltbhold; - var srcc = b.bltcdat; - var dstd = 0; - var dstp = 0; - for (j = 0; j < b.vblitsize; j++) { - for (i = 0; i < b.hblitsize; i++) { - var bltadat, srca; - - if (ptc) { srcc = AMIGA.mem.chip.data[ptc >>> 1]; ptc += 2; } - if (ptb) { - var bltbdat = blt_info.bltbdat = AMIGA.mem.chip.data[ptb >>> 1]; ptb += 2; - srcb = ((((prevb << 16) | bltbdat) >>> 0) >>> b.blitbshift) & 0xffff; - prevb = bltbdat; - } - if (pta) { bltadat = blt_info.bltadat = AMIGA.mem.chip.data[pta >>> 1]; pta += 2; } else { bltadat = blt_info.bltadat; } - bltadat &= blit_masktable[i]; - srca = ((((preva << 16) | bltadat) >>> 0) >>> b.blitashift) & 0xffff; - preva = bltadat; - if (dstp) AMIGA.mem.chip.data[dstp >>> 1] = dstd; - dstd = ((srcc & (~srca | srcb))) & 0xffff; - totald |= dstd; - if (ptd) { dstp = ptd; ptd += 2; } - } - if (pta) pta += b.bltamod; - if (ptb) ptb += b.bltbmod; - if (ptc) ptc += b.bltcmod; - if (ptd) ptd += b.bltdmod; - } - b.bltbhold = srcb; - b.bltcdat = srcc; - if (dstp) AMIGA.mem.chip.data[dstp >>> 1] = dstd; - if (totald != 0) b.blitzero = 0; - } - - function blitdofast_desc_8a(pta, ptb, ptc, ptd, b) { - var totald = 0; - var i,j; - var preva = 0; - var prevb = 0, srcb = b.bltbhold; - var srcc = b.bltcdat; - var dstd = 0; - var dstp = 0; - for (j = 0; j < b.vblitsize; j++) { - for (i = 0; i < b.hblitsize; i++) { - var bltadat, srca; - if (ptc) { srcc = AMIGA.mem.chip.data[ptc >>> 1]; ptc -= 2; } - if (ptb) { - var bltbdat = blt_info.bltbdat = AMIGA.mem.chip.data[ptb >>> 1]; ptb -= 2; - srcb = ((((bltbdat << 16) | prevb) >>> 0) >>> b.blitdownbshift) & 0xffff; - prevb = bltbdat; - } - if (pta) { bltadat = blt_info.bltadat = AMIGA.mem.chip.data[pta >>> 1]; pta -= 2; } else { bltadat = blt_info.bltadat; } - bltadat &= blit_masktable[i]; - srca = ((((bltadat << 16) | preva) >>> 0) >>> b.blitdownashift) & 0xffff; - preva = bltadat; - if (dstp) AMIGA.mem.chip.data[dstp >>> 1] = dstd; - dstd = ((srcc & (~srca | srcb))) & 0xffff; - totald |= dstd; - if (ptd) { dstp = ptd; ptd -= 2; } - } - if (pta) pta -= b.bltamod; - if (ptb) ptb -= b.bltbmod; - if (ptc) ptc -= b.bltcmod; - if (ptd) ptd -= b.bltdmod; - } - b.bltbhold = srcb; - b.bltcdat = srcc; - if (dstp) AMIGA.mem.chip.data[dstp >>> 1] = dstd; - if (totald != 0) b.blitzero = 0; - } - - function blitdofast_8c(pta, ptb, ptc, ptd, b) { - var i,j; - var totald = 0; - var preva = 0; - var prevb = 0, srcb = b.bltbhold; - var srcc = b.bltcdat; - var dstd = 0; - var dstp = 0; - for (j = 0; j < b.vblitsize; j++) { - for (i = 0; i < b.hblitsize; i++) { - var bltadat, srca; - - if (ptc) { srcc = AMIGA.mem.chip.data[ptc >>> 1]; ptc += 2; } - if (ptb) { - var bltbdat = blt_info.bltbdat = AMIGA.mem.chip.data[ptb >>> 1]; ptb += 2; - srcb = ((((prevb << 16) | bltbdat) >>> 0) >>> b.blitbshift) & 0xffff; - prevb = bltbdat; - } - if (pta) { bltadat = blt_info.bltadat = AMIGA.mem.chip.data[pta >>> 1]; pta += 2; } else { bltadat = blt_info.bltadat; } - bltadat &= blit_masktable[i]; - srca = ((((preva << 16) | bltadat) >>> 0) >>> b.blitashift) & 0xffff; - preva = bltadat; - if (dstp) AMIGA.mem.chip.data[dstp >>> 1] = dstd; - dstd = ((srcb & (~srca | srcc))) & 0xffff; - totald |= dstd; - if (ptd) { dstp = ptd; ptd += 2; } - } - if (pta) pta += b.bltamod; - if (ptb) ptb += b.bltbmod; - if (ptc) ptc += b.bltcmod; - if (ptd) ptd += b.bltdmod; - } - b.bltbhold = srcb; - b.bltcdat = srcc; - if (dstp) AMIGA.mem.chip.data[dstp >>> 1] = dstd; - if (totald != 0) b.blitzero = 0; - } - - function blitdofast_desc_8c(pta, ptb, ptc, ptd, b) { - var totald = 0; - var i,j; - var preva = 0; - var prevb = 0, srcb = b.bltbhold; - var srcc = b.bltcdat; - var dstd = 0; - var dstp = 0; - for (j = 0; j < b.vblitsize; j++) { - for (i = 0; i < b.hblitsize; i++) { - var bltadat, srca; - if (ptc) { srcc = AMIGA.mem.chip.data[ptc >>> 1]; ptc -= 2; } - if (ptb) { - var bltbdat = blt_info.bltbdat = AMIGA.mem.chip.data[ptb >>> 1]; ptb -= 2; - srcb = ((((bltbdat << 16) | prevb) >>> 0) >>> b.blitdownbshift) & 0xffff; - prevb = bltbdat; - } - if (pta) { bltadat = blt_info.bltadat = AMIGA.mem.chip.data[pta >>> 1]; pta -= 2; } else { bltadat = blt_info.bltadat; } - bltadat &= blit_masktable[i]; - srca = ((((bltadat << 16) | preva) >>> 0) >>> b.blitdownashift) & 0xffff; - preva = bltadat; - if (dstp) AMIGA.mem.chip.data[dstp >>> 1] = dstd; - dstd = ((srcb & (~srca | srcc))) & 0xffff; - totald |= dstd; - if (ptd) { dstp = ptd; ptd -= 2; } - } - if (pta) pta -= b.bltamod; - if (ptb) ptb -= b.bltbmod; - if (ptc) ptc -= b.bltcmod; - if (ptd) ptd -= b.bltdmod; - } - b.bltbhold = srcb; - b.bltcdat = srcc; - if (dstp) AMIGA.mem.chip.data[dstp >>> 1] = dstd; - if (totald != 0) b.blitzero = 0; - } - - function blitdofast_9a(pta, ptb, ptc, ptd, b) { - var i,j; - var totald = 0; - var preva = 0; - var prevb = 0, srcb = b.bltbhold; - var srcc = b.bltcdat; - var dstd = 0; - var dstp = 0; - for (j = 0; j < b.vblitsize; j++) { - for (i = 0; i < b.hblitsize; i++) { - var bltadat, srca; - - if (ptc) { srcc = AMIGA.mem.chip.data[ptc >>> 1]; ptc += 2; } - if (ptb) { - var bltbdat = blt_info.bltbdat = AMIGA.mem.chip.data[ptb >>> 1]; ptb += 2; - srcb = ((((prevb << 16) | bltbdat) >>> 0) >>> b.blitbshift) & 0xffff; - prevb = bltbdat; - } - if (pta) { bltadat = blt_info.bltadat = AMIGA.mem.chip.data[pta >>> 1]; pta += 2; } else { bltadat = blt_info.bltadat; } - bltadat &= blit_masktable[i]; - srca = ((((preva << 16) | bltadat) >>> 0) >>> b.blitashift) & 0xffff; - preva = bltadat; - if (dstp) AMIGA.mem.chip.data[dstp >>> 1] = dstd; - dstd = ((srcc ^ (srca & ~srcb))) & 0xffff; - totald |= dstd; - if (ptd) { dstp = ptd; ptd += 2; } - } - if (pta) pta += b.bltamod; - if (ptb) ptb += b.bltbmod; - if (ptc) ptc += b.bltcmod; - if (ptd) ptd += b.bltdmod; - } - b.bltbhold = srcb; - b.bltcdat = srcc; - if (dstp) AMIGA.mem.chip.data[dstp >>> 1] = dstd; - if (totald != 0) b.blitzero = 0; - } - - function blitdofast_desc_9a(pta, ptb, ptc, ptd, b) { - var totald = 0; - var i,j; - var preva = 0; - var prevb = 0, srcb = b.bltbhold; - var srcc = b.bltcdat; - var dstd = 0; - var dstp = 0; - for (j = 0; j < b.vblitsize; j++) { - for (i = 0; i < b.hblitsize; i++) { - var bltadat, srca; - if (ptc) { srcc = AMIGA.mem.chip.data[ptc >>> 1]; ptc -= 2; } - if (ptb) { - var bltbdat = blt_info.bltbdat = AMIGA.mem.chip.data[ptb >>> 1]; ptb -= 2; - srcb = ((((bltbdat << 16) | prevb) >>> 0) >>> b.blitdownbshift) & 0xffff; - prevb = bltbdat; - } - if (pta) { bltadat = blt_info.bltadat = AMIGA.mem.chip.data[pta >>> 1]; pta -= 2; } else { bltadat = blt_info.bltadat; } - bltadat &= blit_masktable[i]; - srca = ((((bltadat << 16) | preva) >>> 0) >>> b.blitdownashift) & 0xffff; - preva = bltadat; - if (dstp) AMIGA.mem.chip.data[dstp >>> 1] = dstd; - dstd = ((srcc ^ (srca & ~srcb))) & 0xffff; - totald |= dstd; - if (ptd) { dstp = ptd; ptd -= 2; } - } - if (pta) pta -= b.bltamod; - if (ptb) ptb -= b.bltbmod; - if (ptc) ptc -= b.bltcmod; - if (ptd) ptd -= b.bltdmod; - } - b.bltbhold = srcb; - b.bltcdat = srcc; - if (dstp) AMIGA.mem.chip.data[dstp >>> 1] = dstd; - if (totald != 0) b.blitzero = 0; - } - - function blitdofast_a8(pta, ptb, ptc, ptd, b) { - var i,j; - var totald = 0; - var preva = 0; - var prevb = 0, srcb = b.bltbhold; - var srcc = b.bltcdat; - var dstd = 0; - var dstp = 0; - for (j = 0; j < b.vblitsize; j++) { - for (i = 0; i < b.hblitsize; i++) { - var bltadat, srca; - - if (ptc) { srcc = AMIGA.mem.chip.data[ptc >>> 1]; ptc += 2; } - if (ptb) { - var bltbdat = blt_info.bltbdat = AMIGA.mem.chip.data[ptb >>> 1]; ptb += 2; - srcb = ((((prevb << 16) | bltbdat) >>> 0) >>> b.blitbshift) & 0xffff; - prevb = bltbdat; - } - if (pta) { bltadat = blt_info.bltadat = AMIGA.mem.chip.data[pta >>> 1]; pta += 2; } else { bltadat = blt_info.bltadat; } - bltadat &= blit_masktable[i]; - srca = ((((preva << 16) | bltadat) >>> 0) >>> b.blitashift) & 0xffff; - preva = bltadat; - if (dstp) AMIGA.mem.chip.data[dstp >>> 1] = dstd; - dstd = ((srcc & (srca | srcb))) & 0xffff; - totald |= dstd; - if (ptd) { dstp = ptd; ptd += 2; } - } - if (pta) pta += b.bltamod; - if (ptb) ptb += b.bltbmod; - if (ptc) ptc += b.bltcmod; - if (ptd) ptd += b.bltdmod; - } - b.bltbhold = srcb; - b.bltcdat = srcc; - if (dstp) AMIGA.mem.chip.data[dstp >>> 1] = dstd; - if (totald != 0) b.blitzero = 0; - } - - function blitdofast_desc_a8(pta, ptb, ptc, ptd, b) { - var totald = 0; - var i,j; - var preva = 0; - var prevb = 0, srcb = b.bltbhold; - var srcc = b.bltcdat; - var dstd = 0; - var dstp = 0; - for (j = 0; j < b.vblitsize; j++) { - for (i = 0; i < b.hblitsize; i++) { - var bltadat, srca; - if (ptc) { srcc = AMIGA.mem.chip.data[ptc >>> 1]; ptc -= 2; } - if (ptb) { - var bltbdat = blt_info.bltbdat = AMIGA.mem.chip.data[ptb >>> 1]; ptb -= 2; - srcb = ((((bltbdat << 16) | prevb) >>> 0) >>> b.blitdownbshift) & 0xffff; - prevb = bltbdat; - } - if (pta) { bltadat = blt_info.bltadat = AMIGA.mem.chip.data[pta >>> 1]; pta -= 2; } else { bltadat = blt_info.bltadat; } - bltadat &= blit_masktable[i]; - srca = ((((bltadat << 16) | preva) >>> 0) >>> b.blitdownashift) & 0xffff; - preva = bltadat; - if (dstp) AMIGA.mem.chip.data[dstp >>> 1] = dstd; - dstd = ((srcc & (srca | srcb))) & 0xffff; - totald |= dstd; - if (ptd) { dstp = ptd; ptd -= 2; } - } - if (pta) pta -= b.bltamod; - if (ptb) ptb -= b.bltbmod; - if (ptc) ptc -= b.bltcmod; - if (ptd) ptd -= b.bltdmod; - } - b.bltbhold = srcb; - b.bltcdat = srcc; - if (dstp) AMIGA.mem.chip.data[dstp >>> 1] = dstd; - if (totald != 0) b.blitzero = 0; - } - - function blitdofast_aa(pta, ptb, ptc, ptd, b) { - var i,j; - var totald = 0; - var srcc = b.bltcdat; - var dstd = 0; - var dstp = 0; - for (j = 0; j < b.vblitsize; j++) { - for (i = 0; i < b.hblitsize; i++) { - var bltadat, srca; - - if (ptc) { srcc = AMIGA.mem.chip.data[ptc >>> 1]; ptc += 2; } - if (dstp) AMIGA.mem.chip.data[dstp >>> 1] = dstd; - dstd = (srcc) & 0xffff; - totald |= dstd; - if (ptd) { dstp = ptd; ptd += 2; } - } - if (ptc) ptc += b.bltcmod; - if (ptd) ptd += b.bltdmod; - } - b.bltcdat = srcc; - if (dstp) AMIGA.mem.chip.data[dstp >>> 1] = dstd; - if (totald != 0) b.blitzero = 0; - } - - function blitdofast_desc_aa(pta, ptb, ptc, ptd, b) { - var totald = 0; - var i,j; - var srcc = b.bltcdat; - var dstd = 0; - var dstp = 0; - for (j = 0; j < b.vblitsize; j++) { - for (i = 0; i < b.hblitsize; i++) { - var bltadat, srca; - if (ptc) { srcc = AMIGA.mem.chip.data[ptc >>> 1]; ptc -= 2; } - if (dstp) AMIGA.mem.chip.data[dstp >>> 1] = dstd; - dstd = (srcc) & 0xffff; - totald |= dstd; - if (ptd) { dstp = ptd; ptd -= 2; } - } - if (ptc) ptc -= b.bltcmod; - if (ptd) ptd -= b.bltdmod; - } - b.bltcdat = srcc; - if (dstp) AMIGA.mem.chip.data[dstp >>> 1] = dstd; - if (totald != 0) b.blitzero = 0; - } - - function blitdofast_b1(pta, ptb, ptc, ptd, b) { - var i,j; - var totald = 0; - var preva = 0; - var prevb = 0, srcb = b.bltbhold; - var srcc = b.bltcdat; - var dstd = 0; - var dstp = 0; - for (j = 0; j < b.vblitsize; j++) { - for (i = 0; i < b.hblitsize; i++) { - var bltadat, srca; - - if (ptc) { srcc = AMIGA.mem.chip.data[ptc >>> 1]; ptc += 2; } - if (ptb) { - var bltbdat = blt_info.bltbdat = AMIGA.mem.chip.data[ptb >>> 1]; ptb += 2; - srcb = ((((prevb << 16) | bltbdat) >>> 0) >>> b.blitbshift) & 0xffff; - prevb = bltbdat; - } - if (pta) { bltadat = blt_info.bltadat = AMIGA.mem.chip.data[pta >>> 1]; pta += 2; } else { bltadat = blt_info.bltadat; } - bltadat &= blit_masktable[i]; - srca = ((((preva << 16) | bltadat) >>> 0) >>> b.blitashift) & 0xffff; - preva = bltadat; - if (dstp) AMIGA.mem.chip.data[dstp >>> 1] = dstd; - dstd = (~(srca ^ (srcc | (srca ^ srcb)))) & 0xffff; - totald |= dstd; - if (ptd) { dstp = ptd; ptd += 2; } - } - if (pta) pta += b.bltamod; - if (ptb) ptb += b.bltbmod; - if (ptc) ptc += b.bltcmod; - if (ptd) ptd += b.bltdmod; - } - b.bltbhold = srcb; - b.bltcdat = srcc; - if (dstp) AMIGA.mem.chip.data[dstp >>> 1] = dstd; - if (totald != 0) b.blitzero = 0; - } - - function blitdofast_desc_b1(pta, ptb, ptc, ptd, b) { - var totald = 0; - var i,j; - var preva = 0; - var prevb = 0, srcb = b.bltbhold; - var srcc = b.bltcdat; - var dstd = 0; - var dstp = 0; - for (j = 0; j < b.vblitsize; j++) { - for (i = 0; i < b.hblitsize; i++) { - var bltadat, srca; - if (ptc) { srcc = AMIGA.mem.chip.data[ptc >>> 1]; ptc -= 2; } - if (ptb) { - var bltbdat = blt_info.bltbdat = AMIGA.mem.chip.data[ptb >>> 1]; ptb -= 2; - srcb = ((((bltbdat << 16) | prevb) >>> 0) >>> b.blitdownbshift) & 0xffff; - prevb = bltbdat; - } - if (pta) { bltadat = blt_info.bltadat = AMIGA.mem.chip.data[pta >>> 1]; pta -= 2; } else { bltadat = blt_info.bltadat; } - bltadat &= blit_masktable[i]; - srca = ((((bltadat << 16) | preva) >>> 0) >>> b.blitdownashift) & 0xffff; - preva = bltadat; - if (dstp) AMIGA.mem.chip.data[dstp >>> 1] = dstd; - dstd = (~(srca ^ (srcc | (srca ^ srcb)))) & 0xffff; - totald |= dstd; - if (ptd) { dstp = ptd; ptd -= 2; } - } - if (pta) pta -= b.bltamod; - if (ptb) ptb -= b.bltbmod; - if (ptc) ptc -= b.bltcmod; - if (ptd) ptd -= b.bltdmod; - } - b.bltbhold = srcb; - b.bltcdat = srcc; - if (dstp) AMIGA.mem.chip.data[dstp >>> 1] = dstd; - if (totald != 0) b.blitzero = 0; - } - - function blitdofast_ca(pta, ptb, ptc, ptd, b) { - var i,j; - var totald = 0; - var preva = 0; - var prevb = 0, srcb = b.bltbhold; - var srcc = b.bltcdat; - var dstd = 0; - var dstp = 0; - for (j = 0; j < b.vblitsize; j++) { - for (i = 0; i < b.hblitsize; i++) { - var bltadat, srca; - - if (ptc) { srcc = AMIGA.mem.chip.data[ptc >>> 1]; ptc += 2; } - if (ptb) { - var bltbdat = blt_info.bltbdat = AMIGA.mem.chip.data[ptb >>> 1]; ptb += 2; - srcb = ((((prevb << 16) | bltbdat) >>> 0) >>> b.blitbshift) & 0xffff; - prevb = bltbdat; - } - if (pta) { bltadat = blt_info.bltadat = AMIGA.mem.chip.data[pta >>> 1]; pta += 2; } else { bltadat = blt_info.bltadat; } - bltadat &= blit_masktable[i]; - srca = ((((preva << 16) | bltadat) >>> 0) >>> b.blitashift) & 0xffff; - preva = bltadat; - if (dstp) AMIGA.mem.chip.data[dstp >>> 1] = dstd; - dstd = ((srcc ^ (srca & (srcb ^ srcc)))) & 0xffff; - totald |= dstd; - if (ptd) { dstp = ptd; ptd += 2; } - } - if (pta) pta += b.bltamod; - if (ptb) ptb += b.bltbmod; - if (ptc) ptc += b.bltcmod; - if (ptd) ptd += b.bltdmod; - } - b.bltbhold = srcb; - b.bltcdat = srcc; - if (dstp) AMIGA.mem.chip.data[dstp >>> 1] = dstd; - if (totald != 0) b.blitzero = 0; - } - - function blitdofast_desc_ca(pta, ptb, ptc, ptd, b) { - var totald = 0; - var i,j; - var preva = 0; - var prevb = 0, srcb = b.bltbhold; - var srcc = b.bltcdat; - var dstd = 0; - var dstp = 0; - for (j = 0; j < b.vblitsize; j++) { - for (i = 0; i < b.hblitsize; i++) { - var bltadat, srca; - if (ptc) { srcc = AMIGA.mem.chip.data[ptc >>> 1]; ptc -= 2; } - if (ptb) { - var bltbdat = blt_info.bltbdat = AMIGA.mem.chip.data[ptb >>> 1]; ptb -= 2; - srcb = ((((bltbdat << 16) | prevb) >>> 0) >>> b.blitdownbshift) & 0xffff; - prevb = bltbdat; - } - if (pta) { bltadat = blt_info.bltadat = AMIGA.mem.chip.data[pta >>> 1]; pta -= 2; } else { bltadat = blt_info.bltadat; } - bltadat &= blit_masktable[i]; - srca = ((((bltadat << 16) | preva) >>> 0) >>> b.blitdownashift) & 0xffff; - preva = bltadat; - if (dstp) AMIGA.mem.chip.data[dstp >>> 1] = dstd; - dstd = ((srcc ^ (srca & (srcb ^ srcc)))) & 0xffff; - totald |= dstd; - if (ptd) { dstp = ptd; ptd -= 2; } - } - if (pta) pta -= b.bltamod; - if (ptb) ptb -= b.bltbmod; - if (ptc) ptc -= b.bltcmod; - if (ptd) ptd -= b.bltdmod; - } - b.bltbhold = srcb; - b.bltcdat = srcc; - if (dstp) AMIGA.mem.chip.data[dstp >>> 1] = dstd; - if (totald != 0) b.blitzero = 0; - } - - function blitdofast_cc(pta, ptb, ptc, ptd, b) { - var i,j; - var totald = 0; - var prevb = 0, srcb = b.bltbhold; - var dstd = 0; - var dstp = 0; - for (j = 0; j < b.vblitsize; j++) { - for (i = 0; i < b.hblitsize; i++) { - var bltadat, srca; - - if (ptb) { - var bltbdat = blt_info.bltbdat = AMIGA.mem.chip.data[ptb >>> 1]; ptb += 2; - srcb = ((((prevb << 16) | bltbdat) >>> 0) >>> b.blitbshift) & 0xffff; - prevb = bltbdat; - } - if (dstp) AMIGA.mem.chip.data[dstp >>> 1] = dstd; - dstd = (srcb) & 0xffff; - totald |= dstd; - if (ptd) { dstp = ptd; ptd += 2; } - } - if (ptb) ptb += b.bltbmod; - if (ptd) ptd += b.bltdmod; - } - b.bltbhold = srcb; - if (dstp) AMIGA.mem.chip.data[dstp >>> 1] = dstd; - if (totald != 0) b.blitzero = 0; - } - - function blitdofast_desc_cc(pta, ptb, ptc, ptd, b) { - var totald = 0; - var i,j; - var prevb = 0, srcb = b.bltbhold; - var dstd = 0; - var dstp = 0; - for (j = 0; j < b.vblitsize; j++) { - for (i = 0; i < b.hblitsize; i++) { - var bltadat, srca; - if (ptb) { - var bltbdat = blt_info.bltbdat = AMIGA.mem.chip.data[ptb >>> 1]; ptb -= 2; - srcb = ((((bltbdat << 16) | prevb) >>> 0) >>> b.blitdownbshift) & 0xffff; - prevb = bltbdat; - } - if (dstp) AMIGA.mem.chip.data[dstp >>> 1] = dstd; - dstd = (srcb) & 0xffff; - totald |= dstd; - if (ptd) { dstp = ptd; ptd -= 2; } - } - if (ptb) ptb -= b.bltbmod; - if (ptd) ptd -= b.bltdmod; - } - b.bltbhold = srcb; - if (dstp) AMIGA.mem.chip.data[dstp >>> 1] = dstd; - if (totald != 0) b.blitzero = 0; - } - - function blitdofast_d8(pta, ptb, ptc, ptd, b) { - var i,j; - var totald = 0; - var preva = 0; - var prevb = 0, srcb = b.bltbhold; - var srcc = b.bltcdat; - var dstd = 0; - var dstp = 0; - for (j = 0; j < b.vblitsize; j++) { - for (i = 0; i < b.hblitsize; i++) { - var bltadat, srca; - - if (ptc) { srcc = AMIGA.mem.chip.data[ptc >>> 1]; ptc += 2; } - if (ptb) { - var bltbdat = blt_info.bltbdat = AMIGA.mem.chip.data[ptb >>> 1]; ptb += 2; - srcb = ((((prevb << 16) | bltbdat) >>> 0) >>> b.blitbshift) & 0xffff; - prevb = bltbdat; - } - if (pta) { bltadat = blt_info.bltadat = AMIGA.mem.chip.data[pta >>> 1]; pta += 2; } else { bltadat = blt_info.bltadat; } - bltadat &= blit_masktable[i]; - srca = ((((preva << 16) | bltadat) >>> 0) >>> b.blitashift) & 0xffff; - preva = bltadat; - if (dstp) AMIGA.mem.chip.data[dstp >>> 1] = dstd; - dstd = ((srca ^ (srcc & (srca ^ srcb)))) & 0xffff; - totald |= dstd; - if (ptd) { dstp = ptd; ptd += 2; } - } - if (pta) pta += b.bltamod; - if (ptb) ptb += b.bltbmod; - if (ptc) ptc += b.bltcmod; - if (ptd) ptd += b.bltdmod; - } - b.bltbhold = srcb; - b.bltcdat = srcc; - if (dstp) AMIGA.mem.chip.data[dstp >>> 1] = dstd; - if (totald != 0) b.blitzero = 0; - } - - function blitdofast_desc_d8(pta, ptb, ptc, ptd, b) { - var totald = 0; - var i,j; - var preva = 0; - var prevb = 0, srcb = b.bltbhold; - var srcc = b.bltcdat; - var dstd = 0; - var dstp = 0; - for (j = 0; j < b.vblitsize; j++) { - for (i = 0; i < b.hblitsize; i++) { - var bltadat, srca; - if (ptc) { srcc = AMIGA.mem.chip.data[ptc >>> 1]; ptc -= 2; } - if (ptb) { - var bltbdat = blt_info.bltbdat = AMIGA.mem.chip.data[ptb >>> 1]; ptb -= 2; - srcb = ((((bltbdat << 16) | prevb) >>> 0) >>> b.blitdownbshift) & 0xffff; - prevb = bltbdat; - } - if (pta) { bltadat = blt_info.bltadat = AMIGA.mem.chip.data[pta >>> 1]; pta -= 2; } else { bltadat = blt_info.bltadat; } - bltadat &= blit_masktable[i]; - srca = ((((bltadat << 16) | preva) >>> 0) >>> b.blitdownashift) & 0xffff; - preva = bltadat; - if (dstp) AMIGA.mem.chip.data[dstp >>> 1] = dstd; - dstd = ((srca ^ (srcc & (srca ^ srcb)))) & 0xffff; - totald |= dstd; - if (ptd) { dstp = ptd; ptd -= 2; } - } - if (pta) pta -= b.bltamod; - if (ptb) ptb -= b.bltbmod; - if (ptc) ptc -= b.bltcmod; - if (ptd) ptd -= b.bltdmod; - } - b.bltbhold = srcb; - b.bltcdat = srcc; - if (dstp) AMIGA.mem.chip.data[dstp >>> 1] = dstd; - if (totald != 0) b.blitzero = 0; - } - - function blitdofast_e2(pta, ptb, ptc, ptd, b) { - var i,j; - var totald = 0; - var preva = 0; - var prevb = 0, srcb = b.bltbhold; - var srcc = b.bltcdat; - var dstd = 0; - var dstp = 0; - for (j = 0; j < b.vblitsize; j++) { - for (i = 0; i < b.hblitsize; i++) { - var bltadat, srca; - - if (ptc) { srcc = AMIGA.mem.chip.data[ptc >>> 1]; ptc += 2; } - if (ptb) { - var bltbdat = blt_info.bltbdat = AMIGA.mem.chip.data[ptb >>> 1]; ptb += 2; - srcb = ((((prevb << 16) | bltbdat) >>> 0) >>> b.blitbshift) & 0xffff; - prevb = bltbdat; - } - if (pta) { bltadat = blt_info.bltadat = AMIGA.mem.chip.data[pta >>> 1]; pta += 2; } else { bltadat = blt_info.bltadat; } - bltadat &= blit_masktable[i]; - srca = ((((preva << 16) | bltadat) >>> 0) >>> b.blitashift) & 0xffff; - preva = bltadat; - if (dstp) AMIGA.mem.chip.data[dstp >>> 1] = dstd; - dstd = ((srcc ^ (srcb & (srca ^ srcc)))) & 0xffff; - totald |= dstd; - if (ptd) { dstp = ptd; ptd += 2; } - } - if (pta) pta += b.bltamod; - if (ptb) ptb += b.bltbmod; - if (ptc) ptc += b.bltcmod; - if (ptd) ptd += b.bltdmod; - } - b.bltbhold = srcb; - b.bltcdat = srcc; - if (dstp) AMIGA.mem.chip.data[dstp >>> 1] = dstd; - if (totald != 0) b.blitzero = 0; - } - - function blitdofast_desc_e2(pta, ptb, ptc, ptd, b) { - var totald = 0; - var i,j; - var preva = 0; - var prevb = 0, srcb = b.bltbhold; - var srcc = b.bltcdat; - var dstd = 0; - var dstp = 0; - for (j = 0; j < b.vblitsize; j++) { - for (i = 0; i < b.hblitsize; i++) { - var bltadat, srca; - if (ptc) { srcc = AMIGA.mem.chip.data[ptc >>> 1]; ptc -= 2; } - if (ptb) { - var bltbdat = blt_info.bltbdat = AMIGA.mem.chip.data[ptb >>> 1]; ptb -= 2; - srcb = ((((bltbdat << 16) | prevb) >>> 0) >>> b.blitdownbshift) & 0xffff; - prevb = bltbdat; - } - if (pta) { bltadat = blt_info.bltadat = AMIGA.mem.chip.data[pta >>> 1]; pta -= 2; } else { bltadat = blt_info.bltadat; } - bltadat &= blit_masktable[i]; - srca = ((((bltadat << 16) | preva) >>> 0) >>> b.blitdownashift) & 0xffff; - preva = bltadat; - if (dstp) AMIGA.mem.chip.data[dstp >>> 1] = dstd; - dstd = ((srcc ^ (srcb & (srca ^ srcc)))) & 0xffff; - totald |= dstd; - if (ptd) { dstp = ptd; ptd -= 2; } - } - if (pta) pta -= b.bltamod; - if (ptb) ptb -= b.bltbmod; - if (ptc) ptc -= b.bltcmod; - if (ptd) ptd -= b.bltdmod; - } - b.bltbhold = srcb; - b.bltcdat = srcc; - if (dstp) AMIGA.mem.chip.data[dstp >>> 1] = dstd; - if (totald != 0) b.blitzero = 0; - } - - function blitdofast_ea(pta, ptb, ptc, ptd, b) { - var i,j; - var totald = 0; - var preva = 0; - var prevb = 0, srcb = b.bltbhold; - var srcc = b.bltcdat; - var dstd = 0; - var dstp = 0; - for (j = 0; j < b.vblitsize; j++) { - for (i = 0; i < b.hblitsize; i++) { - var bltadat, srca; - - if (ptc) { srcc = AMIGA.mem.chip.data[ptc >>> 1]; ptc += 2; } - if (ptb) { - var bltbdat = blt_info.bltbdat = AMIGA.mem.chip.data[ptb >>> 1]; ptb += 2; - srcb = ((((prevb << 16) | bltbdat) >>> 0) >>> b.blitbshift) & 0xffff; - prevb = bltbdat; - } - if (pta) { bltadat = blt_info.bltadat = AMIGA.mem.chip.data[pta >>> 1]; pta += 2; } else { bltadat = blt_info.bltadat; } - bltadat &= blit_masktable[i]; - srca = ((((preva << 16) | bltadat) >>> 0) >>> b.blitashift) & 0xffff; - preva = bltadat; - if (dstp) AMIGA.mem.chip.data[dstp >>> 1] = dstd; - dstd = ((srcc | (srca & srcb))) & 0xffff; - totald |= dstd; - if (ptd) { dstp = ptd; ptd += 2; } - } - if (pta) pta += b.bltamod; - if (ptb) ptb += b.bltbmod; - if (ptc) ptc += b.bltcmod; - if (ptd) ptd += b.bltdmod; - } - b.bltbhold = srcb; - b.bltcdat = srcc; - if (dstp) AMIGA.mem.chip.data[dstp >>> 1] = dstd; - if (totald != 0) b.blitzero = 0; - } - - function blitdofast_desc_ea(pta, ptb, ptc, ptd, b) { - var totald = 0; - var i,j; - var preva = 0; - var prevb = 0, srcb = b.bltbhold; - var srcc = b.bltcdat; - var dstd = 0; - var dstp = 0; - for (j = 0; j < b.vblitsize; j++) { - for (i = 0; i < b.hblitsize; i++) { - var bltadat, srca; - if (ptc) { srcc = AMIGA.mem.chip.data[ptc >>> 1]; ptc -= 2; } - if (ptb) { - var bltbdat = blt_info.bltbdat = AMIGA.mem.chip.data[ptb >>> 1]; ptb -= 2; - srcb = ((((bltbdat << 16) | prevb) >>> 0) >>> b.blitdownbshift) & 0xffff; - prevb = bltbdat; - } - if (pta) { bltadat = blt_info.bltadat = AMIGA.mem.chip.data[pta >>> 1]; pta -= 2; } else { bltadat = blt_info.bltadat; } - bltadat &= blit_masktable[i]; - srca = ((((bltadat << 16) | preva) >>> 0) >>> b.blitdownashift) & 0xffff; - preva = bltadat; - if (dstp) AMIGA.mem.chip.data[dstp >>> 1] = dstd; - dstd = ((srcc | (srca & srcb))) & 0xffff; - totald |= dstd; - if (ptd) { dstp = ptd; ptd -= 2; } - } - if (pta) pta -= b.bltamod; - if (ptb) ptb -= b.bltbmod; - if (ptc) ptc -= b.bltcmod; - if (ptd) ptd -= b.bltdmod; - } - b.bltbhold = srcb; - b.bltcdat = srcc; - if (dstp) AMIGA.mem.chip.data[dstp >>> 1] = dstd; - if (totald != 0) b.blitzero = 0; - } - - function blitdofast_f0(pta, ptb, ptc, ptd, b) { - var i,j; - var totald = 0; - var preva = 0; - var dstd = 0; - var dstp = 0; - for (j = 0; j < b.vblitsize; j++) { - for (i = 0; i < b.hblitsize; i++) { - var bltadat, srca; - - if (pta) { bltadat = blt_info.bltadat = AMIGA.mem.chip.data[pta >>> 1]; pta += 2; } else { bltadat = blt_info.bltadat; } - bltadat &= blit_masktable[i]; - srca = ((((preva << 16) | bltadat) >>> 0) >>> b.blitashift) & 0xffff; - preva = bltadat; - if (dstp) AMIGA.mem.chip.data[dstp >>> 1] = dstd; - dstd = (srca) & 0xffff; - totald |= dstd; - if (ptd) { dstp = ptd; ptd += 2; } - } - if (pta) pta += b.bltamod; - if (ptd) ptd += b.bltdmod; - } - if (dstp) AMIGA.mem.chip.data[dstp >>> 1] = dstd; - if (totald != 0) b.blitzero = 0; - } - - function blitdofast_desc_f0(pta, ptb, ptc, ptd, b) { - var totald = 0; - var i,j; - var preva = 0; - var dstd = 0; - var dstp = 0; - for (j = 0; j < b.vblitsize; j++) { - for (i = 0; i < b.hblitsize; i++) { - var bltadat, srca; - if (pta) { bltadat = blt_info.bltadat = AMIGA.mem.chip.data[pta >>> 1]; pta -= 2; } else { bltadat = blt_info.bltadat; } - bltadat &= blit_masktable[i]; - srca = ((((bltadat << 16) | preva) >>> 0) >>> b.blitdownashift) & 0xffff; - preva = bltadat; - if (dstp) AMIGA.mem.chip.data[dstp >>> 1] = dstd; - dstd = (srca) & 0xffff; - totald |= dstd; - if (ptd) { dstp = ptd; ptd -= 2; } - } - if (pta) pta -= b.bltamod; - if (ptd) ptd -= b.bltdmod; - } - if (dstp) AMIGA.mem.chip.data[dstp >>> 1] = dstd; - if (totald != 0) b.blitzero = 0; - } - - function blitdofast_fa(pta, ptb, ptc, ptd, b) { - var i,j; - var totald = 0; - var preva = 0; - var srcc = b.bltcdat; - var dstd = 0; - var dstp = 0; - for (j = 0; j < b.vblitsize; j++) { - for (i = 0; i < b.hblitsize; i++) { - var bltadat, srca; - - if (ptc) { srcc = AMIGA.mem.chip.data[ptc >>> 1]; ptc += 2; } - if (pta) { bltadat = blt_info.bltadat = AMIGA.mem.chip.data[pta >>> 1]; pta += 2; } else { bltadat = blt_info.bltadat; } - bltadat &= blit_masktable[i]; - srca = ((((preva << 16) | bltadat) >>> 0) >>> b.blitashift) & 0xffff; - preva = bltadat; - if (dstp) AMIGA.mem.chip.data[dstp >>> 1] = dstd; - dstd = ((srca | srcc)) & 0xffff; - totald |= dstd; - if (ptd) { dstp = ptd; ptd += 2; } - } - if (pta) pta += b.bltamod; - if (ptc) ptc += b.bltcmod; - if (ptd) ptd += b.bltdmod; - } - b.bltcdat = srcc; - if (dstp) AMIGA.mem.chip.data[dstp >>> 1] = dstd; - if (totald != 0) b.blitzero = 0; - } - - function blitdofast_desc_fa(pta, ptb, ptc, ptd, b) { - var totald = 0; - var i,j; - var preva = 0; - var srcc = b.bltcdat; - var dstd = 0; - var dstp = 0; - for (j = 0; j < b.vblitsize; j++) { - for (i = 0; i < b.hblitsize; i++) { - var bltadat, srca; - if (ptc) { srcc = AMIGA.mem.chip.data[ptc >>> 1]; ptc -= 2; } - if (pta) { bltadat = blt_info.bltadat = AMIGA.mem.chip.data[pta >>> 1]; pta -= 2; } else { bltadat = blt_info.bltadat; } - bltadat &= blit_masktable[i]; - srca = ((((bltadat << 16) | preva) >>> 0) >>> b.blitdownashift) & 0xffff; - preva = bltadat; - if (dstp) AMIGA.mem.chip.data[dstp >>> 1] = dstd; - dstd = ((srca | srcc)) & 0xffff; - totald |= dstd; - if (ptd) { dstp = ptd; ptd -= 2; } - } - if (pta) pta -= b.bltamod; - if (ptc) ptc -= b.bltcmod; - if (ptd) ptd -= b.bltdmod; - } - b.bltcdat = srcc; - if (dstp) AMIGA.mem.chip.data[dstp >>> 1] = dstd; - if (totald != 0) b.blitzero = 0; - } - - function blitdofast_fc(pta, ptb, ptc, ptd, b) { - var i,j; - var totald = 0; - var preva = 0; - var prevb = 0, srcb = b.bltbhold; - var dstd = 0; - var dstp = 0; - for (j = 0; j < b.vblitsize; j++) { - for (i = 0; i < b.hblitsize; i++) { - var bltadat, srca; - - if (ptb) { - var bltbdat = blt_info.bltbdat = AMIGA.mem.chip.data[ptb >>> 1]; ptb += 2; - srcb = ((((prevb << 16) | bltbdat) >>> 0) >>> b.blitbshift) & 0xffff; - prevb = bltbdat; - } - if (pta) { bltadat = blt_info.bltadat = AMIGA.mem.chip.data[pta >>> 1]; pta += 2; } else { bltadat = blt_info.bltadat; } - bltadat &= blit_masktable[i]; - srca = ((((preva << 16) | bltadat) >>> 0) >>> b.blitashift) & 0xffff; - preva = bltadat; - if (dstp) AMIGA.mem.chip.data[dstp >>> 1] = dstd; - dstd = ((srca | srcb)) & 0xffff; - totald |= dstd; - if (ptd) { dstp = ptd; ptd += 2; } - } - if (pta) pta += b.bltamod; - if (ptb) ptb += b.bltbmod; - if (ptd) ptd += b.bltdmod; - } - b.bltbhold = srcb; - if (dstp) AMIGA.mem.chip.data[dstp >>> 1] = dstd; - if (totald != 0) b.blitzero = 0; - } - - function blitdofast_desc_fc(pta, ptb, ptc, ptd, b) { - var totald = 0; - var i,j; - var preva = 0; - var prevb = 0, srcb = b.bltbhold; - var dstd = 0; - var dstp = 0; - for (j = 0; j < b.vblitsize; j++) { - for (i = 0; i < b.hblitsize; i++) { - var bltadat, srca; - if (ptb) { - var bltbdat = blt_info.bltbdat = AMIGA.mem.chip.data[ptb >>> 1]; ptb -= 2; - srcb = ((((bltbdat << 16) | prevb) >>> 0) >>> b.blitdownbshift) & 0xffff; - prevb = bltbdat; - } - if (pta) { bltadat = blt_info.bltadat = AMIGA.mem.chip.data[pta >>> 1]; pta -= 2; } else { bltadat = blt_info.bltadat; } - bltadat &= blit_masktable[i]; - srca = ((((bltadat << 16) | preva) >>> 0) >>> b.blitdownashift) & 0xffff; - preva = bltadat; - if (dstp) AMIGA.mem.chip.data[dstp >>> 1] = dstd; - dstd = ((srca | srcb)) & 0xffff; - totald |= dstd; - if (ptd) { dstp = ptd; ptd -= 2; } - } - if (pta) pta -= b.bltamod; - if (ptb) ptb -= b.bltbmod; - if (ptd) ptd -= b.bltdmod; - } - b.bltbhold = srcb; - if (dstp) AMIGA.mem.chip.data[dstp >>> 1] = dstd; - if (totald != 0) b.blitzero = 0; - } - - const blitfunc_dofast = [ - blitdofast_0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, blitdofast_a, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, blitdofast_2a, 0, 0, 0, 0, 0, - blitdofast_30, 0, 0, 0, 0, 0, 0, 0, - 0, 0, blitdofast_3a, 0, blitdofast_3c, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, blitdofast_4a, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, blitdofast_6a, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, blitdofast_8a, 0, blitdofast_8c, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, blitdofast_9a, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - blitdofast_a8, 0, blitdofast_aa, 0, 0, 0, 0, 0, - 0, blitdofast_b1, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, blitdofast_ca, 0, blitdofast_cc, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - blitdofast_d8, 0, 0, 0, 0, 0, 0, 0, - 0, 0, blitdofast_e2, 0, 0, 0, 0, 0, - 0, 0, blitdofast_ea, 0, 0, 0, 0, 0, - blitdofast_f0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, blitdofast_fa, 0, blitdofast_fc, 0, 0, 0 - ]; - - const blitfunc_dofast_desc = [ - blitdofast_desc_0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, blitdofast_desc_a, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, blitdofast_desc_2a, 0, 0, 0, 0, 0, - blitdofast_desc_30, 0, 0, 0, 0, 0, 0, 0, - 0, 0, blitdofast_desc_3a, 0, blitdofast_desc_3c, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, blitdofast_desc_4a, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, blitdofast_desc_6a, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, blitdofast_desc_8a, 0, blitdofast_desc_8c, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, blitdofast_desc_9a, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - blitdofast_desc_a8, 0, blitdofast_desc_aa, 0, 0, 0, 0, 0, - 0, blitdofast_desc_b1, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, blitdofast_desc_ca, 0, blitdofast_desc_cc, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - blitdofast_desc_d8, 0, 0, 0, 0, 0, 0, 0, - 0, 0, blitdofast_desc_e2, 0, 0, 0, 0, 0, - 0, 0, blitdofast_desc_ea, 0, 0, 0, 0, 0, - blitdofast_desc_f0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, blitdofast_desc_fa, 0, blitdofast_desc_fc, 0, 0, 0 - ]; - - function blit_func(a, b, c, mt) { - switch (mt) { - case 0x00: return 0; - case 0x01: return (~c & ~b & ~a); - case 0x02: return (c & ~b & ~a); - case 0x03: return (~b & ~a); - case 0x04: return (~c & b & ~a); - case 0x05: return (~c & ~a); - case 0x06: return (c & ~b & ~a) | (~c & b & ~a); - case 0x07: return (~b & ~a) | (~c & ~a); - case 0x08: return (c & b & ~a); - case 0x09: return (~c & ~b & ~a) | (c & b & ~a); - case 0x0a: return (c & ~a); - case 0x0b: return (~b & ~a) | (c & ~a); - case 0x0c: return (b & ~a); - case 0x0d: return (~c & ~a) | (b & ~a); - case 0x0e: return (c & ~a) | (b & ~a); - case 0x0f: return (~a); - case 0x10: return (~c & ~b & a); - case 0x11: return (~c & ~b); - case 0x12: return (c & ~b & ~a) | (~c & ~b & a); - case 0x13: return (~b & ~a) | (~c & ~b); - case 0x14: return (~c & b & ~a) | (~c & ~b & a); - case 0x15: return (~c & ~a) | (~c & ~b); - case 0x16: return (c & ~b & ~a) | (~c & b & ~a) | (~c & ~b & a); - case 0x17: return (~b & ~a) | (~c & ~a) | (~c & ~b); - case 0x18: return (c & b & ~a) | (~c & ~b & a); - case 0x19: return (~c & ~b) | (c & b & ~a); - case 0x1a: return (c & ~a) | (~c & ~b & a); - case 0x1b: return (~b & ~a) | (c & ~a) | (~c & ~b); - case 0x1c: return (b & ~a) | (~c & ~b & a); - case 0x1d: return (~c & ~a) | (b & ~a) | (~c & ~b); - case 0x1e: return (c & ~a) | (b & ~a) | (~c & ~b & a); - case 0x1f: return (~a) | (~c & ~b); - case 0x20: return (c & ~b & a); - case 0x21: return (~c & ~b & ~a) | (c & ~b & a); - case 0x22: return (c & ~b); - case 0x23: return (~b & ~a) | (c & ~b); - case 0x24: return (~c & b & ~a) | (c & ~b & a); - case 0x25: return (~c & ~a) | (c & ~b & a); - case 0x26: return (c & ~b) | (~c & b & ~a); - case 0x27: return (~b & ~a) | (~c & ~a) | (c & ~b); - case 0x28: return (c & b & ~a) | (c & ~b & a); - case 0x29: return (~c & ~b & ~a) | (c & b & ~a) | (c & ~b & a); - case 0x2a: return (c & ~a) | (c & ~b); - case 0x2b: return (~b & ~a) | (c & ~a) | (c & ~b); - case 0x2c: return (b & ~a) | (c & ~b & a); - case 0x2d: return (~c & ~a) | (b & ~a) | (c & ~b & a); - case 0x2e: return (c & ~a) | (b & ~a) | (c & ~b); - case 0x2f: return (~a) | (c & ~b); - case 0x30: return (~b & a); - case 0x31: return (~c & ~b) | (~b & a); - case 0x32: return (c & ~b) | (~b & a); - case 0x33: return (~b); - case 0x34: return (~c & b & ~a) | (~b & a); - case 0x35: return (~c & ~a) | (~b & a); - case 0x36: return (c & ~b) | (~c & b & ~a) | (~b & a); - case 0x37: return (~b) | (~c & ~a); - case 0x38: return (c & b & ~a) | (~b & a); - case 0x39: return (~c & ~b) | (c & b & ~a) | (~b & a); - case 0x3a: return (c & ~a) | (~b & a); - case 0x3b: return (~b) | (c & ~a); - case 0x3c: return (b & ~a) | (~b & a); - case 0x3d: return (~c & ~a) | (b & ~a) | (~b & a); - case 0x3e: return (c & ~a) | (b & ~a) | (~b & a); - case 0x3f: return (~a) | (~b); - case 0x40: return (~c & b & a); - case 0x41: return (~c & ~b & ~a) | (~c & b & a); - case 0x42: return (c & ~b & ~a) | (~c & b & a); - case 0x43: return (~b & ~a) | (~c & b & a); - case 0x44: return (~c & b); - case 0x45: return (~c & ~a) | (~c & b); - case 0x46: return (c & ~b & ~a) | (~c & b); - case 0x47: return (~b & ~a) | (~c & ~a) | (~c & b); - case 0x48: return (c & b & ~a) | (~c & b & a); - case 0x49: return (~c & ~b & ~a) | (c & b & ~a) | (~c & b & a); - case 0x4a: return (c & ~a) | (~c & b & a); - case 0x4b: return (~b & ~a) | (c & ~a) | (~c & b & a); - case 0x4c: return (b & ~a) | (~c & b); - case 0x4d: return (~c & ~a) | (b & ~a) | (~c & b); - case 0x4e: return (c & ~a) | (b & ~a) | (~c & b); - case 0x4f: return (~a) | (~c & b); - case 0x50: return (~c & a); - case 0x51: return (~c & ~b) | (~c & a); - case 0x52: return (c & ~b & ~a) | (~c & a); - case 0x53: return (~b & ~a) | (~c & a); - case 0x54: return (~c & b) | (~c & a); - case 0x55: return (~c); - case 0x56: return (c & ~b & ~a) | (~c & b) | (~c & a); - case 0x57: return (~b & ~a) | (~c); - case 0x58: return (c & b & ~a) | (~c & a); - case 0x59: return (~c & ~b) | (c & b & ~a) | (~c & a); - case 0x5a: return (c & ~a) | (~c & a); - case 0x5b: return (~b & ~a) | (c & ~a) | (~c & a); - case 0x5c: return (b & ~a) | (~c & a); - case 0x5d: return (~c) | (b & ~a); - case 0x5e: return (c & ~a) | (b & ~a) | (~c & a); - case 0x5f: return (~a) | (~c); - case 0x60: return (c & ~b & a) | (~c & b & a); - case 0x61: return (~c & ~b & ~a) | (c & ~b & a) | (~c & b & a); - case 0x62: return (c & ~b) | (~c & b & a); - case 0x63: return (~b & ~a) | (c & ~b) | (~c & b & a); - case 0x64: return (~c & b) | (c & ~b & a); - case 0x65: return (~c & ~a) | (c & ~b & a) | (~c & b); - case 0x66: return (c & ~b) | (~c & b); - case 0x67: return (~b & ~a) | (~c & ~a) | (c & ~b) | (~c & b); - case 0x68: return (c & b & ~a) | (c & ~b & a) | (~c & b & a); - case 0x69: return (~c & ~b & ~a) | (c & b & ~a) | (c & ~b & a) | (~c & b & a); - case 0x6a: return (c & ~a) | (c & ~b) | (~c & b & a); - case 0x6b: return (~b & ~a) | (c & ~a) | (c & ~b) | (~c & b & a); - case 0x6c: return (b & ~a) | (c & ~b & a) | (~c & b); - case 0x6d: return (~c & ~a) | (b & ~a) | (c & ~b & a) | (~c & b); - case 0x6e: return (c & ~a) | (b & ~a) | (c & ~b) | (~c & b); - case 0x6f: return (~a) | (c & ~b) | (~c & b); - case 0x70: return (~b & a) | (~c & a); - case 0x71: return (~c & ~b) | (~b & a) | (~c & a); - case 0x72: return (c & ~b) | (~b & a) | (~c & a); - case 0x73: return (~b) | (~c & a); - case 0x74: return (~c & b) | (~b & a); - case 0x75: return (~c) | (~b & a); - case 0x76: return (c & ~b) | (~c & b) | (~b & a); - case 0x77: return (~b) | (~c); - case 0x78: return (c & b & ~a) | (~b & a) | (~c & a); - case 0x79: return (~c & ~b) | (c & b & ~a) | (~b & a) | (~c & a); - case 0x7a: return (c & ~a) | (~b & a) | (~c & a); - case 0x7b: return (~b) | (c & ~a) | (~c & a); - case 0x7c: return (b & ~a) | (~b & a) | (~c & a); - case 0x7d: return (~c) | (b & ~a) | (~b & a); - case 0x7e: return (c & ~a) | (b & ~a) | (~b & a) | (~c & a); - case 0x7f: return (~a) | (~b) | (~c); - case 0x80: return (c & b & a); - case 0x81: return (~c & ~b & ~a) | (c & b & a); - case 0x82: return (c & ~b & ~a) | (c & b & a); - case 0x83: return (~b & ~a) | (c & b & a); - case 0x84: return (~c & b & ~a) | (c & b & a); - case 0x85: return (~c & ~a) | (c & b & a); - case 0x86: return (c & ~b & ~a) | (~c & b & ~a) | (c & b & a); - case 0x87: return (~b & ~a) | (~c & ~a) | (c & b & a); - case 0x88: return (c & b); - case 0x89: return (~c & ~b & ~a) | (c & b); - case 0x8a: return (c & ~a) | (c & b); - case 0x8b: return (~b & ~a) | (c & ~a) | (c & b); - case 0x8c: return (b & ~a) | (c & b); - case 0x8d: return (~c & ~a) | (b & ~a) | (c & b); - case 0x8e: return (c & ~a) | (b & ~a) | (c & b); - case 0x8f: return (~a) | (c & b); - case 0x90: return (~c & ~b & a) | (c & b & a); - case 0x91: return (~c & ~b) | (c & b & a); - case 0x92: return (c & ~b & ~a) | (~c & ~b & a) | (c & b & a); - case 0x93: return (~b & ~a) | (~c & ~b) | (c & b & a); - case 0x94: return (~c & b & ~a) | (~c & ~b & a) | (c & b & a); - case 0x95: return (~c & ~a) | (~c & ~b) | (c & b & a); - case 0x96: return (c & ~b & ~a) | (~c & b & ~a) | (~c & ~b & a) | (c & b & a); - case 0x97: return (~b & ~a) | (~c & ~a) | (~c & ~b) | (c & b & a); - case 0x98: return (c & b) | (~c & ~b & a); - case 0x99: return (~c & ~b) | (c & b); - case 0x9a: return (c & ~a) | (~c & ~b & a) | (c & b); - case 0x9b: return (~b & ~a) | (c & ~a) | (~c & ~b) | (c & b); - case 0x9c: return (b & ~a) | (~c & ~b & a) | (c & b); - case 0x9d: return (~c & ~a) | (b & ~a) | (~c & ~b) | (c & b); - case 0x9e: return (c & ~a) | (b & ~a) | (~c & ~b & a) | (c & b); - case 0x9f: return (~a) | (~c & ~b) | (c & b); - case 0xa0: return (c & a); - case 0xa1: return (~c & ~b & ~a) | (c & a); - case 0xa2: return (c & ~b) | (c & a); - case 0xa3: return (~b & ~a) | (c & a); - case 0xa4: return (~c & b & ~a) | (c & a); - case 0xa5: return (~c & ~a) | (c & a); - case 0xa6: return (c & ~b) | (~c & b & ~a) | (c & a); - case 0xa7: return (~b & ~a) | (~c & ~a) | (c & a); - case 0xa8: return (c & b) | (c & a); - case 0xa9: return (~c & ~b & ~a) | (c & b) | (c & a); - case 0xaa: return (c); - case 0xab: return (~b & ~a) | (c); - case 0xac: return (b & ~a) | (c & a); - case 0xad: return (~c & ~a) | (b & ~a) | (c & a); - case 0xae: return (c) | (b & ~a); - case 0xaf: return (~a) | (c); - case 0xb0: return (~b & a) | (c & a); - case 0xb1: return (~c & ~b) | (~b & a) | (c & a); - case 0xb2: return (c & ~b) | (~b & a) | (c & a); - case 0xb3: return (~b) | (c & a); - case 0xb4: return (~c & b & ~a) | (~b & a) | (c & a); - case 0xb5: return (~c & ~a) | (~b & a) | (c & a); - case 0xb6: return (c & ~b) | (~c & b & ~a) | (~b & a) | (c & a); - case 0xb7: return (~b) | (~c & ~a) | (c & a); - case 0xb8: return (c & b) | (~b & a); - case 0xb9: return (~c & ~b) | (c & b) | (~b & a); - case 0xba: return (c) | (~b & a); - case 0xbb: return (~b) | (c); - case 0xbc: return (b & ~a) | (~b & a) | (c & a); - case 0xbd: return (~c & ~a) | (b & ~a) | (~b & a) | (c & a); - case 0xbe: return (c) | (b & ~a) | (~b & a); - case 0xbf: return (~a) | (~b) | (c); - case 0xc0: return (b & a); - case 0xc1: return (~c & ~b & ~a) | (b & a); - case 0xc2: return (c & ~b & ~a) | (b & a); - case 0xc3: return (~b & ~a) | (b & a); - case 0xc4: return (~c & b) | (b & a); - case 0xc5: return (~c & ~a) | (b & a); - case 0xc6: return (c & ~b & ~a) | (~c & b) | (b & a); - case 0xc7: return (~b & ~a) | (~c & ~a) | (b & a); - case 0xc8: return (c & b) | (b & a); - case 0xc9: return (~c & ~b & ~a) | (c & b) | (b & a); - case 0xca: return (c & ~a) | (b & a); - case 0xcb: return (~b & ~a) | (c & ~a) | (b & a); - case 0xcc: return (b); - case 0xcd: return (~c & ~a) | (b); - case 0xce: return (c & ~a) | (b); - case 0xcf: return (~a) | (b); - case 0xd0: return (~c & a) | (b & a); - case 0xd1: return (~c & ~b) | (b & a); - case 0xd2: return (c & ~b & ~a) | (~c & a) | (b & a); - case 0xd3: return (~b & ~a) | (~c & a) | (b & a); - case 0xd4: return (~c & b) | (~c & a) | (b & a); - case 0xd5: return (~c) | (b & a); - case 0xd6: return (c & ~b & ~a) | (~c & b) | (~c & a) | (b & a); - case 0xd7: return (~b & ~a) | (~c) | (b & a); - case 0xd8: return (c & b) | (~c & a); - case 0xd9: return (~c & ~b) | (c & b) | (b & a); - case 0xda: return (c & ~a) | (~c & a) | (b & a); - case 0xdb: return (~b & ~a) | (c & ~a) | (~c & a) | (b & a); - case 0xdc: return (b) | (~c & a); - case 0xdd: return (~c) | (b); - case 0xde: return (c & ~a) | (b) | (~c & a); - case 0xdf: return (~a) | (~c) | (b); - case 0xe0: return (c & a) | (b & a); - case 0xe1: return (~c & ~b & ~a) | (c & a) | (b & a); - case 0xe2: return (c & ~b) | (b & a); - case 0xe3: return (~b & ~a) | (c & a) | (b & a); - case 0xe4: return (~c & b) | (c & a); - case 0xe5: return (~c & ~a) | (c & a) | (b & a); - case 0xe6: return (c & ~b) | (~c & b) | (b & a); - case 0xe7: return (~b & ~a) | (~c & ~a) | (c & a) | (b & a); - case 0xe8: return (c & b) | (c & a) | (b & a); - case 0xe9: return (~c & ~b & ~a) | (c & b) | (c & a) | (b & a); - case 0xea: return (c) | (b & a); - case 0xeb: return (~b & ~a) | (c) | (b & a); - case 0xec: return (b) | (c & a); - case 0xed: return (~c & ~a) | (b) | (c & a); - case 0xee: return (c) | (b); - case 0xef: return (~a) | (c) | (b); - case 0xf0: return (a); - case 0xf1: return (~c & ~b) | (a); - case 0xf2: return (c & ~b) | (a); - case 0xf3: return (~b) | (a); - case 0xf4: return (~c & b) | (a); - case 0xf5: return (~c) | (a); - case 0xf6: return (c & ~b) | (~c & b) | (a); - case 0xf7: return (~b) | (~c) | (a); - case 0xf8: return (c & b) | (a); - case 0xf9: return (~c & ~b) | (c & b) | (a); - case 0xfa: return (c) | (a); - case 0xfb: return (~b) | (c) | (a); - case 0xfc: return (b) | (a); - case 0xfd: return (~c) | (b) | (a); - case 0xfe: return (c) | (b) | (a); - case 0xff: return 0xffff; - default: return 0; - } - } - function blitter_dofast() { - //console.log('blitter_dofast'); - var i,j; + var i, j; var bltadatptr = 0, bltbdatptr = 0, bltcdatptr = 0, bltddatptr = 0; - var mt = bltcon0 & 0xFF; + var mt = bltcon0 & 0xff; blit_masktable[0] = blt_info.bltafwm; blit_masktable[blt_info.hblitsize - 1] &= blt_info.bltalwm; @@ -2040,9 +366,9 @@ function Blitter() { bltdpt += (blt_info.hblitsize * 2 + blt_info.bltdmod) * blt_info.vblitsize; } - if (FAST && blitfunc_dofast[mt] !== 0 && !blitfill) + if (blitfunc_dofast[mt] !== 0 && !blitfill) { blitfunc_dofast[mt](bltadatptr, bltbdatptr, bltcdatptr, bltddatptr, blt_info); - else { + } else { var blitbhold = blt_info.bltbhold; var preva = 0, prevb = 0; var dstp = 0; @@ -2054,8 +380,8 @@ function Blitter() { var bltadat, blitahold; var bltbdat; if (bltadatptr) { - //blt_info.bltadat = bltadat = AMIGA.mem.load16_chip(bltadatptr); - blt_info.bltadat = bltadat = AMIGA.mem.chip.data[bltadatptr >>> 1]; + //blt_info.bltadat = bltadat = SAER_Memory_chipGet16_indirect(bltadatptr); + blt_info.bltadat = bltadat = (SAER_Memory_chipData[bltadatptr] << 8) | SAER_Memory_chipData[bltadatptr + 1]; bltadatptr += 2; } else bltadat = blt_info.bltadat; @@ -2064,23 +390,25 @@ function Blitter() { preva = bltadat; if (bltbdatptr) { - //blt_info.bltbdat = bltbdat = AMIGA.mem.load16_chip(bltbdatptr); - blt_info.bltbdat = bltbdat = AMIGA.mem.chip.data[bltbdatptr >>> 1]; + //blt_info.bltbdat = bltbdat = SAER_Memory_chipGet16_indirect(bltbdatptr); + blt_info.bltbdat = bltbdat = (SAER_Memory_chipData[bltbdatptr] << 8) | SAER_Memory_chipData[bltbdatptr + 1]; bltbdatptr += 2; blitbhold = (((prevb << 16) | bltbdat) >>> 0) >>> blt_info.blitbshift; prevb = bltbdat; } if (bltcdatptr) { - //blt_info.bltcdat = AMIGA.mem.load16_chip(bltcdatptr); - blt_info.bltcdat = AMIGA.mem.chip.data[bltcdatptr >>> 1]; + //blt_info.bltcdat = SAER_Memory_chipGet16_indirect(bltcdatptr); + blt_info.bltcdat = (SAER_Memory_chipData[bltcdatptr] << 8) | SAER_Memory_chipData[bltcdatptr + 1]; bltcdatptr += 2; } - if (dodst) - //AMIGA.mem.store16_chip(dstp, blt_info.bltddat); - AMIGA.mem.chip.data[dstp >>> 1] = blt_info.bltddat; - - blt_info.bltddat = (blit_func(blitahold & 0xffff, blitbhold & 0xffff, blt_info.bltcdat & 0xffff, mt) >>> 0) & 0xffff; + //if (dodst) chipmem_agnus_wput2(dstp, blt_info.bltddat); + //if (dodst) SAER_Memory_chipPut16_indirect(dstp, blt_info.bltddat); + if (dodst) { + SAER_Memory_chipData[dstp] = blt_info.bltddat >> 8; + SAER_Memory_chipData[dstp+1] = blt_info.bltddat & 0xff; + } + blt_info.bltddat = blit_func_tab[mt](blitahold, blitbhold, blt_info.bltcdat) & 0xffff; if (blitfill) { var d = blt_info.bltddat; var ifemode = blitife ? 2 : 0; @@ -2101,23 +429,24 @@ function Blitter() { if (bltcdatptr) bltcdatptr += blt_info.bltcmod; if (bltddatptr) bltddatptr += blt_info.bltdmod; } - if (dodst) - //AMIGA.mem.store16_chip(dstp, blt_info.bltddat); - AMIGA.mem.chip.data[dstp >>> 1] = blt_info.bltddat; - + //if (dodst) chipmem_agnus_wput2(dstp, blt_info.bltddat); + //if (dodst) SAER_Memory_chipPut16_indirect(dstp, blt_info.bltddat); + if (dodst) { + SAER_Memory_chipData[dstp] = blt_info.bltddat >> 8; + SAER_Memory_chipData[dstp+1] = blt_info.bltddat & 0xff; + } blt_info.bltbhold = blitbhold; } blit_masktable[0] = 0xffff; blit_masktable[blt_info.hblitsize - 1] = 0xffff; - bltstate = BLT_done; + SAEV_Blitter_bltstate = SAEC_Blitter_bltstate_DONE; } function blitter_dofast_desc() { - //console.log('blitter_dofast_desc'); - var i,j; + var i, j; var bltadatptr = 0, bltbdatptr = 0, bltcdatptr = 0, bltddatptr = 0; - var mt = bltcon0 & 0xFF; + var mt = bltcon0 & 0xff; blit_masktable[0] = blt_info.bltafwm; blit_masktable[blt_info.hblitsize - 1] &= blt_info.bltalwm; @@ -2138,10 +467,9 @@ function Blitter() { bltddatptr = bltdpt; bltdpt -= (blt_info.hblitsize * 2 + blt_info.bltdmod) * blt_info.vblitsize; } - - if (FAST && blitfunc_dofast_desc[mt] !== 0 && !blitfill) + if (blitfunc_dofast_desc[mt] !== 0 && !blitfill) { blitfunc_dofast_desc[mt](bltadatptr, bltbdatptr, bltcdatptr, bltddatptr, blt_info); - else { + } else { var blitbhold = blt_info.bltbhold; var preva = 0, prevb = 0; var dstp = 0; @@ -2153,33 +481,35 @@ function Blitter() { var bltadat, blitahold; var bltbdat; if (bltadatptr) { - //blt_info.bltadat = bltadat = AMIGA.mem.load16_chip(bltadatptr); - blt_info.bltadat = bltadat = AMIGA.mem.chip.data[bltadatptr >>> 1]; + //blt_info.bltadat = bltadat = SAER_Memory_chipGet16_indirect(bltadatptr); + blt_info.bltadat = bltadat = (SAER_Memory_chipData[bltadatptr] << 8) | SAER_Memory_chipData[bltadatptr + 1]; bltadatptr -= 2; } else bltadat = blt_info.bltadat; bltadat &= blit_masktable[i]; - blitahold = (((bltadat << 16) | preva) >>> 0) >> blt_info.blitdownashift; + blitahold = (((bltadat << 16) | preva) >>> 0) >>> blt_info.blitdownashift; preva = bltadat; if (bltbdatptr) { - //blt_info.bltbdat = bltbdat = AMIGA.mem.load16_chip(bltbdatptr); - blt_info.bltbdat = bltbdat = AMIGA.mem.chip.data[bltbdatptr >>> 1]; + //blt_info.bltbdat = bltbdat = SAER_Memory_chipGet16_indirect(bltbdatptr); + blt_info.bltbdat = bltbdat = (SAER_Memory_chipData[bltbdatptr] << 8) | SAER_Memory_chipData[bltbdatptr + 1]; bltbdatptr -= 2; - blitbhold = (((bltbdat << 16) | prevb) >>> 0) >> blt_info.blitdownbshift; + blitbhold = (((bltbdat << 16) | prevb) >>> 0) >>> blt_info.blitdownbshift; prevb = bltbdat; } if (bltcdatptr) { - //blt_info.bltcdat = blt_info.bltbdat = AMIGA.mem.load16_chip(bltcdatptr); - blt_info.bltcdat = blt_info.bltbdat = AMIGA.mem.chip.data[bltcdatptr >>> 1]; + //blt_info.bltcdat = blt_info.bltbdat = SAER_Memory_chipGet16_indirect(bltcdatptr); + blt_info.bltcdat = (SAER_Memory_chipData[bltcdatptr] << 8) | SAER_Memory_chipData[bltcdatptr + 1]; bltcdatptr -= 2; } - if (dodst) - //AMIGA.mem.store16_chip(dstp, blt_info.bltddat); - AMIGA.mem.chip.data[dstp >>> 1] = blt_info.bltddat; - - blt_info.bltddat = (blit_func(blitahold & 0xffff, blitbhold & 0xffff, blt_info.bltcdat & 0xffff, mt) >>> 0) & 0xffff; + //if (dodst) chipmem_agnus_wput2(dstp, blt_info.bltddat); + //if (dodst) SAER_Memory_chipPut16_indirect(dstp, blt_info.bltddat); + if (dodst) { + SAER_Memory_chipData[dstp] = blt_info.bltddat >> 8; + SAER_Memory_chipData[dstp+1] = blt_info.bltddat & 0xff; + } + blt_info.bltddat = blit_func_tab[mt](blitahold, blitbhold, blt_info.bltcdat) & 0xffff; if (blitfill) { var d = blt_info.bltddat; var ifemode = blitife ? 2 : 0; @@ -2200,50 +530,57 @@ function Blitter() { if (bltcdatptr) bltcdatptr -= blt_info.bltcmod; if (bltddatptr) bltddatptr -= blt_info.bltdmod; } - if (dodst) - //AMIGA.mem.store16_chip(dstp, blt_info.bltddat); - AMIGA.mem.chip.data[dstp >>> 1] = blt_info.bltddat; - + //if (dodst) chipmem_agnus_wput2(dstp, blt_info.bltddat); + //if (dodst) SAER_Memory_chipPut16_indirect(dstp, blt_info.bltddat); + if (dodst) { + SAER_Memory_chipData[dstp] = blt_info.bltddat >> 8; + SAER_Memory_chipData[dstp+1] = blt_info.bltddat & 0xff; + } blt_info.bltbhold = blitbhold; } blit_masktable[0] = 0xffff; blit_masktable[blt_info.hblitsize - 1] = 0xffff; - bltstate = BLT_done; + SAEV_Blitter_bltstate = SAEC_Blitter_bltstate_DONE; } function blitter_read() { if (bltcon0 & 0x200) { - if (AMIGA.dmaen(DMAF_BLTEN)) - //blt_info.bltcdat = AMIGA.mem.load16_chip(bltcpt); - blt_info.bltcdat = AMIGA.mem.chip.data[bltcpt >>> 1]; + if (!SAEF_Custom_dmaen(SAEC_Custom_DMAF_BLTEN)) + return; + //blt_info.bltcdat = SAER_Memory_chipGet16_indirect(bltcpt); + blt_info.bltcdat = (SAER_Memory_chipData[bltcpt] << 8) | SAER_Memory_chipData[bltcpt + 1]; + SAEV_Custom_last_value = blt_info.bltcdat; } - bltstate = BLT_work; + SAEV_Blitter_bltstate = SAEC_Blitter_bltstate_WORK; } function blitter_write() { if (blt_info.bltddat) blt_info.blitzero = 0; - + /* D-channel state has no effect on linedraw, but C must be enabled or nothing is drawn! */ if (bltcon0 & 0x200) { - if (AMIGA.dmaen(DMAF_BLTEN)) - //AMIGA.mem.store16_chip(bltdpt, blt_info.bltddat); - AMIGA.mem.chip.data[bltdpt >>> 1] = blt_info.bltddat; + if (!SAEF_Custom_dmaen(SAEC_Custom_DMAF_BLTEN)) + return; + //SAEV_Custom_last_value = blt_info.bltddat; blitter writes are not stored + //SAER_Memory_chipPut16_indirect(bltdpt, blt_info.bltddat); + SAER_Memory_chipData[bltdpt] = blt_info.bltddat >> 8; + SAER_Memory_chipData[bltdpt+1] = blt_info.bltddat & 0xff; } - bltstate = BLT_next; + SAEV_Blitter_bltstate = SAEC_Blitter_bltstate_NEXT; } function blitter_line() { - var blitahold = (blinea & blt_info.bltafwm) >>> blinea_shift; + var blitahold = (blinea & blt_info.bltafwm) >> blinea_shift; var blitchold = blt_info.bltcdat; blt_info.bltbhold = (blineb & 1) ? 0xffff : 0; blitlinepixel = !blitsing || (blitsing && !blitonedot); - blt_info.bltddat = blit_func(blitahold, blt_info.bltbhold, blitchold, bltcon0 & 0xff); + blt_info.bltddat = blit_func_tab[bltcon0 & 0xff](blitahold, blt_info.bltbhold, blitchold) & 0xffff; blitonedot++; } - /*function blitter_line_incx() { + /*function blitter_line_incx() { if (++blinea_shift == 16) { blinea_shift = 0; bltcpt += 2; @@ -2262,69 +599,42 @@ function Blitter() { function blitter_line_incy() { bltcpt += blt_info.bltcmod; blitonedot = 0; - } - function blitter_line_proc() { - if (bltcon0 & 0x800) { - if (blitsign) - bltapt_line += blt_info.bltbmod; - else - bltapt_line += blt_info.bltamod; - } - if (!blitsign) { - if (bltcon1 & 0x10) { - if (bltcon1 & 0x8) { - blitter_line_decy(); - } else { - blitter_line_incy(); - } - } else { - if (bltcon1 & 0x8) { - blitter_line_decx(); - } else { - blitter_line_incx(); - } - } - } - if (bltcon1 & 0x10) { - if (bltcon1 & 0x4) { - blitter_line_decx(); - } else { - blitter_line_incx(); - } - } else { - if (bltcon1 & 0x4) { - blitter_line_decy(); - } else { - blitter_line_incy(); - } - } - blitsign = 0 > bltapt_line; - bltstate = BLT_write; }*/ - - function blitter_line_proc_fast() { + function blitter_line_proc() { + /* ORG if (bltcon0 & 0x800) { if (blitsign) - bltapt_line += blt_info.bltbmod; + bltapt += (uae_s16)blt_info.bltbmod; else - bltapt_line += blt_info.bltamod; + bltapt += (uae_s16)blt_info.bltamod; + }*/ + if (bltcon0 & 0x800) { + if (blitsign) + bltapt += blt_info.bltbmod; + else + bltapt += blt_info.bltamod; } + if (!blitsign) { if (bltcon1 & 0x10) { if (bltcon1 & 0x8) { + //blitter_line_decy(); bltcpt -= blt_info.bltcmod; blitonedot = 0; } else { + //blitter_line_incy(); bltcpt += blt_info.bltcmod; blitonedot = 0; } } else { if (bltcon1 & 0x8) { + //blitter_line_decx(); if (blinea_shift-- == 0) { blinea_shift = 15; bltcpt -= 2; } } else { + //blitter_line_incx(); if (++blinea_shift == 16) { blinea_shift = 0; bltcpt += 2; @@ -2334,11 +644,13 @@ function Blitter() { } if (bltcon1 & 0x10) { if (bltcon1 & 0x4) { + //blitter_line_decx(); if (blinea_shift-- == 0) { blinea_shift = 15; bltcpt -= 2; } } else { + //blitter_line_incx(); if (++blinea_shift == 16) { blinea_shift = 0; bltcpt += 2; @@ -2346,140 +658,625 @@ function Blitter() { } } else { if (bltcon1 & 0x4) { + //blitter_line_decy(); bltcpt -= blt_info.bltcmod; blitonedot = 0; } else { + //blitter_line_incy(); bltcpt += blt_info.bltcmod; blitonedot = 0; } } - blitsign = 0 > bltapt_line; - bltstate = BLT_write; + + //blitsign = 0 > (uae_s16)bltapt; //ORG + blitsign = (bltapt & 0x8000) != 0; + SAEV_Blitter_bltstate = SAEC_Blitter_bltstate_WRITE; } - function blitter_nxline() { + function blitter_nxline() { blineb = ((blineb << 1) | (blineb >> 15)) & 0xffff; blt_info.vblitsize--; - bltstate = BLT_read; + SAEV_Blitter_bltstate = SAEC_Blitter_bltstate_READ; } + //#ifdef CPUEMU_13 + function decide_blitter_line(hsync, hpos) { + var ptr = { val:0 }; + + if (blit_final && blt_info.vblitsize) + blit_final = 0; + while (last_blitter_hpos < hpos) { + var c = channel_state(blit_cyclecounter); + + for (;;) { + var v = canblit(last_blitter_hpos); + + if (blit_waitcyclecounter) { + blit_waitcyclecounter = 0; + break; + } + + // final 2 idle cycles? does not need free bus + if (blit_final) { + blit_cyclecounter++; + blit_totalcyclecounter++; + if (blit_cyclecounter >= 2) { + blitter_done(last_blitter_hpos); + return; + } + break; + } + + if (v <= 0) { + blit_misscyclecounter++; + blitter_nasty++; + break; + } + + blit_cyclecounter++; + blit_totalcyclecounter++; + + check_channel_mods(last_blitter_hpos, c); + + if (c == 3) { + blitter_read(); + ptr.val = bltcpt; + //SAER.events.alloc_cycle_blitter(last_blitter_hpos, ptr, 3); + bltcpt = ptr.val; + blitter_nasty++; + } else if (c == 5) { + if (ddat1use) { + bltdpt = bltcpt; + } + ddat1use = 1; + blitter_line(); + blitter_line_proc(); + blitter_nxline(); + } else if (c == 4) { + /* onedot mode and no pixel = bus write access is skipped */ + if (blitlinepixel) { + blitter_write(); + ptr.val = bltdpt; + //SAER.events.alloc_cycle_blitter(last_blitter_hpos, ptr, 4); + bltdpt = ptr.val; + blitlinepixel = 0; + blitter_nasty++; + } + if (blt_info.vblitsize == 0) { + bltdpt = bltcpt; + blit_final = 1; + blit_cyclecounter = 0; + blit_waitcyclecounter = 0; + // blit finished bit is set and interrupt triggered + // immediately after last D write + blitter_interrupt(last_blitter_hpos, 0); + break; + } + } + break; + } + last_blitter_hpos++; + } + if (hsync) + last_blitter_hpos = 0; + + reset_channel_mods(); + } + //#endif + function actually_do_blit() { if (blitline) { - bltapt_line = bltapt & 0xffff; if (bltapt_line & 0x8000) bltapt_line -= 0x10000; do { blitter_read(); if (ddat1use) bltdpt = bltcpt; ddat1use = 1; blitter_line(); - blitter_line_proc_fast(); + blitter_line_proc(); blitter_nxline(); if (blitlinepixel) { blitter_write(); blitlinepixel = 0; } - if (blt_info.vblitsize <= 0) - bltstate = BLT_done; - } while (bltstate != BLT_done); - //bltapt_line = null; + if (blt_info.vblitsize == 0) + SAEV_Blitter_bltstate = SAEC_Blitter_bltstate_DONE; + } while (SAEV_Blitter_bltstate != SAEC_Blitter_bltstate_DONE); bltdpt = bltcpt; } else { if (blitdesc) blitter_dofast_desc(); else - blitter_dofast(); - bltstate = BLT_done; + blitter_dofast(); + + SAEV_Blitter_bltstate = SAEC_Blitter_bltstate_DONE; } } - function blitter_do() { - actually_do_blit(); - blitter_done(AMIGA.playfield.hpos()); + function blitter_doit() { + if (blt_info.vblitsize == 0 || (blitline && blt_info.hblitsize != 2)) { + blitter_done(SAER.events.current_hpos()); + return; + } + /*if (log_blitter) { + if (!blitter_dontdo) + actually_do_blit(); + else + SAEV_Blitter_bltstate = SAEC_Blitter_bltstate_DONE; + } else*/ + actually_do_blit(); + + blitter_done(SAER.events.current_hpos()); } - /*---------------------------------*/ + this.handler = function(data) { //blitter_handler + //static int blitter_stuck; - this.handler = function (data) { - if (!AMIGA.dmaen(DMAF_BLTEN)) { - AMIGA.events.newevent(EV2_BLITTER, 10, 0); - if (++blit_stuck < 20000 || !AMIGA.config.blitter.immediate) - return; - - BUG.info('blitter_handler() force-unstuck!'); + if (!SAEF_Custom_dmaen(SAEC_Custom_DMAF_BLTEN)) { + SAER.events.event2_newevent(SAEC_Events_EV2_BLITTER, 10, 0); + blitter_stuck++; + if (blitter_stuck < 20000 || !immediate_blits) + return; /* gotta come back later. */ + //debugtest (DEBUGTEST_BLITTER, "force-unstuck!"); } - blit_stuck = 0; - if (blit_slowdown > 0 && !AMIGA.config.blitter.immediate) { - //console.log('Blitter.handler () slowdown', blit_slowdown); - AMIGA.events.newevent(EV2_BLITTER, blit_slowdown, 0); + blitter_stuck = 0; + if (blit_slowdown > 0 && !immediate_blits) { + SAER.events.event2_newevent(SAEC_Events_EV2_BLITTER, blit_slowdown, 0); blit_slowdown = -1; return; } - blitter_do(); - }; + blitter_doit(); + } + + /*-----------------------------------------------------------------------*/ + + //#ifdef CPUEMU_13 + + function blitter_doblit() { + var blitahold; + var bltadat, ddat; + + bltadat = blt_info.bltadat; + if (blitter_hcounter1 == 0) + bltadat &= blt_info.bltafwm; + if (blitter_hcounter1 == blt_info.hblitsize - 1) + bltadat &= blt_info.bltalwm; + if (blitdesc) + blitahold = (((bltadat << 16) | preva) >>> 0) >>> blt_info.blitdownashift; + else + blitahold = (((preva << 16) | bltadat) >>> 0) >>> blt_info.blitashift; + + preva = bltadat; + ddat = blit_func_tab[bltcon0 & 0xff](blitahold, blt_info.bltbhold, blt_info.bltcdat) & 0xffff; + + if ((bltcon1 & 0x18)) { + var d = ddat; + var ifemode = blitife ? 2 : 0; + var fc1 = blit_filltable[d & 255][ifemode + blitfc][1]; + ddat = (blit_filltable[d & 255][ifemode + blitfc][0] + (blit_filltable[d >> 8][ifemode + fc1][0] << 8)); + blitfc = blit_filltable[d >> 8][ifemode + fc1][1]; + } + if (ddat) blt_info.blitzero = 0; + return ddat; + } + + function blitter_doddma(hpos) { + var d, ptr = { val:0 }; + + if (blit_dmacount2 == 0) { + d = blitter_doblit(); + } else if (ddat2use) { + d = ddat2; + ddat2use = 0; + } else if (ddat1use) { + d = ddat1; + ddat1use = 0; + } else { + /*static int warn = 10; + if (warn > 0) { + warn--; + SAEF_warn("blitter.blitter_doddma() D-channel without nothing to do?"); + }*/ + return; + } + //SAEV_Custom_last_value = d; blitter writes are not stored + //chipmem_agnus_wput2(bltdpt, d); + //SAER_Memory_chipPut16_indirect(bltdpt, d); + SAER_Memory_chipData[bltdpt] = d >> 8; + SAER_Memory_chipData[bltdpt+1] = d & 0xff; + ptr.val = bltdpt; + //SAER.events.alloc_cycle_blitter(hpos, ptr, 4); + bltdpt = ptr.val; + bltdpt += blit_add; + blitter_hcounter2++; + if (blitter_hcounter2 == blt_info.hblitsize) { + blitter_hcounter2 = 0; + bltdpt += blit_modaddd; + blitter_vcounter2++; + if (blit_dmacount2 == 0) // d-only + blitter_vcounter1++; + if (blitter_vcounter2 > blitter_vcounter1) + blitter_vcounter1 = blitter_vcounter2; + } + if (blit_ch == 1) + blitter_hcounter1 = blitter_hcounter2; + } + + function blitter_dodma(ch, hpos) { + var dat, reg; + var addr; + var ptr = { val:0 }; + + switch (ch) { + case 1: + //blt_info.bltadat = dat = SAER_Memory_chipGet16_indirect(bltapt); + blt_info.bltadat = (SAER_Memory_chipData[bltapt] << 8) | SAER_Memory_chipData[bltapt + 1]; + SAEV_Custom_last_value = blt_info.bltadat; + addr = bltapt; + bltapt += blit_add; + reg = 0x74; + ptr.val = bltapt; + //SAER.events.alloc_cycle_blitter(hpos, ptr, 1); + bltapt = ptr.val; + break; + case 2: + //blt_info.bltbdat = dat = SAER_Memory_chipGet16_indirect(bltbpt); + blt_info.bltbdat = (SAER_Memory_chipData[bltbpt] << 8) | SAER_Memory_chipData[bltbpt + 1]; + SAEV_Custom_last_value = blt_info.bltbdat; + addr = bltbpt; + bltbpt += blit_add; + if (blitdesc) + blt_info.bltbhold = (((blt_info.bltbdat << 16) | prevb) >>> 0) >>> blt_info.blitdownbshift; + else + blt_info.bltbhold = (((prevb << 16) | blt_info.bltbdat) >>> 0) >>> blt_info.blitbshift; + prevb = blt_info.bltbdat; + reg = 0x72; + ptr.val = bltbpt; + //SAER.events.alloc_cycle_blitter(hpos, ptr, 2); + bltbpt = ptr.val; + break; + case 3: + //blt_info.bltcdat = dat = SAER_Memory_chipGet16_indirect(bltcpt); + blt_info.bltcdat = (SAER_Memory_chipData[bltcpt] << 8) | SAER_Memory_chipData[bltcpt + 1]; + SAEV_Custom_last_value = blt_info.bltcdat; + addr = bltcpt; + bltcpt += blit_add; + reg = 0x70; + ptr.val = bltcpt; + //SAER.events.alloc_cycle_blitter(hpos, ptr, 3); + bltcpt = ptr.val; + break; + //default: abort(); + } + + blitter_cyclecounter++; + if (blitter_cyclecounter >= blit_dmacount2) { + blitter_cyclecounter = 0; + ddat2 = ddat1; + ddat2use = ddat1use; + ddat1use = 0; + ddat1 = blitter_doblit(); + if (bltcon0 & 0x100) + ddat1use = 1; + blitter_hcounter1++; + if (blitter_hcounter1 == blt_info.hblitsize) { + blitter_hcounter1 = 0; + if (bltcon0 & 0x800) bltapt += blit_modadda; + if (bltcon0 & 0x400) bltbpt += blit_modaddb; + if (bltcon0 & 0x200) bltcpt += blit_modaddc; + blitter_vcounter1++; + blitfc = !!(bltcon1 & 0x4); + } + } + } + + /*this.blitter_need = function(hpos) { + if (SAEV_Blitter_bltstate == SAEC_Blitter_bltstate_DONE) + return 0; + if (!SAEF_Custom_dmaen(SAEC_Custom_DMAF_BLTEN)) + return 0; + return channel_state(blit_cyclecounter); + }*/ + + function do_startcycles(hpos) { + var vhpos = last_blitter_hpos; + while (vhpos < hpos) { + var v = canblit(vhpos); + vhpos++; + if (v > 0) { + blit_startcycles--; + if (blit_startcycles == 0) { + if (blit_faulty) + blit_faulty = -1; + SAEV_Blitter_bltstate = SAEC_Blitter_bltstate_DONE; + blit_final = 0; + do_blitter(vhpos, 0); + blit_startcycles = 0; + blit_cyclecounter = 0; + blit_waitcyclecounter = 0; + if (blit_faulty) + blit_faulty = 1; + return; + } + } + } + } + + this.decide_blitter = function(hpos) { + var hsync = hpos < 0; + + if (immediate_blits) { + if (SAEV_Blitter_bltstate == SAEC_Blitter_bltstate_DONE) + return; + if (SAEF_Custom_dmaen(SAEC_Custom_DMAF_BLTEN)) + blitter_doit(); + return; + } + + if (blit_startcycles > 0) + do_startcycles(hpos); + + if (blt_delayed_irq > 0 && hsync) { + blt_delayed_irq--; + if (!blt_delayed_irq) + SAER.custom.send_interrupt(SAEC_Custom_INTF_BLIT, 2 * SAEC_Events_CYCLE_UNIT); + } + + if (SAEV_Blitter_bltstate == SAEC_Blitter_bltstate_DONE) + return; + + /*if (log_blitter && blitter_delayed_debug) { + blitter_delayed_debug = 0; + blitter_dump (); + }*/ + + if (!blitter_cycle_exact) + return; + + if (hpos < 0) + hpos = SAER.playfield.get_maxhpos(); + + if (blitline) { + blt_info.got_cycle = 1; + decide_blitter_line(hsync, hpos); + return; + } + + while (last_blitter_hpos < hpos) { + var c = channel_state(blit_cyclecounter); + + for (;;) { + var v = canblit(last_blitter_hpos); + + // copper bltsize write needs one cycle (any cycle) delay + if (blit_waitcyclecounter) { + blit_waitcyclecounter = 0; + break; + } + // idle cycles require free bus. + // Final empty cycle does not, unless it is fill mode that requires extra idle cycle + // (CPU can still use this cycle) + if ((c == 0 && v == 0) || v < 0) { + if (blit_cyclecounter < 0 || !blit_final) { + blit_misscyclecounter++; + break; + } + if (blitfill && blit_cycle_diagram_fill[blit_ch][0]) { + blit_misscyclecounter++; + blitter_nasty++; + break; + } + } + + if (blit_frozen) { + blit_misscyclecounter++; + break; + } + + if (c == 0) { + blt_info.got_cycle = 1; + blit_cyclecounter++; + if (blit_cyclecounter == 0) + blit_final = 0; + blit_totalcyclecounter++; + /* check if blit with zero channels has ended */ + if (blit_ch == 0 && blit_cyclecounter >= blit_maxcyclecounter) { + blitter_done(last_blitter_hpos); + return; + } + break; + } + + blitter_nasty++; + + if (v <= 0) { + blit_misscyclecounter++; + break; + } + + blt_info.got_cycle = 1; + if (c == 4) { + blitter_doddma(last_blitter_hpos); + blit_cyclecounter++; + blit_totalcyclecounter++; + } else { + if (blitter_vcounter1 < blt_info.vblitsize) { + blitter_dodma(c, last_blitter_hpos); + } + blit_cyclecounter++; + blit_totalcyclecounter++; + } + + if (blitter_vcounter1 >= blt_info.vblitsize && blitter_vcounter2 >= blt_info.vblitsize) { + if (!ddat1use && !ddat2use) { + blitter_done(last_blitter_hpos); + return; + } + } + // check this after end check because last D write won't cause any problems. + check_channel_mods(last_blitter_hpos, c); + break; + } + + if (SAEF_Custom_dmaen(SAEC_Custom_DMAF_BLTEN) && !blit_final && (blitter_vcounter1 == blt_info.vblitsize || (blitter_vcounter1 == blt_info.vblitsize - 1 && blitter_hcounter1 == blt_info.hblitsize - 1 && blit_dmacount2 == 0))) { + if (channel_pos(blit_cyclecounter - 1) == blit_diag[0] - 1) { + blitter_interrupt(last_blitter_hpos, 0); + blit_cyclecounter = 0; + blit_final = 1; + } + } + last_blitter_hpos++; + } + reset_channel_mods(); + if (hsync) + last_blitter_hpos = 0; + } + /*#else + this.decide_blitter = function(hpos) { } + #endif*/ + + /*-----------------------------------------------------------------------*/ + + function blitter_force_finish() { + if (SAEV_Blitter_bltstate == SAEC_Blitter_bltstate_DONE) + return; + if (SAEV_Blitter_bltstate != SAEC_Blitter_bltstate_DONE) { + /* blitter is currently running + * force finish (no blitter state support yet) + */ + var odmacon = SAEV_Custom_dmacon; + SAEV_Custom_dmacon |= (SAEC_Custom_DMAF_DMAEN | SAEC_Custom_DMAF_BLTEN); + SAEF_log("blitter.blitter_force_finish() forcing finish"); + if (blitter_cycle_exact && !immediate_blits) { + var rounds = 10000; + while (SAEV_Blitter_bltstate != SAEC_Blitter_bltstate_DONE && rounds > 0) { + //SAER_Events_cycle_line.clr(); + SAER.blitter.decide_blitter(-1); + rounds--; + } + if (rounds == 0) SAEF_warn("blitter.blitter_force_finish() froze!?"); + blit_startcycles = 0; + } else + actually_do_blit(); + + blitter_done(SAER.events.current_hpos()); + SAEV_Custom_dmacon = odmacon; + } + } + + /*function invstate() { //OPT inline, ok + return SAEV_Blitter_bltstate != SAEC_Blitter_bltstate_DONE && SAEV_Blitter_bltstate != SAEC_Blitter_bltstate_INIT; + }*/ - var changetable = new Uint8Array(32 * 32); for (var i = 0; i < changetable.length; i++) changetable[i] = 0; - //var freezes = 10; function blit_bltset(con) { + //const int *olddiag = blit_diag; + var old_diag_type = blit_diag_type; + if (con & 2) { blitdesc = bltcon1 & 2; blt_info.blitbshift = bltcon1 >> 12; blt_info.blitdownbshift = 16 - blt_info.blitbshift; + if ((bltcon1 & 1) && !blitline_started) { + SAEF_warn("blitter.blit_bltset() linedraw enabled after starting normal blit!"); + return; + } } - if (con & 1) { blt_info.blitashift = bltcon0 >> 12; blt_info.blitdownashift = 16 - blt_info.blitashift; } blit_ch = (bltcon0 & 0x0f00) >> 8; - blitline = (bltcon1 & 1) != 0; + blitline = bltcon1 & 1; blitfill = !!(bltcon1 & 0x18); - if (bltstate != BLT_done && blitline) { + // disable line draw if bltcon0 is written while it is active + if (SAEV_Blitter_bltstate != SAEC_Blitter_bltstate_DONE && SAEV_Blitter_bltstate != SAEC_Blitter_bltstate_INIT && blitline && blitline_started) { blitline = 0; - bltstate = BLT_done; - blit_interrupt = true; - BUG.info('blit_bltset() register modification during linedraw! (%d)', bltstate); + SAEV_Blitter_bltstate = SAEC_Blitter_bltstate_DONE; + SAEV_Blitter_interrupt = true; + SAEF_warn("blitter.blit_bltset() register modification during linedraw!"); } if (blitline) { - if (blt_info.hblitsize != 2) - BUG.info('blit_bltset() weird hsize in linemode: %d vsize=%d', blt_info.hblitsize, blt_info.vblitsize); + /*if (blt_info.hblitsize != 2) { + debugtest (DEBUGTEST_BLITTER, "weird blt_info.hblitsize in linemode: %d vsize=%d", blt_info.hblitsize, blt_info.vblitsize); + }*/ blit_diag = blit_cycle_diagram_line; + blit_diag_type = DT_LINE; //OWN } else { if (con & 2) { blitfc = !!(bltcon1 & 0x4); blitife = !!(bltcon1 & 0x8); if ((bltcon1 & 0x18) == 0x18) { - //BUG.info('blit_bltset() weird fill mode'); + //debugtest (DEBUGTEST_BLITTER, "weird fill mode"); blitife = 0; } } - //if (blitfill && !blitdesc) BUG.info('blit_bltset() fill without desc'); - - blit_diag = blitfill && blit_cycle_diagram_fill[blit_ch][0] ? blit_cycle_diagram_fill[blit_ch] : blit_cycle_diagram[blit_ch]; + /*if (blitfill && !blitdesc) { + debugtest (DEBUGTEST_BLITTER, "fill without desc"); + }*/ + if (blitfill && blit_cycle_diagram_fill[blit_ch][0]) { + blit_diag = blit_cycle_diagram_fill[blit_ch]; + blit_diag_type = DT_BLOCKFILL; + } else { + blit_diag = blit_cycle_diagram[blit_ch]; + blit_diag_type = DT_BLOCK; + } + } + /*if ((bltcon1 & 0x80) && (SAEV_config.chipset.mask & SAEC_Config_Chipset_Mask_ECS_AGNUS)) { + debugtest (DEBUGTEST_BLITTER, "ECS BLTCON1 DOFF-bit set"); + }*/ + + // on the fly switching fillmode from extra cycle to non-extra: blitter freezes + // non-extra cycle to extra cycle: does not freeze but cycle diagram goes weird, + // extra free cycle changes to another D write.. + // (Absolute Inebriation vector cube inside semi-filled vector object requires freezing blitter.) + //if (invstate()) { + if (SAEV_Blitter_bltstate != SAEC_Blitter_bltstate_DONE && SAEV_Blitter_bltstate != SAEC_Blitter_bltstate_INIT) { + //static int freezes = 10; + //var isen = blit_diag >= &blit_cycle_diagram_fill[0][0] && blit_diag <= &blit_cycle_diagram_fill[15][0]; + //var iseo = olddiag >= &blit_cycle_diagram_fill[0][0] && olddiag <= &blit_cycle_diagram_fill[15][0]; + var isen = blit_diag_type == DT_BLOCKFILL; //OWN + var iseo = old_diag_type == DT_BLOCKFILL; //OWN + if (iseo != isen) { + if (freezes > 0) { + SAEF_warn("blitter.blit_bltset() on the fly %d (%d) -> %d (%d) switch!", original_ch, iseo, blit_ch, isen); + freezes--; + } + } + if (original_fill == isen) { + blit_frozen = 0; // switched back to original fill mode? unfreeze + } else if (iseo && !isen) { + blit_frozen = 1; + SAEF_warn("blitter.blit_bltset() frozen! %d (%d) -> %d (%d)", original_ch, iseo, blit_ch, isen); + } else if (!iseo && isen) { + if (!SAEF_Custom_dmaen(SAEC_Custom_DMAF_BLTEN)) // subtle shades / nuance bootblock bug + blit_frozen = 1; + //if (log_blitter) onsole.log(sprintf("blit_bltset() on the fly %d (%d) -> %d (%d) switch", original_ch, iseo, blit_ch, isen)); + } } - if ((bltcon1 & 0x80) && (AMIGA.config.chipset.mask & CSMASK_ECS_AGNUS)) - BUG.info('blit_bltset() ECS BLTCON1 DOFF-bit set'); // on the fly switching from CH=1 to CH=D -> blitter stops writing (Rampage/TEK) // currently just switch to no-channels mode, better than crashing the demo.. - if (bltstate != BLT_done) { + // if (invstate()) { + if (SAEV_Blitter_bltstate != SAEC_Blitter_bltstate_DONE && SAEV_Blitter_bltstate != SAEC_Blitter_bltstate_INIT) { + //static uae_u8 changetable[32 * 32]; var o = original_ch + (original_fill ? 16 : 0); var n = blit_ch + (blitfill ? 16 : 0); if (o != n) { if (changetable[o * 32 + n] < 10) { changetable[o * 32 + n]++; - BUG.info('blit_bltset() channel mode changed while active (%02x->%02x)', o, n); + SAEF_warn("blitter.blit_bltset() channel mode changed while active (%02x->%02x)", o, n); } } if (blit_ch == 13 && original_ch == 1) blit_faulty = 1; } + if (blit_faulty) { - BUG.info('blit_bltset() blitter faulty!'); blit_ch = 0; blit_diag = blit_cycle_diagram[blit_ch]; + blit_diag_type = DT_BLOCK; //OWN } blit_dmacount = blit_dmacount2 = 0; @@ -2493,65 +1290,104 @@ function Blitter() { if (v == 4) blit_nod = 0; } + if (blit_dmacount2 == 0) { + ddat2use = 0; + ddat1use = 0; + } + } + + function blit_modset() { + blit_add = blitdesc ? -2 : 2; + var mult = blitdesc ? -1 : 1; + blit_modadda = mult * blt_info.bltamod; + blit_modaddb = mult * blt_info.bltbmod; + blit_modaddc = mult * blt_info.bltcmod; + blit_modaddd = mult * blt_info.bltdmod; } function reset_blit(bltcon) { if (bltcon & 1) blinea_shift = bltcon0 >> 12; if (bltcon & 2) - blitsign = (bltcon1 & 0x40) != 0; - if (bltstate == BLT_done) + blitsign = !!(bltcon1 & 0x40); + if (SAEV_Blitter_bltstate == SAEC_Blitter_bltstate_DONE) return; if (bltcon) blit_bltset(bltcon); + blit_modset(); } - var warned1 = 10; function waitingblits() { var waited = false; - while (bltstate != BLT_done && AMIGA.dmaen(DMAF_BLTEN)) { + while (SAEV_Blitter_bltstate != SAEC_Blitter_bltstate_DONE && SAEF_Custom_dmaen(SAEC_Custom_DMAF_BLTEN)) { waited = true; - AMIGA.events.cycle(8 * CYCLE_UNIT); + SAER.events.do_cycles(8 * SAEC_Events_CYCLE_UNIT); } if (warned1 && waited) { warned1--; - BUG.info('waiting_blits detected'); + SAEF_warn("blitter.waitingblits() waiting blits detected"); } - return bltstate == BLT_done; - + return SAEV_Blitter_bltstate == SAEC_Blitter_bltstate_DONE; } - function do_blitter(hpos, copper) { + function blitter_start_init() { + blt_info.blitzero = 1; + preva = 0; + prevb = 0; + blit_frozen = 0; + blitline_started = bltcon1 & 1; + + blit_bltset(1 | 2); + blit_modset(); + ddat1use = ddat2use = 0; + SAEV_Blitter_interrupt = false; + + if (blitline) { + blinea = blt_info.bltadat; + blineb = (blt_info.bltbdat >> blt_info.blitbshift) | ((blt_info.bltbdat << (16 - blt_info.blitbshift)) & 0xffff); + blitonedot = 0; + blitlinepixel = 0; + blitsing = bltcon1 & 0x2; + } + } + + function do_blitter2(hpos, copper) { var cycles; + /*if ((log_blitter & 2)) { + if (SAEV_Blitter_bltstate != SAEC_Blitter_bltstate_DONE) { + if (blit_final) + SAEF_log("blitter.do_blitter2() blitter was already active!"); + } + }*/ + var cleanstart = 0; - if (bltstate == BLT_done) { + if (SAEV_Blitter_bltstate == SAEC_Blitter_bltstate_DONE) { if (blit_faulty > 0) blit_faulty = 0; cleanstart = 1; } - blt_info.blitzero = 1; + SAEV_Blitter_bltstate = SAEC_Blitter_bltstate_DONE; + + blitter_cycle_exact = SAEV_config.chipset.blitter.cycle_exact; + immediate_blits = SAEV_config.chipset.blitter.immediate; blt_info.got_cycle = 0; - - blit_firstline_cycles = blit_first_cycle = AMIGA.events.currcycle; - blit_last_cycle = 0; last_blitter_hpos = hpos + 1; + blit_firstline_cycles = blit_first_cycle = SAEV_Events_currcycle; + blit_misscyclecounter = 0; + blit_last_cycle = 0; + blit_maxcyclecounter = 0; + blit_cyclecounter = 0; + blit_totalcyclecounter = 0; - blit_bltset(1 | 2); - ddat1use = ddat2use = 0; - blit_interrupt = false; + blitter_start_init(); if (blitline) { - blinea = blt_info.bltadat; - blineb = ((blt_info.bltbdat >>> blt_info.blitbshift) | (blt_info.bltbdat << (16 - blt_info.blitbshift))) & 0xffff; - blitonedot = 0; - blitlinepixel = 0; - blitsing = (bltcon1 & 0x2) != 0; cycles = blt_info.vblitsize; } else { - blit_firstline_cycles = blit_first_cycle + (blit_diag[0] * blt_info.hblitsize + AMIGA.cpu.cycles) * CYCLE_UNIT; cycles = blt_info.vblitsize * blt_info.hblitsize; + blit_firstline_cycles = blit_first_cycle + (blit_diag[0] * blt_info.hblitsize) * SAEC_Events_CYCLE_UNIT + SAEV_CPU_cycles; } if (cleanstart) { @@ -2560,120 +1396,202 @@ function Blitter() { original_line = blitline; } - /*if (0) { - var ch = 0; - if (blit_ch & 1) ch++; - if (blit_ch & 2) ch++; - if (blit_ch & 4) ch++; - if (blit_ch & 8) ch++; - BUG.info('do_blitter2() %dx%d ch=%d %d*%d=%d d=%d f=%d n=%d l=%d dma=%04x %s', - blt_info.hblitsize, blt_info.vblitsize, ch, blit_diag[0], cycles, blit_diag[0] * cycles, - blitdesc ? 1 : 0, blitfill ? 1 : 0, AMIGA.dmaen(DMAF_BLTPRI) ? 1 : 0, blitline ? 1 : 0, - AMIGA.dmacon, AMIGA.dmaen(DMAF_BLTEN) ? 'on' : 'off!'); - blitter_dump(); + /*if (log_blitter & 1) { + blitter_dontdo = 0; + if (1) { + var ch = 0; + if (blit_ch & 1) ch++; + if (blit_ch & 2) ch++; + if (blit_ch & 4) ch++; + if (blit_ch & 8) ch++; + SAEF_log("blitter.do_blitter2() blitstart: %dx%d ch=%d %d*%d=%d d=%d f=%02x n=%d pc=%08x l=%d dma=%04x %s", + blt_info.hblitsize, blt_info.vblitsize, ch, blit_diag[0], cycles, blit_diag[0] * cycles, + blitdesc ? 1 : 0, blitfill, SAEF_Custom_dmaen(SAEC_Custom_DMAF_BLTPRI) ? 1 : 0, SAER_CPU_getPC(), blitline, + SAEV_Custom_dmacon, ((SAEV_Custom_dmacon & (SAEC_Custom_DMAF_DMAEN | SAEC_Custom_DMAF_BLTEN)) == (SAEC_Custom_DMAF_DMAEN | SAEC_Custom_DMAF_BLTEN)) ? "" : " off!"); + blitter_dump(); + } }*/ - bltstate = BLT_init; + SAEV_Blitter_bltstate = SAEC_Blitter_bltstate_INIT; blit_slowdown = 0; - clr_special(SPCFLAG_BLTNASTY); - if (AMIGA.dmaen(DMAF_BLTPRI)) - set_special(SPCFLAG_BLTNASTY); + SAEF_clrSpcFlags(SAEC_spcflag_BLTNASTY); + if (SAEF_Custom_dmaen(SAEC_Custom_DMAF_BLTPRI)) + SAEF_setSpcFlags(SAEC_spcflag_BLTNASTY); - if (AMIGA.dmaen(DMAF_BLTEN)) - bltstate = BLT_work; + if (SAEF_Custom_dmaen(SAEC_Custom_DMAF_BLTEN)) + SAEV_Blitter_bltstate = SAEC_Blitter_bltstate_WORK; + + blit_maxcyclecounter = 0x7fffffff; + blit_waitcyclecounter = 0; + + if (blitter_cycle_exact) { + if (immediate_blits) { + if (SAEF_Custom_dmaen(SAEC_Custom_DMAF_BLTEN)) + blitter_doit(); + return; + } + /*if (log_blitter & 8) + SAER.blitter.handler(0); + else*/ + { + blitter_hcounter1 = blitter_hcounter2 = 0; + blitter_vcounter1 = blitter_vcounter2 = 0; + if (blit_nod) + blitter_vcounter2 = blt_info.vblitsize; + blit_cyclecounter = -BLITTER_STARTUP_CYCLES; + blit_waitcyclecounter = copper; + blit_startcycles = 0; + blit_maxcyclecounter = blt_info.hblitsize * blt_info.vblitsize + 2; + } + return; + } if (blt_info.vblitsize == 0 || (blitline && blt_info.hblitsize != 2)) { - blitter_done(hpos); - return; - } - blt_info.got_cycle = 1; - - if (AMIGA.config.blitter.immediate) { - blitter_do(); + if (SAEF_Custom_dmaen(SAEC_Custom_DMAF_BLTEN)) + blitter_done(hpos); return; } - blit_cyclecounter = cycles * (blit_dmacount2 + (blit_nod ? 0 : 1)); + if (SAEF_Custom_dmaen(SAEC_Custom_DMAF_BLTEN)) + blt_info.got_cycle = 1; - AMIGA.events.newevent(EV2_BLITTER, blit_cyclecounter, 0); + if (immediate_blits) { + if (SAEF_Custom_dmaen(SAEC_Custom_DMAF_BLTEN)) + blitter_doit(); + return; + } - if (AMIGA.dmaen(DMAF_BLTEN)) { - if (AMIGA.config.blitter.waiting) { + blit_cyclecounter = cycles * (blit_dmacount2 + (blit_nod ? 0 : 1)); + SAER.events.event2_newevent(SAEC_Events_EV2_BLITTER, blit_cyclecounter, 0); + + if (SAEF_Custom_dmaen(SAEC_Custom_DMAF_BLTEN)) { + if (SAEV_config.chipset.blitter.waiting) { // wait immediately if all cycles in use and blitter nastry - if (blit_dmacount == blit_diag[0] && (AMIGA.spcflags & SPCFLAG_BLTNASTY)) + if (blit_dmacount == blit_diag[0] && (SAEV_spcflags & SAEC_spcflag_BLTNASTY)) { waitingblits(); + } } } } - - var warned2 = 10; - this.maybe_blit = function (hpos, hack) { - if (bltstate == BLT_done) + + this.blitter_check_start = function() { + if (SAEV_Blitter_bltstate != SAEC_Blitter_bltstate_INIT) + return; + blitter_start_init(); + SAEV_Blitter_bltstate = SAEC_Blitter_bltstate_WORK; + if (immediate_blits) + blitter_doit(); + } + + function do_blitter(hpos, copper) { + if (SAEV_Blitter_bltstate == SAEC_Blitter_bltstate_DONE || !blitter_cycle_exact) { + do_blitter2(hpos, copper); + return; + } + if (!SAEF_Custom_dmaen(SAEC_Custom_DMAF_BLTEN) || !blt_info.got_cycle) + return; + // previous blit may have last write cycle left + // and we must let it finish + blit_startcycles = BLITTER_STARTUP_CYCLES; + blit_waitcyclecounter = copper; + } + + function maybe_blit(hpos, hack) { + reset_channel_mods(); + + if (SAEV_Blitter_bltstate == SAEC_Blitter_bltstate_DONE) return; - if (AMIGA.dmaen(DMAF_BLTEN)) { + if (SAEF_Custom_dmaen(SAEC_Custom_DMAF_BLTEN)) { var doit = false; - if (AMIGA.config.blitter.waiting == 3) { // always + if (SAEV_config.chipset.blitter.waiting == 3) { // always doit = true; - } else if (AMIGA.config.blitter.waiting == 2) { // no idle - if (blit_dmacount == blit_diag[0] && (AMIGA.spcflags & SPCFLAG_BLTNASTY)) + } else if (SAEV_config.chipset.blitter.waiting == 2) { // noidle + if (blit_dmacount == blit_diag[0] && (SAEV_spcflags & SAEC_spcflag_BLTNASTY)) doit = true; - } else if (AMIGA.config.blitter.waiting == 1) { // automatic - if (blit_dmacount == blit_diag[0] && (AMIGA.spcflags & SPCFLAG_BLTNASTY)) + } else if (SAEV_config.chipset.blitter.waiting == 1) { // automatic + if (blit_dmacount == blit_diag[0] && (SAEV_spcflags & SAEC_spcflag_BLTNASTY)) doit = true; - else if (AMIGA.config.cpu.speed < 0) + else if (SAEV_config.cpu.speed < 0) doit = true; - } + } //else {} never + if (doit) { if (waitingblits()) return; } } - if (warned2 && AMIGA.dmaen(DMAF_BLTEN) && blt_info.got_cycle) { + if (warned2 && SAEF_Custom_dmaen(SAEC_Custom_DMAF_BLTEN) && blt_info.got_cycle) { warned2--; - BUG.info('maybe_blit() program does not wait for blitter tc=%d', blit_cyclecounter); + //debugtest (DEBUGTEST_BLITTER, "program does not wait for blitter tc=%d", blit_cyclecounter); + //if (log_blitter) warned2 = 0; + //if (log_blitter & 2) + { + //warned2 = 10; + SAEF_warn("blitter.maybe_blit() program does not wait for blitter"); + //blitter_done(hpos); + } } - if (hack == 1 && AMIGA.events.currcycle < blit_firstline_cycles) + if (blitter_cycle_exact) { + SAER.blitter.decide_blitter(hpos); + //if (log_blitter) blitter_delayed_debug = 1; return; + } + if (hack == 1 && SAEV_Events_currcycle - blit_firstline_cycles < 0) { + //if (log_blitter) blitter_delayed_debug = 1; + return; + } + SAER.blitter.handler(0); + } - AMIGA.blitter.handler(0); - }; + this.check_is_blit_dangerous = function(bplpt, planes, words) { + SAEV_Blitter_dangerous = false; + if (SAEV_Blitter_bltstate == SAEC_Blitter_bltstate_DONE || !blitter_cycle_exact) + return; + for (var i = 0; i < planes; i++) { + var bpl = bplpt[i]; + //var dpt = bltdpt & chipmem_bank.mask; + var dpt = (bltdpt & SAEV_Memory_chipMask) >>> 0; + if (dpt >= bpl - 2 * words && dpt < bpl + 2 * words) { + SAEV_Blitter_dangerous = true; + return; + } + } + } - this.blitnasty = function () { - if (bltstate == BLT_done || !AMIGA.dmaen(DMAF_BLTEN)) + this.blitnasty = function() { + if (SAEV_Blitter_bltstate == SAEC_Blitter_bltstate_DONE) return 0; + if (!SAEF_Custom_dmaen(SAEC_Custom_DMAF_BLTEN)) + return 0; + if (blitter_cycle_exact) { + blitter_force_finish(); + return -1; + } if (blit_last_cycle >= blit_diag[0] && blit_dmacount == blit_diag[0]) return 0; - - var cycles = Math.floor((AMIGA.events.currcycle - blit_first_cycle) * CYCLE_UNIT_INV); + var cycles = ((SAEV_Events_currcycle - blit_first_cycle) * SAEC_Events_CYCLE_UNIT_INV) >>> 0; var ccnt = 0; while (blit_last_cycle < cycles) { - if (!channel_state(blit_last_cycle++)) - ccnt++; + var c = channel_state(blit_last_cycle++); + if (!c) ccnt++; } return ccnt; - }; + } - /*---------------------------------*/ - - var oddfstrt = 0, oddfstop = 0, ototal = 0, ofree = 0, slow = 0; - this.slowdown = function () { - var data = AMIGA.playfield.getData(); - var ddfstrt = data[0]; - var ddfstop = data[1]; - var totalcycles = data[2]; - var freecycles = data[3]; + /* very approximate emulation of blitter slowdown caused by bitplane DMA */ + this.blitter_slowdown = function(ddfstrt, ddfstop, totalcycles, freecycles) { + //static int oddfstrt, oddfstop, ototal, ofree, slow; if (!totalcycles || ddfstrt < 0 || ddfstop < 0) return; if (ddfstrt != oddfstrt || ddfstop != oddfstop || totalcycles != ototal || ofree != freecycles) { - var linecycles = Math.floor(((ddfstop - ddfstrt + totalcycles - 1) / totalcycles) * totalcycles); - var freelinecycles = Math.floor(((ddfstop - ddfstrt + totalcycles - 1) / totalcycles) * freecycles); - var dmacycles = Math.floor((linecycles * blit_dmacount) / blit_diag[0]); - + var linecycles = (((ddfstop - ddfstrt + totalcycles - 1) / totalcycles) * totalcycles) >>> 0; + var freelinecycles = (((ddfstop - ddfstrt + totalcycles - 1) / totalcycles) * freecycles) >>> 0; + var dmacycles = ((linecycles * blit_dmacount) / blit_diag[0]) >>> 0; oddfstrt = ddfstrt; oddfstop = ddfstop; ototal = totalcycles; @@ -2684,115 +1602,170 @@ function Blitter() { } if (blit_slowdown < 0 || blitline) return; - blit_slowdown += slow; - }; - - /*---------------------------------*/ + blit_misscyclecounter += slow; + } - this.BLTADAT = function (hpos, v) { - this.maybe_blit(hpos, 0); + /*-----------------------------------------------------------------------*/ + + this.BLTADAT = function(hpos, v) { + maybe_blit(hpos, 0); blt_info.bltadat = v; - }; - this.BLTBDAT = function (hpos, v) { - this.maybe_blit(hpos, 0); + } + this.BLTBDAT = function(hpos, v) { + maybe_blit(hpos, 0); if (bltcon1 & 2) blt_info.bltbhold = (v << (bltcon1 >> 12)) & 0xffff; else blt_info.bltbhold = (v >> (bltcon1 >> 12)) & 0xffff; - blt_info.bltbdat = v; - }; - this.BLTCDAT = function (hpos, v) { - this.maybe_blit(hpos, 0); + } + this.BLTCDAT = function(hpos, v) { + maybe_blit(hpos, 0); blt_info.bltcdat = v; reset_blit(0); - }; + } - this.BLTAMOD = function (hpos, v) { - this.maybe_blit(hpos, 1); - blt_info.bltamod = castWord(v & 0xfffe); + this.BLTAMOD = function(hpos, v) { + maybe_blit(hpos, 1); + //blt_info.bltamod = (uae_s16)(v & 0xFFFE); //ORG + blt_info.bltamod = v & 0xfffe; if (blt_info.bltamod & 0x8000) blt_info.bltamod -= 0x10000; //OWN reset_blit(0); - }; - this.BLTBMOD = function (hpos, v) { - this.maybe_blit(hpos, 1); - blt_info.bltbmod = castWord(v & 0xfffe); + } + this.BLTBMOD = function(hpos, v) { + maybe_blit(hpos, 1); + //blt_info.bltbmod = (uae_s16)(v & 0xFFFE); //ORG + blt_info.bltbmod = v & 0xfffe; if (blt_info.bltbmod & 0x8000) blt_info.bltbmod -= 0x10000; //OWN reset_blit(0); - }; - this.BLTCMOD = function (hpos, v) { - this.maybe_blit(hpos, 1); - blt_info.bltcmod = castWord(v & 0xfffe); + } + this.BLTCMOD = function(hpos, v) { + maybe_blit(hpos, 1); + //blt_info.bltcmod = (uae_s16)(v & 0xFFFE); //ORG + blt_info.bltcmod = v & 0xfffe; if (blt_info.bltcmod & 0x8000) blt_info.bltcmod -= 0x10000; //OWN reset_blit(0); - }; - this.BLTDMOD = function (hpos, v) { - this.maybe_blit(hpos, 1); - blt_info.bltdmod = castWord(v & 0xfffe); + } + this.BLTDMOD = function(hpos, v) { + maybe_blit(hpos, 1); + //blt_info.bltdmod = (uae_s16)(v & 0xFFFE); //ORG + blt_info.bltdmod = v & 0xfffe; if (blt_info.bltdmod & 0x8000) blt_info.bltdmod -= 0x10000; //OWN reset_blit(0); - }; + } - this.BLTCON0 = function (hpos, v) { - this.maybe_blit(hpos, 2); + this.BLTCON0 = function(hpos, v) { + maybe_blit(hpos, 2); bltcon0 = v; reset_blit(1); - }; - this.BLTCON0L = function (hpos, v) { - if (!(AMIGA.config.chipset.mask & CSMASK_ECS_AGNUS)) return; - this.maybe_blit(hpos, 2); + } + this.BLTCON0L = function(hpos, v) { + //if (!(SAEV_config.chipset.mask & SAEC_Config_Chipset_Mask_ECS_AGNUS)) return; + maybe_blit(hpos, 2); bltcon0 = (bltcon0 & 0xFF00) | (v & 0xFF); reset_blit(1); - }; - this.BLTCON1 = function (hpos, v) { - this.maybe_blit(hpos, 2); + } + this.BLTCON1 = function(hpos, v) { + maybe_blit(hpos, 2); bltcon1 = v; reset_blit(2); - }; + } - this.BLTAFWM = function (hpos, v) { - this.maybe_blit(hpos, 2); + this.BLTAFWM = function(hpos, v) { + maybe_blit(hpos, 2); blt_info.bltafwm = v; reset_blit(0); - }; - this.BLTALWM = function (hpos, v) { - this.maybe_blit(hpos, 2); + } + this.BLTALWM = function(hpos, v) { + maybe_blit(hpos, 2); blt_info.bltalwm = v; reset_blit(0); - }; + } - this.BLTAPTH = function (hpos, v) { - this.maybe_blit(hpos, 0); - bltapt = ((bltapt & 0xffff) | (v << 16)) >>> 0; - }; - this.BLTAPTL = function (hpos, v) { - this.maybe_blit(hpos, 0); - bltapt = ((bltapt & ~0xffff) | (v & 0xfffe)) >>> 0; - }; - this.BLTBPTH = function (hpos, v) { - this.maybe_blit(hpos, 0); - bltbpt = ((bltbpt & 0xffff) | (v << 16)) >>> 0; - }; - this.BLTBPTL = function (hpos, v) { - this.maybe_blit(hpos, 0); - bltbpt = ((bltbpt & ~0xffff) | (v & 0xfffe)) >>> 0; - }; - this.BLTCPTH = function (hpos, v) { - this.maybe_blit(hpos, 0); - bltcpt = ((bltcpt & 0xffff) | (v << 16)) >>> 0; - }; - this.BLTCPTL = function (hpos, v) { - this.maybe_blit(hpos, 0); - bltcpt = ((bltcpt & ~0xffff) | (v & 0xfffe)) >>> 0; - }; - this.BLTDPTH = function (hpos, v) { - this.maybe_blit(hpos, 0); - bltdpt = ((bltdpt & 0xffff) | (v << 16)) >>> 0; - }; - this.BLTDPTL = function (hpos, v) { - this.maybe_blit(hpos, 0); - bltdpt = ((bltdpt & ~0xffff) | (v & 0xfffe)) >>> 0; - }; + this.BLTAPTH = function(hpos, v) { + v = v & (SAEV_config.chipset.mask == SAEC_Config_Chipset_Mask_OCS ? 7 : 31); //OWN + maybe_blit(hpos, 0); + if (SAEV_Blitter_bltstate != SAEC_Blitter_bltstate_DONE && SAEV_config.chipset.blitter.cycle_exact) { + bltptx = ((bltapt & 0xffff) | (v << 16)) >>> 0; + bltptxpos = hpos; + bltptxc = 1; + } else { + bltapt = ((bltapt & 0xffff) | (v << 16)) >>> 0; + } + } + this.BLTAPTL = function(hpos, v) { + maybe_blit(hpos, 0); + if (SAEV_Blitter_bltstate != SAEC_Blitter_bltstate_DONE && SAEV_config.chipset.blitter.cycle_exact) { + bltptx = ((bltapt & 0xffff0000) | (v & 0xfffe)) >>> 0; + bltptxpos = hpos; + bltptxc = 1; + } else { + bltapt = ((bltapt & 0xffff0000) | (v & 0xfffe)) >>> 0; + } + } + this.BLTBPTH = function(hpos, v) { + v = v & (SAEV_config.chipset.mask == SAEC_Config_Chipset_Mask_OCS ? 7 : 31); //OWN + maybe_blit(hpos, 0); + if (SAEV_Blitter_bltstate != SAEC_Blitter_bltstate_DONE && SAEV_config.chipset.blitter.cycle_exact) { + bltptx = ((bltbpt & 0xffff) | (v << 16)) >>> 0; + bltptxpos = hpos; + bltptxc = 2; + } else { + bltbpt = ((bltbpt & 0xffff) | (v << 16)) >>> 0; + } + } + this.BLTBPTL = function(hpos, v) { + maybe_blit(hpos, 0); + if (SAEV_Blitter_bltstate != SAEC_Blitter_bltstate_DONE && SAEV_config.chipset.blitter.cycle_exact) { + bltptx = ((bltbpt & 0xffff0000) | (v & 0xfffe)) >>> 0; + bltptxpos = hpos; + bltptxc = 2; + } else { + bltbpt = ((bltbpt & 0xffff0000) | (v & 0xfffe)) >>> 0; + } + } + this.BLTCPTH = function(hpos, v) { + v = v & (SAEV_config.chipset.mask == SAEC_Config_Chipset_Mask_OCS ? 7 : 31); //OWN + maybe_blit(hpos, 0); + if (SAEV_Blitter_bltstate != SAEC_Blitter_bltstate_DONE && SAEV_config.chipset.blitter.cycle_exact) { + bltptx = ((bltcpt & 0xffff) | (v << 16)) >>> 0; + bltptxpos = hpos; + bltptxc = 3; + } else { + bltcpt = ((bltcpt & 0xffff) | (v << 16)) >>> 0; + } + } + this.BLTCPTL = function(hpos, v) { + maybe_blit(hpos, 0); + if (SAEV_Blitter_bltstate != SAEC_Blitter_bltstate_DONE && SAEV_config.chipset.blitter.cycle_exact) { + bltptx = ((bltcpt & 0xffff0000) | (v & 0xfffe)) >>> 0; + bltptxpos = hpos; + bltptxc = 3; + } else { + bltcpt = ((bltcpt & 0xffff0000) | (v & 0xfffe)) >>> 0; + } + } + this.BLTDPTH = function(hpos, v) { + v = v & (SAEV_config.chipset.mask == SAEC_Config_Chipset_Mask_OCS ? 7 : 31); //OWN + maybe_blit(hpos, 0); + if (SAEV_Blitter_bltstate != SAEC_Blitter_bltstate_DONE && SAEV_config.chipset.blitter.cycle_exact) { + bltptx = ((bltdpt & 0xffff) | (v << 16)) >>> 0; + bltptxpos = hpos; + bltptxc = 4; + } else { + bltdpt = ((bltdpt & 0xffff) | (v << 16)) >>> 0; + } + } + this.BLTDPTL = function(hpos, v) { + maybe_blit(hpos, 0); + if (SAEV_Blitter_bltstate != SAEC_Blitter_bltstate_DONE && SAEV_config.chipset.blitter.cycle_exact) { + bltptx = ((bltdpt & 0xffff0000) | (v & 0xfffe)) >>> 0; + bltptxpos = hpos; + bltptxc = 4; + } else { + bltdpt = ((bltdpt & 0xffff0000) | (v & 0xfffe)) >>> 0; + } + } - this.BLTSIZE = function (hpos, v) { - this.maybe_blit(hpos, 0); + this.BLTSIZE = function(hpos, v) { + maybe_blit(hpos, 0); blt_info.vblitsize = v >> 6; blt_info.hblitsize = v & 0x3F; @@ -2800,38 +1773,2122 @@ function Blitter() { blt_info.vblitsize = 1024; if (!blt_info.hblitsize) blt_info.hblitsize = 64; + do_blitter(hpos, SAEV_Copper_access); + SAER.playfield.dcheck_is_blit_dangerous(); + } - do_blitter(hpos, AMIGA.copper.access); - }; - - this.BLTSIZV = function (hpos, v) { - if (!(AMIGA.config.chipset.mask & CSMASK_ECS_AGNUS)) return; - this.maybe_blit(hpos, 0); + this.BLTSIZV = function(hpos, v) { + //if (!(SAEV_config.chipset.mask & SAEC_Config_Chipset_Mask_ECS_AGNUS)) return; + maybe_blit(hpos, 0); blt_info.vblitsize = v & 0x7FFF; - }; + } - this.BLTSIZH = function (hpos, v) { - if (!(AMIGA.config.chipset.mask & CSMASK_ECS_AGNUS)) return; - this.maybe_blit(hpos, 0); + this.BLTSIZH = function(hpos, v) { + //if (!(SAEV_config.chipset.mask & SAEC_Config_Chipset_Mask_ECS_AGNUS)) return; + maybe_blit(hpos, 0); blt_info.hblitsize = v & 0x7FF; if (!blt_info.vblitsize) blt_info.vblitsize = 0x8000; if (!blt_info.hblitsize) blt_info.hblitsize = 0x0800; + do_blitter(hpos, SAEV_Copper_access); + } - do_blitter(hpos, AMIGA.copper.access); - }; - - /*---------------------------------*/ + /*-----------------------------------------------------------------------*/ - this.getState = function () { - return bltstate; - }; - this.setState = function (s) { - bltstate = s; - }; - this.getIntZero = function() { - return [blit_interrupt, blt_info.blitzero]; + function build_blitfilltable() { + const BLITTER_MAX_WORDS = 2048; + + if (blit_masktable !== null) return; + + blit_masktable = new Uint32Array(BLITTER_MAX_WORDS); + for (var i = 0; i < blit_masktable.length; i++) + blit_masktable[i] = 0xFFFF; + + blit_filltable = new Array(256); + for (var d = 0; d < 256; d++) { + blit_filltable[d] = new Array(4); + for (var i = 0; i < 4; i++) { + var fc = i & 1; + var data = d; //u8 + blit_filltable[d][i] = new Uint8Array(2); + for (var fillmask = 1; fillmask != 0x100; fillmask <<= 1) { + var tmp = data; //u16 + if (fc) { + if (i & 2) + data |= fillmask; + else + data ^= fillmask; + } + if (tmp & fillmask) fc = !fc; + } + blit_filltable[d][i][0] = data; + blit_filltable[d][i][1] = fc; + } + } + } + + function build_blitfunctable() { + if (blit_func_tab !== null) return; + + var i = 0; + blit_func_tab = new Array(256); + blit_func_tab[i++] = function(a, b, c) { return 0; }; + blit_func_tab[i++] = function(a, b, c) { return (~c & ~b & ~a); }; + blit_func_tab[i++] = function(a, b, c) { return (c & ~b & ~a); }; + blit_func_tab[i++] = function(a, b, c) { return (~b & ~a); }; + blit_func_tab[i++] = function(a, b, c) { return (~c & b & ~a); }; + blit_func_tab[i++] = function(a, b, c) { return (~c & ~a); }; + blit_func_tab[i++] = function(a, b, c) { return (c & ~b & ~a) | (~c & b & ~a); }; + blit_func_tab[i++] = function(a, b, c) { return (~b & ~a) | (~c & ~a); }; + blit_func_tab[i++] = function(a, b, c) { return (c & b & ~a); }; + blit_func_tab[i++] = function(a, b, c) { return (~c & ~b & ~a) | (c & b & ~a); }; + blit_func_tab[i++] = function(a, b, c) { return (c & ~a); }; + blit_func_tab[i++] = function(a, b, c) { return (~b & ~a) | (c & ~a); }; + blit_func_tab[i++] = function(a, b, c) { return (b & ~a); }; + blit_func_tab[i++] = function(a, b, c) { return (~c & ~a) | (b & ~a); }; + blit_func_tab[i++] = function(a, b, c) { return (c & ~a) | (b & ~a); }; + blit_func_tab[i++] = function(a, b, c) { return (~a); }; + blit_func_tab[i++] = function(a, b, c) { return (~c & ~b & a); }; + blit_func_tab[i++] = function(a, b, c) { return (~c & ~b); }; + blit_func_tab[i++] = function(a, b, c) { return (c & ~b & ~a) | (~c & ~b & a); }; + blit_func_tab[i++] = function(a, b, c) { return (~b & ~a) | (~c & ~b); }; + blit_func_tab[i++] = function(a, b, c) { return (~c & b & ~a) | (~c & ~b & a); }; + blit_func_tab[i++] = function(a, b, c) { return (~c & ~a) | (~c & ~b); }; + blit_func_tab[i++] = function(a, b, c) { return (c & ~b & ~a) | (~c & b & ~a) | (~c & ~b & a); }; + blit_func_tab[i++] = function(a, b, c) { return (~b & ~a) | (~c & ~a) | (~c & ~b); }; + blit_func_tab[i++] = function(a, b, c) { return (c & b & ~a) | (~c & ~b & a); }; + blit_func_tab[i++] = function(a, b, c) { return (~c & ~b) | (c & b & ~a); }; + blit_func_tab[i++] = function(a, b, c) { return (c & ~a) | (~c & ~b & a); }; + blit_func_tab[i++] = function(a, b, c) { return (~b & ~a) | (c & ~a) | (~c & ~b); }; + blit_func_tab[i++] = function(a, b, c) { return (b & ~a) | (~c & ~b & a); }; + blit_func_tab[i++] = function(a, b, c) { return (~c & ~a) | (b & ~a) | (~c & ~b); }; + blit_func_tab[i++] = function(a, b, c) { return (c & ~a) | (b & ~a) | (~c & ~b & a); }; + blit_func_tab[i++] = function(a, b, c) { return (~a) | (~c & ~b); }; + blit_func_tab[i++] = function(a, b, c) { return (c & ~b & a); }; + blit_func_tab[i++] = function(a, b, c) { return (~c & ~b & ~a) | (c & ~b & a); }; + blit_func_tab[i++] = function(a, b, c) { return (c & ~b); }; + blit_func_tab[i++] = function(a, b, c) { return (~b & ~a) | (c & ~b); }; + blit_func_tab[i++] = function(a, b, c) { return (~c & b & ~a) | (c & ~b & a); }; + blit_func_tab[i++] = function(a, b, c) { return (~c & ~a) | (c & ~b & a); }; + blit_func_tab[i++] = function(a, b, c) { return (c & ~b) | (~c & b & ~a); }; + blit_func_tab[i++] = function(a, b, c) { return (~b & ~a) | (~c & ~a) | (c & ~b); }; + blit_func_tab[i++] = function(a, b, c) { return (c & b & ~a) | (c & ~b & a); }; + blit_func_tab[i++] = function(a, b, c) { return (~c & ~b & ~a) | (c & b & ~a) | (c & ~b & a); }; + blit_func_tab[i++] = function(a, b, c) { return (c & ~a) | (c & ~b); }; + blit_func_tab[i++] = function(a, b, c) { return (~b & ~a) | (c & ~a) | (c & ~b); }; + blit_func_tab[i++] = function(a, b, c) { return (b & ~a) | (c & ~b & a); }; + blit_func_tab[i++] = function(a, b, c) { return (~c & ~a) | (b & ~a) | (c & ~b & a); }; + blit_func_tab[i++] = function(a, b, c) { return (c & ~a) | (b & ~a) | (c & ~b); }; + blit_func_tab[i++] = function(a, b, c) { return (~a) | (c & ~b); }; + blit_func_tab[i++] = function(a, b, c) { return (~b & a); }; + blit_func_tab[i++] = function(a, b, c) { return (~c & ~b) | (~b & a); }; + blit_func_tab[i++] = function(a, b, c) { return (c & ~b) | (~b & a); }; + blit_func_tab[i++] = function(a, b, c) { return (~b); }; + blit_func_tab[i++] = function(a, b, c) { return (~c & b & ~a) | (~b & a); }; + blit_func_tab[i++] = function(a, b, c) { return (~c & ~a) | (~b & a); }; + blit_func_tab[i++] = function(a, b, c) { return (c & ~b) | (~c & b & ~a) | (~b & a); }; + blit_func_tab[i++] = function(a, b, c) { return (~b) | (~c & ~a); }; + blit_func_tab[i++] = function(a, b, c) { return (c & b & ~a) | (~b & a); }; + blit_func_tab[i++] = function(a, b, c) { return (~c & ~b) | (c & b & ~a) | (~b & a); }; + blit_func_tab[i++] = function(a, b, c) { return (c & ~a) | (~b & a); }; + blit_func_tab[i++] = function(a, b, c) { return (~b) | (c & ~a); }; + blit_func_tab[i++] = function(a, b, c) { return (b & ~a) | (~b & a); }; + blit_func_tab[i++] = function(a, b, c) { return (~c & ~a) | (b & ~a) | (~b & a); }; + blit_func_tab[i++] = function(a, b, c) { return (c & ~a) | (b & ~a) | (~b & a); }; + blit_func_tab[i++] = function(a, b, c) { return (~a) | (~b); }; + blit_func_tab[i++] = function(a, b, c) { return (~c & b & a); }; + blit_func_tab[i++] = function(a, b, c) { return (~c & ~b & ~a) | (~c & b & a); }; + blit_func_tab[i++] = function(a, b, c) { return (c & ~b & ~a) | (~c & b & a); }; + blit_func_tab[i++] = function(a, b, c) { return (~b & ~a) | (~c & b & a); }; + blit_func_tab[i++] = function(a, b, c) { return (~c & b); }; + blit_func_tab[i++] = function(a, b, c) { return (~c & ~a) | (~c & b); }; + blit_func_tab[i++] = function(a, b, c) { return (c & ~b & ~a) | (~c & b); }; + blit_func_tab[i++] = function(a, b, c) { return (~b & ~a) | (~c & ~a) | (~c & b); }; + blit_func_tab[i++] = function(a, b, c) { return (c & b & ~a) | (~c & b & a); }; + blit_func_tab[i++] = function(a, b, c) { return (~c & ~b & ~a) | (c & b & ~a) | (~c & b & a); }; + blit_func_tab[i++] = function(a, b, c) { return (c & ~a) | (~c & b & a); }; + blit_func_tab[i++] = function(a, b, c) { return (~b & ~a) | (c & ~a) | (~c & b & a); }; + blit_func_tab[i++] = function(a, b, c) { return (b & ~a) | (~c & b); }; + blit_func_tab[i++] = function(a, b, c) { return (~c & ~a) | (b & ~a) | (~c & b); }; + blit_func_tab[i++] = function(a, b, c) { return (c & ~a) | (b & ~a) | (~c & b); }; + blit_func_tab[i++] = function(a, b, c) { return (~a) | (~c & b); }; + blit_func_tab[i++] = function(a, b, c) { return (~c & a); }; + blit_func_tab[i++] = function(a, b, c) { return (~c & ~b) | (~c & a); }; + blit_func_tab[i++] = function(a, b, c) { return (c & ~b & ~a) | (~c & a); }; + blit_func_tab[i++] = function(a, b, c) { return (~b & ~a) | (~c & a); }; + blit_func_tab[i++] = function(a, b, c) { return (~c & b) | (~c & a); }; + blit_func_tab[i++] = function(a, b, c) { return (~c); }; + blit_func_tab[i++] = function(a, b, c) { return (c & ~b & ~a) | (~c & b) | (~c & a); }; + blit_func_tab[i++] = function(a, b, c) { return (~b & ~a) | (~c); }; + blit_func_tab[i++] = function(a, b, c) { return (c & b & ~a) | (~c & a); }; + blit_func_tab[i++] = function(a, b, c) { return (~c & ~b) | (c & b & ~a) | (~c & a); }; + blit_func_tab[i++] = function(a, b, c) { return (c & ~a) | (~c & a); }; + blit_func_tab[i++] = function(a, b, c) { return (~b & ~a) | (c & ~a) | (~c & a); }; + blit_func_tab[i++] = function(a, b, c) { return (b & ~a) | (~c & a); }; + blit_func_tab[i++] = function(a, b, c) { return (~c) | (b & ~a); }; + blit_func_tab[i++] = function(a, b, c) { return (c & ~a) | (b & ~a) | (~c & a); }; + blit_func_tab[i++] = function(a, b, c) { return (~a) | (~c); }; + blit_func_tab[i++] = function(a, b, c) { return (c & ~b & a) | (~c & b & a); }; + blit_func_tab[i++] = function(a, b, c) { return (~c & ~b & ~a) | (c & ~b & a) | (~c & b & a); }; + blit_func_tab[i++] = function(a, b, c) { return (c & ~b) | (~c & b & a); }; + blit_func_tab[i++] = function(a, b, c) { return (~b & ~a) | (c & ~b) | (~c & b & a); }; + blit_func_tab[i++] = function(a, b, c) { return (~c & b) | (c & ~b & a); }; + blit_func_tab[i++] = function(a, b, c) { return (~c & ~a) | (c & ~b & a) | (~c & b); }; + blit_func_tab[i++] = function(a, b, c) { return (c & ~b) | (~c & b); }; + blit_func_tab[i++] = function(a, b, c) { return (~b & ~a) | (~c & ~a) | (c & ~b) | (~c & b); }; + blit_func_tab[i++] = function(a, b, c) { return (c & b & ~a) | (c & ~b & a) | (~c & b & a); }; + blit_func_tab[i++] = function(a, b, c) { return (~c & ~b & ~a) | (c & b & ~a) | (c & ~b & a) | (~c & b & a); }; + blit_func_tab[i++] = function(a, b, c) { return (c & ~a) | (c & ~b) | (~c & b & a); }; + blit_func_tab[i++] = function(a, b, c) { return (~b & ~a) | (c & ~a) | (c & ~b) | (~c & b & a); }; + blit_func_tab[i++] = function(a, b, c) { return (b & ~a) | (c & ~b & a) | (~c & b); }; + blit_func_tab[i++] = function(a, b, c) { return (~c & ~a) | (b & ~a) | (c & ~b & a) | (~c & b); }; + blit_func_tab[i++] = function(a, b, c) { return (c & ~a) | (b & ~a) | (c & ~b) | (~c & b); }; + blit_func_tab[i++] = function(a, b, c) { return (~a) | (c & ~b) | (~c & b); }; + blit_func_tab[i++] = function(a, b, c) { return (~b & a) | (~c & a); }; + blit_func_tab[i++] = function(a, b, c) { return (~c & ~b) | (~b & a) | (~c & a); }; + blit_func_tab[i++] = function(a, b, c) { return (c & ~b) | (~b & a) | (~c & a); }; + blit_func_tab[i++] = function(a, b, c) { return (~b) | (~c & a); }; + blit_func_tab[i++] = function(a, b, c) { return (~c & b) | (~b & a); }; + blit_func_tab[i++] = function(a, b, c) { return (~c) | (~b & a); }; + blit_func_tab[i++] = function(a, b, c) { return (c & ~b) | (~c & b) | (~b & a); }; + blit_func_tab[i++] = function(a, b, c) { return (~b) | (~c); }; + blit_func_tab[i++] = function(a, b, c) { return (c & b & ~a) | (~b & a) | (~c & a); }; + blit_func_tab[i++] = function(a, b, c) { return (~c & ~b) | (c & b & ~a) | (~b & a) | (~c & a); }; + blit_func_tab[i++] = function(a, b, c) { return (c & ~a) | (~b & a) | (~c & a); }; + blit_func_tab[i++] = function(a, b, c) { return (~b) | (c & ~a) | (~c & a); }; + blit_func_tab[i++] = function(a, b, c) { return (b & ~a) | (~b & a) | (~c & a); }; + blit_func_tab[i++] = function(a, b, c) { return (~c) | (b & ~a) | (~b & a); }; + blit_func_tab[i++] = function(a, b, c) { return (c & ~a) | (b & ~a) | (~b & a) | (~c & a); }; + blit_func_tab[i++] = function(a, b, c) { return (~a) | (~b) | (~c); }; + blit_func_tab[i++] = function(a, b, c) { return (c & b & a); }; + blit_func_tab[i++] = function(a, b, c) { return (~c & ~b & ~a) | (c & b & a); }; + blit_func_tab[i++] = function(a, b, c) { return (c & ~b & ~a) | (c & b & a); }; + blit_func_tab[i++] = function(a, b, c) { return (~b & ~a) | (c & b & a); }; + blit_func_tab[i++] = function(a, b, c) { return (~c & b & ~a) | (c & b & a); }; + blit_func_tab[i++] = function(a, b, c) { return (~c & ~a) | (c & b & a); }; + blit_func_tab[i++] = function(a, b, c) { return (c & ~b & ~a) | (~c & b & ~a) | (c & b & a); }; + blit_func_tab[i++] = function(a, b, c) { return (~b & ~a) | (~c & ~a) | (c & b & a); }; + blit_func_tab[i++] = function(a, b, c) { return (c & b); }; + blit_func_tab[i++] = function(a, b, c) { return (~c & ~b & ~a) | (c & b); }; + blit_func_tab[i++] = function(a, b, c) { return (c & ~a) | (c & b); }; + blit_func_tab[i++] = function(a, b, c) { return (~b & ~a) | (c & ~a) | (c & b); }; + blit_func_tab[i++] = function(a, b, c) { return (b & ~a) | (c & b); }; + blit_func_tab[i++] = function(a, b, c) { return (~c & ~a) | (b & ~a) | (c & b); }; + blit_func_tab[i++] = function(a, b, c) { return (c & ~a) | (b & ~a) | (c & b); }; + blit_func_tab[i++] = function(a, b, c) { return (~a) | (c & b); }; + blit_func_tab[i++] = function(a, b, c) { return (~c & ~b & a) | (c & b & a); }; + blit_func_tab[i++] = function(a, b, c) { return (~c & ~b) | (c & b & a); }; + blit_func_tab[i++] = function(a, b, c) { return (c & ~b & ~a) | (~c & ~b & a) | (c & b & a); }; + blit_func_tab[i++] = function(a, b, c) { return (~b & ~a) | (~c & ~b) | (c & b & a); }; + blit_func_tab[i++] = function(a, b, c) { return (~c & b & ~a) | (~c & ~b & a) | (c & b & a); }; + blit_func_tab[i++] = function(a, b, c) { return (~c & ~a) | (~c & ~b) | (c & b & a); }; + blit_func_tab[i++] = function(a, b, c) { return (c & ~b & ~a) | (~c & b & ~a) | (~c & ~b & a) | (c & b & a); }; + blit_func_tab[i++] = function(a, b, c) { return (~b & ~a) | (~c & ~a) | (~c & ~b) | (c & b & a); }; + blit_func_tab[i++] = function(a, b, c) { return (c & b) | (~c & ~b & a); }; + blit_func_tab[i++] = function(a, b, c) { return (~c & ~b) | (c & b); }; + blit_func_tab[i++] = function(a, b, c) { return (c & ~a) | (~c & ~b & a) | (c & b); }; + blit_func_tab[i++] = function(a, b, c) { return (~b & ~a) | (c & ~a) | (~c & ~b) | (c & b); }; + blit_func_tab[i++] = function(a, b, c) { return (b & ~a) | (~c & ~b & a) | (c & b); }; + blit_func_tab[i++] = function(a, b, c) { return (~c & ~a) | (b & ~a) | (~c & ~b) | (c & b); }; + blit_func_tab[i++] = function(a, b, c) { return (c & ~a) | (b & ~a) | (~c & ~b & a) | (c & b); }; + blit_func_tab[i++] = function(a, b, c) { return (~a) | (~c & ~b) | (c & b); }; + blit_func_tab[i++] = function(a, b, c) { return (c & a); }; + blit_func_tab[i++] = function(a, b, c) { return (~c & ~b & ~a) | (c & a); }; + blit_func_tab[i++] = function(a, b, c) { return (c & ~b) | (c & a); }; + blit_func_tab[i++] = function(a, b, c) { return (~b & ~a) | (c & a); }; + blit_func_tab[i++] = function(a, b, c) { return (~c & b & ~a) | (c & a); }; + blit_func_tab[i++] = function(a, b, c) { return (~c & ~a) | (c & a); }; + blit_func_tab[i++] = function(a, b, c) { return (c & ~b) | (~c & b & ~a) | (c & a); }; + blit_func_tab[i++] = function(a, b, c) { return (~b & ~a) | (~c & ~a) | (c & a); }; + blit_func_tab[i++] = function(a, b, c) { return (c & b) | (c & a); }; + blit_func_tab[i++] = function(a, b, c) { return (~c & ~b & ~a) | (c & b) | (c & a); }; + blit_func_tab[i++] = function(a, b, c) { return (c); }; + blit_func_tab[i++] = function(a, b, c) { return (~b & ~a) | (c); }; + blit_func_tab[i++] = function(a, b, c) { return (b & ~a) | (c & a); }; + blit_func_tab[i++] = function(a, b, c) { return (~c & ~a) | (b & ~a) | (c & a); }; + blit_func_tab[i++] = function(a, b, c) { return (c) | (b & ~a); }; + blit_func_tab[i++] = function(a, b, c) { return (~a) | (c); }; + blit_func_tab[i++] = function(a, b, c) { return (~b & a) | (c & a); }; + blit_func_tab[i++] = function(a, b, c) { return (~c & ~b) | (~b & a) | (c & a); }; + blit_func_tab[i++] = function(a, b, c) { return (c & ~b) | (~b & a) | (c & a); }; + blit_func_tab[i++] = function(a, b, c) { return (~b) | (c & a); }; + blit_func_tab[i++] = function(a, b, c) { return (~c & b & ~a) | (~b & a) | (c & a); }; + blit_func_tab[i++] = function(a, b, c) { return (~c & ~a) | (~b & a) | (c & a); }; + blit_func_tab[i++] = function(a, b, c) { return (c & ~b) | (~c & b & ~a) | (~b & a) | (c & a); }; + blit_func_tab[i++] = function(a, b, c) { return (~b) | (~c & ~a) | (c & a); }; + blit_func_tab[i++] = function(a, b, c) { return (c & b) | (~b & a); }; + blit_func_tab[i++] = function(a, b, c) { return (~c & ~b) | (c & b) | (~b & a); }; + blit_func_tab[i++] = function(a, b, c) { return (c) | (~b & a); }; + blit_func_tab[i++] = function(a, b, c) { return (~b) | (c); }; + blit_func_tab[i++] = function(a, b, c) { return (b & ~a) | (~b & a) | (c & a); }; + blit_func_tab[i++] = function(a, b, c) { return (~c & ~a) | (b & ~a) | (~b & a) | (c & a); }; + blit_func_tab[i++] = function(a, b, c) { return (c) | (b & ~a) | (~b & a); }; + blit_func_tab[i++] = function(a, b, c) { return (~a) | (~b) | (c); }; + blit_func_tab[i++] = function(a, b, c) { return (b & a); }; + blit_func_tab[i++] = function(a, b, c) { return (~c & ~b & ~a) | (b & a); }; + blit_func_tab[i++] = function(a, b, c) { return (c & ~b & ~a) | (b & a); }; + blit_func_tab[i++] = function(a, b, c) { return (~b & ~a) | (b & a); }; + blit_func_tab[i++] = function(a, b, c) { return (~c & b) | (b & a); }; + blit_func_tab[i++] = function(a, b, c) { return (~c & ~a) | (b & a); }; + blit_func_tab[i++] = function(a, b, c) { return (c & ~b & ~a) | (~c & b) | (b & a); }; + blit_func_tab[i++] = function(a, b, c) { return (~b & ~a) | (~c & ~a) | (b & a); }; + blit_func_tab[i++] = function(a, b, c) { return (c & b) | (b & a); }; + blit_func_tab[i++] = function(a, b, c) { return (~c & ~b & ~a) | (c & b) | (b & a); }; + blit_func_tab[i++] = function(a, b, c) { return (c & ~a) | (b & a); }; + blit_func_tab[i++] = function(a, b, c) { return (~b & ~a) | (c & ~a) | (b & a); }; + blit_func_tab[i++] = function(a, b, c) { return (b); }; + blit_func_tab[i++] = function(a, b, c) { return (~c & ~a) | (b); }; + blit_func_tab[i++] = function(a, b, c) { return (c & ~a) | (b); }; + blit_func_tab[i++] = function(a, b, c) { return (~a) | (b); }; + blit_func_tab[i++] = function(a, b, c) { return (~c & a) | (b & a); }; + blit_func_tab[i++] = function(a, b, c) { return (~c & ~b) | (b & a); }; + blit_func_tab[i++] = function(a, b, c) { return (c & ~b & ~a) | (~c & a) | (b & a); }; + blit_func_tab[i++] = function(a, b, c) { return (~b & ~a) | (~c & a) | (b & a); }; + blit_func_tab[i++] = function(a, b, c) { return (~c & b) | (~c & a) | (b & a); }; + blit_func_tab[i++] = function(a, b, c) { return (~c) | (b & a); }; + blit_func_tab[i++] = function(a, b, c) { return (c & ~b & ~a) | (~c & b) | (~c & a) | (b & a); }; + blit_func_tab[i++] = function(a, b, c) { return (~b & ~a) | (~c) | (b & a); }; + blit_func_tab[i++] = function(a, b, c) { return (c & b) | (~c & a); }; + blit_func_tab[i++] = function(a, b, c) { return (~c & ~b) | (c & b) | (b & a); }; + blit_func_tab[i++] = function(a, b, c) { return (c & ~a) | (~c & a) | (b & a); }; + blit_func_tab[i++] = function(a, b, c) { return (~b & ~a) | (c & ~a) | (~c & a) | (b & a); }; + blit_func_tab[i++] = function(a, b, c) { return (b) | (~c & a); }; + blit_func_tab[i++] = function(a, b, c) { return (~c) | (b); }; + blit_func_tab[i++] = function(a, b, c) { return (c & ~a) | (b) | (~c & a); }; + blit_func_tab[i++] = function(a, b, c) { return (~a) | (~c) | (b); }; + blit_func_tab[i++] = function(a, b, c) { return (c & a) | (b & a); }; + blit_func_tab[i++] = function(a, b, c) { return (~c & ~b & ~a) | (c & a) | (b & a); }; + blit_func_tab[i++] = function(a, b, c) { return (c & ~b) | (b & a); }; + blit_func_tab[i++] = function(a, b, c) { return (~b & ~a) | (c & a) | (b & a); }; + blit_func_tab[i++] = function(a, b, c) { return (~c & b) | (c & a); }; + blit_func_tab[i++] = function(a, b, c) { return (~c & ~a) | (c & a) | (b & a); }; + blit_func_tab[i++] = function(a, b, c) { return (c & ~b) | (~c & b) | (b & a); }; + blit_func_tab[i++] = function(a, b, c) { return (~b & ~a) | (~c & ~a) | (c & a) | (b & a); }; + blit_func_tab[i++] = function(a, b, c) { return (c & b) | (c & a) | (b & a); }; + blit_func_tab[i++] = function(a, b, c) { return (~c & ~b & ~a) | (c & b) | (c & a) | (b & a); }; + blit_func_tab[i++] = function(a, b, c) { return (c) | (b & a); }; + blit_func_tab[i++] = function(a, b, c) { return (~b & ~a) | (c) | (b & a); }; + blit_func_tab[i++] = function(a, b, c) { return (b) | (c & a); }; + blit_func_tab[i++] = function(a, b, c) { return (~c & ~a) | (b) | (c & a); }; + blit_func_tab[i++] = function(a, b, c) { return (c) | (b); }; + blit_func_tab[i++] = function(a, b, c) { return (~a) | (c) | (b); }; + blit_func_tab[i++] = function(a, b, c) { return (a); }; + blit_func_tab[i++] = function(a, b, c) { return (~c & ~b) | (a); }; + blit_func_tab[i++] = function(a, b, c) { return (c & ~b) | (a); }; + blit_func_tab[i++] = function(a, b, c) { return (~b) | (a); }; + blit_func_tab[i++] = function(a, b, c) { return (~c & b) | (a); }; + blit_func_tab[i++] = function(a, b, c) { return (~c) | (a); }; + blit_func_tab[i++] = function(a, b, c) { return (c & ~b) | (~c & b) | (a); }; + blit_func_tab[i++] = function(a, b, c) { return (~b) | (~c) | (a); }; + blit_func_tab[i++] = function(a, b, c) { return (c & b) | (a); }; + blit_func_tab[i++] = function(a, b, c) { return (~c & ~b) | (c & b) | (a); }; + blit_func_tab[i++] = function(a, b, c) { return (c) | (a); }; + blit_func_tab[i++] = function(a, b, c) { return (~b) | (c) | (a); }; + blit_func_tab[i++] = function(a, b, c) { return (b) | (a); }; + blit_func_tab[i++] = function(a, b, c) { return (~c) | (b) | (a); }; + blit_func_tab[i++] = function(a, b, c) { return (c) | (b) | (a); }; + blit_func_tab[i ] = function(a, b, c) { return 0xffff; }; + } + + /*-----------------------------------------------------------------------*/ + /* auto-generated speedup-functions */ + + const blitfunc_dofast = [ + blitdofast_0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, blitdofast_a, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, blitdofast_2a, 0, 0, 0, 0, 0, + blitdofast_30, 0, 0, 0, 0, 0, 0, 0, + 0, 0, blitdofast_3a, 0, blitdofast_3c, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, blitdofast_4a, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, blitdofast_6a, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, blitdofast_8a, 0, blitdofast_8c, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, blitdofast_9a, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + blitdofast_a8, 0, blitdofast_aa, 0, 0, 0, 0, 0, + 0, blitdofast_b1, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, blitdofast_ca, 0, blitdofast_cc, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + blitdofast_d8, 0, 0, 0, 0, 0, 0, 0, + 0, 0, blitdofast_e2, 0, 0, 0, 0, 0, + 0, 0, blitdofast_ea, 0, 0, 0, 0, 0, + blitdofast_f0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, blitdofast_fa, 0, blitdofast_fc, 0, 0, 0 + ]; + + const blitfunc_dofast_desc = [ + blitdofast_desc_0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, blitdofast_desc_a, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, blitdofast_desc_2a, 0, 0, 0, 0, 0, + blitdofast_desc_30, 0, 0, 0, 0, 0, 0, 0, + 0, 0, blitdofast_desc_3a, 0, blitdofast_desc_3c, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, blitdofast_desc_4a, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, blitdofast_desc_6a, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, blitdofast_desc_8a, 0, blitdofast_desc_8c, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, blitdofast_desc_9a, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + blitdofast_desc_a8, 0, blitdofast_desc_aa, 0, 0, 0, 0, 0, + 0, blitdofast_desc_b1, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, blitdofast_desc_ca, 0, blitdofast_desc_cc, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + blitdofast_desc_d8, 0, 0, 0, 0, 0, 0, 0, + 0, 0, blitdofast_desc_e2, 0, 0, 0, 0, 0, + 0, 0, blitdofast_desc_ea, 0, 0, 0, 0, 0, + blitdofast_desc_f0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, blitdofast_desc_fa, 0, blitdofast_desc_fc, 0, 0, 0 + ]; + + function blitdofast_0(pta, ptb, ptc, ptd, b) { + var i,j; + var totald = 0; + var dstd = 0; + var dstp = 0; + for (j = 0; j < b.vblitsize; j++) { + for (i = 0; i < b.hblitsize; i++) { + var bltadat, srca; + if (dstp) { + SAER_Memory_chipData[dstp] = dstd >> 8; + SAER_Memory_chipData[dstp + 1] = dstd & 0xff; + } + dstd = 0 & 0xffff; + totald |= dstd; + if (ptd) { dstp = ptd; ptd += 2; } + } + if (ptd) ptd += b.bltdmod; + } + if (dstp) { + SAER_Memory_chipData[dstp] = dstd >> 8; + SAER_Memory_chipData[dstp + 1] = dstd & 0xff; + } + if (totald != 0) b.blitzero = 0; + } + + function blitdofast_desc_0(pta, ptb, ptc, ptd, b) { + var totald = 0; + var i,j; + var dstd = 0; + var dstp = 0; + for (j = 0; j < b.vblitsize; j++) { + for (i = 0; i < b.hblitsize; i++) { + var bltadat, srca; + if (dstp) { + SAER_Memory_chipData[dstp] = dstd >> 8; + SAER_Memory_chipData[dstp + 1] = dstd & 0xff; + } + dstd = 0 & 0xffff; + totald |= dstd; + if (ptd) { dstp = ptd; ptd -= 2; } + } + if (ptd) ptd -= b.bltdmod; + } + if (dstp) { + SAER_Memory_chipData[dstp] = dstd >> 8; + SAER_Memory_chipData[dstp + 1] = dstd & 0xff; + } + if (totald != 0) b.blitzero = 0; + } + + function blitdofast_a(pta, ptb, ptc, ptd, b) { + var i,j; + var totald = 0; + var preva = 0; + var srcc = b.bltcdat; + var dstd = 0; + var dstp = 0; + for (j = 0; j < b.vblitsize; j++) { + for (i = 0; i < b.hblitsize; i++) { + var bltadat, srca; + if (ptc) { srcc = (SAER_Memory_chipData[ptc] << 8) | SAER_Memory_chipData[ptc + 1]; ptc += 2; } + if (pta) { bltadat = blt_info.bltadat = (SAER_Memory_chipData[pta] << 8) | SAER_Memory_chipData[pta + 1]; pta += 2; } else { bltadat = blt_info.bltadat; } + bltadat &= blit_masktable[i]; + srca = (((preva << 16) | bltadat) >>> 0) >>> b.blitashift; + preva = bltadat; + if (dstp) { + SAER_Memory_chipData[dstp] = dstd >> 8; + SAER_Memory_chipData[dstp + 1] = dstd & 0xff; + } + dstd = (~srca & srcc) & 0xffff; + totald |= dstd; + if (ptd) { dstp = ptd; ptd += 2; } + } + if (pta) pta += b.bltamod; + if (ptc) ptc += b.bltcmod; + if (ptd) ptd += b.bltdmod; + } + b.bltcdat = srcc; + if (dstp) { + SAER_Memory_chipData[dstp] = dstd >> 8; + SAER_Memory_chipData[dstp + 1] = dstd & 0xff; + } + if (totald != 0) b.blitzero = 0; + } + + function blitdofast_desc_a(pta, ptb, ptc, ptd, b) { + var totald = 0; + var i,j; + var preva = 0; + var srcc = b.bltcdat; + var dstd = 0; + var dstp = 0; + for (j = 0; j < b.vblitsize; j++) { + for (i = 0; i < b.hblitsize; i++) { + var bltadat, srca; + if (ptc) { srcc = (SAER_Memory_chipData[ptc] << 8) | SAER_Memory_chipData[ptc + 1]; ptc -= 2; } + if (pta) { bltadat = blt_info.bltadat = (SAER_Memory_chipData[pta] << 8) | SAER_Memory_chipData[pta + 1]; pta -= 2; } else { bltadat = blt_info.bltadat; } + bltadat &= blit_masktable[i]; + srca = (((bltadat << 16) | preva) >>> 0) >>> b.blitdownashift; + preva = bltadat; + if (dstp) { + SAER_Memory_chipData[dstp] = dstd >> 8; + SAER_Memory_chipData[dstp + 1] = dstd & 0xff; + } + dstd = (~srca & srcc) & 0xffff; + totald |= dstd; + if (ptd) { dstp = ptd; ptd -= 2; } + } + if (pta) pta -= b.bltamod; + if (ptc) ptc -= b.bltcmod; + if (ptd) ptd -= b.bltdmod; + } + b.bltcdat = srcc; + if (dstp) { + SAER_Memory_chipData[dstp] = dstd >> 8; + SAER_Memory_chipData[dstp + 1] = dstd & 0xff; + } + if (totald != 0) b.blitzero = 0; + } + + function blitdofast_2a(pta, ptb, ptc, ptd, b) { + var i,j; + var totald = 0; + var preva = 0; + var prevb = 0, srcb = b.bltbhold; + var srcc = b.bltcdat; + var dstd = 0; + var dstp = 0; + for (j = 0; j < b.vblitsize; j++) { + for (i = 0; i < b.hblitsize; i++) { + var bltadat, srca; + if (ptc) { srcc = (SAER_Memory_chipData[ptc] << 8) | SAER_Memory_chipData[ptc + 1]; ptc += 2; } + if (ptb) { + var bltbdat = blt_info.bltbdat = (SAER_Memory_chipData[ptb] << 8) | SAER_Memory_chipData[ptb + 1]; ptb += 2; + srcb = (((prevb << 16) | bltbdat) >>> 0) >>> b.blitbshift; + prevb = bltbdat; + } + if (pta) { bltadat = blt_info.bltadat = (SAER_Memory_chipData[pta] << 8) | SAER_Memory_chipData[pta + 1]; pta += 2; } else { bltadat = blt_info.bltadat; } + bltadat &= blit_masktable[i]; + srca = (((preva << 16) | bltadat) >>> 0) >>> b.blitashift; + preva = bltadat; + if (dstp) { + SAER_Memory_chipData[dstp] = dstd >> 8; + SAER_Memory_chipData[dstp + 1] = dstd & 0xff; + } + dstd = (srcc & ~(srca & srcb)) & 0xffff; + totald |= dstd; + if (ptd) { dstp = ptd; ptd += 2; } + } + if (pta) pta += b.bltamod; + if (ptb) ptb += b.bltbmod; + if (ptc) ptc += b.bltcmod; + if (ptd) ptd += b.bltdmod; + } + b.bltbhold = srcb; + b.bltcdat = srcc; + if (dstp) { + SAER_Memory_chipData[dstp] = dstd >> 8; + SAER_Memory_chipData[dstp + 1] = dstd & 0xff; + } + if (totald != 0) b.blitzero = 0; + } + + function blitdofast_desc_2a(pta, ptb, ptc, ptd, b) { + var totald = 0; + var i,j; + var preva = 0; + var prevb = 0, srcb = b.bltbhold; + var srcc = b.bltcdat; + var dstd = 0; + var dstp = 0; + for (j = 0; j < b.vblitsize; j++) { + for (i = 0; i < b.hblitsize; i++) { + var bltadat, srca; + if (ptc) { srcc = (SAER_Memory_chipData[ptc] << 8) | SAER_Memory_chipData[ptc + 1]; ptc -= 2; } + if (ptb) { + var bltbdat = blt_info.bltbdat = (SAER_Memory_chipData[ptb] << 8) | SAER_Memory_chipData[ptb + 1]; ptb -= 2; + srcb = (((bltbdat << 16) | prevb) >>> 0) >>> b.blitdownbshift; + prevb = bltbdat; + } + if (pta) { bltadat = blt_info.bltadat = (SAER_Memory_chipData[pta] << 8) | SAER_Memory_chipData[pta + 1]; pta -= 2; } else { bltadat = blt_info.bltadat; } + bltadat &= blit_masktable[i]; + srca = (((bltadat << 16) | preva) >>> 0) >>> b.blitdownashift; + preva = bltadat; + if (dstp) { + SAER_Memory_chipData[dstp] = dstd >> 8; + SAER_Memory_chipData[dstp + 1] = dstd & 0xff; + } + dstd = (srcc & ~(srca & srcb)) & 0xffff; + totald |= dstd; + if (ptd) { dstp = ptd; ptd -= 2; } + } + if (pta) pta -= b.bltamod; + if (ptb) ptb -= b.bltbmod; + if (ptc) ptc -= b.bltcmod; + if (ptd) ptd -= b.bltdmod; + } + b.bltbhold = srcb; + b.bltcdat = srcc; + if (dstp) { + SAER_Memory_chipData[dstp] = dstd >> 8; + SAER_Memory_chipData[dstp + 1] = dstd & 0xff; + } + if (totald != 0) b.blitzero = 0; + } + + function blitdofast_30(pta, ptb, ptc, ptd, b) { + var i,j; + var totald = 0; + var preva = 0; + var prevb = 0, srcb = b.bltbhold; + var dstd = 0; + var dstp = 0; + for (j = 0; j < b.vblitsize; j++) { + for (i = 0; i < b.hblitsize; i++) { + var bltadat, srca; + if (ptb) { + var bltbdat = blt_info.bltbdat = (SAER_Memory_chipData[ptb] << 8) | SAER_Memory_chipData[ptb + 1]; ptb += 2; + srcb = (((prevb << 16) | bltbdat) >>> 0) >>> b.blitbshift; + prevb = bltbdat; + } + if (pta) { bltadat = blt_info.bltadat = (SAER_Memory_chipData[pta] << 8) | SAER_Memory_chipData[pta + 1]; pta += 2; } else { bltadat = blt_info.bltadat; } + bltadat &= blit_masktable[i]; + srca = (((preva << 16) | bltadat) >>> 0) >>> b.blitashift; + preva = bltadat; + if (dstp) { + SAER_Memory_chipData[dstp] = dstd >> 8; + SAER_Memory_chipData[dstp + 1] = dstd & 0xff; + } + dstd = (srca & ~srcb) & 0xffff; + totald |= dstd; + if (ptd) { dstp = ptd; ptd += 2; } + } + if (pta) pta += b.bltamod; + if (ptb) ptb += b.bltbmod; + if (ptd) ptd += b.bltdmod; + } + b.bltbhold = srcb; + if (dstp) { + SAER_Memory_chipData[dstp] = dstd >> 8; + SAER_Memory_chipData[dstp + 1] = dstd & 0xff; + } + if (totald != 0) b.blitzero = 0; + } + + function blitdofast_desc_30(pta, ptb, ptc, ptd, b) { + var totald = 0; + var i,j; + var preva = 0; + var prevb = 0, srcb = b.bltbhold; + var dstd = 0; + var dstp = 0; + for (j = 0; j < b.vblitsize; j++) { + for (i = 0; i < b.hblitsize; i++) { + var bltadat, srca; + if (ptb) { + var bltbdat = blt_info.bltbdat = (SAER_Memory_chipData[ptb] << 8) | SAER_Memory_chipData[ptb + 1]; ptb -= 2; + srcb = (((bltbdat << 16) | prevb) >>> 0) >>> b.blitdownbshift; + prevb = bltbdat; + } + if (pta) { bltadat = blt_info.bltadat = (SAER_Memory_chipData[pta] << 8) | SAER_Memory_chipData[pta + 1]; pta -= 2; } else { bltadat = blt_info.bltadat; } + bltadat &= blit_masktable[i]; + srca = (((bltadat << 16) | preva) >>> 0) >>> b.blitdownashift; + preva = bltadat; + if (dstp) { + SAER_Memory_chipData[dstp] = dstd >> 8; + SAER_Memory_chipData[dstp + 1] = dstd & 0xff; + } + dstd = (srca & ~srcb) & 0xffff; + totald |= dstd; + if (ptd) { dstp = ptd; ptd -= 2; } + } + if (pta) pta -= b.bltamod; + if (ptb) ptb -= b.bltbmod; + if (ptd) ptd -= b.bltdmod; + } + b.bltbhold = srcb; + if (dstp) { + SAER_Memory_chipData[dstp] = dstd >> 8; + SAER_Memory_chipData[dstp + 1] = dstd & 0xff; + } + if (totald != 0) b.blitzero = 0; + } + + function blitdofast_3a(pta, ptb, ptc, ptd, b) { + var i,j; + var totald = 0; + var preva = 0; + var prevb = 0, srcb = b.bltbhold; + var srcc = b.bltcdat; + var dstd = 0; + var dstp = 0; + for (j = 0; j < b.vblitsize; j++) { + for (i = 0; i < b.hblitsize; i++) { + var bltadat, srca; + if (ptc) { srcc = (SAER_Memory_chipData[ptc] << 8) | SAER_Memory_chipData[ptc + 1]; ptc += 2; } + if (ptb) { + var bltbdat = blt_info.bltbdat = (SAER_Memory_chipData[ptb] << 8) | SAER_Memory_chipData[ptb + 1]; ptb += 2; + srcb = (((prevb << 16) | bltbdat) >>> 0) >>> b.blitbshift; + prevb = bltbdat; + } + if (pta) { bltadat = blt_info.bltadat = (SAER_Memory_chipData[pta] << 8) | SAER_Memory_chipData[pta + 1]; pta += 2; } else { bltadat = blt_info.bltadat; } + bltadat &= blit_masktable[i]; + srca = (((preva << 16) | bltadat) >>> 0) >>> b.blitashift; + preva = bltadat; + if (dstp) { + SAER_Memory_chipData[dstp] = dstd >> 8; + SAER_Memory_chipData[dstp + 1] = dstd & 0xff; + } + dstd = (srcb ^ (srca | (srcb ^ srcc))) & 0xffff; + totald |= dstd; + if (ptd) { dstp = ptd; ptd += 2; } + } + if (pta) pta += b.bltamod; + if (ptb) ptb += b.bltbmod; + if (ptc) ptc += b.bltcmod; + if (ptd) ptd += b.bltdmod; + } + b.bltbhold = srcb; + b.bltcdat = srcc; + if (dstp) { + SAER_Memory_chipData[dstp] = dstd >> 8; + SAER_Memory_chipData[dstp + 1] = dstd & 0xff; + } + if (totald != 0) b.blitzero = 0; + } + + function blitdofast_desc_3a(pta, ptb, ptc, ptd, b) { + var totald = 0; + var i,j; + var preva = 0; + var prevb = 0, srcb = b.bltbhold; + var srcc = b.bltcdat; + var dstd = 0; + var dstp = 0; + for (j = 0; j < b.vblitsize; j++) { + for (i = 0; i < b.hblitsize; i++) { + var bltadat, srca; + if (ptc) { srcc = (SAER_Memory_chipData[ptc] << 8) | SAER_Memory_chipData[ptc + 1]; ptc -= 2; } + if (ptb) { + var bltbdat = blt_info.bltbdat = (SAER_Memory_chipData[ptb] << 8) | SAER_Memory_chipData[ptb + 1]; ptb -= 2; + srcb = (((bltbdat << 16) | prevb) >>> 0) >>> b.blitdownbshift; + prevb = bltbdat; + } + if (pta) { bltadat = blt_info.bltadat = (SAER_Memory_chipData[pta] << 8) | SAER_Memory_chipData[pta + 1]; pta -= 2; } else { bltadat = blt_info.bltadat; } + bltadat &= blit_masktable[i]; + srca = (((bltadat << 16) | preva) >>> 0) >>> b.blitdownashift; + preva = bltadat; + if (dstp) { + SAER_Memory_chipData[dstp] = dstd >> 8; + SAER_Memory_chipData[dstp + 1] = dstd & 0xff; + } + dstd = (srcb ^ (srca | (srcb ^ srcc))) & 0xffff; + totald |= dstd; + if (ptd) { dstp = ptd; ptd -= 2; } + } + if (pta) pta -= b.bltamod; + if (ptb) ptb -= b.bltbmod; + if (ptc) ptc -= b.bltcmod; + if (ptd) ptd -= b.bltdmod; + } + b.bltbhold = srcb; + b.bltcdat = srcc; + if (dstp) { + SAER_Memory_chipData[dstp] = dstd >> 8; + SAER_Memory_chipData[dstp + 1] = dstd & 0xff; + } + if (totald != 0) b.blitzero = 0; + } + + function blitdofast_3c(pta, ptb, ptc, ptd, b) { + var i,j; + var totald = 0; + var preva = 0; + var prevb = 0, srcb = b.bltbhold; + var dstd = 0; + var dstp = 0; + for (j = 0; j < b.vblitsize; j++) { + for (i = 0; i < b.hblitsize; i++) { + var bltadat, srca; + if (ptb) { + var bltbdat = blt_info.bltbdat = (SAER_Memory_chipData[ptb] << 8) | SAER_Memory_chipData[ptb + 1]; ptb += 2; + srcb = (((prevb << 16) | bltbdat) >>> 0) >>> b.blitbshift; + prevb = bltbdat; + } + if (pta) { bltadat = blt_info.bltadat = (SAER_Memory_chipData[pta] << 8) | SAER_Memory_chipData[pta + 1]; pta += 2; } else { bltadat = blt_info.bltadat; } + bltadat &= blit_masktable[i]; + srca = (((preva << 16) | bltadat) >>> 0) >>> b.blitashift; + preva = bltadat; + if (dstp) { + SAER_Memory_chipData[dstp] = dstd >> 8; + SAER_Memory_chipData[dstp + 1] = dstd & 0xff; + } + dstd = (srca ^ srcb) & 0xffff; + totald |= dstd; + if (ptd) { dstp = ptd; ptd += 2; } + } + if (pta) pta += b.bltamod; + if (ptb) ptb += b.bltbmod; + if (ptd) ptd += b.bltdmod; + } + b.bltbhold = srcb; + if (dstp) { + SAER_Memory_chipData[dstp] = dstd >> 8; + SAER_Memory_chipData[dstp + 1] = dstd & 0xff; + } + if (totald != 0) b.blitzero = 0; + } + + function blitdofast_desc_3c(pta, ptb, ptc, ptd, b) { + var totald = 0; + var i,j; + var preva = 0; + var prevb = 0, srcb = b.bltbhold; + var dstd = 0; + var dstp = 0; + for (j = 0; j < b.vblitsize; j++) { + for (i = 0; i < b.hblitsize; i++) { + var bltadat, srca; + if (ptb) { + var bltbdat = blt_info.bltbdat = (SAER_Memory_chipData[ptb] << 8) | SAER_Memory_chipData[ptb + 1]; ptb -= 2; + srcb = (((bltbdat << 16) | prevb) >>> 0) >>> b.blitdownbshift; + prevb = bltbdat; + } + if (pta) { bltadat = blt_info.bltadat = (SAER_Memory_chipData[pta] << 8) | SAER_Memory_chipData[pta + 1]; pta -= 2; } else { bltadat = blt_info.bltadat; } + bltadat &= blit_masktable[i]; + srca = (((bltadat << 16) | preva) >>> 0) >>> b.blitdownashift; + preva = bltadat; + if (dstp) { + SAER_Memory_chipData[dstp] = dstd >> 8; + SAER_Memory_chipData[dstp + 1] = dstd & 0xff; + } + dstd = (srca ^ srcb) & 0xffff; + totald |= dstd; + if (ptd) { dstp = ptd; ptd -= 2; } + } + if (pta) pta -= b.bltamod; + if (ptb) ptb -= b.bltbmod; + if (ptd) ptd -= b.bltdmod; + } + b.bltbhold = srcb; + if (dstp) { + SAER_Memory_chipData[dstp] = dstd >> 8; + SAER_Memory_chipData[dstp + 1] = dstd & 0xff; + } + if (totald != 0) b.blitzero = 0; + } + + function blitdofast_4a(pta, ptb, ptc, ptd, b) { + var i,j; + var totald = 0; + var preva = 0; + var prevb = 0, srcb = b.bltbhold; + var srcc = b.bltcdat; + var dstd = 0; + var dstp = 0; + for (j = 0; j < b.vblitsize; j++) { + for (i = 0; i < b.hblitsize; i++) { + var bltadat, srca; + if (ptc) { srcc = (SAER_Memory_chipData[ptc] << 8) | SAER_Memory_chipData[ptc + 1]; ptc += 2; } + if (ptb) { + var bltbdat = blt_info.bltbdat = (SAER_Memory_chipData[ptb] << 8) | SAER_Memory_chipData[ptb + 1]; ptb += 2; + srcb = (((prevb << 16) | bltbdat) >>> 0) >>> b.blitbshift; + prevb = bltbdat; + } + if (pta) { bltadat = blt_info.bltadat = (SAER_Memory_chipData[pta] << 8) | SAER_Memory_chipData[pta + 1]; pta += 2; } else { bltadat = blt_info.bltadat; } + bltadat &= blit_masktable[i]; + srca = (((preva << 16) | bltadat) >>> 0) >>> b.blitashift; + preva = bltadat; + if (dstp) { + SAER_Memory_chipData[dstp] = dstd >> 8; + SAER_Memory_chipData[dstp + 1] = dstd & 0xff; + } + dstd = (srcc ^ (srca & (srcb | srcc))) & 0xffff; + totald |= dstd; + if (ptd) { dstp = ptd; ptd += 2; } + } + if (pta) pta += b.bltamod; + if (ptb) ptb += b.bltbmod; + if (ptc) ptc += b.bltcmod; + if (ptd) ptd += b.bltdmod; + } + b.bltbhold = srcb; + b.bltcdat = srcc; + if (dstp) { + SAER_Memory_chipData[dstp] = dstd >> 8; + SAER_Memory_chipData[dstp + 1] = dstd & 0xff; + } + if (totald != 0) b.blitzero = 0; + } + + function blitdofast_desc_4a(pta, ptb, ptc, ptd, b) { + var totald = 0; + var i,j; + var preva = 0; + var prevb = 0, srcb = b.bltbhold; + var srcc = b.bltcdat; + var dstd = 0; + var dstp = 0; + for (j = 0; j < b.vblitsize; j++) { + for (i = 0; i < b.hblitsize; i++) { + var bltadat, srca; + if (ptc) { srcc = (SAER_Memory_chipData[ptc] << 8) | SAER_Memory_chipData[ptc + 1]; ptc -= 2; } + if (ptb) { + var bltbdat = blt_info.bltbdat = (SAER_Memory_chipData[ptb] << 8) | SAER_Memory_chipData[ptb + 1]; ptb -= 2; + srcb = (((bltbdat << 16) | prevb) >>> 0) >>> b.blitdownbshift; + prevb = bltbdat; + } + if (pta) { bltadat = blt_info.bltadat = (SAER_Memory_chipData[pta] << 8) | SAER_Memory_chipData[pta + 1]; pta -= 2; } else { bltadat = blt_info.bltadat; } + bltadat &= blit_masktable[i]; + srca = (((bltadat << 16) | preva) >>> 0) >>> b.blitdownashift; + preva = bltadat; + if (dstp) { + SAER_Memory_chipData[dstp] = dstd >> 8; + SAER_Memory_chipData[dstp + 1] = dstd & 0xff; + } + dstd = (srcc ^ (srca & (srcb | srcc))) & 0xffff; + totald |= dstd; + if (ptd) { dstp = ptd; ptd -= 2; } + } + if (pta) pta -= b.bltamod; + if (ptb) ptb -= b.bltbmod; + if (ptc) ptc -= b.bltcmod; + if (ptd) ptd -= b.bltdmod; + } + b.bltbhold = srcb; + b.bltcdat = srcc; + if (dstp) { + SAER_Memory_chipData[dstp] = dstd >> 8; + SAER_Memory_chipData[dstp + 1] = dstd & 0xff; + } + if (totald != 0) b.blitzero = 0; + } + + function blitdofast_6a(pta, ptb, ptc, ptd, b) { + var i,j; + var totald = 0; + var preva = 0; + var prevb = 0, srcb = b.bltbhold; + var srcc = b.bltcdat; + var dstd = 0; + var dstp = 0; + for (j = 0; j < b.vblitsize; j++) { + for (i = 0; i < b.hblitsize; i++) { + var bltadat, srca; + if (ptc) { srcc = (SAER_Memory_chipData[ptc] << 8) | SAER_Memory_chipData[ptc + 1]; ptc += 2; } + if (ptb) { + var bltbdat = blt_info.bltbdat = (SAER_Memory_chipData[ptb] << 8) | SAER_Memory_chipData[ptb + 1]; ptb += 2; + srcb = (((prevb << 16) | bltbdat) >>> 0) >>> b.blitbshift; + prevb = bltbdat; + } + if (pta) { bltadat = blt_info.bltadat = (SAER_Memory_chipData[pta] << 8) | SAER_Memory_chipData[pta + 1]; pta += 2; } else { bltadat = blt_info.bltadat; } + bltadat &= blit_masktable[i]; + srca = (((preva << 16) | bltadat) >>> 0) >>> b.blitashift; + preva = bltadat; + if (dstp) { + SAER_Memory_chipData[dstp] = dstd >> 8; + SAER_Memory_chipData[dstp + 1] = dstd & 0xff; + } + dstd = (srcc ^ (srca & srcb)) & 0xffff; + totald |= dstd; + if (ptd) { dstp = ptd; ptd += 2; } + } + if (pta) pta += b.bltamod; + if (ptb) ptb += b.bltbmod; + if (ptc) ptc += b.bltcmod; + if (ptd) ptd += b.bltdmod; + } + b.bltbhold = srcb; + b.bltcdat = srcc; + if (dstp) { + SAER_Memory_chipData[dstp] = dstd >> 8; + SAER_Memory_chipData[dstp + 1] = dstd & 0xff; + } + if (totald != 0) b.blitzero = 0; + } + + function blitdofast_desc_6a(pta, ptb, ptc, ptd, b) { + var totald = 0; + var i,j; + var preva = 0; + var prevb = 0, srcb = b.bltbhold; + var srcc = b.bltcdat; + var dstd = 0; + var dstp = 0; + for (j = 0; j < b.vblitsize; j++) { + for (i = 0; i < b.hblitsize; i++) { + var bltadat, srca; + if (ptc) { srcc = (SAER_Memory_chipData[ptc] << 8) | SAER_Memory_chipData[ptc + 1]; ptc -= 2; } + if (ptb) { + var bltbdat = blt_info.bltbdat = (SAER_Memory_chipData[ptb] << 8) | SAER_Memory_chipData[ptb + 1]; ptb -= 2; + srcb = (((bltbdat << 16) | prevb) >>> 0) >>> b.blitdownbshift; + prevb = bltbdat; + } + if (pta) { bltadat = blt_info.bltadat = (SAER_Memory_chipData[pta] << 8) | SAER_Memory_chipData[pta + 1]; pta -= 2; } else { bltadat = blt_info.bltadat; } + bltadat &= blit_masktable[i]; + srca = (((bltadat << 16) | preva) >>> 0) >>> b.blitdownashift; + preva = bltadat; + if (dstp) { + SAER_Memory_chipData[dstp] = dstd >> 8; + SAER_Memory_chipData[dstp + 1] = dstd & 0xff; + } + dstd = (srcc ^ (srca & srcb)) & 0xffff; + totald |= dstd; + if (ptd) { dstp = ptd; ptd -= 2; } + } + if (pta) pta -= b.bltamod; + if (ptb) ptb -= b.bltbmod; + if (ptc) ptc -= b.bltcmod; + if (ptd) ptd -= b.bltdmod; + } + b.bltbhold = srcb; + b.bltcdat = srcc; + if (dstp) { + SAER_Memory_chipData[dstp] = dstd >> 8; + SAER_Memory_chipData[dstp + 1] = dstd & 0xff; + } + if (totald != 0) b.blitzero = 0; + } + + function blitdofast_8a(pta, ptb, ptc, ptd, b) { + var i,j; + var totald = 0; + var preva = 0; + var prevb = 0, srcb = b.bltbhold; + var srcc = b.bltcdat; + var dstd = 0; + var dstp = 0; + for (j = 0; j < b.vblitsize; j++) { + for (i = 0; i < b.hblitsize; i++) { + var bltadat, srca; + if (ptc) { srcc = (SAER_Memory_chipData[ptc] << 8) | SAER_Memory_chipData[ptc + 1]; ptc += 2; } + if (ptb) { + var bltbdat = blt_info.bltbdat = (SAER_Memory_chipData[ptb] << 8) | SAER_Memory_chipData[ptb + 1]; ptb += 2; + srcb = (((prevb << 16) | bltbdat) >>> 0) >>> b.blitbshift; + prevb = bltbdat; + } + if (pta) { bltadat = blt_info.bltadat = (SAER_Memory_chipData[pta] << 8) | SAER_Memory_chipData[pta + 1]; pta += 2; } else { bltadat = blt_info.bltadat; } + bltadat &= blit_masktable[i]; + srca = (((preva << 16) | bltadat) >>> 0) >>> b.blitashift; + preva = bltadat; + if (dstp) { + SAER_Memory_chipData[dstp] = dstd >> 8; + SAER_Memory_chipData[dstp + 1] = dstd & 0xff; + } + dstd = (srcc & (~srca | srcb)) & 0xffff; + totald |= dstd; + if (ptd) { dstp = ptd; ptd += 2; } + } + if (pta) pta += b.bltamod; + if (ptb) ptb += b.bltbmod; + if (ptc) ptc += b.bltcmod; + if (ptd) ptd += b.bltdmod; + } + b.bltbhold = srcb; + b.bltcdat = srcc; + if (dstp) { + SAER_Memory_chipData[dstp] = dstd >> 8; + SAER_Memory_chipData[dstp + 1] = dstd & 0xff; + } + if (totald != 0) b.blitzero = 0; + } + + function blitdofast_desc_8a(pta, ptb, ptc, ptd, b) { + var totald = 0; + var i,j; + var preva = 0; + var prevb = 0, srcb = b.bltbhold; + var srcc = b.bltcdat; + var dstd = 0; + var dstp = 0; + for (j = 0; j < b.vblitsize; j++) { + for (i = 0; i < b.hblitsize; i++) { + var bltadat, srca; + if (ptc) { srcc = (SAER_Memory_chipData[ptc] << 8) | SAER_Memory_chipData[ptc + 1]; ptc -= 2; } + if (ptb) { + var bltbdat = blt_info.bltbdat = (SAER_Memory_chipData[ptb] << 8) | SAER_Memory_chipData[ptb + 1]; ptb -= 2; + srcb = (((bltbdat << 16) | prevb) >>> 0) >>> b.blitdownbshift; + prevb = bltbdat; + } + if (pta) { bltadat = blt_info.bltadat = (SAER_Memory_chipData[pta] << 8) | SAER_Memory_chipData[pta + 1]; pta -= 2; } else { bltadat = blt_info.bltadat; } + bltadat &= blit_masktable[i]; + srca = (((bltadat << 16) | preva) >>> 0) >>> b.blitdownashift; + preva = bltadat; + if (dstp) { + SAER_Memory_chipData[dstp] = dstd >> 8; + SAER_Memory_chipData[dstp + 1] = dstd & 0xff; + } + dstd = (srcc & (~srca | srcb)) & 0xffff; + totald |= dstd; + if (ptd) { dstp = ptd; ptd -= 2; } + } + if (pta) pta -= b.bltamod; + if (ptb) ptb -= b.bltbmod; + if (ptc) ptc -= b.bltcmod; + if (ptd) ptd -= b.bltdmod; + } + b.bltbhold = srcb; + b.bltcdat = srcc; + if (dstp) { + SAER_Memory_chipData[dstp] = dstd >> 8; + SAER_Memory_chipData[dstp + 1] = dstd & 0xff; + } + if (totald != 0) b.blitzero = 0; + } + + function blitdofast_8c(pta, ptb, ptc, ptd, b) { + var i,j; + var totald = 0; + var preva = 0; + var prevb = 0, srcb = b.bltbhold; + var srcc = b.bltcdat; + var dstd = 0; + var dstp = 0; + for (j = 0; j < b.vblitsize; j++) { + for (i = 0; i < b.hblitsize; i++) { + var bltadat, srca; + if (ptc) { srcc = (SAER_Memory_chipData[ptc] << 8) | SAER_Memory_chipData[ptc + 1]; ptc += 2; } + if (ptb) { + var bltbdat = blt_info.bltbdat = (SAER_Memory_chipData[ptb] << 8) | SAER_Memory_chipData[ptb + 1]; ptb += 2; + srcb = (((prevb << 16) | bltbdat) >>> 0) >>> b.blitbshift; + prevb = bltbdat; + } + if (pta) { bltadat = blt_info.bltadat = (SAER_Memory_chipData[pta] << 8) | SAER_Memory_chipData[pta + 1]; pta += 2; } else { bltadat = blt_info.bltadat; } + bltadat &= blit_masktable[i]; + srca = (((preva << 16) | bltadat) >>> 0) >>> b.blitashift; + preva = bltadat; + if (dstp) { + SAER_Memory_chipData[dstp] = dstd >> 8; + SAER_Memory_chipData[dstp + 1] = dstd & 0xff; + } + dstd = (srcb & (~srca | srcc)) & 0xffff; + totald |= dstd; + if (ptd) { dstp = ptd; ptd += 2; } + } + if (pta) pta += b.bltamod; + if (ptb) ptb += b.bltbmod; + if (ptc) ptc += b.bltcmod; + if (ptd) ptd += b.bltdmod; + } + b.bltbhold = srcb; + b.bltcdat = srcc; + if (dstp) { + SAER_Memory_chipData[dstp] = dstd >> 8; + SAER_Memory_chipData[dstp + 1] = dstd & 0xff; + } + if (totald != 0) b.blitzero = 0; + } + + function blitdofast_desc_8c(pta, ptb, ptc, ptd, b) { + var totald = 0; + var i,j; + var preva = 0; + var prevb = 0, srcb = b.bltbhold; + var srcc = b.bltcdat; + var dstd = 0; + var dstp = 0; + for (j = 0; j < b.vblitsize; j++) { + for (i = 0; i < b.hblitsize; i++) { + var bltadat, srca; + if (ptc) { srcc = (SAER_Memory_chipData[ptc] << 8) | SAER_Memory_chipData[ptc + 1]; ptc -= 2; } + if (ptb) { + var bltbdat = blt_info.bltbdat = (SAER_Memory_chipData[ptb] << 8) | SAER_Memory_chipData[ptb + 1]; ptb -= 2; + srcb = (((bltbdat << 16) | prevb) >>> 0) >>> b.blitdownbshift; + prevb = bltbdat; + } + if (pta) { bltadat = blt_info.bltadat = (SAER_Memory_chipData[pta] << 8) | SAER_Memory_chipData[pta + 1]; pta -= 2; } else { bltadat = blt_info.bltadat; } + bltadat &= blit_masktable[i]; + srca = (((bltadat << 16) | preva) >>> 0) >>> b.blitdownashift; + preva = bltadat; + if (dstp) { + SAER_Memory_chipData[dstp] = dstd >> 8; + SAER_Memory_chipData[dstp + 1] = dstd & 0xff; + } + dstd = (srcb & (~srca | srcc)) & 0xffff; + totald |= dstd; + if (ptd) { dstp = ptd; ptd -= 2; } + } + if (pta) pta -= b.bltamod; + if (ptb) ptb -= b.bltbmod; + if (ptc) ptc -= b.bltcmod; + if (ptd) ptd -= b.bltdmod; + } + b.bltbhold = srcb; + b.bltcdat = srcc; + if (dstp) { + SAER_Memory_chipData[dstp] = dstd >> 8; + SAER_Memory_chipData[dstp + 1] = dstd & 0xff; + } + if (totald != 0) b.blitzero = 0; + } + + function blitdofast_9a(pta, ptb, ptc, ptd, b) { + var i,j; + var totald = 0; + var preva = 0; + var prevb = 0, srcb = b.bltbhold; + var srcc = b.bltcdat; + var dstd = 0; + var dstp = 0; + for (j = 0; j < b.vblitsize; j++) { + for (i = 0; i < b.hblitsize; i++) { + var bltadat, srca; + if (ptc) { srcc = (SAER_Memory_chipData[ptc] << 8) | SAER_Memory_chipData[ptc + 1]; ptc += 2; } + if (ptb) { + var bltbdat = blt_info.bltbdat = (SAER_Memory_chipData[ptb] << 8) | SAER_Memory_chipData[ptb + 1]; ptb += 2; + srcb = (((prevb << 16) | bltbdat) >>> 0) >>> b.blitbshift; + prevb = bltbdat; + } + if (pta) { bltadat = blt_info.bltadat = (SAER_Memory_chipData[pta] << 8) | SAER_Memory_chipData[pta + 1]; pta += 2; } else { bltadat = blt_info.bltadat; } + bltadat &= blit_masktable[i]; + srca = (((preva << 16) | bltadat) >>> 0) >>> b.blitashift; + preva = bltadat; + if (dstp) { + SAER_Memory_chipData[dstp] = dstd >> 8; + SAER_Memory_chipData[dstp + 1] = dstd & 0xff; + } + dstd = (srcc ^ (srca & ~srcb)) & 0xffff; + totald |= dstd; + if (ptd) { dstp = ptd; ptd += 2; } + } + if (pta) pta += b.bltamod; + if (ptb) ptb += b.bltbmod; + if (ptc) ptc += b.bltcmod; + if (ptd) ptd += b.bltdmod; + } + b.bltbhold = srcb; + b.bltcdat = srcc; + if (dstp) { + SAER_Memory_chipData[dstp] = dstd >> 8; + SAER_Memory_chipData[dstp + 1] = dstd & 0xff; + } + if (totald != 0) b.blitzero = 0; + } + + function blitdofast_desc_9a(pta, ptb, ptc, ptd, b) { + var totald = 0; + var i,j; + var preva = 0; + var prevb = 0, srcb = b.bltbhold; + var srcc = b.bltcdat; + var dstd = 0; + var dstp = 0; + for (j = 0; j < b.vblitsize; j++) { + for (i = 0; i < b.hblitsize; i++) { + var bltadat, srca; + if (ptc) { srcc = (SAER_Memory_chipData[ptc] << 8) | SAER_Memory_chipData[ptc + 1]; ptc -= 2; } + if (ptb) { + var bltbdat = blt_info.bltbdat = (SAER_Memory_chipData[ptb] << 8) | SAER_Memory_chipData[ptb + 1]; ptb -= 2; + srcb = (((bltbdat << 16) | prevb) >>> 0) >>> b.blitdownbshift; + prevb = bltbdat; + } + if (pta) { bltadat = blt_info.bltadat = (SAER_Memory_chipData[pta] << 8) | SAER_Memory_chipData[pta + 1]; pta -= 2; } else { bltadat = blt_info.bltadat; } + bltadat &= blit_masktable[i]; + srca = (((bltadat << 16) | preva) >>> 0) >>> b.blitdownashift; + preva = bltadat; + if (dstp) { + SAER_Memory_chipData[dstp] = dstd >> 8; + SAER_Memory_chipData[dstp + 1] = dstd & 0xff; + } + dstd = (srcc ^ (srca & ~srcb)) & 0xffff; + totald |= dstd; + if (ptd) { dstp = ptd; ptd -= 2; } + } + if (pta) pta -= b.bltamod; + if (ptb) ptb -= b.bltbmod; + if (ptc) ptc -= b.bltcmod; + if (ptd) ptd -= b.bltdmod; + } + b.bltbhold = srcb; + b.bltcdat = srcc; + if (dstp) { + SAER_Memory_chipData[dstp] = dstd >> 8; + SAER_Memory_chipData[dstp + 1] = dstd & 0xff; + } + if (totald != 0) b.blitzero = 0; + } + + function blitdofast_a8(pta, ptb, ptc, ptd, b) { + var i,j; + var totald = 0; + var preva = 0; + var prevb = 0, srcb = b.bltbhold; + var srcc = b.bltcdat; + var dstd = 0; + var dstp = 0; + for (j = 0; j < b.vblitsize; j++) { + for (i = 0; i < b.hblitsize; i++) { + var bltadat, srca; + if (ptc) { srcc = (SAER_Memory_chipData[ptc] << 8) | SAER_Memory_chipData[ptc + 1]; ptc += 2; } + if (ptb) { + var bltbdat = blt_info.bltbdat = (SAER_Memory_chipData[ptb] << 8) | SAER_Memory_chipData[ptb + 1]; ptb += 2; + srcb = (((prevb << 16) | bltbdat) >>> 0) >>> b.blitbshift; + prevb = bltbdat; + } + if (pta) { bltadat = blt_info.bltadat = (SAER_Memory_chipData[pta] << 8) | SAER_Memory_chipData[pta + 1]; pta += 2; } else { bltadat = blt_info.bltadat; } + bltadat &= blit_masktable[i]; + srca = (((preva << 16) | bltadat) >>> 0) >>> b.blitashift; + preva = bltadat; + if (dstp) { + SAER_Memory_chipData[dstp] = dstd >> 8; + SAER_Memory_chipData[dstp + 1] = dstd & 0xff; + } + dstd = (srcc & (srca | srcb)) & 0xffff; + totald |= dstd; + if (ptd) { dstp = ptd; ptd += 2; } + } + if (pta) pta += b.bltamod; + if (ptb) ptb += b.bltbmod; + if (ptc) ptc += b.bltcmod; + if (ptd) ptd += b.bltdmod; + } + b.bltbhold = srcb; + b.bltcdat = srcc; + if (dstp) { + SAER_Memory_chipData[dstp] = dstd >> 8; + SAER_Memory_chipData[dstp + 1] = dstd & 0xff; + } + if (totald != 0) b.blitzero = 0; + } + + function blitdofast_desc_a8(pta, ptb, ptc, ptd, b) { + var totald = 0; + var i,j; + var preva = 0; + var prevb = 0, srcb = b.bltbhold; + var srcc = b.bltcdat; + var dstd = 0; + var dstp = 0; + for (j = 0; j < b.vblitsize; j++) { + for (i = 0; i < b.hblitsize; i++) { + var bltadat, srca; + if (ptc) { srcc = (SAER_Memory_chipData[ptc] << 8) | SAER_Memory_chipData[ptc + 1]; ptc -= 2; } + if (ptb) { + var bltbdat = blt_info.bltbdat = (SAER_Memory_chipData[ptb] << 8) | SAER_Memory_chipData[ptb + 1]; ptb -= 2; + srcb = (((bltbdat << 16) | prevb) >>> 0) >>> b.blitdownbshift; + prevb = bltbdat; + } + if (pta) { bltadat = blt_info.bltadat = (SAER_Memory_chipData[pta] << 8) | SAER_Memory_chipData[pta + 1]; pta -= 2; } else { bltadat = blt_info.bltadat; } + bltadat &= blit_masktable[i]; + srca = (((bltadat << 16) | preva) >>> 0) >>> b.blitdownashift; + preva = bltadat; + if (dstp) { + SAER_Memory_chipData[dstp] = dstd >> 8; + SAER_Memory_chipData[dstp + 1] = dstd & 0xff; + } + dstd = (srcc & (srca | srcb)) & 0xffff; + totald |= dstd; + if (ptd) { dstp = ptd; ptd -= 2; } + } + if (pta) pta -= b.bltamod; + if (ptb) ptb -= b.bltbmod; + if (ptc) ptc -= b.bltcmod; + if (ptd) ptd -= b.bltdmod; + } + b.bltbhold = srcb; + b.bltcdat = srcc; + if (dstp) { + SAER_Memory_chipData[dstp] = dstd >> 8; + SAER_Memory_chipData[dstp + 1] = dstd & 0xff; + } + if (totald != 0) b.blitzero = 0; + } + + function blitdofast_aa(pta, ptb, ptc, ptd, b) { + var i,j; + var totald = 0; + var srcc = b.bltcdat; + var dstd = 0; + var dstp = 0; + for (j = 0; j < b.vblitsize; j++) { + for (i = 0; i < b.hblitsize; i++) { + var bltadat, srca; + if (ptc) { srcc = (SAER_Memory_chipData[ptc] << 8) | SAER_Memory_chipData[ptc + 1]; ptc += 2; } + if (dstp) { + SAER_Memory_chipData[dstp] = dstd >> 8; + SAER_Memory_chipData[dstp + 1] = dstd & 0xff; + } + dstd = srcc & 0xffff; + totald |= dstd; + if (ptd) { dstp = ptd; ptd += 2; } + } + if (ptc) ptc += b.bltcmod; + if (ptd) ptd += b.bltdmod; + } + b.bltcdat = srcc; + if (dstp) { + SAER_Memory_chipData[dstp] = dstd >> 8; + SAER_Memory_chipData[dstp + 1] = dstd & 0xff; + } + if (totald != 0) b.blitzero = 0; + } + + function blitdofast_desc_aa(pta, ptb, ptc, ptd, b) { + var totald = 0; + var i,j; + var srcc = b.bltcdat; + var dstd = 0; + var dstp = 0; + for (j = 0; j < b.vblitsize; j++) { + for (i = 0; i < b.hblitsize; i++) { + var bltadat, srca; + if (ptc) { srcc = (SAER_Memory_chipData[ptc] << 8) | SAER_Memory_chipData[ptc + 1]; ptc -= 2; } + if (dstp) { + SAER_Memory_chipData[dstp] = dstd >> 8; + SAER_Memory_chipData[dstp + 1] = dstd & 0xff; + } + dstd = srcc & 0xffff; + totald |= dstd; + if (ptd) { dstp = ptd; ptd -= 2; } + } + if (ptc) ptc -= b.bltcmod; + if (ptd) ptd -= b.bltdmod; + } + b.bltcdat = srcc; + if (dstp) { + SAER_Memory_chipData[dstp] = dstd >> 8; + SAER_Memory_chipData[dstp + 1] = dstd & 0xff; + } + if (totald != 0) b.blitzero = 0; + } + + function blitdofast_b1(pta, ptb, ptc, ptd, b) { + var i,j; + var totald = 0; + var preva = 0; + var prevb = 0, srcb = b.bltbhold; + var srcc = b.bltcdat; + var dstd = 0; + var dstp = 0; + for (j = 0; j < b.vblitsize; j++) { + for (i = 0; i < b.hblitsize; i++) { + var bltadat, srca; + if (ptc) { srcc = (SAER_Memory_chipData[ptc] << 8) | SAER_Memory_chipData[ptc + 1]; ptc += 2; } + if (ptb) { + var bltbdat = blt_info.bltbdat = (SAER_Memory_chipData[ptb] << 8) | SAER_Memory_chipData[ptb + 1]; ptb += 2; + srcb = (((prevb << 16) | bltbdat) >>> 0) >>> b.blitbshift; + prevb = bltbdat; + } + if (pta) { bltadat = blt_info.bltadat = (SAER_Memory_chipData[pta] << 8) | SAER_Memory_chipData[pta + 1]; pta += 2; } else { bltadat = blt_info.bltadat; } + bltadat &= blit_masktable[i]; + srca = (((preva << 16) | bltadat) >>> 0) >>> b.blitashift; + preva = bltadat; + if (dstp) { + SAER_Memory_chipData[dstp] = dstd >> 8; + SAER_Memory_chipData[dstp + 1] = dstd & 0xff; + } + dstd = ~(srca ^ (srcc | (srca ^ srcb))) & 0xffff; + totald |= dstd; + if (ptd) { dstp = ptd; ptd += 2; } + } + if (pta) pta += b.bltamod; + if (ptb) ptb += b.bltbmod; + if (ptc) ptc += b.bltcmod; + if (ptd) ptd += b.bltdmod; + } + b.bltbhold = srcb; + b.bltcdat = srcc; + if (dstp) { + SAER_Memory_chipData[dstp] = dstd >> 8; + SAER_Memory_chipData[dstp + 1] = dstd & 0xff; + } + if (totald != 0) b.blitzero = 0; + } + + function blitdofast_desc_b1(pta, ptb, ptc, ptd, b) { + var totald = 0; + var i,j; + var preva = 0; + var prevb = 0, srcb = b.bltbhold; + var srcc = b.bltcdat; + var dstd = 0; + var dstp = 0; + for (j = 0; j < b.vblitsize; j++) { + for (i = 0; i < b.hblitsize; i++) { + var bltadat, srca; + if (ptc) { srcc = (SAER_Memory_chipData[ptc] << 8) | SAER_Memory_chipData[ptc + 1]; ptc -= 2; } + if (ptb) { + var bltbdat = blt_info.bltbdat = (SAER_Memory_chipData[ptb] << 8) | SAER_Memory_chipData[ptb + 1]; ptb -= 2; + srcb = (((bltbdat << 16) | prevb) >>> 0) >>> b.blitdownbshift; + prevb = bltbdat; + } + if (pta) { bltadat = blt_info.bltadat = (SAER_Memory_chipData[pta] << 8) | SAER_Memory_chipData[pta + 1]; pta -= 2; } else { bltadat = blt_info.bltadat; } + bltadat &= blit_masktable[i]; + srca = (((bltadat << 16) | preva) >>> 0) >>> b.blitdownashift; + preva = bltadat; + if (dstp) { + SAER_Memory_chipData[dstp] = dstd >> 8; + SAER_Memory_chipData[dstp + 1] = dstd & 0xff; + } + dstd = ~(srca ^ (srcc | (srca ^ srcb))) & 0xffff; + totald |= dstd; + if (ptd) { dstp = ptd; ptd -= 2; } + } + if (pta) pta -= b.bltamod; + if (ptb) ptb -= b.bltbmod; + if (ptc) ptc -= b.bltcmod; + if (ptd) ptd -= b.bltdmod; + } + b.bltbhold = srcb; + b.bltcdat = srcc; + if (dstp) { + SAER_Memory_chipData[dstp] = dstd >> 8; + SAER_Memory_chipData[dstp + 1] = dstd & 0xff; + } + if (totald != 0) b.blitzero = 0; + } + + function blitdofast_ca(pta, ptb, ptc, ptd, b) { + var i,j; + var totald = 0; + var preva = 0; + var prevb = 0, srcb = b.bltbhold; + var srcc = b.bltcdat; + var dstd = 0; + var dstp = 0; + for (j = 0; j < b.vblitsize; j++) { + for (i = 0; i < b.hblitsize; i++) { + var bltadat, srca; + if (ptc) { srcc = (SAER_Memory_chipData[ptc] << 8) | SAER_Memory_chipData[ptc + 1]; ptc += 2; } + if (ptb) { + var bltbdat = blt_info.bltbdat = (SAER_Memory_chipData[ptb] << 8) | SAER_Memory_chipData[ptb + 1]; ptb += 2; + srcb = (((prevb << 16) | bltbdat) >>> 0) >>> b.blitbshift; + prevb = bltbdat; + } + if (pta) { bltadat = blt_info.bltadat = (SAER_Memory_chipData[pta] << 8) | SAER_Memory_chipData[pta + 1]; pta += 2; } else { bltadat = blt_info.bltadat; } + bltadat &= blit_masktable[i]; + srca = (((preva << 16) | bltadat) >>> 0) >>> b.blitashift; + preva = bltadat; + if (dstp) { + SAER_Memory_chipData[dstp] = dstd >> 8; + SAER_Memory_chipData[dstp + 1] = dstd & 0xff; + } + dstd = (srcc ^ (srca & (srcb ^ srcc))) & 0xffff; + totald |= dstd; + if (ptd) { dstp = ptd; ptd += 2; } + } + if (pta) pta += b.bltamod; + if (ptb) ptb += b.bltbmod; + if (ptc) ptc += b.bltcmod; + if (ptd) ptd += b.bltdmod; + } + b.bltbhold = srcb; + b.bltcdat = srcc; + if (dstp) { + SAER_Memory_chipData[dstp] = dstd >> 8; + SAER_Memory_chipData[dstp + 1] = dstd & 0xff; + } + if (totald != 0) b.blitzero = 0; + } + + function blitdofast_desc_ca(pta, ptb, ptc, ptd, b) { + var totald = 0; + var i,j; + var preva = 0; + var prevb = 0, srcb = b.bltbhold; + var srcc = b.bltcdat; + var dstd = 0; + var dstp = 0; + for (j = 0; j < b.vblitsize; j++) { + for (i = 0; i < b.hblitsize; i++) { + var bltadat, srca; + if (ptc) { srcc = (SAER_Memory_chipData[ptc] << 8) | SAER_Memory_chipData[ptc + 1]; ptc -= 2; } + if (ptb) { + var bltbdat = blt_info.bltbdat = (SAER_Memory_chipData[ptb] << 8) | SAER_Memory_chipData[ptb + 1]; ptb -= 2; + srcb = (((bltbdat << 16) | prevb) >>> 0) >>> b.blitdownbshift; + prevb = bltbdat; + } + if (pta) { bltadat = blt_info.bltadat = (SAER_Memory_chipData[pta] << 8) | SAER_Memory_chipData[pta + 1]; pta -= 2; } else { bltadat = blt_info.bltadat; } + bltadat &= blit_masktable[i]; + srca = (((bltadat << 16) | preva) >>> 0) >>> b.blitdownashift; + preva = bltadat; + if (dstp) { + SAER_Memory_chipData[dstp] = dstd >> 8; + SAER_Memory_chipData[dstp + 1] = dstd & 0xff; + } + dstd = (srcc ^ (srca & (srcb ^ srcc))) & 0xffff; + totald |= dstd; + if (ptd) { dstp = ptd; ptd -= 2; } + } + if (pta) pta -= b.bltamod; + if (ptb) ptb -= b.bltbmod; + if (ptc) ptc -= b.bltcmod; + if (ptd) ptd -= b.bltdmod; + } + b.bltbhold = srcb; + b.bltcdat = srcc; + if (dstp) { + SAER_Memory_chipData[dstp] = dstd >> 8; + SAER_Memory_chipData[dstp + 1] = dstd & 0xff; + } + if (totald != 0) b.blitzero = 0; + } + + function blitdofast_cc(pta, ptb, ptc, ptd, b) { + var i,j; + var totald = 0; + var prevb = 0, srcb = b.bltbhold; + var dstd = 0; + var dstp = 0; + for (j = 0; j < b.vblitsize; j++) { + for (i = 0; i < b.hblitsize; i++) { + var bltadat, srca; + if (ptb) { + var bltbdat = blt_info.bltbdat = (SAER_Memory_chipData[ptb] << 8) | SAER_Memory_chipData[ptb + 1]; ptb += 2; + srcb = (((prevb << 16) | bltbdat) >>> 0) >>> b.blitbshift; + prevb = bltbdat; + } + if (dstp) { + SAER_Memory_chipData[dstp] = dstd >> 8; + SAER_Memory_chipData[dstp + 1] = dstd & 0xff; + } + dstd = srcb & 0xffff; + totald |= dstd; + if (ptd) { dstp = ptd; ptd += 2; } + } + if (ptb) ptb += b.bltbmod; + if (ptd) ptd += b.bltdmod; + } + b.bltbhold = srcb; + if (dstp) { + SAER_Memory_chipData[dstp] = dstd >> 8; + SAER_Memory_chipData[dstp + 1] = dstd & 0xff; + } + if (totald != 0) b.blitzero = 0; + } + + function blitdofast_desc_cc(pta, ptb, ptc, ptd, b) { + var totald = 0; + var i,j; + var prevb = 0, srcb = b.bltbhold; + var dstd = 0; + var dstp = 0; + for (j = 0; j < b.vblitsize; j++) { + for (i = 0; i < b.hblitsize; i++) { + var bltadat, srca; + if (ptb) { + var bltbdat = blt_info.bltbdat = (SAER_Memory_chipData[ptb] << 8) | SAER_Memory_chipData[ptb + 1]; ptb -= 2; + srcb = (((bltbdat << 16) | prevb) >>> 0) >>> b.blitdownbshift; + prevb = bltbdat; + } + if (dstp) { + SAER_Memory_chipData[dstp] = dstd >> 8; + SAER_Memory_chipData[dstp + 1] = dstd & 0xff; + } + dstd = srcb & 0xffff; + totald |= dstd; + if (ptd) { dstp = ptd; ptd -= 2; } + } + if (ptb) ptb -= b.bltbmod; + if (ptd) ptd -= b.bltdmod; + } + b.bltbhold = srcb; + if (dstp) { + SAER_Memory_chipData[dstp] = dstd >> 8; + SAER_Memory_chipData[dstp + 1] = dstd & 0xff; + } + if (totald != 0) b.blitzero = 0; + } + + function blitdofast_d8(pta, ptb, ptc, ptd, b) { + var i,j; + var totald = 0; + var preva = 0; + var prevb = 0, srcb = b.bltbhold; + var srcc = b.bltcdat; + var dstd = 0; + var dstp = 0; + for (j = 0; j < b.vblitsize; j++) { + for (i = 0; i < b.hblitsize; i++) { + var bltadat, srca; + if (ptc) { srcc = (SAER_Memory_chipData[ptc] << 8) | SAER_Memory_chipData[ptc + 1]; ptc += 2; } + if (ptb) { + var bltbdat = blt_info.bltbdat = (SAER_Memory_chipData[ptb] << 8) | SAER_Memory_chipData[ptb + 1]; ptb += 2; + srcb = (((prevb << 16) | bltbdat) >>> 0) >>> b.blitbshift; + prevb = bltbdat; + } + if (pta) { bltadat = blt_info.bltadat = (SAER_Memory_chipData[pta] << 8) | SAER_Memory_chipData[pta + 1]; pta += 2; } else { bltadat = blt_info.bltadat; } + bltadat &= blit_masktable[i]; + srca = (((preva << 16) | bltadat) >>> 0) >>> b.blitashift; + preva = bltadat; + if (dstp) { + SAER_Memory_chipData[dstp] = dstd >> 8; + SAER_Memory_chipData[dstp + 1] = dstd & 0xff; + } + dstd = (srca ^ (srcc & (srca ^ srcb))) & 0xffff; + totald |= dstd; + if (ptd) { dstp = ptd; ptd += 2; } + } + if (pta) pta += b.bltamod; + if (ptb) ptb += b.bltbmod; + if (ptc) ptc += b.bltcmod; + if (ptd) ptd += b.bltdmod; + } + b.bltbhold = srcb; + b.bltcdat = srcc; + if (dstp) { + SAER_Memory_chipData[dstp] = dstd >> 8; + SAER_Memory_chipData[dstp + 1] = dstd & 0xff; + } + if (totald != 0) b.blitzero = 0; + } + + function blitdofast_desc_d8(pta, ptb, ptc, ptd, b) { + var totald = 0; + var i,j; + var preva = 0; + var prevb = 0, srcb = b.bltbhold; + var srcc = b.bltcdat; + var dstd = 0; + var dstp = 0; + for (j = 0; j < b.vblitsize; j++) { + for (i = 0; i < b.hblitsize; i++) { + var bltadat, srca; + if (ptc) { srcc = (SAER_Memory_chipData[ptc] << 8) | SAER_Memory_chipData[ptc + 1]; ptc -= 2; } + if (ptb) { + var bltbdat = blt_info.bltbdat = (SAER_Memory_chipData[ptb] << 8) | SAER_Memory_chipData[ptb + 1]; ptb -= 2; + srcb = (((bltbdat << 16) | prevb) >>> 0) >>> b.blitdownbshift; + prevb = bltbdat; + } + if (pta) { bltadat = blt_info.bltadat = (SAER_Memory_chipData[pta] << 8) | SAER_Memory_chipData[pta + 1]; pta -= 2; } else { bltadat = blt_info.bltadat; } + bltadat &= blit_masktable[i]; + srca = (((bltadat << 16) | preva) >>> 0) >>> b.blitdownashift; + preva = bltadat; + if (dstp) { + SAER_Memory_chipData[dstp] = dstd >> 8; + SAER_Memory_chipData[dstp + 1] = dstd & 0xff; + } + dstd = (srca ^ (srcc & (srca ^ srcb))) & 0xffff; + totald |= dstd; + if (ptd) { dstp = ptd; ptd -= 2; } + } + if (pta) pta -= b.bltamod; + if (ptb) ptb -= b.bltbmod; + if (ptc) ptc -= b.bltcmod; + if (ptd) ptd -= b.bltdmod; + } + b.bltbhold = srcb; + b.bltcdat = srcc; + if (dstp) { + SAER_Memory_chipData[dstp] = dstd >> 8; + SAER_Memory_chipData[dstp + 1] = dstd & 0xff; + } + if (totald != 0) b.blitzero = 0; + } + + function blitdofast_e2(pta, ptb, ptc, ptd, b) { + var i,j; + var totald = 0; + var preva = 0; + var prevb = 0, srcb = b.bltbhold; + var srcc = b.bltcdat; + var dstd = 0; + var dstp = 0; + for (j = 0; j < b.vblitsize; j++) { + for (i = 0; i < b.hblitsize; i++) { + var bltadat, srca; + if (ptc) { srcc = (SAER_Memory_chipData[ptc] << 8) | SAER_Memory_chipData[ptc + 1]; ptc += 2; } + if (ptb) { + var bltbdat = blt_info.bltbdat = (SAER_Memory_chipData[ptb] << 8) | SAER_Memory_chipData[ptb + 1]; ptb += 2; + srcb = (((prevb << 16) | bltbdat) >>> 0) >>> b.blitbshift; + prevb = bltbdat; + } + if (pta) { bltadat = blt_info.bltadat = (SAER_Memory_chipData[pta] << 8) | SAER_Memory_chipData[pta + 1]; pta += 2; } else { bltadat = blt_info.bltadat; } + bltadat &= blit_masktable[i]; + srca = (((preva << 16) | bltadat) >>> 0) >>> b.blitashift; + preva = bltadat; + if (dstp) { + SAER_Memory_chipData[dstp] = dstd >> 8; + SAER_Memory_chipData[dstp + 1] = dstd & 0xff; + } + dstd = (srcc ^ (srcb & (srca ^ srcc))) & 0xffff; + totald |= dstd; + if (ptd) { dstp = ptd; ptd += 2; } + } + if (pta) pta += b.bltamod; + if (ptb) ptb += b.bltbmod; + if (ptc) ptc += b.bltcmod; + if (ptd) ptd += b.bltdmod; + } + b.bltbhold = srcb; + b.bltcdat = srcc; + if (dstp) { + SAER_Memory_chipData[dstp] = dstd >> 8; + SAER_Memory_chipData[dstp + 1] = dstd & 0xff; + } + if (totald != 0) b.blitzero = 0; + } + + function blitdofast_desc_e2(pta, ptb, ptc, ptd, b) { + var totald = 0; + var i,j; + var preva = 0; + var prevb = 0, srcb = b.bltbhold; + var srcc = b.bltcdat; + var dstd = 0; + var dstp = 0; + for (j = 0; j < b.vblitsize; j++) { + for (i = 0; i < b.hblitsize; i++) { + var bltadat, srca; + if (ptc) { srcc = (SAER_Memory_chipData[ptc] << 8) | SAER_Memory_chipData[ptc + 1]; ptc -= 2; } + if (ptb) { + var bltbdat = blt_info.bltbdat = (SAER_Memory_chipData[ptb] << 8) | SAER_Memory_chipData[ptb + 1]; ptb -= 2; + srcb = (((bltbdat << 16) | prevb) >>> 0) >>> b.blitdownbshift; + prevb = bltbdat; + } + if (pta) { bltadat = blt_info.bltadat = (SAER_Memory_chipData[pta] << 8) | SAER_Memory_chipData[pta + 1]; pta -= 2; } else { bltadat = blt_info.bltadat; } + bltadat &= blit_masktable[i]; + srca = (((bltadat << 16) | preva) >>> 0) >>> b.blitdownashift; + preva = bltadat; + if (dstp) { + SAER_Memory_chipData[dstp] = dstd >> 8; + SAER_Memory_chipData[dstp + 1] = dstd & 0xff; + } + dstd = (srcc ^ (srcb & (srca ^ srcc))) & 0xffff; + totald |= dstd; + if (ptd) { dstp = ptd; ptd -= 2; } + } + if (pta) pta -= b.bltamod; + if (ptb) ptb -= b.bltbmod; + if (ptc) ptc -= b.bltcmod; + if (ptd) ptd -= b.bltdmod; + } + b.bltbhold = srcb; + b.bltcdat = srcc; + if (dstp) { + SAER_Memory_chipData[dstp] = dstd >> 8; + SAER_Memory_chipData[dstp + 1] = dstd & 0xff; + } + if (totald != 0) b.blitzero = 0; + } + + function blitdofast_ea(pta, ptb, ptc, ptd, b) { + var i,j; + var totald = 0; + var preva = 0; + var prevb = 0, srcb = b.bltbhold; + var srcc = b.bltcdat; + var dstd = 0; + var dstp = 0; + for (j = 0; j < b.vblitsize; j++) { + for (i = 0; i < b.hblitsize; i++) { + var bltadat, srca; + if (ptc) { srcc = (SAER_Memory_chipData[ptc] << 8) | SAER_Memory_chipData[ptc + 1]; ptc += 2; } + if (ptb) { + var bltbdat = blt_info.bltbdat = (SAER_Memory_chipData[ptb] << 8) | SAER_Memory_chipData[ptb + 1]; ptb += 2; + srcb = (((prevb << 16) | bltbdat) >>> 0) >>> b.blitbshift; + prevb = bltbdat; + } + if (pta) { bltadat = blt_info.bltadat = (SAER_Memory_chipData[pta] << 8) | SAER_Memory_chipData[pta + 1]; pta += 2; } else { bltadat = blt_info.bltadat; } + bltadat &= blit_masktable[i]; + srca = (((preva << 16) | bltadat) >>> 0) >>> b.blitashift; + preva = bltadat; + if (dstp) { + SAER_Memory_chipData[dstp] = dstd >> 8; + SAER_Memory_chipData[dstp + 1] = dstd & 0xff; + } + dstd = (srcc | (srca & srcb)) & 0xffff; + totald |= dstd; + if (ptd) { dstp = ptd; ptd += 2; } + } + if (pta) pta += b.bltamod; + if (ptb) ptb += b.bltbmod; + if (ptc) ptc += b.bltcmod; + if (ptd) ptd += b.bltdmod; + } + b.bltbhold = srcb; + b.bltcdat = srcc; + if (dstp) { + SAER_Memory_chipData[dstp] = dstd >> 8; + SAER_Memory_chipData[dstp + 1] = dstd & 0xff; + } + if (totald != 0) b.blitzero = 0; + } + + function blitdofast_desc_ea(pta, ptb, ptc, ptd, b) { + var totald = 0; + var i,j; + var preva = 0; + var prevb = 0, srcb = b.bltbhold; + var srcc = b.bltcdat; + var dstd = 0; + var dstp = 0; + for (j = 0; j < b.vblitsize; j++) { + for (i = 0; i < b.hblitsize; i++) { + var bltadat, srca; + if (ptc) { srcc = (SAER_Memory_chipData[ptc] << 8) | SAER_Memory_chipData[ptc + 1]; ptc -= 2; } + if (ptb) { + var bltbdat = blt_info.bltbdat = (SAER_Memory_chipData[ptb] << 8) | SAER_Memory_chipData[ptb + 1]; ptb -= 2; + srcb = (((bltbdat << 16) | prevb) >>> 0) >>> b.blitdownbshift; + prevb = bltbdat; + } + if (pta) { bltadat = blt_info.bltadat = (SAER_Memory_chipData[pta] << 8) | SAER_Memory_chipData[pta + 1]; pta -= 2; } else { bltadat = blt_info.bltadat; } + bltadat &= blit_masktable[i]; + srca = (((bltadat << 16) | preva) >>> 0) >>> b.blitdownashift; + preva = bltadat; + if (dstp) { + SAER_Memory_chipData[dstp] = dstd >> 8; + SAER_Memory_chipData[dstp + 1] = dstd & 0xff; + } + dstd = (srcc | (srca & srcb)) & 0xffff; + totald |= dstd; + if (ptd) { dstp = ptd; ptd -= 2; } + } + if (pta) pta -= b.bltamod; + if (ptb) ptb -= b.bltbmod; + if (ptc) ptc -= b.bltcmod; + if (ptd) ptd -= b.bltdmod; + } + b.bltbhold = srcb; + b.bltcdat = srcc; + if (dstp) { + SAER_Memory_chipData[dstp] = dstd >> 8; + SAER_Memory_chipData[dstp + 1] = dstd & 0xff; + } + if (totald != 0) b.blitzero = 0; + } + + function blitdofast_f0(pta, ptb, ptc, ptd, b) { + var i,j; + var totald = 0; + var preva = 0; + var dstd = 0; + var dstp = 0; + for (j = 0; j < b.vblitsize; j++) { + for (i = 0; i < b.hblitsize; i++) { + var bltadat, srca; + if (pta) { bltadat = blt_info.bltadat = (SAER_Memory_chipData[pta] << 8) | SAER_Memory_chipData[pta + 1]; pta += 2; } else { bltadat = blt_info.bltadat; } + bltadat &= blit_masktable[i]; + srca = (((preva << 16) | bltadat) >>> 0) >>> b.blitashift; + preva = bltadat; + if (dstp) { + SAER_Memory_chipData[dstp] = dstd >> 8; + SAER_Memory_chipData[dstp + 1] = dstd & 0xff; + } + dstd = srca & 0xffff; + totald |= dstd; + if (ptd) { dstp = ptd; ptd += 2; } + } + if (pta) pta += b.bltamod; + if (ptd) ptd += b.bltdmod; + } + if (dstp) { + SAER_Memory_chipData[dstp] = dstd >> 8; + SAER_Memory_chipData[dstp + 1] = dstd & 0xff; + } + if (totald != 0) b.blitzero = 0; + } + + function blitdofast_desc_f0(pta, ptb, ptc, ptd, b) { + var totald = 0; + var i,j; + var preva = 0; + var dstd = 0; + var dstp = 0; + for (j = 0; j < b.vblitsize; j++) { + for (i = 0; i < b.hblitsize; i++) { + var bltadat, srca; + if (pta) { bltadat = blt_info.bltadat = (SAER_Memory_chipData[pta] << 8) | SAER_Memory_chipData[pta + 1]; pta -= 2; } else { bltadat = blt_info.bltadat; } + bltadat &= blit_masktable[i]; + srca = (((bltadat << 16) | preva) >>> 0) >>> b.blitdownashift; + preva = bltadat; + if (dstp) { + SAER_Memory_chipData[dstp] = dstd >> 8; + SAER_Memory_chipData[dstp + 1] = dstd & 0xff; + } + dstd = srca & 0xffff; + totald |= dstd; + if (ptd) { dstp = ptd; ptd -= 2; } + } + if (pta) pta -= b.bltamod; + if (ptd) ptd -= b.bltdmod; + } + if (dstp) { + SAER_Memory_chipData[dstp] = dstd >> 8; + SAER_Memory_chipData[dstp + 1] = dstd & 0xff; + } + if (totald != 0) b.blitzero = 0; + } + + function blitdofast_fa(pta, ptb, ptc, ptd, b) { + var i,j; + var totald = 0; + var preva = 0; + var srcc = b.bltcdat; + var dstd = 0; + var dstp = 0; + for (j = 0; j < b.vblitsize; j++) { + for (i = 0; i < b.hblitsize; i++) { + var bltadat, srca; + if (ptc) { srcc = (SAER_Memory_chipData[ptc] << 8) | SAER_Memory_chipData[ptc + 1]; ptc += 2; } + if (pta) { bltadat = blt_info.bltadat = (SAER_Memory_chipData[pta] << 8) | SAER_Memory_chipData[pta + 1]; pta += 2; } else { bltadat = blt_info.bltadat; } + bltadat &= blit_masktable[i]; + srca = (((preva << 16) | bltadat) >>> 0) >>> b.blitashift; + preva = bltadat; + if (dstp) { + SAER_Memory_chipData[dstp] = dstd >> 8; + SAER_Memory_chipData[dstp + 1] = dstd & 0xff; + } + dstd = (srca | srcc) & 0xffff; + totald |= dstd; + if (ptd) { dstp = ptd; ptd += 2; } + } + if (pta) pta += b.bltamod; + if (ptc) ptc += b.bltcmod; + if (ptd) ptd += b.bltdmod; + } + b.bltcdat = srcc; + if (dstp) { + SAER_Memory_chipData[dstp] = dstd >> 8; + SAER_Memory_chipData[dstp + 1] = dstd & 0xff; + } + if (totald != 0) b.blitzero = 0; + } + + function blitdofast_desc_fa(pta, ptb, ptc, ptd, b) { + var totald = 0; + var i,j; + var preva = 0; + var srcc = b.bltcdat; + var dstd = 0; + var dstp = 0; + for (j = 0; j < b.vblitsize; j++) { + for (i = 0; i < b.hblitsize; i++) { + var bltadat, srca; + if (ptc) { srcc = (SAER_Memory_chipData[ptc] << 8) | SAER_Memory_chipData[ptc + 1]; ptc -= 2; } + if (pta) { bltadat = blt_info.bltadat = (SAER_Memory_chipData[pta] << 8) | SAER_Memory_chipData[pta + 1]; pta -= 2; } else { bltadat = blt_info.bltadat; } + bltadat &= blit_masktable[i]; + srca = (((bltadat << 16) | preva) >>> 0) >>> b.blitdownashift; + preva = bltadat; + if (dstp) { + SAER_Memory_chipData[dstp] = dstd >> 8; + SAER_Memory_chipData[dstp + 1] = dstd & 0xff; + } + dstd = (srca | srcc) & 0xffff; + totald |= dstd; + if (ptd) { dstp = ptd; ptd -= 2; } + } + if (pta) pta -= b.bltamod; + if (ptc) ptc -= b.bltcmod; + if (ptd) ptd -= b.bltdmod; + } + b.bltcdat = srcc; + if (dstp) { + SAER_Memory_chipData[dstp] = dstd >> 8; + SAER_Memory_chipData[dstp + 1] = dstd & 0xff; + } + if (totald != 0) b.blitzero = 0; + } + + function blitdofast_fc(pta, ptb, ptc, ptd, b) { + var i,j; + var totald = 0; + var preva = 0; + var prevb = 0, srcb = b.bltbhold; + var dstd = 0; + var dstp = 0; + for (j = 0; j < b.vblitsize; j++) { + for (i = 0; i < b.hblitsize; i++) { + var bltadat, srca; + if (ptb) { + var bltbdat = blt_info.bltbdat = (SAER_Memory_chipData[ptb] << 8) | SAER_Memory_chipData[ptb + 1]; ptb += 2; + srcb = (((prevb << 16) | bltbdat) >>> 0) >>> b.blitbshift; + prevb = bltbdat; + } + if (pta) { bltadat = blt_info.bltadat = (SAER_Memory_chipData[pta] << 8) | SAER_Memory_chipData[pta + 1]; pta += 2; } else { bltadat = blt_info.bltadat; } + bltadat &= blit_masktable[i]; + srca = (((preva << 16) | bltadat) >>> 0) >>> b.blitashift; + preva = bltadat; + if (dstp) { + SAER_Memory_chipData[dstp] = dstd >> 8; + SAER_Memory_chipData[dstp + 1] = dstd & 0xff; + } + dstd = (srca | srcb) & 0xffff; + totald |= dstd; + if (ptd) { dstp = ptd; ptd += 2; } + } + if (pta) pta += b.bltamod; + if (ptb) ptb += b.bltbmod; + if (ptd) ptd += b.bltdmod; + } + b.bltbhold = srcb; + if (dstp) { + SAER_Memory_chipData[dstp] = dstd >> 8; + SAER_Memory_chipData[dstp + 1] = dstd & 0xff; + } + if (totald != 0) b.blitzero = 0; + } + + function blitdofast_desc_fc(pta, ptb, ptc, ptd, b) { + var totald = 0; + var i,j; + var preva = 0; + var prevb = 0, srcb = b.bltbhold; + var dstd = 0; + var dstp = 0; + for (j = 0; j < b.vblitsize; j++) { + for (i = 0; i < b.hblitsize; i++) { + var bltadat, srca; + if (ptb) { + var bltbdat = blt_info.bltbdat = (SAER_Memory_chipData[ptb] << 8) | SAER_Memory_chipData[ptb + 1]; ptb -= 2; + srcb = (((bltbdat << 16) | prevb) >>> 0) >>> b.blitdownbshift; + prevb = bltbdat; + } + if (pta) { bltadat = blt_info.bltadat = (SAER_Memory_chipData[pta] << 8) | SAER_Memory_chipData[pta + 1]; pta -= 2; } else { bltadat = blt_info.bltadat; } + bltadat &= blit_masktable[i]; + srca = (((bltadat << 16) | preva) >>> 0) >>> b.blitdownashift; + preva = bltadat; + if (dstp) { + SAER_Memory_chipData[dstp] = dstd >> 8; + SAER_Memory_chipData[dstp + 1] = dstd & 0xff; + } + dstd = (srca | srcb) & 0xffff; + totald |= dstd; + if (ptd) { dstp = ptd; ptd -= 2; } + } + if (pta) pta -= b.bltamod; + if (ptb) ptb -= b.bltbmod; + if (ptd) ptd -= b.bltdmod; + } + b.bltbhold = srcb; + if (dstp) { + SAER_Memory_chipData[dstp] = dstd >> 8; + SAER_Memory_chipData[dstp + 1] = dstd & 0xff; + } + if (totald != 0) b.blitzero = 0; } } - diff --git a/sae/cia.js b/sae/cia.js index 84f8cc5..db09d7d 100644 --- a/sae/cia.js +++ b/sae/cia.js @@ -1,63 +1,68 @@ -/************************************************************************** -* SAE - Scripted Amiga Emulator -* -* 2012-2015 Rupert Hausberger -* -* https://github.com/naTmeg/ScriptedAmigaEmulator -* -*************************************************************************** -* Notes: Ported from WinUAE 2.5.0 -* -**************************************************************************/ +/*------------------------------------------------------------------------- +| SAE - Scripted Amiga Emulator +| https://github.com/naTmeg/ScriptedAmigaEmulator +| +| Copyright (C) 2012-2016 Rupert Hausberger +| +| This program is free software; you can redistribute it and/or +| modify it under the terms of the GNU General Public License +| as published by the Free Software Foundation; either version 2 +| of the License, or (at your option) any later version. +| +| This program is distributed in the hope that it will be useful, +| but WITHOUT ANY WARRANTY; without even the implied warranty of +| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +| GNU General Public License for more details. +| +| Note: ported from WinUAE 3.2.x +-------------------------------------------------------------------------*/ +/* global variables */ -/*const CIAA_DEBUG_R = 0; -const CIAA_DEBUG_W = 0; -const CIAB_DEBUG_R = 0; -const CIAB_DEBUG_W = 0; -const DONGLE_DEBUG = 0; -const KB_DEBUG = 0; -const CLOCK_DEBUG = 0;*/ +var SAEV_CIA_bank = null; -const TOD_HACK = 1; +/*---------------------------------*/ -/* e-clock is 10 CPU cycles, 4 cycles high, 6 low data transfer happens during 4 high cycles */ -const ECLOCK_DATA_CYCLE = 4; -const ECLOCK_WAIT_CYCLE = 6; +function SAEO_CIA() { + const TOD_HACK = true; -const DIV10 = ((ECLOCK_DATA_CYCLE + ECLOCK_WAIT_CYCLE) * CYCLE_UNIT / 2); /* Yes, a bad identifier. */ -const CIASTARTCYCLESHI = 3; -const CIASTARTCYCLESCRA = 2; + /* e-clock is 10 CPU cycles, 4 cycles high, 6 low data transfer happens during 4 high cycles */ + const ECLOCK_DATA_CYCLE = 4; + const ECLOCK_WAIT_CYCLE = 6; -//console.log('DIV10', CYCLE_UNIT, DIV10); + const DIV10 = (ECLOCK_DATA_CYCLE + ECLOCK_WAIT_CYCLE) * SAEC_Events_CYCLE_UNIT >> 1; /* Yes, a bad identifier. */ + const CIASTARTCYCLESHI = 3; + const CIASTARTCYCLESCRA = 2; -function CIA() { - var ciaaicr = 0, ciaaimask = 0, ciabicr = 0, ciabimask = 0; - var ciaacra = 0, ciaacrb = 0, ciabcra = 0, ciabcrb = 0; - var ciaastarta = 0, ciaastartb = 0, ciabstarta = 0, ciabstartb = 0; - var ciaaicr_reg = 0, ciabicr_reg = 0; + var ciaaicr = 0, ciaaimask = 0, ciabicr = 0, ciabimask = 0; //uint + var ciaacra = 0, ciaacrb = 0, ciabcra = 0, ciabcrb = 0; //uint + var ciaastarta = 0, ciaastartb = 0, ciabstarta = 0, ciabstartb = 0; //uint - var ciaata = 0, ciaatb = 0, ciabta = 0, ciabtb = 0; - var ciaata_passed = 0, ciaatb_passed = 0, ciabta_passed = 0, ciabtb_passed = 0; + /* Values of the CIA timers. */ + var ciaata = 0, ciaatb = 0, ciabta = 0, ciabtb = 0; //ulong + /* Computed by compute_passed_time. */ + var ciaata_passed = 0, ciaatb_passed = 0, ciabta_passed = 0, ciabtb_passed = 0; //ulong - var ciaatod = 0, ciabtod = 0, ciaatol = 0, ciabtol = 0, ciaaalarm = 0, ciabalarm = 0; - var ciaatlatch = 0, ciabtlatch = 0; - var oldled = false;//, oldovl = false, oldcd32mute = false; - var led = false; - var led_old_brightness = 0; - var led_cycles_on = 0, led_cycles_off = 0, led_cycle = 0; + var ciaatod = 0, ciabtod = 0, ciaatol = 0, ciabtol = 0, ciaaalarm = 0, ciabalarm = 0; //ulong + var ciaatlatch = 0, ciabtlatch = 0; //int + var oldovl = false, oldcd32mute = false; //bool + var led = false; //bool + var led_old_brightness = 0; //int + var led_cycles_on = 0, led_cycles_off = 0, led_cycle = 0; //ulong - var ciaala = 0, ciaalb = 0, ciabla = 0, ciablb = 0; - var ciaatodon = 0, ciabtodon = 0; - var ciaapra = 0, ciaaprb = 0, ciaadra = 0, ciaadrb = 0, ciaasdr = 0, ciaasdr_cnt = 0; - var ciabpra = 0, ciabprb = 0, ciabdra = 0, ciabdrb = 0, ciabsdr = 0, ciabsdr_cnt = 0; - var div10 = 0; - //var kbstate = 0, kblostsynccnt = 0, kbcode = 0; + var ciabpra = 0; //uint - //var serbits = 0; - var warned = 10; - //var rtc_delayed_write = 0; + var ciaala = 0, ciaalb = 0, ciabla = 0, ciablb = 0; //ulong + var ciaatodon = 0, ciabtodon = 0; //int + var ciaapra = 0, ciaaprb = 0, ciaadra = 0, ciaadrb = 0, ciaasdr = 0, ciaasdr_cnt = 0; //ulong + var ciabprb = 0, ciabdra = 0, ciabdrb = 0, ciabsdr = 0, ciabsdr_cnt = 0; //ulong + var div10 = 0; //int + var kbstate = 0, kblostsynccnt = 0; //int + var kbcode = 0; //u8 - /*function setclr (unsigned int *p, unsigned int val) { + var serbits = 0; //u8 + var warned = 10; //int + + /*static void setclr (unsigned int *p, unsigned int val) { if (val & 0x80) { *p |= val & 0x7F; } else { @@ -65,63 +70,59 @@ function CIA() { } }*/ - function setclra(val) { - if (val & 0x80) { - ciaaimask |= val & 0x7F; - } else { - ciaaimask &= ~val; - } + /* delay interrupt after current CIA register access if interrupt would have triggered mid access */ + var cia_interrupt_disabled = 0; //int + var cia_interrupt_delay = 0; //int + + /*-----------------------------------------------------------------------*/ + + function ICR(data) { + SAER.custom.INTREQ_0(SAEC_Custom_INTF_SETCLR | data); } - function setclrb(val) { - if (val & 0x80) { - ciabimask |= val & 0x7F; - } else { - ciabimask &= ~val; - } + + function ICRA(data) { + ciaaicr |= 0x40; + ciaaicr |= 0x20; + ICR(0x0008); + } + + function ICRB(data) { + ciabicr |= 0x40; + ciabicr |= 0x20; + if (SAEV_config.chipset.compatible == SAEC_Config_Chipset_Compatible_A1000V) + ICR(0x0008); /* Both CIAs in Velvet are connected to level 2 */ + else + ICR(0x2000); } function RethinkICRA() { - if (ciaaicr) { - if (ciaaimask & ciaaicr) { + if (ciaaicr & ciaaimask) { + if (!(ciaaicr & 0x80)) { ciaaicr |= 0x80; - AMIGA.INTREQ_0(0x8000 | 0x0008); + ICRA(0x0008); } - ciaaicr_reg |= ciaaicr; } } function RethinkICRB() { - if (ciabicr) { - if (ciabimask & ciabicr) { + if (ciabicr & ciabimask) { + if (!(ciabicr & 0x80)) { ciabicr |= 0x80; - AMIGA.INTREQ_0(0x8000 | 0x2000); + ICRB(0); } - ciabicr_reg |= ciabicr; } } - this.SetICRA = function (icr, sdr) { - ciaaicr |= icr; - ciaasdr = sdr; - RethinkICRA(); - }; - - this.SetICRB = function (icr, sdr) { - ciabicr |= icr; - if (sdr !== null) - ciabsdr = sdr; - RethinkICRB(); - }; - - this.rethink = function () { - RethinkICRA(); - RethinkICRB(); - }; + this.rethink = function() { //rethink_cias() + if (ciaaicr & 0x40) ICRA(0); + if (ciabicr & 0x40) ICRB(0); + } /* Figure out how many CIA timer cycles have passed for each timer since the last call of CIA_calctimers. */ + function compute_passed_time() { - var ccount = (AMIGA.events.currcycle - AMIGA.events.eventtab[EV_CIA].oldcycles + div10); - var ciaclocks = Math.floor(ccount / DIV10); + var ccount = SAEV_Events_currcycle - SAER_Events_eventtab[SAEC_Events_EV_CIA].oldcycles + div10; + var ciaclocks = ccount / DIV10 >>> 0; ciaata_passed = ciaatb_passed = ciabta_passed = ciabtb_passed = 0; @@ -132,7 +133,7 @@ function CIA() { cc -= ciaastarta; else cc = 0; - //assert((ciaata + 1) >= cc); + SAEF_assert((ciaata + 1) >= cc); ciaata_passed = cc; } if ((ciaacrb & 0x61) == 0x01) { @@ -141,7 +142,7 @@ function CIA() { cc -= ciaastartb; else cc = 0; - //assert((ciaatb + 1) >= cc); + SAEF_assert((ciaatb + 1) >= cc); ciaatb_passed = cc; } @@ -152,7 +153,7 @@ function CIA() { cc -= ciabstarta; else cc = 0; - //assert((ciabta + 1) >= cc); + SAEF_assert((ciabta + 1) >= cc); ciabta_passed = cc; } if ((ciabcrb & 0x61) == 0x01) { @@ -161,7 +162,7 @@ function CIA() { cc -= ciabstartb; else cc = 0; - //assert((ciabtb + 1) >= cc); + SAEF_assert((ciabtb + 1) >= cc); ciabtb_passed = cc; } } @@ -169,10 +170,9 @@ function CIA() { /* Called to advance all CIA timers to the current time. This expects that one of the timer values will be modified, and CIA_calctimers will be called in the same cycle. */ - function CIA_update_check() { - var ccount = (AMIGA.events.currcycle - AMIGA.events.eventtab[EV_CIA].oldcycles + div10); - var ciaclocks = Math.floor(ccount / DIV10); + var ccount = SAEV_Events_currcycle - SAER_Events_eventtab[SAEC_Events_EV_CIA].oldcycles + div10; + var ciaclocks = ccount / DIV10 >>> 0; var aovfla = 0, aovflb = 0, asp = 0, bovfla = 0, bovflb = 0, bsp = 0; var icr = 0; @@ -193,7 +193,7 @@ function CIA() { } } if (check) { - //assert((ciaata + 1) >= cc); + SAEF_assert((ciaata + 1) >= cc); if ((ciaata + 1) == cc) { if ((ciaacra & 0x48) == 0x40 && ciaasdr_cnt > 0 && --ciaasdr_cnt == 0) asp = 1; @@ -219,7 +219,7 @@ function CIA() { } } if (check) { - //assert((ciaatb + 1) >= cc); + SAEF_assert((ciaatb + 1) >= cc); if ((ciaatb + 1) == cc) aovflb = 1; ciaatb -= cc; @@ -240,7 +240,7 @@ function CIA() { } } if (check) { - //assert((ciabta + 1) >= cc); + SAEF_assert((ciabta + 1) >= cc); if ((ciabta + 1) == cc) { if ((ciabcra & 0x48) == 0x40 && ciabsdr_cnt > 0 && --ciabsdr_cnt == 0) bsp = 1; @@ -266,7 +266,7 @@ function CIA() { } } if (check) { - //assert((ciabtb + 1) >= cc); + SAEF_assert((ciabtb + 1) >= cc); if ((ciabtb + 1) == cc) bovflb = 1; ciabtb -= cc; @@ -309,13 +309,10 @@ function CIA() { } return icr; } - function CIA_update() { - var icr = CIA_update_check (); - if (icr & 1) - RethinkICRA(); - if (icr & 2) - RethinkICRB(); + var icr = CIA_update_check(); + if (icr & 1) RethinkICRA(); + if (icr & 2) RethinkICRB(); } /* Call this only after CIA_update has been called in the same cycle. */ @@ -323,103 +320,161 @@ function CIA() { var ciaatimea = -1, ciaatimeb = -1, ciabtimea = -1, ciabtimeb = -1; var div10diff = DIV10 - div10; - if ((ciaacra & 0x21) == 0x01) ciaatimea = div10diff + DIV10 * (ciaata + ciaastarta); - if ((ciaacrb & 0x61) == 0x01) ciaatimeb = div10diff + DIV10 * (ciaatb + ciaastartb); - if ((ciabcra & 0x21) == 0x01) ciabtimea = div10diff + DIV10 * (ciabta + ciabstarta); - if ((ciabcrb & 0x61) == 0x01) ciabtimeb = div10diff + DIV10 * (ciabtb + ciabstartb); + SAER_Events_eventtab[SAEC_Events_EV_CIA].oldcycles = SAEV_Events_currcycle; - AMIGA.events.eventtab[EV_CIA].oldcycles = AMIGA.events.currcycle; - AMIGA.events.eventtab[EV_CIA].active = (ciaatimea != -1 || ciaatimeb != -1 || ciabtimea != -1 || ciabtimeb != -1); - - if (AMIGA.events.eventtab[EV_CIA].active) { - var ciatime = CYCLE_MAX; - if (ciaatimea != -1) ciatime = ciaatimea; - if (ciaatimeb != -1 && ciaatimeb < ciatime) ciatime = ciaatimeb; - if (ciabtimea != -1 && ciabtimea < ciatime) ciatime = ciabtimea; - if (ciabtimeb != -1 && ciabtimeb < ciatime) ciatime = ciabtimeb; - AMIGA.events.eventtab[EV_CIA].evtime = ciatime + AMIGA.events.currcycle; + if ((ciaacra & 0x21) == 0x01) { + ciaatimea = div10diff + DIV10 * (ciaata + ciaastarta); } - AMIGA.events.schedule(); + /*#if 0 + if ((ciaacrb & 0x61) == 0x41) { + // Timer B will not get any pulses if Timer A is off. + if (ciaatimea >= 0) { + // If Timer A is in one-shot mode, and Timer B needs more than one pulse, it will not underflow. + if (ciaatb == 0 || (ciaacra & 0x8) == 0) { + // Otherwise, we can determine the time of the underflow. + // This may overflow, however. So just ignore this timer and use the fact that we"ll call CIA_handler for the A timer. + // ciaatimeb = ciaatimea + ciaala * DIV10 * ciaatb; + } + } + } + #endif*/ + if ((ciaacrb & 0x61) == 0x01) { + ciaatimeb = div10diff + DIV10 * (ciaatb + ciaastartb); + } + + if ((ciabcra & 0x21) == 0x01) { + ciabtimea = div10diff + DIV10 * (ciabta + ciabstarta); + } + /*#if 0 + if ((ciabcrb & 0x61) == 0x41) { + // Timer B will not get any pulses if Timer A is off. + if (ciabtimea >= 0) { + // If Timer A is in one-shot mode, and Timer B needs more than one pulse, it will not underflow. + if (ciabtb == 0 || (ciabcra & 0x8) == 0) { + // Otherwise, we can determine the time of the underflow. + // ciabtimeb = ciabtimea + ciabla * DIV10 * ciabtb; + } + } + } + #endif*/ + if ((ciabcrb & 0x61) == 0x01) { + ciabtimeb = div10diff + DIV10 * (ciabtb + ciabstartb); + } + + SAER_Events_eventtab[SAEC_Events_EV_CIA].active = (ciaatimea != -1 || ciaatimeb != -1 || ciabtimea != -1 || ciabtimeb != -1); + if (SAER_Events_eventtab[SAEC_Events_EV_CIA].active) { + var ciatime = SAEC_Events_CYCLE_MAX; + if (ciaatimea != -1) + ciatime = ciaatimea; + if (ciaatimeb != -1 && ciaatimeb < ciatime) + ciatime = ciaatimeb; + if (ciabtimea != -1 && ciabtimea < ciatime) + ciatime = ciabtimea; + if (ciabtimeb != -1 && ciabtimeb < ciatime) + ciatime = ciabtimeb; + SAER_Events_eventtab[SAEC_Events_EV_CIA].evtime = SAEV_Events_currcycle + ciatime; + } + SAER.events.schedule(); } - this.handler = function () { + this.handler = function() { //CIA_handler() CIA_update(); CIA_calctimers(); - }; + } - /*this.diskindex = function() { + this.diskindex = function() { //cia_diskindex() ciabicr |= 0x10; RethinkICRB(); } - this.parallelack = function() { + /*function cia_parallelack() { ciaaicr |= 0x10; RethinkICRA(); }*/ - function checkalarm (tod, alarm, inc) { + function checkalarm(tod, alarm, inc, ab) { if (tod == alarm) - return 1; + return true; + /*#if 0 + if (!ab) + return false; + #endif*/ + if (!SAEV_config.chipset.cia.todBug) + return false; if (!inc) - return 0; + return false; /* emulate buggy TODMED counter. * it counts: .. 29 2A 2B 2C 2D 2E 2F 20 30 31 32 .. - * (2F->20->30 only takes couple of cycles but it will trigger alarm.. - */ + * (2F->20->30 only takes couple of cycles but it will trigger alarm... */ if (tod & 0x000fff) - return 0; - if (((tod - 1) & 0xfff000) == alarm) - return 1; - return 0; + return false; + + return (((tod - 1) >>> 0) & 0xfff000) == alarm; } - function ciab_checkalarm(inc) { - if (checkalarm(ciabtod, ciabalarm, inc)) { - ciabicr |= 4; - RethinkICRB(); + //function munge24(x) { return x & (SAEV_config.cpu.model == SAEC_Config_CPU_Model_68000 ? 0x00ffffff : 0xffffffff); } + + function ciab_checkalarm(inc, irq) { + // hack: do not trigger alarm interrupt if KS code and both + // tod and alarm == 0. This incorrectly triggers on non-cycle exact + // modes. Real hardware value written to ciabtod by KS is always + // at least 1 or larger due to bus cycle delays when reading old value. + //#if 1 + //if ((munge24(SAER.cpu.m68k_getpc2()) & 0xFFF80000) != 0xF80000) { + if (!SAER.cpu.pc_in_rom()) { + if (ciabtod == 0 && ciabalarm == 0) + return false; } + //#endif + if (checkalarm(ciabtod, ciabalarm, inc, 1)) { + if (irq) { + ciabicr |= 4; + RethinkICRB(); + } + return true; + } + return false; } function ciaa_checkalarm(inc) { - if (checkalarm(ciaatod, ciaaalarm, inc)) { + if (checkalarm (ciaatod, ciaaalarm, inc, 0)) { ciaaicr |= 4; RethinkICRA(); } } - function gettimeofday() { - return Math.floor(new Date().getTime()); - } - -//#ifdef TOD_HACK - var tod_hack_tv = 0, tod_hack_tod = 0, tod_hack_tod_last = 0; - var tod_hack_enabled = -1; + //#ifdef TOD_HACK + var tod_hack_tv = 0, tod_hack_tod = 0, tod_hack_tod_last = 0; //u64 + var tod_hack_enabled = 0; //all int + var tod_hack_delay = 0; + var tod_diff_cnt = 0; + const TOD_HACK_DELAY = 50; const TOD_HACK_TIME = 312 * 50 * 10; function tod_hack_reset() { - //var tv; - //gettimeofday (&tv, NULL); - //tod_hack_tv = (uae_u64)tv.tv_sec * 1000000 + tv.tv_usec; - tod_hack_tv = gettimeofday(); + var tv = {}; + SAEF_gettimeofday(tv, null); + tod_hack_tv = tv.tv_sec * 1000000 + tv.tv_usec; tod_hack_tod = ciaatod; tod_hack_tod_last = tod_hack_tod; + tod_diff_cnt = 0; } -//#endif + //#endif - /*var heartbeat_cnt = 0; - function cia_heartbeat() { + var heartbeat_cnt = 0; //int + /*this.cia_heartbeat = function() { heartbeat_cnt = 10; }*/ var oldrate = 0; function do_tod_hack(dotod) { - //console.log('tod',tod_hack_enabled); - //var tv; - var t; + //struct timeval tv; + //static int oldrate; var rate; - var docount = 0; + var docount = false; if (tod_hack_enabled == 0) return; - /*if (!heartbeat_cnt) { + /*OWN + if (!heartbeat_cnt) { if (tod_hack_enabled > 0) tod_hack_enabled = -1; return; @@ -431,216 +486,357 @@ function CIA() { if (tod_hack_enabled > 1) { tod_hack_enabled--; if (tod_hack_enabled == 1) { - BUG.info('TOD HACK enabled'); + SAEF_log("cia.do_tod_hack() enabled"); tod_hack_reset(); } return; } - if (AMIGA.config.cia.tod == 0) - rate = Math.floor(AMIGA.playfield.vblank_hz + 0.5); - else if (AMIGA.config.cia.tod == 1) + if (SAEV_config.chipset.cia.tod == SAEC_Config_Chipset_CIA_TOD_VSync) { + rate = Math.floor(SAER.playfield.get_vblank_hz() + 0.5); + if (rate >= 59 && rate <= 61) + rate = 60; + if (rate >= 49 && rate <= 51) + rate = 50; + } else if (SAEV_config.chipset.cia.tod == SAEC_Config_Chipset_CIA_TOD_50Hz) rate = 50; else rate = 60; + if (rate <= 0) return; - if (rate != oldrate || ciaatod != tod_hack_tod_last) { - if (ciaatod != 0) BUG.info('TOD HACK reset %d,%d %d,%d', rate, oldrate, ciaatod, tod_hack_tod_last); + if (rate != oldrate || (ciaatod & 0xfff) != (tod_hack_tod_last & 0xfff)) { + SAEF_log("cia.do_tod_hack() reset"); tod_hack_reset(); oldrate = rate; - docount = 1; + docount = true; } - if (!dotod && AMIGA.config.cia.tod == 0) + + if (!dotod && SAEV_config.chipset.cia.tod == SAEC_Config_Chipset_CIA_TOD_VSync) return; - /*gettimeofday (&tv, NULL); - t = (uae_u64)tv.tv_sec * 1000000 + tv.tv_usec; - if (t - tod_hack_tv >= 1000000 / rate) { - tod_hack_tv += 1000000 / rate; - docount = 1; - }*/ - t = gettimeofday(); - if (t - tod_hack_tv >= Math.floor(1000 / rate)) { - tod_hack_tv += Math.floor(1000 / rate); - docount = 1; + if (tod_hack_delay > 0) { + tod_hack_delay--; + if (tod_hack_delay > 0) + return; + tod_hack_delay = TOD_HACK_DELAY; + } + + var tv = {}; + SAEF_gettimeofday(tv, null); + var t = tv.tv_sec * 1000000 + tv.tv_usec; + var base = 1000000 / rate >>> 0; + if (t - tod_hack_tv >= base) { + tod_hack_tv += base; + tod_diff_cnt += 1000000 - base * rate; + tod_hack_tv += (tod_diff_cnt / rate >>> 0); + tod_diff_cnt %= rate; + docount = true; } if (docount) { ciaatod++; ciaatod &= 0x00ffffff; tod_hack_tod_last = ciaatod; - ciaa_checkalarm(0); + ciaa_checkalarm(false); } } - //this.hsync_prehandler = function() {} + /*var resetwarning_phase = 0, resetwarning_timer = 0; //int - this.hsync_posthandler = function (dotod) { - if (ciabtodon && dotod) { - ciabtod++; - ciabtod &= 0xFFFFFF; - ciab_checkalarm(1); + function sendrw() { + setcode(AK_RESETWARNING); + ciaasdr = kbcode; + kblostsynccnt = 8 * maxvpos * 8; // 8 frames * 8 bits. + ciaaicr |= 8; + RethinkICRA (); + SAEF_log("cia.sendrw() sent reset warning code (phase=%d)", resetwarning_phase); + } + int resetwarning_do (int canreset) { + if (resetwarning_phase || SAR.m68k.halted > 0) { + if (canreset) { + resetwarning_phase = 0; + resetwarning_timer = 0; + } + return 0; } - if (AMIGA.config.cia.tod_hack && ciaatodon) + resetwarning_phase = 1; + resetwarning_timer = maxvpos_nom * 5; + SAEF_log("cia.resetwarning_do() triggered"); + sendrw(); + return 1; + } + static void resetwarning_check (void) { + if (resetwarning_timer > 0) { + resetwarning_timer--; + if (resetwarning_timer <= 0) { + SAEF_log("cia.resetwarning_check() forced reset. phase=%d", resetwarning_phase); + resetwarning_phase = -1; + kblostsynccnt = 0; + send_internalevent(INTERNALEVENT_KBRESET); + uae_reset(0, 1); + } + } + if (resetwarning_phase == 1) { + if (!kblostsynccnt) { // first AK_RESETWARNING handshake received + SAEF_log("cia.resetwarning_check() second phase..."); + resetwarning_phase = 2; + resetwarning_timer = maxvpos_nom * 5; + sendrw(); + } + } else if (resetwarning_phase == 2) { + if (ciaacra & 0x40) { // second AK_RESETWARNING handshake active + resetwarning_phase = 3; + SAEF_log("cia.resetwarning_check() reset warning SP = output"); + /* System won"t reset until handshake signal becomes inactive or 10s has passed + resetwarning_timer = 10 * maxvpos_nom * SAER.playfield.get_vblank_hz(); + } + } else if (resetwarning_phase == 3) { + if (!(ciaacra & 0x40)) { // second AK_RESETWARNING handshake disabled + SAEF_log("cia.resetwarning_check() reset warning end by software. reset."); + resetwarning_phase = -1; + kblostsynccnt = 0; + send_internalevent(INTERNALEVENT_KBRESET); + uae_reset (0, 1); + } + } + }*/ + + //this.hsync = function() {} //CIA_hsync_prehandler() + + function setcode(keycode) { + kbcode = ~((keycode << 1) | (keycode >> 7)) & 0xff; + } + + function keyreq() { + ciaasdr = kbcode; + kblostsynccnt = 8 * SAER.playfield.get_maxvpos() * 8; // 8 frames * 8 bits. + ciaaicr |= 8; + RethinkICRA(); + } + + /* All this complexity to lazy evaluate TOD increase. + * Only increase it cycle-exactly if it is visible to running program: + * causes interrupt or program is reading or writing TOD registers + */ + + var ciab_tod_hoffset = 0; //int + var ciab_tod_event_state = 0; //int + // TOD increase has extra 14-16 E-clock delay + // Possibly TICK input pin has built-in debounce circuit + const TOD_INC_DELAY = 14 * (ECLOCK_DATA_CYCLE + ECLOCK_WAIT_CYCLE) >> 1; + + function CIAB_tod_inc(irq) { + ciab_tod_event_state = 3; // done + if (!ciabtodon) + return; + ciabtod++; + ciabtod &= 0xFFFFFF; + ciab_checkalarm(true, irq); + } + + function CIAB_tod_inc_event(v) { + if (ciab_tod_event_state != 2) + return; + CIAB_tod_inc(true); + } + + // Someone reads or writes TOD registers, sync TOD increase + function CIAB_tod_check() { + if (ciab_tod_event_state != 1 || !ciabtodon) + return; + var hpos = SAER.events.current_hpos(); + hpos -= ciab_tod_hoffset; + if (hpos >= 0 || SAEV_config.cpu.speed < 0) { + // Program should see the changed TOD + CIAB_tod_inc(true); + return; + } + // Not yet, add event to guarantee exact TOD inc position + ciab_tod_event_state = 2; // event active + SAER.events.event2_newevent_xx(-1, -hpos, 0, CIAB_tod_inc_event); + } + + this.b_tod_handler = function(hoffset) { //CIAB_tod_handler() + if (!ciabtodon) + return; + ciab_tod_hoffset = hoffset + TOD_INC_DELAY; + ciab_tod_event_state = 1; // TOD inc needed + if (checkalarm((ciabtod + 1) & 0xffffff, ciabalarm, true, 1)) { + // causes interrupt on this line, add event + ciab_tod_event_state = 2; // event active + SAER.events.event2_newevent_xx (-1, ciab_tod_hoffset, 0, CIAB_tod_inc_event); + } + } + + //const RAWKEY_RESETWARNING = 0x78; + const RAWKEY_INIT_POWER_UP = 0xFD; + const RAWKEY_TERM_POWER_UP = 0xFE; + + function check_keyboard() { + if ((SAER.input.keyboard.keysAvail() || kbstate < 3) && !kblostsynccnt ) { + switch (kbstate) { + case 0: + kbcode = 0; //powerup resync + kbstate++; + break; + case 1: + setcode(RAWKEY_INIT_POWER_UP); + kbstate++; + break; + case 2: + setcode(RAWKEY_TERM_POWER_UP); + kbstate++; + break; + case 3: + kbcode = ~SAER.input.keyboard.nextKey() & 0xff; + break; + } + keyreq(); + } + } + + this.hsync_post = function(dotod) { //CIA_hsync_posthandler() + // Previous line was supposed to increase TOD but no one cared. Do it now. + if (ciab_tod_event_state == 1) + CIAB_tod_inc(false); + ciab_tod_event_state = 0; + + if (SAEV_config.chipset.cia.todHack && ciaatodon) do_tod_hack(dotod); /*if (resetwarning_phase) { - resetwarning_check (); - while (keys_available ()) - get_next_key (); - } else if ((keys_available () || kbstate < 3) && !kblostsynccnt && (hsync_counter & 15) == 0) { - switch (kbstate) { - case 0: - kbcode = 0; - kbstate++; - break; - case 1: - setcode(AK_INIT_POWERUP); - kbstate++; - break; - case 2: - setcode(AK_TERM_POWERUP); - kbstate++; - break; - case 3: - kbcode = ~get_next_key(); - break; - } - keyreq(); - }*/ - AMIGA.input.keyboard.hsync(); - }; + resetwarning_check(); + while (keys_available()) + get_next_key(); + } else*/ { + if ((SAEV_Events_hsync_counter & 15) == 0) + check_keyboard(); + } + } function calc_led(old_led) { - var c = AMIGA.events.currcycle; - var t = Math.floor((c - led_cycle) * CYCLE_UNIT_INV); + var c = SAEV_Events_currcycle; + var t = ((c - led_cycle) * SAEC_Events_CYCLE_UNIT_INV) >>> 0; if (old_led) led_cycles_on += t; else led_cycles_off += t; led_cycle = c; } - - var powerled_brightness = 255; - var powerled = true; function led_vsync() { - var v; - calc_led(led); + if (led_cycles_on && !led_cycles_off) - v = 255; + var v = 255; else if (led_cycles_off && !led_cycles_on) - v = 0; + var v = 0; else if (led_cycles_off) - v = Math.floor(led_cycles_on * 255 / (led_cycles_on + led_cycles_off)); + var v = ~~(led_cycles_on * 255 / (led_cycles_on + led_cycles_off)); else + var v = 255; + + if (v < 0) + v = 0; + else if (v > 255) v = 255; - if (v < 0) v = 0; - if (v > 255) v = 255; - /*gui_data.powerled_brightness = v; - if (led_old_brightness != gui_data.powerled_brightness) { - gui_data.powerled = gui_data.powerled_brightness > 127; - gui_led (LED_POWER, gui_data.powerled); - led_filter_audio (); - } - led_old_brightness = gui_data.powerled_brightness;*/ - - powerled_brightness = v; - if (led_old_brightness != powerled_brightness) { - powerled = powerled_brightness > 127; - AMIGA.config.hooks.power_led(powerled); - AMIGA.audio.filter.led_filter_on = powerled; - } - led_old_brightness = powerled_brightness; - - led_cycle = AMIGA.events.currcycle; led_cycles_on = 0; led_cycles_off = 0; + SAER.gui.data.powerled_brightness = v; + if (led_old_brightness != SAER.gui.data.powerled_brightness) { + SAER.gui.data.powerled = SAER.gui.data.powerled_brightness > 127; + SAER.gui.led(SAEC_GUI_LED_POWER, SAER.gui.data.powerled, SAER.gui.data.powerled_brightness); + SAER.audio.led_filter_audio(); + } + led_old_brightness = v; + led_cycle = SAEV_Events_currcycle; } - this.vsync_prehandler = function () { - /*if (rtc_delayed_write < 0) { - rtc_delayed_write = 50; - } else if (rtc_delayed_write > 0) { - rtc_delayed_write--; - if (rtc_delayed_write == 0) - write_battclock (); - }*/ + this.vsync = function() { //CIA_vsync_prehandler() + if (heartbeat_cnt > 0) + heartbeat_cnt--; + if (SAEV_RTC_delayed_write < 0) + SAEV_RTC_delayed_write = 50; + else if (SAEV_RTC_delayed_write > 0) { + SAEV_RTC_delayed_write--; + if (SAEV_RTC_delayed_write == 0) + SAER.rtc.write(); + } led_vsync(); this.handler(); - /*if (kblostsynccnt > 0) { - kblostsynccnt -= maxvpos; - if (kblostsynccnt <= 0) { - kblostsynccnt = 0; - keyreq (); - write_log (_T('lostsync\n')); - } - }*/ - AMIGA.input.keyboard.vsync(); - }; - this.vsync_posthandler = function (dotod) { - //if (heartbeat_cnt > 0) heartbeat_cnt--; - if (TOD_HACK) { - if (AMIGA.config.cia.tod_hack && tod_hack_enabled == 1) - return; + if (kblostsynccnt > 0) { + kblostsynccnt -= SAER.playfield.get_maxvpos(); + if (kblostsynccnt <= 0) { + kblostsynccnt = 0; + keyreq(); + } } - if (ciaatodon && dotod) { - ciaatod++; - ciaatod &= 0xFFFFFF; - ciaa_checkalarm(1); - } - /*if (vpos == 0) { - write_log ('%d', vsync_counter); - this.dump(); - }*/ - }; + } - function bfe001_change() { + function CIAA_tod_handler(v) { + ciaatod++; + ciaatod &= 0xFFFFFF; + ciaa_checkalarm(true); + } + + this.a_tod_inc = function(cycles) { //CIAA_tod_inc() + //#ifdef TOD_HACK + if (SAEV_config.chipset.cia.todHack && tod_hack_enabled == 1) + return; + //#endif + if (!ciaatodon) + return; + + SAER.events.event2_newevent_xx(-1, cycles + TOD_INC_DELAY, 0, CIAA_tod_handler); + } + + function check_led() { var v = ciaapra; - var led2; - v |= ~ciaadra; /* output is high when pin's direction is input */ - led2 = (v & 2) ? 0 : 1; + v |= ~ciaadra; /* output is high when pin"s direction is input */ + var led2 = (v & 2) ? 0 : 1; if (led2 != led) { calc_led(led); led = led2; led_old_brightness = -1; } - /*if (currprefs.cs_ciaoverlay && (v & 1) != oldovl) { + } + + function bfe001_change() { + var v = ciaapra; + check_led(); + if (SAEV_config.chipset.cia.overlay && (v & 1) != oldovl) { oldovl = v & 1; - if (!oldovl) { - map_overlay (1); - } else { - //activate_debugger (); - map_overlay (0); - } + if (!oldovl) + SAER.memory.mapOverlay(true); + else + SAER.memory.mapOverlay(false); } - if (currprefs.cs_cd32cd && (v & 1) != oldcd32mute) { + /*if (currprefs.cs_cd32cd && (v & 1) != oldcd32mute) { oldcd32mute = v & 1; akiko_mute (oldcd32mute ? 0 : 1); }*/ } - + function handle_joystick_buttons(pra, dra) { var tmp = 0; - if (AMIGA.config.ports[0].type == SAEV_Config_Ports_Type_Mouse) { - if (!AMIGA.input.mouse.button[0]) tmp |= 0x40; + if (SAEV_config.ports[0].type == SAEC_Config_Ports_Type_Mouse) { + if (!SAER.input.mouse.button[0]) tmp |= 0x40; if (dra & 0x40) tmp = (tmp & ~0x40) | (pra & 0x40); - } else if (AMIGA.config.ports[0].type == SAEV_Config_Ports_Type_Joy0) { - if (!AMIGA.input.joystick[0].button[0]) tmp |= 0x40; + } else if (SAEV_config.ports[0].type == SAEC_Config_Ports_Type_Joy0) { + if (!SAER.input.joystick[0].button[0]) tmp |= 0x40; if (dra & 0x40) tmp = (tmp & ~0x40) | (pra & 0x40); } else tmp |= 0x40; - if (AMIGA.config.ports[1].type == SAEV_Config_Ports_Type_Joy1) { - if (!AMIGA.input.joystick[1].button[0]) tmp |= 0x80; + if (SAEV_config.ports[1].type == SAEC_Config_Ports_Type_Joy1) { + if (!SAER.input.joystick[1].button[0]) tmp |= 0x80; if (dra & 0x80) tmp = (tmp & ~0x80) | (pra & 0x80); } else tmp |= 0x80; return tmp; } - + function handle_parport_joystick (port, pra, dra) { var v; switch (port) { @@ -654,94 +850,153 @@ function CIA() { return 0; } } - + + function getciatod(tod) { + if (SAEV_config.chipset.cia.type6526) { + var bcdtod = 0; //u32 + for (var i = 0; i < 4; i++) { + var val = tod % 10; + bcdtod *= 16; if (bcdtod > 0xffffffff) bcdtod -= 0x100000000; + bcdtod += val; if (bcdtod > 0xffffffff) bcdtod -= 0x100000000; + tod = tod / 10 >>> 0; + } + return bcdtod; + } + return tod; + } + + function calc_bintod(v) { //OWN + var bintod = 0; + for (var i = 0; i < 4; i++) { + var val = v / 16 >>> 0; + bintod *= 10; if (bintod > 0xffffffff) bintod -= 0x100000000; + bintod += val; if (bintod > 0xffffffff) bintod -= 0x100000000; + v = v / 16 >>> 0; + } + return bintod; + } + //function setciatod(*tod, v) { + function setciatod_ciaatod(v) { + ciaatod = SAEV_config.chipset.cia.type6526 ? calc_bintod(v) : v; + } + function setciatod_ciaaalarm(v) { + ciaaalarm = SAEV_config.chipset.cia.type6526 ? calc_bintod(v) : v; + } + function setciatod_ciabtod(v) { + ciabtod = SAEV_config.chipset.cia.type6526 ? calc_bintod(v) : v; + } + function setciatod_ciabalarm(v) { + ciabalarm = SAEV_config.chipset.cia.type6526 ? calc_bintod(v) : v; + } + function ReadCIAA(addr) { var tmp; var reg = addr & 15; compute_passed_time(); - //if (CIAA_DEBUG_R) write_log (_T('R_CIAA: bfe%x01 %08X\n'), reg, M68K_GETPC); - switch (reg) { case 0: - tmp = AMIGA.disk.status() & 0x3c; + /*#ifdef ACTION_REPLAY + action_replay_cia_access(false); + #endif*/ + tmp = SAER.disk.status_ciaa() & 0x3c; tmp |= handle_joystick_buttons(ciaapra, ciaadra); tmp |= (ciaapra | (ciaadra ^ 3)) & 0x03; - //tmp = dongle_cia_read (0, reg, tmp); - //if (DONGLE_DEBUG && notinrom()) write_log (_T('BFE001 R %02X %s\n'), tmp, debuginfo(0)); + //tmp = dongle_cia_read(0, reg, tmp); return tmp; case 1: -/*#ifdef PARALLEL_PORT + /*#ifdef PARALLEL_PORT if (isprinter () > 0) { tmp = ciaaprb; } else if (isprinter () < 0) { uae_u8 v; parallel_direct_read_data (&v); tmp = v; + #ifdef ARCADIA + } else if (arcadia_bios) { + tmp = arcadia_parport (0, ciaaprb, ciaadrb); + #endif } else if (currprefs.win32_samplersoundcard >= 0) { tmp = sampler_getsample ((ciabpra & 4) ? 1 : 0); - } else -#endif*/ - { + #endif + }*/ { tmp = handle_parport_joystick(0, ciaaprb, ciaadrb); - //tmp = dongle_cia_read (1, reg, tmp); - //if (DONGLE_DEBUG && notinrom()) write_log (_T('BFE101 R %02X %s\n'), tmp, debuginfo(0)); + //tmp = dongle_cia_read(1, reg, tmp); } if (ciaacrb & 2) { var pb7 = 0; if (ciaacrb & 4) pb7 = ciaacrb & 1; tmp &= ~0x80; - tmp |= pb7 ? 0x80 : 0; + tmp |= pb7 ? 0x80 : 00; } if (ciaacra & 2) { var pb6 = 0; if (ciaacra & 4) pb6 = ciaacra & 1; tmp &= ~0x40; - tmp |= pb6 ? 0x40 : 0; + tmp |= pb6 ? 0x40 : 00; } return tmp; case 2: - //if (DONGLE_DEBUG && notinrom()) write_log (_T('BFE201 R %02X %s\n'), ciaadra, debuginfo(0)); return ciaadra; case 3: - //if (DONGLE_DEBUG && notinrom()) write_log (_T('BFE301 R %02X %s\n'), ciaadrb, debuginfo(0)); return ciaadrb; case 4: return (ciaata - ciaata_passed) & 0xff; case 5: - return ((ciaata - ciaata_passed) >> 8) & 0xff; + return ((ciaata - ciaata_passed) >>> 8) & 0xff; case 6: return (ciaatb - ciaatb_passed) & 0xff; case 7: - return ((ciaatb - ciaatb_passed) >> 8) & 0xff; + return ((ciaatb - ciaatb_passed) >>> 8) & 0xff; case 8: if (ciaatlatch) { ciaatlatch = 0; - return ciaatol & 0xff; + return getciatod(ciaatol) & 0xff; } else - return ciaatod & 0xff; + return getciatod(ciaatod) & 0xff; case 9: if (ciaatlatch) - return (ciaatol >> 8) & 0xff; + return (getciatod(ciaatol) >>> 8) & 0xff; else - return (ciaatod >> 8) & 0xff; + return (getciatod(ciaatod) >>> 8) & 0xff; case 10: - if (!ciaatlatch) { - if (!(ciaacrb & 0x80)) - ciaatlatch = 1; - ciaatol = ciaatod; + /* only if not already latched. A1200 confirmed. (TW) */ + if (!SAEV_config.chipset.cia.type6526) { + if (!ciaatlatch) { + /* no latching if ALARM is set */ + if (!(ciaacrb & 0x80)) + ciaatlatch = 1; + ciaatol = ciaatod; + } + return (getciatod(ciaatol) >>> 16) & 0xff; + } else { + if (ciaatlatch) + return (getciatod(ciaatol) >>> 16) & 0xff; + else + return (getciatod(ciaatod) >>> 16) & 0xff; } - return (ciaatol >> 16) & 0xff; + break; + case 11: + if (SAEV_config.chipset.cia.type6526) { + if (!ciaatlatch) { + if (!(ciaacrb & 0x80)) + ciaatlatch = 1; + ciaatol = ciaatod; + } + if (ciaatlatch) + return getciatod(ciaatol) >>> 24; + else + return getciatod(ciaatod) >>> 24; + } + break; case 12: return ciaasdr; case 13: - tmp = ciaaicr_reg; - ciaaicr &= ~ciaaicr_reg; - ciaaicr_reg = 0; - RethinkICRA(); + tmp = ciaaicr & ~(0x40 | 0x20); + ciaaicr = 0; return tmp; case 14: return ciaacra; @@ -755,15 +1010,19 @@ function CIA() { var tmp; var reg = addr & 15; - //if ((addr >= 8 && addr <= 10) || CIAB_DEBUG_R > 1) write_log (_T('R_CIAB: bfd%x00 %08X\n'), reg, M68K_GETPC); - - compute_passed_time (); + compute_passed_time(); switch (reg) { case 0: - //if (currprefs.use_serial) - tmp = AMIGA.serial.readStatus(ciabdra); -/*#ifdef PARALLEL_PORT + tmp = 0; + /*#ifdef ARCADIA + // CD inactive, Arcadia bios 4.00 does not detect printer + if (arcadia_bios && !SAEV_config.serial.enabled) + tmp = 0x20; + #endif*/ + if (SAEV_config.serial.enabled) + tmp = SAER.serial.readstatus(ciabdra); + /*#ifdef PARALLEL_PORT if (isprinter () > 0) { //tmp |= ciabpra & (0x04 | 0x02 | 0x01); tmp &= ~3; // clear BUSY and PAPEROUT @@ -772,31 +1031,29 @@ function CIA() { uae_u8 v; parallel_direct_read_status (&v); tmp |= v & 7; - } else -#endif*/ - { + }*/ { tmp |= handle_parport_joystick(1, ciabpra, ciabdra); - //tmp = dongle_cia_read (1, reg, tmp); - //if (DONGLE_DEBUG && notinrom()) write_log (_T('BFD000 R %02X %s\n'), tmp, debuginfo(0)); } + //#endif + //tmp = dongle_cia_read(1, reg, tmp); return tmp; case 1: - //if (DONGLE_DEBUG && notinrom()) write_log (_T('BFD100 R %02X %s\n'), ciabprb, debuginfo(0)); tmp = ciabprb; + tmp = SAER.disk.status_ciab(tmp); //tmp = dongle_cia_read(1, reg, tmp); if (ciabcrb & 2) { var pb7 = 0; if (ciabcrb & 4) pb7 = ciabcrb & 1; tmp &= ~0x80; - tmp |= pb7 ? 0x80 : 0; + tmp |= pb7 ? 0x80 : 00; } if (ciabcra & 2) { var pb6 = 0; if (ciabcra & 4) pb6 = ciabcra & 1; tmp &= ~0x40; - tmp |= pb6 ? 0x40 : 0; + tmp |= pb6 ? 0x40 : 00; } return tmp; case 2: @@ -806,39 +1063,60 @@ function CIA() { case 4: return (ciabta - ciabta_passed) & 0xff; case 5: - return ((ciabta - ciabta_passed) >> 8) & 0xff; + return ((ciabta - ciabta_passed) >>> 8) & 0xff; case 6: return (ciabtb - ciabtb_passed) & 0xff; case 7: - return ((ciabtb - ciabtb_passed) >> 8) & 0xff; + return ((ciabtb - ciabtb_passed) >>> 8) & 0xff; case 8: + CIAB_tod_check(); if (ciabtlatch) { ciabtlatch = 0; - return ciabtol & 0xff; + return getciatod(ciabtol) & 0xff; } else - return ciabtod & 0xff; + return getciatod(ciabtod) & 0xff; case 9: + CIAB_tod_check(); if (ciabtlatch) - return (ciabtol >> 8) & 0xff; + return (getciatod(ciabtol) >>> 8) & 0xff; else - return (ciabtod >> 8) & 0xff; + return (getciatod(ciabtod) >>> 8) & 0xff; case 10: - if (!ciabtlatch) { - if (!(ciabcrb & 0x80)) - ciabtlatch = 1; - ciabtol = ciabtod; + CIAB_tod_check(); + if (!SAEV_config.chipset.cia.type6526) { + if (!ciabtlatch) { + /* no latching if ALARM is set */ + if (!(ciabcrb & 0x80)) + ciabtlatch = 1; + ciabtol = ciabtod; + } + return (getciatod(ciabtol) >>> 16) & 0xff; + } else { + if (ciabtlatch) + return (getciatod(ciabtol) >>> 16) & 0xff; + else + return (getciatod(ciabtod) >>> 16) & 0xff; } - return (ciabtol >> 16) & 0xff; + case 11: + if (SAEV_config.chipset.cia.type6526) { + if (!ciabtlatch) { + if (!(ciabcrb & 0x80)) + ciabtlatch = 1; + ciabtol = ciabtod; + } + if (ciabtlatch) + return getciatod(ciabtol) >>> 24; + else + return getciatod(ciabtod) >>> 24; + } + break; case 12: return ciabsdr; case 13: - tmp = ciabicr_reg; - ciabicr &= ~ciabicr_reg; - ciabicr_reg = 0; - RethinkICRB(); + tmp = ciabicr & ~(0x40 | 0x20); + ciabicr = 0; return tmp; case 14: - //write_log (_T('CIABCRA READ %d %x\n'), ciabcra, M68K_GETPC); return ciabcra; case 15: return ciabcrb; @@ -849,44 +1127,54 @@ function CIA() { function WriteCIAA(addr, val) { var reg = addr & 15; - //if (CIAA_DEBUG_W) write_log (_T('W_CIAA: bfe%x01 %02X %08X\n'), reg, val, M68K_GETPC); - - /*if (!currprefs.cs_ciaoverlay && oldovl) { - map_overlay (1); + /*#ifdef ACTION_REPLAY + ar_ciaa[reg] = val; + #endif*/ + if (!SAEV_config.chipset.cia.overlay && oldovl) { + SAER.memory.mapOverlay(true); oldovl = 0; - }*/ + } switch (reg) { case 0: - //if (DONGLE_DEBUG && notinrom()) write_log (_T('BFE001 W %02X %s\n'), val, debuginfo(0)); ciaapra = (ciaapra & ~0xc3) | (val & 0xc3); bfe001_change(); - //handle_cd32_joystick_cia(ciaapra, ciaadra); + //handle_cd32_joystick_cia (ciaapra, ciaadra); //dongle_cia_write (0, reg, val); + + //if (is_device_rom(SAEV_config, SAEC_RomType_AMAX, 0) > 0) + if (SAEV_config.memory.amaxRom.size > 0) + SAER.disk.amax_bfe001_write(val, ciaadra); + break; case 1: - //if (DONGLE_DEBUG && notinrom()) write_log (_T('BFE101 W %02X %s\n'), val, debuginfo(0)); ciaaprb = val; //dongle_cia_write (0, reg, val); -/*#ifdef PARALLEL_PORT + /*#ifdef PARALLEL_PORT if (isprinter() > 0) { doprinter (val); - this.parallelack(); + cia_parallelack (); } else if (isprinter() < 0) { parallel_direct_write_data (val, ciaadrb); - this.parallelack(); + cia_parallelack (); + #ifdef ARCADIA + } else if (arcadia_bios) { + arcadia_parport (1, ciaaprb, ciaadrb); + #endif } -#endif*/ + #endif*/ break; case 2: - //if (DONGLE_DEBUG && notinrom()) write_log (_T('BFE201 W %02X %s\n'), val, debuginfo(0)); ciaadra = val; - //dongle_cia_write (0, reg, val); + //dongle_cia_write(0, reg, val); bfe001_change(); break; case 3: ciaadrb = val; - //dongle_cia_write (0, reg, val); - //if (DONGLE_DEBUG && notinrom()) write_log (_T('BFE301 W %02X %s\n'), val, debuginfo(0)); + //dongle_cia_write(0, reg, val); + /*#ifdef ARCADIA + if (arcadia_bios) + arcadia_parport (1, ciaaprb, ciaadrb); + #endif*/ break; case 4: CIA_update(); @@ -924,26 +1212,45 @@ function CIA() { break; case 8: if (ciaacrb & 0x80) { - ciaaalarm = (ciaaalarm & ~0xff) | val; + //setciatod(&ciaaalarm, (getciatod(ciaaalarm) & ~0xff) | val); + setciatod_ciaaalarm(((getciatod(ciaaalarm) & 0xffffff00) | val) >>> 0); } else { - ciaatod = (ciaatod & ~0xff) | val; + //setciatod(&ciaatod, (getciatod(ciaatod) & ~0xff) | val); + setciatod_ciaatod(((getciatod(ciaatod) & 0xffffff00) | val) >>> 0); ciaatodon = 1; - ciaa_checkalarm(0); + ciaa_checkalarm(false); } break; case 9: if (ciaacrb & 0x80) { - ciaaalarm = (ciaaalarm & ~0xff00) | (val << 8); + //setciatod(&ciaaalarm, (getciatod(ciaaalarm) & ~0xff00) | (val << 8)); + setciatod_ciaaalarm(((getciatod(ciaaalarm) & 0xffff00ff) | (val << 8)) >>> 0); } else { - ciaatod = (ciaatod & ~0xff00) | (val << 8); + //setciatod(&ciaatod, (getciatod(ciaatod) & ~0xff00) | (val << 8)); + setciatod_ciaatod(((getciatod(ciaatod) & 0xffff00ff) | (val << 8)) >>> 0); } break; case 10: if (ciaacrb & 0x80) { - ciaaalarm = (ciaaalarm & ~0xff0000) | (val << 16); + //setciatod(&ciaaalarm, (getciatod(ciaaalarm) & ~0xff0000) | (val << 16)); + setciatod_ciaaalarm(((getciatod(ciaaalarm) & 0xff00ffff) | (val << 16)) >>> 0); } else { - ciaatod = (ciaatod & ~0xff0000) | (val << 16); - ciaatodon = 0; + //setciatod(&ciaatod, (getciatod(ciaatod) & ~0xff0000) | (val << 16)); + setciatod_ciaatod(((getciatod(ciaatod) & 0xff00ffff) | (val << 16)) >>> 0); + if (!SAEV_config.chipset.cia.type6526) + ciaatodon = 0; + } + break; + case 11: + if (SAEV_config.chipset.cia.type6526) { + if (ciaacrb & 0x80) { + //setciatod(&ciaaalarm, (getciatod(ciaaalarm) & ~0xff000000) | (val << 24)); + setciatod_ciaaalarm(((getciatod(ciaaalarm) & 0x00ffffff) | (val << 24)) >>> 0); + } else { + //setciatod(&ciaatod, (getciatod(ciaatod) & ~0xff000000) | (val << 24)); + setciatod_ciaatod(((getciatod(ciaatod) & 0x00ffffff) | (val << 24)) >>> 0); + ciaatodon = 0; + } } break; case 12: @@ -951,10 +1258,13 @@ function CIA() { ciaasdr = val; if ((ciaacra & 0x41) == 0x41 && ciaasdr_cnt == 0) ciaasdr_cnt = 8 * 2; + CIA_calctimers(); break; case 13: - setclra(val); + //setclr(&ciaaimask, val); + if (val & 0x80) ciaaimask |= val & 0x7F; else ciaaimask &= ~val; + RethinkICRA(); break; case 14: CIA_update(); @@ -962,8 +1272,8 @@ function CIA() { if ((val & 1) && !(ciaacra & 1)) ciaastarta = CIASTARTCYCLESCRA; if ((val & 0x40) == 0 && (ciaacra & 0x40) != 0) { - AMIGA.input.keyboard.lostsynccnt = 0; - //if (KB_DEBUG) BUG.info('KB_ACK %02x->%02x', ciaacra, val); + /* todo: check if low to high or high to low only */ + kblostsynccnt = 0; } ciaacra = val; if (ciaacra & 0x10) { @@ -986,38 +1296,40 @@ function CIA() { } } - function WriteCIAB(addr, val) { + function WriteCIAB(addr, val) { var reg = addr & 15; - //if ((addr >= 8 && addr <= 10) || CIAB_DEBUG_W > 1) write_log (_T('W_CIAB: bfd%x00 %02X %08X\n'), reg, val, M68K_GETPC); + /*#ifdef ACTION_REPLAY + ar_ciab[reg] = val; + #endif*/ switch (reg) { case 0: - //if (DONGLE_DEBUG && notinrom()) write_log (_T('BFD000 W %02X %s\n'), val, debuginfo(0)); - //dongle_cia_write (1, reg, val); + //dongle_cia_write(1, reg, val); ciabpra = val; - //if (currprefs.use_serial) - AMIGA.serial.writeStatus(ciabpra, ciabdra); -/*#ifdef PARALLEL_PORT - if (isprinter () < 0) + if (SAEV_config.serial.enabled) + SAER.serial.writestatus(ciabpra, ciabdra); + /*#ifdef PARALLEL_PORT + if (isprinter () < 0) { parallel_direct_write_status (val, ciabdra); -#endif*/ + } + #endif*/ break; case 1: - //if (DONGLE_DEBUG && notinrom()) write_log (_T('BFD100 W %02X %s\n'), val, debuginfo(0)); - //dongle_cia_write (1, reg, val); + /*#ifdef ACTION_REPLAY + action_replay_cia_access(true); + #endif*/ + //dongle_cia_write(1, reg, val); ciabprb = val; - AMIGA.disk.select(val); + SAER.disk.select(val); break; case 2: - //if (DONGLE_DEBUG && notinrom()) write_log (_T('BFD200 W %02X %s\n'), val, debuginfo(0)); - //dongle_cia_write (1, reg, val); + //dongle_cia_write(1, reg, val); ciabdra = val; - //if (currprefs.use_serial) - AMIGA.serial.writeStatus(ciabpra, ciabdra); + if (SAEV_config.serial.enabled) + SAER.serial.writestatus(ciabpra, ciabdra); break; case 3: - //if (DONGLE_DEBUG && notinrom()) write_log (_T('BFD300 W %02X %s\n'), val, debuginfo(0)); - //dongle_cia_write (1, reg, val); + //dongle_cia_write(1, reg, val); ciabdrb = val; break; case 4: @@ -1055,27 +1367,50 @@ function CIA() { CIA_calctimers(); break; case 8: + CIAB_tod_check(); if (ciabcrb & 0x80) { - ciabalarm = (ciabalarm & ~0xff) | val; + //setciatod(&ciabalarm, (getciatod(ciabalarm) & ~0xff) | val); + setciatod_ciabalarm(((getciatod(ciabalarm) & 0xffffff00) | val) >>> 0); } else { - ciabtod = (ciabtod & ~0xff) | val; + //setciatod(&ciabtod, (getciatod(ciabtod) & ~0xff) | val); + setciatod_ciabtod(((getciatod(ciabtod) & 0xffffff00) | val) >>> 0); ciabtodon = 1; - ciab_checkalarm (0); + ciab_checkalarm(false, true); } break; case 9: + CIAB_tod_check (); if (ciabcrb & 0x80) { - ciabalarm = (ciabalarm & ~0xff00) | (val << 8); + //setciatod(&ciabalarm, (getciatod(ciabalarm) & ~0xff00) | (val << 8)); + setciatod_ciabalarm(((getciatod(ciabalarm) & 0xffff00ff) | (val << 8)) >>> 0); } else { - ciabtod = (ciabtod & ~0xff00) | (val << 8); + //setciatod(&ciabtod, (getciatod(ciabtod) & ~0xff00) | (val << 8)); + setciatod_ciabtod(((getciatod(ciabtod) & 0xffff00ff) | (val << 8)) >>> 0); } break; case 10: + CIAB_tod_check(); if (ciabcrb & 0x80) { - ciabalarm = (ciabalarm & ~0xff0000) | (val << 16); + //setciatod(&ciabalarm, (getciatod(ciabalarm) & ~0xff0000) | (val << 16)); + setciatod_ciabalarm(((getciatod(ciabalarm) & 0xff00ffff) | (val << 16)) >>> 0); } else { - ciabtod = (ciabtod & ~0xff0000) | (val << 16); - ciabtodon = 0; + //setciatod(&ciabtod, (getciatod(ciabtod) & ~0xff0000) | (val << 16)); + setciatod_ciabtod(((getciatod(ciabtod) & 0xff00ffff) | (val << 16)) >>> 0); + if (!SAEV_config.chipset.cia.type6526) + ciabtodon = 0; + } + break; + case 11: + if (SAEV_config.chipset.cia.type6526) { + CIAB_tod_check(); + if (ciabcrb & 0x80) { + //setciatod(&ciabalarm, (getciatod(ciabalarm) & ~0xff000000) | (val << 24)); + setciatod_ciabalarm(((getciatod(ciabalarm) & 0x00ffffff) | (val << 24)) >>> 0); + } else { + //setciatod(&ciabtod, (getciatod(ciabtod) & ~0xff000000) | (val << 24)); + setciatod_ciabtod(((getciatod(ciabtod) & 0x00ffffff) | (val << 24)) >>> 0); + ciabtodon = 0; + } } break; case 12: @@ -1088,7 +1423,9 @@ function CIA() { CIA_calctimers(); break; case 13: - setclrb(val); + //setclr(&ciabimask, val); + if (val & 0x80) ciabimask |= val & 0x7F; else ciabimask &= ~val; + RethinkICRB(); break; case 14: CIA_update(); @@ -1116,214 +1453,273 @@ function CIA() { } } - this.setup = function () { - }; + /*this.cia_set_overlay = function(overlay) { + oldovl = overlay; + }*/ - this.reset = function () { - if (TOD_HACK) { - tod_hack_tv = 0; - tod_hack_tod = 0; - tod_hack_enabled = 0; - if (AMIGA.config.cia.tod_hack) - tod_hack_enabled = TOD_HACK_TIME; - } - //kblostsynccnt = 0; - //serbits = 0; - //oldcd32mute = 1; - oldled = true; + /*-----------------------------------------------------------------------*/ + + //this.setup = function () {} + + this.reset = function() { //CIA_reset() + //#ifdef TOD_HACK + tod_hack_tv = 0; + tod_hack_tod = 0; + tod_hack_enabled = 0; + if (SAEV_config.chipset.cia.todHack) + tod_hack_enabled = TOD_HACK_TIME; + //#endif + + kblostsynccnt = 0; + serbits = 0; + oldcd32mute = 1; //resetwarning_phase = resetwarning_timer = 0; - //heartbeat_cnt = 0; + heartbeat_cnt = 0; + ciab_tod_event_state = 0; - //oldovl = true; - //kbstate = 0; - ciaatlatch = ciabtlatch = 0; - ciaapra = 0; - ciaadra = 0; - ciaatod = ciabtod = 0; - ciaatodon = ciabtodon = 0; - ciaaicr = ciabicr = ciaaimask = ciabimask = 0; - ciaacra = ciaacrb = ciabcra = ciabcrb = 0x4; - /* outmode = toggle; */ - ciaala = ciaalb = ciabla = ciablb = ciaata = ciaatb = ciabta = ciabtb = 0xFFFF; - ciaaalarm = ciabalarm = 0; - ciabpra = 0x8C; - ciabdra = 0; - div10 = 0; - ciaasdr_cnt = 0; - ciaasdr = 0; - ciabsdr_cnt = 0; - ciabsdr = 0; - ciaata_passed = ciaatb_passed = ciabta_passed = ciabtb_passed = 0; + { + oldovl = true; + kbstate = 0; + ciaatlatch = ciabtlatch = 0; + ciaapra = 0; ciaadra = 0; + ciaatod = ciabtod = 0; ciaatodon = ciabtodon = 0; + ciaaicr = ciabicr = ciaaimask = ciabimask = 0; + ciaacra = ciaacrb = ciabcra = ciabcrb = 0x4; /* outmode = toggle; */ + ciaala = ciaalb = ciabla = ciablb = ciaata = ciaatb = ciabta = ciabtb = 0xFFFF; + ciaaalarm = ciabalarm = 0; + ciabpra = 0x8C; ciabdra = 0; + div10 = 0; + ciaasdr_cnt = 0; ciaasdr = 0; + ciabsdr_cnt = 0; ciabsdr = 0; + ciaata_passed = ciaatb_passed = ciabta_passed = ciabtb_passed = 0; + CIA_calctimers(); + SAER.disk.select_set(ciabprb); + } + SAER.memory.mapOverlay(false); + check_led(); - CIA_calctimers(); - AMIGA.disk.select_set(ciabprb); + if (SAEV_config.serial.enabled) + SAER.serial.dtr_off(); // Drop DTR at reset - //map_overlay (0); + /*#ifdef CD32 + akiko_reset (); + if (!akiko_init ()) + currprefs.cs_cd32cd = changed_prefs.cs_cd32cd = 0; + #endif*/ + } - //if (currprefs.use_serial) serial_dtr_off (); NI /* Drop DTR at reset */ - }; - - this.dump = function () { - BUG.info('A: CRA %02x CRB %02x ICR %02x IM %02x TA %04x (%04x) TB %04x (%04x)', ciaacra, ciaacrb, ciaaicr, ciaaimask, ciaata, ciaala, ciaatb, ciaalb); - BUG.info('TOD %06x (%06x) ALARM %06x %s%s CYC=%.1f', ciaatod, ciaatol, ciaaalarm, ciaatlatch ? 'L' : ' ', ciaatodon ? ' ' : 'S', AMIGA.events.currcycle * CYCLE_UNIT_INV); - BUG.info('B: CRA %02x CRB %02x ICR %02x IM %02x TA %04x (%04x) TB %04x (%04x)', ciabcra, ciabcrb, ciabicr, ciabimask, ciabta, ciabla, ciabtb, ciablb); - BUG.info('TOD %06x (%06x) ALARM %06x %s%s CLK=%.1f', ciabtod, ciabtol, ciabalarm, ciabtlatch ? 'L' : ' ', ciabtodon ? ' ' : 'S', div10 * CYCLE_UNIT_INV); - }; + this.dump = function() { //dumpcia() + SAEF_log("cia.dump() A: CRA %02x CRB %02x ICR %02x IM %02x TA %04x (%04x) TB %04x (%04x)", ciaacra, ciaacrb, ciaaicr, ciaaimask, ciaata, ciaala, ciaatb, ciaalb); + SAEF_log("cia.dump() TOD %06x (%06x) ALARM %06x %c%c CYC=%08X", ciaatod, ciaatol, ciaaalarm, ciaatlatch ? "L" : " ", ciaatodon ? " " : "S", SAEV_Events_currcycle); + SAEF_log("cia.dump() B: CRA %02x CRB %02x ICR %02x IM %02x TA %04x (%04x) TB %04x (%04x)", ciabcra, ciabcrb, ciabicr, ciabimask, ciabta, ciabla, ciabtb, ciablb); + SAEF_log("cia.dump() TOD %06x (%06x) ALARM %06x %c%c CLK=%d", ciabtod, ciabtol, ciabalarm, ciabtlatch ? "L" : " ", ciabtodon ? " " : "S", div10 / SAEC_Events_CYCLE_UNIT); + } + /*-----------------------------------------------------------------------*/ // Gayle or Fat Gary does not enable CIA /CS lines if both CIAs are selected // Old Gary based Amigas enable both CIAs in this situation + function issinglecia() { - return false; //currprefs.cs_ide || currprefs.cs_pcmcia || currprefs.cs_mbdmac; + return SAEV_config.chipset.ide || SAEV_config.chipset.pcmcia || SAEV_config.chipset.mbdmac; } function isgayle() { - return false; //currprefs.cs_ide || currprefs.cs_pcmcia; + return SAEV_config.chipset.ide || SAEV_config.chipset.pcmcia; } - function cia_wait_pre() { - if (!CUSTOM_SIMPLE) { - var div = (AMIGA.events.currcycle - AMIGA.events.eventtab[EV_CIA].oldcycles) % DIV10; - var tmp = Math.floor(DIV10 * ECLOCK_DATA_CYCLE / 10); - var cycles; - - if (div >= tmp) - cycles = DIV10 - div + tmp; - else if (div) - cycles = DIV10 + tmp - div; - else - cycles = tmp - div; - - if (cycles) - AMIGA.events.cycle(cycles); - } - } - - function cia_wait_post(value) { - AMIGA.events.cycle(6 * CYCLE_UNIT / 2); - } - - function isgaylenocia(addr) { - // gayle CIA region is only 4096 bytes at 0xbfd000 and 0xbfe000 - if (!isgayle()) - return true; + function iscia(addr) { var mask = addr & 0xf000; return mask == 0xe000 || mask == 0xd000; } + function isgaylenocia(addr) { + if (!isgayle()) + return true; + // gayle CIA region is only 4096 bytes at 0xbfd000 and 0xbfe000 + return iscia(addr); + } + function isgarynocia(addr) { + return !iscia(addr) && SAEV_config.chipset.fatGaryRev >= 0; + } - this.load8 = function (addr) { + /*---------------------------------*/ + + function cia_wait_pre(cianummask) { + var div = (SAEV_Events_currcycle - SAER_Events_eventtab[SAEC_Events_EV_CIA].oldcycles) % DIV10; + var help = DIV10 * ECLOCK_DATA_CYCLE / 10 >>> 0; + var cycles; + + if (div >= help) { + cycles = DIV10 - div; + cycles += help; + } else if (div) + cycles = DIV10 + help - div; + else + cycles = help - div; + + if (cycles) + SAER.events.do_cycles(cycles); + } + + function cia_wait_post(cianummask, value) { + SAER.events.do_cycles(6 * SAEC_Events_CYCLE_UNIT >> 1); + + if (cia_interrupt_delay) { + var v = cia_interrupt_delay; + cia_interrupt_delay = 0; + if (v & 1) ICR(0x0008); + if (v & 2) ICR(0x2000); + } + } + + /*---------------------------------*/ + + function get8(addr) { var r = (addr & 0xf00) >> 8; var v = 0xff; + if (isgarynocia(addr)) + return SAER.memory.dummyGet(addr, 1, false, 0); if (!isgaylenocia(addr)) return v; - cia_wait_pre(); switch ((addr >> 12) & 3) { - case 0: - if (!issinglecia()) - v = (addr & 1) ? ReadCIAA(r) : ReadCIAB(r); - break; - case 1: - v = (addr & 1) ? 0xff : ReadCIAB(r); - break; - case 2: - v = (addr & 1) ? ReadCIAA(r) : 0xff; - break; - case 3: - { - //if (AMIGA.config.cpu.model == 68000 && AMIGA.config.cpu.compatible) v = (addr & 1) ? regs.irc : regs.irc >> 8; - if (warned > 0) { - BUG.info('cia_bget: unknown CIA address %x', addr); - warned--; - } - break; + case 0: + if (!issinglecia()) { + cia_wait_pre(1 | 2); + v = (addr & 1) ? ReadCIAA(r) : ReadCIAB(r); + cia_wait_post(1 | 2, v); } - } - cia_wait_post(v); - return v; - }; + break; + case 1: + cia_wait_pre(2); + if (SAEV_config.cpu.model == SAEC_Config_CPU_Model_68000 && SAEV_config.cpu.compatible) { + v = (addr & 1) ? SAER_CPU_regs.irc & 0xff : ReadCIAB(r); + } else { + v = (addr & 1) ? 0xff : ReadCIAB(r); + } + cia_wait_post(2, v); + break; + case 2: + cia_wait_pre(1); + if (SAEV_config.cpu.model == SAEC_Config_CPU_Model_68000 && SAEV_config.cpu.compatible) + v = (addr & 1) ? ReadCIAA(r) : SAER_CPU_regs.irc >> 8; + else + v = (addr & 1) ? ReadCIAA(r) : 0xff; - this.load16 = function (addr) { + cia_wait_post(1, v); + break; + case 3: + if (SAEV_config.cpu.model == SAEC_Config_CPU_Model_68000 && SAEV_config.cpu.compatible) { + cia_wait_pre(0); + v = (addr & 1) ? SAER_CPU_regs.irc & 0xff : SAER_CPU_regs.irc >> 8; + cia_wait_post(0, v); + } + break; + } + + return v; + } + + function get16(addr) { var r = (addr & 0xf00) >> 8; var v = 0xffff; - if (!isgaylenocia(addr)) + if (isgarynocia(addr)) + return SAER.memory.dummyGet(addr, 2, false, 0); + if (!isgaylenocia (addr)) return v; - cia_wait_pre(); switch ((addr >> 12) & 3) { case 0: - if (!issinglecia()) + if (!issinglecia()) { + cia_wait_pre(1 | 2); v = (ReadCIAB(r) << 8) | ReadCIAA(r); - break; - case 1: - v = (ReadCIAB(r) << 8) | 0xff; - break; - case 2: - v = (0xff << 8) | ReadCIAA(r); - break; - case 3: - { - //if (AMIGA.config.cpu.model == 68000 && AMIGA.config.cpu.compatible) v = regs.irc; - if (warned > 0) { - BUG.info('cia_wget: unknown CIA address %x', addr); - warned--; + cia_wait_post(1 | 2, v); + } + break; + case 1: + cia_wait_pre(2); + v = (ReadCIAB(r) << 8) | 0xff; + cia_wait_post(2, v); + break; + case 2: + cia_wait_pre(1); + v = (0xff << 8) | ReadCIAA (r); + cia_wait_post(1, v); + break; + case 3: + if (SAEV_config.cpu.model == SAEC_Config_CPU_Model_68000 && SAEV_config.cpu.compatible) { + cia_wait_pre(0); + v = SAER_CPU_regs.irc; + cia_wait_post(0, v); } break; - } } - cia_wait_post(v); return v; - }; + } - this.load32 = function (addr) { - var v = this.load16(addr) << 16; - v |= this.load16(addr + 2); - return v >>> 0; - }; + function get32(addr) { + return ((get16(addr) << 16) | get16(addr + 2)) >>> 0; + } - this.store8 = function (addr, value) { + function put8(addr, value) { var r = (addr & 0xf00) >> 8; - if (!isgaylenocia(addr)) + if (isgarynocia(addr)) { + SAER.memory.dummyPut(addr, 1, 0); + return; + } + if (!isgaylenocia (addr)) return; - cia_wait_pre(); if (!issinglecia() || (addr & 0x3000) != 0) { + cia_wait_pre(((addr & 0x2000) == 0 ? 1 : 0) | ((addr & 0x1000) == 0 ? 2 : 0)); if ((addr & 0x2000) == 0) WriteCIAB(r, value); if ((addr & 0x1000) == 0) WriteCIAA(r, value); - if (((addr & 0x3000) == 0x3000) && warned > 0) { - BUG.info('cia_bput: unknown CIA address %x %x', addr, value); - warned--; - } + cia_wait_post(((addr & 0x2000) == 0 ? 1 : 0) | ((addr & 0x1000) == 0 ? 2 : 0), value); } - cia_wait_post(value); - }; + } - this.store16 = function (addr, value) { + function put16(addr, value) { var r = (addr & 0xf00) >> 8; - if (!isgaylenocia(addr)) + if (isgarynocia(addr)) { + SAER.memory.dummyPut(addr, 2, 0); + return; + } + if (!isgaylenocia (addr)) return; - cia_wait_pre(); if (!issinglecia() || (addr & 0x3000) != 0) { + cia_wait_pre(((addr & 0x2000) == 0 ? 1 : 0) | ((addr & 0x1000) == 0 ? 2 : 0)); if ((addr & 0x2000) == 0) WriteCIAB(r, value >> 8); if ((addr & 0x1000) == 0) WriteCIAA(r, value & 0xff); - if (((addr & 0x3000) == 0x3000) && warned > 0) { - BUG.info('cia_wput: unknown CIA address %x %x', addr, value); - warned--; - } + cia_wait_post(((addr & 0x2000) == 0 ? 1 : 0) | ((addr & 0x1000) == 0 ? 2 : 0), value); } - cia_wait_post(value); - }; - - this.store32 = function (addr, value) { - this.store16(addr, value >> 16); - this.store16(addr + 2, value & 0xffff); } -} + function put32(addr, value) { + put16(addr, value >>> 16); + put16(addr + 2, value & 0xffff); + } + + function getInst32(addr) { + if (SAEV_config.cpu.model >= SAEC_Config_CPU_Model_68020) return SAEF_Memory_dummyGetInst32(addr); + return get32(addr); + } + function getInst16(addr) { + if (SAEV_config.cpu.model >= SAEC_Config_CPU_Model_68020) return SAEF_Memory_dummyGetInst16(addr); + return get16(addr); + } + SAEV_CIA_bank = new SAEO_Memory_addrbank( + get32, get16, get8, + put32, put16, put8, + SAEF_Memory_defaultXLate, SAEF_Memory_defaultCheck, null, null, "CIA", + getInst32, getInst16, + //SAEC_Memory_addrbank_flag_IO | SAEC_Memory_addrbank_flag_CIA, S_READ, S_WRITE, null, 0x3f01, 0xbfc000 + SAEC_Memory_addrbank_flag_IO | SAEC_Memory_addrbank_flag_CIA, null, 0x3f01, 0xbfc000 + ); +} diff --git a/sae/config.js b/sae/config.js index 27bf8a7..478981a 100644 --- a/sae/config.js +++ b/sae/config.js @@ -1,217 +1,2398 @@ -/************************************************************************** -* SAE - Scripted Amiga Emulator -* -* 2012-2015 Rupert Hausberger -* -* https://github.com/naTmeg/ScriptedAmigaEmulator -* -**************************************************************************/ +/*------------------------------------------------------------------------- +| SAE - Scripted Amiga Emulator +| https://github.com/naTmeg/ScriptedAmigaEmulator +| +| Copyright (C) 2012-2016 Rupert Hausberger +| +| This program is free software; you can redistribute it and/or +| modify it under the terms of the GNU General Public License +| as published by the Free Software Foundation; either version 2 +| of the License, or (at your option) any later version. +| +| This program is distributed in the hope that it will be useful, +| but WITHOUT ANY WARRANTY; without even the implied warranty of +| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +| GNU General Public License for more details. +| +| Notes: +| - Ported from WinUAE 3.2.x +| - There is many comment in this file. I did not strip it, +| because it's easier to enable features in the future... +-------------------------------------------------------------------------*/ +/* global variables */ -function Config() { - this.init = false; +var SAEV_config = {}; - this.cpu = { - model: 0, - speed: 0, - compatible: false - }; - this.blitter = { - immediate: false, - waiting: 0 - }; - this.chipset = { - mask: 0, - agnus_dip: 0, - agnus_rev: 0, - denise_rev: 0, - collision_level: 0, - genlock: false, - refreshrate: 0 - }; - this.ram = { - chip: { - size: 0 - }, - slow: { - size: 0 - }, - fast: { - size: 0 - } - }; - this.rom = { - size: 0, - data: null - }; - this.ext = { - addr: 0, - size: 0, - data: null - }; - this.floppy = { - drive:[{ - type: 0, - name: null, - data: null - }, { - type: 0, - name: null, - data: null - }, { - type: 0, - name: null, - data: null - }, { - type: 0, - name: null, - data: null - }], - speed:0 - }; - this.video = { - id: '', - enabled: false, - scale: false, - ntsc: false, //~ - framerate: 0, - hresolution: 0, - vresolution: 0, - scandoubler: false, - scanlines: false, - extrawidth: 0, - xcenter: 0, - ycenter: 0 - }; - this.audio = { - enabled: false, - mode:0, - channels: 0, - filter: false - }; - this.ports = [{ - type: 0, - move: 0, - fire: [0,0] - }, { - type: 0, - move: 0, - fire: [0,0] - }]; - this.keyboard = { - enabled: false, - mapShift: false - }; - this.serial = { - enabled: false - }; - this.rtc = { - type: 0 - }; - this.cia = { - tod: 0, - tod_hack: 0 - }; - this.hooks = { - error: null, - power_led: null, - floppy_motor: null, - floppy_step: null, - fps: null, - cpu: null - }; +/*---------------------------------*/ +/* models */ - function configSetDefaults(c) { - c.init = true; +const SAEC_Model_A500 = 1; +const SAEC_Model_A500P = 2; +const SAEC_Model_A600 = 3; +const SAEC_Model_A1000 = 4; +const SAEC_Model_A1200 = 5; +const SAEC_Model_A2000 = 6; +const SAEC_Model_A3000 = 7; +const SAEC_Model_A4000 = 8; +const SAEC_Model_A4000T = 9; +/* future (cd-emulation is not implemented) */ +const SAEC_Model_CDTV = 10; +const SAEC_Model_CD32 = 11; - c.cpu.model = 68000; - c.cpu.speed = SAEV_Config_CPU_Speed_Original; - c.cpu.compatible = false; +/*---------------------------------*/ +/* file */ - //c.chipset.mask = CSMASK_ECS_AGNUS | CSMASK_ECS_DENISE; - //c.chipset.mask = CSMASK_ECS_AGNUS; - c.chipset.mask = 0; - c.chipset.agnus_dip = false; /* A1000 */ - c.chipset.agnus_rev = -1; - c.chipset.denise_rev = -1; - c.chipset.collision_level = SAEV_Config_Chipset_ColLevel_None; - c.chipset.genlock = false; - c.chipset.refreshrate = -1; - - c.blitter.immediate = 0 ? true : false; - c.blitter.waiting = 1; /* 0 if blitter.immediate */ - - c.ram.chip.size = SAEV_Config_RAM_Chip_Size_512K; - c.ram.slow.size = SAEV_Config_RAM_Slow_Size_512K; - c.ram.fast.size = SAEV_Config_RAM_Fast_Size_1M; +function SAEO_Config_File() { + //this.path = ""; + this.name = ""; + this.data = ""; + this.size = 0; + this.crc32 = false; + this.prot = false; - c.rom.size = SAEV_Config_ROM_Size_None; - c.rom.data = null; - c.ext.addr = SAEV_Config_EXT_Addr_E0; - c.ext.size = SAEV_Config_EXT_Size_None; - c.ext.data = null; - - c.floppy.drive[0].type = SAEV_Config_Floppy_Type_35_DD; - c.floppy.drive[0].name = null; - c.floppy.drive[0].data = null; - c.floppy.drive[1].type = SAEV_Config_Floppy_Type_35_DD; - c.floppy.drive[1].name = null; - c.floppy.drive[1].data = null; - c.floppy.drive[2].type = SAEV_Config_Floppy_Type_None; - c.floppy.drive[2].name = null; - c.floppy.drive[2].data = null; - c.floppy.drive[3].type = SAEV_Config_Floppy_Type_None; - c.floppy.drive[3].name = null; - c.floppy.drive[3].data = null; - c.floppy.speed = SAEV_Config_Floppy_Speed_Original; - - c.video.id = 'video'; - c.video.enabled = true; - c.video.scale = false; - c.video.ntsc = false; - c.video.framerate = 1; //2 - c.video.hresolution = 1 ? RES_HIRES : RES_LORES; - c.video.vresolution = 1 ? VRES_DOUBLE : VRES_NONDOUBLE; - c.video.scandoubler = 0 ? true : false; - c.video.scanlines = 0 ? true : false; - c.video.extrawidth = 0; - c.video.xcenter = 0; - c.video.ycenter = 0; - - c.audio.enabled = true; - //c.audio.mode = SAEV_Config_Audio_Mode_Play_Best; - c.audio.mode = SAEV_Config_Audio_Mode_Play; - c.audio.channels = SAEV_Config_Audio_Channels_Stereo; - c.audio.filter = false; - - c.ports[0].type = SAEV_Config_Ports_Type_Mouse; - c.ports[0].move = SAEV_Config_Ports_Move_WASD; - c.ports[0].fire[0] = 49; - c.ports[0].fire[1] = 50; - c.ports[1].type = SAEV_Config_Ports_Type_Joy1; - c.ports[1].move = SAEV_Config_Ports_Move_Arrows; - c.ports[1].fire[0] = 16; - c.ports[1].fire[1] = 17; - - c.keyboard.enabled = true; - c.keyboard.mapShift = false; - - c.rtc.type = 1 ? SAEV_Config_RTC_Type_MSM6242B : SAEV_Config_RTC_Type_RF5C01A; - - c.cia.tod = 0; - c.cia.tod_hack = true; - - c.hooks.error = function (err, msg) { - }; - c.hooks.power_led = function (on) { - }; - c.hooks.floppy_motor = function (unit, on) { - }; - c.hooks.floppy_step = function (unit, cyl) { - }; - c.hooks.fps = function (fps) { - }; - c.hooks.cpu = function(usage) {} + this.clr = function() { + //this.path = ""; + this.name = ""; + this.data = ""; + this.size = 0; + this.crc32 = false; + this.prot = false; } - configSetDefaults(this); } +/*---------------------------------*/ +/* cpu */ + +const SAEC_Config_CPU_Model_68000 = 68000; +const SAEC_Config_CPU_Model_68010 = 68010; +const SAEC_Config_CPU_Model_68020 = 68020; +const SAEC_Config_CPU_Model_68030 = 68030; +const SAEC_Config_CPU_Model_68040 = 68040; /* future */ +const SAEC_Config_CPU_Model_68060 = 68060; /* future */ + +const SAEC_Config_CPU_Speed_Maximum = -1; +const SAEC_Config_CPU_Speed_Original = 0; + +/*---------------------------------*/ +/* chipset */ + +const SAEC_Config_Chipset_Mask_OCS = 0; +const SAEC_Config_Chipset_Mask_ECS_AGNUS = 1; +const SAEC_Config_Chipset_Mask_ECS_DENISE = 2; +const SAEC_Config_Chipset_Mask_AGA = 4; + +const SAEC_Config_Chipset_ColLevel_None = 0; +const SAEC_Config_Chipset_ColLevel_Sprite_Sprite = 1; +const SAEC_Config_Chipset_ColLevel_Sprite_Playfield = 2; +const SAEC_Config_Chipset_ColLevel_Full = 3; + + +const SAEC_Config_Chipset_CR_MAX = 10; +const SAEC_Config_Chipset_CR_PAL = SAEC_Config_Chipset_CR_MAX + 0; +const SAEC_Config_Chipset_CR_NTSC = SAEC_Config_Chipset_CR_MAX + 1; +const SAEC_Config_Chipset_CR_TOTAL = SAEC_Config_Chipset_CR_MAX + 2; + +function SAEO_Config_Chipset_Refresh() { + this.index = 0; + this.locked = false; + this.rtg = false; + this.horiz = 0; + this.vert = 0; + this.lace = 0; + this.ntsc = false; + this.vsync = 0; + this.framelength = 0; + this.rate = 0.0; + this.label = ""; + this.commands = ""; +} + +/*--------------*/ +/* features */ + +const SAEC_Config_Chipset_Compatible_Manual = 0; +const SAEC_Config_Chipset_Compatible_Generic = 1; +const SAEC_Config_Chipset_Compatible_A500 = 2; +const SAEC_Config_Chipset_Compatible_A500P = 3; +const SAEC_Config_Chipset_Compatible_A600 = 4; +const SAEC_Config_Chipset_Compatible_A1000 = 5; +const SAEC_Config_Chipset_Compatible_A1000V = 6; +const SAEC_Config_Chipset_Compatible_A1200 = 7; +const SAEC_Config_Chipset_Compatible_A2000 = 8; +const SAEC_Config_Chipset_Compatible_A3000 = 9; +const SAEC_Config_Chipset_Compatible_A4000 = 10; +const SAEC_Config_Chipset_Compatible_A4000T = 11; +const SAEC_Config_Chipset_Compatible_CDTV = 12; +const SAEC_Config_Chipset_Compatible_CDTVCR = 13; +const SAEC_Config_Chipset_Compatible_CD32 = 14; + +const SAEC_Config_Chipset_CIA_TOD_VSync = 0; +const SAEC_Config_Chipset_CIA_TOD_50Hz = 1; +const SAEC_Config_Chipset_CIA_TOD_60Hz = 2; + +const SAEC_Config_RTC_Type_None = 0; +const SAEC_Config_RTC_Type_MSM6242B = 1; +const SAEC_Config_RTC_Type_RF5C01A = 2; /* A3000(T)/A4000(T) */ +const SAEC_Config_RTC_Type_MSM6242B_A2000 = 3; + +const SAEC_Config_Chipset_IDE_A600A1200 = 1; +const SAEC_Config_Chipset_IDE_A4000 = 2; + +/*---------------------------------*/ +/* memory */ + +/* DEPRECATED +const SAEC_Config_RAM_Chip_Size_256K = 256 << 10; +const SAEC_Config_RAM_Chip_Size_512K = 512 << 10; +const SAEC_Config_RAM_Chip_Size_1M = 1024 << 10; +const SAEC_Config_RAM_Chip_Size_2M = 2048 << 10; + +const SAEC_Config_RAM_Slow_Size_None = 0; +const SAEC_Config_RAM_Slow_Size_256K = 256 << 10; +const SAEC_Config_RAM_Slow_Size_512K = 512 << 10; +const SAEC_Config_RAM_Slow_Size_1M = 1024 << 10; +const SAEC_Config_RAM_Slow_Size_1536K = 1536 << 10; + +const SAEC_Config_RAM_Fast_Size_None = 0; +const SAEC_Config_RAM_Fast_Size_512K = 512 << 10; +const SAEC_Config_RAM_Fast_Size_1M = 1024 << 10; +const SAEC_Config_RAM_Fast_Size_2M = 2048 << 10; +const SAEC_Config_RAM_Fast_Size_4M = 4096 << 10; +const SAEC_Config_RAM_Fast_Size_8M = 8192 << 10;*/ + +const SAEC_Config_Memory_z3Mapping_Auto = 0; +const SAEC_Config_Memory_z3Mapping_SAE = 1; +const SAEC_Config_Memory_z3Mapping_Real = 2; + +//const SAEC_Config_Memory_Custom_MAX = 2; //MAX_CUSTOM_MEMORY_ADDRS + +/*---------------------------------*/ +/* disk */ + +const SAEC_Config_Floppy_Type_None = 0; +const SAEC_Config_Floppy_Type_35_DD = 1; +const SAEC_Config_Floppy_Type_35_HD = 2; +const SAEC_Config_Floppy_Type_35_DD_ESCOM = 3; +const SAEC_Config_Floppy_Type_35_DD_PC = 4; +const SAEC_Config_Floppy_Type_35_HD_PC = 5; +const SAEC_Config_Floppy_Type_525_SD = 6; + +const SAEC_Config_Floppy_Speed_Turbo = 0; +const SAEC_Config_Floppy_Speed_Original = 100; + +function SAEO_Config_Floppy_Drive() { //floppyslot + this.type = SAEC_Config_Floppy_Type_None; //dfxtype + this.file = new SAEO_Config_File(); + //this.name = ""; //df + //this.prot = false; //forcedwriteprotect + //this.dfxclick = 0; + //this.dfxclickexternal = ""; +} + +/*---------------------------------*/ +/* mount */ + +const SAEC_Config_Mount_Controller_Type_MB_IDE = 1; +const SAEC_Config_Mount_Controller_Type_PCMCIA_SRAM = 2; +const SAEC_Config_Mount_Controller_Type_PCMCIA_IDE = 3; + +const SAEC_Config_Mount_Controller_Level_ATA_1 = 0; +const SAEC_Config_Mount_Controller_Level_ATA_2 = 1; +const SAEC_Config_Mount_Controller_Level_ATA_2S = 2; + +const SAEC_Config_Mount_Controller_Level_SCSI_1 = 0; +const SAEC_Config_Mount_Controller_Level_SCSI_2 = 1; +const SAEC_Config_Mount_Controller_Level_SASI = 2; +const SAEC_Config_Mount_Controller_Level_SASI_ENHANCED = 2; +const SAEC_Config_Mount_Controller_Level_SASI_CHS = 3; + +const SAEC_Config_Mount_Bootpri_NOAUTOBOOT = -128; +const SAEC_Config_Mount_Bootpri_NOAUTOMOUNT = -129; + +function SAEO_Config_Mount_Info() { //uaedev_config_info + //controller + this.controller_type = 0; + this.controller_unit = 0; //IDE channel + unit + this.controller_media_type = 0; // 1 = CF IDE, 0 = normal + this.unit_feature_level = 0; + this.unit_special_flags = 0; //1 = force LBA48 + //file + this.type = 0; + //this.rootdir = ""; + this.file = new SAEO_Config_File(); //OWN + this.readonly = false; + //rdb drive geometry + this.blocksize = 0; + this.cyls = 0; // calculated/corrected highcyl + this.surfaces = 0; //heads + this.sectors = 0; + this.interleave = false; + this.physical_geometry = false; // if false: use defaults + this.pcyls = 0, this.pheads = 0, this.psecs = 0; + //partition + this.bootable = false; + this.automount = false; + this.unit = 0; + this.flags = 0; + this.devname = ""; + //partition DosEnvec + this.sectorsperblock = 0; + this.reserved = 0; + this.lowcyl = 0; + this.highcyl = 0; // zero if detected from size + this.buffers = 0; + this.bufmemtype = 0; + this.maxtransfer = 0; + this.mask = 0; //u32 + this.bootpri = 0; + this.dostype = 0; //u32 + //filesystem + this.filesys = ""; + //filesystem DeviceNode + this.stacksize = 0; + this.priority = 0; + //misc + //this.device_emu_unit = 0; //CD +} +function SAEO_Config_Mount_Data() { //uaedev_config_data + this.ci = new SAEO_Config_Mount_Info(); + this.configoffset = 0; + this.unitnum = 0; +} + +/*---------------------------------*/ +/* video */ + +const SAEC_Config_Video_API_Canvas = 0; +const SAEC_Config_Video_API_WebGL = 1; + +const SAEC_Config_Video_HResolution_LoRes = 0; +const SAEC_Config_Video_HResolution_HiRes = 1; +const SAEC_Config_Video_HResolution_SuperHiRes = 2; + +const SAEC_Config_Video_VResolution_NonDouble = 0; +const SAEC_Config_Video_VResolution_Double = 1; + +const SAEC_Config_Video_AP_Fullscreen_WINDOW = 0; //GFX_WINDOW +const SAEC_Config_Video_AP_Fullscreen_FULLSCREEN = 1; //GFX_FULLSCREEN +const SAEC_Config_Video_AP_Fullscreen_FULLWINDOW = 2; //GFX_FULLWINDOW + +function SAEO_Config_Video_WH() { //struct wh + this.x = 0; + this.y = 0; + this.width = 0; + this.height = 0; + this.special = false; +} + +function SAEO_Config_Video_APMode() { //struct apmode + this.gfx_fullscreen = 0; + this.gfx_display = 0; + this.gfx_vsync = 0; + // 0 = immediate flip + // -1 = wait for flip, before frame ends + // 1 = wait for flip, after new frame has started + this.gfx_vflip = 0; + this.gfx_strobo = false; //doubleframemode strobo + this.gfx_vsyncmode = 0; + this.gfx_backbuffers = 0; + this.gfx_interlaced = false; + this.gfx_refreshrate = 0; +} + +const MAX_FILTERSHADERS = 4; +function SAEO_Config_Video_FilterData() { //struct gfx_filterdata + this.gfx_filter = 0; + this.gfx_filtershader = new Array(2 * MAX_FILTERSHADERS + 1); + this.gfx_filtermask = new Array(2 * MAX_FILTERSHADERS + 1); + this.gfx_filteroverlay = ""; //char + this.gfx_filteroverlay_pos = new SAEO_Config_Video_WH(); + this.gfx_filteroverlay_overscan = 0; + this.gfx_filter_scanlines = 0; //0, 100, 1, + this.gfx_filter_scanlineratio = 0; + this.gfx_filter_scanlinelevel = 0; //0, 100, 10, + this.gfx_filter_horiz_zoom = 0.0; this.gfx_filter_vert_zoom = 0.0; //float + this.gfx_filter_horiz_zoom_mult = 0.0; this.gfx_filter_vert_zoom_mult = 0.0; //float + this.gfx_filter_horiz_offset = 0.0; this.gfx_filter_vert_offset = 0.0; //float + this.gfx_filter_left_border = 0; this.gfx_filter_right_border = 0; + this.gfx_filter_top_border = 0; this.gfx_filter_bottom_border = 0; + this.gfx_filter_filtermode = 0; + this.gfx_filter_bilinear = 0; //0, 1, 1, + this.gfx_filter_noise = 0; //0, 100, 10, + this.gfx_filter_blur = 0; //0, 2000, 10, + this.gfx_filter_saturation = 0; this.gfx_filter_luminance = 0; this.gfx_filter_contrast = 0; + this.gfx_filter_gamma = 0; + this.gfx_filter_gamma_ch = [0,0,0]; + this.gfx_filter_keep_aspect = 0; this.gfx_filter_aspect = 0; + this.gfx_filter_autoscale = 0; + this.gfx_filter_integerscalelimit = 0; + this.gfx_filter_keep_autoscale_aspect = 0; + + for (var i = 0; i < 2 * MAX_FILTERSHADERS + 1; i++) { + this.gfx_filtershader[i] = ""; + this.gfx_filtermask[i] = ""; + } +}; + +/*---------------------------------*/ +/* audio */ + +/* DEPRECATED +const SAEC_Config_Audio_Mode_Emul = 0; +const SAEC_Config_Audio_Mode_Play = 1; +const SAEC_Config_Audio_Mode_Play_Best = 2;*/ + +const SAEC_Config_Audio_Mode_Off = 0; +const SAEC_Config_Audio_Mode_Off_Emul = 1; +const SAEC_Config_Audio_Mode_On = 2; +const SAEC_Config_Audio_Mode_On_Best = 3; + +const SAEC_Config_Audio_Freq_Auto = 0; +const SAEC_Config_Audio_Freq_11025 = 11025; +const SAEC_Config_Audio_Freq_22050 = 22050; +const SAEC_Config_Audio_Freq_44100 = 44100; +const SAEC_Config_Audio_Freq_48000 = 48000; + +const SAEC_Config_Audio_Channels_Mono = 1; +const SAEC_Config_Audio_Channels_Stereo = 2; + +const SAEC_Config_Audio_Filter_Off = 0; +const SAEC_Config_Audio_Filter_Emul = 1; +const SAEC_Config_Audio_Filter_On = 2; +const SAEC_Config_Audio_FilterType_A500 = 0; +const SAEC_Config_Audio_FilterType_A1200 = 1; + +const SAEC_Config_Audio_Interpol_None = 0; +const SAEC_Config_Audio_Interpol_Anti = 1; +const SAEC_Config_Audio_Interpol_RH = 2; +const SAEC_Config_Audio_Interpol_Crux = 3; + +/*---------------------------------*/ +/* input */ + +const SAEC_Config_Ports_Type_None = 0; +const SAEC_Config_Ports_Type_Mouse = 1; +const SAEC_Config_Ports_Type_Joy0 = 2; +const SAEC_Config_Ports_Type_Joy1 = 3; + +const SAEC_Config_Ports_Move_None = 0; +const SAEC_Config_Ports_Move_Arrows = 1; +const SAEC_Config_Ports_Move_Numpad = 2; +const SAEC_Config_Ports_Move_WASD = 3; + +const SAEC_Config_Ports_Fire_None = 0; + +/*---------------------------------*/ +/* debug */ + +const SAEC_Config_Debug_Level_Fatal = 0; +const SAEC_Config_Debug_Level_Error = 1; +const SAEC_Config_Debug_Level_Warn = 2; +const SAEC_Config_Debug_Level_Info = 3; +const SAEC_Config_Debug_Level_Log = 4; + +/*---------------------------------*/ +/* the main config-object */ + +function SAEO_Config() { + //int turbo_emulation; + //int turbo_emulation_limit; + + this.cpu = { + model: 0, //cpu_model + speed: 0, //m68k_speed + speedThrottle: 0.0, //m68k_speed_throttle (0.0 - 1000.0) + clock: { //cpu_frequency + multiplier: 0, //cpu_clock_multiplier + frequency: 0 //cpu_frequency + }, + compatible: false, //cpu_compatible + addressSpace24: false, //address_space_24 + resetDelay: false //reset_delay; + /*int cpu_idle; + bool cpu_cycle_exact; + bool cpu_memory_cycle_exact; + bool int_no_unimplemented; 68060*/ + }; + /*this.fpu = { future + int fpu_model; + int fpu_revision; + bool fpu_strict; + bool fpu_softfloat; + bool fpu_no_unimplemented; + };*/ + + this.chipset = { + mask: 0, //chipset_mask + ntsc: false, //ntscmode + genlock: false, //genlock + colLevel: 0, //collision_level + refreshRate: 0.0, //chipset_refreshrate + refresh: null, //cr[SAEC_Config_Chipset_CR_TOTAL] + /*int cr_selected; + int genlock_image; + int genlock_mix; + TCHAR genlock_image_file[MAX_DPATH];*/ + blitter: { + immediate: false, //immediate_blits + waiting: 0, //waiting_blits + cycle_exact: false //blitter_cycle_exact + }, + cia: { + todHack: false, //tod_hack + todBug: false, //cs_ciatodbug + tod: 0, //cs_ciaatod + overlay: false, //cs_ciaoverlay + type6526: false //cs_cia6526 + }, + rtc: { + type: 0, //cs_rtc + adjust: 0 //cs_rtc_adjust + //file: "" //rtcfile + }, + //features + compatible: 0, //cs_compatible + mirrorE0: false, //cs_ksmirror_e0 + mirrorA8: false, //cs_ksmirror_a8 + a1000ram: false, //cs_a1000ram + agnusRev: 0, //cs_agnusrev + agnusDIP: false, //cs_dipagnus + agnusBltBusyBug: false, //cs_agnusbltbusybug + deniseRev: 0, //cs_deniserev + deniseNoEHB: false, //cs_denisenoehb + fatGaryRev: 0, //cs_fatgaryrev + ramseyRev: 0, //cs_ramseyrev + df0idhw: false, //cs_df0idhw + ide: 0, //cs_ide + pcmcia: false, //cs_pcmcia + mbdmac: 0, //cs_mbdmac + jumper1MbChip: false, //cs_1mchipjumper + bogomemIsFast: false, //cs_slowmemisfast + z3AutoConfig: false //cs_z3autoconfig + /*bool cs_cd32cd; + bool cs_cd32c2p; + bool cs_cd32nvram; + int cs_cd32nvram_size; + bool cs_cd32fmv; + bool cs_cdtvcd; + bool cs_cdtvram; + int cs_cdtvcard; + bool cs_cdtvscsi; + bool cs_cdtvcr; + bool cs_resetwarning; + bool cs_bytecustomwritebug; // >= 68040 + bool cs_color_burst; + int cs_hacks;*/ + }; + + this.memory = { + rom: new SAEO_Config_File(), //romfile[MAX_DPATH], romident[256]; + extRom: new SAEO_Config_File(), //romextfile[MAX_DPATH], romextident[256]; + romKey: new SAEO_Config_File(), + amaxRom: new SAEO_Config_File(), + kickShifter: false, //kickshifter + //maprom: 0, //BlizKick + /*struct boardromconfig expansionboard[MAX_EXPANSION_BOARDS]; + uae_u32 romextfile2addr; + TCHAR romextfile2[MAX_DPATH]; + TCHAR flashfile[MAX_DPATH]; + TCHAR cartfile[MAX_DPATH]; + TCHAR cartident[256]; + TCHAR a2065name[MAX_DPATH]; + TCHAR picassoivromfile[MAX_DPATH]; + int uaeboard; + int boot_rom;*/ + + chipSize: 0, //chipmem_size + bogoSize: 0, //bogomem_size + z2FastSize: 0, //fastmem_size + z2FastAutoConfig: false, //fastmem_autoconfig + z3FastSize: 0, //z3fastmem_size + z3Mapping: 0, //z3_mapping_mode + z3AutoConfigStart: 0, //z3autoconfig_start + ramsey: { + lowSize: 0, //mbresmem_low_size /* mainboard */ + highSize: 0 //mbresmem_high_size /* processor-slot */ + }, + custom: [{ + addr: 0, //custom_memory_addrs[SAEC_Config_Memory_Custom_MAX] + size: 0, //custom_memory_sizes[SAEC_Config_Memory_Custom_MAX] + mask: 0 //custom_memory_mask[SAEC_Config_Memory_Custom_MAX] + }, { + addr: 0, + size: 0, + mask: 0 + }], + logIllegal: false //illegal_mem + /*uae_u32 z3fastmem2_size; + uae_u32 z3chipmem_size; + uae_u32 z3chipmem_start; + uae_u32 fastmem2_size; + uae_u32 mem25bit_size; + uae_u32 rtgmem_size; + bool rtg_hardwareinterrupt; + bool rtg_hardwaresprite; + int rtgmem_type; + bool rtg_more_compatible; + bool picasso96_nocustom; + int picasso96_modeflags;*/ + }; + + this.floppy = { + drive: null, //floppyslots[4] + readOnly: false, //floppy_read_only + //writeLength: 0, //floppy_write_length + randomBitsMin: 0, //floppy_random_bits_min + randomBitsMax: 0, //floppy_random_bits_max + speed: 0, //floppy_speed + autoEXT2: 0 //floppy_auto_ext2 + /*int nr_floppies; + int dfxclickvolume_disk[4]; + int dfxclickvolume_empty[4]; + int dfxclickchannelmask;*/ + }; + + this.mount = { + items: 0, //mountitems + config: null //mountconfig + }; + + /*struct cdslot cdslots[MAX_TOTAL_SCSI_DEVICES]; + int cd_speed; + TCHAR inprecfile[MAX_DPATH]; + bool inprec_autoplay; + int filesys_limit; + int filesys_max_name; + int filesys_max_file_size; + bool filesys_inject_icons; + TCHAR filesys_inject_icons_tool[MAX_DPATH]; + TCHAR filesys_inject_icons_project[MAX_DPATH]; + TCHAR filesys_inject_icons_drawer[MAX_DPATH]; + bool filesys_no_uaefsdb; + bool filesys_custom_uaefsdb;*/ + + this.video = { + id: "", + enabled: false, + //driver: 0, + + scandoubler: false, //gfx_scandoubler + framerate: 0, //gfx_framerate + hresolution: 0, //gfx_resolution + vresolution: 0, //gfx_vresolution + pscanlines: 0, //gfx_pscanlines + iscanlines: 0, //gfx_iscanlines + xcenter: 0, //gfx_xcenter + ycenter: 0, //gfx_ycenter + lores_mode: false, //gfx_lores_mode + extrawidth: 0, //gfx_extrawidth + backgroundColor: 0, + //saturation: 0, //gfx_saturation -1000, 1000, 10, + luminance: 0, //gfx_luminance -1000, 1000, 10, + contrast: 0, //gfx_contrast -1000, 1000, 10, + gamma: 0, //gfx_gamma -1000, 1000, 10, + gammaCh: [0,0,0], //gfx_gamma_ch[3] + alpha: 0, + antialias: false, + size: new SAEO_Config_Video_WH(), //gfx_size + size_win: new SAEO_Config_Video_WH(), //gfx_size_win + //size_win_xtra: new Array(6), //gfx_size_win_xtra[6]; + size_fs: new SAEO_Config_Video_WH(), //gfx_size_fs; + //size_fs_xtra: new Array(6), //gfx_size_fs_xtra[6]; + apmode: null, //gfx_apmode[2] + gf: null, //gf[2] + api: 0, //gfx_api + colorMode: 0, //color_mode + blackerThanBlack: false, //gfx_blackerthanblack + refreshIndicator: false //refresh_indicator + /*int gfx_autoframerate; + bool gfx_autoresolution_vga; + int gfx_autoresolution; + int gfx_autoresolution_delay; + int gfx_autoresolution_minv, gfx_autoresolution_minh; + int gfx_xcenter_pos, gfx_ycenter_pos; + int gfx_xcenter_size, gfx_ycenter_size; + int gfx_max_horizontal, gfx_max_vertical; + bool gfx_threebitcolors; + bool gfx_grayscale; + bool lightboost_strobo; + float rtg_horiz_zoom_mult; //p96 + float rtg_vert_zoom_mult; //p96 + int monitoremu;*/ + }; + + this.audio = { + bufferFrames: 0, + mode: 0, //produce_sound + channels: 0, //sound_stereo + freq: 0, //sound_freq + stereoSeparation: 0, //sound_stereo_separation + stereoDelay: 0, //sound_mixed_stereo_delay + interpol: 0, //sound_interpol + filter: 0, //sound_filter + filterType: 0 //sound_filter_type + /*int sound_maxbsiz; + int sound_volume_master; + int sound_volume_paula; + int sound_volume_cd; + int sound_volume_board; + bool sound_stereo_swap_paula; + bool sound_stereo_swap_ahi; + bool sound_auto; + bool sound_cdaudio; + bool sound_toccata; + bool sound_toccata_mixer;*/ + }; + + /*struct jport jports[MAX_JPORTS]; + struct jport_custom jports_custom[MAX_JPORTS_CUSTOM]; + int input_selected_setting; + int input_joymouse_multiplier; + int input_joymouse_deadzone; + int input_joystick_deadzone; + int input_joymouse_speed; + int input_analog_joystick_mult; + int input_analog_joystick_offset; + int input_autofire_linecnt; + int input_mouse_speed; + int input_tablet; + bool tablet_library; + bool input_magic_mouse; + int input_magic_mouse_cursor; + int input_keyboard_type; + int input_autoswitch; + struct uae_input_device joystick_settings[MAX_INPUT_SETTINGS][MAX_INPUT_DEVICES]; + struct uae_input_device mouse_settings[MAX_INPUT_SETTINGS][MAX_INPUT_DEVICES]; + struct uae_input_device keyboard_settings[MAX_INPUT_SETTINGS][MAX_INPUT_DEVICES]; + struct uae_input_device internalevent_settings[MAX_INPUT_SETTINGS][INTERNALEVENT_COUNT]; + TCHAR input_config_name[GAMEPORT_INPUT_SETTINGS][256]; + int dongle; + int input_contact_bounce;*/ + + this.ports = [{ + type: SAEC_Config_Ports_Type_Mouse, + move: SAEC_Config_Ports_Move_WASD, + fire: [49,50] + }, { + type: SAEC_Config_Ports_Type_Joy1, + move: SAEC_Config_Ports_Move_Arrows, + fire: [16,17] + }]; + + this.keyboard = { + enabled: true + //KbdLang keyboard_lang; + }; + + this.serial = { + enabled: false, //use_serial + demand: false //serial_demand + /*bool serial_hwctsrts; + bool serial_direct; + int serial_stopbits; + int serial_crlf; + TCHAR sername[256];*/ + }; + + /*bool parallel_demand; + int parallel_matrix_emulation; + bool parallel_postscript_emulation; + bool parallel_postscript_detection; + int parallel_autoflush_time; + TCHAR ghostscript_parameters[256]; + TCHAR prtname[256];*/ + + /*int leds_on_screen; + int leds_on_screen_mask[2]; + struct wh osd_pos; + int keyboard_leds[3]; + bool keyboard_leds_in_use;*/ + + this.hook = { + log: { + error: function (err, msg) {} + }, + led: { + power: function(on) {}, + hd: function(rw) {}, + df: function(unit, dis, cyl, side, rw) {}, + fps: function(fps, paused) {}, + cpu: function(usage, paused) {} + } + }; + + this.debug = { + level: 0 + }; + + this.chipset.refresh = new Array(SAEC_Config_Chipset_CR_TOTAL); + for (var vi = 0; vi < SAEC_Config_Chipset_CR_TOTAL; vi++) + this.chipset.refresh[vi] = new SAEO_Config_Chipset_Refresh(); + + this.floppy.drive = new Array(4); + for (vi = 0; vi < 4; vi++) + this.floppy.drive[vi] = new SAEO_Config_Floppy_Drive(); + + this.mount.config = new Array(6); + for (vi = 0; vi < 6; vi++) + this.mount.config[vi] = new SAEO_Config_Mount_Data(); + + this.video.apmode = new Array(2); + for (vi = 0; vi < 2; vi++) + this.video.apmode[vi] = new SAEO_Config_Video_APMode(); + + this.video.gf = new Array(2); + for (vi = 0; vi < 2; vi++) + this.video.gf[vi] = new SAEO_Config_Video_FilterData(); +}; + +/*---------------------------------*/ + +function SAEO_Configuration() { + /*---------------------------------*/ + /* rom */ + + /*const MAX_DUPLICATE_EXPANSION_BOARDS = 4; + const MAX_EXPANSION_BOARDS = 4; + struct romconfig { + TCHAR romfile[MAX_DPATH]; + TCHAR romident[256]; + uae_u32 board_ram_size; + bool autoboot_disabled; + int device_id; + int device_settings; + int subtype; + void *unitdata; + }; + const MAX_BOARD_ROMS = 2; + struct boardromconfig { + int device_type; + int device_num; + struct romconfig roms[MAX_BOARD_ROMS]; + };*/ + + + /*---------------------------------*/ + /* mount */ + + /*const MAX_TOTAL_SCSI_DEVICES = 8; + function cdslot() { + this.name = ""; + this.inuse = false; + this.delayed = false; + this.temporary = false; + this.type = 0; + };*/ + + /*---------------------------------*/ + /* video */ + + //const APMODE_NATIVE = 0; + //const APMODE_RTG = 1; + + /*const MONITOREMU_NONE = 0; + const MONITOREMU_AUTO = 1; + const MONITOREMU_A2024 = 2; + const MONITOREMU_GRAFFITI = 3; + const MONITOREMU_HAM_E = 4; + const MONITOREMU_HAM_E_PLUS = 5; + const MONITOREMU_VIDEODAC18 = 6; + const MONITOREMU_AVIDEO12 = 7; + const MONITOREMU_AVIDEO24 = 8; + const MONITOREMU_FIRECRACKER24 = 9; + const MONITOREMU_DCTV = 10;*/ + + /*const AUTOSCALE_NONE = 0; + const AUTOSCALE_STATIC_AUTO = 1; + const AUTOSCALE_STATIC_NOMINAL = 2; + const AUTOSCALE_STATIC_MAX = 3; + const AUTOSCALE_NORMAL = 4; + const AUTOSCALE_RESIZE = 5; + const AUTOSCALE_CENTER = 6; + const AUTOSCALE_MANUAL = 7; // use gfx_xcenter_pos and gfx_ycenter_pos + const AUTOSCALE_INTEGER = 8; + const AUTOSCALE_INTEGER_AUTOSCALE = 9; + const AUTOSCALE_SEPARATOR = 10; + const AUTOSCALE_OVERSCAN_BLANK = 11;*/ + + /*---------------------------------*/ + /* input */ + + /*const MAX_INPUT_DEVICES 20 // maximum number native input devices supported (single type) + const MAX_INPUT_DEVICE_EVENTS 256 // maximum number of native input device"s buttons and axles supported + const MAX_INPUT_SETTINGS 4 // 4 different customization settings + const GAMEPORT_INPUT_SETTINGS 3 // last slot is for gameport panel mappings + const INTERNALEVENT_COUNT 1 + + const MAX_INPUT_SUB_EVENT 8 + const MAX_INPUT_SUB_EVENT_ALL 9 + const SPARE_SUB_EVENT 8 + + struct uae_input_device { + TCHAR *name; + TCHAR *configname; + uae_s16 eventid[MAX_INPUT_DEVICE_EVENTS][MAX_INPUT_SUB_EVENT_ALL]; + TCHAR *custom[MAX_INPUT_DEVICE_EVENTS][MAX_INPUT_SUB_EVENT_ALL]; + uae_u64 flags[MAX_INPUT_DEVICE_EVENTS][MAX_INPUT_SUB_EVENT_ALL]; + uae_s8 port[MAX_INPUT_DEVICE_EVENTS][MAX_INPUT_SUB_EVENT_ALL]; + uae_s16 extra[MAX_INPUT_DEVICE_EVENTS]; + uae_s8 enabled; + }; + + const MAX_JPORTS_CUSTOM 6 + const MAX_JPORTS 4 + const NORMAL_JPORTS 2 + const MAX_JPORTNAME 128 + struct jport_custom { + TCHAR custom[MAX_DPATH]; + }; + struct inputdevconfig { + TCHAR name[MAX_JPORTNAME]; + TCHAR configname[MAX_JPORTNAME]; + }; + struct jport { + int id; + int mode; // 0=def,1=mouse,2=joy,3=anajoy,4=lightpen + int autofire; + struct inputdevconfig idc; + bool nokeyboardoverride; + }; + const JPORT_NONE -1 + + const JPORT_AF_NORMAL 1 + const JPORT_AF_TOGGLE 2 + const JPORT_AF_ALWAYS 3 + + typedef enum { KBD_LANG_US, KBD_LANG_DK, KBD_LANG_DE, KBD_LANG_SE, KBD_LANG_FR, KBD_LANG_IT, KBD_LANG_ES } KbdLang; + const KBTYPE_AMIGA 0 + const KBTYPE_PC1 1 + const KBTYPE_PC2 2 + + const TABLET_OFF 0 + const TABLET_MOUSEHACK 1 + const TABLET_REAL 2*/ + + /*-----------------------------------------------------------------------*/ + + SAEV_config = new SAEO_Config(); + default_prefs(SAEV_config); + + /*---------------------------------*/ + + this.setup = function() { + if (fixup_prefs(SAEV_config)) + return SAEE_None; + + return SAEE_Config_Invalid; + } + + this.setModel = function(model, config) { + built_in_prefs(SAEV_config, model, config, 2, 0); + return SAEE_None; + } + + this.setDefaults = function() { + default_prefs(SAEV_config); + return SAEE_None; + } + + /*-----------------------------------------------------------------------*/ + + function default_prefs(p) { + //var roms = [ 6, 7, 8, 9, 10, 14, 5, 4, 3, 2, 1, -1 ]; + //var i; + + //reset_inputdevice_config(p); + //memset(p, 0, sizeof(*p)); + + + //p.turbo_emulation = 0; + //p.turbo_emulation_limit = 0; + + p.cpu.model = SAEC_Config_CPU_Model_68000; + p.cpu.speed = SAEC_Config_CPU_Speed_Original; + p.cpu.speedThrottle = 0.0; + p.cpu.clock.multiplier = 0; + p.cpu.clock.frequency = 0; + p.cpu.compatible = 0 ? true : false; + p.cpu.addressSpace24 = true; + /*p.cpu_cycle_exact = 0; + p.cpu_memory_cycle_exact = 0; + p.cpu_idle = 0; + p.mmu_model = 0;*/ + + /*p.fpu_model = 0; + p.fpu_revision = 0; + p.fpu_strict = 0; + p.fpu_softfloat = 0;*/ + + p.chipset.mask = SAEC_Config_Chipset_Mask_ECS_AGNUS; + p.chipset.colLevel = SAEC_Config_Chipset_ColLevel_Sprite_Playfield; + p.chipset.ntsc = false; + p.chipset.genlock = false; + + var cr; + for (var i = 0; i < p.chipset.refresh.length; i++) { + cr = p.chipset.refresh[i]; + cr.index = i; + cr.rate = -1; + } + cr = p.chipset.refresh[SAEC_Config_Chipset_CR_PAL]; + cr.index = SAEC_Config_Chipset_CR_PAL; + cr.horiz = -1; + cr.vert = -1; + cr.lace = -1; + cr.vsync = -1; + cr.framelength = -1; + cr.rate = 50.0; + cr.ntsc = false; + cr.locked = false; + cr.label = "PAL"; + cr = p.chipset.refresh[SAEC_Config_Chipset_CR_NTSC]; + cr.index = SAEC_Config_Chipset_CR_NTSC; + cr.horiz = -1; + cr.vert = -1; + cr.lace = -1; + cr.vsync = -1; + cr.framelength = -1; + cr.rate = 60.0; + cr.ntsc = true; + cr.locked = false; + cr.label = "NTSC"; + /*p.cr_selected = -1; + p.genlock_image = 0; + p.genlock_mix = 0;*/ + + p.chipset.blitter.immediate = false; + p.chipset.blitter.waiting = 0; + p.chipset.blitter.cycle_exact = false; + + p.chipset.cia.todHack = false; + p.chipset.cia.todBug = false; + p.chipset.cia.tod = SAEC_Config_Chipset_CIA_TOD_VSync; + p.chipset.cia.overlay = true; + + //p.chipset.rtc.type = SAEC_Config_RTC_Type_RF5C01A; + p.chipset.rtc.type = SAEC_Config_RTC_Type_None; + //p.chipset.rtc.file = ""; + + p.chipset.compatible = SAEC_Config_Chipset_Compatible_Generic; + p.chipset.a1000ram = 0; + p.chipset.mirrorE0 = true; + p.chipset.mirrorA8 = false; + p.chipset.agnusRev = -1; + p.chipset.deniseRev = -1; + p.chipset.fatGaryRev = -1; + p.chipset.ramseyRev = -1; + p.chipset.df0idhw = true; + p.chipset.ide = 0; + p.chipset.pcmcia = false; + p.chipset.mbdmac = 0; + p.chipset.z3AutoConfig = false; + p.chipset.bogomemIsFast = false; + /*p.cs_cd32c2p = p.cs_cd32cd = p.cs_cd32nvram = p.cs_cd32fmv = false; + p.cs_cd32nvram_size = 1024; + p.cs_cdtvcd = p.cs_cdtvram = false; + p.cs_cdtvcard = 0; + p.cs_resetwarning = 1; + p.cs_color_burst = false;*/ + + //configure_rom(p, roms, 0); + p.memory.rom.clr(); + p.memory.extRom.clr(); + p.memory.romKey.clr(); + p.memory.amaxRom.clr(); + //p.memory.maprom = 0; //0x0f000000 + /*p.romextfile, ""; + p.romextfile2, """; + p.romextfile2addr = 0; + p.flashfile, ""; + p.cartfile, ""; + p.boot_rom = 0; + */ + + p.memory.chipSize = 0x00080000; + p.memory.bogoSize = 0x00080000; + p.memory.z2FastSize = 0x00000000; + p.memory.z2FastAutoConfig = true; + p.memory.z3FastSize = 0x00000000; + p.memory.z3Mapping = SAEC_Config_Memory_z3Mapping_Auto; + p.memory.z3AutoConfigStart = 0x10000000; + p.memory.ramsey.lowSize = 0x00000000; + p.memory.ramsey.highSize = 0x00000000; + p.memory.custom[0].addr = 0; + p.memory.custom[0].size = 0; + p.memory.custom[1].addr = 0; + p.memory.custom[1].size = 0; + p.logIllegal = false; + /*p.fastmem2_size = 0x00000000; + p.mem25bit_size = 0x00000000; + p.z3fastmem2_size = 0x00000000; + p.rtgmem_size = 0x00000000; + p.rtgmem_type = GFXBOARD_UAE_Z3;*/ + + p.floppy.drive[0].type = SAEC_Config_Floppy_Type_35_DD; + p.floppy.drive[1].type = SAEC_Config_Floppy_Type_35_DD; + p.floppy.drive[2].type = SAEC_Config_Floppy_Type_None; + p.floppy.drive[3].type = SAEC_Config_Floppy_Type_None; + p.floppy.drive[0].file.clr(); + p.floppy.drive[1].file.clr(); + p.floppy.drive[2].file.clr(); + p.floppy.drive[3].file.clr(); + p.floppy.readOnly = false; + //p.floppy.writeLength = 0; + p.floppy.randomBitsMin = 1; + p.floppy.randomBitsMax = 3; + p.floppy.speed = 100; + //c.floppy.speed = SAEC_Config_Floppy_Speed_Original; + //c.floppy.speed = SAEC_Config_Floppy_Speed_Turbo; + p.floppy.autoEXT2 = 0; + /*p.nr_floppies = 2; + p.dfxclickvolume_disk[0] = 33; + p.dfxclickvolume_disk[1] = 33; + p.dfxclickvolume_empty[0] = 33; + p.dfxclickvolume_empty[1] = 33; + p.dfxclickchannelmask = 0xffff;*/ + + //p.mount.items = 0; + for (var i = 0; i < 6; i++) { + p.mount.config[i].configoffset = -1; + p.mount.config[i].unitnum = -1; + } + /*p.cd_speed = 100; + p.inprec_autoplay = true; + p.filesys_limit = 0; + p.filesys_max_name = 107; + p.filesys_max_file_size = 0x7fffffff; + p.filesys_no_uaefsdb = 0; + p.filesys_custom_uaefsdb = 1;*/ + + p.video.id = "video"; + p.video.enabled = true; + p.video.scandoubler = false; + p.video.framerate = 1; + p.video.hresolution = SAEC_Config_Video_HResolution_HiRes; + p.video.vresolution = SAEC_Config_Video_VResolution_Double; + p.video.pscanlines = 0; //1 enabled, 2 double fields, 3 double fields+ + p.video.iscanlines = 0; //0 normal, 1 fields, 2 fields+ + p.video.xcenter = 0; + p.video.ycenter = 0; + p.video.backgroundColor = 0x000000; + p.video.luminance = 0; + p.video.contrast = 0; + p.video.gamma = 0; + p.video.alpha = 255; + p.video.antialias = true; + p.video.size_fs.width = screen.width; //800; + p.video.size_fs.height = screen.height; //600; + //p.video.size_win.width = 768; + //p.video.size_win.height = 576; + //p.video.size_win.width = 720; + //p.video.size_win.height = 568; + p.video.size_win.width = SAEC_Video_DEF_AMIGA_WIDTH << 1; + p.video.size_win.height = SAEC_Video_DEF_AMIGA_HEIGHT << 1; + p.video.apmode[0].gfx_display = 1; + p.video.apmode[0].gfx_fullscreen = SAEC_Config_Video_AP_Fullscreen_WINDOW; + p.video.apmode[1].gfx_fullscreen = SAEC_Config_Video_AP_Fullscreen_WINDOW; + p.video.apmode[0].gfx_backbuffers = 0; //2; //1 double, 2 tripple + p.video.apmode[1].gfx_backbuffers = 0; + for (var i = 0; i <= 1; i++) { + var f = p.video.gf[i]; + f.gfx_filter = 0; + f.gfx_filter_scanlineratio = (1 << 4) | 1; + for (var j = 0; j <= 2 * MAX_FILTERSHADERS; j++) { + f.gfx_filtershader[i][0] = 0; + f.gfx_filtermask[i][0] = 0; + } + f.gfx_filter_horiz_zoom_mult = 1.0; + f.gfx_filter_vert_zoom_mult = 1.0; + f.gfx_filter_bilinear = 0; + f.gfx_filter_filtermode = 0; + f.gfx_filter_keep_aspect = 0; + f.gfx_filter_autoscale = 0; //AUTOSCALE_STATIC_AUTO; + f.gfx_filter_keep_autoscale_aspect = false; + f.gfx_filteroverlay_overscan = 0; + } + p.video.api = SAEC_Config_Video_API_WebGL; + p.video.colorMode = 2; /* < 5 == 16 bit else 32 bit */ + p.video.blackerThanBlack = false; + /*for (i = 0; i < 4; i++) { + p.gfx_size_fs_xtra[i].width = 0; + p.gfx_size_fs_xtra[i].height = 0; + p.gfx_size_win_xtra[i].width = 0; + p.gfx_size_win_xtra[i].height = 0; + } + p.gfx_xcenter_pos = -1; + p.gfx_ycenter_pos = -1; + p.gfx_xcenter_size = -1; + p.gfx_ycenter_size = -1; + p.gfx_max_horizontal = SAEC_Config_Video_HResolution_HiRes; + p.gfx_max_vertical = SAEC_Config_Video_VResolution_Double; + p.gfx_autoresolution_minv = 0; + p.gfx_autoresolution_minh = 0; + p.gfx_autoresolution_vga = true; + p.gfx_autoframerate = 50; //unused by winuae + p.rtg_horiz_zoom_mult = 1.0; + p.rtg_vert_zoom_mult = 1.0; + p.picasso96_nocustom = 1;*/ + + p.audio.bufferFrames = 4096; + p.audio.mode = SAEC_Config_Audio_Mode_On_Best; + p.audio.channels = SAEC_Config_Audio_Channels_Stereo; + p.audio.stereoSeparation = 10; /* 0-10 resp. 0-100%, 10 == no separation */ + p.audio.stereoDelay = 0; /* 0-10, 0 == no delay */ + p.audio.freq = SAEC_Config_Audio_Freq_Auto; + //p.audio.interpol = SAEC_Config_Audio_Interpol_Anti; + p.audio.interpol = SAEC_Config_Audio_Interpol_None; /* use no interpolation, for more speed */ + p.audio.filter = SAEC_Config_Audio_Filter_Emul; + p.audio.filterType = 0; + /*p.sound_maxbsiz = DEFAULT_SOUND_MAXB; + p.sound_auto = 1; + p.sound_cdaudio = false;*/ + + p.ports[0].type = SAEC_Config_Ports_Type_Mouse; + p.ports[0].move = SAEC_Config_Ports_Move_WASD; + p.ports[0].fire = [49,50]; + p.ports[1].type = SAEC_Config_Ports_Type_Joy1; + p.ports[1].move = SAEC_Config_Ports_Move_Arrows; + p.ports[1].fire = [16,17]; + /*memset (&p.jports[0], 0, sizeof (struct jport)); + memset (&p.jports[1], 0, sizeof (struct jport)); + memset (&p.jports[2], 0, sizeof (struct jport)); + memset (&p.jports[3], 0, sizeof (struct jport)); + p.jports[0].id = JSEM_MICE; + p.jports[1].id = JSEM_KBDLAYOUT; + p.jports[2].id = -1; + p.jports[3].id = -1; + p.input_tablet = TABLET_OFF; + p.tablet_library = false; + p.input_magic_mouse = 0; + p.input_magic_mouse_cursor = 0; + inputdevice_default_prefs (p);*/ + + p.keyboard.enabled = true; + //p.keyboard_lang = KBD_LANG_US; + + p.serial.enabled = false; + p.serial.demand = false; + //p.serial_hwctsrts = 1; + //p.serial_stopbits = 0; + //p.sername[0] = 0; + + /*p.parallel_demand = 0; + p.parallel_matrix_emulation = 0; + p.parallel_postscript_emulation = 0; + p.parallel_postscript_detection = 0; + p.parallel_autoflush_time = 5; + p.ghostscript_parameters[0] = 0; + p.prtname[0] = 0;*/ + + /*p.leds_on_screen = 0; + p.leds_on_screen_mask[0] = p.leds_on_screen_mask[1] = (1 << SAEC_GUI_LED_MAX) - 1; + p.keyboard_leds_in_use = 0; + p.keyboard_leds[0] = p.keyboard_leds[1] = p.keyboard_leds[2] = 0;*/ + + //p.debug.level = SAEC_Config_Debug_Level_Error; + p.debug.level = SAEC_Config_Debug_Level_Warn; + //p.debug.level = SAEC_Config_Debug_Level_Info; + //p.debug.level = SAEC_Config_Debug_Level_Log; + } + + /*-----------------------------------------------------------------------*/ + + function buildin_default_prefs_68020(p) { + p.cpu.model = SAEC_Config_CPU_Model_68020; + p.cpu.speed = SAEC_Config_CPU_Speed_Original; //SAEC_Config_CPU_Speed_Maximum; + p.cpu.compatible = 0 ? true : false; + p.cpu.addressSpace24 = true; + p.chipset.mask = SAEC_Config_Chipset_Mask_ECS_AGNUS | SAEC_Config_Chipset_Mask_ECS_DENISE | SAEC_Config_Chipset_Mask_AGA; + p.memory.chipSize = 0x200000; + p.memory.bogoSize = 0; + } + + function buildin_default_prefs(p) { + p.cpu.model = SAEC_Config_CPU_Model_68000; + p.cpu.speed = SAEC_Config_CPU_Speed_Original; + p.cpu.clock.multiplier = 0; + p.cpu.clock.frequency = 0; + p.cpu.compatible = false; //true; + p.cpu.addressSpace24 = true; + /*p.fpu_model = 0; + p.fpu_revision = -1; + p.cpu_cycle_exact = 0; + p.cpu_memory_cycle_exact = 0; + p.cpu_idle = 0; + p.turbo_emulation = 0; + p.turbo_emulation_limit = 0; + */ + + p.chipset.mask = SAEC_Config_Chipset_Mask_ECS_AGNUS; + p.chipset.colLevel = SAEC_Config_Chipset_ColLevel_Sprite_Playfield; + + p.chipset.blitter.immediate = false; + p.chipset.blitter.waiting = 0; + p.chipset.blitter.cycle_exact = false; + + p.chipset.cia.todHack = false; + p.chipset.cia.todBug = false; + p.chipset.cia.tod = SAEC_Config_Chipset_CIA_TOD_VSync; + p.chipset.cia.overlay = true; + + p.chipset.rtc.type = SAEC_Config_RTC_Type_None; + + p.chipset.compatible = SAEC_Config_Chipset_Compatible_Generic; + p.chipset.a1000ram = false; + p.chipset.mirrorE0 = true; + p.chipset.mirrorA8 = false; + p.chipset.agnusRev = -1; + p.chipset.deniseRev = -1; + p.chipset.fatGaryRev = -1; + p.chipset.ramseyRev = -1; + p.chipset.df0idhw = true; + p.chipset.ide = 0; + p.chipset.pcmcia = false; + p.chipset.mbdmac = 0; + p.chipset.jumper1MbChip = false; + /*p.cs_cd32c2p = p.cs_cd32cd = p.cs_cd32nvram = p.cs_cd32fmv = false; + p.cs_cdtvcd = p.cs_cdtvram = false; + p.cs_cdtvcard = 0; + p.cs_resetwarning = 0; + */ + + p.memory.chipSize = 0x00080000; + p.memory.bogoSize = 0x00080000; + p.memory.z2FastSize = 0x00000000; + p.memory.z3FastSize = 0x00000000; + p.memory.ramsey.lowSize = 0x00000000; + p.memory.ramsey.highSize = 0x00000000; + //p.memory.maprom = 0; + /*p.mem25bit_size = 0x00000000; + p.z3fastmem2_size = 0x00000000; + p.z3chipmem_size = 0x00000000; + p.rtgmem_size = 0x00000000; + p.rtgmem_type = GFXBOARD_UAE_Z3;*/ + + /*p.romextfile, ""; + p.romextfile2, ""; + set_device_rom(p, NULL, SAEC_RomType_CPUBOARD, 0);*/ + + p.floppy.drive[0].type = SAEC_Config_Floppy_Type_35_DD; + //if (p.nr_floppies != 1 && p.nr_floppies != 2) p.nr_floppies = 2; + //p.floppy.drive[1].type = p.nr_floppies >= 2 ? SAEC_Config_Floppy_Type_35_DD : SAEC_Config_Floppy_Type_None; + p.floppy.drive[1].type = SAEC_Config_Floppy_Type_35_DD; + p.floppy.drive[2].type = SAEC_Config_Floppy_Type_None; + p.floppy.drive[3].type = SAEC_Config_Floppy_Type_None; + p.floppy.speed = 100; + + //p.mount.items = 0; + + if (p.audio.mode == SAEC_Config_Audio_Mode_Off) p.audio.mode = SAEC_Config_Audio_Mode_Off_Emul; + /*p.sound_volume_master = 0; + p.sound_volume_paula = 0; + p.sound_volume_cd = 0;*/ + + /*p.prtname[0] = 0; + p.sername[0] = 0;*/ + } + + function built_in_chipset_prefs(p) { + if (p.chipset.compatible == SAEC_Config_Chipset_Compatible_Manual) + return 1; + + p.chipset.cia.todBug = false; + p.chipset.cia.tod = SAEC_Config_Chipset_CIA_TOD_VSync; + p.chipset.cia.overlay = true; + p.chipset.cia.type6526 = false; + p.chipset.rtc.type = SAEC_Config_RTC_Type_None; + p.chipset.rtc.adjust = 0; + p.chipset.a1000ram = 0; + p.chipset.mirrorE0 = true; + p.chipset.mirrorA8 = false; + p.chipset.agnusRev = -1; + p.chipset.agnusDIP = false; + p.chipset.agnusBltBusyBug = false; + p.chipset.deniseRev = -1; + p.chipset.deniseNoEHB = false; + p.chipset.fatGaryRev = -1; + p.chipset.ramseyRev = -1; + p.chipset.df0idhw = true; + p.chipset.ide = 0; + p.chipset.pcmcia = false; + p.chipset.mbdmac = 0; + p.chipset.z3AutoConfig = false; + p.chipset.bogomemIsFast = false; + /*p.cs_cd32c2p = p.cs_cd32cd = p.cs_cd32nvram = 0; + p.cs_cdtvcd = p.cs_cdtvram = p.cs_cdtvscsi = p.cs_cdtvcr = 0; + p.cs_resetwarning = 1; + p.cs_bytecustomwritebug = false;*/ + + switch (p.chipset.compatible) { + case SAEC_Config_Chipset_Compatible_Generic: // generic + if (p.cpu.model >= SAEC_Config_CPU_Model_68020) { + // big box-like + p.chipset.rtc.type = SAEC_Config_RTC_Type_RF5C01A; + p.chipset.fatGaryRev = 0; + p.chipset.ramseyRev = 0x0f; + p.chipset.ide = -1; + p.chipset.mbdmac = -1; + } else if (p.cpu.compatible) { + // very A500-like + p.chipset.df0idhw = false; + //p.cs_resetwarning = 0; + if (p.memory.bogoSize || p.memory.chipSize > 0x80000 || p.memory.z2FastSize) + p.chipset.rtc.type = SAEC_Config_RTC_Type_MSM6242B; + p.chipset.cia.todBug = true; + } else { + // sort of A500-like + p.chipset.ide = -1; + p.chipset.rtc.type = SAEC_Config_RTC_Type_MSM6242B; + } + break; + case SAEC_Config_Chipset_Compatible_CDTV: // CDTV + p.chipset.rtc.type = SAEC_Config_RTC_Type_MSM6242B; + //p.cs_cdtvcd = p.cs_cdtvram = 1; + p.chipset.df0idhw = true; + p.chipset.mirrorE0 = false; + break; + case SAEC_Config_Chipset_Compatible_CDTVCR: // CDTV-CR + p.chipset.rtc.type = SAEC_Config_RTC_Type_MSM6242B; + //p.cs_cdtvcd = p.cs_cdtvram = 1; + //p.cs_cdtvcr = true; + p.chipset.df0idhw = true; + p.chipset.mirrorE0 = false; + p.chipset.ide = SAEC_Config_Chipset_IDE_A600A1200; + p.chipset.pcmcia = true; + p.chipset.mirrorA8 = true; + p.chipset.cia.overlay = false; + //p.cs_resetwarning = 0; + p.chipset.cia.todBug = true; + break; + case SAEC_Config_Chipset_Compatible_CD32: // CD32 + //p.cs_cd32c2p = p.cs_cd32cd = p.cs_cd32nvram = true; + p.chipset.mirrorE0 = false; + p.chipset.mirrorA8 = true; + p.chipset.cia.overlay = false; + //p.cs_resetwarning = 0; + break; + case SAEC_Config_Chipset_Compatible_A500: // A500 + p.chipset.df0idhw = false; + //p.cs_resetwarning = 0; + if (p.memory.bogoSize || p.memory.chipSize > 0x80000 || p.memory.z2FastSize) + p.chipset.rtc.type = SAEC_Config_RTC_Type_MSM6242B; + p.chipset.cia.todBug = true; + break; + case SAEC_Config_Chipset_Compatible_A500P: // A500+ + p.chipset.rtc.type = SAEC_Config_RTC_Type_MSM6242B; + //p.cs_resetwarning = 0; + p.chipset.cia.todBug = true; + break; + case SAEC_Config_Chipset_Compatible_A600: // A600 + p.chipset.ide = SAEC_Config_Chipset_IDE_A600A1200; + p.chipset.pcmcia = true; + p.chipset.mirrorA8 = true; + p.chipset.cia.overlay = false; + //p.cs_resetwarning = 0; + p.chipset.cia.todBug = true; + break; + case SAEC_Config_Chipset_Compatible_A1000: // A1000 + p.chipset.a1000ram = 1; + p.chipset.cia.tod = p.chipset.ntsc ? SAEC_Config_Chipset_CIA_TOD_60Hz : SAEC_Config_Chipset_CIA_TOD_50Hz; + p.chipset.mirrorE0 = false; + p.chipset.agnusBltBusyBug = true; + p.chipset.agnusDIP = true; + p.chipset.cia.todBug = true; + break; + case SAEC_Config_Chipset_Compatible_A1000V: // A1000 Prototype + p.chipset.cia.tod = p.chipset.ntsc ? SAEC_Config_Chipset_CIA_TOD_60Hz : SAEC_Config_Chipset_CIA_TOD_50Hz; + p.chipset.mirrorE0 = false; + p.chipset.agnusBltBusyBug = true; + p.chipset.agnusDIP = true; + p.chipset.deniseNoEHB = true; + break; + case SAEC_Config_Chipset_Compatible_A1200: // A1200 + p.chipset.ide = SAEC_Config_Chipset_IDE_A600A1200; + p.chipset.pcmcia = true; + p.chipset.mirrorA8 = true; + p.chipset.cia.overlay = false; + if (p.memory.z2FastSize || p.memory.z3FastSize) + p.chipset.rtc.type = SAEC_Config_RTC_Type_MSM6242B; + break; + case SAEC_Config_Chipset_Compatible_A2000: // A2000 + //p.chipset.rtc.type = SAEC_Config_RTC_Type_MSM6242B; + p.chipset.rtc.type = SAEC_Config_RTC_Type_MSM6242B_A2000; //OWN + p.chipset.cia.tod = p.chipset.ntsc ? SAEC_Config_Chipset_CIA_TOD_60Hz : SAEC_Config_Chipset_CIA_TOD_50Hz; + p.chipset.cia.todBug = true; + break; + case SAEC_Config_Chipset_Compatible_A3000: // A3000 + p.chipset.rtc.type = SAEC_Config_RTC_Type_RF5C01A; + p.chipset.fatGaryRev = 0; + p.chipset.ramseyRev = 0x0d; + p.chipset.mbdmac = 1; + p.chipset.mirrorE0 = false; + p.chipset.cia.tod = p.chipset.ntsc ? SAEC_Config_Chipset_CIA_TOD_60Hz : SAEC_Config_Chipset_CIA_TOD_50Hz; + p.chipset.z3AutoConfig = true; + break; + case SAEC_Config_Chipset_Compatible_A4000: // A4000 + p.chipset.rtc.type = SAEC_Config_RTC_Type_RF5C01A; + p.chipset.fatGaryRev = 0; + p.chipset.ramseyRev = 0x0f; + p.chipset.ide = SAEC_Config_Chipset_IDE_A4000; + p.chipset.mbdmac = 0; + p.chipset.mirrorA8 = false; + p.chipset.mirrorE0 = false; + p.chipset.cia.overlay = false; + p.chipset.z3AutoConfig = true; + break; + case SAEC_Config_Chipset_Compatible_A4000T: // A4000T + p.chipset.rtc.type = SAEC_Config_RTC_Type_RF5C01A; + p.chipset.fatGaryRev = 0; + p.chipset.ramseyRev = 0x0f; + p.chipset.ide = SAEC_Config_Chipset_IDE_A4000; + p.chipset.mbdmac = 2; + p.chipset.mirrorA8 = false; + p.chipset.mirrorE0 = false; + p.chipset.cia.overlay = false; + p.chipset.z3AutoConfig = true; + break; + } + //if (p.cpu.model >= SAEC_Config_CPU_Model_68040) p.cs_bytecustomwritebug = true; + return 1; + } + + /* 0: cycle-exact + * 1: more compatible + * 2: no more compatible, no 100% sound + * 3: no more compatible, waiting blits, no 100% sound + */ + function set_68000_compa(p, compa) { + p.cpu.clock.multiplier = 2 << 8; + switch (compa) { + case 0: + p.chipset.blitter.cycle_exact = true; //p.cpu_cycle_exact = p.cpu_memory_cycle_exact = p.chipset.blitter.cycle_exact = true; + break; + case 1: + p.cpu.compatible = true; + break; + case 2: //used + p.cpu.compatible = false; + break; + /*case 3: + p.audio.mode = SAEC_Config_Audio_Mode_On; + p.cpu.compatible = false; + break;*/ + } + } + function set_68020_compa(p, compa, cd32) { + switch (compa) { + case 0: + p.chipset.blitter.cycle_exact = true; + //p.cpu.speed = SAEC_Config_CPU_Speed_Original; + /*if (p.cpu.model == SAEC_Config_CPU_Model_68020) { + p.cpu_cycle_exact = 1; + p.cpu_memory_cycle_exact = 1; + p.cpu.clock.multiplier = 4 << 8; + }*/ + break; + case 1: + p.cpu.compatible = true; + //p.cpu.speed = SAEC_Config_CPU_Speed_Original; + break; + case 2: //used + p.cpu.compatible = false; + //p.cpu.speed = SAEC_Config_CPU_Speed_Maximum; + //p.cpu.addressSpace24 = false; + break; + /*case 3: + p.cpu.compatible = false; + p.cpu.addressSpace24 = false; + break;*/ + } + } + + function bip_a3000(p, config, compa, romcheck) { + /*int roms[2]; + if (config == 2) roms[0] = 61; + else if (config == 1) roms[0] = 71; + else roms[0] = 59; + roms[1] = -1;*/ + + p.memory.bogoSize = 0; + p.memory.chipSize = 0x200000; + //p.memory.ramsey.lowSize = 8 * 1024 * 1024; + p.memory.ramsey.lowSize = 2 * 1024 * 1024; //OWN + p.cpu.model = SAEC_Config_CPU_Model_68030; + //p.cpu.speed = SAEC_Config_CPU_Speed_Maximum; //OWN + p.cpu.compatible = p.cpu.addressSpace24 = false; + /*p.fpu_model = 68882; + p.fpu_no_unimplemented = true; + if (compa == 0) + p.mmu_model = 68030; + else + p.cachesize = MAX_JIT_CACHE;*/ + p.chipset.mask = SAEC_Config_Chipset_Mask_ECS_AGNUS | SAEC_Config_Chipset_Mask_ECS_DENISE; + p.chipset.blitter.immediate = false; + p.audio.mode = SAEC_Config_Audio_Mode_On; + p.floppy.drive[0].type = SAEC_Config_Floppy_Type_35_HD; + p.floppy.speed = 0; + //p.cpu_idle = 150; + p.chipset.compatible = SAEC_Config_Chipset_Compatible_A3000; + built_in_chipset_prefs(p); + p.chipset.cia.tod = p.chipset.ntsc ? SAEC_Config_Chipset_CIA_TOD_60Hz : SAEC_Config_Chipset_CIA_TOD_50Hz; + return 1; //configure_rom(p, roms, romcheck); + } + function bip_a4000(p, config, compa, romcheck) { + /*int roms[8]; + roms[0] = 16; + roms[1] = 31; + roms[2] = 13; + roms[3] = 12; + roms[4] = -1;*/ + + p.memory.bogoSize = 0; + p.memory.chipSize = 0x200000; + p.memory.ramsey.lowSize = 8 * 1024 * 1024; + p.cpu.model = SAEC_Config_CPU_Model_68030; + //p.cpu.speed = SAEC_Config_CPU_Speed_Maximum; //OWN + p.cpu.compatible = p.cpu.addressSpace24 = false; + //p.fpu_model = 68882; + /*if (config == 1) { + p.cpu.model = SAEC_Config_CPU_Model_68040; + //p.fpu_model = 68040; + }*/ + p.chipset.mask = SAEC_Config_Chipset_Mask_AGA | SAEC_Config_Chipset_Mask_ECS_AGNUS | SAEC_Config_Chipset_Mask_ECS_DENISE; + p.chipset.blitter.immediate = false; + p.audio.mode = SAEC_Config_Audio_Mode_On; + p.floppy.drive[0].type = SAEC_Config_Floppy_Type_35_HD; + p.floppy.drive[1].type = SAEC_Config_Floppy_Type_35_HD; + p.floppy.speed = 0; + //p.cpu_idle = 150; + p.chipset.compatible = SAEC_Config_Chipset_Compatible_A4000; + built_in_chipset_prefs(p); + p.chipset.cia.tod = p.chipset.ntsc ? SAEC_Config_Chipset_CIA_TOD_60Hz : SAEC_Config_Chipset_CIA_TOD_50Hz; + return 1; //configure_rom (p, roms, romcheck); + } + function bip_a4000t(p, config, compa, romcheck) { + /*int roms[8]; + roms[0] = 16; + roms[1] = 31; + roms[2] = 13; + roms[3] = -1;*/ + + p.memory.bogoSize = 0; + p.memory.chipSize = 0x200000; + p.memory.ramsey.lowSize = 8 * 1024 * 1024; + p.cpu.model = SAEC_Config_CPU_Model_68030; + //p.cpu.speed = SAEC_Config_CPU_Speed_Maximum; //OWN + p.cpu.compatible = p.cpu.addressSpace24 = false; + //p.fpu_model = 68882; + /*if (config == 1) { + p.cpu.model = SAEC_Config_CPU_Model_68040; + //p.fpu_model = 68040; + }*/ + p.chipset.mask = SAEC_Config_Chipset_Mask_AGA | SAEC_Config_Chipset_Mask_ECS_AGNUS | SAEC_Config_Chipset_Mask_ECS_DENISE; + p.chipset.blitter.immediate = false; + p.audio.mode = SAEC_Config_Audio_Mode_On; + p.floppy.drive[0].type = SAEC_Config_Floppy_Type_35_HD; + p.floppy.drive[1].type = SAEC_Config_Floppy_Type_35_HD; + p.floppy.speed = 0; + //p.cpu_idle = 150; + p.chipset.compatible = SAEC_Config_Chipset_Compatible_A4000T; + built_in_chipset_prefs(p); + p.chipset.cia.tod = p.chipset.ntsc ? SAEC_Config_Chipset_CIA_TOD_60Hz : SAEC_Config_Chipset_CIA_TOD_50Hz; + return 1; //configure_rom (p, roms, romcheck); + } + + function bip_velvet(p, config, compa, romcheck) { + p.chipset.mask = 0; + p.memory.bogoSize = 0; + p.audio.filter = SAEC_Config_Audio_Filter_On; + set_68000_compa(p, compa); + p.floppy.drive[1].type = SAEC_Config_Floppy_Type_None; + p.chipset.bogomemIsFast = true; + p.chipset.agnusDIP = true; + p.chipset.agnusBltBusyBug = true; + p.chipset.compatible = SAEC_Config_Chipset_Compatible_A1000V; + built_in_chipset_prefs(p); + p.chipset.deniseNoEHB = true; + p.chipset.cia.type6526 = true; + p.memory.chipSize = 0x40000; + } + + function bip_a1000(p, config, compa, romcheck) { + /*int roms[2]; + roms[0] = 24; + roms[1] = -1;*/ + p.chipset.mask = 0; + p.memory.bogoSize = 0; + p.audio.filter = SAEC_Config_Audio_Filter_On; + set_68000_compa(p, compa); + p.floppy.drive[1].type = SAEC_Config_Floppy_Type_None; + p.chipset.bogomemIsFast = true; + p.chipset.agnusDIP = true; + p.chipset.agnusBltBusyBug = true; + p.chipset.compatible = SAEC_Config_Chipset_Compatible_A1000; + built_in_chipset_prefs(p); + if (config == 1) + p.memory.chipSize = 0x40000; + else if (config == 2) { + p.chipset.deniseNoEHB = true; + p.memory.chipSize = 0x40000; + } else if (config == 3) { + //roms[0] = 125; + //roms[1] = -1; + bip_velvet(p, config, compa, romcheck); + } + return 1; //configure_rom (p, roms, romcheck); + } + + function bip_cdtvcr(p, config, compa, romcheck) { + //int roms[4]; + p.memory.bogoSize = 0; + p.memory.chipSize = 0x100000; + p.chipset.mask = SAEC_Config_Chipset_Mask_ECS_AGNUS | SAEC_Config_Chipset_Mask_ECS_DENISE; + //p.cs_cdtvcd = p.cs_cdtvram = true; + //p.cs_cdtvcr = true; + p.chipset.rtc.type = SAEC_Config_RTC_Type_MSM6242B; + //p.nr_floppies = 0; + p.floppy.drive[0].type = SAEC_Config_Floppy_Type_None; + p.floppy.drive[1].type = SAEC_Config_Floppy_Type_None; + set_68000_compa(p, compa); + p.chipset.compatible = SAEC_Config_Chipset_Compatible_CDTVCR; + built_in_chipset_prefs(p); + /*fetch_datapath (p.flashfile, sizeof (p.flashfile) / sizeof (TCHAR)); + p.flashfile = "cdtv-cr.nvr"; + roms[0] = 9; + roms[1] = 10; + roms[2] = -1; + if (!configure_rom (p, roms, romcheck)) return 0; + roms[0] = 108; + roms[1] = 107; + roms[2] = -1; + if (!configure_rom (p, roms, romcheck)) return 0;*/ + return 1; + } + function bip_cdtv(p, config, compa, romcheck) { + //int roms[4]; + if (config == 1) + return bip_cdtvcr(p, config - 2, compa, romcheck); + + p.memory.bogoSize = 0; + p.memory.chipSize = 0x100000; + p.chipset.mask = SAEC_Config_Chipset_Mask_ECS_AGNUS; + //p.cs_cdtvcd = p.cs_cdtvram = 1; + //if (config > 0) p.cs_cdtvcard = 64; + p.chipset.rtc.type = SAEC_Config_RTC_Type_MSM6242B; + //p.nr_floppies = 0; + p.floppy.drive[0].type = SAEC_Config_Floppy_Type_None; + p.floppy.drive[1].type = SAEC_Config_Floppy_Type_None; + set_68000_compa(p, compa); + p.chipset.compatible = SAEC_Config_Chipset_Compatible_CDTV; + built_in_chipset_prefs(p); + /*fetch_datapath (p.flashfile, sizeof (p.flashfile) / sizeof (TCHAR)); + _tcscat (p.flashfile, "cdtv.nvr"; + roms[0] = 6; + roms[1] = 32; + roms[2] = -1; + if (!configure_rom (p, roms, romcheck)) return 0; + roms[0] = 20; + roms[1] = 21; + roms[2] = 22; + roms[3] = -1; + if (!configure_rom (p, roms, romcheck)) return 0;*/ + return 1; + } + + function bip_cd32(p, config, compa, romcheck) { + //int roms[3]; + buildin_default_prefs_68020(p); + //p.cs_cd32c2p = p.cs_cd32cd = p.cs_cd32nvram = true; + //p.nr_floppies = 0; + p.floppy.drive[0].type = SAEC_Config_Floppy_Type_None; + p.floppy.drive[1].type = SAEC_Config_Floppy_Type_None; + set_68020_compa(p, compa, true); + p.chipset.compatible = SAEC_Config_Chipset_Compatible_CD32; + built_in_chipset_prefs(p); + /*fetch_datapath (p.flashfile, sizeof (p.flashfile) / sizeof (TCHAR)); + _tcscat (p.flashfile, "cd32.nvr"; + roms[0] = 64; + roms[1] = -1; + if (!configure_rom (p, roms, 0)) { + roms[0] = 18; + roms[1] = -1; + if (!configure_rom (p, roms, romcheck)) + return 0; + roms[0] = 19; + if (!configure_rom (p, roms, romcheck)) + return 0; + } + if (config > 0) { + //p.cs_cd32fmv = true; + roms[0] = 74; + roms[1] = 23; + roms[2] = -1; + if (!configure_rom (p, roms, romcheck)) + return 0; + }*/ + return 1; + } + + function bip_a1200(p, config, compa, romcheck) { + /*int roms[4]; + roms[0] = 11; + roms[1] = 15; + roms[2] = 31; + roms[3] = -1;*/ + buildin_default_prefs_68020(p); + p.chipset.rtc.type = SAEC_Config_RTC_Type_None; + p.chipset.compatible = SAEC_Config_Chipset_Compatible_A1200; + built_in_chipset_prefs(p); + if (config == 1) { //4mb fastram extended + p.memory.z2FastSize = 0x400000; + p.chipset.rtc.type = SAEC_Config_RTC_Type_MSM6242B; + } + set_68020_compa(p, compa, false); + return 1; //configure_rom (p, roms, romcheck); + } + + function bip_a600(p, config, compa, romcheck) { + /*int roms[4]; + roms[0] = 10; + roms[1] = 9; + roms[2] = 8; + roms[3] = -1;*/ + set_68000_compa(p, compa); + p.chipset.compatible = SAEC_Config_Chipset_Compatible_A600; + built_in_chipset_prefs(p); + p.memory.bogoSize = 0; + p.memory.chipSize = 0x100000; + if (config == 1) { + p.chipset.rtc.type = SAEC_Config_RTC_Type_MSM6242B; + p.memory.chipSize = 0x200000; + } + else if (config == 2) { + p.chipset.rtc.type = SAEC_Config_RTC_Type_MSM6242B; + p.memory.chipSize = 0x200000; + p.memory.z2FastSize = 0x400000; + } + p.chipset.mask = SAEC_Config_Chipset_Mask_ECS_AGNUS | SAEC_Config_Chipset_Mask_ECS_DENISE; + return 1; //configure_rom (p, roms, romcheck); + } + + function bip_a500p(p, config, compa, romcheck) { + /*int roms[2]; + roms[0] = 7; + roms[1] = -1;*/ + set_68000_compa(p, compa); + p.chipset.compatible = SAEC_Config_Chipset_Compatible_A500P; + built_in_chipset_prefs(p); + p.memory.bogoSize = 0; + p.memory.chipSize = 0x100000; + if (config == 1) { + //p.chipset.rtc.type = SAEC_Config_RTC_Type_MSM6242B; + p.memory.chipSize = 0x200000; + } + else if (config == 2) { + //p.chipset.rtc.type = SAEC_Config_RTC_Type_MSM6242B; + p.memory.chipSize = 0x200000; + p.memory.z2FastSize = 0x400000; + } + p.chipset.mask = SAEC_Config_Chipset_Mask_ECS_AGNUS | SAEC_Config_Chipset_Mask_ECS_DENISE; + return 1; //configure_rom (p, roms, romcheck); + } + function bip_a500(p, config, compa, romcheck) { + //int roms[4]; roms[0] = roms[1] = roms[2] = roms[3] = -1; + switch (config) { + case 0: // KS 1.3, OCS Agnus, 0.5M Chip + 0.5M Slow + //roms[0] = 6; + //roms[1] = 32; + p.chipset.mask = 0; + break; + case 1: // KS 1.3, ECS Agnus, 0.5M Chip + 0.5M Slow + //roms[0] = 6; + //roms[1] = 32; + break; + case 2: // KS 1.3, ECS Agnus, 1.0M Chip + //roms[0] = 6; + //roms[1] = 32; + p.memory.bogoSize = 0; + p.memory.chipSize = 0x100000; + break; + /*case 3: // KS 1.3, OCS Agnus, 0.5M Chip + //roms[0] = 6; + //roms[1] = 32; + p.memory.bogoSize = 0; + p.chipset.mask = 0; + p.chipset.rtc.type = SAEC_Config_RTC_Type_None; + p.floppy.drive[1].type = SAEC_Config_Floppy_Type_None; + break; + case 4: // KS 1.2, OCS Agnus, 0.5M Chip + //roms[0] = 5; + //roms[1] = 4; + //roms[2] = 3; + p.memory.bogoSize = 0; + p.chipset.mask = 0; + p.chipset.rtc.type = SAEC_Config_RTC_Type_None; + p.floppy.drive[1].type = SAEC_Config_Floppy_Type_None; + break; + case 5: // KS 1.2, OCS Agnus, 0.5M Chip + 0.5M Slow + //roms[0] = 5; + //roms[1] = 4; + //roms[2] = 3; + p.chipset.mask = 0; + break;*/ + } + set_68000_compa(p, compa); + p.chipset.compatible = SAEC_Config_Chipset_Compatible_A500; + built_in_chipset_prefs(p); + return 1; //configure_rom (p, roms, romcheck); + } + + function bip_a2000(p, config, compa, romcheck) { + p.chipset.compatible = SAEC_Config_Chipset_Compatible_A2000; + built_in_chipset_prefs(p); + return 1; + } + + /*function bip_super(p, config, compa, romcheck) { + int roms[7]; + roms[0] = 16; + roms[1] = 31; + roms[2] = 15; + roms[3] = 14; + roms[4] = 12; + roms[5] = 11; + roms[6] = -1; + p.memory.bogoSize = 0; + p.memory.chipSize = 0x400000; + p.memory.z3FastSize = 8 * 1024 * 1024; + //p.rtgmem_size = 16 * 1024 * 1024; + p.cpu.model = SAEC_Config_CPU_Model_68040; + //p.fpu_model = 68040; + p.chipset.mask = SAEC_Config_Chipset_Mask_AGA | SAEC_Config_Chipset_Mask_ECS_AGNUS | SAEC_Config_Chipset_Mask_ECS_DENISE; + p.cpu.compatible = p.cpu.addressSpace24 = false; + p.cpu.speed = SAEC_Config_CPU_Speed_Maximum; + p.chipset.blitter.immediate = true; + p.audio.mode = SAEC_Config_Audio_Mode_On; + p.floppy.drive[0].type = SAEC_Config_Floppy_Type_35_HD; + p.floppy.drive[1].type = SAEC_Config_Floppy_Type_35_HD; + p.floppy.speed = 0; + //p.cpu_idle = 150; + //p.picasso96_nocustom = 1; + p.chipset.compatible = SAEC_Config_Chipset_Compatible_Generic; + built_in_chipset_prefs(p); + p.chipset.ide = -1; + p.chipset.cia.tod = p.chipset.ntsc ? SAEC_Config_Chipset_CIA_TOD_60Hz : SAEC_Config_Chipset_CIA_TOD_50Hz; + //_tcscat(p.flashfile, "battclock.nvr"; + return 1; //configure_rom (p, roms, romcheck); + } + function bip_arcadia(p, config, compa, romcheck) { + int roms[4], i; + struct romlist **rl; + p.memory.bogoSize = 0; + p.chipset.mask = 0; + p.chipset.rtc.type = SAEC_Config_RTC_Type_None; + p.nr_floppies = 0; + p.floppy.drive[0].type = SAEC_Config_Floppy_Type_None; + p.floppy.drive[1].type = SAEC_Config_Floppy_Type_None; + set_68000_compa (p, compa); + p.chipset.compatible = SAEC_Config_Chipset_Compatible_A500; + built_in_chipset_prefs(p); + fetch_datapath (p.flashfile, sizeof (p.flashfile) / sizeof (TCHAR)); + _tcscat (p.flashfile, "arcadia.nvr"; + roms[0] = 5; + roms[1] = 4; + roms[2] = -1; + if (!configure_rom (p, roms, romcheck)) + return 0; + roms[0] = 51; + roms[1] = 49; + roms[2] = -1; + if (!configure_rom (p, roms, romcheck)) + return 0; + rl = getarcadiaroms (); + for (i = 0; rl[i]; i++) { + if (config-- == 0) { + roms[0] = rl[i]->rd->id; + roms[1] = -1; + configure_rom (p, roms, 0); + break; + } + } + xfree (rl); + return 1; + }*/ + + function built_in_prefs(p, model, config, compa, romcheck) { + var v = 0; + + buildin_default_prefs(p); + switch (model) { + case SAEC_Model_A500: v = bip_a500(p, config, compa, romcheck); break; + case SAEC_Model_A500P: v = bip_a500p(p, config, compa, romcheck); break; + case SAEC_Model_A600: v = bip_a600(p, config, compa, romcheck); break; + case SAEC_Model_A1000: v = bip_a1000(p, config, compa, romcheck); break; + case SAEC_Model_A1200: v = bip_a1200(p, config, compa, romcheck); break; + case SAEC_Model_A2000: v = bip_a2000(p, config, compa, romcheck); break; //OWN + case SAEC_Model_A3000: v = bip_a3000(p, config, compa, romcheck); break; + case SAEC_Model_A4000: v = bip_a4000(p, config, compa, romcheck); break; + case SAEC_Model_A4000T: v = bip_a4000t(p, config, compa, romcheck); break; + case SAEC_Model_CD32: v = bip_cd32(p, config, compa, romcheck); break; + case SAEC_Model_CDTV: v = bip_cdtv(p, config, compa, romcheck); break; + /*case 10: v = bip_arcadia(p, config , compa, romcheck); break; + case 11: v = bip_super(p, config, compa, romcheck); break;*/ + } + //if ((p.cpu.model >= SAEC_Config_CPU_Model_68020 || !p.cpu_cycle_exact || !p.cpu_memory_cycle_exact) && !p.chipset.blitter.immediate) + if (p.cpu.model >= SAEC_Config_CPU_Model_68020 && !p.chipset.blitter.immediate) + p.chipset.blitter.waiting = 1; + + if (p.audio.filterType == SAEC_Config_Audio_FilterType_A500 && (p.chipset.mask & SAEC_Config_Chipset_Mask_AGA)) + p.audio.filterType = SAEC_Config_Audio_FilterType_A1200; + else if (p.audio.filterType == SAEC_Config_Audio_FilterType_A1200 && !(p.chipset.mask & SAEC_Config_Chipset_Mask_AGA)) + p.audio.filterType = SAEC_Config_Audio_FilterType_A500; + + //if (p.cpu.model >= SAEC_Config_CPU_Model_68040) p.cs_bytecustomwritebug = true; + return v; + } + + /*-----------------------------------------------------------------------*/ + /*-----------------------------------------------------------------------*/ + /*-----------------------------------------------------------------------*/ + + function fixup_prefs_dim2(wh) { + if (wh.special) + return; + if (wh.width < SAEC_Video_MIN_UAE_WIDTH) { + SAEF_warn("config.fixup_prefs_dim2() Width (%d) min is %d.", wh.width, SAEC_Video_MIN_UAE_WIDTH); + wh.width = SAEC_Video_MIN_UAE_WIDTH; + } + if (wh.height < SAEC_Video_MIN_UAE_HEIGHT) { + SAEF_warn("config.fixup_prefs_dim2() Height (%d) min is %d.", wh.height, SAEC_Video_MIN_UAE_HEIGHT); + wh.height = SAEC_Video_MIN_UAE_HEIGHT; + } + if (wh.width > SAEC_Video_MAX_UAE_WIDTH) { + SAEF_warn("config.fixup_prefs_dim2() Width (%d) max is %d.", wh.width, SAEC_Video_MAX_UAE_WIDTH); + wh.width = SAEC_Video_MAX_UAE_WIDTH; + } + if (wh.height > SAEC_Video_MAX_UAE_HEIGHT) { + SAEF_warn("config.fixup_prefs_dim2() Height (%d) max is %d.", wh.height, SAEC_Video_MAX_UAE_HEIGHT); + wh.height = SAEC_Video_MAX_UAE_HEIGHT; + } + } + + function fixup_prefs_dimensions(p) { + fixup_prefs_dim2(p.video.size_win); + fixup_prefs_dim2(p.video.size_fs); + + if (p.video.apmode[1].gfx_vsync) + p.video.apmode[1].gfx_vsyncmode = 1; + + for (var i = 0; i < 2; i++) { + var ap = p.video.apmode[i]; + ap.gfx_vflip = 0; + ap.gfx_strobo = false; + if (ap.gfx_vsync) { + if (ap.gfx_vsyncmode) { + // low latency vsync: no flip only if no-buffer + if (ap.gfx_backbuffers >= 1) + ap.gfx_vflip = 1; + if (!i && ap.gfx_backbuffers == 2) + ap.gfx_vflip = 1; + ap.gfx_strobo = p.lightboost_strobo; + } else { + // legacy vsync: always wait for flip + ap.gfx_vflip = -1; + if (p.video.api == SAEC_Config_Video_API_WebGL && ap.gfx_backbuffers < 1) + ap.gfx_backbuffers = 1; + if (ap.gfx_vflip) + ap.gfx_strobo = p.lightboost_strobo; + } + } else { + // no vsync: wait if triple bufferirng + if (ap.gfx_backbuffers >= 2) + ap.gfx_vflip = -1; + } + + /*var f = p.video.gf[i]; + if (f.gfx_filter == 0 && ((f.gfx_filter_autoscale && p.video.api == SAEC_Config_Video_API_Canvas) || (p.video.apmode[0].gfx_vsyncmode))) { + SAEF_warn("config.fixup_prefs_dimensions() Current settings require at least null filter enabled. Enabling filter..."); + f.gfx_filter = 1; + }*/ + /*if (i == 0) { + if (f.gfx_filter == 0 && p.monitoremu) { + SAEF_warn("config.fixup_prefs_dimensions() Display port adapter emulation require at least null filter enabled. Enabling filter..."); + f.gfx_filter = 1; + } + if (f.gfx_filter == 0 && p.cs_cd32fmv) { + SAEF_warn("config.fixup_prefs_dimensions() CD32 MPEG module overlay support require at least null filter enabled. Enabling filter..."); + f.gfx_filter = 1; + } + if (f.gfx_filter == 0 && (p.chipset.genlock && p.genlock_image)) { + SAEF_warn("config.fixup_prefs_dimensions() Genlock emulation require at least null filter enabled. Enabling filter..."); + f.gfx_filter = 1; + } + }*/ + } + } + this.fixup_prefs_dimensions_ext = function(p) { + fixup_prefs_dimensions(p); + } + + function fixup_cpu(p) { + switch (p.cpu.model) { //OWN + case SAEC_Config_CPU_Model_68000: + case SAEC_Config_CPU_Model_68010: + p.cpu.clock.multiplier = 2 << 8; + break; + case SAEC_Config_CPU_Model_68020: + p.cpu.clock.multiplier = 4 << 8; + break; + case SAEC_Config_CPU_Model_68030: + p.cpu.clock.multiplier = 8 << 8; + //p.cpu.clock.multiplier = 0; + //p.cpu.clock.frequency = 25000000; + break; + } + + if (p.cpu.clock.frequency == 1000000) + p.cpu.clock.frequency = 0; + + /*if (p.cpu.model >= SAEC_Config_CPU_Model_68040 && p.cpu.addressSpace24) { + SAEF_error("24-bit address space is not supported with 68040/060 configurations."); + p.cpu.addressSpace24 = false; + } + if (p.cpu.model < SAEC_Config_CPU_Model_68020 && p.fpu_model && (p.cpu.compatible || p.cpu_memory_cycle_exact)) { + SAEF_error("FPU is not supported with 68000/010 configurations."); + p.fpu_model = 0; + } + switch (p.cpu.model) { + case SAEC_Config_CPU_Model_68000: + case SAEC_Config_CPU_Model_68010: + case SAEC_Config_CPU_Model_68020: + case SAEC_Config_CPU_Model_68030: + break; + case SAEC_Config_CPU_Model_68040: + if (p.fpu_model) + p.fpu_model = 68040; + break; + case SAEC_Config_CPU_Model_68060: + if (p.fpu_model) + p.fpu_model = 68060; + break; + } + + if ((p.cpu.model < SAEC_Config_CPU_Model_68030 || p.cachesize) && p.mmu_model) { + SAEF_warn("config.fixup_cpu() MMU emulation requires 68030/040/060 and it is not JIT compatible."); + p.mmu_model = 0; + } + + if (!p.cpu_memory_cycle_exact && p.cpu_cycle_exact) + p.cpu_memory_cycle_exact = true; + #if 0 + if (p.cpu_cycle_exact && p.cpu.speed < 0 && currprefs.cpu.model <= SAEC_Config_CPU_Model_68020) + p.cpu.speed = SAEC_Config_CPU_Speed_Original; + #endif + #if 0 + if (p.chipset.blitter.immediate && p.chipset.blitter.cycle_exact) { + SAEF_error("Cycle-exact and immediate blitter can't be enabled simultaneously."); + p.chipset.blitter.immediate = false; + } + #endif*/ + if (p.chipset.blitter.immediate && p.chipset.blitter.waiting) { + SAEF_warn("config.fixup_cpu() Immediate blitter and waiting blits can't be enabled simultaneously. Disabling waiting blits..."); + p.chipset.blitter.waiting = 0; + } + /*if (p.cpu_memory_cycle_exact) + p.cpu.compatible = true; + + if (p.cpu_memory_cycle_exact && p.audio.mode == SAEC_Config_Audio_Mode_Off) { + p.audio.mode = SAEC_Config_Audio_Mode_Off_Emul; + SAEF_error("Cycle-exact mode requires at least Disabled but emulated sound setting."); + }*/ + } + + function fixup_prefs(p) { + //var max_z3fastmem = SAEC_info.memory.maxSize; + //var err = 0; + + built_in_chipset_prefs(p); + fixup_cpu(p); + + if (((p.memory.chipSize & (p.memory.chipSize - 1)) != 0 && p.memory.chipSize != 0x180000) + || p.memory.chipSize < 0x20000 + || p.memory.chipSize > 0x800000) + { + SAEF_warn("config.fixup_prefs() Unsupported chipmem size %d (0x%x). Setting to 2M...", p.memory.chipSize, p.memory.chipSize); + p.memory.chipSize = 0x200000; + //err = 1; + } + + if ((p.memory.z2FastSize & (p.memory.z2FastSize - 1)) != 0 || (p.memory.z2FastSize != 0 && (p.memory.z2FastSize < 0x10000 || p.memory.z2FastSize > 0x800000))) { + SAEF_warn("config.fixup_prefs() Unsupported Zorro II fastmem size %d (0x%x). Disabling fastmem...", p.memory.z2FastSize, p.memory.z2FastSize); + p.memory.z2FastSize = 0; + //err = 1; + } + /*if ((p.fastmem2_size & (p.fastmem2_size - 1)) != 0 || (p.fastmem2_size != 0 && (p.fastmem2_size < 0x10000 || p.fastmem2_size > 0x800000))) { + SAEF_error("Unsupported fastmem2 size %d (0x%x).", p.fastmem2_size, p.fastmem2_size); + p.fastmem2_size = 0; + err = 1; + }*/ + + /*if (p.rtgmem_size > max_z3fastmem && p.rtgmem_type == GFXBOARD_UAE_Z3) { + SAEF_error("Graphics card memory size %d (0x%x) larger than maximum reserved %d (0x%x).", p.rtgmem_size, p.rtgmem_size, max_z3fastmem, max_z3fastmem); + p.rtgmem_size = max_z3fastmem; + err = 1; + } + if ((p.rtgmem_size & (p.rtgmem_size - 1)) != 0 || (p.rtgmem_size != 0 && (p.rtgmem_size < 0x100000))) { + SAEF_error("Unsupported graphics card memory size %d (0x%x).", p.rtgmem_size, p.rtgmem_size); + if (p.rtgmem_size > max_z3fastmem) + p.rtgmem_size = max_z3fastmem; + else + p.rtgmem_size = 0; + err = 1; + }*/ + + /*if (p.memory.z3FastSize > max_z3fastmem) { + SAEF_error("Zorro III fastmem size %d (0x%x) larger than max reserved %d (0x%x).", p.memory.z3FastSize, p.memory.z3FastSize, max_z3fastmem, max_z3fastmem); + p.memory.z3FastSize = max_z3fastmem; + err = 1; + }*/ + if ((p.memory.z3FastSize & (p.memory.z3FastSize - 1)) != 0 || (p.memory.z3FastSize != 0 && p.memory.z3FastSize < 0x100000)) { + SAEF_warn("config.fixup_prefs() Unsupported Zorro III fastmem size %d (0x%x). Disabling fastmem...", p.memory.z3FastSize, p.memory.z3FastSize); + p.memory.z3FastSize = 0; + //err = 1; + } + /*if (p.z3fastmem2_size > max_z3fastmem) { + SAEF_error("Zorro III fastmem2 size %d (0x%x) larger than max reserved %d (0x%x).", p.z3fastmem2_size, p.z3fastmem2_size, max_z3fastmem, max_z3fastmem); + p.z3fastmem2_size = max_z3fastmem; + err = 1; + } + if ((p.z3fastmem2_size & (p.z3fastmem2_size - 1)) != 0 || (p.z3fastmem2_size != 0 && p.z3fastmem2_size < 0x100000)) { + SAEF_error("Unsupported Zorro III fastmem2 size %x (%x).", p.z3fastmem2_size, p.z3fastmem2_size); + p.z3fastmem2_size = 0; + err = 1; + }*/ + p.memory.z3AutoConfigStart = (p.memory.z3AutoConfigStart & 0xffff0000) >>> 0; + if (p.memory.z3AutoConfigStart < 0x1000000) + p.memory.z3AutoConfigStart = 0x1000000; + + /*if (p.z3chipmem_size > max_z3fastmem) { + SAEF_error("Zorro III fake chipmem size %d (0x%x) larger than max reserved %d (0x%x).", p.z3chipmem_size, p.z3chipmem_size, max_z3fastmem, max_z3fastmem); + p.z3chipmem_size = max_z3fastmem; + err = 1; + } + if (((p.z3chipmem_size & (p.z3chipmem_size - 1)) != 0 && p.z3chipmem_size != 0x18000000 && p.z3chipmem_size != 0x30000000) || (p.z3chipmem_size != 0 && p.z3chipmem_size < 0x100000)) { + SAEF_error("Unsupported 32-bit chipmem size %d (0x%x).", p.z3chipmem_size, p.z3chipmem_size); + p.z3chipmem_size = 0; + err = 1; + }*/ + //if (p.cpu.addressSpace24 && (p.memory.z3FastSize != 0 || p.z3fastmem2_size != 0 || p.z3chipmem_size != 0)) { + if (p.cpu.addressSpace24 && (p.memory.z3FastSize != 0)) { + //p.memory.z3FastSize = p.z3fastmem2_size = p.z3chipmem_size = 0; + p.memory.z3FastSize = 0; + //SAEF_error("Can't use a Z3 graphics card or 32-bit memory when using a 24 bit address space."); + SAEF_warn("config.fixup_prefs() Can't use Zorro III memory when using a 24 bit address space. Disabling memory..."); + } + + if (p.memory.bogoSize != 0 && p.memory.bogoSize != 0x80000 && p.memory.bogoSize != 0x100000 && p.memory.bogoSize != 0x180000 && p.memory.bogoSize != 0x1c0000) { + SAEF_warn("config.fixup_prefs() Unsupported bogomem size %d (0x%x). Disabling bogomem...", p.memory.bogoSize, p.memory.bogoSize); + p.memory.bogoSize = 0; + //err = 1; + } + if (p.memory.bogoSize > 0x180000 && (p.chipset.fatGaryRev >= 0 || p.chipset.ide || p.chipset.ramseyRev >= 0)) { + p.memory.bogoSize = 0x180000; + SAEF_warn("config.fixup_prefs() Possible Gayle bogomem conflict fixed."); + } + if (p.memory.chipSize > 0x200000 && p.memory.z2FastSize > 262144) { + SAEF_warn("config.fixup_prefs() Can't use Zorro II fastmem and more than 2M chipmem at the same time. Limiting chipmem to 2M..."); + p.memory.chipSize = 0x200000; + //err = 1; + } + /*if (p.memory.chipSize > 0x200000 && p.rtgmem_size && gfxboard_get_configtype(p.rtgmem_type) == 2) { + SAEF_error("You can't use Zorro II RTG and more than 2MB chip at the same time."); + p.memory.chipSize = 0x200000; + err = 1; + } + if (p.mem25bit_size > 128 << 20 || (p.mem25bit_size & 0xfffff)) { + p.mem25bit_size = 0; + SAEF_error("Unsupported 25bit RAM size"); + }*/ + if (p.memory.ramsey.lowSize > 64 << 20 || (p.memory.ramsey.lowSize & 0xfffff)) { + p.memory.ramsey.lowSize = 0; + SAEF_warn("config.fixup_prefs() Unsupported Mainboard fastmem size. Disabling fastmem... (RAMSEY low)"); + } + if (p.memory.ramsey.highSize > 128 << 20 || (p.memory.ramsey.highSize & 0xfffff)) { + p.memory.ramsey.highSize = 0; + SAEF_warn("config.fixup_prefs() Unsupported CPU-Board fastmem size. Disabling fastmem... (RAMSEY high)"); + } + + /*if (p.rtgmem_type >= GFXBOARD_HARDWARE) { + if (gfxboard_get_vram_min(p.rtgmem_type) > 0 && p.rtgmem_size < gfxboard_get_vram_min (p.rtgmem_type)) { + SAEF_error("Graphics card memory size %d (0x%x) smaller than minimum hardware supported %d (0x%x).", + p.rtgmem_size, p.rtgmem_size, gfxboard_get_vram_min(p.rtgmem_type), gfxboard_get_vram_min(p.rtgmem_type)); + p.rtgmem_size = gfxboard_get_vram_min (p.rtgmem_type); + } + if (p.cpu.addressSpace24 && gfxboard_get_configtype(p.rtgmem_type) == 3) { + p.rtgmem_type = GFXBOARD_UAE_Z2; + p.rtgmem_size = 0; + SAEF_error("Z3 RTG and 24-bit address space are not compatible.")); + } + if (gfxboard_get_vram_max(p.rtgmem_type) > 0 && p.rtgmem_size > gfxboard_get_vram_max(p.rtgmem_type)) { + SAEF_error("Graphics card memory size %d (0x%x) larger than maximum hardware supported %d (0x%x).", + p.rtgmem_size, p.rtgmem_size, gfxboard_get_vram_max(p.rtgmem_type), gfxboard_get_vram_max(p.rtgmem_type)); + p.rtgmem_size = gfxboard_get_vram_max(p.rtgmem_type); + } + } + if (p.cpu.addressSpace24 && p.rtgmem_size && p.rtgmem_type == GFXBOARD_UAE_Z3) { + SAEF_error("Z3 RTG and 24bit address space are not compatible."); + p.rtgmem_type = GFXBOARD_UAE_Z2; + } + if (p.rtgmem_type == GFXBOARD_UAE_Z2 && (p.memory.chipSize > 2 * 1024 * 1024 || getz2size (p) > 8 * 1024 * 1024 || getz2size (p) < 0)) { + p.rtgmem_size = 0; + SAEF_error("Too large Z2 RTG memory size."); + }*/ + + + + /*#if 0 + if (p.cpu.speed < -1 || p.cpu.speed > 20) { + SAEF_error("Bad value for -w parameter: must be -1, 0, or within 1..20.\n"); + p.cpu.speed = 4; + err = 1; + } + #endif*/ + + if (p.audio.mode < SAEC_Config_Audio_Mode_Off || p.audio.mode > SAEC_Config_Audio_Mode_On_Best) { + SAEF_warn("config.fixup_prefs() Bad 'config.audio.mode'. Disabling audio..."); + p.audio.mode = SAEC_Config_Audio_Mode_Off; + //err = 1; + } + + if (p.chipset.z3AutoConfig && p.cpu.addressSpace24) { + p.chipset.z3AutoConfig = false; + SAEF_warn("config.fixup_prefs() Zorro III autoconfig and 24bit address space are not compatible. Disabling Zorro III autoconfig..."); + } + //if ((p.memory.z3FastSize || p.z3fastmem2_size || p.z3chipmem_size) && p.cpu.addressSpace24) { + if ((p.memory.z3FastSize) && p.cpu.addressSpace24) { + SAEF_warn("config.fixup_prefs() Zorro III memory can't be used if address space is 24-bit., Disabling Zorro III memory..."); + p.memory.z3FastSize = 0; + //p.z3fastmem2_size = 0; + //p.z3chipmem_size = 0; + //err = 1; + } + /*if ((p.rtgmem_size > 0 && p.rtgmem_type == GFXBOARD_UAE_Z3) && p.cpu.addressSpace24) { + SAEF_error("UAEGFX RTG can't be used if address space is 24-bit."); + p.rtgmem_size = 0; + err = 1; + }*/ + + /*if (p.nr_floppies < 0 || p.nr_floppies > 4) { + SAEF_error("Invalid number of floppies. Using 2."); + p.nr_floppies = 2; + p.floppy.drive[0].type = SAEC_Config_Floppy_Type_35_DD; + p.floppy.drive[1].type = SAEC_Config_Floppy_Type_35_DD; + p.floppy.drive[2].type = SAEC_Config_Floppy_Type_None; + p.floppy.drive[3].type = SAEC_Config_Floppy_Type_None; + err = 1; + }*/ + if (p.floppy.speed > 0 && p.floppy.speed < 10) { + SAEF_warn("config.fixup_prefs() Invalid floppy speed. Setting to 'Turbo' (100)..."); + p.floppy.speed = 100; + } + + /*if (p.input_mouse_speed < 1 || p.input_mouse_speed > 1000) { + SAEF_error("Invalid mouse speed."); + p.input_mouse_speed = 100; + }*/ + if (p.chipset.colLevel < SAEC_Config_Chipset_ColLevel_None || p.chipset.colLevel > SAEC_Config_Chipset_ColLevel_Full) { + SAEF_warn("config.fixup_prefs() Invalid collision support level. Using Sprite-Sprite..."); + p.chipset.colLevel = SAEC_Config_Chipset_ColLevel_Sprite_Sprite; + //err = 1; + } + //if (p.parallel_postscript_emulation) p.parallel_postscript_detection = 1; + if (p.chipset.compatible == SAEC_Config_Chipset_Compatible_Generic) { + p.chipset.fatGaryRev = p.chipset.ramseyRev = -1; + p.chipset.ide = 0; + p.chipset.mbdmac = -1; + if (p.cpu.model >= SAEC_Config_CPU_Model_68020) { + p.chipset.fatGaryRev = 0; + p.chipset.ramseyRev = 0x0f; + p.chipset.ide = -1; + p.chipset.mbdmac = 0; + } + } else if (p.chipset.compatible == SAEC_Config_Chipset_Compatible_Manual) { + if (p.chipset.ide == SAEC_Config_Chipset_IDE_A4000) { + if (p.chipset.fatGaryRev < 0) + p.chipset.fatGaryRev = 0; + if (p.chipset.ramseyRev < 0) + p.chipset.ramseyRev = 0x0f; + } + } + if (p.memory.chipSize >= 0x100000) + p.chipset.jumper1MbChip = true; + + /* Can"t fit genlock and A2024 or Graffiti at the same time, + * also Graffiti uses genlock audio bit as an enable signal + */ + /*if (p.chipset.genlock && p.monitoremu) { + SAEF_error("Genlock and A2024 or Graffiti can't be active simultaneously."); + p.chipset.genlock = false; + } + if (p.cs_hacks) { + SAEF_error("chipset_hacks is nonzero (0x%04x).", p.cs_hacks); + }*/ + + fixup_prefs_dimensions(p); + + //OWN + if (cfg.video.api == SAEC_Config_Video_API_Canvas && cfg.video.colorMode != 5) { + cfg.video.colorMode = 5; + SAEF_warn("config.fixup_prefs() cfg.video.colorMode must 5 if 'Canvas' is used. (set to 5)"); + } + //OWN + if (cfg.video.luminance < -1000 || cfg.video.luminance > 1000) { + cfg.video.luminance = 0; + SAEF_warn("config.fixup_prefs() cfg.video.luminance must be between -1000 and 1000. (reset to 0)"); + } + if (cfg.video.contrast < -1000 || cfg.video.contrast > 1000) { + cfg.video.contrast = 0; + SAEF_warn("config.fixup_prefs() cfg.video.contrast must be between -1000 and 1000. (reset to 0)"); + } + if (cfg.video.gamma < -1000 || cfg.video.gamma > 1000) { + cfg.video.gamma = 0; + SAEF_warn("config.fixup_prefs() cfg.video.gamma must be between -1000 and 1000. (reset to 0)"); + } + if (cfg.video.alpha < 0 || cfg.video.alpha > 255) { + cfg.video.alpha = 255; + SAEF_warn("config.fixup_prefs() cfg.video.gamma must be between 0 and 255. (reset to 255)"); + } + + /*#if !defined (CPUEMU_13) + p.cpu_cycle_exact = p.chipset.blitter.cycle_exact = false; + #endif*/ + + /*#ifndef AUTOCONFIG + p.memory.z2FastSize = 0; + p.memory.z3FastSize = 0; + p.rtgmem_size = 0; + #endif*/ + + /*if (p.cpu_cycle_exact) { + if (p.video.framerate > 1) { + SAEF_error("Cycle-exact requires disabled frameskip."); + p.video.framerate = 1; + } + }*/ + + /*if (p.memory.maprom && !p.cpu.addressSpace24) + p.memory.maprom = 0x0f000000; + if (((p.memory.maprom & 0xff000000) && p.cpu.addressSpace24) || (p.memory.maprom && p.memory.ramsey.highSize >= 0x08000000)) + p.memory.maprom = 0x00e00000;*/ + + if (p.chipset.cia.todHack && p.chipset.cia.tod == SAEC_Config_Chipset_CIA_TOD_VSync) + p.chipset.cia.tod = p.chipset.ntsc ? SAEC_Config_Chipset_CIA_TOD_60Hz : SAEC_Config_Chipset_CIA_TOD_50Hz; + + built_in_chipset_prefs(p); + //inputdevice_fix_prefs(p); + return true; //err == 0; + } +} diff --git a/sae/constants.js b/sae/constants.js deleted file mode 100644 index aa5aaa2..0000000 --- a/sae/constants.js +++ /dev/null @@ -1,366 +0,0 @@ -/************************************************************************** -* SAE - Scripted Amiga Emulator -* -* 2012-2015 Rupert Hausberger -* -* https://github.com/naTmeg/ScriptedAmigaEmulator -* -**************************************************************************/ - -const SAEV_Version = 0; -const SAEV_Revision = 8; -const SAEV_Revision_Sub = 2; - -/*-----------------------------------------------------------------------*/ -/* info */ - -const SAEI_Audio_WebAudio = 1; - -const SAEI_Video_Canvas2D = 1; -const SAEI_Video_WebGL = 2; - -/*-----------------------------------------------------------------------*/ -/* cpu */ - -const SAEV_Config_CPU_Speed_Maximum = -1; -const SAEV_Config_CPU_Speed_Original = 0; - -/*-----------------------------------------------------------------------*/ -/* chipset */ - -const SAEV_Config_Chipset_Type_OCS = 1; -const SAEV_Config_Chipset_Type_ECS_AGNUS = 2; -const SAEV_Config_Chipset_Type_ECS_DENISE = 3; - -const SAEV_Config_Chipset_Mask_OCS = 0; -const SAEV_Config_Chipset_Mask_ECS_AGNUS = 1; -const SAEV_Config_Chipset_Mask_ECS_DENISE = 1 | 2; - - -const SAEV_Config_Chipset_ColLevel_None = 0; -const SAEV_Config_Chipset_ColLevel_Sprite_Sprite = 1; -const SAEV_Config_Chipset_ColLevel_Sprite_Playfield = 2; -const SAEV_Config_Chipset_ColLevel_Full = 3; - -/*-----------------------------------------------------------------------*/ -/* ram */ - -const SAEV_Config_RAM_Chip_Size_256K = 1; -const SAEV_Config_RAM_Chip_Size_512K = 2; -const SAEV_Config_RAM_Chip_Size_1M = 3; -const SAEV_Config_RAM_Chip_Size_2M = 4; - -const SAEV_Config_RAM_Slow_Size_None = 0; -const SAEV_Config_RAM_Slow_Size_256K = 1; -const SAEV_Config_RAM_Slow_Size_512K = 2; -const SAEV_Config_RAM_Slow_Size_1M = 3; -const SAEV_Config_RAM_Slow_Size_1536K = 4; - -const SAEV_Config_RAM_Fast_Size_None = 0; -const SAEV_Config_RAM_Fast_Size_512K = 1; -const SAEV_Config_RAM_Fast_Size_1M = 2; -const SAEV_Config_RAM_Fast_Size_2M = 3; -const SAEV_Config_RAM_Fast_Size_4M = 4; -const SAEV_Config_RAM_Fast_Size_8M = 5; - -/*-----------------------------------------------------------------------*/ -/* rom, ext */ - -const SAEV_Config_ROM_Size_None = 0; -const SAEV_Config_ROM_Size_256K = 1; -const SAEV_Config_ROM_Size_512K = 2; - -const SAEV_Config_EXT_Size_None = 0; -const SAEV_Config_EXT_Size_256K = 1; -const SAEV_Config_EXT_Size_512K = 2; - -//const SAEV_Config_EXT_Addr_A0 = 1; -const SAEV_Config_EXT_Addr_E0 = 2; -const SAEV_Config_EXT_Addr_F0 = 3; - -/*-----------------------------------------------------------------------*/ -/* disk */ - -const SAEV_Config_Floppy_Type_None = 0; -const SAEV_Config_Floppy_Type_35_DD = 1; -const SAEV_Config_Floppy_Type_35_HD = 2; -const SAEV_Config_Floppy_Type_525_SD = 3; - -const SAEV_Config_Floppy_Speed_Turbo = 0; -const SAEV_Config_Floppy_Speed_Original = 100; - -/*-----------------------------------------------------------------------*/ -/* audio */ - -const SAEV_Config_Audio_Mode_Emul = 0; -const SAEV_Config_Audio_Mode_Play = 1; -const SAEV_Config_Audio_Mode_Play_Best = 2; - -const SAEV_Config_Audio_Channels_Mono = 1; -const SAEV_Config_Audio_Channels_Stereo = 2; - -/*-----------------------------------------------------------------------*/ -/* input */ - -const SAEV_Config_Ports_Type_None = 0; -const SAEV_Config_Ports_Type_Mouse = 1; -const SAEV_Config_Ports_Type_Joy0 = 2; -const SAEV_Config_Ports_Type_Joy1 = 3; - -const SAEV_Config_Ports_Move_None = 0; -const SAEV_Config_Ports_Move_Arrows = 1; -const SAEV_Config_Ports_Move_Numpad = 2; -const SAEV_Config_Ports_Move_WASD = 3; - -const SAEV_Config_Ports_Fire_None = 0; - -/*-----------------------------------------------------------------------*/ -/* rtc */ - -const SAEV_Config_RTC_Type_None = 0; -const SAEV_Config_RTC_Type_MSM6242B = 1; -const SAEV_Config_RTC_Type_RF5C01A = 2; - -/*-----------------------------------------------------------------------*/ -/* erros */ - -//const SAEE_None = 0; - -const SAEE_CPU_Internal = 1; -const SAEE_CPU_68020_Required = 2; - -const SAEE_Disk_File_Too_Big = 3; - -const SAEE_Video_Shader_Error = 4; -const SAEE_Video_ID_Not_Found = 5; -const SAEE_Video_Canvas_Not_Supported = 6; -//const SAEE_Video_WebGL_Not_Avail = 7; - -const SAEE_Audio_WebAudio_Not_Avail = 8; - -/*-----------------------------------------------------------------------*/ -/* methods */ - -/*const SAEM_Init = 1; -const SAEM_Start = 2; -const SAEM_Stop = 3; -const SAEM_Pause = 4; -const SAEM_Reset = 5; -const SAEM_Insert = 6; -const SAEM_Eject = 7;*/ - -/*-----------------------------------------------------------------------*/ -/*-----------------------------------------------------------------------*/ -/* amiga */ - -const ST_STOP = 0; -const ST_CYCLE = 1; -const ST_PAUSE = 2; -const ST_IDLE = 3; - -/*-----------------------------------------------------------------------*/ -/* events */ - -const EV_CIA = 0; -const EV_AUDIO = 1; -const EV_MISC = 2; -const EV_HSYNC = 3; -const EV_MAX = 4; - -const EV2_BLITTER = 0; -const EV2_DISK = 1; -const EV2_DMAL = 2; -const EV2_MISC = 3; -const EV2_MAX = 3 + 10; - -const CYCLE_UNIT = 512; -const CYCLE_UNIT_INV = 1.0 / CYCLE_UNIT; /* mul is always faster than div */ - -const CYCLE_MAX = 0xffffffff * CYCLE_UNIT; - -/*-----------------------------------------------------------------------*/ -/* cpu */ - -const SPCFLAG_STOP = 2; -const SPCFLAG_COPPER = 4; -const SPCFLAG_INT = 8; -//const SPCFLAG_BRK = 16; -const SPCFLAG_TRACE = 64; -const SPCFLAG_DOTRACE = 128; -const SPCFLAG_DOINT = 256; -const SPCFLAG_BLTNASTY = 512; -const SPCFLAG_TRAP = 1024; - -/*-----------------------------------------------------------------------*/ -/* amiga */ - -const INTF_TBE = 1 << 0; -const INTF_DSKBLK = 1 << 1; -const INTF_PORTS = 1 << 3; -const INTF_COPER = 1 << 4; -const INTF_VERTB = 1 << 5; -const INTF_BLIT = 1 << 6; -const INTF_AUD0 = 1 << 7; -const INTF_AUD1 = 1 << 8; -const INTF_AUD2 = 1 << 9; -const INTF_AUD3 = 1 << 10; -const INTF_RBF = 1 << 11; -const INTF_DSKSYN = 1 << 12; -const INTF_EXTER = 1 << 13; -const INTF_INTEN = 1 << 14; -const INTF_SETCLR = 1 << 15; - -const INT_DSKBLK = INTF_SETCLR | INTF_DSKBLK; -const INT_VERTB = INTF_SETCLR | INTF_VERTB; -const INT_BLIT = INTF_SETCLR | INTF_BLIT; -const INT_DSKSYN = INTF_SETCLR | INTF_DSKSYN; - -const DMAF_AUD0EN = 1 << 0; -const DMAF_AUD1EN = 1 << 1; -const DMAF_AUD2EN = 1 << 2; -const DMAF_AUD3EN = 1 << 3; -const DMAF_DSKEN = 1 << 4; -const DMAF_SPREN = 1 << 5; -const DMAF_BLTEN = 1 << 6; -const DMAF_COPEN = 1 << 7; -const DMAF_BPLEN = 1 << 8; -const DMAF_DMAEN = 1 << 9; -const DMAF_BLTPRI = 1 << 10; -const DMAF_BZERO = 1 << 13; -const DMAF_BBUSY = 1 << 14; -const DMAF_SETCLR = 1 << 15; - -/*-----------------------------------------------------------------------*/ -/* blitter */ - -const BLT_done = 0; -const BLT_init = 1; -const BLT_read = 2; -const BLT_work = 3; -const BLT_write = 4; -const BLT_next = 5; - -/*-----------------------------------------------------------------------*/ -/* video */ - -const VIDEO_WIDTH = 720; /* == 360*2 */ -const VIDEO_HEIGHT = 568; /* == 284*2 */ -const VIDEO_DEPTH = 32; - -/*-----------------------------------------------------------------------*/ -/* audio */ - -const PERIOD_MIN = 4; -const PERIOD_MIN_NONCE = 60; -const PERIOD_MAX = 0xffffffff * CYCLE_UNIT; - -/*-----------------------------------------------------------------------*/ -/* playfield, sprites */ - -const CUSTOM_SIMPLE = 0; -const SMART_UPDATE = 0; - -const MAXHPOS = 227; -const MAXHPOS_PAL = 227; -const MAXHPOS_NTSC = 227; -const MAXVPOS = 312; -const MAXVPOS_PAL = 312; -const MAXVPOS_NTSC = 262; -const VBLANK_ENDLINE_PAL = 26; -const VBLANK_ENDLINE_NTSC = 21; -const VBLANK_SPRITE_PAL = 25; -const VBLANK_SPRITE_NTSC = 20; -const VBLANK_HZ_PAL = 50; -const VBLANK_HZ_NTSC = 60; -const EQU_ENDLINE_PAL = 8; -const EQU_ENDLINE_NTSC = 10; - -const CSMASK_ECS_AGNUS = 1; -const CSMASK_ECS_DENISE = 2; -const CSMASK_AGA = 4; -//const CSMASK_MASK = (CSMASK_ECS_AGNUS | CSMASK_ECS_DENISE | CSMASK_AGA); - -const CHIPSET_CLOCK_PAL = 3546895; -const CHIPSET_CLOCK_NTSC = 3579545; - -const RES_LORES = 0; -const RES_HIRES = 1; -const RES_SUPERHIRES = 2; -const RES_MAX = 2; - -const VRES_NONDOUBLE = 0; -const VRES_DOUBLE = 1; -const VRES_QUAD = 2; -const VRES_MAX = 1; - -const DIW_WAITING_START = 0; -const DIW_WAITING_STOP = 1; - -const LINE_UNDECIDED = 1; -const LINE_DECIDED = 2; -const LINE_DECIDED_DOUBLE = 3; -const LINE_AS_PREVIOUS = 4; -const LINE_BLACK = 5; -const LINE_REMEMBERED_AS_BLACK = 6; -const LINE_DONE = 7; -const LINE_DONE_AS_PREVIOUS = 8; -const LINE_REMEMBERED_AS_PREVIOUS = 9; - -const LOF_TOGGLES_NEEDED = 4; -const NLACE_CNT_NEEDED = 50; - -const HARD_DDF_STOP = 0xd4; -const HARD_DDF_START = 0x18; - -const MAX_PLANES = 6; /* 8 = AGA */ - -const AMIGA_WIDTH_MAX = 752 / 2; -//const AMIGA_HEIGHT_MAX = 574 / 2; - -const DIW_DDF_OFFSET = 1; -const HBLANK_OFFSET = 9; -const DISPLAY_LEFT_SHIFT = 0x38; - -const NLN_NORMAL = 0; -const NLN_DOUBLED = 1; -const NLN_UPPER = 2; -const NLN_LOWER = 3; -const NLN_NBLACK = 4; - -const PLF_IDLE = 0; -const PLF_START = 1; -const PLF_ACTIVE = 2; -const PLF_PASSED_STOP = 3; -const PLF_PASSED_STOP2 = 4; -const PLF_END = 5; - -const FETCH_NOT_STARTED = 0; -const FETCH_STARTED = 1; -const FETCH_WAS_PLANE0 = 2; - -const COLOR_TABLE_SIZE = (MAXVPOS + 2) * 2; -const COLOR_CHANGE_BRDBLANK = 0x80000000; - -const BPLCON_DENISE_DELAY = 1; - -//const SPRITE_DEBUG = 0; -//const SPRITE_DEBUG_MINY = 0x0; -//const SPRITE_DEBUG_MAXY = 0x100; -//const AUTOSCALE_SPRITES = 1; -//const SPRBORDER = 0; -const SPR0_HPOS = 0x15; -const MAX_SPRITES = 8; - -const MAX_PIXELS_PER_LINE = 1760; - -const MAX_SPR_PIXELS = (((MAXVPOS + 1) * 2 + 1) * MAX_PIXELS_PER_LINE); -const MAX_REG_CHANGE = ((MAXVPOS + 1) * 2 * MAXHPOS); - -const MAX_STOP = 30000; -const NO_BLOCK = -3; - -const MAX_WORDS_PER_LINE = 100; - -const DO_SPRITES = 1; -const FAST_COLORS = 0; - diff --git a/sae/copper.js b/sae/copper.js index a4e3e98..9f0bc45 100644 --- a/sae/copper.js +++ b/sae/copper.js @@ -1,197 +1,583 @@ -/************************************************************************** -* SAE - Scripted Amiga Emulator -* -* 2012-2015 Rupert Hausberger -* -* https://github.com/naTmeg/ScriptedAmigaEmulator -* -*************************************************************************** -* Notes: Ported from WinUAE 2.5.0 -* -**************************************************************************/ +/*------------------------------------------------------------------------- +| SAE - Scripted Amiga Emulator +| https://github.com/naTmeg/ScriptedAmigaEmulator +| +| Copyright (C) 2012-2016 Rupert Hausberger +| +| This program is free software; you can redistribute it and/or +| modify it under the terms of the GNU General Public License +| as published by the Free Software Foundation; either version 2 +| of the License, or (at your option) any later version. +| +| This program is distributed in the hope that it will be useful, +| but WITHOUT ANY WARRANTY; without even the implied warranty of +| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +| GNU General Public License for more details. +| +| Note: ported from WinUAE 3.2.x +-------------------------------------------------------------------------*/ +/* global references */ -//copper_states -const COP_stop = 0; -const COP_waitforever = 1; -const COP_read1 = 2; -const COP_read2 = 3; -const COP_bltwait = 4; -const COP_wait_in2 = 5; -const COP_skip_in2 = 6; -const COP_wait1 = 7; -const COP_wait = 8; -const COP_skip1 = 9; -const COP_strobe_delay1 = 10; -const COP_strobe_delay2 = 11; -const COP_strobe_delay1x = 12; -const COP_strobe_delay2x = 13; -const COP_strobe_extra = 14; -const COP_start_delay = 15; +var SAER_Copper_cop_state = null; -function Copper() { +/*---------------------------------*/ +/* global variables */ + +var SAEV_Copper_access = false; +var SAEV_Copper_last_hpos = 0; +var SAEV_Copper_enabled_thisline = 0; + +/*---------------------------------*/ + +function SAEO_Copper() { const customdelay = [ 1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,1,1,1,1,0,0,0,0,0,0,0,0, /* 32 0x00 - 0x3e */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x40 - 0x5e */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x60 - 0x7e */ - 0,0,0,0,1,1,1,1,1,1,1,1,0,0,0,0, /* 0x80 - 0x9e */ + 0,0,0,0,1,1,1,1,1,0,0,0,0,0,0,0, /* 0x80 - 0x9e */ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* 32 0xa0 - 0xde */ /* BPLxPTH/BPLxPTL */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 16 */ /* BPLCON0-3,BPLMOD1-2 */ - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 16 */ + 0,0,0,0,0,0,0,0, /* 8 */ + /* BPLxDAT */ + 0,0,0,0,0,0,0,0, /* 8 */ /* SPRxPTH/SPRxPTL */ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* 16 */ /* SPRxPOS/SPRxCTL/SPRxDATA/SPRxDATB */ - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* COLORxx */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* RESERVED */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 ]; - this.cop1lc = 0; - this.cop2lc = 0; - this.copcon = 0; - this.enabled_thisline = false; - this.access = false; - this.last_copper_hpos = 0; - var cop_state = { - /* The current instruction words. */ - i1:0, i2:0, - saved_i1:0, saved_i2:0, - state:0, state_prev:0, - /* Instruction pointer. */ - ip:0, saved_ip:0, - hpos:0, vpos:0, - ignore_next:0, - vcmp:0, hcmp:0, + const COP_stop = 0; + const COP_waitforever = 1; + const COP_read1 = 2; + const COP_read2 = 3; + const COP_bltwait = 4; + const COP_wait_in2 = 5; + const COP_skip_in2 = 6; + const COP_wait1 = 7; + const COP_wait = 8; + const COP_skip1 = 9; + const COP_strobe_delay1 = 10; + const COP_strobe_delay2 = 11; + const COP_strobe_delay1x = 12; + const COP_strobe_delay2x = 13; + const COP_strobe_extra = 14; /* just to skip current cycle when CPU wrote to COPJMP */ + const COP_start_delay = 15; - strobe:0, /* COPJMP1 / COPJMP2 accessed */ - last_write:0, last_write_hpos:0, - moveaddr:0, movedata:0, movedelay:0 + function copper_state() { + this.i1 = 0; this.saved_i1 = 0; /* The current instruction words. */ + this.i2 = 0; this.saved_i2 = 0; + this.state = COP_stop; + this.state_prev = COP_stop; + this.ip = 0; this.saved_ip = 0; /* Instruction pointer */ + this.hpos = 0; + this.vpos = 0; + this.ignore_next = false; + this.vcmp = 0; + this.hcmp = 0; + this.strobe = 0; /* COPJMP1 / COPJMP2 accessed */ + this.moveaddr = 0; + this.movedata = 0; + this.movedelay = 0; }; - this.reset = function () { - this.copcon = 0; + var cop_state = new copper_state(); + SAER_Copper_cop_state = cop_state; + + var cop1lc = 0, cop2lc = 0, copcon = 0; + + //var last_copper_hpos = 0; -> SAEV_Copper_last_hpos + //var copper_access = false; -> SAEV_Copper_access + //var copper_enabled_thisline = 0; -> SAEV_Copper_enabled_thisline + + /*-----------------------------------------------------------------------*/ + + this.reset = function() { + copcon = 0; cop_state.state = COP_stop; - }; + cop_state.movedelay = 0; + cop_state.strobe = 0; + cop_state.ignore_next = false; + } - this.reset2 = function () { - cop_state.hpos = 0; - cop_state.last_write = 0; - this.compute_spcflag_copper(AMIGA.playfield.maxhpos); - }; + /*-----------------------------------------------------------------------*/ - this.COPCON = function (v) { - this.copcon = v; - }; - this.COP1LCH = function (v) { - this.cop1lc = ((v << 16) | (this.cop1lc & 0xffff)) >>> 0; - }; - this.COP1LCL = function (v) { - this.cop1lc = ((this.cop1lc & 0xffff0000) | (v & 0xfffe)) >>> 0; - }; - this.COP2LCH = function (v) { - this.cop2lc = ((v << 16) | (this.cop2lc & 0xffff)) >>> 0; - }; - this.COP2LCL = function (v) { - this.cop2lc = ((this.cop2lc & 0xffff0000) | (v & 0xfffe)) >>> 0; - }; + this.clr_copcon = function() { //OWN used in playfield.reset_cutom() + copcon = 0; + } + /*this.get_copxlc = function() { //OWN used in events.alloc_cycle_blitter() + return cop_state.strobe == 1 ? cop1lc : cop2lc; + }*/ - this.COPJMP = function (num, vblank) { - var oldstrobe = cop_state.strobe; - - //if (AMIGA.dmaen(DMAF_COPEN) && (cop_state.saved_i1 != 0xffff || cop_state.saved_i2 != 0xfffe)) - //BUG.info('COPJMP(%d) vblank without copper ending %08x (%08x %08x) (%08x %08x)', num, cop_state.ip, this.cop1lc, this.cop2lc, cop_state.saved_i1, cop_state.saved_i2); - - clr_special(SPCFLAG_COPPER); - cop_state.ignore_next = 0; - if (!oldstrobe) - cop_state.state_prev = cop_state.state; - - if ((cop_state.state == COP_wait || cop_state.state == COP_waitforever) && !vblank) - cop_state.state = COP_strobe_delay1x; - else - cop_state.state = vblank ? COP_start_delay : (this.access ? COP_strobe_delay1 : COP_strobe_extra); - - //BUG.info('COPJMP(%d) %d', num, cop_state.state); - - cop_state.vpos = AMIGA.playfield.vpos; - cop_state.hpos = AMIGA.playfield.hpos() & ~1; - cop_state.strobe = num; - this.enabled_thisline = false; - - if (0) { - this.immediate_copper(num); - return; - } - - if (AMIGA.dmaen(DMAF_COPEN)) - this.compute_spcflag_copper(AMIGA.playfield.hpos()); - else if (oldstrobe > 0 && oldstrobe != num && cop_state.state_prev == COP_wait) { - /* dma disabled, copper idle and accessed both COPxJMPs -> copper stops! */ - cop_state.state = COP_stop; - //BUG.info('COPJMP(%d) COP_stop'); - } - }; - - /*function get_copper_address(copno) { + /*this.get_copper_address = function(copno) { switch (copno) { - case 1: return this.cop1lc; - case 2: return this.cop2lc; + case 1: return cop1lc; + case 2: return cop2lc; case -1: return cop_state.ip; default: return 0; } }*/ - this.test_copper_dangerous = function (address) { - var addr = address & 0x1fe; - if (addr < ((this.copcon & 2) ? ((AMIGA.config.chipset.mask & CSMASK_ECS_AGNUS) ? 0 : 0x40) : 0x80)) { + this.copper_stop = function() { //called in custom.DMACON() + if (SAEV_Copper_enabled_thisline) { + // let MOVE to finish + switch (cop_state.state) { + case COP_read2: + SAEV_Copper_enabled_thisline = -1; + break; + } + } + if (SAEV_Copper_enabled_thisline >= 0) { + SAEV_Copper_enabled_thisline = 0; + SAEF_clrSpcFlags(SAEC_spcflag_COPPER); + } + } + + function check_copper_stop() { + //if (SAEV_Copper_enabled_thisline < 0 && !((SAEV_Custom_dmacon & SAEC_Custom_DMAF_COPEN) && (SAEV_Custom_dmacon & SAEC_Custom_DMAF_DMAEN))) { + if (SAEV_Copper_enabled_thisline < 0 && !SAEF_Custom_dmaen(SAEC_Custom_DMAF_COPEN)) { + SAEV_Copper_enabled_thisline = 0; + SAEF_clrSpcFlags(SAEC_spcflag_COPPER); + } + } + + /*-> playfield + function copper_cant_read(hpos, alloc) { + if (hpos + 1 >= maxhpos) // first refresh slot + return 1; + if ((hpos == maxhpos - 3) && (maxhpos & 1) && alloc >= 0) { + //if (alloc) SAER.events.alloc_cycle(hpos, SAEC_Events_cycle_line_COPPER); + return -1; + } + return is_bitplane_dma_inline(hpos); + }*/ + + function put16_copper(hpos, addr, value, noget) { + SAEV_Copper_access = true; + //var v = custom_wput_1(hpos, addr, value, noget); + var v = SAER_Custom_put16_real(hpos, addr, value, noget); + SAEV_Copper_access = false; + return v; + } + + /*function dump(error, until_hpos) { + SAEF_log("copper.dump() %s: vpos=%d until_hpos=%d vp=%d", error, vpos, until_hpos, vpos & (((cop_state.saved_i2 >> 8) & 0x7F) | 0x80)); + SAEF_log("copper.dump() cvcmp=%d chcmp=%d chpos=%d cvpos=%d ci1=%04X ci2=%04X", cop_state.vcmp, cop_state.hcmp, cop_state.hpos, cop_state.vpos, cop_state.saved_i1, cop_state.saved_i2); + SAEF_log("copper.dump() cstate=%d ip=%x SPCFLAGS=%x iscline=%d", cop_state.state, cop_state.ip, SAEV_spcflags, SAEV_Copper_enabled_thisline); + }*/ + + function update_copper(until_hpos) { + var vp = SAER.playfield.get_vpos() & (((cop_state.saved_i2 >> 8) & 0x7F) | 0x80); + var c_hpos = cop_state.hpos; + var maxhpos; + + //if (nocustom()) return; + + if (cop_state.state == COP_wait && vp < cop_state.vcmp) { + //dump("error2", until_hpos); + SAEV_Copper_enabled_thisline = 0; cop_state.state = COP_stop; - this.enabled_thisline = false; - clr_special(SPCFLAG_COPPER); + SAEF_clrSpcFlags(SAEC_spcflag_COPPER); + return; + } + + if (until_hpos <= SAEV_Copper_last_hpos) + return; + + maxhpos = SAER.playfield.get_maxhpos(); + if (until_hpos > (maxhpos & ~1)) + until_hpos = maxhpos & ~1; + + for (;;) { + var old_hpos = c_hpos; + var hp; + + if (c_hpos >= until_hpos) + break; + + + /* So we know about the fetch state. */ + SAER.playfield.decide_line(c_hpos); + // bitplane only, don't want blitter to steal our cycles. + SAER.playfield.decide_fetch(c_hpos); + + if (cop_state.movedelay > 0) { + cop_state.movedelay--; + if (cop_state.movedelay == 0) { + put16_copper(c_hpos, cop_state.moveaddr, cop_state.movedata, 0); + } + } + + maxhpos = SAER.playfield.get_maxhpos(); + if ((c_hpos == maxhpos - 3) && (maxhpos & 1)) + c_hpos += 1; + else + c_hpos += 2; + + switch (cop_state.state) { + case COP_wait_in2: { + if (SAER.playfield.copper_cant_read(old_hpos, 0)) + continue; + cop_state.state = COP_wait1; + break; + } + case COP_skip_in2: { + if (SAER.playfield.copper_cant_read(old_hpos, 0)) + continue; + cop_state.state = COP_skip1; + break; + } + case COP_strobe_extra: { + // Wait 1 copper cycle doing nothing + cop_state.state = COP_strobe_delay1; + break; + } + case COP_strobe_delay1: { + // First cycle after COPJMP is just like normal first read cycle + // Cycle is used and needs to be free. + if (SAER.playfield.copper_cant_read(old_hpos, 1)) + continue; + //SAER.events.alloc_cycle(old_hpos, SAEC_Events_cycle_line_COPPER); + maxhpos = SAER.playfield.get_maxhpos(); + if (old_hpos == maxhpos - 2) { + // if COP_strobe_delay2 would cross scanlines (positioned immediately + // after first strobe/refresh slot) it will disappear! + cop_state.state = COP_read1; + if (cop_state.strobe == 1) + cop_state.ip = cop1lc; + else + cop_state.ip = cop2lc; + cop_state.strobe = 0; + } else { + cop_state.state = COP_strobe_delay2; + cop_state.ip += 2; + } + break; + } + case COP_strobe_delay2: { + // Second cycle after COPJMP. This is the strange one. + // This cycle does not need to be free + // But it still gets allocated by copper if it is free = CPU and blitter can't use it. + //if (!SAER.playfield.copper_cant_read(old_hpos, 0)) SAER.events.alloc_cycle(old_hpos, SAEC_Events_cycle_line_COPPER); + + cop_state.state = COP_read1; + // Next cycle finally reads from new pointer + if (cop_state.strobe == 1) + cop_state.ip = cop1lc; + else + cop_state.ip = cop2lc; + cop_state.strobe = 0; + break; + } + case COP_strobe_delay1x: { + // First cycle after COPJMP and Copper was waiting. This is the buggy one. + // Cycle can be free and copper won"t allocate it. + // If Blitter uses this cycle = Copper"s PC gets copied to blitter DMA pointer.. + cop_state.state = COP_strobe_delay2x; + break; + } + case COP_strobe_delay2x: { + // Second cycle fetches following word and tosses it away. Must be free cycle + // but it is not allocated, blitter or cpu can still use it. + if (SAER.playfield.copper_cant_read(old_hpos, 1)) + continue; + //SAER_Events_cycle_line[old_hpos] |= SAEC_Events_cycle_line_COPPER_SPECIAL; + cop_state.state = COP_read1; + // Next cycle finally reads from new pointer + if (cop_state.strobe == 1) + cop_state.ip = cop1lc; + else + cop_state.ip = cop2lc; + cop_state.strobe = 0; + break; + } + case COP_start_delay: { + // cycle after vblank strobe fetches word from old pointer first + if (SAER.playfield.copper_cant_read(old_hpos, 1)) + continue; + cop_state.state = COP_read1; + //cop_state.i1 = SAEV_Custom_last_value = SAER_Memory_chipGet16_indirect(cop_state.ip); + cop_state.i1 = SAEV_Custom_last_value = (SAER_Memory_chipData[cop_state.ip] << 8) | SAER_Memory_chipData[cop_state.ip + 1]; + //SAER.events.alloc_cycle(old_hpos, SAEC_Events_cycle_line_COPPER); + cop_state.ip = cop1lc; + break; + } + case COP_read1: { + if (SAER.playfield.copper_cant_read(old_hpos, 1)) + continue; + //cop_state.i1 = SAEV_Custom_last_value = SAER_Memory_chipGet16_indirect(cop_state.ip); + cop_state.i1 = SAEV_Custom_last_value = (SAER_Memory_chipData[cop_state.ip] << 8) | SAER_Memory_chipData[cop_state.ip + 1]; + //SAER.events.alloc_cycle(old_hpos, SAEC_Events_cycle_line_COPPER); + cop_state.ip += 2; + cop_state.state = COP_read2; + break; + } + case COP_read2: { + if (SAER.playfield.copper_cant_read(old_hpos, 1)) + continue; + //cop_state.i2 = SAEV_Custom_last_value = SAER_Memory_chipGet16_indirect(cop_state.ip); + cop_state.i2 = SAEV_Custom_last_value = (SAER_Memory_chipData[cop_state.ip] << 8) | SAER_Memory_chipData[cop_state.ip + 1]; + //SAER.events.alloc_cycle(old_hpos, SAEC_Events_cycle_line_COPPER); + cop_state.ip += 2; + cop_state.saved_i1 = cop_state.i1; + cop_state.saved_i2 = cop_state.i2; + cop_state.saved_ip = cop_state.ip; + + if (cop_state.i1 & 1) { // WAIT or SKIP + cop_state.ignore_next = false; + if (cop_state.i2 & 1) + cop_state.state = COP_skip_in2; + else + cop_state.state = COP_wait_in2; + } else { // MOVE + var reg = cop_state.i1 & 0x1FE; + var data = cop_state.i2; + cop_state.state = COP_read1; + test_copper_dangerous(reg); + if (!SAEV_Copper_enabled_thisline) { + //goto out; //was "dangerous" register -> copper stopped + cop_state.hpos = c_hpos; + SAEV_Copper_last_hpos = until_hpos; + return; + } + if (cop_state.ignore_next) + reg = 0x1fe; + + if (reg == 0x88) { + cop_state.strobe = 1; + cop_state.state = COP_strobe_delay1; + } else if (reg == 0x8a) { + cop_state.strobe = 2; + cop_state.state = COP_strobe_delay1; + } else { + if (customdelay[reg >> 1]) { + cop_state.moveaddr = reg; + cop_state.movedata = data; + cop_state.movedelay = customdelay[reg >> 1]; + } else + put16_copper(old_hpos, reg, data, 0); + } + cop_state.ignore_next = false; + } + check_copper_stop(); + break; + } + case COP_wait1: { + cop_state.state = COP_wait; + + cop_state.vcmp = (cop_state.saved_i1 & (cop_state.saved_i2 | 0x8000)) >> 8; + cop_state.hcmp = (cop_state.saved_i1 & cop_state.saved_i2 & 0xFE); + + vp = SAER.playfield.get_vpos() & (((cop_state.saved_i2 >> 8) & 0x7F) | 0x80); + + if (cop_state.saved_i1 == 0xFFFF && cop_state.saved_i2 == 0xFFFE) { + cop_state.state = COP_waitforever; + SAEV_Copper_enabled_thisline = 0; + SAEF_clrSpcFlags(SAEC_spcflag_COPPER); + //goto out; + cop_state.hpos = c_hpos; + SAEV_Copper_last_hpos = until_hpos; + return; + } + if (vp < cop_state.vcmp) { + SAEV_Copper_enabled_thisline = 0; + SAEF_clrSpcFlags(SAEC_spcflag_COPPER); + //goto out; + cop_state.hpos = c_hpos; + SAEV_Copper_last_hpos = until_hpos; + return; + } + /* fall through */ + } + case COP_wait: { + var ch_comp = c_hpos; + if (ch_comp & 1) + ch_comp = 0; + + /* First handle possible blitter wait + * Must be before following free cycle check */ + if ((cop_state.saved_i2 & 0x8000) == 0) { + SAER.blitter.decide_blitter(old_hpos); + if (SAEV_Blitter_bltstate != SAEC_Blitter_bltstate_DONE) { + /* We need to wait for the blitter. */ + cop_state.state = COP_bltwait; + SAEV_Copper_enabled_thisline = 0; + SAEF_clrSpcFlags(SAEC_spcflag_COPPER); + //goto out; + cop_state.hpos = c_hpos; + SAEV_Copper_last_hpos = until_hpos; + return; + } + } + + if (SAER.playfield.copper_cant_read(old_hpos, 0)) + continue; + + hp = ch_comp & (cop_state.saved_i2 & 0xFE); + if (vp == cop_state.vcmp && hp < cop_state.hcmp) + break; + + cop_state.state = COP_read1; + break; + } + case COP_skip1: { + var vcmp, hcmp, vp1, hp1; + + maxhpos = SAER.playfield.get_maxhpos(); + if (c_hpos >= (maxhpos & ~1) || (c_hpos & 1)) + break; + + if (SAER.playfield.copper_cant_read(old_hpos, 0)) + continue; + + vcmp = (cop_state.saved_i1 & (cop_state.saved_i2 | 0x8000)) >> 8; + hcmp = (cop_state.saved_i1 & cop_state.saved_i2 & 0xFE); + vp1 = SAER.playfield.get_vpos() & (((cop_state.saved_i2 >> 8) & 0x7F) | 0x80); + hp1 = c_hpos & (cop_state.saved_i2 & 0xFE); + + if ((vp1 > vcmp || (vp1 == vcmp && hp1 >= hcmp)) && ((cop_state.saved_i2 & 0x8000) != 0 || SAEV_Blitter_bltstate == SAEC_Blitter_bltstate_DONE)) + cop_state.ignore_next = true; + + cop_state.state = COP_read1; + break; + } + default: + break; + } + } + + //out: + cop_state.hpos = c_hpos; + SAEV_Copper_last_hpos = until_hpos; + } + + this.compute_spcflag_copper = function(hpos) { + var wasenabled = SAEV_Copper_enabled_thisline; + + SAEV_Copper_enabled_thisline = 0; + SAEF_clrSpcFlags(SAEC_spcflag_COPPER); + if (!SAEF_Custom_dmaen(SAEC_Custom_DMAF_COPEN) || cop_state.state == COP_stop || cop_state.state == COP_waitforever || cop_state.state == COP_bltwait) //|| nocustom()) + return; + + if (cop_state.state == COP_wait) { + var vp = SAER.playfield.get_vpos() & (((cop_state.saved_i2 >> 8) & 0x7F) | 0x80); + if (vp < cop_state.vcmp) + return; + } + // do not use past cycles if starting for the first time in this line + // (write to DMACON for example) hpos+1 for long lines + if (!wasenabled && cop_state.hpos < hpos && hpos < SAER.playfield.get_maxhpos()) { + var maxhpos_short = SAER.playfield.get_maxhpos_short(); + hpos = (hpos + 2) & ~1; + if (hpos > (maxhpos_short & ~1)) + hpos = maxhpos_short & ~1; + cop_state.hpos = hpos; + } + // if COPJMPx was written while DMA was disabled, advance to next state, + // COP_strobe_extra is single cycle only and does not need free bus. + // (copper state emulation does not run if DMA is disabled) + if (!wasenabled && cop_state.state == COP_strobe_extra) + cop_state.state = COP_strobe_delay1; + + SAEV_Copper_enabled_thisline = 1; + SAEF_setSpcFlags(SAEC_spcflag_COPPER); + } + + this.blitter_done_notify = function(hpos) { + if (cop_state.state != COP_bltwait) + return; + + var vpos = SAER.playfield.get_vpos(); + var vp_wait = vpos & (((cop_state.saved_i2 >> 8) & 0x7F) | 0x80); + var vp = vpos; + var maxhpos = SAER.playfield.get_maxhpos(); + + hpos++; + hpos &= ~1; + if (hpos >= maxhpos) { + hpos -= maxhpos; + vp++; + } + cop_state.hpos = hpos; + cop_state.vpos = vp; + cop_state.state = COP_wait; + /* No need to check blitter state again */ + cop_state.saved_i2 |= 0x8000; + + if (SAEF_Custom_dmaen(SAEC_Custom_DMAF_COPEN) && vp_wait >= cop_state.vcmp) { + SAEV_Copper_enabled_thisline = 1; + SAEF_setSpcFlags(SAEC_spcflag_COPPER); + } else + SAEF_clrSpcFlags(SAEC_spcflag_COPPER); + } + + this.cycle = function() { //do_copper() + var hpos = SAER.events.current_hpos(); + update_copper(hpos); + } + + this.sync_copper_with_cpu = function(hpos, do_schedule) { + /* Need to let the copper advance to the current position. */ + if (SAEV_Copper_enabled_thisline) + update_copper(hpos); + } + + /*-----------------------------------------------------------------------*/ + + function test_copper_dangerous(address) { + var addr = address & 0x01fe; + if (addr < ((copcon & 2) ? ((SAEV_config.chipset.mask & SAEC_Config_Chipset_Mask_ECS_AGNUS) ? 0 : 0x40) : 0x80)) { + cop_state.state = COP_stop; + SAEV_Copper_enabled_thisline = 0; + SAEF_clrSpcFlags(SAEC_spcflag_COPPER); return true; } return false; - }; + } - this.immediate_copper = function (num) { + /*function immediate_copper(num) { var pos = 0; var oldpos = 0; cop_state.state = COP_stop; - cop_state.vpos = AMIGA.playfield.vpos; - cop_state.hpos = AMIGA.playfield.hpos() & ~1; - cop_state.ip = num == 1 ? this.cop1lc : this.cop2lc; + cop_state.vpos = SAER.playfield.get_vpos(); + cop_state.hpos = SAER.events.current_hpos() & ~1; + cop_state.ip = num == 1 ? cop1lc : cop2lc; - while (pos < (AMIGA.playfield.maxvpos << 5)) { + while (pos < (maxvpos << 5)) { if (oldpos > pos) pos = oldpos; - if (!AMIGA.dmaen(DMAF_COPEN)) + if (!SAEF_Custom_dmaen(SAEC_Custom_DMAF_COPEN)) break; - if (cop_state.ip >= AMIGA.mem.chip.size) + if (cop_state.ip >= SAEV_config.memory.chipSize && cop_state.ip < currprefs.z3chipmem_start && cop_state.ip >= currprefs.z3chipmem_start + currprefs.z3chipmem_size) break; pos++; oldpos = pos; - //cop_state.i1 = AMIGA.mem.load16_chip(cop_state.ip); - //cop_state.i2 = AMIGA.mem.load16_chip(cop_state.ip + 2); - cop_state.i1 = AMIGA.mem.chip.data[cop_state.ip >>> 1]; - cop_state.i2 = AMIGA.mem.chip.data[(cop_state.ip + 2) >>> 1]; - AMIGA.custom.last_value = cop_state.i2; + //cop_state.i1 = SAER_Memory_chipGet16_indirect(cop_state.ip); + //cop_state.i2 = SAER_Memory_chipGet16_indirect(cop_state.ip + 2); + cop_state.i1 = (SAER_Memory_chipData[cop_state.ip ] << 8) | SAER_Memory_chipData[cop_state.ip + 1]; + cop_state.i2 = (SAER_Memory_chipData[cop_state.ip + 2] << 8) | SAER_Memory_chipData[cop_state.ip + 3]; cop_state.ip += 4; if (!(cop_state.i1 & 1)) { // move cop_state.i1 &= 0x1fe; if (cop_state.i1 == 0x88) { - cop_state.ip = this.cop1lc; + cop_state.ip = cop1lc; continue; } if (cop_state.i1 == 0x8a) { - cop_state.ip = this.cop2lc; + cop_state.ip = cop2lc; continue; } - if (this.test_copper_dangerous(cop_state.i1)) + if (test_copper_dangerous(cop_state.i1)) break; - AMIGA.custom.store16_real(0, cop_state.i1, cop_state.i2, 0); + + //custom_wput_1(0, cop_state.i1, cop_state.i2, 0); + SAER_Custom_put16_real(0, addr, value, 0); } else { // wait or skip if ((cop_state.i1 >> 8) > ((pos >> 5) & 0xff)) pos = (((pos >> 5) & 0x100) | ((cop_state.i1 >> 8)) << 5) | ((cop_state.i1 & 0xff) >> 3); @@ -200,405 +586,61 @@ function Copper() { } } cop_state.state = COP_stop; - clr_special(SPCFLAG_COPPER); - }; - - this.copper_cant_read = function (hpos, alloc) { - //BUG.info('copper_cant_read2() hpos %d / %d', hpos, AMIGA.playfield.maxhpos); - if (hpos + 1 >= AMIGA.playfield.maxhpos) // first refresh slot - return 1; - if ((hpos == AMIGA.playfield.maxhpos - 3) && (AMIGA.playfield.maxhpos & 1) && alloc >= 0) { - return -1; - } - return AMIGA.playfield.is_bitplane_dma(hpos); - }; - - this.custom_store16_copper = function (hpos, addr, value, noget) { - //if (addr == 0x88 || addr == 0x8a) - //BUG.info('custom_store16_copper() addr %08x, value %04x | vpos %d hpos %d %d cvcmp %d chcmp %d chpos %d cvpos %d', addr, value, AMIGA.playfield.vpos, AMIGA.playfield.hpos(), hpos, cop_state.vcmp, cop_state.hcmp, cop_state.hpos, cop_state.vpos); - //value = debug_wputpeekdma (0xdff000 + addr, value); - this.access = true; - var v = AMIGA.custom.store16_real(hpos, addr, value, noget); - this.access = false; - return v; - }; - - this.dump_copper = function (error, until_hpos) { - BUG.info('\n'); - BUG.info('%s: vpos=%d until_hpos=%d vp=%d', error, AMIGA.playfield.vpos, until_hpos, AMIGA.playfield.vpos & (((cop_state.saved_i2 >> 8) & 0x7f) | 0x80)); - BUG.info('cvcmp=%d chcmp=%d chpos=%d cvpos=%d ci1=%04X ci2=%04X', cop_state.vcmp, cop_state.hcmp, cop_state.hpos, cop_state.vpos, cop_state.saved_i1, cop_state.saved_i2); - BUG.info('cstate=%d ip=%x SPCFLAGS=%x iscline=%d', cop_state.state, cop_state.ip, AMIGA.spcflags, this.enabled_thisline ? 1 : 0); - BUG.info('\n'); - }; - - this.update = function (until_hpos) { - var vp = AMIGA.playfield.vpos & (((cop_state.saved_i2 >> 8) & 0x7f) | 0x80); - var c_hpos = cop_state.hpos; - - //BUG.info('update() until_hpos %d, vp %d', until_hpos, vp); - - if (cop_state.state == COP_wait && vp < cop_state.vcmp) { - this.dump_copper('error2', until_hpos); - this.enabled_thisline = false; - cop_state.state = COP_stop; - clr_special(SPCFLAG_COPPER); - return; - } - - if (until_hpos <= this.last_copper_hpos) - return; - - if (until_hpos > (AMIGA.playfield.maxhpos & ~1)) - until_hpos = AMIGA.playfield.maxhpos & ~1; - - for (; ;) { - var old_hpos = c_hpos; - var hp; - - if (c_hpos >= until_hpos) - break; - - /* So we know about the fetch state. */ - AMIGA.playfield.decide_line(c_hpos); - AMIGA.playfield.decide_fetch(c_hpos); - - if (cop_state.movedelay > 0) { - cop_state.movedelay--; - if (cop_state.movedelay == 0) { - this.custom_store16_copper(c_hpos, cop_state.moveaddr, cop_state.movedata, 0); - } - } - - if ((c_hpos == AMIGA.playfield.maxhpos - 3) && (AMIGA.playfield.maxhpos & 1)) - c_hpos += 1; - else - c_hpos += 2; - - switch (cop_state.state) { - case COP_wait_in2: - { - if (this.copper_cant_read(old_hpos, 0)) - continue; - cop_state.state = COP_wait1; - break; - } - case COP_skip_in2: - { - if (this.copper_cant_read(old_hpos, 0)) - continue; - cop_state.state = COP_skip1; - break; - } - case COP_strobe_extra: - { - // Wait 1 copper cycle doing nothing - cop_state.state = COP_strobe_delay1; - break; - } - case COP_strobe_delay1: - { - // First cycle after COPJMP is just like normal first read cycle - // Cycle is used and needs to be free. - if (this.copper_cant_read(old_hpos, 1)) - continue; - cop_state.state = COP_strobe_delay2; - cop_state.ip += 2; - break; - } - case COP_strobe_delay2: - { - // Second cycle after COPJMP. This is the strange one. - // This cycle does not need to be free - // But it still gets allocated by copper if it is free = CPU and blitter can't use it. - cop_state.state = COP_read1; - // Next cycle finally reads from new pointer - if (cop_state.strobe == 1) - cop_state.ip = this.cop1lc; - else - cop_state.ip = this.cop2lc; - cop_state.strobe = 0; - break; - } - case COP_strobe_delay1x: - { - // First cycle after COPJMP and Copper was waiting. This is the buggy one. - // Cycle can be free and copper won't allocate it. - // If Blitter uses this cycle = Copper's address gets copied blitter DMA pointer.. - cop_state.state = COP_strobe_delay2x; - break; - } - case COP_strobe_delay2x: - { - // Second cycle fetches following word and tosses it away. Must be free cycle - // but is not allocated, blitter or cpu can still use it. - if (this.copper_cant_read(old_hpos, 1)) - continue; - cop_state.state = COP_read1; - // Next cycle finally reads from new pointer - if (cop_state.strobe == 1) - cop_state.ip = this.cop1lc; - else - cop_state.ip = this.cop2lc; - cop_state.strobe = 0; - break; - } - case COP_start_delay: - { - if (this.copper_cant_read(old_hpos, 1)) - continue; - cop_state.state = COP_read1; - cop_state.ip = this.cop1lc; - break; - } - case COP_read1: - { - if (this.copper_cant_read(old_hpos, 1)) - continue; - /* workaround for a bug in kick 1.x */ - if (cop_state.ip == 0x00000004 || cop_state.ip == 0x00000676 || cop_state.ip == 0x00c00276) { - //BUG.info('COP_read1() invalid addr $%08x', cop_state.ip); - cop_state.state = COP_stop; - this.enabled_thisline = false; - clr_special(SPCFLAG_COPPER); - return; - } - //cop_state.i1 = AMIGA.mem.load16_chip(cop_state.ip); - cop_state.i1 = AMIGA.custom.last_value = AMIGA.mem.chip.data[cop_state.ip >>> 1]; - cop_state.ip += 2; - cop_state.state = COP_read2; - break; - } - case COP_read2: - { - if (this.copper_cant_read(old_hpos, 1)) - continue; - //cop_state.i2 = AMIGA.mem.load16_chip(cop_state.ip); - cop_state.i2 = AMIGA.custom.last_value = AMIGA.mem.chip.data[cop_state.ip >>> 1]; - cop_state.ip += 2; - cop_state.saved_i1 = cop_state.i1; - cop_state.saved_i2 = cop_state.i2; - cop_state.saved_ip = cop_state.ip; - - if (cop_state.i1 & 1) { // WAIT or SKIP - cop_state.ignore_next = 0; - if (cop_state.i2 & 1) - cop_state.state = COP_skip_in2; - else - cop_state.state = COP_wait_in2; - } else { // MOVE - //uaecptr debugip = cop_state.ip; - var reg = cop_state.i1 & 0x1fe; - var data = cop_state.i2; - cop_state.state = COP_read1; - this.test_copper_dangerous(reg); - if (!this.enabled_thisline) { - //goto out; // was 'dangerous' register -> copper stopped - cop_state.hpos = c_hpos; - this.last_copper_hpos = until_hpos; - return; - } - if (cop_state.ignore_next) - reg = 0x1fe; - - cop_state.last_write = reg; - cop_state.last_write_hpos = old_hpos; - if (reg == 0x88) { - cop_state.strobe = 1; - cop_state.state = COP_strobe_delay1; - } else if (reg == 0x8a) { - cop_state.strobe = 2; - cop_state.state = COP_strobe_delay1; - } else { - /*if (0) { - AMIGA.events.newevent2(1, (reg << 16) | data, function(v) { //copper_write); - AMIGA.copper.custom_store16_copper(AMIGA.playfield.hpos(), v >>> 16, v & 0xffff, 0); - }); - //this.custom_store16_copper(old_hpos, reg, data, 0); - } else*/ - { - // FIX: all copper writes happen 1 cycle later than CPU writes - if (customdelay[reg >> 1]) { - cop_state.moveaddr = reg; - cop_state.movedata = data; - cop_state.movedelay = customdelay[cop_state.moveaddr >> 1]; - } else { - var hpos2 = old_hpos; - this.custom_store16_copper(hpos2, reg, data, 0); - hpos2++; - if (reg >= 0x140 && reg < 0x180 && hpos2 >= SPR0_HPOS && hpos2 < SPR0_HPOS + 4 * MAX_SPRITES) - AMIGA.playfield.do_sprites(hpos2); - } - } - } - cop_state.ignore_next = 0; - } - break; - } - case COP_wait1: - { - /*#if 0 - if (c_hpos >= (AMIGA.playfield.maxhpos & ~1) || (c_hpos & 1)) break; - #endif*/ - cop_state.state = COP_wait; - - cop_state.vcmp = (cop_state.saved_i1 & (cop_state.saved_i2 | 0x8000)) >> 8; - cop_state.hcmp = (cop_state.saved_i1 & cop_state.saved_i2 & 0xfe); - - vp = AMIGA.playfield.vpos & (((cop_state.saved_i2 >> 8) & 0x7f) | 0x80); - - if (cop_state.saved_i1 == 0xffff && cop_state.saved_i2 == 0xfffe) { - cop_state.state = COP_waitforever; - this.enabled_thisline = false; - clr_special(SPCFLAG_COPPER); - //goto out; - cop_state.hpos = c_hpos; - this.last_copper_hpos = until_hpos; - return; - } - if (vp < cop_state.vcmp) { - this.enabled_thisline = false; - clr_special(SPCFLAG_COPPER); - //goto out; - cop_state.hpos = c_hpos; - this.last_copper_hpos = until_hpos; - return; - } - } - /* fall through */ - case COP_wait: - { - var ch_comp = c_hpos; - if (ch_comp & 1) - ch_comp = 0; - - if (this.copper_cant_read(old_hpos, 0)) - continue; - - hp = ch_comp & (cop_state.saved_i2 & 0xfe); - if (vp == cop_state.vcmp && hp < cop_state.hcmp) - break; - - /* Now we know that the comparisons were successful. We might still have to wait for the blitter though. */ - if ((cop_state.saved_i2 & 0x8000) == 0) { - if (AMIGA.blitter.getState() != BLT_done) { - //We need to wait for the blitter. - cop_state.state = COP_bltwait; - this.enabled_thisline = false; - clr_special(SPCFLAG_COPPER); - //goto out; - cop_state.hpos = c_hpos; - this.last_copper_hpos = until_hpos; - return; - } - } - cop_state.state = COP_read1; - break; - } - case COP_skip1: - { - var vcmp, hcmp, vp1, hp1; - - if (c_hpos >= (AMIGA.playfield.maxhpos & ~1) || (c_hpos & 1)) - break; - - if (this.copper_cant_read(old_hpos, 0)) - continue; - - vcmp = (cop_state.saved_i1 & (cop_state.saved_i2 | 0x8000)) >> 8; - hcmp = (cop_state.saved_i1 & cop_state.saved_i2 & 0xfe); - vp1 = AMIGA.playfield.vpos & (((cop_state.saved_i2 >> 8) & 0x7f) | 0x80); - hp1 = c_hpos & (cop_state.saved_i2 & 0xfe); - - if ((vp1 > vcmp || (vp1 == vcmp && hp1 >= hcmp)) && ((cop_state.saved_i2 & 0x8000) != 0 || AMIGA.blitter.getState() == BLT_done)) - cop_state.ignore_next = 1; - - cop_state.state = COP_read1; - break; - } - } - } - - //out: - cop_state.hpos = c_hpos; - this.last_copper_hpos = until_hpos; - }; - - this.compute_spcflag_copper = function (hpos) { - //BUG.info('compute_spcflag_copper() hpos %d', hpos); - var wasenabled = this.enabled_thisline; - - this.enabled_thisline = false; - clr_special(SPCFLAG_COPPER); - if (!AMIGA.dmaen(DMAF_COPEN) || cop_state.state == COP_stop || cop_state.state == COP_waitforever || cop_state.state == COP_bltwait) - return; - - if (cop_state.state == COP_wait) { - var vp = AMIGA.playfield.vpos & (((cop_state.saved_i2 >> 8) & 0x7f) | 0x80); - - if (vp < cop_state.vcmp) - return; - } - // do not use past cycles if starting for the first time in this line - // (write to DMACON for example) hpos+1 for long lines - if (!wasenabled && cop_state.hpos < hpos && hpos < AMIGA.playfield.maxhpos) { - hpos = (hpos + 2) & ~1; - if (hpos > AMIGA.playfield.maxhpos_short) - hpos = AMIGA.playfield.maxhpos_short; - cop_state.hpos = hpos; - //BUG.info('compute_spcflag_copper() hpos %d %d', hpos, AMIGA.playfield.maxhpos_short); - } - - // if COPJMPx was written while DMA was disabled, advance to next state, - // COP_strobe_extra is single cycle only and does not need free bus. - // (copper state emulation does not run if DMA is disabled) - if (!wasenabled && cop_state.state == COP_strobe_extra) - cop_state.state = COP_strobe_delay1; - - this.enabled_thisline = true; - set_special(SPCFLAG_COPPER); - }; - - this.blitter_done_notify = function (hpos) { - if (cop_state.state != COP_bltwait) - return; - - //BUG.info('blitter_done_notify() hpos %d', hpos); - - var vp = AMIGA.playfield.vpos; - hpos += 3; - hpos &= ~1; - if (hpos >= AMIGA.playfield.maxhpos) { - hpos -= AMIGA.playfield.maxhpos; - vp++; - } - cop_state.hpos = hpos; - cop_state.vpos = vp; - cop_state.state = COP_read1; - - if (AMIGA.dmaen(DMAF_COPEN) && vp == AMIGA.playfield.vpos) { - this.enabled_thisline = true; - set_special(SPCFLAG_COPPER); - } - }; - - this.cycle = function () { - this.update(AMIGA.playfield.hpos()); - }; - - this.sync_copper_with_cpu = function (hpos, do_schedule) { - /* Need to let the copper advance to the current position. */ - if (this.enabled_thisline) - this.update(hpos); - }; - - /*this.check = function (n) { - if (cop_state.state == COP_wait) { - var vp = AMIGA.playfield.vpos & (((cop_state.saved_i2 >> 8) & 0x7f) | 0x80); - if (vp < cop_state.vcmp) { - if (this.enabled_thisline) - BUG.info('COPPER BUG %d: vp=%d vpos=%d vcmp=%d thisline=%d', n, vp, AMIGA.playfield.vpos, cop_state.vcmp, this.enabled_thisline?1:0); - } - } + SAEF_clrSpcFlags(SAEC_spcflag_COPPER); }*/ -} + this.COP1LCH = function(v) { + v = v & (SAEV_config.chipset.mask == SAEC_Config_Chipset_Mask_OCS ? 7 : 31); //OWN + cop1lc = ((cop1lc & 0x0000ffff) | (v << 16)) >>> 0; + } + this.COP1LCL = function(v) { + cop1lc = ((cop1lc & 0xffff0000) | (v & 0xfffe)) >>> 0; + } + this.COP2LCH = function(v) { + v = v & (SAEV_config.chipset.mask == SAEC_Config_Chipset_Mask_OCS ? 7 : 31); //OWN + cop2lc = ((cop2lc & 0x0000ffff) | (v << 16)) >>> 0; + } + this.COP2LCL = function(v) { + cop2lc = ((cop2lc & 0xffff0000) | (v & 0xfffe)) >>> 0; + } + + // vblank = copper starts at hpos=2 + // normal COPJMP write: takes 2 more cycles + this.COPJMP = function(num, vblank) { + var oldstrobe = cop_state.strobe; + var wasstopped = cop_state.state == COP_stop && !vblank; + + /*if (SAEF_Custom_dmaen(SAEC_Custom_DMAF_COPEN) && (cop_state.saved_i1 != 0xffff || cop_state.saved_i2 != 0xfffe)) + SAEF_warn("copper.COPJMP vblank without copper ending %08x (%08x %08x)", cop_state.ip, cop1lc, cop2lc);*/ + + SAEF_clrSpcFlags(SAEC_spcflag_COPPER); + cop_state.ignore_next = false; + + if (!oldstrobe) + cop_state.state_prev = cop_state.state; + if ((cop_state.state == COP_wait || cop_state.state == COP_waitforever) && !vblank && SAEF_Custom_dmaen(SAEC_Custom_DMAF_COPEN)) { + cop_state.state = COP_strobe_delay1x; + } else { + cop_state.state = vblank ? COP_start_delay : (SAEV_Copper_access ? COP_strobe_delay1 : COP_strobe_extra); + } + cop_state.vpos = SAER.playfield.get_vpos(); + cop_state.hpos = SAER.events.current_hpos() & ~1; + SAEV_Copper_enabled_thisline = 0; + cop_state.strobe = num; + + /*if (nocustom()) { + immediate_copper(num); + return; + }*/ + if (SAEF_Custom_dmaen(SAEC_Custom_DMAF_COPEN)) { + this.compute_spcflag_copper(SAER.events.current_hpos()); + } else if (wasstopped || (oldstrobe > 0 && oldstrobe != num && cop_state.state_prev == COP_wait)) { + /* dma disabled, copper idle and accessed both COPxJMPs -> copper stops! */ + cop_state.state = COP_stop; + } + } + + this.COPCON = function(a) { + copcon = a; + } +} diff --git a/sae/cpu.js b/sae/cpu.js index dcc108f..7073dbf 100644 --- a/sae/cpu.js +++ b/sae/cpu.js @@ -1,22 +1,207 @@ -/************************************************************************** -* SAE - Scripted Amiga Emulator -* -* 2012-2015 Rupert Hausberger -* -* https://github.com/naTmeg/ScriptedAmigaEmulator -* -*************************************************************************** -* -* TODO: -* - Faster versions of ASx/LSx/ROx/ROXx and xBCD -* -* Notes: -* - Based on M68000PRM.pdf -* - Written from scratch. -* -**************************************************************************/ +/*------------------------------------------------------------------------- +| SAE - Scripted Amiga Emulator +| https://github.com/naTmeg/ScriptedAmigaEmulator +| +| Copyright (C) 2012-2016 Rupert Hausberger +| +| This program is free software; you can redistribute it and/or +| modify it under the terms of the GNU General Public License +| as published by the Free Software Foundation; either version 2 +| of the License, or (at your option) any later version. +| +| This program is distributed in the hope that it will be useful, +| but WITHOUT ANY WARRANTY; without even the implied warranty of +| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +| GNU General Public License for more details. +| +| Notes: This file consists of two parts: high-level functions, +| ported from WinUAE 3.2.x and low-level functions, written from scratch. +-------------------------------------------------------------------------*/ +/* global constants */ + +/*---------------------------------*/ +/* global references */ + +var SAER_CPU_regs = null; + +var SAER_CPU_setPC = null; +var SAER_CPU_getPC = null; + +var SAER_CPU_exception = null; + +var SAER_CPU_run_func = null; + +var SAER_CPU_fill_prefetch = null; + +/*---------------------------------*/ +/* global variables */ + +var SAEV_CPU_cycles = 0; + +/*---------------------------------*/ + +function SAEO_CPU() { + /* Exception 2/3 error */ + function Exception23(num) { + this.num = num; + } + Exception23.prototype = new Error; + + /* Exception 3 info */ + var last_op_for_exception_3 = 0;/* Opcode of faulting instruction */ + var last_addr_for_exception_3 = 0;/* PC at fault time */ + var last_fault_for_exception_3 = 0;/* Address that generated the exception */ + var last_writeaccess_for_exception_3 = false;/* read (0) or write (1) access */ + var last_instructionaccess_for_exception_3 = false;/* instruction (1) or data (0) access */ + var last_notinstruction_for_exception_3 = false;/* not instruction */ + var exception_in_exception = 0; /* set when writing exception stack frame */ + var bus_error_offset = 0; + + /* 68020 cache */ + const CACR020_C = 1 << 3; /* Clear Cache */ + const CACR020_CE = 1 << 2; /* Clear Entry in Cache */ + const CACR020_F = 1 << 1; /* Freeze Cache */ + const CACR020_E = 1 << 0; /* Enable Cache */ + const CACR020_RMASK = 0x3; + const CACR020_WMASK = 0xf; + + const CACHELINES020 = 64; + const CACHELINE020_IM = CACHELINES020 - 1; + const CACHELINE020_TM = ~((CACHELINES020 << 2) - 1) >>> 0; + function cache020() { + this.data = 0; + this.tag = 0; + this.valid = false; + } + var caches020 = new Array(CACHELINES020); + for (var vi = 0; vi < CACHELINES020; vi++) + caches020[vi] = new cache020(); + + /* 68030 cache */ + const CACR030_WA = 1 << 13; /* Write Allocate */ + const CACR030_DBE = 1 << 12; /* Data Burst Enable */ + const CACR030_CD = 1 << 11; /* Clear Data Cache */ + const CACR030_CED = 1 << 10; /* Clear Entry in Data Cache */ + const CACR030_FD = 1 << 9; /* Freeze Data Cache */ + const CACR030_ED = 1 << 8; /* Enable Data Cache */ + const CACR030_IBE = 1 << 4; /* Instruction Burst Enable */ + const CACR030_CI = 1 << 3; /* Clear Instruction Cache */ + const CACR030_CEI = 1 << 2; /* Clear Entry in Instruction Cache */ + const CACR030_FI = 1 << 1; /* Freeze Instruction Cache */ + const CACR030_EI = 1 << 0; /* Enable Instruction Cache */ + const CACR030_RMASK = 0x3313; + const CACR030_WMASK = 0x3f1f; + + const CACHELINES030 = 16; + const CACHELINE030_IM = CACHELINES030 - 1; + const CACHELINE030_TM = ~((CACHELINES030 << 4) - 1) >>> 0; + function cache030() { + this.data = new Uint32Array(4); + this.valid = [false, false, false, false]; + this.tag = 0; + } + var icaches030 = new Array(CACHELINES030); + for (var vi = 0; vi < CACHELINES030; vi++) + icaches030[vi] = new cache030(); + + var dcaches030 = new Array(CACHELINES030); + for (var vi = 0; vi < CACHELINES030; vi++) + dcaches030[vi] = new cache030(); + + /* 68040 cache */ + /*#define CACHESETS040 64 + #define CACHELINES040 4 + struct cache040 { + uae_u32 data[CACHELINES040][4]; + bool dirty[CACHELINES040][4]; + bool valid[CACHELINES040]; + uae_u32 tag[CACHELINES040]; + }; + static struct cache040 icaches040[CACHESETS040]; + static struct cache040 dcaches040[CACHESETS040]; + var icachelinecnt = 0, dcachelinecnt = 0;*/ + + /* 68030 fake MMU */ + //var fake_srp_030 = 0, fake_crp_030 = 0; //64 + var fake_srp_030_hi = 0, fake_srp_030_lo = 0; + var fake_crp_030_hi = 0, fake_crp_030_lo = 0; + var fake_tt0_030 = 0, fake_tt1_030 = 0, fake_tc_030 = 0; //32 + var fake_mmusr_030 = 0; //16 + + /* shared CPU registers */ + function regstruct() { + this.a = new Uint32Array(8); + this.d = new Uint32Array(8); + + this.pc = 0; //u32 + this.pc_p = 0; //u8 * + this.pc_oldp = 0; //u8 * + this.opcode = 0; //u16 + this.instruction_pc = 0; //u32 + + this.db = 0; //u16 + this.irc = 0, this.ir = 0; //u16 + //this.chipset_latch_rw = 0; //u32 + //this.chipset_latch_read = 0; //u32 + //this.chipset_latch_write = 0; //u32 + + this.usp = 0, this.isp = 0, this.msp = 0; + + this.t1 = false; + this.t0 = false; + this.s = false; + this.m = false; + this.intmask = 0; + this.x = false; + this.n = false; + this.z = false; + this.v = false; + this.c = false; + this.stopped = false; + this.halted = 0; + + this.vbr = 0, this.sfc = 0, this.dfc = 0; //u32 + + this.cacr = 0, this.caar = 0; //u32 + //uae_u32 itt0, itt1, dtt0, dtt1; + //uae_u32 tcr, mmusr, urp, srp, buscr; + + this.prefetch020 = new Uint32Array(4); + this.prefetch020addr = 0; //u32 + this.cacheholdingdata020 = 0; //u32 + this.cacheholdingaddr020 = 0; //u32 + }; + var regs = new regstruct(); + SAER_CPU_regs = regs; + + const CYCLES_DIV = 8192; + var cycles_mult = 0; + var cpucycleunit = 0; + var cpu_cycles = 0; + + var illegal_warned = 0; + + /*-----------------------------------------------------------------------*/ + + const PC_OFFSET = 2; + var pc_offset = PC_OFFSET; //, pc_offset_old = 0; + + var coreGetPC = null; + var coreSetPC = null; + var coreSyncPC = null; + var coreNext16 = null; + var coreNext32 = null; + var coreGetInst16 = null; + var coreGetInst32 = null; + var coreGet8 = null; + var coreGet16 = null; + var coreGet32 = null; + var corePut8 = null; + var corePut16 = null; + var corePut32 = null; + + /*---------------------------------*/ -function CPU() { const M_rdd = 1; /* Register Direct Data */ const M_rda = 2; /* Register Direct Address */ const M_ria = 3; /* Register Indirect Address */ @@ -29,147 +214,2647 @@ function CPU() { const M_absw = 10; /* Absolute Data Addressing */ const M_absl = 11; /* Absolute Data Addressing */ const M_imm = 12; /* Immediate Data */ - const M_list = 16; /* Ax,Dx-list for easy MOVEM debug */ - const T_RD = 1; /* Register Data */ - const T_RA = 2; /* Register Address */ - const T_AD = 3; /* Address */ - const T_IM = 4; /* Immediate */ + const ccNames = ["T", "F", "HI", "LS", "CC", "CS", "NE", "EQ", "VC", "VS", "PL", "MI", "GE", "LT", "GT", "LE"]; - const ccNames = ['T', 'F', 'HI', 'LS', 'CC', 'CS', 'NE', 'EQ', 'VC', 'VS', 'PL', 'MI', 'GE', 'LT', 'GT', 'LE']; + var iTab = []; + var ccTab = []; + var exEAtab = []; + var ldEA8tab = [], stEA8tab = []; + var ldEA16tab = [], stEA16tab = []; + var ldEA32tab = [], stEA32tab = []; - /* Effective Address */ - function EffAddr(m, r) { - this.m = m; /* Mode M_ */ - this.t = 0; /* Type T_ */ - this.r = r; /* Register An/Dn */ - this.a = 0; /* Address */ - this.c = 0; /* Cycles */ - } - - /* Instruction Condition */ - function ICon(cc, dp, dr) { - this.cc = cc; /* Condition Code */ - this.dp = dp; /* Displacement */ - this.dr = dr; /* Data Register for DBcc */ - } - - /* Instruction Paramenter */ - function IPar() { - this.z = 0; /* size B,W,L */ - /* Filled on demand - this.s = new EffAddr(); - this.d = new EffAddr(); - this.c = new ICon(); - this.ms = 0; - this.mz = 0; - this.cyc = 0;*/ - } - - /* Instruction Definition */ - function IDef() { - this.op = 0; /* OP-code */ - //this.pr = false; /* Privileged */ - this.mn = ''; /* Mnemonic */ - this.f = null; /* Function */ - this.p = new IPar(); - } - - /* Exception 2/3 error */ - function Exception23(num) { - this.num = num; - } - Exception23.prototype = new Error; + var model = 0; /*-----------------------------------------------------------------------*/ - - const undef = false; /* use undef */ - - var regs = { - //d: [0, 0, 0, 0, 0, 0, 0, 0], /* Dn */ - //a: [0, 0, 0, 0, 0, 0, 0, 0], /* An */ - d: new Uint32Array(8), - a: new Uint32Array(8), - /* Status Register (SR) */ - t: false, - s: false, - intmask: 0, - /* Condition Code Register (CCR) */ - x: false, - n: false, - z: false, - v: false, - c: false, - usp: 0, /* User Stack Ptr (USP) */ - isp: 0, /* Interrupt Stack Ptr (ISP) */ - pc: 0, /* Program Counter (PC) */ - stopped:true - }; - var fault = { - op: 0, - pc: 0, - ad: 0, - ia: false - }; - var iTab = null; - var cpu_cycle_unit = CYCLE_UNIT / 2; - var cpu_cycles = 4 * cpu_cycle_unit; - + /* SECT core high-level, ported from WinUAE */ /*-----------------------------------------------------------------------*/ - this.setup = function () { - if (iTab === null) { - BUG.say('cpu.setup() no instruction table, generating...'); - if (!mkiTab()) - Fatal(SAEE_CPU_Internal, 'cpu.setup() error generating function table'); + this.setup = function() { //init_m68k() + /*switch (SAEV_config.cpu.model) { + case SAEC_Config_CPU_Model_68030: cpucycleunit = SAEC_Events_CYCLE_UNIT >> 3; break; + case SAEC_Config_CPU_Model_68020: cpucycleunit = SAEC_Events_CYCLE_UNIT >> 2; break; + default: cpucycleunit = SAEC_Events_CYCLE_UNIT >> 1; + }*/ + update_cycles(); + + if (SAEV_config.cpu.model < SAEC_Config_CPU_Model_68020) + SAER_CPU_run_func = SAEV_config.cpu.compatible ? runPrefetch000 : runNormal; + else + SAER_CPU_run_func = SAEV_config.cpu.compatible ? runPrefetch020 : runNormal; + + setup_functions(); + + if (!iTab.length || model != SAEV_config.cpu.model) { + //SAEF_log("cpu.setup_core() no/invalid instruction table, generating..."); + model = SAEV_config.cpu.model; + if (!mkITab()) + return SAEE_CPU_Internal; } else - BUG.say('cpu.setup() instruction table is cached'); - }; + SAEF_log("cpu.setup_core() instruction table is cached"); - this.reset = function (addr) { - for (var i = 0; i < 8; i++) - regs.d[i] = regs.a[i] = 0; + if (!ccTab.length) mkCCTab(); + if (!exEAtab.length) mkEATabs(); - regs.t = false; + return SAEE_None; + } + + /*-----------------------------------------------------------------------*/ + + this.reset = function(hardreset) { + regs.a[7] = SAER_Memory_get32(0); + this.setPC_normal(SAER_Memory_get32(4)); + + regs.t1 = false; + regs.t0 = false; regs.s = true; + regs.m = false; regs.intmask = 7; regs.x = regs.n = regs.z = regs.v = regs.c = false; - regs.usp = 0; - regs.isp = 0; - regs.a[7] = AMIGA.mem.load32(addr); - regs.pc = AMIGA.mem.load32(addr + 4); - regs.stopped = false; + regs.vbr = regs.sfc = regs.dfc = 0; + regs.irc = 0xffff; + regs.db = 0; - BUG.say(sprintf('cpu.reset() addr 0x%08x, A7 0x%08x, PC 0x%08x', addr, regs.a[7], regs.pc)); - }; + if (SAEV_config.cpu.model == SAEC_Config_CPU_Model_68020) { + regs.caar = 0; + regs.cacr = CACR020_C; + coreSetCaches(false); + } + else if (SAEV_config.cpu.model == SAEC_Config_CPU_Model_68030) { //OWN + regs.caar = 0; + regs.cacr = CACR030_CD|CACR030_CI; + coreSetCaches(false); + } + + { + SAER.memory.a3000_fakekick(false); + /* only (E)nable bit is zeroed when CPU is reset, A3000 SuperKickstart expects this */ + fake_tc_030 &= ~0x80000000; + fake_tt0_030 &= ~0x80000000; + fake_tt1_030 &= ~0x80000000; + if (hardreset || regs.halted) { + //fake_srp_030 = fake_crp_030 = 0; + fake_srp_030_hi = fake_srp_030_lo = 0; + fake_crp_030_hi = fake_crp_030_lo = 0; + fake_tt0_030 = fake_tt1_030 = fake_tc_030 = 0; + } + fake_mmusr_030 = 0; + } + + fill_prefetch(); + + illegal_warned = 0; + } /*-----------------------------------------------------------------------*/ - function szChr(z) { - switch (z) { - case 0: return 'S'; - case 1: return 'B'; - case 2: return 'W'; - case 4: return 'L'; - default: - Fatal(SAEE_CPU_Internal, 'cpu.szChr() invalid size'); - return ''; - } + this.dump = function() { + var i, j, out = ""; + + for (i = 0; i < 8; i++) out += sprintf("D%d $%08x ", i, regs.d[i]); out += "\n"; + for (i = 0; i < 8; i++) out += sprintf("A%d $%08x ", i, regs.a[i]); out += "\n"; + + if (!regs.s) regs.usp = regs.a[7]; + if (regs.s && regs.m) regs.msp = regs.a[7]; + if (regs.s && !regs.m) regs.isp = regs.a[7]; + out += sprintf("PC $%08x USP $%08x ISP $%08x ", getPC(), regs.usp, regs.isp); + if (model >= SAEC_Config_CPU_Model_68020) out += sprintf("MSP $%08x ", regs.msp); + if (model >= SAEC_Config_CPU_Model_68010) out += sprintf("SFC $%08x DFC $%08x VBR $%08x", regs.sfc, regs.dfc, regs.vbr); + out += "\n"; + out += sprintf("SR T=%d%d S=%d M=%d IMASK=%d X=%d N=%d Z=%d V=%d C=%d\n", + regs.t1?1:0, regs.t0?1:0, regs.s?1:0, regs.m?1:0, regs.intmask, + regs.x?1:0, regs.n?1:0, regs.z?1:0, regs.v?1:0, regs.c?1:0); + + if (model >= SAEC_Config_CPU_Model_68020) + out += dump_cache(); + + SAEF_log(out); } - - function regsStr(v, inv) { - var out = ''; - for (var i = 0; i < 16; i++) { - if (v & (1 << (inv ? 15-i : i))) { - if (i < 8) { - out += 'D'+i+' '; - } else { - out += 'A'+(i-8)+' '; + + /*-----------------------------------------------------------------------*/ + /* caches */ + + function dump_cache() { + if (!SAEV_config.cpu.compatible) + return "CACHE disabled\n"; + + var out = sprintf("CACR $%08x CAAR $%08x\n", regs.cacr, regs.caar); + if (SAEV_config.cpu.model == SAEC_Config_CPU_Model_68020) { + out += "68020 inst-cache:\n"; + for (var i = 0; i < CACHELINES020; i += 4) { + for (var j = 0; j < 4; j++) { + var s = i + j; + var c = caches020[s]; + var addr = c.tag & ~1; + addr |= s << 2; + out += sprintf("%08X:%08X%s ", addr, c.data, c.valid ? "*" : " "); } + out += "\n"; + } + } else if (SAEV_config.cpu.model == SAEC_Config_CPU_Model_68030) { + out += "68030 inst-cache: ["+((regs.cacr & CACR030_EI) ? "enabled" : "disabled") +"]\n"; + for (var i = 0; i < CACHELINES030; i++) { + var c = icaches030[i]; + var addr = c.tag & ~1; + addr |= i << 4; + out += sprintf("%02d %08X: ", i, addr); + for (var j = 0; j < 4; j++) + out += sprintf("%08X%s ", c.data[j], c.valid[j] ? '*' : ' '); + + out += "\n"; + } + out += "68030 data-cache: ["+((regs.cacr & CACR030_ED) ? "enabled" : "disabled") +"]\n"; + for (var i = 0; i < CACHELINES030; i++) { + var c = dcaches030[i]; + var addr = c.tag & ~1; + addr |= i << 4; + out += sprintf("%02d %08X: ", i, addr); + for (var j = 0; j < 4; j++) + out += sprintf("%08X%s ", c.data[j], c.valid[j] ? '*' : ' '); + + out += "\n"; } } return out; - } + } + + function flush_caches(force) { //flush_cpu_caches() + var doflush = SAEV_config.cpu.compatible; + + if (SAEV_config.cpu.model == SAEC_Config_CPU_Model_68020) { + if (regs.cacr & CACR020_C) { + for (var i = 0; i < CACHELINES020; i++) + caches020[i].valid = false; + regs.cacr &= ~CACR020_C; + } + if (regs.cacr & CACR020_CE) { + caches020[(regs.caar >>> 2) & CACHELINE020_IM].valid = false; + regs.cacr &= ~CACR020_CE; + } + } + else if (SAEV_config.cpu.model == SAEC_Config_CPU_Model_68030) { + if (regs.cacr & CACR030_CI) { + if (doflush) { + for (var i = 0; i < CACHELINES030; i++) { + icaches030[i].valid[0] = false; + icaches030[i].valid[1] = false; + icaches030[i].valid[2] = false; + icaches030[i].valid[3] = false; + } + } + regs.cacr &= ~CACR030_CI; + } + if (regs.cacr & CACR030_CEI) { + icaches030[(regs.caar >>> 4) & CACHELINE030_IM].valid[(regs.caar >>> 2) & 3] = 0; + regs.cacr &= ~CACR030_CEI; + } + if (regs.cacr & CACR030_CD) { + if (doflush) { + for (var i = 0; i < CACHELINES030; i++) { + dcaches030[i].valid[0] = false; + dcaches030[i].valid[1] = false; + dcaches030[i].valid[2] = false; + dcaches030[i].valid[3] = false; + } + } + regs.cacr &= ~CACR030_CD; + } + if (regs.cacr & CACR030_CED) { + dcaches030[(regs.caar >>> 4) & CACHELINE030_IM].valid[(regs.caar >>> 2) & 3] = 0; + regs.cacr &= ~CACR030_CED; + } + } + /*else if (SAEV_config.cpu.model >= SAEC_Config_CPU_Model_68040) { + icachelinecnt = 0; + dcachelinecnt = 0; + if (doflush) { + for (var i = 0; i < CACHESETS040; i++) { + icaches040[i].valid[0] = 0; + icaches040[i].valid[1] = 0; + icaches040[i].valid[2] = 0; + icaches040[i].valid[3] = 0; + } + } + }*/ + } + /*function flush_cpu_caches_040(opcode) { + var cache = (opcode >> 6) & 3; + if (cache & 2) + flush_caches(true); + }*/ + function coreSetCaches(flush) { //set_cpu_caches() + /*if (SAEV_config.cpu.model == SAEC_Config_CPU_Model_68020) { + SAEF_log("cpu.set_caches_68020() C%d CE%d F%d E%d", + (regs.cacr & CACR020_C )?1:0, + (regs.cacr & CACR020_CE)?1:0, + (regs.cacr & CACR020_F )?1:0, + (regs.cacr & CACR020_E )?1:0 + ); + } + else if (SAEV_config.cpu.model == SAEC_Config_CPU_Model_68030) { + SAEF_log("cpu.set_caches_68030() WA%d DBE%d CD%d CED%d FD%d ED%d IBE%d CI%d CEI%d FI%d EI%d", + (regs.cacr & CACR030_WA )?1:0, + (regs.cacr & CACR030_DBE)?1:0, + (regs.cacr & CACR030_CD )?1:0, + (regs.cacr & CACR030_CED)?1:0, + (regs.cacr & CACR030_FD )?1:0, + (regs.cacr & CACR030_ED )?1:0, + (regs.cacr & CACR030_IBE)?1:0, + (regs.cacr & CACR030_CI )?1:0, + (regs.cacr & CACR030_CEI)?1:0, + (regs.cacr & CACR030_FI )?1:0, + (regs.cacr & CACR030_EI )?1:0 + ); + }*/ + regs.prefetch020addr = 0xffffffff; + regs.cacheholdingaddr020 = 0xffffffff; + flush_caches(flush); + } + + /*---------------------------------*/ + + function fill_icache020(addr) { + addr = (addr & ~3) >>> 0; + if (regs.cacheholdingaddr020 != addr) { + var index = (addr >>> 2) & CACHELINE020_IM; + var tag = ((addr & CACHELINE020_TM) | (regs.s ? 1 : 0)) >>> 0; + var c = caches020[index]; + if (c.valid && c.tag == tag) { + // cache hit + regs.cacheholdingaddr020 = addr; + regs.cacheholdingdata020 = c.data; + } else { + // cache miss + //var data = SAER_Memory_getInst32(addr); + var data = SAER_Memory_banks[addr >>> 16].getInst32(addr); + if (!(regs.cacr & CACR020_F)) { + c.tag = tag; + c.valid = (regs.cacr & CACR020_E) != 0; + c.data = data; + } + regs.cacheholdingaddr020 = addr; + regs.cacheholdingdata020 = data; + } + } + } + + /*---------------------------------*/ + + function getcache030(cp, addr, p) { + addr = (addr & ~3) >>> 0; + var index = (addr >>> 4) & CACHELINE030_IM; + p.tag = ((addr & CACHELINE030_TM) | (regs.s ? 1 : 0)) >>> 0; + p.lws = (addr >>> 2) & 3; + return cp[index]; + } + function update_cache030(c, val, tag, lws) { + if (c.tag != tag) + c.valid[0] = c.valid[1] = c.valid[2] = c.valid[3] = false; + c.tag = tag; + c.valid[lws] = true; + c.data[lws] = val; + } + + function fill_icache030(addr) { + addr = (addr & ~3) >>> 0; + if (regs.cacheholdingaddr020 == addr) + return; + var p = {}; + var c = getcache030(icaches030, addr, p); + if (c.valid[p.lws] && c.tag == p.tag) { + // cache hit + regs.cacheholdingaddr020 = addr; + regs.cacheholdingdata020 = c.data[p.lws]; + return; + } + // cache miss + //var data = SAER_Memory_getInst32(addr); + var data = SAER_Memory_banks[addr >>> 16].getInst32(addr); + if ((regs.cacr & (CACR030_FI|CACR030_EI)) == CACR030_EI) // not frozen and enabled + update_cache030(c, data, p.tag, p.lws); + + // do burst fetch if cache enabled, not frozen, all slots invalid, no chip ram + if ((regs.cacr & (CACR030_IBE|CACR030_EI)) == (CACR030_IBE|CACR030_EI) && p.lws == 0 && + !c.valid[1] && !c.valid[2] && !c.valid[3] && + SAER_Memory_banktype[addr >>> 16] == SAEC_Memory_banktype_FAST32 + ) { + /*c.data[1] = SAER_Memory_getInst32(addr + 4); + c.data[2] = SAER_Memory_getInst32(addr + 8); + c.data[3] = SAER_Memory_getInst32(addr + 12);*/ + c.data[1] = SAER_Memory_banks[(addr + 4) >>> 16].getInst32(addr + 4); + c.data[2] = SAER_Memory_banks[(addr + 8) >>> 16].getInst32(addr + 8); + c.data[3] = SAER_Memory_banks[(addr + 12) >>> 16].getInst32(addr + 12); + c.valid[1] = c.valid[2] = c.valid[3] = true; + } + regs.cacheholdingaddr020 = addr; + regs.cacheholdingdata020 = data; + } + /*function get16_icache030(addr) { //get_word_icache030() + fill_icache030(addr); + if (addr & 2) + return regs.cacheholdingdata020 & 0xffff; + else + return regs.cacheholdingdata020 >>> 16; + } + function get32_icache030(addr) { //get_long_icache030() + fill_icache030(addr); + if ((addr & 2) == 0) + return regs.cacheholdingdata020; + else { + var v = regs.cacheholdingdata020 << 16; + fill_icache030(addr + 4); + v |= regs.cacheholdingdata020 >>> 16; + return v >>> 0; + } + }*/ + + function read_dcache030x(addr, size) { + var aligned = addr & 3; + var v1, v2; + + var p1 = {}; + var c1 = getcache030(dcaches030, addr, p1); + addr = (addr & ~3) >>> 0; + if (!c1.valid[p1.lws] || c1.tag != p1.tag) { + v1 = SAER_Memory_get32(addr); + update_cache030(c1, v1, p1.tag, p1.lws); + } else { + v1 = c1.data[p1.lws]; + if (SAEV_AutoConf_boot_rom_type > 0) { + var tv = SAER_Memory_get32(addr); + if (tv != v1) { + SAEF_warn("cpu.read_dcache030x() data cache mismatch %d %d %08x %08x != %08x %08x %d PC=%08x", size, aligned, addr, tv, v1, p1.tag, p1.lws, getPC()); + v1 = tv; + } + } + } + // only one long fetch needed? + if (size == 0) { + v1 >>>= (3 - aligned) * 8; + return v1 & 0xff; + } else if (size == 1 && aligned <= 2) { + v1 >>>= (2 - aligned) * 8; + return v1 & 0xffff; + } else if (size == 2 && aligned == 0) { + // do burst fetch if cache enabled, not frozen, all slots invalid, no chip ram + if ((regs.cacr & (CACR030_DBE|CACR030_ED)) == (CACR030_DBE|CACR030_ED) && p1.lws == 0 && + !c1.valid[1] && !c1.valid[2] && !c1.valid[3] && + SAER_Memory_banktype[addr >> 16] == SAEC_Memory_banktype_FAST32 + ) { + c1.data[1] = SAER_Memory_get32(addr + 4); + c1.data[2] = SAER_Memory_get32(addr + 8); + c1.data[3] = SAER_Memory_get32(addr + 12); + c1.valid[1] = c1.valid[2] = c1.valid[3] = true; + } + return v1 >>> 0; + } + // no, need another one + addr += 4; + var p2 = {}; + var c2 = getcache030(dcaches030, addr, p2); + if (!c2.valid[p2.lws] || c2.tag != p2.tag) { + v2 = SAER_Memory_get32(addr); + update_cache030(c2, v2, p2.tag, p2.lws); + } else { + v2 = c2.data[p2.lws]; + if (SAEV_AutoConf_boot_rom_type > 0) { + var tv = SAER_Memory_get32(addr); + if (tv != v2) { + SAEF_warn("cpu.read_dcache030x() data cache mismatch %d %d %08x %08x != %08x %08x %d PC=%08x", size, aligned, addr, tv, v2, p2.tag, p2.lws, getPC()); + v2 = tv; + } + } + } + if (size == 1 && aligned == 3) + return ((v1 << 8) | (v2 >>> 24)) & 0xffff; + else if (size == 2 && aligned == 1) + return ((v1 << 8) | (v2 >>> 24)) >>> 0; + else if (size == 2 && aligned == 2) + return ((v1 << 16) | (v2 >>> 16)) >>> 0; + else if (size == 2 && aligned == 3) + return ((v1 << 24) | (v2 >>> 8)) >>> 0; + + SAEF_warn("cpu.read_dcache030x() weirdness!?"); + return 0; + } + + function write_dcache030x(addr, val, size) { + var aligned = addr & 3; + var wa = (regs.cacr & CACR030_WA) != 0; + + var p1 = {}; + var c1 = getcache030(dcaches030, addr, p1); + + // easy one + if (size == 2 && aligned == 0 && wa) { + update_cache030(c1, val, p1.tag, p1.lws); + return; + } + + var hit = (c1.tag == p1.tag && c1.valid[p1.lws]); + if (hit || wa) { + if (size == 2) { + if (hit) { + c1.data[p1.lws] &= ~(0xffffffff >>> (aligned * 8)); + c1.data[p1.lws] |= val >>> (aligned * 8); + } else + c1.valid[p1.lws] = false; + } else if (size == 1) { + if (hit) { + c1.data[p1.lws] &= ~(0xffff0000 >>> (aligned * 8)); + c1.data[p1.lws] |= (val << 16) >>> (aligned * 8); + } else + c1.valid[p1.lws] = false; + } else if (size == 0) { + if (hit) { + c1.data[p1.lws] &= ~(0xff000000 >>> (aligned * 8)); + c1.data[p1.lws] |= (val << 24) >>> (aligned * 8); + } else + c1.valid[p1.lws] = false; + } + } + + // do we need to update a 2nd cache entry ? + if ((size == 0) || (size == 1 && aligned <= 2) || (size == 2 && aligned == 0)) + return; + + var p2 = {}; + var c2 = getcache030(dcaches030, addr + 4, p2); + hit = (c2.tag == p2.tag && c2.valid[p2.lws]); + if (hit || wa) { + if (size == 2) { + if (hit) { + c2.data[p2.lws] &= 0xffffffff >>> (aligned * 8); + c2.data[p2.lws] |= val << ((4 - aligned) * 8); + } else + c2.valid[p2.lws] = false; + } else if (size == 1) { + if (hit) { + c2.data[p2.lws] &= 0x00ffffff; + c2.data[p2.lws] |= val << 24; + } else + c2.valid[p2.lws] = false; + } + } + } + + function cancache030(addr) { + return SAER_Memory_cachable[addr >>> 16] != 0; + } + + function read_dcache030(addr, size) { + if ((regs.cacr & CACR030_ED) && cancache030(addr)) + return read_dcache030x(addr, size); + + if (size == 2) + return SAER_Memory_get32(addr); + else if (size == 1) + return SAER_Memory_get16(addr); + else + return SAER_Memory_get8(addr); + } + function get32_dcache030(addr) { //get_long_030() + return read_dcache030(addr, 2); + } + function get16_dcache030(addr) { //get_word_030() + return read_dcache030(addr, 1); + } + function get8_dcache030(addr) { //get_byte_030() + return read_dcache030(addr, 0); + } + + function write_dcache030(addr, v, size) { + if ((regs.cacr & CACR030_ED) && cancache030(addr)) + write_dcache030x(addr, v, size); + + if (size == 2) + SAER_Memory_put32(addr, v); + else if (size == 1) + SAER_Memory_put16(addr, v); + else + SAER_Memory_put8(addr, v); + } + function put32_dcache030(addr, v) { //put_long_030() + write_dcache030(addr, v, 2); + } + function put16_dcache030(addr, v) { //put_word_030() + write_dcache030(addr, v, 1); + } + function put8_dcache030(addr, v) { //put_byte_030() + write_dcache030(addr, v, 0); + } + + /*---------------------------------*/ + /* prefetch */ + + function getInst16_icache020_prefetch(o) { //get_word_020_prefetch() + var pc = getPC() + o; + var v; + + if (pc & 2) { + v = regs.prefetch020[0] & 0xffff; + regs.prefetch020[0] = regs.prefetch020[1]; + fill_icache020(pc + 2 + 4); + regs.prefetch020[1] = regs.cacheholdingdata020; + + regs.db = regs.prefetch020[0] >>> 16; + } else { + v = regs.prefetch020[0] >>> 16; + regs.db = regs.prefetch020[0]; + } + return v; + } + function getInst32_icache020_prefetch(o) { //get_long_020_prefetch() + return ((getInst16_icache020_prefetch(o) << 16) | getInst16_icache020_prefetch(o + 2)) >>> 0; + } + + function getInst16_icache030_prefetch(o) { //get_word_030_prefetch() + var pc = getPC() + o; + var v; + + if (pc & 2) { + v = regs.prefetch020[0] & 0xffff; + regs.prefetch020[0] = regs.prefetch020[1]; + fill_icache030(pc + 2 + 4); + regs.prefetch020[1] = regs.cacheholdingdata020; + } else + v = regs.prefetch020[0] >>> 16; + + return v; + } + function getInst32_icache030_prefetch(o) { //get_long_030_prefetch() + return ((getInst16_icache030_prefetch(o) << 16) | getInst16_icache030_prefetch(o + 2)) >>> 0; + } + + + function fill_prefetch_020() { + var pc = (getPC() & ~3) >>> 0; + + fill_icache020(pc); + regs.prefetch020[0] = regs.cacheholdingdata020; + fill_icache020(pc + 4); + regs.prefetch020[1] = regs.cacheholdingdata020; + + regs.irc = getInst16_icache020_prefetch(0); + } + function fill_prefetch_030() { + var pc = (getPC() & ~3) >>> 0; + + fill_icache030(pc); + regs.prefetch020[0] = regs.cacheholdingdata020; + fill_icache030(pc + 4); + regs.prefetch020[1] = regs.cacheholdingdata020; + + regs.irc = getInst16_icache030_prefetch(0); + } + function fill_prefetch() { + //regs.pipeline_pos = 0; + if (!SAEV_config.cpu.compatible) + return; + /*if (SAEV_config.cpu.model >= SAEC_Config_CPU_Model_68040) { + if (SAEV_config.cpu.compatible || currprefs.cpu_memory_cycle_exact) { + fill_icache040(getPC() + 16); + fill_icache040(getPC()); + } + } else*/ + if (SAEV_config.cpu.model == SAEC_Config_CPU_Model_68030) + fill_prefetch_030(); + else if (SAEV_config.cpu.model == SAEC_Config_CPU_Model_68020) + fill_prefetch_020(); + else if (SAEV_config.cpu.model <= SAEC_Config_CPU_Model_68010) { + var pc = getPC(); + //regs.ir = SAER_Memory_getInst16(pc); + //regs.irc = SAER_Memory_getInst16(pc + 2); + regs.ir = SAER_Memory_banks[pc >>> 16].getInst16(pc); + regs.irc = SAER_Memory_banks[(pc + 2) >>> 16].getInst16(pc + 2); + + } + } + SAER_CPU_fill_prefetch = fill_prefetch; + + /*-----------------------------------------------------------------------*/ + /* PC direct (regs.pc_p) access */ + + function setPC(newpc) { //m68k_setpc() + regs.instruction_pc = regs.pc = newpc; + regs.pc_p = regs.pc_oldp = newpc; + } + SAER_CPU_setPC = setPC; + + function getPC() { //m68k_getpc() + return regs.pc + (regs.pc_p - regs.pc_oldp); + } + SAER_CPU_getPC = getPC; + + function incPC(o) { //m68k_incpc() + regs.pc_p += o; + } + + function syncPC() { + setPC(getPC()); + } + + /*function setPC_default(pc) { + setPC(pc); + pc_offset = PC_OFFSET; + } + function getPC_default() { + return getPC() + pc_offset; + } + function syncPC_default() { + //pc_offset_old = pc_offset; + incPC(pc_offset); + pc_offset = PC_OFFSET; + } + function syncPC_default_noreset() { //sync_m68k_pc_noreset() + coreSyncPC(); + pc_offset = pc_offset_old; + } + function clrPC_default() { //clear_m68k_offset() + pc_offset = 0; + }*/ + + /*---------------------------------*/ + /* PC indirect (regs.pc) access */ + + function setPCi(newpc) { //m68k_setpci() + regs.instruction_pc = regs.pc = newpc; + } + function getPCi() { //m68k_getpci() + return regs.pc; + } + function incPCi(o) { //m68k_incpci() + regs.pc += o; + } + //function syncPCi() {} + + function getPC_prefetch() { + return getPCi() + pc_offset; + } + function setPC_prefetch(pc) { + setPCi(pc); + pc_offset = PC_OFFSET; + fill_prefetch(); + } + function syncPC_prefetch() { + //pc_offset_old = pc_offset; + incPCi(pc_offset); + pc_offset = PC_OFFSET; + regs.ir = getInst16_prefetch(2); + } + function syncPC_icache020_prefetch() { + //pc_offset_old = pc_offset; + incPCi(pc_offset); + pc_offset = PC_OFFSET; + regs.irc = getInst16_icache020_prefetch(0); + } + function syncPC_icache030_prefetch() { + //pc_offset_old = pc_offset; + incPCi(pc_offset); + pc_offset = PC_OFFSET; + regs.irc = getInst16_icache030_prefetch(0); + } + + /*-----------------------------------------------------------------------*/ + /* PC common access */ + + this.setPC_normal = function(pc) { //m68k_setpc_normal() + if (SAEV_config.cpu.compatible) { + regs.pc_p = regs.pc_oldp = 0; + setPCi(pc); + } else + setPC(pc); + } + + this.getPC_normal = function() { //m68k_getpc_normal() + if (SAEV_config.cpu.compatible) + return getPCi(); + else + return getPC(); + } + + this.incPC_normal = function(o) { //m68k_incpc_normal() + if (SAEV_config.cpu.compatible) + incPCi(o); + else + incPC(o); + } + + /*-----------------------------------------------------------------------*/ + /* next instruction direct (regs.pc_p) */ + + function nextInst16_default() { //next_diword() + //var r = SAER_Memory_getInst16(regs.pc_p); + var r = SAER_Memory_banks[regs.pc_p >>> 16].getInst16(regs.pc_p); + regs.pc_p += 2; //incPC(2); + return r; + } + function nextInst32_default() { //next_dilong() + //var r = SAER_Memory_getInst32(regs.pc_p); + var r = SAER_Memory_banks[regs.pc_p >>> 16].getInst32(regs.pc_p); + regs.pc_p += 4; //incPC(4); + return r; + } + /*function nextInst16_default() { + var r = pc_offset; + pc_offset += 2; + return SAER_Memory_getInst16(regs.pc_p + r); + } + function nextInst32_default() { + var r = pc_offset; + pc_offset += 4; + return SAER_Memory_getInst32(regs.pc_p + r); + }*/ + + + function getInst16_default(o) { //get_diword() + //return SAER_Memory_getInst16(regs.pc_p + o); + return SAER_Memory_banks[(regs.pc_p + o) >>> 16].getInst16(regs.pc_p + o); + } + function getInst32_default(o) { //get_dilong() + //return SAER_Memory_getInst32(regs.pc_p + o); + return SAER_Memory_banks[(regs.pc_p + o) >>> 16].getInst32(regs.pc_p + o); + } + + /*function m68k_do_bsr(oldpc, offset) { + regs.a[7] -= 4; + SAER_Memory_put32(regs.a[7], oldpc); + incPC(offset); + } + function m68k_do_rts() { + uae_u32 newpc = SAER_Memory_get32(regs.a[7]); + setPC(newpc); + regs.a[7] += 4; + }*/ + + /*-----------------------------------------------------------------------*/ + /* next instruction indirect (regs.pc) */ + + /*function next_iibyte() { + var r = get_iibyte(0); + incPCi(2); + return r; + } + function next_iiword() { + var r = get_iiword(0); + incPCi(2); + return r; + } + function next_iilong() { + var r = get_iilong(0); + incPCi(4); + return r; + } + function next_iiwordi() { + var r = SAER_Memory_getInst16(getPCi()); + incPCi(2); + return r; + } + function next_iilongi() { + var r = SAER_Memory_getInst32(getPCi()); + incPCi(4); + return r; + } + + function get_iibyte(o) { + return SAER_Memory_getInst16(getPCi() + o) & 0xff; + } + function get_iiword(o) { + return SAER_Memory_getInst16(getPCi() + o); + } + function get_iilong(o) { + return SAER_Memory_getInst32(getPCi() + o); + } + + function void m68k_do_bsri(oldpc, offset) { + regs.a[7] -= 4; + SAER_Memory_put32(regs.a[7], oldpc); + incPCi(offset); + } + function void m68k_do_rtsi() { + uae_u32 newpc = SAER_Memory_get32(regs.a[7]); + setPCi(newpc); + regs.a[7] += 4; + }*/ + + /*-----------------------------------------------------------------------*/ + /* 68000/68010 prefetch */ + + function getInst16_prefetch(o) { //get_word_000_prefetch() + var v = regs.irc; + //regs.irc = regs.db = SAER_Memory_getInst16(getPCi() + o); + //regs.irc = regs.db = SAER_Memory_getInst16(regs.pc + o); + regs.irc = regs.db = SAER_Memory_banks[(regs.pc + o) >>> 16].getInst16(regs.pc + o); + return v; + } + function getInst32_prefetch(o) { //get_long_000_prefetch() + return ((getInst16_prefetch(o) << 16) | getInst16_prefetch(o + 2)) >>> 0; + } + + /*function nextInst16_prefetch() { //OWN + var r = getInst16_prefetch(0); + incPCi(2); + return r; + } + function nextInst32_prefetch() { //OWN + return ((nextInst16_prefetch() << 16) | nextInst16_prefetch()) >>> 0; + }*/ + function nextInst16_prefetch() { + var r = pc_offset; + pc_offset += 2; + return getInst16_prefetch(r + 2); + } + function nextInst32_prefetch() { + var r = pc_offset; + pc_offset += 4; + return getInst32_prefetch(r + 2); + } + + function get8_prefetch(addr) { //get_byte_000() + var v = SAER_Memory_get8(addr); + regs.db = (v << 8) | v; + return v; + } + function get16_prefetch(addr) { //get_word_000() + var v = SAER_Memory_get16(addr); + regs.db = v; + return v; + } + function get32_prefetch(addr) { //OWN + return ((get16_prefetch(addr) << 16) | get16_prefetch(addr + 2)) >>> 0; + } + + function put8_prefetch(addr, v) { //put_byte_000() + regs.db = (v << 8) | v; + SAER_Memory_put8(addr, v); + } + function put16_prefetch(addr, v) { //put_word_000() + regs.db = v; + SAER_Memory_put16(addr, v); + } + function put32_prefetch(addr, v) { //OWN + put16_prefetch(addr, v >>> 16); + put16_prefetch(addr + 2, v & 0xffff); + } + + /*---------------------------------*/ + /* 68020 prefetch */ + + /*function nextInst16_icache020_prefetch() { //next_iword_020_prefetch() + var r = getInst16_icache020_prefetch(0); + incPCi(2); + return r; + } + function nextInst32_icache020_prefetch() { //next_ilong_020_prefetch() + return ((nextInst16_icache020_prefetch() << 16) | nextInst16_icache020_prefetch()) >>> 0; + }*/ + function nextInst16_icache020_prefetch() { + var r = pc_offset; + pc_offset += 2; + return getInst16_icache020_prefetch(r); + } + function nextInst32_icache020_prefetch() { + var r = pc_offset; + pc_offset += 4; + return getInst32_icache020_prefetch(r); + } + + /*---------------------------------*/ + /* 68030 prefetch */ + + /*function nextInst16_icache030_prefetch() { //next_iword_030_prefetch() + var r = getInst16_icache030_prefetch(0); + incPCi(2); + return r; + } + function nextInst32_icache030_prefetch() { //next_ilong_030_prefetch() + var r = getInst32_icache030_prefetch(0); + incPCi(4); + return r; + }*/ + function nextInst16_icache030_prefetch() { + var r = pc_offset; + pc_offset += 2; + return getInst16_icache030_prefetch(r); + } + function nextInst32_icache030_prefetch() { + var r = pc_offset; + pc_offset += 4; + return getInst32_icache030_prefetch(r); + } + + /*function m68k_do_bsr_030(oldpc, offset) { + regs.a[7] -= 4; + dcachePut32(regs.a[7], oldpc); + incPCi(offset); + } + function m68k_do_rts_030() { + setPC(dcacheGet32(regs.a[7])); + regs.a[7] += 4; + }*/ + + /*---------------------------------*/ + + function setup_functions() { + if (SAEV_config.cpu.compatible) { + coreGetPC = getPC_prefetch; + coreSetPC = setPC_prefetch; + + if (SAEV_config.cpu.model < SAEC_Config_CPU_Model_68020) { + coreSyncPC = syncPC_prefetch; + coreNext16 = nextInst16_prefetch; + coreNext32 = nextInst32_prefetch; + coreGetInst16 = getInst16_prefetch; + coreGetInst32 = getInst32_prefetch; + coreGet8 = get8_prefetch; + coreGet16 = get16_prefetch; + coreGet32 = get32_prefetch; + corePut8 = put8_prefetch; + corePut16 = put16_prefetch; + corePut32 = put32_prefetch; + } else if (SAEV_config.cpu.model == SAEC_Config_CPU_Model_68020) { + coreSyncPC = syncPC_icache020_prefetch; + coreNext16 = nextInst16_icache020_prefetch; + coreNext32 = nextInst32_icache020_prefetch; + coreGetInst16 = getInst16_icache020_prefetch; + coreGetInst32 = getInst32_icache020_prefetch; + coreGet32 = SAER_Memory_get32; + corePut32 = SAER_Memory_put32; + coreGet16 = SAER_Memory_get16; + corePut16 = SAER_Memory_put16; + coreGet8 = SAER_Memory_get8; + corePut8 = SAER_Memory_put8; + } else if (SAEV_config.cpu.model == SAEC_Config_CPU_Model_68030) { + coreSyncPC = syncPC_icache030_prefetch; + coreNext16 = nextInst16_icache030_prefetch; + coreNext32 = nextInst32_icache030_prefetch; + coreGetInst32 = getInst32_icache030_prefetch; + coreGetInst16 = getInst16_icache030_prefetch; + coreGet8 = get8_dcache030; + coreGet16 = get16_dcache030; + coreGet32 = get32_dcache030; + corePut8 = put8_dcache030; + corePut16 = put16_dcache030; + corePut32 = put32_dcache030; + } + } else { + //coreGetPC = getPC_default; + //coreSetPC = setPC_default; + //coreSyncPC = syncPC_default; + coreGetPC = getPC; + coreSetPC = setPC; + coreSyncPC = syncPC; + coreNext16 = nextInst16_default; + coreNext32 = nextInst32_default; + coreGetInst32 = getInst32_default; + coreGetInst16 = getInst16_default; + coreGet32 = SAER_Memory_get32; + corePut32 = SAER_Memory_put32; + coreGet16 = SAER_Memory_get16; + corePut16 = SAER_Memory_put16; + coreGet8 = SAER_Memory_get8; + corePut8 = SAER_Memory_put8; + } + } + + /*-----------------------------------------------------------------------*/ + + function coreReset() { + SAER.m68k.cpureset(); + } + + function coreStop() { + SAER.m68k.m68k_setstopped(); + } + + /*-----------------------------------------------------------------------*/ + + function coreGetCCR() { + return (((regs.x ? 1 : 0) << 4) | ((regs.n ? 1 : 0) << 3) | ((regs.z ? 1 : 0) << 2) | ((regs.v ? 1 : 0) << 1) | (regs.c ? 1 : 0)); + } + function coreSetCCR(ccr) { + regs.x = ((ccr >> 4) & 1) == 1; + regs.n = ((ccr >> 3) & 1) == 1; + regs.z = ((ccr >> 2) & 1) == 1; + regs.v = ((ccr >> 1) & 1) == 1; + regs.c = (ccr & 1) == 1; + } + + /*-----------------------------------------------------------------------*/ + + function coreGetSR() { + return ( + ((regs.t1 ? 1 : 0) << 15) | ((regs.t0 ? 1 : 0) << 14) | + ((regs.s ? 1 : 0) << 13) | ((regs.m ? 1 : 0) << 12) | (regs.intmask << 8) | + ((regs.x ? 1 : 0) << 4) | ((regs.n ? 1 : 0) << 3) | ((regs.z ? 1 : 0) << 2) | ((regs.v ? 1 : 0) << 1) | (regs.c ? 1 : 0) + ); + } + function coreSetSR(sr) { + var oldm = regs.m; + var olds = regs.s; + + regs.x = ((sr >> 4) & 1) == 1; + regs.n = ((sr >> 3) & 1) == 1; + regs.z = ((sr >> 2) & 1) == 1; + regs.v = ((sr >> 1) & 1) == 1; + regs.c = (sr & 1) == 1; + + var t1 = ((sr >> 15) & 1) == 1; + var t0 = ((sr >> 14) & 1) == 1; + var s = ((sr >> 13) & 1) == 1; + var m = ((sr >> 12) & 1) == 1; + var intmask = ((sr >> 8) & 7); + if (regs.t1 == t1 && regs.t0 == t0 && regs.s == s && regs.m == m && regs.intmask == intmask) { + //SAEF_log("cpu.coreSetSR() mode ok!"); + return; + } + regs.t1 = t1; + regs.t0 = t0; + regs.s = s; + regs.m = m; + regs.intmask = intmask; + + if (SAEV_config.cpu.model >= SAEC_Config_CPU_Model_68020) { + if (olds != regs.s) { + if (olds) { + if (oldm) + regs.msp = regs.a[7]; + else + regs.isp = regs.a[7]; + regs.a[7] = regs.usp; + } else { + regs.usp = regs.a[7]; + regs.a[7] = regs.m ? regs.msp : regs.isp; + } + } else if (olds && oldm != regs.m) { + if (oldm) { + regs.msp = regs.a[7]; + regs.a[7] = regs.isp; + } else { + regs.isp = regs.a[7]; + regs.a[7] = regs.msp; + } + } + } else { + regs.t0 = regs.m = 0; + if (olds != regs.s) { + if (olds) { + regs.isp = regs.a[7]; + regs.a[7] = regs.usp; + } else { + regs.usp = regs.a[7]; + regs.a[7] = regs.isp; + } + } + } + + SAER.m68k.doint_trace(regs.t1 || regs.t0); /*{ + if (regs.t1 || regs.t0) + SAEF_setSpcFlags(SAEC_spcflag_TRACE); + else + SAEF_clrSpcFlags(SAEC_spcflag_TRACE); + }*/ + } + + /*-----------------------------------------------------------------------*/ + /* exception */ + + function exception_trace(nr) { + SAEF_clrSpcFlags(SAEC_spcflag_TRACE | SAEC_spcflag_DOTRACE); + if (regs.t1 && !regs.t0) { + if (nr == 5 || nr == 6 || nr == 7 || (nr >= 32 && nr <= 47)) + SAEF_setSpcFlags(SAEC_spcflag_DOTRACE); + } + regs.t1 = regs.t0 = regs.m = false; + } + + function exception_pc(nr) { + // bus error, address error, illegal instruction, privilege violation, a-line, f-line + if (nr == 2 || nr == 3 || nr == 4 || nr == 8 || nr == 10 || nr == 11) + return regs.instruction_pc; + return getPC(); + } + + function add_approximate_exception_cycles(nr) { + var cycles; + + if (SAEV_config.cpu.model > SAEC_Config_CPU_Model_68000) + return; + + if (nr >= 24 && nr <= 31) { + /* Interrupts */ + cycles = 44 + 4; + } else if (nr >= 32 && nr <= 47) { + /* Trap (total is 34, but cpuemux.c already adds 4) */ + cycles = 34; //- 4; + } else { + switch (nr) { + case 2: cycles = 50; break; /* Bus error */ + case 3: cycles = 50; break; /* Address error */ + case 4: cycles = 34; break; /* Illegal instruction */ + case 5: cycles = 38; break; /* Division by zero */ + case 6: cycles = 40; break; /* CHK */ + case 7: cycles = 34; break; /* TRAPV */ + case 8: cycles = 34; break; /* Privilege violation */ + case 9: cycles = 34; break; /* Trace */ + case 10: cycles = 34; break; /* Line-A */ + case 11: cycles = 34; break; /* Line-F */ + default: cycles = 4; + } + } + //SAEF_log("cpu.add_approximate_exception_cycles() nr %d, cycles %d", nr, cycles); + //cycles = cycles * cpucycleunit; + //cycles = adjust_cycles(cycles * SAEC_Events_CYCLE_UNIT / 2); + cycles = adjust_cycles((cycles * SAEC_Events_CYCLE_UNIT) >> 1); + SAER.events.do_cycles(cycles); + } + + function add_approximate_exception_cycles_020(nr) { //OWN + var cycles; + + if (nr >= 24 && nr <= 31) { + /* Interrupts */ + cycles = regs.m ? 41 : 26; + } else if (nr >= 32 && nr <= 47) { + /* Trap */ + cycles = 20; + } else { + switch (nr) { + case 2: cycles = 50; break; /* Bus error */ + case 3: cycles = 50; break; /* Address error */ + case 4: cycles = 20; break; /* Illegal instruction */ + case 5: cycles = 20; break; /* Division by zero */ + case 6: cycles = 20; break; /* CHK */ + case 7: cycles = 23; break; /* TRAPV */ + case 8: cycles = 20; break; /* Privilege violation */ + case 9: cycles = 25; break; /* Trace */ + case 10: cycles = 20; break; /* Line-A */ + case 11: cycles = 20; break; /* Line-F */ + default: cycles = 4; + } + } + //SAEF_log("cpu.add_approximate_exception_cycles_020() nr %d, cycles %d", nr, cycles); + cycles = cycles * cpucycleunit; + SAER.events.do_cycles(cycles); + } + + function exception(nr) { + var currpc; + var sv = regs.s; + var vector_nr = nr; + var kludge_me_do = true; + + var interrupt = nr >= 24 && nr < 24 + 8; + + if (interrupt && SAEV_config.cpu.model <= SAEC_Config_CPU_Model_68010) + vector_nr = coreGet8(0x00fffff1 | ((nr - 24) << 1)); + + var sr = coreGetSR(); + + if (!regs.s) { + regs.usp = regs.a[7]; + if (SAEV_config.cpu.model >= SAEC_Config_CPU_Model_68020) { + regs.a[7] = regs.m ? regs.msp : regs.isp; + } else { + regs.a[7] = regs.isp; + } + regs.s = true; + } + + if ((regs.a[7] & 1) && SAEV_config.cpu.model < SAEC_Config_CPU_Model_68020) { + if (nr == 2 || nr == 3) + SAER.m68k.cpu_halt(SAEC_CPU_halt_DOUBLE_FAULT); + else + exception3_notinstruction(regs.ir, regs.a[7]); + return; + } + if ((nr == 2 || nr == 3) && exception_in_exception < 0) { + SAER.m68k.cpu_halt(SAEC_CPU_halt_DOUBLE_FAULT); + return; + } + + if (SAEV_config.cpu.model > SAEC_Config_CPU_Model_68000) { + /*if (SAEV_config.cpu.model >= SAEC_Config_CPU_Model_68020) //OWN + add_approximate_exception_cycles_020(nr); + else + add_approximate_exception_cycles(nr);*/ + + currpc = exception_pc(nr); + if (nr == 2 || nr == 3) { + var ssw = (sv ? 4 : 0) | (last_instructionaccess_for_exception_3 ? 2 : 1); + ssw |= last_writeaccess_for_exception_3 ? 0 : 0x40; + ssw |= 0x20; + /*for (var i = 0 ; i < 36; i++) { + regs.a[7] -= 2; corePut16(regs.a[7], 0); + } + regs.a[7] -= 4; corePut32(regs.a[7], last_fault_for_exception_3); + regs.a[7] -= 2; corePut16(regs.a[7], 0); + regs.a[7] -= 2; corePut16(regs.a[7], 0); + regs.a[7] -= 2; corePut16(regs.a[7], 0); + regs.a[7] -= 2; corePut16(regs.a[7], ssw); + regs.a[7] -= 2; corePut16(regs.a[7], 0xb000 + vector_nr * 4);*/ + + for (var i = 0 ; i < 36; i++) stackPut16(0); + stackPut32(last_fault_for_exception_3); + stackPut16(0); + stackPut16(0); + stackPut16(0); + stackPut16(ssw); + stackPut16(0xb000 + vector_nr * 4); + + SAEF_log("cpu.exception() %d (%x) at %x -> %x!", nr, regs.instruction_pc, currpc, SAER_Memory_get32(regs.vbr + 4 * vector_nr)); + } else if (nr == 5 || nr == 6 || nr == 7 || nr == 9) { + //regs.a[7] -= 4; corePut32(regs.a[7], regs.instruction_pc); + //regs.a[7] -= 2; corePut16(regs.a[7], 0x2000 + vector_nr * 4); + stackPut32(regs.instruction_pc); + stackPut16(0x2000 + vector_nr * 4); + } else if (regs.m && interrupt) { // M + Interrupt + //regs.a[7] -= 2; corePut16(regs.a[7], vector_nr * 4); + //regs.a[7] -= 4; corePut32(regs.a[7], currpc); + //regs.a[7] -= 2; corePut16(regs.a[7], sr); + stackPut16(vector_nr * 4); + stackPut32(currpc); + stackPut16(sr); + //sr |= (1 << 13); + regs.s = true; + regs.msp = regs.a[7]; + regs.m = false; + regs.a[7] = regs.isp; + //regs.a[7] -= 2; corePut16(regs.a[7], 0x1000 + vector_nr * 4); + stackPut16(0x1000 + vector_nr * 4); + } else { + //regs.a[7] -= 2; corePut16(regs.a[7], vector_nr * 4); + stackPut16(vector_nr * 4); + } + } else { + add_approximate_exception_cycles(nr); + //currpc = getPC(); + currpc = exception_pc(nr); + if (nr == 2 || nr == 3) { + var mode = (sv ? 4 : 0) | (last_instructionaccess_for_exception_3 ? 2 : 1); + mode |= last_writeaccess_for_exception_3 ? 0 : 16; + mode |= last_notinstruction_for_exception_3 ? 8 : 0; + mode |= last_op_for_exception_3 & ~31;// undocumented bits seem to contain opcode + exception_in_exception = -1; + /*regs.a[7] -= 14; + corePut16(regs.a[7] + 0, mode); + corePut32(regs.a[7] + 2, last_fault_for_exception_3); + corePut16(regs.a[7] + 6, last_op_for_exception_3); + corePut16(regs.a[7] + 8, sr); + corePut32(regs.a[7] + 10, last_addr_for_exception_3);*/ + stackPut32(last_addr_for_exception_3); + stackPut16(sr); + stackPut16(last_op_for_exception_3); + stackPut32(last_fault_for_exception_3); + stackPut16(mode); + + SAEF_log("cpu.exception() %d (%x) at %x -> %x!", nr, last_fault_for_exception_3, currpc, SAER_Memory_get32(regs.vbr + 4 * vector_nr)); + //goto kludge_me_do; + kludge_me_do = false; + } //else + //SAEF_log("cpu.exception() %d at %x -> %x!", nr, currpc, SAER_Memory_get32(regs.vbr + 4 * vector_nr)); + } + if (kludge_me_do) { + //regs.a[7] -= 4; corePut32(regs.a[7], currpc); + //regs.a[7] -= 2; corePut16(regs.a[7], sr); + stackPut32(currpc); + stackPut16(sr); + } + //kludge_me_do: + var newpc = coreGet32(regs.vbr + 4 * vector_nr); + //SAEF_log("cpu.exception() %08x -> %08x", currpc, newpc); + exception_in_exception = 0; + if (newpc & 1) { + if (nr == 2 || nr == 3) + SAER.m68k.cpu_halt(SAEC_CPU_halt_DOUBLE_FAULT); + else + exception3_notinstruction(regs.ir, newpc); + return; + } + setPC(newpc); + fill_prefetch(); + exception_trace(nr); + } + SAER_CPU_exception = exception; + function coreException(nr) { + if (!(nr == 2 || nr == 3 || nr == 4 || nr == 8 || nr == 10 || nr == 11)) + coreSyncPC(); + + exception(nr); + return [0,0,0]; + } + + function exception3f(opcode, addr, writeaccess, instructionaccess, notinstruction, pc, plus2) { + if (SAEV_config.cpu.model >= SAEC_Config_CPU_Model_68020) { + if (pc == 0xffffffff) + last_addr_for_exception_3 = regs.instruction_pc; + else + last_addr_for_exception_3 = pc; + } else if (pc == 0xffffffff) { + last_addr_for_exception_3 = getPC(); + if (plus2) + last_addr_for_exception_3 += 2; + } else { + last_addr_for_exception_3 = pc; + } + last_fault_for_exception_3 = addr; + last_op_for_exception_3 = opcode; + last_writeaccess_for_exception_3 = writeaccess; + last_instructionaccess_for_exception_3 = instructionaccess; + last_notinstruction_for_exception_3 = notinstruction; + exception(3); + } + function exception3_notinstruction(opcode, addr) { + exception3f(opcode, addr, true, false, true, 0xffffffff, false); + } + function exception3i(opcode, addr) { + exception3f(opcode, addr, 0, 1, false, 0xffffffff, true); + } + /*this.exception3b = function(opcode, addr, w, i, pc) { + exception3f(opcode, addr, w, i, false, pc, true); + } + this.exception3_read = function(opcode, addr) { + exception3f(opcode, addr, false, 0, false, 0xffffffff, false); + } + this.exception3_write = function(opcode, addr) { + exception3f(opcode, addr, true, 0, false, 0xffffffff, false); + }*/ + function coreException3i(opcode, addr) { + exception3i(opcode, addr) + return [0,0,0]; + } + + this.exception2 = function(addr, read, size, fc) { + last_addr_for_exception_3 = getPC() + bus_error_offset; + last_fault_for_exception_3 = addr; + last_writeaccess_for_exception_3 = read == 0; + last_instructionaccess_for_exception_3 = (fc & 1) == 0; + last_op_for_exception_3 = regs.opcode; + last_notinstruction_for_exception_3 = exception_in_exception != 0; + throw new Exception23(2); + } + + /*-----------------------------------------------------------------------*/ + /* illegal instruction */ + + function munge24(x) { + return (x & (SAEV_config.cpu.addressSpace24 ? 0x00ffffff : 0xffffffff)) >>> 0; + } + function in_rom(pc) { + return (munge24(pc) & 0xFFF80000) >>> 0 == 0xF80000; + } + function in_rtarea(pc) { + return (munge24(pc) & 0xFFFF0000) >>> 0 == SAEV_AutoConf_base && SAEV_AutoConf_boot_rom_type; + } + this.pc_in_rom = function() { /* used in cia.ciab_checkalarm() */ + var pc = getPC(); + return (munge24(pc) & 0xFFF80000) == 0xF80000; + } + + function illegal(opcode) { + var pc = getPC(); + var inrom = in_rom(pc); + var inrt = in_rtarea(pc); + + if (SAEV_Memory_cloantoRom && (opcode & 0xF100) == 0x7100) { + regs.d[(opcode >> 9) & 7] = extByte(opcode & 0xFF); + SAER.cpu.incPC_normal(2); + fill_prefetch(); + return true; + } + + if (opcode == 0x4E7B && inrom) { + if (SAER_Memory_get32(0x10) == 0) { + SAEF_fatal(SAEE_CPU_Requires68020, "The selected kickstart-rom does require a 68020 and 32bit address-space"); + //notify_user (NUMSG_KS68020); + //uae_restart(-1, null); + } + } + + //#ifdef AUTOCONFIG + if (opcode == 0xFF0D && inrt) { + // User-mode STOP replacement + SAEF_log("cpu.illegal() STOP replacement, pc %08x", pc); + m68k_setstopped(); + return true; + } + if ((opcode & 0xF000) == 0xA000 && inrt) { + // Calltrap. + SAEF_log("cpu.illegal() Trap %03X at %08X, call...", opcode & 0xFFF, pc); + SAER.cpu.incPC_normal(2); + SAER.autoconf.m68k_handle_trap(opcode & 0xFFF); + fill_prefetch(); + return true; + } + //#endif + + if ((opcode & 0xF000) == 0xF000) { + if (++illegal_warned < 20) + SAEF_log("cpu.illegal() B-Trap %04X at %08X -> %08X (VBR %08X)", opcode, pc, SAER_Memory_get32(regs.vbr + 0x2c), regs.vbr); + + coreException(0xB); + return false; + } + if ((opcode & 0xF000) == 0xA000) { + if (++illegal_warned < 20) + SAEF_log("cpu.illegal() A-Trap %04X at %08X -> %08X (VBR %08X)", opcode, pc, SAER_Memory_get32(regs.vbr + 0x28), regs.vbr); + + coreException(0xA); + return false; + } + if (++illegal_warned < 20) + SAEF_log("cpu.illegal() op %04x, pc %08x -> %08x", opcode, pc, SAER_Memory_get32(regs.vbr + 0x10)); + + coreException(4); + return false; + } + function coreIllegal(op) { + coreSyncPC(); + if (illegal(op)) + return [4,0,0]; /* no exception */ + else + return [0,0,0]; + } + + /*-----------------------------------------------------------------------*/ + /* core-loop */ + + function update_cycles() { //update_68k_cycles() + cycles_mult = 0; + if (SAEV_config.cpu.speed != SAEC_Config_CPU_Speed_Maximum) { //&& !currprefs.cpu_cycle_exact) { + if (SAEV_config.cpu.speedThrottle < 0.0) + cycles_mult = Math.floor(CYCLES_DIV * 1000 / (1000 + SAEV_config.cpu.speedThrottle)); + else if (SAEV_config.cpu.speedThrottle > 0) + cycles_mult = Math.floor(CYCLES_DIV * 1000 / (1000 + SAEV_config.cpu.speedThrottle)); + } + /*if (SAEV_config.cpu.speed == SAEC_Config_CPU_Speed_Original) { + //if (SAEV_config.cpu.model >= SAEC_Config_CPU_Model_68040) { + if (SAEV_config.cpu.model >= SAEC_Config_CPU_Model_68030) { + if (!cycles_mult) + cycles_mult = CYCLES_DIV / 8; // == 1024 + else + cycles_mult = Math.floor(cycles_mult / 8); + } else if (SAEV_config.cpu.model >= SAEC_Config_CPU_Model_68020) { + if (!cycles_mult) + cycles_mult = CYCLES_DIV / 4; // == 2048 + else + cycles_mult = Math.floor(cycles_mult / 4); + } else { //OWN + if (!cycles_mult) + cycles_mult = CYCLES_DIV / 2; // == 4096 + else + cycles_mult = Math.floor(cycles_mult / 2); + } + }*/ + + cpucycleunit = SAEC_Events_CYCLE_UNIT / 2; + if (SAEV_config.cpu.clock.multiplier) { + if (SAEV_config.cpu.clock.multiplier >= 256) + cpucycleunit = SAEC_Events_CYCLE_UNIT / (SAEV_config.cpu.clock.multiplier >> 8); + else + cpucycleunit = SAEC_Events_CYCLE_UNIT * SAEV_config.cpu.clock.multiplier; + + //if (SAEV_config.cpu.model >= SAEC_Config_CPU_Model_68040) cpucycleunit >>= 1; + } + else if (SAEV_config.cpu.clock.frequency) { + var baseclock = (SAEV_config.chipset.ntsc ? SAEC_Playfield_CLOCK_NTSC : SAEC_Playfield_CLOCK_PAL) * 8; //28 MHz + cpucycleunit = Math.floor(SAEC_Events_CYCLE_UNIT * baseclock / SAEV_config.cpu.clock.frequency); + } + /*else if (currprefs.cpu_cycle_exact && SAEV_config.cpu.clock.multiplier == 0) { + if (SAEV_config.cpu.model >= 68040) + cpucycleunit = SAEC_Events_CYCLE_UNIT / 16; + if (SAEV_config.cpu.model == 68030) + cpucycleunit = SAEC_Events_CYCLE_UNIT / 8; + else if (SAEV_config.cpu.model == 68020) + cpucycleunit = SAEC_Events_CYCLE_UNIT / 4; + else + cpucycleunit = SAEC_Events_CYCLE_UNIT / 2; + }*/ + + if (cpucycleunit < 1) + cpucycleunit = 1; + + SAEF_log("cpu.update_cycles() cycleunit: %d (%.3f), cycles_mult %d", cpucycleunit, cpucycleunit / SAEC_Events_CYCLE_UNIT, cycles_mult); + } + + function adjust_cycles(cycles) { + if (cycles_mult == 0 || SAEV_config.cpu.speed == SAEC_Config_CPU_Speed_Maximum) + return cycles; + /*cycles *= cycles_mult; + cycles /= CYCLES_DIV; + return cycles;*/ + return Math.floor((cycles * cycles_mult) / CYCLES_DIV); + } + + function bus_error() { + SAEF_warn("cpu.bus_error() PC %08x", getPC()); + try { + exception(2); + } catch(e) { + if (e instanceof Exception23) + SAER.m68k.cpu_halt(SAEC_CPU_halt_BUS_ERROR_DOUBLE_FAULT); + else + throw e; + } + } + + function runPrefetch000() { //m68k_run_2p() + var exit = false; + + while (!exit) { + try { + while (!exit) { + regs.instruction_pc = getPC(); + regs.opcode = regs.ir; + + SAER.events.do_cycles(cpu_cycles); + //regs.instruction_pc = getPC(); + + var orw_cycles = iTab[regs.opcode].f(iTab[regs.opcode].p); + cpu_cycles = orw_cycles[0] * cpucycleunit; + //cpu_cycles = adjust_cycles(orw_cycles[0] * cpucycleunit); + SAEV_CPU_cycles = cpu_cycles; + + if (SAEV_spcflags) { + if (SAER.m68k.do_specialties(cpu_cycles)) + exit = true; + } + } + } catch(e) { + if (e instanceof Exception23) { + bus_error(); + if (SAEV_spcflags) { + if (SAER.m68k.do_specialties(cpu_cycles)) + exit = true; + } + } else + throw e; + } + } + } + + function runPrefetch020() { //m68k_run_2p() + var exit = false; + + while (!exit) { + try { + while (!exit) { + regs.instruction_pc = getPC(); + regs.opcode = regs.irc; + + SAER.events.do_cycles(cpu_cycles); + + var orw_cycles = iTab[regs.opcode].f(iTab[regs.opcode].p); + cpu_cycles = orw_cycles[0] * cpucycleunit; + //cpu_cycles = adjust_cycles(orw_cycles[0] * cpucycleunit); + SAEV_CPU_cycles = cpu_cycles; + + if (SAEV_spcflags) { + if (SAER.m68k.do_specialties(cpu_cycles)) + exit = true; + } + } + } catch(e) { + if (e instanceof Exception23) { + bus_error(); + if (SAEV_spcflags) { + if (SAER.m68k.do_specialties(cpu_cycles)) + exit = true; + } + } else + throw e; + } + } + } + + function runNormal() { //m68k_run_2() + var exit = false; + + while (!exit) { + try { + while (!exit) { + regs.instruction_pc = getPC(); + //regs.opcode = getInst16_default(0); + regs.opcode = nextInst16_default(); + SAER.events.do_cycles(cpu_cycles); + var orw_cycles = iTab[regs.opcode].f(iTab[regs.opcode].p); + cpu_cycles = orw_cycles[0] * cpucycleunit; + //cpu_cycles = adjust_cycles(orw_cycles[0] * cpucycleunit); + SAEV_CPU_cycles = cpu_cycles; + + if (SAEV_spcflags) { + if (SAER.m68k.do_specialties(cpu_cycles)) + exit = true; + } + } + } catch(e) { + if (e instanceof Exception23) { + bus_error(); + if (SAEV_spcflags) { + if (SAER.m68k.do_specialties(cpu_cycles)) + exit = true; + } + } else + throw e; + } + } + } + + /*-----------------------------------------------------------------------*/ + /* SECT core support functions, ported from WinUAE */ + /*-----------------------------------------------------------------------*/ + /* MULx/DIVx >= 68020 */ + + function mul64(src1, src2) { + var r0 = (src1 & 0xffff) * (src2 & 0xffff); + var r1 = ((src1 >>> 16) & 0xffff) * (src2 & 0xffff); + var r2 = (src1 & 0xffff) * ((src2 >>> 16) & 0xffff); + var r3 = ((src1 >>> 16) & 0xffff) * ((src2 >>> 16) & 0xffff); + + var lo = r0 + (((r1 << 16) & 0xffff0000) >>> 0); if (lo > 0xffffffff) lo -= 0x100000000; + if (lo < r0) r3++; + r0 = lo; + lo = r0 + (((r2 << 16) & 0xffff0000) >>> 0); if (lo > 0xffffffff) lo -= 0x100000000; + if (lo < r0) r3++; + r3 += ((r1 >>> 16) & 0xffff) + ((r2 >>> 16) & 0xffff); if (r3 > 0xffffffff) r3 -= 0x100000000; + return [lo, r3]; + } + + function divu64(hi, lo, div) { + var i, quo = 0, cbit = false; + if (div <= hi) return [1,0,0]; + + for (i = 0 ; i < 32 ; i++) { + cbit = (hi & 0x80000000) != 0; + hi = (hi << 1) >>> 0; + if (lo & 0x80000000) hi++; + lo = (lo << 1) >>> 0; + quo = (quo << 1) >>> 0; + if (cbit || div <= hi) { + quo = (quo | 1) >>> 0; + hi -= div; + } + } + return [0, quo, hi]; + } + + /*---------------------------------*/ + /* Bitfield >= 68020 */ + + const ID_BFCHG = 1; /* {offset:width} */ + const ID_BFCLR = 2; /* {offset:width} */ + const ID_BFEXTS = 3; /* {offset:width},Dn */ + const ID_BFEXTU = 4; /* {offset:width},Dn */ + const ID_BFFFO = 5; /* {offset:width},Dn */ + const ID_BFINS = 6; /* Dn, {offset:width} */ + const ID_BFSET = 7; /* {offset:width} */ + const ID_BFTST = 8; /* {offset:width} */ + + function bfName(id) { + switch (id) { + case ID_BFCHG: return "BFCHG"; + case ID_BFCLR: return "BFCLR"; + case ID_BFEXTS: return "BFEXTS"; + case ID_BFEXTU: return "BFEXTU"; + case ID_BFFFO: return "BFFFO"; + case ID_BFINS: return "BFINS"; + case ID_BFSET: return "BFSET"; + case ID_BFTST: return "BFTST"; + } + } + + function getBitfield(addr, offset, width) { + var tmp, res, mask; + var data = [0,0]; + + offs = offset & 7; + mask = (0xffffffff << (32 - width)) >>> 0; + + switch ((offs + width + 7) >> 3) { + case 1: + tmp = coreGet8(addr); + res = tmp << (24 + offs); + data[0] = tmp & ~(mask >>> (24 + offs)); + //SAEF_log(("get_bitfield_1 {%d:%d}, data $%08x $%08x, val $%x\n", offset,width, data[0],data[1],res >>> 0)); + break; + case 2: + tmp = coreGet16(addr); + res = tmp << (16 + offs); + data[0] = tmp & ~(mask >>> (16 + offs)); + //SAEF_log(("get_bitfield_2 {%d:%d}, data $%08x $%08x, val $%x\n", offset,width, data[0],data[1],res >>> 0)); + break; + case 3: + tmp = coreGet16(addr); + res = tmp << (16 + offs); + data[0] = tmp & ~(mask >>> (16 + offs)); + tmp = coreGet8(addr + 2); + res |= tmp << (8 + offs); + data[1] = tmp & ~(mask >>> (8 + offs)); + //SAEF_log(("get_bitfield_3 {%d:%d}, data $%08x $%08x, val $%x\n", offset,width, data[0],data[1],res >>> 0)); + break; + case 4: + tmp = coreGet32(addr); + res = tmp << offs; + data[0] = tmp & ~(mask >>> offs); + //SAEF_log(("get_bitfield_4 {%d:%d}, data $%08x $%08x, val $%x\n", offset,width, data[0],data[1],res >>> 0)); + break; + case 5: + tmp = coreGet32(addr); + res = tmp << offs; + data[0] = tmp & ~(mask >>> offs); + tmp = coreGet8(addr + 4); + res |= tmp >> (8 - offs); + data[1] = tmp & ~(mask << (8 - offs)); + //SAEF_log(("get_bitfield_5 {%d:%d}, data $%08x $%08x, val $%x\n", offset,width, data[0],data[1],res >>> 0)); + break; + default: + //SAEF_log(("get_bitfield2() cant happen %d\n", (offs + width + 7) >> 3)); + SAEF_fatal(SAEE_CPU_Internal, "cpu.get_bitfield2() invalid mode (%d)", (offs + width + 7) >> 3); + } + return [res >>> 0, data]; + } + + function putBitfield(addr, offset, width, data, val) { + var out8, out16, out32; + + offs = (offset & 7) + width; + switch ((offs + 7) >> 3) { + case 1: + out8 = ((data[0] | (val << (8 - offs))) >>> 0) & 0xff; + corePut8(addr, out8); //data[0] | (val << (8 - offs))); + //SAEF_log(("put_bitfield_1 {%d:%d}, data $%08x $%08x, val $%x, out8 $%x\n", offset,width, data[0],data[1],val, out8)); + break; + case 2: + out16 = ((data[0] | (val << (16 - offs))) >>> 0) & 0xffff; + corePut16(addr, out16); //data[0] | (val << (16 - offs))); + //SAEF_log(("put_bitfield_2 {%d:%d}, data $%08x $%08x, val $%x, out16 $%x\n", offset,width, data[0],data[1],val, out16)); + break; + case 3: + out16 = ((data[0] | (val >> (offs - 16))) >>> 0) & 0xffff; + out8 = ((data[1] | (val << (24 - offs))) >>> 0) & 0xff; + corePut16(addr, out16); //data[0] | (val >> (offs - 16))); + corePut8(addr + 2, out8); //data[1] | (val << (24 - offs))); + //SAEF_log(("put_bitfield_3 {%d:%d}, data $%08x $%08x, val $%x, out16 $%x out8 $%x\n", offset,width, data[0],data[1],val, out16,out8)); + break; + case 4: + out32 = (data[0] | (val << (32 - offs))) >>> 0; + corePut32(addr, out32); //data[0] | (val << (32 - offs))); + //SAEF_log(("put_bitfield_4 {%d:%d}, data $%08x $%08x, val $%x, out32 $%x\n", offset,width, data[0],data[1],val, out32)); + break; + case 5: + out32 = (data[0] | (val >> (offs - 32))) >>> 0; + out8 = ((data[1] | (val << (40 - offs))) >>> 0) & 0xff; + corePut32(addr, out32); //data[0] | (val >> (offs - 32))); + corePut8(addr + 4, out8); //data[1] | (val << (40 - offs))); + //SAEF_log(("put_bitfield_5 {%d:%d}, data $%08x $%08x, val $%x, out32 $%x out8 $%x\n", offset,width, data[0],data[1],val, out32,out8)); + break; + default: + //SAEF_log(("put_bitfield() cant happen %d\n", (offs + 7) >> 3)); + SAEF_fatal(SAEE_CPU_Internal, "cpu.put_bitfield2() invalid mode (%d)", (offs + 7) >> 3); + } + } + + /*---------------------------------*/ + /* MOVEC >= 68010 */ + + function movecRegName(cr) { + switch (cr) { + //68010/68020/68030/68040 + case 0x000: return "SFC"; //Source Function Code + case 0x001: return "DFC"; //Destination Function Code + case 0x800: return "USP"; //User Stack Pointer + case 0x801: return "VBR"; //Vector Base Register + //68020/68030/68040 + case 0x002: return "CACR"; //Cache Control Register + case 0x802: return "CAAR"; //Cache Address Register + case 0x803: return "MSP"; //Master Stack Pointer + case 0x804: return "ISP"; //Interrupt Stack Pointer + //68040/68LC040 + case 0x003: return "TC"; //MMU Translation Control Register + case 0x004: return "ITT0"; //Instruction Transparent Translation Register 0 + case 0x005: return "ITT1"; //Instruction Transparent Translation Register 1 + case 0x006: return "DTT0"; //Data Transparent Translation Register 0 + case 0x007: return "DTT1"; //Data Transparent Translation Register 1 + case 0x805: return "MMUSR"; //MMU Status Register + case 0x806: return "URP"; //User Root Pointer + case 0x807: return "SRP"; //Supervisor Root Pointer + //68EC040 only + //case 0x004: return "IACR0"; //Instruction Access Control Register 0 + //case 0x005: return "IACR1"; //Instruction Access Control Register 1 + //case 0x006: return "DACR1"; //Data Access Control Register 0 + //case 0x007: return "DACR1"; //Data Access Control Register 1 + } + return "???"; + } + + /*function movec_illg(regno) { + var regno2 = regno & 0x7ff; + + if (model == 68010) { + if (regno2 < 2) + return 0; + return 1; + } + else if (model == 68020) { + if (regno == 3) + return 1; //68040/060 only + if (regno2 < 4 || regno == 0x804) //4 is >=68040, but 0x804 is in 68020 + return 0; + return 1; + } + else if (model == 68030) { + if (regno2 <= 2) + return 0; + if (regno == 0x803 || regno == 0x804) + return 0; + return 1; + } + else if (model == 68040) { + if (regno == 0x802) + return 1; //68020/030 only + if (regno2 < 8) return 0; + return 1; + } + else if (model == 68060) { + if (regno <= 8) + return 0; + if (regno == 0x800 || regno == 0x801 || regno == 0x806 || regno == 0x807 || regno == 0x808) + return 0; + return 1; + } + return 1; + }*/ + function movecValid(r) { + switch (r) { + //MC68010/MC68020/MC68030/MC68040 + case 0x000: return model >= 68010; //Source Function Code (SFC) + case 0x001: return model >= 68010; //Destination Function Code (DFC) + case 0x800: return model >= 68010; //User Stack Pointer (USP) + case 0x801: return model >= 68010; //Vector Base Register (VBR) + //MC68020/MC68030/MC68040 + case 0x002: return model >= 68020; //Cache Control Register (CACR) + case 0x802: return model == 68020 || model == 68030; //Cache Address Register (CAAR) !MC68040 + case 0x803: return model >= 68020; //Master Stack Pointer (MSP) + case 0x804: return model >= 68020; //Interrupt Stack Pointer (ISP) + //MC68040/MC68LC040 + /*case 0x003: return model >= 68040; //MMU Translation Control Register (TC) + case 0x004: return model >= 68040; //Instruction Transparent Translation Register 0 (ITT0) + case 0x005: return model >= 68040; //Instruction Transparent Translation Register 1 (ITT1) + case 0x006: return model >= 68040; //Data Transparent Translation Register 0 (DTT0) + case 0x007: return model >= 68040; //Data Transparent Translation Register 1 (DTT1) + case 0x805: return model >= 68040; //MMU Status Register (MMUSR) + case 0x806: return model >= 68040; //User Root Pointer (URP) + case 0x807: return model >= 68040; //Supervisor Root Pointer (SRP) + //MC68EC040 only + case 0x004: return model >= 68040; //Instruction Access Control Register 0 (IACR0) + case 0x005: return model >= 68040; //Instruction Access Control Register 1 (IACR1) + case 0x006: return model >= 68040; //Data Access Control Register 0 (DACR1) + case 0x007: return model >= 68040; //Data Access Control Register 1 (DACR1) + */ + } + return false; + } + + function movec2C(cr, data) { + switch (cr) { + case 0: regs.sfc = data & 7; break; + case 1: regs.dfc = data & 7; break; + case 2: { + switch (model) { + case 68020: regs.cacr = data & CACR020_WMASK; break; + case 68030: regs.cacr = data & CACR030_WMASK; break; + //case 68040: regs.cacr = (data & 0x80008000) >>> 0; break; + //case 68060: regs.cacr = (data & 0xf8e0e000) >>> 0; break; + default: regs.cacr = 0; + } + coreSetCaches(false); + break; + } + /*case 3: { + regs.tcr = data & (model == 68060 ? 0xfffe : 0xc000); + if (currprefs.mmu_model) + mmu_set_tc(regs.tcr); + break; + } + case 4: regs.itt0 = data & 0xffffe364; mmu_tt_modified(); break; + case 5: regs.itt1 = data & 0xffffe364; mmu_tt_modified(); break; + case 6: regs.dtt0 = data & 0xffffe364; mmu_tt_modified(); break; + case 7: regs.dtt1 = data & 0xffffe364; mmu_tt_modified(); break; + case 8: regs.buscr = data & 0xf0000000; break;*/ + + case 0x800: regs.usp = data; break; + case 0x801: regs.vbr = data; break; + case 0x802: regs.caar = data; break; + case 0x803: regs.msp = data; if ( regs.m) regs.a[7] = regs.msp; break; + case 0x804: regs.isp = data; if (!regs.m) regs.a[7] = regs.isp; break; + /*case 0x805: regs.mmusr = data; break; + case 0x806: regs.urp = data & 0xfffffe00; break; + case 0x807: regs.srp = data & 0xfffffe00; break; + case 0x808: { + var opcr = regs.pcr; + regs.pcr &= ~(0x40 | 2 | 1); + regs.pcr |= data & (0x40 | 2 | 1); + if (currprefs.fpu_model <= 0) + regs.pcr |= 2; + if (((opcr ^ regs.pcr) & 2) == 2) { + SAEF_log("68060 FPU state: %s", regs.pcr & 2 ? "disabled" : "enabled"); + //flush possible already translated FPU instructions + flush_icache(0, 3); + } + break; + }*/ + default: SAEF_fatal(SAEE_CPU_Internal, "cpu.movec2C() invalid register %d", cr); + } + } + + function movecC2(cr) { + var data = null; + switch (cr) { + case 0: data = regs.sfc; break; + case 1: data = regs.dfc; break; + case 2: { + switch (model) { + case 68020: data = regs.cacr & CACR020_RMASK; break; + case 68030: data = regs.cacr & CACR030_RMASK; break; + //case 68040: data = (regs.cacr & 0x80008000) >>> 0; break; + //case 68060: data = (regs.cacr & 0xf880e000) >>> 0; break; + default: data = 0; + } + break; + } + //case 3: data = regs.tcr; break; + //case 4: data = regs.itt0; break; + //case 5: data = regs.itt1; break; + //case 6: data = regs.dtt0; break; + //case 7: data = regs.dtt1; break; + //case 8: data = regs.buscr; break; + + case 0x800: data = regs.usp; break; + case 0x801: data = regs.vbr; break; + case 0x802: data = regs.caar; break; + case 0x803: data = regs.m == 1 ? regs.a[7] : regs.msp; break; + case 0x804: data = regs.m == 0 ? regs.a[7] : regs.isp; break; + //case 0x805: data = regs.mmusr; break; + //case 0x806: data = regs.urp; break; + //case 0x807: data = regs.srp; break; + //case 0x808: data = regs.pcr; break; + default: SAEF_fatal(SAEE_CPU_Internal, "cpu.movecC2() invalid register %d", cr); + } + return data; + } + + /*---------------------------------*/ + /* 68030 fake MMU */ + + const MMUOP_DEBUG = false; + + function mmu_op30fake_pmove(pc, op, ext, addr) { + var preg = (ext >> 10) & 31; + var rw = (ext >> 9) & 1; + var fd = (ext >> 8) & 1; + var reg = null; + var otc = fake_tc_030; + var siz; + + switch (preg) { + case 0x10: + reg = "TC"; + siz = 4; + if (rw) + corePut32(addr, fake_tc_030); + else + fake_tc_030 = coreGet32(addr); + break; + case 0x12: + reg = "SRP"; + siz = 8; + if (rw) { + //corePut32(addr, fake_srp_030 >> 32); + //corePut32(addr + 4, (uae_u32)fake_srp_030); + corePut32(addr, fake_srp_030_hi); + corePut32(addr + 4, fake_srp_030_lo); + } else { + //fake_srp_030 = (uae_u64)coreGet32(addr) << 32; + //fake_srp_030 |= coreGet32(addr + 4); + fake_srp_030_hi = coreGet32(addr); + fake_srp_030_lo = coreGet32(addr + 4); + } + break; + case 0x13: + reg = "CRP"; + siz = 8; + if (rw) { + //corePut32(addr, fake_crp_030 >> 32); + //corePut32(addr + 4, (uae_u32)fake_crp_030); + corePut32(addr, fake_crp_030_hi); + corePut32(addr + 4, fake_crp_030_lo); + } else { + //fake_crp_030 = (uae_u64)coreGet32(addr) << 32; + //fake_crp_030 |= coreGet32(addr + 4); + fake_crp_030_hi = coreGet32(addr); + fake_crp_030_lo = coreGet32(addr + 4); + } + break; + case 0x18: + reg = "MMUSR"; + siz = 2; + if (rw) + corePut16(addr, fake_mmusr_030); + else + fake_mmusr_030 = coreGet16(addr); + break; + case 0x02: + reg = "TT0"; + siz = 4; + if (rw) + corePut32(addr, fake_tt0_030); + else + fake_tt0_030 = coreGet32(addr); + break; + case 0x03: + reg = "TT1"; + siz = 4; + if (rw) + corePut32(addr, fake_tt1_030); + else + fake_tt1_030 = coreGet32(addr); + break; + } + + if (reg === null) + return true; + + if (MMUOP_DEBUG) { + if (siz == 8) { + var val2 = coreGet32(addr); + var val = coreGet32(addr + 4); + if (rw) + SAEF_log("I_MMU_PMOVE %s,%08X%08X PC=%08X", reg, val2, val, pc); + else + SAEF_log("I_MMU_PMOVE %08X%08X,%s PC=%08X", val2, val, reg, pc); + } else { + if (siz == 4) + var val = coreGet32(addr); + else + var val = coreGet16(addr); + if (rw) + SAEF_log("I_MMU_PMOVE %s,%08X PC=%08X", reg, val, pc); + else + SAEF_log("I_MMU_PMOVE %08X,%s PC=%08X", val, reg, pc); + } + } + + if ((SAEV_config.chipset.mbdmac & 1) && SAEV_config.memory.ramsey.lowSize > 0) { + if (otc != fake_tc_030) + SAER.memory.a3000_fakekick((fake_tc_030 & 0x80000000) != 0); + } + return false; + } + + function mmu_op30fake_ptest(pc, op, ext, addr) { + if (MMUOP_DEBUG) { + var tmp = ""; + if ((ext >> 8) & 1) + tmp = sprintf(",A%d", (ext >> 4) & 15); + SAEF_log("I_MMU_PTEST%c %02X,%08X,#%X%s PC=%08X", ((ext >> 9) & 1) ? 'W' : 'R', (ext & 15), addr, (ext >> 10) & 7, tmp, pc); + } + fake_mmusr_030 = 0; + return false; + } + + function mmu_op30fake_pflush(pc, op, ext, addr) { + var flushmode = (ext >> 10) & 7; + var fc = ext & 31; + var mask = (ext >> 5) & 3; + var fname = ""; + + switch (flushmode) { + case 6: + fname = sprintf("FC=%x MASK=%x EA=%08x", fc, mask, 0); + break; + case 4: + fname = sprintf("FC=%x MASK=%x", fc, mask); + break; + case 1: + fname = "ALL"; + break; + default: + return true; + } + if (MMUOP_DEBUG) SAEF_log("I_MMU_PFLUSH %s PC=%08X", fname, pc); + return false; + } + + function mmu_op30(pc, opcode, ext, addr) { + /*if (currprefs.mmu_model) { + if (ext & 0x8000) + return mmu_op30_ptest(pc, opcode, ext, addr); + else if ((ext & 0xE000) == 0x2000 && (ext & 0x1C00)) + return mmu_op30_pflush(pc, opcode, ext, addr); + else if ((ext & 0xE000) == 0x2000 && !(ext & 0x1C00)) + return mmu_op30_pload(pc, opcode, ext, addr); + else + return mmu_op30_pmove(pc, opcode, ext, addr); + }*/ + var type = ext >> 13; + switch (type) { + case 0: + case 2: + case 3: + return mmu_op30fake_pmove(pc, opcode, ext, addr); + case 1: + return mmu_op30fake_pflush(pc, opcode, ext, addr); + case 4: + return mmu_op30fake_ptest(pc, opcode, ext, addr); + default: + return true; + } + } + + /*-----------------------------------------------------------------------*/ + /* SECT dissassembling */ + /*-----------------------------------------------------------------------*/ + + const D_RDD = 1; + const D_RDA = 2; + const D_RIPR = 3; + const D_RIPO = 4; + const D_RID = 5; + const D_IMD = 6; + const D_IME = 7; + const D_IME_DP = 8; + const D_EA = 10; + const D_CCR = 11; + const D_SR = 12; + const D_USP = 13; + const D_EXT_BITFIELD = 20; + const D_EXT_MOVEM = 21; + const D_EXT_MOVEC = 22; + const D_EXT_MUL64 = 23; + const D_EXT_DIV64 = 24; + const D_EXT_MMU = 25; + + function regs_da_def() { + this.memory = null; + this.pc = 0; + this.io = 0; + this.fmt8 = "%x"; + this.fmt16 = "%x"; + this.fmt32 = "%x"; + } + var regs_da = new regs_da_def(); + var inst_mn = null; + + function config_da_def() { + this.code = ""; + this.offset = 0; + this.limit = 32; + + this.radix = 16; + this.prefx = "$"; + this.width = 0; + this.reloc = true; + } + config_da = new config_da_def(); + + function setPC_da(pc) { + regs_da.pc = pc; + regs_da.io = 0; + } + function getPC_da() { + return regs_da.pc + regs_da.io; + } + function incPC_da(o) { + regs_da.io += o; + } + function syncPC_da() { + regs_da.pc += regs_da.io; + regs_da.io = 0; + } + + function get16_da(addr) { + return (regs_da.memory[addr] << 8) | regs_da.memory[addr+1]; + } + function get32_da(addr) { + return ((regs_da.memory[addr] << 24) | (regs_da.memory[addr+1] << 16) | (regs_da.memory[addr+2] << 8) | regs_da.memory[addr+3]) >>> 0; + } + function next16_da() { + var r = get16_da(regs_da.pc + regs_da.io); + incPC_da(2); + return r; + } + function next32_da() { + var r = get32_da(regs_da.pc + regs_da.io); + incPC_da(4); + return r; + } + + function szChr(z) { + switch (z) { + case 0: return "s"; + case 1: return "b"; + case 2: return "w"; + case 4: return "l"; + //default: SAEF_fatal(SAEE_CPU_Internal, "cpu.szChr() invalid size (%d)", z); + default: return "?"; + } + } + + function printMovec(ext, dir) { + var o; + var xn = (ext >> 12) & 7; + var reg = movecRegName(ext & 0xfff); + reg = reg.toLowerCase(); + if (dir) { + if (ext & 0x8000) + o = reg+",a"+xn; + else + o = reg+",d"+xn; + } else { + if (ext & 0x8000) + o = "a"+xn+","+reg; + else + o = "d"+xn+","+reg; + } + return o; + } + function printMovem(ext, inv) { + var d = [0,0,0,0,0,0,0,0]; + var a = [0,0,0,0,0,0,0,0]; + var i, o = ""; + for (i = 0; i < 16; i++) { + if (ext & (1 << (inv ? 15-i : i))) { + if (i < 8) + d[i] = 1; + else + a[i - 8] = 1; + } + } + var fi = d.indexOf(1); + var li = d.lastIndexOf(1); + if (fi != -1) { + o += "d"+fi; + if (li != fi) + o += "-d"+li; + } + fi = a.indexOf(1); + li = a.lastIndexOf(1); + if (fi != -1) { + if (o.length) o += "/"; + o += "a"+fi; + if (li != fi) + o += "-a"+li; + } + return o; + } + function printMul64(ext) { + var Dl = (ext >> 12) & 7; + var Dh = ext & 7; + inst_mn = (ext & 0x800) ? "muls" : "mulu"; + + return (ext & 0x400) ? "d"+Dh+"-d"+Dl : "d"+Dl; + } + function printDiv64(ext) { + var Dq = (ext >> 12) & 7; + var Dr = ext & 7; + inst_mn = (ext & 0x800) ? "divs" : "divu"; + + return (ext & 0x400) ? "d"+Dr+":d"+Dq : "d"+Dq; + } + function printMMU(ext) { + return "FIXME"; //FIX not implemented + } + + function printII(base, dp, ar) { + var o = ""; + var reg = (dp >> 12) & 7; + var cycles = 0; + var v; + var regd = (dp & 0x8000) ? regs.a[reg] : regs.d[reg]; + var scale = (dp >> 9) & 3; + + if ((dp & 0x800) == 0) + regd = extWord(regd & 0xffff); + + if (scale) regd = ((regd << scale) & 0xffffffff) >>> 0; + + if (dp & 0x100) { + var outer = 0; + + if (dp & 0x80) base = 0; + if (dp & 0x40) regd = 0; + + if ((dp & 0x30) == 0x20) { + base = add32(base, extWord(next16_da())); + cycles++; + } + if ((dp & 0x30) == 0x30) { + base = add32(base, next32_da()); + cycles++; + } + + if ((dp & 0x3) == 0x2) { + outer = extWord(next16_da()); + cycles++; + } + if ((dp & 0x3) == 0x3) { + outer = next32_da(); + cycles++; + } + + if ((dp & 0x4) == 0) { + base = add32(base, regd); + cycles++; + } + if (dp & 0x3) { + base = get32_da(base); + cycles++; + } + if (dp & 0x4) { + base = add32(base, regd); + cycles++; + } + v = add32(base, outer); + } else + v = add32(add32(base, extByte(dp & 0xff)), regd); + + /*if (ar != -1) + o += sprintf("(%d,A%d,%s%d.%s*%d)[$%08x]", castByte(dp & 0xff), ar, (dp & 0x8000)?"A":"D",reg, (dp & 0x800)?"L":"W", 1 << scale, v); + else + o += sprintf("(%d,PC,%s%d.%s*%d)[$%08x]", castByte(dp & 0xff), (dp & 0x8000)?"A":"D",reg, (dp & 0x800)?"L":"W", 1 << scale, v); + */ + if (ar != -1) + o += sprintf("(%d,a%d,%s%d.%s*%d)", castByte(dp & 0xff), ar, (dp & 0x8000)?"a":"d",reg, (dp & 0x800)?"l":"w", 1 << scale); + else + o += sprintf("(%d,pc,%s%d.%s*%d)", castByte(dp & 0xff), (dp & 0x8000)?"a":"d",reg, (dp & 0x800)?"l":"w", 1 << scale); + + return o; + } + + function printEA(ea, z) { + var m = ea >> 3; + if (m == 7) { + switch (ea & 7) { + case 0: { //absw + var dp = next16_da(); + return sprintf(config_da.radix == 10 ? "(%d)" : "("+regs_da.fmt16+")", dp); + } + case 1: { //absl + var dp = next32_da(); + return sprintf(config_da.radix == 10 ? "(%d)" : "("+regs_da.fmt32+")", dp); + } + case 2: { //pcid + var pc = getPC_da(); + var dp = extWord(next16_da()); + if (config_da.reloc) + return sprintf(regs_da.fmt32, add32(pc, dp)); + else + return sprintf(config_da.radix == 10 ? "%d(pc)" : regs_da.fmt32+"(pc)", castLong(dp)); + } + case 3: { //pcii + var pc = getPC_da(); + var dp = next16_da(); + return printII(pc, dp, -1); + } + case 4: { //imm + var dp = 0; + switch (z) { + case 1: + dp = next16_da() & 0xff; + return sprintf(config_da.radix == 10 ? "#%d" : "#"+regs_da.fmt8, castByte(dp)); + case 2: + dp = next16_da(); + return sprintf(config_da.radix == 10 ? "#%d" : "#"+regs_da.fmt16, castWord(dp)); + case 4: + dp = next32_da(); + return sprintf(config_da.radix == 10 ? "#%d" : "#"+regs_da.fmt32, castLong(dp)); + } + } + } + } else { + var r = ea & 7; + switch (m) { + case 0: return sprintf("d%d", r); //rdd + case 1: return sprintf("a%d", r); //rda + case 2: return sprintf("(a%d)", r); //ria + case 3: return sprintf("(a%d)+", r); //ripo + case 4: return sprintf("-(a%d)", r); //ripr + case 5: { //rid + var dp = extWord(next16_da()); + //return sprintf(config_da.radix == 10 ? "%d(A%d)[$%08x]" : "$%08x(A%d)[$%08x]", castLong(dp), r, add32(regs.a[r], dp)); + return sprintf(config_da.radix == 10 ? "%d(a%d)" : regs_da.fmt32+"(a%d)", dp, r); + } + case 6: { //rii + var dp = next16_da(); + return printII(regs.a[r], dp, r); + } + } + } + return "???"; + } + + function printI2(ext, mode, value, z) { + switch (mode) { + case D_RDD: return sprintf("d%d", value); + case D_RDA: return sprintf("a%d", value); + case D_RIPR: return sprintf("-(a%d)", value); + case D_RIPO: return sprintf("(a%d)+", value); + case D_RID: { + var dp = castLong(extWord(next16_da())); + //return sprintf("%d(A%d)[$%08x]", dp, value, regs.a[value] + dp); + return sprintf("%d(A%d)", dp, value); + } + case D_IMD: return sprintf(config_da.radix == 10 ? "#%d" : "#"+regs_da.fmt8, value); + case D_IME: { + var imm = value == 1 ? next16_da() : next32_da(); + return sprintf(config_da.radix == 10 ? "#%d" : (value == 1 ? "#"+regs_da.fmt16 : "#"+regs_da.fmt32), imm); + } + case D_IME_DP: { + var pc = getPC_da(); + if (value == 0) dp = castLong(extWord(next16_da())); + else if (value == 255) dp = castLong(next32_da()); + else dp = castLong(extByte(value)); + if (config_da.reloc) + return sprintf("<"+regs_da.fmt32+">", pc + dp); + else + return sprintf("<%d>", dp); + } + case D_EA: return printEA(value, z); + case D_CCR: return "ccr"; + case D_SR: return "sr"; + case D_USP: return "usp"; + case D_EXT_BITFIELD: { + var offset = (ext & 0x800) ? regs.d[(ext >> 6) & 7] : (ext >> 6) & 0x1f; + var width = (ext & 0x20) ? regs.d[ext & 7] & 0x1f : ext & 0x1f; if (width == 0) width = 32; + return sprintf("{%d:%d}", offset, width); + } + case D_EXT_MOVEM: return printMovem(ext, value); + case D_EXT_MOVEC: return printMovec(ext, value); + case D_EXT_MUL64: return printMul64(ext); + case D_EXT_DIV64: return printDiv64(ext); + case D_EXT_MMU: return printMMU(ext); + } + } + + function printI(i) { + var mn = i.mn; + + mn = mn.toLowerCase(); + if (mn == "illegal") + return mn; + + inst_mn = null; + + var o = ""; + if (i.d) { + var ext = i.d.ext == 0 ? false : (i.d.ext == 1 ? next16_da() : next32_da()); + + if (i.d.z) + o += "." + szChr(i.d.z); + else if (1 && i.d.z2) + o += "." + szChr(i.d.z2); + + + if (i.d.sm && i.d.dm) { + o += " "; + o += printI2(ext, i.d.sm, i.d.s, i.d.z); + o += ","; + o += printI2(ext, i.d.dm, i.d.d, i.d.z); + } + else if (i.d.dm) { + o += " "; + o += printI2(ext, i.d.dm, i.d.d, i.d.z); + } + } + if (inst_mn !== null) + return inst_mn + o; + else + return mn + o; + } + + this.getConfig_da = function() { + return config_da; + } + this.setup_da = function(m) { + model = m; + if (!mkITab()) + return SAEE_CPU_Internal; + + mkCCTab(); + mkEATabs(); + return SAEE_None; + } + + function fixup_da() { + if (config_da.code.length > 0) { + regs_da.memory = new Uint8Array(config_da.code.length); + regs_da.memory.set(SAEF_String2Array(config_da.code, 0, config_da.code.length)); + config_da.code = ""; + } + if (regs_da.memory === null) + throw 1; + + if (getPC_da() >= regs_da.memory.length) + regs_da.pc = regs_da.io = 0x0; + + if (config_da.limit <= 0) + config_da.limit = 8; + + regs_da.fmt8 = regs_da.fmt16 = regs_da.fmt32 = config_da.prefx; + if (config_da.width == 0) { + regs_da.fmt8 += "%x"; + regs_da.fmt16 += "%x"; + regs_da.fmt32 += "%x"; + } else { + regs_da.fmt8 += "%02x"; + regs_da.fmt16 += "%04x"; + regs_da.fmt32 += config_da.width == 24 ? "%06x" : "%08x"; + } + + } + + this.disassemble = function() { + fixup_da(); + + setPC_da(config_da.offset); + + var op, addr, code, words, inst; + + var out = []; + var cnt = 0; + while (cnt++ < config_da.limit) { + addr = regs_da.pc; + code = []; for (var i = 0; i < 5; i++) code.push(get16_da(addr + i * 2)); + + op = next16_da(); + inst = printI(iTab[op]); + words = regs_da.io >> 1; + + out.push([addr, code, words, inst]); + + syncPC_da(); + } + return out; + } + + this.diss = function(addr, limit) { + if (typeof addr == "undefined") addr = coreGetPC(); + if (typeof limit == "undefined" || limit == 0) limit = 8; + + var bank = SAER_Memory_getBank(addr); + regs_da.memory = bank.baseaddr; + setPC_da(addr - bank.start); + + var cnt = 0; + while (cnt++ < limit) { + var o = ""; + + if (1) { + o += sprintf("$%08x: ", regs_da.pc + bank.start); + for (var i = 0; i < 5; i++) + o += sprintf("$%04x ", get16_da(regs_da.pc + i * 2)); + } + var op = next16_da(); + o += printI(iTab[op]); + o += sprintf(" (%d)", regs_da.io >> 1); + SAEF_log(o); + + syncPC_da(); + } + }; + + /*-----------------------------------------------------------------------*/ + /* SECT instruction core. Implementation based on M68000PRM.pdf */ + /*-----------------------------------------------------------------------*/ + + function stackPut16(v) { + regs.a[7] -= 2; /* pre-decrement */ + corePut16(regs.a[7], v); + } + function stackPut32(v) { + regs.a[7] -= 4; /* pre-decrement */ + corePut32(regs.a[7], v); + } + function stackGet16() { + var v = coreGet16(regs.a[7]); + regs.a[7] += 2; /* post-increment */ + return v; + } + function stackGet32() { + var v = coreGet32(regs.a[7]); + regs.a[7] += 4; /* post-increment */ + return v; + } + + /*-----------------------------------------------------------------------*/ + + const aIncDec = [ + [], + [1,1,1,1,1,1,1,2], + [2,2,2,2,2,2,2,2], + [], + [4,4,4,4,4,4,4,4] + ]; function castByte(v) { return (v & 0x80) ? (v - 0x100) : v; @@ -195,354 +2880,23 @@ function CPU() { var r = a + b; return r > 0xffffffff ? r - 0x100000000 : r; } - function addAuto(a, b, z) { - var r = a + b; - switch (z) { - case 1: return r > 0xff ? r - 0x100 : r; - case 2: return r > 0xffff ? r - 0x10000 : r; - case 4: return r > 0xffffffff ? r - 0x100000000 : r; - default: - Fatal(SAEE_CPU_Internal, 'cpu.addAuto() invalid size'); - return 0; - } - } + function sub32(a, b) { var r = a - b; return r < 0 ? r + 0x100000000 : r; } - function subAuto(a, b, z) { - var r = a - b; - switch (z) { - case 1: return r < 0 ? r + 0x100 : r; - case 2: return r < 0 ? r + 0x10000 : r; - case 4: return r < 0 ? r + 0x100000000 : r; - default: - Fatal(SAEE_CPU_Internal, 'cpu.subAuto() invalid size'); - return 0; - } - } - function nextOPCode() { - var op = AMIGA.mem.load16(regs.pc); - fault.pc = regs.pc; - fault.op = op; - regs.pc += 2; - return op; - } - function nextIWord() { - var r = AMIGA.mem.load16(regs.pc); - regs.pc += 2; - return r; - } - function nextILong() { - var r = AMIGA.mem.load32(regs.pc); - regs.pc += 4; - return r; - } + /*-----------------------------------------------------------------------*/ + /* Condition codes */ - //var scale = 1 << ((ext & 0x600) >> 9); if (scale != 1) alert('exII() scale '+scale); - function exII(base) { - var ext = nextIWord(); - if (ext & 0x100) { - Fatal(SAEE_CPU_68020_Required, 'cpu.exII() Full extension index (not a 68000 program)'); - return 0; - } else { - var disp = extByte(ext & 0xff); - var r = (ext & 0x7000) >> 12; - var reg = (ext & 0x8000) ? regs.a[r] : regs.d[r]; - if (!(ext & 0x800)) reg = extWord(reg & 0xffff); - return add32(add32(base, disp), reg); - } - } - - function exEA(ea, z) { - var dp; - - switch (ea.m) { - case M_rdd: - ea.a = ea.r; - ea.t = T_RD; - break; - case M_rda: - ea.a = ea.r; - ea.t = T_RA; - break; - case M_ria: - ea.a = regs.a[ea.r]; - ea.t = T_AD; - break; - case M_ripo: - ea.a = regs.a[ea.r]; - ea.t = T_AD; - regs.a[ea.r] += z; - if (regs.a[ea.r] > 0xffffffff) { - BUG.say(sprintf('exEA() M_ripo A%d > 2^32 ($%x)', ea.r, regs.a[ea.r])); - regs.a[ea.r] -= 0x100000000; - //AMIGA.cpu.diss(fault.pc, 1); - //AMIGA.cpu.dump(); - //exception2(regs.a[ea.r], 0); - } - break; - case M_ripr: - regs.a[ea.r] -= z; - if (regs.a[ea.r] < 0) { - BUG.say(sprintf('exEA() M_ripr A%d < 0 ($%x)', ea.r, regs.a[ea.r])); - regs.a[ea.r] += 0x100000000; - //AMIGA.cpu.diss(fault.pc, 1); - //AMIGA.cpu.dump(); - //exception2(regs.a[ea.r], 0); - } - ea.a = regs.a[ea.r]; - ea.t = T_AD; - break; - case M_rid: - dp = (nextIWord()); - ea.a = add32(regs.a[ea.r], extWord(dp)); - ea.t = T_AD; - break; - case M_rii: - ea.a = exII(regs.a[ea.r]); - ea.t = T_AD; - break; - case M_pcid: - dp = extWord(nextIWord()); - ea.a = add32(regs.pc - 2, dp); - ea.t = T_AD; - break; - case M_pcii: - ea.a = exII(regs.pc); - ea.t = T_AD; - break; - case M_absw: - ea.a = extWord(nextIWord()); - ea.t = T_AD; - break; - case M_absl: - ea.a = nextILong(); - ea.t = T_AD; - break; - case M_imm: { - if (ea.r == -1) { - switch (z) { - case 1: ea.a = nextIWord() & 0xff; break; - case 2: ea.a = nextIWord(); break; - case 4: ea.a = nextILong(); break; - default: - Fatal(SAEE_CPU_Internal, 'cpu.exEA() invalid size'); - } - } else - ea.a = ea.r; - ea.t = T_IM; - break; - } - default: - Fatal(SAEE_CPU_Internal, 'cpu.exEA() invalid mode (' + ea.m + ')'); - } - return ea; - } - - function exEAM(ea) { /* MOVEM */ - var dp; - - switch (ea.m) { - case M_ria: - case M_ripo: - case M_ripr: - ea.a = regs.a[ea.r]; - ea.t = T_AD; - break; - case M_rid: - dp = extWord(nextIWord()); - ea.a = add32(regs.a[ea.r], dp); - ea.t = T_AD; - break; - case M_rii: - ea.a = exII(regs.a[ea.r]); - ea.t = T_AD; - break; - case M_pcid: - dp = extWord(nextIWord()); - ea.a = add32(regs.pc - 2, dp); - ea.t = T_AD; - break; - case M_pcii: - ea.a = exII(regs.pc); - ea.t = T_AD; - break; - case M_absw: - ea.a = extWord(nextIWord()); - ea.t = T_AD; - break; - case M_absl: - ea.a = nextILong(); - ea.t = T_AD; - break; - case M_list: /* M_imm */ - ea.a = nextIWord(); - ea.t = T_IM; - break; - default: - Fatal(SAEE_CPU_Internal, 'cpu.exEAM() invalid mode (' + ea.m + ')'); - } - ea.c = 0; - return ea; - } - - function ldEA(ea, z) { - switch (ea.t) { - case T_RD: { - switch (z) { - case 1: return regs.d[ea.a] & 0xff; - case 2: return regs.d[ea.a] & 0xffff; - case 4: return regs.d[ea.a]; - default: - Fatal(SAEE_CPU_Internal, 'cpu.ldEA() T_RD invalid size'); - return 0; - } - } - case T_RA: { - switch (z) { - case 2: return regs.a[ea.a] & 0xffff; - case 4: return regs.a[ea.a]; - default: - Fatal(SAEE_CPU_Internal, 'cpu.ldEA() T_RA invalid size'); - return 0; - } - } - case T_AD: { - /* The USP must not be byte-aligned */ - if (ea.m == M_ripo && ea.r == 7 && z == 1) { - //BUG.say(sprintf('ldEA() USP ADDRESS ERROR A7 $%08x', regs.a[7])); - regs.a[7]++; - return AMIGA.mem.load16(regs.a[7] - 2) >> 8; - } - if (ea.a > 0xffffff) { //&& ea.m != M_absl) { - //BUG.say(sprintf('ldEA() BUS ERROR, $%08x > 24bit, reducing address to $%08x', ea.a, ea.a & 0xffffff)); - ea.a &= 0xffffff; - } - if ((ea.a & 1) && z != 1) { - BUG.say(sprintf('ldEA() ADDRESS ERROR $%08x, pc $%08x', ea.a, fault.pc)); - //AMIGA.cpu.diss(fault.pc-8, 20); - //AMIGA.cpu.dump(); - exception3(ea.a, 1); - } - switch (z) { - case 1: return AMIGA.mem.load8(ea.a); - case 2: return AMIGA.mem.load16(ea.a); - case 4: return AMIGA.mem.load32(ea.a); - default: - Fatal(SAEE_CPU_Internal, 'cpu.ldEA() T_AD invalid size'); - return 0; - } - } - case T_IM: - return ea.a; - default: - Fatal(SAEE_CPU_Internal, 'cpu.ldEA() invalid type (' + ea.t + ')'); - return 0; - } - } - - function stEA(ea, z, v) { - switch (ea.t) { - case T_RD: - switch (z) { - case 1: regs.d[ea.a] = ((regs.d[ea.a] & 0xffffff00) | v) >>> 0; break; - case 2: regs.d[ea.a] = ((regs.d[ea.a] & 0xffff0000) | v) >>> 0; break; - case 4: regs.d[ea.a] = v; break; - default: - Fatal(SAEE_CPU_Internal, 'cpu.stEA() invalid size'); - } - break; - case T_RA: - regs.a[ea.a] = v; - break; - case T_AD: { - /* The USP must not be byte-aligned */ - if (ea.m == M_ripr && ea.r == 7 && z == 1) { - //BUG.say(sprintf('stEA() USP ADDRESS ERROR A7 $%08x', regs.a[7])); - AMIGA.mem.store16(--regs.a[7], v << 8); - return; - } - if (ea.a > 0xffffff) { //&& ea.m != M_absl) { - //BUG.say(sprintf('stEA() BUS ERROR, $%08x > 24bit, reducing address to $%08x', ea.a, ea.a & 0xffffff)); - ea.a &= 0xffffff; - } - if ((ea.a & 1) && z != 1) { - BUG.say(sprintf('stEA() ADDRESS ERROR $%08x, pc $%08x', ea.a, fault.pc)); - //AMIGA.cpu.diss(fault.pc-8, 20); - //AMIGA.cpu.dump(); - exception3(ea.a, 1); - } - switch (z) { - case 1: AMIGA.mem.store8(ea.a, v); break; - case 2: AMIGA.mem.store16(ea.a, v); break; - case 4: AMIGA.mem.store32(ea.a, v); break; - default: - Fatal(SAEE_CPU_Internal, 'cpu.stEA() invalid size'); - } - break; - } - default: - Fatal(SAEE_CPU_Internal, 'cpu.stEA() invalid type (' + ea.t + ')'); - } - } - - function ccTrue(cc) { - switch (cc) { - case 0: return true; //T - case 1: return false; //F - case 2: return !regs.c && !regs.z; //HI - case 3: return regs.c || regs.z; //LS - case 4: return !regs.c; //CC - case 5: return regs.c; //CS - case 6: return !regs.z; //NE - case 7: return regs.z; //EQ - case 8: return !regs.v; //VC - case 9: return regs.v; //VV - case 10: return !regs.n; //PL - case 11: return regs.n; //MI - case 12: return regs.n == regs.v; //GE - case 13: return regs.n != regs.v; //LT - case 14: return !regs.z && (regs.n == regs.v); //GT - case 15: return regs.z || (regs.n != regs.v); //LE - default: - Fatal(SAEE_CPU_Internal, 'cpu.ccTrue() invalid condition code (' + cc + ')'); - return false; - } - } - - /*switch (z) { - case 1: if (S > 0xff || D > 0xff || R > 0xff) alert('fadd 8'); break; - case 2: if (S > 0xffff || D > 0xffff || R > 0xffff) alert('fadd 16'); break; - }*/ - function flgAdd(S, D, R, z, isADDX) /* ADD, ADDI, ADDQ, ADDX */ - { - var Sm, Dm, Rm; - - switch (z) { - case 1: - Sm = (S & 0x80) != 0; - Dm = (D & 0x80) != 0; - Rm = (R & 0x80) != 0; - break; - case 2: - Sm = (S & 0x8000) != 0; - Dm = (D & 0x8000) != 0; - Rm = (R & 0x8000) != 0; - break; - case 4: - Sm = (S & 0x80000000) != 0; - Dm = (D & 0x80000000) != 0; - Rm = (R & 0x80000000) != 0; - break; - default: - Fatal(SAEE_CPU_Internal, 'cpu.flgAdd() invalid size'); - } - regs.v = (Sm && Dm && !Rm) || (!Sm && !Dm && Rm); - regs.c = (Sm && Dm) || (!Rm && Dm) || (Sm && !Rm); + function flgAdd(S, D, R, m, isADDX) { /* ADD, ADDI, ADDQ, ADDX */ + var Sn = (S & m) != 0; + var Dn = (D & m) != 0; + var Rn = (R & m) != 0; + regs.v = (Sn && Dn && !Rn) || (!Sn && !Dn && Rn); + regs.c = (Sn && Dn) || (!Rn && Dn) || (Sn && !Rn); regs.x = regs.c; - regs.n = Rm; + regs.n = Rn; if (isADDX) { if (R != 0) regs.z = false; @@ -550,37 +2904,14 @@ function CPU() { regs.z = R == 0; } - /*switch (z) { - case 1: if (S > 0xff || D > 0xff || R > 0xff) alert('fsub 8'); break; - case 2: if (S > 0xffff || D > 0xffff || R > 0xffff) alert('fsub 16'); break; - }*/ - function flgSub(S, D, R, z, isSUBX) /* SUB, SUBI, SUBQ, SUBX */ - { - var Sm, Dm, Rm; - - switch (z) { - case 1: - Sm = (S & 0x80) != 0; - Dm = (D & 0x80) != 0; - Rm = (R & 0x80) != 0; - break; - case 2: - Sm = (S & 0x8000) != 0; - Dm = (D & 0x8000) != 0; - Rm = (R & 0x8000) != 0; - break; - case 4: - Sm = (S & 0x80000000) != 0; - Dm = (D & 0x80000000) != 0; - Rm = (R & 0x80000000) != 0; - break; - default: - Fatal(SAEE_CPU_Internal, 'cpu.flgSub() invalid size'); - } - regs.v = (!Sm && Dm && !Rm) || (Sm && !Dm && Rm); - regs.c = (Sm && !Dm) || (Rm && !Dm) || (Sm && Rm); + function flgSub(S, D, R, m, isSUBX) { /* SUB, SUBI, SUBQ, SUBX */ + var Sn = (S & m) != 0; + var Dn = (D & m) != 0; + var Rn = (R & m) != 0; + regs.v = (!Sn && Dn && !Rn) || (Sn && !Dn && Rn); + regs.c = (Sn && !Dn) || (Rn && !Dn) || (Sn && Rn); regs.x = regs.c; - regs.n = Rm; + regs.n = Rn; if (isSUBX) { if (R != 0) regs.z = false; @@ -588,1206 +2919,2679 @@ function CPU() { regs.z = R == 0; } - /*switch (z) { - case 1: if (S > 0xff || D > 0xff || R > 0xff) alert('fcmp 8'); break; - case 2: if (S > 0xffff || D > 0xffff || R > 0xffff) alert('fcmp 16'); break; - }*/ - function flgCmp(S, D, R, z) /* CMP, CMPA, CMPI, CMPM */ - { - var Sm, Dm, Rm; - - switch (z) { - case 1: - Sm = (S & 0x80) != 0; - Dm = (D & 0x80) != 0; - Rm = (R & 0x80) != 0; - break; - case 2: - Sm = (S & 0x8000) != 0; - Dm = (D & 0x8000) != 0; - Rm = (R & 0x8000) != 0; - break; - case 4: - Sm = (S & 0x80000000) != 0; - Dm = (D & 0x80000000) != 0; - Rm = (R & 0x80000000) != 0; - break; - default: - Fatal(SAEE_CPU_Internal, 'cpu.flgCmp() invalid size'); - } - regs.v = (!Sm && Dm && !Rm) || (Sm && !Dm && Rm); - regs.c = (Sm && !Dm) || (Rm && !Dm) || (Sm && Rm); - regs.n = Rm; + function flgCmp(S, D, R, m) { /* CAS, CAS2, CMP, CMPA, CMPI, CMPM */ + var Sn = (S & m) != 0; + var Dn = (D & m) != 0; + var Rn = (R & m) != 0; + regs.v = (!Sn && Dn && !Rn) || (Sn && !Dn && Rn); + regs.c = (Sn && !Dn) || (Rn && !Dn) || (Sn && Rn); + regs.n = Rn; regs.z = R == 0; } - - /*switch (z) { - case 1: if (D > 0xff || R > 0xff) alert('fneg 8'); break; - case 2: if (D > 0xffff || R > 0xffff) alert('fneg 16'); break; - }*/ - function flgNeg(D, R, z, isNEGX) /* NEG, NEGX */ - { - var Dm, Rm; - - switch (z) { - case 1: - Dm = (D & 0x80) != 0; - Rm = (R & 0x80) != 0; - break; - case 2: - Dm = (D & 0x8000) != 0; - Rm = (R & 0x8000) != 0; - break; - case 4: - Dm = (D & 0x80000000) != 0; - Rm = (R & 0x80000000) != 0; - break; - default: - Fatal(SAEE_CPU_Internal, 'cpu.flgNeg() invalid size'); - } - regs.v = Dm && Rm; - regs.c = Dm || Rm; + + function flgNeg(D, R, m, isNEGX) { /* NEG, NEGX */ + var Dn = (D & m) != 0; + var Rn = (R & m) != 0; + regs.v = Dn && Rn; + regs.c = Dn || Rn; regs.x = regs.c; - regs.n = Rm; + regs.n = Rn; if (isNEGX) { if (R != 0) regs.z = false; } else regs.z = R == 0; } - - /*switch (z) { - case 1: if (R > 0xff) alert('flog 8'); break; - case 2: if (R > 0xffff) alert('flog 16'); break; - }*/ - function flgLogical(R, z) { /* AND ANDI OR ORI EOR EORI MOVE MOVEQ EXT NOT TST */ - switch (z) { - case 1: - regs.n = (R & 0x80) != 0; - break; - case 2: - regs.n = (R & 0x8000) != 0; - break; - case 4: - regs.n = (R & 0x80000000) != 0; - break; - default: - Fatal(SAEE_CPU_Internal, 'cpu.flgLogical() invalid size'); - } + + function flgLogical(R, m) { /* AND ANDI OR ORI EOR EORI MOVE MOVEQ EXT NOT TST */ + regs.n = (R & m) != 0; regs.z = R == 0; regs.v = regs.c = false; } - - /*-----------------------------------------------------------------------*/ + /*-----------------------------------------------------------------------*/ + /* Instructions ---------------------------------------------------------*/ /*-----------------------------------------------------------------------*/ /* Data Movement */ - function I_EXG(p) { - var sea = exEA(p.s, p.z); - var s = ldEA(sea, p.z); - var dea = exEA(p.d, p.z); - var d = ldEA(dea, p.z); - stEA(sea, p.z, d); - stEA(dea, p.z, s); + function I_EXG_DD(p) { + var t = regs.d[p.Rx]; + regs.d[p.Rx] = regs.d[p.Ry]; + regs.d[p.Ry] = t; //ccna - //BUG.say(sprintf('I_EXG.%s s $%08x <-> d $%08x', szChr(p.z), s, d)); - return p.cyc;//6; + coreSyncPC(); + return p.cyc; } - - function I_LEA(p) { - var sea = exEA(p.s, p.z); - var dea = exEA(p.d, p.z); - stEA(dea, p.z, sea.a); + function I_EXG_AA(p) { + var t = regs.a[p.Rx]; + regs.a[p.Rx] = regs.a[p.Ry]; + regs.a[p.Ry] = t; //ccna - //BUG.say(sprintf('I_LEA.%s sea $%08x', szChr(p.z), sea.a)); - return p.cyc; + coreSyncPC(); + return p.cyc; + } + function I_EXG_DA(p) { + var t = regs.d[p.Rx]; + regs.d[p.Rx] = regs.a[p.Ry]; + regs.a[p.Ry] = t; + //ccna + coreSyncPC(); + return p.cyc; + } + + function I_LEA(p) { + regs.a[p.An] = exEAtab[p.ea](4); + //SAEF_log("I_LEA.L $%08x %d/%d", regs.a[p.An], p.ea>>3,p.ea&7); + //ccna + coreSyncPC(); + return p.cyc; } function I_PEA(p) { - var sea = exEA(p.s, p.z); - var dea = exEA(new EffAddr(M_ripr, 7), p.z); - stEA(dea, p.z, sea.a); - //ccna - return p.cyc; + var a = exEAtab[p.ea](4); + stackPut32(a); + //SAEF_log(("I_PEA.L $%08x", a)); + //ccna + coreSyncPC(); + return p.cyc; } function I_LINK(p) { - var sea = exEA(p.s, p.z); - var An = sea.a; - var dea = exEA(p.d, p.z); - var dp = ldEA(dea, p.z); if (p.z == 2) dp = extWord(dp); - - stEA(exEA(new EffAddr(M_ripr, 7), 4), 4, regs.a[An]); - regs.a[An] = regs.a[7]; + var dp = extWord(coreNext16()); + stackPut32(regs.a[p.An]); + regs.a[p.An] = regs.a[7]; regs.a[7] = add32(regs.a[7], dp); + //SAEF_log(("I_LINK.W A%d, dp $%04x", p.An, dp)); //ccna + coreSyncPC(); + return p.cyc; + } + function I_LINK_32(p) { /* >= 68020 */ + var dp = coreNext32(); + stackPut32(regs.a[p.An]); + regs.a[p.An] = regs.a[7]; + regs.a[7] = add32(regs.a[7], dp); + //SAEF_log(("I_LINK.L A%d, dp $%04x", p.An, dp)); + //ccna + coreSyncPC(); return p.cyc; - - /*debug - var newsp = add32(regs.a[7], dp); - BUG.say(sprintf('I_LINK.%s A%d, dp $%08x, oldsp $%08x, newsp $%08x', szChr(p.z), An, dp, regs.a[7], newsp)); - regs.a[7] = newsp;*/ } function I_UNLK(p) { - var sea = exEA(p.s, p.z); - var An = sea.a; - regs.a[7] = regs.a[An]; - regs.a[An] = ldEA(exEA(new EffAddr(M_ripo, 7), 4), 4); + regs.a[7] = regs.a[p.An]; + regs.a[p.An] = stackGet32(); + //SAEF_log(("I_UNLK A%d", p.An)); //ccna - //BUG.say(sprintf('I_UNLK.%s A%d', szChr(p.z), An)); + coreSyncPC(); return p.cyc; } - function I_MOVE(p) { - var sea = exEA(p.s, p.z); - var s = ldEA(sea, p.z); - var dea = exEA(p.d, p.z); - stEA(dea, p.z, s); - flgLogical(s, p.z); - //BUG.say(sprintf('I_MOVE.%s sm %d dm %d sa $%08x da $%08x r $%08x', szChr(p.z), p.s.m, p.d.m, sea.a, dea.a, s)); + function I_MOVE_8(p) { + var s = ldEA8tab[p.sea](); + stEA8tab[p.dea](s); + flgLogical(s, p.zm); + //SAEF_log(("I_MOVE.B $%08x", s)); + coreSyncPC(); + return p.cyc; + } + function I_MOVE_16(p) { + var s = ldEA16tab[p.sea](); + stEA16tab[p.dea](s); + flgLogical(s, p.zm); + //SAEF_log(("I_MOVE.W $%08x", s)); + coreSyncPC(); + return p.cyc; + } + function I_MOVE_32(p) { + var s = ldEA32tab[p.sea](); + stEA32tab[p.dea](s); + flgLogical(s, p.zm); + //SAEF_log(("I_MOVE.L $%08x", s)); + coreSyncPC(); return p.cyc; } - function I_MOVEA(p) { - var sea = exEA(p.s, p.z); - var s = ldEA(sea, p.z); if (p.z == 2) s = extWord(s); - var dea = exEA(p.d, 4); - stEA(dea, 4, s); + function I_MOVEA_16(p) { + var s = ldEA16tab[p.ea](); + regs.a[p.An] = extWord(s); + //SAEF_log(("I_MOVEA.W $%08x A%d", extWord(s), p.An)); //ccna - //BUG.say(sprintf('I_MOVEA.%s s $%08x A%d', szChr(p.z), s, p.d.r)); + coreSyncPC(); + return p.cyc; + } + function I_MOVEA_32(p) { + var s = ldEA32tab[p.ea](); + regs.a[p.An] = s; + //SAEF_log(("I_MOVEA.L $%08x A%d", s, p.An)); + //ccna + coreSyncPC(); return p.cyc; } function I_MOVEQ(p) { - var sea = exEA(p.s, p.z); - var s = ldEA(sea, p.z); s = extByte(s); - var dea = exEA(p.d, p.z); - stEA(dea, p.z, s); - flgLogical(s, p.z); - //BUG.say(sprintf('I_MOVEQ.%s s $%08x', szChr(p.z), s)); + var s = extByte(p.data); + regs.d[p.Dn] = s; + flgLogical(s, p.zm); + //SAEF_log(("I_MOVEQ.L $%08x,D%d", s, p.Dn)); + coreSyncPC(); return p.cyc; } - - function I_MOVEM_R2M(p) { - /* p. 4-128: The MC68000 and MC68010 write the initial register value (not decremented). */ - var i, rd = [], ra = []; - for (i = 0; i < 8; i++) { - rd[i] = regs.d[i]; - ra[i] = regs.a[i]; - } - var sea = exEAM(p.s); - var dea = exEAM(p.d); - var n = 0, k; - if (p.d.m == M_ripr) { - var c = 0; - for (var i = 0; i < 16; i++) { - if (sea.a & (1 << i)) c++; - } - c *= p.z; - regs.a[p.d.r] -= c; - dea.a -= c; - k = 15; - //BUG.say(sprintf('I_MOVEM_R2M.%s M_ripr bc %d == %d bytes', szChr(p.z), bc, bc * p.z)); - } else k = 0; - - for (var i = 0; i < 16; i++) { - if (sea.a & (1 << (i ^ k))) { - var r; - - if (i < 8) { - r = rd[i]; - //BUG.say(sprintf('I_MOVEM_R2M.%s D%d d $%08x', szChr(p.z), i, r)); - } else { - r = ra[i - 8]; - //BUG.say(sprintf('I_MOVEM_R2M.%s A%d d $%08x', szChr(p.z), i - 8, r)); - //if (i - 8 == p.d.r) BUG.say(sprintf('I_MOVEM_R2M.%s A%d d $%08x, WRITE OWN', szChr(p.z), i - 8, r)); - } - if (p.z == 2) - r &= 0xffff; - - stEA(dea, p.z, r); - dea.a += p.z; - n++; - } - } - //ccna - //BUG.say(sprintf('I_MOVEM_R2M.%s s $%08x d $%08x', szChr(p.z), sea.a, dea.a)); - return [p.cyc[0] + (p.z == 2 ? 4 : 8) * n, 0,0]; //FIXME - } - - function I_MOVEM_M2R(p) { - var sea = exEAM(p.s); - var dea = exEAM(p.d); + function I_MOVEM_R2M_16(p) { + var list = coreNext16(); + var ripr = p.ea >> 3 == 4; + var Xn, An = p.ea & 7; + var a = exEAtab[ripr ? (2<<3|An) : p.ea](2); + var pre, inv = ripr ? 15 : 0; var n = 0; - for (var i = 0; i < 16; i++) { - if (sea.a & (1 << i)) { - var r = ldEA(dea, p.z); if (p.z == 2) r = extWord(r); - dea.a += p.z; + if (ripr) { /* pre-decrement */ + pre = 0; + for (Xn = 0; Xn < 16; Xn++) { + if (list & (1 << Xn)) pre += 2; + } + a -= pre; + /* p. 4-128: The MC68000 and MC68010 write the initial register value (not decremented). */ + if (model >= 68020) regs.a[An] -= pre; + } + for (Xn = 0; Xn < 16; Xn++) { + if (list & (1 << (Xn ^ inv))) { + if (Xn < 8) + corePut16(a, regs.d[Xn] & 0xffff); + else + corePut16(a, regs.a[Xn & 7] & 0xffff); - if (i < 8) { - regs.d[i] = r; - //BUG.say(sprintf('I_MOVEM_M2R.%s D%d d $%08x', szChr(p.z), i, regs.d[i])); - } else { - regs.a[i - 8] = r; - //BUG.say(sprintf('I_MOVEM_M2R.%s A%d d $%08x', szChr(p.z), i - 8, regs.a[i - 8])); - } + a += 2; n++; } } - if (p.d.m == M_ripo) { - //BUG.say(sprintf('I_MOVEM_M2R.%s RIPO old $%08x', szChr(p.z), regs.a[p.d.r])); - regs.a[p.d.r] = dea.a; - //BUG.say(sprintf('I_MOVEM_M2R.%s RIPO new $%08x', szChr(p.z), regs.a[p.d.r])); + if (ripr && model < 68020) regs.a[An] -= pre; + //ccna + coreSyncPC(); + return [p.cyc[0]+4*n,p.cyc[1],n]; + } + function I_MOVEM_R2M_32(p) { + var list = coreNext16(); + var ripr = p.ea >> 3 == 4; + var Xn, An = p.ea & 7; + var a = exEAtab[ripr ? (2<<3|An) : p.ea](4); + var pre, inv = ripr ? 15 : 0; + var n = 0; + + if (ripr) { /* pre-decrement */ + pre = 0; + for (Xn = 0; Xn < 16; Xn++) { + if (list & (1 << Xn)) pre += 4; + } + a -= pre; + /* p. 4-128: The MC68000 and MC68010 write the initial register value (not decremented). */ + if (model >= 68020) regs.a[An] -= pre; } - //ccna - //BUG.say(sprintf('I_MOVEM_M2R.%s s $%08x d $%08x', szChr(p.z), sea.a, dea.a)); - return [p.cyc[0] + (p.z == 2 ? 4 : 8) * n, 0,0]; //FIXME + for (Xn = 0; Xn < 16; Xn++) { + if (list & (1 << (Xn ^ inv))) { + if (Xn < 8) + corePut32(a, regs.d[Xn]); + else + corePut32(a, regs.a[Xn & 7]); + + a += 4; + n++; + } + } + if (ripr && model < 68020) regs.a[An] -= pre; + //ccna + coreSyncPC(); + return [p.cyc[0]+8*n,p.cyc[1],2*n]; } - function I_MOVEP(p) { - var sea = exEA(p.s, p.z); - var dea = exEA(p.d, p.z); + function I_MOVEM_M2R_16(p) { + var list = coreNext16(); + var ripo = p.ea >> 3 == 3; + var An = p.ea & 7; + var a = exEAtab[ripo ? (2<<3|An) : p.ea](2); + var n = 0; - //M2R - if (sea.m == M_rid) { - var r; + for (var Xn = 0; Xn < 16; Xn++) { + if (list & (1 << Xn)) { + if (Xn < 8) + regs.d[Xn] = extWord(coreGet16(a)); + else + regs.a[Xn & 7] = extWord(coreGet16(a)); - if (p.z == 2) { - r = ldEA(sea, 1) << 8; - sea.a += 2; - r += ldEA(sea, 1); - } else { - r = ldEA(sea, 1) << 24; - sea.a += 2; - r += ldEA(sea, 1) << 16; - sea.a += 2; - r += ldEA(sea, 1) << 8; - sea.a += 2; - r += ldEA(sea, 1); - r >>>= 0; + a += 2; + n++; } - //BUG.say(sprintf('I_MOVEP_M2R.%s A%d addr $%08x r $%08x', szChr(p.z), dea.a, sea.a - (p.z == 2 ? 4 : 8), r)); - stEA(dea, p.z, r); } - //R2M - else { - var r = ldEA(sea, p.z); + if (ripo) regs.a[An] = a; /* post-increment */ + //ccna + coreSyncPC(); + return [p.cyc[0]+4*n,p.cyc[1]+n,0]; + } + function I_MOVEM_M2R_32(p) { + var list = coreNext16(); + var ripo = p.ea >> 3 == 3; + var An = p.ea & 7; + var a = exEAtab[ripo ? (2<<3|An) : p.ea](4); + var n = 0; - if (p.z == 2) { - stEA(dea, 1, r >> 8); - dea.a += 2; - stEA(dea, 1, r); - } else { - stEA(dea, 1, r >> 24); - dea.a += 2; - stEA(dea, 1, r >> 16); - dea.a += 2; - stEA(dea, 1, r >> 8); - dea.a += 2; - stEA(dea, 1, r); + for (var Xn = 0; Xn < 16; Xn++) { + if (list & (1 << Xn)) { + if (Xn < 8) + regs.d[Xn] = coreGet32(a); + else + regs.a[Xn & 7] = coreGet32(a); + + a += 4; + n++; } - //BUG.say(sprintf('I_MOVEP_R2M.%s A%d addr $%08x r $%08x', szChr(p.z), sea.a, dea.a - (p.z == 2 ? 4 : 8), r)); } - //ccna + if (ripo) regs.a[An] = a; /* post-increment */ + //ccna + coreSyncPC(); + return [p.cyc[0]+8*n,p.cyc[1]+2*n,0]; + } + + function I_MOVEP_R2M_16(p) { + var dp = coreNext16(); + var s = regs.d[p.Dn] & 0xffff; + var a = add32(regs.a[p.An], extWord(dp)); + //SAEF_log("I_MOVEP_R2M_16 D%d A%d addr $%08x <- $%04x", p.Dn, p.An, a, s); + corePut8(a, s >> 8); + corePut8(a+2, s & 0xff); + //ccna + coreSyncPC(); + return p.cyc; + } + function I_MOVEP_R2M_32(p) { + var dp = coreNext16(); + var s = regs.d[p.Dn]; + var a = add32(regs.a[p.An], extWord(dp)); + //SAEF_log("I_MOVEP_R2M_32 D%d A%d addr $%08x <- $%08x", p.Dn, p.An, a, s); + corePut8(a, s >>> 24); + corePut8(a+2, (s >>> 16) & 0xff); + corePut8(a+4, (s >>> 8) & 0xff); + corePut8(a+6, s & 0xff); + //ccna + coreSyncPC(); + return p.cyc; + } + function I_MOVEP_M2R_16(p) { + var dp = coreNext16(); + var a = add32(regs.a[p.An], extWord(dp)); + var d = (coreGet8(a) << 8) | corePut8(a+2); + //SAEF_log("I_MOVEP_M2R_16 A%d D%d addr $%08x -> $%04x", p.An, p.Dn, a, d); + regs.d[p.Dn] = (regs.d[p.Dn] & 0xffff0000) | d; + //ccna + coreSyncPC(); + return p.cyc; + } + function I_MOVEP_M2R_32(p) { + var dp = coreNext16(); + var a = add32(regs.a[p.An], extWord(dp)); + var d = ((coreGet8(a) << 24) | (coreGet8(a+2) << 16) | (coreGet8(a+4) << 8) | corePut8(a+6)) >>> 0; + //SAEF_log("I_MOVEP_M2R_32 A%d D%d addr $%08x -> $%08x", p.An, p.Dn, a, d); + regs.d[p.Dn] = d; + //ccna + coreSyncPC(); return p.cyc; } /*-----------------------------------------------------------------------*/ - /* Integer Arithmetic */ - - function I_ADD(p) { - var sea = exEA(p.s, p.z); - var s = ldEA(sea, p.z); - var dea = exEA(p.d, p.z); - var d = ldEA(dea, p.z); - var r = addAuto(s, d, p.z); - stEA(dea, p.z, r); - flgAdd(s, d, r, p.z, false); - //BUG.say(sprintf('I_ADD.%s s $%08x d $%08x r $%08x', szChr(p.z), s, d, r)); - return p.cyc; - } + /* Integer Arithmetic - Basic */ - function I_ADDA(p) { - var sea = exEA(p.s, p.z); - var s = ldEA(sea, p.z); if (p.z == 2) s = extWord(s); - var dea = exEA(p.d, 4); - var d = ldEA(dea, 4); - var r = add32(s, d); - stEA(dea, 4, r); - //ccna - //BUG.say(sprintf('I_ADDA.%s s $%08x d $%08x r $%08x', szChr(p.z), s, d, r)); - return p.cyc; - } - - function I_ADDI(p) { - var sea = exEA(p.s, p.z); - var s = ldEA(sea, p.z); - var dea = exEA(p.d, p.z); - var d = ldEA(dea, p.z); - var r = addAuto(s, d, p.z); - stEA(dea, p.z, r); - flgAdd(s, d, r, p.z, false); - //BUG.say(sprintf('I_ADDI.%s s $%08x d $%08x r $%08x', szChr(p.z), s, d, r)); - return p.cyc; - } - - /*function I_ADDQ(p) { - var sea = exEA(p.s, p.z); - var s = ldEA(sea, p.z); - if (p.d.m == M_rda) { - var dea = exEA(p.d, 4); - var d = ldEA(dea, 4); - var r = add32(s, d); - stEA(dea, 4, r); - //ccna - //return 8; - } else { - var dea = exEA(p.d, p.z); - var d = ldEA(dea, p.z); - var r = addAuto(s, d, p.z); - stEA(dea, p.z, r); - flgAdd(s, d, r, p.z, false); - //return dea.m == M_rdd ? (p.z == 4 ? 8 : 4) : (p.z == 4 ? 12 : 8) + dea.c; - } - //BUG.say(sprintf('I_ADDQ.%s s $%08x d $%08x r $%08x', szChr(p.z), s, d, r)); - return p.cyc; - }*/ - - function I_ADDQ(p) { - var sea = exEA(p.s, p.z); - var s = ldEA(sea, p.z); - var dea = exEA(p.d, p.z); - var d = ldEA(dea, p.z); - var r = addAuto(s, d, p.z); - stEA(dea, p.z, r); - flgAdd(s, d, r, p.z, false); - //BUG.say(sprintf('I_ADDQ.%s s $%08x d $%08x r $%08x', szChr(p.z), s, d, r)); + function I_ADD_ED_32(p) { + var s = ldEA32tab[p.ea](); + var d = regs.d[p.Dn]; + var r = s + d; if (r > 0xffffffff) r -= 0x100000000; + regs.d[p.Dn] = r; + flgAdd(s, d, r, 0x80000000, false); + //SAEF_log(("I_ADD_ED.L %08x + %08x = %08x", s, d, r)); + coreSyncPC(); return p.cyc; } - function I_ADDQA(p) { - var sea = exEA(p.s, p.z); - var s = ldEA(sea, p.z); - var dea = exEA(p.d, 4); - var d = ldEA(dea, 4); - var r = add32(s, d); - stEA(dea, 4, r); - //ccna - //BUG.say(sprintf('I_ADDQA.%s s $%08x d $%08x r $%08x', szChr(p.z), s, d, r)); + function I_ADD_DE_32(p) { + var a = exEAtab[p.ea](4); + var s = regs.d[p.Dn]; + var d = coreGet32(a); + var r = s + d; if (r > 0xffffffff) r -= 0x100000000; + corePut32(a, r); + flgAdd(s, d, r, 0x80000000, false); + //SAEF_log(("I_ADD_DE.L %08x + %08x = %08x", s, d, r)); + coreSyncPC(); + return p.cyc; + } + function I_ADD_ED_16(p) { + var s = ldEA16tab[p.ea](); + var d = regs.d[p.Dn] & 0xffff; + var r = s + d; if (r > 0xffff) r -= 0x10000; + regs.d[p.Dn] = (regs.d[p.Dn] & 0xffff0000) | r; + flgAdd(s, d, r, 0x8000, false); + //SAEF_log(("I_ADD_ED.W %08x + %08x = %08x", s, d, r)); + coreSyncPC(); + return p.cyc; + } + function I_ADD_DE_16(p) { + var a = exEAtab[p.ea](2); + var s = regs.d[p.Dn] & 0xffff; + var d = coreGet16(a); + var r = s + d; if (r > 0xffff) r -= 0x10000; + corePut16(a, r); + flgAdd(s, d, r, 0x8000, false); + //SAEF_log(("I_ADD_DE.W %08x + %08x = %08x", s, d, r)); + coreSyncPC(); + return p.cyc; + } + function I_ADD_ED_8(p) { + var s = ldEA8tab[p.ea](); + var d = regs.d[p.Dn] & 0xff; + var r = s + d; if (r > 0xff) r -= 0x100; + regs.d[p.Dn] = (regs.d[p.Dn] & 0xffffff00) | r; + flgAdd(s, d, r, 0x80, false); + //SAEF_log(("I_ADD_ED.B %08x + %08x = %08x", s, d, r)); + coreSyncPC(); + return p.cyc; + } + function I_ADD_DE_8(p) { + var a = exEAtab[p.ea](1); + var s = regs.d[p.Dn] & 0xff; + var d = coreGet8(a); + var r = s + d; if (r > 0xff) r -= 0x100; + corePut8(a, r); + flgAdd(s, d, r, 0x80, false); + //SAEF_log(("I_ADD_DE.B %08x + %08x = %08x", s, d, r)); + coreSyncPC(); return p.cyc; } - function I_ADDX(p) { - var sea = exEA(p.s, p.z); - var s = ldEA(sea, p.z); - var dea = exEA(p.d, p.z); - var d = ldEA(dea, p.z); - var r = addAuto(s, d, p.z); if (regs.x) r = addAuto(r, 1, p.z); - //var _x = regs.x?1:0; - stEA(dea, p.z, r); - flgAdd(s, d, r, p.z, true); - //BUG.say(sprintf('I_ADDX.%s s $%08x d $%08x xo %d xn %d r $%08x', szChr(p.z), s, d, _x, regs.x?1:0, r)); + function I_SUB_ED_32(p) { + var s = ldEA32tab[p.ea](); + var d = regs.d[p.Dn]; + var r = d - s; if (r < 0) r += 0x100000000; + regs.d[p.Dn] = r; + flgSub(s, d, r, 0x80000000, false); + //SAEF_log(("I_SUB_ED.L %08x - %08x = %08x", s, d, r)); + coreSyncPC(); + return p.cyc; + } + function I_SUB_DE_32(p) { + var a = exEAtab[p.ea](4); + var s = regs.d[p.Dn]; + var d = coreGet32(a); + var r = d - s; if (r < 0) r += 0x100000000; + corePut32(a, r); + flgSub(s, d, r, 0x80000000, false); + //SAEF_log(("I_SUB_DE.L %08x - %08x = %08x", s, d, r)); + coreSyncPC(); + return p.cyc; + } + function I_SUB_ED_16(p) { + var s = ldEA16tab[p.ea](); + var d = regs.d[p.Dn] & 0xffff; + var r = d - s; if (r < 0) r += 0x10000; + regs.d[p.Dn] = (regs.d[p.Dn] & 0xffff0000) | r; + flgSub(s, d, r, 0x8000, false); + //SAEF_log(("I_SUB_ED.W %08x - %08x = %08x", s, d, r)); + coreSyncPC(); + return p.cyc; + } + function I_SUB_DE_16(p) { + var a = exEAtab[p.ea](2); + var s = regs.d[p.Dn] & 0xffff; + var d = coreGet16(a); + var r = d - s; if (r < 0) r += 0x10000; + corePut16(a, r); + flgSub(s, d, r, 0x8000, false); + //SAEF_log(("I_SUB_DE.W %08x - %08x = %08x", s, d, r)); + coreSyncPC(); + return p.cyc; + } + function I_SUB_ED_8(p) { + var s = ldEA8tab[p.ea](); + var d = regs.d[p.Dn] & 0xff; + var r = d - s; if (r < 0) r += 0x100; + regs.d[p.Dn] = (regs.d[p.Dn] & 0xffffff00) | r; + flgSub(s, d, r, 0x80, false); + //SAEF_log(("I_SUB_ED.B %08x - %08x = %08x", s, d, r)); + coreSyncPC(); + return p.cyc; + } + function I_SUB_DE_8(p) { + var a = exEAtab[p.ea](1); + var s = regs.d[p.Dn] & 0xff; + var d = coreGet8(a); + var r = d - s; if (r < 0) r += 0x100; + corePut8(a, r); + flgSub(s, d, r, 0x80, false); + //SAEF_log(("I_SUB_DE.B %08x - %08x = %08x", s, d, r)); + coreSyncPC(); return p.cyc; } - function I_CLR(p) { - var dea = exEA(p.d, p.z); - //var foo = ldEA(dea, p.z); /* In the MC68000 and MC68008 a memory location is read before it is cleared. */ - stEA(dea, p.z, 0); + function I_CMP_32(p) { + var s = ldEA32tab[p.ea](); + var d = regs.d[p.Dn]; + var r = d - s; if (r < 0) r += 0x100000000; + flgCmp(s, d, r, 0x80000000); + //SAEF_log(("I_CMP.L %08x - %08x", d, s)); + coreSyncPC(); + return p.cyc; + } + function I_CMP_16(p) { + var s = ldEA16tab[p.ea](); + var d = regs.d[p.Dn] & 0xffff; + var r = d - s; if (r < 0) r += 0x10000; + flgCmp(s, d, r, 0x8000); + //SAEF_log(("I_CMP.W %08x - %08x", d, s)); + coreSyncPC(); + return p.cyc; + } + function I_CMP_8(p) { + var s = ldEA8tab[p.ea](); + var d = regs.d[p.Dn] & 0xff; + var r = d - s; if (r < 0) r += 0x100; + flgCmp(s, d, r, 0x80); + //SAEF_log(("I_CMP.B %08x - %08x", d, s)); + coreSyncPC(); + return p.cyc; + } - regs.n = false; - regs.z = true; + function I_CLR_32(p) { + stEA32tab[p.ea](0); + regs.z = true; regs.n = regs.v = regs.c = false; + coreSyncPC(); + return p.cyc; + } + function I_CLR_16(p) { + stEA16tab[p.ea](0); + regs.z = true; regs.n = regs.v = regs.c = false; + coreSyncPC(); + return p.cyc; + } + function I_CLR_8(p) { + stEA8tab[p.ea](0); + regs.z = true; regs.n = regs.v = regs.c = false; + coreSyncPC(); + return p.cyc; + } + + function I_NEG_D_32(p) { + var d = regs.d[p.Dn]; + var r = 0 - d; if (r < 0) r += 0x100000000; + regs.d[p.Dn] = r; + flgNeg(d, r, 0x80000000, false); + //SAEF_log(("I_NEG_D.L -%08x = %08x", d, r)); + coreSyncPC(); + return p.cyc; + } + function I_NEG_D_16(p) { + var d = regs.d[p.Dn] & 0xffff; + var r = 0 - d; if (r < 0) r += 0x10000; + regs.d[p.Dn] = (regs.d[p.Dn] & 0xffff0000) | r; + flgNeg(d, r, 0x8000, false); + //SAEF_log(("I_NEG_D.W -%08x = %08x", d, r)); + coreSyncPC(); + return p.cyc; + } + function I_NEG_D_8(p) { + var d = regs.d[p.Dn] & 0xff; + var r = 0 - d; if (r < 0) r += 0x100; + regs.d[p.Dn] = (regs.d[p.Dn] & 0xffffff00) | r; + flgNeg(d, r, 0x80, false); + //SAEF_log(("I_NEG_D.B -%08x = %08x", d, r)); + coreSyncPC(); + return p.cyc; + } + function I_NEG_E_32(p) { + var a = exEAtab[p.ea](4); + var d = coreGet32(a); + var r = 0 - d; if (r < 0) r += 0x100000000; + corePut32(a, r); + flgNeg(d, r, 0x80000000, false); + //SAEF_log(("I_NEG_E.L -%08x = %08x", d, r)); + coreSyncPC(); + return p.cyc; + } + function I_NEG_E_16(p) { + var a = exEAtab[p.ea](2); + var d = coreGet16(a); + var r = 0 - d; if (r < 0) r += 0x10000; + corePut16(a, r); + flgNeg(d, r, 0x8000, false); + //SAEF_log(("I_NEG_E.W -%08x = %08x", d, r)); + coreSyncPC(); + return p.cyc; + } + function I_NEG_E_8(p) { + var a = exEAtab[p.ea](1); + var d = coreGet8(a); + var r = 0 - d; if (r < 0) r += 0x100; + corePut8(a, r); + flgNeg(d, r, 0x80, false); + //SAEF_log(("I_NEG_E.B -%08x = %08x", d, r)); + coreSyncPC(); + return p.cyc; + } + + function I_MULS(p) { + var s = ldEA16tab[p.ea](); + var d = regs.d[p.Dn] & 0xffff; + var sign = s ^ d; + if (s & 0x8000) s = -s + 0x10000; + if (d & 0x8000) d = -d + 0x10000; + var r = s * d; if (r && (sign & 0x8000)) r = -r + 0x100000000; + regs.d[p.Dn] = r; + regs.n = (r & 0x80000000) != 0; + regs.z = r == 0; regs.v = false; regs.c = false; - //BUG.say(sprintf('I_CLR.%s', szChr(p.z))); + //if (regs.n) SAEF_log(("I_MULS.W %08x * %08x = %08x", s, d, r)); + coreSyncPC(); return p.cyc; } - function I_CMP(p) { - var sea = exEA(p.s, p.z); - var s = ldEA(sea, p.z); - var dea = exEA(p.d, p.z); - var d = ldEA(dea, p.z); - var r = subAuto(d, s, p.z); - flgCmp(s, d, r, p.z); - //BUG.say(sprintf('I_CMP.%s s $%08x d $%08x r $%08x', szChr(p.z), s, d, r)); - return p.cyc; - } - - function I_CMPA(p) { - var sea = exEA(p.s, p.z); - var s = ldEA(sea, p.z); if (p.z == 2) s = extWord(s); - var dea = exEA(p.d, 4); - var d = ldEA(dea, 4); - var r = sub32(d, s); - flgCmp(s, d, r, 4); - //BUG.say(sprintf('I_CMPA.%s s $%08x d $%08x r $%08x', szChr(p.z), s, d, r)); - return p.cyc; - } - - function I_CMPI(p) { - var sea = exEA(p.s, p.z); - var s = ldEA(sea, p.z); - var dea = exEA(p.d, p.z); - var d = ldEA(dea, p.z); - var r = subAuto(d, s, p.z); - flgCmp(s, d, r, p.z); - //BUG.say(sprintf('I_CMPI.%s s $%08x d $%08x r $%08x', szChr(p.z), s, d, r)); + function I_MULU(p) { + var s = ldEA16tab[p.ea](); + var d = regs.d[p.Dn] & 0xffff; + var r = s * d; + regs.d[p.Dn] = r; + regs.n = (r & 0x80000000) != 0; + regs.z = r == 0; + regs.v = false; + regs.c = false; + //SAEF_log(("I_MULU.W %08x * %08x = %08x", s, d, r)); + coreSyncPC(); return p.cyc; } - function I_CMPM(p) { - var sea = exEA(p.s, p.z); - var s = ldEA(sea, p.z); - var dea = exEA(p.d, p.z); - var d = ldEA(dea, p.z); - var r = subAuto(d, s, p.z); - flgCmp(s, d, r, p.z); - //BUG.say(sprintf('I_CMPM.%s s $%08x d $%08x r $%08x | %c', szChr(p.z), s, d, r, s)); + function I_MULx(p) { /* >= 68020 */ + var ext = coreNext16(); + var multiplier = ldEA32tab[p.ea](); + var Dl = (ext >> 12) & 7; + var multiplicand = regs.d[Dl]; + var productLo, productHi; + var _a = multiplier, _b = multiplicand; //debug + + if (ext & 0x800) { + var sign = ((multiplier ^ multiplicand) & 0x80000000) != 0; + if (multiplier & 0x80000000) multiplier = -multiplier + 0x100000000; + if (multiplicand & 0x80000000) multiplicand = -multiplicand + 0x100000000; + if (multiplier < 0x8000 && multiplicand < 0x8000) { + productLo = multiplier * multiplicand; + productHi = 0; + if (productLo && sign) { + productLo = -productLo + 0x100000000; + productHi = 0xffffffff; + } + regs.v = false; + //SAEF_log("I_MULS.L $%04x, %d * %d = [%08x:%08x] | PC %08x", ext, castLong(_a),castLong(_b), productHi,productLo, getPC()); + } else { + var result = mul64(multiplier, multiplicand); + productLo = result[0]; + productHi = result[1]; + if (sign) { + productHi = ~productHi >>> 0; + if (productLo) productLo = -productLo + 0x100000000; + if (productLo == 0) { productHi++; if (productHi > 0xffffffff) productHi -= 0x100000000; } + } + regs.v = (ext & 0x400) == 0 && (productHi != 0 || (productLo & 0x80000000) != 0) && ((productHi & 0xffffffff) != 0xffffffff || (productLo & 0x80000000) != 0x80000000); + //SAEF_log("I_MULS64.L $%04x, %d * %d = [%08x:%08x] | v %d, PC %08x", ext, castLong(_a),castLong(_b), productHi,productLo, regs.v?1:0, getPC()); + } + } else { + if (multiplier < 0x10000 && multiplicand < 0x10000) { + productLo = multiplier * multiplicand; + productHi = 0; + regs.v = false; + //SAEF_log("I_MULU.L $%04x, %d * %d = [%08x:%08x] | PC %08x", ext, _a,_b, productHi,productLo, getPC()); + } else { + var result = mul64(multiplier, multiplicand); + productLo = result[0]; + productHi = result[1]; + //SAEF_log("I_MULU64.L $%04x, %d * %d = [%08x:%08x] | PC %08x", ext, _a,_b, productHi,productLo, getPC()); + } + regs.v = (ext & 0x400) == 0 && productHi != 0; + } + regs.d[Dl] = productLo; + if (ext & 0x400) regs.d[ext & 7] = productHi; + regs.n = (productHi & 0x80000000) != 0; + regs.z = productHi == 0 && productLo == 0; + regs.c = false; + + coreSyncPC(); return p.cyc; } function I_DIVS(p) { - var sea = exEA(p.s, p.z); - var s = ldEA(sea, p.z); s = castWord(s); - var dea = exEA(p.d, 4); - var d = ldEA(dea, 4); d = castLong(d); + var s = ldEA16tab[p.ea](); regs.c = false; if (s == 0) { - BUG.say(sprintf('I_DIVS NULL $%08x / $%08x', d, s)); - regs.pc = fault.pc; - return exception(5); + //SAEF_log(("I_DIVS.W %08x / 0 (coreException 5)", regs.d[p.Dn])); + //coreSyncPC(); + return coreException(5); } else { - var quo = ~~(d / s); /* Thanks 'dmcoles' */ - - if (quo < 0) quo += 0x10000; - - if (quo < 0 || quo > 0xffff) { + var d = regs.d[p.Dn], ds = d; + var sign = ((d & 0x80000000) ? 1 : 0) ^ ((s & 0x8000) ? 1 : 0); + if (s & 0x8000) s = -s + 0x10000; + if (d & 0x80000000) d = -d + 0x100000000; + var quo = (d / s) >>> 0; + if (sign ? quo > 0x8000 : quo > 0x7fff) { regs.v = true; - //BUG.say(sprintf('I_DIVS.%s $%08x / $%08x = OVERFLOW (quo $%08x | rem $%08x)', szChr(p.z), d, s, quo, rem)); + //SAEF_log(("I_DIVS.W %d / %d = %d OVERFLOW", d,s, quo)); } else { var rem = d % s; - - if (rem && ((rem < 0) != (d < 0))) rem = -rem; - if (rem < 0) rem += 0x10000; - + if (quo && sign) quo = -quo + 0x10000; + if (rem && (rem >> 15) != (ds >>> 31)) rem = -rem + 0x10000; + regs.d[p.Dn] = (rem << 16) | quo; regs.v = false; regs.z = quo == 0; regs.n = (quo & 0x8000) != 0; - - var r = ((rem << 16) | quo) >>> 0; - stEA(dea, 4, r); - //BUG.say(sprintf('I_DIVS.%s $%08x / $%08x = $%08x (quo $%08x | rem $%08x)', szChr(p.z), d, s, r, quo, rem)); + //SAEF_log(("I_DIVS.W %d / %d = %d[%04x:%04x] sign %x", d,s,regs.d[p.Dn], rem,quo, sign)); } + coreSyncPC(); return p.cyc; } } function I_DIVU(p) { - var sea = exEA(p.s, p.z); - var s = ldEA(sea, p.z); - var dea = exEA(p.d, 4); - var d = ldEA(dea, 4); + var s = ldEA16tab[p.ea](); regs.c = false; if (s == 0) { - BUG.say(sprintf('I_DIVU NULL $%08x / $%08x', d, s)); - regs.pc = fault.pc; - return exception(5); + //SAEF_log(("I_DIVU.%s %08x / 0 (coreException 5)", regs.d[p.Dn])); + //coreSyncPC(); + return coreException(5); } else { - var quo = Math.floor(d / s); - + var d = regs.d[p.Dn]; + var quo = (d / s) >>> 0; if (quo > 0xffff) { regs.v = true; - //BUG.say(sprintf('I_DIVU.%s $%08x / $%08x = OVERFLOW (quo $%08x | rem $%08x)', szChr(p.z), d, s, quo, rem)); + //SAEF_log(("I_DIVU.W %d / %d = %d OVERFLOW", d,s, quo)); } else { var rem = d % s; - - if (rem && (!!(rem & 0x8000) != !!(d & 0x80000000))) { - //var oldrem = rem; - rem = -rem + 0x10000; - //BUG.say(sprintf('I_DIVU d $%08x oldrem $%08x rem $%08x', d, oldrem, rem)); - } + regs.d[p.Dn] = (rem << 16) | quo; regs.v = false; regs.z = quo == 0; regs.n = (quo & 0x8000) != 0; - - var r = ((rem << 16) | quo) >>> 0; - stEA(dea, 4, r); - //BUG.say(sprintf('I_DIVU.%s $%08x / $%08x = $%08x (quo $%08x | rem $%08x)', szChr(p.z), d, s, r, quo, rem)); + //SAEF_log(("I_DIVU.W %d / %d = %d[%d:%d]", d,s,regs.d[p.Dn], rem,quo)); } + coreSyncPC(); return p.cyc; } } - function I_EXT(p) { - var z = p.z == 2 ? 1 : 2; - var dea = exEA(p.d, z); - var d = ldEA(dea, z); - var r = p.z == 2 ? extByteToWord(d) : extWord(d); - stEA(dea, p.z, r); - flgLogical(r, p.z); - //BUG.say(sprintf('I_EXT.%s d $%08x r $%08x', szChr(p.z), d, r)); - return p.cyc; - } + function I_DIVx(p) { /* >= 68020 */ + var ext = coreNext16(); + var divisor = ldEA32tab[p.ea](); + var Dq = (ext >> 12) & 7; + var Dr = ext & 7; + var quo, rem; + //var quotient, remainder; - function I_MULS(p) { - var sea = exEA(p.s, p.z); - var s = ldEA(sea, p.z); s = castWord(s); - var dea = exEA(p.d, p.z); - var d = ldEA(dea, p.z); d = castWord(d); - var r = s * d; - if (r < 0) r += 0x100000000; - stEA(dea, 4, r); - - regs.v = false; /* not possible for 16x16 */ regs.c = false; - regs.n = (r & 0x80000000) != 0; - regs.z = r == 0; - //BUG.say(sprintf('I_MULS.%s s $%08x d $%08x r $%08x', szChr(p.z), s, d, r)); - return p.cyc; - } + if (divisor == 0) { + //SAEF_log(("I_DIV%s.L %08x / 0 (coreException 5)", (ext&0x800)?"S":"U", divisor)); + //coreSyncPC(); + return coreException(5); + } - function I_MULU(p) { - var sea = exEA(p.s, p.z); - var s = ldEA(sea, p.z); - var dea = exEA(p.d, p.z); - var d = ldEA(dea, p.z); - var r = s * d; - stEA(dea, 4, r); + if (ext & 0x800) { + if (ext & 0x400) { + var dividendLo = regs.d[Dq]; + var dividendHi = regs.d[Dr], orgDividendHi = dividendHi; + var sign = ((dividendHi ^ divisor) & 0x80000000) != 0; - regs.v = false; /* not possible for 16x16 */ - regs.c = false; - regs.n = (r & 0x80000000) != 0; - regs.z = r == 0; - //BUG.say(sprintf('I_MULU.%s s $%08x d $%08x r $%08x', szChr(p.z), s, d, r)); - return p.cyc; - } + if (dividendHi & 0x80000000) { + dividendHi = ~dividendHi >>> 0; + if (dividendLo) dividendLo = -dividendLo + 0x100000000; + if (dividendLo == 0) { dividendHi++; if (dividendHi > 0xffffffff) dividendHi -= 0x100000000; } + } + if (divisor & 0x80000000) divisor = -divisor + 0x100000000; - function I_NEG(p) { - var dea = exEA(p.d, p.z); - var d = ldEA(dea, p.z); - var r = subAuto(0, d, p.z); - stEA(dea, p.z, r); - flgNeg(d, r, p.z, false); - //BUG.say(sprintf('I_NEG.%s d $%08x r $%08x', szChr(p.z), d, r)); - return p.cyc; - } - - function I_NEGX(p) { - var dea = exEA(p.d, p.z); - var d = ldEA(dea, p.z); - var r = subAuto(0, d, p.z); if (regs.x) r = subAuto(r, 1, p.z); - stEA(dea, p.z, r); - flgNeg(d, r, p.z, true); - //BUG.say(sprintf('I_NEGX.%s d $%08x x %d r $%08x', szChr(p.z), d, regs.x ? 1 : 0, r)); - return p.cyc; - } + var result = divu64(dividendHi, dividendLo, divisor); + quo = result[1]; + rem = result[2]; + if (result[0] || sign ? quo > 0x80000000 : quo > 0x7fffffff) { + regs.v = true; + //SAEF_log("I_DIVS64.L %d:%d / %d OVERFLOW", dividendHi,dividendLo,divisor); + coreSyncPC(); + return p.cyc; + } + if (quo && sign) quo = -quo + 0x100000000; + if (rem && (rem & 0x80000000) != (orgDividendHi & 0x80000000)) rem = -rem + 0x100000000; + //SAEF_log("I_DIVS64.L %d:%d / %d = [%08x:%08x] | PC %08x", dividendHi,dividendLo,divisor, rem,quo, getPC()); + } else { + var dividend = regs.d[Dq], orgDividend = dividend; + var sign = ((dividend ^ divisor) & 0x80000000) != 0; - function I_SUB(p) { - var sea = exEA(p.s, p.z); - var s = ldEA(sea, p.z); - var dea = exEA(p.d, p.z); - var d = ldEA(dea, p.z); - var r = subAuto(d, s, p.z); - stEA(dea, p.z, r); - flgSub(s, d, r, p.z, false); - //BUG.say(sprintf('I_SUB.%s s $%08x d $%08x r $%08x', szChr(p.z), s, d, r)); - return p.cyc; - } + if (dividend & 0x80000000) dividend = -dividend + 0x100000000; + if (divisor & 0x80000000) divisor = -divisor + 0x100000000; - function I_SUBA(p) { - var sea = exEA(p.s, p.z); - var s = ldEA(sea, p.z); if (p.z == 2) s = extWord(s); - var dea = exEA(p.d, 4); - var d = ldEA(dea, 4); - var r = sub32(d, s); - stEA(dea, 4, r); - //ccna - //BUG.say(sprintf('I_SUBA.%s s $%08x d $%08x r $%08x', szChr(p.z), s, d, r)); - return p.cyc; - } - - function I_SUBI(p) { - var sea = exEA(p.s, p.z); - var s = ldEA(sea, p.z); - var dea = exEA(p.d, p.z); - var d = ldEA(dea, p.z); - var r = subAuto(d, s, p.z); - stEA(dea, p.z, r); - flgSub(s, d, r, p.z, false); - //BUG.say(sprintf('I_SUBI.%s s $%08x d $%08x r $%08x', szChr(p.z), s, d, r)); - return p.cyc; - } - - /*function I_SUBQ(p) { - var sea = exEA(p.s, p.z); - var s = ldEA(sea, p.z); - if (p.d.m == M_rda) { - var dea = exEA(p.d, 4); - var d = ldEA(dea, 4); - var r = sub32(d, s); - stEA(dea, 4, r); - //ccna - //return 8; + quo = (dividend / divisor) >>> 0; + if (sign ? quo > 0x80000000 : quo > 0x7fffffff) { + regs.v = true; + //SAEF_log("I_DIVS.L %d / %d OVERFLOW", dividend,divisor); + coreSyncPC(); + return p.cyc; + } + rem = dividend % divisor; + if (quo && sign) quo = -quo + 0x100000000; + if (rem && (rem & 0x80000000) != (orgDividend & 0x80000000)) rem = -rem + 0x100000000; + //SAEF_log("I_DIVS.L %d / %d = [%08x:%08x] | PC %08x", dividend,divisor, rem,quo, getPC()); + } } else { - var dea = exEA(p.d, p.z); - var d = ldEA(dea, p.z); - var r = subAuto(d, s, p.z); - stEA(dea, p.z, r); - flgSub(s, d, r, p.z, false); - //return dea.m == M_rdd ? (p.z == 4 ? 8 : 4) : (p.z == 4 ? 12 : 8) + dea.c; - } - //BUG.say(sprintf('I_SUBQ.%s s $%08x d $%08x r $%08x', szChr(p.z), s, d, r)); - return p.cyc; - }*/ - - function I_SUBQ(p) { - var sea = exEA(p.s, p.z); - var s = ldEA(sea, p.z); - var dea = exEA(p.d, p.z); - var d = ldEA(dea, p.z); - var r = subAuto(d, s, p.z); - stEA(dea, p.z, r); - flgSub(s, d, r, p.z, false); - //BUG.say(sprintf('I_SUBQ.%s s $%08x d $%08x r $%08x', szChr(p.z), s, d, r)); - return p.cyc; - } - function I_SUBQA(p) { - var sea = exEA(p.s, p.z); - var s = ldEA(sea, p.z); - var dea = exEA(p.d, 4); - var d = ldEA(dea, 4); - var r = sub32(d, s); - stEA(dea, 4, r); - //ccna - //BUG.say(sprintf('I_SUBQA.%s s $%08x d $%08x r $%08x', szChr(p.z), s, d, r)); + if (ext & 0x400) { + var result = divu64(regs.d[Dr], regs.d[Dq], divisor); + if (result[0]) { + regs.v = true; + //SAEF_log("I_DIVU64.L %d:%d / %d OVERFLOW", regs.d[Dr],regs.d[Dq],divisor); + coreSyncPC(); + return p.cyc; + } + quo = result[1]; + rem = result[2]; + //SAEF_log("I_DIVU64.L %d:%d / %d = [%08x:%08x] | PC %08x", regs.d[Dr],regs.d[Dq],divisor, rem,quo, getPC()); + } else { + quo = (regs.d[Dq] / divisor) >>> 0; + rem = regs.d[Dq] % divisor; + //SAEF_log("I_DIVU.L %d / %d = [%08x:%08x] | PC %08x", regs.d[Dq],divisor, rem,quo, getPC()); + } + } + regs.d[Dq] = quo; + if (Dr != Dq) regs.d[Dr] = rem; + regs.v = false; + regs.z = quo == 0; + regs.n = (quo & 0x80000000) != 0; + + coreSyncPC(); return p.cyc; } - function I_SUBX(p) { - var sea = exEA(p.s, p.z); - var s = ldEA(sea, p.z); - var dea = exEA(p.d, p.z); - var d = ldEA(dea, p.z); - var r = subAuto(d, s, p.z); if (regs.x) r = subAuto(r, 1, p.z); - //var _x = regs.x?1:0; - stEA(dea, p.z, r); - flgSub(s, d, r, p.z, true); - //BUG.say(sprintf('I_SUBX.%s s $%08x d $%08x xo %d xn %d r $%08x', szChr(p.z), s, d, _x, regs.x?1:0, r)); + /*-----------------------------------------------------------------------*/ + /* Integer Arithmetic - Extended */ + + function I_ADDX_D_32(p) { + var s = regs.d[p.Ry]; + var d = regs.d[p.Rx]; + var r = s + d + (regs.x ? 1:0); if (r > 0xffffffff) r -= 0x100000000; + regs.d[p.Rx] = r; + //SAEF_log(("I_ADDX_D.L %08x + %08x + %d = %08x", s, d, regs.x?1:0, r)); + flgAdd(s, d, r, 0x80000000, true); + coreSyncPC(); return p.cyc; } - + function I_ADDX_D_16(p) { + var s = regs.d[p.Ry] & 0xffff; + var d = regs.d[p.Rx] & 0xffff; + var r = s + d + (regs.x ? 1:0); if (r > 0xffff) r -= 0x10000; + regs.d[p.Rx] = (regs.d[p.Rx] & 0xffff0000) | r; + //SAEF_log(("I_ADDX_D.W %08x + %08x + %d = %08x", s, d, regs.x?1:0, r)); + flgAdd(s, d, r, 0x8000, true); + coreSyncPC(); + return p.cyc; + } + function I_ADDX_D_8(p) { + var s = regs.d[p.Ry] & 0xff; + var d = regs.d[p.Rx] & 0xff; + var r = s + d + (regs.x ? 1:0); if (r > 0xff) r -= 0x100; + regs.d[p.Rx] = (regs.d[p.Rx] & 0xffffff00) | r; + //SAEF_log(("I_ADDX_D.B %08x + %08x + %d = %08x", s, d, regs.x?1:0, r)); + flgAdd(s, d, r, 0x80, true); + coreSyncPC(); + return p.cyc; + } + + function I_ADDX_M_32(p) { + regs.a[p.Ry] -= 4; var s = coreGet32(regs.a[p.Ry]); + regs.a[p.Rx] -= 4; var d = coreGet32(regs.a[p.Rx]); + var r = s + d + (regs.x ? 1:0); if (r > 0xffffffff) r -= 0x100000000; + corePut32(regs.a[p.Rx], r); + //SAEF_log(("I_ADDX_M.L %08x + %08x + %d = %08x", s, d, regs.x?1:0, r)); + flgAdd(s, d, r, 0x80000000, true); + coreSyncPC(); + return p.cyc; + } + function I_ADDX_M_16(p) { + regs.a[p.Ry] -= 2; var s = coreGet16(regs.a[p.Ry]); + regs.a[p.Rx] -= 2; var d = coreGet16(regs.a[p.Rx]); + var r = s + d + (regs.x ? 1:0); if (r > 0xffff) r -= 0x10000; + corePut16(regs.a[p.Rx], r); + //SAEF_log(("I_ADDX_M.W %08x + %08x + %d = %08x", s, d, regs.x?1:0, r)); + flgAdd(s, d, r, 0x8000, true); + coreSyncPC(); + return p.cyc; + } + function I_ADDX_M_8(p) { + regs.a[p.Ry] -= aIncDec[1][p.Ry]; var s = coreGet8(regs.a[p.Ry]); + regs.a[p.Rx] -= aIncDec[1][p.Rx]; var d = coreGet8(regs.a[p.Rx]); + var r = s + d + (regs.x ? 1:0); if (r > 0xff) r -= 0x100; + corePut8(regs.a[p.Rx], r); + //SAEF_log(("I_ADDX_M.B %08x + %08x + %d = %08x", s, d, regs.x?1:0, r)); + flgAdd(s, d, r, 0x80, true); + coreSyncPC(); + return p.cyc; + } + + function I_SUBX_D_32(p) { + var s = regs.d[p.Rx]; + var d = regs.d[p.Ry]; + var r = d - s - (regs.x ? 1:0); if (r < 0) r += 0x100000000; + regs.d[p.Ry] = r; + //SAEF_log(("I_SUBX_D.L %08x - %08x - %d = %08x", d, s, regs.x?1:0, r)); + flgSub(s, d, r, 0x80000000, true); + coreSyncPC(); + return p.cyc; + } + function I_SUBX_D_16(p) { + var s = regs.d[p.Rx] & 0xffff; + var d = regs.d[p.Ry] & 0xffff; + var r = d - s - (regs.x ? 1:0); if (r < 0) r += 0x10000; + regs.d[p.Ry] = (regs.d[p.Ry] & 0xffff0000) | r; + //SAEF_log(("I_SUBX_D.W %08x - %08x - %d = %08x", d, s, regs.x?1:0, r)); + flgSub(s, d, r, 0x8000, true); + coreSyncPC(); + return p.cyc; + } + function I_SUBX_D_8(p) { + var s = regs.d[p.Rx] & 0xff; + var d = regs.d[p.Ry] & 0xff; + var r = d - s - (regs.x ? 1:0); if (r < 0) r += 0x100; + regs.d[p.Ry] = (regs.d[p.Ry] & 0xffffff00) | r; + //SAEF_log(("I_SUBX_D.B %08x - %08x - %d = %08x", d, s, regs.x?1:0, r)); + flgSub(s, d, r, 0x80, true); + coreSyncPC(); + return p.cyc; + } + + function I_SUBX_M_32(p) { + regs.a[p.Rx] -= 4; var s = coreGet32(regs.a[p.Rx]); + regs.a[p.Ry] -= 4; var d = coreGet32(regs.a[p.Ry]); + var r = d - s - (regs.x ? 1:0); if (r < 0) r += 0x100000000; + corePut32(regs.a[p.Ry], r); + //SAEF_log(("I_SUBX_M.L %08x - %08x - %d = %08x", d, s, regs.x?1:0, r)); + flgSub(s, d, r, 0x80000000, true); + coreSyncPC(); + return p.cyc; + } + function I_SUBX_M_16(p) { + regs.a[p.Rx] -= 2; var s = coreGet16(regs.a[p.Rx]); + regs.a[p.Ry] -= 2; var d = coreGet16(regs.a[p.Ry]); + var r = d - s - (regs.x ? 1:0); if (r < 0) r += 0x10000; + corePut16(regs.a[p.Ry], r); + //SAEF_log(("I_SUBX_M.W %08x - %08x - %d = %08x", d, s, regs.x?1:0, r)); + flgSub(s, d, r, 0x8000, true); + coreSyncPC(); + return p.cyc; + } + function I_SUBX_M_8(p) { + regs.a[p.Rx] -= aIncDec[1][p.Rx]; var s = coreGet8(regs.a[p.Rx]); + regs.a[p.Ry] -= aIncDec[1][p.Ry]; var d = coreGet8(regs.a[p.Ry]); + var r = d - s - (regs.x ? 1:0); if (r < 0) r += 0x100; + corePut8(regs.a[p.Ry], r); + //SAEF_log(("I_SUBX_M.B %08x - %08x - %d = %08x", d, s, regs.x?1:0, r)); + flgSub(s, d, r, 0x80, true); + coreSyncPC(); + return p.cyc; + } + + function I_NEGX_D_32(p) { + var d = regs.d[p.Dn]; + var r = 0 - d - (regs.x ? 1:0); if (r < 0) r += 0x100000000; + regs.d[p.Dn] = r; + //SAEF_log(("I_NEGX_D.L 0 - %08x - %d = %08x", d, regs.x?1:0, r)); + flgNeg(d, r, 0x80000000, true); + coreSyncPC(); + return p.cyc; + } + function I_NEGX_D_16(p) { + var d = regs.d[p.Dn] & 0xffff; + var r = 0 - d - (regs.x ? 1:0); if (r < 0) r += 0x10000; + regs.d[p.Dn] = (regs.d[p.Dn] & 0xffff0000) | r; + //SAEF_log(("I_NEGX_D.W 0 - %08x - %d = %08x", d, regs.x?1:0, r)); + flgNeg(d, r, 0x8000, true); + coreSyncPC(); + return p.cyc; + } + function I_NEGX_D_8(p) { + var d = regs.d[p.Dn] & 0xff; + var r = 0 - d - (regs.x ? 1:0); if (r < 0) r += 0x100; + regs.d[p.Dn] = (regs.d[p.Dn] & 0xffffff00) | r; + //SAEF_log(("I_NEGX_D.B 0 - %08x - %d = %08x", d, regs.x?1:0, r)); + flgNeg(d, r, 0x80, true); + coreSyncPC(); + return p.cyc; + } + function I_NEGX_E_32(p) { + var a = exEAtab[p.ea](4); + var d = coreGet32(a); + var r = 0 - d - (regs.x ? 1:0); if (r < 0) r += 0x100000000; + corePut32(a, r); + //SAEF_log(("I_NEGX_E.L 0 - %08x - %d = %08x", d, regs.x?1:0, r)); + flgNeg(d, r, 0x80000000, true); + coreSyncPC(); + return p.cyc; + } + function I_NEGX_E_16(p) { + var a = exEAtab[p.ea](2); + var d = coreGet16(a); + var r = 0 - d - (regs.x ? 1:0); if (r < 0) r += 0x10000; + corePut16(a, r); + //SAEF_log(("I_NEGX_E.W 0 - %08x - %d = %08x", d, regs.x?1:0, r)); + flgNeg(d, r, 0x8000, true); + coreSyncPC(); + return p.cyc; + } + function I_NEGX_E_8(p) { + var a = exEAtab[p.ea](1); + var d = coreGet8(a); + var r = 0 - d - (regs.x ? 1:0); if (r < 0) r += 0x100; + corePut8(a, r); + //SAEF_log(("I_NEGX_E.B 0 - %08x - %d = %08x", d, regs.x?1:0, r)); + flgNeg(d, r, 0x80, true); + coreSyncPC(); + return p.cyc; + } + + /*-----------------------------------------------------------------------*/ + /* Integer Arithmetic - Address */ + + function I_ADDA_32(p) { + var s = ldEA32tab[p.ea](); + var d = regs.a[p.An]; + var r = s + d; if (r > 0xffffffff) r -= 0x100000000; + regs.a[p.An] = r; + //SAEF_log(("I_ADDA.L %08x + %08x = %08x", s, d, r)); + //ccna + coreSyncPC(); + return p.cyc; + } + function I_ADDA_16(p) { + var s = extWord(ldEA16tab[p.ea]()); + var d = regs.a[p.An]; + var r = s + d; if (r > 0xffffffff) r -= 0x100000000; + regs.a[p.An] = r; + //SAEF_log(("I_ADDA.W %08x + %08x = %08x", s, d, r)); + //ccna + coreSyncPC(); + return p.cyc; + } + + function I_SUBA_32(p) { + var s = ldEA32tab[p.ea](); + var d = regs.a[p.An]; + var r = d - s; if (r < 0) r += 0x100000000; + regs.a[p.An] = r; + //SAEF_log(("I_SUBA.L %08x - %08x = %08x", d, s, r)); + //ccna + coreSyncPC(); + return p.cyc; + } + function I_SUBA_16(p) { + var s = extWord(ldEA16tab[p.ea]()); + var d = regs.a[p.An]; + var r = d - s; if (r < 0) r += 0x100000000; + regs.a[p.An] = r; + //SAEF_log(("I_SUBA.W %08x - %08x = %08x", d, s, r)); + //ccna + coreSyncPC(); + return p.cyc; + } + + function I_CMPA_32(p) { + var s = ldEA32tab[p.ea](); + var d = regs.a[p.An]; + var r = d - s; if (r < 0) r += 0x100000000; + flgCmp(s, d, r, 0x80000000); + //SAEF_log(("I_CMPA.L %08x - %08x = %08x", d, s, r)); + coreSyncPC(); + return p.cyc; + } + function I_CMPA_16(p) { + var s = extWord(ldEA16tab[p.ea]()); + var d = regs.a[p.An]; + var r = d - s; if (r < 0) r += 0x100000000; + flgCmp(s, d, r, 0x80000000); + //SAEF_log(("I_CMPA.W %08x - %08x = %08x", d, s, r)); + coreSyncPC(); + return p.cyc; + } + + /*-----------------------------------------------------------------------*/ + /* Integer Arithmetic - Immediate */ + + function I_ADDI_D_32(p) { + var s = coreNext32(); + var d = regs.d[p.Dn]; + var r = s + d; if (r > 0xffffffff) r -= 0x100000000; + regs.d[p.Dn] = r; + flgAdd(s, d, r, 0x80000000, false); + //SAEF_log(("I_ADDI_D.L %08x + %08x = %08x", s, d, r)); + coreSyncPC(); + return p.cyc; + } + function I_ADDI_D_16(p) { + var s = coreNext16(); + var d = regs.d[p.Dn] & 0xffff; + var r = s + d; if (r > 0xffff) r -= 0x10000; + regs.d[p.Dn] = (regs.d[p.Dn] & 0xffff0000) | r; + flgAdd(s, d, r, 0x8000, false); + //SAEF_log(("I_ADDI_D.W %08x + %08x = %08x", s, d, r)); + coreSyncPC(); + return p.cyc; + } + function I_ADDI_D_8(p) { + var s = coreNext16() & 0xff; + var d = regs.d[p.Dn] & 0xff; + var r = s + d; if (r > 0xff) r -= 0x100; + regs.d[p.Dn] = (regs.d[p.Dn] & 0xffffff00) | r; + flgAdd(s, d, r, 0x80, false); + //SAEF_log(("I_ADDI_D.B %08x + %08x = %08x", s, d, r)); + coreSyncPC(); + return p.cyc; + } + function I_ADDI_E_32(p) { + var s = coreNext32(); + var a = exEAtab[p.ea](4); + var d = coreGet32(a); + var r = s + d; if (r > 0xffffffff) r -= 0x100000000; + corePut32(a, r); + flgAdd(s, d, r, 0x80000000, false); + //SAEF_log(("I_ADDI_E.L %08x + %08x = %08x", s, d, r)); + coreSyncPC(); + return p.cyc; + } + function I_ADDI_E_16(p) { + var s = coreNext16(); + var a = exEAtab[p.ea](2); + var d = coreGet16(a); + var r = s + d; if (r > 0xffff) r -= 0x10000; + corePut16(a, r); + flgAdd(s, d, r, 0x8000, false); + //SAEF_log(("I_ADDI_E.W %08x + %08x = %08x", s, d, r)); + coreSyncPC(); + return p.cyc; + } + function I_ADDI_E_8(p) { + var s = coreNext16() & 0xff; + var a = exEAtab[p.ea](1); + var d = coreGet8(a); + var r = s + d; if (r > 0xff) r -= 0x100; + corePut8(a, r); + flgAdd(s, d, r, 0x80, false); + //SAEF_log(("I_ADDI_E.B %08x + %08x = %08x", s, d, r)); + coreSyncPC(); + return p.cyc; + } + + function I_SUBI_D_32(p) { + var s = coreNext32(); + var d = regs.d[p.Dn]; + var r = d - s; if (r < 0) r += 0x100000000; + regs.d[p.Dn] = r; + flgSub(s, d, r, 0x80000000, false); + //SAEF_log(("I_SUBI_D.L %08x - %08x = %08x", d, s, r)); + coreSyncPC(); + return p.cyc; + } + function I_SUBI_D_16(p) { + var s = coreNext16(); + var d = regs.d[p.Dn] & 0xffff; + var r = d - s; if (r < 0) r += 0x10000; + regs.d[p.Dn] = (regs.d[p.Dn] & 0xffff0000) | r; + flgSub(s, d, r, 0x8000, false); + //SAEF_log(("I_SUBI_D.W %08x - %08x = %08x", d, s, d, r)); + coreSyncPC(); + return p.cyc; + } + function I_SUBI_D_8(p) { + var s = coreNext16() & 0xff; + var d = regs.d[p.Dn] & 0xff; + var r = d - s; if (r < 0) r += 0x100; + regs.d[p.Dn] = (regs.d[p.Dn] & 0xffffff00) | r; + flgSub(s, d, r, 0x80, false); + //SAEF_log(("I_SUBI_D.B %08x - %08x = %08x", d, s, r)); + coreSyncPC(); + return p.cyc; + } + function I_SUBI_E_32(p) { + var s = coreNext32(); + var a = exEAtab[p.ea](4); + var d = coreGet32(a); + var r = d - s; if (r < 0) r += 0x100000000; + corePut32(a, r); + flgSub(s, d, r, 0x80000000, false); + //SAEF_log(("I_SUBI_E.L %08x - %08x = %08x", d, s, r)); + coreSyncPC(); + return p.cyc; + } + function I_SUBI_E_16(p) { + var s = coreNext16(); + var a = exEAtab[p.ea](2); + var d = coreGet16(a); + var r = d - s; if (r < 0) r += 0x10000; + corePut16(a, r); + flgSub(s, d, r, 0x8000, false); + //SAEF_log(("I_SUBI_E.W %08x - %08x = %08x", d, s, r)); + coreSyncPC(); + return p.cyc; + } + function I_SUBI_E_8(p) { + var s = coreNext16() & 0xff; + var a = exEAtab[p.ea](1); + var d = coreGet8(a); + var r = d - s; if (r < 0) r += 0x100; + corePut8(a, r); + flgSub(s, d, r, 0x80, false); + //SAEF_log(("I_SUBI_E.B %08x - %08x = %08x", d, s, r)); + coreSyncPC(); + return p.cyc; + } + + function I_CMPI_32(p) { + var s = coreNext32(); + var d = ldEA32tab[p.ea](); + var r = d - s; if (r < 0) r += 0x100000000; + flgCmp(s, d, r, 0x80000000); + //SAEF_log(("I_CMPI.L %08x - %08x = %08x", d, s, r)); + coreSyncPC(); + return p.cyc; + } + function I_CMPI_16(p) { + var s = coreNext16(); + var d = ldEA16tab[p.ea](); + var r = d - s; if (r < 0) r += 0x10000; + flgCmp(s, d, r, 0x8000); + //SAEF_log(("I_CMPI.W %08x - %08x = %08x", d, s, r)); + coreSyncPC(); + return p.cyc; + } + function I_CMPI_8(p) { + var s = coreNext16() & 0xff; + var d = ldEA8tab[p.ea](); + var r = d - s; if (r < 0) r += 0x100; + flgCmp(s, d, r, 0x80); + //SAEF_log(("I_CMPI.B %08x - %08x = %08x", d, s, r)); + coreSyncPC(); + return p.cyc; + } + + /*-----------------------------------------------------------------------*/ + /* Integer Arithmetic - Quick */ + + function I_ADDQ_D_32(p) { + var s = p.data; + var d = regs.d[p.Dn]; + var r = s + d; if (r > 0xffffffff) r -= 0x100000000; + regs.d[p.Dn] = r; + flgAdd(s, d, r, 0x80000000, false); + //SAEF_log(("I_ADDQ_D.L %08x + %08x = %08x", s, d, r)); + coreSyncPC(); + return p.cyc; + } + function I_ADDQ_A_32(p) { + var s = p.data; + var d = regs.a[p.An]; + var r = s + d; if (r > 0xffffffff) r -= 0x100000000; + regs.a[p.An] = r; + //ccna + //SAEF_log(("I_ADDQ_A.L %08x + %08x = %08x", s, d, r)); + coreSyncPC(); + return p.cyc; + } + function I_ADDQ_E_32(p) { + var a = exEAtab[p.ea](4); + var s = p.data; + var d = coreGet32(a); + var r = s + d; if (r > 0xffffffff) r -= 0x100000000; + corePut32(a, r); + flgAdd(s, d, r, 0x80000000, false); + //SAEF_log(("I_ADDQ_E.L %08x + %08x = %08x", s, d, r)); + coreSyncPC(); + return p.cyc; + } + function I_ADDQ_D_16(p) { + var s = p.data; + var d = regs.d[p.Dn] & 0xffff; + var r = s + d; if (r > 0xffff) r -= 0x10000; + regs.d[p.Dn] = (regs.d[p.Dn] & 0xffff0000) | r; + flgAdd(s, d, r, 0x8000, false); + //SAEF_log(("I_ADDQ_D.W %08x + %08x = %08x", s, d, r)); + coreSyncPC(); + return p.cyc; + } + function I_ADDQ_E_16(p) { + var a = exEAtab[p.ea](2); + var s = p.data; + var d = coreGet16(a); + var r = s + d; if (r > 0xffff) r -= 0x10000; + corePut16(a, r); + flgAdd(s, d, r, 0x8000, false); + //SAEF_log(("I_ADDQ_E.W %08x + %08x = %08x", s, d, r)); + coreSyncPC(); + return p.cyc; + } + function I_ADDQ_D_8(p) { + var s = p.data; + var d = regs.d[p.Dn] & 0xff; + var r = s + d; if (r > 0xff) r -= 0x100; + regs.d[p.Dn] = (regs.d[p.Dn] & 0xffffff00) | r; + flgAdd(s, d, r, 0x80, false); + //SAEF_log(("I_ADDQ_D.B %08x + %08x = %08x", s, d, r)); + coreSyncPC(); + return p.cyc; + } + function I_ADDQ_E_8(p) { + var a = exEAtab[p.ea](1); + var s = p.data; + var d = coreGet8(a); + var r = s + d; if (r > 0xff) r -= 0x100; + corePut8(a, r); + flgAdd(s, d, r, 0x80, false); + //SAEF_log(("I_ADDQ_E.B %08x + %08x = %08x", s, d, r)); + coreSyncPC(); + return p.cyc; + } + + function I_SUBQ_D_32(p) { + var s = p.data; + var d = regs.d[p.Dn]; + var r = d - s; if (r < 0) r += 0x100000000; + regs.d[p.Dn] = r; + flgSub(s, d, r, 0x80000000, false); + //SAEF_log(("I_SUBQ_D.L %08x - %08x = %08x", d, s, r)); + coreSyncPC(); + return p.cyc; + } + function I_SUBQ_A_32(p) { + var s = p.data; + var d = regs.a[p.An]; + var r = d - s; if (r < 0) r += 0x100000000; + regs.a[p.An] = r; + //ccna + //SAEF_log(("I_SUBQ_A.L %08x - %08x = %08x", d, s, r)); + coreSyncPC(); + return p.cyc; + } + function I_SUBQ_E_32(p) { + var a = exEAtab[p.ea](4); + var s = p.data; + var d = coreGet32(a); + var r = d - s; if (r < 0) r += 0x100000000; + corePut32(a, r); + flgSub(s, d, r, 0x80000000, false); + //SAEF_log(("I_SUBQ_E.L %08x - %08x = %08x", d, s, r)); + coreSyncPC(); + return p.cyc; + } + function I_SUBQ_D_16(p) { + var s = p.data; + var d = regs.d[p.Dn] & 0xffff; + var r = d - s; if (r < 0) r += 0x10000; + regs.d[p.Dn] = (regs.d[p.Dn] & 0xffff0000) | r; + flgSub(s, d, r, 0x8000, false); + //SAEF_log(("I_SUBQ_D.W %08x - %08x = %08x", d, s, r)); + coreSyncPC(); + return p.cyc; + } + function I_SUBQ_E_16(p) { + var a = exEAtab[p.ea](2); + var s = p.data; + var d = coreGet16(a); + var r = d - s; if (r < 0) r += 0x10000; + corePut16(a, r); + flgSub(s, d, r, 0x8000, false); + //SAEF_log(("I_SUBQ_E.W %08x - %08x = %08x", d, s, r)); + coreSyncPC(); + return p.cyc; + } + function I_SUBQ_D_8(p) { + var s = p.data; + var d = regs.d[p.Dn] & 0xff; + var r = d - s; if (r < 0) r += 0x100; + regs.d[p.Dn] = (regs.d[p.Dn] & 0xffffff00) | r; + flgSub(s, d, r, 0x80, false); + //SAEF_log(("I_SUBQ_D.B %08x - %08x = %08x", d, s, r)); + coreSyncPC(); + return p.cyc; + } + function I_SUBQ_E_8(p) { + var a = exEAtab[p.ea](1); + var s = p.data; + var d = coreGet8(a); + var r = d - s; if (r < 0) r += 0x100; + corePut8(a, r); + flgSub(s, d, r, 0x80, false); + //SAEF_log(("I_SUBQ_E.B %08x - %08x = %08x", d, s, r)); + coreSyncPC(); + return p.cyc; + } + + /*-----------------------------------------------------------------------*/ + /* Integer Arithmetic - Misc */ + + function I_CMPM_32(p) { + var s = coreGet32(regs.a[p.Ay]); regs.a[p.Ay] += 4; + var d = coreGet32(regs.a[p.Ax]); regs.a[p.Ax] += 4; + var r = d - s; if (r < 0) r += 0x100000000; + flgCmp(s, d, r, 0x80000000); + //SAEF_log(("I_CMPM.L %08x - %08x = %08x", d, s, r)); + coreSyncPC(); + return p.cyc; + } + function I_CMPM_16(p) { + var s = coreGet16(regs.a[p.Ay]); regs.a[p.Ay] += 2; + var d = coreGet16(regs.a[p.Ax]); regs.a[p.Ax] += 2; + var r = d - s; if (r < 0) r += 0x10000; + flgCmp(s, d, r, 0x8000); + //SAEF_log(("I_CMPM.W %08x - %08x = %08x", d, s, r)); + coreSyncPC(); + return p.cyc; + } + function I_CMPM_8(p) { + var s = coreGet8(regs.a[p.Ay]); regs.a[p.Ay] += aIncDec[1][p.Ay]; + var d = coreGet8(regs.a[p.Ax]); regs.a[p.Ax] += aIncDec[1][p.Ax]; + var r = d - s; if (r < 0) r += 0x100; + flgCmp(s, d, r, 0x80); + //SAEF_log(("I_CMPM.B %08x - %08x = %08x", d, s, r)); + coreSyncPC(); + return p.cyc; + } + + function I_EXT_16(p) { + var d = regs.d[p.Dn] & 0xff; + var r = (d & 0x80) ? 0xff00 | d : d; + regs.d[p.Dn] = (regs.d[p.Dn] & 0xffff0000) | r; + flgLogical(r, 0x8000); + //SAEF_log(("I_EXT.W %08x -> %08x", d, r)); + coreSyncPC(); + return p.cyc; + } + function I_EXT_32(p) { + var d = regs.d[p.Dn] & 0xffff; + var r = (d & 0x8000) ? ((0xffff0000 | d) >>> 0) : d; + regs.d[p.Dn] = r; + flgLogical(r, 0x80000000); + //SAEF_log(("I_EXT.L %08x -> %08x", d, r)); + coreSyncPC(); + return p.cyc; + } + function I_EXTB(p) { /* >= 68020 */ + var d = regs.d[p.Dn] & 0xff; + var r = (d & 0x80) ? ((0xffffff00 | d) >>> 0) : d; + regs.d[p.Dn] = r; + flgLogical(r, 0x80000000); + //SAEF_log(("I_EXTB.L %08x -> %08x", d, r)); + coreSyncPC(); + return p.cyc; + } + /*-----------------------------------------------------------------------*/ /* Logical */ - function I_AND(p) { - var sea = exEA(p.s, p.z); - var s = ldEA(sea, p.z); - var dea = exEA(p.d, p.z); - var d = ldEA(dea, p.z); - var r = (s & d) >>> 0; - stEA(dea, p.z, r); - flgLogical(r, p.z); - //BUG.say(sprintf('I_AND.%s s $%08x d $%08x r $%08x, cyc %d', szChr(p.z), s, d, r, p.cyc)); - return p.cyc; - } - - function I_ANDI(p) { - var sea = exEA(p.s, p.z); - var s = ldEA(sea, p.z); - var dea = exEA(p.d, p.z); - var d = ldEA(dea, p.z); - var r = (s & d) >>> 0; - stEA(dea, p.z, r); - flgLogical(r, p.z); - //BUG.say(sprintf('I_ANDI.%s s $%08x d $%08x r $%08x', szChr(p.z), s, d, r)); - return p.cyc; - } - - function I_EOR(p) { - var sea = exEA(p.s, p.z); - var s = ldEA(sea, p.z); - var dea = exEA(p.d, p.z); - var d = ldEA(dea, p.z); - var r = (s ^ d) >>> 0; - stEA(dea, p.z, r); - flgLogical(r, p.z); - //BUG.say(sprintf('I_EOR.%s s $%08x d $%08x r $%08x', szChr(p.z), s, d, r)); - return p.cyc; - } - - function I_EORI(p) { - var sea = exEA(p.s, p.z); - var s = ldEA(sea, p.z); - var dea = exEA(p.d, p.z); - var d = ldEA(dea, p.z); - var r = (s ^ d) >>> 0; - stEA(dea, p.z, r); - flgLogical(r, p.z); - //BUG.say(sprintf('I_EORI.%s s $%08x d $%08x r $%08x', szChr(p.z), s, d, r)); - return p.cyc; - } - - function I_NOT(p) { - var dea = exEA(p.d, p.z); - var d = ldEA(dea, p.z); - var m = p.z == 1 ? 0xff : (p.z == 2 ? 0xffff : 0xffffffff); - var r = ~d & m; if (r < 0) r += 0x100000000; - stEA(dea, p.z, r); - flgLogical(r, p.z); - //BUG.say(sprintf('I_NOT.%s d $%08x r $%08x', szChr(p.z), d, r)); + function I_AND_D_32(p) { + var r = (ldEA32tab[p.ea]() & regs.d[p.Dn]) >>> 0; + regs.d[p.Dn] = r; + flgLogical(r, p.zm); + coreSyncPC(); return p.cyc; } - - function I_OR(p) { - var sea = exEA(p.s, p.z); - var s = ldEA(sea, p.z); - var dea = exEA(p.d, p.z); - var d = ldEA(dea, p.z); - var r = (s | d) >>> 0; - stEA(dea, p.z, r); - flgLogical(r, p.z); - //BUG.say(sprintf('I_OR.%s s $%08x d $%08x r $%08x', szChr(p.z), s, d, r)); - return p.cyc; + function I_AND_D_16(p) { + var r = ldEA16tab[p.ea]() & (regs.d[p.Dn] & 0xffff); + regs.d[p.Dn] = (regs.d[p.Dn] & 0xffff0000) | r; + flgLogical(r, p.zm); + coreSyncPC(); + return p.cyc; + } + function I_AND_D_8(p) { + var r = ldEA8tab[p.ea]() & (regs.d[p.Dn] & 0xff); + regs.d[p.Dn] = (regs.d[p.Dn] & 0xffffff00) | r; + flgLogical(r, p.zm); + coreSyncPC(); + return p.cyc; + } + function I_AND_E_32(p) { + var a = exEAtab[p.ea](4); + var r = (regs.d[p.Dn] & coreGet32(a)) >>> 0; + corePut32(a, r); + flgLogical(r, p.zm); + coreSyncPC(); + return p.cyc; + } + function I_AND_E_16(p) { + var a = exEAtab[p.ea](2); + var r = (regs.d[p.Dn] & 0xffff) & coreGet16(a); + corePut16(a, r); + flgLogical(r, p.zm); + coreSyncPC(); + return p.cyc; + } + function I_AND_E_8(p) { + var a = exEAtab[p.ea](1); + var r = (regs.d[p.Dn] & 0xff) & coreGet8(a); + corePut8(a, r); + flgLogical(r, p.zm); + coreSyncPC(); + return p.cyc; } - function I_ORI(p) { - var sea = exEA(p.s, p.z); - var s = ldEA(sea, p.z); - var dea = exEA(p.d, p.z); - var d = ldEA(dea, p.z); + function I_EOR_D_32(p) { + var r = (regs.d[p.Dd] ^ regs.d[p.Dn]) >>> 0; + regs.d[p.Dd] = r; + flgLogical(r, p.zm); + coreSyncPC(); + return p.cyc; + } + function I_EOR_D_16(p) { + var r = (regs.d[p.Dd] & 0xffff) ^ (regs.d[p.Dn] & 0xffff); + regs.d[p.Dd] = (regs.d[p.Dd] & 0xffff0000) | r; + flgLogical(r, p.zm); + coreSyncPC(); + return p.cyc; + } + function I_EOR_D_8(p) { + var r = (regs.d[p.Dd] & 0xff) ^ (regs.d[p.Dn] & 0xff); + regs.d[p.Dd] = (regs.d[p.Dd] & 0xffffff00) | r; + flgLogical(r, p.zm); + coreSyncPC(); + return p.cyc; + } + function I_EOR_E_32(p) { + var a = exEAtab[p.ea](4); + var r = (coreGet32(a) ^ regs.d[p.Dn]) >>> 0; + corePut32(a, r); + flgLogical(r, p.zm); + coreSyncPC(); + return p.cyc; + } + function I_EOR_E_16(p) { + var a = exEAtab[p.ea](2); + var r = coreGet16(a) ^ (regs.d[p.Dn] & 0xffff); + corePut16(a, r); + flgLogical(r, p.zm); + coreSyncPC(); + return p.cyc; + } + function I_EOR_E_8(p) { + var a = exEAtab[p.ea](1); + var r = coreGet8(a) ^ (regs.d[p.Dn] & 0xff); + corePut8(a, r); + flgLogical(r, p.zm); + coreSyncPC(); + return p.cyc; + } + + function I_NOT_D_32(p) { + var r = ~regs.d[p.Dn] >>> 0; + regs.d[p.Dn] = r; + flgLogical(r, p.zm); + coreSyncPC(); + return p.cyc; + } + function I_NOT_D_16(p) { + var r = ~(regs.d[p.Dn] & 0xffff) & p.m; + regs.d[p.Dn] = (regs.d[p.Dn] & 0xffff0000) | r; + flgLogical(r, p.zm); + coreSyncPC(); + return p.cyc; + } + function I_NOT_D_8(p) { + var r = ~(regs.d[p.Dn] & 0xff) & p.m; + regs.d[p.Dn] = (regs.d[p.Dn] & 0xffffff00) | r; + flgLogical(r, p.zm); + coreSyncPC(); + return p.cyc; + } + function I_NOT_E_32(p) { + var a = exEAtab[p.ea](4); + var r = ~coreGet32(a) >>> 0; + corePut32(a, r); + flgLogical(r, p.zm); + coreSyncPC(); + return p.cyc; + } + function I_NOT_E_16(p) { + var a = exEAtab[p.ea](2); + var r = ~coreGet16(a) & p.m; + corePut16(a, r); + flgLogical(r, p.zm); + coreSyncPC(); + return p.cyc; + } + function I_NOT_E_8(p) { + var a = exEAtab[p.ea](1); + var r = ~coreGet8(a) & p.m; + corePut8(a, r); + flgLogical(r, p.zm); + coreSyncPC(); + return p.cyc; + } + + function I_OR_D_32(p) { + var r = (ldEA32tab[p.ea]() | regs.d[p.Dn]) >>> 0; + regs.d[p.Dn] = r; + flgLogical(r, p.zm); + coreSyncPC(); + return p.cyc; + } + function I_OR_D_16(p) { + var r = ldEA16tab[p.ea]() | (regs.d[p.Dn] & 0xffff); + regs.d[p.Dn] = (regs.d[p.Dn] & 0xffff0000) | r; + flgLogical(r, p.zm); + coreSyncPC(); + return p.cyc; + } + function I_OR_D_8(p) { + var r = ldEA8tab[p.ea]() | (regs.d[p.Dn] & 0xff); + regs.d[p.Dn] = (regs.d[p.Dn] & 0xffffff00) | r; + flgLogical(r, p.zm); + coreSyncPC(); + return p.cyc; + } + function I_OR_E_32(p) { + var a = exEAtab[p.ea](4); + var r = (regs.d[p.Dn] | coreGet32(a)) >>> 0; + corePut32(a, r); + flgLogical(r, p.zm); + coreSyncPC(); + return p.cyc; + } + function I_OR_E_16(p) { + var a = exEAtab[p.ea](2); + var r = (regs.d[p.Dn] & 0xffff) | coreGet16(a); + corePut16(a, r); + flgLogical(r, p.zm); + coreSyncPC(); + return p.cyc; + } + function I_OR_E_8(p) { + var a = exEAtab[p.ea](1); + var r = (regs.d[p.Dn] & 0xff) | coreGet8(a); + corePut8(a, r); + flgLogical(r, p.zm); + coreSyncPC(); + return p.cyc; + } + + /*-----------------------------------------------------------------------*/ + /* Logical - Immediate */ + + function I_ANDI_D_32(p) { + var r = (coreNext32() & regs.d[p.Dn]) >>> 0; + regs.d[p.Dn] = r; + flgLogical(r, p.zm); + coreSyncPC(); + return p.cyc; + } + function I_ANDI_D_16(p) { + var r = coreNext16() & (regs.d[p.Dn] & 0xffff); + regs.d[p.Dn] = (regs.d[p.Dn] & 0xffff0000) | r; + flgLogical(r, p.zm); + coreSyncPC(); + return p.cyc; + } + function I_ANDI_D_8(p) { + var r = (coreNext16() & 0xff) & (regs.d[p.Dn] & 0xff); + regs.d[p.Dn] = (regs.d[p.Dn] & 0xffffff00) | r; + flgLogical(r, p.zm); + coreSyncPC(); + return p.cyc; + } + function I_ANDI_E_32(p) { + var s = coreNext32(); + var a = exEAtab[p.ea](4); + var d = coreGet32(a); + var r = (s & d) >>> 0; + corePut32(a, r); + flgLogical(r, p.zm); + coreSyncPC(); + return p.cyc; + } + function I_ANDI_E_16(p) { + var s = coreNext16(); + var a = exEAtab[p.ea](2); + var d = coreGet16(a); + var r = s & d; + corePut16(a, r); + flgLogical(r, p.zm); + coreSyncPC(); + return p.cyc; + } + function I_ANDI_E_8(p) { + var s = coreNext16() & 0xff; + var a = exEAtab[p.ea](1); + var d = coreGet8(a); + var r = s & d; + corePut8(a, r); + flgLogical(r, p.zm); + coreSyncPC(); + return p.cyc; + } + + function I_EORI_D_32(p) { + var r = (coreNext32() ^ regs.d[p.Dn]) >>> 0; + regs.d[p.Dn] = r; + flgLogical(r, p.zm); + coreSyncPC(); + return p.cyc; + } + function I_EORI_D_16(p) { + var r = coreNext16() ^ (regs.d[p.Dn] & 0xffff); + regs.d[p.Dn] = (regs.d[p.Dn] & 0xffff0000) | r; + flgLogical(r, p.zm); + coreSyncPC(); + return p.cyc; + } + function I_EORI_D_8(p) { + var r = (coreNext16() & 0xff) ^ (regs.d[p.Dn] & 0xff); + regs.d[p.Dn] = (regs.d[p.Dn] & 0xffffff00) | r; + flgLogical(r, p.zm); + coreSyncPC(); + return p.cyc; + } + function I_EORI_E_32(p) { + var s = coreNext32(); + var a = exEAtab[p.ea](4); + var d = coreGet32(a); + var r = (s ^ d) >>> 0; + corePut32(a, r); + flgLogical(r, p.zm); + coreSyncPC(); + return p.cyc; + } + function I_EORI_E_16(p) { + var s = coreNext16(); + var a = exEAtab[p.ea](2); + var d = coreGet16(a); + var r = s ^ d; + corePut16(a, r); + flgLogical(r, p.zm); + coreSyncPC(); + return p.cyc; + } + function I_EORI_E_8(p) { + var s = coreNext16() & 0xff; + var a = exEAtab[p.ea](1); + var d = coreGet8(a); + var r = s ^ d; + corePut8(a, r); + flgLogical(r, p.zm); + coreSyncPC(); + return p.cyc; + } + + function I_ORI_D_32(p) { + var r = (coreNext32() | regs.d[p.Dn]) >>> 0; + regs.d[p.Dn] = r; + flgLogical(r, p.zm); + coreSyncPC(); + return p.cyc; + } + function I_ORI_D_16(p) { + var r = coreNext16() | (regs.d[p.Dn] & 0xffff); + regs.d[p.Dn] = (regs.d[p.Dn] & 0xffff0000) | r; + flgLogical(r, p.zm); + coreSyncPC(); + return p.cyc; + } + function I_ORI_D_8(p) { + var r = (coreNext16() & 0xff) | (regs.d[p.Dn] & 0xff); + regs.d[p.Dn] = (regs.d[p.Dn] & 0xffffff00) | r; + flgLogical(r, p.zm); + coreSyncPC(); + return p.cyc; + } + function I_ORI_E_32(p) { + var s = coreNext32(); + var a = exEAtab[p.ea](4); + var d = coreGet32(a); var r = (s | d) >>> 0; - stEA(dea, p.z, r); - flgLogical(r, p.z); - //BUG.say(sprintf('I_ORI.%s s $%08x d $%08x r $%08x', szChr(p.z), s, d, r)); + corePut32(a, r); + flgLogical(r, p.zm); + coreSyncPC(); + return p.cyc; + } + function I_ORI_E_16(p) { + var s = coreNext16(); + var a = exEAtab[p.ea](2); + var d = coreGet16(a); + var r = s | d; + corePut16(a, r); + flgLogical(r, p.zm); + coreSyncPC(); + return p.cyc; + } + function I_ORI_E_8(p) { + var s = coreNext16() & 0xff; + var a = exEAtab[p.ea](1); + var d = coreGet8(a); + var r = s | d; + corePut8(a, r); + flgLogical(r, p.zm); + coreSyncPC(); return p.cyc; } /*-----------------------------------------------------------------------*/ /* Shift and Rotate */ - function I_ASL(p) { - var sea = exEA(p.s, p.z); - var s = ldEA(sea, p.z) % 64; - var dea = exEA(p.d, p.z); - var d = ldEA(dea, p.z); - var n = s; - var r = d; - var c = false; - var v = false; - var rm = r & p.ms; - - if (n > 0) { - for (; n > 0; --n) { - c = (r & p.ms) != 0; - r <<= 1; - r = (r & p.mz) >>> 0; - if (!v && (r & p.ms) != rm) v = true; - } - stEA(dea, p.z, r); - regs.c = regs.x = c; - } else regs.c = false; - - regs.v = v; - regs.n = (r & p.ms) != 0; - regs.z = r == 0; - //BUG.say(sprintf('I_ASL.%s num %d d $%08x r $%08x', szChr(p.z), s, d, r)); - return [p.cyc[0] + (dea.m == M_rdd ? s << 1 : 0), 0,0]; //FIXME + function I_ASL_32(p) { + var d = regs.d[p.Dy], _d = d; + var n = p.ir ? regs.d[p.cr] & 63 : p.cr; + if (n) { + var sign = (d & 0x80000000) != 0; + var mask = ~((1 << (32 - n)) - 1) >>> 0; + //var mask = (0xffffffff << (31 - n)) >>> 0; + regs.x = regs.c = (d & (1 << (32-n))) != 0; + regs.v = sign ? (((d & mask) >>> 0) != mask) : (((d & mask) >>> 0) != 0); + //regs.v = ((d & mask) >>> 0) != mask && ((d & mask) >>> 0) != 0; + d = ((d << n) & 0xffffffff) >>> 0; + regs.d[p.Dy] = d; + } else regs.v = regs.c = false; + regs.n = (d & 0x80000000) != 0; + regs.z = d == 0; + //if (sign) SAEF_log(("I_ASL.L %08x << %d = %08x, sign %d, mask %x, V %d -> %08x", _d, n, d, sign?1:0, mask, regs.v?1:0, (_d & mask)>>>0)); + coreSyncPC(); + return [p.cyc[0]+2*n,p.cyc[1],p.cyc[2]]; } - - function I_ASR(p) { - var sea = exEA(p.s, p.z); - var s = ldEA(sea, p.z) % 64; - var dea = exEA(p.d, p.z); - var d = ldEA(dea, p.z); - var n = s; - var r = d; - var c = false; - var sign = (r & p.ms) ? p.ms : 0; - - if (n > 0) { - for (; n > 0; --n) { - c = (r & 1) != 0; - r = (sign | (r >>> 1)) >>> 0; - } - stEA(dea, p.z, r); - regs.c = regs.x = c; + function I_ASL_16(p) { + var d = regs.d[p.Dy] & 0xffff, _d = d; + var n = p.ir ? regs.d[p.cr] & 63 : p.cr; + if (n) { + var sign = (d & 0x8000) != 0; + var mask = ~((1 << (16 - n)) - 1) & 0xffff; + //var mask = (0xffff << (15 - n)) & 0xffff; + regs.x = regs.c = (d & (1 << (16-n))) != 0; + regs.v = sign ? (d & mask) != mask : (d & mask) != 0; + //regs.v = (d & mask) != mask && (d & mask) != 0; + d = ((d << n) & 0xffff) >>> 0; + regs.d[p.Dy] = (regs.d[p.Dy] & 0xffff0000) | d; + } else regs.v = regs.c = false; + regs.n = (d & 0x8000) != 0; + regs.z = d == 0; + //if (sign) SAEF_log(("I_ASL.W %08x << %d = %08x, sign %d, mask %x, V %d", _d, n, d, sign?1:0, mask, regs.v?1:0)); + coreSyncPC(); + return [p.cyc[0]+2*n,p.cyc[1],p.cyc[2]]; + } + function I_ASL_8(p) { + var d = regs.d[p.Dy] & 0xff, _d = d; + var n = p.ir ? regs.d[p.cr] & 63 : p.cr; + if (n) { + var sign = (d & 0x80) != 0; + var mask = ~((1 << (8 - n)) - 1) & 0xff; + //var mask = (0xff << (7 - n)) & 0xff; + regs.x = regs.c = (d & (1 << (8-n))) != 0; + regs.v = sign ? (d & mask) != mask : (d & mask) != 0; + //regs.v = (d & mask) != mask && (d & mask) != 0; + d = ((d << n) & 0xff) >>> 0; + regs.d[p.Dy] = (regs.d[p.Dy] & 0xffffff00) | d; + } else regs.v = regs.c = false; + regs.n = (d & 0x80) != 0; + regs.z = d == 0; + //if (sign) SAEF_log(("I_ASL.B %08x << %d = %08x, sign %d, mask %x, V %d", _d, n, d, sign?1:0, mask, regs.v?1:0)); + coreSyncPC(); + return [p.cyc[0]+2*n,p.cyc[1],p.cyc[2]]; + } + function I_ASR_32(p) { + var d = regs.d[p.Dy], _d = d; + var n = p.ir ? regs.d[p.cr] & 63 : p.cr; + if (n) { + regs.x = regs.c = (d & (1 << (n-1))) != 0; + d = (d >> n) >>> 0; //js 32 + regs.d[p.Dy] = d; } else regs.c = false; - + regs.n = (d & 0x80000000) != 0; + regs.z = d == 0; regs.v = false; - regs.n = (r & p.ms) != 0; - regs.z = r == 0; - //BUG.say(sprintf('I_ASR.%s num %d d $%08x r $%08x sign %d', szChr(p.z), s, d, r, sign)); - return [p.cyc[0] + (dea.m == M_rdd ? s << 1 : 0), 0,0]; //FIXME + //SAEF_log(("I_ASR.L %08x >> %d = %08x", _d, n, d)); + coreSyncPC(); + return [p.cyc[0]+2*n,p.cyc[1],p.cyc[2]]; } - - function I_LSL(p) { - var sea = exEA(p.s, p.z); - var s = ldEA(sea, p.z) % 64; - var dea = exEA(p.d, p.z); - var d = ldEA(dea, p.z); - var n = s; - var r = d; - var c = false; - - if (n > 0) { - for (; n > 0; --n) { - c = (r & p.ms) != 0; - r <<= 1; - r = (r & p.mz) >>> 0; - } - stEA(dea, p.z, r); - regs.c = regs.x = c; + function I_ASR_16(p) { + var d = regs.d[p.Dy] & 0xffff, _d = d; + var n = p.ir ? regs.d[p.cr] & 63 : p.cr; + if (n) { + regs.x = regs.c = (d & (1 << (n-1))) != 0; + d = extWord(d); d = ((d >> n) & 0xffff) >>> 0; //js 32 + //d >>= n; + regs.d[p.Dy] = (regs.d[p.Dy] & 0xffff0000) | d; } else regs.c = false; - + regs.n = (d & 0x8000) != 0; + regs.z = d == 0; regs.v = false; - regs.n = (r & p.ms) != 0; - regs.z = r == 0; - //BUG.say(sprintf('I_LSL.%s num %d d $%08x r $%08x', szChr(p.z), s, d, r)); - return [p.cyc[0] + (dea.m == M_rdd ? s << 1 : 0), 0,0]; //FIXME + //SAEF_log(("I_ASR.W %08x >> %d = %08x", _d, n, d)); + coreSyncPC(); + return [p.cyc[0]+2*n,p.cyc[1],p.cyc[2]]; } - - function I_LSR(p) { - var sea = exEA(p.s, p.z); - var s = ldEA(sea, p.z) % 64; - var dea = exEA(p.d, p.z); - var d = ldEA(dea, p.z); - var n = s; - var r = d; - var c = false; - - if (n > 0) { - for (; n > 0; --n) { - c = (r & 1) != 0; - r >>>= 1; - } - stEA(dea, p.z, r); - regs.c = regs.x = c; + function I_ASR_8(p) { + var d = regs.d[p.Dy] & 0xff, _d = d; + var n = p.ir ? regs.d[p.cr] & 63 : p.cr; + if (n) { + regs.x = regs.c = (d & (1 << (n-1))) != 0; + d = extByte(d); d = ((d >> n) & 0xff) >>> 0; //js 32 + //d >>= n; + regs.d[p.Dy] = (regs.d[p.Dy] & 0xffffff00) | d; } else regs.c = false; - + regs.n = (d & 0x80) != 0; + regs.z = d == 0; regs.v = false; - regs.n = (r & p.ms) != 0; - regs.z = r == 0; - //BUG.say(sprintf('I_LSR.%s num %d d $%08x r $%08x', szChr(p.z), s, d, r)); - return [p.cyc[0] + (dea.m == M_rdd ? s << 1 : 0), 0,0]; //FIXME + //SAEF_log(("I_ASR.B %08x >> %d = %08x", _d, n, d)); + coreSyncPC(); + return [p.cyc[0]+2*n,p.cyc[1],p.cyc[2]]; + } + function I_ASL_M(p) { + var a = exEAtab[p.ea](2); + var d = coreGet16(a), _d = d; + regs.x = regs.c = (d & 0x8000) != 0; + regs.v = regs.c != ((d & 0x4000) != 0); + d = (d << 1) & 0xffff; + regs.n = (d & 0x8000) != 0; + regs.z = d == 0; + corePut16(a, d); + //SAEF_log(("I_ASL_M.W %08x << 1 = %08x", _d, d)); + coreSyncPC(); + return p.cyc; + } + function I_ASR_M(p) { + var a = exEAtab[p.ea](2); + var d = coreGet16(a), _d = d; + var sign = d & 0x8000; + regs.x = regs.c = (d & 1) != 0; + regs.v = false; + d = sign | (d >> 1); + regs.n = (d & 0x8000) != 0; + regs.z = d == 0; + corePut16(a, d); + //SAEF_log(("I_ASR_M.W %08x >> 1 = %08x", _d, d)); + coreSyncPC(); + return p.cyc; } - function I_ROL(p) { - var sea = exEA(p.s, p.z); - var s = ldEA(sea, p.z) % 64; - var dea = exEA(p.d, p.z); - var d = ldEA(dea, p.z); - var n = s; - var r = d; - var c = false; - - if (n > 0) { - for (; n > 0; --n) { - c = (r & p.ms) != 0; - r <<= 1; - r = (r & p.mz) >>> 0; - if (c) r = (r | 1) >>> 0; - } - stEA(dea, p.z, r); - regs.c = c; + function I_LSL_32(p) { + var d = regs.d[p.Dy], _d = d; + var n = p.ir ? regs.d[p.cr] & 63 : p.cr; + if (n) { + regs.x = regs.c = (d & (1 << (32-n))) != 0; + d = ((d << n) & 0xffffffff) >>> 0; + regs.d[p.Dy] = d; } else regs.c = false; - + regs.n = (d & 0x80000000) != 0; + regs.z = d == 0; regs.v = false; - regs.n = (r & p.ms) != 0; - regs.z = r == 0; - //BUG.say(sprintf('I_ROL.%s num %d d $%08x r $%08x', szChr(p.z), s, d, r)); - return [p.cyc[0] + (dea.m == M_rdd ? s << 1 : 0), 0,0]; //FIXME + //SAEF_log(("I_LSL.L %08x << %d = %08x", _d, n, d)); + coreSyncPC(); + return [p.cyc[0]+2*n,p.cyc[1],p.cyc[2]]; } - - function I_ROR(p) { - var sea = exEA(p.s, p.z); - var s = ldEA(sea, p.z) % 64; - var dea = exEA(p.d, p.z); - var d = ldEA(dea, p.z); - var n = s; - var r = d; - var c = false; - - if (n > 0) { - for (; n > 0; --n) { - c = (r & 1) != 0; - r >>>= 1; - if (c) r = (p.ms | r) >>> 0; - } - stEA(dea, p.z, r); - regs.c = c; + function I_LSL_16(p) { + var d = regs.d[p.Dy] & 0xffff, _d = d; + var n = p.ir ? regs.d[p.cr] & 63 : p.cr; + if (n) { + regs.x = regs.c = (d & (1 << (16-n))) != 0; + d = ((d << n) & 0xffff) >>> 0; + regs.d[p.Dy] = (regs.d[p.Dy] & 0xffff0000) | d; } else regs.c = false; - + regs.n = (d & 0x8000) != 0; + regs.z = d == 0; regs.v = false; - regs.n = (r & p.ms) != 0; - regs.z = r == 0; - //BUG.say(sprintf('I_ROR.%s num %d d $%08x r $%08x', szChr(p.z), s, d, r)); - return [p.cyc[0] + (dea.m == M_rdd ? s << 1 : 0), 0,0]; //FIXME + //SAEF_log(("I_LSL.W %08x << %d = %08x", _d, n, d)); + coreSyncPC(); + return [p.cyc[0]+2*n,p.cyc[1],p.cyc[2]]; + } + function I_LSL_8(p) { + var d = regs.d[p.Dy] & 0xff, _d = d; + var n = p.ir ? regs.d[p.cr] & 63 : p.cr; + if (n) { + regs.x = regs.c = (d & (1 << (8-n))) != 0; + d = ((d << n) & 0xff) >>> 0; + regs.d[p.Dy] = (regs.d[p.Dy] & 0xffffff00) | d; + } else regs.c = false; + regs.n = (d & 0x80) != 0; + regs.z = d == 0; + regs.v = false; + //SAEF_log(("I_LSL.B %08x << %d = %08x", _d, n, d)); + coreSyncPC(); + return [p.cyc[0]+2*n,p.cyc[1],p.cyc[2]]; + } + function I_LSR_32(p) { + var d = regs.d[p.Dy], _d = d; + var n = p.ir ? regs.d[p.cr] & 63 : p.cr; + if (n) { + regs.x = regs.c = (d & (1 << (n-1))) != 0; + d = d >>> n; + regs.d[p.Dy] = d; + } else regs.c = false; + regs.n = (d & 0x80000000) != 0; + regs.z = d == 0; + regs.v = false; + //SAEF_log(("I_LSR.L %08x >> %d = %08x", _d, n, d)); + coreSyncPC(); + return [p.cyc[0]+2*n,p.cyc[1],p.cyc[2]]; + } + function I_LSR_16(p) { + var d = regs.d[p.Dy] & 0xffff, _d = d; + var n = p.ir ? regs.d[p.cr] & 63 : p.cr; + if (n) { + regs.x = regs.c = (d & (1 << (n-1))) != 0; + d >>= n; + regs.d[p.Dy] = (regs.d[p.Dy] & 0xffff0000) | d; + } else regs.c = false; + regs.n = (d & 0x8000) != 0; + regs.z = d == 0; + regs.v = false; + //SAEF_log(("I_LSR.W %08x >> %d = %08x", _d, n, d)); + coreSyncPC(); + return [p.cyc[0]+2*n,p.cyc[1],p.cyc[2]]; + } + function I_LSR_8(p) { + var d = regs.d[p.Dy] & 0xff, _d = d; + var n = p.ir ? regs.d[p.cr] & 63 : p.cr; + if (n) { + regs.x = regs.c = (d & (1 << (n-1))) != 0; + d >>= n; + regs.d[p.Dy] = (regs.d[p.Dy] & 0xffffff00) | d; + } else regs.c = false; + regs.n = (d & 0x80) != 0; + regs.z = d == 0; + regs.v = false; + //SAEF_log(("I_LSR.B %08x >> %d = %08x", _d, n, d)); + coreSyncPC(); + return [p.cyc[0]+2*n,p.cyc[1],p.cyc[2]]; + } + function I_LSL_M(p) { + var a = exEAtab[p.ea](2); + var d = coreGet16(a), _d = d; + regs.x = regs.c = (d & 0x8000) != 0; + d = (d << 1) & 0xffff; + regs.n = (d & 0x8000) != 0; + regs.z = d == 0; + regs.v = false; + corePut16(a, d); + //SAEF_log(("I_LSL_M.W %08x << 1 = %08x", _d, d)); + coreSyncPC(); + return p.cyc; + } + function I_LSR_M(p) { + var a = exEAtab[p.ea](2); + var d = coreGet16(a), _d = d; + regs.x = regs.c = (d & 1) != 0; + d >>= 1; + regs.n = (d & 0x8000) != 0; + regs.z = d == 0; + regs.v = false; + corePut16(a, d); + //SAEF_log(("I_LSR_M.W %08x >> 1 = %08x", _d, d)); + coreSyncPC(); + return p.cyc; } - function I_ROXL(p) { - var sea = exEA(p.s, p.z); - var s = ldEA(sea, p.z) % 64; - var dea = exEA(p.d, p.z); - var d = ldEA(dea, p.z); - var n = s; - var r = d; - var c = false; - var x = regs.x; //var _x = x?1:0; + function I_ROL_32(p) { + var d = regs.d[p.Dy], _d = d; + var n = p.ir ? regs.d[p.cr] & 63 : p.cr; + if (n) { + regs.c = (d & (1 << (32-n))) != 0; + d = (((d << n) | (d >>> (32-n))) & 0xffffffff) >>> 0; + regs.d[p.Dy] = d; + } else regs.c = false; + regs.n = (d & 0x80000000) != 0; + regs.z = d == 0; + regs.v = false; + //SAEF_log(("I_ROL.L %08x << %d = %08x", _d, n, d)); + coreSyncPC(); + return [p.cyc[0]+2*n,p.cyc[1],p.cyc[2]]; + } + function I_ROL_16(p) { + var d = regs.d[p.Dy] & 0xffff, _d = d; + var n = p.ir ? regs.d[p.cr] & 63 : p.cr; + if (n) { + regs.c = (d & (1 << (16-n))) != 0; + d = (((d << n) | (d >> (16-n))) & 0xffff) >>> 0; + regs.d[p.Dy] = (regs.d[p.Dy] & 0xffff0000) | d; + } else regs.c = false; + regs.n = (d & 0x8000) != 0; + regs.z = d == 0; + regs.v = false; + //SAEF_log(("I_ROL.W %08x << %d = %08x", _d, n, d)); + coreSyncPC(); + return [p.cyc[0]+2*n,p.cyc[1],p.cyc[2]]; + } + function I_ROL_8(p) { + var d = regs.d[p.Dy] & 0xff, _d = d; + var n = p.ir ? regs.d[p.cr] & 63 : p.cr; + if (n) { + regs.c = (d & (1 << (8-n))) != 0; + d = (((d << n) | (d >> (8-n))) & 0xff) >>> 0; + regs.d[p.Dy] = (regs.d[p.Dy] & 0xffffff00) | d; + } else regs.c = false; + regs.n = (d & 0x80) != 0; + regs.z = d == 0; + regs.v = false; + //SAEF_log(("I_ROL.B %08x << %d = %08x", _d, n, d)); + coreSyncPC(); + return [p.cyc[0]+2*n,p.cyc[1],p.cyc[2]]; + } + function I_ROR_32(p) { + var d = regs.d[p.Dy], _d = d; + var n = p.ir ? regs.d[p.cr] & 63 : p.cr; + if (n) { + regs.c = (d & (1 << (n-1))) != 0; + d = (((d << (32-n)) | (d >>> n)) & 0xffffffff) >>> 0; + regs.d[p.Dy] = d; + } else regs.c = false; + regs.n = (d & 0x80000000) != 0; + regs.z = d == 0; + regs.v = false; + //SAEF_log(("I_ROR.L %08x >> %d = %08x", _d, n, d)); + coreSyncPC(); + return [p.cyc[0]+2*n,p.cyc[1],p.cyc[2]]; + } + function I_ROR_16(p) { + var d = regs.d[p.Dy] & 0xffff, _d = d; + var n = p.ir ? regs.d[p.cr] & 63 : p.cr; + if (n) { + regs.c = (d & (1 << (n-1))) != 0; + d = (((d << (16-n)) | (d >>> n)) & 0xffff) >>> 0; + regs.d[p.Dy] = (regs.d[p.Dy] & 0xffff0000) | d; + } else regs.c = false; + regs.n = (d & 0x8000) != 0; + regs.z = d == 0; + regs.v = false; + //SAEF_log(("I_ROR.W %08x >> %d = %08x", _d, n, d)); + coreSyncPC(); + return [p.cyc[0]+2*n,p.cyc[1],p.cyc[2]]; + } + function I_ROR_8(p) { + var d = regs.d[p.Dy] & 0xff, _d = d; + var n = p.ir ? regs.d[p.cr] & 63 : p.cr; + if (n) { + regs.c = (d & (1 << (n-1))) != 0; + d = (((d << (8-n)) | (d >>> n)) & 0xff) >>> 0; + regs.d[p.Dy] = (regs.d[p.Dy] & 0xffffff00) | d; + } else regs.c = false; + regs.n = (d & 0x80) != 0; + regs.z = d == 0; + regs.v = false; + //SAEF_log(("I_ROR.B %08x >> %d = %08x", _d, n, d)); + coreSyncPC(); + return [p.cyc[0]+2*n,p.cyc[1],p.cyc[2]]; + } + function I_ROL_M(p) { + var a = exEAtab[p.ea](2); + var d = coreGet16(a), _d = d; + regs.c = (d & 0x8000) != 0; + d = ((d << 1) & 0xffff) | (regs.c ? 1:0); + regs.n = (d & 0x8000) != 0; + regs.z = d == 0; + regs.v = false; + corePut16(a, d); + //SAEF_log(("I_ROL_M.W %08x << 1 = %08x", _d, d)); + coreSyncPC(); + return p.cyc; + } + function I_ROR_M(p) { + var a = exEAtab[p.ea](2); + var d = coreGet16(a), _d = d; + regs.c = (d & 1) != 0; + d = (regs.c ? 0x8000 : 0) | (d >> 1); + regs.n = (d & 0x8000) != 0; + regs.z = d == 0; + regs.v = false; + corePut16(a, d); + //SAEF_log(("I_ROR_M.W %08x >> 1 = %08x", _d, d)); + coreSyncPC(); + return p.cyc; + } - if (n > 0) { - for (; n > 0; --n) { - c = (r & p.ms) != 0; - r <<= 1; - r = (r & p.mz) >>> 0; - if (x) r = (r | 1) >>> 0; - x = c; - } - stEA(dea, p.z, r); - regs.c = regs.x = c; + function I_ROXL_32(p) { + var d = regs.d[p.Dy], _d = d; + var n = p.ir ? regs.d[p.cr] & 63 : p.cr; + if (n) { + regs.c = (d & (1 << (32-n))) != 0; + d = (((d << n) | (d >>> (32-n))) & 0xffffffff) >>> 0; + d = ((d & 0xfffffffe) | (regs.x ? 1 : 0)) >>> 0; + regs.d[p.Dy] = d; + regs.x = regs.c; } else regs.c = regs.x; - + regs.n = (d & 0x80000000) != 0; + regs.z = d == 0; regs.v = false; - regs.n = (r & p.ms) != 0; - regs.z = r == 0; - //BUG.say(sprintf('I_ROXL.%s num %d d $%08x ox %d nx %d r $%08x', szChr(p.z), s, d, _x, regs.x?1:0, r)); - return [p.cyc[0] + (dea.m == M_rdd ? s << 1 : 0), 0,0]; //FIXME + //SAEF_log(("I_ROXL.L %08x << %d = %08x", _d, n, d)); + coreSyncPC(); + return [p.cyc[0]+2*n,p.cyc[1],p.cyc[2]]; } - - function I_ROXR(p) { - var sea = exEA(p.s, p.z); - var s = ldEA(sea, p.z) % 64; - var dea = exEA(p.d, p.z); - var d = ldEA(dea, p.z); - var n = s; - var r = d; - var c = false; - var x = regs.x; //var _x = x?1:0; - - if (n > 0) { - for (; n > 0; --n) { - c = (r & 1) != 0; - r >>>= 1; - if (x) r = (p.ms | r) >>> 0; - x = c; - } - stEA(dea, p.z, r); - regs.c = regs.x = c; + function I_ROXL_16(p) { + var d = regs.d[p.Dy] & 0xffff, _d = d; + var n = p.ir ? regs.d[p.cr] & 63 : p.cr; + if (n) { + regs.c = (d & (1 << (16-n))) != 0; + d = ((d << n) | (d >> (16-n))) & 0xffff; + d = (d & 0xfffe) | (regs.x ? 1 : 0); + regs.d[p.Dy] = (regs.d[p.Dy] & 0xffff0000) | d; + regs.x = regs.c; } else regs.c = regs.x; - + regs.n = (d & 0x8000) != 0; + regs.z = d == 0; regs.v = false; - regs.n = (r & p.ms) != 0; - regs.z = r == 0; - //BUG.say(sprintf('I_ROXR.%s num %d d $%08x ox %d nx %d r $%08x', szChr(p.z), s, d, _x, regs.x?1:0, r)); - return [p.cyc[0] + (dea.m == M_rdd ? s << 1 : 0), 0,0]; //FIXME + //SAEF_log(("I_ROXL.W %08x << %d = %08x", _d, n, d)); + coreSyncPC(); + return [p.cyc[0]+2*n,p.cyc[1],p.cyc[2]]; + } + function I_ROXL_8(p) { + var d = regs.d[p.Dy] & 0xff, _d = d; + var n = p.ir ? regs.d[p.cr] & 63 : p.cr; + if (n) { + regs.c = (d & (1 << (8-n))) != 0; + d = ((d << n) | (d >> (8-n))) & 0xff; + d = (d & 0xfe) | (regs.x ? 1 : 0); + regs.d[p.Dy] = (regs.d[p.Dy] & 0xffffff00) | d; + regs.x = regs.c; + } else regs.c = regs.x; + regs.n = (d & 0x80) != 0; + regs.z = d == 0; + regs.v = false; + //SAEF_log(("I_ROXL.B %08x << %d = %08x", _d, n, d)); + coreSyncPC(); + return [p.cyc[0]+2*n,p.cyc[1],p.cyc[2]]; + } + function I_ROXR_32(p) { + var d = regs.d[p.Dy], _d = d; + var n = p.ir ? regs.d[p.cr] & 63 : p.cr; + if (n) { + regs.c = (d & (1 << (n-1))) != 0; + d = (((d << (32-n)) | (d >>> n)) & 0xffffffff) >>> 0; + d = ((regs.x ? 0x80000000 : 0) | (d & 0x7fffffff)) >>> 0; + regs.d[p.Dy] = d; + regs.x = regs.c; + } else regs.c = regs.x; + regs.n = (d & 0x80000000) != 0; + regs.z = d == 0; + regs.v = false; + //SAEF_log(("I_ROXR.L %08x >> %d = %08x", _d, n, d)); + coreSyncPC(); + return [p.cyc[0]+2*n,p.cyc[1],p.cyc[2]]; + } + function I_ROXR_16(p) { + var d = regs.d[p.Dy] & 0xffff, _d = d; + var n = p.ir ? regs.d[p.cr] & 63 : p.cr; + if (n) { + regs.c = (d & (1 << (n-1))) != 0; + d = ((d << (16-n)) | (d >>> n)) & 0xffff; + d = (regs.x ? 0x8000 : 0) | (d & 0x7fff); + regs.d[p.Dy] = (regs.d[p.Dy] & 0xffff0000) | d; + regs.x = regs.c; + } else regs.c = regs.x; + regs.n = (d & 0x8000) != 0; + regs.z = d == 0; + regs.v = false; + //SAEF_log(("I_ROXR.W %08x >> %d = %08x", _d, n, d)); + coreSyncPC(); + return [p.cyc[0]+2*n,p.cyc[1],p.cyc[2]]; + } + function I_ROXR_8(p) { + var d = regs.d[p.Dy] & 0xff, _d = d; + var n = p.ir ? regs.d[p.cr] & 63 : p.cr; + if (n) { + regs.c = (d & (1 << (n-1))) != 0; + d = ((d << (8-n)) | (d >>> n)) & 0xff; + d = (regs.x ? 0x80 : 0) | (d & 0x7f); + regs.d[p.Dy] = (regs.d[p.Dy] & 0xffffff00) | d; + regs.x = regs.c; + } else regs.c = regs.x; + regs.n = (d & 0x80) != 0; + regs.z = d == 0; + regs.v = false; + //SAEF_log(("I_ROXR.B %08x >> %d = %08x", _d, n, d)); + coreSyncPC(); + return [p.cyc[0]+2*n,p.cyc[1],p.cyc[2]]; + } + function I_ROXL_M(p) { + var a = exEAtab[p.ea](2); + var d = coreGet16(a), _d = d; + regs.c = (d & 0x8000) != 0; + d = ((d << 1) & 0xffff) | (regs.x ? 1:0); + regs.x = regs.c; + regs.n = (d & 0x8000) != 0; + regs.z = d == 0; + regs.v = false; + corePut16(a, d); + //SAEF_log(("I_ROXL_M.W %08x << 1 = %08x", _d, d)); + coreSyncPC(); + return p.cyc; + } + function I_ROXR_M(p) { + var a = exEAtab[p.ea](2); + var d = coreGet16(a), _d = d; + regs.c = (d & 1) != 0; + d = (regs.x ? 0x8000 : 0) | (d >> 1); + regs.x = regs.c; + regs.n = (d & 0x8000) != 0; + regs.z = d == 0; + regs.v = false; + corePut16(a, d); + //SAEF_log(("I_ROXR_M.W %08x >> 1 = %08x", _d, d)); + coreSyncPC(); + return p.cyc; } function I_SWAP(p) { - var dea = exEA(p.d, 4); - var d = ldEA(dea, 4); - var r = ((d << 16) | (d >>> 16)) >>> 0; - stEA(dea, 4, r); - + var d = regs.d[p.Dn]; + var r = (((d & 0xffff) << 16) | (d >>> 16)) >>> 0; + regs.d[p.Dn] = r; regs.n = (r & 0x80000000) != 0; regs.z = r == 0; - regs.v = false; - regs.c = false; - //BUG.say(sprintf('I_SWAP.%s d $%08x r $%08x', szChr(p.z), d, r)); + regs.v = regs.c = false; + //SAEF_log(("I_SWAP.W %08x <> %08x", d, r)); + coreSyncPC(); return p.cyc; } /*-----------------------------------------------------------------------*/ /* Bit Manipulation */ - function I_BCHG(p) { - var dz = p.d.m == M_rdd ? 4 : 1; - var sea = exEA(p.s, p.z); - var s = ldEA(sea, p.z); - var dea = exEA(p.d, dz); - var d = ldEA(dea, dz); - var m = (1 << (s % (p.d.m == M_rdd ? 32 : 8))) >>> 0; - - var r = ((d & m) ? (d & ~m) : (d | m)) >>> 0; - stEA(dea, dz, r); + function I_BCHG_DD_32(p) { + var s = regs.d[p.Dn] & 31; + var d = regs.d[p.Dd]; + var m = (1 << s) >>> 0; regs.z = (d & m) == 0; - - /*if (p.d.m == M_rdd) - BUG.say(sprintf('I_BCHG.%s s $%08x == m $%08x, d $%08x, r $%08x', szChr(p.z), s, m, d, r)); - else - BUG.say(sprintf('I_BCHG.%s s $%02x == m $%02x, d $%02x, r $%02x', szChr(p.z), s, m, d, r));*/ - + var r = (d ^ m) >>> 0; + regs.d[p.Dd] = r; + //SAEF_log(("I_BCHG1.L s %08x == m %08x, d %08x, r %08x", s, m, d, r)); + coreSyncPC(); + return p.cyc; + } + function I_BCHG_DE_8(p) { + var a = exEAtab[p.ea](1); + var s = regs.d[p.Dn] & 7; + var d = coreGet8(a); + var m = 1 << s; + regs.z = (d & m) == 0; + var r = d ^ m; + corePut8(a, r); + //SAEF_log(("I_BCHG1.B s %08x == m %08x, d %08x, r %08x", s, m, d, r)); + coreSyncPC(); + return p.cyc; + } + function I_BCHG_ID_32(p) { + var s = coreNext16() & 31; + var d = regs.d[p.Dd]; + var m = (1 << s) >>> 0; + regs.z = (d & m) == 0; + var r = (d ^ m) >>> 0; + regs.d[p.Dd] = r; + //SAEF_log(("I_BCHG2.L s %08x == m %08x, d %08x, r %08x", s, m, d, r)); + coreSyncPC(); + return p.cyc; + } + function I_BCHG_IE_8(p) { + var s = coreNext16() & 7; + var a = exEAtab[p.ea](1); + var d = coreGet8(a); + var m = 1 << s; + regs.z = (d & m) == 0; + var r = d ^ m; + corePut8(a, r); + //SAEF_log(("I_BCHG2.B s %08x == m %08x, d %08x, r %08x", s, m, d, r)); + coreSyncPC(); return p.cyc; } - function I_BCLR(p) { - var dz = p.d.m == M_rdd ? 4 : 1; - var sea = exEA(p.s, p.z); - var s = ldEA(sea, p.z); - var dea = exEA(p.d, dz); - var d = ldEA(dea, dz); - var m = (1 << (s % (p.d.m == M_rdd ? 32 : 8))) >>> 0; - + function I_BCLR_DD_32(p) { + var s = regs.d[p.Dn] & 31; + var d = regs.d[p.Dd]; + var m = (1 << s) >>> 0; + regs.z = (d & m) == 0; var r = (d & ~m) >>> 0; - stEA(dea, dz, r); + regs.d[p.Dd] = r; + //SAEF_log(("I_BCLR1.L s %08x == m %08x, d %08x, r %08x", s, m, d, r)); + coreSyncPC(); + return p.cyc; + } + function I_BCLR_DE_8(p) { + var a = exEAtab[p.ea](1); + var s = regs.d[p.Dn] & 7; + var d = coreGet8(a); + var m = 1 << s; regs.z = (d & m) == 0; - - /*if (p.d.m == M_rdd) - BUG.say(sprintf('I_BCLR.%s s $%08x == m $%08x, d $%08x, r $%08x', szChr(p.z), s, m, d, r)); - else - BUG.say(sprintf('I_BCLR.%s s $%02x == m $%02x, d $%02x, r $%02x', szChr(p.z), s, m, d, r));*/ + var r = d & ~m; + corePut8(a, r); + //SAEF_log(("I_BCLR1.B s %08x == m %08x, d %08x, r %08x", s, m, d, r)); + coreSyncPC(); + return p.cyc; + } + function I_BCLR_ID_32(p) { + var s = coreNext16() & 31; + var d = regs.d[p.Dd]; + var m = (1 << s) >>> 0; + regs.z = (d & m) == 0; + var r = (d & ~m) >>> 0; + regs.d[p.Dd] = r; + //SAEF_log(("I_BCLR2.L s %08x == m %08x, d %08x, r %08x", s, m, d, r)); + coreSyncPC(); + return p.cyc; + } + function I_BCLR_IE_8(p) { + var s = coreNext16() & 7; + var a = exEAtab[p.ea](1); + var d = coreGet8(a); + var m = 1 << s; + regs.z = (d & m) == 0; + var r = d & ~m; + corePut8(a, r); + //SAEF_log(("I_BCLR2.B s %08x == m %08x, d %08x, r %08x", s, m, d, r)); + coreSyncPC(); return p.cyc; } - function I_BSET(p) { - var dz = p.d.m == M_rdd ? 4 : 1; - var sea = exEA(p.s, p.z); - var s = ldEA(sea, p.z); - var dea = exEA(p.d, dz); - var d = ldEA(dea, dz); - var m = (1 << (s % (p.d.m == M_rdd ? 32 : 8))) >>> 0; - + function I_BSET_DD_32(p) { + var s = regs.d[p.Dn] & 31; + var d = regs.d[p.Dd]; + var m = (1 << s) >>> 0; + regs.z = (d & m) == 0; var r = (d | m) >>> 0; - stEA(dea, dz, r); + regs.d[p.Dd] = r; + //SAEF_log(("I_BSET1.L s %08x == m %08x, d %08x, r %08x", s, m, d, r)); + coreSyncPC(); + return p.cyc; + } + function I_BSET_DE_8(p) { + var a = exEAtab[p.ea](1); + var s = regs.d[p.Dn] & 7; + var d = coreGet8(a); + var m = 1 << s; regs.z = (d & m) == 0; - - /*if (p.d.m == M_rdd) - BUG.say(sprintf('I_BSET.%s s $%08x == m $%08x, d $%08x, r $%08x', szChr(p.z), s, m, d, r)); - else - BUG.say(sprintf('I_BSET.%s s $%02x == m $%02x, d $%02x, r $%02x', szChr(p.z), s, m, d, r));*/ + var r = d | m; + corePut8(a, r); + //SAEF_log(("I_BSET1.B s %08x == m %08x, d %08x, r %08x", s, m, d, r)); + coreSyncPC(); + return p.cyc; + } + function I_BSET_ID_32(p) { + var s = coreNext16() & 31; + var d = regs.d[p.Dd]; + var m = (1 << s) >>> 0; + regs.z = (d & m) == 0; + var r = (d | m) >>> 0; + regs.d[p.Dd] = r; + //SAEF_log(("I_BSET2.L s %08x == m %08x, d %08x, r %08x", s, m, d, r)); + coreSyncPC(); + return p.cyc; + } + function I_BSET_IE_8(p) { + var s = coreNext16() & 7; + var a = exEAtab[p.ea](1); + var d = coreGet8(a); + var m = 1 << s; + regs.z = (d & m) == 0; + var r = d | m; + corePut8(a, r); + //SAEF_log(("I_BSET2.B s %08x == m %08x, d %08x, r %08x", s, m, d, r)); + coreSyncPC(); return p.cyc; } - function I_BTST(p) { - var dz = p.d.m == M_rdd ? 4 : 1; - var sea = exEA(p.s, p.z); - var s = ldEA(sea, p.z); - var dea = exEA(p.d, dz); - var d = ldEA(dea, dz); - var m = (1 << (s % (p.d.m == M_rdd ? 32 : 8))) >>> 0; - + function I_BTST_DD_32(p) { + var s = regs.d[p.Dn] & 31; + var d = regs.d[p.Dd]; + var m = (1 << s) >>> 0; regs.z = (d & m) == 0; - - /*if (p.d.m == M_rdd) - BUG.say(sprintf('I_BTST.%s s $%08x == m $%08x, d $%08x, r $%08x', szChr(p.z), s, m, d, r)); + //SAEF_log(("I_BTST1.L s %08x == m %08x, d %08x, zero %d", s, m, d, regs.z?1:0)); + coreSyncPC(); + return p.cyc; + } + function I_BTST_DE_8(p) { + var s = regs.d[p.Dn] & 7; + var d = ldEA8tab[p.ea](); + var m = 1 << s; + regs.z = (d & m) == 0; + //SAEF_log(("I_BTST1.B s %08x == m %08x, d %08x, zero %d", s, m, d, regs.z?1:0)); + coreSyncPC(); + return p.cyc; + } + function I_BTST_ID_32(p) { + var s = coreNext16() & 31; + var d = regs.d[p.Dd]; + var m = (1 << s) >>> 0; + regs.z = (d & m) == 0; + //SAEF_log(("I_BTST2.L s %08x == m %08x, d %08x, zero %d", s, m, d, regs.z?1:0)); + coreSyncPC(); + return p.cyc; + } + function I_BTST_IE_8(p) { + var s = coreNext16() & 7; + var d = ldEA8tab[p.ea](); + var m = 1 << s; + regs.z = (d & m) == 0; + //SAEF_log(("I_BTST2.B s %08x == m %08x, d %08x, zero %d", s, m, d, regs.z?1:0)); + coreSyncPC(); + return p.cyc; + } + + /*-----------------------------------------------------------------------*/ + /* Bitfield >= 68020 (ported from WinUAE) */ + + function I_BFXXX(p) { + var ext = coreNext16(); + var offset = (ext & 0x800) ? regs.d[(ext >> 6) & 7] : (ext >> 6) & 0x1f; + var width = (ext & 0x20) ? regs.d[ext & 7] & 0x1f : ext & 0x1f; if (width == 0) width = 32; + var tmp, bdata = [0,0]; + + if (p.ea >> 3 == 0) { + tmp = regs.d[p.ea & 7]; + offset &= 0x1f; + tmp = ((tmp << offset) | (tmp >>> (32 - offset))) >>> 0; + bdata[0] = (tmp & ((1 << (32 - width)) - 1)) >>> 0; + } else { + if (offset & 0x80000000) offset -= 0x100000000; + addr = exEAtab[p.ea](1); + if (offset) addr += Math.truncate(offset / 8); + var bf = getBitfield(addr, Math.abs(offset), width); + tmp = bf[0]; + bdata = bf[1]; + } + + regs.n = (tmp & 0x80000000) != 0; + if (p.id == ID_BFEXTS) + tmp >>= (32 - width); /* having fun with javascript signed-shift feature */ else - BUG.say(sprintf('I_BTST.%s s $%02x == m $%02x, d $%02x, r $%02x', szChr(p.z), s, m, d, r));*/ + tmp >>>= (32 - width); + + regs.z = tmp == 0; + regs.v = false; + regs.c = false; + + switch (p.id) { + case ID_BFTST: + break; + case ID_BFEXTU: + case ID_BFEXTS: + regs.d[(ext >> 12) & 7] = tmp; + break; + case ID_BFCHG: + tmp = (tmp ^ (0xffffffff >>> (32 - width))) >>> 0; + break; + case ID_BFCLR: + tmp = 0; + break; + case ID_BFFFO: { + var mask = (1 << (width - 1)) >>> 0; + while (mask) { if (tmp & mask) break; mask >>>= 1; offset++; }} + if (offset < 0) offset += 0x100000000; + regs.d[(ext >> 12) & 7] = offset; + break; + case ID_BFSET: + tmp = 0xffffffff >>> (32 - width); + break; + case ID_BFINS: + tmp = regs.d[(ext >> 12) & 7] & (0xffffffff >>> (32 - width)); + regs.n = (tmp & (1 << (width - 1))) != 0; + regs.z = tmp == 0; + break; + } + if (p.id == ID_BFCHG || p.id == ID_BFCLR || p.id == ID_BFSET || p.id == ID_BFINS) { + if (p.ea >> 3 == 0) { + tmp = bdata[0] | (tmp << (32 - width)); + regs.d[p.ea & 7] = (tmp >>> offset) | (tmp << (32 - offset)); + } else { + putBitfield(addr, Math.abs(offset), width, bdata, tmp); + } + } + /*if (p.ea >> 3 == 0) + SAEF_log(("I_%s at D%d Do %d Dw %d {%d:%d} | s %08x data %08x:%08x | N=%d Z=%d", bfName(p.id), p.ea&7, (ext & 0x800)?1:0,(ext & 0x20)?1:0, offset,width, tmp,bdata[0],bdata[1], regs.n?1:0, regs.z?1:0)); + else + SAEF_log(("I_%s at %08x Do %d Dw %d {%d:%d} | s %08x data %08x:%08x | N=%d Z=%d", bfName(p.id), addr, (ext & 0x800)?1:0,(ext & 0x20)?1:0, offset,width, tmp,bdata[0],bdata[1], regs.n?1:0, regs.z?1:0)); + */ + coreSyncPC(); return p.cyc; } /*-----------------------------------------------------------------------*/ /* Binary-Coded Decimal */ - function I_ABCD(p) { - var sea = exEA(p.s, p.z); - var s = ldEA(sea, p.z); - var dea = exEA(p.d, p.z); - var d = ldEA(dea, p.z); - var x = regs.x ? 1 : 0; - var c = false; - - var s_h = (s >> 4) & 0xf; - var s_l = s & 0xf; - var d_h = (d >> 4) & 0xf; - var d_l = d & 0xf; - - var l = s_l + d_l + x; - if (l > 9) { - l -= 10; - c = true; - } - var h = s_h + d_h + (c ? 1 : 0); - c = false; - if (h > 9) { - h -= 10; - c = true; - } - var r = (h << 4) | l; - - stEA(dea, p.z, r); - - regs.x = regs.c = c; + function I_ABCD_D(p) { + var s = regs.d[p.Ry] & 0xff; + var d = regs.d[p.Rx] & 0xff; + var lo = (s & 0x0f) + (d & 0x0f) + (regs.x?1:0); + var hi = (s & 0xf0) + (d & 0xf0); + var r = hi + lo; + if (lo > 9) r += 6; + if ((r & 0x3f0) > 0x90) { + r = (r + 0x60) & 0xff; + regs.x = regs.c = true; + } else regs.x = regs.c = false; if (r) regs.z = false; - if (undef) { - regs.n = !regs.n; //undef - regs.v = !regs.v; //undef - } - //BUG.say(sprintf('I_ABCD.%s s $%02x d $%02x x %d | s_h %d s_l %d d_h %d d_l %d | r $%02x c %d', szChr(p.z), s, d, x, s_h, s_l, d_h, d_l, r, c?1:0)); + //n,v undef + regs.d[p.Rx] = (regs.d[p.Rx] & 0xffffff00) | r; + //SAEF_log(("I_ABCD_D.B %02x + %02x = %02x carry %d", s,d,r,regs.c?1:0)); + coreSyncPC(); + return p.cyc; + } + function I_ABCD_A(p) { + regs.a[p.Ry] -= aIncDec[1][p.Ry]; var s = coreGet8(regs.a[p.Ry]); + regs.a[p.Rx] -= aIncDec[1][p.Rx]; var d = coreGet8(regs.a[p.Rx]); + var lo = (s & 0x0f) + (d & 0x0f) + (regs.x?1:0); + var hi = (s & 0xf0) + (d & 0xf0); + var r = hi + lo; + if (lo > 9) r += 6; + if ((r & 0x3f0) > 0x90) { + r = (r + 0x60) & 0xff; + regs.x = regs.c = true; + } else regs.x = regs.c = false; + if (r) regs.z = false; + //n,v undef + corePut8(regs.a[p.Rx], r); + //SAEF_log(("I_ABCD_A.B %02x + %02x = %02x carry %d", s,d,r,regs.c?1:0)); + coreSyncPC(); return p.cyc; } - function I_NBCD(p) { - var dea = exEA(p.d, p.z); - var d = ldEA(dea, p.z); - var c = false; - - var d_h = (d >> 4) & 0xf; - var d_l = d & 0xf; - - var l = 0 - d_l; - if (l < 0) { - l += 10; - c = true; - } - var h = 0 - d_h - (c ? 1 : 0); - c = false; - if (h < 0) { - h += 10; - c = true; - } - var r = (h << 4) | l; - - stEA(dea, p.z, r); - - regs.x = regs.c = c; + function I_SBCD_D(p) { + var s = regs.d[p.Rx] & 0xff; + var d = regs.d[p.Ry] & 0xff; + var lo = (d & 0x0f) - (s & 0x0f) - (regs.x?1:0); + var hi = (d & 0xf0) - (s & 0xf0); + var r = hi + lo, bcd = 0; + if (lo & 0xf0) { r -= 6; bcd = 6; }; + if ((((d & 0xff) - (s & 0xff) - (regs.x?1:0)) & 0x100) > 0xff) r = (r - 0x60) & 0xff; + regs.x = regs.c = (((d & 0xff) - (s & 0xff) - bcd - (regs.x?1:0)) & 0x300) > 0xff; if (r) regs.z = false; - if (undef) { - regs.n = !regs.n; //undef - regs.v = !regs.v; //undef - } - //BUG.say(sprintf('I_NBCD.%s s $%02x d $%02x x %d | s_h %d s_l %d d_h %d d_l %d | r $%02x c %d', szChr(p.z), s, d, x, s_h, s_l, d_h, d_l, r, c?1:0)); + //n,v undef + regs.d[p.Ry] = (regs.d[p.Ry] & 0xffffff00) | r; + //SAEF_log(("I_SBCD_D.B %02x - %02x = %02x carry %d", d,s,r,regs.c?1:0)); + coreSyncPC(); + return p.cyc; + } + function I_SBCD_A(p) { + regs.a[p.Rx] -= aIncDec[1][p.Rx]; var s = coreGet8(regs.a[p.Rx]); + regs.a[p.Ry] -= aIncDec[1][p.Ry]; var d = coreGet8(regs.a[p.Ry]); + var lo = (d & 0x0f) - (s & 0x0f) - (regs.x?1:0); + var hi = (d & 0xf0) - (s & 0xf0); + var r = hi + lo, bcd = 0; + if (lo & 0xf0) { r -= 6; bcd = 6; }; + if ((((d & 0xff) - (s & 0xff) - (regs.x?1:0)) & 0x100) > 0xff) r = (r - 0x60) & 0xff; + regs.x = regs.c = (((d & 0xff) - (s & 0xff) - bcd - (regs.x?1:0)) & 0x300) > 0xff; + if (r) regs.z = false; + //n,v undef + corePut8(regs.a[p.Ry], r); + //SAEF_log(("I_SBCD_A.B %02x - %02x = %02x carry %d", d,s,r,regs.c?1:0)); + coreSyncPC(); return p.cyc; } - function I_SBCD(p) { - var sea = exEA(p.s, p.z); - var s = ldEA(sea, p.z); - var dea = exEA(p.d, p.z); - var d = ldEA(dea, p.z); - var x = regs.x ? 1 : 0; - var c = false; - - var s_h = (s >> 4) & 0xf; - var s_l = s & 0xf; - var d_h = (d >> 4) & 0xf; - var d_l = d & 0xf; - - var l = d_l - s_l - x; - if (l < 0) { - l += 10; - c = true; - } - var h = d_h - s_h - (c ? 1 : 0); - c = false; - if (h < 0) { - h += 10; - c = true; - } - var r = (h << 4) | l; - - stEA(dea, p.z, r); - - regs.x = regs.c = c; + function I_NBCD_D(p) { + var d = regs.d[p.Dd] & 0xff; + var lo = -(d & 0x0f) - (regs.x?1:0); + var hi = -(d & 0xf0); + if (lo > 9) { lo -= 6; } + var r = hi + lo; + if ((r & 0x1f0) > 0x90) { + r = (r - 0x60) & 0xff; + regs.x = regs.c = true; + } else regs.x = regs.c = false; if (r) regs.z = false; - if (undef) { - regs.n = !regs.n; //undef - regs.v = !regs.v; //undef - } - //BUG.say(sprintf('I_SBCD.%s s $%02x d $%02x x %d | s_h %d s_l %d d_h %d d_l %d | r $%02x c %d', szChr(p.z), s, d, x, s_h, s_l, d_h, d_l, r, c?1:0)); + //n,v undef + regs.d[p.Dd] = (regs.d[p.Dd] & 0xffffff00) | r; + //SAEF_log(("I_NBCD_D.B 0 - %02x = %02x carry %d", d,r,regs.c?1:0)); + coreSyncPC(); + return p.cyc; + } + function I_NBCD_E(p) { + var a = exEAtab[p.ea](1); + var d = coreGet8(a); + var lo = -(d & 0x0f) - (regs.x?1:0); + var hi = -(d & 0xf0); + if (lo > 9) { lo -= 6; } + var r = hi + lo; + if ((r & 0x1f0) > 0x90) { + r = (r - 0x60) & 0xff; + regs.x = regs.c = true; + } else regs.x = regs.c = false; + if (r) regs.z = false; + //n,v undef + corePut8(a, r); + //SAEF_log(("I_NBCD_E.B 0 - %02x = %02x carry %d", d,r,regs.c?1:0)); + coreSyncPC(); + return p.cyc; + } + + function I_PACK_D(p) { /* >= 68020 */ + var adj = coreNext16(); + var s = (regs.d[p.Rx] & 0xffff) + adj; if (s > 0xffff) s -= 0x10000; + var d = ((s >> 4) & 0xf0) | (s & 0xf); + regs.d[p.Ry] = (regs.d[p.Ry] & 0xffffff00) | d; + //SAEF_log(("I_PACK D%d,D%d,#%04x | %04x -> %02x", p.Rx,p.Ry,adj, s,d)); + //ccna + coreSyncPC(); + return p.cyc; + } + function I_PACK_A(p) { /* >= 68020 */ + var adj = coreNext16(); + regs.a[p.Rx] -= aIncDec[1][p.Rx]; var s_hi = coreGet8(regs.a[p.Rx]); + regs.a[p.Rx] -= aIncDec[1][p.Rx]; var s_lo = coreGet8(regs.a[p.Rx]); + var s = (((s_hi & 0xf) << 8) | (s_lo & 0xf)) + adj; if (s > 0xffff) s -= 0x10000; + var d = (((s >> 4) & 0xf0) | (s & 0xf)); + regs.a[p.Ry] -= aIncDec[1][p.Ry]; corePut8(regs.a[p.Ry], d); + //SAEF_log(("I_PACK -(A%d),-(A%d),#%04x | %04x -> %02x", p.Rx,p.Ry,adj, s,d)); + //ccna + coreSyncPC(); + return p.cyc; + } + + function I_UNPK_D(p) { /* >= 68020 */ + var adj = coreNext16(); + var s = regs.d[p.Rx] & 0xffff; + var d = (((s << 4) & 0xf00) | (s & 0xf)) + adj; if (d > 0xffff) d -= 0x10000; + regs.d[p.Ry] = (regs.d[p.Ry] & 0xffff0000) | d; + //SAEF_log(("I_UNPK D%d,D%d,#%04x | %02x -> %04x", p.Rx,p.Ry,adj, s&0xff,d)); + //ccna + coreSyncPC(); + return p.cyc; + } + function I_UNPK_A(p) { /* >= 68020 */ + var adj = coreNext16(); + regs.a[p.Rx] -= aIncDec[1][p.Rx]; var s = coreGet8(regs.a[p.Rx]); + var d = (((s << 4) & 0xf00) | (s & 0xf)) + adj; if (d > 0xffff) d -= 0x10000; + regs.a[p.Ry] -= aIncDec[1][p.Ry]; corePut8(regs.a[p.Ry], d >> 8); + regs.a[p.Ry] -= aIncDec[1][p.Ry]; corePut8(regs.a[p.Ry], d & 0xff); + //SAEF_log(("I_UNPK -(A%d),-(A%d),#%04x | %02x -> %04x", p.Rx,p.Ry,adj, s,d)); + //ccna + coreSyncPC(); return p.cyc; } @@ -1795,137 +5599,172 @@ function CPU() { /* Program Control */ function I_Bcc(p) { - var cc = p.c.cc; - var dp = p.c.dp; - var dp16; - var pc; + var pc = coreGetPC(); + var dp; - if (dp == 0) dp16 = nextIWord(); - //else if (dp == 255) Fatal(SAEE_CPU_68020_Required, 'cpu.I_Bcc() Full extension index detected (not a 68000 programm)'); + if (p.dp == 0) dp = coreNext16(); + else if (p.dp == 255) dp = coreNext32(); /* 68020 only*/ - if (ccTrue(cc)) { - if (dp == 0) pc = add32(regs.pc - 2, extWord(dp16)); - else pc = add32(regs.pc, extByte(dp)); - //BUG.say(sprintf('I_Bcc pc $%08x', pc)); - setPC(pc); + if (ccTab[p.cc]()) { + if (p.dp == 0) pc = add32(pc, extWord(dp)); + else if (p.dp == 255) pc = add32(pc, dp); + else pc = add32(pc, extByte(p.dp)); + //SAEF_log(("I_Bcc pc $%08x", pc)); + if (pc & 1) return coreException3i(p.op, pc); + coreSetPC(pc); return p.cycTaken; } //ccna + coreSyncPC(); return p.cyc; } - + function I_DBcc(p) { - var cc = p.c.cc; - var dp = nextIWord(); + var pc = coreGetPC(); + var dp = coreNext16(); var cyc; - if (!ccTrue(cc)) { - var ea = exEA(new EffAddr(M_rdd, p.c.dr), p.z); - var dr = ldEA(ea, p.z); - - if (dr--) { - var pc = add32(regs.pc - 2, extWord(dp)); - setPC(pc); - cyc = p.cycFalseTaken; - } else { - dr = 0xffff; - cyc = p.cycFalse; + if (!ccTab[p.cc]()) { + var dr = (regs.d[p.Dn] & 0xffff) - 1; if (dr < 0) dr += 0x10000; + regs.d[p.Dn] = (regs.d[p.Dn] & 0xffff0000) | dr; + + if (dr != 0xffff) { + pc = add32(pc, extWord(dp)); + if (pc & 1) return coreException3i(p.op, pc); + coreSetPC(pc); + return p.cyc; } - stEA(ea, p.z, dr); - } else cyc = p.cycTrue; + cyc = p.cycNotTakenFalse; + } else cyc = p.cycNotTakenTrue; //ccna - return cyc; + coreSyncPC(); + return cyc; } function I_Scc(p) { - //var cc = p.s.r; - var cc = p.c.cc; - var dea = exEA(p.d, p.z); - //var foo = ldEA(dea, p.z); /* In the MC68000 and MC68008 a memory location is read before it is cleared. */ - var isTrue = ccTrue(cc); - stEA(dea, p.z, isTrue ? 0xff : 0); + var rdd = (p.ea >> 3) == 0; + var isTrue = ccTab[p.cc](); + + if (rdd) { + var Dn = p.ea & 7; + regs.d[Dn] = (regs.d[Dn] & 0xffffff00) | (isTrue ? 0xff : 0x00); + } else { + var a = exEAtab[p.ea](1); + /* page 4-173: In the MC68000 and MC68008 a memory location is read before it is cleared. */ + if (model < 68020) { + var foo = coreGet8(a); + } + corePut8(a, isTrue ? 0xff : 0x00); + } //ccna - //BUG.say(sprintf('I_S%s, cc %d, ccTrue %d, cyc %d', ccNames[cc], cc, ccTrue(cc)?1:0, isTrue ? p.cycTrue : p.cycFalse)); - return isTrue ? p.cycTrue : p.cycFalse; + //SAEF_log(("I_S%s, cc %d, ccTrue %d", ccNames[p.cc], p.cc, isTrue?1:0)); + coreSyncPC(); + return isTrue ? (rdd ? p.cycTrue : p.cyc) : (rdd ? p.cycFalse : p.cyc); } function I_BRA(p) { - var dp = p.c.dp; - var pc; + var dp, pc = coreGetPC(); - if (dp == 0) { - dp = extWord(nextIWord()); - pc = add32(regs.pc - 2, dp); - } - //else if (dp == 255) Fatal(SAEE_CPU_68020_Required, 'cpu.I_BRA() Full extension index detected (not a 68000 programm)'); - else pc = add32(regs.pc, extByte(dp)); - - setPC(pc); + if (p.dp == 0) dp = extWord(coreNext16()); + else if (p.dp == 255) dp = coreNext32(); /* 68020 only */ + else dp = extByte(p.dp); + pc = add32(pc, dp); + if (pc & 1) return coreException3i(p.op, pc); + coreSetPC(pc); //ccna - return p.cycTaken; + return p.cyc; } function I_BSR(p) { - var dp = p.c.dp; - var pc; + var dp, pc = coreGetPC(); - if (dp == 0) { - dp = extWord(nextIWord()); - pc = add32(regs.pc - 2, dp); - } - //else if (dp == 255) Fatal(SAEE_CPU_68020_Required, 'cpu.I_BSR() Full extension index detected (not a 68000 programm)'); - else pc = add32(regs.pc, extByte(dp)); - - stEA(exEA(new EffAddr(M_ripr, 7), 4), 4, regs.pc); - setPC(pc); + if (p.dp == 0) dp = extWord(coreNext16()); + else if (p.dp == 255) dp = coreNext32(); /* 68020 only */ + else dp = extByte(p.dp); + pc = add32(pc, dp); + if (pc & 1) return coreException3i(p.op, pc); + //SAEF_log(("I_BSR $%08x -> $%08x", coreGetPC(), pc)); + stackPut32(coreGetPC()); + coreSetPC(pc); //ccna - return p.cycTaken; + return p.cyc; } function I_JMP(p) { - var dea = exEA(p.d, p.z); - setPC(dea.a); - //ccna - //BUG.say(sprintf('I_JMP $%08x', dea.a)); + var pc = exEAtab[p.ea](4); + if (pc & 1) return coreException3i(p.op, pc); + coreSetPC(pc); + //ccna + //SAEF_log(("I_JMP $%08x", pc)); return p.cyc; } function I_JSR(p) { - var dea = exEA(p.d, p.z); - stEA(exEA(new EffAddr(M_ripr, 7), 4), 4, regs.pc); - setPC(dea.a); - //ccna - //BUG.say(sprintf('I_JSR $%08x', dea.a)); - return p.cyc; - } - - function I_RTR(p) { - var ccr = ldEA(exEA(new EffAddr(M_ripo, 7), 2), 2) & 0xff; - var pc = ldEA(exEA(new EffAddr(M_ripo, 7), 4), 4); - setCCR(ccr); - setPC(pc); - //BUG.say(sprintf('I_RTR crr $%04x pc $%08x', crr, pc)); - return p.cyc; - } - - function I_RTS(p) { - var pc = ldEA(exEA(new EffAddr(M_ripo, 7), 4), 4); - //BUG.say(sprintf('I_RTS() regs.pc $%08x newpc $%08x', regs.pc, pc)); - setPC(pc); - //ccna - return p.cyc; - } - - function I_TST(p) { - var dea = exEA(p.d, p.z); - var r = ldEA(dea, p.z); //r = extAuto(r, p.z); - flgLogical(r, p.z); - //BUG.say(sprintf('I_TST.%s r $%08x', szChr(p.z), r)); + var pc = exEAtab[p.ea](4); + if (pc & 1) return coreException3i(p.op, pc); + stackPut32(coreGetPC()); + coreSetPC(pc); + //ccna + //SAEF_log(("I_JSR $%08x", pc)); return p.cyc; } function I_NOP(p) { - //BUG.say('I_NOP'); + //SAEF_log("I_NOP"); + coreSyncPC(); + return p.cyc; + } + + function I_RTD(p) { /* >= 68010 */ + var pc = stackGet32(); + var dp = coreNext16(); + + pc = add32(pc, extWord(dp)); + //SAEF_log(("I_RTD oldpc $%08x newpc $%08x dp %d", regs.pc, pc, castWord(dp))); + if (pc & 1) return coreException3i(p.op, pc); + coreSetPC(pc); + //ccna + return p.cyc; + } + + function I_RTR(p) { + var ccr = stackGet16() & 0xff; + var pc = stackGet32(); + coreSetCCR(ccr); + //SAEF_log(("I_RTR crr $%04x pc $%08x", crr, pc)); + if (pc & 1) return coreException3i(p.op, pc); + coreSetPC(pc); + return p.cyc; + } + + function I_RTS(p) { + var pc = stackGet32(); + //SAEF_log("I_RTS regs.pc $%08x newpc $%08x", regs.pc, pc); + if (pc & 1) return coreException3i(p.op, pc); + coreSetPC(pc); + //ccna + return p.cyc; + } + + function I_TST_8(p) { + var r = ldEA8tab[p.ea](); + flgLogical(r, p.zm); + //SAEF_log(("I_TST.B r $%08x", r)); + coreSyncPC(); + return p.cyc; + } + function I_TST_16(p) { + var r = ldEA16tab[p.ea](); + flgLogical(r, p.zm); + //SAEF_log(("I_TST.W r $%08x", r)); + coreSyncPC(); + return p.cyc; + } + function I_TST_32(p) { + var r = ldEA32tab[p.ea](); + flgLogical(r, p.zm); + //SAEF_log(("I_TST.L r $%08x", r)); + coreSyncPC(); return p.cyc; } @@ -1933,125 +5772,133 @@ function CPU() { /* System Control - CCR */ function I_ANDI_CCR(p) { - var sea = exEA(p.s, p.z); - var s = ldEA(sea, p.z); - var d = getCCR(); + var s = coreNext16() & 0xff; + var d = coreGetCCR(); var r = s & d; - setCCR(r); - //BUG.say(sprintf('I_ANDI_CCR.%s val $%02x, old $%02x new $%02x', szChr(p.z), s, d, r)); + coreSetCCR(r); + //SAEF_log(("I_ANDI_CCR.B val $%02x, old $%02x new $%02x", s, d, r)); + coreSyncPC(); return p.cyc; } function I_EORI_CCR(p) { - var sea = exEA(p.s, p.z); - var s = ldEA(sea, p.z); - var d = getCCR(); + var s = coreNext16() & 0xff; + var d = coreGetCCR(); var r = s ^ d; - setCCR(r); - //BUG.say(sprintf('I_EORI_CCR.%s val $%02x, old $%02x new $%02x', szChr(p.z), s, d, r)); + coreSetCCR(r); + //SAEF_log(("I_EORI_CCR.B val $%02x, old $%02x new $%02x", s, d, r)); + coreSyncPC(); return p.cyc; } function I_ORI_CCR(p) { - var sea = exEA(p.s, p.z); - var s = ldEA(sea, p.z); - var d = getCCR(); + var s = coreNext16() & 0xff; + var d = coreGetCCR(); var r = s | d; - setCCR(r); - //BUG.say(sprintf('I_ORI_CCR.%s val $%02x, old $%02x new $%02x', szChr(p.z), s, d, r)); + coreSetCCR(r); + //SAEF_log(("I_ORI_CCR.B val $%02x, old $%02x new $%02x", s, d, r)); + coreSyncPC(); return p.cyc; } function I_MOVE_2CCR(p) { - var sea = exEA(p.s, p.z); - var ccr = ldEA(sea, p.z) & 0xff; - //BUG.say(sprintf('I_MOVE_2CCR.%s old $%02x new $%02x', szChr(p.z), getCCR(), ccr)); - setCCR(ccr); + var ccr = ldEA16tab[p.ea]() & 0xff; + //SAEF_log(("I_MOVE_2CCR.W old $%02x new $%02x", coreGetCCR(), ccr)); + coreSyncPC(); + coreSetCCR(ccr); return p.cyc; } - /*function I_MOVE_CCR2(p) { //ups, not for the 68000 - var ccr = getCCR(); - var dea = exEA(p.d, p.z); - stEA(dea, p.z, ccr); - //ccna - //BUG.say(sprintf('I_MOVE_CCR2.%s $%02x', szChr(p.z), ccr)); + function I_MOVE_CCR2(p) { /* >= 68010 */ + var ccr = coreGetCCR(); + stEA16tab[p.ea](ccr); + //SAEF_log(("I_MOVE_CCR2.W $%02x", ccr)); + coreSyncPC(); + //ccna return p.cyc; - }*/ + } /*-----------------------------------------------------------------------*/ /* System Control - SR */ function I_ANDI_SR(p) { if (regs.s) { - var sea = exEA(p.s, p.z); - var s = ldEA(sea, p.z); - var d = getSR(); + var s = coreNext16(); + var d = coreGetSR(); var r = s & d; - //BUG.say(sprintf('I_ANDI_SR.%s val $%02x, old $%02x new $%02x', szChr(p.z), s, d, r)); - setSR(r); + //SAEF_log(("I_ANDI_SR.W val $%04x, old $%04x new $%04x", s, d, r)); + coreSetSR(r); + coreSyncPC(); + //ccna return p.cyc; } else { - //BUG.say('I_ANDI_SR PRIVILIG VIOLATION'); - regs.pc = fault.pc; - return exception(8); + //SAEF_log("I_ANDI_SR PRIVILIG VIOLATION"); + //coreClrPC(); + return coreException(8); } } function I_EORI_SR(p) { if (regs.s) { - var sea = exEA(p.s, p.z); - var s = ldEA(sea, p.z); - var d = getSR(); + var s = coreNext16(); + var d = coreGetSR(); var r = s ^ d; - //BUG.say(sprintf('I_EORI_SR.%s val $%02x, old $%02x new $%02x', szChr(p.z), s, d, r)); - setSR(r); + //SAEF_log(("I_EORI_SR.W val $%04x, old $%04x new $%04x", s, d, r)); + coreSetSR(r); + coreSyncPC(); + //ccna return p.cyc; } else { - //BUG.say('I_EORI_SR PRIVILIG VIOLATION'); - regs.pc = fault.pc; - return exception(8); + //SAEF_log("I_EORI_SR PRIVILIG VIOLATION"); + //coreClrPC(); + return coreException(8); } } function I_ORI_SR(p) { if (regs.s) { - var sea = exEA(p.s, p.z); - var s = ldEA(sea, p.z); - var d = getSR(); + var s = coreNext16(); + var d = coreGetSR(); var r = s | d; - //BUG.say(sprintf('I_ORI_SR.%s val $%02x, old $%02x new $%02x', szChr(p.z), s, d, r)); - setSR(r); + //SAEF_log(("I_ORI_SR.W val $%04x, old $%04x new $%04x", s, d, r)); + coreSetSR(r); + coreSyncPC(); + //ccna return p.cyc; } else { - //BUG.say('I_ORI_SR PRIVILIG VIOLATION'); - regs.pc = fault.pc; - return exception(8); + //SAEF_log("I_ORI_SR PRIVILIG VIOLATION"); + //coreClrPC(); + return coreException(8); } } function I_MOVE_2SR(p) { if (regs.s) { - var sea = exEA(p.s, p.z); - var sr = ldEA(sea, p.z); - //BUG.say(sprintf('I_MOVE_2SR.%s sr $%04x', szChr(p.z), sr)); - setSR(sr); + var sr = ldEA16tab[p.ea](); + //SAEF_log(("I_MOVE_2SR.W sr $%04x", sr)); + coreSetSR(sr); + coreSyncPC(); + //ccna return p.cyc; } else { - //BUG.say('I_MOVE_2SR PRIVILIG VIOLATION'); - regs.pc = fault.pc; - return exception(8); + //SAEF_log("I_MOVE_2SR PRIVILIG VIOLATION"); + //coreClrPC(); + return coreException(8); } } - function I_MOVE_SR2(p) { - var sr = getSR(); - var dea = exEA(p.d, p.z); - //var foo = ldEA(dea, p.z); /* Memory destination is read before it is written to. */ - stEA(dea, p.z, sr); - //ccna - //BUG.say(sprintf('I_MOVE_SR2.%s sr $%04x', szChr(p.z), sr)); - return p.cyc; + if (regs.s || model == 68000) { /* This instruction is not privileged for the MC68000 and MC68008 */ + var sr = coreGetSR(); + //SAEF_log(("I_MOVE_SR2.W sr $%04x", sr)); + stEA16tab[p.ea](sr); + coreSyncPC(); + //ccna + return p.cyc; + } else { + //SAEF_log("I_MOVE_2SR PRIVILIG VIOLATION"); + //coreClrPC(); + return coreException(8); + } } /*-----------------------------------------------------------------------*/ @@ -2059,1305 +5906,1371 @@ function CPU() { function I_MOVE_USP2A(p) { if (regs.s) { - var dea = exEA(p.d, p.z); - stEA(dea, p.z, regs.usp); + //SAEF_log(("I_MOVE_USP2A.L usp $%08x", regs.usp)); + regs.a[p.An] = regs.usp; + coreSyncPC(); return p.cyc; } else { - //BUG.say('I_MOVE_USP PRIVILIG VIOLATION'); - regs.pc = fault.pc; - return exception(8); + //SAEF_log("I_MOVE_USP PRIVILIG VIOLATION"); + //coreClrPC(); + return coreException(8); } } function I_MOVE_A2USP(p) { if (regs.s) { - var sea = exEA(p.s, p.z); - regs.usp = ldEA(sea, p.z); + regs.usp = regs.a[p.An]; + //SAEF_log(("I_MOVE_A2USP.L usp $%08x", regs.usp)); + coreSyncPC(); return p.cyc; } else { - //BUG.say('I_MOVE_USP PRIVILIG VIOLATION'); - regs.pc = fault.pc; - return exception(8); + //SAEF_log("I_MOVE_USP PRIVILIG VIOLATION"); + //coreClrPC(); + return coreException(8); + } + } + + /*-----------------------------------------------------------------------*/ + /* System Control - MOVEC */ + + function I_MOVE_2C(p) { /* >= 68010 */ + var ext = coreNext16(); + if (regs.s) { + var cr = ext & 0xfff; + + if (movecValid(cr)) { + if (ext & 0x8000) + var data = regs.a[(ext >> 12) & 7]; + else + var data = regs.d[(ext >> 12) & 7]; + + movec2C(cr, data); + //SAEF_log("I_MOVE_2C.L %s%d,%s [%08x]", (ext&0x8000)?"A":"D",(ext>>12)&7, movecRegName(cr), data); + + coreSyncPC(); + //ccna + return p.cyc; + } else { + //coreSyncPC(); + return coreIllegal(p.op); + } + } else { + //SAEF_log("I_MOVE_2C PRIVILIG VIOLATION"); + //coreClrPC(); + return coreException(8); + } + } + + function I_MOVE_C2(p) { /* >= 68010 */ + var ext = coreNext16(); + if (regs.s) { + var cr = ext & 0xfff; + + if (movecValid(cr)) { + var data = movecC2(cr); + //SAEF_log("I_MOVE_C2.L %s,%s%d [%08x]", movecRegName(cr), (ext&0x8000)?"A":"D", (ext>>12)&7, data); + + if (ext & 0x8000) + regs.a[(ext >> 12) & 7] = data; + else + regs.d[(ext >> 12) & 7] = data; + + coreSyncPC(); + //ccna + return p.cyc; + } else { + //coreSyncPC(); + return coreIllegal(p.op); + } + } else { + //SAEF_log("I_MOVE_C2 PRIVILIG VIOLATION"); + //coreClrPC(); + return coreException(8); + } + } + + /*-----------------------------------------------------------------------*/ + /* System Control - MOVES, ignore the registers SFC/DFC for now */ + + function I_MOVES_32(p) { /* >= 68010 */ + if (regs.s) { + var args = coreNext16(); + //SAEF_log(("I_MOVES.L %04x", args)); + if (args & 0x800) { + var s = (args & 0x8000) ? regs.a[(args >> 12) & 7] : regs.d[(args >> 12) & 7]; + stEA32tab[p.ea](s); + } else { + if (args & 0x8000) regs.a[(args >> 12) & 7] = ldEA32tab[p.ea](); + else regs.d[(args >> 12) & 7] = ldEA32tab[p.ea](); + } + //ccna + coreSyncPC(); + return p.cyc; + } else { + //SAEF_log("I_MOVES PRIVILIG VIOLATION"); + //coreClrPC(); + return coreException(8); + } + } + function I_MOVES_16(p) { /* >= 68010 */ + if (regs.s) { + var args = coreNext16(); + //SAEF_log(("I_MOVES.W %04x", args)); + if (args & 0x800) { + var s = (args & 0x8000) ? regs.a[(args >> 12) & 7] : regs.d[(args >> 12) & 7]; + stEA16tab[p.ea](s & 0xffff); + } else { + var s = ldEA16tab[p.ea](); + if (args & 0x8000) + regs.a[(args >> 12) & 7] = extWord(s); + else + regs.d[(args >> 12) & 7] = (regs.d[(args >> 12) & 7] & 0xffff0000) | s; + } + //ccna + coreSyncPC(); + return p.cyc; + } else { + //SAEF_log("I_MOVES PRIVILIG VIOLATION"); + //coreClrPC(); + return coreException(8); + } + } + function I_MOVES_8(p) { /* >= 68010 */ + if (regs.s) { + var args = coreNext16(); + //SAEF_log(("I_MOVES.B %04x", args)); + if (args & 0x800) { + var s = (args & 0x8000) ? regs.a[(args >> 12) & 7] : regs.d[(args >> 12) & 7]; + stEA8tab[p.ea](s & 0xff); + } else { + var s = ldEA8tab[p.ea](); + if (args & 0x8000) + regs.a[(args >> 12) & 7] = extByte(s); + else + regs.d[(args >> 12) & 7] = (regs.d[(args >> 12) & 7] & 0xffffff00) | s; + } + //ccna + coreSyncPC(); + return p.cyc; + } else { + //SAEF_log("I_MOVES PRIVILIG VIOLATION"); + //coreClrPC(); + return coreException(8); } } /*-----------------------------------------------------------------------*/ /* System Control */ - function I_CHK(p) { - var sea = exEA(p.s, p.z); - var s = ldEA(sea, p.z); - var dea = exEA(p.d, p.z); - var d = ldEA(dea, p.z); + function I_BKPT(p) { /* >= 68010, FIX not implemented */ + //SAEF_log(("I_BKPT vec %d", p.v)); + //ccna + coreSyncPC(); + return p.cyc; + } - //BUG.say(sprintf('I_CHK.%s s $%08x d $%08x (d>s||d<0)', szChr(p.z), s, d)); + function I_CHK_16(p) { + var s = castWord(ldEA16tab[p.ea]()); + var d = castWord(regs.d[p.Dn] & 0xffff); - if (undef) { - regs.z = !regs.z; //undef - regs.v = !regs.v; //undef - regs.c = !regs.c; //undef - } - if (d > s) { - regs.n = false; - regs.pc = fault.pc; - return exception(6) + p.cycTaken; - } else if (d & 0x8000) { /* 68000 word only */ + if (d < 0) { + //SAEF_log(("I_CHK.W YES (%d < 0)", d)); regs.n = true; - regs.pc = fault.pc; - return exception(6) + p.cycTaken; + //coreSyncPC(); + return coreException(6); } + else if (d > s) { + //SAEF_log(("I_CHK.W YES (%d > %d)", d, s)); + regs.n = false; + //coreSyncPC(); + return coreException(6); + } + //else n undef + //z v c undef + //SAEF_log(("I_CHK.W no (%d >= 0 && %d < %d)", d, d, s)); + coreSyncPC(); + return p.cyc; + } + function I_CHK_32(p) { + var s = castLong(ldEA32tab[p.ea]()); + var d = castLong(regs.d[p.Dn]); + + if (d < 0) { + //SAEF_log(("I_CHK.L YES (%d < 0)", d)); + regs.n = true; + //coreSyncPC(); + return coreException(6); + } + else if (d > s) { + //SAEF_log(("I_CHK.L YES (%d > %d)", d, s)); + regs.n = false; + //coreSyncPC(); + return coreException(6); + } + //else n undef + //z v c undef + //SAEF_log(("I_CHK.L no (%d >= 0 && %d < %d)", d, d, s)); + coreSyncPC(); + return p.cyc; + } + + function I_CHK2_32(p) { /* >= 68020 */ + var ext = coreNext16(); + var a = exEAtab[p.ea](4); + var lb = coreGet32(a); + var ub = coreGet32(a + 4); + var Rn; + if (ext & 0x8000) + Rn = regs.a[(ext >> 12) & 7]; + else { + Rn = castLong(regs.d[(ext >> 12) & 7]); + lb = castLong(lb); ub = castLong(ub); + } + regs.z = ub == Rn || lb == Rn; + regs.c = lb <= ub ? Rn < lb || Rn > ub : Rn < ub || Rn > lb; // Rn > ub || Rn < lb; + //n v undef + //SAEF_log("I_%s2.L (%d < %d || %d > %d) -> %s", (ext&0x800)?"CHK":"CMP", Rn, lb<=ub?lb:ub, Rn, lb<=ub?ub:lb, regs.c?"true":"false"); + if ((ext & 0x800) && regs.c) { + //coreSyncPC(); + return coreException(6); + } + coreSyncPC(); + return p.cyc; + } + function I_CHK2_16(p) { /* >= 68020 */ + var ext = coreNext16(); + var a = exEAtab[p.ea](2); + var lb = coreGet16(a); + var ub = coreGet16(a + 2); + var Rn; + if (ext & 0x8000) { + Rn = extWord(regs.a[(ext >> 12) & 7] & 0xffff); + lb = extWord(lb); ub = extWord(ub); + } else { + Rn = castWord(regs.d[(ext >> 12) & 7] & 0xffff); + lb = castWord(lb); ub = castWord(ub); + } + regs.z = ub == Rn || lb == Rn; + regs.c = lb <= ub ? Rn < lb || Rn > ub : Rn < ub || Rn > lb; // Rn > ub || Rn < lb; + //n v undef + //SAEF_log("I_%s2.W (%d < %d || %d > %d) -> %s", (ext&0x800)?"CHK":"CMP", Rn, lb<=ub?lb:ub, Rn, lb<=ub?ub:lb, regs.c?"true":"false"); + if ((ext & 0x800) && regs.c) { + //coreSyncPC(); + return coreException(6); + } + coreSyncPC(); + return p.cyc; + } + function I_CHK2_8(p) { /* >= 68020 */ + var ext = coreNext16(); + var a = exEAtab[p.ea](1); + var lb = coreGet8(a); + var ub = coreGet8(a + 1); + var Rn; + if (ext & 0x8000) { + Rn = extByte(regs.a[(ext >> 12) & 7] & 0xff); + lb = extByte(lb); ub = extByte(ub); + } else { + Rn = castByte(regs.d[(ext >> 12) & 7] & 0xff); + lb = castByte(lb); ub = castByte(ub); + } + regs.z = ub == Rn || lb == Rn; + regs.c = lb <= ub ? Rn < lb || Rn > ub : Rn < ub || Rn > lb; // Rn > ub || Rn < lb; + //n v undef + //SAEF_log("I_%s2.B (%d < %d || %d > %d) -> %s", (ext&0x800)?"CHK":"CMP", Rn, lb<=ub?lb:ub, Rn, lb<=ub?ub:lb, regs.c?"true":"false"); + if ((ext & 0x800) && regs.c) { + //coreSyncPC(); + return coreException(6); + } + coreSyncPC(); return p.cyc; } function I_ILLEGAL(p) { - var op = fault.op; - var pc = fault.pc; - - if (op == 0x4E7B && AMIGA.mem.load32(0x10) == 0 && (pc & 0xf80000) == 0xf80000) - Fatal(SAEE_CPU_68020_Required, 'Your Kickstart requires a 68020'); - - if ((op & 0xf000) == 0xf000) { - BUG.say(sprintf('I_ILLEGAL exception 11, line F[1111] emulator, op $%04x, pc $%08x', op, pc)); - //AMIGA.cpu.diss(fault.pc - 8, 20); - //AMIGA.cpu.dump(); - regs.pc = fault.pc; - return exception(11); - } else if ((op & 0xf000) == 0xa000) { - BUG.say(sprintf('I_ILLEGAL exception 10, line A[1010] emulator, op $%04x, pc $%08x', op, pc)); - //AMIGA.cpu.diss(fault.pc - 8, 20); - //AMIGA.cpu.dump(); - regs.pc = fault.pc; - return exception(10); - } - - BUG.say(sprintf('I_ILLEGAL exception 4, op $%04x, pc $%08x', op, pc)); - //AMIGA.cpu.diss(fault.pc - 8, 20); - //AMIGA.cpu.dump(); - regs.pc = fault.pc; - return exception(4); - //ccna + //SAEF_log("I_ILLEGAL op $%04x, pc $%08x", p.op, regs.instruction_pc); + //coreSyncPC(); + return coreIllegal(p.op); } function I_RESET(p) { if (regs.s) { - BUG.say('I_RESET()'); - AMIGA.reset(); + SAEF_log("I_RESET pc $%08x", regs.instruction_pc); + coreReset(); + coreSyncPC(); return p.cyc; } else { - //BUG.say('I_RESET PRIVILIG VIOLATION'); - regs.pc = fault.pc; - return exception(8); + //SAEF_log("I_RESET PRIVILIG VIOLATION"); + //coreClrPC(); + return coreException(8); } } function I_RTE(p) { if (regs.s) { - var sr = ldEA(exEA(new EffAddr(M_ripo, 7), 2), 2); - var pc = ldEA(exEA(new EffAddr(M_ripo, 7), 4), 4); - setSR(sr); - //BUG.say(sprintf('I_RTE sr $%04x newpc $%08x oldpc $%08x', sr, pc, regs.pc)); - setPC(pc); + var sr = stackGet16(); + var pc = stackGet32(); + + if (model == 68000) { + //SAEF_log("I_RTE000 sr $%04x newpc $%08x oldpc $%08x", sr, pc, regs.pc); + } else { + var fmt = stackGet16(); + var frame = fmt >> 12; + var offset = 0; //8 + + //if (frame > 1) SAEF_log("I_RTE010 fmt %04x frame %x sr $%04x newpc $%08x oldpc $%08x", fmt, frame, sr, pc, regs.pc); + + if (frame == 0x0) {}//regs.a[7] += offset; + else if (frame == 0x1) {}//regs.a[7] += offset; + else if (frame == 0x2) regs.a[7] += offset + 4; + else if (frame == 0x4) regs.a[7] += offset + 8; + else if (frame == 0x8) regs.a[7] += offset + 50; + else if (frame == 0x9) regs.a[7] += offset + 12; + else if (frame == 0xa) regs.a[7] += offset + 24; + else if (frame == 0xb) regs.a[7] += offset + 84; + else { regs.a[7] += offset; + //coreSyncPC(); + return coreException(14); + } + } + coreSetSR(sr); + if (pc & 1) return coreException3i(p.op, pc); + coreSetPC(pc); return p.cyc; } else { - //BUG.say('I_RTE PRIVILEG VIOLATION'); - regs.pc = fault.pc; - return exception(8); + //SAEF_log("I_RTE PRIVILEG VIOLATION"); + //coreClrPC(); + return coreException(8); } } function I_STOP(p) { if (regs.s) { - var sea = exEA(p.s, p.z); - var sr = ldEA(sea, p.z); - setSR(sr); - - regs.stopped = true; - if ((AMIGA.spcflags & SPCFLAG_DOTRACE) == 0) - set_special(SPCFLAG_STOP); - - //BUG.say(sprintf('I_STOP() new sr $%04x', regs.sr)); + var sr = coreNext16(); + coreSetSR(sr); + coreStop(); + //SAEF_log("I_STOP new sr $%04x", sr); + coreSyncPC(); return p.cyc; } else { - regs.pc = fault.pc; - return exception(8); + //coreClrPC(); + return coreException(8); } } function I_TRAP(p) { - var dea = exEA(p.d, p.z); - var vec = ldEA(dea, p.z); - //BUG.say(sprintf('I_TRAP exception 32 + %d', vec)); - return exception(32 + vec); + //SAEF_log(("I_TRAP coreException 32 + %d", p.v)); //ccna + //coreSyncPC(); + return coreException(32 + p.v); + } + + function I_TRAPCC(p) { /* 68020 */ + if (ccTab[p.cc]()) { + //SAEF_log(("I_TRAP%s coreException 7 -> take", ccNames(p.cc))); + stackPut32(coreGetPC()); + //coreSyncPC(); + return coreException(7); + } //else SAEF_log(("I_TRAP%s coreException 7 -> abort", ccNames(p.cc))); + //ccna + coreSyncPC(); + return p.cyc; + } + function I_TRAPCC_16(p) { /* 68020 */ + var entry = coreNext16(); + if (ccTab[p.cc]()) { + //SAEF_log(("I_TRAP%s.W coreException 7 -> take", ccNames(p.cc))); + stackPut32(coreGetPC()); + //coreSyncPC(); + return coreException(7); + } //else SAEF_log(("I_TRAP%s.W coreException 7 -> abort", ccNames(p.cc))); + //ccna + coreSyncPC(); + return p.cyc; + } + function I_TRAPCC_32(p) { /* 68020 */ + var entry = coreNext32(); + if (ccTab[p.cc]()) { + //SAEF_log(("I_TRAP%s.L coreException 7 -> take", ccNames(p.cc))); + stackPut32(coreGetPC()); + //coreSyncPC(); + return coreException(7); + } //else SAEF_log(("I_TRAP%s.L coreException 7 -> abort", ccNames(p.cc))); + //ccna + coreSyncPC(); + return p.cyc; } function I_TRAPV(p) { if (regs.v) { - BUG.say('I_TRAPV exception 7'); - return exception(7); + //SAEF_log("I_TRAPV coreException 7"); + //coreSyncPC(); + return coreException(7); } //ccna + coreSyncPC(); + return p.cyc; + } + + /*-----------------------------------------------------------------------*/ + /* Multiprocessor */ + + function I_CAS_32(p) { /* >= 68020 */ + var ext = coreNext16(); + var a = exEAtab[p.ea](4); + var c = regs.d[ext & 7]; + var d = coreGet32(a); + var r = d - c; if (r < 0) r += 0x100000000; + flgCmp(c, d, r, 0x80000000); + if (regs.z) corePut32(a, regs.d[(ext >> 6) & 7]); + else regs.d[ext & 7] = d; + //SAEF_log(("I_CAS.L %04x", ext)); + coreSyncPC(); + return p.cyc; + } + function I_CAS_16(p) { /* >= 68020 */ + var ext = coreNext16(); + var a = exEAtab[p.ea](2); + var c = regs.d[ext & 7] & 0xffff; + var d = coreGet16(a); + var r = d - c; if (r < 0) r += 0x10000; + flgCmp(c, d, r, 0x8000); + if (regs.z) corePut16(a, regs.d[(ext >> 6) & 7] & 0xffff); + else regs.d[ext & 7] = (regs.d[ext & 7] & 0xffff0000) | d; + //SAEF_log(("I_CAS.W %04x", ext)); + coreSyncPC(); + return p.cyc; + } + function I_CAS_8(p) { /* >= 68020 */ + var ext = coreNext16(); + var a = exEAtab[p.ea](1); + var c = regs.d[ext & 7] & 0xff; + var d = coreGet8(a); + var r = d - c; if (r < 0) r += 0x100; + flgCmp(c, d, r, 0x80); + if (regs.z) corePut8(a, regs.d[(ext >> 6) & 7] & 0xff); + else regs.d[ext & 7] = (regs.d[ext & 7] & 0xffffff00) | d; + //SAEF_log(("I_CAS.B %04x", ext)); + coreSyncPC(); + return p.cyc; + } + + function I_CAS2_32(p) { /* >= 68020 */ + var ext1 = coreNext16(); + var ext2 = coreNext16(); + var Rn1 = (ext1 >> 12) & 7; + var Rn2 = (ext2 >> 12) & 7; + var Du1 = (ext1 >> 6) & 7; + var Du2 = (ext2 >> 6) & 7; + var Dc1 = ext1 & 7; + var Dc2 = ext2 & 7; + var c1 = regs.d[Dc1]; + var c2 = regs.d[Dc2]; + var d1 = (ext1 & 0x8000) ? coreGet32(regs.a[Rn1]) : regs.d[Rn1]; + var d2 = (ext2 & 0x8000) ? coreGet32(regs.a[Rn2]) : regs.d[Rn2]; + var upd = false; + var r = d1 - c1; if (r < 0) r += 0x100000000; + flgCmp(c1, d1, r, 0x80000000); + if (regs.z) { + r = d2 - c2; if (r < 0) r += 0x100000000; + flgCmp(c2, d2, r, 0x80000000); + upd = regs.z; + } + if (upd) { + if (ext1 & 0x8000) corePut32(regs.a[Rn1], regs.d[Du1]); + else regs.d[Rn1] = regs.d[Du1]; + if (ext2 & 0x8000) corePut32(regs.a[Rn2], regs.d[Du2]); + else regs.d[Rn2] = regs.d[Du2]; + } else { + regs.d[Dc1] = d1; + regs.d[Dc2] = d2; + } + //SAEF_log(("I_CAS2.L %04x %04x", ext1, ext2)); + coreSyncPC(); + return p.cyc; + } + function I_CAS2_16(p) { /* >= 68020 */ + var ext1 = coreNext16(); + var ext2 = coreNext16(); + var Rn1 = (ext1 >> 12) & 7; + var Rn2 = (ext2 >> 12) & 7; + var Du1 = (ext1 >> 6) & 7; + var Du2 = (ext2 >> 6) & 7; + var Dc1 = ext1 & 7; + var Dc2 = ext2 & 7; + var c1 = regs.d[Dc1] & 0xffff; + var c2 = regs.d[Dc2] & 0xffff; + var d1 = (ext1 & 0x8000) ? coreGet16(regs.a[Rn1]) : regs.d[Rn1] & 0xffff; + var d2 = (ext2 & 0x8000) ? coreGet16(regs.a[Rn2]) : regs.d[Rn2] & 0xffff; + var upd = false; + var r = d1 - c1; if (r < 0) r += 0x10000; + flgCmp(c1, d1, r, 0x8000); + if (regs.z) { + r = d2 - c2; if (r < 0) r += 0x10000; + flgCmp(c2, d2, r, 0x8000); + upd = regs.z; + } + if (upd) { + if (ext1 & 0x8000) corePut16(regs.a[Rn1], regs.d[Du1] & 0xffff); + else regs.d[Rn1] = (regs.d[Rn1] & 0xffff0000) | (regs.d[Du1] & 0xffff); + if (ext2 & 0x8000) corePut16(regs.a[Rn2], regs.d[Du2] & 0xffff); + else regs.d[Rn2] = (regs.d[Rn2] & 0xffff0000) | (regs.d[Du2] & 0xffff); + } else { + regs.d[Dc1] = (regs.d[Dc1] & 0xffff0000) | d1; + regs.d[Dc2] = (regs.d[Dc2] & 0xffff0000) | d2; + } + //SAEF_log(("I_CAS2.W %04x %04x", ext1, ext2)); + coreSyncPC(); return p.cyc; } function I_TAS(p) { - var dea = exEA(p.d, p.z); - var d = ldEA(dea, p.z); - var r = 0x80 | d; - stEA(dea, p.z, r); + var d = ldEA8tab[p.ea](); + stEA8tab[p.ea](0x80 | d); regs.n = (d & 0x80) != 0; regs.z = d == 0; regs.v = false; - regs.c = false; - BUG.say(sprintf('I_TAS.%s d $%02x r $%02x', szChr(p.z), d, r)); + regs.c = false; + //SAEF_log(("I_TAS.B $%02x", d)); + coreSyncPC(); return p.cyc; } /*-----------------------------------------------------------------------*/ + /* 68020 only */ + + function I_CALLM(p) { /* FIX not implemented */ + var ext = coreNext16() & 0xff; + SAEF_warn("I_CALLM not implemented (ext %d)", ext); + //coreSyncPC(); + return coreIllegal(p.op); + } + + function I_RTM(p) { /* FIX not implemented */ + SAEF_warn("I_RTM not implemented"); + //coreSyncPC(); + return coreIllegal(p.op); + } + /*-----------------------------------------------------------------------*/ + /* 68030 fake MMU */ + + function I_MMU(p) { + if (regs.s) { + var pc = coreGetPC(); + var ext = coreNext16(); + var a = exEAtab[p.ea](4); + + if (mmu_op30(pc, p.op, ext, a)) { + //coreSyncPC(); + return coreIllegal(p.op); + } + coreSyncPC(); + //ccna + return p.cyc; + } else { + //coreClrPC(); + return coreException(8); + } + } + /*-----------------------------------------------------------------------*/ - - function mkCyc(z, m) { - /*switch (m) { - case M_rdd: - case M_rda: return 0; - case M_ria: return z == 4 ? 8 : 4; - case M_ripo: return z == 4 ? 8 : 4; - case M_ripr: return z == 4 ? 10 : 6; - case M_rid: return z == 4 ? 12 : 8; - case M_rii: return z == 4 ? 14 : 10; - case M_pcid: return z == 4 ? 12 : 8; - case M_pcii: return z == 4 ? 14 : 10; - case M_absw: return z == 4 ? 12 : 8; - case M_absl: return z == 4 ? 16 : 12; - case M_imm: - case M_list: return z == 4 ? 8 : 4; - }*/ + /* Coprocessor 68020/68030 */ + + function I_cpBcc(p) { + //SAEF_warn("I_cpBcc.%s not implemented, cid %d, ccc %d, pc %08x", szChr(p.z), p.cid, p.ccc, regs.instruction_pc); + return coreIllegal(p.op); + //ccna + //return p.cyc; + } + function I_cpDBcc(p) { + //SAEF_warn("I_cpDBcc.w not implemented, cid %d, dn %d, pc %08x", p.cid, p.dn, regs.instruction_pc); + return coreIllegal(p.op); + //ccna + //return p.cyc; + } + function I_cpGEN(p) { + //SAEF_warn("I_cpGEN not implemented, cid %d, ea %d(%d:%d), pc %08x", p.cid, p.ea,p.ea>>3,p.ea&7, regs.instruction_pc); + return coreIllegal(p.op); + //var cmd = coreNext16(); + //ccna + //return p.cyc; + } + function I_cpRESTORE(p) { + //SAEF_warn("I_cpRESTORE not implemented, cid %d, pc %08x", p.cid, regs.instruction_pc); + return coreIllegal(p.op); + if (regs.s) { + //var data = ldEA32tab[p.ea](); + //ccna + //return p.cyc; + } else { + //coreClrPC(); + return coreException(8); + } + } + function I_cpSAVE(p) { + //SAEF_warn("I_cpSAVE not implemented, cid %d, pc %08x", p.cid, regs.instruction_pc); + return coreIllegal(p.op); + if (regs.s) { + //var data = 12345; + //stEA32tab[p.ea](data); + //ccna + //return p.cyc; + } else { + //coreClrPC(); + return coreException(8); + } + } + function I_cpScc(p) { + //SAEF_warn("I_cpScc not implemented, cid %d, pc %08x", p.cid, regs.instruction_pc); + return coreIllegal(p.op); + //var data = ldEA32tab[p.ea](); + //ccna + //return p.cyc; + } + function I_cpTRAPcc(p) { + //SAEF_warn("I_cpTRAPcc not implemented, cid %d, opm %d, pc %08x", p.cid, p.opm, regs.instruction_pc); + return coreIllegal(p.op); + //var ext coreNext16(); + //var ext2 = p.opm == 2 ? coreNext16() : (p.opm == 3 ? coreNext32() : 0); + //ccna + //return p.cyc; + } + /*function I_cpXXX(p) { + //var cmd = coreNext16(); + SAEF_warn("I_cpXXX not implemented, cid %d, xxx %x, pc %08x", p.cid, p.xxx, regs.instruction_pc); + //ccna + //return p.cyc; + return coreIllegal(p.op); + }*/ + + /*-----------------------------------------------------------------------*/ + /* real illegal/undefined instruction */ + + function ILLEGAL(op) { + /*if (typeof SAER != "undefined") { + SAEF_warn("ILLEGAL op $%04x", op); + SAER.cpu.diss(regs.instruction_pc,0); + }*/ + //coreSyncPC(); + return coreIllegal(op); + } + + /*-----------------------------------------------------------------------*/ + /* SECT core tables */ + /*-----------------------------------------------------------------------*/ + /* Condition-code table */ + + function mkCCTab() { + var i = 0; + + ccTab = new Array(16); + ccTab[i++] = function() { return true; }; //T + ccTab[i++] = function() { return false; }; //F + ccTab[i++] = function() { return !regs.c && !regs.z; }; //HI + ccTab[i++] = function() { return regs.c || regs.z; }; //LS + ccTab[i++] = function() { return !regs.c; }; //CC + ccTab[i++] = function() { return regs.c; }; //CS + ccTab[i++] = function() { return !regs.z; }; //NE + ccTab[i++] = function() { return regs.z; }; //EQ + ccTab[i++] = function() { return !regs.v; }; //VC + ccTab[i++] = function() { return regs.v; }; //VV + ccTab[i++] = function() { return !regs.n; }; //PL + ccTab[i++] = function() { return regs.n; }; //MI + ccTab[i++] = function() { return regs.n == regs.v; }; //GE + ccTab[i++] = function() { return regs.n != regs.v; }; //LT + ccTab[i++] = function() { return !regs.z && (regs.n == regs.v); }; //GT + ccTab[i ] = function() { return regs.z || (regs.n != regs.v); }; //LE + } + + /*-----------------------------------------------------------------------*/ + /* Effective-Address tables */ + + function exII(base, dp) { + var reg = (dp >> 12) & 7; + //var cycles = 0; + var v; + var regd = (dp & 0x8000) ? regs.a[reg] : regs.d[reg]; + var scale = (dp >> 9) & 3; + + if ((dp & 0x800) == 0) + //regd = (uae_s32)(uae_s16)regd; + regd = extWord(regd & 0xffff); + + //regd <<= (dp >> 9) & 3; + if (scale) regd = ((regd << scale) & 0xffffffff) >>> 0; + + if (dp & 0x100) { + var outer = 0; + + if (dp & 0x80) base = 0; + if (dp & 0x40) regd = 0; + + if ((dp & 0x30) == 0x20) { + //base += (uae_s32)(uae_s16)coreNext16(); + base = add32(base, extWord(coreNext16())); + //cycles++; + } + if ((dp & 0x30) == 0x30) { + //base += coreNext32(); + base = add32(base, coreNext32()); + //cycles++; + } + + if ((dp & 0x3) == 0x2) { + //outer = (uae_s32)(uae_s16)coreNext16(); + outer = extWord(coreNext16()); + //cycles++; + } + if ((dp & 0x3) == 0x3) { + //outer = coreNext32(); + outer = coreNext32(); + //cycles++; + } + + if ((dp & 0x4) == 0) { + //base += regd; + base = add32(base, regd); + //cycles++; + } + if (dp & 0x3) { + base = coreGet32(base); + //cycles++; + } + if (dp & 0x4) { + //base += regd; + base = add32(base, regd); + //cycles++; + } + //v = base + outer; + v = add32(base, outer); + } else { + //v = base + (uae_s32)((uae_s8)dp) + regd; + v = add32(add32(base, extByte(dp & 0xff)), regd); + } + return v; + } + + function mkEATabs() { + exEAtab = new Array(64); + exEAtab[(2<<3)|0] = function() { return regs.a[0]; } //ria + exEAtab[(2<<3)|1] = function() { return regs.a[1]; } + exEAtab[(2<<3)|2] = function() { return regs.a[2]; } + exEAtab[(2<<3)|3] = function() { return regs.a[3]; } + exEAtab[(2<<3)|4] = function() { return regs.a[4]; } + exEAtab[(2<<3)|5] = function() { return regs.a[5]; } + exEAtab[(2<<3)|6] = function() { return regs.a[6]; } + exEAtab[(2<<3)|7] = function() { return regs.a[7]; } + exEAtab[(3<<3)|0] = function(z) { var a = regs.a[0]; regs.a[0] += aIncDec[z][0]; return a; }; //ripo + exEAtab[(3<<3)|1] = function(z) { var a = regs.a[1]; regs.a[1] += aIncDec[z][1]; return a; }; + exEAtab[(3<<3)|2] = function(z) { var a = regs.a[2]; regs.a[2] += aIncDec[z][2]; return a; }; + exEAtab[(3<<3)|3] = function(z) { var a = regs.a[3]; regs.a[3] += aIncDec[z][3]; return a; }; + exEAtab[(3<<3)|4] = function(z) { var a = regs.a[4]; regs.a[4] += aIncDec[z][4]; return a; }; + exEAtab[(3<<3)|5] = function(z) { var a = regs.a[5]; regs.a[5] += aIncDec[z][5]; return a; }; + exEAtab[(3<<3)|6] = function(z) { var a = regs.a[6]; regs.a[6] += aIncDec[z][6]; return a; }; + exEAtab[(3<<3)|7] = function(z) { var a = regs.a[7]; regs.a[7] += aIncDec[z][7]; return a; }; + exEAtab[(4<<3)|0] = function(z) { regs.a[0] -= aIncDec[z][0]; return regs.a[0]; } //ripr + exEAtab[(4<<3)|1] = function(z) { regs.a[1] -= aIncDec[z][1]; return regs.a[1]; } + exEAtab[(4<<3)|2] = function(z) { regs.a[2] -= aIncDec[z][2]; return regs.a[2]; } + exEAtab[(4<<3)|3] = function(z) { regs.a[3] -= aIncDec[z][3]; return regs.a[3]; } + exEAtab[(4<<3)|4] = function(z) { regs.a[4] -= aIncDec[z][4]; return regs.a[4]; } + exEAtab[(4<<3)|5] = function(z) { regs.a[5] -= aIncDec[z][5]; return regs.a[5]; } + exEAtab[(4<<3)|6] = function(z) { regs.a[6] -= aIncDec[z][6]; return regs.a[6]; } + exEAtab[(4<<3)|7] = function(z) { regs.a[7] -= aIncDec[z][7]; return regs.a[7]; } + exEAtab[(5<<3)|0] = function() { return add32(regs.a[0], extWord(coreNext16())); } //rid + exEAtab[(5<<3)|1] = function() { return add32(regs.a[1], extWord(coreNext16())); } + exEAtab[(5<<3)|2] = function() { return add32(regs.a[2], extWord(coreNext16())); } + exEAtab[(5<<3)|3] = function() { return add32(regs.a[3], extWord(coreNext16())); } + exEAtab[(5<<3)|4] = function() { return add32(regs.a[4], extWord(coreNext16())); } + exEAtab[(5<<3)|5] = function() { return add32(regs.a[5], extWord(coreNext16())); } + exEAtab[(5<<3)|6] = function() { return add32(regs.a[6], extWord(coreNext16())); } + exEAtab[(5<<3)|7] = function() { return add32(regs.a[7], extWord(coreNext16())); } + exEAtab[(6<<3)|0] = function() { return exII(regs.a[0], coreNext16()); } //rii + exEAtab[(6<<3)|1] = function() { return exII(regs.a[1], coreNext16()); } + exEAtab[(6<<3)|2] = function() { return exII(regs.a[2], coreNext16()); } + exEAtab[(6<<3)|3] = function() { return exII(regs.a[3], coreNext16()); } + exEAtab[(6<<3)|4] = function() { return exII(regs.a[4], coreNext16()); } + exEAtab[(6<<3)|5] = function() { return exII(regs.a[5], coreNext16()); } + exEAtab[(6<<3)|6] = function() { return exII(regs.a[6], coreNext16()); } + exEAtab[(6<<3)|7] = function() { return exII(regs.a[7], coreNext16()); } + exEAtab[(7<<3)|0] = function() { return extWord(coreNext16()); } //absw + exEAtab[(7<<3)|1] = function() { return coreNext32(); } //absl + exEAtab[(7<<3)|2] = function() { return add32(coreGetPC(), extWord(coreNext16())); } //pcid + exEAtab[(7<<3)|3] = function() { return exII(coreGetPC(), coreNext16()); } //pcii + exEAtab[(7<<3)|4] = function() { SAEF_error("cpu.exEAtab() invalid EA 60 (7|4) (imm)"); } //imm + + /*-----------------------------------------------------------------------*/ + + ldEA8tab = new Array(64); + ldEA8tab[ 0] = function() { return regs.d[0] & 0xff; } //rdd + ldEA8tab[ 1] = function() { return regs.d[1] & 0xff; } + ldEA8tab[ 2] = function() { return regs.d[2] & 0xff; } + ldEA8tab[ 3] = function() { return regs.d[3] & 0xff; } + ldEA8tab[ 4] = function() { return regs.d[4] & 0xff; } + ldEA8tab[ 5] = function() { return regs.d[5] & 0xff; } + ldEA8tab[ 6] = function() { return regs.d[6] & 0xff; } + ldEA8tab[ 7] = function() { return regs.d[7] & 0xff; } + ldEA8tab[(1<<3)|0] = function() { SAEF_error("cpu.ldEA8tab() invalid EA 8 (1|0)"); } //rda + ldEA8tab[(1<<3)|1] = function() { SAEF_error("cpu.ldEA8tab() invalid EA 9 (1|1)"); } + ldEA8tab[(1<<3)|2] = function() { SAEF_error("cpu.ldEA8tab() invalid EA 10 (1|2)"); } + ldEA8tab[(1<<3)|3] = function() { SAEF_error("cpu.ldEA8tab() invalid EA 11 (1|3)"); } + ldEA8tab[(1<<3)|4] = function() { SAEF_error("cpu.ldEA8tab() invalid EA 12 (1|4)"); } + ldEA8tab[(1<<3)|5] = function() { SAEF_error("cpu.ldEA8tab() invalid EA 13 (1|5)"); } + ldEA8tab[(1<<3)|6] = function() { SAEF_error("cpu.ldEA8tab() invalid EA 14 (1|6)"); } + ldEA8tab[(1<<3)|7] = function() { SAEF_error("cpu.ldEA8tab() invalid EA 15 (1|7)"); } + ldEA8tab[(2<<3)|0] = function() { return coreGet8(regs.a[0]); } //ria + ldEA8tab[(2<<3)|1] = function() { return coreGet8(regs.a[1]); } + ldEA8tab[(2<<3)|2] = function() { return coreGet8(regs.a[2]); } + ldEA8tab[(2<<3)|3] = function() { return coreGet8(regs.a[3]); } + ldEA8tab[(2<<3)|4] = function() { return coreGet8(regs.a[4]); } + ldEA8tab[(2<<3)|5] = function() { return coreGet8(regs.a[5]); } + ldEA8tab[(2<<3)|6] = function() { return coreGet8(regs.a[6]); } + ldEA8tab[(2<<3)|7] = function() { return coreGet8(regs.a[7]); } + ldEA8tab[(3<<3)|0] = function() { var a = regs.a[0]; regs.a[0] += 1; return coreGet8(a); } //ripo + ldEA8tab[(3<<3)|1] = function() { var a = regs.a[1]; regs.a[1] += 1; return coreGet8(a); } + ldEA8tab[(3<<3)|2] = function() { var a = regs.a[2]; regs.a[2] += 1; return coreGet8(a); } + ldEA8tab[(3<<3)|3] = function() { var a = regs.a[3]; regs.a[3] += 1; return coreGet8(a); } + ldEA8tab[(3<<3)|4] = function() { var a = regs.a[4]; regs.a[4] += 1; return coreGet8(a); } + ldEA8tab[(3<<3)|5] = function() { var a = regs.a[5]; regs.a[5] += 1; return coreGet8(a); } + ldEA8tab[(3<<3)|6] = function() { var a = regs.a[6]; regs.a[6] += 1; return coreGet8(a); } + ldEA8tab[(3<<3)|7] = function() { var a = regs.a[7]; regs.a[7] += 2; return coreGet8(a); } + ldEA8tab[(4<<3)|0] = function() { regs.a[0] -= 1; return coreGet8(regs.a[0]); } //ripr + ldEA8tab[(4<<3)|1] = function() { regs.a[1] -= 1; return coreGet8(regs.a[1]); } + ldEA8tab[(4<<3)|2] = function() { regs.a[2] -= 1; return coreGet8(regs.a[2]); } + ldEA8tab[(4<<3)|3] = function() { regs.a[3] -= 1; return coreGet8(regs.a[3]); } + ldEA8tab[(4<<3)|4] = function() { regs.a[4] -= 1; return coreGet8(regs.a[4]); } + ldEA8tab[(4<<3)|5] = function() { regs.a[5] -= 1; return coreGet8(regs.a[5]); } + ldEA8tab[(4<<3)|6] = function() { regs.a[6] -= 1; return coreGet8(regs.a[6]); } + ldEA8tab[(4<<3)|7] = function() { regs.a[7] -= 2; return coreGet8(regs.a[7]); } + ldEA8tab[(5<<3)|0] = function() { return coreGet8(add32(regs.a[0], extWord(coreNext16()))); } //rid + ldEA8tab[(5<<3)|1] = function() { return coreGet8(add32(regs.a[1], extWord(coreNext16()))); } + ldEA8tab[(5<<3)|2] = function() { return coreGet8(add32(regs.a[2], extWord(coreNext16()))); } + ldEA8tab[(5<<3)|3] = function() { return coreGet8(add32(regs.a[3], extWord(coreNext16()))); } + ldEA8tab[(5<<3)|4] = function() { return coreGet8(add32(regs.a[4], extWord(coreNext16()))); } + ldEA8tab[(5<<3)|5] = function() { return coreGet8(add32(regs.a[5], extWord(coreNext16()))); } + ldEA8tab[(5<<3)|6] = function() { return coreGet8(add32(regs.a[6], extWord(coreNext16()))); } + ldEA8tab[(5<<3)|7] = function() { return coreGet8(add32(regs.a[7], extWord(coreNext16()))); } + ldEA8tab[(6<<3)|0] = function() { return coreGet8(exII(regs.a[0], coreNext16())); } //rii + ldEA8tab[(6<<3)|1] = function() { return coreGet8(exII(regs.a[1], coreNext16())); } + ldEA8tab[(6<<3)|2] = function() { return coreGet8(exII(regs.a[2], coreNext16())); } + ldEA8tab[(6<<3)|3] = function() { return coreGet8(exII(regs.a[3], coreNext16())); } + ldEA8tab[(6<<3)|4] = function() { return coreGet8(exII(regs.a[4], coreNext16())); } + ldEA8tab[(6<<3)|5] = function() { return coreGet8(exII(regs.a[5], coreNext16())); } + ldEA8tab[(6<<3)|6] = function() { return coreGet8(exII(regs.a[6], coreNext16())); } + ldEA8tab[(6<<3)|7] = function() { return coreGet8(exII(regs.a[7], coreNext16())); } + ldEA8tab[(7<<3)|0] = function() { return coreGet8(extWord(coreNext16())); } //absw + ldEA8tab[(7<<3)|1] = function() { return coreGet8(coreNext32()); } //absl + ldEA8tab[(7<<3)|2] = function() { return coreGet8(add32(coreGetPC(), extWord(coreNext16()))); } //pcid + ldEA8tab[(7<<3)|3] = function() { return coreGet8(exII(coreGetPC(), coreNext16())); } //pcii + ldEA8tab[(7<<3)|4] = function() { return coreNext16() & 0xff; } //imm + + ldEA16tab = new Array(64); + ldEA16tab[ 0] = function() { return regs.d[0] & 0xffff; } //rdd + ldEA16tab[ 1] = function() { return regs.d[1] & 0xffff; } + ldEA16tab[ 2] = function() { return regs.d[2] & 0xffff; } + ldEA16tab[ 3] = function() { return regs.d[3] & 0xffff; } + ldEA16tab[ 4] = function() { return regs.d[4] & 0xffff; } + ldEA16tab[ 5] = function() { return regs.d[5] & 0xffff; } + ldEA16tab[ 6] = function() { return regs.d[6] & 0xffff; } + ldEA16tab[ 7] = function() { return regs.d[7] & 0xffff; } + ldEA16tab[(1<<3)|0] = function() { return regs.a[0] & 0xffff; } //rda + ldEA16tab[(1<<3)|1] = function() { return regs.a[1] & 0xffff; } + ldEA16tab[(1<<3)|2] = function() { return regs.a[2] & 0xffff; } + ldEA16tab[(1<<3)|3] = function() { return regs.a[3] & 0xffff; } + ldEA16tab[(1<<3)|4] = function() { return regs.a[4] & 0xffff; } + ldEA16tab[(1<<3)|5] = function() { return regs.a[5] & 0xffff; } + ldEA16tab[(1<<3)|6] = function() { return regs.a[6] & 0xffff; } + ldEA16tab[(1<<3)|7] = function() { return regs.a[7] & 0xffff; } + ldEA16tab[(2<<3)|0] = function() { return coreGet16(regs.a[0]); } //ria + ldEA16tab[(2<<3)|1] = function() { return coreGet16(regs.a[1]); } + ldEA16tab[(2<<3)|2] = function() { return coreGet16(regs.a[2]); } + ldEA16tab[(2<<3)|3] = function() { return coreGet16(regs.a[3]); } + ldEA16tab[(2<<3)|4] = function() { return coreGet16(regs.a[4]); } + ldEA16tab[(2<<3)|5] = function() { return coreGet16(regs.a[5]); } + ldEA16tab[(2<<3)|6] = function() { return coreGet16(regs.a[6]); } + ldEA16tab[(2<<3)|7] = function() { return coreGet16(regs.a[7]); } + ldEA16tab[(3<<3)|0] = function() { var a = regs.a[0]; regs.a[0] += 2; return coreGet16(a); } //ripo + ldEA16tab[(3<<3)|1] = function() { var a = regs.a[1]; regs.a[1] += 2; return coreGet16(a); } + ldEA16tab[(3<<3)|2] = function() { var a = regs.a[2]; regs.a[2] += 2; return coreGet16(a); } + ldEA16tab[(3<<3)|3] = function() { var a = regs.a[3]; regs.a[3] += 2; return coreGet16(a); } + ldEA16tab[(3<<3)|4] = function() { var a = regs.a[4]; regs.a[4] += 2; return coreGet16(a); } + ldEA16tab[(3<<3)|5] = function() { var a = regs.a[5]; regs.a[5] += 2; return coreGet16(a); } + ldEA16tab[(3<<3)|6] = function() { var a = regs.a[6]; regs.a[6] += 2; return coreGet16(a); } + ldEA16tab[(3<<3)|7] = function() { var a = regs.a[7]; regs.a[7] += 2; return coreGet16(a); } + ldEA16tab[(4<<3)|0] = function() { regs.a[0] -= 2; return coreGet16(regs.a[0]); } //ripr + ldEA16tab[(4<<3)|1] = function() { regs.a[1] -= 2; return coreGet16(regs.a[1]); } + ldEA16tab[(4<<3)|2] = function() { regs.a[2] -= 2; return coreGet16(regs.a[2]); } + ldEA16tab[(4<<3)|3] = function() { regs.a[3] -= 2; return coreGet16(regs.a[3]); } + ldEA16tab[(4<<3)|4] = function() { regs.a[4] -= 2; return coreGet16(regs.a[4]); } + ldEA16tab[(4<<3)|5] = function() { regs.a[5] -= 2; return coreGet16(regs.a[5]); } + ldEA16tab[(4<<3)|6] = function() { regs.a[6] -= 2; return coreGet16(regs.a[6]); } + ldEA16tab[(4<<3)|7] = function() { regs.a[7] -= 2; return coreGet16(regs.a[7]); } + ldEA16tab[(5<<3)|0] = function() { return coreGet16(add32(regs.a[0], extWord(coreNext16()))); } //rid + ldEA16tab[(5<<3)|1] = function() { return coreGet16(add32(regs.a[1], extWord(coreNext16()))); } + ldEA16tab[(5<<3)|2] = function() { return coreGet16(add32(regs.a[2], extWord(coreNext16()))); } + ldEA16tab[(5<<3)|3] = function() { return coreGet16(add32(regs.a[3], extWord(coreNext16()))); } + ldEA16tab[(5<<3)|4] = function() { return coreGet16(add32(regs.a[4], extWord(coreNext16()))); } + ldEA16tab[(5<<3)|5] = function() { return coreGet16(add32(regs.a[5], extWord(coreNext16()))); } + ldEA16tab[(5<<3)|6] = function() { return coreGet16(add32(regs.a[6], extWord(coreNext16()))); } + ldEA16tab[(5<<3)|7] = function() { return coreGet16(add32(regs.a[7], extWord(coreNext16()))); } + ldEA16tab[(6<<3)|0] = function() { return coreGet16(exII(regs.a[0], coreNext16())); } //rii + ldEA16tab[(6<<3)|1] = function() { return coreGet16(exII(regs.a[1], coreNext16())); } + ldEA16tab[(6<<3)|2] = function() { return coreGet16(exII(regs.a[2], coreNext16())); } + ldEA16tab[(6<<3)|3] = function() { return coreGet16(exII(regs.a[3], coreNext16())); } + ldEA16tab[(6<<3)|4] = function() { return coreGet16(exII(regs.a[4], coreNext16())); } + ldEA16tab[(6<<3)|5] = function() { return coreGet16(exII(regs.a[5], coreNext16())); } + ldEA16tab[(6<<3)|6] = function() { return coreGet16(exII(regs.a[6], coreNext16())); } + ldEA16tab[(6<<3)|7] = function() { return coreGet16(exII(regs.a[7], coreNext16())); } + ldEA16tab[(7<<3)|0] = function() { return coreGet16(extWord(coreNext16())); } //absw + ldEA16tab[(7<<3)|1] = function() { return coreGet16(coreNext32()); } //absl + ldEA16tab[(7<<3)|2] = function() { return coreGet16(add32(coreGetPC(), extWord(coreNext16()))); } //pcid + ldEA16tab[(7<<3)|3] = function() { return coreGet16(exII(coreGetPC(), coreNext16())); } //pcii + ldEA16tab[(7<<3)|4] = function() { return coreNext16(); } //imm + + ldEA32tab = new Array(64); + ldEA32tab[ 0] = function() { return regs.d[0]; } //rdd + ldEA32tab[ 1] = function() { return regs.d[1]; } + ldEA32tab[ 2] = function() { return regs.d[2]; } + ldEA32tab[ 3] = function() { return regs.d[3]; } + ldEA32tab[ 4] = function() { return regs.d[4]; } + ldEA32tab[ 5] = function() { return regs.d[5]; } + ldEA32tab[ 6] = function() { return regs.d[6]; } + ldEA32tab[ 7] = function() { return regs.d[7]; } + ldEA32tab[(1<<3)|0] = function() { return regs.a[0]; } //rda + ldEA32tab[(1<<3)|1] = function() { return regs.a[1]; } + ldEA32tab[(1<<3)|2] = function() { return regs.a[2]; } + ldEA32tab[(1<<3)|3] = function() { return regs.a[3]; } + ldEA32tab[(1<<3)|4] = function() { return regs.a[4]; } + ldEA32tab[(1<<3)|5] = function() { return regs.a[5]; } + ldEA32tab[(1<<3)|6] = function() { return regs.a[6]; } + ldEA32tab[(1<<3)|7] = function() { return regs.a[7]; } + ldEA32tab[(2<<3)|0] = function() { return coreGet32(regs.a[0]); } //ria + ldEA32tab[(2<<3)|1] = function() { return coreGet32(regs.a[1]); } + ldEA32tab[(2<<3)|2] = function() { return coreGet32(regs.a[2]); } + ldEA32tab[(2<<3)|3] = function() { return coreGet32(regs.a[3]); } + ldEA32tab[(2<<3)|4] = function() { return coreGet32(regs.a[4]); } + ldEA32tab[(2<<3)|5] = function() { return coreGet32(regs.a[5]); } + ldEA32tab[(2<<3)|6] = function() { return coreGet32(regs.a[6]); } + ldEA32tab[(2<<3)|7] = function() { return coreGet32(regs.a[7]); } + ldEA32tab[(3<<3)|0] = function() { var a = regs.a[0]; regs.a[0] += 4; return coreGet32(a); } //ripo + ldEA32tab[(3<<3)|1] = function() { var a = regs.a[1]; regs.a[1] += 4; return coreGet32(a); } + ldEA32tab[(3<<3)|2] = function() { var a = regs.a[2]; regs.a[2] += 4; return coreGet32(a); } + ldEA32tab[(3<<3)|3] = function() { var a = regs.a[3]; regs.a[3] += 4; return coreGet32(a); } + ldEA32tab[(3<<3)|4] = function() { var a = regs.a[4]; regs.a[4] += 4; return coreGet32(a); } + ldEA32tab[(3<<3)|5] = function() { var a = regs.a[5]; regs.a[5] += 4; return coreGet32(a); } + ldEA32tab[(3<<3)|6] = function() { var a = regs.a[6]; regs.a[6] += 4; return coreGet32(a); } + ldEA32tab[(3<<3)|7] = function() { var a = regs.a[7]; regs.a[7] += 4; return coreGet32(a); } + ldEA32tab[(4<<3)|0] = function() { regs.a[0] -= 4; return coreGet32(regs.a[0]); } //ripr + ldEA32tab[(4<<3)|1] = function() { regs.a[1] -= 4; return coreGet32(regs.a[1]); } + ldEA32tab[(4<<3)|2] = function() { regs.a[2] -= 4; return coreGet32(regs.a[2]); } + ldEA32tab[(4<<3)|3] = function() { regs.a[3] -= 4; return coreGet32(regs.a[3]); } + ldEA32tab[(4<<3)|4] = function() { regs.a[4] -= 4; return coreGet32(regs.a[4]); } + ldEA32tab[(4<<3)|5] = function() { regs.a[5] -= 4; return coreGet32(regs.a[5]); } + ldEA32tab[(4<<3)|6] = function() { regs.a[6] -= 4; return coreGet32(regs.a[6]); } + ldEA32tab[(4<<3)|7] = function() { regs.a[7] -= 4; return coreGet32(regs.a[7]); } + ldEA32tab[(5<<3)|0] = function() { return coreGet32(add32(regs.a[0], extWord(coreNext16()))); } //rid + ldEA32tab[(5<<3)|1] = function() { return coreGet32(add32(regs.a[1], extWord(coreNext16()))); } + ldEA32tab[(5<<3)|2] = function() { return coreGet32(add32(regs.a[2], extWord(coreNext16()))); } + ldEA32tab[(5<<3)|3] = function() { return coreGet32(add32(regs.a[3], extWord(coreNext16()))); } + ldEA32tab[(5<<3)|4] = function() { return coreGet32(add32(regs.a[4], extWord(coreNext16()))); } + ldEA32tab[(5<<3)|5] = function() { return coreGet32(add32(regs.a[5], extWord(coreNext16()))); } + ldEA32tab[(5<<3)|6] = function() { return coreGet32(add32(regs.a[6], extWord(coreNext16()))); } + ldEA32tab[(5<<3)|7] = function() { return coreGet32(add32(regs.a[7], extWord(coreNext16()))); } + ldEA32tab[(6<<3)|0] = function() { return coreGet32(exII(regs.a[0], coreNext16())); } //rii0 + ldEA32tab[(6<<3)|1] = function() { return coreGet32(exII(regs.a[1], coreNext16())); } + ldEA32tab[(6<<3)|2] = function() { return coreGet32(exII(regs.a[2], coreNext16())); } + ldEA32tab[(6<<3)|3] = function() { return coreGet32(exII(regs.a[3], coreNext16())); } + ldEA32tab[(6<<3)|4] = function() { return coreGet32(exII(regs.a[4], coreNext16())); } + ldEA32tab[(6<<3)|5] = function() { return coreGet32(exII(regs.a[5], coreNext16())); } + ldEA32tab[(6<<3)|6] = function() { return coreGet32(exII(regs.a[6], coreNext16())); } + ldEA32tab[(6<<3)|7] = function() { return coreGet32(exII(regs.a[7], coreNext16())); } + ldEA32tab[(7<<3)|0] = function() { return coreGet32(extWord(coreNext16())); } //absw + ldEA32tab[(7<<3)|1] = function() { return coreGet32(coreNext32()); } //absl + ldEA32tab[(7<<3)|2] = function() { return coreGet32(add32(coreGetPC(), extWord(coreNext16()))); } //pcid + ldEA32tab[(7<<3)|3] = function() { return coreGet32(exII(coreGetPC(), coreNext16())); } //pcii + ldEA32tab[(7<<3)|4] = function() { return coreNext32(); } //imm + + stEA8tab = new Array(64); + stEA8tab[ 0] = function(v) { regs.d[0] = (regs.d[0] & 0xffffff00) | v; } //rdd + stEA8tab[ 1] = function(v) { regs.d[1] = (regs.d[1] & 0xffffff00) | v; } + stEA8tab[ 2] = function(v) { regs.d[2] = (regs.d[2] & 0xffffff00) | v; } + stEA8tab[ 3] = function(v) { regs.d[3] = (regs.d[3] & 0xffffff00) | v; } + stEA8tab[ 4] = function(v) { regs.d[4] = (regs.d[4] & 0xffffff00) | v; } + stEA8tab[ 5] = function(v) { regs.d[5] = (regs.d[5] & 0xffffff00) | v; } + stEA8tab[ 6] = function(v) { regs.d[6] = (regs.d[6] & 0xffffff00) | v; } + stEA8tab[ 7] = function(v) { regs.d[7] = (regs.d[7] & 0xffffff00) | v; } + stEA8tab[(1<<3)|0] = function(v) { SAEF_error("cpu.stEA8tab() invalid EA 8 (1|0)"); } //rda + stEA8tab[(1<<3)|1] = function(v) { SAEF_error("cpu.stEA8tab() invalid EA 9 (1|1)"); } + stEA8tab[(1<<3)|2] = function(v) { SAEF_error("cpu.stEA8tab() invalid EA 10 (1|2)"); } + stEA8tab[(1<<3)|3] = function(v) { SAEF_error("cpu.stEA8tab() invalid EA 11 (1|3)"); } + stEA8tab[(1<<3)|4] = function(v) { SAEF_error("cpu.stEA8tab() invalid EA 12 (1|4)"); } + stEA8tab[(1<<3)|5] = function(v) { SAEF_error("cpu.stEA8tab() invalid EA 13 (1|5)"); } + stEA8tab[(1<<3)|6] = function(v) { SAEF_error("cpu.stEA8tab() invalid EA 14 (1|6)"); } + stEA8tab[(1<<3)|7] = function(v) { SAEF_error("cpu.stEA8tab() invalid EA 15 (1|7)"); } + stEA8tab[(2<<3)|0] = function(v) { corePut8(regs.a[0], v); } //ria + stEA8tab[(2<<3)|1] = function(v) { corePut8(regs.a[1], v); } + stEA8tab[(2<<3)|2] = function(v) { corePut8(regs.a[2], v); } + stEA8tab[(2<<3)|3] = function(v) { corePut8(regs.a[3], v); } + stEA8tab[(2<<3)|4] = function(v) { corePut8(regs.a[4], v); } + stEA8tab[(2<<3)|5] = function(v) { corePut8(regs.a[5], v); } + stEA8tab[(2<<3)|6] = function(v) { corePut8(regs.a[6], v); } + stEA8tab[(2<<3)|7] = function(v) { corePut8(regs.a[7], v); } + stEA8tab[(3<<3)|0] = function(v) { corePut8(regs.a[0], v); regs.a[0] += 1; } //ripo + stEA8tab[(3<<3)|1] = function(v) { corePut8(regs.a[1], v); regs.a[1] += 1; } + stEA8tab[(3<<3)|2] = function(v) { corePut8(regs.a[2], v); regs.a[2] += 1; } + stEA8tab[(3<<3)|3] = function(v) { corePut8(regs.a[3], v); regs.a[3] += 1; } + stEA8tab[(3<<3)|4] = function(v) { corePut8(regs.a[4], v); regs.a[4] += 1; } + stEA8tab[(3<<3)|5] = function(v) { corePut8(regs.a[5], v); regs.a[5] += 1; } + stEA8tab[(3<<3)|6] = function(v) { corePut8(regs.a[6], v); regs.a[6] += 1; } + stEA8tab[(3<<3)|7] = function(v) { corePut8(regs.a[7], v); regs.a[7] += 2; } + stEA8tab[(4<<3)|0] = function(v) { regs.a[0] -= 1; corePut8(regs.a[0], v); } //ripr + stEA8tab[(4<<3)|1] = function(v) { regs.a[1] -= 1; corePut8(regs.a[1], v); } + stEA8tab[(4<<3)|2] = function(v) { regs.a[2] -= 1; corePut8(regs.a[2], v); } + stEA8tab[(4<<3)|3] = function(v) { regs.a[3] -= 1; corePut8(regs.a[3], v); } + stEA8tab[(4<<3)|4] = function(v) { regs.a[4] -= 1; corePut8(regs.a[4], v); } + stEA8tab[(4<<3)|5] = function(v) { regs.a[5] -= 1; corePut8(regs.a[5], v); } + stEA8tab[(4<<3)|6] = function(v) { regs.a[6] -= 1; corePut8(regs.a[6], v); } + stEA8tab[(4<<3)|7] = function(v) { regs.a[7] -= 2; corePut8(regs.a[7], v); } + stEA8tab[(5<<3)|0] = function(v) { corePut8(add32(regs.a[0], extWord(coreNext16())), v); } //rid + stEA8tab[(5<<3)|1] = function(v) { corePut8(add32(regs.a[1], extWord(coreNext16())), v); } + stEA8tab[(5<<3)|2] = function(v) { corePut8(add32(regs.a[2], extWord(coreNext16())), v); } + stEA8tab[(5<<3)|3] = function(v) { corePut8(add32(regs.a[3], extWord(coreNext16())), v); } + stEA8tab[(5<<3)|4] = function(v) { corePut8(add32(regs.a[4], extWord(coreNext16())), v); } + stEA8tab[(5<<3)|5] = function(v) { corePut8(add32(regs.a[5], extWord(coreNext16())), v); } + stEA8tab[(5<<3)|6] = function(v) { corePut8(add32(regs.a[6], extWord(coreNext16())), v); } + stEA8tab[(5<<3)|7] = function(v) { corePut8(add32(regs.a[7], extWord(coreNext16())), v); } + stEA8tab[(6<<3)|0] = function(v) { corePut8(exII(regs.a[0], coreNext16()), v); } //rii + stEA8tab[(6<<3)|1] = function(v) { corePut8(exII(regs.a[1], coreNext16()), v); } + stEA8tab[(6<<3)|2] = function(v) { corePut8(exII(regs.a[2], coreNext16()), v); } + stEA8tab[(6<<3)|3] = function(v) { corePut8(exII(regs.a[3], coreNext16()), v); } + stEA8tab[(6<<3)|4] = function(v) { corePut8(exII(regs.a[4], coreNext16()), v); } + stEA8tab[(6<<3)|5] = function(v) { corePut8(exII(regs.a[5], coreNext16()), v); } + stEA8tab[(6<<3)|6] = function(v) { corePut8(exII(regs.a[6], coreNext16()), v); } + stEA8tab[(6<<3)|7] = function(v) { corePut8(exII(regs.a[7], coreNext16()), v); } + stEA8tab[(7<<3)|0] = function(v) { corePut8(extWord(coreNext16()), v); } //absw + stEA8tab[(7<<3)|1] = function(v) { corePut8(coreNext32(), v); } //absl + stEA8tab[(7<<3)|2] = function(v) { corePut8(add32(coreGetPC(), extWord(coreNext16())), v); } //pcid + stEA8tab[(7<<3)|3] = function(v) { corePut8(exII(coreGetPC(), coreNext16()), v); } //pcii + stEA8tab[(7<<3)|4] = function(v) { SAEF_error("cpu.stEA8tab() invalid EA 60 (7|4)"); } //imm + + stEA16tab = new Array(64); + stEA16tab[ 0] = function(v) { regs.d[0] = (regs.d[0] & 0xffff0000) | v; } //rdd + stEA16tab[ 1] = function(v) { regs.d[1] = (regs.d[1] & 0xffff0000) | v; } + stEA16tab[ 2] = function(v) { regs.d[2] = (regs.d[2] & 0xffff0000) | v; } + stEA16tab[ 3] = function(v) { regs.d[3] = (regs.d[3] & 0xffff0000) | v; } + stEA16tab[ 4] = function(v) { regs.d[4] = (regs.d[4] & 0xffff0000) | v; } + stEA16tab[ 5] = function(v) { regs.d[5] = (regs.d[5] & 0xffff0000) | v; } + stEA16tab[ 6] = function(v) { regs.d[6] = (regs.d[6] & 0xffff0000) | v; } + stEA16tab[ 7] = function(v) { regs.d[7] = (regs.d[7] & 0xffff0000) | v; } + stEA16tab[(1<<3)|0] = function(v) { regs.a[0] = v; } //rda + stEA16tab[(1<<3)|1] = function(v) { regs.a[1] = v; } + stEA16tab[(1<<3)|2] = function(v) { regs.a[2] = v; } + stEA16tab[(1<<3)|3] = function(v) { regs.a[3] = v; } + stEA16tab[(1<<3)|4] = function(v) { regs.a[4] = v; } + stEA16tab[(1<<3)|5] = function(v) { regs.a[5] = v; } + stEA16tab[(1<<3)|6] = function(v) { regs.a[6] = v; } + stEA16tab[(1<<3)|7] = function(v) { regs.a[7] = v; } + stEA16tab[(2<<3)|0] = function(v) { corePut16(regs.a[0], v); } //ria + stEA16tab[(2<<3)|1] = function(v) { corePut16(regs.a[1], v); } + stEA16tab[(2<<3)|2] = function(v) { corePut16(regs.a[2], v); } + stEA16tab[(2<<3)|3] = function(v) { corePut16(regs.a[3], v); } + stEA16tab[(2<<3)|4] = function(v) { corePut16(regs.a[4], v); } + stEA16tab[(2<<3)|5] = function(v) { corePut16(regs.a[5], v); } + stEA16tab[(2<<3)|6] = function(v) { corePut16(regs.a[6], v); } + stEA16tab[(2<<3)|7] = function(v) { corePut16(regs.a[7], v); } + stEA16tab[(3<<3)|0] = function(v) { corePut16(regs.a[0], v); regs.a[0] += 2; } //ripo + stEA16tab[(3<<3)|1] = function(v) { corePut16(regs.a[1], v); regs.a[1] += 2; } + stEA16tab[(3<<3)|2] = function(v) { corePut16(regs.a[2], v); regs.a[2] += 2; } + stEA16tab[(3<<3)|3] = function(v) { corePut16(regs.a[3], v); regs.a[3] += 2; } + stEA16tab[(3<<3)|4] = function(v) { corePut16(regs.a[4], v); regs.a[4] += 2; } + stEA16tab[(3<<3)|5] = function(v) { corePut16(regs.a[5], v); regs.a[5] += 2; } + stEA16tab[(3<<3)|6] = function(v) { corePut16(regs.a[6], v); regs.a[6] += 2; } + stEA16tab[(3<<3)|7] = function(v) { corePut16(regs.a[7], v); regs.a[7] += 2; } + stEA16tab[(4<<3)|0] = function(v) { regs.a[0] -= 2; corePut16(regs.a[0], v); } //ripr + stEA16tab[(4<<3)|1] = function(v) { regs.a[1] -= 2; corePut16(regs.a[1], v); } + stEA16tab[(4<<3)|2] = function(v) { regs.a[2] -= 2; corePut16(regs.a[2], v); } + stEA16tab[(4<<3)|3] = function(v) { regs.a[3] -= 2; corePut16(regs.a[3], v); } + stEA16tab[(4<<3)|4] = function(v) { regs.a[4] -= 2; corePut16(regs.a[4], v); } + stEA16tab[(4<<3)|5] = function(v) { regs.a[5] -= 2; corePut16(regs.a[5], v); } + stEA16tab[(4<<3)|6] = function(v) { regs.a[6] -= 2; corePut16(regs.a[6], v); } + stEA16tab[(4<<3)|7] = function(v) { regs.a[7] -= 2; corePut16(regs.a[7], v); } + stEA16tab[(5<<3)|0] = function(v) { corePut16(add32(regs.a[0], extWord(coreNext16())), v); } //rid + stEA16tab[(5<<3)|1] = function(v) { corePut16(add32(regs.a[1], extWord(coreNext16())), v); } + stEA16tab[(5<<3)|2] = function(v) { corePut16(add32(regs.a[2], extWord(coreNext16())), v); } + stEA16tab[(5<<3)|3] = function(v) { corePut16(add32(regs.a[3], extWord(coreNext16())), v); } + stEA16tab[(5<<3)|4] = function(v) { corePut16(add32(regs.a[4], extWord(coreNext16())), v); } + stEA16tab[(5<<3)|5] = function(v) { corePut16(add32(regs.a[5], extWord(coreNext16())), v); } + stEA16tab[(5<<3)|6] = function(v) { corePut16(add32(regs.a[6], extWord(coreNext16())), v); } + stEA16tab[(5<<3)|7] = function(v) { corePut16(add32(regs.a[7], extWord(coreNext16())), v); } + stEA16tab[(6<<3)|0] = function(v) { corePut16(exII(regs.a[0], coreNext16()), v); } //rii + stEA16tab[(6<<3)|1] = function(v) { corePut16(exII(regs.a[1], coreNext16()), v); } + stEA16tab[(6<<3)|2] = function(v) { corePut16(exII(regs.a[2], coreNext16()), v); } + stEA16tab[(6<<3)|3] = function(v) { corePut16(exII(regs.a[3], coreNext16()), v); } + stEA16tab[(6<<3)|4] = function(v) { corePut16(exII(regs.a[4], coreNext16()), v); } + stEA16tab[(6<<3)|5] = function(v) { corePut16(exII(regs.a[5], coreNext16()), v); } + stEA16tab[(6<<3)|6] = function(v) { corePut16(exII(regs.a[6], coreNext16()), v); } + stEA16tab[(6<<3)|7] = function(v) { corePut16(exII(regs.a[7], coreNext16()), v); } + stEA16tab[(7<<3)|0] = function(v) { corePut16(extWord(coreNext16()), v); } //absw + stEA16tab[(7<<3)|1] = function(v) { corePut16(coreNext32(), v); } //absl + stEA16tab[(7<<3)|2] = function(v) { corePut16(add32(coreGetPC(), extWord(coreNext16())), v); } //pcid + stEA16tab[(7<<3)|3] = function(v) { corePut16(exII(coreGetPC(), coreNext16()), v); } //pcii + stEA16tab[(7<<3)|4] = function(v) { SAEF_error("cpu.stEA16tab() invalid EA 60 (7|4)"); } //imm + + stEA32tab = new Array(64); + stEA32tab[ 0] = function(v) { regs.d[0] = v; } //rdd + stEA32tab[ 1] = function(v) { regs.d[1] = v; } + stEA32tab[ 2] = function(v) { regs.d[2] = v; } + stEA32tab[ 3] = function(v) { regs.d[3] = v; } + stEA32tab[ 4] = function(v) { regs.d[4] = v; } + stEA32tab[ 5] = function(v) { regs.d[5] = v; } + stEA32tab[ 6] = function(v) { regs.d[6] = v; } + stEA32tab[ 7] = function(v) { regs.d[7] = v; } + stEA32tab[(1<<3)|0] = function(v) { regs.a[0] = v; } //rda + stEA32tab[(1<<3)|1] = function(v) { regs.a[1] = v; } + stEA32tab[(1<<3)|2] = function(v) { regs.a[2] = v; } + stEA32tab[(1<<3)|3] = function(v) { regs.a[3] = v; } + stEA32tab[(1<<3)|4] = function(v) { regs.a[4] = v; } + stEA32tab[(1<<3)|5] = function(v) { regs.a[5] = v; } + stEA32tab[(1<<3)|6] = function(v) { regs.a[6] = v; } + stEA32tab[(1<<3)|7] = function(v) { regs.a[7] = v; } + stEA32tab[(2<<3)|0] = function(v) { corePut32(regs.a[0], v); } //ria + stEA32tab[(2<<3)|1] = function(v) { corePut32(regs.a[1], v); } + stEA32tab[(2<<3)|2] = function(v) { corePut32(regs.a[2], v); } + stEA32tab[(2<<3)|3] = function(v) { corePut32(regs.a[3], v); } + stEA32tab[(2<<3)|4] = function(v) { corePut32(regs.a[4], v); } + stEA32tab[(2<<3)|5] = function(v) { corePut32(regs.a[5], v); } + stEA32tab[(2<<3)|6] = function(v) { corePut32(regs.a[6], v); } + stEA32tab[(2<<3)|7] = function(v) { corePut32(regs.a[7], v); } + stEA32tab[(3<<3)|0] = function(v) { corePut32(regs.a[0], v); regs.a[0] += 4; } //ripo + stEA32tab[(3<<3)|1] = function(v) { corePut32(regs.a[1], v); regs.a[1] += 4; } + stEA32tab[(3<<3)|2] = function(v) { corePut32(regs.a[2], v); regs.a[2] += 4; } + stEA32tab[(3<<3)|3] = function(v) { corePut32(regs.a[3], v); regs.a[3] += 4; } + stEA32tab[(3<<3)|4] = function(v) { corePut32(regs.a[4], v); regs.a[4] += 4; } + stEA32tab[(3<<3)|5] = function(v) { corePut32(regs.a[5], v); regs.a[5] += 4; } + stEA32tab[(3<<3)|6] = function(v) { corePut32(regs.a[6], v); regs.a[6] += 4; } + stEA32tab[(3<<3)|7] = function(v) { corePut32(regs.a[7], v); regs.a[7] += 4; } + stEA32tab[(4<<3)|0] = function(v) { regs.a[0] -= 4; corePut32(regs.a[0], v); } //ripr + stEA32tab[(4<<3)|1] = function(v) { regs.a[1] -= 4; corePut32(regs.a[1], v); } + stEA32tab[(4<<3)|2] = function(v) { regs.a[2] -= 4; corePut32(regs.a[2], v); } + stEA32tab[(4<<3)|3] = function(v) { regs.a[3] -= 4; corePut32(regs.a[3], v); } + stEA32tab[(4<<3)|4] = function(v) { regs.a[4] -= 4; corePut32(regs.a[4], v); } + stEA32tab[(4<<3)|5] = function(v) { regs.a[5] -= 4; corePut32(regs.a[5], v); } + stEA32tab[(4<<3)|6] = function(v) { regs.a[6] -= 4; corePut32(regs.a[6], v); } + stEA32tab[(4<<3)|7] = function(v) { regs.a[7] -= 4; corePut32(regs.a[7], v); } + stEA32tab[(5<<3)|0] = function(v) { corePut32(add32(regs.a[0], extWord(coreNext16())), v); } //rid + stEA32tab[(5<<3)|1] = function(v) { corePut32(add32(regs.a[1], extWord(coreNext16())), v); } + stEA32tab[(5<<3)|2] = function(v) { corePut32(add32(regs.a[2], extWord(coreNext16())), v); } + stEA32tab[(5<<3)|3] = function(v) { corePut32(add32(regs.a[3], extWord(coreNext16())), v); } + stEA32tab[(5<<3)|4] = function(v) { corePut32(add32(regs.a[4], extWord(coreNext16())), v); } + stEA32tab[(5<<3)|5] = function(v) { corePut32(add32(regs.a[5], extWord(coreNext16())), v); } + stEA32tab[(5<<3)|6] = function(v) { corePut32(add32(regs.a[6], extWord(coreNext16())), v); } + stEA32tab[(5<<3)|7] = function(v) { corePut32(add32(regs.a[7], extWord(coreNext16())), v); } + stEA32tab[(6<<3)|0] = function(v) { corePut32(exII(regs.a[0], coreNext16()), v); } //rii + stEA32tab[(6<<3)|1] = function(v) { corePut32(exII(regs.a[1], coreNext16()), v); } + stEA32tab[(6<<3)|2] = function(v) { corePut32(exII(regs.a[2], coreNext16()), v); } + stEA32tab[(6<<3)|3] = function(v) { corePut32(exII(regs.a[3], coreNext16()), v); } + stEA32tab[(6<<3)|4] = function(v) { corePut32(exII(regs.a[4], coreNext16()), v); } + stEA32tab[(6<<3)|5] = function(v) { corePut32(exII(regs.a[5], coreNext16()), v); } + stEA32tab[(6<<3)|6] = function(v) { corePut32(exII(regs.a[6], coreNext16()), v); } + stEA32tab[(6<<3)|7] = function(v) { corePut32(exII(regs.a[7], coreNext16()), v); } + stEA32tab[(7<<3)|0] = function(v) { corePut32(extWord(coreNext16()), v); } //absw + stEA32tab[(7<<3)|1] = function(v) { corePut32(coreNext32(), v); } //absl + stEA32tab[(7<<3)|2] = function(v) { corePut32(add32(coreGetPC(), extWord(coreNext16())), v); } //pcid + stEA32tab[(7<<3)|3] = function(v) { corePut32(exII(coreGetPC(), coreNext16()), v); } //pcii + stEA32tab[(7<<3)|4] = function(v) { SAEF_error("cpu.stEA32tab() invalid EA 60 (7|4)"); } //imm + } + + /*-----------------------------------------------------------------------*/ + /* Instruction table */ + + /*function mkEA(m,r) { switch (m) { - case M_rdd: - case M_rda: return z == 4 ? [ 0,0,0] : [ 0,0,0]; - case M_ria: return z == 4 ? [ 8,2,0] : [ 4,1,0]; - case M_ripo: return z == 4 ? [ 8,2,0] : [ 4,1,0]; - case M_ripr: return z == 4 ? [10,2,0] : [ 6,1,0]; - case M_rid: return z == 4 ? [12,3,0] : [ 8,2,0]; - case M_rii: return z == 4 ? [14,3,0] : [10,2,0]; - case M_pcid: return z == 4 ? [12,3,0] : [ 8,2,0]; - case M_pcii: return z == 4 ? [14,3,0] : [10,2,0]; - case M_absw: return z == 4 ? [12,3,0] : [ 8,2,0]; - case M_absl: return z == 4 ? [16,4,0] : [12,3,0]; - case M_imm: - case M_list: return z == 4 ? [ 8,2,0] : [ 4,1,0]; - default: return [0,0,0]; + case M_rdd: return (0 << 3) | r; + case M_rda: return (1 << 3) | r; + case M_ria: return (2 << 3) | r; + case M_ripo: return (3 << 3) | r; + case M_ripr: return (4 << 3) | r; + case M_rid: return (5 << 3) | r; + case M_rii: return (6 << 3) | r; + case M_absw: return (7 << 3) | 0; + case M_absl: return (7 << 3) | 1; + case M_pcid: return (7 << 3) | 2; + case M_pcii: return (7 << 3) | 3; + case M_imm: return (7 << 3) | 4; } - } + SAEF_error("cpu.mkEA() ERROR m "+m+", r "+r); + return -1; + }*/ - function mkN(op, mn, cyc) { - var i = new IDef(); - i.op = op; - i.pr = false; - i.mn = mn; - i.f = null; - i.p = {}; - i.p.cyc = cyc; - return i; - } - - function mkS(op, mn, z, s, r, cyc, add) { - var i = new IDef(); - i.op = op; - i.pr = false; - i.mn = mn; - i.f = null; - i.p = {}; - i.p.z = z; - i.p.s = new EffAddr(s, r); - i.p.s.c = mkCyc(z, s); - i.p.cyc = cyc; - if (add) i.p.cyc[0] += i.p.s.c[0]; - i.p.cyc[1] += i.p.s.c[1]; - i.p.cyc[2] += i.p.s.c[2]; - return i; - } - - function mkD(op, mn, z, d, r, cyc, add) { - var i = new IDef(); - i.op = op; - i.pr = false; - i.mn = mn; - i.f = null; - i.p = {}; - i.p.z = z; - i.p.d = new EffAddr(d, r); - i.p.d.c = mkCyc(z, d); - i.p.cyc = cyc; - if (add) i.p.cyc[0] += i.p.d.c[0]; - i.p.cyc[1] += i.p.d.c[1]; - i.p.cyc[2] += i.p.d.c[2]; - return i; - } - - function mkSD(op, mn, z, sm, sr, dm, dr, cyc, sa, da) { - var i = new IDef(); - i.op = op; - i.pr = false; - i.mn = mn; - i.f = null; - i.p = {}; - i.p.z = z; - i.p.ms = z == 1 ? 0x80 : (z == 2 ? 0x8000 : 0x80000000); - i.p.mz = z == 1 ? 0xff : (z == 2 ? 0xffff : 0xffffffff); - i.p.s = new EffAddr(sm, sr); - i.p.d = new EffAddr(dm, dr); - i.p.s.c = mkCyc(z, sm); - i.p.d.c = mkCyc(z, dm); - i.p.cyc = cyc; - if (sa) i.p.cyc[0] += i.p.s.c[0]; - if (da) i.p.cyc[0] += i.p.d.c[0]; - i.p.cyc[1] += i.p.s.c[1]; - i.p.cyc[2] += i.p.s.c[2]; - i.p.cyc[1] += i.p.d.c[1]; - i.p.cyc[2] += i.p.d.c[2]; - return i; - } - - function mkC(op, mn, sz, cc, dp, dr, cycTaken, cyc) { - var i = new IDef(); - i.op = op; - i.pr = false; - i.mn = mn; - i.f = null; - i.p = {}; - i.p.z = sz; - i.p.c = new ICon(cc, dp, dr); - if (cycTaken !== null) i.p.cycTaken = cycTaken; - if (cyc !== null) i.p.cyc = cyc; - return i; - } - - function mkDBcc(op, mn, sz, cc, dp, dr, cycTrue, cycFalseTaken, cycFalse) { - var i = new IDef(); - i.op = op; - i.pr = false; - i.mn = mn; - i.f = null; - i.p = {}; - i.p.z = sz; - i.p.c = new ICon(cc, dp, dr); - i.p.cycTrue = cycTrue; - i.p.cycFalseTaken = cycFalseTaken; - i.p.cycFalse = cycFalse; - return i; - } - - function mkCD(op, mn, z, cc, dp, dr, m, r, cycTrue, cycFalse, add) { - var i = new IDef(); - i.op = op; - i.pr = false; - i.mn = mn; - i.f = null; - i.p = {}; - i.p.z = z; - i.p.c = new ICon(cc, dp, dr); - i.p.d = new EffAddr(m, r); - i.p.d.c = mkCyc(z, m); - i.p.cycTrue = cycTrue; - i.p.cycFalse = cycFalse; - if (add) { - i.p.cycTrue[0] += i.p.d.c[0]; - i.p.cycFalse[0] += i.p.d.c[0]; - } - i.p.cycTrue[1] += i.p.d.c[1]; - i.p.cycTrue[2] += i.p.d.c[2]; - i.p.cycFalse[1] += i.p.d.c[1]; - i.p.cycFalse[2] += i.p.d.c[2]; - return i; - } - - function mkEA(mr, en, inv) { - var m = (mr >> 3) & 7; - var r = mr & 7; - var b = inv ? (r << 3) | m : (m << 3) | r; - - if (m != 7) { - switch (m) { - case 0: { if (en.indexOf(M_rdd) != -1) return [b, M_rdd, r]; break; } - case 1: { if (en.indexOf(M_rda) != -1) return [b, M_rda, r]; break; } - case 2: { if (en.indexOf(M_ria) != -1) return [b, M_ria, r]; break; } - case 3: { if (en.indexOf(M_ripo) != -1) return [b, M_ripo, r]; break; } - case 4: { if (en.indexOf(M_ripr) != -1) return [b, M_ripr, r]; break; } - case 5: { if (en.indexOf(M_rid) != -1) return [b, M_rid, r]; break; } - case 6: { if (en.indexOf(M_rii) != -1) return [b, M_rii, r]; break; } + function getEAMode(ea) { + var m = ea >> 3; + if (m == 7) { + switch (ea & 7) { + case 0: return M_absw; + case 1: return M_absl; + case 2: return M_pcid; + case 3: return M_pcii; + case 4: return M_imm; } } else { - if (r == 0 && en.indexOf(M_absw) != -1) return [b, M_absw, -1]; - if (r == 1 && en.indexOf(M_absl) != -1) return [b, M_absl, -1]; - if (r == 2 && en.indexOf(M_pcid) != -1) return [b, M_pcid, -1]; - if (r == 3 && en.indexOf(M_pcii) != -1) return [b, M_pcii, -1]; - if (r == 4 && en.indexOf(M_imm) != -1) return [b, M_imm, -1]; + switch (m) { + case 0: return M_rdd; + case 1: return M_rda; + case 2: return M_ria; + case 3: return M_ripo; + case 4: return M_ripr; + case 5: return M_rid; + case 6: return M_rii; + } } - return [-1, -1, -1]; + SAEF_error("cpu.getEAMode() ERROR ea "+ea); + return -1; } - /* Start of the fun part... */ - function mkiTab() { - var op, cnt = 0; + function isEA(ea, en) { + var m = ea >> 3; + if (m == 7) { + var r = ea & 7; + if (r == 0 && en.indexOf(M_absw) != -1) return true; + if (r == 1 && en.indexOf(M_absl) != -1) return true; + if (r == 2 && en.indexOf(M_pcid) != -1) return true; + if (r == 3 && en.indexOf(M_pcii) != -1) return true; + if (r == 4 && en.indexOf(M_imm) != -1) return true; + } else { + if (m == 0 && en.indexOf(M_rdd) != -1) return true; + if (m == 1 && en.indexOf(M_rda) != -1) return true; + if (m == 2 && en.indexOf(M_ria) != -1) return true; + if (m == 3 && en.indexOf(M_ripo) != -1) return true; + if (m == 4 && en.indexOf(M_ripr) != -1) return true; + if (m == 5 && en.indexOf(M_rid) != -1) return true; + if (m == 6 && en.indexOf(M_rii) != -1) return true; + } + return false; + } + + function getEACycs(ea, z) { + var m = ea >> 3; + if (m == 7) { + switch (ea & 7) { + case 0: return z == 4 ? [12,3,0] : [ 8,2,0]; //absw + case 1: return z == 4 ? [16,4,0] : [12,3,0]; //absl + case 2: return z == 4 ? [12,3,0] : [ 8,2,0]; //pcid + case 3: return z == 4 ? [14,3,0] : [10,2,0]; //pcii + case 4: return z == 4 ? [ 8,2,0] : [ 4,1,0]; //imm + } + } else { + switch (m) { + case 0: return [0,0,0]; //rdd + case 1: return [0,0,0]; //rda + case 2: return z == 4 ? [ 8,2,0] : [ 4,1,0]; //ria + case 3: return z == 4 ? [ 8,2,0] : [ 4,1,0]; //ripo + case 4: return z == 4 ? [10,2,0] : [ 6,1,0]; //ripr + case 5: return z == 4 ? [12,3,0] : [ 8,2,0]; //rid + case 6: return z == 4 ? [14,3,0] : [10,2,0]; //rii + } + } + } + function addCycs(c1, c2) { + c1[0] += c2[0]; + c1[1] += c2[1]; + c1[2] += c2[2]; + return c1; + } + + function mkI(op, mn, cyc) { + return { + op: op, + mn: mn, + p: { + op:op, + cyc:cyc + } + }; + } + + function mkDiss(ext, sm, s, dm, d, z, z2) { + if (sm && dm) + return { + ext:ext, + sm:sm, + s:s, + dm:dm, + d:d, + z:z, + z2:z2 + }; + else if (dm) + return { + ext:ext, + dm:dm, + d:d, + z:z, + z2:z2 + }; + else + return { + ext:ext, + z:z, + z2:z2 + }; + } + + function mkITab() { + var op, cnt = 0; //45827 + var old = 0; iTab = new Array(0x10000); for (op = 0; op < 0x10000; op++) { - iTab[op] = new IDef(); - iTab[op].op = -1; - iTab[op].pr = false; - iTab[op].mn = 'ILLEGAL'; - iTab[op].f = I_ILLEGAL; - iTab[op].p = null; + iTab[op] = { + op: -1, + mn: "ILLEGAL", + p: op, /* opcode as param for ILLEGAL or real param if function */ + f: ILLEGAL + }; } - //ABCD - { - var rm, Rx, Ry; + /*-----------------------------------------------------------------------*/ + /* Data Movement */ - for (rm = 0; rm < 2; rm++) { - for (Rx = 0; Rx < 8; Rx++) { - for (Ry = 0; Ry < 8; Ry++) { - op = (12 << 12) | (Rx << 9) | (1 << 8) | (rm << 3) | Ry; - - if (iTab[op].op === -1) { - if (rm == 0) - iTab[op] = mkSD(op, 'ABCD', 1, M_rdd, Ry, M_rdd, Rx, [6,1,0], false, false); - else - iTab[op] = mkSD(op, 'ABCD', 1, M_ripr, Ry, M_ripr, Rx, [18,3,1], false, false); - - iTab[op].f = I_ABCD; - cnt++; - } else { - BUG.say('OP EXISTS ABCD ' + op); - return false; - } - } - } - } - } - //ADD - { - var z, z2, dir, en, Dn, mr, ea, cyc; - - for (z = 0; z < 3; z++) { - z2 = z == 0 ? 1 : (z == 1 ? 2 : 4); - for (dir = 0; dir < 2; dir++) { - if (dir == 0) en = [M_rdd, M_rda, M_ria, M_ripo, M_ripr, M_rid, M_rii, M_pcid, M_pcii, M_absw, M_absl, M_imm]; - else en = [M_ria, M_ripo, M_ripr, M_rid, M_rii, M_absw, M_absl]; - - for (Dn = 0; Dn < 8; Dn++) { - for (mr = 0; mr < 64; mr++) { - ea = mkEA(mr, en, 0); - if (ea[0] != -1) { - if (dir == 0 && ea[1] == M_rda && z == 0) continue; //An word and long only - - op = (13 << 12) | (Dn << 9) | (dir << 8) | (z << 6) | ea[0]; - - cyc = dir == 0 ? (z2 == 4 ? (ea[1] == M_rdd || ea[1] == M_imm ? [8,1,0] : [6,1,0]) : [4,1,0]) : (z2 == 4 ? [12,1,2] : [8,1,1]); - - if (iTab[op].op === -1) { - if (dir == 0) - iTab[op] = mkSD(op, 'ADD', z2, ea[1], ea[2], M_rdd, Dn, cyc, true, false); - else - iTab[op] = mkSD(op, 'ADD', z2, M_rdd, Dn, ea[1], ea[2], cyc, false, true); - - iTab[op].f = I_ADD; - cnt++; - } else { - BUG.say('OP EXISTS ADD ' + op); - return false; - } - } - } - } - } - } - } - //ADDA - { - var en = [M_rdd, M_rda, M_ria, M_ripo, M_ripr, M_rid, M_rii, M_pcid, M_pcii, M_absw, M_absl, M_imm]; - var z, z2, z3, An, mr, ea; - - for (z = 0; z < 2; z++) { - z2 = z == 0 ? 2 : 4; - z3 = z == 0 ? 3 : 7; - for (An = 0; An < 8; An++) { - for (mr = 0; mr < 64; mr++) { - ea = mkEA(mr, en, 0); - if (ea[0] != -1) { - op = (13 << 12) | (An << 9) | (z3 << 6) | ea[0]; - - if (iTab[op].op === -1) { - iTab[op] = mkSD(op, 'ADDA', z2, ea[1], ea[2], M_rda, An, z2 == 4 ? (ea[1] == M_rdd || ea[1] == M_imm ? [8,1,0] : [6,1,0]) : [8,1,0], true, false); - iTab[op].f = I_ADDA; - cnt++; - } else { - BUG.say('OP EXISTS ADDA ' + op); - return false; - } - } - } - } - } - } - //ADDI - { - var en = [M_rdd, M_ria, M_ripo, M_ripr, M_rid, M_rii, M_absw, M_absl]; - var z, z2, mr, ea; - - for (z = 0; z < 3; z++) { - z2 = z == 0 ? 1 : (z == 1 ? 2 : 4); - for (mr = 0; mr < 64; mr++) { - ea = mkEA(mr, en, 0); - if (ea[0] != -1) { - op = (6 << 8) | (z << 6) | ea[0]; - - if (iTab[op].op === -1) { - iTab[op] = mkSD(op, 'ADDI', z2, M_imm, -1, ea[1], ea[2], ea[1] == M_rdd ? (z2 == 4 ? [16,3,0] : [8,2,0]) : (z2 == 4 ? [20,3,2] : [12,2,1]), false, ea[1] != M_rdd); - iTab[op].f = I_ADDI; - cnt++; - } else { - BUG.say('OP EXISTS ADDI ' + op); - return false; - } - } - } - } - } - //ADDQ - { - var en = [M_rdd, M_rda, M_ria, M_ripo, M_ripr, M_rid, M_rii, M_absw, M_absl]; - var z, z2, id, mr, ea, cyc; - - for (z = 0; z < 3; z++) { - z2 = z == 0 ? 1 : (z == 1 ? 2 : 4); - for (id = 0; id < 8; id++) { - for (mr = 0; mr < 64; mr++) { - ea = mkEA(mr, en, 0); - if (ea[0] != -1) { - if (ea[1] == M_rda && z == 0) continue; //An word and long only - - op = (5 << 12) | (id << 9) | (z << 6) | ea[0]; - cyc = ea[1] == M_rda ? [8,1,0] : (ea[1] == M_rdd ? (z2 == 4 ? [8,1,0] : [4,1,0]) : (z2 == 4 ? [12,1,2] : [8,1,1])); - - if (iTab[op].op === -1) { - iTab[op] = mkSD(op, 'ADDQ', z2, M_imm, id == 0 ? 8 : id, ea[1], ea[2], cyc, false, ea[1] != M_rdd && ea[1] != M_rda); - //iTab[op].f = I_ADDQ; - iTab[op].f = ea[1] != M_rda ? I_ADDQ : I_ADDQA; - cnt++; - } else { - BUG.say('OP EXISTS ADDQ ' + op); - return false; - } - } - } - } - } - } - //ADDX - { - var z, z2, rm, Rx, Ry; - - for (z = 0; z < 3; z++) { - z2 = z == 0 ? 1 : (z == 1 ? 2 : 4); - for (rm = 0; rm < 2; rm++) { - for (Rx = 0; Rx < 8; Rx++) { - for (Ry = 0; Ry < 8; Ry++) { - op = (13 << 12) | (Rx << 9) | (1 << 8) | (z << 6) | (rm << 3) | Ry; - - if (iTab[op].op === -1) { - if (rm == 0) - iTab[op] = mkSD(op, 'ADDX', z2, M_rdd, Ry, M_rdd, Rx, z2 == 4 ? [8,1,0] : [4,1,0], false, false); - else - iTab[op] = mkSD(op, 'ADDX', z2, M_ripr, Ry, M_ripr, Rx, z2 == 4 ? [30,5,2] : [18,1,0], false, false); - - iTab[op].f = I_ADDX; - cnt++; - } else { - BUG.say('OP EXISTS ADDX ' + op + ' ' + iTab[op].mn + ' ' + iTab[op].p.s.r + ' ' + iTab[op].p.d.r); - return false; - } - } - } - } - } - } - //AND - { - var z, z2, dir, en, Dn, mr, ea, cyc; - - for (z = 0; z < 3; z++) { - z2 = z == 0 ? 1 : (z == 1 ? 2 : 4); - for (dir = 0; dir < 2; dir++) { - if (dir == 0) en = [M_rdd, M_ria, M_ripo, M_ripr, M_rid, M_rii, M_pcid, M_pcii, M_absw, M_absl, M_imm]; - else en = [M_ria, M_ripo, M_ripr, M_rid, M_rii, M_absw, M_absl]; - - for (Dn = 0; Dn < 8; Dn++) { - for (mr = 0; mr < 64; mr++) { - ea = mkEA(mr, en, 0); - if (ea[0] != -1) { - op = (12 << 12) | (Dn << 9) | (dir << 8) | (z << 6) | ea[0]; - - cyc = dir == 0 ? (z2 == 4 ? (ea[1] == M_rdd || ea[1] == M_imm ? [8,1,0] : [6,1,0]) : [4,1,0]) : (z2 == 4 ? [12,1,2] : [8,1,1]); - - if (iTab[op].op === -1) { - if (dir == 0) - iTab[op] = mkSD(op, 'AND', z2, ea[1], ea[2], M_rdd, Dn, cyc, true, false); - else - iTab[op] = mkSD(op, 'AND', z2, M_rdd, Dn, ea[1], ea[2], cyc, false, true); - - iTab[op].f = I_AND; - cnt++; - } else { - BUG.say('OP EXISTS AND ' + op); - return false; - } - } - } - } - } - } - } - //ANDI - { - var en = [M_rdd, M_ria, M_ripo, M_ripr, M_rid, M_rii, M_absw, M_absl]; - var z, z2, mr, ea; - - for (z = 0; z < 3; z++) { - z2 = z == 0 ? 1 : (z == 1 ? 2 : 4); - for (mr = 0; mr < 64; mr++) { - ea = mkEA(mr, en, 0); - if (ea[0] != -1) { - op = (2 << 8) | (z << 6) | ea[0]; - - if (iTab[op].op === -1) { - iTab[op] = mkSD(op, 'ANDI', z2, M_imm, -1, ea[1], ea[2], ea[1] == M_rdd ? (z2 == 4 ? [16,3,0] : [8,2,0]) : (z2 == 4 ? [20,3,2] : [12,2,1]), false, ea[1] != M_rdd); - iTab[op].f = I_ANDI; - cnt++; - } else { - BUG.say('OP EXISTS ANDI ' + op); - return false; - } - } - } - } - } - //ANDI_CCR - { - op = 0x23C; - - if (iTab[op].op === -1) { - iTab[op] = mkS(op, 'ANDI_CCR', 1, M_imm, -1, [20,3,0], false); - iTab[op].f = I_ANDI_CCR; - cnt++; - } else { - BUG.say('OP EXISTS ANDI ' + op); - return false; - } - } - //ANDI_SR - { - op = 0x27C; - - if (iTab[op].op === -1) { - iTab[op] = mkS(op, 'ANDI_SR', 2, M_imm, -1, [20,3,0], false); - iTab[op].pr = true; - iTab[op].f = I_ANDI_SR; - cnt++; - } else { - BUG.say('OP EXISTS ANDI ' + op); - return false; - } - } - //ASL,ASR - { - var en = [M_ria, M_ripo, M_ripr, M_rid, M_rii, M_absw, M_absl]; - var z, z2, dr, ir, cr, Dy, mr, ea; - - for (z = 0; z < 3; z++) { - z2 = z == 0 ? 1 : (z == 1 ? 2 : 4); - - for (dr = 0; dr < 2; dr++) { - for (ir = 0; ir < 2; ir++) { - for (cr = 0; cr < 8; cr++) { - for (Dy = 0; Dy < 8; Dy++) { - op = (14 << 12) | (cr << 9) | (dr << 8) | (z << 6) | (ir << 5) | Dy; - - if (iTab[op].op === -1) { - if (ir == 0) - iTab[op] = mkSD(op, dr == 0 ? 'ASR_RI' : 'ASL_RI', z2, M_imm, cr == 0 ? 8 : cr, M_rdd, Dy, z2 == 4 ? [8,1,0] : [6,1,0], false, false); - else - iTab[op] = mkSD(op, dr == 0 ? 'ASR_RD' : 'ASL_RD', z2, M_rdd, cr, M_rdd, Dy, z2 == 4 ? [8,1,0] : [6,1,0], false, false); - - iTab[op].f = dr == 0 ? I_ASR : I_ASL; - cnt++; - } else { - BUG.say('OP EXISTS ASx ' + op); - return false; - } - } - } - } - } - } - for (dr = 0; dr < 2; dr++) { - for (mr = 0; mr < 64; mr++) { - ea = mkEA(mr, en, 0); - if (ea[0] != -1) { - op = (112 << 9) | (dr << 8) | (3 << 6) | ea[0]; - - if (iTab[op].op === -1) { - iTab[op] = mkSD(op, dr == 0 ? 'ASR_M' : 'ASL_M', 2, M_imm, 1, ea[1], ea[2], [8,1,1], false, true); - iTab[op].f = dr == 0 ? I_ASR : I_ASL; - cnt++; - } else { - BUG.say('OP EXISTS ASx ' + op); - return false; - } - } - } - } - } - //Bcc - { - var cc, dp; - - for (cc = 2; cc < 16; cc++) { - for (dp = 0; dp < 255; dp++) /* 0xff = long, 68020 only */ - { - op = (6 << 12) | (cc << 8) | dp; - - if (iTab[op].op === -1) { - iTab[op] = mkC(op, 'B' + ccNames[cc], dp == 0 ? 1 : 2, cc, dp, -1, [10,2,0], dp == 0 ? [12,1,0] : [8,1,0]); - iTab[op].f = I_Bcc; - cnt++; - } else { - BUG.say('OP EXISTS B' + ccNames[cc] + ' ' + op); - return false; - } - } - } - } - //BCHG - { - var en = [M_rdd, M_ria, M_ripo, M_ripr, M_rid, M_rii, M_absw, M_absl]; - var Dn, mr, ea; - - for (Dn = 0; Dn < 8; Dn++) { - for (mr = 0; mr < 64; mr++) { - ea = mkEA(mr, en, 0); - if (ea[0] != -1) { - op = (Dn << 9) | (5 << 6) | ea[0]; - - if (iTab[op].op === -1) { - iTab[op] = mkSD(op, 'BCHG1', 4, M_rdd, Dn, ea[1], ea[2], [8,1,0], false, false); - iTab[op].f = I_BCHG; - cnt++; - } else { - BUG.say('OP EXISTS BCHG1 ' + op); - return false; - } - } - } - } - for (mr = 0; mr < 64; mr++) { - ea = mkEA(mr, en, 0); - if (ea[0] != -1) { - op = (33 << 6) | ea[0]; - - if (iTab[op].op === -1) { - iTab[op] = mkSD(op, 'BCHG2', 1, M_imm, -1, ea[1], ea[2], [8,1,1], false, true); - iTab[op].f = I_BCHG; - cnt++; - } else { - BUG.say('OP EXISTS BCHG2 ' + op); - return false; - } - } - } - } - //BCLR - { - var en = [M_rdd, M_ria, M_ripo, M_ripr, M_rid, M_rii, M_absw, M_absl]; - var Dn, mr, ea; - - for (Dn = 0; Dn < 8; Dn++) { - for (mr = 0; mr < 64; mr++) { - ea = mkEA(mr, en, 0); - if (ea[0] != -1) { - op = (Dn << 9) | (6 << 6) | ea[0]; - - if (iTab[op].op === -1) { - iTab[op] = mkSD(op, 'BCLR1', 4, M_rdd, Dn, ea[1], ea[2], [10,1,0], false, false); - iTab[op].f = I_BCLR; - cnt++; - } else { - BUG.say('OP EXISTS BCHG1 ' + op); - return false; - } - } - } - } - for (mr = 0; mr < 64; mr++) { - ea = mkEA(mr, en, 0); - if (ea[0] != -1) { - op = (34 << 6) | ea[0]; - - if (iTab[op].op === -1) { - iTab[op] = mkSD(op, 'BCLR2', 1, M_imm, - 1, ea[1], ea[2], [8,1,1], false, true); - iTab[op].f = I_BCLR; - cnt++; - } else { - BUG.say('OP EXISTS BCLR2 ' + op); - return false; - } - } - } - } - //BSET - { - var en = [M_rdd, M_ria, M_ripo, M_ripr, M_rid, M_rii, M_absw, M_absl]; - var Dn, mr, ea; - - for (Dn = 0; Dn < 8; Dn++) { - for (mr = 0; mr < 64; mr++) { - ea = mkEA(mr, en, 0); - if (ea[0] != -1) { - op = (Dn << 9) | (7 << 6) | ea[0]; - - if (iTab[op].op === -1) { - iTab[op] = mkSD(op, 'BSET1', 4, M_rdd, Dn, ea[1], ea[2], [8,1,0], false, false); - iTab[op].f = I_BSET; - cnt++; - } else { - BUG.say('OP EXISTS BSET1 ' + op); - return false; - } - } - } - } - for (mr = 0; mr < 64; mr++) { - ea = mkEA(mr, en, 0); - if (ea[0] != -1) { - op = (35 << 6) | ea[0]; - - if (iTab[op].op === -1) { - iTab[op] = mkSD(op, 'BSET2', 1, M_imm, - 1, ea[1], ea[2], [8,1,1], false, true); - iTab[op].f = I_BSET; - cnt++; - } else { - BUG.say('OP EXISTS BSET2 ' + op); - return false; - } - } - } - } - //BTST - { - var en = [M_rdd, M_ria, M_ripo, M_ripr, M_rid, M_rii, M_pcid, M_pcii, M_absw, M_absl, M_imm]; - var Dn, mr, ea; - - for (Dn = 0; Dn < 8; Dn++) { - for (mr = 0; mr < 64; mr++) { - ea = mkEA(mr, en, 0); - if (ea[0] != -1) { - op = (Dn << 9) | (4 << 6) | ea[0]; - - if (iTab[op].op === -1) { - iTab[op] = mkSD(op, 'BTST1', 4, M_rdd, Dn, ea[1], ea[2], [6,1,0], false, false); - iTab[op].f = I_BTST; - cnt++; - } else { - BUG.say('OP EXISTS BTST1 ' + op); - return false; - } - } - } - } - en = [M_rdd, M_ria, M_ripo, M_ripr, M_rid, M_rii, M_pcid, M_pcii, M_absw, M_absl]; - for (mr = 0; mr < 64; mr++) { - ea = mkEA(mr, en, 0); - if (ea[0] != -1) { - op = (32 << 6) | ea[0]; - - if (iTab[op].op === -1) { - iTab[op] = mkSD(op, 'BTST2', 1, M_imm, -1, ea[1], ea[2], [4,1,0], false, true); - iTab[op].f = I_BTST; - cnt++; - } else { - BUG.say('OP EXISTS BTST2 ' + op); - return false; - } - } - } - } - //BRA - { - var dp; - - for (dp = 0; dp < 255; dp++) /* 0xff = 68020 only */ - { - op = (96 << 8) | dp; - - if (iTab[op].op === -1) { - iTab[op] = mkC(op, 'BRA', dp == 0 ? 1 : 2, 0, dp, -1, [10,2,0], null); - iTab[op].f = I_BRA; - cnt++; - } else { - BUG.say('OP EXISTS BRA ' + op); - return false; - } - } - } - //BSR - { - var dp; - - for (dp = 0; dp < 255; dp++) /* 0xff = 68020 only */ - { - op = (97 << 8) | dp; - - if (iTab[op].op === -1) { - iTab[op] = mkC(op, 'BSR', dp == 0 ? 1 : 2, 1, dp, -1, [18,2,2], null); - iTab[op].f = I_BSR; - cnt++; - } else { - BUG.say('OP EXISTS BSR ' + op); - return false; - } - } - } - //CHK - { - var en = [M_rdd, M_ria, M_ripo, M_ripr, M_rid, M_rii, M_pcid, M_pcii, M_absw, M_absl, M_imm]; - var z2 = 2, - z3 = 3, - Dn, mr, ea; - - for (Dn = 0; Dn < 8; Dn++) { - for (mr = 0; mr < 64; mr++) { - ea = mkEA(mr, en, 0); - if (ea[0] != -1) { - op = (4 << 12) | (Dn << 9) | (z3 << 7) | ea[0]; - - if (iTab[op].op === -1) { - iTab[op] = mkSD(op, 'CHK', z2, ea[1], ea[2], M_rdd, Dn, [10,1,0], true, false); - iTab[op].f = I_CHK; - iTab[op].p.cycTaken = iTab[op].p.s.c; - cnt++; - } else { - BUG.say('OP EXISTS CHK ' + op); - return false; - } - } - } - } - } - //CLR - { - var en = [M_rdd, M_ria, M_ripo, M_ripr, M_rid, M_rii, M_absw, M_absl]; - var z, z2, mr, ea; - - for (z = 0; z < 3; z++) { - z2 = z == 0 ? 1 : (z == 1 ? 2 : 4); - for (mr = 0; mr < 64; mr++) { - ea = mkEA(mr, en, 0); - if (ea[0] != -1) { - op = (66 << 8) | (z << 6) | ea[0]; - - if (iTab[op].op === -1) { - iTab[op] = mkD(op, 'CLR', z2, ea[1], ea[2], ea[1] == M_rdd ? (z2 == 4 ? [6,1,0] : [4,1,0]) : (z2 == 4 ? [12,1,2] : [8,1,1]), ea[1] != M_rdd); - iTab[op].f = I_CLR; - cnt++; - } else { - BUG.say('OP EXISTS CLR ' + op); - return false; - } - } - } - } - } - //CMP - { - var en = [M_rdd, M_rda, M_ria, M_ripo, M_ripr, M_rid, M_rii, M_pcid, M_pcii, M_absw, M_absl, M_imm]; - var z, z2, Dn, mr, ea; - - for (z = 0; z < 3; z++) { - z2 = z == 0 ? 1 : (z == 1 ? 2 : 4); - for (Dn = 0; Dn < 8; Dn++) { - for (mr = 0; mr < 64; mr++) { - ea = mkEA(mr, en, 0); - if (ea[0] != -1) { - if (ea[1] == M_rda && z == 0) continue; //An word and long only - - op = (11 << 12) | (Dn << 9) | (z << 6) | ea[0]; - - if (iTab[op].op === -1) { - iTab[op] = mkSD(op, 'CMP', z2, ea[1], ea[2], M_rdd, Dn, z2 == 4 ? [6,1,0] : [4,1,0], true, false); - iTab[op].f = I_CMP; - cnt++; - } else { - BUG.say('OP EXISTS CMP ' + op); - return false; - } - } - } - } - } - } - //CMPA - { - var en = [M_rdd, M_rda, M_ria, M_ripo, M_ripr, M_rid, M_rii, M_pcid, M_pcii, M_absw, M_absl, M_imm]; - var z, z2, z3, An, mr, ea; - - for (z = 1; z < 3; z++) { - z2 = z == 1 ? 2 : 4; - z3 = z == 1 ? 3 : 7; - for (An = 0; An < 8; An++) { - for (mr = 0; mr < 64; mr++) { - ea = mkEA(mr, en, 0); - if (ea[0] != -1) { - op = (11 << 12) | (An << 9) | (z3 << 6) | ea[0]; - - if (iTab[op].op === -1) { - iTab[op] = mkSD(op, 'CMPA', z2, ea[1], ea[2], M_rda, An, [6,1,0], true, false); - iTab[op].f = I_CMPA; - cnt++; - } else { - BUG.say('OP EXISTS CMPA ' + op); - return false; - } - } - } - } - } - } - //CMPI - { - var en = [M_rdd, M_ria, M_ripo, M_ripr, M_rid, M_rii, M_absw, M_absl]; - var z, z2, mr, ea; - - for (z = 0; z < 3; z++) { - z2 = z == 0 ? 1 : (z == 1 ? 2 : 4); - for (mr = 0; mr < 64; mr++) { - ea = mkEA(mr, en, 0); - if (ea[0] != -1) { - op = (12 << 8) | (z << 6) | ea[0]; - - if (iTab[op].op === -1) { - iTab[op] = mkSD(op, 'CMPI', z2, M_imm, -1, ea[1], ea[2], ea[1] == M_rdd ? (z2 == 4 ? [14,3,0] : [8,2,0]) : (z2 == 4 ? [12,3,0] : [8,2,0]), false, ea[1] != M_rdd); - iTab[op].f = I_CMPI; - cnt++; - } else { - BUG.say('OP EXISTS CMPI ' + op); - return false; - } - } - } - } - } - //CMPM - { - var z, z2, Ax, Ay; - - for (z = 0; z < 3; z++) { - z2 = z == 0 ? 1 : (z == 1 ? 2 : 4); - for (Ax = 0; Ax < 8; Ax++) { - for (Ay = 0; Ay < 8; Ay++) { - op = (11 << 12) | (Ax << 9) | (1 << 8) | (z << 6) | (1 << 3) | Ay; - - if (iTab[op].op === -1) { - iTab[op] = mkSD(op, 'CMPM', z2, M_ripo, Ay, M_ripo, Ax, z2 == 4 ? [20,5,0] : [12,3,0], false, false); - iTab[op].f = I_CMPM; - cnt++; - } else { - BUG.say('OP EXISTS CMPM ' + op + ' ' + iTab[op].mn + ' ' + iTab[op].p.s.r + ' ' + iTab[op].p.d.r); - return false; - } - } - } - } - } - //DBcc - { - var cc, dr; - - for (cc = 0; cc < 16; cc++) { - for (dr = 0; dr < 8; dr++) { - op = (5 << 12) | (cc << 8) | (25 << 3) | dr; - - if (iTab[op].op === -1) { - iTab[op] = mkDBcc(op, 'DB' + ccNames[cc], 2, cc, -1, dr, [12,2,0], [10,2,0], [14,3,0]); - iTab[op].f = I_DBcc; - cnt++; - } else { - BUG.say('OP EXISTS DBcc ' + op); - return false; - } - } - } - } - //DIVS - { - var en = [M_rdd, M_ria, M_ripo, M_ripr, M_rid, M_rii, M_pcid, M_pcii, M_absw, M_absl, M_imm]; - var Dn, mr, ea; - - for (Dn = 0; Dn < 8; Dn++) { - for (mr = 0; mr < 64; mr++) { - ea = mkEA(mr, en, 0); - if (ea[0] != -1) { - op = (8 << 12) | (Dn << 9) | (7 << 6) | ea[0]; - - if (iTab[op].op === -1) { - iTab[op] = mkSD(op, 'DIVS', 2, ea[1], ea[2], M_rdd, Dn, [158,1,0], true, false); - iTab[op].f = I_DIVS; - cnt++; - } else { - BUG.say('OP EXISTS DIVS ' + op); - return false; - } - } - } - } - } - //DIVU - { - var en = [M_rdd, M_ria, M_ripo, M_ripr, M_rid, M_rii, M_pcid, M_pcii, M_absw, M_absl, M_imm]; - var Dn, mr, ea; - - for (Dn = 0; Dn < 8; Dn++) { - for (mr = 0; mr < 64; mr++) { - ea = mkEA(mr, en, 0); - if (ea[0] != -1) { - op = (8 << 12) | (Dn << 9) | (3 << 6) | ea[0]; - - if (iTab[op].op === -1) { - iTab[op] = mkSD(op, 'DIVU', 2, ea[1], ea[2], M_rdd, Dn, [140,1,0], true, false); - iTab[op].f = I_DIVU; - cnt++; - } else { - BUG.say('OP EXISTS DIVU ' + op); - return false; - } - } - } - } - } - //EOR - { - var en = [M_rdd, M_ria, M_ripo, M_ripr, M_rid, M_rii, M_absw, M_absl]; - var z, z2, z3, Dn, mr, ea; - - for (z = 0; z < 3; z++) { - z2 = z == 0 ? 1 : (z == 1 ? 2 : 4); - z3 = z == 0 ? 4 : (z == 1 ? 5 : 6); - for (Dn = 0; Dn < 8; Dn++) { - for (mr = 0; mr < 64; mr++) { - ea = mkEA(mr, en, 0); - if (ea[0] != -1) { - op = (11 << 12) | (Dn << 9) | (z3 << 6) | ea[0]; - - if (iTab[op].op === -1) { - iTab[op] = mkSD(op, 'EOR', z2, M_rdd, Dn, ea[1], ea[2], ea[1] == M_rdd ? (z2 == 4 ? [8,1,0] : [4,1,0]) : (z2 == 4 ? [12,1,2] : [8,1,1]), false, true); - iTab[op].f = I_EOR; - cnt++; - } else { - BUG.say('OP EXISTS EOR ' + op); - return false; - } - } - } - } - } - } - //EORI - { - var en = [M_rdd, M_ria, M_ripo, M_ripr, M_rid, M_rii, M_absw, M_absl]; - var z, z2, mr, ea; - - for (z = 0; z < 3; z++) { - z2 = z == 0 ? 1 : (z == 1 ? 2 : 4); - for (mr = 0; mr < 64; mr++) { - ea = mkEA(mr, en, 0); - if (ea[0] != -1) { - op = (10 << 8) | (z << 6) | ea[0]; - - if (iTab[op].op === -1) { - iTab[op] = mkSD(op, 'EORI', z2, M_imm, -1, ea[1], ea[2], ea[1] == M_rdd ? (z2 == 4 ? [16,3,0] : [8,2,0]) : (z2 == 4 ? [20,3,2] : [12,2,1]), false, ea[1] != M_rdd); - iTab[op].f = I_EORI; - cnt++; - } else { - BUG.say('OP EXISTS EORI ' + op); - return false; - } - } - } - } - } - //EORI_CCR - { - op = 0xA3C; - - if (iTab[op].op === -1) { - iTab[op] = mkS(op, 'EORI_CCR', 1, M_imm, -1, [20,3,0], false); - iTab[op].f = I_EORI_CCR; - cnt++; - } else { - BUG.say('OP EXISTS EORI ' + op); - return false; - } - } - //EORI_SR - { - op = 0xA7C; - - if (iTab[op].op === -1) { - iTab[op] = mkS(op, 'EORI_SR', 2, M_imm, -1, [20,3,0], false); - iTab[op].pr = true; - iTab[op].f = I_EORI_SR; - cnt++; - } else { - BUG.say('OP EXISTS EORI ' + op); - return false; - } - } //EXG { - var m, opm, Rx, Ry; - - for (m = 0; m < 3; m++) { - opm = m == 0 ? 8 : (m == 1 ? 9 : 17); - for (Rx = 0; Rx < 8; Rx++) { - for (Ry = 0; Ry < 8; Ry++) { + for (var m = 0; m < 3; m++) { + var opm = m == 0 ? 8 : (m == 1 ? 9 : 17); + for (var Rx = 0; Rx < 8; Rx++) { + for (var Ry = 0; Ry < 8; Ry++) { op = (12 << 12) | (Rx << 9) | (1 << 8) | (opm << 3) | Ry; - if (iTab[op].op === -1) { - if (m == 0) - iTab[op] = mkSD(op, 'EXG', 4, M_rdd, Rx, M_rdd, Ry, [6,1,0], false, false); - else if (m == 1) - iTab[op] = mkSD(op, 'EXG', 4, M_rda, Rx, M_rda, Ry, [6,1,0], false, false); - else - iTab[op] = mkSD(op, 'EXG', 4, M_rdd, Rx, M_rda, Ry, [6,1,0], false, false); - - iTab[op].f = I_EXG; + iTab[op] = mkI(op, "EXG", [6,1,0]); + iTab[op].p.Rx = Rx; + iTab[op].p.Ry = Ry; + if (m == 0) { + iTab[op].f = I_EXG_DD; + iTab[op].d = mkDiss(0, D_RDD,Rx, D_RDD,Ry, 4,0); + } else if (m == 1) { + iTab[op].f = I_EXG_AA; + iTab[op].d = mkDiss(0, D_RDA,Rx, D_RDA,Ry, 4,0); + } else { + iTab[op].f = I_EXG_DA; + iTab[op].d = mkDiss(0, D_RDD,Rx, D_RDA,Ry, 4,0); + } cnt++; } else { - BUG.say('OP EXISTS EXG ' + op + ' ' + iTab[op].mn + ' ' + iTab[op].p.s.r + ' ' + iTab[op].p.d.r); + SAEF_error("cpu.mkITab() op exists EXG "+op); return false; } } } } } - //EXT - { - var z, z2, opm, Dn; - - for (z = 1; z < 3; z++) { - z2 = z == 1 ? 2 : 4; - opm = z == 1 ? 2 : 3; - for (Dn = 0; Dn < 8; Dn++) { - op = (36 << 9) | (opm << 6) | Dn; - - if (iTab[op].op === -1) { - iTab[op] = mkD(op, 'EXT', z2, M_rdd, Dn, [4,1,0], false); - iTab[op].f = I_EXT; - cnt++; - } else { - BUG.say('OP EXISTS EXT ' + op + ' ' + iTab[op].mn + ' ' + iTab[op].p.s.r + ' ' + iTab[op].p.d.r); - return false; - } - } - } - } - //ILLEGAL - { - op = 0x4AFC; - - if (iTab[op].op === -1) { - iTab[op] = mkN(op, 'ILLEGAL', [0,0,0]); - iTab[op].f = I_ILLEGAL; - cnt++; - } else { - BUG.say('OP EXISTS ILLEGAL ' + op); - return false; - } - } - //JMP + //LEA { var en = [M_ria, M_rid, M_rii, M_pcid, M_pcii, M_absw, M_absl]; - var mr, ea, cyc; - - for (mr = 0; mr < 64; mr++) { - ea = mkEA(mr, en, 0); - if (ea[0] != -1) { - op = (315 << 6) | ea[0]; - - if (iTab[op].op === -1) { - switch (ea[1]) { - case M_ria: cyc = [ 8,2,0]; break; - case M_rid: cyc = [10,2,0]; break; - case M_rii: cyc = [14,3,0]; break; - case M_pcid: cyc = [10,2,0]; break; - case M_pcii: cyc = [14,3,0]; break; - case M_absw: cyc = [10,2,0]; break; - case M_absl: cyc = [12,3,0]; break; - } - iTab[op] = mkD(op, 'JMP', 0, ea[1], ea[2], cyc, false); - iTab[op].f = I_JMP; - cnt++; - } else { - BUG.say('OP EXISTS JMP ' + op); - return false; - } - } - } - } - //JSR - { - var en = [M_ria, M_rid, M_rii, M_pcid, M_pcii, M_absw, M_absl]; - var mr, ea, cyc; - - for (mr = 0; mr < 64; mr++) { - ea = mkEA(mr, en, 0); - if (ea[0] != -1) { - op = (314 << 6) | ea[0]; - - if (iTab[op].op === -1) { - switch (ea[1]) { - case M_ria: cyc = [16,2,2]; break; - case M_rid: cyc = [18,2,2]; break; - case M_rii: cyc = [22,2,2]; break; - case M_pcid: cyc = [18,2,2]; break; - case M_pcii: cyc = [22,2,2]; break; - case M_absw: cyc = [18,2,2]; break; - case M_absl: cyc = [20,3,2]; break; - } - iTab[op] = mkD(op, 'JSR', 0, ea[1], ea[2], cyc, false); - iTab[op].f = I_JSR; - cnt++; - } else { - BUG.say('OP EXISTS JSR ' + op); - return false; - } - } - } - } - //LEA - { - var en = [M_ria, M_rid, M_rii, M_pcid, M_pcii, M_absw, M_absl]; - var An, mr, ea, cyc; - - for (An = 0; An < 8; An++) { - for (mr = 0; mr < 64; mr++) { - ea = mkEA(mr, en, 0); - if (ea[0] != -1) { - op = (4 << 12) | (An << 9) | (7 << 6) | ea[0]; - + for (var An = 0; An < 8; An++) { + for (var ea = 0; ea < 61; ea++) { + if (isEA(ea, en)) { + op = (4 << 12) | (An << 9) | (7 << 6) | ea; if (iTab[op].op === -1) { - switch (ea[1]) { + var cyc; + switch (getEAMode(ea)) { case M_ria: cyc = [ 4,1,0]; break; case M_rid: cyc = [ 8,2,0]; break; case M_rii: cyc = [12,2,0]; break; @@ -3366,85 +7279,98 @@ function CPU() { case M_absw: cyc = [ 8,2,0]; break; case M_absl: cyc = [12,3,0]; break; } - iTab[op] = mkSD(op, 'LEA', 4, ea[1], ea[2], M_rda, An, cyc, false, false); + iTab[op] = mkI(op, "LEA", cyc); + iTab[op].p.An = An; + iTab[op].p.ea = ea; iTab[op].f = I_LEA; + iTab[op].d = mkDiss(0, D_EA,ea, D_RDA,An, 4,0); cnt++; } else { - BUG.say('OP EXISTS LEA ' + op); + SAEF_error("cpu.mkITab() op exists LEA "+op); return false; } } } } } - //LINK + //PEA { - var An; - - for (An = 0; An < 8; An++) { + var en = [M_ria, M_rid, M_rii, M_pcid, M_pcii, M_absw, M_absl]; + for (var ea = 0; ea < 61; ea++) { + if (isEA(ea, en)) { + op = (289 << 6) | ea; + if (iTab[op].op === -1) { + var cyc; + switch (getEAMode(ea)) { + case M_ria: cyc = [12,1,2]; break; + case M_rid: cyc = [16,2,2]; break; + case M_rii: cyc = [20,2,2]; break; + case M_pcid: cyc = [16,2,2]; break; + case M_pcii: cyc = [20,2,2]; break; + case M_absw: cyc = [16,2,2]; break; + case M_absl: cyc = [20,3,2]; break; + } + iTab[op] = mkI(op, "PEA", cyc); + iTab[op].p.ea = ea; + iTab[op].f = I_PEA; + iTab[op].d = mkDiss(0, false,false, D_EA,ea, 4,0); + cnt++; + } else { + SAEF_error("cpu.mkITab() op exists PEA " + op); + return false; + } + } + } + } + //LINK + { + for (var An = 0; An < 8; An++) { op = (2506 << 3) | An; - if (iTab[op].op === -1) { - iTab[op] = mkSD(op, 'LINK', 2, M_rda, An, M_imm, -1, [16,2,2], false, false); + iTab[op] = mkI(op, "LINK", [16,2,2]); + iTab[op].p.An = An; iTab[op].f = I_LINK; + iTab[op].d = mkDiss(0, D_RDA,An, D_IME,1, 2,0); cnt++; } else { - BUG.say('OP EXISTS LINK ' + op); + SAEF_error("cpu.mkITab() op exists LINK "+op); + return false; + } + } + if (model >= 68020) { + for (var An = 0; An < 8; An++) { + op = (2305 << 3) | An; + if (iTab[op].op === -1) { + iTab[op] = mkI(op, "LINK", [16,2,2]); //FIXME cycles + iTab[op].p.An = An; + iTab[op].f = I_LINK_32; + iTab[op].d = mkDiss(0, D_RDA,An, D_IME,2, 4,0); + cnt++; + } else { + SAEF_error("cpu.mkITab() op exists LINK "+op); + return false; + } + } + } + } + //UNLK + { + for (var An = 0; An < 8; An++) { + op = (2507 << 3) | An; + if (iTab[op].op === -1) { + iTab[op] = mkI(op, "UNLK", [12,3,0]); + iTab[op].p.An = An; + iTab[op].f = I_UNLK; + iTab[op].d = mkDiss(0, false,false, D_RDA,An, 0,0); + cnt++; + } else { + SAEF_error("cpu.mkITab() op exists UNLK "+op); return false; } } } - //LSL,LSR + //MOVE { - var en = [M_ria, M_ripo, M_ripr, M_rid, M_rii, M_absw, M_absl]; - var z, z2, dr, ir, cr, Dy, mr, ea; - - for (z = 0; z < 3; z++) { - z2 = z == 0 ? 1 : (z == 1 ? 2 : 4); - - for (dr = 0; dr < 2; dr++) { - for (ir = 0; ir < 2; ir++) { - for (cr = 0; cr < 8; cr++) { - for (Dy = 0; Dy < 8; Dy++) { - op = (14 << 12) | (cr << 9) | (dr << 8) | (z << 6) | (ir << 5) | (1 << 3) | Dy; - - if (iTab[op].op === -1) { - if (ir == 0) - iTab[op] = mkSD(op, dr == 0 ? 'LSR_RI' : 'LSL_RI', z2, M_imm, cr == 0 ? 8 : cr, M_rdd, Dy, z2 == 4 ? [8,1,0] : [6,1,0], false, false); - else - iTab[op] = mkSD(op, dr == 0 ? 'LSR_RD' : 'LSL_RD', z2, M_rdd, cr, M_rdd, Dy, z2 == 4 ? [8,1,0] : [6,1,0], false, false); - - iTab[op].f = dr == 0 ? I_LSR : I_LSL; - cnt++; - } else { - BUG.say('OP EXISTS LSx ' + op); - return false; - } - } - } - } - } - } - for (dr = 0; dr < 2; dr++) { - for (mr = 0; mr < 64; mr++) { - ea = mkEA(mr, en, 0); - if (ea[0] != -1) { - op = (113 << 9) | (dr << 8) | (3 << 6) | ea[0]; - - if (iTab[op].op === -1) { - iTab[op] = mkSD(op, dr == 0 ? 'LSR_M' : 'LSL_M', 2, M_imm, 1, ea[1], ea[2], [8,1,1], false, true); - iTab[op].f = dr == 0 ? I_LSR : I_LSL; - cnt++; - } else { - BUG.say('OP EXISTS LSx ' + op); - return false; - } - } - } - } - } - //MOVE - { var tab2 = [ [[ 4,1,0],null,[ 8,1,1],[ 8,1,1],[ 8,1,1],[12,2,1],[14,2,1],null,null,[12,2,1],[16,3,1],null], [[ 4,1,0],null,[ 8,1,1],[ 8,1,1],[ 8,1,1],[12,2,1],[14,2,1],null,null,[12,2,1],[16,3,1],null], @@ -3458,7 +7384,7 @@ function CPU() { [[12,3,0],null,[16,3,1],[16,3,1],[16,3,1],[20,4,1],[22,4,1],null,null,[20,4,1],[24,5,1],null], [[16,4,0],null,[20,4,1],[20,4,1],[20,4,1],[24,5,1],[26,5,1],null,null,[24,5,1],[28,6,1],null], [[ 8,2,0],null,[12,2,1],[12,2,1],[12,2,1],[16,3,1],[18,3,1],null,null,[16,3,1],[20,4,1],null] - ]; + ]; var tab4 = [ [[ 4,1,0],null,[12,1,2],[12,1,2],[12,1,2],[16,2,2],[18,2,2],null,null,[16,2,2],[20,3,2],null], [[ 4,1,0],null,[12,1,2],[12,1,2],[12,1,2],[16,2,2],[18,2,2],null,null,[16,2,2],[20,3,2],null], @@ -3471,93 +7397,28 @@ function CPU() { [[18,4,0],null,[26,4,2],[26,4,2],[26,4,2],[30,5,2],[32,5,2],null,null,[30,5,2],[34,6,2],null], [[16,4,0],null,[24,4,2],[24,4,2],[24,4,2],[28,5,2],[30,5,2],null,null,[28,5,2],[32,6,2],null], [[20,5,0],null,[28,5,2],[28,5,2],[28,5,2],[32,6,2],[34,6,2],null,null,[32,6,2],[36,7,2],null], - [[12,3,0],null,[20,3,2],[20,3,2],[20,3,2],[24,4,2],[26,4,2],null,null,[24,4,2],[28,5,2],null] - ]; - var sen = [M_rdd, M_rda, M_ria, M_ripo, M_ripr, M_rid, M_rii, M_pcid, M_pcii, M_absw, M_absl, M_imm]; + [[12,3,0],null,[20,3,2],[20,3,2],[20,3,2],[24,4,2],[26,4,2],null,null,[24,4,2],[28,5,2],null] + ]; var den = [M_rdd, M_ria, M_ripo, M_ripr, M_rid, M_rii, M_absw, M_absl]; - var z, z2, z3, smr, dmr, sea, dea; - - for (z = 0; z < 3; z++) { - z2 = z == 0 ? 1 : (z == 1 ? 2 : 4); - z3 = z == 0 ? 1 : (z == 1 ? 3 : 2); - - for (dmr = 0; dmr < 64; dmr++) { - dea = mkEA(dmr, den, 1); - if (dea[0] != -1) { - for (smr = 0; smr < 64; smr++) { - sea = mkEA(smr, sen, 0); - if (sea[0] != -1) { - if (sea[1] == M_rda && z == 0) //For byte size operation, address register direct is not allowed. - continue; - - op = (z3 << 12) | (dea[0] << 6) | sea[0]; - - if (iTab[op].op === -1) { - iTab[op] = mkSD(op, 'MOVE', z2, sea[1], sea[2], dea[1], dea[2], z2 == 4 ? tab4[sea[1]-1][dea[1]-1] : tab2[sea[1]-1][dea[1]-1], false, false); - iTab[op].f = I_MOVE; - //iTab[op].p.cyc = z2 == 4 ? tab4[sea[1]-1][dea[1]-1] : tab2[sea[1]-1][dea[1]-1]; - //if (typeof(iTab[op].p.cyc) != 'number') console.log(op, z2, sea[1], dea[1]); - cnt++; - } else { - BUG.say('OP EXISTS MOVE op ' + op + ', size ' + z2 + ', sm ' + sea[1] + ', sr ' + sea[2] + ', dm ' + dea[1] + ', dr ' + dea[2]); - return false; - } - } - } - } - } - } - } - //MOVEA - { - var tab2 = [ - [ 4,1,0], - [ 4,1,0], - [ 8,2,0], - [ 8,2,0], - [10,2,0], - [12,3,0], - [14,3,0], - [12,3,0], - [14,3,0], - [12,3,0], - [16,4,0], - [ 8,2,0] - ]; - var tab4 = [ - [ 4,1,0], - [ 4,1,0], - [12,3,0], - [12,3,0], - [14,3,0], - [16,4,0], - [18,4,0], - [16,4,0], - [18,4,0], - [16,4,0], - [20,5,0], - [12,3,0] - ]; - var en = [M_rdd, M_rda, M_ria, M_ripo, M_ripr, M_rid, M_rii, M_pcid, M_pcii, M_absw, M_absl, M_imm]; - var z, z2, z3, An, mr, ea; - - for (z = 1; z < 3; z++) { - z2 = z == 1 ? 2 : 4; - z3 = z == 1 ? 3 : 2; - - for (An = 0; An < 8; An++) { - for (mr = 0; mr < 64; mr++) { - ea = mkEA(mr, en, 0); - if (ea[0] != -1) { - op = (z3 << 12) | (An << 9) | (1 << 6) | ea[0]; - + for (var z = 0; z < 3; z++) { + var z2 = z == 0 ? 1 : (z == 1 ? 2 : 4); + var z3 = z == 0 ? 1 : (z == 1 ? 3 : 2); + for (var dea = 0; dea < 61; dea++) { + if (isEA(dea, den)) { + for (var sea = 0; sea < 61; sea++) { + if (z2 == 1 && sea >> 3 == 1) continue; //For byte size operation, address register direct is not allowed. + var deainv = ((dea & 7) << 3) | (dea >> 3); + op = (z3 << 12) | (deainv << 6) | sea; if (iTab[op].op === -1) { - iTab[op] = mkSD(op, 'MOVEA', z2, ea[1], ea[2], M_rda, An, z2 == 4 ? tab4[ea[1]-1] : tab2[ea[1]-1], false, false); - iTab[op].f = I_MOVEA; - //iTab[op].p.cyc = z2 == 4 ? tab4[ea[1]-1] : tab2[ea[1]-1]; + iTab[op] = mkI(op, "MOVE", z2 == 4 ? tab4[getEAMode(sea)-1][getEAMode(dea)-1] : tab2[getEAMode(sea)-1][getEAMode(dea)-1]); + iTab[op].p.sea = sea; + iTab[op].p.dea = dea; + iTab[op].p.zm = z2 == 1 ? 0x80 : (z2 == 2 ? 0x8000 : 0x80000000); + iTab[op].f = z2 == 4 ? I_MOVE_32 : (z2 == 2 ? I_MOVE_16 : I_MOVE_8); + iTab[op].d = mkDiss(0, D_EA,sea, D_EA,dea, z2,0); cnt++; } else { - BUG.say('OP EXISTS MOVEA op ' + op + ', size ' + z2 + ', sm ' + sea[1] + ', sr ' + sea[2] + ', dm ' + dea[1] + ', dr ' + dea[2]); + SAEF_error("cpu.mkITab() op exists MOVE "+op); return false; } } @@ -3565,174 +7426,109 @@ function CPU() { } } } - //MOVE_CCR2 ups, not for the 68000 - /*{ - var en = [M_rdd,M_ria,M_ripo,M_ripr,M_rid,M_rii,M_absw,M_absl]; - var mr, ea; - - for (mr = 0; mr < 64; mr++) - { - ea = mkEA(mr, en, 0); - if (ea[0] != -1) - { - op = (267 << 6) | ea[0]; - - if (iTab[op].op === -1) { - iTab[op] = mkD(op, 'MOVE_CCR2', 2, ea[1], ea[2], [0,0,0], false); - iTab[op].f = I_MOVE_CCR2; - cnt++; - } else { - BUG.say('OP EXISTS MOVE_CCR2 '+op); - return false; - } - } - } - }*/ - //MOVE_2CCR + //MOVEA { - var en = [M_rdd, M_ria, M_ripo, M_ripr, M_rid, M_rii, M_pcid, M_pcii, M_absw, M_absl, M_imm]; - var mr, ea; - - for (mr = 0; mr < 64; mr++) { - ea = mkEA(mr, en, 0); - if (ea[0] != -1) { - op = (275 << 6) | ea[0]; - - if (iTab[op].op === -1) { - iTab[op] = mkS(op, 'MOVE_2CCR', 2, ea[1], ea[2], [12,1,0], ea[1] != M_rdd); - iTab[op].f = I_MOVE_2CCR; - cnt++; - } else { - BUG.say('OP EXISTS MOVE_2CCR ' + op); - return false; + var tab2 = [[4,1,0],[4,1,0],[ 8,2,0],[ 8,2,0],[10,2,0],[12,3,0],[14,3,0],[12,3,0],[14,3,0],[12,3,0],[16,4,0],[ 8,2,0]]; + var tab4 = [[4,1,0],[4,1,0],[12,3,0],[12,3,0],[14,3,0],[16,4,0],[18,4,0],[16,4,0],[18,4,0],[16,4,0],[20,5,0],[12,3,0]]; + for (var z = 1; z < 3; z++) { + var z2 = z == 1 ? 2 : 4; + var z3 = z == 1 ? 3 : 2; + for (var An = 0; An < 8; An++) { + for (var ea = 0; ea < 61; ea++) { + op = (z3 << 12) | (An << 9) | (1 << 6) | ea; + if (iTab[op].op === -1) { + iTab[op] = mkI(op, "MOVEA", z2 == 4 ? tab4[getEAMode(ea)-1] : tab2[getEAMode(ea)-1]); + iTab[op].p.An = An; + iTab[op].p.ea = ea; + iTab[op].f = z2 == 4 ? I_MOVEA_32 : I_MOVEA_16; + iTab[op].d = mkDiss(0, D_EA,ea, D_RDA,An, z2,0); + cnt++; + } else { + SAEF_error("cpu.mkITab() op exists MOVEA "+op); + return false; + } } } } } - //MOVE_SR2 + //MOVEQ { - var en = [M_rdd, M_ria, M_ripo, M_ripr, M_rid, M_rii, M_absw, M_absl]; - var mr, ea; - - for (mr = 0; mr < 64; mr++) { - ea = mkEA(mr, en, 0); - if (ea[0] != -1) { - op = (259 << 6) | ea[0]; - + for (var Dn = 0; Dn < 8; Dn++) { + for (var d = 0; d < 256; d++) { + op = (7 << 12) | (Dn << 9) | d; if (iTab[op].op === -1) { - iTab[op] = mkD(op, 'MOVE_SR2', 2, ea[1], ea[2], ea[1] == M_rdd ? [6,1,0] : [8,1,1], ea[1] != M_rdd); - iTab[op].f = I_MOVE_SR2; + iTab[op] = mkI(op, "MOVEQ", [4,1,0]); + iTab[op].p.Dn = Dn; + iTab[op].p.data = d; + iTab[op].p.zm = 0x80000000; + iTab[op].f = I_MOVEQ; + iTab[op].d = mkDiss(0, D_IMD,d, D_RDD,Dn, 4,0); cnt++; } else { - BUG.say('OP EXISTS MOVE_SR2 ' + op); - return false; - } - } - } - } - //MOVE_2SR - { - var en = [M_rdd, M_ria, M_ripo, M_ripr, M_rid, M_rii, M_pcid, M_pcii, M_absw, M_absl, M_imm]; - var mr, ea; - - for (mr = 0; mr < 64; mr++) { - ea = mkEA(mr, en, 0); - if (ea[0] != -1) { - op = (283 << 6) | ea[0]; - - if (iTab[op].op === -1) { - iTab[op] = mkS(op, 'MOVE_2SR', 2, ea[1], ea[2], [12,1,0], ea[1] != M_rdd); - iTab[op].pr = true; - iTab[op].f = I_MOVE_2SR; - cnt++; - } else { - BUG.say('OP EXISTS MOVE_2SR ' + op); - return false; - } - } - } - } - //MOVE_USP - { - var dr, An; - - for (dr = 0; dr < 2; dr++) { - for (An = 0; An < 8; An++) { - op = (1254 << 4) | (dr << 3) | An; - - if (iTab[op].op === -1) { - if (dr == 0) - iTab[op] = mkS(op, 'MOVE_A2USP', 4, M_rda, An, [4,1,0], false); - else - iTab[op] = mkD(op, 'MOVE_USP2A', 4, M_rda, An, [4,1,0], false); - - iTab[op].pr = true; - iTab[op].f = (dr == 0) ? I_MOVE_A2USP : I_MOVE_USP2A; - cnt++; - } else { - BUG.say('OP EXISTS MOVE_USP ' + op); + SAEF_error("cpu.mkITab() op exists MOVEQ " + op); return false; } } } } //MOVEM - /* - instr size (An) (An)+ -(An) d(An) d(An,ix)+ d(PC) d(PC,ix)* xxx.W xxx.L - MOVEM - word 12+4n 12+4n - 16+4n 18+4n 16+4n 18+4n 16+4n 20+4n - M->R (3+n/0) (3+n/0) - (4+n/0) (4+n/0) (4+n/0) (4+n/0) (4+n/0) (5+n/0) - long 12+8n 12+8n - 16+8n 18+8n 16+8n 18+8n 16+8n 20+8n - (3+2n/0) (3+2n/0) - (4+2n/0) (4+2n/0) (4+2n/0) (4+2n/0) (4+2n/0) (5+2n/0) - - MOVEM - word 8+4n - 8+4n 12+4n 14+4n - - 12+4n 16+4n - R->M (2/n) - (2/n) (3/n) (3/n) - - (3/n) (4/n) - long 8+8n - 8+8n 12+8n 14+8n - - 12+8n 16+8n - (2/2n) - (2/2n) (3/2n) (3/2n) - - (3/2n) (4/2n)*/ - { - var z, z2, dr, mr, ea, cyc; + /* + size (An) (An)+ -(An) d(An) d(An,ix)+ xxx.W xxx.L d(PC) d(PC,ix)* + --------------------------------------------------------------------------------------------------------------- + R->M word 8+4n - 8+4n 12+4n 14+4n 12+4n 16+4n - - + (2/n) - (2/n) (3/n) (3/n) (3/n) (4/n) - - - for (z = 0; z < 2; z++) { - z2 = z == 0 ? 2 : 4; - for (dr = 0; dr < 2; dr++) { + long 8+8n - 8+8n 12+8n 14+8n 12+8n 16+8n - - + (2/2n) - (2/2n) (3/2n) (3/2n) (3/2n) (4/2n) - - + + M->R word 12+4n 12+4n - 16+4n 18+4n 16+4n 20+4n 16+4n 18+4n + (3+n/0) (3+n/0) - (4+n/0) (4+n/0) (4+n/0) (5+n/0) (4+n/0) (4+n/0) + + long 12+8n 12+8n - 16+8n 18+8n 16+8n 20+8n 16+8n 18+8n + (3+2n/0) (3+2n/0) - (4+2n/0) (4+2n/0) (4+2n/0) (5+2n/0) (4+2n/0) (4+2n/0) + */ + { + for (var z = 0; z < 2; z++) { + var z2 = z == 0 ? 2 : 4; + for (var dr = 0; dr < 2; dr++) { if (dr == 0) en = [M_ria, M_ripr, M_rid, M_rii, M_absw, M_absl]; else en = [M_ria, M_ripo, M_rid, M_rii, M_pcid, M_pcii, M_absw, M_absl]; - - for (mr = 0; mr < 64; mr++) { - ea = mkEA(mr, en, 0); - if (ea[0] != -1) { - op = (9 << 11) | (dr << 10) | (1 << 7) | (z << 6) | ea[0]; - + for (var ea = 0; ea < 61; ea++) { + if (isEA(ea, en)) { + op = (9 << 11) | (dr << 10) | (1 << 7) | (z << 6) | ea; if (iTab[op].op === -1) { + var cyc, m = getEAMode(ea); if (dr == 0) { - switch (ea[1]) { + switch (m) { case M_ria: cyc = [8,2,0]; break; case M_ripr: cyc = [8,2,0]; break; case M_rid: cyc = [12,3,0]; break; case M_rii: cyc = [14,3,0]; break; case M_absw: cyc = [12,3,0]; break; case M_absl: cyc = [16,4,0]; break; - } - iTab[op] = mkSD(op, 'MOVEM_R2M', z2, M_list, -1, ea[1], ea[2], cyc, false, false); - iTab[op].f = I_MOVEM_R2M; + } + iTab[op] = mkI(op, "MOVEM", cyc); + iTab[op].f = z2 == 2 ? I_MOVEM_R2M_16 : I_MOVEM_R2M_32; + iTab[op].d = mkDiss(1, D_EXT_MOVEM,m == M_ripr, D_EA,ea, z2,0); } else { - switch (ea[1]) { + switch (m) { case M_ria: cyc = [12,3,0]; break; case M_ripo: cyc = [12,3,0]; break; case M_rid: cyc = [16,4,0]; break; case M_rii: cyc = [18,4,0]; break; case M_pcid: cyc = [16,4,0]; break; - case M_pcii: cyc = [18,4,0]; break; + case M_pcii: cyc = [20,5,0]; break; case M_absw: cyc = [16,4,0]; break; - case M_absl: cyc = [20,5,0]; break; - } - iTab[op] = mkSD(op, 'MOVEM_M2R', z2, M_list, -1, ea[1], ea[2], cyc, false, false); - iTab[op].f = I_MOVEM_M2R; + case M_absl: cyc = [18,4,0]; break; + } + iTab[op] = mkI(op, "MOVEM", cyc); + iTab[op].f = z2 == 2 ? I_MOVEM_M2R_16 : I_MOVEM_M2R_32; + iTab[op].d = mkDiss(1, D_EA,ea, D_EXT_MOVEM,m == M_ripr, z2,0); } + iTab[op].p.ea = ea; cnt++; } else { - BUG.say('OP EXISTS MOVEM ' + op); + SAEF_error("cpu.mkITab() op exists MOVEM " + op); return false; } } @@ -3742,359 +7538,75 @@ function CPU() { } //MOVEP { - var m, opm, Dn, An; - - for (m = 0; m < 4; m++) { - opm = m + 4; - for (Dn = 0; Dn < 8; Dn++) { - for (An = 0; An < 8; An++) { - op = (Dn << 9) | (opm << 6) | (1 << 3) | An; - + for (var m = 4; m < 8; m++) { + for (var Dn = 0; Dn < 8; Dn++) { + for (var An = 0; An < 8; An++) { + op = (Dn << 9) | (m << 6) | (1 << 3) | An; if (iTab[op].op === -1) { - if (m == 0) - iTab[op] = mkSD(op, 'MOVEP', 2, M_rid, An, M_rdd, Dn, [16,4,0], false, false); - else if (m == 1) - iTab[op] = mkSD(op, 'MOVEP', 4, M_rid, An, M_rdd, Dn, [24,6,0], false, false); - else if (m == 2) - iTab[op] = mkSD(op, 'MOVEP', 2, M_rdd, Dn, M_rid, An, [16,2,2], false, false); - else - iTab[op] = mkSD(op, 'MOVEP', 4, M_rdd, Dn, M_rid, An, [24,2,4], false, false); - - iTab[op].f = I_MOVEP; - cnt++; - } else { - BUG.say('OP EXISTS MOVEP ' + op); - return false; - } - } - } - } - } - //MOVEQ - { - var Dn, d; - - for (Dn = 0; Dn < 8; Dn++) { - for (d = 0; d < 256; d++) { - op = (7 << 12) | (Dn << 9) | d; - - if (iTab[op].op === -1) { - iTab[op] = mkSD(op, 'MOVEQ', 4, M_imm, d, M_rdd, Dn, [4,1,0], false, false); - iTab[op].f = I_MOVEQ; - cnt++; - } else { - BUG.say('OP EXISTS MOVEQ ' + op); - return false; - } - } - } - } - //MULS - { - var en = [M_rdd, M_ria, M_ripo, M_ripr, M_rid, M_rii, M_pcid, M_pcii, M_absw, M_absl, M_imm]; - var Dn, mr, ea; - - for (Dn = 0; Dn < 8; Dn++) { - for (mr = 0; mr < 64; mr++) { - ea = mkEA(mr, en, 0); - if (ea[0] != -1) { - op = (12 << 12) | (Dn << 9) | (7 << 6) | ea[0]; - - if (iTab[op].op === -1) { - iTab[op] = mkSD(op, 'MULS', 2, ea[1], ea[2], M_rdd, Dn, [70,1,0], true, false); - iTab[op].f = I_MULS; - cnt++; - } else { - BUG.say('OP EXISTS MULS ' + op); - return false; - } - } - } - } - } - //MULU - { - var en = [M_rdd, M_ria, M_ripo, M_ripr, M_rid, M_rii, M_pcid, M_pcii, M_absw, M_absl, M_imm]; - var Dn, mr, ea; - - for (Dn = 0; Dn < 8; Dn++) { - for (mr = 0; mr < 64; mr++) { - ea = mkEA(mr, en, 0); - if (ea[0] != -1) { - op = (12 << 12) | (Dn << 9) | (3 << 6) | ea[0]; - - if (iTab[op].op === -1) { - iTab[op] = mkSD(op, 'MULU', 2, ea[1], ea[2], M_rdd, Dn, [70,1,0], true, false); - iTab[op].f = I_MULU; - cnt++; - } else { - BUG.say('OP EXISTS MULU ' + op); - return false; - } - } - } - } - } - //NBCD - { - var en = [M_rdd, M_ria, M_ripo, M_ripr, M_rid, M_rii, M_absw, M_absl]; - var mr, ea; - - for (mr = 0; mr < 64; mr++) { - ea = mkEA(mr, en, 0); - if (ea[0] != -1) { - op = (288 << 6) | ea[0]; - - if (iTab[op].op === -1) { - iTab[op] = mkD(op, 'NBCD', 1, ea[1], ea[2], ea[1] == M_rdd ? [6,1,0] : [8,1,1], ea[1] != M_rdd); - iTab[op].f = I_NBCD; - cnt++; - } else { - BUG.say('OP EXISTS NBCD ' + op); - return false; - } - } - } - } - //NEG - { - var en = [M_rdd, M_ria, M_ripo, M_ripr, M_rid, M_rii, M_absw, M_absl]; - var z, z2, mr, ea; - - for (z = 0; z < 3; z++) { - z2 = z == 0 ? 1 : (z == 1 ? 2 : 4); - for (mr = 0; mr < 64; mr++) { - ea = mkEA(mr, en, 0); - if (ea[0] != -1) { - op = (68 << 8) | (z << 6) | ea[0]; - - if (iTab[op].op === -1) { - iTab[op] = mkD(op, 'NEG', z2, ea[1], ea[2], ea[1] == M_rdd ? (z2 == 4 ? [6,1,0] : [4,1,0]) : (z2 == 4 ? [12,1,2] : [8,1,1]), ea[1] != M_rdd); - iTab[op].f = I_NEG; - cnt++; - } else { - BUG.say('OP EXISTS NEG ' + op); - return false; - } - } - } - } - } - //NEGX - { - var en = [M_rdd, M_ria, M_ripo, M_ripr, M_rid, M_rii, M_absw, M_absl]; - var z, z2, mr, ea; - - for (z = 0; z < 3; z++) { - z2 = z == 0 ? 1 : (z == 1 ? 2 : 4); - for (mr = 0; mr < 64; mr++) { - ea = mkEA(mr, en, 0); - if (ea[0] != -1) { - op = (64 << 8) | (z << 6) | ea[0]; - - if (iTab[op].op === -1) { - iTab[op] = mkD(op, 'NEGX', z2, ea[1], ea[2], ea[1] == M_rdd ? (z2 == 4 ? [6,1,0] : [4,1,0]) : (z2 == 4 ? [12,1,2] : [8,1,1]), ea[1] != M_rdd); - iTab[op].f = I_NEGX; - cnt++; - } else { - BUG.say('OP EXISTS NEGX ' + op); - return false; - } - } - } - } - } - //NOP - { - op = 0x4E71; - - if (iTab[op].op === -1) { - iTab[op] = mkN(op, 'NOP', [4,1,0]); - iTab[op].f = I_NOP; - cnt++; - } else { - BUG.say('OP EXISTS NOP ' + op); - return false; - } - } - //NOT - { - var en = [M_rdd, M_ria, M_ripo, M_ripr, M_rid, M_rii, M_absw, M_absl]; - var z, z2, mr, ea; - - for (z = 0; z < 3; z++) { - z2 = z == 0 ? 1 : (z == 1 ? 2 : 4); - for (mr = 0; mr < 64; mr++) { - ea = mkEA(mr, en, 0); - if (ea[0] != -1) { - op = (70 << 8) | (z << 6) | ea[0]; - - if (iTab[op].op === -1) { - iTab[op] = mkD(op, 'NOT', z2, ea[1], ea[2], ea[1] == M_rdd ? (z2 == 4 ? [6,1,0] : [4,1,0]) : (z2 == 4 ? [12,1,2] : [8,1,1]), ea[1] != M_rdd); - iTab[op].f = I_NOT; - cnt++; - } else { - BUG.say('OP EXISTS NOT ' + op); - return false; - } - } - } - } - } - //OR - { - var z, z2, dir, en, Dn, mr, ea, cyc; - - for (z = 0; z < 3; z++) { - z2 = z == 0 ? 1 : (z == 1 ? 2 : 4); - for (dir = 0; dir < 2; dir++) { - if (dir == 0) en = [M_rdd, M_ria, M_ripo, M_ripr, M_rid, M_rii, M_pcid, M_pcii, M_absw, M_absl, M_imm]; - else en = [M_ria, M_ripo, M_ripr, M_rid, M_rii, M_absw, M_absl]; - - for (Dn = 0; Dn < 8; Dn++) { - for (mr = 0; mr < 64; mr++) { - ea = mkEA(mr, en, 0); - if (ea[0] != -1) { - op = (8 << 12) | (Dn << 9) | (dir << 8) | (z << 6) | ea[0]; - - cyc = dir == 0 ? (z2 == 4 ? (ea[1] == M_rdd || ea[1] == M_imm ? [8,1,0] : [6,1,0]) : (ea[1] == M_rdd || ea[1] == M_imm ? [8,1,0] : [4,1,0])) : (z2 == 4 ? [12,1,2] : [8,1,1]); - - if (iTab[op].op === -1) { - if (dir == 0) - iTab[op] = mkSD(op, 'OR', z2, ea[1], ea[2], M_rdd, Dn, cyc, true, false); - else - iTab[op] = mkSD(op, 'OR', z2, M_rdd, Dn, ea[1], ea[2], cyc, false, true); - - iTab[op].f = I_OR; - cnt++; - } else { - BUG.say('OP EXISTS OR ' + op); - return false; - } + if (m == 4) { + iTab[op] = mkI(op, "MOVEP", [16,4,0]); + iTab[op].f = I_MOVEP_M2R_16; + iTab[op].d = mkDiss(0, D_RID,An, D_RDD,Dn, 2,0); } - } - } - } - } - } - //ORI - { - var en = [M_rdd, M_ria, M_ripo, M_ripr, M_rid, M_rii, M_absw, M_absl]; - var z, z2, mr, ea; - - for (z = 0; z < 3; z++) { - z2 = z == 0 ? 1 : (z == 1 ? 2 : 4); - for (mr = 0; mr < 64; mr++) { - ea = mkEA(mr, en, 0); - if (ea[0] != -1) { - op = (z << 6) | ea[0]; - - if (iTab[op].op === -1) { - iTab[op] = mkSD(op, 'ORI', z2, M_imm, -1, ea[1], ea[2], ea[1] == M_rdd ? (z2 == 4 ? [16,3,0] : [8,2,0]) : (z2 == 4 ? [20,3,2] : [12,2,1]), false, ea[1] != M_rdd); - iTab[op].f = I_ORI; + else if (m == 5) { + iTab[op] = mkI(op, "MOVEP", [24,6,0]); + iTab[op].f = I_MOVEP_M2R_32; + iTab[op].d = mkDiss(0, D_RID,An, D_RDD,Dn, 4,0); + } + else if (m == 6) { + iTab[op] = mkI(op, "MOVEP", [16,2,2]); + iTab[op].f = I_MOVEP_R2M_16; + iTab[op].d = mkDiss(0, D_RDD,Dn, D_RID,An, 2,0); + } + else { + iTab[op] = mkI(op, "MOVEP", [24,2,4]); + iTab[op].f = I_MOVEP_R2M_32; + iTab[op].d = mkDiss(0, D_RDD,Dn, D_RID,An, 4,0); + } + iTab[op].p.Dn = Dn; + iTab[op].p.An = An; cnt++; } else { - BUG.say('OP EXISTS ORI ' + op); + SAEF_error("cpu.mkITab() op exists MOVEP " + op); return false; } } } } } - //ORI_CCR - { - op = 0x3C; - if (iTab[op].op === -1) { - iTab[op] = mkS(op, 'ORI_CCR', 1, M_imm, -1, [20,3,0], false); - iTab[op].f = I_ORI_CCR; - cnt++; - } else { - BUG.say('OP EXISTS ORI_CCR ' + op); - return false; - } - } - //ORI_SR - { - op = 0x7C; + /*-----------------------------------------------------------------------*/ + /* Integer - Basic */ - if (iTab[op].op === -1) { - iTab[op] = mkS(op, 'ORI_SR', 2, M_imm, -1, [20,3,0], false); - iTab[op].pr = true; - iTab[op].f = I_ORI_SR; - cnt++; - } else { - BUG.say('OP EXISTS ORI_SR ' + op); - return false; - } - } - //PEA - { - var en = [M_ria, M_rid, M_rii, M_pcid, M_pcii, M_absw, M_absl]; - var mr, ea, cyc; - - for (mr = 0; mr < 64; mr++) { - ea = mkEA(mr, en, 0); - if (ea[0] != -1) { - op = (289 << 6) | ea[0]; - - if (iTab[op].op === -1) { - switch (ea[1]) { - case M_ria: cyc = [12,1,2]; break; - case M_rid: cyc = [16,2,2]; break; - case M_rii: cyc = [20,2,2]; break; - case M_pcid: cyc = [16,2,2]; break; - case M_pcii: cyc = [20,2,2]; break; - case M_absw: cyc = [16,2,2]; break; - case M_absl: cyc = [20,3,2]; break; - } - iTab[op] = mkS(op, 'PEA', 4, ea[1], ea[2], cyc, false); - iTab[op].f = I_PEA; - cnt++; - } else { - BUG.say('OP EXISTS PEA ' + op); - return false; - } - } - } - } - //RESET - { - op = 0x4E70; - - if (iTab[op].op === -1) { - iTab[op] = mkN(op, 'RESET', [132,1,0]); - iTab[op].f = I_RESET; - cnt++; - } else { - BUG.say('OP EXISTS RESET ' + op); - return false; - } - } - //ROL,ROR + //ADD { var en = [M_ria, M_ripo, M_ripr, M_rid, M_rii, M_absw, M_absl]; - var z, z2, dr, ir, cr, Dy, mr, ea; - - for (z = 0; z < 3; z++) { - z2 = z == 0 ? 1 : (z == 1 ? 2 : 4); - - for (dr = 0; dr < 2; dr++) { - for (ir = 0; ir < 2; ir++) { - for (cr = 0; cr < 8; cr++) { - for (Dy = 0; Dy < 8; Dy++) { - op = (14 << 12) | (cr << 9) | (dr << 8) | (z << 6) | (ir << 5) | (3 << 3) | Dy; - - if (iTab[op].op === -1) { - if (ir == 0) - iTab[op] = mkSD(op, dr == 0 ? 'ROR_RI' : 'ROL_RI', z2, M_imm, cr == 0 ? 8 : cr, M_rdd, Dy, z2 == 4 ? [8,1,0] : [6,1,0], false, false); - else - iTab[op] = mkSD(op, dr == 0 ? 'ROR_RD' : 'ROL_RD', z2, M_rdd, cr, M_rdd, Dy, z2 == 4 ? [8,1,0] : [6,1,0], false, false); - - iTab[op].f = dr == 0 ? I_ROR : I_ROL; + for (var z = 0; z < 3; z++) { + var z2 = z == 0 ? 1 : (z == 1 ? 2 : 4); + for (var dir = 0; dir < 2; dir++) { + for (var Dn = 0; Dn < 8; Dn++) { + for (var ea = 0; ea < 61; ea++) { + if (dir == 0 || (dir == 1 && isEA(ea, en))) { + var m = getEAMode(ea); + if (dir == 0 && m == M_rda && z == 0) continue; //An word and long only + op = (13 << 12) | (Dn << 9) | (dir << 8) | (z << 6) | ea; + if (iTab[op].op === -1) { + iTab[op] = mkI(op, "ADD", []); + iTab[op].p.Dn = Dn; + iTab[op].p.ea = ea; + iTab[op].p.zm = z2 == 4 ? 0x80000000 : (z2 == 2 ? 0x8000 : 0x80); + if (dir == 0) { + iTab[op].p.cyc = addCycs(z2 == 4 ? (m == M_rdd || m == M_imm ? [8,1,0]:[6,1,0]) : [4,1,0], getEACycs(ea, z2)); + iTab[op].f = z2 == 4 ? I_ADD_ED_32 : (z2 == 2 ? I_ADD_ED_16 : I_ADD_ED_8); + iTab[op].d = mkDiss(0, D_EA,ea, D_RDD,Dn, z2,0); + } else { + iTab[op].p.cyc = addCycs(z2 == 4 ? [12,1,2] : [8,1,1], getEACycs(ea, z2)); + iTab[op].f = z2 == 4 ? I_ADD_DE_32 : (z2 == 2 ? I_ADD_DE_16 : I_ADD_DE_8); + iTab[op].d = mkDiss(0, D_RDD,Dn, D_EA,ea, z2,0); + } cnt++; } else { - BUG.say('OP EXISTS ROx ' + op); + SAEF_error("cpu.mkITab() op exists ADD " + op); return false; } } @@ -4102,206 +7614,36 @@ function CPU() { } } } - for (dr = 0; dr < 2; dr++) { - for (mr = 0; mr < 64; mr++) { - ea = mkEA(mr, en, 0); - if (ea[0] != -1) { - op = (115 << 9) | (dr << 8) | (3 << 6) | ea[0]; - - if (iTab[op].op === -1) { - iTab[op] = mkSD(op, dr == 0 ? 'ROR_M' : 'ROL_M', 2, M_imm, 1, ea[1], ea[2], [8,1,1], false, true); - iTab[op].f = dr == 0 ? I_ROR : I_ROL; - cnt++; - } else { - BUG.say('OP EXISTS ROx ' + op); - return false; - } - } - } - } - } - //ROXL,ROXR - { - var en = [M_ria, M_ripo, M_ripr, M_rid, M_rii, M_absw, M_absl]; - var z, z2, dr, ir, cr, Dy, mr, ea; - - for (z = 0; z < 3; z++) { - z2 = z == 0 ? 1 : (z == 1 ? 2 : 4); - - for (dr = 0; dr < 2; dr++) { - for (ir = 0; ir < 2; ir++) { - for (cr = 0; cr < 8; cr++) { - for (Dy = 0; Dy < 8; Dy++) { - op = (14 << 12) | (cr << 9) | (dr << 8) | (z << 6) | (ir << 5) | (2 << 3) | Dy; - - if (iTab[op].op === -1) { - if (ir == 0) - iTab[op] = mkSD(op, dr == 0 ? 'ROXR_RI' : 'ROXL_RI', z2, M_imm, cr == 0 ? 8 : cr, M_rdd, Dy, z2 == 4 ? [8,1,0] : [6,1,0], false, false); - else - iTab[op] = mkSD(op, dr == 0 ? 'ROXR_RD' : 'ROXL_RD', z2, M_rdd, cr, M_rdd, Dy, z2 == 4 ? [8,1,0] : [6,1,0], false, false); - - iTab[op].f = dr == 0 ? I_ROXR : I_ROXL; - cnt++; - } else { - BUG.say('OP EXISTS ROx ' + op); - return false; - } - } - } - } - } - } - for (dr = 0; dr < 2; dr++) { - for (mr = 0; mr < 64; mr++) { - ea = mkEA(mr, en, 0); - if (ea[0] != -1) { - op = (114 << 9) | (dr << 8) | (3 << 6) | ea[0]; - - if (iTab[op].op === -1) { - iTab[op] = mkSD(op, dr == 0 ? 'ROXR_M' : 'ROXL_M', 2, M_imm, 1, ea[1], ea[2], [8,1,1], false, true); - iTab[op].f = dr == 0 ? I_ROXR : I_ROXL; - cnt++; - } else { - BUG.say('OP EXISTS ROx ' + op); - return false; - } - } - } - } - } - //RTE - { - op = 0x4E73; - - if (iTab[op].op === -1) { - iTab[op] = mkN(op, 'RTE', [20,5,0]); - iTab[op].pr = true; - iTab[op].f = I_RTE; - cnt++; - } else { - BUG.say('OP EXISTS RTE ' + op); - return false; - } - } - //RTR - { - op = 0x4E77; - - if (iTab[op].op === -1) { - iTab[op] = mkN(op, 'RTR', [20,5,0]); - iTab[op].f = I_RTR; - cnt++; - } else { - BUG.say('OP EXISTS RTR ' + op); - return false; - } - } - //RTS - { - op = 0x4E75; - - if (iTab[op].op === -1) { - iTab[op] = mkN(op, 'RTS', [16,4,0]); - iTab[op].f = I_RTS; - cnt++; - } else { - BUG.say('OP EXISTS RTS ' + op); - return false; - } - } - //SBCD - { - var rm, Rx, Ry; - - for (rm = 0; rm < 2; rm++) { - for (Rx = 0; Rx < 8; Rx++) { - for (Ry = 0; Ry < 8; Ry++) { - op = (8 << 12) | (Ry << 9) | (1 << 8) | (rm << 3) | Rx; - - if (iTab[op].op === -1) { - if (rm == 0) - iTab[op] = mkSD(op, 'SBCD', 1, M_rdd, Rx, M_rdd, Ry, [6,3,1], false, false); - else - iTab[op] = mkSD(op, 'SBCD', 1, M_ripr, Rx, M_ripr, Ry, [18,3,1], false, false); - - iTab[op].f = I_SBCD; - cnt++; - } else { - BUG.say('OP EXISTS SBCD ' + op); - return false; - } - } - } - } - } - //Scc - { - var en = [M_rdd, M_ria, M_ripo, M_ripr, M_rid, M_rii, M_absw, M_absl]; - var cc, mr, ea; - - for (cc = 0; cc < 16; cc++) { - for (mr = 0; mr < 64; mr++) { - ea = mkEA(mr, en, 0); - if (ea[0] != -1) { - op = (5 << 12) | (cc << 8) | (3 << 6) | ea[0]; - - if (iTab[op].op === -1) { - iTab[op] = mkCD(op, 'S' + ccNames[cc], 1, cc, -1, -1, ea[1], ea[2], ea[1] == M_rdd ? [6,1,0] : [8,1,1], ea[1] == M_rdd ? [4,1,0] : [8,1,1], ea[1] != M_rdd); - iTab[op].f = I_Scc; - cnt++; - } else { - BUG.say('OP EXISTS S' + ccNames[cc] + ' ' + op); - return false; - } - } - } - } - } - //STOP - { - op = 0x4E72; - - if (iTab[op].op === -1) { - iTab[op] = mkS(op, 'STOP', 2, M_imm, -1, [4,0,0], false); - iTab[op].pr = true; - iTab[op].f = I_STOP; - cnt++; - } else { - BUG.say('OP EXISTS STOP ' + op); - return false; - } } //SUB { - var z, z2, dir, en, Dn, mr, ea, cyc; - - for (z = 0; z < 3; z++) { - z2 = z == 0 ? 1 : (z == 1 ? 2 : 4); - for (dir = 0; dir < 2; dir++) { - if (dir == 0) en = [M_rdd, M_rda, M_ria, M_ripo, M_ripr, M_rid, M_rii, M_pcid, M_pcii, M_absw, M_absl, M_imm]; - else en = [M_ria, M_ripo, M_ripr, M_rid, M_rii, M_absw, M_absl]; - - for (Dn = 0; Dn < 8; Dn++) { - for (mr = 0; mr < 64; mr++) { - ea = mkEA(mr, en, 0); - if (ea[0] != -1) { - if (dir == 0 && ea[1] == M_rda && z == 0) //For byte-sized operation, address register direct is not allowed - continue; - - op = (9 << 12) | (Dn << 9) | (dir << 8) | (z << 6) | ea[0]; - - cyc = dir == 0 ? (z2 == 4 ? (ea[1] == M_rdd || ea[1] == M_imm ? [8,1,0] : [6,1,0]) : [4,1,0]) : (z2 == 4 ? [12,1,2] : [8,1,1]); - + var en = [M_ria, M_ripo, M_ripr, M_rid, M_rii, M_absw, M_absl]; + for (var z = 0; z < 3; z++) { + var z2 = z == 0 ? 1 : (z == 1 ? 2 : 4); + for (var dir = 0; dir < 2; dir++) { + for (var Dn = 0; Dn < 8; Dn++) { + for (var ea = 0; ea < 61; ea++) { + if (dir == 0 || (dir == 1 && isEA(ea, en))) { + var m = getEAMode(ea); + if (dir == 0 && m == M_rda && z == 0) continue; //An word and long only + op = (9 << 12) | (Dn << 9) | (dir << 8) | (z << 6) | ea; if (iTab[op].op === -1) { - if (dir == 0) - iTab[op] = mkSD(op, 'SUB', z2, ea[1], ea[2], M_rdd, Dn, cyc, true, false); - else - iTab[op] = mkSD(op, 'SUB', z2, M_rdd, Dn, ea[1], ea[2], cyc, false, true); - - iTab[op].f = I_SUB; + iTab[op] = mkI(op, "SUB", []); + iTab[op].p.Dn = Dn; + iTab[op].p.ea = ea; + iTab[op].p.zm = z2 == 4 ? 0x80000000 : (z2 == 2 ? 0x8000 : 0x80); + if (dir == 0) { + iTab[op].p.cyc = addCycs(z2 == 4 ? (m == M_rdd || m == M_imm ? [8,1,0]:[6,1,0]) : [4,1,0], getEACycs(ea, z2)); + iTab[op].f = z2 == 4 ? I_SUB_ED_32 : (z2 == 2 ? I_SUB_ED_16 : I_SUB_ED_8); + iTab[op].d = mkDiss(0, D_EA,ea, D_RDD,Dn, z2,0); + } else { + iTab[op].p.cyc = addCycs(z2 == 4 ? [12,1,2] : [8,1,1], getEACycs(ea, z2)); + iTab[op].f = z2 == 4 ? I_SUB_DE_32 : (z2 == 2 ? I_SUB_DE_16 : I_SUB_DE_8); + iTab[op].d = mkDiss(0, D_RDD,Dn, D_EA,ea, z2,0); + } cnt++; } else { - BUG.say('OP EXISTS SUB ' + op); + SAEF_error("cpu.mkITab() op exists SUB "+op); return false; } } @@ -4310,80 +7652,248 @@ function CPU() { } } } - //SUBA + //CMP { - var en = [M_rdd, M_rda, M_ria, M_ripo, M_ripr, M_rid, M_rii, M_pcid, M_pcii, M_absw, M_absl, M_imm]; - var z, z2, z3, An, mr, ea; - - for (z = 0; z < 2; z++) { - z2 = z == 0 ? 2 : 4; - z3 = z == 0 ? 3 : 7; - for (An = 0; An < 8; An++) { - for (mr = 0; mr < 64; mr++) { - ea = mkEA(mr, en, 0); - if (ea[0] != -1) { - op = (9 << 12) | (An << 9) | (z3 << 6) | ea[0]; - - if (iTab[op].op === -1) { - iTab[op] = mkSD(op, 'SUBA', z2, ea[1], ea[2], M_rda, An, z2 == 4 ? (ea[1] == M_rdd || ea[1] == M_imm ? [8,1,0] : [6,1,0]) : [8,1,0], true, false); - iTab[op].f = I_SUBA; - cnt++; - } else { - BUG.say('OP EXISTS SUBA ' + op); - return false; - } - } - } - } - } - } - //SUBI - { - var en = [M_rdd, M_ria, M_ripo, M_ripr, M_rid, M_rii, M_absw, M_absl]; - var z, z2, mr, ea; - - for (z = 0; z < 3; z++) { - z2 = z == 0 ? 1 : (z == 1 ? 2 : 4); - for (mr = 0; mr < 64; mr++) { - ea = mkEA(mr, en, 0); - if (ea[0] != -1) { - op = (4 << 8) | (z << 6) | ea[0]; - + for (var z = 0; z < 3; z++) { + var z2 = z == 0 ? 1 : (z == 1 ? 2 : 4); + for (var Dn = 0; Dn < 8; Dn++) { + for (var ea = 0; ea < 61; ea++) { + var m = getEAMode(ea); + if (m == M_rda && z == 0) continue; //An word and long only + op = (11 << 12) | (Dn << 9) | (z << 6) | ea; if (iTab[op].op === -1) { - iTab[op] = mkSD(op, 'SUBI', z2, M_imm, -1, ea[1], ea[2], ea[1] == M_rdd ? (z2 == 4 ? [16,3,0] : [8,2,0]) : (z2 == 4 ? [20,3,2] : [12,2,1]), false, ea[1] != M_rdd); - iTab[op].f = I_SUBI; + var cyc = z2 == 4 ? [6,1,0] : [4,1,0]; + if (!(m == M_rdd || m == M_rda)) cyc = addCycs(cyc, getEACycs(ea, z2)); + iTab[op] = mkI(op, "CMP", cyc); + iTab[op].p.Dn = Dn; + iTab[op].p.ea = ea; + iTab[op].f = z2 == 4 ? I_CMP_32 : (z2 == 2 ? I_CMP_16 : I_CMP_8); + iTab[op].d = mkDiss(0, D_EA,ea, D_RDD,Dn, z2,0); cnt++; } else { - BUG.say('OP EXISTS SUBI ' + op); + SAEF_error("cpu.mkITab() op exists CMP "+op); return false; } } } } } - //SUBQ + //CLR { - var en = [M_rdd, M_rda, M_ria, M_ripo, M_ripr, M_rid, M_rii, M_absw, M_absl]; - var z, z2, id, mr, ea, cyc; + var en = [M_rdd, M_ria, M_ripo, M_ripr, M_rid, M_rii, M_absw, M_absl]; + for (var z = 0; z < 3; z++) { + var z2 = z == 0 ? 1 : (z == 1 ? 2 : 4); + for (var ea = 0; ea < 61; ea++) { + if (isEA(ea, en)) { + op = (66 << 8) | (z << 6) | ea; + if (iTab[op].op === -1) { + var m = getEAMode(ea); + var cyc = m == M_rdd ? (z2 == 4 ? [6,1,0]:[4,1,0]) : (z2 == 4 ? [12,1,2]:[8,1,1]); + if (m == M_rdd) cyc = addCycs(cyc, getEACycs(ea, z2)); + iTab[op] = mkI(op, "CLR", cyc); + iTab[op].p.ea = ea; + iTab[op].f = z2 == 4 ? I_CLR_32 : (z2 == 2 ? I_CLR_16 : I_CLR_8); + iTab[op].d = mkDiss(0, false,false, D_EA,ea, z2,0); + cnt++; + } else { + SAEF_error("cpu.mkITab() op exists CLR "+op); + return false; + } + } + } + } + } + //NEG + { + var en = [M_rdd, M_ria, M_ripo, M_ripr, M_rid, M_rii, M_absw, M_absl]; + for (var z = 0; z < 3; z++) { + var z2 = z == 0 ? 1 : (z == 1 ? 2 : 4); + for (ea = 0; ea < 61; ea++) { + if (isEA(ea, en)) { + op = (68 << 8) | (z << 6) | ea; + if (iTab[op].op === -1) { + var m = getEAMode(ea); + var cyc = m == M_rdd ? (z2 == 4 ? [6,1,0]:[4,1,0]) : (z2 == 4 ? [12,1,2]:[8,1,1]); + iTab[op] = mkI(op, "NEG", cyc); + if (m == M_rdd) { + iTab[op].p.Dn = ea & 7; + iTab[op].f = z2 == 4 ? I_NEG_D_32 : (z2 == 2 ? I_NEG_D_16 : I_NEG_D_8); + } else { + iTab[op].p.ea = ea; + iTab[op].p.cyc = addCycs(iTab[op].p.cyc, getEACycs(ea, z2)); + iTab[op].f = z2 == 4 ? I_NEG_E_32 : (z2 == 2 ? I_NEG_E_16 : I_NEG_E_8); + } + iTab[op].d = mkDiss(0, false,false, D_EA,ea, z2,0); + cnt++; + } else { + SAEF_error("cpu.mkITab() op exists NEG "+op); + return false; + } + } + } + } + } + //MULS + { + var en = [M_rdd, M_ria, M_ripo, M_ripr, M_rid, M_rii, M_pcid, M_pcii, M_absw, M_absl, M_imm]; + for (var Dn = 0; Dn < 8; Dn++) { + for (var ea = 0; ea < 61; ea++) { + if (isEA(ea, en)) { + op = (12 << 12) | (Dn << 9) | (7 << 6) | ea; + if (iTab[op].op === -1) { + var avg = ((70 - 38) / 2 + 38) >>> 0; /* average */ + var cyc = getEAMode(ea) == M_rdd ? [70,1,0] : addCycs([70,1,0], getEACycs(ea, z2)); + iTab[op] = mkI(op, "MULS", cyc); + iTab[op].p.Dn = Dn; + iTab[op].p.ea = ea; + iTab[op].f = I_MULS; + iTab[op].d = mkDiss(0, D_EA,ea, D_RDD,Dn, 2,0); + cnt++; + } else { + SAEF_error("cpu.mkITab() op exists MULS "+op); + return false; + } + } + } + } + } + //MULU + { + var en = [M_rdd, M_ria, M_ripo, M_ripr, M_rid, M_rii, M_pcid, M_pcii, M_absw, M_absl, M_imm]; + for (var Dn = 0; Dn < 8; Dn++) { + for (var ea = 0; ea < 61; ea++) { + if (isEA(ea, en)) { + op = (12 << 12) | (Dn << 9) | (3 << 6) | ea; + if (iTab[op].op === -1) { + var avg = ((70 - 38) / 2 + 38) >>> 0; /* average */ + var cyc = getEAMode(ea) == M_rdd ? [avg,1,0] : addCycs([avg,1,0], getEACycs(ea, z2)); + iTab[op] = mkI(op, "MULU", cyc); + iTab[op].p.Dn = Dn; + iTab[op].p.ea = ea; + iTab[op].f = I_MULU; + iTab[op].d = mkDiss(0, D_EA,ea, D_RDD,Dn, 2,0); + cnt++; + } else { + SAEF_error("cpu.mkITab() op exists MULU "+op); + return false; + } + } + } + } + } + //MULx + if (model >= 68020) { + var en = [M_rdd, M_ria, M_ripo, M_ripr, M_rid, M_rii, M_pcid, M_pcii, M_absw, M_absl, M_imm]; + for (var ea = 0; ea < 61; ea++) { + if (isEA(ea, en)) { + op = (304 << 6) | ea; + if (iTab[op].op === -1) { + iTab[op] = mkI(op, "MULx", [40,0,0]); //FIXME cycles + iTab[op].p.ea = ea; + iTab[op].f = I_MULx; + iTab[op].d = mkDiss(1, D_EA,ea, D_EXT_MUL64,0, 4,0); //FIXME + cnt++; + } else { + SAEF_error("cpu.mkITab() op exists MULx "+op); + return false; + } + } + } + } + //DIVS + { + var en = [M_rdd, M_ria, M_ripo, M_ripr, M_rid, M_rii, M_pcid, M_pcii, M_absw, M_absl, M_imm]; + for (var Dn = 0; Dn < 8; Dn++) { + for (var ea = 0; ea < 61; ea++) { + if (isEA(ea, en)) { + op = (8 << 12) | (Dn << 9) | (7 << 6) | ea; + if (iTab[op].op === -1) { + var avg = (156 - (156 - 120) / 2) >>> 0; /* average */ + var cyc = getEAMode(ea) == M_rdd ? [avg,1,0] : addCycs([avg,1,0], getEACycs(ea, z2)); + iTab[op] = mkI(op, "DIVS", cyc); + iTab[op].p.Dn = Dn; + iTab[op].p.ea = ea; + iTab[op].f = I_DIVS; + iTab[op].d = mkDiss(0, D_EA,ea, D_RDD,Dn, 2,0); + cnt++; + } else { + SAEF_error("cpu.mkITab() op exists DIVS "+op); + return false; + } + } + } + } + } + //DIVU + { + var en = [M_rdd, M_ria, M_ripo, M_ripr, M_rid, M_rii, M_pcid, M_pcii, M_absw, M_absl, M_imm]; + for (var Dn = 0; Dn < 8; Dn++) { + for (var ea = 0; ea < 61; ea++) { + if (isEA(ea, en)) { + op = (8 << 12) | (Dn << 9) | (3 << 6) | ea; + if (iTab[op].op === -1) { + var avg = (136 - (136 - 76) / 2) >>> 0; /* average */ + var cyc = getEAMode(ea) == M_rdd ? [avg,1,0] : addCycs([avg,1,0], getEACycs(ea, z2)); + iTab[op] = mkI(op, "DIVU", cyc); + iTab[op].p.Dn = Dn; + iTab[op].p.ea = ea; + iTab[op].f = I_DIVU; + iTab[op].d = mkDiss(0, D_EA,ea, D_RDD,Dn, 2,0); + cnt++; + } else { + SAEF_error("cpu.mkITab() op exists DIVU "+op); + return false; + } + } + } + } + } + //DIVx + if (model >= 68020) { + var en = [M_rdd, M_ria, M_ripo, M_ripr, M_rid, M_rii, M_pcid, M_pcii, M_absw, M_absl, M_imm]; + for (var ea = 0; ea < 61; ea++) { + if (isEA(ea, en)) { + op = (305 << 6) | ea; + if (iTab[op].op === -1) { + iTab[op] = mkI(op, "DIVx", [70,0,0]); //FIXME cycles + iTab[op].p.ea = ea; + iTab[op].f = I_DIVx; + iTab[op].d = mkDiss(1, D_EA,ea, D_EXT_DIV64,0, 4,0); //FIXME + cnt++; + } else { + SAEF_error("cpu.mkITab() op exists DIVx "+op); + return false; + } + } + } + } - for (z = 0; z < 3; z++) { - z2 = z == 0 ? 1 : (z == 1 ? 2 : 4); - for (id = 0; id < 8; id++) { - for (mr = 0; mr < 64; mr++) { - ea = mkEA(mr, en, 0); - if (ea[0] != -1) { - if (ea[1] == M_rda && z == 0) continue; //An word and long only - - op = (5 << 12) | (id << 9) | (1 << 8) | (z << 6) | ea[0]; - cyc = ea[1] == M_rda ? [8,1,0] : (ea[1] == M_rdd ? (z2 == 4 ? [8,1,0] : [4,1,0]) : (z2 == 4 ? [12,1,2] : [8,1,1])); + /*-----------------------------------------------------------------------*/ + /* Integer - Extended */ + //ADDX + { + for (var z = 0; z < 3; z++) { + var z2 = z == 0 ? 1 : (z == 1 ? 2 : 4); + for (var rm = 0; rm < 2; rm++) { + for (var Rx = 0; Rx < 8; Rx++) { + for (var Ry = 0; Ry < 8; Ry++) { + op = (13 << 12) | (Rx << 9) | (1 << 8) | (z << 6) | (rm << 3) | Ry; if (iTab[op].op === -1) { - iTab[op] = mkSD(op, 'SUBQ', z2, M_imm, id == 0 ? 8 : id, ea[1], ea[2], cyc, false, ea[1] != M_rdd && ea[1] != M_rda); - //iTab[op].f = I_SUBQ; - iTab[op].f = ea[1] != M_rda ? I_SUBQ : I_SUBQA; + var cyc = rm == 0 ? (z2 == 4 ? [8,1,0] : [4,1,0]) : (z2 == 4 ? [30,5,2] : [18,3,1]); + iTab[op] = mkI(op, "ADDX", cyc); + iTab[op].p.Rx = Rx; + iTab[op].p.Ry = Ry; + if (rm == 0) { + iTab[op].f = z2 == 4 ? I_ADDX_D_32 : (z2 == 2 ? I_ADDX_D_16 : I_ADDX_D_8); + iTab[op].d = mkDiss(0, D_RDD,Ry, D_RDD,Rx, z2,0); + } else { + iTab[op].f = z2 == 4 ? I_ADDX_M_32 : (z2 == 2 ? I_ADDX_M_16 : I_ADDX_M_8); + iTab[op].d = mkDiss(0, D_RIPR,Ry, D_RIPR,Rx, z2,0); + } cnt++; } else { - BUG.say('OP EXISTS SUBQ ' + op); + SAEF_error("cpu.mkITab() op exists ADDX "+op); return false; } } @@ -4393,25 +7903,27 @@ function CPU() { } //SUBX { - var z, z2, rm, Rx, Ry; - - for (z = 0; z < 3; z++) { - z2 = z == 0 ? 1 : (z == 1 ? 2 : 4); - for (rm = 0; rm < 2; rm++) { - for (Rx = 0; Rx < 8; Rx++) { - for (Ry = 0; Ry < 8; Ry++) { + for (var z = 0; z < 3; z++) { + var z2 = z == 0 ? 1 : (z == 1 ? 2 : 4); + for (var rm = 0; rm < 2; rm++) { + for (var Rx = 0; Rx < 8; Rx++) { + for (var Ry = 0; Ry < 8; Ry++) { op = (9 << 12) | (Ry << 9) | (1 << 8) | (z << 6) | (rm << 3) | Rx; - if (iTab[op].op === -1) { - if (rm == 0) - iTab[op] = mkSD(op, 'SUBX', z2, M_rdd, Rx, M_rdd, Ry, z2 == 4 ? [8,1,0] : [4,1,0], false, false); - else - iTab[op] = mkSD(op, 'SUBX', z2, M_ripr, Rx, M_ripr, Ry, z2 == 4 ? [30,5,2] : [18,1,0], false, false); - - iTab[op].f = I_SUBX; + var cyc = rm == 0 ? (z2 == 4 ? [8,1,0] : [4,1,0]) : (z2 == 4 ? [30,5,2] : [18,3,1]); + iTab[op] = mkI(op, "SUBX", cyc); + iTab[op].p.Rx = Rx; + iTab[op].p.Ry = Ry; + if (rm == 0) { + iTab[op].f = z2 == 4 ? I_SUBX_D_32 : (z2 == 2 ? I_SUBX_D_16 : I_SUBX_D_8); + iTab[op].d = mkDiss(0, D_RDD,Rx, D_RDD,Ry, z2,0); + } else { + iTab[op].f = z2 == 4 ? I_SUBX_M_32 : (z2 == 2 ? I_SUBX_M_16 : I_SUBX_M_8); + iTab[op].d = mkDiss(0, D_RIPR,Rx, D_RIPR,Ry, z2,0); + } cnt++; } else { - BUG.say('OP EXISTS SUBX ' + op + ' ' + iTab[op].mn + ' ' + iTab[op].p.s.r + ' ' + iTab[op].p.d.r); + SAEF_error("cpu.mkITab() op exists SUBX "+op); return false; } } @@ -4419,19 +7931,1997 @@ function CPU() { } } } - //SWAP + //NEGX { - var Dn; + var en = [M_rdd, M_ria, M_ripo, M_ripr, M_rid, M_rii, M_absw, M_absl]; + for (var z = 0; z < 3; z++) { + var z2 = z == 0 ? 1 : (z == 1 ? 2 : 4); + for (var ea = 0; ea < 61; ea++) { + if (isEA(ea, en)) { + op = (64 << 8) | (z << 6) | ea; + if (iTab[op].op === -1) { + var m = getEAMode(ea); + var cyc = m == M_rdd ? (z2 == 4 ? [6,1,0]:[4,1,0]) : (z2 == 4 ? [12,1,2]:[8,1,1]); + iTab[op] = mkI(op, "NEGX", cyc); + if (m == M_rdd) { + iTab[op].p.Dn = ea & 7; + iTab[op].f = z2 == 4 ? I_NEGX_D_32 : (z2 == 2 ? I_NEGX_D_16 : I_NEGX_D_8); + } else { + iTab[op].p.ea = ea; + iTab[op].p.cyc = addCycs(iTab[op].p.cyc, getEACycs(ea, z2)); + iTab[op].f = z2 == 4 ? I_NEGX_E_32 : (z2 == 2 ? I_NEGX_E_16 : I_NEGX_E_8); + } + iTab[op].d = mkDiss(0, false,false, D_EA,ea, z2,0); + cnt++; + } else { + SAEF_error("cpu.mkITab() op exists NEGX "+op); + return false; + } + } + } + } + } - for (Dn = 0; Dn < 8; Dn++) { - op = (2312 << 3) | Dn; + /*-----------------------------------------------------------------------*/ + /* Integer - Address */ + //ADDA + { + for (var z = 1; z < 3; z++) { + var z2 = z == 1 ? 2 : 4; + var z3 = z == 1 ? 3 : 7; + for (var An = 0; An < 8; An++) { + for (var ea = 0; ea < 61; ea++) { + op = (13 << 12) | (An << 9) | (z3 << 6) | ea; + if (iTab[op].op === -1) { + var cyc = z2 == 4 ? (m == M_rdd || m == M_rda || m == M_imm ? [8,1,0] : [6,1,0]) : [8,1,0]; + if (!(m == M_rdd || m == M_rda)) cyc = addCycs(cyc, getEACycs(ea, z2)); + iTab[op] = mkI(op, "ADDA", cyc); + iTab[op].p.An = An; + iTab[op].p.ea = ea; + iTab[op].f = z2 == 4 ? I_ADDA_32 : I_ADDA_16; + iTab[op].d = mkDiss(0, D_EA,ea, D_RDA,An, z2,0); + cnt++; + } else { + SAEF_error("cpu.mkITab() op exists ADDA "+op); + return false; + } + } + } + } + } + //SUBA + { + for (var z = 1; z < 3; z++) { + var z2 = z == 1 ? 2 : 4; + var z3 = z == 1 ? 3 : 7; + for (var An = 0; An < 8; An++) { + for (var ea = 0; ea < 61; ea++) { + op = (9 << 12) | (An << 9) | (z3 << 6) | ea; + if (iTab[op].op === -1) { + var cyc = z2 == 4 ? (m == M_rdd || m == M_rda || m == M_imm ? [8,1,0] : [6,1,0]) : [8,1,0]; + if (!(m == M_rdd || m == M_rda)) cyc = addCycs(cyc, getEACycs(ea, z2)); + iTab[op] = mkI(op, "SUBA", cyc); + iTab[op].p.An = An; + iTab[op].p.ea = ea; + iTab[op].f = z2 == 4 ? I_SUBA_32 : I_SUBA_16; + iTab[op].d = mkDiss(0, D_EA,ea, D_RDA,An, z2,0); + cnt++; + } else { + SAEF_error("cpu.mkITab() op exists SUBA "+op); + return false; + } + } + } + } + } + //CMPA + { + for (var z = 1; z < 3; z++) { + var z2 = z == 1 ? 2 : 4; + var z3 = z == 1 ? 3 : 7; + for (var An = 0; An < 8; An++) { + for (var ea = 0; ea < 61; ea++) { + op = (11 << 12) | (An << 9) | (z3 << 6) | ea; + if (iTab[op].op === -1) { + var cyc = [6,1,0]; + if (!(m == M_rdd || m == M_rda)) cyc = addCycs(cyc, getEACycs(ea, z2)); + iTab[op] = mkI(op, "CMPA", cyc); + iTab[op].p.An = An; + iTab[op].p.ea = ea; + iTab[op].f = z2 == 4 ? I_CMPA_32 : I_CMPA_16; + iTab[op].d = mkDiss(0, D_EA,ea, D_RDA,An, z2,0); + cnt++; + } else { + SAEF_error("cpu.mkITab() op exists CMPA "+op); + return false; + } + } + } + } + } + + /*-----------------------------------------------------------------------*/ + /* Integer - Immediate */ + + //ADDI + { + var en = [M_rdd, M_ria, M_ripo, M_ripr, M_rid, M_rii, M_absw, M_absl]; + for (var z = 0; z < 3; z++) { + var z2 = z == 0 ? 1 : (z == 1 ? 2 : 4); + for (var ea = 0; ea < 61; ea++) { + if (isEA(ea, en)) { + op = (6 << 8) | (z << 6) | ea; + if (iTab[op].op === -1) { + var m = getEAMode(ea); + var cyc = m == M_rdd ? (z2 == 4 ? [16,3,0]:[8,2,0]) : (z2 == 4 ? [20,3,2]:[12,2,1]); + iTab[op] = mkI(op, "ADDI", cyc); + if (m == M_rdd) { + iTab[op].p.Dn = ea & 7; + iTab[op].f = z2 == 4 ? I_ADDI_D_32 : (z2 == 2 ? I_ADDI_D_16 : I_ADDI_D_8); + } else { + iTab[op].p.ea = ea; + iTab[op].p.cyc = addCycs(iTab[op].p.cyc, getEACycs(ea, z2)); + iTab[op].f = z2 == 4 ? I_ADDI_E_32 : (z2 == 2 ? I_ADDI_E_16 : I_ADDI_E_8); + } + iTab[op].d = mkDiss(0, D_IME,z2 == 4 ? 2 : 1, D_EA,ea, z2,0); + cnt++; + } else { + SAEF_error("cpu.mkITab() op exists ADDI "+op); + return false; + } + } + } + } + } + //SUBI + { + var en = [M_rdd, M_ria, M_ripo, M_ripr, M_rid, M_rii, M_absw, M_absl]; + for (var z = 0; z < 3; z++) { + var z2 = z == 0 ? 1 : (z == 1 ? 2 : 4); + for (var ea = 0; ea < 61; ea++) { + if (isEA(ea, en)) { + op = (4 << 8) | (z << 6) | ea; + if (iTab[op].op === -1) { + var m = getEAMode(ea); + var cyc = m == M_rdd ? (z2 == 4 ? [16,3,0]:[8,2,0]) : (z2 == 4 ? [20,3,2]:[12,2,1]); + iTab[op] = mkI(op, "SUBI", cyc); + if (m == M_rdd) { + iTab[op].p.Dn = ea & 7; + iTab[op].f = z2 == 4 ? I_SUBI_D_32 : (z2 == 2 ? I_SUBI_D_16 : I_SUBI_D_8); + } else { + iTab[op].p.ea = ea; + iTab[op].p.cyc = addCycs(iTab[op].p.cyc, getEACycs(ea, z2)); + iTab[op].f = z2 == 4 ? I_SUBI_E_32 : (z2 == 2 ? I_SUBI_E_16 : I_SUBI_E_8); + } + iTab[op].d = mkDiss(0, D_IME,z2 == 4 ? 2 : 1, D_EA,ea, z2,0); + cnt++; + } else { + SAEF_error("cpu.mkITab() op exists SUBI "+op); + return false; + } + } + } + } + } + //CMPI + { + var en = [M_rdd, M_ria, M_ripo, M_ripr, M_rid, M_rii, M_absw, M_absl]; + if (model >= 68020) en.push(M_pcid, M_pcii); + for (var z = 0; z < 3; z++) { + var z2 = z == 0 ? 1 : (z == 1 ? 2 : 4); + for (var ea = 0; ea < 61; ea++) { + if (isEA(ea, en)) { + op = (12 << 8) | (z << 6) | ea; + if (iTab[op].op === -1) { + var m = getEAMode(ea); + var cyc = m == M_rdd ? (z2 == 4 ? [14,3,0]:[8,2,0]) : (z2 == 4 ? [12,3,0]:[8,2,0]); + if (m != M_rdd) cyc = addCycs(cyc, getEACycs(ea, z2)); + iTab[op] = mkI(op, "CMPI", cyc); + iTab[op].p.ea = ea; + iTab[op].f = z2 == 4 ? I_CMPI_32 : (z2 == 2 ? I_CMPI_16 : I_CMPI_8); + iTab[op].d = mkDiss(0, D_IME,z2 == 4 ? 2 : 1, D_EA,ea, z2,0); + cnt++; + } else { + SAEF_error("cpu.mkITab() op exists CMPI "+op); + return false; + } + } + } + } + } + + /*-----------------------------------------------------------------------*/ + /* Integer - Quick */ + + //ADDQ + { + var en = [M_rdd, M_rda, M_ria, M_ripo, M_ripr, M_rid, M_rii, M_absw, M_absl]; + for (var z = 0; z < 3; z++) { + var z2 = z == 0 ? 1 : (z == 1 ? 2 : 4); + for (var id = 0; id < 8; id++) { + for (var ea = 0; ea < 61; ea++) { + if (isEA(ea, en)) { + var m = getEAMode(ea); + if (m == M_rda && z == 0) continue; //An word and long only + op = (5 << 12) | (id << 9) | (z << 6) | ea; + if (iTab[op].op === -1) { + var cyc = m == M_rda ? [8,1,0] : (m == M_rdd ? (z2 == 4 ? [8,1,0]:[4,1,0]) : (z2 == 4 ? [12,1,2]:[8,1,1])); + iTab[op] = mkI(op, "ADDQ", cyc); + iTab[op].p.data = id == 0 ? 8 : id; + if (m == M_rdd) { + iTab[op].p.Dn = ea & 7; + iTab[op].f = z2 == 4 ? I_ADDQ_D_32 : (z2 == 2 ? I_ADDQ_D_16 : I_ADDQ_D_8); + } + else if (m == M_rda) { + iTab[op].p.An = ea & 7; + iTab[op].f = I_ADDQ_A_32; + } + else { + iTab[op].p.ea = ea; + iTab[op].p.cyc = addCycs(iTab[op].p.cyc, getEACycs(ea, z2)); + iTab[op].f = z2 == 4 ? I_ADDQ_E_32 : (z2 == 2 ? I_ADDQ_E_16 : I_ADDQ_E_8); + } + iTab[op].d = mkDiss(0, D_IMD,id == 0 ? 8 : id, D_EA,ea, z2,0); + cnt++; + } else { + SAEF_error("cpu.mkITab() op exists ADDQ " + op); + return false; + } + } + } + } + } + } + //SUBQ + { + var en = [M_rdd, M_rda, M_ria, M_ripo, M_ripr, M_rid, M_rii, M_absw, M_absl]; + for (var z = 0; z < 3; z++) { + var z2 = z == 0 ? 1 : (z == 1 ? 2 : 4); + for (var id = 0; id < 8; id++) { + for (var ea = 0; ea < 61; ea++) { + if (isEA(ea, en)) { + var m = getEAMode(ea); + if (m == M_rda && z == 0) continue; //An word and long only + op = (5 << 12) | (id << 9) | (1 << 8) | (z << 6) | ea; + if (iTab[op].op === -1) { + var cyc = m == M_rda ? [8,1,0] : (m == M_rdd ? (z2 == 4 ? [8,1,0]:[4,1,0]) : (z2 == 4 ? [12,1,2]:[8,1,1])); + iTab[op] = mkI(op, "SUBQ", cyc); + iTab[op].p.data = id == 0 ? 8 : id; + if (m == M_rdd) { + iTab[op].p.Dn = ea & 7; + iTab[op].f = z2 == 4 ? I_SUBQ_D_32 : (z2 == 2 ? I_SUBQ_D_16 : I_SUBQ_D_8); + } + else if (m == M_rda) { + iTab[op].p.An = ea & 7; + iTab[op].f = I_SUBQ_A_32; + } + else { + iTab[op].p.ea = ea; + iTab[op].p.cyc = addCycs(iTab[op].p.cyc, getEACycs(ea, z2)); + iTab[op].f = z2 == 4 ? I_SUBQ_E_32 : (z2 == 2 ? I_SUBQ_E_16 : I_SUBQ_E_8); + } + iTab[op].d = mkDiss(0, D_IMD,id == 0 ? 8 : id, D_EA,ea, z2,0); + cnt++; + } else { + SAEF_error("cpu.mkITab() op exists SUBQ " + op); + return false; + } + } + } + } + } + } + + /*-----------------------------------------------------------------------*/ + /* Integer - Misc */ + + //CMPM + { + for (var z = 0; z < 3; z++) { + var z2 = z == 0 ? 1 : (z == 1 ? 2 : 4); + for (var Ax = 0; Ax < 8; Ax++) { + for (var Ay = 0; Ay < 8; Ay++) { + op = (11 << 12) | (Ax << 9) | (1 << 8) | (z << 6) | (1 << 3) | Ay; + if (iTab[op].op === -1) { + iTab[op] = mkI(op, "CMPM", z2 == 4 ? [20,5,0] : [12,3,0]); + iTab[op].p.Ax = Ax; + iTab[op].p.Ay = Ay; + iTab[op].f = z2 == 4 ? I_CMPM_32 : (z2 == 2 ? I_CMPM_16 : I_CMPM_8); + iTab[op].d = mkDiss(0, D_RIPO,Ay, D_RIPO,Ax, z2,0); + cnt++; + } else { + SAEF_error("cpu.mkITab() op exists CMPM "+op); + return false; + } + } + } + } + } + //EXT + { + for (var z = 1; z < 3; z++) { + var z2 = z == 1 ? 2 : 4; + var opm = z == 1 ? 2 : 3; + for (var Dn = 0; Dn < 8; Dn++) { + op = (36 << 9) | (opm << 6) | Dn; + if (iTab[op].op === -1) { + iTab[op] = mkI(op, "EXT", [4,1,0]); + iTab[op].p.Dn = Dn; + iTab[op].f = z2 == 4 ? I_EXT_32 : I_EXT_16; + iTab[op].d = mkDiss(0, false,false, D_RDD,Dn, z2,0); + cnt++; + } else { + SAEF_error("cpu.mkITab() op exists EXT "+op); + return false; + } + } + } + } + //EXTB + if (model >= 68020) { + for (var Dn = 0; Dn < 8; Dn++) { + op = (36 << 9) | (7 << 6) | Dn; if (iTab[op].op === -1) { - iTab[op] = mkD(op, 'SWAP', 2, M_rdd, Dn, [4,1,0], false); - iTab[op].f = I_SWAP; + iTab[op] = mkI(op, "EXTB", [4,1,0]); + iTab[op].p.Dn = Dn; + iTab[op].f = I_EXTB; + iTab[op].d = mkDiss(0, false,false, D_RDD,Dn, 4,0); cnt++; } else { - BUG.say('OP EXISTS SWAP ' + op); + SAEF_error("cpu.mkITab() op exists EXTB "+op); + return false; + } + } + } + + /*-----------------------------------------------------------------------*/ + /* Logical */ + + //AND + { + var en0 = [M_rdd, M_ria, M_ripo, M_ripr, M_rid, M_rii, M_pcid, M_pcii, M_absw, M_absl, M_imm]; + var en1 = [M_ria, M_ripo, M_ripr, M_rid, M_rii, M_absw, M_absl]; + for (var z = 0; z < 3; z++) { + var z2 = z == 0 ? 1 : (z == 1 ? 2 : 4); + for (var dir = 0; dir < 2; dir++) { + for (var Dn = 0; Dn < 8; Dn++) { + for (var ea = 0; ea < 61; ea++) { + if (isEA(ea, dir == 0 ? en0 : en1)) { + op = (12 << 12) | (Dn << 9) | (dir << 8) | (z << 6) | ea; + if (iTab[op].op === -1) { + iTab[op] = mkI(op, "AND", []); + iTab[op].p.Dn = Dn; + iTab[op].p.ea = ea; + iTab[op].p.zm = z2 == 4 ? 0x80000000 : (z2 == 2 ? 0x8000 : 0x80); + if (dir == 0) { + var m = getEAMode(ea); + iTab[op].p.cyc = addCycs(z2 == 4 ? (m == M_rdd || m == M_imm ? [8,1,0]:[6,1,0]) : [4,1,0], getEACycs(ea, z2)); + iTab[op].f = z2 == 4 ? I_AND_D_32 : (z2 == 2 ? I_AND_D_16 : I_AND_D_8); + iTab[op].d = mkDiss(0, D_EA,ea, D_RDD,Dn, z2,0); + } else { + iTab[op].p.cyc = addCycs(z2 == 4 ? [12,1,2] : [8,1,1], getEACycs(ea, z2)); + iTab[op].f = z2 == 4 ? I_AND_E_32 : (z2 == 2 ? I_AND_E_16 : I_AND_E_8); + iTab[op].d = mkDiss(0, D_RDD,Dn, D_EA,ea, z2,0); + } + cnt++; + } else { + SAEF_error("cpu.mkITab() op exists AND "+op); + return false; + } + } + } + } + } + } + } + //EOR + { + var en = [M_rdd, M_ria, M_ripo, M_ripr, M_rid, M_rii, M_absw, M_absl]; + for (var z = 0; z < 3; z++) { + var z2 = z == 0 ? 1 : (z == 1 ? 2 : 4); + var z3 = z == 0 ? 4 : (z == 1 ? 5 : 6); + for (var Dn = 0; Dn < 8; Dn++) { + for (var ea = 0; ea < 61; ea++) { + if (isEA(ea, en)) { + op = (11 << 12) | (Dn << 9) | (z3 << 6) | ea; + if (iTab[op].op === -1) { + var m = getEAMode(ea); + iTab[op] = mkI(op, "EOR", z2 == 4 ? [8,1,0] : [4,1,0]); + iTab[op].p.Dn = Dn; + iTab[op].p.zm = z2 == 4 ? 0x80000000 : (z2 == 2 ? 0x8000 : 0x80); + if (m == M_rdd) { + iTab[op].p.Dd = ea & 7; + iTab[op].f = z2 == 4 ? I_EOR_D_32 : (z2 == 2 ? I_EOR_D_16 : I_EOR_D_8); + } else { + iTab[op].p.ea = ea; + iTab[op].p.cyc = addCycs(iTab[op].p.cyc, getEACycs(ea, z2)); + iTab[op].f = z2 == 4 ? I_EOR_E_32 : (z2 == 2 ? I_EOR_E_16 : I_EOR_E_8); + } + iTab[op].d = mkDiss(0, D_RDD,Dn, D_EA,ea, z2,0); + cnt++; + } else { + SAEF_error("cpu.mkITab() op exists EOR "+op); + return false; + } + } + } + } + } + } + //OR + { + var en0 = [M_rdd, M_ria, M_ripo, M_ripr, M_rid, M_rii, M_pcid, M_pcii, M_absw, M_absl, M_imm]; + var en1 = [M_ria, M_ripo, M_ripr, M_rid, M_rii, M_absw, M_absl]; + for (var z = 0; z < 3; z++) { + var z2 = z == 0 ? 1 : (z == 1 ? 2 : 4); + for (var dir = 0; dir < 2; dir++) { + for (var Dn = 0; Dn < 8; Dn++) { + for (var ea = 0; ea < 61; ea++) { + if (isEA(ea, dir == 0 ? en0 : en1)) { + op = (8 << 12) | (Dn << 9) | (dir << 8) | (z << 6) | ea; + if (iTab[op].op === -1) { + iTab[op] = mkI(op, "OR", []); + iTab[op].p.Dn = Dn; + iTab[op].p.ea = ea; + iTab[op].p.zm = z2 == 4 ? 0x80000000 : (z2 == 2 ? 0x8000 : 0x80); + if (dir == 0) { + var m = getEAMode(ea); + iTab[op].p.cyc = addCycs(z2 == 4 ? (m == M_rdd || m == M_imm ? [8,1,0]:[6,1,0]) : [4,1,0], getEACycs(ea, z2)); + iTab[op].f = z2 == 4 ? I_OR_D_32 : (z2 == 2 ? I_OR_D_16 : I_OR_D_8); + iTab[op].d = mkDiss(0, D_EA,ea, D_RDD,Dn, z2,0); + } else { + iTab[op].p.cyc = addCycs(z2 == 4 ? [12,1,2] : [8,1,1], getEACycs(ea, z2)); + iTab[op].f = z2 == 4 ? I_OR_E_32 : (z2 == 2 ? I_OR_E_16 : I_OR_E_8); + iTab[op].d = mkDiss(0, D_RDD,Dn, D_EA,ea, z2,0); + } + cnt++; + } else { + SAEF_error("cpu.mkITab() op exists OR " + op); + return false; + } + } + } + } + } + } + } + //NOT + { + var en = [M_rdd, M_ria, M_ripo, M_ripr, M_rid, M_rii, M_absw, M_absl]; + for (var z = 0; z < 3; z++) { + var z2 = z == 0 ? 1 : (z == 1 ? 2 : 4); + for (var ea = 0; ea < 61; ea++) { + if (isEA(ea, en)) { + op = (70 << 8) | (z << 6) | ea; + if (iTab[op].op === -1) { + var m = getEAMode(ea); + var cyc = m == M_rdd ? (z2 == 4 ? [6,1,0]:[4,1,0]) : (z2 == 4 ? [12,1,2]:[8,1,1]); + iTab[op] = mkI(op, "NOT", cyc); + if (m == M_rdd) { + iTab[op].p.Dn = ea & 7; + iTab[op].f = z2 == 4 ? I_NOT_D_32 : (z2 == 2 ? I_NOT_D_16 : I_NOT_D_8); + } else { + iTab[op].p.ea = ea; + iTab[op].p.cyc = addCycs(iTab[op].p.cyc, getEACycs(ea, z2)); + iTab[op].f = z2 == 4 ? I_NOT_E_32 : (z2 == 2 ? I_NOT_E_16 : I_NOT_E_8); + } + iTab[op].p.m = z2 == 4 ? 0xffffffff : (z2 == 2 ? 0xffff : 0xff); + iTab[op].p.zm = z2 == 4 ? 0x80000000 : (z2 == 2 ? 0x8000 : 0x80); + iTab[op].d = mkDiss(0, false,false, D_EA,ea, z2,0); + cnt++; + } else { + SAEF_error("cpu.mkITab() op exists NOT "+op); + return false; + } + } + } + } + } + //ANDI + { + var en = [M_rdd, M_ria, M_ripo, M_ripr, M_rid, M_rii, M_absw, M_absl]; + for (var z = 0; z < 3; z++) { + var z2 = z == 0 ? 1 : (z == 1 ? 2 : 4); + for (var ea = 0; ea < 61; ea++) { + if (isEA(ea, en)) { + op = (2 << 8) | (z << 6) | ea; + if (iTab[op].op === -1) { + var m = getEAMode(ea); + var cyc = m == M_rdd ? (z2 == 4 ? [16,3,0]:[8,2,0]) : (z2 == 4 ? [20,3,1]:[12,2,1]) + iTab[op] = mkI(op, "ANDI", cyc); + if (m == M_rdd) { + iTab[op].p.Dn = ea & 7; + iTab[op].f = z2 == 4 ? I_ANDI_D_32 : (z2 == 2 ? I_ANDI_D_16 : I_ANDI_D_8); + } else { + iTab[op].p.ea = ea; + iTab[op].p.cyc = addCycs(iTab[op].p.cyc, getEACycs(ea, z2)); + iTab[op].f = z2 == 4 ? I_ANDI_E_32 : (z2 == 2 ? I_ANDI_E_16 : I_ANDI_E_8); + } + iTab[op].p.zm = z2 == 4 ? 0x80000000 : (z2 == 2 ? 0x8000 : 0x80); + iTab[op].d = mkDiss(0, D_IME,z2 == 4 ? 2 : 1, D_EA,ea, z2,0); + cnt++; + } else { + SAEF_error("cpu.mkITab() op exists ANDI "+op); + return false; + } + } + } + } + } + //EORI + { + var en = [M_rdd, M_ria, M_ripo, M_ripr, M_rid, M_rii, M_absw, M_absl]; + for (var z = 0; z < 3; z++) { + var z2 = z == 0 ? 1 : (z == 1 ? 2 : 4); + for (var ea = 0; ea < 61; ea++) { + if (isEA(ea, en)) { + op = (10 << 8) | (z << 6) | ea; + if (iTab[op].op === -1) { + var m = getEAMode(ea); + var cyc = m == M_rdd ? (z2 == 4 ? [16,3,0]:[8,2,0]) : (z2 == 4 ? [20,3,1]:[12,2,1]) + iTab[op] = mkI(op, "EORI", cyc); + if (m == M_rdd) { + iTab[op].p.Dn = ea & 7; + iTab[op].f = z2 == 4 ? I_EORI_D_32 : (z2 == 2 ? I_EORI_D_16 : I_EORI_D_8); + } else { + iTab[op].p.ea = ea; + iTab[op].p.cyc = addCycs(iTab[op].p.cyc, getEACycs(ea, z2)); + iTab[op].f = z2 == 4 ? I_EORI_E_32 : (z2 == 2 ? I_EORI_E_16 : I_EORI_E_8); + } + iTab[op].p.zm = z2 == 4 ? 0x80000000 : (z2 == 2 ? 0x8000 : 0x80); + iTab[op].d = mkDiss(0, D_IME,z2 == 4 ? 2 : 1, D_EA,ea, z2,0); + cnt++; + } else { + SAEF_error("cpu.mkITab() op exists EORI "+op); + return false; + } + } + } + } + } + //ORI + { + var en = [M_rdd, M_ria, M_ripo, M_ripr, M_rid, M_rii, M_absw, M_absl]; + for (var z = 0; z < 3; z++) { + var z2 = z == 0 ? 1 : (z == 1 ? 2 : 4); + for (var ea = 0; ea < 61; ea++) { + if (isEA(ea, en)) { + op = (z << 6) | ea; + if (iTab[op].op === -1) { + var m = getEAMode(ea); + var cyc = m == M_rdd ? (z2 == 4 ? [16,3,0]:[8,2,0]) : (z2 == 4 ? [20,3,1]:[12,2,1]) + iTab[op] = mkI(op, "ORI", cyc); + if (m == M_rdd) { + iTab[op].p.Dn = ea & 7; + iTab[op].f = z2 == 4 ? I_ORI_D_32 : (z2 == 2 ? I_ORI_D_16 : I_ORI_D_8); + } else { + iTab[op].p.ea = ea; + iTab[op].p.cyc = addCycs(iTab[op].p.cyc, getEACycs(ea, z2)); + iTab[op].f = z2 == 4 ? I_ORI_E_32 : (z2 == 2 ? I_ORI_E_16 : I_ORI_E_8); + } + iTab[op].p.zm = z2 == 4 ? 0x80000000 : (z2 == 2 ? 0x8000 : 0x80); + iTab[op].d = mkDiss(0, D_IME,z2 == 4 ? 2 : 1, D_EA,ea, z2,0); + cnt++; + } else { + SAEF_error("cpu.mkITab() op exists ORI "+op); + return false; + } + } + } + } + } + + /*-----------------------------------------------------------------------*/ + /* Shift and Rotate */ + + //ASL,ASR + { + for (var z = 0; z < 3; z++) { + var z2 = z == 0 ? 1 : (z == 1 ? 2 : 4); + for (var dr = 0; dr < 2; dr++) { + for (var ir = 0; ir < 2; ir++) { + for (var cr = 0; cr < 8; cr++) { + for (var Dy = 0; Dy < 8; Dy++) { + op = (14 << 12) | (cr << 9) | (dr << 8) | (z << 6) | (ir << 5) | Dy; + if (iTab[op].op === -1) { + iTab[op] = mkI(op, dr == 0 ? "ASR" : "ASL", z2 == 4 ? [8,1,0] : [6,1,0]); + iTab[op].p.ir = ir; + iTab[op].p.cr = ir == 0 ? (cr == 0 ? 8 : cr) : cr; + iTab[op].p.Dy = Dy; + if (dr == 0) + iTab[op].f = z2 == 4 ? I_ASR_32 : (z2 == 2 ? I_ASR_16 : I_ASR_8); + else + iTab[op].f = z2 == 4 ? I_ASL_32 : (z2 == 2 ? I_ASL_16 : I_ASL_8); + + iTab[op].d = mkDiss(0, ir == 0 ? D_IMD : D_RDD,ir == 0 ? (cr == 0 ? 8 : cr) : cr, D_RDD,Dy, z2,0); + cnt++; + } else { + SAEF_error("cpu.mkITab() op exists ASx "+op); + return false; + } + } + } + } + } + } + var en = [M_ria, M_ripo, M_ripr, M_rid, M_rii, M_absw, M_absl]; + for (var dr = 0; dr < 2; dr++) { + for (var ea = 0; ea < 61; ea++) { + if (isEA(ea, en)) { + op = (112 << 9) | (dr << 8) | (3 << 6) | ea; + if (iTab[op].op === -1) { + iTab[op] = mkI(op, dr == 0 ? "ASR" : "ASL", addCycs([8,1,1], getEACycs(ea, 2))); + iTab[op].p.ea = ea; + iTab[op].f = dr == 0 ? I_ASR_M : I_ASL_M; + iTab[op].d = mkDiss(0, false,false, D_EA,ea, 2,0); + cnt++; + } else { + SAEF_error("cpu.mkITab() op exists ASx "+op); + return false; + } + } + } + } + } + //LSL,LSR + { + for (var z = 0; z < 3; z++) { + z2 = z == 0 ? 1 : (z == 1 ? 2 : 4); + for (var dr = 0; dr < 2; dr++) { + for (var ir = 0; ir < 2; ir++) { + for (var cr = 0; cr < 8; cr++) { + for (var Dy = 0; Dy < 8; Dy++) { + op = (14 << 12) | (cr << 9) | (dr << 8) | (z << 6) | (ir << 5) | (1 << 3) | Dy; + if (iTab[op].op === -1) { + iTab[op] = mkI(op, dr == 0 ? "LSR" : "LSL", z2 == 4 ? [8,1,0] : [6,1,0]); + iTab[op].p.ir = ir; + iTab[op].p.cr = ir == 0 ? (cr == 0 ? 8 : cr) : cr; + iTab[op].p.Dy = Dy; + if (dr == 0) + iTab[op].f = z2 == 4 ? I_LSR_32 : (z2 == 2 ? I_LSR_16 : I_LSR_8); + else + iTab[op].f = z2 == 4 ? I_LSL_32 : (z2 == 2 ? I_LSL_16 : I_LSL_8); + + iTab[op].d = mkDiss(0, ir == 0 ? D_IMD : D_RDD,ir == 0 ? (cr == 0 ? 8 : cr) : cr, D_RDD,Dy, z2,0); + cnt++; + } else { + SAEF_error("cpu.mkITab() op exists LSx "+op); + return false; + } + } + } + } + } + } + var en = [M_ria, M_ripo, M_ripr, M_rid, M_rii, M_absw, M_absl]; + for (var dr = 0; dr < 2; dr++) { + for (var ea = 0; ea < 61; ea++) { + if (isEA(ea, en)) { + op = (113 << 9) | (dr << 8) | (3 << 6) | ea; + if (iTab[op].op === -1) { + iTab[op] = mkI(op, dr == 0 ? "LSR" : "LSL", addCycs([8,1,1], getEACycs(ea, 2))); + iTab[op].p.ea = ea; + iTab[op].f = dr == 0 ? I_LSR_M : I_LSL_M; + iTab[op].d = mkDiss(0, false,false, D_EA,ea, 2,0); + cnt++; + } else { + SAEF_error("cpu.mkITab() op exists LSx "+op); + return false; + } + } + } + } + } + //ROL,ROR + { + for (var z = 0; z < 3; z++) { + var z2 = z == 0 ? 1 : (z == 1 ? 2 : 4); + for (var dr = 0; dr < 2; dr++) { + for (var ir = 0; ir < 2; ir++) { + for (var cr = 0; cr < 8; cr++) { + for (var Dy = 0; Dy < 8; Dy++) { + op = (14 << 12) | (cr << 9) | (dr << 8) | (z << 6) | (ir << 5) | (3 << 3) | Dy; + if (iTab[op].op === -1) { + iTab[op] = mkI(op, dr == 0 ? "ROR" : "ROL", z2 == 4 ? [8,1,0] : [6,1,0]); + iTab[op].p.ir = ir; + iTab[op].p.cr = ir == 0 ? (cr == 0 ? 8 : cr) : cr; + iTab[op].p.Dy = Dy; + if (dr == 0) + iTab[op].f = z2 == 4 ? I_ROR_32 : (z2 == 2 ? I_ROR_16 : I_ROR_8); + else + iTab[op].f = z2 == 4 ? I_ROL_32 : (z2 == 2 ? I_ROL_16 : I_ROL_8); + + iTab[op].d = mkDiss(0, ir == 0 ? D_IMD : D_RDD,ir == 0 ? (cr == 0 ? 8 : cr) : cr, D_RDD,Dy, z2,0); + cnt++; + } else { + SAEF_error("cpu.mkITab() op exists ROx "+op); + return false; + } + } + } + } + } + } + var en = [M_ria, M_ripo, M_ripr, M_rid, M_rii, M_absw, M_absl]; + for (var dr = 0; dr < 2; dr++) { + for (var ea = 0; ea < 61; ea++) { + if (isEA(ea, en)) { + op = (115 << 9) | (dr << 8) | (3 << 6) | ea; + if (iTab[op].op === -1) { + iTab[op] = mkI(op, dr == 0 ? "ROR" : "ROL", addCycs([8,1,1], getEACycs(ea, 2))); + iTab[op].p.ea = ea; + iTab[op].f = dr == 0 ? I_ROR_M : I_ROL_M; + iTab[op].d = mkDiss(0, false,false, D_EA,ea, 2,0); + cnt++; + } else { + SAEF_error("cpu.mkITab() op exists ROx "+op); + return false; + } + } + } + } + } + //ROXL,ROXR + { + for (var z = 0; z < 3; z++) { + var z2 = z == 0 ? 1 : (z == 1 ? 2 : 4); + for (var dr = 0; dr < 2; dr++) { + for (var ir = 0; ir < 2; ir++) { + for (var cr = 0; cr < 8; cr++) { + for (var Dy = 0; Dy < 8; Dy++) { + op = (14 << 12) | (cr << 9) | (dr << 8) | (z << 6) | (ir << 5) | (2 << 3) | Dy; + if (iTab[op].op === -1) { + iTab[op] = mkI(op, dr == 0 ? "ROR" : "ROL", z2 == 4 ? [8,1,0] : [6,1,0]); + iTab[op].p.ir = ir; + iTab[op].p.cr = ir == 0 ? (cr == 0 ? 8 : cr) : cr; + iTab[op].p.Dy = Dy; + if (dr == 0) + iTab[op].f = z2 == 4 ? I_ROXR_32 : (z2 == 2 ? I_ROXR_16 : I_ROXR_8); + else + iTab[op].f = z2 == 4 ? I_ROXL_32 : (z2 == 2 ? I_ROXL_16 : I_ROXL_8); + + iTab[op].d = mkDiss(0, ir == 0 ? D_IMD : D_RDD,ir == 0 ? (cr == 0 ? 8 : cr) : cr, D_RDD,Dy, z2,0); + cnt++; + } else { + SAEF_error("cpu.mkITab() op exists ROx "+op); + return false; + } + } + } + } + } + } + var en = [M_ria, M_ripo, M_ripr, M_rid, M_rii, M_absw, M_absl]; + for (var dr = 0; dr < 2; dr++) { + for (var ea = 0; ea < 61; ea++) { + if (isEA(ea, en)) { + op = (114 << 9) | (dr << 8) | (3 << 6) | ea; + if (iTab[op].op === -1) { + iTab[op] = mkI(op, dr == 0 ? "ROXR" : "ROXL", addCycs([8,1,1], getEACycs(ea, 2))); + iTab[op].p.ea = ea; + iTab[op].f = dr == 0 ? I_ROXR_M : I_ROXL_M; + iTab[op].d = mkDiss(0, false,false, D_EA,ea, 2,0); + cnt++; + } else { + SAEF_error("cpu.mkITab() op exists ROx "+op); + return false; + } + } + } + } + } + //SWAP + { + for (var Dn = 0; Dn < 8; Dn++) { + op = (2312 << 3) | Dn; + if (iTab[op].op === -1) { + iTab[op] = mkI(op, "SWAP", [4,1,0]); + iTab[op].p.Dn = Dn; + iTab[op].f = I_SWAP; + iTab[op].d = mkDiss(0, false,false, D_RDD,Dn, 2,0); + cnt++; + } else { + SAEF_error("cpu.mkITab() op exists SWAP "+op); + return false; + } + } + } + + /*-----------------------------------------------------------------------*/ + /* Bit Manipulation */ + + //BCHG + { + var en = [M_rdd, M_ria, M_ripo, M_ripr, M_rid, M_rii, M_absw, M_absl]; + for (var Dn = 0; Dn < 8; Dn++) { + for (var ea = 0; ea < 61; ea++) { + if (isEA(ea, en)) { + op = (Dn << 9) | (5 << 6) | ea; + if (iTab[op].op === -1) { + var m = getEAMode(ea); + iTab[op] = mkI(op, "BCHG", m == M_rdd ? [8,1,0]:[8,1,1]); + iTab[op].p.Dn = Dn; + if (m == M_rdd) { + iTab[op].p.Dd = ea & 7; + iTab[op].f = I_BCHG_DD_32; + } else { + iTab[op].p.ea = ea; + iTab[op].p.cyc = addCycs(iTab[op].p.cyc, getEACycs(ea, 1)); + iTab[op].f = I_BCHG_DE_8; + } + iTab[op].d = mkDiss(0, D_RDD,Dn, D_EA,ea, m == M_rdd ? 4 : 1,0); + cnt++; + } else { + SAEF_error("cpu.mkITab() op exists BCHG1 "+op); + return false; + } + } + } + } + for (var ea = 0; ea < 61; ea++) { + if (isEA(ea, en)) { + op = (33 << 6) | ea; + if (iTab[op].op === -1) { + var m = getEAMode(ea); + iTab[op] = mkI(op, "BCHG", m == M_rdd ? [12,2,0]:[12,2,1]); + if (m == M_rdd) { + iTab[op].p.Dd = ea & 7; + iTab[op].f = I_BCHG_ID_32; + } else { + iTab[op].p.ea = ea; + iTab[op].p.cyc = addCycs(iTab[op].p.cyc, getEACycs(ea, 1)); + iTab[op].f = I_BCHG_IE_8; + } + iTab[op].d = mkDiss(0, D_IME,1, D_EA,ea, m == M_rdd ? 4 : 1,0); + cnt++; + } else { + SAEF_error("cpu.mkITab() op exists BCHG "+op); + return false; + } + } + } + } + //BCLR + { + var en = [M_rdd, M_ria, M_ripo, M_ripr, M_rid, M_rii, M_absw, M_absl]; + for (var Dn = 0; Dn < 8; Dn++) { + for (var ea = 0; ea < 61; ea++) { + if (isEA(ea, en)) { + op = (Dn << 9) | (6 << 6) | ea; + if (iTab[op].op === -1) { + var m = getEAMode(ea); + iTab[op] = mkI(op, "BCLR", m == M_rdd ? [10,1,0]:[8,1,1]); + iTab[op].p.Dn = Dn; + if (m == M_rdd) { + iTab[op].p.Dd = ea & 7; + iTab[op].f = I_BCLR_DD_32; + } else { + iTab[op].p.ea = ea; + iTab[op].p.cyc = addCycs(iTab[op].p.cyc, getEACycs(ea, 1)); + iTab[op].f = I_BCLR_DE_8; + } + iTab[op].d = mkDiss(0, D_RDD,Dn, D_EA,ea, m == M_rdd ? 4 : 1,0); + cnt++; + } else { + SAEF_error("cpu.mkITab() op exists BCLR "+op); + return false; + } + } + } + } + for (var ea = 0; ea < 61; ea++) { + if (isEA(ea, en)) { + op = (34 << 6) | ea; + if (iTab[op].op === -1) { + var m = getEAMode(ea); + iTab[op] = mkI(op, "BCLR", m == M_rdd ? [14,2,0]:[12,2,1]); + if (m == M_rdd) { + iTab[op].p.Dd = ea & 7; + iTab[op].f = I_BCLR_ID_32; + } else { + iTab[op].p.ea = ea; + iTab[op].p.cyc = addCycs(iTab[op].p.cyc, getEACycs(ea, 1)); + iTab[op].f = I_BCLR_IE_8; + } + iTab[op].d = mkDiss(0, D_IME,1, D_EA,ea, m == M_rdd ? 4 : 1,0); + cnt++; + } else { + SAEF_error("cpu.mkITab() op exists BCLR "+op); + return false; + } + } + } + } + //BSET + { + var en = [M_rdd, M_ria, M_ripo, M_ripr, M_rid, M_rii, M_absw, M_absl]; + for (var Dn = 0; Dn < 8; Dn++) { + for (var ea = 0; ea < 61; ea++) { + if (isEA(ea, en)) { + op = (Dn << 9) | (7 << 6) | ea; + if (iTab[op].op === -1) { + var m = getEAMode(ea); + iTab[op] = mkI(op, "BSET", m == M_rdd ? [8,1,0]:[8,1,1]); + iTab[op].p.Dn = Dn; + if (m == M_rdd) { + iTab[op].p.Dd = ea & 7; + iTab[op].f = I_BSET_DD_32; + } else { + iTab[op].p.ea = ea; + iTab[op].p.cyc = addCycs(iTab[op].p.cyc, getEACycs(ea, 1)); + iTab[op].f = I_BSET_DE_8; + } + iTab[op].d = mkDiss(0, D_RDD,Dn, D_EA,ea, m == M_rdd ? 4 : 1,0); + cnt++; + } else { + SAEF_error("cpu.mkITab() op exists BSET "+op); + return false; + } + } + } + } + for (var ea = 0; ea < 61; ea++) { + if (isEA(ea, en)) { + op = (35 << 6) | ea; + if (iTab[op].op === -1) { + var m = getEAMode(ea); + iTab[op] = mkI(op, "BSET", m == M_rdd ? [12,2,0]:[12,2,1]); + if (m == M_rdd) { + iTab[op].p.Dd = ea & 7; + iTab[op].f = I_BSET_ID_32; + } else { + iTab[op].p.ea = ea; + iTab[op].p.cyc = addCycs(iTab[op].p.cyc, getEACycs(ea, 1)); + iTab[op].f = I_BSET_IE_8; + } + iTab[op].d = mkDiss(0, D_IME,1, D_EA,ea, m == M_rdd ? 4 : 1,0); + cnt++; + } else { + SAEF_error("cpu.mkITab() op exists BSET "+op); + return false; + } + } + } + } + //BTST + { + var en = [M_rdd, M_ria, M_ripo, M_ripr, M_rid, M_rii, M_pcid, M_pcii, M_absw, M_absl, M_imm]; + for (var Dn = 0; Dn < 8; Dn++) { + for (var ea = 0; ea < 61; ea++) { + if (isEA(ea, en)) { + op = (Dn << 9) | (4 << 6) | ea; + if (iTab[op].op === -1) { + var m = getEAMode(ea); + iTab[op] = mkI(op, "BTST", m == M_rdd ? [6,1,0]:[4,1,0]); + iTab[op].p.Dn = Dn; + if (m == M_rdd) { + iTab[op].p.Dd = ea & 7; + iTab[op].f = I_BTST_DD_32; + } else { + iTab[op].p.ea = ea; + iTab[op].p.cyc = addCycs(iTab[op].p.cyc, getEACycs(ea, 1)); + iTab[op].f = I_BTST_DE_8; + } + iTab[op].d = mkDiss(0, D_RDD,Dn, D_EA,ea, m == M_rdd ? 4 : 1,0); + cnt++; + } else { + SAEF_error("cpu.mkITab() op exists BTST "+op); + return false; + } + } + } + } + en = [M_rdd, M_ria, M_ripo, M_ripr, M_rid, M_rii, M_pcid, M_pcii, M_absw, M_absl]; + for (var ea = 0; ea < 61; ea++) { + if (isEA(ea, en)) { + op = (32 << 6) | ea; + if (iTab[op].op === -1) { + var m = getEAMode(ea); + iTab[op] = mkI(op, "BTST", m == M_rdd ? [12,2,0]:[8,2,0]); + if (m == M_rdd) { + iTab[op].p.Dd = ea & 7; + iTab[op].f = I_BTST_ID_32; + } else { + iTab[op].p.ea = ea; + iTab[op].p.cyc = addCycs(iTab[op].p.cyc, getEACycs(ea, 1)); + iTab[op].f = I_BTST_IE_8; + } + iTab[op].d = mkDiss(0, D_IME,1, D_EA,ea, m == M_rdd ? 4 : 1,0); + cnt++; + } else { + SAEF_error("cpu.mkITab() op exists BTST "+op); + return false; + } + } + } + } + + /*-----------------------------------------------------------------------*/ + /* Bitfield >= 68020 */ + + //BFCHG + if (model >= 68020) { + var en = [M_rdd, M_ria, M_rid, M_rii, M_pcid, M_pcii, M_absw, M_absl]; + for (var ea = 0; ea < 61; ea++) { + if (isEA(ea, en)) { + op = (939 << 6) | ea; + if (iTab[op].op === -1) { + iTab[op] = mkI(op, "BFCHG", [4,1,0]); //FIXME cycles + iTab[op].p.id = ID_BFCHG; + iTab[op].p.ea = ea; + iTab[op].f = I_BFXXX; + iTab[op].d = mkDiss(1, D_EA,ea, D_EXT_BITFIELD,0, 0,0); + cnt++; + } else { + SAEF_error("cpu.mkITab() op exists BFCHG "+op); + return false; + } + } + } + } + //BFCLR + if (model >= 68020) { + var en = [M_rdd, M_ria, M_rid, M_rii, M_pcid, M_pcii, M_absw, M_absl]; + for (var ea = 0; ea < 61; ea++) { + if (isEA(ea, en)) { + op = (947 << 6) | ea; + if (iTab[op].op === -1) { + iTab[op] = mkI(op, "BFCLR", [4,1,0]); //FIXME cycles + iTab[op].p.id = ID_BFCLR; + iTab[op].p.ea = ea; + iTab[op].f = I_BFXXX; + iTab[op].d = mkDiss(1, D_EA,ea, D_EXT_BITFIELD,0, 0,0); + cnt++; + } else { + SAEF_error("cpu.mkITab() op exists BFCLR "+op); + return false; + } + } + } + } + //BFEXTS + if (model >= 68020) { + var en = [M_rdd, M_ria, M_rid, M_rii, M_pcid, M_pcii, M_absw, M_absl]; + for (var ea = 0; ea < 61; ea++) { + if (isEA(ea, en)) { + op = (943 << 6) | ea; + if (iTab[op].op === -1) { + iTab[op] = mkI(op, "BFEXTS", [4,1,0]); //FIXME cycles + iTab[op].p.id = ID_BFEXTS; + iTab[op].p.ea = ea; + iTab[op].f = I_BFXXX; + iTab[op].d = mkDiss(1, D_EA,ea, D_EXT_BITFIELD,0, 0,0); + cnt++; + } else { + SAEF_error("cpu.mkITab() op exists BFEXTS "+op); + return false; + } + } + } + } + //BFEXTU + if (model >= 68020) { + var en = [M_rdd, M_ria, M_rid, M_rii, M_pcid, M_pcii, M_absw, M_absl]; + for (var ea = 0; ea < 61; ea++) { + if (isEA(ea, en)) { + op = (935 << 6) | ea; + if (iTab[op].op === -1) { + iTab[op] = mkI(op, "BFEXTU", [4,1,0]); //FIXME cycles + iTab[op].p.id = ID_BFEXTU; + iTab[op].p.ea = ea; + iTab[op].f = I_BFXXX; + iTab[op].d = mkDiss(1, D_EA,ea, D_EXT_BITFIELD,0, 0,0); + cnt++; + } else { + SAEF_error("cpu.mkITab() op exists BFEXTU "+op); + return false; + } + } + } + } + //BFFFO + if (model >= 68020) { + var en = [M_rdd, M_ria, M_rid, M_rii, M_pcid, M_pcii, M_absw, M_absl]; + for (var ea = 0; ea < 61; ea++) { + if (isEA(ea, en)) { + op = (951 << 6) | ea; + if (iTab[op].op === -1) { + iTab[op] = mkI(op, "BFFFO", [4,1,0]); //FIXME cycles + iTab[op].p.id = ID_BFFFO; + iTab[op].p.ea = ea; + iTab[op].f = I_BFXXX; + iTab[op].d = mkDiss(1, D_EA,ea, D_EXT_BITFIELD,0, 0,0); + cnt++; + } else { + SAEF_error("cpu.mkITab() op exists BFFFO "+op); + return false; + } + } + } + } + //BFINS + if (model >= 68020) { + var en = [M_rdd, M_ria, M_rid, M_rii, M_absw, M_absl]; + for (var ea = 0; ea < 61; ea++) { + if (isEA(ea, en)) { + op = (959 << 6) | ea; + if (iTab[op].op === -1) { + iTab[op] = mkI(op, "BFINS", [4,1,0]); //FIXME cycles + iTab[op].p.id = ID_BFINS; + iTab[op].p.ea = ea; + iTab[op].f = I_BFXXX; + iTab[op].d = mkDiss(1, D_EA,ea, D_EXT_BITFIELD,0, 0,0); + cnt++; + } else { + SAEF_error("cpu.mkITab() op exists BFINS "+op); + return false; + } + } + } + } + //BFSET + if (model >= 68020) { + var en = [M_rdd, M_ria, M_rid, M_rii, M_absw, M_absl]; + for (var ea = 0; ea < 61; ea++) { + if (isEA(ea, en)) { + op = (955 << 6) | ea; + if (iTab[op].op === -1) { + iTab[op] = mkI(op, "BFSET", [4,1,0]); //FIXME cycles + iTab[op].p.id = ID_BFSET; + iTab[op].p.ea = ea; + iTab[op].f = I_BFXXX; + iTab[op].d = mkDiss(1, D_EA,ea, D_EXT_BITFIELD,0, 0,0); + cnt++; + } else { + SAEF_error("cpu.mkITab() op exists BFSET "+op); + return false; + } + } + } + } + //BFTST + if (model >= 68020) { + var en = [M_rdd, M_ria, M_rid, M_rii, M_pcid, M_pcii, M_absw, M_absl]; + for (var ea = 0; ea < 61; ea++) { + if (isEA(ea, en)) { + op = (931 << 6) | ea; + if (iTab[op].op === -1) { + iTab[op] = mkI(op, "BFTST", [4,1,0]); //FIXME cycles + iTab[op].p.id = ID_BFTST; + iTab[op].p.ea = ea; + iTab[op].f = I_BFXXX; + iTab[op].d = mkDiss(1, D_EA,ea, D_EXT_BITFIELD,0, 0,0); + cnt++; + } else { + SAEF_error("cpu.mkITab() op exists BFTST "+op); + return false; + } + } + } + } + + /*-----------------------------------------------------------------------*/ + /* Binary-Coded Decimal */ + + //ABCD + { + for (var Rx = 0; Rx < 8; Rx++) { + for (var rm = 0; rm < 2; rm++) { + for (var Ry = 0; Ry < 8; Ry++) { + op = (12 << 12) | (Rx << 9) | (1 << 8) | (rm << 3) | Ry; + if (iTab[op].op === -1) { + iTab[op] = mkI(op, "ABCD", rm == 0 ? [6,1,0] : [18,3,1]); + iTab[op].p.Rx = Rx; + iTab[op].p.Ry = Ry; + if (rm == 0) { + iTab[op].f = I_ABCD_D; + iTab[op].d = mkDiss(0, D_RDD,Ry, D_RDD,Rx, 1,0); + } else { + iTab[op].f = I_ABCD_A; + iTab[op].d = mkDiss(0, D_RIPR,Ry, D_RIPR,Rx, 1,0); + } + cnt++; + } else { + SAEF_error("cpu.mkITab() op exists ABCD "+op); + return false; + } + } + } + } + } + //SBCD + { + for (var Ry = 0; Ry < 8; Ry++) { + for (var rm = 0; rm < 2; rm++) { + for (var Rx = 0; Rx < 8; Rx++) { + op = (8 << 12) | (Ry << 9) | (1 << 8) | (rm << 3) | Rx; + if (iTab[op].op === -1) { + iTab[op] = mkI(op, "SBCD", rm == 0 ? [6,1,0] : [18,3,1]); + iTab[op].p.Ry = Ry; + iTab[op].p.Rx = Rx; + if (rm == 0) { + iTab[op].f = I_SBCD_D; + iTab[op].d = mkDiss(0, D_RDD,Rx, D_RDD,Ry, 1,0); + } else { + iTab[op].f = I_SBCD_A; + iTab[op].d = mkDiss(0, D_RIPR,Rx, D_RIPR,Ry, 1,0); + } + cnt++; + } else { + SAEF_error("cpu.mkITab() op exists SBCD "+op); + return false; + } + } + } + } + } + //NBCD + { + var en = [M_rdd, M_ria, M_ripo, M_ripr, M_rid, M_rii, M_absw, M_absl]; + for (var ea = 0; ea < 61; ea++) { + if (isEA(ea, en)) { + op = (288 << 6) | ea; + if (iTab[op].op === -1) { + var m = getEAMode(ea); + iTab[op] = mkI(op, "NBCD", m == M_rdd ? [6,1,0] : [8,1,1]); + if (m == M_rdd) { + iTab[op].p.Dd = ea & 7; + iTab[op].f = I_NBCD_D; + } else { + iTab[op].p.ea = ea; + iTab[op].p.cyc = addCycs(iTab[op].p.cyc, getEACycs(ea, 1)); + iTab[op].f = I_NBCD_E; + } + iTab[op].d = mkDiss(0, false,false, D_EA,ea, 1,0); + cnt++; + } else { + SAEF_error("cpu.mkITab() op exists NBCD "+op); + return false; + } + } + } + } + //PACK + if (model >= 68020) { + for (var Ry = 0; Ry < 8; Ry++) { + for (var rm = 0; rm < 2; rm++) { + for (var Rx = 0; Rx < 8; Rx++) { + op = (8 << 12) | (Ry << 9) | (20 << 4) | (rm << 3) | Rx; + if (iTab[op].op === -1) { + iTab[op] = mkI(op, "PACK", [4,0,0]); //FIXME cycles + iTab[op].p.Ry = Ry; + iTab[op].p.Rx = Rx; + if (rm == 0) { + iTab[op].f = I_PACK_D; + iTab[op].d = mkDiss(1, D_RDD,Rx, D_RDD,Ry, 0,0); //FIXME adjustment + } else { + iTab[op].f = I_PACK_A; + iTab[op].d = mkDiss(1, D_RIPR,Rx, D_RIPR,Ry, 0,0); //FIXME adjustment + } + cnt++; + } else { + SAEF_error("cpu.mkITab() op exists PACK "+op); + return false; + } + } + } + } + } + //UNPK + if (model >= 68020) { + for (var Ry = 0; Ry < 8; Ry++) { + for (var rm = 0; rm < 2; rm++) { + for (var Rx = 0; Rx < 8; Rx++) { + op = (8 << 12) | (Ry << 9) | (24 << 4) | (rm << 3) | Rx; + if (iTab[op].op === -1) { + iTab[op] = mkI(op, "PACK", [4,0,0]); //FIXME cycles + iTab[op].p.Ry = Ry; + iTab[op].p.Rx = Rx; + if (rm == 0) { + iTab[op].f = I_UNPK_D; + iTab[op].d = mkDiss(1, D_RDD,Rx, D_RDD,Ry, 0,0); //FIXME adjustment + } else { + iTab[op].f = I_UNPK_A; + iTab[op].d = mkDiss(1, D_RIPR,Rx, D_RIPR,Ry, 0,0); //FIXME adjustment + } + cnt++; + } else { + SAEF_error("cpu.mkITab() op exists UNPK " + op); + return false; + } + } + } + } + } + + /*-----------------------------------------------------------------------*/ + /* Program Control */ + + //Bcc + { + for (var cc = 2; cc < 16; cc++) { + for (var dp = 0; dp < (model >= 68020 ? 256 : 255); dp++) { /* 0xff = long, 68020 only */ + op = (6 << 12) | (cc << 8) | dp; + if (iTab[op].op === -1) { + iTab[op] = mkI(op, "B"+ccNames[cc], dp == 255 ? [12,1,0] : [8,1,0]); + iTab[op].p.cc = cc; + iTab[op].p.dp = dp; + iTab[op].p.cycTaken = [10,2,2]; + iTab[op].f = I_Bcc; + iTab[op].d = mkDiss(0, false,false, D_IME_DP,dp, dp == 255 ? 2 : 1,0); + cnt++; + } else { + SAEF_error("cpu.mkITab() op exists B"+ccNames[cc]+" "+op); + return false; + } + } + } + } + //DBcc + { + for (var cc = 0; cc < 16; cc++) { + for (var Dn = 0; Dn < 8; Dn++) { + op = (5 << 12) | (cc << 8) | (25 << 3) | Dn; + if (iTab[op].op === -1) { + iTab[op] = mkI(op, "DB"+ccNames[cc], [10,2,0]); + iTab[op].p.cc = cc; + iTab[op].p.Dn = Dn; + iTab[op].p.cycNotTakenTrue = [12,2,0]; + iTab[op].p.cycNotTakenFalse = [14,3,0]; + iTab[op].f = I_DBcc; + iTab[op].d = mkDiss(0, D_RDD,Dn, D_IME_DP,0, 2,0); + cnt++; + } else { + SAEF_error("cpu.mkITab() op exists DB"+ccNames[cc]+" "+op); + return false; + } + } + } + } + //Scc + { + var en = [M_rdd, M_ria, M_ripo, M_ripr, M_rid, M_rii, M_absw, M_absl]; + for (var cc = 0; cc < 16; cc++) { + for (var ea = 0; ea < 61; ea++) { + if (isEA(ea, en)) { + op = (5 << 12) | (cc << 8) | (3 << 6) | ea; + if (iTab[op].op === -1) { + var cyc = getEAMode(ea) == M_rdd ? [8,1,1] : addCycs([8,1,1], getEACycs(ea, 1)); + iTab[op] = mkI(op, "S"+ccNames[cc], cyc); + iTab[op].p.cc = cc; + iTab[op].p.ea = ea; + iTab[op].p.cycFalse = [4,1,0]; + iTab[op].p.cycTrue = [6,1,0]; + iTab[op].f = I_Scc; + iTab[op].d = mkDiss(0, false,false, D_EA,ea, 1,0); + cnt++; + } else { + SAEF_error("cpu.mkITab() op exists S"+ccNames[cc]+" "+op); + return false; + } + } + } + } + } + //BRA + { + for (var dp = 0; dp < (model >= 68020 ? 256 : 255); dp++) { /* 0xff = 68020 only */ + op = (96 << 8) | dp; + if (iTab[op].op === -1) { + iTab[op] = mkI(op, "BRA", [10,2,0]); + iTab[op].p.dp = dp; + iTab[op].f = I_BRA; + iTab[op].d = mkDiss(0, false,false, D_IME_DP,dp, dp == 0 ? 2 : (dp == 255 ? 4 : 1),0); + cnt++; + } else { + SAEF_error("cpu.mkITab() op exists BRA "+op); + return false; + } + } + } + //BSR + { + for (var dp = 0; dp < (model >= 68020 ? 256 : 255); dp++) { /* 0xff = 68020 only */ + op = (97 << 8) | dp; + if (iTab[op].op === -1) { + iTab[op] = mkI(op, "BSR", [18,2,2]); + iTab[op].p.dp = dp; + iTab[op].f = I_BSR; + iTab[op].d = mkDiss(0, false,false, D_IME_DP,dp, dp == 0 ? 2 : (dp == 255 ? 4 : 1),0); + cnt++; + } else { + SAEF_error("cpu.mkITab() op exists BSR " + op); + return false; + } + } + } + //JMP + { + var en = [M_ria, M_rid, M_rii, M_pcid, M_pcii, M_absw, M_absl]; + for (var ea = 0; ea < 61; ea++) { + if (isEA(ea, en)) { + op = (315 << 6) | ea; + if (iTab[op].op === -1) { + var cyc; + switch (getEAMode(ea)) { + case M_ria: cyc = [ 8,2,0]; break; + case M_rid: cyc = [10,2,0]; break; + case M_rii: cyc = [14,3,0]; break; + case M_pcid: cyc = [10,2,0]; break; + case M_pcii: cyc = [14,3,0]; break; + case M_absw: cyc = [10,2,0]; break; + case M_absl: cyc = [12,3,0]; break; + } + iTab[op] = mkI(op, "JMP", cyc); + iTab[op].p.ea = ea; + iTab[op].f = I_JMP; + iTab[op].d = mkDiss(0, false,false, D_EA,ea, 0,0); + cnt++; + } else { + SAEF_error("cpu.mkITab() op exists JMP "+op); + return false; + } + } + } + } + //JSR + { + var en = [M_ria, M_rid, M_rii, M_pcid, M_pcii, M_absw, M_absl]; + for (var ea = 0; ea < 61; ea++) { + if (isEA(ea, en)) { + op = (314 << 6) | ea; + if (iTab[op].op === -1) { + var cyc; + switch (getEAMode(ea)) { + case M_ria: cyc = [16,2,2]; break; + case M_rid: cyc = [18,2,2]; break; + case M_rii: cyc = [22,2,2]; break; + case M_pcid: cyc = [18,2,2]; break; + case M_pcii: cyc = [22,2,2]; break; + case M_absw: cyc = [18,2,2]; break; + case M_absl: cyc = [20,3,2]; break; + } + iTab[op] = mkI(op, "JSR", cyc); + iTab[op].p.ea = ea; + iTab[op].f = I_JSR; + iTab[op].d = mkDiss(0, false,false, D_EA,ea, 0,0); + cnt++; + } else { + SAEF_error("cpu.mkITab() op exists JSR " + op); + return false; + } + } + } + } + //NOP + { + op = 0x4E71; + if (iTab[op].op === -1) { + iTab[op] = mkI(op, "NOP", [4,1,0]); + iTab[op].f = I_NOP; + iTab[op].d = mkDiss(0, false,false, false,false, 0,0); + cnt++; + } else { + SAEF_error("cpu.mkITab() op exists NOP "+op); + return false; + } + } + //RTD + if (model >= 68010) { + op = 0x4E74; + if (iTab[op].op === -1) { + iTab[op] = mkI(op, "RTD", [4,0,0]); //FIXME cycles + iTab[op].f = I_RTD; + iTab[op].d = mkDiss(0, false,false, D_IME,1, 0,0); //FIXME + cnt++; + } else { + SAEF_error("cpu.mkITab() op exists RTD "+op); + return false; + } + } + //RTR + { + op = 0x4E77; + if (iTab[op].op === -1) { + iTab[op] = mkI(op, "RTR", [20,5,0]); + iTab[op].f = I_RTR; + iTab[op].d = mkDiss(0, false,false, false,false, 0,0); + cnt++; + } else { + SAEF_error("cpu.mkITab() op exists RTR "+op); + return false; + } + } + //RTS + { + op = 0x4E75; + if (iTab[op].op === -1) { + iTab[op] = mkI(op, "RTS", [16,4,0]); + iTab[op].f = I_RTS; + iTab[op].d = mkDiss(0, false,false, false,false, 0,0); + cnt++; + } else { + SAEF_error("cpu.mkITab() op exists RTS "+op); + return false; + } + } + //TST + { + var en = [M_rdd, M_rda, M_ria, M_ripo, M_ripr, M_rid, M_rii, M_absw, M_absl, M_imm]; + if (model >= 68020) en.push(M_pcid, M_pcii); + for (var z = 0; z < 3; z++) { + var z2 = z == 0 ? 1 : (z == 1 ? 2 : 4); + for (var ea = 0; ea < 61; ea++) { + if (isEA(ea, en)) { + var m = getEAMode(ea); + if (model >= 68020 && z == 0 && m == M_rda) continue; //68020 An word and long only + op = (74 << 8) | (z << 6) | ea; + if (iTab[op].op === -1) { + cyc = m == M_rdd || m == M_rda ? [4,1,0] : addCycs([4,1,0], getEACycs(ea, z2)); + iTab[op] = mkI(op, "TST", cyc); + iTab[op].p.ea = ea; + iTab[op].p.zm = z2 == 4 ? 0x80000000 : (z2 == 2 ? 0x8000 : 0x80); + iTab[op].f = z2 == 4 ? I_TST_32 : (z2 == 2 ? I_TST_16 : I_TST_8); + iTab[op].d = mkDiss(0, false,false, D_EA,ea, z2,0); + cnt++; + } else { + SAEF_error("cpu.mkITab() op exists TST "+op); + return false; + } + } + } + } + } + + /*-----------------------------------------------------------------------*/ + /* System Control - CCR */ + + //ANDI_CCR + { + op = 0x23C; + if (iTab[op].op === -1) { + iTab[op] = mkI(op, "ANDI", [20,3,0]); + iTab[op].f = I_ANDI_CCR; + iTab[op].d = mkDiss(0, D_IME,1, D_CCR,0, 1,0); + cnt++; + } else { + SAEF_error("cpu.mkITab() op exists ANDI_CCR "+op); + return false; + } + } + //EORI_CCR + { + op = 0xA3C; + if (iTab[op].op === -1) { + iTab[op] = mkI(op, "EORI", [20,3,0]); + iTab[op].f = I_EORI_CCR; + iTab[op].d = mkDiss(0, D_IME,1, D_CCR,0, 1,0); + cnt++; + } else { + SAEF_error("cpu.mkITab() op exists EORI "+op); + return false; + } + } + //ORI_CCR + { + op = 0x3C; + if (iTab[op].op === -1) { + iTab[op] = mkI(op, "ORI", [20,3,0]); + iTab[op].f = I_ORI_CCR; + iTab[op].d = mkDiss(0, D_IME,1, D_CCR,0, 1,0); + cnt++; + } else { + SAEF_error("cpu.mkITab() op exists ORI_CCR "+op); + return false; + } + } + //MOVE_CCR2 + if (model >= 68010) { + var en = [M_rdd,M_ria,M_ripo,M_ripr,M_rid,M_rii,M_absw,M_absl]; + for (var ea = 0; ea < 61; ea++) { + if (isEA(ea, en)) { + op = (267 << 6) | ea; + if (iTab[op].op === -1) { + iTab[op] = mkI(op, "MOVE", [4,1,0]); + iTab[op].p.ea = ea; + iTab[op].f = I_MOVE_CCR2; + iTab[op].d = mkDiss(0, D_CCR,0, D_EA,ea, 2,0); + cnt++; + } else { + SAEF_error("cpu.mkITab() op exists MOVE_CCR2 "+op); + return false; + } + } + } + } + //MOVE_2CCR + { + var en = [M_rdd, M_ria, M_ripo, M_ripr, M_rid, M_rii, M_pcid, M_pcii, M_absw, M_absl, M_imm]; + for (var ea = 0; ea < 61; ea++) { + if (isEA(ea, en)) { + op = (275 << 6) | ea; + if (iTab[op].op === -1) { + var cyc = getEAMode(ea) == M_rdd ? [12,1,0] : addCycs([12,1,0], getEACycs(ea, 2)); + iTab[op] = mkI(op, "MOVE", cyc); + iTab[op].p.ea = ea; + iTab[op].f = I_MOVE_2CCR; + iTab[op].d = mkDiss(0, D_EA,ea, D_CCR,0, 2,0); + cnt++; + } else { + SAEF_error("cpu.mkITab() op exists MOVE_2CCR "+op); + return false; + } + } + } + } + + /*-----------------------------------------------------------------------*/ + /* System Control - SR */ + + //ANDI_SR + { + op = 0x27C; + if (iTab[op].op === -1) { + iTab[op] = mkI(op, "ANDI", [20,3,0]); + iTab[op].f = I_ANDI_SR; + iTab[op].d = mkDiss(0, D_IME,1, D_SR,0, 2,0); + cnt++; + } else { + SAEF_error("cpu.mkITab() op exists ANDI_SR "+op); + return false; + } + } + //EORI_SR + { + op = 0xA7C; + if (iTab[op].op === -1) { + iTab[op] = mkI(op, "EORI", [20,3,0]); + iTab[op].f = I_EORI_SR; + iTab[op].d = mkDiss(0, D_IME,1, D_SR,0, 2,0); + cnt++; + } else { + SAEF_error("cpu.mkITab() op exists EORI "+op); + return false; + } + } + //ORI_SR + { + op = 0x7C; + if (iTab[op].op === -1) { + iTab[op] = mkI(op, "ORI", [20,3,0]); + iTab[op].f = I_ORI_SR; + iTab[op].d = mkDiss(0, D_IME,1, D_SR,0, 2,0); + cnt++; + } else { + SAEF_error("cpu.mkITab() op exists ORI_SR "+op); + return false; + } + } + //MOVE_SR2 + { + var en = [M_rdd, M_ria, M_ripo, M_ripr, M_rid, M_rii, M_absw, M_absl]; + for (var ea = 0; ea < 61; ea++) { + if (isEA(ea, en)) { + op = (259 << 6) | ea; + if (iTab[op].op === -1) { + var cyc = getEAMode(ea) == M_rdd ? [6,1,0] : addCycs([8,1,1], getEACycs(ea, 2)); + iTab[op] = mkI(op, "MOVE", cyc); + iTab[op].p.ea = ea; + iTab[op].f = I_MOVE_SR2; + iTab[op].d = mkDiss(0, D_SR,0, D_EA,ea, 2,0); + cnt++; + } else { + SAEF_error("cpu.mkITab() op exists MOVE_SR2 " + op); + return false; + } + } + } + } + //MOVE_2SR + { + var en = [M_rdd, M_ria, M_ripo, M_ripr, M_rid, M_rii, M_pcid, M_pcii, M_absw, M_absl, M_imm]; + for (var ea = 0; ea < 61; ea++) { + if (isEA(ea, en)) { + op = (283 << 6) | ea; + if (iTab[op].op === -1) { + var cyc = getEAMode(ea) == M_rdd ? [12,1,0] : addCycs([12,1,0], getEACycs(ea, 2)); + iTab[op] = mkI(op, "MOVE", cyc); + iTab[op].p.ea = ea; + iTab[op].f = I_MOVE_2SR; + iTab[op].d = mkDiss(0, D_EA,ea, D_SR,0, 2,0); + cnt++; + } else { + SAEF_error("cpu.mkITab() op exists MOVE_2SR " + op); + return false; + } + } + } + } + + /*-----------------------------------------------------------------------*/ + /* System Control - USP */ + + //MOVE_USP + { + for (var dr = 0; dr < 2; dr++) { + for (var An = 0; An < 8; An++) { + op = (1254 << 4) | (dr << 3) | An; + if (iTab[op].op === -1) { + iTab[op] = mkI(op, "MOVE", [4,1,0]); + iTab[op].p.An = An; + if (dr == 0) { + iTab[op].f = I_MOVE_A2USP; + iTab[op].d = mkDiss(0, D_RDA,An, D_USP,0, 4,0); + } else { + iTab[op].f = I_MOVE_USP2A; + iTab[op].d = mkDiss(0, D_USP,0, D_RDA,An, 4,0); + } + cnt++; + } else { + SAEF_error("cpu.mkITab() op exists MOVE_USP "+op); + return false; + } + } + } + } + + /*-----------------------------------------------------------------------*/ + /* System Control - MOVEC */ + + //MOVEC + if (model >= 68010) { + for (var dr = 0; dr < 2; dr++) { + op = (10045 << 1) | dr; + if (iTab[op].op === -1) { + iTab[op] = mkI(op, "MOVEC", [4,0,0]); //FIXME cycles + iTab[op].f = dr == 0 ? I_MOVE_C2 : I_MOVE_2C; + iTab[op].d = mkDiss(1, false,false, D_EXT_MOVEC,dr == 0, 4,0); + cnt++; + } else { + SAEF_error("cpu.mkITab() op exists MOVEC "+op); + return false; + } + } + } + + /*-----------------------------------------------------------------------*/ + /* System Control - MOVES */ + + //MOVES + if (model >= 68010) { + var en = [M_ria, M_ripo, M_ripr, M_rid, M_rii, M_absw, M_absl]; + for (var z = 0; z < 3; z++) { + var z2 = z == 0 ? 1 : (z == 1 ? 2 : 4); + for (var ea = 0; ea < 61; ea++) { + if (isEA(ea, en)) { + op = (14 << 8) | (z << 6) | ea; + if (iTab[op].op === -1) { + iTab[op] = mkI(op, "MOVES", [4,0,0]); //FIXME cycles + iTab[op].p.ea = ea; + iTab[op].f = z2 == 4 ? I_MOVES_32 : (z2 == 2 ? I_MOVES_16 : I_MOVES_8); + iTab[op].d = mkDiss(1, false,false, D_EA,ea, z2,0); //FIXME + //iTab[op].d = mkDiss(1, D_EA,ea, false,false, z2,0); //FIXME + cnt++; + } else { + SAEF_error("cpu.mkITab() op exists MOVES " + op); + return false; + } + } + } + } + } + + /*-----------------------------------------------------------------------*/ + /* System Control */ + + //BKPT + if (model >= 68010) { + for (var vec = 0; vec < 8; vec++) { + op = (2313 << 3) | vec; + if (iTab[op].op === -1) { + iTab[op] = mkI(op, "BKPT", [45,5,4]); + iTab[op].p.v = vec; + iTab[op].f = I_BKPT; + iTab[op].d = mkDiss(0, false,false, D_IMD,vec, 0,0); + cnt++; + } else { + SAEF_error("cpu.mkITab() op exists BKPT " + op); + return false; + } + } + } + //CHK + { + var en = [M_rdd, M_ria, M_ripo, M_ripr, M_rid, M_rii, M_pcid, M_pcii, M_absw, M_absl, M_imm]; + for (var Dn = 0; Dn < 8; Dn++) { + for (var z = 0; z < (model >= 68020 ? 2 : 1); z++) { + var z2 = z == 0 ? 2 : 4; + var z3 = z == 0 ? 3 : 2; + for (var ea = 0; ea < 61; ea++) { + if (isEA(ea, en)) { + op = (4 << 12) | (Dn << 9) | (z3 << 7) | ea; + if (iTab[op].op === -1) { + var cyc = getEAMode(ea) == M_rdd ? [10,1,0] : addCycs([10,1,0], getEACycs(ea, z2)); + iTab[op] = mkI(op, "CHK", cyc); + iTab[op].p.Dn = Dn; + iTab[op].p.ea = ea; + iTab[op].f = z2 == 2 ? I_CHK_16 : I_CHK_32; + iTab[op].d = mkDiss(0, D_EA,ea, D_RDD,Dn, z2,0); + cnt++; + } else { + SAEF_error("cpu.mkITab() op exists CHK "+op); + return false; + } + } + } + } + } + } + //CHK2 + if (model >= 68020) { + var en = [M_ria, M_rid, M_rii, M_pcid, M_pcii, M_absw, M_absl]; + for (var z = 0; z < 3; z++) { + var z2 = z == 0 ? 1 : (z == 1 ? 2 : 4); + for (var ea = 0; ea < 61; ea++) { + if (isEA(ea, en)) { + op = (z << 9) | (3 << 6) | ea; + if (iTab[op].op === -1) { + var cyc = getEAMode(ea) == M_rdd ? [10,1,0] : addCycs([10,1,0], getEACycs(ea, z2)); + iTab[op] = mkI(op, "CHK2", cyc); + iTab[op].p.ea = ea; + iTab[op].f = z2 == 4 ? I_CHK2_32 : (z2 == 2 ? I_CHK2_16 : I_CHK2_8); + //iTab[op].d = mkDiss(1, D_EA,ea, false,false, z2,0); //FIXME + iTab[op].d = mkDiss(1, false,false, D_EA,ea, z2,0); //FIXME + cnt++; + } else { + SAEF_error("cpu.mkITab() op exists CHK2 "+op); + return false; + } + } + } + } + } + //ILLEGAL + { + op = 0x4AFC; + if (iTab[op].op === -1) { + iTab[op] = mkI(op, "ILLEGAL", [0,0,0]); + iTab[op].f = I_ILLEGAL; + iTab[op].d = mkDiss(0, false,false, false,false, 0,0); + cnt++; + } else { + SAEF_error("cpu.mkITab() op exists ILLEGAL "+op); + return false; + } + } + //RESET + { + op = 0x4E70; + if (iTab[op].op === -1) { + iTab[op] = mkI(op, "RESET", [132,1,0]); + iTab[op].f = I_RESET; + iTab[op].d = mkDiss(0, false,false, false,false, 0,0); + cnt++; + } else { + SAEF_error("cpu.mkITab() op exists RESET "+op); + return false; + } + } + //RTE + { + op = 0x4E73; + if (iTab[op].op === -1) { + iTab[op] = mkI(op, "RTE", [20,5,0]); + iTab[op].f = I_RTE; + iTab[op].d = mkDiss(0, false,false, false,false, 0,0); + cnt++; + } else { + SAEF_error("cpu.mkITab() op exists RTE "+op); + return false; + } + } + //STOP + { + op = 0x4E72; + if (iTab[op].op === -1) { + iTab[op] = mkI(op, "STOP", [4,0,0]); + iTab[op].f = I_STOP; + iTab[op].d = mkDiss(0, false,false, D_IME,1, 0,0); + cnt++; + } else { + SAEF_error("cpu.mkITab() op exists STOP "+op); + return false; + } + } + //TRAP + { + for (var v = 0; v < 16; v++) { + op = (1252 << 4) | v; + if (iTab[op].op === -1) { + iTab[op] = mkI(op, "TRAP", [38,4,3]); + iTab[op].p.v = v; + iTab[op].f = I_TRAP; + iTab[op].d = mkDiss(0, false,false, D_IMD,v, 0,0); + cnt++; + } else { + SAEF_error("cpu.mkITab() op exists TRAP "+op); + return false; + } + } + } + //TRAPCC + if (model >= 68020) { + for (var z = 0; z < 3; z++) { + var z2 = z == 0 ? 0 : (z == 1 ? 2 : 4); + var opm = z == 0 ? 4 : (z == 1 ? 2 : 3); + for (var cc = 0; cc < 16; cc++) { + op = (5 << 12) | (cc << 8) | (31 << 3) | opm; + if (iTab[op].op === -1) { + iTab[op] = mkI(op, "TRAP"+ccNames[cc], [4,1,0]); + iTab[op].p.cc = cc; + iTab[op].f = z2 == 4 ? I_TRAPCC_32 : (z2 == 2 ? I_TRAPCC_16 : I_TRAPCC); + if (z2) + iTab[op].d = mkDiss(0, false,false, D_IMD,z2 == 2 ? 1 : 2, z2,0); + cnt++; + } else { + SAEF_error("cpu.mkITab() op exists TRAP"+ccNames[cc]+" "+op); + return false; + } + } + } + } + //TRAPV + { + op = 0x4E76; + if (iTab[op].op === -1) { + iTab[op] = mkI(op, "TRAPV", [4,1,0]); + iTab[op].f = I_TRAPV; + iTab[op].d = mkDiss(0, false,false, false,false, 0,0); + cnt++; + } else { + SAEF_error("cpu.mkITab() op exists TRAPV "+op); + return false; + } + } + + /*-----------------------------------------------------------------------*/ + /* Multiprocessor */ + + //CAS + if (model >= 68020) { + var en = [M_ria, M_ripo, M_ripr, M_rid, M_rii, M_absw, M_absl]; + for (var z = 1; z <= 3; z++) { + var z2 = z == 1 ? 1 : (z == 2 ? 2 : 4); + for (var ea = 0; ea < 61; ea++) { + if (isEA(ea, en)) { + op = (1 << 11) | (z << 9) | (3 << 6) | ea; + if (iTab[op].op === -1) { + iTab[op] = mkI(op, "CAS", [4,0,0]); //FIXME cycles + iTab[op].p.ea = ea; + iTab[op].f = z2 == 4 ? I_CAS_32 : (z2 == 2 ? I_CAS_16 : I_CAS_8); + iTab[op].d = mkDiss(1, false,false, D_EA,ea, z2,0); //FIXME + cnt++; + } else { + SAEF_error("cpu.mkITab() op exists CAS "+op); + return false; + } + } + } + } + } + //CAS2 + if (model >= 68020) { + for (var z = 2; z <= 3; z++) { + var z2 = z == 2 ? 2 : 4; + op = (1 << 11) | (z << 9) | 252; + if (iTab[op].op === -1) { + iTab[op] = mkI(op, "CAS2", [4,0,0]); //FIXME cycles + iTab[op].f = z2 == 4 ? I_CAS2_32 : I_CAS2_16; + iTab[op].d = mkDiss(2, false,false, false,false, z2,0); //FIXME + cnt++; + } else { + SAEF_error("cpu.mkITab() op exists CAS2 "+op); return false; } } @@ -4439,818 +9929,339 @@ function CPU() { //TAS { var en = [M_rdd, M_ria, M_ripo, M_ripr, M_rid, M_rii, M_absw, M_absl]; - var mr, ea; - - for (mr = 0; mr < 64; mr++) { - ea = mkEA(mr, en, 0); - if (ea[0] != -1) { - op = (299 << 6) | ea[0]; - + for (var ea = 0; ea < 61; ea++) { + if (isEA(ea, en)) { + op = (299 << 6) | ea; if (iTab[op].op === -1) { - iTab[op] = mkD(op, 'TAS', 1, ea[1], ea[2], ea[1] == M_rdd ? [4,1,0] : [10,1,1], ea[1] != M_rdd); + var cyc = getEAMode(ea) == M_rdd ? [4,1,0] : addCycs([10,1,1], getEACycs(ea, 1)); + iTab[op] = mkI(op, "TAS", cyc); + iTab[op].p.ea = ea; iTab[op].f = I_TAS; + iTab[op].d = mkDiss(0, false,false, D_EA,ea, 1,0); cnt++; } else { - BUG.say('OP EXISTS TAS ' + op); + SAEF_error("cpu.mkITab() op exists TAS "+op); return false; } } } } - //TRAP - { - var v; - for (v = 0; v < 16; v++) { - op = (1252 << 4) | v; + /*-----------------------------------------------------------------------*/ - if (iTab[op].op === -1) { - iTab[op] = mkD(op, 'TRAP', 0, M_imm, v, [38,4,3], false); - iTab[op].f = I_TRAP; - cnt++; - } else { - BUG.say('OP EXISTS TRAP ' + op); - return false; + //CALLM + if (model == 68020) { + var en = [M_ria, M_rid, M_rii, M_pcid, M_pcii, M_absw, M_absl]; + for (var ea = 0; ea < 61; ea++) { + if (isEA(ea, en)) { + op = (27 << 6) | ea; + if (iTab[op].op === -1) { + iTab[op] = mkI(op, "CALLM", [4,0,0]); //FIXME cycles + iTab[op].p.ea = ea; + iTab[op].f = I_CALLM; + iTab[op].d = mkDiss(0, D_IME,1, D_EA,ea, 0,0); //FIXME + cnt++; + } else { + SAEF_error("cpu.mkITab() op exists CALLM "+op); + return false; + } } } } - //TRAPV - { - op = 0x4E76; - - if (iTab[op].op === -1) { - iTab[op] = mkN(op, 'TRAPV', [4,1,0]); - iTab[op].f = I_TRAPV; - cnt++; - } else { - BUG.say('OP EXISTS TRAPV ' + op); - return false; + //RTM + if (model == 68020) { + for (var da = 0; da < 1; da++) { + for (var Rn = 0; Rn < 8; Rn++) { + op = (108 << 4) | (da << 3) | Rn; + if (iTab[op].op === -1) { + iTab[op] = mkI(op, "RTM", [4,0,0]); //FIXME cycles + iTab[op].p.da = da; + iTab[op].p.Rn = Rn; + iTab[op].f = I_RTM; + iTab[op].d = mkDiss(0, false,false, da ? D_RDD : D_RDA,Rn, 0,0); + cnt++; + } else { + SAEF_error("cpu.mkITab() op exists RTM "+op); + return false; + } + } } } - //TST - { - var en = [M_rdd, M_rda, M_ria, M_ripo, M_ripr, M_rid, M_rii, M_absw, M_absl, M_imm]; - var z, z2, mr, ea; - for (z = 0; z < 3; z++) { - z2 = z == 0 ? 1 : (z == 1 ? 2 : 4); - for (mr = 0; mr < 64; mr++) { - ea = mkEA(mr, en, 0); - if (ea[0] != -1) { - op = (74 << 8) | (z << 6) | ea[0]; + /*-----------------------------------------------------------------------*/ + /* MMU 68851/68030/68040 */ + /* + S PBcc 1 + S PDBcc 1 + S PFLUSH 1 3 4 + S PFLUSHA 1 3 + S PFLUSHR 1 + S PFLUSHS 1 + S PLOAD 1 3 + S PMOVE 1 3 + S PRESTORE 1 + S PSAVE 1 + S PScc 1 + S PTEST 1 3 4 + S PTRAPcc 1 + PVALID 1 */ + if (model == 68030) { + var cid = 0; /* page 4-86: coprocessor ID of 000 is reserved for MMU instructions for the MC68030 */ + var en = [M_ria, M_rid, M_rii, M_absw, M_absl]; + for (var ea = 0; ea < 61; ea++) { + if (isEA(ea, en)) { + op = (15 << 12) | (cid << 9) | ea; + if (iTab[op].op === -1) { + iTab[op] = mkI(op, "MMU", [4,0,0]); //FIXME name, cycles + iTab[op].p.ea = ea; + iTab[op].f = I_MMU; + iTab[op].d = mkDiss(1, D_EA,ea, D_EXT_MMU,false, 0,0); + cnt++; + } else { + SAEF_error("cpu.mkITab() op exists PFLUSH "+op); + return false; + } + } + } + } + + /*-----------------------------------------------------------------------*/ + /* 68040 */ + /* + S CINV (cache) + S CPUSH (cache) + MOVE16 + */ + + /*-----------------------------------------------------------------------*/ + /* Coprocessor 68020/68030 */ + + //cpBcc + if (model == 68020 || model == 68030) { + for (var cid = 0; cid < 8; cid++) { + if (cid == 0 && model == 68030) /* page 4-86: coprocessor ID of 000 is reserved for MMU instructions for the MC68030 */ + continue; + for (var z = 0; z < 2; z++) { + var z2 = z == 0 ? 2 : 4; + for (var ccc = 0; ccc < 64; ccc++) { + op = (15 << 12) | (cid << 9) | (1 << 7) | (z << 6) | ccc; if (iTab[op].op === -1) { - iTab[op] = mkD(op, 'TST', z2, ea[1], ea[2], [4,1,0], ea[1] != M_rdd && ea[1] != M_rda); - iTab[op].f = I_TST; + iTab[op] = mkI(op, "cpBcc", [4,0,0]); //FIXME cycles + iTab[op].p.cid = cid; + iTab[op].p.ccc = ccc; + iTab[op].p.z = z2; + iTab[op].f = I_cpBcc; + iTab[op].d = mkDiss(1 + (z2 == 2 ? 1 : 2), false,false, D_IME_DP,z == 0 ? 0 : 255, z2,0); cnt++; } else { - BUG.say('OP EXISTS TST ' + op); + SAEF_error("cpu.mkITab() op exists cpBcc "+op); return false; } } } } } - //UNLK - { - var An; - - for (An = 0; An < 8; An++) { - op = (2507 << 3) | An; - - if (iTab[op].op === -1) { - iTab[op] = mkS(op, 'UNLK', 0, M_rda, An, [12,3,0], false); - iTab[op].f = I_UNLK; - cnt++; - } else { - BUG.say('OP EXISTS UNLK ' + op); - return false; + //cpDBcc + if (model == 68020 || model == 68030) { + for (var cid = 0; cid < 8; cid++) { + if (cid == 0 && model == 68030) + continue; + for (var dn = 0; dn < 8; dn++) { + op = (15 << 12) | (cid << 9) | (1 << 6) | (1 << 3) | dn; + if (iTab[op].op === -1) { + iTab[op] = mkI(op, "cpDBcc", [4,0,0]); //FIXME cycles + iTab[op].p.cid = cid; + iTab[op].p.dn = dn; + iTab[op].f = I_cpDBcc; + iTab[op].d = mkDiss(2, D_RDD,dn, false,false, 2,0); //FIXME + cnt++; + } else { + SAEF_error("cpu.mkITab() op exists cpDBcc "+op); + return false; + } } } } - - //for (op = 0; op < 0x10000; op++) if (iTab[op].op !== -1 && !(iTab[op].p.cyc || iTab[op].p.cycTaken || iTab[op].p.cycTrue || iTab[op].p.cycFalse || typeof(iTab[op].p.cyc) == 'number')) console.log(iTab[op].mn, iTab[op].p.z); - - BUG.say(sprintf('cpu.mkiTab() build %d instructions', cnt)); + //cpGEN + if (model == 68020 || model == 68030) { + for (var cid = 0; cid < 8; cid++) { + if (cid == 0 && model == 68030) + continue; + for (var ea = 0; ea < 61; ea++) { + op = (15 << 12) | (cid << 9) | ea; + if (iTab[op].op === -1) { + iTab[op] = mkI(op, "cpGEN", [4,0,0]); //FIXME cycles + iTab[op].p.cid = cid; + iTab[op].p.ea = ea; + iTab[op].f = I_cpGEN; + iTab[op].d = mkDiss(2, false,false, false,false, 0,0); //FIXME + cnt++; + } else { + SAEF_error("cpu.mkITab() op exists cpGEN "+op); + return false; + } + } + } + } + //cpRESTORE + if (model == 68020 || model == 68030) { + var en = [M_ria, M_ripo, M_rid, M_rii, M_pcid, M_pcii, M_absw, M_absl, M_imm]; + for (var cid = 0; cid < 8; cid++) { + if (cid == 0 && model == 68030) + continue; + for (var ea = 0; ea < 61; ea++) { + if (isEA(ea, en)) { + op = (15 << 12) | (cid << 9) | (5 << 6) | ea; + if (iTab[op].op === -1) { + iTab[op] = mkI(op, "cpRESTORE", [4,0,0]); //FIXME cycles + iTab[op].p.cid = cid; + iTab[op].p.ea = ea; + iTab[op].f = I_cpRESTORE; + iTab[op].d = mkDiss(0, false,false, D_EA,ea, 0,0); + cnt++; + } else { + SAEF_error("cpu.mkITab() op exists cpRESTORE "+op); + return false; + } + } + } + } + } + //cpSAVE + if (model == 68020 || model == 68030) { + var en = [M_ria, M_ripo, M_rid, M_rii, M_absw, M_absl]; + for (var cid = 0; cid < 8; cid++) { + if (cid == 0 && model == 68030) + continue; + for (var ea = 0; ea < 61; ea++) { + if (isEA(ea, en)) { + op = (15 << 12) | (cid << 9) | (4 << 6) | ea; + if (iTab[op].op === -1) { + iTab[op] = mkI(op, "cpSAVE", [4,0,0]); //FIXME cycles + iTab[op].p.cid = cid; + iTab[op].p.ea = ea; + iTab[op].f = I_cpSAVE; + iTab[op].d = mkDiss(0, false,false, D_EA,ea, 0,0); + cnt++; + } else { + SAEF_error("cpu.mkITab() op exists cpSAVE "+op); + return false; + } + } + } + } + } + //cpScc + if (model == 68020 || model == 68030) { + var en = [M_rdd, M_ria, M_ripo, M_ripr, M_rid, M_rii, M_absw, M_absl]; + for (var cid = 0; cid < 8; cid++) { + if (cid == 0 && model == 68030) + continue; + for (var ea = 0; ea < 61; ea++) { + if (isEA(ea, en)) { + op = (15 << 12) | (cid << 9) | (1 << 6) | ea; + if (iTab[op].op === -1) { + iTab[op] = mkI(op, "cpScc", [4,0,0]); //FIXME cycles + iTab[op].p.cid = cid; + iTab[op].p.ea = ea; + iTab[op].f = I_cpScc; + iTab[op].d = mkDiss(2, false,false, D_EA,ea, 1,0); + cnt++; + } else { + SAEF_error("cpu.mkITab() op exists cpScc "+op); + return false; + } + } + } + } + } + //cpTRAPcc + if (model == 68020 || model == 68030) { + for (var cid = 0; cid < 8; cid++) { + if (cid == 0 && model == 68030) + continue; + for (var opm = 2; opm <= 4; opm++) { + var z2 = opm == 2 ? 2 : (opm = 3 ? 4 : 0); + op = (15 << 12) | (cid << 9) | (1 << 6) | (7 << 3) | opm; + if (iTab[op].op === -1) { + iTab[op] = mkI(op, "cpTRAPcc", [4,0,0]); //FIXME cycles + iTab[op].p.cid = cid; + iTab[op].p.opm = opm; + iTab[op].f = I_cpTRAPcc; + iTab[op].d = mkDiss(1 + (z2 == 1 ? 0 : (z2 == 2 ? 2 : 4)), false,false, false,false, z2,0); //FIXME + cnt++; + } else { + SAEF_error("cpu.mkITab() op exists cpTRAPcc "+op); + return false; + } + } + } + } + + //cpXXX + /*if (model == 68020 || model == 68030) { + for (var cid = 0; cid < 8; cid++) { + if (cid == 0 && model == 68030) + continue; + for (var args = 0; args < 512; args++) { + op = (15 << 12) | (cid << 9) | args; + if (iTab[op].op === -1) { + iTab[op] = mkI(op, "cpXXX", [4,0,0]); //FIXME cycles + iTab[op].p.cid = cid; + iTab[op].p.args = args; + iTab[op].f = I_cpXXX; + iTab[op].d = mkDiss(0, false,false, false,false, 0,0); //FIXME + cnt++; + } else { + SAEF_error("cpu.mkITab() op exists cpXXX "+op); + return false; + } + } + } + }*/ + + /*-----------------------------------------------------------------------*/ + + if (typeof SAER != "undefined") + SAEF_log("cpu.mkiTab() %d instructions created", cnt); + return true; } - /* ...end of the fun part. */ - - /*-----------------------------------------------------------------------*/ - /*-----------------------------------------------------------------------*/ - /*-----------------------------------------------------------------------*/ - - function printIdx(base, ar, pc) { - var ext = AMIGA.mem.load16(pc); - var disp = castByte(ext & 0xff); - var r = (ext & 0x7000) >>> 12; - var idx = (ext & 0x8000) ? regs.a[r] : regs.d[r]; - if (ext & 0x800) idx = castLong(idx); - else idx = castWord(idx & 0xffff); - var addr = (base + disp + idx); - if (ar != -1) - return sprintf('(%d,A%d,%s%d)[$%08x]', disp, ar, (ext & 0x8000) ? 'A' : 'D', r, addr); - else - return sprintf('(%d,PC,%s%d)[$%08x]', disp, (ext & 0x8000) ? 'A' : 'D', r, addr); - } - - function printEA(ea, z, m, pc) { - var dp, o = ' '; - - switch (ea.m) { - case M_rdd: - o += sprintf('D%d', ea.r); - break; - case M_rda: - o += sprintf('A%d', ea.r); - break; - case M_ria: - o += sprintf('(A%d)', ea.r); - break; - case M_ripo: - o += sprintf('(A%d)+', ea.r); - break; - case M_ripr: - o += sprintf('-(A%d)', ea.r); - break; - case M_rid: - dp = castWord(AMIGA.mem.load16(pc)); pc += 2; - o += sprintf('$%04x(A%d)[$%08x]', dp, ea.r, regs.a[ea.r] + dp); - break; - case M_rii: - o += printIdx(regs.a[ea.r], ea.r, pc); - break; - case M_pcid: - dp = castWord(AMIGA.mem.load16(pc)); - o += sprintf('$%04x(PC)[$%08x]', dp, pc + dp); - pc += 2; - break; - case M_pcii: - o += printIdx(pc, -1, pc); pc += 2; - break; - case M_absw: - dp = castWord(AMIGA.mem.load16(pc)); pc += 2; - o += sprintf('($%04x)', dp); - break; - case M_absl: - dp = AMIGA.mem.load32(pc); pc += 4; - o += sprintf('($%08x)', dp); - break; - case M_imm: { - if (ea.r == -1) { - switch (z) { - case 1: - dp = castByte(AMIGA.mem.load16(pc)); pc += 2; - o += sprintf('#$%02x', dp & 0xff); - break; - case 2: - dp = castWord(AMIGA.mem.load16(pc)); pc += 2; - o += sprintf('#$%04x', dp); - break; - case 4: - dp = castLong(AMIGA.mem.load32(pc)); pc += 4; - o += sprintf('#$%08x', dp); - break; - } - } else - o += sprintf('#$%02x', castByte(ea.r)); - break; - } - case M_list: - dp = AMIGA.mem.load16(pc); pc += 2; - o += sprintf('#$%04x', dp) + ' ['+regsStr(dp, m == M_ripr)+']'; - break; - } - return [o, pc]; - } - - function printC(c, pc) { - var o = ' '; - - if (c.dp != -1) { - if (c.dp == 0) { - var dp = castWord(AMIGA.mem.load16(pc)); - o += sprintf('$%08x', pc + dp); - pc += 2; - } - /*else if (c.dp == 0xff) { //68020 - var dp = castLong(AMIGA.mem.load32(pc)); - o += sprintf('$%08x', pc + dp); - pc += 4; - }*/ - else { - var dp = castByte(c.dp); - o += sprintf('$%08x', pc + dp); - } - } else { - var dp = castWord(AMIGA.mem.load16(pc)); - o += sprintf('D%d,$%08x', c.dr, pc + dp); - pc += 2; - } - return [o, pc]; - } - - function printI(i, pc) { - var o = i.mn; - - if (o == 'ILLEGAL') return [o, pc]; - - if (i.p.z) o += '.' + szChr(i.p.z); - o += ' '; - if (i.p.s) { - var ip = printEA(i.p.s, i.p.z, i.p.d ? i.p.d.m : 0, pc); - o += ip[0]; - pc = ip[1]; - } - if (i.p.s && i.p.d) o += ','; - if (i.p.d) { - var ip = printEA(i.p.d, i.p.z, i.p.s ? i.p.s.m : 0, pc); - o += ip[0]; - pc = ip[1]; - } - if (i.p.c) { - var ip = printC(i.p.c, pc); - o += ip[0]; - pc = ip[1]; - } - return [o, pc]; - } - - this.diss = function (offset, limit) { - var pc = offset === null ? regs.pc : offset; - var cnt = 0; - - while (cnt++ < limit) { - var o = ''; - - o += sprintf('$%08x: ', pc); - for (var i = 0; i < 5; i++) - o += sprintf('$%04x ', AMIGA.mem.load16(pc + i * 2)); - - var op = AMIGA.mem.load16(pc); - pc += 2; - - var ip = printI(iTab[op], pc); - o += ip[0]; - pc = ip[1]; - - BUG.say(o); - } - }; - /*this.dissFault = function (limit) { - this.diss(fault.pc, limit); - };*/ - - /*function nextIWordData(data, pc) { - return (data[pc] << 8) | data[pc + 1]; - } - function nextILongData(data, pc) { - return (data[pc] << 24) | (data[pc + 1] << 16) | (data[pc + 2] << 8) | data[pc + 3]; - } - function printIdxData(data, base, ar, pc) { - var ext = nextIWordData(data, pc); - var dp8 = castByte(ext & 0xff); - var r = (ext & 0x7000) >>> 12; - var idx = (ext & 0x8000) ? regs.a[r] : regs.d[r]; - if (ext & 0x800) idx = castLong(idx); - else idx = castWord(idx & 0xffff); - //dispreg <<= (dp >> 9) & 3; //68020 - var addr = (base + dp8 + idx); - if (ar != -1) - //return sprintf('(A%d,%s%d,%02x[$%08x][%s])', ar, (dp & 0x8000)?'A':'D', r, disp8, addr, (dp & 0x800)?'L':'W'); - return sprintf('(%d,A%d,%s%d)[$%08x]', dp8, ar, (ext & 0x8000) ? 'A' : 'D', r, addr); - else - //return sprintf('(PC($%08x),%s%d,%02x[$%08x][%s])', base, (dp & 0x8000)?'A':'D', r, disp8, addr, (dp & 0x800)?'L':'W'); - return sprintf('(%d,PC,%s%d)[$%08x]', dp8, (ext & 0x8000) ? 'A' : 'D', r, addr); - } - - function printEAData(data, ea, z, pc) { - var dp, o = ' '; - - switch (ea.m) { - case M_rdd: - o += sprintf('D%d', ea.r); - break; - case M_rda: - o += sprintf('A%d', ea.r); - break; - case M_ria: - o += sprintf('(A%d)', ea.r); - break; - case M_ripo: - o += sprintf('(A%d)+', ea.r); - break; - case M_ripr: - o += sprintf('-(A%d)', ea.r); - break; - case M_rid: - dp = castWord(nextIWordData(data, pc)); pc += 2; - o += sprintf('($%04x,A%d)[$%08x]', dp, ea.r, regs.a[ea.r] + dp); - break; - case M_rii: - o += printIdxData(data, regs.a[ea.r], ea.r, pc); - break; - case M_pcid: - dp = castWord(nextIWordData(data, pc)); pc += 2; - o += sprintf('($%04x,PC)[$%08x]', dp, pc + dp); - break; - case M_pcii: - o += printIdxData(data, pc, - 1, pc); pc += 2; - break; - case M_absw: - dp = nextIWordData(data, pc); pc += 2; - o += sprintf('($%04x).W', dp); - break; - case M_absl: - dp = nextILongData(data, pc); pc += 4; - o += sprintf('($%08x).L', dp); - break; - case M_imm: { - if (ea.r == -1) { - switch (z) { - case 1: - dp = castByte(nextIWordData(data, pc)); pc += 2; - o += sprintf('#<$%02x>', dp & 0xff); - break; - case 2: - dp = castWord(nextIWordData(data, pc)); pc += 2; - o += sprintf('#<$%04x>', dp); - break; - case 4: - dp = castLong(nextILongData(data, pc)); pc += 4; - o += sprintf('#<$%08x>', dp); - break; - } - } else - o += sprintf('#<$%02x>', castByte(ea.r)); - break; - } - case M_list: - dp = nextIWordData(data, pc); pc += 2; - o += sprintf('[$%04x]', dp); - break; - } - return [o, pc]; - } - - function printCData(data, c, pc) { - var o = ' '; - - if (c.dp != -1) { - if (c.dp == 0) { - var dp = castWord(nextIWordData(data, pc)); - o += sprintf('$%08x', pc + dp); - pc += 2; - } - else { - var dp = castByte(c.dp); - o += sprintf('$%08x', pc + dp); - } - } else { - var dp = castWord(nextIWordData(data, pc)); - o += sprintf('D%d,$%08x', c.dr, pc + dp); - pc += 2; - } - return [o, pc]; - } - - function printIData(data, i, pc) { - var o = i.mn; - - if (o == 'ILLEGAL') return [o, pc]; - - if (i.p.z) o += '.' + szChr(i.p.z); - o += ' '; - if (i.p.s) { - var ip = printEAData(data, i.p.s, i.p.z, pc); - o += ip[0]; - pc = ip[1]; - } - if (i.p.s && i.p.d) o += ','; - if (i.p.d) { - var ip = printEAData(data, i.p.d, i.p.z, pc); - o += ip[0]; - pc = ip[1]; - } - if (i.p.c) { - var ip = printCData(data, i.p.c, pc); - o += ip[0]; - pc = ip[1]; - } - return [o, pc]; - } - this.dissData = function (data, limit) { - var pc = 0; - var cnt = 0; - - while (cnt++ < limit) { - var o = ''; - - o += sprintf('$%08x: ', pc); - for (var i = 0; i < 5; i++) - o += sprintf('$%04x ', nextIWordData(data, pc+i*2)); - - var op = nextIWordData(data, pc); - pc += 2; - - var ip = printIData(data, iTab[op], pc); - o += ip[0]; - pc = ip[1]; - - BUG.say(o); - } - }*/ - - function getName(addr) - { - var c, p = 0, n = ''; - while ((c = AMIGA.mem.load8(addr + p))) { - n += String.fromCharCode(c); - if (p++ > 100) return ''; - } - return n; - } - - function getTaskName(task) { - return getName(AMIGA.mem.load32(task + 10)); - } - - this.getThisTaskName = function () { - var tn = ''; - /* Extract current task-name form SysBase */ - var sysBase = AMIGA.mem.load32(4); - if (sysBase == 0x000676 || sysBase == 0xc00276 || sysBase == 0xc00a88 || sysBase == 0xc00560) { - var thisTask = AMIGA.mem.load32(sysBase + 276); - if (thisTask) - tn = getTaskName(thisTask); - } - return tn; - }; - - this.dump = function () { - var i, out = '', tn = 1 ? this.getThisTaskName() : ''; - - for (i = 0; i < 8; i++) { - out += sprintf('D%d $%08x ', i, regs.d[i]); //if ((i & 3) == 3) out += '
'; - } - //out += '
'; - out += "\n"; - for (i = 0; i < 8; i++) { - out += sprintf('A%d $%08x ', i, regs.a[i]); //if ((i & 3) == 3) out += '
'; - } - //out += '
'; - out += "\n"; - out += sprintf('PC $%08x USP $%08x ISP $%08x ', regs.pc, regs.usp, regs.isp); - out += sprintf('T=%d S=%d X=%d N=%d Z=%d V=%d C=%d IMASK=%d, LTASK=%s', regs.t ? 1 : 0, regs.s ? 1 : 0, regs.x ? 1 : 0, regs.n ? 1 : 0, regs.z ? 1 : 0, regs.v ? 1 : 0, regs.c ? 1 : 0, regs.intmask, tn); - out += "\n"; - out += "\n"; - BUG.say(out); - }; - - /*-----------------------------------------------------------------------*/ - /*-----------------------------------------------------------------------*/ - /*-----------------------------------------------------------------------*/ - - /*function superState() - { - if (!regs.s) { - regs.s = true; - //regs.t = false; - var temp = regs.usp; - regs.usp = regs.a[7]; - regs.a[7] = temp; - BUG.col = 2; - } - } - - function userState(s) - { - if (s) { - var temp = regs.usp; - regs.usp = regs.a[7]; - regs.a[7] = temp; - BUG.col = 1; - } - }*/ - - function getCCR() { - return (((regs.x ? 1 : 0) << 4) | ((regs.n ? 1 : 0) << 3) | ((regs.z ? 1 : 0) << 2) | ((regs.v ? 1 : 0) << 1) | (regs.c ? 1 : 0)); - } - - function setCCR(ccr) { - regs.x = ((ccr >> 4) & 1) == 1; - regs.n = ((ccr >> 3) & 1) == 1; - regs.z = ((ccr >> 2) & 1) == 1; - regs.v = ((ccr >> 1) & 1) == 1; - regs.c = (ccr & 1) == 1; - } - - function getSR() { - return (((regs.t ? 1 : 0) << 15) | ((regs.s ? 1 : 0) << 13) | (regs.intmask << 8) | ((regs.x ? 1 : 0) << 4) | ((regs.n ? 1 : 0) << 3) | ((regs.z ? 1 : 0) << 2) | ((regs.v ? 1 : 0) << 1) | (regs.c ? 1 : 0)); - } - - function setSR(sr) { - regs.x = ((sr >> 4) & 1) == 1; - regs.n = ((sr >> 3) & 1) == 1; - regs.z = ((sr >> 2) & 1) == 1; - regs.v = ((sr >> 1) & 1) == 1; - regs.c = (sr & 1) == 1; - - var t = ((sr >> 15) & 1) == 1; - var s = ((sr >> 13) & 1) == 1; - var intmask = ((sr >> 8) & 7); - - if (regs.t == t && regs.s == s && regs.intmask == intmask) { - //BUG.say('cpu.setSR() mode ok!'); - return; - } - - var olds = regs.s; - regs.t = t; - regs.s = s; - regs.intmask = intmask; - - if (regs.s != olds) { - //BUG.say(sprintf('cpu.setSR() mode switch %s', olds ? 'userstate' : 'superstate')); - //userState(olds); - - if (olds) { - regs.isp = regs.a[7]; - regs.a[7] = regs.usp; - - BUG.col = 1; - } else { - BUG.say('cpu.setSR() mode switch to superstate!'); - - regs.usp = regs.a[7]; - regs.a[7] = regs.isp; - - BUG.col = 2; - } - } - - AMIGA.doint(); - //if (regs.t1 || regs.t0) - if (regs.t) - set_special(SPCFLAG_TRACE); - else - /* Keep SPCFLAG_DOTRACE, we still want a trace exception for SR-modifying instructions (including STOP). */ - clr_special(SPCFLAG_TRACE); - } - - function setPC(pc) { - if (pc & 1) { - BUG.say(sprintf('cpu.setPC() ADDRESS ERROR pc $%08x', pc)); - AMIGA.cpu.diss(fault.pc, 1); - //AMIGA.cpu.dump(); - exception3(pc, 0); - } - else if (pc > 0xffffff) { - BUG.say(sprintf('cpu.setPC() BUS ERROR, $%08x > 24bit, reducing address to $%08x', pc, pc & 0xffffff)); - AMIGA.cpu.diss(fault.pc, 1); - //AMIGA.cpu.dump(); - //exception2(pc, 0); - pc &= 0xffffff; - } - else if (pc < 4) { - BUG.say(sprintf('cpu.setPC() BUS ERROR pc $%08x', pc)); - AMIGA.cpu.diss(fault.pc, 1); - //AMIGA.cpu.dump(); - //exception2(pc, 0); - //AMIGA.state = 0; - } - regs.pc = pc; - } - - function exception_trace(n) { - clr_special(SPCFLAG_TRACE | SPCFLAG_DOTRACE); - //if (regs.t1 && !regs.t0) { - if (regs.t) { - /* trace stays pending if exception is div by zero, chk, trapv or trap #x */ - if (n == 5 || n == 6 || n == 7 || (n >= 32 && n <= 47)) - set_special(SPCFLAG_DOTRACE); - } - //regs.t1 = regs.t0 = regs.m = 0; - regs.t = 0; - } - - /*function exception_cycles(n) { - var c; - if (n < 16) - switch (n) { - case 0: c = [40,6,0]; break; //Reset Initial Interrupt Stack Pointer - case 1: c = [40,6,0]; break; //Reset Initial Program Counter - case 2: c = [50,4,7]; break; //Access Fault - case 3: c = [50,4,7]; break; //Address Error - case 4: c = [34,4,3]; break; //Illegal Instruction - case 5: c = [42,5,3]; break; //Integer Divide by Zero - case 6: c = [44,5,3]; break; //CHK, CHK2 Instruction - case 7: c = [34,4,3]; break; //FTRAPcc, TRAPcc, TRAPV Instructions - case 8: c = [34,4,3]; break; //Privilege Violation - case 9: c = [34,4,3]; break; //Trace - case 10: c = [34,4,3]; break; //Line 1010 Emulator (Unimplemented A- Line Opcode) - case 11: c = [34,4,3]; break; //Line 1111 Emulator (Unimplemented F-Line Opcode) - } - else if (n >= 24 && n < 32) - c = [44+4,5,3]; - else if (n >= 32 && n < 48) - c = [38,4,3]; - else { - BUG.say(sprintf('cpu.exception() no cycle for %d', n)); - c = [4,0,0]; - } - return c; - }*/ - - function exception(n) { - //BUG.say(sprintf('cpu.exception() nr %d', n)); - var olds = regs.s; - - if (n >= 24 && n < 24 + 8) { - var oldn = n; - n = AMIGA.mem.load8(0x00fffff1 | (n << 1)); - if (n != oldn) BUG.say(sprintf('cpu.exception() exception from %d to %d', oldn, n)); - } - - var sr = getSR(); - //superState(); - if (!regs.s) { - regs.s = true; - regs.usp = regs.a[7]; - regs.a[7] = regs.isp; - - BUG.col = 2; - } - - if (n == 2) { - BUG.say(sprintf('cpu.exception() %d, regs.pc $%08x, fault.pc $%08x, fault.op $%04x, fault.ad $%08x, fault.ia %d', n, regs.pc, fault.pc, fault.op, fault.ad, fault.ia ? 1 : 0)); - - stEA(exEA(new EffAddr(M_ripr, 7), 4), 4, regs.pc); - stEA(exEA(new EffAddr(M_ripr, 7), 2), 2, sr); - } else if (n == 3) { - BUG.say(sprintf('cpu.exception() %d, regs.pc $%08x, fault.pc $%08x, fault.op $%04x, fault.ad $%08x, fault.ia %d', n, regs.pc, fault.pc, fault.op, fault.ad, fault.ia ? 1 : 0)); - - var ia = fault.ia; - var wa = 0; - var cd = (wa ? 0 : 16) | (olds ? 4 : 0) | (ia ? 2 : 1); - - stEA(exEA(new EffAddr(M_ripr, 7), 4), 4, fault.pc); - stEA(exEA(new EffAddr(M_ripr, 7), 2), 2, sr); - stEA(exEA(new EffAddr(M_ripr, 7), 2), 2, fault.op); - stEA(exEA(new EffAddr(M_ripr, 7), 4), 4, fault.ad); - stEA(exEA(new EffAddr(M_ripr, 7), 2), 2, cd); - } else { - stEA(exEA(new EffAddr(M_ripr, 7), 4), 4, regs.pc); - stEA(exEA(new EffAddr(M_ripr, 7), 2), 2, sr); - } - - var pc = AMIGA.mem.load32(n * 4); - if (pc & 1) { - BUG.say(sprintf('cpu.exception() ADDRESS ERROR pc $%08x', pc)); - if (n == 2 || n == 3) { - AMIGA.reset(); - throw new Error('double address/bus-error'); - } else - exception3(pc, 0); - } - /*else if (pc > 0xffffff) { - BUG.say(sprintf('cpu.exception() BUS ERROR pc $%08x', pc)); - //AMIGA.cpu.diss(fault.pc, 1); - //AMIGA.cpu.dump(); - exception2(pc, 0); - }*/ - regs.pc = pc; - - exception_trace(n); - return [4,0,0];//exception_cycles(n); - } - - /*function exception2(ad) { - fault.ad = ad; - fault.ia = 0; - throw new Exception23(2); - }*/ - - function exception3(ad, ia) { - fault.ad = ad; - fault.ia = ia; - throw new Exception23(3); - } - - function interrupt(nr) { - regs.stopped = false; - clr_special(SPCFLAG_STOP); - //assert(nr < 8 && nr >= 0); - - exception(nr + 24); - - regs.intmask = nr; - AMIGA.doint(); - } - - function cycle_spc(cycles) { - if (AMIGA.spcflags & SPCFLAG_COPPER) - AMIGA.copper.cycle(); - - while ((AMIGA.spcflags & SPCFLAG_BLTNASTY) && AMIGA.dmaen(DMAF_BLTEN) && cycles > 0) { - var c = AMIGA.blitter.blitnasty(); - //console.log('nasty', cycles, c); - if (c > 0) { - cycles -= c * CYCLE_UNIT * 2; - if (cycles < CYCLE_UNIT) - cycles = 0; - } else - c = 4; - - AMIGA.events.cycle(c * CYCLE_UNIT); - if (AMIGA.spcflags & SPCFLAG_COPPER) - AMIGA.copper.cycle(); - } - - if (AMIGA.spcflags & SPCFLAG_DOTRACE) - exception(9); - - if (AMIGA.spcflags & SPCFLAG_TRAP) { - clr_special(SPCFLAG_TRAP); - exception(3); - } - - while (AMIGA.spcflags & SPCFLAG_STOP) { - AMIGA.events.cycle(4 * CYCLE_UNIT); - - if (AMIGA.spcflags & SPCFLAG_COPPER) - AMIGA.copper.cycle(); - - if (AMIGA.spcflags & (SPCFLAG_INT | SPCFLAG_DOINT)) { - clr_special(SPCFLAG_INT | SPCFLAG_DOINT); - var intr = AMIGA.intlev(); - if (intr > 0 && intr > regs.intmask) - interrupt(intr); - } - //if (AMIGA.spcflags & SPCFLAG_BRK) { - if (AMIGA.state != ST_CYCLE) { - //clr_special(SPCFLAG_BRK); - clr_special(SPCFLAG_STOP); - regs.stopped = false; - return true; - } - } - - if (AMIGA.spcflags & SPCFLAG_TRACE) { - if (regs.t) { - clr_special(SPCFLAG_TRACE); - set_special(SPCFLAG_DOTRACE); - } - } - - if (AMIGA.spcflags & SPCFLAG_INT) { - clr_special(SPCFLAG_INT | SPCFLAG_DOINT); - var intr = AMIGA.intlev(); - if (intr > 0 && intr > regs.intmask) - interrupt(intr); - } - if (AMIGA.spcflags & SPCFLAG_DOINT) { - clr_special(SPCFLAG_DOINT); - set_special(SPCFLAG_INT); - } - /*if (AMIGA.spcflags & SPCFLAG_BRK) { - clr_special(SPCFLAG_BRK); - return true; - }*/ - return false; - } - - this.cycle = function() { - while (AMIGA.state == ST_CYCLE) { - AMIGA.events.cycle(cpu_cycles); - - var op = nextOPCode(); - try { - var cycles = iTab[op].f(iTab[op].p); - cpu_cycles = cycles[0] * cpu_cycle_unit; - } catch (e) { - if (e instanceof Exception23) { - //BUG.info('cpu.cycle_real() USER EXCEPTION [%d]', e.num); - var cycles = exception(e.num); - cpu_cycles = cycles[0] * cpu_cycle_unit; - } - else if (e instanceof VSync) { - //BUG.info('cpu.cycle_real() VSYNC [%s]', e); - cpu_cycles = 48 * cpu_cycle_unit; - throw new VSync(e.error, e.message); - } - else if (e instanceof FatalError) { - //BUG.info('cpu.cycle_real() FATAL ERROR [%s]', e); - Fatal(e.error, e.message); - } - else { - Fatal(SAEE_CPU_Internal, e.message); - } - } - - if (AMIGA.spcflags) - cycle_spc(cpu_cycles); - } - } } + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/sae/custom.js b/sae/custom.js index fe63871..4ba3d70 100644 --- a/sae/custom.js +++ b/sae/custom.js @@ -1,728 +1,888 @@ -/************************************************************************** -* SAE - Scripted Amiga Emulator -* -* 2012-2015 Rupert Hausberger -* -* https://github.com/naTmeg/ScriptedAmigaEmulator -* -**************************************************************************/ +/*------------------------------------------------------------------------- +| SAE - Scripted Amiga Emulator +| https://github.com/naTmeg/ScriptedAmigaEmulator +| +| Copyright (C) 2012-2016 Rupert Hausberger +| +| This program is free software; you can redistribute it and/or +| modify it under the terms of the GNU General Public License +| as published by the Free Software Foundation; either version 2 +| of the License, or (at your option) any later version. +| +| This program is distributed in the hope that it will be useful, +| but WITHOUT ANY WARRANTY; without even the implied warranty of +| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +| GNU General Public License for more details. +| +| Note: ported from WinUAE 3.2.x +-------------------------------------------------------------------------*/ +/* global constants */ -function Custom() { - this.last_value = 0; +const SAEC_Custom_DMAF_AUD0EN = 1 << 0; +const SAEC_Custom_DMAF_AUD1EN = 1 << 1; +const SAEC_Custom_DMAF_AUD2EN = 1 << 2; +const SAEC_Custom_DMAF_AUD3EN = 1 << 3; +const SAEC_Custom_DMAF_DSKEN = 1 << 4; +const SAEC_Custom_DMAF_SPREN = 1 << 5; +const SAEC_Custom_DMAF_BLTEN = 1 << 6; +const SAEC_Custom_DMAF_COPEN = 1 << 7; +const SAEC_Custom_DMAF_BPLEN = 1 << 8; +const SAEC_Custom_DMAF_DMAEN = 1 << 9; +const SAEC_Custom_DMAF_BLTPRI = 1 << 10; +const SAEC_Custom_DMAF_BZERO = 1 << 13; +const SAEC_Custom_DMAF_BBUSY = 1 << 14; +const SAEC_Custom_DMAF_SETCLR = 1 << 15; + +const SAEC_Custom_INTF_TBE = 1 << 0; +const SAEC_Custom_INTF_DSKBLK = 1 << 1; +//const SAEC_Custom_INTF_PORTS = 1 << 3; +//const SAEC_Custom_INTF_COPER = 1 << 4; +const SAEC_Custom_INTF_VERTB = 1 << 5; +const SAEC_Custom_INTF_BLIT = 1 << 6; +//const SAEC_Custom_INTF_AUD0 = 1 << 7; +//const SAEC_Custom_INTF_AUD1 = 1 << 8; +//const SAEC_Custom_INTF_AUD2 = 1 << 9; +//const SAEC_Custom_INTF_AUD3 = 1 << 10; +const SAEC_Custom_INTF_RBF = 1 << 11; +const SAEC_Custom_INTF_DSKSYN = 1 << 12; +//const SAEC_Custom_INTF_EXTER = 1 << 13; +const SAEC_Custom_INTF_INTEN = 1 << 14; +const SAEC_Custom_INTF_SETCLR = 1 << 15; + +/*---------------------------------*/ +/* global references */ + +var SAER_Custom_put16_real = null; + +/*---------------------------------*/ +/* global variables */ + +var SAEV_Custom_bank = null; + +var SAEV_Custom_dmacon = 0; +var SAEV_Custom_intreq = 0; +var SAEV_Custom_intena = 0; +var SAEV_Custom_adkcon = 0; +var SAEV_Custom_last_value = 0; + +/*---------------------------------*/ +/* global functions */ + +function SAEF_Custom_dmaen(dmamask) { + return (SAEV_Custom_dmacon & dmamask) != 0 && (SAEV_Custom_dmacon & SAEC_Custom_DMAF_DMAEN) != 0; +} + +/*---------------------------------*/ + +function SAEO_Custom() { + var readMap = null; + var writeMap = null; + + //var last_custom_value = 0; -> SAEV_Custom_last_value + + //var dmacon = 0; -> SAEV_Custom_dmacon + //var intreq = 0; -> SAEV_Custom_intreq + //var intena = 0; -> SAEV_Custom_intena + //var adkcon = 0; -> SAEV_Custom_adkcon + var intreq_internal = 0; + var intena_internal = 0; + + const INT_PROCESSING_DELAY = 3 * SAEC_Events_CYCLE_UNIT; + + /*-----------------------------------------------------------------------*/ this.setup = function () { - }; + createReadMap(); + createWriteMap(); + } this.reset = function () { - }; + SAEV_Custom_dmacon = 0; + SAEV_Custom_intena = intena_internal = 0; + intreq_internal = 0; + } - /*---------------------------------*/ - - this.load16_real = function (hpos, addr, noput) { - var writeonly = false; - var v; + /*-----------------------------------------------------------------------*/ - addr &= 0xfff; + function DMACONR(hpos) { + SAER.playfield.decide_line(hpos); + SAER.playfield.decide_fetch_safe(hpos); + SAEV_Custom_dmacon &= ~(0x4000 | 0x2000); + SAEV_Custom_dmacon |= (((SAEV_Blitter_interrupt || (!SAEV_Blitter_interrupt && SAEV_config.chipset.agnusBltBusyBug && !SAER_Blitter_blt_info.got_cycle)) ? 0 : 0x4000) | (SAER_Blitter_blt_info.blitzero ? 0x2000 : 0)); + return SAEV_Custom_dmacon; + } + function DMACON(v, hpos) { + var oldcon = SAEV_Custom_dmacon; - switch (addr & 0x1fe) { - case 0x002: - v = AMIGA.DMACONR(hpos); - break; - case 0x004: - v = AMIGA.playfield.VPOSR(); - break; - case 0x006: - v = AMIGA.playfield.VHPOSR(); - break; + SAER.playfield.decide_line(hpos); + SAER.playfield.decide_fetch_safe(hpos); - case 0x00A: - v = AMIGA.input.JOY0DAT(); - break; - case 0x00C: - v = AMIGA.input.JOY1DAT(); - break; - case 0x00E: - v = AMIGA.playfield.CLXDAT(); - break; - case 0x010: - v = AMIGA.ADKCONR(); - break; + if (v & 0x8000) SAEV_Custom_dmacon |= v & 0x7FFF; else SAEV_Custom_dmacon &= ~v; + SAEV_Custom_dmacon &= 0x07FF; - case 0x012: - v = AMIGA.input.POT0DAT(); - break; - case 0x014: - v = AMIGA.input.POT1DAT(); - break; - case 0x016: - v = AMIGA.input.POTGOR(); - break; - case 0x018: - v = AMIGA.serial.SERDATR(); - break; - case 0x01A: - v = AMIGA.disk.DSKBYTR(hpos); - break; - case 0x01C: - v = AMIGA.INTENAR(); - break; - case 0x01E: - v = AMIGA.INTREQR(); - break; - case 0x07C: - { - var result = AMIGA.playfield.DENISEID(); - if (result[0]) - writeonly = true; - else - v = result[1]; - break; + var changed = SAEV_Custom_dmacon ^ oldcon; + var oldcop = (oldcon & SAEC_Custom_DMAF_COPEN) != 0 && (oldcon & SAEC_Custom_DMAF_DMAEN) != 0; + var newcop = (SAEV_Custom_dmacon & SAEC_Custom_DMAF_COPEN) != 0 && (SAEV_Custom_dmacon & SAEC_Custom_DMAF_DMAEN) != 0; + + if (oldcop != newcop) { + if (newcop && !oldcop) { + SAER.copper.compute_spcflag_copper(hpos); + } else if (!newcop) { + SAER.copper.copper_stop(); } - - /*#ifdef AGA - case 0x180: case 0x182: case 0x184: case 0x186: case 0x188: case 0x18A: - case 0x18C: case 0x18E: case 0x190: case 0x192: case 0x194: case 0x196: - case 0x198: case 0x19A: case 0x19C: case 0x19E: case 0x1A0: case 0x1A2: - case 0x1A4: case 0x1A6: case 0x1A8: case 0x1AA: case 0x1AC: case 0x1AE: - case 0x1B0: case 0x1B2: case 0x1B4: case 0x1B6: case 0x1B8: case 0x1BA: - case 0x1BC: case 0x1BE: - if (!(AMIGA.config.chipset.mask & CSMASK_AGA)) - writeonly = true; - v = COLOR_READ ((addr & 0x3E) >> 1); - break; - #endif*/ - - default: - writeonly = true; } - if (writeonly) { - v = this.last_value; - if (!noput) { - var l = 0xffff; //AMIGA.config.cpu.compatible && AMIGA.config.cpu.model == 68000 ? regs.irc : 0xffff; - AMIGA.playfield.decide_line(hpos); - AMIGA.playfield.decide_fetch(hpos); + if ((SAEV_Custom_dmacon & SAEC_Custom_DMAF_BLTPRI) > (oldcon & SAEC_Custom_DMAF_BLTPRI) && SAEV_Blitter_bltstate != SAEC_Blitter_bltstate_DONE) + SAEF_setSpcFlags(SAEC_spcflag_BLTNASTY); - var r = this.store16_real(hpos, addr, l, 1); - if (r) { /* register don't exist */ - if (AMIGA.config.chipset.mask & CSMASK_ECS_AGNUS) { - v = l; - } else { - if ((addr & 0x1fe) == 0) { - /*if (is_cycle_ce()) - v = this.last_value; - else*/ - v = l; - } - } + if (SAEF_Custom_dmaen(SAEC_Custom_DMAF_BLTEN) && SAEV_Blitter_bltstate == SAEC_Blitter_bltstate_INIT) + SAER.blitter.blitter_check_start(); + + if ((SAEV_Custom_dmacon & (SAEC_Custom_DMAF_BLTPRI | SAEC_Custom_DMAF_BLTEN | SAEC_Custom_DMAF_DMAEN)) != (SAEC_Custom_DMAF_BLTPRI | SAEC_Custom_DMAF_BLTEN | SAEC_Custom_DMAF_DMAEN)) + SAEF_clrSpcFlags(SAEC_spcflag_BLTNASTY); + + if (changed & (SAEC_Custom_DMAF_DMAEN | 0x0f)) + SAER.audio.state_machine(); + + if (changed & (SAEC_Custom_DMAF_DMAEN | SAEC_Custom_DMAF_BPLEN)) + SAER.playfield.set_bitplane_maybe_start_hpos(hpos); + } + + /*---------------------------------*/ + + function INTREQR() { + return SAEV_Custom_intreq; + } + this.INTREQ_0 = function(v) { + var old = SAEV_Custom_intreq; + + if (v & 0x8000) SAEV_Custom_intreq |= v & 0x7FFF; else SAEV_Custom_intreq &= ~v; + + //if ((old & 0x0800) && !(SAEV_Custom_intreq & 0x0800)) serial_rbf_clear(); + + var old2 = intreq_internal; + intreq_internal = SAEV_Custom_intreq; + if (old == SAEV_Custom_intreq && old2 == intreq_internal) + return false; + if (v & 0x8000) + SAER.m68k.doint(); + return true; + } + this.INTREQ = function(v) { + if (this.INTREQ_0(v)) { + //serial_check_irq(); + SAER.devices.rethink(); + } + } + + /*---------------------------------*/ + + function INTENAR() { + return SAEV_Custom_intena; + } + function INTENA(v, hpos) { + var old = SAEV_Custom_intena; + + if (v & 0x8000) SAEV_Custom_intena |= v & 0x7FFF; else SAEV_Custom_intena &= ~v; + + if (!(v & 0x8000) && old == SAEV_Custom_intena && SAEV_Custom_intena == intena_internal) + return; + + intena_internal = SAEV_Custom_intena; + if (v & 0x8000) + SAER.m68k.doint(); + } + + /*---------------------------------*/ + + function ADKCONR() { + return SAEV_Custom_adkcon; + } + function ADKCON(v, hpos) { + if (SAEV_config.audio.mode != SAEC_Config_Audio_Mode_Off) + SAER.audio.update(); + + SAER.disk.update(hpos); + SAER.disk.update_adkcon(hpos, v); + + if (v & 0x8000) SAEV_Custom_adkcon |= v & 0x7FFF; else SAEV_Custom_adkcon &= ~v; + + SAER.audio.update_adkmasks(); + //if ((v >> 11) & 1) serial_uartbreak((SAEV_Custom_adkcon >> 11) & 1); + } + + /*---------------------------------*/ + + this.send_interrupt = function(num, delay) { + this.INTREQ_0(SAEC_Custom_INTF_SETCLR | num); + } + + /*---------------------------------*/ + + /* + var irq_nmi = 0; + this.NMI_delayed = function() { + irq_nmi = 1; + }*/ + + this.intlev = function() { + var imask = intreq_internal & intena_internal; + /*if (irq_nmi) { + irq_nmi = 0; + return 7; + }*/ + if (imask && (intena_internal & SAEC_Custom_INTF_INTEN)) { //0x4000)) { + if (imask & (0x4000 | 0x2000)) return 6; // 13 14 + if (imask & (0x1000 | 0x0800)) return 5; // 11 12 + if (imask & (0x0400 | 0x0200 | 0x0100 | 0x0080)) return 4; // 7 8 9 10 + if (imask & (0x0040 | 0x0020 | 0x0010)) return 3; // 4 5 6 + if (imask & 0x0008) return 2; // 3 + if (imask & (0x0001 | 0x0002 | 0x0004)) return 1; // 0 1 2 + } + return -1; + } + + /*-----------------------------------------------------------------------*/ + + function get16_real(hpos, addr, noput, isbyte) { + var v = false; + + addr &= 0xfff; + try { + v = readMap[(addr & 0x1fe) >> 1](hpos); + } catch(e) { + if (!(e instanceof Error)) + throw e; + /* OCS/ECS: + * reading write-only register causes write with last value in chip + * bus (custom registers, chipram, slowram) + * and finally returns either all ones or something weird if DMA happens + * in next (or previous) cycle.. FIXME. + * + * OCS-only special case: DFF000 (BLTDDAT) will always return whatever was left in bus + * + * AGA: + * Can also return last CPU accessed value + * Remembers old SAEV_Custom_last_value + */ + v = SAEV_Custom_last_value; + SAER.playfield.set_line_cyclebased(); + if (!noput) { + var l; + + if (SAEV_config.chipset.mask & SAEC_Config_Chipset_Mask_AGA) { + l = 0; } else { - if (AMIGA.config.chipset.mask & CSMASK_ECS_AGNUS) - v = 0xffff; - else - v = l; + // last chip bus value (read or write) is written to register + /*if (SAEV_config.cpu.compatible && SAEV_config.cpu.model == SAEC_Config_CPU_Model_68000) { //FIX 68000 prefetch not implemented + if (isbyte) + l = (SAER_CPU_regs.chipset_latch_rw << 8) | (SAER_CPU_regs.chipset_latch_rw & 0xff); + else + l = SAER_CPU_regs.chipset_latch_rw; + } else + l = SAER_CPU_regs.chipset_latch_rw; + */ + l = 0; } - //BUG.info('Custom.load16_real() %08x read = %04x. value written = %04x', 0xdff000 | addr, v, l); + SAER.playfield.decide_line(hpos); + SAER.playfield.decide_fetch_safe(hpos); + var r = put16_real(hpos, addr, l, true); + + /* CPU gets back (OCS/ECS only): + - if last cycle was DMA cycle: DMA cycle data + - if last cycle was not DMA cycle: FFFF or some ANDed old data. */ + + /*var c = SAER_Events_cycle_line[hpos] & SAEC_Events_cycle_line_MASK; + var bmdma = SAER.playfield.is_bitplane_dma(hpos); + if (SAEV_config.chipset.mask & SAEC_Config_Chipset_Mask_AGA) { + if (bmdma || (c > SAEC_Events_cycle_line_REFRESH && c < SAEC_Events_cycle_line_CPU)) + v = SAEV_Custom_last_value; + else if (c == SAEC_Events_cycle_line_CPU) + v = SAER_CPU_regs.db; + else + v = SAEV_Custom_last_value >>> ((addr & 2) ? 0 : 16); + } else { + if (bmdma || (c > SAEC_Events_cycle_line_REFRESH && c < SAEC_Events_cycle_line_CPU)) + v = SAEV_Custom_last_value; + else + // refresh checked because refresh cycles do not always set SAEV_Custom_last_value for performance reasons. + v = 0xffff; + }*/ + var bmdma = SAER.playfield.is_bitplane_dma(hpos); + if (SAEV_config.chipset.mask & SAEC_Config_Chipset_Mask_AGA) { + if (bmdma) + v = SAEV_Custom_last_value & 0xffff; + else + v = (SAEV_Custom_last_value >>> ((addr & 2) ? 0 : 16)) & 0xffff; + } else { + if (bmdma) + v = SAEV_Custom_last_value & 0xffff; + else + v = 0xffff; + } + + //SAEF_log("Custom.get16_real() %08x read = %04x. value written = %04x", 0xdff000 | addr, v, l); return v; } } - - this.last_value = v; return v; - }; + } - this.load16_2 = function (addr) { - var hpos = AMIGA.playfield.hpos(); + function get16_2(addr, isbyte) { + var hpos = SAER.events.current_hpos(); - AMIGA.copper.sync_copper_with_cpu(hpos, 1); - return this.load16_real(hpos, addr, 0); - }; + SAER.copper.sync_copper_with_cpu(hpos, 1); + //var v = + return get16_real(hpos, addr, false, isbyte); + /*#ifdef ACTION_REPLAY + #ifdef ACTION_REPLAY_COMMON + addr &= 0x1ff; + ar_custom[addr + 0] = (uae_u8)(v >> 8); + ar_custom[addr + 1] = (uae_u8)(v); + #endif + #endif + return v;*/ + } + function get8(addr) { + if ((addr & 0xffff) < 0x8000 && SAEV_config.chipset.fatGaryRev >= 0) + return SAER.memory.dummyGet(addr, 1, false, 0); + + return (get16_2(addr & ~1, true) >> (addr & 1 ? 0 : 8)) & 0xff; + } + function get16(addr) { + if ((addr & 0xffff) < 0x8000 && SAEV_config.chipset.fatGaryRev >= 0) + return SAER.memory.dummyGet(addr, 2, false, 0); - this.load16 = function (addr) { if (addr & 1) { + /* think about move.w $dff005,d0.. (68020+ only) */ addr &= ~1; - return (this.load16_2(addr) << 8) | (this.load16_2(addr + 2) >> 8); + return ((get16_2(addr, false) << 8) & 0xff00) | (get16_2(addr + 2, false) >> 8); } - return this.load16_2(addr); - }; + return get16_2(addr, false); + } + function getInst16(addr) { + if (SAEV_config.cpu.model >= SAEC_Config_CPU_Model_68020) + return SAEF_Memory_dummyGetInst16(addr); + return get16(addr); + } + function get32(addr) { + if ((addr & 0xffff) < 0x8000 && SAEV_config.chipset.fatGaryRev >= 0) + return SAER.memory.dummyGet(addr, 4, false, 0); - this.load8 = function (addr) { - return this.load16_2(addr & ~1) >> ((addr & 1) ? 0 : 8); - }; + return ((get16(addr) << 16) | get16(addr + 2)) >>> 0; + } + function getInst32(addr) { + if (SAEV_config.cpu.model >= SAEC_Config_CPU_Model_68020) + return SAEF_Memory_dummyGetInst32(addr); + return get32(addr); + } - this.load32 = function (addr) { - return ((this.load16(addr) << 16) | this.load16(addr + 2)) >>> 0; - }; - /*---------------------------------*/ - - this.store16_real = function (hpos, addr, value, noget) { - if (!noget) this.last_value = value; - addr &= 0x1fe; + function put16_real(hpos, addr, value, noget) { + addr &= 0x1FE; value &= 0xffff; - switch (addr) { - case 0x00E: - AMIGA.playfield.CLXDAT(); - break; - - case 0x020: - AMIGA.disk.DSKPTH(value); - break; - case 0x022: - AMIGA.disk.DSKPTL(value); - break; - case 0x024: - AMIGA.disk.DSKLEN(value, hpos); - break; - case 0x026: /* AMIGA.disk.DSKDAT(value). Writing to DMA write registers won't do anything */ - break; - - case 0x02A: - AMIGA.playfield.VPOSW(value); - break; - case 0x02C: - AMIGA.playfield.VHPOSW(value); - break; - case 0x02E: - AMIGA.copper.COPCON(value); - break; - case 0x030: - AMIGA.serial.SERDAT(value); - break; - case 0x032: - AMIGA.serial.SERPER(value); - break; - case 0x034: - AMIGA.input.POTGO(value); - break; - - case 0x040: - AMIGA.blitter.BLTCON0(hpos, value); - break; - case 0x042: - AMIGA.blitter.BLTCON1(hpos, value); - break; - - case 0x044: - AMIGA.blitter.BLTAFWM(hpos, value); - break; - case 0x046: - AMIGA.blitter.BLTALWM(hpos, value); - break; - - case 0x050: - AMIGA.blitter.BLTAPTH(hpos, value); - break; - case 0x052: - AMIGA.blitter.BLTAPTL(hpos, value); - break; - case 0x04C: - AMIGA.blitter.BLTBPTH(hpos, value); - break; - case 0x04E: - AMIGA.blitter.BLTBPTL(hpos, value); - break; - case 0x048: - AMIGA.blitter.BLTCPTH(hpos, value); - break; - case 0x04A: - AMIGA.blitter.BLTCPTL(hpos, value); - break; - case 0x054: - AMIGA.blitter.BLTDPTH(hpos, value); - break; - case 0x056: - AMIGA.blitter.BLTDPTL(hpos, value); - break; - - case 0x058: - AMIGA.blitter.BLTSIZE(hpos, value); - break; - - case 0x064: - AMIGA.blitter.BLTAMOD(hpos, value); - break; - case 0x062: - AMIGA.blitter.BLTBMOD(hpos, value); - break; - case 0x060: - AMIGA.blitter.BLTCMOD(hpos, value); - break; - case 0x066: - AMIGA.blitter.BLTDMOD(hpos, value); - break; - - case 0x070: - AMIGA.blitter.BLTCDAT(hpos, value); - break; - case 0x072: - AMIGA.blitter.BLTBDAT(hpos, value); - break; - case 0x074: - AMIGA.blitter.BLTADAT(hpos, value); - break; - - case 0x07E: - AMIGA.disk.DSKSYNC(value, hpos); - break; - - case 0x080: - AMIGA.copper.COP1LCH(value); - break; - case 0x082: - AMIGA.copper.COP1LCL(value); - break; - case 0x084: - AMIGA.copper.COP2LCH(value); - break; - case 0x086: - AMIGA.copper.COP2LCL(value); - break; - - case 0x088: - AMIGA.copper.COPJMP(1, 0); - break; - case 0x08A: - AMIGA.copper.COPJMP(2, 0); - break; - - case 0x08E: - AMIGA.playfield.DIWSTRT(hpos, value); - break; - case 0x090: - AMIGA.playfield.DIWSTOP(hpos, value); - break; - case 0x092: - AMIGA.playfield.DDFSTRT(hpos, value); - break; - case 0x094: - AMIGA.playfield.DDFSTOP(hpos, value); - break; - - case 0x096: - AMIGA.DMACON(value, hpos); - break; - case 0x098: - AMIGA.playfield.CLXCON(value); - break; - case 0x09A: - AMIGA.INTENA(value); - break; - case 0x09C: - AMIGA.INTREQ(value); - break; - case 0x09E: - AMIGA.ADKCON(value, hpos); - break; - - case 0x0A0: - AMIGA.audio.AUDxLCH(0, value); - break; - case 0x0A2: - AMIGA.audio.AUDxLCL(0, value); - break; - case 0x0A4: - AMIGA.audio.AUDxLEN(0, value); - break; - case 0x0A6: - AMIGA.audio.AUDxPER(0, value); - break; - case 0x0A8: - AMIGA.audio.AUDxVOL(0, value); - break; - case 0x0AA: - AMIGA.audio.AUDxDAT(0, value); - break; - - case 0x0B0: - AMIGA.audio.AUDxLCH(1, value); - break; - case 0x0B2: - AMIGA.audio.AUDxLCL(1, value); - break; - case 0x0B4: - AMIGA.audio.AUDxLEN(1, value); - break; - case 0x0B6: - AMIGA.audio.AUDxPER(1, value); - break; - case 0x0B8: - AMIGA.audio.AUDxVOL(1, value); - break; - case 0x0BA: - AMIGA.audio.AUDxDAT(1, value); - break; - - case 0x0C0: - AMIGA.audio.AUDxLCH(2, value); - break; - case 0x0C2: - AMIGA.audio.AUDxLCL(2, value); - break; - case 0x0C4: - AMIGA.audio.AUDxLEN(2, value); - break; - case 0x0C6: - AMIGA.audio.AUDxPER(2, value); - break; - case 0x0C8: - AMIGA.audio.AUDxVOL(2, value); - break; - case 0x0CA: - AMIGA.audio.AUDxDAT(2, value); - break; - - case 0x0D0: - AMIGA.audio.AUDxLCH(3, value); - break; - case 0x0D2: - AMIGA.audio.AUDxLCL(3, value); - break; - case 0x0D4: - AMIGA.audio.AUDxLEN(3, value); - break; - case 0x0D6: - AMIGA.audio.AUDxPER(3, value); - break; - case 0x0D8: - AMIGA.audio.AUDxVOL(3, value); - break; - case 0x0DA: - AMIGA.audio.AUDxDAT(3, value); - break; - - case 0x0E0: - AMIGA.playfield.BPLxPTH(hpos, value, 0); - break; - case 0x0E2: - AMIGA.playfield.BPLxPTL(hpos, value, 0); - break; - case 0x0E4: - AMIGA.playfield.BPLxPTH(hpos, value, 1); - break; - case 0x0E6: - AMIGA.playfield.BPLxPTL(hpos, value, 1); - break; - case 0x0E8: - AMIGA.playfield.BPLxPTH(hpos, value, 2); - break; - case 0x0EA: - AMIGA.playfield.BPLxPTL(hpos, value, 2); - break; - case 0x0EC: - AMIGA.playfield.BPLxPTH(hpos, value, 3); - break; - case 0x0EE: - AMIGA.playfield.BPLxPTL(hpos, value, 3); - break; - case 0x0F0: - AMIGA.playfield.BPLxPTH(hpos, value, 4); - break; - case 0x0F2: - AMIGA.playfield.BPLxPTL(hpos, value, 4); - break; - case 0x0F4: - AMIGA.playfield.BPLxPTH(hpos, value, 5); - break; - case 0x0F6: - AMIGA.playfield.BPLxPTL(hpos, value, 5); - break; - case 0x0F8: - AMIGA.playfield.BPLxPTH(hpos, value, 6); - break; - case 0x0FA: - AMIGA.playfield.BPLxPTL(hpos, value, 6); - break; - case 0x0FC: - AMIGA.playfield.BPLxPTH(hpos, value, 7); - break; - case 0x0FE: - AMIGA.playfield.BPLxPTL(hpos, value, 7); - break; - - case 0x100: - AMIGA.playfield.BPLCON0(hpos, value); - break; - case 0x102: - AMIGA.playfield.BPLCON1(hpos, value); - break; - case 0x104: - AMIGA.playfield.BPLCON2(hpos, value); - break; - case 0x106: - AMIGA.playfield.BPLCON3(hpos, value); - break; - - case 0x108: - AMIGA.playfield.BPL1MOD(hpos, value); - break; - case 0x10A: - AMIGA.playfield.BPL2MOD(hpos, value); - break; - //case 0x10E: AMIGA.playfield.CLXCON2(value); break; //AGA - - case 0x110: - AMIGA.playfield.BPLxDAT(hpos, value, 0); - break; - case 0x112: - AMIGA.playfield.BPLxDAT(hpos, value, 1); - break; - case 0x114: - AMIGA.playfield.BPLxDAT(hpos, value, 2); - break; - case 0x116: - AMIGA.playfield.BPLxDAT(hpos, value, 3); - break; - case 0x118: - AMIGA.playfield.BPLxDAT(hpos, value, 4); - break; - case 0x11A: - AMIGA.playfield.BPLxDAT(hpos, value, 5); - break; - case 0x11C: - AMIGA.playfield.BPLxDAT(hpos, value, 6); - break; - case 0x11E: - AMIGA.playfield.BPLxDAT(hpos, value, 7); - break; - - case 0x180: - case 0x182: - case 0x184: - case 0x186: - case 0x188: - case 0x18A: - case 0x18C: - case 0x18E: - case 0x190: - case 0x192: - case 0x194: - case 0x196: - case 0x198: - case 0x19A: - case 0x19C: - case 0x19E: - case 0x1A0: - case 0x1A2: - case 0x1A4: - case 0x1A6: - case 0x1A8: - case 0x1AA: - case 0x1AC: - case 0x1AE: - case 0x1B0: - case 0x1B2: - case 0x1B4: - case 0x1B6: - case 0x1B8: - case 0x1BA: - case 0x1BC: - case 0x1BE: - AMIGA.playfield.COLOR_WRITE(hpos, value & 0xFFF, (addr & 0x3E) >> 1); - break; - - case 0x120: - case 0x124: - case 0x128: - case 0x12C: - case 0x130: - case 0x134: - case 0x138: - case 0x13C: - AMIGA.playfield.SPRxPTH(hpos, value, (addr - 0x120) >> 2); - break; - case 0x122: - case 0x126: - case 0x12A: - case 0x12E: - case 0x132: - case 0x136: - case 0x13A: - case 0x13E: - AMIGA.playfield.SPRxPTL(hpos, value, (addr - 0x122) >> 2); - break; - case 0x140: - case 0x148: - case 0x150: - case 0x158: - case 0x160: - case 0x168: - case 0x170: - case 0x178: - AMIGA.playfield.SPRxPOS(hpos, value, (addr - 0x140) >> 3); - break; - case 0x142: - case 0x14A: - case 0x152: - case 0x15A: - case 0x162: - case 0x16A: - case 0x172: - case 0x17A: - AMIGA.playfield.SPRxCTL(hpos, value, (addr - 0x142) >> 3); - break; - case 0x144: - case 0x14C: - case 0x154: - case 0x15C: - case 0x164: - case 0x16C: - case 0x174: - case 0x17C: - AMIGA.playfield.SPRxDATA(hpos, value, (addr - 0x144) >> 3); - break; - case 0x146: - case 0x14E: - case 0x156: - case 0x15E: - case 0x166: - case 0x16E: - case 0x176: - case 0x17E: - AMIGA.playfield.SPRxDATB(hpos, value, (addr - 0x146) >> 3); - break; - - case 0x36: - AMIGA.input.JOYTEST(value); - break; - case 0x5A: - AMIGA.blitter.BLTCON0L(hpos, value); - break; - case 0x5C: - AMIGA.blitter.BLTSIZV(hpos, value); - break; - case 0x5E: - AMIGA.blitter.BLTSIZH(hpos, value); - break; - case 0x1E4: - AMIGA.playfield.DIWHIGH(hpos, value); - break; - //case 0x10C: AMIGA.playfield.BPLCON4(hpos, value); break; //AGA - - case 0x1DC: - AMIGA.playfield.BEAMCON0(value); - break; - case 0x1C0: - if (AMIGA.playfield.htotal != value) { - AMIGA.playfield.htotal = value; - AMIGA.playfield.varsync(); - } - break; - case 0x1C2: - if (AMIGA.playfield.hsstop != value) { - AMIGA.playfield.hsstop = value; - AMIGA.playfield.varsync(); - } - break; - case 0x1C4: - if (AMIGA.playfield.hbstrt != value) { - AMIGA.playfield.hbstrt = value; - AMIGA.playfield.varsync(); - } - break; - case 0x1C6: - if (AMIGA.playfield.hbstop != value) { - AMIGA.playfield.hbstop = value; - AMIGA.playfield.varsync(); - } - break; - case 0x1C8: - if (AMIGA.playfield.vtotal != value) { - AMIGA.playfield.vtotal = value; - AMIGA.playfield.varsync(); - } - break; - case 0x1CA: - if (AMIGA.playfield.vsstop != value) { - AMIGA.playfield.vsstop = value; - AMIGA.playfield.varsync(); - } - break; - case 0x1CC: - if (AMIGA.playfield.vbstrt < value || AMIGA.playfield.vbstrt > value + 1) { - AMIGA.playfield.vbstrt = value; - AMIGA.playfield.varsync(); - } - break; - case 0x1CE: - if (AMIGA.playfield.vbstop < value || AMIGA.playfield.vbstop > value + 1) { - AMIGA.playfield.vbstop = value; - AMIGA.playfield.varsync(); - } - break; - case 0x1DE: - if (AMIGA.playfield.hsstrt != value) { - AMIGA.playfield.hsstrt = value; - AMIGA.playfield.varsync(); - } - break; - case 0x1E0: - if (AMIGA.playfield.vsstrt != value) { - AMIGA.playfield.vsstrt = value; - AMIGA.playfield.varsync(); - } - break; - case 0x1E2: - if (AMIGA.playfield.hcenter != value) { - AMIGA.playfield.hcenter = value; - AMIGA.playfield.varsync(); - } - break; - - //case 0x1FC: AMIGA.playfield.FMODE(hpos, value); break; //AGA - //case 0x1FE: FNULL (value); break; - case 0x1FE: - break; + /*#ifdef ACTION_REPLAY + #ifdef ACTION_REPLAY_COMMON + ar_custom[addr+0]=(uae_u8)(value>>8); + ar_custom[addr+1]=(uae_u8)(value); + #endif + #endif*/ + try { + writeMap[addr >> 1](value, hpos); + } catch(e) { + if (!(e instanceof Error)) + throw e; /* writing to read-only register causes read access */ - default: - { - if (!noget) { - //BUG.info('Custom.store16_real() %04x written', addr); - this.load16_real(hpos, addr, 1); - } - return true; + if (!noget) { + //SAEF_log("Custom.put16_real() %04x written", addr); + get16_real(hpos, addr, true, false); } + return true; } return false; - }; + } + SAER_Custom_put16_real = put16_real; - this.store16 = function (addr, value) { - var hpos = AMIGA.playfield.hpos(); - AMIGA.copper.sync_copper_with_cpu(hpos, 1); - if (addr & 1) { - addr &= ~1; - this.store16_real(hpos, addr, (value >> 8) | (value & 0xff00), 0); - this.store16_real(hpos, addr + 2, (value << 8) | (value & 0x00ff), 0); + function put16(addr, value) { + var hpos = SAER.events.current_hpos(); + if ((addr & 0xffff) < 0x8000 && SAEV_config.chipset.fatGaryRev >= 0) { + SAER.memory.dummyPut(addr, 2, value); + return; + } + SAER.copper.sync_copper_with_cpu(hpos, 1); + if (addr & 1) { + addr &= ~1; + put16_real(hpos, addr, (value >> 8) | (value & 0xff00), 0); + put16_real(hpos, addr + 2, ((value << 8) & 0xff00) | (value & 0x00ff), 0); + return; + } + put16_real(hpos, addr, value, 0); + } + function put8(addr, value) { + if ((addr & 0xffff) < 0x8000 && SAEV_config.chipset.fatGaryRev >= 0) { + SAER.memory.dummyPut(addr, 1, value); return; } - this.store16_real(hpos, addr, value, 0); - }; - - this.store8 = function (addr, value) { var rval; + if (SAEV_config.chipset.mask & SAEC_Config_Chipset_Mask_AGA) { + if (addr & 1) + rval = value & 0xff; + else + rval = (value << 8) | (value & 0xff); + } else + rval = (value << 8) | (value & 0xff); - /*if (AMIGA.config.chipset.mask & CSMASK_AGA) { - if (addr & 1) { - rval = value & 0xff; - } else { - rval = (value << 8) | (value & 0xFF); - } - } else*/ - rval = (value << 8) | (value & 0xff); + /*if (currprefs.cs_bytecustomwritebug) { + if (addr & 1) + put16(addr & ~1, rval); + else + put16(addr, value << 8); + } else*/ + put16(addr & ~1, rval); + } + function put32(addr, value) { + if ((addr & 0xffff) < 0x8000 && SAEV_config.chipset.fatGaryRev >= 0) { + SAER.memory.dummyPut(addr, 4, value); + return; + } + put16(addr & 0xfffe, value >>> 16); + put16((addr + 2) & 0xfffe, value & 0xffff); + } - /*if (AMIGA.config.cpu.model == 68060) { - if (addr & 1) - this.store16(addr & ~1, rval); - else - this.store16(addr, value << 8); - } else*/ - this.store16(addr & ~1, rval); - }; + SAEV_Custom_bank = new SAEO_Memory_addrbank( + get32, get16, get8, + put32, put16, put8, + SAEF_Memory_defaultXLate, SAEF_Memory_defaultCheck, null, null, "Custom chipset", + getInst32, getInst16, + //SAEC_Memory_addrbank_flag_IO, S_READ, S_WRITE, null, 0x1ff, 0xdff000 + SAEC_Memory_addrbank_flag_IO, null, 0x1ff, 0xdff000 + ); - this.store32 = function (addr, value) { - this.store16(addr & 0xfffe, value >>> 16); - this.store16((addr + 2) & 0xfffe, value & 0xffff); + /*-----------------------------------------------------------------------*/ + + function createReadMap() { + var i; + + readMap = new Array(0x100); + for (i = 0; i < readMap.length; i++) readMap[i] = false; + + readMap[0x002 >> 1] = DMACONR; + readMap[0x004 >> 1] = function() { return SAER.playfield.VPOSR(); }; + readMap[0x006 >> 1] = function() { return SAER.playfield.VHPOSR(); }; + readMap[0x00A >> 1] = function() { return SAER.input.JOY0DAT(); }; + readMap[0x00C >> 1] = function() { return SAER.input.JOY1DAT(); }; + readMap[0x00E >> 1] = function() { return SAER.playfield.CLXDAT(); }; + readMap[0x010 >> 1] = ADKCONR; + readMap[0x012 >> 1] = function() { return SAER.input.POT0DAT(); }; + readMap[0x014 >> 1] = function() { return SAER.input.POT1DAT(); }; + readMap[0x016 >> 1] = function() { return SAER.input.POTGOR(); }; + readMap[0x018 >> 1] = function() { return SAER.serial.SERDATR(); }; + readMap[0x01A >> 1] = function(hpos) { return SAER.disk.DSKBYTR(hpos); }; + readMap[0x01C >> 1] = INTENAR; + readMap[0x01E >> 1] = INTREQR; + if (SAEV_config.chipset.mask & SAEC_Config_Chipset_Mask_ECS_DENISE) + readMap[0x07C >> 1] = function() { return SAER.playfield.DENISEID(); }; + if (SAEV_config.chipset.mask & SAEC_Config_Chipset_Mask_AGA) { + readMap[0x180 >> 1] = function() { return SAER.playfield.COLOR_READ(0); }; + readMap[0x182 >> 1] = function() { return SAER.playfield.COLOR_READ(1); }; + readMap[0x184 >> 1] = function() { return SAER.playfield.COLOR_READ(2); }; + readMap[0x186 >> 1] = function() { return SAER.playfield.COLOR_READ(3); }; + readMap[0x188 >> 1] = function() { return SAER.playfield.COLOR_READ(4); }; + readMap[0x18A >> 1] = function() { return SAER.playfield.COLOR_READ(5); }; + readMap[0x18C >> 1] = function() { return SAER.playfield.COLOR_READ(6); }; + readMap[0x18E >> 1] = function() { return SAER.playfield.COLOR_READ(7); }; + readMap[0x190 >> 1] = function() { return SAER.playfield.COLOR_READ(8); }; + readMap[0x192 >> 1] = function() { return SAER.playfield.COLOR_READ(9); }; + readMap[0x194 >> 1] = function() { return SAER.playfield.COLOR_READ(10); }; + readMap[0x196 >> 1] = function() { return SAER.playfield.COLOR_READ(11); }; + readMap[0x198 >> 1] = function() { return SAER.playfield.COLOR_READ(12); }; + readMap[0x19A >> 1] = function() { return SAER.playfield.COLOR_READ(13); }; + readMap[0x19C >> 1] = function() { return SAER.playfield.COLOR_READ(14); }; + readMap[0x19E >> 1] = function() { return SAER.playfield.COLOR_READ(15); }; + readMap[0x1A0 >> 1] = function() { return SAER.playfield.COLOR_READ(16); }; + readMap[0x1A2 >> 1] = function() { return SAER.playfield.COLOR_READ(17); }; + readMap[0x1A4 >> 1] = function() { return SAER.playfield.COLOR_READ(18); }; + readMap[0x1A6 >> 1] = function() { return SAER.playfield.COLOR_READ(19); }; + readMap[0x1A8 >> 1] = function() { return SAER.playfield.COLOR_READ(20); }; + readMap[0x1AA >> 1] = function() { return SAER.playfield.COLOR_READ(21); }; + readMap[0x1AC >> 1] = function() { return SAER.playfield.COLOR_READ(22); }; + readMap[0x1AE >> 1] = function() { return SAER.playfield.COLOR_READ(23); }; + readMap[0x1B0 >> 1] = function() { return SAER.playfield.COLOR_READ(24); }; + readMap[0x1B2 >> 1] = function() { return SAER.playfield.COLOR_READ(25); }; + readMap[0x1B4 >> 1] = function() { return SAER.playfield.COLOR_READ(26); }; + readMap[0x1B6 >> 1] = function() { return SAER.playfield.COLOR_READ(27); }; + readMap[0x1B8 >> 1] = function() { return SAER.playfield.COLOR_READ(28); }; + readMap[0x1BA >> 1] = function() { return SAER.playfield.COLOR_READ(29); }; + readMap[0x1BC >> 1] = function() { return SAER.playfield.COLOR_READ(30); }; + readMap[0x1BE >> 1] = function() { return SAER.playfield.COLOR_READ(31); }; + } + } + + function createWriteMap() { + var i; + + writeMap = new Array(0x100); + for (i = 0; i < writeMap.length; i++) writeMap[i] = false; + + writeMap[0x00E >> 1] = function(value, hpos) { SAER.playfield.CLXDAT(); }; + writeMap[0x020 >> 1] = function(value, hpos) { SAER.disk.DSKPTH(value); }; + writeMap[0x022 >> 1] = function(value, hpos) { SAER.disk.DSKPTL(value); }; + writeMap[0x024 >> 1] = function(value, hpos) { SAER.disk.DSKLEN(value, hpos); }; + writeMap[0x026 >> 1] = function(value, hpos) { /* SAER.disk.DSKDAT(value); */ }; + writeMap[0x028 >> 1] = function(value, hpos) { SAER.playfield.REFPTR(value); }; + writeMap[0x02A >> 1] = function(value, hpos) { SAER.playfield.VPOSW(value); }; + writeMap[0x02C >> 1] = function(value, hpos) { SAER.playfield.VHPOSW(value); }; + writeMap[0x02E >> 1] = function(value, hpos) { SAER.copper.COPCON(value); }; + writeMap[0x030 >> 1] = function(value, hpos) { SAER.serial.SERDAT(value); }; + writeMap[0x032 >> 1] = function(value, hpos) { SAER.serial.SERPER(value); }; + writeMap[0x034 >> 1] = function(value, hpos) { SAER.input.POTGO(value); }; + writeMap[0x036 >> 1] = function(value, hpos) { SAER.input.JOYTEST(value); }; + /* 038 STREQU S * * * Strobe for horiz sync with VB and EQU + 03A STRVBL S * * * Strobe for horiz sync with VB (vert blank) + 03C STRHOR S * * * Strobe for horiz sync + 03E STRLONG S * * * Strobe for identification of long horiz line*/ + writeMap[0x040 >> 1] = function(value, hpos) { SAER.blitter.BLTCON0(hpos, value); }; + writeMap[0x042 >> 1] = function(value, hpos) { SAER.blitter.BLTCON1(hpos, value); }; + writeMap[0x044 >> 1] = function(value, hpos) { SAER.blitter.BLTAFWM(hpos, value); }; + writeMap[0x046 >> 1] = function(value, hpos) { SAER.blitter.BLTALWM(hpos, value); }; + writeMap[0x048 >> 1] = function(value, hpos) { SAER.blitter.BLTCPTH(hpos, value); }; + writeMap[0x04A >> 1] = function(value, hpos) { SAER.blitter.BLTCPTL(hpos, value); }; + writeMap[0x04C >> 1] = function(value, hpos) { SAER.blitter.BLTBPTH(hpos, value); }; + writeMap[0x04E >> 1] = function(value, hpos) { SAER.blitter.BLTBPTL(hpos, value); }; + writeMap[0x050 >> 1] = function(value, hpos) { SAER.blitter.BLTAPTH(hpos, value); }; + writeMap[0x052 >> 1] = function(value, hpos) { SAER.blitter.BLTAPTL(hpos, value); }; + writeMap[0x054 >> 1] = function(value, hpos) { SAER.blitter.BLTDPTH(hpos, value); }; + writeMap[0x056 >> 1] = function(value, hpos) { SAER.blitter.BLTDPTL(hpos, value); }; + writeMap[0x058 >> 1] = function(value, hpos) { SAER.blitter.BLTSIZE(hpos, value); }; + if (SAEV_config.chipset.mask & SAEC_Config_Chipset_Mask_ECS_AGNUS) { + writeMap[0x05A >> 1] = function(value, hpos) { SAER.blitter.BLTCON0L(hpos, value); }; + writeMap[0x05C >> 1] = function(value, hpos) { SAER.blitter.BLTSIZV(hpos, value); }; + writeMap[0x05E >> 1] = function(value, hpos) { SAER.blitter.BLTSIZH(hpos, value); }; + } + writeMap[0x060 >> 1] = function(value, hpos) { SAER.blitter.BLTCMOD(hpos, value); }; + writeMap[0x062 >> 1] = function(value, hpos) { SAER.blitter.BLTBMOD(hpos, value); }; + writeMap[0x064 >> 1] = function(value, hpos) { SAER.blitter.BLTAMOD(hpos, value); }; + writeMap[0x066 >> 1] = function(value, hpos) { SAER.blitter.BLTDMOD(hpos, value); }; + /* - */ + writeMap[0x070 >> 1] = function(value, hpos) { SAER.blitter.BLTCDAT(hpos, value); }; + writeMap[0x072 >> 1] = function(value, hpos) { SAER.blitter.BLTBDAT(hpos, value); }; + writeMap[0x074 >> 1] = function(value, hpos) { SAER.blitter.BLTADAT(hpos, value); }; + /*if (SAEV_config.chipset.mask & (SAEC_Config_Chipset_Mask_ECS_AGNUS | SAEC_Config_Chipset_Mask_ECS_DENISE)) { + 078 SPRHDAT W * * Ext. logic UHRES sprite pointer and data identifier + 07A BPLHDAT W * * Ext. logic UHRES bit plane identifier + }*/ + writeMap[0x07E >> 1] = function(value, hpos) { SAER.disk.DSKSYNC(hpos, value); }; + writeMap[0x080 >> 1] = function(value, hpos) { SAER.copper.COP1LCH(value); }; + writeMap[0x082 >> 1] = function(value, hpos) { SAER.copper.COP1LCL(value); }; + writeMap[0x084 >> 1] = function(value, hpos) { SAER.copper.COP2LCH(value); }; + writeMap[0x086 >> 1] = function(value, hpos) { SAER.copper.COP2LCL(value); }; + writeMap[0x088 >> 1] = function(value, hpos) { SAER.copper.COPJMP(1, 0); }; + writeMap[0x08A >> 1] = function(value, hpos) { SAER.copper.COPJMP(2, 0); }; + writeMap[0x08E >> 1] = function(value, hpos) { SAER.playfield.DIWSTRT(hpos, value); }; + writeMap[0x090 >> 1] = function(value, hpos) { SAER.playfield.DIWSTOP(hpos, value); }; + writeMap[0x092 >> 1] = function(value, hpos) { SAER.playfield.DDFSTRT(hpos, value); }; + writeMap[0x094 >> 1] = function(value, hpos) { SAER.playfield.DDFSTOP(hpos, value); }; + writeMap[0x096 >> 1] = DMACON; + writeMap[0x098 >> 1] = function(value, hpos) { SAER.playfield.CLXCON(value); }; + writeMap[0x09A >> 1] = INTENA; + writeMap[0x09C >> 1] = function(value, hpos) { SAER.custom.INTREQ(value); }; + writeMap[0x09E >> 1] = ADKCON; + writeMap[0x0A0 >> 1] = function(value, hpos) { SAER.audio.AUDxLCH(0, value); }; + writeMap[0x0A2 >> 1] = function(value, hpos) { SAER.audio.AUDxLCL(0, value); }; + writeMap[0x0A4 >> 1] = function(value, hpos) { SAER.audio.AUDxLEN(0, value); }; + writeMap[0x0A6 >> 1] = function(value, hpos) { SAER.audio.AUDxPER(0, value); }; + writeMap[0x0A8 >> 1] = function(value, hpos) { SAER.audio.AUDxVOL(0, value); }; + writeMap[0x0AA >> 1] = function(value, hpos) { SAER.audio.AUDxDAT(0, value); }; + writeMap[0x0B0 >> 1] = function(value, hpos) { SAER.audio.AUDxLCH(1, value); }; + writeMap[0x0B2 >> 1] = function(value, hpos) { SAER.audio.AUDxLCL(1, value); }; + writeMap[0x0B4 >> 1] = function(value, hpos) { SAER.audio.AUDxLEN(1, value); }; + writeMap[0x0B6 >> 1] = function(value, hpos) { SAER.audio.AUDxPER(1, value); }; + writeMap[0x0B8 >> 1] = function(value, hpos) { SAER.audio.AUDxVOL(1, value); }; + writeMap[0x0BA >> 1] = function(value, hpos) { SAER.audio.AUDxDAT(1, value); }; + writeMap[0x0C0 >> 1] = function(value, hpos) { SAER.audio.AUDxLCH(2, value); }; + writeMap[0x0C2 >> 1] = function(value, hpos) { SAER.audio.AUDxLCL(2, value); }; + writeMap[0x0C4 >> 1] = function(value, hpos) { SAER.audio.AUDxLEN(2, value); }; + writeMap[0x0C6 >> 1] = function(value, hpos) { SAER.audio.AUDxPER(2, value); }; + writeMap[0x0C8 >> 1] = function(value, hpos) { SAER.audio.AUDxVOL(2, value); }; + writeMap[0x0CA >> 1] = function(value, hpos) { SAER.audio.AUDxDAT(2, value); }; + writeMap[0x0D0 >> 1] = function(value, hpos) { SAER.audio.AUDxLCH(3, value); }; + writeMap[0x0D2 >> 1] = function(value, hpos) { SAER.audio.AUDxLCL(3, value); }; + writeMap[0x0D4 >> 1] = function(value, hpos) { SAER.audio.AUDxLEN(3, value); }; + writeMap[0x0D6 >> 1] = function(value, hpos) { SAER.audio.AUDxPER(3, value); }; + writeMap[0x0D8 >> 1] = function(value, hpos) { SAER.audio.AUDxVOL(3, value); }; + writeMap[0x0DA >> 1] = function(value, hpos) { SAER.audio.AUDxDAT(3, value); }; + writeMap[0x0E0 >> 1] = function(value, hpos) { SAER.playfield.BPLxPTH(hpos, value, 0); }; + writeMap[0x0E2 >> 1] = function(value, hpos) { SAER.playfield.BPLxPTL(hpos, value, 0); }; + writeMap[0x0E4 >> 1] = function(value, hpos) { SAER.playfield.BPLxPTH(hpos, value, 1); }; + writeMap[0x0E6 >> 1] = function(value, hpos) { SAER.playfield.BPLxPTL(hpos, value, 1); }; + writeMap[0x0E8 >> 1] = function(value, hpos) { SAER.playfield.BPLxPTH(hpos, value, 2); }; + writeMap[0x0EA >> 1] = function(value, hpos) { SAER.playfield.BPLxPTL(hpos, value, 2); }; + writeMap[0x0EC >> 1] = function(value, hpos) { SAER.playfield.BPLxPTH(hpos, value, 3); }; + writeMap[0x0EE >> 1] = function(value, hpos) { SAER.playfield.BPLxPTL(hpos, value, 3); }; + writeMap[0x0F0 >> 1] = function(value, hpos) { SAER.playfield.BPLxPTH(hpos, value, 4); }; + writeMap[0x0F2 >> 1] = function(value, hpos) { SAER.playfield.BPLxPTL(hpos, value, 4); }; + writeMap[0x0F4 >> 1] = function(value, hpos) { SAER.playfield.BPLxPTH(hpos, value, 5); }; + writeMap[0x0F6 >> 1] = function(value, hpos) { SAER.playfield.BPLxPTL(hpos, value, 5); }; + if (SAEV_config.chipset.mask & SAEC_Config_Chipset_Mask_AGA) { + writeMap[0x0F8 >> 1] = function(value, hpos) { SAER.playfield.BPLxPTH(hpos, value, 6); }; + writeMap[0x0FA >> 1] = function(value, hpos) { SAER.playfield.BPLxPTL(hpos, value, 6); }; + writeMap[0x0FC >> 1] = function(value, hpos) { SAER.playfield.BPLxPTH(hpos, value, 7); }; + writeMap[0x0FE >> 1] = function(value, hpos) { SAER.playfield.BPLxPTL(hpos, value, 7); }; + } + writeMap[0x100 >> 1] = function(value, hpos) { SAER.playfield.BPLCON0(hpos, value); }; + writeMap[0x102 >> 1] = function(value, hpos) { SAER.playfield.BPLCON1(hpos, value); }; + writeMap[0x104 >> 1] = function(value, hpos) { SAER.playfield.BPLCON2(hpos, value); }; + if (SAEV_config.chipset.mask & SAEC_Config_Chipset_Mask_ECS_DENISE) + writeMap[0x106 >> 1] = function(value, hpos) { SAER.playfield.BPLCON3(hpos, value); }; + writeMap[0x108 >> 1] = function(value, hpos) { SAER.playfield.BPL1MOD(hpos, value); }; + writeMap[0x10A >> 1] = function(value, hpos) { SAER.playfield.BPL2MOD(hpos, value); }; + if (SAEV_config.chipset.mask & SAEC_Config_Chipset_Mask_AGA) { + writeMap[0x10C >> 1] = function(value, hpos) { SAER.playfield.BPLCON4(hpos, value); }; + writeMap[0x10E >> 1] = function(value, hpos) { SAER.playfield.CLXCON2(value); }; + } + writeMap[0x110 >> 1] = function(value, hpos) { SAER.playfield.BPLxDAT(hpos, 0, value); }; + writeMap[0x112 >> 1] = function(value, hpos) { SAER.playfield.BPLxDAT(hpos, 1, value); }; + writeMap[0x114 >> 1] = function(value, hpos) { SAER.playfield.BPLxDAT(hpos, 2, value); }; + writeMap[0x116 >> 1] = function(value, hpos) { SAER.playfield.BPLxDAT(hpos, 3, value); }; + writeMap[0x118 >> 1] = function(value, hpos) { SAER.playfield.BPLxDAT(hpos, 4, value); }; + writeMap[0x11A >> 1] = function(value, hpos) { SAER.playfield.BPLxDAT(hpos, 5, value); }; + if (SAEV_config.chipset.mask & SAEC_Config_Chipset_Mask_AGA) { + writeMap[0x11C >> 1] = function(value, hpos) { SAER.playfield.BPLxDAT(hpos, 6, value); }; + writeMap[0x11E >> 1] = function(value, hpos) { SAER.playfield.BPLxDAT(hpos, 7, value); }; + } + writeMap[0x120 >> 1] = function(value, hpos) { SAER.playfield.SPRxPTH(hpos, value, 0); }; + writeMap[0x122 >> 1] = function(value, hpos) { SAER.playfield.SPRxPTL(hpos, value, 0); }; + writeMap[0x124 >> 1] = function(value, hpos) { SAER.playfield.SPRxPTH(hpos, value, 1); }; + writeMap[0x126 >> 1] = function(value, hpos) { SAER.playfield.SPRxPTL(hpos, value, 1); }; + writeMap[0x128 >> 1] = function(value, hpos) { SAER.playfield.SPRxPTH(hpos, value, 2); }; + writeMap[0x12A >> 1] = function(value, hpos) { SAER.playfield.SPRxPTL(hpos, value, 2); }; + writeMap[0x12C >> 1] = function(value, hpos) { SAER.playfield.SPRxPTH(hpos, value, 3); }; + writeMap[0x12E >> 1] = function(value, hpos) { SAER.playfield.SPRxPTL(hpos, value, 3); }; + writeMap[0x130 >> 1] = function(value, hpos) { SAER.playfield.SPRxPTH(hpos, value, 4); }; + writeMap[0x132 >> 1] = function(value, hpos) { SAER.playfield.SPRxPTL(hpos, value, 4); }; + writeMap[0x134 >> 1] = function(value, hpos) { SAER.playfield.SPRxPTH(hpos, value, 5); }; + writeMap[0x136 >> 1] = function(value, hpos) { SAER.playfield.SPRxPTL(hpos, value, 5); }; + writeMap[0x138 >> 1] = function(value, hpos) { SAER.playfield.SPRxPTH(hpos, value, 6); }; + writeMap[0x13A >> 1] = function(value, hpos) { SAER.playfield.SPRxPTL(hpos, value, 6); }; + writeMap[0x13C >> 1] = function(value, hpos) { SAER.playfield.SPRxPTH(hpos, value, 7); }; + writeMap[0x13E >> 1] = function(value, hpos) { SAER.playfield.SPRxPTL(hpos, value, 7); }; + writeMap[0x140 >> 1] = function(value, hpos) { SAER.playfield.SPRxPOS(hpos, value, 0); }; + writeMap[0x142 >> 1] = function(value, hpos) { SAER.playfield.SPRxCTL(hpos, value, 0); }; + writeMap[0x144 >> 1] = function(value, hpos) { SAER.playfield.SPRxDATA(hpos, value, 0); }; + writeMap[0x146 >> 1] = function(value, hpos) { SAER.playfield.SPRxDATB(hpos, value, 0); }; + writeMap[0x148 >> 1] = function(value, hpos) { SAER.playfield.SPRxPOS(hpos, value, 1); }; + writeMap[0x14A >> 1] = function(value, hpos) { SAER.playfield.SPRxCTL(hpos, value, 1); }; + writeMap[0x14C >> 1] = function(value, hpos) { SAER.playfield.SPRxDATA(hpos, value, 1); }; + writeMap[0x14E >> 1] = function(value, hpos) { SAER.playfield.SPRxDATB(hpos, value, 1); }; + writeMap[0x150 >> 1] = function(value, hpos) { SAER.playfield.SPRxPOS(hpos, value, 2); }; + writeMap[0x152 >> 1] = function(value, hpos) { SAER.playfield.SPRxCTL(hpos, value, 2); }; + writeMap[0x154 >> 1] = function(value, hpos) { SAER.playfield.SPRxDATA(hpos, value, 2); }; + writeMap[0x156 >> 1] = function(value, hpos) { SAER.playfield.SPRxDATB(hpos, value, 2); }; + writeMap[0x158 >> 1] = function(value, hpos) { SAER.playfield.SPRxPOS(hpos, value, 3); }; + writeMap[0x15A >> 1] = function(value, hpos) { SAER.playfield.SPRxCTL(hpos, value, 3); }; + writeMap[0x15C >> 1] = function(value, hpos) { SAER.playfield.SPRxDATA(hpos, value, 3); }; + writeMap[0x15E >> 1] = function(value, hpos) { SAER.playfield.SPRxDATB(hpos, value, 3); }; + writeMap[0x160 >> 1] = function(value, hpos) { SAER.playfield.SPRxPOS(hpos, value, 4); }; + writeMap[0x162 >> 1] = function(value, hpos) { SAER.playfield.SPRxCTL(hpos, value, 4); }; + writeMap[0x164 >> 1] = function(value, hpos) { SAER.playfield.SPRxDATA(hpos, value, 4); }; + writeMap[0x166 >> 1] = function(value, hpos) { SAER.playfield.SPRxDATB(hpos, value, 4); }; + writeMap[0x168 >> 1] = function(value, hpos) { SAER.playfield.SPRxPOS(hpos, value, 5); }; + writeMap[0x16A >> 1] = function(value, hpos) { SAER.playfield.SPRxCTL(hpos, value, 5); }; + writeMap[0x16C >> 1] = function(value, hpos) { SAER.playfield.SPRxDATA(hpos, value, 5); }; + writeMap[0x16E >> 1] = function(value, hpos) { SAER.playfield.SPRxDATB(hpos, value, 5); }; + writeMap[0x170 >> 1] = function(value, hpos) { SAER.playfield.SPRxPOS(hpos, value, 6); }; + writeMap[0x172 >> 1] = function(value, hpos) { SAER.playfield.SPRxCTL(hpos, value, 6); }; + writeMap[0x174 >> 1] = function(value, hpos) { SAER.playfield.SPRxDATA(hpos, value, 6); }; + writeMap[0x176 >> 1] = function(value, hpos) { SAER.playfield.SPRxDATB(hpos, value, 6); }; + writeMap[0x178 >> 1] = function(value, hpos) { SAER.playfield.SPRxPOS(hpos, value, 7); }; + writeMap[0x17A >> 1] = function(value, hpos) { SAER.playfield.SPRxCTL(hpos, value, 7); }; + writeMap[0x17C >> 1] = function(value, hpos) { SAER.playfield.SPRxDATA(hpos, value, 7); }; + writeMap[0x17E >> 1] = function(value, hpos) { SAER.playfield.SPRxDATB(hpos, value, 7); }; + writeMap[0x180 >> 1] = function(value, hpos) { SAER.playfield.COLOR_WRITE(hpos, value & 0xfff, 0); }; + writeMap[0x182 >> 1] = function(value, hpos) { SAER.playfield.COLOR_WRITE(hpos, value & 0xfff, 1); }; + writeMap[0x184 >> 1] = function(value, hpos) { SAER.playfield.COLOR_WRITE(hpos, value & 0xfff, 2); }; + writeMap[0x186 >> 1] = function(value, hpos) { SAER.playfield.COLOR_WRITE(hpos, value & 0xfff, 3); }; + writeMap[0x188 >> 1] = function(value, hpos) { SAER.playfield.COLOR_WRITE(hpos, value & 0xfff, 4); }; + writeMap[0x18A >> 1] = function(value, hpos) { SAER.playfield.COLOR_WRITE(hpos, value & 0xfff, 5); }; + writeMap[0x18C >> 1] = function(value, hpos) { SAER.playfield.COLOR_WRITE(hpos, value & 0xfff, 6); }; + writeMap[0x18E >> 1] = function(value, hpos) { SAER.playfield.COLOR_WRITE(hpos, value & 0xfff, 7); }; + writeMap[0x190 >> 1] = function(value, hpos) { SAER.playfield.COLOR_WRITE(hpos, value & 0xfff, 8); }; + writeMap[0x192 >> 1] = function(value, hpos) { SAER.playfield.COLOR_WRITE(hpos, value & 0xfff, 9); }; + writeMap[0x194 >> 1] = function(value, hpos) { SAER.playfield.COLOR_WRITE(hpos, value & 0xfff, 10); }; + writeMap[0x196 >> 1] = function(value, hpos) { SAER.playfield.COLOR_WRITE(hpos, value & 0xfff, 11); }; + writeMap[0x198 >> 1] = function(value, hpos) { SAER.playfield.COLOR_WRITE(hpos, value & 0xfff, 12); }; + writeMap[0x19A >> 1] = function(value, hpos) { SAER.playfield.COLOR_WRITE(hpos, value & 0xfff, 13); }; + writeMap[0x19C >> 1] = function(value, hpos) { SAER.playfield.COLOR_WRITE(hpos, value & 0xfff, 14); }; + writeMap[0x19E >> 1] = function(value, hpos) { SAER.playfield.COLOR_WRITE(hpos, value & 0xfff, 15); }; + writeMap[0x1A0 >> 1] = function(value, hpos) { SAER.playfield.COLOR_WRITE(hpos, value & 0xfff, 16); }; + writeMap[0x1A2 >> 1] = function(value, hpos) { SAER.playfield.COLOR_WRITE(hpos, value & 0xfff, 17); }; + writeMap[0x1A4 >> 1] = function(value, hpos) { SAER.playfield.COLOR_WRITE(hpos, value & 0xfff, 18); }; + writeMap[0x1A6 >> 1] = function(value, hpos) { SAER.playfield.COLOR_WRITE(hpos, value & 0xfff, 19); }; + writeMap[0x1A8 >> 1] = function(value, hpos) { SAER.playfield.COLOR_WRITE(hpos, value & 0xfff, 20); }; + writeMap[0x1AA >> 1] = function(value, hpos) { SAER.playfield.COLOR_WRITE(hpos, value & 0xfff, 21); }; + writeMap[0x1AC >> 1] = function(value, hpos) { SAER.playfield.COLOR_WRITE(hpos, value & 0xfff, 22); }; + writeMap[0x1AE >> 1] = function(value, hpos) { SAER.playfield.COLOR_WRITE(hpos, value & 0xfff, 23); }; + writeMap[0x1B0 >> 1] = function(value, hpos) { SAER.playfield.COLOR_WRITE(hpos, value & 0xfff, 24); }; + writeMap[0x1B2 >> 1] = function(value, hpos) { SAER.playfield.COLOR_WRITE(hpos, value & 0xfff, 25); }; + writeMap[0x1B4 >> 1] = function(value, hpos) { SAER.playfield.COLOR_WRITE(hpos, value & 0xfff, 26); }; + writeMap[0x1B6 >> 1] = function(value, hpos) { SAER.playfield.COLOR_WRITE(hpos, value & 0xfff, 27); }; + writeMap[0x1B8 >> 1] = function(value, hpos) { SAER.playfield.COLOR_WRITE(hpos, value & 0xfff, 28); }; + writeMap[0x1BA >> 1] = function(value, hpos) { SAER.playfield.COLOR_WRITE(hpos, value & 0xfff, 29); }; + writeMap[0x1BC >> 1] = function(value, hpos) { SAER.playfield.COLOR_WRITE(hpos, value & 0xfff, 30); }; + writeMap[0x1BE >> 1] = function(value, hpos) { SAER.playfield.COLOR_WRITE(hpos, value & 0xfff, 31); }; + if (SAEV_config.chipset.mask & SAEC_Config_Chipset_Mask_ECS_AGNUS) { + writeMap[0x1C0 >> 1] = function(value, hpos) { SAER.playfield.HTOTAL(value); }; + writeMap[0x1C2 >> 1] = function(value, hpos) { SAER.playfield.HSSTOP(value); }; + writeMap[0x1C4 >> 1] = function(value, hpos) { SAER.playfield.HBSTRT(value); }; + writeMap[0x1C6 >> 1] = function(value, hpos) { SAER.playfield.HBSTOP(value); }; + writeMap[0x1C8 >> 1] = function(value, hpos) { SAER.playfield.VTOTAL(value); }; + writeMap[0x1CA >> 1] = function(value, hpos) { SAER.playfield.VSSTOP(value); }; + writeMap[0x1CC >> 1] = function(value, hpos) { SAER.playfield.VBSTRT(value); }; + writeMap[0x1CE >> 1] = function(value, hpos) { SAER.playfield.VBSTOP(value); }; + /* 1D0 SPRHSTRT W * * UHRES sprite vertical start + 1D2 SPRHSTOP W * * UHRES sprite vertical stop + 1D4 BPLHSTRT W * * UHRES bit plane vertical start + 1D6 BPLHSTOP W * * UHRES bit plane vertical stop + 1D8 HHPOSW W * * DUAL mode hires H beam counter write + 1DA HHPOSR R * * DUAL mode hires H beam counter read*/ + writeMap[0x1DC >> 1] = function(value, hpos) { SAER.playfield.BEAMCON0(value); }; + writeMap[0x1DE >> 1] = function(value, hpos) { SAER.playfield.HSSTRT(value); }; + writeMap[0x1E0 >> 1] = function(value, hpos) { SAER.playfield.VSSTRT(value); }; + writeMap[0x1E2 >> 1] = function(value, hpos) { SAER.playfield.HCENTER(value); }; + } + if (SAEV_config.chipset.mask & (SAEC_Config_Chipset_Mask_ECS_AGNUS | SAEC_Config_Chipset_Mask_ECS_DENISE)) + writeMap[0x1E4 >> 1] = function(value, hpos) { SAER.playfield.DIWHIGH(hpos, value); }; + /* 1E6 BPLHMOD W * * UHRES bit plane modulo + 1E8 SPRHPTH W * * UHRES sprite pointer (high 5 bits) + 1EA SPRHPTL W * * UHRES sprite pointer (low 15 bits) + 1EC BPLHPTH W * * VRam (UHRES) bitplane pointer (hi 5 bits) + 1EE BPLHPTL W * * VRam (UHRES) bitplane pointer (lo 15 bits) + */ + if (SAEV_config.chipset.mask & SAEC_Config_Chipset_Mask_AGA) + writeMap[0x1FC >> 1] = function(value, hpos) { SAER.playfield.FMODE(hpos, value); }; + + writeMap[0x1FE >> 1] = function(value, hpos) { SAER.playfield.FNULL(value); }; } } +/*-----------------------------------------------------------------------*/ + +function SAEO_Devices() { + this.virtualdevice_init = function() { + //#ifdef AUTOCONFIG + SAER.autoconf.init(); //rtarea_setup + //#endif + //#ifdef FILESYS + SAER.autoconf.setup(); //rtarea_init + /*uaeres_install(); + hardfile_install(); + #endif + #ifdef AUTOCONFIG*/ + SAER.expansion.setup(); + /*emulib_install(); + uaeexe_install(); + #endif + #ifdef FILESYS + filesys_install(); + #endif + #ifdef CDTV + cdtvcr_reset(); + #endif*/ + } + + this.reset = function(hardreset) { + SAER.gayle.reset(hardreset); + //idecontroller_reset(); + SAER.memory.a1000_reset(); + SAER.disk.reset(); + SAER.cia.reset(); + SAER.gayle.reset(0); + /*#ifdef WITH_TOCCATA + sndboard_reset(); + #endif*/ + //#ifdef AUTOCONFIG + SAER.expansion.reset(); + SAER.autoconf.reset(); + //#endif + } + + this.vsync_pre = function() { + //SAER.audio.vsync(); empty + SAER.cia.vsync(); + /*inputdevice_vsync(); + filesys_vsync(); + sampler_vsync(); + clipboard_vsync(); + #ifdef RETROPLATFORM + rp_vsync(); + #endif + #ifdef CD32 + cd32_fmv_vsync_handler(); + #endif + statusline_vsync(); + */ + } + + this.vsync_post = function() { + /*#ifdef WITH_TOCCATA + sndboard_vsync(); + #endif*/ + } + + this.hsync = function(onvsync) { + /*#ifdef CD32 + AKIKO_hsync_handler(); + cd32_fmv_hsync_handler(); + #endif + #ifdef CDTV + CDTV_hsync_handler(); + CDTVCR_hsync_handler(); + #endif*/ + SAER.blitter.decide_blitter(-1); + /*#ifdef PICASSO96 + picasso_handle_hsync(); + #endif + #ifdef WITH_TOCCATA + sndboard_hsync(); + #endif*/ + SAER.disk.hsync(); + if (SAEV_config.audio.mode != SAEC_Config_Audio_Mode_Off) + SAER.audio.hsync(); + + //SAER.cia.hsync(); //OWN empty + //serial_hsynchandler(); + if (SAEV_config.chipset.ide >= 0 || SAEV_config.chipset.pcmcia) //OWN ATT + SAER.gayle.hsync(); + //idecontroller_hsync(); + } + + this.rethink = function() { + SAER.cia.rethink(); + /*#ifdef CDTV + rethink_cdtv(); + rethink_cdtvcr(); + #endif + #ifdef CD32 + rethink_akiko(); + rethink_cd32fmv(); + #endif + #ifdef WITH_TOCCATA + sndboard_rethink(); + #endif*/ + SAER.gayle.rethink(); + //idecontroller_rethink(); + //SAER.autoconf.rethink_traps(); //empty + } + + this.update_sound = function(clk, syncadjust) { + SAER.audio.update_sound(clk); + //update_sndboard_sound (clk / syncadjust); + //update_cda_sound(clk / syncadjust); + } + + /*this.update_sync = function(svpos, syncadjust) { + cd32_fmv_set_sync(svpos, syncadjust); + }*/ +} diff --git a/sae/disassembler.js b/sae/disassembler.js new file mode 100644 index 0000000..89fc274 --- /dev/null +++ b/sae/disassembler.js @@ -0,0 +1,58 @@ +/*------------------------------------------------------------------------- +| SAE - Scripted Amiga Emulator +| https://github.com/naTmeg/ScriptedAmigaEmulator +| +| Copyright (C) 2012-2016 Rupert Hausberger +| +| This program is free software; you can redistribute it and/or +| modify it under the terms of the GNU General Public License +| as published by the Free Software Foundation; either version 2 +| of the License, or (at your option) any later version. +| +| This program is distributed in the hope that it will be useful, +| but WITHOUT ANY WARRANTY; without even the implied warranty of +| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +| GNU General Public License for more details. +-------------------------------------------------------------------------*/ +/* errors (copied from amiga.js) */ + +function SAEO_Error(err, msg) { + this.err = err; + this.msg = msg; +} +SAEO_Error.prototype = new Error; + +const SAEE_None = 0; + +const SAEE_AlreadyRunning = 1; +const SAEE_NotRunning = 2; +const SAEE_NoTimer = 3; +const SAEE_NoMemory = 4; +const SAEE_Assert = 5; +const SAEE_Internal = 6; + +const SAEE_Config_Invalid = 10; + +const SAEE_CPU_Internal = 20; +const SAEE_CPU_Requires68020 = 21; +const SAEE_CPU_Requires680EC20 = 22; +const SAEE_CPU_Requires68030 = 23; +const SAEE_CPU_Requires68040 = 24; + +/*-----------------------------------------------------------------------*/ + +function ScriptedDisAssembler() { + this.cpu = new SAEO_CPU(); + var err = this.cpu.setup_da(68030); + if (err != SAEE_None) + throw err; + + /*---------------------------------*/ + + this.getConfig = function() { + return this.cpu.getConfig_da(); + } + this.disassemble = function() { + return this.cpu.disassemble(); + } +} diff --git a/sae/disk.js b/sae/disk.js index 90aaf8d..2c4ee1f 100644 --- a/sae/disk.js +++ b/sae/disk.js @@ -1,475 +1,1636 @@ -/************************************************************************** -* SAE - Scripted Amiga Emulator -* -* 2012-2015 Rupert Hausberger -* -* https://github.com/naTmeg/ScriptedAmigaEmulator -* -*************************************************************************** -* Notes: Ported from WinUAE 2.5.0 -* -**************************************************************************/ +/*------------------------------------------------------------------------- +| SAE - Scripted Amiga Emulator +| https://github.com/naTmeg/ScriptedAmigaEmulator +| +| Copyright (C) 2012-2016 Rupert Hausberger +| +| This program is free software; you can redistribute it and/or +| modify it under the terms of the GNU General Public License +| as published by the Free Software Foundation; either version 2 +| of the License, or (at your option) any later version. +| +| This program is distributed in the hope that it will be useful, +| but WITHOUT ANY WARRANTY; without even the implied warranty of +| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +| GNU General Public License for more details. +| +| Note: ported from WinUAE 3.2.x +-------------------------------------------------------------------------*/ +/* global constants */ -const LONGWRITEMODE = 0; - -const FLOPPY_DRIVE_HD = 1; -const FLOPPY_WRITE_MAXLEN = 0x3800; +const SAEC_Disk_Create_Mode_Normal = 1; +const SAEC_Disk_Create_Mode_Custom = 2; -const DDHDMULT = FLOPPY_DRIVE_HD ? 2 : 1; +const SAEC_Disk_Create_Type_35_DD = 1; +const SAEC_Disk_Create_Type_35_HD = 2; +const SAEC_Disk_Create_Type_35_DD_PC = 3; +const SAEC_Disk_Create_Type_35_HD_PC = 4; +const SAEC_Disk_Create_Type_525_SD = 5; -const MAX_FLOPPY_DRIVES = 4; -const MAX_SECTORS = DDHDMULT * 11; -const MAX_TRACKS = 2 * 83; +/*---------------------------------*/ +/* global objects */ -const MIN_STEPLIMIT_CYCLE = CYCLE_UNIT * 250; +function SAEO_DiskInfo() { //struct diskinfo + this.diskname = ""; + this.hd = false; -const DISK_INDEXSYNC = 1; -const DISK_WORDSYNC = 2; -const DISK_REVOLUTION = 4; /* 8,16,32,64 */ + this.crc32 = 0; -const DSKREADY_UP_TIME = 20; -const DSKREADY_DOWN_TIME = 50; -const WORDSYNC_TIME = 11; + this.bootblock = new Uint8Array(1024); + this.bootblockChecksum = false; + this.bootblockChecksumValid = false; + this.bootblockType = 0; -const DSKDMA_OFF = 0; -const DSKDMA_READ = 1; -const DSKDMA_WRITE = 2; + this.unreadable = false; -const DRIVE_ID_NONE = 0x00000000; -const DRIVE_ID_35DD = 0xFFFFFFFF; -const DRIVE_ID_35HD = 0xAAAAAAAA; -const DRIVE_ID_525SD = 0x55555555; + this.clr = function() { + this.diskname = ""; + this.hd = false; -const TRACK_AMIGADOS = 0; -const TRACK_RAW = 1; -const TRACK_RAW1 = 2; -const TRACK_PCDOS = 3; -const TRACK_DISKSPARE= 4; -const TRACK_NONE = 5; + this.crc32 = 0; -const ADF_NONE = -1; -const ADF_NORMAL = 0; -const ADF_EXT1 = 1; -const ADF_EXT2 = 2; -/*const ADF_FDI = 3; -const ADF_IPF = 4; -const ADF_PCDOS = 5;*/ + SAEF_memset(this.bootblock,0, 0, 1024); + this.bootblockChecksum = 0; + this.bootblockChecksumValid = false; + this.bootblockType = 0; -function Track() { - this.len = 0; - this.offs = 0; - this.bitlen = 0; - this.sync = 0; - this.type = TRACK_NONE; + this.unreadable = false; + }; } -function get_floppy_speed() { - var speed = AMIGA.config.floppy.speed == SAEV_Config_Floppy_Speed_Turbo ? 100 : AMIGA.config.floppy.speed; - return Math.floor((AMIGA.config.video.ntsc ? 1812 : 1829) * 100 / speed); -} +/*---------------------------------*/ -function uaerand() { - var l = 0, u = 0xffffffff; - return Math.floor((Math.random() * (u - l + 1)) + l); -} +function SAEO_Disk() { + /*#define DISK_DEBUG_DMA_READ 1 + #define DISK_DEBUG_DMA_WRITE 2 + #define DISK_DEBUG_PIO 4 + const disk_debug_mode = 0; + const disk_debug_track = -1;*/ + const disk_debug_logging = 0; -function Drive(number) { - this.num = number; - this.diskdata = null; - this.diskfile = null; - //this.writediskfile = null; - this.filetype = 0; //drive_filetype - this.trackdata = new Array(MAX_TRACKS); for (var i = 0; i < MAX_TRACKS; i++) this.trackdata[i] = new Track(); - //this.writetrackdata = new Array(MAX_TRACKS); for (var i = 0; i < MAX_TRACKS; i++) this.trackdata[i] = new Track(); - this.writebuffer = new Uint8Array(544 * MAX_SECTORS); for (var i = 0; i < 544 * MAX_SECTORS; i++) this.writebuffer[i] = 0; - this.buffered_cyl = 0; - this.buffered_side = 0; - this.cyl = 0; - this.motoroff = true; - this.motordelay = false; /* dskrdy needs some clock cycles before it changes after switching off motor */ - //this.state = 0; - this.wrprot = false; - this.bigmfmbuf = new Uint16Array(0x4000 * DDHDMULT); for (var i = 0; i < 0x4000 * DDHDMULT; i++) this.bigmfmbuf[i] = 0; - this.tracktiming = new Uint16Array(0x4000 * DDHDMULT); for (var i = 0; i < 0x4000 * DDHDMULT; i++) this.tracktiming[i] = 0; - this.skipoffset = 0; - this.mfmpos = 0; - this.indexoffset = 0; - this.tracklen = 0; - this.prevtracklen = 0; - this.trackspeed = 0; - this.num_tracks = 0; - this.num_secs = 0; - this.hard_num_cyls = 0; - this.dskchange = false; - this.dskchange_time = 0; - this.dskready = false; - this.dskready_up_time = 0; - this.dskready_down_time = 0; - this.writtento = 0; - this.steplimit = 0; - this.steplimitcycle = 0; - this.indexhack = 0; - this.indexhackmode = 0; - this.ddhd = 0; - this.idbit = 0; - this.drive_id_scnt = 0; - this.drive_id = DRIVE_ID_NONE; - this.useturbo = false; - this.floppybitcounter = 0; - - /*this.id_name = function () { - switch (this.drive_id) { - case DRIVE_ID_35HD : - return '3.5HD'; - case DRIVE_ID_525SD: - return '5.25SD'; - case DRIVE_ID_35DD : - return '3.5DD'; - case DRIVE_ID_NONE : - return 'NONE'; - } - return 'UNKNOWN'; - };*/ + const DEBUG_DRIVE_ID = 0; + const REVOLUTION_DEBUG = 0; - this.set_id = function () { - switch (AMIGA.config.floppy.drive[this.num].type) { - case SAEV_Config_Floppy_Type_35_HD: - { - if (FLOPPY_DRIVE_HD) { - if (!this.diskfile || this.ddhd <= 1) - this.drive_id = DRIVE_ID_35DD; - else - this.drive_id = DRIVE_ID_35HD; - } else - this.drive_id = DRIVE_ID_35DD; + /*---------------------------------*/ - break; - } - case SAEV_Config_Floppy_Type_35_DD: - this.drive_id = DRIVE_ID_35DD; - break; - case SAEV_Config_Floppy_Type_525_SD: - this.drive_id = DRIVE_ID_525SD; - break; - case SAEV_Config_Floppy_Type_None: - this.drive_id = DRIVE_ID_NONE; - break; - default: - this.drive_id = DRIVE_ID_35DD; - } - //BUG.info('Drive.set_id() DF%d set to %s', this.num, this.id_name()); - }; - - this.get_floppy_speed2 = function () { - var m = Math.floor(get_floppy_speed() * this.tracklen / (2 * 8 * (AMIGA.config.video.ntsc ? 6399 : 6334) * this.ddhd)); - if (m <= 0) m = 1; - return m; - }; - - this.reset = function () { - //BUG.info('Drive.reset() DF%d', this.num); + const FLOPPY_WRITE_MAXLEN = 0x3800; + /* writable track length with normal 2us bitcell/300RPM motor, 12667 PAL, 12797 NTSC */ + //function FLOPPY_WRITE_LEN() { return SAEV_config.floppy.writeLength > 256 ? SAEV_config.floppy.writeLength / 2 : (SAEV_config.chipset.ntsc ? (12798 / 2) : (12668 / 2)); } + //function FLOPPY_WRITE_LEN() { return SAEV_config.chipset.ntsc ? 12798 / 2 : 12668 / 2; } + function FLOPPY_WRITE_LEN() { return SAEV_config.chipset.ntsc ? 6399 : 6334; } + //function FLOPPY_GAP_LEN() { return FLOPPY_WRITE_LEN() - 11 * 544; } /* This works out to 350 */ + function FLOPPY_GAP_LEN() { return SAEV_config.chipset.ntsc ? 415 : 350; } /* This works out to 415/350 */ + + /* (cycles/bitcell) << 8, normal = ((2us/280ns)<<8) = ~1828.5714 */ + function NORMAL_FLOPPY_SPEED() { return SAEV_config.chipset.ntsc ? 1812 : 1829; } + + const DDHDMULT = 2; + const MAX_SECTORS = DDHDMULT * 11; + const MAX_FLOPPY_DRIVES = 4; + + const MIN_STEPLIMIT_CYCLE = 140 * SAEC_Events_CYCLE_UNIT; + + const exeheader = [0x00,0x00,0x03,0xf3,0x00,0x00,0x00,0x00]; + + /*---------------------------------*/ + + var side = 0, direction = 0, reserved_side = 0; + var selected = 15, disabled = 0, reserved = 0; //u8 + + var writebuffer = new Uint8Array(544 * MAX_SECTORS); + var longwritemode = 0; + + const DISK_INDEXSYNC = 1; + const DISK_WORDSYNC = 2; + const DISK_REVOLUTION = 4; /* 8,16,32,64 */ + + const DSKREADY_UP_TIME = 18; + const DSKREADY_DOWN_TIME = 24; + const WORDSYNC_TIME = 11; + + const DSKDMA_OFF = 0; + const DSKDMA_INIT = 1; + const DSKDMA_READ = 2; + const DSKDMA_WRITE = 3; + + var dskdmaen = 0, dsklength = 0, dsklength2 = 0, dsklen = 0; + var dskbytr_val = 0; //u16 + var dskpt = 0; //u32 + var fifo_filled = false; + var fifo = new Uint16Array(3); + var fifo_inuse = new Int8Array(3); //int [3] + var dma_enable = 0, bitoffset = 0, syncoffset = 0; + var word = 0, dsksync = 0; //u16 + var dsksync_cycles = 0; //ulong + var disk_hpos = 0; + var disk_jitter = 0; + var indexdecay = 0; + var prev_data = 0; //u8 + var prev_step = 0; + var initial_disk_statusline = false; + //var disk_info_data = new SAEO_DiskInfo(); + var amax_enabled = false; + var linecounter = 0; + var prev_days = 0, prev_mins = 0, prev_ticks = 0; + var warned_ext2 = false; + var warned_trackspeed = 0; + var driveNames = ["","","",""]; //OWN + + /*---------------------------------*/ + + const MAX_TRACKS = 2 * 83; + + const TRACK_AMIGADOS = 0; + const TRACK_RAW = 1; + const TRACK_RAW1 = 2; + const TRACK_PCDOS = 3; + const TRACK_DISKSPARE = 4; + const TRACK_NONE = 5; + + function trackid() { + this.len = 0; //u16 + this.offs = 0; //u32 + this.bitlen = 0; + this.track = 0; + this.sync = 0; //u16 + this.type = TRACK_NONE; + this.revolutions = 0; + } + + /*---------------------------------*/ + + /* We have three kinds of Amiga floppy drives + * - internal A500/A2000 drive: + * ID is always DRIVE_ID_NONE (S.T.A.G expects this) + * - HD drive (A3000/A4000): + * ID is DRIVE_ID_35DD if DD floppy is inserted or drive is empty + * ID is DRIVE_ID_35HD if HD floppy is inserted + * - regular external drive: + * ID is always DRIVE_ID_35DD + */ + const DRIVE_ID_NONE = 0x00000000; + const DRIVE_ID_35DD = 0xFFFFFFFF; + const DRIVE_ID_35HD = 0xAAAAAAAA; + const DRIVE_ID_525SD = 0x55555555; /* 40 track 5.25 drive , kickstart does not recognize this */ + + const ADF_NONE = -1; + const ADF_NORMAL = 0; + const ADF_EXT1 = 1; + const ADF_EXT2 = 2; + //const ADF_FDI = 3; /* not implemented */ + //const ADF_IPF = 4; /* not implemented */ + const ADF_SCP = 5; + //const ADF_CATWEASEL = 6; /* not implemented (support not possible with javascript) */ + const ADF_PCDOS = 7; + const ADF_KICK = 8; + const ADF_SKICK = 9; + + function drive(num) { + this.num = num; //OWN + this.diskfile = null; //zfile * + this.writediskfile = null; + this.pcdecodedfile = null; this.filetype = ADF_NONE; - this.diskfile = null; - //this.writediskfile = null; - this.motoroff = true; - this.idbit = 0; - this.drive_id = 0; - this.drive_id_scnt = 0; - this.indexhackmode = 0; - this.dskchange_time = 0; - this.dskchange = false; - this.dskready_down_time = 0; - this.dskready_up_time = 0; - this.buffered_cyl = -1; - this.buffered_side = -1; - if (this.num == 0 && AMIGA.config.floppy.drive[this.num].type == SAEV_Config_Floppy_Type_35_DD) - this.indexhackmode = 1; - this.set_id(); - }; - - this.updatemfmpos = function () { - if (this.prevtracklen) - this.mfmpos = this.mfmpos * Math.floor(Math.floor(this.tracklen * 1000 / this.prevtracklen) / 1000); - this.mfmpos %= this.tracklen; - this.prevtracklen = this.tracklen; - }; - - this.reset_track = function () { - //BUG.info('Drive.reset_track() DF%d', this.num); - this.tracklen = (AMIGA.config.video.ntsc ? 6399 : 6334) * this.ddhd * 2 * 8; - this.trackspeed = get_floppy_speed(); - this.buffered_side = -1; - this.skipoffset = -1; - this.tracktiming[0] = 0; - for (var i = 0; i < (AMIGA.config.video.ntsc ? 6399 : 6334) * this.ddhd; i++) this.bigmfmbuf[i] = 0xaaaa; //memset (this.bigmfmbuf, 0xaa, (AMIGA.config.video.ntsc ? 6399 : 6334) * 2 * this.ddhd); - this.updatemfmpos(); - }; - - function strncmp_as(str1, str2, n) { - for (var i = 0; i < n; i++) { - if (str1[i] != (str2.charCodeAt(i) & 0xff)) - return 1; + this.trackdata = new Array(MAX_TRACKS); + this.writetrackdata = new Array(MAX_TRACKS); + for (var vi = 0; vi < MAX_TRACKS; vi++) { + this.trackdata[vi] = new trackid(); + this.writetrackdata[vi] = new trackid(); } - return 0; - } - /*function strncmp_aa(str1, str2, n) { - for (var i = 0; i < n; i++) { - if (str1[i] != str2[i]) - return 1; - } - return 0; - }*/ - this.insert = function () { - //BUG.info('DF%d.insert()', this.num); - //const exeheader = [0x00,0x00,0x03,0xf3,0x00,0x00,0x00,0x00]; - - this.filetype = ADF_NONE; - this.diskfile = null; - //this.writediskfile = null; - this.ddhd = 1; - this.num_secs = 0; - this.hard_num_cyls = AMIGA.config.floppy.drive[this.num].type == SAEV_Config_Floppy_Type_525_SD ? 40 : 80; - this.tracktiming[0] = 0; - this.useturbo = false; + this.buffered_cyl = 0; + this.buffered_side = 0; + this.cyl = 0; + this.motoroff = false; + this.motordelay = 0; /* dskrdy needs some clock cycles before it changes after switching off motor */ + this.state = false; + this.wrprot = false; + this.forcedwrprot = false; + this.bigmfmbuf = new Uint16Array(0x4000 * DDHDMULT); + this.tracktiming = new Uint16Array(0x4000 * DDHDMULT); + this.multi_revolution = 0; + this.revolution_check = 0; + this.skipoffset = 0; + this.mfmpos = 0; this.indexoffset = 0; - - var size = 0; - if (this.diskdata !== null) { - this.diskfile = new Uint8Array(this.diskdata.length); - for (var i = 0; i < this.diskdata.length; i++) - this.diskfile[i] = this.diskdata[i]; - size = this.diskfile.length; - } - - if (!this.motoroff) { - this.dskready_up_time = DSKREADY_UP_TIME; - this.dskready_down_time = 0; - } - if (this.diskfile === null) { - this.reset_track(); - return 0; - } - - if (strncmp_as(this.diskfile, 'UAE-1ADF', 8) == 0) { - //BUG.info('DF%d.insert() UAE-1ADF', this.num); - - //read_header_ext2 (drv->diskfile, drv->trackdata, &drv->num_tracks, &drv->ddhd); - this.filetype = ADF_EXT2; - this.num_secs = 11; - if (this.ddhd > 1) - this.num_secs = 22; - } - else if (strncmp_as(this.diskfile, 'UAE--ADF', 8) == 0) { - //BUG.info('DF%d.insert() UAE--ADF', this.num); - var offs = 160 * 4 + 8; - - this.wrprot = true; - this.filetype = ADF_EXT1; - this.num_tracks = 160; - this.num_secs = 11; - - for (var i = 0; i < this.num_tracks; i++) { - var buffer = []; - for (var j = 0; j < 4; j++) - buffer[j] = this.diskfile[8 + i * 4 + j]; - - this.trackdata[i].sync = buffer[0] * 256 + buffer[1]; - this.trackdata[i].len = buffer[2] * 256 + buffer[3]; - this.trackdata[i].offs = offs; - - if (this.trackdata[i].sync == 0) { - this.trackdata[i].type = TRACK_AMIGADOS; - this.trackdata[i].bitlen = 0; - } else { - this.trackdata[i].type = TRACK_RAW1; - this.trackdata[i].bitlen = this.trackdata[i].len * 8; - } - offs += this.trackdata[i].len; - } - } - /*else if (strncmp_aa(this.diskfile, exeheader, 8) == 0) { - //BUG.info('DF%d.insert() EXE', this.num); - //struct zfile *z = zfile_fopen_empty(NULL, "", 512 * 1760); - //createimagefromexe (drv->diskfile, z); - //zfile_fclose (drv->diskfile); - - //this.diskfile = z; - this.filetype = ADF_NORMAL; - this.num_tracks = 160; - this.num_secs = 11; - - for (var i = 0; i < this.num_tracks; i++) { - this.trackdata[i].type = TRACK_AMIGADOS; - this.trackdata[i].len = 512 * this.num_secs; - this.trackdata[i].bitlen = 0; - this.trackdata[i].offs = i * 512 * this.num_secs; - } - this.useturbo = true; - }*/ - else { - this.filetype = ADF_NORMAL; - - /* high-density or diskspare disk? */ - var ds = false; - this.num_tracks = 0; - if (size > 160 * 11 * 512 + 511) { /* larger than standard adf? */ - for (var i = 80; i <= 83; i++) { - if (size == i * 22 * 512 * 2) { // HD - this.ddhd = 2; - this.num_tracks = Math.floor(size / (512 * (this.num_secs = 22))); - break; - } - if (size == i * 11 * 512 * 2) { // >80 cyl DD - this.num_tracks = Math.floor(size / (512 * (this.num_secs = 11))); - break; - } - if (size == i * 12 * 512 * 2) { // ds 12 sectors - this.num_tracks = Math.floor(size / (512 * (this.num_secs = 12))); - ds = true; - break; - } - if (size == i * 24 * 512 * 2) { // ds 24 sectors - this.num_tracks = Math.floor(size / (512 * (this.num_secs = 24))); - this.ddhd = 2; - ds = true; - break; - } - } - if (this.num_tracks == 0) { - this.num_tracks = Math.floor(size / (512 * (this.num_secs = 22))); - this.ddhd = 2; - } - } else - this.num_tracks = Math.floor(size / (512 * (this.num_secs = 11))); - - if (!ds && this.num_tracks > MAX_TRACKS) - Fatal(SAEE_Disk_File_Too_Big, sprintf('The diskfile in DF%d is too big. (%d tracks)', this.num, this.num_tracks)); - - for (var i = 0; i < this.num_tracks; i++) { - this.trackdata[i].type = ds ? TRACK_DISKSPARE : TRACK_AMIGADOS; - this.trackdata[i].len = 512 * this.num_secs; - this.trackdata[i].bitlen = 0; - this.trackdata[i].offs = i * 512 * this.num_secs; - } - } - this.set_id(); - this.fill_bigbuf(AMIGA.disk.side, 1); - - this.mfmpos = uaerand(); - this.mfmpos |= (uaerand() << 16); - this.mfmpos %= this.tracklen; + this.tracklen = 0; + this.revolutions = 0; this.prevtracklen = 0; - return 1; - }; - - this.eject = function () { - //BUG.info('DF%d.eject()', this.num); - this.filetype = ADF_NONE; - this.diskfile = null; - //this.writediskfile = null; - this.dskchange = true; + this.trackspeed = 0; + this.num_tracks = 0; + this.write_num_tracks = 0; + this.num_secs = 0; + this.num_heads = 0; + this.hard_num_cyls = 0; + this.dskeject = false; + this.dskchange = false; this.dskchange_time = 0; + this.dskchange_request = false; //OWN this.dskready = false; this.dskready_up_time = 0; this.dskready_down_time = 0; - this.ddhd = 1; - this.set_id(); - }; - - this.is_empty = function () { - return this.diskfile === null; - }; + this.writtento = 0; + this.steplimit = 0; + this.steplimitcycle = 0; //frame_time_t + this.indexhack = false; + this.indexhackmode = 0; + this.ddhd = 0; /* 1=DD 2=HD */ + this.drive_id_scnt = 0; /* drive id shift counter */ + this.idbit = 0; + this.drive_id = 0; /* drive id to be reported */ + //this.newname = ""; /* storage space for new filename during eject delay */ + //this.newnamewriteprotected = false; + this.newfile = null; //OWN + this.crc32 = 0; + //FDI *fdi; + this.useturbo = 0; + this.floppybitcounter = 0; /* number of bits left */ + this.amax = false; + this.lastdataacesstrack = 0; + this.lastrev = 0; + this.track_access_done = false; + } + var floppy = new Array(MAX_FLOPPY_DRIVES); + for (var vi = 0; vi < MAX_FLOPPY_DRIVES; vi++) + floppy[vi] = new drive(vi); - this.set_steplimit = function () { - this.steplimit = 10; - this.steplimitcycle = AMIGA.events.currcycle; - }; - - this.step = function () { - if (!this.is_empty()) - this.dskchange = 0; + var bigmfmbufw = new Uint16Array(0x4000 * DDHDMULT); - if (this.steplimit && AMIGA.events.currcycle - this.steplimitcycle < MIN_STEPLIMIT_CYCLE) { - BUG.info('Drive.step() DF%d, ignoring step %d', this.num, Math.floor((AMIGA.events.currcycle - this.steplimitcycle) * CYCLE_UNIT_INV)); + /*-----------------------------------------------------------------------*/ + /* SECT drive AMAX-support */ + /*-----------------------------------------------------------------------*/ + + const data_scramble = [ 3, 2, 4, 5, 7, 6, 0, 1 ]; + const addr_scramble = [ 14, 12, 2, 10, 15, 13, 1, 0, 7, 6, 5, 4, 8, 9, 11, 3 ]; + + var amax_rom_ptr = 0; + var amax_rom = null; //u8 * + var amax_rom_size = 0; + var amax_rom_oddeven = 0; + //u8 + var amax_data = 0; + var amax_bfd100 = 0; + //var amax_bfe001 = 0; + var amax_bfe001_ov = 0; + var amax_select = 0; + + var amax_lastbit = 0; + var amax_is_active = false; + + const AMAX_LOG = 0; + + function amax_load_byte() { + var v = 0xff; + var addr = 0; + for (var i = 0; i < 16; i++) { + if (amax_rom_ptr & (1 << i)) + addr |= 1 << addr_scramble[i]; + } + if (amax_rom_oddeven < 0) + amax_data = v; + else { + var v = amax_rom[addr * 2 + amax_rom_oddeven]; + val = 0; + for (i = 0; i < 8; i++) { + if (v & (1 << data_scramble[i])) + val |= 1 << i; + } + amax_data = val; + } + if (AMAX_LOG > 0) SAEF_log("disk.amax_load_byte() amax_rom=%d addr=%06x (%06x) data=%02x (%02x) PC=%08x", amax_rom_oddeven, amax_rom_ptr, addr, v, val, SAER_CPU_getPC()); + } + + function amax_check() { + /* DIR low = reset address counter */ + if (amax_bfd100 & 2) { + if (amax_rom_ptr && AMAX_LOG > 0) SAEF_log("disk.amax_check() counter reset PC=%08x", SAER_CPU_getPC()); + amax_rom_ptr = 0; + amax_is_active = false; + } + } + + function amax_diskwrite(w) { + /* this is weird, 1->0 transition in disk write line increases address pointer.. */ + for (var i = 0; i < 16; i++) { + if (amax_lastbit && !(w & 0x8000)) { + amax_rom_ptr++; + if (AMAX_LOG > 0) SAEF_log("disk.amax_diskwrite() counter increase %d PC=%08x", amax_rom_ptr, SAER_CPU_getPC()); + } + amax_lastbit = (w & 0x8000) ? 1 : 0; + w = (w << 1) & 0xffff; + } + amax_rom_ptr &= amax_rom_size - 1; + amax_check(); + } + + this.amax_bfe001_write = function(pra, dra) { + var v = dra & pra; + + //amax_bfe001 = v; + + /* CHNG low -> high: shift data register */ + if ((v & 4) && !(amax_bfe001_ov & 4)) { + amax_data = ((amax_data << 1) | 1) & 0xff; + if (AMAX_LOG > 0) SAEF_log("disk.amax_bfe001_write() data shifted"); + } + /* TK0 = even, WPRO = odd */ + amax_rom_oddeven = -1; + if ((v & (8 | 16)) != (8 | 16)) { + amax_rom_oddeven = 0; + if (!(v & 16)) + amax_rom_oddeven = 1; + } + amax_bfe001_ov = v; + amax_check(); + } + + function amax_disk_select(v, ov, num) { + amax_bfd100 = v; + + amax_select = 1 << (num + 3); + if (!(amax_bfd100 & amax_select) && (ov & amax_select)) { + amax_is_active = true; + amax_load_byte(); + } + amax_check(); + } + + function amax_disk_status(st) { + if (!(amax_data & 0x80)) + st &= ~0x20; + return st; + } + + function amax_active() { + return amax_is_active; + } + + function amax_reset() { + amax_rom_ptr = 0; + amax_rom_oddeven = 0; + amax_bfe001_ov = 0; + amax_lastbit = 0; + amax_data = 0xff; + //xfree(amax_rom); + amax_rom = null; + amax_select = 0; + } + + function amax_init() { + //var z = null; + + //if (is_device_rom(&currprefs, SAEC_RomType_AMAX, 0) < 0) return; + if (SAEV_config.memory.amaxRom.size == 0) return; + + amax_reset(); + //if (is_device_rom(SAEV_config, SAEC_RomType_AMAX, 0) > 0) z = read_device_rom(SAEV_config, SAEC_RomType_AMAX, 0, null); + var z = SAEF_ZFile_fopen_file(SAEV_config.memory.amaxRom); + if (z !== null) { + SAEF_ZFile_fseek(z, 0, SEEK_END); + amax_rom_size = SAEF_ZFile_ftell(z); + SAEF_ZFile_fseek(z, 0, SEEK_SET); + } else { + SAEF_log("disk.amax_init() failed to load rom"); + amax_rom_size = 262144; + } + amax_rom = new Uint8Array(amax_rom_size); + if (z !== null) { + SAEF_ZFile_fread(amax_rom,0, amax_rom_size, 1, z); + SAEF_ZFile_fclose(z); + } + SAEF_log("disk.amax_init() loaded %d bytes (%dK ROM)", amax_rom_size, amax_rom_size >> 10); + } + + /*-----------------------------------------------------------------------*/ + /* SECT drive SCP-support */ + /*-----------------------------------------------------------------------*/ + + /* Support for reading .SCP (Supercard Pro) disk flux dumps. + * Based on version by Keir Fraser */ + + const MAX_REVS = 5; + + //enum pll_mode { + const PLL_fixed_clock = 0; /* Fixed clock, snap phase to flux transitions. */ + const PLL_variable_clock = 1; /* Variable clock, snap phase to flux transitions. */ + const PLL_authentic = 2; /* Variable clock, do not snap phase to flux transition. */ + //}; + + function scpDrive_def(num) { + this.num = num + this.zf = null; + + this.track = 0; /* Current track number. */ + + this.dat = null; /* u16 *, Raw track data. */ + this.dat8 = null; //OWN + this.dat16 = null; //OWN + this.datsz = 0; + + this.revs = 0; /* stored disk revolutions */ + this.dat_idx = 0; /* current index into dat[] */ + this.index_pos = 0; /* next index offset */ + this.nr_index = 0; + this.index_off = new Uint32Array(MAX_REVS); /* data offsets of each index */ + + this.latency = 0; /* u64, Accumulated read latency in nanosecs. */ + + this.pll_mode = 0; /* Flux-based streams: Authentic emulation of FDC PLL behaviour? */ + + this.flux = 0; /* signed, Nanoseconds to next flux reversal */ + this.clock = 0; /* signed, Clock base value in nanoseconds */ + this.clock_centre = 0; //signed + this.clocked_zeros = 0; + + this.clr = function() { + this.zf = null; + this.track = 0; + this.dat16 = null; + this.dat8 = null; + this.dat = null; + this.datsz = 0; + this.revs = 0; + this.dat_idx = 0; + this.index_pos = 0; + this.nr_index = 0; + this.index_off = new Uint32Array(MAX_REVS); + this.latency = 0; + this.pll_mode = 0; + this.flux = 0; + this.clock = 0; + this.clock_centre = 0; + this.clocked_zeros = 0; + }; + }; + var scpdrive = new Array(4); + for (var vi = 0; vi < 4; vi++) + scpdrive[vi] = new scpDrive_def(-1); + + const CLOCK_CENTRE = 2000; /* 2000ns = 2us */ + const CLOCK_MAX_ADJ = 10; /* +/- 10% adjustment */ + function CLOCK_MIN(c) { return Math.truncate((c * (100 - CLOCK_MAX_ADJ)) / 100); } + function CLOCK_MAX(c) { return Math.truncate((c * (100 + CLOCK_MAX_ADJ)) / 100); } + + const SCK_NS_PER_TICK = 25; + + function scp_open(zf, drv) { //, *num_tracks) { + var d = scpdrive[drv]; + var header = new Uint8Array(0x10); header[0] = 0; + + scp_close(drv); + + SAEF_ZFile_fread(header,0, header.length, 1, zf); + if (SAEF_CompareArray(header, SAEF_String2Array("SCP"), 3) != 0) { + SAEF_warn("disk.scp_open() header missing"); + return false; + } + if (header[5] == 0) { + SAEF_warn("disk.scp_open() invalid revolution count (%d)", header[5]); + return false; + } + if (header[9] != 0 && header[9] != 16) { + SAEF_warn("disk.scp_open() unsupported bit cell time width (%d)", header[9]); + return false; + } + d.zf = zf; + d.revs = Math.min(header[5], MAX_REVS); + + floppy[drv].num_tracks = header[7] + 1; // *num_tracks = header[7] + 1; + SAEF_log("disk.scp_open() ok, %d tracks", floppy[drv].num_tracks); + return true; + } + + function scp_close(drv) { + var d = scpdrive[drv]; + if (d.revs) { + //xfree(d.dat); + d.clr(); //memset(d, 0, sizeof(*d)); + } + } + + //function scp_loadtrack(uae_u16 *mfmbuf, uae_u16 *tracktiming, int drv, int track, int *tracklength, int *multirev, int *gapoffset, int *nextrev, bool setrev) { + function scp_loadtrack(mfmbuf, tracktiming, drv, track, setrev) { + var d = scpdrive[drv]; + var trk_header = new Uint8Array(4); + var longwords = new ArrayBuffer(3 * 4); + var longwords8 = new Uint8Array(longwords); + var longwords32 = new Uint32Array(longwords); + var trkoffset = new Uint32Array(MAX_REVS); //uint + var hdr_offset, tdh_offset; //u32 + var rev; + + floppy[drv].multi_revolution = 1; // *multirev = 1; + floppy[drv].skipoffset = -1; // *gapoffset = -1; + + //xfree(d.dat); + d.dat16 = null; + d.dat8 = null; + d.dat = null; + d.datsz = 0; + + //hdr_offset = 0x10 + track * sizeof(uint32_t); + hdr_offset = 0x10 + track * 4; + SAEF_ZFile_fseek(d.zf, hdr_offset, SEEK_SET); + + SAEF_ZFile_fread(longwords8,0, longwords.byteLength, 1, d.zf); + tdh_offset = SAEF_le32toh(longwords32[0]); + + SAEF_ZFile_fseek(d.zf, tdh_offset, SEEK_SET); + SAEF_ZFile_fread(trk_header,0, trk_header.length, 1, d.zf); + if (SAEF_CompareArray(trk_header, SAEF_String2Array("TRK"), 3) != 0) { + SAEF_warn("disk.scp_loadtrack() track header not found"); + return false; + } + if (trk_header[3] != track) { + SAEF_warn("disk.scp_loadtrack() track error (%d != %d)", trk_header[3], track); + return false; + } + for (rev = 0 ; rev < d.revs ; rev++) { + SAEF_ZFile_fread(longwords8,0, longwords.byteLength, 1, d.zf); + trkoffset[rev] = tdh_offset + SAEF_le32toh(longwords32[2]); + d.index_off[rev] = SAEF_le32toh(longwords32[1]); + d.datsz += d.index_off[rev]; + } + + //d.dat = xmalloc(uint16_t, d.datsz * sizeof(d.dat[0])); + d.dat = new ArrayBuffer(d.datsz * 2); + d.dat8 = new Uint8Array(d.dat); + d.dat16 = new Uint16Array(d.dat); + d.datsz = 0; + + for (rev = 0 ; rev < d.revs ; rev++) { + SAEF_ZFile_fseek(d.zf, trkoffset[rev], SEEK_SET); + SAEF_ZFile_fread(d.dat8,d.datsz * 2, d.index_off[rev] * 2, 1, d.zf); + d.datsz += d.index_off[rev]; + d.index_off[rev] = d.datsz; + } + + d.track = track; + d.pll_mode = PLL_authentic; + d.dat_idx = 0; + d.index_pos = d.index_off[0]; + d.clock = d.clock_centre = CLOCK_CENTRE; + d.nr_index = 0; + d.flux = 0; + d.clocked_zeros = 0; + + scp_loadrevolution(mfmbuf, drv, tracktiming); //, tracklength); + return true; + } + + function next_flux(d) { + var val = 0; //u32 + + for (;;) { + if (d.dat_idx >= d.index_pos) { + var rev = d.nr_index++ % d.revs; + d.index_pos = d.index_off[rev]; + d.dat_idx = rev ? d.index_off[rev - 1] : 0; + return -1; + } + + var t = SAEF_be16toh(d.dat16[d.dat_idx++]); + if (t == 0) { // overflow + val += 0x10000; if (val > 0xffffffff) val -= 0x100000000; + continue; + } + val += t; if (val > 0xffffffff) val -= 0x100000000; + break; + } + var flux = val * SCK_NS_PER_TICK; while (flux > 0xffffffff) flux -= 0x100000000; + return (flux & 0x80000000) ? flux - 0x100000000 : flux; + } + + function flux_next_bit(d) { + var new_flux; + + while (d.flux < Math.truncate(d.clock / 2)) { //ATT + if ((new_flux = next_flux(d)) == -1) + return -1; + + d.flux += new_flux; + d.clocked_zeros = 0; + } + d.latency += d.clock; + d.flux -= d.clock; + + if (d.flux >= Math.truncate(d.clock / 2)) { //ATT + d.clocked_zeros++; + return 0; + } + + if (d.pll_mode != PLL_fixed_clock) { + // PLL: Adjust clock frequency according to phase mismatch. + if ((d.clocked_zeros >= 1) && (d.clocked_zeros <= 3)) { + // In sync: adjust base clock by 10% of phase mismatch. + var diff = Math.truncate(d.flux / (d.clocked_zeros + 1)); //ATT + d.clock += Math.truncate(diff / 10); //ATT + } else { + // Out of sync: adjust base clock towards centre. + d.clock += Math.truncate((d.clock_centre - d.clock) / 10); //ATT + } + + // Clamp the clock's adjustment range. + d.clock = Math.max(CLOCK_MIN(d.clock_centre), Math.min(CLOCK_MAX(d.clock_centre), d.clock)); + } else + d.clock = d.clock_centre; + + // Authentic PLL: Do not snap the timing window to each flux transition. + new_flux = d.pll_mode == PLL_authentic ? Math.truncate(d.flux / 2) : 0; //ATT + d.latency += d.flux - new_flux; + d.flux = new_flux; + return 1; + } + + //void scp_loadrevolution(uae_u16 *mfmbuf, int drv, uae_u16 *tracktiming, int *tracklength) { + function scp_loadrevolution(mfmbuf, drv, tracktiming) { + var d = scpdrive[drv]; + var prev_latency; //u64 + var av_latency; //u32 + var i, j, b; + + d.latency = prev_latency = 0; + for (i = 0; (b = flux_next_bit(d)) != -1; i++) { + if ((i & 15) == 0) + mfmbuf[i >> 4] = 0; + if (b) + mfmbuf[i >> 4] |= 0x8000 >> (i & 15); + + if ((i & 7) == 7) { + tracktiming[i >> 3] = d.latency - prev_latency; + prev_latency = d.latency; + } + } + if (i & 7) + tracktiming[i >> 3] = Math.floor((d.latency - prev_latency) * 8 / (i & 7)); //ATT + + av_latency = Math.floor(prev_latency / (i >> 3)); //ATT + + for (j = 0; j < (i + 7) >> 3; j++) + tracktiming[j] = Math.floor((tracktiming[j] * 1000) / av_latency); //ATT + + floppy[drv].tracklen = i; // *tracklength = i; + } + + /*-----------------------------------------------------------------------*/ + /* SECT drive */ + /*-----------------------------------------------------------------------*/ + + function get_floppy_speed() { + var m = SAEV_config.floppy.speed; + if (m <= 10) m = 100; + return Math.floor(NORMAL_FLOPPY_SPEED() * 100 / m); + } + + function get_floppy_speed2(drv) { + var m = Math.truncate(get_floppy_speed() * drv.tracklen / (FLOPPY_WRITE_LEN() * 2 * drv.ddhd * 8)); + if (m <= 0) + m = 1; + return m; + } + + function drive_id_name(drv) { + switch(drv.drive_id) { + case DRIVE_ID_35HD : return "3.5HD"; + case DRIVE_ID_525SD: return "5.25SD"; + case DRIVE_ID_35DD : return "3.5DD"; + case DRIVE_ID_NONE : return "NONE"; + } + return "UNKNOWN"; + } + + /* Simulate exact behaviour of an A3000T 3.5 HD disk drive. + * The drive reports to be a 3.5 DD drive whenever there is no + * disk or a 3.5 DD disk is inserted. Only 3.5 HD drive id is reported + * when a real 3.5 HD disk is inserted. -Adil */ + function drive_settype_id(drv) { + var t = SAEV_config.floppy.drive[drv.num].type; + + switch (t) { + case SAEC_Config_Floppy_Type_35_HD: { + if (drv.diskfile === null || drv.ddhd <= 1) + drv.drive_id = DRIVE_ID_35DD; + else + drv.drive_id = DRIVE_ID_35HD; + break; + } + case SAEC_Config_Floppy_Type_35_DD_ESCOM: + case SAEC_Config_Floppy_Type_35_DD: + default: + drv.drive_id = DRIVE_ID_35DD; + break; + case SAEC_Config_Floppy_Type_525_SD: + drv.drive_id = DRIVE_ID_525SD; + break; + case SAEC_Config_Floppy_Type_None: + case SAEC_Config_Floppy_Type_35_DD_PC: + case SAEC_Config_Floppy_Type_35_HD_PC: + drv.drive_id = DRIVE_ID_NONE; + break; + } + if (DEBUG_DRIVE_ID) SAEF_log("disk.drive_settype_id() DF%d: set to %s", drv.num, drive_id_name(drv)); + } + + /*-----------------------------------------------------------------------*/ + + function drive_image_free(drv) { + switch (drv.filetype) { + case ADF_SCP: + scp_close(drv.num); + break; + /*case ADF_FDI: + fdi2raw_header_free(drv.fdi); + drv.fdi = 0; + break;*/ + } + drv.filetype = ADF_NONE; + SAEF_ZFile_fclose(drv.diskfile); + drv.diskfile = null; + //SAEF_ZFile_fclose(drv.writediskfile); + drv.writediskfile = null; + //SAEF_ZFile_fclose(drv.pcdecodedfile); + drv.pcdecodedfile = null; + } + + /*-----------------------------------------------------------------------*/ + + function reset_drive_gui(num) { + var gd = SAER.gui.data; + + gd.df[num] = ""; + gd.crc32[num] = 0; + gd.drive_disabled[num] = false; + if (SAEV_config.floppy.drive[num].type <= SAEC_Config_Floppy_Type_None) + gd.drive_disabled[num] = true; + } + + function update_drive_gui(num, force) { + var drv = floppy[num]; + var writ = dskdmaen == DSKDMA_WRITE && drv.state && !((selected | disabled) & (1 << num)); + var gd = SAER.gui.data; + + if (!force && drv.state == gd.drive_motor[num] + && drv.cyl == gd.drive_track[num] + && side == gd.drive_side + && drv.crc32 == gd.crc32[num] + && writ == gd.drive_writing[num] + && gd.df[num] == SAEV_config.floppy.drive[num].file.name + ) return; + + gd.df[num] = SAEV_config.floppy.drive[num].file.name; + gd.crc32[num] = drv.crc32; + gd.drive_motor[num] = drv.state; + gd.drive_track[num] = drv.cyl; + if (reserved & (1 << num)) + gd.drive_side = reserved_side; + else + gd.drive_side = side; + gd.drive_writing[num] = writ; + + SAER.gui.led(num + SAEC_GUI_LED_DF0, (gd.drive_motor[num] ? 1 : 0) | (gd.drive_writing[num] ? 2 : 0), -1); + } + + /*-----------------------------------------------------------------------*/ + /* reset */ + + function reset_drive(num) { + var drv = floppy[num]; + + drv.amax = false; + drive_image_free(drv); + drv.motoroff = true; + drv.idbit = 0; + drv.drive_id = 0; + drv.drive_id_scnt = 0; + drv.lastdataacesstrack = -1; + + disabled &= ~(1 << num); + if (SAEV_config.floppy.drive[num].type <= SAEC_Config_Floppy_Type_None || SAEV_config.floppy.drive[num].type >= SAEC_Config_Floppy_Type_35_DD_PC) + disabled |= 1 << num; + reserved &= ~(1 << num); + if (SAEV_config.floppy.drive[num].type >= SAEC_Config_Floppy_Type_35_DD_PC) + reserved |= 1 << num; + + reset_drive_gui(num); + + /* most internal Amiga floppy drives won't enable + * diskready until motor is running at full speed + * and next indexsync has been passed + */ + drv.indexhackmode = 0; + if (num == 0 && SAEV_config.floppy.drive[num].type == SAEC_Config_Floppy_Type_35_DD) + drv.indexhackmode = 1; + drv.dskchange_time = 0; + drv.dskchange_request = false; + drv.dskchange = false; + drv.dskready_down_time = 0; + drv.dskready_up_time = 0; + drv.buffered_cyl = -1; + drv.buffered_side = -1; + + SAER.gui.led(num + SAEC_GUI_LED_DF0, 0, -1); + drive_settype_id(drv); + //SAEV_config.floppy.drive[num].name = changed_prefs.floppyslots[num].name; + //drv.newname = ""; + //drv.newnamewriteprotected = false; + drv.newfile = null; + if (!drive_insert(drv, SAEV_config, num, SAEV_config.floppy.drive[num].file, false)) + SAER.disk.eject(num); + } + + function setamax() { + amax_enabled = false; + //if (is_device_rom(SAEV_config, SAEC_RomType_AMAX, 0) > 0) { + if (SAEV_config.memory.amaxRom.data.length > 0) { + amax_enabled = true; + // Put A-Max as last drive in drive chain + var i; + for (i = 0; i < MAX_FLOPPY_DRIVES; i++) + if (floppy[i].amax) + return; + for (i = 0; i < MAX_FLOPPY_DRIVES; i++) { + if ((1 << i) & disabled) { + floppy[i].amax = true; + SAEF_log("disk.setamax() using DF%d", i); + return; + } + } + SAEF_warn("disk.setamax() no drive available. (disable an drive to make it working)"); + } + } + + /*-----------------------------------------------------------------------*/ + /* insert / eject */ + + //function DISK_validate_filename(p, fname, leave_open, get_wrprot, get_crc, get_zf) { + function DISK_validate_filename(p, file, leave_open, get_wrprot, get_crc, get_zf) { + var wrprot = false; + var crc32 = 0; + var zf = null; + + if (get_zf) + zf = null; + if (get_crc) + crc32 = 0; + if (get_wrprot) + wrprot = p.floppy.readOnly ? true : false; + + if (leave_open || !get_zf) { + /*var f = SAEF_ZFile_fopen(fname, "r+b", ZFD_NORMAL | ZFD_DISKHISTORY); + if (!f) { + if (get_wrprot) wrprot = true; + f = SAEF_ZFile_fopen(fname, "rb", ZFD_NORMAL | ZFD_DISKHISTORY); + }*/ + var f = SAEF_ZFile_fopen_file(file); + if (f !== null) { + if (get_crc) { + if (file.crc32 !== false) + crc32 = file.crc32; + else + crc32 = SAEF_ZFile_crc32(f); + } + if (get_zf) + zf = f; + else + SAEF_ZFile_fclose(f); + + return [true, wrprot, crc32, zf]; + } + return [false, false, 0, null]; + } else { + /*if (SAEF_ZFile_exists(fname)) { + if (get_wrprot && !p.floppy.readOnly) + wrprot = false; + if (get_crc) { + var f = SAEF_ZFile_fopen(fname, "rb", ZFD_NORMAL | ZFD_DISKHISTORY); + if (f) crc32 = SAEF_ZFile_crc32(f); + SAEF_ZFile_fclose(f); + } + return [true, wrprot, crc32, zf]; + } else { + if (get_wrprot) wrprot = true; + return [false, wrprot, crc32, zf]; + }*/ + } + } + + function updatemfmpos(drv) { + if (drv.prevtracklen) { + drv.mfmpos = Math.floor(drv.mfmpos * Math.floor(drv.tracklen * 1000 / drv.prevtracklen) / 1000); //ATT + if (drv.mfmpos >= drv.tracklen) + drv.mfmpos = drv.tracklen - 1; + } + drv.mfmpos %= drv.tracklen; + drv.prevtracklen = drv.tracklen; + } + + function track_reset(drv) { + drv.tracklen = FLOPPY_WRITE_LEN() * 2 * drv.ddhd * 8; + drv.revolutions = 1; + drv.trackspeed = get_floppy_speed(); + drv.buffered_side = -1; + drv.skipoffset = -1; + drv.tracktiming[0] = 0; + //memset(drv.bigmfmbuf, 0xaa, FLOPPY_WRITE_LEN() * 2 * drv.ddhd); + SAEF_memset(drv.bigmfmbuf,0, 0xaaaa, FLOPPY_WRITE_LEN() * 2 * drv.ddhd >> 1); + updatemfmpos(drv); + } + + /*---------------------------------*/ + + //static int read_header_ext2(struct zfile *diskfile, trackid *trackdata, int *num_tracks, int *ddhd) { + function read_header_ext2(drv, ddhd) { + var buffer = new Uint8Array(2 + 2 + 4 + 4); + + SAEF_ZFile_fseek(drv.diskfile, 0, SEEK_SET); + SAEF_ZFile_fread(buffer,0, 1, 8, drv.diskfile); + if (SAEF_CompareArray(buffer, SAEF_String2Array("UAE-1ADF"), 8) != 0) + return 0; + SAEF_ZFile_fread(buffer,0, 1, 4, drv.diskfile); + drv.num_tracks = buffer[2] * 256 + buffer[3]; + var offs = 8 + 2 + 2 + drv.num_tracks * (2 + 2 + 4 + 4); + + for (var i = 0; i < drv.num_tracks; i++) { + var tid = drv.trackdata[i]; + SAEF_ZFile_fread(buffer,0, 2 + 2 + 4 + 4, 1, drv.diskfile); + tid.type = buffer[3]; + tid.revolutions = buffer[2] + 1; + tid.len = buffer[5] * 65536 + buffer[6] * 256 + buffer[7]; + tid.bitlen = buffer[9] * 65536 + buffer[10] * 256 + buffer[11]; + tid.offs = offs; + if (tid.len > 20000 && ddhd) + drv.ddhd = 2; + tid.track = i; + offs += tid.len; + } + return 1; + } + + /*---------------------------------*/ + + /*static void saveimagecutpathpart(TCHAR *name) { + int i; + + i = _tcslen (name) - 1; + while (i > 0) { + if (name[i] == '/' || name[i] == '\\') { + name[i] = 0; + break; + } + if (name[i] == '.') { + name[i] = 0; + break; + } + i--; + } + while (i > 0) { + if (name[i] == '/' || name[i] == '\\') { + name[i] = 0; + break; + } + i--; + } + } + static void saveimagecutfilepart(TCHAR *name) { + TCHAR tmp[MAX_DPATH]; + int i; + + _tcscpy(tmp, name); + i = _tcslen (tmp) - 1; + while (i > 0) { + if (tmp[i] == '/' || tmp[i] == '\\') { + _tcscpy(name, tmp + i + 1); + break; + } + if (tmp[i] == '.') { + tmp[i] = 0; + break; + } + i--; + } + while (i > 0) { + if (tmp[i] == '/' || tmp[i] == '\\') { + _tcscpy(name, tmp + i + 1); + break; + } + i--; + } + } + static void saveimageaddfilename(TCHAR *dst, const TCHAR *src, int type) { + _tcscat(dst, src); + if (type) + _tcscat(dst, _T(".save_adf")); + else + _tcscat(dst, _T("_save.adf")); + } + + static TCHAR *DISK_get_default_saveimagepath (const TCHAR *name) { + TCHAR name1[MAX_DPATH]; + TCHAR path[MAX_DPATH]; + _tcscpy(name1, name); + saveimagecutfilepart(name1); + fetch_saveimagepath (path, sizeof path / sizeof (TCHAR), 1); + saveimageaddfilename(path, name1, 0); + return my_strdup(path); + } + // -2 = existing, if not, use 0. + // -1 = as configured + // 0 = saveimages-dir + // 1 = image dir + TCHAR *DISK_get_saveimagepath(const TCHAR *name, int type) { + int typev = type; + + for (int i = 0; i < 2; i++) { + if (typev == 1 || (typev == -1 && saveimageoriginalpath) || (typev == -2 && (saveimageoriginalpath || i == 1))) { + TCHAR si_name[MAX_DPATH], si_path[MAX_DPATH]; + _tcscpy(si_name, name); + _tcscpy(si_path, name); + saveimagecutfilepart(si_name); + saveimagecutpathpart(si_path); + _tcscat(si_path, FSDB_DIR_SEPARATOR_S); + saveimageaddfilename(si_path, si_name, 1); + if (typev != -2 || (typev == -2 && SAEF_ZFile_exists(si_path))) + return my_strdup(si_path); + } + if (typev == 2 || (typev == -1 && !saveimageoriginalpath) || (typev == -2 && (!saveimageoriginalpath || i == 1))) { + TCHAR *p = DISK_get_default_saveimagepath(name); + if (typev != -2 || (typev == -2 && SAEF_ZFile_exists(p))) + return p; + xfree(p); + } + } + return DISK_get_saveimagepath(name, -1); + } + static struct zfile *getexistingwritefile(struct uae_prefs *p, const TCHAR *name, bool *wrprot) { + struct zfile *zf = null; + TCHAR *path; + path = DISK_get_saveimagepath(name, saveimageoriginalpath); + DISK_validate_filename (p, path, 1, wrprot, null, &zf); + xfree(path); + if (zf) + return zf; + path = DISK_get_saveimagepath(name, !saveimageoriginalpath); + DISK_validate_filename (p, path, 1, wrprot, null, &zf); + xfree(path); + return zf; + } + static int openwritefile (struct uae_prefs *p, drive *drv, int create) { + bool wrprot = 0; + + drv->writediskfile = getexistingwritefile(p, SAEV_config.floppy.drive[drv.num].name, &wrprot); + if (drv->writediskfile) { + drv->wrprot = wrprot; + if (!read_header_ext2(drv->writediskfile, drv->writetrackdata, &drv->write_num_tracks, 0)) { + SAEF_ZFile_fclose (drv->writediskfile); + drv->writediskfile = 0; + drv->wrprot = 1; + } else { + if (drv->write_num_tracks > drv->num_tracks) + drv->num_tracks = drv->write_num_tracks; + } + } else if (SAEF_ZFile_iscompressed (drv->diskfile)) { + drv->wrprot = 1; + } + return drv->writediskfile ? 1 : 0; + }*/ + + /*---------------------------------*/ + + function isrecognizedext(name) { + var last = name.lastIndexOf("."); + if (last != -1 && last + 1 != name.length) { + var ext = name.substring(last + 1); + ext = ext.toLowerCase(); + if (ext == "adf" || ext == "adz" || ext == "st" || ext == "ima" || ext == "img") { + SAEF_log("disk.isrecognizedext() extention '%s' found", ext); + return true; + } + SAEF_log("disk.isrecognizedext() unknow extention '%s'", ext); + } else + SAEF_log("disk.isrecognizedext() no extention"); + + return false; + } + + function update_disk_statusline(num) { + /* + drive *drv = &floppy[num]; + if (drv->diskfile === null) + return; + const TCHAR *fname = SAEF_ZFile_getoriginalname(drv->diskfile); + if (!fname) + fname = SAEF_ZFile_getname(drv->diskfile); + if (!fname) + fname = _T("?"); + if (disk_info_data.diskname[0]) + statusline_add_message(_T("DF%d: [%s] %s"), num, disk_info_data.diskname, my_getfilepart(fname)); + else + statusline_add_message(_T("DF%d: %s"), num, my_getfilepart(fname));*/ + } + + /*---------------------------------*/ + + //function drive_insert(drv, p, dnum, fname, fake, forcedwriteprotect) { + function drive_insert(drv, p, dnum, file, fake) { + var buffer = new Uint8Array(2 + 2 + 4 + 4); + var tid = null; + + drive_image_free(drv); + //if (!fake) examine_image(p, dnum, disk_info_data); + //DISK_validate_filename(p, fname, 1, &drv.wrprot, &drv.crc32, &drv.diskfile); + //var result = DISK_validate_filename(p, fname, fdata, true, true, true, true); + var result = DISK_validate_filename(p, file, true, true, true, true); + drv.wrprot = result[1]; + drv.crc32 = result[2]; + drv.diskfile = result[3]; + + drv.forcedwrprot = file.prot; //forcedwriteprotect; + if (drv.forcedwrprot) + drv.wrprot = true; + drv.ddhd = 1; + drv.num_heads = 2; + drv.num_secs = 0; + drv.hard_num_cyls = p.floppy.drive[dnum].type == SAEC_Config_Floppy_Type_525_SD ? 40 : 80; + drv.tracktiming[0] = 0; + drv.useturbo = 0; + drv.indexoffset = 0; + if (!fake) { + drv.dskeject = false; + //gui_disk_image_change(dnum, fname, drv.wrprot); + } + + if (!drv.motoroff) { + drv.dskready_up_time = DSKREADY_UP_TIME * 312 + (Math.decimalRandom() & 511); + drv.dskready_down_time = 0; + } + + if (drv.diskfile === null) { + track_reset(drv); + return 0; + } + + if (!fake) { + //inprec_recorddiskchange(dnum, fname, drv.wrprot); + + //if (SAEV_config.floppy.drive[dnum].name !== fname) SAEV_config.floppy.drive[dnum].name = fname; + //SAEV_config.floppy.drive[dnum].forcedWriteProtect = forcedwriteprotect; + //changed_prefs.floppyslots[dnum].name = fname; + //changed_prefs.floppyslots[dnum].forcedWriteProtect = forcedwriteprotect; + + //drv.newname = fname; + //drv.newnamewriteprotected = forcedwriteprotect; + drv.newfile = file.clone(); //ATT + //SAER.gui.filename(dnum, file.name); //fname); + } + + //memset(buffer, 0, sizeof buffer); + SAEF_memset(buffer,0, 0, buffer.length); + + var size = 0; + if (drv.diskfile !== null) { + SAEF_ZFile_fread(buffer,0, 1, 8, drv.diskfile); + SAEF_ZFile_fseek(drv.diskfile, 0, SEEK_END); + size = SAEF_ZFile_ftell(drv.diskfile); + SAEF_ZFile_fseek(drv.diskfile, 0, SEEK_SET); + } + + var canauto = 0; + if (isrecognizedext(file.name)) + canauto = 1; + if (!canauto && drv.diskfile && isrecognizedext(SAEF_ZFile_getname(drv.diskfile))) + canauto = 1; + // if PC-only drive, make sure PC-like floppies are alwayss detected + if (!canauto && SAEV_config.floppy.drive[dnum].type >= SAEC_Config_Floppy_Type_35_DD_PC) + canauto = 1; + + if (SAEF_CompareArray(buffer, SAEF_String2Array("SCP"), 3) == 0) { + //var num_tracks; + drv.wrprot = true; + //if (!scp_open(drv.diskfile, drv.num, num_tracks)) { + if (!scp_open(drv.diskfile, drv.num)) { + SAEF_ZFile_fclose(drv.diskfile); + drv.diskfile = null; + return 0; + } + //drv.num_tracks = num_tracks; + drv.filetype = ADF_SCP; + } + /*else if ((drv.fdi = fdi2raw_header(drv.diskfile))) { + drv.wrprot = true; + drv.num_tracks = fdi2raw_get_last_track(drv.fdi); + drv.num_secs = fdi2raw_get_num_sector(drv.fdi); + drv.filetype = ADF_FDI; + }*/ + else if (SAEF_CompareArray(buffer, SAEF_String2Array("UAE-1ADF"), 8) == 0) { + //read_header_ext2(drv.diskfile, drv.trackdata, &drv.num_tracks, &drv.ddhd); + read_header_ext2(drv, drv.ddhd); + drv.filetype = ADF_EXT2; + drv.num_secs = 11; + if (drv.ddhd > 1) + drv.num_secs = 22; + } + else if (SAEF_CompareArray(buffer, SAEF_String2Array("UAE--ADF"), 8) == 0) { + var offs = 160 * 4 + 8; + + drv.wrprot = true; + drv.filetype = ADF_EXT1; + drv.num_tracks = 160; + drv.num_secs = 11; + + SAEF_ZFile_fseek(drv.diskfile, 8, SEEK_SET); + for (var i = 0; i < 160; i++) { + tid = drv.trackdata[i]; + SAEF_ZFile_fread(buffer,0, 4, 1, drv.diskfile); + tid.sync = buffer[0] * 256 + buffer[1]; + tid.len = buffer[2] * 256 + buffer[3]; + tid.offs = offs; + tid.revolutions = 1; + if (tid.sync == 0) { + tid.type = TRACK_AMIGADOS; + tid.bitlen = 0; + } else { + tid.type = TRACK_RAW1; + tid.bitlen = tid.len * 8; + } + offs += tid.len; + } + } + /*else if (SAEF_CompareArray(buffer, exeheader, 8) == 0) { + var z = SAEF_ZFile_fopen_empty(null, "", 512 * 1760); + if (createimagefromexe(drv.diskfile, z)) { + SAEF_log("disk.drive_insert() converted '%s' to ADF", SAEF_ZFile_getname(drv.diskfile)); + drv.filetype = ADF_NORMAL; + SAEF_ZFile_fclose(drv.diskfile); + drv.diskfile = z; + drv.num_tracks = 160; + drv.num_secs = 11; + for (var i = 0; i < drv.num_tracks; i++) { + tid = drv.trackdata[i]; + tid.type = TRACK_AMIGADOS; + tid.len = 512 * drv.num_secs; + tid.bitlen = 0; + tid.offs = i * 512 * drv.num_secs; + tid.revolutions = 1; + } + drv.useturbo = 1; + } else + //SAEF_warn("disk.drive_insert() can't convert '%s' to ADF, because the file is too big", SAEF_ZFile_getname(drv.diskfile)); + alert(sprintf("Can't convert '%s' to ADF. (too big)", SAEF_ZFile_getname(drv.diskfile))); + }*/ + else if (canauto && ( + // 320k double sided + size == 8 * 40 * 2 * 512 || + // 320k single sided + size == 8 * 40 * 1 * 512 || + + // 360k double sided + size == 9 * 40 * 2 * 512 || + // 360k single sided + size == 9 * 40 * 1 * 512 || + + // 1.2M double sided + size == 15 * 80 * 2 * 512 || + + // 720k/1440k double sided + size == 9 * 80 * 2 * 512 || size == 18 * 80 * 2 * 512 || size == 10 * 80 * 2 * 512 || size == 20 * 80 * 2 * 512 || size == 21 * 80 * 2 * 512 || + size == 9 * 81 * 2 * 512 || size == 18 * 81 * 2 * 512 || size == 10 * 81 * 2 * 512 || size == 20 * 81 * 2 * 512 || size == 21 * 81 * 2 * 512 || + size == 9 * 82 * 2 * 512 || size == 18 * 82 * 2 * 512 || size == 10 * 82 * 2 * 512 || size == 20 * 82 * 2 * 512 || size == 21 * 82 * 2 * 512 || + // 720k/1440k single sided + size == 9 * 80 * 1 * 512 || size == 18 * 80 * 1 * 512 || size == 10 * 80 * 1 * 512 || size == 20 * 80 * 1 * 512 || + size == 9 * 81 * 1 * 512 || size == 18 * 81 * 1 * 512 || size == 10 * 81 * 1 * 512 || size == 20 * 81 * 1 * 512 || + size == 9 * 82 * 1 * 512 || size == 18 * 82 * 1 * 512 || size == 10 * 82 * 1 * 512 || size == 20 * 82 * 1 * 512) + ) { + /* PC formatted image */ + var side; + + drv.num_secs = 9; + drv.ddhd = 1; + + for (side = 2; side > 0; side--) { + if ( size == 9 * 80 * side * 512 || size == 9 * 81 * side * 512 || size == 9 * 82 * side * 512) { + drv.num_secs = 9; + drv.ddhd = 1; + break; + } else if (size == 18 * 80 * side * 512 || size == 18 * 81 * side * 512 || size == 18 * 82 * side * 512) { + drv.num_secs = 18; + drv.ddhd = 2; + break; + } else if (size == 10 * 80 * side * 512 || size == 10 * 81 * side * 512 || size == 10 * 82 * side * 512) { + drv.num_secs = 10; + drv.ddhd = 1; + break; + } else if (size == 20 * 80 * side * 512 || size == 20 * 81 * side * 512 || size == 20 * 82 * side * 512) { + drv.num_secs = 20; + drv.ddhd = 2; + break; + } else if (size == 21 * 80 * side * 512 || size == 21 * 81 * side * 512 || size == 21 * 82 * side * 512) { + drv.num_secs = 21; + drv.ddhd = 2; + break; + } else if (size == 9 * 40 * side * 512) { + drv.num_secs = 9; + drv.ddhd = 1; + break; + } else if (size == 8 * 40 * side * 512) { + drv.num_secs = 8; + drv.ddhd = 1; + break; + } else if (size == 15 * 80 * side * 512) { + drv.num_secs = 15; + drv.ddhd = 1; + break; + } + } + drv.num_tracks = Math.floor(size / (drv.num_secs * 512)); + drv.filetype = ADF_PCDOS; + tid = drv.trackdata[0]; + for (var i = 0; i < drv.num_tracks; i++) { + tid.type = TRACK_PCDOS; + tid.len = 512 * drv.num_secs; + tid.bitlen = 0; + tid.offs = i * 512 * drv.num_secs; + if (side == 1) { + tid++; + tid.type = TRACK_NONE; + tid.len = 512 * drv.num_secs; + } + tid.revolutions = 1; + tid++; + + } + drv.num_heads = side; + if (side == 1) + drv.num_tracks *= 2; + } else if ((size == 262144 || size == 524288) && buffer[0] == 0x11 && (buffer[1] == 0x11 || buffer[1] == 0x14)) { + //256k == Kickstart disk, 512k == SuperKickstart disk + drv.filetype = size == 262144 ? ADF_KICK : ADF_SKICK; + drv.num_tracks = 1760 / (drv.num_secs = 11); + for (var i = 0; i < drv.num_tracks; i++) { + tid = drv.trackdata[i]; + tid.type = TRACK_AMIGADOS; + tid.len = 512 * drv.num_secs; + tid.bitlen = 0; + tid.offs = i * 512 * drv.num_secs - (drv.filetype == ADF_KICK ? 512 : 262144 + 1024); + tid.track = i; + tid.revolutions = 1; + } + } else { + var i; + + var ds = 0; + drv.filetype = ADF_NORMAL; + + /* High-density or diskspare disk? */ + drv.num_tracks = 0; + if (size > 160 * 11 * 512 + 511) { // larger than standard adf? + for (i = 80; i <= 83; i++) { + if (size == i * 22 * 512 * 2) { // HD + drv.num_secs = 22; + drv.num_tracks = size / (22 * 512); + drv.ddhd = 2; + break; + } + if (size == i * 11 * 512 * 2) { // >80 cyl DD + drv.num_secs = 11; + drv.num_tracks = size / (11 * 512); + break; + } + if (size == i * 12 * 512 * 2) { // ds 12 sectors + drv.num_secs = 12; + drv.num_tracks = size / (12 * 512); + ds = 1; + break; + } + if (size == i * 24 * 512 * 2) { // ds 24 sectors + drv.num_secs = 24; + drv.num_tracks = size / (24 * 512); + drv.ddhd = 2; + ds = 1; + break; + } + } + if (drv.num_tracks == 0) { + drv.num_secs = 22; + drv.num_tracks = Math.floor(size / (22 * 512)); + drv.ddhd = 2; + } + } else { + drv.num_secs = 11; + drv.num_tracks = Math.floor(size / (11 * 512)); + } + if (!ds && drv.num_tracks > MAX_TRACKS) { + SAEF_warn("disk.drive_insert() Your diskfile is too big, %d bytes!", size); + //OWN + SAEF_ZFile_fclose(drv.diskfile); + drv.diskfile = null; + return 0; + } + for (i = 0; i < drv.num_tracks; i++) { + tid = drv.trackdata[i]; + tid.type = ds ? TRACK_DISKSPARE : TRACK_AMIGADOS; + tid.len = 512 * drv.num_secs; + tid.bitlen = 0; + tid.offs = i * 512 * drv.num_secs; + tid.revolutions = 1; + } + } + //openwritefile(p, drv, 0); + drive_settype_id(drv); /* Set DD or HD drive */ + drive_fill_bigbuf(drv, true); + drv.mfmpos = (((Math.decimalRandom() & 0xffff) << 16) | (Math.decimalRandom() & 0xffff)) >>> 0; + drv.mfmpos %= drv.tracklen; + drv.prevtracklen = 0; + if (!fake) { + update_drive_gui(drv.num, false); + update_disk_statusline(drv.num); + } + return 1; + } + + function drive_eject(drv) { + //if (drv.diskfile || drv.filetype >= 0) statusline_add_message("DF%d: -", drv.num); + //gui_disk_image_change(drv.num, null, drv.wrprot); + drive_image_free(drv); + drv.dskeject = false; + drv.dskchange = true; + drv.ddhd = 1; + drv.dskchange_time = 0; + drv.dskready = 0; + drv.dskready_up_time = 0; + drv.dskready_down_time = 0; + drv.crc32 = 0; + drive_settype_id(drv); /* Back to 35 DD */ + if (disk_debug_logging > 0) SAEF_log("disk.drive_eject() %d", drv.num); + //inprec_recorddiskchange(drv.num, null, false); + } + + function drive_writeprotected(drv) { + //SAEF_log("disk.drive_writeprotected() df%d: ro %d wp %d fwp %d %s", drv.num, SAEV_config.floppy.readOnly?1:0, drv.wrprot?1:0, drv.forcedwrprot?1:0, drv.diskfile ? SAEF_ZFile_getname(drv.diskfile) : "none"); + return SAEV_config.floppy.readOnly || drv.wrprot || drv.forcedwrprot || drv.diskfile === null; + } + + /*-----------------------------------------------------------------------*/ + /* step / motor */ + + function rand_shifter(drv) { + var r = ((Math.decimalRandom() >>> 4) & 7) + 1; + while (r-- > 0) { + word <<= 1; + word |= (Math.decimalRandom() & 0x1000) ? 1 : 0; + word &= 0xffff; //OWN + bitoffset++; + bitoffset &= 15; + } + } + + function drive_empty(drv) { + return drv.diskfile === null && drv.dskchange_time >= 0; + } + + function set_steplimit(drv) { + // emulate step limit only if cycle-exact or approximate CPU speed + if (SAEV_config.cpu.speed == SAEC_Config_CPU_Speed_Original) { + drv.steplimit = 4; + drv.steplimitcycle = SAEV_Events_currcycle; + } + } + + function drive_step(drv, step_direction) { + if (!drive_empty(drv)) + drv.dskchange = false; + if (drv.steplimit && SAEV_Events_currcycle - drv.steplimitcycle < MIN_STEPLIMIT_CYCLE) { + SAEF_log("disk.drive_step() ignored df%d, cycle %d", drv.num, Math.floor((SAEV_Events_currcycle - drv.steplimitcycle) * SAEC_Events_CYCLE_UNIT_INV)); return; } - - this.set_steplimit(); - - if (AMIGA.disk.direction) { - if (this.cyl) - this.cyl--; - //else BUG.info('Drive.step() DF%d, program tried to step beyond track zero', this.num); //'no-click' programs does that + /* A1200's floppy drive needs at least 30 raster lines between steps + * but we'll use very small value for better compatibility with faster CPU emulation + * (stupid trackloaders with CPU delay loops) + */ + set_steplimit(drv); + if (step_direction) { + if (drv.cyl) { + drv.cyl--; + } + /* else + SAEF_log("disk.drive_step() program tried to step beyond track zero"); + "no-click" programs does that + */ } else { - var maxtrack = this.hard_num_cyls; - if (this.cyl < maxtrack + 3) - this.cyl++; - //if (this.cyl >= maxtrack) BUG.info('Drive.step() DF%d, program tried to step over track %d', this.num, maxtrack); //'no-click' programs does that + var maxtrack = drv.hard_num_cyls; + if (drv.cyl < maxtrack + 3) { + drv.cyl++; + } + if (drv.cyl >= maxtrack) + SAEF_warn("disk.drive_step() program tried to step over track %d", maxtrack); } - AMIGA.disk.rand_shifter(); - AMIGA.config.hooks.floppy_step(this.num, this.cyl); - }; + rand_shifter(drv); + if (disk_debug_logging > 2) SAEF_log("disk.drive_step() %d", drv.cyl); + } - this.is_track0 = function () { - return this.cyl == 0; - }; + function drive_track0(drv) { + return drv.cyl == 0; + } - this.is_writeprotected = function () { - return this.wrprot || this.diskfile === null; - }; + /*---------------------------------*/ - this.is_running = function () { - return !this.motoroff; - }; - - this.set_motor = function (off) { - if (this.motoroff && !off) { - this.dskready_up_time = DSKREADY_UP_TIME; - AMIGA.disk.rand_shifter(); + function drive_running(drv) { + return !drv.motoroff; + } + + /*function motordelay_func(v) { + floppy[v].motordelay = 0; + }*/ + function drive_motor(drv, off) { + if (drv.motoroff && !off) { + drv.dskready_up_time = DSKREADY_UP_TIME * 312 + (Math.decimalRandom() & 511); + rand_shifter(drv); + if (disk_debug_logging > 2) SAEF_log("disk.drive_motor() on"); } - if (!this.motoroff && off) { - this.drive_id_scnt = 0; - /* Reset id shift reg counter */ - this.dskready_down_time = DSKREADY_DOWN_TIME; + if (!drv.motoroff && off) { + drv.drive_id_scnt = 0; /* Reset id shift reg counter */ + drv.dskready_down_time = DSKREADY_DOWN_TIME * 312 + (Math.decimalRandom() & 511); + if (DEBUG_DRIVE_ID) SAEF_log("disk.drive_motor() Selected DF%d: reset id shift reg.", drv.num); + if (disk_debug_logging > 2) SAEF_log("disk.drive_motor() off"); - if (AMIGA.config.cpu.model <= 68010 && AMIGA.config.cpu.speed == SAEV_Config_CPU_Speed_Original) { - this.motordelay = true; - AMIGA.events.newevent2(30, this.num, function (v) { - AMIGA.disk.motordelay_func(v); + if (SAEV_config.cpu.model <= SAEC_Config_CPU_Model_68010 && SAEV_config.cpu.speed == SAEC_Config_CPU_Speed_Original) { + drv.motordelay = 1; + //SAER.events.event2_newevent2(30, drv.num, motordelay_func); + SAER.events.event2_newevent_xx(-1, 30 * SAEC_Events_CYCLE_UNIT, drv.num, function(v) { + floppy[v].motordelay = 0; }); } } - this.motoroff = off; - if (this.motoroff) { - this.dskready = false; - this.dskready_up_time = 0; - } else { - this.dskready_down_time = 0; + drv.motoroff = off; + if (drv.motoroff) { + drv.dskready = 0; + drv.dskready_up_time = 0; + } else + drv.dskready_down_time = 0; + } + + /*-----------------------------------------------------------------------*/ + /* read */ + + function read_floppy_data(diskfile, type, tid, offset, dst,dsto, len) { + if (len == 0) + return; + if (tid.track == 0) { + if (type == ADF_KICK) { + //memset(dst, 0, len > 512 ? 512 : len); + SAEF_memset(dst,dsto, 0, len > 512 ? 512 : len); + if (offset == 0) { + dst.set(SAEF_String2Array("KICK"), dsto); + len -= 512; + } + } else if (type == ADF_SKICK) { + //memset(dst, 0, len > 512 ? 512 : len); + SAEF_memset(dst,dsto, 0, len > 512 ? 512 : len); + if (offset == 0) { + dst.set(SAEF_String2Array("KICKSUP0"), dsto); + len -= 1024; + } else if (offset == 512) + len -= 512; + } } - }; - - /* get one bit from MFM bit stream */ - this.getonebit = function (mfmpos) { - return (this.bigmfmbuf[mfmpos >> 4] & (1 << (15 - (mfmpos & 15)))) ? 1 : 0; - }; - this.decode_amigados = function () { - var gap_len = AMIGA.config.video.ntsc ? 415 : 350; - var tr = this.cyl * 2 + AMIGA.disk.side; - var len = this.num_secs * 544 + gap_len; - var bigmfmpos = gap_len; - var sec; - var i; + var off = tid.offs + offset; + if (off >= 0 && len > 0) { + SAEF_ZFile_fseek(diskfile, off, SEEK_SET); + SAEF_ZFile_fread(dst,dsto, 1, len, diskfile); + } + } - for (i = 0; i < len; i++) - this.bigmfmbuf[i] = 0xaaaa; + /* Megalomania does not like zero MFM words... */ + function mfmcode(mfm,mfmo, words) { + var lastword = 0; + while (words--) { + var v = mfm[mfmo] & 0x5555;//5555; + var lv = ((lastword << 16) | v) >>> 0; + var nlv = ~lv & 0x55555555; + var mfmbits = (((nlv << 1) & (nlv >>> 1)) >>> 0) & 0xffff; + mfm[mfmo++] = v | mfmbits; + lastword = v; + } + } - this.skipoffset = Math.floor((gap_len * 8) / 3) * 2; - this.tracklen = len * 2 * 8; + /*---------------------------------*/ + /* read amigados */ - for (sec = 0; sec < this.num_secs; sec++) { + function decode_amigados(drv) { + var tr = drv.cyl * 2 + side; + var dstmfmoffset = FLOPPY_GAP_LEN(); + //var dstmfmbuf = drv.bigmfmbuf; //u16 * + var len = drv.num_secs * 544 + FLOPPY_GAP_LEN(); + var ti = drv.trackdata[tr]; + + //memset(dstmfmbuf, 0xaa, len * 2); + SAEF_memset(drv.bigmfmbuf,0, 0xaaaa, len); + //dstmfmoffset += FLOPPY_GAP_LEN(); + drv.skipoffset = Math.floor((FLOPPY_GAP_LEN() * 8) / 3) * 2; //ATT + drv.tracklen = len * 2 * 8; + + var prevbit = 0; + for (var sec = 0; sec < drv.num_secs; sec++) { var secbuf = new Uint8Array(544); - var mfmbuf = new Uint16Array(544); - var deven, dodd; + var mfmbuf = new Uint16Array(544 + 1); var hck = 0, dck = 0; secbuf[0] = secbuf[1] = 0x00; @@ -477,25 +1638,21 @@ function Drive(number) { secbuf[4] = 0xff; secbuf[5] = tr; secbuf[6] = sec; - secbuf[7] = this.num_secs - sec; + secbuf[7] = drv.num_secs - sec; - for (i = 8; i < 24; i++) + for (var i = 8; i < 24; i++) secbuf[i] = 0; - //read_floppy_data (this.diskfile, ti, sec * 512, &secbuf[32], 512); - { - var offset = this.trackdata[tr].offs + sec * 512; - for (i = 0; i < 512; i++) secbuf[32 + i] = this.diskfile[offset + i]; - } + read_floppy_data(drv.diskfile, drv.filetype, ti, sec * 512, secbuf,32, 512); - mfmbuf[0] = mfmbuf[1] = 0xaaaa; + mfmbuf[0] = prevbit ? 0x2aaa : 0xaaaa; + mfmbuf[1] = 0xaaaa; mfmbuf[2] = mfmbuf[3] = 0x4489; - deven = ((secbuf[4] << 24) | (secbuf[5] << 16) | (secbuf[6] << 8) | (secbuf[7])) >>> 0; - dodd = deven >>> 1; + var deven = ((secbuf[4] << 24) | (secbuf[5] << 16) | (secbuf[6] << 8) | (secbuf[7])) >>> 0; + var dodd = deven >>> 1; deven &= 0x55555555; dodd &= 0x55555555; - mfmbuf[4] = dodd >>> 16; mfmbuf[5] = dodd & 0xffff; mfmbuf[6] = deven >>> 16; @@ -515,7 +1672,7 @@ function Drive(number) { } for (i = 4; i < 24; i += 2) - hck ^= ((mfmbuf[i] << 16) | mfmbuf[i + 1]) >>> 0; + hck = (hck ^ ((mfmbuf[i] << 16) | mfmbuf[i + 1]) >>> 0) >>> 0; deven = dodd = hck; dodd >>>= 1; @@ -525,7 +1682,7 @@ function Drive(number) { mfmbuf[27] = deven & 0xffff; for (i = 32; i < 544; i += 2) - dck ^= ((mfmbuf[i] << 16) | mfmbuf[i + 1]) >>> 0; + dck = (dck ^ ((mfmbuf[i] << 16) | mfmbuf[i + 1]) >>> 0) >>> 0; deven = dodd = dck; dodd >>>= 1; @@ -534,582 +1691,1336 @@ function Drive(number) { mfmbuf[30] = deven >>> 16; mfmbuf[31] = deven & 0xffff; - //mfmcode (mfmbuf + 4, 544 - 4); static this.mfmcode (var * mfm, var words) - { - var words = 540, lastword = 0, pos = 4; - while (words--) { - //var v = *mfm; - var v = mfmbuf[pos]; - var lv = ((lastword << 16) | v) >>> 0; - var nlv = (0x55555555 & ~lv) >>> 0; - var mfmbits = (((nlv << 1) & (nlv >>> 1)) >>> 0) & 0xffff; - //*mfm++ = v | mfmbits; - mfmbuf[pos] = v | mfmbits; - lastword = v; - pos++; - } - } + mfmbuf[544] = 0; + + mfmcode(mfmbuf,4, 544 - 4 + 1); for (i = 0; i < 544; i++) { - this.bigmfmbuf[bigmfmpos % len] = mfmbuf[i]; - bigmfmpos++; + drv.bigmfmbuf[dstmfmoffset % len] = mfmbuf[i]; + dstmfmoffset++; + } + prevbit = mfmbuf[i - 1] & 1; + // so that final word has correct MFM encoding + drv.bigmfmbuf[dstmfmoffset % len] = mfmbuf[i]; + } + + if (disk_debug_logging > 0) SAEF_log("disk.decode_amigados() read track %d", tr); + } + + /*---------------------------------*/ + /* read pcdos */ + + const mfmencodetable = [ + 0x2a, 0x29, 0x24, 0x25, 0x12, 0x11, 0x14, 0x15, + 0x4a, 0x49, 0x44, 0x45, 0x52, 0x51, 0x54, 0x55 + ]; + function dos_encode_byte(byte) { + var word = (mfmencodetable[byte >> 4] << 8) | mfmencodetable[byte & 15]; + return (word | ((word & (256 | 64)) ? 0 : 128)); + } + function mfmcoder(src, dest,desto, len) { + var i, srco = 0; + + for (i = 0; i < len; i++) { + dest[desto] = dos_encode_byte(src[srco++]); + dest[desto] |= ((dest[desto - 1] & 1) || (dest[desto] & 0x4000)) ? 0: 0x8000; + desto++; + } + return desto; + } + function decode_pcdos(drv) { + var i, len; + var tr = drv.cyl * 2 + side; + //uae_u16 *dstmfmbuf, *mfm2; + var secbuf = new Uint8Array(1000); + var crc16; + var ti = drv.trackdata[tr]; + const tracklen = 12500; + + //SAEF_log("disk.decode_pcdos() num_secs %d, hd %d", drv.num_secs, drv.ddhd); + + var mfm2 = drv.bigmfmbuf; + var mfm2o = 0; //OWN + var dstmfmbufo = 0; //OWN + + mfm2[mfm2o++] = 0x9254; // *mfm2++ = 0x9254; + SAEF_memset(secbuf,0, 0x4e, 40); + SAEF_memset(secbuf,40, 0x00, 12); + secbuf[52] = 0xc2; + secbuf[53] = 0xc2; + secbuf[54] = 0xc2; + secbuf[55] = 0xfc; + SAEF_memset(secbuf,56, 0x4e, 40); + dstmfmbufo = mfmcoder(secbuf, mfm2,mfm2o, 96); + mfm2[mfm2o + 52] = 0x5224; + mfm2[mfm2o + 53] = 0x5224; + mfm2[mfm2o + 54] = 0x5224; + for (i = 0; i < drv.num_secs; i++) { + mfm2o = dstmfmbufo; + SAEF_memset(secbuf,0, 0x00, 12); + secbuf[12] = 0xa1; + secbuf[13] = 0xa1; + secbuf[14] = 0xa1; + secbuf[15] = 0xfe; + secbuf[16] = drv.cyl; + secbuf[17] = side; + secbuf[18] = 1 + i; + secbuf[19] = 2; // 128 << 2 = 512 + crc16 = SAEF_crc16(secbuf,12, 3 + 1 + 4); + secbuf[20] = crc16 >> 8; + secbuf[21] = crc16 & 0xff; + SAEF_memset(secbuf,22, 0x4e, 22); + SAEF_memset(secbuf,44, 0x00, 12); + secbuf[56] = 0xa1; + secbuf[57] = 0xa1; + secbuf[58] = 0xa1; + secbuf[59] = 0xfb; + read_floppy_data(drv.diskfile, drv.filetype, ti, i * 512, secbuf,60, 512); + crc16 = SAEF_crc16(secbuf,56, 3 + 1 + 512); + secbuf[60 + 512] = crc16 >> 8; + secbuf[61 + 512] = crc16 & 0xff; + len = Math.floor((tracklen / 2 - 96) / drv.num_secs) - 574 / drv.ddhd; + if (len > 0) SAEF_memset(secbuf,512 + 62, 0x4e, len); + dstmfmbufo = mfmcoder(secbuf, mfm2,mfm2o, 62 + 512 + 76 / drv.ddhd); + mfm2[mfm2o + 12] = 0x4489; + mfm2[mfm2o + 13] = 0x4489; + mfm2[mfm2o + 14] = 0x4489; + mfm2[mfm2o + 56] = 0x4489; + mfm2[mfm2o + 57] = 0x4489; + mfm2[mfm2o + 58] = 0x4489; + } + //while (dstmfmbuf - drv.bigmfmbuf < tracklen / 2) *dstmfmbuf++ = 0x9254; + while (dstmfmbufo < tracklen / 2) drv.bigmfmbuf[dstmfmbufo++] = 0x9254; + drv.skipoffset = 0; + //drv.tracklen = (dstmfmbuf - drv.bigmfmbuf) * 16; + drv.tracklen = dstmfmbufo * 16; + if (disk_debug_logging > 0) SAEF_log("disk.decode_pcdos() read track %d, len %d bytes", tr, drv.tracklen / 8); + } + + /*---------------------------------*/ + /* read diskspare + * + * 0 <4489> <4489> 0 track sector crchi, crclo, data[512] (520 bytes per sector) + * + * 0xAAAA 0x4489 0x4489 0x2AAA oddhi, oddlo, evenhi, evenlo, ... + * + * NOTE: data is MFM encoded using same method as ADOS header, not like ADOS data! */ + + function decode_diskspare(drv) { + var tr = drv.cyl * 2 + side; + var dstmfmoffset = FLOPPY_GAP_LEN(); + //var dstmfmbuf = drv.bigmfmbuf; //u16 * + var len = drv.num_secs * (512 + 8) + FLOPPY_GAP_LEN(); //12 * 520 + 350 = 6590 + var ti = drv.trackdata[tr]; + + //memset(dstmfmbuf, 0xaa, len * 2); + SAEF_memset(drv.bigmfmbuf,0, 0xaaaa, len); + //dstmfmoffset += FLOPPY_GAP_LEN(); + drv.skipoffset = Math.floor((FLOPPY_GAP_LEN() * 8) / 3) * 2; //ATT + drv.tracklen = len * 2 * 8; + + for (var sec = 0; sec < drv.num_secs; sec++) { + var secbuf = new Uint8Array(512 + 8); + var mfmbuf = new Uint16Array(512 + 8); + var i, deven, dodd; + + secbuf[0] = tr; + secbuf[1] = sec; + secbuf[2] = 0; + secbuf[3] = 0; + + read_floppy_data(drv.diskfile, drv.filetype, ti, sec * 512, secbuf,4, 512); + + mfmbuf[0] = 0xaaaa; + mfmbuf[1] = 0x4489; + mfmbuf[2] = 0x4489; + mfmbuf[3] = 0x2aaa; + + for (i = 0; i < 512; i += 4) { + deven = ((secbuf[i + 4] << 24) | (secbuf[i + 5] << 16) | (secbuf[i + 6] << 8) | (secbuf[i + 7])) >>> 0; + dodd = deven >>> 1; + deven &= 0x55555555; + dodd &= 0x55555555; + + mfmbuf[i + 8 + 0] = dodd >>> 16; + mfmbuf[i + 8 + 1] = dodd & 0xffff; + mfmbuf[i + 8 + 2] = deven >>> 16; + mfmbuf[i + 8 + 3] = deven & 0xffff; + } + mfmcode(mfmbuf,8, 512); + + i = 8; + var chk = mfmbuf[i++] & 0x7fff; + while (i < 512 + 8) chk ^= mfmbuf[i++]; + secbuf[2] = chk >> 8; + secbuf[3] = chk; + + deven = ((secbuf[0] << 24) | (secbuf[1] << 16) | (secbuf[2] << 8) | (secbuf[3])) >>> 0; + dodd = deven >>> 1; + deven &= 0x55555555; + dodd &= 0x55555555; + + mfmbuf[4] = dodd >>> 16; + mfmbuf[5] = dodd & 0xffff; + mfmbuf[6] = deven >>> 16; + mfmbuf[7] = deven & 0xffff; + mfmcode(mfmbuf,4, 4); + + for (i = 0; i < 512 + 8; i++) { + drv.bigmfmbuf[dstmfmoffset % len] = mfmbuf[i]; + dstmfmoffset++; } } - }; + if (disk_debug_logging > 0) SAEF_log("disk.decode_diskspare() read track %d", tr); + } - this.decode_raw = function () { - var tr = this.cyl * 2 + AMIGA.disk.side; + /*---------------------------------*/ - var base_offset = this.trackdata[tr].type == TRACK_RAW ? 0 : 1; - this.tracklen = this.trackdata[tr].bitlen + 16 * base_offset; - this.bigmfmbuf[0] = this.trackdata[tr].sync; - var len = Math.floor((this.trackdata[tr].bitlen + 7) / 8); - var buf = new Uint8Array(len); + function drive_fill_bigbuf(drv, force) { + var tr = drv.cyl * 2 + side; + var ti = drv.trackdata[tr]; - //read_floppy_data (this.diskfile, ti, 0, (var*)(this.bigmfmbuf + base_offset), Math.floor((ti->bitlen + 7) / 8)); - { - var offset = this.trackdata[tr].offs; - for (var i = 0; i < len; i++) - buf[i] = this.diskfile[offset + i]; - } - - for (var i = base_offset; i < Math.floor((this.tracklen + 15) / 16); i++) - this.bigmfmbuf[i] = 256 * buf[(i - base_offset) << 1] + buf[((i - base_offset) << 1) + 1]; - - //BUG.info('DF%d.decode_raw() rawtrack %d, offset %d', this.num, tr, this.trackdata[tr].offs); - }; - - this.fill_bigbuf = function (force) { - var tr = this.cyl * 2 + AMIGA.disk.side; - - if (!this.diskfile || tr >= this.num_tracks) { - this.reset_track(); + if (drv.diskfile === null || tr >= drv.num_tracks) { + track_reset(drv); return; } - if (!force && this.buffered_cyl == this.cyl && this.buffered_side == AMIGA.disk.side) + if (!force && drv.buffered_cyl == drv.cyl && drv.buffered_side == side) return; - this.indexoffset = 0; - this.tracktiming[0] = 0; - this.skipoffset = -1; + drv.indexoffset = 0; + drv.multi_revolution = 0; + drv.tracktiming[0] = 0; + drv.skipoffset = -1; + drv.revolutions = 1; + var retrytrack = drv.lastdataacesstrack == drv.cyl * 2 + side; + if (!dskdmaen && !retrytrack) + drv.track_access_done = false; - /*if (this.writediskfile && this.writetrackdata[tr].bitlen > 0) { - var i; - Track *wti = &this.writetrackdata[tr]; - this.tracklen = wti->bitlen; - read_floppy_data (this.writediskfile, wti, 0, (var*)this.bigmfmbuf, Math.floor((wti->bitlen + 7) / 8)); - for (i = 0; i < Math.floor((this.tracklen + 15) / 16); i++) { - var *mfm = this.bigmfmbuf + i; - var *data = (var *) mfm; - *mfm = 256 * *data + *(data + 1); - } - write_log ('track %d, length %d read from \'saveimage\'\n', tr, this.tracklen); - } else*/ - if (this.trackdata[tr].type == TRACK_NONE) { + if (drv.writediskfile && drv.writetrackdata[tr].bitlen > 0) { + var wti = drv.writetrackdata[tr]; + drv.tracklen = wti.bitlen; + drv.revolutions = wti.revolutions; + /*read_floppy_data(drv.writediskfile, drv.filetype, wti, 0, (uae_u8 *)drv.bigmfmbuf, (wti.bitlen + 7) / 8); + for (int i = 0; i < (drv.tracklen + 15) / 16; i++) { + uae_u16 *mfm = drv.bigmfmbuf + i; + uae_u8 *data = (uae_u8 *) mfm; + *mfm = 256 * *data + *(data + 1); + }*/ + var size = (wti.bitlen + 7) >>> 3; + var tmp = new Uint8Array(size); + read_floppy_data(drv.writediskfile, drv.filetype, wti, 0, tmp,0, size); + size = (drv.tracklen + 15) >> 4; + for (var i = 0, j = 0; i < size; i++, j += 2) + drv.bigmfmbuf[i] = (tmp[j] << 8) | tmp[j + 1]; + + if (disk_debug_logging > 0) SAEF_log("disk.drive_fill_bigbuf() track %d, length %d read from \"saveimage\"", tr, drv.tracklen); } - else if (this.trackdata[tr].type == TRACK_AMIGADOS) - this.decode_amigados(); - else if (this.trackdata[tr].type == TRACK_DISKSPARE) - this.decode_diskspare(); - else if (this.trackdata[tr].type == TRACK_PCDOS) - this.decode_pcdos(); - else - this.decode_raw(); - - this.buffered_side = AMIGA.disk.side; - this.buffered_cyl = this.cyl; - if (this.tracklen == 0) { - this.tracklen = (AMIGA.config.video.ntsc ? 6399 : 6334) * this.ddhd * 2 * 8; - for (var i = 0; i < (AMIGA.config.video.ntsc ? 6399 : 6334) * this.ddhd; i++) this.bigmfmbuf[i] = 0; //memset (this.bigmfmbuf, 0, (AMIGA.config.video.ntsc ? 6399 : 6334) * 2 * this.ddhd); + else if (drv.filetype == ADF_SCP) { + //scp_loadtrack(drv.bigmfmbuf, drv.tracktiming, drv - floppy, tr, &drv.tracklen, &drv.multi_revolution, &drv.skipoffset, &drv.lastrev, retrytrack); + scp_loadtrack(drv.bigmfmbuf, drv.tracktiming, drv.num, tr, retrytrack); } + /*else if (drv.filetype == ADF_FDI) { + fdi2raw_loadtrack (drv.fdi, drv.bigmfmbuf, drv.tracktiming, tr, &drv.tracklen, &drv.indexoffset, &drv.multi_revolution, 1); + }*/ + else if (ti.type == TRACK_PCDOS) { + decode_pcdos(drv); + } + else if (ti.type == TRACK_AMIGADOS) { + decode_amigados(drv); + } + else if (ti.type == TRACK_DISKSPARE) { + decode_diskspare(drv); + } + else if (ti.type == TRACK_NONE) { + ; + } else { + var wti = drv.writetrackdata[tr]; + var base_offset = ti.type == TRACK_RAW ? 0 : 1; + drv.tracklen = ti.bitlen + 16 * base_offset; + drv.bigmfmbuf[0] = ti.sync; + /*read_floppy_data(drv.diskfile, drv.filetype, ti, 0, (uae_u8*)(drv.bigmfmbuf + base_offset), (ti.bitlen + 7) / 8); + for (int i = base_offset; i < (drv.tracklen + 15) / 16; i++) { + uae_u16 *mfm = drv.bigmfmbuf + i; + uae_u8 *data = (uae_u8 *) mfm; + *mfm = 256 * *data + *(data + 1); + }*/ + var size = (wti.bitlen + 7) >>> 3; + var tmp = new Uint8Array(size); + read_floppy_data(drv.diskfile, drv.filetype, ti, 0, tmp,0, size); + size = (drv.tracklen + 15) >> 4; + for (var i = base_offset, j = 0; i < size; i++, j += 2) + drv.bigmfmbuf[i] = (tmp[j] << 8) | tmp[j + 1]; - this.trackspeed = this.get_floppy_speed2(); - this.updatemfmpos(); - }; + if (disk_debug_logging > 2) SAEF_log("disk.drive_fill_bigbuf() rawtrack %d image offset $%x", tr, ti.offs); + } + drv.buffered_side = side; + drv.buffered_cyl = drv.cyl; + if (drv.tracklen == 0) { + drv.tracklen = FLOPPY_WRITE_LEN() * 2 * drv.ddhd * 8; + //memset(drv.bigmfmbuf, 0, FLOPPY_WRITE_LEN() * 2 * drv.ddhd); + SAEF_memset(drv.bigmfmbuf,0, 0, FLOPPY_WRITE_LEN() * 2 * drv.ddhd >> 1); + } + drv.trackspeed = get_floppy_speed2(drv); + updatemfmpos(drv); + } - this.getmfmword = function (mbuf, shift) { - return (((this.bigmfmbuf[mbuf] << shift) | (this.bigmfmbuf[mbuf + 1] >>> (16 - shift))) >>> 0) & 0xffff; - }; - this.getmfmlong = function (mbuf, shift) { - return (((this.getmfmword(mbuf, shift) << 16) | this.getmfmword(mbuf + 1, shift)) >>> 0) & 0x55555555; - }; - this.decode_buffer = function (checkmode) { - var mbuf = 0; - var cyl = this.cyl; - var drvsec = this.num_secs; - var ddhd = this.ddhd; - var filetype = this.filetype; + /*-----------------------------------------------------------------------*/ + /* write */ - var i, secwritten = 0; - var fwlen = (AMIGA.config.video.ntsc ? 6399 : 6334) * ddhd; - var length = 2 * fwlen; - var odd, even, chksum, id, dlong; + const MFMMASK = 0x55555555; + function getmfmword(mbuf,mbufo, shift) { + return ((mbuf[mbufo] << shift) | (mbuf[mbufo + 1] >> (16 - shift))) & 0xffff; + } + function getmfmlong(mbuf,mbufo, shift) { + return (((getmfmword(mbuf,mbufo, shift) << 16) | getmfmword(mbuf,mbufo + 1, shift)) & MFMMASK) >>> 0; + } + + /*---------------------------------*/ + /* write amigados */ + + function check_valid_mfm(mbuf,mbufo, words, sector) { + var prevbit = 0; + for (var i = 0; i < words * 8; i++) { + var wordoffset = i / 8 >>> 0; + var w = mbuf[mbufo + wordoffset]; + var wp = mbuf[mbufo + wordoffset - 1]; + var bitoffset = (7 - (i & 7)) * 2; + var clockbit = w & (1 << (bitoffset + 1)); + var databit = w & (1 << (bitoffset + 0)); + + if ((clockbit && databit) || (clockbit && !databit && prevbit) || (!clockbit && !databit && !prevbit)) + SAEF_warn("disk.check_valid_mfm() illegal mfm sector %d data %04x %04x, bit %d:%d", sector, wp, w, wordoffset, bitoffset); + + prevbit = databit; + } + } + function decode_buffer(mbuf, cyl, drvsec, ddhd, filetype, drvsecp, sectable, checkmode) { + var i = 0, secwritten = 0; + var fwlen = FLOPPY_WRITE_LEN() * ddhd; + var odd = 0, even = 0, chksum = 0, id = 0, dlong = 0; //u32 var secbuf = new Uint8Array(544); - var sectable = new Array(22); - var mend = length - (4 + 16 + 8 + 512); + var secbufo = 0; //OWN + var mbufo = 0; //OWN + var mend = fwlen * 2 - (4 + 16 + 8 + 512); + var sechead = new Uint32Array(4); var shift = 0; + var issechead = false; - for (i = 0; i < sectable.length; i++) sectable[i] = 0; //memset (sectable, 0, sizeof (sectable)); - for (i = 0; i < fwlen; i++) this.bigmfmbuf[fwlen + i] = this.bigmfmbuf[i]; //memcpy (mbuf + fwlen, mbuf, fwlen * sizeof(uae_u16)); + //memset(sectable, 0, MAX_SECTORS * sizeof (int)); + SAEF_memset(sectable,0, 0, MAX_SECTORS); + //memcpy(mbuf + fwlen, mbuf, fwlen * sizeof (uae_u16)); + SAEF_memcpy(mbuf,fwlen, mbuf,0, fwlen); + //mbuf.copyWithin(fwlen, 0, fwlen); while (secwritten < drvsec) { - while (this.getmfmword(mbuf, shift) != 0x4489) { - if (mbuf >= mend) return 1; + while (getmfmword(mbuf,mbufo, shift) != 0x4489) { + if (mbufo >= mend) { + SAEF_log("disk.decode_buffer() sync not found (1)"); + return 1; + } shift++; if (shift == 16) { shift = 0; - mbuf++; + mbufo++; } } - while (this.getmfmword(mbuf, shift) == 0x4489) { - if (mbuf >= mend) return 10; - mbuf++; + while (getmfmword(mbuf,mbufo, shift) == 0x4489) { + if (mbufo >= mend) { + SAEF_log("disk.decode_buffer() sync not found (2)"); + return 1; + } + mbufo++; } - odd = this.getmfmlong(mbuf, shift); - even = this.getmfmlong(mbuf + 2, shift); - mbuf += 4; - id = (((odd << 1) | even) >>> 0) & 0xffffffff; + odd = getmfmlong(mbuf,mbufo, shift); + even = getmfmlong(mbuf,mbufo + 2, shift); + mbufo += 4; + id = ((odd << 1) | even) >>> 0; - var trackoffs = (id & 0xff00) >>> 8; + var trackoffs = (id & 0xff00) >> 8; if (trackoffs + 1 > drvsec) { - BUG.info('DF%d.decode_buffer() weird sector number %d', this.num, trackoffs); + SAEF_log("disk.decode_buffer() weird sector number %d (id $%08x, offset %d)", trackoffs, id, mbufo); if (filetype == ADF_EXT2) return 2; continue; } + + //check_valid_mfm(mbuf,mbufo - 4, 544 - 4 + 1, trackoffs); + + issechead = false; chksum = (odd ^ even) >>> 0; for (i = 0; i < 4; i++) { - odd = this.getmfmlong(mbuf, shift); - even = this.getmfmlong(mbuf + 8, shift); - mbuf += 2; + odd = getmfmlong(mbuf,mbufo, shift); + even = getmfmlong(mbuf,mbufo + 8, shift); + mbufo += 2; - dlong = (((odd << 1) | even) >>> 0) & 0xffffffff; - if (dlong && !checkmode) { - if (filetype == ADF_EXT2) return 6; - secwritten = -200; - } - chksum ^= odd ^ even; - chksum &= 0xffffffff; + dlong = ((odd << 1) | even) >>> 0; + if (dlong && !checkmode) + issechead = true; + + sechead[i] = dlong; + chksum = (chksum ^ ((odd ^ even) >>> 0)) >>> 0; } - mbuf += 8; - odd = this.getmfmlong(mbuf, shift); - even = this.getmfmlong(mbuf + 2, shift); - mbuf += 4; - if (((((odd << 1) | even) >>> 0) & 0xffffffff) != chksum || ((id & 0x00ff0000) >> 16) != cyl * 2 + AMIGA.disk.side) { - BUG.info('DF%d.decode_buffer() checksum error on sector %d header', this.num, trackoffs); + if (issechead) { + SAEF_log("disk.decode_buffer() sector %d header: %08X %08X %08X %08X", trackoffs, sechead[0], sechead[1], sechead[2], sechead[3]); + if (filetype == ADF_EXT2) return 6; + } + mbufo += 8; + odd = getmfmlong(mbuf,mbufo, shift); + even = getmfmlong(mbuf,mbufo + 2, shift); + mbufo += 4; + if ((((odd << 1) | even) >>> 0) != chksum) { + SAEF_log("disk.decode_buffer() sector %d, header checksum error (%08X != %08X) ", trackoffs, ((odd << 1) | even) >>> 0, chksum); if (filetype == ADF_EXT2) return 3; continue; } - odd = this.getmfmlong(mbuf, shift); - even = this.getmfmlong(mbuf + 2, shift); - mbuf += 4; - chksum = (((odd << 1) | even) >>> 0) & 0xffffffff; - for (i = 0; i < 512; i += 4) { - odd = this.getmfmlong(mbuf, shift); - even = this.getmfmlong(mbuf + 256, shift); - mbuf += 2; - dlong = (((odd << 1) | even) >>> 0) & 0xffffffff; - secbuf[32 + i] = (dlong >>> 24) & 0xff; - secbuf[33 + i] = (dlong >>> 16) & 0xff; - secbuf[34 + i] = (dlong >>> 8) & 0xff; - secbuf[35 + i] = dlong & 0xff; - chksum ^= odd ^ even; - chksum &= 0xffffffff; + if (((id & 0x00ff0000) >>> 16) != cyl * 2 + side) { + SAEF_log("disk.decode_buffer() mismatched track (%d <> %d) on sector %d header (%08X)", (id & 0x00ff0000) >>> 16, cyl * 2 + side, trackoffs, id); + if (filetype == ADF_EXT2) return 3; + continue; + } + odd = getmfmlong(mbuf,mbufo, shift); + even = getmfmlong(mbuf,mbufo + 2, shift); + mbufo += 4; + chksum = ((odd << 1) | even) >>> 0; + secbufo = 32; + for (i = 0; i < 128; i++) { + odd = getmfmlong(mbuf,mbufo, shift); + even = getmfmlong(mbuf,mbufo + 256, shift); + mbufo += 2; + dlong = ((odd << 1) | even) >>> 0; + secbuf[secbufo++] = dlong >>> 24; + secbuf[secbufo++] = (dlong >>> 16) & 0xff; + secbuf[secbufo++] = (dlong >>> 8) & 0xff; + secbuf[secbufo++] = dlong & 0xff; + chksum = (chksum ^ ((odd ^ even) >>> 0)) >>> 0; } if (chksum) { - BUG.info('DF%d.decode_buffer() sector %d, data checksum error', this.num, trackoffs); + SAEF_log("disk.decode_buffer() sector %d, data checksum error", trackoffs); if (filetype == ADF_EXT2) return 4; continue; } - mbuf += 256; + mbufo += 256; + //SAEF_log("disk.decode_buffer() sector %d ok", trackoffs); sectable[trackoffs] = 1; secwritten++; - - for (i = 0; i < 512; i++) this.writebuffer[trackoffs * 512 + i] = secbuf[32 + i]; //memcpy (writebuffer + trackoffs * 512, secbuf + 32, 512); + writebuffer.set(secbuf.subarray(32, 32 + 512), trackoffs * 512); //memcpy(writebuffer + trackoffs * 512, secbuf + 32, 512); } if (filetype == ADF_EXT2 && (secwritten == 0 || secwritten < 0)) return 5; - if (secwritten == 0) BUG.info('DF%d.decode_buffer() unsupported format', this.num); - if (secwritten < 0) BUG.info('DF%d.decode_buffer() sector labels ignored', this.num); + if (secwritten == 0) + SAEF_log("disk.decode_buffer() unsupported format"); + else if (secwritten < 0) + SAEF_log("disk.decode_buffer() sector labels ignored"); + drvsecp.value = drvsec; return 0; - }; - - this.write_adf_amigados = function () { - //var drvsec, i; - //var sectable[MAX_SECTORS]; + } - if (this.decode_buffer(0)) //drv->bigmfmbuf, drv->cyl, drv->num_secs, drv->ddhd, drv->filetype, &drvsec, sectable, 0)) + /* Update EXT2 track header */ + function diskfile_update(diskfile, ti, len, type) { + var buf = new Uint8Array(2 + 2 + 4 + 4); + + ti.revolutions = 1; + ti.bitlen = len; + ti.type = type; + + buf[0] = 0; + buf[1] = 0; + buf[2] = 0; + buf[3] = ti.type; + //do_put_mem_long((uae_u32 *)(buf + 4), ti.len); + buf[4] = ti.len >>> 24; + buf[5] = (ti.len >>> 16) & 0xff; + buf[6] = (ti.len >>> 8) & 0xff; + buf[7] = ti.len & 0xff; + //do_put_mem_long((uae_u32 *)(buf + 8), ti.bitlen); + buf[8] = ti.bitlen >>> 24; + buf[9] = (ti.bitlen >>> 16) & 0xff; + buf[10] = (ti.bitlen >>> 8) & 0xff; + buf[11] = ti.bitlen & 0xff; + + SAEF_ZFile_fseek(diskfile, 8 + 4 + (2 + 2 + 4 + 4) * ti.track, SEEK_SET); + SAEF_ZFile_fwrite(buf,0, buf.length, 1, diskfile); + if (ti.len > Math.floor((len + 7) / 8)) { + var zerobuf = new Uint8Array(ti.len); + //memset(zerobuf, 0, ti.len); + SAEF_memset(zerobuf,0, 0, ti.len); + SAEF_ZFile_fseek(diskfile, ti.offs, SEEK_SET); + SAEF_ZFile_fwrite(zerobuf,0, 1, ti.len, diskfile); + } + if (disk_debug_logging > 0) SAEF_log("disk.diskfile_update() track %d, raw track length %d written (total size %d)", ti.track, Math.floor((ti.bitlen + 7) / 8), ti.len); + } + + function drive_write_adf_amigados(drv) { + var drvsec = { value:0 }; + var sectable = new Uint8Array(MAX_SECTORS); + + if (decode_buffer(drv.bigmfmbuf, drv.cyl, drv.num_secs, drv.ddhd, drv.filetype, drvsec, sectable, false)) + return 2; + if (!drvsec.value) return 2; - //if (!drvsec) return 2; - /*for (i = 0; i < drvsec; i++) { - zfile_fseek (drv->diskfile, drv->trackdata[drv->cyl * 2 + AMIGA.disk.side].offs + i * 512, SEEK_SET); - zfile_fwrite (writebuffer + i * 512, sizeof (var), 512, drv->diskfile); - }*/ - for (var i = 0; i < this.num_secs; i++) { - var offset = this.trackdata[this.cyl * 2 + AMIGA.disk.side].offs + i * 512; - for (var j = 0; j < 512; j++) - this.diskfile[offset + j] = this.diskdata[offset + j] = this.writebuffer[i * 512 + j]; + if (drv.filetype == ADF_EXT2) + diskfile_update(drv.diskfile, drv.trackdata[drv.cyl * 2 + side], drvsec.value * 512 * 8, TRACK_AMIGADOS); + + for (var i = 0; i < drvsec.value; i++) { + SAEF_ZFile_fseek(drv.diskfile, drv.trackdata[drv.cyl * 2 + side].offs + i * 512, SEEK_SET); + SAEF_ZFile_fwrite(writebuffer,i * 512, 1, 512, drv.diskfile); } return 0; - }; + } - this.write_data = function () { - var tr = this.cyl * 2 + AMIGA.disk.side; + /*---------------------------------*/ + /* write EXT2 */ - if (this.is_writeprotected() || this.trackdata[tr].type == TRACK_NONE) { - this.buffered_side = 2; + /* UAE-1ADF (ADF_EXT2) + * W reserved + * W number of tracks (default 2*80=160) + * + * W reserved + * W type, 0=normal AmigaDOS track, 1 = raw MFM (upper byte = disk revolutions - 1) + * L available space for track in bytes (must be even) + * L track length in bits + */ + + /* write raw track to disk file */ + function drive_write_ext2(bigmfmbuf, diskfile, ti, tracklen) { + var len = Math.floor((tracklen + 7) / 8); + if (len > ti.len) { + SAEF_warn("disk.drive_write_ext2() image file's track %d is too small (%d < %d)", ti.track, ti.len, len); + len = ti.len; + } + diskfile_update(diskfile, ti, tracklen, TRACK_RAW); + /*for (var i = 0; i < ti.len / 2; i++) { + uae_u16 *mfm = bigmfmbuf + i; + uae_u16 *mfmw = bigmfmbufw + i; + uae_u8 *data = (uae_u8 *) mfm; + *mfmw = 256 * *data + *(data + 1); + }*/ + for (var i = 0; i < ti.len >> 1; i++) + bigmfmbufw[i] = bigmfmbuf[i]; //ATT + + SAEF_ZFile_fseek(diskfile, ti.offs, SEEK_SET); + SAEF_ZFile_fwrite(bigmfmbufw,0, 1, len, diskfile); + return 1; + } + + /*---------------------------------*/ + /* write pcdos */ + + function mfmdecode(mfmp,mfmo, shift) { + var mfm = getmfmword(mfmp,mfmo, shift); + var out = 0; + + mfm &= 0x5555; //ATT + for (var i = 0; i < 8; i++) { + out >>= 1; + if (mfm & 1) + out |= 0x80; + mfm >>= 2; + } + return out; + } + function drive_write_pcdos(drv, zf, count) { + var drvsec = drv.num_secs; + var fwlen = FLOPPY_WRITE_LEN() * drv.ddhd; + var mbuf = drv.bigmfmbuf; + var mbufo = 0; //OWN + var mend = fwlen * 2 - 518; + var secwritten = 0, seccnt = 0; + var shift = 0, sector = -1; + var sectable = new Uint8Array(24); + var secbuf = new Uint8Array(3 + 1 + 512); + var mark = 0; //u8 + var crc = 0; //u16 + var i = 0; + + //memset(sectable, 0, sizeof sectable); + SAEF_memset(sectable,0, 0, 24); + //memcpy(mbuf + fwlen, mbuf, fwlen * sizeof (uae_u16)); + SAEF_memcpy(mbuf,fwlen, mbuf,0, fwlen); + //mbuf.copyWithin(fwlen, 0, fwlen); + secbuf[0] = secbuf[1] = secbuf[2] = 0xa1; + secbuf[3] = 0xfb; + + while (seccnt < drvsec) { + var mfmcount = 0; + while (getmfmword(mbuf,mbufo, shift) != 0x4489) { + mfmcount++; + if (mbufo >= mend) + return -1; + shift++; + if (shift == 16) { + shift = 0; + mbufo++; + } + if (sector >= 0 && mfmcount / 16 >= 43) + sector = -1; + } + + mfmcount = 0; + while (getmfmword(mbuf,mbufo, shift) == 0x4489) { + mfmcount++; + if (mbufo >= mend) + return -1; + mbufo++; + } + if (mfmcount < 3) // ignore if less than 3 sync markers + continue; + + mark = mfmdecode(mbuf,mbufo++, shift); + if (mark == 0xfe) { + var tmp = new Uint8Array(8); + var cyl, head, size; //u8 + + cyl = mfmdecode(mbuf,mbufo++, shift); + head = mfmdecode(mbuf,mbufo++, shift); + sector = mfmdecode(mbuf,mbufo++, shift); + size = mfmdecode(mbuf,mbufo++, shift); + crc = (mfmdecode(mbuf,mbufo++, shift) << 8) | mfmdecode(mbuf,mbufo++, shift); + + tmp[0] = tmp[1] = tmp[2] = 0xa1; tmp[3] = mark; + tmp[4] = cyl; tmp[5] = head; tmp[6] = sector; tmp[7] = size; + + // skip 28 bytes + for (i = 0; i < 28; i++) + mfmdecode(mbuf,mbufo++, shift); + + if (SAEF_crc16(tmp,0, 8) != crc || cyl != drv.cyl || head != side || size != 2 || sector < 1 || sector > drv.num_secs || sector >= sectable.length) { + SAEF_warn("disk.drive_write_pcdos() track %d, corrupted sector header", drv.cyl * 2 + side); + return -1; + } + sector--; + continue; + } + if (mark != 0xfb && mark != 0xfa) { + SAEF_warn("disk.drive_write_pcdos() track %d: unknown address mark %02X", drv.cyl * 2 + side, mark); + continue; + } + if (sector < 0) + continue; + for (i = 0; i < 512; i++) + secbuf[i + 4] = mfmdecode(mbuf,mbufo++, shift); + + crc = (mfmdecode(mbuf,mbufo++, shift) << 8) | mfmdecode(mbuf,mbufo++, shift); + if (SAEF_crc16(secbuf,0, 3 + 1 + 512) != crc) { + SAEF_warn("disk.drive_write_pcdos() track %d, sector %d data checksum error", drv.cyl * 2 + side, sector + 1); + continue; + } + seccnt++; + if (count && sectable[sector]) + break; + if (!sectable[sector]) { + secwritten++; + sectable[sector] = 1; + SAEF_ZFile_fseek(zf, drv.trackdata[drv.cyl * 2 + side].offs + sector * 512, SEEK_SET); + SAEF_ZFile_fwrite(secbuf,4, 1, 512, zf); + //SAEF_log("disk.drive_write_pcdos() track %d sector %d written", drv.cyl * 2 + side, sector + 1); + } + sector = -1; + } + if (!count && secwritten != drv.num_secs) + SAEF_warn("disk.drive_write_pcdos() track %d, %d corrupted sectors ignored", drv.cyl * 2 + side, drv.num_secs - secwritten); + + return secwritten; + } + + /*---------------------------------*/ + + function drive_write_data(drv) { + var ret = -1; + var tr = drv.cyl * 2 + side; + + if (drive_writeprotected(drv) || drv.trackdata[tr].type == TRACK_NONE) { + /* read original track back because we didn't really write anything */ + drv.buffered_side = 2; return; } - //if (this.writediskfile) drive_write_ext2 (this.bigmfmbuf, this.writediskfile, &this.writetrackdata[tr], LONGWRITEMODE ? dsklength2 * 8 : this.tracklen); + if (drv.writediskfile) + drive_write_ext2(drv.bigmfmbuf, drv.writediskfile, drv.writetrackdata[tr], longwritemode ? dsklength2 * 8 : drv.tracklen); - switch (this.filetype) { - case ADF_NORMAL: - { - if (this.write_adf_amigados()) { - //notify_user (NUMSG_NEEDEXT2); + switch (drv.filetype) { + case ADF_NORMAL: { + if (drive_write_adf_amigados(drv)) { + if (SAEV_config.floppy.autoEXT2) + convert_adf_to_ext2(drv, SAEV_config.floppy.autoEXT2); + else { + if (!warned_ext2) { + warned_ext2 = true; + //notify_user(NUMSG_NEEDEXT2); + alert("Disk in DF"+drv.num+" does use a non-standard floppy disk format.\n"+ + "You may need to use a custom floppy disk image file instead of a standard one\n"+ + "or enable 'Auto convert to EXT2' in the floppy-page.\n\n"+ + "This message will not appear again." + ); + } + } } return; } + case ADF_EXT1: + break; + case ADF_EXT2: { + if (!longwritemode) + ret = drive_write_adf_amigados(drv); + if (ret) { + SAEF_warn("disk.drive_write_data() not an amigados track %d (error %d), writing as raw track", drv.cyl * 2 + side, ret); + drive_write_ext2(drv.bigmfmbuf, drv.diskfile, drv.trackdata[drv.cyl * 2 + side], longwritemode ? dsklength2 * 8 : drv.tracklen); + } + return; + } + case ADF_SCP: + break; + case ADF_PCDOS: { + ret = drive_write_pcdos(drv, drv.diskfile, 0); + if (ret < 0) SAEF_log("disk.drive_write_data() not a PC formatted track %d (error %d)", drv.cyl * 2 + side, ret); + break; + } } - this.tracktiming[0] = 0; - }; - - this.is_unformatted = function () { - var tr = this.cyl * 2 + AMIGA.disk.side; - if (tr >= this.num_tracks) return true; - if (this.filetype == ADF_EXT2 && this.trackdata[tr].bitlen == 0 && this.trackdata[tr].type != TRACK_AMIGADOS) - return true; - - return this.trackdata[tr].type == TRACK_NONE; - }; - - this.vsync = function() { - if (this.dskready_down_time > 0) - this.dskready_down_time--; - /* emulate drive motor turn on time */ - if (this.dskready_up_time > 0 && !this.is_empty()) { - if ((--this.dskready_up_time) == 0 && !this.motoroff) - this.dskready = true; - } - /* delay until new disk image is inserted */ - if (this.dskchange_time) { - if ((--this.dskchange_time) == 0) - this.insert(); - } + drv.tracktiming[0] = 0; } -} -function Disk() { - this.side = 0; - this.direction = 0; - var selected = 15; - var disabled = 0; - var dskdmaen = DSKDMA_OFF; - var dsklength = 0; - var dsklength2 = 0; - var dsklen = 0; - var dskbytr_val = 0; - var dskpt = 0; - var fifo = new Array(3); for (var i = 0; i < 3; i++) fifo[i] = 0; - var fifo_inuse = new Array(3); for (var i = 0; i < 3; i++) fifo_inuse[i] = 0; - var fifo_filled = false; - var dma_enable = false; - var bitoffset = 0; - var word = 0; - var dsksync = 0; - var dsksync_cycles = 0; - var disk_hpos = 0; - var disk_jitter = 0; - var indexdecay = 0; - var prev_data = 0; - var prev_step = 0; - var linecounter = 0; - var random_bits_min = 1; - var random_bits_max = 3; - var ledstate = new Array(MAX_FLOPPY_DRIVES); for (var i = 0; i < MAX_FLOPPY_DRIVES; i++) ledstate[i] = false; - var floppy = new Array(MAX_FLOPPY_DRIVES); for (var i = 0; i < MAX_FLOPPY_DRIVES; i++) floppy[i] = new Drive(i); + /*-----------------------------------------------------------------------*/ + /* SECT disk */ + /*-----------------------------------------------------------------------*/ - this.setup = function () { - }; - - this.reset = function () { - disk_hpos = 0; - dskdmaen = DSKDMA_OFF; - disabled = 0; - for (var i = 0; i < MAX_FLOPPY_DRIVES; i++) { - floppy[i].reset(); - ledstate[i] = false; - AMIGA.config.hooks.floppy_motor(i, false); - AMIGA.config.hooks.floppy_step(i, floppy[i].cyl); - } - this.DSKLEN(0, 0); - for (var i = 0; i < MAX_FLOPPY_DRIVES; i++) { - this.eject(i); - this.insert(i); - } - }; - - this.rand_shifter = function () { - var r = ((uaerand() >>> 4) & 7) + 1; - while (r-- > 0) { - word <<= 1; - word |= (uaerand() & 0x1000) ? 1 : 0; - bitoffset++; - bitoffset &= 15; - } - }; - - this.setdskchangetime = function (num, dsktime) { - if (floppy[num].dskchange_time > 0) + function setdskchangetime(drv, dsktime) { + /* prevent multiple disk insertions at the same time */ + if (drv.dskchange_time > 0) return; - for (var i = 0; i < MAX_FLOPPY_DRIVES; i++) { - if (floppy[i].num != num && floppy[i].dskchange_time > 0 && floppy[i].dskchange_time + 1 >= dsktime) + if (floppy[i].num != drv.num && floppy[i].dskchange_time > 0 && floppy[i].dskchange_time + 1 >= dsktime) dsktime = floppy[i].dskchange_time + 1; } - floppy[num].dskchange_time = dsktime; - //BUG.info('Disk.setdskchangetime() delayed insert enable %d', dsktime); - }; + drv.dskchange_time = dsktime; + if (disk_debug_logging > 0) SAEF_log("disk.setdskchangetime() delayed insert enable %d", dsktime); + } - this.insert2 = function (num, forced) { - //BUG.info('Disk.insert() DF%d', num); + /*function DISK_reinsert(num) { + drive_eject(floppy[num]); + setdskchangetime(floppy[num], 2 * 50 * 312); + }*/ - if (AMIGA.config.floppy.drive[num].name && AMIGA.config.floppy.drive[num].data) { - floppy[num].diskdata = new Uint8Array(AMIGA.config.floppy.drive[num].data.length); - for (var i = 0; i < AMIGA.config.floppy.drive[num].data.length; i++) - floppy[num].diskdata[i] = AMIGA.config.floppy.drive[num].data.charCodeAt(i) & 0xff; - } + /*-----------------------------------------------------------------------*/ + + //function disk_insert_2(num, name, forced, forcedwriteprotect) { + function disk_insert_2(num, file, forced) { + var drv = floppy[num]; if (forced) { - if (!floppy[num].is_empty()) - floppy[num].eject(); - floppy[num].insert(null); + //drive_insert(drv, SAEV_config, num, name, data, false, forcedwriteprotect); + drive_insert(drv, SAEV_config, num, file, false); return; } + /*if (SAEV_config.floppy.drive[num].name === name) { + SAEF_warn("disk_insert_2() already inserted"); + return; + } + SAEV_config.floppy.drive[num].name = name; + SAEV_config.floppy.drive[num].forcedWriteProtect = forcedwriteprotect;*/ - if (!floppy[num].is_empty() || floppy[num].dskchange_time > 0) { - floppy[num].eject(); - this.setdskchangetime(num, 100); - } else - this.setdskchangetime(num, 1); - }; - this.insert = function (num) { - this.insert2(num, false); - }; - - this.eject = function (num) { - floppy[num].eject(); - floppy[num].diskdata = null; - }; - - this.is_empty = function (num) { - return floppy[num].is_empty(); - }; + drv.dskeject = false; + //drv.newname = name; + //drv.newnamewriteprotected = forcedwriteprotect; + drv.newfile = file.clone(); //ATT - this.select_fetch = function (data) { - selected = (data >> 3) & 15; - this.side = 1 - ((data >> 2) & 1); - this.direction = (data >> 1) & 1; - }; - - this.select_set = function (data) { + if (file.size == 0) + SAER.disk.eject(num); + else if (!drive_empty(drv) || drv.dskchange_time > 0) + //delay eject so that it is always called when emulation is active + drv.dskeject = true; + else + setdskchangetime(drv, 1 * 312); + } + //this.insert = function(num, name, forcedwriteprotect) { //disk_insert() + this.insert = function(num, file) { //disk_insert() + //set_config_changed(); + //target_addtorecent(name, 0); + disk_insert_2(num, file, false); + } + this.insert_force = function(num, file) { //disk_insert_force() + disk_insert_2(num, file, true); + } + + this.eject = function(num) { //disk_eject() + //set_config_changed(); + //SAER.gui.filename(num, ""); + drive_eject(floppy[num]); + SAEV_config.floppy.drive[num].file.clr(); + //floppy[num].newname = ""; + floppy[num].newfile = null; + driveNames[num] = ""; //OWN + update_drive_gui(num, true); + } + + /*-----------------------------------------------------------------------*/ + + function disk_check_change() { + /*if (SAEV_config.floppy.speed != changed_prefs.floppy_speed) + SAEV_config.floppy.speed = changed_prefs.floppy_speed; + if (SAEV_config.floppy.readOnly != changed_prefs.floppy_read_only) + SAEV_config.floppy.readOnly = changed_prefs.floppy_read_only;*/ + for (var i = 0; i < MAX_FLOPPY_DRIVES; i++) { + var drv = floppy[i]; + if (drv.dskeject) { + drive_eject(drv); + /* set dskchange_time, disk_insert() will be + * called from disk_check_change() after 2 second delay + * this makes sure that all programs detect disk change correctly */ + setdskchangetime(drv, 2 * 50 * 312); + } + /*if (SAEV_config.floppy.drive[i].type != changed_prefs.floppyslots[i].type) { + SAEV_config.floppy.drive[i].type = changed_prefs.floppyslots[i].type; + reset_drive(i); + #ifdef RETROPLATFORM + rp_floppy_device_enable (i, SAEV_config.floppy.drive[i].type >= SAEC_Config_Floppy_Type_35_DD); + #endif + }*/ + } + } + + this.vsync = function() { //DISK_vsync() + disk_check_change(); + + for (var i = 0; i < MAX_FLOPPY_DRIVES; i++) { + if (SAEV_config.floppy.drive[i].type > SAEC_Config_Floppy_Type_None) { //OWN + var drv = floppy[i]; + var file = SAEV_config.floppy.drive[i].file; + if (drv.dskchange_time == 0 && file.name !== driveNames[i]) { + //SAEF_log("disk.vsync() dskchange unit %d ('%s')", i, file.name); + this.insert_force(i, file); + driveNames[i] = file.name; + } + } + } + } + + /*-----------------------------------------------------------------------*/ + + /*this.disk_empty = function(num) { + return drive_empty(floppy[num]); + }*/ + + /*static TCHAR *tobin (uae_u8 v) { + static TCHAR buf[9]; + for (int i = 7; i >= 0; i--) + buf[7 - i] = v & (1 << i) ? '1' : '0'; + return buf; + }*/ + + function fetch_DISK_select(data) { + if (SAEV_config.chipset.compatible == SAEC_Config_Chipset_Compatible_A1000V) + selected = (data >> 3) & 3; + else + selected = (data >> 3) & 15; + + side = 1 - ((data >> 2) & 1); + direction = (data >> 1) & 1; + } + + this.select_set = function(data) { //DISK_select_set() prev_data = data; prev_step = data & 1; - this.select_fetch(data); - }; - - this.select = function (data) { - //BUG.info('Disk.select() $%02x', data); - var step_pulse, prev_selected, dr; + fetch_DISK_select(data); + } - prev_selected = selected; - this.select_fetch(data); - step_pulse = data & 1; + this.select = function(data) { //DISK_select() + var velvet = SAEV_config.chipset.compatible == SAEC_Config_Chipset_Compatible_A1000V; + var dr; - if ((prev_data & 0x80) != (data & 0x80)) { - for (dr = 0; dr < 4; dr++) { - if (floppy[dr].indexhackmode > 1 && !(selected & (1 << dr))) { - floppy[dr].indexhack = 1; - BUG.info('Disk.select() indexhack!'); - } + var prev_selected = selected; + + fetch_DISK_select(data); + var step_pulse = data & 1; + + /*if (disk_debug_logging > 2) { + if (velvet) + write_log (_T("%08X %02X.%02X %s drvmask=%x"), SAER_CPU_getPC(), prev_data, data, tobin(data), selected ^ 3); + else + write_log (_T("%08X %02X.%02X %s drvmask=%x"), SAER_CPU_getPC(), prev_data, data, tobin(data), selected ^ 15); + }*/ + + if (amax_enabled) { + for (dr = 0; dr < MAX_FLOPPY_DRIVES; dr++) { + var drv = floppy[dr]; + if (drv.amax) + amax_disk_select(data, prev_data, dr); } } - if (prev_step != step_pulse) { - prev_step = step_pulse; - if (prev_step) { - for (dr = 0; dr < MAX_FLOPPY_DRIVES; dr++) { - if (!((prev_selected | disabled) & (1 << dr))) { - floppy[dr].step(); - if (floppy[dr].indexhackmode > 1 && (data & 0x80)) - floppy[dr].indexhack = 1; + + if (!velvet) { + if ((prev_data & 0x80) != (data & 0x80)) { + for (dr = 0; dr < 4; dr++) { + if (floppy[dr].indexhackmode > 1 && !((selected | disabled) & (1 << dr))) { + floppy[dr].indexhack = true; + //if (disk_debug_logging > 2) SAEF_log("indexhack! "); } } } } - for (dr = 0; dr < MAX_FLOPPY_DRIVES; dr++) { - if (!(selected & (1 << dr)) && (prev_selected & (1 << dr))) { - floppy[dr].drive_id_scnt++; - floppy[dr].drive_id_scnt &= 31; - floppy[dr].idbit = (floppy[dr].drive_id & (1 << (31 - floppy[dr].drive_id_scnt))) ? 1 : 0; - if (!(disabled & (1 << dr))) { - if ((prev_data & 0x80) == 0 || (data & 0x80) == 0) - floppy[dr].set_motor(0); /* motor off: if motor bit = 0 in prevdata or data -> turn motor on */ - else if (prev_data & 0x80) - floppy[dr].set_motor(1); - /* motor on: if motor bit = 1 in prevdata only (motor flag state in data has no effect) -> turn motor off */ + /*if (disk_debug_logging > 2) { + if (velvet) { + write_log (_T(" %d%d "), (selected & 1) ? 0 : 1, (selected & 2) ? 0 : 1); + if ((prev_data & 0x08) != (data & 0x08)) write_log (_T(" dsksel0 %d "), (data & 0x08) ? 0 : 1); + if ((prev_data & 0x10) != (data & 0x10)) write_log (_T(" dsksel1 %d "), (data & 0x10) ? 0 : 1); + if ((prev_data & 0x20) != (data & 0x20)) write_log (_T(" dskmotor0 %d "), (data & 0x20) ? 0 : 1); + if ((prev_data & 0x40) != (data & 0x40)) write_log (_T(" dskmotor1 %d "), (data & 0x40) ? 0 : 1); + if ((prev_data & 0x02) != (data & 0x02)) write_log (_T(" direct %d "), (data & 0x02) ? 1 : 0); + if ((prev_data & 0x04) != (data & 0x04)) write_log (_T(" side %d "), (data & 0x04) ? 1 : 0); + } else { + write_log (_T(" %d%d%d%d "), (selected & 1) ? 0 : 1, (selected & 2) ? 0 : 1, (selected & 4) ? 0 : 1, (selected & 8) ? 0 : 1); + if ((prev_data & 0x80) != (data & 0x80)) write_log (_T(" dskmotor %d "), (data & 0x80) ? 1 : 0); + if ((prev_data & 0x02) != (data & 0x02)) write_log (_T(" direct %d "), (data & 0x02) ? 1 : 0); + if ((prev_data & 0x04) != (data & 0x04)) write_log (_T(" side %d "), (data & 0x04) ? 1 : 0); + } + }*/ + + // step goes high and drive was selected when step pulse changes: step + if (prev_step != step_pulse) { + //if (disk_debug_logging > 2) SAEF_log("step %d ", step_pulse); + prev_step = step_pulse; + if (prev_step) { // && !savestate_state) { + for (dr = 0; dr < MAX_FLOPPY_DRIVES; dr++) { + if (!((prev_selected | disabled) & (1 << dr))) { + drive_step(floppy[dr], direction); + if (floppy[dr].indexhackmode > 1 && (data & 0x80)) + floppy[dr].indexhack = true; + } } - if (dr == 0) - floppy[dr].idbit = 0; } } - for (dr = 0; dr < MAX_FLOPPY_DRIVES; dr++) { - var state = (!(selected & (1 << dr))) | !floppy[dr].motoroff; - if (ledstate[dr] != state) { - ledstate[dr] = state; - AMIGA.config.hooks.floppy_motor(dr, ledstate[dr]); + + //if (!savestate_state) + { + if (velvet) { + for (dr = 0; dr < 2; dr++) { + var drv = floppy[dr]; + var motormask = 0x20 << dr; + var selectmask = 0x08 << dr; + if (!(selected & (1 << dr)) && !(disabled & (1 << dr))) { + if (!(prev_data & motormask) && (data & motormask)) { + drive_motor(drv, 1); + } else if ((prev_data & motormask) && !(data & motormask)) { + drive_motor(drv, 0); + } + } + } + } else { + for (dr = 0; dr < MAX_FLOPPY_DRIVES; dr++) { + var drv = floppy[dr]; + /* motor on/off workings tested with small assembler code on real Amiga 1200. */ + /* motor/id flipflop is set only when drive select goes from high to low */ + if (!((selected | disabled) & (1 << dr)) && (prev_selected & (1 << dr)) ) { + drv.drive_id_scnt++; + drv.drive_id_scnt &= 31; + drv.idbit = (drv.drive_id & (1 << (31 - drv.drive_id_scnt))) ? 1 : 0; + if (!(disabled & (1 << dr))) { + if ((prev_data & 0x80) == 0 || (data & 0x80) == 0) { + /* motor off: if motor bit = 0 in prevdata or data . turn motor on */ + drive_motor(drv, 0); + } else if (prev_data & 0x80) { + /* motor on: if motor bit = 1 in prevdata only (motor flag state in data has no effect). turn motor off */ + drive_motor(drv, 1); + } + } + if (!SAEV_config.chipset.df0idhw && dr == 0) + drv.idbit = 0; + + if (DEBUG_DRIVE_ID) SAEF_log("disk.select() sel %d id %s ($%08X) [$%08x, bit #%02d: %d]", dr, drive_id_name(drv), drv.drive_id, drv.drive_id << drv.drive_id_scnt >>> 0, 31 - drv.drive_id_scnt, drv.idbit); + } + } } } + + for (dr = 0; dr < MAX_FLOPPY_DRIVES; dr++) { + floppy[dr].state = (!(selected & (1 << dr))) | !floppy[dr].motoroff; + update_drive_gui(dr, false); + } prev_data = data; - }; + //if (disk_debug_logging > 2) SAEF_log("\n"); + } - this.status = function () { + /*-----------------------------------------------------------------------*/ + + this.status_ciaa = function() { //DISK_status_ciaa() var st = 0x3c; + if (SAEV_config.chipset.compatible == SAEC_Config_Chipset_Compatible_A1000V) { + for (var dr = 0; dr < 2; dr++) { + var drv = floppy[dr]; + if (!(((selected >> 3) | disabled) & (1 << dr))) { + if (drv.dskchange) + st &= ~0x20; + if (drive_track0(drv)) + st &= ~0x10; + } + } + if (disk_debug_logging > 2) SAEF_log("disk.status_ciaa() pc $%08x, status $%02x", SAER_CPU_getPC(), st); + return st; + } + for (var dr = 0; dr < MAX_FLOPPY_DRIVES; dr++) { - if (!((selected | disabled) & (1 << dr))) { - if (floppy[dr].is_running()) { - if (floppy[dr].dskready && !floppy[dr].indexhack) + var drv = floppy[dr]; + if (drv.amax) { + if (amax_active()) + st = amax_disk_status(st); + } else if (!((selected | disabled) & (1 << dr))) { + if (drive_running(drv)) { + if (drv.dskready && !drv.indexhack && SAEV_config.floppy.drive[dr].type != SAEC_Config_Floppy_Type_35_DD_ESCOM) st &= ~0x20; } else { - if (dr > 0) { - if (floppy[dr].idbit) + if (SAEV_config.chipset.df0idhw || dr > 0) { + /* report drive ID */ + if (drv.idbit && SAEV_config.floppy.drive[dr].type != SAEC_Config_Floppy_Type_35_DD_ESCOM) st &= ~0x20; } else { /* non-ID internal drive: mirror real dskready */ - if (floppy[dr].dskready) + if (drv.dskready) st &= ~0x20; } /* dskrdy needs some cycles after switching the motor off.. (Pro Tennis Tour) */ - if (dr == 0 && floppy[dr].motordelay) + if (!SAEV_config.chipset.df0idhw && dr == 0 && drv.motordelay) st &= ~0x20; } - if (floppy[dr].is_track0()) + if (drive_track0(drv)) st &= ~0x10; - if (floppy[dr].is_writeprotected()) + if (drive_writeprotected(drv)) st &= ~8; - if (floppy[dr].dskchange && AMIGA.config.floppy.drive[dr].type != SAEV_Config_Floppy_Type_525_SD) + if (drv.dskchange && SAEV_config.floppy.drive[dr].type != SAEC_Config_Floppy_Type_525_SD) st &= ~4; - } else if (!(selected & (1 << dr))) { - if (floppy[dr].idbit) + } else if (!((selected | disabled) & (1 << dr))) { + if (drv.idbit) st &= ~0x20; } } - //BUG.info('Disk.status() $%02x', st); return st; - }; - - this.fetchnextrevolution = function (num) { - floppy[num].trackspeed = floppy[num].get_floppy_speed2(); - }; + } - this.handler = function (data) { - var flag = data & 255; - var disk_sync_cycle = data >> 8; - //BUG.info('Disk.handler() data $%x, flag %d, disk_sync_cycle %d', data, flag, disk_sync_cycle); + this.status_ciab = function(st) { //DISK_status_ciab() + if (SAEV_config.chipset.compatible == SAEC_Config_Chipset_Compatible_A1000V) { + st |= 0x80; + for (var dr = 0; dr < 2; dr++) { + var drv = floppy[dr]; + if (!(((selected >> 3) | disabled) & (1 << dr))) { + if (drive_writeprotected(drv)) + st &= ~0x80; + } + } + if (disk_debug_logging > 2) SAEF_log("disk.status_ciab() pc $%08x, status $%02x", SAER_CPU_getPC(), st); + } + return st; + } - AMIGA.events.remevent(EV2_DISK); + /*-----------------------------------------------------------------------*/ - this.update(disk_sync_cycle); + function unformatted(drv) { + var tr = drv.cyl * 2 + side; + if (tr >= drv.num_tracks) + return true; + if (drv.filetype == ADF_EXT2 && drv.trackdata[tr].bitlen == 0 && drv.trackdata[tr].type != TRACK_AMIGADOS) + return true; + if (drv.trackdata[tr].type == TRACK_NONE) + return true; + return false; + } - if (flag & (DISK_REVOLUTION << 0)) this.fetchnextrevolution(0); - if (flag & (DISK_REVOLUTION << 1)) this.fetchnextrevolution(1); - if (flag & (DISK_REVOLUTION << 2)) this.fetchnextrevolution(2); - if (flag & (DISK_REVOLUTION << 3)) this.fetchnextrevolution(3); - if (flag & DISK_WORDSYNC) - AMIGA.INTREQ(INT_DSKSYN); - if (flag & DISK_INDEXSYNC) { - if (!indexdecay) { - indexdecay = 2; - //AMIGA.cia.setICR(CIA_B, 0x10, null); - //AMIGA.cia.diskindex(); - AMIGA.cia.SetICRB(0x10, null); + /* get one bit from MFM bit stream */ + /*STATIC_INLINE uae_u32 getonebit (uae_u16 * mfmbuf, int mfmpos) { + uae_u16 *buf = &mfmbuf[mfmpos >> 4]; + return (buf[0] & (1 << (15 - (mfmpos & 15)))) ? 1 : 0; + }*/ + function getonebit(mfmbuf, mfmpos) { + return (mfmbuf[mfmpos >> 4] & (1 << (15 - (mfmpos & 15)))) ? 1 : 0; + } + + function dumpdisk(name) { + /*var i, j, k, w; + + for (i = 0; i < MAX_FLOPPY_DRIVES; i++) { + drive *drv = &floppy[i]; + if (!(disabled & (1 << i))) { + console_out_f (_T("%s: drive %d motor %s cylinder %2d sel %s %s mfmpos %d/%d\n"), + name, i, drv->motoroff ? _T("off") : _T(" on"), drv->cyl, (selected & (1 << i)) ? _T("no") : _T("yes"), + drive_writeprotected(drv) ? _T("ro") : _T("rw"), drv->mfmpos, drv->tracklen); + if (drv->motoroff == 0) { + w = 0; + for (j = -4; j < 13; j++) { + for (k = 0; k < 16; k++) { + int pos = drv->mfmpos + j * 16 + k; + if (pos < 0) + pos += drv->tracklen; + w <<= 1; + w |= getonebit(drv->bigmfmbuf, pos); + } + console_out_f(_T("%04X%c"), w, j == -1 ? '|' : ' '); + } + console_out (_T("\n")); + } } } - }; - - this.update_jitter = function () { - if (random_bits_max > 0) - disk_jitter = ((uaerand() >>> 4) % (random_bits_max - random_bits_min + 1)) + random_bits_min; - else - disk_jitter = 0; - }; + console_out_f (_T("side %d dma %d off %d word %04X pt %08X len %04X bytr %04X adk %04X sync %04X\n"), + side, dskdmaen, bitoffset, word, dskpt, dsklen, dskbytr_val, SAEV_Custom_adkcon, dsksync);*/ + SAEF_log("disk.dumpdisk() %s", name); + } - this.updatetrackspeed = function (num, mfmpos) { - if (dskdmaen < DSKDMA_WRITE) { - var t = floppy[num].tracktiming[Math.floor(mfmpos / 8)]; - floppy[num].trackspeed = Math.floor(floppy[num].get_floppy_speed2() * t / 1000); - if (floppy[num].trackspeed < 700 || floppy[num].trackspeed > 3000) { - BUG.info('Disk.updatetrackspeed() corrupted trackspeed value %d', floppy[num].trackspeed); - floppy[num].trackspeed = 1000; - } - } - }; - - this.fifostatus = function () { - if (fifo_inuse[0] && fifo_inuse[1] && fifo_inuse[2]) - return 1; - else if (!fifo_inuse[0] && !fifo_inuse[1] && !fifo_inuse[2]) - return -1; - return 0; - }; - - this.dmafinished = function () { - //BUG.info('Disk.dmafinished()'); - AMIGA.INTREQ(INT_DSKBLK); - //LONGWRITEMODE = 0; + function disk_dmafinished() { + SAER.custom.INTREQ(SAEC_Custom_INTF_SETCLR | SAEC_Custom_INTF_DSKBLK); + longwritemode = 0; dskdmaen = DSKDMA_OFF; dsklength = 0; - }; + dsklen = 0; + /*if (disk_debug_logging > 0) { + write_log (_T("disk dma finished %08X MFMpos="), dskpt); + for (var dr = 0; dr < MAX_FLOPPY_DRIVES; dr++) + write_log (_T("%d%s"), floppy[dr].mfmpos, dr < MAX_FLOPPY_DRIVES - 1 ? _T(",") : _T("")); + write_log (_T("\n")); + }*/ + } - this.readdma = function () { - if (AMIGA.dmaen(DMAF_DSKEN) && bitoffset == 15 && dma_enable && dskdmaen == DSKDMA_READ && dsklength >= 0) { + function fetchnextrevolution(drv) { + if (drv.revolution_check) + return; + drv.trackspeed = get_floppy_speed2(drv); + if (REVOLUTION_DEBUG && (1 || drv.mfmpos != 0)) SAEF_log("disk.fetchnextrevolution() DMA=%d %d %d/%d %d %d %d", dskdmaen, drv.trackspeed, drv.mfmpos, drv.tracklen, drv.indexoffset, drv.floppybitcounter); + drv.revolution_check = 2; + if (!drv.multi_revolution) + return; + switch (drv.filetype) { + case ADF_SCP: + scp_loadrevolution(drv.bigmfmbuf, drv.num, drv.tracktiming); //, &drv.tracklen); + break; + /*case ADF_FDI: + fdi2raw_loadrevolution(drv.fdi, drv.bigmfmbuf, drv.tracktiming, drv.cyl * 2 + side, &drv.tracklen, 1); + break;*/ + } + } + + function do_disk_index() { + if (REVOLUTION_DEBUG) SAEF_log("disk.do_disk_index() %d", indexdecay); + if (!indexdecay) { + indexdecay = 2; + SAER.cia.diskindex(); + } + } + + this.handler = function(data) { //DISK_handler() + var flag = data & 255; + var disk_sync_cycle = data >>> 8; + var hpos = SAER.events.current_hpos(); + + SAER.events.event2_remevent(SAEC_Events_EV2_DISK); + this.update(disk_sync_cycle); + if (!dskdmaen) { + if (flag & (DISK_REVOLUTION << 0)) fetchnextrevolution(floppy[0]); + if (flag & (DISK_REVOLUTION << 1)) fetchnextrevolution(floppy[1]); + if (flag & (DISK_REVOLUTION << 2)) fetchnextrevolution(floppy[2]); + if (flag & (DISK_REVOLUTION << 3)) fetchnextrevolution(floppy[3]); + } + if (flag & DISK_WORDSYNC) + SAER.custom.INTREQ(SAEC_Custom_INTF_SETCLR | SAEC_Custom_INTF_DSKSYN); + if (flag & DISK_INDEXSYNC) + do_disk_index(); + } + + function disk_doupdate_write(drv, floppybits) { + var dr, drives = [0,0,0,0]; + + for (dr = 0; dr < MAX_FLOPPY_DRIVES; dr++) { + var drv2 = floppy[dr]; + drives[dr] = 0; + if (drv2.motoroff) + continue; + if ((selected | disabled) & (1 << dr)) + continue; + drives[dr] = 1; + } + + while (floppybits >= drv.trackspeed) { + for (dr = 0; dr < MAX_FLOPPY_DRIVES; dr++) { + if (drives[dr]) { + floppy[dr].mfmpos++; + floppy[dr].mfmpos %= drv.tracklen; + } + } + if (SAEF_Custom_dmaen(SAEC_Custom_DMAF_DSKEN) && dskdmaen == DSKDMA_WRITE && dsklength > 0 && fifo_filled) { + bitoffset++; + bitoffset &= 15; + if (!bitoffset) { + // fast disk modes, fill the fifo instantly + if (SAEV_config.floppy.speed > 100 && !fifo_inuse[0] && !fifo_inuse[1] && !fifo_inuse[2]) { + while (!fifo_inuse[2]) { + var w = SAER_Memory_chipGet16_indirect(dskpt); + SAER.disk.DSKDAT(w); + dskpt += 2; + } + } + if (SAER.disk.fifostatus() >= 0) { + var w = SAER.disk.DSKDATR(); + for (dr = 0; dr < MAX_FLOPPY_DRIVES ; dr++) { + var drv2 = floppy[dr]; + if (drives[dr]) { + drv2.bigmfmbuf[drv2.mfmpos >> 4] = w; + drv2.bigmfmbuf[(drv2.mfmpos >> 4) + 1] = 0x5555; + drv2.writtento = 1; + } + if (amax_enabled) + amax_diskwrite(w); + } + dsklength--; + if (dsklength <= 0) { + disk_dmafinished(); + for (dr = 0; dr < MAX_FLOPPY_DRIVES ; dr++) { + var drv = floppy[dr]; + drv.writtento = 0; + if (drv.motoroff) + continue; + if ((selected | disabled) & (1 << dr)) + continue; + drive_write_data(drv); + } + } + } + } + } + floppybits -= drv.trackspeed; + } + } + + function update_jitter() { + if (SAEV_config.floppy.randomBitsMax > 0) + disk_jitter = ((Math.decimalRandom() >>> 4) % (SAEV_config.floppy.randomBitsMax - SAEV_config.floppy.randomBitsMin + 1)) + SAEV_config.floppy.randomBitsMin; + else + disk_jitter = 0; + } + + function updatetrackspeed(drv, mfmpos) { + if (dskdmaen < DSKDMA_WRITE) { + var t = drv.tracktiming[mfmpos >> 3]; //ORG mfmpos / 8 + var ts = Math.floor(get_floppy_speed2(drv) * t / 1000); + if (ts < 700 || ts > 3000) { + if (++warned_trackspeed < 50) + SAEF_warn("disk.updatetrackspeed() corrupted trackspeed value %d %d (%d/%d)", t, ts, mfmpos, drv.tracklen); + } else + drv.trackspeed = ts; + } + } + + function disk_doupdate_predict(startcycle) { + var finaleventcycle = SAER.playfield.get_maxhpos() << 8; + var finaleventflag = 0; + var noselected = true; + + for (var dr = 0; dr < MAX_FLOPPY_DRIVES; dr++) { + var drv = floppy[dr]; + if (drv.motoroff) + continue; + if (!drv.trackspeed) + continue; + if ((selected | disabled) & (1 << dr)) + continue; + var mfmpos = drv.mfmpos; + if (drv.tracktiming[0]) + updatetrackspeed(drv, mfmpos); + var diskevent_flag = 0; + var tword = word; //u32 + noselected = false; + //int diff = drv.floppybitcounter % drv.trackspeed; ORG + var countcycle = startcycle; // + (diff ? drv.trackspeed - diff : 0); ORG + while (countcycle < (SAER.playfield.get_maxhpos() << 8)) { + if (drv.tracktiming[0]) + updatetrackspeed(drv, mfmpos); + countcycle += drv.trackspeed; + if (dskdmaen != DSKDMA_WRITE || (dskdmaen == DSKDMA_WRITE && !dma_enable)) { + tword = (tword << 1) >>> 0; + if (!drive_empty(drv)) { + if (unformatted(drv)) + tword = (tword | ((Math.decimalRandom() & 0x1000) ? 1 : 0)) >>> 0; + else + tword = (tword | getonebit(drv.bigmfmbuf, mfmpos)) >>> 0; + } + if (dskdmaen != DSKDMA_READ && (tword & 0xffff) == dsksync && dsksync != 0) + diskevent_flag |= DISK_WORDSYNC; + } + mfmpos++; + mfmpos %= drv.tracklen; + if (!dskdmaen) { + if (mfmpos == 0) + diskevent_flag |= DISK_REVOLUTION << drv.num; + if (mfmpos == drv.indexoffset) + diskevent_flag |= DISK_INDEXSYNC; + } + if (dskdmaen != DSKDMA_WRITE && mfmpos == drv.skipoffset) { + update_jitter(); + var skipcnt = disk_jitter; + while (skipcnt-- > 0) { + mfmpos++; + mfmpos %= drv.tracklen; + if (!dskdmaen) { + if (mfmpos == 0) + diskevent_flag |= DISK_REVOLUTION << drv.num; + if (mfmpos == drv.indexoffset) + diskevent_flag |= DISK_INDEXSYNC; + } + } + } + if (diskevent_flag) + break; + } + if (drv.tracktiming[0]) + updatetrackspeed(drv, drv.mfmpos); + if (diskevent_flag && countcycle < finaleventcycle) { + finaleventcycle = countcycle; + finaleventflag = diskevent_flag; + } + } + if (finaleventflag && (finaleventcycle >> 8) < SAER.playfield.get_maxhpos()) + SAER.events.event2_newevent(SAEC_Events_EV2_DISK, (finaleventcycle - startcycle) >> 8, ((finaleventcycle >> 8) << 8) | finaleventflag); + } + + this.fifostatus = function() { //disk_fifostatus() + if (fifo_inuse[0] && fifo_inuse[1] && fifo_inuse[2]) + return 1; + if (!fifo_inuse[0] && !fifo_inuse[1] && !fifo_inuse[2]) + return -1; + return 0; + } + + function doreaddma() { + if (SAEF_Custom_dmaen(SAEC_Custom_DMAF_DSKEN) && bitoffset == 15 && dma_enable && dskdmaen == DSKDMA_READ && dsklength >= 0) { if (dsklength > 0) { + // DSKLEN == 1: finish without DMA transfer. if (dsklength == 1 && dsklength2 == 1) { - this.dmafinished(); + disk_dmafinished(); return 0; } - /* fast disk modes, just flush the fifo */ - if (AMIGA.config.floppy.speed > SAEV_Config_Floppy_Speed_Original && fifo_inuse[0] && fifo_inuse[1] && fifo_inuse[2]) { + // fast disk modes, just flush the fifo + if (SAEV_config.floppy.speed > 100 && fifo_inuse[0] && fifo_inuse[1] && fifo_inuse[2]) { while (fifo_inuse[0]) { - var w = this.DSKDATR(); - AMIGA.mem.store16(dskpt, w); + var w = SAER.disk.DSKDATR(); + SAER_Memory_chipPut16_indirect(dskpt, w); dskpt += 2; } } - if (this.fifostatus() > 0) { - BUG.info('Disk.readdma() fifo overflow detected, retrying...'); + if (SAER.disk.fifostatus() > 0) { + SAEF_warn("disk.doreaddma() fifo overflow detected, retrying..."); return -1; } else { - this.DSKDAT(word); + SAER.disk.DSKDAT(word); dsklength--; } } return 1; } return 0; - }; - - this.update_read_nothing = function (floppybits) { - //BUG.info('Disk.update_read_nothing() floppybits %d', floppybits); + } + function disk_doupdate_read_nothing(floppybits) { while (floppybits >= get_floppy_speed()) { word <<= 1; - this.readdma(); - word &= 0xffff; + word &= 0xffff; //OWN + doreaddma(); if ((bitoffset & 7) == 7) { dskbytr_val = word & 0xff; dskbytr_val |= 0x8000; @@ -1118,498 +3029,548 @@ function Disk() { bitoffset &= 15; floppybits -= get_floppy_speed(); } - }; + } - /*static this.read_floppy_data (struct zfile *diskfile, Track *tid, var offset, var *dst, var len) { - if (len == 0) - return; - zfile_fseek (diskfile, tid->offs + offset, SEEK_SET); - zfile_fread (dst, 1, len, diskfile); - }*/ - - this.update_read = function (num, floppybits) { - //BUG.info('Disk.update_read() DF%d, floppybits %d', num, floppybits); - - while (floppybits >= floppy[num].trackspeed) { - var oldmfmpos = floppy[num].mfmpos; - if (floppy[num].tracktiming[0]) - this.updatetrackspeed(num, floppy[num].mfmpos); + function wordsync_detected(startup) { + dsksync_cycles = SAEV_Events_currcycle + WORDSYNC_TIME * SAEC_Events_CYCLE_UNIT; + if (dskdmaen != DSKDMA_OFF) { + /*if (disk_debug_logging && dma_enable == 0) { + int pos = -1; + for (int i = 0; i < MAX_FLOPPY_DRIVES; i++) { + drive *drv = &floppy[i]; + if (!(disabled & (1 << i)) && !drv->motoroff) { + pos = drv->mfmpos; + break; + } + } + write_log(_T("Sync match %04x mfmpos %d enable %d wordsync %d\n"), dsksync, pos, dma_enable, (SAEV_Custom_adkcon & 0x0400) != 0); + if (disk_debug_logging > 1) + dumpdisk(_T("SYNC")); + }*/ + if (!startup) + dma_enable = 1; + SAER.custom.INTREQ(SAEC_Custom_INTF_SETCLR | SAEC_Custom_INTF_DSKSYN); + } + if (SAEV_Custom_adkcon & 0x0400) + bitoffset = 15; + } + function disk_doupdate_read(drv, floppybits) { + /* ORG + uae_u16 *mfmbuf = drv.bigmfmbuf; + dsksync = 0x4444; + SAEV_Custom_adkcon |= 0x400; + drv.mfmpos = 0; + memset (mfmbuf, 0, 1000); + cycles = 0x1000000; + // 4444 4444 4444 aaaa aaaaa 4444 4444 4444 + // 4444 aaaa aaaa 4444 + mfmbuf[0] = 0x4444; + mfmbuf[1] = 0x4444; + mfmbuf[2] = 0x4444; + mfmbuf[3] = 0xaaaa; + mfmbuf[4] = 0xaaaa; + mfmbuf[5] = 0x4444; + mfmbuf[6] = 0x4444; + mfmbuf[7] = 0x4444; + */ + while (floppybits >= drv.trackspeed) { + if (drv.tracktiming[0]) + updatetrackspeed(drv, drv.mfmpos); word <<= 1; - if (!floppy[num].is_empty()) { - if (floppy[num].is_unformatted()) - word |= ((uaerand() & 0x1000) ? 1 : 0); - else - word |= floppy[num].getonebit(floppy[num].mfmpos); - } - word &= 0xffff; + word &= 0xffff; //OWN - floppy[num].mfmpos++; - floppy[num].mfmpos %= floppy[num].tracklen; - if (floppy[num].mfmpos == floppy[num].indexoffset) { - //if (floppy[num].indexhack) BUG.info('Disk.update_read() indexhack cleared'); - floppy[num].indexhack = 0; + if (!drive_empty(drv)) { + if (unformatted(drv)) + word |= (Math.decimalRandom() & 0x1000) ? 1 : 0; + else + word |= getonebit(drv.bigmfmbuf, drv.mfmpos); } - if (floppy[num].mfmpos == floppy[num].skipoffset) { - this.update_jitter(); - floppy[num].mfmpos += disk_jitter; - floppy[num].mfmpos %= floppy[num].tracklen; - } - if (this.readdma() < 0) { - floppy[num].mfmpos = oldmfmpos; + if (doreaddma() < 0) { + word >>= 1; return; } + drv.mfmpos++; + drv.mfmpos %= drv.tracklen; + if (drv.mfmpos == drv.indexoffset) { + if (disk_debug_logging > 2 && drv.indexhack) SAEF_log("disk.disk_doupdate_read() indexhack cleared"); + drv.indexhack = false; + do_disk_index(); + } + if (drv.mfmpos == 0) { + fetchnextrevolution(drv); + if (drv.tracktiming[0]) + updatetrackspeed(drv, drv.mfmpos); + } + if (drv.mfmpos == drv.skipoffset) { + update_jitter(); + var skipcnt = disk_jitter; + while (skipcnt-- > 0) { + drv.mfmpos++; + drv.mfmpos %= drv.tracklen; + if (drv.mfmpos == drv.indexoffset) { + if (disk_debug_logging > 2 && drv.indexhack) SAEF_log("disk.disk_doupdate_read() indexhack cleared"); + drv.indexhack = false; + do_disk_index(); + } + if (drv.mfmpos == 0) { + fetchnextrevolution(drv); + if (drv.tracktiming[0]) + updatetrackspeed(drv, drv.mfmpos); + } + } + } if ((bitoffset & 7) == 7) { dskbytr_val = word & 0xff; dskbytr_val |= 0x8000; } - if (word == dsksync) { - dsksync_cycles = AMIGA.events.currcycle + WORDSYNC_TIME * CYCLE_UNIT; - if (dskdmaen != DSKDMA_OFF) { - //if (!dma_enable) BUG.info('Disk.update_read() Sync match, DMA started at %d', floppy[num].mfmpos); - dma_enable = true; - } - if (AMIGA.adkcon & 0x400) { - bitoffset = 15; - } - } + if (word == dsksync) + wordsync_detected(false); bitoffset++; bitoffset &= 15; - floppybits -= floppy[num].trackspeed; + floppybits -= drv.trackspeed; } - }; - - this.update_write = function (num, floppybits) { - var dr, drives = [0, 0, 0, 0]; + } - for (dr = 0; dr < MAX_FLOPPY_DRIVES; dr++) { - drives[dr] = 0; - if (floppy[dr].motoroff) - continue; - if (selected & (1 << dr)) - continue; - drives[dr] = 1; + /*function disk_dma_debugmsg() { + SAEF_log("LEN=%04X (%d) SYNC=%04X PT=%08X ADKCON=%04X INTREQ=%04X PC=%08X", dsklength, dsklength, (SAEV_Custom_adkcon & 0x400) ? dsksync : 0xffff, dskpt, SAEV_Custom_adkcon, SAEV_Custom_intreq, SAER_CPU_getPC()); + }*/ + /* this is very unoptimized. DSKBYTR is used very rarely, so it should not matter. */ + this.DSKBYTR = function(hpos) { + this.update(hpos); + var v = dskbytr_val; + dskbytr_val &= 0x7fff; //ATT ORG ~0x8000; + //if (word == dsksync && cycles_in_range(dsksync_cycles)) { + if (word == dsksync && dsksync_cycles - SAEV_Events_currcycle > 0) { + v |= 0x1000; + if (disk_debug_logging > 1) dumpdisk("disk.DSKBYTR() SYNC"); } - while (floppybits >= floppy[num].trackspeed) { - for (dr = 0; dr < MAX_FLOPPY_DRIVES; dr++) { - if (drives[dr]) { - floppy[dr].mfmpos++; - floppy[dr].mfmpos %= floppy[num].tracklen; - } - } - if (AMIGA.dmaen(DMAF_DSKEN) && dskdmaen == DSKDMA_WRITE && dsklength > 0 && fifo_filled) { - bitoffset++; - bitoffset &= 15; - if (!bitoffset) { - /* fast disk modes, fill the fifo instantly */ - if (AMIGA.config.floppy.speed > SAEV_Config_Floppy_Speed_Original && !fifo_inuse[0] && !fifo_inuse[1] && !fifo_inuse[2]) { - while (!fifo_inuse[2]) { - var w = AMIGA.mem.load16(dskpt); - this.DSKDAT(w); - dskpt += 2; - } - } - if (this.fifostatus() >= 0) { - var w = this.DSKDATR(); - for (dr = 0; dr < MAX_FLOPPY_DRIVES; dr++) { - if (drives[dr]) { - floppy[dr].bigmfmbuf[floppy[dr].mfmpos >> 4] = w; - floppy[dr].bigmfmbuf[(floppy[dr].mfmpos >> 4) + 1] = 0x5555; - floppy[dr].writtento = 1; - } - } - dsklength--; - if (dsklength <= 0) { - this.dmafinished(); - for (dr = 0; dr < MAX_FLOPPY_DRIVES; dr++) { - floppy[dr].writtento = 0; - if (floppy[dr].motoroff) - continue; - if (selected & (1 << dr)) - continue; - floppy[dr].write_data(); - } - } - } - } - } - floppybits -= floppy[num].trackspeed; - } - }; - - this.doupdate_predict = function (startcycle) { - //BUG.info('Disk.doupdate_predict() startcycle %d', startcycle); - var finaleventcycle = AMIGA.playfield.maxhpos << 8; - var finaleventflag = 0; + if (dskdmaen != DSKDMA_OFF && SAEF_Custom_dmaen(SAEC_Custom_DMAF_DSKEN)) + v |= 0x4000; + if (dsklen & 0x4000) + v |= 0x2000; + if (disk_debug_logging > 2) SAEF_log("disk.DSKBYTR() $%04X, hpos %d", v, hpos); for (var dr = 0; dr < MAX_FLOPPY_DRIVES; dr++) { - if (selected & (1 << dr)) + var drv = floppy[dr]; + if (drv.motoroff) continue; - else if (floppy[dr].motoroff || !floppy[dr].trackspeed) - continue; - - var diskevent_flag = 0; - var tword = word; - var countcycle = startcycle + (floppy[dr].floppybitcounter % floppy[dr].trackspeed); - var mfmpos = floppy[dr].mfmpos; - while (countcycle < (AMIGA.playfield.maxhpos << 8)) { - if (floppy[dr].tracktiming[0]) - this.updatetrackspeed(dr, mfmpos); - if (dskdmaen != DSKDMA_WRITE || (dskdmaen == DSKDMA_WRITE && !dma_enable)) { - tword <<= 1; - if (!floppy[dr].is_empty()) { - if (floppy[dr].is_unformatted()) - tword |= ((uaerand() & 0x1000) ? 1 : 0); - else - tword |= floppy[dr].getonebit(mfmpos); + if (!((selected | disabled) & (1 << dr))) { + drv.lastdataacesstrack = drv.cyl * 2 + side; + if (REVOLUTION_DEBUG && !drv.track_access_done) SAEF_log("disk.DSKBYTR()"); + drv.track_access_done = true; + /*if (disk_debug_mode & DISK_DEBUG_PIO) { + if (disk_debug_track < 0 || disk_debug_track == 2 * drv.cyl + side) { + //disk_dma_debugmsg(); + SAEF_log("disk.DSKBYTR () $%04X", v); + //activate_debugger(); + break; } - tword &= 0xffff; - if (tword == dsksync && dsksync != 0) - diskevent_flag |= DISK_WORDSYNC; - } - mfmpos++; - mfmpos %= floppy[dr].tracklen; - if (mfmpos == 0) - diskevent_flag |= (DISK_REVOLUTION << dr); - if (mfmpos == floppy[dr].indexoffset) - diskevent_flag |= DISK_INDEXSYNC; - if (dskdmaen != DSKDMA_WRITE && mfmpos == floppy[dr].skipoffset) { - this.update_jitter(); - var skipcnt = disk_jitter; - while (skipcnt-- > 0) { - mfmpos++; - mfmpos %= floppy[dr].tracklen; - if (mfmpos == 0) - diskevent_flag |= (DISK_REVOLUTION << dr); - if (mfmpos == floppy[dr].indexoffset) - diskevent_flag |= DISK_INDEXSYNC; - } - } - if (diskevent_flag) - break; - countcycle += floppy[dr].trackspeed; - } - if (floppy[dr].tracktiming[0]) - this.updatetrackspeed(dr, floppy[dr].mfmpos); - if (diskevent_flag && countcycle < finaleventcycle) { - finaleventcycle = countcycle; - finaleventflag = diskevent_flag; + }*/ } } + return v; + } - if (finaleventflag && (finaleventcycle >>> 8) < AMIGA.playfield.maxhpos) - AMIGA.events.newevent(EV2_DISK, (finaleventcycle - startcycle) >>> 8, ((finaleventcycle >>> 8) << 8) | finaleventflag); - }; + function DISK_start() { + if (disk_debug_logging > 1) dumpdisk("DSKLEN"); - this.update = function (tohpos) { - //if (tohpos != 227) BUG.info('Disk.update() disk_hpos %f, to hpos %d', disk_hpos / CYCLE_UNIT, tohpos); - var dr; - var cycles; + for (var i = 0; i < 3; i++) fifo_inuse[i] = false; + fifo_filled = 0; + + for (var dr = 0; dr < MAX_FLOPPY_DRIVES; dr++) { + var drv = floppy[dr]; + if (!((selected | disabled) & (1 << dr))) { + var tr = drv.cyl * 2 + side; + var ti = drv.trackdata[tr]; + + if (dskdmaen == DSKDMA_WRITE) { + word = 0; + drv.tracklen = longwritemode ? FLOPPY_WRITE_MAXLEN : FLOPPY_WRITE_LEN() * drv.ddhd * 8 * 2; + drv.trackspeed = get_floppy_speed(); + drv.skipoffset = -1; + updatemfmpos(drv); + } + /* Ugh. A nasty hack. Assume ADF_EXT1 tracks are always read from the start. */ + if (ti.type == TRACK_RAW1) { + drv.mfmpos = 0; + bitoffset = 0; + word = 0; + } + } + drv.floppybitcounter = 0; + } + + dma_enable = (SAEV_Custom_adkcon & 0x400) ? 0 : 1; + if (word == dsksync) + wordsync_detected(true); + } + + /*-----------------------------------------------------------------------*/ + + this.hsync = function() { //DISK_hsync() + for (var dr = 0; dr < MAX_FLOPPY_DRIVES; dr++) { + var drv = floppy[dr]; + if (drv.steplimit) + drv.steplimit--; + if (drv.revolution_check) + drv.revolution_check--; + + if (drv.dskready_down_time > 0) + drv.dskready_down_time--; + /* emulate drive motor turn on time */ + if (drv.dskready_up_time > 0 && !drive_empty(drv)) { + drv.dskready_up_time--; + if (drv.dskready_up_time == 0 && !drv.motoroff) + drv.dskready = true; + } + /* delay until new disk image is inserted */ + if (drv.dskchange_time > 0) { + drv.dskchange_time--; + if (drv.dskchange_time == 0) { + drive_insert(drv, SAEV_config, dr, drv.newfile, false); + if (disk_debug_logging > 0) SAEF_log("disk.hsync() delayed insert, drive %d, image '%s', size %d", dr, drv.newfile.name, drv.newfile.size); + update_drive_gui(dr, false); + } + } + } + if (indexdecay) + indexdecay--; + if (linecounter) { + linecounter--; + if (!linecounter) + disk_dmafinished(); + return; + } + this.update(SAER.playfield.get_maxhpos()); + + // show insert disk in df0: when booting + if (initial_disk_statusline) { + initial_disk_statusline = false; + update_disk_statusline(0); + } + } + + /*-----------------------------------------------------------------------*/ + + this.update = function(tohpos) { //DISK_update() + var dr, cycles; if (disk_hpos < 0) { disk_hpos = -disk_hpos; return; } + cycles = (tohpos << 8) - disk_hpos; + /*#if 0 + if (tohpos == 228) write_log (_T("x")); + if (tohpos != SAER.playfield.get_maxhpos() || cycles / 256 != SAER.playfield.get_maxhpos()) write_log (_T("%d %d %d\n"), tohpos, cycles / 256, disk_hpos / 256); + #endif*/ if (cycles <= 0) return; - disk_hpos += cycles; - if (disk_hpos >= (AMIGA.playfield.maxhpos << 8)) - disk_hpos %= (1 << 8); + if (disk_hpos >= (SAER.playfield.get_maxhpos() << 8)) + disk_hpos %= 1 << 8; for (dr = 0; dr < MAX_FLOPPY_DRIVES; dr++) { - if (floppy[dr].motoroff || !floppy[dr].tracklen || !floppy[dr].trackspeed) + var drv = floppy[dr]; + + if (drv.motoroff || !drv.tracklen || !drv.trackspeed) continue; - floppy[dr].floppybitcounter += cycles; - if (selected & (1 << dr)) { - floppy[dr].mfmpos += Math.floor(floppy[dr].floppybitcounter / floppy[dr].trackspeed); - floppy[dr].mfmpos %= floppy[dr].tracklen; - floppy[dr].floppybitcounter %= floppy[dr].trackspeed; + drv.floppybitcounter += cycles; + if ((selected | disabled) & (1 << dr)) { + drv.mfmpos += Math.floor(drv.floppybitcounter / drv.trackspeed); + drv.mfmpos %= drv.tracklen; + drv.floppybitcounter %= drv.trackspeed; continue; } - if (floppy[dr].diskfile) - floppy[dr].fill_bigbuf(0); - floppy[dr].mfmpos %= floppy[dr].tracklen; + if (drv.diskfile) + drive_fill_bigbuf(drv, false); + drv.mfmpos %= drv.tracklen; } - var didaccess = 0; + var didaccess = false; for (dr = 0; dr < MAX_FLOPPY_DRIVES; dr++) { - if (selected & (1 << dr)) + var drv = floppy[dr]; + if (drv.motoroff || !drv.trackspeed) continue; - else if (floppy[dr].motoroff || !floppy[dr].trackspeed) + if ((selected | disabled) & (1 << dr)) continue; /* write dma and wordsync enabled: read until wordsync match found */ if (dskdmaen == DSKDMA_WRITE && dma_enable) - this.update_write(dr, floppy[dr].floppybitcounter); + disk_doupdate_write(drv, drv.floppybitcounter); else - this.update_read(dr, floppy[dr].floppybitcounter); + disk_doupdate_read(drv, drv.floppybitcounter); - floppy[dr].floppybitcounter %= floppy[dr].trackspeed; - didaccess = 1; + drv.floppybitcounter %= drv.trackspeed; + didaccess = true; } /* no floppy selected but read dma */ if (!didaccess && dskdmaen == DSKDMA_READ) - this.update_read_nothing(cycles); + disk_doupdate_read_nothing (cycles); /* instantly finish dma if dsklen==0 and wordsync detected */ if (dskdmaen != DSKDMA_OFF && dma_enable && dsklength2 == 0 && dsklength == 0) - this.dmafinished(); + disk_dmafinished(); - this.doupdate_predict(disk_hpos); - }; - - this.dma_debugmsg = function () { - BUG.info('Disk.dma_debugmsg() LEN=%04x (%d) SYNC=%04x PT=%08x ADKCON=%04x', dsklength, dsklength, (AMIGA.adkcon & 0x400) ? dsksync : 0xffff, dskpt, AMIGA.adkcon); - }; - - this.start = function () { - fifo_filled = false; - for (var i = 0; i < 3; i++) - fifo_inuse[i] = 0; + disk_doupdate_predict(disk_hpos); + } - for (var dr = 0; dr < MAX_FLOPPY_DRIVES; dr++) { - if (!(selected & (1 << dr))) { - if (dskdmaen == DSKDMA_WRITE) { - floppy[dr].tracklen = LONGWRITEMODE ? FLOPPY_WRITE_MAXLEN : (AMIGA.config.video.ntsc ? 6399 : 6334) * floppy[dr].ddhd * 8 * 2; - floppy[dr].trackspeed = get_floppy_speed(); - floppy[dr].skipoffset = -1; - floppy[dr].updatemfmpos(); - } - - var tr = floppy[dr].cyl * 2 + this.side; - if (floppy[dr].trackdata[tr].type == TRACK_RAW1) { - floppy[dr].mfmpos = 0; - bitoffset = 0; - } - } - floppy[dr].floppybitcounter = 0; - } - dma_enable = (AMIGA.adkcon & 0x400) ? false : true; - }; - - this.check_change = function () { - //if (currprefs.floppy_speed != changed_prefs.floppy_speed) currprefs.floppy_speed = changed_prefs.floppy_speed; - /*for (var i = 0; i < MAX_FLOPPY_DRIVES; i++) { - if (currprefs.floppyslots[i].dfxtype != changed_prefs.floppyslots[i].dfxtype) { - currprefs.floppyslots[i].dfxtype = changed_prefs.floppyslots[i].dfxtype; - floppy[i].reset(); - } - }*/ - }; - - this.vsync = function () { - this.check_change(); - - for (var i = 0; i < MAX_FLOPPY_DRIVES; i++) { - //if (drv->dskchange_time == 0 && _tcscmp (currprefs.floppyslots[i].df, changed_prefs.floppyslots[i].df)) this.insert(i, changed_prefs.floppyslots[i].df); - floppy[i].vsync(); - } - }; - - this.hsync = function () { - for (var dr = 0; dr < MAX_FLOPPY_DRIVES; dr++) { - if (floppy[dr].steplimit) - floppy[dr].steplimit--; - } - if (indexdecay) - indexdecay--; - if (linecounter) { - if (!(--linecounter)) - this.dmafinished(); - return; - } - this.update(AMIGA.playfield.maxhpos); - }; - - this.update_adkcon = function (v) { - var vold = AMIGA.adkcon; - var vnew = AMIGA.adkcon; + this.update_adkcon = function(hpos, v) { //DISK_update_adkcon() + var vold = SAEV_Custom_adkcon; + var vnew = SAEV_Custom_adkcon; if (v & 0x8000) - vnew |= v & 0x7FFF; + vnew |= v & 0x7FFF; else vnew &= ~v; - if ((vnew & 0x400) && !(vold & 0x400)) bitoffset = 0; - }; - - this.motordelay_func = function (unit) { - //BUG.info('Disk.motordelay_func(%d)', unit); - floppy[unit].motordelay = false; - }; - - this.DSKLEN = function (v, hpos) { - //BUG.info('Disk.DSKLEN() $%04x', v); + } + + /*-----------------------------------------------------------------------*/ + + this.DSKLEN = function(v, hpos) { var dr, prev = dsklen; + var noselected = 0; + var motormask; this.update(hpos); - if ((v & 0x8000) && (dsklen & 0x8000)) { + dsklen = v; + dsklength2 = dsklength = dsklen & 0x3fff; + + if ((v & 0x8000) && (prev & 0x8000)) { + if (dskdmaen == DSKDMA_READ) { + // update only currently active DMA length, don't change DMA state + SAEF_warn("disk.DSKLEN() read DMA length rewrite %d -> %d ($%04x), PC=$%x", prev & 0x3fff, v & 0x3fff, v, SAER_CPU_getPC()); + return; + } dskdmaen = DSKDMA_READ; - this.start(); + DISK_start(); } if (!(v & 0x8000)) { if (dskdmaen != DSKDMA_OFF) { - if (dskdmaen == DSKDMA_READ) - BUG.info('Disk.DSKLEN() warning: Disk read DMA aborted, %d words left', dsklength); - else if (dskdmaen == DSKDMA_WRITE) { - BUG.info('Disk.DSKLEN() warning: Disk write DMA aborted, %d words left', dsklength); + /* Megalomania and Knightmare does this */ + if (disk_debug_logging > 0 && dskdmaen == DSKDMA_READ) + SAEF_warn("disk.DSKLEN() read DMA aborted, %d words left, PC=$%x", dsklength, SAER_CPU_getPC()); + if (dskdmaen == DSKDMA_WRITE) { + SAEF_warn("disk.DSKLEN() write DMA aborted, %d words left, PC=$%x", dsklength, SAER_CPU_getPC()); + // did program write something that needs to be stored to file? for (dr = 0; dr < MAX_FLOPPY_DRIVES; dr++) { - if (floppy[dr].writtento) floppy[dr].write_data(); + var drv2 = floppy[dr]; + if (!drv2.writtento) + continue; + drive_write_data(drv2); } } dskdmaen = DSKDMA_OFF; } } - dsklen = v; - dsklength2 = dsklength = dsklen & 0x3fff; if (dskdmaen == DSKDMA_OFF) return; + if (dsklength == 0 && dma_enable) { - this.dmafinished(); + disk_dmafinished(); return; } + if ((v & 0x4000) && (prev & 0x4000)) { if (dsklength == 0) return; if (dsklength == 1) { - this.dmafinished(); + disk_dmafinished(); + return; + } + if (dskdmaen == DSKDMA_WRITE) { + SAEF_warn("disk.DSKLEN() write DMA length rewrite %d -> %d, PC=$%x", prev & 0x3fff, v & 0x3fff, SAER_CPU_getPC()); return; } dskdmaen = DSKDMA_WRITE; - this.start(); + DISK_start(); } - var motormask = 0; for (dr = 0; dr < MAX_FLOPPY_DRIVES; dr++) { - floppy[dr].writtento = 0; - if (floppy[dr].motoroff) + var drv = floppy[dr]; + if (drv.motoroff) + continue; + if (selected & (1 << dr)) + continue; + if (dskdmaen == DSKDMA_READ) { + drv.lastdataacesstrack = drv.cyl * 2 + side; + drv.track_access_done = true; + if (REVOLUTION_DEBUG) SAEF_log("disk.DSKLEN() DMA"); + } + } + + /*if (((disk_debug_mode & DISK_DEBUG_DMA_READ) && dskdmaen == DSKDMA_READ) || + ((disk_debug_mode & DISK_DEBUG_DMA_WRITE) && dskdmaen == DSKDMA_WRITE)) + { + for (dr = 0; dr < MAX_FLOPPY_DRIVES; dr++) { + var drv = floppy[dr]; + if (drv.motoroff) + continue; + if (!(selected & (1 << dr))) { + if (disk_debug_track < 0 || disk_debug_track == 2 * drv.cyl + side) { + //disk_dma_debugmsg(); + //activate_debugger (); + break; + } + } + } + }*/ + + motormask = 0; + for (dr = 0; dr < MAX_FLOPPY_DRIVES; dr++) { + var drv = floppy[dr]; + drv.writtento = 0; + if (drv.motoroff) continue; motormask |= 1 << dr; if ((selected & (1 << dr)) == 0) break; } - var noselected = dr == 4; + if (dr == 4) { + if (!amax_enabled) + SAEF_log("disk.DSKLEN() %s DMA started, drvmask=$%x motormask=$%x PC=$%08x", dskdmaen == DSKDMA_WRITE ? "write" : "read", selected ^ 15, motormask, SAER_CPU_getPC()); + noselected = 1; + } else { + if (disk_debug_logging > 0) { + SAEF_log("disk.DSKLEN() %s DMA started, drvmask=%x track %d mfmpos %d dmaen=%d PC=$%08X", dskdmaen == DSKDMA_WRITE ? "write" : "read", selected ^ 15, floppy[dr].cyl * 2 + side, floppy[dr].mfmpos, dma_enable, SAER_CPU_getPC()); + //disk_dma_debugmsg(); + } + } + + for (dr = 0; dr < MAX_FLOPPY_DRIVES; dr++) + update_drive_gui(dr, false); /* Try to make floppy access from Kickstart faster. */ if (dskdmaen != DSKDMA_READ && dskdmaen != DSKDMA_WRITE) return; - /* no turbo mode if any selected drive has non-standard ADF */ for (dr = 0; dr < MAX_FLOPPY_DRIVES; dr++) { + var drv = floppy[dr]; if (selected & (1 << dr)) continue; - if (floppy[dr].filetype != ADF_NORMAL) + if (drv.filetype != ADF_NORMAL && drv.filetype != ADF_KICK && drv.filetype != ADF_SKICK) break; } - if (dr < MAX_FLOPPY_DRIVES) + if (dr < MAX_FLOPPY_DRIVES) /* no turbo mode if any selected drive has non-standard ADF */ return; - { - var done = false; + var done = 0; for (dr = 0; dr < MAX_FLOPPY_DRIVES; dr++) { - var pos, i; + var i, drv = floppy[dr]; + if (drv.motoroff) + continue; + if (!drv.useturbo && SAEV_config.floppy.speed > 0) + continue; if (selected & (1 << dr)) continue; - else if (floppy[dr].motoroff) - continue; - else if (!floppy[dr].useturbo && AMIGA.config.floppy.speed != SAEV_Config_Floppy_Speed_Turbo) - continue; - pos = floppy[dr].mfmpos & ~15; - floppy[dr].fill_bigbuf(0); + var pos = drv.mfmpos & ~15; + drive_fill_bigbuf(drv, false); - if (dskdmaen == DSKDMA_READ) { //TURBO read - if (AMIGA.adkcon & 0x400) { - for (i = 0; i < floppy[dr].tracklen; i += 16) { + if (dskdmaen == DSKDMA_READ) { /* TURBO read */ + if (SAEV_Custom_adkcon & 0x400) { + for (i = 0; i < drv.tracklen; i += 16) { pos += 16; - pos %= floppy[dr].tracklen; - if (floppy[dr].bigmfmbuf[pos >> 4] == dsksync) { + pos %= drv.tracklen; + if (drv.bigmfmbuf[pos >> 4] == dsksync) { + /* must skip first disk sync marker */ pos += 16; - pos %= floppy[dr].tracklen; + pos %= drv.tracklen; break; } } - if (i >= floppy[dr].tracklen) + if (i >= drv.tracklen) return; } while (dsklength-- > 0) { - AMIGA.mem.store16(dskpt, floppy[dr].bigmfmbuf[pos >> 4]); + SAER_Memory_chipPut16_indirect(dskpt, drv.bigmfmbuf[pos >> 4]); dskpt += 2; pos += 16; - pos %= floppy[dr].tracklen; + pos %= drv.tracklen; } - AMIGA.INTREQ(INT_DSKSYN); - done = true; - } else if (dskdmaen == DSKDMA_WRITE) { //TURBO write + drv.mfmpos = pos; + SAER.custom.INTREQ(SAEC_Custom_INTF_SETCLR | SAEC_Custom_INTF_DSKSYN); + done = 2; + } else if (dskdmaen == DSKDMA_WRITE) { /* TURBO write */ for (i = 0; i < dsklength; i++) { - floppy[dr].bigmfmbuf[pos >> 4] = AMIGA.mem.load16(dskpt + i * 2); + var w = SAER_Memory_chipGet16_indirect(dskpt + i * 2); + drv.bigmfmbuf[pos >> 4] = w; + if (amax_enabled) + amax_diskwrite(w); + pos += 16; - pos %= floppy[dr].tracklen; + pos %= drv.tracklen; } - floppy[dr].write_data(); - done = true; + drv.mfmpos = pos; + drive_write_data(drv); + done = 2; } } if (!done && noselected) { + var bits = -1; while (dsklength-- > 0) { - if (dskdmaen == DSKDMA_WRITE) - AMIGA.mem.load16(dskpt); - else - AMIGA.mem.store16(dskpt, 0); + if (dskdmaen == DSKDMA_WRITE) { + var w = SAER_Memory_chipGet16_indirect(dskpt); + if (amax_enabled) { + amax_diskwrite(w); + if (w) { + for (var i = 0; i < 16; i++) { + if (w & (1 << i)) + bits++; + } + } + } + } else + SAER_Memory_chipPut16_indirect(dskpt, 0); + dskpt += 2; } - AMIGA.INTREQ(INT_DSKSYN); - done = true; + if (bits == 0) { + //AMAX speedup hack + done = 1; + } else { + SAER.custom.INTREQ(SAEC_Custom_INTF_SETCLR | SAEC_Custom_INTF_DSKSYN); + done = 2; + } } + if (done) { - linecounter = 2; + linecounter = done; dskdmaen = DSKDMA_OFF; + return; } } - }; - - this.DSKBYTR = function (hpos) { - this.update(hpos); + } - var v = dskbytr_val; - dskbytr_val &= ~0x8000; - if (word == dsksync && AMIGA.events.cycles_in_range(dsksync_cycles)) - v |= 0x1000; - if (dskdmaen != DSKDMA_OFF && AMIGA.dmaen(DMAF_DSKEN)) - v |= 0x4000; - if (dsklen & 0x4000) - v |= 0x2000; - - //BUG.info('Disk.DSKBYTR() %x', v); - return v; - }; - - this.DSKSYNC = function (v, hpos) { + this.DSKSYNC = function(hpos, v) { if (v == dsksync) return; - this.update(hpos); dsksync = v; - }; + } - this.DSKDAT = function (v) { + /*function iswrite() { + return dskdmaen == DSKDMA_WRITE; + }*/ + this.DSKDAT = function(v) { if (fifo_inuse[2]) { - BUG.info('Disk.DSKDAT() FIFO overflow!'); + SAEF_warn("disk.DSKDAT() FIFO overflow!"); return; } fifo_inuse[2] = fifo_inuse[1]; fifo[2] = fifo[1]; fifo_inuse[1] = fifo_inuse[0]; fifo[1] = fifo[0]; + //fifo_inuse[0] = iswrite() ? 2 : 1; fifo_inuse[0] = dskdmaen == DSKDMA_WRITE ? 2 : 1; fifo[0] = v; - fifo_filled = true; - }; - - this.DSKDATR = function () { + fifo_filled = 1; + } + this.DSKDATR = function() { var i, v = 0; for (i = 2; i >= 0; i--) { @@ -1620,43 +3581,929 @@ function Disk() { } } if (i < 0) - BUG.info('Disk.DSKDATR() FIFO underflow!'); + SAEF_warn("disk.DSKDATR() FIFO underflow!"); else if (dskdmaen > 0 && dskdmaen < 3 && dsklength <= 0 && this.fifostatus() < 0) - this.dmafinished(); + disk_dmafinished(); - //BUG.info('Disk.DSKDATR() %x', v); return v; - }; + } - this.DSKPTH = function (v) { + this.DSKPTH = function(v) { + v = v & (SAEV_config.chipset.mask == SAEC_Config_Chipset_Mask_OCS ? 7 : 31); //OWN dskpt = ((v << 16) | (dskpt & 0xffff)) >>> 0; - }; - - this.DSKPTL = function (v) { + } + this.DSKPTL = function(v) { dskpt = ((dskpt & 0xffff0000) | v) >>> 0; - }; - - this.getpt = function () { - var pt = dskpt; - dskpt += 2; - return pt; - }; + } - this.dmal = function() { + /*-----------------------------------------------------------------------*/ + + this.dmal = function() { //disk_dmal() var dmal = 0; - if (dskdmaen != DSKDMA_OFF) { - if (dskdmaen == DSKDMA_WRITE) { + if (dskdmaen) { + if (dskdmaen == 3) { dmal = (1 + 2) * (fifo_inuse[0] ? 1 : 0) + (4 + 8) * (fifo_inuse[1] ? 1 : 0) + (16 + 32) * (fifo_inuse[2] ? 1 : 0); dmal ^= 63; if (dsklength == 2) dmal &= ~(16 + 32); if (dsklength == 1) dmal &= ~(16 + 32 + 4 + 8); - } else { - dmal = 16 * (fifo_inuse[0] ? 1 : 0) + 4 * (fifo_inuse[1] ? 1 : 0) + (fifo_inuse[2] ? 1 : 0); - } + } else + dmal = 16 * (fifo_inuse[0] ? 1 : 0) + 4 * (fifo_inuse[1] ? 1 : 0) + 1 * (fifo_inuse[2] ? 1 : 0); } return dmal; } -} + this.getpt = function() { //disk_getpt() + var pt = dskpt; + dskpt += 2; + return pt; + } + /*-----------------------------------------------------------------------*/ + + this.setup = function() { //DISK_init() + for (var dr = MAX_FLOPPY_DRIVES - 1; dr >= 0; dr--) { + var drv = floppy[dr]; + /* reset all drive types to 3.5 DD */ + drive_settype_id(drv); + if (!drive_insert(drv, SAEV_config, dr, SAEV_config.floppy.drive[dr].file, false)) + this.eject(dr); + } + if (drive_empty(floppy[0])) //if (disk_empty(0)) + SAEF_log("disk.setup() No disk in drive DF0."); + + amax_init(); + } + this.cleanup = function() { //DISK_free() + for (var dr = 0; dr < MAX_FLOPPY_DRIVES; dr++) { + var drv = floppy[dr]; + drive_image_free(drv); + } + } + + this.reset = function() { //DISK_reset() + disk_hpos = 0; + dskdmaen = 0; + disabled = 0; + //disk_info_data.clr(); //memset(&disk_info_data, 0, sizeof disk_info_data); + for (var dr = MAX_FLOPPY_DRIVES - 1; dr >= 0; dr--) + reset_drive(dr); + + initial_disk_statusline = true; + setamax(); + + //OWN + linecounter = 0; + warned_ext2 = false; + warned_trackspeed = 0; + driveNames = ["","","",""]; + } + + /*-----------------------------------------------------------------------*/ + /* SECT disk tools */ + /*-----------------------------------------------------------------------*/ + + const FS_FLOPPY_BLOCKSIZE = 512; + const FS_OFS_DATABLOCKSIZE = 488; + const FS_EXTENSION_BLOCKS = 72; + const FS_FLOPPY_TOTALBLOCKS = 1760; + //const FS_FLOPPY_RESERVED = 2; + + const bootblock_ofs = [ + 0x44,0x4f,0x53,0x00,0xc0,0x20,0x0f,0x19,0x00,0x00,0x03,0x70,0x43,0xfa,0x00,0x18, + 0x4e,0xae,0xff,0xa0,0x4a,0x80,0x67,0x0a,0x20,0x40,0x20,0x68,0x00,0x16,0x70,0x00, + 0x4e,0x75,0x70,0xff,0x60,0xfa,0x64,0x6f,0x73,0x2e,0x6c,0x69,0x62,0x72,0x61,0x72, + 0x79 + ]; + const bootblock_ffs = [ + 0x44, 0x4F, 0x53, 0x01, 0xE3, 0x3D, 0x0E, 0x72, 0x00, 0x00, 0x03, 0x70, 0x43, 0xFA, 0x00, 0x3E, + 0x70, 0x25, 0x4E, 0xAE, 0xFD, 0xD8, 0x4A, 0x80, 0x67, 0x0C, 0x22, 0x40, 0x08, 0xE9, 0x00, 0x06, + 0x00, 0x22, 0x4E, 0xAE, 0xFE, 0x62, 0x43, 0xFA, 0x00, 0x18, 0x4E, 0xAE, 0xFF, 0xA0, 0x4A, 0x80, + 0x67, 0x0A, 0x20, 0x40, 0x20, 0x68, 0x00, 0x16, 0x70, 0x00, 0x4E, 0x75, 0x70, 0xFF, 0x4E, 0x75, + 0x64, 0x6F, 0x73, 0x2E, 0x6C, 0x69, 0x62, 0x72, 0x61, 0x72, 0x79, 0x00, 0x65, 0x78, 0x70, 0x61, + 0x6E, 0x73, 0x69, 0x6F, 0x6E, 0x2E, 0x6C, 0x69, 0x62, 0x72, 0x61, 0x72, 0x79, 0x00, 0x00, 0x00 + ]; + + /*---------------------------------*/ + + function disk_checksum(p,po, c,co) { + var cs = 0; + for (var i = 0; i < FS_FLOPPY_BLOCKSIZE; i += 4) { + cs += ((p[po + i] << 24) | (p[po + i + 1] << 16) | (p[po + i + 2] << 8) | p[po + i + 3]) >>> 0; + if (cs > 0xffffffff) cs -= 0x100000000; //OWN + } + cs = -cs; + if (cs < 0) cs += 0x100000000; //OWN + + if (c !== null) { + c[co ] = cs >>> 24; + c[co + 1] = (cs >>> 16) & 0xff; + c[co + 2] = (cs >>> 8) & 0xff; + c[co + 3] = cs & 0xff; + } + //SAEF_log('disk.disk_checksum() 0x%08X', cs); + return cs; + } + + function disk_date(p,po) { + var tv = {}; + SAEF_gettimeofday(tv, null); + //tv.tv_sec -= _timezone; + var amiga = { days:0, mins:0, ticks:0 }; + SAEF_timeval_to_amiga(tv, amiga, 50); + if (amiga.days == prev_days && amiga.mins == prev_mins && amiga.ticks == prev_ticks) { + amiga.ticks++; + if (amiga.ticks >= 50 * 60) { + amiga.ticks = 0; + amiga.mins++; + if (amiga.mins >= 24 * 60) + amiga.days++; + } + } + prev_days = amiga.days; + prev_mins = amiga.mins; + prev_ticks = amiga.ticks; + p[po + 0] = amiga.days >>> 24; + p[po + 1] = (amiga.days >>> 16) & 0xff; + p[po + 2] = (amiga.days >>> 8) & 0xff; + p[po + 3] = amiga.days & 0xff; + p[po + 4] = amiga.mins >>> 24; + p[po + 5] = (amiga.mins >>> 16) & 0xff; + p[po + 6] = (amiga.mins >>> 8) & 0xff; + p[po + 7] = amiga.mins & 0xff; + p[po + 8] = amiga.ticks >>> 24; + p[po + 9] = (amiga.ticks >>> 16) & 0xff; + p[po + 10] = (amiga.ticks >>> 8) & 0xff; + p[po + 11] = amiga.ticks & 0xff; + } + + /*---------------------------------*/ + /* DiskInfo */ + + function load_track(num, cyl, side, sectable) { + var drv = floppy[num]; + var oldcyl = drv.cyl; + var oldside = side; + var drvsec = { value:0 }; + drv.cyl = cyl; + side = 0; + drv.buffered_cyl = -1; + drive_fill_bigbuf(drv, true); + decode_buffer(drv.bigmfmbuf, drv.cyl, 11, drv.ddhd, drv.filetype, drvsec, sectable, true); + drv.cyl = oldcyl; + side = oldside; + drv.buffered_cyl = -1; + } + function examine_image(p, num, di) { //DISK_examine_image() + var drv = floppy[num]; + var dos, crc, tmpcrc, crc2; //u32 + var wasdelayed = drv.dskchange_time; + var drvsec = { value:0 }; + var sectable = new Uint8Array(MAX_SECTORS); + var i, v = 0; //u32 + + var ret = 0; + di.clr(); //memset(di, 0, sizeof (struct diskinfo)); + di.unreadable = true; + var oldcyl = drv.cyl; + var oldside = side; + drv.cyl = 0; + side = 0; + if (!drive_insert(drv, p, num, p.floppy.drive[num].file, true) || drv.diskfile === null) { + drv.cyl = oldcyl; + side = oldside; + return 1; + } + //di.crc32 = SAEF_ZFile_crc32(drv.diskfile); + di.crc32 = drv.crc32; + di.unreadable = false; + decode_buffer(drv.bigmfmbuf, drv.cyl, 11, drv.ddhd, drv.filetype, drvsec, sectable, true); + di.hd = drv.ddhd == 2; + drv.cyl = oldcyl; + side = oldside; + if (sectable[0] == 0 || sectable[1] == 0) { + ret = 2; + //goto end2; + } + if (ret != 2) { + crc = crc2 = 0; + for (i = 0; i < 1024; i += 4) { + di.bootblock[i ] = writebuffer[i ]; + di.bootblock[i + 1] = writebuffer[i + 1]; + di.bootblock[i + 2] = writebuffer[i + 2]; + di.bootblock[i + 3] = writebuffer[i + 3]; + var v = ((writebuffer[i] << 24) | (writebuffer[i + 1] << 16) | (writebuffer[i + 2] << 8) | writebuffer[i + 3]) >>> 0; + if (i == 0) + dos = v; + else if (i == 4) { + crc2 = v; + v = 0; + } + //if (crc + v < crc) crc++; + tmpcrc = crc + v; if (tmpcrc > 0xffffffff) tmpcrc -= 0x100000000; + if (tmpcrc < crc) { + crc++; if (crc > 0xffffffff) crc -= 0x100000000; + } + crc += v; if (crc > 0xffffffff) crc -= 0x100000000; + } + if (dos == 0x4b49434b) { /* KICK */ + ret = 10; + //goto end; + } + if (ret != 10) { + di.bootblockChecksum = crc2; + crc = (crc ^ 0xffffffff) >>> 0; + if (crc != crc2) { + ret = 3; + //goto end; + } + if (ret != 3) { + di.bootblockChecksumValid = true; + writebuffer[4] = writebuffer[5] = writebuffer[6] = writebuffer[7] = 0; + if (SAEF_crc32(writebuffer,0, 0x31) == 0xae5e282c) + di.bootblockType = 1; + + if (dos == 0x444f5300) + ret = 10; + else if (dos == 0x444f5301 || dos == 0x444f5302 || dos == 0x444f5303) + ret = 11; + else if (dos == 0x444f5304 || dos == 0x444f5305 || dos == 0x444f5306 || dos == 0x444f5307) + ret = 12; + else + ret = 4; + + v = SAEF_crc32(writebuffer,8, 0x5c - 8); + if (ret >= 10 && v == 0xe158ca4b) + di.bootblockType = 2; + } + } + //end: + load_track(num, 40, 0, sectable); + if (sectable[0]) { + if (!disk_checksum(writebuffer,0, null,0) && + writebuffer[0] == 0 && writebuffer[1] == 0 && writebuffer[2] == 0 && writebuffer[3] == 2 && + writebuffer[508] == 0 && writebuffer[509] == 0 && writebuffer[510] == 0 && writebuffer[511] == 1 + ) { + + /*writebuffer[512 - 20 * 4 + 1 + writebuffer[512 - 20 * 4]] = 0; + TCHAR *n = au((const char*)(writebuffer + 512 - 20 * 4 + 1)); + if (_tcslen (n) >= sizeof (di.diskname)) n[sizeof (di.diskname) - 1] = 0; + di.diskname = n; + xfree(n);*/ + var len = writebuffer[512 - 20 * 4]; //BSTR + var off = 512 - 20 * 4 + 1; + var n = ""; + while (--len >= 0) n += String.fromCharCode(writebuffer[off++]); + di.diskname = n; + } + } + } + //end2: + drive_image_free(drv); + if (wasdelayed > 1) { + drive_eject(drv); + SAEV_config.floppy.drive[num].file.clr(); + drv.dskchange_time = wasdelayed; + SAER.disk.insert(num, drv.newfile); + } + return ret; + } + this.examine = function(di, num) { + var ret = examine_image(SAEV_config, num, di); + if (ret != 1) + return SAEE_None; + + return SAEE_Internal; //FIX better error + } + + /*---------------------------------*/ + /* EXE -> ADF */ + + function writeimageblock(dst, sector, offset) { + SAEF_ZFile_fseek(dst, offset, SEEK_SET); + SAEF_ZFile_fwrite(sector,0, FS_FLOPPY_BLOCKSIZE, 1, dst); + } + function dirhash(name) { + name = name.toUpperCase(); + var hash = name.length; //u32 + for (var i = 0; i < name.length; i++) { + hash = hash * 13; + hash = hash + name.charCodeAt(i); + hash = hash & 0x7ff; + } + hash = hash % ((FS_FLOPPY_BLOCKSIZE >> 2) - 56); + //SAEF_log("disk.dirhash() %X", hash); + return hash; + } + function createbootblock(sector, bootable) { + //memset(sector, 0, FS_FLOPPY_BLOCKSIZE); + SAEF_memset(sector,0, 0, FS_FLOPPY_BLOCKSIZE); + if (bootable) { + //memcpy(sector, bootblock_ofs, sizeof bootblock_ofs); + sector.set(bootblock_ofs); + } else { + //memcpy(sector, "DOS", 3); + sector.set(SAEF_String2Array("DOS")); + } + } + function createrootblock(sector, disk_name) { + var dn = disk_name; + if (dn.length > 30) + dn = dn.substr(0, 30); + dn2 = dn; + if (dn2.length == 0) + dn2 = "empty"; + //memset(sector, 0, FS_FLOPPY_BLOCKSIZE); + SAEF_memset(sector,0, 0, FS_FLOPPY_BLOCKSIZE); + sector[0+3] = 2; + sector[12+3] = 0x48; + sector[312] = sector[313] = sector[314] = sector[315] = 0xff; + sector[316+2] = 881 >> 8; + sector[316+3] = 881 & 255; + sector[432] = dn2.length; sector.set(SAEF_String2Array(dn2), 433); //BSTR + sector[508 + 3] = 1; + disk_date(sector,420); + //memcpy(sector + 472, sector + 420, 3 * 4); + //memcpy(sector + 484, sector + 420, 3 * 4); + SAEF_memcpy(sector,472, sector,420, 3 * 4); + SAEF_memcpy(sector,484, sector,420, 3 * 4); + //sector.copyWithin(472, 420, 420 + 3 * 4); + //sector.copyWithin(484, 420, 420 + 3 * 4); + } + function getblock(bitmap, prev) { + var i = prev.block; + while (bitmap[i] != 0xff) { + if (bitmap[i] == 0) { + bitmap[i] = 1; + prev.block = i; + return i; + } + i++; + } + i = 0; + while (bitmap[i] != 0xff) { + if (bitmap[i] == 0) { + bitmap[i] = 1; + prev.block = i; + return i; + } + i++; + } + return -1; + } + function pl(sector, offset, v) { + sector[offset + 0] = v >>> 24; + sector[offset + 1] = (v >>> 16) & 0xff; + sector[offset + 2] = (v >>> 8) & 0xff; + sector[offset + 3] = v & 0xff; + } + function createdirheaderblock(sector, parent, filename, bitmap, prevblock) { + var block = getblock(bitmap, prevblock); + + //memset(sector, 0, FS_FLOPPY_BLOCKSIZE); + SAEF_memset(sector,0, 0, FS_FLOPPY_BLOCKSIZE); + pl(sector, 0, 2); + pl(sector, 4, block); + disk_date(sector, 512 - 92); + sector[512 - 80] = filename.length; sector.set(SAEF_String2Array(filename), 512 - 79); //BSTR + pl(sector, 512 - 12, parent); + pl(sector, 512 - 4, 2); + return block; + } + function createfileheaderblock(z, sector, parent, filename, src, bitmap, prevblock) { + var sector2 = new Uint8Array(FS_FLOPPY_BLOCKSIZE); + var sector3 = new Uint8Array(FS_FLOPPY_BLOCKSIZE); + var block = getblock(bitmap, prevblock); + var datablock = getblock(bitmap, prevblock); + var datasec = 1; + var headerextension = 1; + + SAEF_ZFile_fseek(src, 0, SEEK_END); + var size = SAEF_ZFile_ftell(src); + SAEF_ZFile_fseek(src, 0, SEEK_SET); + var extensions = Math.floor((size + FS_OFS_DATABLOCKSIZE - 1) / FS_OFS_DATABLOCKSIZE); + + //memset(sector, 0, FS_FLOPPY_BLOCKSIZE); + SAEF_memset(sector,0, 0, FS_FLOPPY_BLOCKSIZE); + pl(sector, 0, 2); + pl(sector, 4, block); + pl(sector, 8, extensions > FS_EXTENSION_BLOCKS ? FS_EXTENSION_BLOCKS : extensions); + pl(sector, 16, datablock); + pl(sector, FS_FLOPPY_BLOCKSIZE - 188, size); + disk_date(sector,FS_FLOPPY_BLOCKSIZE - 92); + sector[FS_FLOPPY_BLOCKSIZE - 80] = filename.length; sector.set(SAEF_String2Array(filename), FS_FLOPPY_BLOCKSIZE - 79); //BSTR + pl(sector, FS_FLOPPY_BLOCKSIZE - 12, parent); + pl(sector, FS_FLOPPY_BLOCKSIZE - 4, -3 >>> 0); + var extensioncounter = 0; + var extensionblock = 0; + + while (size > 0) { + var datablock2 = datablock; + var extensionblock2 = extensionblock; + if (extensioncounter == FS_EXTENSION_BLOCKS) { + extensioncounter = 0; + extensionblock = getblock(bitmap, prevblock); + if (datasec > FS_EXTENSION_BLOCKS + 1) { + pl(sector3, 8, FS_EXTENSION_BLOCKS); + pl(sector3, FS_FLOPPY_BLOCKSIZE - 8, extensionblock); + pl(sector3, 4, extensionblock2); + disk_checksum(sector3,0, sector3,20); + writeimageblock(z, sector3, extensionblock2 * FS_FLOPPY_BLOCKSIZE); + } else + pl(sector, 512 - 8, extensionblock); + + //memset(sector3, 0, FS_FLOPPY_BLOCKSIZE); + SAEF_memset(sector3,0, 0, FS_FLOPPY_BLOCKSIZE); + pl(sector3, 0, 16); + pl(sector3, FS_FLOPPY_BLOCKSIZE - 12, block); + pl(sector3, FS_FLOPPY_BLOCKSIZE - 4, -3 >>> 0); + } + //memset(sector2, 0, FS_FLOPPY_BLOCKSIZE); + SAEF_memset(sector2,0, 0, FS_FLOPPY_BLOCKSIZE); + pl(sector2, 0, 8); + pl(sector2, 4, block); + pl(sector2, 8, datasec++); + pl(sector2, 12, size > FS_OFS_DATABLOCKSIZE ? FS_OFS_DATABLOCKSIZE : size); + SAEF_ZFile_fread(sector2,24, size > FS_OFS_DATABLOCKSIZE ? FS_OFS_DATABLOCKSIZE : size, 1, src); + size -= FS_OFS_DATABLOCKSIZE; + datablock = 0; + if (size > 0) datablock = getblock(bitmap, prevblock); + pl(sector2, 16, datablock); + disk_checksum(sector2,0, sector2,20); + writeimageblock(z, sector2, datablock2 * FS_FLOPPY_BLOCKSIZE); + if (datasec <= FS_EXTENSION_BLOCKS + 1) + pl(sector, 512 - 204 - extensioncounter * 4, datablock2); + else + pl(sector3, 512 - 204 - extensioncounter * 4, datablock2); + extensioncounter++; + } + if (datasec > FS_EXTENSION_BLOCKS) { + pl(sector3, 8, extensioncounter); + disk_checksum(sector3,0, sector3,20); + writeimageblock(z, sector3, extensionblock * FS_FLOPPY_BLOCKSIZE); + } + disk_checksum(sector,0, sector,20); + writeimageblock(z, sector, block * FS_FLOPPY_BLOCKSIZE); + return block; + } + function createbitmapblock(sector, bitmap) { + //memset(sector, 0, FS_FLOPPY_BLOCKSIZE); + SAEF_memset(sector,0, 0, FS_FLOPPY_BLOCKSIZE); + var i = 0; + for (;;) { + var mask = 0; + for (var j = 0; j < 32; j++) { + if (bitmap[2 + i * 32 + j] == 0xff) + break; + if (!bitmap[2 + i * 32 + j]) + mask |= 1 << j; + } + mask >>>= 0; + sector[4 + i * 4 + 0] = mask >>> 24; + sector[4 + i * 4 + 1] = (mask >>> 16) & 0xff; + sector[4 + i * 4 + 2] = (mask >>> 8) & 0xff; + sector[4 + i * 4 + 3] = mask & 0xff; + if (bitmap[2 + i * 32 + j] == 0xff) + break; + i++; + } + disk_checksum(sector,0, sector,0); + } + function createimagefromexe(src, dst) { + var sector1 = new Uint8Array(FS_FLOPPY_BLOCKSIZE) + var sector2 = new Uint8Array(FS_FLOPPY_BLOCKSIZE) + var bitmap = new Uint8Array(FS_FLOPPY_TOTALBLOCKS + 8); + var blocksize = FS_OFS_DATABLOCKSIZE; + const fname1 = "runme.exe"; + const fname1b = "runme.adf"; + const fname2 = "startup-sequence"; + const dirname1 = "s"; + var prevblock = { + block:880 + }; + + //memset(bitmap, 0, sizeof bitmap); + SAEF_ZFile_fseek(src, 0, SEEK_END); + var exesize = SAEF_ZFile_ftell(src); + var blocks = Math.floor((exesize + blocksize - 1) / blocksize); + var extensionblocks = Math.floor((blocks + FS_EXTENSION_BLOCKS - 1) / FS_EXTENSION_BLOCKS); + //bootblock=2, root=1, bitmap=1, startup-sequence=1+1, exefileheader=1 + var totalblocks = 2 + 1 + 1 + 2 + 1 + blocks + extensionblocks; + if (totalblocks > FS_FLOPPY_TOTALBLOCKS) + return 0; + + bitmap[880] = 1; + bitmap[881] = 1; + bitmap[0] = 1; + bitmap[1] = 1; + bitmap[1760] = -1; + //prevblock = 880; + + var dblock1 = createdirheaderblock(sector2, 880, dirname1, bitmap, prevblock); + var ss = SAEF_ZFile_fopen_empty(src, fname1b, fname1.length); + SAEF_ZFile_fwrite(SAEF_String2Array(fname1),0, fname1.length, 1, ss); + var fblock1 = createfileheaderblock(dst, sector1, dblock1, fname2, ss, bitmap, prevblock); + SAEF_ZFile_fclose(ss); + pl(sector2, 24 + dirhash(fname2) * 4, fblock1); + disk_checksum(sector2,0, sector2,20); + writeimageblock(dst, sector2, dblock1 * FS_FLOPPY_BLOCKSIZE); + + fblock1 = createfileheaderblock(dst, sector1, 880, fname1, src, bitmap, prevblock); + + createrootblock(sector1, SAEF_ZFile_getfilename(src)); + pl(sector1, 24 + dirhash(fname1) * 4, fblock1); + pl(sector1, 24 + dirhash(dirname1) * 4, dblock1); + disk_checksum(sector1,0, sector1,20); + writeimageblock(dst, sector1, 880 * FS_FLOPPY_BLOCKSIZE); + + createbitmapblock(sector1, bitmap); + writeimageblock(dst, sector1, 881 * FS_FLOPPY_BLOCKSIZE); + + createbootblock(sector1, 1); + writeimageblock(dst, sector1, 0 * FS_FLOPPY_BLOCKSIZE); + return 1; + } + + this.EXE2ADF = function(z) { + var orgname = SAEF_ZFile_getname(z); + var newname = ""; + + var ext = orgname.lastIndexOf('.'); + if (ext != -1) { + newname = orgname.substr(0, ext); + newname += ".ADF"; + } else + newname = orgname + ".ADF"; + + var zo = SAEF_ZFile_fopen_empty(z, newname, 1760 * 512); + if (zo === null) + return null; + + var ret = createimagefromexe(z, zo); + if (ret) { + SAEF_ZFile_fseek(zo, 0, SEEK_SET); + + SAEF_ZFile_fclose(z); + z = null; + + SAEF_log("disk.EXE2ADF() converted '%s' to '%s'", orgname, newname); + } else { + SAEF_ZFile_fclose(zo); + zo = null; + + //SAEF_warn("disk.EXE2ADF() error converting '%s' (too big)"), orgname); + alert(sprintf("Can't convert '%s' to ADF. (too big)", orgname)); + } + return zo; + } + + /*---------------------------------*/ + /* create ADF */ + + function floppy_get_bootblock(dst, ffs, bootable) { + if (bootable) + dst.set(ffs ? bootblock_ffs : bootblock_ofs); + else { + dst[0] = 68; //D + dst[1] = 79; //O + dst[2] = 83; //S + dst[3] = ffs ? 1 : 0; + } + } + function floppy_get_rootblock(dst, block, label, type) { + var ls = label.length > 0 ? label : "empty"; + dst[0+3] = 2; + dst[12+3] = 0x48; + dst[312] = dst[313] = dst[314] = dst[315] = 0xff; + dst[316+2] = ((block + 1) >> 8) & 255; + dst[316+3] = (block + 1) & 255; + dst[432] = ls.length; dst.set(SAEF_String2Array(ls), 433); //BSTR + dst[508 + 3] = 1; + disk_date(dst,420); + //memcpy(dst + 472, dst + 420, 3 * 4); + //memcpy(dst + 484, dst + 420, 3 * 4); + SAEF_memcpy(dst,472, dst,420, 3 * 4); + SAEF_memcpy(dst,484, dst,420, 3 * 4); + //dst.copyWithin(472, 420, 420 + 3 * 4); + //dst.copyWithin(484, 420, 420 + 3 * 4); + disk_checksum(dst,0, dst,20); + //bitmap block + //memset(dst + 512 + 4, 0xff, 2 * block / 8); + SAEF_memset(dst,512 + 4, 0xff, 2 * block >> 3); + if (type == SAEC_Disk_Create_Type_35_DD) + dst[512 + 0x72] = 0x3f; + else + dst[512 + 0xdc] = 0x3f; + disk_checksum(dst,512, dst,512); + } + + //function creatediskfile(name, mode, type, label, ffs, bootable, copyfrom) { + function creatediskfile(name, mode, type, label, ffs, bootable, copyfrom) { //disk_creatediskfile() + const size = 32768; + var chunk = null; //u8 * + var ddhd = 1; + var pos; //u64 + var i; + var ok = false; + + var tracks = 2 * (mode == SAEC_Disk_Create_Mode_Custom ? 83 : 80); + var file_size = 880 * 1024; + var sectors = 11; + if (type == SAEC_Disk_Create_Type_35_DD_PC || type == SAEC_Disk_Create_Type_35_HD_PC) { + file_size = 720 * 1024; + sectors = 9; + } + var track_len = FLOPPY_WRITE_LEN() * 2; + if (type == SAEC_Disk_Create_Type_35_HD || type == SAEC_Disk_Create_Type_35_HD_PC) { + file_size <<= 1; + track_len <<= 1; + ddhd = 2; + } else if (type == SAEC_Disk_Create_Type_525_SD) { + file_size >>= 1; + tracks >>= 1; + } + + if (copyfrom !== null) { + pos = SAEF_ZFile_ftell(copyfrom); + SAEF_ZFile_fseek(copyfrom, 0, SEEK_SET); + } + + //var f = SAEF_ZFile_fopen(name, "wb", 0); + var f = SAEF_ZFile_fopen_empty(null, name, file_size); + chunk = new Uint8Array(size); + if (f !== null) { + var cylsize = sectors * 2 * 512; + //memset(chunk, 0, size); + SAEF_memset(chunk,0, 0, size); + if (mode == SAEC_Disk_Create_Mode_Normal) { + for (i = 0; i < file_size; i += cylsize) { + //memset(chunk, 0, cylsize); + SAEF_memset(chunk,0, 0, cylsize); + if (type <= SAEC_Disk_Create_Type_35_HD) { + if (i == 0) { + //boot block + floppy_get_bootblock(chunk, ffs, bootable); + } else if (i == file_size >> 1) { + //root block + floppy_get_rootblock(chunk, file_size / (2 * 512), label, type); + } + } + SAEF_ZFile_fwrite(chunk,0, cylsize, 1, f); + } + ok = true; + } else { + var root = new Uint8Array(4); + var rawtrack = new Uint8Array(3 * 4); + var dostrack = new Uint8Array(3 * 4); + var l = track_len; + SAEF_ZFile_fwrite(SAEF_String2Array("UAE-1ADF"),0, 8, 1, f); + root[0] = 0; root[1] = 0; //flags (reserved) + root[2] = 0; root[3] = tracks; //number of tracks + SAEF_ZFile_fwrite(root,0, 4, 1, f); + rawtrack[0] = 0; rawtrack[1] = 0; //flags (reserved) + rawtrack[2] = 0; rawtrack[3] = 1; //track type + rawtrack[4] = 0; rawtrack[5] = 0; rawtrack[6] = l >> 8; rawtrack[7] = l & 0xff; + rawtrack[8] = 0; rawtrack[9] = 0; rawtrack[10] = 0; rawtrack[11] = 0; + dostrack.set(rawtrack); + dostrack[3] = 0; + dostrack[9] = ((l * 8) >> 16) & 0xff; + dostrack[10] = ((l * 8) >> 8) & 0xff; + dostrack[11] = (l * 8) & 0xff; + var dodos = ffs || bootable || label.length > 0; + for (i = 0; i < tracks; i++) { + var tmp = new Uint8Array(3 * 4); + if (dodos || copyfrom !== null) + tmp.set(dostrack); + else + tmp.set(rawtrack); + SAEF_ZFile_fwrite(tmp,0, tmp.length, 1, f); + } + for (i = 0; i < tracks; i++) { + //memset(chunk, 0, size); + SAEF_memset(chunk,0, 0, size); + if (copyfrom !== null) + SAEF_ZFile_fread(chunk,0, 11 * ddhd, 512, copyfrom); + else { + if (dodos) { + if (i == 0) + floppy_get_bootblock(chunk, ffs, bootable); + else if (i == 80) + floppy_get_rootblock(chunk, 80 * 11 * ddhd, label, type); + } + } + SAEF_ZFile_fwrite(chunk,0, l, 1, f); + } + ok = true; + } + } + + //SAEF_ZFile_fclose(f); + + if (copyfrom !== null) + SAEF_ZFile_fseek(copyfrom, pos, SEEK_SET); + + //return ok; + return ok ? f : null; + } + this.create = function(unit, name, mode, type, label, ffs, bootable) { + var f = creatediskfile(name, mode, type, label, ffs, bootable, null); + if (f !== null) { + switch (type) { + case SAEC_Disk_Create_Type_35_DD: SAEV_config.floppy.drive[unit].type = SAEC_Config_Floppy_Type_35_DD; break; + case SAEC_Disk_Create_Type_35_HD: SAEV_config.floppy.drive[unit].type = SAEC_Config_Floppy_Type_35_HD; break; + case SAEC_Disk_Create_Type_35_DD_PC: SAEV_config.floppy.drive[unit].type = SAEC_Config_Floppy_Type_35_DD_PC; break; + case SAEC_Disk_Create_Type_35_HD_PC: SAEV_config.floppy.drive[unit].type = SAEC_Config_Floppy_Type_35_HD_PC; break; + case SAEC_Disk_Create_Type_525_SD: SAEV_config.floppy.drive[unit].type = SAEC_Config_Floppy_Type_525_SD; break; + } + var data = SAEF_ZFile_getdata(f, 0, -1); + var file = SAEV_config.floppy.drive[unit].file; + file.name = SAEF_ZFile_getname(f); + file.data = SAEF_Array2String(data); + file.size = SAEF_ZFile_size(f); + file.prot = false; + + SAEF_ZFile_fclose(f); + return true; + } + return false; + } + + /*---------------------------------*/ + + function convert_adf_to_ext2(drv, mode) { + if (drv.filetype != ADF_NORMAL) + return false; + + var file = SAEV_config.floppy.drive[drv.num].file; + var hd = drv.ddhd == 2; + var name = file.name; + if (name.length == 0) + return false; + + var f = null; + if (mode == 1) { + /*var p = name.lastIndexOf('.'); + if (p != -1) + name = name.substr(0, p) + ".extended.adf"; + else + name += ".extended.adf";*/ + + f = creatediskfile(name, SAEC_Disk_Create_Mode_Custom, hd ? SAEC_Disk_Create_Type_35_HD : SAEC_Disk_Create_Type_35_DD, "", false, false, drv.diskfile); + if (f === null) + return false; + } else if (mode == 2) { + var tmp = SAEF_ZFile_fopen_load_zfile(drv.diskfile); + if (tmp === null) + return false; + + SAEF_ZFile_fclose(drv.diskfile); + drv.diskfile = null; + + f = creatediskfile(name, SAEC_Disk_Create_Mode_Custom, hd ? SAEC_Disk_Create_Type_35_HD : SAEC_Disk_Create_Type_35_DD, "", false, false, tmp); + if (f === null) { + SAEF_ZFile_fclose(tmp); + return false; + } + } else + return false; + + /*var f = SAEF_ZFile_fopen(name, "r+b"); + if (f === null) + return false;*/ + + //file.name = name; + //changed_prefs.floppyslots[drv.num].file.name = name; + SAEF_ZFile_fclose(drv.diskfile); + + drv.diskfile = f; + drv.filetype = ADF_EXT2; + //read_header_ext2(drv.diskfile, drv.trackdata, &drv.num_tracks, &drv.ddhd); + read_header_ext2(drv, drv.ddhd); + + drive_write_data(drv); + /*#ifdef RETROPLATFORM + rp_disk_image_change(drv - &floppy[0], name, false); + #endif*/ + drive_fill_bigbuf(drv, true); + + SAEF_log("disk.convert_adf_to_ext2() converted '%s' to ADF-EXT2", file.name); + return true; + } + + /*-----------------------------------------------------------------------*/ + + /*#define FLOPPY_RATE_500K 0 + #define FLOPPY_RATE_300K 1 + #define FLOPPY_RATE_250K 2 + #define FLOPPY_RATE_1M 3 + struct floppy_reserved { + int num; + struct zfile *img; + bool wrprot; + int cyl; + int cyls; + int heads; + int secs; + int drive_cyls; + bool disk_changed; + int rate; + }; + static int get_reserved_id(int num) { + for (int i = 0; i < MAX_FLOPPY_DRIVES; i++) { + if (reserved & (1 << i)) { + if (num > 0) { + num--; + continue; + } + return i; + } + } + return -1; + } + void disk_reserved_setinfo(int num, int cyl, int head, int motor) { + int i = get_reserved_id(num); + if (i >= 0) { + drive *drv = &floppy[i]; + reserved_side = head; + drv->cyl = cyl; + drv->state = motor != 0; + update_drive_gui(i, false); + } + } + bool disk_reserved_getinfo(int num, struct floppy_reserved *fr) { + int idx = get_reserved_id(num); + if (idx >= 0) { + drive *drv = &floppy[idx]; + fr->num = idx; + fr->img = drv->diskfile; + fr->wrprot = drv->wrprot; + if (drv->diskfile && !drv->pcdecodedfile && (drv->filetype == ADF_EXT2 || drv->filetype == ADF_FDI || drv->filetype == ADF_SCP)) { + int cyl = drv->cyl; + int side2 = side; + struct zfile *z = SAEF_ZFile_fopen_empty(null, SAEF_ZFile_getfilename(drv->diskfile)); + if (z) { + bool ok = false; + drv->num_secs = 21; // max possible + drive_fill_bigbuf(drv, true); + int secs = drive_write_pcdos(drv, z, 1); + if (secs >= 8) { + ok = true; + drv->num_secs = secs; + for (int i = 0; i < drv->num_tracks; i++) { + drv->cyl = i / 2; + side = i & 1; + drive_fill_bigbuf(drv, true); + drive_write_pcdos(drv, z, 0); + } + } + drv->cyl = cyl; + side = side2; + if (ok) { + write_log(_T("Created internal PC disk image cyl=%d secs=%d size=%d\n"), drv->num_tracks / 2, drv->num_secs, SAEF_ZFile_size(z)); + drv->pcdecodedfile = z; + } else { + write_log(_T("Failed to create internal PC disk image\n")); + SAEF_ZFile_fclose(z); + } + } + } + if (drv->pcdecodedfile) { + fr->img = drv->pcdecodedfile; + } + fr->cyl = drv->cyl; + fr->cyls = drv->num_tracks / 2; + fr->drive_cyls = SAEV_config.floppy.drive[idx].type == SAEC_Config_Floppy_Type_35_DD_PC ? 40 : 80; + fr->secs = drv->num_secs; + fr->heads = drv->num_heads; + fr->disk_changed = drv->dskchange || fr->img == null; + if (SAEV_config.floppy.drive[idx].type == SAEC_Config_Floppy_Type_35_HD_PC) { + if (fr->cyls < 80) { + if (drv->num_secs < 9) + fr->rate = FLOPPY_RATE_250K; // 320k in 80 track drive + else + fr->rate = FLOPPY_RATE_300K; // 360k in 80 track drive + } else { + if (drv->num_secs > 14) + fr->rate = FLOPPY_RATE_500K; // 1.2M/1.4M + else + fr->rate = FLOPPY_RATE_250K; // 720K + } + } else { + if (drv->num_secs < 9) + fr->rate = FLOPPY_RATE_300K;// 320k in 40 track drive + else + fr->rate = FLOPPY_RATE_250K;// 360k in 40 track drive + // yes, above values are swapped compared to 1.2M drive case + } + return true; + } + return false; + } + void disk_reserved_reset_disk_change(int num) { + int i = get_reserved_id(num); + if (i >= 0) { + drive *drv = &floppy[i]; + drv->dskchange = false; + } + }*/ +} diff --git a/sae/dms.js b/sae/dms.js new file mode 100644 index 0000000..a2b61c7 --- /dev/null +++ b/sae/dms.js @@ -0,0 +1,1308 @@ +/*------------------------------------------------------------------------- +| SAE - Scripted Amiga Emulator +| https://github.com/naTmeg/ScriptedAmigaEmulator +| +| Copyright (C) 2012-2016 Rupert Hausberger +| +| This program is free software; you can redistribute it and/or +| modify it under the terms of the GNU General Public License +| as published by the Free Software Foundation; either version 2 +| of the License, or (at your option) any later version. +| +| This program is distributed in the hope that it will be useful, +| but WITHOUT ANY WARRANTY; without even the implied warranty of +| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +| GNU General Public License for more details. +| +| Notes: ported from WinUAE 3.2.x +| +| xDMS v1.3 - Portable DMS archive unpacker - Public Domain +| Written by Andre Rodrigues de la Rocha +| +| Handles the processing of a single DMS archive +-------------------------------------------------------------------------*/ + +function SAEO_DMS() { + const DMS_LOG = 0 ? true : false; + + /* Functions return codes */ + const NO_PROBLEM = 0; + const DMS_FILE_END = 1; + const ERR_NOMEMORY = 2; + const ERR_CANTOPENIN = 3; + const ERR_CANTOPENOUT = 4; + const ERR_NOTDMS = 5; + const ERR_SREAD = 6; + const ERR_HCRC = 7; + const ERR_NOTTRACK = 8; + const ERR_BIGTRACK = 9; + const ERR_THCRC = 10; + const ERR_TDCRC = 11; + const ERR_CSUM = 12; + const ERR_CANTWRITE = 13; + const ERR_BADDECR = 14; + const ERR_UNKNMODE = 15; + const ERR_NOPASSWD = 16; + const ERR_BADPASSWD = 17; + const ERR_FMS = 18; + const ERR_GZIP = 19; + const ERR_READDISK = 20; + + /* Command to execute */ + const CMD_VIEW = 1; + const CMD_VIEWFULL = 2; + const CMD_SHOWDIZ = 3; + const CMD_SHOWBANNER = 4; + const CMD_TEST = 5; + const CMD_UNPACK = 6; + const CMD_UNPKGZ = 7; + const CMD_EXTRACT = 8; + + const OPT_VERBOSE = 1; + const OPT_QUIET = 2; + + /*---------------------------------*/ + /* support */ + + const d_code = [ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, + 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, + 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, + 0x0C, 0x0C, 0x0C, 0x0C, 0x0D, 0x0D, 0x0D, 0x0D, + 0x0E, 0x0E, 0x0E, 0x0E, 0x0F, 0x0F, 0x0F, 0x0F, + 0x10, 0x10, 0x10, 0x10, 0x11, 0x11, 0x11, 0x11, + 0x12, 0x12, 0x12, 0x12, 0x13, 0x13, 0x13, 0x13, + 0x14, 0x14, 0x14, 0x14, 0x15, 0x15, 0x15, 0x15, + 0x16, 0x16, 0x16, 0x16, 0x17, 0x17, 0x17, 0x17, + 0x18, 0x18, 0x19, 0x19, 0x1A, 0x1A, 0x1B, 0x1B, + 0x1C, 0x1C, 0x1D, 0x1D, 0x1E, 0x1E, 0x1F, 0x1F, + 0x20, 0x20, 0x21, 0x21, 0x22, 0x22, 0x23, 0x23, + 0x24, 0x24, 0x25, 0x25, 0x26, 0x26, 0x27, 0x27, + 0x28, 0x28, 0x29, 0x29, 0x2A, 0x2A, 0x2B, 0x2B, + 0x2C, 0x2C, 0x2D, 0x2D, 0x2E, 0x2E, 0x2F, 0x2F, + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, + 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F + ]; + const d_len = [ + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08 + ]; + + const LOC_QUICK = 0; + const LOC_MEDIUM = 1; + const LOC_HEAVY = 2; + const LOC_DEEP = 3; + var dms_loc = new Uint16Array(4); //OWN + + const dms_mask_bits = [ + 0x000000,0x000001,0x000003,0x000007,0x00000f,0x00001f, + 0x00003f,0x00007f,0x0000ff,0x0001ff,0x0003ff,0x0007ff, + 0x000fff,0x001fff,0x003fff,0x007fff,0x00ffff,0x01ffff, + 0x03ffff,0x07ffff,0x0fffff,0x1fffff,0x3fffff,0x7fffff, + 0xffffff + ]; + var dms_indata = null; + var dms_indata_pos = 0; //OWN + var dms_bitcount = 0; + var dms_bitbuf = 0; //u32 + + function GETBITS(n) { + return (dms_bitbuf >>> (dms_bitcount - n)) & 0xffff; + } + function DROPBITS(n) { + dms_bitcount -= n; + dms_bitbuf = dms_bitbuf & dms_mask_bits[dms_bitcount]; + while (dms_bitcount < 16) { + dms_bitbuf = ((dms_bitbuf << 8) | dms_indata[dms_indata_pos++]) >>> 0; + dms_bitcount += 8; + } + } + + function initbitbuf(id) { + dms_bitbuf = 0; + dms_bitcount = 0; + dms_indata = id; + dms_indata_pos = 0; + DROPBITS(0); + } + + /*---------------------------------*/ + /* Run Length Encoding */ + + function Unpack_RLE(src, dst, origsize) { + var srco = 0, dsto = 0; + var n = 0; //u16 + var a = 0, b = 0; + + while (dsto < origsize){ + if ((a = src[srco++]) != 0x90) + dst[dsto++] = a; + else if (!(b = src[srco++])) + dst[dsto++] = a; + else { + a = src[srco++]; + if (b == 0xff) { + n = src[srco++]; + n = (n << 8) + src[srco++]; + } else + n = b; + if (dsto + n > origsize) return 1; + //memset(dst,a,n); + SAEF_memset(dst,dsto, a, n); + dsto += n; + } + } + return 0; + } + + /*---------------------------------*/ + /* Quick */ + + const QBITMASK = 0xff; + + function Unpack_QUICK(src, dst, origsize){ + var dsto = 0; + var i = 0, j = 0; + + initbitbuf(src); + while (dsto < origsize) { + if (GETBITS(1) != 0) { + DROPBITS(1); + dst[dsto++] = dms_text[dms_loc[LOC_QUICK]++ & QBITMASK] = GETBITS(8) & 0xff; DROPBITS(8); + } else { + DROPBITS(1); + j = GETBITS(2) + 2; DROPBITS(2); + i = dms_loc[LOC_QUICK] - GETBITS(8) - 1; DROPBITS(8); + while (j--) { + dst[dsto++] = dms_text[dms_loc[LOC_QUICK]++ & QBITMASK] = dms_text[i++ & QBITMASK]; + } + } + } + dms_loc[LOC_QUICK] = dms_loc[LOC_QUICK] + 5 & QBITMASK; + return 0; + } + + /*---------------------------------*/ + /* Medium */ + + const MBITMASK = 0x3fff; + + function Unpack_MEDIUM(src, dst, origsize) { + var dsto = 0; + var i = 0, j = 0, c = 0; + + initbitbuf(src); + while (dsto < origsize) { + if (GETBITS(1) != 0) { + DROPBITS(1); + dst[dsto++] = dms_text[dms_loc[LOC_MEDIUM]++ & MBITMASK] = GETBITS(8) & 0xff; + DROPBITS(8); + } else { + DROPBITS(1); + c = GETBITS(8); DROPBITS(8); + j = d_code[c] + 3; + u = d_len[c]; + c = ((c << u) | GETBITS(u)) & 0xff; DROPBITS(u); + u = d_len[c]; + c = (d_code[c] << 8) | (((c << u) | GETBITS(u)) & 0xff); DROPBITS(u); + i = dms_loc[LOC_MEDIUM] - c - 1; + + while (j--) dst[dsto++] = dms_text[dms_loc[LOC_MEDIUM]++ & MBITMASK] = dms_text[i++ & MBITMASK]; + + } + } + dms_loc[LOC_MEDIUM] = dms_loc[LOC_MEDIUM] + 66 & MBITMASK; + return 0; + } + + /*---------------------------------*/ + /* Deep, Lempel-Ziv-DynamicHuffman decompression */ + + const DBITMASK = 0x3fff; /* uses 16Kb dictionary */ + + const F = 60; /* lookahead buffer size */ + const THRESHOLD = 2; + const N_CHAR = 256 - THRESHOLD + F; /* kinds of characters (character code = 0..N_CHAR-1) */ + + const T = N_CHAR * 2 - 1; /* size of table */ + const R = T - 1; /* position of root */ + const MAX_FREQ = 0x8000; /* updates tree when the */ + + var freq = new Uint16Array(T + 1); /* frequency table */ + /* pointers to parent nodes, except for the */ + /* elements [T..T + N_CHAR - 1] which are used to get */ + /* the positions of leaves corresponding to the codes. */ + var prnt = new Uint16Array(T + N_CHAR); + var son = new Uint16Array(T); /* pointers to child nodes (son[], son[] + 1) */ + + var dms_init_deep_tabs = true; + + + function Init_DEEP_Tabs(){ + for (var i = 0; i < N_CHAR; i++) { + freq[i] = 1; + son[i] = i + T; + prnt[i + T] = i; + } + i = 0; + var j = N_CHAR; + while (j <= R) { + freq[j] = freq[i] + freq[i + 1]; + son[j] = i; + prnt[i] = prnt[i + 1] = j; + i += 2; j++; + } + freq[T] = 0xffff; + prnt[R] = 0; + + dms_init_deep_tabs = false; + } + + /* reconstruction of tree */ + function reconst(){ + var i = 0, j = 0, k = 0, f = 0, l = 0, m = 0; + + /* collect leaf nodes in the first half of the table */ + /* and replace the freq by (freq + 1) / 2. */ + for (i = 0; i < T; i++) { + if (son[i] >= T) { + freq[j] = (freq[i] + 1) >> 1; + son[j] = son[i]; + j++; + } + } + /* begin constructing tree by connecting sons */ + for (i = 0, j = N_CHAR; j < T; i += 2, j++) { + k = i + 1; + f = freq[j] = freq[i] + freq[k]; + for (k = j - 1; f < freq[k]; k--); + k++; + //l = (j - k) << 1; + l = j - k; + //memmove(&freq[k + 1], &freq[k], (size_t)l); + for (m = l; m >= 0; m--) freq[k + m + 1] = freq[k + m]; + freq[k] = f; + //memmove(&son[k + 1], &son[k], (size_t)l); + for (m = l; m >= 0; m--) son[k + m + 1] = son[k + m]; + son[k] = i; + } + /* connect prnt */ + for (i = 0; i < T; i++) { + if ((k = son[i]) >= T) { + prnt[k] = i; + } else { + prnt[k] = prnt[k + 1] = i; + } + } + } + + /* increment frequency of given code by one, and update tree */ + function update(c){ + var i = 0, j = 0, k = 0, l = 0; + + if (freq[R] == MAX_FREQ) + reconst(); + + c = prnt[c + T]; + do { + k = ++freq[c]; + + /* if the order is disturbed, exchange nodes */ + if (k > freq[l = c + 1]) { + while (k > freq[++l]); + l--; + freq[c] = freq[l]; + freq[l] = k; + + i = son[c]; + prnt[i] = l; + if (i < T) prnt[i + 1] = l; + + j = son[l]; + son[l] = i; + + prnt[j] = c; + if (j < T) prnt[j + 1] = c; + son[c] = j; + + c = l; + } + } while ((c = prnt[c]) != 0); /* repeat up to root */ + } + + function DecodeChar(){ + var c = son[R]; + /* travel from root to leaf, */ + /* choosing the smaller child node (son[]) if the read bit is 0, */ + /* the bigger (son[]+1} if 1 */ + while (c < T) { + c = son[c + GETBITS(1)]; + DROPBITS(1); + } + c -= T; + update(c); + return c; + } + + function DecodePosition(){ + var i = GETBITS(8); DROPBITS(8); + var c = d_code[i] << 8; + var j = d_len[i]; + i = ((i << j) | GETBITS(j)) & 0xff; DROPBITS(j); + return c | i; + } + + function Unpack_DEEP(src, dst, origsize){ + var dsto = 0; + var i = 0, j = 0, c = 0; + + initbitbuf(src); + if (dms_init_deep_tabs) + Init_DEEP_Tabs(); + + while (dsto < origsize) { + c = DecodeChar(); + if (c < 256) { + dst[dsto++] = dms_text[dms_loc[LOC_DEEP]++ & DBITMASK] = c & 0xff; + } else { + j = c - 255 + THRESHOLD; + i = dms_loc[LOC_DEEP] - DecodePosition() - 1; + while (j--) dst[dsto++] = dms_text[dms_loc[LOC_DEEP]++ & DBITMASK] = dms_text[i++ & DBITMASK]; + } + } + dms_loc[LOC_DEEP] = dms_loc[LOC_DEEP] + 60 & DBITMASK; + return 0; + } + + /*---------------------------------*/ + /* Heavy, Lempel-Ziv-Huffman decompression */ + + const NC = 510; + const NPT = 20; + const N1 = 510; + const OFFSET = 253; + + var c_len = new Uint8Array(NC); + var c_table = new Uint16Array(4096); + var pt_len = new Uint8Array(NPT); + var pt_table = new Uint16Array(256); + + var dms_left = new Uint16Array(2 * NC - 1); + var dms_right = new Uint16Array(2 * NC - 1 + 9); + var dms_lastlen = 0, dms_np = 0; //u16 + + function dms_make_table(nchar, bitlen, tablebits, table) { + var c = 0; //s16 + var n = 0, tblsiz = 0, len = 0, depth = 0, maxdepth = 0, avail = 0; //u16 + var codeword = 0, bit = 0, tbl = null, err = 0; //u16 + var blen = null; //u8 * + + function mktbl() { + var i = 0; + + if (err) return 0; + + if (len == depth) { + while (++c < n) + if (blen[c] == len) { + i = codeword; + codeword += bit; + if (codeword > tblsiz) { + err = 1; + return 0; + } + while (i < codeword) tbl[i++] = c; + return c; + } + c = -1; + len++; + bit >>= 1; + } + depth++; + if (depth < maxdepth) { + mktbl(); + mktbl(); + } else if (depth > 32) { + err = 2; + return 0; + } else { + if ((i = avail++) >= 2 * n - 1) { + err = 3; + return 0; + } + dms_left[i] = mktbl(); + dms_right[i] = mktbl(); + if (codeword >= tblsiz) { + err = 4; + return 0; + } + if (depth == maxdepth) tbl[codeword++] = i; + } + depth--; + return i; + } + + n = avail = nchar; + blen = bitlen; + tbl = table; + tblsiz = 1 << tablebits; + bit = tblsiz >> 1; + maxdepth = tablebits + 1; + depth = len = 1; + c = -1; + codeword = 0; + err = 0; + mktbl(); // left subtree + if (err) return err; + mktbl(); // right subtree + if (err) return err; + if (codeword != tblsiz) return 5; + return 0; + } + + function read_tree_c() { + var n = GETBITS(9); + DROPBITS(9); + if (n > 0) { + for (var i = 0; i < n; i++) { + c_len[i] = GETBITS(5) & 0xff; + DROPBITS(5); + } + for (i = n; i < 510; i++) c_len[i] = 0; + if (dms_make_table(510, c_len, 12, c_table)) return 1; + } else { + n = GETBITS(9); + DROPBITS(9); + for (var i = 0; i < 510; i++) c_len[i] = 0; + for (i = 0; i < 4096; i++) c_table[i] = n; + } + return 0; + } + function read_tree_p() { + var n = GETBITS(5); + DROPBITS(5); + if (n > 0){ + for (var i = 0; i < n; i++) { + pt_len[i] = GETBITS(4) & 0xff; + DROPBITS(4); + } + for (i = n; i < dms_np; i++) pt_len[i] = 0; + if (dms_make_table(dms_np, pt_len, 8, pt_table)) return 1; + } else { + n = GETBITS(5); + DROPBITS(5); + for (var i = 0; i < dms_np; i++) pt_len[i] = 0; + for (i = 0; i < 256; i++) pt_table[i] = n; + } + return 0; + } + + function decode_c(){ + var j = c_table[GETBITS(12)]; + if (j < N1) { + DROPBITS(c_len[j]); + } else { + DROPBITS(12); + var i = GETBITS(16); + var m = 0x8000; + do { + if (i & m) j = dms_right[j]; + else j = dms_left [j]; + m >>= 1; + } while (j >= N1); + DROPBITS(c_len[j] - 12); + } + return j; + } + function decode_p(){ + var j = pt_table[GETBITS(8)]; + if (j < dms_np) { + DROPBITS(pt_len[j]); + } else { + DROPBITS(8); + var i = GETBITS(16); + var m = 0x8000; + do { + if (i & m) j = dms_right[j]; + else j = dms_left [j]; + m >>= 1; + } while (j >= dms_np); + DROPBITS(pt_len[j] - 8); + } + if (j != dms_np-1) { + if (j > 0) { + j = GETBITS(i = j-1) | (1 << (j-1)); + DROPBITS(i); + } + dms_lastlen = j; + } + return dms_lastlen; + } + + function Unpack_HEAVY(src, dst, flags, origsize){ + /* Heavy 1 uses a 4Kb dictionary, Heavy 2 uses 8Kb */ + if (flags & 8) { + dms_np = 15; + var bitmask = 0x1fff; + } else { + dms_np = 14; + var bitmask = 0x0fff; + } + initbitbuf(src); + + if (flags & 2) { + if (read_tree_c()) return 1; + if (read_tree_p()) return 2; + } + + var dsto = 0; + while (dsto < origsize) { + var c = decode_c(); + if (c < 256) { + dst[dsto++] = dms_text[dms_loc[LOC_HEAVY]++ & bitmask] = c; + } else { + var j = c - OFFSET; + var i = dms_loc[LOC_HEAVY] - decode_p() - 1; + while (j--) dst[dsto++] = dms_text[dms_loc[LOC_HEAVY]++ & bitmask] = dms_text[i++ & bitmask]; + } + } + return 0; + } + + /*---------------------------------*/ + + function Init_Decrunchers() { + dms_loc[LOC_QUICK] = 251; + + dms_loc[LOC_MEDIUM] = 0x3fbe; + + dms_loc[LOC_HEAVY] = 0; + dms_lastlen = 0; + dms_np = 0; + + dms_loc[LOC_DEEP] = 0x3fc4; + dms_init_deep_tabs = true; + + //memset(dms_text,0,0x3fc8); + SAEF_memset(dms_text,0, 0, 0x3fc8); + } + + /*-----------------------------------------------------------------------*/ + + const HEADLEN = 56; + const THLEN = 20; + const TRACK_BUFFER_LEN = 32000; + const TEMP_BUFFER_LEN = 32000; + + const DMSFLAG_ENCRYPTED = 2; + const DMSFLAG_HD = 16; + + const DMS_MAX_EXTRA = 10; + + const modes = ["NOCOMP", "SIMPLE", "QUICK ", "MEDIUM", "DEEP ", "HEAVY1", "HEAVY2"]; + + var PWDCRC = 0; //u16 + var passfound = 0, passretries = 0; + + var dms_text = null; //u8 * + + /*---------------------------------*/ + + function ctime(t){ + var a = new Date(t * 1000); + var months = ['Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec']; + var year = a.getFullYear(); + var month = months[a.getMonth()]; + var date = a.getDate(); + var hour = a.getHours(); + var min = a.getMinutes(); + var sec = a.getSeconds(); + return date + ' ' + month + ' ' + year + ' ' + sprintf("%02d:%02d:%02d", hour, min, sec); + } + + /*---------------------------------*/ + + function log_error(track) { + SAEF_warn("DMS() Ignored error on track %d!\n", track); + } + + function printbandiz(m, len) { + /*UCHAR *i, *j; + i = j = m; + while (i < m + len) { + if (*i == 10) { + *i = 0; + TCHAR *u = au ((char*)j); + SAEF_log("%s\n",u); + xfree(u); + j = i + 1; + } + i++; + }*/ + if (DMS_LOG) + SAEF_log(SAEF_Array2String(m, 0, len)); + } + + /*---------------------------------*/ + + function dms_Calc_CheckSum(mem, size){ + var u = 0; //u16 + var p = 0; + while (size--) { + u += mem[p++]; + if (u > 0xffff) u -= 0x10000; + } + return u; //(u & 0xffff); + } + + /*---------------------------------*/ + + const CRCTab = [ + 0x0000,0xC0C1,0xC181,0x0140,0xC301,0x03C0,0x0280,0xC241, + 0xC601,0x06C0,0x0780,0xC741,0x0500,0xC5C1,0xC481,0x0440, + 0xCC01,0x0CC0,0x0D80,0xCD41,0x0F00,0xCFC1,0xCE81,0x0E40, + 0x0A00,0xCAC1,0xCB81,0x0B40,0xC901,0x09C0,0x0880,0xC841, + 0xD801,0x18C0,0x1980,0xD941,0x1B00,0xDBC1,0xDA81,0x1A40, + 0x1E00,0xDEC1,0xDF81,0x1F40,0xDD01,0x1DC0,0x1C80,0xDC41, + 0x1400,0xD4C1,0xD581,0x1540,0xD701,0x17C0,0x1680,0xD641, + 0xD201,0x12C0,0x1380,0xD341,0x1100,0xD1C1,0xD081,0x1040, + 0xF001,0x30C0,0x3180,0xF141,0x3300,0xF3C1,0xF281,0x3240, + 0x3600,0xF6C1,0xF781,0x3740,0xF501,0x35C0,0x3480,0xF441, + 0x3C00,0xFCC1,0xFD81,0x3D40,0xFF01,0x3FC0,0x3E80,0xFE41, + 0xFA01,0x3AC0,0x3B80,0xFB41,0x3900,0xF9C1,0xF881,0x3840, + 0x2800,0xE8C1,0xE981,0x2940,0xEB01,0x2BC0,0x2A80,0xEA41, + 0xEE01,0x2EC0,0x2F80,0xEF41,0x2D00,0xEDC1,0xEC81,0x2C40, + 0xE401,0x24C0,0x2580,0xE541,0x2700,0xE7C1,0xE681,0x2640, + 0x2200,0xE2C1,0xE381,0x2340,0xE101,0x21C0,0x2080,0xE041, + 0xA001,0x60C0,0x6180,0xA141,0x6300,0xA3C1,0xA281,0x6240, + 0x6600,0xA6C1,0xA781,0x6740,0xA501,0x65C0,0x6480,0xA441, + 0x6C00,0xACC1,0xAD81,0x6D40,0xAF01,0x6FC0,0x6E80,0xAE41, + 0xAA01,0x6AC0,0x6B80,0xAB41,0x6900,0xA9C1,0xA881,0x6840, + 0x7800,0xB8C1,0xB981,0x7940,0xBB01,0x7BC0,0x7A80,0xBA41, + 0xBE01,0x7EC0,0x7F80,0xBF41,0x7D00,0xBDC1,0xBC81,0x7C40, + 0xB401,0x74C0,0x7580,0xB541,0x7700,0xB7C1,0xB681,0x7640, + 0x7200,0xB2C1,0xB381,0x7340,0xB101,0x71C0,0x7080,0xB041, + 0x5000,0x90C1,0x9181,0x5140,0x9301,0x53C0,0x5280,0x9241, + 0x9601,0x56C0,0x5780,0x9741,0x5500,0x95C1,0x9481,0x5440, + 0x9C01,0x5CC0,0x5D80,0x9D41,0x5F00,0x9FC1,0x9E81,0x5E40, + 0x5A00,0x9AC1,0x9B81,0x5B40,0x9901,0x59C0,0x5880,0x9841, + 0x8801,0x48C0,0x4980,0x8941,0x4B00,0x8BC1,0x8A81,0x4A40, + 0x4E00,0x8EC1,0x8F81,0x4F40,0x8D01,0x4DC0,0x4C80,0x8C41, + 0x4400,0x84C1,0x8581,0x4540,0x8701,0x47C0,0x4680,0x8641, + 0x8201,0x42C0,0x4380,0x8341,0x4100,0x81C1,0x8081,0x4040 + ]; + function dms_CreateCRC(mem,memo, size) { + var CRC = 0; + + while (size--) + CRC = CRCTab[(CRC ^ mem[memo++]) & 255] ^ ((CRC >> 8) & 255); + + return CRC; + } + + /*---------------------------------*/ + + function addextra(name, extra, p, size) { + if (extra === null) + return; + for (var i = 0; i < DMS_MAX_EXTRA; i++) { + if (extra[i] === null) + break; + } + if (i == DMS_MAX_EXTRA) + return; + var zf = SAEF_ZFile_fopen_empty(null, name, size); + if (zf === null) + return; + SAEF_ZFile_fwrite(p,0, size, 1, zf); + SAEF_ZFile_fseek(zf, 0, SEEK_SET); + extra[i] = zf; + } + + /*---------------------------------*/ + + /* DMS uses a lame encryption */ + function dms_decrypt(p, len, src){ + var srco = 0, po = 0; + var t = 0; //u16 + + while (len--) { + t = src[srco++]; + p[po++] = t ^ (PWDCRC & 0xff); + PWDCRC = ((PWDCRC >> 1) + t) & 0xffff; + } + } + + function Unpack_Track_2(b1, b2, pklen2, unpklen, cmode, flags){ + switch (cmode){ + case 0: + /* No Compression */ + b2.set(b1.subarray(0, unpklen)); //memcpy(b2,b1,(size_t)unpklen); + break; + case 1: + /* Simple Compression */ + if (Unpack_RLE(b1, b2, unpklen)) return ERR_BADDECR; + break; + case 2: + /* Quick Compression */ + if (Unpack_QUICK(b1, b2, pklen2)) return ERR_BADDECR; + if (Unpack_RLE(b2, b1, unpklen)) return ERR_BADDECR; + b2.set(b1.subarray(0, unpklen)); //memcpy(b2,b1,(size_t)unpklen); + break; + case 3: + /* Medium Compression */ + if (Unpack_MEDIUM(b1, b2, pklen2)) return ERR_BADDECR; + if (Unpack_RLE(b2, b1, unpklen)) return ERR_BADDECR; + b2.set(b1.subarray(0, unpklen)); //memcpy(b2,b1,(size_t)unpklen); + break; + case 4: + /* Deep Compression */ + if (Unpack_DEEP(b1, b2, pklen2)) return ERR_BADDECR; + if (Unpack_RLE(b2, b1, unpklen)) return ERR_BADDECR; + b2.set(b1.subarray(0, unpklen)); //memcpy(b2,b1,(size_t)unpklen); + break; + case 5: + case 6: + /* Heavy Compression */ + if (cmode == 5) { + /* Heavy 1 */ + if (Unpack_HEAVY(b1,b2,flags & 7,pklen2)) return ERR_BADDECR; + } else { + /* Heavy 2 */ + if (Unpack_HEAVY(b1,b2,flags | 8,pklen2)) return ERR_BADDECR; + } + if (flags & 4) { + //memset(b1, 0, unpklen); + SAEF_memset(b1,0, 0, unpklen); + /* Unpack with RLE only if this flag is set */ + if (Unpack_RLE(b2, b1, unpklen)) return ERR_BADDECR; + b2.set(b1.subarray(0, unpklen)); //memcpy(b2,b1,(size_t)unpklen); + } + break; + default: + return ERR_UNKNMODE; + } + if (!(flags & 1)) + Init_Decrunchers(); + + return NO_PROBLEM; + } + + var pass = 0; + function Unpack_Track(b1, b2, pklen2, unpklen, cmode, flags, number, pklen1, usum1, enc) { + //static USHORT pass; + var r = 0, err = NO_PROBLEM; + var prevpass = 0; + + if (passfound) { + if (number != 80) + dms_decrypt(b1, pklen1, b1); + r = Unpack_Track_2(b1, b2, pklen2, unpklen, cmode, flags); + if (r == NO_PROBLEM) { + if (usum1 == dms_Calc_CheckSum(b2, unpklen)) + return NO_PROBLEM; + } + log_error(number); + if (passretries <= 0) + return ERR_CSUM; + } + + passretries--; + var pwrounds = 0; + var maybeencrypted = 0; + //UCHAR *tmp = (unsigned char*)malloc (pklen1); + var tmp = new Uint8Array(pklen1); + tmp.set(b1.subarray(0, pklen1)); //memcpy(tmp, b1, pklen1); + //memset(b2, 0, unpklen); + SAEF_memset(b2,0, 0, unpklen); + for (;;) { + r = Unpack_Track_2(b1, b2, pklen2, unpklen, cmode, flags); + if (r == NO_PROBLEM) { + if (usum1 == dms_Calc_CheckSum(b2, unpklen)) { + passfound = maybeencrypted; + if (passfound) + SAEF_log("DMS() decryption key = 0x%04X\n", prevpass); + err = NO_PROBLEM; + pass = prevpass; + break; + } + } + if (number == 80 || !enc) { + err = ERR_CSUM; + break; + } + maybeencrypted = 1; + prevpass = pass; + PWDCRC = pass; + pass++; + dms_decrypt(b1, pklen1, tmp); + pwrounds++; + if (pwrounds == 65536) { + err = ERR_CSUM; + passfound = 0; + break; + } + } + //free(tmp); + return err; + } + + function Process_Track(fi, fo, b1, b2, cmd, opt, dmsflags, extra){ + var crcerr = 0; + + var l = SAEF_ZFile_fread(b1,0, 1, THLEN, fi); + if (l != THLEN) { + if (l == 0) + return DMS_FILE_END; + else + return ERR_SREAD; + } + + /* "TR" identifies a Track Header */ + if ((b1[0] != 84) || (b1[1] != 82)) + return ERR_NOTTRACK; + + /* Track Header CRC */ + var hcrc = ((b1[THLEN-2] << 8) | b1[THLEN-1]); + + if (dms_CreateCRC(b1,0, THLEN-2) != hcrc) + return ERR_THCRC; + + var number = (b1[2] << 8) | b1[3]; /* Number of track */ + var pklen1 = (b1[6] << 8) | b1[7]; /* Length of packed track data as in archive */ + var pklen2 = (b1[8] << 8) | b1[9]; /* Length of data after first unpacking */ + var unpklen = (b1[10] << 8) | b1[11]; /* Length of data after subsequent rle unpacking */ + var flags = b1[12]; /* control flags */ + var cmode = b1[13]; /* compression mode used */ + var usum = (b1[14] << 8) | b1[15]; /* Track Data CheckSum AFTER unpacking */ + var dcrc = (b1[16] << 8) | b1[17]; /* Track Data CRC BEFORE unpacking */ + + //if (DMS_LOG) SAEF_log("DMS() track=%d\n", number); + + if (DMS_LOG) { + var out = ""; + if (number == 80) + out += " FileID "; + else if (number == 0xffff) + out += " Banner "; + else if ((number == 0) && (unpklen == 1024)) + out += " FakeBB "; + else + out += sprintf(" %2d ", number); + + out += sprintf("%5d %5d %s %04X %04X %04X %0d", pklen1, unpklen, modes[cmode], usum, hcrc, dcrc, flags); + SAEF_log(out); + } + + if ((pklen1 > TRACK_BUFFER_LEN) || (pklen2 > TRACK_BUFFER_LEN) || (unpklen > TRACK_BUFFER_LEN)) + return ERR_BIGTRACK; + + if (SAEF_ZFile_fread(b1,0, 1, pklen1, fi) != pklen1) + return ERR_SREAD; + + if (dms_CreateCRC(b1,0, pklen1) != dcrc) { + log_error(number); + crcerr = 1; + } + /* track 80 is FILEID.DIZ, track 0xffff (-1) is Banner */ + /* and track 0 with 1024 bytes only is a fake boot block with more advertising */ + /* FILE_ID.DIZ is never encrypted */ + + //if (pwd && (number!=80)) dms_decrypt(b1,pklen1); ORG + + var normaltrack = false; + if ((cmd == CMD_UNPACK) && (number < 80) && (unpklen > 2048)) { + //memset(b2, 0, unpklen); + SAEF_memset(b2,0, 0, unpklen); + if (!crcerr) + Unpack_Track(b1, b2, pklen2, unpklen, cmode, flags, number, pklen1, usum, dmsflags & DMSFLAG_ENCRYPTED); + + if (number == 0 && SAEF_ZFile_ftell(fo) == 512 * 22) { + // did we have another cylinder 0 already? + SAEF_ZFile_fseek(fo, 0, SEEK_SET); + //uae_u8 *p = xcalloc (uae_u8, 512 * 22); + var p = new Uint8Array(512 * 22); + SAEF_ZFile_fread(p,0, 512 * 22, 1, fo); + addextra("BigFakeBootBlock", extra, p, 512 * 22); + //xfree(p); + delete p; + } + SAEF_ZFile_fseek(fo, number * 512 * 22 * ((dmsflags & DMSFLAG_HD) ? 2 : 1), SEEK_SET); + if (SAEF_ZFile_fwrite(b2,0, 1, unpklen, fo) != unpklen) + return ERR_CANTWRITE; + normaltrack = true; + } else if (number == 0 && unpklen == 1024) { + b2.set(0, 0, unpklen); //memset(b2, 0, unpklen); + if (!crcerr) + Unpack_Track(b1, b2, pklen2, unpklen, cmode, flags, number, pklen1, usum, dmsflags & DMSFLAG_ENCRYPTED); + addextra("FakeBootBlock", extra, b2, unpklen); + } + + if (crcerr) + return NO_PROBLEM; + + if (number == 0xffff) { + Unpack_Track(b1, b2, pklen2, unpklen, cmode, flags, number, pklen1, usum, dmsflags & DMSFLAG_ENCRYPTED); + if (extra) + addextra("Banner", extra, b2, unpklen); + + printbandiz(b2, unpklen); + } + + if (number == 80) { + Unpack_Track(b1, b2, pklen2, unpklen, cmode, flags, number, pklen1, usum, dmsflags & DMSFLAG_ENCRYPTED); + if (extra) + addextra("FILEID.DIZ", extra, b2, unpklen); + + printbandiz(b2, unpklen); + } + + if (!normaltrack) + Init_Decrunchers(); + + return NO_PROBLEM; + } + + function DMS_Process_File(fi, fo, cmd, opt, PCRC, pwd, part, extra) { + passfound = 0; + passretries = 2; + /*UCHAR *b1 = xcalloc(UCHAR,TRACK_BUFFER_LEN); + if (!b1) return ERR_NOMEMORY; + UCHAR *b2 = xcalloc(UCHAR,TRACK_BUFFER_LEN); + if (!b2) { + free(b1); + return ERR_NOMEMORY; + } + dms_text = xcalloc(UCHAR,TEMP_BUFFER_LEN); + if (!dms_text) { + free(b1); + free(b2); + return ERR_NOMEMORY; + }*/ + b1 = new Uint8Array(TRACK_BUFFER_LEN); + b2 = new Uint8Array(TRACK_BUFFER_LEN); + dms_text = new Uint8Array(TEMP_BUFFER_LEN); + + if (SAEF_ZFile_fread(b1,0, 1, HEADLEN, fi) != HEADLEN) { + /*free(b1); + free(b2); + free(dms_text);*/ + dms_text = null; + return ERR_SREAD; + } + + /* Check the first 4 bytes of file to see if it is "DMS!" */ + //if ((b1[0] != 'D') || (b1[1] != 'M') || (b1[2] != 'S') || (b1[3] != '!')) { + if (!(b1[0] == 68 && b1[1] == 77 && b1[2] == 83 && b1[3] == 33)) { /* DMS! */ + /*free(b1); + free(b2); + free(dms_text);*/ + dms_text = null; + return ERR_NOTDMS; + } + + /* Header CRC */ + var hcrc = (b1[HEADLEN - 2] << 8) | b1[HEADLEN - 1]; + if (hcrc != dms_CreateCRC(b1,4, HEADLEN - 6)) { + /*free(b1); + free(b2); + free(dms_text);*/ + dms_text = null; + return ERR_HCRC; + } + + var geninfo = (b1[10] << 8) | b1[11]; /* General info about archive */ + var date = (((b1[12]) << 24) | ((b1[13]) << 16) | ((b1[14]) << 8) | b1[15]) >>> 0; /* date in standard UNIX/ANSI format */ + var low = (b1[16] << 8) | b1[17]; /* Lowest track in archive. May be incorrect if archive is "appended" */ + var high = (b1[18] << 8) | b1[19]; /* Highest track in archive. May be incorrect if archive is "appended" */ + + if (part && low < 30) { + /*free(b1); + free(b2); + free(dms_text);*/ + dms_text = null; + return DMS_FILE_END; + } + + var pkfsize = (((b1[21]) << 16) | ((b1[22]) << 8) | b1[23]) >>> 0; /* Length of total packed data as in archive */ + var unpkfsize = (((b1[25]) << 16) | ((b1[26]) << 8) | b1[27]) >>> 0; /* Length of unpacked data. Usually 901120 bytes */ + + var c_version = (b1[46] << 8) | b1[47]; /* version of DMS used to generate it */ + var disktype = (b1[50] << 8) | b1[51]; /* Type of compressed disk */ + var cmode = (b1[52] << 8) | b1[53]; /* Compression mode mostly used in this archive */ + + PWDCRC = PCRC; + + if (DMS_LOG) { + var pv = Math.floor(c_version / 100); + SAEF_log(" Created with DMS version %d.%02d %s\n", pv, c_version - pv * 100, (geninfo & 0x80) ? "Registered" : "Evaluation"); + SAEF_log(" Creation date : %s", ctime(date)); + SAEF_log(" Lowest track in archive : %d\n", low); + SAEF_log(" Highest track in archive : %d\n", high); + SAEF_log(" Packed data size : %d\n", pkfsize); + SAEF_log(" Unpacked data size : %d\n", unpkfsize); + + var out = " Disk type of archive : "; + /* The original DMS from SDS software (DMS up to 1.11) used other values */ + /* in disk type to indicate formats as MS-DOS, AMax and Mac, but it was */ + /* not suported for compression. It was for future expansion and was never */ + /* used. The newer versions of DMS made by ParCon Software changed it to */ + /* add support for new Amiga disk types. */ + switch (disktype) { + case 0: + case 1: + /* Can also be a non-dos disk */ + out += "AmigaOS 1.0 OFS\n"; + break; + case 2: + out += "AmigaOS 2.0 FFS\n"; + break; + case 3: + out += "AmigaOS 3.0 OFS / International\n"; + break; + case 4: + out += "AmigaOS 3.0 FFS / International\n"; + break; + case 5: + out += "AmigaOS 3.0 OFS / Dir Cache\n"; + break; + case 6: + out += "AmigaOS 3.0 FFS / Dir Cache\n"; + break; + case 7: + out += "FMS Amiga System File\n"; + break; + default: + out += "Unknown\n"; + } + SAEF_log(out); + + out = " Compression mode used : "; + if (cmode > 6) + out += "Unknown !\n"; + else + out += modes[cmode] + "\n"; + SAEF_log(out); + + out = " General info : "; + if ((geninfo == 0) || (geninfo == 0x80)) out += "None"; + if (geninfo & 1) out += "NoZero "; + if (geninfo & 2) out += "Encrypted "; + if (geninfo & 4) out += "Appends "; + if (geninfo & 8) out += "Banner "; + if (geninfo & 16) out += "HD "; + if (geninfo & 32) out += "MS-DOS "; + if (geninfo & 64) out += "DMS_DEV_Fixed "; + if (geninfo & 256) out += "FILEID.DIZ"; + out += "\n"; + SAEF_log(out); + + SAEF_log(" Info Header CRC : %04X\n\n", hcrc); + } + + if (disktype == 7) { + /* It's not a DMS compressed disk image, but a FMS archive */ + /*free(b1); + free(b2); + free(dms_text);*/ + dms_text = null; + return ERR_FMS; + } + + if (DMS_LOG) { + SAEF_log(" Track Plength Ulength Cmode USUM HCRC DCRC Cflag\n"); + SAEF_log(" ------ ------- ------- ------ ---- ---- ---- -----\n"); + } + + // if (((cmd==CMD_UNPACK) || (cmd==CMD_SHOWBANNER)) && (geninfo & 2) && (!pwd)) + // return ERR_NOPASSWD; + + var ret = NO_PROBLEM; + + Init_Decrunchers(); + + if (cmd != CMD_VIEW) { + if (cmd == CMD_SHOWBANNER) /* Banner is in the first track */ + ret = Process_Track(fi, null, b1, b2, cmd, opt, geninfo, extra); + else { + Init_Decrunchers(); + for (;;) { + ret = Process_Track(fi, fo, b1, b2, cmd, opt, geninfo, extra); + if (ret == DMS_FILE_END) + break; + if (ret == NO_PROBLEM) + continue; + break; + /*#if 0 + int ok = 0; + while (!ok) { + uae_u8 b1[THLEN]; + + if (SAEF_ZFile_fread(b1,1,THLEN,fi) != 1) { + SAEF_log(_T("DMS() unexpected end of file\n")); + break; + } + SAEF_log(_T("DMS() corrupted track, searching for next track header..\n")); + if (b1[0] == 'T' && b1[1] == 'R') { + USHORT hcrc = (USHORT)((b1[THLEN-2] << 8) | b1[THLEN-1]); + if (CreateCRC(b1,(ULONG)(THLEN-2)) == hcrc) { + SAEF_log(_T("DMS() found checksum correct track header, retrying..\n")); + SAEF_ZFile_fseek (fi, SEEK_CUR, -THLEN); + ok = 1; + break; + } + } + if (!ok) + SAEF_ZFile_fseek (fi, SEEK_CUR, -(THLEN - 1)); + } + #endif*/ + } + } + } + if ((cmd == CMD_VIEWFULL) || (cmd == CMD_SHOWDIZ) || (cmd == CMD_SHOWBANNER)) + SAEF_log("\n"); + + if (ret == DMS_FILE_END) + ret = NO_PROBLEM; + + /* Used to give an error message, but I have seen some DMS */ + /* files with texts or zeros at the end of the valid data */ + /* So, when we find something that is not a track header, */ + /* we suppose that the valid data is over. And say it's ok. */ + if (ret == ERR_NOTTRACK) + ret = NO_PROBLEM; + + /*free(b1); + free(b2); + free(dms_text);*/ + dms_text = null; + return ret; + } + + this.DMS2ADF = function(z, index, retcode) { + if (typeof index == "undefined") index = 0; + if (typeof retcode == "undefined") retcode = null; + //static int recursive; + var orgname = SAEF_ZFile_getname(z); + var newname = ""; + var zextra = new Array(DMS_MAX_EXTRA); //zfile * + for (var vi = 0; vi < DMS_MAX_EXTRA; vi++) + zextra[vi] = null; + + //if (checkwrite(z, retcode)) return null; + //if (recursive) return null; + + var ext = orgname.lastIndexOf('.'); + if (ext != -1) { + newname = orgname.substr(0, ext); + newname += ".ADF"; + } else + newname = orgname + ".ADF"; + + var zo = SAEF_ZFile_fopen_empty(z, newname, 1760 * 512); + if (zo === null) + return null; + + pass = 0; + var ret = DMS_Process_File(z, zo, CMD_UNPACK, OPT_VERBOSE, 0, null, false, zextra); + if (ret == NO_PROBLEM) { // || ret == DMS_FILE_END) { + /*var off = SAEF_ZFile_ftell(zo); + if (off >= Math.floor(1760 * 512 / 3) && off <= Math.floor(1760 * 512 * 3 / 4)) { // possible split dms? + if (_tcslen (orgname) > 5) { + TCHAR *s = orgname + _tcslen (orgname) - 5; + if (!_tcsicmp (s, _T("a.dms"))) { + TCHAR *fn2 = my_strdup (orgname); + struct zfile *z2; + fn2[_tcslen (fn2) - 5]++; + recursive++; + z2 = SAEF_ZFile_fopen(fn2, _T("rb"), z->zfdmask); + recursive--; + if (z2) { + ret = DMS_Process_File(z2, zo, CMD_UNPACK, OPT_VERBOSE, 0, null, true, null); + SAEF_ZFile_fclose (z2); + } + xfree (fn2); + } + } + }*/ + + SAEF_ZFile_fseek(zo, 0, SEEK_SET); + if (index > 0) { + SAEF_ZFile_fclose(zo); + zo = null; + for (var i = 0; i < DMS_MAX_EXTRA && zextra[i]; i++); + if (index > i) { + //goto end; + for (i = 0; i < DMS_MAX_EXTRA; i++) + SAEF_ZFile_fclose(zextra[i]); + return zo; + } + zo = zextra[index - 1]; + zextra[index - 1] = null; + } + + //if (retcode !== null) *retcode = 1; + + SAEF_ZFile_fclose(z); + z = null; + + SAEF_log("DMS() converted '%s' to '%s'", orgname, newname); + } else { + SAEF_ZFile_fclose(zo); + zo = null; + + //SAEF_warn("DMS() error converting '%s' (%d)", orgname, ret); + alert(sprintf("Can't convert '%s' to ADF. (error %d)", orgname, ret)); + } + //end: + for (var i = 0; i < DMS_MAX_EXTRA; i++) + SAEF_ZFile_fclose(zextra[i]); + + return zo; + } +} diff --git a/sae/events.js b/sae/events.js index a9807fd..6723dce 100644 --- a/sae/events.js +++ b/sae/events.js @@ -1,641 +1,740 @@ -/************************************************************************** -* SAE - Scripted Amiga Emulator -* -* 2012-2015 Rupert Hausberger -* -* https://github.com/naTmeg/ScriptedAmigaEmulator -* -**************************************************************************/ +/*------------------------------------------------------------------------- +| SAE - Scripted Amiga Emulator +| https://github.com/naTmeg/ScriptedAmigaEmulator +| +| Copyright (C) 2012-2016 Rupert Hausberger +| +| This program is free software; you can redistribute it and/or +| modify it under the terms of the GNU General Public License +| as published by the Free Software Foundation; either version 2 +| of the License, or (at your option) any later version. +| +| This program is distributed in the hope that it will be useful, +| but WITHOUT ANY WARRANTY; without even the implied warranty of +| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +| GNU General Public License for more details. +| +| Note: ported from WinUAE 3.2.x +-------------------------------------------------------------------------*/ +/* global constants */ -function Event1() { - this.active = false; - this.evtime = 0; - this.oldcycles = 0; - this.handler = function(v) {}; -} +const SAEC_Events_CYCLE_UNIT = 512; +const SAEC_Events_CYCLE_UNIT_INV = 1.0 / SAEC_Events_CYCLE_UNIT; /* mul is always faster than div */ +const SAEC_Events_CYCLE_MAX = 0x100000000 * SAEC_Events_CYCLE_UNIT; -function Event2() { - this.active = false; - this.evtime = 0; - this.handler = function(v) {}; - this.data = null; -} +/*---------------------------------*/ -function Events() { - const SYNCBASE = 1000; +const SAEC_Events_EV_CIA = 0; +const SAEC_Events_EV_AUDIO = 1; +const SAEC_Events_EV_HSYNC = 2; - this.eventtab = null; - this.eventtab2 = null; - this.currcycle = 0; +const SAEC_Events_EV2_BLITTER = 0; +const SAEC_Events_EV2_DISK = 1; + +const SAEC_Events_syncbase = 1000000; + +/*---------------------------------*/ + +/*const SAEC_Events_cycle_line_REFRESH = 1; +const SAEC_Events_cycle_line_STROBE = 2; +const SAEC_Events_cycle_line_MISC = 3; +const SAEC_Events_cycle_line_SPRITE = 4; +const SAEC_Events_cycle_line_COPPER = 5; +const SAEC_Events_cycle_line_BLITTER = 6; +const SAEC_Events_cycle_line_CPU = 7; +//const SAEC_Events_cycle_line_CPUNASTY = 8; +const SAEC_Events_cycle_line_COPPER_SPECIAL = 0x10; +const SAEC_Events_cycle_line_MASK = 0x0f;*/ + +/*---------------------------------*/ +/* global references */ + +var SAER_Events_eventtab = null; + +//var SAER_Events_cycle_line = null; + +/*---------------------------------*/ +/* global variables */ + +var SAEV_Events_currcycle = 0; +var SAEV_Events_bogusframe = 0; +var SAEV_Events_timeframes = 0; +var SAEV_Events_hsync_counter = 0; +var SAEV_Events_vsync_counter = 0; +var SAEV_Events_frameskiptime = 0; +var SAEV_Events_reflowtime = 0; //OWN + +/*---------------------------------*/ + +function SAEO_Events() { + const EV_MISC = 3; + const EV_MAX = 4; + function Event() { + this.active = false; + this.evtime = 0; + this.oldcycles = 0; + this.handler = null; + }; + var eventtab = new Array(EV_MAX); for (i = 0; i < EV_MAX; i++) eventtab[i] = new Event(); + SAER_Events_eventtab = eventtab; + + const EV2_MISC = 2; + const EV2_MAX = 12; + function Event2() { + this.active = false; + this.evtime = 0; + this.data = null; + this.handler = null; + }; + var eventtab2 = new Array(EV2_MAX); for (i = 0; i < EV2_MAX; i++) eventtab2[i] = new Event2(); + + //var currcycle = 0; -> SAEV_Events_currcycle var nextevent = 0; - var nextevent2 = 0; - - var dmal = 0; - var dmal_hpos = 0; - - var vsynctimebase = 0; - var vsyncmintime = 0; - var vsyncmaxtime = 0; - var vsyncwaittime = 0; - var vsynctimeperline = 0; - var is_syncline = 0; - var is_syncline_end = 0; - //var hsync_counter = 0; - //var vsync_counter = 0; - - const MAVG_VSYNC_SIZE = 128; - var ma_frameskipt = new MAvg(MAVG_VSYNC_SIZE); - - const FPSCOUNTER_MAVG_SIZE = 10; - var fps_mavg = new MAvg(FPSCOUNTER_MAVG_SIZE); - var idle_mavg = new MAvg(FPSCOUNTER_MAVG_SIZE); - var timeframes = 0; - var lastframetime = 0; - var idletime = 0; - var frametime = 0; - var frameskiptime = 0; + var is_syncline = 0, is_syncline_end = 0; + //var vblank_found_chipset = false; + //var sleeps_remaining = 0; var linecounter = 0; - var vsync_rendered = false; - var frame_rendered = false; - var frame_shown = false; + //var syncbase = 0; -> SAEC_Events_syncbase + var vsyncmintime = 0, vsyncmaxtime = 0, vsyncwaittime = 0; + var vsynctimebase = 0; + //var rpt_did_reset = 0; - var vsyncresume = false; + //var frameskiptime = 0; -> SAEV_Events_frameskiptime + var vsynctimeperline = 0; //global - /*---------------------------------*/ - - this.setup = function () { - if (this.eventtab === null) { - this.eventtab = new Array(EV_MAX); - for (var i = 0; i < EV_MAX; i++) - this.eventtab[i] = new Event1(); + var dmal = 0, dmal_hpos = 0; //u16 - this.eventtab[EV_CIA].handler = function () { - AMIGA.cia.handler(); - }; - this.eventtab[EV_AUDIO].handler = function () { - AMIGA.audio.handler(); - }; - this.eventtab[EV_MISC].handler = function () { - AMIGA.events.misc_handler(); - }; - this.eventtab[EV_HSYNC].handler = function () { - AMIGA.events.hsync_handler(); - } - } - if (this.eventtab2 === null) { - this.eventtab2 = new Array(EV2_MAX); - for (var i = 0; i < EV2_MAX; i++) - this.eventtab2[i] = new Event2(); + //in framewait() + const MAVG_VSYNC_SIZE = 128; + var ma_frameskipt = new SAEO_MAvg(MAVG_VSYNC_SIZE); + //var ma_adjust = new mavg_data(); + //var ma_legacy = new mavg_data(); + //var ma_skip = new mavg_data(); + var ma_reflowt = new SAEO_MAvg(10); //OWN + //var vsync_time = 0; - this.eventtab2[EV2_BLITTER].handler = function (data) { - AMIGA.blitter.handler(data); - }; - this.eventtab2[EV2_DISK].handler = function (data) { - AMIGA.disk.handler(data); - }; - this.eventtab2[EV2_DMAL].handler = function (data) { - AMIGA.events.dmal_handler(data); - } + //in MISC_handler() + var dorecheck = false; + var recursive = 0; + + /* Statistics */ + const FPSCOUNTER_MAVG_SIZE = 10 + var fps_mavg = new SAEO_MAvg(FPSCOUNTER_MAVG_SIZE); + var idle_mavg = new SAEO_MAvg(FPSCOUNTER_MAVG_SIZE); + + //var bogusframe = 0; //-> SAEV_Events_bogusframe + //var timeframes = 0; //-> SAEV_Events_timeframes + var frametime = 0, lastframetime = 0; //global + var idletime = 0; //global + //var hsync_counter = 0; -> SAEV_Events_hsync_counter + //var vsync_counter = 0; -> SAEV_Events_vsync_counter + + //event2_newevent_xx() + var nextno = EV2_MISC; + + const PISSOFF_NOJIT_VALUE = 256 * SAEC_Events_CYCLE_UNIT; + var pissoff = 0; + //#define countdown pissoff + + //#ifdef CPUEMU_13 + //var cycle_line = new Uint8Array(256 + 1); + //SAER_Events_cycle_line = cycle_line; + //#endif + + /*-----------------------------------------------------------------------*/ + + this.reset = function() { //init_eventtab() + if (eventtab[SAEC_Events_EV_HSYNC].handler === null) { //OWN + eventtab[SAEC_Events_EV_CIA].handler = function() { SAER.cia.handler(); }; + eventtab[SAEC_Events_EV_HSYNC].handler = function() { SAER.playfield.hsync_handler(); }; + eventtab[SAEC_Events_EV_AUDIO].handler = function() { SAER.audio.handler(); }; + eventtab[EV_MISC].handler = MISC_handler; + + eventtab2[SAEC_Events_EV2_BLITTER].handler = function(data) { SAER.blitter.handler(data); }; + eventtab2[SAEC_Events_EV2_DISK].handler = function(data) { SAER.disk.handler(data); }; } - this.calc_vsynctimebase(AMIGA.config.video.ntsc ? 60 : 50); - }; - - this.reset = function () { - dmal = 0; - dmal_hpos = 0; - - this.currcycle = 0; - nextevent = CYCLE_MAX; - nextevent2 = EV2_MISC; - - vsynctimebase = 0; - vsyncmintime = 0; - vsyncmaxtime = 0; - vsyncwaittime = 0; - vsynctimeperline = 0; - is_syncline = 0; - is_syncline_end = 0; - - this.fpscounter_reset(); - + nextevent = 0; + nextno = EV2_MISC; //OWN for (var i = 0; i < EV_MAX; i++) { - this.eventtab[i].active = false; - this.eventtab[i].evtime = 0; - this.eventtab[i].oldcycles = 0; + eventtab[i].active = false; + eventtab[i].oldcycles = SAEV_Events_currcycle; } - for (var i = 0; i < EV2_MAX; i++) { - this.eventtab2[i].active = false; - this.eventtab2[i].evtime = 0; - } - this.eventtab[EV_HSYNC].evtime = 227 * CYCLE_UNIT; - /* 0xe3 */ - this.eventtab[EV_HSYNC].active = true; + eventtab[SAEC_Events_EV_HSYNC].evtime = SAEV_Events_currcycle + SAER.playfield.get_maxhpos() * SAEC_Events_CYCLE_UNIT; + eventtab[SAEC_Events_EV_HSYNC].active = true; + + for (i = 0; i < EV2_MAX; i++) + eventtab2[i].active = false; this.schedule(); - }; - - this.calc_vsynctimebase = function (hz) { - vsynctimebase = Math.floor(SYNCBASE / hz); - }; - - /*---------------------------------*/ - this.hpos = function () { - return Math.floor((this.currcycle - this.eventtab[EV_HSYNC].oldcycles) * CYCLE_UNIT_INV); - }; - - this.cycles_in_range = function (endcycles) { - return (endcycles - this.currcycle > 0); - }; + //OWN + dorecheck = false; + recursive = 0; + //nextno = EV2_MISC; + fpscounter_reset(); + ma_frameskipt.clr(); + ma_reflowt.clr(); + //reset_frame_rate_hack(); + //sleeps_remaining = 0; + linecounter = 0; + } - /*---------------------------------*/ + this.clr_dmal = function() { + dmal = 0; + } - this.schedule = function () { - var mintime = CYCLE_MAX; + this.pauseResume = function(pause) { + if (pause) { + SAER.gui.data.fps = 0; + SAER.gui.data.idle = 0; + SAER.gui.fps(0, 0, 1); + } else { + dmal = 0; + fpscounter_reset(); + ma_frameskipt.clr(); + } + } + /*-----------------------------------------------------------------------*/ + + this.reset_frame_rate_hack = function() { + if (SAEV_config.cpu.speed < 0) { + //rpt_did_reset = 1; + is_syncline = 0; + vsyncmintime = SAEF_now() + vsynctimebase; + //SAEF_log("events.reset_frame_rate_hack() %d", vsyncmintime); + } + } + this.calc_vsynctimebase = function(hz) { + vsynctimebase = SAEC_Events_syncbase / hz >>> 0; + SAEF_log("events.calc_vsynctimebase() %d us (%f)", vsynctimebase, hz); + this.reset_frame_rate_hack(); + return vsynctimebase; + } + + this.schedule = function() { + var mintime = SAEC_Events_CYCLE_MAX; for (var i = 0; i < EV_MAX; i++) { - if (this.eventtab[i].active) { - var evtime = this.eventtab[i].evtime - this.currcycle; - if (evtime < mintime) mintime = evtime; + if (eventtab[i].active) { + var eventtime = eventtab[i].evtime - SAEV_Events_currcycle; + if (eventtime < mintime) + mintime = eventtime; } } - nextevent = this.currcycle + mintime; - }; - - this.cycle = function (cycles) { - if (vsyncresume) { - vsyncresume = false; - this.hsync_handler_post(1); - } + nextevent = SAEV_Events_currcycle + mintime; + } - while ((nextevent - this.currcycle) <= cycles) { + /*this.get_cycles = function() { //OPT inline ok + return SAEV_Events_currcycle; + } + this.set_cycles = function(x) { + SAEV_Events_currcycle = x; + eventtab[SAEC_Events_EV_HSYNC].oldcycles = x; + } + this.cycles_in_range = function(endcycles) { //OPT inline ok, used in disk.DSKBYTR() + return endcycles - SAEV_Events_currcycle > 0; + }*/ + + /*function current_hpos_safe() { //OPT inline ok + return ((SAEV_Events_currcycle - eventtab[SAEC_Events_EV_HSYNC].oldcycles) * SAEC_Events_CYCLE_UNIT_INV) >>> 0; + }*/ + this.current_hpos = function() { + //var hp = current_hpos_safe(); + var hp = ((SAEV_Events_currcycle - eventtab[SAEC_Events_EV_HSYNC].oldcycles) * SAEC_Events_CYCLE_UNIT_INV) >>> 0; + if (hp < 0 || hp > 256) { + SAEF_error("events.current_hpos() hpos = %d !?", hp); + hp = 0; + } + return hp; + } + + /*-----------------------------------------------------------------------*/ + + this.do_cycles = function(cycles_to_add) { //do_cycles_slow() + if ((pissoff -= cycles_to_add) >= 0) + return; + + cycles_to_add = -pissoff; + pissoff = 0; + + //if (cycles_to_add == 0) SAEF_warn("event.do_cycles() cycles_to_add == 0"); + + while ((nextevent - SAEV_Events_currcycle) <= cycles_to_add) { + // Keep only CPU emulation running while waiting for sync point. if (is_syncline) { - var rpt = read_processor_time(); - if (is_syncline > 0) { - var v = rpt - vsyncmintime; - var v2 = rpt - is_syncline_end; - if (v > vsynctimebase || v < -vsynctimebase) v = 0; - if (v < 0 && v2 < 0) return; - } else if (is_syncline < 0) { - var v = rpt - is_syncline_end; - if (v < 0) return; - } + //if (!vblank_found_chipset) { + if (is_syncline > 0) { + var rpt = SAEF_now(); + var v = rpt - vsyncmintime; + var v2 = rpt - is_syncline_end; + if (v > vsynctimebase || v < -vsynctimebase) v = 0; + if (v < 0 && v2 < 0) { + pissoff = PISSOFF_NOJIT_VALUE; + return; + } + } else if (is_syncline < 0) { + var rpt = SAEF_now(); + var v = rpt - is_syncline_end; + if (v < 0) { + pissoff = PISSOFF_NOJIT_VALUE; + return; + } + } + //} is_syncline = 0; } - cycles -= nextevent - this.currcycle; - this.currcycle = nextevent; + cycles_to_add -= nextevent - SAEV_Events_currcycle; + SAEV_Events_currcycle = nextevent; for (var i = 0; i < EV_MAX; i++) { - if (this.eventtab[i].active && this.eventtab[i].evtime == this.currcycle) - this.eventtab[i].handler(this.eventtab[i].data); + if (eventtab[i].active && eventtab[i].evtime == SAEV_Events_currcycle) { + /*if (eventtab[i].handler === null) { + SAEF_error("events.eventtab[%d].handler is null!", i); + eventtab[i].active = false; + } else*/ + eventtab[i].handler(); + } } this.schedule(); } - this.currcycle += cycles; - }; + SAEV_Events_currcycle += cycles_to_add; + } + this.do_cycles_post = function(cycles, v) { + this.do_cycles(cycles); + } - /*---------------------------------*/ - - var stack = { recursive:0, dorecheck:false }; + /*-----------------------------------------------------------------------*/ - this.misc_handler = function () { - //if (stack.recursive > 1) BUG.info('misc_handler() recursive %d', stack.recursive); - var mintime; - var ct = this.currcycle; + function MISC_handler() { + var mintime = SAEC_Events_CYCLE_MAX; + var ct = SAEV_Events_currcycle; - if (stack.recursive) { - stack.dorecheck = true; + if (recursive) { + dorecheck = true; return; } - stack.recursive++; - this.eventtab[EV_MISC].active = false; + recursive++; + SAER_Events_eventtab[EV_MISC].active = false; var recheck = true; while (recheck) { recheck = false; - mintime = CYCLE_MAX; - + mintime = SAEC_Events_CYCLE_MAX; for (var i = 0; i < EV2_MAX; i++) { - if (this.eventtab2[i].active) { - if (this.eventtab2[i].evtime == ct) { - this.eventtab2[i].active = false; - this.eventtab2[i].handler(this.eventtab2[i].data); - - if (stack.dorecheck || this.eventtab2[i].active) { + if (eventtab2[i].active) { + if (eventtab2[i].evtime == ct) { + eventtab2[i].active = false; + eventtab2[i].handler(eventtab2[i].data); + if (dorecheck || eventtab2[i].active) { recheck = true; - stack.dorecheck = false; + dorecheck = false; } } else { - var eventtime = this.eventtab2[i].evtime - ct; + var eventtime = eventtab2[i].evtime - ct; if (eventtime < mintime) mintime = eventtime; } } } } - if (mintime != CYCLE_MAX) { - this.eventtab[EV_MISC].active = true; - this.eventtab[EV_MISC].oldcycles = ct; - this.eventtab[EV_MISC].evtime = ct + mintime; - this.schedule(); + if (mintime != SAEC_Events_CYCLE_MAX) { + SAER_Events_eventtab[EV_MISC].active = true; + SAER_Events_eventtab[EV_MISC].oldcycles = ct; + SAER_Events_eventtab[EV_MISC].evtime = ct + mintime; + SAER.events.schedule(); } - stack.recursive--; - }; + recursive--; + } - this.newevent2_x = function (t, data, func) { - var et = this.currcycle + t; - var no = nextevent2; - for (; ;) { - if (!this.eventtab2[no].active) - break; - - no++; - if (no == EV2_MAX) - no = EV2_MISC; - if (no == nextevent2) { - BUG.info('newevent2_x() out of events!'); - return; + this.event2_newevent_xx = function(no, t, data, func) { + var et = SAEV_Events_currcycle + t; + if (no < 0) { + no = nextno; + for (;;) { + if (!eventtab2[no].active) + break; + if (eventtab2[no].evtime == et && eventtab2[no].data == data && eventtab2[no].handler === func) + break; + no++; + if (no == EV2_MAX) + no = EV2_MISC; + if (no == nextno) { + SAEF_error("events.event2_newevent_xx() out of events!"); + return; + } } + nextno = no; } - nextevent2 = no; - - this.eventtab2[no].active = true; - this.eventtab2[no].evtime = et; - this.eventtab2[no].handler = func; - this.eventtab2[no].data = data; - this.misc_handler(); - }; - - this.newevent2 = function (t, data, func) { - if (t <= 0) + eventtab2[no].active = true; + eventtab2[no].evtime = et; + eventtab2[no].handler = func; + eventtab2[no].data = data; + MISC_handler(); + } + function event2_newevent_x(no, t, data, func) { + if (t <= 0) { func(data); - else - this.newevent2_x(t * CYCLE_UNIT, data, func); - }; - - this.newevent = function (id, t, data) { - this.eventtab2[id].active = true; - this.eventtab2[id].evtime = this.currcycle + t * CYCLE_UNIT; - this.eventtab2[id].data = data; - this.misc_handler(); - }; - - this.remevent = function (no) { - if (this.eventtab2[no].active) { - this.eventtab2[no].active = false; - //BUG.info('remevent() %d', no); + return; } - }; - - /*---------------------------------*/ - - this.dmal_emu = function (v) { - if (!(AMIGA.dmacon & DMAF_DMAEN)) + SAER.events.event2_newevent_xx(no, t * SAEC_Events_CYCLE_UNIT, data, func); + } + this.event2_newevent = function(no, t, data) { + event2_newevent_x(no, t, data, eventtab2[no].handler); + } + /*this.event2_newevent2 = function(t, data, func) { + event2_newevent_x(-1, t, data, func); + }*/ + + this.event2_remevent = function(no) { + eventtab2[no].active = false; + } + + /*-----------------------------------------------------------------------*/ + /* events dmal */ + + function dmal_emu(v) { + // Disk and Audio DMA bits are ignored by Agnus, Agnus only checks DMAL and master bit + if (!(SAEV_Custom_dmacon & SAEC_Custom_DMAF_DMAEN)) return; - //var hpos = this.hpos(); - var dat, pt; + var hpos = SAER.events.current_hpos(); if (v >= 6) { v -= 6; var nr = v >> 1; - pt = AMIGA.audio.getpt(nr, (v & 1) != 0); - //var dat = AMIGA.mem.load16_chip(pt); - dat = AMIGA.mem.chip.data[pt >>> 1]; - AMIGA.custom.last_value = dat; - AMIGA.audio.AUDxDAT(nr, dat); + var pt = SAER.audio.getpt(nr, (v & 1) != 0); + var dat = SAER_Memory_chipGet16_indirect(pt); + SAEV_Custom_last_value = dat; + SAER.audio.AUDxDAT(nr, dat); } else { var w = v & 1; - pt = AMIGA.disk.getpt(); + var pt = SAER.disk.getpt(); + // disk_fifostatus() needed in >100% disk speed modes if (w) { - if (AMIGA.disk.fifostatus() <= 0) { - //var dat = AMIGA.mem.load16_chip(pt); - dat = AMIGA.mem.chip.data[pt >>> 1]; - AMIGA.custom.last_value = dat; - AMIGA.disk.DSKDAT(dat); + // write to disk + if (SAER.disk.fifostatus() <= 0) { + var dat = SAER_Memory_chipGet16_indirect(pt); + SAEV_Custom_last_value = dat; + SAER.disk.DSKDAT(dat); } } else { - if (AMIGA.disk.fifostatus() >= 0) { - dat = AMIGA.disk.DSKDATR(); - //AMIGA.mem.store16_chip(pt, dat); - AMIGA.mem.chip.data[pt >>> 1] = dat; + // read from disk + if (SAER.disk.fifostatus() >= 0) { + var dat = SAER.disk.DSKDATR(); + SAER_Memory_chipPut16_indirect(pt, dat); } } } - }; + } - this.dmal_handler = function (v) { - while (dmal) { - if (dmal & 3) - this.dmal_emu(dmal_hpos + ((dmal & 2) ? 1 : 0)); - dmal_hpos += 2; - dmal >>>= 2; - } - this.remevent(EV2_DMAL); - }; - - this.dmal_hsync = function () { - if (dmal) BUG.info('dmal_hsync() DMAL error!? %04x', dmal); - dmal = AMIGA.audio.dmal(); - dmal <<= 6; - dmal |= AMIGA.disk.dmal(); + this.events_dmal_hsync = function() { + if (dmal) SAEF_error("events.events_dmal_hsync() DMAL error!? %04x", dmal); + dmal = SAER.audio.dmal(); + dmal = (dmal << 6) & 0xffff; + dmal |= SAER.disk.dmal(); if (dmal) { dmal_hpos = 0; - this.newevent(EV2_DMAL, 7, 13); + //SAER.events.event2_newevent2(7, 13, function(v) { + SAER.events.event2_newevent_xx(-1, 7 * SAEC_Events_CYCLE_UNIT, 13, function(v) { + while (dmal) { + if (dmal & 3) + dmal_emu(dmal_hpos + ((dmal & 2) ? 1 : 0)); + dmal_hpos += 2; + dmal >>>= 2; + } + }); } - }; + } + + /*-----------------------------------------------------------------------*/ + /* fps counter */ + + function fpscounter_reset() { //global + fps_mavg.clr(); + idle_mavg.clr(); + SAEV_Events_bogusframe = 2; + SAEV_Events_timeframes = 0; + lastframetime = SAEF_now(); + idletime = 0; + } + + this.fpscounter = function(frameok) { + var now = SAEF_now(); + var last = now - lastframetime; + lastframetime = now; + + if (SAEV_Events_bogusframe || last < 0) + return; + + fps_mavg.set(last); + idle_mavg.set(idletime); + idletime = 0; + + frametime += last; + SAEV_Events_timeframes++; + + if ((SAEV_Events_timeframes & 7) == 0) { + var avg = idle_mavg.get(); + var idle = 100.0 - (avg == 0 ? 0 : avg * 100 / vsynctimebase); + if (idle < 0) + idle = 0.0; + else if (idle > 100) + idle = 100.0; + + avg = fps_mavg.get(); + var fps = avg == 0 ? 0 : SAEC_Events_syncbase / avg; + if (fps > 999) + fps = 999.0; + + if (SAEV_Playfield_fake_vblank_hz > fps) idle *= SAEV_Playfield_fake_vblank_hz / fps; + //if (currprefs.turbo_emulation && idle < 100) idle = 100.0; + + SAER.gui.data.fps = fps; + //SAER.gui.data.idle = (int)idle; + SAER.gui.data.idle = idle; + SAER.gui.data.fps_color = frameok ? 0 : 1; + if ((SAEV_Events_timeframes & 15) == 0) { + //SAER.gui.fps(fps, (int)idle, frameok ? 0 : 1); + SAER.gui.fps(fps, idle, frameok ? 0 : 1); + } + } + } + + /*-----------------------------------------------------------------------*/ + /* synchronization */ + + this.framewait2_maximum = function(ll) { + //static int sleeps_remaining; + //if (is_last_line()) { + if (ll) { + /*sleeps_remaining = (165 - currprefs.cpu_idle) / 6; + if (sleeps_remaining < 0) + sleeps_remaining = 0; + // really last line, just run the cpu emulation until whole vsync time has been used + if (SAER.m68k.stopped && currprefs.cpu_idle) { + // CPU in STOP state: sleep if enough time left. + var rpt = SAEF_now(); + while (!vsync_isdone () && ~~vsyncmintime - ~~(rpt + vsynctimebase / 10) > 0 && ~~vsyncmintime - ~~rpt < vsynctimebase) { + //if (!execute_other_cpu(rpt + vsynctimebase / 10)) + SAEF_sleep(1); + rpt = SAEF_now(); + } + } else*/ if (SAEV_config.cpu.speedThrottle) { + vsyncmintime = SAEF_now(); // end of CPU emulation time + is_syncline = 0; + } else { + vsyncmintime = vsyncmaxtime; // emulate if still time left + is_syncline_end = SAEF_now() + vsynctimebase; // far enough in future, we never wait that long + is_syncline = 2; + } + } else { + //static int linecounter; + // end of scanline, run cpu emulation as long as we still have time + vsyncmintime += vsynctimeperline; + linecounter++; + is_syncline = 0; + //if (!vsync_isdone() && !currprefs.turbo_emulation) + { + if (vsyncmaxtime - vsyncmintime > 0) { + if (vsyncwaittime - vsyncmintime > 0) { + var rpt = SAEF_now(); + // Extra time left? Do some extra CPU emulation + if (vsyncmintime - rpt > 0) { + /*if (SAER.m68k.stopped && currprefs.cpu_idle && sleeps_remaining > 0) { + // STOP STATE: sleep. + SAEF_sleep(1); + sleeps_remaining--; + } else*/ { + is_syncline = 1; + // limit extra time + is_syncline_end = rpt + vsynctimeperline; + linecounter = 0; + } + } + } + if (!SAER_Playfield_isvsync()) { + // extra cpu emulation time if previous 10 lines without extra time. + if (!is_syncline && linecounter >= 10 && (!SAER.m68k.stopped)) { // || !currprefs.cpu_idle)) { + is_syncline = -1; + is_syncline_end = SAEF_now() + vsynctimeperline; + linecounter = 0; + } + } + } + } + } + } + this.framewait2_normal = function() { + vsyncmintime += vsynctimeperline; + //if (!vsync_isdone() && !currprefs.turbo_emulation) + { + var rpt = SAEF_now(); + // sleep if more than 2ms "free" time + //while (!vsync_isdone() && vsyncmintime - Math.floor(rpt + vsynctimebase / 10) > 0 && vsyncmintime - rpt < vsynctimebase) { + while (vsyncmintime - Math.floor(rpt + vsynctimebase / 10) > 0 && vsyncmintime - rpt < vsynctimebase) { + //if (!execute_other_cpu(rpt + vsynctimebase / 10)) + SAEF_sleep(1); + rpt = SAEF_now(); + //SAEF_log("*"); + } + } + } /*---------------------------------*/ - - function sleep(ms) { - var start = new Date().getTime(); - while ((new Date().getTime() - start) < ms) {} - } - - function read_processor_time() { - return (new Date().getTime()); - //return window.performance.now(); - //return window.performance.webkitNow(); - } function rpt_vsync(adjust) { - var curr_time = read_processor_time(); + var curr_time = SAEF_now(); var v = curr_time - vsyncwaittime + adjust; - if (v > SYNCBASE || v < -SYNCBASE) { + if (v > SAEC_Events_syncbase || v < -SAEC_Events_syncbase) { vsyncmintime = vsyncmaxtime = vsyncwaittime = curr_time; v = 0; } return v; } + /*function rtg_vsync() { + #ifdef PICASSO96 + var start = SAEF_now(); + picasso_handle_vsync(); + var end = SAEF_now(); + SAEV_Events_frameskiptime += end - start; + #endif + } + function rtg_vsynccheck() { + if (vblank_found_rtg) { + vblank_found_rtg = false; + rtg_vsync(); + } + }*/ - this.framewait = function () { - var clockadjust = 0; + this.framewait = function() { var curr_time; - - var frameskipt_avg = ma_frameskipt.set(frameskiptime); - frameskiptime = 0; + var start; + var vs = SAER_Playfield_isvsync_chipset(); + var status = 0; is_syncline = 0; - if (AMIGA.config.cpu.speed < 0) { - if (!frame_rendered) - frame_rendered = AMIGA.playfield.render_screen(false); + //static struct mavg_data ma_frameskipt; + var frameskipt_avg = ~~ma_frameskipt.set(SAEV_Events_frameskiptime); SAEV_Events_frameskiptime = 0; + var reflowt_avg = ~~ma_reflowt.set(SAEV_Events_reflowtime); - curr_time = read_processor_time(); + /*OWN stripped + if (vs > 0) {} else if (vs < 0) {}*/ - var adjust = 0; - if (Math.floor(curr_time - vsyncwaittime) > 0 && Math.floor(curr_time - vsyncwaittime) < (vsynctimebase >> 1)) + status = 1; + + var clockadjust = 0; + var vstb = vsynctimebase; + + if (SAEV_config.cpu.speed < 0) { //max + if (!SAEV_Playfield_frame_rendered && !SAEV_Playfield_picasso_on) + SAEV_Playfield_frame_rendered = SAER.video.render_screen(false); + + if (SAEV_config.cpu.speedThrottle) { + // this delay can safely overshoot frame time by 1-2 ms, following code will compensate for it. + for (;;) { + curr_time = SAEF_now(); + if (vsyncwaittime - curr_time <= 0 || vsyncwaittime - curr_time > 2 * vsynctimebase) + break; + //rtg_vsynccheck(); + SAEF_sleep(1); + } + } else + curr_time = SAEF_now(); + + var adjust = 0, max; + if (curr_time - vsyncwaittime > 0 && curr_time - vsyncwaittime < (vstb >> 1)) adjust += curr_time - vsyncwaittime; adjust += clockadjust; - - //console.log(adjust); - - vsyncwaittime = curr_time + vsynctimebase - adjust; + if (SAEV_config.cpu.speedThrottle) + max = Math.truncate(vstb * (1000.0 + SAEV_config.cpu.speedThrottle) / 1000.0 - adjust); + else + max = vstb - adjust; + vsyncwaittime = curr_time + vstb - adjust; vsyncmintime = curr_time; - var max = Math.floor(vsynctimebase - adjust); if (max < 0) { max = 0; vsynctimeperline = 1; } else - vsynctimeperline = Math.floor(max / (AMIGA.playfield.maxvpos_nom + 1)); + vsynctimeperline = max / (SAER.playfield.get_maxvpos_display() + 1) >>> 0; vsyncmaxtime = curr_time + max; + + //SAEF_info("%06d:%06d/%06d", adjust, vsynctimeperline, vstb); } else { - var start; - var t = 0; + const syncbase1000inv = 1.0 / (SAEC_Events_syncbase / 1000); //OWN + var t = reflowt_avg; //OWN - if (!frame_rendered) { - start = read_processor_time(); - frame_rendered = AMIGA.playfield.render_screen(false); - t = read_processor_time() - start; + if (!SAEV_Playfield_frame_rendered && !SAEV_Playfield_picasso_on) { + start = SAEF_now(); + SAEV_Playfield_frame_rendered = SAER.video.render_screen(false); + t += SAEF_now() - start; + } + start = SAEF_now(); + while (true) { //while (!currprefs.turbo_emulation) { + var v = rpt_vsync(clockadjust) * syncbase1000inv; //double + if (v >= -4) break; + //rtg_vsynccheck(); + SAEF_sleep(2); } - while (rpt_vsync(clockadjust) < -4)// / (SYNCBASE / 1000.0); - sleep(2); - - start = read_processor_time(); while (rpt_vsync(clockadjust) < 0) { + //rtg_vsynccheck(); } - idletime += read_processor_time() - start; + curr_time = SAEF_now(); + idletime += curr_time - start; - curr_time = read_processor_time(); vsyncmintime = curr_time; - vsyncmaxtime = vsyncwaittime = curr_time + vsynctimebase; - if (frame_rendered) { - frame_shown = AMIGA.playfield.show_screen(); - t += read_processor_time() - curr_time; + vsyncmaxtime = vsyncwaittime = curr_time + vstb; + + if (SAEV_Playfield_frame_rendered) { + SAER.video.show_screen(0); + t += SAEF_now() - curr_time; } t += frameskipt_avg; - - vsynctimeperline = Math.floor((vsynctimebase - t) / 3); + vsynctimeperline = ~~((vstb - t) / 3); if (vsynctimeperline < 0) vsynctimeperline = 0; - else if (vsynctimeperline > Math.floor(vsynctimebase / 3)) - vsynctimeperline = Math.floor(vsynctimebase / 3); - } - }; + else if (vsynctimeperline > vstb / 3 >>> 0) + vsynctimeperline = vstb / 3 >>> 0; - this.framewait2 = function () { - if (AMIGA.config.cpu.speed < 0) { - if (AMIGA.playfield.is_last_line()) { - /* really last line, just run the cpu emulation until whole vsync time has been used */ - vsyncmintime = vsyncmaxtime; - /* emulate if still time left */ - is_syncline_end = read_processor_time() + vsynctimebase; - /* far enough in future, we never wait that long */ - is_syncline = 1; - } else { - /* end of scanline, run cpu emulation as long as we still have time */ - vsyncmintime += vsynctimeperline; - linecounter++; - is_syncline = 0; - if (Math.floor(vsyncmaxtime - vsyncmintime) > 0) { - if (Math.floor(vsyncwaittime - vsyncmintime) > 0) { - var rpt = read_processor_time(); - /* Extra time left? Do some extra CPU emulation */ - if (Math.floor(vsyncmintime - rpt) > 0) { - is_syncline = 1; - /* limit extra time */ - is_syncline_end = rpt + vsynctimeperline; - linecounter = 0; - } - } - // extra cpu emulation time if previous 10 lines without extra time. - if (!is_syncline && linecounter >= 10) { - is_syncline = -1; - is_syncline_end = read_processor_time() + vsynctimeperline; - linecounter = 0; - } - } - } - } else { - if (AMIGA.playfield.vpos + 1 < AMIGA.playfield.maxvpos + AMIGA.playfield.lof_store && (AMIGA.playfield.vpos == Math.floor(AMIGA.playfield.maxvpos_nom / 3) || AMIGA.playfield.vpos == Math.floor(AMIGA.playfield.maxvpos_nom * 2 / 3))) { - vsyncmintime += vsynctimeperline; - var rpt = read_processor_time(); - // sleep if more than 2ms "free" time - while (Math.floor(vsyncmintime) - Math.floor(rpt + vsynctimebase / 10) > 0 && Math.floor(vsyncmintime - rpt) < vsynctimebase) { - sleep(1); - rpt = read_processor_time(); - //console.log('*'); - } + SAEV_Playfield_frame_shown = true; + } + return status != 0; + } + + /*-----------------------------------------------------------------------*/ + /* exact cycling */ + + /*this.alloc_cycle = function(hpos, type) { + //#ifdef CPUEMU_13 + //#if 0 + //if (cycle_line[hpos]) SAEF_log("events.alloc_cycle() hpos=%d, old=%d, new=%d", hpos, cycle_line[hpos], type); + //if ((type == SAEC_Events_cycle_line_COPPER) && (hpos & 1) && hpos != SAER.playfield.get_maxhpos() - 2) SAEF_log("events.alloc_cycle() odd %d cycle %d", hpos); + //if (!(hpos & 1) && (type == SAEC_Events_cycle_line_SPRITE || type == SAEC_Events_cycle_line_REFRESH || type == SAEC_Events_cycle_line_MISC)) SAEF_log("events.alloc_cycle() even %d cycle %d", type, hpos); + //#endif + cycle_line[hpos] = type; + //#endif + } + this.alloc_cycle_maybe = function(hpos, type) { + if ((cycle_line[hpos] & SAEC_Events_cycle_line_MASK) == 0) + this.alloc_cycle(hpos, type); + } + this.alloc_cycle_blitter = function(hpos, ptr, chnum) { + if (cycle_line[hpos] & SAEC_Events_cycle_line_COPPER_SPECIAL) { + //static int warned = 100; + var srcptr = SAER.copper.get_copxlc(); //cop_state.strobe == 1 ? cop1lc : cop2lc; + //if (warned > 0) + { + SAEF_warn("events.alloc_cycle_blitter() buggy copper cycle conflict with blitter ch %d", chnum); + //warned--; } + //if ((currprefs.cs_hacks & 1) && SAEV_config.cpu.model == SAEC_Config_CPU_Model_68000) + if (SAEV_config.cpu.model == SAEC_Config_CPU_Model_68000 && SAEV_config.chipset.blitter.cycle_exact) + ptr.val = srcptr; } - }; - - this.fpscounter_reset = function () { - timeframes = 0; - fps_mavg.clr(); - idle_mavg.clr(); - lastframetime = read_processor_time(); - idletime = 0; - }; - - this.fpscounter = function () { - var hz = AMIGA.playfield.vblank_hz; - - var now = read_processor_time(); - var last = now - lastframetime; - lastframetime = now; - - if (AMIGA.config.video.framerate > 1) { - last <<= 1; - hz /= 2; - } - - fps_mavg.set(last / 10); - idle_mavg.set(idletime / 10); - idletime = 0; - - frametime += last; - timeframes++; - - if ((timeframes & 7) == 0) { - var idle = 1000 - (idle_mavg.average == 0 ? 0.0 : idle_mavg.average * 1000.0 / vsynctimebase); - var fps = fps_mavg.average == 0 ? 0 : SYNCBASE * 10 / fps_mavg.average; - if (fps > 9999) fps = 9999; - if (idle < 0) idle = 0; - if (idle > 100 * 10) idle = 100 * 10; - if (hz * 10 > fps) idle *= (hz * 10 / fps); - - if ((timeframes & 15) == 0) { - AMIGA.config.hooks.fps(Math.round(fps * 0.1)); - AMIGA.config.hooks.cpu(Math.round(idle * 0.1)); - } - } - }; - - /*---------------------------------*/ - - this.hsync_handler_pre = function (onvsync) { - //var hpos = this.hpos(); - AMIGA.copper.sync_copper_with_cpu(AMIGA.playfield.maxhpos, 0); - AMIGA.playfield.hsync_handler_pre(); - AMIGA.disk.hsync(); - if (AMIGA.config.audio.enabled) - AMIGA.audio.hsync(); - //AMIGA.cia.hsync_prehandler(); //empty - //hsync_counter++; - AMIGA.playfield.hsync_handler_pre_next_vpos(onvsync); - - this.eventtab[EV_HSYNC].evtime = this.currcycle + AMIGA.playfield.maxhpos * CYCLE_UNIT; - this.eventtab[EV_HSYNC].oldcycles = this.currcycle; - }; - - this.vsync_handler_pre = function () { - //AMIGA.audio.vsync(); //empty - AMIGA.cia.vsync_prehandler(); - - if (!vsync_rendered) { - var start = read_processor_time(); - AMIGA.playfield.vsync_handle_redraw(); - frameskiptime += read_processor_time() - start; - //vsync_rendered = true; - } - this.framewait(); - if (!frame_rendered) - frame_rendered = AMIGA.playfield.render_screen(false); - if (frame_rendered && !frame_shown) - //frame_shown = AMIGA.playfield.show_screen(); - AMIGA.playfield.show_screen(); - - this.fpscounter(); - vsync_rendered = false; - frame_shown = false; - frame_rendered = false; - - AMIGA.playfield.checklacecount(null); - }; - - var cia_hsync = 256; - this.hsync_handler_post = function (onvsync) { - AMIGA.copper.last_copper_hpos = 0; - - var ciasyncs = !(AMIGA.playfield.bplcon0 & 2) || ((AMIGA.playfield.bplcon0 & 2) && AMIGA.config.chipset.genlock); - AMIGA.cia.hsync_posthandler(ciasyncs); - if (AMIGA.config.cia.tod > 0) { - cia_hsync -= 256; - if (cia_hsync <= 0) { - AMIGA.cia.vsync_posthandler(1); - cia_hsync += Math.floor((MAXVPOS_PAL * MAXHPOS_PAL * 50 * 256) / (AMIGA.playfield.maxhpos * (AMIGA.config.cia.tod == 2 ? 60 : 50))); - } - } else if (AMIGA.config.cia.tod == 0 && onvsync) - AMIGA.cia.vsync_posthandler(ciasyncs); - - AMIGA.playfield.hsync_handler_post(); - AMIGA.custom.last_value = 0xffff; - - if (!AMIGA.config.blitter.immediate && AMIGA.blitter.getState() != BLT_done && AMIGA.dmaen(DMAF_BPLEN) && AMIGA.playfield.getDiwstate() == DIW_WAITING_STOP) - AMIGA.blitter.slowdown(); - - if (onvsync) { - // vpos_count >= MAXVPOS just to not crash if VPOSW writes prevent vsync completely - /*if ((AMIGA.playfield.bplcon0 & 8) && !lightpen_triggered) { - vpos_lpen = AMIGA.playfield.vpos - 1; - hpos_lpen = AMIGA.playfield.maxhpos; - lightpen_triggered = 1; - }*/ - AMIGA.playfield.vpos = 0; - this.vsync_handler_post(); - AMIGA.playfield.vpos_count = 0; - } - if (AMIGA.config.chipset.agnus_dip) { - if (AMIGA.playfield.vpos == 1) - AMIGA.INTREQ_0(INT_VERTB); - } else { - if (AMIGA.playfield.vpos == 0) - AMIGA.INTREQ_0(INT_VERTB); - } - this.dmal_hsync(); - this.framewait2(); - AMIGA.playfield.hsync_handler_post_nextline_how(); - AMIGA.copper.reset2(); - - if (CUSTOM_SIMPLE) - AMIGA.playfield.do_sprites(0); - - //AMIGA.copper.check(2); - AMIGA.playfield.hsync_handler_post_diw_change(); - }; - - this.vsync_handler_post = function () { - //if ((AMIGA.intreq & 0x0020) && (AMIGA.intena & 0x0020)) BUG.info('vblank interrupt not cleared'); - AMIGA.disk.vsync(); - AMIGA.playfield.vsync_handler_post(); - }; - - this.hsync_handler = function() { - var vs = AMIGA.playfield.is_custom_vsync(); - this.hsync_handler_pre(vs); - if (vs) { - this.vsync_handler_pre(); - - //vsyncresume = true; throw new VSync(0, 'vsync'); - - AMIGA.state = ST_IDLE; - } - this.hsync_handler_post(vs); - } + this.alloc_cycle(hpos, SAEC_Events_cycle_line_BLITTER); + }*/ } - diff --git a/sae/expansion.js b/sae/expansion.js index 322185e..daf20c4 100644 --- a/sae/expansion.js +++ b/sae/expansion.js @@ -1,177 +1,1570 @@ -/************************************************************************** -* SAE - Scripted Amiga Emulator -* -* 2012-2015 Rupert Hausberger -* -* https://github.com/naTmeg/ScriptedAmigaEmulator -* -**************************************************************************/ +/*------------------------------------------------------------------------- +| SAE - Scripted Amiga Emulator +| https://github.com/naTmeg/ScriptedAmigaEmulator +| +| Copyright (C) 2012-2016 Rupert Hausberger +| +| This program is free software; you can redistribute it and/or +| modify it under the terms of the GNU General Public License +| as published by the Free Software Foundation; either version 2 +| of the License, or (at your option) any later version. +| +| This program is distributed in the hope that it will be useful, +| but WITHOUT ANY WARRANTY; without even the implied warranty of +| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +| GNU General Public License for more details. +| +| Note: ported from WinUAE 3.2.x +-------------------------------------------------------------------------*/ +/* global references */ -function Board_A2058() { - const MEM_8MB = 0x00; - const MEM_4MB = 0x07; - const MEM_2MB = 0x06; - const MEM_1MB = 0x05; - const MEM_512KB = 0x04; - //const MEM_256KB = 0x03; - //const MEM_128KB = 0x02; - //const MEM_64KB = 0x01; - - //const SAME_SLOT = 0x08; /* Next card is in the same Slot */ - //const ROM_CARD = 0x10; /* Card has valid ROM */ - const ADD_MEMORY = 0x20; /* Add Memory to List of Free Ram */ +var SAER_Expansion_expamem_bank = null; +var SAER_Expansion_z3fastmem_bank = null; - const ZORRO2 = 0xc0; /* Type of Expansion Card */ - //const ZORRO3 = 0x80; +/*---------------------------------*/ - const CARE_ADDR = 0x80; /* Adress HAS to be $200000-$9fffff */ +function SAEO_Expansion() { + const BOARD_AUTOCONFIG_Z2 = 2; + const BOARD_AUTOCONFIG_Z3 = 3; + const BOARD_NONAUTOCONFIG_BEFORE = 4; + const BOARD_NONAUTOCONFIG_AFTER_Z2 = 5; + const BOARD_NONAUTOCONFIG_AFTER_Z3 = 6; + const BOARD_IGNORE = 7; - const VENDOR_COMMODORE = 514; - const PRODUCT_A2058 = 10; + const MAX_EXPANSION_BOARD_SPACE = 16; + //const KS12_BOOT_HACK = 1; + //const EXP_DEBUG = 0; - this.info = function() { - //BUG.info('Board_A2058.info()'); - var type; - switch (AMIGA.mem.fast.size) { - case 0x080000: type = ZORRO2 + ADD_MEMORY + MEM_512KB; break; - case 0x100000: type = ZORRO2 + ADD_MEMORY + MEM_1MB; break; - case 0x200000: type = ZORRO2 + ADD_MEMORY + MEM_2MB; break; - case 0x400000: type = ZORRO2 + ADD_MEMORY + MEM_4MB; break; - case 0x800000: type = ZORRO2 + ADD_MEMORY + MEM_8MB; break; + /*---------------------------------*/ + /* 00 / 02 */ + /* er_Type */ + + const Z2_MEM_8MB = 0x00; /* Size of Memory Block */ + const Z2_MEM_4MB = 0x07; + const Z2_MEM_2MB = 0x06; + const Z2_MEM_1MB = 0x05; + const Z2_MEM_512KB = 0x04; + const Z2_MEM_256KB = 0x03; + const Z2_MEM_128KB = 0x02; + const Z2_MEM_64KB = 0x01; + /* extended definitions */ + const Z3_MEM_16MB = 0x00; + const Z3_MEM_32MB = 0x01; + const Z3_MEM_64MB = 0x02; + const Z3_MEM_128MB = 0x03; + const Z3_MEM_256MB = 0x04; + const Z3_MEM_512MB = 0x05; + const Z3_MEM_1GB = 0x06; + + const chainedconfig = 0x08; /* Next config is part of the same card */ + const rom_card = 0x10; /* ROM vector is valid */ + const add_memory = 0x20; /* Link RAM into free memory list */ + + /* Type of Expansion Card */ + const protoautoconfig = 0x40; + const zorroII = 0xc0; + const zorroIII = 0x80; + + /*---------------------------------*/ + /* 04 - 06 & 10-16 */ + + /* Manufacturer */ + const commodore_g = 513; /* Commodore Braunschweig (Germany) */ + const commodore = 514; /* Commodore West Chester */ + const gvp = 2017; /* GVP */ + const ass = 2102; /* Advanced Systems & Software */ + const hackers_id = 2011; /* Special ID for test cards */ + + /* Card Type */ + const commodore_a2091 = 3; /* A2091 / A590 Card from C= */ + const commodore_a2091_ram = 10; /* A2091 / A590 Ram on HD-Card */ + const commodore_a2232 = 70; /* A2232 Multiport Expansion */ + const ass_nexus_scsi = 1; /* Nexus SCSI Controller */ + + const gvp_series_2_scsi = 11; + const gvp_iv_24_gfx = 32; + + /*---------------------------------*/ + /* 08 - 0A */ + /* er_Flags */ + + const Z3_SS_MEM_SAME = 0x00; + const Z3_SS_MEM_AUTO = 0x01; + const Z3_SS_MEM_64KB = 0x02; + const Z3_SS_MEM_128KB = 0x03; + const Z3_SS_MEM_256KB = 0x04; + const Z3_SS_MEM_512KB = 0x05; + const Z3_SS_MEM_1MB = 0x06; /* Zorro III card subsize */ + const Z3_SS_MEM_2MB = 0x07; + const Z3_SS_MEM_4MB = 0x08; + const Z3_SS_MEM_6MB = 0x09; + const Z3_SS_MEM_8MB = 0x0a; + const Z3_SS_MEM_10MB = 0x0b; + const Z3_SS_MEM_12MB = 0x0c; + const Z3_SS_MEM_14MB = 0x0d; + const Z3_SS_MEM_defunct1 = 0x0e; + const Z3_SS_MEM_defunct2 = 0x0f; + + const force_z3 = 0x10; /* *MUST* be set if card is Z3 */ + const ext_size = 0x20; /* Use extended size table for bits 0-2 of er_Type */ + const no_shutup = 0x40; /* Card cannot receive Shut_up_forever */ + const care_addr = 0x80; /* Z2=Adress HAS to be $200000-$9fffff Z3=1->mem,0=io */ + + /*---------------------------------*/ + /* 40-42 */ + /* ec_interrupt (unused) */ + + const enable_irq = 0x01; /* enable Interrupt */ + const reset_card = 0x04; /* Reset of Expansion Card - must be 0 */ + const card_int2 = 0x10; /* READ ONLY: IRQ 2 active */ + const card_irq6 = 0x20; /* READ ONLY: IRQ 6 active */ + const card_irq7 = 0x40; /* READ ONLY: IRQ 7 active */ + const does_irq = 0x80; /* READ ONLY: Card currently throws IRQ */ + + /*---------------------------------*/ + /* ROM defines (DiagVec) */ + + const rom_4bit = (0x00<<14); /* ROM width */ + const rom_8bit = (0x01<<14); + const rom_16bit = (0x02<<14); + + const rom_never = (0x00<<12); /* Never run Boot Code */ + const rom_install = (0x01<<12); /* run code at install time */ + const rom_binddrv = (0x02<<12); /* run code with binddrivers */ + + //var chipdone = false; + + /*const FILESYS_DIAGPOINT = 0x01e0; + const FILESYS_BOOTPOINT = 0x01e6; + const FILESYS_DIAGAREA = 0x2000; + uaecptr ROM_filesys_resname, ROM_filesys_resid; + uaecptr ROM_filesys_diagentry; + uaecptr ROM_hardfile_resname, ROM_hardfile_resid; + uaecptr ROM_hardfile_init;*/ + + /*---------------------------------*/ + + function card_data() { + this.initrc = null; //addrbank *(*initrc)(struct romconfig*); + this.initnum = null; //addrbank *(*initnum)(int); + this.map = null; //addrbank *(*map)(void); + this.rc = null; //struct romconfig * + this.name = ""; + this.flags = 0; + this.zorro = 0; + } + var cards = new Array(MAX_EXPANSION_BOARD_SPACE); + for (var vi = 0; vi < MAX_EXPANSION_BOARD_SPACE; vi++) + cards[vi] = new card_data(); + + var ecard = 0, cardno = 0, cardid = 0; + + /* Autoconfig address space at 0xE80000 */ + const Z3BASE_UAE = 0x10000000; + const Z3BASE_REAL = 0x40000000; + + var expamem = new Uint8Array(65536); + var expamem_lo = 0; //u8 + var expamem_hi = 0; //u16 + var expamem_z2_pointer = 0; + var expamem_z2_size = 0; + var expamem_z3_pointer = 0; + var expamem_z3_size = 0; + var expamem_z3_sum = 0; + var expamem_board_size = 0; + var expamem_board_pointer = 0 + var expamem_bank_current = null; + + var z3hack_override = false; + //var z3num = 0; + + /*-----------------------------------------------------------------------*/ + /* Autoconfig base */ + + function isnonautoconfig(v) { + return v == BOARD_NONAUTOCONFIG_AFTER_Z2 || + v == BOARD_NONAUTOCONFIG_AFTER_Z3 || + v == BOARD_NONAUTOCONFIG_BEFORE; + } + + /* Ugly hack for >2M chip RAM in single pool + * We can't add it any later or early boot menu + * stops working because it sets kicktag at the end + * of chip ram... + */ + /*function addextrachip(sysbase) { + var cs = SAEV_config.memory.chipSize; + if (cs <= 0x00200000) + return; + if (sysbase & 0x80000001) + return; + if (!SAER_Memory_check(sysbase, 1000)) + return; + var ml = SAER_Memory_get32(sysbase + 322); + if (!SAER_Memory_check(ml, 32)) + return; + var next = 0; + while ((next = SAER_Memory_get32(ml))) { + if (!SAER_Memory_check(ml, 32)) + return; + var upper = SAER_Memory_get32(ml + 24); + var lower = SAER_Memory_get32(ml + 20); + if (lower & 0xffff0000) { + ml = next; + continue; + } + var attr = SAER_Memory_get16(ml + 14); + if ((attr & 0x8002) != 2) { + ml = next; + continue; + } + if (upper >= cs) + return; + var added = cs - upper; + var first = SAER_Memory_get32(ml + 16); + SAER_Memory_put32(ml + 24, cs); // mh_Upper + SAER_Memory_put32(ml + 28, SAER_Memory_get32(ml + 28) + added); // mh_Free + while (first) { + next = first; + first = SAER_Memory_get32(next); + } + var bytes = SAER_Memory_get32(next + 4); + if (next + bytes == 0x00200000) { + SAER_Memory_put32 (next + 4, cs - next); + } else { + SAER_Memory_put32(0x00200000 + 0, 0); + SAER_Memory_put32(0x00200000 + 4, added); + SAER_Memory_put32(next, 0x00200000); + } + return; } - return { - name:'Commodore A2058', - vendor:VENDOR_COMMODORE, - product:PRODUCT_A2058, - serial:1, - type:type, - flags:CARE_ADDR, - rom:0, - ctrl:0 - }; + }*/ + + /*this.set_expamem_z3_hack_override = function(overridenoz3hack) { + z3hack_override = overridenoz3hack; + }*/ + function expamem_z3hack(p) { + if (z3hack_override) return false; + return p.memory.z3Mapping == SAEC_Config_Memory_z3Mapping_Auto || p.memory.z3Mapping == SAEC_Config_Memory_z3Mapping_SAE; // || cpuboard_memorytype(p) == BOARD_MEMORY_BLIZZARD_12xx; } -} -function Board_Dummy() { - this.info = function() { - //BUG.info('Board_Dummy.info()'); - return { - name:null, - vendor:0, - product:0, - serial:0, - type:0, - flags:0, - rom:0, - ctrl:0 - }; + function expamem_map_clear() { + SAEF_warn("expamem_map_clear() got called. Shouldn't happen."); + return null; } -} -function Expansion() { - const MAX_EXPANSION_BOARDS = 5; + function expamem_init_clear() { + //memset(expamem, 0xff, sizeof expamem); + SAEF_memset(expamem,0, 0xff, 65536); + } + /* autoconfig area is "non-existing" after last device */ + function expamem_init_clear_zero() { + SAER_Memory_mapBanks(SAEV_Memory_dummyBank, 0xe8, 1, 0); + if (!SAEV_config.cpu.addressSpace24) + SAER_Memory_mapBanks(SAEV_Memory_dummyBank, 0xff000000 >>> 16, 1, 0); + } - var mem = { - data:null, - lo:0, - hi:0 - }; - var boards = []; - var board = 0; + function expamem_init_clear2() { + expamem_bank.name = "Autoconfig Z2"; + expamemz3_bank.name = "Autoconfig Z3"; + expamem_init_clear_zero(); + ecard = cardno; + } - this.setup = function () { - mem.data = new Uint16Array(0x8000); - boards = []; - if (AMIGA.mem.fast.size > 0) - boards[0] = new Board_A2058(); - else - boards[0] = new Board_Dummy(); + function expamem_init_last() { + expamem_init_clear2(); + SAEF_log("Memory map after autoconfig:"); + SAER.memory.map_dump(); + return null; + } - for (var i = 1; i < MAX_EXPANSION_BOARDS; i++) - boards[i] = new Board_Dummy(); - }; - - this.reset = function () { - board = 0; - this.config(board); - }; - - this.clear = function () { - for (var i = 0; i < mem.data.length; i++) - mem.data[i] = 0; - }; - - this.write = function (addr, value) { - mem.data[(addr >> 1)] = (value & 0xf0) << 8; - mem.data[(addr >> 1) + 1] = (value & 0x0f) << 12; - }; - - this.load8 = function (addr) { - addr &= 0xffff; - var value = (mem.data[addr >>> 1] >> ((addr & 1) ? 0 : 8)) & 0xff; + function expamem_read(addr) { + var b = (expamem[addr] & 0xf0) | (expamem[addr + 2] >> 4); if (addr == 0 || addr == 2 || addr == 0x40 || addr == 0x42) - return value; - return ~value & 0xff; - }; + return b; + b = ~b; + return b & 0xff; + } - this.store8 = function (addr, value) { - switch (addr & 0xff) { - case 0x30: - case 0x32: - mem.hi = 0; - mem.lo = 0; - this.write(0x48, 0x00); + function expamem_write(addr, value) { + addr &= 0xffff; + if (addr == 0 || addr == 2 || addr == 0x40 || addr == 0x42) { + expamem[addr] = (value & 0xf0); + expamem[addr + 2] = (value & 0x0f) << 4; + } else { + expamem[addr] = ~(value & 0xf0); + expamem[addr + 2] = ~((value & 0x0f) << 4); + } + } + + function expamem_type() { + return expamem_read(0) & 0xc0; + } + + function call_card_init(index) { + var ab; + + expamem_bank.name = cards[ecard].name ? cards[ecard].name : "None"; + if (cards[ecard].initnum) + ab = cards[ecard].initnum(0); + else + ab = cards[ecard].initrc(cards[ecard].rc); + + expamem_z3_size = 0; + /*if (ab === expamem_none) { //cpu-boards + expamem_init_clear(); + expamem_init_clear_zero(); + SAER_Memory_mapBanks(expamem_bank, 0xE8, 1, 0); + if (!SAEV_config.cpu.addressSpace24) + SAER_Memory_mapBanks(SAEV_Memory_dummyBank, 0xff000000 >>> 16, 1, 0); + expamem_bank_current = null; + return; + }*/ + if (ab === false) { //expamem_null) { + expamem_next(null, null); + return; + } + + var abe = ab; + if (abe === null) + abe = expamem_bank; + if (abe !== expamem_bank) { + for (var i = 0; i < 16 * 4; i++) + expamem[i] = abe.get8(i); + } + + var code = expamem_read(0); + if ((code & 0xc0) == zorroII) { + // Z2 + code &= 7; + if (code == 0) + expamem_z2_size = 8 * 1024 * 1024; + else + expamem_z2_size = 32768 << code; + + expamem_board_size = expamem_z2_size; + expamem_board_pointer = expamem_z2_pointer; + + } else if ((code & 0xc0) == zorroIII) { + // Z3 + if (expamem_z3_sum < Z3BASE_UAE) { + expamem_z3_sum = SAEV_config.memory.z3AutoConfigStart; + if (SAEV_config.memory.ramsey.highSize >= 128 * 1024 * 1024 && expamem_z3_sum == Z3BASE_UAE) + expamem_z3_sum += (SAEV_config.memory.ramsey.highSize - 128 * 1024 * 1024) + 16 * 1024 * 1024; + if (!expamem_z3hack(SAEV_config)) + expamem_z3_sum = Z3BASE_REAL; + //if (expamem_z3_sum == Z3BASE_UAE) + // expamem_z3_sum += currprefs.z3chipmem_size; + } + + expamem_z3_pointer = expamem_z3_sum; + + code &= 7; + if (expamem_read(8) & ext_size) + expamem_z3_size = (16 * 1024 * 1024) << code; + else + expamem_z3_size = 16 * 1024 * 1024; + expamem_z3_sum += expamem_z3_size; + + var expamem_z3_pointer_old = expamem_z3_pointer; + // align 32M boards (FastLane is 32M and needs to be aligned) + if (expamem_z3_size <= 32 * 1024 * 1024) + expamem_z3_pointer = ((expamem_z3_pointer + expamem_z3_size - 1) & ~(expamem_z3_size - 1)) >>> 0; + + expamem_z3_sum += expamem_z3_pointer - expamem_z3_pointer_old; + + expamem_board_size = expamem_z3_size; + expamem_board_pointer = expamem_z3_pointer; + + } else if ((code & 0xc0) == 0x40) { + // 0x40 = "Box without init/diagnostic code" + // proto autoconfig "box" size. + //expamem_z2_size = (1 << ((code >> 3) & 7)) * 4096; + // much easier this way, all old-style boards were made for + // A1000 and didn"t have passthrough connector. + expamem_z2_size = 65536; + expamem_board_size = expamem_z2_size; + expamem_board_pointer = expamem_z2_pointer; + } + + if (ab !== null) { + // non-null: not using expamem_bank + expamem_bank_current = ab; + if ((cards[ecard].flags & 1) && SAEV_config.chipset.z3AutoConfig && !SAEV_config.cpu.addressSpace24) { + SAER_Memory_mapBanks(expamemz3_bank, 0xff000000 >>> 16, 1, 0); + SAER_Memory_mapBanks(SAEV_Memory_dummyBank, 0xE8, 1, 0); + } else { + SAER_Memory_mapBanks(expamem_bank, 0xE8, 1, 0); + if (!SAEV_config.cpu.addressSpace24) + SAER_Memory_mapBanks(SAEV_Memory_dummyBank, 0xff000000 >>> 16, 1, 0); + } + } else { + if ((cards[ecard].flags & 1) && SAEV_config.chipset.z3AutoConfig && !SAEV_config.cpu.addressSpace24) { + expamem_bank_current = expamem_bank; + SAER_Memory_mapBanks(expamemz3_bank, 0xff000000 >>> 16, 1, 0); + SAER_Memory_mapBanks(SAEV_Memory_dummyBank, 0xE8, 1, 0); + } else { + expamem_bank_current = null; + SAER_Memory_mapBanks(expamem_bank, 0xE8, 1, 0); + if (!SAEV_config.cpu.addressSpace24) + SAER_Memory_mapBanks(SAEV_Memory_dummyBank, 0xff000000 >>> 16, 1, 0); + } + } + } + + function boardmessage(mapped, success) { + var type = expamem_read(0); + var size = expamem_board_size; + var sizemod = "K"; + + //size /= 1024; + size >>>= 10; + if (size > 8 * 1024) { + sizemod = "M"; + //size /= 1024; + size >>>= 10; + } + SAEF_log("memory.boardmessage() Card %d: Z%d 0x%08x %4d%s %s %s%s", + ecard + 1, (type & 0xc0) == zorroII ? 2 : ((type & 0xc0) == zorroIII ? 3 : 1), + expamem_board_pointer, size, sizemod, + type & rom_card ? "ROM" : (type & add_memory ? "RAM" : "IO "), + mapped.name, + success ? "" : " SHUT UP" + ); + /*#if 0 + for (var i = 0; i < 16; i++) { + SAEF_log("%s%02X", i > 0 ? "." : "", expamem_read(i * 4)); + } + SAEF_log("\n"); + #endif*/ + } + + function expamem_shutup(mapped) { + if (mapped) + boardmessage(mapped, false); + } + + function expamem_next(mapped, next) { + if (mapped) + boardmessage(mapped, true); + + expamem_init_clear(); + expamem_init_clear_zero(); + for (;;) { + ++ecard; + if (ecard >= cardno) break; + var ec = cards[ecard]; + if (ec.initrc && isnonautoconfig(ec.zorro)) { + ec.initrc(cards[ecard].rc); + } else { + call_card_init(ecard); + break; + } + } + if (ecard >= cardno) { + expamem_init_clear2(); + expamem_init_last(); + } + } + /*-----------------------------------------------------------------------*/ + /* BANK Z2-Fast memory */ + + function fastmem_get32(addr) { + addr = (addr & fastmem_bank.mask) >>> 0; + //var m = fastmem_bank.baseaddr + addr; return do_get_mem_long ((uae_u32 *)m); + return ((fastmem_bank.baseaddr[addr] << 24) | (fastmem_bank.baseaddr[addr+1] << 16) | (fastmem_bank.baseaddr[addr+2] << 8) | fastmem_bank.baseaddr[addr+3]) >>> 0; + } + function fastmem_get16(addr) { + addr = (addr & fastmem_bank.mask) >>> 0; + //var m = fastmem_bank.baseaddr + addr; return do_get_mem_word ((uae_u16 *)m); + return (fastmem_bank.baseaddr[addr] << 8) | fastmem_bank.baseaddr[addr+1]; + } + function fastmem_get8(addr) { + addr = (addr & fastmem_bank.mask) >>> 0; + return fastmem_bank.baseaddr[addr]; + } + function fastmem_put32(addr, l) { + addr = (addr & fastmem_bank.mask) >>> 0; + //var m = fastmem_bank.baseaddr + addr; do_put_mem_long ((uae_u32 *)m, l); + fastmem_bank.baseaddr[addr] = l >>> 24; + fastmem_bank.baseaddr[addr+1] = (l >>> 16) & 0xff; + fastmem_bank.baseaddr[addr+2] = (l >>> 8) & 0xff; + fastmem_bank.baseaddr[addr+3] = l & 0xff; + } + function fastmem_put16(addr, w) { + addr = (addr & fastmem_bank.mask) >>> 0; + //var m = fastmem_bank.baseaddr + addr; do_put_mem_word ((uae_u16 *)m, w); + fastmem_bank.baseaddr[addr] = w >> 8; + fastmem_bank.baseaddr[addr+1] = w & 0xff; + } + function fastmem_put8(addr, b) { + addr = (addr & fastmem_bank.mask) >>> 0; + fastmem_bank.baseaddr[addr] = b; + } + function fastmem_check(addr, size) { + addr = (addr & fastmem_bank.mask) >>> 0; + return (addr + size) <= fastmem_bank.allocated; + } + function fastmem_xlate(addr) { + addr = (addr & fastmem_bank.mask) >>> 0; + //return fastmem_bank.baseaddr + addr; + return addr; + } + var fastmem_bank = new SAEO_Memory_addrbank( + fastmem_get32, fastmem_get16, fastmem_get8, + fastmem_put32, fastmem_put16, fastmem_put8, + fastmem_xlate, fastmem_check, null, "fast", "Fast memory", + fastmem_get32, fastmem_get16, + //SAEC_Memory_addrbank_flag_RAM | SAEC_Memory_addrbank_flag_THREADSAFE, 0, 0 + SAEC_Memory_addrbank_flag_RAM | SAEC_Memory_addrbank_flag_THREADSAFE + ); + + /*---------------------------------*/ + + /*var fastmem2_bank = new SAEO_Memory_addrbank( + fastmem2_get32, fastmem2_get16, fastmem2_get8, + fastmem2_put32, fastmem2_put16, fastmem2_put8, + fastmem2_xlate, fastmem2_check, null, "fast2", "Fast memory 2", + fastmem2_get32, fastmem2_get16, + //SAEC_Memory_addrbank_flag_RAM | SAEC_Memory_addrbank_flag_THREADSAFE, 0, 0 + SAEC_Memory_addrbank_flag_RAM | SAEC_Memory_addrbank_flag_THREADSAFE + };*/ + + /*-----------------------------------------------------------------------*/ + + function fastmem_autoconfig(boardnum, zorro, type, serial, allocated) { + var mid = 0; + var pid; + var flags = care_addr; + //DEVICE_MEMORY_CALLBACK dmc = null; + //struct romconfig *dmc_rc = null; + var ac = new Uint8Array(16); + + /*if (boardnum == 1) { + + } else if (boardnum == 0) { + for (int i = 0; expansionroms[i].name; i++) { + const struct expansionromtype *erc = &expansionroms[i]; + if (((erc->zorro == zorro) || (zorro < 0 && erc->zorro >= BOARD_NONAUTOCONFIG_BEFORE)) && cfgfile_board_enabled(&currprefs, erc->romtype, 0)) { + struct romconfig *rc = get_device_romconfig(&currprefs, erc->romtype, 0); + if (erc->subtypes) { + const struct expansionsubromtype *srt = &erc->subtypes[rc->subtype]; + if (srt->memory_mid) { + mid = srt->memory_mid; + pid = srt->memory_pid; + serial = srt->memory_serial; + if (!srt->memory_after) + type |= chainedconfig; + } + } else { + if (erc->memory_mid) { + mid = erc->memory_mid; + pid = erc->memory_pid; + serial = erc->memory_serial; + if (!erc->memory_after) + type |= chainedconfig; + } + } + dmc = erc->memory_callback; + dmc_rc = rc; + break; + } + } + }*/ + + if (!mid) { + if (zorro <= 2) { + //pid = SAEV_config.memory.maprom ? 1 : 81; + pid = 81; + } else { + var subsize = (allocated == 0x100000 ? Z3_SS_MEM_1MB + : allocated == 0x200000 ? Z3_SS_MEM_2MB + : allocated == 0x400000 ? Z3_SS_MEM_4MB + : allocated == 0x800000 ? Z3_SS_MEM_8MB + : Z3_SS_MEM_SAME); + + //pid = SAEV_config.memory.maprom ? 3 : 83; + pid = 83; + flags |= force_z3 | (allocated > 0x800000 ? ext_size : subsize); + } + mid = cardid; + } + + ac[0x00 / 4] = type; + ac[0x04 / 4] = pid; + ac[0x08 / 4] = flags; + ac[0x10 / 4] = mid >> 8; + ac[0x14 / 4] = mid & 0xff; + ac[0x18 / 4] = serial >>> 24; + ac[0x1c / 4] = (serial >>> 16) & 0xff; + ac[0x20 / 4] = (serial >>> 8) & 0xff; + ac[0x24 / 4] = serial & 0xff; + + //if (dmc && dmc_rc) dmc(dmc_rc, ac, allocated); + + expamem_write(0x00, ac[0x00 / 4]); + expamem_write(0x04, ac[0x04 / 4]); + expamem_write(0x08, ac[0x08 / 4]); + expamem_write(0x10, ac[0x10 / 4]); + expamem_write(0x14, ac[0x14 / 4]); + + expamem_write(0x18, ac[0x18 / 4]); /* ser.no. Byte 0 */ + expamem_write(0x1c, ac[0x1c / 4]); /* ser.no. Byte 1 */ + expamem_write(0x20, ac[0x20 / 4]); /* ser.no. Byte 2 */ + expamem_write(0x24, ac[0x24 / 4]); /* ser.no. Byte 3 */ + + expamem_write(0x28, 0x00); /* ROM-Offset hi */ + expamem_write(0x2c, 0x00); /* ROM-Offset lo */ + + expamem_write(0x40, 0x00); /* Ctrl/Statusreg.*/ + } + + /*---------------------------------*/ + /* Expansion Card (ZORRO II) */ + + function expamem_map_fastcard_2(boardnum) { + var start = ((expamem_hi | (expamem_lo >> 4)) << 16) >>> 0; + //var ab = fastbanks[boardnum * 2 + ((start < 0x00A00000) ? 0 : 1)]; + var ab = fastmem_bank; + var size = ab.allocated; + ab.start = start; + if (ab.start) + SAER.memory.map_banks_z2(ab, ab.start >>> 16, size >>> 16); + + return ab; + } + + function expamem_init_fastcard_2(boardnum) { + var type = add_memory | zorroII; + //var allocated = boardnum ? fastmem2_bank.allocated : fastmem_bank.allocated; + var allocated = fastmem_bank.allocated; + var serial = 1; + + if (allocated == 0) + return false; //expamem_null; + + expamem_init_clear(); + + if (allocated == 65536) type |= Z2_MEM_64KB; + else if (allocated == 131072) type |= Z2_MEM_128KB; + else if (allocated == 262144) type |= Z2_MEM_256KB; + else if (allocated == 524288) type |= Z2_MEM_512KB; + else if (allocated == 0x100000) type |= Z2_MEM_1MB; + else if (allocated == 0x200000) type |= Z2_MEM_2MB; + else if (allocated == 0x400000) type |= Z2_MEM_4MB; + else if (allocated == 0x800000) type |= Z2_MEM_8MB; + + /*if (boardnum == 1) { + const a2630_autoconfig = [ 0xe7, 0x51, 0x40, 0x00, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ]; + + if (ISCPUBOARD(BOARD_COMMODORE, BOARD_COMMODORE_SUB_A26x0)) { + for (int i = 1; i < 16; i++) + expamem_write(i * 4, a2630_autoconfig[i]); + type &= 7; + type |= a2630_autoconfig[0] & ~7; + expamem_write(0, type); + return null; + } + }*/ + + fastmem_autoconfig(boardnum, BOARD_AUTOCONFIG_Z2, type, serial, allocated); + fastmem_autoconfig(boardnum, -1, type, serial, allocated); + return null; + } + + function expamem_init_fastcard(boardnum) { + return expamem_init_fastcard_2(0); + } + function expamem_map_fastcard() { + return expamem_map_fastcard_2(0); + } + + /*function expamem_init_fastcard2(boardnum) { + return expamem_init_fastcard_2(1); + } + function expamem_map_fastcard2() { + return expamem_map_fastcard_2(1); + }*/ + + /*this.expansion_is_next_board_fastram = function() { + return ecard + 1 < MAX_EXPANSION_BOARD_SPACE && cards[ecard + 1].map == expamem_map_fastcard; + }*/ + + /*---------------------------------*/ + /* Expansion Card (Zorro III) */ + + function expamem_map_z3fastmem_2(bank, ptr, size, allocated, chip) { + var z3fs = expamem_z3_pointer; + var start = ptr.start; + + if (expamem_z3hack(SAEV_config)) { + if (z3fs && start != z3fs) { + SAEF_warn("memory.expamem_map_z3fastmem_2() Z3MEM mapping changed from $%08x to $%08x", start, z3fs); + map_banks(SAEV_Memory_dummyBank, start >>> 16, size >>> 16, allocated); + ptr.start = z3fs; + SAER.memory.map_banks_z3(bank, start >>> 16, size >>> 16); + } + } else { + SAER.memory.map_banks_z3(bank, z3fs >>> 16, size >>> 16); + //start = z3fs; //OWN unneeded + ptr.start = z3fs; + } + return bank; + } + function expamem_map_z3fastmem() { + var ptr = { start:z3fastmem_bank.start }; + var bank = expamem_map_z3fastmem_2(z3fastmem_bank, ptr, SAEV_config.memory.z3FastSize, z3fastmem_bank.allocated, 0); + z3fastmem_bank.start = ptr.start; + return bank; + } + /*function expamem_map_z3fastmem2() { + var ptr = { start:z3fastmem2_bank.start }; + var bank = expamem_map_z3fastmem_2(z3fastmem2_bank, ptr, currprefs.z3fastmem2_size, z3fastmem2_bank.allocated, 0); + z3fastmem2_bank.start = ptr.start; + return bank; + }*/ + + function expamem_init_z3fastmem_2(boardnum, bank, start, size, allocated) { + var code = (allocated == 0x100000 ? Z2_MEM_1MB + : allocated == 0x200000 ? Z2_MEM_2MB + : allocated == 0x400000 ? Z2_MEM_4MB + : allocated == 0x800000 ? Z2_MEM_8MB + : allocated == 0x1000000 ? Z3_MEM_16MB + : allocated == 0x2000000 ? Z3_MEM_32MB + : allocated == 0x4000000 ? Z3_MEM_64MB + : allocated == 0x8000000 ? Z3_MEM_128MB + : allocated == 0x10000000 ? Z3_MEM_256MB + : allocated == 0x20000000 ? Z3_MEM_512MB + : Z3_MEM_1GB); + + if (allocated < 0x1000000) + code = Z3_MEM_16MB; /* Z3 physical board size is always at least 16M */ + + expamem_init_clear(); + fastmem_autoconfig(boardnum, BOARD_AUTOCONFIG_Z3, add_memory | zorroIII | code, 1, allocated); + SAER.memory.map_banks_z3(bank, start >>> 16, size >>> 16); + return null; + } + function expamem_init_z3fastmem(devnum) { + return expamem_init_z3fastmem_2(0, z3fastmem_bank, z3fastmem_bank.start, SAEV_config.memory.z3FastSize, z3fastmem_bank.allocated); + } + /*function expamem_init_z3fastmem2(devnum) { + return expamem_init_z3fastmem_2(1, z3fastmem2_bank, z3fastmem2_bank.start, currprefs.z3fastmem2_size, z3fastmem2_bank.allocated); + }*/ + + /*---------------------------------*/ + /* BANK Z3 memory */ + + function z3fastmem_get32(addr) { + addr = (addr & z3fastmem_bank.mask) >>> 0; + //var m = z3fastmem_bank.baseaddr + addr; return do_get_mem_long ((uae_u32 *)m); + return ((z3fastmem_bank.baseaddr[addr] << 24) | (z3fastmem_bank.baseaddr[addr+1] << 16) | (z3fastmem_bank.baseaddr[addr+2] << 8) | z3fastmem_bank.baseaddr[addr+3]) >>> 0; + } + function z3fastmem_get16(addr) { + addr = (addr & z3fastmem_bank.mask) >>> 0; + //var m = z3fastmem_bank.baseaddr + addr; return do_get_mem_word ((uae_u16 *)m); + return (z3fastmem_bank.baseaddr[addr] << 8) | z3fastmem_bank.baseaddr[addr+1]; + } + function z3fastmem_get8(addr) { + addr = (addr & z3fastmem_bank.mask) >>> 0; + return z3fastmem_bank.baseaddr[addr]; + } + function z3fastmem_put32(addr, l) { + addr = (addr & z3fastmem_bank.mask) >>> 0; + //var m = z3fastmem_bank.baseaddr + addr; do_put_mem_long ((uae_u32 *)m, l); + z3fastmem_bank.baseaddr[addr] = l >>> 24; + z3fastmem_bank.baseaddr[addr+1] = (l >>> 16) & 0xff; + z3fastmem_bank.baseaddr[addr+2] = (l >>> 8) & 0xff; + z3fastmem_bank.baseaddr[addr+3] = l & 0xff; + } + function z3fastmem_put16(addr, w) { + addr = (addr & z3fastmem_bank.mask) >>> 0; + //var m = z3fastmem_bank.baseaddr + addr; do_put_mem_word ((uae_u16 *)m, w); + z3fastmem_bank.baseaddr[addr] = w >> 8; + z3fastmem_bank.baseaddr[addr+1] = w & 0xff; + } + function z3fastmem_put8(addr, b) { + addr = (addr & z3fastmem_bank.mask) >>> 0; + z3fastmem_bank.baseaddr[addr] = b; + } + function z3fastmem_check(addr, size) { + addr = (addr & z3fastmem_bank.mask) >>> 0; + return (addr + size) <= z3fastmem_bank.allocated; + } + function z3fastmem_xlate(addr) { + addr = (addr & z3fastmem_bank.mask) >>> 0; + //return z3fastmem_bank.baseaddr + addr; + return addr; + } + var z3fastmem_bank = new SAEO_Memory_addrbank( + z3fastmem_get32, z3fastmem_get16, z3fastmem_get8, + z3fastmem_put32, z3fastmem_put16, z3fastmem_put8, + z3fastmem_xlate, z3fastmem_check, null, "z3", "Zorro III Fast RAM", + z3fastmem_get32, z3fastmem_get16, + //SAEC_Memory_addrbank_flag_RAM | SAEC_Memory_addrbank_flag_THREADSAFE, 0, 0 + SAEC_Memory_addrbank_flag_RAM | SAEC_Memory_addrbank_flag_THREADSAFE + ); + SAER_Expansion_z3fastmem_bank = z3fastmem_bank; + + /*MEMORY_FUNCTIONS(z3fastmem2); + var z3fastmem2_bank = new SAEO_Memory_addrbank( + z3fastmem2_get32, z3fastmem2_get16, z3fastmem2_get8, + z3fastmem2_put32, z3fastmem2_put16, z3fastmem2_put8, + z3fastmem2_xlate, z3fastmem2_check, null, "z3_2", "Zorro III Fast RAM #2", + z3fastmem2_get32, z3fastmem2_get16, + //SAEC_Memory_addrbank_flag_RAM | SAEC_Memory_addrbank_flag_THREADSAFE, 0, 0 + SAEC_Memory_addrbank_flag_RAM | SAEC_Memory_addrbank_flag_THREADSAFE + ); + + MEMORY_FUNCTIONS(z3chipmem); + var z3chipmem_bank = new SAEO_Memory_addrbank( + z3chipmem_get32, z3chipmem_get16, z3chipmem_get8, + z3chipmem_put32, z3chipmem_put16, z3chipmem_put8, + z3chipmem_xlate, z3chipmem_check, null, "z3_chip", "MegaChipRAM", + z3chipmem_get32, z3chipmem_get16, + //SAEC_Memory_addrbank_flag_RAM | SAEC_Memory_addrbank_flag_THREADSAFE, 0, 0 + SAEC_Memory_addrbank_flag_RAM | SAEC_Memory_addrbank_flag_THREADSAFE + );*/ + + /*-----------------------------------------------------------------------*/ + /* Autoconfig setup/cleanup/reset */ + + function mapped_malloc(ab) { + ab.startmask = ab.start; + try { + //ab.baseaddr = xcalloc(uae_u8, ab.allocated + 4); + ab.baseaddr = new Uint8Array(ab.allocated + 4); + return true; + } catch (e) { + ab.baseaddr = null; + return false; + } + } + function mapped_free(ab) { + //xfree(ab.baseaddr); + ab.baseaddr = null; + } + + function free_fastmemory(boardnum) { + if (boardnum == 0) + mapped_free(fastmem_bank); + //else + //mapped_free(fastmem2_bank); + } + this.free_fastmemory_ext = function(boardnum) { + free_fastmemory(boardnum); + } + + //function mapped_malloc_dynamic(curr, changed, bank, max, name) { + function mapped_malloc_dynamic(curr, bank, max, name) { + var alloc = curr.size; + + bank.allocated = 0; + bank.baseaddr = null; + bank.mask = 0; + + if (!alloc) + return false; + + while (alloc >= max * 1024 * 1024) { + bank.mask = alloc - 1; + bank.allocated = alloc; + bank.label = name; + if (mapped_malloc(bank)) { + curr.size = alloc; + //changed.size = alloc; + return true; + } + SAEF_warn("expansion.mapped_malloc_dynamic() out of memory for '%s'. (%d bytes)", name, alloc); + alloc >>>= 1; + } + return false; + } + + /*uaecptr expansion_startaddress(uaecptr addr, uae_u32 size) { + if (!size) + return addr; + if (size < 16 * 1024 * 1024) + size = 16 * 1024 * 1024; + if (!expamem_z3hack(SAEV_config)) + return (addr + size - 1) & ~(size - 1); + return addr; + }*/ + + function allocate() { //allocate_expamem + /*z3chipmem_bank.start = Z3BASE_UAE; + if (SAEV_config.memory.ramsey.highSize >= 128 * 1024 * 1024) + z3chipmem_bank.start += (SAEV_config.memory.ramsey.highSize - 128 * 1024 * 1024) + 16 * 1024 * 1024;*/ + + z3fastmem_bank.start = SAEV_config.memory.z3AutoConfigStart; + if (!expamem_z3hack(SAEV_config)) + z3fastmem_bank.start = Z3BASE_REAL; + if (z3fastmem_bank.start == Z3BASE_UAE) { + if (SAEV_config.memory.ramsey.highSize >= 128 * 1024 * 1024) + z3fastmem_bank.start += (SAEV_config.memory.ramsey.highSize - 128 * 1024 * 1024) + 16 * 1024 * 1024; + //z3fastmem_bank.start += currprefs.z3chipmem_size; + } + /*z3fastmem2_bank.start = z3fastmem_bank.start + SAEV_config.memory.z3FastSize; + + if (currprefs.z3chipmem_size && z3fastmem_bank.start - z3chipmem_bank.start < currprefs.z3chipmem_size) + currprefs.z3chipmem_size = changed_prefs.z3chipmem_size = 0;*/ + + if (fastmem_bank.allocated != SAEV_config.memory.z2FastSize) { + free_fastmemory(0); + + fastmem_bank.allocated = SAEV_config.memory.z2FastSize; + fastmem_bank.mask = fastmem_bank.allocated - 1; + + //fastmem_nojit_bank.allocated = fastmem_bank.allocated; + //fastmem_nojit_bank.mask = fastmem_bank.mask; + + if (fastmem_bank.allocated) { + mapped_malloc(fastmem_bank); + /*fastmem_nojit_bank.baseaddr = fastmem_bank.baseaddr; + if (fastmem_bank.baseaddr == 0) { + SAEF_error("Out of memory for fastmem card."); + fastmem_bank.allocated = 0; + fastmem_nojit_bank.allocated = 0; + }*/ + } + SAER.memory.hardreset(1); + } + + /*if (fastmem2_bank.allocated != currprefs.fastmem2_size) { + free_fastmemory(1); + + fastmem2_bank.allocated = currprefs.fastmem2_size; + fastmem2_bank.mask = fastmem2_bank.allocated - 1; + + fastmem2_nojit_bank.allocated = fastmem2_bank.allocated; + fastmem2_nojit_bank.mask = fastmem2_bank.mask; + + if (fastmem2_bank.allocated) { + mapped_malloc (&fastmem2_bank); + fastmem2_nojit_bank.baseaddr = fastmem2_bank.baseaddr; + if (fastmem2_bank.baseaddr == 0) { + SAEF_error("Out of memory for fastmem2 card."); + fastmem2_bank.allocated = 0; + fastmem2_nojit_bank.allocated = 0; + } + } + SAER.memory.hardreset(1); + }*/ + + if (z3fastmem_bank.allocated != SAEV_config.memory.z3FastSize) { + mapped_free(z3fastmem_bank); + //mapped_malloc_dynamic(SAEV_config.memory.z3FastSize, &changed_prefs.z3fastmem_size, z3fastmem_bank, 1, "z3"); + var curr = { size:SAEV_config.memory.z3FastSize }; + mapped_malloc_dynamic(curr, z3fastmem_bank, 1, "z3"); + SAEV_config.memory.z3FastSize = curr.size; + SAER.memory.hardreset(1); + } + /*if (z3fastmem2_bank.allocated != currprefs.z3fastmem2_size) { + mapped_free (&z3fastmem2_bank); + + z3fastmem2_bank.allocated = currprefs.z3fastmem2_size; + z3fastmem2_bank.mask = z3fastmem2_bank.allocated - 1; + + if (z3fastmem2_bank.allocated) { + mapped_malloc (&z3fastmem2_bank); + if (z3fastmem2_bank.baseaddr == 0) { + SAEF_error("Out of memory for 32 bit fast memory #2."); + z3fastmem2_bank.allocated = 0; + } + } + SAER.memory.hardreset(1); + } + if (z3chipmem_bank.allocated != currprefs.z3chipmem_size) { + mapped_free (&z3chipmem_bank); + mapped_malloc_dynamic(&currprefs.z3chipmem_size, &changed_prefs.z3chipmem_size, &z3chipmem_bank, 16, "z3_chip"); + SAER.memory.hardreset(1); + }*/ + } + + /*-----------------------------------------------------------------------*/ + + /*static bool add_fastram_after_expansion(int zorro) + { + for (int i = 0; expansionroms[i].name; i++) { + const struct expansionromtype *ert = &expansionroms[i]; + if (ert->zorro == zorro) { + for (int j = 0; j < MAX_DUPLICATE_EXPANSION_BOARDS; j++) { + struct romconfig *rc = get_device_romconfig(&currprefs, ert->romtype, j); + if (rc) { + if (ert->subtypes) { + const struct expansionsubromtype *srt = &ert->subtypes[rc->subtype]; + return srt->memory_after; + } + return ert->memory_after; + } + } + } + } + return false; + } + + static void add_expansions(int zorro) + { + for (int i = 0; expansionroms[i].name; i++) { + const struct expansionromtype *ert = &expansionroms[i]; + if (ert->zorro == zorro) { + for (int j = 0; j < MAX_DUPLICATE_EXPANSION_BOARDS; j++) { + struct romconfig *rc = get_device_romconfig(&currprefs, ert->romtype, j); + if (rc) { + if (zorro == 1) { + ert->init(rc); + if (ert->init2) + ert->init2(rc); + } else { + cards[cardno].flags = 0; + cards[cardno].name = ert->name; + cards[cardno].initrc = ert->init; + cards[cardno].rc = rc; + cards[cardno].zorro = zorro; + cards[cardno++].map = null; + if (ert->init2) { + cards[cardno].flags = 0; + cards[cardno].name = ert->name; + cards[cardno].initrc = ert->init2; + cards[cardno].rc = rc; + cards[cardno].zorro = zorro; + cards[cardno++].map = null; + } + } + } + } + } + } + }*/ + + this.reset = function() { //expamem_reset() + var do_mount = 1; + + ecard = 0; + cardno = 0; + //cardid = currprefs.uae_hide ? commodore : hackers_id; + cardid = true ? commodore : hackers_id; + + //chipdone = false; + + allocate(); + expamem_bank.name = "Autoconfig [reset]"; + + if (SAER.autoconf.need_uae_boot_rom() == 0) + do_mount = 0; + if (SAEV_AutoConf_boot_rom_type <= 0) + do_mount = 0; + + /* check if Kickstart version is below 1.3 */ + if (SAER.memory.ks12orolder() && do_mount) { //&& currprefs.uaeboard < 2) { + /*#if KS12_BOOT_HACK + do_mount = -1; + if (SAER.memory.ks11orolder()) { + filesys_start = 0xe90000; + SAER.memory.map_banks_z2(&filesys_bank, filesys_start >>> 16, 1); + expamem_init_filesys(0); + expamem_map_filesys_update(); + } + #else*/ + SAEF_log("expansion.reset() Kickstart version is below 1.3! Disabling automount devices."); + do_mount = 0; + //#endif + } + + //add possible non-autoconfig boards + //add_expansions(BOARD_NONAUTOCONFIG_BEFORE); + + var fastmem_after = false; + if (SAEV_config.memory.z2FastAutoConfig) { + //fastmem_after = add_fastram_after_expansion(BOARD_AUTOCONFIG_Z2); + if (!fastmem_after && fastmem_bank.baseaddr !== null && (fastmem_bank.allocated <= 262144 || SAEV_config.memory.chipSize <= 2 * 1024 * 1024)) { + cards[cardno].flags = 0; + cards[cardno].name = "Z2Fast"; + cards[cardno].initnum = expamem_init_fastcard; + cards[cardno++].map = expamem_map_fastcard; + } + /*if (fastmem2_bank.baseaddr !== null && (fastmem2_bank.allocated <= 262144 || SAEV_config.memory.chipSize <= 2 * 1024 * 1024)) { + cards[cardno].flags = 0; + cards[cardno].name = "Z2Fast2"; + cards[cardno].initnum = expamem_init_fastcard2; + cards[cardno++].map = expamem_map_fastcard2; + }*/ + } else { + if (fastmem_bank.baseaddr !== null) { + fastmem_bank.name = "Fast memory (non-autoconfig)"; + SAER_Memory_mapBanks(fastmem_bank, 0x00200000 >>> 16, fastmem_bank.allocated >>> 16, 0); + } + /*if (fastmem2_bank.baseaddr !== null) { + fastmem2_bank.name = "Fast memory 2 (non-autoconfig)"; + SAER_Memory_mapBanks(fastmem2_bank, (0x00200000 + fastmem_bank.allocated) >>> 16, fastmem2_bank.allocated >>> 16, 0); + }*/ + } + + // immediately after Z2Fast so that they can be emulated as A590/A2091 with fast ram. + //add_expansions(BOARD_AUTOCONFIG_Z2); + //add_expansions(BOARD_NONAUTOCONFIG_AFTER_Z2); + + /*if (fastmem_after && SAEV_config.memory.z2FastAutoConfig) { + if (fastmem_bank.baseaddr != null && (fastmem_bank.allocated <= 262144 || SAEV_config.memory.chipSize <= 2 * 1024 * 1024)) { + cards[cardno].flags = 0; + cards[cardno].name = "Z2Fast"; + cards[cardno].initnum = expamem_init_fastcard; + cards[cardno++].map = expamem_map_fastcard; + } + }*/ + + /*#ifdef CDTV + if (currprefs.cs_cdtvcd && !currprefs.cs_cdtvcr) { + cards[cardno].flags = 0; + cards[cardno].name = "CDTV DMAC"; + cards[cardno].initrc = cdtv_init; + cards[cardno++].map = null; + } + #endif + #ifdef CD32 + if (currprefs.cs_cd32cd && SAEV_config.memory.z2FastSize == 0 && SAEV_config.memory.chipSize <= 0x200000 && currprefs.cs_cd32fmv) { + cards[cardno].flags = 0; + cards[cardno].name = "CD32MPEG"; + cards[cardno].initnum = expamem_init_cd32fmv; + cards[cardno++].map = expamem_map_cd32fmv; + } + #endif + #ifdef A2065 + if (currprefs.a2065name[0]) { + cards[cardno].flags = 0; + cards[cardno].name = "A2065"; + cards[cardno].initnum = a2065_init; + cards[cardno++].map = null; + } + #endif + #ifdef FILESYS + if (do_mount && currprefs.uaeboard < 2) { + cards[cardno].flags = 0; + cards[cardno].name = "UAEFS"; + cards[cardno].initnum = expamem_init_filesys; + cards[cardno++].map = expamem_map_filesys; + } + if (currprefs.uaeboard) { + cards[cardno].flags = 0; + cards[cardno].name = "UAEBOARD"; + cards[cardno].initnum = expamem_init_uaeboard; + cards[cardno++].map = expamem_map_uaeboard; + } + #endif + #ifdef WITH_TOCCATA + if (currprefs.sound_toccata) { + cards[cardno].flags = 0; + cards[cardno].name = "Toccata"; + cards[cardno++].initnum = sndboard_init; + } + #endif + if (currprefs.monitoremu == MONITOREMU_FIRECRACKER24) { + cards[cardno].flags = 0; + cards[cardno].name = "FireCracker24"; + cards[cardno++].initnum = specialmonitor_autoconfig_init; + }*/ + + /* Z3 boards last */ + if (!SAEV_config.cpu.addressSpace24) { + if (z3fastmem_bank.baseaddr !== null) { + var alwaysmapz3 = SAEV_config.memory.z3Mapping != SAEC_Config_Memory_z3Mapping_Real; + z3num = 0; + cards[cardno].flags = 2 | 1; + cards[cardno].name = "Z3Fast"; + cards[cardno].initnum = expamem_init_z3fastmem; + cards[cardno++].map = expamem_map_z3fastmem; + if (alwaysmapz3 || expamem_z3hack(SAEV_config)) + SAER.memory.map_banks_z3(z3fastmem_bank, z3fastmem_bank.start >>> 16, SAEV_config.memory.z3FastSize >>> 16); + + /*if (z3fastmem2_bank.baseaddr != null) { + cards[cardno].flags = 2 | 1; + cards[cardno].name = "Z3Fast2"; + cards[cardno].initnum = expamem_init_z3fastmem2; + cards[cardno++].map = expamem_map_z3fastmem2; + if (alwaysmapz3 || expamem_z3hack(SAEV_config)) + SAER.memory.map_banks_z3(z3fastmem2_bank, z3fastmem2_bank.start >>> 16, currprefs.z3fastmem2_size >>> 16); + }*/ + } + /*if (z3chipmem_bank.baseaddr != null) + SAER.memory.map_banks_z3(z3chipmem_bank, z3chipmem_bank.start >>> 16, currprefs.z3chipmem_size >>> 16); + + add_expansions(BOARD_AUTOCONFIG_Z3);*/ + } + + //add_expansions(BOARD_NONAUTOCONFIG_AFTER_Z3); + + expamem_z2_pointer = 0; + expamem_z3_pointer = 0; + expamem_z3_sum = 0; + + if (cardno == 0) + expamem_init_clear_zero(); + else + call_card_init(0); + } + + this.setup = function() { //expansion_init() + fastmem_bank.allocated = 0; + fastmem_bank.mask = fastmem_bank.start = 0; + fastmem_bank.baseaddr = null; + /*fastmem_nojit_bank.allocated = 0; + fastmem_nojit_bank.mask = fastmem_nojit_bank.start = 0; + fastmem_nojit_bank.baseaddr = null; + + fastmem2_bank.allocated = 0; + fastmem2_bank.mask = fastmem2_bank.start = 0; + fastmem2_bank.baseaddr = null; + fastmem2_nojit_bank.allocated = 0; + fastmem2_nojit_bank.mask = fastmem2_nojit_bank.start = 0; + fastmem2_nojit_bank.baseaddr = null; + + z3fastmem_bank.allocated = 0; + z3fastmem_bank.mask = z3fastmem_bank.start = 0; + z3fastmem_bank.baseaddr = null; + + z3fastmem2_bank.allocated = 0; + z3fastmem2_bank.mask = z3fastmem2_bank.start = 0; + z3fastmem2_bank.baseaddr = null; + + z3chipmem_bank.allocated = 0; + z3chipmem_bank.mask = z3chipmem_bank.start = 0; + z3chipmem_bank.baseaddr = null;*/ + + /*#ifdef FILESYS + filesys_start = 0; + #endif*/ + + allocate(); + + /*#ifdef FILESYS + if (currprefs.uaeboard < 2) { + filesys_bank.allocated = 0x10000; + if (!mapped_malloc (&filesys_bank)) { + SAEF_error("virtual memory exhausted (filesysory)!"); + exit(0); + } + } + #endif + if (currprefs.uaeboard) { + uaeboard_bank.allocated = 0x10000; + mapped_malloc(&uaeboard_bank); + }*/ + } + + this.cleanup = function() { + mapped_free(fastmem_bank); + /*mapped_free(fastmem2_bank); + mapped_free(z3fastmem_bank); + mapped_free(z3fastmem2_bank); + mapped_free(z3chipmem_bank); + + fastmem_nojit_bank.baseaddr = null; + fastmem2_nojit_bank.baseaddr = null;*/ + + /*#ifdef FILESYS + mapped_free (&filesys_bank); + #endif + if (currprefs.uaeboard) + mapped_free(&uaeboard_bank);*/ + } + + function clear_bank(ab) { + if (ab.baseaddr !== null && ab.allocated) { + //memset(ab->baseaddr, 0, ab->allocated > 0x800000 ? 0x800000 : ab->allocated); + SAEF_memset(ab.baseaddr,0, 0, ab.allocated > 0x800000 ? 0x800000 : ab.allocated); + } + } + this.clear = function() { //expansion_clear() + clear_bank(fastmem_bank); + /*clear_bank(fastmem2_bank); + clear_bank(z3fastmem_bank); + clear_bank(z3fastmem2_bank); + clear_bank(z3chipmem_bank);*/ + } + + /*-----------------------------------------------------------------------*/ + /*-----------------------------------------------------------------------*/ + /*-----------------------------------------------------------------------*/ + + /*var expamem_null = new SAEO_Memory_addrbank( + null, null, null, + null, null, null, + null, null, null, null, "", + null, null, + //0, 0, 0 + 0 + ); + var expamem_none = new SAEO_Memory_addrbank( + null, null, null, + null, null, null, + null, null, null, null, "", + null, null, + //0, 0, 0 + 0 + );*/ + + /*-----------------------------------------------------------------------*/ + /* BANK Autoconfig Z2 */ + + function expamem_get32(addr) { + if (expamem_bank_current && expamem_bank_current !== expamem_bank) + return expamem_bank_current.get32(addr); + SAEF_warn("expamem_get32() Z2 READ.L from address $%08x PC=%x", addr, SAER_CPU_getPC()); + return ((expamem_get16(addr) << 16) | expamem_get16(addr + 2)) >>> 0; + } + function expamem_get16(addr) { + if (expamem_bank_current && expamem_bank_current !== expamem_bank) + return expamem_bank_current.get16(addr); + if (expamem_type() != zorroIII) { + if (expamem_bank_current && expamem_bank_current !== expamem_bank) + return expamem_bank_current.get8(addr) << 8; + } + SAEF_warn("expamem_get16() READ.W from address $%08x PC=%x", addr, SAER_CPU_getPC()); + return (expamem_get8(addr) << 8) | expamem_get8(addr + 1); + } + function expamem_get8(addr) { + /*if (!chipdone) { + chipdone = true; + addextrachip(SAER_Memory_get32(4)); + }*/ + if (expamem_bank_current && expamem_bank_current !== expamem_bank) + return expamem_bank_current.get8(addr); + + return expamem[addr & 0xffff]; + /*addr &= 0xFFFF; + var b = expamem[addr]; + #if EXP_DEBUG + SAEF_log("expamem_get8 %x %x", addr, b); + #endif + return b;*/ + } + function expamem_put32(addr, value) { + if (expamem_bank_current && expamem_bank_current !== expamem_bank) { + expamem_bank_current.put32(addr, value); + return; + } + SAEF_warn("expamem_put32() Z2 WRITE.L to address $%08x : value $%08x", addr, value); + } + function expamem_put16(addr, value) { + /*#if EXP_DEBUG + SAEF_log("expamem_put16 %x %x", addr, value); + #endif*/ + value &= 0xffff; + if (ecard >= cardno) + return; + if (expamem_type() != zorroIII) + SAEF_warn("expamem_put16() WRITE.W to address $%08x : value $%x PC=%08x", addr, value, SAER_CPU_getPC()); + + switch (addr & 0xff) { case 0x48: - mem.hi = value; - //BUG.info('Expansion.store8() board %d done.', board + 1); - ++board; - if (board <= MAX_EXPANSION_BOARDS) - this.config(board); - else - this.clear(); + // A2630 boot rom writes WORDs to Z2 boards! + if (expamem_type() == zorroII) { + expamem_lo = 0; + expamem_hi = (value >> 8) & 0xff; + expamem_z2_pointer = (expamem_hi | (expamem_lo >> 4)) << 16; + expamem_board_pointer = expamem_z2_pointer; + if (cards[ecard].map) { + expamem_next(cards[ecard].map(), null); + return; + } + if (expamem_bank_current && expamem_bank_current !== expamem_bank) { + expamem_bank_current.put8(addr, value >> 8); + return; + } + } + break; + case 0x44: + if (expamem_type() == zorroIII) { + expamem_hi = value & 0xff00; + var addr = ((expamem_hi | (expamem_lo >> 4)) << 16) >>> 0; + if (!expamem_z3hack(SAEV_config)) + expamem_z3_pointer = addr; + else { + if (addr != expamem_z3_pointer) { + SAEF_warn("expansion.expamem_put16() hack %08x %08x", addr, expamem_z3_pointer); + SAER_Memory_put16(SAER_CPU_regs.a[3] + 0x20, expamem_z3_pointer >>> 16); //ATT regs.regs[11] + SAER_Memory_put16(SAER_CPU_regs.a[3] + 0x28, expamem_z3_pointer >>> 16); + } + } + expamem_board_pointer = expamem_z3_pointer; + } + if (cards[ecard].map) { + expamem_next(cards[ecard].map(), null); + return; + } + break; + case 0x4c: + if (cards[ecard].map) { + expamem_next(null, null); + return; + } + break; + } + if (expamem_bank_current && expamem_bank_current !== expamem_bank) + expamem_bank_current.put16(addr, value); + } + function expamem_put8(addr, value) { + /*#if EXP_DEBUG + SAEF_log("expamem_put8 %x %x", addr, value); + #endif*/ + value &= 0xff; + if (ecard >= cardno) + return; + if (expamem_type() == protoautoconfig) { + switch (addr & 0xff) { + case 0x22: { + expamem_hi = value & 0x7f; + expamem_z2_pointer = 0xe80000 | (expamem_hi * 4096); + expamem_board_pointer = expamem_z2_pointer; + if (cards[ecard].map) { + expamem_next(cards[ecard].map(), null); + return; + } + } + } + } else { + switch (addr & 0xff) { + case 0x48: + if (expamem_type() == zorroII) { + expamem_hi = value & 0xff; + expamem_z2_pointer = (expamem_hi | (expamem_lo >> 4)) << 16; + expamem_board_pointer = expamem_z2_pointer; + if (cards[ecard].map) { + expamem_next(cards[ecard].map(), null); + return; + } + } else { + expamem_lo = value & 0xff; + } break; case 0x4a: - mem.lo = value; + if (expamem_type() == zorroII) + expamem_lo = value & 0xff; break; case 0x4c: - //BUG.info('Expansion.store8() board %d faild.', board + 1); - ++board; - if (board <= MAX_EXPANSION_BOARDS) - this.config(board); - else - this.clear(); + if (cards[ecard].map) { + expamem_next(expamem_bank_current, null); + return; + } break; + } } - }; - - this.config = function(board) { - var info = boards[board].info(); - - this.clear(); - if (info.name) { - BUG.info('Expansion.config() Added \'%s\' into slot %d', info.name, board + 1); - - this.write(0x00, info.type); - this.write(0x08, info.flags); + if (expamem_bank_current && expamem_bank_current !== expamem_bank) + expamem_bank_current.put8(addr, value); + } - this.write(0x04, info.product); - this.write(0x10, info.vendor >> 8); - this.write(0x14, info.vendor & 0x0f); + var expamem_bank = new SAEO_Memory_addrbank( + expamem_get32, expamem_get16, expamem_get8, + expamem_put32, expamem_put16, expamem_put8, + SAEF_Memory_defaultXLate, SAEF_Memory_defaultCheck, null, null, "Autoconfig Z2", + SAEF_Memory_dummyGetInst32, SAEF_Memory_dummyGetInst16, + //SAEC_Memory_addrbank_flag_IO | SAEC_Memory_addrbank_flag_SAFE | SAEC_Memory_addrbank_flag_PPCIOSPACE, S_READ, S_WRITE + SAEC_Memory_addrbank_flag_IO | SAEC_Memory_addrbank_flag_SAFE | SAEC_Memory_addrbank_flag_PPCIOSPACE + ); + SAER_Expansion_expamem_bank = expamem_bank; - this.write(0x18, (info.serial >> 24) & 0xff); - this.write(0x1c, (info.serial >> 16) & 0xff); - this.write(0x20, (info.serial >> 8) & 0xff); - this.write(0x24, info.serial & 0xff); + /*-----------------------------------------------------------------------*/ + /* BANK Autoconfig Z3 */ - this.write(0x28, (info.rom >> 8) & 0xff); - this.write(0x2c, info.rom & 0xff); - - this.write(0x40, info.ctrl); + function expamemz3_get8(addr) { + if (!expamem_bank_current) + return 0; + var reg = addr & 0xff; + if (addr & 0x100) + reg += 2; + return expamem_bank_current.get8(reg); + } + function expamemz3_get16(addr) { + SAEF_warn("expansion.expamemz3_get16() READ.W from address $%08x PC=%x", addr, SAER_CPU_getPC()); + return (expamemz3_get8(addr) << 8) | expamemz3_get8(addr + 1); + } + function expamemz3_get32(addr) { + SAEF_warn("expansion.expamemz3_get32() READ.L from address $%08x PC=%x", addr, SAER_CPU_getPC()); + return ((expamemz3_get16(addr) << 16) | expamemz3_get16(addr + 2)) >>> 0; + } + function expamemz3_put8(addr, value) { + if (!expamem_bank_current) + return; + var reg = addr & 0xff; + if (addr & 0x100) + reg += 2; + if (reg == 0x48) { + if (expamem_type() == zorroII) { + expamem_hi = value & 0xff; + expamem_z2_pointer = ((expamem_hi | (expamem_lo >> 4)) << 16) >>> 0; + expamem_board_pointer = expamem_z2_pointer; + } else { + expamem_lo = value & 0xff; + } + } else if (reg == 0x4a) { + if (expamem_type() == zorroII) + expamem_lo = value & 0xff; } - } + expamem_bank_current.put8(reg, value); + } + function expamemz3_put16(addr, value) { + if (!expamem_bank_current) + return; + var reg = addr & 0xff; + if (addr & 0x100) + reg += 2; + if (reg == 0x44) { + if (expamem_type() == zorroIII) { + expamem_hi = value & 0xff00; + var z3_pointer = ((expamem_hi | (expamem_lo >> 4)) << 16) >>> 0; + if (!expamem_z3hack(SAEV_config)) + expamem_z3_pointer = z3_pointer; + else { + if (z3_pointer != expamem_z3_pointer) { + SAEF_warn("expansion.expamemz3_put16() hack %08x %08x", addr, expamem_z3_pointer); + SAER_Memory_put16(SAER_CPU_regs.a[3] + 0x20, expamem_z3_pointer >>> 16); //ATT regs.regs[11] + SAER_Memory_put16(SAER_CPU_regs.a[3] + 0x28, expamem_z3_pointer >>> 16); + } + } + expamem_board_pointer = expamem_z3_pointer; + } + } + expamem_bank_current.put16(reg, value); + } + function expamemz3_put32(addr, value) { + SAEF_warn("expansion.expamemz3_put32() WRITE.L to address $%08x, value $%08x", addr, value); + } + var expamemz3_bank = new SAEO_Memory_addrbank( + expamemz3_get32, expamemz3_get16, expamemz3_get8, + expamemz3_put32, expamemz3_put16, expamemz3_put8, + SAEF_Memory_defaultXLate, SAEF_Memory_defaultCheck, null, null, "Autoconfig Z3", + SAEF_Memory_dummyGetInst32, SAEF_Memory_dummyGetInst16, + //SAEC_Memory_addrbank_flag_IO | SAEC_Memory_addrbank_flag_SAFE | SAEC_Memory_addrbank_flag_PPCIOSPACE, S_READ, S_WRITE + SAEC_Memory_addrbank_flag_IO | SAEC_Memory_addrbank_flag_SAFE | SAEC_Memory_addrbank_flag_PPCIOSPACE + ); + + /*-----------------------------------------------------------------------*/ + + /*#ifdef CD32 + static addrbank *expamem_map_cd32fmv (void) { + return cd32_fmv_init (expamem_z2_pointer); + } + static addrbank *expamem_init_cd32fmv (int devnum) { + int ids[] = { 23, -1 }; + struct romlist *rl = getromlistbyids (ids, NULL); + struct romdata *rd; + struct zfile *z; + + expamem_init_clear (); + if (!rl) + return NULL; + write_log (_T("CD32 FMV ROM '%s' %d.%d\n"), rl->path, rl->rd->ver, rl->rd->rev); + rd = rl->rd; + z = read_rom (rd); + if (z) { + zfile_fread (expamem, 128, 1, z); + zfile_fclose (z); + } + return NULL; + } + #endif*/ } - diff --git a/sae/filesys.js b/sae/filesys.js new file mode 100644 index 0000000..e615031 --- /dev/null +++ b/sae/filesys.js @@ -0,0 +1,179 @@ +/*------------------------------------------------------------------------- +| SAE - Scripted Amiga Emulator +| https://github.com/naTmeg/ScriptedAmigaEmulator +| +| Copyright (C) 2012-2016 Rupert Hausberger +| +| This program is free software; you can redistribute it and/or +| modify it under the terms of the GNU General Public License +| as published by the Free Software Foundation; either version 2 +| of the License, or (at your option) any later version. +| +| This program is distributed in the hope that it will be useful, +| but WITHOUT ANY WARRANTY; without even the implied warranty of +| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +| GNU General Public License for more details. +| +| Note: ported from WinUAE 3.2.x +-------------------------------------------------------------------------*/ + +function SAEO_Filesys() { + this.uci_set_defaults = function(uci, rdb) { + //memset(uci, 0, sizeof(struct uaedev_config_info)); + //controller + //if (uci.controller_type == 0) + uci.controller_type = SAEC_Config_Mount_Controller_Type_MB_IDE; + uci.controller_unit = 0; //IDE channel + unit + uci.controller_media_type = 0; // 1 = CF IDE, 0 = normal + uci.unit_feature_level = SAEC_Config_Mount_Controller_Level_ATA_2; + uci.unit_special_flags = 0; //1 = force LBA48 + //file + //uci.type = UAEDEV_HDF; + //uci.file.name = ""; + //uci.file.size = 0; + //uci.file.data = ""; + uci.readonly = false; + //rdb + //drive geometry + uci.blocksize = 512; + uci.cyls = 0; // calculated/corrected highcyl + if (!rdb) { + uci.surfaces = 1; + uci.sectors = 32; + } + //partition + uci.bootable = true; + uci.automount = true; + uci.unit = 0; + uci.flags = 0; + uci.devname = ""; + //DosEnvec + uci.sectorsperblock = 1; + if (!rdb) + uci.reserved = 2; + uci.interleave = false; + uci.lowcyl = 0; + uci.highcyl = 0; // zero if detected from size + uci.buffers = 50; + uci.bufmemtype = 1; + uci.maxtransfer = 0x7fffffff; + uci.mask = 0xffffffff; + uci.bootpri = 0; + uci.dostype = 0x444f5301; + //filesystem + uci.filesys = ""; + //DeviceNode + uci.stacksize = 4000; + uci.priority = -129; + //uci.device_emu_unit = -1; + } + + /*-----------------------------------------------------------------------*/ + + function allocuci(p, nr, idx, unitnum) { + if (typeof unitnum == "undefined") + unitnum = -1; + var uci = p.mount.config[nr]; + if (idx >= 0) { + /*var ui = mountinfo.ui[idx]; + ui.configureddrive = 1;*/ + + uci.configoffset = idx; + uci.unitnum = unitnum; + } else { + uci.configoffset = -1; + uci.unitnum = -1; + } + } + + /*---------------------------------*/ + + function getunittype(uci) { + return "HD" //uci.type == UAEDEV_CD ? "CD" : (uci.type == UAEDEV_TAPE ? "TAPE" : "HD"); + } + function ismainboardide() { + return SAEV_config.chipset.ide != 0; + } + /*function isa3000scsi() { + return SAEV_config.chipset.mbdmac == 1; + } + function isa4000tscsi() { + return SAEV_config.chipset.mbdmac == 2; + } + function iscdtvscsi() { + return currprefs.cs_cdtvscsi != 0; + }*/ + function add_mainboard_unit_init() { + if (ismainboardide()) { + SAEF_log("filesys.add_mainboard_unit_init() Initializing mainboard IDE"); + SAER.gayle.gayle_add_ide_unit(-1, null); + } + /*if (isa3000scsi()) { + SAEF_log("filesys.add_mainboard_unit_init() Initializing A3000 mainboard SCSI"); + a3000_add_scsi_unit(-1, null, null); + } + if (isa4000tscsi()) { + SAEF_log("filesys.add_mainboard_unit_init() Initializing A4000T mainboard SCSI"); + a4000t_add_scsi_unit(-1, null, null); + } + if (iscdtvscsi()) { + SAEF_log("filesys.add_mainboard_unit_init() Initializing CDTV SCSI expansion"); + cdtv_add_scsi_unit(-1, null, null); + }*/ + } + + function add_ide_unit(type, unit, uci) { + var added = false; + if (type == SAEC_Config_Mount_Controller_Type_MB_IDE) { + if (ismainboardide()) { + SAEF_log("filesys.add_ide_unit() Adding mainboard IDE %s unit %d ('%s')", getunittype(uci), unit, uci.file.name); + SAER.gayle.gayle_add_ide_unit(unit, uci); + added = true; + } + } + return added; + } + + function initialize_mountinfo() { + // init all controllers first + add_mainboard_unit_init(); + + for (var nr = 0; nr < 6; nr++) { + var uci = SAEV_config.mount.config[nr].ci; + var type = uci.controller_type; + var unit = uci.controller_unit; + var added = false; + if (type == 0 || uci.file.size == 0) + continue; + if (type == SAEC_Config_Mount_Controller_Type_MB_IDE) + added = add_ide_unit(type, unit, uci); + else if (type == SAEC_Config_Mount_Controller_Type_PCMCIA_SRAM) { + SAER.gayle.gayle_add_pcmcia_sram_unit(uci); + added = true; + } + else if (type == SAEC_Config_Mount_Controller_Type_PCMCIA_IDE) { + SAER.gayle.gayle_add_pcmcia_ide_unit(uci); + added = true; + } + if (added) + allocuci(SAEV_config, nr, -1); + } + } + function free_mountinfo() { + SAER.gayle.free_units(); + } + + /*-----------------------------------------------------------------------*/ + + this.start_threads = function() {} //filesys_start_threads() + + this.cleanup = function() { //filesys_cleanup() + free_mountinfo(); + } + + this.reset = function() { //filesys_reset() + free_mountinfo(); + initialize_mountinfo(); + } + this.prepare_reset = function() {} //filesys_prepare_reset() +} diff --git a/sae/gayle.js b/sae/gayle.js new file mode 100644 index 0000000..3b8c629 --- /dev/null +++ b/sae/gayle.js @@ -0,0 +1,1586 @@ +/*------------------------------------------------------------------------- +| SAE - Scripted Amiga Emulator +| https://github.com/naTmeg/ScriptedAmigaEmulator +| +| Copyright (C) 2012-2016 Rupert Hausberger +| +| This program is free software; you can redistribute it and/or +| modify it under the terms of the GNU General Public License +| as published by the Free Software Foundation; either version 2 +| of the License, or (at your option) any later version. +| +| This program is distributed in the hope that it will be useful, +| but WITHOUT ANY WARRANTY; without even the implied warranty of +| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +| GNU General Public License for more details. +| +| Note: ported from WinUAE 3.2.x +-------------------------------------------------------------------------*/ +/* global variables */ + +var SAEV_Gayle_bank = null; +var SAEV_Gayle2_bank = null; + +var SAEV_MBRes_bank = null; +var SAEV_MBRes_gary_timeout = 0; +var SAEV_MBRes_gary_toenb = 0; + +/*---------------------------------*/ + +function SAEO_Gayle() { + /* + 600000 to 9FFFFF 4 MB Credit Card memory if CC present + A00000 to A1FFFF 128 KB Credit Card Attributes + A20000 to A3FFFF 128 KB Credit Card I/O + A40000 to A5FFFF 128 KB Credit Card Bits + A60000 to A7FFFF 128 KB PC I/O + + D80000 to D8FFFF 64 KB SPARE chip select + D90000 to D9FFFF 64 KB ARCNET chip select + DA0000 to DA3FFF 16 KB IDE drive + DA4000 to DA4FFF 16 KB IDE reserved + DA8000 to DAFFFF 32 KB Credit Card and IDE configregisters + DB0000 to DBFFFF 64 KB Not used (reserved for external IDE) + * DC0000 to DCFFFF 64 KB Real Time Clock (RTC) + DD0000 to DDFFFF 64 KB A3000 DMA controller + DD0000 to DD1FFF A4000 DMAC + DD2000 to DDFFFF A4000 IDE + DE0000 to DEFFFF 64 KB Motherboard resources*/ + + + const PCMCIA_COMMON_START = 0x600000; + const PCMCIA_COMMON_SIZE = 0x400000; + + const GAYLE_LOG = 0; //0-6 + const MBRES_LOG = 1; //0-1 + const PCMCIA_LOG = 0; //0-3 + + const PCMCIA_SRAM = 1; + const PCMCIA_IDE = 2; + + /* A4000T NCR */ + const NCR_OFFSET = 0x40; + const NCR_ALT_OFFSET = 0x80; + const NCR_MASK = 0x3f; + + /* Gayle definitions from Linux drivers and preliminary Gayle datasheet */ + + /* PCMCIA stuff */ + + const GAYLE_RAM = 0x600000; + const GAYLE_RAMSIZE = 0x400000; + const GAYLE_ATTRIBUTE = 0xa00000; + const GAYLE_ATTRIBUTESIZE = 0x020000; + const GAYLE_IO = 0xa20000; /* 16bit and even 8bit registers */ + const GAYLE_IOSIZE = 0x010000; + const GAYLE_IO_8BITODD = 0xa30000; /* odd 8bit registers */ + + const GAYLE_ADDRESS = 0xda8000; /* gayle main registers base address */ + const GAYLE_RESET = 0xa40000; /* write 0x00 to start reset, read 1 byte to stop reset */ + + /* Bases of the IDE interfaces */ + const GAYLE_BASE_4000 = 0xdd2020; /* A4000/A4000T */ + const GAYLE_BASE_1200 = 0xda0000; /* A1200/A600 and E-Matrix 530 */ + + /* These are at different offsets from the base */ + const GAYLE_IRQ_4000 = 0x3020; /* WORD register MSB = 1, Harddisk is source of interrupt */ + const GAYLE_CS_1200 = 0x8000; + const GAYLE_IRQ_1200 = 0x9000; + const GAYLE_INT_1200 = 0xA000; + const GAYLE_CFG_1200 = 0xB000; + + /* DA8000 */ + const GAYLE_CS_IDE = 0x80; /* IDE int status */ + const GAYLE_CS_CCDET = 0x40; /* credit card detect */ + const GAYLE_CS_BVD1 = 0x20; /* battery voltage detect 1 */ + const GAYLE_CS_SC = 0x20; /* credit card status change */ + const GAYLE_CS_BVD2 = 0x10; /* battery voltage detect 2 */ + const GAYLE_CS_DA = 0x10; /* digital audio */ + const GAYLE_CS_WR = 0x08; /* write enable (1 == enabled) */ + const GAYLE_CS_BSY = 0x04; /* credit card busy */ + const GAYLE_CS_IRQ = 0x04; /* interrupt request */ + const GAYLE_CS_DAEN = 0x02; /* enable digital audio */ + const GAYLE_CS_DIS = 0x01; /* disable PCMCIA slot */ + + /* DA9000 */ + const GAYLE_IRQ_IDE = 0x80; + const GAYLE_IRQ_CCDET = 0x40; /* credit card detect */ + const GAYLE_IRQ_BVD1 = 0x20; /* battery voltage detect 1 */ + const GAYLE_IRQ_SC = 0x20; /* credit card status change */ + const GAYLE_IRQ_BVD2 = 0x10; /* battery voltage detect 2 */ + const GAYLE_IRQ_DA = 0x10; /* digital audio */ + const GAYLE_IRQ_WR = 0x08; /* write enable (1 == enabled) */ + const GAYLE_IRQ_BSY = 0x04; /* credit card busy */ + const GAYLE_IRQ_IRQ = 0x04; /* interrupt request */ + const GAYLE_IRQ_RESET = 0x02; /* reset machine after CCDET change */ + const GAYLE_IRQ_BERR = 0x01; /* generate bus error after CCDET change */ + + /* DAA000 */ + const GAYLE_INT_IDE = 0x80; /* IDE interrupt enable */ + const GAYLE_INT_CCDET = 0x40; /* credit card detect change enable */ + const GAYLE_INT_BVD1 = 0x20; /* battery voltage detect 1 change enable */ + const GAYLE_INT_SC = 0x20; /* credit card status change enable */ + const GAYLE_INT_BVD2 = 0x10; /* battery voltage detect 2 change enable */ + const GAYLE_INT_DA = 0x10; /* digital audio change enable */ + const GAYLE_INT_WR = 0x08; /* write enable change enabled */ + const GAYLE_INT_BSY = 0x04; /* credit card busy */ + const GAYLE_INT_IRQ = 0x04; /* credit card interrupt request */ + const GAYLE_INT_BVD_LEV = 0x02; /* BVD int level, 0=lev2,1=lev6 */ + const GAYLE_INT_BSY_LEV = 0x01; /* BSY int level, 0=lev2,1=lev6 */ + + /* 0xDAB000 GAYLE_CONFIG */ + const GAYLE_CFG_0V = 0x00; + const GAYLE_CFG_5V = 0x01; + const GAYLE_CFG_12V = 0x02; + const GAYLE_CFG_100NS = 0x08; + const GAYLE_CFG_150NS = 0x04; + const GAYLE_CFG_250NS = 0x00; + const GAYLE_CFG_720NS = 0x0c; + + const TOTAL_IDE = 3; + const GAYLE_IDE_ID = 0; + const PCMCIA_IDE_ID = 2; + + /* copied from ide.js */ + const IDE_DATA = 0x00; + const IDE_ERROR = 0x01; + const IDE_STATUS = 0x07; + const IDE_SECONDARY = 0x0400; + const IDE_DEVCON = 0x0406; + const IDE_DRVADDR = 0x0407; + + /*---------------------------------*/ + + var idedrive = new Array(TOTAL_IDE * 2); //struct ide_hdf * + for (var vi = 0; vi < TOTAL_IDE * 2; vi++) + idedrive[vi] = null; + + var pcmcia_sram = null; //struct hd_hardfiledata *, global + + var pcmcia_card = 0; + var pcmcia_readonly = false; + var pcmcia_type = 0; + var pcmcia_configuration = new Uint8Array(20); + var pcmcia_configured = 0; + + var gayle_id_cnt = 0; + var gayle_irq = 0, gayle_int = 0, gayle_cs = 0, gayle_cs_mask = 0, gayle_cfg = 0; //u8 + var ide_splitter = 0; + + var gayle_its = null; //new SAEO_IDE_threadState(); + + var dataflyer_state = 0; + var dataflyer_disable_irq = 0; + var dataflyer_byte = 0; //u8 + + /*-----------------------------------------------------------------------*/ + + function pcmcia_reset() { + //memset(pcmcia_configuration, 0, sizeof pcmcia_configuration); + SAEF_memset(pcmcia_configuration,0, 0, 20); + pcmcia_configured = -1; + if (PCMCIA_LOG > 0) SAEF_log("gayle.pcmcia_reset()"); + } + + /*-----------------------------------------------------------------------*/ + + function checkpcmciaideirq() { + if (idedrive[PCMCIA_IDE_ID * 2] === null || pcmcia_type != PCMCIA_IDE || pcmcia_configured < 0) + return 0; + if (idedrive[PCMCIA_IDE_ID * 2].regs0 === null || (idedrive[PCMCIA_IDE_ID * 2].regs0.ide_devcon & 2)) + return 0; + if (idedrive[PCMCIA_IDE_ID * 2].irq) + return GAYLE_IRQ_BSY; + return 0; + } + + function checkgayleideirq() { + var irq = false; + + if (dataflyer_disable_irq) { + gayle_irq &= ~GAYLE_IRQ_IDE; + return 0; + } + for (var i = 0; i < 2; i++) { + if (idedrive[i] !== null) { + if (!(idedrive[i].regs.ide_devcon & 2) && (idedrive[i].irq || (idedrive[i + 2] && idedrive[i + 2].irq))) + irq = true; + /* IDE killer feature. Do not eat interrupt to make booting faster. */ + if (idedrive[i].irq && !SAER.ide.ide_isdrive(idedrive[i])) + idedrive[i].irq = 0; + if (idedrive[i + 2] && idedrive[i + 2].irq && !SAER.ide.ide_isdrive(idedrive[i + 2])) + idedrive[i + 2].irq = 0; + } + } + return irq ? GAYLE_IRQ_IDE : 0; + } + + this.rethink = function() { //rethink_gayle() + var lev2 = 0; + var lev6 = 0; + var mask; //u8 + + if (SAEV_config.chipset.ide == SAEC_Config_Chipset_IDE_A4000) { + gayle_irq |= checkgayleideirq(); + if ((gayle_irq & GAYLE_IRQ_IDE) && !(SAEV_Custom_intreq & 0x0008)) + SAER.custom.INTREQ_0(0x8000 | 0x0008); + return; + } + if (SAEV_config.chipset.ide != SAEC_Config_Chipset_IDE_A600A1200 && !SAEV_config.chipset.pcmcia) + return; + gayle_irq |= checkgayleideirq(); + gayle_irq |= checkpcmciaideirq(); + mask = gayle_int & gayle_irq; + if (mask & (GAYLE_IRQ_IDE | GAYLE_IRQ_WR)) + lev2 = 1; + if (mask & GAYLE_IRQ_CCDET) + lev6 = 1; + if (mask & (GAYLE_IRQ_BVD1 | GAYLE_IRQ_BVD2)) { + if (gayle_int & GAYLE_INT_BVD_LEV) + lev6 = 1; + else + lev2 = 1; + } + if (mask & GAYLE_IRQ_BSY) { + if (gayle_int & GAYLE_INT_BSY_LEV) + lev6 = 1; + else + lev2 = 1; + } + if (lev2 && !(SAEV_Custom_intreq & 0x0008)) + SAER.custom.INTREQ_0(0x8000 | 0x0008); + if (lev6 && !(SAEV_Custom_intreq & 0x2000)) + SAER.custom.INTREQ_0(0x8000 | 0x2000); + } + + this.hsync = function() { //gayle_hsync() + if (SAER.ide.ide_interrupt_hsync(idedrive[0]) || SAER.ide.ide_interrupt_hsync(idedrive[2]) || SAER.ide.ide_interrupt_hsync(idedrive[4])) + this.rethink(); + } + + /*-----------------------------------------------------------------------*/ + /* Gayle (low) */ + + function gayle_cs_change(mask, onoff) { + var changed = false; + if ((gayle_cs & mask) && !onoff) { + gayle_cs &= ~mask; + changed = true; + } else if (!(gayle_cs & mask) && onoff) { + gayle_cs |= mask; + changed = true; + } + if (changed) { + gayle_irq |= mask; + SAER.gayle.rethink(); + if ((mask & GAYLE_CS_CCDET) && (gayle_irq & (GAYLE_IRQ_RESET | GAYLE_IRQ_BERR)) != (GAYLE_IRQ_RESET | GAYLE_IRQ_BERR)) { + if (gayle_irq & GAYLE_IRQ_RESET) + SAER.reset(0, 0); + if (gayle_irq & GAYLE_IRQ_BERR) + SAER_CPU_exception(2); + } + } + } + + function card_trigger(insert) { + if (insert) { + if (pcmcia_card) { + gayle_cs_change(GAYLE_CS_CCDET, 1); + gayle_cfg = GAYLE_CFG_100NS; + if (!pcmcia_readonly) + gayle_cs_change(GAYLE_CS_WR, 1); + } + } else { + gayle_cfg = 0; + gayle_cs_change(GAYLE_CS_CCDET, 0); + gayle_cs_change(GAYLE_CS_BVD2, 0); + gayle_cs_change(GAYLE_CS_BVD1, 0); + gayle_cs_change(GAYLE_CS_WR, 0); + gayle_cs_change(GAYLE_CS_BSY, 0); + } + SAER.gayle.rethink(); + } + + function write_gayle_cfg(val) { + gayle_cfg = val; + } + function read_gayle_cfg() { + return gayle_cfg & 0x0f; + } + function write_gayle_irq(val) { + gayle_irq = (gayle_irq & val) | (val & (GAYLE_IRQ_RESET | GAYLE_IRQ_BERR)); + if ((gayle_irq & (GAYLE_IRQ_RESET | GAYLE_IRQ_BERR)) == (GAYLE_IRQ_RESET | GAYLE_IRQ_BERR)) + pcmcia_reset(); + } + function read_gayle_irq() { + return gayle_irq; + } + function write_gayle_int(val) { + gayle_int = val; + } + function read_gayle_int() { + return gayle_int; + } + function write_gayle_cs(val) { + var ov = gayle_cs; + + gayle_cs_mask = val & ~3; + gayle_cs &= ~3; + gayle_cs |= val & 3; + if ((ov & 1) != (gayle_cs & 1)) { + SAER.gayle.map_pcmcia(); + /* PCMCIA disable -> enable */ + card_trigger(!(gayle_cs & GAYLE_CS_DIS) ? 1 : 0); + if (PCMCIA_LOG) + SAEF_log("gayle.write_gayle_cs() %s, PC %x", !(gayle_cs & 1) ? "enabled" : "disabled", SAER_CPU_getPC()); + } + } + function read_gayle_cs() { + var v = gayle_cs_mask | gayle_cs; //u8 + v |= checkgayleideirq(); + v |= checkpcmciaideirq(); + return v; + } + + /*---------------------------------*/ + + function get_gayle_ide_reg(addr) { //, struct ide_hdf **ide) + addr &= 0xffff; + // *ide = NULL; + if (addr >= GAYLE_IRQ_4000 && addr <= GAYLE_IRQ_4000 + 1 && SAEV_config.chipset.ide == SAEC_Config_Chipset_IDE_A4000) + return { addr:-1, unit:-1 }; + addr &= ~0x2020; + addr >>= 2; + var ide2 = 0; + if (addr & IDE_SECONDARY) { + if (ide_splitter) { + ide2 = 2; + addr &= ~IDE_SECONDARY; + } + } + // *ide = idedrive[ide2 + idedrive[ide2]->ide_drv]; + //return addr; + return { addr:addr, unit:ide2 + idedrive[ide2].ide_drv }; + } + + function gayle_read2(addr) { + addr &= 0xffff; + if ((GAYLE_LOG > 3 && (addr != 0x2000 && addr != 0x2001 && addr != 0x3020 && addr != 0x3021 && addr != GAYLE_IRQ_1200)) || GAYLE_LOG > 5) + SAEF_log("gayle.gayle_read2(%08x) PC %x", addr, SAER_CPU_getPC()); + + if (SAEV_config.chipset.ide <= 0) { + if (addr == 0x201c) // AR1200 IDE detection hack + return 0x7f; + return 0xff; + } + if (addr >= GAYLE_IRQ_4000 && addr <= GAYLE_IRQ_4000 + 1 && SAEV_config.chipset.ide == SAEC_Config_Chipset_IDE_A4000) { + var v = gayle_irq; + gayle_irq = 0; + return v; + } + if (addr >= 0x4000) { + if (addr == GAYLE_IRQ_1200) { + if (SAEV_config.chipset.ide == SAEC_Config_Chipset_IDE_A600A1200) + return read_gayle_irq(); + return 0; + } else if (addr == GAYLE_INT_1200) { + if (SAEV_config.chipset.ide == SAEC_Config_Chipset_IDE_A600A1200) + return read_gayle_int(); + return 0; + } + return 0; + } + var query = get_gayle_ide_reg(addr); + /* Emulated "ide killer". Prevents long KS boot delay if no drives installed */ + if (!SAER.ide.ide_isdrive(idedrive[0]) && !SAER.ide.ide_isdrive(idedrive[1]) && !SAER.ide.ide_isdrive(idedrive[2]) && !SAER.ide.ide_isdrive(idedrive[3])) { + if (query.addr == IDE_STATUS) + return 0x7f; + return 0xff; + } + if (query.addr != -1) //OWN + return SAER.ide.ide_read_reg(idedrive[query.unit], query.addr); + + return 0; //OWN + } + + function gayle_write2(addr, val) { + if ((GAYLE_LOG > 3 && (addr != 0x2000 && addr != 0x2001 && addr != 0x3020 && addr != 0x3021 && addr != GAYLE_IRQ_1200)) || GAYLE_LOG > 5) + SAEF_log("gayle.gayle_write2(%08x, %02x) PC %x", addr, val & 0xff, SAER_CPU_getPC()); + + if (SAEV_config.chipset.ide <= 0) + return; + if (SAEV_config.chipset.ide == SAEC_Config_Chipset_IDE_A600A1200) { + if (addr == GAYLE_IRQ_1200) { + write_gayle_irq(val); + return; + } + if (addr == GAYLE_INT_1200) { + write_gayle_int(val); + return; + } + } + if (addr >= 0x4000) + return; + var query = get_gayle_ide_reg(addr); + if (query.addr != -1) //OWN + SAER.ide.ide_write_reg(idedrive[query.unit], query.addr, val); + } + + function gayle_read(addr) { + var oaddr = addr; + var v = 0; //u32 + var got = false; + if (SAEV_config.chipset.ide == SAEC_Config_Chipset_IDE_A600A1200) { + if ((addr & 0xA0000) != 0xA0000) + return 0; + } + addr &= 0xffff; + if (SAEV_config.chipset.pcmcia) { + if (SAEV_config.chipset.ide != SAEC_Config_Chipset_IDE_A600A1200) { + if (addr == GAYLE_IRQ_1200) { + v = read_gayle_irq(); + got = true; + } else if (addr == GAYLE_INT_1200) { + v = read_gayle_int(); + got = true; + } + } + if (addr == GAYLE_CS_1200) { + v = read_gayle_cs(); + got = true; + if (PCMCIA_LOG) + SAEF_log("gayle.gayle_read(%08x) PCMCIA STATUS %02x, PC %x", oaddr, v & 0xff, SAER_CPU_getPC()); + } else if (addr == GAYLE_CFG_1200) { + v = read_gayle_cfg(); + got = true; + if (PCMCIA_LOG) + SAEF_log("gayle.gayle_read(%08x) PCMCIA CONFIG %02x, PC %x", oaddr, v & 0xff, SAER_CPU_getPC()); + } + } + if (!got) + v = gayle_read2(addr); + if (GAYLE_LOG) + SAEF_log("gayle.gayle_read(%08x) %02x, PC %x", oaddr, v & 0xff, SAER_CPU_getPC()); + return v; + } + + function gayle_write(addr, val) { + var oaddr = addr; + var got = false; + if (SAEV_config.chipset.ide == SAEC_Config_Chipset_IDE_A600A1200) { + if ((addr & 0xA0000) != 0xA0000) + return; + } + addr &= 0xffff; + if (SAEV_config.chipset.pcmcia) { + if (SAEV_config.chipset.ide != SAEC_Config_Chipset_IDE_A600A1200) { + if (addr == GAYLE_IRQ_1200) { + write_gayle_irq(val); + got = true; + } else if (addr == GAYLE_INT_1200) { + write_gayle_int(val); + got = true; + } + } + if (addr == GAYLE_CS_1200) { + write_gayle_cs(val); + got = true; + if (PCMCIA_LOG > 1) + SAEF_log("gayle.gayle_write(%08x, %02x) PCMCIA STATUS PC %x", oaddr, val & 0xff, SAER_CPU_getPC()); + } else if (addr == GAYLE_CFG_1200) { + write_gayle_cfg(val); + got = 1; + if (PCMCIA_LOG > 1) + SAEF_log("gayle.gayle_write(%08x, %02x) PCMCIA CONFIG PC %x", oaddr, val & 0xff, SAER_CPU_getPC()); + } + } + + if (GAYLE_LOG) + SAEF_log("gayle.gayle_write(%08x, %02x) PC %x", oaddr, val & 0xff, SAER_CPU_getPC()); + if (!got) + gayle_write2(addr, val); + } + + this.gayle_dataflyer_enable = function(enable) { + if (!enable) { + dataflyer_state = 0; + dataflyer_disable_irq = 0; + } else + dataflyer_state = 1; + } + + //function isdataflyerscsiplus(uaecptr addr, uae_u32 *v, int size) + function isdataflyerscsiplus(addr, v, size) { + if (!dataflyer_state) + return false; + /*uaecptr addrmask = addr & 0xffff; + if (addrmask >= GAYLE_IRQ_4000 && addrmask <= GAYLE_IRQ_4000 + 1 && SAEV_config.chipset.ide == SAEC_Config_Chipset_IDE_A4000) + return false; + uaecptr addrbase = (addr & ~0xff) & ~0x1020; + int reg = ((addr & 0xffff) & ~0x2020) >> 2; + if (reg >= IDE_SECONDARY) { + reg &= ~IDE_SECONDARY; + if (reg >= 6) // normal IDE registers + return false; + if (size < 0) { + switch (reg) + { + case 0: // 53C80 fake dma port + soft_scsi_put(addrbase | 8, 1, *v); + break; + case 3: + dataflyer_byte = *v; + break; + } + } else { + switch (reg) + { + case 0: // 53C80 fake dma port + *v = soft_scsi_get(addrbase | 8, 1); + break; + case 3: + *v = 0; + if (ide_irq_check(idedrive[0], false)) + *v = dataflyer_byte; + break; + case 4: // select SCSI + dataflyer_disable_irq = 1; + dataflyer_state |= 2; + break; + case 5: // select IDE + dataflyer_disable_irq = 1; + dataflyer_state &= ~2; + break; + } + } + #if 0 + if (size < 0) + write_log(_T("SECONDARY BASE PUT(%d) %08x %08x PC=%08x\n"), -size, addr, *v, SAER_CPU_getPC()); + else + write_log(_T("SECONDARY BASE GET(%d) %08x PC=%08x\n"), size, addr, SAER_CPU_getPC()); + #endif + return true; + } + if (!(dataflyer_state & 2)) + return false; + if (size < 0) + soft_scsi_put(addrbase | reg, -size, *v); + else + *v = soft_scsi_get(addrbase | reg, size);*/ + return true; + } + + /*function isa4000t(*paddr) { + if (SAEV_config.chipset.mbdmac != 2) + return false; + uaecptr addr = *paddr; + if ((addr & 0xffff) >= (GAYLE_BASE_4000 & 0xffff)) + return false; + addr &= 0xff; + *paddr = addr; + return true; + }*/ + + function gayle_get32(addr) { + /*#ifdef NCR + var v; + if (SAEV_config.chipset.mbdmac == 2 && (addr & 0xffff) == 0x3000) + return 0xffffffff; // NCR DIP BANK + if (isdataflyerscsiplus(addr, &v, 4)) { + return v; + } + if (isa4000t(&addr)) { + if (addr >= NCR_ALT_OFFSET) { + addr &= NCR_MASK; + v = (ncr710_io_get8_a4000t(addr + 3) << 0) | (ncr710_io_get8_a4000t(addr + 2) << 8) | + (ncr710_io_get8_a4000t(addr + 1) << 16) | (ncr710_io_get8_a4000t(addr + 0) << 24); + } else if (addr >= NCR_OFFSET) { + addr &= NCR_MASK; + v = (ncr710_io_get8_a4000t(addr + 3) << 0) | (ncr710_io_get8_a4000t(addr + 2) << 8) | + (ncr710_io_get8_a4000t(addr + 1) << 16) | (ncr710_io_get8_a4000t(addr + 0) << 24); + } + return v; + } + #endif*/ + var query = get_gayle_ide_reg(addr); + if (query.addr == IDE_DATA) { + var ide = idedrive[query.unit]; + return ((SAER.ide.ide_get_data(ide) << 16) | SAER.ide.ide_get_data(ide)) >>> 0; + } + return ((gayle_get16(addr) << 16) | gayle_get16(addr + 2)) >>> 0; + } + function gayle_get16(addr) { + /*#ifdef NCR + var v; + if (SAEV_config.chipset.mbdmac == 2 && (addr & (0xffff - 1)) == 0x3000) + return 0xffff; // NCR DIP BANK + if (isdataflyerscsiplus(addr, &v, 2)) { + return v; + } + if (isa4000t(&addr)) { + if (addr >= NCR_OFFSET) { + addr &= NCR_MASK; + v = (ncr710_io_get8_a4000t(addr) << 8) | ncr710_io_get8_a4000t(addr + 1); + } + return v; + } + #endif*/ + var query = get_gayle_ide_reg(addr); + if (query.addr == IDE_DATA) { + var ide = idedrive[query.unit]; + return SAER.ide.ide_get_data(ide); + } + return (gayle_get8(addr) << 8) | gayle_get8(addr + 1); + } + function gayle_get8(addr) { + /*#ifdef NCR + var v; + if (SAEV_config.chipset.mbdmac == 2 && (addr & (0xffff - 3)) == 0x3000) + return 0xff; // NCR DIP BANK + if (isdataflyerscsiplus(addr, &v, 1)) { + return v; + } + if (isa4000t(&addr)) { + if (addr >= NCR_OFFSET) { + addr &= NCR_MASK; + return ncr710_io_get8_a4000t(addr); + } + return 0; + } + #endif*/ + return gayle_read(addr); //ATT limits + } + + function gayle_put32(addr, value) { + /*if (isdataflyerscsiplus(addr, &value, -4)) + return; + if (isa4000t(&addr)) { + if (addr >= NCR_ALT_OFFSET) { + addr &= NCR_MASK; + ncr710_io_put8_a4000t(addr + 3, value >> 0); + ncr710_io_put8_a4000t(addr + 2, value >> 8); + ncr710_io_put8_a4000t(addr + 1, value >> 16); + ncr710_io_put8_a4000t(addr + 0, value >> 24); + } else if (addr >= NCR_OFFSET) { + addr &= NCR_MASK; + ncr710_io_put8_a4000t(addr + 3, value >> 0); + ncr710_io_put8_a4000t(addr + 2, value >> 8); + ncr710_io_put8_a4000t(addr + 1, value >> 16); + ncr710_io_put8_a4000t(addr + 0, value >> 24); + } + return; + }*/ + var query = get_gayle_ide_reg(addr); + if (query.addr == IDE_DATA) { + var ide = idedrive[query.unit]; + SAER.ide.ide_put_data(ide, value >>> 16); + SAER.ide.ide_put_data(ide, value & 0xffff); + return; + } + gayle_put16(addr, value >>> 16); + gayle_put16(addr + 2, value & 0xffff); + } + function gayle_put16(addr, value) { + /*#ifdef NCR + if (isdataflyerscsiplus(addr, &value, -2)) { + return; + } + if (isa4000t(&addr)) { + if (addr >= NCR_OFFSET) { + addr &= NCR_MASK; + ncr710_io_put8_a4000t(addr, value >> 8); + ncr710_io_put8_a4000t(addr + 1, value); + } + return; + } + #endif*/ + var query = get_gayle_ide_reg(addr); + if (query.addr == IDE_DATA) { + var ide = idedrive[query.unit]; + SAER.ide.ide_put_data(ide, value); + return; + } + gayle_put8(addr, value >> 8); + gayle_put8(addr + 1, value & 0xff); + } + function gayle_put8(addr, value) { + /*#ifdef NCR + if (isdataflyerscsiplus(addr, &value, -1)) { + return; + } + if (isa4000t(&addr)) { + if (addr >= NCR_OFFSET) { + addr &= NCR_MASK; + ncr710_io_put8_a4000t(addr, value); + } + return; + } + #endif*/ + gayle_write(addr, value); //ATT limits + } + + //DECLARE_MEMORY_FUNCTIONS(gayle); + //addrbank gayle_bank = { + SAEV_Gayle_bank = new SAEO_Memory_addrbank( + gayle_get32, gayle_get16, gayle_get8, + gayle_put32, gayle_put16, gayle_put8, + SAEF_Memory_defaultXLate, SAEF_Memory_defaultCheck, null, null, "Gayle (low)", + SAEF_Memory_dummyGetInst32, SAEF_Memory_dummyGetInst16, + SAEC_Memory_addrbank_flag_IO //, S_READ, S_WRITE + ); + + /*---------------------------------*/ + /* Gayle (high) */ + + function gayle2_read(addr) { + var v = 0; //u8 + if ((addr & 0xffff) == 0x1000) { + /* Gayle ID. Gayle = 0xd0. AA Gayle = 0xd1 */ + if (gayle_id_cnt == 0 || gayle_id_cnt == 1 || gayle_id_cnt == 3 || ((SAEV_config.chipset.mask & SAEC_Config_Chipset_Mask_AGA) && gayle_id_cnt == 7) + // || (currprefs.cs_cd32cd && !SAEV_config.chipset.ide && !SAEV_config.chipset.pcmcia && gayle_id_cnt == 2) + ) v = 0x80; + gayle_id_cnt++; + } + return v; + } + + function gayle2_write(addr, v) { + gayle_id_cnt = 0; + } + + function gayle2_get32(addr) { + return ((gayle2_get16(addr) << 16) | gayle2_get16(addr + 2)) >>> 0; + } + function gayle2_get16(addr) { + return (gayle2_get8(addr) << 8) | gayle2_get8(addr + 1); + } + function gayle2_get8(addr) { + return gayle2_read(addr); + } + + function gayle2_put32(addr, value) { + gayle2_put16(addr, value >>> 16); + gayle2_put16(addr + 2, value & 0xffff); + } + function gayle2_put16(addr, value) { + gayle2_put8(addr, value >> 8); + gayle2_put8(addr + 1, value & 0xff); + } + function gayle2_put8(addr, value) { + gayle2_write(addr, value); + } + + //DECLARE_MEMORY_FUNCTIONS(gayle2); + //addrbank gayle2_bank = { + SAEV_Gayle2_bank = new SAEO_Memory_addrbank( + gayle2_get32, gayle2_get16, gayle2_get8, + gayle2_put32, gayle2_put16, gayle2_put8, + SAEF_Memory_defaultXLate, SAEF_Memory_defaultCheck, null, null, "Gayle (high)", + SAEF_Memory_dummyGetInst32, SAEF_Memory_dummyGetInst16, + SAEC_Memory_addrbank_flag_IO //, S_READ, S_WRITE + ); + + /*-----------------------------------------------------------------------*/ + /* Motherboard Resources */ + + var ramsey_config = 0; //u8 + var garyidoffset = 0; + var gary_coldboot = 0; + //var gary_timeout = 0; -> SAEV_MBRes_gary_timeout + //var gary_toenb = 0; -> SAEV_MBRes_gary_toenb + + function mbres_read(addr, size) { + var v = 0; + addr &= 0xffff; + if (1 || SAER_CPU_regs.s) { /* CPU FC = supervisor only (only newest ramsey/gary? never implemented?) */ + var addr2 = addr & 3; + var addr64 = (addr >> 6) & 3; + /* Gary ID (I don't think this exists in real chips..) */ + if (addr == 0x1002 && SAEV_config.chipset.fatGaryRev >= 0) { + garyidoffset++; + garyidoffset &= 7; + v = (SAEV_config.chipset.fatGaryRev << garyidoffset) & 0x80; + } + for (;;) { + if (addr64 == 1 && addr2 == 0x03) { /* RAMSEY revision */ + if (SAEV_config.chipset.ramseyRev >= 0) + v = SAEV_config.chipset.ramseyRev; + break; + } + if (addr64 == 0 && addr2 == 0x03) { /* RAMSEY config */ + if (SAEV_config.chipset.ramseyRev >= 0) + v = ramsey_config; + break; + } + if (addr2 == 0x03) { + v = 0xff; + break; + } + if (addr2 == 0x02) { /* coldreboot flag */ + if (SAEV_config.chipset.fatGaryRev >= 0) + v = gary_coldboot ? 0x80 : 0x00; + } + if (addr2 == 0x01) { /* toenb flag */ + if (SAEV_config.chipset.fatGaryRev >= 0) + v = SAEV_MBRes_gary_toenb ? 0x80 : 0x00; + } + if (addr2 == 0x00) { /* timeout flag */ + if (SAEV_config.chipset.fatGaryRev >= 0) + v = SAEV_MBRes_gary_timeout ? 0x80 : 0x00; + } + v |= 0x7f; + break; + } + } else { + v = 0xff; + } + if (MBRES_LOG > 0) + SAEF_log("gayle.mbres_read(%08x, %d) %08x, PC %x, S %d", addr, size, v, SAER_CPU_getPC(), SAER_CPU_regs.s ? 1 : 0); + return v; + } + + function mbres_write(addr, val, size) { + addr &= 0xffff; + if (MBRES_LOG > 0) + SAEF_log("gayle.mbres_write(%08x, %08x, %d) PC %x, S %d", addr, val, size, SAER_CPU_getPC(), SAER_CPU_regs.s ? 1 : 0); + if (addr < 0x8000 && (1 || SAER_CPU_regs.s)) { /* CPU FC = supervisor only */ + var addr2 = addr & 3; + var addr64 = (addr >> 6) & 3; + if (addr == 0x1002) + garyidoffset = -1; + if (addr64 == 0 && addr2 == 0x03) + ramsey_config = val; + if (addr2 == 0x02) + gary_coldboot = (val & 0x80) ? 1 : 0; + if (addr2 == 0x01) + SAEV_MBRes_gary_toenb = (val & 0x80) ? 1 : 0; + if (addr2 == 0x00) + SAEV_MBRes_gary_timeout = (val & 0x80) ? 1 : 0; + } + } + + function mbres_get32(addr) { + return ((mbres_get16(addr) << 16) | mbres_get16(addr + 2)) >>> 0; + } + function mbres_get16(addr) { + return mbres_read(addr, 2); + } + function mbres_get8(addr) { + return mbres_read(addr, 1); + } + + function mbres_put32(addr, value) { + mbres_put16(addr, value >>> 16); + mbres_put16(addr + 2, value & 0xffff); + } + function mbres_put16(addr, value) { + mbres_write(addr, value, 2); + } + function mbres_put8(addr, value) { + mbres_write(addr, value, 1); + } + + var mbres_sub_bank = new SAEO_Memory_addrbank( + mbres_get32, mbres_get16, mbres_get8, + mbres_put32, mbres_put16, mbres_put8, + SAEF_Memory_defaultXLate, SAEF_Memory_defaultCheck, null, null, "Motherboard Resources", + SAEF_Memory_dummyGetInst32, SAEF_Memory_dummyGetInst16, + SAEC_Memory_addrbank_flag_IO //, S_READ, S_WRITE, + ); + SAEV_MBRes_bank = new SAEO_Memory_addrbank( //mbres_bank + SAEF_Memory_subBankGet32, SAEF_Memory_subBankGet16, SAEF_Memory_subBankGet8, + SAEF_Memory_subBankPut32, SAEF_Memory_subBankPut16, SAEF_Memory_subBankPut8, + SAEF_Memory_subBankXLate, SAEF_Memory_subBankCheck, null, null, "Motherboard Resources", + SAEF_Memory_subBankGetInst32, SAEF_Memory_subBankGetInst16, + SAEC_Memory_addrbank_flag_IO, /* S_READ, S_WRITE, */ [ + new SAEO_Memory_addrbank_sub(mbres_sub_bank, 0x0000), + new SAEO_Memory_addrbank_sub(SAEV_Memory_dummyBank, 0x8000), + new SAEO_Memory_addrbank_sub(null, 0) + ] + ); + + /*-----------------------------------------------------------------------*/ + /* PCMCIA support */ + + var pcmcia_common_size = 0, pcmcia_attrs_size = 0; + var pcmcia_common = null; //u8 * + var pcmcia_attrs = null; //u8 * + var pcmcia_write_min = 0, pcmcia_write_max = 0; + var pcmcia_idedata = 0; //u16 + + function get_pcmcmia_ide_reg(addr, width) { //, struct ide_hdf **ide) + // *ide = NULL; + addr &= 0x80000 - 1; + if (addr < 0x20000) + return { reg:-1, unit:-1 }; /* attribute */ + if (addr >= 0x40000) + return { reg:-1, unit:-1 }; + addr -= 0x20000; + // 8BITODD + if (addr >= 0x10000) { + addr &= ~0x10000; + addr |= 1; + } + // *ide = idedrive[PCMCIA_IDE_ID * 2]; + var unit = PCMCIA_IDE_ID * 2; + //if ((*ide)->ide_drv) + if (idedrive[unit].ide_drv) + //*ide = idedrive[PCMCIA_IDE_ID * 2 + 1]; + unit = PCMCIA_IDE_ID * 2 + 1; + + var reg = -1; + if (pcmcia_configured == 1) { + // IO mapped linear + reg = addr & 15; + if (reg < 8) + return reg; + if (reg == 8) + reg = IDE_DATA; + else if (reg == 9) + reg = IDE_DATA; + else if (reg == 13) + reg = IDE_ERROR; + else if (reg == 14) + reg = IDE_DEVCON; + else if (reg == 15) + reg = IDE_DRVADDR; + else + reg = -1; + } else if (pcmcia_configured == 2) { + // primary io mapped (PC) + if (addr >= 0x1f0 && addr <= 0x1f7) + reg = addr - 0x1f0; + else if (addr == 0x3f6) + reg = IDE_DEVCON; + else if (addr == 0x3f7) + reg = IDE_DRVADDR; + else + reg = -1; + } + return { reg:reg, unit:unit }; + } + + function checkflush(addr) { + if (pcmcia_card == 0 || pcmcia_sram === null) + return; + if (addr >= 0 && pcmcia_common[0] == 0 && pcmcia_common[1] == 0 && pcmcia_common[2] == 0) + return; // do not flush periodically if used as a ram expension + if (addr < 0) { + pcmcia_write_min = 0; + pcmcia_write_max = pcmcia_common_size; + } + if (pcmcia_write_min >= 0) { + if (Math.abs(pcmcia_write_min - addr) >= 512 || Math.abs(pcmcia_write_max - addr) >= 512) { + var blocksize = pcmcia_sram.hfd.ci.blocksize; + var mask = ~(blocksize - 1) >>> 0; + var start = (pcmcia_write_min & mask) >>> 0; + var end = ((pcmcia_write_max + blocksize - 1) & mask) >>> 0; + var len = end - start; + if (len > 0) { + //SAER.hardfile.hdf_write(pcmcia_sram.hfd, pcmcia_common + start, start, len); //ATT + + SAER.hardfile.hdf_write(pcmcia_sram.hfd, pcmcia_common.subarray(start), start, len); + pcmcia_write_min = -1; + pcmcia_write_max = -1; + } + } + } + if (pcmcia_write_min < 0 || pcmcia_write_min > addr) + pcmcia_write_min = addr; + if (pcmcia_write_max < 0 || pcmcia_write_max < addr) + pcmcia_write_max = addr; + } + + /*-----------------------------------------------------------------------*/ + /* PCMCIA Common */ + + function gayle_common_read(addr) { + if (PCMCIA_LOG > 2) + SAEF_log("gayle.gayle_common_read(%x) PC %x", addr, SAER_CPU_getPC()); + if (!pcmcia_common_size) + return 0; + addr -= PCMCIA_COMMON_START & (PCMCIA_COMMON_SIZE - 1); + addr &= PCMCIA_COMMON_SIZE - 1; + if (addr < pcmcia_common_size) + return pcmcia_common[addr]; + return 0; + } + + function gayle_common_write(addr, v) { + if (PCMCIA_LOG > 2) + SAEF_log("gayle.gayle_common_write(%x, %x) PC %x", addr, v, SAER_CPU_getPC()); + if (!pcmcia_common_size) + return; + if (pcmcia_readonly) + return; + addr -= PCMCIA_COMMON_START & (PCMCIA_COMMON_SIZE - 1); + addr &= PCMCIA_COMMON_SIZE - 1; + if (addr < pcmcia_common_size) { + if (pcmcia_common[addr] != v) { + checkflush(addr); + pcmcia_common[addr] = v; + } + } + } + + function gayle_common_get32(addr) { + return ((gayle_common_get16(addr) << 16) | gayle_common_get16(addr + 2)) >>> 0; + } + function gayle_common_get16(addr) { + return (gayle_common_get8(addr) << 8) | gayle_common_get8(addr + 1); + } + function gayle_common_get8(addr) { + return gayle_common_read(addr); + } + function gayle_common_put32(addr, value) { + gayle_common_put16(addr, value >>> 16); + gayle_common_put16(addr + 2, value & 0xffff); + } + function gayle_common_put16(addr, value) { + gayle_common_put8(addr, value >> 8); + gayle_common_put8(addr + 1, value & 0xff); + } + function gayle_common_put8(addr, value) { + gayle_common_write(addr, value); + } + + function gayle_common_check(addr, size) { + if (!pcmcia_common_size) + return 0; + addr -= PCMCIA_COMMON_START & (PCMCIA_COMMON_SIZE - 1); + addr &= PCMCIA_COMMON_SIZE - 1; + return (addr + size) <= PCMCIA_COMMON_SIZE; + } + + function gayle_common_xlate(addr) { + addr -= PCMCIA_COMMON_START & (PCMCIA_COMMON_SIZE - 1); + addr &= PCMCIA_COMMON_SIZE - 1; + //return pcmcia_common + addr; + return addr; + } + + var gayle_common_bank = new SAEO_Memory_addrbank( + gayle_common_get32, gayle_common_get16, gayle_common_get8, + gayle_common_put32, gayle_common_put16, gayle_common_put8, + gayle_common_xlate, gayle_common_check, null, null, "Gayle PCMCIA Common", + gayle_common_get32, gayle_common_get16, + SAEC_Memory_addrbank_flag_RAM | SAEC_Memory_addrbank_flag_SAFE //, S_READ, S_WRITE + ); + + /*-----------------------------------------------------------------------*/ + /* PCMCIA Attribute/Misc */ + + function gayle_attr_read(addr) { + if (PCMCIA_LOG > 1) + SAEF_log("gayle.gayle_attr_read(%x) PCMCIA ATTR, PC %x", addr, SAER_CPU_getPC()); + addr &= 0x80000 - 1; + if (addr >= 0x40000) { + if (PCMCIA_LOG > 0) + SAEF_log("gayle.gayle_attr_read() reset disabled"); + return 0; + } + if (addr >= pcmcia_attrs_size) + return 0; + if (pcmcia_type == PCMCIA_IDE) { + if (addr >= 0x200 && addr < 0x200 + pcmcia_configuration.length * 2) { + var offset = (addr - 0x200) >> 1; + return pcmcia_configuration[offset]; + } + if (pcmcia_configured >= 0) { + var query = get_pcmcmia_ide_reg(addr, 1); + if (query.reg >= 0) { + var ide = idedrive[query.unit]; + if (query.reg == 0) { + if (addr >= 0x30000) { + return pcmcia_idedata & 0xff; + } else { + pcmcia_idedata = SAER.ide.ide_get_data(ide); + return (pcmcia_idedata >> 8) & 0xff; + } + } else + return SAER.ide.ide_read_reg(ide, query.reg); + } + } + } + return pcmcia_attrs[addr >> 1]; + } + + function gayle_attr_write(addr, v) { + if (PCMCIA_LOG > 1) + SAEF_log("gayle.gayle_attr_write(%x, %x) PCMCIA ATTR, PC %x", addr, v, SAER_CPU_getPC()); + addr &= 0x80000 - 1; + if (addr >= 0x40000) { + if (PCMCIA_LOG > 0) + SAEF_log("gayle.gayle_attr_write() reset enabled"); + pcmcia_reset(); + } else if (addr < pcmcia_attrs_size) { + if (pcmcia_type == PCMCIA_IDE) { + if (addr >= 0x200 && addr < 0x200 + pcmcia_configuration.length * 2) { + var offset = (addr - 0x200) >> 1; + pcmcia_configuration[offset] = v; + if (offset == 0) { + if (v & 0x80) { + pcmcia_reset(); + } else { + var index = v & 0x3f; + if (index != 1 && index != 2) { + SAEF_warn("gayle.gayle_attr_write() only config index 1 and 2 emulated, attempted to select %d!", index); + } else { + pcmcia_configured = index; + SAEF_log("gayle.gayle_attr_write() PCMCIA IO configured = %02x", v); + } + } + } + } + if (pcmcia_configured >= 0) { + var query = get_pcmcmia_ide_reg(addr, 1); + if (query.reg >= 0) { + var ide = idedrive[query.unit]; + if (query.reg == 0) { + if (addr >= 0x30000) { + pcmcia_idedata = (v & 0xff) << 8; + } else { + pcmcia_idedata &= 0xff00; + pcmcia_idedata |= v & 0xff; + SAER.ide.ide_put_data(ide, pcmcia_idedata); + } + return; + } + SAER.ide.ide_write_reg(ide, query.reg, v); + } + } + } + } + } + + function gayle_attr_get32(addr) { + return ((gayle_attr_get16(addr) << 16) | gayle_attr_get16(addr + 2)) >>> 0; + } + function gayle_attr_get16(addr) { + if (pcmcia_type == PCMCIA_IDE && pcmcia_configured >= 0) { + var query = get_pcmcmia_ide_reg(addr, 2); + if (query.reg == IDE_DATA) { + // 16-bit register + pcmcia_idedata = SAER.ide.ide_get_data(idedrive[query.unit]); + return pcmcia_idedata; + } + } + return (gayle_attr_get8(addr) << 8) | gayle_attr_get8(addr + 1); + } + function gayle_attr_get8(addr) { + return gayle_attr_read(addr); + } + + function gayle_attr_put32(addr, value) { + gayle_attr_put16(addr, value >>> 16); + gayle_attr_put16(addr + 2, value & 0xffff); + } + function gayle_attr_put16 (addr, value) { + if (pcmcia_type == PCMCIA_IDE && pcmcia_configured >= 0) { + var query = get_pcmcmia_ide_reg(addr, 2); + if (query.reg == IDE_DATA) { + // 16-bit register + pcmcia_idedata = value; + SAER.ide.ide_put_data(idedrive[query.unit], pcmcia_idedata); + return; + } + } + gayle_attr_put8(addr, value >> 8); + gayle_attr_put8(addr + 1, value & 0xff); + } + function gayle_attr_put8 (addr, value) { + gayle_attr_write(addr, value); + } + + var gayle_attr_bank = new SAEO_Memory_addrbank( + gayle_attr_get32, gayle_attr_get16, gayle_attr_get8, + gayle_attr_put32, gayle_attr_put16, gayle_attr_put8, + SAEF_Memory_defaultXLate, SAEF_Memory_defaultCheck, null, null, "Gayle PCMCIA Attribute/Misc", + SAEF_Memory_dummyGetInst32, SAEF_Memory_dummyGetInst16, + SAEC_Memory_addrbank_flag_IO | SAEC_Memory_addrbank_flag_SAFE //, S_READ, S_WRITE + ); + + /*-----------------------------------------------------------------------*/ + /* setup/cleanup/reset */ + + function setCSTR(p, po, s) { //OWN + var sl = s.length; + p.set(SAEF_String2Array(s, 0, sl), po); + p[po + sl] = 0; + return sl + 1; + } + function initscideattr(readonly) { + var p = pcmcia_attrs; + var po = 0; //OWN + //var hfd = pcmcia_sram.hfd; + + /* Mostly just copied from real CF cards.. */ + + /* CISTPL_DEVICE */ + p[po++] = 0x01; + p[po++] = 0x04; + p[po++] = 0xdf; + p[po++] = 0x4a; + p[po++] = 0x01; + p[po++] = 0xff; + + /* CISTPL_DEVICEOC */ + p[po++] = 0x1c; + p[po++] = 0x04; + p[po++] = 0x02; + p[po++] = 0xd9; + p[po++] = 0x01; + p[po++] = 0xff; + + /* CISTPL_JEDEC */ + p[po++] = 0x18; + p[po++] = 0x02; + p[po++] = 0xdf; + p[po++] = 0x01; + + /* CISTPL_VERS_1 */ + p[po++]= 0x15; + var rp = po++; + p[po++]= 4; /* PCMCIA 2.1 */ + p[po++]= 1; + po += setCSTR(p, po, "UAE"); + po += setCSTR(p, po, "68000"); + po += setCSTR(p, po, "Generic Emulated PCMCIA IDE"); + p[po++]= 0xff; + p[rp] = po - rp - 1; + + /* CISTPL_FUNCID */ + p[po++] = 0x21; + p[po++] = 0x02; + p[po++] = 0x04; + p[po++] = 0x01; + + /* CISTPL_FUNCE */ + p[po++] = 0x22; + p[po++] = 0x02; + p[po++] = 0x01; + p[po++] = 0x01; + + /* CISTPL_FUNCE */ + p[po++] = 0x22; + p[po++] = 0x03; + p[po++] = 0x02; + p[po++] = 0x0c; + p[po++] = 0x0f; + + /* CISTPL_CONFIG */ + p[po++] = 0x1a; + p[po++] = 0x05; + p[po++] = 0x01; + p[po++] = 0x01; + p[po++] = 0x00; + p[po++] = 0x02; + p[po++] = 0x0f; + + /* CISTPL_CFTABLEENTRY */ + p[po++] = 0x1b; + p[po++] = 0x06; + p[po++] = 0xc0; + p[po++] = 0x01; + p[po++] = 0x21; + p[po++] = 0xb5; + p[po++] = 0x1e; + p[po++] = 0x4d; + + /* CISTPL_NO_LINK */ + p[po++] = 0x14; + p[po++] = 0x00; + + /* CISTPL_END */ + p[po] = 0xff; + } + + function initsramattr(size, readonly) { + var p = pcmcia_attrs; + var po = 0; //OWN + var hfd = pcmcia_sram.hfd; + var real = false; //hfd.flags & HFD_FLAGS_REALDRIVE; + + var code = 0; + var su = 512; + var sm = 16384; + while (size > sm) { + sm *= 4; + su *= 4; + code++; + } + var units = 31 - Math.floor((sm - size) / su); + + /* CISTPL_DEVICE */ + p[po++] = 0x01; + p[po++] = 3; + p[po++] = (6 /* DTYPE_SRAM */ << 4) | (readonly ? 8 : 0) | (4 /* SPEED_100NS */); + p[po++] = (units << 3) | code; /* memory card size in weird units */ + p[po++] = 0xff; + + /* CISTPL_DEVICEGEO */ + p[po++] = 0x1e; + p[po++] = 7; + p[po++] = 2; /* 16-bit PCMCIA */ + p[po++] = 0; + p[po++] = 1; + p[po++] = 1; + p[po++] = 1; + p[po++] = 1; + p[po++] = 0xff; + + /* CISTPL_VERS_1 */ + p[po++]= 0x15; + var rp = po++; + p[po++]= 4; /* PCMCIA 2.1 */ + p[po++]= 1; + if (real) { + po += setCSTR(p, po, hfd.product_id); + po += setCSTR(p, po, hfd.product_rev); + } else { + po += setCSTR(p, po, "UAE"); + po += setCSTR(p, po, "68000"); + } + po += setCSTR(p, po, sprintf("Generic Emulated %dKB PCMCIA SRAM Card", size >> 10)); + p[po++]= 0xff; + p[rp] = po - rp - 1; + + /* CISTPL_FUNCID */ + p[po++] = 0x21; + p[po++] = 2; + p[po++] = 1; /* Memory Card */ + p[po++] = 0; + + /* CISTPL_MANFID */ + p[po++] = 0x20; + p[po++] = 4; + p[po++] = 0xff; + p[po++] = 0xff; + p[po++] = 1; + p[po++] = 1; + + /* CISTPL_END */ + p[po++] = 0xff; + } + + function initpcmcia(path, data, readonly, type, reset, uci) { + if (!SAEV_config.chipset.pcmcia) + return 0; + freepcmcia(reset); + if (pcmcia_sram === null) + pcmcia_sram = new SAEO_Hardfile_Data_HD(); + if (!pcmcia_sram.hfd.handle_valid) + reset = true; + + //pcmcia_sram.hfd.ci.rootdir = path; + pcmcia_sram.hfd.ci.file.name = path; //OWN + pcmcia_sram.hfd.ci.file.size = data.length; + pcmcia_sram.hfd.ci.file.data = data; + pcmcia_sram.hfd.ci.readonly = readonly; + pcmcia_sram.hfd.ci.blocksize = 512; + + if (type == PCMCIA_SRAM) { + if (reset) { + if (path.length) + SAER.hardfile.hdf_hd_open(pcmcia_sram); + } else + pcmcia_sram.hfd.drive_empty = false; + + if (pcmcia_sram.hfd.ci.readonly) + readonly = true; + pcmcia_common_size = 0; + pcmcia_readonly = readonly; + pcmcia_attrs_size = 256; + pcmcia_attrs = new Uint8Array(pcmcia_attrs_size); + pcmcia_type = type; + + if (!pcmcia_sram.hfd.drive_empty) { + pcmcia_common_size = pcmcia_sram.hfd.virtsize; + if (pcmcia_sram.hfd.virtsize > 4 * 1024 * 1024) { + SAEF_warn("gayle.initpcmcia() PCMCIA SRAM: too large device (%d bytes)", pcmcia_sram.hfd.virtsize); + pcmcia_common_size = 4 * 1024 * 1024; + } + pcmcia_common = new Uint8Array(pcmcia_common_size); + SAEF_log("gayle.initpcmcia() PCMCIA SRAM: '%s' open, size %d", path, pcmcia_common_size); + SAER.hardfile.hdf_read(pcmcia_sram.hfd, pcmcia_common, 0, pcmcia_common_size); + pcmcia_card = 1; + initsramattr(pcmcia_common_size, readonly); + if (!(gayle_cs & GAYLE_CS_DIS)) { + SAER.gayle.map_pcmcia(); + card_trigger(1); + } + } + } else if (type == PCMCIA_IDE) { + if (reset && path.length) + SAER.ide.add_ide_unit(idedrive, TOTAL_IDE * 2, PCMCIA_IDE_ID * 2, uci, null); + + SAER.ide.ide_initialize(idedrive, PCMCIA_IDE_ID); + + pcmcia_common_size = 0; + pcmcia_readonly = uci.readonly; + pcmcia_attrs_size = 0x40000; + pcmcia_attrs = new Uint8Array(pcmcia_attrs_size); + pcmcia_type = type; + + SAEF_log("gayle.initpcmcia() PCMCIA IDE: '%s' open", path); + pcmcia_card = 1; + initscideattr(pcmcia_readonly); + if (!(gayle_cs & GAYLE_CS_DIS)) { + SAER.gayle.map_pcmcia(); + card_trigger(1); + } + } + pcmcia_write_min = -1; + pcmcia_write_max = -1; + return 1; + } + + function freepcmcia(reset) { + SAEF_log("gayle.freepcmcia() reset %d", reset?1:0); + if (pcmcia_sram !== null) { + checkflush(-1); + if (reset) { + SAER.hardfile.hdf_hd_close(pcmcia_sram); + //xfree(pcmcia_sram); + pcmcia_sram = null; + } else + pcmcia_sram.hfd.drive_empty = true; + } + SAER.ide.remove_ide_unit(idedrive, PCMCIA_IDE_ID * 2); + if (pcmcia_card) + gayle_cs_change(GAYLE_CS_CCDET, 0); + + pcmcia_reset(); + pcmcia_card = 0; + + //xfree(pcmcia_common); + //xfree(pcmcia_attrs); + pcmcia_common = null; + pcmcia_attrs = null; + pcmcia_common_size = 0; + pcmcia_attrs_size = 0; + + gayle_cfg = 0; + gayle_cs = 0; + return 1; + } + + /*---------------------------------*/ + + this.map_pcmcia = function() { //gayle_map_pcmcia() + if (!SAEV_config.chipset.pcmcia) + return; + if (pcmcia_card == 0 || (gayle_cs & GAYLE_CS_DIS)) { + SAER.memory.map_banks_cond(SAEV_Memory_dummyBank, 0xa0, 8, 0); + if (SAEV_config.memory.chipSize <= 4 * 1024 * 1024 && SAER.memory.getz2endaddr() <= 4 * 1024 * 1024) + SAER.memory.map_banks_cond(SAEV_Memory_dummyBank, PCMCIA_COMMON_START >> 16, PCMCIA_COMMON_SIZE >> 16, 0); + } else { + SAER.memory.map_banks_cond(gayle_attr_bank, 0xa0, 8, 0); + if (SAEV_config.memory.chipSize <= 4 * 1024 * 1024 && SAER.memory.getz2endaddr() <= 4 * 1024 * 1024) + SAER.memory.map_banks_cond(gayle_common_bank, PCMCIA_COMMON_START >> 16, PCMCIA_COMMON_SIZE >> 16, 0); + } + } + + this.free_units = function() { //gayle_free_units() + for (var i = 0; i < TOTAL_IDE * 2; i++) { + SAER.ide.remove_ide_unit(idedrive, i); + } + freepcmcia(true); + } + + /*---------------------------------*/ + + /*#if 0 + #include "zfile.h" + static void dumphdf (struct hardfiledata *hfd) { + int i; + uae_u8 buf[512]; + int off; + struct zfile *zf; + + zf = zfile_fopen("c:\\d\\tmp.dmp", "wb"); + off = 0; + for (i = 0; i < 128; i++) { + SAER.hardfile.hdf_read(hfd, buf, off, 512); + zfile_fwrite(buf, 1, 512, zf); + off += 512; + } + zfile_fclose(zf); + } + #endif*/ + + /*---------------------------------*/ + + this.gayle_add_ide_unit = function(ch, ci) { + if (ch >= 2 * 2) + return -1; + var ide = SAER.ide.add_ide_unit(idedrive, TOTAL_IDE * 2, ch, ci, null); + if (ide === null) + return 0; + //dumphdf(ide.hdhfd.hfd); + return 1; + } + + this.gayle_add_pcmcia_sram_unit = function(uci) { + return initpcmcia(uci.file.name, uci.file.data, uci.readonly, PCMCIA_SRAM, true, null); + } + this.gayle_add_pcmcia_ide_unit = function(uci) { + return initpcmcia(uci.file.name, uci.file.data, false, PCMCIA_IDE, true, uci); + } + + this.gayle_modify_pcmcia_sram_unit = function(uci, insert) { + if (insert) + return initpcmcia(uci.file.name, uci.file.data, uci.readonly, PCMCIA_SRAM, pcmcia_sram === null, null); + else + return freepcmcia(false); + } + this.gayle_modify_pcmcia_ide_unit = function(uci, insert) { + if (insert) + return initpcmcia(uci.file.name, uci.file.data, false, PCMCIA_IDE, pcmcia_sram === null, uci); + else + return freepcmcia(false); + } + + function initide() { + //gayle_its.idetable = idedrive; + //gayle_its.idetotal = TOTAL_IDE * 2; + //SAER.ide.start_ide_thread(gayle_its); + SAER.ide.alloc_ide_mem(idedrive, TOTAL_IDE * 2, gayle_its); + SAER.ide.ide_initialize(idedrive, GAYLE_IDE_ID); + SAER.ide.ide_initialize(idedrive, GAYLE_IDE_ID + 1); + + ide_splitter = 0; + if (SAER.ide.ide_isdrive(idedrive[2]) || SAER.ide.ide_isdrive(idedrive[3])) { + ide_splitter = 1; + SAEF_log("gayle.initide() IDE splitter enabled"); + } + gayle_irq = gayle_int = 0; + } + + this.cleanup = function() { //gayle_free() + //SAER.ide.stop_ide_thread(gayle_its); + } + + /*---------------------------------*/ + + this.reset = function(hardreset) { //gayle_reset() + initide(); + if (hardreset) { + ramsey_config = 0; + gary_coldboot = 1; + SAEV_MBRes_gary_timeout = 0; + SAEV_MBRes_gary_toenb = 0; + } + var bankname = "Gayle (low)"; + if (SAEV_config.chipset.ide == SAEC_Config_Chipset_IDE_A4000) + bankname = "A4000 IDE"; + /*#ifdef NCR + if (SAEV_config.chipset.mbdmac == 2) { + bankname += " + NCR53C710 SCSI"; + ncr_init(); + ncr_reset(); + } + #endif*/ + SAEV_Gayle_bank.name = bankname; + this.gayle_dataflyer_enable(false); + } +} diff --git a/sae/hardfile.js b/sae/hardfile.js new file mode 100644 index 0000000..b500e91 --- /dev/null +++ b/sae/hardfile.js @@ -0,0 +1,1339 @@ +/*------------------------------------------------------------------------- +| SAE - Scripted Amiga Emulator +| https://github.com/naTmeg/ScriptedAmigaEmulator +| +| Copyright (C) 2012-2016 Rupert Hausberger +| +| This program is free software; you can redistribute it and/or +| modify it under the terms of the GNU General Public License +| as published by the Free Software Foundation; either version 2 +| of the License, or (at your option) any later version. +| +| This program is distributed in the hope that it will be useful, +| but WITHOUT ANY WARRANTY; without even the implied warranty of +| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +| GNU General Public License for more details. +| +| Note: ported from WinUAE 3.2.x +-------------------------------------------------------------------------*/ + +function SAEO_Hardfile_Data() { //hardfiledata + this.virtsize = 0; //u64, virtual size + this.physsize = 0; //u64, physical size (dynamic disk) + this.offset = 0; //u64 + this.ci = new SAEO_Config_Mount_Info(); + this.handle = null; //struct hardfilehandle * + this.handle_valid = 0; + //this.dangerous = 0; + //this.flags = 0; + this.cache = null; //u8 * + this.cache_valid = 0; + this.cache_offset = 0; //u64 + this.vendor_id = ""; //[8 + 1] + this.product_id = ""; //[16 + 1] + this.product_rev = ""; //[4 + 1] + + // geometry from possible RDSK block + //int rdbcylinders; + //int rdbsectors; + //int rdbheads; + this.virtual_rdb = null; + this.virtual_size = 0; //u64 + + //int unitnum; //FS + this.byteswap = false; + this.adide = false; + this.hfd_type = 0; + + //virtual hard disk + this.vhd_header = null; + this.vhd_bamoffset = 0; //u32 + this.vhd_bamsize = 0; //u32 + this.vhd_blocksize = 0; //u32 + this.vhd_sectormap = null; + this.vhd_sectormapblock = 0; //u64 + this.vhd_bitmapsize = 0; //u32 + this.vhd_footerblock = 0; //u64 + + //void *chd_handle; + + this.drive_empty = false; + //TCHAR *emptyname; +}; + +function SAEO_Hardfile_Data_HD() { //hd_hardfiledata + this.hfd = new SAEO_Hardfile_Data(); + this.size = 0; //u64 + this.cyls = 0; + this.heads = 0; + this.secspertrack = 0; + this.cyls_def = 0; + this.secspertrack_def = 0; + this.heads_def = 0; + this.ansi_version = 0; +}; + +/*---------------------------------*/ + +function SAEO_Hardfile() { + const HFD_VHD_FIXED = 2; + const HFD_VHD_DYNAMIC = 3; + + //const WITH_CHD = 1; + //const HFD_CHD_HD = 4; + //const HFD_CHD_OTHER = 5; + + /*---------------------------------*/ + + function getchsgeometry(size, ptr, mode) { //int *pcyl, int *phead, int *psectorspertrack, int mode) { + var spt, head, cyl; + var total = Math.floor(size / 512); + + if (typeof mode == "undefined") mode = 0; + + if (mode == 1) { + // old-style head=1, spt=32 always mode + head = 1; + spt = 32; + cyl = Math.floor(total / (head * spt)); + } else { + var sptt = new Array(4); + sptt[0] = 63; + sptt[1] = 127; + sptt[2] = 255; + sptt[3] = -1; + + for (var i = 0; sptt[i] >= 0; i++) { + var maxhead = sptt[i] < 255 ? 16 : 255; + spt = sptt[i]; + for (head = 4; head <= maxhead; head++) { + cyl = Math.floor(total / (head * spt)); + if (size <= 512 * 1024 * 1024) { + if (cyl <= 1023) + break; + } else { + if (cyl < 16383) + break; + if (cyl < 32767 && head >= 5) + break; + if (cyl <= 65535) + break; + } + if (maxhead > 16) { + head *= 2; + head--; + } + } + if (head <= 16) + break; + } + } + if (head > 16) + head--; + + ptr.cyl = cyl; + ptr.head = head; + ptr.sectorspertrack = spt; + } + + /*void getchsgeometry_hdf(struct hardfiledata *hfd, uae_u64 size, int *pcyl, int *phead, int *psectorspertrack) { + uae_u8 block[512]; + int i; + uae_u64 minsize = 512 * 1024 * 1024; + + if (size <= minsize) { + *phead = 1; + *psectorspertrack = 32; + } + memset (block, 0, sizeof block); + if (hfd) { + hdf_read(hfd, block, 0, 512); + if (block[0] == 'D' && block[1] == 'O' && block[2] == 'S') { + int mode; + for (mode = 0; mode < 2; mode++) { + uae_u32 rootblock; + uae_u32 chk = 0; + getchsgeometry(size, pcyl, phead, psectorspertrack, mode); + rootblock = (2 + ((*pcyl) * (*phead) * (*psectorspertrack) - 1)) / 2; + memset (block, 0, sizeof block); + hdf_read(hfd, block, (uae_u64)rootblock * 512, 512); + for (i = 0; i < 512; i += 4) + chk += (block[i] << 24) | (block[i + 1] << 16) | (block[i + 2] << 8) | (block[i + 3] << 0); + if (!chk && block[0] == 0 && block[1] == 0 && block[2] == 0 && block[3] == 2 && + block[4] == 0 && block[5] == 0 && block[6] == 0 && block[7] == 0 && + block[8] == 0 && block[9] == 0 && block[10] == 0 && block[11] == 0 && + block[508] == 0 && block[509] == 0 && block[510] == 0 && block[511] == 1) { + return; + } + } + } + } + getchsgeometry(size, pcyl, phead, psectorspertrack, size <= minsize ? 1 : 2); + }*/ + + function getchspgeometry(total, ptr, idegeometry) { //, int *pcyl, int *phead, int *psectorspertrack, bool idegeometry) + blocks = Math.floor(total / 512); + + if (blocks > 16515072) { + /* >8G, CHS=16383/16/63 */ + ptr.cyl = 16383; + ptr.head = 16; + ptr.sectorspertrack = 63; + return; + } + if (idegeometry) { + ptr.head = 16; + ptr.sectorspertrack = 63; + ptr.cyl = Math.floor(blocks / (ptr.sectorspertrack * ptr.head)); + return; + } + //getchsgeometry(total, pcyl, phead, psectorspertrack); + getchsgeometry(total, ptr); + } + function getchshd(hfd, ptr) { //int *pcyl, int *phead, int *psectorspertrack) { + //getchspgeometry(hfd.virtsize, pcyl, phead, psectorspertrack, false); + getchspgeometry(hfd.virtsize, ptr, false); + } + + /*---------------------------------*/ + + function gl(p, po) { //OPT + return ((p[po] << 24) | (p[po+1] << 16) | (p[po+2] << 8) | p[po+3]) >>> 0; + } + + /*-----------------------------------------------------------------------*/ + + function rl(p, po) { + po <<= 2; + return ((p[po] << 24) | (p[po+1] << 16) | (p[po+2] << 8) | p[po+3]) >>> 0; + } + function pl(p, po, v) { + po <<= 2; + p[po ] = v >>> 24; + p[po+1] = (v >>> 16) & 0xff; + p[po+2] = (v >>> 8) & 0xff; + p[po+3] = v & 0xff; + } + function ps(p, po, max, src) { //OWN + const space = ' '.charCodeAt(0); + var len = src.length; + po <<= 2; + p[po++] = Math.min(len, max); + for (var i = 0; i < max; i++) + p[po++] = i < len ? src.charCodeAt(i) : space; + } + function rdb_crc(p,po) { + var sum = 0; //u32 + var blocksize = rl(p, po + 1); + for (var i = 0; i < blocksize; i++) { + sum += rl(p, po + i); + if (sum > 0xffffffff) sum -= 0x100000000; + } + sum = -sum; if (sum < 0) sum += 0x100000000; + pl(p, po + 2, sum); + } + function create_virtual_rdb(hfd) { + var cyl = hfd.ci.surfaces * hfd.ci.sectors; + var cyls = 262144 / (cyl * 512); + var size = cyl * cyls * 512; + + SAEF_log("hardfile.create_virtual_rdb() cyl %d, cyls %d, size %d", cyl, cyls, size); + + var rdb = new Uint8Array(size); + SAEF_memset(rdb,0, 0, size); //OWN + hfd.virtual_rdb = rdb; + hfd.virtual_size = size; + + pl(rdb, 0, 0x5244534b); + pl(rdb, 1, 64); + pl(rdb, 2, 0); // chksum + pl(rdb, 3, 7); // hostid + pl(rdb, 4, 512); // blockbytes + pl(rdb, 5, 0); // flags + pl(rdb, 6, -1); // badblock + pl(rdb, 7, 1); // part + pl(rdb, 8, -1); // fs + pl(rdb, 9, -1); // driveinit + pl(rdb, 10, -1); // reserved + pl(rdb, 11, -1); // reserved + pl(rdb, 12, -1); // reserved + pl(rdb, 13, -1); // reserved + pl(rdb, 14, -1); // reserved + pl(rdb, 15, -1); // reserved + pl(rdb, 16, hfd.ci.highcyl); + pl(rdb, 17, hfd.ci.sectors); + pl(rdb, 18, hfd.ci.surfaces); + pl(rdb, 19, hfd.ci.interleave ? 1 : 0); // interleave + pl(rdb, 20, 0); // park + pl(rdb, 21, -1); // res + pl(rdb, 22, -1); // res + pl(rdb, 23, -1); // res + pl(rdb, 24, 0); // writeprecomp + pl(rdb, 25, 0); // reducedwrite + pl(rdb, 26, 0); // steprate + pl(rdb, 27, -1); // res + pl(rdb, 28, -1); // res + pl(rdb, 29, -1); // res + pl(rdb, 30, -1); // res + pl(rdb, 31, -1); // res + pl(rdb, 32, 0); // rdbblockslo + pl(rdb, 33, cyl * cyls); // rdbblockshi + pl(rdb, 34, cyls); // locyl + pl(rdb, 35, hfd.ci.highcyl + cyls); // hicyl + pl(rdb, 36, cyl); // cylblocks + pl(rdb, 37, 0); // autopark + pl(rdb, 38, 2); // highrdskblock + pl(rdb, 39, -1); // res + ps(rdb, 40, 8, hfd.vendor_id); + ps(rdb, 42, 16, hfd.product_id); + ps(rdb, 46, 4, hfd.product_rev); + rdb_crc(rdb, 0); + + //var part = rdb + 512; + var part = 512 >> 2; + pl(rdb, part+0, 0x50415254); + pl(rdb, part+1, 64); + pl(rdb, part+2, 0); + pl(rdb, part+3, 0); + pl(rdb, part+4, -1); + pl(rdb, part+5, 1); // 1 = bootable, 3 = bootable + noautomount + pl(rdb, part+6, -1); + pl(rdb, part+7, -1); + pl(rdb, part+8, 0); // devflags + ps(rdb, part+9, 30, hfd.ci.devname); + + //denv = part + 128; + var denv = part + (128 >> 2); + pl(rdb, denv+0, 80); + pl(rdb, denv+1, 512 >> 2); + pl(rdb, denv+2, 0); // secorg + pl(rdb, denv+3, hfd.ci.surfaces); + pl(rdb, denv+4, hfd.ci.blocksize >> 9); // / 512); + pl(rdb, denv+5, hfd.ci.sectors); + pl(rdb, denv+6, hfd.ci.reserved); + pl(rdb, denv+7, 0); // prealloc + pl(rdb, denv+8, hfd.ci.interleave ? 1 : 0); // interleave + pl(rdb, denv+9, cyls); // lowcyl + pl(rdb, denv+10, hfd.ci.highcyl + cyls - 1); + pl(rdb, denv+11, hfd.ci.buffers); + pl(rdb, denv+12, hfd.ci.bufmemtype); + pl(rdb, denv+13, hfd.ci.maxtransfer); + pl(rdb, denv+14, hfd.ci.mask); + pl(rdb, denv+15, hfd.ci.bootpri); + pl(rdb, denv+16, hfd.ci.dostype); + rdb_crc(rdb, part); + + hfd.virtsize += size; + } + + /*-----------------------------------------------------------------------*/ + + this.hdf_hd_open = function(hfd) { + if (hdf_open(hfd.hfd) <= 0) + return 0; + var ci = hfd.hfd.ci; + if (ci.physical_geometry) { + hfd.cyls = ci.pcyls; + hfd.heads = ci.pheads; + hfd.secspertrack = ci.psecs; + } else if (ci.highcyl && ci.surfaces && ci.sectors) { + hfd.cyls = ci.highcyl; + hfd.heads = ci.surfaces; + hfd.secspertrack = ci.sectors; + } else { + var ptr = {}; + getchshd(hfd.hfd, ptr); //&hfd.cyls, &hfd.heads, &hfd.secspertrack); + hfd.cyls = ptr.cyl; + hfd.heads = ptr.head; + hfd.secspertrack = ptr.sectorspertrack; + } + hfd.cyls_def = hfd.cyls; + hfd.secspertrack_def = hfd.secspertrack; + hfd.heads_def = hfd.heads; + + if (ci.surfaces && ci.sectors) { + var buf = new Uint8Array(512); buf[0] = 0; + this.hdf_read(hfd.hfd, buf, 0, 512); + if (buf[0] != 0 && SAEF_CompareArray(buf, SAEF_String2Array("RDSK"), 4) != 0) { + ci.highcyl = Math.floor(Math.floor(hfd.hfd.virtsize / ci.blocksize) / (ci.sectors * ci.surfaces)); + ci.dostype = rl(buf,0); + SAEF_warn("hardfile.hdf_hd_open() no RDSK, dostype 0x%08x, highcyl %d", ci.dostype, ci.highcyl); + create_virtual_rdb(hfd.hfd); + while (ci.highcyl * ci.surfaces * ci.sectors > hfd.cyls_def * hfd.secspertrack_def * hfd.heads_def) + hfd.cyls_def++; + } + } + hfd.size = hfd.hfd.virtsize; + return 1; + } + + this.hdf_hd_close = function(hfd) { + if (hfd !== null) + hdf_close(hfd.hfd); + } + + /*-----------------------------------------------------------------------*/ + + //function hdf_open(hfd, pname) { + function hdf_open(hfd, file) { + if (typeof file == "undefined") file = null; + + //if ((!pname || pname[0] == 0) && hfd.ci.rootdir[0] == 0) + //if (!pname) pname = hfd.ci.rootdir; + + if (file === null) { //OWN + if (hfd.ci.file.size == 0) + return 0; + + file = hfd.ci.file.clone(); + } + hfd.byteswap = false; + hfd.adide = false; + hfd.hfd_type = 0; + + /*#ifdef WITH_CHD + TCHAR nametmp[MAX_DPATH]; + _tcscpy (nametmp, pname); + TCHAR *ext = _tcsrchr (nametmp, '.'); + if (ext && !_tcsicmp (ext, _T(".chd"))) { + bool chd_readonly = false; + struct zfile *zf = null; + if (!hfd.ci.readonly) + zf = SAEF_ZFile_fopen(nametmp, "rb+"); + if (!zf) { + chd_readonly = true; + zf = SAEF_ZFile_fopen(nametmp, "rb"); + } + if (zf) { + int err = CHDERR_FILE_NOT_WRITEABLE; + hard_disk_file *chdf; + chd_file *cf = new chd_file(); + if (!chd_readonly) + err = cf.open(*zf, true, null); + if (err == CHDERR_FILE_NOT_WRITEABLE) { + chd_readonly = true; + err = cf.open(*zf, false, null); + } + if (err != CHDERR_NONE) { + SAEF_ZFile_fclose(zf); + delete cf; + goto end; + } + chdf = hard_disk_open(cf); + if (!chdf) { + hfd.ci.readonly = true; + hfd.hfd_type = HFD_CHD_OTHER; + hfd.chd_handle = cf; + } else { + hfd.hfd_type = HFD_CHD_HD; + hfd.chd_handle = chdf; + } + if (chd_readonly) + hfd.ci.readonly = true; + hfd.virtsize = cf.logical_bytes(); + hfd.handle_valid = -1; + write_log(_T("CHD '%s' mounted as %s, %s.\n"), pname, chdf ? _T("HD") : _T("OTHER"), hfd.ci.readonly ? _T("read only") : _T("read/write")); + return 1; + } + } + #endif*/ + var ret = hdf_open_target(hfd, file); + if (ret <= 0) + return ret; + var tmp = new Uint8Array(512); + if (hdf_read_target(hfd, tmp,0, 0, 512) != 512) { + //goto nonvhd; + SAEF_log("hardfile.hdf_open() no VHD-image, file samller than 512 bytes"); + hfd.hfd_type = 0; + return 1; + } + var v = gl(tmp, 8); // features + if ((v & 3) != 2) { + SAEF_log("hardfile.hdf_open() no VHD-image, wrong file features %d != 2", v & 3); + //goto nonvhd; + hfd.hfd_type = 0; + return 1; + } + v = gl(tmp, 8 + 4); // version + if ((v >>> 16) != 1) { + SAEF_log("hardfile.hdf_open() no VHD-image, wrong file version %d != 1", v >>> 16); + //goto nonvhd; + hfd.hfd_type = 0; + return 1; + } + hfd.hfd_type = gl(tmp, 8 + 4 + 4 + 8 + 4 + 4 + 4 + 4 + 8 + 8 + 4); + if (hfd.hfd_type != HFD_VHD_FIXED && hfd.hfd_type != HFD_VHD_DYNAMIC) { + SAEF_log("hardfile.hdf_open() no VHD-image, wrong file type %d", hfd.hfd_type); + //goto nonvhd; + hfd.hfd_type = 0; + return 1; + } + v = gl(tmp, 8 + 4 + 4 + 8 + 4 + 4 + 4 + 4 + 8 + 8 + 4 + 4); + if (v == 0) { + SAEF_log("hardfile.hdf_open() no VHD-image, error 1"); + //goto nonvhd; + hfd.hfd_type = 0; + return 1; + } + var cs = vhd_checksum(tmp, 8 + 4 + 4 + 8 + 4 + 4 + 4 + 4 + 8 + 8 + 4 + 4); + if (cs != v) { + SAEF_log("hardfile.hdf_open() no VHD-image, wrong file checksum 0x%08x != 0x%08x", cs, v); + //goto nonvhd; + hfd.hfd_type = 0; + return 1; + } + var tmp2 = new Uint8Array(512); + if (hdf_read_target(hfd, tmp2,0, hfd.physsize - tmp2.length, 512) != 512) { + SAEF_warn("hardfile.hdf_open() file read error"); + hdf_close_target(hfd); return 0; + //goto end; + } + if (SAEF_CompareArray(tmp, tmp2) != 0) { + SAEF_log("hardfile.hdf_open() no VHD-image, error 2"); + //goto nonvhd; + hfd.hfd_type = 0; + return 1; + } + hfd.vhd_footerblock = hfd.physsize - 512; + //hfd.virtsize = gl(tmp, 8 + 4 + 4 + 8 + 4 + 4 + 4 + 4 + 8) << 32; //ATT + //hfd.virtsize |= gl(tmp, 8 + 4 + 4 + 8 + 4 + 4 + 4 + 4 + 8 + 4); + hfd.virtsize = gl(tmp, 8 + 4 + 4 + 8 + 4 + 4 + 4 + 4 + 8) * 0x100000000; + hfd.virtsize += gl(tmp, 8 + 4 + 4 + 8 + 4 + 4 + 4 + 4 + 8 + 4); + + if (hfd.hfd_type == HFD_VHD_DYNAMIC) { + var fail = true; + hfd.vhd_bamoffset = gl(tmp, 8 + 4 + 4 + 4); + if (hfd.vhd_bamoffset > 0 && hfd.vhd_bamoffset < hfd.physsize) { + if (hdf_read_target(hfd, tmp,0, hfd.vhd_bamoffset, 512) == 512) { + v = gl(tmp, 8 + 8 + 8 + 4 + 4 + 4); + if (vhd_checksum(tmp, 8 + 8 + 8 + 4 + 4 + 4) == v) { + v = gl(tmp, 8 + 8 + 8); + if ((v >>> 16) == 1) { //version + hfd.vhd_blocksize = gl(tmp, 8 + 8 + 8 + 4 + 4); + hfd.vhd_bamoffset = gl(tmp, 8 + 8 + 4); + hfd.vhd_bamsize = (Math.floor((hfd.virtsize + hfd.vhd_blocksize - 1) / hfd.vhd_blocksize) * 4 + 511) & ~511; + var size = hfd.vhd_bamoffset + hfd.vhd_bamsize; + hfd.vhd_header = new Uint8Array(size); + if (hdf_read_target(hfd, hfd.vhd_header,0, 0, size) == size) { + hfd.vhd_sectormap = new Uint8Array(512); + hfd.vhd_sectormapblock = -1; + hfd.vhd_bitmapsize = (Math.floor(hfd.vhd_blocksize / (8 * 512)) + 511) & ~511; + fail = false; + } + } + } + } + } + if (fail) { + hdf_close_target(hfd); + return 0; + } + } + SAEF_log("hardfile.hdf_open() HDF is VHD %s image, virtual size=%dK (%x %d)", hfd.hfd_type == HFD_VHD_FIXED ? "fixed" : "dynamic", Math.floor(hfd.virtsize / 1024), hfd.virtsize, hfd.virtsize); + hdf_init_cache(hfd); + return 1; + /*nonvhd: + hfd.hfd_type = 0; + return 1; + end: + hdf_close_target (hfd); + return 0;*/ + } + + function hdf_close(hfd) { + hdf_flush_cache(hfd); + hdf_close_target(hfd); + /* + #ifdef WITH_CHD + if (hfd.hfd_type == HFD_CHD_OTHER) { + chd_file *cf = (chd_file*)hfd.chd_handle; + cf.close(); + delete cf; + } else if (hfd.hfd_type == HFD_CHD_HD) { + hard_disk_file *chdf = (hard_disk_file*)hfd.chd_handle; + chd_file *cf = hard_disk_get_chd(chdf); + hard_disk_close(chdf); + cf.close(); + delete cf; + } + hfd.chd_handle = null; + #endif*/ + hfd.hfd_type = 0; + //xfree(hfd.vhd_header); + hfd.vhd_header = null; + //xfree(hfd.vhd_sectormap); + hfd.vhd_sectormap = null; + } + + /*int hdf_dup(struct hardfiledata *dhfd, const struct hardfiledata *shfd) { + return hdf_dup_target(dhfd, shfd); + }*/ + + /*-----------------------------------------------------------------------*/ + + function vhd_checksum(p, offset) { + var sum = 0; //u32 + for (var i = 0; i < 512; i++) { + if (offset >= 0 && i >= offset && i < offset + 4) + continue; + sum += p[i]; + if (sum > 0xffffffff) sum -= 0x100000000; + } + return ~sum >>> 0; + } + + function vhd_read(hfd, data, offset, len) { + //uae_u8 *dataptr = (uae_u8*)data; + var dataptr = 0; + + //SAEF_log("hardfile.vhd_read() %08x %08x", offset, len); + //SAEF_log("hardfile.vhd_read() %d %d", offset, len); + + var read = 0; //u64 + if (offset & 511) + return read; + if (len & 511) + return read; + while (len > 0) { + var bamoffset = Math.floor(offset / hfd.vhd_blocksize) * 4 + hfd.vhd_bamoffset; //u32 + var sectoroffset = gl(hfd.vhd_header, bamoffset); //u32 + if (sectoroffset == 0xffffffff) { + //memset(dataptr, 0, 512); + SAEF_memset(data,dataptr, 0, 512); + read += 512; + } else { + var bitmapoffsetbits = Math.floor(offset / 512) % (hfd.vhd_blocksize >> 9); //int + var bitmapoffsetbytes = Math.floor(bitmapoffsetbits / 8); //int + var sectormapblock = sectoroffset * 512 + (bitmapoffsetbytes & ~511); //u64 + if (hfd.vhd_sectormapblock != sectormapblock) { + // read sector bitmap + //SAEF_log("hardfile.vhd_read() BM %08x", sectormapblock); + if (hdf_read_target(hfd, hfd.vhd_sectormap,0, sectormapblock, 512) != 512) { + SAEF_warn("hardfile.vhd_read() bitmap read error"); + return read; + } + hfd.vhd_sectormapblock = sectormapblock; + } + // block allocated in bitmap? + if (hfd.vhd_sectormap[bitmapoffsetbytes & 511] & (1 << (7 - (bitmapoffsetbits & 7)))) { + // read data block + var block = sectoroffset * 512 + hfd.vhd_bitmapsize + bitmapoffsetbits * 512; //u64 + //SAEF_log("hardfile.vhd_read() DB %08x", block); + if (hdf_read_target(hfd, data,dataptr, block, 512) != 512) { + SAEF_warn("hardfile.vhd_read() data read error"); + return read; + } + } else { + //memset(dataptr, 0, 512); + SAEF_memset(data,dataptr, 0, 512); + } + read += 512; + } + len -= 512; + dataptr += 512; + offset += 512; + } + return read; + } + + function vhd_write_enlarge(hfd, bamoffset) { + var len = hfd.vhd_blocksize + hfd.vhd_bitmapsize + 512; + if (!hdf_resize_target(hfd, hfd.physsize + len - 512)) { + SAEF_warn("hardfile.vhd_write_enlarge() failure"); + return false; + } + // add footer (same as 512 byte header) + var buf = new Uint8Array(len); + SAEF_memset(buf,0, 0, len - 512); //OWN + buf.set(hfd.vhd_header.subarray(0, 512), len - 512); //memcpy (buf + len - 512, hfd->vhd_header, 512); + var v = hdf_write_target(hfd, buf,0, hfd.vhd_footerblock, len); + delete buf; + if (v != len) { + SAEF_warn("hardfile.vhd_write_enlarge() footer write error"); + return false; + } + // write new offset to BAM + var block = Math.floor(hfd.vhd_footerblock / 512); + hfd.vhd_header[bamoffset + 0] = block >>> 24; + hfd.vhd_header[bamoffset + 1] = (block >>> 16) & 0xff; + hfd.vhd_header[bamoffset + 2] = (block >>> 8) & 0xff; + hfd.vhd_header[bamoffset + 3] = block & 0xff; + // write to disk + if (hdf_write_target(hfd, hfd.vhd_header,hfd.vhd_bamoffset, hfd.vhd_bamoffset, hfd.vhd_bamsize) != hfd.vhd_bamsize) { + SAEF_warn("hardfile.vhd_write_enlarge() bam write error"); + return false; + } + hfd.vhd_footerblock += len - 512; + return true; + } + function vhd_write(hfd, data, offset, len) { + //uae_u8 *dataptr = (uae_u8*)v; + var dataptr = 0; + + //SAEF_log("hardfile.vhd_read() %08x %08x", offset, len); + //SAEF_log("hardfile.vhd_write() %d %d", offset, len); + + var written = 0; //u64 + if (offset & 511) + return written; + if (len & 511) + return written; + while (len > 0) { + var bamoffset = Math.floor(offset / hfd.vhd_blocksize) * 4 + hfd.vhd_bamoffset; //u32 + var sectoroffset = gl(hfd.vhd_header, bamoffset); //u32 + if (sectoroffset == 0xffffffff) { + if (!vhd_write_enlarge(hfd, bamoffset)) + return written; + continue; + } else { + var bitmapoffsetbits = Math.floor(offset / 512) % (hfd.vhd_blocksize >> 9); //int + var bitmapoffsetbytes = Math.floor(bitmapoffsetbits / 8); //int + var sectormapblock = sectoroffset * 512 + (bitmapoffsetbytes & ~511); //u64 + if (hfd.vhd_sectormapblock != sectormapblock) { + // read sector bitmap + //SAEF_log("hardfile.vhd_write() BM %08x", sectormapblock); + if (hdf_read_target(hfd, hfd.vhd_sectormap,0, sectormapblock, 512) != 512) { + SAEF_warn("hardfile.vhd_write() bitmap read error"); + return written; + } + hfd.vhd_sectormapblock = sectormapblock; + } + // write data + var block = sectoroffset * 512 + hfd.vhd_bitmapsize + bitmapoffsetbits * 512; //u64 + //SAEF_log("hardfile.vhd_write() DB %08x", block); + if (hdf_write_target(hfd, data,dataptr, block, 512) != 512) { + SAEF_warn("hardfile.vhd_write() data write error"); + return written; + } + // block already allocated in bitmap? + if (!(hfd.vhd_sectormap[bitmapoffsetbytes & 511] & (1 << (7 - (bitmapoffsetbits & 7))))) { + // no, we need to mark it allocated and write the modified bitmap back to the disk + hfd.vhd_sectormap[bitmapoffsetbytes & 511] |= (1 << (7 - (bitmapoffsetbits & 7))); + if (hdf_write_target(hfd, hfd.vhd_sectormap,0, sectormapblock, 512) != 512) { + SAEF_warn("hardfile.vhd_write() bam write error"); + return written; + } + } + written += 512; + } + len -= 512; + dataptr += 512; + offset += 512; + } + return written; + } + + /*int vhd_create (const TCHAR *name, uae_u64 size, uae_u32 dostype) { + struct hardfiledata hfd; + struct zfile *zf; + uae_u8 *b; + int cyl, cylsec, head, tracksec; + uae_u32 crc, blocksize, batsize, batentrysize; + int ret, i; + time_t tm; + + if (size >= (uae_u64)10 * 1024 * 1024 * 1024) + blocksize = 2 * 1024 * 1024; + else + blocksize = 512 * 1024; + batsize = (size + blocksize - 1) / blocksize; + batentrysize = batsize; + batsize *= 4; + batsize += 511; + batsize &= ~511; + ret = 0; + b = NULL; + zf = SAEF_ZFile_fopen(name, "wb", 0); + if (!zf) + goto end; + b = xcalloc (uae_u8, 512 + 1024 + batsize + 512); + if (SAEF_ZFile_fwrite(b,0, 512 + 1024 + batsize + 512, 1, zf) != 1) + goto end; + + memset (&hfd, 0, sizeof hfd); + hfd.virtsize = hfd.physsize = size; + hfd.ci.blocksize = 512; + strcpy ((char*)b, "conectix"); // cookie + b[0x0b] = 2; // features + b[0x0d] = 1; // version + b[0x10 + 6] = 2; // data offset + // time stamp + tm = time (NULL) - 946684800; + b[0x18] = tm >> 24; + b[0x19] = tm >> 16; + b[0x1a] = tm >> 8; + b[0x1b] = tm >> 0; + strcpy ((char*)b + 0x1c, "vpc "); // creator application + b[0x21] = 5; // creator version + strcpy ((char*)b + 0x24, "Wi2k"); // creator host os + // original and current size + b[0x28] = b[0x30] = size >> 56; + b[0x29] = b[0x31] = size >> 48; + b[0x2a] = b[0x32] = size >> 40; + b[0x2b] = b[0x33] = size >> 32; + b[0x2c] = b[0x34] = size >> 24; + b[0x2d] = b[0x35] = size >> 16; + b[0x2e] = b[0x36] = size >> 8; + b[0x2f] = b[0x37] = size >> 0; + getchs2 (&hfd, &cyl, &cylsec, &head, &tracksec); + // cylinders + b[0x38] = cyl >> 8; + b[0x39] = cyl; + // heads + b[0x3a] = head; + // sectors per track + b[0x3b] = tracksec; + // disk type + b[0x3c + 3] = HFD_VHD_DYNAMIC; + get_guid_target (b + 0x44); + crc = vhd_checksum (b, -1); + b[0x40] = crc >> 24; + b[0x41] = crc >> 16; + b[0x42] = crc >> 8; + b[0x43] = crc >> 0; + + // write header + SAEF_ZFile_fseek(zf, 0, SEEK_SET); + SAEF_ZFile_fwrite(b,0, 512, 1, zf); + // write footer + SAEF_ZFile_fseek(zf, 512 + 1024 + batsize, SEEK_SET); + SAEF_ZFile_fwrite(b,0, 512, 1, zf); + + // dynamic disk header + memset (b, 0, 1024); + // cookie + strcpy ((char*)b, "cxsparse"); + // data offset + for (i = 0; i < 8; i++) + b[0x08 + i] = 0xff; + // table offset (bat) + b[0x10 + 6] = 0x06; + // version + b[0x19] = 1; + // max table entries + b[0x1c] = batentrysize >> 24; + b[0x1d] = batentrysize >> 16; + b[0x1e] = batentrysize >> 8; + b[0x1f] = batentrysize >> 0; + b[0x20] = blocksize >> 24; + b[0x21] = blocksize >> 16; + b[0x22] = blocksize >> 8; + b[0x23] = blocksize >> 0; + crc = vhd_checksum (b, -1); + b[0x24] = crc >> 24; + b[0x25] = crc >> 16; + b[0x26] = crc >> 8; + b[0x27] = crc >> 0; + + // write dynamic header + SAEF_ZFile_fseek(zf, 512, SEEK_SET); + SAEF_ZFile_fwrite(b,0, 1024, 1, zf); + + // bat + memset (b, 0, batsize); + memset (b, 0xff, batentrysize * 4); + SAEF_ZFile_fwrite(b,0, batsize, 1, zf); + + SAEF_ZFile_fclose(zf); + zf = NULL; + + if (dostype) { + uae_u8 bootblock[512] = { 0 }; + bootblock[0] = dostype >> 24; + bootblock[1] = dostype >> 16; + bootblock[2] = dostype >> 8; + bootblock[3] = dostype >> 0; + if (hdf_open(&hfd, file) > 0) { + vhd_write(&hfd, bootblock, 0, 512); + hdf_close(&hfd); + } + } + + ret = 1; + + end: + xfree (b); + SAEF_ZFile_fclose(zf); + return ret; + }*/ + + /*-----------------------------------------------------------------------*/ + + function hdf_read2(hfd, buffer, offset, len) { + if (hfd.hfd_type == HFD_VHD_DYNAMIC) + return vhd_read(hfd, buffer, offset, len); + else if (hfd.hfd_type == HFD_VHD_FIXED) + return hdf_read_target(hfd, buffer,0, offset + 512, len); + /* + #ifdef WITH_CHD + else if (hfd.hfd_type == HFD_CHD_OTHER) { + chd_file *cf = (chd_file*)hfd.chd_handle; + if (cf.read_bytes(offset, buffer, len) == CHDERR_NONE) + return len; + return 0; + } else if (hfd.hfd_type == HFD_CHD_HD) { + hard_disk_file *chdf = (hard_disk_file*)hfd.chd_handle; + hard_disk_info *chdi = hard_disk_get_info(chdf); + chd_file *cf = hard_disk_get_chd(chdf); + uae_u8 *buf = (uae_u8*)buffer; + int got = 0; + offset /= chdi.sectorbytes; + while (len > 0) { + if (cf.read_units(offset, buf) != CHDERR_NONE) + return got; + got += chdi.sectorbytes; + buf += chdi.sectorbytes; + len -= chdi.sectorbytes; + offset++; + } + return got; + } + #endif*/ + else + return hdf_read_target(hfd, buffer,0, offset, len); + } + + function hdf_write2(hfd, buffer, offset, len) { + if (hfd.hfd_type == HFD_VHD_DYNAMIC) + return vhd_write(hfd, buffer, offset, len); + else if (hfd.hfd_type == HFD_VHD_FIXED) + return hdf_write_target(hfd, buffer,0, offset + 512, len); + /* + #ifdef WITH_CHD + else if (hfd.hfd_type == HFD_CHD_OTHER) + return 0; + else if (hfd.hfd_type == HFD_CHD_HD) { + if (hfd.ci.readonly) + return 0; + hard_disk_file *chdf = (hard_disk_file*)hfd.chd_handle; + hard_disk_info *chdi = hard_disk_get_info(chdf); + chd_file *cf = hard_disk_get_chd(chdf); + uae_u8 *buf = (uae_u8*)buffer; + int got = 0; + offset /= chdi.sectorbytes; + while (len > 0) { + if (cf.write_units(offset, buf) != CHDERR_NONE) + return got; + got += chdi.sectorbytes; + buf += chdi.sectorbytes; + len -= chdi.sectorbytes; + offset++; + } + return got; + } + #endif*/ + else + return hdf_write_target(hfd, buffer,0, offset, len); + } + + function hdf_cache_read(hfd, buffer, offset, len) { + return hdf_read2(hfd, buffer, offset, len); + } + function hdf_cache_write(hfd, buffer, offset, len) { + return hdf_write2(hfd, buffer, offset, len); + } + function hdf_init_cache(hfd) {} + function hdf_flush_cache(hdf) {} + + /*-----------------------------------------------------------------------*/ + + function adide_decode(v, len) { + SAEF_warn("hardfile.adide_decode() 0x%04x %d", v, len); + /*int i; + uae_u8 *buffer = (uae_u8*)v; + for (i = 0; i < len; i += 2) { + uae_u8 *b = buffer + i; + uae_u16 w = (b[0] << 8) | (b[1] << 0); + uae_u16 o = SAER.ide.adide_decode_word(w); + b[0] = o >> 8; + b[1] = o >> 0; + }*/ + } + function adide_encode(v, len) { + SAEF_warn("hardfile.adide_encode() 0x%04x %d", v, len); + /*int i; + uae_u8 *buffer = (uae_u8*)v; + for (i = 0; i < len; i += 2) { + uae_u8 *b = buffer + i; + uae_u16 w = (b[0] << 8) | (b[1] << 0); + uae_u16 o = SAER.ide.adide_encode_word(w); + b[0] = o >> 8; + b[1] = o >> 0; + }*/ + } + function hdf_byteswap(v, len) { + SAEF_warn("hardfile.hdf_byteswap() 0x%04x %d", v, len); + /*int i; + uae_u8 *b = (uae_u8*)v; + for (i = 0; i < len; i += 2) { + uae_u8 tmp = b[i]; + b[i] = b[i + 1]; + b[i + 1] = tmp; + }*/ + } + + /*int hdf_read_rdb (struct hardfiledata *hfd, void *buffer, uae_u64 offset, int len) { + int v; + v = hdf_read (hfd, buffer, offset, len); + if (v > 0 && offset < 16 * 512 && !hfd.byteswap && !hfd.adide) { + uae_u8 *buf = (uae_u8*)buffer; + bool changed = false; + if (buf[0] == 0x39 && buf[1] == 0x10 && buf[2] == 0xd3 && buf[3] == 0x12) { // AdIDE encoded "CPRM" + hfd.adide = true; + changed = true; + write_log (_T("HDF: adide scrambling detected\n")); + } else if (!memcmp (buf, "DRKS", 4)) { + hfd.byteswap = true; + changed = true; + write_log (_T("HDF: byteswapped RDB detected\n")); + } + if (changed) + v = hdf_read (hfd, buffer, offset, len); + } + return v; + }*/ + + this.hdf_read = function(hfd, buffer, offset, len) { + var v; + + //SAEF_log("hardfile.hdf_read() %04x-%08x (%d) %08x (%d)", Math.floor(offset / 0x100000000), Math.floor(offset % 0x100000000), Math.floor(offset / hfd.ci.blocksize), len >>> 0, Math.floor(len / hfd.ci.blocksize)); + + if (!hfd.adide) { + v = hdf_cache_read(hfd, buffer, offset, len); + } else { + offset += 512; + v = hdf_cache_read(hfd, buffer, offset, len); + adide_decode(buffer, len); + } + if (hfd.byteswap) + hdf_byteswap(buffer, len); + return v; + } + + this.hdf_write = function(hfd, buffer, offset, len) { + var v; + + //SAEF_log("hardfile.hdf_write() %04x-%08x (%d) %08x (%d)", Math.floor(offset / 0x100000000), Math.floor(offset % 0x100000000), Math.floor(offset / hfd.ci.blocksize), len >>> 0, Math.floor(len / hfd.ci.blocksize)); + + if (hfd.byteswap) + hdf_byteswap(buffer, len); + if (!hfd.adide) + v = hdf_cache_write(hfd, buffer, offset, len); + else { + offset += 512; + adide_encode(buffer, len); + v = hdf_cache_write(hfd, buffer, offset, len); + adide_decode(buffer, len); + } + if (hfd.byteswap) + hdf_byteswap(buffer, len); + return v; + } + + /*-----------------------------------------------------------------------*/ + /* target */ + + const CACHE_SIZE = 16384; + + function hardfilehandle() { + this.zf = null; + this.firstwrite = false; + }; + + //function hdf_open_target(hfd, pname) { + function hdf_open_target(hfd, file) { + //hfd.flags = 0; + hfd.drive_empty = false; + hdf_close(hfd); + hfd.cache = new Uint8Array(CACHE_SIZE); //(uae_u8*)VirtualAlloc (null, CACHE_SIZE, MEM_COMMIT, PAGE_READWRITE); + /*if (!hfd.cache) { + SAEF_warn("VirtualAlloc(%d) failed, error %d", CACHE_SIZE, GetLastError()); + hdf_close(hfd); + return -1; + }*/ + hfd.cache_valid = 0; + hfd.virtual_size = 0; + hfd.virtual_rdb = null; + + hfd.vendor_id = "UAE"; + hfd.product_id = file.name.substr(0, Math.min(file.name.length, 16-1)); + hfd.product_rev = "0.1"; + + SAEF_log("hardfile.hdf_open_target() attempting to open HDF '%s'... (%d bytes)", file.name, file.size); + hfd.handle = new hardfilehandle(); + //hfd.handle.zf = SAEF_ZFile_fopen(pname, "rb", ZFD_NORMAL); + hfd.handle.zf = SAEF_ZFile_fopen_file(file); + if (hfd.handle.zf === null) { + hdf_close(hfd); + return -1; + } + SAEF_ZFile_fseek(hfd.handle.zf, 0, SEEK_END); + hfd.physsize = hfd.virtsize = SAEF_ZFile_ftell(hfd.handle.zf); + SAEF_ZFile_fseek(hfd.handle.zf, 0, SEEK_SET); + hfd.handle_valid = 1; + + SAEF_log("hardfile.hdf_open_target() HDF '%s' opened (size %dK, empty %d)", file.name, Math.floor(hfd.physsize / 1024), hfd.drive_empty ? 1:0); + return 1; + + /*if (hfd.handle_valid || hfd.drive_empty) { + SAEF_log("hardfile.hdf_open_target() HDF '%s' opened (size %dK, mode %d, empty %d)", file.name, Math.floor(hfd.physsize / 1024), hfd.handle_valid, hfd.drive_empty); + return 1; + } + hdf_close(hfd); + return -1;*/ + } + + function freehandle(h) { + if (h !== null) { + if (h.zf !== null) { + SAEF_ZFile_fclose(h.zf); + h.zf = null; + } + } + } + + function hdf_close_target(hfd) { + freehandle(hfd.handle); + //xfree(hfd.handle); + //xfree(hfd.emptyname); + //hfd.emptyname = null; + hfd.handle = null; + hfd.handle_valid = 0; + //if (hfd.cache) VirtualFree(hfd.cache, 0, MEM_RELEASE); + hfd.cache = null; + hfd.cache_valid = 0; + //xfree(hfd.virtual_rdb); + hfd.virtual_rdb = null; + hfd.virtual_size = 0; + hfd.drive_empty = false; + //hfd.dangerous = 0; + } + + /*---------------------------------*/ + + /*int hdf_dup_target(struct hardfiledata *dhfd, const struct hardfiledata *shfd) { + if (!shfd.handle_valid) + return 0; + freehandle (dhfd.handle); + + struct zfile *zf = SAEF_ZFile_dup(shfd.handle.zf); + if (!zf) + return 0; + dhfd.handle.zf = zf; + dhfd.handle_valid = 1; + + dhfd.cache = (uae_u8*)VirtualAlloc (null, CACHE_SIZE, MEM_COMMIT, PAGE_READWRITE); + dhfd.cache_valid = 0; + if (!dhfd.cache) { + hdf_close(dhfd); + return 0; + } + return 1; + }*/ + + function hdf_resize_target(hfd, newsize) { + /*DWORD ret, err; + if (newsize >= 0x80000000) { + LONG highword = (DWORD)(newsize >> 32); + ret = SetFilePointer (hfd.handle.h, (DWORD)newsize, &highword, FILE_BEGIN); + } else { + ret = SetFilePointer (hfd.handle.h, (DWORD)newsize, null, FILE_BEGIN); + } + err = GetLastError (); + if (ret == INVALID_SET_FILE_POINTER && err != NO_ERROR) { + write_log (_T("hdf_resize_target: SetFilePointer() %d\n"), err); + return 0; + } + if (SetEndOfFile (hfd.handle.h)) { + hfd.physsize = newsize; + return 1; + } + err = GetLastError (); + write_log (_T("hdf_resize_target: SetEndOfFile() %d\n"), err); + return 0;*/ + + SAEF_ZFile_resize(hfd.handle.zf, newsize); + hfd.physsize = newsize; + return true; + } + + /*---------------------------------*/ + + function hdf_seek(hfd, offset) { + if (hfd.handle_valid == 0) { + SAEF_warn("hardfile.hdf_seek() hdf handle is not valid. bug."); + //abort(); + return -1; + } + if (offset >= hfd.physsize - hfd.virtual_size) { + SAEF_warn("hardfile.hdf_seek() tried to seek out of bounds! (%X >= %X - %X)", offset, hfd.physsize, hfd.virtual_size); + //abort(); + return -1; + } + offset += hfd.offset; + if (offset & (hfd.ci.blocksize - 1)) { + SAEF_warn("hardfile.hdf_seek() fail, offset = %X not aligned to blocksize %d! (%X & %04X = %04X)", offset, hfd.ci.blocksize, offset, hfd.ci.blocksize, offset & (hfd.ci.blocksize - 1)); + //abort(); + return -1; + } + if (SAEF_ZFile_fseek(hfd.handle.zf, offset, SEEK_SET) != 0) { + SAEF_warn("hardfile.hdf_seek() common seek error"); + return -1; + } + return 0; + } + + /*---------------------------------*/ + + function poscheck(hfd, len) { + var pos = SAEF_ZFile_ftell(hfd.handle.zf); + if (len < 0) { + SAEF_warn("hardfile.poscheck() fail, negative length! (%d)", len); + //abort(); + return -1; + } + if (pos < hfd.offset) { + SAEF_warn("hardfile.poscheck() fail, offset out of bounds! (%d < %d)", pos, hfd.offset); + //abort(); + return -1; + } + if (pos >= hfd.offset + hfd.physsize - hfd.virtual_size || pos >= hfd.offset + hfd.physsize + len - hfd.virtual_size) { + SAEF_warn("hardfile.poscheck() fail, offset out of bounds! (%d >= %d, LEN=%d)", pos, hfd.offset + hfd.physsize, len); + //abort(); + return -1; + } + if (pos & (hfd.ci.blocksize - 1)) { + SAEF_warn("hardfile.poscheck() fail, offset not aligned to blocksize! (%X & %X = %04X)", pos, hfd.ci.blocksize, pos & hfd.ci.blocksize); + //abort(); + return -1; + } + return 0; + } + + /*---------------------------------*/ + + function isincache(hfd, offset, len) { + if (!hfd.cache_valid) + return -1; + if (offset >= hfd.cache_offset && offset + len <= hfd.cache_offset + CACHE_SIZE) + return offset - hfd.cache_offset; + return -1; + } + + function hdf_read_target_2(hfd, buffer,buffero, offset, len) { //hdf_read_2() + if (offset == 0) + hfd.cache_valid = 0; + var coffset = isincache(hfd, offset, len); + if (coffset >= 0) { + buffer.set(hfd.cache.subarray(coffset, coffset + len), buffero); //memcpy (buffer, hfd->cache + coffset, len); + return len; + } + hfd.cache_offset = offset; + if (offset + CACHE_SIZE > hfd.offset + (hfd.physsize - hfd.virtual_size)) + hfd.cache_offset = hfd.offset + (hfd.physsize - hfd.virtual_size) - CACHE_SIZE; + if (hdf_seek(hfd, hfd.cache_offset) == -1) + return -1; + if (poscheck(hfd, CACHE_SIZE) == -1) + return -1; + var outlen = SAEF_ZFile_fread(hfd.cache,0, 1, CACHE_SIZE, hfd.handle.zf); + hfd.cache_valid = 0; + if (outlen != CACHE_SIZE) + return 0; + hfd.cache_valid = 1; + coffset = isincache(hfd, offset, len); + if (coffset >= 0) { + buffer.set(hfd.cache.subarray(coffset, coffset + len), buffero); //memcpy (buffer, hfd->cache + coffset, len); + return len; + } + SAEF_error("hardfile.hdf_read_target_2() cache bug! offset %d, len %d", offset, len); + hfd.cache_valid = 0; + return 0; + } + + function hdf_read_target(hfd, buffer,buffero, offset, len) { + var got = 0; + //var p = buffer; + var p = buffero; + + if (hfd.drive_empty) + return 0; + if (offset < hfd.virtual_size) { + var len2 = offset + len <= hfd.virtual_size ? len : hfd.virtual_size - offset; + if (!hfd.virtual_rdb) + return 0; + buffer.set(hfd.virtual_rdb.subarray(offset, offset + len2), p); //memcpy(buffer, hfd.virtual_rdb + offset, len2); + return len2; + } + offset -= hfd.virtual_size; + while (len > 0) { + var maxlen; + var ret; + if (hfd.physsize < CACHE_SIZE) { + hfd.cache_valid = 0; + if (hdf_seek(hfd, offset) == -1) + return -1; + if (poscheck(hfd, len) == -1) + return -1; + ret = SAEF_ZFile_fread(buffer,p, 1, len, hfd.handle.zf); + maxlen = len; + } else { + maxlen = len > CACHE_SIZE ? CACHE_SIZE : len; + ret = hdf_read_target_2(hfd, buffer,p, offset, maxlen); + } + if (ret < 0) + return ret; + got += ret; + if (ret != maxlen) + return got; + offset += maxlen; + p += maxlen; + len -= maxlen; + } + return got; + } + + /*---------------------------------*/ + + function hdf_write_target_2(hfd, buffer,buffero, offset, len) { //hdf_write_2() + if (hfd.ci.readonly) + return 0; + //if (hfd.dangerous) + //return 0; + hfd.cache_valid = 0; + if (hdf_seek(hfd, offset) == -1) + return -1; + if (poscheck(hfd, len) == -1) + return -1; + hfd.cache.set(buffer.subarray(buffero, buffero + len)); //memcpy(hfd.cache, buffer, len); + return SAEF_ZFile_fwrite(hfd.cache,0, 1, len, hfd.handle.zf); + } + + function hdf_write_target(hfd, buffer,buffero, offset, len) { + var got = 0; + //var p = buffer; + var p = buffero; + + if (hfd.drive_empty) + return 0; + if (offset < hfd.virtual_size) + return len; + offset -= hfd.virtual_size; + while (len > 0) { + var maxlen = len > CACHE_SIZE ? CACHE_SIZE : len; + var ret = hdf_write_target_2(hfd, buffer,p, offset, maxlen); + if (ret < 0) + return ret; + got += ret; + if (ret != maxlen) + return got; + offset += maxlen; + p += maxlen; + len -= maxlen; + } + return got; + } + + /*-----------------------------------------------------------------------*/ + + this.reset = function() {} //hardfile_reset() +} diff --git a/sae/ide.js b/sae/ide.js new file mode 100644 index 0000000..b59de3e --- /dev/null +++ b/sae/ide.js @@ -0,0 +1,1499 @@ +/*------------------------------------------------------------------------- +| SAE - Scripted Amiga Emulator +| https://github.com/naTmeg/ScriptedAmigaEmulator +| +| Copyright (C) 2012-2016 Rupert Hausberger +| +| This program is free software; you can redistribute it and/or +| modify it under the terms of the GNU General Public License +| as published by the Free Software Foundation; either version 2 +| of the License, or (at your option) any later version. +| +| This program is distributed in the hope that it will be useful, +| but WITHOUT ANY WARRANTY; without even the implied warranty of +| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +| GNU General Public License for more details. +| +| Note: ported from WinUAE 3.2.x +-------------------------------------------------------------------------*/ + +function SAEO_IDE_threadState() { //ide_thread_state + this.idetable = null; //** + this.idetotal = 0; + this.state = 0; //volatile + this.requests = new smp_comm_pipe(); +}; + +/*---------------------------------*/ + +/*#define IDE_MEMORY_FUNCTIONS(x, y, z) \ +static void REGPARAM2 x ## _put8(uaecptr addr, uae_u32 b) \ +{ \ + y ## _write_byte(z, addr, b); \ +} \ +static void REGPARAM2 x ## _put16(uaecptr addr, uae_u32 b) \ +{ \ + y ## _write_word(z, addr, b); \ +} \ +static void REGPARAM2 x ## _put32(uaecptr addr, uae_u32 b) \ +{ \ + y ## _write_word(z, addr, b >> 16); \ + y ## _write_word(z, addr + 2, b); \ +} \ +static uae_u32 REGPARAM2 x ## _get8(uaecptr addr) \ +{ \ +return y ## _read_byte(z, addr); \ +} \ +static uae_u32 REGPARAM2 x ## _get16(uaecptr addr) \ +{ \ +return y ## _read_word(z, addr); \ +} \ +static uae_u32 REGPARAM2 x ## _get32(uaecptr addr) \ +{ \ + uae_u32 v = y ## _read_word(z, addr) << 16; \ + v |= y ## _read_word(z, addr + 2); \ + return v; \ +}*/ + +function SAEO_IDE() { + const IDE_LOG = 0; //0-3 + + const IDE_DATA = 0x00; + const IDE_ERROR = 0x01; /* see err-bits */ + const IDE_NSECTOR = 0x02; /* sector count, nr of sectors to read/write */ + const IDE_SECTOR = 0x03; /* starting sector */ + const IDE_LCYL = 0x04; /* starting cylinder */ + const IDE_HCYL = 0x05; /* high byte of starting cyl */ + const IDE_SELECT = 0x06; /* 101dhhhh , d=drive, hhhh=head */ + const IDE_STATUS = 0x07; /* see status-bits */ + + const IDE_SECONDARY = 0x0400; + const IDE_DEVCON = 0x0406; + const IDE_DRVADDR = 0x0407; + + /* STATUS bits */ + const IDE_STATUS_ERR = 0x01; // 0 + const IDE_STATUS_IDX = 0x02; // 1 + const IDE_STATUS_DRQ = 0x08; // 3 + const IDE_STATUS_DSC = 0x10; // 4 + const IDE_STATUS_DRDY = 0x40;// 6 + const IDE_STATUS_BSY = 0x80; // 7 + //const ATAPI_STATUS_CHK = IDE_STATUS_ERR; + + /* ERROR bits */ + const IDE_ERR_UNC = 0x40; + const IDE_ERR_MC = 0x20; + const IDE_ERR_IDNF = 0x10; + const IDE_ERR_MCR = 0x08; + const IDE_ERR_ABRT = 0x04; + const IDE_ERR_NM = 0x02; + + const ATAPI_ERR_EOM = 0x02; + const ATAPI_ERR_ILI = 0x01; + + /* ATAPI interrupt reason (Sector Count) */ + /*const ATAPI_IO = 0x02; + const ATAPI_CD = 0x01; + const ATAPI_MAX_TRANSFER = 32768;*/ + const MAX_IDE_MULTIPLE_SECTORS = 128; + + function ide_registers() { //all u8 + this.ide_select = 0; + this.ide_nsector = 0; + this.ide_sector = 0; + this.ide_lcyl = 0; + this.ide_hcyl = 0; + this.ide_devcon = 0; + this.ide_error = 0; + this.ide_feat = 0; + + this.ide_nsector2 = 0; + this.ide_sector2 = 0; + this.ide_lcyl2 = 0; + this.ide_hcyl2 = 0; + this.ide_feat2 = 0; + + this.ide_status = 0; + }; + + /*const MAX_IDE_PORTS_BOARD = 2; + function ide_board() { + uae_u8 *rom; + uae_u8 acmemory[128]; + int rom_size; + int rom_start; + int rom_mask; + uaecptr baseaddress; + int configured; + bool keepautoconfig; + int mask; + addrbank *bank; + struct ide_hdf *ide[MAX_IDE_PORTS_BOARD]; + bool irq; + bool intena; + bool enabled; + int state; + int type; + int userdata; + int subtype; + uae_u16 data_latch; + struct romconfig *rc, *original_rc; + struct ide_board **self_ptr; + };*/ + + function ide_hdf() { + this.hdhfd = new SAEO_Hardfile_Data_HD(); + //struct ide_board *board; + this.regs = new ide_registers(); + this.regs0 = null; + this.regs1 = null; + this.pair = null; // master<>slave + this.its = null; //new SAEO_IDE_threadState() + this.byteswap = false; + this.byteswapped_buffer = 0; + this.adide = false; + + this.secbuf = null; //u8 * + this.secbuf_size = 0; + this.buffer_offset = 0; + this.data_offset = 0; + this.data_size = 0; + this.data_multi = 0; + this.direction = 0; // 0 = read, 1 = write + this.intdrq = false; + this.lba48 = false; + this.lba48cmd = false; + this.start_lba = 0; //u64 + this.start_nsec = 0; + this.multiple_mode = 0; //u8 + this.irq_delay = 0; + this.irq = 0; + this.irq_new = false; + this.num = 0; + this.blocksize = 0; + this.maxtransferstate = 0; + this.ata_level = 0; + this.ide_drv = 0; + this.media_type = 0; + this.mode_8bit = false; + + this.atapi = false; + this.atapi_drdy = false; + this.cd_unit_num = 0; + + this.packet_state = 0; + this.packet_data_size = 0; + this.packet_data_offset = 0; + this.packet_transfer_size = 0; + + //struct scsi_data *scsi;*/ + }; + + /*-----------------------------------------------------------------------*/ + + this.adide_decode_word = function(w) { + var o = 0; + if (w & 0x8000) o |= 0x0001; + if (w & 0x0001) o |= 0x0002; + if (w & 0x4000) o |= 0x0004; + if (w & 0x0002) o |= 0x0008; + if (w & 0x2000) o |= 0x0010; + if (w & 0x0004) o |= 0x0020; + if (w & 0x1000) o |= 0x0040; + if (w & 0x0008) o |= 0x0080; + if (w & 0x0800) o |= 0x0100; + if (w & 0x0010) o |= 0x0200; + if (w & 0x0400) o |= 0x0400; + if (w & 0x0020) o |= 0x0800; + if (w & 0x0200) o |= 0x1000; + if (w & 0x0040) o |= 0x2000; + if (w & 0x0100) o |= 0x4000; + if (w & 0x0080) o |= 0x8000; + return o; + } + this.adide_encode_word = function(w) { + var o = 0; + if (w & 0x0001) o |= 0x8000; + if (w & 0x0002) o |= 0x0001; + if (w & 0x0004) o |= 0x4000; + if (w & 0x0008) o |= 0x0002; + if (w & 0x0010) o |= 0x2000; + if (w & 0x0020) o |= 0x0004; + if (w & 0x0040) o |= 0x1000; + if (w & 0x0080) o |= 0x0008; + if (w & 0x0100) o |= 0x0800; + if (w & 0x0200) o |= 0x0010; + if (w & 0x0400) o |= 0x0400; + if (w & 0x0800) o |= 0x0020; + if (w & 0x1000) o |= 0x0200; + if (w & 0x2000) o |= 0x0040; + if (w & 0x4000) o |= 0x0100; + if (w & 0x8000) o |= 0x0080; + return o; + } + + function pw(ide, offset, w) { + if (ide.byteswap) + w = ((w << 8) & 0xffff) | (w >> 8); + if (ide.adide) + w = SAER.ide.adide_decode_word(w); + ide.secbuf[offset * 2 + 0] = w & 0xff; + ide.secbuf[offset * 2 + 1] = w >> 8; + } + function ps(ide, offset, src, max) { + var s = src; //ua(src); + var len = s.length; //strlen(s); + + for (var i = 0; i < max; i += 2) { + var c1 = ' '; + if (i < len) + c1 = s.charCodeAt(i); + var c2 = ' '; + if (i + 1 < len) + c2 = s.charCodeAt(i + 1); + var w = (c2 << 8) | c1; + if (ide.byteswap) + w = ((w << 8) & 0xffff) | (w >> 8); + if (ide.adide) + w = SAER.ide.adide_decode_word(w); + ide.secbuf[offset * 2 + 0] = w >> 8; + ide.secbuf[offset * 2 + 1] = w & 0xff; + offset++; + } + //xfree(s); + } + + this.ide_isdrive = function(ide) { + return ide !== null && (ide.hdhfd.size != 0 || ide.atapi); + } + + function ide_grow_buffer(ide, newsize) { + if (ide.secbuf_size >= newsize) + return; + var oldbuf = ide.secbuf; + var oldsize = ide.secbuf_size; + ide.secbuf_size = newsize + 16384; + ide.secbuf = new Uint8Array(ide.secbuf_size); + if (oldsize) { + ide.secbuf.set(oldbuf); //memcpy(ide->secbuf, oldbuf, oldsize); + SAEF_log("ide.ide_grow_buffer() IDE%d buffer %d -> %d", ide.num, oldsize, ide.secbuf_size); + } + } + + function ide_interrupt_do(ide) { + var os = ide.regs.ide_status; + ide.regs.ide_status &= ~IDE_STATUS_DRQ; + if (ide.intdrq) + ide.regs.ide_status |= IDE_STATUS_DRQ; + ide.regs.ide_status &= ~IDE_STATUS_BSY; + if (IDE_LOG > 1) + SAEF_log("ide.ide_interrupt_do() INT %02X -> %02X", os, ide.regs.ide_status); + ide.intdrq = false; + ide.irq_delay = 0; + if (ide.regs.ide_devcon & 2) + return false; + ide.irq_new = true; + ide.irq = 1; + return true; + } + + /*bool ide_drq_check(struct ide_hdf *idep) { + for (int i = 0; idep && i < 2; i++) { + struct ide_hdf *ide = i == 0 ? idep : idep->pair; + if (ide) { + if (ide->regs.ide_status & IDE_STATUS_DRQ) + return true; + } + } + return false; + } + bool ide_irq_check(struct ide_hdf *idep, bool edge_triggered) { + for (int i = 0; idep && i < 2; i++) { + struct ide_hdf *ide = i == 0 ? idep : idep->pair; + if (ide->irq) { + if (edge_triggered) { + if (ide->irq_new) { + ide->irq_new = false; + return true; + } + continue; + } + return true; + } + } + return false; + }*/ + + this.ide_interrupt_hsync = function(idep) { + var irq = false; + for (var i = 0; idep && i < 2; i++) { + var ide = i == 0 ? idep : idep.pair; + if (ide) { + if (ide.irq_delay > 0) { + ide.irq_delay--; + if (ide.irq_delay == 0) { + ide_interrupt_do(ide); + } + } + if (ide.irq && !(ide.regs.ide_devcon & 2)) + irq = true; + } + } + return irq; + } + + /*-----------------------------------------------------------------------*/ + + function ide_interrupt(ide) { + ide.regs.ide_status |= IDE_STATUS_BSY; + ide.regs.ide_status &= ~IDE_STATUS_DRQ; + ide.irq_delay = 2; + } + function ide_fast_interrupt(ide) { + ide.regs.ide_status |= IDE_STATUS_BSY; + ide.regs.ide_status &= ~IDE_STATUS_DRQ; + ide.irq_delay = 1; + } + + function ide_fail_err(ide, err) { + ide.regs.ide_error |= err; + if (ide.ide_drv == 1 && !SAER.ide.ide_isdrive(ide.pair)) { + ide.pair.regs.ide_status |= IDE_STATUS_ERR; + } + ide.regs.ide_status |= IDE_STATUS_ERR; + ide_interrupt(ide); + } + function ide_fail(ide) { + ide_fail_err(ide, IDE_ERR_ABRT); + } + + function ide_data_ready(ide) { + //memset(ide.secbuf, 0, ide.blocksize); + SAEF_memset(ide.secbuf,0, 0, ide.blocksize); + ide.data_offset = 0; + ide.data_size = ide.blocksize; + ide.data_multi = 1; + ide.intdrq = true; + ide_interrupt(ide); + } + + function ide_recalibrate(ide) { + SAEF_log("ide.ide_recalibrate() IDE%d recalibrate", ide.num); + ide.regs.ide_sector = 0; + ide.regs.ide_lcyl = ide.regs.ide_hcyl = 0; + ide_interrupt(ide); + } + + function ide_identify_drive(ide) { + var totalsecs; //u64 + var v; + //var buf = ide.secbuf; + var tmp = ""; + var atapi = ide.atapi; + var cf = ide.media_type > 0; + + if (!SAER.ide.ide_isdrive(ide)) { + ide_fail(ide); + return; + } + //memset(buf, 0, ide.blocksize); + SAEF_memset(ide.secbuf,0, 0, ide.blocksize); + ide.byteswapped_buffer = 1; + if (IDE_LOG > 0) + SAEF_log("ide.ide_identify_drive() IDE%d identify drive", ide.num); + ide_data_ready(ide); + ide.direction = 0; + pw(ide, 0, atapi ? 0x85c0 : (cf ? 0x848a : (1 << 6))); + pw(ide, 1, ide.hdhfd.cyls_def); + pw(ide, 2, 0xc837); + pw(ide, 3, ide.hdhfd.heads_def); + pw(ide, 4, ide.blocksize * ide.hdhfd.secspertrack_def); + pw(ide, 5, ide.blocksize); + pw(ide, 6, ide.hdhfd.secspertrack_def); + ps(ide, 10, "68000", 20); /* serial */ + pw(ide, 20, 3); + pw(ide, 21, ide.blocksize); + pw(ide, 22, 4); + ps(ide, 23, "0.7", 8); /* firmware revision */ + if (ide.atapi) //OPT + tmp = "UAE-ATAPI"; + else + tmp = sprintf("UAE-IDE %s", ide.hdhfd.hfd.product_id); + ps(ide, 27, tmp, 40); /* model */ + pw(ide, 47, MAX_IDE_MULTIPLE_SECTORS >> (ide.blocksize / 512 - 1)); /* max sectors in multiple mode */ + pw(ide, 48, 1); + pw(ide, 49, (1 << 9) | (1 << 8)); /* LBA and DMA supported */ + pw(ide, 51, 0x200); /* PIO cycles */ + pw(ide, 52, 0x200); /* DMA cycles */ + pw(ide, 53, 1 | 2 | 4); + pw(ide, 54, ide.hdhfd.cyls); + pw(ide, 55, ide.hdhfd.heads); + pw(ide, 56, ide.hdhfd.secspertrack); + totalsecs = ide.hdhfd.cyls * ide.hdhfd.heads * ide.hdhfd.secspertrack; + pw(ide, 57, totalsecs & 0xffff); + pw(ide, 58, totalsecs >>> 16); + v = ide.multiple_mode; + pw(ide, 59, (v > 0 ? 0x100 : 0) | v); + totalsecs = ide.blocksize ? Math.floor(ide.hdhfd.size / ide.blocksize) : 0; + if (totalsecs > 0x0fffffff) + totalsecs = 0x0fffffff; + pw(ide, 60, totalsecs & 0xffff); + pw(ide, 61, totalsecs >>> 16); + pw(ide, 62, 0x0f); + pw(ide, 63, 0x0f); + if (ide.ata_level) { + pw(ide, 64, ide.ata_level ? 0x03 : 0x00); /* PIO4|PIO3 */ + pw(ide, 65, 120); /* MDMA2 supported */ + pw(ide, 66, 120); + pw(ide, 67, 120); + pw(ide, 68, 120); + pw(ide, 80, (1 << 1) | (1 << 2) | (1 << 3) | (1 << 4) | (1 << 5) | (1 << 6)); /* ATA-1 to ATA-6 */ + pw(ide, 81, 0x1c); /* ATA revision */ + pw(ide, 82, (1 << 14) | (atapi ? 0x10 | 4 : 0)); /* NOP, ATAPI: PACKET and Removable media features supported */ + pw(ide, 83, (1 << 14) | (1 << 13) | (1 << 12) | (ide.lba48 ? (1 << 10) : 0)); /* cache flushes, LBA 48 supported */ + pw(ide, 84, 1 << 14); + pw(ide, 85, 1 << 14); + pw(ide, 86, (1 << 14) | (1 << 13) | (1 << 12) | (ide.lba48 ? (1 << 10) : 0)); /* cache flushes, LBA 48 enabled */ + pw(ide, 87, 1 << 14); + pw(ide, 88, (1 << 5) | (1 << 4) | (1 << 3) | (1 << 2) | (1 << 1) | (1 << 0)); /* UDMA modes */ + pw(ide, 93, (1 << 14) | (1 << 13) | (1 << 0)); + if (ide.lba48) { //ATT + totalsecs = Math.floor(ide.hdhfd.size / ide.blocksize); + var hi = Math.floor(totalsecs / 0x100000000); + var lo = totalsecs % 0x100000000; + pw(ide, 100, lo & 0xffff); + pw(ide, 101, lo >>> 16); + pw(ide, 102, hi & 0xffff); + pw(ide, 103, hi >>> 16); + } + } + } + + function set_signature(ide) { + if (ide.atapi) { + ide.regs.ide_sector = 1; + ide.regs.ide_nsector = 1; + ide.regs.ide_lcyl = 0x14; + ide.regs.ide_hcyl = 0xeb; + ide.regs.ide_status = 0; + ide.atapi_drdy = false; + } else { + ide.regs.ide_nsector = 1; + ide.regs.ide_sector = 1; + ide.regs.ide_lcyl = 0; + ide.regs.ide_hcyl = 0; + ide.regs.ide_status = 0; + } + ide.regs.ide_error = 0x01; // device ok + ide.packet_state = 0; + } + function reset_device(ide, both) { + set_signature(ide); + if (both) + set_signature(ide.pair); + } + /*this.ide_reset_device = function(ide) { + reset_device(ide, true); + }*/ + + function ide_execute_drive_diagnostics(ide, irq) { + reset_device(ide, irq); + if (irq) + ide_interrupt(ide); + else + ide.regs.ide_status &= ~IDE_STATUS_BSY; + } + + function ide_initialize_drive_parameters(ide) { + var p = ide.hdhfd; + if (p.size) { + p.secspertrack = ide.regs.ide_nsector == 0 ? 256 : ide.regs.ide_nsector; + p.heads = (ide.regs.ide_select & 15) + 1; + if (p.hfd.ci.pcyls) + p.cyls = p.hfd.ci.pcyls; + else + p.cyls = Math.floor(Math.floor(p.size / ide.blocksize) / (p.secspertrack * p.heads)); + if (p.heads * p.cyls * p.secspertrack > 16515072 || ide.lba48) { + p.cyls = p.hfd.ci.pcyls ? p.hfd.ci.pcyls : p.cyls_def; + p.heads = p.heads_def; + p.secspertrack = p.secspertrack_def; + } + } else { + ide.regs.ide_error |= IDE_ERR_ABRT; + ide.regs.ide_status |= IDE_STATUS_ERR; + } + SAEF_log("ide.ide_initialize_drive_parameters() IDE%d initialize drive parameters, CYL=%d,SPT=%d,HEAD=%d", ide.num, p.cyls, p.secspertrack, p.heads); + ide_interrupt(ide); + } + + function ide_set_multiple_mode(ide) { + SAEF_log("ide.ide_set_multiple_mode() IDE%d drive multiple mode = %d", ide.num, ide.regs.ide_nsector); + ide.multiple_mode = ide.regs.ide_nsector; + ide_interrupt(ide); + } + + function ide_set_features(ide) { + var type = ide.regs.ide_nsector >> 3; + var mode = ide.regs.ide_nsector & 7; + + SAEF_log("ide.ide_set_features() IDE%d set features %02X (%02X)", ide.num, ide.regs.ide_feat, ide.regs.ide_nsector); + switch (ide.regs.ide_feat) { + // 8-bit mode + case 1: + ide.mode_8bit = true; + ide_interrupt(ide); + break; + case 0x81: + ide.mode_8bit = false; + ide_interrupt(ide); + break; + // write cache + case 2: + case 0x82: + ide_interrupt(ide); + break; + default: + ide_fail(ide); + } + } + + + + + + + + + function get_nsec(ide) { + if (ide.lba48 && ide.lba48cmd) + //return (ide.regs.ide_nsector == 0 && ide.regs.ide_nsector2 == 0) ? 65536 : (ide.regs.ide_nsector2 * 256 + ide.regs.ide_nsector); + return (ide.regs.ide_nsector == 0 && ide.regs.ide_nsector2 == 0) ? 65536 : ((ide.regs.ide_nsector2 << 8) | ide.regs.ide_nsector); + else + return ide.regs.ide_nsector == 0 ? 256 : ide.regs.ide_nsector; + } + function dec_nsec(ide, v) { + if (ide.lba48 && ide.lba48cmd) { + var nsec = (ide.regs.ide_nsector2 << 8) | ide.regs.ide_nsector; + nsec -= v; + if (nsec < 0) nsec += 0x10000; + ide.regs.ide_nsector2 = nsec >> 8; + ide.regs.ide_nsector = nsec & 0xff; + return nsec; + } else { + ide.regs.ide_nsector -= v; + if (ide.regs.ide_nsector < 0) ide.regs.ide_nsector += 0x100; + return ide.regs.ide_nsector; + } + } + + //function get_lbachs(ide, uae_u64 *lbap, unsigned int *cyl, unsigned int *head, unsigned int *sec) { + function get_lbachs(ide, ptr) { + if (ide.lba48 && ide.lba48cmd && (ide.regs.ide_select & 0x40)) { + /*ATT + uae_u64 lba; + lba = (ide.regs.ide_hcyl << 16) | (ide.regs.ide_lcyl << 8) | ide.regs.ide_sector; + lba |= ((ide.regs.ide_hcyl2 << 16) | (ide.regs.ide_lcyl2 << 8) | ide.regs.ide_sector2) << 24; + ptr.lba = lba;*/ + var lo = (ide.regs.ide_hcyl << 16) | (ide.regs.ide_lcyl << 8) | ide.regs.ide_sector; + var hi = (ide.regs.ide_hcyl2 << 16) | (ide.regs.ide_lcyl2 << 8) | ide.regs.ide_sector2; + ptr.lba = hi * 0x1000000 + lo; + } else { + if (ide.regs.ide_select & 0x40) { + ptr.lba = (((ide.regs.ide_select & 15) << 24) | (ide.regs.ide_hcyl << 16) | (ide.regs.ide_lcyl << 8) | ide.regs.ide_sector) >>> 0; + } else { + ptr.cyl = (ide.regs.ide_hcyl << 8) | ide.regs.ide_lcyl; + ptr.head = ide.regs.ide_select & 15; + ptr.sec = ide.regs.ide_sector; + ptr.lba = ((ptr.cyl * ide.hdhfd.heads + ptr.head) * ide.hdhfd.secspertrack) + ptr.sec - 1; + } + } + } + function put_lbachs(ide, lba, cyl, head, sec, inc) { + if (ide.lba48 && ide.lba48cmd) { + lba += inc; + /*ATT + ide.regs.ide_hcyl = (lba >> 16) & 0xff; + ide.regs.ide_lcyl = (lba >> 8) & 0xff; + ide.regs.ide_sector = lba & 0xff; + lba >>= 24; + ide.regs.ide_hcyl2 = (lba >> 16) & 0xff; + ide.regs.ide_lcyl2 = (lba >> 8) & 0xff; + ide.regs.ide_sector2 = lba & 0xff;*/ + var lo = lba % 0x1000000; + var hi = Math.floor(lba / 0x1000000); + ide.regs.ide_hcyl = (lo >>> 16) & 0xff; + ide.regs.ide_lcyl = (lo >>> 8) & 0xff; + ide.regs.ide_sector = lo & 0xff; + ide.regs.ide_hcyl2 = (hi >>> 16) & 0xff; + ide.regs.ide_lcyl2 = (hi >>> 8) & 0xff; + ide.regs.ide_sector2 = hi & 0xff; + } else { + if (ide.regs.ide_select & 0x40) { + lba += inc; + ide.regs.ide_select &= ~15; + ide.regs.ide_select |= (lba >>> 24) & 15; + ide.regs.ide_hcyl = (lba >>> 16) & 0xff; + ide.regs.ide_lcyl = (lba >>> 8) & 0xff; + ide.regs.ide_sector = lba & 0xff; + } else { + sec += inc; + while (sec >= ide.hdhfd.secspertrack) { + sec -= ide.hdhfd.secspertrack; + head++; + if (head >= ide.hdhfd.heads) { + head -= ide.hdhfd.heads; + cyl++; + } + } + ide.regs.ide_select &= ~15; + ide.regs.ide_select |= head; + ide.regs.ide_sector = sec; + ide.regs.ide_hcyl = cyl >> 8; + ide.regs.ide_lcyl = cyl & 0xff; + } + } + } + + function check_maxtransfer(ide, state) { + if (state == 1) { + // transfer was started + if (ide.maxtransferstate < 2 && ide.regs.ide_nsector == 0) + ide.maxtransferstate = 1; + else if (ide.maxtransferstate == 2) { + // second transfer was started (part of split) + SAEF_log("ide.check_maxtransfer() maxtransfer check detected split >256 block transfer"); + ide.maxtransferstate = 0; + } else + ide.maxtransferstate = 0; + } else if (state == 2) { + // address was read + if (ide.maxtransferstate == 1) + ide.maxtransferstate++; + else + ide.maxtransferstate = 0; + } + } + + function setdrq(ide) { + ide.regs.ide_status |= IDE_STATUS_DRQ; + ide.regs.ide_status &= ~IDE_STATUS_BSY; + } + function setbsy(ide) { + ide.regs.ide_status |= IDE_STATUS_BSY; + ide.regs.ide_status &= ~IDE_STATUS_DRQ; + } + + function process_rw_command(ide) { + setbsy(ide); + //write_comm_pipe_u32(ide.its.requests, ide.num, 1); + do_process_rw_command(ide); + } + function process_packet_command(ide) { + setbsy(ide); + write_comm_pipe_u32(ide.its.requests, ide.num | 0x80, 1); + } + + /*static void atapi_data_done (struct ide_hdf *ide) { + ide->regs.ide_nsector = ATAPI_IO | ATAPI_CD; + ide->regs.ide_status = IDE_STATUS_DRDY; + ide->data_size = 0; + ide->packet_data_offset = 0; + ide->data_offset = 0; + } + static bool atapi_set_size (struct ide_hdf *ide) { + int size; + size = ide->data_size; + ide->data_offset = 0; + if (!size) { + ide->packet_state = 0; + ide->packet_transfer_size = 0; + return false; + } + if (ide->packet_state == 2) { + if (size > ide->packet_data_size) + size = ide->packet_data_size; + if (size > ATAPI_MAX_TRANSFER) + size = ATAPI_MAX_TRANSFER; + ide->packet_transfer_size = size & ~1; + ide->regs.ide_lcyl = size & 0xff; + ide->regs.ide_hcyl = size >> 8; + } else { + ide->packet_transfer_size = 12; + } + if (IDE_LOG > 1) + write_log (_T("ATAPI data transfer %d/%d bytes\n"), ide->packet_transfer_size, ide->data_size); + return true; + } + static void atapi_packet (struct ide_hdf *ide) { + ide->packet_data_offset = 0; + ide->packet_data_size = (ide->regs.ide_hcyl << 8) | ide->regs.ide_lcyl; + if (ide->packet_data_size == 65535) + ide->packet_data_size = 65534; + ide->data_size = 12; + if (IDE_LOG > 0) + write_log (_T("ATAPI packet command. Data size = %d\n"), ide->packet_data_size); + ide->packet_state = 1; + ide->data_multi = 1; + ide->data_offset = 0; + ide->regs.ide_nsector = ATAPI_CD; + ide->regs.ide_error = 0; + if (atapi_set_size (ide)) + setdrq (ide); + }*/ + + /*static void do_packet_command (struct ide_hdf *ide) { + memcpy (ide->scsi->cmd, ide->secbuf, 12); + ide->scsi->cmd_len = 12; + if (IDE_LOG > 0) { + uae_u8 *c = ide->scsi->cmd; + write_log (_T("ATASCSI %02x.%02x.%02x.%02x.%02x.%02x.%02x.%02x.%02x.%02x.%02x.%02x\n"), + c[0], c[1], c[2], c[3], c[4], c[5], c[6], c[7], c[8], c[9], c[10], c[11]); + } + ide->direction = 0; + scsi_emulate_analyze (ide->scsi); + if (ide->scsi->direction <= 0) { + // data in + scsi_emulate_cmd (ide->scsi); + ide->data_size = ide->scsi->data_len; + ide->regs.ide_status = 0; + if (ide->scsi->status) { + // error + ide->regs.ide_error = (ide->scsi->sense[2] << 4) | 4; + atapi_data_done (ide); + ide->regs.ide_status |= ATAPI_STATUS_CHK; + atapi_set_size (ide); + return; + } else if (ide->scsi->data_len) { + // data in + ide_grow_buffer(ide, ide->scsi->data_len); + memcpy (ide->secbuf, ide->scsi->buffer, ide->scsi->data_len); + ide->regs.ide_nsector = ATAPI_IO; + } else { + // no data + atapi_data_done (ide); + } + } else { + // data out + ide->direction = 1; + ide->regs.ide_nsector = 0; + ide->data_size = ide->scsi->data_len; + } + ide->packet_state = 2; // data phase + if (atapi_set_size (ide)) + ide->intdrq = true; + }*/ + + /*static void do_process_packet_command (struct ide_hdf *ide) { + if (ide->packet_state == 1) { + do_packet_command (ide); + } else { + ide->packet_data_offset += ide->packet_transfer_size; + if (!ide->direction) { + // data still remaining, next transfer + if (atapi_set_size (ide)) + ide->intdrq = true; + } else { + if (atapi_set_size (ide)) { + ide->intdrq = true; + } else { + if (IDE_LOG > 1) + write_log(_T("IDE%d ATAPI write finished, %d bytes\n"), ide->num, ide->data_size); + memcpy (&ide->scsi->buffer, ide->secbuf, ide->data_size); + ide->scsi->data_len = ide->data_size; + scsi_emulate_cmd (ide->scsi); + } + } + } + ide_fast_interrupt (ide); + }*/ + + function do_process_rw_command(ide) { + //SAEF_log("ide.do_process_rw_command()"); + //unsigned int cyl, head, sec; + //uae_u64 lba; + var ptr = {}; + + ide.data_offset = 0; + var nsec = get_nsec(ide); + //get_lbachs(ide, &lba, &cyl, &head, &sec); + get_lbachs(ide, ptr); + if (IDE_LOG > 1) + SAEF_log("ide.do_process_rw_command() IDE%d off=%d, nsec=%d (%d) lba48=%d bs=%d", ide.num, ptr.lba, nsec, ide.multiple_mode, ide.lba48 + ide.lba48cmd, ide.blocksize); + + if (nsec * ide.blocksize > ide.hdhfd.size - ptr.lba * ide.blocksize) { + nsec = Math.truncate((ide.hdhfd.size - ptr.lba * ide.blocksize) / ide.blocksize); + if (IDE_LOG > 1) + SAEF_log("ide.do_process_rw_command() IDE%d nsec changed to %d", ide.num, nsec); + } + if (nsec <= 0) { + ide_data_ready(ide); + ide_fail_err(ide, IDE_ERR_IDNF); + return; + } + var nsec_total = nsec; + ide_grow_buffer(ide, nsec_total * ide.blocksize); + + if (nsec > ide.data_multi) + nsec = ide.data_multi; + + if (ide.buffer_offset == 0) { + // store initial lba and number of sectors to transfer + ide.start_lba = ptr.lba; + ide.start_nsec = nsec_total; + } + + if (ide.direction) { + if (IDE_LOG > 1) + SAEF_log("ide.do_process_rw_command() IDE%d write, %d/%d bytes, buffer offset %d", ide.num, nsec * ide.blocksize, nsec_total * ide.blocksize, ide.buffer_offset); + } else { + if (ide.buffer_offset == 0) { + SAER.hardfile.hdf_read(ide.hdhfd.hfd, ide.secbuf, ide.start_lba * ide.blocksize, ide.start_nsec * ide.blocksize); + if (IDE_LOG > 1) + SAEF_log("ide.do_process_rw_command() IDE%d initial read, %d bytes", ide.num, nsec_total * ide.blocksize); + } + if (IDE_LOG > 1) + SAEF_log("ide.do_process_rw_command() IDE%d read, read %d/%d bytes, buffer offset=%d", ide.num, nsec * ide.blocksize, nsec_total * ide.blocksize, ide.buffer_offset); + } + ide.intdrq = true; + var last = dec_nsec(ide, nsec) == 0; + // ATA-2 spec says CHS/LBA does only need to be updated if error condition + if (ide.ata_level != SAEC_Config_Mount_Controller_Level_ATA_2S || !last) + put_lbachs(ide, ptr.lba, ptr.cyl, ptr.head, ptr.sec, last ? nsec - 1 : nsec); + + if (last && ide.direction) { + if (IDE_LOG > 1) + SAEF_log("ide.do_process_rw_command() IDE%d write finished, %d bytes", ide.num, ide.start_nsec * ide.blocksize); + ide.intdrq = false; + SAER.hardfile.hdf_write(ide.hdhfd.hfd, ide.secbuf, ide.start_lba * ide.blocksize, ide.start_nsec * ide.blocksize); + } + + if (ide.direction) { + if (last) + ide_fast_interrupt(ide); + else + ide.irq_delay = 1; + } else { + if (ide.buffer_offset == 0) + ide_fast_interrupt(ide); + else + ide.irq_delay = 1; + } + } + + function ide_read_sectors(ide, flags) { + //unsigned int cyl, head, sec, nsec; + //uae_u64 lba; + var ptr = {}; + var multi = flags & 1; + + ide.lba48cmd = (flags & 2) != 0; + if (multi && ide.multiple_mode == 0) { + ide_fail(ide); + return; + } + check_maxtransfer(ide, 1); + SAER.gui.flicker_led(SAEC_GUI_LED_HD, ide.num, 1); + var nsec = get_nsec(ide); + //get_lbachs(ide, &lba, &cyl, &head, &sec); + get_lbachs(ide, ptr); + if (ptr.lba * ide.blocksize >= ide.hdhfd.size) { + ide_data_ready(ide); + ide_fail_err(ide, IDE_ERR_IDNF); + return; + } + if (IDE_LOG > 0) + SAEF_log("ide.ide_read_sectors() IDE%d %s off=%d, sec=%d (%d) lba48=%d", ide.num, (flags & 4) ? "verify" : "read", ptr.lba, nsec, ide.multiple_mode, ide.lba48 + ide.lba48cmd); + if (flags & 4) { + // verify + ide_interrupt(ide); + return; + } + ide.data_multi = multi ? ide.multiple_mode : 1; + ide.data_offset = 0; + ide.data_size = nsec * ide.blocksize; + ide.direction = 0; + ide.buffer_offset = 0; + // read start: preload sector(s), then trigger interrupt. + process_rw_command(ide); + } + function ide_write_sectors(ide, flags) { + //unsigned int cyl, head, sec, nsec; + //uae_u64 lba; + var ptr = {}; + var multi = flags & 1; + + ide.lba48cmd = (flags & 2) != 0; + if (multi && ide.multiple_mode == 0) { + ide_fail(ide); + return; + } + check_maxtransfer(ide, 1); + SAER.gui.flicker_led(SAEC_GUI_LED_HD, ide.num, 2); + nsec = get_nsec(ide); + //get_lbachs(ide, &lba, &cyl, &head, &sec); + get_lbachs(ide, ptr); + if (ptr.lba * ide.blocksize >= ide.hdhfd.size) { + ide_data_ready(ide); + ide_fail_err(ide, IDE_ERR_IDNF); + return; + } + if (IDE_LOG > 0) + SAEF_log("ide.ide_write_sectors() IDE%d write off=%d, sec=%d (%d) lba48=%d", ide.num, ptr.lba, nsec, ide.multiple_mode, ide.lba48 + ide.lba48cmd); + if (nsec * ide.blocksize > ide.hdhfd.size - ptr.lba * ide.blocksize) + nsec = Math.truncate((ide.hdhfd.size - ptr.lba * ide.blocksize) / ide.blocksize); + if (nsec <= 0) { + ide_data_ready(ide); + ide_fail_err(ide, IDE_ERR_IDNF); + return; + } + ide.data_multi = multi ? ide.multiple_mode : 1; + ide.data_offset = 0; + ide.data_size = nsec * ide.blocksize; + ide.direction = 1; + ide.buffer_offset = 0; + // write start: set DRQ and clear BSY. No interrupt. + ide.regs.ide_status |= IDE_STATUS_DRQ; + ide.regs.ide_status &= ~IDE_STATUS_BSY; + } + + function ide_do_command(ide, cmd) { + var lba48 = ide.lba48; + + if (IDE_LOG > 1) + SAEF_log("ide.ide_do_command() IDE%d command %02X", ide.num, cmd); + + ide.regs.ide_status &= ~ (IDE_STATUS_DRDY | IDE_STATUS_DRQ | IDE_STATUS_ERR); + ide.regs.ide_error = 0; + ide.intdrq = false; + ide.lba48cmd = false; + ide.byteswapped_buffer = 0; + + if (ide.atapi) { + //SAER.gui.flicker_led(SAEC_GUI_LED_CD, ide.num, 1); + ide.atapi_drdy = true; + if (cmd == 0x00) { /* nop */ + ide_interrupt(ide); + } else if (cmd == 0x08) { /* device reset */ + ide_execute_drive_diagnostics(ide, true); + } else if (cmd == 0xa1) { /* identify packet device */ + ide_identify_drive(ide); + } else if (cmd == 0xa0) { /* packet */ + atapi_packet(ide); + } else if (cmd == 0x90) { /* execute drive diagnostics */ + ide_execute_drive_diagnostics(ide, true); + } else { + ide_execute_drive_diagnostics(ide, false); + ide.atapi_drdy = false; + ide_fail(ide); + SAEF_warn("ide.ide_do_command() IDE%d: unknown ATAPI command 0x%02x", ide.num, cmd); + } + } else { + if (cmd == 0x10) { /* recalibrate */ + ide_recalibrate (ide); + } else if (cmd == 0xec) { /* identify drive */ + ide_identify_drive(ide); + } else if (cmd == 0x90) { /* execute drive diagnostics */ + ide_execute_drive_diagnostics(ide, true); + } else if (cmd == 0x91) { /* initialize drive parameters */ + ide_initialize_drive_parameters(ide); + } else if (cmd == 0xc6) { /* set multiple mode */ + ide_set_multiple_mode(ide); + } else if (cmd == 0x20 || cmd == 0x21) { /* read sectors */ + ide_read_sectors(ide, 0); + } else if (cmd == 0x40 || cmd == 0x41) { /* verify sectors */ + ide_read_sectors(ide, 4); + } else if (cmd == 0x24 && lba48) { /* read sectors ext */ + ide_read_sectors(ide, 2); + } else if (cmd == 0xc4) { /* read multiple */ + ide_read_sectors(ide, 1); + } else if (cmd == 0x29 && lba48) { /* read multiple ext */ + ide_read_sectors(ide, 1|2); + } else if (cmd == 0x30 || cmd == 0x31) { /* write sectors */ + ide_write_sectors(ide, 0); + } else if (cmd == 0x34 && lba48) { /* write sectors ext */ + ide_write_sectors(ide, 2); + } else if (cmd == 0xc5) { /* write multiple */ + ide_write_sectors(ide, 1); + } else if (cmd == 0x39 && lba48) { /* write multiple ext */ + ide_write_sectors(ide, 1|2); + } else if (cmd == 0x50) { /* format track (nop) */ + ide_interrupt(ide); + } else if (cmd == 0xef) { /* set features */ + ide_set_features(ide); + } else if (cmd == 0x00) { /* nop */ + ide_fail(ide); + } else if (cmd == 0x70) { /* seek */ + ide_interrupt(ide); + } else if (cmd == 0xe0 || cmd == 0xe1 || cmd == 0xe7 || cmd == 0xea) { /* standby now/idle/flush cache/flush cache ext */ + ide_interrupt(ide); + } else if (cmd == 0xe5) { /* check power mode */ + ide.regs.ide_nsector = 0xff; + ide_interrupt(ide); + } else { + ide_fail(ide); + SAEF_warn("ide.ide_do_command() IDE%d: unknown ATA command 0x%02x", ide.num, cmd); + } + } + } + + /*-----------------------------------------------------------------------*/ + + function ide_get_data_2(ide, bussize) { + var irq = false; + var v; + var inc = bussize ? 2 : 1; + + if (ide.data_size == 0) { + if (IDE_LOG > 0) + SAEF_warn("ide.ide_get_data_2() IDE%d DATA but no data left!? 0x%02X, PC 0x%08X", ide.num, ide.regs.ide_status, SAER_CPU_getPC()); + if (!SAER.ide.ide_isdrive(ide)) + return 0xffff; + return 0; + } + if (ide.packet_state) { + if (bussize) + v = (ide.secbuf[ide.packet_data_offset + ide.data_offset] << 8) | ide.secbuf[ide.packet_data_offset + ide.data_offset + 1]; + else + v = ide.secbuf[ide.packet_data_offset + ide.data_offset]; + + if (IDE_LOG > 4) + SAEF_log("ide.ide_get_data_2() IDE%d DATA read 0x%04x", ide.num, v); + ide.data_offset += inc; + if (ide.data_size < 0) + ide.data_size += inc; + else + ide.data_size -= inc; + if (ide.data_offset == ide.packet_transfer_size) { + if (IDE_LOG > 1) + SAEF_log("ide.ide_get_data_2() IDE%d ATAPI partial read finished, %d bytes remaining", ide.num, ide.data_size); + if (ide.data_size == 0) { + ide.packet_state = 0; + atapi_data_done(ide); + if (IDE_LOG > 1) + SAEF_log("ide.ide_get_data_2() IDE%d ATAPI read finished, %d bytes", ide.num, ide.packet_data_offset + ide.data_offset); + irq = true; + } else + process_packet_command(ide); + } + } else { + if (bussize) + v = (ide.secbuf[ide.buffer_offset + ide.data_offset] << 8) | ide.secbuf[ide.buffer_offset + ide.data_offset + 1]; + else + v = ide.secbuf[ide.buffer_offset + ide.data_offset]; + + if (IDE_LOG > 4) + SAEF_log("ide.ide_get_data_2() IDE%d DATA read 0x%04x %d/%d", ide.num, v, ide.data_offset, ide.data_size); + ide.data_offset += inc; + if (ide.data_size < 0) + ide.data_size += inc; + else { + ide.data_size -= inc; + if (((ide.data_offset % ide.blocksize) == 0) && (Math.floor(ide.data_offset / ide.blocksize) % ide.data_multi) == 0) { + if (ide.data_size) { + ide.buffer_offset += ide.data_offset; + do_process_rw_command(ide); + } + } + } + if (ide.data_size == 0) { + if (!(ide.regs.ide_status & IDE_STATUS_DRQ)) { + SAEF_warn("ide.ide_get_data_2() IDE%d read finished but DRQ was not active?", ide.num); + } + ide.regs.ide_status &= ~IDE_STATUS_DRQ; + if (IDE_LOG > 1) + SAEF_log("ide.ide_get_data_2() IDE%d read finished", ide.num); + } + } + if (irq) + ide_fast_interrupt(ide); + return v; + } + this.ide_get_data = function(ide) { + return ide_get_data_2(ide, 1); + } + /*this.ide_get_data_8bit = function(ide) { + return ide_get_data_2(ide, 0) & 0xff; + }*/ + + function ide_put_data_2(ide, v, bussize) { + var inc = bussize ? 2 : 1; + if (IDE_LOG > 4) + SAEF_log("ide.ide_put_data_2() IDE%d DATA write 0x%04x %d/%d", ide.num, v, ide.data_offset, ide.data_size); + if (ide.data_size == 0) { + if (IDE_LOG > 0) + SAEF_warn("ide.ide_put_data_2() IDE%d DATA write without request!? 0x%02X, PC 0x%08X", ide.num, ide.regs.ide_status, SAER_CPU_getPC()); + return; + } + ide_grow_buffer(ide, ide.packet_data_offset + ide.data_offset + 2); + if (ide.packet_state) { + if (bussize) { + ide.secbuf[ide.packet_data_offset + ide.data_offset + 1] = v & 0xff; + ide.secbuf[ide.packet_data_offset + ide.data_offset ] = v >> 8; + } else + ide.secbuf[(ide.packet_data_offset + ide.data_offset) ^ 1] = v; + } else { + if (bussize) { + ide.secbuf[ide.buffer_offset + ide.data_offset + 1] = v & 0xff; + ide.secbuf[ide.buffer_offset + ide.data_offset ] = v >> 8; + } else + ide.secbuf[ide.buffer_offset + ide.data_offset] = v; + + } + ide.data_offset += inc; + ide.data_size -= inc; + if (ide.packet_state) { + if (ide.data_offset == ide.packet_transfer_size) { + if (IDE_LOG > 0) { + var v = (ide.regs.ide_hcyl << 8) | ide.regs.ide_lcyl; + SAEF_warn("ide.ide_put_data_2() Data size after command received = %d (%d)", v, ide.packet_data_size); + } + process_packet_command(ide); + } + } else { + if (ide.data_size == 0) { + process_rw_command(ide); + } else if (((ide.data_offset % ide.blocksize) == 0) && (Math.floor(ide.data_offset / ide.blocksize) % ide.data_multi) == 0) { + var off = ide.data_offset; + do_process_rw_command(ide); + ide.buffer_offset += off; + } + } + } + this.ide_put_data = function(ide, v) { + ide_put_data_2(ide, v, 1); + } + this.ide_put_data_8bit = function(ide, v) { + ide_put_data_2(ide, v, 0); + } + + /*-----------------------------------------------------------------------*/ + + this.ide_read_reg = function(ide, ide_reg) { + var isdrv = this.ide_isdrive(ide); + var v = 0; + + if (ide === null) { + SAEF_warn("ide.ide_read_reg() no handle"); + //goto end; + return v; + } + if (ide.regs.ide_status & IDE_STATUS_BSY) + ide_reg = IDE_STATUS; + if (!this.ide_isdrive(ide)) { + if (ide_reg == IDE_STATUS) { + if (ide.pair.irq) + ide.pair.irq = 0; + if (this.ide_isdrive(ide.pair)) + v = 0x01; + else + v = 0xff; + } else + v = 0; + + //goto end; + if (IDE_LOG > 2 && ide_reg > 0 && (1 || ide.num > 0)) + SAEF_log("ide.ide_read_reg() IDE%d GET register %d=%02X (%08X)", ide.num, ide_reg, v & 0xff, SAER_CPU_getPC()); + return v; + } + + switch (ide_reg) { + case IDE_SECONDARY: + case IDE_SECONDARY + 1: + case IDE_SECONDARY + 2: + case IDE_SECONDARY + 3: + case IDE_SECONDARY + 4: + case IDE_SECONDARY + 5: + v = 0xff; + break; + case IDE_DRVADDR: + v = ((ide.ide_drv ? 2 : 1) | ((ide.regs.ide_select & 15) << 2)) ^ 0xff; + break; + case IDE_DATA: + break; + case IDE_ERROR: + v = ide.regs.ide_error; + break; + case IDE_NSECTOR: + if (isdrv) { + if (ide.regs.ide_devcon & 0x80) + v = ide.regs.ide_nsector2; + else + v = ide.regs.ide_nsector; + } + break; + case IDE_SECTOR: + if (isdrv) { + if (ide.regs.ide_devcon & 0x80) + v = ide.regs.ide_sector2; + else + v = ide.regs.ide_sector; + check_maxtransfer(ide, 2); + } + break; + case IDE_LCYL: + if (isdrv) { + if (ide.regs.ide_devcon & 0x80) + v = ide.regs.ide_lcyl2; + else + v = ide.regs.ide_lcyl; + } + break; + case IDE_HCYL: + if (isdrv) { + if (ide.regs.ide_devcon & 0x80) + v = ide.regs.ide_hcyl2; + else + v = ide.regs.ide_hcyl; + } + break; + case IDE_SELECT: + v = ide.regs.ide_select; + break; + case IDE_STATUS: + ide.irq = 0; + ide.irq_new = false; + // fall through + case IDE_DEVCON: // ALTSTATUS when reading + if (!isdrv) { + v = 0; + if (ide.regs.ide_error) + v |= IDE_STATUS_ERR; + } else { + v = ide.regs.ide_status; + if (!ide.atapi || (ide.atapi && ide.atapi_drdy)) + v |= IDE_STATUS_DRDY | IDE_STATUS_DSC; + } + break; + } + //end: + if (IDE_LOG > 2 && ide_reg > 0 && (1 || ide.num > 0)) + SAEF_log("ide.ide_read_reg() IDE%d GET register %d=%02X (%08X)", ide.num, ide_reg, v & 0xff, SAER_CPU_getPC()); + + return v; + } + + this.ide_write_reg = function(ide, ide_reg, val) { + if (ide === null) { + SAEF_warn("ide.ide_write_reg() no handle"); + return; + } + ide.regs1.ide_devcon &= ~0x80; // clear HOB + ide.regs0.ide_devcon &= ~0x80; // clear HOB + if (IDE_LOG > 2 && ide_reg > 0 && (1 || ide.num > 0)) + SAEF_log("ide.ide_write_reg() IDE%d PUT register %d=%02X (%08X)", ide.num, ide_reg, val & 0xff, SAER_CPU_getPC()); + + switch (ide_reg) { + case IDE_DRVADDR: + break; + case IDE_DEVCON: + if ((ide.regs.ide_devcon & 4) == 0 && (val & 4) != 0) { + reset_device(ide, true); + if (IDE_LOG > 1) + SAEF_log("ide.ide_write_reg() IDE%d: SRST", ide.num); + } + ide.regs0.ide_devcon = val; + ide.regs1.ide_devcon = val; + break; + case IDE_DATA: + break; + case IDE_ERROR: + ide.regs0.ide_feat2 = ide.regs0.ide_feat; + ide.regs0.ide_feat = val; + ide.regs1.ide_feat2 = ide.regs1.ide_feat; + ide.regs1.ide_feat = val; + break; + case IDE_NSECTOR: + ide.regs0.ide_nsector2 = ide.regs0.ide_nsector; + ide.regs0.ide_nsector = val; + ide.regs1.ide_nsector2 = ide.regs1.ide_nsector; + ide.regs1.ide_nsector = val; + break; + case IDE_SECTOR: + ide.regs0.ide_sector2 = ide.regs0.ide_sector; + ide.regs0.ide_sector = val; + ide.regs1.ide_sector2 = ide.regs1.ide_sector; + ide.regs1.ide_sector = val; + break; + case IDE_LCYL: + ide.regs0.ide_lcyl2 = ide.regs0.ide_lcyl; + ide.regs0.ide_lcyl = val; + ide.regs1.ide_lcyl2 = ide.regs1.ide_lcyl; + ide.regs1.ide_lcyl = val; + break; + case IDE_HCYL: + ide.regs0.ide_hcyl2 = ide.regs0.ide_hcyl; + ide.regs0.ide_hcyl = val; + ide.regs1.ide_hcyl2 = ide.regs1.ide_hcyl; + ide.regs1.ide_hcyl = val; + break; + case IDE_SELECT: + ide.regs0.ide_select = val; + ide.regs1.ide_select = val; + if (IDE_LOG > 2) { + if (ide.ide_drv != (val & 0x10) ? 1 : 0) + SAEF_log("ide.ide_write_reg() DRIVE=%d", (val & 0x10) ? 1 : 0); + } + ide.pair.ide_drv = ide.ide_drv = (val & 0x10) ? 1 : 0; + break; + case IDE_STATUS: + ide.irq = 0; + ide.irq_new = false; + if (this.ide_isdrive(ide)) { + ide.regs.ide_status |= IDE_STATUS_BSY; + ide_do_command(ide, val); + } + break; + } + } + + /*-----------------------------------------------------------------------*/ + + //function ide_thread(idedata) { + this.ide_thread = function(its) { + //struct ide_thread_state *its = (struct ide_thread_state*)idedata; + var quit = false; //OWN + + //for (;;) + { + var unit = read_comm_pipe_u32_blocking(its.requests); + if (unit) SAEF_log("ide.ide_thread() unit 0x%08x", unit); + + if (its.state == 0 || unit == 0xfffffff) { + SAEF_log("ide.ide_thread() QUIT"); + quit = true; + //break; + } else { + var ide = its.idetable[unit & 0x7f]; + if (SAER.ide.ide_isdrive(ide)) //OWN + { + if (unit & 0x80) + do_process_packet_command(ide); + else + do_process_rw_command(ide); + } else { + //SAEF_fatal(SAEE_Internal, "ide.ide_thread() no ide"); + } + } + } + if (quit) { + its.state = -1; + return 0; + } + setTimeout(function() { SAER.ide.ide_thread(its); }, 10); + } + + this.start_ide_thread = function(its) { + if (!its.state) { + SAEF_log("ide.start_ide_thread() state %d", its.state); + its.state = 1; + init_comm_pipe(its.requests, 100, 1); + //uae_start_thread("ide", ide_thread, its, null); + setTimeout(function() { SAER.ide.ide_thread(its); }, 0); + } + } + + this.stop_ide_thread = function(its) { + if (its.state > 0) { + SAEF_log("ide.stop_ide_thread() state %d", its.state); + its.state = 0; + write_comm_pipe_u32(its.requests, 0xffffffff, 1); + //while (its.state == 0) SAEF_sleep(10); //FIX will never break + its.state = 0; + } + } + + /*-----------------------------------------------------------------------*/ + + this.ide_initialize = function(idetable, chpair) { + var ide0 = idetable[chpair * 2 + 0]; + var ide1 = idetable[chpair * 2 + 1]; + + ide0.regs0 = ide0.regs; + ide0.regs1 = ide1.regs; + ide0.pair = ide1; + + ide1.regs1 = ide1.regs; + ide1.regs0 = ide0.regs; + ide1.pair = ide0; + + ide0.num = chpair * 2 + 0; + ide1.num = chpair * 2 + 1; + + reset_device(ide0, true); + } + + this.alloc_ide_mem = function(idetable, max, its) { + for (var i = 0; i < max; i++) { + var ide; + if (idetable[i] === null) { + ide = idetable[i] = new ide_hdf(); + ide.cd_unit_num = -1; + } + ide = idetable[i]; + ide_grow_buffer(ide, 1024); + if (its !== null) + ide.its = its; + } + } + + this.add_ide_unit = function(idetable, max, ch, ci, rc) { + this.alloc_ide_mem(idetable, max, null); + if (ch < 0) + return null; + var ide = idetable[ch]; + if (ci !== null) { + ide.hdhfd.hfd.ci = ci.clone(); //memcpy(&ide.hdhfd.hfd.ci, ci, sizeof(struct uaedev_config_info)); //ATT + } + /*if (ci.type == UAEDEV_CD && ci.device_emu_unit >= 0) { + device_func_init (0); + ide.scsi = scsi_alloc_cd (ch, ci.device_emu_unit, true); + if (!ide.scsi) { + SAEF_log("ide.add_ide_unit() IDE: CD EMU unit %d failed to open", ide.cd_unit_num); + return null; + } + ide.cd_unit_num = ci.device_emu_unit; + ide.atapi = true; + ide.blocksize = 512; + SAER.gui.flicker_led(SAEC_GUI_LED_CD, ch, -1); + + SAEF_log("ide.add_ide_unit() IDE%d CD %d", ch, ide.cd_unit_num); + } else if (ci.type == UAEDEV_HDF)*/ + { + if (!SAER.hardfile.hdf_hd_open(ide.hdhfd)) + return null; + ide.blocksize = ide.hdhfd.hfd.ci.blocksize; + ide.lba48 = (ide.hdhfd.hfd.ci.unit_special_flags & 1) || ide.hdhfd.size >= 128 * 0x40000000 ? 1 : 0; + SAER.gui.flicker_led(SAEC_GUI_LED_HD, ch, -1); + ide.cd_unit_num = -1; + ide.media_type = ci.controller_media_type; + ide.ata_level = ci.unit_feature_level; + if (ide.ata_level == SAEC_Config_Mount_Controller_Level_ATA_1 && (ide.hdhfd.size >= 4 * 0x40000000 || ide.media_type)) + ide.ata_level = SAEC_Config_Mount_Controller_Level_ATA_2; + + SAEF_log("ide.add_ide_unit() IDE%d HD '%s', LCHS=%d/%d/%d. PCHS=%d/%d/%d %dM. LBA48=%d", + ch, ide.hdhfd.hfd.ci.file.name, + ide.hdhfd.cyls, ide.hdhfd.heads, ide.hdhfd.secspertrack, + ide.hdhfd.hfd.ci.pcyls, ide.hdhfd.hfd.ci.pheads, ide.hdhfd.hfd.ci.psecs, + Math.floor(ide.hdhfd.size / (1024 * 1024)), ide.lba48); + + } + ide.regs.ide_status = 0; + ide.data_offset = 0; + ide.data_size = 0; + return ide; + } + + this.remove_ide_unit = function(idetable, ch) { + if (idetable === null) + return; + var ide = idetable[ch]; + if (ide) { + SAER.hardfile.hdf_hd_close(ide.hdhfd); + //scsi_free(ide.scsi); + //xfree(ide.secbuf); + var its = ide.its; + //clear(ide); //memset(ide, 0, sizeof(struct ide_hdf)); + ide.its = its; + } + } +} diff --git a/sae/input.js b/sae/input.js index 0c7801e..33e8ed3 100644 --- a/sae/input.js +++ b/sae/input.js @@ -1,13 +1,21 @@ -/************************************************************************** -* SAE - Scripted Amiga Emulator -* -* 2012-2015 Rupert Hausberger -* -* https://github.com/naTmeg/ScriptedAmigaEmulator -* -**************************************************************************/ +/*------------------------------------------------------------------------- +| SAE - Scripted Amiga Emulator +| https://github.com/naTmeg/ScriptedAmigaEmulator +| +| Copyright (C) 2012-2016 Rupert Hausberger +| +| This program is free software; you can redistribute it and/or +| modify it under the terms of the GNU General Public License +| as published by the Free Software Foundation; either version 2 +| of the License, or (at your option) any later version. +| +| This program is distributed in the hope that it will be useful, +| but WITHOUT ANY WARRANTY; without even the implied warranty of +| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +| GNU General Public License for more details. +-------------------------------------------------------------------------*/ -function Mouse() { +function SAEO_Mouse() { this.button = [false, false, false]; this.pos = 0; @@ -18,41 +26,41 @@ function Mouse() { var lx = -1; var ly = -1; - this.reset = function () { + this.reset = function() { this.button = [0, 0, 0]; cx = cy = 0; lx = ly = -1; }; - this.mousedown = function (e) { + this.mousedown = function(e) { e = e || window.event; if (!e) return; this.button[e.button] = true; }; - this.mouseup = function (e) { + this.mouseup = function(e) { e = e || window.event; if (!e) return; this.button[e.button] = false; }; - this.mouseover = function (e) { - //AMIGA.video.hideCursor(1); + this.mouseover = function(e) { + //SAER.video.hideCursor(1); this.mousemove(e); lx = cx; ly = cy; }; - this.mouseout = function (e) { - //AMIGA.video.hideCursor(0); + this.mouseout = function(e) { + //SAER.video.hideCursor(0); this.mouseup(e); }; - this.mousemove = function (e) { + this.mousemove = function(e) { e = e || window.event; - if (!e || !AMIGA.video) return; + if (!e) return; if (e.pageX || e.pageY) { cx = e.pageX; @@ -65,7 +73,7 @@ function Mouse() { lx = cx; ly = cy; } - //BUG.info('USER() mousemove %d %d', cx, cy); + //SAEF_log("input.mousemove() %d %d", cx, cy); }; this.update = function() { @@ -73,6 +81,16 @@ function Mouse() { var dx = cx - lx; var dy = cy - ly; + /* not working + var shift = SAEV_config.video.hresolution - SAER.playfield.get_bplcon0_res(); + var bplcon = SAER.playfield.get_bplcon0(); + var res = (bplcon & 0x40) ? SAEC_Config_Video_HResolution_SuperHiRes : ((bplcon & 0x8000) ? SAEC_Config_Video_HResolution_HiRes : SAEC_Config_Video_HResolution_LoRes); + var shift = SAEV_config.video.hresolution - res; + if (shift) { + dx <<= shift; + dy <<= shift; + }*/ + if (dx > 127) dx = 127; else if (dx < -127) dx = -127; mx += dx; if (mx > 255) mx -= 256; else if (mx < 0) mx += 256; @@ -80,24 +98,24 @@ function Mouse() { if (dy > 127) dy = 127; else if (dy < -127) dy = -127; my += dy; if (my > 255) my -= 256; else if (my < 0) my += 256; - } else + } else mx = my = 0; - + lx = cx; ly = cy; - + this.pos = (my << 8) + mx; - //BUG.info('USER() mousemove %d %d, ps $%04x', mx, my, this.pos); + //SAEF_log("input.update() %d %d %d, ps $%04x", shift, mx, my, this.pos); } } -function Joystick(type) { +function SAEO_Joystick(type) { this.type = type; this.button = [false, false, false]; this.state = [false, false, false, false]; this.dir = 0; - this.reset = function () { + this.reset = function() { this.button = [false, false, false]; this.state = [false, false, false, false]; }; @@ -110,7 +128,7 @@ function Joystick(type) { if (this.state[2]) d = !d; this.dir = d | (this.state[2] << 1) | (u << 8) | (this.state[0] << 9); - + /*var l = 1, r = 1, u = 1, d = 1; if (this.state[0]) l = 0; @@ -122,12 +140,17 @@ function Joystick(type) { var b1 = (r ^ 1) ? 2 : 0; var b8 = (u ^ l) ? 1 : 0; var b9 = (l ^ 1) ? 2 : 0; - + this.dir = ((b8 | b9) << 8) | (b0 | b1);*/ } } -function Keyboard() { +function SAEO_Keyboard() { + const DOM_KEY_LOCATION_STANDARD = 0x00; + const DOM_KEY_LOCATION_LEFT = 0x01; + const DOM_KEY_LOCATION_RIGHT = 0x02; + const DOM_KEY_LOCATION_NUMPAD = 0x03; + const RAWKEY_TILDE = 0x00; const RAWKEY_1 = 0x01; const RAWKEY_2 = 0x02; @@ -191,13 +214,13 @@ function Keyboard() { const RAWKEY_SPACE = 0x40; const RAWKEY_BACKSPACE = 0x41; const RAWKEY_TAB = 0x42; - //const RAWKEY_KP_ENTER = 0x43; + const RAWKEY_KP_ENTER = 0x43; const RAWKEY_RETURN = 0x44; const RAWKEY_ESCAPE = 0x45; const RAWKEY_DELETE = 0x46; - //const RAWKEY_INSERT = 0x47; - //const RAWKEY_PAGEUP = 0x48; - //const RAWKEY_PAGEDOWN = 0x49; + const RAWKEY_INSERT = 0x47; + const RAWKEY_PAGEUP = 0x48; + const RAWKEY_PAGEDOWN = 0x49; const RAWKEY_KP_MINUS = 0x4A; //const RAWKEY_F11 = 0x4B; const RAWKEY_UP = 0x4C; @@ -223,54 +246,55 @@ function Keyboard() { const RAWKEY_CAPSLOCK = 0x62; const RAWKEY_CONTROL = 0x63; const RAWKEY_LALT = 0x64; - //const RAWKEY_RALT = 0x65; + const RAWKEY_RALT = 0x65; const RAWKEY_LAMIGA = 0x66; const RAWKEY_RAMIGA = 0x67; - /*const RAWKEY_SCRLOCK = 0x6B; - const RAWKEY_PRTSCREEN = 0x6C; + const RAWKEY_SCRLOCK = 0x6B; + //const RAWKEY_PRTSCREEN = 0x6C;*/ const RAWKEY_NUMLOCK = 0x6D; const RAWKEY_PAUSE = 0x6E; - const RAWKEY_F12 = 0x6F; + //const RAWKEY_F12 = 0x6F; const RAWKEY_HOME = 0x70; const RAWKEY_END = 0x71; - const RAWKEY_MEDIA1 = 0x72; + /*const RAWKEY_MEDIA1 = 0x72; const RAWKEY_MEDIA2 = 0x73; const RAWKEY_MEDIA3 = 0x74; const RAWKEY_MEDIA4 = 0x75; const RAWKEY_MEDIA5 = 0x76; - const RAWKEY_MEDIA6 = 0x77; - const RAWKEY_NM_WHEEL_UP = 0x7A; + const RAWKEY_MEDIA6 = 0x77;*/ + const RAWKEY_RESETWARNING = 0x78; + /*const RAWKEY_NM_WHEEL_UP = 0x7A; const RAWKEY_NM_WHEEL_DOWN = 0x7B; const RAWKEY_NM_WHEEL_LEFT = 0x7C; const RAWKEY_NM_WHEEL_RIGHT = 0x7D; - const RAWKEY_NM_BUTTON_FOURTH = 0x7E;*/ - /*const RAWKEY_BAD_CODE = 0xF9; + const RAWKEY_NM_BUTTON_FOURTH = 0x7E; + const RAWKEY_BAD_CODE = 0xF9; const RAWKEY_BUFFER_OVERFLOW = 0xFA; const RAWKEY_SELFTEST_FAILED = 0xFC;*/ const RAWKEY_INIT_POWER_UP = 0xFD; const RAWKEY_TERM_POWER_UP = 0xFE; const defKeyCodeMap = { - 8:RAWKEY_BACKSPACE, //backspace - 9:RAWKEY_TAB, //tab - 13:RAWKEY_RETURN, //enter - 16:RAWKEY_LSHIFT, //shift - 17:RAWKEY_CONTROL, //ctrl - 18:RAWKEY_LALT, //alt - //19:RAWKEY_PAUSE, //pause/break - 20:RAWKEY_CAPSLOCK, //caps lock - 27:RAWKEY_ESCAPE, //escape - 32:RAWKEY_SPACE, //space - //33:RAWKEY_PAGEUP, //page up - //34:RAWKEY_PAGEDOWN, //page down - //35:RAWKEY_END, //end - //36:RAWKEY_HOME, //home - 37:RAWKEY_LEFT, //left arrow - 38:RAWKEY_UP, //up arrow - 39:RAWKEY_RIGHT, //right arrow - 40:RAWKEY_DOWN, //down arrow - //45:RAWKEY_INSERT, //insert - 46:RAWKEY_DELETE, //delete + 8:RAWKEY_BACKSPACE, //backspace + 9:RAWKEY_TAB, //tab + 13:RAWKEY_RETURN, //enter + 16:RAWKEY_LSHIFT, //shift + 17:RAWKEY_CONTROL, //ctrl + 18:RAWKEY_LALT, //alt + 19:RAWKEY_PAUSE, //pause/break + 20:RAWKEY_CAPSLOCK, //caps lock + 27:RAWKEY_ESCAPE, //escape + 32:RAWKEY_SPACE, //space + 33:RAWKEY_PAGEUP, //page up + 34:RAWKEY_PAGEDOWN, //page down + 35:RAWKEY_END, //end + 36:RAWKEY_HOME, //home + 37:RAWKEY_LEFT, //left arrow + 38:RAWKEY_UP, //up arrow + 39:RAWKEY_RIGHT, //right arrow + 40:RAWKEY_DOWN, //down arrow + 45:RAWKEY_INSERT, //insert + 46:RAWKEY_DELETE, //delete 48:RAWKEY_0, //0 49:RAWKEY_1, //1 50:RAWKEY_2, //2 @@ -307,84 +331,84 @@ function Keyboard() { 88:RAWKEY_X, //x 89:RAWKEY_Z, //y 90:RAWKEY_Y, //z - 91:RAWKEY_LAMIGA, //left window key + 91:RAWKEY_LAMIGA, //left window key 92:RAWKEY_RAMIGA, //right window key - 93:RAWKEY_HELP, //select key - 96:RAWKEY_KP_0, //numpad 0 - 97:RAWKEY_KP_1, //numpad 1 - 98:RAWKEY_KP_2, //numpad 2 - 99:RAWKEY_KP_3, //numpad 3 - 100:RAWKEY_KP_4, //numpad 4 - 101:RAWKEY_KP_5, //numpad 5 - 102:RAWKEY_KP_6, //numpad 6 - 103:RAWKEY_KP_7, //numpad 7 - 104:RAWKEY_KP_8, //numpad 8 - 105:RAWKEY_KP_9, //numpad 9 - 106:RAWKEY_KP_MULTIPLY, //multiply - 107:RAWKEY_KP_PLUS, //add - 109:RAWKEY_KP_MINUS, //subtract - 110:RAWKEY_KP_DECIMAL, //decimal point - 111:RAWKEY_KP_DIVIDE, //divide - 112:RAWKEY_F1 , //f1 - 113:RAWKEY_F2 , //f2 - 114:RAWKEY_F3 , //f3 - 115:RAWKEY_F4 , //f4 - 116:RAWKEY_F5 , //f5 - 117:RAWKEY_F6 , //f6 - 118:RAWKEY_F7 , //f7 - 119:RAWKEY_F8 , //f8 - 120:RAWKEY_F9 , //f9 - 121:RAWKEY_F10, //f10 - //122:RAWKEY_F11, //f11 - //123:RAWKEY_F12, //f12 - //144:RAWKEY_NUMLOCK, //num lock - //145:RAWKEY_SCRLOCK, //scroll lock + 93:RAWKEY_HELP, //select key + 96:RAWKEY_KP_0, //numpad 0 + 97:RAWKEY_KP_1, //numpad 1 + 98:RAWKEY_KP_2, //numpad 2 + 99:RAWKEY_KP_3, //numpad 3 + 100:RAWKEY_KP_4, //numpad 4 + 101:RAWKEY_KP_5, //numpad 5 + 102:RAWKEY_KP_6, //numpad 6 + 103:RAWKEY_KP_7, //numpad 7 + 104:RAWKEY_KP_8, //numpad 8 + 105:RAWKEY_KP_9, //numpad 9 + 106:RAWKEY_KP_MULTIPLY, //multiply + 107:RAWKEY_KP_PLUS, //add + 109:RAWKEY_KP_MINUS, //subtract + 110:RAWKEY_KP_DECIMAL, //decimal point + 111:RAWKEY_KP_DIVIDE, //divide + 112:RAWKEY_F1 , //f1 + 113:RAWKEY_F2 , //f2 + 114:RAWKEY_F3 , //f3 + 115:RAWKEY_F4 , //f4 + 116:RAWKEY_F5 , //f5 + 117:RAWKEY_F6 , //f6 + 118:RAWKEY_F7 , //f7 + 119:RAWKEY_F8 , //f8 + 120:RAWKEY_F9 , //f9 + 121:RAWKEY_F10, //f10 + //122:RAWKEY_F11, //f11 + //123:RAWKEY_F12, //f12 + 144:RAWKEY_NUMLOCK, //num lock + 145:RAWKEY_SCRLOCK, //scroll lock /*186:RAWKEY_SEMICOLON, //semi-colon - 187:RAWKEY_EQUAL, //equal sign - 188:RAWKEY_COMMA, //comma - 189:RAWKEY_MINUS, //dash - 190:RAWKEY_PERIOD, //period - 191:RAWKEY_SLASH, //forward slash - 192:RAWKEY_TILDE, //grave accent - 219:RAWKEY_LBRACKET, //open bracket - 220:RAWKEY_BACKSLASH, //back slash - 221:RAWKEY_RBRACKET, //close braket - 222:RAWKEY_QUOTE, //single quote - 226:RAWKEY_LESSGREATER*/ - 186:RAWKEY_LBRACKET, + 187:RAWKEY_EQUAL, //equal sign + 188:RAWKEY_COMMA, //comma + 189:RAWKEY_MINUS, //dash + 190:RAWKEY_PERIOD, //period + 191:RAWKEY_SLASH, //forward slash + 192:RAWKEY_TILDE, //grave accent + 219:RAWKEY_LBRACKET, //open bracket + 220:RAWKEY_BACKSLASH, //back slash + 221:RAWKEY_RBRACKET, //close braket + 222:RAWKEY_QUOTE, //single quote + 226:RAWKEY_LESSGREATER*/ + 186:RAWKEY_LBRACKET, 187:RAWKEY_RBRACKET, - 188:RAWKEY_COMMA, + 188:RAWKEY_COMMA, 189:RAWKEY_SLASH, - 190:RAWKEY_PERIOD, - 191:RAWKEY_2B, - 192:RAWKEY_SEMICOLON, - 219:RAWKEY_MINUS, - 220:RAWKEY_TILDE, - 221:RAWKEY_EQUAL, + 190:RAWKEY_PERIOD, + 191:RAWKEY_2B, + 192:RAWKEY_SEMICOLON, + 219:RAWKEY_MINUS, + 220:RAWKEY_TILDE, + 221:RAWKEY_EQUAL, 222:RAWKEY_QUOTE, - 226:RAWKEY_LESSGREATER - }; + 226:RAWKEY_LESSGREATER + }; const mozKeyCodeMap = { - 8:RAWKEY_BACKSPACE, //backspace - 9:RAWKEY_TAB, //tab - 13:RAWKEY_RETURN, //enter - 16:RAWKEY_LSHIFT, //shift - 17:RAWKEY_CONTROL, //ctrl - 18:RAWKEY_LALT, //alt - //19:RAWKEY_PAUSE, //pause/break - 20:RAWKEY_CAPSLOCK, //caps lock - 27:RAWKEY_ESCAPE, //escape - 32:RAWKEY_SPACE, //space - //33:RAWKEY_PAGEUP, //page up - //34:RAWKEY_PAGEDOWN, //page down - //35:RAWKEY_END, //end - //36:RAWKEY_HOME, //home - 37:RAWKEY_LEFT, //left arrow - 38:RAWKEY_UP, //up arrow - 39:RAWKEY_RIGHT, //right arrow - 40:RAWKEY_DOWN, //down arrow - //45:RAWKEY_INSERT, //insert - 46:RAWKEY_DELETE, //delete + 8:RAWKEY_BACKSPACE, //backspace + 9:RAWKEY_TAB, //tab + 13:RAWKEY_RETURN, //enter + 16:RAWKEY_LSHIFT, //shift + 17:RAWKEY_CONTROL, //ctrl + 18:RAWKEY_LALT, //alt + 19:RAWKEY_PAUSE, //pause/break + 20:RAWKEY_CAPSLOCK, //caps lock + 27:RAWKEY_ESCAPE, //escape + 32:RAWKEY_SPACE, //space + 33:RAWKEY_PAGEUP, //page up + 34:RAWKEY_PAGEDOWN, //page down + 35:RAWKEY_END, //end + 36:RAWKEY_HOME, //home + 37:RAWKEY_LEFT, //left arrow + 38:RAWKEY_UP, //up arrow + 39:RAWKEY_RIGHT, //right arrow + 40:RAWKEY_DOWN, //down arrow + 45:RAWKEY_INSERT, //insert + 46:RAWKEY_DELETE, //delete 48:RAWKEY_0, //0 49:RAWKEY_1, //1 50:RAWKEY_2, //2 @@ -394,9 +418,9 @@ function Keyboard() { 54:RAWKEY_6, //6 55:RAWKEY_7, //7 56:RAWKEY_8, //8 - 57:RAWKEY_9, //9 + 57:RAWKEY_9, //9 60:RAWKEY_LESSGREATER, - 63:RAWKEY_MINUS, + 63:RAWKEY_MINUS, 65:RAWKEY_A, //a 66:RAWKEY_B, //b 67:RAWKEY_C, //c @@ -423,119 +447,119 @@ function Keyboard() { 88:RAWKEY_X, //x 89:RAWKEY_Z, //y 90:RAWKEY_Y, //z - 91:RAWKEY_LAMIGA, //left window key + 91:RAWKEY_LAMIGA, //left window key 92:RAWKEY_RAMIGA, //right window key - 93:RAWKEY_HELP, //select key - 96:RAWKEY_KP_0, //numpad 0 - 97:RAWKEY_KP_1, //numpad 1 - 98:RAWKEY_KP_2, //numpad 2 - 99:RAWKEY_KP_3, //numpad 3 - 100:RAWKEY_KP_4, //numpad 4 - 101:RAWKEY_KP_5, //numpad 5 - 102:RAWKEY_KP_6, //numpad 6 - 103:RAWKEY_KP_7, //numpad 7 - 104:RAWKEY_KP_8, //numpad 8 - 105:RAWKEY_KP_9, //numpad 9 - 106:RAWKEY_KP_MULTIPLY, //multiply - 107:RAWKEY_KP_PLUS, //add - 109:RAWKEY_KP_MINUS, //subtract - 110:RAWKEY_KP_DECIMAL, //decimal point - 111:RAWKEY_KP_DIVIDE, //divide - 112:RAWKEY_F1 , //f1 - 113:RAWKEY_F2 , //f2 - 114:RAWKEY_F3 , //f3 - 115:RAWKEY_F4 , //f4 - 116:RAWKEY_F5 , //f5 - 117:RAWKEY_F6 , //f6 - 118:RAWKEY_F7 , //f7 - 119:RAWKEY_F8 , //f8 - 120:RAWKEY_F9 , //f9 - 121:RAWKEY_F10, //f10 - //122:RAWKEY_F11, //f11 - //123:RAWKEY_F12, //f12 - //144:RAWKEY_NUMLOCK, //num lock - //145:RAWKEY_SCRLOCK, //scroll lock - 160:RAWKEY_TILDE, - 163:RAWKEY_2B, - 171:RAWKEY_RBRACKET, - 173:RAWKEY_SLASH, - 188:RAWKEY_COMMA, - 190:RAWKEY_PERIOD, - 192:RAWKEY_EQUAL - }; + 93:RAWKEY_HELP, //select key + 96:RAWKEY_KP_0, //numpad 0 + 97:RAWKEY_KP_1, //numpad 1 + 98:RAWKEY_KP_2, //numpad 2 + 99:RAWKEY_KP_3, //numpad 3 + 100:RAWKEY_KP_4, //numpad 4 + 101:RAWKEY_KP_5, //numpad 5 + 102:RAWKEY_KP_6, //numpad 6 + 103:RAWKEY_KP_7, //numpad 7 + 104:RAWKEY_KP_8, //numpad 8 + 105:RAWKEY_KP_9, //numpad 9 + 106:RAWKEY_KP_MULTIPLY, //multiply + 107:RAWKEY_KP_PLUS, //add + 109:RAWKEY_KP_MINUS, //subtract + 110:RAWKEY_KP_DECIMAL, //decimal point + 111:RAWKEY_KP_DIVIDE, //divide + 112:RAWKEY_F1 , //f1 + 113:RAWKEY_F2 , //f2 + 114:RAWKEY_F3 , //f3 + 115:RAWKEY_F4 , //f4 + 116:RAWKEY_F5 , //f5 + 117:RAWKEY_F6 , //f6 + 118:RAWKEY_F7 , //f7 + 119:RAWKEY_F8 , //f8 + 120:RAWKEY_F9 , //f9 + 121:RAWKEY_F10, //f10 + //122:RAWKEY_F11, //f11 + //123:RAWKEY_F12, //f12 + 144:RAWKEY_NUMLOCK, //num lock + 145:RAWKEY_SCRLOCK, //scroll lock + 160:RAWKEY_TILDE, + 163:RAWKEY_2B, + 171:RAWKEY_RBRACKET, + 173:RAWKEY_SLASH, + 188:RAWKEY_COMMA, + 190:RAWKEY_PERIOD, + 192:RAWKEY_EQUAL + }; const MAXKEYS = 256; const KEYBUFSIZE = 512; + const USECAPTURE = false; /* capturing/bubbling phase */ + + var keyState = new Array(4); + for (var vi = 0; vi < 4; vi++) + keyState[vi] = new Uint8Array(MAXKEYS); - var keyState = new Uint8Array(MAXKEYS); var keyBuf = new Uint8Array(KEYBUFSIZE); + var state = 0; var code = 0; var first = 0, last = 0; var capsLock = false; - - var hsynccnt = 0; - this.lostsynccnt = 0; - //for (var k in KeyEvent) document.writeln('KeyEvent.' + k + ' = ' + KeyEvent[k]+'
'); //FF - for (var i = 0; i < MAXKEYS; i++) keyState[i] = false; - for (var i = 0; i < KEYBUFSIZE; i++) keyBuf[i] = 0; - - function _onkeydown(e) { AMIGA.input.keyboard.handleKey(e, true); } - function _onkeyup(e) { AMIGA.input.keyboard.handleKey(e, false); } - this.setup = function () { - /*document.onkeydown = function (e) { - AMIGA.input.keyboard.keydownup(e, true); - } - document.onkeyup = function (e) { - AMIGA.input.keyboard.keydownup(e, false); - }*/ - window.document.addEventListener('keydown', _onkeydown, false); - window.document.addEventListener('keyup', _onkeyup, false); + function keydown(e) { handleKey(e, true); } + function keyup(e) { handleKey(e, false); } + /*function fullscreenchange(e) { + SAEF_log("fullscreenchange()"); + }*/ + + this.setup = function() { + if (SAEV_config.keyboard.enabled) { + document.addEventListener("keydown", keydown, USECAPTURE); + document.addEventListener("keyup", keyup, USECAPTURE); + //document.addEventListener("webkitfullscreenchange", fullscreenchange); + } }; - this.cleanup = function () { - //BUG.info('Keyboard.cleanup()'); - //document.onkeydown = null; - //document.onkeyup = null; - window.document.removeEventListener('keydown', _onkeydown, false); - window.document.removeEventListener('keyup', _onkeyup, false); + this.cleanup = function() { + if (SAEV_config.keyboard.enabled) { + document.removeEventListener("keydown", keydown, USECAPTURE); + document.removeEventListener("keyup", keyup, USECAPTURE); + //document.removeEventListener("webkitfullscreenchange", fullscreenchange); + } }; - this.reset = function () { - for (var i = 0; i < MAXKEYS; i++) keyState[i] = false; + this.reset = function() { + for (var j = 0; j < keyState.length; j++) { + for (var i = 0; i < keyState[j].length; i++) + keyState[j][i] = 0; + } state = 0; code = 0; first = last = 0; - hsynccnt = 0; - this.lostsynccnt = 0; }; - this.keysAvail = function () { + this.keysAvail = function() { return first != last; }; - this.nextKey = function () { - //assert (first != last); + this.nextKey = function() { + SAEF_assert(first != last); var key = keyBuf[last]; if (++last == KEYBUFSIZE) last = 0; return key; }; - this.recordKey = function (kc) { + function recordKey(kc) { var next = first + 1; if (next == KEYBUFSIZE) next = 0; if (next == last) { - BUG.info('Keyboard() buffer overrun!'); + SAEF_warn("imput.recordKey() buffer overrun!"); return false; } keyBuf[first] = kc; first = next; return true; }; - - this.processKey = function (code, down) { + + function processKey(loc, code, down) { /* Caps-lock */ if (code == 20) { if (down) { @@ -547,268 +571,184 @@ function Keyboard() { } /* joystick emul */ - if (AMIGA.config.ports[0].type == SAEV_Config_Ports_Type_Joy0) { + if (SAEV_config.ports[0].type == SAEC_Config_Ports_Type_Joy0) { var l, u, r, d, f1, f2; - switch (AMIGA.config.ports[0].move) { - case SAEV_Config_Ports_Move_Arrows: - { + switch (SAEV_config.ports[0].move) { + case SAEC_Config_Ports_Move_Arrows: l = 37; u = 38; r = 39; d = 40; break; - } - case SAEV_Config_Ports_Move_Numpad: - { + case SAEC_Config_Ports_Move_Numpad: l = 100; u = 104; r = 102; d = 101; break; - } - case SAEV_Config_Ports_Move_WASD: - { + case SAEC_Config_Ports_Move_WASD: l = 65; u = 87; r = 68; d = 83; break; - } } - f1 = AMIGA.config.ports[0].fire[0]; - f2 = AMIGA.config.ports[0].fire[1]; + f1 = SAEV_config.ports[0].fire[0]; + f2 = SAEV_config.ports[0].fire[1]; switch (code) { case f1: - { - AMIGA.input.joystick[0].button[0] = down; + SAER.input.joystick[0].button[0] = down; break; - } case f2: - { - AMIGA.input.joystick[0].button[1] = down; + SAER.input.joystick[0].button[1] = down; + break; + case l: { + SAER.input.joystick[0].state[0] = down; + if (down && SAER.input.joystick[0].state[2]) SAER.input.joystick[0].state[2] = false; break; } - case l: - { - AMIGA.input.joystick[0].state[0] = down; - if (down && AMIGA.input.joystick[0].state[2]) AMIGA.input.joystick[0].state[2] = false; + case u: { + SAER.input.joystick[0].state[1] = down; + if (down && SAER.input.joystick[0].state[3]) SAER.input.joystick[0].state[3] = false; break; } - case u: - { - AMIGA.input.joystick[0].state[1] = down; - if (down && AMIGA.input.joystick[0].state[3]) AMIGA.input.joystick[0].state[3] = false; + case r: { + SAER.input.joystick[0].state[2] = down; + if (down && SAER.input.joystick[0].state[0]) SAER.input.joystick[0].state[0] = false; break; } - case r: - { - AMIGA.input.joystick[0].state[2] = down; - if (down && AMIGA.input.joystick[0].state[0]) AMIGA.input.joystick[0].state[0] = false; - break; - } - case d: - { - AMIGA.input.joystick[0].state[3] = down; - if (down && AMIGA.input.joystick[0].state[1]) AMIGA.input.joystick[0].state[1] = false; + case d: { + SAER.input.joystick[0].state[3] = down; + if (down && SAER.input.joystick[0].state[1]) SAER.input.joystick[0].state[1] = false; break; } } } - if (AMIGA.config.ports[1].type == SAEV_Config_Ports_Type_Joy1) { + if (SAEV_config.ports[1].type == SAEC_Config_Ports_Type_Joy1) { var l, u, r, d, f1, f2; - switch (AMIGA.config.ports[1].move) { - case SAEV_Config_Ports_Move_Arrows: - { + switch (SAEV_config.ports[1].move) { + case SAEC_Config_Ports_Move_Arrows: l = 37; u = 38; r = 39; d = 40; break; - } - case SAEV_Config_Ports_Move_Numpad: - { + case SAEC_Config_Ports_Move_Numpad: l = 100; u = 104; r = 102; d = 101; break; - } - case SAEV_Config_Ports_Move_WASD: - { + case SAEC_Config_Ports_Move_WASD: l = 65; u = 87; r = 68; d = 83; break; - } } - f1 = AMIGA.config.ports[1].fire[0]; - f2 = AMIGA.config.ports[1].fire[1]; + f1 = SAEV_config.ports[1].fire[0]; + f2 = SAEV_config.ports[1].fire[1]; switch (code) { case f1: - { - AMIGA.input.joystick[1].button[0] = down; + SAER.input.joystick[1].button[0] = down; break; - } case f2: - { - AMIGA.input.joystick[1].button[1] = down; + SAER.input.joystick[1].button[1] = down; + break; + case l: { + SAER.input.joystick[1].state[0] = down; + if (down && SAER.input.joystick[1].state[2]) SAER.input.joystick[1].state[2] = false; break; } - case l: - { - AMIGA.input.joystick[1].state[0] = down; - if (down && AMIGA.input.joystick[1].state[2]) AMIGA.input.joystick[1].state[2] = false; + case u: { + SAER.input.joystick[1].state[1] = down; + if (down && SAER.input.joystick[1].state[3]) SAER.input.joystick[1].state[3] = false; break; } - case u: - { - AMIGA.input.joystick[1].state[1] = down; - if (down && AMIGA.input.joystick[1].state[3]) AMIGA.input.joystick[1].state[3] = false; + case r: { + SAER.input.joystick[1].state[2] = down; + if (down && SAER.input.joystick[1].state[0]) SAER.input.joystick[1].state[0] = false; break; } - case r: - { - AMIGA.input.joystick[1].state[2] = down; - if (down && AMIGA.input.joystick[1].state[0]) AMIGA.input.joystick[1].state[0] = false; - break; - } - case d: - { - AMIGA.input.joystick[1].state[3] = down; - if (down && AMIGA.input.joystick[1].state[1]) AMIGA.input.joystick[1].state[1] = false; + case d: { + SAER.input.joystick[1].state[3] = down; + if (down && SAER.input.joystick[1].state[1]) SAER.input.joystick[1].state[1] = false; break; } } } - if (!AMIGA.config.keyboard.enabled) + if (!SAEV_config.keyboard.enabled) return; - /* map shift-keys (team17 pinball games) */ - if (AMIGA.config.keyboard.mapShift) { - switch (code) { - case 37: - { //left arrow - if (!down) { - this.recordKey((RAWKEY_LSHIFT << 1) | 1); - } else { - this.recordKey(RAWKEY_LSHIFT << 1); - } - //break; - return; - } - case 39: - { //right arrow - if (!down) { - this.recordKey((RAWKEY_RSHIFT << 1) | 1); - } else { - this.recordKey(RAWKEY_RSHIFT << 1); - } - //break; - return; - } - } - } - var rawkey = false; - if (BrowserDetect.browser == 'Firefox') { - if (typeof(mozKeyCodeMap[code]) != 'undefined') + if (SAEC_info.browser.id == SAEC_Info_Brower_ID_Firefox) { + if (typeof mozKeyCodeMap[code] != "undefined") rawkey = mozKeyCodeMap[code]; } else { - if (typeof(defKeyCodeMap[code]) != 'undefined') + if (typeof defKeyCodeMap[code] != "undefined") rawkey = defKeyCodeMap[code]; } - //BUG.info('Keyboard.processKey() code %d $%04x, rawkey $%04x', code, code, rawkey); if (rawkey !== false) { + switch (rawkey) { + case RAWKEY_LSHIFT: { + if (loc == DOM_KEY_LOCATION_RIGHT) rawkey = RAWKEY_RSHIFT; + break; + } + case RAWKEY_LALT: { + if (loc == DOM_KEY_LOCATION_RIGHT) rawkey = RAWKEY_RALT; + break; + } + /*case RAWKEY_LAMIGA: { + if (loc == DOM_KEY_LOCATION_RIGHT) rawkey = RAWKEY_RAMIGA; + break; + }*/ + case RAWKEY_RETURN: { + if (loc == DOM_KEY_LOCATION_NUMPAD) rawkey = RAWKEY_KP_ENTER; + break; + } + + } + + //if (down) SAEF_log("Keyboard.processKey() loc %d, code %d $%04x, rawkey $%04x", loc, code, code, rawkey); + if (down) - this.recordKey(rawkey << 1); + recordKey(rawkey << 1); else - this.recordKey((rawkey << 1) | 1); + recordKey((rawkey << 1) | 1); } }; - - this.handleKey = function (e, down) { + + function handleKey(e, down) { e = e || window.event; - var code = e.which ? e.which : e.keyCode; + var code = typeof e.keyCode == "undefined" ? e.which : e.keyCode; + var loc = typeof e.location == "undefined" ? 0 : e.location; - if (AMIGA.config.keyboard.enabled && code != 122 && code != 123) //all but F11 F12 - e.preventDefault(); + if (code == 122) { //F11 + //if (!down) SAER.video.toggle_fullscreen_real(2); + return; + } + if (code == 123) //F12 + return; - //BUG.info('Keyboard.handleKey() down %d, code %d, alt %d, shift %d, ctrl %d', down?1:0, code, e.altKey?1:0, e.shiftKey?1:0, e.ctrlKey?1:0); + e.preventDefault(); - /* Ctrl-Alt fix */ - if (!down && code == 17 && keyState[18]) { - keyState[18] = false; - this.processKey(18, keyState[18]); - } + //SAEF_log("Keyboard.handleKey() down %d, code %d, loc %d, alt %d, shift %d, ctrl %d", down?1:0, code, loc, e.ctrlKey?1:0, e.shiftKey?1:0, e.altKey?1:0, e.metaKey?1:0); - var oldstate = keyState[code]; - if (down && !keyState[code]) { - keyState[code] = true; - } - else if (!down) { - keyState[code] = false; - } - if (keyState[code] != oldstate) { - this.processKey(code, keyState[code]); - } + var oldstate = keyState[loc][code]; + keyState[loc][code] = down ? 1 : 0; + if (keyState[loc][code] != oldstate) + processKey(loc, code, keyState[loc][code]); }; - - this.setCode = function (keycode) { - code = ~((keycode << 1) | (keycode >> 7)) & 0xff; - }; - - this.keyReq = function () { - this.lostsynccnt = 8 * AMIGA.playfield.maxvpos * 8; - /* 8 frames * 8 bits */ - - //AMIGA.cia.setICR(CIA_A, 8, code); - AMIGA.cia.SetICRA(8, code); - }; - - this.hsync = function () { - if ((this.keysAvail() || state < 3) && !this.lostsynccnt && ((++hsynccnt) & 15) == 0) { - switch (state) { - case 0: - code = 0; - state++; - break; - case 1: - this.setCode(RAWKEY_INIT_POWER_UP); - state++; - break; - case 2: - this.setCode(RAWKEY_TERM_POWER_UP); - state++; - break; - case 3: - code = ~this.nextKey() & 0xff; - break; - } - this.keyReq(); - } - }; - - this.vsync = function() { - if (this.lostsynccnt > 0) { - this.lostsynccnt -= AMIGA.playfield.maxvpos; - if (this.lostsynccnt <= 0) { - this.lostsynccnt = 0; - this.keyReq(); - //BUG.info('Keyboard() lost sync'); - } - } - } } -function Input() { - this.mouse = new Mouse(); +function SAEO_Input() { + this.mouse = new SAEO_Mouse(); this.joystick = new Array(2); - this.joystick[0] = new Joystick(SAEV_Config_Ports_Type_Joy0); - this.joystick[1] = new Joystick(SAEV_Config_Ports_Type_Joy1); - this.keyboard = new Keyboard(); + this.joystick[0] = new SAEO_Joystick(SAEC_Config_Ports_Type_Joy0); + this.joystick[1] = new SAEO_Joystick(SAEC_Config_Ports_Type_Joy1); + this.keyboard = new SAEO_Keyboard(); var potgo = { data: 0, @@ -818,7 +758,7 @@ function Input() { this.setup = function () { this.keyboard.setup(); }; - + this.cleanup = function () { this.keyboard.cleanup(); }; @@ -833,7 +773,7 @@ function Input() { }; this.POTGO = function (v) { - //BUG.info('Input.POTGO() $%04x', v); + //SAEF_log("Input.POTGO() $%04x", v); potgo.data = v; }; @@ -841,40 +781,40 @@ function Input() { var v = (potgo.data | (potgo.data << 1)) & 0xaa00; v |= v >> 1; - if (AMIGA.config.ports[0].type == SAEV_Config_Ports_Type_Mouse) { + if (SAEV_config.ports[0].type == SAEC_Config_Ports_Type_Mouse) { if (this.mouse.button[2]) v &= 0xfbff; if (this.mouse.button[1]) v &= 0xfeff; - } else if (AMIGA.config.ports[0].type == SAEV_Config_Ports_Type_Joy0) { + } else if (SAEV_config.ports[0].type == SAEC_Config_Ports_Type_Joy0) { if (this.joystick[0].button[1]) v &= 0xfbff; if (this.joystick[0].button[2]) v &= 0xfeff; } - if (AMIGA.config.ports[1].type == SAEV_Config_Ports_Type_Joy1) { + if (SAEV_config.ports[1].type == SAEC_Config_Ports_Type_Joy1) { if (this.joystick[1].button[1]) v &= 0xbfff; if (this.joystick[1].button[2]) v &= 0xefff; } - //BUG.info('Input.POTGOR() $%04x', v); + //SAEF_log("Input.POTGOR() $%04x", v); return v; }; this.POT0DAT = function () { - if (AMIGA.config.ports[0].type == SAEV_Config_Ports_Type_Mouse) { + if (SAEV_config.ports[0].type == SAEC_Config_Ports_Type_Mouse) { if (this.mouse.button[2]) potgo.count = (potgo.count & 0xff00) | ((potgo.count + 1) & 0xff); if (this.mouse.button[1]) potgo.count = (potgo.count + 0x100) & 0xffff; } - //BUG.info('Input.POT0DAT() $%04x', v); + //SAEF_log("Input.POT0DAT() $%04x", v); return potgo.count; }; this.POT1DAT = function () { - //BUG.info('Input.POT1DAT() NOT IMPLEMENTED'); + //SAEF_log("Input.POT1DAT() NOT IMPLEMENTED"); return 0xffff; }; this.JOY0DAT = function () { - if (AMIGA.config.ports[0].type == SAEV_Config_Ports_Type_Mouse) { + if (SAEV_config.ports[0].type == SAEC_Config_Ports_Type_Mouse) { this.mouse.update(); return this.mouse.pos; - } else if (AMIGA.config.ports[0].type == SAEV_Config_Ports_Type_Joy0) { + } else if (SAEV_config.ports[0].type == SAEC_Config_Ports_Type_Joy0) { this.joystick[0].update(); return this.joystick[0].dir; } @@ -882,10 +822,10 @@ function Input() { }; this.JOY1DAT = function () { - if (AMIGA.config.ports[1].type == SAEV_Config_Ports_Type_Mouse) { + if (SAEV_config.ports[1].type == SAEC_Config_Ports_Type_Mouse) { this.mouse.update(); return this.mouse.pos; - } else if (AMIGA.config.ports[1].type == SAEV_Config_Ports_Type_Joy1) { + } else if (SAEV_config.ports[1].type == SAEC_Config_Ports_Type_Joy1) { this.joystick[1].update(); return this.joystick[1].dir; } @@ -893,7 +833,7 @@ function Input() { }; this.JOYTEST = function (v) { - //BUG.info('Input.JOYTEST() $%04x', v); + //SAEF_log("Input.JOYTEST() $%04x", v); } } diff --git a/sae/m68k.js b/sae/m68k.js new file mode 100644 index 0000000..127b163 --- /dev/null +++ b/sae/m68k.js @@ -0,0 +1,519 @@ +/*------------------------------------------------------------------------- +| SAE - Scripted Amiga Emulator +| https://github.com/naTmeg/ScriptedAmigaEmulator +| +| Copyright (C) 2012-2016 Rupert Hausberger +| +| This program is free software; you can redistribute it and/or +| modify it under the terms of the GNU General Public License +| as published by the Free Software Foundation; either version 2 +| of the License, or (at your option) any later version. +| +| This program is distributed in the hope that it will be useful, +| but WITHOUT ANY WARRANTY; without even the implied warranty of +| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +| GNU General Public License for more details. +| +| Notes: +| This file consists of two parts: high-level functions, which are ported +| from WinUAE 3.2.x and low-level functions, written from scratch. +-------------------------------------------------------------------------*/ +/* global constants */ + +//const SAEC_CPU_halt_PPC_ONLY = -1; + const SAEC_CPU_halt_BUS_ERROR_DOUBLE_FAULT = 1; + const SAEC_CPU_halt_DOUBLE_FAULT = 2; + const SAEC_CPU_halt_OPCODE_FETCH_FROM_NON_EXISTING_ADDRESS = 3; +//const SAEC_CPU_halt_ACCELERATOR_CPU_FALLBACK = 4; +//const SAEC_CPU_halt_ALL_CPUS_STOPPED = 5; +//const SAEC_CPU_halt_FAKE_DMA = 6; + const SAEC_CPU_halt_AUTOCONFIG_CONFLICT = 7; +//const SAEC_CPU_halt_PCI_CONFLICT = 8; +//const SAEC_CPU_halt_CPU_STUCK = 9; + +/*---------------------------------*/ +/* global references */ + +/*---------------------------------*/ +/* global variables */ + +/*---------------------------------*/ + +function SAEO_M68K() { + var reset_delay = false; + this.halted = 0; + this.stopped = false; + + var haltloop_prevvpos = false; + var prevtime = false; + + /*-----------------------------------------------------------------------*/ + + this.setup = function() { //init_m68k() + return SAER.cpu.setup(); + } + + function m68k_reset(hardreset) { //m68k_reset2 + SAEV_spcflags = 0; + SAEF_setSpcFlags(SAEC_spcflag_CHECK); + + this.halted = 0; + haltloop_prevvpos = false; + SAER.gui.data.cpu_halted = 0; + SAER.gui.led(SAEC_GUI_LED_CPU, 0, -1); + + reset_delay = false; + prevtime = false; + + SAER.cpu.reset(hardreset); + //SAER.cpu.diss(regs.pc, 16); + } + + this.dump = function() { + //var out = ""; + SAER.cpu.dump(); + //SAEF_log(out); + } + + /*-----------------------------------------------------------------------*/ + + this.cpureset = function() { + /* RESET hasn"t increased PC yet, 1 word offset */ + var ksboot = 0xf80002 - 2; + + reset_delay = SAEV_config.cpu.resetDelay; + SAEF_setSpcFlags(SAEC_spcflag_CHECK); + //send_internalevent(INTERNALEVENT_CPURESET); + if (SAEV_config.cpu.compatible && SAEV_config.cpu.model <= SAEC_Config_CPU_Model_68020) { + SAER.playfield.custom_reset(false, false); + return; + } + var pc = SAER_CPU_getPC() + 2; + var bank = SAER_Memory_getBank(pc); + if (bank.check(pc, 2)) { + SAEF_log("cpu.cpureset() PC=%x (%s)...", pc - 2, bank.name); + var ins = SAER_Memory_get16(pc); + SAER.playfield.custom_reset(false, false); + // did memory disappear under us? + if (bank === SAER_Memory_getBank(pc)) + return; + // it did + if ((ins & ~7) == 0x4ed0) { + var addr = SAER_CPU_regs.a[ins & 7]; + if (addr < 0x80000) + addr += 0xf80000; + SAEF_log("cpu.cpureset() reset/jmp combination at %08x emulated -> %x", pc, addr); + SAER.cpu.setPC_normal(addr - 2); + return; + } + } + SAEF_log("cpu.cpureset() PC=%x (%s), invalid memory -> %x.", pc, bank.name, ksboot + 2); + SAER.playfield.custom_reset(false, false); + SAER.cpu.setPC_normal(ksboot); + } + + /*-----------------------------------------------------------------------*/ + + this.cpu_halt = function(id) { + // id < 0: m68k halted, PPC active. + // id > 0: emulation halted. + if (!this.halted) { + SAEF_log("CPU halted: reason = %d PC=%08x", id, SAER_CPU_getPC()); + this.halted = id; + SAER.gui.data.cpu_halted = id; + SAER.gui.led(SAEC_GUI_LED_CPU, 0, -1); + if (id >= 0) { + SAER_CPU_regs.intmask = 7; + SAER_Audio_deactivate(); + } + SAEF_setSpcFlags(SAEC_spcflag_CHECK); + } + } + + function haltloop() { + while (SAER.m68k.halted) { + //SAEF_log("cpu.haltloop()"); + var vpos = SAER.playfield.get_vpos(); + if (vpos == 0 && haltloop_prevvpos) { + haltloop_prevvpos = false; + SAEF_sleep(8); + } + if (vpos) + haltloop_prevvpos = true; + + SAER.events.do_cycles(8 * SAEC_Events_CYCLE_UNIT); + + if (SAEV_spcflags & SAEC_spcflag_COPPER) + SAER.copper.cycle(); + + if (SAEV_spcflags) { + if ((SAEV_spcflags & (SAEC_spcflag_BRK | SAEC_spcflag_MODE_CHANGE))) + return true; + } + } + return false; + } + + /*-----------------------------------------------------------------------*/ + + var cpu_keyboardreset = false; + var cpu_hardreset = true; + + this.is_keyboardreset = function() { + return cpu_keyboardreset; + } + this.is_hardreset = function() { + return cpu_hardreset; + } + + this.m68k_pause = function() { + if (SAEV_command == SAEC_command_Pause) { + SAEV_command = 0; + if (!SAER.paused) { + SAEF_log("->pause"); + SAER.paused = true; + SAER.pause_program(1); + } + } + else if (SAEV_command == SAEC_command_Resume) { + SAEV_command = 0; + if (SAER.paused) { + SAEF_log("->resume"); + SAER.pause_program(0); + SAER.paused = false; + prevtime = false; + } + } + else if (SAEV_command == -SAEC_command_Quit || + SAEV_command == -SAEC_command_Reset || + SAEV_command == -SAEC_command_KeyboardReset || + SAEV_command == -SAEC_command_HardReset + ) { + SAEF_log("->stop"); + SAER.paused = false; + } + + if (SAER.paused) + setTimeout(function() { SAER.m68k.m68k_pause(); }, 500); + else + setTimeout(function() { SAER.m68k.m68k_cycle(0, 0); }, 0); + } + + this.m68k_cycle = function(hardboot, startup) { + try { + if (SAEV_command > 0) { + cpu_keyboardreset = SAEV_command == SAEC_command_KeyboardReset; + cpu_hardreset = ((SAEV_command == SAEC_command_HardReset ? 1 : 0) | hardboot) != 0; + + if (SAEV_command == SAEC_command_Quit) { + this.m68k_gone(); + return; + } + else if (SAEV_command == SAEC_command_Pause) { + this.m68k_pause(); + return; + } + + SAEV_command = 0; + hardboot = 0; + + SAEV_Events_hsync_counter = 0; + SAEV_Events_vsync_counter = 0; + SAEV_Events_currcycle = 0; SAER_Events_eventtab[SAEC_Events_EV_HSYNC].oldcycles = 0; + + SAER.playfield.custom_reset(cpu_hardreset, cpu_keyboardreset); + m68k_reset(cpu_hardreset); + if (cpu_hardreset) { + SAER.memory.clear(); + SAEF_log("m68k.m68k_cycle() hardreset, memory cleared."); + } + cpu_hardreset = false; + + if (SAEV_config.audio.mode == 0) + SAER_Events_eventtab[SAEC_Events_EV_AUDIO].active = false; + + SAER.cpu.setPC_normal(SAER_CPU_regs.pc); + + //SAER.audio.check_prefs_changed_audio(); + + //statusline_clear(); + } + + if (startup) { + SAER.playfield.custom_prepare(); + //protect_roms(true); + startup = 0; + } + SAEF_clrSpcFlags(SAEC_spcflag_MODE_CHANGE); + + if (this.halted) { + this.cpu_halt(this.halted); + /*if (this.halted < 0) { + haltloop(); + //continue; + setTimeout(function() { SAER.m68k.m68k_cycle(hardboot, startup); }, 0); + return; + }*/ + } + + if (prevtime !== false) // && SAEV_config.cpu.speed >= 0) + SAEV_Events_reflowtime = SAEF_now() - prevtime; + + SAER_CPU_run_func(); + + //if (SAEV_config.cpu.speed >= 0) + prevtime = SAEF_now(); + + setTimeout(function() { SAER.m68k.m68k_cycle(hardboot, startup); }, 0); + } catch(e) { + this.m68k_gone(); + if (e instanceof SAEO_Error) { + if (typeof SAEV_config.hook.log.error === "function") + SAEV_config.hook.log.error(e.err, e.msg); + else + alert(e.msg); + } else + throw e; + } + } + this.m68k_go = function(may_quit) { + var hardboot = 1; + var startup = 1; + + //SAEF_info("m68k.m68k_go()"); + SAER.events.reset_frame_rate_hack(); + + SAER.running = true; + //this.m68k_cycle(1, 1); + setTimeout(function() { SAER.m68k.m68k_cycle(hardboot, startup); }, 0); + } + this.m68k_gone = function() { + //SAEF_info("m68k.m68k_gone()"); + //protect_roms(false); + SAER.running = false; + + SAER.leave_program(); + } + + /*-----------------------------------------------------------------------*/ + + this.m68k_setstopped = function() { + this.stopped = true; + /* A traced STOP instruction drops through immediately without actually stopping. */ + if ((SAEV_spcflags & SAEC_spcflag_DOTRACE) == 0) + SAEF_setSpcFlags(SAEC_spcflag_STOP); + else + this.m68k_resumestopped(); + } + + this.m68k_resumestopped = function() { + if (this.stopped) { + this.stopped = false; + SAER_CPU_fill_prefetch(); + SAEF_clrSpcFlags(SAEC_spcflag_STOP); + } + } + + /*-----------------------------------------------------------------------*/ + + this.doint = function() { + if (SAEV_config.cpu.compatible && SAEV_config.cpu.model < SAEC_Config_CPU_Model_68020) + SAEF_setSpcFlags(SAEC_spcflag_INT); + else + SAEF_setSpcFlags(SAEC_spcflag_DOINT); + } + + this.doint_trace = function(t) { //OWN cpu.setSR() + //this.doint(); + if (SAEV_config.cpu.compatible && SAEV_config.cpu.model < SAEC_Config_CPU_Model_68020) + SAEF_setSpcFlags(SAEC_spcflag_INT); + else + SAEF_setSpcFlags(SAEC_spcflag_DOINT); + if (t) + SAEF_setSpcFlags(SAEC_spcflag_TRACE); + else + SAEF_clrSpcFlags(SAEC_spcflag_TRACE); + } + + /*-----------------------------------------------------------------------*/ + + function do_interrupt(nr) { + this.stopped = false; + SAEF_clrSpcFlags (SAEC_spcflag_STOP); + SAEF_assert(nr < 8 && nr >= 0); + + for (;;) { + SAER_CPU_exception(nr + 24); + SAER_CPU_regs.intmask = nr; + if (!SAEV_config.cpu.compatible) + break; + + nr = SAER.custom.intlev(); + if (nr <= 0 || SAER_CPU_regs.intmask >= nr) + break; + } + + SAER.m68k.doint(); + } + /*this.NMI = function() { + do_interrupt(7); + }*/ + + //static uaecptr last_trace_ad = 0; + function do_trace() { + if (SAER_CPU_regs.t0 && SAEV_config.cpu.model >= SAEC_Config_CPU_Model_68020) { + /* should also include TRAP, CHK, SR modification FPcc */ + /* probably never used so why bother */ + /* We can afford this to be inefficient... */ + SAER.cpu.setPC_normal(SAER_CPU_getPC()); + SAER_CPU_fill_prefetch(); + var opcode = SAER_Memory_get16(SAER_CPU_regs.pc); + if (opcode == 0x4e73 /* RTE */ + || opcode == 0x4e74 /* RTD */ + || opcode == 0x4e75 /* RTS */ + || opcode == 0x4e77 /* RTR */ + || opcode == 0x4e76 /* TRAPV */ + || (opcode & 0xffc0) == 0x4e80 /* JSR */ + || (opcode & 0xffc0) == 0x4ec0 /* JMP */ + || (opcode & 0xff00) == 0x6100 /* BSR */ + || ((opcode & 0xf000) == 0x6000 && ccTab[(opcode >> 8) & 0xf]()) /* Bcc */ + || ((opcode & 0xf0f0) == 0x5050 && !ccTab[(opcode >> 8) & 0xf]() && SAER_CPU_regs.d[opcode & 7] & 0xffff != 0) /* DBcc */ + ) { + //last_trace_ad = SAER_CPU_getPC(); + SAEF_clrSpcFlags(SAEC_spcflag_TRACE); + SAEF_setSpcFlags(SAEC_spcflag_DOTRACE); + } + } else if (SAER_CPU_regs.t1) { + //last_trace_ad = SAER_CPU_getPC(); + SAEF_clrSpcFlags(SAEC_spcflag_TRACE); + SAEF_setSpcFlags(SAEC_spcflag_DOTRACE); + } + } + + this.do_specialties = function(cycles) { + if (SAEV_spcflags & SAEC_spcflag_MODE_CHANGE) + return true; + + if (SAEV_spcflags & SAEC_spcflag_CHECK) { + if (this.halted) { + SAEF_clrSpcFlags(SAEC_spcflag_CHECK); + if (haltloop()) + return true; + } + if (reset_delay) { + var vsynccnt = 60; + var vsyncstate = -1; + while (vsynccnt > 0 && SAEV_command == 0) { + SAER.events.do_cycles(8 * SAEC_Events_CYCLE_UNIT); + if (SAEV_spcflags & SAEC_spcflag_COPPER) + SAER.copper.cycle(); + if (SAEV_Events_timeframes != vsyncstate) { + vsyncstate = SAEV_Events_timeframes; + vsynccnt--; + } + } + reset_delay = false; + } + SAEF_clrSpcFlags(SAEC_spcflag_CHECK); + } + + /*#ifdef ACTION_REPLAY + #ifdef ACTION_REPLAY_HRTMON + if ((SAEV_spcflags & SAEC_spcflag_ACTION_REPLAY) && hrtmon_flag != ACTION_REPLAY_INACTIVE) { + int isinhrt = (SAER_CPU_getPC() >= hrtmem_start && SAER_CPU_getPC() < hrtmem_start + hrtmem_size); + if (hrtmon_flag == ACTION_REPLAY_ACTIVE && !isinhrt) + hrtmon_hide (); + if (hrtmon_flag == ACTION_REPLAY_IDLE && isinhrt) + hrtmon_breakenter (); + if (hrtmon_flag == ACTION_REPLAY_ACTIVATE) + hrtmon_enter (); + } + #endif + if ((SAEV_spcflags & SAEC_spcflag_ACTION_REPLAY) && action_replay_flag != ACTION_REPLAY_INACTIVE) { + if (action_replay_flag == ACTION_REPLAY_ACTIVE && !is_ar_pc_in_rom ()) + SAEF_log("PC:%p", SAER_CPU_getPC()); + if (action_replay_flag == ACTION_REPLAY_ACTIVATE || action_replay_flag == ACTION_REPLAY_DORESET) + action_replay_enter (); + if ((action_replay_flag == ACTION_REPLAY_HIDE || action_replay_flag == ACTION_REPLAY_ACTIVE) && !is_ar_pc_in_rom ()) { + action_replay_hide (); + SAEF_clrSpcFlags (SAEC_spcflag_ACTION_REPLAY); + } + if (action_replay_flag == ACTION_REPLAY_WAIT_PC) { + SAEF_log("Waiting for PC: %p, current PC= %p", wait_for_pc, SAER_CPU_getPC()); + if (SAER_CPU_getPC() == wait_for_pc) { + action_replay_flag = ACTION_REPLAY_ACTIVATE; + } + } + } + #endif*/ + + if (SAEV_spcflags & SAEC_spcflag_COPPER) + SAER.copper.cycle(); + + while ((SAEV_spcflags & SAEC_spcflag_BLTNASTY) && SAEF_Custom_dmaen(SAEC_Custom_DMAF_BLTEN) && cycles > 0 && !SAEV_config.chipset.blitter.cycle_exact) { + var c = SAER.blitter.blitnasty(); + if (c < 0) + break; + else if (c > 0) { + cycles -= c * SAEC_Events_CYCLE_UNIT * 2; + if (cycles < SAEC_Events_CYCLE_UNIT) + cycles = 0; + } else + c = 4; + + SAER.events.do_cycles(c * SAEC_Events_CYCLE_UNIT); + if (SAEV_spcflags & SAEC_spcflag_COPPER) + SAER.copper.cycle(); + } + + if (SAEV_spcflags & SAEC_spcflag_DOTRACE) + SAER_CPU_exception(9); + + /*if (SAEV_spcflags & SAEC_spcflag_TRAP) { + SAEF_clrSpcFlags(SAEC_spcflag_TRAP); + SAER_CPU_exception(3); + }*/ + var first = true; + while ((SAEV_spcflags & SAEC_spcflag_STOP) && !(SAEV_spcflags & SAEC_spcflag_BRK)) { + if (!first) SAER.events.do_cycles(4 * SAEC_Events_CYCLE_UNIT); + first = false; + + if (SAEV_spcflags & SAEC_spcflag_COPPER) + SAER.copper.cycle(); + + if (SAEV_spcflags & (SAEC_spcflag_INT | SAEC_spcflag_DOINT)) { + var intr = SAER.custom.intlev(); + SAEF_clrSpcFlags(SAEC_spcflag_INT | SAEC_spcflag_DOINT); + + if (intr > 0 && intr > SAER_CPU_regs.intmask) + do_interrupt(intr); + } + + if (SAEV_spcflags & SAEC_spcflag_MODE_CHANGE) { + this.m68k_resumestopped(); + return true; + } + } + + if (SAEV_spcflags & SAEC_spcflag_TRACE) + do_trace(); + + if (SAEV_spcflags & SAEC_spcflag_INT) { + var intr = SAER.custom.intlev(); + SAEF_clrSpcFlags(SAEC_spcflag_INT | SAEC_spcflag_DOINT); + if (intr > 0 && (intr > SAER_CPU_regs.intmask || intr == 7)) + do_interrupt(intr); + } + if (SAEV_spcflags & SAEC_spcflag_DOINT) { + SAEF_clrSpcFlags(SAEC_spcflag_DOINT); + SAEF_setSpcFlags(SAEC_spcflag_INT); + } + + if (SAEV_spcflags & SAEC_spcflag_BRK) { + SAEF_clrSpcFlags(SAEC_spcflag_BRK); + return true; //OWN + } + + return false; + } +} diff --git a/sae/memory.js b/sae/memory.js index 58b40c1..81bba22 100644 --- a/sae/memory.js +++ b/sae/memory.js @@ -1,655 +1,2828 @@ -/************************************************************************** -* SAE - Scripted Amiga Emulator -* -* 2012-2015 Rupert Hausberger -* -* https://github.com/naTmeg/ScriptedAmigaEmulator -* -**************************************************************************/ -/* -0x0000 0000 2024.0 Chip RAM -0x00C0 0000 1536.0 Slow RAM +/*------------------------------------------------------------------------- +| SAE - Scripted Amiga Emulator +| https://github.com/naTmeg/ScriptedAmigaEmulator +| +| Copyright (C) 2012-2016 Rupert Hausberger +| +| This program is free software; you can redistribute it and/or +| modify it under the terms of the GNU General Public License +| as published by the Free Software Foundation; either version 2 +| of the License, or (at your option) any later version. +| +| This program is distributed in the hope that it will be useful, +| but WITHOUT ANY WARRANTY; without even the implied warranty of +| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +| GNU General Public License for more details. +| +| Note: ported from WinUAE 3.2.x +-------------------------------------------------------------------------*/ +/* global constants */ -0x00F8 0000 256.0 256K System ROM (Kickstart 2.04 or higher) -0x00FC 0000 256.0 256K System ROM +//ORG ABFLAG_* +const SAEC_Memory_addrbank_flag_UNK = 0; +const SAEC_Memory_addrbank_flag_RAM = 1; +const SAEC_Memory_addrbank_flag_ROM = 2; +const SAEC_Memory_addrbank_flag_ROMIN = 4; +const SAEC_Memory_addrbank_flag_IO = 8; +const SAEC_Memory_addrbank_flag_NONE = 16; +const SAEC_Memory_addrbank_flag_SAFE = 32; +//const SAEC_Memory_addrbank_flag_INDIRECT = 64; +const SAEC_Memory_addrbank_flag_NOALLOC = 128; +//const SAEC_Memory_addrbank_flag_RTG = 256; +const SAEC_Memory_addrbank_flag_THREADSAFE = 512; +//const SAEC_Memory_addrbank_flag_DIRECTMAP = 1024; +const SAEC_Memory_addrbank_flag_ALLOCINDIRECT = 2048; +const SAEC_Memory_addrbank_flag_CHIPRAM = 4096; +const SAEC_Memory_addrbank_flag_CIA = 8192; +const SAEC_Memory_addrbank_flag_PPCIOSPACE = 16384; -0x00DF F000 4.0 Custom chip registers -0x00BF D000 3.8 8520-B (even-byte addresses) -0x00BF E001 3.8 8520-A (odd-byte addresses) -0x00DC 0000 64.0 Real time clock +const SAEC_Memory_addrbank_READ = 1; +const SAEC_Memory_addrbank_WRITE = 2; -0x00F0 0000 512.0 Reserved 512K System ROM (CDTV or CD³²) -0x00E0 0000 512.0 Reserved -0x00A0 0000 1984.0 Reserved -0x00D8 0000 256.0 Reserved -0x00DD 0000 188.0 Reserved -0x0020 0000 8192.0 Primary auto-config space (Fast RAM) -0x00E8 0000 64.0 Zorro II auto-config space (before relocation) -0x00E9 0000 448.0 Secondary auto-config space (usually 64K I/O boards) -*/ +const SAEC_Memory_banktype_FAST32 = 0; //CE_MEMBANK_FAST32 +const SAEC_Memory_banktype_CHIP16 = 1; //CE_MEMBANK_CHIP16 +const SAEC_Memory_banktype_CHIP32 = 2; //CE_MEMBANK_CHIP32 +const SAEC_Memory_banktype_CIA = 3; //CE_MEMBANK_CIA +const SAEC_Memory_banktype_FAST16 = 4; //CE_MEMBANK_FAST16 -function Memory() { - const NULL8 = 0xff; - const NULL16 = 0xffff; - const NULL32 = 0xffffffff; +/*---------------------------------*/ +/* global references */ - this.chip = { - size: 0, - align: 0, - data: null, - lower: 0, - upper: 0 - }; - this.slow = { - enabled: false, - size: 0, - align: 0, - data: null, - lower: 0x00C00000, - upper: 0 - }; - this.fast = { - enabled: false, - size: 0, - align: 0, - data: null, - lower: 0x00200000, - upper: 0 - }; - this.rom = { - size: 0, - align: 0, - data: null, - lower: 0xf80000, - upper: 0x1000000 - }; - this.res_d8 = { - size: 0x40000, - align: 0x20000, - data: null, - lower: 0x00D80000, - upper: 0x00DC0000 - }; - this.res_e0 = { - size: 0x80000, - align: 0x40000, - data: null, - lower: 0x00E00000, - upper: 0x00E80000 - }; - this.res_f0 = { - size: 0x80000, - align: 0x40000, - data: null, - lower: 0x00F00000, - upper: 0x00F80000 - }; - this.ac_z2 = { - size: 0x10000, - lower: 0x00E80000, - upper: 0x00E90000 - }; - /*this.aros = { - cached: false, - rom: '', - ext: '' - };*/ - - function getChipSize(v) { - switch (v) { - case SAEV_Config_RAM_Chip_Size_256K: return 256 << 10; - case SAEV_Config_RAM_Chip_Size_512K: return 512 << 10; - case SAEV_Config_RAM_Chip_Size_1M: return 1024 << 10; - case SAEV_Config_RAM_Chip_Size_2M: return 2048 << 10; - default: return false; - } - } - - function getSlowSize(v) { - switch (v) { - case SAEV_Config_RAM_Slow_Size_None: return 0; - case SAEV_Config_RAM_Slow_Size_256K: return 256 << 10; - case SAEV_Config_RAM_Slow_Size_512K: return 512 << 10; - case SAEV_Config_RAM_Slow_Size_1M: return 1024 << 10; - case SAEV_Config_RAM_Slow_Size_1536K: return 1536 << 10; - default: return false; - } - } - - function getFastSize(v) { - switch (v) { - case SAEV_Config_RAM_Fast_Size_None: return 0; - case SAEV_Config_RAM_Fast_Size_512K: return 512 << 10; - case SAEV_Config_RAM_Fast_Size_1M: return 1024 << 10; - case SAEV_Config_RAM_Fast_Size_2M: return 2048 << 10; - case SAEV_Config_RAM_Fast_Size_4M: return 4096 << 10; - case SAEV_Config_RAM_Fast_Size_8M: return 8192 << 10; - default: return false; - } - } - - function getROMSize(v) { - switch (v) { - case SAEV_Config_ROM_Size_256K: return 256 << 10; - case SAEV_Config_ROM_Size_512K: return 512 << 10; - default: return false; - } - } - - /*function getEXTSize(v) { - switch (v) { - case SAEV_Config_EXT_Size_256K: return 256 << 10; - case SAEV_Config_EXT_Size_512K: return 512 << 10; - default: return false; - } - } - function getEXTAddr(v) { - switch (v) { - case SAEV_Config_EXT_Addr_A0: return 0xa00000; - case SAEV_Config_EXT_Addr_E0: return 0xe00000; - case SAEV_Config_EXT_Addr_F0: return 0xf00000; - default: return false; - } - }*/ - - this.setup = function () { - this.chip.size = getChipSize(AMIGA.config.ram.chip.size); - this.chip.align = this.chip.size >>> 1; - this.chip.data = new Uint16Array(this.chip.align); - for (var i = 0; i < this.chip.align; i++) this.chip.data[i] = 0; - this.chip.lower = 0; - this.chip.upper = this.chip.size; +var SAER_Memory_banks = null; +var SAER_Memory_banktype = null; +var SAER_Memory_cachable = null; - if (AMIGA.config.ram.slow.size) { - this.slow.enabled = true; - this.slow.size = getSlowSize(AMIGA.config.ram.slow.size); - this.slow.align = this.slow.size >>> 1; - this.slow.data = new Uint16Array(this.slow.align); - for (var i = 0; i < this.slow.align; i++) this.slow.data[i] = 0; - this.slow.upper = this.slow.lower + this.slow.size; - } else { - this.slow.enabled = false; - this.slow.size = 0; - this.slow.align = 0; - this.slow.data = null; - this.slow.upper = 0; - } - if (AMIGA.config.ram.fast.size) { - this.fast.enabled = true; - this.fast.size = getFastSize(AMIGA.config.ram.fast.size); - this.fast.align = this.fast.size >>> 1; - this.fast.data = new Uint16Array(this.fast.align); - for (var i = 0; i < this.fast.align; i++) this.fast.data[i] = 0; - this.fast.upper = this.fast.lower + this.fast.size; - } else { - this.fast.enabled = false; - this.fast.size = 0; - this.fast.align = 0; - this.fast.data = null; - this.fast.upper = 0; - } - BUG.info('Memory.init() chip %d, slow %d, fast %d', this.chip.size >>> 10, this.slow.size >>> 10, this.fast.size >>> 10); +var SAER_Memory_getBank = null; +var SAER_Memory_get8 = null; +var SAER_Memory_get16 = null; +var SAER_Memory_getInst16 = null; +var SAER_Memory_get32 = null; +var SAER_Memory_getInst32 = null; +var SAER_Memory_put8 = null; +var SAER_Memory_put16 = null; +var SAER_Memory_put32 = null; +//var SAER_Memory_xlate = null; +var SAER_Memory_check = null; /* autoconf/check_boot_rom() */ - this.rom.size = getROMSize(AMIGA.config.rom.size); - this.rom.align = this.rom.size >>> 1; - this.rom.data = new Uint16Array(this.rom.align); - for (var i = 0; i < this.rom.align; i++) this.rom.data[i] = 0; - this.res_d8.data = new Uint16Array(this.res_d8.align); - for (var i = 0; i < this.res_d8.align; i++) this.res_d8.data[i] = 0; - this.res_e0.data = new Uint16Array(this.res_e0.align); - for (var i = 0; i < this.res_e0.align; i++) this.res_e0.data[i] = 0; - this.res_f0.data = new Uint16Array(this.res_f0.align); - for (var i = 0; i < this.res_f0.align; i++) this.res_f0.data[i] = 0; +var SAER_Memory_chipData = null; - this.copy_rom(AMIGA.config.rom.data); +var SAER_Memory_chipGet8_indirect = null; +var SAER_Memory_chipGet16_indirect = null; +var SAER_Memory_chipGet32_indirect = null; +var SAER_Memory_chipPut8_indirect = null; +var SAER_Memory_chipPut16_indirect = null; +var SAER_Memory_chipPut32_indirect = null; +var SAER_Memory_chipCheck_indirect = null; +var SAER_Memory_chipXLate_indirect = null; - if (AMIGA.config.ext.size != SAEV_Config_EXT_Size_None) { - if (AMIGA.config.ext.addr == SAEV_Config_EXT_Addr_E0) - this.copy_e0(AMIGA.config.ext.data); - else if (AMIGA.config.ext.addr == SAEV_Config_EXT_Addr_F0) - this.copy_f0(AMIGA.config.ext.data); - } - //this.mirror_rom_to_chipram(); +var SAER_Memory_mapBanks = null; - /*if (AMIGA.config.rom.mode == 1) { - if (!this.aros.cached) { - BUG.info('Memory.setup() AROS-ROM is not cached, downloading...'); - AMIGA.loading += 2; - loadRemote('aros-amiga-m68k-rom.bin', 0xfc4635e1, function(data) { - AMIGA.mem.aros.cached = true; - AMIGA.mem.aros.rom = data; - AMIGA.mem.copy_rom(data); - AMIGA.loading--; - }); - loadRemote('aros-amiga-m68k-ext.bin', 0xc612f82e, function(data) { - AMIGA.mem.aros.cached = true; - AMIGA.mem.aros.ext = data; - AMIGA.mem.copy_e0(data); - AMIGA.loading--; - }); - } else { - BUG.info('Memory.setup() AROS-ROM is cached, download skipped.'); - this.copy_rom(this.aros.rom); - this.copy_e0(this.aros.ext); - } - } else { - AMIGA.loading++; - loadLocal('cfg_rom_name', function(event) { - AMIGA.mem.copy_rom(event.target.result); - AMIGA.loading--; - }); - if (AMIGA.config.ext.size > 0) { - AMIGA.loading++; - loadLocal('cfg_ext_name', function(event) { - if (AMIGA.config.ext.addr == 0xe00000) - AMIGA.mem.copy_e0(event.target.result); - else - AMIGA.mem.copy_f0(event.target.result); +/*---------------------------------*/ +/* global variables */ - AMIGA.loading--; - }); - } - }*/ - }; +//var SAEV_Memory_chipSizeReal = 0; +var SAEV_Memory_chipMask = 0; - this.load8 = function (addr) { - //BUG.info('Memory.load8() addr $%08x', addr); +var SAEV_Memory_cloantoRom = false; - if (addr >= 0x000000 && addr < this.chip.size) { - return (addr & 1) ? (this.chip.data[addr >>> 1] & 0xff) : (this.chip.data[addr >>> 1] >> 8); - } - else if (this.slow.enabled && addr >= this.slow.lower && addr < this.slow.upper) { - return (addr & 1) ? (this.slow.data[(addr - this.slow.lower) >>> 1] & 0xff) : (this.slow.data[(addr - this.slow.lower) >>> 1] >> 8); - } - else if (this.fast.enabled && addr >= this.fast.lower && addr < this.fast.upper) { - return (addr & 1) ? (this.fast.data[(addr - this.fast.lower) >>> 1] & 0xff) : (this.fast.data[(addr - this.fast.lower) >>> 1] >> 8); - } - else if (addr >= this.rom.lower && addr < this.rom.upper) { - return (addr & 1) ? (this.rom.data[(addr - this.rom.lower) >>> 1] & 0xff) : (this.rom.data[(addr - this.rom.lower) >>> 1] >> 8); - } - else if (addr >= 0xdff000 && addr < 0xe00000) { - return AMIGA.custom.load8(addr); - } - else if (addr >= 0xbfd000 && addr < 0xbfdf01) { - return AMIGA.cia.load8(addr); - } - else if (addr >= 0xbfe001 && addr < 0xbfef02) { - return AMIGA.cia.load8(addr); - } - else if (addr >= 0xdc0000 && addr < 0xdd0000) { - return AMIGA.rtc.load8(addr); - } - else if (addr >= this.res_e0.lower && addr < this.res_e0.upper) { - return (addr & 1) ? (this.res_e0.data[(addr - this.res_e0.lower) >>> 1] & 0xff) : (this.res_e0.data[(addr - this.res_e0.lower) >>> 1] >> 8); - } - else if (addr >= this.res_f0.lower && addr < this.res_f0.upper) { - return (addr & 1) ? (this.res_f0.data[(addr - this.res_f0.lower) >>> 1] & 0xff) : (this.res_f0.data[(addr - this.res_f0.lower) >>> 1] >> 8); - } - else if (addr >= this.res_d8.lower && addr < this.res_d8.upper) { - return (addr & 1) ? (this.res_d8.data[(addr - this.res_d8.lower) >>> 1] & 0xff) : (this.res_d8.data[(addr - this.res_d8.lower) >>> 1] >> 8); - } - else if (addr >= this.ac_z2.lower && addr < this.ac_z2.upper) { - return AMIGA.expansion.load8(addr); - } - //else BUG.info('Memory.load8() ILLEGAL MEMORY ACCESS addr $%08x', addr); +/*---------------------------------*/ +/* global objects */ - return NULL8; - }; +/*typedef uae_u32 (REGPARAM3 *mem_get_func)(uaecptr) REGPARAM; +typedef void (REGPARAM3 *mem_put_func)(uaecptr, uae_u32) REGPARAM; +typedef uae_u8 *(REGPARAM3 *xlate_func)(uaecptr) REGPARAM; +typedef int (REGPARAM3 *check_func)(uaecptr, uae_u32) REGPARAM;*/ - this.load16 = function (addr) { - //BUG.info('Memory.load16() addr $%08x', addr); - - if (addr >= 0 && addr < this.chip.size - 1) { - return this.chip.data[addr >>> 1]; - } - else if (this.slow.enabled && addr >= this.slow.lower && addr < this.slow.upper - 1) { - return this.slow.data[(addr - this.slow.lower) >>> 1]; - } - else if (this.fast.enabled && addr >= this.fast.lower && addr < this.fast.upper - 1) { - return this.fast.data[(addr - this.fast.lower) >>> 1]; - } - else if (addr >= this.rom.lower && addr < this.rom.upper - 1) { - return this.rom.data[(addr - this.rom.lower) >>> 1]; - } - else if (addr >= 0xdff000 && addr < 0xe00000 - 1) { - return AMIGA.custom.load16(addr); - } - else if (addr >= 0xbfd000 && addr < 0xbfdf01 - 1) { - return AMIGA.cia.load16(addr); - } - else if (addr >= 0xbfe001 && addr < 0xbfef02 - 1) { - return AMIGA.cia.load16(addr); - } - else if (addr >= 0xdc0000 && addr < 0xdd0000 - 1) { - return AMIGA.rtc.load16(addr); - } - else if (addr >= this.res_e0.lower && addr < this.res_e0.upper - 1) { - return this.res_e0.data[(addr - this.res_e0.lower) >>> 1]; - } - else if (addr >= this.res_f0.lower && addr < this.res_f0.upper - 1) { - return this.res_f0.data[(addr - this.res_f0.lower) >>> 1]; - } - else if (addr >= this.res_d8.lower && addr < this.res_d8.upper - 1) { - return this.res_d8.data[(addr - this.res_d8.lower) >>> 1]; - } - //else BUG.info('Memory.load16() ILLEGAL MEMORY ACCESS addr $%08x', addr); - - return NULL16; - }; - - this.load32 = function (addr) { - //BUG.info('Memory.load32() addr $%08x', addr); - - if (addr >= 0 && addr < this.chip.size - 3) { - addr >>>= 1; - return ((this.chip.data[addr] << 16) | this.chip.data[addr + 1]) >>> 0; - } - else if (this.slow.enabled && addr >= this.slow.lower && addr < this.slow.upper - 3) { - addr = (addr - this.slow.lower) >>> 1; - return ((this.slow.data[addr] << 16) | this.slow.data[addr + 1]) >>> 0; - } - else if (this.fast.enabled && addr >= this.fast.lower && addr < this.fast.upper - 3) { - addr = (addr - this.fast.lower) >>> 1; - return ((this.fast.data[addr] << 16) | this.fast.data[addr + 1]) >>> 0; - } - else if (addr >= this.rom.lower && addr < this.rom.upper - 3) { - addr = (addr - this.rom.lower) >>> 1; - return ((this.rom.data[addr] << 16) | this.rom.data[addr + 1]) >>> 0; - } - else if (addr >= 0xdff000 && addr < 0xe00000 - 3) { - return AMIGA.custom.load32(addr); - } - else if (addr >= 0xbfd000 && addr < 0xbfdf01 - 3) { - return AMIGA.cia.load32(addr); - } - else if (addr >= 0xbfe001 && addr < 0xbfef02 - 3) { - return AMIGA.cia.load32(addr); - } - else if (addr >= 0xdc0000 && addr < 0xdd0000 - 3) { - return AMIGA.rtc.load32(addr); - } - else if (addr >= this.res_e0.lower && addr < this.res_e0.upper - 3) { - addr = (addr - this.res_e0.lower) >>> 1; - return ((this.res_e0.data[addr] << 16) | this.res_e0.data[addr + 1]) >>> 0; - } - else if (addr >= this.res_f0.lower && addr < this.res_f0.upper - 3) { - addr = (addr - this.res_f0.lower) >>> 1; - return ((this.res_f0.data[addr] << 16) | this.res_f0.data[addr + 1]) >>> 0; - } - else if (addr >= this.res_d8.lower && addr < this.res_d8.upper - 3) { - addr = (addr - this.res_d8.lower) >>> 1; - return ((this.res_d8.data[addr] << 16) | this.res_d8.data[addr + 1]) >>> 0; - } - //else BUG.info('Memory.load32() ILLEGAL MEMORY ACCESS addr $%08x', addr); - - return NULL32; - }; - - this.store8 = function (addr, value) { - //BUG.info('Memory.store8() addr $%08x, val $%02x', addr, value); - - if (addr >= 0 && addr < this.chip.size) { - if (addr & 1) { - addr >>>= 1; - this.chip.data[addr] = (this.chip.data[addr] & 0xff00) | value; - } else { - addr >>>= 1; - this.chip.data[addr] = (value << 8) | (this.chip.data[addr] & 0x00ff); - } - } - else if (this.slow.enabled && addr >= this.slow.lower && addr < this.slow.upper) { - if (addr & 1) { - addr = (addr - this.slow.lower) >>> 1; - this.slow.data[addr] = (this.slow.data[addr] & 0xff00) | value; - } else { - addr = (addr - this.slow.lower) >>> 1; - this.slow.data[addr] = (value << 8) | (this.slow.data[addr] & 0x00ff); - } - } - else if (this.fast.enabled && addr >= this.fast.lower && addr < this.fast.upper) { - if (addr & 1) { - addr = (addr - this.fast.lower) >>> 1; - this.fast.data[addr] = (this.fast.data[addr] & 0xff00) | value; - } else { - addr = (addr - this.fast.lower) >>> 1; - this.fast.data[addr] = (value << 8) | (this.fast.data[addr] & 0x00ff); - } - } - else if (addr >= 0xdff000 && addr < 0xe00000) { - AMIGA.custom.store8(addr, value); - } - else if (addr >= 0xbfd000 && addr < 0xbfdf01) { - AMIGA.cia.store8(addr, value); - } - else if (addr >= 0xbfe001 && addr < 0xbfef02) { - AMIGA.cia.store8(addr, value); - } - else if (addr >= 0xdc0000 && addr < 0xdd0000) { - AMIGA.rtc.store8(addr, value); - } - else if (addr >= this.res_e0.lower && addr < this.res_e0.upper) { - if (addr & 1) { - addr = (addr - this.res_e0.lower) >>> 1; - this.res_e0.data[addr] = (this.res_e0.data[addr] & 0xff00) | value; - } else { - addr = (addr - this.res_e0.lower) >>> 1; - this.res_e0.data[addr] = (value << 8) | (this.res_e0.data[addr] & 0x00ff); - } - } - else if (addr >= this.res_f0.lower && addr < this.res_f0.upper) { - if (addr & 1) { - addr = (addr - this.res_f0.lower) >>> 1; - this.res_f0.data[addr] = (this.res_f0.data[addr] & 0xff00) | value; - } else { - addr = (addr - this.res_f0.lower) >>> 1; - this.res_f0.data[addr] = (value << 8) | (this.res_f0.data[addr] & 0x00ff); - } - } - else if (addr >= this.res_d8.lower && addr < this.res_d8.upper) { - if (addr & 1) { - addr = (addr - this.res_d8.lower) >>> 1; - this.res_d8.data[addr] = (this.res_d8.data[addr] & 0xff00) | value; - } else { - addr = (addr - this.res_d8.lower) >>> 1; - this.res_d8.data[addr] = (value << 8) | (this.res_d8.data[addr] & 0x00ff); - } - } - else if (addr >= this.ac_z2.lower && addr < this.ac_z2.upper) { - AMIGA.expansion.store8(addr, value); - } - //else BUG.info('Memory.store8() ILLEGAL MEMORY ACCESS addr $%08x, val %02x', addr, value); - }; - - this.store16 = function (addr, value) { - //BUG.info('Memory.store16() addr $%08x, val $%04x', addr, value); - - if (addr >= 0 && addr < this.chip.size - 1) { - this.chip.data[addr >>> 1] = value; - } - else if (this.slow.enabled && addr >= this.slow.lower && addr < this.slow.upper - 1) { - this.slow.data[(addr - this.slow.lower) >>> 1] = value; - } - else if (this.fast.enabled && addr >= this.fast.lower && addr < this.fast.upper - 1) { - this.fast.data[(addr - this.fast.lower) >>> 1] = value; - } - else if (addr >= 0xdff000 && addr < 0xe00000 - 1) { - AMIGA.custom.store16(addr, value); - } - else if (addr >= 0xbfd000 && addr < 0xbfdf01 - 1) { - AMIGA.cia.store16(addr, value); - } - else if (addr >= 0xbfe001 && addr < 0xbfef02 - 1) { - AMIGA.cia.store16(addr, value); - } - else if (addr >= 0xdc0000 && addr < 0xdd0000 - 1) { - AMIGA.rtc.store16(addr, value); - } - else if (addr >= this.res_e0.lower && addr < this.res_e0.upper - 1) { - this.res_e0.data[(addr - this.res_e0.lower) >>> 1] = value; - } - else if (addr >= this.res_f0.lower && addr < this.res_f0.upper - 1) { - this.res_f0.data[(addr - this.res_f0.lower) >>> 1] = value; - } - else if (addr >= this.res_d8.lower && addr < this.res_d8.upper - 1) { - this.res_d8.data[(addr - this.res_d8.lower) >>> 1] = value; - } - //else BUG.info('Memory.store16() ILLEGAL MEMORY ACCESS addr $%08x, val %04x', addr, value); - }; - - this.store32 = function (addr, value) { - //BUG.info('Memory.store32() addr $%08x, val $%08x', addr, value); - - if (addr >= 0 && addr < this.chip.size - 3) { - addr >>>= 1; - this.chip.data[addr] = value >>> 16; - this.chip.data[addr + 1] = value & 0xffff; - } - else if (this.slow.enabled && addr >= this.slow.lower && addr < this.slow.upper - 3) { - addr = (addr - this.slow.lower) >>> 1; - this.slow.data[addr] = value >>> 16; - this.slow.data[addr + 1] = value & 0xffff; - } - else if (this.fast.enabled && addr >= this.fast.lower && addr < this.fast.upper - 3) { - addr = (addr - this.fast.lower) >>> 1; - this.fast.data[addr] = value >>> 16; - this.fast.data[addr + 1] = value & 0xffff; - } - else if (addr >= 0xdff000 && addr < 0xe00000 - 3) { - AMIGA.custom.store32(addr, value); - } - else if (addr >= 0xbfd000 && addr < 0xbfdf01 - 3) { - AMIGA.cia.store32(addr, value); - } - else if (addr >= 0xbfe001 && addr < 0xbfef02 - 3) { - AMIGA.cia.store32(addr, value); - } - else if (addr >= 0xdc0000 && addr < 0xdd0000 - 3) { - AMIGA.rtc.store32(addr, value); - } - else if (addr >= this.res_e0.lower && addr < this.res_e0.upper - 3) { - addr = (addr - this.res_e0.lower) >>> 1; - this.res_e0.data[addr] = value >>> 16; - this.res_e0.data[addr + 1] = value & 0xffff; - } - else if (addr >= this.res_f0.lower && addr < this.res_f0.upper - 3) { - addr = (addr - this.res_f0.lower) >>> 1; - this.res_f0.data[addr] = value >>> 16; - this.res_f0.data[addr + 1] = value & 0xffff; - } - else if (addr >= this.res_d8.lower && addr < this.res_d8.upper - 3) { - addr = (addr - this.res_d8.lower) >>> 1; - this.res_d8.data[addr] = value >>> 16; - this.res_d8.data[addr + 1] = value & 0xffff; - } - //else if (!(addr & 0xc80000)) BUG.info('Memory.store32() ILLEGAL MEMORY ACCESS addr $%08x, val %08x', addr, value); - }; - - /*this.check16_chip = function (addr, size) { - return (addr >= 0 && addr + size < this.chip.size - 1); - };*/ - /*this.load16_chip = function (addr) { - if (this.check16_chip(addr, 1)) { - var v = this.chip.data[addr >>> 1]; - AMIGA.custom.last_value = v; - return v; - } else BUG.info('load16_chip() ILLEGAL MEMORY ACCESS addr %x', addr); - return 0xffff; - } - this.store16_chip = function (addr, value) { - if (this.check16_chip(addr, 1)) { - this.chip.data[addr >>> 1] = value; - AMIGA.custom.last_value = value; - } else BUG.info('store16_chip() ILLEGAL MEMORY ACCESS addr %x, value %x', addr, value); - } - this.load16_chip = function (addr) { - if (addr < this.chip.size - 1) - AMIGA.custom.last_value = this.chip.data[addr >>> 1]; - else - AMIGA.custom.last_value = 0xffff; - - return AMIGA.custom.last_value; - } - this.store16_chip = function (addr, value) { - if (addr < this.chip.size - 1) - this.chip.data[addr >>> 1] = AMIGA.custom.last_value = value; - else - AMIGA.custom.last_value = 0xffff; - }*/ - - this.copy_rom = function (data) { - //BUG.info('copyrom() size %d', data.length); - //BUG.info('copyrom() crc32 $%08x', crc32(data)); - - if (data.length == 0x80000) { - /*var lo = crc32(data.substr(0, 0x40000)); - var hi = crc32(data.substr(0x40000, 0x80000)); - if (lo != hi) { - BUG.info('copyrom() lo crc32 $%08x', lo); - BUG.info('copyrom() hi crc32 $%08x', hi); - }*/ - for (var i = 0; i < data.length; i++) { - var v = data.charCodeAt(i) & 0xff; - if (i & 1) { - var j = i >>> 1; - this.rom.data[j] = (this.rom.data[j] & 0xff00) | v; - } else { - var j = i >>> 1; - this.rom.data[j] = (v << 8) | (this.rom.data[j] & 0x00ff); - } - } - this.rom.lower = 0xf80000; - } - else if (data.length == 0x40000) { - for (var i = 0; i < data.length; i++) { - var v = data.charCodeAt(i) & 0xff; - if (i & 1) { - var j = i >>> 1; - this.rom.data[j] = (this.rom.data[j] & 0xff00) | v; - this.rom.data[0x20000 + j] = (this.rom.data[0x20000 + j] & 0xff00) | v; - } else { - var j = i >>> 1; - this.rom.data[j] = (v << 8) | (this.rom.data[j] & 0x00ff); - this.rom.data[0x20000 + j] = (v << 8) | (this.rom.data[0x20000 + j] & 0x00ff); - } - } - this.rom.lower = 0xfc0000; - } - }; - - this.copy_e0 = function (data) { - if (data.length <= 0x80000) { - for (var i = 0; i < data.length; i++) { - var v = data.charCodeAt(i) & 0xff; - if (i & 1) { - var j = i >>> 1; - this.res_e0.data[j] = (this.res_e0.data[j] & 0xff00) | v; - } else { - var j = i >>> 1; - this.res_e0.data[j] = (v << 8) | (this.res_e0.data[j] & 0x00ff); - } - } - } - }; - this.copy_f0 = function (data) { - if (data.length <= 0x80000) { - for (var i = 0; i < data.length; i++) { - var v = data.charCodeAt(i) & 0xff; - if (i & 1) { - var j = i >>> 1; - this.res_f0.data[j] = (this.res_f0.data[j] & 0xff00) | v; - } else { - var j = i >>> 1; - this.res_f0.data[j] = (v << 8) | (this.res_f0.data[j] & 0x00ff); - } - } - } - }; - - /*this.mirror_rom_to_chipram = function() { - for (var i = 0; i < this.rom.size; i++) - this.chip.data[i] = this.rom.data[i]; - }*/ +function SAEO_Memory_addrbank_sub(bank,offset) { + this.bank = bank; //addrbank * + this.offset = offset; //u32 + this.suboffset = 0; + this.mask = 0; + this.maskval = 0; +} +//function SAEO_Memory_addrbank(get32,get16,get8,put32,put16,put8, xlate,check,baseaddr,label,name, getInst32,getInst16, flags,read,write,sub_banks,mask,startmask) { +function SAEO_Memory_addrbank(get32,get16,get8,put32,put16,put8, xlate,check,baseaddr,label,name, getInst32,getInst16, flags,sub_banks,mask,startmask) { + if (typeof sub_banks == "undefined") sub_banks = null; + if (typeof mask == "undefined") mask = 0; + if (typeof startmask == "undefined") startmask = 0; + this.get32 = get32, this.get16 = get16, this.get8 = get8; //mem_get_func + this.put32 = put32, this.put16 = put16, this.put8 = put8; //mem_put_func + this.xlateaddr = xlate; //xlate_func + this.check = check; //check_func + this.baseaddr = baseaddr; //u8 * + this.label = label; + this.name = name; + this.getInst32 = getInst32, this.getInst16 = getInst16; //mem_get_func + this.flags = flags; + //this.jit_read_flag = read; + //this.jit_write_flag = write; + this.sub_banks = sub_banks; //struct addrbank_sub * + this.mask = mask; //u32 + this.startmask = startmask; + this.start = 0; + this.allocated = 0; } +/*---------------------------------*/ +/* global functions */ + +function SAEF_Memory_defaultCheck(a, b) { + return 0; +} + +var SAEV_Memory_defaultXLate_cnt = 0; +var SAEV_Memory_defaultXLate_recursive = 0; + +function SAEF_Memory_defaultXLate(addr) { + if (SAEV_Memory_defaultXLate_recursive) { + SAER.m68k.cpu_halt(SAEC_CPU_halt_OPCODE_FETCH_FROM_NON_EXISTING_ADDRESS); + return kickmem_xlate(2); + } + SAEV_Memory_defaultXLate_recursive++; + var size = SAEV_config.cpu.model >= SAEC_Config_CPU_Model_68020 ? 4 : 2; + if (SAEV_command == 0) { + /* do this only in 68010+ mode, there are some tricky A500 programs.. */ + //if ((SAEV_config.cpu.model > SAEC_Config_CPU_Model_68000 || !SAEV_config.cpu.compatible) && !currprefs.mmu_model) { + if ((SAEV_config.cpu.model > SAEC_Config_CPU_Model_68000 || !SAEV_config.cpu.compatible)) { + if (++SAEV_Memory_defaultXLate_cnt <= 5) { + SAEF_warn("memory.default_xlate() Your Amiga program just did something terribly stupid %08X PC=%08X", addr, SAER_CPU_getPC()); + + /*var txt = ""; + var a2 = addr - 32; + var a3 = SAER_CPU_getPC() - 32; + for (var i = 0; i < 10; i++) { + txt += sprintf("%08X ", i >= 5 ? a3 : a2); + for (var j = 0; j < 16; j += 2) { + txt += sprintf(" %04X", get16(i >= 5 ? a3 : a2)); + if (i >= 5) a3 += 2; else a2 += 2; + } + txt += "\n"; + } + SAEF_warn(txt);*/ + SAER.memory.map_dump(); + } + /*if (0 || (SAEV_MBRes_gary_toenb && (gary_nonrange(addr) || (size > 1 && gary_nonrange(addr + size - 1))))) + exception2(addr, false, size, regs.s ? 4 : 0); + else*/ + SAER.m68k.cpu_halt(SAEC_CPU_halt_OPCODE_FETCH_FROM_NON_EXISTING_ADDRESS); + } + } + SAEV_Memory_defaultXLate_recursive--; + return kickmem_xlate(2); /* So we don't crash. */ +} + +/*---------------------------------*/ + +const SAEC_Memory_dummyGet_NONEXISTINGDATA = 0; + +function SAEF_Memory_dummyGet32(addr) { + SAER.memory.dummylog(0, addr, 4, 0, 0); + return SAER.memory.dummyGet(addr, 4, false, SAEC_Memory_dummyGet_NONEXISTINGDATA); +} +function SAEF_Memory_dummyGetInst32(addr) { + SAER.memory.dummylog(0, addr, 4, 0, 1); + return SAER.memory.dummyGet(addr, 4, true, SAEC_Memory_dummyGet_NONEXISTINGDATA); +} +function SAEF_Memory_dummyGet16(addr) { + SAER.memory.dummylog(0, addr, 2, 0, 0); + return SAER.memory.dummyGet(addr, 2, false, SAEC_Memory_dummyGet_NONEXISTINGDATA); +} +function SAEF_Memory_dummyGetInst16(addr) { + SAER.memory.dummylog(0, addr, 2, 0, 1); + return SAER.memory.dummyGet(addr, 2, true, SAEC_Memory_dummyGet_NONEXISTINGDATA); +} +function SAEF_Memory_dummyGet8(addr) { + SAER.memory.dummylog(0, addr, 1, 0, 0); + return SAER.memory.dummyGet(addr, 1, false, SAEC_Memory_dummyGet_NONEXISTINGDATA); +} +function SAEF_Memory_dummyPut32(addr, l) { + SAER.memory.dummylog(1, addr, 4, l, 0); + SAER.memory.dummyPut(addr, 4, l); +} +function SAEF_Memory_dummyPut16(addr, w) { + SAER.memory.dummylog(1, addr, 2, w, 0); + SAER.memory.dummyPut(addr, 2, w); +} +function SAEF_Memory_dummyPut8(addr, b) { + SAER.memory.dummylog(1, addr, 1, b, 0); + SAER.memory.dummyPut(addr, 1, b); +} +function SAEF_Memory_dummyCheck(addr, size) { + return 0; +} +var SAEV_Memory_dummyBank = new SAEO_Memory_addrbank( + SAEF_Memory_dummyGet32, SAEF_Memory_dummyGet16, SAEF_Memory_dummyGet8, + SAEF_Memory_dummyPut32, SAEF_Memory_dummyPut16, SAEF_Memory_dummyPut8, + SAEF_Memory_defaultXLate, SAEF_Memory_dummyCheck, null, null, null, + SAEF_Memory_dummyGetInst32, SAEF_Memory_dummyGetInst16, + //SAEC_Memory_addrbank_flag_NONE, S_READ, S_WRITE + SAEC_Memory_addrbank_flag_NONE +); + +/*---------------------------------*/ + +function SAEF_Memory_subBankGet32(addr) { + var ptr = { value:addr }; + var ab = SAER.memory.getSubBank(ptr); + return ab.get32(ptr.value); +} +function SAEF_Memory_subBankGet16(addr) { + var ptr = { value:addr }; + var ab = SAER.memory.getSubBank(ptr); + return ab.get16(ptr.value); +} +function SAEF_Memory_subBankGet8(addr) { + var ptr = { value:addr }; + var ab = SAER.memory.getSubBank(ptr); + return ab.get8(ptr.value); +} +function SAEF_Memory_subBankPut32(addr, v) { + var ptr = { value:addr }; + var ab = SAER.memory.getSubBank(ptr); + ab.put32(ptr.value, v); +} +function SAEF_Memory_subBankPut16(addr, v) { + var ptr = { value:addr }; + var ab = SAER.memory.getSubBank(ptr); + ab.put16(ptr.value, v); +} +function SAEF_Memory_subBankPut8(addr, v) { + var ptr = { value:addr }; + var ab = SAER.memory.getSubBank(ptr); + ab.put8(ptr.value, v); +} +function SAEF_Memory_subBankGetInst32(addr) { + var ptr = { value:addr }; + var ab = SAER.memory.getSubBank(ptr); + return ab.getInst32(ptr.value); +} +function SAEF_Memory_subBankGetInst16(addr) { + var ptr = { value:addr }; + var ab = SAER.memory.getSubBank(ptr); + return ab.getInst16(ptr.value); +} +function SAEF_Memory_subBankCheck(addr, size) { + var ptr = { value:addr }; + var ab = SAER.memory.getSubBank(ptr); + return ab.check(ptr.value, size); +} +function SAEF_Memory_subBankXLate(addr) { + var ptr = { value:addr }; + var ab = SAER.memory.getSubBank(ptr); + return ab.xlateaddr(ptr.value); +} + +/*---------------------------------*/ + +function SAEO_Memory() { + const ADDRESS_SPACE_24BIT = false; /* limit address-bus to 24bit */ + const MEMORY_BANKS = ADDRESS_SPACE_24BIT ? 256 : 65536; + const MEMORY_RANGE_MASK = ADDRESS_SPACE_24BIT ? 0x00FFFFFF : 0xFFFFFFFF; + + //const S_READ = 1; + //const S_WRITE = 2; + + //const FLASHEMU = 0; + + const ROM_SIZE_512 = 524288; + const ROM_SIZE_256 = 262144; + const ROM_SIZE_128 = 131072; + + const chipmem_start_addr = 0x00000000; + const bogomem_start_addr = 0x00C00000; + const cardmem_start_addr = 0x00E00000; + const kickmem_start_addr = 0x00F80000; + + var kickstart_version = 0; + //var kickstart_rom = false; //68060 + //var cloanto_rom = false; -> SAEV_Memory_cloantoRom + + var rom_write_enabled = false; + var mem_hardreset = 0; + var bogomem_aliasing = 0; + var bogomem_aliasing_offset = 0; //OWN + //var need_hardreset = false; //unused in whole source + //var lastAaddressSpace24 = false; + + var mem_banks = new Array(MEMORY_BANKS); //addrbank *mem_banks[MEMORY_BANKS]; + for (var vi = 0; vi < MEMORY_BANKS; vi++) mem_banks[vi] = null; + SAER_Memory_banks = mem_banks; + + var ce_banktype = new Uint8Array(65536); SAER_Memory_banktype = ce_banktype; + var ce_cachable = new Uint8Array(65536); SAER_Memory_cachable = ce_cachable; + + /* This has two functions. It either holds a host address that, when added + to the 68k address, gives the host address corresponding to that 68k + address (in which case the value in this array is even), OR it holds the + same value as mem_banks, for those banks that have baseaddr==0. In that + case, bit 0 is set (the memory access routines will take care of it). + + var baseaddr = new Uint32Array(MEMORY_BANKS); //u8 *baseaddr[MEMORY_BANKS];*/ + + var aros = true; //OWN + + /*-----------------------------------------------------------------------*/ + + function get_mem_bank(addr) { return mem_banks[addr >>> 16]; } + SAER_Memory_getBank = get_mem_bank; + + function get32(addr) { return mem_banks[addr >>> 16].get32(addr); } //get_long() + function getInst32(addr) { return mem_banks[addr >>> 16].getInst32(addr); } //get_longi() + function get16(addr) { return mem_banks[addr >>> 16].get16(addr); } //get_word() + function getInst16(addr) { return mem_banks[addr >>> 16].getInst16(addr); } //get_wordi() + function get8(addr) { return mem_banks[addr >>> 16].get8(addr); } //get_byte() + function put32(addr, l) { mem_banks[addr >>> 16].put32(addr, l); } //put_long() + function put16(addr, w) { mem_banks[addr >>> 16].put16(addr, w); } //put_word() + function put8(addr, b) { mem_banks[addr >>> 16].put8(addr, b); } //put_byte() + function xlate_address(addr) { return mem_banks[addr >>> 16].xlateaddr(addr); } //get_real_address() + function check_address(addr, size) { return mem_banks[addr >>> 16].check(addr, size); } //valid_address() + + SAER_Memory_get8 = get8; + SAER_Memory_get16 = get16; + SAER_Memory_getInst16 = getInst16; + SAER_Memory_get32 = get32; + SAER_Memory_getInst32 = getInst32; + SAER_Memory_put8 = put8; + SAER_Memory_put16 = put16; + SAER_Memory_put32 = put32; + //SAER_Memory_xlate = xlate_address; + SAER_Memory_check = check_address; + + //function get_pointer(addr) { return mem_banks[addr >>> 16].get32(addr); } + //function put_pointer(addr, p) { mem_banks[addr >>> 16].put32(addr, p); } + + /*-----------------------------------------------------------------------*/ + /* BANK dummy */ + + /* A dummy bank that only contains zeros */ + const MAX_ILG = 1000; + const NONEXISTINGDATA = 0; + var dummylog_cnt = 0; + + this.dummylog = function(rw, addr, size, val, ins) { + if (!SAEV_config.memory.logIllegal) + return; + if (dummylog_cnt >= MAX_ILG && MAX_ILG > 0) + return; + /* ignore Zorro3 expansion space */ + if (addr >= 0xff000000 && addr <= 0xff000200) + return; + /* autoconfig and extended rom */ + if (addr >= 0xe00000 && addr <= 0xf7ffff) + return; + /* motherboard ram */ + if (addr >= 0x08000000 && addr <= 0x08000007) + return; + if (addr >= 0x07f00000 && addr <= 0x07f00007) + return; + if (addr >= 0x07f7fff0 && addr <= 0x07ffffff) + return; + if (MAX_ILG >= 0) + dummylog_cnt++; + + if (ins) + SAEF_log("memory.geti%s(0x%08x) illegal access (PC 0x%x)", size == 2 ? "16" : "32", addr, SAER_CPU_getPC()); + else if (rw) + SAEF_log("memory.put%s(0x%08x, 0x%x) illegal access (PC 0x%x)", size == 1 ? "8" : size == 2 ? "16" : "32", addr, val, SAER_CPU_getPC()); + else + SAEF_log("memory.get%s(0x%08x) illegal access (PC 0x%x)", size == 1 ? "8" : size == 2 ? "16" : "32", addr, SAER_CPU_getPC()); + } + + // 250ms delay + var gary_wait_cnt = 50; + function gary_wait(addr, size, write) { + /*#if 0 + var lines = 313 * 12; + while (lines-- > 0) SAER.events.do_cycles(228 * SAEC_Events_CYCLE_UNIT); //x_do_cycles + #endif*/ + + if (gary_wait_cnt > 0) { + SAEF_log("memory.gary_wait() Gary timeout: %08x %d %s PC=%08x", addr, size, write ? "W" : "R", SAER_CPU_getPC()); + gary_wait_cnt--; + } + } + function gary_nonrange(addr) { + if (SAEV_config.chipset.fatGaryRev < 0) + return false; + if (addr < 0xb80000) + return false; + if (addr >= 0xd00000 && addr < 0xdc0000) + return true; + if (addr >= 0xdd0000 && addr < 0xde0000) + return true; + if (addr >= 0xdf8000 && addr < 0xe00000) + return false; + if (addr >= 0xe80000 && addr < 0xf80000) + return false; + return true; + } + + function dummy_get_safe(addr, size, inst, defvalue) { + var v = defvalue; + if (SAEV_config.cpu.model >= SAEC_Config_CPU_Model_68040) + return v; + if (!SAEV_config.cpu.compatible) + return v; + if (SAEV_config.cpu.addressSpace24) + addr &= 0x00ffffff; + if (addr >= 0x10000000) + return v; + if ((SAEV_config.cpu.model <= SAEC_Config_CPU_Model_68010) || (SAEV_config.cpu.model == SAEC_Config_CPU_Model_68020 && (SAEV_config.chipset.mask & SAEC_Config_Chipset_Mask_AGA) != 0 && SAEV_config.cpu.addressSpace24)) { + if (size == 4) { + v = SAER_CPU_regs.db & 0xffff; + if (addr & 1) + v = ((v << 8) & 0xffff) | (v >> 8); + v = ((v << 16) | v) >>> 0; + } else if (size == 2) { + v = SAER_CPU_regs.db & 0xffff; + if (addr & 1) + v = ((v << 8) & 0xffff) | (v >> 8); + } else { + v = SAER_CPU_regs.db; + v = (addr & 1) ? (v & 0xff) : ((v >> 8) & 0xff); + } + } + return v; + } + this.dummyGet = function(addr, size, inst, defvalue) { + var v = defvalue; + /*#if FLASHEMU + if (addr >= 0xf00000 && addr < 0xf80000 && size < 2) { + if (addr < 0xf60000) return flash_read(addr); + return 8; + } + #endif*/ + if (gary_nonrange(addr) || (size > 1 && gary_nonrange(addr + size - 1))) { + if (SAEV_MBRes_gary_timeout) gary_wait(addr, size, false); + if (SAEV_MBRes_gary_toenb) SAER.cpu.exception2(addr, false, size, (SAER_CPU_regs.s ? 4 : 0) | (inst ? 0 : 1)); + return v; + } + return dummy_get_safe(addr, size, inst, defvalue); + } + + this.dummyPut = function(addr, size, val) { + /*#if FLASHEMU + if (addr >= 0xf00000 && addr < 0xf80000 && size < 2) flash_write(addr, val); + #endif*/ + if (gary_nonrange(addr) || (size > 1 && gary_nonrange(addr + size - 1))) { + if (SAEV_MBRes_gary_timeout) gary_wait(addr, size, true); + //if (SAEV_MBRes_gary_toenb && currprefs.mmu_model) SAER.cpu.exception2(addr, true, size, SAER_CPU_regs.s ? 4 : 0); + } + } + + /*-----------------------------------------------------------------------*/ + /* BANK Ones */ + + /*function none_put(addr, v) {} + function ones_get(addr) { + return 0xffffffff; + } + var ones_bank = new SAEO_Memory_addrbank( + ones_get, ones_get, ones_get, + none_put, none_put, none_put, + SAEF_Memory_defaultXLate, SAEF_Memory_defaultXLate, null, null, "Ones", + SAEF_Memory_dummyGetInst32, SAEF_Memory_dummyGetInst16, + //SAEC_Memory_addrbank_flag_NONE, S_READ, S_WRITE + SAEC_Memory_addrbank_flag_NONE + );*/ + + /*-----------------------------------------------------------------------*/ + /* BANK Sub */ + + this.getSubBank = function(ptr) { + var i, addr = ptr.value; + //var ab = get_mem_bank(addr); + var ab = mem_banks[addr >>> 16]; + var sb = ab.sub_banks; //struct addrbank_sub * + if (sb === null) + return SAEV_Memory_dummyBank; + for (i = 0; sb[i].bank !== null; i++) { + var offset = addr & 65535; + if (offset < sb[i + 1].offset) { + var mask = sb[i].mask; //u32 + var maskval = sb[i].maskval; //u32 + if ((offset & mask) >>> 0 == maskval) { + ptr.value = addr - sb[i].suboffset; + return sb[i].bank; + } + } + } + ptr.value = addr - sb[i - 1].suboffset; + return sb[i - 1].bank; + } + + /*-----------------------------------------------------------------------*/ + /* BANK Chip memory */ + + function chipmem_dummy() { + return (0xffff & ~((1 << (Math.decimalRandom() & 31)) | (1 << (Math.decimalRandom() & 31)))) >>> 0; + } + function chipmem_dummy_put8(addr, b) {} + function chipmem_dummy_put16(addr, w) {} + function chipmem_dummy_put32(addr, l) {} + function chipmem_dummy_get8(addr) { return chipmem_dummy(); } + function chipmem_dummy_get16(addr) { return chipmem_dummy(); } + function chipmem_dummy_get32(addr) { return ((chipmem_dummy() << 16) | chipmem_dummy()) >>> 0; } + + var chipmem_dummy_bank = new SAEO_Memory_addrbank( + chipmem_dummy_get32, chipmem_dummy_get16, chipmem_dummy_get8, + chipmem_dummy_put32, chipmem_dummy_put16, chipmem_dummy_put8, + SAEF_Memory_defaultXLate, SAEF_Memory_defaultXLate, null, null, "Dummy Chip memory", + SAEF_Memory_dummyGetInst32, SAEF_Memory_dummyGetInst16, + //SAEC_Memory_addrbank_flag_IO | SAEC_Memory_addrbank_flag_CHIPRAM, S_READ, S_WRITE + SAEC_Memory_addrbank_flag_IO | SAEC_Memory_addrbank_flag_CHIPRAM + ); + + /*---------------------------------*/ + + var chipmem_full_mask = 0; + var chipmem_full_size = 0; + + function chipmem_get32(addr) { + addr = (addr & chipmem_bank.mask) >>> 0; + //var m = (uae_u32 *)(chipmem_bank.baseaddr + addr); return do_get_mem_long (m); + return ((chipmem_bank.baseaddr[addr] << 24) | (chipmem_bank.baseaddr[addr+1] << 16) | (chipmem_bank.baseaddr[addr+2] << 8) | chipmem_bank.baseaddr[addr+3]) >>> 0; + } + function chipmem_get16(addr) { + addr = (addr & chipmem_bank.mask) >>> 0; + //var m = (uae_u16 *)(chipmem_bank.baseaddr + addr); return do_get_mem_word (m); + return (chipmem_bank.baseaddr[addr] << 8) | chipmem_bank.baseaddr[addr+1]; + } + function chipmem_get8(addr) { + addr = (addr & chipmem_bank.mask) >>> 0; + return chipmem_bank.baseaddr[addr]; + } + function chipmem_put32(addr, l) { + addr = (addr & chipmem_bank.mask) >>> 0; + //var m = (uae_u32 *)(chipmem_bank.baseaddr + addr); do_put_mem_long (m, l); + chipmem_bank.baseaddr[addr] = l >>> 24; + chipmem_bank.baseaddr[addr+1] = (l >>> 16) & 0xff; + chipmem_bank.baseaddr[addr+2] = (l >>> 8) & 0xff; + chipmem_bank.baseaddr[addr+3] = l & 0xff; + } + function chipmem_put16(addr, w) { + addr = (addr & chipmem_bank.mask) >>> 0; + //var m = (uae_u16 *)(chipmem_bank.baseaddr + addr); do_put_mem_word (m, w); + chipmem_bank.baseaddr[addr] = w >> 8; + chipmem_bank.baseaddr[addr+1] = w & 0xff; + } + function chipmem_put8(addr, b) { + addr = (addr & chipmem_bank.mask) >>> 0; + chipmem_bank.baseaddr[addr] = b; + } + function chipmem_check(addr, size) { + addr = (addr & chipmem_bank.mask) >>> 0; + return (addr + size) <= chipmem_full_size; + } + function chipmem_xlate(addr) { + addr = (addr & chipmem_bank.mask) >>> 0; + //return chipmem_bank.baseaddr + addr; + return addr; + } + var chipmem_bank = new SAEO_Memory_addrbank( + chipmem_get32, chipmem_get16, chipmem_get8, + chipmem_put32, chipmem_put16, chipmem_put8, + chipmem_xlate, chipmem_check, null, "chip", "Chip memory", + chipmem_get32, chipmem_get16, + //SAEC_Memory_addrbank_flag_RAM | SAEC_Memory_addrbank_flag_THREADSAFE | SAEC_Memory_addrbank_flag_CHIPRAM, 0, 0 + SAEC_Memory_addrbank_flag_RAM | SAEC_Memory_addrbank_flag_THREADSAFE | SAEC_Memory_addrbank_flag_CHIPRAM + ); + + /*---------------------------------*/ + + /*function chipmem_agnus_get32(addr) { + addr = (addr & chipmem_full_mask) >>> 0; + if (addr >= chipmem_full_size - 3) + return 0; + return ((chipmem_bank.baseaddr[addr] << 24) | (chipmem_bank.baseaddr[addr+1] << 16) | (chipmem_bank.baseaddr[addr+2] << 8) | chipmem_bank.baseaddr[addr+3]) >>> 0; + }*/ + function chipmem_agnus_get16(addr) { + addr = (addr & chipmem_full_mask) >>> 0; + if (addr >= chipmem_full_size - 1) + return 0; + return (chipmem_bank.baseaddr[addr] << 8) | chipmem_bank.baseaddr[addr+1]; + } + function chipmem_agnus_get8(addr) { + addr = (addr & chipmem_full_mask) >>> 0; + if (addr >= chipmem_full_size) + return 0; + return chipmem_bank.baseaddr[addr]; + } + /*function chipmem_agnus_put32(addr, l) { + addr = (addr & chipmem_full_mask) >>> 0; + if (addr >= chipmem_full_size - 3) + return; + chipmem_bank.baseaddr[addr] = l >>> 24; + chipmem_bank.baseaddr[addr+1] = (l >>> 16) & 0xff; + chipmem_bank.baseaddr[addr+2] = (l >>> 8) & 0xff; + chipmem_bank.baseaddr[addr+3] = l & 0xff; + }*/ + function chipmem_agnus_put16(addr, w) { + addr = (addr & chipmem_full_mask) >>> 0; + if (addr >= chipmem_full_size - 1) + return; + chipmem_bank.baseaddr[addr] = w >> 8; + chipmem_bank.baseaddr[addr+1] = w & 0xff; + } + function chipmem_agnus_put8(addr, b) { + addr = (addr & chipmem_full_mask) >>> 0; + if (addr >= chipmem_full_size) + return; + chipmem_bank.baseaddr[addr] = b; + } + + /*---------------------------------*/ + + /*function chipmem_put32_bigmem(addr, v) { mem_banks[addr >>> 16].put32(addr, v); } + function chipmem_put16_bigmem(addr, v) { mem_banks[addr >>> 16].put16(addr, v); } + function chipmem_put8_bigmem(addr, v) { mem_banks[addr >>> 16].put8(addr, v); } + function chipmem_get32_bigmem(addr) { return mem_banks[addr >>> 16].get32(addr); } + function chipmem_get16_bigmem(addr) { return mem_banks[addr >>> 16].get16(addr); } + function chipmem_get8_bigmem(addr) { return mem_banks[addr >>> 16].get8(addr); } + function chipmem_check_bigmem(addr, size) { return mem_banks[addr >>> 16].check(addr, size); } + function chipmem_xlate_bigmem(addr) { return mem_banks[addr >>> 16].xlateaddr(addr); }*/ + + /*---------------------------------*/ + + function chipmem_setindirect() { + /*if (currprefs.z3chipmem_size) { + chipmem_get32_indirect = chipmem_get32_bigmem; + chipmem_get16_indirect = chipmem_get16_bigmem; + chipmem_get8_indirect = chipmem_get8_bigmem; + chipmem_put32_indirect = chipmem_put32_bigmem; + chipmem_put16_indirect = chipmem_put16_bigmem; + chipmem_put8_indirect = chipmem_put8_bigmem; + chipmem_check_indirect = chipmem_check_bigmem; + chipmem_xlate_indirect = chipmem_xlate_bigmem; + } else { + /*chipmem_get32_indirect = chipmem_get32; + chipmem_get16_indirect = chipmem_agnus_get16; + chipmem_get8_indirect = chipmem_agnus_get8; + chipmem_put32_indirect = chipmem_put32; + chipmem_put16_indirect = chipmem_agnus_put16; + chipmem_put8_indirect = chipmem_agnus_put8; + chipmem_check_indirect = chipmem_check; + chipmem_xlate_indirect = chipmem_xlate; + }*/ + + SAER_Memory_chipGet8_indirect = chipmem_agnus_get8; + SAER_Memory_chipGet16_indirect = chipmem_agnus_get16; + SAER_Memory_chipGet32_indirect = chipmem_get32; + SAER_Memory_chipPut8_indirect = chipmem_agnus_put8; + SAER_Memory_chipPut16_indirect = chipmem_agnus_put16; + SAER_Memory_chipPut32_indirect = chipmem_put32; + SAER_Memory_chipCheck_indirect = chipmem_check; + SAER_Memory_chipXLate_indirect = chipmem_xlate; + } + + /*-----------------------------------------------------------------------*/ + /* BANK Slow/Bogo memory */ + + function bogomem_get32(addr) { + addr = (addr & bogomem_bank.mask) + bogomem_aliasing_offset; + //var m = bogomem_bank.baseaddr + addr; return do_get_mem_long ((uae_u32 *)m); + return ((bogomem_bank.baseaddr[addr] << 24) | (bogomem_bank.baseaddr[addr+1] << 16) | (bogomem_bank.baseaddr[addr+2] << 8) | bogomem_bank.baseaddr[addr+3]) >>> 0; + } + function bogomem_get16(addr) { + addr = (addr & bogomem_bank.mask) + bogomem_aliasing_offset; + //var m = bogomem_bank.baseaddr + addr; return do_get_mem_word ((uae_u16 *)m); + return (bogomem_bank.baseaddr[addr] << 8) | bogomem_bank.baseaddr[addr+1]; + } + function bogomem_get8(addr) { + addr = (addr & bogomem_bank.mask) + bogomem_aliasing_offset; + return bogomem_bank.baseaddr[addr]; + } + function bogomem_put32(addr, l) { + addr = (addr & bogomem_bank.mask) + bogomem_aliasing_offset; + //var m = bogomem_bank.baseaddr + addr; do_put_mem_long ((uae_u32 *)m, l); + bogomem_bank.baseaddr[addr] = l >>> 24; + bogomem_bank.baseaddr[addr+1] = (l >>> 16) & 0xff; + bogomem_bank.baseaddr[addr+2] = (l >>> 8) & 0xff; + bogomem_bank.baseaddr[addr+3] = l & 0xff; + } + function bogomem_put16(addr, w) { + addr = (addr & bogomem_bank.mask) + bogomem_aliasing_offset; + //var m = bogomem_bank.baseaddr + addr; do_put_mem_word ((uae_u16 *)m, w); + bogomem_bank.baseaddr[addr] = w >> 8; + bogomem_bank.baseaddr[addr+1] = w & 0xff; + } + function bogomem_put8(addr, b) { + addr = (addr & bogomem_bank.mask) + bogomem_aliasing_offset; + bogomem_bank.baseaddr[addr] = b; + } + function bogomem_check(addr, size) { + addr = (addr & bogomem_bank.mask);// + bogomem_aliasing_offset; + return (addr + size) <= bogomem_bank.allocated; + } + function bogomem_xlate(addr) { + addr = (addr & bogomem_bank.mask) + bogomem_aliasing_offset; + //return bogomem_bank.baseaddr + addr; + return addr; + } + var bogomem_bank = new SAEO_Memory_addrbank( + bogomem_get32, bogomem_get16, bogomem_get8, + bogomem_put32, bogomem_put16, bogomem_put8, + bogomem_xlate, bogomem_check, null, "bogo", "Slow memory", + bogomem_get32, bogomem_get16, + //SAEC_Memory_addrbank_flag_RAM | SAEC_Memory_addrbank_flag_THREADSAFE, 0, 0 + SAEC_Memory_addrbank_flag_RAM | SAEC_Memory_addrbank_flag_THREADSAFE + ); + + /*-----------------------------------------------------------------------*/ + /* BANK CDTV memory card */ + + /*MEMORY_FUNCTIONS(cardmem); + var cardmem_bank = new SAEO_Memory_addrbank( + cardmem_get32, cardmem_get16, cardmem_get8, + cardmem_put32, cardmem_put16, cardmem_put8, + cardmem_xlate, cardmem_check, null, "rom_e0", "CDTV memory card", + cardmem_get32, cardmem_get16, + //SAEC_Memory_addrbank_flag_RAM, 0, 0 + SAEC_Memory_addrbank_flag_RAM + );*/ + + /*-----------------------------------------------------------------------*/ + /* BANK A3000 motherboard fast memory */ + + function a3000lmem_get32(addr) { + addr = (addr & a3000lmem_bank.mask) >>> 0; + //var m = a3000lmem_bank.baseaddr + addr; return do_get_mem_long ((uae_u32 *)m); + return ((a3000lmem_bank.baseaddr[addr] << 24) | (a3000lmem_bank.baseaddr[addr+1] << 16) | (a3000lmem_bank.baseaddr[addr+2] << 8) | a3000lmem_bank.baseaddr[addr+3]) >>> 0; + } + function a3000lmem_get16(addr) { + addr = (addr & a3000lmem_bank.mask) >>> 0; + //var m = a3000lmem_bank.baseaddr + addr; return do_get_mem_word ((uae_u16 *)m); + return (a3000lmem_bank.baseaddr[addr] << 8) | a3000lmem_bank.baseaddr[addr+1]; + } + function a3000lmem_get8(addr) { + addr = (addr & a3000lmem_bank.mask) >>> 0; + return a3000lmem_bank.baseaddr[addr]; + } + function a3000lmem_put32(addr, l) { + addr = (addr & a3000lmem_bank.mask) >>> 0; + //var m = a3000lmem_bank.baseaddr + addr; do_put_mem_long ((uae_u32 *)m, l); + a3000lmem_bank.baseaddr[addr] = l >>> 24; + a3000lmem_bank.baseaddr[addr+1] = (l >>> 16) & 0xff; + a3000lmem_bank.baseaddr[addr+2] = (l >>> 8) & 0xff; + a3000lmem_bank.baseaddr[addr+3] = l & 0xff; + } + function a3000lmem_put16(addr, w) { + addr = (addr & a3000lmem_bank.mask) >>> 0; + //var m = a3000lmem_bank.baseaddr + addr; do_put_mem_word ((uae_u16 *)m, w); + a3000lmem_bank.baseaddr[addr] = w >> 8; + a3000lmem_bank.baseaddr[addr+1] = w & 0xff; + } + function a3000lmem_put8(addr, b) { + addr = (addr & a3000lmem_bank.mask) >>> 0; + a3000lmem_bank.baseaddr[addr] = b; + } + function a3000lmem_check(addr, size) { + addr = (addr & a3000lmem_bank.mask) >>> 0; + return (addr + size) <= a3000lmem_bank.allocated; + } + function a3000lmem_xlate(addr) { + addr = (addr & a3000lmem_bank.mask) >>> 0; + //return a3000lmem_bank.baseaddr + addr; + return addr; + } + var a3000lmem_bank = new SAEO_Memory_addrbank( + a3000lmem_get32, a3000lmem_get16, a3000lmem_get8, + a3000lmem_put32, a3000lmem_put16, a3000lmem_put8, + a3000lmem_xlate, a3000lmem_check, null, "ramsey_low", "RAMSEY memory (low)", + a3000lmem_get32, a3000lmem_get16, + //SAEC_Memory_addrbank_flag_RAM | SAEC_Memory_addrbank_flag_THREADSAFE, 0, 0 + SAEC_Memory_addrbank_flag_RAM | SAEC_Memory_addrbank_flag_THREADSAFE + ); + + + function a3000hmem_get32(addr) { + addr = (addr & a3000hmem_bank.mask) >>> 0; + //var m = a3000hmem_bank.baseaddr + addr; return do_get_mem_long ((uae_u32 *)m); + return ((a3000hmem_bank.baseaddr[addr] << 24) | (a3000hmem_bank.baseaddr[addr+1] << 16) | (a3000hmem_bank.baseaddr[addr+2] << 8) | a3000hmem_bank.baseaddr[addr+3]) >>> 0; + } + function a3000hmem_get16(addr) { + addr = (addr & a3000hmem_bank.mask) >>> 0; + //var m = a3000hmem_bank.baseaddr + addr; return do_get_mem_word ((uae_u16 *)m); + return (a3000hmem_bank.baseaddr[addr] << 8) | a3000hmem_bank.baseaddr[addr+1]; + } + function a3000hmem_get8(addr) { + addr = (addr & a3000hmem_bank.mask) >>> 0; + return a3000hmem_bank.baseaddr[addr]; + } + function a3000hmem_put32(addr, l) { + addr = (addr & a3000hmem_bank.mask) >>> 0; + //var m = a3000hmem_bank.baseaddr + addr; do_put_mem_long ((uae_u32 *)m, l); + a3000hmem_bank.baseaddr[addr] = l >>> 24; + a3000hmem_bank.baseaddr[addr+1] = (l >>> 16) & 0xff; + a3000hmem_bank.baseaddr[addr+2] = (l >>> 8) & 0xff; + a3000hmem_bank.baseaddr[addr+3] = l & 0xff; + } + function a3000hmem_put16(addr, w) { + addr = (addr & a3000hmem_bank.mask) >>> 0; + //var m = a3000hmem_bank.baseaddr + addr; do_put_mem_word ((uae_u16 *)m, w); + a3000hmem_bank.baseaddr[addr] = w >> 8; + a3000hmem_bank.baseaddr[addr+1] = w & 0xff; + } + function a3000hmem_put8(addr, b) { + addr = (addr & a3000hmem_bank.mask) >>> 0; + a3000hmem_bank.baseaddr[addr] = b; + } + function a3000hmem_check(addr, size) { + addr = (addr & a3000hmem_bank.mask) >>> 0; + return (addr + size) <= a3000hmem_bank.allocated; + } + function a3000hmem_xlate(addr) { + addr = (addr & a3000hmem_bank.mask) >>> 0; + //return a3000hmem_bank.baseaddr + addr; + return addr; + } + var a3000hmem_bank = new SAEO_Memory_addrbank( + a3000hmem_get32, a3000hmem_get16, a3000hmem_get8, + a3000hmem_put32, a3000hmem_put16, a3000hmem_put8, + a3000hmem_xlate, a3000hmem_check, null, "ramsey_high", "RAMSEY memory (high)", + a3000hmem_get32, a3000hmem_get16, + //SAEC_Memory_addrbank_flag_RAM | SAEC_Memory_addrbank_flag_THREADSAFE, 0, 0 + SAEC_Memory_addrbank_flag_RAM | SAEC_Memory_addrbank_flag_THREADSAFE + ); + + /*-----------------------------------------------------------------------*/ + /* BANK 25bit memory (0x01000000) */ + + /*MEMORY_FUNCTIONS(mem25bit); + var mem25bit_bank = new SAEO_Memory_addrbank( + mem25bit_get32, mem25bit_get16, mem25bit_get8, + mem25bit_put32, mem25bit_put16, mem25bit_put8, + mem25bit_xlate, mem25bit_check, null, "25bitmem", "25bit memory", + mem25bit_get32, mem25bit_get16, + //SAEC_Memory_addrbank_flag_RAM | SAEC_Memory_addrbank_flag_THREADSAFE, 0, 0 + SAEC_Memory_addrbank_flag_RAM | SAEC_Memory_addrbank_flag_THREADSAFE + );*/ + + /*-----------------------------------------------------------------------*/ + /* BANK Kickstart ROM */ + + /* A1000 kickstart RAM handling + * + * RESET instruction unhides boot ROM and disables write protection + * write access to boot ROM hides boot ROM and enables write protection */ + + var a1000_kickstart_mode = false; //int + var a1000_bootrom = null; //u8 * + function a1000_handle_kickstart(mode) { + if (a1000_bootrom !== null) { + //protect_roms(false); + if (mode == 0) { + a1000_kickstart_mode = false; + //memcpy(kickmem_bank.baseaddr, kickmem_bank.baseaddr + ROM_SIZE_256, ROM_SIZE_256); + SAEF_memcpy(kickmem_bank.baseaddr,0, kickmem_bank.baseaddr,ROM_SIZE_256, ROM_SIZE_256); + //kickmem_bank.baseaddr.copyWithin(0, ROM_SIZE_256, ROM_SIZE_256 + ROM_SIZE_256); + kickstart_version = (kickmem_bank.baseaddr[ROM_SIZE_256 + 12] << 8) | kickmem_bank.baseaddr[ROM_SIZE_256 + 13]; + } else { + a1000_kickstart_mode = true; + kickmem_bank.baseaddr.set(a1000_bootrom); //memcpy (kickmem_bank.baseaddr, a1000_bootrom, ROM_SIZE_256); + kickstart_version = 0; + } + if (kickstart_version == 0xffff) + kickstart_version = 0; + } + } + this.a1000_reset = function() { + a1000_handle_kickstart(1); + } + + /*---------------------------------*/ + + function kickmem_get32(addr) { + addr = (addr & kickmem_bank.mask) >>> 0; + //var m = kickmem_bank.baseaddr + addr; return do_get_mem_long ((uae_u32 *)m); + return ((kickmem_bank.baseaddr[addr] << 24) | (kickmem_bank.baseaddr[addr+1] << 16) | (kickmem_bank.baseaddr[addr+2] << 8) | kickmem_bank.baseaddr[addr+3]) >>> 0; + } + function kickmem_get16(addr) { + addr = (addr & kickmem_bank.mask) >>> 0; + //var m = kickmem_bank.baseaddr + addr; return do_get_mem_word ((uae_u16 *)m); + return (kickmem_bank.baseaddr[addr] << 8) | kickmem_bank.baseaddr[addr+1]; + } + function kickmem_get8(addr) { + addr = (addr & kickmem_bank.mask) >>> 0; + return kickmem_bank.baseaddr[addr]; + } + function kickmem_put32(addr, l) { + if (rom_write_enabled) { + addr = (addr & kickmem_bank.mask) >>> 0; + //var m = (uae_u32 *)(kickmem_bank.baseaddr + addr); do_put_mem_long(m, l); + kickmem_bank.baseaddr[addr] = l >>> 24; + kickmem_bank.baseaddr[addr+1] = (l >>> 16) & 0xff; + kickmem_bank.baseaddr[addr+2] = (l >>> 8) & 0xff; + kickmem_bank.baseaddr[addr+3] = l & 0xff; + } else if (a1000_kickstart_mode) { + if (addr >= 0xfc0000) { + addr = (addr & kickmem_bank.mask) >>> 0; + //var m = (uae_u32 *)(kickmem_bank.baseaddr + addr); do_put_mem_long(m, l); + kickmem_bank.baseaddr[addr] = l >>> 24; + kickmem_bank.baseaddr[addr+1] = (l >>> 16) & 0xff; + kickmem_bank.baseaddr[addr+2] = (l >>> 8) & 0xff; + kickmem_bank.baseaddr[addr+3] = l & 0xff; + //return; + } else + a1000_handle_kickstart(0); + } else if (SAEV_config.memory.logIllegal) + SAEF_warn("Illegal kickmem put32 at %08x", addr); + } + function kickmem_put16(addr, w) { + if (rom_write_enabled) { + addr = (addr & kickmem_bank.mask) >>> 0; + //var m = (uae_u16 *)(kickmem_bank.baseaddr + addr); do_put_mem_word(m, w); + kickmem_bank.baseaddr[addr] = w >> 8; + kickmem_bank.baseaddr[addr+1] = w & 0xff; + } else if (a1000_kickstart_mode) { + if (addr >= 0xfc0000) { + addr = (addr & kickmem_bank.mask) >>> 0; + //var m = (uae_u16 *)(kickmem_bank.baseaddr + addr); do_put_mem_word(m, w); + kickmem_bank.baseaddr[addr] = w >> 8; + kickmem_bank.baseaddr[addr+1] = w & 0xff; + //return; + } else + a1000_handle_kickstart(0); + } else if (SAEV_config.memory.logIllegal) + SAEF_warn("Illegal kickmem put16 at %08x", addr); + } + function kickmem_put8(addr, b) { + if (rom_write_enabled) { + addr = (addr & kickmem_bank.mask) >>> 0; + kickmem_bank.baseaddr[addr] = b; + } else if (a1000_kickstart_mode) { + if (addr >= 0xfc0000) { + addr = (addr & kickmem_bank.mask) >>> 0; + kickmem_bank.baseaddr[addr] = b; + //return; + } else + a1000_handle_kickstart(0); + } else if (SAEV_config.memory.logIllegal) + SAEF_warn("Illegal kickmem put8 at %08x", addr); + } + function kickmem_check(addr, size) { + addr = (addr & kickmem_bank.mask) >>> 0; + return (addr + size) <= kickmem_bank.allocated; + } + function kickmem_xlate(addr) { + addr = (addr & kickmem_bank.mask) >>> 0; + //return kickmem_bank.baseaddr + addr; + return addr; + } + var kickmem_bank = new SAEO_Memory_addrbank( + kickmem_get32, kickmem_get16, kickmem_get8, + kickmem_put32, kickmem_put16, kickmem_put8, + kickmem_xlate, kickmem_check, null, "kick", "Kickstart ROM", + kickmem_get32, kickmem_get16, + //SAEC_Memory_addrbank_flag_ROM | SAEC_Memory_addrbank_flag_THREADSAFE, 0, S_WRITE + SAEC_Memory_addrbank_flag_ROM | SAEC_Memory_addrbank_flag_THREADSAFE + ); + + /*-----------------------------------------------------------------------*/ + /* BANK Kickstart Shadow RAM (maprom) */ + + /*function kickmem2_put32(addr, l) { + addr = (addr & kickmem_bank.mask) >>> 0; + //var m = (uae_u32 *)(kickmem_bank.baseaddr + addr); do_put_mem_long (m, l); + kickmem_bank.baseaddr[addr] = l >>> 24; + kickmem_bank.baseaddr[addr+1] = (l >>> 16) & 0xff; + kickmem_bank.baseaddr[addr+2] = (l >>> 8) & 0xff; + kickmem_bank.baseaddr[addr+3] = l & 0xff; + } + function kickmem2_put16(addr, w) { + addr = (addr & kickmem_bank.mask) >>> 0; + //var m = (uae_u16 *)(kickmem_bank.baseaddr + addr); do_put_mem_word (m, w); + kickmem_bank.baseaddr[addr] = w >> 8; + kickmem_bank.baseaddr[addr+1] = w & 0xff; + } + function kickmem2_put8(addr, b) { + addr = (addr & kickmem_bank.mask) >>> 0; + kickmem_bank.baseaddr[addr] = b; + } + var kickram_bank = new SAEO_Memory_addrbank( + kickmem_get32, kickmem_get16, kickmem_get8, + kickmem2_put32, kickmem2_put16, kickmem2_put8, + kickmem_xlate, kickmem_check, null, null, "Kickstart Shadow RAM", + kickmem_get32, kickmem_get16, + //SAEC_Memory_addrbank_flag_UNK | SAEC_Memory_addrbank_flag_SAFE, 0, S_WRITE + SAEC_Memory_addrbank_flag_UNK | SAEC_Memory_addrbank_flag_SAFE + );*/ + + /*-----------------------------------------------------------------------*/ + /* BANK Extended Kickstart ROM */ + + var extendedkickmem_type = 0; + + const EXTENDED_ROM_CD32 = 1; + const EXTENDED_ROM_CDTV = 2; + const EXTENDED_ROM_KS = 3; + const EXTENDED_ROM_ARCADIA = 4; + + function extendedkickmem_get32(addr) { + addr = (addr & extendedkickmem_bank.mask) >>> 0; + //var m = extendedkickmem_bank.baseaddr + addr; return do_get_mem_long ((uae_u32 *)m); + return ((extendedkickmem_bank.baseaddr[addr] << 24) | (extendedkickmem_bank.baseaddr[addr+1] << 16) | (extendedkickmem_bank.baseaddr[addr+2] << 8) | extendedkickmem_bank.baseaddr[addr+3]) >>> 0; + } + function extendedkickmem_get16(addr) { + addr = (addr & extendedkickmem_bank.mask) >>> 0; + //var m = extendedkickmem_bank.baseaddr + addr; return do_get_mem_word ((uae_u16 *)m); + return (extendedkickmem_bank.baseaddr[addr] << 8) | extendedkickmem_bank.baseaddr[addr+1]; + } + function extendedkickmem_get8(addr) { + addr = (addr & extendedkickmem_bank.mask) >>> 0; + return extendedkickmem_bank.baseaddr[addr]; + } + function extendedkickmem_put32(addr, b) { + if (SAEV_config.memory.logIllegal) + SAEF_warn("Illegal extendedkickmem put32 at %08x", addr); + } + function extendedkickmem_put16(addr, b) { + if (SAEV_config.memory.logIllegal) + SAEF_warn("Illegal extendedkickmem put16 at %08x", addr); + } + function extendedkickmem_put8(addr, b) { + if (SAEV_config.memory.logIllegal) + SAEF_warn("Illegal extendedkickmem put32 at %08x", addr); + } + function extendedkickmem_check(addr, size) { + addr = (addr & extendedkickmem_bank.mask) >>> 0; + return (addr + size) <= extendedkickmem_bank.allocated; + } + function extendedkickmem_xlate(addr) { + addr = (addr & extendedkickmem_bank.mask) >>> 0; + //return extendedkickmem_bank.baseaddr + addr; + return addr; + } + var extendedkickmem_bank = new SAEO_Memory_addrbank( + extendedkickmem_get32, extendedkickmem_get16, extendedkickmem_get8, + extendedkickmem_put32, extendedkickmem_put16, extendedkickmem_put8, + extendedkickmem_xlate, extendedkickmem_check, null, null, "Extended Kickstart ROM", + extendedkickmem_get32, extendedkickmem_get16, + //SAEC_Memory_addrbank_flag_ROM | SAEC_Memory_addrbank_flag_THREADSAFE, 0, S_WRITE + SAEC_Memory_addrbank_flag_ROM | SAEC_Memory_addrbank_flag_THREADSAFE + ); + + /*-----------------------------------------------------------------------*/ + /* BANK Extended 2nd Kickstart ROM */ + + function extendedkickmem2_get32(addr) { + addr = (addr & extendedkickmem2_bank.mask) >>> 0; + //var m = extendedkickmem2_bank.baseaddr + addr; return do_get_mem_long ((uae_u32 *)m); + return ((extendedkickmem2_bank.baseaddr[addr] << 24) | (extendedkickmem2_bank.baseaddr[addr+1] << 16) | (extendedkickmem2_bank.baseaddr[addr+2] << 8) | extendedkickmem2_bank.baseaddr[addr+3]) >>> 0; + } + function extendedkickmem2_get16(addr) { + addr = (addr & extendedkickmem2_bank.mask) >>> 0; + //var m = extendedkickmem2_bank.baseaddr + addr; return do_get_mem_word ((uae_u16 *)m); + return (extendedkickmem2_bank.baseaddr[addr] << 8) | extendedkickmem2_bank.baseaddr[addr+1]; + } + function extendedkickmem2_get8(addr) { + addr = (addr & extendedkickmem2_bank.mask) >>> 0; + return extendedkickmem2_bank.baseaddr[addr]; + } + function extendedkickmem2_put32(addr, b) { + if (SAEV_config.memory.logIllegal) + SAEF_warn("Illegal extendedkickmem2 put32 at %08x", addr); + } + function extendedkickmem2_put16(addr, b) { + if (SAEV_config.memory.logIllegal) + SAEF_warn("Illegal extendedkickmem2 put16 at %08x", addr); + } + function extendedkickmem2_put8(addr, b) { + if (SAEV_config.memory.logIllegal) + SAEF_warn("Illegal extendedkickmem2 put32 at %08x", addr); + } + function extendedkickmem2_check(addr, size) { + addr = (addr & extendedkickmem2_bank.mask) >>> 0; + return (addr + size) <= extendedkickmem2_bank.allocated; + } + function extendedkickmem2_xlate(addr) { + addr = (addr & extendedkickmem2_bank.mask) >>> 0; + //return extendedkickmem2_bank.baseaddr + addr; + return addr; + } + var extendedkickmem2_bank = new SAEO_Memory_addrbank( + extendedkickmem2_get32, extendedkickmem2_get16, extendedkickmem2_get8, + extendedkickmem2_put32, extendedkickmem2_put16, extendedkickmem2_put8, + extendedkickmem2_xlate, extendedkickmem2_check, null, "rom_a8", "Extended 2nd Kickstart ROM", + extendedkickmem2_get32, extendedkickmem2_get16, + //SAEC_Memory_addrbank_flag_ROM | SAEC_Memory_addrbank_flag_THREADSAFE, 0, S_WRITE + SAEC_Memory_addrbank_flag_ROM | SAEC_Memory_addrbank_flag_THREADSAFE + ); + + /*-----------------------------------------------------------------------*/ + /* BANK Non-autoconfig RAM */ + + function custmem1_get32(addr) { + addr = (addr & custmem1_bank.mask) >>> 0; + //var m = custmem1_bank.baseaddr + addr; return do_get_mem_long ((uae_u32 *)m); + return ((custmem1_bank.baseaddr[addr] << 24) | (custmem1_bank.baseaddr[addr+1] << 16) | (custmem1_bank.baseaddr[addr+2] << 8) | custmem1_bank.baseaddr[addr+3]) >>> 0; + } + function custmem1_get16(addr) { + addr = (addr & custmem1_bank.mask) >>> 0; + //var m = custmem1_bank.baseaddr + addr; return do_get_mem_word ((uae_u16 *)m); + return (custmem1_bank.baseaddr[addr] << 8) | custmem1_bank.baseaddr[addr+1]; + } + function custmem1_get8(addr) { + addr = (addr & custmem1_bank.mask) >>> 0; + return custmem1_bank.baseaddr[addr]; + } + function custmem1_put32(addr, l) { + addr = (addr & custmem1_bank.mask) >>> 0; + //var m = custmem1_bank.baseaddr + addr; do_put_mem_long ((uae_u32 *)m, l); + custmem1_bank.baseaddr[addr] = l >>> 24; + custmem1_bank.baseaddr[addr+1] = (l >>> 16) & 0xff; + custmem1_bank.baseaddr[addr+2] = (l >>> 8) & 0xff; + custmem1_bank.baseaddr[addr+3] = l & 0xff; + } + function custmem1_put16(addr, w) { + addr = (addr & custmem1_bank.mask) >>> 0; + //var m = custmem1_bank.baseaddr + addr; do_put_mem_word ((uae_u16 *)m, w); + custmem1_bank.baseaddr[addr] = w >> 8; + custmem1_bank.baseaddr[addr+1] = w & 0xff; + } + function custmem1_put8(addr, b) { + addr = (addr & custmem1_bank.mask) >>> 0; + custmem1_bank.baseaddr[addr] = b; + } + function custmem1_check(addr, size) { + addr = (addr & custmem1_bank.mask) >>> 0; + return (addr + size) <= custmem1_bank.allocated; + } + function custmem1_xlate(addr) { + addr = (addr & custmem1_bank.mask) >>> 0; + //return custmem1_bank.baseaddr + addr; + return addr; + } + var custmem1_bank = new SAEO_Memory_addrbank( + custmem1_get32, custmem1_get16, custmem1_get8, + custmem1_put32, custmem1_put16, custmem1_put8, + custmem1_xlate, custmem1_check, null, "custmem1", "Non-autoconfig RAM #1", + custmem1_get32, custmem1_get16, + //SAEC_Memory_addrbank_flag_RAM | SAEC_Memory_addrbank_flag_THREADSAFE, 0, 0 + SAEC_Memory_addrbank_flag_RAM | SAEC_Memory_addrbank_flag_THREADSAFE + ); + + /*---------------------------------*/ + + function custmem2_get32(addr) { + addr = (addr & custmem2_bank.mask) >>> 0; + //var m = custmem2_bank.baseaddr + addr; return do_get_mem_long ((uae_u32 *)m); + return ((custmem2_bank.baseaddr[addr] << 24) | (custmem2_bank.baseaddr[addr+1] << 16) | (custmem2_bank.baseaddr[addr+2] << 8) | custmem2_bank.baseaddr[addr+3]) >>> 0; + } + function custmem2_get16(addr) { + addr = (addr & custmem2_bank.mask) >>> 0; + //var m = custmem2_bank.baseaddr + addr; return do_get_mem_word ((uae_u16 *)m); + return (custmem2_bank.baseaddr[addr] << 8) | custmem2_bank.baseaddr[addr+1]; + } + function custmem2_get8(addr) { + addr = (addr & custmem2_bank.mask) >>> 0; + return custmem2_bank.baseaddr[addr]; + } + function custmem2_put32(addr, l) { + addr = (addr & custmem2_bank.mask) >>> 0; + //var m = custmem2_bank.baseaddr + addr; do_put_mem_long ((uae_u32 *)m, l); + custmem2_bank.baseaddr[addr] = l >>> 24; + custmem2_bank.baseaddr[addr+1] = (l >>> 16) & 0xff; + custmem2_bank.baseaddr[addr+2] = (l >>> 8) & 0xff; + custmem2_bank.baseaddr[addr+3] = l & 0xff; + } + function custmem2_put16(addr, w) { + addr = (addr & custmem2_bank.mask) >>> 0; + //var m = custmem2_bank.baseaddr + addr; do_put_mem_word ((uae_u16 *)m, w); + custmem2_bank.baseaddr[addr] = w >> 8; + custmem2_bank.baseaddr[addr+1] = w & 0xff; + } + function custmem2_put8(addr, b) { + addr = (addr & custmem2_bank.mask) >>> 0; + custmem2_bank.baseaddr[addr] = b; + } + function custmem2_check(addr, size) { + addr = (addr & custmem2_bank.mask) >>> 0; + return (addr + size) <= custmem2_bank.allocated; + } + function custmem2_xlate(addr) { + addr = (addr & custmem2_bank.mask) >>> 0; + //return custmem2_bank.baseaddr + addr; + return addr; + } + var custmem2_bank = new SAEO_Memory_addrbank( + custmem2_get32, custmem2_get16, custmem2_get8, + custmem2_put32, custmem2_put16, custmem2_put8, + custmem2_xlate, custmem2_check, null, "custmem2", "Non-autoconfig RAM #2", + custmem2_get32, custmem2_get16, + //SAEC_Memory_addrbank_flag_RAM | SAEC_Memory_addrbank_flag_THREADSAFE, 0, 0 + SAEC_Memory_addrbank_flag_RAM | SAEC_Memory_addrbank_flag_THREADSAFE + ); + + /*-----------------------------------------------------------------------*/ + /*-----------------------------------------------------------------------*/ + /*-----------------------------------------------------------------------*/ + /* Kickstart handling */ + + const fkickmem_size = ROM_SIZE_512; + const fkickmem_halfsize = fkickmem_size >> 1; //OWN + var kickstore = null; + var a3000_f0 = false; + + this.a3000_fakekick = function(map) { + //protect_roms(false); + SAEF_log("memory.a3000_fakekick() map %d", map?1:0); + if (map) { + //var fkickmemory = a3000lmem_bank.baseaddr + a3000lmem_bank.allocated - fkickmem_size; //u8 * ATT bomb + + var fkickmemory = a3000lmem_bank.baseaddr; + var fkickoffset = a3000lmem_bank.allocated - fkickmem_size; //OWN + + //if (fkickmemory[2] == 0x4e && fkickmemory[3] == 0xf9 && fkickmemory[4] == 0x00) { + if (fkickmemory[fkickoffset + 2] == 0x4e && fkickmemory[fkickoffset + 3] == 0xf9 && fkickmemory[fkickoffset + 4] == 0x00) { + if (kickstore === null) + kickstore = new Uint8Array(fkickmem_size); + kickstore.set(kickmem_bank.baseaddr.subarray(0, fkickmem_size)); //memcpy (kickstore, kickmem_bank.baseaddr, fkickmem_size); + + //if (fkickmemory[5] == 0xfc) { + if (fkickmemory[fkickoffset + 5] == 0xfc) { + kickmem_bank.baseaddr.set(fkickmemory.subarray(0, fkickmem_halfsize)); //memcpy (kickmem_bank.baseaddr, fkickmemory, fkickmem_size / 2); + kickmem_bank.baseaddr.set(fkickmemory.subarray(0, fkickmem_halfsize), fkickmem_halfsize); //memcpy (kickmem_bank.baseaddr + fkickmem_size / 2, fkickmemory, fkickmem_size / 2); + extendedkickmem_bank.allocated = 65536; + extendedkickmem_bank.label = "rom_f0"; + extendedkickmem_bank.mask = extendedkickmem_bank.allocated - 1; + mapped_malloc(extendedkickmem_bank); + extendedkickmem_bank.baseaddr.set(fkickmemory.subarray(fkickmem_halfsize, fkickmem_halfsize + 65536)); //memcpy (extendedkickmem_bank.baseaddr, fkickmemory + fkickmem_size / 2, 65536); + map_banks(extendedkickmem_bank, 0xf0, 1, 1); + a3000_f0 = true; + } else + kickmem_bank.baseaddr.set(fkickmemory.subarray(0, fkickmem_size)); //memcpy (kickmem_bank.baseaddr, fkickmemory, fkickmem_size); + } + } else { + if (a3000_f0) { + map_banks(SAEV_Memory_dummyBank, 0xf0, 1, 1); + mapped_free(extendedkickmem_bank); + a3000_f0 = false; + } + if (kickstore !== null) { + kickmem_bank.baseaddr.set(kickstore); //memcpy (kickmem_bank.baseaddr, kickstore, fkickmem_size); + kickstore = null; + } + } + //protect_roms(true); + } + + /*-----------------------------------------------------------------------*/ + + function read_kickstart(f, mem,memo, size, dochecksum, noalias) { + const kickstring = SAEF_String2Array("exec.library"); + const kickstring_length = kickstring.length; + var buffer = new Uint8Array(20); + var i, j, oldpos; + var cr = 0, kickdisk = 0; + + if (size < 0) { + SAEF_ZFile_fseek(f, 0, SEEK_END); + size = SAEF_ZFile_ftell(f) & ~0x3ff >>> 0; + SAEF_ZFile_fseek(f, 0, SEEK_SET); + } + oldpos = SAEF_ZFile_ftell(f); + i = SAEF_ZFile_fread(buffer,0, 1, 11, f); + if (SAEF_CompareArray(buffer, SAEF_String2Array("KICK"), 4) == 0) { + SAEF_ZFile_fseek(f, 512, SEEK_SET); + kickdisk = 1; + /*#if 0 + } else if (size >= ROM_SIZE_512 && SAEF_CompareArray(buffer, SAEF_String2Array("AMIG"), 4) == 0) { + //ReKick + SAEF_ZFile_fseek(f, oldpos + 0x6c, SEEK_SET); + cr = 2; + #endif*/ + } else if (SAEF_CompareArray(buffer, SAEF_String2Array("AMIROMTYPE1"), 11) == 0) { + SAEV_Memory_cloantoRom = true; + cr = 1; + } else { + SAEF_ZFile_fseek(f, oldpos, SEEK_SET); + } + //memset(mem, 0, size); + SAEF_memset(mem,memo, 0, size); + for (i = 0; i < 8; i++) + mem[memo + size - 16 + i * 2 + 1] = 0x18 + i; + mem[memo + size - 20] = size >>> 24; + mem[memo + size - 19] = (size >>> 16) & 0xff; + mem[memo + size - 18] = (size >>> 8) & 0xff; + mem[memo + size - 17] = size & 0xff; + + i = SAEF_ZFile_fread(mem,memo, 1, size, f); + + if (kickdisk && i > ROM_SIZE_256) + i = ROM_SIZE_256; + /*#if 0 + if (i >= ROM_SIZE_256 && (i != ROM_SIZE_256 && i != ROM_SIZE_512 && i != ROM_SIZE_512 * 2 && i != ROM_SIZE_512 * 4)) { + notify_user (NUMSG_KSROMREADERROR); + return -123; + } + #endif*/ + if (i < size - 20) + SAER.roms.kickstart_fix_checksum(mem,memo, size); + + j = 1; + while (j < i) j <<= 1; + i = j; + + + + if (!noalias && i == size >> 1) { + //memcpy(mem + size / 2, mem, size / 2); + SAEF_memcpy(mem,size >> 1, mem,0, size >> 1); + //mem.copyWithin(memo + (size >> 1), memo, memo + (size >> 1)); + } + if (cr) { + var err = SAER.roms.decode_rom(mem,memo, size, cr, i); + if (err == -1) + return -SAEE_Memory_RomDecode; + if (err == -2) + return -SAEE_Memory_RomKey; + } + if (SAEV_config.chipset.a1000ram && i < ROM_SIZE_256) { + var off = 0; + if (a1000_bootrom === null) + a1000_bootrom = new Uint8Array(ROM_SIZE_256); + while (off + i < ROM_SIZE_256) { + a1000_bootrom.set(kickmem_bank.baseaddr.subarray(0, i), off); //memcpy (a1000_bootrom + off, kickmem_bank.baseaddr, i); + off += i; + } + //memset(kickmem_bank.baseaddr, 0, kickmem_bank.allocated); + SAEF_memset(kickmem_bank.baseaddr,0, 0, kickmem_bank.allocated); + a1000_handle_kickstart(1); + dochecksum = 0; + i = ROM_SIZE_512; + } + + for (j = 0; j < 256 && i >= ROM_SIZE_256; j++) { + if (SAEF_CompareArrayAfter(mem, memo + j, kickstring, kickstring_length) == 0) + break; + } + if (j == 256 || i < ROM_SIZE_256) + dochecksum = 0; + if (dochecksum) { + if (!SAER.roms.kickstart_verify_checksum(mem,memo, size)) + return -SAEE_Memory_RomChecksum; + } + return i > 0 ? i : -SAEE_Memory_RomSize; + } + + function load_extendedkickstart(romextfile, type) { + var err = SAEE_None; + + if (romextfile.size == 0) + return err; //SAEE_Memory_NoExtendedRom; + + /*if (is_arcadia_rom(romextfile) == ARCADIA_BIOS) { + extendedkickmem_type = EXTENDED_ROM_ARCADIA; + return false; + }*/ + //var f = read_rom_name(romextfile); + var f = SAEF_ZFile_fopen_file(romextfile); + if (f === null) { + //notify_user(NUMSG_NOEXTROM); + return SAEE_Memory_NoExtendedRom; + } + SAEF_ZFile_fseek(f, 0, SEEK_END); + var size = SAEF_ZFile_ftell(f); + extendedkickmem_bank.allocated = ROM_SIZE_512; + + if (type == 0) { + /*if (currprefs.cs_cd32cd) { + extendedkickmem_type = EXTENDED_ROM_CD32; + } else if (currprefs.cs_cdtvcd || currprefs.cs_cdtvram) { + extendedkickmem_type = EXTENDED_ROM_CDTV; + } else*/ if (size > 300000) { + extendedkickmem_type = EXTENDED_ROM_CD32; + } else if (SAER.autoconf.need_uae_boot_rom() != 0xf00000) { + extendedkickmem_type = EXTENDED_ROM_CDTV; + } + } else { + extendedkickmem_type = type; + } + SAEF_log("memory.load_extendedkickstart() type %d", extendedkickmem_type); + if (extendedkickmem_type) { + var off = 0; + SAEF_ZFile_fseek(f, off, SEEK_SET); + switch (extendedkickmem_type) { + case EXTENDED_ROM_CDTV: + extendedkickmem_bank.label = "rom_f0"; + mapped_malloc(extendedkickmem_bank); + extendedkickmem_bank.start = 0xf00000; + break; + case EXTENDED_ROM_CD32: + extendedkickmem_bank.label = "rom_e0"; + mapped_malloc(extendedkickmem_bank); + extendedkickmem_bank.start = 0xe00000; + break; + } + + if (extendedkickmem_bank.baseaddr !== null) { + extendedkickmem_bank.mask = extendedkickmem_bank.allocated - 1; + size = read_kickstart(f, extendedkickmem_bank.baseaddr,0, extendedkickmem_bank.allocated, 0, 1); + if (size < 0) + err = -size; + } + } + SAEF_ZFile_fclose(f); + return err; + } + + function patch_shapeshifter(kickmemory) { + /* Patch Kickstart ROM for ShapeShifter - from Christian Bauer. + * Changes "lea $400,a0" and "lea $1000,a0" to "lea $3000,a0" for + * ShapeShifter compatability. */ + var kickshift1 = [ 0x41, 0xf8, 0x04, 0x00 ]; + var kickshift2 = [ 0x41, 0xf8, 0x10, 0x00 ]; + var kickshift3 = [ 0x43, 0xf8, 0x04, 0x00 ]; + var patched = 0; + + for (var i = 0x200; i < 0x300; i++) { + if (!SAEF_CompareArrayAfter(kickmemory, i, kickshift1, 4) || + !SAEF_CompareArrayAfter(kickmemory, i, kickshift2, 4) || + !SAEF_CompareArrayAfter(kickmemory, i, kickshift3, 4) + ) { + kickmemory[i + 2] = 0x30; + SAEF_log("memory.patch_shapeshifter() KickShifted at %04X", i); + patched++; + } + } + return patched; + } + + /* disable incompatible drivers */ + function patch_residents(kickmemory, size) { + //const residents = [ "NCR scsi.device", "scsi.device", "carddisk.device", "card.resource" ]; + var residents = []; + var base = size == ROM_SIZE_512 ? 0xf80000 : 0xfc0000; + var i, j, patched = 0; + + //OWN + if (SAEV_config.chipset.mbdmac & 1) + residents.push(SAEF_String2Array("scsi.device")); + if (SAEV_config.chipset.mbdmac & 2) + residents.push(SAEF_String2Array("NCR scsi.device")); + + //if (SAEV_config.chipset.mbdmac != 2) //ORG + if (residents.length) //OWN + { + for (i = 0; i < size - 100; i++) { + if (kickmemory[i] == 0x4a && kickmemory[i + 1] == 0xfc) { + var addr = (kickmemory[i + 2] << 24) | (kickmemory[i + 3] << 16) | (kickmemory[i + 4] << 8) | (kickmemory[i + 5] << 0); + if (addr != i + base) + continue; + addr = (kickmemory[i + 14] << 24) | (kickmemory[i + 15] << 16) | (kickmemory[i + 16] << 8) | (kickmemory[i + 17] << 0); + if (addr >= base && addr < base + size) { + for (j = 0; j < residents.length; j++) { + if (SAEF_CompareArrayAfter(kickmemory, addr - base, residents[j]) == 0) { + SAEF_log("memory.patch_residents() '%s' at %08X disabled", SAEF_Array2String(residents[j]), i + base); + kickmemory[i] = 0x4b; /* destroy RTC_MATCHWORD */ + patched++; + break; + } + } + } + } + } + } + return patched; + } + + function patch_kick() { + var patched = 0; + if (kickmem_bank.allocated >= ROM_SIZE_512 && SAEV_config.memory.kickShifter) + patched += patch_shapeshifter(kickmem_bank.baseaddr); + patched += patch_residents(kickmem_bank.baseaddr, kickmem_bank.allocated); + if (extendedkickmem_bank.baseaddr !== null) { + patched += patch_residents(extendedkickmem_bank.baseaddr, extendedkickmem_bank.allocated); + if (patched) + SAER.roms.kickstart_fix_checksum(extendedkickmem_bank.baseaddr,0, extendedkickmem_bank.allocated); + } + if (patched) + SAER.roms.kickstart_fix_checksum(kickmem_bank.baseaddr,0, kickmem_bank.allocated); + } + + + function load_kickstart_replacement() { + /*extern unsigned char arosrom[]; + extern unsigned int arosrom_len; + var f = SAEF_ZFile_fopen_data("aros.gz", arosrom_len, arosrom); + if (!f) return false; + f = zfile_gunzip(f); + if (!f) return false;*/ + + var f = SAEF_ZFile_fopen_file(SAEV_config.memory.extRom); + if (!f) return SAEE_Memory_NoExtendedRom; + extendedkickmem_bank.allocated = ROM_SIZE_512; + extendedkickmem_bank.mask = ROM_SIZE_512 - 1; + extendedkickmem_bank.label = "rom_e0"; + extendedkickmem_type = EXTENDED_ROM_KS; + mapped_malloc(extendedkickmem_bank); + var size = read_kickstart(f, extendedkickmem_bank.baseaddr,0, ROM_SIZE_512, 0, 1); + SAEF_ZFile_fclose(f); + if (size < 0) return -size; + + f = SAEF_ZFile_fopen_file(SAEV_config.memory.rom); + kickmem_bank.allocated = ROM_SIZE_512; + kickmem_bank.mask = ROM_SIZE_512 - 1; + size = read_kickstart(f, kickmem_bank.baseaddr,0, ROM_SIZE_512, 1, 0); + SAEF_ZFile_fclose(f); + if (size < 0) return -size; + + // if 68000-68020 config without any other fast ram with m68k aros: enable special extra RAM. + if ( + SAEV_config.cpu.model <= SAEC_Config_CPU_Model_68020 && + SAEV_config.memory.z2FastSize == 0 && + SAEV_config.memory.z3FastSize == 0 && + SAEV_config.memory.ramsey.highSize == 0 && + SAEV_config.memory.ramsey.lowSize == 0 + ) { + var ptr = SAEV_config.memory.custom[0]; + ptr.addr = 0xa80000; + ptr.size = 512 * 1024; + ptr.mask = 0; + ptr = SAEV_config.memory.custom[1]; + ptr.addr = 0xb00000; + ptr.size = 512 * 1024; + ptr.mask = 0; + SAEF_log("memory.load_kickstart_replacement() enabled 1M extra-memory"); + } + aros = true; //OWN + return SAEE_None; + } + + function load_kickstart() { + SAEV_Memory_cloantoRom = false; + aros = false; //OWN + //if (currprefs.romfile == ":AROS") + if (SAEV_config.memory.rom.name.indexOf("aros") != -1) + return load_kickstart_replacement(); + + //var f = read_rom_name(currprefs.romfile); + var f = SAEF_ZFile_fopen_file(SAEV_config.memory.rom); + if (f !== null) { + var filesize, size, maxsize; + var kspos = ROM_SIZE_512; + var extpos = 0; + + maxsize = ROM_SIZE_512; + SAEF_ZFile_fseek(f, 0, SEEK_END); + filesize = SAEF_ZFile_ftell(f); + SAEF_ZFile_fseek(f, 0, SEEK_SET); + if (filesize == 1760 * 512) { + filesize = ROM_SIZE_256; + maxsize = ROM_SIZE_256; + } + if (filesize == ROM_SIZE_512 + 8) { + /* GVP 0xf0 kickstart */ + SAEF_ZFile_fseek(f, 8, SEEK_SET); + } + if (filesize >= ROM_SIZE_512 * 2) { + SAEF_ZFile_fseek(f, kspos, SEEK_SET); + } + if (filesize >= ROM_SIZE_512 * 4) { + kspos = ROM_SIZE_512 * 3; + extpos = 0; + SAEF_ZFile_fseek(f, kspos, SEEK_SET); + } + size = read_kickstart(f, kickmem_bank.baseaddr,0, maxsize, 1, 0); + if (size < 0) { + SAEF_ZFile_fclose(f); + return -size; + } + kickmem_bank.mask = size - 1; + kickmem_bank.allocated = size; + if (filesize >= ROM_SIZE_512 * 2 && !extendedkickmem_type) { + extendedkickmem_bank.allocated = ROM_SIZE_512; + /*if (currprefs.cs_cdtvcd || currprefs.cs_cdtvram) { + extendedkickmem_type = EXTENDED_ROM_CDTV; + extendedkickmem_bank.allocated *= 2; + extendedkickmem_bank.label = "rom_f0"; + extendedkickmem_bank.start = 0xf00000; + } else*/ { + extendedkickmem_type = EXTENDED_ROM_KS; + extendedkickmem_bank.label = "rom_e0"; + extendedkickmem_bank.start = 0xe00000; + } + mapped_malloc(extendedkickmem_bank); + SAEF_ZFile_fseek(f, extpos, SEEK_SET); + size = read_kickstart(f, extendedkickmem_bank.baseaddr,0, extendedkickmem_bank.allocated, 0, 1); + if (size < 0) { + SAEF_ZFile_fclose(f); + return -size; + } + extendedkickmem_bank.mask = extendedkickmem_bank.allocated - 1; + } + if (filesize > ROM_SIZE_512 * 2) { + extendedkickmem2_bank.allocated = ROM_SIZE_512 * 2; + mapped_malloc(extendedkickmem2_bank); + SAEF_ZFile_fseek(f, extpos + ROM_SIZE_512, SEEK_SET); + size = read_kickstart(f, extendedkickmem2_bank.baseaddr,0, ROM_SIZE_512, 0, 1); + if (size < 0) { + SAEF_ZFile_fclose(f); + return -size; + } + SAEF_ZFile_fseek(f, extpos + ROM_SIZE_512 * 2, SEEK_SET); + size = read_kickstart(f, extendedkickmem2_bank.baseaddr,ROM_SIZE_512, ROM_SIZE_512, 0, 1); + if (size < 0) { + SAEF_ZFile_fclose(f); + return -size; + } + extendedkickmem2_bank.mask = extendedkickmem2_bank.allocated - 1; + extendedkickmem2_bank.start = 0xa80000; + } + } else + return SAEE_Memory_NoKickstartRom; + + kickstart_version = (kickmem_bank.baseaddr[12] << 8) | kickmem_bank.baseaddr[13]; + if (kickstart_version == 0xffff) { + // 1.0-1.1 and older + kickstart_version = (kickmem_bank.baseaddr[16] << 8) | kickmem_bank.baseaddr[17]; + if (kickstart_version > 33) + kickstart_version = 0; + } + SAEF_log("memory.load_kickstart() kickstart version %d", kickstart_version); + + SAEF_ZFile_fclose(f); + return SAEE_None; + } + + /*-----------------------------------------------------------------------*/ + /* setup/reset */ + + function mapped_malloc(ab) { + ab.startmask = ab.start; + try { + //ab.baseaddr = xcalloc(uae_u8, ab.allocated + 4); + ab.baseaddr = new Uint8Array(ab.allocated + 4); + return true; + } catch (e) { + ab.baseaddr = null; + return false; + } + } + function mapped_free(ab) { + //xfree(ab.baseaddr); + ab.baseaddr = null; + + if (bogomem_aliasing_offset && ab.label == "bogo") //OWN + bogomem_aliasing_offset = 0; + } + + function init_mem_banks() { + // unsigned so i << 16 won't overflow to negative when i >= 32768 + for (var i = 0; i < MEMORY_BANKS; i++) + //put_mem_bank(i << 16, SAEV_Memory_dummyBank, 0); + mem_banks[i] = SAEV_Memory_dummyBank; + } + + function singlebit(v) { + while (v && !(v & 1)) v >>>= 1; + return (v & ~1) >>> 0 == 0; + } + + function allocate() { //allocate_memory() + bogomem_aliasing = 0; + + var bogoreset = (bogomem_bank.flags & SAEC_Memory_addrbank_flag_NOALLOC) != 0 && (chipmem_bank.allocated != SAEV_config.memory.chipSize || bogomem_bank.allocated != SAEV_config.memory.bogoSize); + if (bogoreset) { + mapped_free(chipmem_bank); + mapped_free(bogomem_bank); + } + + /* emulate 0.5M+0.5M with 1M Agnus chip ram aliasing */ + if (SAEV_config.memory.chipSize == 0x80000 && SAEV_config.memory.bogoSize >= 0x80000 && SAEV_config.cpu.model < 68020) { + if ((SAEV_config.chipset.mask & SAEC_Config_Chipset_Mask_ECS_AGNUS) != 0 && (SAEV_config.chipset.mask & SAEC_Config_Chipset_Mask_AGA) == 0) { + if ((chipmem_bank.allocated != SAEV_config.memory.chipSize || bogomem_bank.allocated != SAEV_config.memory.bogoSize)) { + mapped_free(chipmem_bank); + mapped_free(bogomem_bank); + //bogomem_bank.allocated = 0; + var memsize1 = chipmem_bank.allocated = SAEV_config.memory.chipSize; + var memsize2 = bogomem_bank.allocated = SAEV_config.memory.bogoSize; + chipmem_bank.mask = chipmem_bank.allocated - 1; + chipmem_bank.start = chipmem_start_addr; + chipmem_full_mask = bogomem_bank.allocated * 2 - 1; + chipmem_full_size = 0x80000 * 2; + chipmem_bank.allocated = memsize1 + memsize2; + mapped_malloc(chipmem_bank); + chipmem_bank.allocated = SAEV_config.memory.chipSize; + + //bogomem_bank.baseaddr = chipmem_bank.baseaddr + memsize1; //ATT + + bogomem_bank.baseaddr = chipmem_bank.baseaddr; + bogomem_bank.mask = bogomem_bank.allocated - 1; + bogomem_bank.start = bogomem_start_addr; + bogomem_bank.flags |= SAEC_Memory_addrbank_flag_NOALLOC; + + bogomem_aliasing_offset = memsize1; //OWN + //need_hardreset = true; + } + bogomem_aliasing = 1; + } else if ((SAEV_config.chipset.mask & SAEC_Config_Chipset_Mask_ECS_AGNUS) == 0 && SAEV_config.chipset.jumper1MbChip) { + if ((chipmem_bank.allocated != SAEV_config.memory.chipSize || bogomem_bank.allocated != SAEV_config.memory.bogoSize)) { + mapped_free(chipmem_bank); + mapped_free(bogomem_bank); + //bogomem_bank.allocated = 0; + var memsize1 = chipmem_bank.allocated = SAEV_config.memory.chipSize; + var memsize2 = bogomem_bank.allocated = SAEV_config.memory.bogoSize; + chipmem_bank.mask = chipmem_bank.allocated - 1; + chipmem_bank.start = chipmem_start_addr; + chipmem_full_mask = chipmem_bank.allocated - 1; + chipmem_full_size = chipmem_bank.allocated; + chipmem_bank.allocated = memsize1 + memsize2; + mapped_malloc(chipmem_bank); + chipmem_bank.allocated = SAEV_config.memory.chipSize; + + //bogomem_bank.baseaddr = chipmem_bank.baseaddr + memsize1; //ATT + + bogomem_bank.baseaddr = chipmem_bank.baseaddr; + bogomem_bank.mask = bogomem_bank.allocated - 1; + bogomem_bank.start = chipmem_bank.start + SAEV_config.memory.chipSize; + bogomem_bank.flags |= SAEC_Memory_addrbank_flag_NOALLOC; + + bogomem_aliasing_offset = memsize1; //OWN + //need_hardreset = true; + } + bogomem_aliasing = 2; + } + } + if (bogomem_aliasing) + SAEF_log("memory.allocate() %dK chip/%dK bogo-ram to %dK chip-ram aliasing enabled", SAEV_config.memory.chipSize >> 10, SAEV_config.memory.bogoSize >> 10, chipmem_full_size >> 10); + + if (chipmem_bank.allocated != SAEV_config.memory.chipSize || bogoreset) { + mapped_free(chipmem_bank); + chipmem_bank.flags &= ~SAEC_Memory_addrbank_flag_NOALLOC; + if (SAEV_config.memory.chipSize > 2 * 1024 * 1024) { + if (SAEV_config.memory.z2FastSize >= 524288) SAER.expansion.free_fastmemory_ext(0); + //if (currprefs.fastmem2_size >= 524288) SAER.expansion.free_fastmemory_ext(1); + } + + var memsize = chipmem_bank.allocated = chipmem_full_size = SAEV_config.memory.chipSize; + chipmem_full_mask = chipmem_bank.mask = chipmem_bank.allocated - 1; + chipmem_bank.start = chipmem_start_addr; + if (memsize < 0x100000) + memsize = 0x100000; + if (memsize > 0x100000 && memsize < 0x200000) + memsize = 0x200000; + chipmem_bank.allocated = memsize; + mapped_malloc(chipmem_bank); + chipmem_bank.allocated = SAEV_config.memory.chipSize; + /*if (chipmem_bank.baseaddr == 0) { + SAEF_error("Fatal error: out of memory for chipmem."); + chipmem_bank.allocated = 0; + } else*/ { + //need_hardreset = true; + if (memsize > chipmem_bank.allocated) { + //memset(chipmem_bank.baseaddr + chipmem_bank.allocated, 0xff, memsize - chipmem_bank.allocated); + SAEF_memset(chipmem_bank.baseaddr,chipmem_bank.allocated, 0xff, memsize - chipmem_bank.allocated); + } + } + chipmem_full_mask = chipmem_bank.allocated - 1; + if (SAEV_config.chipset.mask & SAEC_Config_Chipset_Mask_ECS_AGNUS) { + if (chipmem_bank.allocated < 0x100000) + chipmem_full_mask = 0x100000 - 1; + if (chipmem_bank.allocated > 0x100000 && chipmem_bank.allocated < 0x200000) + chipmem_full_mask = chipmem_bank.mask = 0x200000 - 1; + } + else if (SAEV_config.chipset.jumper1MbChip) + chipmem_full_mask = 0x80000 - 1; + } + SAER_Memory_chipData = chipmem_bank.baseaddr; + //SAEV_Memory_chipSizeReal = chipmem_full_size; + SAEV_Memory_chipMask = chipmem_full_mask; + + if (bogomem_bank.allocated != SAEV_config.memory.bogoSize || bogoreset) { + if (!(bogomem_bank.allocated == 0x200000 && SAEV_config.memory.bogoSize == 0x180000)) { + mapped_free(bogomem_bank); + bogomem_bank.flags &= ~SAEC_Memory_addrbank_flag_NOALLOC; + bogomem_bank.allocated = 0; + + bogomem_bank.allocated = SAEV_config.memory.bogoSize; + if (bogomem_bank.allocated >= 0x180000) + bogomem_bank.allocated = 0x200000; + bogomem_bank.mask = bogomem_bank.allocated - 1; + bogomem_bank.start = bogomem_start_addr; + + if (bogomem_bank.allocated) { + if (!mapped_malloc(bogomem_bank)) { + //SAEF_error("Out of memory for bogomem."); + //bogomem_bank.allocated = 0; + } + } + //need_hardreset = true; + } + } + /*if (mem25bit_bank.allocated != currprefs.mem25bit_size) { + mapped_free(mem25bit_bank); + + mem25bit_bank.allocated = currprefs.mem25bit_size; + mem25bit_bank.mask = mem25bit_bank.allocated - 1; + mem25bit_bank.start = 0x01000000; + if (mem25bit_bank.allocated) { + if (!mapped_malloc(mem25bit_bank)) { + SAEF_error("Out of memory for 25 bit memory."); + mem25bit_bank.allocated = 0; + } + } + need_hardreset = true; + }*/ + if (a3000lmem_bank.allocated != SAEV_config.memory.ramsey.lowSize) { + mapped_free(a3000lmem_bank); + + a3000lmem_bank.allocated = SAEV_config.memory.ramsey.lowSize; + a3000lmem_bank.mask = a3000lmem_bank.allocated - 1; + a3000lmem_bank.start = 0x08000000 - a3000lmem_bank.allocated; + if (a3000lmem_bank.allocated) { + if (!mapped_malloc(a3000lmem_bank)) { + //SAEF_error("Out of memory for a3000lowmem."); + //a3000lmem_bank.allocated = 0; + } + } + //need_hardreset = true; + } + if (a3000hmem_bank.allocated != SAEV_config.memory.ramsey.highSize) { + mapped_free(a3000hmem_bank); + + a3000hmem_bank.allocated = SAEV_config.memory.ramsey.highSize; + a3000hmem_bank.mask = a3000hmem_bank.allocated - 1; + a3000hmem_bank.start = 0x08000000; + if (a3000hmem_bank.allocated) { + if (!mapped_malloc(a3000hmem_bank)) { + //SAEF_error("Out of memory for a3000highmem."); + //a3000hmem_bank.allocated = 0; + } + } + //need_hardreset = true; + } + /*#ifdef CDTV + if (cardmem_bank.allocated != currprefs.cs_cdtvcard * 1024) { + mapped_free(cardmem_bank); + cardmem_bank.baseaddr = null; + + cardmem_bank.allocated = currprefs.cs_cdtvcard * 1024; + cardmem_bank.mask = cardmem_bank.allocated - 1; + cardmem_bank.start = 0xe00000; + if (cardmem_bank.allocated) { + if (!mapped_malloc(cardmem_bank)) { + SAEF_error("Out of memory for cardmem."); + cardmem_bank.allocated = 0; + } + } + cdtv_loadcardmem(cardmem_bank.baseaddr, cardmem_bank.allocated); + } + #endif*/ + + if (custmem1_bank.allocated != SAEV_config.memory.custom[0].size) { + mapped_free(custmem1_bank); + custmem1_bank.allocated = SAEV_config.memory.custom[0].size; + // custmem1 and 2 can have non-power of 2 size so only set correct mask if size is power of 2. + custmem1_bank.mask = singlebit(custmem1_bank.allocated) ? custmem1_bank.allocated - 1 : -1; + custmem1_bank.start = SAEV_config.memory.custom[0].addr; + if (custmem1_bank.allocated) { + if (!mapped_malloc(custmem1_bank)) + custmem1_bank.allocated = 0; + } + } + if (custmem2_bank.allocated != SAEV_config.memory.custom[1].size) { + mapped_free(custmem2_bank); + custmem2_bank.allocated = SAEV_config.memory.custom[1].size; + custmem2_bank.mask = singlebit(custmem2_bank.allocated) ? custmem2_bank.allocated - 1 : -1; + custmem2_bank.start = SAEV_config.memory.custom[1].addr; + if (custmem2_bank.allocated) { + if (!mapped_malloc(custmem2_bank)) + custmem2_bank.allocated = 0; + } + } + + /*#ifdef AGA + chipmem_bank_ce2.baseaddr = chipmem_bank.baseaddr; + #endif*/ + + //cpuboard_init(); + } + + function fill_ce_banks() { + var i = 0; + + if (SAEV_config.cpu.model <= SAEC_Config_CPU_Model_68010) { + //memset(ce_banktype, SAEC_Memory_banktype_FAST16, sizeof ce_banktype); + SAEF_memset(ce_banktype,0, SAEC_Memory_banktype_FAST16, 65536); + } else { + //memset(ce_banktype, SAEC_Memory_banktype_FAST32, sizeof ce_banktype); + SAEF_memset(ce_banktype,0, SAEC_Memory_banktype_FAST32, 65536); + } + + /*memset(ce_cachable, 0, sizeof ce_cachable); + memset(ce_cachable + (0x00200000 >> 16), 1 | 2, currprefs.fastmem_size >> 16); + memset(ce_cachable + (0x00c00000 >> 16), 1, currprefs.bogomem_size >> 16); + memset(ce_cachable + (z3fastmem_bank.start >> 16), 1 | 2, currprefs.z3fastmem_size >> 16); + memset(ce_cachable + (z3fastmem2_bank.start >> 16), 1 | 2, currprefs.z3fastmem2_size >> 16); + memset(ce_cachable + (a3000hmem_bank.start >> 16), 1 | 2, currprefs.mbresmem_high_size >> 16); + memset(ce_cachable + (a3000lmem_bank.start >> 16), 1 | 2, currprefs.mbresmem_low_size >> 16); + memset(ce_cachable + (mem25bit_bank.start >> 16), 1 | 2, currprefs.mem25bit_size >> 16);*/ + + SAEF_memset(ce_cachable,0, 0, 65536); + SAEF_memset(ce_cachable,0x00200000 >>> 16, 1 | 2, SAEV_config.memory.z2FastSize >>> 16); + SAEF_memset(ce_cachable,0x00c00000 >>> 16, 1, SAEV_config.memory.bogoSize >>> 16); + SAEF_memset(ce_cachable,SAER_Expansion_z3fastmem_bank.start >>> 16, 1 | 2, SAEV_config.memory.z3FastSize >>> 16); + //SAEF_memset(ce_cachable,z3fastmem2_bank.start >>> 16, 1 | 2, currprefs.z3fastmem2_size >>> 16); + SAEF_memset(ce_cachable,a3000hmem_bank.start >>> 16, 1 | 2, SAEV_config.memory.ramsey.highSize >>> 16); + SAEF_memset(ce_cachable,a3000lmem_bank.start >>> 16, 1 | 2, SAEV_config.memory.ramsey.lowSize >>> 16); + //SAEF_memset(ce_cachable,mem25bit_bank.start >>> 16, 1 | 2, currprefs.mem25bit_size >>> 16); + + //if (get_mem_bank(0).flags & SAEC_Memory_addrbank_flag_CHIPRAM) { + if (mem_banks[0].flags & SAEC_Memory_addrbank_flag_CHIPRAM) { + for (i = 0; i < (0x200000 >>> 16); i++) { + ce_banktype[i] = (SAEV_config.chipset.mbdmac || (SAEV_config.chipset.mask & SAEC_Config_Chipset_Mask_AGA)) ? SAEC_Memory_banktype_CHIP32 : SAEC_Memory_banktype_CHIP16; + } + } + if (!SAEV_config.chipset.bogomemIsFast) { + for (i = (0xc00000 >>> 16); i < (0xe00000 >>> 16); i++) + ce_banktype[i] = ce_banktype[0]; + for (i = (bogomem_bank.start >>> 16); i < ((bogomem_bank.start + bogomem_bank.allocated) >>> 16); i++) + ce_banktype[i] = ce_banktype[0]; + } + for (i = (0xd00000 >>> 16); i < (0xe00000 >>> 16); i++) + ce_banktype[i] = SAEC_Memory_banktype_CHIP16; + for (i = (0xa00000 >>> 16); i < (0xc00000 >>> 16); i++) { + ce_banktype[i] = SAEC_Memory_banktype_CIA; + //var b = get_mem_bank(i << 16); + var b = mem_banks[i]; + if (!(b.flags & SAEC_Memory_addrbank_flag_CIA)) { + ce_banktype[i] = SAEC_Memory_banktype_FAST32; + ce_cachable[i] = 1; + } + } + // CD32 ROM is 16-bit + /*if (currprefs.cs_cd32cd) { + for (i = (0xe00000 >>> 16); i < (0xe80000 >>> 16); i++) + ce_banktype[i] = SAEC_Memory_banktype_FAST16; + for (i = (0xf80000 >>> 16); i <= (0xff0000 >>> 16); i++) + ce_banktype[i] = SAEC_Memory_banktype_FAST16; + }*/ + // A4000T NCR is 32-bit + if (SAEV_config.chipset.mbdmac == 2) { + ce_banktype[0xdd0000 >>> 16] = SAEC_Memory_banktype_FAST32; + } + if (SAEV_config.cpu.addressSpace24) { + for (i = 1; i < 256; i++) { + //memcpy(&ce_banktype[i * 256], &ce_banktype[0], 256); + for (var j = 0; j < 256; j++) ce_banktype[i * 256 + j] = ce_banktype[j]; + } + } + } + + this.mapOverlay = function(chip) { + var size = chipmem_bank.allocated >= 0x180000 ? (chipmem_bank.allocated >>> 16) : 32; + if (bogomem_aliasing) + size = 8; + + var cb = chipmem_bank; + if (chip) { + map_banks(SAEV_Memory_dummyBank, 0, size, 0); + if ((SAEV_config.chipset.mask & SAEC_Config_Chipset_Mask_ECS_AGNUS) && bogomem_bank.allocated == 0) { + map_banks(cb, 0, size, chipmem_bank.allocated); + var start = chipmem_bank.allocated >>> 16; + if (chipmem_bank.allocated < 0x100000) { + if (SAEV_config.chipset.jumper1MbChip) { + var dummy = (0x100000 - chipmem_bank.allocated) >>> 16; + map_banks(chipmem_dummy_bank, start, dummy, 0); + map_banks(chipmem_dummy_bank, start + 16, dummy, 0); + } + } else if (chipmem_bank.allocated < 0x200000 && chipmem_bank.allocated > 0x100000) { + var dummy = (0x200000 - chipmem_bank.allocated) >>> 16; + map_banks(chipmem_dummy_bank, start, dummy, 0); + } + } else + map_banks(cb, 0, 32, chipmem_bank.allocated); + } else { + var rb = null; + if (size < 32 && bogomem_aliasing == 0) + size = 32; + //cb = get_mem_bank_real(0xf00000); + cb = mem_banks[0xf00000 >>> 16]; + if (rb === null && cb && (cb.flags & SAEC_Memory_addrbank_flag_ROM) && get16(0xf00000) == 0x1114) + rb = cb; + //cb = get_mem_bank_real(0xe00000); + cb = mem_banks[0xe00000 >>> 16]; + if (rb === null && cb && (cb.flags & SAEC_Memory_addrbank_flag_ROM) && get16(0xe00000) == 0x1114) + rb = cb; + if (rb === null) + rb = kickmem_bank; + map_banks(rb, 0, size, 0x80000); + } + fill_ce_banks(); + //cpuboard_overlay_override(); + if (check_address(SAER_CPU_regs.pc, 4)) + SAER.cpu.setPC_normal(SAER_CPU_getPC()); + } + + this.getz2size = function(p) { + var start = p.memory.z2FastSize; + /*if (p.rtgmem_size && gfxboard_get_configtype(p.rtgmem_type) == 2) { + while (start & (p.rtgmem_size - 1) && start < 8 * 1024 * 1024) + start += 1024 * 1024; + if (start + p.rtgmem_size > 8 * 1024 * 1024) + return -1; + } + start += p.rtgmem_size;*/ + return start; + } + this.getz2endaddr = function() { + var start = SAEV_config.memory.z2FastSize; + /*if (currprefs.rtgmem_size && gfxboard_get_configtype(currprefs.rtgmem_type) == 2) { + if (!start) + start = 0x00200000; + while (start & (currprefs.rtgmem_size - 1) && start < 4 * 1024 * 1024) + start += 1024 * 1024; + }*/ + return start + 2 * 1024 * 1024; + } + + function restore_roms() { + var err; + + //protect_roms(false); + SAEF_log("memory.restore_roms() loading '%s'...", SAEV_config.memory.rom.name); + //kickstart_rom = true; + + a1000_handle_kickstart(0); + //xfree(a1000_bootrom); + a1000_bootrom = null; + a1000_kickstart_mode = false; + + //need_hardreset = true; + mapped_free(extendedkickmem_bank); extendedkickmem_bank.allocated = 0; + mapped_free(extendedkickmem2_bank); extendedkickmem2_bank.allocated = 0; + extendedkickmem_type = 0; + err = load_extendedkickstart(SAEV_config.memory.extRom, 0); + if (err != SAEE_None) return err; + //load_extendedkickstart(currprefs.romextfile, 0); + //load_extendedkickstart(currprefs.romextfile2, EXTENDED_ROM_CDTV); + + kickmem_bank.mask = ROM_SIZE_512 - 1; + if ((err = load_kickstart()) == SAEE_None) { + if (!aros) { + var rd = SAER.roms.getromdatabydata(kickmem_bank.baseaddr, kickmem_bank.allocated); + if (rd !== null) { + SAEF_log("memory.restore_roms() identified rom as '%s'", rd.name); + if ((rd.cpu & 8) && SAEV_config.cpu.model < SAEC_Config_CPU_Model_68030) { + //notify_user(NUMSG_KS68030PLUS); uae_restart(-1, null); + return SAEE_CPU_Requires68030; + } else if ((rd.cpu & 3) == 3 && SAEV_config.cpu.model != SAEC_Config_CPU_Model_68030) { + //notify_user(NUMSG_KS68030); uae_restart(-1, null); + return SAEE_CPU_Requires68030; + } else if ((rd.cpu & 3) == 1 && SAEV_config.cpu.model < SAEC_Config_CPU_Model_68020) { + //notify_user(NUMSG_KS68EC020); uae_restart(-1, null); + return SAEE_CPU_Requires680EC20; + } else if ((rd.cpu & 3) == 2 && (SAEV_config.cpu.model < SAEC_Config_CPU_Model_68020 || SAEV_config.cpu.addressSpace24)) { + //notify_user(NUMSG_KS68020); uae_restart(-1, null); + return SAEE_CPU_Requires68020; + } + if (rd.cloanto) + SAEV_Memory_cloantoRom = true; + /*kickstart_rom = false; + if ((rd.type & (SAEC_RomType_SPECIALKICK | SAEC_RomType_KICK)) == SAEC_RomType_KICK) + kickstart_rom = true;*/ + if ((rd.cpu & 4) && SAEV_config.chipset.compatible != SAEC_Config_Chipset_Compatible_Manual) { + //A4000 ROM = need ramsey, gary and ide + if (SAEV_config.chipset.ramseyRev < 0) + SAEV_config.chipset.ramseyRev = 0x0f; + SAEV_config.chipset.fatGaryRev = 0; + if (SAEV_config.chipset.ide != SAEC_Config_Chipset_IDE_A4000) + SAEV_config.chipset.ide = -1; + } + } else + SAEF_log("memory.restore_roms() unknown rom '%s' loaded", SAEV_config.memory.rom.name); + } + } else { + /*if (SAEV_config.memory.rom.name.length > 0) { + SAEF_error("Failed to open '%s'", SAEV_config.memory.rom.name); + notify_user(NUMSG_NOROM); + }*/ + //load_kickstart_replacement(); + } + if (err == SAEE_None) //OWN + patch_kick(); + + SAEF_log("memory.restore_roms() ...done."); + //protect_roms(true); + return err; + } + + function setup() { //memory_init() + init_mem_banks(); + SAER.devices.virtualdevice_init(); + + chipmem_bank.allocated = 0; + chipmem_bank.baseaddr = null; + + bogomem_bank.allocated = 0; + bogomem_bank.baseaddr = null; + //bogomem_aliasing_offset = 0; //OWN + + extendedkickmem_bank.allocated = 0; + extendedkickmem_bank.baseaddr = null; + extendedkickmem2_bank.allocated = 0; + extendedkickmem2_bank.baseaddr = null; + extendedkickmem_type = 0; + + //mem25bit_bank.allocated = 0; + //mem25bit_bank.baseaddr = null; + a3000lmem_bank.allocated = 0; + a3000lmem_bank.baseaddr = null; + a3000hmem_bank.allocated = 0; + a3000hmem_bank.baseaddr = null; + + //cardmem_bank.allocated = 0; + //cardmem_bank.baseaddr = null; + custmem1_bank.allocated = 0; + custmem1_bank.baseaddr = null; + custmem2_bank.allocated = 0; + custmem2_bank.baseaddr = null; + + kickmem_bank.allocated = ROM_SIZE_512; + kickmem_bank.baseaddr = null; + mapped_malloc(kickmem_bank); + //memset(kickmem_bank.baseaddr, 0, ROM_SIZE_512); + SAEF_memset(kickmem_bank.baseaddr,0, 0, ROM_SIZE_512); + + //currprefs.romfile = ""; + //currprefs.romextfile = ""; + + //cpuboard_reset(); + + /*#ifdef ACTION_REPLAY + action_replay_unload (0); + action_replay_load (); + action_replay_init (1); + #ifdef ACTION_REPLAY_HRTMON + hrtmon_load(); + #endif + #endif*/ + } + + this.cleanup = function() { //memory_cleanup() + //mapped_free(mem25bit_bank); mem25bit_bank.baseaddr = null; + mapped_free(a3000lmem_bank); a3000lmem_bank.baseaddr = null; + mapped_free(a3000hmem_bank); a3000hmem_bank.baseaddr = null; + mapped_free(bogomem_bank); bogomem_bank.baseaddr = null; + mapped_free(kickmem_bank); kickmem_bank.baseaddr = null; + //xfree(a1000_bootrom); + a1000_bootrom = null; + a1000_kickstart_mode = false; + mapped_free(chipmem_bank); chipmem_bank.baseaddr = null; + /*#ifdef CDTV + if (cardmem_bank.baseaddr !== null) { + cdtv_savecardmem(cardmem_bank.baseaddr, cardmem_bank.allocated); + mapped_free(cardmem_bank); cardmem_bank.baseaddr = null; + } + #endif*/ + mapped_free(custmem1_bank); custmem1_bank.baseaddr = null; + mapped_free(custmem2_bank); custmem2_bank.baseaddr = null; + + //cpuboard_cleanup(); + + /*#ifdef ACTION_REPLAY + action_replay_cleanup(); + #endif + #ifdef ARCADIA + arcadia_unmap(); + #endif*/ + } + + function map_banks_set(bank, start, size, realsize) { + bank.start = start << 16; //OWN + bank.startmask = start << 16; + map_banks(bank, start, size, realsize); + } + this.reset = function(hardreset) { //memory_reset() + //need_hardreset = false; + rom_write_enabled = true; + /* Use changed_prefs, as m68k_reset is called later. */ + /*if (lastAaddressSpace24 != SAEV_config.cpu.addressSpace24) { + lastAaddressSpace24 = SAEV_config.cpu.addressSpace24; + need_hardreset = true; + }*/ + + if (mem_hardreset > 2) + setup(); + + SAEV_Memory_defaultXLate_cnt = 0; //OWN + SAEV_Memory_defaultXLate_recursive = 0; //OWN + dummylog_cnt = 0; //OWN + gary_wait_cnt = 50; //OWN + + /*SAEV_config.memory.chipSize = changed_prefs.chipmem_size; + SAEV_config.memory.bogoSize = changed_prefs.bogomem_size; + SAEV_config.memory.ramsey.lowSize = changed_prefs.mbresmem_low_size; + SAEV_config.memory.ramsey.highSize = changed_prefs.mbresmem_high_size; + SAEV_config.chipset.mirrorE0 = changed_prefs.cs_ksmirror_e0; + SAEV_config.chipset.mirrorA8 = changed_prefs.cs_ksmirror_a8; + currprefs.cs_cdtvram = changed_prefs.cs_cdtvram; + currprefs.cs_cdtvcard = changed_prefs.cs_cdtvcard; + SAEV_config.chipset.a1000ram = changed_prefs.cs_a1000ram; + SAEV_config.chipset.ide = changed_prefs.cs_ide; + SAEV_config.chipset.fatGaryRev = changed_prefs.cs_fatgaryrev; + SAEV_config.chipset.ramseyRev = changed_prefs.cs_ramseyrev;*/ + + //cpuboard_reset(); + + var gayleorfatgary = (SAEV_config.chipset.mask & SAEC_Config_Chipset_Mask_AGA) != 0 || SAEV_config.chipset.pcmcia || SAEV_config.chipset.ide > 0 || SAEV_config.chipset.mbdmac; + + init_mem_banks(); + allocate(); + chipmem_setindirect(); + + if (mem_hardreset > 1 || (a1000_bootrom !== null && hardreset && SAER.cpu.is_hardreset()) + // || _tcscmp (currprefs.romfile, changed_prefs.romfile) != 0 + // || _tcscmp (currprefs.romextfile, changed_prefs.romextfile) != 0 + ) { + var err = restore_roms(); + if (err != SAEE_None) return err; + } + /*if ((SAEV_Memory_cloantoRom || extendedkickmem_bank.allocated) && SAEV_config.memory.maprom && SAEV_config.memory.maprom < 0x01000000) { + SAEV_config.memory.maprom = 0x00a80000; + if (extendedkickmem2_bank.allocated) // can't do if 2M ROM + SAEV_config.memory.maprom = 0; + }*/ + + map_banks(SAEV_Custom_bank, 0xC0, 0xE0 - 0xC0, 0); + map_banks(SAEV_CIA_bank, 0xA0, 32, 0); + if (!SAEV_config.chipset.a1000ram && SAEV_config.chipset.rtc.type != SAEC_Config_RTC_Type_MSM6242B_A2000) + /* D80000 - DDFFFF not mapped (A1000 or A2000 = custom chips) */ + map_banks(SAEV_Memory_dummyBank, 0xD8, 6, 0); + + /* map "nothing" to 0x200000 - 0x9FFFFF (0xBEFFFF if Gayle or Fat Gary) */ + var bnk = chipmem_bank.allocated >>> 16; + if (bnk < 0x20 + (SAEV_config.memory.z2FastSize >>> 16)) + bnk = 0x20 + (SAEV_config.memory.z2FastSize >>> 16); + var bnk_end = gayleorfatgary ? 0xBF : 0xA0; + map_banks(SAEV_Memory_dummyBank, bnk, bnk_end - bnk, 0); + if (gayleorfatgary) { + // a3000 or a4000 = custom chips from 0xc0 to 0xd0 + if (SAEV_config.chipset.ide == SAEC_Config_Chipset_IDE_A4000 || SAEV_config.chipset.mbdmac) + map_banks(SAEV_Memory_dummyBank, 0xd0, 8, 0); + else + map_banks(SAEV_Memory_dummyBank, 0xc0, 0xd8 - 0xc0, 0); + } + + if (bogomem_bank.baseaddr !== null) { + var t = SAEV_config.memory.bogoSize >>> 16; + if (t > 0x1C) + t = 0x1C; + if (t > 0x18 && ((SAEV_config.chipset.mask & SAEC_Config_Chipset_Mask_AGA) || (SAEV_config.cpu.model >= SAEC_Config_CPU_Model_68020 && SAEV_config.cpu.addressSpace24 == false))) + t = 0x18; + if (bogomem_aliasing == 2) + map_banks(bogomem_bank, 0x08, t, 0); + else + map_banks(bogomem_bank, 0xC0, t, 0); + } + if (SAEV_config.chipset.ide || SAEV_config.chipset.pcmcia) { + if (SAEV_config.chipset.ide == SAEC_Config_Chipset_IDE_A600A1200 || SAEV_config.chipset.pcmcia) { + map_banks(SAEV_Gayle_bank, 0xD8, 6, 0); + map_banks(SAEV_Gayle2_bank, 0xDD, 2, 0); + } + SAER.gayle.map_pcmcia(); + if (SAEV_config.chipset.ide == SAEC_Config_Chipset_IDE_A4000 || SAEV_config.chipset.mbdmac == 2) + map_banks(SAEV_Gayle_bank, 0xDD, 1, 0); + if (SAEV_config.chipset.ide < 0 && !SAEV_config.chipset.pcmcia) + map_banks(SAEV_Gayle_bank, 0xD8, 6, 0); + if (SAEV_config.chipset.ide < 0) + map_banks(SAEV_Gayle_bank, 0xDD, 1, 0); + } + if (SAEV_config.chipset.rtc.type == SAEC_Config_RTC_Type_MSM6242B_A2000) // A2000 clock + map_banks(SAEV_RTC_bank, 0xD8, 4, 0); + //if (SAEV_config.chipset.rtc.type == SAEC_Config_RTC_Type_MSM6242B || SAEV_config.chipset.rtc.type == SAEC_Config_RTC_Type_RF5C01A || currprefs.cs_cdtvram) + if (SAEV_config.chipset.rtc.type == SAEC_Config_RTC_Type_MSM6242B || SAEV_config.chipset.rtc.type == SAEC_Config_RTC_Type_RF5C01A) + map_banks(SAEV_RTC_bank, 0xDC, 1, 0); + else if (SAEV_config.chipset.mirrorA8 || SAEV_config.chipset.ide > 0 || SAEV_config.chipset.pcmcia) + map_banks(SAEV_RTC_bank, 0xDC, 1, 0); /* none clock */ + + if (SAEV_config.chipset.fatGaryRev >= 0 || SAEV_config.chipset.ramseyRev >= 0) + map_banks(SAEV_MBRes_bank, 0xDE, 1, 0); + + /*#ifdef CD32 + if (currprefs.cs_cd32c2p || currprefs.cs_cd32cd || currprefs.cs_cd32nvram) { + map_banks(akiko_bank, AKIKO_BASE >>> 16, 1, 0); + map_banks(SAEV_Gayle2_bank, 0xDD, 2, 0); + } + #endif + #ifdef CDTV + if (currprefs.cs_cdtvcr) { + map_banks(cdtvcr_bank, 0xB8, 1, 0); + } else if (currprefs.cs_cdtvcd) { + cdtv_check_banks(); + } + #endif + #ifdef A2091 + if (SAEV_config.chipset.mbdmac == 1) + a3000scsi_reset(); + #endif*/ + + //if (mem25bit_bank.baseaddr !== null) map_banks(mem25bit_bank, mem25bit_bank.start >>> 16, mem25bit_bank.allocated >>> 16, 0); + if (a3000lmem_bank.baseaddr !== null) map_banks(a3000lmem_bank, a3000lmem_bank.start >>> 16, a3000lmem_bank.allocated >>> 16, 0); + if (a3000hmem_bank.baseaddr !== null) map_banks(a3000hmem_bank, a3000hmem_bank.start >>> 16, a3000hmem_bank.allocated >>> 16, 0); + /*#ifdef CDTV + if (cardmem_bank.baseaddr !== null) map_banks(cardmem_bank, cardmem_bank.start >>> 16, cardmem_bank.allocated >>> 16, 0); + #endif*/ + //cpuboard_map(); + map_banks_set(kickmem_bank, 0xF8, 8, 0); + /*if (SAEV_config.memory.maprom) { + if (!cpuboard_maprom()) + map_banks_set(kickram_bank, SAEV_config.memory.maprom >>> 16, extendedkickmem2_bank.allocated ? 32 : (extendedkickmem_bank.allocated ? 16 : 8), 0); + }*/ + /* map beta Kickstarts at 0x200000/0xC00000/0xF00000 */ + if (kickmem_bank.baseaddr[0] == 0x11 && kickmem_bank.baseaddr[2] == 0x4e && kickmem_bank.baseaddr[3] == 0xf9 && kickmem_bank.baseaddr[4] == 0x00) { + var addr = kickmem_bank.baseaddr[5]; + if (addr == 0x20 && SAEV_config.memory.chipSize <= 0x200000 && SAEV_config.memory.z2FastSize == 0) + map_banks_set(kickmem_bank, addr, 8, 0); + if (addr == 0xC0 && SAEV_config.memory.bogoSize == 0) + map_banks_set(kickmem_bank, addr, 8, 0); + if (addr == 0xF0) + map_banks_set(kickmem_bank, addr, 8, 0); + } + + if (a1000_bootrom !== null) + a1000_handle_kickstart(1); + + //#ifdef AUTOCONFIG + map_banks(SAER_Expansion_expamem_bank, 0xE8, 1, 0); + //#endif + + if (a3000_f0) + map_banks_set(extendedkickmem_bank, 0xf0, 1, 0); + + /* Map the chipmem into all of the lower 8MB */ + this.mapOverlay(true); + + switch (extendedkickmem_type) { + case EXTENDED_ROM_KS: + map_banks_set(extendedkickmem_bank, 0xE0, 8, 0); + break; + //#ifdef CDTV + case EXTENDED_ROM_CDTV: + map_banks_set(extendedkickmem_bank, 0xF0, extendedkickmem_bank.allocated == 2 * ROM_SIZE_512 ? 16 : 8, 0); + break; + //#endif + //#ifdef CD32 + case EXTENDED_ROM_CD32: + map_banks_set(extendedkickmem_bank, 0xE0, 8, 0); + break; + //#endif + } + + //#ifdef AUTOCONFIG + if (SAER.autoconf.need_uae_boot_rom()) // && currprefs.uaeboard < 2) + map_banks_set(SAER_AutoConf_bank, SAEV_AutoConf_base >>> 16, 1, 0); + //#endif + + //if ((SAEV_Memory_cloantoRom || SAEV_config.chipset.mirrorE0) && SAEV_config.memory.maprom != 0xe00000 && !extendedkickmem_type) + if ((SAEV_Memory_cloantoRom || SAEV_config.chipset.mirrorE0) && !extendedkickmem_type) + map_banks(kickmem_bank, 0xE0, 8, 0); + + if (SAEV_config.chipset.mirrorA8) { + if (extendedkickmem2_bank.allocated) { + map_banks_set(extendedkickmem2_bank, 0xa8, 16, 0); + } else { + //var rd = getromdatabypath(currprefs.cartfile); + //if (!rd || rd.id != 63) + { + if (extendedkickmem_type == EXTENDED_ROM_CD32 || extendedkickmem_type == EXTENDED_ROM_KS) + map_banks(extendedkickmem_bank, 0xb0, 8, 0); + else + map_banks(kickmem_bank, 0xb0, 8, 0); + map_banks(kickmem_bank, 0xa8, 8, 0); + } + } + } + + /*#ifdef ARCADIA + if (is_arcadia_rom (currprefs.romextfile) == ARCADIA_BIOS) { + if (_tcscmp (currprefs.romextfile, changed_prefs.romextfile) != 0) + memcpy (currprefs.romextfile, changed_prefs.romextfile, sizeof currprefs.romextfile); + if (_tcscmp (currprefs.cartfile, changed_prefs.cartfile) != 0) + memcpy (currprefs.cartfile, changed_prefs.cartfile, sizeof currprefs.cartfile); + arcadia_unmap (); + is_arcadia_rom (currprefs.romextfile); + is_arcadia_rom (currprefs.cartfile); + arcadia_map_banks (); + } + #endif + #ifdef ACTION_REPLAY + #ifdef ARCADIA + if (!arcadia_bios) { + #endif + action_replay_memory_reset (); + #ifdef ARCADIA + } + #endif + #endif*/ + + for (var i = 0; i < 2; i++) { + var ptr = SAEV_config.memory.custom[i]; + if (ptr.size) { + map_banks(i == 0 ? custmem1_bank : custmem2_bank, ptr.addr >>> 16, ptr.size >>> 16, 0); + if (ptr.mask) { + for (var j = ptr.addr; j & ptr.mask; j += ptr.size) { + map_banks(i == 0 ? custmem1_bank : custmem2_bank, j >>> 16, ptr.size >>> 16, 0); + } + } + } + } + + if (mem_hardreset) + this.clear(); + + return SAEE_None; + } + + this.clear = function() { //memory_clear() + mem_hardreset = 0; + + /*if (chipmem_bank.baseaddr) memset(chipmem_bank.baseaddr, 0, chipmem_bank.allocated); + if (bogomem_bank.baseaddr) memset(bogomem_bank.baseaddr, 0, bogomem_bank.allocated); + if (mem25bit_bank.baseaddr) memset(mem25bit_bank.baseaddr, 0, mem25bit_bank.allocated); + if (a3000lmem_bank.baseaddr) memset(a3000lmem_bank.baseaddr, 0, a3000lmem_bank.allocated); + if (a3000hmem_bank.baseaddr) memset(a3000hmem_bank.baseaddr, 0, a3000hmem_bank.allocated);*/ + + if (chipmem_bank.baseaddr !== null) SAEF_memset(chipmem_bank.baseaddr,0, 0, chipmem_bank.allocated); + if (bogomem_bank.baseaddr !== null) SAEF_memset(bogomem_bank.baseaddr,0, 0, bogomem_bank.allocated); + //if (mem25bit_bank.baseaddr !== null) SAEF_memset(mem25bit_bank.baseaddr,0, 0, mem25bit_bank.allocated); + if (a3000lmem_bank.baseaddr !== null) SAEF_memset(a3000lmem_bank.baseaddr,0, 0, a3000lmem_bank.allocated); + if (a3000hmem_bank.baseaddr !== null) SAEF_memset(a3000hmem_bank.baseaddr,0, 0, a3000hmem_bank.allocated); + + SAER.expansion.clear(); + //cpuboard_clear(); + } + + this.hardreset = function(mode) { //memory_hardreset() + if (mode + 1 > mem_hardreset) + mem_hardreset = mode + 1; + } + + /*-----------------------------------------------------------------------*/ + + this.ks12orolder = function() { + return kickstart_version > 0 && kickstart_version < 34; /* < 1.3 */ + } + this.ks11orolder = function() { + return kickstart_version > 0 && kickstart_version < 33; /* < 1.2 */ + } + + /*-----------------------------------------------------------------------*/ + + // do not map if it conflicts with custom banks + this.map_banks_cond = function(bank, start, size, realsize) { + for (var i = 0; i < SAEV_config.memory.custom.length; i++) { + var cstart = SAEV_config.memory.custom[i].addr >>> 16; + if (!cstart) + continue; + var csize = SAEV_config.memory.custom[i].size >>> 16; + if (!csize) + continue; + if (start <= cstart && start + size >= cstart) + return; + if (cstart <= start && (cstart + size >= start || start + size > cstart)) + return; + } + map_banks(bank, start, size, realsize); + } + + function map_banks2(bank, start, size, realsize, quick) { + var bnr, old; + var hioffs = 0, endhioffs = 0x100; + var realstart = start; + var orig_bank = null; + + //if (quick <= 0) old = debug_bankchange (-1); + //flush_icache_hard(0, 3); /* JIT, Sure don't want to keep any old mappings around! */ + + if (!realsize) + realsize = size << 16; + + if ((size << 16) < realsize) + SAEF_warn("memory.map_banks2() Broken mapping, size=%x, realsize=%x, start=%x", size, realsize, start); + + if (!ADDRESS_SPACE_24BIT) { + if (start >= 0x100) { + var real_left = 0; + for (bnr = start; bnr < start + size; bnr++) { + if (!real_left) { + realstart = bnr; + real_left = realsize >>> 16; + } + mem_banks[bnr] = bank; //put_mem_bank(bnr << 16, bank, realstart << 16); + real_left--; + } + //if (quick <= 0) debug_bankchange (old); + return; + } + } + //if (lastAaddressSpace24) + if (SAEV_config.cpu.addressSpace24) + endhioffs = 0x10000; + if (ADDRESS_SPACE_24BIT) + endhioffs = 0x100; + + for (hioffs = 0; hioffs < endhioffs; hioffs += 0x100) { + var real_left = 0; + for (bnr = start; bnr < start + size; bnr++) { + if (!real_left) { + realstart = bnr + hioffs; + real_left = realsize >>> 16; + } + //put_mem_bank((bnr + hioffs) << 16, bank, realstart << 16); + mem_banks[bnr + hioffs] = bank; + real_left--; + } + } + //if (quick <= 0) debug_bankchange (old); + fill_ce_banks(); + } + function map_banks(bank, start, size, realsize) { + map_banks2(bank, start, size, realsize, 0); + } + SAER_Memory_mapBanks = map_banks; + + + function validate_banks_z2(bank, start, size) { + if (start < 0x20 || (start >= 0xa0 && start < 0xe9) || start >= 0xf0) { + SAEF_error("memory.validate_banks_z2() bank '%s' with invalid start address %08X", bank.name, start << 16); + SAER.m68k.cpu_halt(SAEC_CPU_halt_AUTOCONFIG_CONFLICT); + return false; + } + if (start >= 0xe9) { + if (start + size > 0xf0) { + SAEF_error("memory.validate_banks_z2() bank '%s' with invalid region %08x - %08X", bank.name, start << 16, (start + size) << 16); + SAER.m68k.cpu_halt(SAEC_CPU_halt_AUTOCONFIG_CONFLICT); + return false; + } + } else { + if (start + size > 0xa0) { + SAEF_error("memory.validate_banks_z2() bank '%s' with invalid region %08x - %08X", bank.name, start << 16, (start + size) << 16); + SAER.m68k.cpu_halt(SAEC_CPU_halt_AUTOCONFIG_CONFLICT); + return false; + } + } + if (size <= 0 || size > 0x80) { + SAEF_error("memory.validate_banks_z2() bank '%s' with invalid size %08x", bank.name, size); + SAER.m68k.cpu_halt(SAEC_CPU_halt_AUTOCONFIG_CONFLICT); + return false; + } + for (var i = start; i < start + size; i++) { + //var ab = get_mem_bank(start << 16); + var ab = mem_banks[start]; + if (ab !== SAEV_Memory_dummyBank) { + SAEF_error("memory.validate_banks_z2() bank '%s' attempting to override existing memory bank '%s' at %08X", bank.name, ab.name, i << 16); + return false; + } + } + return true; + } + this.map_banks_z2 = function(bank, start, size) { + if (validate_banks_z2(bank, start, size)) + map_banks(bank, start, size, 0); + } + + function validate_banks_z3(bank, start, size) { + if (start < 0x1000 || size <= 0) { + SAEF_error("memory.validate_banks_z3() invalid bank '%s' start=%08x size=%08x", bank.name, start << 16, size << 16); + SAER.m68k.cpu_halt(SAEC_CPU_halt_AUTOCONFIG_CONFLICT); + return false; + } + if (size > 0x4000 || start + size > 0xf000) { + SAEF_error("memory.validate_banks_z3() invalid bank '%s' start=%08x size=%08x", bank.name, start << 16, size << 16); + return false; + } + for (var i = start; i < start + size; i++) { + //var ab = get_mem_bank(start << 16); + var ab = mem_banks[start]; + if (ab !== SAEV_Memory_dummyBank && ab !== bank) { + SAEF_error("memory.validate_banks_z3() bank '%s' attempting to override existing memory bank '%s' at %08X", bank.name, ab.name, i << 16); + return false; + } + } + return true; + } + this.map_banks_z3 = function(bank, start, size) { + if (validate_banks_z3(bank, start, size)) + map_banks(bank, start, size, 0); + } + + /*void map_banks_quick (addrbank *bank, int start, int size, int realsize) { + map_banks2 (bank, start, size, realsize, 1); + } + void map_banks_nojitdirect (addrbank *bank, int start, int size, int realsize) { + map_banks2 (bank, start, size, realsize, -1); + }*/ + + /*-----------------------------------------------------------------------*/ + + function dump_xlate(addr) { + if (!mem_banks[addr >>> 16].check(addr, 1)) + return null; + return mem_banks[addr >>> 16].xlateaddr(addr); + } + + //const UAE_MEMORY_REGION_NAME_LENGTH = 64; + const UAE_MEMORY_REGIONS_MAX = 64; + const UAE_MEMORY_REGION_RAM = 1 << 0; + const UAE_MEMORY_REGION_ALIAS = 1 << 1; + const UAE_MEMORY_REGION_MIRROR = 1 << 2; + + const MEMORY_MIN_SUBBANK = 1024; + + function UaeMemoryRegion() { + this.start = 0; + this.size = 0; + this.name = ""; //[UAE_MEMORY_REGION_NAME_LENGTH]; + this.rom_name = ""; //[UAE_MEMORY_REGION_NAME_LENGTH]; + this.alias = 0; + this.flags = 0; + } + function UaeMemoryMap() { + this.regions = new Array(UAE_MEMORY_REGIONS_MAX); + this.num_regions = 0; + } + + function memory_map_dump_3(map, log) { + var i, j; + var a1 = mem_banks[0]; + var txt = ""; + + var imold = SAEV_config.memory.logIllegal; + SAEV_config.memory.logIllegal = false; + var max = SAEV_config.cpu.addressSpace24 ? 256 : 65536; + map.num_regions = 0; + j = 0; + for (i = 0; i < max + 1; i++) { + var a2 = null; + if (i < max) + a2 = mem_banks[i]; + if (a1 !== a2) { + var k, mirrored, mirrored2, size, size_out; + var size_ext; + var caddr; + var tmp; + var name = a1.name; + var sb = a1.sub_banks; + var sbi = 0; //OWN + var bankoffset = 0; + var region_size; + + k = j; + caddr = dump_xlate(k << 16); + mirrored = caddr !== null ? 1 : 0; + k++; + while (k < i && caddr !== null) { + if (dump_xlate(k << 16) === caddr) { + mirrored++; + } + k++; + } + mirrored2 = mirrored; + if (mirrored2 == 0) + mirrored2 = 1; + + while (bankoffset < 65536) { + var bankoffset2 = bankoffset; + if (sb !== null) { + if (sb[sbi].bank === null) + break; + var daddr = ((j << 16) | bankoffset) >>> 0; + //a1 = get_sub_bank(&daddr); + a1 = SAER.memory.getSubBank({ value:daddr }); + name = a1.name; + for (;;) { + bankoffset2 += MEMORY_MIN_SUBBANK; + if (bankoffset2 >= 65536) + break; + daddr = ((j << 16) | bankoffset2) >>> 0; + //var dab = get_sub_bank(&daddr); + var dab = SAER.memory.getSubBank({ value:daddr }); + if (dab !== a1) + break; + } + //sb++; + sbi++; + size = (bankoffset2 - bankoffset) >> 10;// / 1024; + region_size = size << 10; // * 1024; + } else { + size = (i - j) << (16 - 10); + region_size = Math.floor(((i - j) << 16) / mirrored2); + } + + if (name === null) + name = ""; + + size_out = size; + size_ext = 'K'; + if (j >= 256 && (Math.floor(size_out / mirrored2) >= 1024) && !(Math.floor(size_out / mirrored2) & 1023)) { + //size_out /= 1024; + size_out >>= 10; + size_ext = 'M'; + } + //#if 1 + txt = sprintf("%08X %7d%s/%d = %7d%s %s", ((j << 16) | bankoffset) >>> 0, size_out, size_ext, mirrored, mirrored ? Math.floor(size_out / mirrored) : size_out, size_ext, name); + //#endif + tmp = ""; + if (0 && (a1.flags & SAEC_Memory_addrbank_flag_ROM) && mirrored) { + var crc = 0xffffffff; + var crcAddr = ((j << 16) | bankoffset) >>> 0; + var crcSize = Math.floor((size * 1024) / mirrored); + if (a1.check(crcAddr, crcSize)) { + crcAddr = a1.xlateaddr(crcAddr, crcSize); + //crc = get_crc32(crcAddr); + { + var crcData = new Uint8Array(crcSize); + for (var o = 0; o < crcSize; o++) crcData[o] = a1.get8(crcAddr + o); + crc = SAEF_crc32(crcData,0, crcSize); + } + } + txt += sprintf(" (%08X)", crc); + + var rd = SAER.roms.getromdatabycrc(crc); + /*if (rd !== null) { + tmp = "="; + tmp += SAER.roms.getromname(rd); + tmp += "\n"; + }*/ + if (rd !== null) { + txt += " = "+SAER.roms.getromname(rd); + } + } + + /*if (a1 !== SAEV_Memory_dummyBank) { + for (var m = 0; m < mirrored2; m++) { + UaeMemoryRegion *r = &map->regions[map->num_regions]; + r->start = (j << 16) + bankoffset + region_size * m; + r->size = region_size; + r->flags = 0; + r->memory = NULL; + r->memory = dump_xlate((j << 16) | bankoffset); + if (r->memory) + r->flags |= UAE_MEMORY_REGION_RAM; + // just to make it easier to spot in debugger + r->alias = 0xffffffff; + if (m >= 0) { + r->alias = j << 16; + r->flags |= UAE_MEMORY_REGION_ALIAS | UAE_MEMORY_REGION_MIRROR; + } + _stprintf(r->name, _T("%s"), name); + _stprintf(r->rom_name, _T("%s"), tmp); + map->num_regions += 1; + } + }*/ + //#if 1 + txt += "\n"; + if (log > 0) + SAEF_log(txt); + else if (log == 0) + console.log(txt); + + if (tmp.length) { + if (log > 0) + SAEF_log(tmp); + else if (log == 0) + console.log(tmp); + } + //#endif + if (sb === null) + break; + bankoffset = bankoffset2; + } + j = i; + a1 = a2; + } + } + //pci_dump(log); + SAEV_config.memory.logIllegal = imold; + } + function memory_map_dump_2(log) { + var map = new UaeMemoryMap(); + memory_map_dump_3(map, log); + + /*for (int i = 0; i < map.num_regions; i++) { + TCHAR txt[256]; + UaeMemoryRegion *r = &map.regions[i]; + int size = r->size / 1024; + TCHAR size_ext = 'K'; + int mirrored = 1; + int size_out = 0; + _stprintf (txt, _T("%08X %7u%c/%d = %7u%c %s\n"), r->start, size, size_ext, r->flags & UAE_MEMORY_REGION_RAM, size, size_ext, r->name); + if (log) + write_log (_T("%s"), txt); + else + console_out (txt); + if (r->rom_name[0]) { + if (log) + write_log (_T("%s"), r->rom_name); + else + console_out (r->rom_name); + } + }*/ + } + this.map_dump = function() { //memory_map_dump() + if (SAEV_config.debug.level == SAEC_Config_Debug_Level_Log) + memory_map_dump_2(1); + } +} diff --git a/sae/playfield.js b/sae/playfield.js index cd1506e..3deba1a 100644 --- a/sae/playfield.js +++ b/sae/playfield.js @@ -1,38 +1,322 @@ -/************************************************************************** -* SAE - Scripted Amiga Emulator -* -* 2012-2015 Rupert Hausberger -* -* https://github.com/naTmeg/ScriptedAmigaEmulator -* -*************************************************************************** -* Notes: -* - Ported from WinUAE 2.5.0 -* - AGA support is commented out. -* -**************************************************************************/ +/*------------------------------------------------------------------------- +| SAE - Scripted Amiga Emulator +| https://github.com/naTmeg/ScriptedAmigaEmulator +| +| Copyright (C) 2012-2016 Rupert Hausberger +| +| This program is free software; you can redistribute it and/or +| modify it under the terms of the GNU General Public License +| as published by the Free Software Foundation; either version 2 +| of the License, or (at your option) any later version. +| +| This program is distributed in the hope that it will be useful, +| but WITHOUT ANY WARRANTY; without even the implied warranty of +| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +| GNU General Public License for more details. +| +| Note: ported from WinUAE 3.2.x +-------------------------------------------------------------------------*/ +/* global constants */ -function Playfield() { - function Decision() { - this.plfleft = 0; - this.plfright = 0; - this.plflinelen = 0; - this.diwfirstword = 0; - this.diwlastword = 0; - this.ctable = 0; - this.bplcon0 = 0; - this.bplcon2 = 0; - this.bplcon3 = 0; -/*#ifdef AGA - this.bplcon4 = 0; -#endif*/ - this.nr_planes = 0; - this.bplres = 0; - this.ehb_seen = false; - this.ham_seen = false; - this.ham_at_start = false; +var SAEC_Playfield_CLOCK_PAL = 3546895; +var SAEC_Playfield_CLOCK_NTSC = 3579545; - this.clr = function () { +/*---------------------------------*/ +/* global variables */ + +var SAEV_Playfield_fake_vblank_hz = 0.0; +var SAEV_Playfield_frame_rendered = false; +var SAEV_Playfield_frame_shown = false; + +var SAEV_Playfield_picasso_requested_on = false; +var SAEV_Playfield_picasso_on = false; + +/*---------------------------------*/ +/* global references */ + +var SAER_Playfield_gfxvidinfo = null; + +var SAER_Playfield_isvsync_chipset = null; +var SAER_Playfield_isvsync = null; + +var SAER_Playfield_init_row_map = null; + +/*---------------------------------*/ + +function SAEF_Playfield_getvsyncrate(hz, result) { //double getvsyncrate(double hz, int *mult) + if (hz < 0) { + result.mult = 0; + result.hz = 0; + } + else if (hz > 85) { + result.mult = -1; + result.hz = hz / 2; + } + else if (hz < 35 && hz > 0) { + var ap = SAEV_config.video.apmode[SAEV_Playfield_picasso_on ? 1 : 0]; + result.mult = ap.gfx_interlaced ? 0 : 1; + result.hz = hz * 2; + } else { + result.mult = 0; + result.hz = hz; + } +} + +/*---------------------------------*/ + +function SAEO_Playfield() { + /* SECT drawing defs */ + const SMART_UPDATE = true; //OPT + const SPEEDUP = true; + + const MAX_SPRITES = 8; + + //#ifdef AGA + const MAX_PLANES = 8; + /*#else + const MAX_PLANES = 6; + #endif*/ + + /* 100 words give you 1600 horizontal pixels. Should be more than enough for + * superhires. Don't forget to update the definition in genp2c.c as well. + * needs to be larger for superhires support */ + const MAX_WORDS_PER_LINE = 100; + + /* maximums for statically allocated tables */ + /*#ifdef UAE_MINI + const MAXHPOS = 227; //absolute minimums for basic A500/A1200-emulation + const MAXVPOS = 312; + #else*/ + const MAXHPOS = 256; + const MAXVPOS = 592; + //#endif + + //-->SAEC_Config_Video_HResolution_LoRes const RES_LORES = 0; + //-->SAEC_Config_Video_HResolution_HiRes const RES_HIRES = 1; + //-->SAEC_Config_Video_HResolution_SuperHiRes const RES_SUPERHIRES = 2; + const RES_MAX = 2; + //-->SAEC_Config_Video_VResolution_NonDouble const VRES_NONDOUBLE = 0; + //-->SAEC_Config_Video_VResolution_Double const VRES_DOUBLE = 1; + const VRES_QUAD = 2; + const VRES_MAX = 1; + + /*const NEWHSYNC = 0; + #ifdef NEWHSYNC + const DIW_DDF_OFFSET = 9; + const HBLANK_OFFSET = 13; + const DISPLAY_LEFT_SHIFT = 0x40; + #else*/ + /* According to the HRM, pixel data spends a couple of cycles somewhere in the chips before it appears on-screen. (TW: display emulation now does this automatically) */ + const DIW_DDF_OFFSET = 1; + /* this many cycles starting from hpos=0 are visible on right border */ + const HBLANK_OFFSET = 9; + /* We ignore that many lores pixels at the start of the display. These are invisible anyway due to hardware DDF limits. */ + const DISPLAY_LEFT_SHIFT = 0x38; + //#endif + + //enum diw_states + const DIW_WAITING_START = 0; + const DIW_WAITING_STOP = 1; + + function PIXEL_XPOS(HPOS) { return ((HPOS * 2 - DISPLAY_LEFT_SHIFT + DIW_DDF_OFFSET - 1) << lores_shift); } + + const min_diwlastword = 0; + function max_diwlastword() { return PIXEL_XPOS(0x1d4 >> 1); } //ATT + + function coord_hw_to_window_x(x) { + x -= DISPLAY_LEFT_SHIFT; + return x << lores_shift; + } + + function coord_window_to_hw_x(x) { + x >>= lores_shift; + return x + DISPLAY_LEFT_SHIFT; + } + + function coord_diw_to_window_x(x) { + return (x - DISPLAY_LEFT_SHIFT + DIW_DDF_OFFSET - 1) << lores_shift; + } + + function coord_window_to_diw_x(x) { + x = coord_window_to_hw_x(x); + return x - DIW_DDF_OFFSET; + } + + /* color values in two formats: 12 (OCS/ECS) or 24 (AGA) bit Amiga RGB (color_regs), + * and the native color value; both for each Amiga hardware color register. + * !!! See color_reg_xxx functions below before touching !!! */ + + const CE_BORDERBLANK = 0; + const CE_BORDERNTRANS = 1; + const CE_BORDERSPRITE = 2; + const CE_SHRES_DELAY = 4; + + function ce_is_borderblank(data) { + return (data & (1 << CE_BORDERBLANK)) != 0; + } + function ce_is_bordersprite(data) { + return (data & (1 << CE_BORDERSPRITE)) != 0; + } + function ce_is_borderntrans(data) { + return (data & (1 << CE_BORDERNTRANS)) != 0; + } + + function color_entry() { + this.color_regs_ecs = new Uint16Array(32); //u16 + /*#ifndef AGA + this.acolors = new Uint32Array(32); //u32 + #else*/ + this.acolors = new Uint32Array(256); //u32 + this.color_regs_aga = new Uint32Array(256); //u32 + //#endif + this.extra = 0; //u8 + }; + + /* convert 24 bit AGA Amiga RGB to native color, warning: this is still ugly, but now works with either byte order */ + /*#ifdef AGA + #ifdef WORDS_BIGENDIAN + #define CONVERT_RGB(c) ( xbluecolors[((uae_u8*)(&c))[3]] | xgreencolors[((uae_u8*)(&c))[2]] | xredcolors[((uae_u8*)(&c))[1]] ) + #else + #define CONVERT_RGB(c) ( xbluecolors[((uae_u8*)(&c))[0]] | xgreencolors[((uae_u8*)(&c))[1]] | xredcolors[((uae_u8*)(&c))[2]] ) + #endif + #else + #define CONVERT_RGB(c) 0 + #endif*/ + function CONVERT_RGB(c) { + if (SAEC_LITTLE_ENDIAN) + return (xbluecolors[c & 0xff] | xgreencolors[(c >>> 8) & 0xff] | xredcolors[(c >>> 16) & 0xff]) >>> 0; + else + return (xbluecolors[(c >>> 24) & 0xff] | xgreencolors[(c >>> 16) & 0xff] | xredcolors[(c >>> 8) & 0xff]) >>> 0; + } + function getxcolor(c) { + //#ifdef AGA + if (direct_rgb) + return CONVERT_RGB(c); + else + //#endif + return xcolors[c]; + } + + /* functions for reading, writing, copying and comparing struct color_entry */ + function color_reg_get(ce, c) { + //#ifdef AGA + if (aga_mode) + return ce.color_regs_aga[c]; + else + //#endif + return ce.color_regs_ecs[c]; + } + function color_reg_set(ce, c, v) { + //#ifdef AGA + if (aga_mode) + ce.color_regs_aga[c] = v; + else + //#endif + ce.color_regs_ecs[c] = v; + } + function color_reg_cmp(ce1, ce2) { + //#ifdef AGA + if (aga_mode) { + for (var i = 0; i < 256; i++) { + if (ce1.color_regs_aga[i] != ce2.color_regs_aga[i]) return 1; + } + } else { + //#endif + for (var i = 0; i < 32; i++) { + if (ce1.color_regs_ecs[i] != ce2.color_regs_ecs[i]) return 1; + } + } + return (ce1.extra == ce2.extra) ? 0 : 1; + } + /* ugly copy hack, is there better solution? */ + function color_reg_cpy(dst, src) { + //#ifdef AGA + if (aga_mode) { + /* copy acolors and color_regs_aga */ + for (var i = 0; i < 256; i++) { + dst.acolors[i] = src.acolors[i]; + dst.color_regs_aga[i] = src.color_regs_aga[i]; + } + } else { + //#endif + /* copy first 32 acolors and color_regs_ecs */ + for (var i = 0; i < 32; i++) { + dst.color_regs_ecs[i] = src.color_regs_ecs[i]; + dst.acolors[i] = src.acolors[i]; + } + } + dst.extra = src.extra; + } + + /* + * The idea behind this code is that at some point during each horizontal + * line, we decide how to draw this line. There are many more-or-less + * independent decisions, each of which can be taken at a different horizontal + * position. + * Sprites and color changes are handled specially: There isn"t a single decision, + * but a list of structures containing information on how to draw the line. + */ + const COLOR_CHANGE_BRDBLANK = 0x80000000; + const COLOR_CHANGE_SHRES_DELAY = 0x40000000; + function color_change() { + this.linepos = 0; //int + this.regno = 0; //int + this.value = 0; //uint + }; + function cpy_color_change(d, s) { //OWN + d.linepos = s.linepos; + d.regno = s.regno; + d.value = s.value; + } + function cmp_color_change(cc1, cc2) { //OWN + return cc1.linepos == cc2.linepos && cc1.regno == cc2.regno && cc1.value == cc2.value ? 0 : 1; + } + + /* 440 rather than 880, since sprites are always lores. */ + /*#ifdef UAE_MINI + const MAX_PIXELS_PER_LINE = 880; + #else*/ + const MAX_PIXELS_PER_LINE = 1760; + //#endif + + /* No divisors for MAX_PIXELS_PER_LINE; we support AGA and SHRES sprites */ + const MAX_SPR_PIXELS = ((MAXVPOS + 1) * 2 + 1) * MAX_PIXELS_PER_LINE; + + function sprite_entry() { + this.pos = 0; //ushort + this.max = 0; //ushort + this.first_pixel = 0; //uint + this.has_attached = false; //bool + }; + /*union sps_union { + uae_u8 bytes[2 * MAX_SPR_PIXELS]; + uae_u32 words[2 * MAX_SPR_PIXELS / 4]; + };*/ + function sps_union() { + this.bytes = new Uint8Array(2 * MAX_SPR_PIXELS); //u8 + }; + + /* Way too much... */ + const MAX_REG_CHANGE = (MAXVPOS + 1) * 2 * MAXHPOS; + + /* struct decision contains things we save across drawing frames for comparison (smart update stuff). */ + function decision() { + this.plfleft = 0; this.plfright = 0; this.plflinelen = 0; //int /* Records the leftmost access of BPL1DAT. */ + this.diwfirstword = 0; this.diwlastword = 0; //int /* Display window: native coordinates, depend on lores state. */ + this.ctable = 0; //int + + this.bplcon0 = 0; this.bplcon2 = 0; //u16 + //#ifdef AGA + this.bplcon3 = 0; this.bplcon4 = 0; //u16 + //#endif + this.nr_planes = 0; //u8 + this.bplres = 0; //u8 + this.ehb_seen = false; //bool + this.ham_seen = false; //bool + this.ham_at_start = false; //bool + this.bordersprite_seen = false; //bool + + this.clr = function() { this.plfleft = 0; this.plfright = 0; this.plflinelen = 0; @@ -41,1160 +325,1281 @@ function Playfield() { this.ctable = 0; this.bplcon0 = 0; this.bplcon2 = 0; + //#ifdef AGA this.bplcon3 = 0; - /*#ifdef AGA - this.bplcon4 = 0; - #endif*/ + this.bplcon4 = 0; + //#endif this.nr_planes = 0; this.bplres = 0; this.ehb_seen = false; this.ham_seen = false; this.ham_at_start = false; - }; - - this.set = function(src) { - this.plfleft = src.plfleft; - this.plfright = src.plfright; - this.plflinelen = src.plflinelen; - this.diwfirstword = src.diwfirstword; - this.diwlastword = src.diwlastword; - this.ctable = src.ctable; - this.bplcon0 = src.bplcon0; - this.bplcon2 = src.bplcon2; - this.bplcon3 = src.bplcon3; -/*#ifdef AGA - this.bplcon4 = src.bplcon4; -#endif*/ - this.nr_planes = src.nr_planes; - this.bplres = src.bplres; - this.ehb_seen = src.ehb_seen; - this.ham_seen = src.ham_seen; - this.ham_at_start = src.ham_at_start; + this.bordersprite_seen = false; } - } - - function ColorEntry() { - this.color_regs_ecs = new Uint16Array(32); -//#ifndef AGA - this.acolors = new Uint32Array(32); -/*#else - this.acolors = new Uint32Array(256); - this.color_regs_aga = new Uint32Array(256); -#endif*/ - this.borderblank = false; - } - - function ColorChange() { - this.linepos = 0; - this.regno = 0; - this.value = 0; - - this.set = function (v) { - this.linepos = v.linepos; - this.regno = v.regno; - this.value = v.value; - }; - this.cmp = function(v) { - return (this.linepos == v.linepos && this.regno == v.regno && this.value == v.value ? 0 : 1); - } - } - - function DrawInfo() { - this.first_sprite_entry = 0; - this.last_sprite_entry = 0; - this.first_color_change = 0; - this.last_color_change = 0; - this.nr_color_changes = 0; - this.nr_sprites = 0; - } - - function VidBuffer() { - this.rowbytes = 0; /* Bytes per row in the memory pointed at by bufmem. */ - this.pixbytes = 0; /* Bytes per pixel. */ - /* size of this buffer */ - this.width_allocated = 0; - this.height_allocated = 0; - /* size of max visible image */ - this.outwidth = 0; - this.outheight = 0; - /* nominal size of image for centering */ - this.inwidth = 0; - this.inheight = 0; - /* same but doublescan multiplier included */ - this.inwidth2 = 0; - this.inheight2 = 0; - /* extra width, chipset hpos extra in right border */ - this.extrawidth = 0; - - //this.xoffset = 0; /* superhires pixels from left edge */ - //this.yoffset = 0; /* lines from top edge */ - this.inxoffset = 0; /* positive if sync positioning */ - //this.inyoffset = 0; - } - - /*---------------------------------*/ - /* drawing */ - - //const dblpfofs = [0, 2, 4, 8, 16, 32, 64, 128]; //DELETE - - var dblpf_ms1 = new Uint8Array(256); - var dblpf_ms2 = new Uint8Array(256); - var dblpf_ms = new Uint8Array(256); - var dblpf_ind1 = new Uint8Array(256); - var dblpf_ind2 = new Uint8Array(256); - var dblpf_2nd1 = new Uint8Array(256); - var dblpf_2nd2 = new Uint8Array(256); - - var linestate = new Uint8Array((MAXVPOS + 2) * 2 + 1); //[(MAXVPOS + 2) * 2 + 1]; - for (var i = 0; i < linestate.length; i++) - linestate[i] = 0; - - var line_data = []; //[(MAXVPOS + 2) * 2][MAX_PLANES * MAX_WORDS_PER_LINE * 2]; - for (var i = 0; i < (MAXVPOS + 2) * 2; i++) { - line_data[i] = []; - for (var j = 0; j < MAX_PLANES; j++) { - line_data[i][j] = new Uint32Array(MAX_WORDS_PER_LINE * 2); - for (var k = 0; k < MAX_WORDS_PER_LINE * 2; k++) - line_data[i][j][k] = 0; - } - } - - var line_decisions = []; - for (var i = 0; i < 2 * (MAXVPOS + 2) + 1; i++) - line_decisions[i] = new Decision(); - var color_tables = []; - for (var i = 0; i < 2; i++) { - color_tables[i] = []; - for (var j = 0; j < COLOR_TABLE_SIZE; j++) - color_tables[i][j] = new ColorEntry(); - } - var color_changes = []; - for (var i = 0; i < 2; i++) { - color_changes[i] = []; - for (var j = 0; j < MAX_REG_CHANGE; j++) - color_changes[i][j] = new ColorChange(); - } - var line_drawinfo = []; - for (var i = 0; i < 2; i++) { - line_drawinfo[i] = []; - for (var j = 0; j < 2 * (MAXVPOS + 2) + 1; j++) - line_drawinfo[i][j] = new DrawInfo(); - } - - var gfxvidinfo = { - maxblocklines:0, - drawbuffer: new VidBuffer(), - gfx_resolution_reserved: 0, // reserved space for currprefs.hresolution - gfx_vresolution_reserved: 0, // reserved space for currprefs.hresolution - xchange: 0, /* how many superhires pixels in one pixel in buffer */ - ychange: 0 /* how many interlaced lines in one line in buffer */ + }; + function cpy_decision(d, s) { //OWN + d.plfleft = s.plfleft; + d.plfright = s.plfright; + d.plflinelen = s.plflinelen; + d.diwfirstword = s.diwfirstword; + d.diwlastword = s.diwlastword; + d.ctable = s.ctable; + d.bplcon0 = s.bplcon0; + d.bplcon2 = s.bplcon2; + //#ifdef AGA + d.bplcon3 = s.bplcon3; + d.bplcon4 = s.bplcon4; + //#endif + d.nr_planes = s.nr_planes; + d.bplres = s.bplres; + d.ehb_seen = s.ehb_seen; + d.ham_seen = s.ham_seen; + d.ham_at_start = s.ham_at_start; + d.bordersprite_seen = s.bordersprite_seen; }; - var xlinebuffer = new Uint32Array(MAX_PIXELS_PER_LINE); - for (var i = 0; i < xlinebuffer.length; i++) xlinebuffer[i] = 0; - - var ham_linebuf = new Uint32Array(MAX_PIXELS_PER_LINE << 1); - for (var i = 0; i < ham_linebuf.length; i++) ham_linebuf[i] = 0; - - var apixels = new Uint8Array(MAX_PIXELS_PER_LINE << 1); - for (var i = 0; i < apixels.length; i++) apixels[i] = 0; - - var colors_for_drawing = new ColorEntry(); - var current_colors = new ColorEntry(); - - var xcolors = new Uint32Array(4096); - for (var i = 0; i < xcolors.length; i++) xcolors[i] = 0; - - var thisline_decision = new Decision(); - var thisline_changed = 0; - - var amiga2aspect_line_map = null; - var native2amiga_line_map = null; - - var curr_sprite_entries = null; - var prev_sprite_entries = null; - var curr_color_changes = null; - var prev_color_changes = null; - var curr_drawinfo = null; - var prev_drawinfo = null; - var curr_color_tables = null; - var prev_color_tables = null; - var current_change_set = 0; - - var autoscale_bordercolors = 0; - var frame_redraw_necessary = 0; - - var first_drawn_line = 0; - var last_drawn_line = 0; - var first_block_line = 0; - var last_block_line = 0; - var thisframe_first_drawn_line = 0; - var thisframe_last_drawn_line = 0; - - var drawing_color_matches = -1; - var linedbl = 0, linedbld = 0; - var min_diwstart = 0; - var max_diwstop = 0; - var min_ypos_for_screen = 0; - var max_ypos_thisframe = 0; - - var visible_left_border = 0; - var visible_right_border = 0; - var visible_left_start = 0; - var visible_right_stop = MAX_STOP; - var visible_top_start = 0; - var visible_bottom_stop = MAX_STOP; - var thisframe_y_adjust = 0; - var thisframe_y_adjust_real = 0; - var max_drawn_amiga_line = 0; - var linetoscr_x_adjust_bytes = 0; - var last_max_ypos = 0; - var extra_y_adjust = 0; - var center_reset = true; - var framecnt = 0; - var last_redraw_point = 0; - var lores_shift = 0; - - var dp_for_drawing = null; - var dip_for_drawing = null; - var hposblank = 0; - //var bplxor = 0; - - var playfield_start = 0, playfield_end = 0; - var real_playfield_start = 0, real_playfield_end = 0; - var linetoscr_diw_start = 0, linetoscr_diw_end = 0; - var native_ddf_left = 0, native_ddf_right = 0; - - var unpainted = 0; /* How many pixels in window coordinates which are to the left of the left border. */ - var pixels_offset = 0; - var src_pixel = 0, ham_src_pixel = 0; - var ham_decode_pixel = 0; - var ham_lastcolor = 0; - - var next_color_change = 0; - var next_color_entry = 0; - var remembered_color_entry = -1; - var color_src_match = -1; - var color_dest_match = -1; - var color_compare_result = 0; - - var res_shift = 0; - var bplres = 0; - var bplplanecnt = 0; - var bplham = false; - var bplehb = false; - var issprites = 0; - var ecsshres = false; - var plf1pri = 0; - var plf2pri = 0; - var plf_sprite_mask = 0; - var bpldualpf = false; - var bpldualpfpri = false; - - /*---------------------------------*/ - /* sprites */ - - function Sprite() { - this.pt = 0; - this.xpos = 0; - this.vstart = 0; - this.vstop = 0; - this.dblscan = 0; /* AGA SSCAN2 */ - this.armed = 0; - this.dmastate = 0; - this.dmacycle = 0; - this.ptxhpos = 0; + /* Anything related to changes in hw registers during the DDF for one line. */ + function draw_info() { + this.first_sprite_entry = 0; //all int + this.last_sprite_entry = 0; + this.first_color_change = 0; + this.last_color_change = 0; + this.nr_color_changes = 0; + this.nr_sprites = 0; this.clr = function() { - this.pt = 0; - this.xpos = 0; - this.vstart = 0; - this.vstop = 0; - //this.dblscan = 0; - this.armed = 0; - this.dmastate = 0; - this.dmacycle = 0; - this.ptxhpos = 0; - } + this.first_sprite_entry = 0; + this.last_sprite_entry = 0; + this.first_color_change = 0; + this.last_color_change = 0; + this.nr_color_changes = 0; + this.nr_sprites = 0; + } + }; + + /* Determine how to draw a scan line. */ + //enum nln_how + const nln_normal = 0; /* All lines on a non-doubled display. */ + const nln_doubled = 1; /* Non-interlace, doubled display. */ + const nln_upper = 2; /* Interlace, doubled display, upper line. */ + const nln_lower = 3; /* Interlace, doubled display, lower line. */ + const nln_nblack = 4; /* This line normal, next one black. */ + const nln_upper_black = 5; + const nln_lower_black = 6; + const nln_upper_black_always = 7; + const nln_lower_black_always = 8; + + const IHF_SCROLLLOCK = 0; + const IHF_QUIT_PROGRAM = 1; + const IHF_PICASSO = 2; + + function set_inhibit_frame(bit) { + inhibit_frame |= 1 << bit; } - - function SpriteEntry() { - this.pos = 0; - this.max = 0; - this.first_pixel = 0; - this.has_attached = false; + function clear_inhibit_frame(bit) { + inhibit_frame &= ~(1 << bit); + } + function toggle_inhibit_frame(bit) { + inhibit_frame ^= 1 << bit; } - function SpritePixelsBuf() { - this.attach = 0; - this.stdata = 0; - this.data = 0; - + /* drawing defs */ + /*-----------------------------------------------------------------------*/ + /*-----------------------------------------------------------------------*/ + /*-----------------------------------------------------------------------*/ + /* SECT drawing code */ + + /* There are a couple of concepts of "coordinates" in this file. + - DIW coordinates + - DDF coordinates (essentially cycles, resolution lower than lores by a factor of 2) + - Pixel coordinates + * in the Amiga"s resolution as determined by BPLCON0 ("Amiga coordinates") + * in the window resolution as determined by the preferences ("window coordinates"). + * in the window resolution, and with the origin being the topmost left corner of + the window ("native coordinates") + One note about window coordinates. The visible area depends on the width of the + window, and the centering code. The first visible horizontal window coordinate is + often _not_ 0, but the value of VISIBLE_LEFT_BORDER instead. + + One important thing to remember: DIW coordinates are in the lowest possible + resolution. + + To prevent extremely bad things (think pixels cut in half by window borders) from + happening, all ports should restrict window widths to be multiples of 16 pixels. */ + + const BG_COLOR_DEBUG = 0; + + var lores_factor = 0; //int + var lores_shift = 0; //global int + + function lores_set(lores) { + var old = lores; + lores_shift = lores; + if (lores_shift != old) + pfield_set_linetoscr(); + } + + function lores_reset() { + lores_factor = SAEV_config.video.hresolution ? 2 : 1; + lores_set(SAEV_config.video.hresolution); + if (doublescan > 0) { + if (lores_shift < 2) + lores_shift++; + lores_factor = 2; + lores_set(lores_shift); + } + sprite_buffer_res = SAEV_config.video.hresolution; + if (doublescan > 0 && sprite_buffer_res < SAEC_Config_Video_HResolution_SuperHiRes) + sprite_buffer_res++; + } + + var aga_mode = false; //global bool /* mirror of chipset_mask & SAEC_Config_Chipset_Mask_AGA */ + var direct_rgb = false; //global bool + + /* The shift factor to apply when converting between Amiga coordinates and window + coordinates. Zero if the resolution is the same, positive if window coordinates + have a higher resolution (i.e. we"re stretching the image), negative if window + coordinates have a lower resolution (i.e. we"re shrinking the image). */ + var res_shift = 0; //int + + var linedbl = 0, linedbld = 0; //int + + var interlace_seen = 0; //int + const AUTO_LORES_FRAMES = 10; + var can_use_lores = 0, frame_res = 0, frame_res_lace = 0; //int + var resolution_count = new Int32Array(RES_MAX + 1); //int + var lines_count = 0; //int + var center_reset = false; //bool + var need_genlock_data = false; //bool + var init_genlock_data = false; //bool + + /* Lookup tables for dual playfields. The dblpf_*1 versions are for the case + that playfield 1 has the priority, dbplpf_*2 are used if playfield 2 has + priority. If we need an array for non-dual playfield mode, it has no number. */ + /* The dbplpf_ms? arrays contain a shift value. plf_spritemask is initialized + to contain two 16 bit words, with the appropriate mask if pf1 is in the + foreground being at bit offset 0, the one used if pf2 is in front being at + offset 16. */ + const dblpfofs = [0, 2, 4, 8, 16, 32, 64, 128]; //int + + var dblpf_ms1 = null, dblpf_ms2 = null, dblpf_ms = null; //int [256] + var dblpf_ind1 = null, dblpf_ind2 = null; //int [256] + var dblpf_2nd1 = null, dblpf_2nd2 = null; //int [256] + //#ifdef AGA /* AGA mode color lookup tables */ + var dblpf_ind1_aga = null, dblpf_ind2_aga = null; //int [256] + /*#else + var dblpf_ind1_aga = null, dblpf_ind2_aga = null; //int [1] + #endif*/ + var sprite_offs = null; //int [256] + var clxtab = null; //u32 [256] + + /* The graphics code has a choice whether it wants to use a large buffer + * for the whole display, or only a small buffer for a single line. + * If you use a large buffer: + * - set bufmem to point at it + * - set linemem to 0 + * - if memcpy within bufmem would be very slow, i.e. because bufmem is + * in graphics card memory, also set emergmem to point to a buffer + * that is large enough to hold a single line. + * - implement flush_line to be a no-op. + * If you use a single line buffer: + * - set bufmem and emergmem to 0 + * - set linemem to point at your buffer + * - implement flush_line to copy a single line to the screen + */ + function vidbuffer() { + /* Function implemented by graphics driver */ + this.flush_line = function(gfxinfo, vb, line_no) {}; + this.flush_block = function(gfxinfo, vb, first_line, last_line) {}; + this.flush_screen = function(gfxinfo, vb, first_line, last_line) {}; + this.flush_clear_screen = function(gfxinfo, vb) {}; + this.lockscr = function(gfxinfo, vb) { return 1; }; + this.unlockscr = function(gfxinfo, vb) {}; + + this.linemem = null; //u8 * + this.emergmem = null; //u8 * + + this.bufmem = null; //u8 * + this.bufmem_pos = 0; //OWN + this.bufmemend = 0; //u8 * + this.bufmemend_pos = 0; //OWN + this.realbufmem = null; //u8 * + this.bufmem_allocated = null; //u8 * + this.bufmem_lockable = false; //bool + this.rowbytes = 0; //int /* Bytes per row in the memory pointed at by bufmem. */ + this.pixbytes = 0; //int /* Bytes per pixel. */ + + this.width_allocated = 0; //int /* size of this buffer */ + this.height_allocated = 0; //int + + this.outwidth = 0; //int /* size of max visible image */ + this.outheight = 0; //int + + this.inwidth = 0; //int /* nominal size of image for centering */ + this.inheight = 0; //int + + this.inwidth2 = 0; //int /* same but doublescan multiplier included */ + this.inheight2 = 0; //int + + this.nativepositioning = false; //bool /* use drawbuffer instead */ + this.tempbufferinuse = false; //bool /* tempbuffer in use */ + + this.extrawidth = 0; //int /* extra width, chipset hpos extra in right border */ + + this.xoffset = 0; //int /* superhires pixels from left edge */ + this.yoffset = 0; //int /* lines from top edge */ + + this.inxoffset = 0; //int /* positive if sync positioning */ + this.inyoffset = 0; //int + + this.clr = function() { + this.linemem = null; + this.emergmem = null; + + this.bufmem = null; + this.bufmem_pos = 0; + this.bufmemend = 0; + this.bufmemend_pos = 0; + this.realbufmem = null; + this.bufmem_allocated = null; + this.bufmem_lockable = false; + this.rowbytes = 0; + this.pixbytes = 0; + + this.width_allocated = 0; + this.height_allocated = 0; + + this.outwidth = 0; + this.outheight = 0; + + this.inwidth = 0; + this.inheight = 0; + + this.inwidth2 = 0; + this.inheight2 = 0; + + this.nativepositioning = false; + this.tempbufferinuse = false; + + this.extrawidth = 0; + + this.xoffset = 0; + this.yoffset = 0; + + this.inxoffset = 0; + this.inyoffset = 0; + } + }; + /* Video buffer description structure. Filled in by the graphics system dependent code. */ + function vidbuf_description() { + this.maxblocklines = 0; //int /* Set to 0 if you want calls to flush_line after each drawn line, or the number of lines that flush_block wants to/can handle (it isn"t really useful to use another value than maxline here). */ + this.drawbuffer = new vidbuffer(); //struct vidbuffer + this.tempbuffer = new vidbuffer(); //struct vidbuffer /* output buffer when using A2024 emulation */ + this.inbuffer = null; //struct vidbuffer * + this.outbuffer = null; //struct vidbuffer * + this.gfx_resolution_reserved = 0; //int + this.gfx_vresolution_reserved = 0; //int + this.xchange = 0; //int /* how many superhires pixels in one pixel in buffer */ + this.ychange = 0; //int /* how many interlaced lines in one line in buffer */ + }; + var gfxvidinfo = new vidbuf_description(); //struct vidbuf_description + SAER_Playfield_gfxvidinfo = gfxvidinfo; + + function spritepixelsbuf() { + this.attach = 0; //u8 + this.stdata = 0; //u8 + this.data = 0; //u16 + this.clr = function() { this.attach = 0; this.stdata = 0; this.data = 0; } + }; + var spritepixels_buffer = new Array(MAX_PIXELS_PER_LINE); //struct spritepixelsbuf [MAX_PIXELS_PER_LINE] + for (var vi = 0; vi < MAX_PIXELS_PER_LINE; vi++) + spritepixels_buffer[vi] = new spritepixelsbuf(); + + var spritepixels = null; //struct spritepixelsbuf * + var spritepixels_pos = 0; //OWN + var sprite_first_x = 0, sprite_last_x = 0; //int + + /* OCS/ECS color lookup table */ + //typedef uae_u32 xcolnr; + var xcolors = new Uint32Array(4096); //xcolnr + /* AGA mode color lookup tables */ + var xredcolors = new Uint32Array(256); //global uint + var xgreencolors = new Uint32Array(256); //global uint + var xbluecolors = new Uint32Array(256); //global uint + + var xredcolor_s = 0, xredcolor_b = 0, xredcolor_m = 0; //global int + var xgreencolor_s = 0, xgreencolor_b = 0, xgreencolor_m = 0; //global int + var xbluecolor_s = 0, xbluecolor_b = 0, xbluecolor_m = 0; //global int + + var colors_for_drawing = new color_entry(); //global struct color_entry + var direct_colors_for_drawing = new color_entry(); //struct color_entry + + var p_acolors = null; //xcolnr * + var p_xcolors = null; //xcolnr * + + /* The size of these arrays is pretty arbitrary; it was chosen to be "more + than enough". The coordinates used for indexing into these arrays are + almost, but not quite, Amiga coordinates (there"s a constant offset). */ + /*static union { + double uupzuq; + long int cruxmedo; + uae_u8 apixels[MAX_PIXELS_PER_LINE * 2]; + uae_u16 apixels_w[MAX_PIXELS_PER_LINE * 2 / sizeof (uae_u16)]; + uae_u32 apixels_l[MAX_PIXELS_PER_LINE * 2 / sizeof (uae_u32)]; + } pixdata;*/ + function pixdata_union() { + this.apixelsBuffer = new ArrayBuffer(MAX_PIXELS_PER_LINE * 2); + this.apixels = new Uint8Array(this.apixelsBuffer); + this.apixels_l = new Uint32Array(this.apixelsBuffer); } + var pixdata = new pixdata_union(); - var sprinit = false; - var sprtaba = new Uint32Array(256); - var sprtabb = new Uint32Array(256); - var sprite_ab_merge = new Uint32Array(256); - var sprclx = new Uint32Array(16); - var clxmask = new Uint32Array(16); + var refresh_indicator_buffer = null; //u8 * + var refresh_indicator_changed = null, refresh_indicator_changed_prev = null; //u8 * + var refresh_indicator_height = 0; //int - var sprite_offs = new Uint8Array(256); - var clxtab = new Uint32Array(256); - - var spr = []; - for (var i = 0; i < MAX_SPRITES; i++) - spr[i] = new Sprite(); - - /*union sps_union { - uae_u8 bytes[MAX_SPR_PIXELS * 2]; - uae_u32 words[MAX_SPR_PIXELS * 2 / 4]; - };*/ - var spixstate = new Uint8Array(MAX_SPR_PIXELS << 1); - var spixels = new Uint16Array(MAX_SPR_PIXELS << 1); - for (var i = 0; i < MAX_SPR_PIXELS << 1; i++) - spixstate[i] = spixels[i] = 0; - - var sprite_entries = []; //[2][MAX_SPR_PIXELS / 16]; - for (var i = 0; i < 2; i++) { - sprite_entries[i] = []; - for (var j = 0; j < MAX_SPR_PIXELS >> 4; j++) - sprite_entries[i][j] = new SpriteEntry(); - } + var spixels = new Uint16Array(2 * MAX_SPR_PIXELS); - var spritepixels = []; - for (var i = 0; i < MAX_PIXELS_PER_LINE; i++) - spritepixels[i] = new SpritePixelsBuf(); + /* Eight bits for every pixel. */ + var spixstate = new sps_union(); //global union sps_union - var sprctl = new Uint16Array(MAX_SPRITES); - var sprpos = new Uint16Array(MAX_SPRITES); - for (var i = 0; i < MAX_SPRITES; i++) - sprctl[i] = sprpos[i] = 0; + var ham_linebuf = new Uint32Array(MAX_PIXELS_PER_LINE * 2); //u32 -/*#ifdef AGA - //[MAX_SPRITES][4] - var sprdata = []; - var sprdatb = []; - for (var i = 0; i < MAX_SPRITES; i++) { - sprdata[i] = new Uint16Array(4); - sprdatb[i] = new Uint16Array(4); - for (var j = 0; j < 4; j++) { - sprdata[i][j] = 0; - sprdatb[i][j] = 0; + var real_bplpt = new Array(8); //u8 * + + var all_ones = new Uint8Array(MAX_PIXELS_PER_LINE); //u8 + SAEF_memset(all_ones,0, 0xff, MAX_PIXELS_PER_LINE); + var all_zeros = new Uint8Array(MAX_PIXELS_PER_LINE); //u8 + + var xlinebuffer = null;//, xlinebuffer_genlock = null; //u8 * + var xlinebuffer_pos = 0; //OWN + + var amiga2aspect_line_map = null, native2amiga_line_map = null; //int * + var max_drawn_amiga_line = 0; //int + + var row_map = null; //u8 ** + //var row_map_genlock = null; //global u8 ** + //var row_map_genlock_buffer = null; //u8 * + var row_map_color_burst_buffer = null; //global u8 * + var row_tmp = new ArrayBuffer(MAX_PIXELS_PER_LINE * 32 / 8); //u8 [] + + /* line_draw_funcs: pfield_do_linetoscr, pfield_do_fill_line, decode_ham */ + //typedef void (*line_draw_func)(int, int, bool); + var line_draw_func = function(a,b,c) {}; //func * + + const LINE_UNDECIDED = 1; + const LINE_DECIDED = 2; + const LINE_DECIDED_DOUBLE = 3; + const LINE_AS_PREVIOUS = 4; + const LINE_BLACK = 5; + const LINE_REMEMBERED_AS_BLACK = 6; + const LINE_DONE = 7; + const LINE_DONE_AS_PREVIOUS = 8; + const LINE_REMEMBERED_AS_PREVIOUS = 9; + + const LINESTATE_SIZE = (MAXVPOS + 2) * 2 + 1; + var linestate = new Uint8Array(LINESTATE_SIZE); //u8 + + const MAX_WORDS_PER_LINE_FULL = MAX_WORDS_PER_LINE * 2 >> 2; //OWN + var line_data = new Array((MAXVPOS + 2) * 2); //u8 [(MAXVPOS + 2) * 2][MAX_PLANES * MAX_WORDS_PER_LINE * 2] + for (var vi = 0; vi < line_data.length; vi++) + line_data[vi] = new Uint32Array(MAX_PLANES * MAX_WORDS_PER_LINE_FULL); //u8 + + /* Centering variables. */ + var min_diwstart = 0, max_diwstop = 0; //int + /* The visible window: VISIBLE_LEFT_BORDER contains the left border of the visible area, VISIBLE_RIGHT_BORDER the right border. These are in window coordinates. */ + var visible_left_border = 0, visible_right_border = 0; //global int + /* Pixels outside of visible_start and visible_stop are always black */ + var visible_left_start = 0, visible_right_stop = 0; //int + var visible_top_start = 0, visible_bottom_stop = 0; //int + /* same for hblank */ + var hblank_left_start = 0, hblank_right_stop = 0; //int + + var linetoscr_x_adjust_pixbytes = 0, linetoscr_x_adjust_pixels = 0; //int + var thisframe_y_adjust = 0; //int + var thisframe_y_adjust_real = 0, max_ypos_thisframe = 0, min_ypos_for_screen = 0; //int + var thisframe_first_drawn_line = 0, thisframe_last_drawn_line = 0; //global int + + /* A frame counter that forces a redraw after at least one skipped frame in interlace mode. */ + var last_redraw_point = 0; //int + + const MAX_STOP = 30000; + var first_drawn_line = 0, last_drawn_line = 0; //int + //var first_block_line = 0, last_block_line = 0; //int, OWN flush_block() is not used + + const NO_BLOCK = -3; + + /* These are generated by the drawing code from the line_decisions array for + each line that needs to be drawn. These are basically extracted out of + bit fields in the hardware registers. */ + var bplehb = false, bplham = false, bpldualpf = false, bpldualpfpri = false, bpldualpf2of = 0, bplplanecnt = 0, ecsshres = false; //int + var bplbypass = false, bplcolorburst = false, bplcolorburst_field = false; //int + var issprites = false; //bool + var bplres = 0; //int + var plf1pri = 0, plf2pri = 0, bplxor = 0, bpland = 0, bpldelay_sh = 0; //int + var plf_sprite_mask = 0; //u32 + var sbasecol = [16, 16]; //int + var hposblank = 0; //int + var specialmonitoron = false; //bool + var ecs_genlock_features_active = false; //bool + var ecs_genlock_features_mask = 0; //u8 + var ecs_genlock_features_colorkey = false; //bool + + //var picasso_requested_on = false; --> SAEV_Playfield_picasso_requested_on + //var picasso_on = false; -> SAEV_Playfield_picasso_on + + var inhibit_frame = 0; //global int + + var framecnt = 0; //global int + var custom_frame_redraw_necessary = 0; //global int + var frame_redraw_necessary = 0; //int + var picasso_redraw_necessary = 0; //int + + var warned_pfield_draw_line = 0; //OWN + + /*-----------------------------------------------------------------------*/ + + var gamma = new Array(256 * 3); //u32 [256 * 3][3] + for (var vi = 0; vi < 256 * 3; vi++) + gamma[vi] = new Uint32Array(3); + + var blur_lf = 0, blur_hf = 0; //int + + /*extern uae_s32 tyhrgb[65536]; + extern uae_s32 tylrgb[65536]; + extern uae_s32 tcbrgb[65536]; + extern uae_s32 tcrrgb[65536]; + extern uae_u32 redc[3 * 256], grec[3 * 256], bluc[3 * 256];*/ + + function bits_in_mask(mask) { + var n = 0; + while (mask) { + n += mask & 1; + mask >>>= 1; } + return n; + } + function mask_shift(mask) { + var n = 0; + if (!mask) + return 0; + while (!(mask & 1)) { + n++; + mask >>>= 1; + } + return n; } -#else*/ - //[MAX_SPRITES][1] - var sprdata = []; - var sprdatb = []; - for (var i = 0; i < MAX_SPRITES; i++) { - sprdata[i] = new Uint16Array(1); - sprdatb[i] = new Uint16Array(1); - sprdata[i][0] = 0; - sprdatb[i][0] = 0; - } -//#endif - var clxcon = 0; - var clxcon_bpl_enable = 0; - var clxcon_bpl_match = 0; - var clxcon2 = 0; - var clxdat = 0; + function doMask(p, bits, shift) { + if (bits == 0) return 0; + /* scale to 0..255, shift to align msb with mask, and apply mask */ + //if (flashscreen) p ^= 0xff; + var val = p << 24; + val >>>= (32 - bits); + val <<= shift; + return val >>> 0; + } + /*function doMask256(p, bits, shift) { + if (bits == 0) return 0; + * p is a value from 0 to 255 (Amiga color value) + * shift to align msb with mask, and apply mask + var val = p * 0x01010101 >>> 0; + val >>= (32 - bits); + val <<= shift; + return val; + }*/ + function doColor(i, bits, shift) { + //if (flashscreen) i = (i ^ 0xffffffff) >>> 0; + if (bits >= 8) + return (i << shift) >>> 0; + else + return ((i >> (8 - bits)) << shift) >>> 0; + } + function doAlpha(alpha, bits, shift) { + return ((alpha & ((1 << bits) - 1)) << shift) >>> 0; + } - var sprres = 0; - var nr_armed = 0; + function calc_gamma(value, gamma, bri, con) { //video_gamma() all float + value += bri; + value *= con; - var sprite_buffer_res = 0; - var sprite_vblank_endline = VBLANK_SPRITE_PAL; - var sprite_minx = 0; - var sprite_maxx = 0; - var sprite_width = 0; - var sprite_first_x = 0; - var sprite_last_x = 0; - - var sprite_0 = 0; - var sprite_0_width = 0; - var sprite_0_height = 0; - var sprite_0_doubled = 0; - var sprite_0_colors = [0,0,0,0]; + if (value <= 0.0) + return 0.0; - var next_sprite_entry = 0; - var next_sprite_forced = 1; - var prev_next_sprite_entry = 0; - var last_sprite_point = 0; - //var magic_sprite_mask = 0xff; + var factor = Math.pow(255.0, 1.0 - gamma); //double + var ret = factor * Math.pow(value, gamma); //float - /*---------------------------------*/ - /* playfield */ + if (ret < 0.0) + ret = 0.0; - var bplcon0 = 0; - var bplcon1 = 0; - var bplcon2 = 0; - var bplcon3 = 0; - var bplcon4 = 0; + return ret; + } - var bpl1mod = 0; - var bpl2mod = 0; - - var bplxdat = [0,0,0,0,0,0,0,0]; - var bplpt = [0,0,0,0,0,0,0,0]; - var bplptx = [0,0,0,0,0,0,0,0]; + function calc_gammatable() { //video_calc_gammatable() + var bri = SAEV_config.video.luminance * (128 / 1000); + var con = (SAEV_config.video.contrast + 1000) / 1000; + var gam = (1000 - SAEV_config.video.gamma) / 1000; - var diwstrt = 0; - var diwstop = 0; - var ddfstrt = 0; - var ddfstrt_old_hpos = -1; - var ddfstop = 0; - var ddf_change = 0; - var diwhigh = 0; - var diwhigh_written = false; - - var hdiwstate = 0; - - var beamcon0 = 0; - var new_beamcon0 = 0; - - this.vpos = 0; - this.vpos_count = 0; - this.vpos_count_diff = 0; - this.hpos = function () { - return Math.floor((AMIGA.events.currcycle - AMIGA.events.eventtab[EV_HSYNC].oldcycles) * CYCLE_UNIT_INV); - }; - var vpos_previous = 0; - var hpos_previous = 0; - - this.maxvpos = MAXVPOS; - this.maxvpos_nom = MAXVPOS; - this.maxvpos_total = MAXVPOS; - this.maxhpos = MAXHPOS; - this.maxhpos_short = MAXHPOS; - - this.lof_store = 0; - this.lof_current = 0; - this.lof_previous = 0; - this.lof_changed = 0; - this.lof_changing = 0; - this.lol = 0; - - this.vblank_hz = 0; - - var aga_mode = 0; - var direct_rgb = 0; - - var prevbpl = []; //[2][MAXVPOS][8]; - for (var i = 0; i < 2; i++) { - prevbpl[i] = []; - for (var j = 0; j < MAXVPOS; j++) { - prevbpl[i][j] = new Uint32Array(8); - for (var k = 0; k < 8; k++) { - prevbpl[i][j][k] = 0; + var gams = new Array(3); + gams[0] = gam + (1000 - SAEV_config.video.gammaCh[0]) / 1000; + gams[1] = gam + (1000 - SAEV_config.video.gammaCh[1]) / 1000; + gams[2] = gam + (1000 - SAEV_config.video.gammaCh[2]) / 1000; + + blur_lf = Math.floor(64 * SAEV_config.video.gf[SAEV_Playfield_picasso_on ? 1 : 0].gfx_filter_blur / 1000); + //blur_lf = 0; + blur_hf = 256 - blur_lf * 2; + + for (var i = 0; i < (256 * 3); i++) { + for (var j = 0; j < 3; j++) { + var v = calc_gamma(i - 256, gams[j], bri, con); + //var vi = Math.floor(v); + var vi = v >>> 0; + + if (SAEV_config.video.luminance == 0 && SAEV_config.video.contrast == 0 && SAEV_config.video.gamma == 0) + vi = i & 0xff; + //if (currprefs.gfx_threebitcolors) vi *= 2; + if (vi > 255) + vi = 255; + + gamma[i][j] = vi; + //SAEF_log("video.calc_gammatable() %03x : %08x (%f)", i, vi, v); } } } - - //var scandoubled_line = 0; - var doublescan = 0; - var interlace_seen = 0; - var interlace_changed = 0; - var lof_togglecnt_nlace = 0; - var lof_togglecnt_lace = 0; - var nlace_cnt = 0; - - var minfirstline = 0; - var equ_vblank_endline = 0; - var equ_vblank_toggle = false; - - this.vtotal = MAXVPOS_PAL; - this.htotal = MAXHPOS_PAL; - this.hsstop = 0; - this.hbstrt = 0; - this.hbstop = 0; - this.vsstop = 0; - this.vbstrt = 0; - this.vbstop = 0; - this.hsstrt = 0; - this.vsstrt = 0; - this.hcenter = 0; - var hsyncstartpos = 0; - var hsyncendpos = 0; - - var diwstate = 0; - var ddfstate = 0; - var diw_change = 2; - var diw_hstrt = 0; - var diw_hstop = 0; - var diw_hcounter = 0; - var last_hdiw = 0; - - var diwfirstword = 0; - var diwlastword = 0; - var plffirstline = 0; - var plflastline = 0; - var plfstrt = 0; - var plfstrt_sprite = 0; - var plfstrt_start = 0; - var plfstop = 0; - - var plf_state = 0; - - var nextline_how = 0; - var next_lineno = 0; - var prev_lineno = -1; - - var first_bpl_vpos = 0; - var first_planes_vpos = 0; - var last_planes_vpos = 0; - var firstword_bplcon1 = 0; - var diwfirstword_total = 0; - var diwlastword_total = 0; - var ddffirstword_total = 0; - var ddflastword_total = 0; - var plffirstline_total = 0; - var plflastline_total = 0; - - /*var lightpen_active = 0; - var lightpen_triggered = 0; - var lightpen_cx = 0; - var lightpen_cy = 0; - var lightpen_y1 = -1; - var lightpen_y2 = -1; - var vpos_lpen = 0; - var hpos_lpen = 0;*/ - - var bplcon0_d = 0; - var bplcon0_dd = 0; - var bplcon1_hpos = 0; - var bplcon1t = 0; - var bplcon1t2 = 0; - - var badmode = 0; - var bplcon0_res = 0; - var bplcon0_planes = 0; - var bplcon0_planes_limit = 0; - - var fmode = 0; - var fetchmode = 0; - var fetchunit = 0; - var fetchunit_mask = 0; - const fetchunits = [ 8,8,8,0, 16,8,8,0, 32,16,8,0 ]; - var fetchstart = 0; - var fetchstart_shift = 0; - var fetchstart_mask = 0; - const fetchstarts = [ 3,2,1,0, 4,3,2,0, 5,4,3,0 ]; - var fm_maxplane = 0; - var fm_maxplane_shift = 0; - const fm_maxplanes = [ 3,2,1,0, 3,3,2,0, 3,3,3,0 ]; - var real_bitplane_number = []; //[3][3][9]; - - var fetch_state = 0; - var fetch_cycle = 0; - var fetch_modulo_cycle = 0; - - const cycle_sequences = [[2,1,2,1,2,1,2,1], [4,2,3,1,4,2,3,1], [8,4,6,2,7,3,5,1]]; - var cycle_diagram_shift = 0; - var cycle_diagram_table = null; //[3][3][9][32]; - var cycle_diagram_free_cycles = []; //[3][3][9]; - var cycle_diagram_total_cycles = []; //[3][3][9]; - var curr_diagram = []; - - var estimated_last_fetch_cycle = 0; - - var bpldmasetuphpos = -1; - var bpldmasetupphase = 0; - - var bpl1dat_written = false; - var bpl1dat_written_at_least_once = false; - var bpl1dat_early = false; - var plfleft_real = -1; - - var out_nbits = 0; - var out_offs = 0; - var outword = new Uint32Array(MAX_PLANES); - var todisplay = []; //[MAX_PLANES][4]; - for (var i = 0; i < MAX_PLANES; i++) { - todisplay[i] = new Uint32Array(4); - for (var j = 0; j < 4; j++) - todisplay[i][j] = 0; + /*static uae_u32 limit256 (double v) { + v = v * (double)(SAEV_config.video.gf[SAEV_Playfield_picasso_on ? 1 : 0].gfx_filter_contrast + 1000) / 1000.0 + SAEV_config.video.gf[SAEV_Playfield_picasso_on ? 1 : 0].gfx_filter_luminance / 10.0; + if (v < 0) + v = 0; + if (v > 255) + v = 255; + return ((uae_u32)v) & 0xff; } - var fetched = new Uint32Array(MAX_PLANES); - for (var i = 0; i < MAX_PLANES; i++) - fetched[i] = 0; -/*#ifdef AGA - var fetched_aga0 = new Uint32Array(MAX_PLANES); - var fetched_aga1 = new Uint32Array(MAX_PLANES); -#endif*/ - - var toscr_res = 0; - var toscr_nr_planes = 0; - var toscr_nr_planes2 = 0; - var toscr_delay1 = 0; - var toscr_delay2 = 0; - var toscr_nbits = 0; - - //var fetchwidth = 0; - var delayoffset = 0; - - var last_decide_line_hpos = -1; - var last_ddf_pix_hpos = -1; - var last_sprite_hpos = -1; - var last_fetch_hpos = -1; - - /*-----------------------------------------------------------------------*/ - /* common */ - /*-----------------------------------------------------------------------*/ - - /*function RES_SHIFT(res) { - return res == RES_LORES ? 8 : (res == RES_HIRES ? 4 : 2); + static uae_u32 limit256rb (double v) { + v *= (double)(SAEV_config.video.gf[SAEV_Playfield_picasso_on ? 1 : 0].gfx_filter_saturation + 1000) / 1000.0; + if (v < -128) + v = -128; + if (v > 127) + v = 127; + return ((uae_u32)v) & 0xff; + } + static double get_y (int r, int g, int b) { + return 0.2989f * r + 0.5866f * g + 0.1145f * b; + } + static uae_u32 get_yh (int r, int g, int b) { + return limit256(get_y (r, g, b) * blur_hf / 256); + } + static uae_u32 get_yl (int r, int g, int b) { + return limit256(get_y (r, g, b) * blur_lf / 256); + } + static uae_u32 get_cb (int r, int g, int b) { + return limit256rb(-0.168736f * r - 0.331264f * g + 0.5f * b); + } + static uae_u32 get_cr (int r, int g, int b) { + return limit256rb(0.5f * r - 0.418688f * g - 0.081312f * b); }*/ - function GET_RES_DENISE(con0) { - if (!(AMIGA.config.chipset.mask & CSMASK_ECS_DENISE)) con0 &= ~0x40; // SUPERHIRES - return (con0 & 0x8000) ? RES_HIRES : ((con0 & 0x40) ? RES_SUPERHIRES : RES_LORES); - } - function GET_RES_AGNUS(con0) { - if (!(AMIGA.config.chipset.mask & CSMASK_ECS_AGNUS)) con0 &= ~0x40; // SUPERHIRES - return (con0 & 0x8000) ? RES_HIRES : ((con0 & 0x40) ? RES_SUPERHIRES : RES_LORES); - } - function GET_SPRITEWIDTH(fmode) { - return (((fmode >> 2) & 3) == 3 ? 64 : ((fmode >> 2) & 3) == 0 ? 16 : 32); - } - function GET_PLANES(con0) { - if ((con0 & 0x0010) && (con0 & 0x7000)) return 0; // >8 planes = 0 planes - if (con0 & 0x0010) return 8; // AGA 8-planes bit - return (con0 >> 12) & 7; // normal planes bits - } - function GET_PLANES_LIMIT(con0) { - var res = GET_RES_AGNUS(con0); - var planes = GET_PLANES(con0); - return real_bitplane_number[fetchmode][res][planes]; - } - - this.nodraw = function () { - return framecnt != 0; - }; - this.doflickerfix = function () { - return AMIGA.config.video.vresolution && doublescan < 0 && this.vpos < MAXVPOS; - }; - - this.current_maxvpos = function () { - return this.maxvpos + (this.lof_store ? 1 : 0); - }; + function lowbits(v, shift, lsize) { + return ((v >>> shift) & ((1 << lsize) - 1)) >>> 0; + } - this.is_custom_vsync = function () { - var vp = this.vpos + 1; - var vpc = this.vpos_count + 1; - /* Agnus vpos counter keeps counting until it wraps around if VPOSW writes put it past maxvpos */ - if (vp >= this.maxvpos_total) - vp = 0; - /* vpos_count >= MAXVPOS just to not crash if VPOSW writes prevent vsync completely */ - return vp == this.maxvpos + this.lof_store || vp == this.maxvpos + this.lof_store + 1 || vpc >= MAXVPOS; - }; - - this.is_linetoggle = function () { - if (!(beamcon0 & 0x0800) && !(beamcon0 & 0x0020) && (AMIGA.config.chipset.mask & CSMASK_ECS_AGNUS)) - return true; //NTSC and !LOLDIS -> LOL toggles every line - else if (!(AMIGA.config.chipset.mask & CSMASK_ECS_AGNUS) && AMIGA.config.video.ntsc) - return true; //hardwired NTSC Agnus - return false; - }; + /*void alloc_colors_picasso (int rw, int gw, int bw, int rs, int gs, int bs, int rgbfmt) { + #ifdef PICASSO96 + int byte_swap = 0; + int i; + int red_bits = 0, green_bits, blue_bits; + int red_shift, green_shift, blue_shift; + int bpp = rw + gw + bw; - this.is_last_line = function () { - return this.vpos + 1 == this.maxvpos + this.lof_store; - }; + switch (rgbfmt) + { + case RGBFB_R5G6B5PC: + red_bits = 5; + green_bits = 6; + blue_bits = 5; + red_shift = 11; + green_shift = 5; + blue_shift = 0; + break; + case RGBFB_R5G5B5PC: + red_bits = green_bits = blue_bits = 5; + red_shift = 10; + green_shift = 5; + blue_shift = 0; + break; + case RGBFB_R5G6B5: + red_bits = 5; + green_bits = 6; + blue_bits = 5; + red_shift = 11; + green_shift = 5; + blue_shift = 0; + byte_swap = 1; + break; + case RGBFB_R5G5B5: + red_bits = green_bits = blue_bits = 5; + red_shift = 10; + green_shift = 5; + blue_shift = 0; + byte_swap = 1; + break; + case RGBFB_B5G6R5PC: + red_bits = 5; + green_bits = 6; + blue_bits = 5; + red_shift = 0; + green_shift = 5; + blue_shift = 11; + break; + case RGBFB_B5G5R5PC: + red_bits = green_bits = blue_bits = 5; + red_shift = 0; + green_shift = 5; + blue_shift = 10; + break; + default: + red_bits = rw; + green_bits = gw; + blue_bits = bw; + red_shift = rs; + green_shift = gs; + blue_shift = bs; + break; + } - /*-----------------------------------------------------------------------*/ - /* drawing */ - /*-----------------------------------------------------------------------*/ - - function setup_drawing_tables() { + #ifdef WORDS_BIGENDIAN + byte_swap = !byte_swap; + #endif + + memset (p96_rgbx16, 0, sizeof p96_rgbx16); + + if (red_bits) { + int lrbits = 8 - red_bits; + int lgbits = 8 - green_bits; + int lbbits = 8 - blue_bits; + int lrmask = (1 << red_bits) - 1; + int lgmask = (1 << green_bits) - 1; + int lbmask = (1 << blue_bits) - 1; + for (i = 65535; i >= 0; i--) { + uae_u32 r, g, b, c; + uae_u32 j = byte_swap ? bswap_16 (i) : i; + r = (((j >> red_shift) & lrmask) << lrbits) | lowbits (j, red_shift, lrbits); + g = (((j >> green_shift) & lgmask) << lgbits) | lowbits (j, green_shift, lgbits); + b = (((j >> blue_shift) & lbmask) << lbbits) | lowbits (j, blue_shift, lbbits); + c = doMask(r, rw, rs) | doMask(g, gw, gs) | doMask(b, bw, bs); + if (bpp <= 16) + c *= 0x00010001; + p96_rgbx16[i] = c; + } + } + #endif + }*/ + + this.alloc_colors_rgb = function(rw, gw, bw, rs, gs, bs, aw, as, alpha, byte_swap, rc, gc, bc) { + var bpp = rw + gw + bw + aw; for (var i = 0; i < 256; i++) { - var plane1 = ((i >> 0) & 1) | ((i >> 1) & 2) | ((i >> 2) & 4) | ((i >> 3) & 8); - var plane2 = ((i >> 1) & 1) | ((i >> 2) & 2) | ((i >> 3) & 4) | ((i >> 4) & 8); + var j = 0; + if (SAEV_config.video.blackerThanBlack) + j = Math.floor(i * 15 / 16) + 15; + else + j = i; - dblpf_2nd1[i] = plane1 == 0 && plane2 != 0; - dblpf_2nd2[i] = plane2 != 0; + j += 256; -/*#ifdef AGA - dblpf_ind1_aga[i] = plane1 == 0 ? plane2 : plane1; - dblpf_ind2_aga[i] = plane2 == 0 ? plane1 : plane2; -#endif*/ - dblpf_ms1[i] = plane1 == 0 ? (plane2 == 0 ? 16 : 8) : 0; - dblpf_ms2[i] = plane2 == 0 ? (plane1 == 0 ? 16 : 0) : 8; - dblpf_ms[i] = i == 0 ? 16 : 8; - - if (plane2 > 0) - plane2 += 8; - dblpf_ind1[i] = i >= 128 ? i & 0x7F : (plane1 == 0 ? plane2 : plane1); - dblpf_ind2[i] = i >= 128 ? i & 0x7F : (plane2 == 0 ? plane1 : plane2); + rc[i] = doColor(gamma[j][0], rw, rs) | doAlpha(alpha, aw, as); + gc[i] = doColor(gamma[j][1], gw, gs) | doAlpha(alpha, aw, as); + bc[i] = doColor(gamma[j][2], bw, bs) | doAlpha(alpha, aw, as); + if (byte_swap) { + if (bpp <= 16) { + rc[i] = SAEF_bswap16(rc[i]); + gc[i] = SAEF_bswap16(gc[i]); + bc[i] = SAEF_bswap16(bc[i]); + } else { + rc[i] = SAEF_bswap32(rc[i]); + gc[i] = SAEF_bswap32(gc[i]); + bc[i] = SAEF_bswap32(bc[i]); + } + } + if (bpp <= 16) { + /* Fill upper 16 bits of each colour value with a copy of the colour */ + rc[i] = (rc[i] * 0x00010001) >>> 0; + gc[i] = (gc[i] * 0x00010001) >>> 0; + bc[i] = (bc[i] * 0x00010001) >>> 0; + } + //SAEF_log("playfield.alloc_colors_rgb() %02x : %08x %08x %08x", i, rc[i], gc[i], bc[i]); } } - this.recreate_aspect_maps = function () { - var i, h = gfxvidinfo.drawbuffer.height_allocated; - if (h == 0) - return; + this.alloc_colors64k = function(rw, gw, bw, rs, gs, bs, aw, as, alpha, byte_swap) { + var bpp = rw + gw + bw + aw; + + calc_gammatable(); + var j = 256; + for (var i = 0; i < 4096; i++) { + var r = ((i >> 8) << 4) | (i >> 8); + var g = (((i >> 4) & 0xf) << 4) | ((i >> 4) & 0x0f); + var b = ((i & 0xf) << 4) | (i & 0x0f); + r = gamma[r + j][0]; + g = gamma[g + j][1]; + b = gamma[b + j][2]; + xcolors[i] = doMask(r, rw, rs) | doMask(g, gw, gs) | doMask(b, bw, bs) | doAlpha(alpha, aw, as); + if (byte_swap) { + if (bpp <= 16) + xcolors[i] = SAEF_bswap16(xcolors[i]); + else + xcolors[i] = SAEF_bswap32(xcolors[i]); + } + if (bpp <= 16) + xcolors[i] = ((xcolors[i] * 0x00010001) | xcolors[i]) >>> 0; - linedbld = linedbl = AMIGA.config.video.vresolution; - if (doublescan > 0 && interlace_seen <= 0) { - linedbl = 0; - linedbld = 1; } - amiga2aspect_line_map = new Int32Array((MAXVPOS + 1) * 2 + 1); - native2amiga_line_map = new Int32Array(h); + //#if defined(AGA) || defined(GFXFILTER) + this.alloc_colors_rgb(rw, gw, bw, rs, gs, bs, aw, as, alpha, byte_swap, xredcolors, xgreencolors, xbluecolors); + /* copy original color table */ + /*for (i = 0; i < 256; i++) { + redc[0 * 256 + i] = xredcolors[0]; + grec[0 * 256 + i] = xgreencolors[0]; + bluc[0 * 256 + i] = xbluecolors[0]; + redc[1 * 256 + i] = xredcolors[i]; + grec[1 * 256 + i] = xgreencolors[i]; + bluc[1 * 256 + i] = xbluecolors[i]; + redc[2 * 256 + i] = xredcolors[255]; + grec[2 * 256 + i] = xgreencolors[255]; + bluc[2 * 256 + i] = xbluecolors[255]; + }*/ - var maxl = (MAXVPOS + 1) << linedbld; - min_ypos_for_screen = minfirstline << linedbl; - max_drawn_amiga_line = -1; - for (i = 0; i < maxl; i++) { - var v = i - min_ypos_for_screen; - if (v >= h && max_drawn_amiga_line < 0) - max_drawn_amiga_line = i - min_ypos_for_screen; - if (i < min_ypos_for_screen || v >= h) - v = -1; - amiga2aspect_line_map[i] = v; + /*if (usedfilter !== null && usedfilter.yuv) { + // create internal 5:6:5 color tables + for (i = 0; i < 256; i++) { + j = i + 256; + xredcolors[i] = doColor(gamma[j][0], 5, 11); + xgreencolors[i] = doColor(gamma[j][1], 6, 5); + xbluecolors[i] = doColor(gamma[j][2], 5, 0); + if (bpp <= 16) { + xredcolors [i] = (xredcolors [i] * 0x00010001) >>> 0; + xgreencolors[i] = (xgreencolors[i] * 0x00010001) >>> 0; + xbluecolors [i] = (xbluecolors [i] * 0x00010001) >>> 0; + } + } + for (i = 0; i < 4096; i++) { + var r = ((i >> 8) << 4) | (i >> 8); + var g = (((i >> 4) & 0xf) << 4) | ((i >> 4) & 0x0f); + var b = ((i & 0xf) << 4) | (i & 0x0f); + r = gamma[r + 256][0]; + g = gamma[g + 256][1]; + b = gamma[b + 256][2]; + xcolors[i] = doMask(r, 5, 11) | doMask(g, 6, 5) | doMask(b, 5, 0); + if (byte_swap) { + if (bpp <= 16) + xcolors[i] = SAEF_bswap16(xcolors[i]); + else + xcolors[i] = SAEF_bswap32(xcolors[i]); + } + if (bpp <= 16) + xcolors[i] = ((xcolors[i] * 0x00010001) | xcolors[i]) >>> 0; + } + // create RGB 5:6:5 -> YUV tables + for (i = 0; i < 65536; i++) { + uae_u32 r, g, b; + r = (((i >> 11) & 31) << 3) | lowbits (i, 11, 3); + r = gamma[r + 256][0]; + g = (((i >> 5) & 63) << 2) | lowbits (i, 5, 2); + g = gamma[g + 256][1]; + b = (((i >> 0) & 31) << 3) | lowbits (i, 0, 3); + b = gamma[b + 256][2]; + tyhrgb[i] = get_yh (r, g, b) * 256 * 256; + tylrgb[i] = get_yl (r, g, b) * 256 * 256; + tcbrgb[i] = ((uae_s8)get_cb (r, g, b)) * 256; + tcrrgb[i] = ((uae_s8)get_cr (r, g, b)) * 256; + } + }*/ + //#endif + + //used by playfield.merge_2pixel16() + xredcolor_b = rw; + xgreencolor_b = gw; + xbluecolor_b = bw; + xredcolor_s = rs; + xgreencolor_s = gs; + xbluecolor_s = bs; + xredcolor_m = (((1 << rw) - 1) << xredcolor_s) >>> 0; + xgreencolor_m = (((1 << gw) - 1) << xgreencolor_s) >>> 0; + xbluecolor_m = (((1 << bw) - 1) << xbluecolor_s) >>> 0; + } + + /*-----------------------------------------------------------------------*/ + + function clearbuffer(dst) { + if (dst.bufmem_allocated !== null) { + /*uae_u8 *p = dst->bufmem_allocated; + for (int y = 0; y < dst->height_allocated; y++) { + memset(p, 0, dst->width_allocated * dst->pixbytes); + p += dst->rowbytes; + }*/ + for (var i = 0; i < dst.bufmem_allocated.length; i++) + dst.bufmem_allocated[i] = 0; } - if (max_drawn_amiga_line < 0) - max_drawn_amiga_line = maxl - min_ypos_for_screen; - max_drawn_amiga_line >>>= linedbl; - - if (AMIGA.config.video.ycenter) { - extra_y_adjust = (h - (this.maxvpos_nom << linedbl)) >> 1; - if (extra_y_adjust < 0) - extra_y_adjust = 0; - } - - for (i = 0; i < h; i++) - native2amiga_line_map[i] = -1; - - for (i = maxl - 1; i >= min_ypos_for_screen; i--) { - if (amiga2aspect_line_map[i] == -1) - continue; - for (var j = amiga2aspect_line_map[i]; j < h && native2amiga_line_map[j] == -1; j++) - native2amiga_line_map[j] = i >> linedbl; - } - - gfxvidinfo.xchange = 1 << (RES_MAX - AMIGA.config.video.hresolution); - gfxvidinfo.ychange = linedbl ? 1 : 2; - - visible_left_start = 0; - visible_right_stop = MAX_STOP; - visible_top_start = 0; - visible_bottom_stop = MAX_STOP; - //console.log('recreate_aspect_maps', amiga2aspect_line_map, native2amiga_line_map); - }; - - /*---------------------------------*/ - - function xlinecheck(id, start, end) { - var xstart = start * gfxvidinfo.drawbuffer.pixbytes; - var xend = end * gfxvidinfo.drawbuffer.pixbytes; - var end1 = gfxvidinfo.drawbuffer.rowbytes * gfxvidinfo.drawbuffer.height; - var min = Math.floor(linetoscr_x_adjust_bytes / gfxvidinfo.drawbuffer.pixbytes); - var ok = 1; - - if (xend > end1 || xstart >= end1) - ok = 0; - if ((xstart % gfxvidinfo.drawbuffer.rowbytes) >= gfxvidinfo.drawbuffer.width * gfxvidinfo.drawbuffer.pixbytes) - ok = 0; - if ((xend % gfxvidinfo.drawbuffer.rowbytes) >= gfxvidinfo.drawbuffer.width * gfxvidinfo.drawbuffer.pixbytes) - ok = 0; - if (xstart >= xend) - ok = 0; - if (xend - xstart > gfxvidinfo.drawbuffer.width * gfxvidinfo.drawbuffer.pixbytes) - ok = 0; - - if (!ok) { - console.log(id, start, end, min); - BUG.info('xlinecheck() ERROR %d-%d (%dx%dx%d %d)', - start - min, end - min, gfxvidinfo.drawbuffer.width, gfxvidinfo.drawbuffer.height, - gfxvidinfo.drawbuffer.pixbytes, gfxvidinfo.drawbuffer.rowbytes); - } - } - - /*---------------------------------*/ - - function max_diwlastword() { - return (0x1d4 - DISPLAY_LEFT_SHIFT + DIW_DDF_OFFSET - 1) << lores_shift; } - function xshift(x, shift) { - return shift < 0 ? x >> (-shift) : x << shift; + function reset_decision_table() { + //for (var i = 0; i < sizeof linestate / sizeof *linestate; i++) + for (var i = 0; i < LINESTATE_SIZE; i++) + linestate[i] = LINE_UNDECIDED; } - function coord_hw_to_window_x(x) { - return (x - DISPLAY_LEFT_SHIFT) << lores_shift; - } - function coord_window_to_hw_x(x) { - return (x >> lores_shift) + DISPLAY_LEFT_SHIFT; + function count_frame() { + framecnt++; + if (framecnt >= SAEV_config.video.framerate) + framecnt = 0; + if (inhibit_frame) + framecnt = 1; } - function coord_diw_to_window_x(x) { - return (x - DISPLAY_LEFT_SHIFT + DIW_DDF_OFFSET - 1) << lores_shift; + function xshift(x, shift) { + if (shift < 0) + return x >> (-shift); + else + return x << shift; } - function coord_window_to_diw_x(x) { - return (x >> lores_shift) + DISPLAY_LEFT_SHIFT - DIW_DDF_OFFSET; - } - - /*function coord_native_to_amiga_x(x) { - return xshift(x + visible_left_border, 1 - lores_shift) + 2 * DISPLAY_LEFT_SHIFT - 2 * DIW_DDF_OFFSET; + + function coord_native_to_amiga_x(x) { + x += visible_left_border; + x = xshift(x, 1 - lores_shift); + return x + 2 * DISPLAY_LEFT_SHIFT - 2 * DIW_DDF_OFFSET; } function coord_native_to_amiga_y(y) { return native2amiga_line_map[y] + thisframe_y_adjust - minfirstline; - }*/ + } function res_shift_from_window(x) { - return res_shift >= 0 ? x >> res_shift : x << -res_shift; + if (res_shift >= 0) + return x >> res_shift; + return x << (-res_shift); } - /*function res_shift_from_amiga(x) { - return res_shift >= 0 ? x >> res_shift : x << -res_shift; - }*/ - - /*---------------------------------*/ - - this.render_screen = function (immediate) { - if (AMIGA.config.video.enabled) - AMIGA.video.render(); - return true; - }; - this.show_screen = function () { - if (AMIGA.config.video.enabled) - AMIGA.video.show(); //flip - return true; - }; - - /*function flush_line(vb, lineno) { - AMIGA.video.drawline(lineno, xlinebuffer, linetoscr_x_adjust_bytes >> 2); - } - function flush_block(vb, first_line, last_line) { - console.log('flush_block() called', first_line, last_line); - } - function flush_screen(vb, first_line, last_line) { - console.log('flush_screen() called', first_line, last_line); + function res_shift_from_amiga(x) { + if (res_shift >= 0) + return x >> res_shift; + return x << (-res_shift); } - this.do_flush_line = function(vb, lineno) { - if (lineno < first_drawn_line) - first_drawn_line = lineno; - if (lineno > last_drawn_line) - last_drawn_line = lineno; - if (gfxvidinfo.maxblocklines == 0) - flush_line(vb, lineno); - else { - if ((last_block_line + 2) < lineno) { - if (first_block_line != NO_BLOCK) - flush_block(vb, first_block_line, last_block_line); - first_block_line = lineno; - } - last_block_line = lineno; - if (last_block_line - first_block_line >= gfxvidinfo.maxblocklines) { - flush_block(vb, first_block_line, last_block_line); - first_block_line = last_block_line = NO_BLOCK; - } - } - }*/ - - this.do_flush_line = function (vb, lineno) { - if (lineno < first_drawn_line) - first_drawn_line = lineno; - if (lineno > last_drawn_line) - last_drawn_line = lineno; + function notice_screen_contents_lost() { + picasso_redraw_necessary = 1; + frame_redraw_necessary = 2; + } - AMIGA.video.drawline(lineno, xlinebuffer, linetoscr_x_adjust_bytes >> 2); - }; - /*this.do_flush_screen = function(vb, start, stop) { - if (gfxvidinfo.maxblocklines != 0 && first_block_line != NO_BLOCK) - flush_block(vb, first_block_line, last_block_line); - if (start <= stop) - flush_screen(vb, start, stop); - }*/ - - /*---------------------------------*/ - - function is_ehb(con0, con2) { - if (AMIGA.config.chipset.mask & CSMASK_AGA) - return ((con0 & 0x7010) == 0x6000); - if (AMIGA.config.chipset.mask & CSMASK_ECS_DENISE) - return ((con0 & 0xFC00) == 0x6000 || (con0 & 0xFC00) == 0x7000); + const MIN_DISPLAY_W = 256; + const MIN_DISPLAY_H = 192; + const MAX_DISPLAY_W = 362; + const MAX_DISPLAY_H = 283; - return ((con0 & 0xFC00) == 0x6000 || (con0 & 0xFC00) == 0x7000);// && !currprefs.cs_denisenoehb; - } - - function is_ham(con0) { - var p = GET_PLANES(con0); - if (!(con0 & 0x800)) + var gclow = 0, gcloh = 0, gclox = 0, gcloy = 0, gclorealh = 0; //int + var stored_left_start = 0, stored_top_start = 0, stored_width = 0, stored_height = 0; //int + + this.isnativevidbuf = function() { + if (gfxvidinfo.outbuffer === null) return false; - if (AMIGA.config.chipset.mask & CSMASK_AGA) { - // AGA only has 6 or 8 plane HAM - if (p == 6 || p == 8) - return true; + if (gfxvidinfo.outbuffer === gfxvidinfo.drawbuffer) + return true; + return gfxvidinfo.outbuffer.nativepositioning; + } + + /*void get_custom_topedge(int *xp, int *yp, bool max) { + if (this.isnativevidbuf() && !max) { + var x, y; + x = visible_left_border + (DISPLAY_LEFT_SHIFT << SAEV_config.video.hresolution); + y = minfirstline << SAEV_config.video.vresolution; + #if 0 + var dbl1, dbl2; + dbl2 = dbl1 = SAEV_config.video.vresolution; + if (doublescan > 0 && interlace_seen <= 0) { + dbl1--; dbl2--; + } + x = -(visible_left_border + (DISPLAY_LEFT_SHIFT << SAEV_config.video.hresolution)); + y = -minfirstline << SAEV_config.video.vresolution; + y = xshift(y, dbl2); + #endif + *xp = x; + *yp = y; } else { - // OCS/ECS also supports 5 plane HAM - if (GET_RES_DENISE(con0) > 0) - return 0; - if (p >= 5) - return true; + *xp = 0; + *yp = 0; } - return false; - } - - /*function get_sprite_mask() { - var hi = new Uint64(0x00000000,0xFFFF0000); - hi.lshift(4 * plf2pri); - var lo = new Uint64(0x00000000,0x0000FFFF); - lo.lshift(4 * plf1pri); - hi.or(lo); - return hi; - }*/ - - this.pfield_expand_dp_bplcon = function () { - bplres = dp_for_drawing.bplres; - bplplanecnt = dp_for_drawing.nr_planes; - bplham = dp_for_drawing.ham_seen; - bplehb = dp_for_drawing.ehb_seen; - if ((AMIGA.config.chipset.mask & CSMASK_AGA) && (dp_for_drawing.bplcon2 & 0x0200)) - bplehb = 0; - issprites = dip_for_drawing.nr_sprites; - ecsshres = bplres == RES_SUPERHIRES && (AMIGA.config.chipset.mask & CSMASK_ECS_DENISE) && !(AMIGA.config.chipset.mask & CSMASK_AGA); + }*/ - plf1pri = dp_for_drawing.bplcon2 & 7; - plf2pri = (dp_for_drawing.bplcon2 >> 3) & 7; - plf_sprite_mask = 0xFFFF0000 << (4 * plf2pri); - plf_sprite_mask |= (0x0000FFFF << (4 * plf1pri)) & 0xFFFF; - plf_sprite_mask >>>= 0; - //plf_sprite_mask = get_sprite_mask(); + function reset_custom_limits() { //global + gclow = gcloh = gclox = gcloy = 0; + gclorealh = -1; + center_reset = true; + } - bpldualpf = (dp_for_drawing.bplcon0 & 0x400) == 0x400; - bpldualpfpri = (dp_for_drawing.bplcon2 & 0x40) == 0x40; + function set_blanking_limits() { //global + hblank_left_start = visible_left_start; + hblank_right_stop = visible_right_stop; - /*#ifdef AGA - bpldualpf2of = (dp_for_drawing.bplcon3 >> 10) & 7; - sbasecol[0] = ((dp_for_drawing.bplcon4 >> 4) & 15) << 4; - sbasecol[1] = ((dp_for_drawing.bplcon4 >> 0) & 15) << 4; - brdsprt = !brdblank && (AMIGA.config.chipset.mask & CSMASK_AGA) && (dp_for_drawing.bplcon0 & 1) && (dp_for_drawing.bplcon3 & 0x02); - bplxor = dp_for_drawing.bplcon4 >> 8; - #endif*/ - }; - - this.pfield_expand_dp_bplconx = function (regno, v) { - if (regno == 0xffff) { - //hposblank = 1; //FIXME - return; + if (programmedmode) { + if (hblank_left_start < coord_hw_to_window_x(hsyncendpos * 2)) + hblank_left_start = coord_hw_to_window_x(hsyncendpos * 2); + if (hblank_right_stop > coord_hw_to_window_x(hsyncstartpos * 2)) + hblank_right_stop = coord_hw_to_window_x(hsyncstartpos * 2); } - regno -= 0x1000; - switch (regno) { - case 0x100: - dp_for_drawing.bplcon0 = v; - dp_for_drawing.bplres = GET_RES_DENISE(v); - dp_for_drawing.nr_planes = GET_PLANES(v); - dp_for_drawing.ham_seen = is_ham(v); - break; - case 0x104: - dp_for_drawing.bplcon2 = v; - break; - case 0x106: - dp_for_drawing.bplcon3 = v; - break; - /*#ifdef AGA - case 0x10c: - dp_for_drawing.bplcon4 = v; - break; - #endif*/ - } - this.pfield_expand_dp_bplcon(); - res_shift = lores_shift - bplres; - }; - - this.center_image = function () { - var prev_x_adjust = visible_left_border; - var prev_y_adjust = thisframe_y_adjust; - var tmp; + } - var w = gfxvidinfo.drawbuffer.inwidth; - if (AMIGA.config.video.xcenter && max_diwstop > 0) { - if (max_diwstop - min_diwstart < w && AMIGA.config.video.xcenter == 2) - /* Try to center. */ - visible_left_border = ((max_diwstop - min_diwstart - w) >> 1) + min_diwstart; - else - visible_left_border = max_diwstop - w - ((max_diwstop - min_diwstart - w) >> 1); - visible_left_border &= ~((xshift(1, lores_shift)) - 1); - - /* Would the old value be good enough? If so, leave it as it is if we want to be clever. */ - if (AMIGA.config.video.xcenter == 2) { - if (center_reset || (visible_left_border < prev_x_adjust && prev_x_adjust < min_diwstart && min_diwstart - visible_left_border <= 32)) - visible_left_border = prev_x_adjust; - } - } else if (gfxvidinfo.drawbuffer.extrawidth) { - visible_left_border = max_diwlastword() - w; - if (gfxvidinfo.drawbuffer.extrawidth > 0) - visible_left_border += gfxvidinfo.drawbuffer.extrawidth << AMIGA.config.video.hresolution; + /*void get_custom_raw_limits (int *pw, int *ph, int *pdx, int *pdy) { + if (stored_width > 0) { + *pw = stored_width; + *ph = stored_height; + *pdx = stored_left_start; + *pdy = stored_top_start; } else { - if (gfxvidinfo.drawbuffer.inxoffset < 0) { - visible_left_border = 0; - } else { - visible_left_border = gfxvidinfo.drawbuffer.inxoffset - DISPLAY_LEFT_SHIFT; + int x = visible_left_border; + if (x < visible_left_start) + x = visible_left_start; + *pdx = x; + int x2 = visible_right_border; + if (x2 > visible_right_stop) + x2 = visible_right_stop; + *pw = x2 - x; + int y = min_ypos_for_screen; + if (y < visible_top_start) + y = visible_top_start; + *pdy = y; + int y2 = max_ypos_thisframe; + if (y2 > visible_bottom_stop) + y2 = visible_bottom_stop; + *ph = y2 - y; + } + }*/ + this.check_custom_limits = function() { + var vls = visible_left_start; + var vrs = visible_right_stop; + var vts = visible_top_start; + var vbs = visible_bottom_stop; + + var fd = SAEV_config.video.gf[0]; + var left = fd.gfx_filter_left_border >> (RES_MAX - SAEV_config.video.hresolution); + var right = fd.gfx_filter_right_border >> (RES_MAX - SAEV_config.video.hresolution); + var top = fd.gfx_filter_top_border; + var bottom = fd.gfx_filter_bottom_border; + + if (left > visible_left_start) + visible_left_start = left; + if (right > left && right < visible_right_stop) + visible_right_stop = right; + + if (top > visible_top_start) + visible_top_start = top; + if (bottom > top && bottom < visible_bottom_stop) + visible_bottom_stop = bottom; + + set_blanking_limits(); + } + this.set_custom_limits = function(w, h, dx, dy) { + var vls = visible_left_start; + var vrs = visible_right_stop; + var vts = visible_top_start; + var vbs = visible_bottom_stop; + + if (w <= 0 || dx < 0) { + visible_left_start = 0; + visible_right_stop = MAX_STOP; + } else { + visible_left_start = visible_left_border + dx; + visible_right_stop = visible_left_start + w; + } + if (h <= 0 || dy < 0) { + visible_top_start = 0; + visible_bottom_stop = MAX_STOP; + } else { + visible_top_start = min_ypos_for_screen + dy; + visible_bottom_stop = visible_top_start + h; + } + + if (vls != visible_left_start || vrs != visible_right_stop || vts != visible_top_start || vbs != visible_bottom_stop) + notice_screen_contents_lost(); + + this.check_custom_limits(); + } + this.store_custom_limits = function(w, h, x, y) { + stored_left_start = x; + stored_top_start = y; + stored_width = w; + stored_height = h; + } + /*int get_custom_limits (int *pw, int *ph, int *pdx, int *pdy, int *prealh) { + int w, h, dx, dy, y1, y2, dbl1, dbl2; + int ret = 0; + + if (!pw || !ph || !pdx || !pdy) { + reset_custom_limits(); + return 0; + } + + if (!this.isnativevidbuf()) { + *pw = gfxvidinfo.outbuffer->outwidth; + *ph = gfxvidinfo.outbuffer->outheight; + *pdx = 0; + *pdy = 0; + *prealh = -1; + return 1; + } + + *pw = gclow; + *ph = gcloh; + *pdx = gclox; + *pdy = gcloy; + *prealh = gclorealh; + + if (gclow > 0 && gcloh > 0) + ret = -1; + + if (interlace_seen) { + static int interlace_count; + // interlace = only use long frames + if (lof_store && (interlace_count & 1) == 0) + interlace_count++; + if (!lof_store && (interlace_count & 1) != 0) + interlace_count++; + if (interlace_count < 3) + return ret; + if (!lof_store) + return ret; + interlace_count = 0; + // program may have set last visible line as last possible line (CD32 boot screen) + if (last_planes_vpos < maxvpos) + last_planes_vpos++; + if (plflastline_total < maxvpos) + plflastline_total++; + } + + if (plflastline_total < 4) + plflastline_total = last_planes_vpos; + + ddffirstword_total = coord_hw_to_window_x (ddffirstword_total * 2 + DIW_DDF_OFFSET); + ddflastword_total = coord_hw_to_window_x (ddflastword_total * 2 + DIW_DDF_OFFSET); + + if (doublescan <= 0 && !programmedmode) { + int min = coord_diw_to_window_x (92); + int max = coord_diw_to_window_x (460); + if (diwfirstword_total < min) + diwfirstword_total = min; + if (diwlastword_total > max) + diwlastword_total = max; + if (ddffirstword_total < min) + ddffirstword_total = min; + if (ddflastword_total > max) + ddflastword_total = max; + if (0 && !(SAEV_config.chipset.mask & SAEC_Config_Chipset_Mask_AGA)) { + if (ddffirstword_total > diwfirstword_total) + diwfirstword_total = ddffirstword_total; + if (ddflastword_total < diwlastword_total) + diwlastword_total = ddflastword_total; } } - if (visible_left_border > max_diwlastword() - 32) - visible_left_border = max_diwlastword() - 32; - if (visible_left_border < 0) - visible_left_border = 0; - visible_left_border &= ~((xshift(1, lores_shift)) - 1); + w = diwlastword_total - diwfirstword_total; + dx = diwfirstword_total - visible_left_border; - linetoscr_x_adjust_bytes = visible_left_border * gfxvidinfo.drawbuffer.pixbytes; + y2 = plflastline_total; + if (y2 > last_planes_vpos) + y2 = last_planes_vpos; + y1 = plffirstline_total; + if (first_planes_vpos > y1) + y1 = first_planes_vpos; + if (minfirstline > y1) + y1 = minfirstline; - visible_right_border = visible_left_border + w; - if (visible_right_border > max_diwlastword()) - visible_right_border = max_diwlastword(); + dbl2 = dbl1 = SAEV_config.video.vresolution; + if (doublescan > 0 && interlace_seen <= 0) { + dbl1--; + dbl2--; + } - thisframe_y_adjust = minfirstline; - if (AMIGA.config.video.ycenter && thisframe_first_drawn_line >= 0) { - if (thisframe_last_drawn_line - thisframe_first_drawn_line < max_drawn_amiga_line && AMIGA.config.video.ycenter == 2) - thisframe_y_adjust = ((thisframe_last_drawn_line - thisframe_first_drawn_line - max_drawn_amiga_line) >> 1) + thisframe_first_drawn_line; - else - thisframe_y_adjust = thisframe_first_drawn_line + (((thisframe_last_drawn_line - thisframe_first_drawn_line) - max_drawn_amiga_line) >> 1); + h = y2 - y1; + dy = y1 - minfirstline; - if (AMIGA.config.video.ycenter == 2) { - if (center_reset || (thisframe_y_adjust != prev_y_adjust - && prev_y_adjust <= thisframe_first_drawn_line - && prev_y_adjust + max_drawn_amiga_line > thisframe_last_drawn_line)) - thisframe_y_adjust = prev_y_adjust; + if (first_planes_vpos == 0) { + // no planes enabled during frame + if (ret < 0) + return 1; + h = SAEV_config.chipset.ntsc ? 200 : 240; + w = 320 << SAEV_config.video.hresolution; + dy = 36 / 2; + dx = 58; + } + + if (dx < 0) + dx = 0; + + *prealh = -1; + if (!programmedmode && first_planes_vpos) { + int th = (maxvpos - minfirstline) * 95 / 100; + if (th > h) { + th = xshift (th, dbl1); + *prealh = th; } } - if (thisframe_y_adjust + max_drawn_amiga_line > this.maxvpos_nom) - thisframe_y_adjust = this.maxvpos_nom - max_drawn_amiga_line; - if (thisframe_y_adjust < minfirstline) - thisframe_y_adjust = minfirstline; - thisframe_y_adjust_real = thisframe_y_adjust << linedbl; - tmp = (this.maxvpos_nom - thisframe_y_adjust + 1) << linedbl; - if (tmp != max_ypos_thisframe) { - last_max_ypos = tmp; - if (last_max_ypos < 0) - last_max_ypos = 0; - } - max_ypos_thisframe = tmp; + dy = xshift (dy, dbl2); + h = xshift (h, dbl1); - if (prev_x_adjust != visible_left_border || prev_y_adjust != thisframe_y_adjust) - frame_redraw_necessary |= (interlace_seen > 0 && linedbl) ? 2 : 1; + if (w == 0 || h == 0) + return 0; - max_diwstop = 0; - min_diwstart = MAX_STOP; - - gfxvidinfo.drawbuffer.xoffset = (DISPLAY_LEFT_SHIFT << RES_MAX) + (visible_left_border << (RES_MAX - AMIGA.config.video.hresolution)); - gfxvidinfo.drawbuffer.yoffset = thisframe_y_adjust << VRES_MAX; - - center_reset = false; - }; - - /*---------------------------------*/ - - const COLOR_MATCH_ACOLORS = 1; - const COLOR_MATCH_FULL = 2; - var color_match_type = 0; - - this.adjust_drawing_colors = function (ctable, need_full) { - if (FAST_COLORS) { - if (need_full) - color_reg_cpy(colors_for_drawing, current_colors); - else - color_reg_cpy_acolors(colors_for_drawing, current_colors); - return; - } - if (drawing_color_matches != ctable) { - if (need_full) { - color_reg_cpy(colors_for_drawing, curr_color_tables[ctable]); - color_match_type = COLOR_MATCH_FULL; - } else { - //memcpy (colors_for_drawing.acolors, curr_color_tables[ctable].acolors, sizeof colors_for_drawing.acolors); - //for (var i = 0; i < colors_for_drawing.acolors.length; i++) colors_for_drawing.acolors[i] = curr_color_tables[ctable].acolors[i]; colors_for_drawing.borderblank = curr_color_tables[ctable].borderblank; - color_reg_cpy_acolors(colors_for_drawing, curr_color_tables[ctable]); - color_match_type = COLOR_MATCH_ACOLORS; + if (doublescan <= 0 && !programmedmode) { + if ((w >> SAEV_config.video.hresolution) < MIN_DISPLAY_W) { + dx += (w - (MIN_DISPLAY_W << SAEV_config.video.hresolution)) / 2; + w = MIN_DISPLAY_W << SAEV_config.video.hresolution; } - drawing_color_matches = ctable; - } - else if (need_full && color_match_type != COLOR_MATCH_FULL) { - color_reg_cpy(colors_for_drawing, curr_color_tables[ctable]); - color_match_type = COLOR_MATCH_FULL; - } - }; - - this.do_color_changes = function (worker_border, worker_pfield, vp) { - var lastpos = visible_left_border; - var endpos = visible_left_border + gfxvidinfo.drawbuffer.inwidth; - - for (var i = dip_for_drawing.first_color_change; i <= dip_for_drawing.last_color_change; i++) { - var regno = curr_color_changes[i].regno; - var value = curr_color_changes[i].value; - var nextpos, nextpos_in_range; - - if (i == dip_for_drawing.last_color_change) - nextpos = endpos; - else - nextpos = coord_hw_to_window_x(curr_color_changes[i].linepos); - - nextpos_in_range = nextpos; - if (nextpos > endpos) - nextpos_in_range = endpos; - - if (nextpos_in_range > lastpos) { - if (lastpos < playfield_start) { - var t = nextpos_in_range <= playfield_start ? nextpos_in_range : playfield_start; - worker_border(lastpos, t, false); - lastpos = t; - } + if ((h >> dbl1) < MIN_DISPLAY_H) { + dy += (h - (MIN_DISPLAY_H << dbl1)) / 2; + h = MIN_DISPLAY_H << dbl1; } - if (nextpos_in_range > lastpos) { - if (lastpos >= playfield_start && lastpos < playfield_end) { - var t = nextpos_in_range <= playfield_end ? nextpos_in_range : playfield_end; - worker_pfield(lastpos, t, false); - // blank start and end that shouldn't be visible - if (lastpos < visible_left_start) - worker_border(lastpos, visible_left_start, true); - if (t > visible_right_stop) - worker_border(visible_right_stop, endpos, true); - lastpos = t; - } + if ((w >> SAEV_config.video.hresolution) > MAX_DISPLAY_W) { + dx += (w - (MAX_DISPLAY_W << SAEV_config.video.hresolution)) / 2; + w = MAX_DISPLAY_W << SAEV_config.video.hresolution; } - if (nextpos_in_range > lastpos) { - if (lastpos >= playfield_end) - worker_border(lastpos, nextpos_in_range, false); - lastpos = nextpos_in_range; + if ((h >> dbl1) > MAX_DISPLAY_H) { + dy += (h - (MAX_DISPLAY_H << dbl1)) / 2; + h = MAX_DISPLAY_H << dbl1; } + } - if (regno >= 0x1000) - this.pfield_expand_dp_bplconx(regno, value); - else if (regno >= 0) { - if (regno == 0 && (value & COLOR_CHANGE_BRDBLANK)) - colors_for_drawing.borderblank = (value & 1) != 0; - else { - color_reg_set(colors_for_drawing, regno, value); - colors_for_drawing.acolors[regno] = getxcolor(value); - } - } - if (lastpos >= endpos) - break; + if (gclow == w && gcloh == h && gclox == dx && gcloy == dy) + return ret; + + if (w <= 0 || h <= 0 || dx < 0 || dy < 0) + return ret; + if (doublescan <= 0 && !programmedmode) { + if (dx > gfxvidinfo.outbuffer->inwidth / 3) + return ret; + if (dy > gfxvidinfo.outbuffer->inheight / 3) + return ret; } - if (vp < visible_top_start || vp >= visible_bottom_stop) { - // outside of visible area - // Just overwrite with black. Above code needs to run because of custom registers, - // not worth the trouble for separate code path just for max 10 lines or so - worker_border(visible_left_border, visible_left_border + gfxvidinfo.drawbuffer.inwidth, true); + + gclow = w; + gcloh = h; + gclox = dx; + gcloy = dy; + gclorealh = *prealh; + *pw = w; + *ph = h; + *pdx = dx; + *pdy = dy; + center_reset = true; + return 1; + }*/ + + /*void get_custom_mouse_limits (int *pw, int *ph, int *pdx, int *pdy, int dbl) { + int delay1, delay2; + int w, h, dx, dy, dbl1, dbl2, y1, y2; + + w = diwlastword_total - diwfirstword_total; + dx = diwfirstword_total - visible_left_border; + + y2 = plflastline_total; + if (y2 > last_planes_vpos) + y2 = last_planes_vpos; + y1 = plffirstline_total; + if (first_planes_vpos > y1) + y1 = first_planes_vpos; + if (minfirstline > y1) + y1 = minfirstline; + + h = y2 - y1; + dy = y1 - minfirstline; + + if (*pw > 0) + w = *pw; + + w = xshift (w, res_shift); + + if (*ph > 0) + h = *ph; + + delay1 = (firstword_bplcon1 & 0x0f) | ((firstword_bplcon1 & 0x0c00) >> 6); + delay2 = ((firstword_bplcon1 >> 4) & 0x0f) | (((firstword_bplcon1 >> 4) & 0x0c00) >> 6); + // if (delay1 == delay2) + // dx += delay1; + + dx = xshift (dx, res_shift); + + dbl2 = dbl1 = SAEV_config.video.vresolution; + if ((doublescan > 0 || interlace_seen > 0) && !dbl) { + dbl1--; + dbl2--; } - }; - - /*---------------------------------*/ - + if (interlace_seen > 0) + dbl2++; + if (interlace_seen <= 0 && dbl) + dbl2--; + h = xshift (h, dbl1); + dy = xshift (dy, dbl2); + + if (w < 1) + w = 1; + if (h < 1) + h = 1; + if (dx < 0) + dx = 0; + if (dy < 0) + dy = 0; + *pw = w; *ph = h; + *pdx = dx; *pdy = dy; + }*/ + + + + var dp_for_drawing = null; //struct decision * + var dip_for_drawing = null; //struct draw_info * + + /* Record DIW of the current line for use by centering code. */ + function record_diw_line(plfstrt, first, last) { + if (last > max_diwstop) + max_diwstop = last; + if (first < min_diwstart) { + min_diwstart = first; + /*if (plfstrt * 2 > min_diwstart) + min_diwstart = plfstrt * 2;*/ + } + } + + function get_shdelay_add() { + if (bplres == SAEC_Config_Video_HResolution_SuperHiRes) + return 0; + /*var add = bpldelay_sh; + add >>= RES_MAX - SAEV_config.video.hresolution; + return add;*/ + return bpldelay_sh >> (RES_MAX - SAEV_config.video.hresolution); + } + + /* + * Screen update macros/functions + */ + + /* The important positions in the line: where do we start drawing the left border, + where do we start drawing the playfield, where do we start drawing the right border. + All of these are forced into the visible window (VISIBLE_LEFT_BORDER .. VISIBLE_RIGHT_BORDER). + PLAYFIELD_START and PLAYFIELD_END are in window coordinates. */ + var playfield_start = 0, playfield_end = 0; //int + var real_playfield_start = 0, real_playfield_end = 0; //int + var sprite_playfield_start = 0; //int + var may_require_hard_way = false; //bool + var linetoscr_diw_start = 0, linetoscr_diw_end = 0; //int + var native_ddf_left = 0, native_ddf_right = 0; //int + + var pixels_offset = 0; //int + var src_pixel = 0; //int + var unpainted = 0; //int /* How many pixels in window coordinates which are to the left of the left border. */ + function getbgc(blank) { -/*#if 0 + /*#if BG_COLOR_DEBUG if (blank) return xcolors[0x088]; else if (hposblank == 1) @@ -1203,80 +1608,282 @@ function Playfield() { return xcolors[0x0f0]; else if (hposblank == 3) return xcolors[0x00f]; - else if (brdblank) + else if (ce_is_borderblank(colors_for_drawing.extra)) return xcolors[0x880]; //return colors_for_drawing.acolors[0]; return xcolors[0xf0f]; -#endif*/ - return (blank || hposblank || colors_for_drawing.borderblank) ? 0 : colors_for_drawing.acolors[0]; + #endif*/ + return (blank || hposblank || ce_is_borderblank(colors_for_drawing.extra)) ? 0 : colors_for_drawing.acolors[0]; } - function fill_line_16(buf, start, stop, blank) { - console.log('fill_line_16() NI', start, stop, blank); - /*uae_u16 *b = (uae_u16 *)buf; - var rem = 0; - var col = getbgc(blank); - - if (((long)&b[start]) & 1) + function set_res_shift(shift) { + var old = res_shift; + res_shift = shift; + if (res_shift != old) + pfield_set_linetoscr(); + } + + /* Initialize the variables necessary for drawing a line. This involves setting up start/stop positions and display window borders. */ + function pfield_init_linetoscr(border) { + /* First, get data fetch start/stop in DIW coordinates. */ + var ddf_left = dp_for_drawing.plfleft * 2 + DIW_DDF_OFFSET; + var ddf_right = dp_for_drawing.plfright * 2 + DIW_DDF_OFFSET; + var leftborderhidden; + var native_ddf_left2; + + if (border) + ddf_left = DISPLAY_LEFT_SHIFT; + + /* Compute datafetch start/stop in pixels; native display coordinates. */ + native_ddf_left = coord_hw_to_window_x(ddf_left); + native_ddf_right = coord_hw_to_window_x(ddf_right); + + // Blerkenwiegel/Scoopex workaround + native_ddf_left2 = native_ddf_left; + if (native_ddf_left < 0) + native_ddf_left = 0; + + if (native_ddf_right < native_ddf_left) + native_ddf_right = native_ddf_left; + + linetoscr_diw_start = dp_for_drawing.diwfirstword; + linetoscr_diw_end = dp_for_drawing.diwlastword; + + /* Perverse cases happen. */ + if (linetoscr_diw_end < linetoscr_diw_start) + linetoscr_diw_end = linetoscr_diw_start; + + set_res_shift(lores_shift - bplres); + + playfield_start = linetoscr_diw_start; + playfield_end = linetoscr_diw_end; + + if (playfield_start < native_ddf_left) + playfield_start = native_ddf_left; + if (playfield_end > native_ddf_right) + playfield_end = native_ddf_right; + + if (playfield_start < visible_left_border) + playfield_start = visible_left_border; + if (playfield_start > visible_right_border) + playfield_start = visible_right_border; + if (playfield_end < visible_left_border) + playfield_end = visible_left_border; + if (playfield_end > visible_right_border) + playfield_end = visible_right_border; + + real_playfield_start = playfield_start; + sprite_playfield_start = playfield_start; + real_playfield_end = playfield_end; + + // Sprite hpos don't include DIW_DDF_OFFSET and can appear 1 lores pixel + // before first bitplane pixel appears. + // This means "bordersprite" condition is possible under OCS/ECS too. Argh! + if (dip_for_drawing.nr_sprites) { + if (!ce_is_borderblank(colors_for_drawing.extra)) { + /* bordersprite off or not supported: sprites are visible until diw_end */ + if (playfield_end < linetoscr_diw_end && hblank_right_stop > playfield_end) { + playfield_end = linetoscr_diw_end; + } + var left = coord_hw_to_window_x(dp_for_drawing.plfleft * 2); + if (left < visible_left_border) + left = visible_left_border; + if (left < playfield_start && left >= linetoscr_diw_start) { + playfield_start = left; + } + } else { + sprite_playfield_start = 0; + if (playfield_end < linetoscr_diw_end && hblank_right_stop > playfield_end) { + playfield_end = linetoscr_diw_end; + } + } + } + + //#ifdef AGA + may_require_hard_way = false; + if (dp_for_drawing.bordersprite_seen && !ce_is_borderblank(colors_for_drawing.extra) && dip_for_drawing.nr_sprites) { + var min = visible_right_border, max = visible_left_border, i; + for (i = 0; i < dip_for_drawing.nr_sprites; i++) { + var x; + x = curr_sprite_entries[dip_for_drawing.first_sprite_entry + i].pos; + if (x < min) + min = x; + // include max extra pixels, sprite may be 2x or 4x size: 4x - 1. + x = curr_sprite_entries[dip_for_drawing.first_sprite_entry + i].max + (4 - 1); + if (x > max) + max = x; + } + min = coord_hw_to_window_x(min >> sprite_buffer_res) + (DIW_DDF_OFFSET << lores_shift); + max = coord_hw_to_window_x(max >> sprite_buffer_res) + (DIW_DDF_OFFSET << lores_shift); + + if (min < playfield_start) + playfield_start = min; + if (playfield_start < visible_left_border) + playfield_start = visible_left_border; + if (max > playfield_end) + playfield_end = max; + if (playfield_end > visible_right_border) + playfield_end = visible_right_border; + sprite_playfield_start = 0; + may_require_hard_way = true; + } + //#endif + + unpainted = visible_left_border < playfield_start ? 0 : visible_left_border - playfield_start; + unpainted = res_shift_from_window(unpainted); + + var first_x = sprite_first_x; + var last_x = sprite_last_x; + if (first_x < last_x) { + if (dp_for_drawing.bordersprite_seen && !ce_is_borderblank(colors_for_drawing.extra)) { + if (first_x > visible_left_border) + first_x = visible_left_border; + if (last_x < visible_right_border) + last_x = visible_right_border; + } + if (first_x < 0) + first_x = 0; + if (last_x > MAX_PIXELS_PER_LINE - 2) + last_x = MAX_PIXELS_PER_LINE - 2; + if (first_x < last_x) { + //memset(spritepixels + first_x, 0, sizeof (struct spritepixelsbuf) * (last_x - first_x + 1)); + for (var i = first_x; i <= last_x; i++) spritepixels[i].clr(); + } + } + + sprite_last_x = 0; + sprite_first_x = MAX_PIXELS_PER_LINE - 1; + + /* Now, compute some offsets. */ + ddf_left -= DISPLAY_LEFT_SHIFT; + pixels_offset = MAX_PIXELS_PER_LINE - (ddf_left << bplres); + ddf_left <<= bplres; + + leftborderhidden = playfield_start - native_ddf_left2; + if (hblank_left_start > playfield_start) + leftborderhidden += hblank_left_start - playfield_start; + src_pixel = MAX_PIXELS_PER_LINE + res_shift_from_window(leftborderhidden); + + if (dip_for_drawing.nr_sprites == 0) + return; + + if (aga_mode) { + var add = get_shdelay_add(); + if (add) { + if (sprite_playfield_start > 0) + sprite_playfield_start -= add; + else + playfield_start -= add; + } + } + + /* We need to clear parts of apixels. */ + if (linetoscr_diw_start < native_ddf_left) { + var len = res_shift_from_window(native_ddf_left - linetoscr_diw_start); + var start = MAX_PIXELS_PER_LINE - len; + var end = start + len; + for (var i = start; i < end; i++) pixdata.apixels[i] = 0; + linetoscr_diw_start = native_ddf_left; + } + if (linetoscr_diw_end > native_ddf_right) { + var start = MAX_PIXELS_PER_LINE + res_shift_from_window(native_ddf_right - native_ddf_left); + var end = start + res_shift_from_window(linetoscr_diw_end - native_ddf_right); + for (var i = start; i < end; i++) pixdata.apixels[i] = 0; + linetoscr_diw_start = native_ddf_left; + } + } + + // erase sprite graphics in pixdata if they were outside of ddf + function pfield_erase_hborder_sprites() { + if (sprite_first_x < native_ddf_left) { + var len = res_shift_from_window(native_ddf_left - sprite_first_x); + var start = MAX_PIXELS_PER_LINE - len; + var end = start + len; + for (var i = start; i < end; i++) pixdata.apixels[i] = 0; + } + if (sprite_last_x > native_ddf_right) { + var start = MAX_PIXELS_PER_LINE + res_shift_from_window(native_ddf_right - native_ddf_left); + var end = start + res_shift_from_window(sprite_last_x - native_ddf_right); + for (var i = start; i < end; i++) pixdata.apixels[i] = 0; + } + } + + // erase whole viewable area if sprite in upper or lower border + function pfield_erase_vborder_sprites() { + if (visible_right_border <= visible_left_border) + return; + var pos = 0, len = 0; + if (visible_left_border < native_ddf_left) { + len = res_shift_from_window(native_ddf_left - visible_left_border); + pos = -len; + } + if (visible_right_border > native_ddf_left) + len += res_shift_from_window(visible_right_border - native_ddf_left); + + var start = MAX_PIXELS_PER_LINE - pos; + var end = start + len; + for (var i = start; i < end; i++) pixdata.apixels[i] = 0; + } + + /*STATIC_INLINE void fill_line_16 (uae_u8 *buf, int start, int stop, bool blank) { + uae_u16 *b = (uae_u16 *)buf; + unsigned int i; + unsigned int rem = 0; + xcolnr col = getbgc (blank); + if (((uintptr_t)&b[start]) & 1) b[start++] = (uae_u16) col; - if (start >= stop) return; - - if (((long)&b[stop]) & 1) { + if (((uintptr_t)&b[stop]) & 1) { rem++; stop--; } - for (var i = start; i < stop; i += 2) { + for (i = start; i < stop; i += 2) { uae_u32 *b2 = (uae_u32 *)&b[i]; *b2 = col; } if (rem) - b[stop] = (uae_u16)col;*/ + b[stop] = (uae_u16)col; } - function fill_line_32(buf, start, stop, blank) { - var col = getbgc(blank); - for (var i = start; i < stop; i++) - buf[i] = col; - } - - function pfield_do_fill_line2(start, stop, blank) { + STATIC_INLINE void fill_line_32 (uae_u8 *buf, int start, int stop, bool blank) { + uae_u32 *b = (uae_u32 *)buf; + unsigned int i; + xcolnr col = getbgc (blank); + for (i = start; i < stop; i++) + b[i] = col; + } + static void pfield_do_fill_line (int start, int stop, bool blank) { switch (gfxvidinfo.drawbuffer.pixbytes) { - case 2: fill_line_16(xlinebuffer, start, stop, blank); break; - case 4: fill_line_32(xlinebuffer, start, stop, blank); break; + case 2: fill_line_16 (xlinebuffer, start, stop, blank); break; + case 4: fill_line_32 (xlinebuffer, start, stop, blank); break; } - } + if (need_genlock_data) + memset(xlinebuffer_genlock + start, 0, stop - start); + }*/ function pfield_do_fill_line(start, stop, blank) { - //console.log('pfield_do_fill_line()', start, stop, blank); - //xlinecheck('pfield_do_fill_line', start, stop); - if (!blank) { - if (start < visible_left_start) { - pfield_do_fill_line2(start, visible_left_start, true); - start = visible_left_start; - } - if (stop > visible_right_stop) { - pfield_do_fill_line2(start, visible_right_stop, false); - blank = true; - start = visible_right_stop; - } - } - pfield_do_fill_line2(start, stop, blank); - } - - function fill_line2(startpos, len) { - //console.log('fill_line2', startpos, len); - /*var shift = 0; - if (gfxvidinfo.drawbuffer.pixbytes == 2) shift = 1; - if (gfxvidinfo.drawbuffer.pixbytes == 4) shift = 2;*/ + //xlinebuffer.fill(getbgc(blank), start + xlinebuffer_pos, stop + xlinebuffer_pos); + //SAEF_memset(xlinebuffer,start + xlinebuffer_pos, getbgc(blank), stop - start); + var col = getbgc(blank); + for (var i = start + xlinebuffer_pos, j = stop + xlinebuffer_pos; i < j; i++) xlinebuffer[i] = col; - var nints = len;// >> (2 - shift); - var nrem = nints & 7; + /*if (need_genlock_data) + memset(xlinebuffer_genlock + start, 0, stop - start);*/ + } + + /*static void fill_line2 (int startpos, int len) { + int shift, nints, nrem, *start; + xcolnr val; + + shift = 0; + if (gfxvidinfo.drawbuffer.pixbytes == 2) shift = 1; + if (gfxvidinfo.drawbuffer.pixbytes == 4) shift = 2; + + nints = len >> (2 - shift); + nrem = nints & 7; nints &= ~7; - //int *start = (int *)(((uae_u8*)xlinebuffer) + (startpos << shift)); - var start = startpos;// << shift >> 2; - var val = getbgc(false); - - /*for (; nints > 0; nints -= 8, start += 8) { + start = (int *)(((uae_u8*)xlinebuffer) + (startpos << shift)); + val = getbgc (false); + for (; nints > 0; nints -= 8, start += 8) { *start = val; *(start+1) = val; *(start+2) = val; @@ -1294,8 +1901,20 @@ function Playfield() { case 3: *start++ = val; case 2: *start++ = val; case 1: *start = val; - }*/ - + } + }*/ + /*function fill_line2(startpos, len) { + var shift = 0; + if (gfxvidinfo.drawbuffer.pixbytes == 2) shift = 1; + if (gfxvidinfo.drawbuffer.pixbytes == 4) shift = 2; + + var nints = len >> (2 - shift); + var nrem = nints & 7; + nints &= ~7; + + //var start = (int *)(((uae_u8*)xlinebuffer) + (startpos << shift)); + var start = startpos + xlinebuffer_pos; + var val = getbgc(false); for (; nints > 0; nints -= 8, start += 8) { xlinebuffer[start ] = val; xlinebuffer[start + 1] = val; @@ -1315,1397 +1934,99 @@ function Playfield() { case 2: xlinebuffer[start++] = val; case 1: xlinebuffer[start] = val; } - } - function fill_line() { - var hs = coord_hw_to_window_x(hsyncstartpos * 2); - if (hs >= gfxvidinfo.drawbuffer.inwidth || hposblank) { - //hposblank = 3; //FIXME - fill_line2(visible_left_border, gfxvidinfo.drawbuffer.inwidth); - } else { - fill_line2(visible_left_border, hs); - //hposblank = 2; //FIXME - fill_line2(visible_left_border + hs, gfxvidinfo.drawbuffer.inwidth); - } - } - - /*---------------------------------*/ - - this.pfield_init_linetoscr = function () { - var ddf_left = dp_for_drawing.plfleft * 2 + DIW_DDF_OFFSET; - var ddf_right = dp_for_drawing.plfright * 2 + DIW_DDF_OFFSET; - - native_ddf_left = coord_hw_to_window_x(ddf_left); - native_ddf_right = coord_hw_to_window_x(ddf_right); - - linetoscr_diw_start = dp_for_drawing.diwfirstword; - linetoscr_diw_end = dp_for_drawing.diwlastword; - - res_shift = lores_shift - bplres; - - if (dip_for_drawing.nr_sprites == 0) { - if (linetoscr_diw_start < native_ddf_left) - linetoscr_diw_start = native_ddf_left; - if (linetoscr_diw_end > native_ddf_right) - linetoscr_diw_end = native_ddf_right; - } - if (linetoscr_diw_end < linetoscr_diw_start) - linetoscr_diw_end = linetoscr_diw_start; - - playfield_start = linetoscr_diw_start; - playfield_end = linetoscr_diw_end; - - unpainted = visible_left_border < playfield_start ? 0 : visible_left_border - playfield_start; - ham_src_pixel = MAX_PIXELS_PER_LINE + res_shift_from_window(playfield_start - native_ddf_left); - unpainted = res_shift_from_window(unpainted); - - if (playfield_start < visible_left_border) - playfield_start = visible_left_border; - if (playfield_start > visible_right_border) - playfield_start = visible_right_border; - if (playfield_end < visible_left_border) - playfield_end = visible_left_border; - if (playfield_end > visible_right_border) - playfield_end = visible_right_border; - - real_playfield_end = playfield_end; - real_playfield_start = playfield_start; - - /*#ifdef AGA - if (brdsprt && dip_for_drawing.nr_sprites) { - var min = visible_right_border, max = visible_left_border, i; - for (i = 0; i < dip_for_drawing.nr_sprites; i++) { - var x; - x = curr_sprite_entries[dip_for_drawing.first_sprite_entry + i].pos; - if (x < min) - min = x; - x = curr_sprite_entries[dip_for_drawing.first_sprite_entry + i].max; - if (x > max) - max = x; - } - min = coord_hw_to_window_x (min >> sprite_buffer_res) + (DIW_DDF_OFFSET << lores_shift); - max = coord_hw_to_window_x (max >> sprite_buffer_res) + (DIW_DDF_OFFSET << lores_shift); - if (min < playfield_start) - playfield_start = min; - if (playfield_start < visible_left_border) - playfield_start = visible_left_border; - if (max > playfield_end) - playfield_end = max; - if (playfield_end > visible_right_border) - playfield_end = visible_right_border; - } - #endif*/ - - if (sprite_first_x < sprite_last_x) { - if (sprite_first_x < 0) - sprite_first_x = 0; - if (sprite_last_x >= MAX_PIXELS_PER_LINE - 1) - sprite_last_x = MAX_PIXELS_PER_LINE - 2; - if (sprite_first_x < sprite_last_x) { - //memset (spritepixels + sprite_first_x, 0, sizeof (struct SpritePixelsBuf) * (sprite_last_x - sprite_first_x + 1)); - for (var i = sprite_first_x; i <= sprite_last_x; i++) { - spritepixels[i].clr(); - } - } - } - sprite_last_x = 0; - sprite_first_x = MAX_PIXELS_PER_LINE - 1; - - ddf_left -= DISPLAY_LEFT_SHIFT; - pixels_offset = MAX_PIXELS_PER_LINE - (ddf_left << bplres); - //ddf_left <<= bplres; - src_pixel = MAX_PIXELS_PER_LINE + res_shift_from_window(playfield_start - native_ddf_left); - - if (dip_for_drawing.nr_sprites == 0) - return; - - /* Must clear parts of apixels. */ - if (linetoscr_diw_start < native_ddf_left) { - var size = res_shift_from_window(native_ddf_left - linetoscr_diw_start); - linetoscr_diw_start = native_ddf_left; - //memset (apixels + MAX_PIXELS_PER_LINE - size, 0, size); - for (var i = 0; i < size; i++) { - apixels[MAX_PIXELS_PER_LINE - size + i] = 0; - } - } - if (linetoscr_diw_end > native_ddf_right) { - var pos = res_shift_from_window(native_ddf_right - native_ddf_left); - var size = res_shift_from_window(linetoscr_diw_end - native_ddf_right); - linetoscr_diw_start = native_ddf_left; - //memset (apixels + MAX_PIXELS_PER_LINE + pos, 0, size); - for (var i = 0; i < size; i++) { - apixels[MAX_PIXELS_PER_LINE + pos + i] = 0; - } - } - }; - - function dummy_worker(start, stop, blank) { } - - - function linetoscr_32(spix, dpix, stoppos) { - //uae_u32 *buf = (uae_u32 *) xlinebuffer; - if (dp_for_drawing.ham_seen) { - while (dpix < stoppos) { - var dpix_val; - var out_val; - - dpix_val = xcolors[ham_linebuf[spix]]; - spix++; - out_val = dpix_val; - xlinebuffer[dpix++] = out_val; - } - } else if (bpldualpf) { - var lookup = bpldualpfpri ? dblpf_ind2 : dblpf_ind1; - while (dpix < stoppos) { - var spix_val; - var dpix_val; - var out_val; - - spix_val = apixels[spix]; - dpix_val = colors_for_drawing.acolors[lookup[spix_val]]; - spix++; - out_val = dpix_val; - xlinebuffer[dpix++] = out_val; - } - } else if (bplehb) { - while (dpix < stoppos) { - var spix_val; - var dpix_val; - var out_val; - - spix_val = apixels[spix]; - if (spix_val <= 31) - dpix_val = colors_for_drawing.acolors[spix_val]; - else - dpix_val = xcolors[(colors_for_drawing.color_regs_ecs[spix_val - 32] >> 1) & 0x777]; - spix++; - out_val = dpix_val; - xlinebuffer[dpix++] = out_val; - } - } else { - while (dpix < stoppos) { - var spix_val; - var dpix_val; - var out_val; - - spix_val = apixels[spix]; - dpix_val = colors_for_drawing.acolors[spix_val]; - spix++; - out_val = dpix_val; - xlinebuffer[dpix++] = out_val; - } - } - - return spix; - } - - function linetoscr_32_stretch1(spix, dpix, stoppos) { - //uae_u32 *buf = (uae_u32 *) xlinebuffer; - if (dp_for_drawing.ham_seen) { - while (dpix < stoppos) { - var dpix_val; - var out_val; - - dpix_val = xcolors[ham_linebuf[spix]]; - spix++; - out_val = dpix_val; - xlinebuffer[dpix++] = out_val; - xlinebuffer[dpix++] = out_val; - } - } else if (bpldualpf) { - var lookup = bpldualpfpri ? dblpf_ind2 : dblpf_ind1; - while (dpix < stoppos) { - var spix_val; - var dpix_val; - var out_val; - - spix_val = apixels[spix]; - dpix_val = colors_for_drawing.acolors[lookup[spix_val]]; - spix++; - out_val = dpix_val; - xlinebuffer[dpix++] = out_val; - xlinebuffer[dpix++] = out_val; - } - } else if (bplehb) { - while (dpix < stoppos) { - var spix_val; - var dpix_val; - var out_val; - - spix_val = apixels[spix]; - if (spix_val <= 31) - dpix_val = colors_for_drawing.acolors[spix_val]; - else - dpix_val = xcolors[(colors_for_drawing.color_regs_ecs[spix_val - 32] >> 1) & 0x777]; - spix++; - out_val = dpix_val; - xlinebuffer[dpix++] = out_val; - xlinebuffer[dpix++] = out_val; - } - } else { - while (dpix < stoppos) { - var spix_val; - var dpix_val; - var out_val; - - spix_val = apixels[spix]; - dpix_val = colors_for_drawing.acolors[spix_val]; - spix++; - out_val = dpix_val; - xlinebuffer[dpix++] = out_val; - xlinebuffer[dpix++] = out_val; - } - } - return spix; - } - - function linetoscr_32_shrink1(spix, dpix, stoppos) { - //uae_u32 *buf = (uae_u32 *) xlinebuffer; - if (dp_for_drawing.ham_seen) { - while (dpix < stoppos) { - var dpix_val; - var out_val; - - dpix_val = xcolors[ham_linebuf[spix]]; - spix += 2; - out_val = dpix_val; - xlinebuffer[dpix++] = out_val; - } - } else if (bpldualpf) { - var lookup = bpldualpfpri ? dblpf_ind2 : dblpf_ind1; - while (dpix < stoppos) { - var spix_val; - var dpix_val; - var out_val; - - spix_val = apixels[spix]; - dpix_val = colors_for_drawing.acolors[lookup[spix_val]]; - spix += 2; - out_val = dpix_val; - xlinebuffer[dpix++] = out_val; - } - } else if (bplehb) { - while (dpix < stoppos) { - var spix_val; - var dpix_val; - var out_val; - - spix_val = apixels[spix]; - if (spix_val <= 31) - dpix_val = colors_for_drawing.acolors[spix_val]; - else - dpix_val = xcolors[(colors_for_drawing.color_regs_ecs[spix_val - 32] >> 1) & 0x777]; - spix += 2; - out_val = dpix_val; - xlinebuffer[dpix++] = out_val; - } - } else { - while (dpix < stoppos) { - var spix_val; - var dpix_val; - var out_val; - - spix_val = apixels[spix]; - dpix_val = colors_for_drawing.acolors[spix_val]; - spix += 2; - out_val = dpix_val; - xlinebuffer[dpix++] = out_val; - } - } - return spix; - } - - - function linetoscr_32_spr(spix, dpix, stoppos) { - //uae_u32 *buf = (uae_u32 *) xlinebuffer; - var sprcol; - - if (dp_for_drawing.ham_seen) { - while (dpix < stoppos) { - var sprpix_val; - var dpix_val; - var out_val; - - dpix_val = xcolors[ham_linebuf[spix]]; - sprpix_val = dpix_val; - spix++; - out_val = dpix_val; - if (spritepixels[dpix].data) { - sprcol = render_sprites (dpix, 0, sprpix_val, 0); - if (sprcol) { - out_val = colors_for_drawing.acolors[sprcol]; - } - } - xlinebuffer[dpix++] = out_val; - } - } else if (bpldualpf) { - var lookup = bpldualpfpri ? dblpf_ind2 : dblpf_ind1; - while (dpix < stoppos) { - var sprpix_val; - var spix_val; - var dpix_val; - var out_val; - - spix_val = apixels[spix]; - sprpix_val = spix_val; - dpix_val = colors_for_drawing.acolors[lookup[spix_val]]; - spix++; - out_val = dpix_val; - if (spritepixels[dpix].data) { - sprcol = render_sprites (dpix, 1, sprpix_val, 0); - if (sprcol) { - out_val = colors_for_drawing.acolors[sprcol]; - } - } - xlinebuffer[dpix++] = out_val; - } - } else if (bplehb) { - while (dpix < stoppos) { - var sprpix_val; - var spix_val; - var dpix_val; - var out_val; - - spix_val = apixels[spix]; - sprpix_val = spix_val; - if (spix_val <= 31) - dpix_val = colors_for_drawing.acolors[spix_val]; - else - dpix_val = xcolors[(colors_for_drawing.color_regs_ecs[spix_val - 32] >> 1) & 0x777]; - spix++; - out_val = dpix_val; - if (spritepixels[dpix].data) { - sprcol = render_sprites (dpix, 0, sprpix_val, 0); - if (sprcol) { - out_val = colors_for_drawing.acolors[sprcol]; - } - } - xlinebuffer[dpix++] = out_val; - } - } else { - while (dpix < stoppos) { - var sprpix_val; - var spix_val; - var dpix_val; - var out_val; - - spix_val = apixels[spix]; - sprpix_val = spix_val; - dpix_val = colors_for_drawing.acolors[spix_val]; - spix++; - out_val = dpix_val; - if (spritepixels[dpix].data) { - sprcol = render_sprites (dpix, 0, sprpix_val, 0); - if (sprcol) { - out_val = colors_for_drawing.acolors[sprcol]; - } - } - xlinebuffer[dpix++] = out_val; - } - } - - return spix; - } - - function linetoscr_32_stretch1_spr(spix, dpix, stoppos) { - //uae_u32 *buf = (uae_u32 *) xlinebuffer; - var sprcol; - - if (dp_for_drawing.ham_seen) { - while (dpix < stoppos) { - var sprpix_val; - var dpix_val; - var out_val; - - dpix_val = xcolors[ham_linebuf[spix]]; - sprpix_val = dpix_val; - spix++; - out_val = dpix_val; - if (spritepixels[dpix].data) { - sprcol = render_sprites (dpix, 0, sprpix_val, 0); - if (sprcol) { - out_val = colors_for_drawing.acolors[sprcol]; - } - } - xlinebuffer[dpix++] = out_val; - xlinebuffer[dpix++] = out_val; - } - } else if (bpldualpf) { - var lookup = bpldualpfpri ? dblpf_ind2 : dblpf_ind1; - while (dpix < stoppos) { - var sprpix_val; - var spix_val; - var dpix_val; - var out_val; - - spix_val = apixels[spix]; - sprpix_val = spix_val; - dpix_val = colors_for_drawing.acolors[lookup[spix_val]]; - spix++; - out_val = dpix_val; - if (spritepixels[dpix].data) { - sprcol = render_sprites (dpix, 1, sprpix_val, 0); - if (sprcol) { - out_val = colors_for_drawing.acolors[sprcol]; - } - } - xlinebuffer[dpix++] = out_val; - xlinebuffer[dpix++] = out_val; - } - } else if (bplehb) { - while (dpix < stoppos) { - var sprpix_val; - var spix_val; - var dpix_val; - var out_val; - - spix_val = apixels[spix]; - sprpix_val = spix_val; - if (spix_val <= 31) - dpix_val = colors_for_drawing.acolors[spix_val]; - else - dpix_val = xcolors[(colors_for_drawing.color_regs_ecs[spix_val - 32] >> 1) & 0x777]; - spix++; - out_val = dpix_val; - if (spritepixels[dpix].data) { - sprcol = render_sprites (dpix, 0, sprpix_val, 0); - if (sprcol) { - out_val = colors_for_drawing.acolors[sprcol]; - } - } - xlinebuffer[dpix++] = out_val; - xlinebuffer[dpix++] = out_val; - } - } else { - while (dpix < stoppos) { - var sprpix_val; - var spix_val; - var dpix_val; - var out_val; - - spix_val = apixels[spix]; - sprpix_val = spix_val; - dpix_val = colors_for_drawing.acolors[spix_val]; - spix++; - out_val = dpix_val; - if (spritepixels[dpix].data) { - sprcol = render_sprites (dpix, 0, sprpix_val, 0); - if (sprcol) { - out_val = colors_for_drawing.acolors[sprcol]; - } - } - xlinebuffer[dpix++] = out_val; - xlinebuffer[dpix++] = out_val; - } - } - return spix; + }*/ + function fill_line2(startpos, len) { + //xlinebuffer.fill(getbgc(false), startpos + xlinebuffer_pos, startpos + xlinebuffer_pos + len); + //SAEF_memset(xlinebuffer,startpos + xlinebuffer_pos, getbgc(false), len); + var col = getbgc(false); + for (var i = startpos + xlinebuffer_pos, j = startpos + xlinebuffer_pos + len; i < j; i++) xlinebuffer[i] = col; } - function linetoscr_32_shrink1_spr(spix, dpix, stoppos) { - //var *buf = (var *) xlinebuffer; - var sprcol; + function fill_line_border(lineno) { + var lastpos = visible_left_border; + var endpos = visible_left_border + gfxvidinfo.drawbuffer.inwidth; - if (dp_for_drawing.ham_seen) { - while (dpix < stoppos) { - var sprpix_val; - var dpix_val; - var out_val; - - dpix_val = xcolors[ham_linebuf[spix]]; - sprpix_val = dpix_val; - spix += 2; - out_val = dpix_val; - if (spritepixels[dpix].data) { - sprcol = render_sprites (dpix, 0, sprpix_val, 0); - if (sprcol) { - out_val = colors_for_drawing.acolors[sprcol]; - } - } - xlinebuffer[dpix++] = out_val; - } - } else if (bpldualpf) { - var lookup = bpldualpfpri ? dblpf_ind2 : dblpf_ind1; - while (dpix < stoppos) { - var sprpix_val; - var spix_val; - var dpix_val; - var out_val; - - spix_val = apixels[spix]; - sprpix_val = spix_val; - dpix_val = colors_for_drawing.acolors[lookup[spix_val]]; - spix += 2; - out_val = dpix_val; - if (spritepixels[dpix].data) { - sprcol = render_sprites (dpix, 1, sprpix_val, 0); - if (sprcol) { - out_val = colors_for_drawing.acolors[sprcol]; - } - } - xlinebuffer[dpix++] = out_val; - } - } else if (bplehb) { - while (dpix < stoppos) { - var sprpix_val; - var spix_val; - var dpix_val; - var out_val; - - spix_val = apixels[spix]; - sprpix_val = spix_val; - if (spix_val <= 31) - dpix_val = colors_for_drawing.acolors[spix_val]; - else - dpix_val = xcolors[(colors_for_drawing.color_regs_ecs[spix_val - 32] >> 1) & 0x777]; - spix += 2; - out_val = dpix_val; - if (spritepixels[dpix].data) { - sprcol = render_sprites (dpix, 0, sprpix_val, 0); - if (sprcol) { - out_val = colors_for_drawing.acolors[sprcol]; - } - } - xlinebuffer[dpix++] = out_val; - } - } else { - while (dpix < stoppos) { - var sprpix_val; - var spix_val; - var dpix_val; - var out_val; - - spix_val = apixels[spix]; - sprpix_val = spix_val; - dpix_val = colors_for_drawing.acolors[spix_val]; - spix += 2; - out_val = dpix_val; - if (spritepixels[dpix].data) { - sprcol = render_sprites (dpix, 0, sprpix_val, 0); - if (sprcol) { - out_val = colors_for_drawing.acolors[sprcol]; - } - } - xlinebuffer[dpix++] = out_val; - } - } - - return spix; - } - - - //apixels -> xlinebuffer - function pfield_do_linetoscr(start, stop, blank) { - //console.log('pfield_do_linetoscr()', start, stop, stop - start); - //xlinecheck('pfield_do_linetoscr', start, stop); - -/*#ifdef AGA - if (issprites && (AMIGA.config.chipset.mask & CSMASK_AGA)) { - if (res_shift == 0) { - switch (gfxvidinfo.drawbuffer.pixbytes) { - case 2: src_pixel = linetoscr_16_aga_spr (src_pixel, start, stop); break; - case 4: src_pixel = linetoscr_32_aga_spr (src_pixel, start, stop); break; - } - } else if (res_shift == 2) { - switch (gfxvidinfo.drawbuffer.pixbytes) { - case 2: src_pixel = linetoscr_16_stretch2_aga_spr (src_pixel, start, stop); break; - case 4: src_pixel = linetoscr_32_stretch2_aga_spr (src_pixel, start, stop); break; - } - } else if (res_shift == 1) { - switch (gfxvidinfo.drawbuffer.pixbytes) { - case 2: src_pixel = linetoscr_16_stretch1_aga_spr (src_pixel, start, stop); break; - case 4: src_pixel = linetoscr_32_stretch1_aga_spr (src_pixel, start, stop); break; - } - } else if (res_shift == -1) { - if (currprefs.gfx_lores_mode) { - switch (gfxvidinfo.drawbuffer.pixbytes) { - case 2: src_pixel = linetoscr_16_shrink1f_aga_spr (src_pixel, start, stop); break; - case 4: src_pixel = linetoscr_32_shrink1f_aga_spr (src_pixel, start, stop); break; - } - } else { - switch (gfxvidinfo.drawbuffer.pixbytes) { - case 2: src_pixel = linetoscr_16_shrink1_aga_spr (src_pixel, start, stop); break; - case 4: src_pixel = linetoscr_32_shrink1_aga_spr (src_pixel, start, stop); break; - } - } - } else if (res_shift == -2) { - if (currprefs.gfx_lores_mode) { - switch (gfxvidinfo.drawbuffer.pixbytes) { - case 2: src_pixel = linetoscr_16_shrink2f_aga_spr (src_pixel, start, stop); break; - case 4: src_pixel = linetoscr_32_shrink2f_aga_spr (src_pixel, start, stop); break; - } - } else { - switch (gfxvidinfo.drawbuffer.pixbytes) { - case 2: src_pixel = linetoscr_16_shrink2_aga_spr (src_pixel, start, stop); break; - case 4: src_pixel = linetoscr_32_shrink2_aga_spr (src_pixel, start, stop); break; - } - } - } - } else if (AMIGA.config.chipset.mask & CSMASK_AGA) { - if (res_shift == 0) { - switch (gfxvidinfo.drawbuffer.pixbytes) { - case 2: src_pixel = linetoscr_16_aga (src_pixel, start, stop); break; - case 4: src_pixel = linetoscr_32_aga (src_pixel, start, stop); break; - } - } else if (res_shift == 2) { - switch (gfxvidinfo.drawbuffer.pixbytes) { - case 2: src_pixel = linetoscr_16_stretch2_aga (src_pixel, start, stop); break; - case 4: src_pixel = linetoscr_32_stretch2_aga (src_pixel, start, stop); break; - } - } else if (res_shift == 1) { - switch (gfxvidinfo.drawbuffer.pixbytes) { - case 2: src_pixel = linetoscr_16_stretch1_aga (src_pixel, start, stop); break; - case 4: src_pixel = linetoscr_32_stretch1_aga (src_pixel, start, stop); break; - } - } else if (res_shift == -1) { - if (currprefs.gfx_lores_mode) { - switch (gfxvidinfo.drawbuffer.pixbytes) { - case 2: src_pixel = linetoscr_16_shrink1f_aga (src_pixel, start, stop); break; - case 4: src_pixel = linetoscr_32_shrink1f_aga (src_pixel, start, stop); break; - } - } else { - switch (gfxvidinfo.drawbuffer.pixbytes) { - case 2: src_pixel = linetoscr_16_shrink1_aga (src_pixel, start, stop); break; - case 4: src_pixel = linetoscr_32_shrink1_aga (src_pixel, start, stop); break; - } - } - } else if (res_shift == -2) { - if (currprefs.gfx_lores_mode) { - switch (gfxvidinfo.drawbuffer.pixbytes) { - case 2: src_pixel = linetoscr_16_shrink2f_aga (src_pixel, start, stop); break; - case 4: src_pixel = linetoscr_32_shrink2f_aga (src_pixel, start, stop); break; - } - } else { - switch (gfxvidinfo.drawbuffer.pixbytes) { - case 2: src_pixel = linetoscr_16_shrink2_aga (src_pixel, start, stop); break; - case 4: src_pixel = linetoscr_32_shrink2_aga (src_pixel, start, stop); break; - } - } - } - } else -#endif*/ - -/*#ifdef ECS_DENISE - if (ecsshres) { - if (res_shift == 0) { - switch (gfxvidinfo.drawbuffer.pixbytes) { - case 2: src_pixel = linetoscr_16_sh (src_pixel, start, stop, issprites); break; - case 4: src_pixel = linetoscr_32_sh (src_pixel, start, stop, issprites); break; - } - } else if (res_shift == -1) { - if (currprefs.gfx_lores_mode) { - switch (gfxvidinfo.drawbuffer.pixbytes) { - case 2: src_pixel = linetoscr_16_shrink1f_sh (src_pixel, start, stop, issprites); break; - case 4: src_pixel = linetoscr_32_shrink1f_sh (src_pixel, start, stop, issprites); break; - } - } else { - switch (gfxvidinfo.drawbuffer.pixbytes) { - case 2: src_pixel = linetoscr_16_shrink1_sh (src_pixel, start, stop, issprites); break; - case 4: src_pixel = linetoscr_32_shrink1_sh (src_pixel, start, stop, issprites); break; - } - } - } else if (res_shift == -2) { - if (currprefs.gfx_lores_mode) { - switch (gfxvidinfo.drawbuffer.pixbytes) { - case 2: src_pixel = linetoscr_16_shrink2f_sh (src_pixel, start, stop, issprites); break; - case 4: src_pixel = linetoscr_32_shrink2f_sh (src_pixel, start, stop, issprites); break; - } - } else { - switch (gfxvidinfo.drawbuffer.pixbytes) { - case 2: src_pixel = linetoscr_16_shrink2_sh (src_pixel, start, stop, issprites); break; - case 4: src_pixel = linetoscr_32_shrink2_sh (src_pixel, start, stop, issprites); break; - } - } - } - } else -#endif*/ - - if (issprites) { - if (res_shift == 0) { - switch (gfxvidinfo.drawbuffer.pixbytes) { - case 2: src_pixel = linetoscr_16_spr (src_pixel, start, stop); break; - case 4: src_pixel = linetoscr_32_spr (src_pixel, start, stop); break; - } - } else if (res_shift == 2) { - switch (gfxvidinfo.drawbuffer.pixbytes) { - case 2: src_pixel = linetoscr_16_stretch2_spr (src_pixel, start, stop); break; - case 4: src_pixel = linetoscr_32_stretch2_spr (src_pixel, start, stop); break; - } - } else if (res_shift == 1) { - switch (gfxvidinfo.drawbuffer.pixbytes) { - case 2: src_pixel = linetoscr_16_stretch1_spr (src_pixel, start, stop); break; - case 4: src_pixel = linetoscr_32_stretch1_spr (src_pixel, start, stop); break; - } - } else if (res_shift == -1) { - switch (gfxvidinfo.drawbuffer.pixbytes) { - case 2: src_pixel = linetoscr_16_shrink1_spr (src_pixel, start, stop); break; - case 4: src_pixel = linetoscr_32_shrink1_spr (src_pixel, start, stop); break; - } - } - } else { - if (res_shift == 0) { - switch (gfxvidinfo.drawbuffer.pixbytes) { - case 2: src_pixel = linetoscr_16 (src_pixel, start, stop); break; - case 4: src_pixel = linetoscr_32 (src_pixel, start, stop); break; - } - } else if (res_shift == 2) { - switch (gfxvidinfo.drawbuffer.pixbytes) { - case 2: src_pixel = linetoscr_16_stretch2 (src_pixel, start, stop); break; - case 4: src_pixel = linetoscr_32_stretch2 (src_pixel, start, stop); break; - } - } else if (res_shift == 1) { - switch (gfxvidinfo.drawbuffer.pixbytes) { - case 2: src_pixel = linetoscr_16_stretch1 (src_pixel, start, stop); break; - case 4: src_pixel = linetoscr_32_stretch1 (src_pixel, start, stop); break; - } - } else if (res_shift == -1) { - switch (gfxvidinfo.drawbuffer.pixbytes) { - case 2: src_pixel = linetoscr_16_shrink1 (src_pixel, start, stop); break; - case 4: src_pixel = linetoscr_32_shrink1 (src_pixel, start, stop); break; - } - } - } - } - - function init_ham_decoding() { - var unpainted_amiga = unpainted; - - ham_decode_pixel = ham_src_pixel; - ham_lastcolor = color_reg_get(colors_for_drawing, 0); - - if (!bplham) { - if (unpainted_amiga > 0) { - var pv = apixels[ham_decode_pixel + unpainted_amiga - 1]; -/*#ifdef AGA - if (currprefs.chipset_mask & CSMASK_AGA) - ham_lastcolor = colors_for_drawing.color_regs_aga[pv ^ bplxor]; - else -#endif*/ - ham_lastcolor = colors_for_drawing.color_regs_ecs[pv]; - } -/*#ifdef AGA - } else if (currprefs.chipset_mask & CSMASK_AGA) { - if (bplplanecnt >= 7) { // AGA mode HAM8 - while (unpainted_amiga-- > 0) { - var pv = apixels[ham_decode_pixel++] ^ bplxor; - switch (pv & 0x3) { - case 0x0: ham_lastcolor = colors_for_drawing.color_regs_aga[pv >> 2]; break; - case 0x1: ham_lastcolor &= 0xFFFF03; ham_lastcolor |= (pv & 0xFC); break; - case 0x2: ham_lastcolor &= 0x03FFFF; ham_lastcolor |= (pv & 0xFC) << 16; break; - case 0x3: ham_lastcolor &= 0xFF03FF; ham_lastcolor |= (pv & 0xFC) << 8; break; - } - } - } else { // AGA mode HAM6 - while (unpainted_amiga-- > 0) { - var pv = apixels[ham_decode_pixel++] ^ bplxor; - switch (pv & 0x30) { - case 0x00: ham_lastcolor = colors_for_drawing.color_regs_aga[pv]; break; - case 0x10: ham_lastcolor &= 0xFFFF00; ham_lastcolor |= (pv & 0xF) << 4; break; - case 0x20: ham_lastcolor &= 0x00FFFF; ham_lastcolor |= (pv & 0xF) << 20; break; - case 0x30: ham_lastcolor &= 0xFF00FF; ham_lastcolor |= (pv & 0xF) << 12; break; - } - } - } -#endif*/ - } else { - /* OCS/ECS mode HAM6 */ - while (unpainted_amiga-- > 0) { - var pv = apixels[ham_decode_pixel++]; - switch (pv & 0x30) { - case 0x00: ham_lastcolor = colors_for_drawing.color_regs_ecs[pv]; break; - case 0x10: ham_lastcolor &= 0xFF0; ham_lastcolor |= (pv & 0xF); break; - case 0x20: ham_lastcolor &= 0x0FF; ham_lastcolor |= (pv & 0xF) << 8; break; - case 0x30: ham_lastcolor &= 0xF0F; ham_lastcolor |= (pv & 0xF) << 4; break; - } - } - } - } - - function decode_ham(pix, stoppos, blank) { - var todraw_amiga = res_shift_from_window(stoppos - pix); - - if (!bplham) { - while (todraw_amiga-- > 0) { - var pv = apixels[ham_decode_pixel]; -/*#ifdef AGA - if (currprefs.chipset_mask & CSMASK_AGA) - ham_lastcolor = colors_for_drawing.color_regs_aga[pv ^ bplxor]; - else -#endif*/ - ham_lastcolor = colors_for_drawing.color_regs_ecs[pv]; - - ham_linebuf[ham_decode_pixel++] = ham_lastcolor; - } -/*#ifdef AGA - } else if (currprefs.chipset_mask & CSMASK_AGA) { - if (bplplanecnt >= 7) { // AGA mode HAM8 - while (todraw_amiga-- > 0) { - var pv = apixels[ham_decode_pixel] ^ bplxor; - switch (pv & 0x3) { - case 0x0: ham_lastcolor = colors_for_drawing.color_regs_aga[pv >> 2]; break; - case 0x1: ham_lastcolor &= 0xFFFF03; ham_lastcolor |= (pv & 0xFC); break; - case 0x2: ham_lastcolor &= 0x03FFFF; ham_lastcolor |= (pv & 0xFC) << 16; break; - case 0x3: ham_lastcolor &= 0xFF03FF; ham_lastcolor |= (pv & 0xFC) << 8; break; - } - ham_linebuf[ham_decode_pixel++] = ham_lastcolor; - } - } else { // AGA mode HAM6 - while (todraw_amiga-- > 0) { - var pv = apixels[ham_decode_pixel] ^ bplxor; - switch (pv & 0x30) { - case 0x00: ham_lastcolor = colors_for_drawing.color_regs_aga[pv]; break; - case 0x10: ham_lastcolor &= 0xFFFF00; ham_lastcolor |= (pv & 0xF) << 4; break; - case 0x20: ham_lastcolor &= 0x00FFFF; ham_lastcolor |= (pv & 0xF) << 20; break; - case 0x30: ham_lastcolor &= 0xFF00FF; ham_lastcolor |= (pv & 0xF) << 12; break; - } - ham_linebuf[ham_decode_pixel++] = ham_lastcolor; - } - } -#endif*/ - } else { - /* OCS/ECS mode HAM6 */ - while (todraw_amiga-- > 0) { - var pv = apixels[ham_decode_pixel]; - switch (pv & 0x30) { - case 0x00: ham_lastcolor = colors_for_drawing.color_regs_ecs[pv]; break; - case 0x10: ham_lastcolor &= 0xFF0; ham_lastcolor |= (pv & 0xF); break; - case 0x20: ham_lastcolor &= 0x0FF; ham_lastcolor |= (pv & 0xF) << 8; break; - case 0x30: ham_lastcolor &= 0xF0F; ham_lastcolor |= (pv & 0xF) << 4; break; - } - ham_linebuf[ham_decode_pixel++] = ham_lastcolor; - } - } - } - - function weird_bitplane_fix() { - for (var i = playfield_start >> lores_shift; i < playfield_end >> lores_shift; i++) { - if (apixels[pixels_offset + i] > 16) apixels[pixels_offset + i] = 16; - } - } - - //line_data -> apixels - this.pfield_doline_1 = function (lineno, wordcount, planes) { - var pixels = MAX_PIXELS_PER_LINE; - var tmp, d0, d1, d2, d3, d4, d5, d6, d7; - var offs = 0; - - while (wordcount-- > 0) { - d0 = d1 = d2 = d3 = d4 = d5 = d6 = d7 = 0; - - switch (planes) { - /*#ifdef AGA - case 8: d0 = line_data[lineno][7][offs]; - case 7: d1 = line_data[lineno][6][offs]; - #endif*/ - case 6: - d2 = line_data[lineno][5][offs]; - case 5: - d3 = line_data[lineno][4][offs]; - case 4: - d4 = line_data[lineno][3][offs]; - case 3: - d5 = line_data[lineno][2][offs]; - case 2: - d6 = line_data[lineno][1][offs]; - case 1: - d7 = line_data[lineno][0][offs]; - } - offs++; - - tmp = (d0 ^ (d1 >>> 1)) & 0x55555555; - d0 ^= tmp; - d1 ^= (tmp << 1); - tmp = (d2 ^ (d3 >>> 1)) & 0x55555555; - d2 ^= tmp; - d3 ^= (tmp << 1); - tmp = (d4 ^ (d5 >>> 1)) & 0x55555555; - d4 ^= tmp; - d5 ^= (tmp << 1); - tmp = (d6 ^ (d7 >>> 1)) & 0x55555555; - d6 ^= tmp; - d7 ^= (tmp << 1); - - tmp = (d0 ^ (d2 >>> 2)) & 0x33333333; - d0 ^= tmp; - d2 ^= (tmp << 2); - tmp = (d1 ^ (d3 >>> 2)) & 0x33333333; - d1 ^= tmp; - d3 ^= (tmp << 2); - tmp = (d4 ^ (d6 >>> 2)) & 0x33333333; - d4 ^= tmp; - d6 ^= (tmp << 2); - tmp = (d5 ^ (d7 >>> 2)) & 0x33333333; - d5 ^= tmp; - d7 ^= (tmp << 2); - - tmp = (d0 ^ (d4 >>> 4)) & 0x0f0f0f0f; - d0 ^= tmp; - d4 ^= (tmp << 4); - tmp = (d1 ^ (d5 >>> 4)) & 0x0f0f0f0f; - d1 ^= tmp; - d5 ^= (tmp << 4); - tmp = (d2 ^ (d6 >>> 4)) & 0x0f0f0f0f; - d2 ^= tmp; - d6 ^= (tmp << 4); - tmp = (d3 ^ (d7 >>> 4)) & 0x0f0f0f0f; - d3 ^= tmp; - d7 ^= (tmp << 4); - - tmp = (d0 ^ (d1 >>> 8)) & 0x00ff00ff; - d0 ^= tmp; - d1 ^= (tmp << 8); - tmp = (d2 ^ (d3 >>> 8)) & 0x00ff00ff; - d2 ^= tmp; - d3 ^= (tmp << 8); - tmp = (d4 ^ (d5 >>> 8)) & 0x00ff00ff; - d4 ^= tmp; - d5 ^= (tmp << 8); - tmp = (d6 ^ (d7 >>> 8)) & 0x00ff00ff; - d6 ^= tmp; - d7 ^= (tmp << 8); - - tmp = (d0 ^ (d2 >>> 16)) & 0x0000ffff; - d0 ^= tmp; - d2 ^= (tmp << 16); - tmp = (d1 ^ (d3 >>> 16)) & 0x0000ffff; - d1 ^= tmp; - d3 ^= (tmp << 16); - tmp = (d4 ^ (d6 >>> 16)) & 0x0000ffff; - d4 ^= tmp; - d6 ^= (tmp << 16); - tmp = (d5 ^ (d7 >>> 16)) & 0x0000ffff; - d5 ^= tmp; - d7 ^= (tmp << 16); - - apixels[pixels ] = (d0 >>> 24) & 0xff; - apixels[pixels + 1] = (d0 >>> 16) & 0xff; - apixels[pixels + 2] = (d0 >>> 8) & 0xff; - apixels[pixels + 3] = d0 & 0xff; - apixels[pixels + 4] = (d4 >>> 24) & 0xff; - apixels[pixels + 5] = (d4 >>> 16) & 0xff; - apixels[pixels + 6] = (d4 >>> 8) & 0xff; - apixels[pixels + 7] = d4 & 0xff; - apixels[pixels + 8] = (d1 >>> 24) & 0xff; - apixels[pixels + 9] = (d1 >>> 16) & 0xff; - apixels[pixels + 10] = (d1 >>> 8) & 0xff; - apixels[pixels + 11] = d1 & 0xff; - apixels[pixels + 12] = (d5 >>> 24) & 0xff; - apixels[pixels + 13] = (d5 >>> 16) & 0xff; - apixels[pixels + 14] = (d5 >>> 8) & 0xff; - apixels[pixels + 15] = d5 & 0xff; - apixels[pixels + 16] = (d2 >>> 24) & 0xff; - apixels[pixels + 17] = (d2 >>> 16) & 0xff; - apixels[pixels + 18] = (d2 >>> 8) & 0xff; - apixels[pixels + 19] = d2 & 0xff; - apixels[pixels + 20] = (d6 >>> 24) & 0xff; - apixels[pixels + 21] = (d6 >>> 16) & 0xff; - apixels[pixels + 22] = (d6 >>> 8) & 0xff; - apixels[pixels + 23] = d6 & 0xff; - apixels[pixels + 24] = (d3 >>> 24) & 0xff; - apixels[pixels + 25] = (d3 >>> 16) & 0xff; - apixels[pixels + 26] = (d3 >>> 8) & 0xff; - apixels[pixels + 27] = d3 & 0xff; - apixels[pixels + 28] = (d7 >>> 24) & 0xff; - apixels[pixels + 29] = (d7 >>> 16) & 0xff; - apixels[pixels + 30] = (d7 >>> 8) & 0xff; - apixels[pixels + 31] = d7 & 0xff; - pixels += 32; - - /*apixels[pixels++] = (d0 >>> 24); - apixels[pixels++] = (d0 >>> 16) & 0xff; - apixels[pixels++] = (d0 >>> 8) & 0xff; - apixels[pixels++] = d0 & 0xff; - apixels[pixels++] = (d4 >>> 24); - apixels[pixels++] = (d4 >>> 16) & 0xff; - apixels[pixels++] = (d4 >>> 8) & 0xff; - apixels[pixels++] = d4 & 0xff; - apixels[pixels++] = (d1 >>> 24); - apixels[pixels++] = (d1 >>> 16) & 0xff; - apixels[pixels++] = (d1 >>> 8) & 0xff; - apixels[pixels++] = d1 & 0xff; - apixels[pixels++] = (d5 >>> 24); - apixels[pixels++] = (d5 >>> 16) & 0xff; - apixels[pixels++] = (d5 >>> 8) & 0xff; - apixels[pixels++] = d5 & 0xff; - apixels[pixels++] = (d2 >>> 24); - apixels[pixels++] = (d2 >>> 16) & 0xff; - apixels[pixels++] = (d2 >>> 8) & 0xff; - apixels[pixels++] = d2 & 0xff; - apixels[pixels++] = (d6 >>> 24); - apixels[pixels++] = (d6 >>> 16) & 0xff; - apixels[pixels++] = (d6 >>> 8) & 0xff; - apixels[pixels++] = d6 & 0xff; - apixels[pixels++] = (d3 >>> 24); - apixels[pixels++] = (d3 >>> 16) & 0xff; - apixels[pixels++] = (d3 >>> 8) & 0xff; - apixels[pixels++] = d3 & 0xff; - apixels[pixels++] = (d7 >>> 24); - apixels[pixels++] = (d7 >>> 16) & 0xff; - apixels[pixels++] = (d7 >>> 8) & 0xff; - apixels[pixels++] = d7 & 0xff;*/ - } - }; - - this.pfield_doline = function (lineno) { - if (bplplanecnt) - this.pfield_doline_1(lineno, dp_for_drawing.plflinelen, bplplanecnt); - else { - for (var i = 0; i < dp_for_drawing.plflinelen * 32; i++) apixels[i] = 0; //memset (data, 0, dp_for_drawing.plflinelen * 32); - } - }; - - this.pfield_draw_line = function (vb, lineno, gfx_ypos, follow_ypos) { - if (!AMIGA.config.video.enabled) return; - //console.log('pfield_draw_line', lineno, gfx_ypos, follow_ypos); - var border = 0; - var do_double = 0; - - dp_for_drawing = line_decisions[lineno]; - dip_for_drawing = curr_drawinfo[lineno]; - - switch (linestate[lineno]) { - case LINE_REMEMBERED_AS_PREVIOUS: - BUG.info('pfield_draw_line() Shouldn\'t get here... this is a bug.'); - return; - case LINE_BLACK: - linestate[lineno] = LINE_REMEMBERED_AS_BLACK; - border = 2; - break; - case LINE_REMEMBERED_AS_BLACK: - return; - case LINE_AS_PREVIOUS: - //dp_for_drawing--; - //dip_for_drawing--; - dp_for_drawing = line_decisions[lineno - 1]; - dip_for_drawing = curr_drawinfo[lineno - 1]; - linestate[lineno] = LINE_DONE_AS_PREVIOUS; - if (dp_for_drawing.plfleft < 0) - border = 1; - break; - case LINE_DONE_AS_PREVIOUS: - /* fall through */ - case LINE_DONE: - return; - case LINE_DECIDED_DOUBLE: - if (follow_ypos >= 0) { - do_double = 1; - linestate[lineno + 1] = LINE_DONE_AS_PREVIOUS; - } - /* fall through */ - default: - if (dp_for_drawing.plfleft < 0) - border = 1; - linestate[lineno] = LINE_DONE; - break; - } - - if (border == 0) { - this.pfield_expand_dp_bplcon(); - this.pfield_init_linetoscr(); - this.pfield_doline(lineno); - - this.adjust_drawing_colors(dp_for_drawing.ctable, dp_for_drawing.ham_seen || bplehb || ecsshres); - - if (dp_for_drawing.ham_seen) { - init_ham_decoding(); - if (dip_for_drawing.nr_color_changes == 0) - decode_ham(visible_left_border, visible_right_border, false); - else { - this.do_color_changes(dummy_worker, decode_ham, lineno); - this.adjust_drawing_colors(dp_for_drawing.ctable, dp_for_drawing.ham_seen || bplehb); - } - bplham = dp_for_drawing.ham_at_start; - } - if (plf2pri > 5 && bplplanecnt == 5 && !(AMIGA.config.chipset.mask & CSMASK_AGA)) - weird_bitplane_fix(); - - if (dip_for_drawing.nr_sprites) { - /*#ifdef AGA - if (brdsprt) - this.clear_bitplane_border_aga(); - #endif*/ - for (var i = 0; i < dip_for_drawing.nr_sprites; i++) - draw_sprites(curr_sprite_entries[dip_for_drawing.first_sprite_entry + i]); - } - this.do_color_changes(pfield_do_fill_line, pfield_do_linetoscr, lineno); - - this.do_flush_line(vb, gfx_ypos); - if (do_double) - this.do_flush_line(vb, follow_ypos); - } else if (border == 1) { - var dosprites = 0; - - this.adjust_drawing_colors(dp_for_drawing.ctable, false); - - /*#ifdef AGA - if (brdsprt && dip_for_drawing->nr_sprites > 0) { - dosprites = 1; - this.pfield_expand_dp_bplcon(); - pfield_init_linetoscr (); - memset (apixels + MAX_PIXELS_PER_LINE, colors_for_drawing.borderblank ? 0 : colors_for_drawing.acolors[0], MAX_PIXELS_PER_LINE); - } - #endif*/ - if (!dosprites && dip_for_drawing.nr_color_changes == 0) { - fill_line(); - this.do_flush_line(vb, gfx_ypos); - if (do_double) - this.do_flush_line(vb, follow_ypos); - return; - } - if (dosprites) { - for (var i = 0; i < dip_for_drawing.nr_sprites; i++) - this.draw_sprites(curr_sprite_entries[dip_for_drawing.first_sprite_entry + i]); - for (var i = 0; i < apixels.length; i++) apixels[i] = 0; //memset (apixels, 0, sizeof apixels); - //var oxor = bplxor; - //bplxor = 0; - this.do_color_changes(pfield_do_fill_line, pfield_do_linetoscr, lineno); - //bplxor = oxor; - } else { - playfield_start = visible_right_border; - playfield_end = visible_right_border; - this.do_color_changes(pfield_do_fill_line, pfield_do_fill_line, lineno); - } - this.do_flush_line(vb, gfx_ypos); - if (do_double) - this.do_flush_line(vb, follow_ypos); - } else { - //var tmp = hposblank; - //hposblank = brdblank; - //hposblank = colors_for_drawing.borderblank; - fill_line(); - this.do_flush_line(vb, gfx_ypos); - //hposblank = tmp; - } - }; - - this.init_drawing_frame = function () { - this.init_hardware_for_drawing_frame(); - - /*if (thisframe_first_drawn_line < 0) - thisframe_first_drawn_line = minfirstline; - if (thisframe_first_drawn_line > thisframe_last_drawn_line) - thisframe_last_drawn_line = thisframe_first_drawn_line;*/ - - var maxline = ((this.maxvpos_nom + 1) << linedbl) + 2; - - if (SMART_UPDATE) { - for (var i = 0; i < maxline; i++) { - switch (linestate[i]) { - case LINE_DONE_AS_PREVIOUS: - linestate[i] = LINE_REMEMBERED_AS_PREVIOUS; - break; - case LINE_REMEMBERED_AS_BLACK: - break; - default: - linestate[i] = LINE_UNDECIDED; - break; - } - } - } else { - for (var i = 0; i < maxline; i++) linestate[i] = LINE_UNDECIDED; //memset(linestate, LINE_UNDECIDED, maxline); - } - - last_drawn_line = 0; - first_drawn_line = 0x7fff; - - first_block_line = last_block_line = NO_BLOCK; - if (frame_redraw_necessary) - frame_redraw_necessary--; - - this.center_image(); - - thisframe_first_drawn_line = -1; - thisframe_last_drawn_line = -1; - - drawing_color_matches = -1; - }; - - this.finish_drawing_frame = function () { - var vb = gfxvidinfo.drawbuffer; - - if (SMART_UPDATE) { - for (var i = 0; i < max_ypos_thisframe; i++) { - var i1 = i + min_ypos_for_screen; - var line = i + thisframe_y_adjust_real; - - var where2 = amiga2aspect_line_map[i1]; - if (where2 >= vb.inheight) - break; - if (where2 < 0) - continue; - hposblank = 0; - this.pfield_draw_line(vb, line, where2, amiga2aspect_line_map[i1 + 1]); - } - //if (lightpen_active) lightpen_update(vb); - - //this.do_flush_screen(vb, first_drawn_line, last_drawn_line); - } - /*else { - if (!interlace_seen) - this.do_flush_screen(vb, first_drawn_line, last_drawn_line); - }*/ - }; - - this.hardware_line_completed = function (lineno) { - if (!SMART_UPDATE) { - var i = lineno - thisframe_y_adjust_real; - if (i >= 0 && i < max_ypos_thisframe) { - var where = amiga2aspect_line_map[i + min_ypos_for_screen]; - if (where < gfxvidinfo.drawbuffer.outheight && where >= 0) - this.pfield_draw_line(null, lineno, where, amiga2aspect_line_map[i + min_ypos_for_screen + 1]); - } - } - }; - - this.notice_interlace_seen = function (lace) { - var changed = false; - if (lace) { - if (interlace_seen == 0) { - changed = true; - //BUG.info('->lace'); - } - interlace_seen = AMIGA.config.video.vresolution ? 1 : -1; - } else { - if (interlace_seen) { - changed = true; - //BUG.info('->non-lace'); - } - interlace_seen = 0; - } - return changed; - }; - - this.notice_screen_contents_lost = function () { - frame_redraw_necessary = 2; - }; - - /*---------------------------------*/ - - this.reset_lores = function () { - lores_shift = AMIGA.config.video.hresolution; - if (doublescan > 0) { - if (lores_shift < 2) - lores_shift++; - } - sprite_buffer_res = AMIGA.config.video.hresolution; - if (doublescan > 0 && sprite_buffer_res < RES_SUPERHIRES) - sprite_buffer_res++; - }; - - this.bpldmainitdelay = function (hpos) { - var hposa = hpos + (4 + (bplcon0_planes == 8 ? 1 : 0)); //BPLCON_AGNUS_DELAY; - ddf_change = this.vpos; - if (hposa < 0x14) { - this.BPLCON0_Denise(hpos, bplcon0, false); - this.setup_fmodes(hpos); + if (lineno < visible_top_start || lineno >= visible_bottom_stop) { + var b = hposblank; + hposblank = 3; + fill_line2(lastpos, gfxvidinfo.drawbuffer.inwidth); + /*if (need_genlock_data) { + memset(xlinebuffer_genlock + lastpos, 0, gfxvidinfo.drawbuffer.inwidth); + }*/ + hposblank = b; return; } - if (bpldmasetuphpos < 0) { - bpldmasetupphase = 0; - bpldmasetuphpos = hpos + BPLCON_DENISE_DELAY; - } - }; - - this.update_ddf_change = function () { - ddf_change = this.vpos; - }; - /*---------------------------------*/ - - this.allocsoftbuffer = function (buf, flags, width, height, depth) { - buf.rowbytes = MAX_PIXELS_PER_LINE >> 3; - /* for xlinecheck() */ - buf.pixbytes = Math.floor((depth + 7) / 8); - buf.width_allocated = (width + 7) & ~7; - buf.height_allocated = height; - }; - - this.setup_drawing = function () { - setup_drawing_tables(); - this.allocsoftbuffer(gfxvidinfo.drawbuffer, 0, VIDEO_WIDTH, VIDEO_HEIGHT, VIDEO_DEPTH); - }; - - this.cleanup_drawing = function () { - }; - - this.reset_drawing = function () { - var i; - max_diwstop = 0; - this.reset_lores(); - for (i = 0; i < linestate.length; i++) linestate[i] = LINE_UNDECIDED; - this.recreate_aspect_maps(); - last_redraw_point = 0; - for (i = 0; i < spixels.length; i++) spixels[i] = 0; //memset(spixels, 0, sizeof spixels); - for (i = 0; i < spixstate.length; i++) spixstate[i] = 0; //memset(&spixstate, 0, sizeof spixstate); - this.init_drawing_frame(); - this.notice_screen_contents_lost(); - //lightpen_y1 = lightpen_y2 = -1; - center_reset = true; - }; - - /*-----------------------------------------------------------------------*/ - /* sprites */ - /*-----------------------------------------------------------------------*/ - - function setup_sprite_tables() { - for (var i = 0; i < 256; i++) { - sprtaba[i] = - (((i >> 7) & 1) << 0) - | (((i >> 6) & 1) << 2) - | (((i >> 5) & 1) << 4) - | (((i >> 4) & 1) << 6) - | (((i >> 3) & 1) << 8) - | (((i >> 2) & 1) << 10) - | (((i >> 1) & 1) << 12) - | (((i >> 0) & 1) << 14); - sprtabb[i] = sprtaba[i] << 1; - sprite_ab_merge[i] = ((i & 15) ? 1 : 0) | ((i & 240) ? 2 : 0); - clxtab[i] = - ((((i & 3) && (i & 12)) << 9) | - (((i & 3) && (i & 48)) << 10) | - (((i & 3) && (i & 192)) << 11) | - (((i & 12) && (i & 48)) << 12) | - (((i & 12) && (i & 192)) << 13) | - (((i & 48) && (i & 192)) << 14)); - sprite_offs[i] = (i & 15) ? 0 : 2; + // full hblank + if (hposblank) { + hposblank = 3; + fill_line2(lastpos, gfxvidinfo.drawbuffer.inwidth); + /*if (need_genlock_data) { + memset(xlinebuffer_genlock + lastpos, 0, gfxvidinfo.drawbuffer.inwidth); + }*/ + return; } - for (var i = 0; i < 16; i++) { - clxmask[i] = - ((i & 1) ? 0xF : 0x3) - | ((i & 2) ? 0xF0 : 0x30) - | ((i & 4) ? 0xF00 : 0x300) - | ((i & 8) ? 0xF000 : 0x3000); - sprclx[i] = - (((i & 0x3) == 0x3 ? 1 : 0) - | ((i & 0x5) == 0x5 ? 2 : 0) - | ((i & 0x9) == 0x9 ? 4 : 0) - | ((i & 0x6) == 0x6 ? 8 : 0) - | ((i & 0xA) == 0xA ? 16 : 0) - | ((i & 0xC) == 0xC ? 32 : 0)) << 9; + // hblank not visible + if (hblank_left_start <= lastpos && hblank_right_stop >= endpos) { + fill_line2(lastpos, gfxvidinfo.drawbuffer.inwidth); + /*if (need_genlock_data) { + memset(xlinebuffer_genlock + lastpos, 0, gfxvidinfo.drawbuffer.inwidth); + }*/ + return; } - } - + + // left, right or both hblanks visible + if (lastpos < hblank_left_start) { + var t = hblank_left_start < endpos ? hblank_left_start : endpos; + pfield_do_fill_line(lastpos, t, true); + lastpos = t; + } + if (lastpos < hblank_right_stop) { + var t = hblank_right_stop < endpos ? hblank_right_stop : endpos; + pfield_do_fill_line(lastpos, t, false); + lastpos = t; + } + if (lastpos < endpos) + pfield_do_fill_line(lastpos, endpos, true); + } + + var sprite_shdelay = 0; //int + function render_sprites(pos, dualpf, apixel, aga) { - if (!DO_SPRITES) return 0; //FIXME + //struct spritepixelsbuf *spb = &spritepixels[pos]; var spb = spritepixels[pos]; - var v = spb.data; - var shift_lookup = dualpf ? (bpldualpfpri ? dblpf_ms2 : dblpf_ms1) : dblpf_ms; - var maskshift = shift_lookup[apixel]; - var plfmask = (plf_sprite_mask >>> maskshift) >>> maskshift; - + var v = spb.data; //uint + var shift_lookup = dualpf ? (bpldualpfpri ? dblpf_ms2 : dblpf_ms1) : dblpf_ms; //int * + var maskshift, plfmask; //int + + // shdelay hack, above &spritepixels[pos] is correct. + pos += sprite_shdelay; + /* The value in the shift lookup table is _half_ the shift count we + need. This is because we can't shift 32 bits at once (undefined behaviour in C). */ + maskshift = shift_lookup[apixel]; + plfmask = (plf_sprite_mask >>> maskshift) >>> maskshift; v &= ~plfmask; - if (v != 0) { //|| SPRITE_DEBUG) { - var vlo, vhi, col; - var v1 = v & 255; + /* Extra 1 sprite pixel at DDFSTRT is only possible if at least 1 plane is active */ + if ((bplplanecnt > 0 || pos >= sprite_playfield_start) && v != 0) { + var vlo, vhi, col; //uint + var v1 = v & 255; //uint + /* OFFS determines the sprite pair with the highest priority that has + any bits set. E.g. if we have 0xFF00 in the buffer, we have sprite + pairs 01 and 23 cleared, and pairs 45 and 67 set, so OFFS will + have a value of 4. + 2 * OFFS is the bit number in V of the sprite pair, and it also + happens to be the color offset for that pair. + */ var offs; if (v1 == 0) offs = 4 + sprite_offs[v >> 8]; else offs = sprite_offs[v1]; - v >>= offs * 2; + /* Shift highest priority sprite pair down to bit zero. */ + v >>>= offs * 2; v &= 15; -/*#if SPRITE_DEBUG > 0 - v ^= 8; -#endif*/ + if (spb.attach && (spb.stdata & (3 << offs))) { col = v; if (aga) @@ -2713,9 +2034,23 @@ function Playfield() { else col += 16; } else { + /* This sequence computes the correct color value. We have to select + either the lower-numbered or the higher-numbered sprite in the pair. + We have to select the high one if the low one has all bits zero. + If the lower-numbered sprite has any bits nonzero, (VLO - 1) is in + the range of 0..2, and with the mask and shift, VHI will be zero. + If the lower-numbered sprite is zero, (VLO - 1) is a mask of + 0xFFFFFFFF, and we select the bits of the higher numbered sprite in VHI. + This is _probably_ more efficient than doing it with branches. */ vlo = v & 3; - vhi = (v & (vlo - 1)) >> 2; - col = (vlo | vhi); + //vhi = (v & (vlo - 1)) >> 2; col = vlo | vhi; //ATT + + vhi = v >> 2; + if (vlo) + col = vlo; + else + col = vhi; + if (aga) { if (vhi > 0) col += sbasecol[1]; @@ -2729,14 +2064,592 @@ function Playfield() { return col; } return 0; - } - + } + + function get_genlock_very_rare_and_complex_case(v) { + // border color without BRDNTRAN bit set = transparent + if (v == 0 && !ce_is_borderntrans(colors_for_drawing.extra)) + return false; + if (ecs_genlock_features_colorkey) { + // color key match? + if (SAEV_config.chipset.mask & SAEC_Config_Chipset_Mask_AGA) { + if (colors_for_drawing.color_regs_aga[v] & 0x80000000) + return false; + } else { + if (colors_for_drawing.color_regs_ecs[v] & 0x8000) + return false; + } + } + // plane mask match? + if (v & ecs_genlock_features_mask) + return false; + return true; + } + // false = transparent + function get_genlock_transparency(v) { + if (!ecs_genlock_features_active) { + if (v == 0) + return false; + return true; + } else + return get_genlock_very_rare_and_complex_case(v); + } + + function merge_2pixel16(p1, p2) { + return ( //u16 + (((((p1 >> xredcolor_s) & xredcolor_m) + ((p2 >> xredcolor_s) & xredcolor_m)) >> 1) << xredcolor_s) | + (((((p1 >> xbluecolor_s) & xbluecolor_m) + ((p2 >> xbluecolor_s) & xbluecolor_m)) >> 1) << xbluecolor_s) | + (((((p1 >> xgreencolor_s) & xgreencolor_m) + ((p2 >> xgreencolor_s) & xgreencolor_m)) >> 1) << xgreencolor_s) + ); + } + function merge_2pixel32(p1, p2) { + return ( //u32 + (((((p1 >> 16) & 0xff) + ((p2 >> 16) & 0xff)) >> 1) << 16) | + (((((p1 >> 8) & 0xff) + ((p2 >> 8) & 0xff)) >> 1) << 8) | + (((((p1 >> 0) & 0xff) + ((p2 >> 0) & 0xff)) >> 1) << 0) + ) >>> 0; + } + + //typedef int(*call_linetoscr)(int spix, int dpix, int dpix_end); + + var pfield_do_linetoscr_normal = function(spix, dpix, dpix_end) {}; //call_linetoscr + var pfield_do_linetoscr_sprite = function(spix, dpix, dpix_end) {}; + var pfield_do_linetoscr_spriteonly = function(spix, dpix, dpix_end) {}; + + function pfield_do_linetoscr(start, stop, blank) { + src_pixel = pfield_do_linetoscr_normal(src_pixel, start, stop); + } + function pfield_do_linetoscr_spr(start, stop, blank) { + src_pixel = pfield_do_linetoscr_sprite(src_pixel, start, stop); + } + function pfield_do_nothing(start, stop, blank) { + return start; + } + /* AGA subpixel delay hack */ + var pfield_do_linetoscr_shdelay_normal = function(a,b,c) {}; //call_linetoscr + var pfield_do_linetoscr_shdelay_sprite = function(a,b,c) {}; + + function pfield_do_linetoscr_normal_shdelay(spix, dpix, dpix_end) { + var add = get_shdelay_add(); + //var add2 = add * gfxvidinfo.drawbuffer.pixbytes; + if (add) + pfield_do_linetoscr_shdelay_sprite(spix, dpix, dpix + add); + + //xlinebuffer += add2; //ORG + xlinebuffer_pos += add; //OWN + var out = pfield_do_linetoscr_shdelay_normal(spix, dpix, dpix_end); + //xlinebuffer -= add2; //ORG + xlinebuffer_pos -= add; //OWN + return out; + } + function pfield_do_linetoscr_sprite_shdelay(spix, dpix, dpix_end) { + var out = spix; + if (dpix < real_playfield_start && dpix_end > real_playfield_start) { + // Crosses real_playfield_start. + // Render only from dpix to real_playfield_start. + var len = real_playfield_start - dpix; + out = pfield_do_linetoscr_spriteonly(out, dpix, dpix + len); + dpix = real_playfield_start; + } else if (dpix_end <= real_playfield_start) { + // Does not cross real_playfield_start, nothing special needed. + out = pfield_do_linetoscr_spriteonly(out, dpix, dpix_end); + return out; + } + // Render bitplane with subpixel scroll, from real_playfield_start to end. + var add = get_shdelay_add(); + //var add2 = add * gfxvidinfo.drawbuffer.pixbytes; + if (add) + pfield_do_linetoscr_shdelay_sprite(out, dpix, dpix + add); + + sprite_shdelay = add; + //spritepixels += add; + spritepixels_pos += add; //OWN + //xlinebuffer += add2; + xlinebuffer_pos += add; //OWN + out = pfield_do_linetoscr_shdelay_sprite(out, dpix, dpix_end); + //xlinebuffer -= add2; //ORG + xlinebuffer_pos -= add; //OWN + //spritepixels -= add; + spritepixels_pos -= add; //OWN + sprite_shdelay = 0; + return out; + } + + function pfield_set_linetoscr() { + p_acolors = colors_for_drawing.acolors; + p_xcolors = xcolors; + bpland = 0xff; + if (bplbypass) + p_acolors = direct_colors_for_drawing.acolors; + + spritepixels = spritepixels_buffer; + spritepixels_pos = 0; //OWN + pfield_do_linetoscr_spriteonly = pfield_do_nothing; + + //#ifdef AGA + if (SAEV_config.chipset.mask & SAEC_Config_Chipset_Mask_AGA) { + if (res_shift == 0) { + switch (gfxvidinfo.drawbuffer.pixbytes) { + case 2: + pfield_do_linetoscr_normal = need_genlock_data ? linetoscr_16_aga_genlock : linetoscr_16_aga; + pfield_do_linetoscr_sprite = need_genlock_data ? linetoscr_16_aga_spr_genlock : linetoscr_16_aga_spr; + pfield_do_linetoscr_spriteonly = linetoscr_16_aga_spronly; + break; + case 4: + pfield_do_linetoscr_normal = need_genlock_data ? linetoscr_32_aga_genlock : linetoscr_32_aga; + pfield_do_linetoscr_sprite = need_genlock_data ? linetoscr_32_aga_spr_genlock : linetoscr_32_aga_spr; + pfield_do_linetoscr_spriteonly = linetoscr_32_aga_spronly; + break; + } + } else if (res_shift == 2) { + switch (gfxvidinfo.drawbuffer.pixbytes) { + case 2: + pfield_do_linetoscr_normal = need_genlock_data ? linetoscr_16_stretch2_aga_genlock : linetoscr_16_stretch2_aga; + pfield_do_linetoscr_sprite = need_genlock_data ? linetoscr_16_stretch2_aga_spr_genlock : linetoscr_16_stretch2_aga_spr_genlock; + pfield_do_linetoscr_spriteonly = linetoscr_16_stretch2_aga_spronly; + break; + case 4: + pfield_do_linetoscr_normal = need_genlock_data ? linetoscr_32_stretch2_aga_genlock : linetoscr_32_stretch2_aga; + pfield_do_linetoscr_sprite = need_genlock_data ? linetoscr_32_stretch2_aga_spr_genlock : linetoscr_32_stretch2_aga_spr; + pfield_do_linetoscr_spriteonly = linetoscr_32_stretch2_aga_spronly; + break; + } + } else if (res_shift == 1) { + switch (gfxvidinfo.drawbuffer.pixbytes) { + case 2: + pfield_do_linetoscr_normal = need_genlock_data ? linetoscr_16_stretch1_aga_genlock : linetoscr_16_stretch1_aga; + pfield_do_linetoscr_sprite = need_genlock_data ? linetoscr_16_stretch1_aga_spr_genlock : linetoscr_16_stretch1_aga_spr; + pfield_do_linetoscr_spriteonly = linetoscr_16_stretch1_aga_spronly; + break; + case 4: + pfield_do_linetoscr_normal = need_genlock_data ? linetoscr_32_stretch1_aga_genlock : linetoscr_32_stretch1_aga; + pfield_do_linetoscr_sprite = need_genlock_data ? linetoscr_32_stretch1_aga_spr_genlock : linetoscr_32_stretch1_aga_spr; + pfield_do_linetoscr_spriteonly = linetoscr_32_stretch1_aga_spronly; + break; + } + } else if (res_shift == -1) { + if (SAEV_config.video.lores_mode) { + switch (gfxvidinfo.drawbuffer.pixbytes) { + case 2: + pfield_do_linetoscr_normal = need_genlock_data ? linetoscr_16_shrink1f_aga_genlock : linetoscr_16_shrink1f_aga; + pfield_do_linetoscr_sprite = need_genlock_data ? linetoscr_16_shrink1f_aga_spr_genlock : linetoscr_16_shrink1f_aga_spr; + pfield_do_linetoscr_spriteonly = linetoscr_16_shrink1f_aga_spronly; + break; + case 4: + pfield_do_linetoscr_normal = need_genlock_data ? linetoscr_32_shrink1f_aga_genlock : linetoscr_32_shrink1f_aga; + pfield_do_linetoscr_sprite = need_genlock_data ? linetoscr_32_shrink1f_aga_spr_genlock : linetoscr_32_shrink1f_aga_spr; + pfield_do_linetoscr_spriteonly = linetoscr_32_shrink1f_aga_spronly; + break; + } + } else { + switch (gfxvidinfo.drawbuffer.pixbytes) { + case 2: + pfield_do_linetoscr_normal = need_genlock_data ? linetoscr_16_shrink1_aga_genlock : linetoscr_16_shrink1_aga; + pfield_do_linetoscr_sprite = need_genlock_data ? linetoscr_16_shrink1_aga_spr_genlock : linetoscr_16_shrink1_aga_spr; + pfield_do_linetoscr_spriteonly = linetoscr_16_shrink1_aga_spronly; + break; + case 4: + pfield_do_linetoscr_normal = need_genlock_data ? linetoscr_32_shrink1_aga_genlock : linetoscr_32_shrink1_aga; + pfield_do_linetoscr_sprite = need_genlock_data ? linetoscr_32_shrink1_aga_spr_genlock : linetoscr_32_shrink1_aga_spr; + pfield_do_linetoscr_spriteonly = linetoscr_32_shrink1_aga_spronly; + break; + } + } + } else if (res_shift == -2) { + if (SAEV_config.video.lores_mode) { + switch (gfxvidinfo.drawbuffer.pixbytes) { + case 2: + pfield_do_linetoscr_normal = need_genlock_data ? linetoscr_16_shrink2f_aga_genlock : linetoscr_16_shrink2f_aga; + pfield_do_linetoscr_sprite = need_genlock_data ? linetoscr_16_shrink2f_aga_spr_genlock : linetoscr_16_shrink2f_aga_spr; + pfield_do_linetoscr_spriteonly = linetoscr_16_shrink2f_aga_spronly; + break; + case 4: + pfield_do_linetoscr_normal = need_genlock_data ? linetoscr_32_shrink2f_aga_genlock : linetoscr_32_shrink2f_aga; + pfield_do_linetoscr_sprite = need_genlock_data ? linetoscr_32_shrink2f_aga_spr_genlock : linetoscr_32_shrink2f_aga_spr; + pfield_do_linetoscr_spriteonly = linetoscr_32_shrink2f_aga_spronly; + break; + } + } else { + switch (gfxvidinfo.drawbuffer.pixbytes) { + case 2: + pfield_do_linetoscr_normal = need_genlock_data ? linetoscr_16_shrink2_aga_genlock : linetoscr_16_shrink2_aga; + pfield_do_linetoscr_sprite = need_genlock_data ? linetoscr_16_shrink2_aga_spr_genlock : linetoscr_16_shrink2_aga_spr; + pfield_do_linetoscr_spriteonly = linetoscr_16_shrink2_aga_spronly; + break; + case 4: + pfield_do_linetoscr_normal = need_genlock_data ? linetoscr_32_shrink2_aga_genlock : linetoscr_32_shrink2_aga; + pfield_do_linetoscr_sprite = need_genlock_data ? linetoscr_32_shrink2_aga_spr_genlock : linetoscr_32_shrink2_aga_spr; + pfield_do_linetoscr_spriteonly = linetoscr_32_shrink2_aga_spronly; + break; + } + } + } + if (get_shdelay_add()) { + pfield_do_linetoscr_shdelay_normal = pfield_do_linetoscr_normal; + pfield_do_linetoscr_shdelay_sprite = pfield_do_linetoscr_sprite; + pfield_do_linetoscr_normal = pfield_do_linetoscr_normal_shdelay; + pfield_do_linetoscr_sprite = pfield_do_linetoscr_sprite_shdelay; + } + } + //#endif /* AGA */ + //#ifdef ECS_DENISE + if (!(SAEV_config.chipset.mask & SAEC_Config_Chipset_Mask_AGA) && ecsshres) { + // TODO: genlock support + if (res_shift == 0) { + switch (gfxvidinfo.drawbuffer.pixbytes) { + case 2: + pfield_do_linetoscr_normal = linetoscr_16_sh; + pfield_do_linetoscr_sprite = linetoscr_16_sh_spr; + break; + case 4: + pfield_do_linetoscr_normal = linetoscr_32_sh; + pfield_do_linetoscr_sprite = linetoscr_32_sh_spr; + break; + } + } else if (res_shift == -1) { + if (SAEV_config.video.lores_mode) { + switch (gfxvidinfo.drawbuffer.pixbytes) { + case 2: + pfield_do_linetoscr_normal = linetoscr_16_shrink1f_sh; + pfield_do_linetoscr_sprite = linetoscr_16_shrink1f_sh_spr; + break; + case 4: + pfield_do_linetoscr_normal = linetoscr_32_shrink1f_sh; + pfield_do_linetoscr_sprite = linetoscr_32_shrink1f_sh_spr; + break; + } + } else { + switch (gfxvidinfo.drawbuffer.pixbytes) { + case 2: + pfield_do_linetoscr_normal = linetoscr_16_shrink1_sh; + pfield_do_linetoscr_sprite = linetoscr_16_shrink1_sh_spr; + break; + case 4: + pfield_do_linetoscr_normal = linetoscr_32_shrink1_sh; + pfield_do_linetoscr_sprite = linetoscr_32_shrink1_sh_spr; + break; + } + } + } else if (res_shift == -2) { + if (SAEV_config.video.lores_mode) { + switch (gfxvidinfo.drawbuffer.pixbytes) { + case 2: + pfield_do_linetoscr_normal = linetoscr_16_shrink2f_sh; + pfield_do_linetoscr_sprite = linetoscr_16_shrink2f_sh_spr; + break; + case 4: + pfield_do_linetoscr_normal = linetoscr_32_shrink2f_sh; + pfield_do_linetoscr_sprite = linetoscr_32_shrink2f_sh_spr; + break; + } + } else { + switch (gfxvidinfo.drawbuffer.pixbytes) { + case 2: + pfield_do_linetoscr_normal = linetoscr_16_shrink2_sh; + pfield_do_linetoscr_sprite = linetoscr_16_shrink2_sh_spr; + break; + case 4: + pfield_do_linetoscr_normal = linetoscr_32_shrink2_sh; + pfield_do_linetoscr_sprite = linetoscr_32_shrink2_sh_spr; + break; + } + } + } + } + //#endif /* ECS_DENISE */ + if (!(SAEV_config.chipset.mask & SAEC_Config_Chipset_Mask_AGA) && !ecsshres) { + if (res_shift == 0) { + switch (gfxvidinfo.drawbuffer.pixbytes) { + case 2: + pfield_do_linetoscr_normal = need_genlock_data ? linetoscr_16_genlock : linetoscr_16; + pfield_do_linetoscr_sprite = need_genlock_data ? linetoscr_16_spr_genlock : linetoscr_16_spr; + break; + case 4: + pfield_do_linetoscr_normal = need_genlock_data ? linetoscr_32_genlock : linetoscr_32; + pfield_do_linetoscr_sprite = need_genlock_data ? linetoscr_32_spr_genlock : linetoscr_32_spr; + break; + } + } else if (res_shift == 2) { + switch (gfxvidinfo.drawbuffer.pixbytes) { + case 2: + pfield_do_linetoscr_normal = need_genlock_data ? linetoscr_16_stretch2_genlock : linetoscr_16_stretch2; + pfield_do_linetoscr_sprite = need_genlock_data ? linetoscr_16_stretch2_spr_genlock : linetoscr_16_stretch2_spr; + break; + case 4: + pfield_do_linetoscr_normal = need_genlock_data ? linetoscr_32_stretch2_genlock : linetoscr_32_stretch2; + pfield_do_linetoscr_sprite = need_genlock_data ? linetoscr_32_stretch2_spr_genlock : linetoscr_32_stretch2_spr; + break; + } + } else if (res_shift == 1) { + switch (gfxvidinfo.drawbuffer.pixbytes) { + case 2: + pfield_do_linetoscr_normal = need_genlock_data ? linetoscr_16_stretch1_genlock : linetoscr_16_stretch1; + pfield_do_linetoscr_sprite = need_genlock_data ? linetoscr_16_stretch1_spr_genlock : linetoscr_16_stretch1_spr; + break; + case 4: + pfield_do_linetoscr_normal = need_genlock_data ? linetoscr_32_stretch1_genlock : linetoscr_32_stretch1; + pfield_do_linetoscr_sprite = need_genlock_data ? linetoscr_32_stretch1_spr_genlock : linetoscr_32_stretch1_spr; + break; + } + } else if (res_shift == -1) { + if (SAEV_config.video.lores_mode) { + switch (gfxvidinfo.drawbuffer.pixbytes) { + case 2: + pfield_do_linetoscr_normal = need_genlock_data ? linetoscr_16_shrink1f_genlock : linetoscr_16_shrink1f; + pfield_do_linetoscr_sprite = need_genlock_data ? linetoscr_16_shrink1f_spr_genlock : linetoscr_16_shrink1f_spr; + break; + case 4: + pfield_do_linetoscr_normal = need_genlock_data ? linetoscr_32_shrink1f_genlock : linetoscr_32_shrink1f; + pfield_do_linetoscr_sprite = need_genlock_data ? linetoscr_32_shrink1f_spr_genlock : linetoscr_32_shrink1f_spr; + break; + } + } else { + switch (gfxvidinfo.drawbuffer.pixbytes) { + case 2: + pfield_do_linetoscr_normal = need_genlock_data ? linetoscr_16_shrink1_genlock : linetoscr_16_shrink1; + pfield_do_linetoscr_sprite = need_genlock_data ? linetoscr_16_shrink1_spr_genlock : linetoscr_16_shrink1_spr; + break; + case 4: + pfield_do_linetoscr_normal = need_genlock_data ? linetoscr_32_shrink1_genlock : linetoscr_32_shrink1; + pfield_do_linetoscr_sprite = need_genlock_data ? linetoscr_32_shrink1_spr_genlock : linetoscr_32_shrink1_spr; + break; + } + } + } + } + } + + // left or right AGA border sprite + function pfield_do_linetoscr_bordersprite_aga(start, stop, blank) { + if (blank) { + pfield_do_fill_line(start, stop, blank); + return; + } + pfield_do_linetoscr_spriteonly(src_pixel, start, stop); + } + + function dummy_worker(start, stop, blank) {} + + var ham_decode_pixel = 0; //int + var ham_lastcolor = 0; //uint + + /* Decode HAM in the invisible portion of the display (left of VISIBLE_LEFT_BORDER), + * but don't draw anything in. This is done to prepare HAM_LASTCOLOR for later, when decode_ham runs. */ + function init_ham_decoding() { + var unpainted_amiga = unpainted; + + ham_decode_pixel = src_pixel; + ham_lastcolor = color_reg_get(colors_for_drawing, 0); + + if (!bplham) { + if (unpainted_amiga > 0) { + var pv = pixdata.apixels[ham_decode_pixel + unpainted_amiga - 1]; + //#ifdef AGA + if (SAEV_config.chipset.mask & SAEC_Config_Chipset_Mask_AGA) + ham_lastcolor = colors_for_drawing.color_regs_aga[pv ^ bplxor] & 0xffffff; + else + //#endif + ham_lastcolor = colors_for_drawing.color_regs_ecs[pv] & 0xfff; + } + //#ifdef AGA + } else if (SAEV_config.chipset.mask & SAEC_Config_Chipset_Mask_AGA) { + if (bplplanecnt >= 7) { /* AGA mode HAM8 */ + while (unpainted_amiga-- > 0) { + var pv = pixdata.apixels[ham_decode_pixel++] ^ bplxor; + switch (pv & 0x3) { + case 0x0: ham_lastcolor = colors_for_drawing.color_regs_aga[pv >> 2] & 0xffffff; break; + case 0x1: ham_lastcolor &= 0xFFFF03; ham_lastcolor |= (pv & 0xFC); break; + case 0x2: ham_lastcolor &= 0x03FFFF; ham_lastcolor |= (pv & 0xFC) << 16; break; + case 0x3: ham_lastcolor &= 0xFF03FF; ham_lastcolor |= (pv & 0xFC) << 8; break; + } + } + } else { /* AGA mode HAM6 */ + while (unpainted_amiga-- > 0) { + var pv = pixdata.apixels[ham_decode_pixel++] ^ bplxor; + switch (pv & 0x30) { + case 0x00: ham_lastcolor = colors_for_drawing.color_regs_aga[pv] & 0xffffff; break; + case 0x10: ham_lastcolor &= 0xFFFF00; ham_lastcolor |= (pv & 0xF) << 4; break; + case 0x20: ham_lastcolor &= 0x00FFFF; ham_lastcolor |= (pv & 0xF) << 20; break; + case 0x30: ham_lastcolor &= 0xFF00FF; ham_lastcolor |= (pv & 0xF) << 12; break; + } + } + } + //#endif + } else { + /* OCS/ECS mode HAM6 */ + while (unpainted_amiga-- > 0) { + var pv = pixdata.apixels[ham_decode_pixel++]; + switch (pv & 0x30) { + case 0x00: ham_lastcolor = colors_for_drawing.color_regs_ecs[pv] & 0xfff; break; + case 0x10: ham_lastcolor &= 0xFF0; ham_lastcolor |= (pv & 0xF); break; + case 0x20: ham_lastcolor &= 0x0FF; ham_lastcolor |= (pv & 0xF) << 8; break; + case 0x30: ham_lastcolor &= 0xF0F; ham_lastcolor |= (pv & 0xF) << 4; break; + } + } + } + } + + function decode_ham(pix, stoppos, blank) { + var todraw_amiga = res_shift_from_window(stoppos - pix); + var hdp = ham_decode_pixel; + + if (!bplham) { + while (todraw_amiga-- > 0) { + var pv = pixdata.apixels[ham_decode_pixel]; + //#ifdef AGA + if (SAEV_config.chipset.mask & SAEC_Config_Chipset_Mask_AGA) + ham_lastcolor = colors_for_drawing.color_regs_aga[pv ^ bplxor] & 0xffffff; + else + //#endif + ham_lastcolor = colors_for_drawing.color_regs_ecs[pv] & 0xfff; + + ham_linebuf[ham_decode_pixel++] = ham_lastcolor; + } + //#ifdef AGA + } else if (SAEV_config.chipset.mask & SAEC_Config_Chipset_Mask_AGA) { + if (bplplanecnt >= 7) { /* AGA mode HAM8 */ + while (todraw_amiga-- > 0) { + var pv = pixdata.apixels[ham_decode_pixel] ^ bplxor; + switch (pv & 0x3) { + case 0x0: ham_lastcolor = colors_for_drawing.color_regs_aga[pv >> 2] & 0xffffff; break; + case 0x1: ham_lastcolor &= 0xFFFF03; ham_lastcolor |= (pv & 0xFC); break; + case 0x2: ham_lastcolor &= 0x03FFFF; ham_lastcolor |= (pv & 0xFC) << 16; break; + case 0x3: ham_lastcolor &= 0xFF03FF; ham_lastcolor |= (pv & 0xFC) << 8; break; + } + ham_linebuf[ham_decode_pixel++] = ham_lastcolor; + } + } else { /* AGA mode HAM6 */ + while (todraw_amiga-- > 0) { + var pv = pixdata.apixels[ham_decode_pixel] ^ bplxor; + switch (pv & 0x30) { + case 0x00: ham_lastcolor = colors_for_drawing.color_regs_aga[pv] & 0xffffff; break; + case 0x10: ham_lastcolor &= 0xFFFF00; ham_lastcolor |= (pv & 0xF) << 4; break; + case 0x20: ham_lastcolor &= 0x00FFFF; ham_lastcolor |= (pv & 0xF) << 20; break; + case 0x30: ham_lastcolor &= 0xFF00FF; ham_lastcolor |= (pv & 0xF) << 12; break; + } + ham_linebuf[ham_decode_pixel++] = ham_lastcolor; + } + } + //#endif + } else { + /* OCS/ECS mode HAM6 */ + while (todraw_amiga-- > 0) { + var pv = pixdata.apixels[ham_decode_pixel]; + switch (pv & 0x30) { + case 0x00: ham_lastcolor = colors_for_drawing.color_regs_ecs[pv] & 0xfff; break; + case 0x10: ham_lastcolor &= 0xFF0; ham_lastcolor |= (pv & 0xF); break; + case 0x20: ham_lastcolor &= 0x0FF; ham_lastcolor |= (pv & 0xF) << 8; break; + case 0x30: ham_lastcolor &= 0xF0F; ham_lastcolor |= (pv & 0xF) << 4; break; + } + ham_linebuf[ham_decode_pixel++] = ham_lastcolor; + } + } + } + + /*function erase_ham_right_border(pix, stoppos, blank) { + if (stoppos < playfield_end) + return; + // erase right border in HAM modes or old HAM data may be visible + // if DDFSTOP < DIWSTOP (Uridium II title screen) + var todraw_amiga = res_shift_from_window(stoppos - pix); + while (todraw_amiga-- > 0) + ham_linebuf[ham_decode_pixel++] = 0; + }*/ + + function gen_pfield_tables() { + if (dblpf_ms1 !== null) + return; + + dblpf_ms1 = new Array(256) + dblpf_ms2 = new Array(256) + dblpf_ms = new Array(256); + dblpf_ind1 = new Array(256) + dblpf_ind2 = new Array(256); + dblpf_2nd1 = new Array(256) + dblpf_2nd2 = new Array(256); + //#ifdef AGA + dblpf_ind1_aga = new Array(256); + dblpf_ind2_aga = new Array(256); + //#endif + sprite_offs = new Array(256); + clxtab = new Uint32Array(256); + + for (var i = 0; i < 256; i++) { + var plane1 = ((i >> 0) & 1) | ((i >> 1) & 2) | ((i >> 2) & 4) | ((i >> 3) & 8); + var plane2 = ((i >> 1) & 1) | ((i >> 2) & 2) | ((i >> 3) & 4) | ((i >> 4) & 8); + + dblpf_2nd1[i] = plane1 == 0 && plane2 != 0; + dblpf_2nd2[i] = plane2 != 0; + + //#ifdef AGA + dblpf_ind1_aga[i] = plane1 == 0 ? plane2 : plane1; + dblpf_ind2_aga[i] = plane2 == 0 ? plane1 : plane2; + //#endif + + dblpf_ms1[i] = plane1 == 0 ? (plane2 == 0 ? 16 : 8) : 0; + dblpf_ms2[i] = plane2 == 0 ? (plane1 == 0 ? 16 : 0) : 8; + dblpf_ms[i] = i == 0 ? 16 : 8; + + if (plane2 > 0) + plane2 += 8; + dblpf_ind1[i] = i >= 128 ? i & 0x7F : (plane1 == 0 ? plane2 : plane1); + dblpf_ind2[i] = i >= 128 ? i & 0x7F : (plane2 == 0 ? plane1 : plane2); + + // Hack for OCS/ECS-only dualplayfield chipset bug. + // If PF2P2 is invalid (>5), playfield color becomes transparent but + // playfield still hides playfield under it! (if plfpri is set) + if (i & 64) { + dblpf_ind2[i] = 0; + dblpf_ind1[i] = 0; + } + + sprite_offs[i] = (i & 15) ? 0 : 2; + + clxtab[i] = ((((i & 3) && (i & 12)) << 9) + | (((i & 3) && (i & 48)) << 10) + | (((i & 3) && (i & 192)) << 11) + | (((i & 12) && (i & 48)) << 12) + | (((i & 12) && (i & 192)) << 13) + | (((i & 48) && (i & 192)) << 14)); + + } + //memset(all_ones, 0xff, MAX_PIXELS_PER_LINE); + //SAEF_memset(all_ones,0, 0xff, MAX_PIXELS_PER_LINE); + } + + /* When looking at this function and the ones that inline it, bear in mind + what an optimizing compiler will do with this code. All callers of this + function only pass in constant arguments (except for E). This means + that many of the if statements will go away completely after inlining. */ + /*STATIC_INLINE void draw_sprites_1 (struct sprite_entry *e, int dualpf, int has_attach) { + uae_u16 *buf = spixels + e->first_pixel; + uae_u8 *stbuf = spixstate.bytes + e->first_pixel; + int spr_pos, pos; + + buf -= e->pos; + stbuf -= e->pos; + + spr_pos = e->pos + ((DIW_DDF_OFFSET - DISPLAY_LEFT_SHIFT) << sprite_buffer_res); + + if (spr_pos < sprite_first_x) + sprite_first_x = spr_pos; + + for (pos = e->pos; pos < e->max; pos++, spr_pos++) { + if (spr_pos >= 0 && spr_pos < MAX_PIXELS_PER_LINE) { + spritepixels[spr_pos].data = buf[pos]; + spritepixels[spr_pos].stdata = stbuf[pos]; + spritepixels[spr_pos].attach = has_attach; + } + } + + if (spr_pos > sprite_last_x) + sprite_last_x = spr_pos; + }*/ function draw_sprites_1(e, dualpf, has_attach) { - //uae_u16 *buf = spixels + e.first_pixel; - //uae_u8 *stbuf = spixstate.bytes + e.first_pixel; - //buf -= e.pos; - //stbuf -= e.pos; - var pos2 = e.first_pixel - e.pos; + /*uae_u16 *buf = spixels + e->first_pixel; + uae_u8 *stbuf = spixstate.bytes + e->first_pixel; + buf -= e->pos; + stbuf -= e->pos;*/ var spr_pos = e.pos + ((DIW_DDF_OFFSET - DISPLAY_LEFT_SHIFT) << sprite_buffer_res); @@ -2747,900 +2660,3078 @@ function Playfield() { if (spr_pos >= 0 && spr_pos < MAX_PIXELS_PER_LINE) { //spritepixels[spr_pos].data = buf[pos]; //spritepixels[spr_pos].stdata = stbuf[pos]; - spritepixels[spr_pos].data = spixels[pos2 + pos]; - spritepixels[spr_pos].stdata = spixstate[pos2 + pos]; + //spritepixels[spr_pos].attach = has_attach; + spritepixels[spr_pos].data = spixels[e.first_pixel - e.pos + pos]; + spritepixels[spr_pos].stdata = spixstate.bytes[e.first_pixel - e.pos + pos]; spritepixels[spr_pos].attach = has_attach; } } + if (spr_pos > sprite_last_x) sprite_last_x = spr_pos; } - function draw_sprites(e) { - if (!DO_SPRITES) return; //FIXME - draw_sprites_1(e, bpldualpf, e.has_attached); - } - - function ecsshres_func() { - return bplcon0_res == RES_SUPERHIRES && (AMIGA.config.chipset.mask & CSMASK_ECS_DENISE) && !(AMIGA.config.chipset.mask & CSMASK_AGA); - } - - /* handle very rarely needed playfield collision (CLXDAT bit 0) only known game needing this is Rotor */ - this.do_playfield_collisions = function () { - var ddf_left = thisline_decision.plfleft * 2 << bplcon0_res; - var hw_diwlast = coord_window_to_diw_x(thisline_decision.diwlastword); - var hw_diwfirst = coord_window_to_diw_x(thisline_decision.diwfirstword); - var i, collided, minpos, maxpos; - /*#ifdef AGA - var planes = (currprefs.chipset_mask & CSMASK_AGA) ? 8 : 6; - #else*/ - var planes = 6; -//#endif - - if (clxcon_bpl_enable == 0) { - clxdat |= 1; - return; - } - if (clxdat & 1) - return; - - collided = 0; - minpos = thisline_decision.plfleft * 2; - if (minpos < hw_diwfirst) - minpos = hw_diwfirst; - maxpos = thisline_decision.plfright * 2; - if (maxpos > hw_diwlast) - maxpos = hw_diwlast; - for (i = minpos; i < maxpos && !collided; i += 32) { - var offs = ((i << bplcon0_res) - ddf_left) >> 3; - var j; - var total = 0xffffffff; - for (j = 0; j < planes; j++) { - var ena = (clxcon_bpl_enable >> j) & 1; - var match = (clxcon_bpl_match >> j) & 1; - var t = 0xffffffff; - if (ena) { - if (j < thisline_decision.nr_planes) { - //t = *(uae_u32 *)(line_data[next_lineno] + offs + 2 * j * MAX_WORDS_PER_LINE); - t = line_data[next_lineno][j][offs]; - t ^= (match & 1) - 1; - } else { - t = (match & 1) - 1; - } - } - total &= t; - } - if (total) { - collided = 1; - /*if (1) { //debug - for (var k = 0; k < 1; k++) { - //uae_u32 *ldata = (uae_u32 *)(line_data[next_lineno] + offs + 2 * k * MAX_WORDS_PER_LINE); *ldata ^= 0x5555555555; - line_data[next_lineno][k][offs] ^= 0x5555555555; - } - }*/ - } - } - if (collided) - clxdat |= 1; - }; - - /* Sprite-to-sprite collisions are taken care of in record_sprite. This one does playfield/sprite collisions. */ - this.do_sprite_collisions = function () { - var nr_sprites = curr_drawinfo[next_lineno].nr_sprites; - var first = curr_drawinfo[next_lineno].first_sprite_entry; - var collision_mask = clxmask[clxcon >> 12]; - var ddf_left = thisline_decision.plfleft * 2 << bplcon0_res; - var hw_diwlast = coord_window_to_diw_x(thisline_decision.diwlastword); - var hw_diwfirst = coord_window_to_diw_x(thisline_decision.diwfirstword); - - if (clxcon_bpl_enable == 0) { - clxdat |= 0x1fe; - return; - } - - for (var i = 0; i < nr_sprites; i++) { - var e = curr_sprite_entries[first + i]; - var minpos = e.pos; - var maxpos = e.max; - var minp1 = minpos >> sprite_buffer_res; - var maxp1 = maxpos >> sprite_buffer_res; - - if (maxp1 > hw_diwlast) - maxpos = hw_diwlast << sprite_buffer_res; - if (maxp1 > thisline_decision.plfright * 2) - maxpos = thisline_decision.plfright * 2 << sprite_buffer_res; - if (minp1 < hw_diwfirst) - minpos = hw_diwfirst << sprite_buffer_res; - if (minp1 < thisline_decision.plfleft * 2) - minpos = thisline_decision.plfleft * 2 << sprite_buffer_res; - - for (var j = minpos; j < maxpos; j++) { - var sprpix = spixels[e.first_pixel + j - e.pos] & collision_mask; - - if (sprpix == 0) - continue; - - var match = 1; - var offs = ((j << bplcon0_res) >> sprite_buffer_res) - ddf_left; - sprpix = (sprite_ab_merge[sprpix & 255] | (sprite_ab_merge[sprpix >> 8] << 2)) << 1; - - for (var k = 1; k >= 0; k--) { - /*#ifdef AGA - var planes = (currprefs.chipset_mask & CSMASK_AGA) ? 8 : 6; - #else*/ - var planes = 6; -//#endif - if (bplcon0 & 0x400) - match = 1; - for (var l = k; match && l < planes; l += 2) { - var t = 0; - if (l < thisline_decision.nr_planes) { - //uae_u32 *ldata = (uae_u32 *)(line_data[next_lineno] + 2 * l * MAX_WORDS_PER_LINE); var word = ldata[offs >> 5]; - var word = line_data[next_lineno][l][offs >> 5]; - t = (word >>> (31 - (offs & 31))) & 1; - /*if (1) { //debug: draw collision mask - for (var m = 0; m < 5; m++) { - //uae_u32 *ldata = (uae_u32 *)(line_data[next_lineno] + 2 * m * MAX_WORDS_PER_LINE); ldata[(offs >> 5) + 1] |= 15 << (31 - (offs & 31)); - line_data[next_lineno][m][(offs >> 5) + 0] |= 15 << (31 - (offs & 31)); - } - }*/ - } - if (clxcon_bpl_enable & (1 << l)) { - if (t != ((clxcon_bpl_match >> l) & 1)) - match = 0; - } - } - if (match) { - /*if (1) { //debug: mark lines where collisions are detected - for (var l = 0; l < 5; l++) { - //uae_u32 *ldata = (uae_u32 *)(line_data[next_lineno] + 2 * l * MAX_WORDS_PER_LINE); ldata[(offs >> 5) + 1] |= 15 << (31 - (offs & 31)); - line_data[next_lineno][l][(offs >> 5) + 0] |= 15 << (31 - (offs & 31)); - } - }*/ - clxdat |= (sprpix << (k * 4)); - } - } - } - } - /*{ - static var olx; - if (clxdat != olx) BUG.info('%d: %04x', vpos, clxdat); - olx = clxdat; - }*/ - }; - - this.record_sprite_1 = function (sprxp, buf, datab, num, dbl, mask, do_collisions, collision_mask) { - var j = 0; - - while (datab) { - var col = 0; - var coltmp = 0; - - if ((sprxp >= sprite_minx && sprxp < sprite_maxx) || (bplcon3 & 2)) - col = (datab & 3) << (2 * num); - - //if (sprxp == sprite_minx || sprxp == sprite_maxx - 1) col ^= Math.floor(Math.random() * 0xffffffff); - - if ((j & mask) == 0) { - //var tmp = (*buf) | col; *buf++ = tmp; - var tmp = spixels[buf] | col; - spixels[buf++] = tmp; - if (do_collisions) - coltmp |= tmp; - sprxp++; - } - if (dbl > 0) { - //var tmp = (*buf) | col; *buf++ = tmp; - var tmp = spixels[buf] | col; - spixels[buf++] = tmp; - if (do_collisions) - coltmp |= tmp; - sprxp++; - } - if (dbl > 1) { - var tmp; - //tmp = (*buf) | col; *buf++ = tmp; - tmp = spixels[buf] | col; - spixels[buf++] = tmp; - if (do_collisions) - coltmp |= tmp; - //tmp = (*buf) | col; *buf++ = tmp; - tmp = spixels[buf] | col; - spixels[buf++] = tmp; - if (do_collisions) - coltmp |= tmp; - sprxp++; - sprxp++; - } - j++; - datab >>>= 2; - if (do_collisions) { - coltmp &= collision_mask; - if (coltmp) { - var shrunk_tmp = sprite_ab_merge[coltmp & 255] | (sprite_ab_merge[coltmp >> 8] << 2); - clxdat |= sprclx[shrunk_tmp]; - } - } - } - }; - - //this.record_sprite = function(line, num, sprxp, data, datb, ctl) { - this.record_sprite = function (line, num, sprxp) { - var e = curr_sprite_entries[next_sprite_entry]; - var word_offs; - var collision_mask; - var width, dbl, half; - var mask = 0; - var attachment; - var i; - - //var data = 0, datb = 0; - var this_sprite_entry = next_sprite_entry; - var num2 = 0; - - half = 0; - dbl = sprite_buffer_res - sprres; - if (dbl < 0) { - half = -dbl; - dbl = 0; - mask = 1 << half; - } - width = (sprite_width << sprite_buffer_res) >> sprres; - attachment = sprctl[num | 1] & 0x80; - - /* Try to coalesce entries if they aren't too far apart */ - //if (!next_sprite_forced && e[-1].max + sprite_width >= sprxp) { - if (this_sprite_entry > 0 && !next_sprite_forced && curr_sprite_entries[this_sprite_entry - 1].max + sprite_width >= sprxp) { - //e--; - e = curr_sprite_entries[this_sprite_entry - 1]; - this_sprite_entry--; - //console.log('RS',this_sprite_entry); - } else { - next_sprite_entry++; - e.pos = sprxp; - e.has_attached = 0; - } - - if (sprxp < e.pos) - Fatal(333, 'sprxp < e->pos'); - - e.max = sprxp + width; - //e[1].first_pixel = e.first_pixel + ((e.max - e.pos + 3) & ~3); - curr_sprite_entries[this_sprite_entry + 1].first_pixel = e.first_pixel + ((e.max - e.pos + 3) & ~3); - next_sprite_forced = 0; - - collision_mask = clxmask[clxcon >> 12]; - word_offs = e.first_pixel + sprxp - e.pos; - - for (i = 0; i < sprite_width; i += 16) { - //var da = *data; - //var db = *datb; - //var da = sprdata[data][0]; - //var db = sprdatb[datb][0]; - var da = sprdata[num][num2]; - var db = sprdatb[num][num2]; - var datab = ((sprtaba[da & 0xFF] << 16) | sprtaba[da >> 8] | (sprtabb[db & 0xFF] << 16) | sprtabb[db >> 8]) >>> 0; - var off = (i << dbl) >> half; - //uae_u16 *buf = spixels + word_offs + off; - var buf = word_offs + off; - if (AMIGA.config.chipset.collision_level > 0 && collision_mask) - this.record_sprite_1(sprxp + off, buf, datab, num, dbl, mask, 1, collision_mask); + /* OPT inline, ok + function draw_sprites_normal_sp_nat(e) { draw_sprites_1(e, 0, 0); } + function draw_sprites_normal_dp_nat(e) { draw_sprites_1(e, 1, 0); } + function draw_sprites_normal_sp_at(e) { draw_sprites_1(e, 0, 1); } + function draw_sprites_normal_dp_at(e) { draw_sprites_1(e, 1, 1); } + function draw_sprites_ecs(e) { + if (e->has_attached) { + if (bpldualpf) + draw_sprites_normal_dp_at(e); else - this.record_sprite_1(sprxp + off, buf, datab, num, dbl, mask, 0, collision_mask); - - //*data++; *datb++; - num2++; + draw_sprites_normal_sp_at(e); + } else { + if (bpldualpf) + draw_sprites_normal_dp_nat(e); + else + draw_sprites_normal_sp_nat(e); } + }*/ + /*OPT inline, ok + function draw_sprites_ecs(e) { + draw_sprites_1(e, bpldualpf, e.has_attached); + } + //#ifdef AGA + function draw_sprites_aga(e, aga) { + draw_sprites_1(e, bpldualpf, e.has_attached); + } + //#endif*/ - /* We have 8 bits per pixel in spixstate, two for every sprite pair. - The low order bit records whether the attach bit was set for this pair. */ - if (attachment && !ecsshres_func()) { - var state = ((0x01010101 << (num & ~1)) >>> 0) & 0xff; - /*uae_u8 *stb1 = spixstate.bytes + word_offs; - for (i = 0; i < width; i += 8) { - stb1[0] |= state; - stb1[1] |= state; - stb1[2] |= state; - stb1[3] |= state; - stb1[4] |= state; - stb1[5] |= state; - stb1[6] |= state; - stb1[7] |= state; - stb1 += 8; - }*/ - var stb1 = word_offs; - for (i = 0; i < width; i += 8) { - spixstate[stb1 + 0] |= state; - spixstate[stb1 + 1] |= state; - spixstate[stb1 + 2] |= state; - spixstate[stb1 + 3] |= state; - spixstate[stb1 + 4] |= state; - spixstate[stb1 + 5] |= state; - spixstate[stb1 + 6] |= state; - spixstate[stb1 + 7] |= state; - stb1 += 8; + //#ifdef AGA + /* clear possible bitplane data outside DIW area */ + function clear_bitplane_border_aga() { + const v = 0; + var shift = res_shift; + var i, start, end; + + if (shift < 0) { + shift = -shift; + start = pixels_offset + (playfield_start << shift); + end = start + ((real_playfield_start - playfield_start) << shift); + for (i = start; i < end; i++) pixdata.apixels[i] = v; + + start = pixels_offset + (real_playfield_end << shift), + end = start + ((playfield_end - real_playfield_end) << shift); + for (i = start; i < end; i++) pixdata.apixels[i] = v; + } else { + start = pixels_offset + (playfield_start >> shift); + end = start + ((real_playfield_start - playfield_start) >> shift); + for (i = start; i < end; i++) pixdata.apixels[i] = v; + + start = pixels_offset + (real_playfield_end >> shift); + end = start + ((playfield_end - real_playfield_end) >> shift); + for (i = start; i < end; i++) pixdata.apixels[i] = v; + } + } + //#endif + + function weird_bitplane_fix(start, end) { + var sh = lores_shift; + //uae_u8 *p = pixdata.apixels + pixels_offset; + + start >>= sh; + end >>= sh; + /*if (bplplanecnt == 5 && !bpldualpf) { + for (var i = start; i < end; i++) { + if (p[i] & 16) p[i] = 16; + } + } else if (bpldualpf && bpldualpfpri) { + for (var i = start; i < end; i++) { + if (p[i] & (2 | 8 | 32)) p[i] |= 0x40; + } + } else if (bpldualpf && !bpldualpfpri) { + for (var i = start; i < end; i++) { + p[i] &= ~(2 | 8 | 32); + } + }*/ + if (bplplanecnt == 5 && !bpldualpf) { + /* emulate OCS/ECS only undocumented "SWIV" hardware feature */ + for (var i = pixels_offset + start; i < pixels_offset + end; i++) { + if (pixdata.apixels[i] & 16) pixdata.apixels[i] = 16; + } + } else if (bpldualpf && bpldualpfpri) { + /* in dualplayfield mode this feature is even more strange.. */ + for (var i = pixels_offset + start; i < pixels_offset + end; i++) { + if (pixdata.apixels[i] & (2 | 8 | 32)) pixdata.apixels[i] |= 0x40; + } + } else if (bpldualpf && !bpldualpfpri) { + for (var i = pixels_offset + start; i < pixels_offset + end; i++) { + pixdata.apixels[i] &= ~(2 | 8 | 32); } - e.has_attached = 1; } - }; + } - function tospritexdiw(diw) { - return coord_window_to_hw_x(diw - (DIW_DDF_OFFSET << lores_shift)) << sprite_buffer_res; + /* We use the compiler"s inlining ability to ensure that PLANES is in effect a compile time + constant. That will cause some unnecessary code to be optimized away. + Don't touch this if you don't know what you are doing. */ + + /*#define MERGE(a,b,mask,shift) do {\ + uae_u32 tmp = mask & (a ^ (b >> shift)); \ + a ^= tmp; \ + b ^= (tmp << shift); \ + } while (0) + + #define GETLONG(P) (*(uae_u32 *)P) + + STATIC_INLINE void pfield_doline_1 (uae_u32 *pixels, int wordcount, int planes) { + while (wordcount-- > 0) { + uae_u32 b0, b1, b2, b3, b4, b5, b6, b7; + + b0 = 0, b1 = 0, b2 = 0, b3 = 0, b4 = 0, b5 = 0, b6 = 0, b7 = 0; + switch (planes) { + #ifdef AGA + case 8: b0 = GETLONG (real_bplpt[7]); real_bplpt[7] += 4; + case 7: b1 = GETLONG (real_bplpt[6]); real_bplpt[6] += 4; + #endif + case 6: b2 = GETLONG (real_bplpt[5]); real_bplpt[5] += 4; + case 5: b3 = GETLONG (real_bplpt[4]); real_bplpt[4] += 4; + case 4: b4 = GETLONG (real_bplpt[3]); real_bplpt[3] += 4; + case 3: b5 = GETLONG (real_bplpt[2]); real_bplpt[2] += 4; + case 2: b6 = GETLONG (real_bplpt[1]); real_bplpt[1] += 4; + case 1: b7 = GETLONG (real_bplpt[0]); real_bplpt[0] += 4; + } + + MERGE (b0, b1, 0x55555555, 1); + MERGE (b2, b3, 0x55555555, 1); + MERGE (b4, b5, 0x55555555, 1); + MERGE (b6, b7, 0x55555555, 1); + + MERGE (b0, b2, 0x33333333, 2); + MERGE (b1, b3, 0x33333333, 2); + MERGE (b4, b6, 0x33333333, 2); + MERGE (b5, b7, 0x33333333, 2); + + MERGE (b0, b4, 0x0f0f0f0f, 4); + MERGE (b1, b5, 0x0f0f0f0f, 4); + MERGE (b2, b6, 0x0f0f0f0f, 4); + MERGE (b3, b7, 0x0f0f0f0f, 4); + + MERGE (b0, b1, 0x00ff00ff, 8); + MERGE (b2, b3, 0x00ff00ff, 8); + MERGE (b4, b5, 0x00ff00ff, 8); + MERGE (b6, b7, 0x00ff00ff, 8); + + MERGE (b0, b2, 0x0000ffff, 16); + do_put_mem_long (pixels, b0); + do_put_mem_long (pixels + 4, b2); + MERGE (b1, b3, 0x0000ffff, 16); + do_put_mem_long (pixels + 2, b1); + do_put_mem_long (pixels + 6, b3); + MERGE (b4, b6, 0x0000ffff, 16); + do_put_mem_long (pixels + 1, b4); + do_put_mem_long (pixels + 5, b6); + MERGE (b5, b7, 0x0000ffff, 16); + do_put_mem_long (pixels + 3, b5); + do_put_mem_long (pixels + 7, b7); + pixels += 8; + } } - function tospritexddf(ddf) { - return (ddf << 1) << sprite_buffer_res; - } - /*function fromspritexdiw(ddf) { - return coord_hw_to_window_x(ddf >> sprite_buffer_res) + (DIW_DDF_OFFSET << lores_shift); + + // See above for comments on inlining. These functions should _not_ be inlined themselves. + static void NOINLINE pfield_doline_n1 (uae_u32 *data, int count) { pfield_doline_1 (data, count, 1); } + static void NOINLINE pfield_doline_n2 (uae_u32 *data, int count) { pfield_doline_1 (data, count, 2); } + static void NOINLINE pfield_doline_n3 (uae_u32 *data, int count) { pfield_doline_1 (data, count, 3); } + static void NOINLINE pfield_doline_n4 (uae_u32 *data, int count) { pfield_doline_1 (data, count, 4); } + static void NOINLINE pfield_doline_n5 (uae_u32 *data, int count) { pfield_doline_1 (data, count, 5); } + static void NOINLINE pfield_doline_n6 (uae_u32 *data, int count) { pfield_doline_1 (data, count, 6); } + #ifdef AGA + static void NOINLINE pfield_doline_n7 (uae_u32 *data, int count) { pfield_doline_1 (data, count, 7); } + static void NOINLINE pfield_doline_n8 (uae_u32 *data, int count) { pfield_doline_1 (data, count, 8); } + #endif + + static void pfield_doline (int lineno) { + int wordcount = dp_for_drawing->plflinelen; + uae_u32 *data = pixdata.apixels_l + MAX_PIXELS_PER_LINE / 4; + + #ifdef SMART_UPDATE + #define DATA_POINTER(n) ((debug_bpl_mask & (1 << n)) ? (line_data[lineno] + (n) * MAX_WORDS_PER_LINE * 2) : (debug_bpl_mask_one ? all_ones : all_zeros)) + real_bplpt[0] = DATA_POINTER (0); + real_bplpt[1] = DATA_POINTER (1); + real_bplpt[2] = DATA_POINTER (2); + real_bplpt[3] = DATA_POINTER (3); + real_bplpt[4] = DATA_POINTER (4); + real_bplpt[5] = DATA_POINTER (5); + #ifdef AGA + real_bplpt[6] = DATA_POINTER (6); + real_bplpt[7] = DATA_POINTER (7); + #endif + #endif + + switch (bplplanecnt) { + default: break; + case 0: memset (data, 0, wordcount * 32); break; + case 1: pfield_doline_n1 (data, wordcount); break; + case 2: pfield_doline_n2 (data, wordcount); break; + case 3: pfield_doline_n3 (data, wordcount); break; + case 4: pfield_doline_n4 (data, wordcount); break; + case 5: pfield_doline_n5 (data, wordcount); break; + case 6: pfield_doline_n6 (data, wordcount); break; + #ifdef AGA + case 7: pfield_doline_n7 (data, wordcount); break; + case 8: pfield_doline_n8 (data, wordcount); break; + #endif + } + + if (refresh_indicator_buffer && refresh_indicator_height > lineno) { + uae_u8 *opline = refresh_indicator_buffer + lineno * MAX_PIXELS_PER_LINE * 2; + wordcount *= 32; + if (!memcmp(opline, data, wordcount)) { + if (refresh_indicator_changed[lineno] != 0xff) { + refresh_indicator_changed[lineno]++; + if (refresh_indicator_changed[lineno] > refresh_indicator_changed_prev[lineno]) { + refresh_indicator_changed_prev[lineno] = refresh_indicator_changed[lineno]; + } + } + } else { + memcpy(opline, data, wordcount); + if (refresh_indicator_changed[lineno] != refresh_indicator_changed_prev[lineno]) + refresh_indicator_changed_prev[lineno] = 0; + refresh_indicator_changed[lineno] = 0; + } + } }*/ - function calcsprite() { - sprite_maxx = 0x7fff; - sprite_minx = 0; - if (thisline_decision.diwlastword >= 0) - sprite_maxx = tospritexdiw(thisline_decision.diwlastword); - if (thisline_decision.diwfirstword >= 0) - sprite_minx = tospritexdiw(thisline_decision.diwfirstword); - if (thisline_decision.plfleft >= 0) { - var min = tospritexddf(thisline_decision.plfleft); - var max = tospritexddf(thisline_decision.plfright); - if (min > sprite_minx && min < max) /* min < max = full line ddf */ - sprite_minx = min; - } - } + const PLANE_OFFS1 = MAX_WORDS_PER_LINE_FULL * 1; + const PLANE_OFFS2 = MAX_WORDS_PER_LINE_FULL * 2; + const PLANE_OFFS3 = MAX_WORDS_PER_LINE_FULL * 3; + const PLANE_OFFS4 = MAX_WORDS_PER_LINE_FULL * 4; + const PLANE_OFFS5 = MAX_WORDS_PER_LINE_FULL * 5; + const PLANE_OFFS6 = MAX_WORDS_PER_LINE_FULL * 6; + const PLANE_OFFS7 = MAX_WORDS_PER_LINE_FULL * 7; - function add_sprite(count, num, sprxp, posns, nrs) { - var bestp, j; - for (bestp = 0; bestp < count; bestp++) { - if (posns[bestp] > sprxp) - break; - if (posns[bestp] == sprxp && nrs[bestp] < num) - break; - } - for (j = count; j > bestp; j--) { - posns[j] = posns[j - 1]; - nrs[j] = nrs[j - 1]; - } - posns[j] = sprxp; - nrs[j] = num; - } - - this.decide_sprites = function (hpos) { - if (!DO_SPRITES) return; //FIXME - var nrs = [], posns = []; - var point = hpos * 2 - 3; - //var width = sprite_width; - var sscanmask = 0x100 << sprite_buffer_res; - //var gotdata = 0; - var count, i; + function pfield_doline(lineno) { + var wordcount = dp_for_drawing.plflinelen; + //var pixels = MAX_PIXELS_PER_LINE; + var pixels_l = MAX_PIXELS_PER_LINE >> 2; - if (thisline_decision.plfleft < 0 && !(bplcon3 & 2)) + if (bplplanecnt == 0) { + //for (var i = pixels, j = pixels + wordcount * 32; i < j; i++) pixdata.apixels[i] = 0; + for (var i = pixels_l, j = pixels_l + wordcount * 8; i < j; i++) pixdata.apixels_l[i] = 0; return; + } - if (this.nodraw() || hpos < 0x14 || nr_armed == 0 || point == last_sprite_point) - return; + var data = line_data[lineno]; + var off0 = 0; + var off1 = PLANE_OFFS1; + var off2 = PLANE_OFFS2; + var off3 = PLANE_OFFS3; + var off4 = PLANE_OFFS4; + var off5 = PLANE_OFFS5; + var off6 = PLANE_OFFS6; + var off7 = PLANE_OFFS7; - this.decide_diw(hpos); - this.decide_line(hpos); + while (wordcount-- > 0) { + var b0 = 0, b1 = 0, b2 = 0, b3 = 0, b4 = 0, b5 = 0, b6 = 0, b7 = 0; //u32 - calcsprite(); - - for (i = 0; i < MAX_SPRITES * 2; i++) - nrs[i] = posns[i] = 0; - - count = 0; - for (i = 0; i < MAX_SPRITES; i++) { - var sprxp = (fmode & 0x8000) ? (spr[i].xpos & ~sscanmask) : spr[i].xpos; - var hw_xp = sprxp >> sprite_buffer_res; - - if (!spr[i].armed || spr[i].xpos < 0) - continue; - /*if (!((debug_sprite_mask & magic_sprite_mask) & (1 << i))) - continue;*/ - - if (hw_xp > last_sprite_point && hw_xp <= point) - add_sprite(count++, i, sprxp, posns, nrs); - - if ((fmode & 0x8000) && !(sprxp & sscanmask)) { - sprxp |= sscanmask; - hw_xp = sprxp >> sprite_buffer_res; - if (hw_xp > last_sprite_point && hw_xp <= point) - add_sprite(count++, MAX_SPRITES + i, sprxp, posns, nrs); + switch (bplplanecnt) { + case 8: b0 = data[off7++]; + case 7: b1 = data[off6++]; + case 6: b2 = data[off5++]; + case 5: b3 = data[off4++]; + case 4: b4 = data[off3++]; + case 3: b5 = data[off2++]; + case 2: b6 = data[off1++]; + case 1: b7 = data[off0++]; } - } - for (i = 0; i < count; i++) { - var nr = nrs[i] & (MAX_SPRITES - 1); - //this.record_sprite(next_lineno, nr, posns[i], sprdata[nr], sprdatb[nr], sprctl[nr]); - this.record_sprite(next_lineno, nr, posns[i]); - /* get left and right sprite edge if brdsprt enabled */ - /*#if AUTOSCALE_SPRITES - if (AMIGA.dmaen(DMAF_SPREN) && (bplcon0 & 1) && (bplcon3 & 0x02) && !(bplcon3 & 0x20) && nr > 0) { - var j, jj; - for (j = 0, jj = 0; j < sprite_width; j+= 16, jj++) { - var nx = fromspritexdiw (posns[i] + j); - if (sprdata[nr][jj] || sprdatb[nr][jj]) { - if (diwfirstword_total > nx && nx >= (48 << currprefs.hresolution)) - diwfirstword_total = nx; - if (diwlastword_total < nx + 16 && nx <= (448 << currprefs.hresolution)) - diwlastword_total = nx + 16; - } - } - gotdata = 1; - } - #endif*/ - } - last_sprite_point = point; + var tmp = (b0 ^ (b1 >>> 1)) & 0x55555555; b0 ^= tmp; b1 ^= (tmp << 1); + tmp = (b2 ^ (b3 >>> 1)) & 0x55555555; b2 ^= tmp; b3 ^= (tmp << 1); + tmp = (b4 ^ (b5 >>> 1)) & 0x55555555; b4 ^= tmp; b5 ^= (tmp << 1); + tmp = (b6 ^ (b7 >>> 1)) & 0x55555555; b6 ^= tmp; b7 ^= (tmp << 1); - /* get upper and lower sprite position if brdsprt enabled */ - /*#if AUTOSCALE_SPRITES - if (gotdata) { - if (vpos < first_planes_vpos) - first_planes_vpos = vpos; - if (vpos < plffirstline_total) - plffirstline_total = vpos; - if (vpos > last_planes_vpos) - last_planes_vpos = vpos; - if (vpos > plflastline_total) - plflastline_total = vpos; - } - #endif*/ - }; - - this.cursorsprite = function () { - if (!AMIGA.dmaen(DMAF_SPREN) || first_planes_vpos == 0) - return; - sprite_0 = spr[0].pt; - sprite_0_height = spr[0].vstop - spr[0].vstart; - sprite_0_colors[0] = 0; - sprite_0_doubled = 0; - if (sprres == 0) - sprite_0_doubled = 1; - if (AMIGA.config.chipset.mask & CSMASK_AGA) { - var sbasecol = ((bplcon4 >> 4) & 15) << 4; - sprite_0_colors[1] = current_colors.color_regs_aga[sbasecol + 1]; - sprite_0_colors[2] = current_colors.color_regs_aga[sbasecol + 2]; - sprite_0_colors[3] = current_colors.color_regs_aga[sbasecol + 3]; - } else { - sprite_0_colors[1] = xcolors[current_colors.color_regs_ecs[17]]; - sprite_0_colors[2] = xcolors[current_colors.color_regs_ecs[18]]; - sprite_0_colors[3] = xcolors[current_colors.color_regs_ecs[19]]; - } - sprite_0_width = sprite_width; - /*if (currprefs.input_tablet && currprefs.input_magic_mouse) { - if (currprefs.input_magic_mouse_cursor == MAGICMOUSE_HOST_ONLY && mousehack_alive ()) - magic_sprite_mask &= ~1; - else - magic_sprite_mask |= 1; - }*/ - }; - - function sprite_fetch(s, dma, hpos, cycle, mode) { - var data = AMIGA.custom.last_value; - if (dma) { - //data = AMIGA.mem.load16_chip(s.pt); - data = AMIGA.custom.last_value = AMIGA.mem.chip.data[s.pt >>> 1]; - } - s.pt += 2; - return data; - } - function sprite_fetch2(s, hpos, cycle, mode) { - //var data = AMIGA.mem.load16_chip(s.pt); - var data = AMIGA.custom.last_value = AMIGA.mem.chip.data[s.pt >>> 1]; - s.pt += 2; - return data; - } + tmp = (b0 ^ (b2 >>> 2)) & 0x33333333; b0 ^= tmp; b2 ^= (tmp << 2); + tmp = (b1 ^ (b3 >>> 2)) & 0x33333333; b1 ^= tmp; b3 ^= (tmp << 2); + tmp = (b4 ^ (b6 >>> 2)) & 0x33333333; b4 ^= tmp; b6 ^= (tmp << 2); + tmp = (b5 ^ (b7 >>> 2)) & 0x33333333; b5 ^= tmp; b7 ^= (tmp << 2); - this.do_sprites_1 = function (num, cycle, hpos) { - var s = spr[num]; - var isdma = AMIGA.dmaen(DMAF_SPREN) || ((num & 1) && spr[num & ~1].dmacycle); + tmp = (b0 ^ (b4 >>> 4)) & 0x0f0f0f0f; b0 ^= tmp; b4 ^= (tmp << 4); + tmp = (b1 ^ (b5 >>> 4)) & 0x0f0f0f0f; b1 ^= tmp; b5 ^= (tmp << 4); + tmp = (b2 ^ (b6 >>> 4)) & 0x0f0f0f0f; b2 ^= tmp; b6 ^= (tmp << 4); + tmp = (b3 ^ (b7 >>> 4)) & 0x0f0f0f0f; b3 ^= tmp; b7 ^= (tmp << 4); - if (isdma && this.vpos == sprite_vblank_endline) - spr_arm(num, 0); - /*#ifdef AGA - if (isdma && s.dblscan && (fmode & 0x8000) && (this.vpos & 1) != (s.vstart & 1) && s.dmastate) { - spr_arm(num, 1); - return; - } - #endif*/ + tmp = (b0 ^ (b1 >>> 8)) & 0x00ff00ff; b0 ^= tmp; b1 ^= (tmp << 8); + tmp = (b2 ^ (b3 >>> 8)) & 0x00ff00ff; b2 ^= tmp; b3 ^= (tmp << 8); + tmp = (b4 ^ (b5 >>> 8)) & 0x00ff00ff; b4 ^= tmp; b5 ^= (tmp << 8); + tmp = (b6 ^ (b7 >>> 8)) & 0x00ff00ff; b6 ^= tmp; b7 ^= (tmp << 8); - //if (this.vpos >= SPRITE_DEBUG_MINY && this.vpos <= SPRITE_DEBUG_MAXY) BUG.info('%d:%d:slot%d:%d', this.vpos, hpos, num, cycle); + tmp = (b0 ^ (b2 >>> 16)) & 0x0000ffff; b0 ^= tmp; b2 ^= (tmp << 16); + tmp = (b1 ^ (b3 >>> 16)) & 0x0000ffff; b1 ^= tmp; b3 ^= (tmp << 16); + tmp = (b4 ^ (b6 >>> 16)) & 0x0000ffff; b4 ^= tmp; b6 ^= (tmp << 16); + tmp = (b5 ^ (b7 >>> 16)) & 0x0000ffff; b5 ^= tmp; b7 ^= (tmp << 16); - if (this.vpos == s.vstart) { - //if (!s.dmastate && this.vpos >= SPRITE_DEBUG_MINY && this.vpos <= SPRITE_DEBUG_MAXY) BUG.info('%d:%d:SPR%d START', this.vpos, hpos, num); - s.dmastate = 1; - if (num == 0 && cycle == 0) - this.cursorsprite(); - } - if (this.vpos == s.vstop || this.vpos == sprite_vblank_endline) { - //if (s.dmastate && this.vpos >= SPRITE_DEBUG_MINY && this.vpos <= SPRITE_DEBUG_MAXY) BUG.info('%d:%d:SPR%d STOP', this.vpos, hpos, num); - s.dmastate = 0; - /*#if 0 - // roots 2.0 flower zoomer bottom part missing if this enabled - if (this.vpos == s.vstop) { - spr_arm (num, 0); - //return; - } - #endif*/ - } + /*pixdata.apixels[pixels ] = b0 >>> 24; + pixdata.apixels[pixels + 1] = b0 >>> 16; + pixdata.apixels[pixels + 2] = b0 >>> 8; + pixdata.apixels[pixels + 3] = b0; + pixdata.apixels[pixels + 4] = b4 >>> 24; + pixdata.apixels[pixels + 5] = b4 >>> 16; + pixdata.apixels[pixels + 6] = b4 >>> 8; + pixdata.apixels[pixels + 7] = b4; + pixdata.apixels[pixels + 8] = b1 >>> 24; + pixdata.apixels[pixels + 9] = b1 >>> 16; + pixdata.apixels[pixels + 10] = b1 >>> 8; + pixdata.apixels[pixels + 11] = b1; + pixdata.apixels[pixels + 12] = b5 >>> 24; + pixdata.apixels[pixels + 13] = b5 >>> 16; + pixdata.apixels[pixels + 14] = b5 >>> 8; + pixdata.apixels[pixels + 15] = b5; + pixdata.apixels[pixels + 16] = b2 >>> 24; + pixdata.apixels[pixels + 17] = b2 >>> 16; + pixdata.apixels[pixels + 18] = b2 >>> 8; + pixdata.apixels[pixels + 19] = b2; + pixdata.apixels[pixels + 20] = b6 >>> 24; + pixdata.apixels[pixels + 21] = b6 >>> 16; + pixdata.apixels[pixels + 22] = b6 >>> 8; + pixdata.apixels[pixels + 23] = b6; + pixdata.apixels[pixels + 24] = b3 >>> 24; + pixdata.apixels[pixels + 25] = b3 >>> 16; + pixdata.apixels[pixels + 26] = b3 >>> 8; + pixdata.apixels[pixels + 27] = b3; + pixdata.apixels[pixels + 28] = b7 >>> 24; + pixdata.apixels[pixels + 29] = b7 >>> 16; + pixdata.apixels[pixels + 30] = b7 >>> 8; + pixdata.apixels[pixels + 31] = b7; + pixels += 32; + */ - if (!isdma) - return; - if (cycle && !s.dmacycle) - return; - /* Superfrog intro flashing bee fix */ - - var dma = hpos < plfstrt_sprite || diwstate != DIW_WAITING_STOP; - var posctl = 0; - - if (this.vpos == s.vstop || this.vpos == sprite_vblank_endline) { - s.dmastate = 0; - posctl = 1; - if (dma) { - var data = sprite_fetch(s, dma, hpos, cycle, 0); - switch (sprite_width) { - case 64: - sprite_fetch2(s, hpos, cycle, 0); - sprite_fetch2(s, hpos, cycle, 0); - break; - case 32: - sprite_fetch2(s, hpos, cycle, 0); - break; - } - //BUG.info('%d:%d: %04X=%04X', this.vpos, hpos, 0x140 + cycle * 2 + num * 8, data); - if (cycle == 0) { - this.SPRxPOS_1(data, num, hpos); - s.dmacycle = 1; - } else { - this.SPRxCTL_1(data, num, hpos); - s.dmastate = 0; - this.sprstartstop(s); - } - } - //if (this.vpos >= SPRITE_DEBUG_MINY && this.vpos <= SPRITE_DEBUG_MAXY) BUG.info('%d:%d:dma:P=%06X '), this.vpos, hpos, s.pt); - } - if (s.dmastate && !posctl && dma) { - var data = sprite_fetch(s, dma, hpos, cycle, 1); - //if (this.vpos >= SPRITE_DEBUG_MINY && this.vpos <= SPRITE_DEBUG_MAXY) BUG.info('%d:%d:dma:P=%06X '), this.vpos, hpos, s.pt); - if (cycle == 0) { - this.SPRxDATA_1(data, num, hpos); - s.dmacycle = 1; + if (SAEC_LITTLE_ENDIAN) { //byte-swap + pixdata.apixels_l[pixels_l ] = ((b0 & 0x000000ff) << 24) | ((b0 & 0x0000ff00) << 8) | ((b0 & 0x00ff0000) >>> 8) | ((b0 & 0xff000000) >>> 24); + pixdata.apixels_l[pixels_l + 1] = ((b4 & 0x000000ff) << 24) | ((b4 & 0x0000ff00) << 8) | ((b4 & 0x00ff0000) >>> 8) | ((b4 & 0xff000000) >>> 24); + pixdata.apixels_l[pixels_l + 2] = ((b1 & 0x000000ff) << 24) | ((b1 & 0x0000ff00) << 8) | ((b1 & 0x00ff0000) >>> 8) | ((b1 & 0xff000000) >>> 24); + pixdata.apixels_l[pixels_l + 3] = ((b5 & 0x000000ff) << 24) | ((b5 & 0x0000ff00) << 8) | ((b5 & 0x00ff0000) >>> 8) | ((b5 & 0xff000000) >>> 24); + pixdata.apixels_l[pixels_l + 4] = ((b2 & 0x000000ff) << 24) | ((b2 & 0x0000ff00) << 8) | ((b2 & 0x00ff0000) >>> 8) | ((b2 & 0xff000000) >>> 24); + pixdata.apixels_l[pixels_l + 5] = ((b6 & 0x000000ff) << 24) | ((b6 & 0x0000ff00) << 8) | ((b6 & 0x00ff0000) >>> 8) | ((b6 & 0xff000000) >>> 24); + pixdata.apixels_l[pixels_l + 6] = ((b3 & 0x000000ff) << 24) | ((b3 & 0x0000ff00) << 8) | ((b3 & 0x00ff0000) >>> 8) | ((b3 & 0xff000000) >>> 24); + pixdata.apixels_l[pixels_l + 7] = ((b7 & 0x000000ff) << 24) | ((b7 & 0x0000ff00) << 8) | ((b7 & 0x00ff0000) >>> 8) | ((b7 & 0xff000000) >>> 24); } else { - this.SPRxDATB_1(data, num, hpos); - spr_arm(num, 1); + pixdata.apixels_l[pixels_l ] = b0; + pixdata.apixels_l[pixels_l + 1] = b4; + pixdata.apixels_l[pixels_l + 2] = b1; + pixdata.apixels_l[pixels_l + 3] = b5; + pixdata.apixels_l[pixels_l + 4] = b2; + pixdata.apixels_l[pixels_l + 5] = b6; + pixdata.apixels_l[pixels_l + 6] = b3; + pixdata.apixels_l[pixels_l + 7] = b7; } - /*#ifdef AGA - switch (sprite_width) { - case 64: { - var data32 = sprite_fetch2 (s, hpos, cycle, 1); - var data641 = sprite_fetch2 (s, hpos, cycle, 1); - var data642 = sprite_fetch2 (s, hpos, cycle, 1); - if (dma) { - if (cycle == 0) { - sprdata[num][3] = data642; - sprdata[num][2] = data641; - sprdata[num][1] = data32; - } else { - sprdatb[num][3] = data642; - sprdatb[num][2] = data641; - sprdatb[num][1] = data32; - } - } - } - break; - case 32: { - var data32 = sprite_fetch2 (s, hpos, cycle, 1); - if (dma) { - if (cycle == 0) - sprdata[num][1] = data32; - else - sprdatb[num][1] = data32; - } - } - break; - } - #endif*/ + pixels_l += 8; } - }; - this.do_sprites = function (hpos) { - if (!DO_SPRITES) return; //FIXME - if (this.vpos < sprite_vblank_endline) - return; + if (refresh_indicator_buffer !== null && refresh_indicator_height > lineno) { + wordcount = dp_for_drawing.plflinelen; - if (this.doflickerfix() && interlace_seen && (next_lineno & 1)) - return; + //uae_u8 *opline = refresh_indicator_buffer + lineno * MAX_PIXELS_PER_LINE * 2; + //wordcount *= 32; - if (!CUSTOM_SIMPLE) { - var minspr = last_sprite_hpos + 1; - var maxspr = hpos; + var opline = new Uint32Array(refresh_indicator_buffer, lineno * MAX_PIXELS_PER_LINE * 2); + wordcount *= 8; // * 32 / 4 - if (minspr >= maxspr || last_sprite_hpos == hpos) - return; - - if (maxspr >= SPR0_HPOS + MAX_SPRITES * 4) - maxspr = SPR0_HPOS + MAX_SPRITES * 4 - 1; - if (minspr < SPR0_HPOS) - minspr = SPR0_HPOS; - - if (minspr == maxspr) - return; - - for (var i = minspr; i <= maxspr; i++) { - var cycle = -1; - var num = (i - SPR0_HPOS) >> 2; - switch ((i - SPR0_HPOS) & 3) { - case 0: - cycle = 0; - spr[num].dmacycle = 0; - break; - case 2: - cycle = 1; - break; - } - if (cycle >= 0) { - spr[num].ptxhpos = MAXHPOS; - this.do_sprites_1(num, cycle, i); + var same = true; + for (var i = 0; i < wordcount; i++) { + if (opline[i] != data[i]) { + same = false; + break; } } - last_sprite_hpos = hpos; + //if (!memcmp(opline, data, wordcount)) { + if (same) { + if (refresh_indicator_changed[lineno] != 0xff) { + refresh_indicator_changed[lineno]++; + if (refresh_indicator_changed[lineno] > refresh_indicator_changed_prev[lineno]) { + refresh_indicator_changed_prev[lineno] = refresh_indicator_changed[lineno]; + } + } + } else { + //memcpy(opline, data, wordcount); + for (i = 0; i < wordcount; i++) + opline[i] = data[i]; + + if (refresh_indicator_changed[lineno] != refresh_indicator_changed_prev[lineno]) + refresh_indicator_changed_prev[lineno] = 0; + refresh_indicator_changed[lineno] = 0; + } + } + } + + + var oldbufmem = null; //u8 * + var oldheight = 0, oldpitch = 0; //int + var oldgenlock = false; //bool + + function init_row_map() { + //static uae_u8 *oldbufmem; + //static int oldheight, oldpitch; + //static bool oldgenlock; + var vb = gfxvidinfo.drawbuffer; + var bpp16 = vb.pixbytes == 2; //OWN + var i, j; + + if (vb.height_allocated > SAEC_Video_MAX_UAE_HEIGHT) { + SAEF_fatal(SAEE_Internal, "playfield.init_row_map() resolution too high, aborting..."); + //abort(); + } + if (row_map === null) { + //row_map = xmalloc(uae_u8*, SAEC_Video_MAX_UAE_HEIGHT + 1); + //row_map_genlock = xmalloc(uae_u8*, SAEC_Video_MAX_UAE_HEIGHT + 1); + row_map = new Array(SAEC_Video_MAX_UAE_HEIGHT + 1); + //row_map_genlock = new Array(SAEC_Video_MAX_UAE_HEIGHT + 1); + } + + if (oldbufmem !== null && oldbufmem === vb.bufmem && + oldheight == vb.height_allocated && + oldpitch == vb.rowbytes && + oldgenlock == init_genlock_data + ) return; + + /*xfree(row_map_genlock_buffer); + row_map_genlock_buffer = null; + if (init_genlock_data) + row_map_genlock_buffer = xcalloc(uae_u8, vb.width_allocated * (vb.height_allocated + 2));*/ + + //xfree(row_map_color_burst_buffer); + row_map_color_burst_buffer = null; + /*if (currprefs.cs_color_burst) { + //row_map_color_burst_buffer = xcalloc(uae_u8, vb.height_allocated + 2); + row_map_color_burst_buffer = new Uint8Array(vb.height_allocated + 2); + }*/ + + j = oldheight == 0 ? SAEC_Video_MAX_UAE_HEIGHT : oldheight; + for (i = vb.height_allocated; i < SAEC_Video_MAX_UAE_HEIGHT + 1 && i < j + 1; i++) { + //row_map[i] = row_tmp; + if (bpp16) + row_map[i] = new Uint16Array(row_tmp); + else + row_map[i] = new Uint32Array(row_tmp); + //row_map_genlock[i] = row_tmp; + } + if (vb.bufmem !== null) { + var maxbytes = vb.bufmem.byteLength; + //try { + for (i = 0, j = vb.bufmem_pos; i < vb.height_allocated; i++, j += vb.rowbytes) { + //row_map[i] = vb.bufmem + j; //ATT + + if (j + vb.rowbytes <= maxbytes) { + if (bpp16) + row_map[i] = new Uint16Array(vb.bufmem, j, vb.rowbytes >> 1); + else + row_map[i] = new Uint32Array(vb.bufmem, j, vb.rowbytes >> 2); + } else { + if (bpp16) + row_map[i] = new Uint16Array(row_tmp); + else + row_map[i] = new Uint32Array(row_tmp); + } + /*if (init_genlock_data) + row_map_genlock[i] = row_map_genlock_buffer + vb.width_allocated * (i + 1); //ATT + + else + row_map_genlock[i] = null;*/ + } + /*} catch(e) { + throw e; + }*/ + } + + oldbufmem = vb.bufmem; + oldheight = vb.height_allocated; + oldpitch = vb.rowbytes; + oldgenlock = init_genlock_data; + } + SAER_Playfield_init_row_map = init_row_map; + + function init_aspect_maps() { + var i, maxl, h; + + h = gfxvidinfo.drawbuffer.height_allocated; + + if (h == 0) /* Do nothing if the gfx driver hasn"t initialized the screen yet */ + return; + + linedbld = linedbl = SAEV_config.video.vresolution; + if (doublescan > 0 && interlace_seen <= 0) { + linedbl = 0; + linedbld = 1; + } + + //if (native2amiga_line_map) xfree (native2amiga_line_map); + //if (amiga2aspect_line_map) xfree (amiga2aspect_line_map); + /* At least for this array the +1 is necessary. */ + //amiga2aspect_line_map = xmalloc (int, (MAXVPOS + 1) * 2 + 1); + //native2amiga_line_map = xmalloc (int, h); + amiga2aspect_line_map = new Array((MAXVPOS + 1) * 2 + 1); + native2amiga_line_map = new Array(h); + + maxl = (MAXVPOS + 1) << linedbld; + min_ypos_for_screen = minfirstline << linedbl; + max_drawn_amiga_line = -1; + for (i = 0; i < maxl; i++) { + var v = i - min_ypos_for_screen; + if (v >= h && max_drawn_amiga_line < 0) + max_drawn_amiga_line = v; + if (i < min_ypos_for_screen || v >= h) + v = -1; + amiga2aspect_line_map[i] = v; + } + if (max_drawn_amiga_line < 0) + max_drawn_amiga_line = maxl - min_ypos_for_screen; + + for (i = 0; i < h; i++) + native2amiga_line_map[i] = -1; + + for (i = maxl - 1; i >= min_ypos_for_screen; i--) { + if (amiga2aspect_line_map[i] == -1) + continue; + for (var j = amiga2aspect_line_map[i]; j < h && native2amiga_line_map[j] == -1; j++) + native2amiga_line_map[j] = i >> linedbl; + } + + gfxvidinfo.xchange = 1 << (RES_MAX - SAEV_config.video.hresolution); + gfxvidinfo.ychange = linedbl ? 1 : 2; + + visible_left_start = 0; + visible_right_stop = MAX_STOP; + visible_top_start = 0; + visible_bottom_stop = MAX_STOP; + set_blanking_limits(); + } + + /* A raster line has been built in the graphics buffer. Tell the graphics code to do anything necessary to display it. */ + /* OWN flush_line() and flush_block() is not used + function do_flush_line(vb, lineno) { //do_flush_line_1() + if (lineno < first_drawn_line) + first_drawn_line = lineno; + if (lineno > last_drawn_line) + last_drawn_line = lineno; + + if (gfxvidinfo.maxblocklines == 0) { + SAER.video.flush_line(vb, lineno); } else { - for (var i = 0; i < MAX_SPRITES * 2; i++) { - spr[i >> 1].dmacycle = 1; - this.do_sprites_1(i >> 1, i & 1, 0); + if ((last_block_line + 2) < lineno) { + if (first_block_line != NO_BLOCK) + SAER.video.flush_block(vb, first_block_line, last_block_line); + first_block_line = lineno; + } + last_block_line = lineno; + if (last_block_line - first_block_line >= gfxvidinfo.maxblocklines) { + SAER.video.flush_block(vb, first_block_line, last_block_line); + first_block_line = last_block_line = NO_BLOCK; } } - }; + }*/ + /*function do_flush_line(vb, lineno) { //OPT inline ok + if (vb) do_flush_line_1(vb, lineno); + }*/ - function expand_sprres(con0, con3) { - switch ((con3 >> 6) & 3) { - case 0: { - if ((AMIGA.config.chipset.mask & CSMASK_ECS_DENISE) && GET_RES_DENISE(con0) == RES_SUPERHIRES) - return RES_HIRES; - else - return RES_LORES; - } -/*#ifdef AGA - case 1: - return RES_LORES; - case 2: - return RES_HIRES; - case 3: - return RES_SUPERHIRES; -#endif*/ - default: - return RES_LORES; - } - } - - function spr_arm(num, state) { - switch (state) { - case 0: - nr_armed -= spr[num].armed; - spr[num].armed = 0; - break; - default: - nr_armed += 1 - spr[num].armed; - spr[num].armed = 1; - break; - } - } - - this.sprstartstop = function (s) { - if (this.vpos == s.vstart) - s.dmastate = 1; - if (this.vpos == s.vstop) - s.dmastate = 0; - }; - - this.CLXCON = function (v) { - clxcon = v; - clxcon_bpl_enable = (v >> 6) & 63; - clxcon_bpl_match = v & 63; - }; - - this.CLXCON2 = function (v) { - if (!(AMIGA.config.chipset.mask & CSMASK_AGA)) + /* One drawing frame has been finished. Tell the graphics code about it. + * Note that the actual flush_screen() call is a no-op for all reasonable systems. */ + function do_flush_screen(vb, start, stop) { + /* TODO: this flush operation is executed outside locked state! Should be corrected. (sjo 26.9.99) */ + if (vb !== gfxvidinfo.outbuffer) return; - clxcon2 = v; - clxcon_bpl_enable |= v & (0x40 | 0x80); - clxcon_bpl_match |= (v & (0x01 | 0x02)) << 6; - }; - this.CLXDAT = function () { - var v = clxdat | 0x8000; - clxdat = 0; - return v; - }; - - this.SPRxCTLPOS = function (num) { - var sprxp; - var s = spr[num]; + /* OWN flush_block() is not used + if (gfxvidinfo.maxblocklines != 0 && first_block_line != NO_BLOCK) + SAER.video.flush_block(vb, first_block_line, last_block_line); */ - this.sprstartstop(s); - sprxp = (sprpos[num] & 0xFF) * 2 + (sprctl[num] & 1); - sprxp <<= sprite_buffer_res; - /*#ifdef AGA - if (AMIGA.config.chipset.mask & CSMASK_AGA) { - sprxp |= ((sprctl[num] >> 3) & 3) >> (RES_MAX - sprite_buffer_res); - s.dblscan = sprpos[num] & 0x80; - } else - #endif*/ - if (AMIGA.config.chipset.mask & CSMASK_ECS_DENISE) { - sprxp |= ((sprctl[num] >> 3) & 2) >> (RES_MAX - sprite_buffer_res); + SAER.video.unlockscr(vb); + + /* OWN flush_screen() is not used + if (start <= stop) + SAER.video.flush_screen(vb, start, stop); + else if (isvsync_chipset()) + SAER.video.flush_screen(vb, 0, 0); //vsync mode + */ + } + + /* We only save hardware registers during the hardware frame. Now, when + * drawing the frame, we expand the data into a slightly more useful form. */ + function pfield_expand_dp_bplcon() { + var pfield_mode_changed = false; + + bplres = dp_for_drawing.bplres; + bplplanecnt = dp_for_drawing.nr_planes; + bplham = dp_for_drawing.ham_seen; + bplehb = dp_for_drawing.ehb_seen; + if ((SAEV_config.chipset.mask & SAEC_Config_Chipset_Mask_ECS_DENISE) != 0 && (dp_for_drawing.bplcon2 & 0x0200) != 0) + bplehb = false; + issprites = dip_for_drawing.nr_sprites > 0; + bplcolorburst = (dp_for_drawing.bplcon0 & 0x200) != 0; + if (!bplcolorburst) + bplcolorburst_field = false; + //#ifdef ECS_DENISE + var oecsshres = ecsshres; + ecsshres = bplres == SAEC_Config_Video_HResolution_SuperHiRes && (SAEV_config.chipset.mask & SAEC_Config_Chipset_Mask_ECS_DENISE) != 0 && (SAEV_config.chipset.mask & SAEC_Config_Chipset_Mask_AGA) == 0; + pfield_mode_changed = oecsshres != ecsshres; + //#endif + + plf1pri = dp_for_drawing.bplcon2 & 7; + plf2pri = (dp_for_drawing.bplcon2 >> 3) & 7; + plf_sprite_mask = 0xFFFF0000 << (4 * plf2pri); + plf_sprite_mask |= (0x0000FFFF << (4 * plf1pri)) & 0xFFFF; + plf_sprite_mask >>>= 0; //OWN + bpldualpf = (dp_for_drawing.bplcon0 & 0x400) == 0x400; + bpldualpfpri = (dp_for_drawing.bplcon2 & 0x40) == 0x40; + + //#ifdef AGA + // BYPASS: HAM and EHB select bits are ignored + if (bplbypass != ((dp_for_drawing.bplcon0 & 0x20) != 0)) { + bpland = 0xff; + bplbypass = (dp_for_drawing.bplcon0 & 0x20) != 0; + pfield_mode_changed = true; } - s.xpos = sprxp; - s.vstart = (sprpos[num] >> 8) | ((sprctl[num] << 6) & 0x100); - s.vstop = (sprctl[num] >> 8) | ((sprctl[num] << 7) & 0x100); - if (AMIGA.config.chipset.mask & CSMASK_ECS_AGNUS) { - s.vstart |= (sprctl[num] << 3) & 0x200; - s.vstop |= (sprctl[num] << 4) & 0x200; + if (bplbypass) { + if (bplham && bplplanecnt == 6) + bpland = 0x0f; + if (bplham && bplplanecnt == 8) + bpland = 0xfc; + bplham = false; + if (bplehb) + bpland = 31; + bplehb = false; } - this.sprstartstop(s); - }; - - this.SPRxCTL_1 = function (v, num, hpos) { - //struct sprite *s = &spr[num]; - sprctl[num] = v; - spr_arm(num, 0); - this.SPRxCTLPOS(num); - /*if (this.vpos >= SPRITE_DEBUG_MINY && this.vpos <= SPRITE_DEBUG_MAXY) { - BUG.info('%d:%d:SPR%dCTL %04X P=%06X VSTRT=%d VSTOP=%d HSTRT=%d D=%d A=%d CP=%x PC=%x', this.vpos, hpos, num, v, s->pt, s->vstart, s->vstop, s->xpos, spr[num].dmastate, spr[num].armed, cop_state.ip, M68K_GETPC); - }*/ - }; - - this.SPRxPOS_1 = function (v, num, hpos) { - //struct sprite *s = &spr[num]; - sprpos[num] = v; - this.SPRxCTLPOS(num); - /*if (this.vpos >= SPRITE_DEBUG_MINY && this.vpos <= SPRITE_DEBUG_MAXY) { - BUG.info('%d:%d:SPR%dPOS %04X P=%06X VSTRT=%d VSTOP=%d HSTRT=%d D=%d A=%d CP=%x PC=%x', this.vpos, hpos, num, v, s->pt, s->vstart, s->vstop, s->xpos, spr[num].dmastate, spr[num].armed, cop_state.ip, M68K_GETPC); - }*/ - }; - - this.SPRxDATA_1 = function (v, num, hpos) { - sprdata[num][0] = v; - /*#ifdef AGA - sprdata[num][1] = v; - sprdata[num][2] = v; - sprdata[num][3] = v; - #endif*/ - spr_arm(num, 1); - /*if (this.vpos >= SPRITE_DEBUG_MINY && this.vpos <= SPRITE_DEBUG_MAXY) { - BUG.info('%d:%d:SPR%dDATA %04X P=%06X D=%d A=%d PC=%x', this.vpos, hpos, num, v, spr[num].pt, spr[num].dmastate, spr[num].armed, M68K_GETPC); - }*/ - }; - - this.SPRxDATB_1 = function (v, num, hpos) { - sprdatb[num][0] = v; - /*#ifdef AGA - sprdatb[num][1] = v; - sprdatb[num][2] = v; - sprdatb[num][3] = v; - #endif*/ - /*if (this.vpos >= SPRITE_DEBUG_MINY && this.vpos <= SPRITE_DEBUG_MAXY) { - BUG.info('%d:%d:SPR%dDATB %04X P=%06X D=%d A=%d PC=%x', this.vpos, hpos, num, v, spr[num].pt, spr[num].dmastate, spr[num].armed, M68K_GETPC); - }*/ - }; - - this.SPRxDATA = function (hpos, v, num) { - this.decide_sprites(hpos); - this.SPRxDATA_1(v, num, hpos); - }; - this.SPRxDATB = function (hpos, v, num) { - this.decide_sprites(hpos); - this.SPRxDATB_1(v, num, hpos); - }; - this.SPRxCTL = function (hpos, v, num) { - this.decide_sprites(hpos); - this.SPRxCTL_1(v, num, hpos); - }; - this.SPRxPOS = function (hpos, v, num) { - this.decide_sprites(hpos); - this.SPRxPOS_1(v, num, hpos); - }; - - this.SPRxPTH = function (hpos, v, num) { - this.decide_sprites(hpos); - if (hpos - 1 != spr[num].ptxhpos) { - spr[num].pt = ((v << 16) | (spr[num].pt & 0xffff)) >>> 0; + bpldualpf2of = (dp_for_drawing.bplcon3 >> 10) & 7; + sbasecol[0] = ((dp_for_drawing.bplcon4 >> 4) & 15) << 4; + sbasecol[1] = ((dp_for_drawing.bplcon4 >> 0) & 15) << 4; + bplxor = dp_for_drawing.bplcon4 >> 8; + var sh = (colors_for_drawing.extra >> CE_SHRES_DELAY) & 3; + if (sh != bpldelay_sh) { + bpldelay_sh = sh; + pfield_mode_changed = true; } - //if (this.vpos >= SPRITE_DEBUG_MINY && this.vpos <= SPRITE_DEBUG_MAXY) BUG.info('%d:%d:SPR%dPTH %06X', this.vpos, hpos, num, spr[num].pt); - }; - this.SPRxPTL = function (hpos, v, num) { - this.decide_sprites(hpos); - if (hpos - 1 != spr[num].ptxhpos) { - spr[num].pt = ((spr[num].pt & 0xffff0000) | (v & 0xfffe)) >>> 0; + //#endif + ecs_genlock_features_active = (SAEV_config.chipset.mask & SAEC_Config_Chipset_Mask_ECS_DENISE) && ((dp_for_drawing.bplcon2 & 0x0c00) || ce_is_borderntrans(colors_for_drawing.extra)) ? 1 : 0; + if (ecs_genlock_features_active) { + ecs_genlock_features_colorkey = false; + ecs_genlock_features_mask = 0; + if (dp_for_drawing.bplcon3 & 0x0800) { + ecs_genlock_features_mask = 1 << ((dp_for_drawing.bplcon2 >> 12) & 7); + } + if (dp_for_drawing.bplcon3 & 0x0400) { + ecs_genlock_features_colorkey = true; + } } - //if (this.vpos >= SPRITE_DEBUG_MINY && this.vpos <= SPRITE_DEBUG_MAXY) BUG.info('%d:%d:SPR%dPTL %06X', this.vpos, hpos, num, spr[num].pt); + if (pfield_mode_changed) + pfield_set_linetoscr(); + } + + function isham(bplcon0) { + var p = GET_PLANES(bplcon0); + if (!(bplcon0 & 0x800)) + return 0; + if (SAEV_config.chipset.mask & SAEC_Config_Chipset_Mask_AGA) { + // AGA only has 6 or 8 plane HAM + if (p == 6 || p == 8) + return 1; + } else { + // OCS/ECS also supports 5 plane HAM + if (GET_RES_DENISE(bplcon0) > 0) + return 0; + if (p >= 5) + return 1; + } + return 0; + } + + function pfield_expand_dp_bplconx(regno, v) { + if (regno == 0xffff) { + hposblank = 1; + return; + } + regno -= 0x1000; + switch (regno) { + case 0x100: // BPLCON0 + dp_for_drawing.bplcon0 = v; + dp_for_drawing.bplres = GET_RES_DENISE(v); + dp_for_drawing.nr_planes = GET_PLANES(v); + dp_for_drawing.ham_seen = isham(v); + break; + case 0x104: // BPLCON2 + dp_for_drawing.bplcon2 = v; + break; + //#ifdef ECS_DENISE + case 0x106: // BPLCON3 + dp_for_drawing.bplcon3 = v; + break; + //#endif + //#ifdef AGA + case 0x10c: // BPLCON4 + dp_for_drawing.bplcon4 = v; + break; + //#endif + } + pfield_expand_dp_bplcon(); + set_res_shift(lores_shift - bplres); + } + + var drawing_color_matches = 0; //int + //static enum { + const color_match_acolors = 0; + const color_match_full = 1; + //} color_match_type; + var color_match_type = 0; + + /* Set up colors_for_drawing to the state at the beginning of the currently drawn line. + Try to avoid copying color tables around whenever possible. */ + function adjust_drawing_colors(ctable, need_full) { + if (drawing_color_matches != ctable || need_full < 0) { + if (need_full) { + color_reg_cpy(colors_for_drawing, curr_color_tables[ctable]); + color_match_type = color_match_full; + } else { + for (var i = 0; i < colors_for_drawing.acolors.length; i++) + colors_for_drawing.acolors[i] = curr_color_tables[ctable].acolors[i]; + + colors_for_drawing.extra = curr_color_tables[ctable].extra; + color_match_type = color_match_acolors; + } + drawing_color_matches = ctable; + } else if (need_full && color_match_type != color_match_full) { + color_reg_cpy(colors_for_drawing, curr_color_tables[ctable]); + color_match_type = color_match_full; + } + } + + function playfield_hard_way(worker_pfield, first, last) { + if (first < real_playfield_start) { + var next = last < real_playfield_start ? last : real_playfield_start; + var diff = next - first; + pfield_do_linetoscr_bordersprite_aga(first, next, false); + if (res_shift >= 0) + diff >>= res_shift; + else + diff <<= res_shift; + src_pixel += diff; + first = next; + } + worker_pfield(first, last < real_playfield_end ? last : real_playfield_end, false); + if (last > real_playfield_end) + pfield_do_linetoscr_bordersprite_aga(real_playfield_end, last, false); + } + + function do_color_changes(worker_border, worker_pfield, vp) { + var lastpos = visible_left_border; + var endpos = visible_left_border + gfxvidinfo.drawbuffer.inwidth; + + for (var i = dip_for_drawing.first_color_change; i <= dip_for_drawing.last_color_change; i++) { + var regno = curr_color_changes[i].regno; + var value = curr_color_changes[i].value; + var nextpos, nextpos_in_range; + + if (i == dip_for_drawing.last_color_change) + nextpos = endpos; + else + nextpos = coord_hw_to_window_x(curr_color_changes[i].linepos); + + nextpos_in_range = nextpos; + if (nextpos > endpos) + nextpos_in_range = endpos; + + // left hblank (left edge to hblank end) + if (nextpos_in_range > lastpos && lastpos < hblank_left_start) { + var t = nextpos_in_range <= hblank_left_start ? nextpos_in_range : hblank_left_start; + worker_border(lastpos, t, true); + lastpos = t; + } + // left border (hblank end to playfield start) + if (nextpos_in_range > lastpos && lastpos < playfield_start) { + var t = nextpos_in_range <= playfield_start ? nextpos_in_range : playfield_start; + worker_border(lastpos, t, false); + lastpos = t; + } + // playfield + if (nextpos_in_range > lastpos && lastpos >= playfield_start && lastpos < playfield_end) { + var t = nextpos_in_range <= playfield_end ? nextpos_in_range : playfield_end; + if (plf2pri > 5 && !(SAEV_config.chipset.mask & SAEC_Config_Chipset_Mask_AGA)) + weird_bitplane_fix(lastpos, t); + if (bplxor && may_require_hard_way && worker_pfield !== pfield_do_linetoscr_bordersprite_aga) + playfield_hard_way(worker_pfield, lastpos, t); + else + worker_pfield(lastpos, t, false); + + lastpos = t; + } + // right border (playfield end to hblank start) + if (nextpos_in_range > lastpos && lastpos >= playfield_end) { + var t = nextpos_in_range <= hblank_right_stop ? nextpos_in_range : hblank_right_stop; + worker_border(lastpos, t, false); + lastpos = t; + } + // right hblank (hblank start to right edge, hblank start may be earlier than playfield end) + if (nextpos_in_range > hblank_right_stop) { + worker_border(hblank_right_stop, nextpos_in_range, true); + lastpos = nextpos_in_range; + } + + if (regno >= 0x1000) { + pfield_expand_dp_bplconx(regno, value); + } else if (regno >= 0) { + if (regno == 0 && (value & COLOR_CHANGE_BRDBLANK)) { + colors_for_drawing.extra &= ~(1 << CE_BORDERBLANK); + colors_for_drawing.extra &= ~(1 << CE_BORDERNTRANS); + colors_for_drawing.extra &= ~(1 << CE_BORDERSPRITE); + colors_for_drawing.extra |= (value & 1) != 0 ? (1 << CE_BORDERBLANK) : 0; + colors_for_drawing.extra |= (value & 3) == 2 ? (1 << CE_BORDERSPRITE) : 0; + colors_for_drawing.extra |= (value & 5) == 4 ? (1 << CE_BORDERNTRANS) : 0; + } else if (regno == 0 && (value & COLOR_CHANGE_SHRES_DELAY)) { + colors_for_drawing.extra &= ~(1 << CE_SHRES_DELAY); + colors_for_drawing.extra &= ~(1 << (CE_SHRES_DELAY + 1)); + colors_for_drawing.extra |= (value & 3) << CE_SHRES_DELAY; + pfield_expand_dp_bplcon(); + } else { + color_reg_set(colors_for_drawing, regno, value); + colors_for_drawing.acolors[regno] = getxcolor(value); + } + } + if (lastpos >= endpos) + break; + } + //#if 1 + if (vp < visible_top_start || vp >= visible_bottom_stop) { + // outside of visible area + // Just overwrite with black. Above code needs to run because of custom registers, + // not worth the trouble for separate code path just for max 10 lines or so + worker_border(visible_left_border, visible_left_border + gfxvidinfo.drawbuffer.inwidth, true); + } + //#endif + } + + function is_color_changes(di) { + var regno = curr_color_changes[di.first_color_change].regno; + var changes = di.nr_color_changes; + return changes > 1 || (changes == 1 && regno != 0xffff && regno != -1); + } + + //enum double_how + const dh_buf = 0; + const dh_line = 1; + const dh_emerg = 2; + + function pfield_draw_line(vb, lineno, gfx_ypos, follow_ypos) { + var border = 0; + var do_double = 0; + var have_color_changes; + var dh = 0; + var ls = linestate[lineno]; + + dp_for_drawing = line_decisions[lineno]; + dip_for_drawing = curr_drawinfo[lineno]; + + if (dp_for_drawing.plfleft >= 0) { + lines_count++; + resolution_count[dp_for_drawing.bplres]++; + } + + switch (ls) { + case LINE_REMEMBERED_AS_PREVIOUS: { + // happens when program messes up with VPOSW + if (!warned_pfield_draw_line) { + SAEF_warn("playfield.pfield_draw_line() Shouldn't get here... this is a bug."); + warned_pfield_draw_line++; + } + return; + } + case LINE_BLACK: { + linestate[lineno] = LINE_REMEMBERED_AS_BLACK; + border = -1; + break; + } + case LINE_REMEMBERED_AS_BLACK: + return; + + case LINE_AS_PREVIOUS: { + //dp_for_drawing--; //ORG + //dip_for_drawing--; //ORG + dp_for_drawing = line_decisions[lineno - 1]; + dip_for_drawing = curr_drawinfo[lineno - 1]; + linestate[lineno] = LINE_DONE_AS_PREVIOUS; + if (dp_for_drawing.plfleft < 0) + border = 1; + break; + } + case LINE_DONE_AS_PREVIOUS: + /* fall through */ + case LINE_DONE: + return; + + case LINE_DECIDED_DOUBLE: { + if (follow_ypos >= 0) { + do_double = 1; + linestate[lineno + 1] = LINE_DONE_AS_PREVIOUS; + } + /* fall through */ + } + default: + if (dp_for_drawing.plfleft < 0) + border = 1; + linestate[lineno] = LINE_DONE; + break; + } + + have_color_changes = is_color_changes(dip_for_drawing); + + xlinebuffer = null; + xlinebuffer_pos = 0; //OWN + if (gfxvidinfo.drawbuffer.linemem !== null) { + dh = dh_line; + if (gfxvidinfo.drawbuffer.pixbytes == 2) + xlinebuffer = new Uint16Array(gfxvidinfo.drawbuffer.linemem); + else + xlinebuffer = new Uint32Array(gfxvidinfo.drawbuffer.linemem); + } + if (xlinebuffer === null && gfxvidinfo.drawbuffer.emergmem !== null && do_double && (border == 0 || have_color_changes)) { + dh = dh_emerg; + if (gfxvidinfo.drawbuffer.pixbytes == 2) + xlinebuffer = new Uint16Array(gfxvidinfo.drawbuffer.emergmem); + else + xlinebuffer = new Uint32Array(gfxvidinfo.drawbuffer.emergmem); + } + if (xlinebuffer === null) { + dh = dh_buf; + xlinebuffer = row_map[gfx_ypos]; + } + //xlinebuffer -= linetoscr_x_adjust_pixbytes; + xlinebuffer_pos -= linetoscr_x_adjust_pixels; //OWN + //xlinebuffer_genlock = row_map_genlock[gfx_ypos] - linetoscr_x_adjust_pixels; + + if (row_map_color_burst_buffer !== null) + row_map_color_burst_buffer[gfx_ypos] = bplcolorburst; + + if (border == 0) { + pfield_expand_dp_bplcon(); + pfield_init_linetoscr(false); + pfield_doline(lineno); + + adjust_drawing_colors(dp_for_drawing.ctable, dp_for_drawing.ham_seen || bplehb || ecsshres); + + /* The problem is that we must call decode_ham() BEFORE we do the sprites. */ + if (dp_for_drawing.ham_seen) { + var ohposblank = hposblank; + init_ham_decoding(); + do_color_changes(dummy_worker, decode_ham, lineno); + if (have_color_changes) { + // do_color_changes() did color changes, reset colors back to original state + adjust_drawing_colors(dp_for_drawing.ctable, -1); + pfield_expand_dp_bplcon(); + } + hposblank = ohposblank; + ham_decode_pixel = src_pixel; + bplham = dp_for_drawing.ham_at_start; + } + + if (dip_for_drawing.nr_sprites) { + var i, e; + //#ifdef AGA + if (ce_is_bordersprite(colors_for_drawing.extra) && dp_for_drawing.bordersprite_seen && !ce_is_borderblank(colors_for_drawing.extra)) + clear_bitplane_border_aga(); + //#endif + /*for (i = 0; i < dip_for_drawing.nr_sprites; i++) { + //#ifdef AGA + if (SAEV_config.chipset.mask & SAEC_Config_Chipset_Mask_AGA) + //draw_sprites_aga(curr_sprite_entries + dip_for_drawing.first_sprite_entry + i, 1); + draw_sprites_aga(curr_sprite_entries[dip_for_drawing.first_sprite_entry + i], 1); + else + //#endif + //draw_sprites_ecs(curr_sprite_entries + dip_for_drawing.first_sprite_entry + i); + draw_sprites_ecs(curr_sprite_entries[dip_for_drawing.first_sprite_entry + i]); + }*/ + for (i = 0; i < dip_for_drawing.nr_sprites; i++) { + e = curr_sprite_entries[dip_for_drawing.first_sprite_entry + i]; + draw_sprites_1(e, bpldualpf, e.has_attached); + } + } + + //#ifdef AGA + if (dip_for_drawing.nr_sprites && ce_is_bordersprite(colors_for_drawing.extra) && !ce_is_borderblank(colors_for_drawing.extra) && dp_for_drawing.bordersprite_seen) + do_color_changes(pfield_do_linetoscr_bordersprite_aga, pfield_do_linetoscr_spr, lineno); + else + //#endif + do_color_changes(pfield_do_fill_line, dip_for_drawing.nr_sprites ? pfield_do_linetoscr_spr : pfield_do_linetoscr, lineno); + + if (dh == dh_emerg) { + //memcpy(row_map[gfx_ypos], xlinebuffer + linetoscr_x_adjust_pixbytes, gfxvidinfo.drawbuffer.pixbytes * gfxvidinfo.drawbuffer.inwidth); + row_map[gfx_ypos].set(xlinebuffer.subarray(0, gfxvidinfo.drawbuffer.inwidth)); + } + //do_flush_line(vb, gfx_ypos); + if (do_double) { + if (dh == dh_emerg) { + //memcpy(row_map[follow_ypos], xlinebuffer + linetoscr_x_adjust_pixbytes, gfxvidinfo.drawbuffer.pixbytes * gfxvidinfo.drawbuffer.inwidth); + row_map[follow_ypos].set(xlinebuffer.subarray(0, gfxvidinfo.drawbuffer.inwidth)); + } else if (dh == dh_buf) { + //memcpy(row_map[follow_ypos], row_map[gfx_ypos], gfxvidinfo.drawbuffer.pixbytes * gfxvidinfo.drawbuffer.inwidth); + row_map[follow_ypos].set(row_map[gfx_ypos].subarray(0, gfxvidinfo.drawbuffer.inwidth)); + } + /*if (need_genlock_data) + memcpy(row_map_genlock[follow_ypos], row_map_genlock[gfx_ypos], gfxvidinfo.drawbuffer.inwidth);*/ + + //do_flush_line(vb, follow_ypos); + } + + if (dip_for_drawing.nr_sprites) + pfield_erase_hborder_sprites(); + + } else if (border > 0) { // border > 0: top or bottom border + var dosprites = false; + + adjust_drawing_colors(dp_for_drawing.ctable, 0); + + //#ifdef AGA /* this makes things complex.. */ + if (dp_for_drawing.bordersprite_seen && !ce_is_borderblank(colors_for_drawing.extra) && dip_for_drawing.nr_sprites) { + dosprites = true; + pfield_expand_dp_bplcon(); + pfield_init_linetoscr(true); + pfield_erase_vborder_sprites(); + } + //#endif + + if (!dosprites && !have_color_changes) { + if (dp_for_drawing.plfleft < -1) { + // blanked border line + var tmp = hposblank; + hposblank = 1; + fill_line_border(lineno); + hposblank = tmp; + } else { + // normal border line + fill_line_border(lineno); + } + + //do_flush_line(vb, gfx_ypos); + if (do_double) { + if (dh == dh_buf) { + //xlinebuffer = row_map[follow_ypos] - linetoscr_x_adjust_pixbytes; + xlinebuffer = row_map[follow_ypos]; + xlinebuffer_pos = 0 - linetoscr_x_adjust_pixels; //OWN + //xlinebuffer_genlock = row_map_genlock[follow_ypos] - linetoscr_x_adjust_pixels; + fill_line_border(lineno); + } + /* If dh == dh_line, do_flush_line will re-use the rendered line from linemem. */ + //do_flush_line(vb, follow_ypos); + } + return; + } + + //#ifdef AGA + if (dosprites) { + for (var i = 0; i < dip_for_drawing.nr_sprites; i++) { + //draw_sprites_aga(curr_sprite_entries + dip_for_drawing->first_sprite_entry + i, 1); + //draw_sprites_aga(curr_sprite_entries[dip_for_drawing.first_sprite_entry + i], 1); + var e = curr_sprite_entries[dip_for_drawing.first_sprite_entry + i]; + draw_sprites_1(e, bpldualpf, e.has_attached); + } + do_color_changes(pfield_do_linetoscr_bordersprite_aga, pfield_do_linetoscr_bordersprite_aga, lineno); + /*#else + if (0) { + #endif*/ + + } else { + playfield_start = visible_right_border; + playfield_end = visible_right_border; + do_color_changes(pfield_do_fill_line, pfield_do_fill_line, lineno); + } + + if (dh == dh_emerg) { + //memcpy(row_map[gfx_ypos], xlinebuffer + linetoscr_x_adjust_pixbytes, gfxvidinfo.drawbuffer.pixbytes * gfxvidinfo.drawbuffer.inwidth); + row_map[gfx_ypos].set(xlinebuffer.subarray(0, gfxvidinfo.drawbuffer.inwidth)); + } + //do_flush_line(vb, gfx_ypos); + if (do_double) { + if (dh == dh_emerg) { + //memcpy(row_map[follow_ypos], xlinebuffer + linetoscr_x_adjust_pixbytes, gfxvidinfo.drawbuffer.pixbytes * gfxvidinfo.drawbuffer.inwidth); + row_map[follow_ypos].set(xlinebuffer.subarray(0, gfxvidinfo.drawbuffer.inwidth)); + } else if (dh == dh_buf) { + //memcpy(row_map[follow_ypos], row_map[gfx_ypos], gfxvidinfo.drawbuffer.pixbytes * gfxvidinfo.drawbuffer.inwidth); + row_map[follow_ypos].set(row_map[gfx_ypos].subarray(0, gfxvidinfo.drawbuffer.inwidth)); + } + /*if (need_genlock_data) + memcpy(row_map_genlock[follow_ypos], row_map_genlock[gfx_ypos], gfxvidinfo.drawbuffer.inwidth);*/ + + //do_flush_line(vb, follow_ypos); + } + } else { + // top or bottom blanking region + var tmp = hposblank; + hposblank = 1; + fill_line_border(lineno); + hposblank = tmp; + //do_flush_line(vb, gfx_ypos); + } + } + + function center_image() { + var prev_x_adjust = visible_left_border; + var prev_y_adjust = thisframe_y_adjust; + + var w = gfxvidinfo.drawbuffer.inwidth; + if (SAEV_config.video.xcenter && max_diwstop > 0 && !SAEV_config.video.gf[0].gfx_filter_autoscale) { + if (max_diwstop - min_diwstart < w && SAEV_config.video.xcenter == 2) + /* Try to center. */ + visible_left_border = Math.truncate((max_diwstop - min_diwstart - w) / 2) + min_diwstart; //ATT + else + visible_left_border = max_diwstop - w - Math.truncate((max_diwstop - min_diwstart - w) / 2); //ATT + visible_left_border &= ~((xshift (1, lores_shift)) - 1); + //#if 1 + if (!center_reset && !vertical_changed) { + /* Would the old value be good enough? If so, leave it as it is if we want to be clever. */ + if (SAEV_config.video.xcenter == 2) { + if (visible_left_border < prev_x_adjust && prev_x_adjust < min_diwstart && min_diwstart - visible_left_border <= 32) + visible_left_border = prev_x_adjust; + } + } + //#endif + } else if (gfxvidinfo.drawbuffer.extrawidth) { + visible_left_border = max_diwlastword() - w; + if (gfxvidinfo.drawbuffer.extrawidth > 0) + visible_left_border += gfxvidinfo.drawbuffer.extrawidth << SAEV_config.video.hresolution; + } else { + if (gfxvidinfo.drawbuffer.inxoffset < 0) { + visible_left_border = 0; + } else { + visible_left_border = gfxvidinfo.drawbuffer.inxoffset - DISPLAY_LEFT_SHIFT; + } + } + + if (visible_left_border > max_diwlastword() - 32) + visible_left_border = max_diwlastword() - 32; + if (visible_left_border < 0) + visible_left_border = 0; + visible_left_border &= ~((xshift (1, lores_shift)) - 1); + + //SAEF_log("playfield.center_image() %d %d %d %d %d", max_diwlastword(), gfxvidinfo.drawbuffer.inwidth, lores_shift, SAEV_config.video.hresolution, visible_left_border); + + linetoscr_x_adjust_pixels = visible_left_border; + linetoscr_x_adjust_pixbytes = linetoscr_x_adjust_pixels * gfxvidinfo.drawbuffer.pixbytes; + + visible_right_border = visible_left_border + w; + if (visible_right_border > max_diwlastword()) + visible_right_border = max_diwlastword(); + + var max_drawn_amiga_line_tmp = max_drawn_amiga_line; + if (max_drawn_amiga_line_tmp > gfxvidinfo.drawbuffer.inheight) + max_drawn_amiga_line_tmp = gfxvidinfo.drawbuffer.inheight; + max_drawn_amiga_line_tmp >>= linedbl; + + thisframe_y_adjust = minfirstline; + if (SAEV_config.video.ycenter && thisframe_first_drawn_line >= 0 && !SAEV_config.video.gf[0].gfx_filter_autoscale) { + if (thisframe_last_drawn_line - thisframe_first_drawn_line < max_drawn_amiga_line_tmp && SAEV_config.video.ycenter == 2) + thisframe_y_adjust = Math.truncate((thisframe_last_drawn_line - thisframe_first_drawn_line - max_drawn_amiga_line_tmp) / 2) + thisframe_first_drawn_line; //ATT + else + thisframe_y_adjust = thisframe_first_drawn_line; + //#if 1 + /* Would the old value be good enough? If so, leave it as it is if we want to be clever. */ + if (!center_reset && !horizontal_changed) { + if (SAEV_config.video.ycenter == 2 && thisframe_y_adjust != prev_y_adjust) { + if (prev_y_adjust <= thisframe_first_drawn_line && prev_y_adjust + max_drawn_amiga_line_tmp > thisframe_last_drawn_line) + thisframe_y_adjust = prev_y_adjust; + } + } + //#endif + } + + /* Make sure the value makes sense */ + if (thisframe_y_adjust + max_drawn_amiga_line_tmp > maxvpos + (maxvpos >> 1)) //ORG / 2 + thisframe_y_adjust = maxvpos + (maxvpos >> 1) - max_drawn_amiga_line_tmp; + if (thisframe_y_adjust < 0) + thisframe_y_adjust = 0; + + thisframe_y_adjust_real = thisframe_y_adjust << linedbl; + max_ypos_thisframe = (maxvpos_display - minfirstline + 1) << linedbl; + + if (prev_x_adjust != visible_left_border || prev_y_adjust != thisframe_y_adjust) { + var redraw = interlace_seen > 0 && linedbl ? 2 : 1; + if (redraw > frame_redraw_necessary) + frame_redraw_necessary = redraw; + } + + max_diwstop = 0; + min_diwstart = MAX_STOP; + + gfxvidinfo.drawbuffer.xoffset = (DISPLAY_LEFT_SHIFT << RES_MAX) + (visible_left_border << (RES_MAX - SAEV_config.video.hresolution)); + gfxvidinfo.drawbuffer.yoffset = thisframe_y_adjust << VRES_MAX; + + center_reset = false; + horizontal_changed = false; + vertical_changed = false; + } + + var frame_res_cnt = 0; //int + var autoswitch_old_resolution = 0; //int + function init_drawing_frame() { + var i, maxline; + //static int frame_res_old; + + /*if (SAEV_config.video.hresolution == changed_prefs.gfx_resolution && lines_count > 0) { + int largest_count = 0; + int largest_count_res = 0; + int largest_res = 0; + for (int i = 0; i <= RES_MAX; i++) { + if (resolution_count[i]) + largest_res = i; + if (resolution_count[i] >= largest_count) { + largest_count = resolution_count[i]; + largest_count_res = i; + } + } + + if (currprefs.gfx_autoresolution_vga && programmedmode && gfxvidinfo.gfx_resolution_reserved >= SAEC_Config_Video_HResolution_HiRes && gfxvidinfo.gfx_vresolution_reserved >= SAEC_Config_Video_VResolution_Double) { + if (largest_res == SAEC_Config_Video_HResolution_SuperHiRes && (gfxvidinfo.gfx_resolution_reserved < SAEC_Config_Video_HResolution_SuperHiRes || gfxvidinfo.gfx_vresolution_reserved < 1)) { + // enable full doubling/superhires support if programmed mode. It may be "half-width" only and may fit in normal display window. + gfxvidinfo.gfx_resolution_reserved = SAEC_Config_Video_HResolution_SuperHiRes; + gfxvidinfo.gfx_vresolution_reserved = SAEC_Config_Video_VResolution_Double; + graphics_reset(false); + } + int newres = largest_res; + if (htotal < 190) + newres = largest_res + 1; + if (newres < SAEC_Config_Video_HResolution_HiRes) + newres = SAEC_Config_Video_HResolution_HiRes; + if (newres > RES_MAX) + newres = RES_MAX; + if (changed_prefs.gfx_resolution != newres) { + autoswitch_old_resolution = SAEC_Config_Video_HResolution_HiRes; + SAEF_log("Programmed mode autores = %d -> %d (%d)", changed_prefs.gfx_resolution, newres, largest_res); + changed_prefs.gfx_resolution = newres; + set_config_changed(); + return; + } + } else if (autoswitch_old_resolution == SAEC_Config_Video_HResolution_HiRes) { + autoswitch_old_resolution = 0; + if (changed_prefs.gfx_resolution != SAEC_Config_Video_HResolution_HiRes) { + changed_prefs.gfx_resolution = SAEC_Config_Video_HResolution_HiRes; + set_config_changed(); + return; + } + } + + if (currprefs.gfx_autoresolution) { + int frame_res_detected; + int frame_res_lace_detected = frame_res_lace; + + if (currprefs.gfx_autoresolution == 1 || currprefs.gfx_autoresolution >= 100) + frame_res_detected = largest_res; + else if (largest_count * 100 / lines_count >= currprefs.gfx_autoresolution) + frame_res_detected = largest_count_res; + else + frame_res_detected = largest_count_res - 1; + if (frame_res_detected < 0) + frame_res_detected = 0; + #if 0 + static int delay; + delay--; + if (delay < 0) { + delay = 50; + SAEF_log("playfield.init_drawing_frame() %d %d, %d %d %d, %d %d, %d %d", currprefs.gfx_autoresolution, lines_count, resolution_count[0], resolution_count[1], resolution_count[2], + largest_count, largest_count_res, frame_res_detected, frame_res_lace_detected); + } + #endif + if (frame_res_detected >= 0 && frame_res_lace_detected >= 0) { + if (frame_res_cnt > 0 && frame_res_old == frame_res_detected * 2 + frame_res_lace_detected) { + frame_res_cnt--; + if (frame_res_cnt == 0) { + int m = frame_res_detected * 2 + frame_res_lace_detected; + struct wh *dst = SAEV_config.video.apmode[0].gfx_fullscreen ? &changed_prefs.gfx_size_fs : &changed_prefs.gfx_size_win; + while (m < 3 * 2) { + struct wh *src = SAEV_config.video.apmode[0].gfx_fullscreen ? &currprefs.gfx_size_fs_xtra[m] : &currprefs.gfx_size_win_xtra[m]; + if ((src->width > 0 && src->height > 0) || (SAEV_config.video.api == SAEC_Config_Video_API_WebGL || SAEV_config.video.gf[0].gfx_filter > 0)) { + int nr = m >> 1; + int nl = (m & 1) == 0 ? 0 : 1; + int nr_o = nr; + int nl_o = nl; + + if (currprefs.gfx_autoresolution >= 100 && nl == 0 && nr > 0) { + nl = 1; + } + + if (currprefs.gfx_autoresolution_minh < 0) { + if (nr < nl) + nr = nl; + } else if (nr < currprefs.gfx_autoresolution_minh) { + nr = currprefs.gfx_autoresolution_minh; + } + if (currprefs.gfx_autoresolution_minv < 0) { + if (nl < nr) + nl = nr; + } else if (nl < currprefs.gfx_autoresolution_minv) { + nl = currprefs.gfx_autoresolution_minv; + } + + if (nr > gfxvidinfo.gfx_resolution_reserved) + nr = gfxvidinfo.gfx_resolution_reserved; + if (nl > gfxvidinfo.gfx_vresolution_reserved) + nl = gfxvidinfo.gfx_vresolution_reserved; + + if (changed_prefs.gfx_resolution != nr || changed_prefs.gfx_vresolution != nl) { + changed_prefs.gfx_resolution = nr; + changed_prefs.gfx_vresolution = nl; + + SAEF_log("playfield.init_drawing_frame() RES -> %d (%d) LINE -> %d (%d) (%d - %d, %d - %d)", nr, nr_o, nl, nl_o, + currprefs.gfx_autoresolution_minh, currprefs.gfx_autoresolution_minv, + gfxvidinfo.gfx_resolution_reserved, gfxvidinfo.gfx_vresolution_reserved); + set_config_changed (); + } + if (src->width > 0 && src->height > 0) { + if (memcmp (dst, src, sizeof *dst)) { + *dst = *src; + set_config_changed (); + } + } + break; + } + m++; + } + frame_res_cnt = currprefs.gfx_autoresolution_delay; + } + } else { + frame_res_old = frame_res_detected * 2 + frame_res_lace_detected; + frame_res_cnt = currprefs.gfx_autoresolution_delay; + if (frame_res_cnt <= 0) + frame_res_cnt = 1; + } + } + } + }*/ + + for (i = 0; i <= RES_MAX; i++) + resolution_count[i] = 0; + lines_count = 0; + frame_res = -1; + frame_res_lace = 0; + + if (can_use_lores > AUTO_LORES_FRAMES && 0) { + lores_factor = 1; + lores_set(0); + } else { + can_use_lores++; + lores_reset(); + } + + init_hardware_for_drawing_frame(); + + if (thisframe_first_drawn_line < 0) + thisframe_first_drawn_line = minfirstline; + if (thisframe_first_drawn_line > thisframe_last_drawn_line) + thisframe_last_drawn_line = thisframe_first_drawn_line; + + maxline = ((maxvpos_display + 1) << linedbl) + 2; + if (SMART_UPDATE) { + for (i = 0; i < maxline; i++) { + var ls = linestate[i]; + switch (ls) { + case LINE_DONE_AS_PREVIOUS: + linestate[i] = LINE_REMEMBERED_AS_PREVIOUS; + break; + case LINE_REMEMBERED_AS_BLACK: + break; + default: + linestate[i] = LINE_UNDECIDED; + } + } + } else { + for (i = 0; i < maxline; i++) + linestate[i] = LINE_UNDECIDED; + } + last_drawn_line = 0; + first_drawn_line = 32767; + + //first_block_line = last_block_line = NO_BLOCK; //OWN flush_line() and flush_block() is not used + if (frame_redraw_necessary) { + reset_decision_table(); + custom_frame_redraw_necessary = 1; + frame_redraw_necessary--; + } else + custom_frame_redraw_necessary = 0; + + center_image(); + + thisframe_first_drawn_line = -1; + thisframe_last_drawn_line = -1; + + drawing_color_matches = -1; + } + + + + + function putpixel(buf, bpp, x, c8, opaq) { + if (x <= 0) + return; + + switch (bpp) { + case 1: + buf[x] = c8 & 0xff; + break; + case 2: { + //uae_u16 *p = (uae_u16*)buf + x; *p = (uae_u16)c8; + buf[x] = c8 & 0xffff; + break; + } + case 3: //no 24 bit yet + break; + case 4: { + if (1 || opaq || SAEV_config.video.gf[0].gfx_filter == 0) { + //uae_u32 *p = (uae_u32*)buf + x; *p = c8; + buf[x] = c8; + } else { + for (var i = 0; i < 4; i++) { + var v1 = buf[i + bpp * x]; + var v2 = (c8 >> (i * 8)) & 255; + v1 = (v1 * 2 + v2 * 3) / 5; + if (v1 > 255) + v1 = 255; + buf[i + bpp * x] = v1; + } + } + break; + } + } + } + + + /*var statusbar_y1, statusbar_y2; //int + + [...] statusline.cpp + + static uae_u8 *status_line_ptr(int line) { + int y; + + y = line - (gfxvidinfo.drawbuffer.outheight - TD_TOTAL_HEIGHT); + xlinebuffer = gfxvidinfo.drawbuffer.linemem; + if (xlinebuffer == 0) + xlinebuffer = row_map[line]; + xlinebuffer_genlock = row_map_genlock[line]; + return xlinebuffer; + } + + static void draw_status_line (int line, int statusy) { + uae_u8 *buf = status_line_ptr(line); + if (!buf) + return; + if (statusy < 0) + statusline_render(buf, gfxvidinfo.drawbuffer.pixbytes, gfxvidinfo.drawbuffer.rowbytes, gfxvidinfo.drawbuffer.outwidth, TD_TOTAL_HEIGHT, xredcolors, xgreencolors, xbluecolors, NULL); + else + draw_status_line_single(buf, gfxvidinfo.drawbuffer.pixbytes, statusy, gfxvidinfo.drawbuffer.outwidth, xredcolors, xgreencolors, xbluecolors, NULL); + } + + static void draw_debug_status_line (int line) { + xlinebuffer = gfxvidinfo.drawbuffer.linemem; + if (xlinebuffer == 0) + xlinebuffer = row_map[line]; + xlinebuffer_genlock = row_map_genlock[line]; + debug_draw(xlinebuffer, gfxvidinfo.drawbuffer.pixbytes, line, gfxvidinfo.drawbuffer.outwidth, gfxvidinfo.drawbuffer.outheight, xredcolors, xgreencolors, xbluecolors); + } + + const LIGHTPEN_HEIGHT = 12; + const LIGHTPEN_WIDTH = 17; + + static const char *lightpen_cursor = { + "------.....------" + "------.xxx.------" + "------.xxx.------" + "------.xxx.------" + ".......xxx......." + ".xxxxxxxxxxxxxxx." + ".xxxxxxxxxxxxxxx." + ".......xxx......." + "------.xxx.------" + "------.xxx.------" + "------.xxx.------" + "------.....------" }; - this.setup_sprites = function () { - if (!sprinit) { - sprinit = true; - setup_sprite_tables(); - } - }; - - this.cleanup_sprites = function () { - }; - - this.reset_sprites = function () { - var i; - for (i = 0; i < sprpos.length; i++) sprpos[i] = 0; //memset (sprpos, 0, sizeof sprpos); - for (i = 0; i < sprctl.length; i++) sprctl[i] = 0; //memset (sprctl, 0, sizeof sprctl); + var lightpen_y1, lightpen_y2; //int - for (i = 0; i < spixels.length; i++) spixels[i] = 0; //memset(spixels, 0, sizeof spixels); - for (i = 0; i < spixstate.length; i++) spixstate[i] = 0; //memset(&spixstate, 0, sizeof spixstate); - }; - + static void draw_lightpen_cursor (int x, int y, int line, int onscreen) + { + int i; + const char *p; + int color1 = onscreen ? 0xff0 : 0xf00; + int color2 = 0x000; + + xlinebuffer = gfxvidinfo.drawbuffer.linemem; + if (xlinebuffer == 0) + xlinebuffer = row_map[line]; + xlinebuffer_genlock = row_map_genlock[line]; + + p = lightpen_cursor + y * LIGHTPEN_WIDTH; + for (i = 0; i < LIGHTPEN_WIDTH; i++) { + int xx = x + i - LIGHTPEN_WIDTH / 2; + if (*p != "-" && xx >= 0 && xx < gfxvidinfo.drawbuffer.outwidth) + putpixel (xlinebuffer, gfxvidinfo.drawbuffer.pixbytes, xx, *p == "x" ? xcolors[color1] : xcolors[color2], 1); + p++; + } + } + + static void lightpen_update (struct vidbuffer *vb) + { + int i; + + if (lightpen_x < LIGHTPEN_WIDTH + 1) + lightpen_x = LIGHTPEN_WIDTH + 1; + if (lightpen_x >= gfxvidinfo.drawbuffer.inwidth - LIGHTPEN_WIDTH - 1) + lightpen_x = gfxvidinfo.drawbuffer.inwidth - LIGHTPEN_WIDTH - 2; + if (lightpen_y < LIGHTPEN_HEIGHT + 1) + lightpen_y = LIGHTPEN_HEIGHT + 1; + if (lightpen_y >= gfxvidinfo.drawbuffer.inheight - LIGHTPEN_HEIGHT - 1) + lightpen_y = gfxvidinfo.drawbuffer.inheight - LIGHTPEN_HEIGHT - 2; + if (lightpen_y >= max_ypos_thisframe - LIGHTPEN_HEIGHT - 1) + lightpen_y = max_ypos_thisframe - LIGHTPEN_HEIGHT - 2; + + lightpen_cx = (((lightpen_x + visible_left_border) >> lores_shift) >> 1) + DISPLAY_LEFT_SHIFT - DIW_DDF_OFFSET; + + lightpen_cy = lightpen_y; + lightpen_cy >>= linedbl; + lightpen_cy += minfirstline; + + if (lightpen_cx < 0x18) + lightpen_cx = 0x18; + if (lightpen_cx >= maxhpos) + lightpen_cx -= maxhpos; + if (lightpen_cy < minfirstline) + lightpen_cy = minfirstline; + if (lightpen_cy >= maxvpos) + lightpen_cy = maxvpos - 1; + + for (i = 0; i < LIGHTPEN_HEIGHT; i++) { + int line = lightpen_y + i - LIGHTPEN_HEIGHT / 2; + if (line >= 0 || line < max_ypos_thisframe) { + if (lightpen_active > 0) + draw_lightpen_cursor (lightpen_x, i, line, lightpen_cx > 0); + SAER.video.flush_line(vb, line); + } + } + lightpen_y1 = lightpen_y - LIGHTPEN_HEIGHT / 2 - 1 + min_ypos_for_screen; + lightpen_y2 = lightpen_y1 + LIGHTPEN_HEIGHT + 2; + + if (lightpen_active < 0) + lightpen_active = 0; + }*/ + + + const refresh_indicator_colors = [ 0x777, 0x0f0, 0x00f, 0xff0, 0xf0f ]; + + function refresh_indicator_init() { + //xfree(refresh_indicator_buffer); + refresh_indicator_buffer = null; + //xfree(refresh_indicator_changed); + refresh_indicator_changed = null; + //xfree(refresh_indicator_changed_prev); + refresh_indicator_changed_prev = null; + + if (!SAEV_config.video.refreshIndicator) + return; + + refresh_indicator_height = 600; + /*refresh_indicator_buffer = xcalloc(uae_u8, MAX_PIXELS_PER_LINE * 2 * refresh_indicator_height); + refresh_indicator_changed = xcalloc(uae_u8, refresh_indicator_height); + refresh_indicator_changed_prev = xcalloc(uae_u8, refresh_indicator_height);*/ + refresh_indicator_buffer = new ArrayBuffer(MAX_PIXELS_PER_LINE * 2 * refresh_indicator_height); + refresh_indicator_changed = new Uint8Array(refresh_indicator_height); + refresh_indicator_changed_prev = new Uint8Array(refresh_indicator_height); + } + + function refresh_indicator_update(vb) { + for (var i = 0; i < max_ypos_thisframe; i++) { + var i1 = i + min_ypos_for_screen; + var line = i + thisframe_y_adjust_real; + var whereline = amiga2aspect_line_map[i1]; + var wherenext = amiga2aspect_line_map[i1 + 1]; + + if (whereline >= vb.inheight) + break; + if (whereline < 0) + continue; + if (line >= refresh_indicator_height) + break; + + xlinebuffer = row_map[whereline]; + var pixel = refresh_indicator_changed_prev[line]; + if (wherenext >= 0) + pixel = refresh_indicator_changed_prev[line & ~1]; + + var color1 = 0; + var color2 = 0; + if (pixel <= 4) { + color1 = color2 = refresh_indicator_colors[pixel]; + } else if (pixel <= 8) { + color2 = refresh_indicator_colors[pixel - 5]; + } + for (var x = 0; x < 8; x++) { + putpixel(xlinebuffer, gfxvidinfo.drawbuffer.pixbytes, x, xcolors[color1], 1); + } + for (var x = 8; x < 16; x++) { + putpixel(xlinebuffer, gfxvidinfo.drawbuffer.pixbytes, x, xcolors[color2], 1); + } + } + } + + + //const LARGEST_LINE_DEBUG = 0; + //var xvbin = null, xvbout = null; //struct vidbuffer * + + function draw_frame2(vbin, vbout) { + //xvbin = vbin; + //xvbout = vbout; + + //if (LARGEST_LINE_DEBUG) var largest = 0; + + for (var i = 0; i < max_ypos_thisframe; i++) { + var i1 = i + min_ypos_for_screen; + var line = i + thisframe_y_adjust_real; + var whereline = amiga2aspect_line_map[i1]; + var wherenext = amiga2aspect_line_map[i1 + 1]; + + if (whereline >= vbin.inheight) + break; + if (whereline < 0) + continue; + //if (LARGEST_LINE_DEBUG && largest < whereline) largest = whereline; + + hposblank = 0; + pfield_draw_line(vbout, line, whereline, wherenext); + } + //if (LARGEST_LINE_DEBUG) SAEF_log("playfield.draw_frame2() largest line %d", largest); + } + + /*bool draw_frame (struct vidbuffer *vb) { + uae_u8 oldstate[LINESTATE_SIZE]; + struct vidbuffer oldvb; + + memcpy (&oldvb, &gfxvidinfo.drawbuffer, sizeof (struct vidbuffer)); + memcpy (&gfxvidinfo.drawbuffer, vb, sizeof (struct vidbuffer)); + clearbuffer (vb); + init_row_map(); + memcpy (oldstate, linestate, LINESTATE_SIZE); + for (int i = 0; i < LINESTATE_SIZE; i++) { + uae_u8 v = linestate[i]; + if (v == LINE_REMEMBERED_AS_PREVIOUS) { + linestate[i - 1] = LINE_DECIDED_DOUBLE; + v = LINE_AS_PREVIOUS; + } else if (v == LINE_DONE_AS_PREVIOUS) { + linestate[i - 1] = LINE_DECIDED_DOUBLE; + v = LINE_AS_PREVIOUS; + } else if (v == LINE_REMEMBERED_AS_BLACK) { + v = LINE_BLACK; + } else if (v == LINE_DONE) { + v = LINE_DECIDED; + } + linestate[i] = v; + } + last_drawn_line = 0; + first_drawn_line = 32767; + drawing_color_matches = -1; + draw_frame2(vb, NULL); + last_drawn_line = 0; + first_drawn_line = 32767; + drawing_color_matches = -1; + memcpy (linestate, oldstate, LINESTATE_SIZE); + memcpy (&gfxvidinfo.drawbuffer, &oldvb, sizeof (struct vidbuffer)); + init_row_map(); + return true; + }*/ + + function setnativeposition(vb) { + vb.inwidth = gfxvidinfo.drawbuffer.inwidth; + vb.inheight = gfxvidinfo.drawbuffer.inheight; + vb.inwidth2 = gfxvidinfo.drawbuffer.inwidth2; + vb.inheight2 = gfxvidinfo.drawbuffer.inheight2; + vb.outwidth = gfxvidinfo.drawbuffer.outwidth; + vb.outheight = gfxvidinfo.drawbuffer.outheight; + } + + function setspecialmonitorpos(vb) { + vb.extrawidth = gfxvidinfo.drawbuffer.extrawidth; + vb.xoffset = gfxvidinfo.drawbuffer.xoffset; + vb.yoffset = gfxvidinfo.drawbuffer.yoffset; + vb.inxoffset = gfxvidinfo.drawbuffer.inxoffset; + vb.inyoffset = gfxvidinfo.drawbuffer.inyoffset; + } + + function init_hardware_frame() { + first_bpl_vpos = -1; + next_lineno = 0; + prev_lineno = -1; + nextline_how = nln_normal; + diwstate = DIW_WAITING_START; + ddfstate = DIW_WAITING_START; + + if (first_bplcon0 != first_bplcon0_old) { + vertical_changed = horizontal_changed = true; + } + first_bplcon0_old = first_bplcon0; + + if (first_planes_vpos != first_planes_vpos_old || + last_planes_vpos != last_planes_vpos_old) { + vertical_changed = true; + } + first_planes_vpos_old = first_planes_vpos; + last_planes_vpos_old = last_planes_vpos; + + if (diwfirstword_total != diwfirstword_total_old || + diwlastword_total != diwlastword_total_old || + ddffirstword_total != ddffirstword_total_old || + ddflastword_total != ddflastword_total_old) { + horizontal_changed = true; + } + diwfirstword_total_old = diwfirstword_total; + diwlastword_total_old = diwlastword_total; + ddffirstword_total_old = ddffirstword_total; + ddflastword_total_old = ddflastword_total; + + first_planes_vpos = 0; + last_planes_vpos = 0; + diwfirstword_total = max_diwlastword(); + diwlastword_total = 0; + ddffirstword_total = max_diwlastword(); + ddflastword_total = 0; + plflastline_total = 0; + plffirstline_total = current_maxvpos(); + first_bplcon0 = 0; + autoscale_bordercolors = 0; + + for (var i = 0; i < MAX_SPRITES; i++) { + spr[i].ptxhpos = MAXHPOS; + spr[i].ptxvpos2 = -1; + } + plf_state = plf_end; + } + + function init_hardware_for_drawing_frame() { //global + /* Avoid this code in the first frame after a customreset. */ + if (prev_sprite_entries) { + var first_pixel = prev_sprite_entries[0].first_pixel; + var npixels = prev_sprite_entries[prev_next_sprite_entry].first_pixel - first_pixel; + for (var i = 0; i < npixels; i++) { + spixels[first_pixel + i] = 0; + spixstate.bytes[first_pixel + i] = 0; + } + } + prev_next_sprite_entry = next_sprite_entry; + + next_color_change = 0; + next_sprite_entry = 0; + next_color_entry = 0; + remembered_color_entry = -1; + + prev_sprite_entries = sprite_entries[current_change_set]; + curr_sprite_entries = sprite_entries[current_change_set ^ 1]; + prev_color_changes = color_changes[current_change_set]; + curr_color_changes = color_changes[current_change_set ^ 1]; + prev_color_tables = color_tables[current_change_set]; + curr_color_tables = color_tables[current_change_set ^ 1]; + + prev_drawinfo = line_drawinfo[current_change_set]; + curr_drawinfo = line_drawinfo[current_change_set ^ 1]; + current_change_set ^= 1; + + color_src_match = color_dest_match = -1; + + /* Use both halves of the array in alternating fashion. */ + curr_sprite_entries[0].first_pixel = current_change_set * MAX_SPR_PIXELS; + next_sprite_forced = 1; + } + + function finish_drawing_frame() { + var didflush = false; + var vb = gfxvidinfo.drawbuffer; + + gfxvidinfo.outbuffer = vb; + + if (!SAER.video.lockscr(vb, false)) { + notice_screen_contents_lost(); + return; + } + if (!SMART_UPDATE) { + /* This isn't exactly right yet. FIXME */ + if (!interlace_seen) + do_flush_screen(vb, first_drawn_line, last_drawn_line); + else + SAER.video.unlockscr(); + return; + } + + draw_frame2(vb, vb); + + /*if (currprefs.leds_on_screen && ((currprefs.leds_on_screen & STATUSLINE_CHIPSET) && !(currprefs.leds_on_screen & STATUSLINE_TARGET))) { + int slx, sly; + statusline_getpos(&slx, &sly, vb->outwidth, vb->outheight); + statusbar_y1 = sly + min_ypos_for_screen - 1; + statusbar_y2 = statusbar_y1 + TD_TOTAL_HEIGHT + 1; + draw_status_line(sly, -1); + for (var i = 0; i < TD_TOTAL_HEIGHT; i++) { + int line = sly + i; + draw_status_line (line, i); + do_flush_line(vb, line); + } + }*/ + + //if (lightpen_active) lightpen_update(vb); + if (refresh_indicator_buffer !== null) refresh_indicator_update(vb); + + /*if (currprefs.monitoremu && gfxvidinfo.tempbuffer.bufmem_allocated) { + setspecialmonitorpos(&gfxvidinfo.tempbuffer); + if (init_genlock_data != specialmonitor_need_genlock()) { + init_genlock_data = specialmonitor_need_genlock(); + init_row_map(); + } + if (emulate_specialmonitors (vb, &gfxvidinfo.tempbuffer)) { + vb = gfxvidinfo.outbuffer = &gfxvidinfo.tempbuffer; + if (vb->nativepositioning) + setnativeposition(vb); + gfxvidinfo.drawbuffer.tempbufferinuse = true; + need_genlock_data = specialmonitor_need_genlock(); + if (!specialmonitoron) { + compute_framesync(); + } + specialmonitoron = true; + pfield_set_linetoscr(); + do_flush_screen(vb, 0, vb->outheight); + didflush = true; + } else { + pfield_set_linetoscr(); + need_genlock_data = false; + if (specialmonitoron || gfxvidinfo.drawbuffer.tempbufferinuse) { + gfxvidinfo.drawbuffer.tempbufferinuse = false; + specialmonitoron = false; + compute_framesync(); + } + } + }*/ + + /*if (!currprefs.monitoremu && gfxvidinfo.tempbuffer.bufmem_allocated && ((!bplcolorburst_field && currprefs.cs_color_burst) || (currprefs.gfx_grayscale))) { + setspecialmonitorpos(&gfxvidinfo.tempbuffer); + emulate_grayscale(vb, &gfxvidinfo.tempbuffer); + vb = gfxvidinfo.outbuffer = &gfxvidinfo.tempbuffer; + if (vb->nativepositioning) + setnativeposition(vb); + gfxvidinfo.drawbuffer.tempbufferinuse = true; + do_flush_screen(vb, 0, vb->outheight); + didflush = true; + }*/ + + /*if (currprefs.genlock_image && !currprefs.monitoremu && !currprefs.cs_color_burst && gfxvidinfo.tempbuffer.bufmem_allocated && SAEV_config.chipset.genlock) { + setspecialmonitorpos(&gfxvidinfo.tempbuffer); + if (init_genlock_data != specialmonitor_need_genlock()) { + need_genlock_data = init_genlock_data = specialmonitor_need_genlock(); + init_row_map(); + } + emulate_genlock(vb, &gfxvidinfo.tempbuffer); + vb = gfxvidinfo.outbuffer = &gfxvidinfo.tempbuffer; + if (vb->nativepositioning) + setnativeposition(vb); + gfxvidinfo.drawbuffer.tempbufferinuse = true; + do_flush_screen(vb, 0, vb->outheight); + didflush = true; + }*/ + + /*if (!currprefs.monitoremu && gfxvidinfo.tempbuffer.bufmem_allocated && currprefs.cs_cd32fmv) { + if (cd32_fmv_active) { + cd32_fmv_genlock(vb, &gfxvidinfo.tempbuffer); + vb = gfxvidinfo.outbuffer = &gfxvidinfo.tempbuffer; + setnativeposition(vb); + gfxvidinfo.drawbuffer.tempbufferinuse = true; + do_flush_screen(vb, 0, vb->outheight); + didflush = true; + } else { + gfxvidinfo.drawbuffer.tempbufferinuse = false; + } + }*/ + + if (!didflush) + do_flush_screen(vb, first_drawn_line, last_drawn_line); + } + + function hardware_line_completed(lineno) { + if (!SMART_UPDATE) { + var i = lineno - thisframe_y_adjust_real; + if (i >= 0 && i < max_ypos_thisframe) { + var where = amiga2aspect_line_map[i + min_ypos_for_screen]; + if (where < gfxvidinfo.drawbuffer.outheight && where >= 0) + pfield_draw_line(gfxvidinfo.drawbuffer, lineno, where, amiga2aspect_line_map[i + min_ypos_for_screen + 1]); + } + } + } + + /*function check_picasso() { + #ifdef PICASSO96 + if (SAEV_Playfield_picasso_on && picasso_redraw_necessary) + picasso_refresh(); + picasso_redraw_necessary = 0; + + if (SAEV_Playfield_picasso_requested_on == SAEV_Playfield_picasso_on) + return; + + SAEV_Playfield_picasso_on = SAEV_Playfield_picasso_requested_on; + + if (!SAEV_Playfield_picasso_on) + clear_inhibit_frame(IHF_PICASSO); + else + set_inhibit_frame(IHF_PICASSO); + + gfx_set_picasso_state(SAEV_Playfield_picasso_on); + picasso_enablescreen(SAEV_Playfield_picasso_requested_on); + + notice_screen_contents_lost(); + notice_new_xcolors(); + count_frame(); + #endif + }*/ + + function redraw_frame() { //global + last_drawn_line = 0; + first_drawn_line = 32767; + finish_drawing_frame(); + /* OWN flush_screen() is not used + SAER.video.flush_screen(gfxvidinfo.inbuffer, 0, 0);*/ + } + + function vsync_handle_check() { //global + /*var changed = check_prefs_changed_gfx(); + if (changed > 0) { + reset_drawing(); + init_row_map(); + init_aspect_maps(); + notice_screen_contents_lost(); + notice_new_xcolors(); + } else if (changed < 0) { + reset_drawing(); + init_row_map(); + init_aspect_maps(); + notice_screen_contents_lost(); + notice_new_xcolors(); + } + check_prefs_changed_cd(); + check_prefs_changed_audio(); + check_prefs_changed_custom(); + check_prefs_changed_cpu(); + check_picasso(); + return changed != 0;*/ + return false; + } + + function vsync_handle_redraw(long_field, lof_changed, bplcon0p, bplcon3p) { //global + last_redraw_point++; + if (lof_changed || interlace_seen <= 0 || (SAEV_config.video.iscanlines && interlace_seen > 0) || last_redraw_point >= 2 || long_field || doublescan < 0) { + last_redraw_point = 0; + + if (framecnt == 0) + finish_drawing_frame(); + /*#if 0 + if (interlace_seen > 0) { + interlace_seen = -1; + } else if (interlace_seen == -1) { + interlace_seen = 0; + if (SAEV_config.video.scandoubler && SAEV_config.video.vresolution) + notice_screen_contents_lost(); + } + #endif*/ + + if (SAEV_command < 0) { + SAEV_command = -SAEV_command; + set_inhibit_frame(IHF_QUIT_PROGRAM); + SAEF_setSpcFlags(SAEC_spcflag_BRK | SAEC_spcflag_MODE_CHANGE); + return; + } + + count_frame(); + + if (framecnt == 0) + init_drawing_frame(); + } + /* OWN flush_screen() is not used + else { + if (isvsync_chipset()) + SAER.video.flush_screen(gfxvidinfo.inbuffer, 0, 0); //vsync mode + }*/ + + SAER.gui.flicker_led(-1, 0, 0); + /*#ifdef AVIOUTPUT + if (!SAEV_Playfield_picasso_on) frame_drawn(); + #endif*/ + } + + function hsync_record_line_state(lineno, how, changed) { //global + //uae_u8 *state = linestate + lineno; + + if (framecnt != 0) + return; + + //changed |= frame_redraw_necessary != 0 || refresh_indicator_buffer !== null || ((lineno >= lightpen_y1 && lineno < lightpen_y2) || (lineno >= statusbar_y1 && lineno < statusbar_y2)); + changed |= (frame_redraw_necessary != 0 || refresh_indicator_buffer !== null) ? 1 : 0; + //changed |= (frame_redraw_necessary != 0 ? 1 : 0); + + switch (how) { + case nln_normal: + linestate[lineno] = changed ? LINE_DECIDED : LINE_DONE; + break; + case nln_doubled: + linestate[lineno] = changed ? LINE_DECIDED_DOUBLE : LINE_DONE; + changed |= (linestate[lineno + 1] != LINE_REMEMBERED_AS_PREVIOUS ? 1 : 0); + linestate[lineno + 1] = changed ? LINE_AS_PREVIOUS : LINE_DONE_AS_PREVIOUS; + break; + case nln_nblack: + linestate[lineno] = changed ? LINE_DECIDED : LINE_DONE; + if (linestate[lineno + 1] != LINE_REMEMBERED_AS_BLACK) { + linestate[lineno + 1] = LINE_BLACK; + } + break; + case nln_lower: + if (lineno > 0 && linestate[lineno - 1] == LINE_UNDECIDED) { + linestate[lineno - 1] = LINE_DECIDED; //LINE_BLACK; + } + linestate[lineno] = changed ? LINE_DECIDED : LINE_DONE; + break; + case nln_upper: + linestate[lineno] = changed ? LINE_DECIDED : LINE_DONE; + if (linestate[lineno + 1] == LINE_UNDECIDED || + linestate[lineno + 1] == LINE_REMEMBERED_AS_PREVIOUS || + linestate[lineno + 1] == LINE_AS_PREVIOUS) + linestate[lineno + 1] = LINE_DECIDED; //LINE_BLACK; + break; + case nln_lower_black_always: + linestate[lineno + 1] = LINE_BLACK; + linestate[lineno] = LINE_DECIDED; + //if (lineno == (maxvpos + lof_store) * 2 - 1) + // linestate[lineno] = LINE_BLACK; + break; + case nln_lower_black: + changed |= (linestate[lineno] != LINE_DONE ? 1 : 0); + linestate[lineno + 1] = LINE_DONE; + linestate[lineno] = changed ? LINE_DECIDED : LINE_DONE; + //if (lineno == (maxvpos + lof_store) * 2 - 1) + // linestate[lineno + 1] = LINE_BLACK; + break; + case nln_upper_black_always: + linestate[lineno] = LINE_DECIDED; + if (lineno > 0) { + linestate[lineno - 1] = LINE_BLACK; + } + if (!interlace_seen && lineno == (maxvpos + lof_store) * 2 - 2) { + linestate[lineno + 1] = LINE_BLACK; + } + break; + case nln_upper_black: + changed |= (linestate[lineno] != LINE_DONE ? 1 : 0); + linestate[lineno] = changed ? LINE_DECIDED : LINE_DONE; + if (lineno > 0) { + linestate[lineno - 1] = LINE_DONE; + } + if (!interlace_seen && lineno == (maxvpos + lof_store) * 2 - 2) { + linestate[lineno + 1] = LINE_DONE; + } + break; + } + } + + function gfxbuffer_reset() { + gfxvidinfo.drawbuffer.flush_line = function(gfxinfo, vb, line_no) {}; + gfxvidinfo.drawbuffer.flush_block = function(gfxinfo, vb, first_line, last_line) {}; + gfxvidinfo.drawbuffer.flush_screen = function(gfxinfo, vb, first_line, last_line) {}; + gfxvidinfo.drawbuffer.flush_clear_screen = function(gfxinfo, vb) {}; + gfxvidinfo.drawbuffer.lockscr = function(gfxinfo, vb) { return 1; }; + gfxvidinfo.drawbuffer.unlockscr = function(gfxinfo, vb) {}; + } + + function notice_resolution_seen(res, lace) { //global + if (res > frame_res) + frame_res = res; + if (res > 0) + can_use_lores = 0; + if (!frame_res_lace && lace) + frame_res_lace = lace; + } + + function notice_interlace_seen(lace) { //global + var changed = false; + // non-lace to lace switch (non-lace active at least one frame)? + if (lace) { + if (interlace_seen == 0) { + changed = true; + //SAEF_log("playfield.notice_interlace_seen() ->lace PC=%x", SAER_CPU_getPC()); + } + interlace_seen = SAEV_config.video.vresolution ? 1 : -1; + } else { + if (interlace_seen) { + changed = true; + //SAEF_log("playfield.notice_interlace_seen() ->non-lace PC=%x", SAER_CPU_getPC()); + } + interlace_seen = 0; + } + return changed; + } + + function reset_drawing() { //global + max_diwstop = 0; + + lores_reset(); + reset_decision_table(); + init_aspect_maps(); + + oldbufmem = null; //OWN + oldheight = 0, oldpitch = 0; //OWN + oldgenlock = false; //OWN + + init_row_map(); + last_redraw_point = 0; + + //memset(spixels, 0, sizeof spixels); + //memset(&spixstate, 0, sizeof spixstate); + SAEF_memset(spixels,0, 0, 2 * MAX_SPR_PIXELS); + SAEF_memset(spixstate.bytes,0, 0, 2 * MAX_SPR_PIXELS); + + init_drawing_frame(); + pfield_set_linetoscr(); + notice_screen_contents_lost(); + + frame_res_cnt = 1; //currprefs.gfx_autoresolution_delay; //OWN + //lightpen_y1 = lightpen_y2 = -1; //OWN + + reset_custom_limits(); + + clearbuffer(gfxvidinfo.drawbuffer); + clearbuffer(gfxvidinfo.tempbuffer); + + center_reset = true; + specialmonitoron = false; + bplcolorburst_field = true; + + warned_pfield_draw_line = 0; //OWN + } + + function gen_direct_drawing_table() { + //#ifdef AGA + // BYPASS color table + for (var i = 0; i < 256; i++) { + var v = ((i << 16) | (i << 8) | i) >>> 0; + direct_colors_for_drawing.acolors[i] = CONVERT_RGB(v); + } + //#endif + } + + function drawing_init() { //global + refresh_indicator_init(); + gen_pfield_tables(); + gen_direct_drawing_table(); + //#ifdef PICASSO96 + SAEV_Playfield_picasso_on = false; + SAEV_Playfield_picasso_requested_on = false; + //gfx_set_picasso_state(0); + //#endif + + //xlinebuffer = gfxvidinfo.drawbuffer.bufmem; + //xlinebuffer_genlock = null; + if (gfxvidinfo.drawbuffer.bufmem !== null) { + if (gfxvidinfo.drawbuffer.pixbytes == 2) + xlinebuffer = new Uint16Array(gfxvidinfo.drawbuffer.bufmem); + else + xlinebuffer = new Uint32Array(gfxvidinfo.drawbuffer.bufmem); + } else + xlinebuffer = null; + + inhibit_frame = 0; + gfxbuffer_reset(); + reset_drawing(); + } + + function isvsync_chipset() { //global + var ap = SAEV_config.video.apmode[0]; + if (SAEV_Playfield_picasso_on || !ap.gfx_vsync) + return 0; + if (ap.gfx_vsyncmode == 0) + return 1; + if (SAEV_config.cpu.speed >= 0) + return -1; + return -2; + } + SAER_Playfield_isvsync_chipset = isvsync_chipset; + + function isvsync_rtg() { //global + var ap = SAEV_config.video.apmode[1]; + if (!SAEV_Playfield_picasso_on || !ap.gfx_vsync) + return 0; + if (ap.gfx_vsyncmode == 0) + return 1; + if (SAEV_config.cpu.speed >= 0) + return -1; + return -2; + } + + function isvsync() { //global + if (SAEV_Playfield_picasso_on) + return isvsync_rtg(); + else + return isvsync_chipset(); + } + SAER_Playfield_isvsync = isvsync; + + /* drawing code */ /*-----------------------------------------------------------------------*/ - /* playfield */ /*-----------------------------------------------------------------------*/ - - /*function debug_cycle_diagram() { - var fm, res, planes, cycle, v; - var aa, txt = ''; + /*-----------------------------------------------------------------------*/ + /* SECT playfield defs */ + + const AUTOSCALE_SPRITES = true; + //const SPRBORDER = 0; + + const MAXHPOS_ROWS = 256; + const MAXVPOS_LINES_ECS = 2048; + const MAXVPOS_LINES_OCS = 512; + const HPOS_SHIFT = 3; + + /* PAL/NTSC values */ + const MAXHPOS_PAL = 227; + const MAXHPOS_NTSC = 227; + + const MAXVPOS_PAL = 312; // short field maxvpos + const MAXVPOS_NTSC = 262; + + const VBLANK_ENDLINE_PAL = 26; // following endlines = first visible line + const VBLANK_ENDLINE_NTSC = 21; + + const VBLANK_SPRITE_PAL = 25; // line when sprite DMA fetches first control words + const VBLANK_SPRITE_NTSC = 20; + const VBLANK_HZ_PAL = 50; + const VBLANK_HZ_NTSC = 60; + const VSYNC_ENDLINE_PAL = 5; + const VSYNC_ENDLINE_NTSC = 6; + const EQU_ENDLINE_PAL = 8; + const EQU_ENDLINE_NTSC = 10; + + /* calculate shift depending on resolution (replaced "decided_hires ? 4 : 8") */ + //function RES_SHIFT(res) { return res == SAEC_Config_Video_HResolution_LoRes ? 8 : (res == SAEC_Config_Video_HResolution_HiRes ? 4 : 2); } + + /* get resolution from bplcon0 */ + function GET_RES_DENISE(con0) { + if (!(SAEV_config.chipset.mask & SAEC_Config_Chipset_Mask_ECS_DENISE)) + con0 &= ~0x40; // SUPERHIRES + return (con0 & 0x40) ? SAEC_Config_Video_HResolution_SuperHiRes : ((con0 & 0x8000) ? SAEC_Config_Video_HResolution_HiRes : SAEC_Config_Video_HResolution_LoRes); + } + function GET_RES_AGNUS(con0) { + if (!(SAEV_config.chipset.mask & SAEC_Config_Chipset_Mask_ECS_AGNUS)) + con0 &= ~0x40; // SUPERHIRES + return (con0 & 0x40) ? SAEC_Config_Video_HResolution_SuperHiRes : ((con0 & 0x8000) ? SAEC_Config_Video_HResolution_HiRes : SAEC_Config_Video_HResolution_LoRes); + } + /* get sprite width from FMODE */ + //#define GET_SPRITEWIDTH(FMODE) ((((FMODE) >> 2) & 3) == 3 ? 64 : (((FMODE) >> 2) & 3) == 0 ? 16 : 32) + function GET_SPRITEWIDTH(fm) { + fm = (fm >> 2) & 3; + return fm == 3 ? 64 : (fm == 0 ? 16 : 32); + } + + /* Compute the number of bitplanes from a value written to BPLCON0 */ + function GET_PLANES(bplcon0) { + if ((bplcon0 & 0x0010) && (bplcon0 & 0x7000)) + return 0; // >8 planes = 0 planes + if (bplcon0 & 0x0010) + return 8; // AGA 8-planes bit + return (bplcon0 >> 12) & 7; // normal planes bits + } + + /* playfield defs */ + /*-----------------------------------------------------------------------*/ + /*-----------------------------------------------------------------------*/ + /*-----------------------------------------------------------------------*/ + /* SECT playfield code */ + + function nocustom() { + return false; //(SAEV_Playfield_picasso_on && currprefs.picasso96_nocustom); + } + + /*#if 0 + struct customhack { + uae_u16 v; + int vpos, hpos; + }; + void customhack_put (struct customhack *ch, uae_u16 v, int hpos) + { + ch->v = v; + ch->vpos = vpos; + ch->hpos = hpos; + } + + uae_u16 customhack_get (struct customhack *ch, int hpos) + { + if (ch->vpos == vpos && ch->hpos == hpos) { + ch->vpos = -1; + return 0xffff; + } + return ch->v; + } + #endif*/ + + //static unsigned int n_consecutive_skipped = 0; + //static unsigned int total_skipped = 0; + + + var hpos_offset = 0; //global int + var vpos = 0; //global int + var vpos_count = 0, vpos_count_diff = 0; //int + var lof_store = 0; //global int, real bit in custom registers + var lof_current = 0; //int, what display device thinks + var lof_lastline = false, lof_prev_lastline = false; //bool + var lol = 0; //int + var next_lineno = 0, prev_lineno = 0; //int + var nextline_how = 0; //enum nln_how + var lof_changed = 0, lof_changing = 0, interlace_changed = 0; //int + var lof_changed_previous_field = 0; //int + var vposw_change = 0; //int + var lof_lace = false; //bool + var bplcon0_interlace_seen = false; //bool + var scandoubled_line = 0; //int + var vsync_rendered = false; //bool + //-> SAEV_Playfield_frame_rendered var frame_rendered = false; //bool + //-> SAEV_Playfield_frame_shown var frame_shown = false; //bool + var genlockhtoggle = false; //bool + var genlockvtoggle = false; //bool + var graphicsbuffer_retry = false; //bool + var scanlinecount = 0; //int + + const LOF_TOGGLES_NEEDED = 3; + //const NLACE_CNT_NEEDED = 50; + var lof_togglecnt_lace = 0, lof_togglecnt_nlace = 0; //, nlace_cnt = 0; //int + + /* Stupid genlock-detection prevention hack. + * We should stop calling vsync_handler() and + * hstop_handler() completely but it is not + * worth the trouble.. + */ + var vpos_previous = 0, hpos_previous = 0; //int + var vpos_lpen = 0, hpos_lpen = 0, lightpen_triggered = 0; //int + var lightpen_x = -1, lightpen_y = -1, lightpen_cx = 0, lightpen_cy = 0, lightpen_active = 0, lightpen_enabled = 0; //global int + + var sprtaba = null, sprtabb = null; //u32 [256] + var sprite_ab_merge = null; //u32 [256] + /* Tables for collision detection. */ + var sprclx = null, clxmask = null; //u32 [16] + + /* T genlock bit in ECS Denise and AGA color registers */ + var color_regs_genlock = new Uint8Array(256); //u8 + + /* + * Hardware registers of all sorts. + */ + var cregs = new Uint16Array(256); //u16 + + //->custom.js var last_custom_value1 = 0; //global u32 + + var maxhpos = MAXHPOS_PAL; //global int + var maxhpos_short = MAXHPOS_PAL; //global int + var maxvpos = MAXVPOS_PAL; //global int + var maxvpos_nom = MAXVPOS_PAL; //global int, nominal value (same as maxvpos but "faked" maxvpos in fake 60hz modes) + var maxvpos_display = MAXVPOS_PAL; //global int, value used for display size + var hsyncendpos = 0, hsyncstartpos = 0; //global int + var maxvpos_total = 511; //int + var minfirstline = VBLANK_ENDLINE_PAL; //global int + var firstblankedline = 0; //global int + var equ_vblank_endline = EQU_ENDLINE_PAL; //int + var equ_vblank_toggle = true; //bool + var vblank_hz = VBLANK_HZ_PAL, vblank_hz_stored = 0.0, vblank_hz_nom = 0.0; //global double + //->SAEV_Playfield_fake_vblank_hz var fake_vblank_hz = 0.0; //global double + var hblank_hz = 0.0; //global double + var vblank_hz_lof = 0.0, vblank_hz_shf = 0.0, vblank_hz_lace = 0.0; //float + var vblank_hz_mult = 0, vblank_hz_state = 0; //int + var stored_chipset_refresh = null; //struct chipset_refresh * + var doublescan = 0; //global int + var programmedmode = false; //global bool + //-> events.js var syncbase = 0; //global int + var fmode_saved = 0, fmode = 0; //int + var beamcon0 = 0, new_beamcon0 = 0; //global u16 + var varsync_changed = false; //bool + var vtotal = MAXVPOS_PAL, htotal = MAXHPOS_PAL; //u16 + var maxvpos_stored = 0, maxhpos_stored = 0; //int + var hsstop = 0, hbstrt = 0, hbstop = 0, vsstop = 0, vbstrt = 0, vbstop = 0, hsstrt = 0, vsstrt = 0, hcenter = 0; //u16 + var ciavsyncmode = 0; //int + var diw_hstrt = 0, diw_hstop = 0; //int + var diw_hcounter = 0; //int + var refptr = 0; //u16 + var refptr_val = 0; //u32 + + function sprite() { + this.pt = 0; //uaecptr + this.xpos = 0; //all int + this.vstart = 0; + this.vstop = 0; + this.dblscan = 0; /* AGA SSCAN2 */ + this.armed = 0; + this.dmastate = 0; + this.dmacycle = 0; + this.ptxhpos = 0; + this.ptxhpos2 = 0; + this.ptxvpos2 = 0; + this.ignoreverticaluntilnextline = false; //bool + + this.clr = function() { + this.pt = 0; + this.xpos = 0; + this.vstart = 0; + this.vstop = 0; + this.dblscan = 0; + this.armed = 0; + this.dmastate = 0; + this.dmacycle = 0; + this.ptxhpos = 0; + this.ptxhpos2 = 0; + this.ptxvpos2 = 0; + this.ignoreverticaluntilnextline = false; + } + }; + const SPR0_HPOS = 0x15; + + var spr = new Array(MAX_SPRITES); //struct sprite [MAX_SPRITES] + for (var vi = 0; vi < MAX_SPRITES; vi++) + spr[vi] = new sprite(); + + var plfstrt_sprite = 0; //int + var sprite_ignoreverticaluntilnextline = false; //bool + + var sprite_0 = 0; //global uaecptr + var sprite_0_width = 0, sprite_0_height = 0, sprite_0_doubled = 0; //global int + var sprite_0_colors = new Uint32Array(4); //global u32 + var magic_sprite_mask = 0xff; //u8 + + var sprite_vblank_endline = VBLANK_SPRITE_PAL; //int + + var sprctl = new Uint16Array(MAX_SPRITES); //u16 + var sprpos = new Uint16Array(MAX_SPRITES); //u16 + //#ifdef AGA + var sprdata = new Array(MAX_SPRITES); //u16 [MAX_SPRITES][4] + for (var vi = 0; vi < MAX_SPRITES; vi++) sprdata[vi] = new Uint16Array(4); + var sprdatb = new Array(MAX_SPRITES); //u16 [MAX_SPRITES][4] + for (var vi = 0; vi < MAX_SPRITES; vi++) sprdatb[vi] = new Uint16Array(4); + /*#else + var sprdata = new Array(MAX_SPRITES); //u16 [MAX_SPRITES][1] + for (var vi = 0; vi < MAX_SPRITES; vi++) sprdata[vi] = new Uint16Array(1); + var sprdatb = new Array(MAX_SPRITES); //u16 [MAX_SPRITES][1] + for (var vi = 0; vi < MAX_SPRITES; vi++) sprdatb[vi] = new Uint16Array(1); + #endif*/ + + //var sprite_last_drawn_at = new Int32Array(MAX_SPRITES); //int + var last_sprite_point = 0, nr_armed = 0; //int + var sprite_width = 0, sprres = 0; //int + var sprite_sprctlmask = 0; //int + var sprite_buffer_res = 0; //global int + + var bpl1dat_written = false, bpl1dat_written_at_least_once = false; //bool + var bpldmawasactive = false; //bool + var bpl1mod = 0, bpl2mod = 0, dbpl1mod = 0, dbpl2mod = 0; //s16 + var dbpl1mod_on = 0, dbpl2mod_on = 0; //int + var prevbpl = new Array(2); //uaecptr [2][MAXVPOS][8] + for (var vi = 0; vi < prevbpl.length; vi++) { + prevbpl[vi] = new Array(MAXVPOS); + for (var vj = 0; vj < prevbpl[vi].length; vj++) { + prevbpl[vi][vj] = new Array(8); + for (var vk = 0; vk < prevbpl[vi][vj].length; vk++) prevbpl[vi][vj][vk] = 0; + } + } + var bplpt = new Array(8); //uaecptr + var bplptx = new Array(8); //uaecptr + for (var vi = 0; vi < 8; vi++) { + bplpt[vi] = 0; + bplptx[vi] = 0; + } + + /*#if 0 + var dbplptl[8], dbplpth[8]; //uaecptr + var dbplptl_on[8], dbplpth_on[8], dbplptl_on2, dbplpth_on2; //int + #endif*/ + var bitplane_line_crossing = 0; //int + + var current_colors = new color_entry(); //struct color_entry + var bplcon0 = 0; //global uint + var bplcon1 = 0, bplcon2 = 0, bplcon3 = 0, bplcon4 = 0; //uint + var bplcon0d = 0, bplcon0dd = 0, bplcon0_res = 0, bplcon0_planes = 0, bplcon0_planes_limit = 0; //uint + var diwstrt = 0, diwstop = 0, diwhigh = 0; //uint + var diwhigh_written = 0; //int + var ddfstrt, ddfstop = 0; //uint + var line_cyclebased = 0, badmode = 0, diw_change = 0; //int + var bplcon1_fetch = 0; //int + var hpos_is_zero_bplcon1_hack = -1; //int + + /* The display and data fetch windows */ + var plffirstline = 0, plflastline = 0; //int + var plffirstline_total = 0, plflastline_total = 0; //global int + var autoscale_bordercolors = 0; //int + var plfstrt = 0, plfstop = 0; //int + var sprite_minx = 0, sprite_maxx = 0; //int + var first_bpl_vpos = 0; //int + var last_ddf_pix_hpos = 0; //int + var last_decide_line_hpos = 0; //int + var last_fetch_hpos = 0, last_sprite_hpos = 0; //int + var diwfirstword = 0, diwlastword = 0; //int + var last_hdiw = 0; //int + var diwstate = 0, hdiwstate = 0, ddfstate = 0; //enum diw_states + var bpl_hstart = 0; //int + + var first_planes_vpos = 0, last_planes_vpos = 0; //global int + var first_bplcon0 = 0, first_bplcon0_old = 0; //int + var first_planes_vpos_old = 0, last_planes_vpos_old = 0; //int + var diwfirstword_total = 0, diwlastword_total = 0; //global int + var ddffirstword_total = 0, ddflastword_total = 0; //global int + var diwfirstword_total_old = 0, diwlastword_total_old = 0; //int + var ddffirstword_total_old = 0, ddflastword_total_old = 0; //int + var vertical_changed = 0, horizontal_changed = 0; //global bool + var firstword_bplcon1 = 0; //global int + + /* Sprite collisions */ + var clxdat = 0, clxcon = 0, clxcon2 = 0, clxcon_bpl_enable = 0, clxcon_bpl_match = 0; //uint + + /* Recording of custom chip register changes. */ + var current_change_set = 0; //int + + var sprite_entries = new Array(2); //struct sprite_entry [2][MAX_SPR_PIXELS / 16]; + for (var vi = 0; vi < sprite_entries.length; vi++) { + sprite_entries[vi] = new Array(MAX_SPR_PIXELS >> 4); + for (var vj = 0; vj < sprite_entries[vi].length; vj++) sprite_entries[vi][vj] = new sprite_entry(); + } + + var color_changes = new Array(2); //struct color_change [2][MAX_REG_CHANGE]; + for (var vi = 0; vi < color_changes.length; vi++) { + color_changes[vi] = new Array(MAX_REG_CHANGE); + for (var vj = 0; vj < color_changes[vi].length; vj++) color_changes[vi][vj] = new color_change(); + } + + var line_drawinfo = new Array(2); //struct draw_info [2][2 * (MAXVPOS + 2) + 1]; + for (var vi = 0; vi < line_drawinfo.length; vi++) { + line_drawinfo[vi] = new Array(2 * (MAXVPOS + 2) + 1); + for (var vj = 0; vj < line_drawinfo[vi].length; vj++) line_drawinfo[vi][vj] = new draw_info(); + } + + const COLOR_TABLE_SIZE = (MAXVPOS + 2) * 2; + var color_tables = new Array(2); //struct color_entry [2][COLOR_TABLE_SIZE]; + for (var vi = 0; vi < color_tables.length; vi++) { + color_tables[vi] = new Array(COLOR_TABLE_SIZE); + for (var vj = 0; vj < color_tables[vi].length; vj++) color_tables[vi][vj] = new color_entry(); + } + + var line_decisions = new Array(2 * (MAXVPOS + 2) + 1); //struct decision [2 * (MAXVPOS + 2) + 1]; + for (var vi = 0; vi < 2 * (MAXVPOS + 2) + 1; vi++) + line_decisions[vi] = new decision(); + + var next_sprite_entry = 0; //int + var prev_next_sprite_entry = 0; //int + var next_sprite_forced = 1; //int + + var curr_sprite_entries = null, prev_sprite_entries = null; //struct sprite_entry * + var curr_color_changes = null, prev_color_changes = null; //struct color_change * + var curr_drawinfo = null, prev_drawinfo = null; //struct draw_info * + var curr_color_tables = null, prev_color_tables = null; //struct color_entry * + + var next_color_change = 0; //int + var next_color_entry = 0, remembered_color_entry = 0; //int + var color_src_match = 0, color_dest_match = 0, color_compare_result = 0; //int + + var thisline_changed = 0; //u32 + + /*OPT inline, ok + #ifdef SMART_UPDATE + #define MARK_LINE_CHANGED do { thisline_changed = 1; } while (0) + #else + #define MARK_LINE_CHANGED do { ; } while (0) + #endif*/ + + var thisline_decision = new decision(); //struct decision + var fetch_cycle = 0, fetch_modulo_cycle = 0; //int + var aga_plf_passed_stop2 = false; //bool + var plf_start_hpos = 0, plf_end_hpos = 0; //int + var ddfstop_written_hpos = 0; //int + var bitplane_off_delay = 0; //int + var ocs_agnus_ddf_enable_toggle = false; //bool + var bpl_dma_off_when_active = 0; //int + var bitplane_maybe_start_hpos = 0; //int + var ddfstop_matched = false; //bool + + var cpu_accurate = true; //OWN + + //enum plfstate + const plf_idle = 0; + //enable passed + const plf_passed_enable = 1; + //ddfstrt match + const plf_passed_start = 2; + //active (ddfstrt + 4 match) + const plf_active = 3; + //inactive = ; waiting + const plf_wait = 4; + //ddfstop passed + const plf_passed_stop = 5; + //ddfstop+4 passed + const plf_passed_stop_act = 6; + //last block finished + const plf_passed_stop2 = 7; + const plf_end = 8; + + var plf_state = plf_idle; + + //enum plfrenderstate + const plfr_idle = 0; + const plfr_active = 1; + const plfr_end = 2; + const plfr_finished = 3; + + var plfr_state = plfr_idle; + + //enum fetchstate + const fetch_not_started = 0; + const fetch_started_first = 1; + const fetch_started = 2; + const fetch_was_plane0 = 3; + + var fetch_state = fetch_not_started; + + var warned_maybe_finish_last_fetch = 20; //OWN + + /*-----------------------------------------------------------------------*/ + /* OWN global functions */ + + + this.get_maxhpos = function() { return maxhpos; } //OWN + this.get_maxhpos_short = function() { return maxhpos_short; } //OWN + this.get_maxvpos = function() { return maxvpos; } //OWN + this.get_maxvpos_nom = function() { return maxvpos_nom; } //OWN + this.get_maxvpos_display = function() { return maxvpos_display; } //OWN + this.get_vpos = function() { return vpos; } //OWN + //this.set_vpos = function(v) { vpos = v; } //OWN + //this.set_vpos_count = function(v) { vpos_count = v; } //OWN + this.get_vblank_hz = function() { return vblank_hz; } //OWN + //this.get_vblank_hz_state = function() { return vblank_hz_state; } //OWN + this.get_beamcon0 = function() { return beamcon0; } //OWN + + //this.get_bplcon0 = function() { return bplcon0; } //OWN input mouse fix + //this.get_bplcon0_res = function() { return bplcon0_res; } //OWN input mouse fix + //this.get_diwstate = function() { return diwstate; }; //OWN + + this.set_line_cyclebased = function() { line_cyclebased = 2; }; //OWN + + this.get_slowdowndata = function() { //OWN + return [ + thisline_decision.plfleft, + thisline_decision.plfright - (16 << fetchmode), + cycle_diagram_total_cycles[fetchmode][GET_RES_AGNUS(bplcon0)][GET_PLANES_LIMIT(bplcon0)], + cycle_diagram_free_cycles[fetchmode][GET_RES_AGNUS(bplcon0)][GET_PLANES_LIMIT(bplcon0)] + ]; + }; + + this.set_bitplane_maybe_start_hpos = function(hpos) { //OWN used from amiga.js + line_cyclebased = 2; //SET_LINE_CYCLEBASED(); + bitplane_maybe_start_hpos = hpos; + } + + /*-----------------------------------------------------------------------*/ + /* SECT helper functions */ + + //#define SET_LINE_CYCLEBASED line_cyclebased = 2; + //function SET_LINE_CYCLEBASED() { line_cyclebased = 2; } //OPT inline ok + + //#define HSYNCTIME (maxhpos * SAEC_Events_CYCLE_UNIT) + //function HSYNCTIME() { return maxhpos * SAEC_Events_CYCLE_UNIT; } //OPT inline ok + + this.copper_cant_read = function(hpos, alloc) { + if (hpos + 1 >= maxhpos) // first refresh slot + return 1; + if ((hpos == maxhpos - 3) && (maxhpos & 1) && alloc >= 0) { + //if (alloc) SAER.events.alloc_cycle(hpos, SAEC_Events_cycle_line_COPPER); + return -1; + } + return this.is_bitplane_dma(hpos); + } + + function isecsshres() { + return bplcon0_res == SAEC_Config_Video_HResolution_SuperHiRes && (SAEV_config.chipset.mask & SAEC_Config_Chipset_Mask_ECS_DENISE) && !(SAEV_config.chipset.mask & SAEC_Config_Chipset_Mask_AGA); + } + + function nodraw() { //OPT inline + return framecnt != 0; + } + + function doflickerfix() { + return SAEV_config.video.vresolution && doublescan < 0 && vpos < MAXVPOS; + } + + /*function void setclr(*p, val) { + if (val & 0x8000) + *p |= val & 0x7FFF; + else + *p &= ~val; + }*/ + + + + function set_chipset_mode() { + if (SAEV_config.chipset.mask & SAEC_Config_Chipset_Mask_AGA) + fmode = fmode_saved; + else + fmode = 0; + + sprite_width = GET_SPRITEWIDTH(fmode); + } + + function update_mirrors() { + aga_mode = (SAEV_config.chipset.mask & SAEC_Config_Chipset_Mask_AGA) != 0; + direct_rgb = aga_mode; + if (SAEV_config.chipset.mask & SAEC_Config_Chipset_Mask_AGA) + sprite_sprctlmask = 0x01 | 0x08 | 0x10; + else if (SAEV_config.chipset.mask & SAEC_Config_Chipset_Mask_ECS_DENISE) + sprite_sprctlmask = 0x01 | 0x10; + else + sprite_sprctlmask = 0x01; + + set_chipset_mode(); + } + + + + + function docols(colentry) { //struct color_entry * + //#ifdef AGA + if (SAEV_config.chipset.mask & SAEC_Config_Chipset_Mask_AGA) { + for (var i = 0; i < 256; i++) { + var v = color_reg_get(colentry, i); + if (v < 0 || v > 16777215) + continue; + colentry.acolors[i] = getxcolor(v); + } + } else { + //#endif + for (var i = 0; i < 32; i++) { + var v = color_reg_get(colentry, i); + if (v < 0 || v > 4095) + continue; + colentry.acolors[i] = getxcolor(v); + } + //#ifdef AGA + } + //#endif + } + + function notice_new_xcolors() { + update_mirrors(); + docols(current_colors); + docols(colors_for_drawing); + for (var i = 0; i < (MAXVPOS + 1) * 2; i++) { + docols(color_tables[0][i]); + docols(color_tables[1][i]); + } + } + this.notice_new_xcolors_ext = function() { + notice_new_xcolors(); + } + + function remember_ctable() { + /* This can happen when program crashes very badly */ + if (next_color_entry >= COLOR_TABLE_SIZE) + return; + if (remembered_color_entry < 0) { + /* The colors changed since we last recorded a color map. Record a new one. */ + //color_reg_cpy(curr_color_tables + next_color_entry, ¤t_colors); + color_reg_cpy(curr_color_tables[next_color_entry], current_colors); + remembered_color_entry = next_color_entry++; + } + thisline_decision.ctable = remembered_color_entry; + if (color_src_match < 0 || color_dest_match != remembered_color_entry || line_decisions[next_lineno].ctable != color_src_match) { + /* The remembered comparison didn"t help us - need to compare again. */ + var oldctable = line_decisions[next_lineno].ctable; + var changed = 0; + + if (oldctable < 0) { + changed = 1; + color_src_match = color_dest_match = -1; + } else { + //color_compare_result = color_reg_cmp(&prev_color_tables[oldctable], ¤t_colors) != 0; + color_compare_result = color_reg_cmp(prev_color_tables[oldctable], current_colors) != 0; + if (color_compare_result) + changed = 1; + color_src_match = oldctable; + color_dest_match = remembered_color_entry; + } + thisline_changed |= changed; + } else { + /* We know the result of the comparison */ + if (color_compare_result) + thisline_changed = 1; + } + } + function remember_ctable_for_border() { + remember_ctable(); + } + + function get_equ_vblank_endline() { + return equ_vblank_endline + (equ_vblank_toggle ? (lof_current ? 1 : 0) : 0); + } + + const DDF_OFFSET = 4; + function HARD_DDF_LIMITS_DISABLED() { return ((beamcon0 & 0x80) || (beamcon0 & 0x4000) || (bplcon0 & 0x40)); } + function HARD_DDF_STOP() { return (HARD_DDF_LIMITS_DISABLED() ? maxhpos : 0xd4); } /* The HRM says 0xD8, but that can't work... */ + //function HARD_DDF_START() { return (HARD_DDF_LIMITS_DISABLED() ? 0x04 : 0x14); } /* Programmed rates or superhires (!) disable normal DMA limits */ + const HARD_DDF_START_REAL = 0x14; + + /* Called to determine the state of the horizontal display window state + * machine at the current position. It might have changed since we last + * checked. */ + function decide_diw(hpos) { + /* Last hpos = hpos + 0.5, eg. normal PAL end hpos is 227.5 * 2 = 455 + OCS Denise: 9 bit hdiw counter does not reset during lines 0 to 9 + (PAL) or lines 0 to 10 (NTSC). A1000 PAL: 1 to 9, NTSC: 1 to 10. + ECS Denise and AGA: no above "features" + */ + var hdiw = hpos >= maxhpos ? maxhpos * 2 + 1 : hpos * 2 + 2; + if (!(SAEV_config.chipset.mask & SAEC_Config_Chipset_Mask_ECS_DENISE) && vpos <= get_equ_vblank_endline()) + hdiw = diw_hcounter; + /* always mask, bad programs may have set maxhpos = 256 */ + hdiw &= 511; + for (;;) { + var lhdiw = hdiw; + if (last_hdiw > lhdiw) + lhdiw = 512; + + if (lhdiw >= diw_hstrt && last_hdiw < diw_hstrt && hdiwstate == DIW_WAITING_START) { + if (thisline_decision.diwfirstword < 0) + thisline_decision.diwfirstword = diwfirstword < 0 ? PIXEL_XPOS(0) : diwfirstword; + hdiwstate = DIW_WAITING_STOP; + } + if (((hpos >= maxhpos && HARD_DDF_LIMITS_DISABLED()) || (lhdiw >= diw_hstop && last_hdiw < diw_hstop)) && hdiwstate == DIW_WAITING_STOP) { + if (thisline_decision.diwlastword < 0) + thisline_decision.diwlastword = diwlastword < 0 ? 0 : diwlastword; + hdiwstate = DIW_WAITING_START; + } + if (lhdiw != 512) + break; + last_hdiw = 0 - 1; + } + last_hdiw = hdiw; + } + + var fetchmode = 0, fetchmode_size = 0, fetchmode_mask = 0, fetchmode_bytes = 0; //int + var real_bitplane_number = []; //[3][3][9]; //int [3][3][9] + + /* Disable bitplane DMA if planes > available DMA slots. This is needed e.g. by the Sanity WOC demo (at the "Party Effect"). */ + function GET_PLANES_LIMIT(bc0) { + var res = GET_RES_AGNUS(bc0); + var planes = GET_PLANES(bc0); + return real_bitplane_number[fetchmode][res][planes]; + } + + /*#if 0 + static void reset_dbplh(int hpos, int num) { + if (dbplpth_on[num] && hpos >= dbplpth_on[num]) { + bplpt[num] = dbplpth[num] | (bplpt[num] & 0x0000fffe); + dbplpth_on[num] = 0; + dbplpth_on2--; + } + } + static void reset_dbplh_all (int hpos) { + if (dbplpth_on2) { + for (int num = 0; num < MAX_PLANES; num++) { + reset_dbplh(hpos, num); + } + dbplpth_on2 = 0; + } + } + static void reset_dbpll (int hpos, int num) { + if (dbplptl_on[num] && hpos >= dbplptl_on[num]) { + bplpt[num] = (bplpt[num] & 0xffff0000) | dbplptl[num]; + dbplptl_on[num] = 0; + dbplptl_on2--; + } + } + static void reset_dbpll_all (int hpos) { + if (dbplptl_on2) { + for (int num = 0; num < MAX_PLANES; num++) { + reset_dbpll(hpos, num); + } + dbplptl_on2 = 0; + } + } + #endif*/ + + function reset_moddelays() { + if (dbpl1mod_on > 0) { + bpl1mod = dbpl1mod; + dbpl1mod_on = 0; + } + if (dbpl2mod_on > 0) { + bpl2mod = dbpl2mod; + dbpl2mod_on = 0; + } + } + + function add_modulo(hpos, nr) { + var mod; + + if (dbpl1mod_on != hpos && dbpl1mod_on) { + bpl1mod = dbpl1mod; + dbpl1mod_on = 0; + } + if (dbpl2mod_on != hpos && dbpl2mod_on) { + bpl2mod = dbpl2mod; + dbpl2mod_on = 0; + } + if (fmode & 0x4000) { + if (((diwstrt >> 8) ^ vpos) & 1) + mod = bpl2mod; + else + mod = bpl1mod; + } else if (nr & 1) + mod = bpl2mod; + else + mod = bpl1mod; + bplpt[nr] += mod; + bplptx[nr] += mod; + reset_moddelays(); + /*#if 0 + reset_dbpll_all (-1); + #endif*/ + } + + function add_modulos() { //speedup + var m1, m2; + + reset_moddelays(); + /*#if 0 + reset_dbpll_all(-1); + #endif*/ + if (fmode & 0x4000) { + if (((diwstrt >> 8) ^ vpos) & 1) + m1 = m2 = bpl2mod; + else + m1 = m2 = bpl1mod; + } else { + m1 = bpl1mod; + m2 = bpl2mod; + } + + switch (bplcon0_planes_limit) { + //#ifdef AGA + case 8: bplpt[7] += m2; bplptx[7] += m2; + case 7: bplpt[6] += m1; bplptx[6] += m1; + //#endif + case 6: bplpt[5] += m2; bplptx[5] += m2; + case 5: bplpt[4] += m1; bplptx[4] += m1; + case 4: bplpt[3] += m2; bplptx[3] += m2; + case 3: bplpt[2] += m1; bplptx[2] += m1; + case 2: bplpt[1] += m2; bplptx[1] += m2; + case 1: bplpt[0] += m1; bplptx[0] += m1; + } + } + + function finish_playfield_line() { + /* The latter condition might be able to happen in interlaced frames. */ + if (vpos >= minfirstline && (thisframe_first_drawn_line < 0 || vpos < thisframe_first_drawn_line)) + thisframe_first_drawn_line = vpos; + thisframe_last_drawn_line = vpos; + + if (SMART_UPDATE) { + if (line_decisions[next_lineno].plflinelen != thisline_decision.plflinelen + || line_decisions[next_lineno].plfleft != thisline_decision.plfleft + || line_decisions[next_lineno].bplcon0 != thisline_decision.bplcon0 + || line_decisions[next_lineno].bplcon2 != thisline_decision.bplcon2 + //#ifdef ECS_DENISE + || line_decisions[next_lineno].bplcon3 != thisline_decision.bplcon3 + //#endif + //#ifdef AGA + || line_decisions[next_lineno].bplcon4 != thisline_decision.bplcon4 + //#endif + ) + thisline_changed = 1; + } else + thisline_changed = 1; + } + + this.isvga = function() { + if (!(beamcon0 & 0x80)) + return false; + if (hblank_hz >= 20000) + return true; + return false; + } + this.ispal = function() { + if (beamcon0 & 0x80) + return SAEV_config.chipset.ntsc == 0; + return maxvpos_display >= MAXVPOS_NTSC + ((MAXVPOS_PAL - MAXVPOS_NTSC) >> 1); + } + + /*-----------------------------------------------------------------------*/ + /* SECT setup */ + + /* The fetch unit mainly controls ddf stop. It"s the number of cycles that + are contained in an indivisible block during which ddf is active. E.g. + if DDF starts at 0x30, and fetchunit is 8, then possible DDF stops are + 0x30 + n * 8. */ + var fetchunit = 0, fetchunit_mask = 0; //int + /* The delay before fetching the same bitplane again. Can be larger than + the number of bitplanes; in that case there are additional empty cycles + with no data fetch (this happens for high fetchmodes and low + resolutions). */ + var fetchstart = 0, fetchstart_shift = 0, fetchstart_mask = 0; //int + /* fm_maxplane holds the maximum number of planes possible with the current + fetch mode. This selects the cycle diagram: + 8 planes: 73516240 + 4 planes: 3120 + 2 planes: 10. */ + var fm_maxplane = 0, fm_maxplane_shift = 0; //int + + /* The corresponding values, by fetchmode and display resolution. */ + const fetchunits = [8,8,8,0, 16,8,8,0, 32,16,8,0]; //int + const fetchstarts = [3,2,1,0, 4,3,2,0, 5,4,3,0]; //int + const fm_maxplanes = [3,2,1,0, 3,3,2,0, 3,3,3,0]; //int + + var cycle_diagram_table = null; //int [3][3][9][32] + var cycle_diagram_free_cycles = null; //int [3][3][9] + var cycle_diagram_total_cycles = null; //int [3][3][9] + var curr_diagram = null; //int * + //const cycle_sequences = [2,1,2,1,2,1,2,1, 4,2,3,1,4,2,3,1, 8,4,6,2,7,3,5,1]; //int + const cycle_sequences = [[2,1,2,1,2,1,2,1], [4,2,3,1,4,2,3,1], [8,4,6,2,7,3,5,1]]; //int + + function debug_cycle_diagram() { + var fm, res, planes, cycle, v, aa; for (fm = 0; fm <= 2; fm++) { - txt += sprintf('FMODE %d\n=======\n', fm); + var t = ""; + t += sprintf("FMODE %d\n=======\n", fm); for (res = 0; res <= 2; res++) { for (planes = 0; planes <= 8; planes++) { - txt += sprintf('%d: ',planes); + t += sprintf("%d: ",planes); for (cycle = 0; cycle < 32; cycle++) { v = cycle_diagram_table[fm][res][planes][cycle]; - if (v == 0) aa='-'; else if (v > 0) aa='1'; else aa='X'; - txt += sprintf('%s', aa); + if (v == 0) aa = "-"; else if (v > 0) aa = "1"; else aa = "X"; + t += aa; } - txt += sprintf(' %d:%d\n', cycle_diagram_free_cycles[fm][res][planes], cycle_diagram_total_cycles[fm][res][planes]); + t += sprintf("%d:%d\n", cycle_diagram_free_cycles[fm][res][planes], cycle_diagram_total_cycles[fm][res][planes]); } - txt += sprintf('\n'); + SAEF_log(t); } } - BUG.info(txt); - }*/ - + fm = 0; + } + function create_cycle_diagram_table() { - var fm, res, cycle, planes, rplanes, v; - var fetch_start, max_planes, freecycles; - var cycle_sequence; - var i, j, k, l; - - for (i = 0; i < 3; i++) { - real_bitplane_number[i] = []; - cycle_diagram_free_cycles[i] = []; - cycle_diagram_total_cycles[i] = []; - for (j = 0; j < 3; j++) { - real_bitplane_number[i][j] = []; - cycle_diagram_free_cycles[i][j] = []; - cycle_diagram_total_cycles[i][j] = []; - for (k = 0; k < 9; k++) { - real_bitplane_number[i][j][k] = 0; - cycle_diagram_free_cycles[i][j][k] = 0; - cycle_diagram_total_cycles[i][j][k] = 0; - } - } - } - cycle_diagram_table = []; - for (i = 0; i < 3; i++) { - cycle_diagram_table[i] = []; - for (j = 0; j < 3; j++) { - cycle_diagram_table[i][j] = []; - for (k = 0; k < 9; k++) { - cycle_diagram_table[i][j][k] = []; - for (l = 0; l < 32; l++) - cycle_diagram_table[i][j][k][l] = 0; - } - } - } - + var fm, res, cycle, planes, rplanes, v; //int + var fetch_start, max_planes, freecycles; //int + var cycle_sequence; //const int * + + if (cycle_diagram_table !== null) return; + + cycle_diagram_table = new Array(3); + cycle_diagram_free_cycles = new Array(3); + cycle_diagram_total_cycles = new Array(3); + real_bitplane_number = new Array(3); + for (fm = 0; fm <= 2; fm++) { + cycle_diagram_table[fm] = new Array(3); + cycle_diagram_free_cycles[fm] = new Array(3); + cycle_diagram_total_cycles[fm] = new Array(3); + real_bitplane_number[fm] = new Array(3); + for (res = 0; res <= 2; res++) { + cycle_diagram_table[fm][res] = new Array(9); + cycle_diagram_free_cycles[fm][res] = new Array(9); + cycle_diagram_total_cycles[fm][res] = new Array(9); + real_bitplane_number[fm][res] = new Array(9); + max_planes = fm_maxplanes[fm * 4 + res]; fetch_start = 1 << fetchstarts[fm * 4 + res]; + //cycle_sequence = &cycle_sequences[(max_planes - 1) * 8]; cycle_sequence = cycle_sequences[max_planes - 1]; max_planes = 1 << max_planes; for (planes = 0; planes <= 8; planes++) { + cycle_diagram_table[fm][res][planes] = new Array(32); + freecycles = 0; for (cycle = 0; cycle < 32; cycle++) cycle_diagram_table[fm][res][planes][cycle] = -1; @@ -3660,7 +5751,7 @@ function Playfield() { rplanes = planes; if (rplanes > max_planes) rplanes = 0; - if (rplanes == 7 && fm == 0 && res == 0 && !(AMIGA.config.chipset.mask & CSMASK_AGA)) + if (rplanes == 7 && fm == 0 && res == 0 && !(SAEV_config.chipset.mask & SAEC_Config_Chipset_Mask_AGA)) rplanes = 4; real_bitplane_number[fm][res][planes] = rplanes; } @@ -3669,1064 +5760,177 @@ function Playfield() { //debug_cycle_diagram(); } - /*---------------------------------*/ - function doMask(p, bits, shift) { - /* scale to 0..255, shift to align msb with mask, and apply mask */ + /* Used by the copper. */ + var estimated_last_fetch_cycle = 0; //int + var cycle_diagram_shift = 0; //int - //if (flashscreen) p ^= 0xff; - var val = (p << 24) >>> 0; - if (!bits) - return 0; - val >>>= (32 - bits); - val <<= shift; + function estimate_last_fetch_cycle(hpos) { + var fetchunit = fetchunits[fetchmode * 4 + bplcon0_res]; + // Last fetch is always max 8 even if fetchunit is larger. + var lastfetchunit = fetchunit >= 8 ? 8 : fetchunit; - return val >>> 0; - } - function doAlpha (alpha, bits, shift) { - return ((alpha & ((1 << bits) - 1)) << shift) >>> 0; - } - function alloc_colors64k (rw, gw, bw, rs, gs, bs, aw, as, alpha, byte_swap) { - //#define bswap_16(x) (((x) >> 8) | (((x) & 0xFF) << 8)) - //#define bswap_32(x) (((x) << 24) | (((x) << 8) & 0x00FF0000) | (((x) >> 8) & 0x0000FF00) | ((x) >> 24)) - var bpp = rw + gw + bw + aw; - //var j = 256; + if (plf_state < plf_passed_stop) { + var stop; - //video_calc_gammatable(); - for (var i = 0; i < 4096; i++) { - var r = ((i >> 8) << 4) | (i >> 8); - var g = (((i >> 4) & 0xf) << 4) | ((i >> 4) & 0x0f); - var b = ((i & 0xf) << 4) | (i & 0x0f); - //r = gamma[r + j]; - //g = gamma[g + j]; - //b = gamma[b + j]; - xcolors[i] = (doMask(r, rw, rs) | doMask(g, gw, gs) | doMask(b, bw, bs) | doAlpha(alpha, aw, as)) >>> 0; - if (byte_swap) { - if (bpp <= 16) - xcolors[i] = bswap_16(xcolors[i]); - else - xcolors[i] = bswap_32(xcolors[i]); - } - if (bpp <= 16) { - /* Fill upper 16 bits of each colour value - * with a copy of the colour. */ - xcolors[i] |= xcolors[i] * 0x00010001; - xcolors[i] >>>= 0; - } - } - //console.log('alloc_colors64k', xcolors); - } - - function update_mirrors() { - aga_mode = (AMIGA.config.chipset.mask & CSMASK_AGA) != 0; - direct_rgb = aga_mode; - } - - function docols(colentry) { -/*#ifdef AGA - if (AMIGA.config.chipset.mask & CSMASK_AGA) { - for (var i = 0; i < 256; i++) { - var v = color_reg_get (colentry, i); - if (v < 0 || v > 16777215) - continue; - colentry->acolors[i] = getxcolor (v); - } - } else { -#endif*/ - for (var i = 0; i < 32; i++) { - var v = color_reg_get(colentry, i); - if (v < 0 || v > 4095) - continue; - colentry.acolors[i] = getxcolor(v); - } -/*#ifdef AGA - } -#endif*/ - } - function notice_new_xcolors() { - update_mirrors(); - docols(current_colors); - docols(colors_for_drawing); - for (var i = 0; i < (MAXVPOS + 1) * 2; i++) { - docols(color_tables[0][i]); - docols(color_tables[1][i]); - } - } - - /*---------------------------------*/ - - function getxcolor(c) { -/*#ifdef AGA - if (direct_rgb) - return CONVERT_RGB(c); - else -#endif*/ - return xcolors[c]; - } - - function color_reg_get(ce, c) { -/*#ifdef AGA - if (aga_mode) - return ce.color_regs_aga[c]; - else -#endif*/ - return ce.color_regs_ecs[c]; - } - - function color_reg_set(ce, c, v) { -/*#ifdef AGA - if (aga_mode) - ce.color_regs_aga[c] = v; - else -#endif*/ - ce.color_regs_ecs[c] = v; - } - - function color_reg_cmp(ce1, ce2) { -/*#ifdef AGA - if (aga_mode) { - v = memcmp (ce1->color_regs_aga, ce2->color_regs_aga, sizeof (uae_u32) * 256); - } else -#endif*/ - { - //v = memcmp (ce1.color_regs_ecs, ce2.color_regs_ecs, sizeof (uae_u16) * 32); - for (var i = 0; i < 32; i++) { - if (ce1.color_regs_ecs[i] != ce2.color_regs_ecs[i]) - return 1; - } - return ce1.borderblank == ce2.borderblank ? 0 : 1; - } - } - - function color_reg_cpy(dst, src) { - dst.borderblank = src.borderblank; -/*#ifdef AGA - if (aga_mode) - //copy acolors and color_regs_aga - memcpy (dst->acolors, src->acolors, sizeof(struct ColorEntry) - sizeof(uae_u16) * 32); - else -#endif*/ - //copy first 32 acolors and color_regs_ecs - //memcpy (dst.color_regs_ecs, src.color_regs_ecs, sizeof(struct ColorEntry)); - - for (var i = 0; i < 32; i++) { - dst.acolors[i] = src.acolors[i]; - dst.color_regs_ecs[i] = src.color_regs_ecs[i]; - } - //console.log('color_reg_cpy()', dst, src); - } - - function color_reg_cpy_acolors(dst, src) { - dst.borderblank = src.borderblank; - for (var i = 0; i < dst.acolors.length; i++) - dst.acolors[i] = src.acolors[i]; - } - - /*---------------------------------*/ - - this.remember_ctable = function () { - if (next_color_entry >= COLOR_TABLE_SIZE) { - BUG.info('remember_ctable() BUG', next_color_entry); - return; - } - if (remembered_color_entry < 0) { - color_reg_cpy(curr_color_tables[next_color_entry], current_colors); - remembered_color_entry = next_color_entry++; - } - thisline_decision.ctable = remembered_color_entry; - - if (color_src_match < 0 || color_dest_match != remembered_color_entry || line_decisions[next_lineno].ctable != color_src_match) { - var oldctable = line_decisions[next_lineno].ctable; - var changed = 0; - - if (oldctable < 0) { - changed = 1; - color_src_match = color_dest_match = -1; + if (SAEV_config.chipset.mask & SAEC_Config_Chipset_Mask_ECS_AGNUS) { + // ECS: stop wins if start == stop + stop = plfstop + DDF_OFFSET < hpos || plfstop > HARD_DDF_STOP() ? HARD_DDF_STOP() : plfstop; } else { - color_compare_result = color_reg_cmp(prev_color_tables[oldctable], current_colors) != 0; - if (color_compare_result) - changed = 1; - color_src_match = oldctable; - color_dest_match = remembered_color_entry; + // OCS: start wins if start == stop + stop = plfstop + DDF_OFFSET <= hpos || plfstop > HARD_DDF_STOP() ? HARD_DDF_STOP() : plfstop; } - thisline_changed |= changed; - } else { - if (color_compare_result) - thisline_changed = 1; - } - }; + /* We know that fetching is up-to-date up until hpos, so we can use fetch_cycle. */ + var fetch_cycle_at_stop = fetch_cycle + (stop - hpos + DDF_OFFSET); + var starting_last_block_at = (fetch_cycle_at_stop + fetchunit - 1) & ~(fetchunit - 1); - this.record_color_change2 = function (hpos, regno, value) { - //if (FAST_COLORS) //en for better? - //return; + estimated_last_fetch_cycle = hpos + (starting_last_block_at - fetch_cycle) + lastfetchunit; + } else { + var starting_last_block_at = (fetch_cycle + fetchunit - 1) & ~(fetchunit - 1); + if (plf_state == plf_passed_stop2) + starting_last_block_at -= fetchunit; + + estimated_last_fetch_cycle = hpos + (starting_last_block_at - fetch_cycle) + lastfetchunit; + } + } + + /*-----------------------------------------------------------------------*/ + /* SECT toscr */ + + var outword = new Uint32Array(MAX_PLANES); //u32 + var out_nbits = 0, out_offs = 0; //int + var todisplay = new Uint16Array(MAX_PLANES); //u16 + var todisplay2 = new Uint16Array(MAX_PLANES); //u16 + var fetched = new Uint16Array(MAX_PLANES); //u16 + var todisplay_fetched = new Array(2); //bool + //#ifdef AGA + //var todisplay_aga[MAX_PLANES], todisplay2_aga[MAX_PLANES], fetched_aga[MAX_PLANES]; //u64 + var todisplay_aga_hi = new Uint32Array(MAX_PLANES); + var todisplay_aga_lo = new Uint32Array(MAX_PLANES); + var todisplay2_aga_hi = new Uint32Array(MAX_PLANES); + var todisplay2_aga_lo = new Uint32Array(MAX_PLANES); + var fetched_aga_hi = new Uint32Array(MAX_PLANES); + var fetched_aga_lo = new Uint32Array(MAX_PLANES); + //#endif + + /* Expansions from bplcon0/bplcon1. */ + var toscr_res = 0, toscr_res2p = 0; //all int + var toscr_nr_planes = 0, toscr_nr_planes2 = 0, toscr_nr_planes_agnus = 0, toscr_nr_planes_shifter = 0; + var fetchwidth = 0; + var toscr_delay = new Int32Array(2); + var toscr_delay_adjusted = new Int32Array(2); + var toscr_delay_sh = new Int32Array(2); + var delay_cycles = 0; + var delay_lastcycle = new Int32Array(2); + var bplcon1_written = false; //bool + + const PLANE_RESET_HPOS = 8; + var planesactiveatresetpoint = 0; //int + + /* The number of bits left from the last fetched words. + This is an optimization - conceptually, we have to make sure the result is + the same as if toscr is called in each clock cycle. However, to speed this + up, we accumulate display data; this variable keeps track of how much. + Thus, once we do call toscr_nbits (which happens at least every 16 bits), + we can do more work at once. */ + var toscr_nbits = 0; //int + + /*#if 0 //undocumented bitplane delay hardware feature + var delayoffset; //int + function compute_delay_offset() { + delayoffset = (16 << fetchmode) - (((plfstrt - HARD_DDF_START_REAL) & fetchstart_mask) << 1); + if (tmp == 4) delayoffset = 4; // Loons Docs + else if (tmp == 8) delayoffset = 8; + else if (tmp == 12) delayoffset = 4; //Loons Docs + else if (tmp == 16) delayoffset = 48; //Overkill AGA + else if (tmp == 24) delayoffset = 8; //AB 2 + else if (tmp == 32) delayoffset = 32; + else if (tmp == 48) delayoffset = 16; //Pinball Illusions AGA, ingame + else delayoffset = 0; //what about 40 and 56? + } + #endif*/ + + function record_color_change2(hpos, regno, value) { var pos = hpos * 2; - if (regno == 0x1000 + 0x10c) pos++; // BPLCON4 change needs 1 lores pixel delay + if (regno == 0x1000 + 0x10c) + pos++; // BPLCON4 change needs 1 lores pixel delay curr_color_changes[next_color_change].linepos = pos; curr_color_changes[next_color_change].regno = regno; - curr_color_changes[next_color_change++].value = value; + curr_color_changes[next_color_change].value = value; + next_color_change++; curr_color_changes[next_color_change].regno = -1; - //console.log('record_color_change2()', next_color_change); - }; - - this.record_color_change = function (hpos, regno, value) { - if (FAST_COLORS) - return; - if (this.vpos < minfirstline || (regno < 0x1000 && this.nodraw())) - return; - - this.decide_diw(hpos); - this.decide_line(hpos); - - if (thisline_decision.ctable < 0) - this.remember_ctable(); - - if ((regno < 0x1000 || regno == 0x1000 + 0x10c) && hpos < HBLANK_OFFSET && !(beamcon0 & 0x80) && prev_lineno >= 0) { - var pdip = curr_drawinfo[prev_lineno]; - var idx = pdip.last_color_change; - var extrahpos = regno == 0x1000 + 0x10c ? 1 : 0; - var lastsync = false; - - if (idx > 0 && curr_color_changes[idx - 1].regno == 0xffff) { - idx--; - lastsync = true; - } - pdip.last_color_change++; - pdip.nr_color_changes++; - curr_color_changes[idx].linepos = (hpos + this.maxhpos) * 2 + extrahpos; - curr_color_changes[idx].regno = regno; - curr_color_changes[idx].value = value; - if (lastsync) { - curr_color_changes[idx + 1].linepos = hsyncstartpos * 2; - curr_color_changes[idx + 1].regno = 0xffff; - curr_color_changes[idx + 2].regno = -1; - } else - curr_color_changes[idx + 1].regno = -1; - } - this.record_color_change2(hpos, regno, value); - }; - - this.isbrdblank = function (hpos, con0, con3) { - var brdblank = (AMIGA.config.chipset.mask & CSMASK_ECS_DENISE) != 0 && (con0 & 1) != 0 && (con3 & 0x20) != 0; - - if (hpos >= 0 && current_colors.borderblank != brdblank) { - if (!FAST_COLORS) { - this.record_color_change(hpos, 0, (COLOR_CHANGE_BRDBLANK | (brdblank ? 1 : 0)) >>> 0); - remembered_color_entry = -1; - } - current_colors.borderblank = brdblank; - } - return brdblank; - }; - - this.record_register_change = function (hpos, regno, value) { - if (regno == 0x100) { // BPLCON0 - if (value & 0x800) - thisline_decision.ham_seen = 1; - thisline_decision.ehb_seen = is_ehb(value, bplcon2); - this.isbrdblank(hpos, value, bplcon3); - } else if (regno == 0x104) // BPLCON2 - thisline_decision.ehb_seen = is_ehb(bplcon0, value); - else if (regno == 0x106) // BPLCON3 - this.isbrdblank(hpos, bplcon0, value); - - if (!FAST_COLORS) - this.record_color_change(hpos, regno + 0x1000, value); - }; - - /*---------------------------------*/ - - this.compute_vsynctime = function () { - if (AMIGA.config.chipset.refreshrate > 0) - this.vblank_hz = AMIGA.config.chipset.refreshrate; - - AMIGA.events.calc_vsynctimebase(this.vblank_hz); - - if (AMIGA.config.audio.enabled && AMIGA.config.audio.mode > 0) - AMIGA.audio.calc_sample_evtime(this.vblank_hz, (bplcon0 & 4) ? -1 : this.lof_store, this.is_linetoggle()); - }; - - this.compute_framesync = function () { - var islace = interlace_seen ? 1 : 0; - var isntsc = (beamcon0 & 0x20) ? 0 : 1; - - interlace_changed = 0; - gfxvidinfo.drawbuffer.inxoffset = -1; - gfxvidinfo.drawbuffer.inyoffset = -1; - - if (beamcon0 & 0x80) { - //var res = GET_RES_AGNUS(bplcon0); - //var vres = islace ? 1 : 0; - var res2, vres2; - - res2 = AMIGA.config.video.hresolution; - if (doublescan > 0) - res2++; - if (res2 > RES_MAX) - res2 = RES_MAX; - - vres2 = AMIGA.config.video.vresolution; - if (doublescan > 0 && !islace) - vres2--; - - if (vres2 < 0) - vres2 = 0; - if (vres2 > VRES_QUAD) - vres2 = VRES_QUAD; - - var start = this.hbstrt; - var stop = this.hbstop; - - gfxvidinfo.drawbuffer.inwidth = (((start > stop ? (this.maxhpos - (this.maxhpos - start + stop)) : (this.maxhpos - (stop - start) + 2)) * 2) << res2); - gfxvidinfo.drawbuffer.inxoffset = ((stop + 1) & ~1) * 2; - - gfxvidinfo.drawbuffer.extrawidth = 0; - gfxvidinfo.drawbuffer.inwidth2 = gfxvidinfo.drawbuffer.inwidth; - - gfxvidinfo.drawbuffer.inheight = (this.maxvpos - minfirstline) << vres2; - gfxvidinfo.drawbuffer.inheight2 = gfxvidinfo.drawbuffer.inheight; - } else { - gfxvidinfo.drawbuffer.inwidth = AMIGA_WIDTH_MAX << AMIGA.config.video.hresolution; - gfxvidinfo.drawbuffer.extrawidth = AMIGA.config.video.extrawidth ? AMIGA.config.video.extrawidth : -1; - gfxvidinfo.drawbuffer.inwidth2 = gfxvidinfo.drawbuffer.inwidth; - gfxvidinfo.drawbuffer.inheight = (this.maxvpos_nom - minfirstline + 1) << AMIGA.config.video.vresolution; - gfxvidinfo.drawbuffer.inheight2 = gfxvidinfo.drawbuffer.inheight; - } - - if (gfxvidinfo.drawbuffer.inwidth > gfxvidinfo.drawbuffer.width_allocated) - gfxvidinfo.drawbuffer.inwidth = gfxvidinfo.drawbuffer.width_allocated; - if (gfxvidinfo.drawbuffer.inwidth2 > gfxvidinfo.drawbuffer.width_allocated) - gfxvidinfo.drawbuffer.inwidth2 = gfxvidinfo.drawbuffer.width_allocated; - - if (gfxvidinfo.drawbuffer.inheight > gfxvidinfo.drawbuffer.height_allocated) - gfxvidinfo.drawbuffer.inheight = gfxvidinfo.drawbuffer.height_allocated; - if (gfxvidinfo.drawbuffer.inheight2 > gfxvidinfo.drawbuffer.height_allocated) - gfxvidinfo.drawbuffer.inheight2 = gfxvidinfo.drawbuffer.height_allocated; - - gfxvidinfo.drawbuffer.outwidth = gfxvidinfo.drawbuffer.inwidth; - gfxvidinfo.drawbuffer.outheight = gfxvidinfo.drawbuffer.inheight; - - if (gfxvidinfo.drawbuffer.outwidth > gfxvidinfo.drawbuffer.width_allocated) - gfxvidinfo.drawbuffer.outwidth = gfxvidinfo.drawbuffer.width_allocated; - - if (gfxvidinfo.drawbuffer.outheight > gfxvidinfo.drawbuffer.height_allocated) - gfxvidinfo.drawbuffer.outheight = gfxvidinfo.drawbuffer.height_allocated; - - //if (target_graphics_buffer_update()) this.reset_drawing(); - - for (var i = 0; i < 2 * (MAXVPOS + 2) + 1; i++) //memset (line_decisions, 0, sizeof line_decisions); - line_decisions[i].clr(); - - this.compute_vsynctime(); - - BUG.info('%s mode%s%s V=%.4fHz H=%.4fHz (%dx%d+%d)', - isntsc ? 'NTSC' : 'PAL', - islace ? ' lace' : '', - doublescan > 0 ? ' dblscan' : '', - this.vblank_hz, - (AMIGA.config.video.ntsc ? CHIPSET_CLOCK_NTSC : CHIPSET_CLOCK_PAL) / (this.maxhpos + (this.is_linetoggle() ? 0.5 : 0)), - this.maxhpos, this.maxvpos, this.lof_store ? 1 : 0 - ); - }; - - this.init_hz = function (fullinit) { - var isntsc, islace; - var odbl = doublescan, omaxvpos = this.maxvpos; - var hzc = 0; - - if (fullinit) - this.vpos_count = 0; - - this.vpos_count_diff = this.vpos_count; - - doublescan = 0; - //programmedmode = false; - if ((beamcon0 & 0xA0) != (new_beamcon0 & 0xA0)) - hzc = 1; - if (beamcon0 != new_beamcon0) { - BUG.info('init_hz() BEAMCON0 %04x -> %04x', beamcon0, new_beamcon0); - this.vpos_count_diff = this.vpos_count = 0; - } - beamcon0 = new_beamcon0; - isntsc = (beamcon0 & 0x20) ? 0 : 1; - islace = (interlace_seen) ? 1 : 0; - if (!(AMIGA.config.chipset.mask & CSMASK_ECS_AGNUS)) - isntsc = AMIGA.config.video.ntsc ? 1 : 0; - if (!isntsc) { - this.maxvpos = MAXVPOS_PAL; - this.maxhpos = MAXHPOS_PAL; - this.vblank_hz = VBLANK_HZ_PAL; - minfirstline = VBLANK_ENDLINE_PAL; - sprite_vblank_endline = VBLANK_SPRITE_PAL; - equ_vblank_endline = EQU_ENDLINE_PAL; - equ_vblank_toggle = true; - } else { - this.maxvpos = MAXVPOS_NTSC; - this.maxhpos = MAXHPOS_NTSC; - this.vblank_hz = VBLANK_HZ_NTSC; - minfirstline = VBLANK_ENDLINE_NTSC; - sprite_vblank_endline = VBLANK_SPRITE_NTSC; - equ_vblank_endline = EQU_ENDLINE_NTSC; - equ_vblank_toggle = false; - } - // long/short field refresh rate adjustment - this.vblank_hz = this.vblank_hz * (this.maxvpos * 2 + 1) / ((this.maxvpos + this.lof_current) * 2); - - this.maxvpos_nom = this.maxvpos; - if (this.vpos_count > 0) { - BUG.info('init_hz() poked VPOSW at %d', this.vpos_count); - // we come here if this.vpos_count != this.maxvpos and beamcon0 didn't change (someone poked VPOSW) - if (this.vpos_count < 10) - this.vpos_count = 10; - this.vblank_hz = (isntsc ? 15734 : 15625) / this.vpos_count; - this.maxvpos_nom = this.vpos_count - (this.lof_current ? 1 : 0); - this.reset_drawing(); - } - if (beamcon0 & 0x80) { - // programmable scanrates (ECS Agnus) - if (this.vtotal >= MAXVPOS) - this.vtotal = MAXVPOS - 1; - this.maxvpos = this.vtotal + 1; - if (this.htotal >= MAXHPOS) - this.htotal = MAXHPOS - 1; - this.maxhpos = this.htotal + 1; - this.vblank_hz = 227 * 312 * 50 / (this.maxvpos * this.maxhpos); - minfirstline = this.vsstop > this.vbstop ? this.vsstop : this.vbstop; - if (minfirstline > this.maxvpos / 2) - minfirstline = this.vsstop > this.vsstop ? this.vbstop : this.vsstop; - if (minfirstline < 2) - minfirstline = 2; - if (minfirstline >= this.maxvpos) - minfirstline = this.maxvpos - 1; - sprite_vblank_endline = minfirstline - 2; - this.maxvpos_nom = this.maxvpos; - equ_vblank_endline = -1; - doublescan = this.htotal <= 164 ? 1 : 0; - //programmedmode = true; - this.dumpsync(); - hzc = 1; - } - if (this.maxvpos_nom >= MAXVPOS) - this.maxvpos_nom = MAXVPOS; - if (AMIGA.config.video.scandoubler && doublescan == 0) - doublescan = -1; - - if (doublescan != odbl || this.maxvpos != omaxvpos) - hzc = 1; - if (this.vblank_hz < 10) - this.vblank_hz = 10; - if (this.vblank_hz > 300) - this.vblank_hz = 300; - this.maxhpos_short = this.maxhpos; - if (beamcon0 & 0x80) { - if (this.hbstrt > this.maxhpos) - hsyncstartpos = this.hbstrt; - else - hsyncstartpos = this.maxhpos + this.hbstrt; - if (this.hbstop > this.maxhpos) - hsyncendpos = this.maxhpos - this.hbstop; - else - hsyncendpos = this.hbstop; - } else { - hsyncstartpos = this.maxhpos_short + 13; - hsyncendpos = 24; - } - - AMIGA.events.eventtab[EV_HSYNC].evtime = AMIGA.events.currcycle + this.maxhpos * CYCLE_UNIT; - AMIGA.events.eventtab[EV_HSYNC].oldcycles = AMIGA.events.currcycle; - AMIGA.events.schedule(); - - if (hzc) { - interlace_seen = islace; - this.reset_drawing(); - } - - this.maxvpos_total = (AMIGA.config.chipset.mask & CSMASK_ECS_AGNUS) ? 2047 : 511; - if (this.maxvpos_total > MAXVPOS) - this.maxvpos_total = MAXVPOS; - /*#ifdef PICASSO96 - if (!p96refresh_active) { - maxvpos_stored = this.maxvpos; - maxhpos_stored = this.maxhpos; - vblank_hz_stored = this.vblank_hz; - } - #endif*/ - this.compute_framesync(); - /*#ifdef PICASSO96 - init_hz_p96 (); - #endif*/ - if (fullinit) - this.vpos_count_diff = this.maxvpos_nom; - }; - - this.BPLxPTH = function (hpos, v, num) { - this.decide_line(hpos); - this.decide_fetch(hpos); - bplpt[num] = ((v << 16) | (bplpt[num] & 0xffff)) >>> 0; - bplptx[num] = ((v << 16) | (bplptx[num] & 0xffff)) >>> 0; - //BUG.info('%d:%d:BPL%dPTH %08X', hpos, this.vpos, num, bplpt[num]); - }; - - this.BPLxPTL = function (hpos, v, num) { - this.decide_line(hpos); - this.decide_fetch(hpos); - //if (AMIGA.copper.access && this.is_bitplane_dma(hpos + 1) == num + 1) return; - - bplpt[num] = ((bplpt[num] & 0xffff0000) | (v & 0xfffe)) >>> 0; - bplptx[num] = ((bplptx[num] & 0xffff0000) | (v & 0xfffe)) >>> 0; - //BUG.info('%d:%d:BPL%dPTL %08X', hpos, this.vpos, num, bplpt[num]); - }; - - this.BPLxDAT = function (hpos, v, num) { - if (num == 0 && hpos >= 7) { - this.decide_line(hpos); - this.decide_fetch(hpos); - } - bplxdat[num] = v; - if (num == 0 && hpos >= 7) { - bpl1dat_written = true; - bpl1dat_written_at_least_once = true; - if (thisline_decision.plfleft < 0) { - thisline_decision.plfleft = hpos & ~3; - this.reset_bpl_vars(); - this.compute_delay_offset(); - } - this.update_bpldats(hpos); - } - }; - - this.BPLCON0_Denise = function (hpos, v, immediate) { - if (!(AMIGA.config.chipset.mask & CSMASK_ECS_DENISE)) - v &= ~0x00F1; - else if (!(AMIGA.config.chipset.mask & CSMASK_AGA)) - v &= ~0x00B0; - v &= ~(0x0200 | 0x0100 | 0x0080 | 0x0020); - /*#if SPRBORDER - v |= 1; - #endif*/ - if (bplcon0_d == v) - return; - - bplcon0_dd = -1; - if (is_ehb(bplcon0_d, bplcon2)) - v |= 0x80; - - if (immediate) - this.record_register_change(hpos, 0x100, v); - else - this.record_register_change(hpos, 0x100, (bplcon0_d & ~(0x800 | 0x400 | 0x80)) | (v & (0x0800 | 0x400 | 0x80 | 0x01))); - - bplcon0_d = v & ~0x80; - - if (AMIGA.config.chipset.mask & CSMASK_ECS_DENISE) { - this.decide_sprites(hpos); - sprres = expand_sprres(v, bplcon3); - } - if (thisline_decision.plfleft < 0) - this.update_denise(hpos); - }; - - this.BPLCON0 = function (hpos, v) { - if (!(AMIGA.config.chipset.mask & CSMASK_ECS_DENISE)) - v &= ~0x00F1; - else if (!(AMIGA.config.chipset.mask & CSMASK_AGA)) - v &= ~0x00B0; - v &= ~(0x0080 | 0x0020); - - /*#if SPRBORDER - v |= 1; - #endif*/ - if (bplcon0 == v) - return; - - if (!this.issyncstopped()) { - vpos_previous = this.vpos; - hpos_previous = hpos; - } - - if ((bplcon0 & 4) != (v & 4)) - this.checklacecount((v & 4) != 0); - - bplcon0 = v; - - this.bpldmainitdelay(hpos); - - if (thisline_decision.plfleft < 0) - this.BPLCON0_Denise(hpos, v, true); - }; - - this.BPLCON1 = function (hpos, v) { - if (!(AMIGA.config.chipset.mask & CSMASK_AGA)) - v &= 0xff; - if (bplcon1 == v) - return; - ddf_change = this.vpos; - this.decide_line(hpos); - this.decide_fetch(hpos); - bplcon1_hpos = hpos; - bplcon1 = v; - }; - - this.BPLCON2 = function (hpos, v) { - if (!(AMIGA.config.chipset.mask & CSMASK_AGA)) - v &= 0x7f; - if (bplcon2 == v) - return; - this.decide_line(hpos); - bplcon2 = v; - this.record_register_change(hpos, 0x104, v); - }; - - this.BPLCON3 = function (hpos, v) { - if (!(AMIGA.config.chipset.mask & CSMASK_ECS_DENISE)) - return; - if (!(AMIGA.config.chipset.mask & CSMASK_AGA)) { - v &= 0x003f; - v |= 0x0c00; - } - /*#if SPRBORDER - v |= 2; - #endif*/ - if (bplcon3 == v) - return; - this.decide_line(hpos); - this.decide_sprites(hpos); - bplcon3 = v; - sprres = expand_sprres(bplcon0, bplcon3); - this.record_register_change(hpos, 0x106, v); - }; - -/*#ifdef AGA - this.BPLCON4 = function(hpos, v) { - if (!(AMIGA.config.chipset.mask & CSMASK_AGA)) - return; - if (bplcon4 == v) - return; - this.decide_line(hpos); - bplcon4 = v; - this.record_register_change(hpos, 0x10c, v); } -#endif*/ - function castWord(v) { return (v & 0x8000) ? (v - 0x10000) : v; } + function isehb(bplcon0, bplcon2) { + if (SAEV_config.chipset.mask & SAEC_Config_Chipset_Mask_AGA) + return (bplcon0 & 0x7010) == 0x6000; + else if (SAEV_config.chipset.mask & SAEC_Config_Chipset_Mask_ECS_DENISE) + return (bplcon0 & 0xFC00) == 0x6000 || (bplcon0 & 0xFC00) == 0x7000; - this.BPL1MOD = function (hpos, v) { - v &= ~1; - if (bpl1mod == castWord(v)) - return; - this.decide_line(hpos); - this.decide_fetch(hpos); - bpl1mod = castWord(v); - }; - - this.BPL2MOD = function (hpos, v) { - v &= ~1; - if (bpl2mod == castWord(v)) - return; - this.decide_line(hpos); - this.decide_fetch(hpos); - bpl2mod = castWord(v); - }; - - this.calcdiw = function () { - var hstrt = diwstrt & 0xFF; - var hstop = diwstop & 0xFF; - var vstrt = diwstrt >> 8; - var vstop = diwstop >> 8; - - // vertical in ECS Agnus - if (diwhigh_written && (AMIGA.config.chipset.mask & CSMASK_ECS_AGNUS)) { - vstrt |= (diwhigh & 7) << 8; - vstop |= ((diwhigh >> 8) & 7) << 8; - } else { - if ((vstop & 0x80) == 0) - vstop |= 0x100; - } - // horizontal in ECS Denise - if (diwhigh_written && (AMIGA.config.chipset.mask & CSMASK_ECS_DENISE)) { - hstrt |= ((diwhigh >> 5) & 1) << 8; - hstop |= ((diwhigh >> 13) & 1) << 8; - } else { - hstop += 0x100; - } - - diw_hstrt = hstrt; - diw_hstop = hstop; - - diwfirstword = coord_diw_to_window_x(hstrt); - diwlastword = coord_diw_to_window_x(hstop); - if (diwfirstword >= diwlastword) { - diwfirstword = 0; - diwlastword = max_diwlastword(); - } - if (diwfirstword < 0) - diwfirstword = 0; - - plffirstline = vstrt; - plflastline = vstop; - - plfstrt = ddfstrt; - plfstop = ddfstop; - /* probably not the correct place.. should use plf_state instead */ - if (AMIGA.config.chipset.mask & CSMASK_ECS_AGNUS) { - /* ECS/AGA and ddfstop > maxhpos == always-on display */ - if (plfstop > this.maxhpos) - plfstrt = 0; - if (plfstrt < HARD_DDF_START) - plfstrt = HARD_DDF_START; - plfstrt_start = plfstrt - 4; - } else { - /* OCS and ddfstrt >= ddfstop == ddfstop = max */ - if (plfstrt >= plfstop && plfstrt >= HARD_DDF_START) - plfstop = 0xff; - plfstrt_start = HARD_DDF_START - 2; - } - diw_change = 2; - //console.log('calcdiw', hstrt,hstop,vstrt,vstop, plfstrt,plfstop); - }; - - this.DIWSTRT = function (hpos, v) { - if (diwstrt == v && !diwhigh_written) - return; - this.decide_diw(hpos); - this.decide_line(hpos); - diwhigh_written = false; - diwstrt = v; - this.calcdiw(); - }; - - this.DIWSTOP = function (hpos, v) { - if (diwstop == v && !diwhigh_written) - return; - this.decide_diw(hpos); - this.decide_line(hpos); - diwhigh_written = false; - diwstop = v; - this.calcdiw(); - }; - - this.DIWHIGH = function (hpos, v) { - if (!(AMIGA.config.chipset.mask & (CSMASK_ECS_DENISE | CSMASK_ECS_AGNUS))) - return; - if (!(AMIGA.config.chipset.mask & CSMASK_AGA)) - v &= ~(0x0008 | 0x0010 | 0x1000 | 0x0800); - v &= ~(0x8000 | 0x4000 | 0x0080 | 0x0040); - if (diwhigh_written && diwhigh == v) - return; - this.decide_line(hpos); - diwhigh_written = true; - diwhigh = v; - this.calcdiw(); - }; - - this.DDFSTRT = function (hpos, v) { - v &= 0xfe; - if (!(AMIGA.config.chipset.mask & CSMASK_ECS_AGNUS)) - v &= 0xfc; - if (ddfstrt == v && hpos + 2 != ddfstrt) - return; - ddf_change = this.vpos; - this.decide_line(hpos); - ddfstrt_old_hpos = hpos; - ddfstrt = v; - this.calcdiw(); - /*if (ddfstop > 0xD4 && (ddfstrt & 4) == 4) { - static int last_warned; - last_warned = (last_warned + 1) & 4095; - if (last_warned == 0) BUG.info('WARNING! Very strange DDF values (%x %x).', ddfstrt, ddfstop); - }*/ - }; - - this.DDFSTOP = function (hpos, v) { - v &= 0xfe; - if (!(AMIGA.config.chipset.mask & CSMASK_ECS_AGNUS)) - v &= 0xfc; - if (ddfstop == v && hpos + 2 != ddfstop) - return; - ddf_change = this.vpos; - this.decide_line(hpos); - this.decide_fetch(hpos); - ddfstop = v; - this.calcdiw(); - if (fetch_state != FETCH_NOT_STARTED) - this.estimate_last_fetch_cycle(hpos); - /*if (ddfstop > 0xD4 && (ddfstrt & 4) == 4) { - static int last_warned; - if (last_warned == 0) BUG.info('WARNING! Very strange DDF values (%x).', ddfstop); - last_warned = (last_warned + 1) & 4095; - }*/ - }; - - this.FMODE = function (hpos, v) { - if (!(AMIGA.config.chipset.mask & CSMASK_AGA)) - v = 0; - v &= 0xC00F; - if (fmode == v) - return; - ddf_change = this.vpos; - fmode = v; - sprite_width = GET_SPRITEWIDTH(fmode); - this.bpldmainitdelay(hpos); - }; - - this.checkautoscalecol0 = function () { - if (!AMIGA.copper.access || this.vpos < 20 || this.isbrdblank(-1, bplcon0, bplcon3)) - return; - // autoscale if copper changes COLOR00 on top or bottom of screen - if (this.vpos >= minfirstline) { - var vpos2 = autoscale_bordercolors ? minfirstline : this.vpos; - if (first_planes_vpos == 0) - first_planes_vpos = vpos2 - 2; - if (plffirstline_total == this.current_maxvpos()) - plffirstline_total = vpos2 - 2; - if (vpos2 > last_planes_vpos || vpos2 > plflastline_total) - plflastline_total = last_planes_vpos = vpos2 + 3; - autoscale_bordercolors = 0; - } else - autoscale_bordercolors++; - }; - - this.COLOR_WRITE = function (hpos, v, num) { - //var colzero = false; - v &= 0xFFF; - /*#ifdef AGA - if (AMIGA.config.chipset.mask & CSMASK_AGA) { - int r,g,b; - int cr,cg,cb; - int colreg; - uae_u32 cval; - - if (bplcon2 & 0x0100) - return; - - colreg = ((bplcon3 >> 13) & 7) * 32 + num; - r = (v & 0xF00) >> 8; - g = (v & 0xF0) >> 4; - b = (v & 0xF) >> 0; - cr = current_colors.color_regs_aga[colreg] >> 16; - cg = (current_colors.color_regs_aga[colreg] >> 8) & 0xFF; - cb = current_colors.color_regs_aga[colreg] & 0xFF; - - if (bplcon3 & 0x200) { - cr &= 0xF0; cr |= r; - cg &= 0xF0; cg |= g; - cb &= 0xF0; cb |= b; - } else { - cr = r + (r << 4); - cg = g + (g << 4); - cb = b + (b << 4); - color_regs_aga_genlock[colreg] = v >> 15; - } - cval = (cr << 16) | (cg << 8) | cb; - if (cval && colreg == 0) - colzero = true; - - if (cval == current_colors.color_regs_aga[colreg]) - return; - - if (colreg == 0) - this.checkautoscalecol0 (); - - //Call this with the old table still intact. - this.record_color_change (hpos, colreg, cval); - remembered_color_entry = -1; - current_colors.color_regs_aga[colreg] = cval; - current_colors.acolors[colreg] = getxcolor (cval); - - } else { - #endif*/ - //if (num && v == 0) colzero = true; - - if (!FAST_COLORS) { - if (current_colors.color_regs_ecs[num] == v) - return; - } - if (num == 0) - this.checkautoscalecol0(); - - if (!FAST_COLORS) { - this.record_color_change(hpos, num, v); - remembered_color_entry = -1; - } - current_colors.color_regs_ecs[num] = v; - current_colors.acolors[num] = getxcolor(v); - /*#ifdef AGA - } - #endif*/ - }; - - /*this.islightpentriggered = function() { - if (beamcon0 & 0x2000) // LPENDIS - return 0; - return lightpen_triggered > 0; + return ((bplcon0 & 0xFC00) == 0x6000 || (bplcon0 & 0xFC00) == 0x7000) && !SAEV_config.chipset.deniseNoEHB; } - this.GETVPOS = function() { - return this.islightpentriggered() ? vpos_lpen : (this.issyncstopped() ? vpos_previous : this.vpos); + + // OCS/ECS, lores, 7 planes = 4 "real" planes + BPL5DAT and BPL6DAT as static 5th and 6th plane + function isocs7planes() { + return (SAEV_config.chipset.mask & SAEC_Config_Chipset_Mask_AGA) == 0 && bplcon0_res == 0 && bplcon0_planes == 7; } - this.GETHPOS = function() { - return this.islightpentriggered() ? hpos_lpen : (this.issyncstopped() ? hpos_previous : this.hpos()); - }*/ - this.issyncstopped = function () { - return (bplcon0 & 2) != 0 && !AMIGA.config.chipset.genlock; - }; - this.GETVPOS = function () { - return this.issyncstopped() ? vpos_previous : this.vpos; - }; - this.GETHPOS = function () { - return this.issyncstopped() ? hpos_previous : this.hpos(); - }; - const HPOS_OFFSET = 3; //(currprefs.cpu_model < 68020 ? 3 : 0) - - this.VPOSR = function () { - var vp = this.GETVPOS(); - var hp = this.GETHPOS(); - //var vp = this.vpos; - //var hp = this.hpos(); - var csbit = 0; - - if (hp + HPOS_OFFSET >= this.maxhpos) { - vp++; - if (vp >= this.maxvpos + this.lof_store) - vp = 0; - } - vp = (vp >> 8) & 7; - - if (AMIGA.config.chipset.agnus_rev >= 0) - csbit |= AMIGA.config.chipset.agnus_rev << 8; - else { - /*#ifdef AGA - csbit |= (AMIGA.config.chipset.mask & CSMASK_AGA) ? 0x2300 : 0; - #endif*/ - csbit |= (AMIGA.config.chipset.mask & CSMASK_ECS_AGNUS) ? 0x2000 : 0; - if (AMIGA.mem.chip.size > 1024 * 1024 && (AMIGA.config.chipset.mask & CSMASK_ECS_AGNUS)) - csbit |= 0x2100; - if (AMIGA.config.video.ntsc) - csbit |= 0x1000; - } - - if (!(AMIGA.config.chipset.mask & CSMASK_ECS_AGNUS)) - vp &= 1; - vp = vp | (this.lof_store ? 0x8000 : 0) | csbit; - if (AMIGA.config.chipset.mask & CSMASK_ECS_AGNUS) - vp |= this.lol ? 0x80 : 0; - - //BUG.info('VPOSR $%x', vp); - return vp; - }; - - this.VPOSW = function (v) { - if (this.lof_store != ((v & 0x8000) ? 1 : 0)) { - this.lof_store = (v & 0x8000) ? 1 : 0; - this.lof_changing = this.lof_store ? 1 : -1; - } - if (AMIGA.config.chipset.mask & CSMASK_ECS_AGNUS) { - this.lol = (v & 0x0080) ? 1 : 0; - if (!this.is_linetoggle()) - this.lol = 0; - } - if (this.lof_changing) - return; - - v &= 7; - if (!(AMIGA.config.chipset.mask & CSMASK_ECS_AGNUS)) - v &= 1; - - this.vpos &= 0x00ff; - this.vpos |= v << 8; - //BUG.info('VPOSW $%x', this.vpos); - }; - - this.VHPOSW = function (v) { - this.vpos &= 0xff00; - this.vpos |= v >> 8; - //BUG.info('VHPOSW %x %d', v, this.vpos); - }; - - this.VHPOSR = function () { - var vp = this.GETVPOS(); - var hp = this.GETHPOS(); - //var vp = this.vpos; - //var hp = this.hpos(); - - hp += HPOS_OFFSET; - if (hp >= this.maxhpos) { - hp -= this.maxhpos; - vp++; - if (vp >= this.maxvpos + this.lof_store) - vp = 0; - } - if (HPOS_OFFSET) { - hp += 1; - if (hp >= this.maxhpos) - hp -= this.maxhpos; - } - vp &= 0xff; - hp &= 0xff; - - vp <<= 8; - vp |= hp; - - //BUG.info('VHPOSR $%x', vp); - return vp; - }; - - this.BEAMCON0 = function (v) { - if (AMIGA.config.chipset.mask & CSMASK_ECS_AGNUS) { - if (!(AMIGA.config.chipset.mask & CSMASK_ECS_DENISE)) - v &= 0x20; - - if (v != new_beamcon0) { - new_beamcon0 = v; - if (v & ~0x20) - BUG.info('BEAMCON0() $%04x written.', v); - } - } - }; - - this.DENISEID = function () { - if (AMIGA.config.chipset.denise_rev >= 0) - return [0, AMIGA.config.chipset.denise_rev]; - /*#ifdef AGA - if (AMIGA.config.chipset.mask & CSMASK_AGA) { - if (currprefs.cs_ide == IDE_A4000) return [0, 0xFCF8]; - return [0, 0x00F8]; - } - #endif*/ - if (AMIGA.config.chipset.mask & CSMASK_ECS_DENISE) - return [0, 0xFFFC]; - - if (AMIGA.config.cpu.model == 68000 && AMIGA.config.cpu.compatible) - return [1, 0xFFFF]; - return [0, 0xFFFF]; - }; - - /*---------------------------------*/ - - this.is_bitplane_dma = function (hpos) { - if (hpos < plfstrt) + this.is_bitplane_dma = function(hpos) { //global + if (hpos < bpl_hstart || fetch_state == fetch_not_started || plf_state == plf_wait) return 0; - if ((plf_state == PLF_END && hpos >= thisline_decision.plfright) || hpos >= estimated_last_fetch_cycle) + if ((plf_state >= plf_end && hpos >= thisline_decision.plfright) || hpos >= estimated_last_fetch_cycle) return 0; - return curr_diagram[(hpos - cycle_diagram_shift) & fetchstart_mask]; - }; - - this.update_denise = function (hpos) { - toscr_res = GET_RES_DENISE(bplcon0_d); - if (bplcon0_dd != bplcon0_d) { - this.record_color_change2(hpos, 0x100 + 0x1000, bplcon0_d); - bplcon0_dd = bplcon0_d; - } - toscr_nr_planes = GET_PLANES(bplcon0_d); + } - if (!(AMIGA.config.chipset.mask & CSMASK_AGA) && bplcon0_res == 0 && bplcon0_planes == 7) { //OCS 7 planes - if (toscr_nr_planes2 < 6) - toscr_nr_planes2 = 6; - } else - toscr_nr_planes2 = toscr_nr_planes; - }; - - this.setup_fmodes = function (hpos) { + function islinetoggle() { + if (!(beamcon0 & 0x0800) && !(beamcon0 & 0x0020) && (SAEV_config.chipset.mask & SAEC_Config_Chipset_Mask_ECS_AGNUS)) return true; // NTSC and !LOLDIS -> LOL toggles every line + else if (!(SAEV_config.chipset.mask & SAEC_Config_Chipset_Mask_ECS_AGNUS) && SAEV_config.chipset.ntsc) return true; // hardwired NTSC Agnus + return false; + } + + /* Expand bplcon0/bplcon1 into the toscr_xxx variables. */ + function compute_toscr_delay(bplcon1) { + var delay1 = (bplcon1 & 0x0f) | ((bplcon1 & 0x0c00) >> 6); + var delay2 = ((bplcon1 >> 4) & 0x0f) | (((bplcon1 >> 4) & 0x0c00) >> 6); + var shdelay1 = (bplcon1 >> 8) & 3; + var shdelay2 = (bplcon1 >> 12) & 3; + var delaymask = fetchmode_mask >> toscr_res; + + toscr_delay[0] = (delay1 & delaymask) << toscr_res; + toscr_delay[0] |= shdelay1 >> (RES_MAX - toscr_res); + toscr_delay[1] = (delay2 & delaymask) << toscr_res; + toscr_delay[1] |= shdelay2 >> (RES_MAX - toscr_res); + + if (SPEEDUP) { + /* SPEEDUP code still needs this hack */ + var delayoffset = fetchmode_size - (((bpl_hstart - (HARD_DDF_START_REAL + DDF_OFFSET)) & fetchstart_mask) << 1); + delay1 += delayoffset; + delay2 += delayoffset; + toscr_delay_adjusted[0] = (delay1 & delaymask) << toscr_res; + toscr_delay_adjusted[0] |= shdelay1 >> (RES_MAX - toscr_res); + toscr_delay_adjusted[1] = (delay2 & delaymask) << toscr_res; + toscr_delay_adjusted[1] |= shdelay2 >> (RES_MAX - toscr_res); + } + } + + function set_delay_lastcycle() { + if (HARD_DDF_LIMITS_DISABLED()) { + delay_lastcycle[0] = (256 * 2) << bplcon0_res; + delay_lastcycle[1] = (256 * 2) << bplcon0_res; + } else { + delay_lastcycle[0] = ((maxhpos + 1) * 2 + 0) << bplcon0_res; + delay_lastcycle[1] = delay_lastcycle[0]; + if (islinetoggle()) + delay_lastcycle[1]++; + } + } + + var bpldmasetuphpos, bpldmasetuphpos_diff; //int + var bpldmasetupphase; //int + + /* set currently active Agnus bitplane DMA sequence */ + function setup_fmodes(hpos) { switch (fmode & 3) { case 0: fetchmode = 0; @@ -4751,108 +5955,2841 @@ function Playfield() { fm_maxplane_shift = fm_maxplanes[fetchmode * 4 + bplcon0_res]; fm_maxplane = 1 << fm_maxplane_shift; fetch_modulo_cycle = fetchunit - fetchstart; + fetchmode_size = 16 << fetchmode; + fetchmode_bytes = 2 << fetchmode; + fetchmode_mask = fetchmode_size - 1; + set_delay_lastcycle(); + compute_toscr_delay(bplcon1); + + if (thisline_decision.plfleft < 0) { + thisline_decision.bplres = bplcon0_res; + thisline_decision.bplcon0 = bplcon0; + thisline_decision.nr_planes = bplcon0_planes; + } + curr_diagram = cycle_diagram_table[fetchmode][bplcon0_res][bplcon0_planes_limit]; - this.estimate_last_fetch_cycle(hpos); + + //if (SAER.playfield.is_bitplane_dma(hpos - 1)) SAER_Events_cycle_line[hpos - 1] = SAEC_Events_cycle_line_REFRESH; + + estimate_last_fetch_cycle(hpos); bpldmasetuphpos = -1; bpldmasetupphase = 0; - ddf_change = this.vpos; - }; - this.maybe_setup_fmodes = function (hpos) { + toscr_nr_planes_agnus = bplcon0_planes; + if (isocs7planes()) + toscr_nr_planes_agnus = 6; + + line_cyclebased = 2; //SET_LINE_CYCLEBASED(); + } + + // writing to BPLCON0 adds 4 cycle delay before Agnus bitplane DMA sequence changes + // (Note that Denise sees the change after 1 cycle) + // AGA needs extra cycle in some specific situations (Brian The Lion "dialog") but not + // in all situations (Superstardust weapon panel) + //#define BPLCON_AGNUS_DELAY (3 + (SAEV_Copper_access ? 1 : 0) + (bplcon0_planes == 8 ? 1 : 0)) //OPT inline, ok + //#define BPLCON_DENISE_DELAY (SAEV_Copper_access ? 1 : 0) //OPT inline, ok + + function maybe_setup_fmodes(hpos) { switch (bpldmasetupphase) { case 0: - this.BPLCON0_Denise(hpos, bplcon0, false); + BPLCON0_Denise(hpos, bplcon0, false); bpldmasetupphase++; - bpldmasetuphpos += (4 + (bplcon0_planes == 8 ? 1 : 0)) - BPLCON_DENISE_DELAY; + bpldmasetuphpos += bpldmasetuphpos_diff; break; case 1: - this.setup_fmodes(hpos); + setup_fmodes(hpos); break; } - }; - - this.maybe_check = function (hpos) { + } + function maybe_check(hpos) { if (bpldmasetuphpos > 0 && hpos >= bpldmasetuphpos) - this.maybe_setup_fmodes(hpos); - }; + maybe_setup_fmodes(hpos); + } - this.compute_delay_offset = function () { - delayoffset = (16 << fetchmode) - (((plfstrt - HARD_DDF_START) & fetchstart_mask) << 1); - }; - - this.compute_toscr_delay_1 = function (con1) { - var delay1 = (con1 & 0x0f) | ((con1 & 0x0c00) >> 6); - var delay2 = ((con1 >> 4) & 0x0f) | (((con1 >> 4) & 0x0c00) >> 6); - var shdelay1 = (con1 >> 12) & 3; - var shdelay2 = (con1 >> 8) & 3; - var delaymask; - var fetchwidth = 16 << fetchmode; + function bpldmainitdelay(hpos) { + line_cyclebased = 2; //SET_LINE_CYCLEBASED(); + //if (hpos + BPLCON_AGNUS_DELAY < 0x14) { //ORG + if (hpos + 3 + (SAEV_Copper_access ? 1 : 0) + (bplcon0_planes == 8 ? 1 : 0) < 0x14) { //OWN opt inline + BPLCON0_Denise(hpos, bplcon0, false); + setup_fmodes(hpos); + return; + } + /*ORG + if (bpldmasetuphpos < 0) { + bpldmasetuphpos = hpos + BPLCON_DENISE_DELAY; + bpldmasetuphpos_diff = BPLCON_AGNUS_DELAY - BPLCON_DENISE_DELAY; + bpldmasetupphase = 0; + if (BPLCON_DENISE_DELAY == 0) + maybe_setup_fmodes(hpos); + }*/ + if (bpldmasetuphpos < 0) { //OWN opt inline + bpldmasetuphpos = hpos + (SAEV_Copper_access ? 1 : 0); + //bpldmasetuphpos_diff = 3 + (SAEV_Copper_access ? 1 : 0) + (bplcon0_planes == 8 ? 1 : 0) - (SAEV_Copper_access ? 1 : 0); + bpldmasetuphpos_diff = 3 + (bplcon0_planes == 8 ? 1 : 0); + bpldmasetupphase = 0; + if (!SAEV_Copper_access) + maybe_setup_fmodes(hpos); + } - delay1 += delayoffset; - delay2 += delayoffset; - delaymask = (fetchwidth - 1) >> toscr_res; - toscr_delay1 = (delay1 & delaymask) << toscr_res; - toscr_delay1 |= shdelay1 >> (RES_MAX - toscr_res); - toscr_delay2 = (delay2 & delaymask) << toscr_res; - toscr_delay2 |= shdelay2 >> (RES_MAX - toscr_res); - }; + } - this.compute_toscr_delay = function (hpos, con1) { - this.update_denise(hpos); - this.compute_toscr_delay_1(con1); - }; + /*STATIC_INLINE void clear_fetchbuffer (uae_u32 *ptr, int nwords) { + if (!thisline_changed) { + for (int i = 0; i < nwords; i++) { + if (ptr[i]) { + thisline_changed = 1; + break; + } + } + } + memset(ptr, 0, nwords * 4); + }*/ + function clear_fetchbuffer(data, offs, nwords) { + if (!thisline_changed) { + for (var i = offs, j = offs + nwords; i < j; i++) { + if (data[i]) { + thisline_changed = 1; + break; + } + } + } + //SAEF_memset(data,offs, 0, nwords); + for (var i = offs, j = offs + nwords; i < j; i++) data[i] = 0; + } + function update_toscr_planes(fm) { + // This must be called just before new bitplane block starts, + // not when depth value changes. Depth can change early and can leave + // 16+ pixel horizontal line of old data visible. + if (toscr_nr_planes_agnus > thisline_decision.nr_planes) { + if (out_offs) { + for (var j = thisline_decision.nr_planes; j < toscr_nr_planes_agnus; j++) { + //clear_fetchbuffer((uae_u32 *)(line_data[next_lineno] + 2 * MAX_WORDS_PER_LINE * j), out_offs); + clear_fetchbuffer(line_data[next_lineno], MAX_WORDS_PER_LINE_FULL * j, out_offs); - this.update_toscr_planes = function () { - if (toscr_nr_planes2 > thisline_decision.nr_planes) { - for (var j = thisline_decision.nr_planes; j < toscr_nr_planes2; j++) { - if (!thisline_changed) { - for (var i = 0; i < out_offs; i++) { - if (line_data[next_lineno][j][i]) { - thisline_changed = 1; - break; + if (thisline_decision.plfleft >= 0) { + todisplay[j] = 0; + //#ifdef AGA + if (fm) { + //todisplay_aga[j] = 0; + todisplay_aga_hi[j] = todisplay_aga_lo[j] = 0; + } + //#endif + } + } + } + thisline_decision.nr_planes = toscr_nr_planes_agnus; + } + } + + function maybe_first_bpl1dat(hpos) { + if (thisline_decision.plfleft < 0) + thisline_decision.plfleft = hpos; + } + + function fetch_warn(nr, hpos) { + //static int warned1 = 30, warned2 = 30; + var add = fetchmode_bytes; + if (hpos == maxhpos - 1) { + //if (warned1 >= 0) + { + SAEF_warn("playfield.fetch_warn() BPL fetch conflicts with strobe refresh slot!"); + //warned1--; + } + add = refptr_val; + } else { + //if (warned2 >= 0) + { + //warned2--; + SAEF_warn("playfield.fetch_warn() BPL fetch at hpos %d/%d", hpos, maxhpos); + } + add = refptr_val; + } + bitplane_line_crossing = hpos; + /*#if 0 + line_cyclebased = vpos; + corrupt_offset = (vpos ^ (SAEV_Events_timeframes << 12)) & 0xff00; + for (var i = 0; i < bplcon0_planes_limit; i++) { + uae_u16 v; + v = bplpt[i] & 0xffff; + v += corrupt_offset; + bplpt[i] = (bplpt[i] & 0xffff0000) | v; + } + #endif*/ + return add; + } + + function fetch(nr, fm, hpos) { + if (nr < bplcon0_planes_limit) { + var p; + var add = fetchmode_bytes; + + if (hpos > maxhpos - HPOS_SHIFT && !(beamcon0 & 0x80)) + add = fetch_warn(nr, hpos); + + p = bplpt[nr]; + bplpt[nr] += add; + bplptx[nr] += add; + + /*#if 0 + if (dbplpth_on2) reset_dbplh(hpos, nr); + if (dbplptl_on2) reset_dbpll(hpos, nr); + #endif*/ + + if (nr == 0) + bpl1dat_written = true; + + switch (fm) { + case 0: { + fetched[nr] = SAER_Memory_chipGet16_indirect(p); + SAEV_Custom_last_value = fetched[nr]; + break; + } + //#ifdef AGA + case 1: { + //fetched_aga[nr] = SAER_Memory_chipGet32_indirect(p); + fetched_aga_hi[nr] = 0; + fetched_aga_lo[nr] = SAER_Memory_chipGet32_indirect(p); + SAEV_Custom_last_value = fetched_aga_lo[nr]; + fetched[nr] = fetched_aga_lo[nr] & 0xffff; + break; + } + case 2: { + //fetched_aga[nr] = ((uae_u64)SAER_Memory_chipGet32_indirect(p)) << 32; + //fetched_aga[nr] |= SAER_Memory_chipGet32_indirect(p + 4); + fetched_aga_hi[nr] = SAER_Memory_chipGet32_indirect(p); + fetched_aga_lo[nr] = SAER_Memory_chipGet32_indirect(p + 4); + SAEV_Custom_last_value = fetched_aga_lo[nr]; + fetched[nr] = fetched_aga_lo[nr] & 0xffff; + break; + } + //#endif + } + if (plf_state == plf_passed_stop2 && fetch_cycle >= (fetch_cycle & ~fetchunit_mask) + fetch_modulo_cycle) + add_modulo(hpos, nr); + } + } + + function toscr_3_ecs(oddeven, step, nbits) { + var i, shift = 16 - nbits; + + // if number of planes decrease (or go to zero), we still need to + // shift all possible remaining pixels out of Denise"s shift register + for (i = oddeven; i < thisline_decision.nr_planes; i += step) + outword[i] <<= nbits; + + for (i = oddeven; i < toscr_nr_planes2; i += step) { + outword[i] |= todisplay2[i] >>> shift; + todisplay2[i] <<= nbits; + } + } + //#ifdef AGA + function toscr_3_aga(oddeven, step, nbits, fm) { + var i, shift = fetchmode_size - nbits; + var mask = 0xffff >> (16 - nbits); + + for (i = oddeven; i < thisline_decision.nr_planes; i += step) + outword[i] <<= nbits; + + for (i = oddeven; i < toscr_nr_planes2; i += step) { + //outword[i] |= (todisplay2_aga[i] >>> shift) & mask; + if (shift < 32) + outword[i] |= ((todisplay2_aga_hi[i] << (32 - shift)) | (todisplay2_aga_lo[i] >>> shift)) & mask; //ATT + else + outword[i] |= (todisplay2_aga_hi[i] >>> (shift - 32)) & mask; + + //todisplay2_aga[i] <<= nbits; + //if (nbits < 32) { + todisplay2_aga_hi[i] = (todisplay2_aga_hi[i] << nbits) | (todisplay2_aga_lo[i] >>> (32 - nbits)); //ATT + todisplay2_aga_lo[i] <<= nbits; + /*} else { + todisplay2_aga_hi[i] = todisplay2_aga_lo[i] << (nbits - 32); + todisplay2_aga_lo[i] = 0; + }*/ + } + } + //#endif + + /*OPT inline, ok + function toscr_2_0(nbits) { toscr_3_ecs (0, 1, nbits); } + function toscr_2_0_oe(oddeven, step, nbits) { toscr_3_ecs (oddeven, step, nbits); } + //#ifdef AGA + function toscr_2_1(nbits) { toscr_3_aga (0, 1, nbits, 1); } + function toscr_2_1_oe(oddeven, step, nbits) { toscr_3_aga (oddeven, step, nbits, 1); } + function toscr_2_2(nbits) { toscr_3_aga (0, 1, nbits, 2); } + function toscr_2_2_oe(oddeven, step, nbits) { toscr_3_aga (oddeven, step, nbits, 2); } + //#endif + function do_tosrc(oddeven, step, nbits, fm) { + switch (fm) { + case 0: + if (step == 2) + toscr_2_0_oe(oddeven, step, nbits); + else + toscr_2_0(nbits); + break; + //#ifdef AGA + case 1: + if (step == 2) + toscr_2_1_oe(oddeven, step, nbits); + else + toscr_2_1(nbits); + break; + case 2: + if (step == 2) + toscr_2_2_oe(oddeven, step, nbits); + else + toscr_2_2(nbits); + break; + //#endif + } + }*/ + function do_tosrc(oddeven, step, nbits, fm) { + if (step == 2) { + if (fm == 0) + toscr_3_ecs(oddeven, 2, nbits); + else + toscr_3_aga(oddeven, 2, nbits, fm); + } else { + if (fm == 0) + toscr_3_ecs(0, 1, nbits); + else + toscr_3_aga(0, 1, nbits, fm); + } + } + + function do_delays_3_ecs(nbits) { + var delaypos = delay_cycles & fetchmode_mask; + for (var oddeven = 0; oddeven < 2; oddeven++) { + var delay = toscr_delay[oddeven]; + /*#if 0 + for (var j = 0; j < nbits; j++) { + var dp = (delay_cycles + j); + if (dp >= (maxhpos * 2) << toscr_res) + dp -= (maxhpos * 2) << toscr_res; + dp &= fetchmode_mask; + do_tosrc(oddeven, 2, 1, 0); + + if (todisplay_fetched[oddeven] && dp == delay) { + for (var i = oddeven; i < toscr_nr_planes_shifter; i += 2) { + todisplay2[i] = todisplay[i]; + } + todisplay_fetched[oddeven] = false; + } + } + #else*/ + if (delaypos > delay) + delay += fetchmode_size; + var diff = delay - delaypos; + var nbits2 = nbits; + if (nbits2 > diff) { + do_tosrc(oddeven, 2, diff, 0); + nbits2 -= diff; + if (todisplay_fetched[oddeven]) { + for (var i = oddeven; i < toscr_nr_planes_shifter; i += 2) + todisplay2[i] = todisplay[i]; + todisplay_fetched[oddeven] = false; + } + } + if (nbits2) do_tosrc(oddeven, 2, nbits2, 0); + //#endif + } + } + + function do_delays_fast_3_ecs(nbits) { + var delaypos = delay_cycles & fetchmode_mask; + var delay = toscr_delay[0]; + if (delaypos > delay) + delay += fetchmode_size; + var diff = delay - delaypos; + var nbits2 = nbits; + if (nbits2 > diff) { + do_tosrc(0, 1, diff, 0); + nbits2 -= diff; + if (todisplay_fetched[0]) { + for (var i = 0; i < toscr_nr_planes_shifter; i++) + todisplay2[i] = todisplay[i]; + todisplay_fetched[0] = false; + todisplay_fetched[1] = false; + } + } + if (nbits2) do_tosrc (0, 1, nbits2, 0); + } + + function do_delays_3_aga (nbits, fm) { + var delaypos = delay_cycles & fetchmode_mask; + for (var oddeven = 0; oddeven < 2; oddeven++) { + var delay = toscr_delay[oddeven]; + if (delaypos > delay) + delay += fetchmode_size; + var diff = delay - delaypos; + var nbits2 = nbits; + if (nbits2 > diff) { + do_tosrc(oddeven, 2, diff, fm); + nbits2 -= diff; + if (todisplay_fetched[oddeven]) { + for (var i = oddeven; i < toscr_nr_planes_shifter; i += 2) { + //todisplay2_aga[i] = todisplay_aga[i]; + todisplay2_aga_hi[i] = todisplay_aga_hi[i]; + todisplay2_aga_lo[i] = todisplay_aga_lo[i]; + } + todisplay_fetched[oddeven] = false; + } + } + if (nbits2) do_tosrc (oddeven, 2, nbits2, fm); + } + } + + function do_delays_fast_3_aga (nbits, fm) { + var delaypos = delay_cycles & fetchmode_mask; + var delay = toscr_delay[0]; + if (delaypos > delay) + delay += fetchmode_size; + var diff = delay - delaypos; + var nbits2 = nbits; + if (nbits2 > diff) { + do_tosrc(0, 1, diff, fm); + nbits2 -= diff; + if (todisplay_fetched[0]) { + for (var i = 0; i < toscr_nr_planes_shifter; i++) { + //todisplay2_aga[i] = todisplay_aga[i]; + todisplay2_aga_hi[i] = todisplay_aga_hi[i]; + todisplay2_aga_lo[i] = todisplay_aga_lo[i]; + } + todisplay_fetched[0] = false; + todisplay_fetched[1] = false; + } + } + if (nbits2) do_tosrc(0, 1, nbits2, fm); + } + + + /*OPT inline, ok + function do_delays_2_0(nbits) { do_delays_3_ecs(nbits); } + //#ifdef AGA + function do_delays_2_1(nbits) { do_delays_3_aga(nbits, 1); } + function do_delays_2_2(nbits) { do_delays_3_aga(nbits, 2); } + //#endif + function do_delays_fast_2_0(nbits) { do_delays_fast_3_ecs(nbits); } + //#ifdef AGA + function do_delays_fast_2_1(nbits) { do_delays_fast_3_aga(nbits, 1); } + function do_delays_fast_2_2(nbits) { do_delays_fast_3_aga(nbits, 2); } + //#endif + // slower version, odd and even delays are different or crosses maxhpos + function do_delays(nbits, fm) { + switch (fm) { + case 0: + do_delays_2_0(nbits); + break; + //#ifdef AGA + case 1: + do_delays_2_1(nbits); + break; + case 2: + do_delays_2_2(nbits); + break; + //#endif + } + }*/ + function do_delays(nbits, fm) { + if (fm == 0) + do_delays_3_ecs(nbits); + else + do_delays_3_aga(nbits, fm); + } + // common optimized case: odd delay == even delay + /*function do_delays_fast(nbits, fm) { + switch (fm) { + case 0: + do_delays_fast_2_0(nbits); + break; + //#ifdef AGA + case 1: + do_delays_fast_2_1(nbits); + break; + case 2: + do_delays_fast_2_2(nbits); + break; + //#endif + } + } + function do_delays_fast(nbits, fm) { + if (fm == 0) + do_delays_fast_3_ecs(nbits); + else + do_delays_fast_3_aga(nbits, fm); + }*/ + + function toscr_right_edge(nbits, fm) { + // Emulate hpos counter (delay_cycles) reseting at the end of scanline. + // (Result is ugly shift in graphics in far right overscan) + var diff = delay_lastcycle[lol] - delay_cycles; + var nbits2 = nbits; + if (nbits2 >= diff) { + do_delays(diff, fm); + nbits2 -= diff; + delay_cycles = 0; + if (hpos_is_zero_bplcon1_hack >= 0) { + compute_toscr_delay(hpos_is_zero_bplcon1_hack); + hpos_is_zero_bplcon1_hack = -1; + } + toscr_delay[0] -= 2; + toscr_delay[0] &= fetchmode_mask; + toscr_delay[1] -= 2; + toscr_delay[1] &= fetchmode_mask; + } + if (nbits2) { + do_delays(nbits2, fm); + delay_cycles += nbits2; + } + } + + function toscr_1(nbits, fm) { + if (delay_cycles + nbits >= delay_lastcycle[lol]) { + toscr_right_edge(nbits, fm); + } else if (toscr_delay[0] == toscr_delay[1]) { + // Most common case. + //do_delays_fast(nbits, fm); //ORG + if (fm == 0) //OWN + do_delays_fast_3_ecs(nbits); + else + do_delays_fast_3_aga(nbits, fm); + + delay_cycles += nbits; + } else { + do_delays(nbits, fm); + delay_cycles += nbits; + } + + out_nbits += nbits; + if (out_nbits == 32) { + /*uae_u8 *dataptr = line_data[next_lineno] + out_offs * 4; + for (int i = 0; i < thisline_decision.nr_planes; i++) { + uae_u32 *dataptr32 = (uae_u32 *)dataptr; + if (*dataptr32 != outword[i]) { + thisline_changed = 1; + *dataptr32 = outword[i]; + } + outword[i] = 0; + dataptr += MAX_WORDS_PER_LINE * 2; + }*/ + + var data = line_data[next_lineno]; + var offs = out_offs; + for (var i = 0; i < thisline_decision.nr_planes; i++) { + if (data[offs] != outword[i]) { + data[offs] = outword[i]; + thisline_changed = 1; + } + outword[i] = 0; + offs += MAX_WORDS_PER_LINE_FULL; + } + + out_offs++; + out_nbits = 0; + } + } + + function toscr_fm0(nbits) { toscr_0(nbits, 0); } + function toscr_fm1(nbits) { toscr_0(nbits, 1); } + function toscr_fm2(nbits) { toscr_0(nbits, 2); } + + function toscr(nbits, fm) { //OPT recursive + switch (fm) { + case 0: toscr_fm0(nbits); break; + //#ifdef AGA + case 1: toscr_fm1(nbits); break; + case 2: toscr_fm2(nbits); break; + //#endif + } + } + + function toscr_0(nbits, fm) { + if (nbits > 16) { + toscr(16, fm); + nbits -= 16; + } + var t = 32 - out_nbits; + if (t < nbits) { + toscr_1(t, fm); + nbits -= t; + } + toscr_1(nbits, fm); + } + + function flush_plane_data(fm) { + var i = 0; + + if (out_nbits <= 16) { + i += 16; + toscr_1(16, fm); + } + if (out_nbits != 0) { + i += 32 - out_nbits; + toscr_1(32 - out_nbits, fm); + } + + i += 32; + toscr_1(16, fm); + toscr_1(16, fm); + + if (fm == 2) { + /* flush AGA full 64-bit shift register + possible data in todisplay */ + i += 32; + toscr_1(16, fm); + toscr_1(16, fm); + i += 32; + toscr_1(16, fm); + toscr_1(16, fm); + } + return i >> (1 + toscr_res); + } + + function flush_display(fm) { + if (toscr_nbits > 0 && thisline_decision.plfleft >= 0) + toscr(toscr_nbits, fm); + toscr_nbits = 0; + } + + /*-----------------------------------------------------------------------*/ + /* SECT fetch */ + + function hack_shres_delay(hpos) { + if (!(SAEV_config.chipset.mask & SAEC_Config_Chipset_Mask_AGA) && !toscr_delay_sh[0] && !toscr_delay_sh[1]) + return; + var o0 = toscr_delay_sh[0]; + var o1 = toscr_delay_sh[1]; + var shdelay1 = (bplcon1 >> 8) & 3; + var shdelay2 = (bplcon1 >> 12) & 3; + toscr_delay_sh[0] = (shdelay1 & 3) >> toscr_res; + toscr_delay_sh[1] = (shdelay2 & 3) >> toscr_res; + if (hpos >= 0 && toscr_delay_sh[0] != o0 || toscr_delay_sh[1] != o1) { + record_color_change(hpos, 0, COLOR_CHANGE_SHRES_DELAY | toscr_delay_sh[0]); + current_colors.extra &= ~(1 << CE_SHRES_DELAY); + current_colors.extra &= ~(1 << (CE_SHRES_DELAY + 1)); + current_colors.extra |= toscr_delay_sh[0] << CE_SHRES_DELAY; + remembered_color_entry = -1; + } + } + + function update_denise_shifter_planes(hpos) { + var np = GET_PLANES(bplcon0d); + // if DMA has ended but there is still data waiting in todisplay, + // it must be flushed out before number of planes change + if (np < toscr_nr_planes_shifter && hpos > thisline_decision.plfright && thisline_decision.plfright && (todisplay_fetched[0] || todisplay_fetched[1])) { + var diff = (hpos - thisline_decision.plfright) << (1 + toscr_res); + while (diff >= 16) { + toscr_1(16, fetchmode); + diff -= 16; + } + if (diff) + toscr_1(diff, fetchmode); + thisline_decision.plfright += hpos - thisline_decision.plfright; + } + // FIXME: Samplers / Back In 90 vs Disposable Hero title screen in fast modes + if (SAEV_config.cpu.model < SAEC_Config_CPU_Model_68020) { + toscr_nr_planes_shifter = np; + if (isocs7planes()) { + if (toscr_nr_planes_shifter < 6) + toscr_nr_planes_shifter = 6; + } + } + } + + function update_denise(hpos) { + var res = GET_RES_DENISE(bplcon0d); + if (res != toscr_res) + flush_display(fetchmode); + toscr_res = GET_RES_DENISE(bplcon0d); + toscr_res2p = 2 << toscr_res; + delay_cycles = (hpos * 2) << toscr_res; + if (bplcon0dd != bplcon0d) { + record_color_change2(hpos, 0x100 + 0x1000, bplcon0d); + bplcon0dd = bplcon0d; + } + toscr_nr_planes = GET_PLANES(bplcon0d); + if (isocs7planes()) { + if (toscr_nr_planes2 < 6) + toscr_nr_planes2 = 6; + } else { + toscr_nr_planes2 = toscr_nr_planes; + } + toscr_nr_planes_shifter = toscr_nr_planes2; + hack_shres_delay(hpos); + } + + /*function fetch_start(hpos) { + fetch_state = fetch_started; + }*/ + + function pfield_xlateptr(plpt, bytecount) { + //if (!chipmem_check_indirect(plpt, bytecount)) { + if (!SAER_Memory_chipCheck_indirect(plpt, bytecount)) { + //static int count = 0; if (!count) count++, SAEF_warn("playfield.pfield_xlateptr() bad playfield pointer %08x", plpt); + return null; + } + //return chipmem_xlate_indirect(plpt); + return SAER_Memory_chipXLate_indirect(plpt); + } + + /* Called when all planes have been fetched, i.e. when a new block + of data is available to be displayed. The data in fetched[] is + moved into todisplay[]. */ + function beginning_of_plane_block(hpos, fm) { + var i; + + if (fm == 0) + for (i = 0; i < MAX_PLANES; i++) { + todisplay[i] = fetched[i]; + } + //#ifdef AGA + else + for (i = 0; i < MAX_PLANES; i++) { + //todisplay_aga[i] = fetched_aga[i]; + todisplay_aga_hi[i] = fetched_aga_hi[i]; + todisplay_aga_lo[i] = fetched_aga_lo[i]; + } + //#endif + todisplay_fetched[0] = todisplay_fetched[1] = true; + maybe_first_bpl1dat(hpos); + update_denise(hpos); + if (toscr_nr_planes_agnus > thisline_decision.nr_planes) + update_toscr_planes(fm); + } + + /* The usual inlining tricks - don't touch unless you know what you are doing. */ + //#if SPEEDUP + function long_fetch_16(plane, nwords, weird_number_of_bits, dma) { + //uae_u16 *real_pt = (uae_u16 *)pfield_xlateptr (bplpt[plane], nwords * 2); + var real_pt = pfield_xlateptr(bplpt[plane], nwords * 2); + //var real_pt2 = bplpt[plane] >>> 1; + var delay = toscr_delay_adjusted[plane & 1]; + var tmp_nbits = out_nbits; + var outval = outword[plane]; //u32 + var fetchval = fetched[plane]; //u32 + //uae_u32 *dataptr = (uae_u32 *)(line_data[next_lineno] + 2 * plane * MAX_WORDS_PER_LINE + 4 * out_offs); + var data = line_data[next_lineno]; + var offs = MAX_WORDS_PER_LINE_FULL * plane + out_offs; //OWN + + if (dma) { + bplpt[plane] += nwords * 2; + bplptx[plane] += nwords * 2; + } + + if (real_pt === null) //Don't do this, fall back on chipmem_wget instead. + return; + + var shiftbuffer = todisplay2[plane] << delay; //u32, ATT + + while (nwords > 0) { + var bits_left = 32 - tmp_nbits; + + shiftbuffer = (shiftbuffer | fetchval) >>> 0; + + var t = (shiftbuffer >>> delay) & 0xffff; //u32 + + if (weird_number_of_bits && bits_left < 16) { + outval = (outval << bits_left) & 0xffffffff; + outval = (outval | (t >>> (16 - bits_left))) >>> 0; + //thisline_changed |= *dataptr ^ outval; *dataptr++ = outval; + thisline_changed |= (data[offs] ^ outval) >>> 0; data[offs++] = outval; + outval = t; + tmp_nbits = 16 - bits_left; + } else { + outval = (((outval << 16) & 0xffffffff) | t) >>> 0; + tmp_nbits += 16; + if (tmp_nbits == 32) { + //thisline_changed |= *dataptr ^ outval; *dataptr++ = outval; + thisline_changed |= (data[offs] ^ outval) >>> 0; data[offs++] = outval; + tmp_nbits = 0; + } + } + shiftbuffer = (shiftbuffer << 16) & 0xffffffff; + nwords--; + if (dma) { + fetchval = (SAER_Memory_chipData[real_pt] << 8) | SAER_Memory_chipData[real_pt+1]; + real_pt += 2; + //fetchval = do_get_mem_word(real_pt); real_pt++; + //fetchval = SAER_Memory_chipGet16_indirect[real_pt]; real_pt += 2; + //fetchval = SAER_Memory_chipData[real_pt2++]; //real_pt2++; + /*#if 0 + if (plane == 0) fetchval ^= 0x55555555; + #endif*/ + } + } + fetched[plane] = fetchval; + todisplay2[plane] = shiftbuffer >>> delay; //ATT + outword[plane] = outval; + } + + //#ifdef AGA + function long_fetch_32(plane, nwords, weird_number_of_bits, dma) { + //uae_u32 *real_pt = (uae_u32 *)pfield_xlateptr (bplpt[plane], nwords * 2); + var real_pt = pfield_xlateptr(bplpt[plane], nwords * 2); + //var real_pt2 = bplpt[plane] >>> 1; + var delay = toscr_delay_adjusted[plane & 1]; + var tmp_nbits = out_nbits; + //var shiftbuffer; //u64 + var shiftbuffer_hi, shiftbuffer_lo; + var outval = outword[plane]; //u32 + //var fetchval = fetched_aga[plane]; //u32 + var fetchval = fetched_aga_lo[plane]; //u32 + //uae_u32 *dataptr = (uae_u32 *)(line_data[next_lineno] + 2 * plane * MAX_WORDS_PER_LINE + 4 * out_offs); + var data = line_data[next_lineno]; + var offs = MAX_WORDS_PER_LINE_FULL * plane + out_offs; //OWN + var shift = 16 + delay; //int + + if (dma) { + bplpt[plane] += nwords * 2; + bplptx[plane] += nwords * 2; + } + + if (real_pt === null) //Don't do this, fall back on chipmem_wget instead. + return; + + //shiftbuffer = todisplay2_aga[plane] << delay; + shiftbuffer_hi = todisplay2_aga_hi[plane]; + shiftbuffer_lo = todisplay2_aga_lo[plane]; + if (delay) { + shiftbuffer_hi = (((shiftbuffer_hi << delay) & 0xffffffff) | (shiftbuffer_lo >>> (32 - delay))) >>> 0; //ATT + shiftbuffer_lo = (shiftbuffer_lo << delay) & 0xffffffff; + } + + while (nwords > 0) { + //shiftbuffer |= fetchval; + shiftbuffer_lo = (shiftbuffer_lo | fetchval) >>> 0; + + for (var i = 0; i < 2; i++) { + var t; + var bits_left = 32 - tmp_nbits; + + //t = (shiftbuffer >> shift) & 0xffff; + if (shift < 32) + t = ((shiftbuffer_hi << (32 - shift)) | (shiftbuffer_lo >>> shift)) & 0xffff; + else + t = (shiftbuffer_hi >>> (shift - 32)) & 0xffff; + + if (weird_number_of_bits && bits_left < 16) { + outval = (outval << bits_left) & 0xffffffff; + outval = (outval | (t >>> (16 - bits_left))) >>> 0; + //thisline_changed |= *dataptr ^ outval; *dataptr++ = outval; + thisline_changed |= (data[offs] ^ outval) >>> 0; data[offs++] = outval; + outval = t; + tmp_nbits = 16 - bits_left; + } else { + outval = (((outval << 16) & 0xffffffff) | t) >>> 0; + tmp_nbits += 16; + if (tmp_nbits == 32) { + //thisline_changed |= *dataptr ^ outval; *dataptr++ = outval; + thisline_changed |= (data[offs] ^ outval) >>> 0; data[offs++] = outval; + tmp_nbits = 0; + } + } + //shiftbuffer <<= 16; + shiftbuffer_hi = (((shiftbuffer_hi << 16) & 0xffffffff) | (shiftbuffer_lo >>> 16)) >>> 0; + shiftbuffer_lo = (shiftbuffer_lo << 16) & 0xffffffff; + } + nwords -= 2; + if (dma) { + fetchval = ((SAER_Memory_chipData[real_pt] << 24) | (SAER_Memory_chipData[real_pt+1] << 16) | (SAER_Memory_chipData[real_pt+2] << 8) | SAER_Memory_chipData[real_pt+3]) >>> 0; + real_pt += 4; + //fetchval = do_get_mem_long(real_pt); real_pt++; + //fetchval = ((SAER_Memory_chipData[real_pt2] << 16) | SAER_Memory_chipData[real_pt2 + 1]) >>> 0; real_pt2 += 2; + //#if 0 + //if (plane == 0) fetchval ^= 0x5555555555555555; + //#endif + } + + } + //fetched_aga[plane] = fetchval; + fetched_aga_lo[plane] = fetchval; + //todisplay2_aga[plane] = (shiftbuffer >> delay) & 0xffffffff; + if (delay) { + todisplay2_aga_lo[plane] = (((shiftbuffer_hi << (32 - delay)) & 0xffffffff) | (shiftbuffer_lo >>> delay)); //ATT + todisplay2_aga_hi[plane] = shiftbuffer_hi >>> delay; + } else { + todisplay2_aga_hi[plane] = shiftbuffer_hi; + todisplay2_aga_lo[plane] = shiftbuffer_lo; + } + outword[plane] = outval; + } + + /*#ifdef HAVE_UAE_U128 + //uae_u128 is available, custom shift functions not necessary + #else*/ + /*function shift32plus(p, n) { + var t = p[1]; //u64 + t = (t << n) | (p[0] >> (64 - n)); + p[1] = t; + } + function aga_shift(p, n) { + if (n == 0) return; + shift32plus(p, n); + p[0] <<= n; + } + function shift32plus_n(p, n) { + var t = p[0]; //u64 + t = (t >> n) | (p[1] << (64 - n)); + p[0] = t; + } + function aga_shift_n(p, n) { + if (n == 0) return; + shift32plus_n(p, n); + p[1] >>= n; + }*/ + //#endif + + function aga_shift(p, n) { + if (n) { + //p[1] = (p[1] << n) | (p[0] >> (64 - n)); + //p[0] <<= n; + n &= 31; + p[3] = (p[3] << n) | (p[2] >>> (32 - n)); + p[2] = (p[2] << n) | (p[1] >>> (32 - n)); + p[1] = (p[1] << n) | (p[0] >>> (32 - n)); + p[0] <<= n; + } + } + function aga_shift_n(p, n) { + if (n) { + //p[0] = (p[0] >> n) | (p[1] << (64 - n)); + //p[1] >>= n; + n &= 31; + p[0] = (p[1] << (32 - n)) | (p[0] >>> n); + p[1] = (p[2] << (32 - n)) | (p[1] >>> n); + p[2] = (p[3] << (32 - n)) | (p[2] >>> n); + p[3] >>>= n; + } + } + + function long_fetch_64(plane, nwords, weird_number_of_bits, dma) { + //uae_u32 *real_pt = (uae_u32 *)pfield_xlateptr (bplpt[plane], nwords * 2); + var real_pt = pfield_xlateptr(bplpt[plane], nwords * 2); + //var real_pt2 = bplpt[plane] >>> 1; + var delay = toscr_delay_adjusted[plane & 1]; + var tmp_nbits = out_nbits; + /*#ifdef HAVE_UAE_U128 + uae_u128 shiftbuffer; + #else + uae_u64 shiftbuffer[2]; + #endif*/ + var shiftbuffer = new Uint32Array(4); + var outval = outword[plane]; //u32 + //var fetchval = fetched_aga[plane]; //u64 + var fetchval_hi = fetched_aga_hi[plane]; + var fetchval_lo = fetched_aga_lo[plane]; + //uae_u32 *dataptr = (uae_u32 *)(line_data[next_lineno] + 2 * plane * MAX_WORDS_PER_LINE + 4 * out_offs); + var data = line_data[next_lineno]; + var offs = MAX_WORDS_PER_LINE_FULL * plane + out_offs; //OWN + //var shift = (64 - 16) + delay; //int + var shift = 48 + delay; //int + + if (dma) { + bplpt[plane] += nwords * 2; + bplptx[plane] += nwords * 2; + } + + if (real_pt === null) //Don't do this, fall back on chipmem_wget instead. + return; + + /*#ifdef HAVE_UAE_U128 + shiftbuffer = todisplay2_aga[plane] << delay; + #else + shiftbuffer[1] = 0; + shiftbuffer[0] = todisplay2_aga[plane]; + aga_shift(shiftbuffer, delay); + #endif*/ + shiftbuffer[3] = 0; + shiftbuffer[2] = 0; + shiftbuffer[1] = todisplay2_aga_hi[plane]; + shiftbuffer[0] = todisplay2_aga_lo[plane]; + aga_shift(shiftbuffer, delay); + + while (nwords > 0) { + /*#ifdef HAVE_UAE_U128 + shiftbuffer |= fetchval; + #else + shiftbuffer[0] |= fetchval; + #endif*/ + shiftbuffer[1] |= fetchval_hi; + shiftbuffer[0] |= fetchval_lo; + + for (var i = 0; i < 4; i++) { + var t; //u32 + var bits_left = 32 - tmp_nbits; + + /*#ifdef HAVE_UAE_U128 + t = (shiftbuffer >> shift) & 0xffff; + #else + if (64 - shift > 0) { + t = (shiftbuffer[1] << (64 - shift)) | (shiftbuffer[0] >> shift); + } else { + t = shiftbuffer[1] >> (shift - 64); + } + t &= 0xffff; + #endif*/ + + if (shift < 32) + t = ((shiftbuffer[1] << (32 - shift)) | (shiftbuffer[0] >>> (shift - 0))) & 0xffff; + else if (shift < 64) + t = ((shiftbuffer[2] << (64 - shift)) | (shiftbuffer[1] >>> (shift - 32))) & 0xffff; + else if (shift < 96) + t = ((shiftbuffer[3] << (96 - shift)) | (shiftbuffer[2] >>> (shift - 64))) & 0xffff; + else + t = (shiftbuffer[3] >>> (shift - 96)) & 0xffff; + + //t = (Math.random() * 0xffff) >>> 0; + + if (weird_number_of_bits && bits_left < 16) { + outval = (outval << bits_left) & 0xffffffff; + outval = (outval | (t >>> (16 - bits_left))) >>> 0; + //thisline_changed |= *dataptr ^ outval; *dataptr++ = outval; + thisline_changed |= (data[offs] ^ outval) >>> 0; data[offs++] = outval; + outval = t; + tmp_nbits = 16 - bits_left; + } else { + outval = (((outval << 16) & 0xffffffff) | t) >>> 0; + tmp_nbits += 16; + if (tmp_nbits == 32) { + //thisline_changed |= *dataptr ^ outval; *dataptr++ = outval; + thisline_changed |= (data[offs] ^ outval) >>> 0; data[offs++] = outval; + tmp_nbits = 0; + } + } + /*#ifdef HAVE_UAE_U128 + shiftbuffer <<= 16; + #else*/ + aga_shift(shiftbuffer, 16); + //#endif + } + + nwords -= 4; + + if (dma) { + fetchval_hi = ((SAER_Memory_chipData[real_pt ] << 24) | (SAER_Memory_chipData[real_pt+1] << 16) | (SAER_Memory_chipData[real_pt+2] << 8) | SAER_Memory_chipData[real_pt+3]) >>> 0; + fetchval_lo = ((SAER_Memory_chipData[real_pt+4] << 24) | (SAER_Memory_chipData[real_pt+5] << 16) | (SAER_Memory_chipData[real_pt+6] << 8) | SAER_Memory_chipData[real_pt+7]) >>> 0; + real_pt += 8; + //fetchval = ((uae_u64)do_get_mem_long (real_pt)) << 32; + //fetchval |= do_get_mem_long (real_pt + 1); + //real_pt += 2; + //fetchval_hi = SAER_Memory_chipGet32_indirect(real_pt); + //fetchval_lo = SAER_Memory_chipGet32_indirect(real_pt + 4); + //real_pt += 8; + //fetchval_hi = ((SAER_Memory_chipData[real_pt2 ] << 16) | SAER_Memory_chipData[real_pt2 + 1]) >>> 0; + //fetchval_lo = ((SAER_Memory_chipData[real_pt2 + 2] << 16) | SAER_Memory_chipData[real_pt2 + 3]) >>> 0; + //real_pt2 += 4; + + //#if 0 + /*if (plane == 0) { + //fetchval ^= 0x5555555555555555; + fetchval_hi = (fetchval_hi ^ 0x55555555) >>> 0; + fetchval_lo = (fetchval_lo ^ 0x55555555) >>> 0; + }*/ + //#endif + } + } + //fetched_aga[plane] = fetchval; + fetched_aga_hi[plane] = fetchval_hi; + fetched_aga_lo[plane] = fetchval_lo; + + /*#ifdef HAVE_UAE_U128 + todisplay2_aga[plane] = shiftbuffer >> delay; + #else*/ + aga_shift_n(shiftbuffer, delay); + //todisplay2_aga[plane] = shiftbuffer[0]; + todisplay2_aga_hi[plane] = shiftbuffer[1]; + todisplay2_aga_lo[plane] = shiftbuffer[0]; + //#endif + outword[plane] = outval; + } + //#endif //AGA*/ + + /*OPT inline, ok + function long_fetch_16_0(hpos, nwords, dma) { long_fetch_16(hpos, nwords, 0, dma); } + function long_fetch_16_1(hpos, nwords, dma) { long_fetch_16(hpos, nwords, 1, dma); } + //#ifdef AGA + function long_fetch_32_0(hpos, nwords, dma) { long_fetch_32(hpos, nwords, 0, dma); } + function long_fetch_32_1(hpos, nwords, dma) { long_fetch_32(hpos, nwords, 1, dma); } + function long_fetch_64_0(hpos, nwords, dma) { long_fetch_64(hpos, nwords, 0, dma); } + function long_fetch_64_1(hpos, nwords, dma) { long_fetch_64(hpos, nwords, 1, dma); } + //#endif + function do_long_fetch(hpos, nwords, dma, fm) { + var i; + + flush_display (fm); + beginning_of_plane_block(hpos, fm); + + switch (fm) { + case 0: + if (out_nbits & 15) { + for (i = 0; i < toscr_nr_planes; i++) + long_fetch_16_1(i, nwords, dma); + } else { + for (i = 0; i < toscr_nr_planes; i++) + long_fetch_16_0(i, nwords, dma); + } + break; + //#ifdef AGA + case 1: + if (out_nbits & 15) { + for (i = 0; i < toscr_nr_planes; i++) + long_fetch_32_1(i, nwords, dma); + } else { + for (i = 0; i < toscr_nr_planes; i++) + long_fetch_32_0(i, nwords, dma); + } + break; + case 2: + if (out_nbits & 15) { + for (i = 0; i < toscr_nr_planes; i++) + long_fetch_64_1(i, nwords, dma); + } else { + for (i = 0; i < toscr_nr_planes; i++) + long_fetch_64_0(i, nwords, dma); + } + break; + //#endif + } + + out_nbits += nwords * 16; + out_offs += out_nbits >> 5; + out_nbits &= 31; + delay_cycles += nwords * 16; + + if (dma && toscr_nr_planes > 0) + fetch_state = fetch_was_plane0; + }*/ + function do_long_fetch(hpos, nwords, dma, fm) { + var i; + + flush_display (fm); + beginning_of_plane_block(hpos, fm); + + switch (fm) { + case 0: + if (out_nbits & 15) { + for (i = 0; i < toscr_nr_planes; i++) + long_fetch_16(i, nwords, 1, dma); + } else { + for (i = 0; i < toscr_nr_planes; i++) + long_fetch_16(i, nwords, 0, dma); + } + break; + //#ifdef AGA + case 1: + if (out_nbits & 15) { + for (i = 0; i < toscr_nr_planes; i++) + long_fetch_32(i, nwords, 1, dma); + } else { + for (i = 0; i < toscr_nr_planes; i++) + long_fetch_32(i, nwords, 0, dma); + } + break; + case 2: + if (out_nbits & 15) { + for (i = 0; i < toscr_nr_planes; i++) + long_fetch_64(i, nwords, 1, dma); + } else { + for (i = 0; i < toscr_nr_planes; i++) + long_fetch_64(i, nwords, 0, dma); + } + break; + //#endif + } + + out_nbits += nwords * 16; + out_offs += out_nbits >> 5; + out_nbits &= 31; + delay_cycles += nwords * 16; + + if (dma && toscr_nr_planes > 0) + fetch_state = fetch_was_plane0; + } + //#endif /* SPEEDUP */ + + function finish_last_fetch(pos, fm, reallylast) { + if (thisline_decision.plfleft < 0) + return; + if (plfr_state >= plfr_end) + return; + plfr_state = plfr_end; + + flush_display(fm); + // This may not be the last fetch, store current endpos for future use. + // There is at least one demo that has two DDFSTRT-DDFSTOP horizontal sections + // Subtle Shades / Nuance. + thisline_decision.plfright = pos; + + if (!reallylast) { + if (SAEV_config.chipset.mask & SAEC_Config_Chipset_Mask_ECS_AGNUS) { + ddfstate = DIW_WAITING_START; + fetch_state = fetch_not_started; + } + } + } + /* check special case where last fetch wraps to next line + * this makes totally corrupted and flickering display on + * real hardware due to refresh cycle conflicts + */ + function maybe_finish_last_fetch(pos, fm) { + //static int warned = 20; + var done = false; + + if (plf_state != plf_passed_stop2 || (fetch_state != fetch_started && fetch_state != fetch_started_first) || aga_plf_passed_stop2 || !SAEF_Custom_dmaen(SAEC_Custom_DMAF_BPLEN)) { + finish_last_fetch(pos, fm, true); + return; + } + do { + var cycle_start = fetch_cycle & fetchstart_mask; + switch (fm_maxplane) { + case 8: + switch (cycle_start) { + case 0: fetch(7, fm, pos); break; + case 1: fetch(3, fm, pos); break; + case 2: fetch(5, fm, pos); break; + case 3: fetch(1, fm, pos); break; + case 4: fetch(6, fm, pos); break; + case 5: fetch(2, fm, pos); break; + case 6: fetch(4, fm, pos); break; + case 7: fetch(0, fm, pos); break; + default: { + //goto end; + finish_last_fetch(pos, fm, true); return; + } + } + break; + case 4: + switch (cycle_start) { + case 0: fetch(3, fm, pos); break; + case 1: fetch(1, fm, pos); break; + case 2: fetch(2, fm, pos); break; + case 3: fetch(0, fm, pos); break; + default: { + //goto end; + finish_last_fetch(pos, fm, true); return; + } + } + break; + case 2: + switch (cycle_start) { + case 0: fetch(1, fm, pos); break; + case 1: fetch(0, fm, pos); break; + default: { + //goto end; + finish_last_fetch(pos, fm, true); return; + } + } + break; + } + fetch_cycle++; + toscr_nbits += toscr_res2p; + + if (toscr_nbits > 16) + toscr_nbits = 0; + if (toscr_nbits == 16) + flush_display(fm); + done = true; + bitplane_line_crossing = pos; + } while ((fetch_cycle & fetchunit_mask) != 0); + + if (done && warned_maybe_finish_last_fetch > 0) { + warned_maybe_finish_last_fetch--; + SAEF_warn("playfield.maybe_finish_last_fetch() bitplane DMA crossing scanlines!"); + } + //end: + finish_last_fetch(pos, fm, true); + } + + /* make sure fetch that goes beyond maxhpos is finished */ + function finish_final_fetch() { + if (thisline_decision.plfleft < 0) + return; + + if (plfr_state < plfr_end) + finish_last_fetch(maxhpos, fetchmode, true); + plfr_state = plfr_finished; + + // workaround for too long fetches that don't pass plf_passed_stop2 before end of scanline + if (aga_plf_passed_stop2 && plf_state >= plf_passed_stop) + plf_state = plf_end; + + // This is really the end of scanline, we can finally flush all remaining data. + thisline_decision.plfright += flush_plane_data(fetchmode); + thisline_decision.plflinelen = out_offs; + + finish_playfield_line(); + } + + //function one_fetch_cycle_0(pos, dma, fm) { //ORG + function one_fetch_cycle(pos, dma, fm) { + var bplactive = true; + var diw = diwstate == DIW_WAITING_STOP; + if (plf_state == plf_wait && dma && diw) { + // same timings as when switching off, see below + bpl_dma_off_when_active = 0; + bplactive = false; + if (bitplane_off_delay >= 0) + bitplane_off_delay = !dma ? -4 : -5; + if (bitplane_off_delay < 0) { + bitplane_off_delay++; + if (bitplane_off_delay == 0) { + if (SAEV_config.chipset.mask & SAEC_Config_Chipset_Mask_ECS_AGNUS) { + plf_state = plf_passed_stop; + } else { + plf_state = plf_active; + } + } + } + } else if (!dma || !diw) { + bplactive = false; + // dma off: turn off bitplane output after 4 cycles + // (yes, switching DMA off won"t disable it immediately) + // diw off: turn off bitplane output after 5 cycles + // (Starflight / Phenomena jumping scroller in ECS) + // This is not correctly emulated, there probably is + // 4+ stage shift register that causes these delays. + if (plf_state == plf_active || plf_state == plf_passed_stop || plf_state == plf_passed_stop_act) { + bpl_dma_off_when_active = 1; + if (bitplane_off_delay <= 0) + bitplane_off_delay = !dma ? 4 : 5; + } + if (bitplane_off_delay > 0) { + bplactive = true; + bitplane_off_delay--; + if (bitplane_off_delay == 0) { + bplactive = false; + plf_state = plf_wait; + } + } + } + + if ((dma && diw) || (SAEV_config.chipset.mask & SAEC_Config_Chipset_Mask_ECS_AGNUS)) { + if (plf_state != plf_wait) { + if (pos == plfstop && ddfstop_written_hpos != pos) { + if (plf_state < plf_passed_stop) { + plf_state = plf_passed_stop; + } + plf_end_hpos = pos + DDF_OFFSET; + } else if (pos == plf_end_hpos) { + ddfstop_matched = true; + if (plf_state < plf_passed_stop_act) { + plf_state = plf_passed_stop_act; + } + } + } + } + + if ((fetch_cycle & fetchunit_mask) == 0) { + if (plf_state == plf_passed_stop2) { + finish_last_fetch(pos, fm, false); + return 1; + } + if (plf_state == plf_passed_stop_act) { + plf_state = plf_passed_stop2; + } + } + + // must be after above test, otherwise same fetch + // block may pass both stop_act and stop2 tests. + if (pos == HARD_DDF_STOP()) { + if (plf_state < plf_wait) { + plf_state = plf_passed_stop_act; + } + } + + maybe_check(pos); + + if (bplactive) { + /* fetchstart_mask can be larger than fm_maxplane if FMODE > 0. This means + that the remaining cycles are idle; we"ll fall through the whole switch + without doing anything. */ + var cycle_start = fetch_cycle & fetchstart_mask; + switch (fm_maxplane) { + case 8: + switch (cycle_start) { + case 0: fetch(7, fm, pos); break; + case 1: fetch(3, fm, pos); break; + case 2: fetch(5, fm, pos); break; + case 3: fetch(1, fm, pos); break; + case 4: fetch(6, fm, pos); break; + case 5: fetch(2, fm, pos); break; + case 6: fetch(4, fm, pos); break; + case 7: fetch(0, fm, pos); break; + //#ifdef AGA + default: { + // if AGA: consider plf_passed_stop2 already + // active when last plane has been written, + // even if there is still idle cycles left + if (plf_state == plf_passed_stop_act) + aga_plf_passed_stop2 = true; + //break; + } + //#endif + } + break; + case 4: + switch (cycle_start) { + case 0: fetch(3, fm, pos); break; + case 1: fetch(1, fm, pos); break; + case 2: fetch(2, fm, pos); break; + case 3: fetch(0, fm, pos); break; + //#ifdef AGA + default: { + if (plf_state == plf_passed_stop_act) + aga_plf_passed_stop2 = true; + //break; + } + //#endif + } + break; + case 2: + switch (cycle_start) { + case 0: fetch(1, fm, pos); break; + case 1: fetch(0, fm, pos); break; + //#ifdef AGA + default: { + if (plf_state == plf_passed_stop_act) + aga_plf_passed_stop2 = true; + //break; + } + //#endif + } + break; + } + } + + if (bpl1dat_written) { + // do this here because if program plays with BPLCON0 during scanline + // it is possible that one DMA BPL1DAT write is completely missed + // and we must not draw anything at all in next dma block if this happens + // (Disposable Hero titlescreen) + fetch_state = fetch_was_plane0; + bpl1dat_written = false; + } + + fetch_cycle++; + toscr_nbits += toscr_res2p; + + if (bplcon1_written) { + flush_display(fm); + compute_toscr_delay(bplcon1); + bplcon1_written = false; + } + + if (toscr_nbits > 16) { + SAEF_error("one_fetch_cycle() toscr_nbits > 16 (%d)", toscr_nbits); + toscr_nbits = 0; + } + if (toscr_nbits == 16) + flush_display(fm); + + return 0; + } + /*OPT inline ok + function one_fetch_cycle_fm0( pos, dma) { return one_fetch_cycle_0(pos, dma, 0); } + function one_fetch_cycle_fm1( pos, dma) { return one_fetch_cycle_0(pos, dma, 1); } + function one_fetch_cycle_fm2( pos, dma) { return one_fetch_cycle_0(pos, dma, 2); } + function one_fetch_cycle(pos, dma, fm) { + switch (fm) { + case 0: return one_fetch_cycle_fm0(pos, dma); + //#ifdef AGA + case 1: return one_fetch_cycle_fm1(pos, dma); + case 2: return one_fetch_cycle_fm2(pos, dma); + //#endif + default: + SAEF_error("one_fetch_cycle() fm corrupt (%d)", fm); + return 0; + } + } + function one_fetch_cycle(pos, dma, fm) { + return one_fetch_cycle_0(pos, dma, fm); + }*/ + + function update_fetch_x(until, fm) { + if (nodraw()) + return; + + var pos = last_fetch_hpos; + update_toscr_planes(fm); + + // not optimized, update_fetch_x() is extremely rarely used. + for (; pos < until; pos++) { + toscr_nbits += toscr_res2p; + if (toscr_nbits > 16) { + SAEF_error("update_fetch_x() toscr_nbits > 16 (%d)", toscr_nbits); + toscr_nbits = 0; + } + if (toscr_nbits == 16) + flush_display(fm); + } + if (until >= maxhpos) { + maybe_finish_last_fetch(pos, fm); + return; + } + flush_display(fm); + } + function update_fetch(until, fm) { + var dma = SAEF_Custom_dmaen(SAEC_Custom_DMAF_BPLEN); + + if (nodraw() || plf_state >= plf_end) + return; + + var pos = last_fetch_hpos; + cycle_diagram_shift = last_fetch_hpos - fetch_cycle; + + /* First, a loop that prepares us for the speedup code. We want to enter + the SPEEDUP case with fetch_state == fetch_was_plane0 or it is the very + first fetch cycle (which equals to same state as fetch_was_plane0) + and then unroll whole blocks, so that we end on the same fetch_state again. */ + for (; ; pos++) { + if (pos == until) { + if (until >= maxhpos) { + maybe_finish_last_fetch(pos, fm); + return; + } + return; + } + + if (fetch_state == fetch_was_plane0) + break; + /*#if 0 + if (fetch_state == fetch_started_first) { + #if SPEEDUP + if (until >= maxhpos) { + fetch_state = fetch_was_plane0; + break; + } + #endif + fetch_state = fetch_started; + } + #endif*/ + fetch_state = fetch_started; //fetch_start(pos); OWN + if (one_fetch_cycle(pos, dma, fm)) + return; + } + //Unrolled version of the for loop below. + if (SPEEDUP && + plf_state == plf_active && !line_cyclebased && dma + && (fetch_cycle & fetchstart_mask) == (fm_maxplane & fetchstart_mask) + && !badmode + && toscr_nr_planes == toscr_nr_planes_agnus) + { + var ddfstop_to_test_ddf = HARD_DDF_STOP(); + if (plfstop >= last_fetch_hpos - DDF_OFFSET && plfstop < ddfstop_to_test_ddf) + ddfstop_to_test_ddf = plfstop; + var ddfstop_to_test = ddfstop_to_test_ddf + DDF_OFFSET; + var offs = (pos - fetch_cycle) & fetchunit_mask; + var ddf2 = ((ddfstop_to_test - offs + fetchunit - 1) & ~fetchunit_mask) + offs; + var ddf3 = ddf2 + fetchunit; + var stop = until < ddf2 ? until : until < ddf3 ? ddf2 : ddf3; + + var count = stop - pos; + if (count >= fetchstart) { + count &= ~fetchstart_mask; + var stoppos = pos + count; + + if (thisline_decision.plfleft < 0) + compute_toscr_delay(bplcon1); + + do_long_fetch (pos, count >> (3 - toscr_res), dma, fm); + + // This must come _after_ do_long_fetch so as not to confuse flush_display + // into thinking the first fetch has produced any output worth emitting to + // the screen. But the calculation of delay_offset must happen _before_. + maybe_first_bpl1dat (pos); + + if (pos <= plfstop && stoppos > plfstop) { + plf_state = plf_passed_stop; + plf_end_hpos = plfstop + DDF_OFFSET; + } + if (pos <= plfstop + DDF_OFFSET && stoppos > plfstop + DDF_OFFSET) { + plf_state = plf_passed_stop_act; + plf_end_hpos = 256 + DDF_OFFSET; + ddfstop_matched = true; + } + if (pos <= HARD_DDF_STOP() && stoppos > HARD_DDF_STOP()) { + if (plf_state < plf_wait) + plf_state = plf_passed_stop_act; + } + if (pos <= ddfstop_to_test && stoppos > ddf2) { + plf_state = plf_passed_stop2; + } + if (pos <= ddf2 && stoppos >= ddf2 + fm_maxplane) { + add_modulos (); + } + pos += count; + fetch_cycle += count; + } + } + for (; pos < until; pos++) { + if (fetch_state == fetch_was_plane0) { + flush_display(fm); + beginning_of_plane_block(pos, fm); + } + fetch_state = fetch_started; //fetch_start(pos); OWN + + if (one_fetch_cycle(pos, dma, fm)) + return; + } + if (until >= maxhpos) { + maybe_finish_last_fetch(pos, fm); + return; + } + flush_display(fm); + } + + /*OPT inline, ok + function update_fetch_0(hpos) { update_fetch(hpos, 0); } + function update_fetch_1(hpos) { update_fetch(hpos, 1); } + function update_fetch_2(hpos) { update_fetch(hpos, 2); }*/ + this.decide_fetch = function(hpos) { + if (hpos > last_fetch_hpos) { + if (fetch_state != fetch_not_started) { + /*ORG + switch (fetchmode) { + case 0: update_fetch_0(hpos); break; + //#ifdef AGA + case 1: update_fetch_1(hpos); break; + case 2: update_fetch_2(hpos); break; + //#endif + default: SAEF_error("decide_fetch() corrupt fetchmode (%d)", fetchmode); + }*/ + update_fetch(hpos, fetchmode); + } else if (bpl1dat_written_at_least_once) { + // "PIO" mode display + update_fetch_x(hpos, fetchmode); + bpl1dat_written = false; + } + maybe_check(hpos); + last_fetch_hpos = hpos; + } + } + this.decide_fetch_safe = function(hpos) { + if (!SAEV_Blitter_dangerous) { + this.decide_fetch(hpos); + SAER.blitter.decide_blitter(hpos); + } else { + while (hpos > last_fetch_hpos) { + this.decide_fetch(last_fetch_hpos + 1); + SAER.blitter.decide_blitter(last_fetch_hpos + 1); + } + } + } + + function reset_bpl_vars() { + out_nbits = 0; + out_offs = 0; + toscr_nbits = 0; + thisline_decision.bplres = bplcon0_res; + } + + function start_bpl_dma(hstart) { + if (first_bpl_vpos < 0) + first_bpl_vpos = vpos; + + if (doflickerfix() && interlace_seen > 0 && !scandoubled_line) { + for (var i = 0; i < 8; i++) { + prevbpl[lof_current][vpos][i] = bplptx[i]; + if (!lof_current && (bplcon0 & 4)) + bplpt[i] = prevbpl[1 - lof_current][vpos][i]; + if (!(bplcon0 & 4) || interlace_seen < 0) + prevbpl[1 - lof_current][vpos][i] = prevbpl[lof_current][vpos][i] = 0; + } + } + + /*#if 0 + fetch_state = (fm_maxplane == fetchstart) ? fetch_started_first : fetch_started; + #else*/ + fetch_state = fetch_started; + //#endif + plfr_state = plfr_active; + ddfstate = DIW_WAITING_STOP; + bpl_hstart = hstart; + + if (!bpldmawasactive) { + if (last_fetch_hpos < 0) + last_fetch_hpos = 0; + plfstrt_sprite = hstart; + // OCS Agnus needs at least 1 empty cycle between + // sprite fetch and bitplane cycle sequence start. + if (!(SAEV_config.chipset.mask & SAEC_Config_Chipset_Mask_ECS_AGNUS)) + plfstrt_sprite--; + fetch_cycle = 0; + update_denise(last_fetch_hpos); + if (bpl1dat_written_at_least_once && hstart > last_fetch_hpos) { + update_fetch_x(hstart, fetchmode); + bpl1dat_written_at_least_once = false; + } else { + reset_bpl_vars(); + } + cycle_diagram_shift = hstart; + bpldmawasactive = true; + } else { + flush_display(fetchmode); + // Calculate difference between last end to new start + var diff = (hstart - thisline_decision.plfright) << (1 + toscr_res); + // Render all missing pixels, use toscr because previous data may still be in buffers. + while (diff >= 16) { + toscr_1(16, fetchmode); + diff -= 16; + } + if (diff) toscr_1(diff, fetchmode); + + cycle_diagram_shift = hstart; + update_denise(last_fetch_hpos); + update_fetch_x(hstart, fetchmode); + } + + last_fetch_hpos = hstart; + estimate_last_fetch_cycle(hstart); + } + + function cant_this_last_line() { + // Last line.. + // ..works normally if A1000 Agnus + if (SAEV_config.chipset.agnusDIP) + return false; + // ..inhibits bitplane and sprite DMA if later Agnus revision. + return vpos + 1 >= maxvpos + lof_store; + } + + /* This function is responsible for turning on datafetch if necessary. */ + this.decide_line = function(hpos) { + var ecs = (SAEV_config.chipset.mask & SAEC_Config_Chipset_Mask_ECS_AGNUS) != 0; + + /* Take care of the vertical DIW. */ + if (vpos == plffirstline) { + // A1000 Agnus won"t start bitplane DMA if vertical diw is zero. + if (vpos > 0 || (vpos == 0 && !SAEV_config.chipset.agnusDIP)) { + diwstate = DIW_WAITING_STOP; + line_cyclebased = 2; //SET_LINE_CYCLEBASED(); + } + } + // last line of field can never have bitplane dma active if not A1000 Agnus. + if (vpos == plflastline || cant_this_last_line() || (vpos == 0 && SAEV_config.chipset.agnusDIP)) { + diwstate = DIW_WAITING_START; + line_cyclebased = 2; //SET_LINE_CYCLEBASED(); + } + + if (hpos <= last_decide_line_hpos) + return; + + var dma = SAEF_Custom_dmaen(SAEC_Custom_DMAF_BPLEN) != 0; + var diw = diwstate == DIW_WAITING_STOP; + + if (ecs) { + //if (1) { + if (last_decide_line_hpos < plfstrt && hpos >= plfstrt) { + ddfstop_matched = false; + } + //} + } else { + //if (1) { + if (last_decide_line_hpos < plfstrt && hpos >= plfstrt) { + ddfstop_matched = false; + // plfstrt==0 works strangely (Nakudemo / Vision-X) + if (plfstrt > -DDF_OFFSET) + ocs_agnus_ddf_enable_toggle = false; + } + //} + } + + if (fetch_state == fetch_not_started) { + var strtpassed = false; + var nextstate = plf_end; + var hstart; + + hstart = last_decide_line_hpos; + if (hstart < bitplane_maybe_start_hpos) + hstart = bitplane_maybe_start_hpos; + if (hstart < HARD_DDF_START_REAL + DDF_OFFSET) + hstart = HARD_DDF_START_REAL + DDF_OFFSET; + // DMA enabled mid-line: DDF_OFFSET delay first + if (bitplane_maybe_start_hpos + DDF_OFFSET > hstart) + hstart = bitplane_maybe_start_hpos + DDF_OFFSET; + if (hstart & 1) + hstart++; + + if (ecs) { + // ECS DDFSTRT/STOP matching does not require DMA or DIW. + //if (1) { + if (last_decide_line_hpos < plfstrt && hpos >= plfstrt) { + // active == already started because ddfstop was not detected in last line + if (plf_state != plf_active) { + plf_state = plf_passed_start; + strtpassed = true; + plf_start_hpos = plfstrt + DDF_OFFSET; + } + } + //} + //if (1) { + if ((strtpassed && hpos >= plf_start_hpos) || (last_decide_line_hpos < plf_start_hpos && hpos >= plf_start_hpos)) { + if (plf_state == plf_passed_start) { + plf_state = plf_active; + hstart = plf_start_hpos; + } + } + //} + } else { + //if (1) { + var start = HARD_DDF_START_REAL; + if (last_decide_line_hpos < start && hpos >= start) { + if (!ocs_agnus_ddf_enable_toggle) + plf_state = plf_passed_enable; + ocs_agnus_ddf_enable_toggle = true; + } + //} + // OCS DDFSTRT/STOP matching requires DMA and DIW enabled. + if (dma && diw) { + if (last_decide_line_hpos < plfstrt && hpos >= plfstrt) { + if (plf_state == plf_passed_enable) { + plf_state = plf_passed_start; + strtpassed = true; + plf_start_hpos = plfstrt + DDF_OFFSET; + } + ocs_agnus_ddf_enable_toggle = false; + } + } + if (dma && diw) { + if ((strtpassed && hpos >= plf_start_hpos) || (last_decide_line_hpos < plf_start_hpos && hpos >= plf_start_hpos)) { + if (plf_state == plf_passed_start) { + plf_state = plf_active; + hstart = plf_start_hpos; } } } - for (var i = 0; i < out_offs; i++) line_data[next_lineno][j][i] = 0; //memset(ptr, 0, out_offs * 4); } - thisline_decision.nr_planes = toscr_nr_planes2; - } - }; - this.maybe_first_bpl1dat = function (hpos) { - if (thisline_decision.plfleft >= 0) { - if (plfleft_real < 0) { - for (var i = 0; i < MAX_PLANES; i++) { - todisplay[i][0] = 0; - /*#ifdef AGA - todisplay[i][1] = 0; - todisplay[i][2] = 0; - todisplay[i][3] = 0; - #endif*/ + if (diw && dma) { + var test = false; + if (ecs) { + test = (plf_state == plf_active && (hpos >= HARD_DDF_START_REAL + DDF_OFFSET || HARD_DDF_LIMITS_DISABLED())); + if (bpl_dma_off_when_active) { + if (plfstop < hstart) { + test = false; + } + } + } else { + test = (plf_state == plf_active); + // if DMA enabled mid-scanline but ddfstrt not matched (dma was off): start when ddfstop is matched + // (Crash Landing crack intro / Scoopex) + if (!test && last_decide_line_hpos < plfstop && hstart > plfstop) { + if (hstart == ((bitplane_maybe_start_hpos + DDF_OFFSET + 1) & ~1)) { + hstart = plfstop + DDF_OFFSET; + test = true; + nextstate = plf_passed_stop; + } + } + } + if (test) { + start_bpl_dma(hstart); + // if ECS: pre-set plf_end_hpos if we have already passed virtual ddfstop + if (ecs) { + if (last_decide_line_hpos < hstart && hstart >= plfstop && hstart - plfstop <= DDF_OFFSET) { + plf_end_hpos = plfstop + DDF_OFFSET; + nextstate = plf_passed_stop; + } + if (last_decide_line_hpos < HARD_DDF_STOP() && hstart > HARD_DDF_STOP()) { + plf_end_hpos = HARD_DDF_STOP() + DDF_OFFSET; + nextstate = plf_passed_stop; + } + if (bpl_dma_off_when_active) { + nextstate = plf_passed_stop_act; + bpl_dma_off_when_active = 0; + } + } + if (nextstate != plf_end) { + plf_state = nextstate; + estimate_last_fetch_cycle(hstart); + } + last_decide_line_hpos = hpos; + do_sprites(hpos); + return; } - plfleft_real = hpos; - bpl1dat_early = true; - } - } else { - plfleft_real = thisline_decision.plfleft = hpos; - this.compute_delay_offset(); - } - }; - - this.checklacecount = function (lace) { - if (lace === null) - lace = (bplcon0 & 4) != 0; + } + + if (ecs) { + //if (1) { + // ddfstrt == ddfstop: ddfstrt wins. + if (plfstrt != plfstop && last_decide_line_hpos < plfstop && hpos >= plfstop && plfstop <= maxhpos - DDF_OFFSET) { + ddfstop_matched = true; + if (plf_state != plf_wait && plf_state < plf_passed_stop) { + plf_state = plf_passed_stop; + plf_end_hpos = plfstop + DDF_OFFSET; + } + } + if (last_decide_line_hpos < HARD_DDF_STOP() && hpos >= HARD_DDF_STOP()) { + plf_state = plf_passed_stop_act; + } + //} + } else { + if (dma && diw) { + if (last_decide_line_hpos < plfstop && hpos >= plfstop && plfstop <= maxhpos - DDF_OFFSET && plf_state != plf_wait) { + ddfstop_matched = true; + } + } + } + } + + if (hpos > last_sprite_hpos && last_sprite_hpos < SPR0_HPOS + 4 * MAX_SPRITES) + do_sprites(hpos); + + last_decide_line_hpos = hpos; + } + + /*-----------------------------------------------------------------------*/ + /* SECT colors */ + + /* Called when a color is about to be changed (write to a color register), + * but the new color has not been entered into the table yet. */ + function record_color_change(hpos, regno, value) { + if (regno < 0x1000 && nodraw()) + return; + /* Early positions don't appear on-screen. */ + if (vpos < minfirstline) + return; + + decide_diw(hpos); + SAER.playfield.decide_line(hpos); + + if (thisline_decision.ctable < 0) + remember_ctable(); + + if ((regno < 0x1000 || regno == 0x1000 + 0x10c) && hpos < HBLANK_OFFSET && !(beamcon0 & 0x80) && prev_lineno >= 0) { + //struct draw_info *pdip = curr_drawinfo + prev_lineno; + var pdip = curr_drawinfo[prev_lineno]; + var idx = pdip.last_color_change; + var extrahpos = regno == 0x1000 + 0x10c ? 1 : 0; + var lastsync = false; + /* Move color changes in horizontal cycles 0 to HBLANK_OFFSET to end of previous line. + Cycles 0 to HBLANK_OFFSET are visible in right border on real Amigas. (because of late hsync) */ + if (curr_color_changes[idx - 1].regno == 0xffff) { + idx--; + lastsync = true; + } + pdip.last_color_change++; + pdip.nr_color_changes++; + curr_color_changes[idx].linepos = (hpos + maxhpos) * 2 + extrahpos; + curr_color_changes[idx].regno = regno; + curr_color_changes[idx].value = value; + if (lastsync) { + curr_color_changes[idx + 1].linepos = hsyncstartpos * 2; + curr_color_changes[idx + 1].regno = 0xffff; + curr_color_changes[idx + 2].regno = -1; + } else { + curr_color_changes[idx + 1].regno = -1; + } + } + record_color_change2(hpos, regno, value); + } + + function isbrdblank(hpos, bplcon0, bplcon3) { + //#ifdef ECS_DENISE + var brdblank = (SAEV_config.chipset.mask & SAEC_Config_Chipset_Mask_ECS_DENISE) && (bplcon0 & 1) && (bplcon3 & 0x20); + var brdntrans = (SAEV_config.chipset.mask & SAEC_Config_Chipset_Mask_ECS_DENISE) && (bplcon0 & 1) && (bplcon3 & 0x10); + /*#else + var brdblank = false; + var brdntrans = false; + #endif*/ + if (hpos >= 0 && (ce_is_borderblank(current_colors.extra) != brdblank || ce_is_borderntrans(current_colors.extra) != brdntrans)) { + record_color_change(hpos, 0, COLOR_CHANGE_BRDBLANK | (brdblank ? 1 : 0) | (ce_is_bordersprite(current_colors.extra) ? 2 : 0) | (brdntrans ? 4 : 0)); + current_colors.extra &= ~(1 << CE_BORDERBLANK); + current_colors.extra &= ~(1 << CE_BORDERNTRANS); + current_colors.extra |= brdblank ? (1 << CE_BORDERBLANK) : 0; + current_colors.extra |= brdntrans ? (1 << CE_BORDERNTRANS) : 0; + remembered_color_entry = -1; + } + return brdblank; + } + function issprbrd(hpos, bplcon0, bplcon3) { + //#ifdef AGA + var brdsprt = (SAEV_config.chipset.mask & SAEC_Config_Chipset_Mask_AGA) && (bplcon0 & 1) && (bplcon3 & 0x02); + /*#else + var brdsprt = false; + #endif*/ + if (hpos >= 0 && ce_is_bordersprite(current_colors.extra) != brdsprt) { + record_color_change(hpos, 0, COLOR_CHANGE_BRDBLANK | (ce_is_borderblank(current_colors.extra) ? 1 : 0) | (ce_is_borderntrans(current_colors.extra) ? 4 : 0) | (brdsprt ? 2 : 0)); + current_colors.extra &= ~(1 << CE_BORDERSPRITE); + current_colors.extra |= brdsprt ? (1 << CE_BORDERSPRITE) : 0; + remembered_color_entry = -1; + if (brdsprt && !ce_is_borderblank(current_colors.extra)) + thisline_decision.bordersprite_seen = true; + } + return brdsprt && !ce_is_borderblank(current_colors.extra); + } + + function record_register_change(hpos, regno, value) { + if (regno == 0x100) { // BPLCON0 + if (value & 0x800) + thisline_decision.ham_seen = 1; + thisline_decision.ehb_seen = isehb(value, bplcon2); + isbrdblank(hpos, value, bplcon3); + issprbrd(hpos, value, bplcon3); + } else if (regno == 0x104) { // BPLCON2 + thisline_decision.ehb_seen = isehb(bplcon0, value); + } else if (regno == 0x106) { // BPLCON3 + isbrdblank(hpos, bplcon0, value); + issprbrd(hpos, bplcon0, value); + } + record_color_change(hpos, regno + 0x1000, value); + } + + /*-----------------------------------------------------------------------*/ + /* SECT sprites */ + + //typedef int sprbuf_res_t, cclockres_t, hwres_t, bplres_t; + + function expand_sprres(con0, con3) { + var res; + + switch ((con3 >> 6) & 3) { + //#ifdef ECS_DENISE + case 0: /* ECS defaults (LORES,HIRES=LORES sprite,SHRES=HIRES sprite) */ + if ((SAEV_config.chipset.mask & SAEC_Config_Chipset_Mask_ECS_DENISE) && GET_RES_DENISE(con0) == SAEC_Config_Video_HResolution_SuperHiRes) + res = SAEC_Config_Video_HResolution_HiRes; + else + res = SAEC_Config_Video_HResolution_LoRes; + break; + //#endif + //#ifdef AGA + case 1: + res = SAEC_Config_Video_HResolution_LoRes; + break; + case 2: + res = SAEC_Config_Video_HResolution_HiRes; + break; + case 3: + res = SAEC_Config_Video_HResolution_SuperHiRes; + break; + //#endif + default: + res = SAEC_Config_Video_HResolution_LoRes; + } + return res; + } + + /* handle very rarely needed playfield collision (CLXDAT bit 0) */ + /* only known game needing this is Rotor */ + function do_playfield_collisions() { + var bplres = bplcon0_res; + var ddf_left = thisline_decision.plfleft * 2 << bplres; + var hw_diwlast = coord_window_to_diw_x(thisline_decision.diwlastword); + var hw_diwfirst = coord_window_to_diw_x(thisline_decision.diwfirstword); + var collided, minpos, maxpos; + //#ifdef AGA + var planes = (SAEV_config.chipset.mask & SAEC_Config_Chipset_Mask_AGA) ? 8 : 6; + /*#else + var planes = 6; + #endif*/ + + if (clxcon_bpl_enable == 0) { + clxdat |= 1; + return; + } + if (clxdat & 1) + return; + + collided = false; + minpos = thisline_decision.plfleft * 2; + if (minpos < hw_diwfirst) + minpos = hw_diwfirst; + maxpos = thisline_decision.plfright * 2; + if (maxpos > hw_diwlast) + maxpos = hw_diwlast; + + var ldata = line_data[next_lineno]; + + for (var i = minpos; i < maxpos && !collided; i += 32) { + //var offs = ((i << bplres) - ddf_left) >> 3; + var offs = ((i << bplres) - ddf_left) >> 5; + var total = 0xffffffff; + for (var j = 0; j < planes; j++) { + var ena = (clxcon_bpl_enable >> j) & 1; + var match = (clxcon_bpl_match >> j) & 1; + var t = 0xffffffff; + if (ena) { + if (j < thisline_decision.nr_planes) { + //t = *(uae_u32 *)(line_data[next_lineno] + offs + 2 * j * MAX_WORDS_PER_LINE); + t = ldata[MAX_WORDS_PER_LINE_FULL * j + offs]; + t = (t ^ ((match & 1) - 1) >>> 0) >>> 0; + } else { + t = ((match & 1) - 1) >>> 0; + } + } + total &= t; + } + if (total) { + collided = true; + /*#if 0 + { + for (var k = 0; k < 1; k++) { + uae_u32 *ldata = (uae_u32 *)(line_data[next_lineno] + offs + 2 * k * MAX_WORDS_PER_LINE); + *ldata ^= 0x5555555555; + } + } + #endif*/ + } + } + if (collided) + clxdat |= 1; + } + + /* Sprite-to-sprite collisions are taken care of in record_sprite. This one does playfield/sprite collisions. */ + function do_sprite_collisions() { + var nr_sprites = curr_drawinfo[next_lineno].nr_sprites; + var first = curr_drawinfo[next_lineno].first_sprite_entry; + var collision_mask = clxmask[clxcon >> 12]; + var bplres = bplcon0_res; + var ddf_left = thisline_decision.plfleft * 2 << bplres; + var hw_diwlast = coord_window_to_diw_x(thisline_decision.diwlastword); + var hw_diwfirst = coord_window_to_diw_x(thisline_decision.diwfirstword); + + if (clxcon_bpl_enable == 0) { + clxdat |= 0x1FE; + return; + } + + for (var i = 0; i < nr_sprites; i++) { + //struct sprite_entry *e = curr_sprite_entries + first + i; + var e = curr_sprite_entries[first + i]; + var minpos = e.pos; + var maxpos = e.max; + var minp1 = minpos >> sprite_buffer_res; + var maxp1 = maxpos >> sprite_buffer_res; + + if (maxp1 > hw_diwlast) + maxpos = hw_diwlast << sprite_buffer_res; + if (maxp1 > thisline_decision.plfright * 2) + maxpos = thisline_decision.plfright * 2 << sprite_buffer_res; + if (minp1 < hw_diwfirst) + minpos = hw_diwfirst << sprite_buffer_res; + if (minp1 < thisline_decision.plfleft * 2) + minpos = thisline_decision.plfleft * 2 << sprite_buffer_res; + + for (var j = minpos; j < maxpos; j++) { + var sprpix = spixels[e.first_pixel + j - e.pos] & collision_mask; + var match = true; + + if (sprpix == 0) + continue; + + var offs = ((j << bplres) >> sprite_buffer_res) - ddf_left; + sprpix = sprite_ab_merge[sprpix & 255] | (sprite_ab_merge[sprpix >> 8] << 2); + sprpix <<= 1; + + var ldata = line_data[next_lineno]; + + /* Loop over number of playfields. */ + for (var k = 1; k >= 0; k--) { + //#ifdef AGA + var planes = (SAEV_config.chipset.mask & SAEC_Config_Chipset_Mask_AGA) ? 8 : 6; + /*#else + var planes = 6; + #endif*/ + if (bplcon0 & 0x400) + match = true; + for (var l = k; match && l < planes; l += 2) { + var t = 0; + if (l < thisline_decision.nr_planes) { + //uae_u32 *ldata = (uae_u32 *)(line_data[next_lineno] + 2 * l * MAX_WORDS_PER_LINE); + //uae_u32 word = ldata[offs >> 5]; + var word = ldata[MAX_WORDS_PER_LINE_FULL * l + (offs >> 5)]; + + t = (word >>> (31 - (offs & 31))) & 1; + /*#if 0 //debug: draw collision mask + if (1) { + for (var m = 0; m < 5; m++) { + ldata = (uae_u32 *)(line_data[next_lineno] + 2 * m * MAX_WORDS_PER_LINE); + ldata[(offs >> 5) + 1] |= 15 << (31 - (offs & 31)); + } + } + #endif*/ + } + if (clxcon_bpl_enable & (1 << l)) { + if (t != ((clxcon_bpl_match >> l) & 1)) + match = false; + } + } + if (match) { + /*#if 0 // debug: mark lines where collisions are detected + if (0) { + for (var l = 0; l < 5; l++) { + uae_u32 *ldata = (uae_u32 *)(line_data[next_lineno] + 2 * l * MAX_WORDS_PER_LINE); + ldata[(offs >> 5) + 1] |= 15 << (31 - (offs & 31)); + } + } + #endif*/ + clxdat |= sprpix << (k * 4); + } + } + } + } + } + + //static void record_sprite_1 (int sprxp, uae_u16 *buf, uae_u32 datab, int num, int dbl,unsigned int mask, int do_collisions, uae_u32 collision_mask) + function record_sprite_1(sprxp, buf, datab, num, dbl, mask, do_collisions, collision_mask) { + var j = 0; + while (datab) { + var col = 0; + var coltmp = 0; + + if ((sprxp >= sprite_minx && sprxp < sprite_maxx) || (bplcon3 & 2)) + col = (datab & 3) << (2 * num); + /*#if 0 + if (sprxp == sprite_minx || sprxp == sprite_maxx - 1) col ^= (. () << 16) | . (); + #endif*/ + + if ((j & mask) == 0) { + //var tmp = (*buf) | col; *buf++ = tmp; + var tmp = spixels[buf] | col; spixels[buf++] = tmp; + if (do_collisions) coltmp |= tmp; + sprxp++; + } + if (dbl > 0) { + //var tmp = (*buf) | col; *buf++ = tmp; + var tmp = spixels[buf] | col; spixels[buf++] = tmp; + if (do_collisions) coltmp |= tmp; + sprxp++; + } + if (dbl > 1) { + var tmp; + //tmp = (*buf) | col; *buf++ = tmp; + tmp = spixels[buf] | col; spixels[buf++] = tmp; + if (do_collisions) coltmp |= tmp; + //tmp = (*buf) | col; *buf++ = tmp; + tmp = spixels[buf] | col; spixels[buf++] = tmp; + if (do_collisions) coltmp |= tmp; + sprxp++; + sprxp++; + } + j++; + datab >>>= 2; + if (do_collisions) { + coltmp &= collision_mask; + if (coltmp) { + var shrunk_tmp = sprite_ab_merge[coltmp & 255] | (sprite_ab_merge[coltmp >> 8] << 2); + clxdat |= sprclx[shrunk_tmp]; + } + } + } + } + + /* DATAB contains the sprite data; 16 pixels in two-bit packets. Bits 0/1 + determine the color of the leftmost pixel, bits 2/3 the color of the next + etc. + This function assumes that for all sprites in a given line, SPRXP either + stays equal or increases between successive calls. + + The data is recorded either in lores pixels (if OCS/ECS), or in hires or + superhires pixels (if AGA). */ + + //static void record_sprite (int line, int num, int sprxp, uae_u16 *data, uae_u16 *datb, unsigned int ctl) + function record_sprite(line, num, sprxp, data, datb, ctl) { + //struct sprite_entry *e = curr_sprite_entries + next_sprite_entry; + var e = curr_sprite_entries[next_sprite_entry]; + var this_sprite_entry = next_sprite_entry; //OWN + var i; + var word_offs; + var collision_mask; //u32 + var width, dbl, half; + var mask = 0; //uint + var attachment; + var nr2 = 0; //OWN + + half = 0; + dbl = sprite_buffer_res - sprres; + if (dbl < 0) { + half = -dbl; + dbl = 0; + mask = 1 << half; + } + width = (sprite_width << sprite_buffer_res) >> sprres; + attachment = sprctl[num | 1] & 0x80; + + /* Try to coalesce entries if they aren"t too far apart */ + //if (!next_sprite_forced && e[-1].max + sprite_width >= sprxp) { + if (!next_sprite_forced && curr_sprite_entries[this_sprite_entry - 1].max + sprite_width >= sprxp) { + //e--; + e = curr_sprite_entries[--this_sprite_entry]; + } else { + next_sprite_entry++; + e.pos = sprxp; + e.has_attached = 0; + } + + if (sprxp < e.pos) SAEF_error("record_sprite() sprxp < e.pos (%d < %d)", sprxp, e.pos); + + e.max = sprxp + width; + //e[1].first_pixel = e->first_pixel + ((e->max - e->pos + 3) & ~3); + curr_sprite_entries[this_sprite_entry + 1].first_pixel = e.first_pixel + ((e.max - e.pos + 3) & ~3); + next_sprite_forced = 0; + + collision_mask = clxmask[clxcon >> 12]; + word_offs = e.first_pixel + sprxp - e.pos; + + for (i = 0; i < sprite_width; i += 16) { + //unsigned int da = *data; + //unsigned int db = *datb; + var da = data[nr2]; + var db = datb[nr2]; + var datab = ((sprtaba[da & 0xFF] << 16) | sprtaba[da >> 8] | (sprtabb[db & 0xFF] << 16) | sprtabb[db >> 8]) >>> 0; //u32 + var off = (i << dbl) >> half; + //uae_u16 *buf = spixels + word_offs + off; + + if (SAEV_config.chipset.colLevel > SAEC_Config_Chipset_ColLevel_None && collision_mask) + record_sprite_1(sprxp + off, word_offs + off, datab, num, dbl, mask, 1, collision_mask); + else + record_sprite_1(sprxp + off, word_offs + off, datab, num, dbl, mask, 0, collision_mask); + + //data++; datb++; + nr2++; + } + + /* We have 8 bits per pixel in spixstate, two for every sprite pair. The + low order bit records whether the attach bit was set for this pair. */ + if (attachment && !isecsshres()) { + //uae_u32 state = 0x01010101 << (num & ~1); + var state = ((0x01010101 << (num & 0xfe)) >>> 0) & 0xff; //ATT + //uae_u8 *stb1 = spixstate.bytes + word_offs; + var stb1 = word_offs; + for (i = 0; i < width; i += 8) { + /*stb1[0] |= state; + stb1[1] |= state; + stb1[2] |= state; + stb1[3] |= state; + stb1[4] |= state; + stb1[5] |= state; + stb1[6] |= state; + stb1[7] |= state;*/ + spixstate.bytes[stb1 + 0] |= state; + spixstate.bytes[stb1 + 1] |= state; + spixstate.bytes[stb1 + 2] |= state; + spixstate.bytes[stb1 + 3] |= state; + spixstate.bytes[stb1 + 4] |= state; + spixstate.bytes[stb1 + 5] |= state; + spixstate.bytes[stb1 + 6] |= state; + spixstate.bytes[stb1 + 7] |= state; + stb1 += 8; + } + e.has_attached = 1; + } + } + + function add_sprite(count, num, sprxp, posns, nrs) { + var j, bestp; + + /* Sort the sprites in order of ascending X position before recording them. */ + for (bestp = 0; bestp < count; bestp++) { + if (posns[bestp] > sprxp) + break; + if (posns[bestp] == sprxp && nrs[bestp] < num) + break; + } + for (j = count; j > bestp; j--) { + posns[j] = posns[j - 1]; + nrs[j] = nrs[j - 1]; + } + posns[j] = sprxp; + nrs[j] = num; + } + + function tospritexdiw(diw) { + return coord_window_to_hw_x(diw - (DIW_DDF_OFFSET << lores_shift)) << sprite_buffer_res; + } + function tospritexddf(ddf) { + return (ddf * 2 - DIW_DDF_OFFSET) << sprite_buffer_res; + } + function fromspritexdiw(ddf) { + return coord_hw_to_window_x(ddf >> sprite_buffer_res) + (DIW_DDF_OFFSET << lores_shift); + } + + function calcsprite() { + sprite_maxx = 0x7fff; + sprite_minx = 0; + if (thisline_decision.diwlastword >= 0) + sprite_maxx = tospritexdiw(thisline_decision.diwlastword); + if (thisline_decision.diwfirstword >= 0) + sprite_minx = tospritexdiw(thisline_decision.diwfirstword); + if (thisline_decision.plfleft >= 0) { + var min = tospritexddf(thisline_decision.plfleft); + var max = tospritexddf(thisline_decision.plfright); + if (min > sprite_minx && min < max) { /* min < max = full line ddf */ + if (SAEV_config.chipset.mask & SAEC_Config_Chipset_Mask_ECS_DENISE) { + sprite_minx = min; + } else { + if (thisline_decision.plfleft >= 0x28 || bpldmawasactive) + sprite_minx = min; + } + } + /* sprites are visible from first BPL1DAT write to end of line + * ECS Denise/AGA: no limits + * OCS Denise: BPL1DAT write only enables sprite if hpos >= 0x28 or so. + * (undocumented feature) */ + } + } + + function decide_sprites(hpos, usepointx) { + if (typeof usepointx == "undefined") var usepointx = false; + var nrs = new Int32Array(MAX_SPRITES * 2); + var posns = new Int32Array(MAX_SPRITES * 2); + var width = sprite_width; + var sscanmask = 0x100 << sprite_buffer_res; + var gotdata = false; + + if (thisline_decision.plfleft < 0 && !(bplcon3 & 2)) + return; + + // let sprite shift register empty completely if sprite is at the very edge of right border + var point = hpos * 2; + if (hpos >= maxhpos) + point += ((9 - 2) * 2) * sprite_buffer_res; + + if (nodraw() || hpos < 0x14 || nr_armed == 0 || point == last_sprite_point) + return; + + decide_diw(hpos); + SAER.playfield.decide_line(hpos); + calcsprite(); + + var i, count = 0; + for (i = 0; i < MAX_SPRITES; i++) { + var xpos = spr[i].xpos; + var sprxp = (fmode & 0x8000) ? (xpos & ~sscanmask) : xpos; + var hw_xp = sprxp >> sprite_buffer_res; + var pointx = usepointx && (sprctl[i] & sprite_sprctlmask) ? 0 : 1; + + if (xpos < 0) + continue; + if (!spr[i].armed) + continue; + + if (hw_xp > last_sprite_point && hw_xp <= point + pointx) + add_sprite(count++, i, sprxp, posns, nrs); + + /* SSCAN2-bit is fun.. */ + if ((fmode & 0x8000) && !(sprxp & sscanmask)) { + sprxp |= sscanmask; + hw_xp = sprxp >> sprite_buffer_res; + if (hw_xp > last_sprite_point && hw_xp <= point + pointx) + add_sprite(count++, MAX_SPRITES + i, sprxp, posns, nrs); + } else if (!(fmode & 0x80) && xpos >= (2 << sprite_buffer_res) && xpos <= (9 << sprite_buffer_res)) { + // right border wrap around. SPRxCTL horizontal bits do not matter. + sprxp += (maxhpos * 2) << sprite_buffer_res; + hw_xp = sprxp >> sprite_buffer_res; + if (hw_xp > last_sprite_point && hw_xp <= point + pointx) + add_sprite(count++, MAX_SPRITES + i, sprxp, posns, nrs); + + // (not really mutually exclusive of SSCAN2-bit but not worth the trouble) + } + } + + for (i = 0; i < count; i++) { + var nr = nrs[i] & (MAX_SPRITES - 1); + record_sprite(next_lineno, nr, posns[i], sprdata[nr], sprdatb[nr], sprctl[nr]); + + if (AUTOSCALE_SPRITES) { + /* get left and right sprite edge if brdsprt enabled */ + if (SAEF_Custom_dmaen(SAEC_Custom_DMAF_SPREN) && (bplcon0 & 1) && (bplcon3 & 0x02) && !(bplcon3 & 0x20) && nr > 0) { + for (var j = 0, jj = 0; j < sprite_width; j += 16, jj++) { + var nx = fromspritexdiw(posns[i] + j); + if (sprdata[nr][jj] || sprdatb[nr][jj]) { + if (diwfirstword_total > nx && nx >= (48 << SAEV_config.video.hresolution)) + diwfirstword_total = nx; + if (diwlastword_total < nx + 16 && nx <= (448 << SAEV_config.video.hresolution)) + diwlastword_total = nx + 16; + } + } + gotdata = true; + } + } + } + last_sprite_point = point; + + if (AUTOSCALE_SPRITES) { + /* get upper and lower sprite position if brdsprt enabled */ + if (gotdata) { + if (vpos < first_planes_vpos) first_planes_vpos = vpos; + if (vpos < plffirstline_total) plffirstline_total = vpos; + if (vpos > last_planes_vpos) last_planes_vpos = vpos; + if (vpos > plflastline_total) plflastline_total = vpos; + } + } + } + /*function decide_sprites(hpos) { //OWN + decide_sprites(hpos, false); + }*/ + + /*-----------------------------------------------------------------------*/ + /* SECT decisions */ + + function sprites_differ(dip, dip_old) { + var this_first = curr_sprite_entries[dip.first_sprite_entry]; + var this_last = curr_sprite_entries[dip.last_sprite_entry]; + var prev_first = prev_sprite_entries[dip_old.first_sprite_entry]; + var i; + + if (dip.nr_sprites != dip_old.nr_sprites) + return 1; + if (dip.nr_sprites == 0) + return 0; + + for (i = 0; i < dip.nr_sprites; i++) { + var this_first_i = curr_sprite_entries[dip.first_sprite_entry + i]; //OWN + var prev_first_i = prev_sprite_entries[dip_old.first_sprite_entry + i]; //OWN + if ( + this_first_i.pos != prev_first_i.pos || + this_first_i.max != prev_first_i.max || + this_first_i.has_attached != prev_first_i.has_attached + ) return 1; + } + + var npixels = this_last.first_pixel + (this_last.max - this_last.pos) - this_first.first_pixel; + for (i = 0; i < npixels; i++) { + if (spixels[this_first.first_pixel + i] != spixels[prev_first.first_pixel + i]) return 1; + if (spixstate.bytes[this_first.first_pixel + i] != spixstate.bytes[prev_first.first_pixel + i]) return 1; + } + return 0; + } + + function color_changes_differ(dip, dip_old) { + if (dip.nr_color_changes != dip_old.nr_color_changes) + return 1; + if (dip.nr_color_changes == 0) + return 0; + //if (memcmp(curr_color_changes + dip->first_color_change, prev_color_changes + dip_old->first_color_change, dip->nr_color_changes * sizeof *curr_color_changes) != 0) return 1; + for (var i = 0; i < dip.nr_color_changes; i++) { + if (cmp_color_change(curr_color_changes[dip.first_color_change], prev_color_changes[dip_old.first_color_change]) != 0) return 1; + } + return 0; + } + + /* End of a horizontal scan line. Finish off all decisions that were not made yet. */ + function finish_decisions() { + var dip; + var dip_old; + var dp; + var changed; + var hpos = maxhpos; + + if (nodraw()) + return; + + decide_diw(hpos); + SAER.playfield.decide_line(hpos); + SAER.playfield.decide_fetch_safe(hpos); + finish_final_fetch(); + + record_color_change2(hsyncstartpos, 0xffff, 0); + if (thisline_decision.plfleft >= 0 && thisline_decision.plflinelen < 0) { + if (fetch_state != fetch_not_started) + SAEF_warn("playfield.finish_decisions() fetch_state != fetch_not_started"); + + thisline_decision.plfright = thisline_decision.plfleft; + thisline_decision.plflinelen = 0; + thisline_decision.bplres = SAEC_Config_Video_HResolution_LoRes; + } + + /* Large DIWSTOP values can cause the stop position never to be + * reached, so the state machine always stays in the same state and + * there"s a more-or-less full-screen DIW. */ + if (hdiwstate == DIW_WAITING_STOP) { + thisline_decision.diwlastword = max_diwlastword(); + if (thisline_decision.diwfirstword < 0) + thisline_decision.diwfirstword = min_diwlastword; + } + + if (thisline_decision.diwfirstword != line_decisions[next_lineno].diwfirstword) { + //MARK_LINE_CHANGED; //ORG + if (SMART_UPDATE) thisline_changed = 1; //OWN opt inline + } + if (thisline_decision.diwlastword != line_decisions[next_lineno].diwlastword) { + //MARK_LINE_CHANGED; //ORG + if (SMART_UPDATE) thisline_changed = 1; //OWN opt inline + } + + dip = curr_drawinfo[next_lineno]; + dip_old = prev_drawinfo[next_lineno]; + dp = line_decisions[next_lineno]; + changed = thisline_changed | custom_frame_redraw_necessary; + if (thisline_decision.plfleft >= 0 && thisline_decision.nr_planes > 0) + record_diw_line(thisline_decision.plfleft, diwfirstword, diwlastword); + + decide_sprites(hpos + 1); + + dip.last_sprite_entry = next_sprite_entry; + dip.last_color_change = next_color_change; + + if (thisline_decision.ctable < 0) { + if (thisline_decision.plfleft < 0) + remember_ctable_for_border(); + else + remember_ctable(); + } + + dip.nr_color_changes = next_color_change - dip.first_color_change; + dip.nr_sprites = next_sprite_entry - dip.first_sprite_entry; + + if (thisline_decision.plfleft != line_decisions[next_lineno].plfleft) + changed = 1; + if (!changed && color_changes_differ(dip, dip_old)) + changed = 1; + if (!changed && /* bitplane visible in this line OR border sprites enabled */ + (thisline_decision.plfleft >= 0 || ((thisline_decision.bplcon0 & 1) && (thisline_decision.bplcon3 & 0x02) && !(thisline_decision.bplcon3 & 0x20))) && + sprites_differ(dip, dip_old)) + { + changed = 1; + } + + if (changed) { + thisline_changed = 1; + // *dp = thisline_decision; //ORG + cpy_decision(dp, thisline_decision); + } else { + /* The only one that may differ: */ + dp.ctable = thisline_decision.ctable; + } + + /* leave free space for possible extra color changes at the end of line */ + next_color_change += (HBLANK_OFFSET + 1) / 2; //ATT ok, (9+1)/2 + + diw_hcounter += maxhpos * 2; + if (!(SAEV_config.chipset.mask & SAEC_Config_Chipset_Mask_ECS_DENISE) && vpos == get_equ_vblank_endline() - 1) + diw_hcounter++; + if ((SAEV_config.chipset.mask & SAEC_Config_Chipset_Mask_ECS_DENISE) || vpos > get_equ_vblank_endline() || (SAEV_config.chipset.agnusDIP && vpos == 0)) { + diw_hcounter = maxhpos * 2; + last_hdiw = 2 - 1; + } + + if (next_color_change >= MAX_REG_CHANGE - 30) { + SAEF_warn("playfield.finish_decisions() color_change buffer overflow!"); + next_color_change = 0; + dip.nr_color_changes = 0; + dip.first_color_change = 0; + dip.last_color_change = 0; + } + } + + /* Set the state of all decisions to "undecided" for a new scanline. */ + function reset_decisions() { + if (nodraw()) + return; + + toscr_nr_planes = toscr_nr_planes2 = 0; + thisline_decision.bplres = bplcon0_res; + thisline_decision.nr_planes = 0; + bpl1dat_written = false; + bpl1dat_written_at_least_once = false; + + thisline_decision.plfleft = -1; + thisline_decision.plflinelen = -1; + thisline_decision.ham_seen = !!(bplcon0 & 0x800); + thisline_decision.ehb_seen = !!isehb(bplcon0, bplcon2); + thisline_decision.ham_at_start = !!(bplcon0 & 0x800); + thisline_decision.bordersprite_seen = issprbrd(-1, bplcon0, bplcon3); + + /* decided_res shouldn"t be touched before it"s initialized by decide_line(). */ + thisline_decision.diwfirstword = -1; + thisline_decision.diwlastword = -1; + if (hdiwstate == DIW_WAITING_STOP) { + thisline_decision.diwfirstword = min_diwlastword; + if (thisline_decision.diwfirstword != line_decisions[next_lineno].diwfirstword) { + //MARK_LINE_CHANGED; //ORG + if (SMART_UPDATE) thisline_changed = 1; //OWN opt inline + } + } + thisline_decision.ctable = -1; + + thisline_changed = 0; + curr_drawinfo[next_lineno].first_color_change = next_color_change; + curr_drawinfo[next_lineno].first_sprite_entry = next_sprite_entry; + next_sprite_forced = 1; + + last_sprite_point = 0; + fetch_state = fetch_not_started; + if (bpldmasetuphpos >= 0) { + // this can happen in "too fast" modes + BPLCON0_Denise(0, bplcon0, true); + setup_fmodes(0); + } + bpldmasetuphpos = -1; + bpldmasetupphase = 0; + bpldmawasactive = false; + reset_moddelays(); + /*#if 0 + reset_dbpll_all(256); + reset_dbplh_all(256); + #endif*/ + delay_cycles = 0; + compute_toscr_delay(bplcon1); + + if (plf_state >= plf_passed_stop2 || plf_state == plf_wait) + plf_state = plf_idle; + + // Only ECS Agnus can keep DDF open between lines + if ((SAEV_config.chipset.mask & SAEC_Config_Chipset_Mask_ECS_AGNUS)) { + if (!ddfstop_matched) + plf_state = plf_active; + } + + bpl_hstart = 256; + plfr_state = plfr_idle; + plf_start_hpos = 256 + DDF_OFFSET; + plf_end_hpos = 256 + DDF_OFFSET; + ddfstop_written_hpos = -1; + bitplane_maybe_start_hpos = -1; + bitplane_off_delay = -1; + + if (line_cyclebased) { + line_cyclebased--; + if (!line_cyclebased) + bpl_dma_off_when_active = 0; + } + + //fetched[] must not be cleared (Sony VX-90 / Royal Amiga Force) + todisplay_fetched[0] = todisplay_fetched[1] = false; + for (var i = 0; i < MAX_PLANES; i++) { + outword[i] = 0; + todisplay[i] = 0; + todisplay2[i] = 0; + } + //#ifdef AGA + if (SAEV_config.chipset.mask & SAEC_Config_Chipset_Mask_AGA) { + for (var i = 0; i < MAX_PLANES; i++) { + //todisplay_aga[i] = 0; + todisplay_aga_hi[i] = todisplay_aga_lo[i] = 0; + //todisplay2_aga[i] = 0; + todisplay2_aga_hi[i] = todisplay2_aga_lo[i] = 0; + } + } + aga_plf_passed_stop2 = false; + //#endif + + if (bitplane_line_crossing) { + // BPL1DAT would have been written after end of last scanline. + // Set BPL1DAT "written at least once" state for new scanline. + bitplane_line_crossing -= maxhpos - HPOS_SHIFT; + if (bitplane_line_crossing > 0) { + bpl1dat_written = true; + bpl1dat_written_at_least_once = true; + reset_bpl_vars(); + beginning_of_plane_block(bitplane_line_crossing, fetchmode); + } + bitplane_line_crossing = 0; + } else + reset_bpl_vars(); + + last_decide_line_hpos = -(DDF_OFFSET + 1); + last_ddf_pix_hpos = -1; + last_sprite_hpos = -1; + last_fetch_hpos = -1; + + if (sprite_ignoreverticaluntilnextline) { + sprite_ignoreverticaluntilnextline = false; + for (var i = 0; i < MAX_SPRITES; i++) + spr[i].ignoreverticaluntilnextline = false; + } + + /* These are for comparison. */ + thisline_decision.bplcon0 = bplcon0; + thisline_decision.bplcon2 = bplcon2; + //#ifdef ECS_DENISE + thisline_decision.bplcon3 = bplcon3; + //#endif + //#ifdef AGA + thisline_decision.bplcon4 = bplcon4; + //#endif + scanlinecount++; + } + + /*-----------------------------------------------------------------------*/ + /* SECT vsync */ + + function compute_vsynctime() { //global + var svpos = maxvpos_nom; //double + var shpos = maxhpos_short; //double + var syncadjust = 1.0; //double + + SAEV_Playfield_fake_vblank_hz = 0.0; + vblank_hz_mult = 0; + vblank_hz_state = 1; + if (Math.abs(SAEV_config.chipset.refreshRate) > 0.1) { + syncadjust = SAEV_config.chipset.refreshRate / vblank_hz_nom; + vblank_hz = SAEV_config.chipset.refreshRate; + if (isvsync_chipset()) { + var result = {}; + SAEF_Playfield_getvsyncrate(vblank_hz, result); + if (result.hz != vblank_hz) { + SAEF_Playfield_getvsyncrate(vblank_hz, result); + vblank_hz = result.hz; + vblank_hz_mult = result.mult; + if (vblank_hz_mult > 0) + vblank_hz_state = 0; + } + } + } + if (!SAEV_Playfield_fake_vblank_hz) + SAEV_Playfield_fake_vblank_hz = vblank_hz; + + /*if (currprefs.turbo_emulation) { + if (currprefs.turbo_emulation_limit > 0) { + SAEV_Audio_vsynctimebase_orig = SAER.events.calc_vsynctimebase(currprefs.turbo_emulation_limit); + } else { + SAEV_Audio_vsynctimebase_orig = SAER.events.calc_vsynctimebase(SAEC_Events_syncbase / 1000); + } + } else*/ + SAEV_Audio_vsynctimebase_orig = SAER.events.calc_vsynctimebase(SAEV_Playfield_fake_vblank_hz); + + /*#if 0 + if (!SAEV_Playfield_picasso_on) updatedisplayarea(); + #endif*/ + + if (islinetoggle()) + shpos += 0.5; + if (interlace_seen) + svpos += 0.5; + else if (lof_current) + svpos += 1.0; + + if (SAEV_config.audio.mode != SAEC_Config_Audio_Mode_Off) { + var clk = svpos * shpos * SAEV_Playfield_fake_vblank_hz; //double + SAEF_log("playfield.compute_vsynctime() %.1f*%.1f*%.6f=%.6f, syncadjust %f", svpos, shpos, SAEV_Playfield_fake_vblank_hz, clk, syncadjust); + SAER.devices.update_sound(clk, syncadjust); + } + //SAER.devices.update_sync(svpos, syncadjust); //OWN cd32 + } + this.compute_vsynctime_ext = function() { + compute_vsynctime(); + } + + /*void getsyncregisters(uae_u16 *phsstrt, uae_u16 *phsstop, uae_u16 *pvsstrt, uae_u16 *pvsstop) { + *phsstrt = hsstrt; + *phsstop = hsstop; + *pvsstrt = vsstrt; + *pvsstop = vsstop; + }*/ + + function dumpsync() { + //static int cnt = 100; if (cnt < 0) return; cnt--; + SAEF_log("BEAMCON0=%04X VTOTAL=%04X HTOTAL=%04X", new_beamcon0, vtotal, htotal); + SAEF_log(" HSSTOP=%04X HBSTRT=%04X HBSTOP=%04X", hsstop, hbstrt, hbstop); + SAEF_log(" VSSTOP=%04X VBSTRT=%04X VBSTOP=%04X", vsstop, vbstrt, vbstop); + SAEF_log(" HSSTRT=%04X VSSTRT=%04X HCENTER=%04X", hsstrt, vsstrt, hcenter); + SAEF_log(" HSYNCSTART=%04X HSYNCEND=%04X", hsyncstartpos, hsyncendpos); + } + + function current_maxvpos() { //global + return maxvpos + (lof_store ? 1 : 0); + } + + /*#if 0 + function checklacecount(lace) { if (!interlace_changed) { if (nlace_cnt >= NLACE_CNT_NEEDED && lace) { lof_togglecnt_lace = LOF_TOGGLES_NEEDED; lof_togglecnt_nlace = 0; - //BUG.info('immediate lace'); nlace_cnt = 0; } else if (nlace_cnt <= -NLACE_CNT_NEEDED && !lace) { lof_togglecnt_nlace = LOF_TOGGLES_NEEDED; lof_togglecnt_lace = 0; - //BUG.info('immediate nlace'); nlace_cnt = 0; } } @@ -4869,1165 +8806,452 @@ function Playfield() { if (nlace_cnt > NLACE_CNT_NEEDED * 2) nlace_cnt = NLACE_CNT_NEEDED * 2; } - }; - - var dumpcnt = 100; - this.dumpsync = function () { - if (dumpcnt < 0) - return; - dumpcnt--; - BUG.info('BEAMCON0=%04X VTOTAL=%04X HTOTAL=%04X', new_beamcon0, this.vtotal, this.htotal); - BUG.info(' HSSTOP=%04X HBSTRT=%04X HBSTOP=%04X', this.hsstop, this.hbstrt, this.hbstop); - BUG.info(' VSSTOP=%04X VBSTRT=%04X VBSTOP=%04X', this.vsstop, this.vbstrt, this.vbstop); - BUG.info(' HSSTRT=%04X VSSTRT=%04X HCENTER=%04X', this.hsstrt, this.vsstrt, this.hcenter); - }; - - this.varsync = function () { - //console.log('varsync()'); - if (!CUSTOM_SIMPLE) { - if (!(AMIGA.config.chipset.mask & CSMASK_ECS_AGNUS)) - return; - if (!(beamcon0 & 0x80)) - return; - this.vpos_count = 0; - //this.dumpsync(); + } + #endif*/ + + function get_chipset_refresh() { //global + var islace = interlace_seen ? 1 : 0; + var isntsc = (beamcon0 & 0x20) ? 0 : 1; + + if (!(SAEV_config.chipset.mask & SAEC_Config_Chipset_Mask_ECS_AGNUS)) + isntsc = SAEV_config.chipset.ntsc ? 1 : 0; + + for (var i = 0; i < SAEV_config.chipset.refresh.length; i++) { + var cr = SAEV_config.chipset.refresh[i]; + if ((cr.horiz < 0 || cr.horiz == maxhpos) && + (cr.vert < 0 || cr.vert == maxvpos_display) && + (cr.ntsc < 0 || (cr.ntsc > 0 && isntsc) || (cr.ntsc == 0 && !isntsc)) && + (cr.lace < 0 || (cr.lace > 0 && islace) || (cr.lace == 0 && !islace)) && + (cr.framelength < 0 || (cr.framelength > 0 && lof_store) || (cr.framelength == 0 && !lof_store) || (cr.framelength >= 0 && islace)) && + ((cr.rtg && SAEV_Playfield_picasso_on) || (!cr.rtg && !SAEV_Playfield_picasso_on)) && + (cr.vsync < 0 || (cr.vsync > 0 && isvsync_chipset()) || (cr.vsync == 0 && !isvsync_chipset()))) + return cr; } - }; - - this.count_frame = function () { - if (++framecnt >= AMIGA.config.video.framerate) - framecnt = 0; - }; - - this.vsync_handle_redraw = function () { //(long_frame, lof_changed, bplcon0p, bplcon3p) - last_redraw_point++; - if (this.lof_changed || this.lof_store || interlace_seen <= 0 || doublescan < 0 || last_redraw_point >= 2) { - last_redraw_point = 0; + return null; + } - if (framecnt == 0) - this.finish_drawing_frame(); - /*#if 0 - if (interlace_seen > 0) - interlace_seen = -1; - else if (interlace_seen == -1) { - interlace_seen = 0; - if (currprefs.scandoubler && currprefs.vresolution) - notice_screen_contents_lost (); - } - #endif*/ - this.count_frame(); + function changed_chipset_refresh() { + return stored_chipset_refresh != get_chipset_refresh(); + } - if (framecnt == 0) - this.init_drawing_frame(); - } - }; - - this.init_hardware_frame = function () { - first_bpl_vpos = -1; - next_lineno = 0; - prev_lineno = -1; - nextline_how = NLN_NORMAL; - diwstate = DIW_WAITING_START; - ddfstate = DIW_WAITING_START; - first_planes_vpos = 0; - last_planes_vpos = 0; - diwfirstword_total = max_diwlastword(); - diwlastword_total = 0; - ddffirstword_total = max_diwlastword(); - ddflastword_total = 0; - plflastline_total = 0; - plffirstline_total = this.current_maxvpos(); - autoscale_bordercolors = 0; - for (var i = 0; i < MAX_SPRITES; i++) - spr[i].ptxhpos = MAXHPOS; - }; - - this.init_hardware_for_drawing_frame = function () { - if (prev_sprite_entries) { - var first_pixel = prev_sprite_entries[0].first_pixel; - var npixels = prev_sprite_entries[prev_next_sprite_entry].first_pixel - first_pixel; - for (var i = 0; i < npixels; i++) spixels[first_pixel + i] = 0; //memset (spixels + first_pixel, 0, npixels * sizeof *spixels); - for (var i = 0; i < npixels; i++) spixstate[first_pixel + i] = 0; //memset (spixstate.bytes + first_pixel, 0, npixels * sizeof *spixstate.bytes); - } - prev_next_sprite_entry = next_sprite_entry; - - next_color_change = 0; - next_sprite_entry = 0; - next_color_entry = 0; - remembered_color_entry = -1; - - prev_sprite_entries = sprite_entries[current_change_set]; - curr_sprite_entries = sprite_entries[current_change_set ^ 1]; - prev_color_changes = color_changes[current_change_set]; - curr_color_changes = color_changes[current_change_set ^ 1]; - prev_color_tables = color_tables[current_change_set]; - curr_color_tables = color_tables[current_change_set ^ 1]; - - prev_drawinfo = line_drawinfo[current_change_set]; - curr_drawinfo = line_drawinfo[current_change_set ^ 1]; - current_change_set ^= 1; - - color_src_match = color_dest_match = -1; - - curr_sprite_entries[0].first_pixel = current_change_set * MAX_SPR_PIXELS; - next_sprite_forced = 1; - }; - - this.reset_decisions = function () { - if (this.nodraw()) - return; - - plfleft_real = -1; - toscr_nr_planes = toscr_nr_planes2 = 0; - - bpl1dat_written = false; - bpl1dat_written_at_least_once = false; - bpl1dat_early = false; - - thisline_decision.bplres = bplcon0_res; - thisline_decision.nr_planes = 0; - thisline_decision.plfleft = -1; - thisline_decision.plflinelen = -1; - thisline_decision.ham_seen = !!(bplcon0 & 0x800); - thisline_decision.ehb_seen = !!is_ehb(bplcon0, bplcon2); - thisline_decision.ham_at_start = !!(bplcon0 & 0x800); - - thisline_changed = 0; - thisline_decision.diwfirstword = -1; - thisline_decision.diwlastword = -1; - if (hdiwstate == DIW_WAITING_STOP) { - thisline_decision.diwfirstword = 0; - if (SMART_UPDATE) { - if (thisline_decision.diwfirstword != line_decisions[next_lineno].diwfirstword) - thisline_changed = 1; //MARK_LINE_CHANGED; - } - } - thisline_decision.ctable = -1; - - curr_drawinfo[next_lineno].first_color_change = next_color_change; - curr_drawinfo[next_lineno].first_sprite_entry = next_sprite_entry; - - next_sprite_forced = 1; - last_sprite_point = 0; - fetch_state = FETCH_NOT_STARTED; - bplcon1_hpos = -1; - if (bpldmasetuphpos >= 0) { - this.BPLCON0_Denise(0, bplcon0, true); - this.setup_fmodes(0); - } - bpldmasetuphpos = -1; - bpldmasetupphase = 0; - ddfstrt_old_hpos = -1; - - if (plf_state > PLF_ACTIVE || (plf_state == PLF_ACTIVE && !(AMIGA.config.chipset.mask & CSMASK_ECS_AGNUS))) - plf_state = PLF_IDLE; - - /*memset (todisplay, 0, sizeof todisplay); - memset (fetched, 0, sizeof fetched); - memset (fetched_aga0, 0, sizeof fetched_aga0); - memset (fetched_aga1, 0, sizeof fetched_aga1); - memset (outword, 0, sizeof outword);*/ - for (var i = 0; i < MAX_PLANES; i++) { - for (var j = 0; j < 4; j++) - todisplay[i][j] = 0; - - fetched[i] = 0; - /*#ifdef AGA - if (AMIGA.config.chipset.mask & CSMASK_AGA) { - fetched_aga0[i] = 0; - fetched_aga1[i] = 0; - } - #endif*/ - outword[i] = 0; - } - - last_decide_line_hpos = -1; - last_ddf_pix_hpos = -1; - last_sprite_hpos = -1; - last_fetch_hpos = -1; - - thisline_decision.bplcon0 = bplcon0; - thisline_decision.bplcon2 = bplcon2; - thisline_decision.bplcon3 = bplcon3; - /*#ifdef AGA - thisline_decision.bplcon4 = bplcon4; - #endif*/ - }; - - this.record_diw_line = function (plfstrt, first, last) { - if (last > max_diwstop) - max_diwstop = last; - if (first < min_diwstart) { - min_diwstart = first; - /* - if (plfstrt * 2 > min_diwstart) - min_diwstart = plfstrt * 2; - */ - } - }; - - this.sprites_differ = function (dip, dip_old) { - var this_first = curr_sprite_entries[dip.first_sprite_entry]; - var this_last = curr_sprite_entries[dip.last_sprite_entry]; - var prev_first = prev_sprite_entries[dip_old.first_sprite_entry]; - - if (dip.nr_sprites != dip_old.nr_sprites) - return 1; - - if (dip.nr_sprites == 0) - return 0; - - /*for (var i = 0; i < dip.nr_sprites; i++) { //FIXME - if (this_first[i].pos != prev_first[i].pos - || this_first[i].max != prev_first[i].max - || this_first[i].has_attached != prev_first[i].has_attached) - return 1; - }*/ - if (this_first.pos != prev_first.pos || this_first.max != prev_first.max || this_first.has_attached != prev_first.has_attached) //FIX - return 1; - - var npixels = this_last.first_pixel + (this_last.max - this_last.pos) - this_first.first_pixel; - - //if (memcmp (spixels + this_first.first_pixel, spixels + prev_first.first_pixel, npixels * sizeof (uae_u16)) != 0) return 1; - for (i = 0; i < npixels; i++) { - if (spixels[this_first.first_pixel + i] != spixels[prev_first.first_pixel + i]) - return 1; - } - //if (memcmp (spixstate.bytes + this_first.first_pixel, spixstate.bytes + prev_first.first_pixel, npixels) != 0) return 1; - for (i = 0; i < npixels; i++) { - if (spixstate[this_first.first_pixel + i] != spixstate[prev_first.first_pixel + i]) - return 1; - } - return 0; - }; - - this.color_changes_differ = function (dip, dip_old) { - if (dip.nr_color_changes != dip_old.nr_color_changes) - return 1; - if (dip.nr_color_changes == 0) - return 0; - //if (memcmp(curr_color_changes + dip.first_color_change, prev_color_changes + dip_old.first_color_change, dip.nr_color_changes * sizeof *curr_color_changes) != 0) - for (i = 0; i < dip.nr_color_changes; i++) { - if (curr_color_changes[dip.first_color_change + i].cmp(prev_color_changes[dip_old.first_color_change + i]) != 0) - return 1; - } - return 0; - }; - - this.finish_decisions = function () { - var hpos = this.maxhpos; - - if (this.nodraw()) - return; - - this.decide_diw(hpos); - this.decide_line(hpos); - this.decide_fetch(hpos); - - this.record_color_change2(hsyncstartpos, 0xffff, 0); - if (thisline_decision.plfleft >= 0 && thisline_decision.plflinelen < 0) { - if (fetch_state != FETCH_NOT_STARTED) { - BUG.info('finish_decisions() fetch_state=%d plfleft=%d,len=%d,vpos=%d,hpos=%d', fetch_state, thisline_decision.plfleft, thisline_decision.plflinelen, this.vpos, hpos); - Fatal(333, 'finish_decisions() fetch_state != FETCH_NOT_STARTED'); - } - thisline_decision.plfright = thisline_decision.plfleft; - thisline_decision.plflinelen = 0; - thisline_decision.bplres = RES_LORES; - } - if (hdiwstate == DIW_WAITING_STOP) { - thisline_decision.diwlastword = max_diwlastword(); - if (thisline_decision.diwfirstword < 0) - thisline_decision.diwfirstword = 0; - } - if (SMART_UPDATE) { - if (thisline_decision.diwfirstword != line_decisions[next_lineno].diwfirstword) - thisline_changed = 1; //MARK_LINE_CHANGED; - if (thisline_decision.diwlastword != line_decisions[next_lineno].diwlastword) - thisline_changed = 1; //MARK_LINE_CHANGED; - } - var dip = curr_drawinfo[next_lineno]; - var dip_old = prev_drawinfo[next_lineno]; - var dp = line_decisions[next_lineno]; - var changed = thisline_changed; - if (thisline_decision.plfleft >= 0 && thisline_decision.nr_planes > 0) - this.record_diw_line(thisline_decision.plfleft, diwfirstword, diwlastword); - - this.decide_sprites(hpos + 1); - - dip.last_sprite_entry = next_sprite_entry; - dip.last_color_change = next_color_change; - - if (thisline_decision.ctable < 0) - this.remember_ctable(); - - dip.nr_color_changes = next_color_change - dip.first_color_change; - dip.nr_sprites = next_sprite_entry - dip.first_sprite_entry; - - if (thisline_decision.plfleft != line_decisions[next_lineno].plfleft) - changed = 1; - if (!changed && this.color_changes_differ(dip, dip_old)) - changed = 1; - if (!changed && /* bitplane visible in this line OR border sprites enabled */ - (thisline_decision.plfleft >= 0 || ((thisline_decision.bplcon0 & 1) && (thisline_decision.bplcon3 & 0x02) && !(thisline_decision.bplcon3 & 0x20))) - && this.sprites_differ(dip, dip_old)) - changed = 1; - - if (changed) { - thisline_changed = 1; - dp.set(thisline_decision); //*dp = thisline_decision; - } else - line_decisions[next_lineno].ctable = thisline_decision.ctable; - - next_color_change += ((HBLANK_OFFSET + 1) >> 1); - - diw_hcounter += this.maxhpos * 2; - if (!(AMIGA.config.chipset.mask & CSMASK_ECS_DENISE) && this.vpos == this.get_equ_vblank_endline() - 1) - diw_hcounter++; - if ((AMIGA.config.chipset.mask & CSMASK_ECS_DENISE) || this.vpos > this.get_equ_vblank_endline() || (AMIGA.config.chipset.agnus_dip && this.vpos == 0)) { - diw_hcounter = this.maxhpos * 2; - last_hdiw = 1; //2 - 1; - } - if (next_color_change >= MAX_REG_CHANGE - 30) { - BUG.info('ColorChange buffer overflow!'); - next_color_change = 0; - dip.nr_color_changes = 0; - dip.first_color_change = 0; - dip.last_color_change = 0; - } - }; - - this.hsync_record_line_state = function (lineno, how, changed) { - if (framecnt != 0) - return; - - //changed += ((frame_redraw_necessary ? 1 : 0) + ((lineno >= lightpen_y1 && lineno <= lightpen_y2) ? 1 : 0)); - changed += (frame_redraw_necessary ? 1 : 0); - - switch (how) { - case NLN_NORMAL: - linestate[lineno] = changed ? LINE_DECIDED : LINE_DONE; - break; - case NLN_DOUBLED: - linestate[lineno] = changed ? LINE_DECIDED_DOUBLE : LINE_DONE; - changed += (linestate[lineno + 1] != LINE_REMEMBERED_AS_PREVIOUS ? 1 : 0); - linestate[lineno + 1] = changed ? LINE_AS_PREVIOUS : LINE_DONE_AS_PREVIOUS; - break; - case NLN_NBLACK: - linestate[lineno] = changed ? LINE_DECIDED : LINE_DONE; - if (linestate[lineno + 1] != LINE_REMEMBERED_AS_BLACK) - linestate[lineno + 1] = LINE_BLACK; - break; - case NLN_LOWER: - if (linestate[lineno - 1] == LINE_UNDECIDED) - linestate[lineno - 1] = LINE_DECIDED; //LINE_BLACK; - linestate[lineno] = changed ? LINE_DECIDED : LINE_DONE; - break; - case NLN_UPPER: - linestate[lineno] = changed ? LINE_DECIDED : LINE_DONE; - if (linestate[lineno + 1] == LINE_UNDECIDED - || linestate[lineno + 1] == LINE_REMEMBERED_AS_PREVIOUS - || linestate[lineno + 1] == LINE_AS_PREVIOUS) - linestate[lineno + 1] = LINE_DECIDED; //LINE_BLACK; - break; - } - }; - - this.get_equ_vblank_endline = function () { - return equ_vblank_endline + (equ_vblank_toggle ? (this.lof_current ? 1 : 0) : 0); - }; - - this.decide_diw = function (hpos) { - var hdiw = hpos >= this.maxhpos ? this.maxhpos * 2 + 1 : hpos * 2 + 2; - if (!(AMIGA.config.chipset.mask & CSMASK_ECS_DENISE) && this.vpos <= this.get_equ_vblank_endline()) - hdiw = diw_hcounter; - - hdiw &= 511; - for (; ;) { - var lhdiw = hdiw; - if (last_hdiw > lhdiw) - lhdiw = 512; - - if (lhdiw >= diw_hstrt && last_hdiw < diw_hstrt && hdiwstate == DIW_WAITING_START) { - if (thisline_decision.diwfirstword < 0) - thisline_decision.diwfirstword = diwfirstword < 0 ? 0 : diwfirstword; - hdiwstate = DIW_WAITING_STOP; - } - if (lhdiw >= diw_hstop && last_hdiw < diw_hstop && hdiwstate == DIW_WAITING_STOP) { - if (thisline_decision.diwlastword < 0) - thisline_decision.diwlastword = diwlastword < 0 ? 0 : diwlastword; - hdiwstate = DIW_WAITING_START; - } - if (lhdiw != 512) - break; - last_hdiw = -1; //0 - 1; - } - last_hdiw = hdiw; - }; - - this.reset_bpl_vars = function (hpos) { - out_nbits = 0; - out_offs = 0; - toscr_nbits = 0; - thisline_decision.bplres = bplcon0_res; - }; - - this.start_bpl_dma = function (hpos, hstart) { - if (first_bpl_vpos < 0) - first_bpl_vpos = this.vpos; - - if (this.doflickerfix() && interlace_seen > 0) { //&& !scandoubled_line) { - for (var i = 0; i < 8; i++) { - prevbpl[this.lof_current][this.vpos][i] = bplptx[i]; - if (!this.lof_current && (bplcon0 & 4)) - bplpt[i] = prevbpl[1 - this.lof_current][this.vpos][i]; - if (!(bplcon0 & 4) || interlace_seen < 0) - prevbpl[1 - this.lof_current][this.vpos][i] = prevbpl[this.lof_current][this.vpos][i] = 0; - } - } - plfstrt_sprite = plfstrt; - fetch_state = FETCH_STARTED; - fetch_cycle = 0; - - ddfstate = DIW_WAITING_STOP; - this.compute_toscr_delay(last_fetch_hpos, bplcon1); - - if (bpl1dat_written_at_least_once && hstart > last_fetch_hpos) { - this.update_fetch_x(hstart, fetchmode); - bpl1dat_written_at_least_once = false; - } else - this.reset_bpl_vars(); - /*#if 0 - if (!this.nodraw ()) { - if (thisline_decision.plfleft >= 0) { - out_nbits = (plfstrt - thisline_decision.plfleft) << (1 + toscr_res); - out_offs = out_nbits >> 5; - out_nbits &= 31; - } - this.update_toscr_planes(); - } - #endif*/ - last_fetch_hpos = hstart; - cycle_diagram_shift = hstart; - }; - - this.maybe_start_bpl_dma = function (hpos) { - //console.log('maybe_start_bpl_dma', hpos); - if (!(AMIGA.config.chipset.mask & CSMASK_ECS_AGNUS)) - return; - if (fetch_state != FETCH_NOT_STARTED) - return; - if (diwstate != DIW_WAITING_STOP) - return; - if (hpos <= plfstrt) - return; - if (hpos > plfstop - fetchunit) - return; - if (ddfstate != DIW_WAITING_START) - plf_state = PLF_PASSED_STOP; - - this.start_bpl_dma(hpos, hpos); - }; - - this.decide_line = function (hpos) { - if (this.vpos == plffirstline) { - diwstate = DIW_WAITING_STOP; - ddf_change = this.vpos; - } - if (this.vpos == plflastline) { - diwstate = DIW_WAITING_START; - ddf_change = this.vpos; - } - if (hpos <= last_decide_line_hpos) - return; - - if (fetch_state == FETCH_NOT_STARTED && (diwstate == DIW_WAITING_STOP || (AMIGA.config.chipset.mask & CSMASK_ECS_AGNUS))) { - var ok = 0; - if (last_decide_line_hpos < plfstrt_start && hpos >= plfstrt_start) { - if (plf_state == PLF_IDLE) - plf_state = PLF_START; - } - if (last_decide_line_hpos < plfstrt && hpos >= plfstrt) { - if (plf_state == PLF_START) - plf_state = PLF_ACTIVE; - if (plf_state == PLF_ACTIVE) - ok = 1; - if (hpos - 2 == ddfstrt_old_hpos) - ok = 0; - } - if (ok && diwstate == DIW_WAITING_STOP) { - if (AMIGA.dmaen(DMAF_BPLEN)) { - this.start_bpl_dma(hpos, plfstrt); - this.estimate_last_fetch_cycle(plfstrt); - } - //last_decide_line_hpos = hpos; - if (!CUSTOM_SIMPLE) - this.do_sprites(hpos); - - return; - } - } - if (!CUSTOM_SIMPLE) { - if (hpos > last_sprite_hpos && last_sprite_hpos < SPR0_HPOS + 4 * MAX_SPRITES) - this.do_sprites(hpos); - } - last_decide_line_hpos = hpos; - }; - - /*---------------------------------*/ - /* to screen */ - - this.toscr_2_ecs = function (nbits) { - var mask = 0xffff >> (16 - nbits); + function compute_framesync() { //global + var islace = interlace_seen ? 1 : 0; + var isntsc = (beamcon0 & 0x20) ? 0 : 1; + var found = false; var i; - for (i = 0; i < toscr_nr_planes2; i += 2) { - outword[i] <<= nbits; - outword[i] |= (todisplay[i][0] >> (16 - nbits + toscr_delay1)) & mask; - todisplay[i][0] <<= nbits; - } - for (i = 1; i < toscr_nr_planes2; i += 2) { - outword[i] <<= nbits; - outword[i] |= (todisplay[i][0] >> (16 - nbits + toscr_delay2)) & mask; - todisplay[i][0] <<= nbits; - } - }; + if (islace) + vblank_hz = vblank_hz_lace; + else if (lof_current) + vblank_hz = vblank_hz_lof; + else + vblank_hz = vblank_hz_shf; - this.toscr_1 = function (nbits, fm) { - switch (fm) { - case 0: - this.toscr_2_ecs(nbits); - break; - /*#ifdef AGA - case 1: - this.toscr_3_aga(nbits, 1); - break; - case 2: - this.toscr_3_aga(nbits, 2); - break; - #endif*/ - } - out_nbits += nbits; - if (out_nbits == 32) { - for (var i = 0; i < thisline_decision.nr_planes; i++) { - if (line_data[next_lineno][i][out_offs] != outword[i]) { - thisline_changed = 1; - line_data[next_lineno][i][out_offs] = outword[i]; + var cr = get_chipset_refresh(); //struct chipset_refresh * + while (cr !== null) { + var v = -1.0; + if (!SAEV_Playfield_picasso_on && !SAEV_Playfield_picasso_requested_on) { + /*if (isvsync_chipset()) { + if (cr.index == SAEC_Config_Chipset_CR_PAL || cr.index == SAEC_Config_Chipset_CR_NTSC) { + if ((fabs (vblank_hz - 50) < 1 || fabs (vblank_hz - 60) < 1 || fabs (vblank_hz - 100) < 1 || fabs (vblank_hz - 120) < 1) && SAEV_config.video.apmode[0].gfx_vsync == 2 && SAEV_config.video.apmode[0].gfx_fullscreen > 0) { + vsync_switchmode((int)vblank_hz); + } + } + if (isvsync_chipset() < 0) { + var v2 = vblank_calibrate(cr.locked ? cr.rate : vblank_hz, cr.locked); + if (!cr.locked) + v = v2; + } else if (isvsync_chipset() > 0) { + if (SAEV_config.video.apmode[0].gfx_refreshrate) + v = abs (SAEV_config.video.apmode[0].gfx_refreshrate); + } + } else*/ { + if (cr.locked == false) { + SAEV_config.chipset.refreshRate = vblank_hz; + //changed_prefs.chipset_refreshrate = SAEV_config.chipset.refreshRate = vblank_hz; cfgfile_parse_lines (&changed_prefs, cr.commands, -1); + break; + } else + v = cr.rate; + } + if (v < 0) + v = cr.rate; + if (v > 0) { + SAEV_config.chipset.refreshRate = v; + //changed_prefs.chipset_refreshrate = SAEV_config.chipset.refreshRate = v; cfgfile_parse_lines (&changed_prefs, cr.commands, -1); } - outword[i] = 0; - } - out_offs++; - out_nbits = 0; - } - }; - - this.toscr = function (nbits, fm) { - if (nbits > 16) { - this.toscr(16, fm); - nbits -= 16; - } - var t = 32 - out_nbits; - if (t < nbits) { - this.toscr_1(t, fm); - nbits -= t; - } - this.toscr_1(nbits, fm); - }; - - this.flush_plane_data = function (fm) { - var i = 0; - - if (out_nbits <= 16) { - i += 16; - this.toscr_1(16, fm); - } - if (out_nbits != 0) { - i += 32 - out_nbits; - this.toscr_1(32 - out_nbits, fm); - } - i += 32; - - this.toscr_1(16, fm); - this.toscr_1(16, fm); - - if (fm == 2) { - // flush AGA full 64-bit shift register - i += 32; - this.toscr_1(16, fm); - this.toscr_1(16, fm); - } - if (bpl1dat_early) { - this.toscr_1(16, fm); - this.toscr_1(16, fm); - } - return i >> (1 + toscr_res); - }; - - this.flush_display = function (fm) { - if (toscr_nbits > 0 && thisline_decision.plfleft >= 0) - this.toscr(toscr_nbits, fm); - toscr_nbits = 0; - }; - - this.beginning_of_plane_block = function (hpos, fm) { - var oleft = thisline_decision.plfleft; - - this.flush_display(fm); - - if (fm == 0) - for (var i = 0; i < MAX_PLANES; i++) { - todisplay[i][0] |= fetched[i]; - } - /*#ifdef AGA - else - for (i = 0; i < MAX_PLANES; i++) { - if (fm == 2) - todisplay[i][1] = fetched_aga1[i]; - todisplay[i][0] = fetched_aga0[i]; - } - #endif*/ - - this.update_denise(hpos); - this.maybe_first_bpl1dat(hpos); - - bplcon1t2 = bplcon1t; - bplcon1t = bplcon1; - if (bplcon1_hpos != hpos || oleft < 0) - bplcon1t2 = bplcon1t; - - this.compute_toscr_delay(hpos, bplcon1t2); - }; - - this.update_bpldats = function (hpos) { - for (var i = 0; i < MAX_PLANES; i++) { - /*#ifdef AGA - fetched_aga0[i] = bplxdat[i]; - fetched_aga1[i] = 0; - #endif*/ - fetched[i] = bplxdat[i]; - } - this.beginning_of_plane_block(hpos, fetchmode); - }; - - /*---------------------------------*/ - /* fetch */ - - this.finish_final_fetch = function (pos, fm) { - if (thisline_decision.plfleft < 0 || plf_state == PLF_END) - return; - - plf_state = PLF_END; - ddfstate = DIW_WAITING_START; - pos += this.flush_plane_data(fm); - thisline_decision.plfright = pos; - thisline_decision.plflinelen = out_offs; - - if (this.vpos >= minfirstline && (thisframe_first_drawn_line < 0 || this.vpos < thisframe_first_drawn_line)) - thisframe_first_drawn_line = this.vpos; - thisframe_last_drawn_line = this.vpos; - - if (SMART_UPDATE) { - if (line_decisions[next_lineno].plflinelen != thisline_decision.plflinelen - || line_decisions[next_lineno].plfleft != thisline_decision.plfleft - || line_decisions[next_lineno].bplcon0 != thisline_decision.bplcon0 - || line_decisions[next_lineno].bplcon2 != thisline_decision.bplcon2 - || line_decisions[next_lineno].bplcon3 != thisline_decision.bplcon3 - /*#ifdef AGA - || line_decisions[next_lineno].bplcon4 != thisline_decision.bplcon4 - #endif*/ - ) thisline_changed = 1; - } else - thisline_changed = 1; - }; - - this.long_fetch_ecs = function (plane, nwords, weird_number_of_bits, dma) { - //uae_u16 *real_pt = (uae_u16 *)pfield_xlateptr (bplpt[plane], nwords * 2); - var real_pt = bplpt[plane]; - var delay = (plane & 1) ? toscr_delay2 : toscr_delay1; - var tmp_nbits = out_nbits; - var shiftbuffer = todisplay[plane][0]; - var outval = outword[plane]; - var fetchval = fetched[plane]; - //var *dataptr = (uae_u32 *)(line_data[next_lineno] + 2 * plane * MAX_WORDS_PER_LINE + 4 * out_offs); - var dataptr = out_offs; - - if (dma) { - bplpt[plane] += nwords * 2; - bplptx[plane] += nwords * 2; - } - - //if (real_pt == 0) /* @@@ Don't do this, fall back on chipmem_wget instead. */ - //return; - - while (nwords > 0) { - var bits_left = 32 - tmp_nbits; - var t; - - shiftbuffer |= fetchval; - - t = (shiftbuffer >>> delay) & 0xFFFF; - - if (weird_number_of_bits && bits_left < 16) { - //outval <<= bits_left; - //outval |= t >>> (16 - bits_left); - outval = ((outval << bits_left) | (t >>> (16 - bits_left))) >>> 0; - //thisline_changed |= *dataptr ^ outval; *dataptr++ = outval; - thisline_changed |= line_data[next_lineno][plane][dataptr] ^ outval; - line_data[next_lineno][plane][dataptr++] = outval; - outval = t; - tmp_nbits = 16 - bits_left; - //shiftbuffer <<= 16; - shiftbuffer = (shiftbuffer << 16) >>> 0; } else { - outval = ((outval << 16) | t) >>> 0; - shiftbuffer = (shiftbuffer << 16) >>> 0; - tmp_nbits += 16; - if (tmp_nbits == 32) { - //thisline_changed |= *dataptr ^ outval; *dataptr++ = outval; - thisline_changed |= line_data[next_lineno][plane][dataptr] ^ outval; - line_data[next_lineno][plane][dataptr++] = outval; - tmp_nbits = 0; - } - } - nwords--; - if (dma) { - //fetchval = do_get_mem_word (real_pt); real_pt++; - //fetchval = AMIGA.mem.load16_chip(real_pt); real_pt += 2; - fetchval = AMIGA.custom.last_value = AMIGA.mem.chip.data[real_pt >>> 1]; - real_pt += 2; - } - } - fetched[plane] = fetchval; - todisplay[plane][0] = shiftbuffer; - outword[plane] = outval; - }; - - this.do_long_fetch = function (hpos, nwords, dma, fm) { - var i; - - this.flush_display(fm); - switch (fm) { - case 0: - if (out_nbits & 15) { - for (i = 0; i < toscr_nr_planes; i++) - this.long_fetch_ecs(i, nwords, 1, dma); - } else { - for (i = 0; i < toscr_nr_planes; i++) - this.long_fetch_ecs(i, nwords, 0, dma); - } - break; - /*#ifdef AGA - case 1: - if (out_nbits & 15) { - for (i = 0; i < toscr_nr_planes; i++) - this.long_fetch_aga(i, nwords, 1, 1, dma); - } else { - for (i = 0; i < toscr_nr_planes; i++) - this.long_fetch_aga(i, nwords, 0, 1, dma); - } - break; - case 2: - if (out_nbits & 15) { - for (i = 0; i < toscr_nr_planes; i++) - this.long_fetch_aga(i, nwords, 1, 2, dma); - } else { - for (i = 0; i < toscr_nr_planes; i++) - this.long_fetch_aga(i, nwords, 0, 2, dma); - } - break; - #endif*/ - } - out_nbits += nwords * 16; - out_offs += out_nbits >> 5; - out_nbits &= 31; - - if (dma && toscr_nr_planes > 0) - fetch_state = FETCH_WAS_PLANE0; - }; - - this.add_modulos = function () { - var m1, m2; - - if (fmode & 0x4000) { - if (((diwstrt >> 8) ^ this.vpos) & 1) - m1 = m2 = bpl2mod; - else - m1 = m2 = bpl1mod; - } else { - m1 = bpl1mod; - m2 = bpl2mod; - } - - switch (bplcon0_planes_limit) { - /*#ifdef AGA - case 8: bplpt[7] += m2; bplptx[7] += m2; - case 7: bplpt[6] += m1; bplptx[6] += m1; - #endif*/ - case 6: - bplpt[5] += m2; - bplptx[5] += m2; - case 5: - bplpt[4] += m1; - bplptx[4] += m1; - case 4: - bplpt[3] += m2; - bplptx[3] += m2; - case 3: - bplpt[2] += m1; - bplptx[2] += m1; - case 2: - bplpt[1] += m2; - bplptx[1] += m2; - case 1: - bplpt[0] += m1; - bplptx[0] += m1; - } - }; - - this.fetch = function (nr, fm, hpos) { - if (nr < bplcon0_planes_limit) { - var p = bplpt[nr]; - bplpt[nr] += (2 << fm); - bplptx[nr] += (2 << fm); - if (nr == 0) - bpl1dat_written = true; - - switch (fm) { - case 0: - //fetched[nr] = bplxdat[nr] = last_custom_value1 = chipmem_wget_indirect (p); - //fetched[nr] = bplxdat[nr] = AMIGA.mem.load16_chip(p); - fetched[nr] = bplxdat[nr] = AMIGA.custom.last_value = AMIGA.mem.chip.data[p >>> 1]; - break; - /*#ifdef AGA - case 1: - fetched_aga0[nr] = chipmem_lget_indirect (p); - last_custom_value1 = (uae_u16)fetched_aga0[nr]; - break; - case 2: - fetched_aga1[nr] = chipmem_lget_indirect (p); - fetched_aga0[nr] = chipmem_lget_indirect (p + 4); - last_custom_value1 = (uae_u16)fetched_aga0[nr]; - break; - #endif*/ - } - if (plf_state == PLF_PASSED_STOP2 && fetch_cycle >= (fetch_cycle & ~fetchunit_mask) + fetch_modulo_cycle) { - var mod; - if (fmode & 0x4000) { - if (((diwstrt >> 8) ^ this.vpos) & 1) - mod = bpl2mod; - else - mod = bpl1mod; - } else if (nr & 1) - mod = bpl2mod; + if (cr.locked == false) + v = vblank_hz; else - mod = bpl1mod; - - bplpt[nr] += mod; - bplptx[nr] += mod; + v = cr.rate; + SAEV_config.chipset.refreshRate = v; + //changed_prefs.chipset_refreshrate = SAEV_config.chipset.refreshRate = v; cfgfile_parse_lines (&changed_prefs, cr.commands, -1); } + found = true; + break; + } + if (!found) SAEV_config.chipset.refreshRate = vblank_hz; + //if (!found) changed_prefs.chipset_refreshrate = SAEV_config.chipset.refreshRate = vblank_hz; + + + stored_chipset_refresh = cr; + interlace_changed = 0; + lof_togglecnt_lace = 0; + lof_togglecnt_nlace = 0; + //nlace_cnt = NLACE_CNT_NEEDED; + lof_changing = 0; + gfxvidinfo.drawbuffer.inxoffset = -1; + gfxvidinfo.drawbuffer.inyoffset = -1; + + if (beamcon0 & 0x80) { + var res = GET_RES_AGNUS(bplcon0); + var vres = islace ? 1 : 0; + var res2, vres2; + + res2 = SAEV_config.video.hresolution; + if (doublescan > 0) + res2++; + if (res2 > RES_MAX) + res2 = RES_MAX; + + vres2 = SAEV_config.video.vresolution; + if (doublescan > 0 && !islace) + vres2--; + + if (vres2 < 0) + vres2 = 0; + if (vres2 > VRES_QUAD) + vres2 = VRES_QUAD; + + var start = hsyncstartpos; //hbstrt; + var stop = hsyncendpos; //hbstop; + + gfxvidinfo.drawbuffer.inwidth = ((maxhpos - (maxhpos - start + DISPLAY_LEFT_SHIFT/2) + 1) * 2) << res2; //ATT ok, DISPLAY_LEFT_SHIFT/2 == 0x38/2 + gfxvidinfo.drawbuffer.inxoffset = stop * 2; + + gfxvidinfo.drawbuffer.extrawidth = 0; + gfxvidinfo.drawbuffer.inwidth2 = gfxvidinfo.drawbuffer.inwidth; + + gfxvidinfo.drawbuffer.inheight = ((firstblankedline < maxvpos ? firstblankedline : maxvpos) - minfirstline + 1) << vres2; + gfxvidinfo.drawbuffer.inheight2 = gfxvidinfo.drawbuffer.inheight; } else { - if (nr < MAX_PLANES) //FIX for illegal memory access if not #ifdef AGA - fetched[nr] = bplxdat[nr]; - } - }; + gfxvidinfo.drawbuffer.inwidth = SAEC_Video_MAX_AMIGA_WIDTH << SAEV_config.video.hresolution; - this.one_fetch_cycle = function (pos, ddfstop_to_test, dma, fm) { - if (plf_state < PLF_PASSED_STOP && pos == ddfstop_to_test) - plf_state = PLF_PASSED_STOP; + gfxvidinfo.drawbuffer.extrawidth = -1; //currprefs.gfx_extrawidth ? currprefs.gfx_extrawidth : -1; //OWN + gfxvidinfo.drawbuffer.inwidth2 = gfxvidinfo.drawbuffer.inwidth; - if ((fetch_cycle & fetchunit_mask) == 0) { - if (plf_state == PLF_PASSED_STOP2) { - this.finish_final_fetch(pos, fm); - return 1; - } - if (plf_state == PLF_PASSED_STOP) - plf_state = PLF_PASSED_STOP2; - else if (plf_state == PLF_PASSED_STOP2) - plf_state = PLF_END; - } - this.maybe_check(pos); - - if (dma) { - var cycle_start = fetch_cycle & fetchstart_mask; - switch (fm_maxplane) { - case 8: - switch (cycle_start) { - case 0: - this.fetch(7, fm, pos); - break; - case 1: - this.fetch(3, fm, pos); - break; - case 2: - this.fetch(5, fm, pos); - break; - case 3: - this.fetch(1, fm, pos); - break; - case 4: - this.fetch(6, fm, pos); - break; - case 5: - this.fetch(2, fm, pos); - break; - case 6: - this.fetch(4, fm, pos); - break; - case 7: - this.fetch(0, fm, pos); - break; - } - break; - case 4: - switch (cycle_start) { - case 0: - this.fetch(3, fm, pos); - break; - case 1: - this.fetch(1, fm, pos); - break; - case 2: - this.fetch(2, fm, pos); - break; - case 3: - this.fetch(0, fm, pos); - break; - } - break; - case 2: - switch (cycle_start) { - case 0: - this.fetch(1, fm, pos); - break; - case 1: - this.fetch(0, fm, pos); - break; - } - break; - } - } - if (bpl1dat_written) { - fetch_state = FETCH_WAS_PLANE0; - bpl1dat_written = false; + gfxvidinfo.drawbuffer.inheight = (maxvpos_display - minfirstline + 1) << SAEV_config.video.vresolution; + gfxvidinfo.drawbuffer.inheight2 = gfxvidinfo.drawbuffer.inheight; } - fetch_cycle++; - toscr_nbits += (2 << toscr_res); + if (gfxvidinfo.drawbuffer.inwidth > gfxvidinfo.drawbuffer.width_allocated) + gfxvidinfo.drawbuffer.inwidth = gfxvidinfo.drawbuffer.width_allocated; + if (gfxvidinfo.drawbuffer.inwidth2 > gfxvidinfo.drawbuffer.width_allocated) + gfxvidinfo.drawbuffer.inwidth2 = gfxvidinfo.drawbuffer.width_allocated; - if (toscr_nbits > 16) { - Fatal(333, sprintf('one_fetch_cycle() toscr_nbits > 16 (%d)', toscr_nbits)); - toscr_nbits = 0; + if (gfxvidinfo.drawbuffer.inheight > gfxvidinfo.drawbuffer.height_allocated) + gfxvidinfo.drawbuffer.inheight = gfxvidinfo.drawbuffer.height_allocated; + if (gfxvidinfo.drawbuffer.inheight2 > gfxvidinfo.drawbuffer.height_allocated) + gfxvidinfo.drawbuffer.inheight2 = gfxvidinfo.drawbuffer.height_allocated; + + gfxvidinfo.drawbuffer.outwidth = gfxvidinfo.drawbuffer.inwidth; + gfxvidinfo.drawbuffer.outheight = gfxvidinfo.drawbuffer.inheight; + + if (gfxvidinfo.drawbuffer.outwidth > gfxvidinfo.drawbuffer.width_allocated) + gfxvidinfo.drawbuffer.outwidth = gfxvidinfo.drawbuffer.width_allocated; + + if (gfxvidinfo.drawbuffer.outheight > gfxvidinfo.drawbuffer.height_allocated) + gfxvidinfo.drawbuffer.outheight = gfxvidinfo.drawbuffer.height_allocated; + + //memset(line_decisions, 0, sizeof line_decisions); + //for (i = 0; i < sizeof (line_decisions) / sizeof *line_decisions; i++) line_decisions[i].plfleft = -2; + for (i = 0; i < line_decisions.length; i++) { + line_decisions[i].clr(); + line_decisions[i].plfleft = -2; } - if (toscr_nbits == 16) - this.flush_display(fm); - - return 0; - }; - - this.update_fetch = function (until, fm) { - var dma = AMIGA.dmaen(DMAF_BPLEN); - - if (this.nodraw() || plf_state == PLF_END) - return; - - var ddfstop_to_test = HARD_DDF_STOP; - if (ddfstop >= last_fetch_hpos && plfstop < ddfstop_to_test) - ddfstop_to_test = plfstop; - - this.update_toscr_planes(); - - var pos = last_fetch_hpos; - cycle_diagram_shift = last_fetch_hpos - fetch_cycle; - - for (; ; pos++) { - if (pos == until) { - if (until >= this.maxhpos) { - this.finish_final_fetch(pos, fm); - return; - } - this.flush_display(fm); - return; - } - if (fetch_state == FETCH_WAS_PLANE0) - break; - - fetch_state = FETCH_STARTED; - if (this.one_fetch_cycle(pos, ddfstop_to_test, dma, fm)) - return; + //memset(line_drawinfo, 0, sizeof line_drawinfo); + for (i = 0; i < line_drawinfo[0].length; i++) { + line_drawinfo[0][i].clr(); + line_drawinfo[1][i].clr(); } - // Unrolled version of the for loop below. - if (1 - && plf_state < PLF_PASSED_STOP && ddf_change != this.vpos && ddf_change + 1 != this.vpos - && dma - && (fetch_cycle & fetchstart_mask) == (fm_maxplane & fetchstart_mask) - && !badmode - //&& (out_nbits & 15) == 0 - && toscr_nr_planes == thisline_decision.nr_planes) { - var offs = (pos - fetch_cycle) & fetchunit_mask; - var ddf2 = ((ddfstop_to_test - offs + fetchunit - 1) & ~fetchunit_mask) + offs; - var ddf3 = ddf2 + fetchunit; - var stop = until < ddf2 ? until : until < ddf3 ? ddf2 : ddf3; - var count = stop - pos; + compute_vsynctime(); - if (count >= fetchstart) { - count &= ~fetchstart_mask; + hblank_hz = (SAEV_config.chipset.ntsc ? SAEC_Playfield_CLOCK_NTSC : SAEC_Playfield_CLOCK_PAL) / (maxhpos + (islinetoggle() ? 0.5 : 0)); - if (thisline_decision.plfleft < 0) { - this.compute_delay_offset(); - this.compute_toscr_delay_1(bplcon1); - } + SAEF_log("playfield.compute_framesync() %s mode%s%s V=%.4fHz H=%0.4fHz (%dx%d+%d) IDX=%d (%s) DSP=%d RTG=%d/%d", + isntsc ? "NTSC" : "PAL", + islace ? " lace" : (lof_lace ? " loflace" : ""), + doublescan > 0 ? " dblscan" : "", + vblank_hz, + hblank_hz, + maxhpos, maxvpos, lof_store ? 1 : 0, + cr !== null ? cr.index : -1, + cr !== null && cr.label.length ? cr.label : "", + SAEV_config.video.apmode[SAEV_Playfield_picasso_on ? 1 : 0].gfx_display, + SAEV_Playfield_picasso_on?1:0, SAEV_Playfield_picasso_requested_on?1:0 + ); - this.do_long_fetch(pos, count >> (3 - toscr_res), dma, fm); + //set_config_changed(); //OWN + if (SAER.video.target_graphics_buffer_update()) + reset_drawing(); + } - this.maybe_first_bpl1dat(pos); + /* set PAL/NTSC or custom timing variables */ + function init_hz(checkvposw) { + var isntsc, islace; + var odbl = doublescan, omaxvpos = maxvpos; + var ovblank = vblank_hz; + var hzc = 0; - if (pos <= ddfstop_to_test && pos + count > ddfstop_to_test) - plf_state = PLF_PASSED_STOP; - if (pos <= ddfstop_to_test && pos + count > ddf2) - plf_state = PLF_PASSED_STOP2; - if (pos <= ddf2 && pos + count >= ddf2 + fm_maxplane) - this.add_modulos(); - pos += count; - fetch_cycle += count; - } + if (!checkvposw) + vpos_count = 0; + + vpos_count_diff = vpos_count; + + doublescan = 0; + programmedmode = false; + if ((beamcon0 & 0xA0) != (new_beamcon0 & 0xA0)) + hzc = 1; + if (beamcon0 != new_beamcon0) { + SAEF_log("playfield.init_hz() BEAMCON0 0x%04x -> 0x%04x", beamcon0, new_beamcon0); + vpos_count_diff = vpos_count = 0; } - - for (; pos < until; pos++) { - if (fetch_state == FETCH_WAS_PLANE0) { - this.beginning_of_plane_block(pos, fm); - this.estimate_last_fetch_cycle(pos); - } - fetch_state = FETCH_STARTED; - if (this.one_fetch_cycle(pos, ddfstop_to_test, dma, fm)) - return; - } - if (until >= this.maxhpos) { - this.finish_final_fetch(pos, fm); - return; - } - this.flush_display(fm); - }; - - this.update_fetch_x = function (until, fm) { - if (this.nodraw()) - return; - - var pos = last_fetch_hpos; - this.update_toscr_planes(); - - for (; pos < until; pos++) { - toscr_nbits += (2 << toscr_res); - if (toscr_nbits > 16) { - Fatal(333, sprintf('update_fetch_x() xtoscr_nbits > 16 (%d)', toscr_nbits)); - toscr_nbits = 0; - } - if (toscr_nbits == 16) - this.flush_display(fm); - } - if (until >= this.maxhpos) { - this.finish_final_fetch(pos, fm); - return; - } - this.flush_display(fm); - }; - - this.decide_fetch = function (hpos) { - if (hpos > last_fetch_hpos) { - if (fetch_state != FETCH_NOT_STARTED) { - this.update_fetch(hpos, fetchmode); - //cycle_diagram_shift = hpos - fetch_cycle; - } else if (bpl1dat_written_at_least_once) { - this.update_fetch_x(hpos, fetchmode); - bpl1dat_written = false; - } - this.maybe_check(hpos); - last_fetch_hpos = hpos; - } - }; - - /*this.decide_fetch_ce = function (hpos) { - if ((ddf_change == this.vpos || ddf_change + 1 == this.vpos) && this.vpos < this.current_maxvpos()) - this.decide_fetch(hpos); - };*/ - - this.estimate_last_fetch_cycle = function (hpos) { - var fetchunit = fetchunits[fetchmode * 4 + bplcon0_res]; - - if (plf_state < PLF_PASSED_STOP) { - var stop = plfstop < hpos || plfstop > HARD_DDF_STOP ? HARD_DDF_STOP : plfstop; - var fetch_cycle_at_stop = fetch_cycle + (stop - hpos); - var starting_last_block_at = (fetch_cycle_at_stop + fetchunit - 1) & ~(fetchunit - 1); - - estimated_last_fetch_cycle = hpos + (starting_last_block_at - fetch_cycle) + fetchunit; + beamcon0 = new_beamcon0; + isntsc = (beamcon0 & 0x20) ? 0 : 1; + islace = (interlace_seen) ? 1 : 0; + if (!(SAEV_config.chipset.mask & SAEC_Config_Chipset_Mask_ECS_AGNUS)) + isntsc = SAEV_config.chipset.ntsc ? 1 : 0; + var clk = SAEV_config.chipset.ntsc ? SAEC_Playfield_CLOCK_NTSC : SAEC_Playfield_CLOCK_PAL; + if (!isntsc) { + maxvpos = MAXVPOS_PAL; + maxhpos = MAXHPOS_PAL; + minfirstline = VBLANK_ENDLINE_PAL; + vblank_hz_nom = vblank_hz = VBLANK_HZ_PAL; + sprite_vblank_endline = VBLANK_SPRITE_PAL; + equ_vblank_endline = EQU_ENDLINE_PAL; + equ_vblank_toggle = true; + vblank_hz_shf = clk / ((maxvpos + 0) * maxhpos); + vblank_hz_lof = clk / ((maxvpos + 1) * maxhpos); + vblank_hz_lace = clk / ((maxvpos + 0.5) * maxhpos); } else { - var starting_last_block_at = (fetch_cycle + fetchunit - 1) & ~(fetchunit - 1); - if (plf_state == PLF_PASSED_STOP2) - starting_last_block_at -= fetchunit; + maxvpos = MAXVPOS_NTSC; + maxhpos = MAXHPOS_NTSC; + minfirstline = VBLANK_ENDLINE_NTSC; + vblank_hz_nom = vblank_hz = VBLANK_HZ_NTSC; + sprite_vblank_endline = VBLANK_SPRITE_NTSC; + equ_vblank_endline = EQU_ENDLINE_NTSC; + equ_vblank_toggle = false; + vblank_hz_shf = clk / ((maxvpos + 0) * (maxhpos + 0.5)); + vblank_hz_lof = clk / ((maxvpos + 1) * (maxhpos + 0.5)); + vblank_hz_lace = clk / ((maxvpos + 0.5) * (maxhpos + 0.5)); + } - estimated_last_fetch_cycle = hpos + (starting_last_block_at - fetch_cycle) + fetchunit; - } - }; - - /*---------------------------------*/ - - this.vsync_handler_post = function () { - if (bplcon0 & 4) - this.lof_store = this.lof_store ? 0 : 1; - this.lof_current = this.lof_store; - if (lof_togglecnt_lace >= LOF_TOGGLES_NEEDED) { - interlace_changed = this.notice_interlace_seen(true); - if (interlace_changed) - this.notice_screen_contents_lost(); - } else if (lof_togglecnt_nlace >= LOF_TOGGLES_NEEDED) { - interlace_changed = this.notice_interlace_seen(false); - if (interlace_changed) - this.notice_screen_contents_lost(); - } - if (this.lof_changing) { - // still same? Trigger change now. - if ((!this.lof_store && this.lof_changing < 0) || (this.lof_store && this.lof_changing > 0)) { - this.lof_changed = 1; + maxvpos_nom = maxvpos; + maxvpos_display = maxvpos; + if (vpos_count > 0) { + // we come here if vpos_count != maxvpos and beamcon0 didn"t change (someone poked VPOSW) + if (vpos_count < 10) + vpos_count = 10; + vblank_hz = (isntsc ? 15734.0 : 15625.0) / vpos_count; + vblank_hz_nom = vblank_hz_shf = vblank_hz_lof = vblank_hz_lace = vblank_hz; + maxvpos_nom = vpos_count - (lof_current ? 1 : 0); + if ((maxvpos_nom >= 256 && maxvpos_nom <= 313) || (beamcon0 & 0x80)) { + maxvpos_display = maxvpos_nom; + } else if (maxvpos_nom < 256) { + maxvpos_display = 255; + } else { + maxvpos_display = 313; } - this.lof_changing = 0; + reset_drawing(); + } else if (vpos_count == 0) { + // mode reset + vpos_count = maxvpos; + vpos_count_diff = maxvpos; } + firstblankedline = maxvpos + 1; + + if (beamcon0 & 0x80) { + // programmable scanrates (ECS Agnus) + if (vtotal >= MAXVPOS) + vtotal = MAXVPOS - 1; + maxvpos = vtotal + 1; + firstblankedline = maxvpos + 1; + if (htotal >= MAXHPOS) + htotal = MAXHPOS - 1; + maxhpos = htotal + 1; + vblank_hz_nom = vblank_hz = 227.0 * 312.0 * 50.0 / (maxvpos * maxhpos); + vblank_hz_shf = vblank_hz; + vblank_hz_lof = 227.0 * 313.0 * 50.0 / (maxvpos * maxhpos); + vblank_hz_lace = 227.0 * 312.5 * 50.0 / (maxvpos * maxhpos); + + if ((beamcon0 & 0x1000) && (beamcon0 & 0x0200)) { // VARVBEN + VARVSYEN + minfirstline = vsstop > vbstop ? vsstop : vbstop; + if (minfirstline > maxvpos >> 1) //OWN / 2 + minfirstline = vsstop > vbstop ? vbstop : vsstop; + firstblankedline = vbstrt; + } else if (beamcon0 & 0x0200) { + minfirstline = vsstop; + if (minfirstline > maxvpos >> 1) //OWN / 2 + minfirstline = 0; + } else if (beamcon0 & 0x1000) { + minfirstline = vbstop; + if (minfirstline > maxvpos >> 1) //OWN / 2 + minfirstline = 0; + firstblankedline = vbstrt; + } + + if (minfirstline < 2) + minfirstline = 2; + if (minfirstline >= maxvpos) + minfirstline = maxvpos - 1; + + if (firstblankedline < minfirstline) + firstblankedline = maxvpos + 1; + + sprite_vblank_endline = minfirstline - 2; + maxvpos_nom = maxvpos; + maxvpos_display = maxvpos; + equ_vblank_endline = -1; + doublescan = htotal <= 164 && vtotal >= 350 ? 1 : 0; + // if superhires and wide enough: not doublescan + if (doublescan && htotal >= 140 && (bplcon0 & 0x0040)) + doublescan = 0; + programmedmode = true; + varsync_changed = true; + vpos_count = maxvpos_nom; + vpos_count_diff = maxvpos_nom; + hzc = 1; + } + if (maxvpos_nom >= MAXVPOS) + maxvpos_nom = MAXVPOS; + if (maxvpos_display >= MAXVPOS) + maxvpos_display = MAXVPOS; + if (SAEV_config.video.scandoubler && doublescan == 0) + doublescan = -1; + if (doublescan != odbl || maxvpos != omaxvpos) + hzc = 1; + /* limit to sane values */ + if (vblank_hz < 10) + vblank_hz = 10; + if (vblank_hz > 300) + vblank_hz = 300; + maxhpos_short = maxhpos; + set_delay_lastcycle(); + if ((beamcon0 & 0x80) && (beamcon0 & 0x0100)) { + hsyncstartpos = hsstrt; + hsyncendpos = hsstop; + + if ((bplcon0 & 1) && (bplcon3 & 1)) { + if (hbstrt > maxhpos >> 1) { //OWN / 2 + if (hsyncstartpos < hbstrt) + hsyncstartpos = hbstrt; + } else { + if (hsyncstartpos > hbstrt) + hsyncstartpos = hbstrt; + } + if (hbstop > maxhpos >> 1) { //OWN / 2 + if (hsyncendpos > hbstop) + hsyncendpos = hbstop; + } else { + if (hsyncendpos < hbstop) + hsyncendpos = hbstop; + } + } + if (hsyncstartpos < hsyncendpos) + hsyncstartpos = maxhpos + hsyncstartpos; + + hsyncendpos--; + + if (hsyncendpos < 2) + hsyncendpos = 2; + } else { + hsyncstartpos = maxhpos_short + 13; + hsyncendpos = 24; + } + hpos_offset = 0; + SAER_Events_eventtab[SAEC_Events_EV_HSYNC].oldcycles = SAEV_Events_currcycle; + SAER_Events_eventtab[SAEC_Events_EV_HSYNC].evtime = SAEV_Events_currcycle + maxhpos * SAEC_Events_CYCLE_UNIT; //HSYNCTIME(); + SAER.events.schedule(); + if (hzc) { + interlace_seen = islace; + reset_drawing(); + } + + maxvpos_total = (SAEV_config.chipset.mask & SAEC_Config_Chipset_Mask_ECS_AGNUS) ? (MAXVPOS_LINES_ECS - 1) : (MAXVPOS_LINES_OCS - 1); + if (maxvpos_total > MAXVPOS) + maxvpos_total = MAXVPOS; /*#ifdef PICASSO96 - if (p96refresh_active) { - vpos_count = p96refresh_active; - vtotal = vpos_count; - } - #endif*/ + if (!p96refresh_active) { + maxvpos_stored = maxvpos; + maxhpos_stored = maxhpos; + vblank_hz_stored = vblank_hz; + } + #endif*/ - if ((beamcon0 & (0x20 | 0x80)) != (new_beamcon0 & (0x20 | 0x80)) || (this.vpos_count > 0 && Math.abs(this.vpos_count - this.vpos_count_diff) > 1) || this.lof_changed) - this.init_hz(false); - else if (interlace_changed) - this.compute_framesync(); + compute_framesync(); - this.lof_changed = 0; + /*#ifdef PICASSO96 + init_hz_p96(); + #endif*/ - AMIGA.copper.COPJMP(1, 1); + if (vblank_hz != ovblank) + SAER.video.updatedisplayarea(); - this.init_hardware_frame(); - }; - - this.hsync_scandoubler = function () { - console.log('hsync_scandoubler'); - var bpltmp = [0, 0, 0, 0, 0, 0, 0, 0], bpltmpx = [0, 0, 0, 0, 0, 0, 0, 0]; + //inputdevice_tablet_strobe(); //OWN + + if (varsync_changed) { + varsync_changed = false; + //dumpsync(); + } + } + function init_hz_vposw() { + init_hz(true); + } + function init_hz_normal() { + init_hz(false); + } + + + + /* + 0 0 - + 1 1 -- + 2 2 - + 3 3 -- + 4 4 - + 5 5 -- + + 0 x -+ + 1 0 -- + 2 1 - + 3 2 -- + 4 3 - + 5 4 -- + */ + function hsync_scandoubler() { + if (lof_store && vpos >= maxvpos_nom - 1) + return; next_lineno++; - //scandoubled_line = 1; + scandoubled_line = 1; - for (var i = 0; i < 8; i++) { + var bpltmp = new Array(8); + var bpltmpx = new Array(8); + var i; + + for (i = 0; i < 8; i++) { bpltmp[i] = bplpt[i]; bpltmpx[i] = bplptx[i]; - if (prevbpl[this.lof_store][this.vpos][i] && prevbpl[1 - this.lof_store][this.vpos][i]) { - var diff = prevbpl[this.lof_store][this.vpos][i] - prevbpl[1 - this.lof_store][this.vpos][i]; - if (this.lof_store) { + if (prevbpl[lof_store][vpos][i] && prevbpl[1 - lof_store][vpos][i]) { + var diff = prevbpl[lof_store][vpos][i] - prevbpl[1 - lof_store][vpos][i]; + if (lof_store) { if (bplcon0 & 4) - bplpt[i] = prevbpl[this.lof_store][this.vpos][i] - diff; + bplpt[i] = prevbpl[lof_store][vpos][i] - diff; } else { if (bplcon0 & 4) - bplpt[i] = prevbpl[this.lof_store][this.vpos][i]; + bplpt[i] = prevbpl[lof_store][vpos][i]; else bplpt[i] = bplpt[i] - diff; @@ -6035,8 +9259,9 @@ function Playfield() { } } - this.reset_decisions(); - plf_state = PLF_IDLE; + reset_decisions(); + plf_state = plf_idle; + plfr_state = plfr_idle; // copy color changes var dip1 = curr_drawinfo[next_lineno - 1]; @@ -6049,125 +9274,481 @@ function Playfield() { var idx = pdip.last_color_change; pdip.last_color_change++; pdip.nr_color_changes++; - curr_color_changes[idx].linepos = hpos + this.maxhpos + 1; + curr_color_changes[idx].linepos = hpos + maxhpos + 1; curr_color_changes[idx].regno = regno; curr_color_changes[idx].value = cs2.value; curr_color_changes[idx + 1].regno = -1; } else { var cs1 = curr_color_changes[next_color_change]; - cs1.set(cs2); //memcpy (cs1, cs2, sizeof (struct ColorChange)); + cpy_color_change(cs1, cs2); //memcpy(cs1, cs2, sizeof (struct color_change)); next_color_change++; } } - curr_color_changes[next_color_change].regno = -1; - this.finish_decisions(); - this.hsync_record_line_state(next_lineno, NLN_NORMAL, thisline_changed); - this.hardware_line_completed(next_lineno); - //scandoubled_line = 0; + finish_decisions(); + hsync_record_line_state(next_lineno, nln_normal, thisline_changed); + hardware_line_completed(next_lineno); + scandoubled_line = 0; - for (var i = 0; i < 8; i++) { + for (i = 0; i < 8; i++) { bplpt[i] = bpltmp[i]; bplptx[i] = bpltmpx[i]; } - }; - - this.hsync_handler_pre = function () { - this.finish_decisions(); - if (thisline_decision.plfleft >= 0) { - if (AMIGA.config.chipset.collision_level > 1) - this.do_sprite_collisions(); - if (AMIGA.config.chipset.collision_level > 2) - this.do_playfield_collisions(); - } - this.hsync_record_line_state(next_lineno, nextline_how, thisline_changed); - if (this.vpos == sprite_vblank_endline) { - //lightpen_triggered = 0; - sprite_0 = 0; - } - /*if (lightpen_cx > 0 && (bplcon0 & 8) && !lightpen_triggered && lightpen_cy == this.vpos) { - vpos_lpen = this.vpos; - hpos_lpen = lightpen_cx; - lightpen_triggered = 1; - }*/ - this.hardware_line_completed(next_lineno); - if (this.doflickerfix() && interlace_seen > 0) - this.hsync_scandoubler(); - }; - - this.hsync_handler_pre_next_vpos = function (onvsync) { - if (this.is_linetoggle()) - this.lol ^= 1; - else - this.lol = 0; + } - this.vpos++; - this.vpos_count++; - if (this.vpos >= this.maxvpos_total) - this.vpos = 0; - if (onvsync) { - this.vpos = 0; - //vsync_counter++; - } - this.maxhpos = this.maxhpos_short + this.lol; - }; - - this.hsync_handler_post = function () { - if (this.vpos == equ_vblank_endline + 1) { - //if (this.lof_current != this.lof_store) {} - if (this.lof_store != this.lof_previous) { - if (lof_togglecnt_lace < LOF_TOGGLES_NEEDED) - lof_togglecnt_lace++; - if (lof_togglecnt_lace >= LOF_TOGGLES_NEEDED) - lof_togglecnt_nlace = 0; - } else { - if (lof_togglecnt_nlace < LOF_TOGGLES_NEEDED) - lof_togglecnt_nlace++; - if (lof_togglecnt_nlace >= LOF_TOGGLES_NEEDED) - lof_togglecnt_lace = 0; + // vsync functions that are not hardware timing related + function vsync_handler_pre() { + if (SAEV_Events_bogusframe > 0) SAEV_Events_bogusframe--; + + /*while (handle_events()) { + // we are paused, do all config checks but don't do any emulation + if (vsync_handle_check()) { + redraw_frame(); + SAER.video.render_screen(true); + SAER.video.show_screen(0); } - this.lof_previous = this.lof_store; + config_check_vsync(); + }*/ + + if (SAEV_command > 0) { + //prevent possible infinite loop at wait_cycles() + framecnt = 0; + reset_decisions(); + return; } - }; - - this.hsync_handler_post_nextline_how = function () { - var lineno = this.vpos; - if (lineno >= MAXVPOS) - lineno %= MAXVPOS; - nextline_how = NLN_NORMAL; - if (this.doflickerfix() && interlace_seen > 0) - lineno *= 2; - else if (AMIGA.config.video.vresolution && (doublescan <= 0 || interlace_seen > 0)) { - lineno *= 2; - nextline_how = AMIGA.config.video.vresolution > VRES_NONDOUBLE && AMIGA.config.video.scanlines == false ? NLN_DOUBLED : NLN_NBLACK; - if (interlace_seen) { - if (!this.lof_current) { - lineno++; - nextline_how = NLN_LOWER; - } else { - nextline_how = NLN_UPPER; + + //config_check_vsync(); + + if (timehack_alive > 0) timehack_alive--; + + SAER.devices.vsync_pre(); + + /*#ifdef PICASSO96 + if (isvsync_rtg() >= 0) + rtg_vsync(); + #endif*/ + + if (!vsync_rendered) { + var start = SAEF_now(); + vsync_handle_redraw(lof_store, lof_changed, bplcon0, bplcon3); + vsync_rendered = true; + SAEV_Events_frameskiptime += SAEF_now() - start; + } + + var frameok = SAER.events.framewait(); + + if (!SAEV_Playfield_picasso_on) { + if (!SAEV_Playfield_frame_rendered && vblank_hz_state) + SAEV_Playfield_frame_rendered = SAER.video.render_screen(false); + if (SAEV_Playfield_frame_rendered && !SAEV_Playfield_frame_shown) + SAEV_Playfield_frame_shown = SAER.video.show_screen_maybe(isvsync_chipset() >= 0); + } + + SAER.events.fpscounter(frameok); + + vsync_rendered = false; + SAEV_Playfield_frame_shown = false; + SAEV_Playfield_frame_rendered = false; + + if (vblank_hz_mult > 0) + vblank_hz_state ^= 1; + else + vblank_hz_state = 1; + + vsync_handle_check(); + + /*#if 0 + checklacecount (bplcon0_interlace_seen || lof_lace); + #endif*/ + } + + // emulated hardware vsync + function vsync_handler_post() { + /*static frame_time_t prevtime; + SAEF_log("playfield.vsync_handler_post() %d %d %d", vsynctimebase, SAEF_now () - vsyncmintime, SAEF_now () - prevtime); + var prevtime = SAEF_now();*/ + + //if ((SAEV_Custom_intreq & 0x0020) && (SAEV_Custom_intena & 0x0020)) SAEF_warn("playfield.vsync_handler_post() vblank interrupt not cleared"); + + SAER.disk.vsync(); + + if (bplcon0 & 4) { + lof_store = lof_store ? 0 : 1; + } + if ((bplcon0 & 2) && SAEV_config.chipset.genlock) { + genlockvtoggle = lof_store ? 1 : 0; + } + + if (lof_prev_lastline != lof_lastline) { + if (lof_togglecnt_lace < LOF_TOGGLES_NEEDED) + lof_togglecnt_lace++; + if (lof_togglecnt_lace >= LOF_TOGGLES_NEEDED) + lof_togglecnt_nlace = 0; + } else { + // only 1-2 vblanks with bplcon0 lace bit set? + // lets check if lof has changed + if (!(bplcon0 & 4) && lof_togglecnt_lace > 0 && lof_togglecnt_lace < LOF_TOGGLES_NEEDED && !interlace_seen) { + lof_changed = 1; + } + lof_togglecnt_nlace = LOF_TOGGLES_NEEDED; + lof_togglecnt_lace = 0; + /*#if 0 + if (lof_togglecnt_nlace < LOF_TOGGLES_NEEDED) + lof_togglecnt_nlace++; + if (lof_togglecnt_nlace >= LOF_TOGGLES_NEEDED) + lof_togglecnt_lace = 0; + #endif*/ + } + lof_prev_lastline = lof_lastline; + lof_current = lof_store; + if (lof_togglecnt_lace >= LOF_TOGGLES_NEEDED) { + interlace_changed = notice_interlace_seen(true); + if (interlace_changed) { + notice_screen_contents_lost(); + } + } else if (lof_togglecnt_nlace >= LOF_TOGGLES_NEEDED) { + interlace_changed = notice_interlace_seen(false); + if (interlace_changed) { + notice_screen_contents_lost(); + } + } + if (lof_changing) { + // still same? Trigger change now. + if ((!lof_store && lof_changing < 0) || (lof_store && lof_changing > 0)) { + lof_changed_previous_field++; + lof_changed = 1; + // lof toggling? decide as interlace. + if (lof_changed_previous_field >= LOF_TOGGLES_NEEDED) { + lof_changed_previous_field = LOF_TOGGLES_NEEDED; + if (lof_lace == false) + lof_lace = true; + else + lof_changed = 0; + } + if (bplcon0 & 4) + lof_changed = 0; + } + lof_changing = 0; + } else { + lof_changed_previous_field = 0; + lof_lace = false; + } + + /*#ifdef PICASSO96 + if (p96refresh_active) { + vpos_count = p96refresh_active; + vtotal = vpos_count; + } + #endif*/ + + SAER.devices.vsync_post(); + + if (varsync_changed || (beamcon0 & (0x10 | 0x20 | 0x80 | 0x100 | 0x200)) != (new_beamcon0 & (0x10 | 0x20 | 0x80 | 0x100 | 0x200))) + init_hz_normal(); + else if (vpos_count > 0 && Math.abs(vpos_count - vpos_count_diff) > 1 && vposw_change < 4) + init_hz_vposw(); + else if (interlace_changed || changed_chipset_refresh() || lof_changed) + compute_framesync(); + + lof_changed = 0; + vposw_change = 0; + bplcon0_interlace_seen = false; + + SAER.copper.COPJMP(1, 1); + + init_hardware_frame(); + } + + /*function copper_check(n) { + const COP_wait = 8; + if (SAER_Copper_cop_state.state == COP_wait) { + var vp = vpos & (((SAER_Copper_cop_state.saved_i2 >> 8) & 0x7F) | 0x80); + if (vp < SAER_Copper_cop_state.vcmp) { + if (SAEV_Copper_enabled_thisline) + SAEF_error("playfield.copper_check() bug %d: vp=%d vpos=%d vcmp=%d thisline=%d", n, vp, vpos, SAER_Copper_cop_state.vcmp, SAEV_Copper_enabled_thisline); + } + } + }*/ + + // OPT inline + function set_hpos() { + maxhpos = maxhpos_short + lol; + hpos_offset = 0; + SAER_Events_eventtab[SAEC_Events_EV_HSYNC].evtime = SAEV_Events_currcycle + maxhpos * SAEC_Events_CYCLE_UNIT; //HSYNCTIME(); + SAER_Events_eventtab[SAEC_Events_EV_HSYNC].oldcycles = SAEV_Events_currcycle; + } + + // this finishes current line + function hsync_handler_pre(onvsync) { + var hpos = SAER.events.current_hpos(); + + if (!nocustom()) { + SAER.copper.sync_copper_with_cpu(maxhpos, 0); + + const COP_read2 = 3; + // Seven Seas scrolling quick fix hack checks if copper is going to modify BPLCON1 in next cycle. + if (SAEV_Copper_enabled_thisline && SAER_Copper_cop_state.state == COP_read2 && (SAER_Copper_cop_state.i1 & 0x1fe) == 0x102) { + // it did, pre-load value for Denise shifter emulation + hpos_is_zero_bplcon1_hack = SAER_Memory_chipGet16_indirect(SAER_Copper_cop_state.ip); + // following finish_decision() is going to finish this line it is too late when copper actually does the move + } + + finish_decisions(); + if (thisline_decision.plfleft >= 0) { + if (SAEV_config.chipset.colLevel > SAEC_Config_Chipset_ColLevel_Sprite_Sprite) + do_sprite_collisions(); + if (SAEV_config.chipset.colLevel > SAEC_Config_Chipset_ColLevel_Sprite_Playfield) + do_playfield_collisions(); + } + hsync_record_line_state(next_lineno, nextline_how, thisline_changed); + // reset light pen latch + if (vpos == sprite_vblank_endline) { + lightpen_triggered = 0; + sprite_0 = 0; + } + if (lightpen_enabled && lightpen_cx > 0 && (bplcon0 & 8) && !lightpen_triggered && lightpen_cy == vpos) { + vpos_lpen = vpos; + hpos_lpen = lightpen_cx; + lightpen_triggered = 1; + } + hardware_line_completed(next_lineno); + if (doflickerfix() && interlace_seen > 0) + hsync_scandoubler(); + + notice_resolution_seen(GET_RES_AGNUS(bplcon0), interlace_seen != 0); + } + + SAER.devices.hsync(onvsync); + + SAEV_Events_hsync_counter++; + + //refptr += 0x0200 * 4; + //refptr_val += 0x0200 * 4; + refptr += 0x0800; if (refptr > 0xffff) refptr -= 0x10000; + refptr_val += 0x0800; if (refptr_val > 0xffffffff) refptr_val -= 0x100000000; + + if (islinetoggle()) + lol ^= 1; + else + lol = 0; + + vpos++; + vpos_count++; + if (vpos >= maxvpos_total) + vpos = 0; + if (onvsync) { + vpos = 0; + SAEV_Events_vsync_counter++; + } + + set_hpos(); + /*{ + maxhpos = maxhpos_short + lol; + hpos_offset = 0; + SAER_Events_eventtab[SAEC_Events_EV_HSYNC].evtime = SAEV_Events_currcycle + maxhpos * SAEC_Events_CYCLE_UNIT; //HSYNCTIME(); + SAER_Events_eventtab[SAEC_Events_EV_HSYNC].oldcycles = SAEV_Events_currcycle; + }*/ + } + + function is_last_line() { + return vpos + 1 == maxvpos + lof_store; + } + + // this prepares for new line + var cia_hsync = 0; //int + function hsync_handler_post(onvsync) { + SAEV_Copper_last_hpos = 0; + + //#ifdef CPUEMU_13 + //if (SAEV_config.chipset.blitter.cycle_exact) + // SAER_Events_cycle_line.clr(); + //#endif + + // genlock active: + // vertical: interlaced = toggles every other field, non-interlaced = both fields (normal) + // horizontal: PAL = every line, NTSC = every other line + genlockhtoggle = !genlockhtoggle; + var ciahsyncs = !(bplcon0 & 2) || ((bplcon0 & 2) && SAEV_config.chipset.genlock && (!SAEV_config.chipset.ntsc || genlockhtoggle)); + var ciavsyncs = !(bplcon0 & 2) || ((bplcon0 & 2) && SAEV_config.chipset.genlock && genlockvtoggle); + + SAER.cia.hsync_post(ciahsyncs); + if (ciahsyncs) { + if (beamcon0 & (0x80 | 0x100)) { + if (hsstop < (maxhpos & ~1) && hsstrt < maxhpos) + SAER.cia.b_tod_handler(hsstop); + } else + SAER.cia.b_tod_handler(18); + } + if (SAEV_config.chipset.cia.tod != SAEC_Config_Chipset_CIA_TOD_VSync) { + /*#if 0 + static uae_s32 oldtick; + uae_s32 tick = read_system_time (); // milliseconds + int ms = 1000 / (SAEV_config.chipset.cia.tod == SAEC_Config_Chipset_CIA_TOD_60Hz ? 60 : 50); + if (tick - oldtick > 2000 || tick - oldtick < -2000) { + oldtick = tick - ms; + } + if (tick - oldtick >= ms) { + CIA_vsync_posthandler(1); + oldtick += ms; + } + #else*/ + //static int cia_hsync; + if (cia_hsync < maxhpos) { + SAER.cia.a_tod_inc(cia_hsync); + var newcount = (vblank_hz * (2 * maxvpos + (interlace_seen ? 1 : 0)) * (2 * maxhpos + (islinetoggle() ? 1 : 0))) / ((SAEV_config.chipset.cia.tod == SAEC_Config_Chipset_CIA_TOD_60Hz ? 60 : 50) * 4) >>> 0; + cia_hsync += newcount; + } else + cia_hsync -= maxhpos; + //#endif + } else if (SAEV_config.chipset.cia.tod == SAEC_Config_Chipset_CIA_TOD_VSync && ciavsyncs) { + // CIA-A TOD counter increases when vsync pulse ends + if (beamcon0 & (0x80 | 0x200)) { + if (vpos == vsstop && vsstrt <= maxvpos) + SAER.cia.a_tod_inc(lof_store ? hsstop : hsstop + hcenter); + } else { + if (vpos == (SAEV_config.chipset.ntsc ? VSYNC_ENDLINE_NTSC : VSYNC_ENDLINE_PAL)) { + SAER.cia.a_tod_inc(lof_store ? 132 : 18); } } } - prev_lineno = next_lineno; - next_lineno = lineno; - this.reset_decisions(); - plfstrt_sprite = plfstrt; - }; - - this.hsync_handler_post_diw_change = function () { - if (GET_PLANES(bplcon0) > 0 && AMIGA.dmaen(DMAF_BPLEN)) { - if (this.vpos > last_planes_vpos) - last_planes_vpos = this.vpos; - if (this.vpos >= minfirstline && first_planes_vpos == 0) - first_planes_vpos = this.vpos > minfirstline ? this.vpos - 1 : this.vpos; - else if (this.vpos >= this.current_maxvpos() - 1) - last_planes_vpos = this.current_maxvpos(); + //inputdevice_hsync(); + + if (!nocustom()) { + if (!SAEV_config.chipset.blitter.cycle_exact && SAEV_Blitter_bltstate != SAEC_Blitter_bltstate_DONE && SAEF_Custom_dmaen(SAEC_Custom_DMAF_BPLEN) && diwstate == DIW_WAITING_STOP) { + SAER.blitter.blitter_slowdown(thisline_decision.plfleft, thisline_decision.plfright - (16 << fetchmode), + cycle_diagram_total_cycles[fetchmode][GET_RES_AGNUS(bplcon0)][GET_PLANES_LIMIT(bplcon0)], + cycle_diagram_free_cycles[fetchmode][GET_RES_AGNUS(bplcon0)][GET_PLANES_LIMIT(bplcon0)]); + } + } + + if (onvsync) { + // vpos_count >= MAXVPOS just to not crash if VPOSW writes prevent vsync completely + if ((bplcon0 & 8) && !lightpen_triggered) { + vpos_lpen = vpos - 1; + hpos_lpen = maxhpos; + lightpen_triggered = 1; + } + vpos = 0; + vsync_handler_post(); + vpos_count = 0; + } + // A1000 DIP Agnus (8361): vblank interrupt is triggered on line 1! + if (SAEV_config.chipset.agnusDIP) { + if (vpos == 1) + SAER.custom.send_interrupt(SAEC_Custom_INTF_VERTB, 1 * SAEC_Events_CYCLE_UNIT); + } else { + if (vpos == 0) + SAER.custom.send_interrupt(SAEC_Custom_INTF_VERTB, 1 * SAEC_Events_CYCLE_UNIT); + } + + // lastline - 1? + if (vpos + 1 == maxvpos + lof_store || vpos + 1 == maxvpos + lof_store + 1) + lof_lastline = lof_store != 0; + + //#ifdef CPUEMU_13 + /*if (SAEV_config.chipset.blitter.cycle_exact) { + var hp = maxhpos - 1; + for (var i = 0; i < 4; i++) { + SAER.events.alloc_cycle(hp, i == 0 ? SAEC_Events_cycle_line_STROBE : SAEC_Events_cycle_line_REFRESH); + hp += 2; + if (hp >= maxhpos) + hp -= maxhpos; + } + }*/ + //#endif + + SAER.events.events_dmal_hsync(); + + /*#if 0 + // AF testing stuff + static int cnt = 0; + cnt++; + if (cnt == 500) { + int port_insert_custom (int inputmap_port, int devicetype, DWORD flags, const TCHAR *custom); + //port_insert_custom (0, 2, 0, "Left=0xCB Right=0xCD Up=0xC8 Down=0xD0 Fire=0x39 Fire.autorepeat=0xD2"); + port_insert_custom (1, 2, 0, "Left=0x1E Right=0x20 Up=0x11 Down=0x1F Fire=0x38"); + } else if (0 && cnt == 1000) { + TCHAR out[256]; + bool port_get_custom (int inputmap_port, TCHAR *out); + port_get_custom (0, out); + port_get_custom (1, out); + } + #endif*/ + + if (SAEV_config.cpu.speed < 0) + SAER.events.framewait2_maximum(is_last_line()); + else { + if (vpos + 1 < maxvpos + lof_store && (vpos == (maxvpos_display * 1 / 3) >>> 0 || vpos == (maxvpos_display * 2 / 3) >>> 0)) + SAER.events.framewait2_normal(); + } + + if (!nocustom()) { + var lineno = vpos; + if (lineno >= MAXVPOS) + lineno %= MAXVPOS; + nextline_how = nln_normal; + if (doflickerfix() && interlace_seen > 0) { + lineno *= 2; + } else if (!interlace_seen && doublescan <= 0 && SAEV_config.video.vresolution && SAEV_config.video.pscanlines > 1) { + lineno *= 2; + if (SAEV_Events_timeframes & 1) { + lineno++; + nextline_how = SAEV_config.video.pscanlines == 3 ? nln_lower_black_always : nln_lower_black; + } else { + nextline_how = SAEV_config.video.pscanlines == 3 ? nln_upper_black_always : nln_upper_black; + } + } else if ((doublescan <= 0 || interlace_seen > 0) && SAEV_config.video.vresolution && SAEV_config.video.iscanlines) { + lineno *= 2; + if (interlace_seen) { + if (!lof_current) { + lineno++; + nextline_how = SAEV_config.video.iscanlines == 2 ? nln_lower_black_always : nln_lower_black; + } else { + nextline_how = SAEV_config.video.iscanlines == 2 ? nln_upper_black_always : nln_upper_black; + } + } else { + nextline_how = SAEV_config.video.vresolution > SAEC_Config_Video_VResolution_NonDouble && SAEV_config.video.pscanlines == 1 ? nln_nblack : nln_doubled; + } + } else if (SAEV_config.video.vresolution && (doublescan <= 0 || interlace_seen > 0)) { + lineno *= 2; + if (interlace_seen) { + if (!lof_current) { + lineno++; + nextline_how = nln_lower; + } else { + nextline_how = nln_upper; + } + } else { + nextline_how = SAEV_config.video.vresolution > SAEC_Config_Video_VResolution_NonDouble && SAEV_config.video.pscanlines == 1 ? nln_nblack : nln_doubled; + } + } + prev_lineno = next_lineno; + next_lineno = lineno; + reset_decisions(); + } + + /* Default to no bitplane DMA overriding sprite DMA */ + plfstrt_sprite = 0xff; + /* See if there"s a chance of a copper wait ending this line. */ + SAER_Copper_cop_state.hpos = 0; + SAER.copper.compute_spcflag_copper(maxhpos); + //copper_check(2); + + if (GET_PLANES (bplcon0) > 0 && SAEF_Custom_dmaen(SAEC_Custom_DMAF_BPLEN)) { + if (first_bplcon0 == 0) + first_bplcon0 = bplcon0; + if (vpos > last_planes_vpos) + last_planes_vpos = vpos; + if (vpos >= minfirstline && first_planes_vpos == 0) { + first_planes_vpos = vpos > minfirstline ? vpos - 1 : vpos; + } else if (vpos >= current_maxvpos() - 1) { + last_planes_vpos = current_maxvpos(); + } } if (diw_change == 0) { - if (this.vpos >= first_planes_vpos && this.vpos <= last_planes_vpos) { + if (vpos >= first_planes_vpos && vpos <= last_planes_vpos) { if (diwlastword > diwlastword_total) { diwlastword_total = diwlastword; if (diwlastword_total > coord_diw_to_window_x(hsyncstartpos * 2)) @@ -6187,135 +9768,10270 @@ function Playfield() { if (plfstop + 2 * f > ddflastword_total + 2 * f) ddflastword_total = plfstop + 2 * f; } - if ((plffirstline < plffirstline_total || (plffirstline_total == minfirstline && this.vpos > minfirstline)) && plffirstline < (this.vpos >> 1)) { + if ((plffirstline < plffirstline_total || (plffirstline_total == minfirstline && vpos > minfirstline)) && plffirstline < vpos >> 1) { //ORG / 2 firstword_bplcon1 = bplcon1; if (plffirstline < minfirstline) plffirstline_total = minfirstline; else plffirstline_total = plffirstline; } - if (plflastline > plflastline_total && plflastline > plffirstline_total && plflastline > (this.maxvpos >> 1)) + if (plflastline > plflastline_total && plflastline > plffirstline_total && plflastline > maxvpos >> 1) //ORG / 2 plflastline_total = plflastline; } if (diw_change > 0) diw_change--; - }; - - /*---------------------------------*/ - this.getDiwstate = function () { - return diwstate; - }; - - this.getData = function () { - return [ - thisline_decision.plfleft, - thisline_decision.plfright - (16 << fetchmode), - cycle_diagram_total_cycles[fetchmode][GET_RES_AGNUS(bplcon0)][GET_PLANES_LIMIT(bplcon0)], - cycle_diagram_free_cycles[fetchmode][GET_RES_AGNUS(bplcon0)][GET_PLANES_LIMIT(bplcon0)] - ]; - }; - - /*---------------------------------*/ - - this.setup = function () { - if (cycle_diagram_table === null) - create_cycle_diagram_table(); - - if (AMIGA.video.available == 1) - alloc_colors64k(4, 4, 4, 8, 4, 0, 0, 0, 0, 0); - else - alloc_colors64k(5, 6, 5, 11, 5, 0, 0, 0, 0, 0); - - notice_new_xcolors(); - - this.setup_drawing(); - this.setup_sprites(); - }; - - this.cleanup = function () { - this.cleanup_sprites(); - this.cleanup_drawing(); - }; - - this.reset = function() { - /*lightpen_active = -1; - lightpen_triggered = 0; - lightpen_cx = lightpen_cy = -1;*/ - - update_mirrors(); - - if (!aga_mode) { - for (i = 0; i < 32; i++) { - current_colors.color_regs_ecs[i] = 0; - current_colors.acolors[i] = getxcolor(0); - } -/*#ifdef AGA - } else { - for (i = 0; i < 256; i++) { - current_colors.color_regs_aga[i] = 0; - current_colors.acolors[i] = getxcolor(0); - } -#endif*/ + /* fastest possible + last line and no vflip wait: render the frame as early as possible */ + if (is_last_line() && isvsync_chipset() <= -2 && !vsync_rendered && SAEV_config.video.apmode[0].gfx_vflip == 0) { + var start = SAEF_now(); + vsync_handle_redraw(lof_store, lof_changed, bplcon0, bplcon3); + vsync_rendered = true; + if (vblank_hz_state) + SAEV_Playfield_frame_rendered = SAER.video.render_screen(true); + SAEV_Events_frameskiptime += SAEF_now() - start; } - clxdat = 0; + //rtg_vsynccheck(); + } - /* Clear the armed flags of all sprites. */ - for (var i = 0; i < MAX_SPRITES; i++) spr[i].clr(); + function is_custom_vsync() { + var vp = vpos + 1; + var vpc = vpos_count + 1; + /* Agnus vpos counter keeps counting until it wraps around if VPOSW writes put it past maxvpos */ + if (vp >= maxvpos_total) + vp = 0; + if (vp == maxvpos + lof_store || vp == maxvpos + lof_store + 1 || vpc >= MAXVPOS) { + /* vpos_count >= MAXVPOS just to not crash if VPOSW writes prevent vsync completely */ + return true; + } + return false; + } + this.hsync_handler = function() { + var vs = is_custom_vsync(); + hsync_handler_pre(vs); + if (vs) { + vsync_handler_pre(); + + /* OWN ATT break the mainloop every vsync for a javascript-reflow */ + SAEF_setSpcFlags(SAEC_spcflag_BRK); + } + hsync_handler_post(vs); + } + + /*-----------------------------------------------------------------------*/ + /* SECT diw */ + + function calcdiw() { + var hstrt = diwstrt & 0xFF; + var hstop = diwstop & 0xFF; + var vstrt = diwstrt >> 8; + var vstop = diwstop >> 8; + + // vertical in ECS Agnus + if (diwhigh_written && (SAEV_config.chipset.mask & SAEC_Config_Chipset_Mask_ECS_AGNUS)) { + vstrt |= (diwhigh & 7) << 8; + vstop |= ((diwhigh >> 8) & 7) << 8; + } else { + if ((vstop & 0x80) == 0) + vstop |= 0x100; + } + // horizontal in ECS Denise + if (diwhigh_written && (SAEV_config.chipset.mask & SAEC_Config_Chipset_Mask_ECS_DENISE)) { + hstrt |= ((diwhigh >> 5) & 1) << 8; + hstop |= ((diwhigh >> 13) & 1) << 8; + } else { + hstop += 0x100; + } + + diw_hstrt = hstrt; + diw_hstop = hstop; + + diwfirstword = coord_diw_to_window_x(hstrt); + diwlastword = coord_diw_to_window_x(hstop); + + if (diwfirstword >= diwlastword) { + diwfirstword = min_diwlastword; + diwlastword = max_diwlastword(); + } + if (diwfirstword < min_diwlastword) + diwfirstword = min_diwlastword; + + if (vstrt == vpos && vstop != vpos && diwstate == DIW_WAITING_START) { + // This may start BPL DMA immediately. + line_cyclebased = 2; //SET_LINE_CYCLEBASED(); + bitplane_maybe_start_hpos = SAER.events.current_hpos(); + } + + plffirstline = vstrt; + plflastline = vstop; + + plfstrt = ddfstrt - DDF_OFFSET; + plfstop = ddfstop - DDF_OFFSET; + + diw_change = 2; + } + + /* playfield code */ + /*-----------------------------------------------------------------------*/ + /*-----------------------------------------------------------------------*/ + /*-----------------------------------------------------------------------*/ + /* SECT playfield read reg */ + + /*this.DENISEID = function() { + if (SAEV_config.chipset.deniseRev >= 0) + return SAEV_config.chipset.deniseRev; + //#ifdef AGA + if (SAEV_config.chipset.mask & SAEC_Config_Chipset_Mask_AGA) { + if (SAEV_config.chipset.ide == SAEC_Config_Chipset_IDE_A4000) + return 0xFCF8; + return 0x00F8; + } + //#endif + if (SAEV_config.chipset.mask & SAEC_Config_Chipset_Mask_ECS_DENISE) + return 0xFFFC; + if (SAEV_config.cpu.model == SAEC_Config_CPU_Model_68000 && SAEV_config.cpu.compatible) + return false; + + return 0xFFFF; + }*/ + this.DENISEID = function() { + if (SAEV_config.chipset.deniseRev >= 0) + return SAEV_config.chipset.deniseRev; + //#ifdef AGA + if (SAEV_config.chipset.mask & SAEC_Config_Chipset_Mask_AGA) { + if (SAEV_config.chipset.ide == SAEC_Config_Chipset_IDE_A4000) + return 0xFCF8; + return 0x00F8; + } + //#endif + return 0xFFFC; + } + + function islightpentriggered() { + if (beamcon0 & 0x2000) //LPENDIS + return false; + return lightpen_triggered > 0; + } + function issyncstopped() { + return (bplcon0 & 2) != 0 && !SAEV_config.chipset.genlock; + } + function GETVPOS() { + return islightpentriggered() ? vpos_lpen : (issyncstopped() ? vpos_previous : vpos); + } + function GETHPOS() { + return islightpentriggered() ? hpos_lpen : (issyncstopped() ? hpos_previous : SAER.events.current_hpos()); + } + + // fake changing hpos when rom genlock test runs and genlock is connected + function hsyncdelay() { + if (!SAEV_config.chipset.genlock) + return false; + if (SAEV_config.cpu.speed >= 0) + return false; + if (bplcon0 == 0x102) //(0x0100 | 0x0002)) + return true; + + return false; + } + + // DFF006 = 0.W must be valid result but better do this only in 68000 modes (whdload black screen!) + // HPOS is shifted by 3 cycles and VPOS increases when shifted HPOS==1 + //#define CPU_ACCURATE (SAEV_config.cpu.model < SAEC_Config_CPU_Model_68020) //OPT inline, ok + //#define HPOS_OFFSET (CPU_ACCURATE ? HPOS_SHIFT : 0) //OPT inline, ok + //#define VPOS_INC_DELAY (HPOS_OFFSET ? 1 : 0) //OPT inline, ok + + this.VPOSR = function() { + var csbit = 0; + var vp = GETVPOS(); + var hp = GETHPOS(); + var lof = lof_store; + + if (vp + 1 == maxvpos + lof_store && (hp == maxhpos - 1 || hp == maxhpos - 2)) { + // lof toggles 2 cycles before maxhpos, so do fake toggle here. + //if ((bplcon0 & 4) && CPU_ACCURATE) + if ((bplcon0 & 4) && cpu_accurate) + lof = lof ? 0 : 1; + } + //if (hp + HPOS_OFFSET >= maxhpos + VPOS_INC_DELAY) { //ORG + if (hp + (cpu_accurate ? HPOS_SHIFT : 0) >= maxhpos + (cpu_accurate ? 1 : 0)) { //OWN opt inline + vp++; + if (vp >= maxvpos + lof_store) + vp = 0; + } + vp = (vp >> 8) & 7; + + if (SAEV_config.chipset.agnusRev >= 0) { + csbit |= SAEV_config.chipset.agnusRev << 8; + } else { + //#ifdef AGA + csbit |= (SAEV_config.chipset.mask & SAEC_Config_Chipset_Mask_AGA) ? 0x2300 : 0; + //#endif + csbit |= (SAEV_config.chipset.mask & SAEC_Config_Chipset_Mask_ECS_AGNUS) ? 0x2000 : 0; + /*#if 0 //apparently "8372 (Fat-hr) (agnushr),rev 5" does not exist + if (SAEV_config.memory.chipSize > 1024 * 1024 && (SAEV_config.chipset.mask & SAEC_Config_Chipset_Mask_ECS_AGNUS)) + csbit |= 0x2100; + #endif*/ + if (SAEV_config.chipset.ntsc) + csbit |= 0x1000; + } + + if (!(SAEV_config.chipset.mask & SAEC_Config_Chipset_Mask_ECS_AGNUS)) + vp &= 1; + vp |= (lof ? 0x8000 : 0) | csbit; + if (SAEV_config.chipset.mask & SAEC_Config_Chipset_Mask_ECS_AGNUS) + vp |= lol ? 0x80 : 0; + + hsyncdelay(); + return vp; + } + this.VPOSW = function(v) { + var oldvpos = vpos; + + if (lof_store != ((v & 0x8000) ? 1 : 0)) { + lof_store = (v & 0x8000) ? 1 : 0; + lof_changing = lof_store ? 1 : -1; + } + if (SAEV_config.chipset.mask & SAEC_Config_Chipset_Mask_ECS_AGNUS) { + lol = (v & 0x0080) ? 1 : 0; + if (!islinetoggle()) + lol = 0; + } + if (lof_changing) + return; + vpos &= 0x00ff; + v &= 7; + if (!(SAEV_config.chipset.mask & SAEC_Config_Chipset_Mask_ECS_AGNUS)) + v &= 1; + vpos |= v << 8; + + if (vpos != oldvpos) + vposw_change++; + if (vpos < oldvpos) + vpos = oldvpos; + } + + /*function vposback(oldvpos) { + if (SAER_Copper_cop_state.state == COP_wait && oldvpos == SAER_Copper_cop_state.vcmp) { + SAEV_Copper_enabled_thisline = 0; + SAEF_clrSpcFlags(SAEC_spcflag_COPPER); + } + }*/ + this.VHPOSW = function(v) { + var oldvpos = vpos; + var changed = false; + + /* This is not that easy, need to decouple denise and paula hpos counters + * from master counter. + * All this just to fix Upfront-CoolFridge Smooth Copper part.. + */ + /*#if 0 + if (oldhpos != newhpos) { + oldhpos = SAER.events.current_hpos(); + int newhpos = v & 0xff; + if (newhpos >= maxhpos) + newhpos = maxhpos - 1; + hpos_offset = newhpos - oldhpos; + //SAER_Events_eventtab[SAEC_Events_EV_HSYNC].evtime = SAEV_Events_currcycle + HSYNCTIME() - (newhpos * SAEC_Events_CYCLE_UNIT); + SAER_Events_eventtab[SAEC_Events_EV_HSYNC].evtime = SAEV_Events_currcycle + (maxhpos * SAEC_Events_CYCLE_UNIT) - (newhpos * SAEC_Events_CYCLE_UNIT); + SAER_Events_eventtab[SAEC_Events_EV_HSYNC].oldcycles = SAEV_Events_currcycle - newhpos * SAEC_Events_CYCLE_UNIT; + SAER.events.schedule(); + newhpos2 = SAER.events.current_hpos(); + #ifdef CPUEMU_13 + if (SAEV_config.chipset.blitter.cycle_exact) { + //memset(cycle_line + newhpos, 0, maxhpos - newhpos); + SAEF_memset(cycle_line,newhpos, 0, maxhpos - newhpos); + for (i = newhpos; i < maxhpos; i++) SAER_Events_cycle_line[i] = 0; + int hp = maxhpos - 1, i; + for (i = 0; i < 4; i++) { + SAER.events.alloc_cycle(hp, i == 0 ? SAEC_Events_cycle_line_STROBE : SAEC_Events_cycle_line_REFRESH); + hp += 2; + if (hp >= maxhpos) + hp -= maxhpos; + } + } + #endif + vposw_change++; + changed = true; + } + #endif*/ + + v >>= 8; + vpos &= 0xff00; + vpos |= v; + if (vpos != oldvpos && !changed) + vposw_change++; + if (vpos < oldvpos) + vpos = oldvpos; + else if (vpos < minfirstline && oldvpos < minfirstline) + vpos = oldvpos; + + /*#if 0 + if (vpos < oldvpos) vposback (oldvpos); + #endif*/ + } + + var vhposr_oldhp = 0; //u16 + this.VHPOSR = function() { + //static uae_u16 vhposr_oldhp; + var vp = GETVPOS(); + var hp = GETHPOS(); + + //hp += HPOS_OFFSET; //ORG + if (cpu_accurate) hp += HPOS_SHIFT; //OWN opt inline + if (hp >= maxhpos) { + hp -= maxhpos; + // vpos increases when hp==1, not when hp==0 + //if (hp >= VPOS_INC_DELAY) { //ORG + if (hp >= (cpu_accurate ? 1 : 0)) { //OWN opt inline + vp++; + if (vp >= maxvpos + lof_store) + vp = 0; + } + } + //if (HPOS_OFFSET) { //ORG + if (cpu_accurate) { //OWN opt inline + hp += 1; + if (hp >= maxhpos) + hp -= maxhpos; + } + + vp = (vp << 8) & 0xffff; + + if (hsyncdelay()) { + // fake continuously changing hpos in fastest possible modes + hp = vhposr_oldhp % maxhpos; + vhposr_oldhp++; + if (vhposr_oldhp > 0xffff) vhposr_oldhp = 0; //OWN handle overflow + } + + vp |= hp; + return vp; + } + + this.REFPTR = function(v) { + /*ECS Agnus: + b15 8000: R 040 + b14 4000: R 020 + b13 2000: R 010 + b12 1000: R 008 + b11 0800: R 004 + b10 0400: R 002 + b09 0200: R 001 + b08 0100: C 080 + b07 0080: C 040 + b06 0040: C 020 + b05 0020: C 010 + b04 0010: C 008 + b03 0008: C 004 + b02 0004: C 002 C 100 + b01 0002: C 001 R 100 + b00 0001: R 080 */ + + refptr = v; + refptr_val = (v & 0xfe00) | ((v & 0x01fe) >> 1); + if (v & 1) { + //refptr_val |= 0x80 << 9; + refptr_val = (refptr_val | 0x10000) >>> 0; + } + if (v & 2) { + //refptr_val |= 1; + //refptr_val |= 0x100 << 9; + refptr_val = (refptr_val | 0x20001) >>> 0; + } + if (v & 4) { + //refptr_val |= 2; + //refptr_val |= 0x100; + refptr_val = (refptr_val | 0x102) >>> 0; + } + } + + /* playfield read reg */ + /*-----------------------------------------------------------------------*/ + /*-----------------------------------------------------------------------*/ + /*-----------------------------------------------------------------------*/ + /* SECT playfield reg */ + + this.BEAMCON0 = function(v) { + //if (!(SAEV_config.chipset.mask & SAEC_Config_Chipset_Mask_ECS_AGNUS)) return; + if (v != new_beamcon0) { + new_beamcon0 = v; + if (v & ~0x20) { + SAEF_warn("playfield.BEAMCON0() write 0x%04x", v); + //dumpsync(); + } + } + calcdiw(); + } + + function varsync() { + //if (!(SAEV_config.chipset.mask & SAEC_Config_Chipset_Mask_ECS_AGNUS)) return; + /*#ifdef PICASSO96 + if (SAEV_Playfield_picasso_on && p96refresh_active) { + vtotal = p96refresh_active; + return; + } + #endif*/ + if (!(beamcon0 & 0x80)) + return; + varsync_changed = true; + } + this.HTOTAL = function(v) { if (htotal != v) { htotal = v & (MAXHPOS_ROWS - 1); varsync(); }} + this.HSSTOP = function(v) { if (hsstop != v) { hsstop = v & (MAXHPOS_ROWS - 1); varsync(); }} + this.HBSTRT = function(v) { if (hbstrt != v) { hbstrt = v & (MAXHPOS_ROWS - 1); varsync(); }} + this.HBSTOP = function(v) { if (hbstop != v) { hbstop = v & (MAXHPOS_ROWS - 1); varsync(); }} + this.VTOTAL = function(v) { if (vtotal != v) { vtotal = v & (MAXVPOS_LINES_ECS - 1); varsync(); }} + this.VSSTOP = function(v) { if (vsstop != v) { vsstop = v & (MAXVPOS_LINES_ECS - 1); varsync(); }} + this.VBSTRT = function(v) { if (vbstrt < v || vbstrt > (v & (MAXVPOS_LINES_ECS - 1)) + 1) { vbstrt = v & (MAXVPOS_LINES_ECS - 1); varsync(); }} + this.VBSTOP = function(v) { if (vbstop < v || vbstop > (v & (MAXVPOS_LINES_ECS - 1)) + 1) { vbstop = v & (MAXVPOS_LINES_ECS - 1); varsync(); }} + this.HSSTRT = function(v) { if (hsstrt != v) { hsstrt = v & (MAXHPOS_ROWS - 1); varsync(); }} + this.VSSTRT = function(v) { if (vsstrt != v) { vsstrt = v & (MAXVPOS_LINES_ECS - 1); varsync(); }} + this.HCENTER = function(v) { if (hcenter != v) { hcenter = v & (MAXHPOS_ROWS - 1); varsync(); }} + + /*#ifdef PICASSO96 + function set_picasso_hack_rate(hz) { //global + if (!SAEV_Playfield_picasso_on) + return; + vpos_count = 0; + p96refresh_active = (maxvpos_stored * vblank_hz_stored / hz) >>> 0; + if (SAEV_config.chipset.cia.tod == SAEC_Config_Chipset_CIA_TOD_VSync) + SAEV_config.chipset.cia.tod = SAEV_config.chipset.ntsc ? SAEC_Config_Chipset_CIA_TOD_60Hz : SAEC_Config_Chipset_CIA_TOD_50Hz; + if (p96refresh_active > 0) { + new_beamcon0 |= 0x80; + } + } + #endif*/ + + //"Dangerous" blitter D-channel: Writing to memory which is also currently read by bitplane DMA + this.dcheck_is_blit_dangerous = function() { + SAER.blitter.check_is_blit_dangerous(bplpt, bplcon0_planes, 50 << bplcon0_res); + } + + this.BPLxPTH = function(hpos, v, num) { + this.decide_line(hpos); + this.decide_fetch_safe(hpos); + if (SAEV_Copper_access && this.is_bitplane_dma(hpos + 1) == num + 1) { + /*#if 0 + if (this.is_bitplane_dma(hpos + 2)) { + dbplpth[num] = (v << 16) & 0xffff0000; + dbplpth_on[num] = hpos; + dbplpth_on2++; + } + #endif*/ + line_cyclebased = 2; //SET_LINE_CYCLEBASED(); + return; + } + bplpt[num] = ((bplpt[num] & 0x0000ffff) | (v << 16)) >>> 0; + bplptx[num] = ((bplptx[num] & 0x0000ffff) | (v << 16)) >>> 0; + this.dcheck_is_blit_dangerous(); + } + this.BPLxPTL = function(hpos, v, num) { + this.decide_line(hpos); + this.decide_fetch_safe(hpos); + /*#if 0 + reset_dbplh (hpos, num); + #endif*/ + + /* chipset feature: + * BPLxPTL write and next cycle doing DMA fetch using same pointer register -> + * next DMA cycle uses old value. + * (Multiscroll / Cult) + * + * If following cycle is not BPL DMA: written value is lost + * + * last fetch block does not have this side-effect, probably due to modulo adds. + * Also it seems only plane 0 fetches have this feature (because of above reason!) + * (MoreNewStuffy / PlasmaForce) + */ + /* only detect copper accesses to prevent too fast CPU mode glitches */ + if (SAEV_Copper_access && this.is_bitplane_dma(hpos + 1) == num + 1) { + /*#if 0 + if (num == 0 && plf_state >= plf_passed_stop) { + // modulo adds use old value! Argh! (This is wrong and disabled) + dbplptl[num] = v & 0x0000fffe; + dbplptl_on[num] = -1; + dbplptl_on2++; + } else if (this.is_bitplane_dma(hpos + 2)) { + dbplptl[num] = v & 0x0000fffe; + dbplptl_on[num] = hpos; + dbplptl_on2++; + } + #endif*/ + line_cyclebased = 2; //SET_LINE_CYCLEBASED(); + return; + } + bplpt[num] = ((bplpt[num] & 0xffff0000) | (v & 0x0000fffe)) >>> 0; + bplptx[num] = ((bplptx[num] & 0xffff0000) | (v & 0x0000fffe)) >>> 0; + this.dcheck_is_blit_dangerous(); + } + + function BPLCON0_Denise(hpos, v, immediate) { + if (!(SAEV_config.chipset.mask & SAEC_Config_Chipset_Mask_ECS_DENISE)) + v &= ~0x00F1; + else if (!(SAEV_config.chipset.mask & SAEC_Config_Chipset_Mask_AGA)) + v &= ~0x00B0; + v &= ~(0x0200 | 0x0100 | 0x0080 | 0x0020); + + /*#if SPRBORDER + v |= 1; + #endif*/ + if (bplcon0d == v && !immediate) + return; + + bplcon0dd = -1; + // fake unused 0x0080 bit as an EHB bit (see below) + if (isehb(bplcon0d, bplcon2)) + v |= 0x80; + if (immediate) + record_register_change(hpos, 0x100, v); + else + record_register_change(hpos, 0x100, (bplcon0d & ~(0x800 | 0x400 | 0x80)) | (v & (0x0800 | 0x400 | 0x80 | 0x01))); + + bplcon0d = v & ~0x80; + + //#ifdef ECS_DENISE + if (SAEV_config.chipset.mask & SAEC_Config_Chipset_Mask_ECS_DENISE) { + decide_sprites(hpos); + sprres = expand_sprres(v, bplcon3); + } + //#endif + if (thisline_decision.plfleft < 0) + update_denise(hpos); + else + update_denise_shifter_planes(hpos); + } + + this.BPLCON0 = function(hpos, v) { + if (!(SAEV_config.chipset.mask & SAEC_Config_Chipset_Mask_ECS_DENISE)) + v &= ~0x00F1; + else if (!(SAEV_config.chipset.mask & SAEC_Config_Chipset_Mask_AGA)) + v &= ~0x00B0; + v &= ~0x0080; + + /*#if SPRBORDER + v |= 1; + #endif*/ + if (bplcon0 == v) + return; + + line_cyclebased = 2; //SET_LINE_CYCLEBASED(); + decide_diw(hpos); + this.decide_line(hpos); + this.decide_fetch_safe(hpos); + + if (!issyncstopped()) { + vpos_previous = vpos; + hpos_previous = hpos; + } + if (bplcon0 & 4) + bplcon0_interlace_seen = true; + + bplcon0 = v; + + bpldmainitdelay(hpos); + + if (thisline_decision.plfleft < 0) + BPLCON0_Denise(hpos, v, true); + } + + this.BPLCON1 = function(hpos, v) { + if (!(SAEV_config.chipset.mask & SAEC_Config_Chipset_Mask_AGA)) + v &= 0xff; + if (bplcon1 == v) + return; + line_cyclebased = 2; //SET_LINE_CYCLEBASED(); + this.decide_line(hpos); + this.decide_fetch_safe(hpos); + bplcon1_written = true; + bplcon1 = v; + hack_shres_delay(hpos); + } + + this.BPLCON2 = function(hpos, v) { + if (!(SAEV_config.chipset.mask & SAEC_Config_Chipset_Mask_AGA)) + v &= 0x7f; + if ((bplcon2 & 0x3fff) == (v & 0x3fff)) + return; + this.decide_line(hpos); + bplcon2 = v; + record_register_change(hpos, 0x104, bplcon2); + } + + //#ifdef ECS_DENISE + this.BPLCON3 = function(hpos, v) { + //if (!(SAEV_config.chipset.mask & SAEC_Config_Chipset_Mask_ECS_DENISE)) return; + if (!(SAEV_config.chipset.mask & SAEC_Config_Chipset_Mask_AGA)) { + v &= 0x003f; + v |= 0x0c00; + } + /*#if SPRBORDER + v |= 2; + #endif*/ + if (bplcon3 == v) + return; + this.decide_line(hpos); + decide_sprites(hpos); + bplcon3 = v; + sprres = expand_sprres(bplcon0, bplcon3); + record_register_change(hpos, 0x106, v); + } + //#endif + //#ifdef AGA + this.BPLCON4 = function(hpos, v) { + //if (!(SAEV_config.chipset.mask & SAEC_Config_Chipset_Mask_AGA)) return; + if (bplcon4 == v) + return; + this.decide_line(hpos); + bplcon4 = v; + record_register_change(hpos, 0x10c, v); + } + //#endif + + function castWord(v) { //OWN ATT + return (v & 0x8000) ? (v - 0x10000) : v; + } + this.BPL1MOD = function(hpos, v) { + v &= ~1; + if (bpl1mod != castWord(v)) { + this.decide_line(hpos); + this.decide_fetch_safe(hpos); + } + // write to BPLxMOD one cycle before + // BPL fetch that also adds modulo: + // Old BPLxMOD value is added. + if (this.is_bitplane_dma(hpos + 1) & 1) { + dbpl1mod = castWord(v); + dbpl1mod_on = hpos + 1; + } else { + bpl1mod = castWord(v); + dbpl1mod_on = 0; + } + } + this.BPL2MOD = function(hpos, v) { + v &= ~1; + if (bpl2mod != castWord(v)) { + this.decide_line(hpos); + this.decide_fetch_safe(hpos); + } + if (this.is_bitplane_dma(hpos + 1) & 2) { + dbpl2mod = castWord(v); + dbpl2mod_on = hpos + 1; + } else { + bpl2mod = castWord(v); + dbpl2mod_on = 0; + } + } + + //Needed in special OCS/ECS "7-plane" mode, also handles CPU generated bitplane data + this.BPLxDAT = function(hpos, num, v) { + // only BPL1DAT access can do anything visible + if (num == 0 && hpos >= 8) { + this.decide_line(hpos); + this.decide_fetch_safe(hpos); + } + flush_display(fetchmode); + fetched[num] = v; + //fetched_aga[num] = v; + fetched_aga_hi[num] = 0; + fetched_aga_lo[num] = v; + if (num == 0 && hpos >= 8) { + bpl1dat_written = true; + bpl1dat_written_at_least_once = true; + if (thisline_decision.plfleft < 0) + reset_bpl_vars(); + beginning_of_plane_block(hpos, fetchmode); + } + } + + this.DIWSTRT = function(hpos, v) { + if (diwstrt == v && !diwhigh_written) + return; + decide_diw(hpos); + this.decide_line(hpos); + diwhigh_written = 0; + diwstrt = v; + calcdiw(); + } + this.DIWSTOP = function(hpos, v) { + if (diwstop == v && !diwhigh_written) + return; + decide_diw(hpos); + this.decide_line(hpos); + diwhigh_written = 0; + diwstop = v; + calcdiw(); + } + + this.DIWHIGH = function(hpos, v) { + //if (!(SAEV_config.chipset.mask & (SAEC_Config_Chipset_Mask_ECS_DENISE | SAEC_Config_Chipset_Mask_ECS_AGNUS))) return; + if (!(SAEV_config.chipset.mask & SAEC_Config_Chipset_Mask_AGA)) + v &= ~(0x0008 | 0x0010 | 0x1000 | 0x0800); + v &= ~(0x8000 | 0x4000 | 0x0080 | 0x0040); + if (diwhigh_written && diwhigh == v) + return; + this.decide_line(hpos); + diwhigh_written = 1; + diwhigh = v; + calcdiw(); + } + + this.DDFSTRT = function(hpos, v) { + v &= 0xfe; + if (!(SAEV_config.chipset.mask & SAEC_Config_Chipset_Mask_ECS_AGNUS)) + v &= 0xfc; + this.decide_line(hpos); + line_cyclebased = 2; //SET_LINE_CYCLEBASED(); + // Move state back to passed_enable if this DDFSTRT write was done exactly when + // it would match and start bitplane DMA. + if (hpos == ddfstrt - DDF_OFFSET && plf_state == plf_passed_start && plf_start_hpos == hpos + DDF_OFFSET) { + plf_state = plf_passed_enable; + plf_start_hpos = maxhpos; + } + ddfstrt = v; + calcdiw(); + if (fetch_state != fetch_not_started) + estimate_last_fetch_cycle(hpos); + + if (ddfstop > 0xD4 && (ddfstrt & 4) == 4) { + //static int last_warned; last_warned = (last_warned + 1) & 4095; if (last_warned == 0) + SAEF_warn("playfield.DDFSTRT() very strange DDF values (%x %x)", ddfstrt, ddfstop); + } + } + + this.DDFSTOP = function(hpos, v) { + v &= 0xfe; + if (!(SAEV_config.chipset.mask & SAEC_Config_Chipset_Mask_ECS_AGNUS)) + v &= 0xfc; + this.decide_line(hpos); + this.decide_fetch_safe(hpos); + line_cyclebased = 2; //SET_LINE_CYCLEBASED(); + // DDFSTOP write when old DDFSTOP value match: old value matches normally. + // Works differently than DDFSTRT which is interesting. + if (hpos == v - DDF_OFFSET) { + if (plf_state == plf_passed_stop && plf_end_hpos == hpos + DDF_OFFSET) { + plf_state = plf_active; + plf_end_hpos = 256 + DDF_OFFSET; + // don't let one_fetch_cycle_0() to do this again + ddfstop_written_hpos = hpos; + } + } else if (hpos == ddfstop - DDF_OFFSET) { + // if old ddfstop would have matched, emulate it here + if (plf_state == plf_active) { + plf_state = plf_passed_stop; + plf_end_hpos = hpos + DDF_OFFSET; + } + } + ddfstop = v; + calcdiw(); + if (fetch_state != fetch_not_started) + estimate_last_fetch_cycle(hpos); + + if (ddfstop > 0xD4 && (ddfstrt & 4) == 4) { + //static int last_warned; last_warned = (last_warned + 1) & 4095; if (last_warned == 0) + SAEF_warn("playfield.DDFSTOP() very strange DDF values (%x %x)", ddfstrt, ddfstop); + } + } + + this.FMODE = function(hpos, v) { + /*if (!(SAEV_config.chipset.mask & SAEC_Config_Chipset_Mask_AGA)) { + //if (currprefs.monitoremu) specialmonitor_store_fmode(vpos, hpos, v); + v = 0; + }*/ + v &= 0xC00F; + if (fmode == v) + return; + + line_cyclebased = 2; //SET_LINE_CYCLEBASED(); + fmode_saved = v; + set_chipset_mode(); + bpldmainitdelay(hpos); + } + + this.FNULL = function(v) {} + + /* playfield reg */ + + /*-----------------------------------------------------------------------*/ + /*-----------------------------------------------------------------------*/ + /*-----------------------------------------------------------------------*/ + /* SECT sprite reg */ + + function spr_arm(num, state) { + switch (state) { + case 0: + nr_armed -= spr[num].armed; + spr[num].armed = 0; + break; + default: + nr_armed += 1 - spr[num].armed; + spr[num].armed = 1; + } + } + + function sprstartstop(s) { + if (vpos < sprite_vblank_endline || cant_this_last_line() || s.ignoreverticaluntilnextline) + return; + if (vpos == s.vstart) + s.dmastate = 1; + if (vpos == s.vstop) + s.dmastate = 0; + } + + function SPRxCTLPOS(num) { + var sprxp; + var s = spr[num]; + + sprstartstop(s); + sprxp = (sprpos[num] & 0xFF) * 2 + (sprctl[num] & 1); + sprxp <<= sprite_buffer_res; + + //#ifdef AGA + if (SAEV_config.chipset.mask & SAEC_Config_Chipset_Mask_AGA) { + sprxp |= ((sprctl[num] >> 3) & 3) >> (RES_MAX - sprite_buffer_res); + s.dblscan = sprpos[num] & 0x80; + } + //#endif + //#ifdef ECS_DENISE + else if (SAEV_config.chipset.mask & SAEC_Config_Chipset_Mask_ECS_DENISE) { + sprxp |= ((sprctl[num] >> 3) & 2) >> (RES_MAX - sprite_buffer_res); + } + //#endif + s.xpos = sprxp; + s.vstart = sprpos[num] >> 8; + s.vstart |= (sprctl[num] & 0x04) ? 0x0100 : 0; + s.vstop = sprctl[num] >> 8; + s.vstop |= (sprctl[num] & 0x02) ? 0x100 : 0; + if (SAEV_config.chipset.mask & SAEC_Config_Chipset_Mask_ECS_AGNUS) { + s.vstart |= (sprctl[num] & 0x40) ? 0x0200 : 0; + s.vstop |= (sprctl[num] & 0x20) ? 0x0200 : 0; + } + sprstartstop(s); + } + + function SPRxCTL_1(v, num, hpos) { + if (hpos >= maxhpos - 2 && sprctl[num] != v && vpos < maxvpos - 1) { + var s = spr[num]; + vpos++; + sprstartstop(s); + vpos--; + s.ignoreverticaluntilnextline = true; + sprite_ignoreverticaluntilnextline = true; + } + sprctl[num] = v; + spr_arm(num, 0); + SPRxCTLPOS(num); + } + function SPRxPOS_1(v, num, hpos) { + if (hpos >= maxhpos - 2 && sprpos[num] != v && vpos < maxvpos - 1) { + var s = spr[num]; + vpos++; + sprstartstop(s); + vpos--; + s.ignoreverticaluntilnextline = true; + sprite_ignoreverticaluntilnextline = true; + } + sprpos[num] = v; + SPRxCTLPOS(num); + } + function SPRxDATA_1(v, num, hpos) { + sprdata[num][0] = v; + //#ifdef AGA + sprdata[num][1] = v; + sprdata[num][2] = v; + sprdata[num][3] = v; + //#endif + spr_arm(num, 1); + } + function SPRxDATB_1(v, num, hpos) { + sprdatb[num][0] = v; + //#ifdef AGA + sprdatb[num][1] = v; + sprdatb[num][2] = v; + sprdatb[num][3] = v; + //#endif + } + + /* + SPRxDATA and SPRxDATB is moved to shift register when SPRxPOS matches. + + When copper writes to SPRxDATx exactly when SPRxPOS matches: + - If sprite low x bit (SPRCTL bit 0) is not set, shift register copy + is done first (previously loaded SPRxDATx value is shown) and then + new SPRxDATx gets stored for future use. + - If sprite low x bit is set, new SPRxDATx is stored, then SPRxPOS + matches and value written to SPRxDATx is visible. + + - Writing to SPRxPOS when SPRxPOS matches: shift register + copy is always done first, then new SPRxPOS value is stored + for future use. (SPRxCTL not tested) + */ + + this.SPRxDATA = function(hpos, v, num) { + decide_sprites(hpos, true); + SPRxDATA_1(v, num, hpos); + } + this.SPRxDATB = function(hpos, v, num) { + decide_sprites(hpos, true); + SPRxDATB_1(v, num, hpos); + } + + this.SPRxCTL = function(hpos, v, num) { + decide_sprites(hpos); + SPRxCTL_1(v, num, hpos); + } + this.SPRxPOS = function(hpos, v, num) { + var s = spr[num]; + var oldvpos; + + decide_sprites(hpos); + oldvpos = s.vstart; + SPRxPOS_1(v, num, hpos); + // Superfrog flashing intro bees fix. + // if SPRxPOS is written one cycle before sprite"s first DMA slot and sprite"s vstart matches after + // SPRxPOS write, current line"s DMA slot"s stay idle. DMA decision seems to be done 4 cycles earlier. + if (hpos >= SPR0_HPOS + num * 4 - 4 && hpos <= SPR0_HPOS + num * 4 - 1 && oldvpos != vpos) { + s.ptxvpos2 = vpos; + s.ptxhpos2 = hpos + 4; + } + } + + this.SPRxPTH = function(hpos, v, num) { + decide_sprites(hpos); + if (hpos - 1 != spr[num].ptxhpos) { + //spr[num].pt &= 0xffff; + //spr[num].pt |= (uae_u32)v << 16; + spr[num].pt = ((v << 16) | (spr[num].pt & 0xffff)) >>> 0; + } + } + this.SPRxPTL = function(hpos, v, num) { + decide_sprites(hpos); + if (hpos - 1 != spr[num].ptxhpos) { + //spr[num].pt &= ~0xffff; + //spr[num].pt |= v & ~1; + spr[num].pt = ((spr[num].pt & 0xffff0000) | (v & 0xfffe)) >>> 0; + } + } + + this.CLXCON = function(v) { + clxcon = v; + clxcon_bpl_enable = (v >> 6) & 63; + clxcon_bpl_match = v & 63; + } + + this.CLXCON2 = function(v) { + //if (!(SAEV_config.chipset.mask & SAEC_Config_Chipset_Mask_AGA)) return; + clxcon2 = v; + clxcon_bpl_enable |= v & (0x40 | 0x80); + clxcon_bpl_match |= (v & (0x01 | 0x02)) << 6; + clxcon_bpl_match &= 0xffffffff; //OWN + } + + this.CLXDAT = function() { + var v = clxdat | 0x8000; + clxdat = 0; + return v; + } + + /* sprite reg */ + /*-----------------------------------------------------------------------*/ + /*-----------------------------------------------------------------------*/ + /*-----------------------------------------------------------------------*/ + /* SECT color reg */ + + //#ifdef AGA + /*function dump_aga_custom() { + var c1, c2, c3, c4; + var rgb1, rgb2, rgb3, rgb4; + + for (c1 = 0; c1 < 64; c1++) { + c2 = c1 + 64; + c3 = c2 + 64; + c4 = c3 + 64; + rgb1 = current_colors.color_regs_aga[c1]; + rgb2 = current_colors.color_regs_aga[c2]; + rgb3 = current_colors.color_regs_aga[c3]; + rgb4 = current_colors.color_regs_aga[c4]; + SAEF_log("playfield.dump_aga_custom() %3d %08X %3d %08X %3d %08X %3d %08X", c1, rgb1, c2, rgb2, c3, rgb3, c4, rgb4); + } + }*/ + + this.COLOR_READ = function(num) { + if (!(SAEV_config.chipset.mask & SAEC_Config_Chipset_Mask_AGA) || !(bplcon2 & 0x0100)) return 0xffff; + var colreg = ((bplcon3 >> 13) & 7) * 32 + num; + var cr = (current_colors.color_regs_aga[colreg] >> 16) & 0xFF; + var cg = (current_colors.color_regs_aga[colreg] >> 8) & 0xFF; + var cb = current_colors.color_regs_aga[colreg] & 0xFF; + var cval; + if (bplcon3 & 0x200) { + cval = ((cr & 15) << 8) | ((cg & 15) << 4) | ((cb & 15) << 0); + } else { + cval = ((cr >> 4) << 8) | ((cg >> 4) << 4) | ((cb >> 4) << 0); + if (color_regs_genlock[num]) + cval |= 0x8000; + } + return cval; + } + //#endif + + function checkautoscalecol0() { + if (!SAEV_Copper_access) + return; + if (vpos < 20) + return; + if (isbrdblank(-1, bplcon0, bplcon3)) + return; + // autoscale if copper changes COLOR00 on top or bottom of screen + if (vpos >= minfirstline) { + var vpos2 = autoscale_bordercolors ? minfirstline : vpos; + if (first_planes_vpos == 0) + first_planes_vpos = vpos2 - 2; + if (plffirstline_total == current_maxvpos()) + plffirstline_total = vpos2 - 2; + if (vpos2 > last_planes_vpos || vpos2 > plflastline_total) + plflastline_total = last_planes_vpos = vpos2 + 3; + autoscale_bordercolors = 0; + } else + autoscale_bordercolors++; + } + + this.COLOR_WRITE = function(hpos, v, num) { + var colzero = false; + //#ifdef AGA + if (SAEV_config.chipset.mask & SAEC_Config_Chipset_Mask_AGA) { + /* writing is disabled when RDRAM=1 */ + if (bplcon2 & 0x0100) + return; + + var colreg = ((bplcon3 >> 13) & 7) * 32 + num; + var r = (v & 0xF00) >> 8; + var g = (v & 0xF0) >> 4; + var b = (v & 0xF) >> 0; + var cr = (current_colors.color_regs_aga[colreg] >> 16) & 0xFF; + var cg = (current_colors.color_regs_aga[colreg] >> 8) & 0xFF; + var cb = current_colors.color_regs_aga[colreg] & 0xFF; + + if (bplcon3 & 0x200) { + cr &= 0xF0; cr |= r; + cg &= 0xF0; cg |= g; + cb &= 0xF0; cb |= b; + } else { + cr = r + (r << 4); + cg = g + (g << 4); + cb = b + (b << 4); + color_regs_genlock[colreg] = v >> 15; + } + var cval = ((cr << 16) | (cg << 8) | cb | (color_regs_genlock[colreg] ? 0x80000000 : 0)) >>> 0; + if (cval && colreg == 0) + colzero = true; + + if (cval == current_colors.color_regs_aga[colreg]) + return; + + if (colreg == 0) + checkautoscalecol0(); + + /* Call this with the old table still intact. */ + record_color_change(hpos, colreg, cval); + remembered_color_entry = -1; + current_colors.color_regs_aga[colreg] = cval; + current_colors.acolors[colreg] = getxcolor(cval); + } else { + //#endif + v &= 0x8fff; + if (!(SAEV_config.chipset.mask & SAEC_Config_Chipset_Mask_ECS_DENISE)) + v &= 0xfff; + color_regs_genlock[num] = v >> 15; + if (num && v == 0) + colzero = true; + if (current_colors.color_regs_ecs[num] == v) + return; + if (num == 0) + checkautoscalecol0(); + + /* Call this with the old table still intact. */ + record_color_change(hpos, num, v); + remembered_color_entry = -1; + current_colors.color_regs_ecs[num] = v; + current_colors.acolors[num] = getxcolor(v); + //#ifdef AGA + } + //#endif + } + + /* color reg */ + /*-----------------------------------------------------------------------*/ + /*-----------------------------------------------------------------------*/ + /*-----------------------------------------------------------------------*/ + /* SECT sprite do */ + + function cursorsprite() { + if (!SAEF_Custom_dmaen(SAEC_Custom_DMAF_SPREN) || first_planes_vpos == 0) + return; + sprite_0 = spr[0].pt; + sprite_0_height = spr[0].vstop - spr[0].vstart; + sprite_0_colors[0] = 0; + sprite_0_doubled = 0; + if (sprres == 0) + sprite_0_doubled = 1; + if (SAEV_config.chipset.mask & SAEC_Config_Chipset_Mask_AGA) { + var sbasecol = ((bplcon4 >> 4) & 15) << 4; + sprite_0_colors[1] = current_colors.color_regs_aga[sbasecol + 1]; + sprite_0_colors[2] = current_colors.color_regs_aga[sbasecol + 2]; + sprite_0_colors[3] = current_colors.color_regs_aga[sbasecol + 3]; + } else { + sprite_0_colors[1] = xcolors[current_colors.color_regs_ecs[17]]; + sprite_0_colors[2] = xcolors[current_colors.color_regs_ecs[18]]; + sprite_0_colors[3] = xcolors[current_colors.color_regs_ecs[19]]; + } + sprite_0_width = sprite_width; + /* OWN + if (currprefs.input_tablet && currprefs.input_magic_mouse) { + if (currprefs.input_magic_mouse_cursor == MAGICMOUSE_HOST_ONLY && mousehack_alive ()) + magic_sprite_mask &= ~1; + else + magic_sprite_mask |= 1; + }*/ + } + + function sprite_fetch(s, dma, hpos, cycle, mode) { + var data = SAEV_Custom_last_value & 0xffff; + if (dma) { + //if (cycle && cpu_cycle_exact) s.ptxhpos = hpos; + data = SAEV_Custom_last_value = SAER_Memory_chipGet16_indirect(s.pt); + //SAER.events.alloc_cycle(hpos, SAEC_Events_cycle_line_SPRITE); + } + s.pt += 2; + return data; + } + function sprite_fetch2(s, hpos, cycle, mode) { + var data = SAER_Memory_chipGet16_indirect(s.pt); + s.pt += 2; + return data; + } + + function do_sprites_1(num, cycle, hpos) { + var s = spr[num]; + var dma, posctl = 0; + var data; + // fetch both sprite pairs even if DMA was switched off between sprites + var isdma = SAEF_Custom_dmaen(SAEC_Custom_DMAF_SPREN) || ((num & 1) && spr[num & ~1].dmacycle); + + if (cant_this_last_line()) + return; + + /*#if 0 //see SPRxCTRL below + if (isdma && vpos == sprite_vblank_endline) + spr_arm (num, 0); + #endif*/ + + //#ifdef AGA + if (isdma && s.dblscan && (fmode & 0x8000) && (vpos & 1) != (s.vstart & 1) && s.dmastate) { + spr_arm(num, 1); + return; + } + //#endif + + if (vpos == s.vstart) { + s.dmastate = 1; + if (s.ptxvpos2 == vpos && hpos < s.ptxhpos2) + return; + if (num == 0 && cycle == 0) + cursorsprite(); + } + if (vpos == s.vstop || vpos == sprite_vblank_endline) { + s.dmastate = 0; + } + if (!isdma) + return; + + dma = hpos < plfstrt_sprite || diwstate != DIW_WAITING_STOP; + if (vpos == s.vstop || vpos == sprite_vblank_endline) { + s.dmastate = 0; + posctl = 1; + if (dma) { + data = sprite_fetch(s, dma, hpos, cycle, 0); + switch (sprite_width) { + case 64: + sprite_fetch2(s, hpos, cycle, 0); + sprite_fetch2(s, hpos, cycle, 0); + case 32: + sprite_fetch2(s, hpos, cycle, 0); + break; + } + if (cycle == 0) { + SPRxPOS_1(data, num, hpos); + s.dmacycle = 1; + } else { + // This is needed to disarm previous field"s sprite. + // It can be seen on OCS Agnus + ECS Denise combination where + // this cycle is disabled due to weird DDFTSTR=$18 copper list + // which causes corrupted sprite to "wrap around" the display. + SPRxCTL_1(data, num, hpos); + s.dmastate = 0; + sprstartstop(s); + } + } + if (vpos == sprite_vblank_endline) { + // s.vstart == sprite_vblank_endline won"t enable the sprite. + s.dmastate = 0; + } + } + if (s.dmastate && !posctl && dma) { + var data = sprite_fetch(s, dma, hpos, cycle, 1); + if (cycle == 0) { + SPRxDATA_1(data, num, hpos); + s.dmacycle = 1; + } else { + SPRxDATB_1(data, num, hpos); + spr_arm(num, 1); + } + //#ifdef AGA + switch (sprite_width) { + case 64: { + var data32 = sprite_fetch2(s, hpos, cycle, 1); + var data641 = sprite_fetch2(s, hpos, cycle, 1); + var data642 = sprite_fetch2(s, hpos, cycle, 1); + if (dma) { + if (cycle == 0) { + sprdata[num][3] = data642; + sprdata[num][2] = data641; + sprdata[num][1] = data32; + } else { + sprdatb[num][3] = data642; + sprdatb[num][2] = data641; + sprdatb[num][1] = data32; + } + } + break; + } + case 32: { + var data32 = sprite_fetch2(s, hpos, cycle, 1); + if (dma) { + if (cycle == 0) + sprdata[num][1] = data32; + else + sprdatb[num][1] = data32; + } + break; + } + } + //#endif + } + } + + function do_sprites(hpos) { + if (vpos < sprite_vblank_endline) + return; + + if (doflickerfix() && interlace_seen && (next_lineno & 1)) + return; + + var maxspr = hpos; + var minspr = last_sprite_hpos + 1; + + if (minspr >= maxspr || last_sprite_hpos == hpos) + return; + + if (maxspr >= SPR0_HPOS + MAX_SPRITES * 4) + maxspr = SPR0_HPOS + MAX_SPRITES * 4 - 1; + if (minspr < SPR0_HPOS) + minspr = SPR0_HPOS; + + if (minspr == maxspr) + return; + + for (var i = minspr; i <= maxspr; i++) { + var cycle = -1; + var num = (i - SPR0_HPOS) >> 2; //ORG / 4 + + switch ((i - SPR0_HPOS) & 3) { + case 0: + cycle = 0; + spr[num].dmacycle = 0; + break; + case 2: + cycle = 1; + break; + } + if (cycle >= 0) { + spr[num].ptxhpos = MAXHPOS; + do_sprites_1(num, cycle, i); + } + } + last_sprite_hpos = hpos; + } + + function setup_sprites() { //ORG gen_custom_tables() + var i; + + if (sprtaba !== null) + return; + + sprtaba = new Uint32Array(256); + sprtabb = new Uint32Array(256); + sprite_ab_merge = new Uint32Array(256); + for (i = 0; i < 256; i++) { + sprtaba[i] = ((((i >> 7) & 1) << 0) + | (((i >> 6) & 1) << 2) + | (((i >> 5) & 1) << 4) + | (((i >> 4) & 1) << 6) + | (((i >> 3) & 1) << 8) + | (((i >> 2) & 1) << 10) + | (((i >> 1) & 1) << 12) + | (((i >> 0) & 1) << 14)); + sprtabb[i] = sprtaba[i] * 2; + sprite_ab_merge[i] = (((i & 15) ? 1 : 0) | ((i & 240) ? 2 : 0)); + } + + sprclx = new Uint32Array(16); + clxmask = new Uint32Array(16); + for (i = 0; i < 16; i++) { + clxmask[i] = (((i & 1) ? 0xF : 0x3) + | ((i & 2) ? 0xF0 : 0x30) + | ((i & 4) ? 0xF00 : 0x300) + | ((i & 8) ? 0xF000 : 0x3000)); + sprclx[i] = (((i & 0x3) == 0x3 ? 1 : 0) + | ((i & 0x5) == 0x5 ? 2 : 0) + | ((i & 0x9) == 0x9 ? 4 : 0) + | ((i & 0x6) == 0x6 ? 8 : 0) + | ((i & 0xA) == 0xA ? 16 : 0) + | ((i & 0xC) == 0xC ? 32 : 0)) << 9; + } + } + + function reset_sprites() { //ORG init_sprites() + //memset(sprpos, 0, sizeof sprpos); + //memset(sprctl, 0, sizeof sprctl); + SAEF_memset(sprpos,0, 0, MAX_SPRITES); + SAEF_memset(sprctl,0, 0, MAX_SPRITES); + } + + /* sprite do */ + /*-----------------------------------------------------------------------*/ + /*-----------------------------------------------------------------------*/ + /*-----------------------------------------------------------------------*/ + /* SECT setup/reset */ + + /* mousehack is now in "filesys boot rom" */ + function mousehack_helper_old(ctx) { //struct TrapContext * + //SAEF_log("playfield.mousehack_helper_old()"); + return 0; + } + var timehack_alive = 0; + function timehack_helper(ctx) { //struct TrapContext * + //SAEF_log("playfield.timehack_helper()"); + //#ifdef HAVE_GETTIMEOFDAY + if (SAER_CPU_regs.d[0] == 0) + return timehack_alive; + + timehack_alive = 10; + + var tv = {}; + SAEF_gettimeofday(tv, null); + SAER_Memory_put32(SAER_CPU_regs.a[0], tv.tv_sec - (((365 * 8 + 2) * 24) * 60 * 60)); + SAER_Memory_put32(SAER_CPU_regs.a[0] + 4, tv.tv_usec); //ATT +4, 32bit overflow + return 0; + /*#else + return 2; + #endif*/ + } + + this.setup = function() { //custom_init() + //#ifdef AUTOCONFIG + if (SAEV_AutoConf_boot_rom_type) { + var pos = SAER.autoconf.here(); + + SAER.autoconf.org(SAEV_AutoConf_base + 0xFF70); + SAER.autoconf.calltrap(SAER.autoconf.define_trap(mousehack_helper_old, 0, "mousehack_helper_old")); + SAER.autoconf.dw(SAEC_AutoConf_RTS); + + SAER.autoconf.org(SAEV_AutoConf_base + 0xFFA0); + SAER.autoconf.calltrap(SAER.autoconf.define_trap(timehack_helper, 0, "timehack_helper")); + SAER.autoconf.dw(SAEC_AutoConf_RTS); + + SAER.autoconf.org(pos); + } + //#endif + setup_sprites(); + //build_blitfilltable(); //OWN in blitter.js + drawing_init(); + create_cycle_diagram_table(); + notice_new_xcolors(); + return SAEE_None; + } + + function reset_all_systems(hardreset) { + SAER.events.reset(); + /*#ifdef PICASSO96 + picasso_reset(); + #endif*/ + //#ifdef FILESYS + //SAER.filesys.prepare_reset(); //OWN empty + SAER.filesys.reset(); + //#endif + //init_shm(); + SAER.memory.reset(hardreset); + //#ifdef FILESYS + //SAER.filesys.start_threads(); //OWN empty + //SAER.hardfile.reset(); //OWN empty + //#endif + /*#ifdef PARALLEL_PORT + initparallel(); + #endif + native2amiga_reset(); + dongle_reset(); + sampler_init(); + */ + SAER.serial.reset(); //OWN + } + + this.custom_reset = function(hardreset, keyboardreset) { + var i; + + //target_reset(); + reset_all_systems(hardreset); + SAER.memory.map_dump(); + + lightpen_active = -1; + lightpen_triggered = 0; + lightpen_cx = lightpen_cy = -1; nr_armed = 0; - bplcon0 = 0; - bplcon3 = 0x0C00; - bplcon4 = 0x0011; // Get AGA chipset into ECS compatibility mode + { + //extra_cycle = 0; //OWN in events.js + SAEV_Events_hsync_counter = 0; + SAEV_Events_vsync_counter = 0; + //SAEV_config.chipset.mask = changed_prefs.chipset_mask; + update_mirrors(); - diwhigh = 0; - diwhigh_written = false; - hdiwstate = DIW_WAITING_START; // this does not reset at vblank + SAER.blitter.reset(); //blitter_reset(); - this.FMODE(0, 0); - this.CLXCON(0); - this.CLXCON2(0); - this.setup_fmodes(0); - //sprite_width = GET_SPRITEWIDTH(fmode); - beamcon0 = new_beamcon0 = AMIGA.config.video.ntsc ? 0x00 : 0x20; - this.lof_store = this.lof_current = 1; + if (hardreset) { + if (!aga_mode) { + var c = (((SAEV_config.chipset.mask & SAEC_Config_Chipset_Mask_ECS_DENISE) && !(SAEV_config.chipset.mask & SAEC_Config_Chipset_Mask_AGA)) || SAEV_config.chipset.deniseNoEHB) ? 0xfff : 0x000; + for (i = 0; i < 32; i++) { + current_colors.color_regs_ecs[i] = c; + current_colors.acolors[i] = getxcolor(c); + } + //#ifdef AGA + } else { + var c = 0; + for (i = 0; i < 256; i++) { + current_colors.color_regs_aga[i] = c; + current_colors.acolors[i] = getxcolor(c); + } + //#endif + } + } - this.vpos = 0; - this.vpos_count = this.vpos_count_diff = 0; + clxdat = 0; - //timehack_alive = 0; + /* Clear the armed flags of all sprites. */ + for (i = 0; i < spr.length; i++) spr[i].clr(); //memset(spr, 0, sizeof spr); - curr_sprite_entries = null; - prev_sprite_entries = null; + SAER.custom.reset(); + /*{ + SAEV_Custom_dmacon = 0; + intreq_internal = 0; + SAEV_Custom_intena = intena_internal = 0; + }*/ + + SAER.copper.clr_copcon(); //copcon = 0; + + SAER.disk.DSKLEN(0, 0); + + bplcon0 = 0; + bplcon4 = 0x0011; /* Get AGA chipset into ECS compatibility mode */ + bplcon3 = 0x0C00; + + diwhigh = 0; + diwhigh_written = 0; + hdiwstate = DIW_WAITING_START; // this does not reset at vblank + + refptr = 0xffff; + this.FMODE(0, 0); + this.CLXCON(0); + this.CLXCON2(0); + setup_fmodes(0); + sprite_width = GET_SPRITEWIDTH(fmode); + beamcon0 = new_beamcon0 = SAEV_config.chipset.ntsc ? 0x00 : 0x20; + + SAEV_Blitter_bltstate = SAEC_Blitter_bltstate_DONE; + SAEV_Blitter_interrupt = true; + + lof_store = lof_current = 0; + lof_lace = false; + + reset_sprites(); + } + + SAER.devices.reset(hardreset); + //specialmonitor_reset(); + + SAEF_clrSpcFlags(~(SAEC_spcflag_BRK | SAEC_spcflag_MODE_CHANGE)); + + vpos = 0; + vpos_count = vpos_count_diff = 0; + + SAER.input.reset(); //inputdevice_reset(); + timehack_alive = 0; + + curr_sprite_entries = 0; + prev_sprite_entries = 0; sprite_entries[0][0].first_pixel = 0; sprite_entries[1][0].first_pixel = MAX_SPR_PIXELS; sprite_entries[0][1].first_pixel = 0; sprite_entries[1][1].first_pixel = MAX_SPR_PIXELS; - for (var i = 0; i < spixels.length; i++) spixels[i] = 0; //memset (spixels, 0, 2 * MAX_SPR_PIXELS * sizeof *spixels); - for (var i = 0; i < spixstate.length; i++) spixstate[i] = 0; //memset (&spixstate, 0, sizeof spixstate); - + //memset(spixels, 0, 2 * MAX_SPR_PIXELS * sizeof *spixels); + //memset(&spixstate, 0, sizeof spixstate); + SAEF_memset(spixels,0, 0, 2 * MAX_SPR_PIXELS); + SAEF_memset(spixstate.bytes,0, 0, 2 * MAX_SPR_PIXELS); + toscr_delay_sh[0] = 0; + toscr_delay_sh[1] = 0; + + SAER_Copper_cop_state.state = 0; //COP_stop; + SAER_Copper_cop_state.movedelay = 0; + SAER_Copper_cop_state.strobe = 0; + SAER_Copper_cop_state.ignore_next = false; + diwstate = DIW_WAITING_START; - this.init_hz(true); - //vpos_lpen = -1; - this.lof_changing = 0; - this.lof_previous = this.lof_store; - lof_togglecnt_nlace = lof_togglecnt_lace = 0; - nlace_cnt = NLACE_CNT_NEEDED; + SAER.events.clr_dmal(); //dmal = 0; - this.reset_sprites(); - this.init_hardware_frame(); - this.reset_drawing(); - this.reset_decisions(); + init_hz_normal(); + vpos_lpen = -1; + lof_changing = 0; + lof_togglecnt_nlace = lof_togglecnt_lace = 0; + //nlace_cnt = NLACE_CNT_NEEDED; //ORG + + SAER.audio.reset(); + //must be called after audio_reset + SAEV_Custom_adkcon = 0; + //serial_uartbreak(0); + SAER.audio.update_adkmasks(); + + init_hardware_frame(); + drawing_init(); + + reset_decisions(); + + SAEV_Events_bogusframe = 1; sprres = expand_sprres(bplcon0, bplcon3); sprite_width = GET_SPRITEWIDTH(fmode); - this.setup_fmodes(0); + setup_fmodes(0); -/*#ifdef PICASSO96 + /*#ifdef ACTION_REPLAY + // Doing this here ensures we can use the "reset" command from within AR + action_replay_reset (hardreset, keyboardreset); + #endif*/ + + if (hardreset) + SAER.rtc.hardreset(); //rtc_hardreset(); + + /*#ifdef PICASSO96 picasso_reset(); -#endif*/ - } -} + #endif*/ + hpos_is_zero_bplcon1_hack = -1; //OWN + cia_hsync = 0; //OWN + vhposr_oldhp = 0; //OWN + + cpu_accurate = SAEV_config.cpu.model < SAEC_Config_CPU_Model_68020; //CPU_ACCURATE(); //OWN + + warned_maybe_finish_last_fetch = 20; //OWN + } + + this.custom_prepare = function() { + set_hpos(); + //hsync_handler_post(true); //OWN framerate error + } + + /* setup/reset */ + /*-----------------------------------------------------------------------*/ + /*-----------------------------------------------------------------------*/ + /*-----------------------------------------------------------------------*/ + /* SECT linedraw functions */ + + /* ECS SuperHires special cases */ + function shsprite(dpix, spix_val, v, spr) { + if (!spr) + return v; + var sprcol = render_sprites(dpix, 0, spix_val, 0); + if (!sprcol) + return v; + // good enough for now.. + var scol = colors_for_drawing.color_regs_ecs[sprcol] & 0xccc; + scol |= scol >> 2; + return xcolors[scol]; + } + + function linetoscr_16_sh_func(spix, dpix, stoppos, spr) { + var buf = xlinebuffer; + + while (dpix < stoppos) { + var spix_val1, spix_val2; + var v; + var off; + spix_val1 = pixdata.apixels[spix++]; + spix_val2 = pixdata.apixels[spix++]; + off = ((spix_val2 & 3) * 4) + (spix_val1 & 3) + ((spix_val1 | spix_val2) & 16); + v = (colors_for_drawing.color_regs_ecs[off] & 0xccc) << 0; + v |= v >> 2; + buf[dpix + xlinebuffer_pos] = shsprite(dpix, spix_val1, xcolors[v], spr); + dpix++; + v = (colors_for_drawing.color_regs_ecs[off] & 0x333) << 2; + v |= v >> 2; + buf[dpix + xlinebuffer_pos] = shsprite(dpix, spix_val2, xcolors[v], spr); + dpix++; + } + return spix; + } + function linetoscr_16_sh_spr(spix, dpix, stoppos) { + return linetoscr_16_sh_func(spix, dpix, stoppos, true); + } + function linetoscr_16_sh(spix, dpix, stoppos) { + return linetoscr_16_sh_func(spix, dpix, stoppos, false); + } + + function linetoscr_32_sh_func(spix, dpix, stoppos, spr) { + var buf = xlinebuffer; + + while (dpix < stoppos) { + var spix_val1, spix_val2; + var v; + var off; + spix_val1 = pixdata.apixels[spix++]; + spix_val2 = pixdata.apixels[spix++]; + off = ((spix_val2 & 3) * 4) + (spix_val1 & 3) + ((spix_val1 | spix_val2) & 16); + v = (colors_for_drawing.color_regs_ecs[off] & 0xccc) << 0; + v |= v >> 2; + buf[dpix + xlinebuffer_pos] = shsprite(dpix, spix_val1, xcolors[v], spr); + dpix++; + v = (colors_for_drawing.color_regs_ecs[off] & 0x333) << 2; + v |= v >> 2; + buf[dpix + xlinebuffer_pos] = shsprite(dpix, spix_val2, xcolors[v], spr); + dpix++; + } + return spix; + } + function linetoscr_32_sh_spr(spix, dpix, stoppos) { + return linetoscr_32_sh_func(spix, dpix, stoppos, true); + } + function linetoscr_32_sh(spix, dpix, stoppos) { + return linetoscr_32_sh_func(spix, dpix, stoppos, false); + } + + function linetoscr_32_shrink1_sh_func(spix, dpix, stoppos, spr) { + var buf = xlinebuffer; + + while (dpix < stoppos) { + var spix_val1, spix_val2; + var v; + var off; + spix_val1 = pixdata.apixels[spix++]; + spix_val2 = pixdata.apixels[spix++]; + off = ((spix_val2 & 3) * 4) + (spix_val1 & 3) + ((spix_val1 | spix_val2) & 16); + v = (colors_for_drawing.color_regs_ecs[off] & 0xccc) << 0; + v |= v >> 2; + buf[dpix + xlinebuffer_pos] = shsprite(dpix, spix_val1, xcolors[v], spr); + dpix++; + } + return spix; + } + function linetoscr_32_shrink1_sh_spr(spix, dpix, stoppos) { + return linetoscr_32_shrink1_sh_func(spix, dpix, stoppos, true); + } + function linetoscr_32_shrink1_sh(spix, dpix, stoppos) { + return linetoscr_32_shrink1_sh_func(spix, dpix, stoppos, false); + } + + function linetoscr_32_shrink1f_sh_func(spix, dpix, stoppos, spr) { + var buf = xlinebuffer; + + while (dpix < stoppos) { + var spix_val1, spix_val2, dpix_val1, dpix_val2; + var v; + var off; + spix_val1 = pixdata.apixels[spix++]; + spix_val2 = pixdata.apixels[spix++]; + off = ((spix_val2 & 3) * 4) + (spix_val1 & 3) + ((spix_val1 | spix_val2) & 16); + v = (colors_for_drawing.color_regs_ecs[off] & 0xccc) << 0; + v |= v >> 2; + dpix_val1 = xcolors[v]; + v = (colors_for_drawing.color_regs_ecs[off] & 0x333) << 2; + v |= v >> 2; + dpix_val2 = xcolors[v]; + buf[dpix + xlinebuffer_pos] = shsprite(dpix, spix_val1, merge_2pixel32 (dpix_val1, dpix_val2), spr); + dpix++; + } + return spix; + } + function linetoscr_32_shrink1f_sh_spr(spix, dpix, stoppos) { + return linetoscr_32_shrink1f_sh_func(spix, dpix, stoppos, true); + } + function linetoscr_32_shrink1f_sh(spix, dpix, stoppos) { + return linetoscr_32_shrink1f_sh_func(spix, dpix, stoppos, false); + } + + function linetoscr_16_shrink1_sh_func(spix, dpix, stoppos, spr) { + var buf = xlinebuffer; + + while (dpix < stoppos) { + var spix_val1, spix_val2; + var v; + var off; + spix_val1 = pixdata.apixels[spix++]; + spix_val2 = pixdata.apixels[spix++]; + off = ((spix_val2 & 3) * 4) + (spix_val1 & 3) + ((spix_val1 | spix_val2) & 16); + v = (colors_for_drawing.color_regs_ecs[off] & 0xccc) << 0; + v |= v >> 2; + buf[dpix + xlinebuffer_pos] = shsprite(dpix, spix_val1, xcolors[v], spr); + dpix++; + } + return spix; + } + function linetoscr_16_shrink1_sh_spr(spix, dpix, stoppos) { + return linetoscr_16_shrink1_sh_func(spix, dpix, stoppos, true); + } + function linetoscr_16_shrink1_sh(spix, dpix, stoppos) { + return linetoscr_16_shrink1_sh_func(spix, dpix, stoppos, false); + } + + function linetoscr_16_shrink1f_sh_func(spix, dpix, stoppos, spr) { + var buf = xlinebuffer; + + while (dpix < stoppos) { + var spix_val1, spix_val2, dpix_val1, dpix_val2; + var v; + var off; + spix_val1 = pixdata.apixels[spix++]; + spix_val2 = pixdata.apixels[spix++]; + off = ((spix_val2 & 3) * 4) + (spix_val1 & 3) + ((spix_val1 | spix_val2) & 16); + v = (colors_for_drawing.color_regs_ecs[off] & 0xccc) << 0; + v |= v >> 2; + dpix_val1 = xcolors[v]; + v = (colors_for_drawing.color_regs_ecs[off] & 0x333) << 2; + v |= v >> 2; + dpix_val2 = xcolors[v]; + buf[dpix + xlinebuffer_pos] = shsprite(dpix, spix_val1, merge_2pixel16(dpix_val1, dpix_val2), spr); + dpix++; + } + return spix; + } + function linetoscr_16_shrink1f_sh_spr(spix, dpix, stoppos) { + return linetoscr_16_shrink1f_sh_func(spix, dpix, stoppos, true); + } + function linetoscr_16_shrink1f_sh(spix, dpix, stoppos) { + return linetoscr_16_shrink1f_sh_func(spix, dpix, stoppos, false); + } + + function linetoscr_32_shrink2_sh_func(spix, dpix, stoppos, spr) { + var buf = xlinebuffer; + + while (dpix < stoppos) { + var spix_val1, spix_val2; + var v; + var off; + spix_val1 = pixdata.apixels[spix++]; + spix_val2 = pixdata.apixels[spix++]; + off = ((spix_val2 & 3) * 4) + (spix_val1 & 3) + ((spix_val1 | spix_val2) & 16); + v = (colors_for_drawing.color_regs_ecs[off] & 0xccc) << 0; + v |= v >> 2; + buf[dpix + xlinebuffer_pos] = shsprite(dpix, spix_val1, xcolors[v], spr); + spix+=2; + dpix++; + } + return spix; + } + function linetoscr_32_shrink2_sh_spr(spix, dpix, stoppos) { + return linetoscr_32_shrink2_sh_func(spix, dpix, stoppos, true); + } + function linetoscr_32_shrink2_sh(spix, dpix, stoppos) { + return linetoscr_32_shrink2_sh_func(spix, dpix, stoppos, false); + } + + function linetoscr_32_shrink2f_sh_func(spix, dpix, stoppos, spr) { + var buf = xlinebuffer; + + while (dpix < stoppos) { + var spix_val1, spix_val2, dpix_val1, dpix_val2, dpix_val3, dpix_val4; + var v; + var off; + spix_val1 = pixdata.apixels[spix++]; + spix_val2 = pixdata.apixels[spix++]; + off = ((spix_val2 & 3) * 4) + (spix_val1 & 3) + ((spix_val1 | spix_val2) & 16); + v = (colors_for_drawing.color_regs_ecs[off] & 0xccc) << 0; + v |= v >> 2; + dpix_val1 = xcolors[v]; + v = (colors_for_drawing.color_regs_ecs[off] & 0x333) << 2; + v |= v >> 2; + dpix_val2 = xcolors[v]; + dpix_val3 = merge_2pixel32 (dpix_val1, dpix_val2); + spix_val1 = pixdata.apixels[spix++]; + spix_val2 = pixdata.apixels[spix++]; + off = ((spix_val2 & 3) * 4) + (spix_val1 & 3) + ((spix_val1 | spix_val2) & 16); + v = (colors_for_drawing.color_regs_ecs[off] & 0xccc) << 0; + v |= v >> 2; + dpix_val1 = xcolors[v]; + v = (colors_for_drawing.color_regs_ecs[off] & 0x333) << 2; + v |= v >> 2; + dpix_val2 = xcolors[v]; + dpix_val4 = merge_2pixel32 (dpix_val1, dpix_val2); + buf[dpix + xlinebuffer_pos] = shsprite(dpix, spix_val1, merge_2pixel32(dpix_val3, dpix_val4), spr); + dpix++; + } + return spix; + } + function linetoscr_32_shrink2f_sh_spr(spix, dpix, stoppos) { + return linetoscr_32_shrink2f_sh_func(spix, dpix, stoppos, true); + } + function linetoscr_32_shrink2f_sh(spix, dpix, stoppos) { + return linetoscr_32_shrink2f_sh_func(spix, dpix, stoppos, false); + } + + function linetoscr_16_shrink2_sh_func(spix, dpix, stoppos, spr) { + var buf = xlinebuffer; + + while (dpix < stoppos) { + var spix_val1, spix_val2; + var v; + var off; + spix_val1 = pixdata.apixels[spix++]; + spix_val2 = pixdata.apixels[spix++]; + off = ((spix_val2 & 3) * 4) + (spix_val1 & 3) + ((spix_val1 | spix_val2) & 16); + v = (colors_for_drawing.color_regs_ecs[off] & 0xccc) << 0; + v |= v >> 2; + buf[dpix + xlinebuffer_pos] = shsprite(dpix, spix_val1, xcolors[v], spr); + spix += 2; + dpix++; + } + return spix; + } + function linetoscr_16_shrink2_sh_spr(spix, dpix, stoppos) { + return linetoscr_16_shrink2_sh_func(spix, dpix, stoppos, true); + } + function linetoscr_16_shrink2_sh(spix, dpix, stoppos) { + return linetoscr_16_shrink2_sh_func(spix, dpix, stoppos, false); + } + + function linetoscr_16_shrink2f_sh_func (spix, dpix, stoppos, spr) { + var buf = xlinebuffer; + + while (dpix < stoppos) { + var spix_val1, spix_val2, dpix_val1, dpix_val2, dpix_val3, dpix_val4; + var v; + var off; + spix_val1 = pixdata.apixels[spix++]; + spix_val2 = pixdata.apixels[spix++]; + off = ((spix_val2 & 3) * 4) + (spix_val1 & 3) + ((spix_val1 | spix_val2) & 16); + v = (colors_for_drawing.color_regs_ecs[off] & 0xccc) << 0; + v |= v >> 2; + dpix_val1 = xcolors[v]; + v = (colors_for_drawing.color_regs_ecs[off] & 0x333) << 2; + v |= v >> 2; + dpix_val2 = xcolors[v]; + dpix_val3 = merge_2pixel32 (dpix_val1, dpix_val2); + spix_val1 = pixdata.apixels[spix++]; + spix_val2 = pixdata.apixels[spix++]; + off = ((spix_val2 & 3) * 4) + (spix_val1 & 3) + ((spix_val1 | spix_val2) & 16); + v = (colors_for_drawing.color_regs_ecs[off] & 0xccc) << 0; + v |= v >> 2; + dpix_val1 = xcolors[v]; + v = (colors_for_drawing.color_regs_ecs[off] & 0x333) << 2; + v |= v >> 2; + dpix_val2 = xcolors[v]; + dpix_val4 = merge_2pixel32 (dpix_val1, dpix_val2); + buf[dpix + xlinebuffer_pos] = shsprite(dpix, spix_val1, merge_2pixel16 (dpix_val3, dpix_val4), spr); + dpix++; + } + return spix; + } + function linetoscr_16_shrink2f_sh_spr(spix, dpix, stoppos) { + return linetoscr_16_shrink2f_sh_func(spix, dpix, stoppos, true); + } + function linetoscr_16_shrink2f_sh(spix, dpix, stoppos) { + return linetoscr_16_shrink2f_sh_func(spix, dpix, stoppos, false); + } + + /*-----------------------------------------------------------------------*/ + /* auto-generated functions */ + + function linetoscr_16(spix, dpix, dpix_end) + { + var buf = xlinebuffer; + if (bplham) { + if ((dpix + xlinebuffer_pos) & 2) { + var spix_val = 0; + var dpix_val = 0; + spix_val = ham_linebuf[spix]; + dpix_val = p_xcolors[spix_val]; + spix++; + buf[dpix + xlinebuffer_pos] = dpix_val; dpix++; + } + if (dpix >= dpix_end) + return spix; + var rem = (dpix_end + xlinebuffer_pos) & 2; + if (rem) + dpix_end--; + while (dpix < dpix_end) { + var spix_val = 0; + var dpix_val = 0; + var out_val = 0; + spix_val = ham_linebuf[spix]; + dpix_val = p_xcolors[spix_val]; + spix++; + out_val = dpix_val; + spix_val = ham_linebuf[spix]; + dpix_val = p_xcolors[spix_val]; + spix++; + out_val = ((out_val << 16) | (dpix_val & 0xFFFF)) >>> 0; + buf[dpix + xlinebuffer_pos] = out_val >>> 16; + buf[dpix + xlinebuffer_pos + 1] = out_val & 0xffff; + dpix += 2; + } + if (rem) { + var spix_val = 0; + var dpix_val = 0; + spix_val = ham_linebuf[spix]; + dpix_val = p_xcolors[spix_val]; + spix++; + buf[dpix + xlinebuffer_pos] = dpix_val; dpix++; + } + } else if (bpldualpf) { + var lookup = bpldualpfpri ? dblpf_ind2 : dblpf_ind1; + if ((dpix + xlinebuffer_pos) & 2) { + var spix_val = 0; + var dpix_val = 0; + spix_val = pixdata.apixels[spix]; + dpix_val = p_acolors[lookup[spix_val]]; + spix++; + buf[dpix + xlinebuffer_pos] = dpix_val; dpix++; + } + if (dpix >= dpix_end) + return spix; + var rem = (dpix_end + xlinebuffer_pos) & 2; + if (rem) + dpix_end--; + while (dpix < dpix_end) { + var spix_val = 0; + var dpix_val = 0; + var out_val = 0; + spix_val = pixdata.apixels[spix]; + dpix_val = p_acolors[lookup[spix_val]]; + spix++; + out_val = dpix_val; + spix_val = pixdata.apixels[spix]; + dpix_val = p_acolors[lookup[spix_val]]; + spix++; + out_val = ((out_val << 16) | (dpix_val & 0xFFFF)) >>> 0; + buf[dpix + xlinebuffer_pos] = out_val >>> 16; + buf[dpix + xlinebuffer_pos + 1] = out_val & 0xffff; + dpix += 2; + } + if (rem) { + var spix_val = 0; + var dpix_val = 0; + spix_val = pixdata.apixels[spix]; + dpix_val = p_acolors[lookup[spix_val]]; + spix++; + buf[dpix + xlinebuffer_pos] = dpix_val; dpix++; + } + } else if (bplehb) { + if ((dpix + xlinebuffer_pos) & 2) { + var spix_val = 0; + var dpix_val = 0; + spix_val = pixdata.apixels[spix]; + if (spix_val <= 31) + dpix_val = p_acolors[spix_val]; + else + dpix_val = p_xcolors[(colors_for_drawing.color_regs_ecs[spix_val - 32] >>> 1) & 0x777]; + spix++; + buf[dpix + xlinebuffer_pos] = dpix_val; dpix++; + } + if (dpix >= dpix_end) + return spix; + var rem = (dpix_end + xlinebuffer_pos) & 2; + if (rem) + dpix_end--; + while (dpix < dpix_end) { + var spix_val = 0; + var dpix_val = 0; + var out_val = 0; + spix_val = pixdata.apixels[spix]; + if (spix_val <= 31) + dpix_val = p_acolors[spix_val]; + else + dpix_val = p_xcolors[(colors_for_drawing.color_regs_ecs[spix_val - 32] >>> 1) & 0x777]; + spix++; + out_val = dpix_val; + spix_val = pixdata.apixels[spix]; + if (spix_val <= 31) + dpix_val = p_acolors[spix_val]; + else + dpix_val = p_xcolors[(colors_for_drawing.color_regs_ecs[spix_val - 32] >>> 1) & 0x777]; + spix++; + out_val = ((out_val << 16) | (dpix_val & 0xFFFF)) >>> 0; + buf[dpix + xlinebuffer_pos] = out_val >>> 16; + buf[dpix + xlinebuffer_pos + 1] = out_val & 0xffff; + dpix += 2; + } + if (rem) { + var spix_val = 0; + var dpix_val = 0; + spix_val = pixdata.apixels[spix]; + if (spix_val <= 31) + dpix_val = p_acolors[spix_val]; + else + dpix_val = p_xcolors[(colors_for_drawing.color_regs_ecs[spix_val - 32] >>> 1) & 0x777]; + spix++; + buf[dpix + xlinebuffer_pos] = dpix_val; dpix++; + } + } else { + if ((dpix + xlinebuffer_pos) & 2) { + var spix_val = 0; + var dpix_val = 0; + spix_val = pixdata.apixels[spix]; + dpix_val = p_acolors[spix_val]; + spix++; + buf[dpix + xlinebuffer_pos] = dpix_val; dpix++; + } + if (dpix >= dpix_end) + return spix; + var rem = (dpix_end + xlinebuffer_pos) & 2; + if (rem) + dpix_end--; + while (dpix < dpix_end) { + var spix_val = 0; + var dpix_val = 0; + var out_val = 0; + spix_val = pixdata.apixels[spix]; + dpix_val = p_acolors[spix_val]; + spix++; + out_val = dpix_val; + spix_val = pixdata.apixels[spix]; + dpix_val = p_acolors[spix_val]; + spix++; + out_val = ((out_val << 16) | (dpix_val & 0xFFFF)) >>> 0; + buf[dpix + xlinebuffer_pos] = out_val >>> 16; + buf[dpix + xlinebuffer_pos + 1] = out_val & 0xffff; + dpix += 2; + } + if (rem) { + var spix_val = 0; + var dpix_val = 0; + spix_val = pixdata.apixels[spix]; + dpix_val = p_acolors[spix_val]; + spix++; + buf[dpix + xlinebuffer_pos] = dpix_val; dpix++; + } + } + return spix; + } + + function linetoscr_16_stretch1(spix, dpix, dpix_end) + { + var buf = xlinebuffer; + if (bplham) { + while (dpix < dpix_end) { + var spix_val = 0; + var dpix_val = 0; + var out_val = 0; + spix_val = ham_linebuf[spix]; + dpix_val = p_xcolors[spix_val]; + spix++; + out_val = dpix_val; + buf[dpix + xlinebuffer_pos] = out_val >>> 16; + buf[dpix + xlinebuffer_pos + 1] = out_val & 0xffff; + dpix += 2; + } + } else if (bpldualpf) { + var lookup = bpldualpfpri ? dblpf_ind2 : dblpf_ind1; + while (dpix < dpix_end) { + var spix_val = 0; + var dpix_val = 0; + var out_val = 0; + spix_val = pixdata.apixels[spix]; + dpix_val = p_acolors[lookup[spix_val]]; + spix++; + out_val = dpix_val; + buf[dpix + xlinebuffer_pos] = out_val >>> 16; + buf[dpix + xlinebuffer_pos + 1] = out_val & 0xffff; + dpix += 2; + } + } else if (bplehb) { + while (dpix < dpix_end) { + var spix_val = 0; + var dpix_val = 0; + var out_val = 0; + spix_val = pixdata.apixels[spix]; + if (spix_val <= 31) + dpix_val = p_acolors[spix_val]; + else + dpix_val = p_xcolors[(colors_for_drawing.color_regs_ecs[spix_val - 32] >>> 1) & 0x777]; + spix++; + out_val = dpix_val; + buf[dpix + xlinebuffer_pos] = out_val >>> 16; + buf[dpix + xlinebuffer_pos + 1] = out_val & 0xffff; + dpix += 2; + } + } else { + while (dpix < dpix_end) { + var spix_val = 0; + var dpix_val = 0; + var out_val = 0; + spix_val = pixdata.apixels[spix]; + dpix_val = p_acolors[spix_val]; + spix++; + out_val = dpix_val; + buf[dpix + xlinebuffer_pos] = out_val >>> 16; + buf[dpix + xlinebuffer_pos + 1] = out_val & 0xffff; + dpix += 2; + } + } + return spix; + } + + function linetoscr_16_stretch2(spix, dpix, dpix_end) + { + var buf = xlinebuffer; + if (bplham) { + while (dpix < dpix_end) { + var spix_val = 0; + var dpix_val = 0; + var out_val = 0; + spix_val = ham_linebuf[spix]; + dpix_val = p_xcolors[spix_val]; + spix++; + out_val = dpix_val; + buf[dpix + xlinebuffer_pos] = out_val >>> 16; + buf[dpix + xlinebuffer_pos + 1] = out_val & 0xffff; + dpix += 2; + buf[dpix + xlinebuffer_pos] = out_val >>> 16; + buf[dpix + xlinebuffer_pos + 1] = out_val & 0xffff; + dpix += 2; + } + } else if (bpldualpf) { + var lookup = bpldualpfpri ? dblpf_ind2 : dblpf_ind1; + while (dpix < dpix_end) { + var spix_val = 0; + var dpix_val = 0; + var out_val = 0; + spix_val = pixdata.apixels[spix]; + dpix_val = p_acolors[lookup[spix_val]]; + spix++; + out_val = dpix_val; + buf[dpix + xlinebuffer_pos] = out_val >>> 16; + buf[dpix + xlinebuffer_pos + 1] = out_val & 0xffff; + dpix += 2; + buf[dpix + xlinebuffer_pos] = out_val >>> 16; + buf[dpix + xlinebuffer_pos + 1] = out_val & 0xffff; + dpix += 2; + } + } else if (bplehb) { + while (dpix < dpix_end) { + var spix_val = 0; + var dpix_val = 0; + var out_val = 0; + spix_val = pixdata.apixels[spix]; + if (spix_val <= 31) + dpix_val = p_acolors[spix_val]; + else + dpix_val = p_xcolors[(colors_for_drawing.color_regs_ecs[spix_val - 32] >>> 1) & 0x777]; + spix++; + out_val = dpix_val; + buf[dpix + xlinebuffer_pos] = out_val >>> 16; + buf[dpix + xlinebuffer_pos + 1] = out_val & 0xffff; + dpix += 2; + buf[dpix + xlinebuffer_pos] = out_val >>> 16; + buf[dpix + xlinebuffer_pos + 1] = out_val & 0xffff; + dpix += 2; + } + } else { + while (dpix < dpix_end) { + var spix_val = 0; + var dpix_val = 0; + var out_val = 0; + spix_val = pixdata.apixels[spix]; + dpix_val = p_acolors[spix_val]; + spix++; + out_val = dpix_val; + buf[dpix + xlinebuffer_pos] = out_val >>> 16; + buf[dpix + xlinebuffer_pos + 1] = out_val & 0xffff; + dpix += 2; + buf[dpix + xlinebuffer_pos] = out_val >>> 16; + buf[dpix + xlinebuffer_pos + 1] = out_val & 0xffff; + dpix += 2; + } + } + return spix; + } + + function linetoscr_16_shrink1(spix, dpix, dpix_end) + { + var buf = xlinebuffer; + if (bplham) { + if ((dpix + xlinebuffer_pos) & 2) { + var spix_val = 0; + var dpix_val = 0; + spix_val = ham_linebuf[spix]; + dpix_val = p_xcolors[spix_val]; + spix += 2; + buf[dpix + xlinebuffer_pos] = dpix_val; dpix++; + } + if (dpix >= dpix_end) + return spix; + var rem = (dpix_end + xlinebuffer_pos) & 2; + if (rem) + dpix_end--; + while (dpix < dpix_end) { + var spix_val = 0; + var dpix_val = 0; + var out_val = 0; + spix_val = ham_linebuf[spix]; + dpix_val = p_xcolors[spix_val]; + spix += 2; + out_val = dpix_val; + spix_val = ham_linebuf[spix]; + dpix_val = p_xcolors[spix_val]; + spix += 2; + out_val = ((out_val << 16) | (dpix_val & 0xFFFF)) >>> 0; + buf[dpix + xlinebuffer_pos] = out_val >>> 16; + buf[dpix + xlinebuffer_pos + 1] = out_val & 0xffff; + dpix += 2; + } + if (rem) { + var spix_val = 0; + var dpix_val = 0; + spix_val = ham_linebuf[spix]; + dpix_val = p_xcolors[spix_val]; + spix += 2; + buf[dpix + xlinebuffer_pos] = dpix_val; dpix++; + } + } else if (bpldualpf) { + var lookup = bpldualpfpri ? dblpf_ind2 : dblpf_ind1; + if ((dpix + xlinebuffer_pos) & 2) { + var spix_val = 0; + var dpix_val = 0; + spix_val = pixdata.apixels[spix]; + dpix_val = p_acolors[lookup[spix_val]]; + spix += 2; + buf[dpix + xlinebuffer_pos] = dpix_val; dpix++; + } + if (dpix >= dpix_end) + return spix; + var rem = (dpix_end + xlinebuffer_pos) & 2; + if (rem) + dpix_end--; + while (dpix < dpix_end) { + var spix_val = 0; + var dpix_val = 0; + var out_val = 0; + spix_val = pixdata.apixels[spix]; + dpix_val = p_acolors[lookup[spix_val]]; + spix += 2; + out_val = dpix_val; + spix_val = pixdata.apixels[spix]; + dpix_val = p_acolors[lookup[spix_val]]; + spix += 2; + out_val = ((out_val << 16) | (dpix_val & 0xFFFF)) >>> 0; + buf[dpix + xlinebuffer_pos] = out_val >>> 16; + buf[dpix + xlinebuffer_pos + 1] = out_val & 0xffff; + dpix += 2; + } + if (rem) { + var spix_val = 0; + var dpix_val = 0; + spix_val = pixdata.apixels[spix]; + dpix_val = p_acolors[lookup[spix_val]]; + spix += 2; + buf[dpix + xlinebuffer_pos] = dpix_val; dpix++; + } + } else if (bplehb) { + if ((dpix + xlinebuffer_pos) & 2) { + var spix_val = 0; + var dpix_val = 0; + spix_val = pixdata.apixels[spix]; + if (spix_val <= 31) + dpix_val = p_acolors[spix_val]; + else + dpix_val = p_xcolors[(colors_for_drawing.color_regs_ecs[spix_val - 32] >>> 1) & 0x777]; + spix += 2; + buf[dpix + xlinebuffer_pos] = dpix_val; dpix++; + } + if (dpix >= dpix_end) + return spix; + var rem = (dpix_end + xlinebuffer_pos) & 2; + if (rem) + dpix_end--; + while (dpix < dpix_end) { + var spix_val = 0; + var dpix_val = 0; + var out_val = 0; + spix_val = pixdata.apixels[spix]; + if (spix_val <= 31) + dpix_val = p_acolors[spix_val]; + else + dpix_val = p_xcolors[(colors_for_drawing.color_regs_ecs[spix_val - 32] >>> 1) & 0x777]; + spix += 2; + out_val = dpix_val; + spix_val = pixdata.apixels[spix]; + if (spix_val <= 31) + dpix_val = p_acolors[spix_val]; + else + dpix_val = p_xcolors[(colors_for_drawing.color_regs_ecs[spix_val - 32] >>> 1) & 0x777]; + spix += 2; + out_val = ((out_val << 16) | (dpix_val & 0xFFFF)) >>> 0; + buf[dpix + xlinebuffer_pos] = out_val >>> 16; + buf[dpix + xlinebuffer_pos + 1] = out_val & 0xffff; + dpix += 2; + } + if (rem) { + var spix_val = 0; + var dpix_val = 0; + spix_val = pixdata.apixels[spix]; + if (spix_val <= 31) + dpix_val = p_acolors[spix_val]; + else + dpix_val = p_xcolors[(colors_for_drawing.color_regs_ecs[spix_val - 32] >>> 1) & 0x777]; + spix += 2; + buf[dpix + xlinebuffer_pos] = dpix_val; dpix++; + } + } else { + if ((dpix + xlinebuffer_pos) & 2) { + var spix_val = 0; + var dpix_val = 0; + spix_val = pixdata.apixels[spix]; + dpix_val = p_acolors[spix_val]; + spix += 2; + buf[dpix + xlinebuffer_pos] = dpix_val; dpix++; + } + if (dpix >= dpix_end) + return spix; + var rem = (dpix_end + xlinebuffer_pos) & 2; + if (rem) + dpix_end--; + while (dpix < dpix_end) { + var spix_val = 0; + var dpix_val = 0; + var out_val = 0; + spix_val = pixdata.apixels[spix]; + dpix_val = p_acolors[spix_val]; + spix += 2; + out_val = dpix_val; + spix_val = pixdata.apixels[spix]; + dpix_val = p_acolors[spix_val]; + spix += 2; + out_val = ((out_val << 16) | (dpix_val & 0xFFFF)) >>> 0; + buf[dpix + xlinebuffer_pos] = out_val >>> 16; + buf[dpix + xlinebuffer_pos + 1] = out_val & 0xffff; + dpix += 2; + } + if (rem) { + var spix_val = 0; + var dpix_val = 0; + spix_val = pixdata.apixels[spix]; + dpix_val = p_acolors[spix_val]; + spix += 2; + buf[dpix + xlinebuffer_pos] = dpix_val; dpix++; + } + } + return spix; + } + + function linetoscr_16_shrink1f(spix, dpix, dpix_end) + { + var buf = xlinebuffer; + if (bplham) { + if ((dpix + xlinebuffer_pos) & 2) { + var spix_val = 0; + var dpix_val = 0; + spix_val = ham_linebuf[spix]; + dpix_val = p_xcolors[spix_val]; + { + var tmp_val; + spix++; + tmp_val = dpix_val; + spix_val = ham_linebuf[spix]; + dpix_val = p_xcolors[spix_val]; + dpix_val = merge_2pixel16(dpix_val, tmp_val); + spix++; + } + buf[dpix + xlinebuffer_pos] = dpix_val; dpix++; + } + if (dpix >= dpix_end) + return spix; + var rem = (dpix_end + xlinebuffer_pos) & 2; + if (rem) + dpix_end--; + while (dpix < dpix_end) { + var spix_val = 0; + var dpix_val = 0; + var out_val = 0; + spix_val = ham_linebuf[spix]; + dpix_val = p_xcolors[spix_val]; + { + var tmp_val; + spix++; + tmp_val = dpix_val; + spix_val = ham_linebuf[spix]; + dpix_val = p_xcolors[spix_val]; + dpix_val = merge_2pixel16(dpix_val, tmp_val); + spix++; + } + out_val = dpix_val; + spix_val = ham_linebuf[spix]; + dpix_val = p_xcolors[spix_val]; + { + var tmp_val; + spix++; + tmp_val = dpix_val; + spix_val = ham_linebuf[spix]; + dpix_val = p_xcolors[spix_val]; + dpix_val = merge_2pixel16(dpix_val, tmp_val); + spix++; + } + out_val = ((out_val << 16) | (dpix_val & 0xFFFF)) >>> 0; + buf[dpix + xlinebuffer_pos] = out_val >>> 16; + buf[dpix + xlinebuffer_pos + 1] = out_val & 0xffff; + dpix += 2; + } + if (rem) { + var spix_val = 0; + var dpix_val = 0; + spix_val = ham_linebuf[spix]; + dpix_val = p_xcolors[spix_val]; + { + var tmp_val; + spix++; + tmp_val = dpix_val; + spix_val = ham_linebuf[spix]; + dpix_val = p_xcolors[spix_val]; + dpix_val = merge_2pixel16(dpix_val, tmp_val); + spix++; + } + buf[dpix + xlinebuffer_pos] = dpix_val; dpix++; + } + } else if (bpldualpf) { + var lookup = bpldualpfpri ? dblpf_ind2 : dblpf_ind1; + if ((dpix + xlinebuffer_pos) & 2) { + var spix_val = 0; + var dpix_val = 0; + spix_val = pixdata.apixels[spix]; + dpix_val = p_acolors[lookup[spix_val]]; + { + var tmp_val; + spix++; + tmp_val = dpix_val; + spix_val = pixdata.apixels[spix]; + dpix_val = p_acolors[lookup[spix_val]]; + dpix_val = merge_2pixel16(dpix_val, tmp_val); + spix++; + } + buf[dpix + xlinebuffer_pos] = dpix_val; dpix++; + } + if (dpix >= dpix_end) + return spix; + var rem = (dpix_end + xlinebuffer_pos) & 2; + if (rem) + dpix_end--; + while (dpix < dpix_end) { + var spix_val = 0; + var dpix_val = 0; + var out_val = 0; + spix_val = pixdata.apixels[spix]; + dpix_val = p_acolors[lookup[spix_val]]; + { + var tmp_val; + spix++; + tmp_val = dpix_val; + spix_val = pixdata.apixels[spix]; + dpix_val = p_acolors[lookup[spix_val]]; + dpix_val = merge_2pixel16(dpix_val, tmp_val); + spix++; + } + out_val = dpix_val; + spix_val = pixdata.apixels[spix]; + dpix_val = p_acolors[lookup[spix_val]]; + { + var tmp_val; + spix++; + tmp_val = dpix_val; + spix_val = pixdata.apixels[spix]; + dpix_val = p_acolors[lookup[spix_val]]; + dpix_val = merge_2pixel16(dpix_val, tmp_val); + spix++; + } + out_val = ((out_val << 16) | (dpix_val & 0xFFFF)) >>> 0; + buf[dpix + xlinebuffer_pos] = out_val >>> 16; + buf[dpix + xlinebuffer_pos + 1] = out_val & 0xffff; + dpix += 2; + } + if (rem) { + var spix_val = 0; + var dpix_val = 0; + spix_val = pixdata.apixels[spix]; + dpix_val = p_acolors[lookup[spix_val]]; + { + var tmp_val; + spix++; + tmp_val = dpix_val; + spix_val = pixdata.apixels[spix]; + dpix_val = p_acolors[lookup[spix_val]]; + dpix_val = merge_2pixel16(dpix_val, tmp_val); + spix++; + } + buf[dpix + xlinebuffer_pos] = dpix_val; dpix++; + } + } else if (bplehb) { + if ((dpix + xlinebuffer_pos) & 2) { + var spix_val = 0; + var dpix_val = 0; + spix_val = pixdata.apixels[spix]; + if (spix_val <= 31) + dpix_val = p_acolors[spix_val]; + else + dpix_val = p_xcolors[(colors_for_drawing.color_regs_ecs[spix_val - 32] >>> 1) & 0x777]; + { + var tmp_val; + spix++; + tmp_val = dpix_val; + spix_val = pixdata.apixels[spix]; + if (spix_val <= 31) + dpix_val = p_acolors[spix_val]; + else + dpix_val = p_xcolors[(colors_for_drawing.color_regs_ecs[spix_val - 32] >>> 1) & 0x777]; + dpix_val = merge_2pixel16(dpix_val, tmp_val); + spix++; + } + buf[dpix + xlinebuffer_pos] = dpix_val; dpix++; + } + if (dpix >= dpix_end) + return spix; + var rem = (dpix_end + xlinebuffer_pos) & 2; + if (rem) + dpix_end--; + while (dpix < dpix_end) { + var spix_val = 0; + var dpix_val = 0; + var out_val = 0; + spix_val = pixdata.apixels[spix]; + if (spix_val <= 31) + dpix_val = p_acolors[spix_val]; + else + dpix_val = p_xcolors[(colors_for_drawing.color_regs_ecs[spix_val - 32] >>> 1) & 0x777]; + { + var tmp_val; + spix++; + tmp_val = dpix_val; + spix_val = pixdata.apixels[spix]; + if (spix_val <= 31) + dpix_val = p_acolors[spix_val]; + else + dpix_val = p_xcolors[(colors_for_drawing.color_regs_ecs[spix_val - 32] >>> 1) & 0x777]; + dpix_val = merge_2pixel16(dpix_val, tmp_val); + spix++; + } + out_val = dpix_val; + spix_val = pixdata.apixels[spix]; + if (spix_val <= 31) + dpix_val = p_acolors[spix_val]; + else + dpix_val = p_xcolors[(colors_for_drawing.color_regs_ecs[spix_val - 32] >>> 1) & 0x777]; + { + var tmp_val; + spix++; + tmp_val = dpix_val; + spix_val = pixdata.apixels[spix]; + if (spix_val <= 31) + dpix_val = p_acolors[spix_val]; + else + dpix_val = p_xcolors[(colors_for_drawing.color_regs_ecs[spix_val - 32] >>> 1) & 0x777]; + dpix_val = merge_2pixel16(dpix_val, tmp_val); + spix++; + } + out_val = ((out_val << 16) | (dpix_val & 0xFFFF)) >>> 0; + buf[dpix + xlinebuffer_pos] = out_val >>> 16; + buf[dpix + xlinebuffer_pos + 1] = out_val & 0xffff; + dpix += 2; + } + if (rem) { + var spix_val = 0; + var dpix_val = 0; + spix_val = pixdata.apixels[spix]; + if (spix_val <= 31) + dpix_val = p_acolors[spix_val]; + else + dpix_val = p_xcolors[(colors_for_drawing.color_regs_ecs[spix_val - 32] >>> 1) & 0x777]; + { + var tmp_val; + spix++; + tmp_val = dpix_val; + spix_val = pixdata.apixels[spix]; + if (spix_val <= 31) + dpix_val = p_acolors[spix_val]; + else + dpix_val = p_xcolors[(colors_for_drawing.color_regs_ecs[spix_val - 32] >>> 1) & 0x777]; + dpix_val = merge_2pixel16(dpix_val, tmp_val); + spix++; + } + buf[dpix + xlinebuffer_pos] = dpix_val; dpix++; + } + } else { + if ((dpix + xlinebuffer_pos) & 2) { + var spix_val = 0; + var dpix_val = 0; + spix_val = pixdata.apixels[spix]; + dpix_val = p_acolors[spix_val]; + { + var tmp_val; + spix++; + tmp_val = dpix_val; + spix_val = pixdata.apixels[spix]; + dpix_val = p_acolors[spix_val]; + dpix_val = merge_2pixel16(dpix_val, tmp_val); + spix++; + } + buf[dpix + xlinebuffer_pos] = dpix_val; dpix++; + } + if (dpix >= dpix_end) + return spix; + var rem = (dpix_end + xlinebuffer_pos) & 2; + if (rem) + dpix_end--; + while (dpix < dpix_end) { + var spix_val = 0; + var dpix_val = 0; + var out_val = 0; + spix_val = pixdata.apixels[spix]; + dpix_val = p_acolors[spix_val]; + { + var tmp_val; + spix++; + tmp_val = dpix_val; + spix_val = pixdata.apixels[spix]; + dpix_val = p_acolors[spix_val]; + dpix_val = merge_2pixel16(dpix_val, tmp_val); + spix++; + } + out_val = dpix_val; + spix_val = pixdata.apixels[spix]; + dpix_val = p_acolors[spix_val]; + { + var tmp_val; + spix++; + tmp_val = dpix_val; + spix_val = pixdata.apixels[spix]; + dpix_val = p_acolors[spix_val]; + dpix_val = merge_2pixel16(dpix_val, tmp_val); + spix++; + } + out_val = ((out_val << 16) | (dpix_val & 0xFFFF)) >>> 0; + buf[dpix + xlinebuffer_pos] = out_val >>> 16; + buf[dpix + xlinebuffer_pos + 1] = out_val & 0xffff; + dpix += 2; + } + if (rem) { + var spix_val = 0; + var dpix_val = 0; + spix_val = pixdata.apixels[spix]; + dpix_val = p_acolors[spix_val]; + { + var tmp_val; + spix++; + tmp_val = dpix_val; + spix_val = pixdata.apixels[spix]; + dpix_val = p_acolors[spix_val]; + dpix_val = merge_2pixel16(dpix_val, tmp_val); + spix++; + } + buf[dpix + xlinebuffer_pos] = dpix_val; dpix++; + } + } + return spix; + } + + function linetoscr_16_shrink2(spix, dpix, dpix_end) + { + var buf = xlinebuffer; + if (bplham) { + if ((dpix + xlinebuffer_pos) & 2) { + var spix_val = 0; + var dpix_val = 0; + spix_val = ham_linebuf[spix]; + dpix_val = p_xcolors[spix_val]; + spix += 4; + buf[dpix + xlinebuffer_pos] = dpix_val; dpix++; + } + if (dpix >= dpix_end) + return spix; + var rem = (dpix_end + xlinebuffer_pos) & 2; + if (rem) + dpix_end--; + while (dpix < dpix_end) { + var spix_val = 0; + var dpix_val = 0; + var out_val = 0; + spix_val = ham_linebuf[spix]; + dpix_val = p_xcolors[spix_val]; + spix += 4; + out_val = dpix_val; + spix_val = ham_linebuf[spix]; + dpix_val = p_xcolors[spix_val]; + spix += 4; + out_val = ((out_val << 16) | (dpix_val & 0xFFFF)) >>> 0; + buf[dpix + xlinebuffer_pos] = out_val >>> 16; + buf[dpix + xlinebuffer_pos + 1] = out_val & 0xffff; + dpix += 2; + } + if (rem) { + var spix_val = 0; + var dpix_val = 0; + spix_val = ham_linebuf[spix]; + dpix_val = p_xcolors[spix_val]; + spix += 4; + buf[dpix + xlinebuffer_pos] = dpix_val; dpix++; + } + } else if (bpldualpf) { + var lookup = bpldualpfpri ? dblpf_ind2 : dblpf_ind1; + if ((dpix + xlinebuffer_pos) & 2) { + var spix_val = 0; + var dpix_val = 0; + spix_val = pixdata.apixels[spix]; + dpix_val = p_acolors[lookup[spix_val]]; + spix += 4; + buf[dpix + xlinebuffer_pos] = dpix_val; dpix++; + } + if (dpix >= dpix_end) + return spix; + var rem = (dpix_end + xlinebuffer_pos) & 2; + if (rem) + dpix_end--; + while (dpix < dpix_end) { + var spix_val = 0; + var dpix_val = 0; + var out_val = 0; + spix_val = pixdata.apixels[spix]; + dpix_val = p_acolors[lookup[spix_val]]; + spix += 4; + out_val = dpix_val; + spix_val = pixdata.apixels[spix]; + dpix_val = p_acolors[lookup[spix_val]]; + spix += 4; + out_val = ((out_val << 16) | (dpix_val & 0xFFFF)) >>> 0; + buf[dpix + xlinebuffer_pos] = out_val >>> 16; + buf[dpix + xlinebuffer_pos + 1] = out_val & 0xffff; + dpix += 2; + } + if (rem) { + var spix_val = 0; + var dpix_val = 0; + spix_val = pixdata.apixels[spix]; + dpix_val = p_acolors[lookup[spix_val]]; + spix += 4; + buf[dpix + xlinebuffer_pos] = dpix_val; dpix++; + } + } else if (bplehb) { + if ((dpix + xlinebuffer_pos) & 2) { + var spix_val = 0; + var dpix_val = 0; + spix_val = pixdata.apixels[spix]; + if (spix_val <= 31) + dpix_val = p_acolors[spix_val]; + else + dpix_val = p_xcolors[(colors_for_drawing.color_regs_ecs[spix_val - 32] >>> 1) & 0x777]; + spix += 4; + buf[dpix + xlinebuffer_pos] = dpix_val; dpix++; + } + if (dpix >= dpix_end) + return spix; + var rem = (dpix_end + xlinebuffer_pos) & 2; + if (rem) + dpix_end--; + while (dpix < dpix_end) { + var spix_val = 0; + var dpix_val = 0; + var out_val = 0; + spix_val = pixdata.apixels[spix]; + if (spix_val <= 31) + dpix_val = p_acolors[spix_val]; + else + dpix_val = p_xcolors[(colors_for_drawing.color_regs_ecs[spix_val - 32] >>> 1) & 0x777]; + spix += 4; + out_val = dpix_val; + spix_val = pixdata.apixels[spix]; + if (spix_val <= 31) + dpix_val = p_acolors[spix_val]; + else + dpix_val = p_xcolors[(colors_for_drawing.color_regs_ecs[spix_val - 32] >>> 1) & 0x777]; + spix += 4; + out_val = ((out_val << 16) | (dpix_val & 0xFFFF)) >>> 0; + buf[dpix + xlinebuffer_pos] = out_val >>> 16; + buf[dpix + xlinebuffer_pos + 1] = out_val & 0xffff; + dpix += 2; + } + if (rem) { + var spix_val = 0; + var dpix_val = 0; + spix_val = pixdata.apixels[spix]; + if (spix_val <= 31) + dpix_val = p_acolors[spix_val]; + else + dpix_val = p_xcolors[(colors_for_drawing.color_regs_ecs[spix_val - 32] >>> 1) & 0x777]; + spix += 4; + buf[dpix + xlinebuffer_pos] = dpix_val; dpix++; + } + } else { + if ((dpix + xlinebuffer_pos) & 2) { + var spix_val = 0; + var dpix_val = 0; + spix_val = pixdata.apixels[spix]; + dpix_val = p_acolors[spix_val]; + spix += 4; + buf[dpix + xlinebuffer_pos] = dpix_val; dpix++; + } + if (dpix >= dpix_end) + return spix; + var rem = (dpix_end + xlinebuffer_pos) & 2; + if (rem) + dpix_end--; + while (dpix < dpix_end) { + var spix_val = 0; + var dpix_val = 0; + var out_val = 0; + spix_val = pixdata.apixels[spix]; + dpix_val = p_acolors[spix_val]; + spix += 4; + out_val = dpix_val; + spix_val = pixdata.apixels[spix]; + dpix_val = p_acolors[spix_val]; + spix += 4; + out_val = ((out_val << 16) | (dpix_val & 0xFFFF)) >>> 0; + buf[dpix + xlinebuffer_pos] = out_val >>> 16; + buf[dpix + xlinebuffer_pos + 1] = out_val & 0xffff; + dpix += 2; + } + if (rem) { + var spix_val = 0; + var dpix_val = 0; + spix_val = pixdata.apixels[spix]; + dpix_val = p_acolors[spix_val]; + spix += 4; + buf[dpix + xlinebuffer_pos] = dpix_val; dpix++; + } + } + return spix; + } + + function linetoscr_16_shrink2f(spix, dpix, dpix_end) + { + var buf = xlinebuffer; + if (bplham) { + if ((dpix + xlinebuffer_pos) & 2) { + var spix_val = 0; + var dpix_val = 0; + spix_val = ham_linebuf[spix]; + dpix_val = p_xcolors[spix_val]; + { + var tmp_val, tmp_val2, tmp_val3; + spix++; + tmp_val = dpix_val; + spix_val = ham_linebuf[spix]; + dpix_val = p_xcolors[spix_val]; + spix++; + tmp_val2 = dpix_val; + spix_val = ham_linebuf[spix]; + dpix_val = p_xcolors[spix_val]; + spix++; + tmp_val3 = dpix_val; + spix_val = ham_linebuf[spix]; + dpix_val = p_xcolors[spix_val]; + tmp_val = merge_2pixel16(tmp_val, tmp_val2); + tmp_val2 = merge_2pixel16(tmp_val3, dpix_val); + dpix_val = merge_2pixel16(tmp_val, tmp_val2); + spix++; + } + buf[dpix + xlinebuffer_pos] = dpix_val; dpix++; + } + if (dpix >= dpix_end) + return spix; + var rem = (dpix_end + xlinebuffer_pos) & 2; + if (rem) + dpix_end--; + while (dpix < dpix_end) { + var spix_val = 0; + var dpix_val = 0; + var out_val = 0; + spix_val = ham_linebuf[spix]; + dpix_val = p_xcolors[spix_val]; + { + var tmp_val, tmp_val2, tmp_val3; + spix++; + tmp_val = dpix_val; + spix_val = ham_linebuf[spix]; + dpix_val = p_xcolors[spix_val]; + spix++; + tmp_val2 = dpix_val; + spix_val = ham_linebuf[spix]; + dpix_val = p_xcolors[spix_val]; + spix++; + tmp_val3 = dpix_val; + spix_val = ham_linebuf[spix]; + dpix_val = p_xcolors[spix_val]; + tmp_val = merge_2pixel16(tmp_val, tmp_val2); + tmp_val2 = merge_2pixel16(tmp_val3, dpix_val); + dpix_val = merge_2pixel16(tmp_val, tmp_val2); + spix++; + } + out_val = dpix_val; + spix_val = ham_linebuf[spix]; + dpix_val = p_xcolors[spix_val]; + { + var tmp_val, tmp_val2, tmp_val3; + spix++; + tmp_val = dpix_val; + spix_val = ham_linebuf[spix]; + dpix_val = p_xcolors[spix_val]; + spix++; + tmp_val2 = dpix_val; + spix_val = ham_linebuf[spix]; + dpix_val = p_xcolors[spix_val]; + spix++; + tmp_val3 = dpix_val; + spix_val = ham_linebuf[spix]; + dpix_val = p_xcolors[spix_val]; + tmp_val = merge_2pixel16(tmp_val, tmp_val2); + tmp_val2 = merge_2pixel16(tmp_val3, dpix_val); + dpix_val = merge_2pixel16(tmp_val, tmp_val2); + spix++; + } + out_val = ((out_val << 16) | (dpix_val & 0xFFFF)) >>> 0; + buf[dpix + xlinebuffer_pos] = out_val >>> 16; + buf[dpix + xlinebuffer_pos + 1] = out_val & 0xffff; + dpix += 2; + } + if (rem) { + var spix_val = 0; + var dpix_val = 0; + spix_val = ham_linebuf[spix]; + dpix_val = p_xcolors[spix_val]; + { + var tmp_val, tmp_val2, tmp_val3; + spix++; + tmp_val = dpix_val; + spix_val = ham_linebuf[spix]; + dpix_val = p_xcolors[spix_val]; + spix++; + tmp_val2 = dpix_val; + spix_val = ham_linebuf[spix]; + dpix_val = p_xcolors[spix_val]; + spix++; + tmp_val3 = dpix_val; + spix_val = ham_linebuf[spix]; + dpix_val = p_xcolors[spix_val]; + tmp_val = merge_2pixel16(tmp_val, tmp_val2); + tmp_val2 = merge_2pixel16(tmp_val3, dpix_val); + dpix_val = merge_2pixel16(tmp_val, tmp_val2); + spix++; + } + buf[dpix + xlinebuffer_pos] = dpix_val; dpix++; + } + } else if (bpldualpf) { + var lookup = bpldualpfpri ? dblpf_ind2 : dblpf_ind1; + if ((dpix + xlinebuffer_pos) & 2) { + var spix_val = 0; + var dpix_val = 0; + spix_val = pixdata.apixels[spix]; + dpix_val = p_acolors[lookup[spix_val]]; + { + var tmp_val, tmp_val2, tmp_val3; + spix++; + tmp_val = dpix_val; + spix_val = pixdata.apixels[spix]; + dpix_val = p_acolors[lookup[spix_val]]; + spix++; + tmp_val2 = dpix_val; + spix_val = pixdata.apixels[spix]; + dpix_val = p_acolors[lookup[spix_val]]; + spix++; + tmp_val3 = dpix_val; + spix_val = pixdata.apixels[spix]; + dpix_val = p_acolors[lookup[spix_val]]; + tmp_val = merge_2pixel16(tmp_val, tmp_val2); + tmp_val2 = merge_2pixel16(tmp_val3, dpix_val); + dpix_val = merge_2pixel16(tmp_val, tmp_val2); + spix++; + } + buf[dpix + xlinebuffer_pos] = dpix_val; dpix++; + } + if (dpix >= dpix_end) + return spix; + var rem = (dpix_end + xlinebuffer_pos) & 2; + if (rem) + dpix_end--; + while (dpix < dpix_end) { + var spix_val = 0; + var dpix_val = 0; + var out_val = 0; + spix_val = pixdata.apixels[spix]; + dpix_val = p_acolors[lookup[spix_val]]; + { + var tmp_val, tmp_val2, tmp_val3; + spix++; + tmp_val = dpix_val; + spix_val = pixdata.apixels[spix]; + dpix_val = p_acolors[lookup[spix_val]]; + spix++; + tmp_val2 = dpix_val; + spix_val = pixdata.apixels[spix]; + dpix_val = p_acolors[lookup[spix_val]]; + spix++; + tmp_val3 = dpix_val; + spix_val = pixdata.apixels[spix]; + dpix_val = p_acolors[lookup[spix_val]]; + tmp_val = merge_2pixel16(tmp_val, tmp_val2); + tmp_val2 = merge_2pixel16(tmp_val3, dpix_val); + dpix_val = merge_2pixel16(tmp_val, tmp_val2); + spix++; + } + out_val = dpix_val; + spix_val = pixdata.apixels[spix]; + dpix_val = p_acolors[lookup[spix_val]]; + { + var tmp_val, tmp_val2, tmp_val3; + spix++; + tmp_val = dpix_val; + spix_val = pixdata.apixels[spix]; + dpix_val = p_acolors[lookup[spix_val]]; + spix++; + tmp_val2 = dpix_val; + spix_val = pixdata.apixels[spix]; + dpix_val = p_acolors[lookup[spix_val]]; + spix++; + tmp_val3 = dpix_val; + spix_val = pixdata.apixels[spix]; + dpix_val = p_acolors[lookup[spix_val]]; + tmp_val = merge_2pixel16(tmp_val, tmp_val2); + tmp_val2 = merge_2pixel16(tmp_val3, dpix_val); + dpix_val = merge_2pixel16(tmp_val, tmp_val2); + spix++; + } + out_val = ((out_val << 16) | (dpix_val & 0xFFFF)) >>> 0; + buf[dpix + xlinebuffer_pos] = out_val >>> 16; + buf[dpix + xlinebuffer_pos + 1] = out_val & 0xffff; + dpix += 2; + } + if (rem) { + var spix_val = 0; + var dpix_val = 0; + spix_val = pixdata.apixels[spix]; + dpix_val = p_acolors[lookup[spix_val]]; + { + var tmp_val, tmp_val2, tmp_val3; + spix++; + tmp_val = dpix_val; + spix_val = pixdata.apixels[spix]; + dpix_val = p_acolors[lookup[spix_val]]; + spix++; + tmp_val2 = dpix_val; + spix_val = pixdata.apixels[spix]; + dpix_val = p_acolors[lookup[spix_val]]; + spix++; + tmp_val3 = dpix_val; + spix_val = pixdata.apixels[spix]; + dpix_val = p_acolors[lookup[spix_val]]; + tmp_val = merge_2pixel16(tmp_val, tmp_val2); + tmp_val2 = merge_2pixel16(tmp_val3, dpix_val); + dpix_val = merge_2pixel16(tmp_val, tmp_val2); + spix++; + } + buf[dpix + xlinebuffer_pos] = dpix_val; dpix++; + } + } else if (bplehb) { + if ((dpix + xlinebuffer_pos) & 2) { + var spix_val = 0; + var dpix_val = 0; + spix_val = pixdata.apixels[spix]; + if (spix_val <= 31) + dpix_val = p_acolors[spix_val]; + else + dpix_val = p_xcolors[(colors_for_drawing.color_regs_ecs[spix_val - 32] >>> 1) & 0x777]; + { + var tmp_val, tmp_val2, tmp_val3; + spix++; + tmp_val = dpix_val; + spix_val = pixdata.apixels[spix]; + if (spix_val <= 31) + dpix_val = p_acolors[spix_val]; + else + dpix_val = p_xcolors[(colors_for_drawing.color_regs_ecs[spix_val - 32] >>> 1) & 0x777]; + spix++; + tmp_val2 = dpix_val; + spix_val = pixdata.apixels[spix]; + if (spix_val <= 31) + dpix_val = p_acolors[spix_val]; + else + dpix_val = p_xcolors[(colors_for_drawing.color_regs_ecs[spix_val - 32] >>> 1) & 0x777]; + spix++; + tmp_val3 = dpix_val; + spix_val = pixdata.apixels[spix]; + if (spix_val <= 31) + dpix_val = p_acolors[spix_val]; + else + dpix_val = p_xcolors[(colors_for_drawing.color_regs_ecs[spix_val - 32] >>> 1) & 0x777]; + tmp_val = merge_2pixel16(tmp_val, tmp_val2); + tmp_val2 = merge_2pixel16(tmp_val3, dpix_val); + dpix_val = merge_2pixel16(tmp_val, tmp_val2); + spix++; + } + buf[dpix + xlinebuffer_pos] = dpix_val; dpix++; + } + if (dpix >= dpix_end) + return spix; + var rem = (dpix_end + xlinebuffer_pos) & 2; + if (rem) + dpix_end--; + while (dpix < dpix_end) { + var spix_val = 0; + var dpix_val = 0; + var out_val = 0; + spix_val = pixdata.apixels[spix]; + if (spix_val <= 31) + dpix_val = p_acolors[spix_val]; + else + dpix_val = p_xcolors[(colors_for_drawing.color_regs_ecs[spix_val - 32] >>> 1) & 0x777]; + { + var tmp_val, tmp_val2, tmp_val3; + spix++; + tmp_val = dpix_val; + spix_val = pixdata.apixels[spix]; + if (spix_val <= 31) + dpix_val = p_acolors[spix_val]; + else + dpix_val = p_xcolors[(colors_for_drawing.color_regs_ecs[spix_val - 32] >>> 1) & 0x777]; + spix++; + tmp_val2 = dpix_val; + spix_val = pixdata.apixels[spix]; + if (spix_val <= 31) + dpix_val = p_acolors[spix_val]; + else + dpix_val = p_xcolors[(colors_for_drawing.color_regs_ecs[spix_val - 32] >>> 1) & 0x777]; + spix++; + tmp_val3 = dpix_val; + spix_val = pixdata.apixels[spix]; + if (spix_val <= 31) + dpix_val = p_acolors[spix_val]; + else + dpix_val = p_xcolors[(colors_for_drawing.color_regs_ecs[spix_val - 32] >>> 1) & 0x777]; + tmp_val = merge_2pixel16(tmp_val, tmp_val2); + tmp_val2 = merge_2pixel16(tmp_val3, dpix_val); + dpix_val = merge_2pixel16(tmp_val, tmp_val2); + spix++; + } + out_val = dpix_val; + spix_val = pixdata.apixels[spix]; + if (spix_val <= 31) + dpix_val = p_acolors[spix_val]; + else + dpix_val = p_xcolors[(colors_for_drawing.color_regs_ecs[spix_val - 32] >>> 1) & 0x777]; + { + var tmp_val, tmp_val2, tmp_val3; + spix++; + tmp_val = dpix_val; + spix_val = pixdata.apixels[spix]; + if (spix_val <= 31) + dpix_val = p_acolors[spix_val]; + else + dpix_val = p_xcolors[(colors_for_drawing.color_regs_ecs[spix_val - 32] >>> 1) & 0x777]; + spix++; + tmp_val2 = dpix_val; + spix_val = pixdata.apixels[spix]; + if (spix_val <= 31) + dpix_val = p_acolors[spix_val]; + else + dpix_val = p_xcolors[(colors_for_drawing.color_regs_ecs[spix_val - 32] >>> 1) & 0x777]; + spix++; + tmp_val3 = dpix_val; + spix_val = pixdata.apixels[spix]; + if (spix_val <= 31) + dpix_val = p_acolors[spix_val]; + else + dpix_val = p_xcolors[(colors_for_drawing.color_regs_ecs[spix_val - 32] >>> 1) & 0x777]; + tmp_val = merge_2pixel16(tmp_val, tmp_val2); + tmp_val2 = merge_2pixel16(tmp_val3, dpix_val); + dpix_val = merge_2pixel16(tmp_val, tmp_val2); + spix++; + } + out_val = ((out_val << 16) | (dpix_val & 0xFFFF)) >>> 0; + buf[dpix + xlinebuffer_pos] = out_val >>> 16; + buf[dpix + xlinebuffer_pos + 1] = out_val & 0xffff; + dpix += 2; + } + if (rem) { + var spix_val = 0; + var dpix_val = 0; + spix_val = pixdata.apixels[spix]; + if (spix_val <= 31) + dpix_val = p_acolors[spix_val]; + else + dpix_val = p_xcolors[(colors_for_drawing.color_regs_ecs[spix_val - 32] >>> 1) & 0x777]; + { + var tmp_val, tmp_val2, tmp_val3; + spix++; + tmp_val = dpix_val; + spix_val = pixdata.apixels[spix]; + if (spix_val <= 31) + dpix_val = p_acolors[spix_val]; + else + dpix_val = p_xcolors[(colors_for_drawing.color_regs_ecs[spix_val - 32] >>> 1) & 0x777]; + spix++; + tmp_val2 = dpix_val; + spix_val = pixdata.apixels[spix]; + if (spix_val <= 31) + dpix_val = p_acolors[spix_val]; + else + dpix_val = p_xcolors[(colors_for_drawing.color_regs_ecs[spix_val - 32] >>> 1) & 0x777]; + spix++; + tmp_val3 = dpix_val; + spix_val = pixdata.apixels[spix]; + if (spix_val <= 31) + dpix_val = p_acolors[spix_val]; + else + dpix_val = p_xcolors[(colors_for_drawing.color_regs_ecs[spix_val - 32] >>> 1) & 0x777]; + tmp_val = merge_2pixel16(tmp_val, tmp_val2); + tmp_val2 = merge_2pixel16(tmp_val3, dpix_val); + dpix_val = merge_2pixel16(tmp_val, tmp_val2); + spix++; + } + buf[dpix + xlinebuffer_pos] = dpix_val; dpix++; + } + } else { + if ((dpix + xlinebuffer_pos) & 2) { + var spix_val = 0; + var dpix_val = 0; + spix_val = pixdata.apixels[spix]; + dpix_val = p_acolors[spix_val]; + { + var tmp_val, tmp_val2, tmp_val3; + spix++; + tmp_val = dpix_val; + spix_val = pixdata.apixels[spix]; + dpix_val = p_acolors[spix_val]; + spix++; + tmp_val2 = dpix_val; + spix_val = pixdata.apixels[spix]; + dpix_val = p_acolors[spix_val]; + spix++; + tmp_val3 = dpix_val; + spix_val = pixdata.apixels[spix]; + dpix_val = p_acolors[spix_val]; + tmp_val = merge_2pixel16(tmp_val, tmp_val2); + tmp_val2 = merge_2pixel16(tmp_val3, dpix_val); + dpix_val = merge_2pixel16(tmp_val, tmp_val2); + spix++; + } + buf[dpix + xlinebuffer_pos] = dpix_val; dpix++; + } + if (dpix >= dpix_end) + return spix; + var rem = (dpix_end + xlinebuffer_pos) & 2; + if (rem) + dpix_end--; + while (dpix < dpix_end) { + var spix_val = 0; + var dpix_val = 0; + var out_val = 0; + spix_val = pixdata.apixels[spix]; + dpix_val = p_acolors[spix_val]; + { + var tmp_val, tmp_val2, tmp_val3; + spix++; + tmp_val = dpix_val; + spix_val = pixdata.apixels[spix]; + dpix_val = p_acolors[spix_val]; + spix++; + tmp_val2 = dpix_val; + spix_val = pixdata.apixels[spix]; + dpix_val = p_acolors[spix_val]; + spix++; + tmp_val3 = dpix_val; + spix_val = pixdata.apixels[spix]; + dpix_val = p_acolors[spix_val]; + tmp_val = merge_2pixel16(tmp_val, tmp_val2); + tmp_val2 = merge_2pixel16(tmp_val3, dpix_val); + dpix_val = merge_2pixel16(tmp_val, tmp_val2); + spix++; + } + out_val = dpix_val; + spix_val = pixdata.apixels[spix]; + dpix_val = p_acolors[spix_val]; + { + var tmp_val, tmp_val2, tmp_val3; + spix++; + tmp_val = dpix_val; + spix_val = pixdata.apixels[spix]; + dpix_val = p_acolors[spix_val]; + spix++; + tmp_val2 = dpix_val; + spix_val = pixdata.apixels[spix]; + dpix_val = p_acolors[spix_val]; + spix++; + tmp_val3 = dpix_val; + spix_val = pixdata.apixels[spix]; + dpix_val = p_acolors[spix_val]; + tmp_val = merge_2pixel16(tmp_val, tmp_val2); + tmp_val2 = merge_2pixel16(tmp_val3, dpix_val); + dpix_val = merge_2pixel16(tmp_val, tmp_val2); + spix++; + } + out_val = ((out_val << 16) | (dpix_val & 0xFFFF)) >>> 0; + buf[dpix + xlinebuffer_pos] = out_val >>> 16; + buf[dpix + xlinebuffer_pos + 1] = out_val & 0xffff; + dpix += 2; + } + if (rem) { + var spix_val = 0; + var dpix_val = 0; + spix_val = pixdata.apixels[spix]; + dpix_val = p_acolors[spix_val]; + { + var tmp_val, tmp_val2, tmp_val3; + spix++; + tmp_val = dpix_val; + spix_val = pixdata.apixels[spix]; + dpix_val = p_acolors[spix_val]; + spix++; + tmp_val2 = dpix_val; + spix_val = pixdata.apixels[spix]; + dpix_val = p_acolors[spix_val]; + spix++; + tmp_val3 = dpix_val; + spix_val = pixdata.apixels[spix]; + dpix_val = p_acolors[spix_val]; + tmp_val = merge_2pixel16(tmp_val, tmp_val2); + tmp_val2 = merge_2pixel16(tmp_val3, dpix_val); + dpix_val = merge_2pixel16(tmp_val, tmp_val2); + spix++; + } + buf[dpix + xlinebuffer_pos] = dpix_val; dpix++; + } + } + return spix; + } + + function linetoscr_16_spr(spix, dpix, dpix_end) + { + var buf = xlinebuffer; + var sprcol = 0; + if (bplham) { + while (dpix < dpix_end) { + var sprpix_val = 0; + var spix_val = 0; + var dpix_val = 0; + var out_val = 0; + spix_val = ham_linebuf[spix]; + dpix_val = p_xcolors[spix_val]; + sprpix_val = pixdata.apixels[spix]; + spix++; + out_val = dpix_val; + if (spritepixels[dpix + spritepixels_pos].data) { + sprcol = render_sprites(dpix, 0, sprpix_val, 0); + if (sprcol) { + var spcol = p_acolors[sprcol]; + out_val = spcol; + } + } + buf[dpix + xlinebuffer_pos] = out_val; dpix++; + } + } else if (bpldualpf) { + var lookup = bpldualpfpri ? dblpf_ind2 : dblpf_ind1; + while (dpix < dpix_end) { + var sprpix_val = 0; + var spix_val = 0; + var dpix_val = 0; + var out_val = 0; + spix_val = pixdata.apixels[spix]; + sprpix_val = spix_val; + dpix_val = p_acolors[lookup[spix_val]]; + spix++; + out_val = dpix_val; + if (spritepixels[dpix + spritepixels_pos].data) { + sprcol = render_sprites(dpix, 1, sprpix_val, 0); + if (sprcol) { + var spcol = p_acolors[sprcol]; + out_val = spcol; + } + } + buf[dpix + xlinebuffer_pos] = out_val; dpix++; + } + } else if (bplehb) { + while (dpix < dpix_end) { + var sprpix_val = 0; + var spix_val = 0; + var dpix_val = 0; + var out_val = 0; + spix_val = pixdata.apixels[spix]; + sprpix_val = spix_val; + if (spix_val <= 31) + dpix_val = p_acolors[spix_val]; + else + dpix_val = p_xcolors[(colors_for_drawing.color_regs_ecs[spix_val - 32] >>> 1) & 0x777]; + spix++; + out_val = dpix_val; + if (spritepixels[dpix + spritepixels_pos].data) { + sprcol = render_sprites(dpix, 0, sprpix_val, 0); + if (sprcol) { + var spcol = p_acolors[sprcol]; + out_val = spcol; + } + } + buf[dpix + xlinebuffer_pos] = out_val; dpix++; + } + } else { + while (dpix < dpix_end) { + var sprpix_val = 0; + var spix_val = 0; + var dpix_val = 0; + var out_val = 0; + spix_val = pixdata.apixels[spix]; + sprpix_val = spix_val; + dpix_val = p_acolors[spix_val]; + spix++; + out_val = dpix_val; + if (spritepixels[dpix + spritepixels_pos].data) { + sprcol = render_sprites(dpix, 0, sprpix_val, 0); + if (sprcol) { + var spcol = p_acolors[sprcol]; + out_val = spcol; + } + } + buf[dpix + xlinebuffer_pos] = out_val; dpix++; + } + } + return spix; + } + + function linetoscr_16_stretch1_spr(spix, dpix, dpix_end) + { + var buf = xlinebuffer; + var sprcol = 0; + if (bplham) { + while (dpix < dpix_end) { + var sprpix_val = 0; + var spix_val = 0; + var dpix_val = 0; + var out_val = 0; + spix_val = ham_linebuf[spix]; + dpix_val = p_xcolors[spix_val]; + sprpix_val = pixdata.apixels[spix]; + spix++; + out_val = dpix_val; + if (spritepixels[dpix + spritepixels_pos].data) { + sprcol = render_sprites(dpix, 0, sprpix_val, 0); + if (sprcol) { + var spcol = p_acolors[sprcol]; + out_val = spcol; + } + } + buf[dpix + xlinebuffer_pos] = out_val; dpix++; + buf[dpix + xlinebuffer_pos] = out_val; dpix++; + } + } else if (bpldualpf) { + var lookup = bpldualpfpri ? dblpf_ind2 : dblpf_ind1; + while (dpix < dpix_end) { + var sprpix_val = 0; + var spix_val = 0; + var dpix_val = 0; + var out_val = 0; + spix_val = pixdata.apixels[spix]; + sprpix_val = spix_val; + dpix_val = p_acolors[lookup[spix_val]]; + spix++; + out_val = dpix_val; + if (spritepixels[dpix + spritepixels_pos].data) { + sprcol = render_sprites(dpix, 1, sprpix_val, 0); + if (sprcol) { + var spcol = p_acolors[sprcol]; + out_val = spcol; + } + } + buf[dpix + xlinebuffer_pos] = out_val; dpix++; + buf[dpix + xlinebuffer_pos] = out_val; dpix++; + } + } else if (bplehb) { + while (dpix < dpix_end) { + var sprpix_val = 0; + var spix_val = 0; + var dpix_val = 0; + var out_val = 0; + spix_val = pixdata.apixels[spix]; + sprpix_val = spix_val; + if (spix_val <= 31) + dpix_val = p_acolors[spix_val]; + else + dpix_val = p_xcolors[(colors_for_drawing.color_regs_ecs[spix_val - 32] >>> 1) & 0x777]; + spix++; + out_val = dpix_val; + if (spritepixels[dpix + spritepixels_pos].data) { + sprcol = render_sprites(dpix, 0, sprpix_val, 0); + if (sprcol) { + var spcol = p_acolors[sprcol]; + out_val = spcol; + } + } + buf[dpix + xlinebuffer_pos] = out_val; dpix++; + buf[dpix + xlinebuffer_pos] = out_val; dpix++; + } + } else { + while (dpix < dpix_end) { + var sprpix_val = 0; + var spix_val = 0; + var dpix_val = 0; + var out_val = 0; + spix_val = pixdata.apixels[spix]; + sprpix_val = spix_val; + dpix_val = p_acolors[spix_val]; + spix++; + out_val = dpix_val; + if (spritepixels[dpix + spritepixels_pos].data) { + sprcol = render_sprites(dpix, 0, sprpix_val, 0); + if (sprcol) { + var spcol = p_acolors[sprcol]; + out_val = spcol; + } + } + buf[dpix + xlinebuffer_pos] = out_val; dpix++; + buf[dpix + xlinebuffer_pos] = out_val; dpix++; + } + } + return spix; + } + + function linetoscr_16_stretch2_spr(spix, dpix, dpix_end) + { + var buf = xlinebuffer; + var sprcol = 0; + if (bplham) { + while (dpix < dpix_end) { + var sprpix_val = 0; + var spix_val = 0; + var dpix_val = 0; + var out_val = 0; + spix_val = ham_linebuf[spix]; + dpix_val = p_xcolors[spix_val]; + sprpix_val = pixdata.apixels[spix]; + spix++; + out_val = dpix_val; + if (spritepixels[dpix + spritepixels_pos].data) { + sprcol = render_sprites(dpix, 0, sprpix_val, 0); + if (sprcol) { + var spcol = p_acolors[sprcol]; + out_val = spcol; + } + } + buf[dpix + xlinebuffer_pos] = out_val; dpix++; + buf[dpix + xlinebuffer_pos] = out_val; dpix++; + buf[dpix + xlinebuffer_pos] = out_val; dpix++; + buf[dpix + xlinebuffer_pos] = out_val; dpix++; + } + } else if (bpldualpf) { + var lookup = bpldualpfpri ? dblpf_ind2 : dblpf_ind1; + while (dpix < dpix_end) { + var sprpix_val = 0; + var spix_val = 0; + var dpix_val = 0; + var out_val = 0; + spix_val = pixdata.apixels[spix]; + sprpix_val = spix_val; + dpix_val = p_acolors[lookup[spix_val]]; + spix++; + out_val = dpix_val; + if (spritepixels[dpix + spritepixels_pos].data) { + sprcol = render_sprites(dpix, 1, sprpix_val, 0); + if (sprcol) { + var spcol = p_acolors[sprcol]; + out_val = spcol; + } + } + buf[dpix + xlinebuffer_pos] = out_val; dpix++; + buf[dpix + xlinebuffer_pos] = out_val; dpix++; + buf[dpix + xlinebuffer_pos] = out_val; dpix++; + buf[dpix + xlinebuffer_pos] = out_val; dpix++; + } + } else if (bplehb) { + while (dpix < dpix_end) { + var sprpix_val = 0; + var spix_val = 0; + var dpix_val = 0; + var out_val = 0; + spix_val = pixdata.apixels[spix]; + sprpix_val = spix_val; + if (spix_val <= 31) + dpix_val = p_acolors[spix_val]; + else + dpix_val = p_xcolors[(colors_for_drawing.color_regs_ecs[spix_val - 32] >>> 1) & 0x777]; + spix++; + out_val = dpix_val; + if (spritepixels[dpix + spritepixels_pos].data) { + sprcol = render_sprites(dpix, 0, sprpix_val, 0); + if (sprcol) { + var spcol = p_acolors[sprcol]; + out_val = spcol; + } + } + buf[dpix + xlinebuffer_pos] = out_val; dpix++; + buf[dpix + xlinebuffer_pos] = out_val; dpix++; + buf[dpix + xlinebuffer_pos] = out_val; dpix++; + buf[dpix + xlinebuffer_pos] = out_val; dpix++; + } + } else { + while (dpix < dpix_end) { + var sprpix_val = 0; + var spix_val = 0; + var dpix_val = 0; + var out_val = 0; + spix_val = pixdata.apixels[spix]; + sprpix_val = spix_val; + dpix_val = p_acolors[spix_val]; + spix++; + out_val = dpix_val; + if (spritepixels[dpix + spritepixels_pos].data) { + sprcol = render_sprites(dpix, 0, sprpix_val, 0); + if (sprcol) { + var spcol = p_acolors[sprcol]; + out_val = spcol; + } + } + buf[dpix + xlinebuffer_pos] = out_val; dpix++; + buf[dpix + xlinebuffer_pos] = out_val; dpix++; + buf[dpix + xlinebuffer_pos] = out_val; dpix++; + buf[dpix + xlinebuffer_pos] = out_val; dpix++; + } + } + return spix; + } + + function linetoscr_16_shrink1_spr(spix, dpix, dpix_end) + { + var buf = xlinebuffer; + var sprcol = 0; + if (bplham) { + while (dpix < dpix_end) { + var sprpix_val = 0; + var spix_val = 0; + var dpix_val = 0; + var out_val = 0; + spix_val = ham_linebuf[spix]; + dpix_val = p_xcolors[spix_val]; + sprpix_val = pixdata.apixels[spix]; + spix += 2; + out_val = dpix_val; + if (spritepixels[dpix + spritepixels_pos].data) { + sprcol = render_sprites(dpix, 0, sprpix_val, 0); + if (sprcol) { + var spcol = p_acolors[sprcol]; + out_val = spcol; + } + } + buf[dpix + xlinebuffer_pos] = out_val; dpix++; + } + } else if (bpldualpf) { + var lookup = bpldualpfpri ? dblpf_ind2 : dblpf_ind1; + while (dpix < dpix_end) { + var sprpix_val = 0; + var spix_val = 0; + var dpix_val = 0; + var out_val = 0; + spix_val = pixdata.apixels[spix]; + sprpix_val = spix_val; + dpix_val = p_acolors[lookup[spix_val]]; + spix += 2; + out_val = dpix_val; + if (spritepixels[dpix + spritepixels_pos].data) { + sprcol = render_sprites(dpix, 1, sprpix_val, 0); + if (sprcol) { + var spcol = p_acolors[sprcol]; + out_val = spcol; + } + } + buf[dpix + xlinebuffer_pos] = out_val; dpix++; + } + } else if (bplehb) { + while (dpix < dpix_end) { + var sprpix_val = 0; + var spix_val = 0; + var dpix_val = 0; + var out_val = 0; + spix_val = pixdata.apixels[spix]; + sprpix_val = spix_val; + if (spix_val <= 31) + dpix_val = p_acolors[spix_val]; + else + dpix_val = p_xcolors[(colors_for_drawing.color_regs_ecs[spix_val - 32] >>> 1) & 0x777]; + spix += 2; + out_val = dpix_val; + if (spritepixels[dpix + spritepixels_pos].data) { + sprcol = render_sprites(dpix, 0, sprpix_val, 0); + if (sprcol) { + var spcol = p_acolors[sprcol]; + out_val = spcol; + } + } + buf[dpix + xlinebuffer_pos] = out_val; dpix++; + } + } else { + while (dpix < dpix_end) { + var sprpix_val = 0; + var spix_val = 0; + var dpix_val = 0; + var out_val = 0; + spix_val = pixdata.apixels[spix]; + sprpix_val = spix_val; + dpix_val = p_acolors[spix_val]; + spix += 2; + out_val = dpix_val; + if (spritepixels[dpix + spritepixels_pos].data) { + sprcol = render_sprites(dpix, 0, sprpix_val, 0); + if (sprcol) { + var spcol = p_acolors[sprcol]; + out_val = spcol; + } + } + buf[dpix + xlinebuffer_pos] = out_val; dpix++; + } + } + return spix; + } + + function linetoscr_16_shrink1f_spr(spix, dpix, dpix_end) + { + var buf = xlinebuffer; + var sprcol = 0; + if (bplham) { + while (dpix < dpix_end) { + var sprpix_val = 0; + var spix_val = 0; + var dpix_val = 0; + var out_val = 0; + spix_val = ham_linebuf[spix]; + dpix_val = p_xcolors[spix_val]; + sprpix_val = pixdata.apixels[spix]; + { + var tmp_val; + spix++; + tmp_val = dpix_val; + spix_val = ham_linebuf[spix]; + dpix_val = p_xcolors[spix_val]; + sprpix_val = pixdata.apixels[spix]; + dpix_val = merge_2pixel16(dpix_val, tmp_val); + spix++; + } + out_val = dpix_val; + if (spritepixels[dpix + spritepixels_pos].data) { + sprcol = render_sprites(dpix, 0, sprpix_val, 0); + if (sprcol) { + var spcol = p_acolors[sprcol]; + out_val = spcol; + } + } + buf[dpix + xlinebuffer_pos] = out_val; dpix++; + } + } else if (bpldualpf) { + var lookup = bpldualpfpri ? dblpf_ind2 : dblpf_ind1; + while (dpix < dpix_end) { + var sprpix_val = 0; + var spix_val = 0; + var dpix_val = 0; + var out_val = 0; + spix_val = pixdata.apixels[spix]; + sprpix_val = spix_val; + dpix_val = p_acolors[lookup[spix_val]]; + { + var tmp_val; + spix++; + tmp_val = dpix_val; + spix_val = pixdata.apixels[spix]; + sprpix_val = spix_val; + dpix_val = p_acolors[lookup[spix_val]]; + dpix_val = merge_2pixel16(dpix_val, tmp_val); + spix++; + } + out_val = dpix_val; + if (spritepixels[dpix + spritepixels_pos].data) { + sprcol = render_sprites(dpix, 1, sprpix_val, 0); + if (sprcol) { + var spcol = p_acolors[sprcol]; + out_val = spcol; + } + } + buf[dpix + xlinebuffer_pos] = out_val; dpix++; + } + } else if (bplehb) { + while (dpix < dpix_end) { + var sprpix_val = 0; + var spix_val = 0; + var dpix_val = 0; + var out_val = 0; + spix_val = pixdata.apixels[spix]; + sprpix_val = spix_val; + if (spix_val <= 31) + dpix_val = p_acolors[spix_val]; + else + dpix_val = p_xcolors[(colors_for_drawing.color_regs_ecs[spix_val - 32] >>> 1) & 0x777]; + { + var tmp_val; + spix++; + tmp_val = dpix_val; + spix_val = pixdata.apixels[spix]; + sprpix_val = spix_val; + if (spix_val <= 31) + dpix_val = p_acolors[spix_val]; + else + dpix_val = p_xcolors[(colors_for_drawing.color_regs_ecs[spix_val - 32] >>> 1) & 0x777]; + dpix_val = merge_2pixel16(dpix_val, tmp_val); + spix++; + } + out_val = dpix_val; + if (spritepixels[dpix + spritepixels_pos].data) { + sprcol = render_sprites(dpix, 0, sprpix_val, 0); + if (sprcol) { + var spcol = p_acolors[sprcol]; + out_val = spcol; + } + } + buf[dpix + xlinebuffer_pos] = out_val; dpix++; + } + } else { + while (dpix < dpix_end) { + var sprpix_val = 0; + var spix_val = 0; + var dpix_val = 0; + var out_val = 0; + spix_val = pixdata.apixels[spix]; + sprpix_val = spix_val; + dpix_val = p_acolors[spix_val]; + { + var tmp_val; + spix++; + tmp_val = dpix_val; + spix_val = pixdata.apixels[spix]; + sprpix_val = spix_val; + dpix_val = p_acolors[spix_val]; + dpix_val = merge_2pixel16(dpix_val, tmp_val); + spix++; + } + out_val = dpix_val; + if (spritepixels[dpix + spritepixels_pos].data) { + sprcol = render_sprites(dpix, 0, sprpix_val, 0); + if (sprcol) { + var spcol = p_acolors[sprcol]; + out_val = spcol; + } + } + buf[dpix + xlinebuffer_pos] = out_val; dpix++; + } + } + return spix; + } + + function linetoscr_16_shrink2_spr(spix, dpix, dpix_end) + { + var buf = xlinebuffer; + var sprcol = 0; + if (bplham) { + while (dpix < dpix_end) { + var sprpix_val = 0; + var spix_val = 0; + var dpix_val = 0; + var out_val = 0; + spix_val = ham_linebuf[spix]; + dpix_val = p_xcolors[spix_val]; + sprpix_val = pixdata.apixels[spix]; + spix += 4; + out_val = dpix_val; + if (spritepixels[dpix + spritepixels_pos].data) { + sprcol = render_sprites(dpix, 0, sprpix_val, 0); + if (sprcol) { + var spcol = p_acolors[sprcol]; + out_val = spcol; + } + } + buf[dpix + xlinebuffer_pos] = out_val; dpix++; + } + } else if (bpldualpf) { + var lookup = bpldualpfpri ? dblpf_ind2 : dblpf_ind1; + while (dpix < dpix_end) { + var sprpix_val = 0; + var spix_val = 0; + var dpix_val = 0; + var out_val = 0; + spix_val = pixdata.apixels[spix]; + sprpix_val = spix_val; + dpix_val = p_acolors[lookup[spix_val]]; + spix += 4; + out_val = dpix_val; + if (spritepixels[dpix + spritepixels_pos].data) { + sprcol = render_sprites(dpix, 1, sprpix_val, 0); + if (sprcol) { + var spcol = p_acolors[sprcol]; + out_val = spcol; + } + } + buf[dpix + xlinebuffer_pos] = out_val; dpix++; + } + } else if (bplehb) { + while (dpix < dpix_end) { + var sprpix_val = 0; + var spix_val = 0; + var dpix_val = 0; + var out_val = 0; + spix_val = pixdata.apixels[spix]; + sprpix_val = spix_val; + if (spix_val <= 31) + dpix_val = p_acolors[spix_val]; + else + dpix_val = p_xcolors[(colors_for_drawing.color_regs_ecs[spix_val - 32] >>> 1) & 0x777]; + spix += 4; + out_val = dpix_val; + if (spritepixels[dpix + spritepixels_pos].data) { + sprcol = render_sprites(dpix, 0, sprpix_val, 0); + if (sprcol) { + var spcol = p_acolors[sprcol]; + out_val = spcol; + } + } + buf[dpix + xlinebuffer_pos] = out_val; dpix++; + } + } else { + while (dpix < dpix_end) { + var sprpix_val = 0; + var spix_val = 0; + var dpix_val = 0; + var out_val = 0; + spix_val = pixdata.apixels[spix]; + sprpix_val = spix_val; + dpix_val = p_acolors[spix_val]; + spix += 4; + out_val = dpix_val; + if (spritepixels[dpix + spritepixels_pos].data) { + sprcol = render_sprites(dpix, 0, sprpix_val, 0); + if (sprcol) { + var spcol = p_acolors[sprcol]; + out_val = spcol; + } + } + buf[dpix + xlinebuffer_pos] = out_val; dpix++; + } + } + return spix; + } + + function linetoscr_16_shrink2f_spr(spix, dpix, dpix_end) + { + var buf = xlinebuffer; + var sprcol = 0; + if (bplham) { + while (dpix < dpix_end) { + var sprpix_val = 0; + var spix_val = 0; + var dpix_val = 0; + var out_val = 0; + spix_val = ham_linebuf[spix]; + dpix_val = p_xcolors[spix_val]; + sprpix_val = pixdata.apixels[spix]; + { + var tmp_val, tmp_val2, tmp_val3; + spix++; + tmp_val = dpix_val; + spix_val = ham_linebuf[spix]; + dpix_val = p_xcolors[spix_val]; + sprpix_val = pixdata.apixels[spix]; + spix++; + tmp_val2 = dpix_val; + spix_val = ham_linebuf[spix]; + dpix_val = p_xcolors[spix_val]; + sprpix_val = pixdata.apixels[spix]; + spix++; + tmp_val3 = dpix_val; + spix_val = ham_linebuf[spix]; + dpix_val = p_xcolors[spix_val]; + sprpix_val = pixdata.apixels[spix]; + tmp_val = merge_2pixel16(tmp_val, tmp_val2); + tmp_val2 = merge_2pixel16(tmp_val3, dpix_val); + dpix_val = merge_2pixel16(tmp_val, tmp_val2); + spix++; + } + out_val = dpix_val; + if (spritepixels[dpix + spritepixels_pos].data) { + sprcol = render_sprites(dpix, 0, sprpix_val, 0); + if (sprcol) { + var spcol = p_acolors[sprcol]; + out_val = spcol; + } + } + buf[dpix + xlinebuffer_pos] = out_val; dpix++; + } + } else if (bpldualpf) { + var lookup = bpldualpfpri ? dblpf_ind2 : dblpf_ind1; + while (dpix < dpix_end) { + var sprpix_val = 0; + var spix_val = 0; + var dpix_val = 0; + var out_val = 0; + spix_val = pixdata.apixels[spix]; + sprpix_val = spix_val; + dpix_val = p_acolors[lookup[spix_val]]; + { + var tmp_val, tmp_val2, tmp_val3; + spix++; + tmp_val = dpix_val; + spix_val = pixdata.apixels[spix]; + sprpix_val = spix_val; + dpix_val = p_acolors[lookup[spix_val]]; + spix++; + tmp_val2 = dpix_val; + spix_val = pixdata.apixels[spix]; + sprpix_val = spix_val; + dpix_val = p_acolors[lookup[spix_val]]; + spix++; + tmp_val3 = dpix_val; + spix_val = pixdata.apixels[spix]; + sprpix_val = spix_val; + dpix_val = p_acolors[lookup[spix_val]]; + tmp_val = merge_2pixel16(tmp_val, tmp_val2); + tmp_val2 = merge_2pixel16(tmp_val3, dpix_val); + dpix_val = merge_2pixel16(tmp_val, tmp_val2); + spix++; + } + out_val = dpix_val; + if (spritepixels[dpix + spritepixels_pos].data) { + sprcol = render_sprites(dpix, 1, sprpix_val, 0); + if (sprcol) { + var spcol = p_acolors[sprcol]; + out_val = spcol; + } + } + buf[dpix + xlinebuffer_pos] = out_val; dpix++; + } + } else if (bplehb) { + while (dpix < dpix_end) { + var sprpix_val = 0; + var spix_val = 0; + var dpix_val = 0; + var out_val = 0; + spix_val = pixdata.apixels[spix]; + sprpix_val = spix_val; + if (spix_val <= 31) + dpix_val = p_acolors[spix_val]; + else + dpix_val = p_xcolors[(colors_for_drawing.color_regs_ecs[spix_val - 32] >>> 1) & 0x777]; + { + var tmp_val, tmp_val2, tmp_val3; + spix++; + tmp_val = dpix_val; + spix_val = pixdata.apixels[spix]; + sprpix_val = spix_val; + if (spix_val <= 31) + dpix_val = p_acolors[spix_val]; + else + dpix_val = p_xcolors[(colors_for_drawing.color_regs_ecs[spix_val - 32] >>> 1) & 0x777]; + spix++; + tmp_val2 = dpix_val; + spix_val = pixdata.apixels[spix]; + sprpix_val = spix_val; + if (spix_val <= 31) + dpix_val = p_acolors[spix_val]; + else + dpix_val = p_xcolors[(colors_for_drawing.color_regs_ecs[spix_val - 32] >>> 1) & 0x777]; + spix++; + tmp_val3 = dpix_val; + spix_val = pixdata.apixels[spix]; + sprpix_val = spix_val; + if (spix_val <= 31) + dpix_val = p_acolors[spix_val]; + else + dpix_val = p_xcolors[(colors_for_drawing.color_regs_ecs[spix_val - 32] >>> 1) & 0x777]; + tmp_val = merge_2pixel16(tmp_val, tmp_val2); + tmp_val2 = merge_2pixel16(tmp_val3, dpix_val); + dpix_val = merge_2pixel16(tmp_val, tmp_val2); + spix++; + } + out_val = dpix_val; + if (spritepixels[dpix + spritepixels_pos].data) { + sprcol = render_sprites(dpix, 0, sprpix_val, 0); + if (sprcol) { + var spcol = p_acolors[sprcol]; + out_val = spcol; + } + } + buf[dpix + xlinebuffer_pos] = out_val; dpix++; + } + } else { + while (dpix < dpix_end) { + var sprpix_val = 0; + var spix_val = 0; + var dpix_val = 0; + var out_val = 0; + spix_val = pixdata.apixels[spix]; + sprpix_val = spix_val; + dpix_val = p_acolors[spix_val]; + { + var tmp_val, tmp_val2, tmp_val3; + spix++; + tmp_val = dpix_val; + spix_val = pixdata.apixels[spix]; + sprpix_val = spix_val; + dpix_val = p_acolors[spix_val]; + spix++; + tmp_val2 = dpix_val; + spix_val = pixdata.apixels[spix]; + sprpix_val = spix_val; + dpix_val = p_acolors[spix_val]; + spix++; + tmp_val3 = dpix_val; + spix_val = pixdata.apixels[spix]; + sprpix_val = spix_val; + dpix_val = p_acolors[spix_val]; + tmp_val = merge_2pixel16(tmp_val, tmp_val2); + tmp_val2 = merge_2pixel16(tmp_val3, dpix_val); + dpix_val = merge_2pixel16(tmp_val, tmp_val2); + spix++; + } + out_val = dpix_val; + if (spritepixels[dpix + spritepixels_pos].data) { + sprcol = render_sprites(dpix, 0, sprpix_val, 0); + if (sprcol) { + var spcol = p_acolors[sprcol]; + out_val = spcol; + } + } + buf[dpix + xlinebuffer_pos] = out_val; dpix++; + } + } + return spix; + } + + function linetoscr_16_aga_spronly(spix, dpix, dpix_end) + { + var buf = xlinebuffer; + var sprcol = 0; + if (1) { + while (dpix < dpix_end) { + var sprpix_val = 0; + var out_val = 0; + spix++; + out_val = p_acolors[0]; + if (spritepixels[dpix + spritepixels_pos].data) { + sprcol = render_sprites(dpix + 0, 0, sprpix_val, 1); + if (sprcol) { + out_val = p_acolors[sprcol]; + } + } + buf[dpix + xlinebuffer_pos] = out_val; dpix++; + } + } + return spix; + } + + function linetoscr_16_stretch1_aga_spronly(spix, dpix, dpix_end) + { + var buf = xlinebuffer; + var sprcol = 0; + if (1) { + while (dpix < dpix_end) { + var sprpix_val = 0; + var out_val = 0; + spix++; + out_val = p_acolors[0]; + { + var out_val1 = out_val; + var out_val2 = out_val; + if (spritepixels[dpix + spritepixels_pos].data) { + sprcol = render_sprites(dpix, 0, sprpix_val, 1); + if (sprcol) { + out_val1 = p_acolors[sprcol]; + } + } + if (spritepixels[dpix + spritepixels_pos + 1].data) { + sprcol = render_sprites(dpix + 1, 0, sprpix_val, 1); + if (sprcol) { + out_val2 = p_acolors[sprcol]; + } + } + buf[dpix + xlinebuffer_pos] = out_val1; dpix++; + buf[dpix + xlinebuffer_pos] = out_val2; dpix++; + } + } + } + return spix; + } + + function linetoscr_16_stretch2_aga_spronly(spix, dpix, dpix_end) + { + var buf = xlinebuffer; + var sprcol = 0; + if (1) { + while (dpix < dpix_end) { + var sprpix_val = 0; + var out_val = 0; + spix++; + out_val = p_acolors[0]; + { + var out_val1 = out_val; + var out_val2 = out_val; + var out_val3 = out_val; + var out_val4 = out_val; + if (spritepixels[dpix + spritepixels_pos].data) { + var sprcol = render_sprites(dpix, 0, sprpix_val, 1); + if (sprcol) { + out_val1 = p_acolors[sprcol]; + } + } + if (spritepixels[dpix + spritepixels_pos + 1].data) { + sprcol = render_sprites(dpix + 1, 0, sprpix_val, 1); + if (sprcol) { + out_val2 = p_acolors[sprcol]; + } + } + if (spritepixels[dpix + spritepixels_pos + 2].data) { + sprcol = render_sprites(dpix + 2, 0, sprpix_val, 1); + if (sprcol) { + out_val3 = p_acolors[sprcol]; + } + } + if (spritepixels[dpix + spritepixels_pos + 3].data) { + sprcol = render_sprites(dpix + 3, 0, sprpix_val, 1); + if (sprcol) { + out_val4 = p_acolors[sprcol]; + } + } + buf[dpix + xlinebuffer_pos] = out_val1; dpix++; + buf[dpix + xlinebuffer_pos] = out_val2; dpix++; + buf[dpix + xlinebuffer_pos] = out_val3; dpix++; + buf[dpix + xlinebuffer_pos] = out_val4; dpix++; + } + } + } + return spix; + } + + function linetoscr_16_shrink1_aga_spronly(spix, dpix, dpix_end) + { + var buf = xlinebuffer; + var sprcol = 0; + if (1) { + while (dpix < dpix_end) { + var sprpix_val = 0; + var out_val = 0; + spix++; + out_val = p_acolors[0]; + if (spritepixels[dpix + spritepixels_pos].data) { + sprcol = render_sprites(dpix + 0, 0, sprpix_val, 1); + if (sprcol) { + out_val = p_acolors[sprcol]; + } + } + buf[dpix + xlinebuffer_pos] = out_val; dpix++; + } + } + return spix; + } + + function linetoscr_16_shrink1f_aga_spronly(spix, dpix, dpix_end) + { + var buf = xlinebuffer; + var sprcol = 0; + if (1) { + while (dpix < dpix_end) { + var sprpix_val = 0; + var out_val = 0; + spix++; + out_val = p_acolors[0]; + if (spritepixels[dpix + spritepixels_pos].data) { + sprcol = render_sprites(dpix + 0, 0, sprpix_val, 1); + if (sprcol) { + out_val = p_acolors[sprcol]; + } + } + buf[dpix + xlinebuffer_pos] = out_val; dpix++; + } + } + return spix; + } + + function linetoscr_16_shrink2_aga_spronly(spix, dpix, dpix_end) + { + var buf = xlinebuffer; + var sprcol = 0; + if (1) { + while (dpix < dpix_end) { + var sprpix_val = 0; + var out_val = 0; + spix++; + out_val = p_acolors[0]; + if (spritepixels[dpix + spritepixels_pos].data) { + sprcol = render_sprites(dpix + 0, 0, sprpix_val, 1); + if (sprcol) { + out_val = p_acolors[sprcol]; + } + } + buf[dpix + xlinebuffer_pos] = out_val; dpix++; + } + } + return spix; + } + + function linetoscr_16_shrink2f_aga_spronly(spix, dpix, dpix_end) + { + var buf = xlinebuffer; + var sprcol = 0; + if (1) { + while (dpix < dpix_end) { + var sprpix_val = 0; + var out_val = 0; + spix++; + out_val = p_acolors[0]; + if (spritepixels[dpix + spritepixels_pos].data) { + sprcol = render_sprites(dpix + 0, 0, sprpix_val, 1); + if (sprcol) { + out_val = p_acolors[sprcol]; + } + } + buf[dpix + xlinebuffer_pos] = out_val; dpix++; + } + } + return spix; + } + + function linetoscr_16_aga(spix, dpix, dpix_end) + { + var buf = xlinebuffer; + var xor_val = bplxor; + var and_val = bpland; + if (bplham) { + if ((dpix + xlinebuffer_pos) & 2) { + var spix_val = 0; + var dpix_val = 0; + spix_val = (pixdata.apixels[spix] ^ xor_val) & and_val; + spix_val = ham_linebuf[spix]; + dpix_val = CONVERT_RGB(spix_val); + spix++; + buf[dpix + xlinebuffer_pos] = dpix_val; dpix++; + } + if (dpix >= dpix_end) + return spix; + var rem = (dpix_end + xlinebuffer_pos) & 2; + if (rem) + dpix_end--; + while (dpix < dpix_end) { + var spix_val = 0; + var dpix_val = 0; + var out_val = 0; + spix_val = (pixdata.apixels[spix] ^ xor_val) & and_val; + spix_val = ham_linebuf[spix]; + dpix_val = CONVERT_RGB(spix_val); + spix++; + out_val = dpix_val; + spix_val = (pixdata.apixels[spix] ^ xor_val) & and_val; + spix_val = ham_linebuf[spix]; + dpix_val = CONVERT_RGB(spix_val); + spix++; + out_val = ((out_val << 16) | (dpix_val & 0xFFFF)) >>> 0; + buf[dpix + xlinebuffer_pos] = out_val >>> 16; + buf[dpix + xlinebuffer_pos + 1] = out_val & 0xffff; + dpix += 2; + } + if (rem) { + var spix_val = 0; + var dpix_val = 0; + spix_val = (pixdata.apixels[spix] ^ xor_val) & and_val; + spix_val = ham_linebuf[spix]; + dpix_val = CONVERT_RGB(spix_val); + spix++; + buf[dpix + xlinebuffer_pos] = dpix_val; dpix++; + } + } else if (bpldualpf) { + var lookup = bpldualpfpri ? dblpf_ind2_aga : dblpf_ind1_aga; + var lookup_no = bpldualpfpri ? dblpf_2nd2 : dblpf_2nd1; + if ((dpix + xlinebuffer_pos) & 2) { + var spix_val = 0; + var dpix_val = 0; + spix_val = pixdata.apixels[spix]; + { + var val = lookup[spix_val]; + if (lookup_no[spix_val]) + val += dblpfofs[bpldualpf2of]; + val ^= xor_val; + dpix_val = p_acolors[val]; + } + spix++; + buf[dpix + xlinebuffer_pos] = dpix_val; dpix++; + } + if (dpix >= dpix_end) + return spix; + var rem = (dpix_end + xlinebuffer_pos) & 2; + if (rem) + dpix_end--; + while (dpix < dpix_end) { + var spix_val = 0; + var dpix_val = 0; + var out_val = 0; + spix_val = pixdata.apixels[spix]; + { + var val = lookup[spix_val]; + if (lookup_no[spix_val]) + val += dblpfofs[bpldualpf2of]; + val ^= xor_val; + dpix_val = p_acolors[val]; + } + spix++; + out_val = dpix_val; + spix_val = pixdata.apixels[spix]; + { + var val = lookup[spix_val]; + if (lookup_no[spix_val]) + val += dblpfofs[bpldualpf2of]; + val ^= xor_val; + dpix_val = p_acolors[val]; + } + spix++; + out_val = ((out_val << 16) | (dpix_val & 0xFFFF)) >>> 0; + buf[dpix + xlinebuffer_pos] = out_val >>> 16; + buf[dpix + xlinebuffer_pos + 1] = out_val & 0xffff; + dpix += 2; + } + if (rem) { + var spix_val = 0; + var dpix_val = 0; + spix_val = pixdata.apixels[spix]; + { + var val = lookup[spix_val]; + if (lookup_no[spix_val]) + val += dblpfofs[bpldualpf2of]; + val ^= xor_val; + dpix_val = p_acolors[val]; + } + spix++; + buf[dpix + xlinebuffer_pos] = dpix_val; dpix++; + } + } else if (bplehb) { + if ((dpix + xlinebuffer_pos) & 2) { + var spix_val = 0; + var dpix_val = 0; + spix_val = (pixdata.apixels[spix] ^ xor_val) & and_val; + if (spix_val >= 32 && spix_val < 64) { + var c = (colors_for_drawing.color_regs_aga[spix_val - 32] >>> 1) & 0x7F7F7F; + dpix_val = CONVERT_RGB(c); + } else + dpix_val = p_acolors[spix_val]; + spix++; + buf[dpix + xlinebuffer_pos] = dpix_val; dpix++; + } + if (dpix >= dpix_end) + return spix; + var rem = (dpix_end + xlinebuffer_pos) & 2; + if (rem) + dpix_end--; + while (dpix < dpix_end) { + var spix_val = 0; + var dpix_val = 0; + var out_val = 0; + spix_val = (pixdata.apixels[spix] ^ xor_val) & and_val; + if (spix_val >= 32 && spix_val < 64) { + var c = (colors_for_drawing.color_regs_aga[spix_val - 32] >>> 1) & 0x7F7F7F; + dpix_val = CONVERT_RGB(c); + } else + dpix_val = p_acolors[spix_val]; + spix++; + out_val = dpix_val; + spix_val = (pixdata.apixels[spix] ^ xor_val) & and_val; + if (spix_val >= 32 && spix_val < 64) { + var c = (colors_for_drawing.color_regs_aga[spix_val - 32] >>> 1) & 0x7F7F7F; + dpix_val = CONVERT_RGB(c); + } else + dpix_val = p_acolors[spix_val]; + spix++; + out_val = ((out_val << 16) | (dpix_val & 0xFFFF)) >>> 0; + buf[dpix + xlinebuffer_pos] = out_val >>> 16; + buf[dpix + xlinebuffer_pos + 1] = out_val & 0xffff; + dpix += 2; + } + if (rem) { + var spix_val = 0; + var dpix_val = 0; + spix_val = (pixdata.apixels[spix] ^ xor_val) & and_val; + if (spix_val >= 32 && spix_val < 64) { + var c = (colors_for_drawing.color_regs_aga[spix_val - 32] >>> 1) & 0x7F7F7F; + dpix_val = CONVERT_RGB(c); + } else + dpix_val = p_acolors[spix_val]; + spix++; + buf[dpix + xlinebuffer_pos] = dpix_val; dpix++; + } + } else { + if ((dpix + xlinebuffer_pos) & 2) { + var spix_val = 0; + var dpix_val = 0; + spix_val = (pixdata.apixels[spix] ^ xor_val) & and_val; + dpix_val = p_acolors[spix_val]; + spix++; + buf[dpix + xlinebuffer_pos] = dpix_val; dpix++; + } + if (dpix >= dpix_end) + return spix; + var rem = (dpix_end + xlinebuffer_pos) & 2; + if (rem) + dpix_end--; + while (dpix < dpix_end) { + var spix_val = 0; + var dpix_val = 0; + var out_val = 0; + spix_val = (pixdata.apixels[spix] ^ xor_val) & and_val; + dpix_val = p_acolors[spix_val]; + spix++; + out_val = dpix_val; + spix_val = (pixdata.apixels[spix] ^ xor_val) & and_val; + dpix_val = p_acolors[spix_val]; + spix++; + out_val = ((out_val << 16) | (dpix_val & 0xFFFF)) >>> 0; + buf[dpix + xlinebuffer_pos] = out_val >>> 16; + buf[dpix + xlinebuffer_pos + 1] = out_val & 0xffff; + dpix += 2; + } + if (rem) { + var spix_val = 0; + var dpix_val = 0; + spix_val = (pixdata.apixels[spix] ^ xor_val) & and_val; + dpix_val = p_acolors[spix_val]; + spix++; + buf[dpix + xlinebuffer_pos] = dpix_val; dpix++; + } + } + return spix; + } + + function linetoscr_16_stretch1_aga(spix, dpix, dpix_end) + { + var buf = xlinebuffer; + var xor_val = bplxor; + var and_val = bpland; + if (bplham) { + while (dpix < dpix_end) { + var spix_val = 0; + var dpix_val = 0; + var out_val = 0; + spix_val = (pixdata.apixels[spix] ^ xor_val) & and_val; + spix_val = ham_linebuf[spix]; + dpix_val = CONVERT_RGB(spix_val); + spix++; + out_val = dpix_val; + buf[dpix + xlinebuffer_pos] = out_val >>> 16; + buf[dpix + xlinebuffer_pos + 1] = out_val & 0xffff; + dpix += 2; + } + } else if (bpldualpf) { + var lookup = bpldualpfpri ? dblpf_ind2_aga : dblpf_ind1_aga; + var lookup_no = bpldualpfpri ? dblpf_2nd2 : dblpf_2nd1; + while (dpix < dpix_end) { + var spix_val = 0; + var dpix_val = 0; + var out_val = 0; + spix_val = pixdata.apixels[spix]; + { + var val = lookup[spix_val]; + if (lookup_no[spix_val]) + val += dblpfofs[bpldualpf2of]; + val ^= xor_val; + dpix_val = p_acolors[val]; + } + spix++; + out_val = dpix_val; + buf[dpix + xlinebuffer_pos] = out_val >>> 16; + buf[dpix + xlinebuffer_pos + 1] = out_val & 0xffff; + dpix += 2; + } + } else if (bplehb) { + while (dpix < dpix_end) { + var spix_val = 0; + var dpix_val = 0; + var out_val = 0; + spix_val = (pixdata.apixels[spix] ^ xor_val) & and_val; + if (spix_val >= 32 && spix_val < 64) { + var c = (colors_for_drawing.color_regs_aga[spix_val - 32] >>> 1) & 0x7F7F7F; + dpix_val = CONVERT_RGB(c); + } else + dpix_val = p_acolors[spix_val]; + spix++; + out_val = dpix_val; + buf[dpix + xlinebuffer_pos] = out_val >>> 16; + buf[dpix + xlinebuffer_pos + 1] = out_val & 0xffff; + dpix += 2; + } + } else { + while (dpix < dpix_end) { + var spix_val = 0; + var dpix_val = 0; + var out_val = 0; + spix_val = (pixdata.apixels[spix] ^ xor_val) & and_val; + dpix_val = p_acolors[spix_val]; + spix++; + out_val = dpix_val; + buf[dpix + xlinebuffer_pos] = out_val >>> 16; + buf[dpix + xlinebuffer_pos + 1] = out_val & 0xffff; + dpix += 2; + } + } + return spix; + } + + function linetoscr_16_stretch2_aga(spix, dpix, dpix_end) + { + var buf = xlinebuffer; + var xor_val = bplxor; + var and_val = bpland; + if (bplham) { + while (dpix < dpix_end) { + var spix_val = 0; + var dpix_val = 0; + var out_val = 0; + spix_val = (pixdata.apixels[spix] ^ xor_val) & and_val; + spix_val = ham_linebuf[spix]; + dpix_val = CONVERT_RGB(spix_val); + spix++; + out_val = dpix_val; + buf[dpix + xlinebuffer_pos] = out_val >>> 16; + buf[dpix + xlinebuffer_pos + 1] = out_val & 0xffff; + dpix += 2; + buf[dpix + xlinebuffer_pos] = out_val >>> 16; + buf[dpix + xlinebuffer_pos + 1] = out_val & 0xffff; + dpix += 2; + } + } else if (bpldualpf) { + var lookup = bpldualpfpri ? dblpf_ind2_aga : dblpf_ind1_aga; + var lookup_no = bpldualpfpri ? dblpf_2nd2 : dblpf_2nd1; + while (dpix < dpix_end) { + var spix_val = 0; + var dpix_val = 0; + var out_val = 0; + spix_val = pixdata.apixels[spix]; + { + var val = lookup[spix_val]; + if (lookup_no[spix_val]) + val += dblpfofs[bpldualpf2of]; + val ^= xor_val; + dpix_val = p_acolors[val]; + } + spix++; + out_val = dpix_val; + buf[dpix + xlinebuffer_pos] = out_val >>> 16; + buf[dpix + xlinebuffer_pos + 1] = out_val & 0xffff; + dpix += 2; + buf[dpix + xlinebuffer_pos] = out_val >>> 16; + buf[dpix + xlinebuffer_pos + 1] = out_val & 0xffff; + dpix += 2; + } + } else if (bplehb) { + while (dpix < dpix_end) { + var spix_val = 0; + var dpix_val = 0; + var out_val = 0; + spix_val = (pixdata.apixels[spix] ^ xor_val) & and_val; + if (spix_val >= 32 && spix_val < 64) { + var c = (colors_for_drawing.color_regs_aga[spix_val - 32] >>> 1) & 0x7F7F7F; + dpix_val = CONVERT_RGB(c); + } else + dpix_val = p_acolors[spix_val]; + spix++; + out_val = dpix_val; + buf[dpix + xlinebuffer_pos] = out_val >>> 16; + buf[dpix + xlinebuffer_pos + 1] = out_val & 0xffff; + dpix += 2; + buf[dpix + xlinebuffer_pos] = out_val >>> 16; + buf[dpix + xlinebuffer_pos + 1] = out_val & 0xffff; + dpix += 2; + } + } else { + while (dpix < dpix_end) { + var spix_val = 0; + var dpix_val = 0; + var out_val = 0; + spix_val = (pixdata.apixels[spix] ^ xor_val) & and_val; + dpix_val = p_acolors[spix_val]; + spix++; + out_val = dpix_val; + buf[dpix + xlinebuffer_pos] = out_val >>> 16; + buf[dpix + xlinebuffer_pos + 1] = out_val & 0xffff; + dpix += 2; + buf[dpix + xlinebuffer_pos] = out_val >>> 16; + buf[dpix + xlinebuffer_pos + 1] = out_val & 0xffff; + dpix += 2; + } + } + return spix; + } + + function linetoscr_16_shrink1_aga(spix, dpix, dpix_end) + { + var buf = xlinebuffer; + var xor_val = bplxor; + var and_val = bpland; + if (bplham) { + if ((dpix + xlinebuffer_pos) & 2) { + var spix_val = 0; + var dpix_val = 0; + spix_val = (pixdata.apixels[spix] ^ xor_val) & and_val; + spix_val = ham_linebuf[spix]; + dpix_val = CONVERT_RGB(spix_val); + spix += 2; + buf[dpix + xlinebuffer_pos] = dpix_val; dpix++; + } + if (dpix >= dpix_end) + return spix; + var rem = (dpix_end + xlinebuffer_pos) & 2; + if (rem) + dpix_end--; + while (dpix < dpix_end) { + var spix_val = 0; + var dpix_val = 0; + var out_val = 0; + spix_val = (pixdata.apixels[spix] ^ xor_val) & and_val; + spix_val = ham_linebuf[spix]; + dpix_val = CONVERT_RGB(spix_val); + spix += 2; + out_val = dpix_val; + spix_val = (pixdata.apixels[spix] ^ xor_val) & and_val; + spix_val = ham_linebuf[spix]; + dpix_val = CONVERT_RGB(spix_val); + spix += 2; + out_val = ((out_val << 16) | (dpix_val & 0xFFFF)) >>> 0; + buf[dpix + xlinebuffer_pos] = out_val >>> 16; + buf[dpix + xlinebuffer_pos + 1] = out_val & 0xffff; + dpix += 2; + } + if (rem) { + var spix_val = 0; + var dpix_val = 0; + spix_val = (pixdata.apixels[spix] ^ xor_val) & and_val; + spix_val = ham_linebuf[spix]; + dpix_val = CONVERT_RGB(spix_val); + spix += 2; + buf[dpix + xlinebuffer_pos] = dpix_val; dpix++; + } + } else if (bpldualpf) { + var lookup = bpldualpfpri ? dblpf_ind2_aga : dblpf_ind1_aga; + var lookup_no = bpldualpfpri ? dblpf_2nd2 : dblpf_2nd1; + if ((dpix + xlinebuffer_pos) & 2) { + var spix_val = 0; + var dpix_val = 0; + spix_val = pixdata.apixels[spix]; + { + var val = lookup[spix_val]; + if (lookup_no[spix_val]) + val += dblpfofs[bpldualpf2of]; + val ^= xor_val; + dpix_val = p_acolors[val]; + } + spix += 2; + buf[dpix + xlinebuffer_pos] = dpix_val; dpix++; + } + if (dpix >= dpix_end) + return spix; + var rem = (dpix_end + xlinebuffer_pos) & 2; + if (rem) + dpix_end--; + while (dpix < dpix_end) { + var spix_val = 0; + var dpix_val = 0; + var out_val = 0; + spix_val = pixdata.apixels[spix]; + { + var val = lookup[spix_val]; + if (lookup_no[spix_val]) + val += dblpfofs[bpldualpf2of]; + val ^= xor_val; + dpix_val = p_acolors[val]; + } + spix += 2; + out_val = dpix_val; + spix_val = pixdata.apixels[spix]; + { + var val = lookup[spix_val]; + if (lookup_no[spix_val]) + val += dblpfofs[bpldualpf2of]; + val ^= xor_val; + dpix_val = p_acolors[val]; + } + spix += 2; + out_val = ((out_val << 16) | (dpix_val & 0xFFFF)) >>> 0; + buf[dpix + xlinebuffer_pos] = out_val >>> 16; + buf[dpix + xlinebuffer_pos + 1] = out_val & 0xffff; + dpix += 2; + } + if (rem) { + var spix_val = 0; + var dpix_val = 0; + spix_val = pixdata.apixels[spix]; + { + var val = lookup[spix_val]; + if (lookup_no[spix_val]) + val += dblpfofs[bpldualpf2of]; + val ^= xor_val; + dpix_val = p_acolors[val]; + } + spix += 2; + buf[dpix + xlinebuffer_pos] = dpix_val; dpix++; + } + } else if (bplehb) { + if ((dpix + xlinebuffer_pos) & 2) { + var spix_val = 0; + var dpix_val = 0; + spix_val = (pixdata.apixels[spix] ^ xor_val) & and_val; + if (spix_val >= 32 && spix_val < 64) { + var c = (colors_for_drawing.color_regs_aga[spix_val - 32] >>> 1) & 0x7F7F7F; + dpix_val = CONVERT_RGB(c); + } else + dpix_val = p_acolors[spix_val]; + spix += 2; + buf[dpix + xlinebuffer_pos] = dpix_val; dpix++; + } + if (dpix >= dpix_end) + return spix; + var rem = (dpix_end + xlinebuffer_pos) & 2; + if (rem) + dpix_end--; + while (dpix < dpix_end) { + var spix_val = 0; + var dpix_val = 0; + var out_val = 0; + spix_val = (pixdata.apixels[spix] ^ xor_val) & and_val; + if (spix_val >= 32 && spix_val < 64) { + var c = (colors_for_drawing.color_regs_aga[spix_val - 32] >>> 1) & 0x7F7F7F; + dpix_val = CONVERT_RGB(c); + } else + dpix_val = p_acolors[spix_val]; + spix += 2; + out_val = dpix_val; + spix_val = (pixdata.apixels[spix] ^ xor_val) & and_val; + if (spix_val >= 32 && spix_val < 64) { + var c = (colors_for_drawing.color_regs_aga[spix_val - 32] >>> 1) & 0x7F7F7F; + dpix_val = CONVERT_RGB(c); + } else + dpix_val = p_acolors[spix_val]; + spix += 2; + out_val = ((out_val << 16) | (dpix_val & 0xFFFF)) >>> 0; + buf[dpix + xlinebuffer_pos] = out_val >>> 16; + buf[dpix + xlinebuffer_pos + 1] = out_val & 0xffff; + dpix += 2; + } + if (rem) { + var spix_val = 0; + var dpix_val = 0; + spix_val = (pixdata.apixels[spix] ^ xor_val) & and_val; + if (spix_val >= 32 && spix_val < 64) { + var c = (colors_for_drawing.color_regs_aga[spix_val - 32] >>> 1) & 0x7F7F7F; + dpix_val = CONVERT_RGB(c); + } else + dpix_val = p_acolors[spix_val]; + spix += 2; + buf[dpix + xlinebuffer_pos] = dpix_val; dpix++; + } + } else { + if ((dpix + xlinebuffer_pos) & 2) { + var spix_val = 0; + var dpix_val = 0; + spix_val = (pixdata.apixels[spix] ^ xor_val) & and_val; + dpix_val = p_acolors[spix_val]; + spix += 2; + buf[dpix + xlinebuffer_pos] = dpix_val; dpix++; + } + if (dpix >= dpix_end) + return spix; + var rem = (dpix_end + xlinebuffer_pos) & 2; + if (rem) + dpix_end--; + while (dpix < dpix_end) { + var spix_val = 0; + var dpix_val = 0; + var out_val = 0; + spix_val = (pixdata.apixels[spix] ^ xor_val) & and_val; + dpix_val = p_acolors[spix_val]; + spix += 2; + out_val = dpix_val; + spix_val = (pixdata.apixels[spix] ^ xor_val) & and_val; + dpix_val = p_acolors[spix_val]; + spix += 2; + out_val = ((out_val << 16) | (dpix_val & 0xFFFF)) >>> 0; + buf[dpix + xlinebuffer_pos] = out_val >>> 16; + buf[dpix + xlinebuffer_pos + 1] = out_val & 0xffff; + dpix += 2; + } + if (rem) { + var spix_val = 0; + var dpix_val = 0; + spix_val = (pixdata.apixels[spix] ^ xor_val) & and_val; + dpix_val = p_acolors[spix_val]; + spix += 2; + buf[dpix + xlinebuffer_pos] = dpix_val; dpix++; + } + } + return spix; + } + + function linetoscr_16_shrink1f_aga(spix, dpix, dpix_end) + { + var buf = xlinebuffer; + var xor_val = bplxor; + var and_val = bpland; + if (bplham) { + if ((dpix + xlinebuffer_pos) & 2) { + var spix_val = 0; + var dpix_val = 0; + spix_val = (pixdata.apixels[spix] ^ xor_val) & and_val; + spix_val = ham_linebuf[spix]; + dpix_val = CONVERT_RGB(spix_val); + { + var tmp_val; + spix++; + tmp_val = dpix_val; + spix_val = (pixdata.apixels[spix] ^ xor_val) & and_val; + spix_val = ham_linebuf[spix]; + dpix_val = CONVERT_RGB(spix_val); + dpix_val = merge_2pixel16(dpix_val, tmp_val); + spix++; + } + buf[dpix + xlinebuffer_pos] = dpix_val; dpix++; + } + if (dpix >= dpix_end) + return spix; + var rem = (dpix_end + xlinebuffer_pos) & 2; + if (rem) + dpix_end--; + while (dpix < dpix_end) { + var spix_val = 0; + var dpix_val = 0; + var out_val = 0; + spix_val = (pixdata.apixels[spix] ^ xor_val) & and_val; + spix_val = ham_linebuf[spix]; + dpix_val = CONVERT_RGB(spix_val); + { + var tmp_val; + spix++; + tmp_val = dpix_val; + spix_val = (pixdata.apixels[spix] ^ xor_val) & and_val; + spix_val = ham_linebuf[spix]; + dpix_val = CONVERT_RGB(spix_val); + dpix_val = merge_2pixel16(dpix_val, tmp_val); + spix++; + } + out_val = dpix_val; + spix_val = (pixdata.apixels[spix] ^ xor_val) & and_val; + spix_val = ham_linebuf[spix]; + dpix_val = CONVERT_RGB(spix_val); + { + var tmp_val; + spix++; + tmp_val = dpix_val; + spix_val = (pixdata.apixels[spix] ^ xor_val) & and_val; + spix_val = ham_linebuf[spix]; + dpix_val = CONVERT_RGB(spix_val); + dpix_val = merge_2pixel16(dpix_val, tmp_val); + spix++; + } + out_val = ((out_val << 16) | (dpix_val & 0xFFFF)) >>> 0; + buf[dpix + xlinebuffer_pos] = out_val >>> 16; + buf[dpix + xlinebuffer_pos + 1] = out_val & 0xffff; + dpix += 2; + } + if (rem) { + var spix_val = 0; + var dpix_val = 0; + spix_val = (pixdata.apixels[spix] ^ xor_val) & and_val; + spix_val = ham_linebuf[spix]; + dpix_val = CONVERT_RGB(spix_val); + { + var tmp_val; + spix++; + tmp_val = dpix_val; + spix_val = (pixdata.apixels[spix] ^ xor_val) & and_val; + spix_val = ham_linebuf[spix]; + dpix_val = CONVERT_RGB(spix_val); + dpix_val = merge_2pixel16(dpix_val, tmp_val); + spix++; + } + buf[dpix + xlinebuffer_pos] = dpix_val; dpix++; + } + } else if (bpldualpf) { + var lookup = bpldualpfpri ? dblpf_ind2_aga : dblpf_ind1_aga; + var lookup_no = bpldualpfpri ? dblpf_2nd2 : dblpf_2nd1; + if ((dpix + xlinebuffer_pos) & 2) { + var spix_val = 0; + var dpix_val = 0; + spix_val = pixdata.apixels[spix]; + { + var val = lookup[spix_val]; + if (lookup_no[spix_val]) + val += dblpfofs[bpldualpf2of]; + val ^= xor_val; + dpix_val = p_acolors[val]; + } + { + var tmp_val; + spix++; + tmp_val = dpix_val; + spix_val = pixdata.apixels[spix]; + { + var val = lookup[spix_val]; + if (lookup_no[spix_val]) + val += dblpfofs[bpldualpf2of]; + val ^= xor_val; + dpix_val = p_acolors[val]; + } + dpix_val = merge_2pixel16(dpix_val, tmp_val); + spix++; + } + buf[dpix + xlinebuffer_pos] = dpix_val; dpix++; + } + if (dpix >= dpix_end) + return spix; + var rem = (dpix_end + xlinebuffer_pos) & 2; + if (rem) + dpix_end--; + while (dpix < dpix_end) { + var spix_val = 0; + var dpix_val = 0; + var out_val = 0; + spix_val = pixdata.apixels[spix]; + { + var val = lookup[spix_val]; + if (lookup_no[spix_val]) + val += dblpfofs[bpldualpf2of]; + val ^= xor_val; + dpix_val = p_acolors[val]; + } + { + var tmp_val; + spix++; + tmp_val = dpix_val; + spix_val = pixdata.apixels[spix]; + { + var val = lookup[spix_val]; + if (lookup_no[spix_val]) + val += dblpfofs[bpldualpf2of]; + val ^= xor_val; + dpix_val = p_acolors[val]; + } + dpix_val = merge_2pixel16(dpix_val, tmp_val); + spix++; + } + out_val = dpix_val; + spix_val = pixdata.apixels[spix]; + { + var val = lookup[spix_val]; + if (lookup_no[spix_val]) + val += dblpfofs[bpldualpf2of]; + val ^= xor_val; + dpix_val = p_acolors[val]; + } + { + var tmp_val; + spix++; + tmp_val = dpix_val; + spix_val = pixdata.apixels[spix]; + { + var val = lookup[spix_val]; + if (lookup_no[spix_val]) + val += dblpfofs[bpldualpf2of]; + val ^= xor_val; + dpix_val = p_acolors[val]; + } + dpix_val = merge_2pixel16(dpix_val, tmp_val); + spix++; + } + out_val = ((out_val << 16) | (dpix_val & 0xFFFF)) >>> 0; + buf[dpix + xlinebuffer_pos] = out_val >>> 16; + buf[dpix + xlinebuffer_pos + 1] = out_val & 0xffff; + dpix += 2; + } + if (rem) { + var spix_val = 0; + var dpix_val = 0; + spix_val = pixdata.apixels[spix]; + { + var val = lookup[spix_val]; + if (lookup_no[spix_val]) + val += dblpfofs[bpldualpf2of]; + val ^= xor_val; + dpix_val = p_acolors[val]; + } + { + var tmp_val; + spix++; + tmp_val = dpix_val; + spix_val = pixdata.apixels[spix]; + { + var val = lookup[spix_val]; + if (lookup_no[spix_val]) + val += dblpfofs[bpldualpf2of]; + val ^= xor_val; + dpix_val = p_acolors[val]; + } + dpix_val = merge_2pixel16(dpix_val, tmp_val); + spix++; + } + buf[dpix + xlinebuffer_pos] = dpix_val; dpix++; + } + } else if (bplehb) { + if ((dpix + xlinebuffer_pos) & 2) { + var spix_val = 0; + var dpix_val = 0; + spix_val = (pixdata.apixels[spix] ^ xor_val) & and_val; + if (spix_val >= 32 && spix_val < 64) { + var c = (colors_for_drawing.color_regs_aga[spix_val - 32] >>> 1) & 0x7F7F7F; + dpix_val = CONVERT_RGB(c); + } else + dpix_val = p_acolors[spix_val]; + { + var tmp_val; + spix++; + tmp_val = dpix_val; + spix_val = (pixdata.apixels[spix] ^ xor_val) & and_val; + if (spix_val >= 32 && spix_val < 64) { + var c = (colors_for_drawing.color_regs_aga[spix_val - 32] >>> 1) & 0x7F7F7F; + dpix_val = CONVERT_RGB(c); + } else + dpix_val = p_acolors[spix_val]; + dpix_val = merge_2pixel16(dpix_val, tmp_val); + spix++; + } + buf[dpix + xlinebuffer_pos] = dpix_val; dpix++; + } + if (dpix >= dpix_end) + return spix; + var rem = (dpix_end + xlinebuffer_pos) & 2; + if (rem) + dpix_end--; + while (dpix < dpix_end) { + var spix_val = 0; + var dpix_val = 0; + var out_val = 0; + spix_val = (pixdata.apixels[spix] ^ xor_val) & and_val; + if (spix_val >= 32 && spix_val < 64) { + var c = (colors_for_drawing.color_regs_aga[spix_val - 32] >>> 1) & 0x7F7F7F; + dpix_val = CONVERT_RGB(c); + } else + dpix_val = p_acolors[spix_val]; + { + var tmp_val; + spix++; + tmp_val = dpix_val; + spix_val = (pixdata.apixels[spix] ^ xor_val) & and_val; + if (spix_val >= 32 && spix_val < 64) { + var c = (colors_for_drawing.color_regs_aga[spix_val - 32] >>> 1) & 0x7F7F7F; + dpix_val = CONVERT_RGB(c); + } else + dpix_val = p_acolors[spix_val]; + dpix_val = merge_2pixel16(dpix_val, tmp_val); + spix++; + } + out_val = dpix_val; + spix_val = (pixdata.apixels[spix] ^ xor_val) & and_val; + if (spix_val >= 32 && spix_val < 64) { + var c = (colors_for_drawing.color_regs_aga[spix_val - 32] >>> 1) & 0x7F7F7F; + dpix_val = CONVERT_RGB(c); + } else + dpix_val = p_acolors[spix_val]; + { + var tmp_val; + spix++; + tmp_val = dpix_val; + spix_val = (pixdata.apixels[spix] ^ xor_val) & and_val; + if (spix_val >= 32 && spix_val < 64) { + var c = (colors_for_drawing.color_regs_aga[spix_val - 32] >>> 1) & 0x7F7F7F; + dpix_val = CONVERT_RGB(c); + } else + dpix_val = p_acolors[spix_val]; + dpix_val = merge_2pixel16(dpix_val, tmp_val); + spix++; + } + out_val = ((out_val << 16) | (dpix_val & 0xFFFF)) >>> 0; + buf[dpix + xlinebuffer_pos] = out_val >>> 16; + buf[dpix + xlinebuffer_pos + 1] = out_val & 0xffff; + dpix += 2; + } + if (rem) { + var spix_val = 0; + var dpix_val = 0; + spix_val = (pixdata.apixels[spix] ^ xor_val) & and_val; + if (spix_val >= 32 && spix_val < 64) { + var c = (colors_for_drawing.color_regs_aga[spix_val - 32] >>> 1) & 0x7F7F7F; + dpix_val = CONVERT_RGB(c); + } else + dpix_val = p_acolors[spix_val]; + { + var tmp_val; + spix++; + tmp_val = dpix_val; + spix_val = (pixdata.apixels[spix] ^ xor_val) & and_val; + if (spix_val >= 32 && spix_val < 64) { + var c = (colors_for_drawing.color_regs_aga[spix_val - 32] >>> 1) & 0x7F7F7F; + dpix_val = CONVERT_RGB(c); + } else + dpix_val = p_acolors[spix_val]; + dpix_val = merge_2pixel16(dpix_val, tmp_val); + spix++; + } + buf[dpix + xlinebuffer_pos] = dpix_val; dpix++; + } + } else { + if ((dpix + xlinebuffer_pos) & 2) { + var spix_val = 0; + var dpix_val = 0; + spix_val = (pixdata.apixels[spix] ^ xor_val) & and_val; + dpix_val = p_acolors[spix_val]; + { + var tmp_val; + spix++; + tmp_val = dpix_val; + spix_val = (pixdata.apixels[spix] ^ xor_val) & and_val; + dpix_val = p_acolors[spix_val]; + dpix_val = merge_2pixel16(dpix_val, tmp_val); + spix++; + } + buf[dpix + xlinebuffer_pos] = dpix_val; dpix++; + } + if (dpix >= dpix_end) + return spix; + var rem = (dpix_end + xlinebuffer_pos) & 2; + if (rem) + dpix_end--; + while (dpix < dpix_end) { + var spix_val = 0; + var dpix_val = 0; + var out_val = 0; + spix_val = (pixdata.apixels[spix] ^ xor_val) & and_val; + dpix_val = p_acolors[spix_val]; + { + var tmp_val; + spix++; + tmp_val = dpix_val; + spix_val = (pixdata.apixels[spix] ^ xor_val) & and_val; + dpix_val = p_acolors[spix_val]; + dpix_val = merge_2pixel16(dpix_val, tmp_val); + spix++; + } + out_val = dpix_val; + spix_val = (pixdata.apixels[spix] ^ xor_val) & and_val; + dpix_val = p_acolors[spix_val]; + { + var tmp_val; + spix++; + tmp_val = dpix_val; + spix_val = (pixdata.apixels[spix] ^ xor_val) & and_val; + dpix_val = p_acolors[spix_val]; + dpix_val = merge_2pixel16(dpix_val, tmp_val); + spix++; + } + out_val = ((out_val << 16) | (dpix_val & 0xFFFF)) >>> 0; + buf[dpix + xlinebuffer_pos] = out_val >>> 16; + buf[dpix + xlinebuffer_pos + 1] = out_val & 0xffff; + dpix += 2; + } + if (rem) { + var spix_val = 0; + var dpix_val = 0; + spix_val = (pixdata.apixels[spix] ^ xor_val) & and_val; + dpix_val = p_acolors[spix_val]; + { + var tmp_val; + spix++; + tmp_val = dpix_val; + spix_val = (pixdata.apixels[spix] ^ xor_val) & and_val; + dpix_val = p_acolors[spix_val]; + dpix_val = merge_2pixel16(dpix_val, tmp_val); + spix++; + } + buf[dpix + xlinebuffer_pos] = dpix_val; dpix++; + } + } + return spix; + } + + function linetoscr_16_shrink2_aga(spix, dpix, dpix_end) + { + var buf = xlinebuffer; + var xor_val = bplxor; + var and_val = bpland; + if (bplham) { + if ((dpix + xlinebuffer_pos) & 2) { + var spix_val = 0; + var dpix_val = 0; + spix_val = (pixdata.apixels[spix] ^ xor_val) & and_val; + spix_val = ham_linebuf[spix]; + dpix_val = CONVERT_RGB(spix_val); + spix += 4; + buf[dpix + xlinebuffer_pos] = dpix_val; dpix++; + } + if (dpix >= dpix_end) + return spix; + var rem = (dpix_end + xlinebuffer_pos) & 2; + if (rem) + dpix_end--; + while (dpix < dpix_end) { + var spix_val = 0; + var dpix_val = 0; + var out_val = 0; + spix_val = (pixdata.apixels[spix] ^ xor_val) & and_val; + spix_val = ham_linebuf[spix]; + dpix_val = CONVERT_RGB(spix_val); + spix += 4; + out_val = dpix_val; + spix_val = (pixdata.apixels[spix] ^ xor_val) & and_val; + spix_val = ham_linebuf[spix]; + dpix_val = CONVERT_RGB(spix_val); + spix += 4; + out_val = ((out_val << 16) | (dpix_val & 0xFFFF)) >>> 0; + buf[dpix + xlinebuffer_pos] = out_val >>> 16; + buf[dpix + xlinebuffer_pos + 1] = out_val & 0xffff; + dpix += 2; + } + if (rem) { + var spix_val = 0; + var dpix_val = 0; + spix_val = (pixdata.apixels[spix] ^ xor_val) & and_val; + spix_val = ham_linebuf[spix]; + dpix_val = CONVERT_RGB(spix_val); + spix += 4; + buf[dpix + xlinebuffer_pos] = dpix_val; dpix++; + } + } else if (bpldualpf) { + var lookup = bpldualpfpri ? dblpf_ind2_aga : dblpf_ind1_aga; + var lookup_no = bpldualpfpri ? dblpf_2nd2 : dblpf_2nd1; + if ((dpix + xlinebuffer_pos) & 2) { + var spix_val = 0; + var dpix_val = 0; + spix_val = pixdata.apixels[spix]; + { + var val = lookup[spix_val]; + if (lookup_no[spix_val]) + val += dblpfofs[bpldualpf2of]; + val ^= xor_val; + dpix_val = p_acolors[val]; + } + spix += 4; + buf[dpix + xlinebuffer_pos] = dpix_val; dpix++; + } + if (dpix >= dpix_end) + return spix; + var rem = (dpix_end + xlinebuffer_pos) & 2; + if (rem) + dpix_end--; + while (dpix < dpix_end) { + var spix_val = 0; + var dpix_val = 0; + var out_val = 0; + spix_val = pixdata.apixels[spix]; + { + var val = lookup[spix_val]; + if (lookup_no[spix_val]) + val += dblpfofs[bpldualpf2of]; + val ^= xor_val; + dpix_val = p_acolors[val]; + } + spix += 4; + out_val = dpix_val; + spix_val = pixdata.apixels[spix]; + { + var val = lookup[spix_val]; + if (lookup_no[spix_val]) + val += dblpfofs[bpldualpf2of]; + val ^= xor_val; + dpix_val = p_acolors[val]; + } + spix += 4; + out_val = ((out_val << 16) | (dpix_val & 0xFFFF)) >>> 0; + buf[dpix + xlinebuffer_pos] = out_val >>> 16; + buf[dpix + xlinebuffer_pos + 1] = out_val & 0xffff; + dpix += 2; + } + if (rem) { + var spix_val = 0; + var dpix_val = 0; + spix_val = pixdata.apixels[spix]; + { + var val = lookup[spix_val]; + if (lookup_no[spix_val]) + val += dblpfofs[bpldualpf2of]; + val ^= xor_val; + dpix_val = p_acolors[val]; + } + spix += 4; + buf[dpix + xlinebuffer_pos] = dpix_val; dpix++; + } + } else if (bplehb) { + if ((dpix + xlinebuffer_pos) & 2) { + var spix_val = 0; + var dpix_val = 0; + spix_val = (pixdata.apixels[spix] ^ xor_val) & and_val; + if (spix_val >= 32 && spix_val < 64) { + var c = (colors_for_drawing.color_regs_aga[spix_val - 32] >>> 1) & 0x7F7F7F; + dpix_val = CONVERT_RGB(c); + } else + dpix_val = p_acolors[spix_val]; + spix += 4; + buf[dpix + xlinebuffer_pos] = dpix_val; dpix++; + } + if (dpix >= dpix_end) + return spix; + var rem = (dpix_end + xlinebuffer_pos) & 2; + if (rem) + dpix_end--; + while (dpix < dpix_end) { + var spix_val = 0; + var dpix_val = 0; + var out_val = 0; + spix_val = (pixdata.apixels[spix] ^ xor_val) & and_val; + if (spix_val >= 32 && spix_val < 64) { + var c = (colors_for_drawing.color_regs_aga[spix_val - 32] >>> 1) & 0x7F7F7F; + dpix_val = CONVERT_RGB(c); + } else + dpix_val = p_acolors[spix_val]; + spix += 4; + out_val = dpix_val; + spix_val = (pixdata.apixels[spix] ^ xor_val) & and_val; + if (spix_val >= 32 && spix_val < 64) { + var c = (colors_for_drawing.color_regs_aga[spix_val - 32] >>> 1) & 0x7F7F7F; + dpix_val = CONVERT_RGB(c); + } else + dpix_val = p_acolors[spix_val]; + spix += 4; + out_val = ((out_val << 16) | (dpix_val & 0xFFFF)) >>> 0; + buf[dpix + xlinebuffer_pos] = out_val >>> 16; + buf[dpix + xlinebuffer_pos + 1] = out_val & 0xffff; + dpix += 2; + } + if (rem) { + var spix_val = 0; + var dpix_val = 0; + spix_val = (pixdata.apixels[spix] ^ xor_val) & and_val; + if (spix_val >= 32 && spix_val < 64) { + var c = (colors_for_drawing.color_regs_aga[spix_val - 32] >>> 1) & 0x7F7F7F; + dpix_val = CONVERT_RGB(c); + } else + dpix_val = p_acolors[spix_val]; + spix += 4; + buf[dpix + xlinebuffer_pos] = dpix_val; dpix++; + } + } else { + if ((dpix + xlinebuffer_pos) & 2) { + var spix_val = 0; + var dpix_val = 0; + spix_val = (pixdata.apixels[spix] ^ xor_val) & and_val; + dpix_val = p_acolors[spix_val]; + spix += 4; + buf[dpix + xlinebuffer_pos] = dpix_val; dpix++; + } + if (dpix >= dpix_end) + return spix; + var rem = (dpix_end + xlinebuffer_pos) & 2; + if (rem) + dpix_end--; + while (dpix < dpix_end) { + var spix_val = 0; + var dpix_val = 0; + var out_val = 0; + spix_val = (pixdata.apixels[spix] ^ xor_val) & and_val; + dpix_val = p_acolors[spix_val]; + spix += 4; + out_val = dpix_val; + spix_val = (pixdata.apixels[spix] ^ xor_val) & and_val; + dpix_val = p_acolors[spix_val]; + spix += 4; + out_val = ((out_val << 16) | (dpix_val & 0xFFFF)) >>> 0; + buf[dpix + xlinebuffer_pos] = out_val >>> 16; + buf[dpix + xlinebuffer_pos + 1] = out_val & 0xffff; + dpix += 2; + } + if (rem) { + var spix_val = 0; + var dpix_val = 0; + spix_val = (pixdata.apixels[spix] ^ xor_val) & and_val; + dpix_val = p_acolors[spix_val]; + spix += 4; + buf[dpix + xlinebuffer_pos] = dpix_val; dpix++; + } + } + return spix; + } + + function linetoscr_16_shrink2f_aga(spix, dpix, dpix_end) + { + var buf = xlinebuffer; + var xor_val = bplxor; + var and_val = bpland; + if (bplham) { + if ((dpix + xlinebuffer_pos) & 2) { + var spix_val = 0; + var dpix_val = 0; + spix_val = (pixdata.apixels[spix] ^ xor_val) & and_val; + spix_val = ham_linebuf[spix]; + dpix_val = CONVERT_RGB(spix_val); + { + var tmp_val, tmp_val2, tmp_val3; + spix++; + tmp_val = dpix_val; + spix_val = (pixdata.apixels[spix] ^ xor_val) & and_val; + spix_val = ham_linebuf[spix]; + dpix_val = CONVERT_RGB(spix_val); + spix++; + tmp_val2 = dpix_val; + spix_val = (pixdata.apixels[spix] ^ xor_val) & and_val; + spix_val = ham_linebuf[spix]; + dpix_val = CONVERT_RGB(spix_val); + spix++; + tmp_val3 = dpix_val; + spix_val = (pixdata.apixels[spix] ^ xor_val) & and_val; + spix_val = ham_linebuf[spix]; + dpix_val = CONVERT_RGB(spix_val); + tmp_val = merge_2pixel16(tmp_val, tmp_val2); + tmp_val2 = merge_2pixel16(tmp_val3, dpix_val); + dpix_val = merge_2pixel16(tmp_val, tmp_val2); + spix++; + } + buf[dpix + xlinebuffer_pos] = dpix_val; dpix++; + } + if (dpix >= dpix_end) + return spix; + var rem = (dpix_end + xlinebuffer_pos) & 2; + if (rem) + dpix_end--; + while (dpix < dpix_end) { + var spix_val = 0; + var dpix_val = 0; + var out_val = 0; + spix_val = (pixdata.apixels[spix] ^ xor_val) & and_val; + spix_val = ham_linebuf[spix]; + dpix_val = CONVERT_RGB(spix_val); + { + var tmp_val, tmp_val2, tmp_val3; + spix++; + tmp_val = dpix_val; + spix_val = (pixdata.apixels[spix] ^ xor_val) & and_val; + spix_val = ham_linebuf[spix]; + dpix_val = CONVERT_RGB(spix_val); + spix++; + tmp_val2 = dpix_val; + spix_val = (pixdata.apixels[spix] ^ xor_val) & and_val; + spix_val = ham_linebuf[spix]; + dpix_val = CONVERT_RGB(spix_val); + spix++; + tmp_val3 = dpix_val; + spix_val = (pixdata.apixels[spix] ^ xor_val) & and_val; + spix_val = ham_linebuf[spix]; + dpix_val = CONVERT_RGB(spix_val); + tmp_val = merge_2pixel16(tmp_val, tmp_val2); + tmp_val2 = merge_2pixel16(tmp_val3, dpix_val); + dpix_val = merge_2pixel16(tmp_val, tmp_val2); + spix++; + } + out_val = dpix_val; + spix_val = (pixdata.apixels[spix] ^ xor_val) & and_val; + spix_val = ham_linebuf[spix]; + dpix_val = CONVERT_RGB(spix_val); + { + var tmp_val, tmp_val2, tmp_val3; + spix++; + tmp_val = dpix_val; + spix_val = (pixdata.apixels[spix] ^ xor_val) & and_val; + spix_val = ham_linebuf[spix]; + dpix_val = CONVERT_RGB(spix_val); + spix++; + tmp_val2 = dpix_val; + spix_val = (pixdata.apixels[spix] ^ xor_val) & and_val; + spix_val = ham_linebuf[spix]; + dpix_val = CONVERT_RGB(spix_val); + spix++; + tmp_val3 = dpix_val; + spix_val = (pixdata.apixels[spix] ^ xor_val) & and_val; + spix_val = ham_linebuf[spix]; + dpix_val = CONVERT_RGB(spix_val); + tmp_val = merge_2pixel16(tmp_val, tmp_val2); + tmp_val2 = merge_2pixel16(tmp_val3, dpix_val); + dpix_val = merge_2pixel16(tmp_val, tmp_val2); + spix++; + } + out_val = ((out_val << 16) | (dpix_val & 0xFFFF)) >>> 0; + buf[dpix + xlinebuffer_pos] = out_val >>> 16; + buf[dpix + xlinebuffer_pos + 1] = out_val & 0xffff; + dpix += 2; + } + if (rem) { + var spix_val = 0; + var dpix_val = 0; + spix_val = (pixdata.apixels[spix] ^ xor_val) & and_val; + spix_val = ham_linebuf[spix]; + dpix_val = CONVERT_RGB(spix_val); + { + var tmp_val, tmp_val2, tmp_val3; + spix++; + tmp_val = dpix_val; + spix_val = (pixdata.apixels[spix] ^ xor_val) & and_val; + spix_val = ham_linebuf[spix]; + dpix_val = CONVERT_RGB(spix_val); + spix++; + tmp_val2 = dpix_val; + spix_val = (pixdata.apixels[spix] ^ xor_val) & and_val; + spix_val = ham_linebuf[spix]; + dpix_val = CONVERT_RGB(spix_val); + spix++; + tmp_val3 = dpix_val; + spix_val = (pixdata.apixels[spix] ^ xor_val) & and_val; + spix_val = ham_linebuf[spix]; + dpix_val = CONVERT_RGB(spix_val); + tmp_val = merge_2pixel16(tmp_val, tmp_val2); + tmp_val2 = merge_2pixel16(tmp_val3, dpix_val); + dpix_val = merge_2pixel16(tmp_val, tmp_val2); + spix++; + } + buf[dpix + xlinebuffer_pos] = dpix_val; dpix++; + } + } else if (bpldualpf) { + var lookup = bpldualpfpri ? dblpf_ind2_aga : dblpf_ind1_aga; + var lookup_no = bpldualpfpri ? dblpf_2nd2 : dblpf_2nd1; + if ((dpix + xlinebuffer_pos) & 2) { + var spix_val = 0; + var dpix_val = 0; + spix_val = pixdata.apixels[spix]; + { + var val = lookup[spix_val]; + if (lookup_no[spix_val]) + val += dblpfofs[bpldualpf2of]; + val ^= xor_val; + dpix_val = p_acolors[val]; + } + { + var tmp_val, tmp_val2, tmp_val3; + spix++; + tmp_val = dpix_val; + spix_val = pixdata.apixels[spix]; + { + var val = lookup[spix_val]; + if (lookup_no[spix_val]) + val += dblpfofs[bpldualpf2of]; + val ^= xor_val; + dpix_val = p_acolors[val]; + } + spix++; + tmp_val2 = dpix_val; + spix_val = pixdata.apixels[spix]; + { + var val = lookup[spix_val]; + if (lookup_no[spix_val]) + val += dblpfofs[bpldualpf2of]; + val ^= xor_val; + dpix_val = p_acolors[val]; + } + spix++; + tmp_val3 = dpix_val; + spix_val = pixdata.apixels[spix]; + { + var val = lookup[spix_val]; + if (lookup_no[spix_val]) + val += dblpfofs[bpldualpf2of]; + val ^= xor_val; + dpix_val = p_acolors[val]; + } + tmp_val = merge_2pixel16(tmp_val, tmp_val2); + tmp_val2 = merge_2pixel16(tmp_val3, dpix_val); + dpix_val = merge_2pixel16(tmp_val, tmp_val2); + spix++; + } + buf[dpix + xlinebuffer_pos] = dpix_val; dpix++; + } + if (dpix >= dpix_end) + return spix; + var rem = (dpix_end + xlinebuffer_pos) & 2; + if (rem) + dpix_end--; + while (dpix < dpix_end) { + var spix_val = 0; + var dpix_val = 0; + var out_val = 0; + spix_val = pixdata.apixels[spix]; + { + var val = lookup[spix_val]; + if (lookup_no[spix_val]) + val += dblpfofs[bpldualpf2of]; + val ^= xor_val; + dpix_val = p_acolors[val]; + } + { + var tmp_val, tmp_val2, tmp_val3; + spix++; + tmp_val = dpix_val; + spix_val = pixdata.apixels[spix]; + { + var val = lookup[spix_val]; + if (lookup_no[spix_val]) + val += dblpfofs[bpldualpf2of]; + val ^= xor_val; + dpix_val = p_acolors[val]; + } + spix++; + tmp_val2 = dpix_val; + spix_val = pixdata.apixels[spix]; + { + var val = lookup[spix_val]; + if (lookup_no[spix_val]) + val += dblpfofs[bpldualpf2of]; + val ^= xor_val; + dpix_val = p_acolors[val]; + } + spix++; + tmp_val3 = dpix_val; + spix_val = pixdata.apixels[spix]; + { + var val = lookup[spix_val]; + if (lookup_no[spix_val]) + val += dblpfofs[bpldualpf2of]; + val ^= xor_val; + dpix_val = p_acolors[val]; + } + tmp_val = merge_2pixel16(tmp_val, tmp_val2); + tmp_val2 = merge_2pixel16(tmp_val3, dpix_val); + dpix_val = merge_2pixel16(tmp_val, tmp_val2); + spix++; + } + out_val = dpix_val; + spix_val = pixdata.apixels[spix]; + { + var val = lookup[spix_val]; + if (lookup_no[spix_val]) + val += dblpfofs[bpldualpf2of]; + val ^= xor_val; + dpix_val = p_acolors[val]; + } + { + var tmp_val, tmp_val2, tmp_val3; + spix++; + tmp_val = dpix_val; + spix_val = pixdata.apixels[spix]; + { + var val = lookup[spix_val]; + if (lookup_no[spix_val]) + val += dblpfofs[bpldualpf2of]; + val ^= xor_val; + dpix_val = p_acolors[val]; + } + spix++; + tmp_val2 = dpix_val; + spix_val = pixdata.apixels[spix]; + { + var val = lookup[spix_val]; + if (lookup_no[spix_val]) + val += dblpfofs[bpldualpf2of]; + val ^= xor_val; + dpix_val = p_acolors[val]; + } + spix++; + tmp_val3 = dpix_val; + spix_val = pixdata.apixels[spix]; + { + var val = lookup[spix_val]; + if (lookup_no[spix_val]) + val += dblpfofs[bpldualpf2of]; + val ^= xor_val; + dpix_val = p_acolors[val]; + } + tmp_val = merge_2pixel16(tmp_val, tmp_val2); + tmp_val2 = merge_2pixel16(tmp_val3, dpix_val); + dpix_val = merge_2pixel16(tmp_val, tmp_val2); + spix++; + } + out_val = ((out_val << 16) | (dpix_val & 0xFFFF)) >>> 0; + buf[dpix + xlinebuffer_pos] = out_val >>> 16; + buf[dpix + xlinebuffer_pos + 1] = out_val & 0xffff; + dpix += 2; + } + if (rem) { + var spix_val = 0; + var dpix_val = 0; + spix_val = pixdata.apixels[spix]; + { + var val = lookup[spix_val]; + if (lookup_no[spix_val]) + val += dblpfofs[bpldualpf2of]; + val ^= xor_val; + dpix_val = p_acolors[val]; + } + { + var tmp_val, tmp_val2, tmp_val3; + spix++; + tmp_val = dpix_val; + spix_val = pixdata.apixels[spix]; + { + var val = lookup[spix_val]; + if (lookup_no[spix_val]) + val += dblpfofs[bpldualpf2of]; + val ^= xor_val; + dpix_val = p_acolors[val]; + } + spix++; + tmp_val2 = dpix_val; + spix_val = pixdata.apixels[spix]; + { + var val = lookup[spix_val]; + if (lookup_no[spix_val]) + val += dblpfofs[bpldualpf2of]; + val ^= xor_val; + dpix_val = p_acolors[val]; + } + spix++; + tmp_val3 = dpix_val; + spix_val = pixdata.apixels[spix]; + { + var val = lookup[spix_val]; + if (lookup_no[spix_val]) + val += dblpfofs[bpldualpf2of]; + val ^= xor_val; + dpix_val = p_acolors[val]; + } + tmp_val = merge_2pixel16(tmp_val, tmp_val2); + tmp_val2 = merge_2pixel16(tmp_val3, dpix_val); + dpix_val = merge_2pixel16(tmp_val, tmp_val2); + spix++; + } + buf[dpix + xlinebuffer_pos] = dpix_val; dpix++; + } + } else if (bplehb) { + if ((dpix + xlinebuffer_pos) & 2) { + var spix_val = 0; + var dpix_val = 0; + spix_val = (pixdata.apixels[spix] ^ xor_val) & and_val; + if (spix_val >= 32 && spix_val < 64) { + var c = (colors_for_drawing.color_regs_aga[spix_val - 32] >>> 1) & 0x7F7F7F; + dpix_val = CONVERT_RGB(c); + } else + dpix_val = p_acolors[spix_val]; + { + var tmp_val, tmp_val2, tmp_val3; + spix++; + tmp_val = dpix_val; + spix_val = (pixdata.apixels[spix] ^ xor_val) & and_val; + if (spix_val >= 32 && spix_val < 64) { + var c = (colors_for_drawing.color_regs_aga[spix_val - 32] >>> 1) & 0x7F7F7F; + dpix_val = CONVERT_RGB(c); + } else + dpix_val = p_acolors[spix_val]; + spix++; + tmp_val2 = dpix_val; + spix_val = (pixdata.apixels[spix] ^ xor_val) & and_val; + if (spix_val >= 32 && spix_val < 64) { + var c = (colors_for_drawing.color_regs_aga[spix_val - 32] >>> 1) & 0x7F7F7F; + dpix_val = CONVERT_RGB(c); + } else + dpix_val = p_acolors[spix_val]; + spix++; + tmp_val3 = dpix_val; + spix_val = (pixdata.apixels[spix] ^ xor_val) & and_val; + if (spix_val >= 32 && spix_val < 64) { + var c = (colors_for_drawing.color_regs_aga[spix_val - 32] >>> 1) & 0x7F7F7F; + dpix_val = CONVERT_RGB(c); + } else + dpix_val = p_acolors[spix_val]; + tmp_val = merge_2pixel16(tmp_val, tmp_val2); + tmp_val2 = merge_2pixel16(tmp_val3, dpix_val); + dpix_val = merge_2pixel16(tmp_val, tmp_val2); + spix++; + } + buf[dpix + xlinebuffer_pos] = dpix_val; dpix++; + } + if (dpix >= dpix_end) + return spix; + var rem = (dpix_end + xlinebuffer_pos) & 2; + if (rem) + dpix_end--; + while (dpix < dpix_end) { + var spix_val = 0; + var dpix_val = 0; + var out_val = 0; + spix_val = (pixdata.apixels[spix] ^ xor_val) & and_val; + if (spix_val >= 32 && spix_val < 64) { + var c = (colors_for_drawing.color_regs_aga[spix_val - 32] >>> 1) & 0x7F7F7F; + dpix_val = CONVERT_RGB(c); + } else + dpix_val = p_acolors[spix_val]; + { + var tmp_val, tmp_val2, tmp_val3; + spix++; + tmp_val = dpix_val; + spix_val = (pixdata.apixels[spix] ^ xor_val) & and_val; + if (spix_val >= 32 && spix_val < 64) { + var c = (colors_for_drawing.color_regs_aga[spix_val - 32] >>> 1) & 0x7F7F7F; + dpix_val = CONVERT_RGB(c); + } else + dpix_val = p_acolors[spix_val]; + spix++; + tmp_val2 = dpix_val; + spix_val = (pixdata.apixels[spix] ^ xor_val) & and_val; + if (spix_val >= 32 && spix_val < 64) { + var c = (colors_for_drawing.color_regs_aga[spix_val - 32] >>> 1) & 0x7F7F7F; + dpix_val = CONVERT_RGB(c); + } else + dpix_val = p_acolors[spix_val]; + spix++; + tmp_val3 = dpix_val; + spix_val = (pixdata.apixels[spix] ^ xor_val) & and_val; + if (spix_val >= 32 && spix_val < 64) { + var c = (colors_for_drawing.color_regs_aga[spix_val - 32] >>> 1) & 0x7F7F7F; + dpix_val = CONVERT_RGB(c); + } else + dpix_val = p_acolors[spix_val]; + tmp_val = merge_2pixel16(tmp_val, tmp_val2); + tmp_val2 = merge_2pixel16(tmp_val3, dpix_val); + dpix_val = merge_2pixel16(tmp_val, tmp_val2); + spix++; + } + out_val = dpix_val; + spix_val = (pixdata.apixels[spix] ^ xor_val) & and_val; + if (spix_val >= 32 && spix_val < 64) { + var c = (colors_for_drawing.color_regs_aga[spix_val - 32] >>> 1) & 0x7F7F7F; + dpix_val = CONVERT_RGB(c); + } else + dpix_val = p_acolors[spix_val]; + { + var tmp_val, tmp_val2, tmp_val3; + spix++; + tmp_val = dpix_val; + spix_val = (pixdata.apixels[spix] ^ xor_val) & and_val; + if (spix_val >= 32 && spix_val < 64) { + var c = (colors_for_drawing.color_regs_aga[spix_val - 32] >>> 1) & 0x7F7F7F; + dpix_val = CONVERT_RGB(c); + } else + dpix_val = p_acolors[spix_val]; + spix++; + tmp_val2 = dpix_val; + spix_val = (pixdata.apixels[spix] ^ xor_val) & and_val; + if (spix_val >= 32 && spix_val < 64) { + var c = (colors_for_drawing.color_regs_aga[spix_val - 32] >>> 1) & 0x7F7F7F; + dpix_val = CONVERT_RGB(c); + } else + dpix_val = p_acolors[spix_val]; + spix++; + tmp_val3 = dpix_val; + spix_val = (pixdata.apixels[spix] ^ xor_val) & and_val; + if (spix_val >= 32 && spix_val < 64) { + var c = (colors_for_drawing.color_regs_aga[spix_val - 32] >>> 1) & 0x7F7F7F; + dpix_val = CONVERT_RGB(c); + } else + dpix_val = p_acolors[spix_val]; + tmp_val = merge_2pixel16(tmp_val, tmp_val2); + tmp_val2 = merge_2pixel16(tmp_val3, dpix_val); + dpix_val = merge_2pixel16(tmp_val, tmp_val2); + spix++; + } + out_val = ((out_val << 16) | (dpix_val & 0xFFFF)) >>> 0; + buf[dpix + xlinebuffer_pos] = out_val >>> 16; + buf[dpix + xlinebuffer_pos + 1] = out_val & 0xffff; + dpix += 2; + } + if (rem) { + var spix_val = 0; + var dpix_val = 0; + spix_val = (pixdata.apixels[spix] ^ xor_val) & and_val; + if (spix_val >= 32 && spix_val < 64) { + var c = (colors_for_drawing.color_regs_aga[spix_val - 32] >>> 1) & 0x7F7F7F; + dpix_val = CONVERT_RGB(c); + } else + dpix_val = p_acolors[spix_val]; + { + var tmp_val, tmp_val2, tmp_val3; + spix++; + tmp_val = dpix_val; + spix_val = (pixdata.apixels[spix] ^ xor_val) & and_val; + if (spix_val >= 32 && spix_val < 64) { + var c = (colors_for_drawing.color_regs_aga[spix_val - 32] >>> 1) & 0x7F7F7F; + dpix_val = CONVERT_RGB(c); + } else + dpix_val = p_acolors[spix_val]; + spix++; + tmp_val2 = dpix_val; + spix_val = (pixdata.apixels[spix] ^ xor_val) & and_val; + if (spix_val >= 32 && spix_val < 64) { + var c = (colors_for_drawing.color_regs_aga[spix_val - 32] >>> 1) & 0x7F7F7F; + dpix_val = CONVERT_RGB(c); + } else + dpix_val = p_acolors[spix_val]; + spix++; + tmp_val3 = dpix_val; + spix_val = (pixdata.apixels[spix] ^ xor_val) & and_val; + if (spix_val >= 32 && spix_val < 64) { + var c = (colors_for_drawing.color_regs_aga[spix_val - 32] >>> 1) & 0x7F7F7F; + dpix_val = CONVERT_RGB(c); + } else + dpix_val = p_acolors[spix_val]; + tmp_val = merge_2pixel16(tmp_val, tmp_val2); + tmp_val2 = merge_2pixel16(tmp_val3, dpix_val); + dpix_val = merge_2pixel16(tmp_val, tmp_val2); + spix++; + } + buf[dpix + xlinebuffer_pos] = dpix_val; dpix++; + } + } else { + if ((dpix + xlinebuffer_pos) & 2) { + var spix_val = 0; + var dpix_val = 0; + spix_val = (pixdata.apixels[spix] ^ xor_val) & and_val; + dpix_val = p_acolors[spix_val]; + { + var tmp_val, tmp_val2, tmp_val3; + spix++; + tmp_val = dpix_val; + spix_val = (pixdata.apixels[spix] ^ xor_val) & and_val; + dpix_val = p_acolors[spix_val]; + spix++; + tmp_val2 = dpix_val; + spix_val = (pixdata.apixels[spix] ^ xor_val) & and_val; + dpix_val = p_acolors[spix_val]; + spix++; + tmp_val3 = dpix_val; + spix_val = (pixdata.apixels[spix] ^ xor_val) & and_val; + dpix_val = p_acolors[spix_val]; + tmp_val = merge_2pixel16(tmp_val, tmp_val2); + tmp_val2 = merge_2pixel16(tmp_val3, dpix_val); + dpix_val = merge_2pixel16(tmp_val, tmp_val2); + spix++; + } + buf[dpix + xlinebuffer_pos] = dpix_val; dpix++; + } + if (dpix >= dpix_end) + return spix; + var rem = (dpix_end + xlinebuffer_pos) & 2; + if (rem) + dpix_end--; + while (dpix < dpix_end) { + var spix_val = 0; + var dpix_val = 0; + var out_val = 0; + spix_val = (pixdata.apixels[spix] ^ xor_val) & and_val; + dpix_val = p_acolors[spix_val]; + { + var tmp_val, tmp_val2, tmp_val3; + spix++; + tmp_val = dpix_val; + spix_val = (pixdata.apixels[spix] ^ xor_val) & and_val; + dpix_val = p_acolors[spix_val]; + spix++; + tmp_val2 = dpix_val; + spix_val = (pixdata.apixels[spix] ^ xor_val) & and_val; + dpix_val = p_acolors[spix_val]; + spix++; + tmp_val3 = dpix_val; + spix_val = (pixdata.apixels[spix] ^ xor_val) & and_val; + dpix_val = p_acolors[spix_val]; + tmp_val = merge_2pixel16(tmp_val, tmp_val2); + tmp_val2 = merge_2pixel16(tmp_val3, dpix_val); + dpix_val = merge_2pixel16(tmp_val, tmp_val2); + spix++; + } + out_val = dpix_val; + spix_val = (pixdata.apixels[spix] ^ xor_val) & and_val; + dpix_val = p_acolors[spix_val]; + { + var tmp_val, tmp_val2, tmp_val3; + spix++; + tmp_val = dpix_val; + spix_val = (pixdata.apixels[spix] ^ xor_val) & and_val; + dpix_val = p_acolors[spix_val]; + spix++; + tmp_val2 = dpix_val; + spix_val = (pixdata.apixels[spix] ^ xor_val) & and_val; + dpix_val = p_acolors[spix_val]; + spix++; + tmp_val3 = dpix_val; + spix_val = (pixdata.apixels[spix] ^ xor_val) & and_val; + dpix_val = p_acolors[spix_val]; + tmp_val = merge_2pixel16(tmp_val, tmp_val2); + tmp_val2 = merge_2pixel16(tmp_val3, dpix_val); + dpix_val = merge_2pixel16(tmp_val, tmp_val2); + spix++; + } + out_val = ((out_val << 16) | (dpix_val & 0xFFFF)) >>> 0; + buf[dpix + xlinebuffer_pos] = out_val >>> 16; + buf[dpix + xlinebuffer_pos + 1] = out_val & 0xffff; + dpix += 2; + } + if (rem) { + var spix_val = 0; + var dpix_val = 0; + spix_val = (pixdata.apixels[spix] ^ xor_val) & and_val; + dpix_val = p_acolors[spix_val]; + { + var tmp_val, tmp_val2, tmp_val3; + spix++; + tmp_val = dpix_val; + spix_val = (pixdata.apixels[spix] ^ xor_val) & and_val; + dpix_val = p_acolors[spix_val]; + spix++; + tmp_val2 = dpix_val; + spix_val = (pixdata.apixels[spix] ^ xor_val) & and_val; + dpix_val = p_acolors[spix_val]; + spix++; + tmp_val3 = dpix_val; + spix_val = (pixdata.apixels[spix] ^ xor_val) & and_val; + dpix_val = p_acolors[spix_val]; + tmp_val = merge_2pixel16(tmp_val, tmp_val2); + tmp_val2 = merge_2pixel16(tmp_val3, dpix_val); + dpix_val = merge_2pixel16(tmp_val, tmp_val2); + spix++; + } + buf[dpix + xlinebuffer_pos] = dpix_val; dpix++; + } + } + return spix; + } + + function linetoscr_16_aga_spr(spix, dpix, dpix_end) + { + var buf = xlinebuffer; + var sprcol = 0; + var xor_val = bplxor; + var and_val = bpland; + if (bplham) { + while (dpix < dpix_end) { + var sprpix_val = 0; + var spix_val = 0; + var dpix_val = 0; + var out_val = 0; + sprpix_val = pixdata.apixels[spix]; + spix_val = (pixdata.apixels[spix] ^ xor_val) & and_val; + spix_val = ham_linebuf[spix]; + dpix_val = CONVERT_RGB(spix_val); + spix++; + out_val = dpix_val; + if (spritepixels[dpix + spritepixels_pos].data) { + sprcol = render_sprites(dpix + 0, 0, sprpix_val, 1); + if (sprcol) { + out_val = p_acolors[sprcol]; + } + } + buf[dpix + xlinebuffer_pos] = out_val; dpix++; + } + } else if (bpldualpf) { + var lookup = bpldualpfpri ? dblpf_ind2_aga : dblpf_ind1_aga; + var lookup_no = bpldualpfpri ? dblpf_2nd2 : dblpf_2nd1; + while (dpix < dpix_end) { + var sprpix_val = 0; + var spix_val = 0; + var dpix_val = 0; + var out_val = 0; + spix_val = pixdata.apixels[spix]; + sprpix_val = spix_val; + { + var val = lookup[spix_val]; + if (lookup_no[spix_val]) + val += dblpfofs[bpldualpf2of]; + val ^= xor_val; + dpix_val = p_acolors[val]; + } + spix++; + out_val = dpix_val; + if (spritepixels[dpix + spritepixels_pos].data) { + sprcol = render_sprites(dpix + 0, 1, sprpix_val, 1); + if (sprcol) { + out_val = p_acolors[sprcol]; + } + } + buf[dpix + xlinebuffer_pos] = out_val; dpix++; + } + } else if (bplehb) { + while (dpix < dpix_end) { + var sprpix_val = 0; + var spix_val = 0; + var dpix_val = 0; + var out_val = 0; + sprpix_val = pixdata.apixels[spix]; + spix_val = (pixdata.apixels[spix] ^ xor_val) & and_val; + if (spix_val >= 32 && spix_val < 64) { + var c = (colors_for_drawing.color_regs_aga[spix_val - 32] >>> 1) & 0x7F7F7F; + dpix_val = CONVERT_RGB(c); + } else + dpix_val = p_acolors[spix_val]; + spix++; + out_val = dpix_val; + if (spritepixels[dpix + spritepixels_pos].data) { + sprcol = render_sprites(dpix + 0, 0, sprpix_val, 1); + if (sprcol) { + out_val = p_acolors[sprcol]; + } + } + buf[dpix + xlinebuffer_pos] = out_val; dpix++; + } + } else { + while (dpix < dpix_end) { + var sprpix_val = 0; + var spix_val = 0; + var dpix_val = 0; + var out_val = 0; + sprpix_val = pixdata.apixels[spix]; + spix_val = (pixdata.apixels[spix] ^ xor_val) & and_val; + dpix_val = p_acolors[spix_val]; + spix++; + out_val = dpix_val; + if (spritepixels[dpix + spritepixels_pos].data) { + sprcol = render_sprites(dpix + 0, 0, sprpix_val, 1); + if (sprcol) { + out_val = p_acolors[sprcol]; + } + } + buf[dpix + xlinebuffer_pos] = out_val; dpix++; + } + } + return spix; + } + + function linetoscr_16_stretch1_aga_spr(spix, dpix, dpix_end) + { + var buf = xlinebuffer; + var sprcol = 0; + var xor_val = bplxor; + var and_val = bpland; + if (bplham) { + while (dpix < dpix_end) { + var sprpix_val = 0; + var spix_val = 0; + var dpix_val = 0; + var out_val = 0; + sprpix_val = pixdata.apixels[spix]; + spix_val = (pixdata.apixels[spix] ^ xor_val) & and_val; + spix_val = ham_linebuf[spix]; + dpix_val = CONVERT_RGB(spix_val); + spix++; + out_val = dpix_val; + { + var out_val1 = out_val; + var out_val2 = out_val; + if (spritepixels[dpix + spritepixels_pos].data) { + sprcol = render_sprites(dpix, 0, sprpix_val, 1); + if (sprcol) { + out_val1 = p_acolors[sprcol]; + } + } + if (spritepixels[dpix + spritepixels_pos + 1].data) { + sprcol = render_sprites(dpix + 1, 0, sprpix_val, 1); + if (sprcol) { + out_val2 = p_acolors[sprcol]; + } + } + buf[dpix + xlinebuffer_pos] = out_val1; dpix++; + buf[dpix + xlinebuffer_pos] = out_val2; dpix++; + } + } + } else if (bpldualpf) { + var lookup = bpldualpfpri ? dblpf_ind2_aga : dblpf_ind1_aga; + var lookup_no = bpldualpfpri ? dblpf_2nd2 : dblpf_2nd1; + while (dpix < dpix_end) { + var sprpix_val = 0; + var spix_val = 0; + var dpix_val = 0; + var out_val = 0; + spix_val = pixdata.apixels[spix]; + sprpix_val = spix_val; + { + var val = lookup[spix_val]; + if (lookup_no[spix_val]) + val += dblpfofs[bpldualpf2of]; + val ^= xor_val; + dpix_val = p_acolors[val]; + } + spix++; + out_val = dpix_val; + { + var out_val1 = out_val; + var out_val2 = out_val; + if (spritepixels[dpix + spritepixels_pos].data) { + sprcol = render_sprites(dpix, 1, sprpix_val, 1); + if (sprcol) { + out_val1 = p_acolors[sprcol]; + } + } + if (spritepixels[dpix + spritepixels_pos + 1].data) { + sprcol = render_sprites(dpix + 1, 1, sprpix_val, 1); + if (sprcol) { + out_val2 = p_acolors[sprcol]; + } + } + buf[dpix + xlinebuffer_pos] = out_val1; dpix++; + buf[dpix + xlinebuffer_pos] = out_val2; dpix++; + } + } + } else if (bplehb) { + while (dpix < dpix_end) { + var sprpix_val = 0; + var spix_val = 0; + var dpix_val = 0; + var out_val = 0; + sprpix_val = pixdata.apixels[spix]; + spix_val = (pixdata.apixels[spix] ^ xor_val) & and_val; + if (spix_val >= 32 && spix_val < 64) { + var c = (colors_for_drawing.color_regs_aga[spix_val - 32] >>> 1) & 0x7F7F7F; + dpix_val = CONVERT_RGB(c); + } else + dpix_val = p_acolors[spix_val]; + spix++; + out_val = dpix_val; + { + var out_val1 = out_val; + var out_val2 = out_val; + if (spritepixels[dpix + spritepixels_pos].data) { + sprcol = render_sprites(dpix, 0, sprpix_val, 1); + if (sprcol) { + out_val1 = p_acolors[sprcol]; + } + } + if (spritepixels[dpix + spritepixels_pos + 1].data) { + sprcol = render_sprites(dpix + 1, 0, sprpix_val, 1); + if (sprcol) { + out_val2 = p_acolors[sprcol]; + } + } + buf[dpix + xlinebuffer_pos] = out_val1; dpix++; + buf[dpix + xlinebuffer_pos] = out_val2; dpix++; + } + } + } else { + while (dpix < dpix_end) { + var sprpix_val = 0; + var spix_val = 0; + var dpix_val = 0; + var out_val = 0; + sprpix_val = pixdata.apixels[spix]; + spix_val = (pixdata.apixels[spix] ^ xor_val) & and_val; + dpix_val = p_acolors[spix_val]; + spix++; + out_val = dpix_val; + { + var out_val1 = out_val; + var out_val2 = out_val; + if (spritepixels[dpix + spritepixels_pos].data) { + sprcol = render_sprites(dpix, 0, sprpix_val, 1); + if (sprcol) { + out_val1 = p_acolors[sprcol]; + } + } + if (spritepixels[dpix + spritepixels_pos + 1].data) { + sprcol = render_sprites(dpix + 1, 0, sprpix_val, 1); + if (sprcol) { + out_val2 = p_acolors[sprcol]; + } + } + buf[dpix + xlinebuffer_pos] = out_val1; dpix++; + buf[dpix + xlinebuffer_pos] = out_val2; dpix++; + } + } + } + return spix; + } + + function linetoscr_16_stretch2_aga_spr(spix, dpix, dpix_end) + { + var buf = xlinebuffer; + var sprcol = 0; + var xor_val = bplxor; + var and_val = bpland; + if (bplham) { + while (dpix < dpix_end) { + var sprpix_val = 0; + var spix_val = 0; + var dpix_val = 0; + var out_val = 0; + sprpix_val = pixdata.apixels[spix]; + spix_val = (pixdata.apixels[spix] ^ xor_val) & and_val; + spix_val = ham_linebuf[spix]; + dpix_val = CONVERT_RGB(spix_val); + spix++; + out_val = dpix_val; + { + var out_val1 = out_val; + var out_val2 = out_val; + var out_val3 = out_val; + var out_val4 = out_val; + if (spritepixels[dpix + spritepixels_pos].data) { + var sprcol = render_sprites(dpix, 0, sprpix_val, 1); + if (sprcol) { + out_val1 = p_acolors[sprcol]; + } + } + if (spritepixels[dpix + spritepixels_pos + 1].data) { + sprcol = render_sprites(dpix + 1, 0, sprpix_val, 1); + if (sprcol) { + out_val2 = p_acolors[sprcol]; + } + } + if (spritepixels[dpix + spritepixels_pos + 2].data) { + sprcol = render_sprites(dpix + 2, 0, sprpix_val, 1); + if (sprcol) { + out_val3 = p_acolors[sprcol]; + } + } + if (spritepixels[dpix + spritepixels_pos + 3].data) { + sprcol = render_sprites(dpix + 3, 0, sprpix_val, 1); + if (sprcol) { + out_val4 = p_acolors[sprcol]; + } + } + buf[dpix + xlinebuffer_pos] = out_val1; dpix++; + buf[dpix + xlinebuffer_pos] = out_val2; dpix++; + buf[dpix + xlinebuffer_pos] = out_val3; dpix++; + buf[dpix + xlinebuffer_pos] = out_val4; dpix++; + } + } + } else if (bpldualpf) { + var lookup = bpldualpfpri ? dblpf_ind2_aga : dblpf_ind1_aga; + var lookup_no = bpldualpfpri ? dblpf_2nd2 : dblpf_2nd1; + while (dpix < dpix_end) { + var sprpix_val = 0; + var spix_val = 0; + var dpix_val = 0; + var out_val = 0; + spix_val = pixdata.apixels[spix]; + sprpix_val = spix_val; + { + var val = lookup[spix_val]; + if (lookup_no[spix_val]) + val += dblpfofs[bpldualpf2of]; + val ^= xor_val; + dpix_val = p_acolors[val]; + } + spix++; + out_val = dpix_val; + { + var out_val1 = out_val; + var out_val2 = out_val; + var out_val3 = out_val; + var out_val4 = out_val; + if (spritepixels[dpix + spritepixels_pos].data) { + var sprcol = render_sprites(dpix, 1, sprpix_val, 1); + if (sprcol) { + out_val1 = p_acolors[sprcol]; + } + } + if (spritepixels[dpix + spritepixels_pos + 1].data) { + sprcol = render_sprites(dpix + 1, 1, sprpix_val, 1); + if (sprcol) { + out_val2 = p_acolors[sprcol]; + } + } + if (spritepixels[dpix + spritepixels_pos + 2].data) { + sprcol = render_sprites(dpix + 2, 1, sprpix_val, 1); + if (sprcol) { + out_val3 = p_acolors[sprcol]; + } + } + if (spritepixels[dpix + spritepixels_pos + 3].data) { + sprcol = render_sprites(dpix + 3, 1, sprpix_val, 1); + if (sprcol) { + out_val4 = p_acolors[sprcol]; + } + } + buf[dpix + xlinebuffer_pos] = out_val1; dpix++; + buf[dpix + xlinebuffer_pos] = out_val2; dpix++; + buf[dpix + xlinebuffer_pos] = out_val3; dpix++; + buf[dpix + xlinebuffer_pos] = out_val4; dpix++; + } + } + } else if (bplehb) { + while (dpix < dpix_end) { + var sprpix_val = 0; + var spix_val = 0; + var dpix_val = 0; + var out_val = 0; + sprpix_val = pixdata.apixels[spix]; + spix_val = (pixdata.apixels[spix] ^ xor_val) & and_val; + if (spix_val >= 32 && spix_val < 64) { + var c = (colors_for_drawing.color_regs_aga[spix_val - 32] >>> 1) & 0x7F7F7F; + dpix_val = CONVERT_RGB(c); + } else + dpix_val = p_acolors[spix_val]; + spix++; + out_val = dpix_val; + { + var out_val1 = out_val; + var out_val2 = out_val; + var out_val3 = out_val; + var out_val4 = out_val; + if (spritepixels[dpix + spritepixels_pos].data) { + var sprcol = render_sprites(dpix, 0, sprpix_val, 1); + if (sprcol) { + out_val1 = p_acolors[sprcol]; + } + } + if (spritepixels[dpix + spritepixels_pos + 1].data) { + sprcol = render_sprites(dpix + 1, 0, sprpix_val, 1); + if (sprcol) { + out_val2 = p_acolors[sprcol]; + } + } + if (spritepixels[dpix + spritepixels_pos + 2].data) { + sprcol = render_sprites(dpix + 2, 0, sprpix_val, 1); + if (sprcol) { + out_val3 = p_acolors[sprcol]; + } + } + if (spritepixels[dpix + spritepixels_pos + 3].data) { + sprcol = render_sprites(dpix + 3, 0, sprpix_val, 1); + if (sprcol) { + out_val4 = p_acolors[sprcol]; + } + } + buf[dpix + xlinebuffer_pos] = out_val1; dpix++; + buf[dpix + xlinebuffer_pos] = out_val2; dpix++; + buf[dpix + xlinebuffer_pos] = out_val3; dpix++; + buf[dpix + xlinebuffer_pos] = out_val4; dpix++; + } + } + } else { + while (dpix < dpix_end) { + var sprpix_val = 0; + var spix_val = 0; + var dpix_val = 0; + var out_val = 0; + sprpix_val = pixdata.apixels[spix]; + spix_val = (pixdata.apixels[spix] ^ xor_val) & and_val; + dpix_val = p_acolors[spix_val]; + spix++; + out_val = dpix_val; + { + var out_val1 = out_val; + var out_val2 = out_val; + var out_val3 = out_val; + var out_val4 = out_val; + if (spritepixels[dpix + spritepixels_pos].data) { + var sprcol = render_sprites(dpix, 0, sprpix_val, 1); + if (sprcol) { + out_val1 = p_acolors[sprcol]; + } + } + if (spritepixels[dpix + spritepixels_pos + 1].data) { + sprcol = render_sprites(dpix + 1, 0, sprpix_val, 1); + if (sprcol) { + out_val2 = p_acolors[sprcol]; + } + } + if (spritepixels[dpix + spritepixels_pos + 2].data) { + sprcol = render_sprites(dpix + 2, 0, sprpix_val, 1); + if (sprcol) { + out_val3 = p_acolors[sprcol]; + } + } + if (spritepixels[dpix + spritepixels_pos + 3].data) { + sprcol = render_sprites(dpix + 3, 0, sprpix_val, 1); + if (sprcol) { + out_val4 = p_acolors[sprcol]; + } + } + buf[dpix + xlinebuffer_pos] = out_val1; dpix++; + buf[dpix + xlinebuffer_pos] = out_val2; dpix++; + buf[dpix + xlinebuffer_pos] = out_val3; dpix++; + buf[dpix + xlinebuffer_pos] = out_val4; dpix++; + } + } + } + return spix; + } + + function linetoscr_16_shrink1_aga_spr(spix, dpix, dpix_end) + { + var buf = xlinebuffer; + var sprcol = 0; + var xor_val = bplxor; + var and_val = bpland; + if (bplham) { + while (dpix < dpix_end) { + var sprpix_val = 0; + var spix_val = 0; + var dpix_val = 0; + var out_val = 0; + sprpix_val = pixdata.apixels[spix]; + spix_val = (pixdata.apixels[spix] ^ xor_val) & and_val; + spix_val = ham_linebuf[spix]; + dpix_val = CONVERT_RGB(spix_val); + spix += 2; + out_val = dpix_val; + if (spritepixels[dpix + spritepixels_pos].data) { + sprcol = render_sprites(dpix + 0, 0, sprpix_val, 1); + if (sprcol) { + out_val = p_acolors[sprcol]; + } + } + buf[dpix + xlinebuffer_pos] = out_val; dpix++; + } + } else if (bpldualpf) { + var lookup = bpldualpfpri ? dblpf_ind2_aga : dblpf_ind1_aga; + var lookup_no = bpldualpfpri ? dblpf_2nd2 : dblpf_2nd1; + while (dpix < dpix_end) { + var sprpix_val = 0; + var spix_val = 0; + var dpix_val = 0; + var out_val = 0; + spix_val = pixdata.apixels[spix]; + sprpix_val = spix_val; + { + var val = lookup[spix_val]; + if (lookup_no[spix_val]) + val += dblpfofs[bpldualpf2of]; + val ^= xor_val; + dpix_val = p_acolors[val]; + } + spix += 2; + out_val = dpix_val; + if (spritepixels[dpix + spritepixels_pos].data) { + sprcol = render_sprites(dpix + 0, 1, sprpix_val, 1); + if (sprcol) { + out_val = p_acolors[sprcol]; + } + } + buf[dpix + xlinebuffer_pos] = out_val; dpix++; + } + } else if (bplehb) { + while (dpix < dpix_end) { + var sprpix_val = 0; + var spix_val = 0; + var dpix_val = 0; + var out_val = 0; + sprpix_val = pixdata.apixels[spix]; + spix_val = (pixdata.apixels[spix] ^ xor_val) & and_val; + if (spix_val >= 32 && spix_val < 64) { + var c = (colors_for_drawing.color_regs_aga[spix_val - 32] >>> 1) & 0x7F7F7F; + dpix_val = CONVERT_RGB(c); + } else + dpix_val = p_acolors[spix_val]; + spix += 2; + out_val = dpix_val; + if (spritepixels[dpix + spritepixels_pos].data) { + sprcol = render_sprites(dpix + 0, 0, sprpix_val, 1); + if (sprcol) { + out_val = p_acolors[sprcol]; + } + } + buf[dpix + xlinebuffer_pos] = out_val; dpix++; + } + } else { + while (dpix < dpix_end) { + var sprpix_val = 0; + var spix_val = 0; + var dpix_val = 0; + var out_val = 0; + sprpix_val = pixdata.apixels[spix]; + spix_val = (pixdata.apixels[spix] ^ xor_val) & and_val; + dpix_val = p_acolors[spix_val]; + spix += 2; + out_val = dpix_val; + if (spritepixels[dpix + spritepixels_pos].data) { + sprcol = render_sprites(dpix + 0, 0, sprpix_val, 1); + if (sprcol) { + out_val = p_acolors[sprcol]; + } + } + buf[dpix + xlinebuffer_pos] = out_val; dpix++; + } + } + return spix; + } + + function linetoscr_16_shrink1f_aga_spr(spix, dpix, dpix_end) + { + var buf = xlinebuffer; + var sprcol = 0; + var xor_val = bplxor; + var and_val = bpland; + if (bplham) { + while (dpix < dpix_end) { + var sprpix_val = 0; + var spix_val = 0; + var dpix_val = 0; + var out_val = 0; + sprpix_val = pixdata.apixels[spix]; + spix_val = (pixdata.apixels[spix] ^ xor_val) & and_val; + spix_val = ham_linebuf[spix]; + dpix_val = CONVERT_RGB(spix_val); + { + var tmp_val; + spix++; + tmp_val = dpix_val; + sprpix_val = pixdata.apixels[spix]; + spix_val = (pixdata.apixels[spix] ^ xor_val) & and_val; + spix_val = ham_linebuf[spix]; + dpix_val = CONVERT_RGB(spix_val); + dpix_val = merge_2pixel16(dpix_val, tmp_val); + spix++; + } + out_val = dpix_val; + if (spritepixels[dpix + spritepixels_pos].data) { + sprcol = render_sprites(dpix + 0, 0, sprpix_val, 1); + if (sprcol) { + out_val = p_acolors[sprcol]; + } + } + buf[dpix + xlinebuffer_pos] = out_val; dpix++; + } + } else if (bpldualpf) { + var lookup = bpldualpfpri ? dblpf_ind2_aga : dblpf_ind1_aga; + var lookup_no = bpldualpfpri ? dblpf_2nd2 : dblpf_2nd1; + while (dpix < dpix_end) { + var sprpix_val = 0; + var spix_val = 0; + var dpix_val = 0; + var out_val = 0; + spix_val = pixdata.apixels[spix]; + sprpix_val = spix_val; + { + var val = lookup[spix_val]; + if (lookup_no[spix_val]) + val += dblpfofs[bpldualpf2of]; + val ^= xor_val; + dpix_val = p_acolors[val]; + } + { + var tmp_val; + spix++; + tmp_val = dpix_val; + spix_val = pixdata.apixels[spix]; + sprpix_val = spix_val; + { + var val = lookup[spix_val]; + if (lookup_no[spix_val]) + val += dblpfofs[bpldualpf2of]; + val ^= xor_val; + dpix_val = p_acolors[val]; + } + dpix_val = merge_2pixel16(dpix_val, tmp_val); + spix++; + } + out_val = dpix_val; + if (spritepixels[dpix + spritepixels_pos].data) { + sprcol = render_sprites(dpix + 0, 1, sprpix_val, 1); + if (sprcol) { + out_val = p_acolors[sprcol]; + } + } + buf[dpix + xlinebuffer_pos] = out_val; dpix++; + } + } else if (bplehb) { + while (dpix < dpix_end) { + var sprpix_val = 0; + var spix_val = 0; + var dpix_val = 0; + var out_val = 0; + sprpix_val = pixdata.apixels[spix]; + spix_val = (pixdata.apixels[spix] ^ xor_val) & and_val; + if (spix_val >= 32 && spix_val < 64) { + var c = (colors_for_drawing.color_regs_aga[spix_val - 32] >>> 1) & 0x7F7F7F; + dpix_val = CONVERT_RGB(c); + } else + dpix_val = p_acolors[spix_val]; + { + var tmp_val; + spix++; + tmp_val = dpix_val; + sprpix_val = pixdata.apixels[spix]; + spix_val = (pixdata.apixels[spix] ^ xor_val) & and_val; + if (spix_val >= 32 && spix_val < 64) { + var c = (colors_for_drawing.color_regs_aga[spix_val - 32] >>> 1) & 0x7F7F7F; + dpix_val = CONVERT_RGB(c); + } else + dpix_val = p_acolors[spix_val]; + dpix_val = merge_2pixel16(dpix_val, tmp_val); + spix++; + } + out_val = dpix_val; + if (spritepixels[dpix + spritepixels_pos].data) { + sprcol = render_sprites(dpix + 0, 0, sprpix_val, 1); + if (sprcol) { + out_val = p_acolors[sprcol]; + } + } + buf[dpix + xlinebuffer_pos] = out_val; dpix++; + } + } else { + while (dpix < dpix_end) { + var sprpix_val = 0; + var spix_val = 0; + var dpix_val = 0; + var out_val = 0; + sprpix_val = pixdata.apixels[spix]; + spix_val = (pixdata.apixels[spix] ^ xor_val) & and_val; + dpix_val = p_acolors[spix_val]; + { + var tmp_val; + spix++; + tmp_val = dpix_val; + sprpix_val = pixdata.apixels[spix]; + spix_val = (pixdata.apixels[spix] ^ xor_val) & and_val; + dpix_val = p_acolors[spix_val]; + dpix_val = merge_2pixel16(dpix_val, tmp_val); + spix++; + } + out_val = dpix_val; + if (spritepixels[dpix + spritepixels_pos].data) { + sprcol = render_sprites(dpix + 0, 0, sprpix_val, 1); + if (sprcol) { + out_val = p_acolors[sprcol]; + } + } + buf[dpix + xlinebuffer_pos] = out_val; dpix++; + } + } + return spix; + } + + function linetoscr_16_shrink2_aga_spr(spix, dpix, dpix_end) + { + var buf = xlinebuffer; + var sprcol = 0; + var xor_val = bplxor; + var and_val = bpland; + if (bplham) { + while (dpix < dpix_end) { + var sprpix_val = 0; + var spix_val = 0; + var dpix_val = 0; + var out_val = 0; + sprpix_val = pixdata.apixels[spix]; + spix_val = (pixdata.apixels[spix] ^ xor_val) & and_val; + spix_val = ham_linebuf[spix]; + dpix_val = CONVERT_RGB(spix_val); + spix += 4; + out_val = dpix_val; + if (spritepixels[dpix + spritepixels_pos].data) { + sprcol = render_sprites(dpix + 0, 0, sprpix_val, 1); + if (sprcol) { + out_val = p_acolors[sprcol]; + } + } + buf[dpix + xlinebuffer_pos] = out_val; dpix++; + } + } else if (bpldualpf) { + var lookup = bpldualpfpri ? dblpf_ind2_aga : dblpf_ind1_aga; + var lookup_no = bpldualpfpri ? dblpf_2nd2 : dblpf_2nd1; + while (dpix < dpix_end) { + var sprpix_val = 0; + var spix_val = 0; + var dpix_val = 0; + var out_val = 0; + spix_val = pixdata.apixels[spix]; + sprpix_val = spix_val; + { + var val = lookup[spix_val]; + if (lookup_no[spix_val]) + val += dblpfofs[bpldualpf2of]; + val ^= xor_val; + dpix_val = p_acolors[val]; + } + spix += 4; + out_val = dpix_val; + if (spritepixels[dpix + spritepixels_pos].data) { + sprcol = render_sprites(dpix + 0, 1, sprpix_val, 1); + if (sprcol) { + out_val = p_acolors[sprcol]; + } + } + buf[dpix + xlinebuffer_pos] = out_val; dpix++; + } + } else if (bplehb) { + while (dpix < dpix_end) { + var sprpix_val = 0; + var spix_val = 0; + var dpix_val = 0; + var out_val = 0; + sprpix_val = pixdata.apixels[spix]; + spix_val = (pixdata.apixels[spix] ^ xor_val) & and_val; + if (spix_val >= 32 && spix_val < 64) { + var c = (colors_for_drawing.color_regs_aga[spix_val - 32] >>> 1) & 0x7F7F7F; + dpix_val = CONVERT_RGB(c); + } else + dpix_val = p_acolors[spix_val]; + spix += 4; + out_val = dpix_val; + if (spritepixels[dpix + spritepixels_pos].data) { + sprcol = render_sprites(dpix + 0, 0, sprpix_val, 1); + if (sprcol) { + out_val = p_acolors[sprcol]; + } + } + buf[dpix + xlinebuffer_pos] = out_val; dpix++; + } + } else { + while (dpix < dpix_end) { + var sprpix_val = 0; + var spix_val = 0; + var dpix_val = 0; + var out_val = 0; + sprpix_val = pixdata.apixels[spix]; + spix_val = (pixdata.apixels[spix] ^ xor_val) & and_val; + dpix_val = p_acolors[spix_val]; + spix += 4; + out_val = dpix_val; + if (spritepixels[dpix + spritepixels_pos].data) { + sprcol = render_sprites(dpix + 0, 0, sprpix_val, 1); + if (sprcol) { + out_val = p_acolors[sprcol]; + } + } + buf[dpix + xlinebuffer_pos] = out_val; dpix++; + } + } + return spix; + } + + function linetoscr_16_shrink2f_aga_spr(spix, dpix, dpix_end) + { + var buf = xlinebuffer; + var sprcol = 0; + var xor_val = bplxor; + var and_val = bpland; + if (bplham) { + while (dpix < dpix_end) { + var sprpix_val = 0; + var spix_val = 0; + var dpix_val = 0; + var out_val = 0; + sprpix_val = pixdata.apixels[spix]; + spix_val = (pixdata.apixels[spix] ^ xor_val) & and_val; + spix_val = ham_linebuf[spix]; + dpix_val = CONVERT_RGB(spix_val); + { + var tmp_val, tmp_val2, tmp_val3; + spix++; + tmp_val = dpix_val; + sprpix_val = pixdata.apixels[spix]; + spix_val = (pixdata.apixels[spix] ^ xor_val) & and_val; + spix_val = ham_linebuf[spix]; + dpix_val = CONVERT_RGB(spix_val); + spix++; + tmp_val2 = dpix_val; + sprpix_val = pixdata.apixels[spix]; + spix_val = (pixdata.apixels[spix] ^ xor_val) & and_val; + spix_val = ham_linebuf[spix]; + dpix_val = CONVERT_RGB(spix_val); + spix++; + tmp_val3 = dpix_val; + sprpix_val = pixdata.apixels[spix]; + spix_val = (pixdata.apixels[spix] ^ xor_val) & and_val; + spix_val = ham_linebuf[spix]; + dpix_val = CONVERT_RGB(spix_val); + tmp_val = merge_2pixel16(tmp_val, tmp_val2); + tmp_val2 = merge_2pixel16(tmp_val3, dpix_val); + dpix_val = merge_2pixel16(tmp_val, tmp_val2); + spix++; + } + out_val = dpix_val; + if (spritepixels[dpix + spritepixels_pos].data) { + sprcol = render_sprites(dpix + 0, 0, sprpix_val, 1); + if (sprcol) { + out_val = p_acolors[sprcol]; + } + } + buf[dpix + xlinebuffer_pos] = out_val; dpix++; + } + } else if (bpldualpf) { + var lookup = bpldualpfpri ? dblpf_ind2_aga : dblpf_ind1_aga; + var lookup_no = bpldualpfpri ? dblpf_2nd2 : dblpf_2nd1; + while (dpix < dpix_end) { + var sprpix_val = 0; + var spix_val = 0; + var dpix_val = 0; + var out_val = 0; + spix_val = pixdata.apixels[spix]; + sprpix_val = spix_val; + { + var val = lookup[spix_val]; + if (lookup_no[spix_val]) + val += dblpfofs[bpldualpf2of]; + val ^= xor_val; + dpix_val = p_acolors[val]; + } + { + var tmp_val, tmp_val2, tmp_val3; + spix++; + tmp_val = dpix_val; + spix_val = pixdata.apixels[spix]; + sprpix_val = spix_val; + { + var val = lookup[spix_val]; + if (lookup_no[spix_val]) + val += dblpfofs[bpldualpf2of]; + val ^= xor_val; + dpix_val = p_acolors[val]; + } + spix++; + tmp_val2 = dpix_val; + spix_val = pixdata.apixels[spix]; + sprpix_val = spix_val; + { + var val = lookup[spix_val]; + if (lookup_no[spix_val]) + val += dblpfofs[bpldualpf2of]; + val ^= xor_val; + dpix_val = p_acolors[val]; + } + spix++; + tmp_val3 = dpix_val; + spix_val = pixdata.apixels[spix]; + sprpix_val = spix_val; + { + var val = lookup[spix_val]; + if (lookup_no[spix_val]) + val += dblpfofs[bpldualpf2of]; + val ^= xor_val; + dpix_val = p_acolors[val]; + } + tmp_val = merge_2pixel16(tmp_val, tmp_val2); + tmp_val2 = merge_2pixel16(tmp_val3, dpix_val); + dpix_val = merge_2pixel16(tmp_val, tmp_val2); + spix++; + } + out_val = dpix_val; + if (spritepixels[dpix + spritepixels_pos].data) { + sprcol = render_sprites(dpix + 0, 1, sprpix_val, 1); + if (sprcol) { + out_val = p_acolors[sprcol]; + } + } + buf[dpix + xlinebuffer_pos] = out_val; dpix++; + } + } else if (bplehb) { + while (dpix < dpix_end) { + var sprpix_val = 0; + var spix_val = 0; + var dpix_val = 0; + var out_val = 0; + sprpix_val = pixdata.apixels[spix]; + spix_val = (pixdata.apixels[spix] ^ xor_val) & and_val; + if (spix_val >= 32 && spix_val < 64) { + var c = (colors_for_drawing.color_regs_aga[spix_val - 32] >>> 1) & 0x7F7F7F; + dpix_val = CONVERT_RGB(c); + } else + dpix_val = p_acolors[spix_val]; + { + var tmp_val, tmp_val2, tmp_val3; + spix++; + tmp_val = dpix_val; + sprpix_val = pixdata.apixels[spix]; + spix_val = (pixdata.apixels[spix] ^ xor_val) & and_val; + if (spix_val >= 32 && spix_val < 64) { + var c = (colors_for_drawing.color_regs_aga[spix_val - 32] >>> 1) & 0x7F7F7F; + dpix_val = CONVERT_RGB(c); + } else + dpix_val = p_acolors[spix_val]; + spix++; + tmp_val2 = dpix_val; + sprpix_val = pixdata.apixels[spix]; + spix_val = (pixdata.apixels[spix] ^ xor_val) & and_val; + if (spix_val >= 32 && spix_val < 64) { + var c = (colors_for_drawing.color_regs_aga[spix_val - 32] >>> 1) & 0x7F7F7F; + dpix_val = CONVERT_RGB(c); + } else + dpix_val = p_acolors[spix_val]; + spix++; + tmp_val3 = dpix_val; + sprpix_val = pixdata.apixels[spix]; + spix_val = (pixdata.apixels[spix] ^ xor_val) & and_val; + if (spix_val >= 32 && spix_val < 64) { + var c = (colors_for_drawing.color_regs_aga[spix_val - 32] >>> 1) & 0x7F7F7F; + dpix_val = CONVERT_RGB(c); + } else + dpix_val = p_acolors[spix_val]; + tmp_val = merge_2pixel16(tmp_val, tmp_val2); + tmp_val2 = merge_2pixel16(tmp_val3, dpix_val); + dpix_val = merge_2pixel16(tmp_val, tmp_val2); + spix++; + } + out_val = dpix_val; + if (spritepixels[dpix + spritepixels_pos].data) { + sprcol = render_sprites(dpix + 0, 0, sprpix_val, 1); + if (sprcol) { + out_val = p_acolors[sprcol]; + } + } + buf[dpix + xlinebuffer_pos] = out_val; dpix++; + } + } else { + while (dpix < dpix_end) { + var sprpix_val = 0; + var spix_val = 0; + var dpix_val = 0; + var out_val = 0; + sprpix_val = pixdata.apixels[spix]; + spix_val = (pixdata.apixels[spix] ^ xor_val) & and_val; + dpix_val = p_acolors[spix_val]; + { + var tmp_val, tmp_val2, tmp_val3; + spix++; + tmp_val = dpix_val; + sprpix_val = pixdata.apixels[spix]; + spix_val = (pixdata.apixels[spix] ^ xor_val) & and_val; + dpix_val = p_acolors[spix_val]; + spix++; + tmp_val2 = dpix_val; + sprpix_val = pixdata.apixels[spix]; + spix_val = (pixdata.apixels[spix] ^ xor_val) & and_val; + dpix_val = p_acolors[spix_val]; + spix++; + tmp_val3 = dpix_val; + sprpix_val = pixdata.apixels[spix]; + spix_val = (pixdata.apixels[spix] ^ xor_val) & and_val; + dpix_val = p_acolors[spix_val]; + tmp_val = merge_2pixel16(tmp_val, tmp_val2); + tmp_val2 = merge_2pixel16(tmp_val3, dpix_val); + dpix_val = merge_2pixel16(tmp_val, tmp_val2); + spix++; + } + out_val = dpix_val; + if (spritepixels[dpix + spritepixels_pos].data) { + sprcol = render_sprites(dpix + 0, 0, sprpix_val, 1); + if (sprcol) { + out_val = p_acolors[sprcol]; + } + } + buf[dpix + xlinebuffer_pos] = out_val; dpix++; + } + } + return spix; + } + + function linetoscr_32(spix, dpix, dpix_end) + { + var buf = xlinebuffer; + if (bplham) { + while (dpix < dpix_end) { + var spix_val = 0; + var dpix_val = 0; + var out_val = 0; + spix_val = ham_linebuf[spix]; + dpix_val = p_xcolors[spix_val]; + spix++; + out_val = dpix_val; + buf[dpix + xlinebuffer_pos] = out_val; dpix++; + } + } else if (bpldualpf) { + var lookup = bpldualpfpri ? dblpf_ind2 : dblpf_ind1; + while (dpix < dpix_end) { + var spix_val = 0; + var dpix_val = 0; + var out_val = 0; + spix_val = pixdata.apixels[spix]; + dpix_val = p_acolors[lookup[spix_val]]; + spix++; + out_val = dpix_val; + buf[dpix + xlinebuffer_pos] = out_val; dpix++; + } + } else if (bplehb) { + while (dpix < dpix_end) { + var spix_val = 0; + var dpix_val = 0; + var out_val = 0; + spix_val = pixdata.apixels[spix]; + if (spix_val <= 31) + dpix_val = p_acolors[spix_val]; + else + dpix_val = p_xcolors[(colors_for_drawing.color_regs_ecs[spix_val - 32] >>> 1) & 0x777]; + spix++; + out_val = dpix_val; + buf[dpix + xlinebuffer_pos] = out_val; dpix++; + } + } else { + while (dpix < dpix_end) { + var spix_val = 0; + var dpix_val = 0; + var out_val = 0; + spix_val = pixdata.apixels[spix]; + dpix_val = p_acolors[spix_val]; + spix++; + out_val = dpix_val; + buf[dpix + xlinebuffer_pos] = out_val; dpix++; + } + } + return spix; + } + + function linetoscr_32_stretch1(spix, dpix, dpix_end) + { + var buf = xlinebuffer; + if (bplham) { + while (dpix < dpix_end) { + var spix_val = 0; + var dpix_val = 0; + var out_val = 0; + spix_val = ham_linebuf[spix]; + dpix_val = p_xcolors[spix_val]; + spix++; + out_val = dpix_val; + buf[dpix + xlinebuffer_pos] = out_val; dpix++; + buf[dpix + xlinebuffer_pos] = out_val; dpix++; + } + } else if (bpldualpf) { + var lookup = bpldualpfpri ? dblpf_ind2 : dblpf_ind1; + while (dpix < dpix_end) { + var spix_val = 0; + var dpix_val = 0; + var out_val = 0; + spix_val = pixdata.apixels[spix]; + dpix_val = p_acolors[lookup[spix_val]]; + spix++; + out_val = dpix_val; + buf[dpix + xlinebuffer_pos] = out_val; dpix++; + buf[dpix + xlinebuffer_pos] = out_val; dpix++; + } + } else if (bplehb) { + while (dpix < dpix_end) { + var spix_val = 0; + var dpix_val = 0; + var out_val = 0; + spix_val = pixdata.apixels[spix]; + if (spix_val <= 31) + dpix_val = p_acolors[spix_val]; + else + dpix_val = p_xcolors[(colors_for_drawing.color_regs_ecs[spix_val - 32] >>> 1) & 0x777]; + spix++; + out_val = dpix_val; + buf[dpix + xlinebuffer_pos] = out_val; dpix++; + buf[dpix + xlinebuffer_pos] = out_val; dpix++; + } + } else { + while (dpix < dpix_end) { + var spix_val = 0; + var dpix_val = 0; + var out_val = 0; + spix_val = pixdata.apixels[spix]; + dpix_val = p_acolors[spix_val]; + spix++; + out_val = dpix_val; + buf[dpix + xlinebuffer_pos] = out_val; dpix++; + buf[dpix + xlinebuffer_pos] = out_val; dpix++; + } + } + return spix; + } + + function linetoscr_32_stretch2(spix, dpix, dpix_end) + { + var buf = xlinebuffer; + if (bplham) { + while (dpix < dpix_end) { + var spix_val = 0; + var dpix_val = 0; + var out_val = 0; + spix_val = ham_linebuf[spix]; + dpix_val = p_xcolors[spix_val]; + spix++; + out_val = dpix_val; + buf[dpix + xlinebuffer_pos] = out_val; dpix++; + buf[dpix + xlinebuffer_pos] = out_val; dpix++; + buf[dpix + xlinebuffer_pos] = out_val; dpix++; + buf[dpix + xlinebuffer_pos] = out_val; dpix++; + } + } else if (bpldualpf) { + var lookup = bpldualpfpri ? dblpf_ind2 : dblpf_ind1; + while (dpix < dpix_end) { + var spix_val = 0; + var dpix_val = 0; + var out_val = 0; + spix_val = pixdata.apixels[spix]; + dpix_val = p_acolors[lookup[spix_val]]; + spix++; + out_val = dpix_val; + buf[dpix + xlinebuffer_pos] = out_val; dpix++; + buf[dpix + xlinebuffer_pos] = out_val; dpix++; + buf[dpix + xlinebuffer_pos] = out_val; dpix++; + buf[dpix + xlinebuffer_pos] = out_val; dpix++; + } + } else if (bplehb) { + while (dpix < dpix_end) { + var spix_val = 0; + var dpix_val = 0; + var out_val = 0; + spix_val = pixdata.apixels[spix]; + if (spix_val <= 31) + dpix_val = p_acolors[spix_val]; + else + dpix_val = p_xcolors[(colors_for_drawing.color_regs_ecs[spix_val - 32] >>> 1) & 0x777]; + spix++; + out_val = dpix_val; + buf[dpix + xlinebuffer_pos] = out_val; dpix++; + buf[dpix + xlinebuffer_pos] = out_val; dpix++; + buf[dpix + xlinebuffer_pos] = out_val; dpix++; + buf[dpix + xlinebuffer_pos] = out_val; dpix++; + } + } else { + while (dpix < dpix_end) { + var spix_val = 0; + var dpix_val = 0; + var out_val = 0; + spix_val = pixdata.apixels[spix]; + dpix_val = p_acolors[spix_val]; + spix++; + out_val = dpix_val; + buf[dpix + xlinebuffer_pos] = out_val; dpix++; + buf[dpix + xlinebuffer_pos] = out_val; dpix++; + buf[dpix + xlinebuffer_pos] = out_val; dpix++; + buf[dpix + xlinebuffer_pos] = out_val; dpix++; + } + } + return spix; + } + + function linetoscr_32_shrink1(spix, dpix, dpix_end) + { + var buf = xlinebuffer; + if (bplham) { + while (dpix < dpix_end) { + var spix_val = 0; + var dpix_val = 0; + var out_val = 0; + spix_val = ham_linebuf[spix]; + dpix_val = p_xcolors[spix_val]; + spix += 2; + out_val = dpix_val; + buf[dpix + xlinebuffer_pos] = out_val; dpix++; + } + } else if (bpldualpf) { + var lookup = bpldualpfpri ? dblpf_ind2 : dblpf_ind1; + while (dpix < dpix_end) { + var spix_val = 0; + var dpix_val = 0; + var out_val = 0; + spix_val = pixdata.apixels[spix]; + dpix_val = p_acolors[lookup[spix_val]]; + spix += 2; + out_val = dpix_val; + buf[dpix + xlinebuffer_pos] = out_val; dpix++; + } + } else if (bplehb) { + while (dpix < dpix_end) { + var spix_val = 0; + var dpix_val = 0; + var out_val = 0; + spix_val = pixdata.apixels[spix]; + if (spix_val <= 31) + dpix_val = p_acolors[spix_val]; + else + dpix_val = p_xcolors[(colors_for_drawing.color_regs_ecs[spix_val - 32] >>> 1) & 0x777]; + spix += 2; + out_val = dpix_val; + buf[dpix + xlinebuffer_pos] = out_val; dpix++; + } + } else { + while (dpix < dpix_end) { + var spix_val = 0; + var dpix_val = 0; + var out_val = 0; + spix_val = pixdata.apixels[spix]; + dpix_val = p_acolors[spix_val]; + spix += 2; + out_val = dpix_val; + buf[dpix + xlinebuffer_pos] = out_val; dpix++; + } + } + return spix; + } + + function linetoscr_32_shrink1f(spix, dpix, dpix_end) + { + var buf = xlinebuffer; + if (bplham) { + while (dpix < dpix_end) { + var spix_val = 0; + var dpix_val = 0; + var out_val = 0; + spix_val = ham_linebuf[spix]; + dpix_val = p_xcolors[spix_val]; + { + var tmp_val; + spix++; + tmp_val = dpix_val; + spix_val = ham_linebuf[spix]; + dpix_val = p_xcolors[spix_val]; + dpix_val = merge_2pixel32(dpix_val, tmp_val); + spix++; + } + out_val = dpix_val; + buf[dpix + xlinebuffer_pos] = out_val; dpix++; + } + } else if (bpldualpf) { + var lookup = bpldualpfpri ? dblpf_ind2 : dblpf_ind1; + while (dpix < dpix_end) { + var spix_val = 0; + var dpix_val = 0; + var out_val = 0; + spix_val = pixdata.apixels[spix]; + dpix_val = p_acolors[lookup[spix_val]]; + { + var tmp_val; + spix++; + tmp_val = dpix_val; + spix_val = pixdata.apixels[spix]; + dpix_val = p_acolors[lookup[spix_val]]; + dpix_val = merge_2pixel32(dpix_val, tmp_val); + spix++; + } + out_val = dpix_val; + buf[dpix + xlinebuffer_pos] = out_val; dpix++; + } + } else if (bplehb) { + while (dpix < dpix_end) { + var spix_val = 0; + var dpix_val = 0; + var out_val = 0; + spix_val = pixdata.apixels[spix]; + if (spix_val <= 31) + dpix_val = p_acolors[spix_val]; + else + dpix_val = p_xcolors[(colors_for_drawing.color_regs_ecs[spix_val - 32] >>> 1) & 0x777]; + { + var tmp_val; + spix++; + tmp_val = dpix_val; + spix_val = pixdata.apixels[spix]; + if (spix_val <= 31) + dpix_val = p_acolors[spix_val]; + else + dpix_val = p_xcolors[(colors_for_drawing.color_regs_ecs[spix_val - 32] >>> 1) & 0x777]; + dpix_val = merge_2pixel32(dpix_val, tmp_val); + spix++; + } + out_val = dpix_val; + buf[dpix + xlinebuffer_pos] = out_val; dpix++; + } + } else { + while (dpix < dpix_end) { + var spix_val = 0; + var dpix_val = 0; + var out_val = 0; + spix_val = pixdata.apixels[spix]; + dpix_val = p_acolors[spix_val]; + { + var tmp_val; + spix++; + tmp_val = dpix_val; + spix_val = pixdata.apixels[spix]; + dpix_val = p_acolors[spix_val]; + dpix_val = merge_2pixel32(dpix_val, tmp_val); + spix++; + } + out_val = dpix_val; + buf[dpix + xlinebuffer_pos] = out_val; dpix++; + } + } + return spix; + } + + function linetoscr_32_shrink2(spix, dpix, dpix_end) + { + var buf = xlinebuffer; + if (bplham) { + while (dpix < dpix_end) { + var spix_val = 0; + var dpix_val = 0; + var out_val = 0; + spix_val = ham_linebuf[spix]; + dpix_val = p_xcolors[spix_val]; + spix += 4; + out_val = dpix_val; + buf[dpix + xlinebuffer_pos] = out_val; dpix++; + } + } else if (bpldualpf) { + var lookup = bpldualpfpri ? dblpf_ind2 : dblpf_ind1; + while (dpix < dpix_end) { + var spix_val = 0; + var dpix_val = 0; + var out_val = 0; + spix_val = pixdata.apixels[spix]; + dpix_val = p_acolors[lookup[spix_val]]; + spix += 4; + out_val = dpix_val; + buf[dpix + xlinebuffer_pos] = out_val; dpix++; + } + } else if (bplehb) { + while (dpix < dpix_end) { + var spix_val = 0; + var dpix_val = 0; + var out_val = 0; + spix_val = pixdata.apixels[spix]; + if (spix_val <= 31) + dpix_val = p_acolors[spix_val]; + else + dpix_val = p_xcolors[(colors_for_drawing.color_regs_ecs[spix_val - 32] >>> 1) & 0x777]; + spix += 4; + out_val = dpix_val; + buf[dpix + xlinebuffer_pos] = out_val; dpix++; + } + } else { + while (dpix < dpix_end) { + var spix_val = 0; + var dpix_val = 0; + var out_val = 0; + spix_val = pixdata.apixels[spix]; + dpix_val = p_acolors[spix_val]; + spix += 4; + out_val = dpix_val; + buf[dpix + xlinebuffer_pos] = out_val; dpix++; + } + } + return spix; + } + + function linetoscr_32_shrink2f(spix, dpix, dpix_end) + { + var buf = xlinebuffer; + if (bplham) { + while (dpix < dpix_end) { + var spix_val = 0; + var dpix_val = 0; + var out_val = 0; + spix_val = ham_linebuf[spix]; + dpix_val = p_xcolors[spix_val]; + { + var tmp_val, tmp_val2, tmp_val3; + spix++; + tmp_val = dpix_val; + spix_val = ham_linebuf[spix]; + dpix_val = p_xcolors[spix_val]; + spix++; + tmp_val2 = dpix_val; + spix_val = ham_linebuf[spix]; + dpix_val = p_xcolors[spix_val]; + spix++; + tmp_val3 = dpix_val; + spix_val = ham_linebuf[spix]; + dpix_val = p_xcolors[spix_val]; + tmp_val = merge_2pixel32(tmp_val, tmp_val2); + tmp_val2 = merge_2pixel32(tmp_val3, dpix_val); + dpix_val = merge_2pixel32(tmp_val, tmp_val2); + spix++; + } + out_val = dpix_val; + buf[dpix + xlinebuffer_pos] = out_val; dpix++; + } + } else if (bpldualpf) { + var lookup = bpldualpfpri ? dblpf_ind2 : dblpf_ind1; + while (dpix < dpix_end) { + var spix_val = 0; + var dpix_val = 0; + var out_val = 0; + spix_val = pixdata.apixels[spix]; + dpix_val = p_acolors[lookup[spix_val]]; + { + var tmp_val, tmp_val2, tmp_val3; + spix++; + tmp_val = dpix_val; + spix_val = pixdata.apixels[spix]; + dpix_val = p_acolors[lookup[spix_val]]; + spix++; + tmp_val2 = dpix_val; + spix_val = pixdata.apixels[spix]; + dpix_val = p_acolors[lookup[spix_val]]; + spix++; + tmp_val3 = dpix_val; + spix_val = pixdata.apixels[spix]; + dpix_val = p_acolors[lookup[spix_val]]; + tmp_val = merge_2pixel32(tmp_val, tmp_val2); + tmp_val2 = merge_2pixel32(tmp_val3, dpix_val); + dpix_val = merge_2pixel32(tmp_val, tmp_val2); + spix++; + } + out_val = dpix_val; + buf[dpix + xlinebuffer_pos] = out_val; dpix++; + } + } else if (bplehb) { + while (dpix < dpix_end) { + var spix_val = 0; + var dpix_val = 0; + var out_val = 0; + spix_val = pixdata.apixels[spix]; + if (spix_val <= 31) + dpix_val = p_acolors[spix_val]; + else + dpix_val = p_xcolors[(colors_for_drawing.color_regs_ecs[spix_val - 32] >>> 1) & 0x777]; + { + var tmp_val, tmp_val2, tmp_val3; + spix++; + tmp_val = dpix_val; + spix_val = pixdata.apixels[spix]; + if (spix_val <= 31) + dpix_val = p_acolors[spix_val]; + else + dpix_val = p_xcolors[(colors_for_drawing.color_regs_ecs[spix_val - 32] >>> 1) & 0x777]; + spix++; + tmp_val2 = dpix_val; + spix_val = pixdata.apixels[spix]; + if (spix_val <= 31) + dpix_val = p_acolors[spix_val]; + else + dpix_val = p_xcolors[(colors_for_drawing.color_regs_ecs[spix_val - 32] >>> 1) & 0x777]; + spix++; + tmp_val3 = dpix_val; + spix_val = pixdata.apixels[spix]; + if (spix_val <= 31) + dpix_val = p_acolors[spix_val]; + else + dpix_val = p_xcolors[(colors_for_drawing.color_regs_ecs[spix_val - 32] >>> 1) & 0x777]; + tmp_val = merge_2pixel32(tmp_val, tmp_val2); + tmp_val2 = merge_2pixel32(tmp_val3, dpix_val); + dpix_val = merge_2pixel32(tmp_val, tmp_val2); + spix++; + } + out_val = dpix_val; + buf[dpix + xlinebuffer_pos] = out_val; dpix++; + } + } else { + while (dpix < dpix_end) { + var spix_val = 0; + var dpix_val = 0; + var out_val = 0; + spix_val = pixdata.apixels[spix]; + dpix_val = p_acolors[spix_val]; + { + var tmp_val, tmp_val2, tmp_val3; + spix++; + tmp_val = dpix_val; + spix_val = pixdata.apixels[spix]; + dpix_val = p_acolors[spix_val]; + spix++; + tmp_val2 = dpix_val; + spix_val = pixdata.apixels[spix]; + dpix_val = p_acolors[spix_val]; + spix++; + tmp_val3 = dpix_val; + spix_val = pixdata.apixels[spix]; + dpix_val = p_acolors[spix_val]; + tmp_val = merge_2pixel32(tmp_val, tmp_val2); + tmp_val2 = merge_2pixel32(tmp_val3, dpix_val); + dpix_val = merge_2pixel32(tmp_val, tmp_val2); + spix++; + } + out_val = dpix_val; + buf[dpix + xlinebuffer_pos] = out_val; dpix++; + } + } + return spix; + } + + function linetoscr_32_spr(spix, dpix, dpix_end) + { + var buf = xlinebuffer; + var sprcol = 0; + if (bplham) { + while (dpix < dpix_end) { + var sprpix_val = 0; + var spix_val = 0; + var dpix_val = 0; + var out_val = 0; + spix_val = ham_linebuf[spix]; + dpix_val = p_xcolors[spix_val]; + sprpix_val = pixdata.apixels[spix]; + spix++; + out_val = dpix_val; + if (spritepixels[dpix + spritepixels_pos].data) { + sprcol = render_sprites(dpix, 0, sprpix_val, 0); + if (sprcol) { + var spcol = p_acolors[sprcol]; + out_val = spcol; + } + } + buf[dpix + xlinebuffer_pos] = out_val; dpix++; + } + } else if (bpldualpf) { + var lookup = bpldualpfpri ? dblpf_ind2 : dblpf_ind1; + while (dpix < dpix_end) { + var sprpix_val = 0; + var spix_val = 0; + var dpix_val = 0; + var out_val = 0; + spix_val = pixdata.apixels[spix]; + sprpix_val = spix_val; + dpix_val = p_acolors[lookup[spix_val]]; + spix++; + out_val = dpix_val; + if (spritepixels[dpix + spritepixels_pos].data) { + sprcol = render_sprites(dpix, 1, sprpix_val, 0); + if (sprcol) { + var spcol = p_acolors[sprcol]; + out_val = spcol; + } + } + buf[dpix + xlinebuffer_pos] = out_val; dpix++; + } + } else if (bplehb) { + while (dpix < dpix_end) { + var sprpix_val = 0; + var spix_val = 0; + var dpix_val = 0; + var out_val = 0; + spix_val = pixdata.apixels[spix]; + sprpix_val = spix_val; + if (spix_val <= 31) + dpix_val = p_acolors[spix_val]; + else + dpix_val = p_xcolors[(colors_for_drawing.color_regs_ecs[spix_val - 32] >>> 1) & 0x777]; + spix++; + out_val = dpix_val; + if (spritepixels[dpix + spritepixels_pos].data) { + sprcol = render_sprites(dpix, 0, sprpix_val, 0); + if (sprcol) { + var spcol = p_acolors[sprcol]; + out_val = spcol; + } + } + buf[dpix + xlinebuffer_pos] = out_val; dpix++; + } + } else { + while (dpix < dpix_end) { + var sprpix_val = 0; + var spix_val = 0; + var dpix_val = 0; + var out_val = 0; + spix_val = pixdata.apixels[spix]; + sprpix_val = spix_val; + dpix_val = p_acolors[spix_val]; + spix++; + out_val = dpix_val; + if (spritepixels[dpix + spritepixels_pos].data) { + sprcol = render_sprites(dpix, 0, sprpix_val, 0); + if (sprcol) { + var spcol = p_acolors[sprcol]; + out_val = spcol; + } + } + buf[dpix + xlinebuffer_pos] = out_val; dpix++; + } + } + return spix; + } + + function linetoscr_32_stretch1_spr(spix, dpix, dpix_end) + { + var buf = xlinebuffer; + var sprcol = 0; + if (bplham) { + while (dpix < dpix_end) { + var sprpix_val = 0; + var spix_val = 0; + var dpix_val = 0; + var out_val = 0; + spix_val = ham_linebuf[spix]; + dpix_val = p_xcolors[spix_val]; + sprpix_val = pixdata.apixels[spix]; + spix++; + out_val = dpix_val; + if (spritepixels[dpix + spritepixels_pos].data) { + sprcol = render_sprites(dpix, 0, sprpix_val, 0); + if (sprcol) { + var spcol = p_acolors[sprcol]; + out_val = spcol; + } + } + buf[dpix + xlinebuffer_pos] = out_val; dpix++; + buf[dpix + xlinebuffer_pos] = out_val; dpix++; + } + } else if (bpldualpf) { + var lookup = bpldualpfpri ? dblpf_ind2 : dblpf_ind1; + while (dpix < dpix_end) { + var sprpix_val = 0; + var spix_val = 0; + var dpix_val = 0; + var out_val = 0; + spix_val = pixdata.apixels[spix]; + sprpix_val = spix_val; + dpix_val = p_acolors[lookup[spix_val]]; + spix++; + out_val = dpix_val; + if (spritepixels[dpix + spritepixels_pos].data) { + sprcol = render_sprites(dpix, 1, sprpix_val, 0); + if (sprcol) { + var spcol = p_acolors[sprcol]; + out_val = spcol; + } + } + buf[dpix + xlinebuffer_pos] = out_val; dpix++; + buf[dpix + xlinebuffer_pos] = out_val; dpix++; + } + } else if (bplehb) { + while (dpix < dpix_end) { + var sprpix_val = 0; + var spix_val = 0; + var dpix_val = 0; + var out_val = 0; + spix_val = pixdata.apixels[spix]; + sprpix_val = spix_val; + if (spix_val <= 31) + dpix_val = p_acolors[spix_val]; + else + dpix_val = p_xcolors[(colors_for_drawing.color_regs_ecs[spix_val - 32] >>> 1) & 0x777]; + spix++; + out_val = dpix_val; + if (spritepixels[dpix + spritepixels_pos].data) { + sprcol = render_sprites(dpix, 0, sprpix_val, 0); + if (sprcol) { + var spcol = p_acolors[sprcol]; + out_val = spcol; + } + } + buf[dpix + xlinebuffer_pos] = out_val; dpix++; + buf[dpix + xlinebuffer_pos] = out_val; dpix++; + } + } else { + while (dpix < dpix_end) { + var sprpix_val = 0; + var spix_val = 0; + var dpix_val = 0; + var out_val = 0; + spix_val = pixdata.apixels[spix]; + sprpix_val = spix_val; + dpix_val = p_acolors[spix_val]; + spix++; + out_val = dpix_val; + if (spritepixels[dpix + spritepixels_pos].data) { + sprcol = render_sprites(dpix, 0, sprpix_val, 0); + if (sprcol) { + var spcol = p_acolors[sprcol]; + out_val = spcol; + } + } + buf[dpix + xlinebuffer_pos] = out_val; dpix++; + buf[dpix + xlinebuffer_pos] = out_val; dpix++; + } + } + return spix; + } + + function linetoscr_32_stretch2_spr(spix, dpix, dpix_end) + { + var buf = xlinebuffer; + var sprcol = 0; + if (bplham) { + while (dpix < dpix_end) { + var sprpix_val = 0; + var spix_val = 0; + var dpix_val = 0; + var out_val = 0; + spix_val = ham_linebuf[spix]; + dpix_val = p_xcolors[spix_val]; + sprpix_val = pixdata.apixels[spix]; + spix++; + out_val = dpix_val; + if (spritepixels[dpix + spritepixels_pos].data) { + sprcol = render_sprites(dpix, 0, sprpix_val, 0); + if (sprcol) { + var spcol = p_acolors[sprcol]; + out_val = spcol; + } + } + buf[dpix + xlinebuffer_pos] = out_val; dpix++; + buf[dpix + xlinebuffer_pos] = out_val; dpix++; + buf[dpix + xlinebuffer_pos] = out_val; dpix++; + buf[dpix + xlinebuffer_pos] = out_val; dpix++; + } + } else if (bpldualpf) { + var lookup = bpldualpfpri ? dblpf_ind2 : dblpf_ind1; + while (dpix < dpix_end) { + var sprpix_val = 0; + var spix_val = 0; + var dpix_val = 0; + var out_val = 0; + spix_val = pixdata.apixels[spix]; + sprpix_val = spix_val; + dpix_val = p_acolors[lookup[spix_val]]; + spix++; + out_val = dpix_val; + if (spritepixels[dpix + spritepixels_pos].data) { + sprcol = render_sprites(dpix, 1, sprpix_val, 0); + if (sprcol) { + var spcol = p_acolors[sprcol]; + out_val = spcol; + } + } + buf[dpix + xlinebuffer_pos] = out_val; dpix++; + buf[dpix + xlinebuffer_pos] = out_val; dpix++; + buf[dpix + xlinebuffer_pos] = out_val; dpix++; + buf[dpix + xlinebuffer_pos] = out_val; dpix++; + } + } else if (bplehb) { + while (dpix < dpix_end) { + var sprpix_val = 0; + var spix_val = 0; + var dpix_val = 0; + var out_val = 0; + spix_val = pixdata.apixels[spix]; + sprpix_val = spix_val; + if (spix_val <= 31) + dpix_val = p_acolors[spix_val]; + else + dpix_val = p_xcolors[(colors_for_drawing.color_regs_ecs[spix_val - 32] >>> 1) & 0x777]; + spix++; + out_val = dpix_val; + if (spritepixels[dpix + spritepixels_pos].data) { + sprcol = render_sprites(dpix, 0, sprpix_val, 0); + if (sprcol) { + var spcol = p_acolors[sprcol]; + out_val = spcol; + } + } + buf[dpix + xlinebuffer_pos] = out_val; dpix++; + buf[dpix + xlinebuffer_pos] = out_val; dpix++; + buf[dpix + xlinebuffer_pos] = out_val; dpix++; + buf[dpix + xlinebuffer_pos] = out_val; dpix++; + } + } else { + while (dpix < dpix_end) { + var sprpix_val = 0; + var spix_val = 0; + var dpix_val = 0; + var out_val = 0; + spix_val = pixdata.apixels[spix]; + sprpix_val = spix_val; + dpix_val = p_acolors[spix_val]; + spix++; + out_val = dpix_val; + if (spritepixels[dpix + spritepixels_pos].data) { + sprcol = render_sprites(dpix, 0, sprpix_val, 0); + if (sprcol) { + var spcol = p_acolors[sprcol]; + out_val = spcol; + } + } + buf[dpix + xlinebuffer_pos] = out_val; dpix++; + buf[dpix + xlinebuffer_pos] = out_val; dpix++; + buf[dpix + xlinebuffer_pos] = out_val; dpix++; + buf[dpix + xlinebuffer_pos] = out_val; dpix++; + } + } + return spix; + } + + function linetoscr_32_shrink1_spr(spix, dpix, dpix_end) + { + var buf = xlinebuffer; + var sprcol = 0; + if (bplham) { + while (dpix < dpix_end) { + var sprpix_val = 0; + var spix_val = 0; + var dpix_val = 0; + var out_val = 0; + spix_val = ham_linebuf[spix]; + dpix_val = p_xcolors[spix_val]; + sprpix_val = pixdata.apixels[spix]; + spix += 2; + out_val = dpix_val; + if (spritepixels[dpix + spritepixels_pos].data) { + sprcol = render_sprites(dpix, 0, sprpix_val, 0); + if (sprcol) { + var spcol = p_acolors[sprcol]; + out_val = spcol; + } + } + buf[dpix + xlinebuffer_pos] = out_val; dpix++; + } + } else if (bpldualpf) { + var lookup = bpldualpfpri ? dblpf_ind2 : dblpf_ind1; + while (dpix < dpix_end) { + var sprpix_val = 0; + var spix_val = 0; + var dpix_val = 0; + var out_val = 0; + spix_val = pixdata.apixels[spix]; + sprpix_val = spix_val; + dpix_val = p_acolors[lookup[spix_val]]; + spix += 2; + out_val = dpix_val; + if (spritepixels[dpix + spritepixels_pos].data) { + sprcol = render_sprites(dpix, 1, sprpix_val, 0); + if (sprcol) { + var spcol = p_acolors[sprcol]; + out_val = spcol; + } + } + buf[dpix + xlinebuffer_pos] = out_val; dpix++; + } + } else if (bplehb) { + while (dpix < dpix_end) { + var sprpix_val = 0; + var spix_val = 0; + var dpix_val = 0; + var out_val = 0; + spix_val = pixdata.apixels[spix]; + sprpix_val = spix_val; + if (spix_val <= 31) + dpix_val = p_acolors[spix_val]; + else + dpix_val = p_xcolors[(colors_for_drawing.color_regs_ecs[spix_val - 32] >>> 1) & 0x777]; + spix += 2; + out_val = dpix_val; + if (spritepixels[dpix + spritepixels_pos].data) { + sprcol = render_sprites(dpix, 0, sprpix_val, 0); + if (sprcol) { + var spcol = p_acolors[sprcol]; + out_val = spcol; + } + } + buf[dpix + xlinebuffer_pos] = out_val; dpix++; + } + } else { + while (dpix < dpix_end) { + var sprpix_val = 0; + var spix_val = 0; + var dpix_val = 0; + var out_val = 0; + spix_val = pixdata.apixels[spix]; + sprpix_val = spix_val; + dpix_val = p_acolors[spix_val]; + spix += 2; + out_val = dpix_val; + if (spritepixels[dpix + spritepixels_pos].data) { + sprcol = render_sprites(dpix, 0, sprpix_val, 0); + if (sprcol) { + var spcol = p_acolors[sprcol]; + out_val = spcol; + } + } + buf[dpix + xlinebuffer_pos] = out_val; dpix++; + } + } + return spix; + } + + function linetoscr_32_shrink1f_spr(spix, dpix, dpix_end) + { + var buf = xlinebuffer; + var sprcol = 0; + if (bplham) { + while (dpix < dpix_end) { + var sprpix_val = 0; + var spix_val = 0; + var dpix_val = 0; + var out_val = 0; + spix_val = ham_linebuf[spix]; + dpix_val = p_xcolors[spix_val]; + sprpix_val = pixdata.apixels[spix]; + { + var tmp_val; + spix++; + tmp_val = dpix_val; + spix_val = ham_linebuf[spix]; + dpix_val = p_xcolors[spix_val]; + sprpix_val = pixdata.apixels[spix]; + dpix_val = merge_2pixel32(dpix_val, tmp_val); + spix++; + } + out_val = dpix_val; + if (spritepixels[dpix + spritepixels_pos].data) { + sprcol = render_sprites(dpix, 0, sprpix_val, 0); + if (sprcol) { + var spcol = p_acolors[sprcol]; + out_val = spcol; + } + } + buf[dpix + xlinebuffer_pos] = out_val; dpix++; + } + } else if (bpldualpf) { + var lookup = bpldualpfpri ? dblpf_ind2 : dblpf_ind1; + while (dpix < dpix_end) { + var sprpix_val = 0; + var spix_val = 0; + var dpix_val = 0; + var out_val = 0; + spix_val = pixdata.apixels[spix]; + sprpix_val = spix_val; + dpix_val = p_acolors[lookup[spix_val]]; + { + var tmp_val; + spix++; + tmp_val = dpix_val; + spix_val = pixdata.apixels[spix]; + sprpix_val = spix_val; + dpix_val = p_acolors[lookup[spix_val]]; + dpix_val = merge_2pixel32(dpix_val, tmp_val); + spix++; + } + out_val = dpix_val; + if (spritepixels[dpix + spritepixels_pos].data) { + sprcol = render_sprites(dpix, 1, sprpix_val, 0); + if (sprcol) { + var spcol = p_acolors[sprcol]; + out_val = spcol; + } + } + buf[dpix + xlinebuffer_pos] = out_val; dpix++; + } + } else if (bplehb) { + while (dpix < dpix_end) { + var sprpix_val = 0; + var spix_val = 0; + var dpix_val = 0; + var out_val = 0; + spix_val = pixdata.apixels[spix]; + sprpix_val = spix_val; + if (spix_val <= 31) + dpix_val = p_acolors[spix_val]; + else + dpix_val = p_xcolors[(colors_for_drawing.color_regs_ecs[spix_val - 32] >>> 1) & 0x777]; + { + var tmp_val; + spix++; + tmp_val = dpix_val; + spix_val = pixdata.apixels[spix]; + sprpix_val = spix_val; + if (spix_val <= 31) + dpix_val = p_acolors[spix_val]; + else + dpix_val = p_xcolors[(colors_for_drawing.color_regs_ecs[spix_val - 32] >>> 1) & 0x777]; + dpix_val = merge_2pixel32(dpix_val, tmp_val); + spix++; + } + out_val = dpix_val; + if (spritepixels[dpix + spritepixels_pos].data) { + sprcol = render_sprites(dpix, 0, sprpix_val, 0); + if (sprcol) { + var spcol = p_acolors[sprcol]; + out_val = spcol; + } + } + buf[dpix + xlinebuffer_pos] = out_val; dpix++; + } + } else { + while (dpix < dpix_end) { + var sprpix_val = 0; + var spix_val = 0; + var dpix_val = 0; + var out_val = 0; + spix_val = pixdata.apixels[spix]; + sprpix_val = spix_val; + dpix_val = p_acolors[spix_val]; + { + var tmp_val; + spix++; + tmp_val = dpix_val; + spix_val = pixdata.apixels[spix]; + sprpix_val = spix_val; + dpix_val = p_acolors[spix_val]; + dpix_val = merge_2pixel32(dpix_val, tmp_val); + spix++; + } + out_val = dpix_val; + if (spritepixels[dpix + spritepixels_pos].data) { + sprcol = render_sprites(dpix, 0, sprpix_val, 0); + if (sprcol) { + var spcol = p_acolors[sprcol]; + out_val = spcol; + } + } + buf[dpix + xlinebuffer_pos] = out_val; dpix++; + } + } + return spix; + } + + function linetoscr_32_shrink2_spr(spix, dpix, dpix_end) + { + var buf = xlinebuffer; + var sprcol = 0; + if (bplham) { + while (dpix < dpix_end) { + var sprpix_val = 0; + var spix_val = 0; + var dpix_val = 0; + var out_val = 0; + spix_val = ham_linebuf[spix]; + dpix_val = p_xcolors[spix_val]; + sprpix_val = pixdata.apixels[spix]; + spix += 4; + out_val = dpix_val; + if (spritepixels[dpix + spritepixels_pos].data) { + sprcol = render_sprites(dpix, 0, sprpix_val, 0); + if (sprcol) { + var spcol = p_acolors[sprcol]; + out_val = spcol; + } + } + buf[dpix + xlinebuffer_pos] = out_val; dpix++; + } + } else if (bpldualpf) { + var lookup = bpldualpfpri ? dblpf_ind2 : dblpf_ind1; + while (dpix < dpix_end) { + var sprpix_val = 0; + var spix_val = 0; + var dpix_val = 0; + var out_val = 0; + spix_val = pixdata.apixels[spix]; + sprpix_val = spix_val; + dpix_val = p_acolors[lookup[spix_val]]; + spix += 4; + out_val = dpix_val; + if (spritepixels[dpix + spritepixels_pos].data) { + sprcol = render_sprites(dpix, 1, sprpix_val, 0); + if (sprcol) { + var spcol = p_acolors[sprcol]; + out_val = spcol; + } + } + buf[dpix + xlinebuffer_pos] = out_val; dpix++; + } + } else if (bplehb) { + while (dpix < dpix_end) { + var sprpix_val = 0; + var spix_val = 0; + var dpix_val = 0; + var out_val = 0; + spix_val = pixdata.apixels[spix]; + sprpix_val = spix_val; + if (spix_val <= 31) + dpix_val = p_acolors[spix_val]; + else + dpix_val = p_xcolors[(colors_for_drawing.color_regs_ecs[spix_val - 32] >>> 1) & 0x777]; + spix += 4; + out_val = dpix_val; + if (spritepixels[dpix + spritepixels_pos].data) { + sprcol = render_sprites(dpix, 0, sprpix_val, 0); + if (sprcol) { + var spcol = p_acolors[sprcol]; + out_val = spcol; + } + } + buf[dpix + xlinebuffer_pos] = out_val; dpix++; + } + } else { + while (dpix < dpix_end) { + var sprpix_val = 0; + var spix_val = 0; + var dpix_val = 0; + var out_val = 0; + spix_val = pixdata.apixels[spix]; + sprpix_val = spix_val; + dpix_val = p_acolors[spix_val]; + spix += 4; + out_val = dpix_val; + if (spritepixels[dpix + spritepixels_pos].data) { + sprcol = render_sprites(dpix, 0, sprpix_val, 0); + if (sprcol) { + var spcol = p_acolors[sprcol]; + out_val = spcol; + } + } + buf[dpix + xlinebuffer_pos] = out_val; dpix++; + } + } + return spix; + } + + function linetoscr_32_shrink2f_spr(spix, dpix, dpix_end) + { + var buf = xlinebuffer; + var sprcol = 0; + if (bplham) { + while (dpix < dpix_end) { + var sprpix_val = 0; + var spix_val = 0; + var dpix_val = 0; + var out_val = 0; + spix_val = ham_linebuf[spix]; + dpix_val = p_xcolors[spix_val]; + sprpix_val = pixdata.apixels[spix]; + { + var tmp_val, tmp_val2, tmp_val3; + spix++; + tmp_val = dpix_val; + spix_val = ham_linebuf[spix]; + dpix_val = p_xcolors[spix_val]; + sprpix_val = pixdata.apixels[spix]; + spix++; + tmp_val2 = dpix_val; + spix_val = ham_linebuf[spix]; + dpix_val = p_xcolors[spix_val]; + sprpix_val = pixdata.apixels[spix]; + spix++; + tmp_val3 = dpix_val; + spix_val = ham_linebuf[spix]; + dpix_val = p_xcolors[spix_val]; + sprpix_val = pixdata.apixels[spix]; + tmp_val = merge_2pixel32(tmp_val, tmp_val2); + tmp_val2 = merge_2pixel32(tmp_val3, dpix_val); + dpix_val = merge_2pixel32(tmp_val, tmp_val2); + spix++; + } + out_val = dpix_val; + if (spritepixels[dpix + spritepixels_pos].data) { + sprcol = render_sprites(dpix, 0, sprpix_val, 0); + if (sprcol) { + var spcol = p_acolors[sprcol]; + out_val = spcol; + } + } + buf[dpix + xlinebuffer_pos] = out_val; dpix++; + } + } else if (bpldualpf) { + var lookup = bpldualpfpri ? dblpf_ind2 : dblpf_ind1; + while (dpix < dpix_end) { + var sprpix_val = 0; + var spix_val = 0; + var dpix_val = 0; + var out_val = 0; + spix_val = pixdata.apixels[spix]; + sprpix_val = spix_val; + dpix_val = p_acolors[lookup[spix_val]]; + { + var tmp_val, tmp_val2, tmp_val3; + spix++; + tmp_val = dpix_val; + spix_val = pixdata.apixels[spix]; + sprpix_val = spix_val; + dpix_val = p_acolors[lookup[spix_val]]; + spix++; + tmp_val2 = dpix_val; + spix_val = pixdata.apixels[spix]; + sprpix_val = spix_val; + dpix_val = p_acolors[lookup[spix_val]]; + spix++; + tmp_val3 = dpix_val; + spix_val = pixdata.apixels[spix]; + sprpix_val = spix_val; + dpix_val = p_acolors[lookup[spix_val]]; + tmp_val = merge_2pixel32(tmp_val, tmp_val2); + tmp_val2 = merge_2pixel32(tmp_val3, dpix_val); + dpix_val = merge_2pixel32(tmp_val, tmp_val2); + spix++; + } + out_val = dpix_val; + if (spritepixels[dpix + spritepixels_pos].data) { + sprcol = render_sprites(dpix, 1, sprpix_val, 0); + if (sprcol) { + var spcol = p_acolors[sprcol]; + out_val = spcol; + } + } + buf[dpix + xlinebuffer_pos] = out_val; dpix++; + } + } else if (bplehb) { + while (dpix < dpix_end) { + var sprpix_val = 0; + var spix_val = 0; + var dpix_val = 0; + var out_val = 0; + spix_val = pixdata.apixels[spix]; + sprpix_val = spix_val; + if (spix_val <= 31) + dpix_val = p_acolors[spix_val]; + else + dpix_val = p_xcolors[(colors_for_drawing.color_regs_ecs[spix_val - 32] >>> 1) & 0x777]; + { + var tmp_val, tmp_val2, tmp_val3; + spix++; + tmp_val = dpix_val; + spix_val = pixdata.apixels[spix]; + sprpix_val = spix_val; + if (spix_val <= 31) + dpix_val = p_acolors[spix_val]; + else + dpix_val = p_xcolors[(colors_for_drawing.color_regs_ecs[spix_val - 32] >>> 1) & 0x777]; + spix++; + tmp_val2 = dpix_val; + spix_val = pixdata.apixels[spix]; + sprpix_val = spix_val; + if (spix_val <= 31) + dpix_val = p_acolors[spix_val]; + else + dpix_val = p_xcolors[(colors_for_drawing.color_regs_ecs[spix_val - 32] >>> 1) & 0x777]; + spix++; + tmp_val3 = dpix_val; + spix_val = pixdata.apixels[spix]; + sprpix_val = spix_val; + if (spix_val <= 31) + dpix_val = p_acolors[spix_val]; + else + dpix_val = p_xcolors[(colors_for_drawing.color_regs_ecs[spix_val - 32] >>> 1) & 0x777]; + tmp_val = merge_2pixel32(tmp_val, tmp_val2); + tmp_val2 = merge_2pixel32(tmp_val3, dpix_val); + dpix_val = merge_2pixel32(tmp_val, tmp_val2); + spix++; + } + out_val = dpix_val; + if (spritepixels[dpix + spritepixels_pos].data) { + sprcol = render_sprites(dpix, 0, sprpix_val, 0); + if (sprcol) { + var spcol = p_acolors[sprcol]; + out_val = spcol; + } + } + buf[dpix + xlinebuffer_pos] = out_val; dpix++; + } + } else { + while (dpix < dpix_end) { + var sprpix_val = 0; + var spix_val = 0; + var dpix_val = 0; + var out_val = 0; + spix_val = pixdata.apixels[spix]; + sprpix_val = spix_val; + dpix_val = p_acolors[spix_val]; + { + var tmp_val, tmp_val2, tmp_val3; + spix++; + tmp_val = dpix_val; + spix_val = pixdata.apixels[spix]; + sprpix_val = spix_val; + dpix_val = p_acolors[spix_val]; + spix++; + tmp_val2 = dpix_val; + spix_val = pixdata.apixels[spix]; + sprpix_val = spix_val; + dpix_val = p_acolors[spix_val]; + spix++; + tmp_val3 = dpix_val; + spix_val = pixdata.apixels[spix]; + sprpix_val = spix_val; + dpix_val = p_acolors[spix_val]; + tmp_val = merge_2pixel32(tmp_val, tmp_val2); + tmp_val2 = merge_2pixel32(tmp_val3, dpix_val); + dpix_val = merge_2pixel32(tmp_val, tmp_val2); + spix++; + } + out_val = dpix_val; + if (spritepixels[dpix + spritepixels_pos].data) { + sprcol = render_sprites(dpix, 0, sprpix_val, 0); + if (sprcol) { + var spcol = p_acolors[sprcol]; + out_val = spcol; + } + } + buf[dpix + xlinebuffer_pos] = out_val; dpix++; + } + } + return spix; + } + + function linetoscr_32_aga_spronly(spix, dpix, dpix_end) + { + var buf = xlinebuffer; + var sprcol = 0; + if (1) { + while (dpix < dpix_end) { + var sprpix_val = 0; + var out_val = 0; + spix++; + out_val = p_acolors[0]; + if (spritepixels[dpix + spritepixels_pos].data) { + sprcol = render_sprites(dpix + 0, 0, sprpix_val, 1); + if (sprcol) { + out_val = p_acolors[sprcol]; + } + } + buf[dpix + xlinebuffer_pos] = out_val; dpix++; + } + } + return spix; + } + + function linetoscr_32_stretch1_aga_spronly(spix, dpix, dpix_end) + { + var buf = xlinebuffer; + var sprcol = 0; + if (1) { + while (dpix < dpix_end) { + var sprpix_val = 0; + var out_val = 0; + spix++; + out_val = p_acolors[0]; + { + var out_val1 = out_val; + var out_val2 = out_val; + if (spritepixels[dpix + spritepixels_pos].data) { + sprcol = render_sprites(dpix, 0, sprpix_val, 1); + if (sprcol) { + out_val1 = p_acolors[sprcol]; + } + } + if (spritepixels[dpix + spritepixels_pos + 1].data) { + sprcol = render_sprites(dpix + 1, 0, sprpix_val, 1); + if (sprcol) { + out_val2 = p_acolors[sprcol]; + } + } + buf[dpix + xlinebuffer_pos] = out_val1; dpix++; + buf[dpix + xlinebuffer_pos] = out_val2; dpix++; + } + } + } + return spix; + } + + function linetoscr_32_stretch2_aga_spronly(spix, dpix, dpix_end) + { + var buf = xlinebuffer; + var sprcol = 0; + if (1) { + while (dpix < dpix_end) { + var sprpix_val = 0; + var out_val = 0; + spix++; + out_val = p_acolors[0]; + { + var out_val1 = out_val; + var out_val2 = out_val; + var out_val3 = out_val; + var out_val4 = out_val; + if (spritepixels[dpix + spritepixels_pos].data) { + var sprcol = render_sprites(dpix, 0, sprpix_val, 1); + if (sprcol) { + out_val1 = p_acolors[sprcol]; + } + } + if (spritepixels[dpix + spritepixels_pos + 1].data) { + sprcol = render_sprites(dpix + 1, 0, sprpix_val, 1); + if (sprcol) { + out_val2 = p_acolors[sprcol]; + } + } + if (spritepixels[dpix + spritepixels_pos + 2].data) { + sprcol = render_sprites(dpix + 2, 0, sprpix_val, 1); + if (sprcol) { + out_val3 = p_acolors[sprcol]; + } + } + if (spritepixels[dpix + spritepixels_pos + 3].data) { + sprcol = render_sprites(dpix + 3, 0, sprpix_val, 1); + if (sprcol) { + out_val4 = p_acolors[sprcol]; + } + } + buf[dpix + xlinebuffer_pos] = out_val1; dpix++; + buf[dpix + xlinebuffer_pos] = out_val2; dpix++; + buf[dpix + xlinebuffer_pos] = out_val3; dpix++; + buf[dpix + xlinebuffer_pos] = out_val4; dpix++; + } + } + } + return spix; + } + + function linetoscr_32_shrink1_aga_spronly(spix, dpix, dpix_end) + { + var buf = xlinebuffer; + var sprcol = 0; + if (1) { + while (dpix < dpix_end) { + var sprpix_val = 0; + var out_val = 0; + spix++; + out_val = p_acolors[0]; + if (spritepixels[dpix + spritepixels_pos].data) { + sprcol = render_sprites(dpix + 0, 0, sprpix_val, 1); + if (sprcol) { + out_val = p_acolors[sprcol]; + } + } + buf[dpix + xlinebuffer_pos] = out_val; dpix++; + } + } + return spix; + } + + function linetoscr_32_shrink1f_aga_spronly(spix, dpix, dpix_end) + { + var buf = xlinebuffer; + var sprcol = 0; + if (1) { + while (dpix < dpix_end) { + var sprpix_val = 0; + var out_val = 0; + spix++; + out_val = p_acolors[0]; + if (spritepixels[dpix + spritepixels_pos].data) { + sprcol = render_sprites(dpix + 0, 0, sprpix_val, 1); + if (sprcol) { + out_val = p_acolors[sprcol]; + } + } + buf[dpix + xlinebuffer_pos] = out_val; dpix++; + } + } + return spix; + } + + function linetoscr_32_shrink2_aga_spronly(spix, dpix, dpix_end) + { + var buf = xlinebuffer; + var sprcol = 0; + if (1) { + while (dpix < dpix_end) { + var sprpix_val = 0; + var out_val = 0; + spix++; + out_val = p_acolors[0]; + if (spritepixels[dpix + spritepixels_pos].data) { + sprcol = render_sprites(dpix + 0, 0, sprpix_val, 1); + if (sprcol) { + out_val = p_acolors[sprcol]; + } + } + buf[dpix + xlinebuffer_pos] = out_val; dpix++; + } + } + return spix; + } + + function linetoscr_32_shrink2f_aga_spronly(spix, dpix, dpix_end) + { + var buf = xlinebuffer; + var sprcol = 0; + if (1) { + while (dpix < dpix_end) { + var sprpix_val = 0; + var out_val = 0; + spix++; + out_val = p_acolors[0]; + if (spritepixels[dpix + spritepixels_pos].data) { + sprcol = render_sprites(dpix + 0, 0, sprpix_val, 1); + if (sprcol) { + out_val = p_acolors[sprcol]; + } + } + buf[dpix + xlinebuffer_pos] = out_val; dpix++; + } + } + return spix; + } + + function linetoscr_32_aga(spix, dpix, dpix_end) + { + var buf = xlinebuffer; + var xor_val = bplxor; + var and_val = bpland; + if (bplham) { + while (dpix < dpix_end) { + var spix_val = 0; + var dpix_val = 0; + var out_val = 0; + spix_val = (pixdata.apixels[spix] ^ xor_val) & and_val; + spix_val = ham_linebuf[spix]; + dpix_val = CONVERT_RGB(spix_val); + spix++; + out_val = dpix_val; + buf[dpix + xlinebuffer_pos] = out_val; dpix++; + } + } else if (bpldualpf) { + var lookup = bpldualpfpri ? dblpf_ind2_aga : dblpf_ind1_aga; + var lookup_no = bpldualpfpri ? dblpf_2nd2 : dblpf_2nd1; + while (dpix < dpix_end) { + var spix_val = 0; + var dpix_val = 0; + var out_val = 0; + spix_val = pixdata.apixels[spix]; + { + var val = lookup[spix_val]; + if (lookup_no[spix_val]) + val += dblpfofs[bpldualpf2of]; + val ^= xor_val; + dpix_val = p_acolors[val]; + } + spix++; + out_val = dpix_val; + buf[dpix + xlinebuffer_pos] = out_val; dpix++; + } + } else if (bplehb) { + while (dpix < dpix_end) { + var spix_val = 0; + var dpix_val = 0; + var out_val = 0; + spix_val = (pixdata.apixels[spix] ^ xor_val) & and_val; + if (spix_val >= 32 && spix_val < 64) { + var c = (colors_for_drawing.color_regs_aga[spix_val - 32] >>> 1) & 0x7F7F7F; + dpix_val = CONVERT_RGB(c); + } else + dpix_val = p_acolors[spix_val]; + spix++; + out_val = dpix_val; + buf[dpix + xlinebuffer_pos] = out_val; dpix++; + } + } else { + while (dpix < dpix_end) { + var spix_val = 0; + var dpix_val = 0; + var out_val = 0; + spix_val = (pixdata.apixels[spix] ^ xor_val) & and_val; + dpix_val = p_acolors[spix_val]; + spix++; + out_val = dpix_val; + buf[dpix + xlinebuffer_pos] = out_val; dpix++; + } + } + return spix; + } + + function linetoscr_32_stretch1_aga(spix, dpix, dpix_end) + { + var buf = xlinebuffer; + var xor_val = bplxor; + var and_val = bpland; + if (bplham) { + while (dpix < dpix_end) { + var spix_val = 0; + var dpix_val = 0; + var out_val = 0; + spix_val = (pixdata.apixels[spix] ^ xor_val) & and_val; + spix_val = ham_linebuf[spix]; + dpix_val = CONVERT_RGB(spix_val); + spix++; + out_val = dpix_val; + buf[dpix + xlinebuffer_pos] = out_val; dpix++; + buf[dpix + xlinebuffer_pos] = out_val; dpix++; + } + } else if (bpldualpf) { + var lookup = bpldualpfpri ? dblpf_ind2_aga : dblpf_ind1_aga; + var lookup_no = bpldualpfpri ? dblpf_2nd2 : dblpf_2nd1; + while (dpix < dpix_end) { + var spix_val = 0; + var dpix_val = 0; + var out_val = 0; + spix_val = pixdata.apixels[spix]; + { + var val = lookup[spix_val]; + if (lookup_no[spix_val]) + val += dblpfofs[bpldualpf2of]; + val ^= xor_val; + dpix_val = p_acolors[val]; + } + spix++; + out_val = dpix_val; + buf[dpix + xlinebuffer_pos] = out_val; dpix++; + buf[dpix + xlinebuffer_pos] = out_val; dpix++; + } + } else if (bplehb) { + while (dpix < dpix_end) { + var spix_val = 0; + var dpix_val = 0; + var out_val = 0; + spix_val = (pixdata.apixels[spix] ^ xor_val) & and_val; + if (spix_val >= 32 && spix_val < 64) { + var c = (colors_for_drawing.color_regs_aga[spix_val - 32] >>> 1) & 0x7F7F7F; + dpix_val = CONVERT_RGB(c); + } else + dpix_val = p_acolors[spix_val]; + spix++; + out_val = dpix_val; + buf[dpix + xlinebuffer_pos] = out_val; dpix++; + buf[dpix + xlinebuffer_pos] = out_val; dpix++; + } + } else { + while (dpix < dpix_end) { + var spix_val = 0; + var dpix_val = 0; + var out_val = 0; + spix_val = (pixdata.apixels[spix] ^ xor_val) & and_val; + dpix_val = p_acolors[spix_val]; + spix++; + out_val = dpix_val; + buf[dpix + xlinebuffer_pos] = out_val; dpix++; + buf[dpix + xlinebuffer_pos] = out_val; dpix++; + } + } + return spix; + } + + function linetoscr_32_stretch2_aga(spix, dpix, dpix_end) + { + var buf = xlinebuffer; + var xor_val = bplxor; + var and_val = bpland; + if (bplham) { + while (dpix < dpix_end) { + var spix_val = 0; + var dpix_val = 0; + var out_val = 0; + spix_val = (pixdata.apixels[spix] ^ xor_val) & and_val; + spix_val = ham_linebuf[spix]; + dpix_val = CONVERT_RGB(spix_val); + spix++; + out_val = dpix_val; + buf[dpix + xlinebuffer_pos] = out_val; dpix++; + buf[dpix + xlinebuffer_pos] = out_val; dpix++; + buf[dpix + xlinebuffer_pos] = out_val; dpix++; + buf[dpix + xlinebuffer_pos] = out_val; dpix++; + } + } else if (bpldualpf) { + var lookup = bpldualpfpri ? dblpf_ind2_aga : dblpf_ind1_aga; + var lookup_no = bpldualpfpri ? dblpf_2nd2 : dblpf_2nd1; + while (dpix < dpix_end) { + var spix_val = 0; + var dpix_val = 0; + var out_val = 0; + spix_val = pixdata.apixels[spix]; + { + var val = lookup[spix_val]; + if (lookup_no[spix_val]) + val += dblpfofs[bpldualpf2of]; + val ^= xor_val; + dpix_val = p_acolors[val]; + } + spix++; + out_val = dpix_val; + buf[dpix + xlinebuffer_pos] = out_val; dpix++; + buf[dpix + xlinebuffer_pos] = out_val; dpix++; + buf[dpix + xlinebuffer_pos] = out_val; dpix++; + buf[dpix + xlinebuffer_pos] = out_val; dpix++; + } + } else if (bplehb) { + while (dpix < dpix_end) { + var spix_val = 0; + var dpix_val = 0; + var out_val = 0; + spix_val = (pixdata.apixels[spix] ^ xor_val) & and_val; + if (spix_val >= 32 && spix_val < 64) { + var c = (colors_for_drawing.color_regs_aga[spix_val - 32] >>> 1) & 0x7F7F7F; + dpix_val = CONVERT_RGB(c); + } else + dpix_val = p_acolors[spix_val]; + spix++; + out_val = dpix_val; + buf[dpix + xlinebuffer_pos] = out_val; dpix++; + buf[dpix + xlinebuffer_pos] = out_val; dpix++; + buf[dpix + xlinebuffer_pos] = out_val; dpix++; + buf[dpix + xlinebuffer_pos] = out_val; dpix++; + } + } else { + while (dpix < dpix_end) { + var spix_val = 0; + var dpix_val = 0; + var out_val = 0; + spix_val = (pixdata.apixels[spix] ^ xor_val) & and_val; + dpix_val = p_acolors[spix_val]; + spix++; + out_val = dpix_val; + buf[dpix + xlinebuffer_pos] = out_val; dpix++; + buf[dpix + xlinebuffer_pos] = out_val; dpix++; + buf[dpix + xlinebuffer_pos] = out_val; dpix++; + buf[dpix + xlinebuffer_pos] = out_val; dpix++; + } + } + return spix; + } + + function linetoscr_32_shrink1_aga(spix, dpix, dpix_end) + { + var buf = xlinebuffer; + var xor_val = bplxor; + var and_val = bpland; + if (bplham) { + while (dpix < dpix_end) { + var spix_val = 0; + var dpix_val = 0; + var out_val = 0; + spix_val = (pixdata.apixels[spix] ^ xor_val) & and_val; + spix_val = ham_linebuf[spix]; + dpix_val = CONVERT_RGB(spix_val); + spix += 2; + out_val = dpix_val; + buf[dpix + xlinebuffer_pos] = out_val; dpix++; + } + } else if (bpldualpf) { + var lookup = bpldualpfpri ? dblpf_ind2_aga : dblpf_ind1_aga; + var lookup_no = bpldualpfpri ? dblpf_2nd2 : dblpf_2nd1; + while (dpix < dpix_end) { + var spix_val = 0; + var dpix_val = 0; + var out_val = 0; + spix_val = pixdata.apixels[spix]; + { + var val = lookup[spix_val]; + if (lookup_no[spix_val]) + val += dblpfofs[bpldualpf2of]; + val ^= xor_val; + dpix_val = p_acolors[val]; + } + spix += 2; + out_val = dpix_val; + buf[dpix + xlinebuffer_pos] = out_val; dpix++; + } + } else if (bplehb) { + while (dpix < dpix_end) { + var spix_val = 0; + var dpix_val = 0; + var out_val = 0; + spix_val = (pixdata.apixels[spix] ^ xor_val) & and_val; + if (spix_val >= 32 && spix_val < 64) { + var c = (colors_for_drawing.color_regs_aga[spix_val - 32] >>> 1) & 0x7F7F7F; + dpix_val = CONVERT_RGB(c); + } else + dpix_val = p_acolors[spix_val]; + spix += 2; + out_val = dpix_val; + buf[dpix + xlinebuffer_pos] = out_val; dpix++; + } + } else { + while (dpix < dpix_end) { + var spix_val = 0; + var dpix_val = 0; + var out_val = 0; + spix_val = (pixdata.apixels[spix] ^ xor_val) & and_val; + dpix_val = p_acolors[spix_val]; + spix += 2; + out_val = dpix_val; + buf[dpix + xlinebuffer_pos] = out_val; dpix++; + } + } + return spix; + } + + function linetoscr_32_shrink1f_aga(spix, dpix, dpix_end) + { + var buf = xlinebuffer; + var xor_val = bplxor; + var and_val = bpland; + if (bplham) { + while (dpix < dpix_end) { + var spix_val = 0; + var dpix_val = 0; + var out_val = 0; + spix_val = (pixdata.apixels[spix] ^ xor_val) & and_val; + spix_val = ham_linebuf[spix]; + dpix_val = CONVERT_RGB(spix_val); + { + var tmp_val; + spix++; + tmp_val = dpix_val; + spix_val = (pixdata.apixels[spix] ^ xor_val) & and_val; + spix_val = ham_linebuf[spix]; + dpix_val = CONVERT_RGB(spix_val); + dpix_val = merge_2pixel32(dpix_val, tmp_val); + spix++; + } + out_val = dpix_val; + buf[dpix + xlinebuffer_pos] = out_val; dpix++; + } + } else if (bpldualpf) { + var lookup = bpldualpfpri ? dblpf_ind2_aga : dblpf_ind1_aga; + var lookup_no = bpldualpfpri ? dblpf_2nd2 : dblpf_2nd1; + while (dpix < dpix_end) { + var spix_val = 0; + var dpix_val = 0; + var out_val = 0; + spix_val = pixdata.apixels[spix]; + { + var val = lookup[spix_val]; + if (lookup_no[spix_val]) + val += dblpfofs[bpldualpf2of]; + val ^= xor_val; + dpix_val = p_acolors[val]; + } + { + var tmp_val; + spix++; + tmp_val = dpix_val; + spix_val = pixdata.apixels[spix]; + { + var val = lookup[spix_val]; + if (lookup_no[spix_val]) + val += dblpfofs[bpldualpf2of]; + val ^= xor_val; + dpix_val = p_acolors[val]; + } + dpix_val = merge_2pixel32(dpix_val, tmp_val); + spix++; + } + out_val = dpix_val; + buf[dpix + xlinebuffer_pos] = out_val; dpix++; + } + } else if (bplehb) { + while (dpix < dpix_end) { + var spix_val = 0; + var dpix_val = 0; + var out_val = 0; + spix_val = (pixdata.apixels[spix] ^ xor_val) & and_val; + if (spix_val >= 32 && spix_val < 64) { + var c = (colors_for_drawing.color_regs_aga[spix_val - 32] >>> 1) & 0x7F7F7F; + dpix_val = CONVERT_RGB(c); + } else + dpix_val = p_acolors[spix_val]; + { + var tmp_val; + spix++; + tmp_val = dpix_val; + spix_val = (pixdata.apixels[spix] ^ xor_val) & and_val; + if (spix_val >= 32 && spix_val < 64) { + var c = (colors_for_drawing.color_regs_aga[spix_val - 32] >>> 1) & 0x7F7F7F; + dpix_val = CONVERT_RGB(c); + } else + dpix_val = p_acolors[spix_val]; + dpix_val = merge_2pixel32(dpix_val, tmp_val); + spix++; + } + out_val = dpix_val; + buf[dpix + xlinebuffer_pos] = out_val; dpix++; + } + } else { + while (dpix < dpix_end) { + var spix_val = 0; + var dpix_val = 0; + var out_val = 0; + spix_val = (pixdata.apixels[spix] ^ xor_val) & and_val; + dpix_val = p_acolors[spix_val]; + { + var tmp_val; + spix++; + tmp_val = dpix_val; + spix_val = (pixdata.apixels[spix] ^ xor_val) & and_val; + dpix_val = p_acolors[spix_val]; + dpix_val = merge_2pixel32(dpix_val, tmp_val); + spix++; + } + out_val = dpix_val; + buf[dpix + xlinebuffer_pos] = out_val; dpix++; + } + } + return spix; + } + + function linetoscr_32_shrink2_aga(spix, dpix, dpix_end) + { + var buf = xlinebuffer; + var xor_val = bplxor; + var and_val = bpland; + if (bplham) { + while (dpix < dpix_end) { + var spix_val = 0; + var dpix_val = 0; + var out_val = 0; + spix_val = (pixdata.apixels[spix] ^ xor_val) & and_val; + spix_val = ham_linebuf[spix]; + dpix_val = CONVERT_RGB(spix_val); + spix += 4; + out_val = dpix_val; + buf[dpix + xlinebuffer_pos] = out_val; dpix++; + } + } else if (bpldualpf) { + var lookup = bpldualpfpri ? dblpf_ind2_aga : dblpf_ind1_aga; + var lookup_no = bpldualpfpri ? dblpf_2nd2 : dblpf_2nd1; + while (dpix < dpix_end) { + var spix_val = 0; + var dpix_val = 0; + var out_val = 0; + spix_val = pixdata.apixels[spix]; + { + var val = lookup[spix_val]; + if (lookup_no[spix_val]) + val += dblpfofs[bpldualpf2of]; + val ^= xor_val; + dpix_val = p_acolors[val]; + } + spix += 4; + out_val = dpix_val; + buf[dpix + xlinebuffer_pos] = out_val; dpix++; + } + } else if (bplehb) { + while (dpix < dpix_end) { + var spix_val = 0; + var dpix_val = 0; + var out_val = 0; + spix_val = (pixdata.apixels[spix] ^ xor_val) & and_val; + if (spix_val >= 32 && spix_val < 64) { + var c = (colors_for_drawing.color_regs_aga[spix_val - 32] >>> 1) & 0x7F7F7F; + dpix_val = CONVERT_RGB(c); + } else + dpix_val = p_acolors[spix_val]; + spix += 4; + out_val = dpix_val; + buf[dpix + xlinebuffer_pos] = out_val; dpix++; + } + } else { + while (dpix < dpix_end) { + var spix_val = 0; + var dpix_val = 0; + var out_val = 0; + spix_val = (pixdata.apixels[spix] ^ xor_val) & and_val; + dpix_val = p_acolors[spix_val]; + spix += 4; + out_val = dpix_val; + buf[dpix + xlinebuffer_pos] = out_val; dpix++; + } + } + return spix; + } + + function linetoscr_32_shrink2f_aga(spix, dpix, dpix_end) + { + var buf = xlinebuffer; + var xor_val = bplxor; + var and_val = bpland; + if (bplham) { + while (dpix < dpix_end) { + var spix_val = 0; + var dpix_val = 0; + var out_val = 0; + spix_val = (pixdata.apixels[spix] ^ xor_val) & and_val; + spix_val = ham_linebuf[spix]; + dpix_val = CONVERT_RGB(spix_val); + { + var tmp_val, tmp_val2, tmp_val3; + spix++; + tmp_val = dpix_val; + spix_val = (pixdata.apixels[spix] ^ xor_val) & and_val; + spix_val = ham_linebuf[spix]; + dpix_val = CONVERT_RGB(spix_val); + spix++; + tmp_val2 = dpix_val; + spix_val = (pixdata.apixels[spix] ^ xor_val) & and_val; + spix_val = ham_linebuf[spix]; + dpix_val = CONVERT_RGB(spix_val); + spix++; + tmp_val3 = dpix_val; + spix_val = (pixdata.apixels[spix] ^ xor_val) & and_val; + spix_val = ham_linebuf[spix]; + dpix_val = CONVERT_RGB(spix_val); + tmp_val = merge_2pixel32(tmp_val, tmp_val2); + tmp_val2 = merge_2pixel32(tmp_val3, dpix_val); + dpix_val = merge_2pixel32(tmp_val, tmp_val2); + spix++; + } + out_val = dpix_val; + buf[dpix + xlinebuffer_pos] = out_val; dpix++; + } + } else if (bpldualpf) { + var lookup = bpldualpfpri ? dblpf_ind2_aga : dblpf_ind1_aga; + var lookup_no = bpldualpfpri ? dblpf_2nd2 : dblpf_2nd1; + while (dpix < dpix_end) { + var spix_val = 0; + var dpix_val = 0; + var out_val = 0; + spix_val = pixdata.apixels[spix]; + { + var val = lookup[spix_val]; + if (lookup_no[spix_val]) + val += dblpfofs[bpldualpf2of]; + val ^= xor_val; + dpix_val = p_acolors[val]; + } + { + var tmp_val, tmp_val2, tmp_val3; + spix++; + tmp_val = dpix_val; + spix_val = pixdata.apixels[spix]; + { + var val = lookup[spix_val]; + if (lookup_no[spix_val]) + val += dblpfofs[bpldualpf2of]; + val ^= xor_val; + dpix_val = p_acolors[val]; + } + spix++; + tmp_val2 = dpix_val; + spix_val = pixdata.apixels[spix]; + { + var val = lookup[spix_val]; + if (lookup_no[spix_val]) + val += dblpfofs[bpldualpf2of]; + val ^= xor_val; + dpix_val = p_acolors[val]; + } + spix++; + tmp_val3 = dpix_val; + spix_val = pixdata.apixels[spix]; + { + var val = lookup[spix_val]; + if (lookup_no[spix_val]) + val += dblpfofs[bpldualpf2of]; + val ^= xor_val; + dpix_val = p_acolors[val]; + } + tmp_val = merge_2pixel32(tmp_val, tmp_val2); + tmp_val2 = merge_2pixel32(tmp_val3, dpix_val); + dpix_val = merge_2pixel32(tmp_val, tmp_val2); + spix++; + } + out_val = dpix_val; + buf[dpix + xlinebuffer_pos] = out_val; dpix++; + } + } else if (bplehb) { + while (dpix < dpix_end) { + var spix_val = 0; + var dpix_val = 0; + var out_val = 0; + spix_val = (pixdata.apixels[spix] ^ xor_val) & and_val; + if (spix_val >= 32 && spix_val < 64) { + var c = (colors_for_drawing.color_regs_aga[spix_val - 32] >>> 1) & 0x7F7F7F; + dpix_val = CONVERT_RGB(c); + } else + dpix_val = p_acolors[spix_val]; + { + var tmp_val, tmp_val2, tmp_val3; + spix++; + tmp_val = dpix_val; + spix_val = (pixdata.apixels[spix] ^ xor_val) & and_val; + if (spix_val >= 32 && spix_val < 64) { + var c = (colors_for_drawing.color_regs_aga[spix_val - 32] >>> 1) & 0x7F7F7F; + dpix_val = CONVERT_RGB(c); + } else + dpix_val = p_acolors[spix_val]; + spix++; + tmp_val2 = dpix_val; + spix_val = (pixdata.apixels[spix] ^ xor_val) & and_val; + if (spix_val >= 32 && spix_val < 64) { + var c = (colors_for_drawing.color_regs_aga[spix_val - 32] >>> 1) & 0x7F7F7F; + dpix_val = CONVERT_RGB(c); + } else + dpix_val = p_acolors[spix_val]; + spix++; + tmp_val3 = dpix_val; + spix_val = (pixdata.apixels[spix] ^ xor_val) & and_val; + if (spix_val >= 32 && spix_val < 64) { + var c = (colors_for_drawing.color_regs_aga[spix_val - 32] >>> 1) & 0x7F7F7F; + dpix_val = CONVERT_RGB(c); + } else + dpix_val = p_acolors[spix_val]; + tmp_val = merge_2pixel32(tmp_val, tmp_val2); + tmp_val2 = merge_2pixel32(tmp_val3, dpix_val); + dpix_val = merge_2pixel32(tmp_val, tmp_val2); + spix++; + } + out_val = dpix_val; + buf[dpix + xlinebuffer_pos] = out_val; dpix++; + } + } else { + while (dpix < dpix_end) { + var spix_val = 0; + var dpix_val = 0; + var out_val = 0; + spix_val = (pixdata.apixels[spix] ^ xor_val) & and_val; + dpix_val = p_acolors[spix_val]; + { + var tmp_val, tmp_val2, tmp_val3; + spix++; + tmp_val = dpix_val; + spix_val = (pixdata.apixels[spix] ^ xor_val) & and_val; + dpix_val = p_acolors[spix_val]; + spix++; + tmp_val2 = dpix_val; + spix_val = (pixdata.apixels[spix] ^ xor_val) & and_val; + dpix_val = p_acolors[spix_val]; + spix++; + tmp_val3 = dpix_val; + spix_val = (pixdata.apixels[spix] ^ xor_val) & and_val; + dpix_val = p_acolors[spix_val]; + tmp_val = merge_2pixel32(tmp_val, tmp_val2); + tmp_val2 = merge_2pixel32(tmp_val3, dpix_val); + dpix_val = merge_2pixel32(tmp_val, tmp_val2); + spix++; + } + out_val = dpix_val; + buf[dpix + xlinebuffer_pos] = out_val; dpix++; + } + } + return spix; + } + + function linetoscr_32_aga_spr(spix, dpix, dpix_end) + { + var buf = xlinebuffer; + var sprcol = 0; + var xor_val = bplxor; + var and_val = bpland; + if (bplham) { + while (dpix < dpix_end) { + var sprpix_val = 0; + var spix_val = 0; + var dpix_val = 0; + var out_val = 0; + sprpix_val = pixdata.apixels[spix]; + spix_val = (pixdata.apixels[spix] ^ xor_val) & and_val; + spix_val = ham_linebuf[spix]; + dpix_val = CONVERT_RGB(spix_val); + spix++; + out_val = dpix_val; + if (spritepixels[dpix + spritepixels_pos].data) { + sprcol = render_sprites(dpix + 0, 0, sprpix_val, 1); + if (sprcol) { + out_val = p_acolors[sprcol]; + } + } + buf[dpix + xlinebuffer_pos] = out_val; dpix++; + } + } else if (bpldualpf) { + var lookup = bpldualpfpri ? dblpf_ind2_aga : dblpf_ind1_aga; + var lookup_no = bpldualpfpri ? dblpf_2nd2 : dblpf_2nd1; + while (dpix < dpix_end) { + var sprpix_val = 0; + var spix_val = 0; + var dpix_val = 0; + var out_val = 0; + spix_val = pixdata.apixels[spix]; + sprpix_val = spix_val; + { + var val = lookup[spix_val]; + if (lookup_no[spix_val]) + val += dblpfofs[bpldualpf2of]; + val ^= xor_val; + dpix_val = p_acolors[val]; + } + spix++; + out_val = dpix_val; + if (spritepixels[dpix + spritepixels_pos].data) { + sprcol = render_sprites(dpix + 0, 1, sprpix_val, 1); + if (sprcol) { + out_val = p_acolors[sprcol]; + } + } + buf[dpix + xlinebuffer_pos] = out_val; dpix++; + } + } else if (bplehb) { + while (dpix < dpix_end) { + var sprpix_val = 0; + var spix_val = 0; + var dpix_val = 0; + var out_val = 0; + sprpix_val = pixdata.apixels[spix]; + spix_val = (pixdata.apixels[spix] ^ xor_val) & and_val; + if (spix_val >= 32 && spix_val < 64) { + var c = (colors_for_drawing.color_regs_aga[spix_val - 32] >>> 1) & 0x7F7F7F; + dpix_val = CONVERT_RGB(c); + } else + dpix_val = p_acolors[spix_val]; + spix++; + out_val = dpix_val; + if (spritepixels[dpix + spritepixels_pos].data) { + sprcol = render_sprites(dpix + 0, 0, sprpix_val, 1); + if (sprcol) { + out_val = p_acolors[sprcol]; + } + } + buf[dpix + xlinebuffer_pos] = out_val; dpix++; + } + } else { + while (dpix < dpix_end) { + var sprpix_val = 0; + var spix_val = 0; + var dpix_val = 0; + var out_val = 0; + sprpix_val = pixdata.apixels[spix]; + spix_val = (pixdata.apixels[spix] ^ xor_val) & and_val; + dpix_val = p_acolors[spix_val]; + spix++; + out_val = dpix_val; + if (spritepixels[dpix + spritepixels_pos].data) { + sprcol = render_sprites(dpix + 0, 0, sprpix_val, 1); + if (sprcol) { + out_val = p_acolors[sprcol]; + } + } + buf[dpix + xlinebuffer_pos] = out_val; dpix++; + } + } + return spix; + } + + function linetoscr_32_stretch1_aga_spr(spix, dpix, dpix_end) + { + var buf = xlinebuffer; + var sprcol = 0; + var xor_val = bplxor; + var and_val = bpland; + if (bplham) { + while (dpix < dpix_end) { + var sprpix_val = 0; + var spix_val = 0; + var dpix_val = 0; + var out_val = 0; + sprpix_val = pixdata.apixels[spix]; + spix_val = (pixdata.apixels[spix] ^ xor_val) & and_val; + spix_val = ham_linebuf[spix]; + dpix_val = CONVERT_RGB(spix_val); + spix++; + out_val = dpix_val; + { + var out_val1 = out_val; + var out_val2 = out_val; + if (spritepixels[dpix + spritepixels_pos].data) { + sprcol = render_sprites(dpix, 0, sprpix_val, 1); + if (sprcol) { + out_val1 = p_acolors[sprcol]; + } + } + if (spritepixels[dpix + spritepixels_pos + 1].data) { + sprcol = render_sprites(dpix + 1, 0, sprpix_val, 1); + if (sprcol) { + out_val2 = p_acolors[sprcol]; + } + } + buf[dpix + xlinebuffer_pos] = out_val1; dpix++; + buf[dpix + xlinebuffer_pos] = out_val2; dpix++; + } + } + } else if (bpldualpf) { + var lookup = bpldualpfpri ? dblpf_ind2_aga : dblpf_ind1_aga; + var lookup_no = bpldualpfpri ? dblpf_2nd2 : dblpf_2nd1; + while (dpix < dpix_end) { + var sprpix_val = 0; + var spix_val = 0; + var dpix_val = 0; + var out_val = 0; + spix_val = pixdata.apixels[spix]; + sprpix_val = spix_val; + { + var val = lookup[spix_val]; + if (lookup_no[spix_val]) + val += dblpfofs[bpldualpf2of]; + val ^= xor_val; + dpix_val = p_acolors[val]; + } + spix++; + out_val = dpix_val; + { + var out_val1 = out_val; + var out_val2 = out_val; + if (spritepixels[dpix + spritepixels_pos].data) { + sprcol = render_sprites(dpix, 1, sprpix_val, 1); + if (sprcol) { + out_val1 = p_acolors[sprcol]; + } + } + if (spritepixels[dpix + spritepixels_pos + 1].data) { + sprcol = render_sprites(dpix + 1, 1, sprpix_val, 1); + if (sprcol) { + out_val2 = p_acolors[sprcol]; + } + } + buf[dpix + xlinebuffer_pos] = out_val1; dpix++; + buf[dpix + xlinebuffer_pos] = out_val2; dpix++; + } + } + } else if (bplehb) { + while (dpix < dpix_end) { + var sprpix_val = 0; + var spix_val = 0; + var dpix_val = 0; + var out_val = 0; + sprpix_val = pixdata.apixels[spix]; + spix_val = (pixdata.apixels[spix] ^ xor_val) & and_val; + if (spix_val >= 32 && spix_val < 64) { + var c = (colors_for_drawing.color_regs_aga[spix_val - 32] >>> 1) & 0x7F7F7F; + dpix_val = CONVERT_RGB(c); + } else + dpix_val = p_acolors[spix_val]; + spix++; + out_val = dpix_val; + { + var out_val1 = out_val; + var out_val2 = out_val; + if (spritepixels[dpix + spritepixels_pos].data) { + sprcol = render_sprites(dpix, 0, sprpix_val, 1); + if (sprcol) { + out_val1 = p_acolors[sprcol]; + } + } + if (spritepixels[dpix + spritepixels_pos + 1].data) { + sprcol = render_sprites(dpix + 1, 0, sprpix_val, 1); + if (sprcol) { + out_val2 = p_acolors[sprcol]; + } + } + buf[dpix + xlinebuffer_pos] = out_val1; dpix++; + buf[dpix + xlinebuffer_pos] = out_val2; dpix++; + } + } + } else { + while (dpix < dpix_end) { + var sprpix_val = 0; + var spix_val = 0; + var dpix_val = 0; + var out_val = 0; + sprpix_val = pixdata.apixels[spix]; + spix_val = (pixdata.apixels[spix] ^ xor_val) & and_val; + dpix_val = p_acolors[spix_val]; + spix++; + out_val = dpix_val; + { + var out_val1 = out_val; + var out_val2 = out_val; + if (spritepixels[dpix + spritepixels_pos].data) { + sprcol = render_sprites(dpix, 0, sprpix_val, 1); + if (sprcol) { + out_val1 = p_acolors[sprcol]; + } + } + if (spritepixels[dpix + spritepixels_pos + 1].data) { + sprcol = render_sprites(dpix + 1, 0, sprpix_val, 1); + if (sprcol) { + out_val2 = p_acolors[sprcol]; + } + } + buf[dpix + xlinebuffer_pos] = out_val1; dpix++; + buf[dpix + xlinebuffer_pos] = out_val2; dpix++; + } + } + } + return spix; + } + + function linetoscr_32_stretch2_aga_spr(spix, dpix, dpix_end) + { + var buf = xlinebuffer; + var sprcol = 0; + var xor_val = bplxor; + var and_val = bpland; + if (bplham) { + while (dpix < dpix_end) { + var sprpix_val = 0; + var spix_val = 0; + var dpix_val = 0; + var out_val = 0; + sprpix_val = pixdata.apixels[spix]; + spix_val = (pixdata.apixels[spix] ^ xor_val) & and_val; + spix_val = ham_linebuf[spix]; + dpix_val = CONVERT_RGB(spix_val); + spix++; + out_val = dpix_val; + { + var out_val1 = out_val; + var out_val2 = out_val; + var out_val3 = out_val; + var out_val4 = out_val; + if (spritepixels[dpix + spritepixels_pos].data) { + var sprcol = render_sprites(dpix, 0, sprpix_val, 1); + if (sprcol) { + out_val1 = p_acolors[sprcol]; + } + } + if (spritepixels[dpix + spritepixels_pos + 1].data) { + sprcol = render_sprites(dpix + 1, 0, sprpix_val, 1); + if (sprcol) { + out_val2 = p_acolors[sprcol]; + } + } + if (spritepixels[dpix + spritepixels_pos + 2].data) { + sprcol = render_sprites(dpix + 2, 0, sprpix_val, 1); + if (sprcol) { + out_val3 = p_acolors[sprcol]; + } + } + if (spritepixels[dpix + spritepixels_pos + 3].data) { + sprcol = render_sprites(dpix + 3, 0, sprpix_val, 1); + if (sprcol) { + out_val4 = p_acolors[sprcol]; + } + } + buf[dpix + xlinebuffer_pos] = out_val1; dpix++; + buf[dpix + xlinebuffer_pos] = out_val2; dpix++; + buf[dpix + xlinebuffer_pos] = out_val3; dpix++; + buf[dpix + xlinebuffer_pos] = out_val4; dpix++; + } + } + } else if (bpldualpf) { + var lookup = bpldualpfpri ? dblpf_ind2_aga : dblpf_ind1_aga; + var lookup_no = bpldualpfpri ? dblpf_2nd2 : dblpf_2nd1; + while (dpix < dpix_end) { + var sprpix_val = 0; + var spix_val = 0; + var dpix_val = 0; + var out_val = 0; + spix_val = pixdata.apixels[spix]; + sprpix_val = spix_val; + { + var val = lookup[spix_val]; + if (lookup_no[spix_val]) + val += dblpfofs[bpldualpf2of]; + val ^= xor_val; + dpix_val = p_acolors[val]; + } + spix++; + out_val = dpix_val; + { + var out_val1 = out_val; + var out_val2 = out_val; + var out_val3 = out_val; + var out_val4 = out_val; + if (spritepixels[dpix + spritepixels_pos].data) { + var sprcol = render_sprites(dpix, 1, sprpix_val, 1); + if (sprcol) { + out_val1 = p_acolors[sprcol]; + } + } + if (spritepixels[dpix + spritepixels_pos + 1].data) { + sprcol = render_sprites(dpix + 1, 1, sprpix_val, 1); + if (sprcol) { + out_val2 = p_acolors[sprcol]; + } + } + if (spritepixels[dpix + spritepixels_pos + 2].data) { + sprcol = render_sprites(dpix + 2, 1, sprpix_val, 1); + if (sprcol) { + out_val3 = p_acolors[sprcol]; + } + } + if (spritepixels[dpix + spritepixels_pos + 3].data) { + sprcol = render_sprites(dpix + 3, 1, sprpix_val, 1); + if (sprcol) { + out_val4 = p_acolors[sprcol]; + } + } + buf[dpix + xlinebuffer_pos] = out_val1; dpix++; + buf[dpix + xlinebuffer_pos] = out_val2; dpix++; + buf[dpix + xlinebuffer_pos] = out_val3; dpix++; + buf[dpix + xlinebuffer_pos] = out_val4; dpix++; + } + } + } else if (bplehb) { + while (dpix < dpix_end) { + var sprpix_val = 0; + var spix_val = 0; + var dpix_val = 0; + var out_val = 0; + sprpix_val = pixdata.apixels[spix]; + spix_val = (pixdata.apixels[spix] ^ xor_val) & and_val; + if (spix_val >= 32 && spix_val < 64) { + var c = (colors_for_drawing.color_regs_aga[spix_val - 32] >>> 1) & 0x7F7F7F; + dpix_val = CONVERT_RGB(c); + } else + dpix_val = p_acolors[spix_val]; + spix++; + out_val = dpix_val; + { + var out_val1 = out_val; + var out_val2 = out_val; + var out_val3 = out_val; + var out_val4 = out_val; + if (spritepixels[dpix + spritepixels_pos].data) { + var sprcol = render_sprites(dpix, 0, sprpix_val, 1); + if (sprcol) { + out_val1 = p_acolors[sprcol]; + } + } + if (spritepixels[dpix + spritepixels_pos + 1].data) { + sprcol = render_sprites(dpix + 1, 0, sprpix_val, 1); + if (sprcol) { + out_val2 = p_acolors[sprcol]; + } + } + if (spritepixels[dpix + spritepixels_pos + 2].data) { + sprcol = render_sprites(dpix + 2, 0, sprpix_val, 1); + if (sprcol) { + out_val3 = p_acolors[sprcol]; + } + } + if (spritepixels[dpix + spritepixels_pos + 3].data) { + sprcol = render_sprites(dpix + 3, 0, sprpix_val, 1); + if (sprcol) { + out_val4 = p_acolors[sprcol]; + } + } + buf[dpix + xlinebuffer_pos] = out_val1; dpix++; + buf[dpix + xlinebuffer_pos] = out_val2; dpix++; + buf[dpix + xlinebuffer_pos] = out_val3; dpix++; + buf[dpix + xlinebuffer_pos] = out_val4; dpix++; + } + } + } else { + while (dpix < dpix_end) { + var sprpix_val = 0; + var spix_val = 0; + var dpix_val = 0; + var out_val = 0; + sprpix_val = pixdata.apixels[spix]; + spix_val = (pixdata.apixels[spix] ^ xor_val) & and_val; + dpix_val = p_acolors[spix_val]; + spix++; + out_val = dpix_val; + { + var out_val1 = out_val; + var out_val2 = out_val; + var out_val3 = out_val; + var out_val4 = out_val; + if (spritepixels[dpix + spritepixels_pos].data) { + var sprcol = render_sprites(dpix, 0, sprpix_val, 1); + if (sprcol) { + out_val1 = p_acolors[sprcol]; + } + } + if (spritepixels[dpix + spritepixels_pos + 1].data) { + sprcol = render_sprites(dpix + 1, 0, sprpix_val, 1); + if (sprcol) { + out_val2 = p_acolors[sprcol]; + } + } + if (spritepixels[dpix + spritepixels_pos + 2].data) { + sprcol = render_sprites(dpix + 2, 0, sprpix_val, 1); + if (sprcol) { + out_val3 = p_acolors[sprcol]; + } + } + if (spritepixels[dpix + spritepixels_pos + 3].data) { + sprcol = render_sprites(dpix + 3, 0, sprpix_val, 1); + if (sprcol) { + out_val4 = p_acolors[sprcol]; + } + } + buf[dpix + xlinebuffer_pos] = out_val1; dpix++; + buf[dpix + xlinebuffer_pos] = out_val2; dpix++; + buf[dpix + xlinebuffer_pos] = out_val3; dpix++; + buf[dpix + xlinebuffer_pos] = out_val4; dpix++; + } + } + } + return spix; + } + + function linetoscr_32_shrink1_aga_spr(spix, dpix, dpix_end) + { + var buf = xlinebuffer; + var sprcol = 0; + var xor_val = bplxor; + var and_val = bpland; + if (bplham) { + while (dpix < dpix_end) { + var sprpix_val = 0; + var spix_val = 0; + var dpix_val = 0; + var out_val = 0; + sprpix_val = pixdata.apixels[spix]; + spix_val = (pixdata.apixels[spix] ^ xor_val) & and_val; + spix_val = ham_linebuf[spix]; + dpix_val = CONVERT_RGB(spix_val); + spix += 2; + out_val = dpix_val; + if (spritepixels[dpix + spritepixels_pos].data) { + sprcol = render_sprites(dpix + 0, 0, sprpix_val, 1); + if (sprcol) { + out_val = p_acolors[sprcol]; + } + } + buf[dpix + xlinebuffer_pos] = out_val; dpix++; + } + } else if (bpldualpf) { + var lookup = bpldualpfpri ? dblpf_ind2_aga : dblpf_ind1_aga; + var lookup_no = bpldualpfpri ? dblpf_2nd2 : dblpf_2nd1; + while (dpix < dpix_end) { + var sprpix_val = 0; + var spix_val = 0; + var dpix_val = 0; + var out_val = 0; + spix_val = pixdata.apixels[spix]; + sprpix_val = spix_val; + { + var val = lookup[spix_val]; + if (lookup_no[spix_val]) + val += dblpfofs[bpldualpf2of]; + val ^= xor_val; + dpix_val = p_acolors[val]; + } + spix += 2; + out_val = dpix_val; + if (spritepixels[dpix + spritepixels_pos].data) { + sprcol = render_sprites(dpix + 0, 1, sprpix_val, 1); + if (sprcol) { + out_val = p_acolors[sprcol]; + } + } + buf[dpix + xlinebuffer_pos] = out_val; dpix++; + } + } else if (bplehb) { + while (dpix < dpix_end) { + var sprpix_val = 0; + var spix_val = 0; + var dpix_val = 0; + var out_val = 0; + sprpix_val = pixdata.apixels[spix]; + spix_val = (pixdata.apixels[spix] ^ xor_val) & and_val; + if (spix_val >= 32 && spix_val < 64) { + var c = (colors_for_drawing.color_regs_aga[spix_val - 32] >>> 1) & 0x7F7F7F; + dpix_val = CONVERT_RGB(c); + } else + dpix_val = p_acolors[spix_val]; + spix += 2; + out_val = dpix_val; + if (spritepixels[dpix + spritepixels_pos].data) { + sprcol = render_sprites(dpix + 0, 0, sprpix_val, 1); + if (sprcol) { + out_val = p_acolors[sprcol]; + } + } + buf[dpix + xlinebuffer_pos] = out_val; dpix++; + } + } else { + while (dpix < dpix_end) { + var sprpix_val = 0; + var spix_val = 0; + var dpix_val = 0; + var out_val = 0; + sprpix_val = pixdata.apixels[spix]; + spix_val = (pixdata.apixels[spix] ^ xor_val) & and_val; + dpix_val = p_acolors[spix_val]; + spix += 2; + out_val = dpix_val; + if (spritepixels[dpix + spritepixels_pos].data) { + sprcol = render_sprites(dpix + 0, 0, sprpix_val, 1); + if (sprcol) { + out_val = p_acolors[sprcol]; + } + } + buf[dpix + xlinebuffer_pos] = out_val; dpix++; + } + } + return spix; + } + + function linetoscr_32_shrink1f_aga_spr(spix, dpix, dpix_end) + { + var buf = xlinebuffer; + var sprcol = 0; + var xor_val = bplxor; + var and_val = bpland; + if (bplham) { + while (dpix < dpix_end) { + var sprpix_val = 0; + var spix_val = 0; + var dpix_val = 0; + var out_val = 0; + sprpix_val = pixdata.apixels[spix]; + spix_val = (pixdata.apixels[spix] ^ xor_val) & and_val; + spix_val = ham_linebuf[spix]; + dpix_val = CONVERT_RGB(spix_val); + { + var tmp_val; + spix++; + tmp_val = dpix_val; + sprpix_val = pixdata.apixels[spix]; + spix_val = (pixdata.apixels[spix] ^ xor_val) & and_val; + spix_val = ham_linebuf[spix]; + dpix_val = CONVERT_RGB(spix_val); + dpix_val = merge_2pixel32(dpix_val, tmp_val); + spix++; + } + out_val = dpix_val; + if (spritepixels[dpix + spritepixels_pos].data) { + sprcol = render_sprites(dpix + 0, 0, sprpix_val, 1); + if (sprcol) { + out_val = p_acolors[sprcol]; + } + } + buf[dpix + xlinebuffer_pos] = out_val; dpix++; + } + } else if (bpldualpf) { + var lookup = bpldualpfpri ? dblpf_ind2_aga : dblpf_ind1_aga; + var lookup_no = bpldualpfpri ? dblpf_2nd2 : dblpf_2nd1; + while (dpix < dpix_end) { + var sprpix_val = 0; + var spix_val = 0; + var dpix_val = 0; + var out_val = 0; + spix_val = pixdata.apixels[spix]; + sprpix_val = spix_val; + { + var val = lookup[spix_val]; + if (lookup_no[spix_val]) + val += dblpfofs[bpldualpf2of]; + val ^= xor_val; + dpix_val = p_acolors[val]; + } + { + var tmp_val; + spix++; + tmp_val = dpix_val; + spix_val = pixdata.apixels[spix]; + sprpix_val = spix_val; + { + var val = lookup[spix_val]; + if (lookup_no[spix_val]) + val += dblpfofs[bpldualpf2of]; + val ^= xor_val; + dpix_val = p_acolors[val]; + } + dpix_val = merge_2pixel32(dpix_val, tmp_val); + spix++; + } + out_val = dpix_val; + if (spritepixels[dpix + spritepixels_pos].data) { + sprcol = render_sprites(dpix + 0, 1, sprpix_val, 1); + if (sprcol) { + out_val = p_acolors[sprcol]; + } + } + buf[dpix + xlinebuffer_pos] = out_val; dpix++; + } + } else if (bplehb) { + while (dpix < dpix_end) { + var sprpix_val = 0; + var spix_val = 0; + var dpix_val = 0; + var out_val = 0; + sprpix_val = pixdata.apixels[spix]; + spix_val = (pixdata.apixels[spix] ^ xor_val) & and_val; + if (spix_val >= 32 && spix_val < 64) { + var c = (colors_for_drawing.color_regs_aga[spix_val - 32] >>> 1) & 0x7F7F7F; + dpix_val = CONVERT_RGB(c); + } else + dpix_val = p_acolors[spix_val]; + { + var tmp_val; + spix++; + tmp_val = dpix_val; + sprpix_val = pixdata.apixels[spix]; + spix_val = (pixdata.apixels[spix] ^ xor_val) & and_val; + if (spix_val >= 32 && spix_val < 64) { + var c = (colors_for_drawing.color_regs_aga[spix_val - 32] >>> 1) & 0x7F7F7F; + dpix_val = CONVERT_RGB(c); + } else + dpix_val = p_acolors[spix_val]; + dpix_val = merge_2pixel32(dpix_val, tmp_val); + spix++; + } + out_val = dpix_val; + if (spritepixels[dpix + spritepixels_pos].data) { + sprcol = render_sprites(dpix + 0, 0, sprpix_val, 1); + if (sprcol) { + out_val = p_acolors[sprcol]; + } + } + buf[dpix + xlinebuffer_pos] = out_val; dpix++; + } + } else { + while (dpix < dpix_end) { + var sprpix_val = 0; + var spix_val = 0; + var dpix_val = 0; + var out_val = 0; + sprpix_val = pixdata.apixels[spix]; + spix_val = (pixdata.apixels[spix] ^ xor_val) & and_val; + dpix_val = p_acolors[spix_val]; + { + var tmp_val; + spix++; + tmp_val = dpix_val; + sprpix_val = pixdata.apixels[spix]; + spix_val = (pixdata.apixels[spix] ^ xor_val) & and_val; + dpix_val = p_acolors[spix_val]; + dpix_val = merge_2pixel32(dpix_val, tmp_val); + spix++; + } + out_val = dpix_val; + if (spritepixels[dpix + spritepixels_pos].data) { + sprcol = render_sprites(dpix + 0, 0, sprpix_val, 1); + if (sprcol) { + out_val = p_acolors[sprcol]; + } + } + buf[dpix + xlinebuffer_pos] = out_val; dpix++; + } + } + return spix; + } + + function linetoscr_32_shrink2_aga_spr(spix, dpix, dpix_end) + { + var buf = xlinebuffer; + var sprcol = 0; + var xor_val = bplxor; + var and_val = bpland; + if (bplham) { + while (dpix < dpix_end) { + var sprpix_val = 0; + var spix_val = 0; + var dpix_val = 0; + var out_val = 0; + sprpix_val = pixdata.apixels[spix]; + spix_val = (pixdata.apixels[spix] ^ xor_val) & and_val; + spix_val = ham_linebuf[spix]; + dpix_val = CONVERT_RGB(spix_val); + spix += 4; + out_val = dpix_val; + if (spritepixels[dpix + spritepixels_pos].data) { + sprcol = render_sprites(dpix + 0, 0, sprpix_val, 1); + if (sprcol) { + out_val = p_acolors[sprcol]; + } + } + buf[dpix + xlinebuffer_pos] = out_val; dpix++; + } + } else if (bpldualpf) { + var lookup = bpldualpfpri ? dblpf_ind2_aga : dblpf_ind1_aga; + var lookup_no = bpldualpfpri ? dblpf_2nd2 : dblpf_2nd1; + while (dpix < dpix_end) { + var sprpix_val = 0; + var spix_val = 0; + var dpix_val = 0; + var out_val = 0; + spix_val = pixdata.apixels[spix]; + sprpix_val = spix_val; + { + var val = lookup[spix_val]; + if (lookup_no[spix_val]) + val += dblpfofs[bpldualpf2of]; + val ^= xor_val; + dpix_val = p_acolors[val]; + } + spix += 4; + out_val = dpix_val; + if (spritepixels[dpix + spritepixels_pos].data) { + sprcol = render_sprites(dpix + 0, 1, sprpix_val, 1); + if (sprcol) { + out_val = p_acolors[sprcol]; + } + } + buf[dpix + xlinebuffer_pos] = out_val; dpix++; + } + } else if (bplehb) { + while (dpix < dpix_end) { + var sprpix_val = 0; + var spix_val = 0; + var dpix_val = 0; + var out_val = 0; + sprpix_val = pixdata.apixels[spix]; + spix_val = (pixdata.apixels[spix] ^ xor_val) & and_val; + if (spix_val >= 32 && spix_val < 64) { + var c = (colors_for_drawing.color_regs_aga[spix_val - 32] >>> 1) & 0x7F7F7F; + dpix_val = CONVERT_RGB(c); + } else + dpix_val = p_acolors[spix_val]; + spix += 4; + out_val = dpix_val; + if (spritepixels[dpix + spritepixels_pos].data) { + sprcol = render_sprites(dpix + 0, 0, sprpix_val, 1); + if (sprcol) { + out_val = p_acolors[sprcol]; + } + } + buf[dpix + xlinebuffer_pos] = out_val; dpix++; + } + } else { + while (dpix < dpix_end) { + var sprpix_val = 0; + var spix_val = 0; + var dpix_val = 0; + var out_val = 0; + sprpix_val = pixdata.apixels[spix]; + spix_val = (pixdata.apixels[spix] ^ xor_val) & and_val; + dpix_val = p_acolors[spix_val]; + spix += 4; + out_val = dpix_val; + if (spritepixels[dpix + spritepixels_pos].data) { + sprcol = render_sprites(dpix + 0, 0, sprpix_val, 1); + if (sprcol) { + out_val = p_acolors[sprcol]; + } + } + buf[dpix + xlinebuffer_pos] = out_val; dpix++; + } + } + return spix; + } + + function linetoscr_32_shrink2f_aga_spr(spix, dpix, dpix_end) + { + var buf = xlinebuffer; + var sprcol = 0; + var xor_val = bplxor; + var and_val = bpland; + if (bplham) { + while (dpix < dpix_end) { + var sprpix_val = 0; + var spix_val = 0; + var dpix_val = 0; + var out_val = 0; + sprpix_val = pixdata.apixels[spix]; + spix_val = (pixdata.apixels[spix] ^ xor_val) & and_val; + spix_val = ham_linebuf[spix]; + dpix_val = CONVERT_RGB(spix_val); + { + var tmp_val, tmp_val2, tmp_val3; + spix++; + tmp_val = dpix_val; + sprpix_val = pixdata.apixels[spix]; + spix_val = (pixdata.apixels[spix] ^ xor_val) & and_val; + spix_val = ham_linebuf[spix]; + dpix_val = CONVERT_RGB(spix_val); + spix++; + tmp_val2 = dpix_val; + sprpix_val = pixdata.apixels[spix]; + spix_val = (pixdata.apixels[spix] ^ xor_val) & and_val; + spix_val = ham_linebuf[spix]; + dpix_val = CONVERT_RGB(spix_val); + spix++; + tmp_val3 = dpix_val; + sprpix_val = pixdata.apixels[spix]; + spix_val = (pixdata.apixels[spix] ^ xor_val) & and_val; + spix_val = ham_linebuf[spix]; + dpix_val = CONVERT_RGB(spix_val); + tmp_val = merge_2pixel32(tmp_val, tmp_val2); + tmp_val2 = merge_2pixel32(tmp_val3, dpix_val); + dpix_val = merge_2pixel32(tmp_val, tmp_val2); + spix++; + } + out_val = dpix_val; + if (spritepixels[dpix + spritepixels_pos].data) { + sprcol = render_sprites(dpix + 0, 0, sprpix_val, 1); + if (sprcol) { + out_val = p_acolors[sprcol]; + } + } + buf[dpix + xlinebuffer_pos] = out_val; dpix++; + } + } else if (bpldualpf) { + var lookup = bpldualpfpri ? dblpf_ind2_aga : dblpf_ind1_aga; + var lookup_no = bpldualpfpri ? dblpf_2nd2 : dblpf_2nd1; + while (dpix < dpix_end) { + var sprpix_val = 0; + var spix_val = 0; + var dpix_val = 0; + var out_val = 0; + spix_val = pixdata.apixels[spix]; + sprpix_val = spix_val; + { + var val = lookup[spix_val]; + if (lookup_no[spix_val]) + val += dblpfofs[bpldualpf2of]; + val ^= xor_val; + dpix_val = p_acolors[val]; + } + { + var tmp_val, tmp_val2, tmp_val3; + spix++; + tmp_val = dpix_val; + spix_val = pixdata.apixels[spix]; + sprpix_val = spix_val; + { + var val = lookup[spix_val]; + if (lookup_no[spix_val]) + val += dblpfofs[bpldualpf2of]; + val ^= xor_val; + dpix_val = p_acolors[val]; + } + spix++; + tmp_val2 = dpix_val; + spix_val = pixdata.apixels[spix]; + sprpix_val = spix_val; + { + var val = lookup[spix_val]; + if (lookup_no[spix_val]) + val += dblpfofs[bpldualpf2of]; + val ^= xor_val; + dpix_val = p_acolors[val]; + } + spix++; + tmp_val3 = dpix_val; + spix_val = pixdata.apixels[spix]; + sprpix_val = spix_val; + { + var val = lookup[spix_val]; + if (lookup_no[spix_val]) + val += dblpfofs[bpldualpf2of]; + val ^= xor_val; + dpix_val = p_acolors[val]; + } + tmp_val = merge_2pixel32(tmp_val, tmp_val2); + tmp_val2 = merge_2pixel32(tmp_val3, dpix_val); + dpix_val = merge_2pixel32(tmp_val, tmp_val2); + spix++; + } + out_val = dpix_val; + if (spritepixels[dpix + spritepixels_pos].data) { + sprcol = render_sprites(dpix + 0, 1, sprpix_val, 1); + if (sprcol) { + out_val = p_acolors[sprcol]; + } + } + buf[dpix + xlinebuffer_pos] = out_val; dpix++; + } + } else if (bplehb) { + while (dpix < dpix_end) { + var sprpix_val = 0; + var spix_val = 0; + var dpix_val = 0; + var out_val = 0; + sprpix_val = pixdata.apixels[spix]; + spix_val = (pixdata.apixels[spix] ^ xor_val) & and_val; + if (spix_val >= 32 && spix_val < 64) { + var c = (colors_for_drawing.color_regs_aga[spix_val - 32] >>> 1) & 0x7F7F7F; + dpix_val = CONVERT_RGB(c); + } else + dpix_val = p_acolors[spix_val]; + { + var tmp_val, tmp_val2, tmp_val3; + spix++; + tmp_val = dpix_val; + sprpix_val = pixdata.apixels[spix]; + spix_val = (pixdata.apixels[spix] ^ xor_val) & and_val; + if (spix_val >= 32 && spix_val < 64) { + var c = (colors_for_drawing.color_regs_aga[spix_val - 32] >>> 1) & 0x7F7F7F; + dpix_val = CONVERT_RGB(c); + } else + dpix_val = p_acolors[spix_val]; + spix++; + tmp_val2 = dpix_val; + sprpix_val = pixdata.apixels[spix]; + spix_val = (pixdata.apixels[spix] ^ xor_val) & and_val; + if (spix_val >= 32 && spix_val < 64) { + var c = (colors_for_drawing.color_regs_aga[spix_val - 32] >>> 1) & 0x7F7F7F; + dpix_val = CONVERT_RGB(c); + } else + dpix_val = p_acolors[spix_val]; + spix++; + tmp_val3 = dpix_val; + sprpix_val = pixdata.apixels[spix]; + spix_val = (pixdata.apixels[spix] ^ xor_val) & and_val; + if (spix_val >= 32 && spix_val < 64) { + var c = (colors_for_drawing.color_regs_aga[spix_val - 32] >>> 1) & 0x7F7F7F; + dpix_val = CONVERT_RGB(c); + } else + dpix_val = p_acolors[spix_val]; + tmp_val = merge_2pixel32(tmp_val, tmp_val2); + tmp_val2 = merge_2pixel32(tmp_val3, dpix_val); + dpix_val = merge_2pixel32(tmp_val, tmp_val2); + spix++; + } + out_val = dpix_val; + if (spritepixels[dpix + spritepixels_pos].data) { + sprcol = render_sprites(dpix + 0, 0, sprpix_val, 1); + if (sprcol) { + out_val = p_acolors[sprcol]; + } + } + buf[dpix + xlinebuffer_pos] = out_val; dpix++; + } + } else { + while (dpix < dpix_end) { + var sprpix_val = 0; + var spix_val = 0; + var dpix_val = 0; + var out_val = 0; + sprpix_val = pixdata.apixels[spix]; + spix_val = (pixdata.apixels[spix] ^ xor_val) & and_val; + dpix_val = p_acolors[spix_val]; + { + var tmp_val, tmp_val2, tmp_val3; + spix++; + tmp_val = dpix_val; + sprpix_val = pixdata.apixels[spix]; + spix_val = (pixdata.apixels[spix] ^ xor_val) & and_val; + dpix_val = p_acolors[spix_val]; + spix++; + tmp_val2 = dpix_val; + sprpix_val = pixdata.apixels[spix]; + spix_val = (pixdata.apixels[spix] ^ xor_val) & and_val; + dpix_val = p_acolors[spix_val]; + spix++; + tmp_val3 = dpix_val; + sprpix_val = pixdata.apixels[spix]; + spix_val = (pixdata.apixels[spix] ^ xor_val) & and_val; + dpix_val = p_acolors[spix_val]; + tmp_val = merge_2pixel32(tmp_val, tmp_val2); + tmp_val2 = merge_2pixel32(tmp_val3, dpix_val); + dpix_val = merge_2pixel32(tmp_val, tmp_val2); + spix++; + } + out_val = dpix_val; + if (spritepixels[dpix + spritepixels_pos].data) { + sprcol = render_sprites(dpix + 0, 0, sprpix_val, 1); + if (sprcol) { + out_val = p_acolors[sprcol]; + } + } + buf[dpix + xlinebuffer_pos] = out_val; dpix++; + } + } + return spix; + } + +} diff --git a/sae/prototypes.js b/sae/prototypes.js new file mode 100644 index 0000000..a335739 --- /dev/null +++ b/sae/prototypes.js @@ -0,0 +1,78 @@ +/*------------------------------------------------------------------------- +| SAE - Scripted Amiga Emulator +| https://github.com/naTmeg/ScriptedAmigaEmulator +| +| Copyright (C) 2012-2016 Rupert Hausberger +| +| This program is free software; you can redistribute it and/or +| modify it under the terms of the GNU General Public License +| as published by the Free Software Foundation; either version 2 +| of the License, or (at your option) any later version. +| +| This program is distributed in the hope that it will be useful, +| but WITHOUT ANY WARRANTY; without even the implied warranty of +| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +| GNU General Public License for more details. +-------------------------------------------------------------------------*/ +/* Object */ + +if (!Object.prototype.clone) { + Object.prototype.clone = function() { + var copy = {}; //this.constructor(); + for (var attr in this) { + if (this.hasOwnProperty(attr)) + copy[attr] = this[attr]; + } + return copy; + }; +} + +/*-----------------------------------------------------------------------*/ +/* Math */ + +if (!Math.truncate) { + Math.truncate = function(v) { + if (v > 0) + return this.floor(v); + else if (v < 0) + return this.ceil(v); + + return 0; + }; +} + +if (!Math.decimalRandom) { + Math.decimalRandom = function() { + //var l = 0, u = 0xffffffff; return this.floor((this.random() * (u - l + 1)) + l); + return (this.random() * 0xffffffff) >>> 0; + }; +} + +/*-----------------------------------------------------------------------*/ +/* Date/Performance */ + +if (!Date.now) { + console.warn("This browser does not support 'Date.now()'. Falling back to 'Date.getTime()'..."); + /* milliseconds since 1 January 1970 00:00:00 UTC */ + Date.now = function() { + return new Date().getTime(); + }; +} + +if (!window.performance) { + console.warn("This browser does not support 'window.performance'. Falling back to 'Date'..."); + window.performance = {}; +} +if (!performance.timing) { + performance.timing = { + navigationStart: Date.now() + }; +} +if (!performance.now) { + if (performance.webkitNow) + performance.now = performance.webkitNow; + else + performance.now = function() { + return Date.now() - this.timing.navigationStart; + }; +} diff --git a/sae/roms.js b/sae/roms.js new file mode 100644 index 0000000..b78556b --- /dev/null +++ b/sae/roms.js @@ -0,0 +1,723 @@ +/*------------------------------------------------------------------------- +| SAE - Scripted Amiga Emulator +| https://github.com/naTmeg/ScriptedAmigaEmulator +| +| Copyright (C) 2012-2016 Rupert Hausberger +| +| This program is free software; you can redistribute it and/or +| modify it under the terms of the GNU General Public License +| as published by the Free Software Foundation; either version 2 +| of the License, or (at your option) any later version. +| +| This program is distributed in the hope that it will be useful, +| but WITHOUT ANY WARRANTY; without even the implied warranty of +| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +| GNU General Public License for more details. +| +| Note: ported from WinUAE 3.2.x +-------------------------------------------------------------------------*/ +/* global constants */ + +//const SAEC_RomType_SUB_MASK = 0x000000ff; +//const SAEC_RomType_GROUP_MASK = 0x003fff00; +//const SAEC_RomType_MASK = 0x003fffff; + +const SAEC_RomType_KICK = 0x00000100; +const SAEC_RomType_KICKCD32 = 0x00000200; +const SAEC_RomType_EXTCD32 = 0x00000400; +const SAEC_RomType_EXTCDTV = 0x00000800; +const SAEC_RomType_KEY = 0x00001000; +//const SAEC_RomType_ARCADIABIOS = 0x00002000; +//const SAEC_RomType_ARCADIAGAME = 0x00004000; +const SAEC_RomType_CD32CART = 0x00008000; +//const SAEC_RomType_SPECIALKICK = 0x00010000; + +/*const SAEC_RomType_CPUBOARD 0x00040000 +const SAEC_RomType_CB_A3001S1 0x00040001 +const SAEC_RomType_CB_APOLLO 0x00040002 +const SAEC_RomType_CB_FUSION 0x00040003 +const SAEC_RomType_CB_DKB12x0 0x00040004 +const SAEC_RomType_CB_WENGINE 0x00040005 +const SAEC_RomType_CB_TEKMAGIC 0x00040006 +const SAEC_RomType_CB_BLIZ1230 0x00040007 +const SAEC_RomType_CB_BLIZ1260 0x00040008 +const SAEC_RomType_CB_BLIZ2060 0x00040009 +const SAEC_RomType_CB_A26x0 0x0004000a +const SAEC_RomType_CB_CSMK1 0x0004000b +const SAEC_RomType_CB_CSMK2 0x0004000c +const SAEC_RomType_CB_CSMK3 0x0004000d +const SAEC_RomType_CB_CSPPC 0x0004000e +const SAEC_RomType_CB_BLIZPPC 0x0004000f +const SAEC_RomType_CB_GOLEM030 0x00040010 +const SAEC_RomType_CB_ACA500 0x00040011 +const SAEC_RomType_CB_DBK_WF 0x00040012 +const SAEC_RomType_CB_EMATRIX 0x00040013 +const SAEC_RomType_CB_SX32PRO 0x00040014 + +const SAEC_RomType_FREEZER 0x00080000 +const SAEC_RomType_AR 0x00080001 +const SAEC_RomType_AR2 0x00080002 +const SAEC_RomType_HRTMON 0x00080003 +const SAEC_RomType_NORDIC 0x00080004 +const SAEC_RomType_XPOWER 0x00080005 +const SAEC_RomType_SUPERIV 0x00080006 + +const SAEC_RomType_SCSI 0x00100000 +const SAEC_RomType_A2091 0x00100001 +const SAEC_RomType_A4091 0x00100002 +const SAEC_RomType_BLIZKIT4 0x00100003 +const SAEC_RomType_FASTLANE 0x00100004 +const SAEC_RomType_OKTAGON 0x00100005 +const SAEC_RomType_GVPS1 0x00100006 +const SAEC_RomType_GVPS12 0x00100007 +const SAEC_RomType_GVPS2 0x00100008*/ +const SAEC_RomType_AMAX = 0x00100009; +/*const SAEC_RomType_ALFA 0x0010000a +const SAEC_RomType_ALFAPLUS 0x0010000b +const SAEC_RomType_APOLLO 0x0010000c +const SAEC_RomType_MASOBOSHI 0x0010000d +const SAEC_RomType_SUPRA 0x0010000e +const SAEC_RomType_A2090 0x0010000f +const SAEC_RomType_GOLEM 0x00100010 +const SAEC_RomType_STARDRIVE 0x00100011 +const SAEC_RomType_KOMMOS 0x00100012 +const SAEC_RomType_VECTOR 0x00100013 +const SAEC_RomType_ADIDE 0x00100014 +const SAEC_RomType_MTEC 0x00100015 +const SAEC_RomType_PROTAR 0x00100016 +const SAEC_RomType_ADD500 0x00100017 +const SAEC_RomType_KRONOS 0x00100018 +const SAEC_RomType_ADSCSI 0x00100019 +const SAEC_RomType_ROCHARD 0x0010001a +const SAEC_RomType_CLTDSCSI 0x0010001b +const SAEC_RomType_PTNEXUS 0x0010001c +const SAEC_RomType_DATAFLYER 0x0010001d +const SAEC_RomType_SUPRADMA 0x0010001e +const SAEC_RomType_GREX 0x0010001f +const SAEC_RomType_PROMETHEUS 0x00100020 +const SAEC_RomType_MEDIATOR 0x00100021 +const SAEC_RomType_TECMAR 0x00100022 +const SAEC_RomType_XEBEC 0x00100023 +const SAEC_RomType_MICROFORGE 0x00100024 +const SAEC_RomType_PARADOX 0x00100025 +const SAEC_RomType_HDA506 0x00100026 +const SAEC_RomType_ALF1 0x00100027 +const SAEC_RomType_PROMIGOS 0x00100028 +const SAEC_RomType_SYSTEM2000 0x00100029 +const SAEC_RomType_A1060 0x0010002a +const SAEC_RomType_A2088 0x0010002b +const SAEC_RomType_A2088T 0x0010002c +const SAEC_RomType_A2286 0x0010002d +const SAEC_RomType_A2386 0x0010002e +const SAEC_RomType_OMTIADAPTER 0x0010002f +const SAEC_RomType_X86_HD 0x00100030 +const SAEC_RomType_X86_AT_HD1 0x00100031 +const SAEC_RomType_X86_AT_HD2 0x00100032 +const SAEC_RomType_X86_XT_IDE 0x00100033 +const SAEC_RomType_PICASSOIV 0x00100034 +const SAEC_RomType_x86_VGA 0x00100035 +const SAEC_RomType_APOLLOHD 0x00100036 +const SAEC_RomType_MEVOLUTION 0x00100037 +const SAEC_RomType_GOLEMFAST 0x00100038 +const SAEC_RomType_PHOENIXB 0x00100039*/ + +const SAEC_RomType_NOT = 0x00800000; +const SAEC_RomType_QUAD = 0x01000000; +const SAEC_RomType_EVEN = 0x02000000; +const SAEC_RomType_ODD = 0x04000000; +const SAEC_RomType_8BIT = 0x08000000; +const SAEC_RomType_BYTESWAP = 0x10000000; +const SAEC_RomType_CD32 = 0x20000000; +const SAEC_RomType_SCRAMBLED = 0x40000000; +const SAEC_RomType_NONE = 0x80000000; + +const SAEC_RomType_ALL_KICK = (SAEC_RomType_KICK | SAEC_RomType_KICKCD32 | SAEC_RomType_CD32) >>> 0; +const SAEC_RomType_ALL_EXT = (SAEC_RomType_EXTCD32 | SAEC_RomType_EXTCDTV) >>> 0; +//const SAEC_RomType_ALL_CART = (SAEC_RomType_AR | SAEC_RomType_HRTMON | SAEC_RomType_NORDIC | SAEC_RomType_XPOWER | SAEC_RomType_CD32CART) >>> 0; +const SAEC_RomType_ALL_CART = (SAEC_RomType_CD32CART) >>> 0; + +/*---------------------------------*/ +/* global object */ + +function SAEO_RomInfo() { //struct rominfo + this.name = 0; + this.models = ""; + this.ver = 0; + this.rev = 0; + this.subVer = 0; + this.subRev = 0; + this.cpu = 0; + this.cpuExact = false; + this.addressSpace24 = false; + this.cloanto = false; + this.type = 0; + this.partNumber = ""; + this.crc32 = 0; + this.checksum = false; /* false = checksum is not available */ + this.checksumValid = false; /* false = checksum is not available */ +} + +/*---------------------------------*/ + +function SAEO_Roms() { + const K1024 = 1048576; + const K512 = 524288; + const K256 = 262144; + const K128 = 131072; + const K64 = 65536; + + function romdata(a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p1,p2,p3,p4,p5,q,r) { + this.num = -1; + this.name = a; + this.ver = b; + this.rev = c; + this.subver = d; + this.subrev = e; + this.model = f; + this.size = g; //u32 + this.id = h; + this.cpu = i; + this.cloanto = j; + this.type = k; + this.group = l; + this.title = m; + this.partnumber = n; + this.crc32 = o; //u32 + this.sha1 = [p1,p2,p3,p4,p5]; //u32 + this.configname = typeof q == "undefined" ? "" : q; + this.defaultfilename = typeof r == "undefined" ? "" : r; + } + + //const ALTROM(id,grp,num,size,flags,crc32,a,b,c,d,e) { "X", 0, 0, 0, 0, 0, size, id, 0, 0, flags, (grp << 16) | num, 0, null, crc32, a, b, c, d, e }, + //const ALTROMPN(id,grp,num,size,flags,pn,crc32,a,b,c,d,e) { "X", 0, 0, 0, 0, 0, size, id, 0, 0, flags, (grp << 16) | num, 0, pn, crc32, a, b, c, d, e }, + // a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p1,p2,p3,p4,p5, q,r + + function ALTROM(id,grp,num,size,flags,crc32,a,b,c,d,e) { + return new romdata("X", 0, 0, 0, 0, 0, size, id, 0, 0, flags, (grp << 16) | num, "", "", crc32, a, b, c, d, e); + } + function ALTROMPN(id,grp,num,size,flags,pn,crc32,a,b,c,d,e) { + return new romdata("X", 0, 0, 0, 0, 0, size, id, 0, 0, flags, (grp << 16) | num, "", pn, crc32, a, b, c, d, e); + } + + const roms = [ + //new romdata("AROS KS ROM (built-in)", 0, 0, 0, 0, "AROS", K512 * 2, 66, 0, 0, SAEC_RomType_KICK, 0, "", "", 0xffffffff, 0, 0, 0, 0, 0, "AROS"), + new romdata("AROS KS ROM (built-in)", 0, 0, 0, 0, "AROS", K512, 66, 0, 0, SAEC_RomType_KICK, 0, "", "", 0xE8A40832, 0, 0, 0, 0, 0, "AROS"), + new romdata("AROS extended ROM (built-in)", 0, 0, 0, 0, "AROS", K512, 66, 0, 0, 0, 0, "", "", 0x5C39D820, 0, 0, 0, 0, 0, "AROS"), + //new romdata("ROM Disabled", 0, 0, 0, 0, "NOROM", 0, 87, 0, 0, SAEC_RomType_NONE, 0, "", "", 0xffffffff, 0, 0, 0, 0, 0, "NOROM"), + //new romdata("Enabled", 0, 0, 0, 0, "ENABLED", 0, 142, 0, 0, SAEC_RomType_NOT, 0, "", "", 0xffffffff, 0, 0, 0, 0, 0, "ENABLED"), + + new romdata("Cloanto Amiga Forever ROM key", 0, 0, 0, 0, "", 2069, 0, 0, 1, SAEC_RomType_KEY, 0, "", "", 0x869ae1b1, 0x801bbab3,0x2e3d3738,0x6dd1636d,0x4f1d6fa7,0xe21d5874), + new romdata("Cloanto Amiga Forever 2006 ROM key", 0, 0, 0, 0, "", 750, 48, 0, 1, SAEC_RomType_KEY, 0, "", "", 0xb01c4b56, 0xbba8e5cd,0x118b8d92,0xafed5693,0x5eeb9770,0x2a662d8f), + new romdata("Cloanto Amiga Forever 2010 ROM key", 0, 0, 0, 0, "", 1544, 73, 0, 1, SAEC_RomType_KEY, 0, "", "", 0x8c4dd05c, 0x05034f62,0x0b5bb7b2,0x86954ea9,0x164fdb90,0xfb2897a4), + + new romdata("KS ROM Velvet 23.93", 23, 93, 23, 93, "VELVET", K128, 125, 0, 0, SAEC_RomType_KICK, 0, "", "", 0xadcb44c9, 0x7c36b2ba,0x298da3da,0xce60d0ba,0x8511d470,0x76a40d5c), + ALTROMPN(125, 1, 1, 32768, SAEC_RomType_QUAD | SAEC_RomType_EVEN | SAEC_RomType_8BIT, "", 0x1d988ab8, 0xee3988a2,0xb2693334,0x0239d1d9,0xf50d4fb3,0xe0daf3bc), + ALTROMPN(125, 1, 2, 32768, SAEC_RomType_QUAD | SAEC_RomType_ODD | SAEC_RomType_8BIT, "", 0xe466b28f, 0x3e197d69,0xcffa3e1a,0x0c291d57,0xb53f7d1f,0xcb858cf7), + ALTROMPN(125, 1, 3, 32768, SAEC_RomType_QUAD | SAEC_RomType_EVEN | SAEC_RomType_8BIT, "", 0x715988a9, 0x08c36600,0x3948c4c5,0x4216ef8c,0x17ebe16c,0xc91d3b7a), + ALTROMPN(125, 1, 4, 32768, SAEC_RomType_QUAD | SAEC_RomType_ODD | SAEC_RomType_8BIT, "", 0xc4dc7e6a, 0x66b231d0,0x8425c858,0xdfcd36d2,0xd38a0df8,0x518e06a4), + new romdata("KS ROM v1.0 (A1000)(NTSC)", 1, 0, 1, 0, "A1000", K256, 1, 0, 0, SAEC_RomType_KICK, 0, "", "", 0x299790ff, 0x00C15406,0xBEB4B8AB,0x1A16AA66,0xC05860E1,0xA7C1AD79), + new romdata("KS ROM v1.1 (A1000)(NTSC)", 1, 1, 31, 34, "A1000", K256, 2, 0, 0, SAEC_RomType_KICK, 0, "", "", 0xd060572a, 0x4192C505,0xD130F446,0xB2ADA6BD,0xC91DAE73,0x0ACAFB4C), + new romdata("KS ROM v1.1 (A1000)(PAL)", 1, 1, 31, 34, "A1000", K256, 3, 0, 0, SAEC_RomType_KICK, 0, "", "", 0xec86dae2, 0x16DF8B5F,0xD524C5A1,0xC7584B24,0x57AC15AF,0xF9E3AD6D), + new romdata("KS ROM v1.2 (A1000)", 1, 2, 33, 166, "A1000", K256, 4, 0, 0, SAEC_RomType_KICK, 0, "", "", 0x9ed783d0, 0x6A7BFB5D,0xBD6B8F17,0x9F03DA84,0xD8D95282,0x67B6273B), + new romdata("KS ROM v1.2 (A500,A1000,A2000)", 1, 2, 33, 180, "A500|A1000|A2000", K256, 5, 0, 0, SAEC_RomType_KICK, 0, "", "315093-01", 0xa6ce1636, 0x11F9E62C,0xF299F721,0x84835B7B,0x2A70A163,0x33FC0D88), + new romdata("KS ROM v1.3 (A500,A1000,A2000)", 1, 3, 34, 5, "A500|A1000|A2000", K256, 6, 0, 0, SAEC_RomType_KICK, 0, "", "315093-02", 0xc4f0f55f, 0x891E9A54,0x7772FE0C,0x6C19B610,0xBAF8BC4E,0xA7FCB785), + new romdata("KS ROM v1.3 (A3000)(SK)", 1, 3, 34, 5, "A3000", K256, 32, 0, 0, SAEC_RomType_KICK, 0, "", "", 0xe0f37258, 0xC39BD909,0x4D4E5F4E,0x28C1411F,0x30869504,0x06062E87), + new romdata("KS ROM v1.4 (A3000)", 1, 4, 36, 16, "A3000", K512, 59, 3, 0, SAEC_RomType_KICK, 0, "", "", 0xbc0ec13f, 0xF76316BF,0x36DFF14B,0x20FA349E,0xD02E4B11,0xDD932B07), + ALTROMPN(59, 1, 1, K256, SAEC_RomType_EVEN, "390629-02", 0x58327536, 0xd1713d7f,0x31474a59,0x48e6d488,0xe3368606,0x1cf3d1e2), + ALTROMPN(59, 1, 2, K256, SAEC_RomType_ODD , "390630-02", 0xfe2f7fb9, 0xc05c9c52,0xd014c66f,0x9019152b,0x3f2a2adc,0x2c678794), + new romdata("KS ROM v2.04 (A500+)", 2, 4, 37, 175, "A500+", K512, 7, 0, 0, SAEC_RomType_KICK, 0, "", "390979-01", 0xc3bdb240, 0xC5839F5C,0xB98A7A89,0x47065C3E,0xD2F14F5F,0x42E334A1), + new romdata("KS ROM v2.05 (A600)", 2, 5, 37, 299, "A600", K512, 8, 0, 0, SAEC_RomType_KICK, 0, "", "391388-01", 0x83028fb5, 0x87508DE8,0x34DC7EB4,0x7359CEDE,0x72D2E3C8,0xA2E5D8DB), + new romdata("KS ROM v2.05 (A600HD)", 2, 5, 37, 300, "A600HD|A600", K512, 9, 0, 0, SAEC_RomType_KICK, 0, "", "391304-01", 0x64466c2a, 0xF72D8914,0x8DAC39C6,0x96E30B10,0x859EBC85,0x9226637B), + new romdata("KS ROM v2.05 (A600HD)", 2, 5, 37, 350, "A600HD|A600", K512, 10, 0, 0, SAEC_RomType_KICK, 0, "", "391304-02", 0x43b0df7b, 0x02843C42,0x53BBD29A,0xBA535B0A,0xA3BD9A85,0x034ECDE4), + new romdata("KS ROM v2.04 (A3000)", 2, 4, 37, 175, "A3000", K512, 71, 8, 0, SAEC_RomType_KICK, 0, "", "", 0x234a7233, 0xd82ebb59,0xafc53540,0xddf2d718,0x7ecf239b,0x7ea91590), + ALTROMPN(71, 1, 1, K256, SAEC_RomType_EVEN, "390629-03", 0xa245dbdf, 0x83bab8e9,0x5d378b55,0xb0c6ae65,0x61385a96,0xf638598f), + ALTROMPN(71, 1, 2, K256, SAEC_RomType_ODD , "390630-03", 0x7db1332b, 0x48f14b31,0x279da675,0x7848df6f,0xeb531881,0x8f8f576c), + new romdata("KS ROM v3.0 (A1200)", 3, 0, 39, 106, "A1200", K512, 11, 0, 0, SAEC_RomType_KICK, 0, "", "", 0x6c9b07d2, 0x70033828,0x182FFFC7,0xED106E53,0x73A8B89D,0xDA76FAA5), + ALTROMPN(11, 1, 1, K256, SAEC_RomType_EVEN, "391523-01", 0xc742a412, 0x999eb81c,0x65dfd07a,0x71ee1931,0x5d99c7eb,0x858ab186), + ALTROMPN(11, 1, 2, K256, SAEC_RomType_ODD , "391524-01", 0xd55c6ec6, 0x3341108d,0x3a402882,0xb5ef9d3b,0x242cbf3c,0x8ab1a3e9), + new romdata("KS ROM v3.0 (A4000)", 3, 0, 39, 106, "A4000", K512, 12, 2 | 4, 0, SAEC_RomType_KICK, 0, "", "", 0x9e6ac152, 0xF0B4E9E2,0x9E12218C,0x2D5BD702,0x0E4E7852,0x97D91FD7), + ALTROMPN(12, 1, 1, K256, SAEC_RomType_EVEN, "391513-02", 0x36f64dd0, 0x196e9f3f,0x9cad934e,0x181c07da,0x33083b1f,0x0a3c702f), + ALTROMPN(12, 1, 2, K256, SAEC_RomType_ODD , "391514-02", 0x17266a55, 0x42fbed34,0x53d1f11c,0xcbde89a9,0x826f2d11,0x75cca5cc), + new romdata("KS ROM v3.1 (A4000)", 3, 1, 40, 70, "A4000", K512, 13, 2 | 4, 0, SAEC_RomType_KICK, 0, "", "", 0x2b4566f1, 0x81c631dd,0x096bbb31,0xd2af9029,0x9c76b774,0xdb74076c), + ALTROM(13, 1, 1, K256, SAEC_RomType_EVEN, 0xf9cbecc9, 0x138d8cb4,0x3b8312fe,0x16d69070,0xde607469,0xb3d4078e), + ALTROM(13, 1, 2, K256, SAEC_RomType_ODD , 0xf8248355, 0xc2379547,0x9fae3910,0xc185512c,0xa268b82f,0x1ae4fe05), + new romdata("KS ROM v3.1 (A500,A600,A2000)", 3, 1, 40, 63, "A500|A600|A2000", K512, 14, 0, 0, SAEC_RomType_KICK, 0, "", "", 0xfc24ae0d, 0x3B7F1493,0xB27E2128,0x30F989F2,0x6CA76C02,0x049F09CA), + new romdata("KS ROM v3.1 (A1200)", 3, 1, 40, 68, "A1200", K512, 15, 1, 0, SAEC_RomType_KICK, 0, "", "", 0x1483a091, 0xE2154572,0x3FE8374E,0x91342617,0x604F1B3D,0x703094F1), + ALTROMPN(15, 1, 1, K256, SAEC_RomType_EVEN, "391773-01", 0x08dbf275,0xb8800f5f,0x90929810,0x9ea69690,0xb1b8523f,0xa22ddb37), + ALTROMPN(15, 1, 2, K256, SAEC_RomType_ODD , "391774-01", 0x16c07bf8,0x90e331be,0x1970b0e5,0x3f53a9b0,0x390b51b5,0x9b3869c2), + new romdata("KS ROM v3.1 (A3000)", 3, 1, 40, 68, "A3000", K512, 61, 2, 0, SAEC_RomType_KICK, 0, "", "", 0xefb239cc, 0xF8E210D7,0x2B4C4853,0xE0C9B85D,0x223BA20E,0x3D1B36EE), + ALTROM(61, 1, 1, K256, SAEC_RomType_EVEN, 0x286b9a0d, 0x6763a225,0x8ec493f7,0x408cf663,0x110dae9a,0x17803ad1), + ALTROM(61, 1, 2, K256, SAEC_RomType_ODD , 0x0b8cde6a, 0x5f02e97b,0x48ebbba8,0x7d516a56,0xb0400c6f,0xc3434d8d), + new romdata("KS ROM v3.1 (A4000)(Cloanto)", 3, 1, 40, 68, "A4000", K512, 31, 2 | 4, 1, SAEC_RomType_KICK, 0, "", "", 0x43b6dd22, 0xC3C48116,0x0866E60D,0x085E436A,0x24DB3617,0xFF60B5F9), + new romdata("KS ROM v3.1 (A4000)", 3, 1, 40, 68, "A4000", K512, 16, 2 | 4, 0, SAEC_RomType_KICK, 0, "", "", 0xd6bae334, 0x5FE04842,0xD04A4897,0x20F0F4BB,0x0E469481,0x99406F49), + ALTROM(16, 1, 1, K256, SAEC_RomType_EVEN, 0xb2af34f8, 0x24e52b5e,0xfc020495,0x17387ab7,0xb1a1475f,0xc540350e), + ALTROM(16, 1, 2, K256, SAEC_RomType_ODD , 0xe65636a3, 0x313c7cbd,0xa5779e56,0xf19a41d3,0x4e760f51,0x7626d882), + new romdata("KS ROM v3.1 (A4000T)", 3, 1, 40, 70, "A4000T", K512, 17, 2 | 4, 0, SAEC_RomType_KICK, 0, "", "", 0x75932c3a, 0xB0EC8B84,0xD6768321,0xE01209F1,0x1E6248F2,0xF5281A21), + ALTROMPN(17, 1, 1, K256, SAEC_RomType_EVEN, "391657-01", 0x0ca94f70, 0xb3806eda,0xcb3362fc,0x16a154ce,0x1eeec5bf,0x5bc24789), + ALTROMPN(17, 1, 2, K256, SAEC_RomType_ODD , "391658-01", 0xdfe03120, 0xcd7a706c,0x431b04d8,0x7814d3a2,0xd8b39710,0x0cf44c0c), + new romdata("KS ROM v3.X (A4000)(Cloanto)", 3, 10, 45, 57, "A4000", K512, 46, 2 | 4, 1, SAEC_RomType_KICK, 0, "", "", 0x3ac99edc, 0x3cbfc9e1,0xfe396360,0x157bd161,0xde74fc90,0x1abee7ec), + + new romdata("CD32 KS ROM v3.1", 3, 1, 40, 60, "CD32", K512, 18, 1, 0, SAEC_RomType_KICKCD32, 0, "", "", 0x1e62d4a5, 0x3525BE88,0x87F79B59,0x29E017B4,0x2380A79E,0xDFEE542D), + new romdata("CD32 extended ROM", 3, 1, 40, 60, "CD32", K512, 19, 1, 0, SAEC_RomType_EXTCD32, 0, "", "", 0x87746be2, 0x5BEF3D62,0x8CE59CC0,0x2A66E6E4,0xAE0DA48F,0x60E78F7F), + + //plain CD32 rom + new romdata("CD32 ROM (KS + extended)", 3, 1, 40, 60, "CD32", K1024, 64, 1, 0, SAEC_RomType_KICKCD32 | SAEC_RomType_EXTCD32 | SAEC_RomType_CD32, 0, "", "", 0xf5d4f3c8, 0x9fa14825,0xc40a2475,0xa2eba5cf,0x325bd483,0xc447e7c1), + //real CD32 rom dump 391640-03 + ALTROMPN(64, 1, 1, K1024, SAEC_RomType_CD32, "391640-03", 0xa4fbc94a, 0x816ce6c5,0x07787585,0x0c7d4345,0x2230a9ba,0x3a2902db), + + new romdata("CD32 Full Motion Video Cartridge ROM", 3, 1, 40, 30, "CD32FMV", K256, 23, 1, 0, SAEC_RomType_CD32CART, 0, "", "", 0xc35c37bf, 0x03ca81c7,0xa7b259cf,0x64bc9582,0x863eca0f,0x6529f435), + new romdata("CD32 Full Motion Video Cartridge ROM", 3, 1, 40, 22, "CD32FMV", K256, 74, 1, 0, SAEC_RomType_CD32CART, 0, "", "391777-01", 0xf11158eb, 0x94e469a7,0x6030dcb2,0x99ebc752,0x0aaeef9d,0xb54284cf), + + new romdata("CDTV extended ROM v1.00", 1, 0, 1, 0, "CDTV", K256, 20, 0, 0, SAEC_RomType_EXTCDTV, 0, "", "", 0x42baa124, 0x7BA40FFA,0x17E500ED,0x9FED041F,0x3424BD81,0xD9C907BE), + ALTROMPN(20, 1, 1, K128, SAEC_RomType_EVEN | SAEC_RomType_8BIT, "252606-01", 0x791cb14b, 0x277a1778,0x92449635,0x3ffe56be,0x68063d2a,0x334360e4), + ALTROMPN(20, 1, 2, K128, SAEC_RomType_ODD | SAEC_RomType_8BIT, "252607-01", 0xaccbbc2e, 0x41b06d16,0x79c6e693,0x3c3378b7,0x626025f7,0x641ebc5c), + new romdata("CDTV extended ROM v2.07", 2, 7, 2, 7, "CDTV", K256, 22, 0, 0, SAEC_RomType_EXTCDTV, 0, "", "", 0xceae68d2, 0x5BC114BB,0xA29F60A6,0x14A31174,0x5B3E2464,0xBFA06846), + ALTROM(22, 1, 1, K128, SAEC_RomType_EVEN | SAEC_RomType_8BIT, 0x36d73cb8, 0x9574e546,0x4b390697,0xf28f9a43,0x4e604e5e,0xf5e5490a), + ALTROM(22, 1, 2, K128, SAEC_RomType_ODD | SAEC_RomType_8BIT, 0x6e84dce7, 0x01a0679e,0x895a1a0f,0x559c7253,0xf539606b,0xd447b54f), + new romdata("CDTV/A570 extended ROM v2.30", 2, 30, 2, 30, "CDTV", K256, 21, 0, 0, SAEC_RomType_EXTCDTV, 0, "", "391298-01", 0x30b54232, 0xED7E461D,0x1FFF3CDA,0x321631AE,0x42B80E3C,0xD4FA5EBB), + ALTROM(21, 1, 1, K128, SAEC_RomType_EVEN | SAEC_RomType_8BIT, 0x48e4d74f, 0x54946054,0x2269e410,0x36018402,0xe1f6b855,0xfd89092b), + ALTROM(21, 1, 2, K128, SAEC_RomType_ODD | SAEC_RomType_8BIT, 0x8a54f362, 0x03df800f,0x032046fd,0x892f6e7e,0xec08b76d,0x33981e8c), + new romdata("CDTV-CR extended ROM v3.32", 3, 32, 3, 32, "CDTVCR", K256, 107, 0, 0, SAEC_RomType_EXTCDTV, 0, "", "", 0x581a85cf, 0xd6b8d3f2,0x854eba9b,0x2d514579,0x9529e8b3,0x3b85e0b4), + new romdata("CDTV-CR extended ROM v3.44", 3, 44, 3, 44, "CDTVCR", K256, 108, 0, 0, SAEC_RomType_EXTCDTV, 0, "", "", 0x0b7bd64f, 0x3b160c5a,0xbe79f10a,0xe6924332,0x8004bb9e,0x3162b648), + + new romdata("A1000 bootstrap ROM", 0, 0, 0, 0, "A1000", K64, 24, 0, 0, SAEC_RomType_KICK, 0, "", "", 0x0b1ad2d0, 0xBA93B8B8,0x5CA0D83A,0x68225CC3,0x3B95050D,0x72D2FDD7), + ALTROM(24, 1, 1, 8192, 0, 0x62f11c04, 0xC87F9FAD,0xA4EE4E69,0xF3CCA0C3,0x6193BE82,0x2B9F5FE6), + ALTROMPN(24, 2, 1, 4096, SAEC_RomType_EVEN | SAEC_RomType_8BIT, "252179-01", 0x42553bc4, 0x8855a97f,0x7a44e3f6,0x2d1c88d9,0x38fee1f4,0xc606af5b), + ALTROMPN(24, 2, 2, 4096, SAEC_RomType_ODD | SAEC_RomType_8BIT, "252180-01", 0x8e5b9a37, 0xd10f1564,0xb99f5ffe,0x108fa042,0x362e877f,0x569de2c3), + + /*new romdata("The Diagnostic 2.0 (Logica)", 2, 0, 2, 0, "LOGICA", K512, 72, 0, 0, SAEC_RomType_KICK | SAEC_RomType_SPECIALKICK, 0, "", "", 0x8484f426, 0xba10d161,0x66b2e2d6,0x177c979c,0x99edf846,0x2b21651e), + + new romdata("Picasso IV", 7, 4, 7, 4, "PIV", K128, 91, 0, 0, SAEC_RomType_PICASSOIV, 0, "", "", 0xa8133e7e, 0xcafafb91,0x6f16b9f3,0xec9b49aa,0x4b40eb4e,0xeceb5b5b), + + new romdata("A1060 BIOS 2.06", 2, 6, 2, 6, "A1060", 16384, 147, 0, 0, SAEC_RomType_A1060, 0, "", "380619-03", 0x185f2bbd, 0xeba74ad1,0x000a5351,0xa5d99179,0xbf75f831,0xac2d2402), + new romdata("A2088 BIOS 3.4", 3, 4, 3, 4, "A2088", 16384, 148, 0, 0, SAEC_RomType_A2088, 0, "", "380788-04", 0x05552160, 0xd1defdee, 0x1c0eae41, 0x07d81e26, 0x74915cd2, 0x9d352f2e), + new romdata("A2088 BIOS 3.5", 3, 5, 3, 5, "A2088", 16384, 158, 0, 0, SAEC_RomType_A2088, 0, "", "380788-04", 0xf8e1ad83, 0x45a2b7db,0x6e86fe80,0x5cfef63c,0x65c331a7,0x16a6e9e8), + new romdata("A2088 BIOS 3.6.1", 3, 61, 3, 61, "A2088", 16384, 149, 0, 0, SAEC_RomType_A2088, 0, "", "380788-06", 0x5fd93e56, 0xc1b707a8,0xa62907d7,0x5299f10a,0xa60efd1f,0x44514b26), + new romdata("A2088T BIOS 4.10", 4, 10, 4, 11, "A2088T", 32768, 150, 0, 0, SAEC_RomType_A2088T, 0, "", "390657-02", 0x20c5d1a9, 0x08e3fbb7,0x28dfc514,0x24083313,0x373ea7a5,0xa2c3e965), + new romdata("A2088T BIOS 4.11", 4, 11, 4, 11, "A2088T", 32768, 151, 0, 0, SAEC_RomType_A2088T, 0, "", "390547-02", 0x074bc9b0, 0x2a3f56bc,0xe395f203,0x46eb68c4,0xade7153e,0x3e69f892), + new romdata("A2088T BIOS 4.12", 4, 12, 4, 12, "A2088T", 32768, 152, 0, 0, SAEC_RomType_A2088T, 0, "", "390547-03", 0x92447176, 0x582fa254,0x73aa2679,0xefcd41a5,0xbdadf1a2,0x6a87a75f), + new romdata("A2286 BIOS 3.6", 3, 6, 3, 6, "A2286", 32768, 153, 0, 0, SAEC_RomType_A2286, 0, "", "", 0x63d75f70, 0x9f5d6c78,0x656d2fe7,0x36608644,0x771b6d30,0x31083264), + //ALTROMPN(153, 1, 1, 16384, SAEC_RomType_ODD | SAEC_RomType_8BIT, "380682-03", 0xb3f76402, 0xef9ba5f2, 0x2714ad6d, 0xfa5e0aef, 0x2d09ce83, 0x578ee26d) + //ALTROMPN(153, 1, 2, 16384, SAEC_RomType_EVEN | SAEC_RomType_8BIT, "380683-03", 0xab053693, 0x75229d80, 0x443fad78, 0xa298d04b, 0x37c8e6c3, 0x2c1b6df0) + new romdata("A2286 BIOS 4.2", 4, 2, 4, 2, "A2286", 32768, 154, 0, 0, SAEC_RomType_A2286, 0, "", "", 0xd572e205, 0x74fdf0f8,0x325fbc41,0x2b98c72d,0xf5095804,0x831c46b5), + //ALTROMPN(154, 1, 1, 16384, SAEC_RomType_ODD | SAEC_RomType_8BIT, "380682-04", 0xc23dcd55, 0x38dc24b7, 0x14427b15, 0xd5214cc9, 0xb9be0de7, 0x20bd6a34) + //ALTROMPN(154, 1, 2, 16384, SAEC_RomType_EVEN | SAEC_RomType_8BIT, "380683-04", 0xdad80c0b, 0x12fe2916, 0x64f8c412, 0x3877a24e, 0x05837091, 0x44d8acd0) + new romdata("A2386SX BIOS 1.0", 1, 0, 1, 0, "A2386SX", K64, 155, 0, 0, SAEC_RomType_A2386, 0, "", "", 0x37003e0c, 0x2e127e9c,0x8581d30c,0x2e46404b,0x21608e3c,0xe935fa27), + + new romdata("Arcadia OnePlay 2.11", 0, 0, 0, 0, "ARCADIA", 0, 49, 0, 0, SAEC_RomType_ARCADIABIOS, 0, "", "", 0, 0,0,0,0,0), + new romdata("Arcadia TenPlay 2.11", 0, 0, 0, 0, "ARCADIA", 0, 50, 0, 0, SAEC_RomType_ARCADIABIOS, 0, "", "", 0, 0,0,0,0,0), + new romdata("Arcadia TenPlay 2.20", 0, 0, 0, 0, "ARCADIA", 0, 75, 0, 0, SAEC_RomType_ARCADIABIOS, 0, "", "", 0, 0,0,0,0,0), + new romdata("Arcadia OnePlay 3.00", 0, 0, 0, 0, "ARCADIA", 0, 51, 0, 0, SAEC_RomType_ARCADIABIOS, 0, "", "", 0, 0,0,0,0,0), + new romdata("Arcadia TenPlay 3.11", 0, 0, 0, 0, "ARCADIA", 0, 76, 0, 0, SAEC_RomType_ARCADIABIOS, 0, "", "", 0, 0,0,0,0,0), + new romdata("Arcadia TenPlay 4.00", 0, 0, 0, 0, "ARCADIA", 0, 77, 0, 0, SAEC_RomType_ARCADIABIOS, 0, "", "", 0, 0,0,0,0,0), + + new romdata("Arcadia SportTime Table Hockey v2.1", 0, 0, 0, 0, "ARCADIA", 0, 33, 0, 0, SAEC_RomType_ARCADIAGAME, 0, "", "", 0, 0,0,0,0,0), + new romdata("Arcadia SportTime Bowling v2.1", 0, 0, 0, 0, "ARCADIA", 0, 34, 0, 0, SAEC_RomType_ARCADIAGAME, 0, "", "", 0, 0,0,0,0,0), + new romdata("Arcadia World Darts v2.1", 0, 0, 0, 0, "ARCADIA", 0, 35, 0, 0, SAEC_RomType_ARCADIAGAME, 0, "", "", 0, 0,0,0,0,0), + new romdata("Arcadia Magic Johnson's Fast Break v2.8", 0, 0, 0, 0, "ARCADIA", 0, 36, 0, 0, SAEC_RomType_ARCADIAGAME, 0, "", "", 0, 0,0,0,0,0), + new romdata("Arcadia Leader Board Golf v2.4", 0, 0, 0, 0, "ARCADIA", 0, 37, 0, 0, SAEC_RomType_ARCADIAGAME, 0, "", "", 0, 0,0,0,0,0), + new romdata("Arcadia Leader Board Golf", 0, 0, 0, 0, "ARCADIA", 0, 38, 0, 0, SAEC_RomType_ARCADIAGAME, 0, "", "", 0, 0,0,0,0,0), + new romdata("Arcadia Ninja Mission v2.5", 0, 0, 0, 0, "ARCADIA", 0, 39, 0, 0, SAEC_RomType_ARCADIAGAME, 0, "", "", 0, 0,0,0,0,0), + new romdata("Arcadia Road Wars v2.3", 0, 0, 0, 0, "ARCADIA", 0, 40, 0, 0, SAEC_RomType_ARCADIAGAME, 0, "", "", 0, 0,0,0,0,0), + new romdata("Arcadia Sidewinder v2.1", 0, 0, 0, 0, "ARCADIA", 0, 41, 0, 0, SAEC_RomType_ARCADIAGAME, 0, "", "", 0, 0,0,0,0,0), + new romdata("Arcadia Spot v2.0", 0, 0, 0, 0, "ARCADIA", 0, 42, 0, 0, SAEC_RomType_ARCADIAGAME, 0, "", "", 0, 0,0,0,0,0), + new romdata("Arcadia Space Ranger v2.0", 0, 0, 0, 0, "ARCADIA", 0, 43, 0, 0, SAEC_RomType_ARCADIAGAME, 0, "", "", 0, 0,0,0,0,0), + new romdata("Arcadia Xenon v2.3", 0, 0, 0, 0, "ARCADIA", 0, 44, 0, 0, SAEC_RomType_ARCADIAGAME, 0, "", "", 0, 0,0,0,0,0), + new romdata("Arcadia World Trophy Soccer v3.0", 0, 0, 0, 0, "ARCADIA", 0, 45, 0, 0, SAEC_RomType_ARCADIAGAME, 0, "", "", 0, 0,0,0,0,0), + new romdata("Arcadia Blastaball v2.1", 0, 0, 0, 0, "ARCADIA", 0, 78, 0, 0, SAEC_RomType_ARCADIAGAME, 0, "", "", 0, 0,0,0,0,0), + new romdata("Arcadia Delta Command", 0, 0, 0, 0, "ARCADIA", 0, 79, 0, 0, SAEC_RomType_ARCADIAGAME, 0, "", "", 0, 0,0,0,0,0), + new romdata("Arcadia Pharaohs Match", 0, 0, 0, 0, "ARCADIA", 0, 80, 0, 0, SAEC_RomType_ARCADIAGAME, 0, "", "", 0, 0,0,0,0,0), + new romdata("Arcadia SportTime Table Hockey", 0, 0, 0, 0, "ARCADIA", 0, 81, 0, 0, SAEC_RomType_ARCADIAGAME, 0, "", "", 0, 0,0,0,0,0), + new romdata("Arcadia World Darts (bad)", 0, 0, 0, 0, "ARCADIA", 0, 82, 0, 0, SAEC_RomType_ARCADIAGAME, 0, "", "", 0, 0,0,0,0,0), + new romdata("Arcadia Magic Johnson's Fast Break v2.7", 0, 0, 0, 0, "ARCADIA", 0, 83, 0, 0, SAEC_RomType_ARCADIAGAME, 0, "", "", 0, 0,0,0,0,0), + new romdata("Arcadia Ninja Mission", 0, 0, 0, 0, "ARCADIA", 0, 84, 0, 0, SAEC_RomType_ARCADIAGAME, 0, "", "", 0, 0,0,0,0,0), + new romdata("Arcadia Sidewinder", 0, 0, 0, 0, "ARCADIA", 0, 85, 0, 0, SAEC_RomType_ARCADIAGAME, 0, "", "", 0, 0,0,0,0,0), + new romdata("Arcadia Leader Board Golf v2.5", 0, 0, 0, 0, "ARCADIA", 0, 86, 0, 0, SAEC_RomType_ARCADIAGAME, 0, "", "", 0, 0,0,0,0,0), + new romdata("Arcadia Aaargh", 0, 0, 0, 0, "ARCADIA", 0, 88, 0, 0, SAEC_RomType_ARCADIAGAME, 0, "", "", 0, 0,0,0,0,0),*/ + + //OWN + //68000 + new romdata("Macintosh 128K", 0,0, 0,0, "128K", K64, 200, 0, 0, SAEC_RomType_AMAX, 0, "", "", 0x6D0C8A28, 0,0,0,0,0), //9D86C883AA09F7EF5F086D9E32330EF85F1BC93B + new romdata("Macintosh 512K", 0,0, 0,0, "512K", K64, 200, 0, 0, SAEC_RomType_AMAX, 0, "", "", 0xCF759E0D, 0,0,0,0,0), //5B1CED181B74CECD3834C49C2A4AA1D7FFE944D7 + new romdata("Macintosh Plus (version 1)", 0,0, 0,0, "Plus", K128, 200, 0, 0, SAEC_RomType_AMAX, 0, "", "", 0x4FA5B399, 0xE0DA7165,0xB92DEE90,0xD8B15224,0x29C03372,0x9FA73FD2), + new romdata("Macintosh Plus (version 2)", 0,0, 0,0, "Plus", K128, 200, 0, 0, SAEC_RomType_AMAX, 0, "", "", 0x7CACD18F, 0x73BF2EB2,0x15646E10,0x8DAA0CDD,0x874E6C84,0x3C8CE421), + new romdata("Macintosh Plus (version 3)", 0,0, 0,0, "Plus", K128, 200, 0, 0, SAEC_RomType_AMAX, 0, "", "", 0xB2102E8E, 0x7D2F808A,0x045AA3A1,0xB242764F,0x0E2C7D13,0xE288BF1F), + new romdata("Macintosh SE", 0,0, 0,0, "SE", K256, 200, 0, 0, SAEC_RomType_AMAX, 0, "", "", 0x0F7FF80C, 0,0,0,0,0), //58532B7D0D49659FD5228AC334A1B094F0241968 + new romdata("Macintosh SE (FDHD)", 0,0, 0,0, "SE", K256, 200, 0, 0, SAEC_RomType_AMAX, 0, "", "", 0xF530CB10, 0,0,0,0,0), //D3670A90273D12E53D86D1228C068CB660B8C9D1 + //new romdata("Macintosh Classic (with XO ROMDisk)", 0,0, 0,0, "Classic", K512, 200, 0, 0, SAEC_RomType_AMAX, 0, "", "", 0x510D7D38, 0,0,0,0,0), //CCD10904DDC0FB6A1D216B2E9EFFD5EC6CF5A83D + new romdata("Macintosh Classic", 0,0, 0,0, "Classic", K256, 200, 0, 0, SAEC_RomType_AMAX, 0, "", "", 0xB14DDCDE, 0,0,0,0,0), //F710E73E8E0F99D9D0E9E79E71F67A6C3648BF06 + //68HC000 16mhz + new romdata("Macintosh Portable", 0,0, 0,0, "Portable",K256, 200, 0, 0, SAEC_RomType_AMAX, 0, "", "", 0x497348F8, 0,0,0,0,0), //79B468B33FC53F11E87E2E4B195AAC981BF0C0A6 + new romdata("PowerBook 100", 0,0, 0,0, "100", K256, 200, 0, 0, SAEC_RomType_AMAX, 0, "", "", 0x29AC7EE9, 0,0,0,0,0), //7F3ACF40B1F63612DE2314A2E9FCFEAFCA0711FC + //68020 16mhz + new romdata("Macintosh II (version 1)", 0,0, 0,0, "II", K256, 200, 2, 0, SAEC_RomType_AMAX, 0, "", "", 0x8C8B9D03, 0,0,0,0,0), //5C264FE976F1E8495D364947C932A5E8309B4300 + new romdata("Macintosh II (version 2)", 0,0, 0,0, "II", K256, 200, 2, 0, SAEC_RomType_AMAX, 0, "", "", 0x4DF6D054, 0,0,0,0,0), //DB6B504744281369794E26BA71A6E385CF6227FA + new romdata("Macintosh LC", 0,0, 0,0, "LC", K512, 200, 2, 0, SAEC_RomType_AMAX, 0, "", "", 0x71681726, 0,0,0,0,0), //6BEF5853AE736F3F06C2B4E79772F65910C3B7D4 + ]; + for (var vi = 0; vi < roms.length; vi++) + roms[vi].num = vi; + + /*-----------------------------------------------------------------------*/ + + this.getromname = function(rd) { + var name = ""; + if (rd === null) + return name; + + while (rd.group) rd = roms[rd.num - 1]; + name += rd.name; + if ((rd.subrev || rd.subver) && rd.subver != rd.ver) + name += sprintf(" rev %d.%d", rd.subver, rd.subrev); + if (rd.size > 0) + name += sprintf(" (%dK)", (rd.size + 1023) >> 10); + if (rd.partnumber && rd.partnumber.length > 0) + name += sprintf(" [%s]", rd.partnumber); + + return name; + } + + /*-----------------------------------------------------------------------*/ + + function notcrc32(crc32) { + return crc32 == 0xffffffff || crc32 == 0x00000000; + } + this.getromdatabycrc = function(crc32, allowgroup) { + if (typeof allowgroup == "undefined") allowgroup = false; + var i, l = roms.length; + for (i = 0; i < l; i++) { + if (roms[i].group == 0 && crc32 == roms[i].crc32 && !notcrc32(crc32)) + return roms[i]; + } + if (allowgroup) { + for (i = 0; i < l; i++) { + if (roms[i].group != 0 && crc32 == roms[i].crc32 && !notcrc32(crc32)) + return roms[i]; + } + } + return null; + } + /*this.getromdatabycrc = function(crc32) { + return getromdatabycrc(crc32, false); + }*/ + + + /*const SHA1_SIZE = 20; + + function cmpsha1(sha1, rd) { + for (var i = 0; i < SHA1_SIZE; i += 4) { + if (((sha1[i] << 24) | (sha1[i + 1] << 16) | (sha1[i + 2] << 8) | (sha1[i + 3] << 0)) >>> 0 != rd.sha1[i >> 2]) + return -1; + } + return 0; + } + function checkromdata(sha1, size, mask) { + for (var i = 0; i < roms.length; i++) { + if (roms[i].size >= size) { + if (roms[i].type & mask) { + if (!cmpsha1(sha1, roms[i])) + return roms[i]; + } + } + } + return null; + }*/ + function checkromdata(crc32, size, mask) { + for (var i = 0; i < roms.length; i++) { + if (!notcrc32(roms[i].crc32) && roms[i].size >= size) { + if (roms[i].type & mask) { + if (crc32 == roms[i].crc32) + return roms[i]; + } + } + } + return null; + } + + this.getromdatabydata = function(rom, size) { + if (size > 11 && SAEF_CompareArray(rom, SAEF_String2Array("AMIROMTYPE1"), 11) == 0) { + var tmpbuf = new Uint8Array(size); + var tmpsize = size - 11; + tmpbuf.set(rom.subarray(11)); //memcpy (tmpbuf, rom + 11, tmpsize); + if (this.decode_rom(tmpbuf,0, tmpsize, 1, tmpsize) != 0) + return null; + rom = tmpbuf; + size = tmpsize; + } + /*#if 0 + if (size > 0x6c + K512 && SAEF_CompareArray(rom, SAEF_String2Array("AMIG"), 4) == 0) { + var tmpbuf = new Uint8Array(size); + var tmpsize = size - 0x6c; + tmpbuf.set(rom.subarray(0x6c)); //memcpy (tmpbuf, rom + 0x6c, tmpsize); + this.decode_rom(tmpbuf,0, tmpsize, 2, tmpsize); + rom = tmpbuf; + size = tmpsize; + } + #endif*/ + + //var sha1[SHA1_SIZE]; get_sha1(rom, size, sha1); var ret = checkromdata(sha1, size, 0xffffffff);*/ + var crc32 = SAEF_crc32(rom,0, size); + var ret = checkromdata(crc32, size, 0xffffffff); + if (ret === null) { + //get_sha1(rom, size >> 1, sha1); ret = checkromdata(sha1, size >> 1, 0xffffffff); + crc32 = SAEF_crc32(rom,0, size >> 1); + ret = checkromdata(crc32, size >> 1, 0xffffffff); + /*if (ret === null) { + var tmp = new Uint8Array(4); + //ignore AR2/3 IO-port range until we have full dump + tmp.set(rom.subarray(0, 4)); //memcpy (tmp, rom, 4); + SAEF_memset(rom,0, 0, 4); //memset (rom, 0, 4); + //get_sha1(rom, size, sha1); ret = checkromdata(sha1, size, SAEC_RomType_AR2); + crc32 = SAEF_crc32(rom,0, size); + ret = checkromdata(crc32, size, SAEC_RomType_AR2); + rom.set(tmp); //memcpy (rom, tmp, 4); + }*/ + } + return ret; + } + + /*-----------------------------------------------------------------------*/ + + this.kickstart_fix_checksum = function(mem,memo, size) { + var cksum = 0, prevck = 0; + var i, ch = size == K512 ? 0x7ffe8 : (size == K256 ? 0x3ffe8 : 0x3e); + + mem[memo + ch ] = 0; + mem[memo + ch + 1] = 0; + mem[memo + ch + 2] = 0; + mem[memo + ch + 3] = 0; + for (i = 0; i < size; i += 4) { + var data = ((mem[memo + i] << 24) | (mem[memo + i + 1] << 16) | (mem[memo + i + 2] << 8) | mem[memo + i + 3]) >>> 0; + cksum += data; if (cksum > 0xffffffff) cksum -= 0x100000000; + if (cksum < prevck) { + cksum++; if (cksum > 0xffffffff) cksum -= 0x100000000; + } + prevck = cksum; + } + cksum = (cksum ^ 0xffffffff) >>> 0; + mem[memo + ch ] = cksum >>> 24; + mem[memo + ch + 1] = (cksum >>> 16) & 0xff; + mem[memo + ch + 2] = (cksum >>> 8) & 0xff; + mem[memo + ch + 3] = cksum & 0xff; + + SAEF_log("roms.kickstart_fix_checksum() %08X", cksum); + } + + function kickstart_calc_checksum(mem,memo, size) { + var cksum = 0, prevck = 0; + for (var i = 0; i < size; i += 4) { + var data = ((mem[memo + i] << 24) | (mem[memo + i + 1] << 16) | (mem[memo + i + 2] << 8) | mem[memo + i + 3]) >>> 0; + cksum += data; if (cksum > 0xffffffff) cksum -= 0x100000000; + if (cksum < prevck) { + cksum++; if (cksum > 0xffffffff) cksum -= 0x100000000; + } + prevck = cksum; + } + return cksum; + } + + this.kickstart_verify_checksum = function(mem,memo, size) { + var cksum = kickstart_calc_checksum(mem,memo, size); + SAEF_log("roms.kickstart_verify_checksum() %08X", cksum); + return cksum == 0xffffffff; + } + + /*-----------------------------------------------------------------------*/ + + function macintosh_calc_checksum(mem,memo, size) { //OWN + var cksum = 0; + + if (size == 0x400000) //Special case: 4MiB ROMs only checksum the first 3 MiB. + size -= 0x100000; + + for (var i = 4; i < size; i += 2) { + var data = (mem[memo + i] << 8) | mem[memo + i + 1]; + cksum += data; if (cksum > 0xffffffff) cksum -= 0x100000000; + } + return cksum; + } + + /*-----------------------------------------------------------------------*/ + + function decode_cloanto_rom(mem,memo, size, real_size) { + var rk = SAEV_config.memory.romKey; + + if (rk.name.length && rk.data.length) { + var keydata = rk.data; + var keysize = rk.data.length; + var cnt, t; + + for (t = cnt = 0; cnt < size; cnt++, t = (t + 1) % keysize) { + mem[memo + cnt] ^= keydata.charCodeAt(t); + if (real_size == cnt + 1) + t = keysize - 1; + } + if ((mem[memo + 2] == 0x4e && mem[memo + 3] == 0xf9) || (mem[memo] == 0x11 && (mem[memo + 1] == 0x11 || mem[memo + 1] == 0x14))) { + //SAEV_Memory_cloantoRom = true; + return 0; + } + + /* + //uae_u8 sha1[SHA1_SIZE]; get_sha1(mem, size, sha1); var rd = checkromdata(sha1, size, 0xffffffff); + var crc32 = SAEF_crc32(mem,memo, size); + var rd = checkromdata(crc32, size, 0xffffffff); + if (rd !== null) { + //if (rd.cloanto) SAEV_Memory_cloantoRom = true; + //SAEF_warn("roms.decode_cloanto_rom() invalid/wrong rom-key"); + return -1; + }*/ + return -1; + } + return -2; + } + function decode_rekick_rom(mem,memo, size, real_size) { + var d1 = 0xdeadfeed, d0; + + for (var i = memo; i < memo + (size >> 3); i++) { + d0 = (((mem[i * 8 + 0] << 24) | (mem[i * 8 + 1] << 16) | (mem[i * 8 + 2] << 8) | mem[i * 8 + 3])) >>> 0; + d1 = (d1 ^ d0) >>> 0; + mem[i * 8 + 0] = d1 >>> 24; + mem[i * 8 + 1] = (d1 >>> 16) & 0xff; + mem[i * 8 + 2] = (d1 >>> 8) & 0xff; + mem[i * 8 + 3] = d1 & 0xff; + d1 = (((mem[i * 8 + 4] << 24) | (mem[i * 8 + 5] << 16) | (mem[i * 8 + 6] << 8) | mem[i * 8 + 7])) >>> 0; + d0 = (d0 ^ d1) >>> 0; + mem[i * 8 + 4] = d0 >>> 24; + mem[i * 8 + 5] = (d0 >>> 16) & 0xff; + mem[i * 8 + 6] = (d0 >>> 8) & 0xff; + mem[i * 8 + 7] = d0 & 0xff; + } + return 0; + } + this.decode_rom = function(mem,memo, size, mode, real_size) { + if (mode == 1) + return decode_cloanto_rom(mem,memo, size, real_size); + else if (mode == 2) + return decode_rekick_rom(mem,memo, size, real_size); + + return -3; + } + + /*-----------------------------------------------------------------------*/ + + function replaceAll(str, search, replacement) { + return str.split(search).join(replacement); + } + + this.examine = function(ri, file) { + var data = SAEF_String2Array(file.data); + var size = file.size; + + var cloanto = false; + if (size > 11 && SAEF_CompareArray(data, SAEF_String2Array("AMIROMTYPE1"), 11) == 0) { + var tmpdata = new Uint8Array(size); + var tmpsize = size - 11; + tmpdata.set(data.subarray(11)); //memcpy (tmpdata, data + 11, tmpsize); + var err = this.decode_rom(tmpdata,0, tmpsize, 1, tmpsize); + if (err == -1) + return SAEE_Memory_RomDecode; + if (err == -2) + return SAEE_Memory_RomKey; + + data = tmpdata; + size = tmpsize; + cloanto = true; + } + + var crc32 = file.crc32; + if (crc32 === false || cloanto) { + crc32 = SAEF_crc32(data,0, size); + if (!cloanto) + file.crc32 = crc32; + } + + var rd = checkromdata(crc32, size, 0xffffffff); + if (rd === null) + return SAEE_Memory_RomUnknown; + + while (rd.group) + rd = roms[rd.num - 1]; + + ri.name = rd.name; + + if (rd.type & SAEC_RomType_AMAX) { + var ver = data.subarray(0x08, 0x08 + 2); + var rev = data.subarray(0x12, 0x12 + 2); + var sub = data.subarray(0x4c, 0x4c + 2); + ri.ver = (ver[0] << 8) | ver[1]; + ri.rev = (rev[0] << 8) | rev[1]; + ri.subVer = (sub[0] << 8) | sub[1]; + ri.subRev = 0; + } else { + ri.ver = rd.ver; + ri.rev = rd.rev; + ri.subVer = rd.subver; + ri.subRev = rd.subrev; + } + ri.models = replaceAll(rd.model, "|", ", "); + ri.size = rd.size; + //rd.id + if (rd.cpu & 8) { //v2.04 (A3000) + ri.cpu = 68030; + } else if ((rd.cpu & 3) == 3) { + ri.cpu = 68030; + ri.cpuExact = true; + } else if ((rd.cpu & 3) == 2) { + ri.cpu = 68020; + } else if ((rd.cpu & 3) == 1) { + ri.cpu = 68020; //EC + ri.addressSpace24 = true; + } else { + ri.cpu = 68000; + ri.addressSpace24 = true; + } + ri.cloanto = cloanto; //rd.cloanto; + ri.type = rd.type; + + //rd.title + ri.partNumber = rd.partnumber; + ri.crc32 = rd.crc32; + //rd.sha1 + + if (rd.type & (SAEC_RomType_ALL_KICK | SAEC_RomType_ALL_EXT)) { + ri.checksum = kickstart_calc_checksum(data,0, size); + ri.checksumValid = ri.checksum == 0xffffffff; + } + else if (rd.type & SAEC_RomType_AMAX) { + var chk = data.subarray(0, 4); + ri.checksum = macintosh_calc_checksum(data,0, size); + ri.checksumValid = ri.checksum == ((chk[0] << 24) | (chk[1] << 16) | (chk[2] << 8) | chk[3]) >>> 0; + } + else { + ri.checksum = false; + ri.checksumValid = false; + } + return SAEE_None; + } +} + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/sae/rtc.js b/sae/rtc.js index ec6d239..76ad20c 100644 --- a/sae/rtc.js +++ b/sae/rtc.js @@ -1,199 +1,306 @@ -/************************************************************************** -* SAE - Scripted Amiga Emulator -* -* 2012-2015 Rupert Hausberger -* -* https://github.com/naTmeg/ScriptedAmigaEmulator -* -**************************************************************************/ +/*------------------------------------------------------------------------- +| SAE - Scripted Amiga Emulator +| https://github.com/naTmeg/ScriptedAmigaEmulator +| +| Copyright (C) 2012-2016 Rupert Hausberger +| +| This program is free software; you can redistribute it and/or +| modify it under the terms of the GNU General Public License +| as published by the Free Software Foundation; either version 2 +| of the License, or (at your option) any later version. +| +| This program is distributed in the hope that it will be useful, +| but WITHOUT ANY WARRANTY; without even the implied warranty of +| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +| GNU General Public License for more details. +| +| Note: ported from WinUAE 3.2.x +-------------------------------------------------------------------------*/ +/* global variables */ + +var SAEV_RTC_bank = null; + +var SAEV_RTC_delayed_write = 0; + +/*---------------------------------*/ + +function SAEO_RTC() { + const RTC_DEBUG = false; + + var clock_control_d = 0; + var clock_control_e = 0; + var clock_control_f = 0; -function RTC() { const RF5C01A_RAM_SIZE = 16; - - var clock_control_d; - var clock_control_e; - var clock_control_f; - var rtc_memory = null; var rtc_alarm = null; - this.read = function () { - /*struct zfile *f; - f = zfile_fopen (currprefs.flashfile, "rb", ZFD_NORMAL); - if (f) { - zfile_fread (rtc_memory, RF5C01A_RAM_SIZE, 1, f); - zfile_fread (rtc_alarm, RF5C01A_RAM_SIZE, 1, f); - zfile_fclose (f); - }*/ - }; - this.write = function () { - /*struct zfile *f = zfile_fopen (currprefs.flashfile, L"rb+", ZFD_NORMAL); - if (!f) { - f = zfile_fopen (currprefs.flashfile, L"wb", 0); - if (f) { - zfile_fwrite (rtc_memory, RF5C01A_RAM_SIZE, 1, f); - zfile_fwrite (rtc_alarm, RF5C01A_RAM_SIZE, 1, f); - zfile_fclose (f); - } - return; - } - zfile_fseek (f, 0, SEEK_END); - if (zfile_ftell (f) <= 2 * RF5C01A_RAM_SIZE) { - zfile_fseek (f, 0, SEEK_SET); - zfile_fwrite (rtc_memory, RF5C01A_RAM_SIZE, 1, f); - zfile_fwrite (rtc_alarm, RF5C01A_RAM_SIZE, 1, f); - } - zfile_fclose (f);*/ - }; + /*---------------------------------*/ - this.setup = function () { - BUG.info('RTC.setup() type ' + (AMIGA.config.rtc.type == SAEV_Config_RTC_Type_MSM6242B ? 'MSM6242B' : 'RF5C01A')); + function localtime(t) { + this.tm_sec = t.getSeconds(); //seconds [0,61] + this.tm_min = t.getMinutes(); //minutes [0,59] + this.tm_hour = t.getHours(); //hour [0,23] + this.tm_mday = t.getDate(); //day of month [1,31] + this.tm_mon = t.getMonth(); //month of year [0,11] + this.tm_year = t.getFullYear() - 1900; //years since 1900 + this.tm_wday = t.getDay(); //day of week [0,6] (Sunday = 0) + this.tm_yday = 0; //day of year [0,365] + this.tm_isdst = false; //daylight savings flag + } - if (AMIGA.config.rtc.type == SAEV_Config_RTC_Type_MSM6242B) { + function getct() { + var d = new Date(); + if (SAEV_config.chipset.rtc.adjust) { + var n = d.valueOf(); + d.setTime(n + SAEV_config.chipset.rtc.adjust * 1000); + } + return new localtime(d); + } + + /*---------------------------------*/ + + function getclockreg(addr, ct) { + var v = 0; + + if (SAEV_config.chipset.rtc.type == SAEC_Config_RTC_Type_MSM6242B || SAEV_config.chipset.rtc.type == SAEC_Config_RTC_Type_MSM6242B_A2000) { /* MSM6242B */ + switch (addr) { + case 0x0: v = ct.tm_sec % 10; break; + case 0x1: v = ct.tm_sec / 10 >>> 0; break; + case 0x2: v = ct.tm_min % 10; break; + case 0x3: v = ct.tm_min / 10 >>> 0; break; + case 0x4: v = ct.tm_hour % 10; break; + case 0x5: { + if (clock_control_f & 4) + v = ct.tm_hour / 10 >>> 0; /* 24h */ + else { + v = (ct.tm_hour % 12) / 10 >>> 0; /* 12h */ + v |= ct.tm_hour >= 12 ? 4 : 0; /* AM/PM bit */ + } + break; + } + case 0x6: v = ct.tm_mday % 10; break; + case 0x7: v = ct.tm_mday / 10 >>> 0; break; + case 0x8: v = (ct.tm_mon + 1) % 10; break; + case 0x9: v = (ct.tm_mon + 1) / 10 >>> 0; break; + case 0xA: v = ct.tm_year % 10; break; + case 0xB: v = ((ct.tm_year / 10) >>> 0) & 0x0f; break; + case 0xC: v = ct.tm_wday; break; + case 0xD: v = clock_control_d; break; + case 0xE: v = clock_control_e; break; + case 0xF: v = clock_control_f; break; + } + } else if (SAEV_config.chipset.rtc.type == SAEC_Config_RTC_Type_RF5C01A) { /* RF5C01A */ + var bank = clock_control_d & 3; + /* memory access */ + if (bank >= 2 && addr < 0x0d) + return (rtc_memory[addr] >> ((bank == 2) ? 0 : 4)) & 0x0f; + /* alarm */ + if (bank == 1 && addr < 0x0d) { + v = rtc_alarm[addr]; + if (RTC_DEBUG) SAEF_log("rtc.get8(0x%X, ct) ALARM (0x%x)", addr, v); + return v; + } + switch (addr) { + case 0x0: v = ct.tm_sec % 10; break; + case 0x1: v = ct.tm_sec / 10 >>> 0; break; + case 0x2: v = ct.tm_min % 10; break; + case 0x3: v = ct.tm_min / 10 >>> 0; break; + case 0x4: v = ct.tm_hour % 10; break; + case 0x5: { + if (rtc_alarm[10] & 1) + v = ct.tm_hour / 10 >>> 0; /* 24h */ + else { + v = (ct.tm_hour % 12) / 10 >>> 0; /* 12h */ + v |= ct.tm_hour >= 12 ? 2 : 0; /* AM/PM bit */ + } + break; + } + case 0x6: v = ct.tm_wday; break; + case 0x7: v = ct.tm_mday % 10; break; + case 0x8: v = ct.tm_mday / 10 >>> 0; break; + case 0x9: v = (ct.tm_mon + 1) % 10; break; + case 0xA: v = (ct.tm_mon + 1) / 10 >>> 0; break; + case 0xB: v = (ct.tm_year % 100) % 10; break; + case 0xC: v = (ct.tm_year % 100) / 10 >>> 0; break; + case 0xD: v = clock_control_d; break; + case 0xE: v = 0; break; //E and F = write-only, reads as zero + case 0xF: v = 0; break; + } + } + if (RTC_DEBUG) SAEF_log("rtc.get8(0x%X, ct) (0x%x)", addr, v); + return v; + } + + /*---------------------------------*/ + + function read() { //read_battclock() + //if (SAEV_config.chipset.rtc.file.length) + { + var f = null; //SAEF_ZFile_fopen(SAEV_config.chipset.rtc.file, "rb"); + if (f) { + var data = new Uint8Array(16); + SAEF_ZFile_fread(data,0, 16, 1, f); + clock_control_d = data[13]; + clock_control_e = data[14]; + clock_control_f = data[15]; + if (SAEV_config.chipset.rtc.type == SAEC_Config_RTC_Type_RF5C01A) { + SAEF_ZFile_fread(rtc_alarm,0, RF5C01A_RAM_SIZE, 1, f); + SAEF_ZFile_fread(rtc_memory,0, RF5C01A_RAM_SIZE, 1, f); + } + SAEF_ZFile_fclose(f); + } + } + } + this.write = function() { //write_battclock() called from cia.vsync() + if (SAEV_config.chipset.rtc.type != SAEC_Config_RTC_Type_None) { + //if (SAEV_config.chipset.rtc.file.length) + { + var f = null; //SAEF_ZFile_fopen(SAEV_config.chipset.rtc.file, "wb"); + if (f) { + var ct = getct(); + var data = new Uint8Array(16); + var od = clock_control_d; + if (SAEV_config.chipset.rtc.type == SAEC_Config_RTC_Type_RF5C01A) + clock_control_d &= ~3; + for (var i = 0; i < 13; i++) + data[i] = getclockreg(i, ct); + clock_control_d = od; + data[i] = clock_control_d; + data[i] = clock_control_e; + data[i] = clock_control_f; + SAEF_ZFile_fwrite(data,0, 16, 1, f); + if (SAEV_config.chipset.rtc.type == SAEC_Config_RTC_Type_RF5C01A) { + SAEF_ZFile_fwrite(rtc_alarm,0, RF5C01A_RAM_SIZE, 1, f); + SAEF_ZFile_fwrite(rtc_memory,0, RF5C01A_RAM_SIZE, 1, f); + } + SAEF_ZFile_fclose(f); + } + } + } + } + + /*---------------------------------*/ + + this.hardreset = function() { //rtc_hardreset() + switch (SAEV_config.chipset.rtc.type) { + case SAEC_Config_RTC_Type_None: type = "none"; break; + case SAEC_Config_RTC_Type_MSM6242B: type = "MSM6242B"; break; + case SAEC_Config_RTC_Type_RF5C01A: type = "RF5C01A"; break; + case SAEC_Config_RTC_Type_MSM6242B_A2000: type = "MSM6242B A2000"; break; + } + SAEF_log("rtc.hardreset() type '%s'", type); + + SAEV_RTC_delayed_write = 0; + if (SAEV_config.chipset.rtc.type == SAEC_Config_RTC_Type_MSM6242B || SAEV_config.chipset.rtc.type == SAEC_Config_RTC_Type_MSM6242B_A2000) { /* MSM6242B */ clock_control_d = 0x1; clock_control_e = 0; - clock_control_f = 0x4; - /* 24/12 */ - } else if (AMIGA.config.rtc.type == SAEV_Config_RTC_Type_RF5C01A) { - clock_control_d = 0x4; - /* Timer EN */ + clock_control_f = 0x4; /* 24/12 */ + rtc_memory = null; + rtc_alarm = null; + } else if (SAEV_config.chipset.rtc.type == SAEC_Config_RTC_Type_RF5C01A) { /* RF5C01A */ + clock_control_d = 0x8; /* Timer EN */ clock_control_e = 0; clock_control_f = 0; - rtc_memory = new Uint8Array(RF5C01A_RAM_SIZE); rtc_alarm = new Uint8Array(RF5C01A_RAM_SIZE); - for (var i = 0; i < RF5C01A_RAM_SIZE; i++) rtc_memory[i] = rtc_alarm[i] = 0; - this.read(); + rtc_alarm[10] = 1; /* 24H mode */ } - }; + SAEV_RTC_bank.name = "Battery backed up clock ("+type+")"; + read(); + } + + /*---------------------------------*/ + + function get32(addr) { + if ((addr & 0xffff) >= 0x8000 && SAEV_config.chipset.fatGaryRev >= 0) + return SAER.memory.dummyGet(addr, 4, false, 0); + + return ((get16(addr) << 16) | get16(addr + 2)) >>> 0; + } + + function get16(addr) { + if ((addr & 0xffff) >= 0x8000 && SAEV_config.chipset.fatGaryRev >= 0) + return SAER.memory.dummyGet(addr, 2, false, 0); + + return (get8(addr) << 8) | get8(addr + 1); + } + + function get8(addr) { + if ((addr & 0xffff) >= 0x8000 && SAEV_config.chipset.fatGaryRev >= 0) + return SAER.memory.dummyGet(addr, 1, false, 0); + /*#ifdef CDTV + if (currprefs.cs_cdtvram && (addr & 0xffff) >= 0x8000) + return cdtv_battram_read(addr); + #endif*/ - this.load8 = function (addr) { addr &= 0x3f; - if ((addr & 3) == 2 || (addr & 3) == 0 || AMIGA.config.rtc.type == SAEV_Config_RTC_Type_None) { - if (AMIGA.config.cpu.model == 68000 && AMIGA.config.cpu.compatible) - return 0xff; //regs.irc >> 8; - return 0; + if ((addr & 3) == 2 || (addr & 3) == 0 || SAEV_config.chipset.rtc.type == SAEC_Config_RTC_Type_None) + return SAER.memory.dummyGet(addr, 1, false, 0); + + var ct = getct(); + return getclockreg(addr >> 2, ct); + } + + function put32(addr, value) { + if ((addr & 0xffff) >= 0x8000 && SAEV_config.chipset.fatGaryRev >= 0) { + SAER.memory.dummyPut(addr, 4, value); + return; } - var t = new Date(); + put16(addr, value >>> 16); + put16(addr + 2, value & 0xffff); + } - addr >>= 2; - if (AMIGA.config.rtc.type == SAEV_Config_RTC_Type_MSM6242B) { - switch (addr) { - case 0x0: - return t.getSeconds() % 10; - case 0x1: - return Math.floor(t.getSeconds() / 10); - case 0x2: - return t.getMinutes() % 10; - case 0x3: - return Math.floor(t.getMinutes() / 10); - case 0x4: - return t.getHours() % 10; - case 0x5: - return Math.floor(t.getHours() / 10); - case 0x6: - return t.getDate() % 10; - case 0x7: - return Math.floor(t.getDate() / 10); - case 0x8: - return (t.getMonth() + 1) % 10; - case 0x9: - return Math.floor((t.getMonth() + 1) / 10); - case 0xA: - return (t.getFullYear() - 1900) % 10; - case 0xB: - return Math.floor((t.getFullYear() - 1900) / 10); - case 0xC: - return t.getDay(); - case 0xD: - return clock_control_d; - case 0xE: - return clock_control_e; - case 0xF: - return clock_control_f; - } - } else if (AMIGA.config.rtc.type == SAEV_Config_RTC_Type_RF5C01A) { - var bank = clock_control_d & 3; - - if (bank >= 2 && addr < 0x0d) return (rtc_memory[addr] >> ((bank == 2) ? 0 : 4)) & 0x0f; - if (bank == 1 && addr < 0x0d) return rtc_alarm[addr]; - - switch (addr) { - case 0x0: - return t.getSeconds() % 10; - case 0x1: - return Math.floor(t.getSeconds() / 10); - case 0x2: - return t.getMinutes() % 10; - case 0x3: - return Math.floor(t.getMinutes() / 10); - case 0x4: - return t.getHours() % 10; - case 0x5: - return Math.floor(t.getHours() / 10); - case 0x6: - return t.getDate() % 10; - case 0x7: - return Math.floor(t.getDate() / 10); - case 0x8: - return (t.getMonth() + 1) % 10; - case 0x9: - return Math.floor((t.getMonth() + 1) / 10); - case 0xA: - return (t.getFullYear() - 1900) % 10; - case 0xB: - return Math.floor((t.getFullYear() - 1900) / 10); - case 0xC: - return t.getDay(); - case 0xD: - return clock_control_d; - /* E and F = write-only */ - } + function put16(addr, value) { + if ((addr & 0xffff) >= 0x8000 && SAEV_config.chipset.fatGaryRev >= 0) { + SAER.memory.dummyPut(addr, 2, value); + return; } - return 0; - }; + put8(addr, value >> 8); + put8(addr + 1, value & 0xff); + } - this.load16 = function (addr) { - return (this.load8(addr) << 8) | this.load8(addr + 1); - }; + function put8(addr, value) { + if ((addr & 0xffff) >= 0x8000 && SAEV_config.chipset.fatGaryRev >= 0) { + SAER.memory.dummyPut(addr, 1, value); + return; + } + /*#ifdef CDTV + if (currprefs.cs_cdtvram && (addr & 0xffff) >= 0x8000) { + cdtv_battram_write(addr, value); + return; + } + #endif*/ - this.load32 = function (addr) { - return ((this.load16(addr) << 16) | this.load16(addr + 2)) >>> 0; - }; - - this.store8 = function (addr, value) { addr &= 0x3f; - if ((addr & 1) != 1 || AMIGA.config.rtc.type == SAEV_Config_RTC_Type_None) return; - + if ((addr & 1) != 1 || SAEV_config.chipset.rtc.type == SAEC_Config_RTC_Type_None) + return; addr >>= 2; value &= 0x0f; - if (AMIGA.config.rtc.type == SAEV_Config_RTC_Type_MSM6242B) { + if (SAEV_config.chipset.rtc.type == SAEC_Config_RTC_Type_MSM6242B || SAEV_config.chipset.rtc.type == SAEC_Config_RTC_Type_MSM6242B_A2000) { /* MSM6242B */ + if (RTC_DEBUG) SAEF_log("rtc.put8(0x%X, 0x%x)", addr, value); switch (addr) { - case 0xD: - clock_control_d = value & (1 | 8); - break; - case 0xE: - clock_control_e = value; - break; - case 0xF: - clock_control_f = value; - break; + case 0xD: clock_control_d = value & (1|8); break; + case 0xE: clock_control_e = value; break; + case 0xF: clock_control_f = value; break; } - } else if (AMIGA.config.rtc.type == SAEV_Config_RTC_Type_RF5C01A) { + } else if (SAEV_config.chipset.rtc.type == SAEC_Config_RTC_Type_RF5C01A) { /* RF5C01A */ var bank = clock_control_d & 3; - + /* memory access */ if (bank >= 2 && addr < 0x0d) { + var ov = rtc_memory[addr]; rtc_memory[addr] &= ((bank == 2) ? 0xf0 : 0x0f); rtc_memory[addr] |= value << ((bank == 2) ? 0 : 4); - - //var ov = rtc_memory[addr]; - if (rtc_memory[addr] != value) this.write(); + if (rtc_memory[addr] != ov) SAEV_RTC_delayed_write = -1; return; } + /* alarm */ if (bank == 1 && addr < 0x0d) { + if (RTC_DEBUG) SAEF_log("rtc.put8(0x%X, 0x%x) ALARM", addr, value); + var ov = rtc_alarm[addr]; rtc_alarm[addr] = value; rtc_alarm[0] = rtc_alarm[1] = rtc_alarm[9] = rtc_alarm[12] = 0; rtc_alarm[3] &= ~0x8; @@ -202,34 +309,25 @@ function RTC() { rtc_alarm[8] &= ~0xc; rtc_alarm[10] &= ~0xe; rtc_alarm[11] &= ~0xc; - - //var ov = rtc_alarm[addr]; - if (rtc_alarm[addr] != value) this.write(); + if (rtc_alarm[addr] != ov) SAEV_RTC_delayed_write = -1; return; } + if (RTC_DEBUG) SAEF_log("rtc.put8(0x%X, 0x%x)", addr, value); switch (addr) { - case 0xD: - clock_control_d = value; - break; - case 0xE: - clock_control_e = value; - break; - case 0xF: - clock_control_f = value; - break; + case 0xD: clock_control_d = value; break; + case 0xE: clock_control_e = value; break; + case 0xF: clock_control_f = value; break; } } - - }; - - this.store16 = function (addr, value) { - this.store8(addr, (value >> 8) & 0xff); - this.store8(addr + 1, value & 0xff); - }; - - this.store32 = function (addr, value) { - this.store16(addr, (value >>> 16) & 0xffff); - this.store16(addr + 2, value & 0xffff); + SAEV_RTC_delayed_write = -1; } -} + SAEV_RTC_bank = new SAEO_Memory_addrbank( + get32, get16, get8, + put32, put16, put8, + SAEF_Memory_defaultXLate, SAEF_Memory_defaultCheck, null, null, "Battery backed up clock (none)", + SAEF_Memory_dummyGetInst32, SAEF_Memory_dummyGetInst16, + //SAEC_Memory_addrbank_flag_IO, S_READ, S_WRITE, null, 0x3f, 0xd80000 + SAEC_Memory_addrbank_flag_IO, null, 0x3f, 0xd80000 + ); +} diff --git a/sae/serial.js b/sae/serial.js index 3f7714b..e42209c 100644 --- a/sae/serial.js +++ b/sae/serial.js @@ -1,82 +1,302 @@ -/************************************************************************** -* SAE - Scripted Amiga Emulator -* -* 2012-2015 Rupert Hausberger -* -* https://github.com/naTmeg/ScriptedAmigaEmulator -* -**************************************************************************/ +/*------------------------------------------------------------------------- +| SAE - Scripted Amiga Emulator +| https://github.com/naTmeg/ScriptedAmigaEmulator +| +| Copyright (C) 2012-2016 Rupert Hausberger +| +| This program is free software; you can redistribute it and/or +| modify it under the terms of the GNU General Public License +| as published by the Free Software Foundation; either version 2 +| of the License, or (at your option) any later version. +| +| This program is distributed in the hope that it will be useful, +| but WITHOUT ANY WARRANTY; without even the implied warranty of +| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +| GNU General Public License for more details. +| +| Note: ported from WinUAE 3.2.x +-------------------------------------------------------------------------*/ -function Serial() -{ - var buf = new Uint8Array(1024); - var pos = 0, dtr = false; - var serper = 0, serdat = 0x2000; +function SAEO_Serial() { + const WARN_SERIAL = true; + const DEBUG_SERIAL = 0; /* 0,1,2,3 */ - this.reset = function () { - this.flushBuffer(); + var inbuf = new Uint8Array(1024); + var outbuf = new Uint8Array(1024); + var inptr = 0, inlast = 0, outlast = 0; - pos = 0; + var waitqueue = false; + var dsr = false; + var dtr = false; + //var carrier = false; + var notify = false; + var serdev = false; + + var serper = 0, serdat = 0; + + /*---------------------------------*/ + + function open() { //serial_open() + if (serdev) + return; + + /*if ((sd = open(currprefs.sername, O_RDWR|O_NONBLOCK|O_BINARY, 0)) < 0) { + SAEF_log("serial.open() Could not open Device %s", currprefs.sername); + return; + } + serdev = true; + + if (tcgetattr (sd, &tios) < 0) { + SAEF_log("serial.open() TCGETATTR failed"); + return; + } + cfmakeraw(&tios); + + #ifndef MODEMTEST + tios.c_cflag &= ~CRTSCTS; + #else + tios.c_cflag |= CRTSCTS; + #endif + + if (tcsetattr (sd, TCSADRAIN, &tios) < 0) + SAEF_log("serial.open() TCSETATTR failed");*/ + } + function close() { //serial_close() + //if (sd >= 0) close(sd); + serdev = false; + } + + /*---------------------------------*/ + + function read_buffer() { + if (inptr < inlast) + return inbuf[inptr++]; + + /*if (serdev) { + inlast = read(sd, inbuf, 1024); + inptr = 0; + if (inptr < inlast) + return inbuf[inptr++]; + }*/ + return false; + } + + function flush_buffer() { + if (outlast > 0) { //OWN + var str = ""; + for (var i = 0; i < outlast; i++) + str += String.fromCharCode(outbuf[i]); + + //SAEF_info(str); + console.log(str); + } + if (serdev) { + /*if (outlast) { + if (sd != 0) + write(sd, outbuf, outlast); + }*/ + outlast = 0; + } else { + outlast = 0; + inptr = 0; + inlast = 0; + } + } + + /*---------------------------------*/ + + this.SERPER = function(w) { + var baud, pspeed; + + if (!SAEV_config.serial.enabled) + return; + if (serper == w) /* don't set baudrate if it's already ok */ + return; + + serper = w; + if (WARN_SERIAL && (w & 0x8000)) SAEF_warn("serial.SERPER() 9bit transmission not implemented."); + + switch (w & 0x7fff) { + case 0x2e9b: + case 0x2e14: baud = 300; pspeed = 300; break; + case 0x170a: + case 0x0b85: baud = 1200; pspeed = 1200; break; + case 0x05c2: + case 0x05b9: baud = 2400; pspeed = 2400; break; + case 0x02e9: + case 0x02e1: baud = 4800; pspeed = 4800; break; + case 0x0174: + case 0x0170: baud = 9600; pspeed = 9600; break; + case 0x00b9: + case 0x00b8: baud = 19200; pspeed = 19200; break; + case 0x005c: + case 0x005d: baud = 38400; pspeed = 38400; break; + case 0x003d: baud = 57600; pspeed = 57600; break; + case 0x001e: baud = 115200; pspeed = 115200; break; + case 0x000f: baud = 230400; pspeed = 230400; break; + default: { + if (WARN_SERIAL) SAEF_warn("serial.SERPER() unsupported baudrate (0x%04x) %d", w & 0x7fff, ~~(3579546.471 / ((w & 0x7fff) + 1))); + return; + } + } + if (serdev) { + /*if (tcgetattr(sd, &tios) < 0) { + if (WARN_SERIAL) SAEF_warn("serial.SERPER() TCGETATTR failed"); + return; + } + if (cfsetispeed(&tios, pspeed) < 0) { + if (WARN_SERIAL) SAEF_warn("serial.SERPER() CFSETISPEED (%d bps) failed", baud); + return; + } + if (cfsetospeed(&tios, pspeed) < 0) { + if (WARN_SERIAL) SAEF_warn("serial.SERPER() CFSETOSPEED (%d bps) failed", baud); + return; + } + if (tcsetattr(sd, TCSADRAIN, &tios) < 0) { + if (WARN_SERIAL) SAEF_warn("serial.SERPER() TCSETATTR failed"); + return; + }*/ + } + if (DEBUG_SERIAL > 0) SAEF_log("serial.SERPER() baudrate set to %d bit/sec", baud); + } + + this.SERDAT = function(w) { + if (!SAEV_config.serial.enabled) + return; + + var z = w & 0xff; + + if (SAEV_config.serial.demand && !dtr) { + if (!notify) { + if (WARN_SERIAL) SAEF_warn("serial.SERDAT() Your software needs SERIAL ALWAYS to work properly. (disable 'serial.demand' in the config)"); + notify = true; + } + return; + } else { + outbuf[outlast++] = z; + if (outlast == outbuf.length) + flush_buffer(); + } + + if (DEBUG_SERIAL > 2) SAEF_log("serial.SERDAT() wrote 0x%04x", w); + + serdat |= 0x2000; /* Set TBE in the SERDATR ... */ + SAEV_Custom_intreq |= SAEC_Custom_INTF_TBE; /* ... and in INTREQ register */ + return; + } + + this.SERDATR = function() { + if (!SAEV_config.serial.enabled) + return 0x2000; + + if (DEBUG_SERIAL > 2) SAEF_log("serial.SERDATR() read 0x%04x", serdat); + waitqueue = false; + return serdat; + } + + this.SERDATS = function() { + if (!serdev) /* || (serdat & 0x4000)) */ + return 0; + + if (waitqueue) { + SAEV_Custom_intreq |= SAEC_Custom_INTF_RBF; + return 1; + } + var z; + if ((z = read_buffer()) !== false) { + waitqueue = true; + serdat = 0x4100; /* RBF and STP set! */ + serdat |= (z & 0xff); + SAEV_Custom_intreq |= SAEC_Custom_INTF_RBF; /* Set RBF flag (Receive Buffer full) */ + + if (DEBUG_SERIAL > 1) SAEF_log("serial.SERDATS() received 0x%02x --> serdat 0x%04x", z, serdat); + return 1; + } + return 0; + } + + /*---------------------------------*/ + + this.dtr_on = function() { + if (DEBUG_SERIAL > 0) SAEF_log("serial.dtr_on()"); + dtr = true; + if (SAEV_config.serial.demand) + open(); + } + this.dtr_off = function() { + if (DEBUG_SERIAL > 0) SAEF_log("serial.dtr_off()"); dtr = false; + if (SAEV_config.serial.demand) + close(); + } + + this.readstatus = function(ignored) { + var status = 0; + + /*ioctl (sd, TIOCMGET, &status); + if (status & TIOCM_CAR) { + if (!carrier) { + ciabpra |= 0x20; + carrier = true; + if (DEBUG_SERIAL > 0) SAEF_log("serial.readstatus() Carrier detect"); + } + } else { + if (carrier) { + ciabpra &= ~0x20; + carrier = false; + if (DEBUG_SERIAL > 0) SAEF_log("serial.readstatus() Carrier lost"); + } + } + if (status & TIOCM_DSR) { + if (!dsr) { + ciabpra |= 0x08; + dsr = true; + } + } else { + if (dsr) { + ciabpra &= ~0x08; + dsr = false; + } + }*/ + return status; + } + + this.writestatus = function(old, nw) { + if ((old & 0x80) == 0x80 && (nw & 0x80) == 0x00) this.dtr_on(); + if ((old & 0x80) == 0x00 && (nw & 0x80) == 0x80) this.dtr_off(); + + if (DEBUG_SERIAL > 0) { + if ((old & 0x40) != (nw & 0x40)) SAEF_log("serial.writestatus() RTS %s", ((nw & 0x40) == 0x40) ? "set" : "cleared"); + if ((old & 0x10) != (nw & 0x10)) SAEF_log("serial.writestatus() CTS %s", ((nw & 0x10) == 0x10) ? "set" : "cleared"); + } + return nw; + } + + /*---------------------------------*/ + + this.setup = function() { //serial_init() + if (!SAEV_config.serial.enabled) + return; + if (!SAEV_config.serial.demand) + open(); + + serdat = 0x2000; + } + this.cleanup = function() { //serial_exit() + close(); + dtr = false; + } + + this.reset = function() { + inptr = 0, inlast = 0, outlast = 0 + + waitqueue = false; + dsr = false; + dtr = false; + //carrier = false; + notify = false; + serper = 0; serdat = 0x2000; }; - - this.flushBuffer = function () { - if (pos > 0) { - var str = ''; - for (var i = 0; i < pos; i++) { - /*if (buf[i] == 13) - str += '
'; - else if (buf[i] == 9) - str += '   '; - else*/ - str += String.fromCharCode(buf[i]); - } - pos = 0; - BUG.col = 3; - BUG.info(str); - BUG.col = 1; - } - }; - - this.readStatus = function () { - //ciabpra |= 0x20; //Push up Carrier Detect line - //ciabpra |= 0x08; //DSR ON - return 0; - }; - - this.writeStatus = function (old, nw) { - if ((old & 0x80) == 0x80 && (nw & 0x80) == 0x00) dtr = true; - if ((old & 0x80) == 0x00 && (nw & 0x80) == 0x80) dtr = false; - //if ((old & 0x40) != (nw & 0x40)) BUG.info('RTS %s.', (nw & 0x40) == 0x40 ? 'set' : 'clr'); - //if ((old & 0x10) != (nw & 0x10)) BUG.info('CTS %s.', (nw & 0x10) == 0x10 ? 'set' : 'clr'); - return nw; - }; - - this.SERPER = function (v) { - if (serper != v) - serper = v; - }; - - this.SERDAT = function (v) { - //BUG.info('SERDAT $%04x', v); - - if (AMIGA.config.serial.enabled) { - buf[pos++] = v & 0xff; - if (pos == 1024) - this.flushBuffer(); - } - serdat |= 0x2000; - /* Set TBE in the SERDATR ... */ - AMIGA.intreq |= 1; - /* ... and in INTREQ register */ - }; - - this.SERDATR = function() - { - //BUG.info('SERDATR $%04x', serdat); - return serdat; - } } - diff --git a/sae/utils.js b/sae/utils.js index 78ae7ef..f45322d 100644 --- a/sae/utils.js +++ b/sae/utils.js @@ -1,96 +1,255 @@ -/************************************************************************** -* SAE - Scripted Amiga Emulator -* -* 2012-2015 Rupert Hausberger -* -* https://github.com/naTmeg/ScriptedAmigaEmulator -* -**************************************************************************/ +/*------------------------------------------------------------------------- +| SAE - Scripted Amiga Emulator +| https://github.com/naTmeg/ScriptedAmigaEmulator +| +| Copyright (C) 2012-2016 Rupert Hausberger +| +| This program is free software; you can redistribute it and/or +| modify it under the terms of the GNU General Public License +| as published by the Free Software Foundation; either version 2 +| of the License, or (at your option) any later version. +| +| This program is distributed in the hope that it will be useful, +| but WITHOUT ANY WARRANTY; without even the implied warranty of +| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +| GNU General Public License for more details. +-------------------------------------------------------------------------*/ +/* global constants */ -/* moving average algorithm */ +const SAEC_LITTLE_ENDIAN = (function() { + var buffer = new ArrayBuffer(2); + new DataView(buffer).setInt16(0, 256, true); + return new Int16Array(buffer)[0] === 256; /* read is LE */ +})(); +//console.log("Little endian system: "+(SAEC_LITTLE_ENDIAN ? "Yes" : "No")); -function MAvg(size) { - this.values = new Array(size); - this.size = size; - this.usage = 0; - this.offset = 0; - this.average = 0; +/*-----------------------------------------------------------------------*/ +/* byte-swapping */ + +function SAEF_bswap16(v) { + return ((v & 0x00ff) << 8) | ((v & 0xff00) >> 8); +} +function SAEF_bswap32(v) { + return (((v & 0x000000ff) << 24) | ((v & 0x0000ff00) << 8) | ((v & 0x00ff0000) >>> 8) | ((v & 0xff000000) >>> 24)) >>> 0; +} + +function SAEF_be16toh(v) { + if (SAEC_LITTLE_ENDIAN) + return ((v & 0x00ff) << 8) | ((v & 0xff00) >> 8); + else + return v; +} +function SAEF_be32toh(v) { + if (SAEC_LITTLE_ENDIAN) + return (((v & 0x000000ff) << 24) | ((v & 0x0000ff00) << 8) | ((v & 0x00ff0000) >>> 8) | ((v & 0xff000000) >>> 24)) >>> 0; + else + return v; +} + +function SAEF_le32toh(v) { + if (SAEC_LITTLE_ENDIAN) + return v; + else + return (((v & 0x000000ff) << 24) | ((v & 0x0000ff00) << 8) | ((v & 0x00ff0000) >>> 8) | ((v & 0xff000000) >>> 24)) >>> 0; +} +function SAEF_le16toh(v) { + if (SAEC_LITTLE_ENDIAN) + return v; + else + return ((v & 0x00ff) << 8) | ((v & 0xff00) >> 8); +} + +/*-----------------------------------------------------------------------*/ +/* moving average */ + +function SAEO_MAvg(size) { + var values = new Array(size); + var size = size; + var usage = 0; + var offset = 0; + var average = 0; this.clr = function () { - this.usage = 0; - this.offset = 0; - this.average = 0; + usage = 0; + offset = 0; + average = 0; }; + this.get = function() { + return average / usage; /* return as float */ + } + this.set = function(newval) { - if (this.usage < this.size) { - this.values[this.usage++] = newval; - this.average += newval; + if (usage < size) { + values[usage++] = newval; + average += newval; } else { - this.average -= this.values[this.offset]; - this.values[this.offset] = newval; - this.average += newval; - if (++this.offset >= this.size) - this.offset -= this.size; + average -= values[offset]; + values[offset] = newval; + average += newval; + if (++offset >= size) + offset -= size; } - return Math.floor(this.average / this.usage); + return average / usage; /* return as float */ } } /*-----------------------------------------------------------------------*/ +/* CRC checksumming */ -/*function crc32(str, crc) { - const tab = - '00000000 77073096 EE0E612C 990951BA 076DC419 706AF48F E963A535 9E6495A3 '+ - '0EDB8832 79DCB8A4 E0D5E91E 97D2D988 09B64C2B 7EB17CBD E7B82D07 90BF1D91 '+ - '1DB71064 6AB020F2 F3B97148 84BE41DE 1ADAD47D 6DDDE4EB F4D4B551 83D385C7 '+ - '136C9856 646BA8C0 FD62F97A 8A65C9EC 14015C4F 63066CD9 FA0F3D63 8D080DF5 '+ - '3B6E20C8 4C69105E D56041E4 A2677172 3C03E4D1 4B04D447 D20D85FD A50AB56B '+ - '35B5A8FA 42B2986C DBBBC9D6 ACBCF940 32D86CE3 45DF5C75 DCD60DCF ABD13D59 '+ - '26D930AC 51DE003A C8D75180 BFD06116 21B4F4B5 56B3C423 CFBA9599 B8BDA50F '+ - '2802B89E 5F058808 C60CD9B2 B10BE924 2F6F7C87 58684C11 C1611DAB B6662D3D '+ - '76DC4190 01DB7106 98D220BC EFD5102A 71B18589 06B6B51F 9FBFE4A5 E8B8D433 '+ - '7807C9A2 0F00F934 9609A88E E10E9818 7F6A0DBB 086D3D2D 91646C97 E6635C01 '+ - '6B6B51F4 1C6C6162 856530D8 F262004E 6C0695ED 1B01A57B 8208F4C1 F50FC457 '+ - '65B0D9C6 12B7E950 8BBEB8EA FCB9887C 62DD1DDF 15DA2D49 8CD37CF3 FBD44C65 '+ - '4DB26158 3AB551CE A3BC0074 D4BB30E2 4ADFA541 3DD895D7 A4D1C46D D3D6F4FB '+ - '4369E96A 346ED9FC AD678846 DA60B8D0 44042D73 33031DE5 AA0A4C5F DD0D7CC9 '+ - '5005713C 270241AA BE0B1010 C90C2086 5768B525 206F85B3 B966D409 CE61E49F '+ - '5EDEF90E 29D9C998 B0D09822 C7D7A8B4 59B33D17 2EB40D81 B7BD5C3B C0BA6CAD '+ - 'EDB88320 9ABFB3B6 03B6E20C 74B1D29A EAD54739 9DD277AF 04DB2615 73DC1683 '+ - 'E3630B12 94643B84 0D6D6A3E 7A6A5AA8 E40ECF0B 9309FF9D 0A00AE27 7D079EB1 '+ - 'F00F9344 8708A3D2 1E01F268 6906C2FE F762575D 806567CB 196C3671 6E6B06E7 '+ - 'FED41B76 89D32BE0 10DA7A5A 67DD4ACC F9B9DF6F 8EBEEFF9 17B7BE43 60B08ED5 '+ - 'D6D6A3E8 A1D1937E 38D8C2C4 4FDFF252 D1BB67F1 A6BC5767 3FB506DD 48B2364B '+ - 'D80D2BDA AF0A1B4C 36034AF6 41047A60 DF60EFC3 A867DF55 316E8EEF 4669BE79 '+ - 'CB61B38C BC66831A 256FD2A0 5268E236 CC0C7795 BB0B4703 220216B9 5505262F '+ - 'C5BA3BBE B2BD0B28 2BB45A92 5CB36A04 C2D7FFA7 B5D0CF31 2CD99E8B 5BDEAE1D '+ - '9B64C2B0 EC63F226 756AA39C 026D930A 9C0906A9 EB0E363F 72076785 05005713 '+ - '95BF4A82 E2B87A14 7BB12BAE 0CB61B38 92D28E9B E5D5BE0D 7CDCEFB7 0BDBDF21 '+ - '86D3D2D4 F1D4E242 68DDB3F8 1FDA836E 81BE16CD F6B9265B 6FB077E1 18B74777 '+ - '88085AE6 FF0F6A70 66063BCA 11010B5C 8F659EFF F862AE69 616BFFD3 166CCF45 '+ - 'A00AE278 D70DD2EE 4E048354 3903B3C2 A7672661 D06016F7 4969474D 3E6E77DB '+ - 'AED16A4A D9D65ADC 40DF0B66 37D83BF0 A9BCAE53 DEBB9EC5 47B2CF7F 30B5FFE9 '+ - 'BDBDF21C CABAC28A 53B39330 24B4A3A6 BAD03605 CDD70693 54DE5729 23D967BF '+ - 'B3667A2E C4614AB8 5D681B02 2A6F2B94 B40BBE37 C30C8EA1 5A05DF1B 2D02EF8D'; +var SAEV_crc32Table = new Uint32Array(256); +var SAEV_crc16Table = new Uint16Array(256); +{ + var c, w; + var n, k; + for (n = 0; n < 256; n++) { + c = n; + w = n << 8; + for (k = 0; k < 8; k++) { + c = ((c >>> 1) ^ (c & 1 ? 0xedb88320 : 0)) >>> 0; + w = ((w << 1) & 0xffff) ^ ((w & 0x8000) ? 0x1021 : 0); + } + SAEV_crc32Table[n] = c; + SAEV_crc16Table[n] = w; + } +} - if (crc == window.undefined) crc = 0; +function SAEF_crc32(buf,bufo, len) { + var crc = 0xffffffff; + if (typeof buf === "string") { + while (len-- > 0) + crc = SAEV_crc32Table[(crc ^ buf.charCodeAt(bufo++)) & 0xff] ^ (crc >>> 8); + } else { + while (len-- > 0) + crc = SAEV_crc32Table[(crc ^ buf[bufo++]) & 0xff] ^ (crc >>> 8); + } + return (crc ^ 0xffffffff) >>> 0; +} - crc = crc ^ (-1); - for (var i = 0, len = str.length; i < len; i++) - crc = (crc >>> 8) ^ parseInt(tab.substr(((crc ^ str.charCodeAt(i)) & 0xff) * 9, 8), 16); - crc = crc ^ (-1); - - return crc < 0 ? crc + 0x100000000 : crc; +function SAEF_crc16(buf,bufo, len) { + var crc = 0xffff; + while (len-- > 0) + crc = ((crc << 8) & 0xffff) ^ SAEV_crc16Table[((crc >> 8) ^ buf[bufo++]) & 0xff]; + return crc; +} + +/*-----------------------------------------------------------------------*/ +/* Date/Time conversion */ + +function SAEF_gettimeofday(tv, tz) { + var now = performance.now(); + now += performance.timing.navigationStart; + now = Math.floor(now * 1000); + tv.tv_sec = Math.floor(now / 1000000); + tv.tv_usec = now % 1000000; +} + +function SAEF_timeval_to_amiga(tv, amiga, tickcount) { + /* tv.tv_sec is secs since 1-1-1970 */ + /* days since 1-1-1978 */ + /* mins since midnight */ + /* ticks past minute @ 50Hz */ + const msecs_per_day = 24 * 60 * 60 * 1000; + + var t = tv.tv_sec * 1000 + Math.floor(tv.tv_usec / 1000); + t -= (8 * 365 + 2) * 24 * 60 * 60 * 1000; + + if (t < 0) + t = 0; + amiga.days = Math.floor(t / msecs_per_day); + t -= amiga.days * msecs_per_day; + amiga.mins = Math.floor(t / (60 * 1000)); + t -= amiga.mins * (60 * 1000); + amiga.ticks = Math.floor(t / (1000 / tickcount)); +} + +/*function SAEF_amiga_to_timeval(tv, days, mins, ticks, tickcount) { + if (days < 0) + days = 0; + if (days > 9900 * 365) + days = 9900 * 365; // in future far enough? + if (mins < 0 || mins >= 24 * 60) + mins = 0; + if (ticks < 0 || ticks >= 60 * tickcount) + ticks = 0; + + var t = ticks * 20; + t += mins * 60 * 1000; + t += days * 24 * 60 * 60 * 1000; + t += (8 * 365 + 2) * 24 * 60 * 60 * 1000; + + tv.tv_sec = Math.floor(t / 1000); + tv.tv_usec = (t % 1000) * 1000; }*/ /*-----------------------------------------------------------------------*/ -/* -* Javascript sprintf -* http://www.webtoolkit.info/ + +function SAEF_memset(dst,dsto, value, length) { + for (var i = dsto, j = dsto + length; i < j; i++) + dst[i] = value; +} + +function SAEF_memcpy(dst,dsto, src,srco, length) { + for (var i = 0; i < length; i++) + dst[dsto + i] = src[srco + i]; +} + +/*-----------------------------------------------------------------------*/ + +function SAEF_Array2String(array, start, end) { + if (typeof end == "undefined") end = array.length; + if (typeof start == "undefined") start = 0; + var string = ""; + for (var i = start; i < end; i++) + string += String.fromCharCode(array[i]); + return string; +} + +function SAEF_String2Array(string, start, end) { + if (typeof end == "undefined") end = string.length; + if (typeof start == "undefined") start = 0; + var array = new Uint8Array(end - start); + for (var i = start; i < end; i++) + array[i - start] = string.charCodeAt(i); + return array; +} + +/*function SAEF_CopyArray(dst_array, src_array, src_end) { + if (typeof src_end == "undefined") src_end = src_array.length; + for (var i = 0; i < src_end; i++) { + if (typeof dst_array[i] === 'undefined' || typeof src_array[i] === 'undefined') + return 1; + dst_array[i] = src_array[i]; + } + return 0; +}*/ + +function SAEF_CompareArray(array1, array2, end2) { + if (typeof end2 == "undefined") end2 = array2.length; + for (var i = 0; i < end2; i++) { + if (typeof array1[i] === 'undefined' || typeof array2[i] === 'undefined') + return 1; + if (array1[i] != array2[i]) + return 1; + } + return 0; +} +function SAEF_CompareArrayAfter(array1, start1, array2, end2) { + if (typeof end2 == "undefined") end2 = array2.length; + for (var i = 0; i < end2; i++) { + if (typeof array1[start1 + i] === 'undefined' || typeof array2[i] === 'undefined') + return 1; + if (array1[start1 + i] != array2[i]) + return 1; + } + return 0; +} + +/*-----------------------------------------------------------------------*/ +/* Javascript sprintf - http://www.webtoolkit.info + This is the only function that does not correspond to the global name space */ - -sprintfWrapper = { +var sprintfWrapper = { init: function () { if (typeof arguments == "undefined") { return null; @@ -113,7 +272,7 @@ sprintfWrapper = { var stringPosStart = 0; var stringPosEnd = 0; var matchPosEnd = 0; - var newString = ''; + var newString = ""; var match; while (match = exp.exec(string)) { @@ -129,11 +288,11 @@ sprintfWrapper = { matches[matches.length] = { match: match[0], left: match[3] ? true : false, - sign: match[4] || '', - pad: match[5] || ' ', + sign: match[4] || "", + pad: match[5] || " ", min: match[6] || 0, precision: match[8], - code: match[9] || '%', + code: match[9] || "%", negative: !!(parseInt(arguments[convCount]) < 0), argument: String(arguments[convCount]) }; @@ -150,30 +309,30 @@ sprintfWrapper = { for (var i = 0; i < matches.length; i++) { var substitution; - if (matches[i].code == '%') { - substitution = '%' - } else if (matches[i].code == 'b') { + if (matches[i].code == "%") { + substitution = "%" + } else if (matches[i].code == "b") { matches[i].argument = String(Math.abs(parseInt(matches[i].argument)).toString(2)); substitution = sprintfWrapper.convert(matches[i], true); - } else if (matches[i].code == 'c') { + } else if (matches[i].code == "c") { matches[i].argument = String(String.fromCharCode(parseInt(Math.abs(parseInt(matches[i].argument))))); substitution = sprintfWrapper.convert(matches[i], true); - } else if (matches[i].code == 'd') { + } else if (matches[i].code == "d") { matches[i].argument = String(Math.abs(parseInt(matches[i].argument))); substitution = sprintfWrapper.convert(matches[i]); - } else if (matches[i].code == 'f') { + } else if (matches[i].code == "f") { matches[i].argument = String(Math.abs(parseFloat(matches[i].argument)).toFixed(matches[i].precision ? matches[i].precision : 6)); substitution = sprintfWrapper.convert(matches[i]); - } else if (matches[i].code == 'o') { + } else if (matches[i].code == "o") { matches[i].argument = String(Math.abs(parseInt(matches[i].argument)).toString(8)); substitution = sprintfWrapper.convert(matches[i]); - } else if (matches[i].code == 's') { + } else if (matches[i].code == "s") { matches[i].argument = matches[i].argument.substring(0, matches[i].precision ? matches[i].precision : matches[i].argument.length); substitution = sprintfWrapper.convert(matches[i], true); - } else if (matches[i].code == 'x') { + } else if (matches[i].code == "x") { matches[i].argument = String(Math.abs(parseInt(matches[i].argument)).toString(16)); substitution = sprintfWrapper.convert(matches[i]); - } else if (matches[i].code == 'X') { + } else if (matches[i].code == "X") { matches[i].argument = String(Math.abs(parseInt(matches[i].argument)).toString(16)); substitution = sprintfWrapper.convert(matches[i]).toUpperCase(); } else { @@ -186,14 +345,12 @@ sprintfWrapper = { newString += strings[i]; return newString; - }, - convert: function (match, nosign) { if (nosign) { - match.sign = ''; + match.sign = ""; } else { - match.sign = match.negative ? '-' : match.sign; + match.sign = match.negative ? "-" : match.sign; } var l = match.min - match.argument.length + 1 - match.sign.length; var pad = new Array(l < 0 ? 0 : l).join(match.pad); @@ -205,274 +362,784 @@ sprintfWrapper = { } } else { if (match.pad == "0" || nosign) { - return match.sign + match.argument + pad.replace(/0/g, ' '); + return match.sign + match.argument + pad.replace(/0/g, " "); } else { return match.sign + match.argument + pad; } } } }; - -sprintf = sprintfWrapper.init; +var sprintf = sprintfWrapper.init; /*-----------------------------------------------------------------------*/ -/* - * http://www.quirksmode.org/js/detect.html - */ +/* Z wrapper */ -var BrowserDetect = { - init: function () { - this.browser = this.searchString(this.dataBrowser) || 'An unknown browser'; - this.version = this.searchVersion(navigator.userAgent) || this.searchVersion(navigator.appVersion) || 'an unknown version'; - this.OS = this.searchString(this.dataOS) || 'an unknown OS'; - }, - searchString: function (data) { - for (var i = 0; i < data.length; i++) { - var dataString = data[i].string; - var dataProp = data[i].prop; - this.versionSearchString = data[i].versionSearch || data[i].identity; - if (dataString) { - if (dataString.indexOf(data[i].subString) != -1) return data[i].identity; - } else if (dataProp) return data[i].identity; +const SEEK_SET = 0; /* set file offset to offset */ +const SEEK_CUR = 1; /* set file offset to current plus offset */ +const SEEK_END = 2; /* set file offset to EOF plus offset */ + +/*struct zfile { + TCHAR *name; + TCHAR *originalname; + uae_u8 *data; // unpacked data + int dataseek; // use seek position even if real file + + uae_s64 size; // real size + uae_s64 datasize; // available size (not yet unpacked completely?) + uae_s64 allocsize; // memory allocated before realloc() needed again + uae_s64 seek; // seek position + + int opencnt; +};*/ +function SAEO_ZFile() { + this.name = ""; + this.originalname = ""; + this.data = null; // unpacked data + this.dataseek = 0; // use seek position even if real file + + this.size = 0; // real size + this.datasize = 0; // available size (not yet unpacked completely?) + this.allocsize = 0; // memory allocated before realloc() needed again + this.seek = 0; // seek position + + this.opencnt = 0; +} + +/*---------------------------------*/ + +function SAEF_ZFile_create(prev, originalname) { + var z = new SAEO_ZFile(); + z.opencnt = 1; + + if (prev !== null && prev.originalname) + z.originalname = prev.originalname; + else if (originalname.length) + z.originalname = originalname; + + return z; +} + +function SAEF_ZFile_free(f) { + f.name = ""; + f.originalname = ""; + f.data = null; +} + +/*---------------------------------*/ + +function SAEF_ZFile_fopen_empty(prev, name, size) { + var l = SAEF_ZFile_create(prev, ""); + l.name = name.length ? name : ""; + if (size) { + l.data = new Uint8Array(size); + /*if (!l.data) { + xfree(l); + return null; + }*/ + l.size = size; + l.datasize = size; + l.allocsize = size; + } else { + l.data = new Uint8Array(1000); + l.size = 0; + l.allocsize = 1000; + } + return l; +} + +function SAEF_ZFile_fopen_load_zfile(f) { + var l = SAEF_ZFile_fopen_empty(f, f.name, f.size); + if (l === null) + return null; + SAEF_ZFile_fseek(f, 0, SEEK_SET); + SAEF_ZFile_fread(l.data,0, f.size, 1, f); + return l; +} + +/*function SAEF_ZFile_fopen_data(name, size, data) { + if (size) { + var l = SAEF_ZFile_create(null, name); + l.name = name.length ? name : ""; + if (1) { // ptr + l.data = data; + } else { + l.data = new Uint8Array(size); + l.data.set(data); //memcpy(l.data, data, size); } - return ''; - }, - searchVersion: function (dataString) { - var index = dataString.indexOf(this.versionSearchString); - if (index == -1) return 0.0; - return parseFloat(dataString.substring(index + this.versionSearchString.length + 1)); - }, - dataBrowser: [{ - string: navigator.userAgent, - subString: 'Chrome', - identity: 'Chrome' - }, { - string: navigator.userAgent, - subString: 'OmniWeb', - versionSearch: 'OmniWeb/', - identity: 'OmniWeb' - }, { - string: navigator.vendor, - subString: 'Apple', - identity: 'Safari', - versionSearch: 'Version' - }, { - prop: window.opera, - identity: 'Opera', - versionSearch: 'Version' - }, { - string: navigator.vendor, - subString: 'iCab', - identity: 'iCab' - }, { - string: navigator.vendor, - subString: 'KDE', - identity: 'Konqueror' - }, { - string: navigator.userAgent, - subString: 'Firefox', - identity: 'Firefox' - }, { - string: navigator.vendor, - subString: 'Camino', - identity: 'Camino' - }, { // for newer Netscapes (6+) - string: navigator.userAgent, - subString: 'Netscape', - identity: 'Netscape' - }, { - string: navigator.userAgent, - subString: 'MSIE', - identity: 'Explorer', - versionSearch: 'MSIE' - }, { - string: navigator.userAgent, - subString: 'Gecko', - identity: 'Mozilla', - versionSearch: 'rv' - }, { // for older Netscapes (4-) - string: navigator.userAgent, - subString: 'Mozilla', - identity: 'Netscape', - versionSearch: 'Mozilla' - }], - dataOS: [{ - string: navigator.platform, - subString: 'Win', - identity: 'Windows' - }, { - string: navigator.platform, - subString: 'Mac', - identity: 'Mac' - }, { - string: navigator.userAgent, - subString: 'iPhone', - identity: 'iPhone/iPod' - }, { - string: navigator.platform, - subString: 'Linux', - identity: 'Linux' - }] - -}; -BrowserDetect.init(); - -/*-----------------------------------------------------------------------*/ - -/*function dump(obj) { - var out = ''; - if (obj) { - for (var i in obj) { - out += i + ': ' + obj[i] + '\n'; - } - } else - out = 'undefined'; - - alert(out); + l.size = size; + l.datasize = size; + l.allocsize = size; //OWN + return l; + } + return null; }*/ -/*-----------------------------------------------------------------------*/ +function SAEF_ZFile_fopen_file(file) { + if (file.size) { + var l = SAEF_ZFile_create(null, file.name); + l.name = file.name.length ? file.name : ""; -function VSync(err, msg) { - this.error = err; - this.message = msg; -} -VSync.prototype = new Error; + if (0) { /* ptr-mode. do not enable */ + l.data = file.data; + } else { + l.data = new Uint8Array(file.size); + //memcpy(l.data, data, size); + if (typeof file.data === "string") + l.data.set(SAEF_String2Array(file.data, 0, file.size)); + else + l.data.set(file.data); + } + l.size = file.size; + l.datasize = file.size; + l.allocsize = file.size; //OWN -function FatalError(err, msg) { - this.error = err; - this.message = msg; -} -FatalError.prototype = new Error; - -function Fatal(err, msg) { - //alert(str); - throw new FatalError(err, msg); + //if (l.data[0] == 68 && l.data[1] == 77 && l.data[2] == 83 && l.data[3] == 33) { /* DMS! */ + if (SAEF_CompareArray(l.data, SAEF_String2Array("DMS!"), 4) == 0) { + var dms = new SAEO_DMS(); + var f = dms.DMS2ADF(l); + if (f !== null) { + var data = SAEF_ZFile_getdata(f, 0, -1); + file.name = SAEF_ZFile_getname(f); + file.data = SAEF_Array2String(data); + file.size = SAEF_ZFile_size(f); + file.prot = false; + return f; + } + } + else if (SAEF_CompareArray(l.data, [0x00,0x00,0x03,0xf3,0x00,0x00,0x00,0x00], 8) == 0) { + var f = SAER.disk.EXE2ADF(l); + if (f !== null) { + var data = SAEF_ZFile_getdata(f, 0, -1); + file.name = SAEF_ZFile_getname(f); + file.data = SAEF_Array2String(data); + file.size = SAEF_ZFile_size(f); + file.prot = false; + return f; + } + } + return l; + } + return null; } -/*function SafeFatal(str) { - alert(str); - console.log(str); - //API_stop(); - API({cmd:'stop'}); +function SAEF_ZFile_fclose(f) { + if (!f) + return; + if (f.opencnt < 0) { + SAEF_warn("SAEF_ZFile_fclose() tried to free already closed filehandle!"); + return; + } + f.opencnt--; + if (f.opencnt > 0) + return; + f.opencnt = -100; + + SAEF_ZFile_free(f); +} + +/*---------------------------------*/ + +function SAEF_ZFile_iscompressed(z) { + return false; //z.data !== null ? 1 : 0; //ATT +} + +/*---------------------------------*/ + +/*function SAEF_ZFile_truncate(z, size) { + if (size < z.size) { + z.size = size; + if (z.size < z.datasize) + z.datasize = z.size; + if (z.size < z.seek) + z.seek = z.size; + return 1; + } + return 0; }*/ -/*-----------------------------------------------------------------------*/ +function SAEF_ZFile_resize(z, newsize) { //OWN + if (newsize > z.allocsize) { + z.allocsize = newsize; -/*function loadLocal(id, callback) { - var e = document.getElementById(id).files[0]; - var reader = new FileReader(); - reader.onload = callback; - reader.readAsBinaryString(e); + SAEF_log("SAEF_ZFile_resize() increase %d -> %d bytes", z.size, z.allocsize); + + var tmp = new Uint8Array(z.allocsize); + tmp.set(z.data); + z.data = tmp; + z.datasize = z.size = newsize; + return 1; + } + if (newsize < z.allocsize) { + z.allocsize = newsize; + + SAEF_log("SAEF_ZFile_resize() decrease %d -> %d bytes", z.size, z.allocsize); + + var tmp = new Uint8Array(z.allocsize); + tmp.set(z.data.subarray(0, z.allocsize)); + z.data = tmp; + z.datasize = z.size = newsize; + return 1; + } + return 0; } -function loadRemote(file, crc, callback) { - //var url = 'http://'+window.location.hostname+'/'+file; - var url = file; +function SAEF_ZFile_size(z) { + return z.size; +} - var req = new XMLHttpRequest(); - req.open('GET', url, true); - req.overrideMimeType('text\/plain; charset=x-user-defined'); - req.onreadystatechange = function(e) { - if (req.readyState == 4) { - if (req.status == 200) { - var newcrc = crc32(req.responseText, 0); - BUG.info('loadRemote() %s (length %d, crc32 $%08x)', file, req.responseText.length, newcrc); - if (newcrc == crc) - callback(req.responseText); - else - SafeFatal('Wrong checksum for file '+file); - } else - SafeFatal('Can\'t download file '+file+' (http status: '+req.status+')'); +/*---------------------------------*/ + +function SAEF_ZFile_ftell(z) { + return z.seek; +} + +function SAEF_ZFile_fseek(z, offset, mode) { + var ret = 0; + switch (mode) { + case SEEK_SET: + z.seek = offset; + break; + case SEEK_CUR: + z.seek += offset; + break; + case SEEK_END: + z.seek = z.size + offset; + break; + } + if (z.seek < 0) { + z.seek = 0; + ret = 1; + } + if (z.seek > z.size) { + z.seek = z.size; + ret = 1; + } + return ret; +} + +/*---------------------------------*/ + +/*function SAEF_ZFile_fread(b,bo, l1, l2, z) { + var l = l1 * l2; + if (z.datasize < z.size && z.seek + l > z.datasize) { + SAEF_warn("SAEF_ZFile_fread() read beyond size"); + return 0; + } + if (z.seek + l > z.size) { + l2 = l1 ? Math.truncate((z.size - z.seek) / l1) : 0; + if (l2 < 0) l2 = 0; + l = l1 * l2; + } + //memcpy(b, z.data + z.seek, l1 * l2); + if (typeof b === "string") { + SAEF_warn("SAEF_ZFile_fread() string"); + return 0; + } else { + var o = z.seek; + if (typeof z.data === "string") { + while (l-- > 0) + b[bo++] = z.data.charCodeAt(o++); + } else { + while (l-- > 0) + b[bo++] = z.data[o++]; } } - req.send(null); + z.seek += l1 * l2; + return l2; +} + +function SAEF_ZFile_fwrite(b,bo, l1, l2, z) { + var off = z.seek + l1 * l2; + if (z.allocsize == 0) { + SAEF_warn("SAEF_ZFile_fwrite() allocsize == 0, aborting..."); + return 0; + } + if (off > z.allocsize) { + //if (z.allocsize < off) + z.allocsize = off; + z.allocsize += Math.floor(z.size / 2); + if (z.allocsize < 10000) + z.allocsize = 10000; + + SAEF_log("SAEF_ZFile_fwrite() relocate %d -> %d bytes", z.size, z.allocsize); + var tmp = new Uint8Array(z.allocsize); + tmp.cpy(z.data, z.size); + z.data = tmp; + z.datasize = z.size = off; + } + //memcpy(z.data + z.seek, b, l1 * l2); + if (typeof b === "string") { + SAEF_warn("SAEF_ZFile_fwrite() string"); + return 0; + } else { + var l = l1 * l2; + if (typeof z.data === "string") { + var txt = "", len = l; + while (l-- > 0) txt += String.fromCharCode(b[bo++]); + var tmp = z.data.substr(0, z.seek) + txt + z.data.substr(z.seek + len); + z.data = tmp; + } else { + var o = z.seek; + while (l-- > 0) + z.data[o++] = b[bo++]; + } + } + z.seek += l1 * l2; + if (z.seek > z.size) + z.size = z.seek; + if (z.size > z.datasize) + z.datasize = z.size; + return l2; }*/ +function SAEF_ZFile_fread(b,bo, l1, l2, z) { + if (z.datasize < z.size && z.seek + l1 * l2 > z.datasize) { + SAEF_warn("SAEF_ZFile_fread() read beyond size"); + return 0; + } + if (z.seek + l1 * l2 > z.size) { + l2 = l1 ? Math.truncate((z.size - z.seek) / l1) : 0; + if (l2 < 0) l2 = 0; + } + b.set(z.data.subarray(z.seek, z.seek + l1 * l2), bo); //memcpy (b, z.data + z.offset + z.seek, l1 * l2); + z.seek += l1 * l2; + return l2; +} + +function SAEF_ZFile_fwrite(b,bo, l1, l2, z) { + var off = z.seek + l1 * l2; //s64 + if (z.allocsize == 0) { + SAEF_warn("SAEF_ZFile_fwrite() allocsize == 0, aborting..."); + return 0; + } + if (off > z.allocsize) { + if (z.allocsize < off) + z.allocsize = off; + z.allocsize += (z.size >> 1); + if (z.allocsize < 10000) + z.allocsize = 10000; + + //z.data = xrealloc (uae_u8, z.data, z.allocsize); + + SAEF_log("SAEF_ZFile_fwrite() relocate %d -> %d bytes", z.size, z.allocsize); + var tmp = new Uint8Array(z.allocsize); + tmp.set(z.data); + z.data = tmp; + + z.datasize = z.size = off; + } + + z.data.set(b.subarray(bo, bo + l1 * l2), z.seek); //memcpy (z.data + z.seek, b, l1 * l2); + + z.seek += l1 * l2; + if (z.seek > z.size) + z.size = z.seek; + if (z.size > z.datasize) + z.datasize = z.size; + return l2; +} + +/*---------------------------------*/ + +/*function SAEF_ZFile_ferror(z) { + return 0; +}*/ + +function SAEF_ZFile_getdata(z, offset, len) { + var pos = SAEF_ZFile_ftell(z); + if (len < 0) { + SAEF_ZFile_fseek(z, 0, SEEK_END); + len = SAEF_ZFile_ftell(z); + SAEF_ZFile_fseek(z, 0, SEEK_SET); + } + var b = new Uint8Array(len); + SAEF_ZFile_fseek(z, offset, SEEK_SET); + SAEF_ZFile_fread(b,0, len, 1, z); + SAEF_ZFile_fseek(z, pos, SEEK_SET); + return b; +} + +function SAEF_ZFile_getname(f) { + return f ? f.name : null; +} + +function SAEF_ZFile_getoriginalname(f) { + return f ? f.originalname : null; +} + +function SAEF_ZFile_getfilename(f) { + /*if (!f.name.length) + return null; + for (var i = f.name.length - 1; i >= 0; i--) { + if (f.name[i] == '\\' || f.name[i] == '/' || f.name[i] == ':') { + i++; + return &f.name[i]; + } + }*/ + return f.name; +} + +/*---------------------------------*/ + +function SAEF_ZFile_crc32(f) { + if (f === null) + return 0; + //if (f.dataBuffer) + return SAEF_crc32(f.data,0, f.size); + + /*var pos = SAEF_ZFile_ftell (f); + SAEF_ZFile_fseek (f, 0, SEEK_END); + var size = SAEF_ZFile_ftell (f); + var p = xmalloc (uae_u8, size); + if (!p) + return 0; + memset (p, 0, size); + SAEF_ZFile_fseek (f, 0, SEEK_SET); + SAEF_ZFile_fread (p, 1, size, f); + SAEF_ZFile_fseek (f, pos, SEEK_SET); + var crc = p.crc32(size); + xfree (p); + return crc;*/ +} + /*-----------------------------------------------------------------------*/ +/*-----------------------------------------------------------------------*/ +/*-----------------------------------------------------------------------*/ +/* some testing stuff */ -function Debug() { - //this.col = 1; - this.on = 1; +function CreateEvent(lpEventAttributes, bManualReset, bInitialState, lpName) { + var hEvent = new uae_sem_t(); + hEvent.manual = bManualReset != 0; + hEvent.signaled = bInitialState != 0; + return hEvent; +} - this.say = function (str) { - if (this.on) { - /*var e = document.createElement('span'); - e.style.color = this.col == 1 ? '#888' : (this.col == 2 ? '#448' : '#484'); - e.innerHTML = buf; - this.debug.appendChild(e); - this.debug.appendChild(document.createElement('br')); - this.debug.scrollTop = this.debug.scrollHeight;*/ +function SetEvent(hEvent) { + hEvent.signaled = true; + return true; +} - console.log(str); - /*console.info(str); - console.warn(str); - console.error(str); - console.assert(str);*/ +function ResetEvent(hEvent) { + hEvent.signaled = false; + return true; +} + +const INFINITE = 0xFFFFFFFF; +const WAIT_ABANDONED = 0x00000080; +const WAIT_OBJECT_0 = 0x00000000; +const WAIT_TIMEOUT = 0x00000102; +const WAIT_FAILED = 0xFFFFFFFF; + +function WaitForSingleObject(hEvent, dwMilliseconds) { + if (!hEvent.signaled) { + if (dwMilliseconds == INFINITE) { + var cnt = 0; + while (!hEvent.signaled && cnt++ < 200) + SAEF_sleep(5); } - }; - - this.info = function () { - if (this.on) { - var str = sprintf.apply(this, arguments); - console.log(str); + else if (dwMilliseconds > 0) + SAEF_sleep(dwMilliseconds); + } + if (hEvent.signaled) { + if (!hEvent.manual) //&& waiting > 0 + ResetEvent(hEvent); + + return WAIT_OBJECT_0; + } + return WAIT_TIMEOUT; +} + +/*---------------------------------*/ + +function uae_sem_init(event, manual_reset, initial_state) { + if (event.handle) { + if (initial_state) + SetEvent(event.handle); + else + ResetEvent(event.handle); + } else + event.handle = CreateEvent(null, manual_reset, initial_state, null); +} + +function uae_sem_wait(event) { + WaitForSingleObject(event.handle, INFINITE); +} + +function uae_sem_post(event) { + SetEvent(event.handle); +} + +/*function uae_sem_trywait(event) { + return WaitForSingleObject(event.handle, 0) == WAIT_OBJECT_0 ? 0 : -1; +}*/ + +/*function uae_sem_destroy(event) { + if (event.handle) { + //CloseHandle(event); + event.handle = null; + } +}*/ + +/*---------------------------------*/ + +//typedef HANDLE uae_sem_t; +//typedef HANDLE uae_thread_id; +function uae_sem_t() { + this.value = null; + this.manual = false; + this.signaled = false; +} + +/*typedef union { + int i; + uae_u32 u32; + void *pv; +} uae_pt;*/ + +function smp_comm_pipe() { + //this.lock = new uae_sem_t(); + //this.reader_wait = new uae_sem_t(); + //this.writer_wait = new uae_sem_t(); + this.lock = { handle:null }; + this.reader_wait = { handle:null }; + this.writer_wait = { handle:null }; + this.data = null; //uae_pt * + this.dataView = null; //OWN + this.size = 0; + this.chunks = 0; + this.rdp = 0; //volatile + this.wrp = 0; //volatile + this.reader_waiting = 0; //volatile + this.writer_waiting = 0; //volatile +} + +function init_comm_pipe(p, size, chunks) { + //p.data = (uae_pt *)malloc (size*sizeof (uae_pt)); + p.lock = { handle:null }; + p.reader_wait = { handle:null }; + p.writer_wait = { handle:null }; + p.data = new ArrayBuffer(size * 4); + p.dataView = new DataView(p.data); + p.size = size; + p.chunks = chunks; + p.rdp = p.wrp = 0; + p.reader_waiting = 0; + p.writer_waiting = 0; + uae_sem_init(p.lock, 0, 1); + uae_sem_init(p.reader_wait, 0, 0); + uae_sem_init(p.writer_wait, 0, 0); +} + +/*function destroy_comm_pipe(p) { + uae_sem_destroy(p.lock); + uae_sem_destroy(p.reader_wait); + uae_sem_destroy(p.writer_wait); +}*/ + +/*function comm_pipe_has_data(p) { + return p.rdp != p.wrp; +}*/ + +function read_comm_pipe_pt_blocking(p, type) { + var data; + + uae_sem_wait(p.lock); + if (p.rdp == p.wrp) { + /* Pipe empty */ + p.reader_waiting = 1; + uae_sem_post(p.lock); + uae_sem_wait(p.reader_wait); + uae_sem_wait(p.lock); + } + switch (type) { + case 1: data = p.dataView.getInt32(p.rdp << 2, false); break; + case 2: + case 3: data = p.dataView.getUint32(p.rdp << 2, false); break; + } + p.rdp = (p.rdp + 1) % p.size; + + /* We ignore chunks here. If this is a problem, make the size bigger in the init call. */ + if (p.writer_waiting) { + p.writer_waiting = 0; + uae_sem_post(p.writer_wait); + } + uae_sem_post(p.lock); + return data; +} +function read_comm_pipe_int_blocking(p) { + //var foo = read_comm_pipe_pt_blocking(p); return foo.i; + return read_comm_pipe_pt_blocking(p, 1); +} +function read_comm_pipe_u32_blocking(p) { + //var foo = read_comm_pipe_pt_blocking(p); return foo.u32; + return read_comm_pipe_pt_blocking(p, 2); +} +function read_comm_pipe_pvoid_blocking(p) { + //var foo = read_comm_pipe_pt_blocking(p); return foo.pv; + return read_comm_pipe_pt_blocking(p, 3); +} + +function maybe_wake_reader(p, no_buffer) { + if (p.reader_waiting && (no_buffer || ((p.wrp - p.rdp + p.size) % p.size) >= p.chunks)) { + p.reader_waiting = 0; + uae_sem_post(p.reader_wait); + } +} +function write_comm_pipe_pt(p, type, data, no_buffer) { + var nxwrp = (p.wrp + 1) % p.size; + + if (p.reader_waiting) { + /* No need to do all the locking */ + switch (type) { + case 1: p.dataView.setInt32(p.wrp << 2, data, SAEC_LITTLE_ENDIAN); break; + case 2: + case 3: p.dataView.setUint32(p.wrp << 2, data, SAEC_LITTLE_ENDIAN); break; } - } + p.wrp = nxwrp; + maybe_wake_reader(p, no_buffer); + return; + } + uae_sem_wait(p.lock); + if (nxwrp == p.rdp) { + /* Pipe full */ + p.writer_waiting = 1; + uae_sem_post(p.lock); + uae_sem_wait(p.writer_wait); + uae_sem_wait(p.lock); + } + switch (type) { + case 1: p.dataView.setInt32(p.wrp << 2, data, SAEC_LITTLE_ENDIAN); break; + case 2: + case 3: p.dataView.setUint32(p.wrp << 2, data, SAEC_LITTLE_ENDIAN); break; + } + p.wrp = nxwrp; + maybe_wake_reader(p, no_buffer); + uae_sem_post(p.lock); +} +function write_comm_pipe_int(p, data, no_buffer) { + //var foo; foo.i = data; write_comm_pipe_pt(p, foo, no_buffer); + write_comm_pipe_pt(p, 1, data, no_buffer); +} +function write_comm_pipe_u32(p, data, no_buffer) { + //var foo; foo.u32 = data; write_comm_pipe_pt(p, foo, no_buffer); + write_comm_pipe_pt(p, 2, data, no_buffer); +} +function write_comm_pipe_pvoid (p, data, no_buffer) { + //var foo; foo.pv = data; write_comm_pipe_pt(p, foo, no_buffer); + write_comm_pipe_pt(p, 3, data, no_buffer); } /*-----------------------------------------------------------------------*/ -/*function Uint64(hi, lo) { - this.hi = hi; - this.lo = lo; +//extern HANDLE AVTask; - this.or = function (v) { - this.hi = (this.hi | v.hi) >>> 0; - this.lo = (this.lo | v.lo) >>> 0; - }; +//typedef unsigned (__stdcall *BEGINTHREADEX_FUNCPTR)(void *); - this.lshift = function (n) { - if (n) { - if (n < 32) { - var m = Math.pow(2, n) - 1; - var t = this.lo & m; - this.hi = ((this.hi << n) | t) >>> 0; - this.lo = (this.lo << n) >>> 0; +/*struct thparms { + void *(*f)(void*); + void *arg; +}; - //BUG.info('lshift %d %x', n, m, t); +static unsigned __stdcall thread_init (void *f) { + struct thparms *thp = (struct thparms*)f; + void *(*fp)(void*) = thp->f; + void *arg = thp->arg; + + xfree (f); + + __try { + fp (arg); + } __except (WIN32_ExceptionFilter (GetExceptionInformation (), GetExceptionCode ())) {} + + return 0; +} + +void uae_end_thread (uae_thread_id *tid) { + if (tid) { + CloseHandle (*tid); + *tid = NULL; + } +} + +STATIC_INLINE void uae_wait_thread (uae_thread_id tid) +{ + WaitForSingleObject (tid, INFINITE); + CloseHandle (tid); +} + +int uae_start_thread (const TCHAR *name, void *(*f)(void *), void *arg, uae_thread_id *tid) { + HANDLE hThread; + int result = 1; + unsigned foo; + struct thparms *thp; + + thp = xmalloc (struct thparms, 1); + thp->f = f; + thp->arg = arg; + hThread = (HANDLE)_beginthreadex (NULL, 0, thread_init, thp, 0, &foo); + if (hThread) { + if (name) { + //write_log (_T("Thread '%s' started (%d)\n"), name, hThread); + if (!AVTask) { + SetThreadPriority (hThread, THREAD_PRIORITY_HIGHEST); } else { - var t = this.lo; - this.hi = (t << (n - 32)) >>> 0; - this.lo = 0; - - //BUG.info('lshift %d %x', n, t); + AvSetMmThreadPriority(AVTask, AVRT_PRIORITY_HIGH); } } - }; - - this.rshift = function (n) { - if (n) { - if (n < 32) { - var m = Math.pow(2, n) - 1; - var t = this.hi & m; - this.hi = (this.hi >>> n) >>> 0; - this.lo = ((t << (32 - n)) | (this.lo >>> n)) >>> 0; - - //BUG.info('rshift %d %x %x', n, m, t); - } else { - var t = this.hi; - this.hi = 0; - this.lo = (t >>> (n - 32)) >>> 0; - - //BUG.info('rshift %d %x %x', n, t); - } - } - }; - - this.print = function() { - BUG.info('$%08x%08x', this.hi, this.lo); - } + } else { + result = 0; + write_log (_T("Thread '%s' failed to start!?\n"), name ? name : _T("")); + } + if (tid) + *tid = hThread; + else + CloseHandle (hThread); + return result; }*/ +/*int uae_start_thread_fast (void *(*f)(void *), void *arg, uae_thread_id *tid) { + int v = uae_start_thread (NULL, f, arg, tid); + if (*tid) { + if (!AVTask) { + SetThreadPriority (*tid, THREAD_PRIORITY_HIGHEST); + } else { + AvSetMmThreadPriority(AVTask, AVRT_PRIORITY_HIGH); + } + } + return v; +}*/ +/*DWORD_PTR cpu_affinity = 1, cpu_paffinity = 1; +void uae_set_thread_priority (uae_thread_id *tid, int pri) { + #if 0 + int pri2; + HANDLE th; + + if (tid) + th = *tid; + else + th = GetCurrentThread (); + pri2 = GetThreadPriority (th); + if (pri2 == THREAD_PRIORITY_ERROR_RETURN) + pri2 = 0; + if (pri > 0) + pri2 = THREAD_PRIORITY_HIGHEST; + else + pri2 = THREAD_PRIORITY_ABOVE_NORMAL; + pri2 += pri; + if (pri2 > 1) + pri2 = 1; + if (pri2 < -1) + pri2 = -1; + SetThreadPriority (th, pri2); + #endif + if (!AVTask) { + if (!SetThreadPriority (GetCurrentThread(), THREAD_PRIORITY_HIGHEST)) + SetThreadPriority (GetCurrentThread(), THREAD_PRIORITY_ABOVE_NORMAL); + } else { + AvSetMmThreadPriority(AVTask, AVRT_PRIORITY_HIGH); + } +}*/ + +/*-----------------------------------------------------------------------*/ diff --git a/sae/video.js b/sae/video.js index 47cc432..163d363 100644 --- a/sae/video.js +++ b/sae/video.js @@ -1,86 +1,123 @@ -/************************************************************************** -* SAE - Scripted Amiga Emulator -* -* 2012-2015 Rupert Hausberger -* -* https://github.com/naTmeg/ScriptedAmigaEmulator -* -**************************************************************************/ +/*------------------------------------------------------------------------- +| SAE - Scripted Amiga Emulator +| https://github.com/naTmeg/ScriptedAmigaEmulator +| +| Copyright (C) 2012-2016 Rupert Hausberger +| +| This program is free software; you can redistribute it and/or +| modify it under the terms of the GNU General Public License +| as published by the Free Software Foundation; either version 2 +| of the License, or (at your option) any later version. +| +| This program is distributed in the hope that it will be useful, +| but WITHOUT ANY WARRANTY; without even the implied warranty of +| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +| GNU General Public License for more details. +| +| Note: ported from WinUAE 3.2.x +-------------------------------------------------------------------------*/ +/* global constants */ -function Vide0() { - const vertexShader = - 'attribute vec2 a_position;'+ - 'attribute vec2 a_texCoord;'+ - 'uniform vec2 u_resolution;'+ - 'varying vec2 v_texCoord;'+ - 'void main() {'+ - 'vec2 zeroToOne = a_position / u_resolution;'+ - 'vec2 zeroToTwo = zeroToOne * 2.0;'+ - 'vec2 clipSpace = zeroToTwo - 1.0;'+ - 'gl_Position = vec4(clipSpace * vec2(1, -1), 0, 1);'+ - 'v_texCoord = a_texCoord;'+ - '}'; - const fragmentShader = - 'precision mediump float;'+ - 'uniform sampler2D u_image;'+ - 'varying vec2 v_texCoord;'+ - 'void main() {'+ - 'gl_FragColor = texture2D(u_image, v_texCoord);'+ - '}'; - const glParams = { +const SAEC_Video_DEF_AMIGA_WIDTH = 360; //720 / 2; +const SAEC_Video_DEF_AMIGA_HEIGHT = 284; //568 / 2; +const SAEC_Video_MAX_AMIGA_WIDTH = 376; //752 / 2; //AMIGA_WIDTH_MAX +const SAEC_Video_MAX_AMIGA_HEIGHT = 288; //576 / 2; //AMIGA_HEIGHT_MAX + +const SAEC_Video_MIN_UAE_WIDTH = 160; +const SAEC_Video_MAX_UAE_WIDTH = 3072; //max_uae_width +const SAEC_Video_MIN_UAE_HEIGHT = 128; +const SAEC_Video_MAX_UAE_HEIGHT = 2048; //max_uae_height + +/*---------------------------------*/ + +function SAEO_Video() { + /*-----------------------------------------------------------------------*/ + /* SECT API */ + /*-----------------------------------------------------------------------*/ + + const vertexShader = + "attribute vec2 a_position;"+ + "attribute vec2 a_texCoord;"+ + "uniform vec2 u_resolution;"+ + "varying vec2 v_texCoord;"+ + "void main() {"+ + "vec2 zeroToOne = a_position / u_resolution;"+ + "vec2 zeroToTwo = zeroToOne * 2.0;"+ + "vec2 clipSpace = zeroToTwo - 1.0;"+ + "gl_Position = vec4(clipSpace * vec2(1, -1), 0, 1);"+ + "v_texCoord = a_texCoord;"+ + "}"; + const fragmentShader = + "precision mediump float;"+ + "uniform sampler2D u_image;"+ + "varying vec2 v_texCoord;"+ + "void main() {"+ + "gl_FragColor = texture2D(u_image, v_texCoord);"+ + "}"; + var glParams = { alpha: false, + depth: false, stencil: false, - antialias: false + antialias: false, + premultipliedAlpha: false, + preserveDrawingBuffer: true, + failIfMajorPerformanceCaveat: false }; - - this.available = 0; - - var width = 0; - var height = 0; - var size = 0; - var scale = false; - var pixels = null; - var div = null; - var canvas = null; - var ctx = null; - var imagedata = null; - var video = null; - var open = false; - - /*---------------------------------*/ + function Texture(width, height, pixbytes) { + this.width = width; + this.width_allocated = (width + 7) & ~7; + this.height = height; + this.height_allocated = height; + this.pixbytes = pixbytes; + this.rowbytes = this.width_allocated * this.pixbytes; + this.data = new ArrayBuffer(this.width_allocated * this.height_allocated * this.pixbytes); + } - //this.init = function() - { - var test = document.createElement('canvas'); - if (test && test.getContext) { - var test2 = test.getContext('2d'); - if (test2) { - this.available |= SAEI_Video_Canvas2D; - test2 = null; - } - } - test = document.createElement('canvas'); - if (test && test.getContext) { - test2 = test.getContext('experimental-webgl', glParams) || test.getContext('webgl', glParams); - if (test2) { - this.available |= SAEI_Video_WebGL; - test2 = null; - } - test = null; - } - //console.log(this.available); - } - - /*---------------------------------*/ + function Surface(width, height, pixbytes) { + this.width = width; + this.width_allocated = (width + 7) & ~7; + this.height = height; + this.height_allocated = height; + this.pixbytes = pixbytes; + this.rowbytes = this.width_allocated * this.pixbytes; + this.data = new ArrayBuffer(this.width_allocated * this.height_allocated * this.pixbytes); + this.imageData = null; + } + + function HWND() { + this.canvas = null; + this.ctx = null; + this.texture = null; + this.surface = null; + + this.div = null; + this.video = null; + this.shown = false; + this.fullscreen = false; + } + + function RECT() { + this.left = 0; + this.top = 0; + this.right = 0; + this.bottom = 0; + } + + var hAmigaWnd = null, hMainWnd = null; //, hHiddenWnd, hGUIWnd; //HWND + var amigawin_rect = new RECT(); + //var mainwin_rect = new RECT(); + //var amigawinclip_rect = new RECT(); + + /*-----------------------------------------------------------------------*/ function getShader(ctx, id) { var shader, source; - if (id == 'vertex') { + if (id == "vertex") { shader = ctx.createShader(ctx.VERTEX_SHADER); source = vertexShader; - } else if (id == 'fragment') { + } else if (id == "fragment") { shader = ctx.createShader(ctx.FRAGMENT_SHADER); source = fragmentShader; } @@ -88,25 +125,26 @@ function Vide0() { ctx.compileShader(shader); if (!ctx.getShaderParameter(shader, ctx.COMPILE_STATUS)) - Fatal(SAEE_Video_Shader_Error, ctx.getShaderInfoLog(shader)); + return SAEE_Video_ComphileShader; return shader; } - function initGL() { - var vertexShader = getShader(ctx, 'vertex'); - var fragmentShader = getShader(ctx, 'fragment'); + function setupWebGL(ctx, width, height) { + SAEF_log("video.setupWebGL() %dx%d", width, height); + var vertexShader = getShader(ctx, "vertex"); + if (vertexShader === SAEE_Video_ComphileShader) return SAEE_Video_ComphileShader; + var fragmentShader = getShader(ctx, "fragment"); + if (fragmentShader === SAEE_Video_ComphileShader) return SAEE_Video_ComphileShader; var program = ctx.createProgram(); ctx.attachShader(program, vertexShader); ctx.attachShader(program, fragmentShader); ctx.linkProgram(program); if (!ctx.getProgramParameter(program, ctx.LINK_STATUS)) - Fatal(SAEE_Video_Shader_Error, 'Can\'t initialise the shaders for WebGL.'); + return SAEE_Video_LinkShader; ctx.useProgram(program); - - var positionLocation = ctx.getAttribLocation(program, "a_position"); - var texCoordLocation = ctx.getAttribLocation(program, "a_texCoord"); + ctx.program = program; var texCoordBuffer = ctx.createBuffer(); ctx.bindBuffer(ctx.ARRAY_BUFFER, texCoordBuffer); @@ -116,12 +154,14 @@ function Vide0() { 0.0, 1.0, 0.0, 1.0, 1.0, 0.0, - 1.0, 1.0]), ctx.STATIC_DRAW); + 1.0, 1.0]), ctx.STATIC_DRAW + ); + var texCoordLocation = ctx.getAttribLocation(program, "a_texCoord"); ctx.enableVertexAttribArray(texCoordLocation); ctx.vertexAttribPointer(texCoordLocation, 2, ctx.FLOAT, false, 0, 0); - var texture = ctx.createTexture(); - ctx.bindTexture(ctx.TEXTURE_2D, texture); + var _texture = ctx.createTexture(); + ctx.bindTexture(ctx.TEXTURE_2D, _texture); ctx.texParameteri(ctx.TEXTURE_2D, ctx.TEXTURE_WRAP_S, ctx.CLAMP_TO_EDGE); ctx.texParameteri(ctx.TEXTURE_2D, ctx.TEXTURE_WRAP_T, ctx.CLAMP_TO_EDGE); ctx.texParameteri(ctx.TEXTURE_2D, ctx.TEXTURE_MIN_FILTER, ctx.NEAREST); @@ -132,168 +172,2548 @@ function Vide0() { var buffer = ctx.createBuffer(); ctx.bindBuffer(ctx.ARRAY_BUFFER, buffer); + var positionLocation = ctx.getAttribLocation(program, "a_position"); ctx.enableVertexAttribArray(positionLocation); ctx.vertexAttribPointer(positionLocation, 2, ctx.FLOAT, false, 0, 0); ctx.viewport(0, 0, width, height); + + ctx.colorMask(true, true, true, true); ctx.clearColor(0, 0, 0, 1); ctx.clear(ctx.COLOR_BUFFER_BIT); - ctx.colorMask(true, true, true, false); + + /*ctx.enable(ctx.BLEND); + if (glParams.alpha) + ctx.blendFunc(ctx.ONE, ctx.ONE_MINUS_SRC_ALPHA); + else { + ctx.colorMask(true, true, true, false); // disable rendering to alpha + ctx.blendFunc(ctx.SRC_ALPHA, ctx.ONE_MINUS_SRC_ALPHA); + }*/ + if (!glParams.alpha) + ctx.colorMask(true, true, true, false); // disable rendering to alpha + + return SAEE_None; } - - this.setup = function () { - if (!AMIGA.config.video.enabled) return; - if (open) this.cleanup(); - div = document.getElementById(AMIGA.config.video.id); - if (!div) - Fatal(SAEE_Video_ID_Not_Found, 'Video DIV-element not found. Check your code. (Malformed-DIV-name: ' + AMIGA.config.video.id + ')'); + function CreateWindow(left, top, width, height) { + var hWnd = new HWND(); - scale = (this.available & SAEI_Video_WebGL) ? AMIGA.config.video.scale : false; - width = VIDEO_WIDTH << (scale ? 1 : 0); - height = VIDEO_HEIGHT << (scale ? 1 : 0); - size = width * height; - //BUG.info('Video.init() %d x %d, %s mode', width, height, AMIGA.config.video.ntsc ? 'ntsc' : 'pal'); + hWnd.canvas = document.createElement("canvas"); + hWnd.canvas.width = width; + hWnd.canvas.height = height; + hWnd.canvas.style.backgroundColor = sprintf("#%06X", SAEV_config.video.backgroundColor); - if (this.available & SAEI_Video_Canvas2D) { - canvas = document.createElement('canvas'); - canvas.width = width; - canvas.height = height; - canvas.oncontextmenu = function () { - return false; + if (SAEV_config.video.api == SAEC_Config_Video_API_WebGL) { + try { + glParams.antialias = SAEV_config.video.antialias; + //glParams.alpha = glParams.premultipliedAlpha = SAEV_config.video.colorMode >= 5; + glParams.alpha = SAEV_config.video.colorMode >= 5; + + hWnd.ctx = hWnd.canvas.getContext("webgl", glParams) || hWnd.canvas.getContext("experimental-webgl", glParams); + //hWnd.texture = new Texture(width, height, SAEV_config.video.colorMode < 5 : 2 : 4); + } catch(e) { + throw SAEE_Video_RequiresWegGl; + } + } + else if (SAEV_config.video.api == SAEC_Config_Video_API_Canvas) { + try { + hWnd.ctx = hWnd.canvas.getContext("2d"); + //hWnd.surface = new Surface(width, height, 4); + //hWnd.surface.imageData = hWnd.ctx.createImageData(width, height); + } catch(e) { + throw SAEE_Video_RequiresCanvas; + } + } + SAEF_info("sae.video() %s mode, %dx%d pixels, %d bpp", + SAEV_config.video.api == SAEC_Config_Video_API_WebGL ? "WebGL" : "Canvas", + width, height, SAEV_config.video.colorMode == 2 ? 16 : 32 + ); + + hWnd.canvas.oncontextmenu = function() { + return false; + }; + if (SAEV_config.ports[0].type == SAEC_Config_Ports_Type_Mouse) { + hWnd.canvas.onmousedown = function(e) { + SAER.input.mouse.mousedown(e); }; - if (AMIGA.config.ports[0].type == SAEV_Config_Ports_Type_Mouse) { - canvas.onmousedown = function (e) { - AMIGA.input.mouse.mousedown(e); - }; - canvas.onmouseup = function (e) { - AMIGA.input.mouse.mouseup(e); - }; - canvas.onmouseover = function (e) { - AMIGA.input.mouse.mouseover(e); - }; - canvas.onmouseout = function (e) { - AMIGA.input.mouse.mouseout(e); - }; - canvas.onmousemove = function (e) { - AMIGA.input.mouse.mousemove(e); + hWnd.canvas.onmouseup = function(e) { + SAER.input.mouse.mouseup(e); + }; + hWnd.canvas.onmouseover = function(e) { + SAER.input.mouse.mouseover(e); + }; + hWnd.canvas.onmouseout = function(e) { + SAER.input.mouse.mouseout(e); + }; + hWnd.canvas.onmousemove = function(e) { + SAER.input.mouse.mousemove(e); + } + } + return hWnd; + } + + function DestroyWindow(hWnd) { + if (SAEV_config.video.api == SAEC_Config_Video_API_WebGL) + hWnd.texture = null; + else if (SAEV_config.video.api == SAEC_Config_Video_API_Canvas) + hWnd.surface = null; + + hWnd.canvas = null; + } + + const SW_HIDE = 0; + const SW_SHOWNORMAL = 1; + //const SW_SHOW = 5; + //const SW_SHOWDEFAULT = 10; + function ShowWindow(hWnd, nCmdShow) { + if (nCmdShow == SW_SHOWNORMAL && !hWnd.shown) { + hWnd.video = document.createElement("div"); + hWnd.video.style.webkitTouchCallout = "none"; + hWnd.video.style.webkitUserSelect = "none"; + hWnd.video.style.khtmlUserSelect = "none"; + hWnd.video.style.mozUserSelect = "none"; + hWnd.video.style.msUserSelect = "none"; + hWnd.video.style.userSelect = "none"; + hWnd.video.appendChild(hWnd.canvas); + + hWnd.div = document.getElementById(SAEV_config.video.id); + hWnd.div.style.width = String(currentmode.native_width)+"px"; + hWnd.div.style.height = String(currentmode.native_height)+"px"; + hWnd.div.appendChild(hWnd.video); + hWnd.shown = true; + } + else if (nCmdShow == SW_HIDE && hWnd.shown) { + hWnd.div.removeChild(hWnd.video); + //hWnd.div.style.width = "0px"; + //hWnd.div.style.height = "0px"; + hWnd.video = null; + hWnd.shown = false; + } + } + + function GetWindowRect(hWnd, rect) { + if (hWnd.shown) { + var bcr = hWnd.div.getBoundingClientRect(); + rect.left = Math.floor(bcr.left); + rect.top = Math.floor(bcr.top); + rect.right = Math.floor(bcr.right); + rect.bottom = Math.floor(bcr.bottom); + } else { + rect.left = (screen.width >> 1) - (currentmode.native_width >> 1); if (rect.left < 0) rect.left = 0; + rect.top = (screen.height >> 1) - (currentmode.native_height >> 1); if (rect.top < 0) rect.top = 0; + rect.right = rect.left + currentmode.native_width; + rect.bottom = rect.top + currentmode.native_height; + } + } + + /*-----------------------------------------------------------------------*/ + /* SECT base */ + /*-----------------------------------------------------------------------*/ + + const DM_FULLSCREEN = 1; //DM_DX_FULLSCREEN + const DM_FULLWINOW = 2; //DM_W_FULLSCREEN + //const DM_D3D_FULLSCREEN = 16; + //const DM_PICASSO96 = 32; + //const DM_DDRAW = 64; + //const DM_DC = 128; + //const DM_D3D = 256; + const DM_CANVAS = 512; //OWN + const DM_WEBGL = 1024; //OWN + const DM_SWSCALE = 2048; //1024 + + /* picasso96 + + //enum RGBFTYPE + const RGBFB_NONE = 0; // no valid RGB format (should not happen) + const RGBFB_CLUT = 1; // palette mode = ; set colors when opening screen using tags or use SetRGB32/LoadRGB32(...) + const RGBFB_R8G8B8 = 2; // TrueColor RGB (8 bit each) + const RGBFB_B8G8R8 = 3; // TrueColor BGR (8 bit each) + const RGBFB_R5G6B5PC = 4; // HiColor16 (5 bit R = ; 6 bit G = ; 5 bit B), format: gggbbbbbrrrrrggg + const RGBFB_R5G5B5PC = 5; // HiColor15 (5 bit each), format: gggbbbbb0rrrrrgg + const RGBFB_A8R8G8B8 = 6; // 4 Byte TrueColor ARGB (A unused alpha channel) + const RGBFB_A8B8G8R8 = 7; // 4 Byte TrueColor ABGR (A unused alpha channel) + const RGBFB_R8G8B8A8 = 8; // 4 Byte TrueColor RGBA (A unused alpha channel) + const RGBFB_B8G8R8A8 = 9; // 4 Byte TrueColor BGRA (A unused alpha channel) + const RGBFB_R5G6B5 = 10; // HiColor16 (5 bit R = ; 6 bit G = ; 5 bit B), format: rrrrrggggggbbbbb + const RGBFB_R5G5B5 = 11; // HiColor15 (5 bit each), format: 0rrrrrgggggbbbbb + const RGBFB_B5G6R5PC = 12; // HiColor16 (5 bit R = ; 6 bit G = ; 5 bit B), format: gggrrrrrbbbbbggg + const RGBFB_B5G5R5PC = 13; // HiColor15 (5 bit each), format: gggrrrrr0bbbbbbgg + const RGBFB_Y4U2V2 = 14; // 2 Byte TrueColor YUV (CCIR recommendation CCIR601) + const RGBFB_Y4U1V1 = 15; // 1 Byte TrueColor ACCUPAK. + const RGBFB_MaxFormats = 16; + + const RGBFF_NONE = (1< currentmode.native_width || currentmode.current_height > currentmode.native_height)) + return; + OffsetRect(dr, + Math.truncate((currentmode.native_width - currentmode.current_width) / 2), + Math.truncate((currentmode.native_height - currentmode.current_height) / 2) + ); + } + } + + //int default_freq = 60; + //HWND hStatusWnd = null; + var scrlinebuf = null; + + function getdisplay2(p, index) { + var max = Displays.length; + /*if (max == 0) { + gui_message("no display adapters! Exiting"); + exit(0); + }*/ + var display = index < 0 ? p.video.apmode[screen_is_picasso ? 1 : 0].gfx_display - 1 : index; + if (index >= 0 && display >= max) + return null; + if (display >= max) + display = 0; + if (display < 0) + display = 0; + return Displays[display]; + } + function getdisplay(p) { //global + return getdisplay2(p, -1); + } + + /*function getbestmode(nextbest) { + var i, index = -1; + + forever: { for (;;) { + var md = getdisplay2(SAEV_config, index); + if (md === null) + return 0; + var max = md.DisplayModes.length; + var ratio = currentmode.native_width > currentmode.native_height ? 1 : 0; + for (i = 0; i < max && md.DisplayModes[i].depth >= 0; i++) { + var pr = md.DisplayModes[i]; + if (pr.res.width == currentmode.native_width && pr.res.height == currentmode.native_height) + break; + } + if (i < max && md.DisplayModes[i].depth >= 0) { + if (!nextbest) + break; + while (i < max && md.DisplayModes[i].res.width == currentmode.native_width && md.DisplayModes[i].res.height == currentmode.native_height) + i++; + } else + i = 0; + + // first iterate only modes that have similar aspect ratio + var startidx = i; + for (; i < max && md.DisplayModes[i].depth >= 0; i++) { + var pr = md.DisplayModes[i]; + var r = pr.res.width > pr.res.height ? 1 : 0; + if (pr.res.width >= currentmode.native_width && pr.res.height >= currentmode.native_height && r == ratio) { + SAEF_log("video.getbestmode() FS: %dx%d . %dx%d %d %d", currentmode.native_width, currentmode.native_height, pr.res.width, pr.res.height, ratio, index); + currentmode.native_width = pr.res.width; + currentmode.native_height = pr.res.height; + currentmode.current_width = currentmode.native_width; + currentmode.current_height = currentmode.native_height; + //goto end; + break forever; } } - if (this.available & SAEI_Video_WebGL) { - ctx = canvas.getContext('experimental-webgl', glParams) || canvas.getContext('webgl', glParams); - initGL(); - pixels = new Uint16Array(size); - for (var i = 0; i < size; i++) pixels[i] = 0; + // still not match? check all modes + i = startidx; + for (; i < max && md.DisplayModes[i].depth >= 0; i++) { + var pr = md.DisplayModes[i]; + var r = pr.res.width > pr.res.height ? 1 : 0; + if (pr.res.width >= currentmode.native_width && pr.res.height >= currentmode.native_height) { + SAEF_log("video.getbestmode() FS: %dx%d . %dx%d", currentmode.native_width, currentmode.native_height, pr.res.width, pr.res.height); + currentmode.native_width = pr.res.width; + currentmode.native_height = pr.res.height; + currentmode.current_width = currentmode.native_width; + currentmode.current_height = currentmode.native_height; + //goto end; + break forever; + } + } + index++; + }} + //end: + if (index >= 0) { + SAEV_config.video.apmode[screen_is_picasso ? 1 : 0].gfx_display = index; + //changed_prefs.gfx_apmode[screen_is_picasso ? 1 : 0].gfx_display = index; + SAEF_warn("video.getbestmode() Can't find mode %dx%d . Monitor switched to '%s'", currentmode.native_width, currentmode.native_height, md.adaptername); + } + return 1; + }*/ - //this.drawpixel = drawpixel_gl; - this.drawline = drawline_gl; - this.render = render_gl; - this.show = show_gl; + /*static int getstatuswindowheight (void) { + int def = GetSystemMetrics (SM_CYMENU) + 3; + WINDOWINFO wi; + HWND h = CreateWindowEx ( + 0, STATUSCLASSNAME, (LPCTSTR) null, SBARS_TOOLTIPS | WS_CHILD | WS_VISIBLE, + 0, 0, 0, 0, hHiddenWnd, (HMENU) 1, hInst, null); + if (!h) + return def; + wi.cbSize = sizeof wi; + if (!GetWindowInfo (h, &wi)) + return def; + DestroyWindow (h); + return wi.rcWindow.bottom - wi.rcWindow.top; + }*/ + + function updatewinrect(allowfullscreen) { + var f = isfullscreen(); + if (!allowfullscreen && f > 0) + return; + GetWindowRect(hAmigaWnd, amigawin_rect); + //GetWindowRect(hAmigaWnd, amigawinclip_rect); + //#if MOUSECLIP_LOG + SAEF_log("video.updatewinrect() GetWindowRect %dx%d %dx%d %d", amigawin_rect.left, amigawin_rect.top, amigawin_rect.right, amigawin_rect.bottom, f); + //#endif + if (f == 0) { + //changed_prefs.gfx_size_win.x = amigawin_rect.left; + //changed_prefs.gfx_size_win.y = amigawin_rect.top; + SAEV_config.video.size_win.x = amigawin_rect.left; + SAEV_config.video.size_win.y = amigawin_rect.top; + } + } + + function gfxmode_reset() { + usedfilter = null; + /*if (SAEV_config.video.gf[SAEV_Playfield_picasso_on ? 1 : 0].gfx_filter > 0) { + for (var i = 0; i < uaefilters.length; i++) { + if (uaefilters[i].type == SAEV_config.video.gf[SAEV_Playfield_picasso_on ? 1 : 0].gfx_filter) { + usedfilter = uaefilters[i]; + break; + } + } + }*/ + } + + /*function movecursor(x, y) { + SAEF_log("video.movecursor() %dx%d", x, y); + //SetCursorPos(x, y); + }*/ + + //var firstwindow = true; + //var prevsbheight = 0; + function create_windows_2() { + var fs = currentmode.flags & DM_FULLSCREEN; + //var d3dfs = currentmode.flags & DM_D3D_FULLSCREEN; + var fw = currentmode.flags & DM_FULLWINOW; + //DWORD style = WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN | WS_CLIPSIBLINGS; + //DWORD exstyle = (currprefs.win32_notaskbarbutton ? WS_EX_TOOLWINDOW : WS_EX_APPWINDOW) | 0; + //DWORD flags = 0; + var borderless = true; //currprefs.win32_borderless; + var cyborder = 0; //GetSystemMetrics(SM_CYFRAME); + var gap = 0; + var x, y, w, h; + var md = getdisplay(SAEV_config); + var sbheight = 0; //currprefs.win32_statusbar ? getstatuswindowheight () : 0; + + /*if (hAmigaWnd !== null) { alread opened + RECT r; + int w, h, x, y; + int nw, nh, nx, ny; + + if (minimized) { + minimized = -1; + return 1; + } + #if 0 + if (minimized && hMainWnd) { + unsetminimized (); + ShowWindow (hMainWnd, SW_SHOW); + ShowWindow (hMainWnd, SW_RESTORE); + } + #endif + GetWindowRect (hAmigaWnd, &r); + x = r.left; + y = r.top; + w = r.right - r.left; + h = r.bottom - r.top; + nx = x; + ny = y; + + if (screen_is_picasso) { + nw = currentmode.current_width; + nh = currentmode.current_height; } else { - ctx = canvas.getContext('2d'); - imagedata = ctx.createImageData(width, height); - pixels = imagedata.data; + nw = SAEV_config.video.size_win.width; + nh = SAEV_config.video.size_win.height; + } - //this.drawpixel = drawpixel_2d; - this.drawline = drawline_2d; - this.render = render_2d; - this.show = show_2d; + if (fsw || dxfs) { + RECT rc = md.rect; + nx = rc.left; + ny = rc.top; + nw = rc.right - rc.left; + nh = rc.bottom - rc.top; + } else if (d3dfs) { + RECT rc = md.rect; + nw = currentmode.native_width; + nh = currentmode.native_height; + if (rc.left >= 0) + nx = rc.left; + else + nx = rc.left + (rc.right - rc.left - nw); + if (rc.top >= 0) + ny = rc.top; + else + ny = rc.top + (rc.bottom - rc.top - nh); + } + if (w != nw || h != nh || x != nx || y != ny || sbheight != prevsbheight) { + w = nw; + h = nh; + x = nx; + y = ny; + in_sizemove++; + if (hMainWnd && !fsw && !dxfs && !d3dfs && !rp_isactive ()) { + window_extra_height += (sbheight - prevsbheight); + GetWindowRect (hMainWnd, &r); + x = r.left; + y = r.top; + SetWindowPos (hMainWnd, HWND_TOP, x, y, w + window_extra_width, h + window_extra_height, + SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOSENDCHANGING | SWP_NOZORDER); + x = gap; + y = gap; + } + SetWindowPos (hAmigaWnd, HWND_TOP, x, y, w, h, + SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOSENDCHANGING | SWP_NOZORDER); + in_sizemove--; + } else { + w = nw; + h = nh; + x = nx; + y = ny; + } + createstatuswindow(); + createstatusline(); + updatewinrect(false); + GetWindowRect(hMainWnd, &mainwin_rect); + if (d3dfs || dxfs) + movecursor (x + w / 2, y + h / 2); + write_log (_T("window already open (%dx%d %dx%d)\n"), amigawin_rect.left, amigawin_rect.top, amigawin_rect.right - amigawin_rect.left, amigawin_rect.bottom - amigawin_rect.top); + updatemouseclip (); + rp_screenmode_changed (); + prevsbheight = sbheight; + return 1; + }*/ + + if (fw && !borderless) + borderless = true; + + //window_led_drives = 0; + //window_led_drives_end = 0; + hMainWnd = null; + x = 0; y = 0; + if (borderless) + sbheight = cyborder = 0; + + if (!fs) { // && !d3dfs) { + var rc = new RECT(); + var stored_x = 1, stored_y = sbheight + cyborder; + //var oldx, oldy; + var first = 2; + + //regqueryint (null, _T("MainPosX"), &stored_x); + //regqueryint (null, _T("MainPosY"), &stored_y); + + if (borderless) { + stored_x = SAEV_config.video.size_win.x; + stored_y = SAEV_config.video.size_win.y; + } + + while (first) { + first--; + /*if (stored_x < GetSystemMetrics (SM_XVIRTUALSCREEN)) + stored_x = GetSystemMetrics (SM_XVIRTUALSCREEN); + if (stored_y < GetSystemMetrics (SM_YVIRTUALSCREEN) + sbheight + cyborder) + stored_y = GetSystemMetrics (SM_YVIRTUALSCREEN) + sbheight + cyborder; + + if (stored_x > GetSystemMetrics (SM_CXVIRTUALSCREEN)) + rc.left = 1; + else + rc.left = stored_x; + + if (stored_y > GetSystemMetrics (SM_CYVIRTUALSCREEN)) + rc.top = 1; + else + rc.top = stored_y;*/ + rc.left = 0; + rc.top = 0; + + rc.right = rc.left + gap + currentmode.current_width + gap; + rc.bottom = rc.top + gap + currentmode.current_height + gap + sbheight; + + /*oldx = rc.left; + oldy = rc.top; + AdjustWindowRect (&rc, borderless ? WS_POPUP : style, FALSE); + win_x_diff = rc.left - oldx; + win_y_diff = rc.top - oldy; + + if (MonitorFromRect (&rc, MONITOR_DEFAULTTONULL) == null) { + write_log (_T("window coordinates are not visible on any monitor, reseting..\n")); + stored_x = stored_y = 0; + continue; + }*/ + break; + } + + if (fw) { + rc = md.rect.clone(); + //flags |= WS_EX_TOPMOST; + //style = WS_POPUP; + currentmode.native_width = rc.right - rc.left; + currentmode.native_height = rc.bottom - rc.top; + } + //flags |= (currprefs.win32_alwaysontop ? WS_EX_TOPMOST : 0); + + if (!borderless) { + /*RECT rc2; + hMainWnd = CreateWindowEx (WS_EX_ACCEPTFILES | exstyle | flags, + _T("PCsuxRox"), _T("WinUAE"), + style, + rc.left, rc.top, + rc.right - rc.left, rc.bottom - rc.top, + null, null, hInst, null); + if (!hMainWnd) { + write_log (_T("main window creation failed\n")); + return 0; + } + GetWindowRect (hMainWnd, &rc2); + window_extra_width = rc2.right - rc2.left - currentmode.current_width; + window_extra_height = rc2.bottom - rc2.top - currentmode.current_height;*/ + + //createstatuswindow(); + //createstatusline(); + } else { + x = rc.left; + y = rc.top; + } + w = currentmode.native_width; + h = currentmode.native_height; + } else { + //getbestmode(0); + w = currentmode.native_width; + h = currentmode.native_height; + var rc = md.rect; + if (rc.left >= 0) + x = rc.left; + else + x = rc.left + (rc.right - rc.left - w); + if (rc.top >= 0) + y = rc.top; + else + y = rc.top + (rc.bottom - rc.top - h); + } + + /*if (rp_isactive() && !fs && !d3dfs && !fw) { + HWND parent = rp_getparent (); + hAmigaWnd = CreateWindowEx (fs || d3dfs ? WS_EX_ACCEPTFILES | WS_EX_TOPMOST : WS_EX_ACCEPTFILES | WS_EX_TOOLWINDOW | (currprefs.win32_alwaysontop ? WS_EX_TOPMOST : 0), + _T("AmigaPowah"), _T("WinUAE"), WS_POPUP, + 0, 0, w, h, + parent, null, hInst, null); + } else*/ { + /*hAmigaWnd = CreateWindowEx ( + ((fs || d3dfs || currprefs.win32_alwaysontop) ? WS_EX_TOPMOST : WS_EX_ACCEPTFILES) | exstyle, _T("AmigaPowah"), _T("WinUAE"), + ((fs || d3dfs || currprefs.headless) ? WS_POPUP : (WS_CLIPCHILDREN | WS_CLIPSIBLINGS | (hMainWnd ? WS_VISIBLE | WS_CHILD : WS_VISIBLE | WS_POPUP | WS_SYSMENU | WS_MINIMIZEBOX))), + x, y, w, h, + borderless ? null : (hMainWnd ? hMainWnd : null), + null, hInst, null + );*/ + try { + hAmigaWnd = CreateWindow(x, y, w, h); + } catch(err) { + doExit(); + return err; + } + } + /*if (hAmigaWnd === null) { + write_log (_T("creation of amiga window failed\n")); + doExit(); + return 0; + }*/ + if (hMainWnd === null) { + hMainWnd = hAmigaWnd; + //registertouch(hAmigaWnd); + } /*else { + registertouch(hMainWnd); + registertouch(hAmigaWnd); + }*/ + + //updatewinrect(true); + //GetWindowRect(hMainWnd, mainwin_rect); + //if (fs || d3dfs) movecursor(x + w / 2, y + h / 2); + + //addnotifications(hAmigaWnd, FALSE, FALSE); + //createblankwindows(); + + /*if (hMainWnd != hAmigaWnd) { + if (!currprefs.headless && !rp_isactive ()) + ShowWindow (hMainWnd, firstwindow ? (currprefs.win32_start_minimized ? SW_SHOWMINIMIZED : SW_SHOWDEFAULT) : SW_SHOWNORMAL); + UpdateWindow (hMainWnd); + }*/ + //if (!currprefs.headless && !rp_isactive ()) + ShowWindow(hAmigaWnd, SW_SHOWNORMAL); + //UpdateWindow(hAmigaWnd); + //setDwmEnableMMCSS (true); + + updatewinrect(true); //OWN must ba called after ShowWindow() + + //firstwindow = false; + //prevsbheight = sbheight; + return SAEE_None; //1; + } + + /*function getrefreshrate(width, height) { + var ap = SAEV_config.video.apmode[SAEV_Playfield_picasso_on ? 1 : 0]; + var freq = 0; + + if (ap.gfx_refreshrate <= 0) + return 0; + + var md = getdisplay(SAEV_config); + for (var i = 0; i < md.DisplayModes.length; i++) { + var pr = md.DisplayModes[i]; + if (pr.res.width == width && pr.res.height == height) { + for (var j = 0; j < pr.refresh.length; j++) { + if (pr.refresh[j] == ap.gfx_refreshrate) + return ap.gfx_refreshrate; + if (pr.refresh[j] > freq && pr.refresh[j] < ap.gfx_refreshrate) + freq = pr.refresh[j]; + } + } + } + SAEF_log("video.getrefreshrate() Refresh rate %d not supported, using %d", ap.gfx_refreshrate, freq); + return freq; + }*/ + + function set_ddraw_2() { + var bits = (currentmode.current_depth + 7) & ~7; + var width = currentmode.native_width; + var height = currentmode.native_height; + var ap = SAEV_config.video.apmode[SAEV_Playfield_picasso_on ? 1 : 0]; + var freq = ap.gfx_refreshrate; + var ddrval = 0; + + var fs = (currentmode.flags & DM_FULLSCREEN) != 0; + //var fw = (currentmode.flags & DM_FULLWINOW) != 0; unused + //var dd = (currentmode.flags & DM_DDRAW) != 0; + var dd = (currentmode.flags & DM_CANVAS) != 0; + + /*if (WIN32GFX_IsPicassoScreen() && (picasso96_state.Width > width || picasso96_state.Height > height)) { + width = picasso96_state.Width; + height = picasso96_state.Height; + }*/ + + hAmigaWnd.surface = null; + //DirectDraw_FreeMainSurface(); + + if (!dd && !fs) + return 1; + + /*ddrval = DirectDraw_SetCooperativeLevel(hAmigaWnd, fs, true); + if (FAILED(ddrval)) + return 0;*/ + + /*if (fs) { + for (;;) { + freq = getrefreshrate(width, height); + SAEF_log("video.set_ddraw_2() trying %dx%d, bits=%d, refreshrate=%d", width, height, bits, freq); + ddrval = DirectDraw_SetDisplayMode(width, height, bits, freq); + if (SUCCEEDED(ddrval)) + break; + var olderr = ddrval; + if (freq) { + SAEF_log("video.set_ddraw_2() failed, trying without forced refresh rate"); + freq = 0; + DirectDraw_SetCooperativeLevel(hAmigaWnd, fs, true); + ddrval = DirectDraw_SetDisplayMode(width, height, bits, freq); + if (SUCCEEDED(ddrval)) + break; + } + if (olderr != DDERR_INVALIDMODE && olderr != 0x80004001 && olderr != DDERR_UNSUPPORTEDMODE) + return 0; + + return -1; + } + currentmode.freq = freq; + updatewinrect(true); + }*/ + + /*if (dd) { + ddrval = DirectDraw_CreateClipper(); + if (FAILED (ddrval)) + return 0; + ddrval = DirectDraw_CreateMainSurface(width, height); + if (FAILED(ddrval)) { + SAEF_error("video.set_ddraw_2() couldn't CreateSurface() for primary because %s.", DXError(ddrval)); + return 0; + } + ddrval = DirectDraw_SetClipper(hAmigaWnd); + if (FAILED(ddrval)) + return 0; + if (DirectDraw_SurfaceLock()) { + currentmode.pitch = DirectDraw_GetSurfacePitch(); + DirectDraw_SurfaceUnlock(); + } + }*/ + if (dd) { + hAmigaWnd.surface = new Surface(width, height, 4); + hAmigaWnd.surface.imageData = hAmigaWnd.ctx.createImageData(width, height); + currentmode.pitch = hAmigaWnd.surface.rowbytes; + } + + SAEF_log("video.set_ddraw_2() %dx%d@%d-bytes", width, height, bits); + return 1; + } + function set_ddraw() { + var cnt = 3; + for (;;) { + var ret = set_ddraw_2(); + if (cnt-- <= 0) + return 0; + /*if (ret < 0) { + getbestmode(1); + continue; + }*/ + if (ret == 0) + return 0; + break; + } + return 1; + } + + function create_windows() { + var err = create_windows_2(); + if (err != SAEE_None) + return err; + + set_ddraw(); + return SAEE_None; + } + + function allocsoftbuffer(name, buf, flags, width, height, depth) { + buf.pixbytes = (depth + 7) >> 3; // / 8; + buf.width_allocated = (width + 7) & ~7; + buf.height_allocated = height; + + if (!(flags & DM_SWSCALE)) { + if (buf !== SAER_Playfield_gfxvidinfo.drawbuffer) + return; + + buf.bufmem = null; + buf.bufmemend = null; + buf.realbufmem = null; + buf.bufmem_allocated = null; + buf.bufmem_lockable = true; + + SAEF_log("video.allocsoftbuffer() Reserved %s temp buffer (%d*%d*%d)", name, width, height, depth); + } else if (flags & DM_SWSCALE) { + var w = buf.width_allocated; + var h = buf.height_allocated; + var size = (w * 2) * (h * 2) * buf.pixbytes; + buf.rowbytes = w * 2 * buf.pixbytes; + + /* ORG + buf.realbufmem = xcalloc(uae_u8, size); + buf.bufmem = buf.realbufmem + (h / 2) * buf.rowbytes + (w / 2) * buf.pixbytes; + buf.bufmemend = buf.realbufmem + size - buf.rowbytes; + buf.bufmem_allocated = buf.bufmem;*/ + + buf.realbufmem = new ArrayBuffer(size); + buf.bufmem = buf.realbufmem; + buf.bufmem_pos = (h / 2) * buf.rowbytes + (w / 2) * buf.pixbytes; ///OWN + buf.bufmemend = buf.realbufmem; + buf.bufmemend_pos = size - buf.rowbytes; ///OWN + buf.bufmem_allocated = buf.bufmem; + + buf.bufmem_lockable = true; + + SAEF_log("video.allocsoftbuffer() Allocated %s temp buffer (%d*%d*%d)", name, width, height, depth); + } + } + function freevidbuffer(buf) { + //xfree (buf.realbufmem); + //buf.realbufmem = null; + buf.clr(); //memset(buf, 0, sizeof (struct vidbuffer)); + } + + /* Color management */ + //static xcolnr xcol8[4096]; + + var red_bits = 0, green_bits = 0, blue_bits = 0, alpha_bits = 0; + var red_shift = 0, green_shift = 0, blue_shift = 0, alpha_shift = 0; + var alpha = 0; + + function init_colors() { //global + var byte_swap = SAEC_LITTLE_ENDIAN; + + if (currentmode.flags & DM_WEBGL) { + if (currentmode.current_depth == 16) { //R5G6B5 + red_bits = 5; + green_bits = 6; + blue_bits = 5; + alpha_bits = 0; + red_shift = 11; + green_shift = 5; + blue_shift = 0; + alpha_shift = 0; + alpha = 0; + byte_swap = false; + } + else { //RGBA + red_bits = 8; + green_bits = 8; + blue_bits = 8; + alpha_bits = 8; + red_shift = 24; + green_shift = 16; + blue_shift = 8; + alpha_shift = 0; + alpha = SAEV_config.video.alpha; + } + } + else if (currentmode.flags & DM_CANVAS) { + if (1) { //RGBA + red_bits = 8; + green_bits = 8; + blue_bits = 8; + alpha_bits = 8; + red_shift = 24; + green_shift = 16; + blue_shift = 8; + alpha_shift = 0; + alpha = SAEV_config.video.alpha; + } + else { //RGB + red_bits = 8; + green_bits = 8; + blue_bits = 8; + alpha_bits = 0; + red_shift = 16; + green_shift = 8; + blue_shift = 0; + alpha_shift = 0; + alpha = 0; + } + } + /*else if (currentmode.flags & DM_D3D) { + D3D_getpixelformat (currentmode.current_depth, &red_bits, &green_bits, &blue_bits, &red_shift, &green_shift, &blue_shift, &alpha_bits, &alpha_shift, &alpha); + } else { + red_bits = bits_in_mask(DirectDraw_GetPixelFormatBitMask(red_mask)); + green_bits = bits_in_mask(DirectDraw_GetPixelFormatBitMask(green_mask)); + blue_bits = bits_in_mask(DirectDraw_GetPixelFormatBitMask(blue_mask)); + alpha_bits = 0; + //alpha_bits = bits_in_mask(DirectDraw_GetPixelFormatBitMask(alpha_mask)); //OWN + red_shift = mask_shift(DirectDraw_GetPixelFormatBitMask(red_mask)); + green_shift = mask_shift(DirectDraw_GetPixelFormatBitMask(green_mask)); + blue_shift = mask_shift(DirectDraw_GetPixelFormatBitMask(blue_mask)); + alpha_shift = 0; + //alpha_shift = mask_shift(DirectDraw_GetPixelFormatBitMask(alpha_mask)); //OWN + + if (currentmode.current_depth != currentmode.native_depth) { + if (currentmode.current_depth == 16) { + red_bits = 5; green_bits = 6; blue_bits = 5; + red_shift = 11; green_shift = 5; blue_shift = 0; + } else { + red_bits = green_bits = blue_bits = 8; + red_shift = 16; green_shift = 8; blue_shift = 0; + } + } + }*/ + + SAER.playfield.alloc_colors64k(red_bits, green_bits, blue_bits, red_shift, green_shift, blue_shift, alpha_bits, alpha_shift, alpha, byte_swap); + + SAER.playfield.notice_new_xcolors_ext(); + + //S2X_configure(red_bits, green_bits, blue_bits, red_shift,green_shift, blue_shift); + + /*#ifdef AVIOUTPUT + AVIOutput_RGBinfo (red_bits, green_bits, blue_bits, red_shift, green_shift, blue_shift); + #endif + Screenshot_RGBinfo (red_bits, green_bits, blue_bits, red_shift, green_shift, blue_shift);*/ + } + + /*static HWND blankwindows[MAX_DISPLAYS]; + static void closeblankwindows (void) { + for (int i = 0; i < MAX_DISPLAYS; i++) { + HWND h = blankwindows[i]; + if (h) { + ShowWindow (h, SW_HIDE); + DestroyWindow (h); + blankwindows[i] = null; + } + } + } + static void createblankwindows (void) { + struct MultiDisplay *mdx = getdisplay (&currprefs); + int i; + + if (!currprefs.win32_blankmonitors) + return; + + for (i = 0; Displays[i].monitorname; i++) { + struct MultiDisplay *md = &Displays[i]; + TCHAR name[100]; + if (mdx == md) + continue; + _stprintf (name, _T("WinUAE_Blank_%d"), i); + blankwindows[i] = CreateWindowEx ( + WS_EX_TOPMOST, + _T("Blank"), name, + WS_POPUP | WS_VISIBLE, + md.rect.left, md.rect.top, md.rect.right - md.rect.left, md.rect.bottom - md.rect.top, + null, + null, hInst, null); + } + }*/ + + function doInit() { + //var fs_warning = -1; + //var tmp_depth = 0; + //var ret = 0; + var err = 0; + + remembered_vblank = -1; + if (wasfullwindow_a == 0) + wasfullwindow_a = SAEV_config.video.apmode[0].gfx_fullscreen == SAEC_Config_Video_AP_Fullscreen_FULLWINDOW ? 1 : -1; + if (wasfullwindow_p == 0) + wasfullwindow_p = SAEV_config.video.apmode[1].gfx_fullscreen == SAEC_Config_Video_AP_Fullscreen_FULLWINDOW ? 1 : -1; + + gfxmode_reset(); + freevidbuffer(SAER_Playfield_gfxvidinfo.drawbuffer); + freevidbuffer(SAER_Playfield_gfxvidinfo.tempbuffer); + + for (;;) { + updatemodes(); + currentmode.native_depth = 0; + //tmp_depth = currentmode.current_depth; + + if (currentmode.flags & DM_FULLWINOW) { + var rc = getdisplay(SAEV_config).rect; + currentmode.native_width = rc.right - rc.left; + currentmode.native_height = rc.bottom - rc.top; + } + + /*if (!(currentmode.flags & DM_D3D) && isfullscreen() <= 0) { + currentmode.current_depth = DirectDraw_GetCurrentDepth(); + updatemodes(); + } + if (!(currentmode.flags & DM_D3D) && DirectDraw_GetCurrentDepth() == currentmode.current_depth) { + updatemodes(); + }*/ + /*if (0) { //OWN + switch (screen.colorDepth) { + case 32: + case 24: + currentmode.current_depth = 32; + break; + default: + currentmode.current_depth = 16; + } + updatemodes(); + }*/ + + /*if (!rp_isactive() && (currentmode.current_width > GetSystemMetrics(SM_CXVIRTUALSCREEN) || currentmode.current_height > GetSystemMetrics(SM_CYVIRTUALSCREEN))) { + if (!console_logging) + fs_warning = IDS_UNSUPPORTEDSCREENMODE_3; + } + if (fs_warning >= 0 && isfullscreen() <= 0) { + TCHAR szMessage[MAX_DPATH], szMessage2[MAX_DPATH]; + WIN32GUI_LoadUIString(IDS_UNSUPPORTEDSCREENMODE, szMessage, MAX_DPATH); + WIN32GUI_LoadUIString(fs_warning, szMessage2, MAX_DPATH); + // Temporarily drop the DirectDraw stuff + DirectDraw_Release(); + var tmpstr = sprintf(szMessage, szMessage2); + gui_message (tmpstr); + // Switch to fullscreen + DirectDraw_Start(); + if (screen_is_picasso) + changed_prefs.gfx_apmode[1].gfx_fullscreen = SAEV_config.video.apmode[1].gfx_fullscreen = SAEC_Config_Video_AP_Fullscreen_FULLSCREEN; + else + changed_prefs.gfx_apmode[0].gfx_fullscreen = SAEV_config.video.apmode[0].gfx_fullscreen = SAEC_Config_Video_AP_Fullscreen_FULLSCREEN; + updatewinfsmode(&currprefs); + updatewinfsmode(&changed_prefs); + currentmode.current_depth = tmp_depth; + updatemodes(); + ret = -2; + goto oops; + }*/ + if ((err = create_windows()) != SAEE_None) { + //ret = 0; goto oops; + doExit(); + return err; + } + + if (screen_is_picasso) { + break; + } else { + currentmode.native_depth = currentmode.current_depth; + + if (SAEV_config.video.hresolution > SAER_Playfield_gfxvidinfo.gfx_resolution_reserved) + SAER_Playfield_gfxvidinfo.gfx_resolution_reserved = SAEV_config.video.hresolution; + if (SAEV_config.video.vresolution > SAER_Playfield_gfxvidinfo.gfx_vresolution_reserved) + SAER_Playfield_gfxvidinfo.gfx_vresolution_reserved = SAEV_config.video.vresolution; + + //SAER_Playfield_gfxvidinfo.drawbuffer.gfx_resolution_reserved = RES_SUPERHIRES; ORG + + //if (currentmode.flags & (DM_D3D | DM_SWSCALE)) { + //if (currentmode.flags & (DM_WEBGL | DM_SWSCALE)) { + if (0) { + //if (!currprefs.gfx_autoresolution) { + currentmode.amiga_width = SAEC_Video_MAX_AMIGA_WIDTH << SAEV_config.video.hresolution; + currentmode.amiga_height = SAEC_Video_MAX_AMIGA_HEIGHT << SAEV_config.video.vresolution; + /*} else { + currentmode.amiga_width = SAEC_Video_MAX_AMIGA_WIDTH << SAER_Playfield_gfxvidinfo.gfx_resolution_reserved; + currentmode.amiga_height = SAEC_Video_MAX_AMIGA_HEIGHT << SAER_Playfield_gfxvidinfo.gfx_vresolution_reserved; + }*/ + /*if (SAER_Playfield_gfxvidinfo.gfx_resolution_reserved == SAEC_Config_Video_HResolution_SuperHiRes) + currentmode.amiga_height <<= 1; + if (currentmode.amiga_height > 1280) + currentmode.amiga_height = 1280;*/ + + SAER_Playfield_gfxvidinfo.drawbuffer.inwidth = SAER_Playfield_gfxvidinfo.drawbuffer.outwidth = currentmode.amiga_width; + SAER_Playfield_gfxvidinfo.drawbuffer.inheight = SAER_Playfield_gfxvidinfo.drawbuffer.outheight = currentmode.amiga_height; + + if (usedfilter !== null) { + if ((usedfilter.flags & (UAE_FILTER_MODE_16 | UAE_FILTER_MODE_32)) == (UAE_FILTER_MODE_16 | UAE_FILTER_MODE_32)) + currentmode.current_depth = currentmode.native_depth; + else + currentmode.current_depth = (usedfilter.flags & UAE_FILTER_MODE_32) ? 32 : 16; + } + currentmode.pitch = currentmode.amiga_width * (currentmode.current_depth >> 3); + } else { + currentmode.amiga_width = currentmode.current_width; + currentmode.amiga_height = currentmode.current_height; + } + SAER_Playfield_gfxvidinfo.drawbuffer.pixbytes = currentmode.current_depth >> 3; + SAER_Playfield_gfxvidinfo.drawbuffer.bufmem = null; + SAER_Playfield_gfxvidinfo.drawbuffer.linemem = null; + SAER_Playfield_gfxvidinfo.drawbuffer.rowbytes = currentmode.pitch; + SAER_Playfield_gfxvidinfo.maxblocklines = 0; // flush_screen actually does everything + break; + } + } + + /*#ifdef PICASSO96 + picasso_vidinfo.rowbytes = 0; + picasso_vidinfo.pixbytes = currentmode.current_depth / 8; + picasso_vidinfo.rgbformat = 0; + picasso_vidinfo.extra_mem = 1; + picasso_vidinfo.height = currentmode.current_height; + picasso_vidinfo.width = currentmode.current_width; + picasso_vidinfo.depth = currentmode.current_depth; + picasso_vidinfo.offset = 0; + #endif*/ + + if (scrlinebuf === null) { + //scrlinebuf = xmalloc(uae_u8, SAEC_Video_MAX_UAE_WIDTH * 4); + scrlinebuf = new ArrayBuffer(SAEC_Video_MAX_UAE_WIDTH * 4); + } + SAER_Playfield_gfxvidinfo.drawbuffer.emergmem = scrlinebuf; // memcpy from system-memory to video-memory + SAER_Playfield_gfxvidinfo.drawbuffer.realbufmem = null; + SAER_Playfield_gfxvidinfo.drawbuffer.bufmem = null; + SAER_Playfield_gfxvidinfo.drawbuffer.bufmem_allocated = null; + SAER_Playfield_gfxvidinfo.drawbuffer.bufmem_lockable = false; + + SAER_Playfield_gfxvidinfo.outbuffer = SAER_Playfield_gfxvidinfo.drawbuffer; + SAER_Playfield_gfxvidinfo.inbuffer = SAER_Playfield_gfxvidinfo.drawbuffer; + + if (!screen_is_picasso) { + //if (SAEV_config.video.api == SAEC_Config_Video_API_Canvas && SAEV_config.video.gf[0].gfx_filter == 0) + allocsoftbuffer("draw", SAER_Playfield_gfxvidinfo.drawbuffer, currentmode.flags, currentmode.native_width, currentmode.native_height, currentmode.current_depth); + //else + //allocsoftbuffer("draw", SAER_Playfield_gfxvidinfo.drawbuffer, currentmode.flags, 1600, 1280, currentmode.current_depth); + + /*if (currprefs.monitoremu || currprefs.cs_cd32fmv || (currprefs.genlock && currprefs.genlock_image) || currprefs.cs_color_burst || currprefs.gfx_grayscale) { + allocsoftbuffer("monemu", SAER_Playfield_gfxvidinfo.tempbuffer, currentmode.flags, + currentmode.amiga_width > 1024 ? currentmode.amiga_width : 1024, + currentmode.amiga_height > 1024 ? currentmode.amiga_height : 1024, + currentmode.current_depth); + }*/ + SAER_Playfield_init_row_map(); + } + init_colors(); + + //S2X_free(); + oldtex_w = oldtex_h = -1; + + /*if (currentmode.flags & DM_D3D) { + const TCHAR *err = D3D_init (hAmigaWnd, currentmode.native_width, currentmode.native_height, currentmode.current_depth, ¤tmode.freq, screen_is_picasso ? 1 : SAEV_config.video.gf[SAEV_Playfield_picasso_on ? 1 : 0].gfx_filter_filtermode + 1); + if (err) { + D3D_free (true); + gui_message (err); + SAEV_config.video.api = SAEC_Config_Video_API_Canvas; //changed_prefs.gfx_api = SAEC_Config_Video_API_Canvas; + SAEV_config.video.gf[SAEV_Playfield_picasso_on ? 1 : 0].gfx_filter = 0; //changed_prefs.gf[SAEV_Playfield_picasso_on ? 1 : 0].gfx_filter = 0 + currentmode.current_depth = currentmode.native_depth; + gfxmode_reset(); + DirectDraw_Start(); + ret = -1; + goto oops; + } + target_graphics_buffer_update(); + updatewinrect(true); + }*/ + if (currentmode.flags & DM_WEBGL) { + err = setupWebGL(hAmigaWnd.ctx, currentmode.native_width, currentmode.native_height); + if (err != SAEE_None) { + doExit(); + return err; + } + //SAER.video.target_graphics_buffer_update(); + updatewinrect(true); + } + + screen_is_initialized = true; + //createstatusline(); + //picasso_refresh(); + /*#ifdef RETROPLATFORM + rp_set_hwnd_delayed(); + #endif*/ + + //if (isfullscreen() != 0) setmouseactive(-1); + + return err; //1; + + /*oops: + doExit(); + return ret;*/ + } + + function doExit() { //close_hwnds() + screen_is_initialized = false; + /*#ifdef AVIOUTPUT + AVIOutput_Restart(); + #endif + setmouseactive(0); + #ifdef RETROPLATFORM + rp_set_hwnd(null); + #endif + closeblankwindows(); + deletestatusline(); + if (hStatusWnd) { + ShowWindow (hStatusWnd, SW_HIDE); + DestroyWindow (hStatusWnd); + hStatusWnd = 0; + }*/ + if (hAmigaWnd !== null) { + //addnotifications (hAmigaWnd, TRUE, FALSE); + //D3D_free (true); + ShowWindow(hAmigaWnd, SW_HIDE); + DestroyWindow(hAmigaWnd); + if (hAmigaWnd == hMainWnd) hMainWnd = null; + hAmigaWnd = null; + } + /*if (hMainWnd) { + ShowWindow (hMainWnd, SW_HIDE); + DestroyWindow (hMainWnd); + hMainWnd = null; + }*/ + } + + + + this.updatedisplayarea = function() { + /*if (!screen_is_initialized) + return; + if (dx_islost()) + return; + + if (currentmode.flags & DM_D3D) { + D3D_refresh(); + } + else if (currentmode.flags & DM_DDRAW) { + if (!SAEV_Playfield_picasso_on && (currentmode.flags & DM_SWSCALE)) + S2X_refresh(); + + DirectDraw_Flip(0); + }*/ + } + + function updatewinfsmode(p) { //global + //struct MultiDisplay *md; + + SAER.config.fixup_prefs_dimensions_ext(p); + if (isfullscreen_2(p) != 0) + p.video.size = p.video.size_fs.clone(); + else + p.video.size = p.video.size_win.clone(); + + //md = getdisplay(p); + //set_config_changed(); + } + + function update_gfxparams() { + updatewinfsmode(SAEV_config); + /*#ifdef PICASSO96 + currentmode.vsync = 0; + if (screen_is_picasso) { + currentmode.current_width = (int)(picasso96_state.Width * currprefs.rtg_horiz_zoom_mult); + currentmode.current_height = (int)(picasso96_state.Height * currprefs.rtg_vert_zoom_mult); + SAEV_config.video.apmode[1].gfx_interlaced = false; + if (currprefs.win32_rtgvblankrate == 0) { + SAEV_config.video.apmode[1].gfx_refreshrate = SAEV_config.video.apmode[0].gfx_refreshrate; + if (SAEV_config.video.apmode[0].gfx_interlaced) { + SAEV_config.video.apmode[1].gfx_refreshrate *= 2; + } + } else if (currprefs.win32_rtgvblankrate < 0) { + SAEV_config.video.apmode[1].gfx_refreshrate = 0; + } else { + SAEV_config.video.apmode[1].gfx_refreshrate = currprefs.win32_rtgvblankrate; + } + if (SAEV_config.video.apmode[1].gfx_vsync) + currentmode.vsync = 1 + SAEV_config.video.apmode[1].gfx_vsyncmode; + } else { + #endif*/ + currentmode.current_width = SAEV_config.video.size.width; + currentmode.current_height = SAEV_config.video.size.height; + if (SAEV_config.video.apmode[0].gfx_vsync) + currentmode.vsync = 1 + SAEV_config.video.apmode[0].gfx_vsyncmode; + /*#ifdef PICASSO96 + } + #endif*/ + + currentmode.current_depth = SAEV_config.video.colorMode < 5 ? 16 : 32; + /*if (screen_is_picasso && currprefs.win32_rtgmatchdepth && isfullscreen() > 0) { + int pbits = picasso96_state.BytesPerPixel * 8; + if (pbits <= 8) { + if (currentmode.current_depth == 32) + pbits = 32; + else + pbits = 16; + } + if (pbits == 24) + pbits = 32; + currentmode.current_depth = pbits; + }*/ + currentmode.amiga_width = currentmode.current_width; + currentmode.amiga_height = currentmode.current_height; + + /*scalepicasso = 0; + if (screen_is_picasso) { + if (isfullscreen () < 0) { + if ((SAEV_config.video.gf[1].gfx_filter_autoscale == RTG_MODE_CENTER || SAEV_config.video.gf[1].gfx_filter_autoscale == RTG_MODE_SCALE || currprefs.win32_rtgallowscaling) && (picasso96_state.Width != currentmode.native_width || picasso96_state.Height != currentmode.native_height)) + scalepicasso = 1; + if (SAEV_config.video.gf[1].gfx_filter_autoscale == RTG_MODE_CENTER) + scalepicasso = SAEV_config.video.gf[1].gfx_filter_autoscale; + if (!scalepicasso && currprefs.win32_rtgscaleaspectratio) + scalepicasso = -1; + } else if (isfullscreen () > 0) { + if (!currprefs.win32_rtgmatchdepth) { // can't scale to different color depth + if (currentmode.native_width > picasso96_state.Width && currentmode.native_height > picasso96_state.Height) { + if (SAEV_config.video.gf[1].gfx_filter_autoscale) + scalepicasso = 1; + } + if (SAEV_config.video.gf[1].gfx_filter_autoscale == RTG_MODE_CENTER) + scalepicasso = SAEV_config.video.gf[1].gfx_filter_autoscale; + if (!scalepicasso && currprefs.win32_rtgscaleaspectratio) + scalepicasso = -1; + } + } else if (isfullscreen () == 0) { + if (SAEV_config.video.gf[1].gfx_filter_autoscale == RTG_MODE_INTEGER_SCALE) { + scalepicasso = RTG_MODE_INTEGER_SCALE; + currentmode.current_width = SAEV_config.video.size.width; + currentmode.current_height = SAEV_config.video.size.height; + } else if (SAEV_config.video.gf[1].gfx_filter_autoscale == RTG_MODE_CENTER) { + if (SAEV_config.video.size.width < picasso96_state.Width || SAEV_config.video.size.height < picasso96_state.Height) { + if (!currprefs.win32_rtgallowscaling) { + ; + } else if (currprefs.win32_rtgscaleaspectratio) { + scalepicasso = -1; + currentmode.current_width = SAEV_config.video.size.width; + currentmode.current_height = SAEV_config.video.size.height; + } + } else { + scalepicasso = 2; + currentmode.current_width = SAEV_config.video.size.width; + currentmode.current_height = SAEV_config.video.size.height; + } + } else if (SAEV_config.video.gf[1].gfx_filter_autoscale == RTG_MODE_SCALE) { + if (SAEV_config.video.size.width > picasso96_state.Width || SAEV_config.video.size.height > picasso96_state.Height) + scalepicasso = 1; + if ((SAEV_config.video.size.width != picasso96_state.Width || SAEV_config.video.size.height != picasso96_state.Height) && currprefs.win32_rtgallowscaling) { + scalepicasso = 1; + } else if (SAEV_config.video.size.width < picasso96_state.Width || SAEV_config.video.size.height < picasso96_state.Height) { + // no always scaling and smaller? Back to normal size + currentmode.current_width = changed_prefs.gfx_size_win.width = picasso96_state.Width; + currentmode.current_height = changed_prefs.gfx_size_win.height = picasso96_state.Height; + } else if (SAEV_config.video.size.width == picasso96_state.Width || SAEV_config.video.size.height == picasso96_state.Height) { + ; + } else if (!scalepicasso && currprefs.win32_rtgscaleaspectratio) { + scalepicasso = -1; + } + } else { + if ((SAEV_config.video.size.width != picasso96_state.Width || SAEV_config.video.size.height != picasso96_state.Height) && currprefs.win32_rtgallowscaling) + scalepicasso = 1; + if (!scalepicasso && currprefs.win32_rtgscaleaspectratio) + scalepicasso = -1; + } + } + + if (scalepicasso > 0 && (SAEV_config.video.size.width != picasso96_state.Width || SAEV_config.video.size.height != picasso96_state.Height)) { + currentmode.current_width = SAEV_config.video.size.width; + currentmode.current_height = SAEV_config.video.size.height; + } + }*/ + } + + function updatemodes() { + currentmode.fullfill = 0; + //var flags = DM_DDRAW; + var flags = DM_CANVAS; + + if (isfullscreen() > 0) + flags |= DM_FULLSCREEN; + else if (isfullscreen() < 0) + flags |= DM_FULLWINOW; + + if (usedfilter !== null) { + flags |= DM_SWSCALE; + if (currentmode.current_depth < 15) + currentmode.current_depth = 16; + } + if (SAEV_config.video.api == SAEC_Config_Video_API_WebGL) { + flags |= DM_WEBGL; + flags &= ~DM_CANVAS; + //flags &= ~DM_DDRAW; + } + /*if (SAEV_config.video.api) { + flags |= DM_D3D; + if (flags & DM_FULLSCREEN) { + flags &= ~DM_FULLSCREEN; + flags |= DM_D3D_FULLSCREEN; + } + flags &= ~DM_DDRAW; + }*/ + currentmode.flags = flags; + if (flags & DM_SWSCALE) + currentmode.fullfill = 1; + if (flags & DM_FULLWINOW) { + var rc = getdisplay(SAEV_config).rect; + currentmode.current_width = rc.right - rc.left; + currentmode.current_height = rc.bottom - rc.top; + } + currentmode.native_width = currentmode.current_width; + currentmode.native_height = currentmode.current_height; + } + + + function open_windows(mousecapture) { + //static bool started = false; + + //changevblankthreadmode(VBLANKTH_IDLE); + + //inputdevice_unacquire(); + //wait_keyrelease(); + //reset_sound(); //ATT maybe enable + //in_sizemove = 0; + + updatewinfsmode(SAEV_config); + + //D3D_free(false); + //OGL_free(); + + //if (!DirectDraw_Start()) + // return 0; + + /*init_round = 0; + var ret = -2; + do { + if (ret < -1) { + updatemodes(); + update_gfxparams(); + } + ret = doInit(); + init_round++; + if (ret < -9) { + DirectDraw_Release(); + if (!DirectDraw_Start()) + return 0; + } + } while (ret < 0); + if (!ret) { + DirectDraw_Release(); + return ret; + }*/ + + updatemodes(); + update_gfxparams(); + var err = doInit(); + if (err != SAEE_None) { + //DirectDraw_Release() + return err; + } + + + /*var startactive = (started && mouseactive) || (!started && !currprefs.win32_start_uncaptured && !currprefs.win32_start_minimized); + var startpaused = !started && ((currprefs.win32_start_minimized && currprefs.win32_iconified_pause) || (currprefs.win32_start_uncaptured && currprefs.win32_inactive_pause && isfullscreen () <= 0)); + var startminimized = !started && currprefs.win32_start_minimized && isfullscreen () <= 0; + var input = 0; + + if (mousecapture && startactive) + setmouseactive(-1); + + var upd = 0; + if (startactive) { + setpriority(&priorities[currprefs.win32_active_capture_priority]); + upd = 2; + } else if (startminimized) { + setpriority(&priorities[currprefs.win32_iconified_priority]); + setminimized(); + input = currprefs.win32_inactive_input; + upd = 1; + } else { + setpriority(&priorities[currprefs.win32_inactive_priority]); + input = currprefs.win32_inactive_input; + upd = 2; + } + if (upd > 1)*/ + { + for (var i = 0; i < SAEC_GUI_LED_MAX; i++) + SAER.gui.flicker_led(i, -1, -1); + SAER.gui.led(SAEC_GUI_LED_POWER, SAER.gui.data.powerled, SAER.gui.data.powerled_brightness); + SAER.gui.fps(0, 0, 0); + //if (SAER.gui.data.md >= 0) SAER.gui.led(SAEC_GUI_LED_MD, 0, -1); + for (i = 0; i < 4; i++) { + if (SAEV_config.floppy.drive[i].type != SAEC_Config_Floppy_Type_None) + SAER.gui.led(SAEC_GUI_LED_DF0 + i, 0, -1); + } + } + /*if (upd > 0) { + inputdevice_acquire(TRUE); + if (!isfocus()) + inputdevice_unacquire(true, input); + } + if (startpaused) + setpaused(1);*/ + + //started = true; + return err; //ret; + } + + function close_windows() { //global + //changevblankthreadmode(VBLANKTH_IDLE); + //waitflipevent(); + //setDwmEnableMMCSS(FALSE); + //reset_sound(); //ATT maybe enable + //S2X_free(); + freevidbuffer(SAER_Playfield_gfxvidinfo.drawbuffer); + freevidbuffer(SAER_Playfield_gfxvidinfo.tempbuffer); + //DirectDraw_Release(); + doExit(); + } + + /*-----------------------------------------------------------------------*/ + /* SECT */ + /*-----------------------------------------------------------------------*/ + + function obtain_displays() { + var md = Displays[0]; + md.monitorname = "Default"; + //md.rect.right = screen.width; + //md.rect.bottom = screen.height; + md.rect.right = screen.availWidth; + md.rect.bottom = screen.availHeight; + + /*if (md.DisplayModes.length) { //picasso96 + var pr = md.DisplayModes[0]; + pr.res.width = screen.availWidth; + pr.res.height = screen.availHeight; + pr.deep = 32; //screen.colorDepth; + pr.refresh[0] = 50; + pr.refreshtype[0] = 0; + pr.name = "Default"; + pr.colormodes = RGBFF_R8G8B8; + }*/ + } + this.obtain = function() { //graphics_setup() + /*if (!screen_cs_allocated) { + InitializeCriticalSection(&screen_cs); + screen_cs_allocated = true; + }*/ + /*#ifdef PICASSO96 + InitPicasso96(); + #endif*/ + + if (!SAEV_config.video.enabled) + return SAEE_None; + + if (!document.getElementById(SAEV_config.video.id)) + return SAEE_Video_ElementNotFound; + + if (SAEV_config.video.api == SAEC_Config_Video_API_WebGL && !SAEC_info.video.webGL) { + SAEF_warn("video.obtain() 'WebGL' is not available. Falling back to 'Canvas'..."); + SAEV_config.video.api = SAEC_Config_Video_API_Canvas; + SAEV_config.video.colorMode = 5; + } + if (SAEV_config.video.api == SAEC_Config_Video_API_Canvas && !SAEC_info.video.canvas) + return SAEE_Video_RequiresCanvas; + + if (SAEV_config.video.api == SAEC_Config_Video_API_Canvas && SAEV_config.video.colorMode != 5) + SAEV_config.video.colorMode = 5; + + obtain_displays(); + return SAEE_None; + } + + + this.setup = function(mousecapture) { //graphics_init() + if (!SAEV_config.video.enabled) + return SAEE_None; + + oldtex_w = -1, oldtex_h = -1, oldtex_rtg = 0; //OWN + render_ok = false; //OWN + + //systray(hHiddenWnd, TRUE); + //systray(hHiddenWnd, FALSE); + gfxmode_reset(); + //graphics_mode_changed = 1; + return open_windows(mousecapture); + } + + this.cleanup = function() { //graphics_leave() + //changevblankthreadmode(VBLANKTH_KILL); + close_windows(); + } + + /*function graphics_reset(forced) { //global + if (forced) + display_change_requested = 2; + else // full reset if display size can't changed. + display_change_requested = SAEV_config.video.api == SAEC_Config_Video_API_WebGL ? 3 : 2; + }*/ + + + + + var oldtex_w = -1, oldtex_h = -1, oldtex_rtg = 0; + + this.target_graphics_buffer_update = function() { + //static bool graphicsbuffer_retry; + var w, h; + + //graphicsbuffer_retry = false; + if (screen_is_picasso) { + w = picasso96_state.Width > picasso_vidinfo.width ? picasso96_state.Width : picasso_vidinfo.width; + h = picasso96_state.Height > picasso_vidinfo.height ? picasso96_state.Height : picasso_vidinfo.height; + } else { + var vb = SAER_Playfield_gfxvidinfo.drawbuffer.tempbufferinuse ? SAER_Playfield_gfxvidinfo.tempbuffer : SAER_Playfield_gfxvidinfo.drawbuffer; + SAER_Playfield_gfxvidinfo.outbuffer = vb; + w = vb.outwidth; + h = vb.outheight; + } + + if (oldtex_w == w && oldtex_h == h && oldtex_rtg == screen_is_picasso) + return false; + + if (!w || !h) { + oldtex_w = w; + oldtex_h = h; + oldtex_rtg = screen_is_picasso; + return false; + } + + //S2X_free(); + + if (currentmode.flags & DM_WEBGL) { + hAmigaWnd.texture = new Texture(w, h, SAER_Playfield_gfxvidinfo.drawbuffer.pixbytes); + + /*var ctx = hAmigaWnd.ctx; + var resolutionLocation = ctx.getUniformLocation(ctx.program, "u_resolution"); + ctx.uniform2f(resolutionLocation, w, h);*/ + } + else if (currentmode.flags & DM_CANVAS) { + hAmigaWnd.surface = new Surface(w, h, 4); + hAmigaWnd.surface.imageData = hAmigaWnd.ctx.createImageData(w, h); + } + /*else if (currentmode.flags & DM_D3D) { + if (!D3D_alloctexture(w, h)) { + graphicsbuffer_retry = true; + return false; } } else { - if (!confirm('Cant\'t initialise "WebGL" nor "Canvas 2D". Continue without video-playback?')) - Fatal(SAEE_Video_Canvas_Not_Supported, null); + DirectDraw_ClearSurface(null); + }*/ + + oldtex_w = w; + oldtex_h = h; + oldtex_rtg = screen_is_picasso; + + SAEF_log("video.target_graphics_buffer_update() Buffer size (%d*%d) %s", w, h, screen_is_picasso ? "RTG" : "Native"); + + /*if ((currentmode.flags & DM_SWSCALE) && !screen_is_picasso) { + if (!S2X_init(currentmode.native_width, currentmode.native_height, currentmode.native_depth)) + return false; + }*/ + return true; + } + + /*function toggle_rtg(mode) { + if (mode == 0) { + if (!SAEV_Playfield_picasso_on) + return false; + } else if (mode > 0) { + if (SAEV_Playfield_picasso_on) + return false; + } + if (currprefs.rtgmem_type >= GFXBOARD_HARDWARE) { + return gfxboard_toggle (mode); + } else { + // can always switch from RTG to custom + if (SAEV_Playfield_picasso_requested_on && SAEV_Playfield_picasso_on) { + SAEV_Playfield_picasso_requested_on = false; + return true; + } + if (SAEV_Playfield_picasso_on) + return false; + // can only switch from custom to RTG if there is some mode active + if (picasso_is_active()) { + SAEV_Playfield_picasso_requested_on = true; + return true; + } + } + return false; + }*/ + + function toggle_fullscreen(mode) { + var v = SAEV_config.video.apmode[SAEV_Playfield_picasso_on ? 1 : 0].gfx_fullscreen; + var wfw = SAEV_Playfield_picasso_on ? wasfullwindow_p : wasfullwindow_a; + + if (mode < 0) { + // fullscreen <> window (if in fullwindow: fullwindow <> fullscreen) + if (v == SAEC_Config_Video_AP_Fullscreen_FULLWINDOW) + v = SAEC_Config_Video_AP_Fullscreen_FULLSCREEN; + else if (v == SAEC_Config_Video_AP_Fullscreen_WINDOW) + v = SAEC_Config_Video_AP_Fullscreen_FULLSCREEN; + else if (v == SAEC_Config_Video_AP_Fullscreen_FULLSCREEN) + if (wfw > 0) + v = SAEC_Config_Video_AP_Fullscreen_FULLWINDOW; + else + v = SAEC_Config_Video_AP_Fullscreen_WINDOW; + } else if (mode == 0) { + // fullscreen <> window + if (v == SAEC_Config_Video_AP_Fullscreen_FULLSCREEN) + v = SAEC_Config_Video_AP_Fullscreen_WINDOW; else - AMIGA.config.video.enabled = false; + v = SAEC_Config_Video_AP_Fullscreen_FULLSCREEN; + } else if (mode == 1) { + // fullscreen <> fullwindow + if (v == SAEC_Config_Video_AP_Fullscreen_FULLSCREEN) + v = SAEC_Config_Video_AP_Fullscreen_FULLWINDOW; + else + v = SAEC_Config_Video_AP_Fullscreen_FULLSCREEN; + } else if (mode == 2) { + // window <> fullwindow + if (v == SAEC_Config_Video_AP_Fullscreen_FULLWINDOW) + v = SAEC_Config_Video_AP_Fullscreen_WINDOW; + else + v = SAEC_Config_Video_AP_Fullscreen_FULLWINDOW; } + SAEV_config.video.apmode[SAEV_Playfield_picasso_on ? 1 : 0].gfx_fullscreen = v; + updatewinfsmode(SAEV_config); + } + this.toggle_fullscreen_real = function(mode) { + close_windows(); + toggle_fullscreen(mode); + open_windows(); + } - video = document.createElement('div'); - video.style.width = width + 'px'; - video.style.height = height + 'px'; - video.style.margin = 'auto'; - video.style.webkitTouchCallout = 'none'; - video.style.webkitUserSelect = 'none'; - video.style.khtmlUserSelect = 'none'; - video.style.mozUserSelect = 'none'; - video.style.msUserSelect = 'none'; - video.style.userSelect = 'none'; - if (AMIGA.config.video.enabled) - video.appendChild(canvas); + /*HDC gethdc (void) { + HDC hdc = 0; - div.appendChild(video); - open = true; - }; + frame_missed = frame_counted = frame_errors = 0; + frame_usage = frame_usage_avg = frame_usage_total = 0; - this.cleanup = function () { - if (open) { - div.removeChild(video); - canvas = null; - imagedata = null; - pixels = null; - video = null; - open = false; + if (OGL_isenabled ()) + return OGL_getDC (0); + if (D3D_isenabled ()) + return D3D_getDC (0); + if (FAILED(DirectDraw_GetDC(&hdc))) + hdc = 0; + return hdc; + } + + void releasehdc (HDC hdc) { + if (OGL_isenabled ()) { + OGL_getDC (hdc); + return; } - }; - - /*---------------------------------*/ - - /*this.hideCursor = function (hide) { - canvas.style.cursor = hide ? 'none' : 'auto'; - };*/ - - /*this.clear_pixels = function () { - for (var i = 0; i < size; i++) - pixels[i] = 0; + if (D3D_isenabled ()) { + D3D_getDC (hdc); + return; + } + DirectDraw_ReleaseDC(hdc); }*/ - /*---------------------------------*/ - /* Canvas 2D */ - - /*function drawpixel_2d(x, y, rgb) { - pixels[y * width + x] = rgb; + /*-----------------------------------------------------------------------*/ + + //var flushymin = 0, flushymax = 0; + //const FLUSH_DIFF = 50; + + /*function flushit(vb, lineno) { + if (SAEV_config.video.api == SAEC_Config_Video_API_Canvas) + return; + if (currentmode.flags & DM_SWSCALE) + return; + if (flushymin > lineno) { + if (flushymin - lineno > FLUSH_DIFF && flushymax != 0) { + D3D_flushtexture(flushymin, flushymax); + flushymin = currentmode.amiga_height; + flushymax = 0; + } else { + flushymin = lineno; + } + } + if (flushymax < lineno) { + if (lineno - flushymax > FLUSH_DIFF && flushymax != 0) { + D3D_flushtexture(flushymin, flushymax); + flushymin = currentmode.amiga_height; + flushymax = 0; + } else { + flushymax = lineno; + } + } }*/ - - function drawline_2d(y, data, offs) { - var yoffs = (y * width) << 2; - for (var x = 0, d = 0; x < width << 2; x += 4, d++) { - pixels[yoffs + x ] = ((data[offs + d] >> 8) & 0xf) << 4; - pixels[yoffs + x + 1] = ((data[offs + d] >> 4) & 0xf) << 4; - pixels[yoffs + x + 2] = ((data[offs + d] >> 0) & 0xf) << 4; - pixels[yoffs + x + 3] = 255; + + this.flush_line = function(vb, lineno) { + //SAEF_log("video.flush_line() %d", lineno); + //flushit(vb, lineno); + } + this.flush_block = function(vb, first, last) { + //SAEF_log("video.flush_block() %d - %d", first, last); + //flushit(vb, first); + //flushit(vb, last); + } + this.flush_screen = function(vb, a, b) { + //SAEF_log("video.flush_screen() %d - %d", a, b); + } + + var render_ok = false; //, wait_render = false; //volatile global + + this.render_screen = function(immediate) { + if (!SAEV_config.video.enabled) { + render_ok = true; + return render_ok; + } + //SAEF_log("video.render_screen() immediate %d", immediate ? 1 : 0); + render_ok = false; + //if (minimized || SAEV_Playfield_picasso_on || monitor_off || dx_islost()) + //if (SAEV_Playfield_picasso_on || dx_islost()) return render_ok; + + /*var cnt = 0; + while (wait_render) { + sleep_millis(1); + cnt++; + if (cnt > 500) + return render_ok; + }*/ + //flushymin = 0; + //flushymax = currentmode.amiga_height; + + //EnterCriticalSection(&screen_cs); + + if (currentmode.flags & DM_WEBGL) { + var ctx = hAmigaWnd.ctx; + var tex = hAmigaWnd.texture; + var x1 = 0; + var x2 = tex.width; + var y1 = 0; + var y2 = tex.height; + + if (SAER_Playfield_gfxvidinfo.drawbuffer.pixbytes == 2) + ctx.texImage2D(ctx.TEXTURE_2D, 0, ctx.RGB, tex.width, tex.height, 0, ctx.RGB, ctx.UNSIGNED_SHORT_5_6_5, new Uint16Array(tex.data)); + else + ctx.texImage2D(ctx.TEXTURE_2D, 0, ctx.RGBA, tex.width, tex.height, 0, ctx.RGBA, ctx.UNSIGNED_BYTE, new Uint8Array(tex.data)); + + ctx.bufferData(ctx.ARRAY_BUFFER, new Float32Array([x1,y1, x2,y1, x1,y2, x1,y2, x2,y1, x2,y2]), ctx.STATIC_DRAW); + ctx.drawArrays(ctx.TRIANGLES, 0, 6); + render_ok = true; + } + else if (currentmode.flags & DM_CANVAS) { + var sur = hAmigaWnd.surface; + + sur.imageData.data.set(new Uint8ClampedArray(sur.data)); + hAmigaWnd.ctx.putImageData(sur.imageData, 0, 0); + render_ok = true; + } + /* + else if (currentmode.flags & DM_D3D) { + render_ok = D3D_renderframe(immediate); + } + else if (currentmode.flags & DM_DDRAW) { + render_ok = true; + } + else if (currentmode.flags & DM_SWSCALE) { + S2X_render(); + render_ok = true; + }*/ + //LeaveCriticalSection(&screen_cs); + return render_ok; + } + + /*static void waitflipevent (void) { + while (flipevent_mode) { + if (WaitForSingleObject (flipevent2, 10) == WAIT_ABANDONED) + break; } } - - function render_2d() { - ctx.putImageData(imagedata, 0, 0); - } - - function show_2d() {} - - /*---------------------------------*/ - /* WebGL */ - - /*function drawpixel_gl(x, y, rgb) { - pixels[y * width + x] = rgb; + static void doflipevent (int mode) { + if (flipevent == NULL) + return; + waitflipevent (); + flipevent_mode = mode; + SetEvent (flipevent); }*/ - - function drawline_gl(y, data, offs) { - var yoffs = y * width; - for (var x = 0; x < width; x++) - pixels[yoffs + x] = data[offs + x] & 0xffff; + + + /*void show_screen_special (void) { + EnterCriticalSection (&screen_cs); + if (currentmode.flags & DM_D3D) + D3D_showframe_special (1); + LeaveCriticalSection (&screen_cs); + }*/ + + this.show_screen = function(mode) { + if (!SAEV_config.video.enabled) { + render_ok = false; + return; + } + /*EnterCriticalSection(&screen_cs); + if (mode == 2) { + if (currentmode.flags & DM_D3D) { + D3D_showframe_special(1); + } + LeaveCriticalSection(&screen_cs); + return; + } + if (!render_ok) { + LeaveCriticalSection(&screen_cs); + return; + } + if (currentmode.flags & DM_D3D) { + D3D_showframe(); + } + else if (currentmode.flags & DM_SWSCALE) { + if (!dx_islost() && !SAEV_Playfield_picasso_on) { + DirectDraw_Flip(1); + } + } + else if (currentmode.flags & DM_DDRAW) { + if (!dx_islost() && !SAEV_Playfield_picasso_on) + DirectDraw_Flip(1); + } + LeaveCriticalSection(&screen_cs);*/ + render_ok = false; } - - function render_gl() { - ctx.texImage2D(ctx.TEXTURE_2D, 0, ctx.RGB, width, height, 0, ctx.RGB, ctx.UNSIGNED_SHORT_5_6_5, pixels); - - var x1 = 0; - var x2 = width << (scale ? 1 : 0); - var y1 = 0; - var y2 = height << (scale ? 1 : 0); - - ctx.bufferData(ctx.ARRAY_BUFFER, new Float32Array([x1, y1, x2, y1, x1, y2, x1, y2, x2, y1, x2, y2]), ctx.STATIC_DRAW); + + this.show_screen_maybe = function(show) { + var ap = SAEV_config.video.apmode[SAEV_Playfield_picasso_on ? 1 : 0]; + if (!ap.gfx_vflip || ap.gfx_vsyncmode == 0 || !ap.gfx_vsync) { + if (show) { + this.show_screen(0); + return true; //OWN + } + return false; + } + /*#if 0 + if (ap.gfx_vflip < 0) { + doflipevent(); + return true; + } + #endif*/ + return false; } - - function show_gl() { - ctx.drawArrays(ctx.TRIANGLES, 0, 6); - } + + this.lockscr = function(vb, fullupdate) { + var ret = false; + + if (!SAEV_config.video.enabled || !isscreen()) + return ret; + + //flushymin = currentmode.amiga_height; + //flushymax = 0; + + if (currentmode.flags & DM_WEBGL) { + vb.bufmem = hAmigaWnd.texture.data; + vb.bufmem_pos = 0; + vb.rowbytes = hAmigaWnd.texture.rowbytes; + SAER_Playfield_init_row_map(); + ret = vb.bufmem !== null; + } + else if (currentmode.flags & DM_CANVAS) { + vb = SAER_Playfield_gfxvidinfo.outbuffer; + vb.bufmem = hAmigaWnd.surface.data; + vb.bufmem_pos = 0; + vb.rowbytes = hAmigaWnd.surface.rowbytes; + SAER_Playfield_init_row_map(); + ret = vb.bufmem !== null; + } + /*else if (currentmode.flags & DM_D3D) { + if (currentmode.flags & DM_SWSCALE) { + ret = true; + } else { + ret = false; + vb.bufmem = D3D_locktexture (&vb.rowbytes, NULL, fullupdate); + if (vb.bufmem) { + init_row_map(); + ret = true; + } + } + } + else if (currentmode.flags & DM_DDRAW) { + if (!DirectDraw_SurfaceLock()) { + dx_check(); + return false; + } + + vb = SAER_Playfield_gfxvidinfo.outbuffer; + vb.bufmem = DirectDraw_GetSurfacePointer(); + vb.bufmem_pos = 0; + vb.rowbytes = DirectDraw_GetSurfacePitch(); + SAER_Playfield_init_row_map(); + //clear_inhibit_frame(IHF_WINDOWHIDDEN); + ret = vb.bufmem !== null; + } + else if (currentmode.flags & DM_SWSCALE) + ret = true;*/ + + return ret; + } + + this.unlockscr = function(vb) { + if (!SAEV_config.video.enabled) + return; + + if (currentmode.flags & DM_WEBGL) { + vb.bufmem = null; + } + else if (currentmode.flags & DM_CANVAS) { + vb.bufmem = null; + } + /*else if (currentmode.flags & DM_D3D) { + if (currentmode.flags & DM_SWSCALE) { + S2X_render(); + } else { + D3D_flushtexture(flushymin, flushymax); + vb.bufmem = null; + } + D3D_unlocktexture (); + } + else if (currentmode.flags & DM_DDRAW) { + DirectDraw_SurfaceUnlock(); + //vb.bufmem = null; + } + else if (currentmode.flags & DM_SWSCALE) + return;*/ + } + + /*bool lockscr3d(struct vidbuffer *vb) { + if (currentmode.flags & DM_D3D) { + if (!(currentmode.flags & DM_SWSCALE)) { + vb.bufmem = D3D_locktexture(&vb.rowbytes, NULL, false); + if (vb.bufmem) + return true; + } + } + return false; + } + void unlockscr3d(struct vidbuffer *vb) { + if (currentmode.flags & DM_D3D) { + if (!(currentmode.flags & DM_SWSCALE)) { + D3D_unlocktexture(); + } + } + }*/ + + /*this.flush_clear_screen = function(vb) { + if (vb === null) + return; + if (this.lockscr(vb, true)) { + for (var y = 0; y < vb.height_allocated; y++) + memset(vb.bufmem + y * vb.rowbytes, 0, vb.width_allocated * vb.pixbytes); + + this.unlockscr(vb); + this.flush_screen(vb, 0, 0); + } + }*/ } +/*-----------------------------------------------------------------------*/ +/* global constants */ + +const SAEC_GUI_LED_POWER = 0; +const SAEC_GUI_LED_DF0 = 1; +const SAEC_GUI_LED_DF1 = 2; +const SAEC_GUI_LED_DF2 = 3; +const SAEC_GUI_LED_DF3 = 4; +const SAEC_GUI_LED_HD = 5; +//const SAEC_GUI_LED_CD = 6; +const SAEC_GUI_LED_FPS = 7; +const SAEC_GUI_LED_CPU = 8; +//const SAEC_GUI_LED_SND = 9; +//const SAEC_GUI_LED_MD = 10; +const SAEC_GUI_LED_MAX = 11; +//const SAEC_GUI_VISIBLE_LEDS = SAEC_GUI_LED_MAX - 1; //statusline.cpp + +/*const SAEC_GUI_LED_CD_ACTIVE = 1; +const SAEC_GUI_LED_CD_ACTIVE2 = 2; +const SAEC_GUI_LED_CD_AUDIO = 4;*/ + +/*---------------------------------*/ + +function SAEO_GUI() { + function gui_info() { + this.drive_side = 0; /* s8, floppy side */ + this.drive_motor = [false,false,false,false]; /* motor on off */ + this.drive_track = [0,0,0,0]; /* u8, rw-head track */ + this.drive_writing = [false,false,false,false]; /* drive is writing */ + this.drive_disabled = [false,false,false,false]; /* drive is disabled */ + this.df = ["","","",""]; /* inserted image */ + this.crc32 = [0,0,0,0]; /* u32, crc32 of image */ + + this.powerled = false; /* state of power led */ + this.powerled_brightness = 0; /* u8, 0 to 255 */ + this.hd = 0; /* s8, harddrive */ + this.cd = 0; /* s8, CD */ + this.md = 0; /* s8, CD32 or CDTV internal storage */ + + this.cpu_halted = 0; + + this.fps = 0; + this.fps_color = 0; + this.idle = 0; + + this.sndbuf = 0; + this.sndbuf_status = 0; + } + this.data = null; //gui_data + //this.data = new gui_info(); //gui_data + + var resetcounter = null; + //var resetcounter = new Array(SAEC_GUI_LED_MAX); + + /*---------------------------------*/ + + this.setup = function() { //gui_init() + this.data = new gui_info(); + this.data.cd = -1; + this.data.hd = -1; + this.data.md = -1; //(currprefs.cs_cd32nvram || currprefs.cs_cdtvram) ? 0 : -1; + + resetcounter = new Array(SAEC_GUI_LED_MAX); + SAEF_memset(resetcounter,0, 0, SAEC_GUI_LED_MAX); + return SAEE_None; //1 + } + //this.cleanup = function() {} //gui_exit() + //this.update = function() { return true; } //gui_update() + //this.lock = function() {} //gui_lock() + //this.unlock = function() {} //gui_unlock() + //this.filename = function(num, name) {} //gui_filename() + /*this.gui_disk_image_change = function(unitnum, name, writeprotected) { + #ifdef RETROPLATFORM + rp_disk_image_change(unitnum, name, writeprotected); + #endif + }*/ + + this.flicker_led2 = function(led, unitnum, status) { + if (led == SAEC_GUI_LED_HD) + var old = this.data.hd; + /*else if (led == SAEC_GUI_LED_CD) + var old = this.data.cd; + else if (led == SAEC_GUI_LED_MD) + var old = this.data.md;*/ + else + return; + + if (status < 0) { + if (old < 0) + this.led(led, -1, -1); + else + this.led(led, 0, -1); + return; + } + if (status == 0 && old < 0) { + if (led == SAEC_GUI_LED_HD) + this.data.hd = 0; + /*else if (led == SAEC_GUI_LED_CD) + this.data.cd = 0; + else if (led == SAEC_GUI_LED_MD) + this.data.md = 0;*/ + + resetcounter[led] = 0; + this.led(led, 0, -1); + return; + } + if (status == 0) { + resetcounter[led]--; + if (resetcounter[led] > 0) + return; + } + /*#ifdef RETROPLATFORM + if (unitnum >= 0) { + if (led == SAEC_GUI_LED_HD) + rp_hd_activity (unitnum, status ? 1 : 0, status == 2 ? 1 : 0); + else if (led == SAEC_GUI_LED_CD) + rp_cd_activity (unitnum, status); + } + #endif*/ + + if (led == SAEC_GUI_LED_HD) + this.data.hd = status; + /*else if (led == SAEC_GUI_LED_CD) + this.data.cd = status; + else if (led == SAEC_GUI_LED_MD) + this.data.md = status;*/ + + resetcounter[led] = 6; + if (old != status) + this.led(led, status, -1); + } + + this.flicker_led = function(led, unitnum, status) { //gui_flicker_led() + if (led < 0) { + this.flicker_led2(SAEC_GUI_LED_HD, 0, 0); + //this.flicker_led2(SAEC_GUI_LED_CD, 0, 0); + //if (this.data.md >= 0) this.flicker_led2(SAEC_GUI_LED_MD, 0, 0); + } else + this.flicker_led2(led, unitnum, status); + } + + this.fps = function(fps, idle, color) { //gui_fps() + this.data.fps = fps; + this.data.idle = idle; + this.data.fps_color = color; + this.led(SAEC_GUI_LED_FPS, 0, -1); + this.led(SAEC_GUI_LED_CPU, 0, -1); + //this.led(SAEC_GUI_LED_SND, (this.data.sndbuf_status > 1 || this.data.sndbuf_status < 0) ? 0 : 1, -1); + } + + this.led = function(led, on, brightness) { //gui_led() + var writing = 0; + + /*indicator_leds(led, on); + + #ifdef LOGITECHLCD + lcd_update (led, on); + #endif + + #ifdef RETROPLATFORM + if (led >= SAEC_GUI_LED_DF0 && led <= SAEC_GUI_LED_DF3 && !this.data.drive_disabled[led - SAEC_GUI_LED_DF0]) { + rp_floppy_track(led - SAEC_GUI_LED_DF0, this.data.drive_track[led - SAEC_GUI_LED_DF0]); + writing = this.data.drive_writing[led - SAEC_GUI_LED_DF0]; + } + rp_update_leds(led, on, brightness, writing); + #endif*/ + + //if (!hStatusWnd) return; + + if (led >= SAEC_GUI_LED_DF0 && led <= SAEC_GUI_LED_DF3) { + if (this.data.drive_writing[led - 1]) + writing = 1; + + SAEV_config.hook.led.df(led - 1, this.data.drive_disabled[led - 1], this.data.drive_track[led - 1], this.data.drive_side, on ? (writing ? 2 : 1) : 0); + } + else if (led == SAEC_GUI_LED_POWER) { + SAEV_config.hook.led.power(on); + } + else if (led == SAEC_GUI_LED_HD) { + if (on > 1) + writing = 1; + + SAEV_config.hook.led.hd(on ? (writing ? 2 : 1) : 0); + } + /*else if (led == SAEC_GUI_LED_CD) { + }*/ + else if (led == SAEC_GUI_LED_FPS) { + on = 1; + on = SAER.paused ? 0 : 1; + SAEV_config.hook.led.fps(this.data.fps, SAER.paused); + } + else if (led == SAEC_GUI_LED_CPU) { + on = SAER.paused ? 0 : 1; + SAEV_config.hook.led.cpu(this.data.idle, SAER.paused); + } + /*else if (led == SAEC_GUI_LED_SND && this.data.drive_disabled[3]) { + } + else if (led == SAEC_GUI_LED_MD) { + }*/ + + if (on < 0) + return; + + //output + } + + //const LED_STRING_WIDTH = 40; + //var drive_text = new Array(SAEC_GUI_LED_MAX); + //for (vi = 0; vi < SAEC_GUI_LED_MAX; vi++) drive_text[vi] = ""; + + this.led_string = function(led, on, brightness) { //gui_led() + //static TCHAR drive_text[SAEC_GUI_LED_MAX * LED_STRING_WIDTH]; + //static TCHAR dfx[4][300]; + //var ptr = null, tt = null, p = null; //TCHAR * + var pos = -1; + var writing = 0, playing = 0, active2 = 0; + var center = 0; + + /*indicator_leds(led, on); + + #ifdef LOGITECHLCD + lcd_update (led, on); + #endif + + #ifdef RETROPLATFORM + if (led >= SAEC_GUI_LED_DF0 && led <= SAEC_GUI_LED_DF3 && !this.data.drive_disabled[led - SAEC_GUI_LED_DF0]) { + rp_floppy_track (led - SAEC_GUI_LED_DF0, this.data.drive_track[led - SAEC_GUI_LED_DF0]); + writing = this.data.drive_writing[led - SAEC_GUI_LED_DF0]; + } + rp_update_leds (led, on, brightness, writing); + #endif*/ + + //if (!hStatusWnd) return; + + //tt = null; + if (led >= SAEC_GUI_LED_DF0 && led <= SAEC_GUI_LED_DF3) { + pos = 6 + (led - SAEC_GUI_LED_DF0); + //ptr = drive_text + pos * LED_STRING_WIDTH; + if (this.data.drive_disabled[led - 1]) + drive_text[pos] = ""; + else + drive_text[pos] = sprintf("%02d", this.data.drive_track[led - 1]); + + /*p = this.data.df[led - 1]; + var j = _tcslen (p) - 1; + if (j < 0) + j = 0; + while (j > 0) { + if (p[j - 1] == '\\' || p[j - 1] == '/') + break; + j--; + } + tt = dfx[led - 1]; + tt[0] = 0; + if (_tcslen (p + j) > 0) + _stprintf (tt, _T("%s [CRC=%08X]"), p + j, this.data.crc32[led - 1]);*/ + + center = 1; + if (this.data.drive_writing[led - 1]) + writing = 1; + + SAEV_config.hook.led.df(led - 1, this.data.drive_disabled[led - 1], this.data.drive_track[led - 1], this.data.drive_side, on ? (writing ? 2 : 1) : 0); + } + else if (led == SAEC_GUI_LED_POWER) { + pos = 3; + //ptr = _tcscpy(drive_text + pos * LED_STRING_WIDTH, _T("Power")); + drive_text[pos] = "Power"; + center = 1; + + SAEV_config.hook.led.power(on); + } + else if (led == SAEC_GUI_LED_HD) { + pos = 4; + //ptr = _tcscpy(drive_text + pos * LED_STRING_WIDTH, _T("HD")); + drive_text[pos] = "HD"; + center = 1; + if (on > 1) + writing = 1; + + SAEV_config.hook.led.hd(on ? (writing ? 2 : 1) : 0); + } + /*else if (led == SAEC_GUI_LED_CD) { + pos = 5; + //ptr = _tcscpy(drive_text + pos * LED_STRING_WIDTH, _T("CD")); + drive_text[pos] = "CD"; + center = 1; + if (on >= 0) { + if (on & SAEC_GUI_LED_CD_AUDIO) + playing = 1; + else if (on & SAEC_GUI_LED_CD_ACTIVE2) + active2 = 1; + on &= 1; + } + }*/ + else if (led == SAEC_GUI_LED_FPS) { + //double fps = (double)this.data.fps / 10.0; + var fps = this.data.fps; + pos = 2; + //ptr = drive_text + pos * LED_STRING_WIDTH; + //if (fps > 999.9) fps = 999.9; + /*if (SAEV_Playfield_picasso_on) + drive_text[pos] = sprintf("%.1f [%.1f]", p96vblank, fps); + else*/ + drive_text[pos] = sprintf("FPS: %.1f", fps); + + if (this.data.cpu_halted > 0) { + drive_text[pos] = sprintf("HALT%d", this.data.cpu_halted); + center = 1; + } + if (SAER.paused) { + drive_text[pos] = "PAUSED"; + center = 1; + } + on = 1; + + SAEV_config.hook.led.fps(this.data.fps, SAER.paused); + } + else if (led == SAEC_GUI_LED_CPU) { + var m68klabelchange = false; + var m68label = "CPU"; + + pos = 1; + //ptr = drive_text + pos * LED_STRING_WIDTH; + //ptr[0] = 0; + drive_text[pos] = ""; + + //p = ptr; + /*if (is_ppc_cpu(&currprefs)) { + _tcscat(ptr, _T("PPC: ")); + if (ppc_state == PPC_STATE_ACTIVE) + _tcscat(ptr, _T("RUN")); + else if (ppc_state == PPC_STATE_CRASH) + _tcscat(ptr, _T("CRASH")); + else if (ppc_state == PPC_STATE_SLEEP) + _tcscat(ptr, _T("SLEEP")); + else + _tcscat(ptr, _T("STOP")); + _tcscat(ptr, _T(" ")); + p = ptr + _tcslen(ptr); + m68label = _T("68k"); + m68klabelchange = true; + } + int state = is_x86_cpu(&currprefs); + if (state > 0) { + _tcscat(ptr, _T("x86: ")); + if (state == X86_STATE_ACTIVE) + _tcscat(ptr, _T("RUN")); + else + _tcscat(ptr, _T("STOP")); + _tcscat(ptr, _T(" ")); + p = ptr + _tcslen(ptr); + m68label = _T("68k"); + m68klabelchange = true; + }*/ + if (this.data.cpu_halted < 0) { + if (!m68klabelchange) + drive_text[pos] = "STOP"; + else + drive_text[pos] = "68k: STOP"; + } else { + //drive_text[pos] = sprintf("%s: %.0f%%", m68label, (double)((this.data.idle) / 10.0)); + drive_text[pos] = sprintf("%s: %.0f%%", m68label, this.data.idle); + } + on = SAER.paused ? 0 : 1; + + SAEV_config.hook.led.cpu(this.data.idle, SAER.paused); + } + /*else if (led == SAEC_GUI_LED_SND && this.data.drive_disabled[3]) { + pos = 0; + ptr = drive_text + pos * LED_STRING_WIDTH; + if (this.data.sndbuf_status < 3 && !SAER.paused && !sound_paused()) { + _stprintf (ptr, _T("SND: %+.0f%%"), (double)((this.data.sndbuf) / 10.0)); + } else { + _tcscpy (ptr, _T("SND: -")); + center = 1; + on = 0; + } + } + else if (led == SAEC_GUI_LED_MD) { + pos = 6 + 3; + ptr = _tcscpy(drive_text + pos * LED_STRING_WIDTH, _T("NV")); + }*/ + + if (on < 0) + return; + + //SAEF_log("%d %s %d", pos, drive_text[pos], on); + + /*var type = SBT_OWNERDRAW; + if (pos >= 0) { + ptr[_tcslen (ptr) + 1] = 0; + if (center) + ptr[_tcslen (ptr) + 1] |= 1; + if (on) { + ptr[_tcslen (ptr) + 1] |= 2; + type |= SBT_POPOUT; + } + if (writing) + ptr[_tcslen (ptr) + 1] |= 4; + if (playing) + ptr[_tcslen (ptr) + 1] |= 8; + if (active2) + ptr[_tcslen (ptr) + 1] |= 16; + pos += window_led_joy_start; + PostMessage (hStatusWnd, SB_SETTEXT, (WPARAM)((pos + 1) | type), (LPARAM)ptr); + if (tt !== null) + PostMessage (hStatusWnd, SB_SETTIPTEXT, (WPARAM)(pos + 1), (LPARAM)tt); + }*/ + } + + //void gui_handle_events (void); + //void gui_display (int shortcut); +}