├── .gitignore
├── Makefile
├── README.md
├── disass.htm
├── disass.js
├── example.css
├── example.htm
├── example.js
├── example2.htm
├── favicon.ico
├── gpl.htm
├── images
└── logo.png
├── index.css
├── index.htm
├── index.js
├── readme.htm
└── sae
├── amiga.js
├── audio.js
├── autoconf.js
├── blitter.js
├── cia.js
├── config.js
├── copper.js
├── cpu.js
├── custom.js
├── disassembler.js
├── disk.js
├── dms.js
├── dongle.js
├── events.js
├── expansion.js
├── filesys.js
├── gayle.js
├── hardfile.js
├── ide.js
├── input.js
├── m68k.js
├── memory.js
├── playfield.js
├── prototypes.js
├── roms.js
├── rtc.js
├── serpar.js
├── utils.js
└── video.js
/.gitignore:
--------------------------------------------------------------------------------
1 | *.adf
2 | db/tools/index.htm
3 | db/index.htm
4 | db/games/index.htm
5 | db/demos_aga/index.htm
6 | db/demos/index.htm
7 | *.bin
8 | scriptedamigaemulator.js
9 | scriptedamigaemulator.js.map
10 |
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 | scriptedamigaemulator.js: sae/prototypes.js sae/utils.js sae/dms.js sae/config.js sae/roms.js sae/memory.js sae/autoconf.js sae/expansion.js sae/events.js sae/gayle.js sae/ide.js sae/filesys.js sae/hardfile.js sae/input.js sae/serial.js sae/custom.js sae/blitter.js sae/copper.js sae/playfield.js sae/video.js sae/audio.js sae/cia.js sae/disk.js sae/rtc.js sae/m68k.js sae/cpu.js sae/amiga.js
2 | closure-compiler --language_in=ECMASCRIPT6 --language_out ES5 $^ --js_output_file $@ --create_source_map $@.map
3 | printf "/*\n//@ sourceMappingURL=%b\n*/" $@.map >> $@
4 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | Scripted Amiga Emulator
2 | =======================
3 |
4 | Amiga Emulator in javascript and HTML5.
5 |
6 | Visit https://scriptedamigaemulator.net
--------------------------------------------------------------------------------
/disass.htm:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | SAE - Scripted Amiga Emulator
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 | JavaScript is disabled or not supported!
20 |
21 |
22 |
23 |
24 |
25 |
26 | Here you can use the internal disassembler. Code-types are from 68000-68030, no FPU, no MMU.
27 |
Note: No files or informations about files are transferred to the internet. Disassembling is done in the browser, using javascript.
28 |
29 |
39 |
40 |
78 |
79 |
80 |
81 |
82 |
88 |
89 |
90 |
91 |
--------------------------------------------------------------------------------
/disass.js:
--------------------------------------------------------------------------------
1 | /*-------------------------------------------------------------------------
2 | | SAE - Scripted Amiga Emulator
3 | | https://github.com/naTmeg/ScriptedAmigaEmulator
4 | |
5 | | Copyright (C) 2012 Rupert Hausberger
6 | |
7 | | This program is free software; you can redistribute it and/or
8 | | modify it under the terms of the GNU General Public License
9 | | as published by the Free Software Foundation; either version 2
10 | | of the License, or (at your option) any later version.
11 | |
12 | | This program is distributed in the hope that it will be useful,
13 | | but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | | GNU General Public License for more details.
16 | |
17 | | Note: This file does not contain any emulator-code.
18 | -------------------------------------------------------------------------*/
19 |
20 | var sda = null; /* SDA instance */
21 | var cfg = null; /* reference to the config-object */
22 |
23 |
24 | var filesize = 0;
25 |
26 | var showAddr = true;
27 | var showCode = true;
28 | var upperCase = false;
29 |
30 | var result = [];
31 |
32 | /*---------------------------------*/
33 |
34 | function isHex(str) {
35 | var str_uc = str.toUpperCase();
36 | for (var i = 0; i < str_uc.length; i++) {
37 | var chr = str_uc.charCodeAt(i);
38 | if (!((chr >= 48 && chr <= 57) || (chr >= 65 && chr <= 70)))
39 | return false;
40 | }
41 | return true;
42 | }
43 |
44 | /*---------------------------------*/
45 |
46 | function getSelectValue(id) {
47 | var e = document.getElementById(id);
48 | for (var i = 0; i < e.length; i++) {
49 | if (e[i].selected) return e[i].value;
50 | }
51 | return false;
52 | }
53 |
54 | /*---------------------------------*/
55 |
56 | function loadFile(e, callback) {
57 | var reader = new FileReader();
58 | reader.onload = callback;
59 | reader.readAsBinaryString(e);
60 | }
61 |
62 | /*---------------------------------*/
63 |
64 | function result2text() {
65 | var i, j, text = "";
66 | for (i = 0; i < result.length; i++) {
67 | var addr = result[i][0];
68 | var code = result[i][1];
69 | var words = result[i][2];
70 | var inst = result[i][3];
71 |
72 | if (showAddr)
73 | text += sprintf(upperCase ? "$%06X " : "$%06x ", addr);
74 | if (showCode) {
75 | for (j = 0; j < words; j++) text += sprintf(upperCase ? "%04X " : "%04x ", code[j]);
76 | //for (j = words; j < 5; j++) text += " ";
77 | for (j = words; j < 5; j++) text += " ";
78 | }
79 | text += upperCase ? inst.toUpperCase() : inst;
80 | //text += " ";
81 | text += "\n";
82 |
83 | if (addr + words*2 >= filesize) break;
84 | }
85 | return text;
86 | }
87 |
88 | /*---------------------------------*/
89 |
90 | function init() {
91 | try {
92 | sda = new ScriptedDisAssembler();
93 | cfg = sda.getConfig(); /* reference to config */
94 | //console.log(cfg);
95 | } catch(e) {
96 | throw e;
97 | }
98 | }
99 |
100 | function disass() {
101 | try {
102 | result = sda.disassemble();
103 | //console.log(result);
104 |
105 | document.getElementById("disass_code").value = result2text();
106 | document.getElementById("disass_cfg").style.display = "table";
107 | document.getElementById("disass_code").style.display = "inline";
108 | } catch(e) {
109 | throw e;
110 | }
111 | }
112 |
113 | /*---------------------------------*/
114 |
115 | function updFile() {
116 | var e = document.getElementById("cfg_file").files[0];
117 | if (!e) return;
118 |
119 | loadFile(e, function (event) {
120 | cfg.code = event.target.result;
121 | cfg.offset = 0;
122 |
123 | filesize = event.target.result.length;
124 |
125 | var fn = document.getElementById("cfg_filename");
126 | fn.className = "";
127 | fn.innerHTML = e.name;
128 | document.getElementById("cfg_offset").value = "0";
129 |
130 | disass();
131 | });
132 | }
133 |
134 | function updOffset() {
135 | var offset = document.getElementById("cfg_offset");
136 | if (isHex(offset.value)) {
137 | var newoffset = parseInt(offset.value, 16);
138 |
139 | if (newoffset < filesize) {
140 | cfg.offset = newoffset;
141 | disass();
142 | } else {
143 | alert(sprintf("The value at 'Offset' is behing the file-size. (max $%x)", filesize - 1));
144 | offset.focus();
145 | }
146 | } else {
147 | alert("The value at 'Offset' in not a hexadecimal number.");
148 | offset.focus();
149 | }
150 | }
151 |
152 | function updLimit() {
153 | var limit = document.getElementById("cfg_limit");
154 | //if (isDec(limit.value)) {
155 | cfg.limit = parseInt(limit.value);
156 | disass();
157 | /*} else {
158 | alert("The value at "Limit" in not a decimal number.");
159 | limit.focus();
160 | }*/
161 | }
162 |
163 | function updNext() {
164 | var addr = result[result.length - 1][0];
165 | var words = result[result.length - 1][2];
166 |
167 | cfg.offset = addr + words*2;
168 | document.getElementById("cfg_offset").value = sprintf("%x", cfg.offset);
169 | disass();
170 | }
171 |
172 | function updRadix() {
173 | cfg.radix = parseInt(getSelectValue("cfg_radix"));
174 | disass();
175 | }
176 | function updPrefx() {
177 | cfg.prefx = parseInt(getSelectValue("cfg_prefx")) == 1 ? "$" : "0x";
178 | disass();
179 | }
180 | function updWidth() {
181 | cfg.width = parseInt(getSelectValue("cfg_width"));
182 | disass();
183 | }
184 |
185 | function updCase() {
186 | upperCase = document.getElementById("cfg_case").checked;
187 | disass();
188 | }
189 |
190 | function updReloc() {
191 | cfg.reloc = document.getElementById("cfg_reloc").checked;
192 | disass();
193 | }
194 |
195 | function updShowAddr() {
196 | showAddr = document.getElementById("cfg_showAddr").checked;
197 | disass();
198 | }
199 | function updShowCode() {
200 | showCode = document.getElementById("cfg_showCode").checked;
201 | disass();
202 | }
203 |
--------------------------------------------------------------------------------
/example.css:
--------------------------------------------------------------------------------
1 | /*-------------------------------------------------------------------------
2 | | SAE - Scripted Amiga Emulator
3 | | https://github.com/naTmeg/ScriptedAmigaEmulator
4 | |
5 | | Copyright (C) 2012-2016 Rupert Hausberger
6 | |
7 | | This program is free software; you can redistribute it and/or
8 | | modify it under the terms of the GNU General Public License
9 | | as published by the Free Software Foundation; either version 2
10 | | of the License, or (at your option) any later version.
11 | |
12 | | This program is distributed in the hope that it will be useful,
13 | | but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | | GNU General Public License for more details.
16 | -------------------------------------------------------------------------*/
17 |
18 | a:link { color:#24c; text-decoration:none; }
19 | a:visited { color:#24c; text-decoration:none; }
20 | a:hover { color:#24c; text-decoration:underline; }
21 |
22 | body {
23 | top:0;
24 | left:0;
25 | margin:0;
26 | padding:0;
27 | font-family:Verdana;
28 | font-size:13px;
29 | background-color:#f8f8f8;
30 | -webkit-touch-callout:none;
31 | -webkit-user-select:none;
32 | -khtml-user-select:none;
33 | -moz-user-select:none;
34 | -ms-user-select:none;
35 | user-select:none;
36 | }
37 |
38 | table {
39 | white-space:nowrap;
40 | }
41 |
42 | /*---------------------------------*/
43 |
44 | .gray { color:gray; }
45 | .green { color:green; }
46 | .orange { color:orange; }
47 | .red { color:red; }
48 |
49 | .alt { text-align:left; vertical-align:top; }
50 | .alm { text-align:left; vertical-align:middle; }
51 | .alb { text-align:left; vertical-align:bottom; }
52 |
53 | .act { text-align:center; vertical-align:top; }
54 | .acm { text-align:center; vertical-align:middle; }
55 | .acb { text-align:center; vertical-align:bottom; }
56 |
57 | .art { text-align:right; vertical-align:top; }
58 | .arm { text-align:right; vertical-align:middle; }
59 | .arb { text-align:right; vertical-align:bottom; }
60 |
61 |
62 | .info {
63 | font-size:11px;
64 | color:dimgray;
65 | }
66 | .warn {
67 | font-size:11px;
68 | color:red;
69 | }
70 |
71 | .noscript {
72 | margin:auto;
73 | padding:4px;
74 | font-size:17px;
75 | font-weight:bold;
76 | text-align:center;
77 | color:red;
78 | }
79 |
--------------------------------------------------------------------------------
/example.htm:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | SAE - Scripted Amiga Emulator
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 | JavaScript is disabled or not supported!
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 | Status
56 |
57 |
58 |
59 | PWR
60 | HD
61 | 0
62 | 0
63 | 0
64 | 0
65 | 0
66 | 0
67 |
68 |
69 |
70 |
71 |
72 |
73 | Config
74 |
75 |
134 |
135 |
136 |
137 |
138 | Controls
139 |
140 |
141 |
142 | Start
143 | Stop
144 | Reset
145 | Pause
146 | Mute
147 | Screen
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 | Output
156 |
157 |
158 |
159 |
160 |
161 |
165 |
166 |
167 |
168 |
169 |
170 |
171 |
172 |
173 |
--------------------------------------------------------------------------------
/example.js:
--------------------------------------------------------------------------------
1 | /*-------------------------------------------------------------------------
2 | | SAE - Scripted Amiga Emulator
3 | | https://github.com/naTmeg/ScriptedAmigaEmulator
4 | |
5 | | Copyright (C) 2012 Rupert Hausberger
6 | |
7 | | This program is free software; you can redistribute it and/or
8 | | modify it under the terms of the GNU General Public License
9 | | as published by the Free Software Foundation; either version 2
10 | | of the License, or (at your option) any later version.
11 | |
12 | | This program is distributed in the hope that it will be useful,
13 | | but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | | GNU General Public License for more details.
16 | |
17 | | Note: This file does not contain any emulator-code.
18 | -------------------------------------------------------------------------*/
19 |
20 | var sae = null; /* SAE instance */
21 | var cfg = null; /* Reference to the config-object */
22 | var inf = null; /* Reference to the info-object */
23 |
24 | var running = false; /* Is the emualtion currently running? */
25 | var paused = false; /* Is the emualtion currently paused? */
26 | var screened = false; /* Is the video-output currently fullscreen? */
27 | var muted = false; /* Is the audio-output currently muted? */
28 |
29 | /*-----------------------------------------------------------------------*/
30 | /* Helpers */
31 |
32 | function getSelect(id, asString) {
33 | if (typeof asString == "undefined") asString = false;
34 | var e = document.getElementById(id);
35 | for (var i = 0; i < e.length; i++) {
36 | if (e[i].selected)
37 | return asString ? e[i].value : Number(e[i].value);
38 | }
39 | return false;
40 | }
41 |
42 | function setSelect(id, v) {
43 | var e = document.getElementById(id);
44 | var vs = String(v);
45 | for (var i = 0; i < e.length; i++) {
46 | if (e[i].value === vs) {
47 | e[i].selected = true;
48 | return;
49 | }
50 | }
51 | }
52 |
53 | function styleDisplayInline(id, show) {
54 | var e = document.getElementById(id);
55 | e.style.display = show ? "inline" : "none";
56 | }
57 |
58 | function switchPauseResume(p) {
59 | var e = document.getElementById("controls_pr");
60 | if (p) {
61 | e.innerHTML = "Resume";
62 | e.onclick = function() { pause(false); };
63 | } else {
64 | e.innerHTML = "Pause";
65 | e.onclick = function() { pause(true); };
66 | }
67 | }
68 |
69 | function switchScreenWindow(s) {
70 | var e = document.getElementById("controls_sw");
71 | if (s) {
72 | e.innerHTML = "Window";
73 | e.onclick = function() { screen(false); };
74 | } else {
75 | e.innerHTML = "Screen";
76 | e.onclick = function() { screen(true); };
77 | }
78 | }
79 |
80 | function switchMutePlay(m) {
81 | var e = document.getElementById("controls_mp");
82 | if (m) {
83 | e.innerHTML = "Play";
84 | e.onclick = function() { mute(false); };
85 | } else {
86 | e.innerHTML = "Mute";
87 | e.onclick = function() { mute(true); };
88 | }
89 | }
90 |
91 | function saee2text(err) {
92 | switch (err) {
93 | case SAEE_AlreadyRunning: return "The emulator is already running.";
94 | case SAEE_NotRunning: return "The emulator is not running.";
95 | case SAEE_NoTimer: return "No timing-functions avail. Please upgrade your browser.";
96 | case SAEE_NoMemory: return "Out of memory.";
97 | case SAEE_Assert: return "Assertiation failed.";
98 | case SAEE_Internal: return "Internal emulator error.";
99 | case SAEE_Config_Invalid: return "Invalid configuration.";
100 | case SAEE_Config_Compressed: return "A ZIP file was detected. Compressed files are not yet supported.";
101 | case SAEE_CPU_Internal: return "Internal CPU-error.";
102 | case SAEE_CPU_Requires68020: return "The selected kickstart-rom does require a 68020 and 32bit address-space";
103 | case SAEE_CPU_Requires680EC20: return "The selected kickstart-rom does require a 68020.";
104 | case SAEE_CPU_Requires68030: return "The selected kickstart-rom does require a 68030.";
105 | case SAEE_CPU_Requires68040: return "The selected kickstart-rom does require a 68040/68060.";
106 | case SAEE_Memory_NoKickstartRom: return "The kickstart-rom is missing.";
107 | case SAEE_Memory_NoExtendedRom: return "An extended-rom is required but missing.\n\nGo to the ROM-page and select a rom from disk...";
108 | case SAEE_Memory_RomSize: return "The kickstart- or extended-rom does have an invalid size.";
109 | case SAEE_Memory_RomKey: return "A ROM-keyfile is required. (Cloanto)";
110 | case SAEE_Memory_RomDecode: return "Invalid ROM-keyfile. (Cloanto)";
111 | case SAEE_Memory_RomChecksum: return "Checksum-error at the kickstart- or extended-rom.";
112 | case SAEE_Memory_RomUnknown: return "Unknown ROM.";
113 | case SAEE_Video_ElementNotFound: return "Video DIV-element not found. Check 'cfg.video.id'";
114 | case SAEE_Video_RequiresCanvas: return "This browser does not support 'Canvas'. Please upgrade to an actual version.";
115 | case SAEE_Video_RequiresWegGl: return "This browser does not support 'WebGL'. Please upgrade to an actual version.";
116 | case SAEE_Video_ComphileShader: return "Can not compile the required shader-program.";
117 | case SAEE_Video_LinkShader: return "Can not link the required shader-program.";
118 | case SAEE_Video_RequiresFullscreen: return "This browser does not support the 'Fullscreen-API'. Please upgrade to an actual version.";
119 | case SAEE_Audio_RequiresWebAudio: return "This browser does not support 'WebAudio'. Please upgrade to an actual version.";
120 | default: return "("+err+")";
121 | }
122 | }
123 |
124 | function loadFile(e, callback) {
125 | var reader = new FileReader();
126 | reader.onload = callback;
127 | reader.readAsBinaryString(e);
128 | }
129 |
130 | /*---------------------------------*/
131 | /* CRC-32 checksumming */
132 |
133 | const crc32Table = (function() {
134 | var table = new Uint32Array(256);
135 | var n, c, k;
136 |
137 | for (n = 0; n < 256; n++) {
138 | c = n;
139 | for (k = 0; k < 8; k++)
140 | c = ((c >>> 1) ^ (c & 1 ? 0xedb88320 : 0)) >>> 0;
141 | table[n] = c;
142 | }
143 | return table;
144 | })();
145 |
146 | function crc32(data) {
147 | var length = data.length;
148 | var offset = 0;
149 | var crc = 0xffffffff;
150 |
151 | while (length-- > 0)
152 | crc = crc32Table[(crc ^ data.charCodeAt(offset++)) & 0xff] ^ (crc >>> 8);
153 |
154 | return (crc ^ 0xffffffff) >>> 0;
155 | }
156 |
157 | if (crc32("The quick brown fox jumps over the lazy dog") != 0x414fa339)
158 | alert("CRC32-hash testing failed. SAE will not work. This is an internal bug!?");
159 |
160 | /*-----------------------------------------------------------------------*/
161 | /* Config */
162 |
163 | function fixConfig() {
164 | /* video */
165 | if (cfg.video.enabled) {
166 | if (!inf.video.canvas && !inf.video.webGL)
167 | cfg.video.enabled = false;
168 | else if (SAEV_config.video.api == SAEC_Config_Video_API_WebGL && !inf.video.webGL)
169 | SAEV_config.video.api = SAEC_Config_Video_API_Canvas;
170 | }
171 | /* audio */
172 | if (cfg.audio.mode >= SAEC_Config_Audio_Mode_On) {
173 | if (!inf.audio.webAudio)
174 | cfg.audio.mode = SAEC_Config_Audio_Mode_Off_Emul;
175 | }
176 | }
177 |
178 | function setRomName() {
179 | var e = document.getElementById("cfg_rom_name");
180 | if (cfg.memory.rom.size) {
181 | e.className = "";
182 | e.innerHTML = cfg.memory.rom.name;
183 | styleDisplayInline("cfg_rom_remove", 1);
184 | } else {
185 | e.className = "red";
186 | e.innerHTML = "<unset> (required)";
187 | styleDisplayInline("cfg_rom_remove", 0);
188 | document.getElementById("cfg_rom_file").value = "";
189 | }
190 | }
191 |
192 | function setFloppyName(n) {
193 | var e = document.getElementById("cfg_df"+n+"_name");
194 | if (cfg.floppy.drive[n].file.size) {
195 | e.className = "";
196 | e.innerHTML = cfg.floppy.drive[n].file.name;
197 | styleDisplayInline("cfg_df"+n+"_eject", 1);
198 | } else {
199 | e.className = "gray";
200 | e.innerHTML = "<unset>";
201 | styleDisplayInline("cfg_df"+n+"_eject", 0);
202 | document.getElementById("cfg_df"+n+"_file").value = "";
203 | }
204 | }
205 |
206 | function setConfig() {
207 | fixConfig();
208 | setSelect("cfg_ntsc", cfg.chipset.ntsc ? 1 : 0);
209 | setRomName();
210 | setFloppyName(0);
211 | setFloppyName(1);
212 | switch (cfg.video.hresolution) {
213 | case SAEC_Config_Video_HResolution_LoRes:
214 | setSelect("cfg_res", 1);
215 | break;
216 | case SAEC_Config_Video_HResolution_HiRes:
217 | setSelect("cfg_res", 2);
218 | break;
219 | case SAEC_Config_Video_HResolution_SuperHiRes:
220 | setSelect("cfg_res", 3);
221 | break;
222 | }
223 | }
224 |
225 | /*---------------------------------*/
226 |
227 | function getConfig() {
228 | var model = SAEC_Model_A2000; /* Default model after page-load*/
229 | var modelSubConfig = 0; /* See config.js */
230 |
231 | switch (getSelect("cfg_model", true)) {
232 | case "A500": model = SAEC_Model_A500; break;
233 | case "A500P": model = SAEC_Model_A500P; break;
234 | case "A600": model = SAEC_Model_A600; break;
235 | case "A1000": model = SAEC_Model_A1000; break;
236 | case "A1200": model = SAEC_Model_A1200; break;
237 | case "A2000": model = SAEC_Model_A2000; break;
238 | case "A3000": model = SAEC_Model_A3000; break;
239 | case "A4000": model = SAEC_Model_A4000; break;
240 | case "A4000T": model = SAEC_Model_A4000T; break;
241 | /* future. do not use. cd-emulation is not implemented yet.
242 | case "CDTV": model = SAEC_Model_CDTV; break;
243 | case "CD32": model = SAEC_Model_CD32; break; */
244 | }
245 | /* Set the defaults for the selected model.
246 | ROMs and Floppies are not affected. */
247 | sae.setModel(model, modelSubConfig);
248 |
249 | /* After here, you may tweak additional settings */
250 |
251 | cfg.chipset.ntsc = getSelect("cfg_ntsc") == 1;
252 |
253 | cfg.memory.z2FastSize = 2 << 20; /* Give 2mb zorro2 fast-ram */
254 |
255 | /* Do we have rom-data? */
256 | if (cfg.memory.rom.size == 0) {
257 | alert(saee2text(SAEE_Memory_NoKickstartRom));
258 | return false;
259 | }
260 |
261 | cfg.floppy.speed = SAEC_Config_Floppy_Speed_Turbo; /* Set speed to turbo. This is not always compatible */
262 |
263 | cfg.video.id = "myVideo"; /* Set the id-name of the desired output-div or output-canvas */
264 |
265 | switch (getSelect("cfg_res")) {
266 | case 1: /* Lores */
267 | cfg.video.hresolution = SAEC_Config_Video_HResolution_LoRes;
268 | cfg.video.vresolution = SAEC_Config_Video_VResolution_NonDouble;
269 | cfg.video.size_win.width = SAEC_Video_DEF_AMIGA_WIDTH; /* 360 */
270 | cfg.video.size_win.height = SAEC_Video_DEF_AMIGA_HEIGHT; /* 284 */
271 | break;
272 | case 2: /* Hires */
273 | cfg.video.hresolution = SAEC_Config_Video_HResolution_HiRes;
274 | cfg.video.vresolution = SAEC_Config_Video_VResolution_Double;
275 | cfg.video.size_win.width = SAEC_Video_DEF_AMIGA_WIDTH << 1; /* 720 */
276 | cfg.video.size_win.height = SAEC_Video_DEF_AMIGA_HEIGHT << 1; /* 568 */
277 | break;
278 | case 3: /* SuperHires */
279 | cfg.video.hresolution = SAEC_Config_Video_HResolution_SuperHiRes;
280 | cfg.video.vresolution = SAEC_Config_Video_VResolution_Double;
281 | cfg.video.size_win.width = SAEC_Video_DEF_AMIGA_WIDTH << 2; /* 1440 */
282 | cfg.video.size_win.height = SAEC_Video_DEF_AMIGA_HEIGHT << 1; /* 568 */
283 | break;
284 | }
285 |
286 | /* Set hooks */
287 | cfg.hook.log.error = hook_log_error;
288 |
289 | cfg.hook.led.power = hook_led_power;
290 | cfg.hook.led.hd = hook_led_hd;
291 | cfg.hook.led.df = hook_led_df;
292 | cfg.hook.led.fps = hook_led_fps;
293 | cfg.hook.led.cpu = hook_led_cpu;
294 |
295 | cfg.hook.event.started = hook_event_started;
296 | cfg.hook.event.stopped = hook_event_stopped;
297 | cfg.hook.event.reseted = hook_event_reseted;
298 | cfg.hook.event.paused = hook_event_paused;
299 | cfg.hook.event.screened = hook_event_screened;
300 |
301 | /* Enable serial */
302 | cfg.serial.enabled = true;
303 | cfg.hook.serial.get = hook_serial_get;
304 | cfg.hook.serial.put = hook_serial_put;
305 |
306 | /* Enable parallel */
307 | cfg.parallel.enabled = true;
308 | cfg.hook.parallel.get = hook_parallel_get;
309 | cfg.hook.parallel.put = hook_parallel_put;
310 |
311 | /* Enable debug-log to developer-console */
312 | cfg.debug.level = SAEC_Config_Debug_Level_Log;
313 |
314 | /* NOTE:
315 | DO NOT ALTER the config-object while the emulator is running.
316 |
317 | I will release a detailed description of the config-object soon.
318 | */
319 | return true;
320 | }
321 |
322 | /*---------------------------------*/
323 | /* Control buttons */
324 |
325 | function start() {
326 | if (getConfig()) {
327 | /* Start the emulator. This does take some time.
328 | Once started, the hook SAEV_config.hook.event.started will be called. (new 0.9.1) */
329 | var err = sae.start();
330 | if (err == SAEE_None) {
331 | /* ... */
332 | } else
333 | alert(saee2text(err));
334 | }
335 | }
336 |
337 | function stop() {
338 | /* Send stop-request. This does take some time.
339 | Once stopped, the hook SAEV_config.hook.event.stopped will be called. (new 0.9.1) */
340 | var err = sae.stop();
341 | if (err == SAEE_None) {
342 | /* ... */
343 | } else
344 | alert(saee2text(err));
345 | }
346 |
347 | function reset() {
348 | /* Send soft-reset request. This does take some time.
349 | Once done, the hook SAEV_config.hook.event.reseted will be called. (new 0.9.1) */
350 | var hard = false, keyboard = false;
351 | var err = sae.reset(hard, keyboard);
352 | if (err == SAEE_None) {
353 | /* ... */
354 | } else
355 | alert(saee2text(err));
356 | }
357 |
358 | function pause(p) {
359 | /* Send Pause- or Resume-request. This does take some time.
360 | Once paused or resumed, the hook SAEV_config.hook.event.paused will be called. (new 0.9.1)
361 | true == pause, false == resume */
362 | var err = sae.pause(p);
363 | if (err == SAEE_None) {
364 | /* ... */
365 | } else
366 | alert(saee2text(err));
367 | }
368 |
369 | function screen(s) {
370 | /* Fullscreen or window.
371 | true == fullscreen, false == window */
372 | var err = sae.screen(s);
373 | if (err == SAEE_None) {
374 | screened = s;
375 | switchScreenWindow(screened);
376 | /* ... */
377 | } else
378 | alert(saee2text(err));
379 | }
380 |
381 | function mute(m) {
382 | /* Mute or play audio.
383 | true == mute, false == play */
384 | var err = sae.mute(m);
385 | if (err == SAEE_None) {
386 | muted = m;
387 | switchMutePlay(muted);
388 | /* ... */
389 | } else
390 | alert(saee2text(err));
391 | }
392 |
393 | function romSelect() {
394 | var e = document.getElementById("cfg_rom_file").files[0];
395 | if (e) {
396 | loadFile(e, function (event) {
397 | //cfg.memory.rom.path = e.path; currently unused in SAE
398 | cfg.memory.rom.name = e.name; /* filename */
399 | cfg.memory.rom.data = event.target.result; /* typeof 'String' or 'Uint8Array' */
400 | cfg.memory.rom.size = e.size; /* size in bytes */
401 | cfg.memory.rom.crc32 = crc32(event.target.result); /* pre-calculate crc32 for a faster start */
402 | setRomName();
403 |
404 | /*ri = new SAEO_RomInfo();
405 | var err = sae.getRomInfo(ri, cfg.memory.rom);
406 | if (err == SAEE_None) {
407 | examine 'ri'...
408 | }*/
409 | });
410 | }
411 | }
412 | function romRemove() {
413 | cfg.memory.rom.clr();
414 | setRomName();
415 | }
416 |
417 | function floppyInsert(n) {
418 | var e = document.getElementById("cfg_df"+n+"_file").files[0];
419 | if (e) {
420 | loadFile(e, function(event) {
421 | var file = cfg.floppy.drive[n].file;
422 | //file.path = e.path; currently unused in SAE
423 | file.name = e.name; /* filename */
424 | file.data = event.target.result; /* typeof 'String' or 'Uint8Array' */
425 | file.size = e.size; /* size in bytes */
426 | file.crc32 = crc32(event.target.result); /* pre-calculate crc32 for a faster start */
427 | setFloppyName(n);
428 |
429 | /*var di = new SAEO_DiskInfo();
430 | var err = sae.getDiskInfo(di, n);
431 | if (err == SAEE_None) {
432 | examine 'di'...
433 | }*/
434 |
435 | /* If the emulator is running, notify about the disk-change */
436 | if (running)
437 | sae.insert(n);
438 | });
439 | }
440 | }
441 | function floppyEject(n) {
442 | cfg.floppy.drive[n].file.clr();
443 | setFloppyName(n);
444 |
445 | /* If the emulator is running, notify about the disk-change */
446 | if (running)
447 | sae.eject(n);
448 | }
449 |
450 | /*---------------------------------*/
451 | /* Init-routine, called once on page-load */
452 |
453 | function init() {
454 | /* Create the emulator */
455 | sae = new ScriptedAmigaEmulator();
456 |
457 | /* Get the reference to the info-object.
458 | As alternative, you can use the constant 'SAEC_info' directly,
459 | defined in amiga.js */
460 | inf = sae.getInfo(); /* or */
461 | //inf = SAEC_info;
462 | //console.dir(inf);
463 |
464 | /* Get the reference to the config-object.
465 | As alternative, you can use the variable 'SAEV_config' directly,
466 | defined in config.js */
467 | cfg = sae.getConfig(); /* or */
468 | //cfg = SAEV_config;
469 | //console.dir(cfg);
470 |
471 | initLEDs();
472 | setConfig();
473 | }
474 |
475 | /*-----------------------------------------------------------------------*/
476 | /* Hooks (callbacks) */
477 |
478 | /*---------------------------------*/
479 | /* Logging */
480 |
481 | /* There is currently only one log-hook, if a fatal error
482 | does occure while the emulator is running. */
483 |
484 | function hook_log_error(err, msg) {
485 | /* err is a number type. See SAEE_* in amiga.js for the error codes. */
486 | running = false;
487 | if (msg.length)
488 | alert(msg);
489 | }
490 |
491 | /*---------------------------------*/
492 | /* Events (new 0.9.1) */
493 |
494 | /* Get called after the emulator has finished the starting-process. */
495 | function hook_event_started() {
496 | running = true;
497 | }
498 |
499 | /* Get called after the emulator has finished the stopping-process. */
500 | function hook_event_stopped() {
501 | running = false;
502 |
503 | if (paused) {
504 | paused = false;
505 | switchPauseResume(paused);
506 | }
507 | if (muted) {
508 | muted = false;
509 | switchMutePlay(muted);
510 | }
511 | if (screened) {
512 | screened = false;
513 | switchScreenWindow(screened);
514 | }
515 | resetLEDs();
516 | }
517 |
518 | /* Get called after the emulator has finished the reset-routine. */
519 | function hook_event_reseted(hard) {
520 | if (paused) {
521 | paused = false;
522 | switchPauseResume(paused);
523 | }
524 | if (muted) {
525 | muted = false;
526 | switchMutePlay(muted);
527 | }
528 | /*if (screened) {
529 | screened = false;
530 | switchScreenWindow(screened);
531 | }*/
532 | }
533 |
534 | /* Get called after the emulator has finished switching between pause-resume. */
535 | function hook_event_paused(p) {
536 | paused = p;
537 | switchPauseResume(p);
538 | }
539 |
540 | /* Get called after the emulator has finished switching between fullscreen-window. */
541 | function hook_event_screened(s) {
542 | screened = s;
543 | switchScreenWindow(s);
544 | }
545 |
546 | /*---------------------------------*/
547 | /* Serial */
548 |
549 | var ser_in = null; /* buffer for serial-data to be transmited */
550 | var in_pos = 0;
551 |
552 | /* Put some random-data in the serial-buffer */
553 | function test_serial_send(bytes) {
554 | if (!bytes || bytes > 1024) bytes = 4;
555 | ser_in = new Uint8Array(bytes);
556 | for (var i = 0; i < bytes; i++)
557 | ser_in[i] = 65 + ((Math.random() * 25) >>> 0); /* ASCII 'A'-'Z' */
558 | }
559 |
560 | /* Get ALWAYS called if the serial.device is enabled. */
561 | function hook_serial_get() {
562 | if (ser_in !== null) {
563 | if (in_pos < ser_in.length)
564 | return ser_in[in_pos++];
565 | else {
566 | ser_in = null; /* terminate transmission */
567 | in_pos = 0;
568 | }
569 | }
570 | return -1; /* return -1 as default */
571 | }
572 |
573 | var ser_out = ""; /* buffer for received serial-data */
574 |
575 | /* Get called if the serial.device want to write a byte. */
576 | function hook_serial_put(charCode) {
577 | if (charCode >= 32 && charCode < 127) /* printable? */
578 | ser_out += String.fromCharCode(charCode);
579 | else
580 | ser_out += '.';
581 |
582 | if (ser_out.length == 76 || charCode == 10) { /* line-full or line-feed? */
583 | console.log("=== SERIAL DATA START ===");
584 | console.log(ser_out);
585 | console.log("=== SERIAL DATA END ===");
586 | ser_out = "";
587 | }
588 | }
589 |
590 | /*---------------------------------*/
591 | /* Parallel */
592 |
593 | /* Get called if the parallel.device want to read a byte. */
594 | function hook_parallel_get() {
595 | /* Must always return a value between 0-255 */
596 | return 97 + ((Math.random() * 25) >>> 0); /* ASCII 'a'-'z' */
597 | }
598 |
599 | var par_out = ""; /* buffer for received parallel-data */
600 |
601 | /* Get called if the parallel.device want to write a byte. */
602 | function hook_parallel_put(charCode) {
603 | if (charCode >= 32 && charCode < 127) /* printable? */
604 | par_out += String.fromCharCode(charCode);
605 | else
606 | par_out += '.';
607 |
608 | if (par_out.length == 76 || charCode == 10) { /* line-full or line-feed? */
609 | console.log("=== PARALLEL DATA START ===");
610 | console.log(par_out);
611 | console.log("=== PARALLEL DATA END ===");
612 | par_out = "";
613 | }
614 | }
615 |
616 | /*---------------------------------*/
617 | /* LEDs */
618 |
619 | const COL_GRAY = "#000";
620 | const COL_GREEN = "#8C8";
621 | const COL_RED = "#E88";
622 | const COL_ORANGE = "#CC8";
623 |
624 | /* cache elements */
625 | var e_led_power = null;
626 | var e_led_hd = null;
627 | var e_led_df = [null,null,null,null];
628 | var e_led_fps = null;
629 | var e_led_cpu = null;
630 |
631 | /* Power LED: boolean On/Off */
632 | function hook_led_power(on) {
633 | e_led_power.style.color = on ? COL_GREEN : COL_GRAY;
634 | }
635 |
636 | /* Harddisk-LED */
637 | function hook_led_hd(rw) {
638 | /* rw 0=Off, 1=Read, 2=Write */
639 | e_led_hd.style.color = rw == 1 ? COL_GREEN : (rw == 2 ? COL_RED : COL_GRAY);
640 | }
641 |
642 | /* Floppy-LED */
643 | function hook_led_df(unit, disabled, cylinder, side, rw) {
644 | /* unit 0-3 */
645 | /* cylinder 0-81 */
646 | /* side 0-1 */
647 | /* rw 0=Off, 1=Read, 2=Write */
648 | if (disabled) {
649 | e_led_df[unit].innerHTML = "-";
650 | e_led_df[unit].style.color = COL_GRAY;
651 | } else {
652 | e_led_df[unit].innerHTML = String(cylinder);
653 | e_led_df[unit].style.color = rw == 1 ? COL_GREEN : (rw == 2 ? COL_RED : COL_GRAY);
654 | }
655 | }
656 |
657 | /* FPS (Frames Per Second) */
658 | function hook_led_fps(fps, paused) {
659 | /* fps is a float-number, 0-50, in frames */
660 | e_led_fps.innerHTML = paused ? "0.0" : fps.toFixed(1);
661 | e_led_fps.style.color = COL_GRAY;
662 | }
663 |
664 | /* CPU-usage */
665 | function hook_led_cpu(usage, paused) {
666 | /* usage is a float-number, 0-1000, in percent */
667 | if (paused) {
668 | e_led_cpu.innerHTML = "0%";
669 | e_led_cpu.style.color = COL_GRAY;
670 | } else {
671 | e_led_cpu.innerHTML = usage.toFixed(0) + "%";
672 | if (usage < 90)
673 | e_led_cpu.style.color = COL_GREEN;
674 | else if (usage < 110)
675 | e_led_cpu.style.color = COL_ORANGE;
676 | else
677 | e_led_cpu.style.color = COL_RED;
678 | }
679 | }
680 |
681 | function resetLEDs() {
682 | hook_led_power(false);
683 | hook_led_hd(0);
684 | hook_led_df(0, true, 0, 0, 0);
685 | hook_led_df(1, true, 0, 0, 0);
686 | hook_led_df(2, true, 0, 0, 0);
687 | hook_led_df(3, true, 0, 0, 0);
688 | hook_led_fps(0, false);
689 | hook_led_cpu(0, false);
690 | }
691 |
692 | function initLEDs() {
693 | e_led_power = document.getElementById("status_led_power");
694 | e_led_hd = document.getElementById("status_led_hd");
695 | e_led_df[0] = document.getElementById("status_led_df0");
696 | e_led_df[1] = document.getElementById("status_led_df1");
697 | e_led_df[2] = document.getElementById("status_led_df2");
698 | e_led_df[3] = document.getElementById("status_led_df3");
699 | e_led_fps = document.getElementById("status_led_fps");
700 | e_led_cpu = document.getElementById("status_led_cpu");
701 |
702 | resetLEDs();
703 | }
704 |
--------------------------------------------------------------------------------
/example2.htm:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | SAE - Scripted Amiga Emulator
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 | JavaScript is disabled or not supported!
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 | Status
56 |
57 |
58 |
59 | PWR
60 | HD
61 | 0
62 | 0
63 | 0
64 | 0
65 | 0
66 | 0
67 |
68 |
69 |
70 |
71 |
72 |
73 | Config
74 |
75 |
134 |
135 |
136 |
137 |
138 | Controls
139 |
140 |
141 |
142 | Start
143 | Stop
144 | Reset
145 | Pause
146 | Mute
147 | Screen
148 |
149 |
150 |
151 |
152 |
153 |
154 | Output
155 |
156 |
159 |
160 |
161 |
162 |
163 |
165 |
166 |
167 |
168 |
169 |
170 |
171 |
172 |
--------------------------------------------------------------------------------
/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/naTmeg/ScriptedAmigaEmulator/7fc423194d9690dc0f4344afe638aaf580e5e8a9/favicon.ico
--------------------------------------------------------------------------------
/gpl.htm:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | GNU General Public License v2.0 - GNU Project - Free Software Foundation (FSF)
6 |
8 |
9 |
10 |
11 |
12 | Version 2, June 1991
13 |
14 |
15 |
16 | Copyright (C) 1989, 1991 Free Software Foundation, Inc.
17 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
18 |
19 | Everyone is permitted to copy and distribute verbatim copies
20 | of this license document, but changing it is not allowed.
21 |
22 |
23 |
24 |
25 |
26 | The licenses for most software are designed to take away your
27 | freedom to share and change it. By contrast, the GNU General Public
28 | License is intended to guarantee your freedom to share and change free
29 | software--to make sure the software is free for all its users. This
30 | General Public License applies to most of the Free Software
31 | Foundation's software and to any other program whose authors commit to
32 | using it. (Some other Free Software Foundation software is covered by
33 | the GNU Lesser General Public License instead.) You can apply it to
34 | your programs, too.
35 |
36 |
37 |
38 | When we speak of free software, we are referring to freedom, not
39 | price. Our General Public Licenses are designed to make sure that you
40 | have the freedom to distribute copies of free software (and charge for
41 | this service if you wish), that you receive source code or can get it
42 | if you want it, that you can change the software or use pieces of it
43 | in new free programs; and that you know you can do these things.
44 |
45 |
46 |
47 | To protect your rights, we need to make restrictions that forbid
48 | anyone to deny you these rights or to ask you to surrender the rights.
49 | These restrictions translate to certain responsibilities for you if you
50 | distribute copies of the software, or if you modify it.
51 |
52 |
53 |
54 | For example, if you distribute copies of such a program, whether
55 | gratis or for a fee, you must give the recipients all the rights that
56 | you have. You must make sure that they, too, receive or can get the
57 | source code. And you must show them these terms so they know their
58 | rights.
59 |
60 |
61 |
62 | We protect your rights with two steps: (1) copyright the software, and
63 | (2) offer you this license which gives you legal permission to copy,
64 | distribute and/or modify the software.
65 |
66 |
67 |
68 | Also, for each author's protection and ours, we want to make certain
69 | that everyone understands that there is no warranty for this free
70 | software. If the software is modified by someone else and passed on, we
71 | want its recipients to know that what they have is not the original, so
72 | that any problems introduced by others will not reflect on the original
73 | authors' reputations.
74 |
75 |
76 |
77 | Finally, any free program is threatened constantly by software
78 | patents. We wish to avoid the danger that redistributors of a free
79 | program will individually obtain patent licenses, in effect making the
80 | program proprietary. To prevent this, we have made it clear that any
81 | patent must be licensed for everyone's free use or not licensed at all.
82 |
83 |
84 |
85 | The precise terms and conditions for copying, distribution and
86 | modification follow.
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 | 0.
95 | This License applies to any program or other work which contains
96 | a notice placed by the copyright holder saying it may be distributed
97 | under the terms of this General Public License. The "Program", below,
98 | refers to any such program or work, and a "work based on the Program"
99 | means either the Program or any derivative work under copyright law:
100 | that is to say, a work containing the Program or a portion of it,
101 | either verbatim or with modifications and/or translated into another
102 | language. (Hereinafter, translation is included without limitation in
103 | the term "modification".) Each licensee is addressed as "you".
104 |
105 |
106 |
107 | Activities other than copying, distribution and modification are not
108 | covered by this License; they are outside its scope. The act of
109 | running the Program is not restricted, and the output from the Program
110 | is covered only if its contents constitute a work based on the
111 | Program (independent of having been made by running the Program).
112 | Whether that is true depends on what the Program does.
113 |
114 |
115 |
116 | 1.
117 | You may copy and distribute verbatim copies of the Program's
118 | source code as you receive it, in any medium, provided that you
119 | conspicuously and appropriately publish on each copy an appropriate
120 | copyright notice and disclaimer of warranty; keep intact all the
121 | notices that refer to this License and to the absence of any warranty;
122 | and give any other recipients of the Program a copy of this License
123 | along with the Program.
124 |
125 |
126 |
127 | You may charge a fee for the physical act of transferring a copy, and
128 | you may at your option offer warranty protection in exchange for a fee.
129 |
130 |
131 |
132 | 2.
133 | You may modify your copy or copies of the Program or any portion
134 | of it, thus forming a work based on the Program, and copy and
135 | distribute such modifications or work under the terms of Section 1
136 | above, provided that you also meet all of these conditions:
137 |
138 |
139 |
140 |
141 |
142 | a)
143 | You must cause the modified files to carry prominent notices
144 | stating that you changed the files and the date of any change.
145 |
146 |
147 |
148 | b)
149 | You must cause any work that you distribute or publish, that in
150 | whole or in part contains or is derived from the Program or any
151 | part thereof, to be licensed as a whole at no charge to all third
152 | parties under the terms of this License.
153 |
154 |
155 |
156 | c)
157 | If the modified program normally reads commands interactively
158 | when run, you must cause it, when started running for such
159 | interactive use in the most ordinary way, to print or display an
160 | announcement including an appropriate copyright notice and a
161 | notice that there is no warranty (or else, saying that you provide
162 | a warranty) and that users may redistribute the program under
163 | these conditions, and telling the user how to view a copy of this
164 | License. (Exception: if the Program itself is interactive but
165 | does not normally print such an announcement, your work based on
166 | the Program is not required to print an announcement.)
167 |
168 |
169 |
170 |
171 | These requirements apply to the modified work as a whole. If
172 | identifiable sections of that work are not derived from the Program,
173 | and can be reasonably considered independent and separate works in
174 | themselves, then this License, and its terms, do not apply to those
175 | sections when you distribute them as separate works. But when you
176 | distribute the same sections as part of a whole which is a work based
177 | on the Program, the distribution of the whole must be on the terms of
178 | this License, whose permissions for other licensees extend to the
179 | entire whole, and thus to each and every part regardless of who wrote it.
180 |
181 |
182 |
183 | Thus, it is not the intent of this section to claim rights or contest
184 | your rights to work written entirely by you; rather, the intent is to
185 | exercise the right to control the distribution of derivative or
186 | collective works based on the Program.
187 |
188 |
189 |
190 | In addition, mere aggregation of another work not based on the Program
191 | with the Program (or with a work based on the Program) on a volume of
192 | a storage or distribution medium does not bring the other work under
193 | the scope of this License.
194 |
195 |
196 |
197 | 3.
198 | You may copy and distribute the Program (or a work based on it,
199 | under Section 2) in object code or executable form under the terms of
200 | Sections 1 and 2 above provided that you also do one of the following:
201 |
202 |
203 |
204 |
205 |
206 |
207 |
208 |
209 | a)
210 | Accompany it with the complete corresponding machine-readable
211 | source code, which must be distributed under the terms of Sections
212 | 1 and 2 above on a medium customarily used for software interchange; or,
213 |
214 |
215 |
216 | b)
217 | Accompany it with a written offer, valid for at least three
218 | years, to give any third party, for a charge no more than your
219 | cost of physically performing source distribution, a complete
220 | machine-readable copy of the corresponding source code, to be
221 | distributed under the terms of Sections 1 and 2 above on a medium
222 | customarily used for software interchange; or,
223 |
224 |
225 |
226 | c)
227 | Accompany it with the information you received as to the offer
228 | to distribute corresponding source code. (This alternative is
229 | allowed only for noncommercial distribution and only if you
230 | received the program in object code or executable form with such
231 | an offer, in accord with Subsection b above.)
232 |
233 |
234 |
235 |
236 | The source code for a work means the preferred form of the work for
237 | making modifications to it. For an executable work, complete source
238 | code means all the source code for all modules it contains, plus any
239 | associated interface definition files, plus the scripts used to
240 | control compilation and installation of the executable. However, as a
241 | special exception, the source code distributed need not include
242 | anything that is normally distributed (in either source or binary
243 | form) with the major components (compiler, kernel, and so on) of the
244 | operating system on which the executable runs, unless that component
245 | itself accompanies the executable.
246 |
247 |
248 |
249 | If distribution of executable or object code is made by offering
250 | access to copy from a designated place, then offering equivalent
251 | access to copy the source code from the same place counts as
252 | distribution of the source code, even though third parties are not
253 | compelled to copy the source along with the object code.
254 |
255 |
256 |
257 | 4.
258 | You may not copy, modify, sublicense, or distribute the Program
259 | except as expressly provided under this License. Any attempt
260 | otherwise to copy, modify, sublicense or distribute the Program is
261 | void, and will automatically terminate your rights under this License.
262 | However, parties who have received copies, or rights, from you under
263 | this License will not have their licenses terminated so long as such
264 | parties remain in full compliance.
265 |
266 |
267 |
268 | 5.
269 | You are not required to accept this License, since you have not
270 | signed it. However, nothing else grants you permission to modify or
271 | distribute the Program or its derivative works. These actions are
272 | prohibited by law if you do not accept this License. Therefore, by
273 | modifying or distributing the Program (or any work based on the
274 | Program), you indicate your acceptance of this License to do so, and
275 | all its terms and conditions for copying, distributing or modifying
276 | the Program or works based on it.
277 |
278 |
279 |
280 | 6.
281 | Each time you redistribute the Program (or any work based on the
282 | Program), the recipient automatically receives a license from the
283 | original licensor to copy, distribute or modify the Program subject to
284 | these terms and conditions. You may not impose any further
285 | restrictions on the recipients' exercise of the rights granted herein.
286 | You are not responsible for enforcing compliance by third parties to
287 | this License.
288 |
289 |
290 |
291 | 7.
292 | If, as a consequence of a court judgment or allegation of patent
293 | infringement or for any other reason (not limited to patent issues),
294 | conditions are imposed on you (whether by court order, agreement or
295 | otherwise) that contradict the conditions of this License, they do not
296 | excuse you from the conditions of this License. If you cannot
297 | distribute so as to satisfy simultaneously your obligations under this
298 | License and any other pertinent obligations, then as a consequence you
299 | may not distribute the Program at all. For example, if a patent
300 | license would not permit royalty-free redistribution of the Program by
301 | all those who receive copies directly or indirectly through you, then
302 | the only way you could satisfy both it and this License would be to
303 | refrain entirely from distribution of the Program.
304 |
305 |
306 |
307 | If any portion of this section is held invalid or unenforceable under
308 | any particular circumstance, the balance of the section is intended to
309 | apply and the section as a whole is intended to apply in other
310 | circumstances.
311 |
312 |
313 |
314 | It is not the purpose of this section to induce you to infringe any
315 | patents or other property right claims or to contest validity of any
316 | such claims; this section has the sole purpose of protecting the
317 | integrity of the free software distribution system, which is
318 | implemented by public license practices. Many people have made
319 | generous contributions to the wide range of software distributed
320 | through that system in reliance on consistent application of that
321 | system; it is up to the author/donor to decide if he or she is willing
322 | to distribute software through any other system and a licensee cannot
323 | impose that choice.
324 |
325 |
326 |
327 | This section is intended to make thoroughly clear what is believed to
328 | be a consequence of the rest of this License.
329 |
330 |
331 |
332 | 8.
333 | If the distribution and/or use of the Program is restricted in
334 | certain countries either by patents or by copyrighted interfaces, the
335 | original copyright holder who places the Program under this License
336 | may add an explicit geographical distribution limitation excluding
337 | those countries, so that distribution is permitted only in or among
338 | countries not thus excluded. In such case, this License incorporates
339 | the limitation as if written in the body of this License.
340 |
341 |
342 |
343 | 9.
344 | The Free Software Foundation may publish revised and/or new versions
345 | of the General Public License from time to time. Such new versions will
346 | be similar in spirit to the present version, but may differ in detail to
347 | address new problems or concerns.
348 |
349 |
350 |
351 | Each version is given a distinguishing version number. If the Program
352 | specifies a version number of this License which applies to it and "any
353 | later version", you have the option of following the terms and conditions
354 | either of that version or of any later version published by the Free
355 | Software Foundation. If the Program does not specify a version number of
356 | this License, you may choose any version ever published by the Free Software
357 | Foundation.
358 |
359 |
360 |
361 | 10.
362 | If you wish to incorporate parts of the Program into other free
363 | programs whose distribution conditions are different, write to the author
364 | to ask for permission. For software which is copyrighted by the Free
365 | Software Foundation, write to the Free Software Foundation; we sometimes
366 | make exceptions for this. Our decision will be guided by the two goals
367 | of preserving the free status of all derivatives of our free software and
368 | of promoting the sharing and reuse of software generally.
369 |
370 |
371 | NO WARRANTY
372 |
373 |
374 | 11.
375 | BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
376 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
377 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
378 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
379 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
380 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
381 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
382 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
383 | REPAIR OR CORRECTION.
384 |
385 |
386 |
387 | 12.
388 | IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
389 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
390 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
391 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
392 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
393 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
394 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
395 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
396 | POSSIBILITY OF SUCH DAMAGES.
397 |
398 |
399 | END OF TERMS AND CONDITIONS
400 |
401 |
402 |
403 |
404 | If you develop a new program, and you want it to be of the greatest
405 | possible use to the public, the best way to achieve this is to make it
406 | free software which everyone can redistribute and change under these terms.
407 |
408 |
409 |
410 | To do so, attach the following notices to the program. It is safest
411 | to attach them to the start of each source file to most effectively
412 | convey the exclusion of warranty; and each file should have at least
413 | the "copyright" line and a pointer to where the full notice is found.
414 |
415 |
416 |
417 | one line to give the program's name and an idea of what it does.
418 | Copyright (C) yyyy name of author
419 |
420 | This program is free software; you can redistribute it and/or
421 | modify it under the terms of the GNU General Public License
422 | as published by the Free Software Foundation; either version 2
423 | of the License, or (at your option) any later version.
424 |
425 | This program is distributed in the hope that it will be useful,
426 | but WITHOUT ANY WARRANTY; without even the implied warranty of
427 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
428 | GNU General Public License for more details.
429 |
430 | You should have received a copy of the GNU General Public License
431 | along with this program; if not, write to the Free Software
432 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
433 |
434 |
435 |
436 | Also add information on how to contact you by electronic and paper mail.
437 |
438 |
439 |
440 | If the program is interactive, make it output a short notice like this
441 | when it starts in an interactive mode:
442 |
443 |
444 |
445 | Gnomovision version 69, Copyright (C) year name of author
446 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details
447 | type `show w'. This is free software, and you are welcome
448 | to redistribute it under certain conditions; type `show c'
449 | for details.
450 |
451 |
452 |
453 | The hypothetical commands `show w' and `show c' should show
454 | the appropriate parts of the General Public License. Of course, the
455 | commands you use may be called something other than `show w' and
456 | `show c' ; they could even be mouse-clicks or menu items--whatever
457 | suits your program.
458 |
459 |
460 |
461 | You should also get your employer (if you work as a programmer) or your
462 | school, if any, to sign a "copyright disclaimer" for the program, if
463 | necessary. Here is a sample; alter the names:
464 |
465 |
466 |
467 |
468 | Yoyodyne, Inc., hereby disclaims all copyright
469 | interest in the program `Gnomovision'
470 | (which makes passes at compilers) written
471 | by James Hacker.
472 |
473 | signature of Ty Coon , 1 April 1989
474 | Ty Coon, President of Vice
475 |
476 |
477 |
478 | This General Public License does not permit incorporating your program into
479 | proprietary programs. If your program is a subroutine library, you may
480 | consider it more useful to permit linking proprietary applications with the
481 | library. If this is what you want to do, use the
482 | GNU Lesser General Public License
483 | instead of this License.
484 |
485 |
486 |
487 |
488 |
--------------------------------------------------------------------------------
/images/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/naTmeg/ScriptedAmigaEmulator/7fc423194d9690dc0f4344afe638aaf580e5e8a9/images/logo.png
--------------------------------------------------------------------------------
/index.css:
--------------------------------------------------------------------------------
1 | /*-------------------------------------------------------------------------
2 | | SAE - Scripted Amiga Emulator
3 | | https://github.com/naTmeg/ScriptedAmigaEmulator
4 | |
5 | | Copyright (C) 2012-2016 Rupert Hausberger
6 | |
7 | | This program is free software; you can redistribute it and/or
8 | | modify it under the terms of the GNU General Public License
9 | | as published by the Free Software Foundation; either version 2
10 | | of the License, or (at your option) any later version.
11 | |
12 | | This program is distributed in the hope that it will be useful,
13 | | but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | | GNU General Public License for more details.
16 | -------------------------------------------------------------------------*/
17 |
18 | a:link { color:#24c; text-decoration:none; }
19 | a:visited { color:#24c; text-decoration:none; }
20 | a:hover { color:#24c; text-decoration:underline; }
21 |
22 | body {
23 | top:0;
24 | left:0;
25 | margin:0;
26 | padding:0;
27 | font-family:Verdana;
28 | font-size:13px;
29 | background-color:#f8f8f8;
30 | -webkit-touch-callout:none;
31 | -webkit-user-select:none;
32 | -khtml-user-select:none;
33 | -moz-user-select:none;
34 | -ms-user-select:none;
35 | user-select:none;
36 | }
37 |
38 | table {
39 | white-space:nowrap;
40 | }
41 | td {
42 | text-align:left;
43 | vertical-align:top;
44 | }
45 |
46 | textarea {
47 | resize:none;
48 | font-size:13px;
49 | font-family:monospace;
50 | border-left:1px solid #ccc;
51 | border-top:1px solid #ccc;
52 | border-right:1px solid #fff;
53 | border-bottom:1px solid #fff;
54 | }
55 |
56 | input[type=text] {
57 | font-size:13px;
58 | border-left:1px solid #ccc;
59 | border-top:1px solid #ccc;
60 | border-right:1px solid #fff;
61 | border-bottom:1px solid #fff;
62 | }
63 |
64 | /*---------------------------------*/
65 |
66 | .gray { color:gray; }
67 | .green { color:green; }
68 | .orange { color:orange; }
69 | .red { color:red; }
70 |
71 | .alt { text-align:left; vertical-align:top; }
72 | .alm { text-align:left; vertical-align:middle; }
73 | .alb { text-align:left; vertical-align:bottom; }
74 |
75 | .act { text-align:center; vertical-align:top; }
76 | .acm { text-align:center; vertical-align:middle; }
77 | .acb { text-align:center; vertical-align:bottom; }
78 |
79 | .art { text-align:right; vertical-align:top; }
80 | .arm { text-align:right; vertical-align:middle; }
81 | .arb { text-align:right; vertical-align:bottom; }
82 |
83 | .label {
84 | font-size:11px;
85 | font-weight:bold;
86 | color:#333;
87 | }
88 | .info {
89 | font-size:11px;
90 | color:dimgray;
91 | }
92 | .warn {
93 | font-size:11px;
94 | color:red;
95 | }
96 |
97 | .noscript {
98 | margin:auto;
99 | padding:4px;
100 | font-size:17px;
101 | font-weight:bold;
102 | text-align:center;
103 | color:red;
104 | }
105 |
106 | .head {
107 | width:100%;
108 | margin:auto;
109 | text-align:center;
110 | }
111 |
112 | .foot {
113 | width:100%;
114 | margin:auto;
115 | font-size:11px;
116 | text-align:center;
117 | }
118 |
119 | .linehoriz {
120 | width:100%;
121 | border-top:1px solid #bbb;
122 | }
123 |
124 | .text {
125 | border-left:1px solid #bbb;
126 | border-top:1px solid #bbb;
127 | border-right:1px solid #fff;
128 | border-bottom:1px solid #fff;
129 | background-color:#fff;
130 | -webkit-touch-callout:text;
131 | -webkit-user-select:text;
132 | -khtml-user-select:text;
133 | -moz-user-select:text;
134 | -ms-user-select:text;
135 | user-select:text;
136 | }
137 |
138 | /*---------------------------------*/
139 |
140 | #myVideo {
141 | margin:auto;
142 | }
143 | #myVideo:-webkit-full-screen {
144 | width: 100%;
145 | height: 100%;
146 | }
147 |
148 | /*---------------------------------*/
149 |
150 | #config select {
151 | border-left:2px solid #fff;
152 | border-top:2px solid #fff;
153 | border-right:1px solid #bbb;
154 | border-bottom:1px solid #bbb;
155 | background-color:#f8f8f8;
156 | }
157 | #config .button {
158 | width:75px;
159 | border-left:1px solid #fff;
160 | border-top:1px solid #fff;
161 | border-right:1px solid #bbb;
162 | border-bottom:1px solid #bbb;
163 | background-color:#f8f8f8;
164 | }
165 | #config .button:hover {
166 | background-color:#e8e8e8;
167 | }
168 | #config .sbutton {
169 | width:100px;
170 | padding:2px;
171 | border-left:1px solid #fff;
172 | border-top:1px solid #fff;
173 | border-right:1px solid #bbb;
174 | border-bottom:1px solid #bbb;
175 | background-color:#f8f8f8;
176 | }
177 | #config .sbutton:hover {
178 | background-color:#e8e8e8;
179 | }
180 |
181 | #config_database {
182 | width:720px;
183 | padding:10px;
184 | margin:auto;
185 | border-left:1px solid #fff;
186 | border-top:1px solid #fff;
187 | border-right:1px solid #bbb;
188 | border-bottom:1px solid #bbb;
189 | background-color:#f0f0f0;
190 | }
191 | #config_database_hof {
192 | width:75%;
193 | margin:auto;
194 | padding:10px;
195 | border-left:1px solid #bbb;
196 | border-top:1px solid #bbb;
197 | border-right:1px solid #fff;
198 | border-bottom:1px solid #fff;
199 | background-color:#e8e8e8;
200 | }
201 | #config_database_hof .ctrl {
202 | padding:2px;
203 | margin:0;
204 | border-left:1px solid #bbb;
205 | border-top:1px solid #bbb;
206 | border-right:1px solid #fff;
207 | border-bottom:1px solid #fff;
208 | background-color:#f0f0f0;
209 | }
210 |
211 | #config_advanced {
212 | width:720px;
213 | margin:auto;
214 | padding:10px;
215 | border-left:1px solid #fff;
216 | border-top:1px solid #fff;
217 | border-right:1px solid #bbb;
218 | border-bottom:1px solid #bbb;
219 | background-color:#f0f0f0;
220 | display:none;
221 | }
222 | #config_advanced table {
223 | width:100%;
224 | }
225 |
226 | #config_advanced .menu {
227 | padding:10px;
228 | border-left:1px solid #ccc;
229 | border-top:1px solid #ccc;
230 | border-right:1px solid #fff;
231 | border-bottom:1px solid #fff;
232 | background-color:#e8e8e8;
233 | }
234 | #config_advanced .menu a:link {
235 | font-size:13px;
236 | color:#000;
237 | text-decoration:none;
238 | }
239 | #config_advanced .menu a:hover {
240 | color:#888;
241 | text-decoration:none;
242 | }
243 |
244 | #config_advanced .page {
245 | padding:10px;
246 | border-left:1px solid #ccc;
247 | border-top:1px solid #ccc;
248 | border-right:1px solid #fff;
249 | border-bottom:1px solid #fff;
250 | background-color:#e8e8e8;
251 | display:none;
252 | }
253 | #cfg_page_video input[type="text"] {
254 | width:60px;
255 | }
256 |
257 | /*---------------------------------*/
258 |
259 | #emul {
260 | display:none;
261 | }
262 |
263 | #emul button {
264 | width:75px;
265 | font-size:11px;
266 | font-weight:bold;
267 | color:#888;
268 | border:1px solid #888;
269 | background-color:#000;
270 | }
271 | #emul button:hover {
272 | color:#ccc;
273 | border:1px solid #ccc;
274 | }
275 |
276 | #controls_status {
277 | margin:auto;
278 | color:#888;
279 | font-size:9px;
280 | font-weight:bold;
281 | }
282 |
283 | #dskchg_database, #dskchg_advanced {
284 | display:none;
285 | }
286 | #dskchg_database table, #dskchg_advanced table {
287 | margin:auto;
288 | }
289 | #dskchg_database select, #dskchg_advanced select {
290 | font-size:11px;
291 | font-weight:bold;
292 | color:#888;
293 | border:1px solid #888;
294 | background-color:#000;
295 | }
296 |
297 | /*---------------------------------*/
298 |
299 | .readme {
300 | width:1080px;
301 | margin:auto;
302 | padding:10px;
303 | border-left:1px solid #fff;
304 | border-top:1px solid #fff;
305 | border-right:1px solid #bbb;
306 | border-bottom:1px solid #bbb;
307 | background-color:#f0f0f0;
308 | }
309 | .readme table {
310 | width:100%;
311 | }
312 | .readme table td {
313 | vertical-align:top;
314 | }
315 | .readme li {
316 | padding:1px;
317 | }
318 |
319 | /*---------------------------------*/
320 |
321 | #disass {
322 | width:720px;
323 | padding:10px;
324 | margin:auto;
325 | border-left:1px solid #fff;
326 | border-top:1px solid #fff;
327 | border-right:1px solid #bbb;
328 | border-bottom:1px solid #bbb;
329 | background-color:#f0f0f0;
330 | }
331 | #disass select {
332 | border-left:1px solid #fff;
333 | border-top:1px solid #fff;
334 | border-right:1px solid #bbb;
335 | border-bottom:1px solid #bbb;
336 | }
337 | #disass input {
338 | border-left:1px solid #bbb;
339 | border-top:1px solid #bbb;
340 | border-right:1px solid #fff;
341 | border-bottom:1px solid #fff;
342 | }
343 |
344 | #disass .button {
345 | width:100px;
346 | border-left:1px solid #fff;
347 | border-top:1px solid #fff;
348 | border-right:1px solid #bbb;
349 | border-bottom:1px solid #bbb;
350 | background-color:#f8f8f8;
351 | }
352 | #disass .button:hover {
353 | background-color:#e8e8e8;
354 | }
355 |
356 | #disass_cfg {
357 | border-left:1px solid #bbb;
358 | border-top:1px solid #bbb;
359 | border-right:1px solid #fff;
360 | border-bottom:1px solid #fff;
361 | background-color:#e8e8e8;
362 | display:none;
363 | }
364 |
365 | #disass_code {
366 | width:100%;
367 | display:none;
368 | }
369 |
--------------------------------------------------------------------------------
/sae/amiga.js:
--------------------------------------------------------------------------------
1 | /*-------------------------------------------------------------------------
2 | | SAE - Scripted Amiga Emulator
3 | | https://github.com/naTmeg/ScriptedAmigaEmulator
4 | |
5 | | Copyright (C) 2012 Rupert Hausberger
6 | |
7 | | This program is free software; you can redistribute it and/or
8 | | modify it under the terms of the GNU General Public License
9 | | as published by the Free Software Foundation; either version 2
10 | | of the License, or (at your option) any later version.
11 | |
12 | | This program is distributed in the hope that it will be useful,
13 | | but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | | GNU General Public License for more details.
16 | |
17 | | Notes on the global-namespace
18 | | -----------------------------
19 | | Global object:
20 | | function SAEO_() {}
21 | |
22 | | Global error constant:
23 | | const SAEE__;
24 | |
25 | | Global constant:
26 | | const SAEC__;
27 | |
28 | | Global variable:
29 | | var SAEV__;
30 | |
31 | | Global function:
32 | | function SAEF__() {}
33 | |
34 | | Global reference (pointer) to another object:
35 | | var SAER__;
36 | |
37 | |
38 | | Tags that may appear in comments (use full-word, case-sensitive text-search)
39 | | --------------------------------
40 | | OWN Own code added.
41 | | ATT Attention, possible source of error or problem.
42 | | FIX Need to be fixed or implemented.
43 | | OPT Need or can be optimized.
44 | | ORG Original code, e.g. something required to be disabled.
45 | | SECT Code section.
46 | -------------------------------------------------------------------------*/
47 |
48 | const SAEC_Version = 0;
49 | const SAEC_Revision = 9;
50 | const SAEC_Patch = 13;
51 |
52 | /*---------------------------------*/
53 | /* errors */
54 |
55 | function SAEO_Error(err, msg) {
56 | this.err = err;
57 | this.msg = msg;
58 | }
59 | SAEO_Error.prototype = new Error;
60 |
61 | const SAEE_None = 0;
62 |
63 | const SAEE_AlreadyRunning = 1;
64 | const SAEE_NotRunning = 2;
65 | const SAEE_NoTimer = 3;
66 | const SAEE_NoMemory = 4;
67 | const SAEE_Assert = 5;
68 | const SAEE_Internal = 6;
69 |
70 | const SAEE_Config_Invalid = 10;
71 | const SAEE_Config_Compressed = 11;
72 |
73 | const SAEE_CPU_Internal = 20;
74 | const SAEE_CPU_Requires68020 = 21;
75 | const SAEE_CPU_Requires680EC20 = 22;
76 | const SAEE_CPU_Requires68030 = 23;
77 | const SAEE_CPU_Requires68040 = 24;
78 |
79 | const SAEE_Memory_NoKickstartRom = 30;
80 | const SAEE_Memory_NoExtendedRom = 31;
81 | const SAEE_Memory_RomSize = 32;
82 | const SAEE_Memory_RomKey = 33;
83 | const SAEE_Memory_RomDecode = 34;
84 | const SAEE_Memory_RomChecksum = 35;
85 | const SAEE_Memory_RomUnknown = 36;
86 |
87 | const SAEE_Video_ElementNotFound = 40;
88 | const SAEE_Video_RequiresCanvas = 41;
89 | const SAEE_Video_RequiresWegGl = 42;
90 | const SAEE_Video_ComphileShader = 43;
91 | const SAEE_Video_LinkShader = 44;
92 | const SAEE_Video_RequiresFullscreen = 45;
93 |
94 | const SAEE_Audio_RequiresWebAudio = 50;
95 |
96 | const SAEE_Input_GamepadNotReady = 60;
97 |
98 | /*-----------------------------------------------------------------------*/
99 | /* global references */
100 |
101 | var SAER = null;
102 |
103 | /*---------------------------------*/
104 | /* global constants */
105 |
106 | const SAEC_spcflag_STOP = 2;
107 | const SAEC_spcflag_COPPER = 4;
108 | const SAEC_spcflag_INT = 8;
109 | const SAEC_spcflag_BRK = 16;
110 | //const SAEC_spcflag_UAEINT = 32;
111 | const SAEC_spcflag_TRACE = 64;
112 | const SAEC_spcflag_DOTRACE = 128;
113 | const SAEC_spcflag_DOINT = 256;
114 | const SAEC_spcflag_BLTNASTY = 512;
115 | //const SAEC_spcflag_EXEC = 1024;
116 | //const SAEC_spcflag_ACTION_REPLAY = 2048;
117 | //const SAEC_spcflag_TRAP = 4096; /* enforcer-hack */
118 | const SAEC_spcflag_MODE_CHANGE = 8192;
119 | const SAEC_spcflag_CHECK = 32768;
120 |
121 | const SAEC_command_Quit = 1;
122 | const SAEC_command_Reset = 2;
123 | const SAEC_command_KeyboardReset = 3;
124 | const SAEC_command_HardReset = 4;
125 | const SAEC_command_Pause = 5;
126 | const SAEC_command_Resume = 6;
127 |
128 | /*---------------------------------*/
129 |
130 | const SAEC_Info_Brower_ID_Unknown = 0;
131 | const SAEC_Info_Brower_ID_Chrome = 1;
132 | const SAEC_Info_Brower_ID_Safari = 2;
133 | const SAEC_Info_Brower_ID_Opera = 3;
134 | const SAEC_Info_Brower_ID_Firefox = 4;
135 | const SAEC_Info_Brower_ID_InternetExplorer = 5;
136 |
137 | const SAEC_info = (function() {
138 | var info = {
139 | browser: {
140 | id: SAEC_Info_Brower_ID_Unknown,
141 | name: "Unknown",
142 | plat: "Unknown",
143 | lang: "en"
144 | },
145 | memory: {
146 | maxSize: 0
147 | },
148 | audio: {
149 | webAudio: false
150 | },
151 | video: {
152 | canvas: false,
153 | webGL: false,
154 | pointerLock: false,
155 | requestFullScreen: false
156 | },
157 | input: {
158 | gamepad: false
159 | }
160 | };
161 |
162 | /* browser */
163 | if (navigator.userAgent.indexOf("Chrome") > -1) {
164 | info.browser.id = SAEC_Info_Brower_ID_Chrome;
165 | info.browser.name = "Google Chrome";
166 | }
167 | else if (navigator.userAgent.indexOf("Safari") > -1) {
168 | info.browser.id = SAEC_Info_Brower_ID_Safari;
169 | info.browser.name = "Apple Safari";
170 | }
171 | else if (navigator.userAgent.indexOf("Opera") > -1) {
172 | info.browser.id = SAEC_Info_Brower_ID_Opera;
173 | info.browser.name = "Opera";
174 | }
175 | else if (navigator.userAgent.indexOf("Firefox") > -1) {
176 | info.browser.id = SAEC_Info_Brower_ID_Firefox;
177 | info.browser.name = "Mozilla Firefox";
178 | }
179 | else if (navigator.userAgent.indexOf("MSIE") > -1) {
180 | info.browser.id = SAEC_Info_Brower_ID_InternetExplorer;
181 | info.browser.name = "Microsoft Internet Explorer";
182 | }
183 | info.browser.plat = navigator.platform;
184 | info.browser.lang = navigator.language;
185 |
186 | /* max memory */
187 | if (0) {
188 | var size = 1048576;
189 | while (true) {
190 | try {
191 | var data = new Uint8Array(size);
192 | delete data;
193 | info.memory.maxSize = size;
194 | } catch (e) {
195 | break;
196 | }
197 | size *= 2;
198 | }
199 | } else
200 | info.memory.maxSize = 1073741824; //1G
201 |
202 | /* audio */
203 | if (typeof window.webkitAudioContext != "undefined" || typeof window.AudioContext != "undefined" )
204 | info.audio.webAudio = true;
205 | /* disabled because audioContextDriver() does require user-initiation
206 | var audioContext = null;
207 | try {
208 | var audioContextDriver = window.AudioContext || window.webkitAudioContext;
209 | audioContext = new audioContextDriver();
210 | var audioProcessor = audioContext.createScriptProcessor(1024, 2, 2);
211 |
212 | info.audio.webAudio = true;
213 |
214 | if (audioContext.close) audioContext.close().then(function() {});
215 | audioContext = null;
216 | } catch (e) {
217 | if (audioContext) {
218 | if (audioContext.close) audioContext.close().then(function() {});
219 | audioContext = null;
220 | }
221 | }*/
222 |
223 | /* video */
224 | var canvas = document.createElement("canvas");
225 | if (canvas && canvas.getContext) {
226 | try {
227 | var ctx = canvas.getContext("2d");
228 | var imageData = ctx.createImageData(16, 16);
229 | info.video.canvas = true;
230 |
231 | try {
232 | const glParams = {
233 | alpha: false,
234 | depth: true,
235 | stencil: false,
236 | antialias: false,
237 | premultipliedAlpha: false,
238 | preserveDrawingBuffer: true,
239 | failIfMajorPerformanceCaveat: false
240 | };
241 | ctx = canvas.getContext("webgl", glParams) || canvas.getContext("experimental-webgl", glParams);
242 | info.video.webGL = true;
243 | } catch(e) {}
244 |
245 | /* pointerLock API */
246 | if (canvas.webkitRequestPointerLock !== undefined ||
247 | canvas.mozRequestPointerLock !== undefined ||
248 | canvas.msRequestPointerLock !== undefined ||
249 | canvas.requestPointerLock !== undefined
250 | ) info.video.pointerLock = true;
251 |
252 | /* fullScreen API */
253 | if (canvas.webkitRequestFullscreen !== undefined ||
254 | canvas.mozRequestFullScreen !== undefined ||
255 | canvas.msRequestFullscreen !== undefined ||
256 | canvas.requestFullScreen !== undefined
257 | ) info.video.requestFullScreen = true;
258 | } catch(e) {}
259 | }
260 |
261 | /* gamepad API */
262 | if (navigator.webkitGetGamepads !== undefined || navigator.getGamepads !== undefined)
263 | info.input.gamepad = true;
264 |
265 | return info;
266 | })();
267 |
268 | /*---------------------------------*/
269 | /* global variables */
270 |
271 | var SAEV_spcflags = 0;
272 | var SAEV_command = 0;
273 |
274 | /*---------------------------------*/
275 | /* global functions */
276 |
277 | function SAEF_setSpcFlags(x) { SAEV_spcflags |= x; };
278 | function SAEF_clrSpcFlags(x) { SAEV_spcflags &= ~x; };
279 |
280 | /*---------------------------------*/
281 |
282 | function SAEF_now() {
283 | return Math.floor(performance.now() * 1000); /* micro-seconds since page-load */
284 | }
285 | function SAEF_sleep(ms) {
286 | var start = performance.now();
287 | while ((performance.now() - start) < ms) {} /* pretty nasty */
288 | }
289 |
290 | /*---------------------------------*/
291 | /* debug */
292 |
293 | function SAEF_log() {
294 | if (SAEV_config.debug.level >= SAEC_Config_Debug_Level_Log && arguments.length) {
295 | var str = sprintf.apply(this, arguments);
296 | if (console.log) console.log(str);
297 | }
298 | }
299 | function SAEF_info() {
300 | if (SAEV_config.debug.level >= SAEC_Config_Debug_Level_Info && arguments.length) {
301 | var str = sprintf.apply(this, arguments);
302 | if (console.info) console.info(str);
303 | }
304 | }
305 | function SAEF_warn() {
306 | if (SAEV_config.debug.level >= SAEC_Config_Debug_Level_Warn && arguments.length) {
307 | var str = sprintf.apply(this, arguments);
308 | if (console.warn) console.warn(str);
309 |
310 | }
311 | }
312 | function SAEF_error() {
313 | if (SAEV_config.debug.level >= SAEC_Config_Debug_Level_Error && arguments.length) {
314 | var str = sprintf.apply(this, arguments);
315 | if (console.error) console.error(str);
316 | }
317 | }
318 | function SAEF_fatal() {
319 | var argumentsArray = Array.prototype.slice.call(arguments);
320 | var err = argumentsArray[0];
321 | var str = sprintf.apply(this, argumentsArray.slice(1));
322 | if (console.error) console.error(str);
323 | throw new SAEO_Error(err, str);
324 | }
325 |
326 | function SAEF_assert(cond) {
327 | if (!cond) {
328 | var err = SAEE_Assert;
329 | var str = "Assertion failed. This is a bug in SAE.";
330 | if (console.error) console.error(str);
331 | throw new SAEO_Error(err, str);
332 | }
333 | }
334 |
335 | /*---------------------------------*/
336 |
337 | function ScriptedAmigaEmulator() {
338 | SAER = this;
339 |
340 | this.audio = new SAEO_Audio();
341 | this.autoconf = new SAEO_AutoConf();
342 | this.blitter = new SAEO_Blitter();
343 | this.cia = new SAEO_CIA();
344 | this.config = new SAEO_Configuration();
345 | this.copper = new SAEO_Copper();
346 | this.cpu = new SAEO_CPU();
347 | this.custom = new SAEO_Custom();
348 | this.devices = new SAEO_Devices();
349 | this.disk = new SAEO_Disk();
350 | this.dongle = new SAEO_Dongle();
351 | this.events = new SAEO_Events();
352 | this.expansion = new SAEO_Expansion();
353 | this.filesys = new SAEO_Filesys();
354 | this.gayle = new SAEO_Gayle();
355 | this.gui = new SAEO_GUI();
356 | this.hardfile = new SAEO_Hardfile();
357 | this.ide = new SAEO_IDE();
358 | this.input = new SAEO_Input();
359 | this.m68k = new SAEO_M68K();
360 | this.memory = new SAEO_Memory();
361 | this.parallel = new SAEO_Parallel();
362 | this.playfield = new SAEO_Playfield();
363 | this.roms = new SAEO_Roms();
364 | this.rtc = new SAEO_RTC();
365 | this.serial = new SAEO_Serial();
366 | this.video = new SAEO_Video();
367 |
368 | /*---------------------------------*/
369 |
370 | this.running = false;
371 | this.paused = false;
372 |
373 | /*-----------------------------------------------------------------------*/
374 |
375 | this.dump = function () {
376 | this.m68k.dump();
377 | //this.memory.dump();
378 | //this.cia.dump();
379 | };
380 |
381 | /*-----------------------------------------------------------------------*/
382 |
383 | this.do_start_program = function() {
384 | if (SAEV_command >= 0)
385 | SAEV_command = SAEC_command_Reset;
386 |
387 | this.m68k.m68k_go(true);
388 | }
389 |
390 | this.do_leave_program = function() {
391 | //sampler_free();
392 | this.video.cleanup();
393 | this.input.cleanup();
394 | this.disk.cleanup();
395 | this.audio.cleanup();
396 | //dump_counts();
397 | this.serial.cleanup();
398 | /*#ifdef CDTV
399 | cdtv_free();
400 | cdtvcr_free();
401 | #endif
402 | #ifdef CD32
403 | akiko_free();
404 | cd32_fmv_free();
405 | #endif*/
406 | //this.gui.cleanup(); //empty
407 | //#ifdef AUTOCONFIG
408 | this.expansion.cleanup();
409 | //#endif
410 | //#ifdef FILESYS
411 | this.filesys.cleanup();
412 | //#endif
413 | this.gayle.cleanup();
414 | /*idecontroller_free();
415 | device_func_reset();
416 | #ifdef WITH_TOCCATA
417 | sndboard_free();
418 | #endif*/
419 | this.memory.cleanup();
420 | //free_shm();
421 | this.autoconf.cleanup();
422 | }
423 |
424 | this.start_program = function() {
425 | this.do_start_program();
426 |
427 | if (typeof SAEV_config.hook.event.started === "function")
428 | SAEV_config.hook.event.started();
429 | }
430 |
431 | this.leave_program = function() {
432 | this.dump();
433 | this.do_leave_program();
434 |
435 | if (typeof SAEV_config.hook.event.stopped === "function")
436 | SAEV_config.hook.event.stopped();
437 | }
438 |
439 | this.pause_program = function(p) {
440 | this.audio.pauseResume(p);
441 | this.events.pauseResume(p);
442 |
443 | if (typeof SAEV_config.hook.event.paused === "function")
444 | SAEV_config.hook.event.paused(p);
445 | }
446 |
447 | /*---------------------------------*/
448 | /* API */
449 |
450 | this.getVersion = function(str) {
451 | if (str)
452 | return sprintf("%d.%d.%d", SAEC_Version, SAEC_Revision, SAEC_Patch);
453 | else
454 | return [SAEC_Version, SAEC_Revision, SAEC_Patch];
455 | }
456 | this.getInfo = function() {
457 | return SAEC_info;
458 | }
459 | this.getConfig = function() {
460 | return SAEV_config;
461 | }
462 |
463 | this.setDefaults = function() {
464 | return this.config.setDefaults();
465 | }
466 | this.setModel = function(model, config) {
467 | return this.config.setModel(model, config);
468 | }
469 |
470 | this.setMountInfoDefaults = function(num) {
471 | var ci = SAEV_config.mount.config[num].ci;
472 | this.filesys.uci_set_defaults(ci, false);
473 | }
474 |
475 | this.start = function() {
476 | if (SAER.running) {
477 | SAEF_warn("sae.start() emulation already running");
478 | return SAEE_AlreadyRunning;
479 | }
480 | SAEF_info("sae.start() starting...");
481 |
482 | var err;
483 | if ((err = this.config.setup()) != SAEE_None)
484 | return err;
485 | if ((err = this.video.obtain()) != SAEE_None)
486 | return err;
487 | if ((err = this.audio.obtain()) != SAEE_None)
488 | return err;
489 | if ((err = this.input.setup()) != SAEE_None) //inputdevice_init();
490 | return err;
491 | if ((err = this.gui.setup()) != SAEE_None)
492 | return err;
493 |
494 | /*#ifdef PICASSO96
495 | picasso_reset();
496 | #endif*/
497 |
498 | //this.config.fixup_prefs(currprefs, true);
499 | //SAEV_config.audio.mode = 0; /* force sound settings change */
500 |
501 | this.memory.hardreset(2);
502 | if ((err = this.memory.reset(true)) == SAEE_None)
503 | {
504 | /*#ifdef AUTOCONFIG
505 | native2amiga_install();
506 | #endif*/
507 | this.custom.setup(); //OWN
508 | this.blitter.setup(); //OWN
509 | this.playfield.setup(); //custom_init();
510 | //this.serial.setup(); //empty
511 | this.disk.setup();
512 |
513 | this.events.reset_frame_rate_hack();
514 | if ((err = this.m68k.setup()) == SAEE_None) /* m68k_init() must come after reset_frame_rate_hack() */
515 | {
516 | //this.gui.update(); //empty
517 | if ((err = this.video.setup(true)) == SAEE_None)
518 | {
519 | if ((err = this.audio.setup()) == SAEE_None)
520 | {
521 | this.start_program();
522 | SAEF_info("sae.start() ...done");
523 | return SAEE_None;
524 | }
525 | this.video.cleanup();
526 | }
527 | }
528 | }
529 | this.input.cleanup();
530 | SAEF_error("sae.start() ...error %d", err);
531 | return err;
532 | }
533 |
534 | this.stop = function() { //uae_quit()
535 | if (this.running) {
536 | SAEF_info("sae.stop()");
537 | if (SAEV_command != -SAEC_command_Quit)
538 | SAEV_command = -SAEC_command_Quit;
539 |
540 | return SAEE_None;
541 | } else {
542 | SAEF_warn("sae.stop() emulation not running");
543 | return SAEE_NotRunning;
544 | }
545 | };
546 |
547 | this.reset = function(hard, keyboard) { //uae_reset(hard, keyboard)
548 | if (typeof hard == "undefined") var hard = false;
549 | if (typeof keyboard == "undefined") var keyboard = false;
550 | if (this.running) {
551 | SAEF_info("sae.reset() hard %d, keyboard %d", hard?1:0, keyboard?1:0);
552 | if (SAEV_command == 0) {
553 | SAEV_command = -SAEC_command_Reset; /* soft */
554 | if (keyboard)
555 | SAEV_command = -SAEC_command_KeyboardReset;
556 | if (hard)
557 | SAEV_command = -SAEC_command_HardReset;
558 | }
559 | return SAEE_None;
560 | } else {
561 | SAEF_warn("sae.reset() emulation not running");
562 | return SAEE_NotRunning;
563 | }
564 | };
565 |
566 | this.pause = function(pause) {
567 | if (this.running) {
568 | if (!this.paused && pause) {
569 | SAEF_info("sae.pause() pausing emulation");
570 | SAEV_command = SAEC_command_Pause;
571 | }
572 | else if (this.paused && !pause) {
573 | SAEF_info("sae.pause() resuming emulation");
574 | SAEV_command = SAEC_command_Resume;
575 | }
576 | return SAEE_None;
577 | } else {
578 | SAEF_warn("sae.pause() emulation not running");
579 | return SAEE_NotRunning;
580 | }
581 | };
582 |
583 | this.mute = function(mute) {
584 | if (this.running) {
585 | this.audio.mute(mute);
586 | if (mute)
587 | SAEF_log("sae.mute() audio muted");
588 | else
589 | SAEF_log("sae.mute() playing audio");
590 | return SAEE_None;
591 | } else {
592 | SAEF_warn("sae.mute() emulation not running");
593 | return SAEE_NotRunning;
594 | }
595 | };
596 |
597 | this.screen = function(screen) {
598 | if (this.running) {
599 | if (SAEC_info.video.requestFullScreen) {
600 | this.video.screen(screen);
601 | if (screen)
602 | SAEF_log("sae.screen() screen-mode");
603 | else
604 | SAEF_log("sae.screen() window-mode");
605 | return SAEE_None;
606 | } else {
607 | SAEF_error("sae.screen() screen-api not supported");
608 | return SAEE_Video_RequiresFullscreen;
609 | }
610 | } else {
611 | SAEF_warn("sae.screen() emulation not running");
612 | return SAEE_NotRunning;
613 | }
614 | };
615 |
616 | this.insert = function(unit) {
617 | if (this.running) {
618 | var file = SAEV_config.floppy.drive[unit].file;
619 | this.disk.insert(unit, file);
620 | SAEF_info("sae.insert() unit %d inserted, name '%s', size %d, protected %d", unit, file.name, file.size, file.prot?1:0);
621 | return SAEE_None;
622 | } else {
623 | SAEF_warn("sae.insert() emulation not running");
624 | return SAEE_NotRunning;
625 | }
626 | };
627 |
628 | this.eject = function(unit) {
629 | if (this.running) {
630 | this.disk.eject(unit);
631 | SAEF_info("sae.eject() unit %d ejected", unit);
632 | return SAEE_None;
633 | } else {
634 | SAEF_warn("sae.eject() emulation not running");
635 | return SAEE_NotRunning;
636 | }
637 | };
638 |
639 | this.getRomInfo = function(ri, file) {
640 | return this.roms.examine(ri, file);
641 | };
642 |
643 | this.getDiskInfo = function(di, unit) {
644 | return this.disk.examine(di, unit);
645 | };
646 |
647 | this.createDisk = function(unit, name, mode, type, label, ffs, bootable) {
648 | if (!this.disk.create(unit, name, mode, type, label, ffs, bootable))
649 | return SAEE_NoMemory;
650 | return SAEE_None;
651 | };
652 |
653 | this.keyPress = function(e, down) {
654 | this.input.keyPress(e, down);
655 | return SAEE_None;
656 | };
657 |
658 | /*---------------------------------*/
659 |
660 | SAEF_info("SAE %d.%d.%d", SAEC_Version, SAEC_Revision, SAEC_Patch);
661 | }
662 |
--------------------------------------------------------------------------------
/sae/autoconf.js:
--------------------------------------------------------------------------------
1 | /*-------------------------------------------------------------------------
2 | | SAE - Scripted Amiga Emulator
3 | | https://github.com/naTmeg/ScriptedAmigaEmulator
4 | |
5 | | Copyright (C) 2012 Rupert Hausberger
6 | |
7 | | This program is free software; you can redistribute it and/or
8 | | modify it under the terms of the GNU General Public License
9 | | as published by the Free Software Foundation; either version 2
10 | | of the License, or (at your option) any later version.
11 | |
12 | | This program is distributed in the hope that it will be useful,
13 | | but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | | GNU General Public License for more details.
16 | |
17 | | Note: ported from WinUAE 3.2.x
18 | -------------------------------------------------------------------------*/
19 | /* global references */
20 |
21 | var SAER_AutoConf_bank = null;
22 |
23 | /*---------------------------------*/
24 | /* global constants */
25 |
26 | const SAEC_AutoConf_RTS = 0x4e75;
27 | //const SAEC_AutoConf_RTE = 0x4e73;
28 |
29 | /*---------------------------------*/
30 | /* global variables */
31 |
32 | var SAEV_AutoConf_base = 0xf00000; //RTAREA_DEFAULT;
33 |
34 | var SAEV_AutoConf_boot_rom_type = 0;
35 | var SAEV_AutoConf_boot_rom_size = 0;
36 |
37 | /*---------------------------------*/
38 |
39 | function SAEO_AutoConf() {
40 | const RTAREA_DEFAULT = 0xf00000;
41 | const RTAREA_BACKUP = 0xef0000;
42 | const RTAREA_BACKUP_2 = 0xdb0000;
43 | const RTAREA_SIZE = 0x10000;
44 |
45 | const RTAREA_TRAPS = 0x3000;
46 | const RTAREA_RTG = 0x3800;
47 | const RTAREA_TRAMPOLINE = 0x3b00;
48 | const RTAREA_DATAREGION = 0xF000;
49 |
50 | const RTAREA_FSBOARD = 0xFFEC;
51 | const RTAREA_HEARTBEAT = 0xFFF0;
52 | const RTAREA_TRAPTASK = 0xFFF4;
53 | const RTAREA_EXTERTASK = 0xFFF8;
54 | const RTAREA_INTREQ = 0xFFFC;
55 |
56 | const RTAREA_TRAP_DATA = 0x4000;
57 | const RTAREA_TRAP_DATA_SIZE = 0x8000;
58 | const RTAREA_TRAP_DATA_SLOT_SIZE = 0x2000; // 8192
59 | const RTAREA_TRAP_DATA_SECOND = 80;
60 | const RTAREA_TRAP_DATA_TASKWAIT = (RTAREA_TRAP_DATA_SECOND - 4);
61 | const RTAREA_TRAP_DATA_EXTRA = 144;
62 | const RTAREA_TRAP_DATA_EXTRA_SIZE = (RTAREA_TRAP_DATA_SLOT_SIZE - RTAREA_TRAP_DATA_EXTRA);
63 |
64 | const RTAREA_TRAP_SEND_DATA = 0xc0000;
65 | const RTAREA_TRAP_SEND_DATA_SIZE = 0x2000;
66 |
67 | const RTAREA_TRAP_STATUS = 0xF000;
68 | const RTAREA_TRAP_STATUS_SIZE = 8;
69 | const RTAREA_TRAP_STATUS_SECOND = 4;
70 |
71 | const RTAREA_TRAP_SEND_STATUS = 0xF100;
72 |
73 | const RTAREA_SYSBASE = 0x3FFC;
74 |
75 | const RTAREA_TRAP_DATA_NUM = (RTAREA_TRAP_DATA_SIZE / RTAREA_TRAP_DATA_SLOT_SIZE);
76 |
77 |
78 |
79 | /* Commonly used autoconfig strings */
80 | //var EXPANSION_explibname = 0, EXPANSION_doslibname = 0, EXPANSION_uaeversion = 0;
81 | //var EXPANSION_uaedevname, EXPANSION_explibbase = 0;
82 | //var EXPANSION_bootcode = 0, EXPANSION_nullfunc = 0;
83 |
84 | /* ROM tag area memory access */
85 | //var rtarea_base = RTAREA_DEFAULT; --> SAEV_AutoConf_base
86 | var hardware_trap_event = new Array(RTAREA_TRAP_DATA_SIZE / RTAREA_TRAP_DATA_SLOT_SIZE); //HANDLE
87 |
88 | var rt_trampoline_ptr = 0, trap_entry = 0;
89 | //var hwtrap_waiting = 0; //extern volatile uae_atomic, in traps
90 | var filesystem_state = 0; //extern int
91 |
92 | //var uae_boot_rom_type = 0; -> SAEV_AutoConf_boot_rom_type
93 | //var uae_boot_rom_size = 0; -> SAEV_AutoConf_boot_rom_size
94 |
95 | var uae_int_requested = 0; //volatile uae_atomic
96 |
97 | /*-----------------------------------------------------------------------*/
98 |
99 | function check_boot_rom(p) {
100 | var b = RTAREA_DEFAULT;
101 |
102 | /*if (currprefs.uaeboard > 1) {
103 | p.type = 2;
104 | return 0x00eb0000; // fixme!
105 | }
106 | p.type = 0;
107 | if (currprefs.boot_rom == 1)
108 | return 0;*/
109 | p.type = 1;
110 | /*if (currprefs.cs_cdtvcd || currprefs.cs_cdtvscsi || currprefs.uae_hide > 1)
111 | b = RTAREA_BACKUP;*/
112 | if (SAEV_config.chipset.mbdmac == 1)// || currprefs.cpuboard_type)
113 | b = RTAREA_BACKUP;
114 | // CSPPC enables MMU at boot and remaps 0xea0000->0xeffff.
115 | /*if (ISCPUBOARD(BOARD_BLIZZARD, BOARD_BLIZZARD_SUB_PPC))
116 | b = RTAREA_BACKUP_2;*/
117 | var ab = SAER_Memory_getBank(RTAREA_DEFAULT);
118 | if (ab !== null) {
119 | if (SAER_Memory_check(RTAREA_DEFAULT, 65536))
120 | b = RTAREA_BACKUP;
121 | }
122 | /*if (nr_directory_units(NULL))
123 | return b;
124 | if (nr_directory_units(&currprefs))
125 | return b;
126 | if (currprefs.socket_emu)
127 | return b;
128 | if (currprefs.uaeserial)
129 | return b;
130 | if (currprefs.scsi == 1) //uaescsi.device
131 | return b;
132 | if (currprefs.sana2)
133 | return b;
134 | if (currprefs.input_tablet > 0)
135 | return b;
136 | if (currprefs.rtgmem_size && currprefs.rtgmem_type < GFXBOARD_HARDWARE)
137 | return b;
138 | if (currprefs.win32_automount_removable)
139 | return b;*/
140 | if (SAEV_config.memory.chipSize > 2 * 1024 * 1024)
141 | return b;
142 | /*if (currprefs.z3chipmem_size)
143 | return b;
144 | if (currprefs.boot_rom >= 3)
145 | return b;
146 | if (currprefs.boot_rom == 2 && b == 0xf00000) {
147 | p.type = -1;
148 | return b;
149 | }*/
150 | p.type = 0;
151 | return 0;
152 | }
153 |
154 | this.need_uae_boot_rom = function() {
155 | var p = { type:0 };
156 | var v = check_boot_rom(p);
157 | SAEV_AutoConf_boot_rom_type = p.type;
158 | SAEF_log("autoconf.need_uae_boot_rom() type %d", SAEV_AutoConf_boot_rom_type);
159 | if (!SAEV_AutoConf_base) {
160 | v = 0;
161 | SAEV_AutoConf_boot_rom_type = 0;
162 | }
163 | return v;
164 | }
165 |
166 | /*-----------------------------------------------------------------------*/
167 |
168 | /*static bool istrapwait(void) {
169 | for (int i = 0; i < RTAREA_TRAP_DATA_NUM; i++) {
170 | uae_u8 *data = rtarea_bank.baseaddr + RTAREA_TRAP_DATA + i * RTAREA_TRAP_DATA_SLOT_SIZE;
171 | uae_u8 *status = rtarea_bank.baseaddr + RTAREA_TRAP_STATUS + i * RTAREA_TRAP_STATUS_SIZE;
172 | if (get_long_host(data + RTAREA_TRAP_DATA_TASKWAIT) && status[3] && status[2] >= 0x80) {
173 | return true;
174 | }
175 | }
176 | return false;
177 | }*/
178 | this.rethink_traps = function() {
179 | return false;
180 | /*if (currprefs.uaeboard < 2)
181 | return false;
182 | if (istrapwait()) {
183 | atomic_or(&uae_int_requested, 0x4000);
184 | set_special_exter(SPCFLAG_UAEINT);
185 | return true;
186 | }
187 | atomic_and(&uae_int_requested, ~0x4000);
188 | return false;*/
189 | }
190 |
191 | /*-----------------------------------------------------------------------*/
192 |
193 | const RTAREA_WRITEOFFSET = 0xfff0;
194 |
195 | function hwtrap_check_int() {
196 | if (hwtrap_waiting == 0) {
197 | atomic_and(uae_int_requested, ~0x2000);
198 | } else {
199 | atomic_or(uae_int_requested, 0x2000);
200 | set_special_exter(SPCFLAG_UAEINT);
201 | }
202 | }
203 |
204 | function rtarea_trap_data(addr) {
205 | if (addr >= RTAREA_TRAP_DATA && addr < RTAREA_TRAP_DATA + RTAREA_TRAP_DATA_SIZE)
206 | return true;
207 | return false;
208 | }
209 |
210 | function rtarea_trap_status(addr) {
211 | if (addr >= RTAREA_TRAP_STATUS && addr < RTAREA_TRAP_STATUS + RTAREA_TRAP_DATA_NUM * RTAREA_TRAP_STATUS_SIZE)
212 | return true;
213 | return false;
214 | }
215 |
216 | /*---------------------------------*/
217 |
218 | function rtarea_get32(addr) {
219 | addr &= 0xFFFF;
220 | return ((rtarea_bank.baseaddr[addr] << 24) | (rtarea_bank.baseaddr[addr + 1] << 16) | (rtarea_bank.baseaddr[addr + 2] << 8) | rtarea_bank.baseaddr[addr + 3]) >>> 0;
221 | }
222 | function rtarea_get16(addr) {
223 | addr &= 0xFFFF;
224 | return (rtarea_bank.baseaddr[addr] << 8) + rtarea_bank.baseaddr[addr + 1];
225 | }
226 | function rtarea_get8(addr) {
227 | addr &= 0xFFFF;
228 |
229 | if (rtarea_trap_status(addr)) {
230 | var addr2 = addr - RTAREA_TRAP_STATUS;
231 | var trap_offset = addr2 & (RTAREA_TRAP_STATUS_SIZE - 1);
232 | var trap_slot = Math.floor(addr2 / RTAREA_TRAP_STATUS_SIZE);
233 | if (trap_offset == 0) {
234 | // 0 = busy wait, 1 = Wait()
235 | rtarea_bank.baseaddr[addr] = filesystem_state ? 1 : 0;
236 | }
237 | } else if (addr == RTAREA_INTREQ + 0) {
238 | rtarea_bank.baseaddr[addr] = atomic_bit_test_and_reset(uae_int_requested, 0);
239 | //SAEF_log("autoconf.rtarea_get8() %s", rtarea_bank.baseaddr[addr] ? "+" : "-");
240 | } else if (addr == RTAREA_INTREQ + 1) {
241 | rtarea_bank.baseaddr[addr] = hwtrap_waiting != 0;
242 | } else if (addr == RTAREA_INTREQ + 2) {
243 | /*if (SAER.autoconf.rethink_traps()) //OWN empty
244 | rtarea_bank.baseaddr[addr] = 1;
245 | else*/
246 | rtarea_bank.baseaddr[addr] = 0;
247 | }
248 | hwtrap_check_int();
249 | return rtarea_bank.baseaddr[addr];
250 | }
251 |
252 | function rtarea_write(addr) {
253 | if (addr >= RTAREA_WRITEOFFSET)
254 | return true;
255 | if (addr >= RTAREA_SYSBASE && addr < RTAREA_SYSBASE + 4)
256 | return true;
257 | return rtarea_trap_data(addr) || rtarea_trap_status(addr);
258 | }
259 | function rtarea_put8(addr, value) {
260 | addr &= 0xffff;
261 | if (!rtarea_write(addr))
262 | return;
263 | rtarea_bank.baseaddr[addr] = value;
264 | if (!rtarea_trap_status(addr))
265 | return;
266 | addr -= RTAREA_TRAP_STATUS;
267 | var trap_offset = addr & (RTAREA_TRAP_STATUS_SIZE - 1);
268 | var trap_slot = Math.floor(addr / RTAREA_TRAP_STATUS_SIZE);
269 | if (trap_offset == RTAREA_TRAP_STATUS_SECOND + 3) {
270 | var v = value;
271 | if (v != 0xff && v != 0xfe && v != 0x01 && v != 02)
272 | SAEF_log("autoconf.rtarea_put8() TRAP %d (%02x)", trap_slot, v);
273 | if (v == 0xfe)
274 | atomic_dec(hwtrap_waiting);
275 | if (v == 0x01)
276 | atomic_dec(hwtrap_waiting);
277 | if (v == 0x01 || v == 0x02) {
278 | // signal call_hardware_trap_back()
279 | // FIXME: OS specific code!
280 | SetEvent(hardware_trap_event[trap_slot]);
281 | }
282 | }
283 | }
284 | function rtarea_put16(addr, value) {
285 | addr &= 0xffff;
286 | value &= 0xffff;
287 | if (!rtarea_write(addr))
288 | return;
289 | rtarea_put8(addr, value >> 8);
290 | rtarea_put8(addr + 1, value & 0xff);
291 | if (!rtarea_trap_status(addr))
292 | return;
293 | addr -= RTAREA_TRAP_STATUS;
294 | var trap_offset = addr & (RTAREA_TRAP_STATUS_SIZE - 1);
295 | var trap_slot = Math.floor(addr / RTAREA_TRAP_STATUS_SIZE);
296 | if (trap_offset == 0) {
297 | SAEF_log("autoconf.rtarea_put16() TRAP %d (%04x)", trap_slot, value);
298 | call_hardware_trap(rtarea_bank.baseaddr, SAEV_AutoConf_base, trap_slot);
299 | }
300 | }
301 | function rtarea_put32(addr, value) {
302 | addr &= 0xffff;
303 | if (!rtarea_write(addr))
304 | return;
305 | rtarea_bank.baseaddr[addr + 0] = value >>> 24;
306 | rtarea_bank.baseaddr[addr + 1] = (value >>> 16) & 0xff;
307 | rtarea_bank.baseaddr[addr + 2] = (value >>> 8) & 0xff;
308 | rtarea_bank.baseaddr[addr + 3] = value & 0xff;
309 | }
310 |
311 | function rtarea_xlate(addr) {
312 | addr &= 0xFFFF;
313 | //return rtarea_bank.baseaddr + addr;
314 | return addr;
315 | }
316 | function rtarea_check(addr, size) {
317 | addr &= 0xFFFF;
318 | return (addr + size) <= 0xFFFF;
319 | }
320 |
321 | var rtarea_bank = new SAEO_Memory_addrbank(
322 | rtarea_get32, rtarea_get16, rtarea_get8,
323 | rtarea_put32, rtarea_put16, rtarea_put8,
324 | rtarea_xlate, rtarea_check, null, "rtarea", "UAE Boot ROM",
325 | rtarea_get32, rtarea_get16,
326 | SAEC_Memory_addrbank_flag_ROMIN | SAEC_Memory_addrbank_flag_PPCIOSPACE//, S_READ, S_WRITE
327 | );
328 | SAER_AutoConf_bank = rtarea_bank;
329 |
330 | /*-----------------------------------------------------------------------*/
331 |
332 | this.reset = function() { //rtarea_reset()
333 | //memset(rtarea_bank.baseaddr + RTAREA_TRAP_DATA, 0, RTAREA_TRAP_DATA_SIZE);
334 | //memset(rtarea_bank.baseaddr + RTAREA_TRAP_STATUS, 0, RTAREA_TRAP_STATUS_SIZE * RTAREA_TRAP_DATA_NUM);
335 | SAEF_memset(rtarea_bank.baseaddr,RTAREA_TRAP_DATA, 0, RTAREA_TRAP_DATA_SIZE);
336 | SAEF_memset(rtarea_bank.baseaddr,RTAREA_TRAP_STATUS, 0, RTAREA_TRAP_STATUS_SIZE * RTAREA_TRAP_DATA_NUM);
337 | }
338 |
339 | /*-----------------------------------------------------------------------*/
340 | /* some quick & dirty code to fill in the rt area and save me a lot of scratch paper */
341 |
342 | var rt_addr = 0;
343 | var rt_straddr = 0;
344 |
345 | function addr(ptr) {
346 | //SAEF_log("autoconf.addr() %08x", ptr + SAEV_AutoConf_base);
347 | //return (uae_u32)ptr + SAEV_AutoConf_base;
348 | return ptr + SAEV_AutoConf_base;
349 | }
350 | this.db = function(data) {
351 | //SAEF_log("autoconf.db() %02x", data);
352 | rtarea_bank.baseaddr[rt_addr++] = data;
353 | }
354 | this.dw = function(data) {
355 | //SAEF_log("autoconf.dw() %04x", data);
356 | rtarea_bank.baseaddr[rt_addr++] = data >> 8;
357 | rtarea_bank.baseaddr[rt_addr++] = data & 0xff;
358 | }
359 | this.dl = function(data) {
360 | //SAEF_log("autoconf.dl() %08x", data);
361 | rtarea_bank.baseaddr[rt_addr++] = data >> 24;
362 | rtarea_bank.baseaddr[rt_addr++] = (data >> 16) & 0xff;
363 | rtarea_bank.baseaddr[rt_addr++] = (data >> 8) & 0xff;
364 | rtarea_bank.baseaddr[rt_addr++] = data & 0xff;
365 | }
366 |
367 | /*this.dbg = function(addr) {
368 | addr -= SAEV_AutoConf_base;
369 | return rtarea_bank.baseaddr[addr];
370 | }*/
371 |
372 | /* store strings starting at the end of the rt area and working backward. store pointer at current address */
373 | /*uae_u32 ds_ansi (const uae_char *str) {
374 | int len;
375 |
376 | if (!str)
377 | return addr (rt_straddr);
378 | len = strlen (str) + 1;
379 | rt_straddr -= len;
380 | strcpy ((uae_char*)rtarea_bank.baseaddr + rt_straddr, str);
381 | return addr (rt_straddr);
382 | }
383 | uae_u32 ds (const TCHAR *str) {
384 | char *s = ua (str);
385 | uae_u32 v = ds_ansi (s);
386 | xfree (s);
387 | return v;
388 | }
389 | uae_u32 ds_bstr_ansi (const uae_char *str) {
390 | int len;
391 |
392 | len = strlen (str) + 2;
393 | rt_straddr -= len;
394 | while (rt_straddr & 3)
395 | rt_straddr--;
396 | rtarea_bank.baseaddr[rt_straddr] = len - 2;
397 | strcpy ((uae_char*)rtarea_bank.baseaddr + rt_straddr + 1, str);
398 | return addr (rt_straddr) >> 2;
399 | }*/
400 |
401 | this.calltrap = function(n) {
402 | /*if (currprefs.uaeboard > 2) {
403 | this.dw(0x4eb9); // JSR rt_trampoline_ptr
404 | this.dl(rt_trampoline_ptr);
405 | uaecptr a = this.here();
406 | this.org(rt_trampoline_ptr);
407 | this.dw(0x3f3c); // MOVE.W #n,-(SP)
408 | this.dw(n);
409 | this.dw(0x4ef9); // JMP rt_trampoline_entry
410 | this.dl(trap_entry);
411 | this.org(a);
412 | rt_trampoline_ptr += 3 * 2 + 1 * 4;
413 | } else*/
414 | this.dw(0xA000 + n);
415 | }
416 |
417 | this.org = function(a) {
418 | if (((a & 0xffff0000) >>> 0 != 0x00f00000) && ((a & 0xffff0000) >>> 0 != SAEV_AutoConf_base))
419 | SAEF_warn("autoconf.org() corrupt address %08X", a);
420 | rt_addr = a & 0xffff;
421 | }
422 |
423 | this.here = function() {
424 | return addr(rt_addr);
425 | }
426 |
427 | /*this.align = function(b) {
428 | rt_addr = (rt_addr + b - 1) & ~(b - 1);
429 | }*/
430 |
431 | /*-----------------------------------------------------------------------*/
432 |
433 | function mapped_malloc(ab) {
434 | ab.startmask = ab.start;
435 | try {
436 | //ab.baseaddr = xcalloc(uae_u8, ab.allocated + 4);
437 | ab.baseaddr = new Uint8Array(ab.allocated + 4);
438 | return true;
439 | } catch (e) {
440 | ab.baseaddr = null;
441 | return false;
442 | }
443 | }
444 | function mapped_free(ab) {
445 | //xfree(ab.baseaddr);
446 | ab.baseaddr = null;
447 | }
448 |
449 | /*static uae_u32 REGPARAM2 nullfunc (TrapContext *ctx) {
450 | write_log (_T("Null function called\n"));
451 | return 0;
452 | }
453 | static uae_u32 REGPARAM2 getchipmemsize (TrapContext *ctx) {
454 | trap_set_dreg(ctx, 1, z3chipmem_bank.allocated);
455 | trap_set_areg(ctx, 1, z3chipmem_bank.start);
456 | return chipmem_bank.allocated;
457 | }
458 | static uae_u32 REGPARAM2 uae_puts (TrapContext *ctx) {
459 | puts ((char*)get_real_address(trap_get_areg(ctx, 0)));
460 | return 0;
461 | }*/
462 |
463 | /* OPT inline ok
464 | function rtarea_init_mem() {
465 | if (SAER.autoconf.need_uae_boot_rom())
466 | rtarea_bank.flags &= ~SAEC_Memory_addrbank_flag_ALLOCINDIRECT;
467 | else
468 | rtarea_bank.flags |= SAEC_Memory_addrbank_flag_ALLOCINDIRECT;
469 |
470 | rtarea_bank.allocated = RTAREA_SIZE;
471 | if (!mapped_malloc(rtarea_bank)) {
472 | SAEF_fatal(SAEE_NoMemory, "autoconf.init_mem() memory exhausted");
473 | //abort();
474 | }
475 | }*/
476 | this.setup = function() { //rtarea_init()
477 | rt_straddr = 0xFF00 - 2;
478 | rt_addr = 0;
479 |
480 | rt_trampoline_ptr = SAEV_AutoConf_base + RTAREA_TRAMPOLINE;
481 | trap_entry = 0;
482 |
483 | this.init_traps();
484 |
485 | //rtarea_init_mem();
486 | {
487 | if (this.need_uae_boot_rom())
488 | rtarea_bank.flags &= ~SAEC_Memory_addrbank_flag_ALLOCINDIRECT;
489 | else
490 | rtarea_bank.flags |= SAEC_Memory_addrbank_flag_ALLOCINDIRECT;
491 |
492 | rtarea_bank.allocated = RTAREA_SIZE;
493 | if (!mapped_malloc(rtarea_bank)) {
494 | SAEF_fatal(SAEE_NoMemory, "autoconf.init_mem() memory exhausted");
495 | //abort();
496 | }
497 | }
498 | //memset(rtarea_bank.baseaddr, 0, RTAREA_SIZE);
499 | SAEF_memset(rtarea_bank.baseaddr,0, 0, RTAREA_SIZE);
500 |
501 | /*var uaever = sprintf("uae-%d.%d.%d", UAEMAJOR, UAEMINOR, UAESUBREV);
502 | var saever = sprintf("sae-%d.%d.%d", SAEC_Version, SAEC_Revision, SAEC_Patch);
503 | EXPANSION_uaeversion = ds(saever);
504 | EXPANSION_explibname = ds("expansion.library");
505 | EXPANSION_doslibname = ds("dos.library");
506 | EXPANSION_uaedevname = ds("uae.device");*/
507 |
508 | this.dw(0);
509 | this.dw(0);
510 |
511 | /*#ifdef FILESYS
512 | filesys_install_code();
513 |
514 | trap_entry = filesys_get_entry(10);
515 | write_log(_T("TRAP_ENTRY = %08x\n"), trap_entry);
516 |
517 | for (int i = 0; i < RTAREA_TRAP_DATA_SIZE / RTAREA_TRAP_DATA_SLOT_SIZE; i++) {
518 | hardware_trap_event[i] = CreateEvent(NULL, FALSE, FALSE, NULL);
519 | }
520 | #endif*/
521 |
522 | this.define_trap(null, 0, "null"); /* Generic emulator trap */
523 |
524 | /*var a = this.here();
525 | // Dummy trap - removing this breaks the filesys emulation.
526 | this.org(SAEV_AutoConf_base + 0xFF00);
527 | this.calltrap(deftrap2(nullfunc, TRAPFLAG_NO_RETVAL, ""));
528 |
529 | this.org(SAEV_AutoConf_base + 0xFF80);
530 | this.calltrap(deftrapres(getchipmemsize, TRAPFLAG_DORET, "getchipmemsize"));
531 | this.dw(SAEC_AutoConf_RTS);
532 |
533 | this.org(SAEV_AutoConf_base + 0xFF10);
534 | this.calltrap(deftrapres(uae_puts, TRAPFLAG_NO_RETVAL, "uae_puts"));
535 | this.dw(SAEC_AutoConf_RTS);
536 |
537 | this.org(a);*/
538 |
539 | SAEV_AutoConf_boot_rom_size = this.here() - SAEV_AutoConf_base;
540 | SAEF_log("autoconf.setup() boot_rom_size %d/%d", SAEV_AutoConf_boot_rom_size, RTAREA_TRAPS);
541 | if (SAEV_AutoConf_boot_rom_size >= RTAREA_TRAPS) {
542 | SAEF_fatal(SAEE_NoMemory, "autoconf.setup() RTAREA_TRAPS needs to be increased!");
543 | //abort();
544 | }
545 |
546 | /*#ifdef PICASSO96
547 | uaegfx_install_code(SAEV_AutoConf_base + RTAREA_RTG);
548 | #endif*/
549 |
550 | this.org(RTAREA_TRAPS | SAEV_AutoConf_base);
551 | this.init_extended_traps();
552 | }
553 |
554 | this.cleanup = function() { //rtarea_free()
555 | mapped_free(rtarea_bank);
556 | this.free_traps();
557 | }
558 |
559 | this.init = function() { //rtarea_setup()
560 | var base = this.need_uae_boot_rom();
561 | if (base) {
562 | SAEF_log("autoconf.init() RTAREA located at %08X", base);
563 | SAEV_AutoConf_base = base;
564 | }
565 | }
566 |
567 | /*-----------------------------------------------------------------------*/
568 |
569 | this.makedatatable = function(resid, resname, type, priority, ver, rev) {
570 | var datatable = this.here();
571 | this.dw(0xE000); /* INITBYTE */
572 | this.dw(0x0008); /* LN_TYPE */
573 | this.dw(type << 8);
574 | this.dw(0xE000); /* INITBYTE */
575 | this.dw(0x0009); /* LN_PRI */
576 | this.dw(priority << 8);
577 | this.dw(0xC000); /* INITLONG */
578 | this.dw(0x000A); /* LN_NAME */
579 | this.dl(resname);
580 | this.dw(0xE000); /* INITBYTE */
581 | this.dw(0x000E); /* LIB_FLAGS */
582 | this.dw(0x0600); /* LIBF_SUMUSED | LIBF_CHANGED */
583 | this.dw(0xD000); /* INITWORD */
584 | this.dw(0x0014); /* LIB_VERSION */
585 | this.dw(ver);
586 | this.dw(0xD000); /* INITWORD */
587 | this.dw(0x0016); /* LIB_REVISION */
588 | this.dw(rev);
589 | this.dw(0xC000); /* INITLONG */
590 | this.dw(0x0018); /* LIB_IDSTRING */
591 | this.dl(resid);
592 | this.dw(0x0000); /* end of table */
593 | return datatable;
594 | }
595 |
596 | /*-----------------------------------------------------------------------*/
597 | /* SECT Traps */
598 | /*-----------------------------------------------------------------------*/
599 |
600 | const TRAPFLAG_NO_REGSAVE = 1;
601 | const TRAPFLAG_NO_RETVAL = 2;
602 | const TRAPFLAG_EXTRA_STACK = 4;
603 | const TRAPFLAG_DORET = 8;
604 | const TRAPFLAG_UAERES = 16;
605 |
606 | function Trap() {
607 | this.handler = null; /* Handler function to be invoked for this trap */
608 | this.flags = 0; /* Trap attributes */
609 | this.name = ""; /* For debugging purposes */
610 | this.addr = 0;
611 | };
612 | const MAX_TRAPS = 16; //4096;
613 |
614 | var trap_count = 1;
615 | var traps = new Array(MAX_TRAPS);
616 | for (var vi = 0; vi < MAX_TRAPS; vi++)
617 | traps[vi] = new Trap();
618 |
619 | var hwtrap_waiting = 0; //volatile uae_atomic
620 |
621 | const trace_traps = true;
622 |
623 | /*-----------------------------------------------------------------------*/
624 |
625 | this.find_trap = function(name) {
626 | for (var i = 0; i < trap_count; i++) {
627 | var trap = traps[i];
628 | if ((trap.flags & TRAPFLAG_UAERES) && trap.name.length && trap.name == name)
629 | return trap.addr;
630 | }
631 | return 0;
632 | }
633 |
634 | /*
635 | * Define an emulator trap
636 | *
637 | * handler_func = host function that will be invoked to handle this trap
638 | * flags = trap attributes
639 | * name = name for debugging purposes
640 | *
641 | * returns trap number of defined trap
642 | */
643 | this.define_trap = function(handler_func, flags, name) {
644 | if (trap_count == MAX_TRAPS) {
645 | SAEF_fatal(SAEE_Internal, "define_trap() Ran out of emulator traps. (increase MAX_TRAPS)");
646 | //abort();
647 | //return -1;
648 | } else {
649 | var addr = this.here();
650 |
651 | for (var i = 0; i < trap_count; i++) {
652 | if (addr == traps[i].addr)
653 | return i;
654 | }
655 |
656 | var trap_num = trap_count++;
657 | var trap = traps[trap_num];
658 |
659 | trap.handler = handler_func;
660 | trap.flags = flags;
661 | trap.name = name;
662 | trap.addr = addr;
663 |
664 | return trap_num;
665 | }
666 | }
667 |
668 | /*
669 | * This function is called by the 68k interpreter to handle an emulator trap.
670 | *
671 | * trap_num = number of trap to invoke
672 | * regs = current 68k state
673 | */
674 | this.m68k_handle_trap = function(trap_num) {
675 | var trap = traps[trap_num];
676 | var retval = 0;
677 |
678 | var has_retval = (trap.flags & TRAPFLAG_NO_RETVAL) == 0;
679 | var implicit_rts = (trap.flags & TRAPFLAG_DORET) != 0;
680 |
681 | if (trap.name.length && trace_traps)
682 | SAEF_log("m68k_handle_trap() TRAP '%s'", trap.name);
683 |
684 | if (trap_num < trap_count) {
685 | if (trap.flags & TRAPFLAG_EXTRA_STACK) {
686 | /* Handle an extended trap.
687 | * Note: the return value of this trap is passed back to 68k
688 | * space via a separate, dedicated simple trap which the trap
689 | * handler causes to be invoked when it is done.
690 | */
691 | //trap_HandleExtendedTrap(trap.handler, has_retval); //FIX implement extended-traps
692 | SAEF_fatal(SAEE_Internal, "m68k_handle_trap() Extended-traps are not implemented.");
693 | } else {
694 | /* Handle simple trap */
695 | //retval = (trap.handler)(null);
696 | retval = trap.handler(null);
697 |
698 | if (has_retval) {
699 | SAER_CPU_regs.d[0] = retval;
700 | SAEF_log("m68k_handle_trap() D0 = %d", retval);
701 | }
702 | if (implicit_rts) {
703 | //m68k_do_rts(); {
704 | var newpc = SAER_Memory_get32(SAER_CPU_regs.a[7]);
705 | SAER_CPU_setPC(newpc);
706 | SAER_CPU_regs.a[7] += 4;
707 | //}
708 | SAER_CPU_fill_prefetch();
709 | }
710 | }
711 | } else
712 | SAEF_warn("m68k_handle_trap() illegal emulator trap");
713 | }
714 |
715 | /*-----------------------------------------------------------------------*/
716 |
717 | this.init_traps = function() {
718 | trap_count = 0;
719 | hwtrap_waiting = 0;
720 | }
721 | this.free_traps = function() {
722 |
723 | }
724 | this.init_extended_traps = function() {
725 |
726 | }
727 | }
728 |
--------------------------------------------------------------------------------
/sae/copper.js:
--------------------------------------------------------------------------------
1 | /*-------------------------------------------------------------------------
2 | | SAE - Scripted Amiga Emulator
3 | | https://github.com/naTmeg/ScriptedAmigaEmulator
4 | |
5 | | Copyright (C) 2012 Rupert Hausberger
6 | |
7 | | This program is free software; you can redistribute it and/or
8 | | modify it under the terms of the GNU General Public License
9 | | as published by the Free Software Foundation; either version 2
10 | | of the License, or (at your option) any later version.
11 | |
12 | | This program is distributed in the hope that it will be useful,
13 | | but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | | GNU General Public License for more details.
16 | |
17 | | Note: ported from WinUAE 3.2.x
18 | -------------------------------------------------------------------------*/
19 | /* global references */
20 |
21 | var SAER_Copper_cop_state = null;
22 |
23 | /*---------------------------------*/
24 | /* global variables */
25 |
26 | var SAEV_Copper_access = false;
27 | var SAEV_Copper_last_hpos = 0;
28 | var SAEV_Copper_enabled_thisline = 0;
29 |
30 | /*---------------------------------*/
31 |
32 | function SAEO_Copper() {
33 | const customdelay = [
34 | 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 */
35 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x40 - 0x5e */
36 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x60 - 0x7e */
37 | 0,0,0,0,1,1,1,1,1,0,0,0,0,0,0,0, /* 0x80 - 0x9e */
38 | 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 */
39 | /* BPLxPTH/BPLxPTL */
40 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 16 */
41 | /* BPLCON0-3,BPLMOD1-2 */
42 | 0,0,0,0,0,0,0,0, /* 8 */
43 | /* BPLxDAT */
44 | 0,0,0,0,0,0,0,0, /* 8 */
45 | /* SPRxPTH/SPRxPTL */
46 | 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* 16 */
47 | /* SPRxPOS/SPRxCTL/SPRxDATA/SPRxDATB */
48 | 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,
49 | /* COLORxx */
50 | 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,
51 | /* RESERVED */
52 | 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
53 | ];
54 |
55 | const COP_stop = 0;
56 | const COP_waitforever = 1;
57 | const COP_read1 = 2;
58 | const COP_read2 = 3;
59 | const COP_bltwait = 4;
60 | const COP_wait_in2 = 5;
61 | const COP_skip_in2 = 6;
62 | const COP_wait1 = 7;
63 | const COP_wait = 8;
64 | const COP_skip1 = 9;
65 | const COP_strobe_delay1 = 10;
66 | const COP_strobe_delay2 = 11;
67 | const COP_strobe_delay1x = 12;
68 | const COP_strobe_delay2x = 13;
69 | const COP_strobe_extra = 14; /* just to skip current cycle when CPU wrote to COPJMP */
70 | const COP_start_delay = 15;
71 |
72 | function copper_state() {
73 | this.i1 = 0; this.saved_i1 = 0; /* The current instruction words. */
74 | this.i2 = 0; this.saved_i2 = 0;
75 | this.state = COP_stop;
76 | this.state_prev = COP_stop;
77 | this.ip = 0; this.saved_ip = 0; /* Instruction pointer */
78 | this.hpos = 0;
79 | this.vpos = 0;
80 | this.ignore_next = false;
81 | this.vcmp = 0;
82 | this.hcmp = 0;
83 | this.strobe = 0; /* COPJMP1 / COPJMP2 accessed */
84 | this.moveaddr = 0;
85 | this.movedata = 0;
86 | this.movedelay = 0;
87 | };
88 |
89 | var cop_state = new copper_state();
90 | SAER_Copper_cop_state = cop_state;
91 |
92 | var cop1lc = 0, cop2lc = 0, copcon = 0;
93 |
94 | //var last_copper_hpos = 0; -> SAEV_Copper_last_hpos
95 | //var copper_access = false; -> SAEV_Copper_access
96 | //var copper_enabled_thisline = 0; -> SAEV_Copper_enabled_thisline
97 |
98 | /*-----------------------------------------------------------------------*/
99 |
100 | this.reset = function() {
101 | copcon = 0;
102 | cop_state.state = COP_stop;
103 | cop_state.movedelay = 0;
104 | cop_state.strobe = 0;
105 | cop_state.ignore_next = false;
106 | }
107 |
108 | /*-----------------------------------------------------------------------*/
109 |
110 | this.clr_copcon = function() { //OWN used in playfield.reset_cutom()
111 | copcon = 0;
112 | }
113 | /*this.get_copxlc = function() { //OWN used in events.alloc_cycle_blitter()
114 | return cop_state.strobe == 1 ? cop1lc : cop2lc;
115 | }*/
116 |
117 | /*this.get_copper_address = function(copno) {
118 | switch (copno) {
119 | case 1: return cop1lc;
120 | case 2: return cop2lc;
121 | case -1: return cop_state.ip;
122 | default: return 0;
123 | }
124 | }*/
125 |
126 | this.copper_stop = function() { //called in custom.DMACON()
127 | if (SAEV_Copper_enabled_thisline) {
128 | // let MOVE to finish
129 | switch (cop_state.state) {
130 | case COP_read2:
131 | SAEV_Copper_enabled_thisline = -1;
132 | break;
133 | }
134 | }
135 | if (SAEV_Copper_enabled_thisline >= 0) {
136 | SAEV_Copper_enabled_thisline = 0;
137 | SAEF_clrSpcFlags(SAEC_spcflag_COPPER);
138 | }
139 | }
140 |
141 | function check_copper_stop() {
142 | //if (SAEV_Copper_enabled_thisline < 0 && !((SAEV_Custom_dmacon & SAEC_Custom_DMAF_COPEN) && (SAEV_Custom_dmacon & SAEC_Custom_DMAF_DMAEN))) {
143 | if (SAEV_Copper_enabled_thisline < 0 && !SAEF_Custom_dmaen(SAEC_Custom_DMAF_COPEN)) {
144 | SAEV_Copper_enabled_thisline = 0;
145 | SAEF_clrSpcFlags(SAEC_spcflag_COPPER);
146 | }
147 | }
148 |
149 | /*-> playfield
150 | function copper_cant_read(hpos, alloc) {
151 | if (hpos + 1 >= maxhpos) // first refresh slot
152 | return 1;
153 | if ((hpos == maxhpos - 3) && (maxhpos & 1) && alloc >= 0) {
154 | //if (alloc) SAER.events.alloc_cycle(hpos, SAEC_Events_cycle_line_COPPER);
155 | return -1;
156 | }
157 | return is_bitplane_dma_inline(hpos);
158 | }*/
159 |
160 | function put16_copper(hpos, addr, value, noget) {
161 | SAEV_Copper_access = true;
162 | //var v = custom_wput_1(hpos, addr, value, noget);
163 | var v = SAER_Custom_put16_real(hpos, addr, value, noget);
164 | SAEV_Copper_access = false;
165 | return v;
166 | }
167 |
168 | /*function dump(error, until_hpos) {
169 | SAEF_log("copper.dump() %s: vpos=%d until_hpos=%d vp=%d", error, vpos, until_hpos, vpos & (((cop_state.saved_i2 >> 8) & 0x7F) | 0x80));
170 | 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);
171 | SAEF_log("copper.dump() cstate=%d ip=%x SPCFLAGS=%x iscline=%d", cop_state.state, cop_state.ip, SAEV_spcflags, SAEV_Copper_enabled_thisline);
172 | }*/
173 |
174 | function update_copper(until_hpos) {
175 | var vp = SAER.playfield.get_vpos() & (((cop_state.saved_i2 >> 8) & 0x7F) | 0x80);
176 | var c_hpos = cop_state.hpos;
177 | var maxhpos;
178 |
179 | //if (nocustom()) return;
180 |
181 | if (cop_state.state == COP_wait && vp < cop_state.vcmp) {
182 | //dump("error2", until_hpos);
183 | SAEV_Copper_enabled_thisline = 0;
184 | cop_state.state = COP_stop;
185 | SAEF_clrSpcFlags(SAEC_spcflag_COPPER);
186 | return;
187 | }
188 |
189 | if (until_hpos <= SAEV_Copper_last_hpos)
190 | return;
191 |
192 | maxhpos = SAER.playfield.get_maxhpos();
193 | if (until_hpos > (maxhpos & ~1))
194 | until_hpos = maxhpos & ~1;
195 |
196 | for (;;) {
197 | var old_hpos = c_hpos;
198 | var hp;
199 |
200 | if (c_hpos >= until_hpos)
201 | break;
202 |
203 |
204 | /* So we know about the fetch state. */
205 | SAER.playfield.decide_line(c_hpos);
206 | // bitplane only, don't want blitter to steal our cycles.
207 | SAER.playfield.decide_fetch(c_hpos);
208 |
209 | if (cop_state.movedelay > 0) {
210 | cop_state.movedelay--;
211 | if (cop_state.movedelay == 0) {
212 | put16_copper(c_hpos, cop_state.moveaddr, cop_state.movedata, 0);
213 | }
214 | }
215 |
216 | maxhpos = SAER.playfield.get_maxhpos();
217 | if ((c_hpos == maxhpos - 3) && (maxhpos & 1))
218 | c_hpos += 1;
219 | else
220 | c_hpos += 2;
221 |
222 | switch (cop_state.state) {
223 | case COP_wait_in2: {
224 | if (SAER.playfield.copper_cant_read(old_hpos, 0))
225 | continue;
226 | cop_state.state = COP_wait1;
227 | break;
228 | }
229 | case COP_skip_in2: {
230 | if (SAER.playfield.copper_cant_read(old_hpos, 0))
231 | continue;
232 | cop_state.state = COP_skip1;
233 | break;
234 | }
235 | case COP_strobe_extra: {
236 | // Wait 1 copper cycle doing nothing
237 | cop_state.state = COP_strobe_delay1;
238 | break;
239 | }
240 | case COP_strobe_delay1: {
241 | // First cycle after COPJMP is just like normal first read cycle
242 | // Cycle is used and needs to be free.
243 | if (SAER.playfield.copper_cant_read(old_hpos, 1))
244 | continue;
245 | //SAER.events.alloc_cycle(old_hpos, SAEC_Events_cycle_line_COPPER);
246 | maxhpos = SAER.playfield.get_maxhpos();
247 | if (old_hpos == maxhpos - 2) {
248 | // if COP_strobe_delay2 would cross scanlines (positioned immediately
249 | // after first strobe/refresh slot) it will disappear!
250 | cop_state.state = COP_read1;
251 | if (cop_state.strobe == 1)
252 | cop_state.ip = cop1lc;
253 | else
254 | cop_state.ip = cop2lc;
255 | cop_state.strobe = 0;
256 | } else {
257 | cop_state.state = COP_strobe_delay2;
258 | cop_state.ip += 2;
259 | }
260 | break;
261 | }
262 | case COP_strobe_delay2: {
263 | // Second cycle after COPJMP. This is the strange one.
264 | // This cycle does not need to be free
265 | // But it still gets allocated by copper if it is free = CPU and blitter can't use it.
266 | //if (!SAER.playfield.copper_cant_read(old_hpos, 0)) SAER.events.alloc_cycle(old_hpos, SAEC_Events_cycle_line_COPPER);
267 |
268 | cop_state.state = COP_read1;
269 | // Next cycle finally reads from new pointer
270 | if (cop_state.strobe == 1)
271 | cop_state.ip = cop1lc;
272 | else
273 | cop_state.ip = cop2lc;
274 | cop_state.strobe = 0;
275 | break;
276 | }
277 | case COP_strobe_delay1x: {
278 | // First cycle after COPJMP and Copper was waiting. This is the buggy one.
279 | // Cycle can be free and copper won"t allocate it.
280 | // If Blitter uses this cycle = Copper"s PC gets copied to blitter DMA pointer..
281 | cop_state.state = COP_strobe_delay2x;
282 | break;
283 | }
284 | case COP_strobe_delay2x: {
285 | // Second cycle fetches following word and tosses it away. Must be free cycle
286 | // but it is not allocated, blitter or cpu can still use it.
287 | if (SAER.playfield.copper_cant_read(old_hpos, 1))
288 | continue;
289 | //SAER_Events_cycle_line[old_hpos] |= SAEC_Events_cycle_line_COPPER_SPECIAL;
290 | cop_state.state = COP_read1;
291 | // Next cycle finally reads from new pointer
292 | if (cop_state.strobe == 1)
293 | cop_state.ip = cop1lc;
294 | else
295 | cop_state.ip = cop2lc;
296 | cop_state.strobe = 0;
297 | break;
298 | }
299 | case COP_start_delay: {
300 | // cycle after vblank strobe fetches word from old pointer first
301 | if (SAER.playfield.copper_cant_read(old_hpos, 1))
302 | continue;
303 | cop_state.state = COP_read1;
304 | //cop_state.i1 = SAEV_Custom_last_value = SAER_Memory_chipGet16_indirect(cop_state.ip);
305 | cop_state.i1 = SAEV_Custom_last_value = (SAER_Memory_chipData[cop_state.ip] << 8) | SAER_Memory_chipData[cop_state.ip + 1];
306 | //SAER.events.alloc_cycle(old_hpos, SAEC_Events_cycle_line_COPPER);
307 | cop_state.ip = cop1lc;
308 | break;
309 | }
310 | case COP_read1: {
311 | if (SAER.playfield.copper_cant_read(old_hpos, 1))
312 | continue;
313 | //cop_state.i1 = SAEV_Custom_last_value = SAER_Memory_chipGet16_indirect(cop_state.ip);
314 | cop_state.i1 = SAEV_Custom_last_value = (SAER_Memory_chipData[cop_state.ip] << 8) | SAER_Memory_chipData[cop_state.ip + 1];
315 | //SAER.events.alloc_cycle(old_hpos, SAEC_Events_cycle_line_COPPER);
316 | cop_state.ip += 2;
317 | cop_state.state = COP_read2;
318 | break;
319 | }
320 | case COP_read2: {
321 | if (SAER.playfield.copper_cant_read(old_hpos, 1))
322 | continue;
323 | //cop_state.i2 = SAEV_Custom_last_value = SAER_Memory_chipGet16_indirect(cop_state.ip);
324 | cop_state.i2 = SAEV_Custom_last_value = (SAER_Memory_chipData[cop_state.ip] << 8) | SAER_Memory_chipData[cop_state.ip + 1];
325 | //SAER.events.alloc_cycle(old_hpos, SAEC_Events_cycle_line_COPPER);
326 | cop_state.ip += 2;
327 | cop_state.saved_i1 = cop_state.i1;
328 | cop_state.saved_i2 = cop_state.i2;
329 | cop_state.saved_ip = cop_state.ip;
330 |
331 | if (cop_state.i1 & 1) { // WAIT or SKIP
332 | cop_state.ignore_next = false;
333 | if (cop_state.i2 & 1)
334 | cop_state.state = COP_skip_in2;
335 | else
336 | cop_state.state = COP_wait_in2;
337 | } else { // MOVE
338 | var reg = cop_state.i1 & 0x1FE;
339 | var data = cop_state.i2;
340 | cop_state.state = COP_read1;
341 | test_copper_dangerous(reg);
342 | if (!SAEV_Copper_enabled_thisline) {
343 | //goto out; //was "dangerous" register -> copper stopped
344 | cop_state.hpos = c_hpos;
345 | SAEV_Copper_last_hpos = until_hpos;
346 | return;
347 | }
348 | if (cop_state.ignore_next)
349 | reg = 0x1fe;
350 |
351 | if (reg == 0x88) {
352 | cop_state.strobe = 1;
353 | cop_state.state = COP_strobe_delay1;
354 | } else if (reg == 0x8a) {
355 | cop_state.strobe = 2;
356 | cop_state.state = COP_strobe_delay1;
357 | } else {
358 | if (customdelay[reg >> 1]) {
359 | cop_state.moveaddr = reg;
360 | cop_state.movedata = data;
361 | cop_state.movedelay = customdelay[reg >> 1];
362 | } else
363 | put16_copper(old_hpos, reg, data, 0);
364 | }
365 | cop_state.ignore_next = false;
366 | }
367 | check_copper_stop();
368 | break;
369 | }
370 | case COP_wait1: {
371 | cop_state.state = COP_wait;
372 |
373 | cop_state.vcmp = (cop_state.saved_i1 & (cop_state.saved_i2 | 0x8000)) >> 8;
374 | cop_state.hcmp = (cop_state.saved_i1 & cop_state.saved_i2 & 0xFE);
375 |
376 | vp = SAER.playfield.get_vpos() & (((cop_state.saved_i2 >> 8) & 0x7F) | 0x80);
377 |
378 | if (cop_state.saved_i1 == 0xFFFF && cop_state.saved_i2 == 0xFFFE) {
379 | cop_state.state = COP_waitforever;
380 | SAEV_Copper_enabled_thisline = 0;
381 | SAEF_clrSpcFlags(SAEC_spcflag_COPPER);
382 | //goto out;
383 | cop_state.hpos = c_hpos;
384 | SAEV_Copper_last_hpos = until_hpos;
385 | return;
386 | }
387 | if (vp < cop_state.vcmp) {
388 | SAEV_Copper_enabled_thisline = 0;
389 | SAEF_clrSpcFlags(SAEC_spcflag_COPPER);
390 | //goto out;
391 | cop_state.hpos = c_hpos;
392 | SAEV_Copper_last_hpos = until_hpos;
393 | return;
394 | }
395 | /* fall through */
396 | }
397 | case COP_wait: {
398 | var ch_comp = c_hpos;
399 | if (ch_comp & 1)
400 | ch_comp = 0;
401 |
402 | /* First handle possible blitter wait
403 | * Must be before following free cycle check */
404 | if ((cop_state.saved_i2 & 0x8000) == 0) {
405 | SAER.blitter.decide_blitter(old_hpos);
406 | if (SAEV_Blitter_bltstate != SAEC_Blitter_bltstate_DONE) {
407 | /* We need to wait for the blitter. */
408 | cop_state.state = COP_bltwait;
409 | SAEV_Copper_enabled_thisline = 0;
410 | SAEF_clrSpcFlags(SAEC_spcflag_COPPER);
411 | //goto out;
412 | cop_state.hpos = c_hpos;
413 | SAEV_Copper_last_hpos = until_hpos;
414 | return;
415 | }
416 | }
417 |
418 | if (SAER.playfield.copper_cant_read(old_hpos, 0))
419 | continue;
420 |
421 | hp = ch_comp & (cop_state.saved_i2 & 0xFE);
422 | if (vp == cop_state.vcmp && hp < cop_state.hcmp)
423 | break;
424 |
425 | cop_state.state = COP_read1;
426 | break;
427 | }
428 | case COP_skip1: {
429 | var vcmp, hcmp, vp1, hp1;
430 |
431 | maxhpos = SAER.playfield.get_maxhpos();
432 | if (c_hpos >= (maxhpos & ~1) || (c_hpos & 1))
433 | break;
434 |
435 | if (SAER.playfield.copper_cant_read(old_hpos, 0))
436 | continue;
437 |
438 | vcmp = (cop_state.saved_i1 & (cop_state.saved_i2 | 0x8000)) >> 8;
439 | hcmp = (cop_state.saved_i1 & cop_state.saved_i2 & 0xFE);
440 | vp1 = SAER.playfield.get_vpos() & (((cop_state.saved_i2 >> 8) & 0x7F) | 0x80);
441 | hp1 = c_hpos & (cop_state.saved_i2 & 0xFE);
442 |
443 | if ((vp1 > vcmp || (vp1 == vcmp && hp1 >= hcmp)) && ((cop_state.saved_i2 & 0x8000) != 0 || SAEV_Blitter_bltstate == SAEC_Blitter_bltstate_DONE))
444 | cop_state.ignore_next = true;
445 |
446 | cop_state.state = COP_read1;
447 | break;
448 | }
449 | default:
450 | break;
451 | }
452 | }
453 |
454 | //out:
455 | cop_state.hpos = c_hpos;
456 | SAEV_Copper_last_hpos = until_hpos;
457 | }
458 |
459 | this.compute_spcflag_copper = function(hpos) {
460 | var wasenabled = SAEV_Copper_enabled_thisline;
461 |
462 | SAEV_Copper_enabled_thisline = 0;
463 | SAEF_clrSpcFlags(SAEC_spcflag_COPPER);
464 | if (!SAEF_Custom_dmaen(SAEC_Custom_DMAF_COPEN) || cop_state.state == COP_stop || cop_state.state == COP_waitforever || cop_state.state == COP_bltwait) //|| nocustom())
465 | return;
466 |
467 | if (cop_state.state == COP_wait) {
468 | var vp = SAER.playfield.get_vpos() & (((cop_state.saved_i2 >> 8) & 0x7F) | 0x80);
469 | if (vp < cop_state.vcmp)
470 | return;
471 | }
472 | // do not use past cycles if starting for the first time in this line
473 | // (write to DMACON for example) hpos+1 for long lines
474 | if (!wasenabled && cop_state.hpos < hpos && hpos < SAER.playfield.get_maxhpos()) {
475 | var maxhpos_short = SAER.playfield.get_maxhpos_short();
476 | hpos = (hpos + 2) & ~1;
477 | if (hpos > (maxhpos_short & ~1))
478 | hpos = maxhpos_short & ~1;
479 | cop_state.hpos = hpos;
480 | }
481 | // if COPJMPx was written while DMA was disabled, advance to next state,
482 | // COP_strobe_extra is single cycle only and does not need free bus.
483 | // (copper state emulation does not run if DMA is disabled)
484 | if (!wasenabled && cop_state.state == COP_strobe_extra)
485 | cop_state.state = COP_strobe_delay1;
486 |
487 | SAEV_Copper_enabled_thisline = 1;
488 | SAEF_setSpcFlags(SAEC_spcflag_COPPER);
489 | }
490 |
491 | this.blitter_done_notify = function(hpos) {
492 | if (cop_state.state != COP_bltwait)
493 | return;
494 |
495 | var vpos = SAER.playfield.get_vpos();
496 | var vp_wait = vpos & (((cop_state.saved_i2 >> 8) & 0x7F) | 0x80);
497 | var vp = vpos;
498 | var maxhpos = SAER.playfield.get_maxhpos();
499 |
500 | hpos++;
501 | hpos &= ~1;
502 | if (hpos >= maxhpos) {
503 | hpos -= maxhpos;
504 | vp++;
505 | }
506 | cop_state.hpos = hpos;
507 | cop_state.vpos = vp;
508 | cop_state.state = COP_wait;
509 | /* No need to check blitter state again */
510 | cop_state.saved_i2 |= 0x8000;
511 |
512 | if (SAEF_Custom_dmaen(SAEC_Custom_DMAF_COPEN) && vp_wait >= cop_state.vcmp) {
513 | SAEV_Copper_enabled_thisline = 1;
514 | SAEF_setSpcFlags(SAEC_spcflag_COPPER);
515 | } else
516 | SAEF_clrSpcFlags(SAEC_spcflag_COPPER);
517 | }
518 |
519 | this.cycle = function() { //do_copper()
520 | var hpos = SAER.events.current_hpos();
521 | update_copper(hpos);
522 | }
523 |
524 | this.sync_copper_with_cpu = function(hpos, do_schedule) {
525 | /* Need to let the copper advance to the current position. */
526 | if (SAEV_Copper_enabled_thisline)
527 | update_copper(hpos);
528 | }
529 |
530 | /*-----------------------------------------------------------------------*/
531 |
532 | function test_copper_dangerous(address) {
533 | var addr = address & 0x01fe;
534 | if (addr < ((copcon & 2) ? ((SAEV_config.chipset.mask & SAEC_Config_Chipset_Mask_ECS_AGNUS) ? 0 : 0x40) : 0x80)) {
535 | cop_state.state = COP_stop;
536 | SAEV_Copper_enabled_thisline = 0;
537 | SAEF_clrSpcFlags(SAEC_spcflag_COPPER);
538 | return true;
539 | }
540 | return false;
541 | }
542 |
543 | /*function immediate_copper(num) {
544 | var pos = 0;
545 | var oldpos = 0;
546 |
547 | cop_state.state = COP_stop;
548 | cop_state.vpos = SAER.playfield.get_vpos();
549 | cop_state.hpos = SAER.events.current_hpos() & ~1;
550 | cop_state.ip = num == 1 ? cop1lc : cop2lc;
551 |
552 | while (pos < (maxvpos << 5)) {
553 | if (oldpos > pos)
554 | pos = oldpos;
555 | if (!SAEF_Custom_dmaen(SAEC_Custom_DMAF_COPEN))
556 | break;
557 | if (cop_state.ip >= SAEV_config.memory.chipSize && cop_state.ip < currprefs.z3chipmem_start && cop_state.ip >= currprefs.z3chipmem_start + currprefs.z3chipmem_size)
558 | break;
559 | pos++;
560 | oldpos = pos;
561 | //cop_state.i1 = SAER_Memory_chipGet16_indirect(cop_state.ip);
562 | //cop_state.i2 = SAER_Memory_chipGet16_indirect(cop_state.ip + 2);
563 | cop_state.i1 = (SAER_Memory_chipData[cop_state.ip ] << 8) | SAER_Memory_chipData[cop_state.ip + 1];
564 | cop_state.i2 = (SAER_Memory_chipData[cop_state.ip + 2] << 8) | SAER_Memory_chipData[cop_state.ip + 3];
565 | cop_state.ip += 4;
566 | if (!(cop_state.i1 & 1)) { // move
567 | cop_state.i1 &= 0x1fe;
568 | if (cop_state.i1 == 0x88) {
569 | cop_state.ip = cop1lc;
570 | continue;
571 | }
572 | if (cop_state.i1 == 0x8a) {
573 | cop_state.ip = cop2lc;
574 | continue;
575 | }
576 | if (test_copper_dangerous(cop_state.i1))
577 | break;
578 |
579 | //custom_wput_1(0, cop_state.i1, cop_state.i2, 0);
580 | SAER_Custom_put16_real(0, addr, value, 0);
581 | } else { // wait or skip
582 | if ((cop_state.i1 >> 8) > ((pos >> 5) & 0xff))
583 | pos = (((pos >> 5) & 0x100) | ((cop_state.i1 >> 8)) << 5) | ((cop_state.i1 & 0xff) >> 3);
584 | if (cop_state.i1 >= 0xffdf && cop_state.i2 == 0xfffe)
585 | break;
586 | }
587 | }
588 | cop_state.state = COP_stop;
589 | SAEF_clrSpcFlags(SAEC_spcflag_COPPER);
590 | }*/
591 |
592 | this.COP1LCH = function(v) {
593 | v = v & (SAEV_config.chipset.mask == SAEC_Config_Chipset_Mask_OCS ? 7 : 31); //OWN
594 | cop1lc = ((cop1lc & 0x0000ffff) | (v << 16)) >>> 0;
595 | }
596 | this.COP1LCL = function(v) {
597 | cop1lc = ((cop1lc & 0xffff0000) | (v & 0xfffe)) >>> 0;
598 | }
599 | this.COP2LCH = function(v) {
600 | v = v & (SAEV_config.chipset.mask == SAEC_Config_Chipset_Mask_OCS ? 7 : 31); //OWN
601 | cop2lc = ((cop2lc & 0x0000ffff) | (v << 16)) >>> 0;
602 | }
603 | this.COP2LCL = function(v) {
604 | cop2lc = ((cop2lc & 0xffff0000) | (v & 0xfffe)) >>> 0;
605 | }
606 |
607 | // vblank = copper starts at hpos=2
608 | // normal COPJMP write: takes 2 more cycles
609 | this.COPJMP = function(num, vblank) {
610 | var oldstrobe = cop_state.strobe;
611 | var wasstopped = cop_state.state == COP_stop && !vblank;
612 |
613 | /*if (SAEF_Custom_dmaen(SAEC_Custom_DMAF_COPEN) && (cop_state.saved_i1 != 0xffff || cop_state.saved_i2 != 0xfffe))
614 | SAEF_warn("copper.COPJMP vblank without copper ending %08x (%08x %08x)", cop_state.ip, cop1lc, cop2lc);*/
615 |
616 | SAEF_clrSpcFlags(SAEC_spcflag_COPPER);
617 | cop_state.ignore_next = false;
618 |
619 | if (!oldstrobe)
620 | cop_state.state_prev = cop_state.state;
621 | if ((cop_state.state == COP_wait || cop_state.state == COP_waitforever) && !vblank && SAEF_Custom_dmaen(SAEC_Custom_DMAF_COPEN)) {
622 | cop_state.state = COP_strobe_delay1x;
623 | } else {
624 | cop_state.state = vblank ? COP_start_delay : (SAEV_Copper_access ? COP_strobe_delay1 : COP_strobe_extra);
625 | }
626 | cop_state.vpos = SAER.playfield.get_vpos();
627 | cop_state.hpos = SAER.events.current_hpos() & ~1;
628 | SAEV_Copper_enabled_thisline = 0;
629 | cop_state.strobe = num;
630 |
631 | /*if (nocustom()) {
632 | immediate_copper(num);
633 | return;
634 | }*/
635 | if (SAEF_Custom_dmaen(SAEC_Custom_DMAF_COPEN)) {
636 | this.compute_spcflag_copper(SAER.events.current_hpos());
637 | } else if (wasstopped || (oldstrobe > 0 && oldstrobe != num && cop_state.state_prev == COP_wait)) {
638 | /* dma disabled, copper idle and accessed both COPxJMPs -> copper stops! */
639 | cop_state.state = COP_stop;
640 | }
641 | }
642 |
643 | this.COPCON = function(a) {
644 | copcon = a;
645 | }
646 | }
647 |
--------------------------------------------------------------------------------
/sae/disassembler.js:
--------------------------------------------------------------------------------
1 | /*-------------------------------------------------------------------------
2 | | SAE - Scripted Amiga Emulator
3 | | https://github.com/naTmeg/ScriptedAmigaEmulator
4 | |
5 | | Copyright (C) 2012 Rupert Hausberger
6 | |
7 | | This program is free software; you can redistribute it and/or
8 | | modify it under the terms of the GNU General Public License
9 | | as published by the Free Software Foundation; either version 2
10 | | of the License, or (at your option) any later version.
11 | |
12 | | This program is distributed in the hope that it will be useful,
13 | | but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | | GNU General Public License for more details.
16 | -------------------------------------------------------------------------*/
17 | /* errors (copied from amiga.js) */
18 |
19 | function SAEO_Error(err, msg) {
20 | this.err = err;
21 | this.msg = msg;
22 | }
23 | SAEO_Error.prototype = new Error;
24 |
25 | const SAEE_None = 0;
26 |
27 | const SAEE_AlreadyRunning = 1;
28 | const SAEE_NotRunning = 2;
29 | const SAEE_NoTimer = 3;
30 | const SAEE_NoMemory = 4;
31 | const SAEE_Assert = 5;
32 | const SAEE_Internal = 6;
33 |
34 | const SAEE_Config_Invalid = 10;
35 |
36 | const SAEE_CPU_Internal = 20;
37 | const SAEE_CPU_Requires68020 = 21;
38 | const SAEE_CPU_Requires680EC20 = 22;
39 | const SAEE_CPU_Requires68030 = 23;
40 | const SAEE_CPU_Requires68040 = 24;
41 |
42 | /*-----------------------------------------------------------------------*/
43 |
44 | function ScriptedDisAssembler() {
45 | this.cpu = new SAEO_CPU();
46 | var err = this.cpu.setup_da(68030);
47 | if (err != SAEE_None)
48 | throw err;
49 |
50 | /*---------------------------------*/
51 |
52 | this.getConfig = function() {
53 | return this.cpu.getConfig_da();
54 | }
55 | this.disassemble = function() {
56 | return this.cpu.disassemble();
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/sae/dongle.js:
--------------------------------------------------------------------------------
1 | /*-------------------------------------------------------------------------
2 | | SAE - Scripted Amiga Emulator
3 | | https://github.com/naTmeg/ScriptedAmigaEmulator
4 | |
5 | | Copyright (C) 2012 Rupert Hausberger
6 | |
7 | | This program is free software; you can redistribute it and/or
8 | | modify it under the terms of the GNU General Public License
9 | | as published by the Free Software Foundation; either version 2
10 | | of the License, or (at your option) any later version.
11 | |
12 | | This program is distributed in the hope that it will be useful,
13 | | but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | | GNU General Public License for more details.
16 | |
17 | | Note: ported from WinUAE 3.2.x
18 | -------------------------------------------------------------------------*/
19 | /*
20 | RoboCop 3
21 | - set firebutton as output
22 | - read JOY1DAT
23 | - pulse firebutton (high->low)
24 | - read JOY1DAT
25 | - JOY1DAT bit 8 must toggle
26 |
27 | Leader Board
28 | - JOY1DAT, both up and down active (0x0101)
29 |
30 | B.A.T. II
31 | - set all serial pins as output except CTS
32 | - game pulses DTR (high->low)
33 | - CTS must be one
34 | - delay
35 | - CTS must be zero
36 |
37 | Italy '90 Soccer
38 | - 220k resistor between pins 5 (+5v) and 7 (POTX)
39 | - POT1DAT POTX must be between 0x32 and 0x60
40 |
41 | Dames Grand Maitre
42 | - read POT1
43 | - POT1X != POT1Y
44 | - POT1Y * 256 / POT1X must be between 450 and 500
45 |
46 | Rugby Coach
47 | - JOY1DAT, left, up and down active (0x0301)
48 |
49 | Cricket Captain
50 | - JOY0DAT bits 0 and 1:
51 | - 10 01 11 allowed
52 | - must continuously change state
53 |
54 | Leviathan
55 | - same as Leaderboard but in mouse port
56 |
57 | Logistix/SuperBase
58 | - second button must be high
59 | - POT1X = 150k
60 | - POT1Y = 100k
61 | - POT1X * 10 / POT1Y must be between 12 and 33
62 | */
63 |
64 | function SAEO_Dongle() {
65 | const NONE = 0;
66 | const ROBOCOP3 = 1; //Joy2
67 | const LEADERBOARD = 2; //Joy2
68 | const BAT2 = 3; //Ser
69 | const ITALY90 = 4; //Joy2
70 | const DAMESGRANDMAITRE = 5; //Joy2
71 | const RUGBYCOACH = 6; //Joy2
72 | const CRICKETCAPTAIN = 7; //Joy1
73 | const LEVIATHAN = 8; //Joy1
74 | const LOGISTIX = 9; //Joy2
75 |
76 | const CYCLE_UNIT_200 = SAEC_Events_CYCLE_UNIT * 200;
77 |
78 | var flag = 0; //int
79 | var cycles = 0; //unsigned int
80 |
81 | /*var oldcia = new Array(2); //u8 [2][16]
82 | oldcia[0] = new Uint8Array(16);
83 | oldcia[1] = new Uint8Array(16);*/
84 |
85 | /*---------------------------------*/
86 |
87 | this.cia_read = function(cia, reg, val) { //dongle_cia_read()
88 | switch (SAEV_config.dongle) {
89 | case BAT2: {
90 | if (cia == 1 && reg == 0) {
91 | if (flag == 0 || SAEV_Events_currcycle > cycles + CYCLE_UNIT_200) {
92 | val &= ~0x10;
93 | flag = 0;
94 | } else
95 | val |= 0x10;
96 | }
97 | break;
98 | }
99 | }
100 | return val;
101 | }
102 |
103 | this.cia_write = function(cia, reg, val) { //dongle_cia_write()
104 | switch (SAEV_config.dongle) {
105 | case NONE:
106 | return;
107 | case ROBOCOP3: {
108 | if (cia == 0 && reg == 0 && (val & 0x80))
109 | flag ^= 1;
110 | break;
111 | }
112 | case BAT2: {
113 | if (cia == 1 && reg == 0 && !(val & 0x80)) {
114 | flag = 1;
115 | cycles = SAEV_Events_currcycle;
116 | }
117 | break;
118 | }
119 | }
120 | //oldcia[cia][reg] = val;
121 | }
122 |
123 | /*---------------------------------*/
124 |
125 | this.joytest = function(val) {} //dongle_joytest()
126 |
127 | this.joydat = function(port, val) { //dongle_joydat()
128 | switch (SAEV_config.dongle) {
129 | case NONE:
130 | break;
131 | case ROBOCOP3: {
132 | if (port == 1 && flag != 0)
133 | val += 0x100;
134 | break;
135 | }
136 | case LEADERBOARD: {
137 | if (port == 1) {
138 | val &= ~0x0303;
139 | val |= 0x0101;
140 | }
141 | break;
142 | }
143 | case LEVIATHAN: {
144 | if (port == 0) {
145 | val &= ~0x0303;
146 | val |= 0x0101;
147 | }
148 | break;
149 | }
150 | case RUGBYCOACH: {
151 | if (port == 1) {
152 | val &= ~0x0303;
153 | val|= 0x0301;
154 | }
155 | break;
156 | }
157 | case CRICKETCAPTAIN: {
158 | if (port == 0) {
159 | val &= ~0x0003;
160 | if (flag == 0)
161 | val |= 0x0001;
162 | else
163 | val |= 0x0002;
164 | }
165 | flag ^= 1;
166 | break;
167 | }
168 | }
169 | return val;
170 | }
171 |
172 | /*---------------------------------*/
173 |
174 | this.potgo = function(val) { //dongle_potgo()
175 | switch (SAEV_config.dongle) {
176 | case NONE:
177 | return;
178 | case ITALY90:
179 | case LOGISTIX:
180 | case DAMESGRANDMAITRE:
181 | //flag = (uaerand() & 7) - 3;
182 | flag = ((Math.random() * 8) >>> 0) - 3;
183 | break;
184 | }
185 | }
186 |
187 | this.potgor = function(val) { //dongle_potgor()
188 | switch (SAEV_config.dongle) {
189 | case LOGISTIX:
190 | val |= 1 << 14;
191 | break;
192 | }
193 | return val;
194 | }
195 |
196 | /*---------------------------------*/
197 |
198 | this.analogjoy = function(joy, axis) { //dongle_analogjoy()
199 | var v = -1; //int
200 |
201 | switch (SAEV_config.dongle) {
202 | case NONE:
203 | return -1;
204 | case ITALY90:
205 | if (joy == 1 && axis == 0)
206 | v = 73;
207 | break;
208 | case LOGISTIX:
209 | if (joy == 1) {
210 | if (axis == 0)
211 | v = 21;
212 | if (axis == 1)
213 | v = 10;
214 | }
215 | break;
216 | case DAMESGRANDMAITRE:
217 | if (joy == 1) {
218 | if (axis == 1)
219 | v = 80;
220 | if (axis == 0)
221 | v = 43;
222 | }
223 | break;
224 | }
225 | if (v >= 0) {
226 | v += flag;
227 | if (v < 0)
228 | v = 0;
229 | }
230 | return v;
231 | }
232 |
233 | /*---------------------------------*/
234 |
235 | this.reset = function() { //dongle_reset()
236 | flag = 0;
237 | cycles = 0; //OWN
238 |
239 | //memset (oldcia, 0, sizeof oldcia);
240 | //for (var i = 0; i < 16; i++) oldcia[0][i] = oldcia[1][i] = 0;
241 | }
242 | }
243 |
--------------------------------------------------------------------------------
/sae/events.js:
--------------------------------------------------------------------------------
1 | /*-------------------------------------------------------------------------
2 | | SAE - Scripted Amiga Emulator
3 | | https://github.com/naTmeg/ScriptedAmigaEmulator
4 | |
5 | | Copyright (C) 2012 Rupert Hausberger
6 | |
7 | | This program is free software; you can redistribute it and/or
8 | | modify it under the terms of the GNU General Public License
9 | | as published by the Free Software Foundation; either version 2
10 | | of the License, or (at your option) any later version.
11 | |
12 | | This program is distributed in the hope that it will be useful,
13 | | but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | | GNU General Public License for more details.
16 | |
17 | | Note: ported from WinUAE 3.2.x
18 | -------------------------------------------------------------------------*/
19 | /* global constants */
20 |
21 | const SAEC_Events_CYCLE_UNIT = 512;
22 | const SAEC_Events_CYCLE_UNIT_INV = 1.0 / SAEC_Events_CYCLE_UNIT; /* mul is always faster than div */
23 | const SAEC_Events_CYCLE_MAX = 0x100000000 * SAEC_Events_CYCLE_UNIT;
24 |
25 | /*---------------------------------*/
26 |
27 | const SAEC_Events_EV_CIA = 0;
28 | const SAEC_Events_EV_AUDIO = 1;
29 | const SAEC_Events_EV_HSYNC = 2;
30 |
31 | const SAEC_Events_EV2_BLITTER = 0;
32 | const SAEC_Events_EV2_DISK = 1;
33 |
34 | const SAEC_Events_syncbase = 1000000;
35 |
36 | /*---------------------------------*/
37 |
38 | /*const SAEC_Events_cycle_line_REFRESH = 1;
39 | const SAEC_Events_cycle_line_STROBE = 2;
40 | const SAEC_Events_cycle_line_MISC = 3;
41 | const SAEC_Events_cycle_line_SPRITE = 4;
42 | const SAEC_Events_cycle_line_COPPER = 5;
43 | const SAEC_Events_cycle_line_BLITTER = 6;
44 | const SAEC_Events_cycle_line_CPU = 7;
45 | //const SAEC_Events_cycle_line_CPUNASTY = 8;
46 | const SAEC_Events_cycle_line_COPPER_SPECIAL = 0x10;
47 | const SAEC_Events_cycle_line_MASK = 0x0f;*/
48 |
49 | /*---------------------------------*/
50 | /* global references */
51 |
52 | var SAER_Events_eventtab = null;
53 |
54 | //var SAER_Events_cycle_line = null;
55 |
56 | /*---------------------------------*/
57 | /* global variables */
58 |
59 | var SAEV_Events_currcycle = 0;
60 | var SAEV_Events_bogusframe = 0;
61 | var SAEV_Events_timeframes = 0;
62 | var SAEV_Events_hsync_counter = 0;
63 | var SAEV_Events_vsync_counter = 0;
64 | var SAEV_Events_frameskiptime = 0;
65 | var SAEV_Events_reflowtime = 0; //OWN
66 |
67 | /*---------------------------------*/
68 |
69 | function SAEO_Events() {
70 | const EV_MISC = 3;
71 | const EV_MAX = 4;
72 | function Event() {
73 | this.active = false;
74 | this.evtime = 0;
75 | this.oldcycles = 0;
76 | this.handler = null;
77 | };
78 | var eventtab = new Array(EV_MAX); for (i = 0; i < EV_MAX; i++) eventtab[i] = new Event();
79 | SAER_Events_eventtab = eventtab;
80 |
81 | const EV2_MISC = 2;
82 | const EV2_MAX = 12;
83 | function Event2() {
84 | this.active = false;
85 | this.evtime = 0;
86 | this.data = null;
87 | this.handler = null;
88 | };
89 | var eventtab2 = new Array(EV2_MAX); for (i = 0; i < EV2_MAX; i++) eventtab2[i] = new Event2();
90 |
91 | //var currcycle = 0; -> SAEV_Events_currcycle
92 | var nextevent = 0;
93 | var is_syncline = 0, is_syncline_end = 0;
94 | //var vblank_found_chipset = false;
95 | //var sleeps_remaining = 0;
96 | var linecounter = 0;
97 |
98 | //var syncbase = 0; -> SAEC_Events_syncbase
99 | var vsyncmintime = 0, vsyncmaxtime = 0, vsyncwaittime = 0;
100 | var vsynctimebase = 0;
101 | //var rpt_did_reset = 0;
102 |
103 | //var frameskiptime = 0; -> SAEV_Events_frameskiptime
104 | var vsynctimeperline = 0; //global
105 |
106 | var dmal = 0, dmal_hpos = 0; //u16
107 |
108 | //in framewait()
109 | const MAVG_VSYNC_SIZE = 128;
110 | var ma_frameskipt = new SAEO_MAvg(MAVG_VSYNC_SIZE);
111 | //var ma_adjust = new mavg_data();
112 | //var ma_legacy = new mavg_data();
113 | //var ma_skip = new mavg_data();
114 | var ma_reflowt = new SAEO_MAvg(10); //OWN
115 | //var vsync_time = 0;
116 |
117 | //in MISC_handler()
118 | var dorecheck = false;
119 | var recursive = 0;
120 |
121 | /* Statistics */
122 | const FPSCOUNTER_MAVG_SIZE = 10
123 | var fps_mavg = new SAEO_MAvg(FPSCOUNTER_MAVG_SIZE);
124 | var idle_mavg = new SAEO_MAvg(FPSCOUNTER_MAVG_SIZE);
125 |
126 | //var bogusframe = 0; //-> SAEV_Events_bogusframe
127 | //var timeframes = 0; //-> SAEV_Events_timeframes
128 | var frametime = 0, lastframetime = 0; //global
129 | var idletime = 0; //global
130 | //var hsync_counter = 0; -> SAEV_Events_hsync_counter
131 | //var vsync_counter = 0; -> SAEV_Events_vsync_counter
132 |
133 | //event2_newevent_xx()
134 | var nextno = EV2_MISC;
135 |
136 | const PISSOFF_NOJIT_VALUE = 256 * SAEC_Events_CYCLE_UNIT;
137 | var pissoff = 0;
138 | //#define countdown pissoff
139 |
140 | //#ifdef CPUEMU_13
141 | //var cycle_line = new Uint8Array(256 + 1);
142 | //SAER_Events_cycle_line = cycle_line;
143 | //#endif
144 |
145 | /*-----------------------------------------------------------------------*/
146 |
147 | this.reset = function() { //init_eventtab()
148 | if (eventtab[SAEC_Events_EV_HSYNC].handler === null) { //OWN
149 | eventtab[SAEC_Events_EV_CIA].handler = function() { SAER.cia.handler(); };
150 | eventtab[SAEC_Events_EV_HSYNC].handler = function() { SAER.playfield.hsync_handler(); };
151 | eventtab[SAEC_Events_EV_AUDIO].handler = function() { SAER.audio.handler(); };
152 | eventtab[EV_MISC].handler = MISC_handler;
153 |
154 | eventtab2[SAEC_Events_EV2_BLITTER].handler = function(data) { SAER.blitter.handler(data); };
155 | eventtab2[SAEC_Events_EV2_DISK].handler = function(data) { SAER.disk.handler(data); };
156 | }
157 |
158 | nextevent = 0;
159 | nextno = EV2_MISC; //OWN
160 | for (var i = 0; i < EV_MAX; i++) {
161 | eventtab[i].active = false;
162 | eventtab[i].oldcycles = SAEV_Events_currcycle;
163 | }
164 | eventtab[SAEC_Events_EV_HSYNC].evtime = SAEV_Events_currcycle + SAER.playfield.get_maxhpos() * SAEC_Events_CYCLE_UNIT;
165 | eventtab[SAEC_Events_EV_HSYNC].active = true;
166 |
167 | for (i = 0; i < EV2_MAX; i++)
168 | eventtab2[i].active = false;
169 |
170 | this.schedule();
171 |
172 | //OWN
173 | dorecheck = false;
174 | recursive = 0;
175 | //nextno = EV2_MISC;
176 | fpscounter_reset();
177 | ma_frameskipt.clr();
178 | ma_reflowt.clr();
179 | //reset_frame_rate_hack();
180 | //sleeps_remaining = 0;
181 | linecounter = 0;
182 | }
183 |
184 | this.clr_dmal = function() {
185 | dmal = 0;
186 | }
187 |
188 | this.pauseResume = function(pause) {
189 | if (pause) {
190 | SAER.gui.data.fps = 0;
191 | SAER.gui.data.idle = 0;
192 | SAER.gui.fps(0, 0, 1);
193 | } else {
194 | dmal = 0;
195 | fpscounter_reset();
196 | ma_frameskipt.clr();
197 | }
198 | }
199 |
200 | /*-----------------------------------------------------------------------*/
201 |
202 | this.reset_frame_rate_hack = function() {
203 | if (SAEV_config.cpu.speed < 0) {
204 | //rpt_did_reset = 1;
205 | is_syncline = 0;
206 | vsyncmintime = SAEF_now() + vsynctimebase;
207 | //SAEF_log("events.reset_frame_rate_hack() %d", vsyncmintime);
208 | }
209 | }
210 | this.calc_vsynctimebase = function(hz) {
211 | vsynctimebase = SAEC_Events_syncbase / hz >>> 0;
212 | SAEF_log("events.calc_vsynctimebase() %d us (%f)", vsynctimebase, hz);
213 | this.reset_frame_rate_hack();
214 | return vsynctimebase;
215 | }
216 |
217 | this.schedule = function() {
218 | var mintime = SAEC_Events_CYCLE_MAX;
219 | for (var i = 0; i < EV_MAX; i++) {
220 | if (eventtab[i].active) {
221 | var eventtime = eventtab[i].evtime - SAEV_Events_currcycle;
222 | if (eventtime < mintime)
223 | mintime = eventtime;
224 | }
225 | }
226 | nextevent = SAEV_Events_currcycle + mintime;
227 | }
228 |
229 | /*this.get_cycles = function() { //OPT inline ok
230 | return SAEV_Events_currcycle;
231 | }
232 | this.set_cycles = function(x) {
233 | SAEV_Events_currcycle = x;
234 | eventtab[SAEC_Events_EV_HSYNC].oldcycles = x;
235 | }
236 | this.cycles_in_range = function(endcycles) { //OPT inline ok, used in disk.DSKBYTR()
237 | return endcycles - SAEV_Events_currcycle > 0;
238 | }*/
239 |
240 | /*function current_hpos_safe() { //OPT inline ok
241 | return ((SAEV_Events_currcycle - eventtab[SAEC_Events_EV_HSYNC].oldcycles) * SAEC_Events_CYCLE_UNIT_INV) >>> 0;
242 | }*/
243 | this.current_hpos = function() {
244 | //var hp = current_hpos_safe();
245 | var hp = ((SAEV_Events_currcycle - eventtab[SAEC_Events_EV_HSYNC].oldcycles) * SAEC_Events_CYCLE_UNIT_INV) >>> 0;
246 | if (hp < 0 || hp > 256) {
247 | SAEF_error("events.current_hpos() hpos = %d !?", hp);
248 | hp = 0;
249 | }
250 | return hp;
251 | }
252 |
253 | /*-----------------------------------------------------------------------*/
254 |
255 | this.do_cycles = function(cycles_to_add) { //do_cycles_slow()
256 | if ((pissoff -= cycles_to_add) >= 0)
257 | return;
258 |
259 | cycles_to_add = -pissoff;
260 | pissoff = 0;
261 |
262 | //if (cycles_to_add == 0) SAEF_warn("event.do_cycles() cycles_to_add == 0");
263 |
264 | while ((nextevent - SAEV_Events_currcycle) <= cycles_to_add) {
265 | // Keep only CPU emulation running while waiting for sync point.
266 | if (is_syncline) {
267 | //if (!vblank_found_chipset) {
268 | if (is_syncline > 0) {
269 | var rpt = SAEF_now();
270 | var v = rpt - vsyncmintime;
271 | var v2 = rpt - is_syncline_end;
272 | if (v > vsynctimebase || v < -vsynctimebase) v = 0;
273 | if (v < 0 && v2 < 0) {
274 | pissoff = PISSOFF_NOJIT_VALUE;
275 | return;
276 | }
277 | } else if (is_syncline < 0) {
278 | var rpt = SAEF_now();
279 | var v = rpt - is_syncline_end;
280 | if (v < 0) {
281 | pissoff = PISSOFF_NOJIT_VALUE;
282 | return;
283 | }
284 | }
285 | //}
286 | is_syncline = 0;
287 | }
288 |
289 | cycles_to_add -= nextevent - SAEV_Events_currcycle;
290 | SAEV_Events_currcycle = nextevent;
291 |
292 | for (var i = 0; i < EV_MAX; i++) {
293 | if (eventtab[i].active && eventtab[i].evtime == SAEV_Events_currcycle) {
294 | /*if (eventtab[i].handler === null) {
295 | SAEF_error("events.eventtab[%d].handler is null!", i);
296 | eventtab[i].active = false;
297 | } else*/
298 | eventtab[i].handler();
299 | }
300 | }
301 | this.schedule();
302 | }
303 | SAEV_Events_currcycle += cycles_to_add;
304 | }
305 | this.do_cycles_post = function(cycles, v) {
306 | this.do_cycles(cycles);
307 | }
308 |
309 | /*-----------------------------------------------------------------------*/
310 |
311 | function MISC_handler() {
312 | var mintime = SAEC_Events_CYCLE_MAX;
313 | var ct = SAEV_Events_currcycle;
314 |
315 | if (recursive) {
316 | dorecheck = true;
317 | return;
318 | }
319 | recursive++;
320 | SAER_Events_eventtab[EV_MISC].active = false;
321 |
322 | var recheck = true;
323 | while (recheck) {
324 | recheck = false;
325 | mintime = SAEC_Events_CYCLE_MAX;
326 | for (var i = 0; i < EV2_MAX; i++) {
327 | if (eventtab2[i].active) {
328 | if (eventtab2[i].evtime == ct) {
329 | eventtab2[i].active = false;
330 | eventtab2[i].handler(eventtab2[i].data);
331 | if (dorecheck || eventtab2[i].active) {
332 | recheck = true;
333 | dorecheck = false;
334 | }
335 | } else {
336 | var eventtime = eventtab2[i].evtime - ct;
337 | if (eventtime < mintime)
338 | mintime = eventtime;
339 | }
340 | }
341 | }
342 | }
343 | if (mintime != SAEC_Events_CYCLE_MAX) {
344 | SAER_Events_eventtab[EV_MISC].active = true;
345 | SAER_Events_eventtab[EV_MISC].oldcycles = ct;
346 | SAER_Events_eventtab[EV_MISC].evtime = ct + mintime;
347 | SAER.events.schedule();
348 | }
349 | recursive--;
350 | }
351 |
352 | this.event2_newevent_xx = function(no, t, data, func) {
353 | var et = SAEV_Events_currcycle + t;
354 | if (no < 0) {
355 | no = nextno;
356 | for (;;) {
357 | if (!eventtab2[no].active)
358 | break;
359 | if (eventtab2[no].evtime == et && eventtab2[no].data == data && eventtab2[no].handler === func)
360 | break;
361 | no++;
362 | if (no == EV2_MAX)
363 | no = EV2_MISC;
364 | if (no == nextno) {
365 | SAEF_error("events.event2_newevent_xx() out of events!");
366 | return;
367 | }
368 | }
369 | nextno = no;
370 | }
371 | eventtab2[no].active = true;
372 | eventtab2[no].evtime = et;
373 | eventtab2[no].handler = func;
374 | eventtab2[no].data = data;
375 | MISC_handler();
376 | }
377 | function event2_newevent_x(no, t, data, func) {
378 | if (t <= 0) {
379 | func(data);
380 | return;
381 | }
382 | SAER.events.event2_newevent_xx(no, t * SAEC_Events_CYCLE_UNIT, data, func);
383 | }
384 | this.event2_newevent = function(no, t, data) {
385 | event2_newevent_x(no, t, data, eventtab2[no].handler);
386 | }
387 | /*this.event2_newevent2 = function(t, data, func) {
388 | event2_newevent_x(-1, t, data, func);
389 | }*/
390 |
391 | this.event2_remevent = function(no) {
392 | eventtab2[no].active = false;
393 | }
394 |
395 | /*-----------------------------------------------------------------------*/
396 | /* events dmal */
397 |
398 | function dmal_emu(v) {
399 | // Disk and Audio DMA bits are ignored by Agnus, Agnus only checks DMAL and master bit
400 | if (!(SAEV_Custom_dmacon & SAEC_Custom_DMAF_DMAEN))
401 | return;
402 |
403 | var hpos = SAER.events.current_hpos();
404 | if (v >= 6) {
405 | v -= 6;
406 | var nr = v >> 1;
407 | var pt = SAER.audio.getpt(nr, (v & 1) != 0);
408 | var dat = SAER_Memory_chipGet16_indirect(pt);
409 | SAEV_Custom_last_value = dat;
410 | SAER.audio.AUDxDAT(nr, dat);
411 | } else {
412 | var w = v & 1;
413 | var pt = SAER.disk.getpt();
414 | // disk_fifostatus() needed in >100% disk speed modes
415 | if (w) {
416 | // write to disk
417 | if (SAER.disk.fifostatus() <= 0) {
418 | var dat = SAER_Memory_chipGet16_indirect(pt);
419 | SAEV_Custom_last_value = dat;
420 | SAER.disk.DSKDAT(dat);
421 | }
422 | } else {
423 | // read from disk
424 | if (SAER.disk.fifostatus() >= 0) {
425 | var dat = SAER.disk.DSKDATR();
426 | SAER_Memory_chipPut16_indirect(pt, dat);
427 | }
428 | }
429 | }
430 | }
431 |
432 | this.events_dmal_hsync = function() {
433 | if (dmal) SAEF_error("events.events_dmal_hsync() DMAL error!? %04x", dmal);
434 | dmal = SAER.audio.dmal();
435 | dmal = (dmal << 6) & 0xffff;
436 | dmal |= SAER.disk.dmal();
437 | if (dmal) {
438 | dmal_hpos = 0;
439 | //SAER.events.event2_newevent2(7, 13, function(v) {
440 | SAER.events.event2_newevent_xx(-1, 7 * SAEC_Events_CYCLE_UNIT, 13, function(v) {
441 | while (dmal) {
442 | if (dmal & 3)
443 | dmal_emu(dmal_hpos + ((dmal & 2) ? 1 : 0));
444 | dmal_hpos += 2;
445 | dmal >>>= 2;
446 | }
447 | });
448 | }
449 | }
450 |
451 | /*-----------------------------------------------------------------------*/
452 | /* fps counter */
453 |
454 | function fpscounter_reset() { //global
455 | fps_mavg.clr();
456 | idle_mavg.clr();
457 | SAEV_Events_bogusframe = 2;
458 | SAEV_Events_timeframes = 0;
459 | lastframetime = SAEF_now();
460 | idletime = 0;
461 | }
462 |
463 | this.fpscounter = function(frameok) {
464 | var now = SAEF_now();
465 | var last = now - lastframetime;
466 | lastframetime = now;
467 |
468 | if (SAEV_Events_bogusframe || last < 0)
469 | return;
470 |
471 | fps_mavg.set(last);
472 | idle_mavg.set(idletime);
473 | idletime = 0;
474 |
475 | frametime += last;
476 | SAEV_Events_timeframes++;
477 |
478 | if ((SAEV_Events_timeframes & 7) == 0) {
479 | var avg = idle_mavg.get();
480 | var idle = 100.0 - (avg == 0 ? 0 : avg * 100 / vsynctimebase);
481 | if (idle < 0)
482 | idle = 0.0;
483 | else if (idle > 100)
484 | idle = 100.0;
485 |
486 | avg = fps_mavg.get();
487 | var fps = avg == 0 ? 0 : SAEC_Events_syncbase / avg;
488 | if (fps > 999)
489 | fps = 999.0;
490 |
491 | if (SAEV_Playfield_fake_vblank_hz > fps) idle *= SAEV_Playfield_fake_vblank_hz / fps;
492 | //if (currprefs.turbo_emulation && idle < 100) idle = 100.0;
493 |
494 | SAER.gui.data.fps = fps;
495 | //SAER.gui.data.idle = (int)idle;
496 | SAER.gui.data.idle = idle;
497 | SAER.gui.data.fps_color = frameok ? 0 : 1;
498 | if ((SAEV_Events_timeframes & 15) == 0) {
499 | //SAER.gui.fps(fps, (int)idle, frameok ? 0 : 1);
500 | SAER.gui.fps(fps, idle, frameok ? 0 : 1);
501 | }
502 | }
503 | }
504 |
505 | /*-----------------------------------------------------------------------*/
506 | /* synchronization */
507 |
508 | this.framewait2_maximum = function(ll) {
509 | //static int sleeps_remaining;
510 | //if (is_last_line()) {
511 | if (ll) {
512 | /*sleeps_remaining = (165 - currprefs.cpu_idle) / 6;
513 | if (sleeps_remaining < 0)
514 | sleeps_remaining = 0;
515 | // really last line, just run the cpu emulation until whole vsync time has been used
516 | if (SAER.m68k.stopped && currprefs.cpu_idle) {
517 | // CPU in STOP state: sleep if enough time left.
518 | var rpt = SAEF_now();
519 | while (!vsync_isdone () && ~~vsyncmintime - ~~(rpt + vsynctimebase / 10) > 0 && ~~vsyncmintime - ~~rpt < vsynctimebase) {
520 | //if (!execute_other_cpu(rpt + vsynctimebase / 10))
521 | SAEF_sleep(1);
522 | rpt = SAEF_now();
523 | }
524 | } else*/ if (SAEV_config.cpu.speedThrottle) {
525 | vsyncmintime = SAEF_now(); // end of CPU emulation time
526 | is_syncline = 0;
527 | } else {
528 | vsyncmintime = vsyncmaxtime; // emulate if still time left
529 | is_syncline_end = SAEF_now() + vsynctimebase; // far enough in future, we never wait that long
530 | is_syncline = 2;
531 | }
532 | } else {
533 | //static int linecounter;
534 | // end of scanline, run cpu emulation as long as we still have time
535 | vsyncmintime += vsynctimeperline;
536 | linecounter++;
537 | is_syncline = 0;
538 | //if (!vsync_isdone() && !currprefs.turbo_emulation)
539 | {
540 | if (vsyncmaxtime - vsyncmintime > 0) {
541 | if (vsyncwaittime - vsyncmintime > 0) {
542 | var rpt = SAEF_now();
543 | // Extra time left? Do some extra CPU emulation
544 | if (vsyncmintime - rpt > 0) {
545 | /*if (SAER.m68k.stopped && currprefs.cpu_idle && sleeps_remaining > 0) {
546 | // STOP STATE: sleep.
547 | SAEF_sleep(1);
548 | sleeps_remaining--;
549 | } else*/ {
550 | is_syncline = 1;
551 | // limit extra time
552 | is_syncline_end = rpt + vsynctimeperline;
553 | linecounter = 0;
554 | }
555 | }
556 | }
557 | if (!SAER_Playfield_isvsync()) {
558 | // extra cpu emulation time if previous 10 lines without extra time.
559 | if (!is_syncline && linecounter >= 10 && (!SAER.m68k.stopped)) { // || !currprefs.cpu_idle)) {
560 | is_syncline = -1;
561 | is_syncline_end = SAEF_now() + vsynctimeperline;
562 | linecounter = 0;
563 | }
564 | }
565 | }
566 | }
567 | }
568 | }
569 | this.framewait2_normal = function() {
570 | vsyncmintime += vsynctimeperline;
571 | //if (!vsync_isdone() && !currprefs.turbo_emulation)
572 | {
573 | var rpt = SAEF_now();
574 | // sleep if more than 2ms "free" time
575 | //while (!vsync_isdone() && vsyncmintime - Math.floor(rpt + vsynctimebase / 10) > 0 && vsyncmintime - rpt < vsynctimebase) {
576 | while (vsyncmintime - Math.floor(rpt + vsynctimebase / 10) > 0 && vsyncmintime - rpt < vsynctimebase) {
577 | //if (!execute_other_cpu(rpt + vsynctimebase / 10))
578 | SAEF_sleep(1);
579 | rpt = SAEF_now();
580 | //SAEF_log("*");
581 | }
582 | }
583 | }
584 |
585 | /*---------------------------------*/
586 |
587 | function rpt_vsync(adjust) {
588 | var curr_time = SAEF_now();
589 | var v = curr_time - vsyncwaittime + adjust;
590 | if (v > SAEC_Events_syncbase || v < -SAEC_Events_syncbase) {
591 | vsyncmintime = vsyncmaxtime = vsyncwaittime = curr_time;
592 | v = 0;
593 | }
594 | return v;
595 | }
596 | /*function rtg_vsync() {
597 | #ifdef PICASSO96
598 | var start = SAEF_now();
599 | picasso_handle_vsync();
600 | var end = SAEF_now();
601 | SAEV_Events_frameskiptime += end - start;
602 | #endif
603 | }
604 | function rtg_vsynccheck() {
605 | if (vblank_found_rtg) {
606 | vblank_found_rtg = false;
607 | rtg_vsync();
608 | }
609 | }*/
610 |
611 | this.framewait = function() {
612 | var curr_time;
613 | var start;
614 | var vs = SAER_Playfield_isvsync_chipset();
615 | var status = 0;
616 |
617 | is_syncline = 0;
618 |
619 | //static struct mavg_data ma_frameskipt;
620 | var frameskipt_avg = ~~ma_frameskipt.set(SAEV_Events_frameskiptime); SAEV_Events_frameskiptime = 0;
621 | var reflowt_avg = ~~ma_reflowt.set(SAEV_Events_reflowtime);
622 |
623 | /*OWN stripped
624 | if (vs > 0) {} else if (vs < 0) {}*/
625 |
626 | status = 1;
627 |
628 | var clockadjust = 0;
629 | var vstb = vsynctimebase;
630 |
631 | if (SAEV_config.cpu.speed < 0) { //max
632 | if (!SAEV_Playfield_frame_rendered && !SAEV_Playfield_picasso_on)
633 | SAEV_Playfield_frame_rendered = SAER.video.render_screen(false);
634 |
635 | if (SAEV_config.cpu.speedThrottle) {
636 | // this delay can safely overshoot frame time by 1-2 ms, following code will compensate for it.
637 | for (;;) {
638 | curr_time = SAEF_now();
639 | if (vsyncwaittime - curr_time <= 0 || vsyncwaittime - curr_time > 2 * vsynctimebase)
640 | break;
641 | //rtg_vsynccheck();
642 | SAEF_sleep(1);
643 | }
644 | } else
645 | curr_time = SAEF_now();
646 |
647 | var adjust = 0, max;
648 | if (curr_time - vsyncwaittime > 0 && curr_time - vsyncwaittime < (vstb >> 1))
649 | adjust += curr_time - vsyncwaittime;
650 | adjust += clockadjust;
651 | if (SAEV_config.cpu.speedThrottle)
652 | max = Math.truncate(vstb * (1000.0 + SAEV_config.cpu.speedThrottle) / 1000.0 - adjust);
653 | else
654 | max = vstb - adjust;
655 | vsyncwaittime = curr_time + vstb - adjust;
656 | vsyncmintime = curr_time;
657 |
658 | if (max < 0) {
659 | max = 0;
660 | vsynctimeperline = 1;
661 | } else
662 | vsynctimeperline = max / (SAER.playfield.get_maxvpos_display() + 1) >>> 0;
663 |
664 | vsyncmaxtime = curr_time + max;
665 |
666 | //SAEF_info("%06d:%06d/%06d", adjust, vsynctimeperline, vstb);
667 | } else {
668 | const syncbase1000inv = 1.0 / (SAEC_Events_syncbase / 1000); //OWN
669 | var t = reflowt_avg; //OWN
670 |
671 | if (!SAEV_Playfield_frame_rendered && !SAEV_Playfield_picasso_on) {
672 | start = SAEF_now();
673 | SAEV_Playfield_frame_rendered = SAER.video.render_screen(false);
674 | t += SAEF_now() - start;
675 | }
676 | start = SAEF_now();
677 | while (true) { //while (!currprefs.turbo_emulation) {
678 | var v = rpt_vsync(clockadjust) * syncbase1000inv; //double
679 | if (v >= -4) break;
680 | //rtg_vsynccheck();
681 | SAEF_sleep(2);
682 | }
683 | while (rpt_vsync(clockadjust) < 0) {
684 | //rtg_vsynccheck();
685 | }
686 | curr_time = SAEF_now();
687 | idletime += curr_time - start;
688 |
689 | vsyncmintime = curr_time;
690 | vsyncmaxtime = vsyncwaittime = curr_time + vstb;
691 |
692 | if (SAEV_Playfield_frame_rendered) {
693 | SAER.video.show_screen(0);
694 | t += SAEF_now() - curr_time;
695 | }
696 | t += frameskipt_avg;
697 | vsynctimeperline = ~~((vstb - t) / 3);
698 | if (vsynctimeperline < 0)
699 | vsynctimeperline = 0;
700 | else if (vsynctimeperline > vstb / 3 >>> 0)
701 | vsynctimeperline = vstb / 3 >>> 0;
702 |
703 | SAEV_Playfield_frame_shown = true;
704 | }
705 | return status != 0;
706 | }
707 |
708 | /*-----------------------------------------------------------------------*/
709 | /* exact cycling */
710 |
711 | /*this.alloc_cycle = function(hpos, type) {
712 | //#ifdef CPUEMU_13
713 | //#if 0
714 | //if (cycle_line[hpos]) SAEF_log("events.alloc_cycle() hpos=%d, old=%d, new=%d", hpos, cycle_line[hpos], type);
715 | //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);
716 | //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);
717 | //#endif
718 | cycle_line[hpos] = type;
719 | //#endif
720 | }
721 | this.alloc_cycle_maybe = function(hpos, type) {
722 | if ((cycle_line[hpos] & SAEC_Events_cycle_line_MASK) == 0)
723 | this.alloc_cycle(hpos, type);
724 | }
725 | this.alloc_cycle_blitter = function(hpos, ptr, chnum) {
726 | if (cycle_line[hpos] & SAEC_Events_cycle_line_COPPER_SPECIAL) {
727 | //static int warned = 100;
728 | var srcptr = SAER.copper.get_copxlc(); //cop_state.strobe == 1 ? cop1lc : cop2lc;
729 | //if (warned > 0)
730 | {
731 | SAEF_warn("events.alloc_cycle_blitter() buggy copper cycle conflict with blitter ch %d", chnum);
732 | //warned--;
733 | }
734 | //if ((currprefs.cs_hacks & 1) && SAEV_config.cpu.model == SAEC_Config_CPU_Model_68000)
735 | if (SAEV_config.cpu.model == SAEC_Config_CPU_Model_68000 && SAEV_config.chipset.blitter.cycle_exact)
736 | ptr.val = srcptr;
737 | }
738 | this.alloc_cycle(hpos, SAEC_Events_cycle_line_BLITTER);
739 | }*/
740 | }
741 |
--------------------------------------------------------------------------------
/sae/filesys.js:
--------------------------------------------------------------------------------
1 | /*-------------------------------------------------------------------------
2 | | SAE - Scripted Amiga Emulator
3 | | https://github.com/naTmeg/ScriptedAmigaEmulator
4 | |
5 | | Copyright (C) 2012 Rupert Hausberger
6 | |
7 | | This program is free software; you can redistribute it and/or
8 | | modify it under the terms of the GNU General Public License
9 | | as published by the Free Software Foundation; either version 2
10 | | of the License, or (at your option) any later version.
11 | |
12 | | This program is distributed in the hope that it will be useful,
13 | | but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | | GNU General Public License for more details.
16 | |
17 | | Note: ported from WinUAE 3.2.x
18 | -------------------------------------------------------------------------*/
19 |
20 | function SAEO_Filesys() {
21 | this.uci_set_defaults = function(uci, rdb) {
22 | //memset(uci, 0, sizeof(struct uaedev_config_info));
23 | //controller
24 | //if (uci.controller_type == 0)
25 | uci.controller_type = SAEC_Config_Mount_Controller_Type_MB_IDE;
26 | uci.controller_unit = 0; //IDE channel + unit
27 | uci.controller_media_type = 0; // 1 = CF IDE, 0 = normal
28 | uci.unit_feature_level = SAEC_Config_Mount_Controller_Level_ATA_2;
29 | uci.unit_special_flags = 0; //1 = force LBA48
30 | //file
31 | //uci.type = UAEDEV_HDF;
32 | //uci.file.name = "";
33 | //uci.file.size = 0;
34 | //uci.file.data = "";
35 | uci.readonly = false;
36 | //rdb
37 | //drive geometry
38 | uci.blocksize = 512;
39 | uci.cyls = 0; // calculated/corrected highcyl
40 | if (!rdb) {
41 | uci.surfaces = 1;
42 | uci.sectors = 32;
43 | }
44 | //partition
45 | uci.bootable = true;
46 | uci.automount = true;
47 | uci.unit = 0;
48 | uci.flags = 0;
49 | uci.devname = "";
50 | //DosEnvec
51 | uci.sectorsperblock = 1;
52 | if (!rdb)
53 | uci.reserved = 2;
54 | uci.interleave = false;
55 | uci.lowcyl = 0;
56 | uci.highcyl = 0; // zero if detected from size
57 | uci.buffers = 50;
58 | uci.bufmemtype = 1;
59 | uci.maxtransfer = 0x7fffffff;
60 | uci.mask = 0xffffffff;
61 | uci.bootpri = 0;
62 | uci.dostype = 0x444f5301;
63 | //filesystem
64 | uci.filesys = "";
65 | //DeviceNode
66 | uci.stacksize = 4000;
67 | uci.priority = -129;
68 | //uci.device_emu_unit = -1;
69 | }
70 |
71 | /*-----------------------------------------------------------------------*/
72 |
73 | function allocuci(p, nr, idx, unitnum) {
74 | if (typeof unitnum == "undefined")
75 | unitnum = -1;
76 | var uci = p.mount.config[nr];
77 | if (idx >= 0) {
78 | /*var ui = mountinfo.ui[idx];
79 | ui.configureddrive = 1;*/
80 |
81 | uci.configoffset = idx;
82 | uci.unitnum = unitnum;
83 | } else {
84 | uci.configoffset = -1;
85 | uci.unitnum = -1;
86 | }
87 | }
88 |
89 | /*---------------------------------*/
90 |
91 | function getunittype(uci) {
92 | return "HD" //uci.type == UAEDEV_CD ? "CD" : (uci.type == UAEDEV_TAPE ? "TAPE" : "HD");
93 | }
94 | function ismainboardide() {
95 | return SAEV_config.chipset.ide != 0;
96 | }
97 | /*function isa3000scsi() {
98 | return SAEV_config.chipset.mbdmac == 1;
99 | }
100 | function isa4000tscsi() {
101 | return SAEV_config.chipset.mbdmac == 2;
102 | }
103 | function iscdtvscsi() {
104 | return currprefs.cs_cdtvscsi != 0;
105 | }*/
106 | function add_mainboard_unit_init() {
107 | if (ismainboardide()) {
108 | SAEF_log("filesys.add_mainboard_unit_init() Initializing mainboard IDE");
109 | SAER.gayle.gayle_add_ide_unit(-1, null);
110 | }
111 | /*if (isa3000scsi()) {
112 | SAEF_log("filesys.add_mainboard_unit_init() Initializing A3000 mainboard SCSI");
113 | a3000_add_scsi_unit(-1, null, null);
114 | }
115 | if (isa4000tscsi()) {
116 | SAEF_log("filesys.add_mainboard_unit_init() Initializing A4000T mainboard SCSI");
117 | a4000t_add_scsi_unit(-1, null, null);
118 | }
119 | if (iscdtvscsi()) {
120 | SAEF_log("filesys.add_mainboard_unit_init() Initializing CDTV SCSI expansion");
121 | cdtv_add_scsi_unit(-1, null, null);
122 | }*/
123 | }
124 |
125 | function add_ide_unit(type, unit, uci) {
126 | var added = false;
127 | if (type == SAEC_Config_Mount_Controller_Type_MB_IDE) {
128 | if (ismainboardide()) {
129 | SAEF_log("filesys.add_ide_unit() Adding mainboard IDE %s unit %d ('%s')", getunittype(uci), unit, uci.file.name);
130 | SAER.gayle.gayle_add_ide_unit(unit, uci);
131 | added = true;
132 | }
133 | }
134 | return added;
135 | }
136 |
137 | function initialize_mountinfo() {
138 | // init all controllers first
139 | add_mainboard_unit_init();
140 |
141 | for (var nr = 0; nr < 6; nr++) {
142 | var uci = SAEV_config.mount.config[nr].ci;
143 | var type = uci.controller_type;
144 | var unit = uci.controller_unit;
145 | var added = false;
146 | if (type == 0 || uci.file.size == 0)
147 | continue;
148 | if (type == SAEC_Config_Mount_Controller_Type_MB_IDE)
149 | added = add_ide_unit(type, unit, uci);
150 | else if (type == SAEC_Config_Mount_Controller_Type_PCMCIA_SRAM) {
151 | SAER.gayle.gayle_add_pcmcia_sram_unit(uci);
152 | added = true;
153 | }
154 | else if (type == SAEC_Config_Mount_Controller_Type_PCMCIA_IDE) {
155 | SAER.gayle.gayle_add_pcmcia_ide_unit(uci);
156 | added = true;
157 | }
158 | if (added)
159 | allocuci(SAEV_config, nr, -1);
160 | }
161 | }
162 | function free_mountinfo() {
163 | SAER.gayle.free_units();
164 | }
165 |
166 | /*-----------------------------------------------------------------------*/
167 |
168 | this.start_threads = function() {} //filesys_start_threads()
169 |
170 | this.cleanup = function() { //filesys_cleanup()
171 | free_mountinfo();
172 | }
173 |
174 | this.reset = function() { //filesys_reset()
175 | free_mountinfo();
176 | initialize_mountinfo();
177 | }
178 | this.prepare_reset = function() {} //filesys_prepare_reset()
179 | }
180 |
--------------------------------------------------------------------------------
/sae/m68k.js:
--------------------------------------------------------------------------------
1 | /*-------------------------------------------------------------------------
2 | | SAE - Scripted Amiga Emulator
3 | | https://github.com/naTmeg/ScriptedAmigaEmulator
4 | |
5 | | Copyright (C) 2012 Rupert Hausberger
6 | |
7 | | This program is free software; you can redistribute it and/or
8 | | modify it under the terms of the GNU General Public License
9 | | as published by the Free Software Foundation; either version 2
10 | | of the License, or (at your option) any later version.
11 | |
12 | | This program is distributed in the hope that it will be useful,
13 | | but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | | GNU General Public License for more details.
16 | |
17 | | Notes:
18 | | This file consists of two parts: high-level functions, which are ported
19 | | from WinUAE 3.2.x and low-level functions, written from scratch.
20 | -------------------------------------------------------------------------*/
21 | /* global constants */
22 |
23 | //const SAEC_CPU_halt_PPC_ONLY = -1;
24 | const SAEC_CPU_halt_BUS_ERROR_DOUBLE_FAULT = 1;
25 | const SAEC_CPU_halt_DOUBLE_FAULT = 2;
26 | const SAEC_CPU_halt_OPCODE_FETCH_FROM_NON_EXISTING_ADDRESS = 3;
27 | //const SAEC_CPU_halt_ACCELERATOR_CPU_FALLBACK = 4;
28 | //const SAEC_CPU_halt_ALL_CPUS_STOPPED = 5;
29 | //const SAEC_CPU_halt_FAKE_DMA = 6;
30 | const SAEC_CPU_halt_AUTOCONFIG_CONFLICT = 7;
31 | //const SAEC_CPU_halt_PCI_CONFLICT = 8;
32 | //const SAEC_CPU_halt_CPU_STUCK = 9;
33 |
34 | /*---------------------------------*/
35 | /* global references */
36 |
37 | /*---------------------------------*/
38 | /* global variables */
39 |
40 | /*---------------------------------*/
41 |
42 | function SAEO_M68K() {
43 | var reset_delay = false;
44 | this.halted = 0;
45 | this.stopped = false;
46 |
47 | var haltloop_prevvpos = false;
48 | var prevtime = false;
49 |
50 | /*-----------------------------------------------------------------------*/
51 |
52 | this.setup = function() { //init_m68k()
53 | return SAER.cpu.setup();
54 | }
55 |
56 | function m68k_reset(hardreset) { //m68k_reset2
57 | SAEV_spcflags = 0;
58 | SAEF_setSpcFlags(SAEC_spcflag_CHECK);
59 |
60 | this.halted = 0;
61 | haltloop_prevvpos = false;
62 | SAER.gui.data.cpu_halted = 0;
63 | SAER.gui.led(SAEC_GUI_LED_CPU, 0, -1);
64 |
65 | reset_delay = false;
66 | prevtime = false;
67 |
68 | SAER.cpu.reset(hardreset);
69 | //SAER.cpu.diss(regs.pc, 16);
70 | }
71 |
72 | this.dump = function() {
73 | //var out = "";
74 | SAER.cpu.dump();
75 | //SAEF_log(out);
76 | }
77 |
78 | /*-----------------------------------------------------------------------*/
79 |
80 | this.cpureset = function() {
81 | /* RESET hasn"t increased PC yet, 1 word offset */
82 | var ksboot = 0xf80002 - 2;
83 |
84 | reset_delay = SAEV_config.cpu.resetDelay;
85 | SAEF_setSpcFlags(SAEC_spcflag_CHECK);
86 | //send_internalevent(INTERNALEVENT_CPURESET);
87 | if (SAEV_config.cpu.compatible && SAEV_config.cpu.model <= SAEC_Config_CPU_Model_68020) {
88 | SAER.playfield.custom_reset(false, false);
89 | return;
90 | }
91 | var pc = SAER_CPU_getPC() + 2;
92 | var bank = SAER_Memory_getBank(pc);
93 | if (bank.check(pc, 2)) {
94 | SAEF_log("cpu.cpureset() PC=%x (%s)...", pc - 2, bank.name);
95 | var ins = SAER_Memory_get16(pc);
96 | SAER.playfield.custom_reset(false, false);
97 | // did memory disappear under us?
98 | if (bank === SAER_Memory_getBank(pc))
99 | return;
100 | // it did
101 | if ((ins & ~7) == 0x4ed0) {
102 | var addr = SAER_CPU_regs.a[ins & 7];
103 | if (addr < 0x80000)
104 | addr += 0xf80000;
105 | SAEF_log("cpu.cpureset() reset/jmp combination at %08x emulated -> %x", pc, addr);
106 | SAER.cpu.setPC_normal(addr - 2);
107 | return;
108 | }
109 | }
110 | SAEF_log("cpu.cpureset() PC=%x (%s), invalid memory -> %x.", pc, bank.name, ksboot + 2);
111 | SAER.playfield.custom_reset(false, false);
112 | SAER.cpu.setPC_normal(ksboot);
113 | }
114 |
115 | /*-----------------------------------------------------------------------*/
116 |
117 | this.cpu_halt = function(id) {
118 | // id < 0: m68k halted, PPC active.
119 | // id > 0: emulation halted.
120 | if (!this.halted) {
121 | SAEF_log("CPU halted: reason = %d PC=%08x", id, SAER_CPU_getPC());
122 | this.halted = id;
123 | SAER.gui.data.cpu_halted = id;
124 | SAER.gui.led(SAEC_GUI_LED_CPU, 0, -1);
125 | if (id >= 0) {
126 | SAER_CPU_regs.intmask = 7;
127 | SAER_Audio_deactivate();
128 | }
129 | SAEF_setSpcFlags(SAEC_spcflag_CHECK);
130 | }
131 | }
132 |
133 | function haltloop() {
134 | while (SAER.m68k.halted) {
135 | //SAEF_log("cpu.haltloop()");
136 | var vpos = SAER.playfield.get_vpos();
137 | if (vpos == 0 && haltloop_prevvpos) {
138 | haltloop_prevvpos = false;
139 | SAEF_sleep(8);
140 | }
141 | if (vpos)
142 | haltloop_prevvpos = true;
143 |
144 | SAER.events.do_cycles(8 * SAEC_Events_CYCLE_UNIT);
145 |
146 | if (SAEV_spcflags & SAEC_spcflag_COPPER)
147 | SAER.copper.cycle();
148 |
149 | if (SAEV_spcflags) {
150 | if ((SAEV_spcflags & (SAEC_spcflag_BRK | SAEC_spcflag_MODE_CHANGE)))
151 | return true;
152 | }
153 | }
154 | return false;
155 | }
156 |
157 | /*-----------------------------------------------------------------------*/
158 |
159 | var cpu_keyboardreset = false;
160 | var cpu_hardreset = true;
161 |
162 | this.is_keyboardreset = function() {
163 | return cpu_keyboardreset;
164 | }
165 | this.is_hardreset = function() {
166 | return cpu_hardreset;
167 | }
168 |
169 | this.m68k_pause = function() {
170 | if (SAEV_command == SAEC_command_Pause) {
171 | SAEV_command = 0;
172 | if (!SAER.paused) {
173 | SAEF_log("->pause");
174 | SAER.paused = true;
175 | SAER.pause_program(1);
176 | }
177 | }
178 | else if (SAEV_command == SAEC_command_Resume) {
179 | SAEV_command = 0;
180 | if (SAER.paused) {
181 | SAEF_log("->resume");
182 | SAER.pause_program(0);
183 | SAER.paused = false;
184 | prevtime = false;
185 | }
186 | }
187 | else if (SAEV_command == -SAEC_command_Quit ||
188 | SAEV_command == -SAEC_command_Reset ||
189 | SAEV_command == -SAEC_command_KeyboardReset ||
190 | SAEV_command == -SAEC_command_HardReset
191 | ) {
192 | SAEF_log("->stop");
193 | SAER.paused = false;
194 | }
195 |
196 | if (SAER.paused)
197 | setTimeout(function() { SAER.m68k.m68k_pause(); }, 500);
198 | else
199 | setTimeout(function() { SAER.m68k.m68k_cycle(0, 0); }, 0);
200 | }
201 |
202 | this.m68k_cycle = function(hardboot, startup) {
203 | try {
204 | if (SAEV_command > 0) {
205 | cpu_keyboardreset = SAEV_command == SAEC_command_KeyboardReset;
206 | cpu_hardreset = ((SAEV_command == SAEC_command_HardReset ? 1 : 0) | hardboot) != 0;
207 |
208 | if (SAEV_command == SAEC_command_Quit) {
209 | this.m68k_gone();
210 | return;
211 | }
212 | else if (SAEV_command == SAEC_command_Pause) {
213 | this.m68k_pause();
214 | return;
215 | }
216 |
217 | SAEV_command = 0;
218 | hardboot = 0;
219 |
220 | SAEV_Events_hsync_counter = 0;
221 | SAEV_Events_vsync_counter = 0;
222 | SAEV_Events_currcycle = 0; SAER_Events_eventtab[SAEC_Events_EV_HSYNC].oldcycles = 0;
223 |
224 | SAER.playfield.custom_reset(cpu_hardreset, cpu_keyboardreset);
225 | m68k_reset(cpu_hardreset);
226 | if (cpu_hardreset) {
227 | SAER.memory.clear();
228 | SAEF_log("m68k.m68k_cycle() hardreset, memory cleared.");
229 | }
230 |
231 | if (SAEV_config.audio.mode == 0)
232 | SAER_Events_eventtab[SAEC_Events_EV_AUDIO].active = false;
233 |
234 | SAER.cpu.setPC_normal(SAER_CPU_regs.pc);
235 |
236 | //SAER.audio.check_prefs_changed_audio();
237 |
238 | //statusline_clear();
239 |
240 | if (typeof SAEV_config.hook.event.reseted === "function")
241 | SAEV_config.hook.event.reseted(cpu_hardreset);
242 |
243 | cpu_hardreset = false;
244 | }
245 |
246 | if (startup) {
247 | SAER.playfield.custom_prepare();
248 | //protect_roms(true);
249 | startup = 0;
250 | }
251 | SAEF_clrSpcFlags(SAEC_spcflag_MODE_CHANGE);
252 |
253 | if (this.halted) {
254 | this.cpu_halt(this.halted);
255 | /*if (this.halted < 0) {
256 | haltloop();
257 | //continue;
258 | setTimeout(function() { SAER.m68k.m68k_cycle(hardboot, startup); }, 0);
259 | return;
260 | }*/
261 | }
262 |
263 | if (prevtime !== false) // && SAEV_config.cpu.speed >= 0)
264 | SAEV_Events_reflowtime = SAEF_now() - prevtime;
265 |
266 | SAER_CPU_run_func();
267 |
268 | //if (SAEV_config.cpu.speed >= 0)
269 | prevtime = SAEF_now();
270 |
271 | setTimeout(function() { SAER.m68k.m68k_cycle(hardboot, startup); }, 0);
272 | } catch(e) {
273 | this.m68k_gone();
274 | if (e instanceof SAEO_Error) {
275 | if (typeof SAEV_config.hook.log.error === "function")
276 | SAEV_config.hook.log.error(e.err, e.msg);
277 | else
278 | alert(e.msg);
279 | } else
280 | throw e;
281 | }
282 | }
283 | this.m68k_go = function(may_quit) {
284 | var hardboot = 1;
285 | var startup = 1;
286 |
287 | //SAEF_info("m68k.m68k_go()");
288 | SAER.events.reset_frame_rate_hack();
289 |
290 | SAER.running = true;
291 | //this.m68k_cycle(1, 1);
292 | setTimeout(function() { SAER.m68k.m68k_cycle(hardboot, startup); }, 0);
293 | }
294 | this.m68k_gone = function() {
295 | //SAEF_info("m68k.m68k_gone()");
296 | //protect_roms(false);
297 | SAER.running = false;
298 |
299 | SAER.leave_program();
300 | }
301 |
302 | /*-----------------------------------------------------------------------*/
303 |
304 | this.m68k_setstopped = function() {
305 | this.stopped = true;
306 | /* A traced STOP instruction drops through immediately without actually stopping. */
307 | if ((SAEV_spcflags & SAEC_spcflag_DOTRACE) == 0)
308 | SAEF_setSpcFlags(SAEC_spcflag_STOP);
309 | else
310 | this.m68k_resumestopped();
311 | }
312 |
313 | this.m68k_resumestopped = function() {
314 | if (this.stopped) {
315 | this.stopped = false;
316 | SAER_CPU_fill_prefetch();
317 | SAEF_clrSpcFlags(SAEC_spcflag_STOP);
318 | }
319 | }
320 |
321 | /*-----------------------------------------------------------------------*/
322 |
323 | this.doint = function() {
324 | if (SAEV_config.cpu.compatible && SAEV_config.cpu.model < SAEC_Config_CPU_Model_68020)
325 | SAEF_setSpcFlags(SAEC_spcflag_INT);
326 | else
327 | SAEF_setSpcFlags(SAEC_spcflag_DOINT);
328 | }
329 |
330 | this.doint_trace = function(t) { //OWN cpu.setSR()
331 | //this.doint();
332 | if (SAEV_config.cpu.compatible && SAEV_config.cpu.model < SAEC_Config_CPU_Model_68020)
333 | SAEF_setSpcFlags(SAEC_spcflag_INT);
334 | else
335 | SAEF_setSpcFlags(SAEC_spcflag_DOINT);
336 | if (t)
337 | SAEF_setSpcFlags(SAEC_spcflag_TRACE);
338 | else
339 | SAEF_clrSpcFlags(SAEC_spcflag_TRACE);
340 | }
341 |
342 | /*-----------------------------------------------------------------------*/
343 |
344 | function do_interrupt(nr) {
345 | this.stopped = false;
346 | SAEF_clrSpcFlags (SAEC_spcflag_STOP);
347 | SAEF_assert(nr < 8 && nr >= 0);
348 |
349 | for (;;) {
350 | SAER_CPU_exception(nr + 24);
351 | SAER_CPU_regs.intmask = nr;
352 | if (!SAEV_config.cpu.compatible)
353 | break;
354 |
355 | nr = SAER.custom.intlev();
356 | if (nr <= 0 || SAER_CPU_regs.intmask >= nr)
357 | break;
358 | }
359 |
360 | SAER.m68k.doint();
361 | }
362 | /*this.NMI = function() {
363 | do_interrupt(7);
364 | }*/
365 |
366 | //static uaecptr last_trace_ad = 0;
367 | function do_trace() {
368 | if (SAER_CPU_regs.t0 && SAEV_config.cpu.model >= SAEC_Config_CPU_Model_68020) {
369 | /* should also include TRAP, CHK, SR modification FPcc */
370 | /* probably never used so why bother */
371 | /* We can afford this to be inefficient... */
372 | SAER.cpu.setPC_normal(SAER_CPU_getPC());
373 | SAER_CPU_fill_prefetch();
374 | var opcode = SAER_Memory_get16(SAER_CPU_regs.pc);
375 | if (opcode == 0x4e73 /* RTE */
376 | || opcode == 0x4e74 /* RTD */
377 | || opcode == 0x4e75 /* RTS */
378 | || opcode == 0x4e77 /* RTR */
379 | || opcode == 0x4e76 /* TRAPV */
380 | || (opcode & 0xffc0) == 0x4e80 /* JSR */
381 | || (opcode & 0xffc0) == 0x4ec0 /* JMP */
382 | || (opcode & 0xff00) == 0x6100 /* BSR */
383 | || ((opcode & 0xf000) == 0x6000 && ccTab[(opcode >> 8) & 0xf]()) /* Bcc */
384 | || ((opcode & 0xf0f0) == 0x5050 && !ccTab[(opcode >> 8) & 0xf]() && SAER_CPU_regs.d[opcode & 7] & 0xffff != 0) /* DBcc */
385 | ) {
386 | //last_trace_ad = SAER_CPU_getPC();
387 | SAEF_clrSpcFlags(SAEC_spcflag_TRACE);
388 | SAEF_setSpcFlags(SAEC_spcflag_DOTRACE);
389 | }
390 | } else if (SAER_CPU_regs.t1) {
391 | //last_trace_ad = SAER_CPU_getPC();
392 | SAEF_clrSpcFlags(SAEC_spcflag_TRACE);
393 | SAEF_setSpcFlags(SAEC_spcflag_DOTRACE);
394 | }
395 | }
396 |
397 | this.do_specialties = function(cycles) {
398 | if (SAEV_spcflags & SAEC_spcflag_MODE_CHANGE)
399 | return true;
400 |
401 | if (SAEV_spcflags & SAEC_spcflag_CHECK) {
402 | if (this.halted) {
403 | SAEF_clrSpcFlags(SAEC_spcflag_CHECK);
404 | if (haltloop())
405 | return true;
406 | }
407 | if (reset_delay) {
408 | var vsynccnt = 60;
409 | var vsyncstate = -1;
410 | while (vsynccnt > 0 && SAEV_command == 0) {
411 | SAER.events.do_cycles(8 * SAEC_Events_CYCLE_UNIT);
412 | if (SAEV_spcflags & SAEC_spcflag_COPPER)
413 | SAER.copper.cycle();
414 | if (SAEV_Events_timeframes != vsyncstate) {
415 | vsyncstate = SAEV_Events_timeframes;
416 | vsynccnt--;
417 | }
418 | }
419 | reset_delay = false;
420 | }
421 | SAEF_clrSpcFlags(SAEC_spcflag_CHECK);
422 | }
423 |
424 | /*#ifdef ACTION_REPLAY
425 | #ifdef ACTION_REPLAY_HRTMON
426 | if ((SAEV_spcflags & SAEC_spcflag_ACTION_REPLAY) && hrtmon_flag != ACTION_REPLAY_INACTIVE) {
427 | int isinhrt = (SAER_CPU_getPC() >= hrtmem_start && SAER_CPU_getPC() < hrtmem_start + hrtmem_size);
428 | if (hrtmon_flag == ACTION_REPLAY_ACTIVE && !isinhrt)
429 | hrtmon_hide ();
430 | if (hrtmon_flag == ACTION_REPLAY_IDLE && isinhrt)
431 | hrtmon_breakenter ();
432 | if (hrtmon_flag == ACTION_REPLAY_ACTIVATE)
433 | hrtmon_enter ();
434 | }
435 | #endif
436 | if ((SAEV_spcflags & SAEC_spcflag_ACTION_REPLAY) && action_replay_flag != ACTION_REPLAY_INACTIVE) {
437 | if (action_replay_flag == ACTION_REPLAY_ACTIVE && !is_ar_pc_in_rom ())
438 | SAEF_log("PC:%p", SAER_CPU_getPC());
439 | if (action_replay_flag == ACTION_REPLAY_ACTIVATE || action_replay_flag == ACTION_REPLAY_DORESET)
440 | action_replay_enter ();
441 | if ((action_replay_flag == ACTION_REPLAY_HIDE || action_replay_flag == ACTION_REPLAY_ACTIVE) && !is_ar_pc_in_rom ()) {
442 | action_replay_hide ();
443 | SAEF_clrSpcFlags (SAEC_spcflag_ACTION_REPLAY);
444 | }
445 | if (action_replay_flag == ACTION_REPLAY_WAIT_PC) {
446 | SAEF_log("Waiting for PC: %p, current PC= %p", wait_for_pc, SAER_CPU_getPC());
447 | if (SAER_CPU_getPC() == wait_for_pc) {
448 | action_replay_flag = ACTION_REPLAY_ACTIVATE;
449 | }
450 | }
451 | }
452 | #endif*/
453 |
454 | if (SAEV_spcflags & SAEC_spcflag_COPPER)
455 | SAER.copper.cycle();
456 |
457 | while ((SAEV_spcflags & SAEC_spcflag_BLTNASTY) && SAEF_Custom_dmaen(SAEC_Custom_DMAF_BLTEN) && cycles > 0 && !SAEV_config.chipset.blitter.cycle_exact) {
458 | var c = SAER.blitter.blitnasty();
459 | if (c < 0)
460 | break;
461 | else if (c > 0) {
462 | cycles -= c * SAEC_Events_CYCLE_UNIT * 2;
463 | if (cycles < SAEC_Events_CYCLE_UNIT)
464 | cycles = 0;
465 | } else
466 | c = 4;
467 |
468 | SAER.events.do_cycles(c * SAEC_Events_CYCLE_UNIT);
469 | if (SAEV_spcflags & SAEC_spcflag_COPPER)
470 | SAER.copper.cycle();
471 | }
472 |
473 | if (SAEV_spcflags & SAEC_spcflag_DOTRACE)
474 | SAER_CPU_exception(9);
475 |
476 | /*if (SAEV_spcflags & SAEC_spcflag_TRAP) {
477 | SAEF_clrSpcFlags(SAEC_spcflag_TRAP);
478 | SAER_CPU_exception(3);
479 | }*/
480 | var first = true;
481 | while ((SAEV_spcflags & SAEC_spcflag_STOP) && !(SAEV_spcflags & SAEC_spcflag_BRK)) {
482 | if (!first) SAER.events.do_cycles(4 * SAEC_Events_CYCLE_UNIT);
483 | first = false;
484 |
485 | if (SAEV_spcflags & SAEC_spcflag_COPPER)
486 | SAER.copper.cycle();
487 |
488 | if (SAEV_spcflags & (SAEC_spcflag_INT | SAEC_spcflag_DOINT)) {
489 | var intr = SAER.custom.intlev();
490 | SAEF_clrSpcFlags(SAEC_spcflag_INT | SAEC_spcflag_DOINT);
491 |
492 | if (intr > 0 && intr > SAER_CPU_regs.intmask)
493 | do_interrupt(intr);
494 | }
495 |
496 | if (SAEV_spcflags & SAEC_spcflag_MODE_CHANGE) {
497 | this.m68k_resumestopped();
498 | return true;
499 | }
500 | }
501 |
502 | if (SAEV_spcflags & SAEC_spcflag_TRACE)
503 | do_trace();
504 |
505 | if (SAEV_spcflags & SAEC_spcflag_INT) {
506 | var intr = SAER.custom.intlev();
507 | SAEF_clrSpcFlags(SAEC_spcflag_INT | SAEC_spcflag_DOINT);
508 | if (intr > 0 && (intr > SAER_CPU_regs.intmask || intr == 7))
509 | do_interrupt(intr);
510 | }
511 | if (SAEV_spcflags & SAEC_spcflag_DOINT) {
512 | SAEF_clrSpcFlags(SAEC_spcflag_DOINT);
513 | SAEF_setSpcFlags(SAEC_spcflag_INT);
514 | }
515 |
516 | if (SAEV_spcflags & SAEC_spcflag_BRK) {
517 | SAEF_clrSpcFlags(SAEC_spcflag_BRK);
518 | return true; //OWN
519 | }
520 |
521 | return false;
522 | }
523 | }
524 |
--------------------------------------------------------------------------------
/sae/prototypes.js:
--------------------------------------------------------------------------------
1 | /*-------------------------------------------------------------------------
2 | | SAE - Scripted Amiga Emulator
3 | | https://github.com/naTmeg/ScriptedAmigaEmulator
4 | |
5 | | Copyright (C) 2012 Rupert Hausberger
6 | |
7 | | This program is free software; you can redistribute it and/or
8 | | modify it under the terms of the GNU General Public License
9 | | as published by the Free Software Foundation; either version 2
10 | | of the License, or (at your option) any later version.
11 | |
12 | | This program is distributed in the hope that it will be useful,
13 | | but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | | GNU General Public License for more details.
16 | -------------------------------------------------------------------------*/
17 | /* Math */
18 |
19 | if (!Math.truncate) {
20 | Math.truncate = function(v) {
21 | if (v > 0)
22 | return this.floor(v);
23 | else if (v < 0)
24 | return this.ceil(v);
25 |
26 | return 0;
27 | };
28 | }
29 |
30 | if (!Math.decimalRandom) {
31 | Math.decimalRandom = function() {
32 | //var l = 0, u = 0xffffffff; return this.floor((this.random() * (u - l + 1)) + l);
33 | return (this.random() * 0xffffffff) >>> 0;
34 | };
35 | }
36 |
37 | /*-----------------------------------------------------------------------*/
38 | /* Date/Performance */
39 |
40 | if (!Date.now) {
41 | console.warn("This browser does not support 'Date.now()'. Falling back to 'Date.getTime()'...");
42 | /* milliseconds since 1 January 1970 00:00:00 UTC */
43 | Date.now = function() {
44 | return new Date().getTime();
45 | };
46 | }
47 |
48 | if (!window.performance) {
49 | console.warn("This browser does not support 'window.performance'. Falling back to 'Date'...");
50 | window.performance = {};
51 | }
52 | if (!performance.timing) {
53 | performance.timing = {
54 | navigationStart: Date.now()
55 | };
56 | }
57 | if (!performance.now) {
58 | if (performance.webkitNow)
59 | performance.now = performance.webkitNow;
60 | else
61 | performance.now = function() {
62 | return Date.now() - this.timing.navigationStart;
63 | };
64 | }
65 |
66 | /*-----------------------------------------------------------------------*/
67 | /* AnimationFrame */
68 |
69 | (function() {
70 | var lastTime = 0;
71 |
72 | if (!window.requestAnimationFrame) {
73 | console.warn("This browser does not support 'window.requestAnimationFrame'. Falling back to 'setTimeout'...");
74 | window.requestAnimationFrame = function(callback, element) {
75 | var currTime = new Date().getTime();
76 | var timeToCall = Math.max(0, 16 - (currTime - lastTime));
77 | var id = window.setTimeout(function() { callback(currTime + timeToCall); }, timeToCall);
78 | lastTime = currTime + timeToCall;
79 | return id;
80 | };
81 | }
82 | if (!window.cancelAnimationFrame) {
83 | console.warn("This browser does not support 'window.cancelAnimationFrame'. Falling back to 'clearTimeout'...");
84 | window.cancelAnimationFrame = function(id) {
85 | clearTimeout(id);
86 | };
87 | }
88 | }());
89 |
--------------------------------------------------------------------------------
/sae/rtc.js:
--------------------------------------------------------------------------------
1 | /*-------------------------------------------------------------------------
2 | | SAE - Scripted Amiga Emulator
3 | | https://github.com/naTmeg/ScriptedAmigaEmulator
4 | |
5 | | Copyright (C) 2012 Rupert Hausberger
6 | |
7 | | This program is free software; you can redistribute it and/or
8 | | modify it under the terms of the GNU General Public License
9 | | as published by the Free Software Foundation; either version 2
10 | | of the License, or (at your option) any later version.
11 | |
12 | | This program is distributed in the hope that it will be useful,
13 | | but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | | GNU General Public License for more details.
16 | |
17 | | Note: ported from WinUAE 3.2.x
18 | -------------------------------------------------------------------------*/
19 | /* global variables */
20 |
21 | var SAEV_RTC_bank = null;
22 |
23 | var SAEV_RTC_delayed_write = 0;
24 |
25 | /*---------------------------------*/
26 |
27 | function SAEO_RTC() {
28 | const RTC_DEBUG = false;
29 |
30 | var clock_control_d = 0;
31 | var clock_control_e = 0;
32 | var clock_control_f = 0;
33 |
34 | const RF5C01A_RAM_SIZE = 16;
35 | var rtc_memory = null;
36 | var rtc_alarm = null;
37 |
38 | /*---------------------------------*/
39 |
40 | function localtime(t) {
41 | this.tm_sec = t.getSeconds(); //seconds [0,61]
42 | this.tm_min = t.getMinutes(); //minutes [0,59]
43 | this.tm_hour = t.getHours(); //hour [0,23]
44 | this.tm_mday = t.getDate(); //day of month [1,31]
45 | this.tm_mon = t.getMonth(); //month of year [0,11]
46 | this.tm_year = t.getFullYear() - 1900; //years since 1900
47 | this.tm_wday = t.getDay(); //day of week [0,6] (Sunday = 0)
48 | this.tm_yday = 0; //day of year [0,365]
49 | this.tm_isdst = false; //daylight savings flag
50 | }
51 |
52 | function getct() {
53 | var d = new Date();
54 | if (SAEV_config.chipset.rtc.adjust) {
55 | var n = d.valueOf();
56 | d.setTime(n + SAEV_config.chipset.rtc.adjust * 1000);
57 | }
58 | return new localtime(d);
59 | }
60 |
61 | /*---------------------------------*/
62 |
63 | function getclockreg(addr, ct) {
64 | var v = 0;
65 |
66 | if (SAEV_config.chipset.rtc.type == SAEC_Config_RTC_Type_MSM6242B || SAEV_config.chipset.rtc.type == SAEC_Config_RTC_Type_MSM6242B_A2000) { /* MSM6242B */
67 | switch (addr) {
68 | case 0x0: v = ct.tm_sec % 10; break;
69 | case 0x1: v = ct.tm_sec / 10 >>> 0; break;
70 | case 0x2: v = ct.tm_min % 10; break;
71 | case 0x3: v = ct.tm_min / 10 >>> 0; break;
72 | case 0x4: v = ct.tm_hour % 10; break;
73 | case 0x5: {
74 | if (clock_control_f & 4)
75 | v = ct.tm_hour / 10 >>> 0; /* 24h */
76 | else {
77 | v = (ct.tm_hour % 12) / 10 >>> 0; /* 12h */
78 | v |= ct.tm_hour >= 12 ? 4 : 0; /* AM/PM bit */
79 | }
80 | break;
81 | }
82 | case 0x6: v = ct.tm_mday % 10; break;
83 | case 0x7: v = ct.tm_mday / 10 >>> 0; break;
84 | case 0x8: v = (ct.tm_mon + 1) % 10; break;
85 | case 0x9: v = (ct.tm_mon + 1) / 10 >>> 0; break;
86 | case 0xA: v = ct.tm_year % 10; break;
87 | case 0xB: v = ((ct.tm_year / 10) >>> 0) & 0x0f; break;
88 | case 0xC: v = ct.tm_wday; break;
89 | case 0xD: v = clock_control_d; break;
90 | case 0xE: v = clock_control_e; break;
91 | case 0xF: v = clock_control_f; break;
92 | }
93 | } else if (SAEV_config.chipset.rtc.type == SAEC_Config_RTC_Type_RF5C01A) { /* RF5C01A */
94 | var bank = clock_control_d & 3;
95 | /* memory access */
96 | if (bank >= 2 && addr < 0x0d)
97 | return (rtc_memory[addr] >> ((bank == 2) ? 0 : 4)) & 0x0f;
98 | /* alarm */
99 | if (bank == 1 && addr < 0x0d) {
100 | v = rtc_alarm[addr];
101 | if (RTC_DEBUG) SAEF_log("rtc.get8(0x%X, ct) ALARM (0x%x)", addr, v);
102 | return v;
103 | }
104 | switch (addr) {
105 | case 0x0: v = ct.tm_sec % 10; break;
106 | case 0x1: v = ct.tm_sec / 10 >>> 0; break;
107 | case 0x2: v = ct.tm_min % 10; break;
108 | case 0x3: v = ct.tm_min / 10 >>> 0; break;
109 | case 0x4: v = ct.tm_hour % 10; break;
110 | case 0x5: {
111 | if (rtc_alarm[10] & 1)
112 | v = ct.tm_hour / 10 >>> 0; /* 24h */
113 | else {
114 | v = (ct.tm_hour % 12) / 10 >>> 0; /* 12h */
115 | v |= ct.tm_hour >= 12 ? 2 : 0; /* AM/PM bit */
116 | }
117 | break;
118 | }
119 | case 0x6: v = ct.tm_wday; break;
120 | case 0x7: v = ct.tm_mday % 10; break;
121 | case 0x8: v = ct.tm_mday / 10 >>> 0; break;
122 | case 0x9: v = (ct.tm_mon + 1) % 10; break;
123 | case 0xA: v = (ct.tm_mon + 1) / 10 >>> 0; break;
124 | case 0xB: v = (ct.tm_year % 100) % 10; break;
125 | case 0xC: v = (ct.tm_year % 100) / 10 >>> 0; break;
126 | case 0xD: v = clock_control_d; break;
127 | case 0xE: v = 0; break; //E and F = write-only, reads as zero
128 | case 0xF: v = 0; break;
129 | }
130 | }
131 | if (RTC_DEBUG) SAEF_log("rtc.get8(0x%X, ct) (0x%x)", addr, v);
132 | return v;
133 | }
134 |
135 | /*---------------------------------*/
136 |
137 | function read() { //read_battclock()
138 | //if (SAEV_config.chipset.rtc.file.length)
139 | {
140 | var f = null; //SAEF_ZFile_fopen(SAEV_config.chipset.rtc.file, "rb");
141 | if (f) {
142 | var data = new Uint8Array(16);
143 | SAEF_ZFile_fread(data,0, 16, 1, f);
144 | clock_control_d = data[13];
145 | clock_control_e = data[14];
146 | clock_control_f = data[15];
147 | if (SAEV_config.chipset.rtc.type == SAEC_Config_RTC_Type_RF5C01A) {
148 | SAEF_ZFile_fread(rtc_alarm,0, RF5C01A_RAM_SIZE, 1, f);
149 | SAEF_ZFile_fread(rtc_memory,0, RF5C01A_RAM_SIZE, 1, f);
150 | }
151 | SAEF_ZFile_fclose(f);
152 | }
153 | }
154 | }
155 | this.write = function() { //write_battclock() called from cia.vsync()
156 | if (SAEV_config.chipset.rtc.type != SAEC_Config_RTC_Type_None) {
157 | //if (SAEV_config.chipset.rtc.file.length)
158 | {
159 | var f = null; //SAEF_ZFile_fopen(SAEV_config.chipset.rtc.file, "wb");
160 | if (f) {
161 | var ct = getct();
162 | var data = new Uint8Array(16);
163 | var od = clock_control_d;
164 | if (SAEV_config.chipset.rtc.type == SAEC_Config_RTC_Type_RF5C01A)
165 | clock_control_d &= ~3;
166 | for (var i = 0; i < 13; i++)
167 | data[i] = getclockreg(i, ct);
168 | clock_control_d = od;
169 | data[i] = clock_control_d;
170 | data[i] = clock_control_e;
171 | data[i] = clock_control_f;
172 | SAEF_ZFile_fwrite(data,0, 16, 1, f);
173 | if (SAEV_config.chipset.rtc.type == SAEC_Config_RTC_Type_RF5C01A) {
174 | SAEF_ZFile_fwrite(rtc_alarm,0, RF5C01A_RAM_SIZE, 1, f);
175 | SAEF_ZFile_fwrite(rtc_memory,0, RF5C01A_RAM_SIZE, 1, f);
176 | }
177 | SAEF_ZFile_fclose(f);
178 | }
179 | }
180 | }
181 | }
182 |
183 | /*---------------------------------*/
184 |
185 | this.hardreset = function() { //rtc_hardreset()
186 | switch (SAEV_config.chipset.rtc.type) {
187 | case SAEC_Config_RTC_Type_None: type = "none"; break;
188 | case SAEC_Config_RTC_Type_MSM6242B: type = "MSM6242B"; break;
189 | case SAEC_Config_RTC_Type_RF5C01A: type = "RF5C01A"; break;
190 | case SAEC_Config_RTC_Type_MSM6242B_A2000: type = "MSM6242B A2000"; break;
191 | }
192 | SAEF_log("rtc.hardreset() type '%s'", type);
193 |
194 | SAEV_RTC_delayed_write = 0;
195 | if (SAEV_config.chipset.rtc.type == SAEC_Config_RTC_Type_MSM6242B || SAEV_config.chipset.rtc.type == SAEC_Config_RTC_Type_MSM6242B_A2000) { /* MSM6242B */
196 | clock_control_d = 0x1;
197 | clock_control_e = 0;
198 | clock_control_f = 0x4; /* 24/12 */
199 | rtc_memory = null;
200 | rtc_alarm = null;
201 | } else if (SAEV_config.chipset.rtc.type == SAEC_Config_RTC_Type_RF5C01A) { /* RF5C01A */
202 | clock_control_d = 0x8; /* Timer EN */
203 | clock_control_e = 0;
204 | clock_control_f = 0;
205 | rtc_memory = new Uint8Array(RF5C01A_RAM_SIZE);
206 | rtc_alarm = new Uint8Array(RF5C01A_RAM_SIZE);
207 | for (var i = 0; i < RF5C01A_RAM_SIZE; i++)
208 | rtc_memory[i] = rtc_alarm[i] = 0;
209 |
210 | rtc_alarm[10] = 1; /* 24H mode */
211 | }
212 | SAEV_RTC_bank.name = "Battery backed up clock ("+type+")";
213 | read();
214 | }
215 |
216 | /*---------------------------------*/
217 |
218 | function get32(addr) {
219 | if ((addr & 0xffff) >= 0x8000 && SAEV_config.chipset.fatGaryRev >= 0)
220 | return SAER.memory.dummyGet(addr, 4, false, 0);
221 |
222 | return ((get16(addr) << 16) | get16(addr + 2)) >>> 0;
223 | }
224 |
225 | function get16(addr) {
226 | if ((addr & 0xffff) >= 0x8000 && SAEV_config.chipset.fatGaryRev >= 0)
227 | return SAER.memory.dummyGet(addr, 2, false, 0);
228 |
229 | return (get8(addr) << 8) | get8(addr + 1);
230 | }
231 |
232 | function get8(addr) {
233 | if ((addr & 0xffff) >= 0x8000 && SAEV_config.chipset.fatGaryRev >= 0)
234 | return SAER.memory.dummyGet(addr, 1, false, 0);
235 | /*#ifdef CDTV
236 | if (currprefs.cs_cdtvram && (addr & 0xffff) >= 0x8000)
237 | return cdtv_battram_read(addr);
238 | #endif*/
239 |
240 | addr &= 0x3f;
241 | if ((addr & 3) == 2 || (addr & 3) == 0 || SAEV_config.chipset.rtc.type == SAEC_Config_RTC_Type_None)
242 | return SAER.memory.dummyGet(addr, 1, false, 0);
243 |
244 | var ct = getct();
245 | return getclockreg(addr >> 2, ct);
246 | }
247 |
248 | function put32(addr, value) {
249 | if ((addr & 0xffff) >= 0x8000 && SAEV_config.chipset.fatGaryRev >= 0) {
250 | SAER.memory.dummyPut(addr, 4, value);
251 | return;
252 | }
253 | put16(addr, value >>> 16);
254 | put16(addr + 2, value & 0xffff);
255 | }
256 |
257 | function put16(addr, value) {
258 | if ((addr & 0xffff) >= 0x8000 && SAEV_config.chipset.fatGaryRev >= 0) {
259 | SAER.memory.dummyPut(addr, 2, value);
260 | return;
261 | }
262 | put8(addr, value >> 8);
263 | put8(addr + 1, value & 0xff);
264 | }
265 |
266 | function put8(addr, value) {
267 | if ((addr & 0xffff) >= 0x8000 && SAEV_config.chipset.fatGaryRev >= 0) {
268 | SAER.memory.dummyPut(addr, 1, value);
269 | return;
270 | }
271 | /*#ifdef CDTV
272 | if (currprefs.cs_cdtvram && (addr & 0xffff) >= 0x8000) {
273 | cdtv_battram_write(addr, value);
274 | return;
275 | }
276 | #endif*/
277 |
278 | addr &= 0x3f;
279 | if ((addr & 1) != 1 || SAEV_config.chipset.rtc.type == SAEC_Config_RTC_Type_None)
280 | return;
281 | addr >>= 2;
282 | value &= 0x0f;
283 | if (SAEV_config.chipset.rtc.type == SAEC_Config_RTC_Type_MSM6242B || SAEV_config.chipset.rtc.type == SAEC_Config_RTC_Type_MSM6242B_A2000) { /* MSM6242B */
284 | if (RTC_DEBUG) SAEF_log("rtc.put8(0x%X, 0x%x)", addr, value);
285 | switch (addr) {
286 | case 0xD: clock_control_d = value & (1|8); break;
287 | case 0xE: clock_control_e = value; break;
288 | case 0xF: clock_control_f = value; break;
289 | }
290 | } else if (SAEV_config.chipset.rtc.type == SAEC_Config_RTC_Type_RF5C01A) { /* RF5C01A */
291 | var bank = clock_control_d & 3;
292 | /* memory access */
293 | if (bank >= 2 && addr < 0x0d) {
294 | var ov = rtc_memory[addr];
295 | rtc_memory[addr] &= ((bank == 2) ? 0xf0 : 0x0f);
296 | rtc_memory[addr] |= value << ((bank == 2) ? 0 : 4);
297 | if (rtc_memory[addr] != ov) SAEV_RTC_delayed_write = -1;
298 | return;
299 | }
300 | /* alarm */
301 | if (bank == 1 && addr < 0x0d) {
302 | if (RTC_DEBUG) SAEF_log("rtc.put8(0x%X, 0x%x) ALARM", addr, value);
303 | var ov = rtc_alarm[addr];
304 | rtc_alarm[addr] = value;
305 | rtc_alarm[0] = rtc_alarm[1] = rtc_alarm[9] = rtc_alarm[12] = 0;
306 | rtc_alarm[3] &= ~0x8;
307 | rtc_alarm[5] &= ~0xc;
308 | rtc_alarm[6] &= ~0x8;
309 | rtc_alarm[8] &= ~0xc;
310 | rtc_alarm[10] &= ~0xe;
311 | rtc_alarm[11] &= ~0xc;
312 | if (rtc_alarm[addr] != ov) SAEV_RTC_delayed_write = -1;
313 | return;
314 | }
315 | if (RTC_DEBUG) SAEF_log("rtc.put8(0x%X, 0x%x)", addr, value);
316 | switch (addr) {
317 | case 0xD: clock_control_d = value; break;
318 | case 0xE: clock_control_e = value; break;
319 | case 0xF: clock_control_f = value; break;
320 | }
321 | }
322 | SAEV_RTC_delayed_write = -1;
323 | }
324 |
325 | SAEV_RTC_bank = new SAEO_Memory_addrbank(
326 | get32, get16, get8,
327 | put32, put16, put8,
328 | SAEF_Memory_defaultXLate, SAEF_Memory_defaultCheck, null, null, "Battery backed up clock (none)",
329 | SAEF_Memory_dummyGetInst32, SAEF_Memory_dummyGetInst16,
330 | //SAEC_Memory_addrbank_flag_IO, S_READ, S_WRITE, null, 0x3f, 0xd80000
331 | SAEC_Memory_addrbank_flag_IO, null, 0x3f, 0xd80000
332 | );
333 | }
334 |
--------------------------------------------------------------------------------
/sae/serpar.js:
--------------------------------------------------------------------------------
1 | /*-------------------------------------------------------------------------
2 | | SAE - Scripted Amiga Emulator
3 | | https://github.com/naTmeg/ScriptedAmigaEmulator
4 | |
5 | | Copyright (C) 2012 Rupert Hausberger
6 | |
7 | | This program is free software; you can redistribute it and/or
8 | | modify it under the terms of the GNU General Public License
9 | | as published by the Free Software Foundation; either version 2
10 | | of the License, or (at your option) any later version.
11 | |
12 | | This program is distributed in the hope that it will be useful,
13 | | but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | | GNU General Public License for more details.
16 | |
17 | | Note: ported from WinUAE 3.2.x
18 | -------------------------------------------------------------------------*/
19 |
20 | function SAEO_Serial() {
21 | const DEBUGIO = 0; /* 0-3 */
22 | const DEBUGHS = 0; /* 0-2 */
23 |
24 | var data_in_serdat = 0; /* new data written to SERDAT */
25 | var data_in_serdatr = 0; /* new data received */
26 | var data_in_sershift = 0; /* data transferred from SERDAT to shift register */
27 | var serdatshift = 0; //u16 /* serial shift register */
28 | var serdatshift_masked = 0; //u16 /* stop bit masked */
29 | var ovrun = false;
30 | var dtr = false;
31 | var oldserbits = 0; //u8
32 |
33 | var serper = 0, serdat = 0, serdatr = 0; //u16
34 |
35 | /*---------------------------------*/
36 |
37 | function dochar(v) {
38 | v &= 0xff;
39 | if (v >= 32 && v < 127)
40 | return v;
41 | return 46; //'.'
42 | }
43 |
44 | /*---------------------------------*/
45 |
46 | function serdatcopy() {
47 | if (data_in_sershift || !data_in_serdat)
48 | return;
49 | serdatshift = serdat;
50 | var bits = ((serdatshift & 0xff80) == 0x80) ? 8 : 7;
51 | serdatshift_masked = serdatshift & ((1 << bits) - 1);
52 | data_in_sershift = 1;
53 | data_in_serdat = 0;
54 |
55 | SAEV_config.hook.serial.put(serdatshift_masked);
56 |
57 | SAER.custom.INTREQ(SAEC_Custom_INTF_SETCLR | SAEC_Custom_INTF_TBE);
58 | }
59 |
60 | this.hsync = function() { //serial_hsynchandler()
61 | if (!data_in_serdatr) {
62 | var ch = SAEV_config.hook.serial.get();
63 | if (ch > 0) {
64 | ch &= 0xff; //OWN
65 | serdatr = ch | 0x100;
66 | data_in_serdatr = 1;
67 | this.check_irq();
68 | }
69 | }
70 |
71 | //if (!first_write) return;
72 |
73 | if (data_in_sershift) {
74 | data_in_sershift = 0;
75 | serdatcopy();
76 | }
77 | }
78 |
79 | this.rbf_clear = function() { //serial_rbf_clear()
80 | ovrun = false;
81 | }
82 |
83 | this.check_irq = function() { //serial_check_irq()
84 | if (data_in_serdatr)
85 | SAER.custom.INTREQ_0(SAEC_Custom_INTF_SETCLR | SAEC_Custom_INTF_RBF);
86 | }
87 |
88 | /*this.uartbreak = function(v) { //serial_uartbreak()
89 | }*/
90 |
91 | /*---------------------------------*/
92 | /* CIA access */
93 |
94 | function status_debug(s) {
95 | SAEF_log("%s DTR=%d RTS=%d CD=%d CTS=%d DSR=%d", s,
96 | (oldserbits & 0x80) ? 0 : 1, (oldserbits & 0x40) ? 0 : 1,
97 | (oldserbits & 0x20) ? 0 : 1, (oldserbits & 0x10) ? 0 : 1, (oldserbits & 0x08) ? 0 : 1);
98 | }
99 |
100 | this.dtr_on = function() { //serial_dtr_on()
101 | if (DEBUGHS > 0) SAEF_log("serial.writestatus() DTR on");
102 | dtr = true;
103 | }
104 |
105 | this.dtr_off = function() { //serial_dtr_off()
106 | if (DEBUGHS > 0) SAEF_log("serial.writestatus() DTR off");
107 | dtr = false;
108 | }
109 |
110 | this.readstatus = function(dir) { //serial_readstatus()
111 | var status = 0;
112 | var serbits = oldserbits; //u8
113 |
114 | /*getserstat (&status);
115 | if (!(status & TIOCM_CAR)) {
116 | if (!(serbits & 0x20)) {
117 | serbits |= 0x20;
118 | if (DEBUGHS > 0) SAEF_log("serial.readstatus() CD off");
119 | }
120 | } else {
121 | if (serbits & 0x20) {
122 | serbits &= ~0x20;
123 | if (DEBUGHS > 0) SAEF_log("serial.readstatus() CD on");
124 | }
125 | }
126 | if (!(status & TIOCM_DSR)) {
127 | if (!(serbits & 0x08)) {
128 | serbits |= 0x08;
129 | if (DEBUGHS > 0) SAEF_log("serial.readstatus() DSR off");
130 | }
131 | } else {
132 | if (serbits & 0x08) {
133 | serbits &= ~0x08;
134 | if (DEBUGHS > 0) SAEF_log("serial.readstatus() DSR on");
135 | }
136 | }
137 | if (!(status & TIOCM_CTS)) {
138 | if (!(serbits & 0x10)) {
139 | serbits |= 0x10;
140 | if (DEBUGHS > 0) SAEF_log("serial.readstatus() CTS off");
141 | }
142 | } else {
143 | if (serbits & 0x10) {
144 | serbits &= ~0x10;
145 | if (DEBUGHS > 0) SAEF_log("serial.readstatus() CTS on");
146 | }
147 | }*/
148 |
149 | serbits &= 0x08 | 0x10 | 0x20;
150 | oldserbits &= ~(0x08 | 0x10 | 0x20);
151 | oldserbits |= serbits;
152 |
153 | if (DEBUGHS > 1) status_debug("serial.readstatus()");
154 | return oldserbits;
155 | }
156 |
157 | this.writestatus = function(newstate, dir) { //serial_writestatus()
158 | oldserbits &= ~(0x80 | 0x40);
159 | newstate &= 0x80 | 0x40;
160 | oldserbits |= newstate;
161 |
162 | if (DEBUGHS > 1) status_debug("serial.writestatus()");
163 | return oldserbits;
164 | }
165 |
166 | /*---------------------------------*/
167 |
168 | this.SERPER = function(w) {
169 | if (!SAEV_config.serial.enabled)
170 | return;
171 | if (serper == w) /* don't set baudrate if it's already ok */
172 | return;
173 |
174 | serper = w;
175 | //first_write = 1;
176 |
177 | if (DEBUGIO > 1) {
178 | const allowed_baudrates = [
179 | 0, 110, 300, 600, 1200, 2400, 4800, 9600, 14400,
180 | 19200, 31400, 38400, 57600, 115200, 128000, 256000, -1
181 | ];
182 | var ninebit = (w & 0x8000) != 0;
183 | w &= 0x7fff;
184 | if (w < 13) w = 13;
185 | var per = w;
186 | if (per == 0) per = 1;
187 | //per = 3546895 / (per + 1);
188 | per = ((SAEV_config.video.ntsc ? SAEC_Playfield_CLOCK_NTSC : SAEC_Playfield_CLOCK_PAL) / (per + 1)) >>> 0; //OWN
189 | if (per == 0) per = 1;
190 | var i = 0;
191 | while (allowed_baudrates[i] >= 0 && per > (allowed_baudrates[i] * 100 / 97) >>> 0) i++;
192 | var baud = allowed_baudrates[i];
193 | SAEF_log("serial.SERPER() period=%d, baud=%d, bits=%d", w, baud, ninebit ? 9 : 8);
194 | }
195 | }
196 |
197 | this.SERDAT = function(w) {
198 | if (!SAEV_config.serial.enabled)
199 | return;
200 | if (DEBUGIO > 2) SAEF_log("serial.SERDAT() write 0x%04x (%c)", w, dochar(w));
201 |
202 | serdatcopy();
203 |
204 | serdat = w;
205 |
206 | if (!w) {
207 | if (DEBUGIO > 1) SAEF_log("serial.SERDAT() zero serial word written?!");
208 | return;
209 | }
210 | if (DEBUGIO > 1 && data_in_serdat) SAEF_log("serial.SERDAT() program wrote to SERDAT but old byte wasn't fetched yet");
211 |
212 | data_in_serdat = 1;
213 | serdatcopy();
214 | }
215 |
216 | this.SERDATR = function() {
217 | if (!SAEV_config.serial.enabled)
218 | return 0x2000;
219 |
220 | serdatr &= 0x03ff;
221 | if (!data_in_serdat)
222 | serdatr |= 0x2000;
223 | if (!data_in_sershift)
224 | serdatr |= 0x1000;
225 | if (data_in_serdatr)
226 | serdatr |= 0x4000;
227 | if (ovrun)
228 | serdatr |= 0x8000;
229 |
230 | if (DEBUGIO > 2) SAEF_log("serial.SERDATR() read 0x%04x (%c)", serdatr, dochar(serdatr));
231 |
232 | data_in_serdatr = 0;
233 | return serdatr;
234 | }
235 |
236 | /*---------------------------------*/
237 |
238 | /*this.setup = function() { //serial_init()
239 | }*/
240 |
241 | this.cleanup = function() { //serial_exit()
242 | dtr = false;
243 | oldserbits = 0;
244 | }
245 | }
246 |
247 | function SAEO_Parallel() {
248 | const DEBUGIO = 0; /* 0-1 */
249 | const DEBUGHS = 0; /* 0-1 */
250 |
251 | var status = 4; /* SEL */
252 |
253 | /*---------------------------------*/
254 | /* direct */
255 |
256 | this.direct_write_status = function(v, dir) {
257 | if (DEBUGHS) SAEF_log("parallel.WS(%02x, %02x)", v, dir);
258 |
259 | //status = 0; if ((dir & 4) && !(v & 4)) status = 4;
260 | SAER.cia.parallelack();
261 | }
262 |
263 | this.direct_read_status = function() {
264 | if (DEBUGHS) SAEF_log("parallel.RS() %02x", status);
265 |
266 | SAER.cia.parallelack();
267 | return status;
268 | }
269 |
270 | this.direct_write_data = function(v, dir) {
271 | if (DEBUGIO) SAEF_log("parallel.WD(%02x, %02x)", v, dir);
272 |
273 | SAEV_config.hook.parallel.put(v);
274 | SAER.cia.parallelack();
275 | }
276 |
277 | this.direct_read_data = function() {
278 | var v = SAEV_config.hook.parallel.get() & 0xff;
279 | SAER.cia.parallelack();
280 |
281 | if (DEBUGIO) SAEF_log("parallel.RD() %02x", v);
282 | return v;
283 | }
284 |
285 | /*---------------------------------*/
286 | /* printer */
287 |
288 | /*this.doprinter = function() {}*/
289 |
290 | /*---------------------------------*/
291 |
292 | /*this.isprinter = function() {
293 | If enabled parport-joystick can not work, but parport-joystick is not enabled anyway.
294 | 0 = disabled, -1 = direct, 1 = printer
295 | return -1;
296 | }*/
297 |
298 | /*---------------------------------*/
299 |
300 | /*this.reset = function() { //initparallel()
301 | }*/
302 | }
303 |
--------------------------------------------------------------------------------