diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..fd95825 --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +node_modules/ +*.log +verify/ +.temp/ +verify_ui.py diff --git a/README.md b/README.md index afe7cc7..41140d8 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,43 @@ -jswqx -===== +# js版文曲星nc1020模拟器 v3.0 -文曲星模拟器 (NC1020) +## 网页版文曲星nc1020[模拟器](https://leoncoolmoon.github.io/jswqx/)
-orginal: http://bbs.emsky.net/viewthread.php?tid=33474 +基于 JavaScript 的文曲星 NC1020 模拟器,从原基础上修改增加了现代化的图形界面。 -demo: http://hackwaly.com/jswqx/ +![screenshot](./nc1020.png) -![感谢@fouber提供的演示图片](http://ww4.sinaimg.cn/large/6767ed9agw1evhjy1jivig20c109rk4t.gif) +### 🌟 3.0 版本新特性 +- **自动同步时间**: 模拟器启动及从后台切回前台时,自动同步系统真实时间与日期。 +- **PWA 增强**: 完善的 Service Worker 缓存机制,支持离线使用,可作为独立应用安装。 +- **UI 细节优化**: 进一步优化的界面响应速度与显示效果。 + +### 🚀 功能特点 +- **高度还原的 UI**: 精心设计的硬件外壳界面,支持硬件精度的 LCD 指示器(三角标)。 +- **移动端优化**: 自适应布局,支持触摸屏操作,横屏模式自动优化。 +- **持久化存储**: 自动保存整个机器状态(含 RAM/NOR Flash/CPU 寄存器)到浏览器 `localStorage`,确保进度永不丢失。 +- **多主题支持**: 内置深色和浅色模式,并可随系统自动切换。 +- **全屏模式**: 支持全屏体验,在桌面端可单独全屏 LCD 显示区域。 +- **高性能**: 优化的 6502 CPU 仿真和 LCD 渲染。 + +### 📜 历史与致谢 +- **Original**: http://bbs.emsky.net/viewthread.php?tid=33474 +- **2018.09.11** Dr.Quest 优化版:压缩 ROM 到 10M ZIP 文件,添加了手机触摸屏支持。 +- **2023.12.24** leoncoolmoon 修改了 UI,增加 Ctrl 为跳出键。 +- **2026.05.17** leoncoolmoon 修复了 Flash 存储,可以在浏览器内永久化保存。 +- **2026.05.19** 升级为 PWA,支持离线访问,移除对本地 Python 服务器的依赖。 +- **2026.05.21** 升级为 3.0 版本,支持自动同步时间,全面优化存储与 PWA 逻辑。 + +### 📖 使用说明 +1. 直接在支持现代 Web 标准的浏览器中打开 `index.html` 即可。 +2. 建议通过 Web 服务器访问(如 GitHub Pages)以获得完整的 PWA 离线体验。 +3. **快捷键说明**: + - **F1-F12**: 对应机器功能键 + - **Enter**: 确认 / 执行 + - **Esc / Ctrl**: 跳出 / 退出 + - **方向键**: 移动光标 + - **字母 A-Z**: 拼音/英文字符输入 + - **数字 1-9**: 数字输入 + - **空格**: 等号 (=) + - **退格**: F2 键 + +目前已在 Chrome 和 iOS Safari 上进行过完美测试。 diff --git a/_config.yml b/_config.yml new file mode 100644 index 0000000..c419263 --- /dev/null +++ b/_config.yml @@ -0,0 +1 @@ +theme: jekyll-theme-cayman \ No newline at end of file diff --git a/favicon.ico b/favicon.ico new file mode 100644 index 0000000..b6782d4 Binary files /dev/null and b/favicon.ico differ diff --git a/icon-192.png b/icon-192.png new file mode 100644 index 0000000..b6782d4 Binary files /dev/null and b/icon-192.png differ diff --git a/icon-512.png b/icon-512.png new file mode 100644 index 0000000..4ae7357 Binary files /dev/null and b/icon-512.png differ diff --git a/index.html b/index.html index 57de7b5..04ec2b2 100644 --- a/index.html +++ b/index.html @@ -1,293 +1,1002 @@ + - - 文曲星模拟器 + + + + + + 文曲星模拟器 - NC1020 + - - -

文曲星模拟器

- - - - -
-
-
- - -
-
-
-
Dict
-
Card
-
Calc
-
Rem
-
Data
-
Time
-
Net
-
-
-
-
F1
-
F2
-
F3
-
F4
-
Power
-
+ + + + + + +
+
+
+

Settings

+
-
-
Q
-
W
-
E
-
R
-
T
-
Y
-
U
-
I
-
O
-
P
+
+

Emulator Controls

+
+ + + +
Initializing...
+
-
-
A
-
S
-
D
-
F
-
G
-
H
-
J
-
K
-
L
-
Enter
+ +
+

Display Settings

+
+ + + +
+ + +
-
-
Z
-
X
-
C
-
V
-
B
-
N
-
M
-
PgUp
-
Up
-
PgDn
+ +
+

Keyboard Shortcuts

+
+
F1-F12: Function Keys
+
Enter: Confirm / OK
+
Esc / Ctrl: Back / Exit
+
Arrows: Navigation
+
PageUp / PageDown: Page Navigation
+
A-Z: Alpha Input
+
1-9: Numeric Keys
+
Backspace: F2 Key
+
Tab: Help
+
Shift: Shift Modifier
+
Space: Equals (=)
+
-
-
Help
-
Shift
-
Caps
-
Esc
-
0
-
.
-
=
-
Left
-
Down
-
Right
+ +

+ Fully opensource@github
+ NC1020 Emulator v2.0
+ Persistent Storage Enabled
+ 支持 PWA 离线使用
+ ROM文件下载地址
+

+
+ +

文曲星模拟器

+ +
+
+
+
+
+
+
+
-
-

- orginal: http://bbs.emsky.net/viewthread.php?tid=33474
- 目前只在chrome浏览器测试过,别的浏览器应该也有能跑的。
- 由于ROM文件有24M之大,若加载过慢,请自行下载到硬盘上,拖拽到模拟器的屏幕区域手动加载。
- 若想要离线使用能正常加载,请在chrome启动参数中加入`--allow-file-access-from-files`。
- ROM文件下载地址
-

- - + return true; + } + + function saveAppState(wqxInstance) { + // ★ 修复:未就绪时不保存,防止写入坏状态覆盖好存档 + if (!isStateReadyToSave(wqxInstance)) return false; + try { + var state = wqxInstance.saveState(); + localStorage.setItem(STATE_STORAGE_KEY, JSON.stringify(state)); + setFlashStatus('💾 Auto-saved'); + return true; + } catch (e) { + setFlashStatus('⚠️ Save failed: ' + e.message); + return false; + } + } + + function loadAppState(wqxInstance) { + try { + var stored = localStorage.getItem(STATE_STORAGE_KEY); + if (!stored) return false; + var state = JSON.parse(stored); + // ★ 修复:存档里的 lcdbuffaddr 必须合法才允许恢复 + if (!state || state.lcdbuffaddr === null || state.lcdbuffaddr === undefined || state.lcdbuffaddr <= 0x100) { + log('⚠️ 存档 lcdbuffaddr 不合法(值=' + (state && state.lcdbuffaddr) + '),丢弃存档'); + localStorage.removeItem(STATE_STORAGE_KEY); + return false; + } + wqxInstance.loadState(state); + setFlashStatus('✅ Restored'); + return true; + } catch (e) { + log('loadAppState error: ' + e); + return false; + } + } + + function clearSavedState() { + localStorage.removeItem(STATE_STORAGE_KEY); + setFlashStatus('🗑️ Cleared'); + setTimeout(() => location.reload(), 500); + } + + (function () { + var btn = document.getElementById('reset'); + var holdTimer = null; + var HOLD_MS = 2000; + + function startHold() { + btn.classList.add('pressing'); + holdTimer = setTimeout(function () { clearSavedState(); }, HOLD_MS); + } + + function endHold() { + if (holdTimer !== null) { + clearTimeout(holdTimer); + holdTimer = null; + if (btn.classList.contains('pressing')) reset(); + } + btn.classList.remove('pressing'); + } + + btn.addEventListener('mousedown', startHold); + btn.addEventListener('mouseup', endHold); + btn.addEventListener('mouseleave', endHold); + btn.addEventListener('touchstart', function(e){ e.preventDefault(); startHold(); }); + btn.addEventListener('touchend', function(e){ e.preventDefault(); endHold(); }); + })(); + + function log(msg, color) { + console.log(msg); + var logEl = document.getElementById('debug-log'); + if (logEl) { + if (color === '#f00') logEl.style.display = 'block'; + var div = document.createElement('div'); + div.style.color = color || '#0f0'; + div.textContent = '[' + new Date().toLocaleTimeString() + '] ' + msg; + logEl.appendChild(div); + logEl.scrollTop = logEl.scrollHeight; + } + } + + window.onerror = function(msg, url, line, col, error) { + log('ERR: ' + msg + ' (' + line + ':' + col + ')', '#f00'); + return false; + }; + window.onunhandledrejection = function(event) { + log('PROMISE ERR: ' + event.reason, '#f00'); + }; + + function setFlashStatus(msg) { + log(msg); + var el = document.getElementById('flash_status'); + if (el) el.textContent = msg; + } + + // ============================================================ + // Device UI Rendering & Interaction + // ============================================================ + var canvas = document.getElementById('key'); + var ctx = canvas.getContext('2d'); + var image = new Image(); + var indicatorStates = new Array(9).fill(false); + var rulerCenters = [66.4, 98.6, 131.3, 163.8, 195.5, 227.5, 260.1, 292.2, 324.9]; + var indicatorY = 177.5; + + function redrawFrame() { + if (!image.complete) return; + ctx.clearRect(0, 0, canvas.width, canvas.height); + ctx.globalCompositeOperation = 'source-over'; + ctx.drawImage(image, 0, 0); + ctx.globalCompositeOperation = 'destination-out'; + ctx.fillRect(15, 14, 376, 163); + ctx.globalCompositeOperation = 'source-over'; + for (var i = 0; i < indicatorStates.length; i++) { + if (indicatorStates[i]) renderIndicator(i); + } + } + + image.onload = function () { redrawFrame(); updateLayout(); }; + image.src = 'nc1020.png'; + + function renderIndicator(index) { + var x = rulerCenters[index]; + var y = indicatorY; + ctx.fillStyle = "rgba(0, 0, 0, 0.85)"; + ctx.beginPath(); + ctx.moveTo(x - 4, y); + ctx.lineTo(x + 4, y); + ctx.lineTo(x, y + 5); + ctx.fill(); + } + + function drawIndicator(index, active) { + if (indicatorStates[index] === active) return; + indicatorStates[index] = active; + if (!image.complete) return; + if (active) { + renderIndicator(index); + } else { + ctx.drawImage(image, rulerCenters[index] - 5, 177, 10, 10, rulerCenters[index] - 5, 177, 10, 10); + } + } + + function updateLayout() { + var device = document.getElementById('device'); + var isFullscreen = document.body.classList.contains('fullscreen'); + var h1 = document.querySelector('h1'); + var h1Height = (h1 && h1.offsetParent && !isFullscreen) ? h1.offsetHeight + 20 : 0; + var availableWidth = window.innerWidth - (isFullscreen ? 0 : 40); + var availableHeight = window.innerHeight - h1Height - (isFullscreen ? 0 : 40); + var s = Math.min(availableWidth / 434, availableHeight / 543); + s = Math.max(0.2, Math.min(s, isFullscreen ? 2.5 : 1.5)); + device.style.transform = "scale(" + s + ")"; + } + + window.addEventListener('resize', updateLayout); + + function hasPhysicalKeyboard() { + return window.matchMedia('(hover: hover)').matches && window.matchMedia('(pointer: fine)').matches; + } + + async function toggleFullscreen() { + if (!document.fullscreenElement) { + try { + const target = hasPhysicalKeyboard() ? document.getElementById('outScr') : document.documentElement; + await target.requestFullscreen(); + } catch (err) { console.error('无法进入全屏:', err.message); } + } else { + try { await document.exitFullscreen(); } + catch (err) { console.error('无法退出全屏:', err.message); } + } + } + + function updateScrLayout() { + var outScr = document.getElementById('outScr'); + var scr = document.getElementById('scr'); + var isFullscreen = !!document.fullscreenElement; + if (isFullscreen) { + document.body.classList.add('fullscreen'); + if (document.fullscreenElement === outScr) { + var s = Math.min(window.innerWidth / 320, window.innerHeight / 160); + scr.style.transform = "scale(" + s + ")"; + } else { + updateLayout(); + } + } else { + document.body.classList.remove('fullscreen'); + scr.style.transform = "scale(1)"; + updateLayout(); + } + } + + document.addEventListener('fullscreenchange', updateScrLayout); + + var keys = [ + { name: 'F1', x: 403, y: 10, width: 28, height: 30 }, + { name: 'F2', x: 403, y: 45, width: 28, height: 30 }, + { name: 'F3', x: 403, y: 80, width: 28, height: 30 }, + { name: 'F4', x: 403, y: 115, width: 28, height: 30 }, + { name: 'F12', x: 400, y: 190, width: 32, height: 32 }, + { name: 'Reset', x: 105, y: 390, width: 10, height: 10 }, + { name: 'F8', x: 131, y: 370, width: 43, height: 35 }, + { name: 'F9', x: 174, y: 370, width: 43, height: 35 }, + { name: 'F10', x: 217, y: 370, width: 43, height: 35 }, + { name: 'F7', x: 260, y: 370, width: 43, height: 35 }, + { name: 'F6', x: 303, y: 370, width: 43, height: 35 }, + { name: 'F5', x: 346, y: 370, width: 43, height: 35 }, + { name: 'F11', x: 389, y: 370, width: 43, height: 35 }, + { name: 'Q', x: 2, y: 407, width: 43, height: 32 }, + { name: 'W', x: 45, y: 407, width: 43, height: 32 }, + { name: 'E', x: 88, y: 407, width: 43, height: 32 }, + { name: 'R', x: 131, y: 407, width: 43, height: 32 }, + { name: 'T', x: 174, y: 407, width: 43, height: 32 }, + { name: 'Y', x: 217, y: 407, width: 43, height: 32 }, + { name: 'U', x: 260, y: 407, width: 43, height: 32 }, + { name: 'I', x: 303, y: 407, width: 43, height: 32 }, + { name: 'O', x: 346, y: 407, width: 43, height: 32 }, + { name: 'P', x: 389, y: 407, width: 43, height: 32 }, + { name: 'A', x: 2, y: 441, width: 43, height: 32 }, + { name: 'S', x: 45, y: 441, width: 43, height: 32 }, + { name: 'D', x: 88, y: 441, width: 43, height: 32 }, + { name: 'F', x: 131, y: 441, width: 43, height: 32 }, + { name: 'G', x: 174, y: 441, width: 43, height: 32 }, + { name: 'H', x: 217, y: 441, width: 43, height: 32 }, + { name: 'J', x: 260, y: 441, width: 43, height: 32 }, + { name: 'K', x: 303, y: 441, width: 43, height: 32 }, + { name: 'L', x: 346, y: 441, width: 43, height: 32 }, + { name: 'Enter', x: 389, y: 441, width: 43, height: 32 }, + { name: 'Z', x: 2, y: 476, width: 43, height: 32 }, + { name: 'X', x: 45, y: 476, width: 43, height: 32 }, + { name: 'C', x: 88, y: 476, width: 43, height: 32 }, + { name: 'V', x: 131, y: 476, width: 43, height: 32 }, + { name: 'B', x: 174, y: 476, width: 43, height: 32 }, + { name: 'N', x: 217, y: 476, width: 43, height: 32 }, + { name: 'M', x: 260, y: 476, width: 43, height: 32 }, + { name: 'PgUp', x: 303, y: 476, width: 43, height: 32 }, + { name: 'Up', x: 346, y: 476, width: 43, height: 32 }, + { name: 'PgDn', x: 389, y: 476, width: 43, height: 32 }, + { name: 'Tab', x: 2, y: 510, width: 43, height: 32 }, + { name: 'Shift', x: 45, y: 510, width: 43, height: 32 }, + { name: 'CapsLock', x: 88, y: 510, width: 43, height: 32 }, + { name: 'Esc', x: 131, y: 510, width: 43, height: 32 }, + { name: '0', x: 174, y: 510, width: 43, height: 32 }, + { name: 'Period', x: 217, y: 510, width: 43, height: 32 }, + { name: 'Equals', x: 260, y: 510, width: 43, height: 32 }, + { name: 'Left', x: 303, y: 510, width: 43, height: 32 }, + { name: 'Down', x: 346, y: 510, width: 43, height: 32 }, + { name: 'Right', x: 389, y: 510, width: 43, height: 32 }, + ]; + + function handleMouseEvent(e, isDown) { + var rect = canvas.getBoundingClientRect(); + var s = rect.width / 434; + var x = (e.clientX - rect.left) / s; + var y = (e.clientY - rect.top) / s; + keyAction(getKeyAt(x, y), isDown); + } + + canvas.addEventListener('mousedown', function(e) { handleMouseEvent(e, true); }); + canvas.addEventListener('mouseup', function(e) { handleMouseEvent(e, false); }); + canvas.addEventListener('mouseleave', function(e) { handleMouseEvent(e, false); }); + canvas.addEventListener('touchstart', function(e) { + e.preventDefault(); + var rect = canvas.getBoundingClientRect(); + var s = rect.width / 434; + keyAction(getKeyAt((e.touches[0].clientX - rect.left) / s, (e.touches[0].clientY - rect.top) / s), true); + }, {passive: false}); + canvas.addEventListener('touchend', function(e) { + e.preventDefault(); + var rect = canvas.getBoundingClientRect(); + var s = rect.width / 434; + keyAction(getKeyAt((e.changedTouches[0].clientX - rect.left) / s, (e.changedTouches[0].clientY - rect.top) / s), false); + }, {passive: false}); + + function getKeyAt(x, y) { + for (var i = 0; i < keys.length; i++) { + if (keys[i].x <= x && x <= keys[i].x + keys[i].width && + keys[i].y <= y && y <= keys[i].y + keys[i].height) { + return keys[i].name; + } + } + return null; + } + + function keyAction(name, isDown) { + if (name != null) { + if (isDown) { + keyInput.keyDown(name); + } else { + if (name === "Reset") reset(); + else keyInput.keyUp(name); + } + } + } + + // ============================================================ + // Emulator Lifecycle + // ============================================================ + var wqxDiv = document.getElementById('lcd'); + var wqx = new Wqx(wqxDiv); + var keyInput = new WqxKeyInput(wqx, document.body); + + // ★ 修复:monkey-patch updateLCD 时先检查 lcdbuffaddr 是否合法 + var _origUpdateLCD = wqx.updateLCD.bind(wqx); + wqx.updateLCD = function(addr, value) { + // lcdbuffaddr 未就绪时直接跳过,避免 NaN 计算 + if (!this.lcdbuffaddr || this.lcdbuffaddr <= 0x100) return; + var offset = addr - this.lcdbuffaddr; + if (offset < 0 || offset >= 1600) return; + var row = Math.floor(offset / 20); + var col = offset % 20; + if (col === 0) { + var active = (value & 0x80) !== 0; + if (row >= 64 && row <= 72) { + drawIndicator(row - 64, active); + } + } + _origUpdateLCD(addr, value); + }; + + // FLS 拖放更新 + document.addEventListener('dragover', function(e) { e.preventDefault(); }); + document.addEventListener('drop', function(e) { + e.preventDefault(); + var file = e.dataTransfer.files[0]; + if (!file || !file.name.endsWith('.fls')) return; + var reader = new FileReader(); + reader.onload = function(ev) { + wqx.loadNorFlash(ev.target.result); + saveAppState(wqx); + setFlashStatus('💾 已加载 ' + file.name); + }; + reader.readAsArrayBuffer(file); + }); + + var romLoaded = false; + var norLoaded = false; + var _stateRestored = false; + + function check() { + if (!romLoaded || !norLoaded) return; + if (_stateRestored) { + wqx.syncCalendar(); + wqx.startFrame(); + setTimeout(() => { wqx.syncClock(); log('Delayed clock sync completed'); }, 2000); + } else { + wqx.run(); + wqx.syncCalendar(); + } + document.getElementById('run').disabled = true; + document.getElementById('stop').disabled = false; + } + + function loadZip() { + log('Loading rom.zip...'); + var xhrZip = new XMLHttpRequest(); + xhrZip.open('GET', 'rom.zip', true); + xhrZip.responseType = 'arraybuffer'; + xhrZip.onload = function() { + if (xhrZip.status === 200) { + log('rom.zip loaded, mounting BFS...'); + mountBFS(xhrZip.response); + } else { + setFlashStatus('❌ ROM Load Error: ' + xhrZip.status); + } + }; + xhrZip.onerror = function() { setFlashStatus('❌ Network Error'); }; + xhrZip.send(); + } + + function mountBFS(zipData) { + try { + var Buffer = BrowserFS.BFSRequire('buffer').Buffer; + BrowserFS.configure({ fs: "ZipFS", options: { zipData: Buffer.from(zipData) } }, function(e) { + if (e) { setFlashStatus('❌ FS Error: ' + e); return; } + log('BFS configured, reading files...'); + var fs = BrowserFS.BFSRequire('fs'); + fs.readFile('/obj_lu.bin', function(err, data) { + if (err) { setFlashStatus('❌ Missing obj_lu.bin'); return; } + log('obj_lu.bin loaded'); + wqx.loadBROM(data); + romLoaded = true; + + // ★ 修复:ROM加载完成后再检查存档,保证 volume array 已就绪 + if (loadAppState(wqx)) { + log('State restored from storage'); + norLoaded = true; + _stateRestored = true; + check(); + } else { + log('No valid saved state, reading nc1020.fls...'); + fs.readFile('/nc1020.fls', function(err, data) { + if (err) { setFlashStatus('❌ Missing nc1020.fls'); return; } + log('nc1020.fls loaded'); + wqx.loadNorFlash(data); + norLoaded = true; + _stateRestored = false; + check(); + }); + } + }); + }); + } catch (err) { + log('BFS Exception: ' + err); + } + } + + function run() { + wqx.run(); + document.getElementById('run').disabled = true; + document.getElementById('stop').disabled = false; + } + function stop() { + wqx.stop(); + document.getElementById('stop').disabled = true; + document.getElementById('run').disabled = false; + } + function reset() { wqx.reset(); } + + window.addEventListener('load', function() { + log('App started, initializing...'); + try { loadZip(); } + catch(e) { log('Fatal initialization error: ' + e, '#f00'); } + + window.addEventListener('pagehide', function() { + if (wqx) saveAppState(wqx); + }); + document.addEventListener('visibilitychange', function() { + if (document.visibilityState === 'hidden' && wqx) saveAppState(wqx); + }); + + if ('serviceWorker' in navigator) { + var refreshing = false; + navigator.serviceWorker.addEventListener('controllerchange', function() { + if (refreshing) return; + refreshing = true; + window.location.reload(); + }); + + navigator.serviceWorker.register('./sw.js').then(function(registration) { + log('SW registered: ' + registration.scope); + registration.onupdatefound = function() { + var installingWorker = registration.installing; + installingWorker.onstatechange = function() { + if (installingWorker.state === 'installed') { + if (navigator.serviceWorker.controller) { + log('新版本已就绪,将自动刷新...'); + setFlashStatus('🔄 更新中...'); + // 不弹 confirm,让 controllerchange 自动处理刷新 + } else { + log('Content cached for offline use.'); + } + } + }; + }; + }, function(err) { + log('SW registration failed: ' + err, '#f00'); + }); + } + }); + + // ============================================================ + // PWA Install Logic + // ============================================================ + let deferredPrompt; + const installBtn = document.getElementById('install-btn'); + + window.addEventListener('beforeinstallprompt', (e) => { + e.preventDefault(); + deferredPrompt = e; + if (installBtn) installBtn.style.display = 'block'; + log('PWA install prompt available'); + }); + + async function installPWA() { + if (!deferredPrompt) return; + deferredPrompt.prompt(); + const { outcome } = await deferredPrompt.userChoice; + log('User response: ' + outcome); + deferredPrompt = null; + if (installBtn) installBtn.style.display = 'none'; + } + + async function clearAppCache() { + if (confirm('确定要清除应用缓存并重新加载吗?')) { + try { + if ('serviceWorker' in navigator) { + const registrations = await navigator.serviceWorker.getRegistrations(); + for (const r of registrations) await r.unregister(); + } + if ('caches' in window) { + const names = await caches.keys(); + for (const name of names) await caches.delete(name); + } + window.location.reload(true); + } catch (err) { + alert('清除缓存失败: ' + err.message); + } + } + } + + window.addEventListener('appinstalled', () => { + log('PWA installed'); + if (installBtn) installBtn.style.display = 'none'; + }); + + canvas.addEventListener('webglcontextlost', function(e) { e.preventDefault(); log('Canvas context lost!', '#f00'); }, false); + canvas.addEventListener('contextrestored', function() { log('Canvas context restored'); redrawFrame(); }, false); + + - \ No newline at end of file + diff --git a/manifest.json b/manifest.json new file mode 100644 index 0000000..53cd63f --- /dev/null +++ b/manifest.json @@ -0,0 +1,26 @@ +{ + "name": "文曲星 NC1020 模拟器", + "short_name": "WQX NC1020", + "description": "基于 JavaScript 的文曲星 NC1020 模拟器", + "start_url": "./index.html", + "display": "standalone", + "background_color": "#0d0d0f", + "theme_color": "#0a84ff", + "icons": [ + { + "src": "icon-192.png", + "sizes": "192x192", + "type": "image/png" + }, + { + "src": "icon-512.png", + "sizes": "512x512", + "type": "image/png" + }, + { + "src": "nc1020.png", + "sizes": "434x543", + "type": "image/png" + } + ] +} diff --git a/nc1020.png b/nc1020.png new file mode 100644 index 0000000..7324fcf Binary files /dev/null and b/nc1020.png differ diff --git a/rom.zip b/rom.zip new file mode 100644 index 0000000..6e6e5a0 Binary files /dev/null and b/rom.zip differ diff --git a/rom/nc1020.fls b/rom/nc1020.fls deleted file mode 100644 index 4313896..0000000 Binary files a/rom/nc1020.fls and /dev/null differ diff --git a/rom/obj_lu.bin b/rom/obj_lu.bin deleted file mode 100644 index 9f9d549..0000000 Binary files a/rom/obj_lu.bin and /dev/null differ diff --git a/src/keyinput.js b/src/keyinput.js index 8ce7229..52e8cb5 100644 --- a/src/keyinput.js +++ b/src/keyinput.js @@ -49,6 +49,7 @@ var WqxKeyInput = function (){ 38: 'Up', 34: 'PageDown', 9: 'Tab', + 16: 'Shift', 229: 'Shift', 20: 'CapsLock', 27: 'Esc', @@ -57,10 +58,22 @@ var WqxKeyInput = function (){ 187: 'Equals', 37: 'Left', 40: 'Down', - 39: 'Right' + 39: 'Right', + 49: 'B',//1 + 50: 'N',//2 + 51: 'M',//3 + 52: 'G',//4 + 53: 'H',//5 + 54: 'J',//6 + 55: 'T',//7 + 56: 'Y',//8 + 57: 'U',//9 + 32: 'Equals',//space + 8: 'F2',//bkspc + 17: 'Esc' }; var keyNameToKeypadMatrixIndex = { - 'F12': 0x02, + 'F12': 0x0F, 'F5': 0x08, 'F6': 0x09, @@ -87,8 +100,7 @@ var WqxKeyInput = function (){ 'N': 0x35, // 46 N 'M': 0x36, // 46 M 'PageUp': 0x37, // 47 PgUp - - 'A': 0x28, // 30 A + 'PgUp': 0x37, // 47 PgUp 'A': 0x28, // 30 A 'S': 0x29, // 31 S 'D': 0x2A, // 32 D 'F': 0x2B, // 33 F @@ -113,6 +125,7 @@ var WqxKeyInput = function (){ 'P': 0x1C, // 29 P 'Enter': 0x1D, // 39 Enter 'PageDown': 0x1E, // 49 PgDown + 'PgDn': 0x1E, // 49 PgDown 'Right': 0x1F, // 59 `->` 'F1': 0x10, // 12 F1 @@ -120,14 +133,13 @@ var WqxKeyInput = function (){ 'F3': 0x12, // 14 F3 'F4': 0x13 // 15 F4 }; - WqxKeyInput.prototype._keyDownOrUp = function (key, downOrUp){ - var wqxKeyCode = keyNameToKeypadMatrixIndex[key]; - if (wqxKeyCode) { - var col = wqxKeyCode >> 3; - var row = wqxKeyCode & 0x07; - this.wqx.keypadmatrix[row][col] = downOrUp ? 1 : 0; - } - }; +WqxKeyInput.prototype._keyDownOrUp = function (key, downOrUp){ + var wqxKeyCode = keyNameToKeypadMatrixIndex[key]; + if (wqxKeyCode !== undefined) { + // 改为调用setKey,走统一的位运算+唤醒逻辑 + this.wqx.setKey(wqxKeyCode, downOrUp); + } +}; WqxKeyInput.prototype.keyDown = function (key){ this._keyDownOrUp(key, true); this.onpress(key); @@ -147,4 +159,4 @@ var WqxKeyInput = function (){ WqxKeyInput.prototype.onpress = function (key){}; WqxKeyInput.prototype.onrelease = function (key){}; return WqxKeyInput; -}(); \ No newline at end of file +}(); diff --git a/src/m65c02.js b/src/m65c02.js index 9324c4d..865e647 100644 --- a/src/m65c02.js +++ b/src/m65c02.js @@ -1,3 +1,4 @@ +// m65c02.js - 修复版本 function M65C02Context() { this.ram = null; this.memmap = null; @@ -11,7 +12,6 @@ function M65C02Context() { this.reg_y = 0; this.reg_pc = 0; this.reg_sp = 0x100; - //this.reg_ps = 0; this.flag_c = 0; this.flag_z = 0; this.flag_i = 0; @@ -30,9 +30,11 @@ function M65C02Context() { this._tmp2 = 0; this._counters = new Uint32Array(0x100); } + M65C02Context.prototype.get_reg_ps = function() { return ((this.flag_c) | (this.flag_z << 1) | (this.flag_i << 2) | (this.flag_d << 3) | (this.flag_b << 4) | (this.flag_u << 5) | (this.flag_v << 6) | (this.flag_n << 7)); }; + M65C02Context.prototype.set_reg_ps = function(ps) { this.flag_c = (ps & 0x01); this.flag_z = (ps & 0x02) >> 1; @@ -44,153 +46,177 @@ M65C02Context.prototype.set_reg_ps = function(ps) { this.flag_n = (ps & 0x80) >> 7; return ps; }; + +// 辅助函数:读取内存(带IO) +M65C02Context.prototype.readMem = function(addr) { + if (this.io_read_map[addr]) { + var value = this.io_read(addr); + // 唤醒检测 - 注意这里需要能访问 wqx 实例的 wakeUpPending + // 问题:M65C02Context 没有直接引用 Wqx 实例 + if (this.wakeUpPending && addr === 0x45F) { + this.wakeUpPending = false; + return this.wakeUpValue; + } + return value; + } + return this.memmap[addr >> 13][addr & 0x1FFF]; +}; + +// 辅助函数:写入内存(带IO) +M65C02Context.prototype.writeMem = function(addr, value) { + if (this.io_write_map[addr]) { + this.io_write(addr, value); + } else { + this.memmap[addr >> 13][addr & 0x1FFF] = value; + } +}; + +// 修复后的 op_func_tbl M65C02Context.prototype.op_func_tbl = [ + // 0x00 BRK function op00(this_) { this_.reg_pc++; - this_.ram[this_.reg_sp] = (this_.reg_pc >> 8); + this_.writeMem(this_.reg_sp, (this_.reg_pc >> 8)); this_.reg_sp = --this_.reg_sp & 0xFF | 0x100; - this_.ram[this_.reg_sp] = (this_.reg_pc & 0xFF); + this_.writeMem(this_.reg_sp, (this_.reg_pc & 0xFF)); this_.reg_sp = --this_.reg_sp & 0xFF | 0x100; this_.flag_b = 1; - this_.ram[this_.reg_sp] = this_.get_reg_ps(); + this_.writeMem(this_.reg_sp, this_.get_reg_ps()); this_.reg_sp = --this_.reg_sp & 0xFF | 0x100; this_.flag_i = 1; this_.reg_pc = (this_.memmap[7][0x1FFF] << 8) | (this_.memmap[7][0x1FFE]); this_.cycles += 7; }, + // 0x01 ORA (indirect,X) function op01(this_) { - this_._tmp1 = (this_.memmap[this_.reg_pc >> 13][this_.reg_pc & 0x1FFF] + this_.reg_x) & 0xFF; - this_._addr = (((this_._tmp1 < 0xFFFF ? this_.memmap[(this_._tmp1 + 1) >> 13][(this_._tmp1 + 1) & 0x1FFF] : this_.ram[0]) << 8) | this_.memmap[this_._tmp1 >> 13][this_._tmp1 & 0x1FFF]); + this_._tmp1 = (this_.readMem(this_.reg_pc) + this_.reg_x) & 0xFF; + this_._addr = (this_.readMem((this_._tmp1 + 1) & 0xFF) << 8) | this_.readMem(this_._tmp1); this_.reg_pc = (this_.reg_pc + 1) & 0xFFFF; - this_.reg_a |= (this_.io_read_map[this_._addr] ? this_.io_read(this_._addr) : this_.memmap[this_._addr >> 13][this_._addr & 0x1FFF]); + this_.reg_a |= this_.readMem(this_._addr); this_.flag_n = (this_.reg_a & 0x80) >> 7; this_.flag_z = (this_.reg_a & 0xFF) ? 0 : 1; this_.cycles += 6; }, + // 0x02 未使用 function op02(this_) { this_.reg_pc = (this_.reg_pc + 1) & 0xFFFF; this_.cycles += 2; }, + // 0x03 未使用 function op03(this_) { this_.cycles += 1; }, + // 0x04 TSB zp function op04(this_) { - this_._addr = this_.memmap[this_.reg_pc >> 13][this_.reg_pc & 0x1FFF]; + this_._addr = this_.readMem(this_.reg_pc); this_.reg_pc = (this_.reg_pc + 1) & 0xFFFF; - this_._tmp1 = (this_.io_read_map[this_._addr] ? this_.io_read(this_._addr) : this_.memmap[this_._addr >> 13][this_._addr & 0x1FFF]); + this_._tmp1 = this_.readMem(this_._addr); this_.flag_z = (this_.reg_a & this_._tmp1) ? 0 : 1; - if (this_.io_write_map[this_._addr]) { - this_.io_write(this_._addr, (this_._tmp1 | this_.reg_a)); - } else { - this_.memmap[this_._addr >> 13][this_._addr & 0x1FFF] = (this_._tmp1 | this_.reg_a); - } + this_.writeMem(this_._addr, (this_._tmp1 | this_.reg_a)); this_.cycles += 5; }, + // 0x05 ORA zp function op05(this_) { - this_._addr = this_.memmap[this_.reg_pc >> 13][this_.reg_pc & 0x1FFF]; + this_._addr = this_.readMem(this_.reg_pc); this_.reg_pc = (this_.reg_pc + 1) & 0xFFFF; - this_.reg_a |= (this_.io_read_map[this_._addr] ? this_.io_read(this_._addr) : this_.memmap[this_._addr >> 13][this_._addr & 0x1FFF]); + this_.reg_a |= this_.readMem(this_._addr); this_.flag_n = (this_.reg_a & 0x80) >> 7; this_.flag_z = (this_.reg_a & 0xFF) ? 0 : 1; this_.cycles += 3; }, + // 0x06 ASL zp function op06(this_) { - this_._addr = this_.memmap[this_.reg_pc >> 13][this_.reg_pc & 0x1FFF]; + this_._addr = this_.readMem(this_.reg_pc); this_.reg_pc = (this_.reg_pc + 1) & 0xFFFF; - this_._tmp1 = (this_.io_read_map[this_._addr] ? this_.io_read(this_._addr) : this_.memmap[this_._addr >> 13][this_._addr & 0x1FFF]) << 1; + this_._tmp1 = this_.readMem(this_._addr) << 1; this_.flag_c = (this_._tmp1 > 0xFF) ? 1 : 0; + this_.writeMem(this_._addr, (this_._tmp1 & 0xFF)); this_.flag_n = (this_._tmp1 & 0x80) >> 7; this_.flag_z = (this_._tmp1 & 0xFF) ? 0 : 1; - if (this_.io_write_map[this_._addr]) { - this_.io_write(this_._addr, (this_._tmp1 & 0xFF)); - } else { - this_.memmap[this_._addr >> 13][this_._addr & 0x1FFF] = (this_._tmp1 & 0xFF); - } this_.cycles += 5; }, + // 0x07 RMB0 zp function op07(this_) { - this_._addr = this_.memmap[this_.reg_pc >> 13][this_.reg_pc & 0x1FFF]; + this_._addr = this_.readMem(this_.reg_pc); this_.reg_pc = (this_.reg_pc + 1) & 0xFFFF; - this_._tmp1 = (this_.io_read_map[this_._addr] ? this_.io_read(this_._addr) : this_.memmap[this_._addr >> 13][this_._addr & 0x1FFF]) & 0xFE; + this_._tmp1 = this_.readMem(this_._addr) & 0xFE; + this_.writeMem(this_._addr, this_._tmp1); this_.flag_n = (this_._tmp1 & 0x80) >> 7; this_.flag_z = (this_._tmp1 & 0xFF) ? 0 : 1; - if (this_.io_write_map[this_._addr]) { - this_.io_write(this_._addr, this_._tmp1); - } else { - this_.memmap[this_._addr >> 13][this_._addr & 0x1FFF] = this_._tmp1; - } this_.cycles += 5; }, + // 0x08 PHP function op08(this_) { this_.flag_u = 1; - this_.ram[this_.reg_sp] = this_.get_reg_ps(); + this_.writeMem(this_.reg_sp, this_.get_reg_ps()); this_.reg_sp = --this_.reg_sp & 0xFF | 0x100; this_.cycles += 3; }, + // 0x09 ORA imm function op09(this_) { this_._addr = this_.reg_pc; this_.reg_pc = (this_.reg_pc + 1) & 0xFFFF; - this_.reg_a |= (this_.io_read_map[this_._addr] ? this_.io_read(this_._addr) : this_.memmap[this_._addr >> 13][this_._addr & 0x1FFF]); + this_.reg_a |= this_.readMem(this_._addr); this_.flag_n = (this_.reg_a & 0x80) >> 7; this_.flag_z = (this_.reg_a & 0xFF) ? 0 : 1; this_.cycles += 2; }, + // 0x0A ASL A function op0A(this_) { this_._tmp1 = this_.reg_a << 1; this_.flag_c = (this_._tmp1 > 0xFF) ? 1 : 0; - this_.flag_n = (this_._tmp1 & 0x80) >> 7; - this_.flag_z = (this_._tmp1 & 0xFF) ? 0 : 1; this_.reg_a = (this_._tmp1 & 0xFF); + this_.flag_n = (this_.reg_a & 0x80) >> 7; + this_.flag_z = (this_.reg_a & 0xFF) ? 0 : 1; this_.cycles += 2; }, + // 0x0B 未使用 function op0B(this_) { this_.cycles += 1; }, + // 0x0C TSB abs function op0C(this_) { - this_._addr = (((this_.reg_pc < 0xFFFF ? this_.memmap[(this_.reg_pc + 1) >> 13][(this_.reg_pc + 1) & 0x1FFF] : this_.ram[0]) << 8) | this_.memmap[this_.reg_pc >> 13][this_.reg_pc & 0x1FFF]); + this_._addr = (this_.readMem(this_.reg_pc + 1) << 8) | this_.readMem(this_.reg_pc); this_.reg_pc = (this_.reg_pc + 2) & 0xFFFF; - this_._tmp1 = (this_.io_read_map[this_._addr] ? this_.io_read(this_._addr) : this_.memmap[this_._addr >> 13][this_._addr & 0x1FFF]); + this_._tmp1 = this_.readMem(this_._addr); this_.flag_z = (this_.reg_a & this_._tmp1) ? 0 : 1; - if (this_.io_write_map[this_._addr]) { - this_.io_write(this_._addr, (this_._tmp1 | this_.reg_a)); - } else { - this_.memmap[this_._addr >> 13][this_._addr & 0x1FFF] = (this_._tmp1 | this_.reg_a); - } + this_.writeMem(this_._addr, (this_._tmp1 | this_.reg_a)); this_.cycles += 6; }, + // 0x0D ORA abs function op0D(this_) { - this_._addr = (((this_.reg_pc < 0xFFFF ? this_.memmap[(this_.reg_pc + 1) >> 13][(this_.reg_pc + 1) & 0x1FFF] : this_.ram[0]) << 8) | this_.memmap[this_.reg_pc >> 13][this_.reg_pc & 0x1FFF]); + this_._addr = (this_.readMem(this_.reg_pc + 1) << 8) | this_.readMem(this_.reg_pc); this_.reg_pc = (this_.reg_pc + 2) & 0xFFFF; - this_.reg_a |= (this_.io_read_map[this_._addr] ? this_.io_read(this_._addr) : this_.memmap[this_._addr >> 13][this_._addr & 0x1FFF]); + this_.reg_a |= this_.readMem(this_._addr); this_.flag_n = (this_.reg_a & 0x80) >> 7; this_.flag_z = (this_.reg_a & 0xFF) ? 0 : 1; this_.cycles += 4; }, + // 0x0E ASL abs function op0E(this_) { - this_._addr = (((this_.reg_pc < 0xFFFF ? this_.memmap[(this_.reg_pc + 1) >> 13][(this_.reg_pc + 1) & 0x1FFF] : this_.ram[0]) << 8) | this_.memmap[this_.reg_pc >> 13][this_.reg_pc & 0x1FFF]); + this_._addr = (this_.readMem(this_.reg_pc + 1) << 8) | this_.readMem(this_.reg_pc); this_.reg_pc = (this_.reg_pc + 2) & 0xFFFF; - this_._tmp1 = (this_.io_read_map[this_._addr] ? this_.io_read(this_._addr) : this_.memmap[this_._addr >> 13][this_._addr & 0x1FFF]) << 1; + this_._tmp1 = this_.readMem(this_._addr) << 1; this_.flag_c = (this_._tmp1 > 0xFF) ? 1 : 0; + this_.writeMem(this_._addr, (this_._tmp1 & 0xFF)); this_.flag_n = (this_._tmp1 & 0x80) >> 7; this_.flag_z = (this_._tmp1 & 0xFF) ? 0 : 1; - if (this_.io_write_map[this_._addr]) { - this_.io_write(this_._addr, (this_._tmp1 & 0xFF)); - } else { - this_.memmap[this_._addr >> 13][this_._addr & 0x1FFF] = (this_._tmp1 & 0xFF); - } this_.cycles += 6; }, + // 0x0F BBR0 function op0F(this_) { - this_._addr = this_.memmap[this_.reg_pc >> 13][this_.reg_pc & 0x1FFF]; - this_.reg_pc = (this_.reg_pc + 1) & 0xFFFF; - if (!((this_.io_read_map[this_._addr] ? this_.io_read(this_._addr) : this_.memmap[this_._addr >> 13][this_._addr & 0x1FFF]) & 0x01)) { + this_._addr = this_.readMem(this_.reg_pc); + this_._tmp2 = this_.readMem(this_.reg_pc + 1); + this_.reg_pc = (this_.reg_pc + 2) & 0xFFFF; + if (!(this_.readMem(this_._addr) & 0x01)) { this_.reg_pc = (this_.reg_pc + this_._tmp2) & 0xFFFF; this_.cycles++; } this_.cycles += 5; }, + // 0x10 BPL function op10(this_) { - this_._tmp1 = this_.memmap[this_.reg_pc >> 13][this_.reg_pc & 0x1FFF]; + this_._tmp1 = this_.readMem(this_.reg_pc); this_._tmp2 = this_._tmp1 - ((this_._tmp1 & 0x80) << 1); this_.reg_pc = (this_.reg_pc + 1) & 0xFFFF; if (!this_.flag_n) { @@ -199,221 +225,236 @@ M65C02Context.prototype.op_func_tbl = [ } this_.cycles += 2; }, + // 0x11 ORA (indirect),Y function op11(this_) { - this_._tmp1 = this_.memmap[this_.reg_pc >> 13][this_.reg_pc & 0x1FFF]; - this_._addr = ((((this_._tmp1 < 0xFFFF ? this_.memmap[(this_._tmp1 + 1) >> 13][(this_._tmp1 + 1) & 0x1FFF] : this_.ram[0]) << 8) | this_.memmap[this_._tmp1 >> 13][this_._tmp1 & 0x1FFF]) + this_.reg_y) & 0xFFFF; + this_._tmp1 = this_.readMem(this_.reg_pc); + this_._addr = (this_.readMem((this_._tmp1 + 1) & 0xFF) << 8) | this_.readMem(this_._tmp1); + // 跨页检测 + if ((this_._addr & 0xFF00) !== ((this_._addr + this_.reg_y) & 0xFF00)) { + this_.cycles++; + } + this_._addr = (this_._addr + this_.reg_y) & 0xFFFF; this_.reg_pc = (this_.reg_pc + 1) & 0xFFFF; - this_.reg_a |= (this_.io_read_map[this_._addr] ? this_.io_read(this_._addr) : this_.memmap[this_._addr >> 13][this_._addr & 0x1FFF]); + this_.reg_a |= this_.readMem(this_._addr); this_.flag_n = (this_.reg_a & 0x80) >> 7; this_.flag_z = (this_.reg_a & 0xFF) ? 0 : 1; this_.cycles += 5; }, + // 0x12 ORA (indirect) function op12(this_) { - this_._tmp1 = this_.memmap[this_.reg_pc >> 13][this_.reg_pc & 0x1FFF]; - this_._addr = ((this_._tmp1 < 0xFF ? this_.ram[this_._tmp1 + 1] : this_.ram[0]) << 8) | this_.ram[this_._tmp1]; + this_._tmp1 = this_.readMem(this_.reg_pc); + this_._addr = (this_.readMem((this_._tmp1 + 1) & 0xFF) << 8) | this_.readMem(this_._tmp1); this_.reg_pc = (this_.reg_pc + 1) & 0xFFFF; - this_.reg_a |= (this_.io_read_map[this_._addr] ? this_.io_read(this_._addr) : this_.memmap[this_._addr >> 13][this_._addr & 0x1FFF]); + this_.reg_a |= this_.readMem(this_._addr); this_.flag_n = (this_.reg_a & 0x80) >> 7; this_.flag_z = (this_.reg_a & 0xFF) ? 0 : 1; this_.cycles += 5; }, + // 0x13 未使用 function op13(this_) { this_.cycles += 1; }, + // 0x14 TRB zp function op14(this_) { - this_._addr = this_.memmap[this_.reg_pc >> 13][this_.reg_pc & 0x1FFF]; + this_._addr = this_.readMem(this_.reg_pc); this_.reg_pc = (this_.reg_pc + 1) & 0xFFFF; - this_._tmp1 = (this_.io_read_map[this_._addr] ? this_.io_read(this_._addr) : this_.memmap[this_._addr >> 13][this_._addr & 0x1FFF]); + this_._tmp1 = this_.readMem(this_._addr); this_.flag_z = (this_.reg_a & this_._tmp1) ? 0 : 1; - if (this_.io_write_map[this_._addr]) { - this_.io_write(this_._addr, (this_._tmp1 & ~this_.reg_a)); - } else { - this_.memmap[this_._addr >> 13][this_._addr & 0x1FFF] = (this_._tmp1 & ~this_.reg_a); - } + this_.writeMem(this_._addr, (this_._tmp1 & ~this_.reg_a)); this_.cycles += 5; }, + // 0x15 ORA zp,X function op15(this_) { - this_._addr = (this_.memmap[this_.reg_pc >> 13][this_.reg_pc & 0x1FFF] + this_.reg_x) & 0xFF; + this_._addr = (this_.readMem(this_.reg_pc) + this_.reg_x) & 0xFF; this_.reg_pc = (this_.reg_pc + 1) & 0xFFFF; - this_.reg_a |= (this_.io_read_map[this_._addr] ? this_.io_read(this_._addr) : this_.memmap[this_._addr >> 13][this_._addr & 0x1FFF]); + this_.reg_a |= this_.readMem(this_._addr); this_.flag_n = (this_.reg_a & 0x80) >> 7; this_.flag_z = (this_.reg_a & 0xFF) ? 0 : 1; this_.cycles += 4; }, + // 0x16 ASL zp,X function op16(this_) { - this_._addr = (this_.memmap[this_.reg_pc >> 13][this_.reg_pc & 0x1FFF] + this_.reg_x) & 0xFF; + this_._addr = (this_.readMem(this_.reg_pc) + this_.reg_x) & 0xFF; this_.reg_pc = (this_.reg_pc + 1) & 0xFFFF; - this_._tmp1 = (this_.io_read_map[this_._addr] ? this_.io_read(this_._addr) : this_.memmap[this_._addr >> 13][this_._addr & 0x1FFF]) << 1; + this_._tmp1 = this_.readMem(this_._addr) << 1; this_.flag_c = (this_._tmp1 > 0xFF) ? 1 : 0; + this_.writeMem(this_._addr, (this_._tmp1 & 0xFF)); this_.flag_n = (this_._tmp1 & 0x80) >> 7; this_.flag_z = (this_._tmp1 & 0xFF) ? 0 : 1; - if (this_.io_write_map[this_._addr]) { - this_.io_write(this_._addr, (this_._tmp1 & 0xFF)); - } else { - this_.memmap[this_._addr >> 13][this_._addr & 0x1FFF] = (this_._tmp1 & 0xFF); - } this_.cycles += 6; }, + // 0x17 RMB1 zp function op17(this_) { - this_._addr = this_.memmap[this_.reg_pc >> 13][this_.reg_pc & 0x1FFF]; + this_._addr = this_.readMem(this_.reg_pc); this_.reg_pc = (this_.reg_pc + 1) & 0xFFFF; - this_._tmp1 = (this_.io_read_map[this_._addr] ? this_.io_read(this_._addr) : this_.memmap[this_._addr >> 13][this_._addr & 0x1FFF]) & 0xFD; + this_._tmp1 = this_.readMem(this_._addr) & 0xFD; + this_.writeMem(this_._addr, this_._tmp1); this_.flag_n = (this_._tmp1 & 0x80) >> 7; this_.flag_z = (this_._tmp1 & 0xFF) ? 0 : 1; - if (this_.io_write_map[this_._addr]) { - this_.io_write(this_._addr, this_._tmp1); - } else { - this_.memmap[this_._addr >> 13][this_._addr & 0x1FFF] = this_._tmp1; - } this_.cycles += 5; }, + // 0x18 CLC function op18(this_) { this_.flag_c = 0; this_.cycles += 2; }, + // 0x19 ORA abs,Y function op19(this_) { - this_._addr = ((((this_.reg_pc < 0xFFFF ? this_.memmap[(this_.reg_pc + 1) >> 13][(this_.reg_pc + 1) & 0x1FFF] : this_.ram[0]) << 8) | this_.memmap[this_.reg_pc >> 13][this_.reg_pc & 0x1FFF]) + this_.reg_y) & 0xFFFF; + this_._addr = (this_.readMem(this_.reg_pc + 1) << 8) | this_.readMem(this_.reg_pc); + // 跨页检测 + if ((this_._addr & 0xFF00) !== ((this_._addr + this_.reg_y) & 0xFF00)) { + this_.cycles++; + } + this_._addr = (this_._addr + this_.reg_y) & 0xFFFF; this_.reg_pc = (this_.reg_pc + 2) & 0xFFFF; - this_.reg_a |= (this_.io_read_map[this_._addr] ? this_.io_read(this_._addr) : this_.memmap[this_._addr >> 13][this_._addr & 0x1FFF]); + this_.reg_a |= this_.readMem(this_._addr); this_.flag_n = (this_.reg_a & 0x80) >> 7; this_.flag_z = (this_.reg_a & 0xFF) ? 0 : 1; this_.cycles += 4; }, + // 0x1A INC A function op1A(this_) { this_.reg_a = (++this_.reg_a & 0xFF); this_.flag_n = (this_.reg_a & 0x80) >> 7; this_.flag_z = (this_.reg_a & 0xFF) ? 0 : 1; this_.cycles += 2; }, + // 0x1B 未使用 function op1B(this_) { this_.cycles += 1; }, + // 0x1C TRB abs function op1C(this_) { - this_._addr = (((this_.reg_pc < 0xFFFF ? this_.memmap[(this_.reg_pc + 1) >> 13][(this_.reg_pc + 1) & 0x1FFF] : this_.ram[0]) << 8) | this_.memmap[this_.reg_pc >> 13][this_.reg_pc & 0x1FFF]); + this_._addr = (this_.readMem(this_.reg_pc + 1) << 8) | this_.readMem(this_.reg_pc); this_.reg_pc = (this_.reg_pc + 2) & 0xFFFF; - this_._tmp1 = (this_.io_read_map[this_._addr] ? this_.io_read(this_._addr) : this_.memmap[this_._addr >> 13][this_._addr & 0x1FFF]); + this_._tmp1 = this_.readMem(this_._addr); this_.flag_z = (this_.reg_a & this_._tmp1) ? 0 : 1; - if (this_.io_write_map[this_._addr]) { - this_.io_write(this_._addr, (this_._tmp1 & ~this_.reg_a)); - } else { - this_.memmap[this_._addr >> 13][this_._addr & 0x1FFF] = (this_._tmp1 & ~this_.reg_a); - } + this_.writeMem(this_._addr, (this_._tmp1 & ~this_.reg_a)); this_.cycles += 6; }, + // 0x1D ORA abs,X function op1D(this_) { - this_._addr = ((((this_.reg_pc < 0xFFFF ? this_.memmap[(this_.reg_pc + 1) >> 13][(this_.reg_pc + 1) & 0x1FFF] : this_.ram[0]) << 8) | this_.memmap[this_.reg_pc >> 13][this_.reg_pc & 0x1FFF]) + this_.reg_x) & 0xFFFF; + this_._addr = (this_.readMem(this_.reg_pc + 1) << 8) | this_.readMem(this_.reg_pc); + // 跨页检测 + if ((this_._addr & 0xFF00) !== ((this_._addr + this_.reg_x) & 0xFF00)) { + this_.cycles++; + } + this_._addr = (this_._addr + this_.reg_x) & 0xFFFF; this_.reg_pc = (this_.reg_pc + 2) & 0xFFFF; - this_.reg_a |= (this_.io_read_map[this_._addr] ? this_.io_read(this_._addr) : this_.memmap[this_._addr >> 13][this_._addr & 0x1FFF]); + this_.reg_a |= this_.readMem(this_._addr); this_.flag_n = (this_.reg_a & 0x80) >> 7; this_.flag_z = (this_.reg_a & 0xFF) ? 0 : 1; this_.cycles += 4; }, + // 0x1E ASL abs,X function op1E(this_) { - this_._addr = ((((this_.reg_pc < 0xFFFF ? this_.memmap[(this_.reg_pc + 1) >> 13][(this_.reg_pc + 1) & 0x1FFF] : this_.ram[0]) << 8) | this_.memmap[this_.reg_pc >> 13][this_.reg_pc & 0x1FFF]) + this_.reg_x) & 0xFFFF; + this_._addr = ((this_.readMem(this_.reg_pc + 1) << 8) | this_.readMem(this_.reg_pc)) + this_.reg_x; this_.reg_pc = (this_.reg_pc + 2) & 0xFFFF; - this_._tmp1 = (this_.io_read_map[this_._addr] ? this_.io_read(this_._addr) : this_.memmap[this_._addr >> 13][this_._addr & 0x1FFF]) << 1; + this_._tmp1 = this_.readMem(this_._addr) << 1; this_.flag_c = (this_._tmp1 > 0xFF) ? 1 : 0; + this_.writeMem(this_._addr, (this_._tmp1 & 0xFF)); this_.flag_n = (this_._tmp1 & 0x80) >> 7; this_.flag_z = (this_._tmp1 & 0xFF) ? 0 : 1; - if (this_.io_write_map[this_._addr]) { - this_.io_write(this_._addr, (this_._tmp1 & 0xFF)); - } else { - this_.memmap[this_._addr >> 13][this_._addr & 0x1FFF] = (this_._tmp1 & 0xFF); - } this_.cycles += 6; }, + // 0x1F BBR1 function op1F(this_) { - this_._addr = this_.memmap[this_.reg_pc >> 13][this_.reg_pc & 0x1FFF]; - this_.reg_pc = (this_.reg_pc + 1) & 0xFFFF; - if (!((this_.io_read_map[this_._addr] ? this_.io_read(this_._addr) : this_.memmap[this_._addr >> 13][this_._addr & 0x1FFF]) & 0x02)) { + this_._addr = this_.readMem(this_.reg_pc); + this_._tmp2 = this_.readMem(this_.reg_pc + 1); + this_.reg_pc = (this_.reg_pc + 2) & 0xFFFF; + if (!(this_.readMem(this_._addr) & 0x02)) { this_.reg_pc = (this_.reg_pc + this_._tmp2) & 0xFFFF; this_.cycles++; } this_.cycles += 5; }, + // 0x20 JSR function op20(this_) { - this_._addr = (((this_.reg_pc < 0xFFFF ? this_.memmap[(this_.reg_pc + 1) >> 13][(this_.reg_pc + 1) & 0x1FFF] : this_.ram[0]) << 8) | this_.memmap[this_.reg_pc >> 13][this_.reg_pc & 0x1FFF]); + this_._addr = (this_.readMem(this_.reg_pc + 1) << 8) | this_.readMem(this_.reg_pc); this_.reg_pc = (this_.reg_pc + 2) & 0xFFFF; this_.reg_pc = (this_.reg_pc - 1) & 0xFFFF; - this_.ram[this_.reg_sp] = (this_.reg_pc >> 8); + this_.writeMem(this_.reg_sp, (this_.reg_pc >> 8)); this_.reg_sp = --this_.reg_sp & 0xFF | 0x100; - this_.ram[this_.reg_sp] = (this_.reg_pc & 0xFF); + this_.writeMem(this_.reg_sp, (this_.reg_pc & 0xFF)); this_.reg_sp = --this_.reg_sp & 0xFF | 0x100; this_.reg_pc = this_._addr; this_.cycles += 6; }, + // 0x21 AND (indirect,X) function op21(this_) { - this_._tmp1 = (this_.memmap[this_.reg_pc >> 13][this_.reg_pc & 0x1FFF] + this_.reg_x) & 0xFF; - this_._addr = (((this_._tmp1 < 0xFFFF ? this_.memmap[(this_._tmp1 + 1) >> 13][(this_._tmp1 + 1) & 0x1FFF] : this_.ram[0]) << 8) | this_.memmap[this_._tmp1 >> 13][this_._tmp1 & 0x1FFF]); + this_._tmp1 = (this_.readMem(this_.reg_pc) + this_.reg_x) & 0xFF; + this_._addr = (this_.readMem((this_._tmp1 + 1) & 0xFF) << 8) | this_.readMem(this_._tmp1); this_.reg_pc = (this_.reg_pc + 1) & 0xFFFF; - this_.reg_a &= (this_.io_read_map[this_._addr] ? this_.io_read(this_._addr) : this_.memmap[this_._addr >> 13][this_._addr & 0x1FFF]); + this_.reg_a &= this_.readMem(this_._addr); this_.flag_n = (this_.reg_a & 0x80) >> 7; this_.flag_z = (this_.reg_a & 0xFF) ? 0 : 1; this_.cycles += 6; }, + // 0x22 未使用 function op22(this_) { this_.reg_pc = (this_.reg_pc + 1) & 0xFFFF; this_.cycles += 2; }, + // 0x23 未使用 function op23(this_) { this_.cycles += 1; }, + // 0x24 BIT zp function op24(this_) { - this_._addr = this_.memmap[this_.reg_pc >> 13][this_.reg_pc & 0x1FFF]; + this_._addr = this_.readMem(this_.reg_pc); this_.reg_pc = (this_.reg_pc + 1) & 0xFFFF; - this_._tmp1 = (this_.io_read_map[this_._addr] ? this_.io_read(this_._addr) : this_.memmap[this_._addr >> 13][this_._addr & 0x1FFF]); + this_._tmp1 = this_.readMem(this_._addr); this_.flag_z = !(this_.reg_a & this_._tmp1) | 0; this_.flag_n = (this_._tmp1 & 0x80) >> 7; this_.flag_v = (this_._tmp1 & 0x40) >> 6; this_.cycles += 3; }, + // 0x25 AND zp function op25(this_) { - this_._addr = this_.memmap[this_.reg_pc >> 13][this_.reg_pc & 0x1FFF]; + this_._addr = this_.readMem(this_.reg_pc); this_.reg_pc = (this_.reg_pc + 1) & 0xFFFF; - this_.reg_a &= (this_.io_read_map[this_._addr] ? this_.io_read(this_._addr) : this_.memmap[this_._addr >> 13][this_._addr & 0x1FFF]); + this_.reg_a &= this_.readMem(this_._addr); this_.flag_n = (this_.reg_a & 0x80) >> 7; this_.flag_z = (this_.reg_a & 0xFF) ? 0 : 1; this_.cycles += 3; }, + // 0x26 ROL zp function op26(this_) { - this_._addr = this_.memmap[this_.reg_pc >> 13][this_.reg_pc & 0x1FFF]; + this_._addr = this_.readMem(this_.reg_pc); this_.reg_pc = (this_.reg_pc + 1) & 0xFFFF; - this_._tmp1 = ((this_.io_read_map[this_._addr] ? this_.io_read(this_._addr) : this_.memmap[this_._addr >> 13][this_._addr & 0x1FFF]) << 1) | this_.flag_c; + this_._tmp1 = (this_.readMem(this_._addr) << 1) | this_.flag_c; this_.flag_c = (this_._tmp1 > 0xFF) ? 1 : 0; + this_.writeMem(this_._addr, (this_._tmp1 & 0xFF)); this_.flag_n = (this_._tmp1 & 0x80) >> 7; this_.flag_z = (this_._tmp1 & 0xFF) ? 0 : 1; - if (this_.io_write_map[this_._addr]) { - this_.io_write(this_._addr, (this_._tmp1 & 0xFF)); - } else { - this_.memmap[this_._addr >> 13][this_._addr & 0x1FFF] = (this_._tmp1 & 0xFF); - } this_.cycles += 5; }, + // 0x27 RMB2 zp function op27(this_) { - this_._addr = this_.memmap[this_.reg_pc >> 13][this_.reg_pc & 0x1FFF]; + this_._addr = this_.readMem(this_.reg_pc); this_.reg_pc = (this_.reg_pc + 1) & 0xFFFF; - this_._tmp1 = (this_.io_read_map[this_._addr] ? this_.io_read(this_._addr) : this_.memmap[this_._addr >> 13][this_._addr & 0x1FFF]) & 0xFB; + this_._tmp1 = this_.readMem(this_._addr) & 0xFB; + this_.writeMem(this_._addr, this_._tmp1); this_.flag_n = (this_._tmp1 & 0x80) >> 7; this_.flag_z = (this_._tmp1 & 0xFF) ? 0 : 1; - if (this_.io_write_map[this_._addr]) { - this_.io_write(this_._addr, this_._tmp1); - } else { - this_.memmap[this_._addr >> 13][this_._addr & 0x1FFF] = this_._tmp1; - } this_.cycles += 5; }, + // 0x28 PLP function op28(this_) { - this_.set_reg_ps(this_.ram[this_.reg_sp = ++this_.reg_sp & 0xFF | 0x100]); + this_.reg_sp = ++this_.reg_sp & 0xFF | 0x100; + this_.set_reg_ps(this_.readMem(this_.reg_sp)); this_.cycles += 4; }, + // 0x29 AND imm function op29(this_) { this_._addr = this_.reg_pc; this_.reg_pc = (this_.reg_pc + 1) & 0xFFFF; - this_.reg_a &= (this_.io_read_map[this_._addr] ? this_.io_read(this_._addr) : this_.memmap[this_._addr >> 13][this_._addr & 0x1FFF]); + this_.reg_a &= this_.readMem(this_._addr); this_.flag_n = (this_.reg_a & 0x80) >> 7; this_.flag_z = (this_.reg_a & 0xFF) ? 0 : 1; this_.cycles += 2; }, + // 0x2A ROL A function op2A(this_) { this_._tmp1 = (this_.reg_a << 1) | this_.flag_c; this_.flag_c = (this_._tmp1 > 0xFF) ? 1 : 0; @@ -422,51 +463,54 @@ M65C02Context.prototype.op_func_tbl = [ this_.flag_z = (this_.reg_a & 0xFF) ? 0 : 1; this_.cycles += 2; }, + // 0x2B 未使用 function op2B(this_) { this_.cycles += 1; }, + // 0x2C BIT abs function op2C(this_) { - this_._addr = (((this_.reg_pc < 0xFFFF ? this_.memmap[(this_.reg_pc + 1) >> 13][(this_.reg_pc + 1) & 0x1FFF] : this_.ram[0]) << 8) | this_.memmap[this_.reg_pc >> 13][this_.reg_pc & 0x1FFF]); + this_._addr = (this_.readMem(this_.reg_pc + 1) << 8) | this_.readMem(this_.reg_pc); this_.reg_pc = (this_.reg_pc + 2) & 0xFFFF; - this_._tmp1 = (this_.io_read_map[this_._addr] ? this_.io_read(this_._addr) : this_.memmap[this_._addr >> 13][this_._addr & 0x1FFF]); + this_._tmp1 = this_.readMem(this_._addr); this_.flag_z = !(this_.reg_a & this_._tmp1) | 0; this_.flag_n = (this_._tmp1 & 0x80) >> 7; this_.flag_v = (this_._tmp1 & 0x40) >> 6; this_.cycles += 4; }, + // 0x2D AND abs function op2D(this_) { - this_._addr = (((this_.reg_pc < 0xFFFF ? this_.memmap[(this_.reg_pc + 1) >> 13][(this_.reg_pc + 1) & 0x1FFF] : this_.ram[0]) << 8) | this_.memmap[this_.reg_pc >> 13][this_.reg_pc & 0x1FFF]); + this_._addr = (this_.readMem(this_.reg_pc + 1) << 8) | this_.readMem(this_.reg_pc); this_.reg_pc = (this_.reg_pc + 2) & 0xFFFF; - this_.reg_a &= (this_.io_read_map[this_._addr] ? this_.io_read(this_._addr) : this_.memmap[this_._addr >> 13][this_._addr & 0x1FFF]); + this_.reg_a &= this_.readMem(this_._addr); this_.flag_n = (this_.reg_a & 0x80) >> 7; this_.flag_z = (this_.reg_a & 0xFF) ? 0 : 1; this_.cycles += 4; }, + // 0x2E ROL abs function op2E(this_) { - this_._addr = (((this_.reg_pc < 0xFFFF ? this_.memmap[(this_.reg_pc + 1) >> 13][(this_.reg_pc + 1) & 0x1FFF] : this_.ram[0]) << 8) | this_.memmap[this_.reg_pc >> 13][this_.reg_pc & 0x1FFF]); + this_._addr = (this_.readMem(this_.reg_pc + 1) << 8) | this_.readMem(this_.reg_pc); this_.reg_pc = (this_.reg_pc + 2) & 0xFFFF; - this_._tmp1 = ((this_.io_read_map[this_._addr] ? this_.io_read(this_._addr) : this_.memmap[this_._addr >> 13][this_._addr & 0x1FFF]) << 1) | this_.flag_c; + this_._tmp1 = (this_.readMem(this_._addr) << 1) | this_.flag_c; this_.flag_c = (this_._tmp1 > 0xFF) ? 1 : 0; + this_.writeMem(this_._addr, (this_._tmp1 & 0xFF)); this_.flag_n = (this_._tmp1 & 0x80) >> 7; this_.flag_z = (this_._tmp1 & 0xFF) ? 0 : 1; - if (this_.io_write_map[this_._addr]) { - this_.io_write(this_._addr, (this_._tmp1 & 0xFF)); - } else { - this_.memmap[this_._addr >> 13][this_._addr & 0x1FFF] = (this_._tmp1 & 0xFF); - } this_.cycles += 6; }, + // 0x2F BBR2 function op2F(this_) { - this_._addr = this_.memmap[this_.reg_pc >> 13][this_.reg_pc & 0x1FFF]; - this_.reg_pc = (this_.reg_pc + 1) & 0xFFFF; - if (!((this_.io_read_map[this_._addr] ? this_.io_read(this_._addr) : this_.memmap[this_._addr >> 13][this_._addr & 0x1FFF]) & 0x04)) { + this_._addr = this_.readMem(this_.reg_pc); + this_._tmp2 = this_.readMem(this_.reg_pc + 1); + this_.reg_pc = (this_.reg_pc + 2) & 0xFFFF; + if (!(this_.readMem(this_._addr) & 0x04)) { this_.reg_pc = (this_.reg_pc + this_._tmp2) & 0xFFFF; this_.cycles++; } this_.cycles += 5; }, + // 0x30 BMI function op30(this_) { - this_._tmp1 = this_.memmap[this_.reg_pc >> 13][this_.reg_pc & 0x1FFF]; + this_._tmp1 = this_.readMem(this_.reg_pc); this_._tmp2 = this_._tmp1 - ((this_._tmp1 & 0x80) << 1); this_.reg_pc = (this_.reg_pc + 1) & 0xFFFF; if (this_.flag_n) { @@ -475,259 +519,279 @@ M65C02Context.prototype.op_func_tbl = [ } this_.cycles += 2; }, + // 0x31 AND (indirect),Y function op31(this_) { - this_._tmp1 = this_.memmap[this_.reg_pc >> 13][this_.reg_pc & 0x1FFF]; - this_._addr = ((((this_._tmp1 < 0xFFFF ? this_.memmap[(this_._tmp1 + 1) >> 13][(this_._tmp1 + 1) & 0x1FFF] : this_.ram[0]) << 8) | this_.memmap[this_._tmp1 >> 13][this_._tmp1 & 0x1FFF]) + this_.reg_y) & 0xFFFF; + this_._tmp1 = this_.readMem(this_.reg_pc); + this_._addr = (this_.readMem((this_._tmp1 + 1) & 0xFF) << 8) | this_.readMem(this_._tmp1); + if ((this_._addr & 0xFF00) !== ((this_._addr + this_.reg_y) & 0xFF00)) { + this_.cycles++; + } + this_._addr = (this_._addr + this_.reg_y) & 0xFFFF; this_.reg_pc = (this_.reg_pc + 1) & 0xFFFF; - this_.reg_a &= (this_.io_read_map[this_._addr] ? this_.io_read(this_._addr) : this_.memmap[this_._addr >> 13][this_._addr & 0x1FFF]); + this_.reg_a &= this_.readMem(this_._addr); this_.flag_n = (this_.reg_a & 0x80) >> 7; this_.flag_z = (this_.reg_a & 0xFF) ? 0 : 1; this_.cycles += 5; }, + // 0x32 AND (indirect) function op32(this_) { - this_._tmp1 = this_.memmap[this_.reg_pc >> 13][this_.reg_pc & 0x1FFF]; - this_._addr = ((this_._tmp1 < 0xFF ? this_.ram[this_._tmp1 + 1] : this_.ram[0]) << 8) | this_.ram[this_._tmp1]; + this_._tmp1 = this_.readMem(this_.reg_pc); + this_._addr = (this_.readMem((this_._tmp1 + 1) & 0xFF) << 8) | this_.readMem(this_._tmp1); this_.reg_pc = (this_.reg_pc + 1) & 0xFFFF; - this_.reg_a &= (this_.io_read_map[this_._addr] ? this_.io_read(this_._addr) : this_.memmap[this_._addr >> 13][this_._addr & 0x1FFF]); + this_.reg_a &= this_.readMem(this_._addr); this_.flag_n = (this_.reg_a & 0x80) >> 7; this_.flag_z = (this_.reg_a & 0xFF) ? 0 : 1; this_.cycles += 5; }, + // 0x33 未使用 function op33(this_) { this_.cycles += 1; }, + // 0x34 BIT zp,X function op34(this_) { - this_._addr = (this_.memmap[this_.reg_pc >> 13][this_.reg_pc & 0x1FFF] + this_.reg_x) & 0xFF; + this_._addr = (this_.readMem(this_.reg_pc) + this_.reg_x) & 0xFF; this_.reg_pc = (this_.reg_pc + 1) & 0xFFFF; - this_._tmp1 = (this_.io_read_map[this_._addr] ? this_.io_read(this_._addr) : this_.memmap[this_._addr >> 13][this_._addr & 0x1FFF]); + this_._tmp1 = this_.readMem(this_._addr); this_.flag_z = !(this_.reg_a & this_._tmp1) | 0; this_.flag_n = (this_._tmp1 & 0x80) >> 7; this_.flag_v = (this_._tmp1 & 0x40) >> 6; this_.cycles += 4; }, + // 0x35 AND zp,X function op35(this_) { - this_._addr = (this_.memmap[this_.reg_pc >> 13][this_.reg_pc & 0x1FFF] + this_.reg_x) & 0xFF; + this_._addr = (this_.readMem(this_.reg_pc) + this_.reg_x) & 0xFF; this_.reg_pc = (this_.reg_pc + 1) & 0xFFFF; - this_.reg_a &= (this_.io_read_map[this_._addr] ? this_.io_read(this_._addr) : this_.memmap[this_._addr >> 13][this_._addr & 0x1FFF]); + this_.reg_a &= this_.readMem(this_._addr); this_.flag_n = (this_.reg_a & 0x80) >> 7; this_.flag_z = (this_.reg_a & 0xFF) ? 0 : 1; this_.cycles += 4; }, + // 0x36 ROL zp,X function op36(this_) { - this_._addr = (this_.memmap[this_.reg_pc >> 13][this_.reg_pc & 0x1FFF] + this_.reg_x) & 0xFF; + this_._addr = (this_.readMem(this_.reg_pc) + this_.reg_x) & 0xFF; this_.reg_pc = (this_.reg_pc + 1) & 0xFFFF; - this_._tmp1 = ((this_.io_read_map[this_._addr] ? this_.io_read(this_._addr) : this_.memmap[this_._addr >> 13][this_._addr & 0x1FFF]) << 1) | this_.flag_c; + this_._tmp1 = (this_.readMem(this_._addr) << 1) | this_.flag_c; this_.flag_c = (this_._tmp1 > 0xFF) ? 1 : 0; + this_.writeMem(this_._addr, (this_._tmp1 & 0xFF)); this_.flag_n = (this_._tmp1 & 0x80) >> 7; this_.flag_z = (this_._tmp1 & 0xFF) ? 0 : 1; - if (this_.io_write_map[this_._addr]) { - this_.io_write(this_._addr, (this_._tmp1 & 0xFF)); - } else { - this_.memmap[this_._addr >> 13][this_._addr & 0x1FFF] = (this_._tmp1 & 0xFF); - } this_.cycles += 6; }, + // 0x37 RMB3 zp function op37(this_) { - this_._addr = this_.memmap[this_.reg_pc >> 13][this_.reg_pc & 0x1FFF]; + this_._addr = this_.readMem(this_.reg_pc); this_.reg_pc = (this_.reg_pc + 1) & 0xFFFF; - this_._tmp1 = (this_.io_read_map[this_._addr] ? this_.io_read(this_._addr) : this_.memmap[this_._addr >> 13][this_._addr & 0x1FFF]) & 0xF7; + this_._tmp1 = this_.readMem(this_._addr) & 0xF7; + this_.writeMem(this_._addr, this_._tmp1); this_.flag_n = (this_._tmp1 & 0x80) >> 7; this_.flag_z = (this_._tmp1 & 0xFF) ? 0 : 1; - if (this_.io_write_map[this_._addr]) { - this_.io_write(this_._addr, this_._tmp1); - } else { - this_.memmap[this_._addr >> 13][this_._addr & 0x1FFF] = this_._tmp1; - } this_.cycles += 5; }, + // 0x38 SEC function op38(this_) { this_.flag_c = 1; this_.cycles += 2; }, + // 0x39 AND abs,Y function op39(this_) { - this_._addr = ((((this_.reg_pc < 0xFFFF ? this_.memmap[(this_.reg_pc + 1) >> 13][(this_.reg_pc + 1) & 0x1FFF] : this_.ram[0]) << 8) | this_.memmap[this_.reg_pc >> 13][this_.reg_pc & 0x1FFF]) + this_.reg_y) & 0xFFFF; + this_._addr = (this_.readMem(this_.reg_pc + 1) << 8) | this_.readMem(this_.reg_pc); + if ((this_._addr & 0xFF00) !== ((this_._addr + this_.reg_y) & 0xFF00)) { + this_.cycles++; + } + this_._addr = (this_._addr + this_.reg_y) & 0xFFFF; this_.reg_pc = (this_.reg_pc + 2) & 0xFFFF; - this_.reg_a &= (this_.io_read_map[this_._addr] ? this_.io_read(this_._addr) : this_.memmap[this_._addr >> 13][this_._addr & 0x1FFF]); + this_.reg_a &= this_.readMem(this_._addr); this_.flag_n = (this_.reg_a & 0x80) >> 7; this_.flag_z = (this_.reg_a & 0xFF) ? 0 : 1; this_.cycles += 4; }, + // 0x3A DEC A function op3A(this_) { this_.reg_a = (--this_.reg_a & 0xFF); this_.flag_n = (this_.reg_a & 0x80) >> 7; this_.flag_z = (this_.reg_a & 0xFF) ? 0 : 1; this_.cycles += 2; }, + // 0x3B 未使用 function op3B(this_) { this_.cycles += 1; }, + // 0x3C BIT abs,X function op3C(this_) { - this_._addr = ((((this_.reg_pc < 0xFFFF ? this_.memmap[(this_.reg_pc + 1) >> 13][(this_.reg_pc + 1) & 0x1FFF] : this_.ram[0]) << 8) | this_.memmap[this_.reg_pc >> 13][this_.reg_pc & 0x1FFF]) + this_.reg_x) & 0xFFFF; + this_._addr = ((this_.readMem(this_.reg_pc + 1) << 8) | this_.readMem(this_.reg_pc)) + this_.reg_x; this_.reg_pc = (this_.reg_pc + 2) & 0xFFFF; - this_._tmp1 = (this_.io_read_map[this_._addr] ? this_.io_read(this_._addr) : this_.memmap[this_._addr >> 13][this_._addr & 0x1FFF]); + this_._tmp1 = this_.readMem(this_._addr); this_.flag_z = !(this_.reg_a & this_._tmp1) | 0; this_.flag_n = (this_._tmp1 & 0x80) >> 7; this_.flag_v = (this_._tmp1 & 0x40) >> 6; this_.cycles += 4; }, + // 0x3D AND abs,X function op3D(this_) { - this_._addr = ((((this_.reg_pc < 0xFFFF ? this_.memmap[(this_.reg_pc + 1) >> 13][(this_.reg_pc + 1) & 0x1FFF] : this_.ram[0]) << 8) | this_.memmap[this_.reg_pc >> 13][this_.reg_pc & 0x1FFF]) + this_.reg_x) & 0xFFFF; + this_._addr = ((this_.readMem(this_.reg_pc + 1) << 8) | this_.readMem(this_.reg_pc)) + this_.reg_x; this_.reg_pc = (this_.reg_pc + 2) & 0xFFFF; - this_.reg_a &= (this_.io_read_map[this_._addr] ? this_.io_read(this_._addr) : this_.memmap[this_._addr >> 13][this_._addr & 0x1FFF]); + this_.reg_a &= this_.readMem(this_._addr); this_.flag_n = (this_.reg_a & 0x80) >> 7; this_.flag_z = (this_.reg_a & 0xFF) ? 0 : 1; this_.cycles += 4; }, + // 0x3E ROL abs,X function op3E(this_) { - this_._addr = ((((this_.reg_pc < 0xFFFF ? this_.memmap[(this_.reg_pc + 1) >> 13][(this_.reg_pc + 1) & 0x1FFF] : this_.ram[0]) << 8) | this_.memmap[this_.reg_pc >> 13][this_.reg_pc & 0x1FFF]) + this_.reg_x) & 0xFFFF; + this_._addr = ((this_.readMem(this_.reg_pc + 1) << 8) | this_.readMem(this_.reg_pc)) + this_.reg_x; this_.reg_pc = (this_.reg_pc + 2) & 0xFFFF; - this_._tmp1 = ((this_.io_read_map[this_._addr] ? this_.io_read(this_._addr) : this_.memmap[this_._addr >> 13][this_._addr & 0x1FFF]) << 1) | this_.flag_c; + this_._tmp1 = (this_.readMem(this_._addr) << 1) | this_.flag_c; this_.flag_c = (this_._tmp1 > 0xFF) ? 1 : 0; + this_.writeMem(this_._addr, (this_._tmp1 & 0xFF)); this_.flag_n = (this_._tmp1 & 0x80) >> 7; this_.flag_z = (this_._tmp1 & 0xFF) ? 0 : 1; - if (this_.io_write_map[this_._addr]) { - this_.io_write(this_._addr, (this_._tmp1 & 0xFF)); - } else { - this_.memmap[this_._addr >> 13][this_._addr & 0x1FFF] = (this_._tmp1 & 0xFF); - } this_.cycles += 6; }, + // 0x3F BBR3 function op3F(this_) { - this_._addr = this_.memmap[this_.reg_pc >> 13][this_.reg_pc & 0x1FFF]; - this_.reg_pc = (this_.reg_pc + 1) & 0xFFFF; - if (!((this_.io_read_map[this_._addr] ? this_.io_read(this_._addr) : this_.memmap[this_._addr >> 13][this_._addr & 0x1FFF]) & 0x08)) { + this_._addr = this_.readMem(this_.reg_pc); + this_._tmp2 = this_.readMem(this_.reg_pc + 1); + this_.reg_pc = (this_.reg_pc + 2) & 0xFFFF; + if (!(this_.readMem(this_._addr) & 0x08)) { this_.reg_pc = (this_.reg_pc + this_._tmp2) & 0xFFFF; this_.cycles++; } this_.cycles += 5; }, + // 0x40 RTI function op40(this_) { - this_.set_reg_ps(this_.ram[this_.reg_sp = ++this_.reg_sp & 0xFF | 0x100]); + this_.reg_sp = ++this_.reg_sp & 0xFF | 0x100; + this_.set_reg_ps(this_.readMem(this_.reg_sp)); this_.irq = 1; - this_.reg_pc = this_.ram[this_.reg_sp = ++this_.reg_sp & 0xFF | 0x100]; - this_.reg_pc |= (this_.ram[this_.reg_sp = ++this_.reg_sp & 0xFF | 0x100] << 8); + this_.reg_sp = ++this_.reg_sp & 0xFF | 0x100; + this_.reg_pc = this_.readMem(this_.reg_sp); + this_.reg_sp = ++this_.reg_sp & 0xFF | 0x100; + this_.reg_pc |= (this_.readMem(this_.reg_sp) << 8); this_.cycles += 6; }, + // 0x41 EOR (indirect,X) function op41(this_) { - this_._tmp1 = (this_.memmap[this_.reg_pc >> 13][this_.reg_pc & 0x1FFF] + this_.reg_x) & 0xFF; - this_._addr = (((this_._tmp1 < 0xFFFF ? this_.memmap[(this_._tmp1 + 1) >> 13][(this_._tmp1 + 1) & 0x1FFF] : this_.ram[0]) << 8) | this_.memmap[this_._tmp1 >> 13][this_._tmp1 & 0x1FFF]); + this_._tmp1 = (this_.readMem(this_.reg_pc) + this_.reg_x) & 0xFF; + this_._addr = (this_.readMem((this_._tmp1 + 1) & 0xFF) << 8) | this_.readMem(this_._tmp1); this_.reg_pc = (this_.reg_pc + 1) & 0xFFFF; - this_.reg_a ^= (this_.io_read_map[this_._addr] ? this_.io_read(this_._addr) : this_.memmap[this_._addr >> 13][this_._addr & 0x1FFF]); + this_.reg_a ^= this_.readMem(this_._addr); this_.flag_n = (this_.reg_a & 0x80) >> 7; this_.flag_z = (this_.reg_a & 0xFF) ? 0 : 1; this_.cycles += 6; }, + // 0x42 未使用 function op42(this_) { this_.reg_pc = (this_.reg_pc + 1) & 0xFFFF; this_.cycles += 2; }, + // 0x43 未使用 function op43(this_) { this_.cycles += 1; }, + // 0x44 未使用 function op44(this_) { this_.reg_pc = (this_.reg_pc + 1) & 0xFFFF; this_.cycles += 3; }, + // 0x45 EOR zp function op45(this_) { - this_._addr = this_.memmap[this_.reg_pc >> 13][this_.reg_pc & 0x1FFF]; + this_._addr = this_.readMem(this_.reg_pc); this_.reg_pc = (this_.reg_pc + 1) & 0xFFFF; - this_.reg_a ^= (this_.io_read_map[this_._addr] ? this_.io_read(this_._addr) : this_.memmap[this_._addr >> 13][this_._addr & 0x1FFF]); + this_.reg_a ^= this_.readMem(this_._addr); this_.flag_n = (this_.reg_a & 0x80) >> 7; this_.flag_z = (this_.reg_a & 0xFF) ? 0 : 1; this_.cycles += 3; }, + // 0x46 LSR zp function op46(this_) { - this_._addr = this_.memmap[this_.reg_pc >> 13][this_.reg_pc & 0x1FFF]; + this_._addr = this_.readMem(this_.reg_pc); this_.reg_pc = (this_.reg_pc + 1) & 0xFFFF; - this_._tmp1 = (this_.io_read_map[this_._addr] ? this_.io_read(this_._addr) : this_.memmap[this_._addr >> 13][this_._addr & 0x1FFF]); + this_._tmp1 = this_.readMem(this_._addr); this_.flag_c = this_._tmp1 & 0x01; - this_.flag_z = (this_._tmp1 ^ 0x01) ? 1 : 0; - this_.flag_n = 0; this_._tmp1 >>= 1; - if (this_.io_write_map[this_._addr]) { - this_.io_write(this_._addr, this_._tmp1); - } else { - this_.memmap[this_._addr >> 13][this_._addr & 0x1FFF] = this_._tmp1; - } + this_.writeMem(this_._addr, this_._tmp1); + this_.flag_n = 0; + this_.flag_z = (this_._tmp1 & 0xFF) ? 0 : 1; this_.cycles += 5; }, + // 0x47 RMB4 zp function op47(this_) { - this_._addr = this_.memmap[this_.reg_pc >> 13][this_.reg_pc & 0x1FFF]; + this_._addr = this_.readMem(this_.reg_pc); this_.reg_pc = (this_.reg_pc + 1) & 0xFFFF; - this_._tmp1 = (this_.io_read_map[this_._addr] ? this_.io_read(this_._addr) : this_.memmap[this_._addr >> 13][this_._addr & 0x1FFF]) & 0xEF; + this_._tmp1 = this_.readMem(this_._addr) & 0xEF; + this_.writeMem(this_._addr, this_._tmp1); this_.flag_n = (this_._tmp1 & 0x80) >> 7; this_.flag_z = (this_._tmp1 & 0xFF) ? 0 : 1; - if (this_.io_write_map[this_._addr]) { - this_.io_write(this_._addr, this_._tmp1); - } else { - this_.memmap[this_._addr >> 13][this_._addr & 0x1FFF] = this_._tmp1; - } this_.cycles += 5; }, + // 0x48 PHA function op48(this_) { - this_.ram[this_.reg_sp] = this_.reg_a; + this_.writeMem(this_.reg_sp, this_.reg_a); this_.reg_sp = --this_.reg_sp & 0xFF | 0x100; this_.cycles += 3; }, + // 0x49 EOR imm function op49(this_) { this_._addr = this_.reg_pc; this_.reg_pc = (this_.reg_pc + 1) & 0xFFFF; - this_.reg_a ^= (this_.io_read_map[this_._addr] ? this_.io_read(this_._addr) : this_.memmap[this_._addr >> 13][this_._addr & 0x1FFF]); + this_.reg_a ^= this_.readMem(this_._addr); this_.flag_n = (this_.reg_a & 0x80) >> 7; this_.flag_z = (this_.reg_a & 0xFF) ? 0 : 1; this_.cycles += 2; }, + // 0x4A LSR A function op4A(this_) { this_.flag_c = (this_.reg_a & 0x01); - this_.flag_n = 0; this_.reg_a >>= 1; - this_.flag_n = (this_.reg_a & 0x80) >> 7; + this_.flag_n = 0; this_.flag_z = (this_.reg_a & 0xFF) ? 0 : 1; this_.cycles += 2; }, + // 0x4B 未使用 function op4B(this_) { this_.cycles += 1; }, + // 0x4C JMP abs function op4C(this_) { - this_._addr = (((this_.reg_pc < 0xFFFF ? this_.memmap[(this_.reg_pc + 1) >> 13][(this_.reg_pc + 1) & 0x1FFF] : this_.ram[0]) << 8) | this_.memmap[this_.reg_pc >> 13][this_.reg_pc & 0x1FFF]); + this_._addr = (this_.readMem(this_.reg_pc + 1) << 8) | this_.readMem(this_.reg_pc); this_.reg_pc = (this_.reg_pc + 2) & 0xFFFF; this_.reg_pc = this_._addr; this_.cycles += 3; }, + // 0x4D EOR abs function op4D(this_) { - this_._addr = (((this_.reg_pc < 0xFFFF ? this_.memmap[(this_.reg_pc + 1) >> 13][(this_.reg_pc + 1) & 0x1FFF] : this_.ram[0]) << 8) | this_.memmap[this_.reg_pc >> 13][this_.reg_pc & 0x1FFF]); + this_._addr = (this_.readMem(this_.reg_pc + 1) << 8) | this_.readMem(this_.reg_pc); this_.reg_pc = (this_.reg_pc + 2) & 0xFFFF; - this_.reg_a ^= (this_.io_read_map[this_._addr] ? this_.io_read(this_._addr) : this_.memmap[this_._addr >> 13][this_._addr & 0x1FFF]); + this_.reg_a ^= this_.readMem(this_._addr); this_.flag_n = (this_.reg_a & 0x80) >> 7; this_.flag_z = (this_.reg_a & 0xFF) ? 0 : 1; this_.cycles += 4; }, + // 0x4E LSR abs function op4E(this_) { - this_._addr = (((this_.reg_pc < 0xFFFF ? this_.memmap[(this_.reg_pc + 1) >> 13][(this_.reg_pc + 1) & 0x1FFF] : this_.ram[0]) << 8) | this_.memmap[this_.reg_pc >> 13][this_.reg_pc & 0x1FFF]); + this_._addr = (this_.readMem(this_.reg_pc + 1) << 8) | this_.readMem(this_.reg_pc); this_.reg_pc = (this_.reg_pc + 2) & 0xFFFF; - this_._tmp1 = (this_.io_read_map[this_._addr] ? this_.io_read(this_._addr) : this_.memmap[this_._addr >> 13][this_._addr & 0x1FFF]); + this_._tmp1 = this_.readMem(this_._addr); this_.flag_c = this_._tmp1 & 0x01; - this_.flag_z = (this_._tmp1 ^ 0x01) ? 1 : 0; - this_.flag_n = 0; this_._tmp1 >>= 1; - if (this_.io_write_map[this_._addr]) { - this_.io_write(this_._addr, this_._tmp1); - } else { - this_.memmap[this_._addr >> 13][this_._addr & 0x1FFF] = this_._tmp1; - } + this_.writeMem(this_._addr, this_._tmp1); + this_.flag_n = 0; + this_.flag_z = (this_._tmp1 & 0xFF) ? 0 : 1; this_.cycles += 6; }, + // 0x4F BBR4 function op4F(this_) { - this_._addr = this_.memmap[this_.reg_pc >> 13][this_.reg_pc & 0x1FFF]; - this_.reg_pc = (this_.reg_pc + 1) & 0xFFFF; - if (!((this_.io_read_map[this_._addr] ? this_.io_read(this_._addr) : this_.memmap[this_._addr >> 13][this_._addr & 0x1FFF]) & 0x10)) { + this_._addr = this_.readMem(this_.reg_pc); + this_._tmp2 = this_.readMem(this_.reg_pc + 1); + this_.reg_pc = (this_.reg_pc + 2) & 0xFFFF; + if (!(this_.readMem(this_._addr) & 0x10)) { this_.reg_pc = (this_.reg_pc + this_._tmp2) & 0xFFFF; this_.cycles++; } this_.cycles += 5; }, + // 0x50 BVC function op50(this_) { - this_._tmp1 = this_.memmap[this_.reg_pc >> 13][this_.reg_pc & 0x1FFF]; + this_._tmp1 = this_.readMem(this_.reg_pc); this_._tmp2 = this_._tmp1 - ((this_._tmp1 & 0x80) << 1); this_.reg_pc = (this_.reg_pc + 1) & 0xFFFF; if (!this_.flag_v) { @@ -736,142 +800,168 @@ M65C02Context.prototype.op_func_tbl = [ } this_.cycles += 2; }, + // 0x51 EOR (indirect),Y function op51(this_) { - this_._tmp1 = this_.memmap[this_.reg_pc >> 13][this_.reg_pc & 0x1FFF]; - this_._addr = ((((this_._tmp1 < 0xFFFF ? this_.memmap[(this_._tmp1 + 1) >> 13][(this_._tmp1 + 1) & 0x1FFF] : this_.ram[0]) << 8) | this_.memmap[this_._tmp1 >> 13][this_._tmp1 & 0x1FFF]) + this_.reg_y) & 0xFFFF; + this_._tmp1 = this_.readMem(this_.reg_pc); + this_._addr = (this_.readMem((this_._tmp1 + 1) & 0xFF) << 8) | this_.readMem(this_._tmp1); + if ((this_._addr & 0xFF00) !== ((this_._addr + this_.reg_y) & 0xFF00)) { + this_.cycles++; + } + this_._addr = (this_._addr + this_.reg_y) & 0xFFFF; this_.reg_pc = (this_.reg_pc + 1) & 0xFFFF; - this_.reg_a ^= (this_.io_read_map[this_._addr] ? this_.io_read(this_._addr) : this_.memmap[this_._addr >> 13][this_._addr & 0x1FFF]); + this_.reg_a ^= this_.readMem(this_._addr); this_.flag_n = (this_.reg_a & 0x80) >> 7; this_.flag_z = (this_.reg_a & 0xFF) ? 0 : 1; this_.cycles += 5; }, + // 0x52 EOR (indirect) function op52(this_) { - this_._tmp1 = this_.memmap[this_.reg_pc >> 13][this_.reg_pc & 0x1FFF]; - this_._addr = ((this_._tmp1 < 0xFF ? this_.ram[this_._tmp1 + 1] : this_.ram[0]) << 8) | this_.ram[this_._tmp1]; + this_._tmp1 = this_.readMem(this_.reg_pc); + this_._addr = (this_.readMem((this_._tmp1 + 1) & 0xFF) << 8) | this_.readMem(this_._tmp1); this_.reg_pc = (this_.reg_pc + 1) & 0xFFFF; - this_.reg_a ^= (this_.io_read_map[this_._addr] ? this_.io_read(this_._addr) : this_.memmap[this_._addr >> 13][this_._addr & 0x1FFF]); + this_.reg_a ^= this_.readMem(this_._addr); this_.flag_n = (this_.reg_a & 0x80) >> 7; this_.flag_z = (this_.reg_a & 0xFF) ? 0 : 1; this_.cycles += 5; }, + // 0x53 未使用 function op53(this_) { this_.cycles += 1; }, + // 0x54 未使用 function op54(this_) { this_.reg_pc = (this_.reg_pc + 1) & 0xFFFF; this_.cycles += 4; }, + // 0x55 EOR zp,X function op55(this_) { - this_._addr = (this_.memmap[this_.reg_pc >> 13][this_.reg_pc & 0x1FFF] + this_.reg_x) & 0xFF; + this_._addr = (this_.readMem(this_.reg_pc) + this_.reg_x) & 0xFF; this_.reg_pc = (this_.reg_pc + 1) & 0xFFFF; - this_.reg_a ^= (this_.io_read_map[this_._addr] ? this_.io_read(this_._addr) : this_.memmap[this_._addr >> 13][this_._addr & 0x1FFF]); + this_.reg_a ^= this_.readMem(this_._addr); this_.flag_n = (this_.reg_a & 0x80) >> 7; this_.flag_z = (this_.reg_a & 0xFF) ? 0 : 1; this_.cycles += 4; }, + // 0x56 LSR zp,X function op56(this_) { - this_._addr = (this_.memmap[this_.reg_pc >> 13][this_.reg_pc & 0x1FFF] + this_.reg_x) & 0xFF; + this_._addr = (this_.readMem(this_.reg_pc) + this_.reg_x) & 0xFF; this_.reg_pc = (this_.reg_pc + 1) & 0xFFFF; - this_._tmp1 = (this_.io_read_map[this_._addr] ? this_.io_read(this_._addr) : this_.memmap[this_._addr >> 13][this_._addr & 0x1FFF]); + this_._tmp1 = this_.readMem(this_._addr); this_.flag_c = this_._tmp1 & 0x01; - this_.flag_z = (this_._tmp1 ^ 0x01) ? 1 : 0; - this_.flag_n = 0; this_._tmp1 >>= 1; - if (this_.io_write_map[this_._addr]) { - this_.io_write(this_._addr, this_._tmp1); - } else { - this_.memmap[this_._addr >> 13][this_._addr & 0x1FFF] = this_._tmp1; - } + this_.writeMem(this_._addr, this_._tmp1); + this_.flag_n = 0; + this_.flag_z = (this_._tmp1 & 0xFF) ? 0 : 1; this_.cycles += 6; }, + // 0x57 RMB5 zp function op57(this_) { - this_._addr = this_.memmap[this_.reg_pc >> 13][this_.reg_pc & 0x1FFF]; + this_._addr = this_.readMem(this_.reg_pc); this_.reg_pc = (this_.reg_pc + 1) & 0xFFFF; - this_._tmp1 = (this_.io_read_map[this_._addr] ? this_.io_read(this_._addr) : this_.memmap[this_._addr >> 13][this_._addr & 0x1FFF]) & 0xDF; + this_._tmp1 = this_.readMem(this_._addr) & 0xDF; + this_.writeMem(this_._addr, this_._tmp1); this_.flag_n = (this_._tmp1 & 0x80) >> 7; this_.flag_z = (this_._tmp1 & 0xFF) ? 0 : 1; - if (this_.io_write_map[this_._addr]) { - this_.io_write(this_._addr, this_._tmp1); - } else { - this_.memmap[this_._addr >> 13][this_._addr & 0x1FFF] = this_._tmp1; - } this_.cycles += 5; }, + // 0x58 CLI function op58(this_) { this_.flag_i = 0; this_.cycles += 2; }, + // 0x59 EOR abs,Y function op59(this_) { - this_._addr = ((((this_.reg_pc < 0xFFFF ? this_.memmap[(this_.reg_pc + 1) >> 13][(this_.reg_pc + 1) & 0x1FFF] : this_.ram[0]) << 8) | this_.memmap[this_.reg_pc >> 13][this_.reg_pc & 0x1FFF]) + this_.reg_y) & 0xFFFF; + this_._addr = (this_.readMem(this_.reg_pc + 1) << 8) | this_.readMem(this_.reg_pc); + if ((this_._addr & 0xFF00) !== ((this_._addr + this_.reg_y) & 0xFF00)) { + this_.cycles++; + } + this_._addr = (this_._addr + this_.reg_y) & 0xFFFF; this_.reg_pc = (this_.reg_pc + 2) & 0xFFFF; - this_.reg_a ^= (this_.io_read_map[this_._addr] ? this_.io_read(this_._addr) : this_.memmap[this_._addr >> 13][this_._addr & 0x1FFF]); + this_.reg_a ^= this_.readMem(this_._addr); this_.flag_n = (this_.reg_a & 0x80) >> 7; this_.flag_z = (this_.reg_a & 0xFF) ? 0 : 1; this_.cycles += 4; }, + // 0x5A PHY function op5A(this_) { - this_.ram[this_.reg_sp] = this_.reg_y; + this_.writeMem(this_.reg_sp, this_.reg_y); this_.reg_sp = --this_.reg_sp & 0xFF | 0x100; this_.cycles += 3; }, + // 0x5B 未使用 function op5B(this_) { this_.cycles += 1; }, + // 0x5C 未使用 function op5C(this_) { this_.reg_pc = (this_.reg_pc + 2) & 0xFFFF; this_.cycles += 8; }, + // 0x5D EOR abs,X function op5D(this_) { - this_._addr = ((((this_.reg_pc < 0xFFFF ? this_.memmap[(this_.reg_pc + 1) >> 13][(this_.reg_pc + 1) & 0x1FFF] : this_.ram[0]) << 8) | this_.memmap[this_.reg_pc >> 13][this_.reg_pc & 0x1FFF]) + this_.reg_x) & 0xFFFF; + this_._addr = ((this_.readMem(this_.reg_pc + 1) << 8) | this_.readMem(this_.reg_pc)) + this_.reg_x; this_.reg_pc = (this_.reg_pc + 2) & 0xFFFF; - this_.reg_a ^= (this_.io_read_map[this_._addr] ? this_.io_read(this_._addr) : this_.memmap[this_._addr >> 13][this_._addr & 0x1FFF]); + this_.reg_a ^= this_.readMem(this_._addr); this_.flag_n = (this_.reg_a & 0x80) >> 7; this_.flag_z = (this_.reg_a & 0xFF) ? 0 : 1; this_.cycles += 4; }, + // 0x5E LSR abs,X function op5E(this_) { - this_._addr = ((((this_.reg_pc < 0xFFFF ? this_.memmap[(this_.reg_pc + 1) >> 13][(this_.reg_pc + 1) & 0x1FFF] : this_.ram[0]) << 8) | this_.memmap[this_.reg_pc >> 13][this_.reg_pc & 0x1FFF]) + this_.reg_x) & 0xFFFF; + this_._addr = ((this_.readMem(this_.reg_pc + 1) << 8) | this_.readMem(this_.reg_pc)) + this_.reg_x; this_.reg_pc = (this_.reg_pc + 2) & 0xFFFF; - this_._tmp1 = (this_.io_read_map[this_._addr] ? this_.io_read(this_._addr) : this_.memmap[this_._addr >> 13][this_._addr & 0x1FFF]); + this_._tmp1 = this_.readMem(this_._addr); this_.flag_c = this_._tmp1 & 0x01; - this_.flag_z = (this_._tmp1 ^ 0x01) ? 1 : 0; - this_.flag_n = 0; this_._tmp1 >>= 1; - if (this_.io_write_map[this_._addr]) { - this_.io_write(this_._addr, this_._tmp1); - } else { - this_.memmap[this_._addr >> 13][this_._addr & 0x1FFF] = this_._tmp1; - } + this_.writeMem(this_._addr, this_._tmp1); + this_.flag_n = 0; + this_.flag_z = (this_._tmp1 & 0xFF) ? 0 : 1; this_.cycles += 6; }, + // 0x5F BBR5 function op5F(this_) { - this_._addr = this_.memmap[this_.reg_pc >> 13][this_.reg_pc & 0x1FFF]; - this_.reg_pc = (this_.reg_pc + 1) & 0xFFFF; - if (!((this_.io_read_map[this_._addr] ? this_.io_read(this_._addr) : this_.memmap[this_._addr >> 13][this_._addr & 0x1FFF]) & 0x20)) { + this_._addr = this_.readMem(this_.reg_pc); + this_._tmp2 = this_.readMem(this_.reg_pc + 1); + this_.reg_pc = (this_.reg_pc + 2) & 0xFFFF; + if (!(this_.readMem(this_._addr) & 0x20)) { this_.reg_pc = (this_.reg_pc + this_._tmp2) & 0xFFFF; this_.cycles++; } this_.cycles += 5; }, + // 0x60 RTS function op60(this_) { - this_.reg_pc = this_.ram[this_.reg_sp = ++this_.reg_sp & 0xFF | 0x100]; - this_.reg_pc |= (this_.ram[this_.reg_sp = ++this_.reg_sp & 0xFF | 0x100] << 8); + this_.reg_sp = ++this_.reg_sp & 0xFF | 0x100; + this_.reg_pc = this_.readMem(this_.reg_sp); + this_.reg_sp = ++this_.reg_sp & 0xFF | 0x100; + this_.reg_pc |= (this_.readMem(this_.reg_sp) << 8); this_.reg_pc = (this_.reg_pc + 1) & 0xFFFF; this_.cycles += 6; }, + // 0x61 ADC (indirect,X) function op61(this_) { - this_._tmp1 = (this_.memmap[this_.reg_pc >> 13][this_.reg_pc & 0x1FFF] + this_.reg_x) & 0xFF; - this_._addr = (((this_._tmp1 < 0xFFFF ? this_.memmap[(this_._tmp1 + 1) >> 13][(this_._tmp1 + 1) & 0x1FFF] : this_.ram[0]) << 8) | this_.memmap[this_._tmp1 >> 13][this_._tmp1 & 0x1FFF]); + this_._tmp1 = (this_.readMem(this_.reg_pc) + this_.reg_x) & 0xFF; + this_._addr = (this_.readMem((this_._tmp1 + 1) & 0xFF) << 8) | this_.readMem(this_._tmp1); this_.reg_pc = (this_.reg_pc + 1) & 0xFFFF; - this_._tmp1 = (this_.io_read_map[this_._addr] ? this_.io_read(this_._addr) : this_.memmap[this_._addr >> 13][this_._addr & 0x1FFF]); + this_._tmp1 = this_.readMem(this_._addr); if (this_.flag_d) { - this_._tmp2 = ((this_.reg_a >> 4) * 10 + (this_.reg_a & 0x0F)) + ((this_._tmp1 >> 4) * 10 + (this_._tmp1 & 0x0F)) + this_.flag_c; - this_.flag_c = (this_._tmp2 > 99) ? 1 : 0; - this_._tmp2 %= 100; - this_.reg_a = ((((this_._tmp2 / 10) % 10) << 4) | (this_._tmp2 % 10)); + var a_lo = this_.reg_a & 0x0F; + var a_hi = (this_.reg_a >> 4) & 0x0F; + var m_lo = this_._tmp1 & 0x0F; + var m_hi = (this_._tmp1 >> 4) & 0x0F; + var sum = a_lo + m_lo + this_.flag_c; + var carry = 0; + if (sum >= 10) { + sum -= 10; + carry = 1; + } + sum += a_hi * 10 + m_hi * 10 + carry * 10; + this_.flag_c = (sum >= 100) ? 1 : 0; + sum = sum % 100; + this_.reg_a = ((Math.floor(sum / 10) << 4) | (sum % 10)); this_.flag_n = (this_.reg_a & 0x80) >> 7; this_.flag_z = (this_.reg_a & 0xFF) ? 0 : 1; - this_.cycles++ + this_.cycles++; } else { this_._tmp2 = this_.reg_a + this_._tmp1 + this_.flag_c; this_.flag_c = (this_._tmp2 > 0xFF) ? 1 : 0; @@ -882,35 +972,45 @@ M65C02Context.prototype.op_func_tbl = [ } this_.cycles += 6; }, + // 0x62 未使用 function op62(this_) { this_.reg_pc = (this_.reg_pc + 1) & 0xFFFF; this_.cycles += 2; }, + // 0x63 未使用 function op63(this_) { this_.cycles += 1; }, + // 0x64 STZ zp function op64(this_) { - this_._addr = this_.memmap[this_.reg_pc >> 13][this_.reg_pc & 0x1FFF]; + this_._addr = this_.readMem(this_.reg_pc); this_.reg_pc = (this_.reg_pc + 1) & 0xFFFF; - if (this_.io_write_map[this_._addr]) { - this_.io_write(this_._addr, 0); - } else { - this_.memmap[this_._addr >> 13][this_._addr & 0x1FFF] = 0; - } + this_.writeMem(this_._addr, 0); this_.cycles += 3; }, + // 0x65 ADC zp function op65(this_) { - this_._addr = this_.memmap[this_.reg_pc >> 13][this_.reg_pc & 0x1FFF]; + this_._addr = this_.readMem(this_.reg_pc); this_.reg_pc = (this_.reg_pc + 1) & 0xFFFF; - this_._tmp1 = (this_.io_read_map[this_._addr] ? this_.io_read(this_._addr) : this_.memmap[this_._addr >> 13][this_._addr & 0x1FFF]); + this_._tmp1 = this_.readMem(this_._addr); if (this_.flag_d) { - this_._tmp2 = ((this_.reg_a >> 4) * 10 + (this_.reg_a & 0x0F)) + ((this_._tmp1 >> 4) * 10 + (this_._tmp1 & 0x0F)) + this_.flag_c; - this_.flag_c = (this_._tmp2 > 99) ? 1 : 0; - this_._tmp2 %= 100; - this_.reg_a = ((((this_._tmp2 / 10) % 10) << 4) | (this_._tmp2 % 10)); + var a_lo = this_.reg_a & 0x0F; + var a_hi = (this_.reg_a >> 4) & 0x0F; + var m_lo = this_._tmp1 & 0x0F; + var m_hi = (this_._tmp1 >> 4) & 0x0F; + var sum = a_lo + m_lo + this_.flag_c; + var carry = 0; + if (sum >= 10) { + sum -= 10; + carry = 1; + } + sum += a_hi * 10 + m_hi * 10 + carry * 10; + this_.flag_c = (sum >= 100) ? 1 : 0; + sum = sum % 100; + this_.reg_a = ((Math.floor(sum / 10) << 4) | (sum % 10)); this_.flag_n = (this_.reg_a & 0x80) >> 7; this_.flag_z = (this_.reg_a & 0xFF) ? 0 : 1; - this_.cycles++ + this_.cycles++; } else { this_._tmp2 = this_.reg_a + this_._tmp1 + this_.flag_c; this_.flag_c = (this_._tmp2 > 0xFF) ? 1 : 0; @@ -921,53 +1021,59 @@ M65C02Context.prototype.op_func_tbl = [ } this_.cycles += 3; }, + // 0x66 ROR zp function op66(this_) { - this_._addr = this_.memmap[this_.reg_pc >> 13][this_.reg_pc & 0x1FFF]; + this_._addr = this_.readMem(this_.reg_pc); this_.reg_pc = (this_.reg_pc + 1) & 0xFFFF; - this_._tmp1 = (this_.io_read_map[this_._addr] ? this_.io_read(this_._addr) : this_.memmap[this_._addr >> 13][this_._addr & 0x1FFF]); - this_.tmp2 = this_.flag_c << 7; + this_._tmp1 = this_.readMem(this_._addr); + this_._tmp2 = (this_.flag_c << 7) | (this_._tmp1 >> 1); this_.flag_c = (this_._tmp1 & 0x01); - this_._tmp2 = (this_._tmp1 >> 1) | this_.tmp2; + this_.writeMem(this_._addr, this_._tmp2); this_.flag_n = (this_._tmp2 & 0x80) >> 7; this_.flag_z = (this_._tmp2 & 0xFF) ? 0 : 1; - if (this_.io_write_map[this_._addr]) { - this_.io_write(this_._addr, this_._tmp2); - } else { - this_.memmap[this_._addr >> 13][this_._addr & 0x1FFF] = this_._tmp2; - } this_.cycles += 5; }, + // 0x67 RMB6 zp function op67(this_) { - this_._addr = this_.memmap[this_.reg_pc >> 13][this_.reg_pc & 0x1FFF]; + this_._addr = this_.readMem(this_.reg_pc); this_.reg_pc = (this_.reg_pc + 1) & 0xFFFF; - this_._tmp1 = (this_.io_read_map[this_._addr] ? this_.io_read(this_._addr) : this_.memmap[this_._addr >> 13][this_._addr & 0x1FFF]) & 0xBF; + this_._tmp1 = this_.readMem(this_._addr) & 0xBF; + this_.writeMem(this_._addr, this_._tmp1); this_.flag_n = (this_._tmp1 & 0x80) >> 7; this_.flag_z = (this_._tmp1 & 0xFF) ? 0 : 1; - if (this_.io_write_map[this_._addr]) { - this_.io_write(this_._addr, this_._tmp1); - } else { - this_.memmap[this_._addr >> 13][this_._addr & 0x1FFF] = this_._tmp1; - } this_.cycles += 5; }, + // 0x68 PLA function op68(this_) { - this_.reg_a = this_.ram[this_.reg_sp = ++this_.reg_sp & 0xFF | 0x100]; + this_.reg_sp = ++this_.reg_sp & 0xFF | 0x100; + this_.reg_a = this_.readMem(this_.reg_sp); this_.flag_n = (this_.reg_a & 0x80) >> 7; this_.flag_z = (this_.reg_a & 0xFF) ? 0 : 1; this_.cycles += 4; }, + // 0x69 ADC imm function op69(this_) { this_._addr = this_.reg_pc; this_.reg_pc = (this_.reg_pc + 1) & 0xFFFF; - this_._tmp1 = (this_.io_read_map[this_._addr] ? this_.io_read(this_._addr) : this_.memmap[this_._addr >> 13][this_._addr & 0x1FFF]); + this_._tmp1 = this_.readMem(this_._addr); if (this_.flag_d) { - this_._tmp2 = ((this_.reg_a >> 4) * 10 + (this_.reg_a & 0x0F)) + ((this_._tmp1 >> 4) * 10 + (this_._tmp1 & 0x0F)) + this_.flag_c; - this_.flag_c = (this_._tmp2 > 99) ? 1 : 0; - this_._tmp2 %= 100; - this_.reg_a = ((((this_._tmp2 / 10) % 10) << 4) | (this_._tmp2 % 10)); + var a_lo = this_.reg_a & 0x0F; + var a_hi = (this_.reg_a >> 4) & 0x0F; + var m_lo = this_._tmp1 & 0x0F; + var m_hi = (this_._tmp1 >> 4) & 0x0F; + var sum = a_lo + m_lo + this_.flag_c; + var carry = 0; + if (sum >= 10) { + sum -= 10; + carry = 1; + } + sum += a_hi * 10 + m_hi * 10 + carry * 10; + this_.flag_c = (sum >= 100) ? 1 : 0; + sum = sum % 100; + this_.reg_a = ((Math.floor(sum / 10) << 4) | (sum % 10)); this_.flag_n = (this_.reg_a & 0x80) >> 7; this_.flag_z = (this_.reg_a & 0xFF) ? 0 : 1; - this_.cycles++ + this_.cycles++; } else { this_._tmp2 = this_.reg_a + this_._tmp1 + this_.flag_c; this_.flag_c = (this_._tmp2 > 0xFF) ? 1 : 0; @@ -978,36 +1084,51 @@ M65C02Context.prototype.op_func_tbl = [ } this_.cycles += 2; }, + // 0x6A ROR A function op6A(this_) { - this_.tmp1 = this_.flag_c << 7; + this_._tmp1 = this_.flag_c << 7; this_.flag_c = (this_.reg_a & 0x01); - this_.reg_a = (this_.reg_a >> 1) | this_.tmp1; + this_.reg_a = (this_.reg_a >> 1) | this_._tmp1; this_.flag_n = (this_.reg_a & 0x80) >> 7; this_.flag_z = (this_.reg_a & 0xFF) ? 0 : 1; this_.cycles += 2; }, + // 0x6B 未使用 function op6B(this_) { this_.cycles += 1; }, + // 0x6C JMP indirect function op6C(this_) { - this_._tmp1 = (((this_.reg_pc < 0xFFFF ? this_.memmap[(this_.reg_pc + 1) >> 13][(this_.reg_pc + 1) & 0x1FFF] : this_.ram[0]) << 8) | this_.memmap[this_.reg_pc >> 13][this_.reg_pc & 0x1FFF]); - this_._addr = (((this_._tmp1 < 0xFFFF ? this_.memmap[(this_._tmp1 + 1) >> 13][(this_._tmp1 + 1) & 0x1FFF] : this_.ram[0]) << 8) | this_.memmap[this_._tmp1 >> 13][this_._tmp1 & 0x1FFF]); + this_._tmp1 = (this_.readMem(this_.reg_pc + 1) << 8) | this_.readMem(this_.reg_pc); + // 65C02 修正:间接跳转跨页时正确处理 + this_._addr = (this_.readMem((this_._tmp1 + 1) & 0xFFFF) << 8) | this_.readMem(this_._tmp1); this_.reg_pc = (this_.reg_pc + 2) & 0xFFFF; this_.reg_pc = this_._addr; this_.cycles += 6; }, + // 0x6D ADC abs function op6D(this_) { - this_._addr = (((this_.reg_pc < 0xFFFF ? this_.memmap[(this_.reg_pc + 1) >> 13][(this_.reg_pc + 1) & 0x1FFF] : this_.ram[0]) << 8) | this_.memmap[this_.reg_pc >> 13][this_.reg_pc & 0x1FFF]); + this_._addr = (this_.readMem(this_.reg_pc + 1) << 8) | this_.readMem(this_.reg_pc); this_.reg_pc = (this_.reg_pc + 2) & 0xFFFF; - this_._tmp1 = (this_.io_read_map[this_._addr] ? this_.io_read(this_._addr) : this_.memmap[this_._addr >> 13][this_._addr & 0x1FFF]); + this_._tmp1 = this_.readMem(this_._addr); if (this_.flag_d) { - this_._tmp2 = ((this_.reg_a >> 4) * 10 + (this_.reg_a & 0x0F)) + ((this_._tmp1 >> 4) * 10 + (this_._tmp1 & 0x0F)) + this_.flag_c; - this_.flag_c = (this_._tmp2 > 99) ? 1 : 0; - this_._tmp2 %= 100; - this_.reg_a = ((((this_._tmp2 / 10) % 10) << 4) | (this_._tmp2 % 10)); + var a_lo = this_.reg_a & 0x0F; + var a_hi = (this_.reg_a >> 4) & 0x0F; + var m_lo = this_._tmp1 & 0x0F; + var m_hi = (this_._tmp1 >> 4) & 0x0F; + var sum = a_lo + m_lo + this_.flag_c; + var carry = 0; + if (sum >= 10) { + sum -= 10; + carry = 1; + } + sum += a_hi * 10 + m_hi * 10 + carry * 10; + this_.flag_c = (sum >= 100) ? 1 : 0; + sum = sum % 100; + this_.reg_a = ((Math.floor(sum / 10) << 4) | (sum % 10)); this_.flag_n = (this_.reg_a & 0x80) >> 7; this_.flag_z = (this_.reg_a & 0xFF) ? 0 : 1; - this_.cycles++ + this_.cycles++; } else { this_._tmp2 = this_.reg_a + this_._tmp1 + this_.flag_c; this_.flag_c = (this_._tmp2 > 0xFF) ? 1 : 0; @@ -1018,33 +1139,32 @@ M65C02Context.prototype.op_func_tbl = [ } this_.cycles += 4; }, + // 0x6E ROR abs function op6E(this_) { - this_._addr = (((this_.reg_pc < 0xFFFF ? this_.memmap[(this_.reg_pc + 1) >> 13][(this_.reg_pc + 1) & 0x1FFF] : this_.ram[0]) << 8) | this_.memmap[this_.reg_pc >> 13][this_.reg_pc & 0x1FFF]); + this_._addr = (this_.readMem(this_.reg_pc + 1) << 8) | this_.readMem(this_.reg_pc); this_.reg_pc = (this_.reg_pc + 2) & 0xFFFF; - this_._tmp1 = (this_.io_read_map[this_._addr] ? this_.io_read(this_._addr) : this_.memmap[this_._addr >> 13][this_._addr & 0x1FFF]); - this_.tmp2 = this_.flag_c << 7; + this_._tmp1 = this_.readMem(this_._addr); + this_._tmp2 = (this_.flag_c << 7) | (this_._tmp1 >> 1); this_.flag_c = (this_._tmp1 & 0x01); - this_._tmp2 = (this_._tmp1 >> 1) | this_.tmp2; + this_.writeMem(this_._addr, this_._tmp2); this_.flag_n = (this_._tmp2 & 0x80) >> 7; this_.flag_z = (this_._tmp2 & 0xFF) ? 0 : 1; - if (this_.io_write_map[this_._addr]) { - this_.io_write(this_._addr, this_._tmp2); - } else { - this_.memmap[this_._addr >> 13][this_._addr & 0x1FFF] = this_._tmp2; - } this_.cycles += 6; }, + // 0x6F BBR6 function op6F(this_) { - this_._addr = this_.memmap[this_.reg_pc >> 13][this_.reg_pc & 0x1FFF]; - this_.reg_pc = (this_.reg_pc + 1) & 0xFFFF; - if (!((this_.io_read_map[this_._addr] ? this_.io_read(this_._addr) : this_.memmap[this_._addr >> 13][this_._addr & 0x1FFF]) & 0x40)) { + this_._addr = this_.readMem(this_.reg_pc); + this_._tmp2 = this_.readMem(this_.reg_pc + 1); + this_.reg_pc = (this_.reg_pc + 2) & 0xFFFF; + if (!(this_.readMem(this_._addr) & 0x40)) { this_.reg_pc = (this_.reg_pc + this_._tmp2) & 0xFFFF; this_.cycles++; } this_.cycles += 5; }, + // 0x70 BVS function op70(this_) { - this_._tmp1 = this_.memmap[this_.reg_pc >> 13][this_.reg_pc & 0x1FFF]; + this_._tmp1 = this_.readMem(this_.reg_pc); this_._tmp2 = this_._tmp1 - ((this_._tmp1 & 0x80) << 1); this_.reg_pc = (this_.reg_pc + 1) & 0xFFFF; if (this_.flag_v) { @@ -1053,19 +1173,34 @@ M65C02Context.prototype.op_func_tbl = [ } this_.cycles += 2; }, + // 0x71 ADC (indirect),Y function op71(this_) { - this_._tmp1 = this_.memmap[this_.reg_pc >> 13][this_.reg_pc & 0x1FFF]; - this_._addr = ((((this_._tmp1 < 0xFFFF ? this_.memmap[(this_._tmp1 + 1) >> 13][(this_._tmp1 + 1) & 0x1FFF] : this_.ram[0]) << 8) | this_.memmap[this_._tmp1 >> 13][this_._tmp1 & 0x1FFF]) + this_.reg_y) & 0xFFFF; + this_._tmp1 = this_.readMem(this_.reg_pc); + this_._addr = (this_.readMem((this_._tmp1 + 1) & 0xFF) << 8) | this_.readMem(this_._tmp1); + if ((this_._addr & 0xFF00) !== ((this_._addr + this_.reg_y) & 0xFF00)) { + this_.cycles++; + } + this_._addr = (this_._addr + this_.reg_y) & 0xFFFF; this_.reg_pc = (this_.reg_pc + 1) & 0xFFFF; - this_._tmp1 = (this_.io_read_map[this_._addr] ? this_.io_read(this_._addr) : this_.memmap[this_._addr >> 13][this_._addr & 0x1FFF]); + this_._tmp1 = this_.readMem(this_._addr); if (this_.flag_d) { - this_._tmp2 = ((this_.reg_a >> 4) * 10 + (this_.reg_a & 0x0F)) + ((this_._tmp1 >> 4) * 10 + (this_._tmp1 & 0x0F)) + this_.flag_c; - this_.flag_c = (this_._tmp2 > 99) ? 1 : 0; - this_._tmp2 %= 100; - this_.reg_a = ((((this_._tmp2 / 10) % 10) << 4) | (this_._tmp2 % 10)); + var a_lo = this_.reg_a & 0x0F; + var a_hi = (this_.reg_a >> 4) & 0x0F; + var m_lo = this_._tmp1 & 0x0F; + var m_hi = (this_._tmp1 >> 4) & 0x0F; + var sum = a_lo + m_lo + this_.flag_c; + var carry = 0; + if (sum >= 10) { + sum -= 10; + carry = 1; + } + sum += a_hi * 10 + m_hi * 10 + carry * 10; + this_.flag_c = (sum >= 100) ? 1 : 0; + sum = sum % 100; + this_.reg_a = ((Math.floor(sum / 10) << 4) | (sum % 10)); this_.flag_n = (this_.reg_a & 0x80) >> 7; this_.flag_z = (this_.reg_a & 0xFF) ? 0 : 1; - this_.cycles++ + this_.cycles++; } else { this_._tmp2 = this_.reg_a + this_._tmp1 + this_.flag_c; this_.flag_c = (this_._tmp2 > 0xFF) ? 1 : 0; @@ -1076,19 +1211,30 @@ M65C02Context.prototype.op_func_tbl = [ } this_.cycles += 5; }, + // 0x72 ADC (indirect) function op72(this_) { - this_._tmp1 = this_.memmap[this_.reg_pc >> 13][this_.reg_pc & 0x1FFF]; - this_._addr = ((this_._tmp1 < 0xFF ? this_.ram[this_._tmp1 + 1] : this_.ram[0]) << 8) | this_.ram[this_._tmp1]; + this_._tmp1 = this_.readMem(this_.reg_pc); + this_._addr = (this_.readMem((this_._tmp1 + 1) & 0xFF) << 8) | this_.readMem(this_._tmp1); this_.reg_pc = (this_.reg_pc + 1) & 0xFFFF; - this_._tmp1 = (this_.io_read_map[this_._addr] ? this_.io_read(this_._addr) : this_.memmap[this_._addr >> 13][this_._addr & 0x1FFF]); + this_._tmp1 = this_.readMem(this_._addr); if (this_.flag_d) { - this_._tmp2 = ((this_.reg_a >> 4) * 10 + (this_.reg_a & 0x0F)) + ((this_._tmp1 >> 4) * 10 + (this_._tmp1 & 0x0F)) + this_.flag_c; - this_.flag_c = (this_._tmp2 > 99) ? 1 : 0; - this_._tmp2 %= 100; - this_.reg_a = ((((this_._tmp2 / 10) % 10) << 4) | (this_._tmp2 % 10)); + var a_lo = this_.reg_a & 0x0F; + var a_hi = (this_.reg_a >> 4) & 0x0F; + var m_lo = this_._tmp1 & 0x0F; + var m_hi = (this_._tmp1 >> 4) & 0x0F; + var sum = a_lo + m_lo + this_.flag_c; + var carry = 0; + if (sum >= 10) { + sum -= 10; + carry = 1; + } + sum += a_hi * 10 + m_hi * 10 + carry * 10; + this_.flag_c = (sum >= 100) ? 1 : 0; + sum = sum % 100; + this_.reg_a = ((Math.floor(sum / 10) << 4) | (sum % 10)); this_.flag_n = (this_.reg_a & 0x80) >> 7; this_.flag_z = (this_.reg_a & 0xFF) ? 0 : 1; - this_.cycles++ + this_.cycles++; } else { this_._tmp2 = this_.reg_a + this_._tmp1 + this_.flag_c; this_.flag_c = (this_._tmp2 > 0xFF) ? 1 : 0; @@ -1099,31 +1245,40 @@ M65C02Context.prototype.op_func_tbl = [ } this_.cycles += 5; }, + // 0x73 未使用 function op73(this_) { this_.cycles += 1; }, + // 0x74 STZ zp,X function op74(this_) { - this_._addr = (this_.memmap[this_.reg_pc >> 13][this_.reg_pc & 0x1FFF] + this_.reg_x) & 0xFF; + this_._addr = (this_.readMem(this_.reg_pc) + this_.reg_x) & 0xFF; this_.reg_pc = (this_.reg_pc + 1) & 0xFFFF; - if (this_.io_write_map[this_._addr]) { - this_.io_write(this_._addr, 0); - } else { - this_.memmap[this_._addr >> 13][this_._addr & 0x1FFF] = 0; - } + this_.writeMem(this_._addr, 0); this_.cycles += 4; }, + // 0x75 ADC zp,X function op75(this_) { - this_._addr = (this_.memmap[this_.reg_pc >> 13][this_.reg_pc & 0x1FFF] + this_.reg_x) & 0xFF; + this_._addr = (this_.readMem(this_.reg_pc) + this_.reg_x) & 0xFF; this_.reg_pc = (this_.reg_pc + 1) & 0xFFFF; - this_._tmp1 = (this_.io_read_map[this_._addr] ? this_.io_read(this_._addr) : this_.memmap[this_._addr >> 13][this_._addr & 0x1FFF]); + this_._tmp1 = this_.readMem(this_._addr); if (this_.flag_d) { - this_._tmp2 = ((this_.reg_a >> 4) * 10 + (this_.reg_a & 0x0F)) + ((this_._tmp1 >> 4) * 10 + (this_._tmp1 & 0x0F)) + this_.flag_c; - this_.flag_c = (this_._tmp2 > 99) ? 1 : 0; - this_._tmp2 %= 100; - this_.reg_a = ((((this_._tmp2 / 10) % 10) << 4) | (this_._tmp2 % 10)); + var a_lo = this_.reg_a & 0x0F; + var a_hi = (this_.reg_a >> 4) & 0x0F; + var m_lo = this_._tmp1 & 0x0F; + var m_hi = (this_._tmp1 >> 4) & 0x0F; + var sum = a_lo + m_lo + this_.flag_c; + var carry = 0; + if (sum >= 10) { + sum -= 10; + carry = 1; + } + sum += a_hi * 10 + m_hi * 10 + carry * 10; + this_.flag_c = (sum >= 100) ? 1 : 0; + sum = sum % 100; + this_.reg_a = ((Math.floor(sum / 10) << 4) | (sum % 10)); this_.flag_n = (this_.reg_a & 0x80) >> 7; this_.flag_z = (this_.reg_a & 0xFF) ? 0 : 1; - this_.cycles++ + this_.cycles++; } else { this_._tmp2 = this_.reg_a + this_._tmp1 + this_.flag_c; this_.flag_c = (this_._tmp2 > 0xFF) ? 1 : 0; @@ -1134,51 +1289,60 @@ M65C02Context.prototype.op_func_tbl = [ } this_.cycles += 4; }, + // 0x76 ROR zp,X function op76(this_) { - this_._addr = (this_.memmap[this_.reg_pc >> 13][this_.reg_pc & 0x1FFF] + this_.reg_x) & 0xFF; + this_._addr = (this_.readMem(this_.reg_pc) + this_.reg_x) & 0xFF; this_.reg_pc = (this_.reg_pc + 1) & 0xFFFF; - this_._tmp1 = (this_.io_read_map[this_._addr] ? this_.io_read(this_._addr) : this_.memmap[this_._addr >> 13][this_._addr & 0x1FFF]); - this_.tmp2 = this_.flag_c << 7; + this_._tmp1 = this_.readMem(this_._addr); + this_._tmp2 = (this_.flag_c << 7) | (this_._tmp1 >> 1); this_.flag_c = (this_._tmp1 & 0x01); - this_._tmp2 = (this_._tmp1 >> 1) | this_.tmp2; + this_.writeMem(this_._addr, this_._tmp2); this_.flag_n = (this_._tmp2 & 0x80) >> 7; this_.flag_z = (this_._tmp2 & 0xFF) ? 0 : 1; - if (this_.io_write_map[this_._addr]) { - this_.io_write(this_._addr, this_._tmp2); - } else { - this_.memmap[this_._addr >> 13][this_._addr & 0x1FFF] = this_._tmp2; - } this_.cycles += 6; }, + // 0x77 RMB7 zp function op77(this_) { - this_._addr = this_.memmap[this_.reg_pc >> 13][this_.reg_pc & 0x1FFF]; + this_._addr = this_.readMem(this_.reg_pc); this_.reg_pc = (this_.reg_pc + 1) & 0xFFFF; - this_._tmp1 = (this_.io_read_map[this_._addr] ? this_.io_read(this_._addr) : this_.memmap[this_._addr >> 13][this_._addr & 0x1FFF]) & 0x7F; + this_._tmp1 = this_.readMem(this_._addr) & 0x7F; + this_.writeMem(this_._addr, this_._tmp1); this_.flag_n = (this_._tmp1 & 0x80) >> 7; this_.flag_z = (this_._tmp1 & 0xFF) ? 0 : 1; - if (this_.io_write_map[this_._addr]) { - this_.io_write(this_._addr, this_._tmp1); - } else { - this_.memmap[this_._addr >> 13][this_._addr & 0x1FFF] = this_._tmp1; - } this_.cycles += 5; }, + // 0x78 SEI function op78(this_) { this_.flag_i = 1; this_.cycles += 2; }, + // 0x79 ADC abs,Y function op79(this_) { - this_._addr = ((((this_.reg_pc < 0xFFFF ? this_.memmap[(this_.reg_pc + 1) >> 13][(this_.reg_pc + 1) & 0x1FFF] : this_.ram[0]) << 8) | this_.memmap[this_.reg_pc >> 13][this_.reg_pc & 0x1FFF]) + this_.reg_y) & 0xFFFF; + this_._addr = (this_.readMem(this_.reg_pc + 1) << 8) | this_.readMem(this_.reg_pc); + if ((this_._addr & 0xFF00) !== ((this_._addr + this_.reg_y) & 0xFF00)) { + this_.cycles++; + } + this_._addr = (this_._addr + this_.reg_y) & 0xFFFF; this_.reg_pc = (this_.reg_pc + 2) & 0xFFFF; - this_._tmp1 = (this_.io_read_map[this_._addr] ? this_.io_read(this_._addr) : this_.memmap[this_._addr >> 13][this_._addr & 0x1FFF]); + this_._tmp1 = this_.readMem(this_._addr); if (this_.flag_d) { - this_._tmp2 = ((this_.reg_a >> 4) * 10 + (this_.reg_a & 0x0F)) + ((this_._tmp1 >> 4) * 10 + (this_._tmp1 & 0x0F)) + this_.flag_c; - this_.flag_c = (this_._tmp2 > 99) ? 1 : 0; - this_._tmp2 %= 100; - this_.reg_a = ((((this_._tmp2 / 10) % 10) << 4) | (this_._tmp2 % 10)); + var a_lo = this_.reg_a & 0x0F; + var a_hi = (this_.reg_a >> 4) & 0x0F; + var m_lo = this_._tmp1 & 0x0F; + var m_hi = (this_._tmp1 >> 4) & 0x0F; + var sum = a_lo + m_lo + this_.flag_c; + var carry = 0; + if (sum >= 10) { + sum -= 10; + carry = 1; + } + sum += a_hi * 10 + m_hi * 10 + carry * 10; + this_.flag_c = (sum >= 100) ? 1 : 0; + sum = sum % 100; + this_.reg_a = ((Math.floor(sum / 10) << 4) | (sum % 10)); this_.flag_n = (this_.reg_a & 0x80) >> 7; this_.flag_z = (this_.reg_a & 0xFF) ? 0 : 1; - this_.cycles++ + this_.cycles++; } else { this_._tmp2 = this_.reg_a + this_._tmp1 + this_.flag_c; this_.flag_c = (this_._tmp2 > 0xFF) ? 1 : 0; @@ -1189,34 +1353,49 @@ M65C02Context.prototype.op_func_tbl = [ } this_.cycles += 4; }, + // 0x7A PLY function op7A(this_) { - this_.reg_y = this_.ram[this_.reg_sp = ++this_.reg_sp & 0xFF | 0x100]; + this_.reg_sp = ++this_.reg_sp & 0xFF | 0x100; + this_.reg_y = this_.readMem(this_.reg_sp); this_.flag_n = (this_.reg_y & 0x80) >> 7; this_.flag_z = (this_.reg_y & 0xFF) ? 0 : 1; this_.cycles += 4; }, + // 0x7B 未使用 function op7B(this_) { this_.cycles += 1; }, + // 0x7C JMP indirect,X function op7C(this_) { - this_._tmp1 = (((this_.reg_pc < 0xFFFF ? this_.memmap[(this_.reg_pc + 1) >> 13][(this_.reg_pc + 1) & 0x1FFF] : this_.ram[0]) << 8) | this_.memmap[this_.reg_pc >> 13][this_.reg_pc & 0x1FFF]) + this_.reg_x; - this_._addr = (((this_._tmp1 < 0xFFFF ? this_.memmap[(this_._tmp1 + 1) >> 13][(this_._tmp1 + 1) & 0x1FFF] : this_.ram[0]) << 8) | this_.memmap[this_._tmp1 >> 13][this_._tmp1 & 0x1FFF]); + this_._tmp1 = ((this_.readMem(this_.reg_pc + 1) << 8) | this_.readMem(this_.reg_pc)) + this_.reg_x; + this_._addr = (this_.readMem((this_._tmp1 + 1) & 0xFFFF) << 8) | this_.readMem(this_._tmp1); this_.reg_pc = (this_.reg_pc + 2) & 0xFFFF; this_.reg_pc = this_._addr; this_.cycles += 6; }, + // 0x7D ADC abs,X function op7D(this_) { - this_._addr = ((((this_.reg_pc < 0xFFFF ? this_.memmap[(this_.reg_pc + 1) >> 13][(this_.reg_pc + 1) & 0x1FFF] : this_.ram[0]) << 8) | this_.memmap[this_.reg_pc >> 13][this_.reg_pc & 0x1FFF]) + this_.reg_x) & 0xFFFF; + this_._addr = ((this_.readMem(this_.reg_pc + 1) << 8) | this_.readMem(this_.reg_pc)) + this_.reg_x; this_.reg_pc = (this_.reg_pc + 2) & 0xFFFF; - this_._tmp1 = (this_.io_read_map[this_._addr] ? this_.io_read(this_._addr) : this_.memmap[this_._addr >> 13][this_._addr & 0x1FFF]); + this_._tmp1 = this_.readMem(this_._addr); if (this_.flag_d) { - this_._tmp2 = ((this_.reg_a >> 4) * 10 + (this_.reg_a & 0x0F)) + ((this_._tmp1 >> 4) * 10 + (this_._tmp1 & 0x0F)) + this_.flag_c; - this_.flag_c = (this_._tmp2 > 99) ? 1 : 0; - this_._tmp2 %= 100; - this_.reg_a = ((((this_._tmp2 / 10) % 10) << 4) | (this_._tmp2 % 10)); + var a_lo = this_.reg_a & 0x0F; + var a_hi = (this_.reg_a >> 4) & 0x0F; + var m_lo = this_._tmp1 & 0x0F; + var m_hi = (this_._tmp1 >> 4) & 0x0F; + var sum = a_lo + m_lo + this_.flag_c; + var carry = 0; + if (sum >= 10) { + sum -= 10; + carry = 1; + } + sum += a_hi * 10 + m_hi * 10 + carry * 10; + this_.flag_c = (sum >= 100) ? 1 : 0; + sum = sum % 100; + this_.reg_a = ((Math.floor(sum / 10) << 4) | (sum % 10)); this_.flag_n = (this_.reg_a & 0x80) >> 7; this_.flag_z = (this_.reg_a & 0xFF) ? 0 : 1; - this_.cycles++ + this_.cycles++; } else { this_._tmp2 = this_.reg_a + this_._tmp1 + this_.flag_c; this_.flag_c = (this_._tmp2 > 0xFF) ? 1 : 0; @@ -1227,161 +1406,148 @@ M65C02Context.prototype.op_func_tbl = [ } this_.cycles += 4; }, + // 0x7E ROR abs,X function op7E(this_) { - this_._addr = ((((this_.reg_pc < 0xFFFF ? this_.memmap[(this_.reg_pc + 1) >> 13][(this_.reg_pc + 1) & 0x1FFF] : this_.ram[0]) << 8) | this_.memmap[this_.reg_pc >> 13][this_.reg_pc & 0x1FFF]) + this_.reg_x) & 0xFFFF; + this_._addr = ((this_.readMem(this_.reg_pc + 1) << 8) | this_.readMem(this_.reg_pc)) + this_.reg_x; this_.reg_pc = (this_.reg_pc + 2) & 0xFFFF; - this_._tmp1 = (this_.io_read_map[this_._addr] ? this_.io_read(this_._addr) : this_.memmap[this_._addr >> 13][this_._addr & 0x1FFF]); - this_.tmp2 = this_.flag_c << 7; + this_._tmp1 = this_.readMem(this_._addr); + this_._tmp2 = (this_.flag_c << 7) | (this_._tmp1 >> 1); this_.flag_c = (this_._tmp1 & 0x01); - this_._tmp2 = (this_._tmp1 >> 1) | this_.tmp2; + this_.writeMem(this_._addr, this_._tmp2); this_.flag_n = (this_._tmp2 & 0x80) >> 7; this_.flag_z = (this_._tmp2 & 0xFF) ? 0 : 1; - if (this_.io_write_map[this_._addr]) { - this_.io_write(this_._addr, this_._tmp2); - } else { - this_.memmap[this_._addr >> 13][this_._addr & 0x1FFF] = this_._tmp2; - } this_.cycles += 6; }, + // 0x7F BBR7 function op7F(this_) { - this_._addr = this_.memmap[this_.reg_pc >> 13][this_.reg_pc & 0x1FFF]; - this_.reg_pc = (this_.reg_pc + 1) & 0xFFFF; - if (!((this_.io_read_map[this_._addr] ? this_.io_read(this_._addr) : this_.memmap[this_._addr >> 13][this_._addr & 0x1FFF]) & 0x80)) { + this_._addr = this_.readMem(this_.reg_pc); + this_._tmp2 = this_.readMem(this_.reg_pc + 1); + this_.reg_pc = (this_.reg_pc + 2) & 0xFFFF; + if (!(this_.readMem(this_._addr) & 0x80)) { this_.reg_pc = (this_.reg_pc + this_._tmp2) & 0xFFFF; this_.cycles++; } this_.cycles += 5; }, + // 0x80 BRA function op80(this_) { - this_._tmp1 = this_.memmap[this_.reg_pc >> 13][this_.reg_pc & 0x1FFF]; + this_._tmp1 = this_.readMem(this_.reg_pc); this_._tmp2 = this_._tmp1 - ((this_._tmp1 & 0x80) << 1); this_.reg_pc = (this_.reg_pc + 1) & 0xFFFF; this_.reg_pc = (this_.reg_pc + this_._tmp2) & 0xFFFF; this_.cycles += 3; }, + // 0x81 STA (indirect,X) function op81(this_) { - this_._tmp1 = (this_.memmap[this_.reg_pc >> 13][this_.reg_pc & 0x1FFF] + this_.reg_x) & 0xFF; - this_._addr = (((this_._tmp1 < 0xFFFF ? this_.memmap[(this_._tmp1 + 1) >> 13][(this_._tmp1 + 1) & 0x1FFF] : this_.ram[0]) << 8) | this_.memmap[this_._tmp1 >> 13][this_._tmp1 & 0x1FFF]); + this_._tmp1 = (this_.readMem(this_.reg_pc) + this_.reg_x) & 0xFF; + this_._addr = (this_.readMem((this_._tmp1 + 1) & 0xFF) << 8) | this_.readMem(this_._tmp1); this_.reg_pc = (this_.reg_pc + 1) & 0xFFFF; - if (this_.io_write_map[this_._addr]) { - this_.io_write(this_._addr, this_.reg_a); - } else { - this_.memmap[this_._addr >> 13][this_._addr & 0x1FFF] = this_.reg_a; - } + this_.writeMem(this_._addr, this_.reg_a); this_.cycles += 6; }, + // 0x82 未使用 function op82(this_) { this_.reg_pc = (this_.reg_pc + 1) & 0xFFFF; this_.cycles += 2; }, + // 0x83 未使用 function op83(this_) { this_.cycles += 1; }, + // 0x84 STY zp function op84(this_) { - this_._addr = this_.memmap[this_.reg_pc >> 13][this_.reg_pc & 0x1FFF]; + this_._addr = this_.readMem(this_.reg_pc); this_.reg_pc = (this_.reg_pc + 1) & 0xFFFF; - if (this_.io_write_map[this_._addr]) { - this_.io_write(this_._addr, this_.reg_y); - } else { - this_.memmap[this_._addr >> 13][this_._addr & 0x1FFF] = this_.reg_y; - } + this_.writeMem(this_._addr, this_.reg_y); this_.cycles += 3; }, + // 0x85 STA zp function op85(this_) { - this_._addr = this_.memmap[this_.reg_pc >> 13][this_.reg_pc & 0x1FFF]; + this_._addr = this_.readMem(this_.reg_pc); this_.reg_pc = (this_.reg_pc + 1) & 0xFFFF; - if (this_.io_write_map[this_._addr]) { - this_.io_write(this_._addr, this_.reg_a); - } else { - this_.memmap[this_._addr >> 13][this_._addr & 0x1FFF] = this_.reg_a; - } + this_.writeMem(this_._addr, this_.reg_a); this_.cycles += 3; }, + // 0x86 STX zp function op86(this_) { - this_._addr = this_.memmap[this_.reg_pc >> 13][this_.reg_pc & 0x1FFF]; + this_._addr = this_.readMem(this_.reg_pc); this_.reg_pc = (this_.reg_pc + 1) & 0xFFFF; - if (this_.io_write_map[this_._addr]) { - this_.io_write(this_._addr, this_.reg_x); - } else { - this_.memmap[this_._addr >> 13][this_._addr & 0x1FFF] = this_.reg_x; - } + this_.writeMem(this_._addr, this_.reg_x); this_.cycles += 3; }, + // 0x87 SMB0 zp function op87(this_) { - this_._addr = this_.memmap[this_.reg_pc >> 13][this_.reg_pc & 0x1FFF]; + this_._addr = this_.readMem(this_.reg_pc); this_.reg_pc = (this_.reg_pc + 1) & 0xFFFF; - this_._tmp1 = (this_.io_read_map[this_._addr] ? this_.io_read(this_._addr) : this_.memmap[this_._addr >> 13][this_._addr & 0x1FFF]) | 0x01; + this_._tmp1 = this_.readMem(this_._addr) | 0x01; + this_.writeMem(this_._addr, this_._tmp1); this_.flag_n = (this_._tmp1 & 0x80) >> 7; this_.flag_z = (this_._tmp1 & 0xFF) ? 0 : 1; - if (this_.io_write_map[this_._addr]) { - this_.io_write(this_._addr, this_._tmp1); - } else { - this_.memmap[this_._addr >> 13][this_._addr & 0x1FFF] = this_._tmp1; - } this_.cycles += 5; }, + // 0x88 DEY function op88(this_) { this_.reg_y = (--this_.reg_y & 0xFF); this_.flag_n = (this_.reg_y & 0x80) >> 7; this_.flag_z = (this_.reg_y & 0xFF) ? 0 : 1; this_.cycles += 2; }, + // 0x89 BIT imm function op89(this_) { this_._addr = this_.reg_pc; this_.reg_pc = (this_.reg_pc + 1) & 0xFFFF; - this_.flag_z = !(this_.reg_a & (this_.io_read_map[this_._addr] ? this_.io_read(this_._addr) : this_.memmap[this_._addr >> 13][this_._addr & 0x1FFF])) | 0; + this_._tmp1 = this_.readMem(this_._addr); + this_.flag_z = !(this_.reg_a & this_._tmp1) | 0; + this_.flag_n = (this_._tmp1 & 0x80) >> 7; + this_.flag_v = (this_._tmp1 & 0x40) >> 6; this_.cycles += 2; }, + // 0x8A TXA function op8A(this_) { this_.reg_a = this_.reg_x; this_.flag_n = (this_.reg_a & 0x80) >> 7; this_.flag_z = (this_.reg_a & 0xFF) ? 0 : 1; this_.cycles += 2; }, + // 0x8B 未使用 function op8B(this_) { this_.cycles += 1; }, + // 0x8C STY abs function op8C(this_) { - this_._addr = (((this_.reg_pc < 0xFFFF ? this_.memmap[(this_.reg_pc + 1) >> 13][(this_.reg_pc + 1) & 0x1FFF] : this_.ram[0]) << 8) | this_.memmap[this_.reg_pc >> 13][this_.reg_pc & 0x1FFF]); + this_._addr = (this_.readMem(this_.reg_pc + 1) << 8) | this_.readMem(this_.reg_pc); this_.reg_pc = (this_.reg_pc + 2) & 0xFFFF; - if (this_.io_write_map[this_._addr]) { - this_.io_write(this_._addr, this_.reg_y); - } else { - this_.memmap[this_._addr >> 13][this_._addr & 0x1FFF] = this_.reg_y; - } + this_.writeMem(this_._addr, this_.reg_y); this_.cycles += 4; }, + // 0x8D STA abs function op8D(this_) { - this_._addr = (((this_.reg_pc < 0xFFFF ? this_.memmap[(this_.reg_pc + 1) >> 13][(this_.reg_pc + 1) & 0x1FFF] : this_.ram[0]) << 8) | this_.memmap[this_.reg_pc >> 13][this_.reg_pc & 0x1FFF]); + this_._addr = (this_.readMem(this_.reg_pc + 1) << 8) | this_.readMem(this_.reg_pc); this_.reg_pc = (this_.reg_pc + 2) & 0xFFFF; - if (this_.io_write_map[this_._addr]) { - this_.io_write(this_._addr, this_.reg_a); - } else { - this_.memmap[this_._addr >> 13][this_._addr & 0x1FFF] = this_.reg_a; - } + this_.writeMem(this_._addr, this_.reg_a); this_.cycles += 4; }, + // 0x8E STX abs function op8E(this_) { - this_._addr = (((this_.reg_pc < 0xFFFF ? this_.memmap[(this_.reg_pc + 1) >> 13][(this_.reg_pc + 1) & 0x1FFF] : this_.ram[0]) << 8) | this_.memmap[this_.reg_pc >> 13][this_.reg_pc & 0x1FFF]); + this_._addr = (this_.readMem(this_.reg_pc + 1) << 8) | this_.readMem(this_.reg_pc); this_.reg_pc = (this_.reg_pc + 2) & 0xFFFF; - if (this_.io_write_map[this_._addr]) { - this_.io_write(this_._addr, this_.reg_x); - } else { - this_.memmap[this_._addr >> 13][this_._addr & 0x1FFF] = this_.reg_x; - } + this_.writeMem(this_._addr, this_.reg_x); this_.cycles += 4; }, + // 0x8F SMB1 zp function op8F(this_) { - this_._addr = this_.memmap[this_.reg_pc >> 13][this_.reg_pc & 0x1FFF]; - this_.reg_pc = (this_.reg_pc + 1) & 0xFFFF; - if ((this_.io_read_map[this_._addr] ? this_.io_read(this_._addr) : this_.memmap[this_._addr >> 13][this_._addr & 0x1FFF]) & 0x01) { + this_._addr = this_.readMem(this_.reg_pc); + this_._tmp2 = this_.readMem(this_.reg_pc + 1); + this_.reg_pc = (this_.reg_pc + 2) & 0xFFFF; + if (this_.readMem(this_._addr) & 0x01) { this_.reg_pc = (this_.reg_pc + this_._tmp2) & 0xFFFF; this_.cycles++; } this_.cycles += 5; }, + // 0x90 BCC function op90(this_) { - this_._tmp1 = this_.memmap[this_.reg_pc >> 13][this_.reg_pc & 0x1FFF]; + this_._tmp1 = this_.readMem(this_.reg_pc); this_._tmp2 = this_._tmp1 - ((this_._tmp1 & 0x80) << 1); this_.reg_pc = (this_.reg_pc + 1) & 0xFFFF; if (!this_.flag_c) { @@ -1390,259 +1556,250 @@ M65C02Context.prototype.op_func_tbl = [ } this_.cycles += 2; }, + // 0x91 STA (indirect),Y function op91(this_) { - this_._tmp1 = this_.memmap[this_.reg_pc >> 13][this_.reg_pc & 0x1FFF]; - this_._addr = ((((this_._tmp1 < 0xFFFF ? this_.memmap[(this_._tmp1 + 1) >> 13][(this_._tmp1 + 1) & 0x1FFF] : this_.ram[0]) << 8) | this_.memmap[this_._tmp1 >> 13][this_._tmp1 & 0x1FFF]) + this_.reg_y) & 0xFFFF; + this_._tmp1 = this_.readMem(this_.reg_pc); + this_._addr = (this_.readMem((this_._tmp1 + 1) & 0xFF) << 8) | this_.readMem(this_._tmp1); + this_._addr = (this_._addr + this_.reg_y) & 0xFFFF; this_.reg_pc = (this_.reg_pc + 1) & 0xFFFF; - if (this_.io_write_map[this_._addr]) { - this_.io_write(this_._addr, this_.reg_a); - } else { - this_.memmap[this_._addr >> 13][this_._addr & 0x1FFF] = this_.reg_a; - } + this_.writeMem(this_._addr, this_.reg_a); this_.cycles += 6; }, + // 0x92 STA (indirect) function op92(this_) { - this_._tmp1 = this_.memmap[this_.reg_pc >> 13][this_.reg_pc & 0x1FFF]; - this_._addr = ((this_._tmp1 < 0xFF ? this_.ram[this_._tmp1 + 1] : this_.ram[0]) << 8) | this_.ram[this_._tmp1]; + this_._tmp1 = this_.readMem(this_.reg_pc); + this_._addr = (this_.readMem((this_._tmp1 + 1) & 0xFF) << 8) | this_.readMem(this_._tmp1); this_.reg_pc = (this_.reg_pc + 1) & 0xFFFF; - if (this_.io_write_map[this_._addr]) { - this_.io_write(this_._addr, this_.reg_a); - } else { - this_.memmap[this_._addr >> 13][this_._addr & 0x1FFF] = this_.reg_a; - } + this_.writeMem(this_._addr, this_.reg_a); this_.cycles += 5; }, + // 0x93 未使用 function op93(this_) { this_.cycles += 1; }, + // 0x94 STY zp,X function op94(this_) { - this_._addr = (this_.memmap[this_.reg_pc >> 13][this_.reg_pc & 0x1FFF] + this_.reg_x) & 0xFF; + this_._addr = (this_.readMem(this_.reg_pc) + this_.reg_x) & 0xFF; this_.reg_pc = (this_.reg_pc + 1) & 0xFFFF; - if (this_.io_write_map[this_._addr]) { - this_.io_write(this_._addr, this_.reg_y); - } else { - this_.memmap[this_._addr >> 13][this_._addr & 0x1FFF] = this_.reg_y; - } + this_.writeMem(this_._addr, this_.reg_y); this_.cycles += 4; }, + // 0x95 STA zp,X function op95(this_) { - this_._addr = (this_.memmap[this_.reg_pc >> 13][this_.reg_pc & 0x1FFF] + this_.reg_x) & 0xFF; + this_._addr = (this_.readMem(this_.reg_pc) + this_.reg_x) & 0xFF; this_.reg_pc = (this_.reg_pc + 1) & 0xFFFF; - if (this_.io_write_map[this_._addr]) { - this_.io_write(this_._addr, this_.reg_a); - } else { - this_.memmap[this_._addr >> 13][this_._addr & 0x1FFF] = this_.reg_a; - } + this_.writeMem(this_._addr, this_.reg_a); this_.cycles += 4; }, + // 0x96 STX zp,Y function op96(this_) { - this_._addr = (this_.memmap[this_.reg_pc >> 13][this_.reg_pc & 0x1FFF] + this_.reg_y) & 0xFF; + this_._addr = (this_.readMem(this_.reg_pc) + this_.reg_y) & 0xFF; this_.reg_pc = (this_.reg_pc + 1) & 0xFFFF; - if (this_.io_write_map[this_._addr]) { - this_.io_write(this_._addr, this_.reg_x); - } else { - this_.memmap[this_._addr >> 13][this_._addr & 0x1FFF] = this_.reg_x; - } + this_.writeMem(this_._addr, this_.reg_x); this_.cycles += 4; }, + // 0x97 SMB2 zp function op97(this_) { - this_._addr = this_.memmap[this_.reg_pc >> 13][this_.reg_pc & 0x1FFF]; + this_._addr = this_.readMem(this_.reg_pc); this_.reg_pc = (this_.reg_pc + 1) & 0xFFFF; - this_._tmp1 = (this_.io_read_map[this_._addr] ? this_.io_read(this_._addr) : this_.memmap[this_._addr >> 13][this_._addr & 0x1FFF]) | 0x02; + this_._tmp1 = this_.readMem(this_._addr) | 0x02; + this_.writeMem(this_._addr, this_._tmp1); this_.flag_n = (this_._tmp1 & 0x80) >> 7; this_.flag_z = (this_._tmp1 & 0xFF) ? 0 : 1; - if (this_.io_write_map[this_._addr]) { - this_.io_write(this_._addr, this_._tmp1); - } else { - this_.memmap[this_._addr >> 13][this_._addr & 0x1FFF] = this_._tmp1; - } this_.cycles += 5; }, + // 0x98 TYA function op98(this_) { this_.reg_a = this_.reg_y; this_.flag_n = (this_.reg_a & 0x80) >> 7; this_.flag_z = (this_.reg_a & 0xFF) ? 0 : 1; this_.cycles += 2; }, + // 0x99 STA abs,Y function op99(this_) { - this_._addr = ((((this_.reg_pc < 0xFFFF ? this_.memmap[(this_.reg_pc + 1) >> 13][(this_.reg_pc + 1) & 0x1FFF] : this_.ram[0]) << 8) | this_.memmap[this_.reg_pc >> 13][this_.reg_pc & 0x1FFF]) + this_.reg_y) & 0xFFFF; + this_._addr = ((this_.readMem(this_.reg_pc + 1) << 8) | this_.readMem(this_.reg_pc)) + this_.reg_y; this_.reg_pc = (this_.reg_pc + 2) & 0xFFFF; - if (this_.io_write_map[this_._addr]) { - this_.io_write(this_._addr, this_.reg_a); - } else { - this_.memmap[this_._addr >> 13][this_._addr & 0x1FFF] = this_.reg_a; - } + this_.writeMem(this_._addr, this_.reg_a); this_.cycles += 5; }, + // 0x9A TXS function op9A(this_) { this_.reg_sp = (this_.reg_x | 0x100); this_.cycles += 2; }, + // 0x9B 未使用 function op9B(this_) { this_.cycles += 1; }, + // 0x9C STZ abs function op9C(this_) { - this_._addr = (((this_.reg_pc < 0xFFFF ? this_.memmap[(this_.reg_pc + 1) >> 13][(this_.reg_pc + 1) & 0x1FFF] : this_.ram[0]) << 8) | this_.memmap[this_.reg_pc >> 13][this_.reg_pc & 0x1FFF]); + this_._addr = (this_.readMem(this_.reg_pc + 1) << 8) | this_.readMem(this_.reg_pc); this_.reg_pc = (this_.reg_pc + 2) & 0xFFFF; - if (this_.io_write_map[this_._addr]) { - this_.io_write(this_._addr, 0); - } else { - this_.memmap[this_._addr >> 13][this_._addr & 0x1FFF] = 0; - } + this_.writeMem(this_._addr, 0); this_.cycles += 4; }, + // 0x9D STA abs,X function op9D(this_) { - this_._addr = ((((this_.reg_pc < 0xFFFF ? this_.memmap[(this_.reg_pc + 1) >> 13][(this_.reg_pc + 1) & 0x1FFF] : this_.ram[0]) << 8) | this_.memmap[this_.reg_pc >> 13][this_.reg_pc & 0x1FFF]) + this_.reg_x) & 0xFFFF; + this_._addr = ((this_.readMem(this_.reg_pc + 1) << 8) | this_.readMem(this_.reg_pc)) + this_.reg_x; this_.reg_pc = (this_.reg_pc + 2) & 0xFFFF; - if (this_.io_write_map[this_._addr]) { - this_.io_write(this_._addr, this_.reg_a); - } else { - this_.memmap[this_._addr >> 13][this_._addr & 0x1FFF] = this_.reg_a; - } + this_.writeMem(this_._addr, this_.reg_a); this_.cycles += 5; }, + // 0x9E STZ abs,X function op9E(this_) { - this_._addr = ((((this_.reg_pc < 0xFFFF ? this_.memmap[(this_.reg_pc + 1) >> 13][(this_.reg_pc + 1) & 0x1FFF] : this_.ram[0]) << 8) | this_.memmap[this_.reg_pc >> 13][this_.reg_pc & 0x1FFF]) + this_.reg_x) & 0xFFFF; + this_._addr = ((this_.readMem(this_.reg_pc + 1) << 8) | this_.readMem(this_.reg_pc)) + this_.reg_x; this_.reg_pc = (this_.reg_pc + 2) & 0xFFFF; - if (this_.io_write_map[this_._addr]) { - this_.io_write(this_._addr, 0); - } else { - this_.memmap[this_._addr >> 13][this_._addr & 0x1FFF] = 0; - } + this_.writeMem(this_._addr, 0); this_.cycles += 5; }, + // 0x9F SMB3 zp function op9F(this_) { - this_._addr = this_.memmap[this_.reg_pc >> 13][this_.reg_pc & 0x1FFF]; - this_.reg_pc = (this_.reg_pc + 1) & 0xFFFF; - if ((this_.io_read_map[this_._addr] ? this_.io_read(this_._addr) : this_.memmap[this_._addr >> 13][this_._addr & 0x1FFF]) & 0x02) { + this_._addr = this_.readMem(this_.reg_pc); + this_._tmp2 = this_.readMem(this_.reg_pc + 1); + this_.reg_pc = (this_.reg_pc + 2) & 0xFFFF; + if (this_.readMem(this_._addr) & 0x02) { this_.reg_pc = (this_.reg_pc + this_._tmp2) & 0xFFFF; this_.cycles++; } this_.cycles += 5; }, + // 0xA0 LDY imm function opA0(this_) { this_._addr = this_.reg_pc; this_.reg_pc = (this_.reg_pc + 1) & 0xFFFF; - this_.reg_y = (this_.io_read_map[this_._addr] ? this_.io_read(this_._addr) : this_.memmap[this_._addr >> 13][this_._addr & 0x1FFF]); + this_.reg_y = this_.readMem(this_._addr); this_.flag_n = (this_.reg_y & 0x80) >> 7; this_.flag_z = (this_.reg_y & 0xFF) ? 0 : 1; this_.cycles += 2; }, + // 0xA1 LDA (indirect,X) function opA1(this_) { - this_._tmp1 = (this_.memmap[this_.reg_pc >> 13][this_.reg_pc & 0x1FFF] + this_.reg_x) & 0xFF; - this_._addr = (((this_._tmp1 < 0xFFFF ? this_.memmap[(this_._tmp1 + 1) >> 13][(this_._tmp1 + 1) & 0x1FFF] : this_.ram[0]) << 8) | this_.memmap[this_._tmp1 >> 13][this_._tmp1 & 0x1FFF]); + this_._tmp1 = (this_.readMem(this_.reg_pc) + this_.reg_x) & 0xFF; + this_._addr = (this_.readMem((this_._tmp1 + 1) & 0xFF) << 8) | this_.readMem(this_._tmp1); this_.reg_pc = (this_.reg_pc + 1) & 0xFFFF; - this_.reg_a = (this_.io_read_map[this_._addr] ? this_.io_read(this_._addr) : this_.memmap[this_._addr >> 13][this_._addr & 0x1FFF]); + this_.reg_a = this_.readMem(this_._addr); this_.flag_n = (this_.reg_a & 0x80) >> 7; this_.flag_z = (this_.reg_a & 0xFF) ? 0 : 1; this_.cycles += 6; }, + // 0xA2 LDX imm function opA2(this_) { this_._addr = this_.reg_pc; this_.reg_pc = (this_.reg_pc + 1) & 0xFFFF; - this_.reg_x = (this_.io_read_map[this_._addr] ? this_.io_read(this_._addr) : this_.memmap[this_._addr >> 13][this_._addr & 0x1FFF]); + this_.reg_x = this_.readMem(this_._addr); this_.flag_n = (this_.reg_x & 0x80) >> 7; this_.flag_z = (this_.reg_x & 0xFF) ? 0 : 1; this_.cycles += 2; }, + // 0xA3 未使用 function opA3(this_) { this_.cycles += 1; }, + // 0xA4 LDY zp function opA4(this_) { - this_._addr = this_.memmap[this_.reg_pc >> 13][this_.reg_pc & 0x1FFF]; + this_._addr = this_.readMem(this_.reg_pc); this_.reg_pc = (this_.reg_pc + 1) & 0xFFFF; - this_.reg_y = (this_.io_read_map[this_._addr] ? this_.io_read(this_._addr) : this_.memmap[this_._addr >> 13][this_._addr & 0x1FFF]); + this_.reg_y = this_.readMem(this_._addr); this_.flag_n = (this_.reg_y & 0x80) >> 7; this_.flag_z = (this_.reg_y & 0xFF) ? 0 : 1; this_.cycles += 3; }, + // 0xA5 LDA zp function opA5(this_) { - this_._addr = this_.memmap[this_.reg_pc >> 13][this_.reg_pc & 0x1FFF]; + this_._addr = this_.readMem(this_.reg_pc); this_.reg_pc = (this_.reg_pc + 1) & 0xFFFF; - this_.reg_a = (this_.io_read_map[this_._addr] ? this_.io_read(this_._addr) : this_.memmap[this_._addr >> 13][this_._addr & 0x1FFF]); + this_.reg_a = this_.readMem(this_._addr); this_.flag_n = (this_.reg_a & 0x80) >> 7; this_.flag_z = (this_.reg_a & 0xFF) ? 0 : 1; this_.cycles += 3; }, + // 0xA6 LDX zp function opA6(this_) { - this_._addr = this_.memmap[this_.reg_pc >> 13][this_.reg_pc & 0x1FFF]; + this_._addr = this_.readMem(this_.reg_pc); this_.reg_pc = (this_.reg_pc + 1) & 0xFFFF; - this_.reg_x = (this_.io_read_map[this_._addr] ? this_.io_read(this_._addr) : this_.memmap[this_._addr >> 13][this_._addr & 0x1FFF]); + this_.reg_x = this_.readMem(this_._addr); this_.flag_n = (this_.reg_x & 0x80) >> 7; this_.flag_z = (this_.reg_x & 0xFF) ? 0 : 1; this_.cycles += 3; }, + // 0xA7 SMB4 zp function opA7(this_) { - this_._addr = this_.memmap[this_.reg_pc >> 13][this_.reg_pc & 0x1FFF]; + this_._addr = this_.readMem(this_.reg_pc); this_.reg_pc = (this_.reg_pc + 1) & 0xFFFF; - this_._tmp1 = (this_.io_read_map[this_._addr] ? this_.io_read(this_._addr) : this_.memmap[this_._addr >> 13][this_._addr & 0x1FFF]) | 0x04; + this_._tmp1 = this_.readMem(this_._addr) | 0x04; + this_.writeMem(this_._addr, this_._tmp1); this_.flag_n = (this_._tmp1 & 0x80) >> 7; this_.flag_z = (this_._tmp1 & 0xFF) ? 0 : 1; - if (this_.io_write_map[this_._addr]) { - this_.io_write(this_._addr, this_._tmp1); - } else { - this_.memmap[this_._addr >> 13][this_._addr & 0x1FFF] = this_._tmp1; - } this_.cycles += 5; }, + // 0xA8 TAY function opA8(this_) { this_.reg_y = this_.reg_a; this_.flag_n = (this_.reg_y & 0x80) >> 7; this_.flag_z = (this_.reg_y & 0xFF) ? 0 : 1; this_.cycles += 2; }, + // 0xA9 LDA imm function opA9(this_) { this_._addr = this_.reg_pc; this_.reg_pc = (this_.reg_pc + 1) & 0xFFFF; - this_.reg_a = (this_.io_read_map[this_._addr] ? this_.io_read(this_._addr) : this_.memmap[this_._addr >> 13][this_._addr & 0x1FFF]); + this_.reg_a = this_.readMem(this_._addr); this_.flag_n = (this_.reg_a & 0x80) >> 7; this_.flag_z = (this_.reg_a & 0xFF) ? 0 : 1; this_.cycles += 2; }, + // 0xAA TAX function opAA(this_) { this_.reg_x = this_.reg_a; this_.flag_n = (this_.reg_x & 0x80) >> 7; this_.flag_z = (this_.reg_x & 0xFF) ? 0 : 1; this_.cycles += 2; }, + // 0xAB 未使用 function opAB(this_) { this_.cycles += 1; }, + // 0xAC LDY abs function opAC(this_) { - this_._addr = (((this_.reg_pc < 0xFFFF ? this_.memmap[(this_.reg_pc + 1) >> 13][(this_.reg_pc + 1) & 0x1FFF] : this_.ram[0]) << 8) | this_.memmap[this_.reg_pc >> 13][this_.reg_pc & 0x1FFF]); + this_._addr = (this_.readMem(this_.reg_pc + 1) << 8) | this_.readMem(this_.reg_pc); this_.reg_pc = (this_.reg_pc + 2) & 0xFFFF; - this_.reg_y = (this_.io_read_map[this_._addr] ? this_.io_read(this_._addr) : this_.memmap[this_._addr >> 13][this_._addr & 0x1FFF]); + this_.reg_y = this_.readMem(this_._addr); this_.flag_n = (this_.reg_y & 0x80) >> 7; this_.flag_z = (this_.reg_y & 0xFF) ? 0 : 1; this_.cycles += 4; }, + // 0xAD LDA abs function opAD(this_) { - this_._addr = (((this_.reg_pc < 0xFFFF ? this_.memmap[(this_.reg_pc + 1) >> 13][(this_.reg_pc + 1) & 0x1FFF] : this_.ram[0]) << 8) | this_.memmap[this_.reg_pc >> 13][this_.reg_pc & 0x1FFF]); + this_._addr = (this_.readMem(this_.reg_pc + 1) << 8) | this_.readMem(this_.reg_pc); this_.reg_pc = (this_.reg_pc + 2) & 0xFFFF; - this_.reg_a = (this_.io_read_map[this_._addr] ? this_.io_read(this_._addr) : this_.memmap[this_._addr >> 13][this_._addr & 0x1FFF]); + this_.reg_a = this_.readMem(this_._addr); this_.flag_n = (this_.reg_a & 0x80) >> 7; this_.flag_z = (this_.reg_a & 0xFF) ? 0 : 1; this_.cycles += 4; }, + // 0xAE LDX abs function opAE(this_) { - this_._addr = (((this_.reg_pc < 0xFFFF ? this_.memmap[(this_.reg_pc + 1) >> 13][(this_.reg_pc + 1) & 0x1FFF] : this_.ram[0]) << 8) | this_.memmap[this_.reg_pc >> 13][this_.reg_pc & 0x1FFF]); + this_._addr = (this_.readMem(this_.reg_pc + 1) << 8) | this_.readMem(this_.reg_pc); this_.reg_pc = (this_.reg_pc + 2) & 0xFFFF; - this_.reg_x = (this_.io_read_map[this_._addr] ? this_.io_read(this_._addr) : this_.memmap[this_._addr >> 13][this_._addr & 0x1FFF]); + this_.reg_x = this_.readMem(this_._addr); this_.flag_n = (this_.reg_x & 0x80) >> 7; this_.flag_z = (this_.reg_x & 0xFF) ? 0 : 1; this_.cycles += 4; }, + // 0xAF SMB5 zp function opAF(this_) { - this_._addr = this_.memmap[this_.reg_pc >> 13][this_.reg_pc & 0x1FFF]; - this_.reg_pc = (this_.reg_pc + 1) & 0xFFFF; - if ((this_.io_read_map[this_._addr] ? this_.io_read(this_._addr) : this_.memmap[this_._addr >> 13][this_._addr & 0x1FFF]) & 0x04) { + this_._addr = this_.readMem(this_.reg_pc); + this_._tmp2 = this_.readMem(this_.reg_pc + 1); + this_.reg_pc = (this_.reg_pc + 2) & 0xFFFF; + if (this_.readMem(this_._addr) & 0x04) { this_.reg_pc = (this_.reg_pc + this_._tmp2) & 0xFFFF; this_.cycles++; } this_.cycles += 5; }, + // 0xB0 BCS function opB0(this_) { - this_._tmp1 = this_.memmap[this_.reg_pc >> 13][this_.reg_pc & 0x1FFF]; + this_._tmp1 = this_.readMem(this_.reg_pc); this_._tmp2 = this_._tmp1 - ((this_._tmp1 & 0x80) << 1); this_.reg_pc = (this_.reg_pc + 1) & 0xFFFF; if (this_.flag_c) { @@ -1651,256 +1808,282 @@ M65C02Context.prototype.op_func_tbl = [ } this_.cycles += 2; }, + // 0xB1 LDA (indirect),Y function opB1(this_) { - this_._tmp1 = this_.memmap[this_.reg_pc >> 13][this_.reg_pc & 0x1FFF]; - this_._addr = ((((this_._tmp1 < 0xFFFF ? this_.memmap[(this_._tmp1 + 1) >> 13][(this_._tmp1 + 1) & 0x1FFF] : this_.ram[0]) << 8) | this_.memmap[this_._tmp1 >> 13][this_._tmp1 & 0x1FFF]) + this_.reg_y) & 0xFFFF; + this_._tmp1 = this_.readMem(this_.reg_pc); + this_._addr = (this_.readMem((this_._tmp1 + 1) & 0xFF) << 8) | this_.readMem(this_._tmp1); + if ((this_._addr & 0xFF00) !== ((this_._addr + this_.reg_y) & 0xFF00)) { + this_.cycles++; + } + this_._addr = (this_._addr + this_.reg_y) & 0xFFFF; this_.reg_pc = (this_.reg_pc + 1) & 0xFFFF; - this_.reg_a = (this_.io_read_map[this_._addr] ? this_.io_read(this_._addr) : this_.memmap[this_._addr >> 13][this_._addr & 0x1FFF]); + this_.reg_a = this_.readMem(this_._addr); this_.flag_n = (this_.reg_a & 0x80) >> 7; this_.flag_z = (this_.reg_a & 0xFF) ? 0 : 1; this_.cycles += 5; }, + // 0xB2 LDA (indirect) function opB2(this_) { - this_._tmp1 = this_.memmap[this_.reg_pc >> 13][this_.reg_pc & 0x1FFF]; - this_._addr = ((this_._tmp1 < 0xFF ? this_.ram[this_._tmp1 + 1] : this_.ram[0]) << 8) | this_.ram[this_._tmp1]; + this_._tmp1 = this_.readMem(this_.reg_pc); + this_._addr = (this_.readMem((this_._tmp1 + 1) & 0xFF) << 8) | this_.readMem(this_._tmp1); this_.reg_pc = (this_.reg_pc + 1) & 0xFFFF; - this_.reg_a = (this_.io_read_map[this_._addr] ? this_.io_read(this_._addr) : this_.memmap[this_._addr >> 13][this_._addr & 0x1FFF]); + this_.reg_a = this_.readMem(this_._addr); this_.flag_n = (this_.reg_a & 0x80) >> 7; this_.flag_z = (this_.reg_a & 0xFF) ? 0 : 1; this_.cycles += 5; }, + // 0xB3 未使用 function opB3(this_) { this_.cycles += 1; }, + // 0xB4 LDY zp,X function opB4(this_) { - this_._addr = (this_.memmap[this_.reg_pc >> 13][this_.reg_pc & 0x1FFF] + this_.reg_x) & 0xFF; + this_._addr = (this_.readMem(this_.reg_pc) + this_.reg_x) & 0xFF; this_.reg_pc = (this_.reg_pc + 1) & 0xFFFF; - this_.reg_y = (this_.io_read_map[this_._addr] ? this_.io_read(this_._addr) : this_.memmap[this_._addr >> 13][this_._addr & 0x1FFF]); + this_.reg_y = this_.readMem(this_._addr); this_.flag_n = (this_.reg_y & 0x80) >> 7; this_.flag_z = (this_.reg_y & 0xFF) ? 0 : 1; this_.cycles += 4; }, + // 0xB5 LDA zp,X function opB5(this_) { - this_._addr = (this_.memmap[this_.reg_pc >> 13][this_.reg_pc & 0x1FFF] + this_.reg_x) & 0xFF; + this_._addr = (this_.readMem(this_.reg_pc) + this_.reg_x) & 0xFF; this_.reg_pc = (this_.reg_pc + 1) & 0xFFFF; - this_.reg_a = (this_.io_read_map[this_._addr] ? this_.io_read(this_._addr) : this_.memmap[this_._addr >> 13][this_._addr & 0x1FFF]); + this_.reg_a = this_.readMem(this_._addr); this_.flag_n = (this_.reg_a & 0x80) >> 7; this_.flag_z = (this_.reg_a & 0xFF) ? 0 : 1; this_.cycles += 4; }, + // 0xB6 LDX zp,Y function opB6(this_) { - this_._addr = (this_.memmap[this_.reg_pc >> 13][this_.reg_pc & 0x1FFF] + this_.reg_y) & 0xFF; + this_._addr = (this_.readMem(this_.reg_pc) + this_.reg_y) & 0xFF; this_.reg_pc = (this_.reg_pc + 1) & 0xFFFF; - this_.reg_x = (this_.io_read_map[this_._addr] ? this_.io_read(this_._addr) : this_.memmap[this_._addr >> 13][this_._addr & 0x1FFF]); + this_.reg_x = this_.readMem(this_._addr); this_.flag_n = (this_.reg_x & 0x80) >> 7; this_.flag_z = (this_.reg_x & 0xFF) ? 0 : 1; this_.cycles += 4; }, + // 0xB7 SMB6 zp function opB7(this_) { - this_._addr = this_.memmap[this_.reg_pc >> 13][this_.reg_pc & 0x1FFF]; + this_._addr = this_.readMem(this_.reg_pc); this_.reg_pc = (this_.reg_pc + 1) & 0xFFFF; - this_._tmp1 = (this_.io_read_map[this_._addr] ? this_.io_read(this_._addr) : this_.memmap[this_._addr >> 13][this_._addr & 0x1FFF]) | 0x08; + this_._tmp1 = this_.readMem(this_._addr) | 0x08; + this_.writeMem(this_._addr, this_._tmp1); this_.flag_n = (this_._tmp1 & 0x80) >> 7; this_.flag_z = (this_._tmp1 & 0xFF) ? 0 : 1; - if (this_.io_write_map[this_._addr]) { - this_.io_write(this_._addr, this_._tmp1); - } else { - this_.memmap[this_._addr >> 13][this_._addr & 0x1FFF] = this_._tmp1; - } this_.cycles += 5; }, + // 0xB8 CLV function opB8(this_) { this_.flag_v = 0; this_.cycles += 2; }, + // 0xB9 LDA abs,Y function opB9(this_) { - this_._addr = ((((this_.reg_pc < 0xFFFF ? this_.memmap[(this_.reg_pc + 1) >> 13][(this_.reg_pc + 1) & 0x1FFF] : this_.ram[0]) << 8) | this_.memmap[this_.reg_pc >> 13][this_.reg_pc & 0x1FFF]) + this_.reg_y) & 0xFFFF; + this_._addr = (this_.readMem(this_.reg_pc + 1) << 8) | this_.readMem(this_.reg_pc); + if ((this_._addr & 0xFF00) !== ((this_._addr + this_.reg_y) & 0xFF00)) { + this_.cycles++; + } + this_._addr = (this_._addr + this_.reg_y) & 0xFFFF; this_.reg_pc = (this_.reg_pc + 2) & 0xFFFF; - this_.reg_a = (this_.io_read_map[this_._addr] ? this_.io_read(this_._addr) : this_.memmap[this_._addr >> 13][this_._addr & 0x1FFF]); + this_.reg_a = this_.readMem(this_._addr); this_.flag_n = (this_.reg_a & 0x80) >> 7; this_.flag_z = (this_.reg_a & 0xFF) ? 0 : 1; this_.cycles += 4; }, + // 0xBA TSX function opBA(this_) { this_.reg_x = (this_.reg_sp & 0xFF); this_.flag_n = (this_.reg_x & 0x80) >> 7; this_.flag_z = (this_.reg_x & 0xFF) ? 0 : 1; this_.cycles += 2; }, + // 0xBB 未使用 function opBB(this_) { this_.cycles += 1; }, + // 0xBC LDY abs,X function opBC(this_) { - this_._addr = ((((this_.reg_pc < 0xFFFF ? this_.memmap[(this_.reg_pc + 1) >> 13][(this_.reg_pc + 1) & 0x1FFF] : this_.ram[0]) << 8) | this_.memmap[this_.reg_pc >> 13][this_.reg_pc & 0x1FFF]) + this_.reg_x) & 0xFFFF; + this_._addr = ((this_.readMem(this_.reg_pc + 1) << 8) | this_.readMem(this_.reg_pc)) + this_.reg_x; this_.reg_pc = (this_.reg_pc + 2) & 0xFFFF; - this_.reg_y = (this_.io_read_map[this_._addr] ? this_.io_read(this_._addr) : this_.memmap[this_._addr >> 13][this_._addr & 0x1FFF]); + this_.reg_y = this_.readMem(this_._addr); this_.flag_n = (this_.reg_y & 0x80) >> 7; this_.flag_z = (this_.reg_y & 0xFF) ? 0 : 1; this_.cycles += 4; }, + // 0xBD LDA abs,X function opBD(this_) { - this_._addr = ((((this_.reg_pc < 0xFFFF ? this_.memmap[(this_.reg_pc + 1) >> 13][(this_.reg_pc + 1) & 0x1FFF] : this_.ram[0]) << 8) | this_.memmap[this_.reg_pc >> 13][this_.reg_pc & 0x1FFF]) + this_.reg_x) & 0xFFFF; + this_._addr = ((this_.readMem(this_.reg_pc + 1) << 8) | this_.readMem(this_.reg_pc)) + this_.reg_x; this_.reg_pc = (this_.reg_pc + 2) & 0xFFFF; - this_.reg_a = (this_.io_read_map[this_._addr] ? this_.io_read(this_._addr) : this_.memmap[this_._addr >> 13][this_._addr & 0x1FFF]); + this_.reg_a = this_.readMem(this_._addr); this_.flag_n = (this_.reg_a & 0x80) >> 7; this_.flag_z = (this_.reg_a & 0xFF) ? 0 : 1; this_.cycles += 4; }, + // 0xBE LDX abs,Y function opBE(this_) { - this_._addr = ((((this_.reg_pc < 0xFFFF ? this_.memmap[(this_.reg_pc + 1) >> 13][(this_.reg_pc + 1) & 0x1FFF] : this_.ram[0]) << 8) | this_.memmap[this_.reg_pc >> 13][this_.reg_pc & 0x1FFF]) + this_.reg_y) & 0xFFFF; + this_._addr = ((this_.readMem(this_.reg_pc + 1) << 8) | this_.readMem(this_.reg_pc)) + this_.reg_y; this_.reg_pc = (this_.reg_pc + 2) & 0xFFFF; - this_.reg_x = (this_.io_read_map[this_._addr] ? this_.io_read(this_._addr) : this_.memmap[this_._addr >> 13][this_._addr & 0x1FFF]); + this_.reg_x = this_.readMem(this_._addr); this_.flag_n = (this_.reg_x & 0x80) >> 7; this_.flag_z = (this_.reg_x & 0xFF) ? 0 : 1; this_.cycles += 4; }, + // 0xBF SMB7 zp function opBF(this_) { - this_._addr = this_.memmap[this_.reg_pc >> 13][this_.reg_pc & 0x1FFF]; - this_.reg_pc = (this_.reg_pc + 1) & 0xFFFF; - if ((this_.io_read_map[this_._addr] ? this_.io_read(this_._addr) : this_.memmap[this_._addr >> 13][this_._addr & 0x1FFF]) & 0x08) { + this_._addr = this_.readMem(this_.reg_pc); + this_._tmp2 = this_.readMem(this_.reg_pc + 1); + this_.reg_pc = (this_.reg_pc + 2) & 0xFFFF; + if (this_.readMem(this_._addr) & 0x08) { this_.reg_pc = (this_.reg_pc + this_._tmp2) & 0xFFFF; this_.cycles++; } this_.cycles += 5; }, + // 0xC0 CPY imm function opC0(this_) { this_._addr = this_.reg_pc; this_.reg_pc = (this_.reg_pc + 1) & 0xFFFF; - this_._tmp1 = this_.reg_y - (this_.io_read_map[this_._addr] ? this_.io_read(this_._addr) : this_.memmap[this_._addr >> 13][this_._addr & 0x1FFF]); - this_.flag_c = this_._tmp1 < 0 ? 0 : 1; + this_._tmp1 = this_.reg_y - this_.readMem(this_._addr); + this_.flag_c = (this_._tmp1 >= 0) ? 1 : 0; this_.flag_n = (this_._tmp1 & 0x80) >> 7; this_.flag_z = (this_._tmp1 & 0xFF) ? 0 : 1; this_.cycles += 2; }, + // 0xC1 CMP (indirect,X) function opC1(this_) { - this_._tmp1 = (this_.memmap[this_.reg_pc >> 13][this_.reg_pc & 0x1FFF] + this_.reg_x) & 0xFF; - this_._addr = (((this_._tmp1 < 0xFFFF ? this_.memmap[(this_._tmp1 + 1) >> 13][(this_._tmp1 + 1) & 0x1FFF] : this_.ram[0]) << 8) | this_.memmap[this_._tmp1 >> 13][this_._tmp1 & 0x1FFF]); + this_._tmp1 = (this_.readMem(this_.reg_pc) + this_.reg_x) & 0xFF; + this_._addr = (this_.readMem((this_._tmp1 + 1) & 0xFF) << 8) | this_.readMem(this_._tmp1); this_.reg_pc = (this_.reg_pc + 1) & 0xFFFF; - this_._tmp1 = this_.reg_a - (this_.io_read_map[this_._addr] ? this_.io_read(this_._addr) : this_.memmap[this_._addr >> 13][this_._addr & 0x1FFF]); - this_.flag_c = this_._tmp1 < 0 ? 0 : 1; + this_._tmp1 = this_.reg_a - this_.readMem(this_._addr); + this_.flag_c = (this_._tmp1 >= 0) ? 1 : 0; this_.flag_n = (this_._tmp1 & 0x80) >> 7; this_.flag_z = (this_._tmp1 & 0xFF) ? 0 : 1; this_.cycles += 6; }, + // 0xC2 未使用 function opC2(this_) { this_.reg_pc = (this_.reg_pc + 1) & 0xFFFF; this_.cycles += 2; }, + // 0xC3 未使用 function opC3(this_) { this_.cycles += 1; }, + // 0xC4 CPY zp function opC4(this_) { - this_._addr = this_.memmap[this_.reg_pc >> 13][this_.reg_pc & 0x1FFF]; + this_._addr = this_.readMem(this_.reg_pc); this_.reg_pc = (this_.reg_pc + 1) & 0xFFFF; - this_._tmp1 = this_.reg_y - (this_.io_read_map[this_._addr] ? this_.io_read(this_._addr) : this_.memmap[this_._addr >> 13][this_._addr & 0x1FFF]); - this_.flag_c = this_._tmp1 < 0 ? 0 : 1; + this_._tmp1 = this_.reg_y - this_.readMem(this_._addr); + this_.flag_c = (this_._tmp1 >= 0) ? 1 : 0; this_.flag_n = (this_._tmp1 & 0x80) >> 7; this_.flag_z = (this_._tmp1 & 0xFF) ? 0 : 1; this_.cycles += 3; }, + // 0xC5 CMP zp function opC5(this_) { - this_._addr = this_.memmap[this_.reg_pc >> 13][this_.reg_pc & 0x1FFF]; + this_._addr = this_.readMem(this_.reg_pc); this_.reg_pc = (this_.reg_pc + 1) & 0xFFFF; - this_._tmp1 = this_.reg_a - (this_.io_read_map[this_._addr] ? this_.io_read(this_._addr) : this_.memmap[this_._addr >> 13][this_._addr & 0x1FFF]); - this_.flag_c = this_._tmp1 < 0 ? 0 : 1; + this_._tmp1 = this_.reg_a - this_.readMem(this_._addr); + this_.flag_c = (this_._tmp1 >= 0) ? 1 : 0; this_.flag_n = (this_._tmp1 & 0x80) >> 7; this_.flag_z = (this_._tmp1 & 0xFF) ? 0 : 1; this_.cycles += 3; }, + // 0xC6 DEC zp function opC6(this_) { - this_._addr = this_.memmap[this_.reg_pc >> 13][this_.reg_pc & 0x1FFF]; + this_._addr = this_.readMem(this_.reg_pc); this_.reg_pc = (this_.reg_pc + 1) & 0xFFFF; - this_._tmp1 = ((this_.io_read_map[this_._addr] ? this_.io_read(this_._addr) : this_.memmap[this_._addr >> 13][this_._addr & 0x1FFF]) - 1) & 0xFF; + this_._tmp1 = (this_.readMem(this_._addr) - 1) & 0xFF; + this_.writeMem(this_._addr, this_._tmp1); this_.flag_n = (this_._tmp1 & 0x80) >> 7; this_.flag_z = (this_._tmp1 & 0xFF) ? 0 : 1; - if (this_.io_write_map[this_._addr]) { - this_.io_write(this_._addr, this_._tmp1); - } else { - this_.memmap[this_._addr >> 13][this_._addr & 0x1FFF] = this_._tmp1; - } this_.cycles += 5; }, + // 0xC7 SMB0 (BBR0?) - 实际是 SMB0 function opC7(this_) { - this_._addr = this_.memmap[this_.reg_pc >> 13][this_.reg_pc & 0x1FFF]; + this_._addr = this_.readMem(this_.reg_pc); this_.reg_pc = (this_.reg_pc + 1) & 0xFFFF; - this_._tmp1 = (this_.io_read_map[this_._addr] ? this_.io_read(this_._addr) : this_.memmap[this_._addr >> 13][this_._addr & 0x1FFF]) | 0x10; + this_._tmp1 = this_.readMem(this_._addr) | 0x10; + this_.writeMem(this_._addr, this_._tmp1); this_.flag_n = (this_._tmp1 & 0x80) >> 7; this_.flag_z = (this_._tmp1 & 0xFF) ? 0 : 1; - if (this_.io_write_map[this_._addr]) { - this_.io_write(this_._addr, this_._tmp1); - } else { - this_.memmap[this_._addr >> 13][this_._addr & 0x1FFF] = this_._tmp1; - } this_.cycles += 5; }, + // 0xC8 INY function opC8(this_) { this_.reg_y = (++this_.reg_y & 0xFF); this_.flag_n = (this_.reg_y & 0x80) >> 7; this_.flag_z = (this_.reg_y & 0xFF) ? 0 : 1; this_.cycles += 2; }, + // 0xC9 CMP imm function opC9(this_) { this_._addr = this_.reg_pc; this_.reg_pc = (this_.reg_pc + 1) & 0xFFFF; - this_._tmp1 = this_.reg_a - (this_.io_read_map[this_._addr] ? this_.io_read(this_._addr) : this_.memmap[this_._addr >> 13][this_._addr & 0x1FFF]); - this_.flag_c = this_._tmp1 < 0 ? 0 : 1; + this_._tmp1 = this_.reg_a - this_.readMem(this_._addr); + this_.flag_c = (this_._tmp1 >= 0) ? 1 : 0; this_.flag_n = (this_._tmp1 & 0x80) >> 7; this_.flag_z = (this_._tmp1 & 0xFF) ? 0 : 1; this_.cycles += 2; }, + // 0xCA DEX function opCA(this_) { this_.reg_x = (--this_.reg_x & 0xFF); this_.flag_n = (this_.reg_x & 0x80) >> 7; this_.flag_z = (this_.reg_x & 0xFF) ? 0 : 1; this_.cycles += 2; }, + // 0xCB WAI function opCB(this_) { this_.reg_pc = (this_.reg_pc - 1) & 0xFFFF; this_.wai = 1; this_.cycles += 3; }, + // 0xCC CPY abs function opCC(this_) { - this_._addr = (((this_.reg_pc < 0xFFFF ? this_.memmap[(this_.reg_pc + 1) >> 13][(this_.reg_pc + 1) & 0x1FFF] : this_.ram[0]) << 8) | this_.memmap[this_.reg_pc >> 13][this_.reg_pc & 0x1FFF]); + this_._addr = (this_.readMem(this_.reg_pc + 1) << 8) | this_.readMem(this_.reg_pc); this_.reg_pc = (this_.reg_pc + 2) & 0xFFFF; - this_._tmp1 = this_.reg_y - (this_.io_read_map[this_._addr] ? this_.io_read(this_._addr) : this_.memmap[this_._addr >> 13][this_._addr & 0x1FFF]); - this_.flag_c = this_._tmp1 < 0 ? 0 : 1; + this_._tmp1 = this_.reg_y - this_.readMem(this_._addr); + this_.flag_c = (this_._tmp1 >= 0) ? 1 : 0; this_.flag_n = (this_._tmp1 & 0x80) >> 7; this_.flag_z = (this_._tmp1 & 0xFF) ? 0 : 1; this_.cycles += 4; }, + // 0xCD CMP abs function opCD(this_) { - this_._addr = (((this_.reg_pc < 0xFFFF ? this_.memmap[(this_.reg_pc + 1) >> 13][(this_.reg_pc + 1) & 0x1FFF] : this_.ram[0]) << 8) | this_.memmap[this_.reg_pc >> 13][this_.reg_pc & 0x1FFF]); + this_._addr = (this_.readMem(this_.reg_pc + 1) << 8) | this_.readMem(this_.reg_pc); this_.reg_pc = (this_.reg_pc + 2) & 0xFFFF; - this_._tmp1 = this_.reg_a - (this_.io_read_map[this_._addr] ? this_.io_read(this_._addr) : this_.memmap[this_._addr >> 13][this_._addr & 0x1FFF]); - this_.flag_c = this_._tmp1 < 0 ? 0 : 1; + this_._tmp1 = this_.reg_a - this_.readMem(this_._addr); + this_.flag_c = (this_._tmp1 >= 0) ? 1 : 0; this_.flag_n = (this_._tmp1 & 0x80) >> 7; this_.flag_z = (this_._tmp1 & 0xFF) ? 0 : 1; this_.cycles += 4; }, + // 0xCE DEC abs function opCE(this_) { - this_._addr = (((this_.reg_pc < 0xFFFF ? this_.memmap[(this_.reg_pc + 1) >> 13][(this_.reg_pc + 1) & 0x1FFF] : this_.ram[0]) << 8) | this_.memmap[this_.reg_pc >> 13][this_.reg_pc & 0x1FFF]); + this_._addr = (this_.readMem(this_.reg_pc + 1) << 8) | this_.readMem(this_.reg_pc); this_.reg_pc = (this_.reg_pc + 2) & 0xFFFF; - this_._tmp1 = ((this_.io_read_map[this_._addr] ? this_.io_read(this_._addr) : this_.memmap[this_._addr >> 13][this_._addr & 0x1FFF]) - 1) & 0xFF; + this_._tmp1 = (this_.readMem(this_._addr) - 1) & 0xFF; + this_.writeMem(this_._addr, this_._tmp1); this_.flag_n = (this_._tmp1 & 0x80) >> 7; this_.flag_z = (this_._tmp1 & 0xFF) ? 0 : 1; - if (this_.io_write_map[this_._addr]) { - this_.io_write(this_._addr, this_._tmp1); - } else { - this_.memmap[this_._addr >> 13][this_._addr & 0x1FFF] = this_._tmp1; - } this_.cycles += 6; }, + // 0xCF SMB1 (BBR1?) - 实际是 SMB1 function opCF(this_) { - this_._addr = this_.memmap[this_.reg_pc >> 13][this_.reg_pc & 0x1FFF]; - this_.reg_pc = (this_.reg_pc + 1) & 0xFFFF; - if ((this_.io_read_map[this_._addr] ? this_.io_read(this_._addr) : this_.memmap[this_._addr >> 13][this_._addr & 0x1FFF]) & 0x10) { + this_._addr = this_.readMem(this_.reg_pc); + this_._tmp2 = this_.readMem(this_.reg_pc + 1); + this_.reg_pc = (this_.reg_pc + 2) & 0xFFFF; + if (this_.readMem(this_._addr) & 0x10) { this_.reg_pc = (this_.reg_pc + this_._tmp2) & 0xFFFF; this_.cycles++; } this_.cycles += 5; }, + // 0xD0 BNE function opD0(this_) { - this_._tmp1 = this_.memmap[this_.reg_pc >> 13][this_.reg_pc & 0x1FFF]; + this_._tmp1 = this_.readMem(this_.reg_pc); this_._tmp2 = this_._tmp1 - ((this_._tmp1 & 0x80) << 1); this_.reg_pc = (this_.reg_pc + 1) & 0xFFFF; if (!this_.flag_z) { @@ -1909,154 +2092,168 @@ M65C02Context.prototype.op_func_tbl = [ } this_.cycles += 2; }, + // 0xD1 CMP (indirect),Y function opD1(this_) { - this_._tmp1 = this_.memmap[this_.reg_pc >> 13][this_.reg_pc & 0x1FFF]; - this_._addr = ((((this_._tmp1 < 0xFFFF ? this_.memmap[(this_._tmp1 + 1) >> 13][(this_._tmp1 + 1) & 0x1FFF] : this_.ram[0]) << 8) | this_.memmap[this_._tmp1 >> 13][this_._tmp1 & 0x1FFF]) + this_.reg_y) & 0xFFFF; + this_._tmp1 = this_.readMem(this_.reg_pc); + this_._addr = (this_.readMem((this_._tmp1 + 1) & 0xFF) << 8) | this_.readMem(this_._tmp1); + if ((this_._addr & 0xFF00) !== ((this_._addr + this_.reg_y) & 0xFF00)) { + this_.cycles++; + } + this_._addr = (this_._addr + this_.reg_y) & 0xFFFF; this_.reg_pc = (this_.reg_pc + 1) & 0xFFFF; - this_._tmp1 = this_.reg_a - (this_.io_read_map[this_._addr] ? this_.io_read(this_._addr) : this_.memmap[this_._addr >> 13][this_._addr & 0x1FFF]); - this_.flag_c = this_._tmp1 < 0 ? 0 : 1; + this_._tmp1 = this_.reg_a - this_.readMem(this_._addr); + this_.flag_c = (this_._tmp1 >= 0) ? 1 : 0; this_.flag_n = (this_._tmp1 & 0x80) >> 7; this_.flag_z = (this_._tmp1 & 0xFF) ? 0 : 1; this_.cycles += 5; }, + // 0xD2 CMP (indirect) function opD2(this_) { - this_._tmp1 = this_.memmap[this_.reg_pc >> 13][this_.reg_pc & 0x1FFF]; - this_._addr = ((this_._tmp1 < 0xFF ? this_.ram[this_._tmp1 + 1] : this_.ram[0]) << 8) | this_.ram[this_._tmp1]; + this_._tmp1 = this_.readMem(this_.reg_pc); + this_._addr = (this_.readMem((this_._tmp1 + 1) & 0xFF) << 8) | this_.readMem(this_._tmp1); this_.reg_pc = (this_.reg_pc + 1) & 0xFFFF; - this_._tmp1 = this_.reg_a - (this_.io_read_map[this_._addr] ? this_.io_read(this_._addr) : this_.memmap[this_._addr >> 13][this_._addr & 0x1FFF]); - this_.flag_c = this_._tmp1 < 0 ? 0 : 1; + this_._tmp1 = this_.reg_a - this_.readMem(this_._addr); + this_.flag_c = (this_._tmp1 >= 0) ? 1 : 0; this_.flag_n = (this_._tmp1 & 0x80) >> 7; this_.flag_z = (this_._tmp1 & 0xFF) ? 0 : 1; this_.cycles += 5; }, + // 0xD3 未使用 function opD3(this_) { this_.cycles += 1; }, + // 0xD4 未使用 function opD4(this_) { this_.reg_pc = (this_.reg_pc + 1) & 0xFFFF; this_.cycles += 4; }, + // 0xD5 CMP zp,X function opD5(this_) { - this_._addr = (this_.memmap[this_.reg_pc >> 13][this_.reg_pc & 0x1FFF] + this_.reg_x) & 0xFF; + this_._addr = (this_.readMem(this_.reg_pc) + this_.reg_x) & 0xFF; this_.reg_pc = (this_.reg_pc + 1) & 0xFFFF; - this_._tmp1 = this_.reg_a - (this_.io_read_map[this_._addr] ? this_.io_read(this_._addr) : this_.memmap[this_._addr >> 13][this_._addr & 0x1FFF]); - this_.flag_c = this_._tmp1 < 0 ? 0 : 1; + this_._tmp1 = this_.reg_a - this_.readMem(this_._addr); + this_.flag_c = (this_._tmp1 >= 0) ? 1 : 0; this_.flag_n = (this_._tmp1 & 0x80) >> 7; this_.flag_z = (this_._tmp1 & 0xFF) ? 0 : 1; this_.cycles += 4; }, + // 0xD6 DEC zp,X function opD6(this_) { - this_._addr = (this_.memmap[this_.reg_pc >> 13][this_.reg_pc & 0x1FFF] + this_.reg_x) & 0xFF; + this_._addr = (this_.readMem(this_.reg_pc) + this_.reg_x) & 0xFF; this_.reg_pc = (this_.reg_pc + 1) & 0xFFFF; - this_._tmp1 = ((this_.io_read_map[this_._addr] ? this_.io_read(this_._addr) : this_.memmap[this_._addr >> 13][this_._addr & 0x1FFF]) - 1) & 0xFF; + this_._tmp1 = (this_.readMem(this_._addr) - 1) & 0xFF; + this_.writeMem(this_._addr, this_._tmp1); this_.flag_n = (this_._tmp1 & 0x80) >> 7; this_.flag_z = (this_._tmp1 & 0xFF) ? 0 : 1; - if (this_.io_write_map[this_._addr]) { - this_.io_write(this_._addr, this_._tmp1); - } else { - this_.memmap[this_._addr >> 13][this_._addr & 0x1FFF] = this_._tmp1; - } this_.cycles += 6; }, + // 0xD7 SMB2 zp function opD7(this_) { - this_._addr = this_.memmap[this_.reg_pc >> 13][this_.reg_pc & 0x1FFF]; + this_._addr = this_.readMem(this_.reg_pc); this_.reg_pc = (this_.reg_pc + 1) & 0xFFFF; - this_._tmp1 = (this_.io_read_map[this_._addr] ? this_.io_read(this_._addr) : this_.memmap[this_._addr >> 13][this_._addr & 0x1FFF]) | 0x20; + this_._tmp1 = this_.readMem(this_._addr) | 0x20; + this_.writeMem(this_._addr, this_._tmp1); this_.flag_n = (this_._tmp1 & 0x80) >> 7; this_.flag_z = (this_._tmp1 & 0xFF) ? 0 : 1; - if (this_.io_write_map[this_._addr]) { - this_.io_write(this_._addr, this_._tmp1); - } else { - this_.memmap[this_._addr >> 13][this_._addr & 0x1FFF] = this_._tmp1; - } this_.cycles += 5; }, + // 0xD8 CLD function opD8(this_) { this_.flag_d = 0; this_.cycles += 2; }, + // 0xD9 CMP abs,Y function opD9(this_) { - this_._addr = ((((this_.reg_pc < 0xFFFF ? this_.memmap[(this_.reg_pc + 1) >> 13][(this_.reg_pc + 1) & 0x1FFF] : this_.ram[0]) << 8) | this_.memmap[this_.reg_pc >> 13][this_.reg_pc & 0x1FFF]) + this_.reg_y) & 0xFFFF; + this_._addr = (this_.readMem(this_.reg_pc + 1) << 8) | this_.readMem(this_.reg_pc); + if ((this_._addr & 0xFF00) !== ((this_._addr + this_.reg_y) & 0xFF00)) { + this_.cycles++; + } + this_._addr = (this_._addr + this_.reg_y) & 0xFFFF; this_.reg_pc = (this_.reg_pc + 2) & 0xFFFF; - this_._tmp1 = this_.reg_a - (this_.io_read_map[this_._addr] ? this_.io_read(this_._addr) : this_.memmap[this_._addr >> 13][this_._addr & 0x1FFF]); - this_.flag_c = this_._tmp1 < 0 ? 0 : 1; + this_._tmp1 = this_.reg_a - this_.readMem(this_._addr); + this_.flag_c = (this_._tmp1 >= 0) ? 1 : 0; this_.flag_n = (this_._tmp1 & 0x80) >> 7; this_.flag_z = (this_._tmp1 & 0xFF) ? 0 : 1; this_.cycles += 4; }, + // 0xDA PHX function opDA(this_) { - this_.ram[this_.reg_sp] = this_.reg_x; + this_.writeMem(this_.reg_sp, this_.reg_x); this_.reg_sp = --this_.reg_sp & 0xFF | 0x100; this_.cycles += 3; }, + // 0xDB STP function opDB(this_) { this_.reg_pc = (this_.reg_pc - 1) & 0xFFFF; this_.stp = 1; this_.cycles += 3; }, + // 0xDC 未使用 function opDC(this_) { this_.reg_pc = (this_.reg_pc + 2) & 0xFFFF; this_.cycles += 4; }, + // 0xDD CMP abs,X function opDD(this_) { - this_._addr = ((((this_.reg_pc < 0xFFFF ? this_.memmap[(this_.reg_pc + 1) >> 13][(this_.reg_pc + 1) & 0x1FFF] : this_.ram[0]) << 8) | this_.memmap[this_.reg_pc >> 13][this_.reg_pc & 0x1FFF]) + this_.reg_x) & 0xFFFF; + this_._addr = ((this_.readMem(this_.reg_pc + 1) << 8) | this_.readMem(this_.reg_pc)) + this_.reg_x; this_.reg_pc = (this_.reg_pc + 2) & 0xFFFF; - this_._tmp1 = this_.reg_a - (this_.io_read_map[this_._addr] ? this_.io_read(this_._addr) : this_.memmap[this_._addr >> 13][this_._addr & 0x1FFF]); - this_.flag_c = this_._tmp1 < 0 ? 0 : 1; + this_._tmp1 = this_.reg_a - this_.readMem(this_._addr); + this_.flag_c = (this_._tmp1 >= 0) ? 1 : 0; this_.flag_n = (this_._tmp1 & 0x80) >> 7; this_.flag_z = (this_._tmp1 & 0xFF) ? 0 : 1; this_.cycles += 4; }, + // 0xDE DEC abs,X function opDE(this_) { - this_._addr = ((((this_.reg_pc < 0xFFFF ? this_.memmap[(this_.reg_pc + 1) >> 13][(this_.reg_pc + 1) & 0x1FFF] : this_.ram[0]) << 8) | this_.memmap[this_.reg_pc >> 13][this_.reg_pc & 0x1FFF]) + this_.reg_x) & 0xFFFF; + this_._addr = ((this_.readMem(this_.reg_pc + 1) << 8) | this_.readMem(this_.reg_pc)) + this_.reg_x; this_.reg_pc = (this_.reg_pc + 2) & 0xFFFF; - this_._tmp1 = ((this_.io_read_map[this_._addr] ? this_.io_read(this_._addr) : this_.memmap[this_._addr >> 13][this_._addr & 0x1FFF]) - 1) & 0xFF; + this_._tmp1 = (this_.readMem(this_._addr) - 1) & 0xFF; + this_.writeMem(this_._addr, this_._tmp1); this_.flag_n = (this_._tmp1 & 0x80) >> 7; this_.flag_z = (this_._tmp1 & 0xFF) ? 0 : 1; - if (this_.io_write_map[this_._addr]) { - this_.io_write(this_._addr, this_._tmp1); - } else { - this_.memmap[this_._addr >> 13][this_._addr & 0x1FFF] = this_._tmp1; - } this_.cycles += 6; }, + // 0xDF SMB3 zp function opDF(this_) { - this_._addr = this_.memmap[this_.reg_pc >> 13][this_.reg_pc & 0x1FFF]; - this_.reg_pc = (this_.reg_pc + 1) & 0xFFFF; - if ((this_.io_read_map[this_._addr] ? this_.io_read(this_._addr) : this_.memmap[this_._addr >> 13][this_._addr & 0x1FFF]) & 0x20) { + this_._addr = this_.readMem(this_.reg_pc); + this_._tmp2 = this_.readMem(this_.reg_pc + 1); + this_.reg_pc = (this_.reg_pc + 2) & 0xFFFF; + if (this_.readMem(this_._addr) & 0x20) { this_.reg_pc = (this_.reg_pc + this_._tmp2) & 0xFFFF; this_.cycles++; } this_.cycles += 5; }, + // 0xE0 CPX imm function opE0(this_) { this_._addr = this_.reg_pc; this_.reg_pc = (this_.reg_pc + 1) & 0xFFFF; - this_._tmp1 = this_.reg_x - (this_.io_read_map[this_._addr] ? this_.io_read(this_._addr) : this_.memmap[this_._addr >> 13][this_._addr & 0x1FFF]); - this_.flag_c = this_._tmp1 < 0 ? 0 : 1; + this_._tmp1 = this_.reg_x - this_.readMem(this_._addr); + this_.flag_c = (this_._tmp1 >= 0) ? 1 : 0; this_.flag_n = (this_._tmp1 & 0x80) >> 7; this_.flag_z = (this_._tmp1 & 0xFF) ? 0 : 1; this_.cycles += 2; }, + // 0xE1 SBC (indirect,X) function opE1(this_) { - this_._tmp1 = (this_.memmap[this_.reg_pc >> 13][this_.reg_pc & 0x1FFF] + this_.reg_x) & 0xFF; - this_._addr = (((this_._tmp1 < 0xFFFF ? this_.memmap[(this_._tmp1 + 1) >> 13][(this_._tmp1 + 1) & 0x1FFF] : this_.ram[0]) << 8) | this_.memmap[this_._tmp1 >> 13][this_._tmp1 & 0x1FFF]); + this_._tmp1 = (this_.readMem(this_.reg_pc) + this_.reg_x) & 0xFF; + this_._addr = (this_.readMem((this_._tmp1 + 1) & 0xFF) << 8) | this_.readMem(this_._tmp1); this_.reg_pc = (this_.reg_pc + 1) & 0xFFFF; - this_._tmp1 = (this_.io_read_map[this_._addr] ? this_.io_read(this_._addr) : this_.memmap[this_._addr >> 13][this_._addr & 0x1FFF]); + this_._tmp1 = this_.readMem(this_._addr); if (this_.flag_d) { - this_._tmp2 = ((this_.reg_a >> 4) * 10 + (this_.reg_a & 0x0F)) - ((this_._tmp1 >> 4) * 10 + (this_._tmp1 & 0x0F)) - 1 + this_.flag_c; - this_.flag_c = (this_._tmp2 < 0) ? 0 : 1; - this_._tmp2 %= 100; - if (this_._tmp2 < 0) { - this_._tmp2 += 100; - } - this_.reg_a = ((((this_._tmp2 / 10) % 10) << 4) | (this_._tmp2 % 10)); + var a_val = (this_.reg_a >> 4) * 10 + (this_.reg_a & 0x0F); + var m_val = (this_._tmp1 >> 4) * 10 + (this_._tmp1 & 0x0F); + var result = a_val - m_val - 1 + this_.flag_c; + this_.flag_c = (result >= 0) ? 1 : 0; + if (result < 0) result += 100; + result = result % 100; + this_.reg_a = ((Math.floor(result / 10) << 4) | (result % 10)); this_.flag_n = (this_.reg_a & 0x80) >> 7; this_.flag_z = (this_.reg_a & 0xFF) ? 0 : 1; - this_.cycles++ + this_.cycles++; } else { this_._tmp2 = this_.reg_a - this_._tmp1 - 1 + this_.flag_c; - this_.flag_c = (this_._tmp2 < 0) ? 0 : 1; + this_.flag_c = (this_._tmp2 >= 0) ? 1 : 0; this_.flag_v = ((this_.reg_a ^ this_._tmp1) & (this_.reg_a ^ this_._tmp2) & 0x80) >> 7; this_.reg_a = (this_._tmp2 & 0xFF); this_.flag_n = (this_.reg_a & 0x80) >> 7; @@ -2064,40 +2261,44 @@ M65C02Context.prototype.op_func_tbl = [ } this_.cycles += 6; }, + // 0xE2 未使用 function opE2(this_) { this_.reg_pc = (this_.reg_pc + 1) & 0xFFFF; this_.cycles += 2; }, + // 0xE3 未使用 function opE3(this_) { this_.cycles += 1; }, + // 0xE4 CPX zp function opE4(this_) { - this_._addr = this_.memmap[this_.reg_pc >> 13][this_.reg_pc & 0x1FFF]; + this_._addr = this_.readMem(this_.reg_pc); this_.reg_pc = (this_.reg_pc + 1) & 0xFFFF; - this_._tmp1 = this_.reg_x - (this_.io_read_map[this_._addr] ? this_.io_read(this_._addr) : this_.memmap[this_._addr >> 13][this_._addr & 0x1FFF]); - this_.flag_c = this_._tmp1 < 0 ? 0 : 1; + this_._tmp1 = this_.reg_x - this_.readMem(this_._addr); + this_.flag_c = (this_._tmp1 >= 0) ? 1 : 0; this_.flag_n = (this_._tmp1 & 0x80) >> 7; this_.flag_z = (this_._tmp1 & 0xFF) ? 0 : 1; this_.cycles += 3; }, + // 0xE5 SBC zp function opE5(this_) { - this_._addr = this_.memmap[this_.reg_pc >> 13][this_.reg_pc & 0x1FFF]; + this_._addr = this_.readMem(this_.reg_pc); this_.reg_pc = (this_.reg_pc + 1) & 0xFFFF; - this_._tmp1 = (this_.io_read_map[this_._addr] ? this_.io_read(this_._addr) : this_.memmap[this_._addr >> 13][this_._addr & 0x1FFF]); + this_._tmp1 = this_.readMem(this_._addr); if (this_.flag_d) { - this_._tmp2 = ((this_.reg_a >> 4) * 10 + (this_.reg_a & 0x0F)) - ((this_._tmp1 >> 4) * 10 + (this_._tmp1 & 0x0F)) - 1 + this_.flag_c; - this_.flag_c = (this_._tmp2 < 0) ? 0 : 1; - this_._tmp2 %= 100; - if (this_._tmp2 < 0) { - this_._tmp2 += 100; - } - this_.reg_a = ((((this_._tmp2 / 10) % 10) << 4) | (this_._tmp2 % 10)); + var a_val = (this_.reg_a >> 4) * 10 + (this_.reg_a & 0x0F); + var m_val = (this_._tmp1 >> 4) * 10 + (this_._tmp1 & 0x0F); + var result = a_val - m_val - 1 + this_.flag_c; + this_.flag_c = (result >= 0) ? 1 : 0; + if (result < 0) result += 100; + result = result % 100; + this_.reg_a = ((Math.floor(result / 10) << 4) | (result % 10)); this_.flag_n = (this_.reg_a & 0x80) >> 7; this_.flag_z = (this_.reg_a & 0xFF) ? 0 : 1; - this_.cycles++ + this_.cycles++; } else { this_._tmp2 = this_.reg_a - this_._tmp1 - 1 + this_.flag_c; - this_.flag_c = (this_._tmp2 < 0) ? 0 : 1; + this_.flag_c = (this_._tmp2 >= 0) ? 1 : 0; this_.flag_v = ((this_.reg_a ^ this_._tmp1) & (this_.reg_a ^ this_._tmp2) & 0x80) >> 7; this_.reg_a = (this_._tmp2 & 0xFF); this_.flag_n = (this_.reg_a & 0x80) >> 7; @@ -2105,56 +2306,52 @@ M65C02Context.prototype.op_func_tbl = [ } this_.cycles += 3; }, + // 0xE6 INC zp function opE6(this_) { - this_._addr = this_.memmap[this_.reg_pc >> 13][this_.reg_pc & 0x1FFF]; + this_._addr = this_.readMem(this_.reg_pc); this_.reg_pc = (this_.reg_pc + 1) & 0xFFFF; - this_._tmp1 = ((this_.io_read_map[this_._addr] ? this_.io_read(this_._addr) : this_.memmap[this_._addr >> 13][this_._addr & 0x1FFF]) + 1) & 0xFF; + this_._tmp1 = (this_.readMem(this_._addr) + 1) & 0xFF; + this_.writeMem(this_._addr, this_._tmp1); this_.flag_n = (this_._tmp1 & 0x80) >> 7; this_.flag_z = (this_._tmp1 & 0xFF) ? 0 : 1; - if (this_.io_write_map[this_._addr]) { - this_.io_write(this_._addr, this_._tmp1); - } else { - this_.memmap[this_._addr >> 13][this_._addr & 0x1FFF] = this_._tmp1; - } this_.cycles += 5; }, + // 0xE7 SMB4 zp function opE7(this_) { - this_._addr = this_.memmap[this_.reg_pc >> 13][this_.reg_pc & 0x1FFF]; + this_._addr = this_.readMem(this_.reg_pc); this_.reg_pc = (this_.reg_pc + 1) & 0xFFFF; - this_._tmp1 = (this_.io_read_map[this_._addr] ? this_.io_read(this_._addr) : this_.memmap[this_._addr >> 13][this_._addr & 0x1FFF]) | 0x40; + this_._tmp1 = this_.readMem(this_._addr) | 0x40; + this_.writeMem(this_._addr, this_._tmp1); this_.flag_n = (this_._tmp1 & 0x80) >> 7; this_.flag_z = (this_._tmp1 & 0xFF) ? 0 : 1; - if (this_.io_write_map[this_._addr]) { - this_.io_write(this_._addr, this_._tmp1); - } else { - this_.memmap[this_._addr >> 13][this_._addr & 0x1FFF] = this_._tmp1; - } this_.cycles += 5; }, + // 0xE8 INX function opE8(this_) { this_.reg_x = (++this_.reg_x & 0xFF); this_.flag_n = (this_.reg_x & 0x80) >> 7; this_.flag_z = (this_.reg_x & 0xFF) ? 0 : 1; this_.cycles += 2; }, + // 0xE9 SBC imm function opE9(this_) { this_._addr = this_.reg_pc; this_.reg_pc = (this_.reg_pc + 1) & 0xFFFF; - this_._tmp1 = (this_.io_read_map[this_._addr] ? this_.io_read(this_._addr) : this_.memmap[this_._addr >> 13][this_._addr & 0x1FFF]); + this_._tmp1 = this_.readMem(this_._addr); if (this_.flag_d) { - this_._tmp2 = ((this_.reg_a >> 4) * 10 + (this_.reg_a & 0x0F)) - ((this_._tmp1 >> 4) * 10 + (this_._tmp1 & 0x0F)) - 1 + this_.flag_c; - this_.flag_c = (this_._tmp2 < 0) ? 0 : 1; - this_._tmp2 %= 100; - if (this_._tmp2 < 0) { - this_._tmp2 += 100; - } - this_.reg_a = ((((this_._tmp2 / 10) % 10) << 4) | (this_._tmp2 % 10)); + var a_val = (this_.reg_a >> 4) * 10 + (this_.reg_a & 0x0F); + var m_val = (this_._tmp1 >> 4) * 10 + (this_._tmp1 & 0x0F); + var result = a_val - m_val - 1 + this_.flag_c; + this_.flag_c = (result >= 0) ? 1 : 0; + if (result < 0) result += 100; + result = result % 100; + this_.reg_a = ((Math.floor(result / 10) << 4) | (result % 10)); this_.flag_n = (this_.reg_a & 0x80) >> 7; this_.flag_z = (this_.reg_a & 0xFF) ? 0 : 1; - this_.cycles++ + this_.cycles++; } else { this_._tmp2 = this_.reg_a - this_._tmp1 - 1 + this_.flag_c; - this_.flag_c = (this_._tmp2 < 0) ? 0 : 1; + this_.flag_c = (this_._tmp2 >= 0) ? 1 : 0; this_.flag_v = ((this_.reg_a ^ this_._tmp1) & (this_.reg_a ^ this_._tmp2) & 0x80) >> 7; this_.reg_a = (this_._tmp2 & 0xFF); this_.flag_n = (this_.reg_a & 0x80) >> 7; @@ -2162,39 +2359,43 @@ M65C02Context.prototype.op_func_tbl = [ } this_.cycles += 2; }, + // 0xEA NOP function opEA(this_) { this_.cycles += 2; }, + // 0xEB 未使用 function opEB(this_) { this_.cycles += 1; }, + // 0xEC CPX abs function opEC(this_) { - this_._addr = (((this_.reg_pc < 0xFFFF ? this_.memmap[(this_.reg_pc + 1) >> 13][(this_.reg_pc + 1) & 0x1FFF] : this_.ram[0]) << 8) | this_.memmap[this_.reg_pc >> 13][this_.reg_pc & 0x1FFF]); + this_._addr = (this_.readMem(this_.reg_pc + 1) << 8) | this_.readMem(this_.reg_pc); this_.reg_pc = (this_.reg_pc + 2) & 0xFFFF; - this_._tmp1 = this_.reg_x - (this_.io_read_map[this_._addr] ? this_.io_read(this_._addr) : this_.memmap[this_._addr >> 13][this_._addr & 0x1FFF]); - this_.flag_c = this_._tmp1 < 0 ? 0 : 1; + this_._tmp1 = this_.reg_x - this_.readMem(this_._addr); + this_.flag_c = (this_._tmp1 >= 0) ? 1 : 0; this_.flag_n = (this_._tmp1 & 0x80) >> 7; this_.flag_z = (this_._tmp1 & 0xFF) ? 0 : 1; this_.cycles += 4; }, + // 0xED SBC abs function opED(this_) { - this_._addr = (((this_.reg_pc < 0xFFFF ? this_.memmap[(this_.reg_pc + 1) >> 13][(this_.reg_pc + 1) & 0x1FFF] : this_.ram[0]) << 8) | this_.memmap[this_.reg_pc >> 13][this_.reg_pc & 0x1FFF]); + this_._addr = (this_.readMem(this_.reg_pc + 1) << 8) | this_.readMem(this_.reg_pc); this_.reg_pc = (this_.reg_pc + 2) & 0xFFFF; - this_._tmp1 = (this_.io_read_map[this_._addr] ? this_.io_read(this_._addr) : this_.memmap[this_._addr >> 13][this_._addr & 0x1FFF]); + this_._tmp1 = this_.readMem(this_._addr); if (this_.flag_d) { - this_._tmp2 = ((this_.reg_a >> 4) * 10 + (this_.reg_a & 0x0F)) - ((this_._tmp1 >> 4) * 10 + (this_._tmp1 & 0x0F)) - 1 + this_.flag_c; - this_.flag_c = (this_._tmp2 < 0) ? 0 : 1; - this_._tmp2 %= 100; - if (this_._tmp2 < 0) { - this_._tmp2 += 100; - } - this_.reg_a = ((((this_._tmp2 / 10) % 10) << 4) | (this_._tmp2 % 10)); + var a_val = (this_.reg_a >> 4) * 10 + (this_.reg_a & 0x0F); + var m_val = (this_._tmp1 >> 4) * 10 + (this_._tmp1 & 0x0F); + var result = a_val - m_val - 1 + this_.flag_c; + this_.flag_c = (result >= 0) ? 1 : 0; + if (result < 0) result += 100; + result = result % 100; + this_.reg_a = ((Math.floor(result / 10) << 4) | (result % 10)); this_.flag_n = (this_.reg_a & 0x80) >> 7; this_.flag_z = (this_.reg_a & 0xFF) ? 0 : 1; - this_.cycles++ + this_.cycles++; } else { this_._tmp2 = this_.reg_a - this_._tmp1 - 1 + this_.flag_c; - this_.flag_c = (this_._tmp2 < 0) ? 0 : 1; + this_.flag_c = (this_._tmp2 >= 0) ? 1 : 0; this_.flag_v = ((this_.reg_a ^ this_._tmp1) & (this_.reg_a ^ this_._tmp2) & 0x80) >> 7; this_.reg_a = (this_._tmp2 & 0xFF); this_.flag_n = (this_.reg_a & 0x80) >> 7; @@ -2202,30 +2403,30 @@ M65C02Context.prototype.op_func_tbl = [ } this_.cycles += 4; }, + // 0xEE INC abs function opEE(this_) { - this_._addr = (((this_.reg_pc < 0xFFFF ? this_.memmap[(this_.reg_pc + 1) >> 13][(this_.reg_pc + 1) & 0x1FFF] : this_.ram[0]) << 8) | this_.memmap[this_.reg_pc >> 13][this_.reg_pc & 0x1FFF]); + this_._addr = (this_.readMem(this_.reg_pc + 1) << 8) | this_.readMem(this_.reg_pc); this_.reg_pc = (this_.reg_pc + 2) & 0xFFFF; - this_._tmp1 = ((this_.io_read_map[this_._addr] ? this_.io_read(this_._addr) : this_.memmap[this_._addr >> 13][this_._addr & 0x1FFF]) + 1) & 0xFF; + this_._tmp1 = (this_.readMem(this_._addr) + 1) & 0xFF; + this_.writeMem(this_._addr, this_._tmp1); this_.flag_n = (this_._tmp1 & 0x80) >> 7; this_.flag_z = (this_._tmp1 & 0xFF) ? 0 : 1; - if (this_.io_write_map[this_._addr]) { - this_.io_write(this_._addr, this_._tmp1); - } else { - this_.memmap[this_._addr >> 13][this_._addr & 0x1FFF] = this_._tmp1; - } this_.cycles += 6; }, + // 0xEF SMB5 zp function opEF(this_) { - this_._addr = this_.memmap[this_.reg_pc >> 13][this_.reg_pc & 0x1FFF]; - this_.reg_pc = (this_.reg_pc + 1) & 0xFFFF; - if ((this_.io_read_map[this_._addr] ? this_.io_read(this_._addr) : this_.memmap[this_._addr >> 13][this_._addr & 0x1FFF]) & 0x40) { + this_._addr = this_.readMem(this_.reg_pc); + this_._tmp2 = this_.readMem(this_.reg_pc + 1); + this_.reg_pc = (this_.reg_pc + 2) & 0xFFFF; + if (this_.readMem(this_._addr) & 0x40) { this_.reg_pc = (this_.reg_pc + this_._tmp2) & 0xFFFF; this_.cycles++; } this_.cycles += 5; }, + // 0xF0 BEQ function opF0(this_) { - this_._tmp1 = this_.memmap[this_.reg_pc >> 13][this_.reg_pc & 0x1FFF]; + this_._tmp1 = this_.readMem(this_.reg_pc); this_._tmp2 = this_._tmp1 - ((this_._tmp1 & 0x80) << 1); this_.reg_pc = (this_.reg_pc + 1) & 0xFFFF; if (this_.flag_z) { @@ -2234,25 +2435,30 @@ M65C02Context.prototype.op_func_tbl = [ } this_.cycles += 2; }, + // 0xF1 SBC (indirect),Y function opF1(this_) { - this_._tmp1 = this_.memmap[this_.reg_pc >> 13][this_.reg_pc & 0x1FFF]; - this_._addr = ((((this_._tmp1 < 0xFFFF ? this_.memmap[(this_._tmp1 + 1) >> 13][(this_._tmp1 + 1) & 0x1FFF] : this_.ram[0]) << 8) | this_.memmap[this_._tmp1 >> 13][this_._tmp1 & 0x1FFF]) + this_.reg_y) & 0xFFFF; + this_._tmp1 = this_.readMem(this_.reg_pc); + this_._addr = (this_.readMem((this_._tmp1 + 1) & 0xFF) << 8) | this_.readMem(this_._tmp1); + if ((this_._addr & 0xFF00) !== ((this_._addr + this_.reg_y) & 0xFF00)) { + this_.cycles++; + } + this_._addr = (this_._addr + this_.reg_y) & 0xFFFF; this_.reg_pc = (this_.reg_pc + 1) & 0xFFFF; - this_._tmp1 = (this_.io_read_map[this_._addr] ? this_.io_read(this_._addr) : this_.memmap[this_._addr >> 13][this_._addr & 0x1FFF]); + this_._tmp1 = this_.readMem(this_._addr); if (this_.flag_d) { - this_._tmp2 = ((this_.reg_a >> 4) * 10 + (this_.reg_a & 0x0F)) - ((this_._tmp1 >> 4) * 10 + (this_._tmp1 & 0x0F)) - 1 + this_.flag_c; - this_.flag_c = (this_._tmp2 < 0) ? 0 : 1; - this_._tmp2 %= 100; - if (this_._tmp2 < 0) { - this_._tmp2 += 100; - } - this_.reg_a = ((((this_._tmp2 / 10) % 10) << 4) | (this_._tmp2 % 10)); + var a_val = (this_.reg_a >> 4) * 10 + (this_.reg_a & 0x0F); + var m_val = (this_._tmp1 >> 4) * 10 + (this_._tmp1 & 0x0F); + var result = a_val - m_val - 1 + this_.flag_c; + this_.flag_c = (result >= 0) ? 1 : 0; + if (result < 0) result += 100; + result = result % 100; + this_.reg_a = ((Math.floor(result / 10) << 4) | (result % 10)); this_.flag_n = (this_.reg_a & 0x80) >> 7; this_.flag_z = (this_.reg_a & 0xFF) ? 0 : 1; - this_.cycles++ + this_.cycles++; } else { this_._tmp2 = this_.reg_a - this_._tmp1 - 1 + this_.flag_c; - this_.flag_c = (this_._tmp2 < 0) ? 0 : 1; + this_.flag_c = (this_._tmp2 >= 0) ? 1 : 0; this_.flag_v = ((this_.reg_a ^ this_._tmp1) & (this_.reg_a ^ this_._tmp2) & 0x80) >> 7; this_.reg_a = (this_._tmp2 & 0xFF); this_.flag_n = (this_.reg_a & 0x80) >> 7; @@ -2260,25 +2466,26 @@ M65C02Context.prototype.op_func_tbl = [ } this_.cycles += 5; }, + // 0xF2 SBC (indirect) function opF2(this_) { - this_._tmp1 = this_.memmap[this_.reg_pc >> 13][this_.reg_pc & 0x1FFF]; - this_._addr = ((this_._tmp1 < 0xFF ? this_.ram[this_._tmp1 + 1] : this_.ram[0]) << 8) | this_.ram[this_._tmp1]; + this_._tmp1 = this_.readMem(this_.reg_pc); + this_._addr = (this_.readMem((this_._tmp1 + 1) & 0xFF) << 8) | this_.readMem(this_._tmp1); this_.reg_pc = (this_.reg_pc + 1) & 0xFFFF; - this_._tmp1 = (this_.io_read_map[this_._addr] ? this_.io_read(this_._addr) : this_.memmap[this_._addr >> 13][this_._addr & 0x1FFF]); + this_._tmp1 = this_.readMem(this_._addr); if (this_.flag_d) { - this_._tmp2 = ((this_.reg_a >> 4) * 10 + (this_.reg_a & 0x0F)) - ((this_._tmp1 >> 4) * 10 + (this_._tmp1 & 0x0F)) - 1 + this_.flag_c; - this_.flag_c = (this_._tmp2 < 0) ? 0 : 1; - this_._tmp2 %= 100; - if (this_._tmp2 < 0) { - this_._tmp2 += 100; - } - this_.reg_a = ((((this_._tmp2 / 10) % 10) << 4) | (this_._tmp2 % 10)); + var a_val = (this_.reg_a >> 4) * 10 + (this_.reg_a & 0x0F); + var m_val = (this_._tmp1 >> 4) * 10 + (this_._tmp1 & 0x0F); + var result = a_val - m_val - 1 + this_.flag_c; + this_.flag_c = (result >= 0) ? 1 : 0; + if (result < 0) result += 100; + result = result % 100; + this_.reg_a = ((Math.floor(result / 10) << 4) | (result % 10)); this_.flag_n = (this_.reg_a & 0x80) >> 7; this_.flag_z = (this_.reg_a & 0xFF) ? 0 : 1; - this_.cycles++ + this_.cycles++; } else { this_._tmp2 = this_.reg_a - this_._tmp1 - 1 + this_.flag_c; - this_.flag_c = (this_._tmp2 < 0) ? 0 : 1; + this_.flag_c = (this_._tmp2 >= 0) ? 1 : 0; this_.flag_v = ((this_.reg_a ^ this_._tmp1) & (this_.reg_a ^ this_._tmp2) & 0x80) >> 7; this_.reg_a = (this_._tmp2 & 0xFF); this_.flag_n = (this_.reg_a & 0x80) >> 7; @@ -2286,31 +2493,34 @@ M65C02Context.prototype.op_func_tbl = [ } this_.cycles += 5; }, + // 0xF3 未使用 function opF3(this_) { this_.cycles += 1; }, + // 0xF4 未使用 function opF4(this_) { this_.reg_pc = (this_.reg_pc + 1) & 0xFFFF; this_.cycles += 4; }, + // 0xF5 SBC zp,X function opF5(this_) { - this_._addr = (this_.memmap[this_.reg_pc >> 13][this_.reg_pc & 0x1FFF] + this_.reg_x) & 0xFF; + this_._addr = (this_.readMem(this_.reg_pc) + this_.reg_x) & 0xFF; this_.reg_pc = (this_.reg_pc + 1) & 0xFFFF; - this_._tmp1 = (this_.io_read_map[this_._addr] ? this_.io_read(this_._addr) : this_.memmap[this_._addr >> 13][this_._addr & 0x1FFF]); + this_._tmp1 = this_.readMem(this_._addr); if (this_.flag_d) { - this_._tmp2 = ((this_.reg_a >> 4) * 10 + (this_.reg_a & 0x0F)) - ((this_._tmp1 >> 4) * 10 + (this_._tmp1 & 0x0F)) - 1 + this_.flag_c; - this_.flag_c = (this_._tmp2 < 0) ? 0 : 1; - this_._tmp2 %= 100; - if (this_._tmp2 < 0) { - this_._tmp2 += 100; - } - this_.reg_a = ((((this_._tmp2 / 10) % 10) << 4) | (this_._tmp2 % 10)); + var a_val = (this_.reg_a >> 4) * 10 + (this_.reg_a & 0x0F); + var m_val = (this_._tmp1 >> 4) * 10 + (this_._tmp1 & 0x0F); + var result = a_val - m_val - 1 + this_.flag_c; + this_.flag_c = (result >= 0) ? 1 : 0; + if (result < 0) result += 100; + result = result % 100; + this_.reg_a = ((Math.floor(result / 10) << 4) | (result % 10)); this_.flag_n = (this_.reg_a & 0x80) >> 7; this_.flag_z = (this_.reg_a & 0xFF) ? 0 : 1; - this_.cycles++ + this_.cycles++; } else { this_._tmp2 = this_.reg_a - this_._tmp1 - 1 + this_.flag_c; - this_.flag_c = (this_._tmp2 < 0) ? 0 : 1; + this_.flag_c = (this_._tmp2 >= 0) ? 1 : 0; this_.flag_v = ((this_.reg_a ^ this_._tmp1) & (this_.reg_a ^ this_._tmp2) & 0x80) >> 7; this_.reg_a = (this_._tmp2 & 0xFF); this_.flag_n = (this_.reg_a & 0x80) >> 7; @@ -2318,54 +2528,54 @@ M65C02Context.prototype.op_func_tbl = [ } this_.cycles += 4; }, + // 0xF6 INC zp,X function opF6(this_) { - this_._addr = (this_.memmap[this_.reg_pc >> 13][this_.reg_pc & 0x1FFF] + this_.reg_x) & 0xFF; + this_._addr = (this_.readMem(this_.reg_pc) + this_.reg_x) & 0xFF; this_.reg_pc = (this_.reg_pc + 1) & 0xFFFF; - this_._tmp1 = ((this_.io_read_map[this_._addr] ? this_.io_read(this_._addr) : this_.memmap[this_._addr >> 13][this_._addr & 0x1FFF]) + 1) & 0xFF; + this_._tmp1 = (this_.readMem(this_._addr) + 1) & 0xFF; + this_.writeMem(this_._addr, this_._tmp1); this_.flag_n = (this_._tmp1 & 0x80) >> 7; this_.flag_z = (this_._tmp1 & 0xFF) ? 0 : 1; - if (this_.io_write_map[this_._addr]) { - this_.io_write(this_._addr, this_._tmp1); - } else { - this_.memmap[this_._addr >> 13][this_._addr & 0x1FFF] = this_._tmp1; - } this_.cycles += 6; }, + // 0xF7 SMB6 zp function opF7(this_) { - this_._addr = this_.memmap[this_.reg_pc >> 13][this_.reg_pc & 0x1FFF]; + this_._addr = this_.readMem(this_.reg_pc); this_.reg_pc = (this_.reg_pc + 1) & 0xFFFF; - this_._tmp1 = (this_.io_read_map[this_._addr] ? this_.io_read(this_._addr) : this_.memmap[this_._addr >> 13][this_._addr & 0x1FFF]) | 0x80; + this_._tmp1 = this_.readMem(this_._addr) | 0x80; + this_.writeMem(this_._addr, this_._tmp1); this_.flag_n = (this_._tmp1 & 0x80) >> 7; this_.flag_z = (this_._tmp1 & 0xFF) ? 0 : 1; - if (this_.io_write_map[this_._addr]) { - this_.io_write(this_._addr, this_._tmp1); - } else { - this_.memmap[this_._addr >> 13][this_._addr & 0x1FFF] = this_._tmp1; - } this_.cycles += 5; }, + // 0xF8 SED function opF8(this_) { this_.flag_d = 1; this_.cycles += 2; }, + // 0xF9 SBC abs,Y function opF9(this_) { - this_._addr = ((((this_.reg_pc < 0xFFFF ? this_.memmap[(this_.reg_pc + 1) >> 13][(this_.reg_pc + 1) & 0x1FFF] : this_.ram[0]) << 8) | this_.memmap[this_.reg_pc >> 13][this_.reg_pc & 0x1FFF]) + this_.reg_y) & 0xFFFF; + this_._addr = (this_.readMem(this_.reg_pc + 1) << 8) | this_.readMem(this_.reg_pc); + if ((this_._addr & 0xFF00) !== ((this_._addr + this_.reg_y) & 0xFF00)) { + this_.cycles++; + } + this_._addr = (this_._addr + this_.reg_y) & 0xFFFF; this_.reg_pc = (this_.reg_pc + 2) & 0xFFFF; - this_._tmp1 = (this_.io_read_map[this_._addr] ? this_.io_read(this_._addr) : this_.memmap[this_._addr >> 13][this_._addr & 0x1FFF]); + this_._tmp1 = this_.readMem(this_._addr); if (this_.flag_d) { - this_._tmp2 = ((this_.reg_a >> 4) * 10 + (this_.reg_a & 0x0F)) - ((this_._tmp1 >> 4) * 10 + (this_._tmp1 & 0x0F)) - 1 + this_.flag_c; - this_.flag_c = (this_._tmp2 < 0) ? 0 : 1; - this_._tmp2 %= 100; - if (this_._tmp2 < 0) { - this_._tmp2 += 100; - } - this_.reg_a = ((((this_._tmp2 / 10) % 10) << 4) | (this_._tmp2 % 10)); + var a_val = (this_.reg_a >> 4) * 10 + (this_.reg_a & 0x0F); + var m_val = (this_._tmp1 >> 4) * 10 + (this_._tmp1 & 0x0F); + var result = a_val - m_val - 1 + this_.flag_c; + this_.flag_c = (result >= 0) ? 1 : 0; + if (result < 0) result += 100; + result = result % 100; + this_.reg_a = ((Math.floor(result / 10) << 4) | (result % 10)); this_.flag_n = (this_.reg_a & 0x80) >> 7; this_.flag_z = (this_.reg_a & 0xFF) ? 0 : 1; - this_.cycles++ + this_.cycles++; } else { this_._tmp2 = this_.reg_a - this_._tmp1 - 1 + this_.flag_c; - this_.flag_c = (this_._tmp2 < 0) ? 0 : 1; + this_.flag_c = (this_._tmp2 >= 0) ? 1 : 0; this_.flag_v = ((this_.reg_a ^ this_._tmp1) & (this_.reg_a ^ this_._tmp2) & 0x80) >> 7; this_.reg_a = (this_._tmp2 & 0xFF); this_.flag_n = (this_.reg_a & 0x80) >> 7; @@ -2373,37 +2583,42 @@ M65C02Context.prototype.op_func_tbl = [ } this_.cycles += 4; }, + // 0xFA PLX function opFA(this_) { - this_.reg_x = this_.ram[this_.reg_sp = ++this_.reg_sp & 0xFF | 0x100]; + this_.reg_sp = ++this_.reg_sp & 0xFF | 0x100; + this_.reg_x = this_.readMem(this_.reg_sp); this_.flag_n = (this_.reg_x & 0x80) >> 7; this_.flag_z = (this_.reg_x & 0xFF) ? 0 : 1; this_.cycles += 4; }, + // 0xFB 未使用 function opFB(this_) { this_.cycles += 1; }, + // 0xFC 未使用 function opFC(this_) { this_.reg_pc = (this_.reg_pc + 2) & 0xFFFF; this_.cycles += 4; }, + // 0xFD SBC abs,X function opFD(this_) { - this_._addr = ((((this_.reg_pc < 0xFFFF ? this_.memmap[(this_.reg_pc + 1) >> 13][(this_.reg_pc + 1) & 0x1FFF] : this_.ram[0]) << 8) | this_.memmap[this_.reg_pc >> 13][this_.reg_pc & 0x1FFF]) + this_.reg_x) & 0xFFFF; + this_._addr = ((this_.readMem(this_.reg_pc + 1) << 8) | this_.readMem(this_.reg_pc)) + this_.reg_x; this_.reg_pc = (this_.reg_pc + 2) & 0xFFFF; - this_._tmp1 = (this_.io_read_map[this_._addr] ? this_.io_read(this_._addr) : this_.memmap[this_._addr >> 13][this_._addr & 0x1FFF]); + this_._tmp1 = this_.readMem(this_._addr); if (this_.flag_d) { - this_._tmp2 = ((this_.reg_a >> 4) * 10 + (this_.reg_a & 0x0F)) - ((this_._tmp1 >> 4) * 10 + (this_._tmp1 & 0x0F)) - 1 + this_.flag_c; - this_.flag_c = (this_._tmp2 < 0) ? 0 : 1; - this_._tmp2 %= 100; - if (this_._tmp2 < 0) { - this_._tmp2 += 100; - } - this_.reg_a = ((((this_._tmp2 / 10) % 10) << 4) | (this_._tmp2 % 10)); + var a_val = (this_.reg_a >> 4) * 10 + (this_.reg_a & 0x0F); + var m_val = (this_._tmp1 >> 4) * 10 + (this_._tmp1 & 0x0F); + var result = a_val - m_val - 1 + this_.flag_c; + this_.flag_c = (result >= 0) ? 1 : 0; + if (result < 0) result += 100; + result = result % 100; + this_.reg_a = ((Math.floor(result / 10) << 4) | (result % 10)); this_.flag_n = (this_.reg_a & 0x80) >> 7; this_.flag_z = (this_.reg_a & 0xFF) ? 0 : 1; - this_.cycles++ + this_.cycles++; } else { this_._tmp2 = this_.reg_a - this_._tmp1 - 1 + this_.flag_c; - this_.flag_c = (this_._tmp2 < 0) ? 0 : 1; + this_.flag_c = (this_._tmp2 >= 0) ? 1 : 0; this_.flag_v = ((this_.reg_a ^ this_._tmp1) & (this_.reg_a ^ this_._tmp2) & 0x80) >> 7; this_.reg_a = (this_._tmp2 & 0xFF); this_.flag_n = (this_.reg_a & 0x80) >> 7; @@ -2411,34 +2626,35 @@ M65C02Context.prototype.op_func_tbl = [ } this_.cycles += 4; }, + // 0xFE INC abs,X function opFE(this_) { - this_._addr = ((((this_.reg_pc < 0xFFFF ? this_.memmap[(this_.reg_pc + 1) >> 13][(this_.reg_pc + 1) & 0x1FFF] : this_.ram[0]) << 8) | this_.memmap[this_.reg_pc >> 13][this_.reg_pc & 0x1FFF]) + this_.reg_x) & 0xFFFF; + this_._addr = ((this_.readMem(this_.reg_pc + 1) << 8) | this_.readMem(this_.reg_pc)) + this_.reg_x; this_.reg_pc = (this_.reg_pc + 2) & 0xFFFF; - this_._tmp1 = ((this_.io_read_map[this_._addr] ? this_.io_read(this_._addr) : this_.memmap[this_._addr >> 13][this_._addr & 0x1FFF]) + 1) & 0xFF; + this_._tmp1 = (this_.readMem(this_._addr) + 1) & 0xFF; + this_.writeMem(this_._addr, this_._tmp1); this_.flag_n = (this_._tmp1 & 0x80) >> 7; this_.flag_z = (this_._tmp1 & 0xFF) ? 0 : 1; - if (this_.io_write_map[this_._addr]) { - this_.io_write(this_._addr, this_._tmp1); - } else { - this_.memmap[this_._addr >> 13][this_._addr & 0x1FFF] = this_._tmp1; - } this_.cycles += 6; }, + // 0xFF SMB7 zp function opFF(this_) { - this_._addr = this_.memmap[this_.reg_pc >> 13][this_.reg_pc & 0x1FFF]; - this_.reg_pc = (this_.reg_pc + 1) & 0xFFFF; - if ((this_.io_read_map[this_._addr] ? this_.io_read(this_._addr) : this_.memmap[this_._addr >> 13][this_._addr & 0x1FFF]) & 0x80) { + this_._addr = this_.readMem(this_.reg_pc); + this_._tmp2 = this_.readMem(this_.reg_pc + 1); + this_.reg_pc = (this_.reg_pc + 2) & 0xFFFF; + if (this_.readMem(this_._addr) & 0x80) { this_.reg_pc = (this_.reg_pc + this_._tmp2) & 0xFFFF; this_.cycles++; } this_.cycles += 5; } ]; + M65C02Context.prototype.execute = function() { this._code = this.memmap[this.reg_pc >> 13][this.reg_pc & 0x1FFF]; this.reg_pc = (this.reg_pc + 1) & 0xFFFF; this.op_func_tbl[this._code](this); }; + M65C02Context.prototype.doIrq = function() { if (!this.stp) { if (!this.nmi) { @@ -2446,12 +2662,12 @@ M65C02Context.prototype.doIrq = function() { this.reg_pc = (this.reg_pc + 1) & 0xFFFF; this.wai = 0; } - this.ram[this.reg_sp] = (this.reg_pc >> 8); + this.writeMem(this.reg_sp, (this.reg_pc >> 8)); this.reg_sp = --this.reg_sp & 0xFF | 0x100; - this.ram[this.reg_sp] = (this.reg_pc & 0xFF); + this.writeMem(this.reg_sp, (this.reg_pc & 0xFF)); this.reg_sp = --this.reg_sp & 0xFF | 0x100; this.flag_i = 1; - this.ram[this.reg_sp] = this.get_reg_ps(); + this.writeMem(this.reg_sp, this.get_reg_ps()); this.reg_sp = --this.reg_sp & 0xFF | 0x100; this.reg_pc = (this.memmap[7][0x1FFB] << 8) | (this.memmap[7][0x1FFA]); this.nmi = 1; @@ -2463,12 +2679,12 @@ M65C02Context.prototype.doIrq = function() { this.wai = 0; } if (!this.flag_i) { - this.ram[this.reg_sp] = (this.reg_pc >> 8); + this.writeMem(this.reg_sp, (this.reg_pc >> 8)); this.reg_sp = --this.reg_sp & 0xFF | 0x100; - this.ram[this.reg_sp] = (this.reg_pc & 0xFF); + this.writeMem(this.reg_sp, (this.reg_pc & 0xFF)); this.reg_sp = --this.reg_sp & 0xFF | 0x100; this.flag_b = 0; - this.ram[this.reg_sp] = this.get_reg_ps(); + this.writeMem(this.reg_sp, this.get_reg_ps()); this.reg_sp = --this.reg_sp & 0xFF | 0x100; this.reg_pc = (this.memmap[7][0x1FFF] << 8) | (this.memmap[7][0x1FFE]); this.flag_i = 1; diff --git a/src/wqx.js b/src/wqx.js index faa3206..13a1d46 100644 --- a/src/wqx.js +++ b/src/wqx.js @@ -1,6 +1,12 @@ // cc800 // http://bbs.emsky.net/viewthread.php?tid=33474 +// ── 调试追踪开关 ────────────────────────────────────────────────── +// 设为 true 可在控制台看到完整启动链和关键函数调用序列 +var WQX_TRACE = false; +function _trace(name) { if (WQX_TRACE) console.log('[WQX] ' + name); } +// ────────────────────────────────────────────────────────────────── + var Wqx = (function (){ var io00_bank_switch = 0x00; var io01_int_enable = 0x01; @@ -39,7 +45,7 @@ var Wqx = (function (){ var io1E_batt_detect = 0x1E; var io20_JG = 0x20; var io23_unknow = 0x23; - var io_ROA_bit = 0x80; // RAM/ROM (io_bios_bsw) + var io_ROA_bit = 0x80; var map0000 = 0; var map2000 = 1; @@ -88,21 +94,18 @@ var Wqx = (function (){ this.frameTimer = null; this.totalInsts = 0; - this.keypadmatrix = [ - [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], - [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] - ]; + // 睡眠/唤醒状态,对应C++ slept/should_wake_up/wake_up_pending/wake_up_key + this.slept = false; + this.shouldWakeUp = false; + this.wakeUpPending = false; + this.wakeUpKey = 0; + + // 对应C++ keypad_matrix: Uint8Array,每行一个字节,直接位运算 + this.keypadmatrix = new Uint8Array(8); // REPLACED_MARKER this.lcdoffshift0flag = 0; this.lcdbuffaddr = null; this.timer0started = false; this.timer0value = 0; -// this.timer0waveoutstart = false; this.ptr40 = null; this.zp40cache = null; @@ -117,6 +120,9 @@ var Wqx = (function (){ this.bbsbankheader = []; this.may4000ptr = null; this.cpu = null; + this.clockRecords = new Uint8Array(80); + this.mayClockFlags = 0; + this.initLcd(); this.initRom(); this.initNor(); @@ -127,6 +133,7 @@ var Wqx = (function (){ } Wqx.prototype.initLcd = function (){ + _trace('initLcd'); var doc = this.div.ownerDocument; var canvas = doc.createElement('canvas'); canvas.width = 320; @@ -138,7 +145,9 @@ var Wqx = (function (){ this.canvasCtx.setTransform(2, 0, 0, 2, 0, 0); this.canvasCtx.save(); }; + Wqx.prototype.initRom = function (){ + _trace('initRom'); this.rom = new Uint8Array(0x8000 * 768); for (var i=0; i<256; i++) { this.volume0array[i] = getByteArray(this.rom, 0x8000 * i, 0x8000); @@ -146,19 +155,25 @@ var Wqx = (function (){ this.volume2array[i] = getByteArray(this.rom, 0x8000 * (i + 512), 0x8000); } }; + Wqx.prototype.initNor = function (){ + _trace('initNor'); this.nor = new Uint8Array(0x8000 * 32); this.norbankheader = []; for (var i=0; i<32; i++) { this.norbankheader[i] = getByteArray(this.nor, 0x8000 * i, 0x8000); } }; + Wqx.prototype.initRam = function (){ + _trace('initRam'); this.ram = new Uint8Array(0x10000); this.ptr40 = getByteArray(this.ram, 0x40, 0x40); this.zp40cache = new Uint8Array(0x40); }; + Wqx.prototype.initMemmap = function (){ + _trace('initMemmap'); this.memmap[map0000] = getByteArray(this.ram, 0, 0x2000); this.ram2000_4000 = getByteArray(this.ram, 0x2000, 0x2000); this.memmap[map2000] = this.ram2000_4000; @@ -175,39 +190,18 @@ var Wqx = (function (){ this.may4000ptr = this.volume0array[0]; this.memmap[mapE000] = getByteArray(this.volume0array[0], 0x2000, 0x2000); this.switch4000ToBFFF(); -// this._dbg_logMemmap(); }; function hex(num, len){ var str = num.toString(16).toUpperCase(); return new Array(len - str.length + 1).join('0') + str; } - var _dbg_mapNames = ['map0000','map2000','map4000','map6000','map8000','mapA000','mapC000','mapE000']; - Wqx.prototype._dbg_ptrName = function (i){ - var ptr = this.memmap[i]; - var mapName = _dbg_mapNames[i]; - if (ptr.buffer === this.rom.buffer) { - return mapName + ': ROM[0x' + hex(ptr.byteOffset, 8) + ']'; - } else if (ptr.buffer === this.nor.buffer) { - return mapName + ': NOR[0x' + hex(ptr.byteOffset, 8) + ']'; - } else { - return mapName + ': RAM[0x' + hex(ptr.byteOffset, 8) + ']'; - } - }; - Wqx.prototype._dbg_logMemmap = function (){ - var buff = []; - for (var i=0; i<_dbg_mapNames.length; i++) { - buff.push(this._dbg_ptrName(i)); - } - console.log(buff.join('\n')); - }; Wqx.prototype.fillC000BIOSBank = function (volume_array){ this.bbsbankheader[0] = getByteArray(volume_array[0], 0, 0x2000); this.bbsbankheader[1] = this.ramRomBank1; this.bbsbankheader[2] = getByteArray(volume_array[0], 0x4000, 0x2000); this.bbsbankheader[3] = getByteArray(volume_array[0], 0x6000, 0x2000); - // 4567, 89AB, CDEF take first 4page 0000~7FFF in BROM for (var i = 0; i < 3; i++) { this.bbsbankheader[i * 4 + 4] = getByteArray(volume_array[i + 1], 0, 0x2000); this.bbsbankheader[i * 4 + 5] = getByteArray(volume_array[i + 1], 0x2000, 0x2000); @@ -215,143 +209,129 @@ var Wqx = (function (){ this.bbsbankheader[i * 4 + 7] = getByteArray(volume_array[i + 1], 0x6000, 0x2000); } }; + Wqx.prototype.switch4000ToBFFF = function (){ this.memmap[map4000] = getByteArray(this.may4000ptr, 0, 0x2000); this.memmap[map6000] = getByteArray(this.may4000ptr, 0x2000, 0x2000); this.memmap[map8000] = getByteArray(this.may4000ptr, 0x4000, 0x2000); this.memmap[mapA000] = getByteArray(this.may4000ptr, 0x6000, 0x2000); -// this._dbg_logMemmap(); }; Wqx.prototype.initIo = function (){ + _trace('initIo'); this.io_read_map = new Array(0x10000); this.io_write_map = new Array(0x10000); for (var i=0; i<0x10000; i++) { this.io_read_map[i] = i < 0x40; this.io_write_map[i] = i < 0x40 || i >= 0x4000; } + // 对应C++ Load():0x045F读取时处理wakeUpPending + this.io_read_map[0x045F] = true; this.io_read = this.readIO.bind(this); this.io_write = this.writeIO.bind(this); this._eraseBuff = new Uint8Array(256); - // bit5 TIMER0 SOURCE CLOCK SELECT BIT1/TIMER CLOCK SELECT BIT2 - // bit3 TIMER1 SOURCE CLOCK SELECT BIT1/TIMER CLOCK SELECT BIT0 - // ([0C] & 3) * 1000 || [06] * 10 = LCDAddr this.ram[io0C_timer01_ctrl] = 0x28; this.ram[io1B_pwm_data] = 0; - this.ram[io01_int_enable] = 0; // Disable all int + this.ram[io01_int_enable] = 0; this.ram[io04_general_ctrl] = 0; this.ram[io05_clock_ctrl] = 0; this.ram[io08_port0_data] = 0; this.ram[io00_bank_switch] = 0; this.ram[io09_port1_data] = 0; }; + Wqx.prototype.readIO = function (addr){ -// console.log('readIO: ' + addr.toString(16) + ' @' + this._instCount); + // 对应C++ Load():Flash编程/擦除完成后返回0x88,复位状态机 + if (addr >= 0x4000 && addr < 0xC000) { + if ((this._eraseStep === 4 && this._eraseType === 2) || + (this._eraseStep === 6 && this._eraseType === 3)) { + this._eraseStep = 0; + this._eraseType = 0; + for (var i = 0x4000; i < 0xC000; i++) this.io_read_map[i] = false; + return 0x88; + } + return this.memmap[addr >> 13][addr & 0x1FFF]; + } switch (addr) { - case 0x00: - return this.read00BankSwitch(); - case 0x02: - return this.read02Timer0Value(); - case 0x04: - return this.read04StopTimer0(); - case 0x05: - return this.read05StartTimer0; - case 0x06: - return this.read06StopTimer1(); - case 0x07: - return this.read07StartTimer1(); - case 0x3B: - return this.read3BUnknown(); - case 0x3F: - return this.read3FClock(); - default: - return this.ram[addr]; + case 0x00: return this.read00BankSwitch(); + case 0x02: return this.read02Timer0Value(); + case 0x04: return this.read04StopTimer0(); + case 0x05: return this.read05StartTimer0; + case 0x06: return this.read06StopTimer1(); + case 0x07: return this.read07StartTimer1(); + case 0x3B: return this.read3BUnknown(); + case 0x3F: return this.read3FClock(); + case 0x045F: + // 对应C++ Load():唤醒键值注入 + if (this.wakeUpPending) { + this.wakeUpPending = false; + this.ram[0x045F] = this.wakeUpKey; + } + return this.ram[0x045F]; + default: return this.ram[addr]; } }; + Wqx.prototype.read00BankSwitch = function (){ -// console.log('read00BankSwitch'); return this.ram[io00_bank_switch]; }; + Wqx.prototype.read04StopTimer0 = function (){ if (this.timer0started) { this.timer0value = this.read02Timer0Value(); this.timer0started = false; } -// if (this.timer0waveoutstart) { -// this.timer0waveoutstart = false; -// } -// console.log('read04StopTimer0: ' + this.ram[io04_general_ctrl]); return this.ram[io04_general_ctrl]; }; + Wqx.prototype.read02Timer0Value = function (){ if (this.timer0started) { this.timer0value = Math.floor((this.cpu.cycles - this.timer0startcycles) / SPDC1016Frequency) & 0xFF; } -// console.log('read02Timer0Value: ' + this.timer0value); return this.timer0value; }; + Wqx.prototype.read05StartTimer0 = function (){ - console.log('read05StartTimer0'); this.timer0started = true; this.timer0startcycles = this.cpu.cycles; -// if (this.read02Timer0Value() == 0x3F) { -// //gTimer0WaveoutStarted = 1; -// //mayTimer0Var1 = 0; -// //maypTimer0VarA8 = (int)&unk_4586A8; -// //mayTimer0Var2 = 0; -// //mayIO2345Var1 = 0; -// //ResetWaveout(&pwh); -// //OpenWaveout((DWORD_PTR)&pwh, 0x1F40u); -// this.timer0waveoutstart = true; -// } - return this.ram[io05_clock_ctrl]; // follow rulz by GGV + return this.ram[io05_clock_ctrl]; }; + Wqx.prototype.read06StopTimer1 = function (){ - console.log('read06StopTimer1: ' + this.ram[io04_general_ctrl]); - //todo return this.ram[io06_lcd_config]; }; + Wqx.prototype.read07StartTimer1 = function (){ - console.log('read06StopTimer1'); + // todo }; + Wqx.prototype.read3BUnknown = function (){ if (!(this.ram[0x3d] & 0x03)) { return this.clockRecords[0x3B] & 0xFE; } + return this.ram[0x3B]; }; + Wqx.prototype.read3FClock = function (){ return this.clockRecords[this.ram[62]] || 0; }; + Wqx.prototype.writeIO = function (addr, value){ -// console.log('writeIO: 0x' + addr.toString(16) + ', 0x' + value.toString(16) + ' @' + this._instCount); switch (addr) { - case 0x00: - return this.write00BankSwitch(value); - case 0x02: - return this.write02Timer0Value(value); - case 0x05: - return this.write05ClockCtrl(value); - case 0x06: - return this.write06LCDStartAddr(value); - case 0x08: - return this.write08Port0(value); - case 0x09: - return this.write09Port1(value); - case 0x0A: - return this.write0AROABBS(value); - case 0x0C: - return this.writeTimer01Control(value); - case 0x0D: - return this.write0DVolumeIDLCDSegCtrl(value); - case 0x0F: - return this.write0FZeroPageBankswitch(value); - case 0x20: - return this.write20JG(value); - case 0x23: - return this.write23JGWav(value); - case 0x3F: - return this.write3FClock(value); + case 0x00: return this.write00BankSwitch(value); + case 0x02: return this.write02Timer0Value(value); + case 0x05: return this.write05ClockCtrl(value); + case 0x06: return this.write06LCDStartAddr(value); + case 0x08: return this.write08Port0(value); + case 0x09: return this.write09Port1(value); + case 0x0A: return this.write0AROABBS(value); + case 0x0C: return this.writeTimer01Control(value); + case 0x0D: return this.write0DVolumeIDLCDSegCtrl(value); + case 0x0F: return this.write0FZeroPageBankswitch(value); + case 0x20: return this.write20JG(value); + case 0x23: return this.write23JGWav(value); + case 0x3F: return this.write3FClock(value); } if (addr >= this.lcdbuffaddr && addr < this.lcdbuffaddr + 1600) { return this.updateLCD(addr, value); @@ -362,9 +342,7 @@ var Wqx = (function (){ this.ram[addr] = value; }; - // decompiled. Wqx.prototype.write00BankSwitch = function (bank){ -// console.log('write00BankSwitch: ' + bank); if (this.ram[io00_bank_switch] !== bank) { if (bank < 0x20) { this.may4000ptr = this.norbankheader[bank]; @@ -381,8 +359,8 @@ var Wqx = (function (){ this.ram[io00_bank_switch] = bank; } }; + Wqx.prototype.write02Timer0Value = function (value){ -// console.log('write02Timer0Value: ' + value); if (this.timer0started) { this.timer0startcycles = (this.cpu.cycles - (value * SPDC1016Frequency / 10)); @@ -390,39 +368,72 @@ var Wqx = (function (){ this.timer0value = value; } }; + + // 修复:对应C++ Write05,bit3变化时控制睡眠状态 Wqx.prototype.write05ClockCtrl = function (value){ -// console.log('write05ClockCtrl: ' + value); - // FROM WQXSIM - // SPDC1016 - if (this.ram[io05_clock_ctrl] & 0x08) { - // old bit3, LCDON + _trace('write05ClockCtrl'); + var oldValue = this.ram[io05_clock_ctrl]; + // bit3 变化控制睡眠(LCD on = 唤醒,LCD off = 睡眠) + if ((oldValue ^ value) & 0x08) { + this.slept = !(value & 0x08); + } + // 原有 lcdoffshift0flag 逻辑保留 + if (oldValue & 0x08) { if ((value & 0x0F) === 0) { - // new bit0~bit3 is 0 this.lcdoffshift0flag = true; } } this.ram[io05_clock_ctrl] = value; }; + + // 对应C++ SetKey:处理按键的睡眠/唤醒逻辑 + Wqx.prototype.setKey = function (keyId, downOrUp){ + var row = keyId & 0x07; + var col = keyId >> 3; + var bits = (keyId === 0x0F) ? 0xFE : (1 << col); + var wakeUpKeyMap = { + 0x08: 0x00, 0x09: 0x0A, 0x0A: 0x08, 0x0B: 0x06, + 0x0C: 0x04, 0x0D: 0x02, 0x0E: 0x0C, 0x0F: 0x00 + }; + + if (downOrUp) { + this.keypadmatrix[row] |= bits; + if (this.slept) { + if (keyId >= 0x08 && keyId <= 0x0F && keyId !== 0x0E) { + this.wakeUpKey = wakeUpKeyMap[keyId]; + this.shouldWakeUp = true; + this.wakeUpPending = true; + this.slept = false; + } + } else { + if (keyId === 0x0F) { + this.slept = true; + } + } + } else { + this.keypadmatrix[row] &= ~bits; + } + }; + Wqx.prototype.setLcdStartAddr = function (addr){ this.lcdbuffaddr = addr; for (var i=0; i<1600; i++) { this.io_write_map[this.lcdbuffaddr+i] = true; } - console.log('lcdAddr: ' + this.lcdbuffaddr); }; + Wqx.prototype.write06LCDStartAddr = function (value){ - console.log('write06LCDStartAddr: ' + value); if (this.lcdbuffaddr == null) { this.setLcdStartAddr(((this.ram[io0C_lcd_config] & 0x03) << 12) | (value << 4)); } this.ram[io06_lcd_config] = value; - // SPDC1016 - // don't know how wqxsim works. - this.ram[io09_port1_data] &= 0xFE; // remove bit0 of port1 (keypad) + this.ram[io09_port1_data] &= 0xFE; }; + Wqx.prototype.write08Port0 = function (value){ this.ram[io0B_port3_data] &= 0xFE; }; + function buildByte(array){ return (array[0]) | (array[1] << 1) | @@ -433,16 +444,17 @@ var Wqx = (function (){ (array[6] << 6) | (array[7] << 7); } + Wqx.prototype.write09Port1 = function (value){ switch (value){ - case 0x01: this.ram[io08_port0_data] = buildByte(this.keypadmatrix[0]); break; - case 0x02: this.ram[io08_port0_data] = buildByte(this.keypadmatrix[1]); break; - case 0x04: this.ram[io08_port0_data] = buildByte(this.keypadmatrix[2]); break; - case 0x08: this.ram[io08_port0_data] = buildByte(this.keypadmatrix[3]); break; - case 0x10: this.ram[io08_port0_data] = buildByte(this.keypadmatrix[4]); break; - case 0x20: this.ram[io08_port0_data] = buildByte(this.keypadmatrix[5]); break; - case 0x40: this.ram[io08_port0_data] = buildByte(this.keypadmatrix[6]); break; - case 0x80: this.ram[io08_port0_data] = buildByte(this.keypadmatrix[7]); break; + case 0x01: this.ram[io08_port0_data] = this.keypadmatrix[0]; break; + case 0x02: this.ram[io08_port0_data] = this.keypadmatrix[1]; break; + case 0x04: this.ram[io08_port0_data] = this.keypadmatrix[2]; break; + case 0x08: this.ram[io08_port0_data] = this.keypadmatrix[3]; break; + case 0x10: this.ram[io08_port0_data] = this.keypadmatrix[4]; break; + case 0x20: this.ram[io08_port0_data] = this.keypadmatrix[5]; break; + case 0x40: this.ram[io08_port0_data] = this.keypadmatrix[6]; break; + case 0x80: this.ram[io08_port0_data] = this.keypadmatrix[7]; break; case 0: this.ram[io0B_port3_data] |= 1; if (this.keypadmatrix[7] === 0xFE) { @@ -452,149 +464,111 @@ var Wqx = (function (){ case 0x7F: if (this.ram[io15_port1_dir] === 0x7F) { this.ram[io08_port0_data] = ( - buildByte(this.keypadmatrix[0]) | - buildByte(this.keypadmatrix[1]) | - buildByte(this.keypadmatrix[2]) | - buildByte(this.keypadmatrix[3]) | - buildByte(this.keypadmatrix[4]) | - buildByte(this.keypadmatrix[5]) | - buildByte(this.keypadmatrix[6]) | - buildByte(this.keypadmatrix[7]) + this.keypadmatrix[0] | + this.keypadmatrix[1] | + this.keypadmatrix[2] | + this.keypadmatrix[3] | + this.keypadmatrix[4] | + this.keypadmatrix[5] | + this.keypadmatrix[6] | + this.keypadmatrix[7] ); break; } } this.ram[io09_port1_data] = value; }; + + // 修复:补充 map2000 切换 + // 对应C++ Write0A + SwitchVolume 里 memmap[1] = roa_bbs & 0x04 ? ram_page2 : ram_page1 Wqx.prototype.write0AROABBS = function (value){ -// console.log('write0AROABBS: ' + value); if (value !== this.ram[io0A_roa]) { this.memmap[mapC000] = getByteArray(this.bbsbankheader[value & 0x0F], 0, 0x2000); + this.memmap[map2000] = (value & 0x04) ? this.ram4000_6000 : this.ram2000_4000; this.ram[io0A_roa] = value; } }; + Wqx.prototype.writeTimer01Control = function (value){ -// console.log('writeTimer01Control: ' + value); if (this.lcdbuffaddr === null) { this.lcdbuffaddr = ((value & 0x03) << 12) | (this.ram[io06_lcd_config] << 4); - console.log('lcdAddr: ' + this.lcdbuffaddr); } this.ram[io0C_lcd_config] = value; }; - // decompiled. Wqx.prototype.write0DVolumeIDLCDSegCtrl = function (value){ -// console.log('write0DVolumeIDLCDSegCtrl: ' + value); + _trace('write0DVolumeIDLCDSegCtrl'); if (value !== this.ram[io0D_volumeid]) { - // bit0 changed. - // volume1,3 != volume0,2 var bank = this.ram[io00_bank_switch]; if ((value & 0x03) === 1) { - // Volume1 this.fillC000BIOSBank(this.volume1array); this.may4000ptr = this.volume1array[bank]; this.memmap[mapE000] = getByteArray(this.volume1array[0], 0x2000, 0x2000); } else if ((value & 0x03) === 3) { - // Volume2 this.fillC000BIOSBank(this.volume2array); this.may4000ptr = this.volume2array[bank]; this.memmap[mapE000] = getByteArray(this.volume2array[0], 0x2000, 0x2000); } else { - // Volume0 this.fillC000BIOSBank(this.volume0array); this.may4000ptr = this.volume0array[bank]; this.memmap[mapE000] = getByteArray(this.volume0array[0], 0x2000, 0x2000); } - - var page2000 = this.ram4000_6000; var roabbs = this.ram[io0A_roa]; - if (!(roabbs & 0x04)) { - page2000 = this.ram2000_4000; - } - if (this.memmap[map2000] !== page2000) { - this.memmap[map2000] = page2000; -// this.canvasCtx.clearRect(0, 0, 160, 80); - } - this.memmap[mapC000] = this.bbsbankheader[roabbs & 0x0F]; + // 对应C++ SwitchVolume: memmap[1] 根据 roa_bbs bit2 决定 + this.memmap[map2000] = (roabbs & 0x04) ? this.ram4000_6000 : this.ram2000_4000; + this.memmap[mapC000] = getByteArray(this.bbsbankheader[roabbs & 0x0F], 0, 0x2000); this.switch4000ToBFFF(); } this.ram[io0D_volumeid] = value; -// this._dbg_logMemmap(); }; + Wqx.prototype.write0FZeroPageBankswitch = function (value){ -// console.log('write0FZeroPageBankswitch: ' + value); var oldzpbank = this.ram[io0F_zp_bsw] & 0x07; var newzpbank = (value & 0x07); var newzpptr = this.getZeroPagePointer(newzpbank); if (oldzpbank !== newzpbank) { if (oldzpbank === 0) { - // oldzpbank == 0 - memcpy(this.zp40cache, this.ptr40, 0x40); // backup fixed 40~80 to cache - memcpy(this.ptr40, newzpptr, 0x40); // copy newbank to 40 + memcpy(this.zp40cache, this.ptr40, 0x40); + memcpy(this.ptr40, newzpptr, 0x40); } else { - // dangerous if exchange 00 <-> 40 - // oldaddr maybe 0 or 200~300 var oldzpptr = this.getZeroPagePointer(oldzpbank); memcpy(oldzpptr, this.ptr40, 0x40); if (newzpbank !== 0) { memcpy(this.ptr40, newzpptr, 0x40); } else { - memcpy(this.ptr40, this.zp40cache, 0x40); // copy backup to 40 + memcpy(this.ptr40, this.zp40cache, 0x40); } } } this.ram[io0F_zp_bsw] = value; }; + Wqx.prototype.getZeroPagePointer = function (bank){ - //.text:0040BFD0 bank = byte ptr 4 - //.text:0040BFD0 - //.text:0040BFD0 mov al, [esp+bank] - //.text:0040BFD4 cmp al, 4 - //.text:0040BFD6 jnb short loc_40BFE5 ; if (bank < 4) { - //.text:0040BFD8 xor eax, eax ; bank == 0,1,2,3 - //.text:0040BFD8 ; set bank = 0 - //.text:0040BFDA and eax, 0FFFFh ; WORD(bank) - //.text:0040BFDF add eax, offset gFixedRAM0 ; result = &gFixedRAM0[WORD(bank)]; - //.text:0040BFE4 retn ; } - //.text:0040BFE5 ; --------------------------------------------------------------------------- - //.text:0040BFE5 - //.text:0040BFE5 loc_40BFE5: ; CODE XREF: GetZeroPagePointer+6j - //.text:0040BFE5 movzx ax, al ; 4,5,6,7 - //.text:0040BFE9 add eax, 4 ; bank+=4 - //.text:0040BFEC shl eax, 6 ; bank *= 40; - //.text:0040BFEF and eax, 0FFFFh ; WORD(bank) - //.text:0040BFF4 add eax, offset gFixedRAM0 - //.text:0040BFF9 retn if (bank >= 4) { - // 4,5,6,7 - // 4 -> 200 5-> 240 return getByteArray(this.ram, (bank + 4) << 6, 0x40); } else { - // 0,1,2,3 return getByteArray(this.ram, 0, 0x40); } }; + Wqx.prototype.write20JG = function (value){ -// console.log('write20JG'); this.ram[io20_JG] = value; if (value === 0x80 || value === 0x40) { - // todo: this.ram[io20_JG] = 0; } }; Wqx.prototype.write23JGWav = function (value){ -// console.log('write23JGWav'); this.ram[io23_unknow] = value; if (value === 0xC2) { - // gMayJGBuff2[(unsigned __int8)gMayJGIndex] = gZeroPage[34]; + // todo } else if (value === 0xC4) { - + // todo } else if (value === 0x80) { this.ram[io20_JG] = 0x80; - // todo: } }; + Wqx.prototype.write3FClock = function (value){ if (this.ram[62] >= 0x07) { if (this.ram[62] === 0x0B) { @@ -608,7 +582,7 @@ var Wqx = (function (){ this.clockRecords[this.ram[62] % 80] = value; } } else { - if (!(this.clockRecords[0x0B] & 0x80)) { + if (!(this.clockRecords[0x0B] & 0x80)) { this.clockRecords[this.ram[62]] = value; } } @@ -621,142 +595,142 @@ var Wqx = (function (){ Wqx.prototype._eraseTemp1 = 0; Wqx.prototype._eraseTemp2 = 0; Wqx.prototype._eraseBuff = null; + + // 严格对照C++ Store()逻辑,else-if链完全一致 Wqx.prototype.writeGE4000 = function (addr, value){ -// console.log('writeGE4000: ' + addr.toString(16) + ', ' + value.toString(16)); - var buffer = this.memmap[addr >> 13].buffer; - // writable bank. - if (buffer === this.ram || buffer === this.ramRomBank1) { - this.memmap[addr >> 13][addr & 0x1FFF] = value; - if (buffer === this.ramRomBank1) { - console.log('write to ramRomBank1'); - } + // 对应C++:ram_page2/ram_page3判断(普通RAM写,最常见路径优先) + var seg = this.memmap[addr >> 13]; + if (seg.buffer === this.ram.buffer || seg === this.ramRomBank1) { + seg[addr & 0x1FFF] = value; return; } + if (addr >= 0xE000) { return; } + var bank = this.ram[io00_bank_switch]; if (bank >= 0x20) { return; } - // ############## - // # erasing .... - var self = this; - function erase_all_nor_banks(){ - for (var i=32; i--;) { - for (var j=0x8000; j--;) { - self.norbankheader[i][j] = 0xFF; - } - } - } - function erase_buff(){ - for (var j=256; j--;) { - self._eraseBuff[j] = 0xFF; - } - } + // ── Flash命令状态机,严格对照C++ else-if链 ────────────────── if (this._eraseStep === 0) { if (addr === 0x5555 && value === 0xAA) { this._eraseStep = 1; - return; - } else if (addr === 0x8000 && value === 0xF0) { - return; + // 开启Flash读拦截,以便CPU能读到0x88完成状态 + for (var i = 0x4000; i < 0xC000; i++) this.io_read_map[i] = true; } - } else if (this._eraseStep === 1) { + return; + } + + // C++: if(fp_step==1){...} else if(fp_step==2){...} — 互斥! + if (this._eraseStep === 1) { if (addr === 0xAAAA && value === 0x55) { this._eraseStep = 2; return; } + // step1不匹配:fall through到最后的0x8000/0xF0检查 } else if (this._eraseStep === 2) { if (addr === 0x5555) { - switch (value){ - case 0x90: - this._eraseSelectedBank = this.ram[io00_bank_switch]; - this._eraseTemp1 = this.norbankheader[this._eraseSelectedBank][0x4000]; - this._eraseTemp2 = this.norbankheader[this._eraseSelectedBank][0x4001]; - this.norbankheader[this._eraseSelectedBank][0x4000] = 0xC7; - this.norbankheader[this._eraseSelectedBank][0x4001] = 0xD5; + var newType = 0; + switch (value) { + case 0x90: newType = 1; break; + case 0xA0: newType = 2; break; + case 0x80: newType = 3; break; + case 0xA8: newType = 4; break; + case 0x88: newType = 5; break; + case 0x78: newType = 6; break; + } + if (newType) { + this._eraseType = newType; + if (this._eraseType === 1) { + // ID读取:备份bank+0x4000处的两字节,写入识别码 + this._eraseSelectedBank = bank; + this._eraseTemp1 = this.norbankheader[bank][0x4000]; + this._eraseTemp2 = this.norbankheader[bank][0x4001]; + // 对应C++:fp_step=3时才写识别码,这里只记录 + } this._eraseStep = 3; - this._eraseType = 1; return; - case 0xA0: this._eraseStep = 3; this._eraseType = 2; return; - case 0x80: this._eraseStep = 3; this._eraseType = 3; return; - case 0xA8: this._eraseStep = 3; this._eraseType = 4; return; - case 0x88: this._eraseStep = 3; this._eraseType = 5; return; - case 0x78: this._eraseStep = 3; this._eraseType = 6; return; } } + // step2不匹配:fall through } else if (this._eraseStep === 3) { - switch (this._eraseType) { - case 1: + if (this._eraseType === 1) { if (value === 0xF0) { + // 恢复备份,退出ID模式 this.norbankheader[this._eraseSelectedBank][0x4000] = this._eraseTemp1; this.norbankheader[this._eraseSelectedBank][0x4001] = this._eraseTemp2; this._eraseStep = 0; this._eraseType = 0; - return; } - break; - case 2: - this.may4000ptr[addr - 0x4000] &= value; + return; + } else if (this._eraseType === 2) { + // 字节编程:bank基址 + (addr - 0x4000),对应C++ bank + addr - 0x4000 + this.norbankheader[bank][addr - 0x4000] &= value; this._eraseStep = 4; return; - case 4: + } else if (this._eraseType === 4) { + this._eraseBuff[addr & 0xFF] &= value; this._eraseStep = 4; - this._eraseBuff[addr % 256] &= value; return; - case 3: - case 5: + } else if (this._eraseType === 3 || this._eraseType === 5) { if (addr === 0x5555 && value === 0xAA) { this._eraseStep = 4; return; } - break; } + // step3不匹配:fall through } else if (this._eraseStep === 4) { - switch (this._eraseType) { - case 3: - case 5: + if (this._eraseType === 3 || this._eraseType === 5) { if (addr === 0xAAAA && value === 0x55) { this._eraseStep = 5; return; } - break; } + // step4不匹配:fall through } else if (this._eraseStep === 5) { if (addr === 0x5555 && value === 0x10) { - erase_all_nor_banks(); - this._eraseStep = 6; + // 全片擦除 + for (var i = 0; i < 32; i++) { + for (var j = 0; j < 0x8000; j++) { + this.norbankheader[i][j] = 0xFF; + } + } if (this._eraseType === 5) { - erase_buff(); + for (var j = 0; j < 256; j++) this._eraseBuff[j] = 0xFF; } + this._eraseStep = 6; return; } if (this._eraseType === 3 && value === 0x30) { - var k = this.ram[io00_bank_switch]; - var a = addr - addr % 0x800 - 0x4000; - for (var j=0x800; j--;) { - this.norbankheader[k][a + j] = 0xFF; + // 扇区擦除:bank基址 + sector对齐偏移 + var offset = addr - 0x4000; + var sectorBase = offset - (offset % 0x800); + for (var j = 0; j < 0x800; j++) { + this.norbankheader[bank][sectorBase + j] = 0xFF; } this._eraseStep = 6; return; } if (this._eraseType === 5 && value === 0x48) { - erase_buff(); + for (var j = 0; j < 256; j++) this._eraseBuff[j] = 0xFF; this._eraseStep = 6; return; } + // step5不匹配:fall through } - // ????. + + // 任意step下:0x8000写0xF0复位状态机(对应C++末尾检查) if (addr === 0x8000 && value === 0xF0) { this._eraseStep = 0; this._eraseType = 0; - return; } - console.log('error occurs when operate in flash! ' + addr.toString(16) + ',' + value.toString(16)); }; Wqx.prototype.resetCpu = function (){ + _trace('resetCpu'); this.cpu = new M65C02Context(); this.cpu.ram = this.ram; this.cpu.memmap = this.memmap; @@ -764,22 +738,30 @@ var Wqx = (function (){ this.cpu.io_write_map = this.io_write_map; this.cpu.io_read = this.io_read; this.cpu.io_write = this.io_write; + // RAM已就绪,在固件从复位向量启动前同步日期和时间 + this.syncCalendar(); + this.syncClock(); this.cpu.cycles = 0; this.cpu.reg_a = 0; this.cpu.reg_x = 0; this.cpu.reg_y = 0; - // 00100100 unused P(bit5) = 1, I(bit3) = 1, B(bit4) = 0 this.cpu.set_reg_ps(0x24); - // assume 1FFC/1FFD in same stripe this.cpu.reg_pc = (this.memmap[7][0x1FFD] << 8) | this.memmap[7][0x1FFC]; this.cpu.reg_sp = 0x01FF; this.cpu.irq = 1; this.cpu.nmi = 1; this.cpu.wai = 0; this.cpu.stp = 0; + + // 重置睡眠状态 + this.slept = false; + this.shouldWakeUp = false; + this.wakeUpPending = false; + this.wakeUpKey = 0; }; Wqx.prototype.loadBROM = function (buffer){ + _trace('loadBROM'); var byteOffset = 0; while (byteOffset < buffer.byteLength) { var bufferSrc1 = getByteArray(buffer, byteOffset, 0x4000); @@ -790,10 +772,10 @@ var Wqx = (function (){ memcpy(bufferDest2, bufferSrc2, 0x4000); byteOffset += 0x8000; } - this.resetCpu(); }; Wqx.prototype.loadNorFlash = function (buffer){ + _trace('loadNorFlash'); var byteOffset = 0; while (byteOffset < buffer.byteLength) { var bufferSrc1 = getByteArray(buffer, byteOffset, 0x4000); @@ -804,26 +786,27 @@ var Wqx = (function (){ memcpy(bufferDest2, bufferSrc2, 0x4000); byteOffset += 0x8000; } - this.resetCpu(); }; + function uint8ArrayToBase64(bytes) { + var binary = ''; + var len = bytes.byteLength; + var chunk = 8192; + for (var i = 0; i < len; i += chunk) { + binary += String.fromCharCode.apply(null, bytes.subarray(i, i + chunk)); + } + return btoa(binary); + } + function base64ToUint8Array(base64) { + var binaryString = atob(base64); + var len = binaryString.length; + var bytes = new Uint8Array(len); + for (var i = 0; i < len; i++) { + bytes[i] = binaryString.charCodeAt(i); + } + return bytes; + } Wqx.prototype.updateLCD = function (addr, value){ -// var lcdBuffer = getByteArray(this.ram, this.lcdbuffaddr, 160*80/8); -// this.canvasCtx.clearRect(0, 0, 160, 80); -// for (var i=0; i<80; i++) { -// for (var j=0; j<20; j++) { -// var p = j * 8; -// var pixelsByte = lcdBuffer[20*i+j]; -// if (pixelsByte & 0x80) if (j > 0) this.canvasCtx.fillRect(p + 0, i, 1, 1); -// if (pixelsByte & 0x40) this.canvasCtx.fillRect(p + 1, i, 1, 1); -// if (pixelsByte & 0x20) this.canvasCtx.fillRect(p + 2, i, 1, 1); -// if (pixelsByte & 0x10) this.canvasCtx.fillRect(p + 3, i, 1, 1); -// if (pixelsByte & 0x08) this.canvasCtx.fillRect(p + 4, i, 1, 1); -// if (pixelsByte & 0x04) this.canvasCtx.fillRect(p + 5, i, 1, 1); -// if (pixelsByte & 0x02) this.canvasCtx.fillRect(p + 6, i, 1, 1); -// if (pixelsByte & 0x01) this.canvasCtx.fillRect(p + 7, i, 1, 1); -// } -// } var offset = addr - this.lcdbuffaddr; var oldValue = this.ram[addr]; var row = Math.floor(offset / 20); @@ -832,77 +815,60 @@ var Wqx = (function (){ var changed = oldValue ^ value; if (changed & 0x80) { - if (value & 0x80) { - if (col > 0) { - this.canvasCtx.fillRect(p + 0, row, 1, 1); - } - } else { - if (col > 0) { - this.canvasCtx.clearRect(p + 0, row, 1, 1); - } - } + if (value & 0x80) { if (col > 0) this.canvasCtx.fillRect(p + 0, row, 1, 1); } + else { if (col > 0) this.canvasCtx.clearRect(p + 0, row, 1, 1); } } if (changed & 0x40) { - if (value & 0x40) { - this.canvasCtx.fillRect(p + 1, row, 1, 1); - } else { - this.canvasCtx.clearRect(p + 1, row, 1, 1); - } + if (value & 0x40) this.canvasCtx.fillRect(p + 1, row, 1, 1); + else this.canvasCtx.clearRect(p + 1, row, 1, 1); } if (changed & 0x20) { - if (value & 0x20) { - this.canvasCtx.fillRect(p + 2, row, 1, 1); - } else { - this.canvasCtx.clearRect(p + 2, row, 1, 1); - } + if (value & 0x20) this.canvasCtx.fillRect(p + 2, row, 1, 1); + else this.canvasCtx.clearRect(p + 2, row, 1, 1); } if (changed & 0x10) { - if (value & 0x10) { - this.canvasCtx.fillRect(p + 3, row, 1, 1); - } else { - this.canvasCtx.clearRect(p + 3, row, 1, 1); - } + if (value & 0x10) this.canvasCtx.fillRect(p + 3, row, 1, 1); + else this.canvasCtx.clearRect(p + 3, row, 1, 1); } if (changed & 0x08) { - if (value & 0x08) { - this.canvasCtx.fillRect(p + 4, row, 1, 1); - } else { - this.canvasCtx.clearRect(p + 4, row, 1, 1); - } + if (value & 0x08) this.canvasCtx.fillRect(p + 4, row, 1, 1); + else this.canvasCtx.clearRect(p + 4, row, 1, 1); } if (changed & 0x04) { - if (value & 0x04) { - this.canvasCtx.fillRect(p + 5, row, 1, 1); - } else { - this.canvasCtx.clearRect(p + 5, row, 1, 1); - } + if (value & 0x04) this.canvasCtx.fillRect(p + 5, row, 1, 1); + else this.canvasCtx.clearRect(p + 5, row, 1, 1); } if (changed & 0x02) { - if (value & 0x02) { - this.canvasCtx.fillRect(p + 6, row, 1, 1); - } else { - this.canvasCtx.clearRect(p + 6, row, 1, 1); - } + if (value & 0x02) this.canvasCtx.fillRect(p + 6, row, 1, 1); + else this.canvasCtx.clearRect(p + 6, row, 1, 1); } if (changed & 0x01) { - if (value & 0x01) { - this.canvasCtx.fillRect(p + 7, row, 1, 1); - } else { - this.canvasCtx.clearRect(p + 7, row, 1, 1); - } + if (value & 0x01) this.canvasCtx.fillRect(p + 7, row, 1, 1); + else this.canvasCtx.clearRect(p + 7, row, 1, 1); } this.ram[addr] = value; }; - Wqx.prototype.mayClockFlags = 0; + // 修复:小时进位用 &= 0xC0 保留高2位标志,对应C++ clock_buff[2] &= 0xC0 Wqx.prototype.adjustTime = function (){ + _trace('adjustTime'); if (++this.clockRecords[0] >= 60) { this.clockRecords[0] = 0; if (++this.clockRecords[1] >= 60) { this.clockRecords[1] = 0; - if (++this.clockRecords[2] >= 24) { - this.clockRecords[2] &= 0; - ++this.clockRecords[3]; + // 小时只用低6位计数,高2位是标志位 + if ((this.clockRecords[2] & 0x3F) >= 23) { + this.clockRecords[2] &= 0xC0; // 保留高2位,清零小时计数 + this.clockRecords[14] = (this.clockRecords[14] + 1) % 7; + if (++this.clockRecords[3] > 31) { + this.clockRecords[3] = 1; + if (++this.clockRecords[8] > 12) { + this.clockRecords[8] = 1; + this.clockRecords[9] = (this.clockRecords[9] + 1) % 100; + } + } + } else { + this.clockRecords[2]++; } } } @@ -918,83 +884,232 @@ var Wqx = (function (){ } return false; }; +Wqx.prototype.saveState = function (){ + var state = { + ram: uint8ArrayToBase64(this.ram), + nor: uint8ArrayToBase64(this.nor), + ramRomBank1: uint8ArrayToBase64(this.ramRomBank1), + zp40cache: uint8ArrayToBase64(this.zp40cache), + cpu: { + reg_a: this.cpu.reg_a, + reg_x: this.cpu.reg_x, + reg_y: this.cpu.reg_y, + reg_pc: this.cpu.reg_pc, + reg_sp: this.cpu.reg_sp, + cycles: this.cpu.cycles, + flag_c: this.cpu.flag_c, + flag_z: this.cpu.flag_z, + flag_i: this.cpu.flag_i, + flag_d: this.cpu.flag_d, + flag_b: this.cpu.flag_b, + flag_u: this.cpu.flag_u, + flag_v: this.cpu.flag_v, + flag_n: this.cpu.flag_n + }, + timer0started: this.timer0started, + timer0value: this.timer0value, + timer0startcycles: this.timer0startcycles, // ← 新增 + timer1started: this.timer1started, + timer1value: this.timer1value, + mayClockFlags: this.mayClockFlags, + // 新增:保存 LCD 刷新所需的关键寄存器 + lcdbuffaddr: this.lcdbuffaddr, + frameCounter: this.frameCounter, + nmiCounter: this.nmiCounter, + clockCounter: this.clockCounter, + shouldIrq: this.shouldIrq + }; + return state; // 返回 state,不要在方法内写 localStorage,让调用者决定 +}; + +Wqx.prototype.loadState = function (state){ + try { + // 恢复 RAM + this.ram.set(base64ToUint8Array(state.ram)); + this.nor.set(base64ToUint8Array(state.nor)); + this.ramRomBank1.set(base64ToUint8Array(state.ramRomBank1)); + this.zp40cache.set(base64ToUint8Array(state.zp40cache)); + + // 重建 NOR 视图(重要!) + for (var i = 0; i < 32; i++) { + this.norbankheader[i] = getByteArray(this.nor, 0x8000 * i, 0x8000); + } + + // 重建 RAM 分段视图 + this.ram2000_4000 = getByteArray(this.ram, 0x2000, 0x2000); + this.ram4000_6000 = getByteArray(this.ram, 0x4000, 0x2000); + this.memmap[map0000] = getByteArray(this.ram, 0, 0x2000); + this.memmap[map2000] = this.ram2000_4000; + this.memmap[map4000] = this.ram4000_6000; + this.memmap[map6000] = getByteArray(this.ram, 0x6000, 0x2000); + this.memmap[map8000] = getByteArray(this.ram, 0x8000, 0x2000); + this.memmap[mapA000] = getByteArray(this.ram, 0xA000, 0x2000); + this.memmap[mapC000] = getByteArray(this.ram, 0xC000, 0x2000); + this.memmap[mapE000] = getByteArray(this.ram, 0xE000, 0x2000); + + // 恢复 CPU + this.cpu.reg_a = state.cpu.reg_a; + this.cpu.reg_x = state.cpu.reg_x; + this.cpu.reg_y = state.cpu.reg_y; + this.cpu.reg_pc = state.cpu.reg_pc; + this.cpu.reg_sp = state.cpu.reg_sp; + this.cpu.cycles = state.cpu.cycles; + this.cpu.flag_c = state.cpu.flag_c; + this.cpu.flag_z = state.cpu.flag_z; + this.cpu.flag_i = state.cpu.flag_i; + this.cpu.flag_d = state.cpu.flag_d; + this.cpu.flag_b = state.cpu.flag_b; + this.cpu.flag_u = state.cpu.flag_u; + this.cpu.flag_v = state.cpu.flag_v; + this.cpu.flag_n = state.cpu.flag_n; + + this.timer0started = state.timer0started; + this.timer0value = state.timer0value; + this.timer0startcycles = state.timer0startcycles || 0; // ← 兼容旧存档 + this.timer1started = state.timer1started; + this.timer1value = state.timer1value; + this.mayClockFlags = state.mayClockFlags; + + // 恢复计数器 + if (state.frameCounter !== undefined) this.frameCounter = state.frameCounter; + if (state.nmiCounter !== undefined) this.nmiCounter = state.nmiCounter; + if (state.clockCounter !== undefined) this.clockCounter = state.clockCounter; + if (state.shouldIrq !== undefined) this.shouldIrq = state.shouldIrq; + + // 重映射所有 bank(基于恢复后的寄存器值) + var volumeid = this.ram[io0D_volumeid]; + var bank = this.ram[io00_bank_switch]; + var roabbs = this.ram[io0A_roa]; + + // 重建 BIOS bank + if ((volumeid & 0x03) === 1) { + this.fillC000BIOSBank(this.volume1array); + this.memmap[mapE000] = getByteArray(this.volume1array[0], 0x2000, 0x2000); + } else if ((volumeid & 0x03) === 3) { + this.fillC000BIOSBank(this.volume2array); + this.memmap[mapE000] = getByteArray(this.volume2array[0], 0x2000, 0x2000); + } else { + this.fillC000BIOSBank(this.volume0array); + this.memmap[mapE000] = getByteArray(this.volume0array[0], 0x2000, 0x2000); + } + + // 重映射 4000-BFFF + if (bank < 0x20) { + this.may4000ptr = this.norbankheader[bank]; + } else if (bank >= 0x80) { + if (volumeid & 0x01) { + this.may4000ptr = this.volume1array[bank]; + } else if (volumeid & 0x02) { + this.may4000ptr = this.volume2array[bank]; + } else { + this.may4000ptr = this.volume0array[bank]; + } + } + this.switch4000ToBFFF(); + + // 重映射 C000 + this.memmap[mapC000] = getByteArray(this.bbsbankheader[roabbs & 0x0F], 0, 0x2000); + + // 重映射 2000 + var page2000 = (roabbs & 0x04) ? this.ram4000_6000 : this.ram2000_4000; + this.memmap[map2000] = page2000; + + // 恢复 LCD 缓冲区地址 + var lcdAddr = ((this.ram[io0C_lcd_config] & 0x03) << 12) | (this.ram[io06_lcd_config] << 4); + this.setLcdStartAddr(lcdAddr); + + // 如果保存了 lcdbuffaddr,直接恢复 + if (state.lcdbuffaddr !== null && state.lcdbuffaddr !== undefined) { + this.lcdbuffaddr = state.lcdbuffaddr; + for (var i = 0; i < 1600; i++) { + this.io_write_map[this.lcdbuffaddr + i] = true; + } + } + + // 重绘屏幕 + this.refreshLCD(); + + console.log('State restored'); + return true; + } catch (e) { + console.error('Failed to load state:', e); + return false; + } +}; + +// 辅助方法:全屏重绘 +Wqx.prototype.refreshLCD = function (){ + if (!this.lcdbuffaddr) return; + for (var i = 0; i < 1600; i++) { + var addr = this.lcdbuffaddr + i; + this.updateLCD(addr, this.ram[addr]); + } +}; + + + // 时间同步:仅同步 时、分、秒,保留 clockRecords[2] 高2位标志位 + Wqx.prototype.syncClock = function (){ + _trace('syncClock'); + var now = new Date(); + this.clockRecords[0] = now.getSeconds(); + this.clockRecords[1] = now.getMinutes(); + this.clockRecords[2] = (this.clockRecords[2] & 0xC0) | (now.getHours() & 0x3F); + }; + + // 日期同步:同步 年、月、日、星期 + Wqx.prototype.syncCalendar = function (){ + _trace('syncCalendar'); + var now = new Date(); + + // 兼容某些固件使用的 RAM 备份 + this.ram[0x472] = now.getFullYear() - 1881; // 年份偏移1881 + this.ram[0x473] = now.getMonth(); // 月份0-based + this.ram[0x474] = now.getDate() - 1; // 日 + }; + + // 从存档恢复后调用:只启动帧定时器,不resetCpu,保留已恢复的CPU状态 + Wqx.prototype.startFrame = function (){ + _trace('startFrame'); + if (!this.frameTimer) { + this.frameTimer = setInterval(this.frame.bind(this), 1000 / FrameRate); + } + }; Wqx.prototype.run = function (){ + _trace('run'); this._timerCounter = 0; this._instCount = 0; - this.clockRecords = new Uint8Array(80); + this.resetCpu(); if (!this.frameTimer) { this.frameTimer = setInterval(this.frame.bind(this), 1000 / FrameRate); } }; -// Wqx.prototype._loop = function (){ -// this.frame(); -// this.frameTimer = requestAnimationFrame(this._loop.bind(this), null); -// }; - Wqx.prototype.stop = function (){ clearInterval(this.frameTimer); this.frameTimer = null; }; Wqx.prototype.reset = function (){ + _trace('reset'); this.resetCpu(); this.frameCounter = 0; this.nmiCounter = 0; + this.clockCounter = 0; + this._eraseStep = 0; + this._eraseType = 0; }; Wqx.prototype.frame = function (){ var frameCycles = CyclesPerFrame * (this.frameCounter + 1); var nmiCycles = CyclesPerNMI * (this.nmiCounter + 1); var clockCycles = CyclesPer4Ms * (this.clockCounter + 1); - var lastCycles = 0; + while (this.cpu.cycles < frameCycles) { -// if (this._instCount === 2854234) { -// debugger; -// } - if (this._DEBUG && - typeof wqxsimlogs !== 'undefined' && - wqxsimlogs.length > 1) { - if (this._instCount >= wqxsimlogs.START && - this._instCount < wqxsimlogs.START + wqxsimlogs.length - 1) { - var log = wqxsimlogs[this._instCount - wqxsimlogs.START]; - var error = ''; - if (log.A !== this.cpu.reg_a) { - error += ' A '; - } - if (log.X !== this.cpu.reg_x) { - error += ' X '; - } - if (log.Y !== this.cpu.reg_y) { - error += ' Y '; - } - if (log.PS !== this.cpu.get_reg_ps()) { - error += ' PS '; - } - if (log.SP + 0x100 !== this.cpu.reg_sp) { - error += ' SP '; - } - if (log.PC !== this.cpu.reg_pc) { - error += ' PC '; - } - if (log.OP !== this.memmap[(this.cpu.reg_pc)>>13][(this.cpu.reg_pc)&0x1FFF]) { - error += ' OP '; - } -// if (log.X !== this.ram[0x20]) { -// error += ' X '; -// } - if (error) { - console.log(this._instCount + ': ' + error); - debugger; - this.stop(); - return; - } - } else if (this._instCount === wqxsimlogs.START + wqxsimlogs.length - 1) { - alert('good!'); - } - } + this.cpu.execute(); + + // NMI / timer0(每0.5秒触发一次) if (this.cpu.cycles >= nmiCycles) { this.nmiCounter++; nmiCycles += CyclesPerNMI; @@ -1009,31 +1124,41 @@ var Wqx = (function (){ } this.shouldIrq = true; } + + // IRQ 触发 if (this.shouldIrq && !this.cpu.flag_i) { this.cpu.irq = 0; this.shouldIrq = false; this.cpu.doIrq(); } - this._instCount ++; + + this._instCount++; + + // timer1(每4ms):含唤醒逻辑,对应C++ timer1_cycles 分支 if (this.cpu.cycles >= clockCycles) { - this.clockCounter ++; - this.clockRecords[4] ++; + this.clockCounter++; clockCycles += CyclesPer4Ms; - this.ram[io01_int_enable] |= 0x08; - this.shouldIrq = true; + this.clockRecords[4]++; + + if (this.shouldWakeUp) { + // 唤醒:对应C++ should_wake_up 分支 + this.shouldWakeUp = false; + this.ram[io01_int_enable] |= 0x01; + this.ram[0x02] |= 0x01; + // 跳回复位向量重新启动 + this.cpu.reg_pc = (this.memmap[7][0x1FFD] << 8) | this.memmap[7][0x1FFC]; + } else { + this.ram[io01_int_enable] |= 0x08; + this.shouldIrq = true; + } } -// if ((this._instCount - 6000) % 6000 === 0) { -// this.clockRecords[4] ++; -// this.ram[io01_int_enable] |= 0x08; -// this.shouldIrq = true; -// console.log(this.cpu.cycles - lastCycles); -// lastCycles = this.cpu.cycles; -// } + this.totalInsts++; } - document.title = (this.frameCounter); + + //document.title = String(this.frameCounter); this.frameCounter++; }; return Wqx; -})(); \ No newline at end of file +})(); diff --git a/sw.js b/sw.js new file mode 100644 index 0000000..c8937a2 --- /dev/null +++ b/sw.js @@ -0,0 +1,45 @@ +const CACHE_NAME = 'wqx-nc1020-v3.1.1'; +const ASSETS = [ + './', + './index.html', + './manifest.json', + './nc1020.png', + './icon-192.png', + './icon-512.png', + './rom.zip', + './src/m65c02.js', + './src/wqx.js', + './src/keyinput.js', + 'https://cdnjs.cloudflare.com/ajax/libs/BrowserFS/2.0.0/browserfs.min.js' +]; + +self.addEventListener('install', (event) => { + self.skipWaiting(); + event.waitUntil( + caches.open(CACHE_NAME).then((cache) => { + return cache.addAll(ASSETS); + }) + ); +}); + +self.addEventListener('activate', (event) => { + event.waitUntil( + caches.keys().then((cacheNames) => { + return Promise.all( + cacheNames.map((cacheName) => { + if (cacheName !== CACHE_NAME) { + return caches.delete(cacheName); + } + }) + ).then(() => self.clients.claim()); + }) + ); +}); + +self.addEventListener('fetch', (event) => { + event.respondWith( + caches.match(event.request).then((response) => { + return response || fetch(event.request); + }) + ); +});