├── .babelrc ├── .idea ├── .gitignore ├── vcs.xml ├── inspectionProfiles │ └── Project_Default.xml ├── modules.xml └── online6809.iml ├── .eslintrc.json ├── webpack.config.js ├── web.config ├── package.json ├── src ├── helper.js ├── memory8.js ├── constants.js ├── application.js ├── interface.js ├── opcodes.js └── assembler.js ├── README.md ├── test ├── assembler.test.js └── cputest.asm ├── .gitignore ├── notices.html └── help.html /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "env": { 3 | "test": { 4 | "plugins": ["@babel/plugin-transform-modules-commonjs"] 5 | } 6 | } 7 | } -------------------------------------------------------------------------------- /.idea/.gitignore: -------------------------------------------------------------------------------- 1 | # Default ignored files 2 | /shelf/ 3 | /workspace.xml 4 | # Editor-based HTTP Client requests 5 | /httpRequests/ 6 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.idea/inspectionProfiles/Project_Default.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "env": { 3 | "browser": true, 4 | "es2021": true 5 | }, 6 | "extends": "google", 7 | "overrides": [ 8 | ], 9 | "parserOptions": { 10 | "ecmaVersion": "latest", 11 | "sourceType": "module" 12 | }, 13 | "rules": { 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /.idea/online6809.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /webpack.config.js: -------------------------------------------------------------------------------- 1 | const {resolve} = require('path'); 2 | const NodePolyfillPlugin = require('node-polyfill-webpack-plugin'); 3 | module.exports = { 4 | resolve: { 5 | fallback: { 6 | "fs": false, 7 | }, 8 | }, 9 | entry: { 10 | emulator: './src/emulator.js', 11 | }, 12 | output: { 13 | path: resolve(__dirname, 'dist'), 14 | filename: 'bundle.js', 15 | library: 'bundle', 16 | }, 17 | plugins: [ 18 | new NodePolyfillPlugin(), 19 | ], 20 | mode: 'production', 21 | // mode: 'development', 22 | } -------------------------------------------------------------------------------- /web.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "online6809", 3 | "version": "1.1.11", 4 | "author": "Julian Brown", 5 | "description": "Update of online 6809 emulator", 6 | "homepage": "https://github.com/jimbro1000/online6809", 7 | "bugs": "https://github.com/jimbro1000/online6809/issues", 8 | "scripts": { 9 | "analysis": "eslint src/*.js", 10 | "test": "jest", 11 | "build": "webpack --stats-error-details && inline-script-tags src/index.html index.html" 12 | }, 13 | "devDependencies": { 14 | "@babel/plugin-transform-modules-commonjs": "^7.22.5", 15 | "eslint": "^8.45.0", 16 | "eslint-config-google": "^0.14.0", 17 | "inline-scripts": "^1.7.4", 18 | "jest": "^29.6.1", 19 | "jest-environment-jsdom": "^29.6.1", 20 | "webpack": "^5.88.1", 21 | "webpack-cli": "^5.1.4" 22 | }, 23 | "dependencies": { 24 | "elliptic": "^6.6.1", 25 | "node-polyfill-webpack-plugin": "^2.0.1", 26 | "setimmediate": "^1.0.5", 27 | "winston": "^3.10.0" 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/helper.js: -------------------------------------------------------------------------------- 1 | import winston from 'winston'; 2 | import 'setimmediate'; 3 | 4 | /** 5 | * Convert decimal to hexadecimal. 6 | * 7 | * @param {number} n number to convert 8 | * @param {number} l bit length of result 9 | * @return {string} 10 | */ 11 | function inHex(n, l = 8) { 12 | let s = n.toString(16).toUpperCase(); 13 | while (s.length < l) { 14 | s = '0' + s; 15 | } 16 | return s; 17 | } 18 | 19 | /** 20 | * Convert decimal to signed hexadecimal. 21 | * 22 | * @param {number} n number to convert 23 | * @param {number} bits bit length of result 24 | * @param {string} symbol symbol prefix 25 | * @return {string} 26 | */ 27 | function signedHex(n, bits, symbol) { 28 | const digits = (bits > 8) ? 4 : 2; 29 | if ((n & (1 << (bits - 1))) !== 0) { 30 | return '-' + symbol + inHex((1 << bits) - n, digits); 31 | } else { 32 | return symbol + inHex(n, digits); 33 | } 34 | } 35 | 36 | const tracing = 1; 37 | 38 | const logger = winston.createLogger({ 39 | level: 'info', 40 | format: winston.format.json(), 41 | defaultMeta: {service: 'online6809assembler'}, 42 | transports: [ 43 | new winston.transports.Console(), 44 | ], 45 | }); 46 | 47 | /** 48 | * Create an info level log entry. 49 | * 50 | * @param {string} caption log message 51 | * @param {Object} data object data to log 52 | * @param {boolean} force override logging flag 53 | */ 54 | function trc(caption, data, force= false) { 55 | if ((tracing !== 0) || (force)) { 56 | logger.info(caption + ' : ' + data); 57 | } 58 | } 59 | 60 | /** 61 | * Pluralise a word if needed. 62 | * 63 | * @param {string} word 64 | * @param {number} n 65 | * @param {string} wordPlural 66 | * @return {string} 67 | */ 68 | function plural(word, n, wordPlural) { 69 | if (n === 1) { 70 | return word; 71 | } else { 72 | if (wordPlural) { 73 | return (wordPlural); 74 | } else { 75 | return word + 's'; 76 | } 77 | } 78 | } 79 | 80 | export {inHex, signedHex, trc, plural}; 81 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Motorola 6809 Emulator # 2 | 3 | This is an update to Gwilym Thomas' emulator as hosted at 4 | http://6809.uk 5 | 6 | Since Gwilym originally published the emulator it has become 7 | apparent that there are some issues with both the compiler 8 | and the emulator. Unfortunately I've been unable to contact 9 | Gwilym, so I've just updated the code to fix issues myself 10 | 11 | The revised emulator is hosted at http://6809.ukdragons.org.uk 12 | 13 | A copy of the original wiki is hosted in the [wiki for this 14 | repository](https://github.com/jimbro1000/online6809/wiki) 15 | 16 | ## How to Build ## 17 | 18 | Some testing is implemented, currently enough to replicate 19 | error scenarios and verify any fixes. To run the test 20 | suite use the npm test script, or execute `npx jest` from 21 | a command line in the root of the project. 22 | 23 | To build the script bundle use the npm build script. This 24 | regenerates the build.js file under the dist folder. It 25 | also aggregates the solution into a single html file in 26 | the root folder. 27 | 28 | ## Running the Emulator ## 29 | 30 | Provided a build cycle has completed the emulator can be 31 | run as either the single file solution in the root of the 32 | folder or by opening index.html in the src folder. Both 33 | variants should work. 34 | 35 | ## Debug ## 36 | 37 | If you need to debug the solution it is vital to set the 38 | webpack.config.js file to use the development mode instead 39 | of production. This prevents obfuscation and minification 40 | of the source scripts. 41 | 42 | ## Known Issues ## 43 | 44 | * The compiler attempts to resolve relative branching within a 45 | fixed two pass execution which results in some offsets being 46 | incorrect. Temporary fix applied by extending to three passes 47 | but this needs revisiting to dynamically adjust the number of 48 | passes to allow offsets to settle (or error if oscillating 49 | indefinitely) 50 | * Data literals have issues with handling of strings and when 51 | the literal contains a match with a label or mnemonic token. 52 | Until fixed make sure labels end with a ":" to help differentiate -------------------------------------------------------------------------------- /test/assembler.test.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @jest-environment jsdom 3 | */ 4 | import {Assembler} from '../src/assembler'; 5 | import * as helper from '../src/helper'; 6 | 7 | describe("assembler", () => { 8 | let asm; 9 | beforeEach(() => { 10 | jest.spyOn(helper,"trc").mockImplementation(() => {}); 11 | asm = new Assembler(); 12 | }) 13 | describe("handling literals", () => { 14 | it.each([ 15 | ["$FC,EOT", ["$FC", "EOT"]], 16 | ["$00,$AA,$55,$FF", ["$00", "$AA", "$55", "$FF"]], 17 | ])("splits literals on commas", (example, expected) => { 18 | const result = asm.splitByComma(example); 19 | expect(result.length).toBe(expected.length); 20 | for (let i = 0; i < expected.length; ++i) { 21 | expect(result[i]).toBe(expected[i]); 22 | } 23 | }) 24 | it.each([ 25 | ['"LEAX [,X++]",EOT', ['"LEAX [,X++]"', 'EOT']] 26 | ])("matches pairs of double quotes to enclose strings", (example, expected) => { 27 | const result = asm.splitByComma(example); 28 | expect(result.length).toBe(expected.length); 29 | for (let i = 0; i < expected.length; ++i) { 30 | expect(result[i]).toBe(expected[i]); 31 | } 32 | }) 33 | it.each([ 34 | ["'LEAX [,X++]',EOT", ["'LEAX [,X++]'", 'EOT']] 35 | ])("matches pairs of single quotes to enclose strings", (example, expected) => { 36 | const result = asm.splitByComma(example); 37 | expect(result.length).toBe(expected.length); 38 | for (let i = 0; i < expected.length; ++i) { 39 | expect(result[i]).toBe(expected[i]); 40 | } 41 | }) 42 | }) 43 | describe('find mnemonic', () => { 44 | it('identifies an operation on a single byte code', () => { 45 | const operation = asm.opFind(206, 0); 46 | expect(operation).not.toBeNull(); 47 | expect(operation.op).toBe(206); 48 | expect(operation.mnem).toBe('LDU'); 49 | }) 50 | it.each([ 51 | [206, 16, 'LDS'], 52 | [206, '0x10', 'LDS'], 53 | ])('identifies an operation on a double byte code', (code, page, op) => { 54 | const operation = asm.opFind(code, page); 55 | expect(operation).not.toBeNull(); 56 | expect(operation.op).toBe(code); 57 | expect(operation.mnem).toBe(op); 58 | }) 59 | }) 60 | }) -------------------------------------------------------------------------------- /src/memory8.js: -------------------------------------------------------------------------------- 1 | import {inHex, trc} from './helper'; 2 | 3 | /** 4 | * Eight bit memory simulation. 5 | * 6 | * @param {number} size memory capacity in bytes 7 | * @constructor 8 | */ 9 | export function Memory8(size) { 10 | let i; 11 | this.mask = size - 1; 12 | this.windows = []; 13 | if (size > 0) { 14 | this.ram = new Array(size); 15 | for (i = 0; i < size; i++) { 16 | this.ram[i] = 0; 17 | } 18 | } 19 | this.wrap = function(address) { 20 | return address & this.mask; 21 | }; 22 | this.plus = function(address) { 23 | return (address + 1) & this.mask; 24 | }; 25 | this.plusplus = function(address) { 26 | return (address + 2) & this.mask; 27 | }; 28 | this.peek = function(address) { 29 | return this.ram[address & this.mask]; 30 | }; 31 | this.deek = function(address) { 32 | return (this.ram[address & this.mask] << 8) + 33 | this.ram[(address + 1) & this.mask]; 34 | }; 35 | this.poke = function(address, byte) { 36 | byte = byte & 0xff; 37 | this.ram[address] = byte; 38 | this.checkWindow(address, byte); 39 | }; 40 | this.read = function(address) { 41 | return [this.wrap(address + 1), this.peek(address)]; 42 | }; 43 | this.fill = function(address, bytes) { 44 | let i = 0; 45 | while (i < bytes.length) { 46 | this.poke(address + i, bytes[i]); 47 | trc('Fill', inHex(bytes[i], 2)); 48 | if ((address + i + 1) !== this.wrap(address + i + 1)) { 49 | break; 50 | } else { 51 | i++; 52 | } 53 | } 54 | return address + i; 55 | }; 56 | this.addWindow = function(holder, base, length) { 57 | const freshWin = new RAMWindow(holder, base, length); 58 | this.windows.push(freshWin); 59 | return freshWin; 60 | }; 61 | this.removeWindow = function(base, length, handle) { 62 | let i; 63 | if (handle == null) { 64 | for (i = this.windows.length - 1; i >= 0; i--) { 65 | if ((this.windows[i].base === base) && 66 | (this.windows[i].ending === base + length)) { 67 | this.windows.splice(i, 1); 68 | trc( 69 | 'Removed array splice at ', 70 | i + ' with base=' + base + ' length=' + length, 71 | ); 72 | } 73 | } 74 | } else { 75 | i = this.windows.indexOf(handle); 76 | trc('removeWindow by handle', i); 77 | if (i >= 0) { 78 | this.windows.splice(i, 1); 79 | } 80 | } 81 | }; 82 | this.checkWindow = function(address, value) { 83 | for (let i = 0; i < this.windows.length; i++) { 84 | const window = this.windows[i]; 85 | if ((address >= window.base) && (address < window.ending)) { 86 | window.holder.update(window.holder, address, value); 87 | } 88 | } 89 | }; 90 | } 91 | 92 | const RAMWindow = function(holderObject, RAMbase, RAMLength) { 93 | this.base = RAMbase; 94 | this.ending = this.base + RAMLength; 95 | this.holder = holderObject; 96 | }; 97 | -------------------------------------------------------------------------------- /src/constants.js: -------------------------------------------------------------------------------- 1 | const SIbaseAddress = 0xff80; 2 | const SIrefreshOff = 0; 3 | const SIrefreshOn = 1; 4 | const SIgraphicsMode = 2; 5 | const SIkeyInterface = 3; 6 | /* System Interface 7 | SIrefreshOff 8 | Write to force OFF register refresh and display animation 9 | SIrefreshOn 10 | Write to re-enable register refresh and display animation 11 | SIgraphicsMode 12 | Write to select graphics mode (2, 4, 16 allowed values) 13 | SIkeyInterface 14 | Write 0 then read an ASCII code (if<128), 15 | write 255 to clear the keyboard buffer 16 | */ 17 | 18 | const Defaults = {org: 0x4000, lineBytes: 0x20}; 19 | 20 | const keyCodesList = { 21 | '0': 0, 22 | '1': 1, 23 | '2': 2, 24 | '3': 3, 25 | '4': 4, 26 | '5': 5, 27 | '6': 6, 28 | '7': 7, 29 | '8': 8, 30 | '9': 9, 31 | 'A': 10, 32 | 'B': 11, 33 | 'C': 12, 34 | 'D': 13, 35 | 'E': 14, 36 | 'F': 15, 37 | }; 38 | 39 | const blockChars = [ 40 | ' ', 41 | '▗', 42 | '▖', 43 | '▄', 44 | '▝', 45 | '▐', 46 | '▞', 47 | '▟', 48 | '▘', 49 | '▚', 50 | '▌', 51 | '▙', 52 | '▀', 53 | '▜', 54 | '▛', 55 | '█', 56 | ' ']; 57 | 58 | const blockClasses = [ 59 | 'txtGGreen', 60 | 'txtGYellow', 61 | 'txtGBlue', 62 | 'txtGRed', 63 | 'txtGWhite', 64 | 'txtGCyan', 65 | 'txtGMagenta', 66 | 'txtGOrange']; 67 | 68 | const modes = { 69 | simple: 0x01, 70 | bits8: 0x00, 71 | bits16: 0x02, 72 | immediate: 0x04, 73 | direct: 0x08, 74 | indexed: 0x10, 75 | extended: 0x20, 76 | pcr: 0x40, 77 | register: 0x80, 78 | pager: 0x100, 79 | pair: 0x02, 80 | pseudo: 0x8000, 81 | }; 82 | 83 | const modesText = { 84 | 0x04: 'Immediate', 85 | 0x08: 'Direct', 86 | 0x10: 'Indexed', 87 | 0x20: 'Extended', 88 | 0x40: 'PCR', 89 | 0x80: 'Register', 90 | }; 91 | 92 | const pairRegsToText = { 93 | 0: 'regD', 94 | 1: 'regX', 95 | 2: 'regY', 96 | 3: 'regU', 97 | 4: 'regS', 98 | 5: 'regPC', 99 | 6: '', 100 | 7: '', 101 | 8: 'regA', 102 | 9: 'regB', 103 | 10: 'regCC', 104 | 11: 'regDP', 105 | }; 106 | 107 | const pairRegsToValue = { 108 | 'D': 0, 'X': 1, 'Y': 2, 'U': 3, 'S': 4, 109 | 'PC': 5, 'A': 8, 'B': 9, 'CC': 10, 'DP': 11, 110 | }; 111 | 112 | const fullRegsToTextS = [ 113 | 'regCC', 'regA', 'regB', 'regDP', 'regX', 'regY', 'regU', 'regPC', 114 | ]; 115 | 116 | const fullRegsToTextU = [ 117 | 'regCC', 'regA', 'regB', 'regDP', 'regX', 'regY', 'regS', 'regPC', 118 | ]; 119 | 120 | const fullRegsToValue = { 121 | 'CC': 0x01, 122 | 'A': 0x02, 123 | 'B': 0x04, 124 | 'D': 0x06, 125 | 'DP': 0x08, 126 | 'X': 0x10, 127 | 'Y': 0x20, 128 | 'U': 0x40, 129 | 'S': 0x40, 130 | 'PC': 0x80, 131 | }; 132 | 133 | export { 134 | SIbaseAddress, 135 | SIrefreshOff, 136 | SIrefreshOn, 137 | SIgraphicsMode, 138 | SIkeyInterface, 139 | Defaults, 140 | keyCodesList, 141 | blockChars, 142 | blockClasses, 143 | modes, 144 | modesText, 145 | pairRegsToText, 146 | pairRegsToValue, 147 | fullRegsToTextS, 148 | fullRegsToTextU, 149 | fullRegsToValue, 150 | }; 151 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ### VisualStudioCode template 2 | .vscode/* 3 | !.vscode/settings.json 4 | !.vscode/tasks.json 5 | !.vscode/launch.json 6 | !.vscode/extensions.json 7 | !.vscode/*.code-snippets 8 | 9 | # Local History for Visual Studio Code 10 | .history/ 11 | 12 | # Built Visual Studio Code Extensions 13 | *.vsix 14 | 15 | ### JetBrains template 16 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider 17 | # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 18 | 19 | # User-specific stuff 20 | .idea/**/workspace.xml 21 | .idea/**/tasks.xml 22 | .idea/**/usage.statistics.xml 23 | .idea/**/dictionaries 24 | .idea/**/shelf 25 | 26 | # AWS User-specific 27 | .idea/**/aws.xml 28 | 29 | # Generated files 30 | .idea/**/contentModel.xml 31 | 32 | # Sensitive or high-churn files 33 | .idea/**/dataSources/ 34 | .idea/**/dataSources.ids 35 | .idea/**/dataSources.local.xml 36 | .idea/**/sqlDataSources.xml 37 | .idea/**/dynamic.xml 38 | .idea/**/uiDesigner.xml 39 | .idea/**/dbnavigator.xml 40 | 41 | # Gradle 42 | .idea/**/gradle.xml 43 | .idea/**/libraries 44 | 45 | # Gradle and Maven with auto-import 46 | # When using Gradle or Maven with auto-import, you should exclude module files, 47 | # since they will be recreated, and may cause churn. Uncomment if using 48 | # auto-import. 49 | # .idea/artifacts 50 | # .idea/compiler.xml 51 | # .idea/jarRepositories.xml 52 | # .idea/modules.xml 53 | # .idea/*.iml 54 | # .idea/modules 55 | # *.iml 56 | # *.ipr 57 | 58 | # CMake 59 | cmake-build-*/ 60 | 61 | # Mongo Explorer plugin 62 | .idea/**/mongoSettings.xml 63 | 64 | # File-based project format 65 | *.iws 66 | 67 | # IntelliJ 68 | out/ 69 | 70 | # mpeltonen/sbt-idea plugin 71 | .idea_modules/ 72 | 73 | # JIRA plugin 74 | atlassian-ide-plugin.xml 75 | 76 | # Cursive Clojure plugin 77 | .idea/replstate.xml 78 | 79 | # SonarLint plugin 80 | .idea/sonarlint/ 81 | 82 | # Crashlytics plugin (for Android Studio and IntelliJ) 83 | com_crashlytics_export_strings.xml 84 | crashlytics.properties 85 | crashlytics-build.properties 86 | fabric.properties 87 | 88 | # Editor-based Rest Client 89 | .idea/httpRequests 90 | 91 | # Android studio 3.1+ serialized cache file 92 | .idea/caches/build_file_checksums.ser 93 | 94 | ### Windows template 95 | # Windows thumbnail cache files 96 | Thumbs.db 97 | Thumbs.db:encryptable 98 | ehthumbs.db 99 | ehthumbs_vista.db 100 | 101 | # Dump file 102 | *.stackdump 103 | 104 | # Folder config file 105 | [Dd]esktop.ini 106 | 107 | # Recycle Bin used on file shares 108 | $RECYCLE.BIN/ 109 | 110 | # Windows Installer files 111 | *.cab 112 | *.msi 113 | *.msix 114 | *.msm 115 | *.msp 116 | 117 | # Windows shortcuts 118 | *.lnk 119 | 120 | ### macOS template 121 | # General 122 | .DS_Store 123 | .AppleDouble 124 | .LSOverride 125 | 126 | # Icon must end with two \r 127 | Icon 128 | 129 | # Thumbnails 130 | ._* 131 | 132 | # Files that might appear in the root of a volume 133 | .DocumentRevisions-V100 134 | .fseventsd 135 | .Spotlight-V100 136 | .TemporaryItems 137 | .Trashes 138 | .VolumeIcon.icns 139 | .com.apple.timemachine.donotpresent 140 | 141 | # Directories potentially created on remote AFP share 142 | .AppleDB 143 | .AppleDesktop 144 | Network Trash Folder 145 | Temporary Items 146 | .apdisk 147 | 148 | # Node 149 | dist/ 150 | node_modules/ 151 | -------------------------------------------------------------------------------- /notices.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Updates and Notices 7 | 20 | 21 | 22 |
23 |

Home

24 |
25 |
26 |

Notices

27 |

28 | The updated version of the 6809 emulator is hosted at 29 | http://6809.ukdragons.org.uk while the original author is un-contactable. If you know the author please 30 | get in touch! 31 |

32 |

33 | The source code for the site is held at github.com, 34 | this also includes the site wiki and issue tracking. If you find any problems please visit the issues area 35 | and enter any information you can provide on the problem. 36 |

37 |

Updates

38 |

39 | Version 1.1.11
40 | Fixes: 41 |

42 |
    43 |
  • Updates to remove potential code vulnerabilities
  • 44 |
45 |

46 | Version 1.1.10
47 | Fixes: 48 |

49 |
    50 |
  • Updates to remove potential code vulnerabilities
  • 51 |
52 |

53 | Version 1.1.9
54 | Fixes: 55 |

56 |
    57 |
  • Updates to remove potential code vulnerabilities
  • 58 |
59 |

60 | Version 1.1.8
61 | Fixes: 62 |

63 |
    64 |
  • Updates to remove potential code vulnerabilities
  • 65 |
66 |

67 | Version 1.1.7
68 | Fixes: 69 |

70 |
    71 |
  • Fix handling of hexadecimal literal data
  • 72 |
73 |

74 | Version 1.1.6
75 | Fixes: 76 |

77 |
    78 |
  • Correct regex declarations
  • 79 |
80 |

81 | Version 1.1.5
82 | Fixes: 83 |

84 |
    85 |
  • Update dependencies due to security vulnerabilities
  • 86 |
87 |

88 | Version 1.1.4
89 | Fixes: 90 |

91 |
    92 |
  • Code quality improvements to facilitate CI pipeline
  • 93 |
94 |

95 | Version 1.1.3
96 | Fixes: 97 |

98 |
    99 |
  • Let disassembler see the list of labels
  • 100 |
101 |

102 | Version 1.1.2
103 | Fixes: 104 |

105 |
    106 |
  • Remedy incorrect constant index offset calculation
  • 107 |
108 |

109 | Version 1.1.1
110 | Fixes: 111 |

112 |
    113 |
  • Stabilise behaviour in Firefox browser
  • 114 |
115 |

116 | Version 1.1.0
117 | Fixes: 118 |

119 |
    120 |
  • String literals can be enclosed in single or double quotes
  • 121 |
  • Post increment directives in indexed addressing now works in more operations
  • 122 |
  • 6809 Assembler is now a separate object, decoupled from the emulator
  • 123 |
  • Assembler now pushes status updates as events instead of writing to the host page
  • 124 |
125 |

126 | Version 1.0.2
127 | Fixes: 128 |

129 |
    130 |
  • Build task correctly injects all the scripts into the host html page
  • 131 |
132 |

133 | Version 1.0.1
134 | Fixes: 135 |

136 |
    137 |
  • The compiler now makes 3 passes instead of 2 in order to stabilise labels
  • 138 |
139 |

Known Problems

140 |
    141 |
  • Assembler is over-enthusiastic when decoding mnemonics and likes to include labels and data
  • 142 |
  • Assembler does not know how to handle hints to force 8 bit or 16 bit offsets in indexed addressing
  • 143 |
144 |
145 | 146 | 147 | -------------------------------------------------------------------------------- /help.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 6809 Emulator Documentation 10 | 11 | 23 | 24 | 25 | 26 | 27 | 28 |
29 |

Home

30 |
31 |
32 |

Introduction

33 |

34 | This is an online emulator designed to make it as easy as possible to get started programming the Motorola 6809 CPU in assembly language. 35 | There's the obligatory Hello World program ready for you to assemble (click the big green button marked Assemble...) 36 | and run (click the big green button marked Run (it's beneath all the dials and knobs to the left)). 37 | If all goes well you will see a greeting appear on the emulated text screen (the horrid-looking box below with all the green @ symbols). 38 |

39 |

40 | If you're familiar with the 6809 hopefully the rest is pretty self-explanatory. 41 | There are a few short programs included to help you along (move your pointer to Examples). 42 |

43 |

44 | If you know some other machine language than the 6809, then it should be easy to pick up using the documentation here. 45 | A reference book wouldn't go amiss though. 46 |

47 |

48 | Even if you know nothing of machine language, try having a go anyway. 49 | A grounding in some other programming language will certainly help. Along with one or more reference books or instructional videos. 50 | But seriously, the best introduction to assembly language I've seen on Youtube is 51 | Computerphile:- Game Physics (in Assembler), which uses the 68000 CPU. 52 |

53 | 54 |

The 6809

55 |

Motorola launched its advanced 8-bit 6809 in 1977. 56 | It was a successor to the 6800 popular in embedded systems, and was mostly source-code compatible with it while offering many extra features. 57 | Due mainly to its late arrival it was never as popular as the 6502 and Z80 micros, but it could be found in the Dragon and Tandy Coco home Computers, 58 | as well as in less visible platforms such as the Vectrex console and several arcade cabinets including Defender. 59 |

60 |

61 | The 6809 has two 8-bit accumulators (A & B), two 16-bit index registers (X & Y), and two 16-bit stack pointers (U & S) which can double as index registers. 62 | All the 8 and 16-bit user registers offer Load, Store, and Compare (fully signed) instructions across the four main addressing modes (Immediate, Direct Paged, Direct Extended, and Indexed). 63 |

64 |

65 | The 8-bit accumulators have the usual set of one and two operand arithmetic and logical instructions. 66 | They can be combined into the 16-bit D register which has basic instructions for Addition and Subtraction, and also is the destination for the unsigned Multiply of A & B. 67 |

68 |

69 | There are 16 different conditional branches which can all have either 8 or 16 bit offsets, reaching any point in memory. 70 | Subroutines can be Branched to as well as Jumped to. 71 | The indexed addressing mode includes a mode with an offset from the Program Counter (8 or 16-bit), thus there is no barrier to writing fully position independent code. 72 |

73 |

System registers are the Condition Codes (CC), Program Counter (PC) and the Direct Page register (DP). 74 | The DP provides the high 8 bits for an address specified in a single byte in Direct Paged addressing mode. 75 | The CC can have any or all bits set or reset at once with the ORCC and ANDCC immediate mode instructions. 76 | Otherwise no instructions are provided for manipulating the system registers directly. 77 | The Transfer and Exchange instructions must be used instead, which work on any pair of registers the same size. 78 | The User (U) and System (S) stacks can have any combination of registers Pushed or Pulled in a single instruction. 79 | Subroutine return addresses and interrupts use the System stack only, the User stack has no system function. 80 |

81 |

82 | As well as the standard Interrupt (IRQ) and Non-maskable Interrupt (NMI) there is the Fast Interrupt (FIRQ) which gives faster response by only stacking the CC. 83 | There are three Software Interrupts with their own user-definable vectors. 84 |

85 |

86 | Indexed addressing is very flexible, working across all four index registers with options for constant offsets (5, 8, or 16-bit), accumulator offsets (A, B or D), 87 | and automatic post-increment and pre-decrement (by 1 or 2). 88 | All indexed modes can optionally be made Indirect, where the operand provides the address of the true operand. 89 | PC relative comes under the Indexed mode umbrella so is available with indirection, and there's also a plain address Indirect mode. 90 | The Load Effective Address is used for initialising pointers to memory objects, or for performing simple arithmetic on index registers. 91 | It calculates the address of the operand as normal, but instead of loading a value from the address loads the address itself. 92 |

93 | 94 |

95 | Altogether the 6809 is a flexible and powerful programming platform that is a pleasure to use. 96 | Its weaknesses are its relatively few registers, and low clock speed and good but sub-optimal efficiency. 97 |

98 | 99 |

Back to the emulator

100 |
101 | 102 | -------------------------------------------------------------------------------- /src/application.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Custom slider for controlling CPU step interval. 3 | */ 4 | class SlideControl { 5 | #cpu; 6 | #value; 7 | #speed; 8 | #readout; 9 | #slider; 10 | 11 | /** 12 | * Inject CPU and set default interval. 13 | * 14 | * @param {CPU} cpu bound CPU 15 | * @param {number} speed default step interval 16 | */ 17 | constructor(cpu, speed) { 18 | this.#cpu = cpu; 19 | this.#speed = Math.trunc(speed); 20 | this.#slider = null; 21 | this.#readout = null; 22 | this.#value = 0; 23 | } 24 | 25 | /** 26 | * Bind control to given UI elements. 27 | * 28 | * @param {String} slideElement slide control element name 29 | * @param {String} textElement text readout element name 30 | */ 31 | bindId(slideElement, textElement) { 32 | this.#readout = document.getElementById(textElement); 33 | this.#slider = document.getElementById(slideElement); 34 | this.#slider.addEventListener('click', this.update.bind(this), false); 35 | this.#slider.min = 1; 36 | this.#slider.max = 10; 37 | this.#speed = Math.max(this.#slider.min, this.#speed); 38 | this.#slider.value = Math.min(this.#speed, this.#slider.max); 39 | this.#cpu.intervalMils = this.#cpu.speedMils[this.#slider.value]; 40 | this.#value = parseInt(this.#slider.value); 41 | this.#readout.innerHTML = this.#value; 42 | } 43 | 44 | /** 45 | * Update CPU with new interval step. 46 | * 47 | * @param {Object} event slide control change event 48 | */ 49 | update(event) { 50 | this.#value = parseInt(event.srcElement.value); 51 | this.#readout.innerHTML = this.#value; 52 | this.#cpu.setSpeed(this.#value); 53 | } 54 | } 55 | 56 | /** 57 | * Event consumer for assembly status updates. 58 | * 59 | * @param {Object} event assembly status event 60 | */ 61 | function statusEventHandler(event) { 62 | const statusBox = document.getElementById('assemblyStatus'); 63 | if (statusBox != null) { 64 | statusBox.innerHTML = event.detail.message; 65 | } 66 | event.preventDefault(); 67 | } 68 | 69 | /** 70 | * Disassemble visible code. 71 | * 72 | * @param {String} id target elementId name 73 | */ 74 | function codeDump(id) { // eslint-disable-line no-unused-vars 75 | let block; 76 | let text = ''; 77 | for (block in mc6809.codeBlocks) { 78 | if (Object.prototype.hasOwnProperty.call(mc6809.codeBlocks, block)) { 79 | text += mc6809.codeBlocks[block].writeCode() + '\n'; 80 | } 81 | } 82 | const element = document.getElementById(id); 83 | if (element !== null) { 84 | element.value = text; 85 | } 86 | } 87 | 88 | /** 89 | * Start assembly process. 90 | * 91 | * @param {String} id elementId name of source container 92 | */ 93 | function compileRun(id) { // eslint-disable-line no-unused-vars 94 | const element = document.getElementById(id); 95 | if (element) { 96 | mc6809.assemble(element.value.split('\n')); 97 | mc6809.refresh(1); 98 | } 99 | } 100 | 101 | /** 102 | * Refresh UI with machine state. 103 | */ 104 | function machineRefresh() { 105 | const refresh= document.getElementById('refreshCheck'); 106 | if (refresh) { 107 | if (refresh.checked) { 108 | mc6809.refresh(1); 109 | } 110 | mc6809.refreshOn = refresh.checked; 111 | } 112 | } 113 | 114 | /** 115 | * Add watchpoint frame. 116 | * 117 | * @param {String} where address reference (EA/X/APPEND) 118 | */ 119 | function addWatchpoint(where) { // eslint-disable-line no-unused-vars 120 | switch (where.toUpperCase()) { 121 | case 'EA': 122 | mc6809.watchList.addWatch(mc6809.alu.eaLast); 123 | break; 124 | case 'X': 125 | mc6809.watchList.addWatch(mc6809.registers['regX'].regValue); 126 | break; 127 | case 'APPEND': 128 | mc6809.watchList.addWatch(mc6809.watchList.lastWatch + 0x10); 129 | break; 130 | } 131 | } 132 | 133 | /** 134 | * Force CPU reset. 135 | */ 136 | function machineReset() { // eslint-disable-line no-unused-vars 137 | machineInterrupt('reset'); 138 | } 139 | 140 | /** 141 | * Trigger named interrupt. 142 | * 143 | * @param {String} irqName interrupt name (NMI/IRQ/FIRQ) 144 | */ 145 | function machineInterrupt(irqName) { 146 | bundle.trc('machineInterrupt', irqName); 147 | mc6809.alu.interrupt(irqName); 148 | mc6809.alu.checkInterrupts(); 149 | mc6809.refresh(1); 150 | mc6809.execute(); 151 | } 152 | 153 | /** 154 | * Stop CPU auto-cycle. 155 | */ 156 | function machineHalt() { // eslint-disable-line no-unused-vars 157 | console.dir(document.getElementById('registers-container')); 158 | mc6809.stop(); 159 | mc6809.refresh(1); 160 | } 161 | 162 | /** 163 | * Start CPU auto-cycle. 164 | */ 165 | function machineRun() { // eslint-disable-line no-unused-vars 166 | machineRefresh(); 167 | mc6809.execute(); 168 | } 169 | 170 | /** 171 | * CPU cycle callback. 172 | */ 173 | function machineCycle() { // eslint-disable-line no-unused-vars 174 | mc6809.cycle(); 175 | } 176 | 177 | /** 178 | * Step CPU by 1 instruction. 179 | */ 180 | function machineStep() { // eslint-disable-line no-unused-vars 181 | mc6809.stop(); 182 | mc6809.cycle(); 183 | if (!mc6809.refreshOn) { 184 | mc6809.refresh(1); 185 | } 186 | } 187 | 188 | /** 189 | * Trigger Interrupt (IRQ). 190 | */ 191 | function doIRQ() { // eslint-disable-line no-unused-vars 192 | mc6809.alu.interrupt('irq'); 193 | mc6809.alu.checkInterrupts(); 194 | } 195 | 196 | /** 197 | * Trigger Fast Interrupt (FIRQ). 198 | */ 199 | function doFIRQ() { // eslint-disable-line no-unused-vars 200 | mc6809.alu.interrupt('firq'); 201 | mc6809.alu.checkInterrupts(); 202 | } 203 | 204 | /** 205 | * Refresh UI with updated program counter. 206 | * 207 | * @param {number} PC program counter 208 | * @param {boolean} force force update 209 | */ 210 | function machineOrg(PC, force) { // eslint-disable-line no-unused-vars 211 | mc6809.registers['regPC'].change(PC, 0); 212 | mc6809.dsmTable.lineOn(mc6809.registers['regPC'].regValue, force); 213 | } 214 | 215 | document.addEventListener('assemblerEvent', statusEventHandler); 216 | const mc6809 = new bundle.CPU(); 217 | mc6809.ready(); 218 | const speed = new SlideControl(mc6809, 5); 219 | speed.bindId('speed', 'speedVal'); 220 | document.getElementById('assembly-code').value = 221 | document.getElementById('demo-helloworld').value; 222 | machineInterrupt('reset'); 223 | mc6809.refresh(1); 224 | mc6809.execute(); 225 | -------------------------------------------------------------------------------- /src/interface.js: -------------------------------------------------------------------------------- 1 | import {blockChars, blockClasses, Defaults} from './constants'; 2 | import {inHex, trc} from './helper'; 3 | 4 | /** 5 | * Generate label list element for ui. 6 | * 7 | * @param {string} id target html element id 8 | * @param {Object} owner owner reference 9 | * @constructor 10 | */ 11 | function LabelList(id, owner) { 12 | this.cpu = owner; 13 | this.list = null; 14 | this.createList = function(listId) { 15 | const container = document.getElementById(listId + '-container'); 16 | trc('labelList id', listId); 17 | if (container !== null) { 18 | const labels = container.childNodes; 19 | if (labels.length === 0) { 20 | trc('LabelList container', ''); 21 | this.list = document.createElement('select'); 22 | this.list.setAttribute('size', '30'); 23 | this.list.className = 'labelsContainer'; 24 | container.appendChild(this.list); 25 | } else { 26 | this.list = labels[0]; 27 | } 28 | } 29 | }; 30 | this.fill = function(labels) { 31 | let label; 32 | let option; 33 | trc('Labels fill', 0); 34 | for (label in labels) { 35 | if (Object.prototype.hasOwnProperty.call(labels, label)) { 36 | option = document.createElement('option'); 37 | option.text = label; 38 | option.value = 1; 39 | trc('Label: ', label); 40 | option.className = 'labelList'; 41 | (function(cpuOwner, optLabel) { 42 | option.onclick = function(event) { 43 | trc('reloadtable call label \'' + optLabel + '\' value', 44 | labels[optLabel]); 45 | cpuOwner.dsmTable.reloadTable(labels[optLabel]); 46 | cpuOwner.dsmTable.lineOn(cpuOwner.registers['regPC'].regValue, true, 47 | true); 48 | }; 49 | }(this.cpu, label)); 50 | this.list.add(option); 51 | } 52 | } 53 | }; 54 | this.empty = function() { 55 | while (this.list.length > 0) { 56 | this.list.remove(this.list.length - 1); 57 | } 58 | }; 59 | this.createList(id); 60 | } 61 | 62 | /** 63 | * Generate DSM window element for UI. 64 | * 65 | * @param {string} id target html element id 66 | * @param {CPU} cpu cpu reference 67 | * @param {number} rows number of rows to create 68 | * @constructor 69 | */ 70 | function DSMWindow(id, cpu, rows) { 71 | this.lineMap = []; 72 | this.lineHi = null; 73 | this.table = null; 74 | this.cpuOwner = cpu; 75 | this.rowCount = rows; 76 | this.editContents = null; 77 | this.baseAddress = 0; 78 | this.codeLength = 0; 79 | this.watch = null; 80 | 81 | this.createTable = function(tableId) { 82 | let newRow; 83 | let rowNo; 84 | 85 | /** 86 | * Extend current watch with new cell. 87 | * 88 | * @param {HTMLTableRowElement} thisRow 89 | * @param {string} cellClass 90 | * @param {string} content 91 | */ 92 | function newCell(thisRow, cellClass, content) { 93 | const cell = thisRow.insertCell(); 94 | cell.className = cellClass; 95 | cell.innerHTML = content; 96 | } 97 | 98 | trc('createTable tableId', tableId); 99 | const container = document.getElementById(tableId + '-container'); 100 | if (container !== null) { 101 | trc('Found container, rows', this.rowCount); 102 | this.table = document.createElement('table'); 103 | this.table.setAttribute('id', 'tableId'); 104 | this.table.style.backgroundColor = 'black'; 105 | this.table.className = 'DSM'; 106 | for (rowNo = 1; rowNo <= this.rowCount; rowNo++) { 107 | trc('newRow', rowNo); 108 | newRow = this.table.insertRow(); 109 | newCell(newRow, 'DSM ADDR', 'addr  '); 110 | newCell(newRow, 'DSM BYTES', 'bytes  '); 111 | newCell(newRow, 'DSM MNEM', 'mnem  '); 112 | } 113 | container.appendChild(this.table); 114 | } 115 | }; 116 | this.setRow = function(rowNo, code, cpu) { 117 | let row; 118 | let address; 119 | let bytes; 120 | let mnemonic; 121 | 122 | /** 123 | * Safe jump CPU to current address in code. 124 | * 125 | * @param {Event} event 126 | * @return {boolean} 127 | */ 128 | function jump(event) { 129 | event.preventDefault(); 130 | if (!cpu.cellEditing) { 131 | cpu.closeEdit(false); 132 | cpu.jumpTo(cpu, code.address); 133 | } 134 | return false; 135 | } 136 | 137 | if (this.table && (rowNo < this.table.rows.length)) { 138 | row = this.table.rows[rowNo]; 139 | bytes = ''; 140 | if (code) { 141 | this.lineMap[code.address] = row; 142 | address = inHex(code.address, 4) + ':'; 143 | for (let i = 0; i < code.maxInstructionLength; i++) { 144 | if (i < code.bytes.length) { 145 | bytes += inHex(code.bytes[i], 2) + ' '; 146 | this.codeLength++; 147 | } else { 148 | bytes += '   '; 149 | } 150 | } 151 | mnemonic = code.operation + ' ' + code.operand; 152 | } else { 153 | address = ''; 154 | mnemonic = ' '; 155 | } 156 | row.cells[0].innerHTML = address; 157 | row.cells[0].oncontextmenu = function(event) { 158 | cpu.setBreakpoint(cpu, event, code.address); 159 | return false; 160 | }; 161 | row.cells[0].onclick = jump; 162 | row.cells[0].style.backgroundColor = (code.address in cpu.breakpoints) ? 163 | 'red' : 164 | ''; 165 | row.cells[1].innerHTML = bytes; 166 | row.cells[1].onclick = jump; 167 | row.cells[2].innerHTML = mnemonic; 168 | row.cells[2].onclick = jump; 169 | row.cells[2].oncontextmenu = function(event) { 170 | if (cpu.cellEditing) { 171 | cpu.cellEditing.input.focus(); 172 | return false; 173 | } 174 | cpu.editCode(cpu, event, code.address); 175 | event.preventDefault(); 176 | return false; 177 | }; 178 | } 179 | }; 180 | this.reloadTable = function(address) { 181 | if (this.watch != null) { 182 | this.cpuOwner.ram.removeWindow(0, 0, this.watch); 183 | this.watch = null; 184 | } 185 | this.setTable(this.cpuOwner.disassemble(address, 0x10000, 186 | this.cpuOwner.dsmTableSize)); 187 | }; 188 | this.lineOff = function() { 189 | if (this.lineHi) { 190 | this.lineHi.className = 'DSMlo'; 191 | this.lineHi = null; 192 | } 193 | }; 194 | this.lineOn = function(address, force, notRequired) { 195 | if (!(this.cpuOwner.refreshOn || force)) { 196 | return; 197 | } 198 | trc('lineOn address', inHex(address, 4)); 199 | this.lineOff(); 200 | if (!(address in this.lineMap)) { 201 | if (notRequired) { 202 | return; 203 | } else { 204 | this.reloadTable(address); 205 | } 206 | } 207 | this.lineHi = this.lineMap[address]; 208 | this.lineHi.className = 'DSMhi'; 209 | }; 210 | this.setTable = function(lines) { 211 | let i; 212 | trc('setTable for code lines count', lines.length); 213 | this.lineMap = []; 214 | this.baseAddress = lines[0].address; 215 | this.codeLength = 0; 216 | if (this.table) { 217 | trc('this.table rows length', this.table.rows.length); 218 | for (i = 0; i < this.table.rows.length; i++) { 219 | // trc ("this.table row", i); 220 | this.setRow(i, (i < lines.length) ? lines[i] : null, this.cpuOwner); 221 | } 222 | this.watch = this.cpuOwner.ram.addWindow(this, this.baseAddress, 223 | this.codeLength); 224 | trc('Add DASM watch length', this.codeLength); 225 | } 226 | }; 227 | this.doTrace = function() { 228 | trc('DSMWindow doTrace', 0); 229 | }; 230 | this.update = function(holder, address, value) { 231 | trc('DASM window update address', inHex(address, 4)); 232 | holder.doTrace(); 233 | trc('Assembling', holder.cpuOwner.assembling); 234 | if ((holder.cpuOwner.cellEditing == null) && 235 | (holder.cpuOwner.assembling == false)) { 236 | holder.reloadTable(holder.baseAddress); 237 | } 238 | }; 239 | this.createTable(id); 240 | } 241 | 242 | /** 243 | * Define graphics screen element for UI. 244 | * 245 | * @param {Memory8} videoRAM ram reference 246 | * @param {number} videoBase base address 247 | * @param {number} width pixel width 248 | * @param {number} height pixel height 249 | * @param {number} colours palette size 250 | * @param {number} zoom scale 251 | * @constructor 252 | */ 253 | function GraphicsScreen(videoRAM, videoBase, width, height, colours, zoom) { 254 | this.ram = videoRAM; 255 | this.base = videoBase; 256 | this.wide = width; 257 | this.high = height; 258 | this.scale = zoom; 259 | this.bitsPerPixel = 1; 260 | this.sourceBitmap = null; 261 | this.canvas = null; 262 | this.colourMap = [ 263 | '#000000', 264 | '#a00000', 265 | '#00a000', 266 | '#a0a000', 267 | '#0000a0', 268 | '#a000a0', 269 | '#00a0a0', 270 | '#808080', 271 | '#404040', 272 | '#ff0000', 273 | '#00ff00', 274 | '#ffff00', 275 | '#0000ff', 276 | '#ff00ff', 277 | '#00ffff', 278 | '#ffffff']; 279 | this.palettes = [ 280 | [], 281 | [0, 2], 282 | [0, 9, 2, 12], 283 | [], 284 | [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15], 285 | ]; 286 | this.setMode = function(colours) { 287 | switch (colours) { 288 | case 2: 289 | this.bitsPerPixel = 1; 290 | break; 291 | case 4: 292 | this.bitsPerPixel = 2; 293 | break; 294 | case 16: 295 | this.bitsPerPixel = 4; 296 | break; 297 | default: 298 | this.bitsPerPixel = 1; 299 | break; 300 | } 301 | }; 302 | this.clearScreen = function() { 303 | const ctx = this.canvas.getContext('2d'); 304 | ctx.fillStyle = this.colourMap[0]; 305 | ctx.fillRect(0, 0, this.wide * this.scale, this.high * this.scale); 306 | }; 307 | this.clearVideoRAM = function(colourByte) { 308 | let x; 309 | for (x = this.base; x < this.base + this.high * Defaults.lineBytes; x++) { 310 | this.ram.poke(x, colourByte); 311 | } 312 | }; 313 | this.update = function(holder, address, value) { 314 | let pixel; 315 | let dx; 316 | let dy; 317 | let byte = value; 318 | switch (this.bitsPerPixel) { 319 | case 1: 320 | dx = 1; 321 | dy = 1; 322 | break; 323 | case 2: 324 | dx = 2; 325 | dy = 1; 326 | break; 327 | case 4: 328 | dx = 2; 329 | dy = 2; 330 | break; 331 | } 332 | let xPos = ((address - this.base) & ((Defaults.lineBytes * dy) - 1)) * 333 | (8 / dy); 334 | const yPos = Math.trunc((address - this.base) / 335 | (Defaults.lineBytes * dy)) * dy; 336 | const ctx = this.canvas.getContext('2d'); 337 | for (let i = 0; i < 8; i += this.bitsPerPixel) { 338 | byte <<= this.bitsPerPixel; 339 | pixel = byte >>> 8; 340 | byte &= 0xff; 341 | ctx.fillStyle = this.colourMap[this.palettes[this.bitsPerPixel][pixel]]; 342 | ctx.fillRect( 343 | xPos * this.scale, 344 | yPos * this.scale, 345 | this.scale * dx, 346 | this.scale * dy, 347 | ); 348 | xPos += dx; 349 | } 350 | }; 351 | this.canvas = document.getElementById('graphicsScreen'); 352 | if (this.canvas !== null) { 353 | this.setMode(colours); 354 | this.clearScreen(); 355 | this.ram.addWindow(this, this.base, (this.wide * this.high) / 8); 356 | } 357 | } 358 | 359 | /** 360 | * Define text screen element for UI. 361 | * 362 | * @param {Memory8} videoRAM memory reference 363 | * @param {number} videoBase base address in memory 364 | * @param {number} width character width 365 | * @param {number} height character height 366 | * @constructor 367 | */ 368 | function TextScreen(videoRAM, videoBase, width, height) { 369 | this.ram = videoRAM; 370 | this.base = videoBase; 371 | this.wide = width; 372 | this.high = height; 373 | this.charSet = '@ABCDEFGHIJKLMNO' + 374 | 'PQRSTUVWXYZ[\\]\u2191\u2190' + 375 | ' !"#$%&\'()*+,-./' + 376 | '0123456789:;<=>?'; 377 | this.update = function(holder, address, value) { 378 | let cell; 379 | const element = document.getElementById('txtScreenTable'); 380 | if (element) { 381 | trc('Update element found', ''); 382 | // console.dir (holder); 383 | cell = element.rows[Math.floor((address - holder.base) / width)].cells[ 384 | (address - holder.base) % width]; 385 | if (cell) { 386 | if (value >= 0x80) { 387 | cell.innerHTML = blockChars[value & 0x0f]; 388 | cell.className = blockClasses[(value & 0x70) >> 4]; 389 | } else { 390 | if ((value & 0x3f) === 0x20) { 391 | cell.innerHTML = ' '; 392 | } else { 393 | cell.innerHTML = holder.charSet[value & 0x3f]; 394 | } 395 | switch (value & 0x40) { 396 | case 0: 397 | cell.className = 'txtBG'; 398 | break; 399 | case 0x40: 400 | cell.className = 'txtFG'; 401 | break; 402 | } 403 | } 404 | } 405 | } 406 | }; 407 | this.createScreenTable = function(tableId, width, height) { 408 | let rows; 409 | let cells; 410 | let newRow; 411 | let newCell; 412 | let container; 413 | let table; 414 | table = null; 415 | if ( 416 | (container = document.getElementById(tableId + '-container')) !== null 417 | ) { 418 | table = document.createElement('table'); 419 | table.setAttribute('id', tableId); 420 | table.setAttribute('tabindex', 0); 421 | table.className = 'txtScreen'; 422 | for (rows = 0; rows < height; rows++) { 423 | newRow = document.createElement('tr'); 424 | for (cells = 0; cells < width; cells++) { 425 | newCell = document.createElement('td'); 426 | newCell.className = 'txtBG'; 427 | newCell.innerText = '@'; 428 | newRow.appendChild(newCell); 429 | } 430 | table.appendChild(newRow); 431 | table.addEventListener('keypress', keyPressHandler); 432 | } 433 | container.appendChild(table); 434 | } 435 | return table; 436 | }; 437 | this.ram.addWindow(this, this.base, this.wide * this.high); 438 | this.table = this.createScreenTable('txtScreenTable', 32, 16); 439 | } 440 | 441 | /** 442 | * Capture keypress events and push to key buffer. 443 | * 444 | * @param {KeyboardEvent} event 445 | */ 446 | function keyPressHandler(event) { 447 | mc6809.keyBuffer.push(event.key); 448 | event.preventDefault(); 449 | } 450 | 451 | export {LabelList, DSMWindow, GraphicsScreen, TextScreen, keyPressHandler}; 452 | -------------------------------------------------------------------------------- /test/cputest.asm: -------------------------------------------------------------------------------- 1 | WARMS EQU $CD03 2 | PCRLF EQU $CD24 3 | PUTCHR EQU $CD18 4 | PSTRNG EQU $CD1E 5 | OUTDEC EQU $CD39 6 | EXTREG EQU $8000 7 | DIRPAG EQU $80 8 | DPREG EQU $00 9 | EOT EQU $4 10 | 11 | ORG $8100 12 | 13 | BEGIN BRA START 14 | VERSIO FCB 1 15 | REG161 FDB 0 16 | 17 | START CLR ERRFLG ; Clear Error flag 18 | JSR TDAA 19 | * 20 | * Test Addressing modes 21 | JSR TAD1 22 | JSR TAD2 23 | JSR TAD3 24 | JSR TAD4 25 | JSR TAD5 26 | JSR TAD6 27 | JSR TAD7 28 | JSR TAD8 29 | JSR TAD9 30 | JSR TADA 31 | JSR TADB 32 | JSR TADI1 33 | JSR TADI3 34 | JSR TADI5 35 | JSR TADI6 36 | JSR TADI7 37 | JSR TADI8 38 | JSR TADI9 39 | JSR TADIA 40 | JSR TADIB 41 | JSR TADIC 42 | * Test Instructions 43 | JSR TNEG 44 | JSR TCOM 45 | JSR TDEC 46 | JSR TINC 47 | JSR TCLR 48 | JSR TADD 49 | JSR TADDD 50 | JSR TADC 51 | JSR TMUL 52 | JSR TSEX 53 | JSR TSUB 54 | JSR TSUBD 55 | JSR TSBC 56 | JSR TDAA 57 | JSR TCMP 58 | JSR TCMPD 59 | JSR TTST 60 | JSR TBIT 61 | JSR TLSR 62 | JSR TLSL 63 | JSR TASR 64 | JSR TROL 65 | JSR TROR 66 | JSR TLD 67 | JSR TST 68 | JSR TLDD 69 | JSR TSTD 70 | JSR TLEA 71 | JSR TTFR 72 | JSR TEXG 73 | * 74 | JSR OUTSUC 75 | JMP WARMS 76 | 77 | ************************************************** 78 | * Test MUL 79 | ************************************************** 80 | TMUL LDU #LMUL 81 | LDX #TBMUL 82 | TMUL1 LDD ,X++ 83 | MUL 84 | TFR CC,DP 85 | CMPD ,X++ 86 | LBNE OUTERR 87 | TFR DP,B 88 | ANDB #$05 ; Only check Bits ZC 89 | CMPB ,X+ 90 | LBNE OUTERR 91 | CMPX #LMUL 92 | LBNE TMUL1 93 | RTS 94 | 95 | TBMUL FDB $0000,$0000 96 | FCB $04 97 | FDB $8080,$4000 98 | FCB $00 99 | FDB $01FF,$00FF 100 | FCB $01 101 | FDB $FF01,$00FF 102 | FCB $01 103 | FDB $7F81,$3FFF 104 | FCB $01 105 | FDB $817F,$3FFF 106 | FCB $01 107 | FDB $C040,$3000 108 | FCB $00 109 | FDB $40C0,$3000 110 | FCB $00 111 | FDB $FFFF,$FE01 112 | FCB $00 113 | FDB $7F7F,$3F01 114 | FCB $00 115 | FDB $0101,$0001 116 | FCB $00 117 | LMUL FCC 'MUL',EOT 118 | 119 | ************************************************** 120 | * Test SEX 121 | ************************************************** 122 | TSEX LDU #LSEX 123 | LDX #TBSEX 124 | TSEX1 LDB ,X+ 125 | SEX 126 | TFR CC,DP 127 | CMPD ,X++ 128 | LBNE OUTERR 129 | TFR DP,B 130 | ANDB #$0C ; Only check Bits NZ 131 | CMPB ,X+ 132 | LBNE OUTERR 133 | CMPX #LSEX 134 | LBNE TSEX1 135 | RTS 136 | 137 | 138 | TBSEX FCB $00 139 | FDB $0000 140 | FCB $04 141 | FCB $01 142 | FDB $0001 143 | FCB $00 144 | FCB $7F 145 | FDB $007F 146 | FCB $00 147 | FCB $80 148 | FDB $FF80 149 | FCB $08 150 | FCB $FF 151 | FDB $FFFF 152 | FCB $08 153 | LSEX FCC 'SEX',EOT 154 | 155 | ************************************************** 156 | * Test TST 157 | ************************************************** 158 | TTST LDU #LTST 159 | LDX #TBTST 160 | TTST1 LDA ,X+ 161 | TSTA 162 | TFR CC,B 163 | ANDB #$0E ; Only check Bits NZV 164 | CMPB ,X+ 165 | LBNE OUTERR 166 | CMPX #LTST 167 | LBNE TTST1 168 | RTS 169 | 170 | TBTST FCB $00,$04 171 | FCB $80,$08 172 | FCB $01,$00 173 | FCB $FF,$08 174 | FCB $7F,$00 175 | FCB $81,$08 176 | FCB $C0,$08 177 | FCB $40,$00 178 | LTST FCC 'TST',EOT 179 | 180 | ************************************************** 181 | * Test LD 182 | ************************************************** 183 | TLD LDU #LLD 184 | LDX #TBTST 185 | TLD1 LDA ,X+ 186 | TFR CC,B 187 | ANDB #$0E ; Only check Bits NZV 188 | CMPB ,X+ 189 | LBNE OUTERR 190 | CMPX #LTST 191 | LBNE TLD1 192 | RTS 193 | LLD FCC 'LD',EOT 194 | 195 | ************************************************** 196 | * Test ST 197 | ************************************************** 198 | TST: LDU #LST 199 | LDX #TBTST 200 | TST1 LDA ,X+ 201 | STA EXTREG 202 | TFR CC,B 203 | ANDB #$0E ; Only check Bits NZV 204 | CMPB ,X+ 205 | LBNE OUTERR 206 | CMPX #LTST 207 | LBNE TST1 208 | RTS 209 | LST FCC 'ST',EOT 210 | 211 | ************************************************** 212 | * Test LDD 213 | ************************************************** 214 | TLDD LDU #LLDD 215 | LDX #TBLDD 216 | TLDD1 LDD ,X++ 217 | TFR CC,B 218 | ANDB #$0E ; Only check Bits NZV 219 | CMPB ,X+ 220 | LBNE OUTERR 221 | CMPX #LLDD 222 | LBNE TLDD1 223 | RTS 224 | TBLDD FDB $0000 225 | FCB $04 226 | FDB $8000 227 | FCB $08 228 | FDB $0001 229 | FCB $00 230 | FDB $FFFF 231 | FCB $08 232 | FDB $7FFF 233 | FCB $00 234 | FDB $8001 235 | FCB $08 236 | FDB $C000 237 | FCB $08 238 | FDB $4000 239 | FCB $00 240 | LLDD FCC 'LDD',EOT 241 | 242 | ************************************************** 243 | * Test STD 244 | ************************************************** 245 | TSTD LDU #LSTD 246 | LDX #TBLDD 247 | TSTD1 LDD ,X++ 248 | STD EXTREG 249 | TFR CC,B 250 | ANDB #$0E ; Only check Bits NZV 251 | CMPB ,X+ 252 | LBNE OUTERR 253 | CMPX #LLDD 254 | LBNE TSTD1 255 | RTS 256 | LSTD FCC 'STD',EOT 257 | 258 | ************************************************** 259 | * Test LEA 260 | ************************************************** 261 | TLEA LDU #LLEA 262 | LDX #TBLEA 263 | TLEA1 LDY ,X++ 264 | LEAY ,Y 265 | TFR CC,B 266 | ANDB #$04 ; Only check Bit Z 267 | CMPB ,X+ 268 | LBNE OUTERR 269 | CMPX #LLEA 270 | LBNE TLEA1 271 | RTS 272 | 273 | TBLEA FDB $0000 274 | FCB $04 275 | FDB $0001 276 | FCB $00 277 | FDB $FFFF 278 | FCB $00 279 | FDB $7FFF 280 | FCB $00 281 | FDB $8000 282 | FCB $00 283 | FDB $8001 284 | FCB $00 285 | LLEA FCC 'LEA',EOT 286 | 287 | ************************************************** 288 | * Test BIT 289 | ************************************************** 290 | TBIT LDU #LBIT 291 | LDX #TBBIT 292 | TBIT1 LDA ,X+ 293 | BITA ,X+ 294 | TFR CC,B 295 | ANDB #$0E ; Only check Bits NZV 296 | CMPB ,X+ 297 | LBNE OUTERR 298 | CMPX #LBIT 299 | LBNE TBIT1 300 | RTS 301 | 302 | TBBIT FCB $00,$00,$04 303 | FCB $AA,$55,$04 304 | FCB $AA,$AA,$08 305 | FCB $55,$55,$00 306 | FCB $FF,$FF,$08 307 | FCB $FF,$80,$08 308 | FCB $81,$80,$08 309 | FCB $FF,$7F,$00 310 | FCB $FF,$01,$00 311 | FCB $F0,$0F,$04 312 | LBIT FCC 'BIT',EOT 313 | 314 | ************************************************** 315 | * Test DAA 316 | ************************************************** 317 | TDAA LDU #LDAA 318 | LDX #TBDAA 319 | TDAA1 LDA ,X+ 320 | TFR CC,B 321 | ANDB ,X+ 322 | ORB ,X+ 323 | TFR B,CC 324 | DAA 325 | TFR CC,B 326 | CMPA ,X+ 327 | LBNE OUTERR 328 | ANDB #$0D ; Only check Bits NZC 329 | CMPB ,X+ 330 | LBNE OUTERR 331 | CMPX #LDAA 332 | LBNE TDAA1 333 | RTS 334 | 335 | TBDAA 336 | * Carry: 0, Halfcarry: 0 337 | FCB $00,$DE,$00,$00,$04 338 | FCB $01,$DE,$00,$01,$00 339 | FCB $09,$DE,$00,$09,$00 340 | FCB $0A,$DE,$00,$10,$00 341 | FCB $0F,$DE,$00,$15,$00 342 | FCB $10,$DE,$00,$10,$00 343 | FCB $4A,$DE,$00,$50,$00 344 | FCB $79,$DE,$00,$79,$00 345 | FCB $7A,$DE,$00,$80,$08 346 | FCB $7F,$DE,$00,$85,$08 347 | FCB $81,$DE,$00,$81,$08 348 | FCB $99,$DE,$00,$99,$08 349 | FCB $A0,$DE,$00,$00,$05 350 | FCB $BF,$DE,$00,$25,$01 351 | FCB $F0,$DE,$00,$50,$01 352 | FCB $FF,$DE,$00,$65,$01 353 | * Carry: 1, Halfcarry: 0 354 | FCB $00,$DF,$01,$60,$01 355 | FCB $01,$DF,$01,$61,$01 356 | FCB $09,$DF,$01,$69,$01 357 | FCB $0A,$DF,$01,$70,$01 358 | FCB $0F,$DF,$01,$75,$01 359 | FCB $10,$DF,$01,$70,$01 360 | FCB $4A,$DF,$01,$B0,$09 361 | FCB $79,$DF,$01,$D9,$09 362 | FCB $7A,$DF,$01,$E0,$09 363 | FCB $7F,$DF,$01,$e5,$09 364 | FCB $81,$DF,$01,$E1,$09 365 | FCB $99,$DF,$01,$F9,$09 366 | FCB $A0,$DF,$01,$00,$05 367 | FCB $BF,$DF,$01,$25,$01 368 | FCB $F0,$DF,$01,$50,$01 369 | FCB $FF,$DF,$01,$65,$01 370 | * Carry: 0, Halfcarry: 1 371 | FCB $00,$FE,$20,$06,$00 372 | FCB $01,$FE,$20,$07,$00 373 | FCB $09,$FE,$20,$0F,$00 374 | FCB $0A,$FE,$20,$10,$00 375 | FCB $0F,$FE,$20,$15,$00 376 | FCB $10,$FE,$20,$16,$00 377 | FCB $4A,$FE,$20,$50,$00 378 | FCB $79,$FE,$20,$7F,$00 379 | FCB $7A,$FE,$20,$80,$08 380 | FCB $7F,$FE,$20,$85,$08 381 | FCB $81,$FE,$20,$87,$08 382 | FCB $99,$FE,$20,$9F,$08 383 | FCB $A0,$FE,$20,$06,$01 384 | FCB $BF,$FE,$20,$25,$01 385 | FCB $F0,$FE,$20,$56,$01 386 | FCB $FF,$FE,$20,$65,$01 387 | * Carry: 1, Halfcarry: 1 388 | FCB $00,$FF,$21,$66,$01 389 | FCB $01,$FF,$21,$67,$01 390 | FCB $09,$FF,$21,$6F,$01 391 | FCB $0A,$FF,$21,$70,$01 392 | FCB $0F,$FF,$21,$75,$01 393 | FCB $10,$FF,$21,$76,$01 394 | FCB $4A,$FF,$21,$B0,$09 395 | FCB $79,$FF,$21,$DF,$09 396 | FCB $7A,$FF,$21,$E0,$09 397 | FCB $7F,$FF,$21,$E5,$09 398 | FCB $81,$FF,$21,$E7,$09 399 | FCB $99,$FF,$21,$FF,$09 400 | FCB $A0,$FF,$21,$06,$01 401 | FCB $BF,$FF,$21,$25,$01 402 | FCB $F0,$FF,$21,$56,$01 403 | FCB $FF,$FF,$21,$65,$01 404 | LDAA FCC 'DAA',EOT 405 | 406 | ************************************************** 407 | * Test NEG 408 | ************************************************** 409 | TNEG LDU #LNEG 410 | LDX #TBNEG 411 | TNEG1 LDA ,X+ 412 | NEGA 413 | TFR CC,B 414 | CMPA ,X+ 415 | LBNE OUTERR 416 | ANDB #$0F ; Only check Bits NZVC 417 | CMPB ,X+ 418 | LBNE OUTERR 419 | CMPX #LNEG 420 | LBNE TNEG1 421 | RTS 422 | 423 | TBNEG FCB $00,$00,$04 424 | FCB $80,$80,$0B 425 | FCB $01,$FF,$09 426 | FCB $FF,$01,$01 427 | FCB $7F,$81,$09 428 | FCB $81,$7F,$01 429 | FCB $C0,$40,$01 430 | FCB $40,$C0,$09 431 | LNEG FCC 'NEG',EOT 432 | 433 | ************************************************** 434 | * Test COM 435 | ************************************************** 436 | TCOM LDU #LCOM 437 | LDX #TBCOM 438 | TCOM1 LDA ,X+ 439 | COMA 440 | TFR CC,B 441 | CMPA ,X+ 442 | LBNE OUTERR 443 | ANDB #$0F ; Only check Bits NZVC 444 | CMPB ,X+ 445 | LBNE OUTERR 446 | CMPX #LCOM 447 | BNE TCOM1 448 | RTS 449 | 450 | 451 | TBCOM FCB $00,$FF,$09 452 | FCB $FF,$00,$05 453 | FCB $F0,$0F,$01 454 | FCB $0F,$F0,$09 455 | FCB $55,$AA,$09 456 | FCB $AA,$55,$01 457 | FCB $01,$FE,$09 458 | FCB $FE,$01,$01 459 | FCB $80,$7F,$01 460 | FCB $7F,$80,$09 461 | LCOM FCC 'COM',EOT 462 | 463 | ************************************************** 464 | * Test LSR 465 | ************************************************** 466 | TLSR LDU #LLSR 467 | LDX #TBLSR 468 | TLSR1 LDA ,X+ 469 | LSRA 470 | TFR CC,B 471 | CMPA ,X+ 472 | LBNE OUTERR 473 | ANDB #$0F ; Only check Bits NZVC 474 | CMPB ,X+ 475 | LBNE OUTERR 476 | CMPX #LLSR 477 | BNE TLSR1 478 | RTS 479 | 480 | 481 | TBLSR FCB $00,$00,$04 482 | FCB $FF,$7F,$01 483 | FCB $7F,$3F,$01 484 | FCB $3F,$1F,$01 485 | FCB $1F,$0F,$01 486 | FCB $0F,$07,$01 487 | FCB $07,$03,$01 488 | FCB $03,$01,$01 489 | FCB $01,$00,$05 490 | FCB $55,$2A,$01 491 | FCB $AA,$55,$00 492 | FCB $80,$40,$00 493 | FCB $10,$08,$00 494 | FCB $C0,$60,$00 495 | FCB $E0,$70,$00 496 | FCB $F0,$78,$00 497 | FCB $F8,$7C,$00 498 | FCB $FC,$7E,$00 499 | FCB $FE,$7F,$00 500 | LLSR FCC 'LSR',EOT 501 | 502 | ************************************************** 503 | * Test LSL 504 | ************************************************** 505 | TLSL LDU #LLSL 506 | LDX #TBLSL 507 | TLSL1 LDA ,X+ 508 | LSLA 509 | TFR CC,B 510 | CMPA ,X+ 511 | LBNE OUTERR 512 | ANDB #$0F ; Only check Bits NZVC 513 | CMPB ,X+ 514 | * LBNE OUTERR 515 | CMPX #LLSL 516 | BNE TLSL1 517 | RTS 518 | 519 | 520 | TBLSL FCB $00,$00,$04 521 | FCB $FF,$FE,$01 522 | FCB $7F,$FE,$01 523 | FCB $3F,$7E,$01 524 | FCB $1F,$3E,$00 525 | FCB $0F,$1E,$00 526 | FCB $07,$0E,$00 527 | FCB $03,$06,$00 528 | FCB $01,$02,$00 529 | FCB $55,$AA,$00 530 | FCB $AA,$54,$00 531 | FCB $80,$00,$01 532 | FCB $10,$20,$01 533 | FCB $C0,$80,$01 534 | FCB $E0,$C0,$01 535 | FCB $F0,$E0,$01 536 | FCB $F8,$F0,$01 537 | FCB $FC,$F8,$01 538 | FCB $FE,$FC,$01 539 | LLSL FCC 'LSL',EOT 540 | 541 | ************************************************** 542 | * Test ASR 543 | ************************************************** 544 | TASR LDU #LASR 545 | LDX #TBASR 546 | TASR1 LDA ,X+ 547 | ASRA 548 | TFR CC,B 549 | CMPA ,X+ 550 | LBNE OUTERR 551 | ANDB #$0D ; Only check Bits NZC 552 | CMPB ,X+ 553 | LBNE OUTERR 554 | CMPX #LASR 555 | BNE TASR1 556 | RTS 557 | 558 | 559 | TBASR FCB $00,$00,$04 560 | FCB $FF,$FF,$09 561 | FCB $7F,$3F,$01 562 | FCB $3F,$1F,$01 563 | FCB $1F,$0F,$01 564 | FCB $0F,$07,$01 565 | FCB $07,$03,$01 566 | FCB $03,$01,$01 567 | FCB $01,$00,$05 568 | FCB $55,$2A,$01 569 | FCB $AA,$D5,$08 570 | FCB $80,$C0,$08 571 | FCB $10,$08,$00 572 | FCB $C0,$E0,$08 573 | FCB $E0,$F0,$08 574 | FCB $F0,$F8,$08 575 | FCB $F8,$FC,$08 576 | FCB $FC,$FE,$08 577 | FCB $FE,$FF,$08 578 | LASR FCC 'ASR',EOT 579 | 580 | ************************************************** 581 | * Test ROR 582 | ************************************************** 583 | TROR LDU #LROR 584 | LDX #TBROR 585 | TROR1 LDA ,X+ 586 | TFR CC,B 587 | ANDB ,X+ 588 | ORB ,X+ 589 | TFR B,CC 590 | RORA 591 | TFR CC,B 592 | CMPA ,X+ 593 | LBNE OUTERR 594 | ANDB #$0D ; Only check Bits NZC 595 | CMPB ,X+ 596 | LBNE OUTERR 597 | CMPX #LROR 598 | BNE TROR1 599 | RTS 600 | 601 | TBROR FCB $00,$FE,$00,$00,$04 602 | FCB $01,$FE,$00,$00,$05 603 | FCB $0F,$FE,$00,$07,$01 604 | FCB $10,$FE,$00,$08,$00 605 | FCB $7F,$FE,$00,$3F,$01 606 | FCB $80,$FE,$00,$40,$00 607 | FCB $FE,$FE,$00,$7F,$00 608 | FCB $FF,$FE,$00,$7F,$01 609 | FCB $00,$FF,$01,$80,$08 610 | FCB $01,$FF,$01,$80,$09 611 | FCB $0F,$FF,$01,$87,$09 612 | FCB $10,$FF,$01,$88,$08 613 | FCB $7F,$FF,$01,$BF,$09 614 | FCB $80,$FF,$01,$C0,$08 615 | FCB $FE,$FF,$01,$FF,$08 616 | FCB $FF,$FF,$01,$FF,$09 617 | LROR FCC 'ROR',EOT 618 | 619 | ************************************************** 620 | * Test ROL 621 | ************************************************** 622 | TROL LDU #LROL 623 | LDX #TBROL 624 | TROL1 LDA ,X+ 625 | TFR CC,B 626 | ANDB ,X+ 627 | ORB ,X+ 628 | TFR B,CC 629 | ROLA 630 | TFR CC,B 631 | CMPA ,X+ 632 | LBNE OUTERR 633 | ANDB #$0D ; Only check Bits NZC 634 | CMPB ,X+ 635 | * LBNE OUTERR 636 | CMPX #LROL 637 | BNE TROL1 638 | RTS 639 | 640 | TBROL FCB $00,$FE,$00,$00,$04 641 | FCB $01,$FE,$00,$02,$00 642 | FCB $0F,$FE,$00,$1E,$00 643 | FCB $08,$FE,$00,$10,$00 644 | FCB $7F,$FE,$00,$FE,$08 645 | FCB $80,$FE,$00,$00,$05 646 | FCB $FE,$FE,$00,$FC,$09 647 | FCB $FF,$FE,$00,$FE,$09 648 | FCB $00,$FF,$01,$01,$00 649 | FCB $01,$FF,$01,$03,$00 650 | FCB $0F,$FF,$01,$1F,$00 651 | FCB $08,$FF,$01,$11,$00 652 | FCB $7F,$FF,$01,$FF,$08 653 | FCB $80,$FF,$01,$01,$01 654 | FCB $FE,$FF,$01,$FD,$09 655 | FCB $FF,$FF,$01,$FF,$09 656 | LROL FCC 'ROL',EOT 657 | 658 | ************************************************** 659 | * Test DEC 660 | ************************************************** 661 | TDEC LDU #LDEC 662 | LDX #TBDEC 663 | TDEC1 LDA ,X+ 664 | DECA 665 | TFR CC,B 666 | CMPA ,X+ 667 | LBNE OUTERR 668 | ANDB #$0E ; Only check Bits NZV 669 | CMPB ,X+ 670 | LBNE OUTERR 671 | CMPX #LDEC 672 | BNE TDEC1 673 | RTS 674 | 675 | TBDEC FCB $01,$00,$04 676 | FCB $00,$FF,$08 677 | FCB $FF,$FE,$08 678 | FCB $80,$7F,$02 679 | FCB $7F,$7E,$00 680 | FCB $10,$0F,$00 681 | FCB $0F,$0E,$00 682 | LDEC FCC 'DEC',EOT 683 | 684 | ************************************************** 685 | * Test INC 686 | ************************************************** 687 | TINC LDU #LINC 688 | LDX #TBINC 689 | TINC1 LDA ,X+ 690 | INCA 691 | TFR CC,B 692 | CMPA ,X+ 693 | LBNE OUTERR 694 | ANDB #$0E ; Only check Bits NZV 695 | CMPB ,X+ 696 | LBNE OUTERR 697 | CMPX #LINC 698 | BNE TINC1 699 | RTS 700 | 701 | TBINC FCB $00,$01,$00 702 | FCB $FE,$FF,$08 703 | FCB $FF,$00,$04 704 | FCB $7F,$80,$0A 705 | FCB $80,$81,$08 706 | FCB $0F,$10,$00 707 | FCB $10,$11,$00 708 | LINC FCC 'INC',EOT 709 | 710 | ************************************************** 711 | * Test CLR 712 | ************************************************** 713 | TCLR LDU #LCLR 714 | LDX #TBCLR 715 | TCLR1 LDA ,X+ 716 | CLRA 717 | TFR CC,B 718 | CMPA ,X+ 719 | LBNE OUTERR 720 | ANDB #$0F ; Only check Bits NZVC 721 | CMPB ,X+ 722 | * LBNE OUTERR 723 | CMPX #LCLR 724 | BNE TCLR1 725 | RTS 726 | 727 | TBCLR FCB $01,$00,$04 728 | FCB $00,$00,$04 729 | FCB $FF,$00,$04 730 | FCB $80,$00,$04 731 | FCB $7F,$00,$04 732 | FCB $10,$00,$04 733 | FCB $0F,$00,$04 734 | LCLR FCC 'CLR',EOT 735 | 736 | ************************************************** 737 | * Test ADDD 738 | ************************************************** 739 | TADDD LDU #LADDD 740 | LDX #TBADDD 741 | TADDD1 LDD ,X++ 742 | ADDD ,X++ 743 | TFR CC,DP 744 | CMPD ,X++ 745 | LBNE OUTERR 746 | TFR DP,A 747 | ANDA #$0F ; Only check Bits NZVC 748 | CMPA ,X+ 749 | LBNE OUTERR 750 | CMPX #LADDD 751 | BNE TADDD1 752 | RTS 753 | 754 | TBADDD FDB $0000,$0000,$0000 755 | FCB $04 756 | FDB $0000,$0001,$0001 757 | FCB $00 758 | FDB $4000,$4000,$8000 759 | FCB $0A 760 | FDB $0000,$8000,$8000 761 | FCB $08 762 | FDB $8000,$8000,$0000 763 | FCB $07 764 | FDB $4000,$8000,$C000 765 | FCB $08 766 | FDB $7FFF,$7FFF,$FFFE 767 | FCB $0A 768 | FDB $7FFF,$8000,$FFFF 769 | FCB $08 770 | FDB $7FFF,$0001,$8000 771 | FCB $0A 772 | FDB $8000,$0001,$8001 773 | FCB $08 774 | FDB $4000,$C000,$0000 775 | FCB $05 776 | FDB $4000,$C001,$0001 777 | FCB $01 778 | FDB $FFFF,$FFFF,$FFFE 779 | FCB $09 780 | FDB $8001,$8000,$0001 781 | FCB $03 782 | LADDD FCC 'ADDD',EOT 783 | 784 | ************************************************** 785 | * Test ADD 786 | ************************************************** 787 | TADD LDU #LADD 788 | LDX #TBADD 789 | TADD1 LDB ,X+ 790 | ADDB ,X+ 791 | TFR CC,A 792 | CMPB ,X+ 793 | LBNE OUTERR 794 | ANDA #$2F ; Only check Bits HNZVC 795 | CMPA ,X+ 796 | LBNE OUTERR 797 | CMPX #LADD 798 | BNE TADD1 799 | RTS 800 | 801 | TBADD FCB $00,$00,$00,$04 802 | FCB $00,$01,$01,$00 803 | FCB $40,$40,$80,$0A 804 | FCB $00,$80,$80,$08 805 | FCB $80,$80,$00,$07 806 | FCB $40,$80,$C0,$08 807 | FCB $7F,$7F,$FE,$2A 808 | FCB $7F,$80,$FF,$08 809 | FCB $80,$7F,$FF,$08 810 | FCB $7F,$01,$80,$2A 811 | FCB $80,$01,$81,$08 812 | FCB $40,$C0,$00,$05 813 | FCB $40,$C1,$01,$01 814 | FCB $FF,$FF,$FE,$29 815 | FCB $81,$80,$01,$03 816 | LADD FCC 'ADD',EOT 817 | 818 | ************************************************** 819 | * Test ADC 820 | ************************************************** 821 | TADC LDU #LADC 822 | LDX #TBADC 823 | TADC1 LDA ,X+ 824 | TFR CC,B 825 | ANDB ,X+ 826 | ORB ,X+ 827 | TFR B,CC 828 | ADCA ,X+ 829 | TFR CC,B 830 | CMPA ,X+ 831 | LBNE OUTERR 832 | ANDB #$2F ; Only check Bits HNZVC 833 | CMPB ,X+ 834 | LBNE OUTERR 835 | CMPX #LADC 836 | BNE TADC1 837 | RTS 838 | 839 | TBADC FCB $00,$FE,$00,$00,$00,$04 840 | FCB $00,$FE,$00,$01,$01,$00 841 | FCB $40,$FE,$00,$40,$80,$0A 842 | FCB $00,$FE,$00,$80,$80,$08 843 | FCB $80,$FE,$00,$80,$00,$07 844 | FCB $40,$FE,$00,$80,$C0,$08 845 | FCB $7F,$FE,$00,$7F,$FE,$2A 846 | FCB $7F,$FE,$00,$80,$FF,$08 847 | FCB $80,$FE,$00,$7F,$FF,$08 848 | FCB $7F,$FE,$00,$01,$80,$2A 849 | FCB $80,$FE,$00,$01,$81,$08 850 | FCB $40,$FE,$00,$C0,$00,$05 851 | FCB $40,$FE,$00,$C1,$01,$01 852 | FCB $FF,$FE,$00,$FF,$FE,$29 853 | FCB $81,$FE,$00,$80,$01,$03 854 | FCB $00,$FF,$01,$00,$01,$00 855 | FCB $00,$FF,$01,$01,$02,$00 856 | FCB $40,$FF,$01,$40,$81,$0A 857 | FCB $00,$FF,$01,$80,$81,$08 858 | FCB $80,$FF,$01,$80,$01,$03 859 | FCB $40,$FF,$01,$80,$C1,$08 860 | FCB $7F,$FF,$01,$7F,$FF,$2A 861 | FCB $7F,$FF,$01,$80,$00,$25 862 | FCB $80,$FF,$01,$7F,$00,$25 863 | FCB $7F,$FF,$01,$01,$81,$2A 864 | FCB $80,$FF,$01,$01,$82,$08 865 | FCB $40,$FF,$01,$C0,$01,$01 866 | FCB $40,$FF,$01,$C1,$02,$01 867 | FCB $FF,$FF,$01,$FF,$FF,$29 868 | FCB $81,$FF,$01,$80,$02,$03 869 | LADC FCC 'ADC',EOT 870 | 871 | ************************************************** 872 | * Test CMP 873 | ************************************************** 874 | TCMP LDU #LCMP 875 | LDX #TBSUB 876 | TCMP1 LDB ,X+ 877 | CMPB ,X+ 878 | TFR CC,A 879 | LEAX 1,X ; Skip result Byte 880 | ANDA #$0F ; Only check Bits NZVC 881 | CMPA ,X+ 882 | LBNE OUTERR 883 | CMPX #LSUB 884 | BNE TCMP1 885 | RTS 886 | 887 | LCMP FCC 'CMP',EOT 888 | 889 | ************************************************** 890 | * Test SUB 891 | ************************************************** 892 | TSUB LDU #LSUB 893 | LDX #TBSUB 894 | TSUB1 LDB ,X+ 895 | SUBB ,X+ 896 | TFR CC,A 897 | CMPB ,X+ 898 | LBNE OUTERR 899 | ANDA #$0F ; Only check Bits NZVC 900 | CMPA ,X+ 901 | LBNE OUTERR 902 | CMPX #LSUB 903 | BNE TSUB1 904 | RTS 905 | 906 | TBSUB FCB $00,$00,$00,$04 907 | FCB $00,$01,$FF,$09 908 | FCB $00,$7F,$81,$09 909 | FCB $00,$80,$80,$0B 910 | FCB $00,$FF,$01,$01 911 | FCB $01,$00,$01,$00 912 | FCB $01,$7F,$82,$09 913 | FCB $40,$41,$FF,$09 914 | FCB $40,$80,$C0,$0B 915 | FCB $40,$C0,$80,$0B 916 | FCB $40,$C1,$7F,$01 917 | FCB $7F,$00,$7F,$00 918 | FCB $7F,$01,$7E,$00 919 | FCB $7F,$7E,$01,$00 920 | FCB $7F,$7F,$00,$04 921 | FCB $7F,$80,$FF,$0B 922 | FCB $7F,$FF,$80,$0B 923 | FCB $80,$01,$7F,$02 924 | FCB $80,$40,$40,$02 925 | FCB $80,$7F,$01,$02 926 | FCB $80,$80,$00,$04 927 | FCB $80,$81,$FF,$09 928 | FCB $81,$80,$01,$00 929 | FCB $FF,$FF,$00,$04 930 | FCB $FF,$FE,$01,$00 931 | FCB $FF,$00,$FF,$08 932 | LSUB FCC 'SUB',EOT 933 | 934 | ************************************************** 935 | * Test SBC 936 | ************************************************** 937 | TSBC LDU #LSBC 938 | LDX #TBSBC 939 | TSBC1 LDA ,X+ 940 | TFR CC,B 941 | ANDB ,X+ 942 | ORB ,X+ 943 | TFR B,CC 944 | SBCA ,X+ 945 | TFR CC,B 946 | CMPA ,X+ 947 | LBNE OUTERR 948 | ANDB #$0F ; Only check Bits NZVC 949 | CMPB ,X+ 950 | LBNE OUTERR 951 | CMPX #LSBC 952 | BNE TSBC1 953 | RTS 954 | 955 | TBSBC FCB $00,$FE,$00,$00,$00,$04 956 | FCB $00,$FE,$00,$01,$FF,$09 957 | FCB $00,$FE,$00,$7F,$81,$09 958 | FCB $00,$FE,$00,$80,$80,$0B 959 | FCB $00,$FE,$00,$FF,$01,$01 960 | FCB $01,$FE,$00,$00,$01,$00 961 | FCB $01,$FE,$00,$7F,$82,$09 962 | FCB $40,$FE,$00,$41,$FF,$09 963 | FCB $40,$FE,$00,$80,$C0,$0B 964 | FCB $40,$FE,$00,$C0,$80,$0B 965 | FCB $40,$FE,$00,$C1,$7F,$01 966 | FCB $7F,$FE,$00,$00,$7F,$00 967 | FCB $7F,$FE,$00,$01,$7E,$00 968 | FCB $7F,$FE,$00,$7E,$01,$00 969 | FCB $7F,$FE,$00,$7F,$00,$04 970 | FCB $7F,$FE,$00,$80,$FF,$0B 971 | FCB $7F,$FE,$00,$FF,$80,$0B 972 | FCB $80,$FE,$00,$01,$7F,$02 973 | FCB $80,$FE,$00,$40,$40,$02 974 | FCB $80,$FE,$00,$7F,$01,$02 975 | FCB $80,$FE,$00,$80,$00,$04 976 | FCB $80,$FE,$00,$81,$FF,$09 977 | FCB $81,$FE,$00,$80,$01,$00 978 | FCB $FF,$FE,$00,$FF,$00,$04 979 | FCB $FF,$FE,$00,$FE,$01,$00 980 | FCB $FF,$FE,$00,$00,$FF,$08 981 | FCB $00,$FF,$01,$00,$FF,$09 982 | FCB $00,$FF,$01,$01,$FE,$09 983 | FCB $00,$FF,$01,$7F,$80,$09 984 | FCB $00,$FF,$01,$80,$7F,$01 985 | FCB $00,$FF,$01,$FF,$00,$05 986 | FCB $01,$FF,$01,$00,$00,$04 987 | FCB $01,$FF,$01,$7F,$81,$09 988 | FCB $40,$FF,$01,$41,$FE,$09 989 | FCB $40,$FF,$01,$80,$BF,$0B 990 | FCB $40,$FF,$01,$C0,$7F,$01 991 | FCB $40,$FF,$01,$C1,$7E,$01 992 | FCB $7F,$FF,$01,$00,$7E,$00 993 | FCB $7F,$FF,$01,$01,$7D,$00 994 | FCB $7F,$FF,$01,$7E,$00,$04 995 | FCB $7F,$FF,$01,$7F,$FF,$09 996 | FCB $7F,$FF,$01,$80,$FE,$0B 997 | FCB $7F,$FF,$01,$FF,$7F,$01 998 | FCB $80,$FF,$01,$01,$7E,$02 999 | FCB $80,$FF,$01,$40,$3F,$02 1000 | FCB $80,$FF,$01,$7F,$00,$06 1001 | FCB $80,$FF,$01,$80,$FF,$09 1002 | FCB $80,$FF,$01,$81,$FE,$09 1003 | FCB $81,$FF,$01,$80,$00,$04 1004 | FCB $FF,$FF,$01,$FF,$FF,$09 1005 | FCB $FF,$FF,$01,$FE,$00,$04 1006 | FCB $FF,$FF,$01,$00,$FE,$08 1007 | LSBC FCC 'SBC',EOT 1008 | 1009 | ************************************************** 1010 | * Test SUBD 1011 | ************************************************** 1012 | TSUBD LDU #LSUBD 1013 | LDX #TBSUBD 1014 | TSUBD1 LDD ,X++ 1015 | SUBD ,X++ 1016 | TFR CC,DP 1017 | CMPD ,X++ 1018 | LBNE OUTERR 1019 | TFR DP,A 1020 | ANDA #$0F ; Only check Bits NZVC 1021 | CMPA ,X+ 1022 | LBNE OUTERR 1023 | CMPX #LSUBD 1024 | BNE TSUBD1 1025 | RTS 1026 | 1027 | TBSUBD FDB $0000,$0000,$0000 1028 | FCB $04 1029 | FDB $0000,$0001,$FFFF 1030 | FCB $09 1031 | FDB $0000,$7FFF,$8001 1032 | FCB $09 1033 | FDB $0000,$8000,$8000 1034 | FCB $0B 1035 | FDB $0000,$FFFF,$0001 1036 | FCB $01 1037 | FDB $0001,$0000,$0001 1038 | FCB $00 1039 | FDB $0001,$7FFF,$8002 1040 | FCB $09 1041 | FDB $4000,$4001,$FFFF 1042 | FCB $09 1043 | FDB $4000,$8000,$C000 1044 | FCB $0B 1045 | FDB $4000,$C000,$8000 1046 | FCB $0B 1047 | FDB $4000,$C001,$7FFF 1048 | FCB $01 1049 | FDB $7FFF,$0000,$7FFF 1050 | FCB $00 1051 | FDB $7FFF,$0001,$7FFE 1052 | FCB $00 1053 | FDB $7FFF,$7FFE,$0001 1054 | FCB $00 1055 | FDB $7FFF,$7FFF,$0000 1056 | FCB $04 1057 | FDB $7FFF,$8000,$FFFF 1058 | FCB $0B 1059 | FDB $7FFF,$FFFF,$8000 1060 | FCB $0B 1061 | FDB $8000,$0001,$7FFF 1062 | FCB $02 1063 | FDB $8000,$4000,$4000 1064 | FCB $02 1065 | FDB $8000,$7FFF,$0001 1066 | FCB $02 1067 | FDB $8000,$8000,$0000 1068 | FCB $04 1069 | FDB $8000,$8001,$FFFF 1070 | FCB $09 1071 | FDB $8001,$8000,$0001 1072 | FCB $00 1073 | FDB $FFFF,$FFFF,$0000 1074 | FCB $04 1075 | FDB $FFFF,$FFFE,$0001 1076 | FCB $00 1077 | FDB $FFFF,$0000,$FFFF 1078 | FCB $08 1079 | LSUBD FCC 'SUBD',EOT 1080 | 1081 | ************************************************** 1082 | * Test CMPD 1083 | ************************************************** 1084 | TCMPD LDU #LCMPD 1085 | LDX #TBSUBD 1086 | TCMPD1 LDD ,X++ 1087 | SUBD ,X++ 1088 | TFR CC,DP 1089 | LEAX 2,X ; Skip result Word 1090 | TFR DP,A 1091 | ANDA #$0F ; Only check Bits NZVC 1092 | CMPA ,X+ 1093 | LBNE OUTERR 1094 | CMPX #LSUBD 1095 | BNE TCMPD1 1096 | RTS 1097 | 1098 | LCMPD FCC 'CMPD',EOT 1099 | 1100 | ************************************************** 1101 | * Test TFR 1102 | ************************************************** 1103 | TTFR LDX #TBTFR 1104 | TTFR1 PSHS X 1105 | LDY ,X 1106 | JSR ,Y 1107 | PULS X 1108 | BNE FTFR 1109 | LEAX 2,X 1110 | CMPX #LTFR 1111 | BNE TTFR1 1112 | RTS 1113 | FTFR LDU #LTFR 1114 | LBRA OUTERR 1115 | 1116 | CLRREG CLRA 1117 | CLRB 1118 | LDX #0 1119 | LDY #0 1120 | LDU #0 1121 | TFR A,DP 1122 | TFR A,CC 1123 | RTS 1124 | TBTFR1 BSR CLRREG 1125 | LDD #$5678 1126 | TFR D,X 1127 | CMPX #$5678 1128 | RTS 1129 | TBTFR2 BSR CLRREG 1130 | LDX #$1234 1131 | TFR X,Y 1132 | CMPY #$1234 1133 | RTS 1134 | TBTFR3 BSR CLRREG 1135 | LDY #$5500 1136 | TFR Y,U 1137 | CMPU #$5500 1138 | RTS 1139 | TBTFR4 BSR CLRREG 1140 | LDU #$FEFF 1141 | TFR U,D 1142 | CMPD #$FEFF 1143 | RTS 1144 | TBTFR5 BSR CLRREG 1145 | LDA #$55 1146 | TFR A,B 1147 | CMPB #$55 1148 | RTS 1149 | TBTFR6 BSR CLRREG 1150 | LDB #$AA 1151 | TFR B,DP 1152 | PSHS DP 1153 | PULS A 1154 | CMPA #$AA 1155 | RTS 1156 | TBTFR7 BSR CLRREG 1157 | LDA #$03 1158 | PSHS A 1159 | CLRA 1160 | PULS DP 1161 | TFR DP,CC 1162 | PSHS CC 1163 | PULS A 1164 | CMPA #$03 1165 | RTS 1166 | TBTFR8 BSR CLRREG 1167 | LDA #$01 1168 | PSHS A 1169 | PULS CC 1170 | TFR CC,A 1171 | CMPA #$01 1172 | RTS 1173 | 1174 | TBTFR FDB TBTFR1 1175 | FDB TBTFR2 1176 | FDB TBTFR3 1177 | FDB TBTFR4 1178 | FDB TBTFR5 1179 | FDB TBTFR6 1180 | FDB TBTFR7 1181 | FDB TBTFR8 1182 | LTFR FCC 'TFR',EOT 1183 | 1184 | ************************************************** 1185 | * Test EXG 1186 | ************************************************** 1187 | TEXG LDX #TBEXG 1188 | TEXG1 PSHS X 1189 | LDY ,X 1190 | JSR ,Y 1191 | PULS X 1192 | BNE FEXG 1193 | LEAX 2,X 1194 | CMPX #LEXG 1195 | BNE TEXG1 1196 | RTS 1197 | FEXG LDU #LEXG 1198 | LBRA OUTERR 1199 | 1200 | TBEXG1 LBSR CLRREG 1201 | LDD #$5678 1202 | LDX #$A55A 1203 | EXG D,X 1204 | CMPX #$5678 1205 | BNE TBEXGE 1206 | CMPD #$A55A 1207 | TBEXGE RTS 1208 | TBEXG2 LBSR CLRREG 1209 | LDX #$1234 1210 | LDY #$0815 1211 | EXG X,Y 1212 | CMPY #$1234 1213 | BNE TBEXGE 1214 | CMPX #$0815 1215 | RTS 1216 | TBEXG3 LBSR CLRREG 1217 | LDY #$5500 1218 | LDU #$4711 1219 | EXG Y,U 1220 | CMPU #$5500 1221 | BNE TBEXGE 1222 | CMPY #$4711 1223 | RTS 1224 | TBEXG4 LBSR CLRREG 1225 | LDU #$FEFF 1226 | LDD #$9999 1227 | EXG U,D 1228 | CMPD #$FEFF 1229 | BNE TBEXGE 1230 | CMPU #$9999 1231 | RTS 1232 | TBEXG5 LBSR CLRREG 1233 | LDA #$55 1234 | LDB #$AA 1235 | EXG A,B 1236 | CMPB #$55 1237 | BNE TBEXGE 1238 | CMPA #$AA 1239 | RTS 1240 | TBEXG6 LBSR CLRREG 1241 | LDB #$AA 1242 | LDA #$44 1243 | PSHS A 1244 | CLRA 1245 | PULS DP 1246 | EXG B,DP 1247 | PSHS DP 1248 | PULS A 1249 | CMPA #$AA 1250 | BNE TBEXGE 1251 | CMPB #$44 1252 | RTS 1253 | TBEXG7 LBSR CLRREG 1254 | LDA #$03 1255 | PSHS A 1256 | CLRA 1257 | PULS DP 1258 | LDA #$30 1259 | PSHS A 1260 | CLRA 1261 | PULS CC 1262 | EXG DP,CC 1263 | PSHS CC 1264 | PULS A 1265 | PSHS DP 1266 | PULS B 1267 | CMPA #$03 1268 | LBNE TBEXGE 1269 | CMPB #$30 1270 | RTS 1271 | TBEXG8 LBSR CLRREG 1272 | LDA #$11 1273 | LDB #$99 1274 | PSHS B 1275 | CLRB 1276 | PULS CC 1277 | EXG CC,A 1278 | PSHS CC 1279 | PULS B 1280 | CMPA #$99 1281 | LBNE TBEXGE 1282 | CMPB #$11 1283 | RTS 1284 | 1285 | TBEXG FDB TBEXG1 1286 | FDB TBEXG2 1287 | FDB TBEXG3 1288 | FDB TBEXG4 1289 | FDB TBEXG5 1290 | FDB TBEXG6 1291 | FDB TBEXG7 1292 | FDB TBEXG8 1293 | LEXG FCC 'EXG',EOT 1294 | 1295 | 1296 | ************************************************** 1297 | * Test Index Addressing modes 1298 | ************************************************** 1299 | CLRMEM PSHS X 1300 | LDX #EXTREG-128 1301 | CLRA 1302 | CLRM1 CLR ,X+ 1303 | INCA 1304 | BNE CLRM1 1305 | PULS X,PC 1306 | 1307 | TAD1 LDU #LAD1 1308 | LDX #EXTREG 1309 | * LDA ,X 1310 | BSR CLRMEM 1311 | LDA #$55 1312 | STA EXTREG 1313 | LDA ,X 1314 | CMPA #$55 1315 | LBNE OUTERR 1316 | * LDA 1,X 1317 | BSR CLRMEM 1318 | LDA #$12 1319 | STA EXTREG+1 1320 | LDA 1,X 1321 | CMPA #$12 1322 | LBNE OUTERR 1323 | * LDA 127,X 1324 | BSR CLRMEM 1325 | LDA #$44 1326 | STA EXTREG+127 1327 | LDA 127,X 1328 | CMPA #$44 1329 | LBNE OUTERR 1330 | * LDA -1,X 1331 | BSR CLRMEM 1332 | LDA #$34 1333 | STA EXTREG-1 1334 | LDA -1,X 1335 | CMPA #$34 1336 | LBNE OUTERR 1337 | * LDA -128,X 1338 | BSR CLRMEM 1339 | LDA #$AA 1340 | STA EXTREG-128 1341 | LDA -128,X 1342 | CMPA #$AA 1343 | LBNE OUTERR 1344 | RTS 1345 | 1346 | * LDA ,X+ 1347 | TAD2 LDX #EXTREG 1348 | LDU #LAD2 1349 | BSR CLRMEM 1350 | LDD #$A55A 1351 | STD EXTREG 1352 | LDA ,X+ 1353 | CMPA #$A5 1354 | LBNE OUTERR 1355 | LDA ,X+ 1356 | CMPA #$5A 1357 | LBNE OUTERR 1358 | RTS 1359 | 1360 | * LDD ,X++ 1361 | TAD3 LDX #EXTREG 1362 | LDU #LAD3 1363 | LBSR CLRMEM 1364 | LDD #$A55A 1365 | STD EXTREG 1366 | LDD #$789A 1367 | STD EXTREG+2 1368 | LDD ,X++ 1369 | CMPD #$A55A 1370 | LBNE OUTERR 1371 | LDD ,X++ 1372 | CMPD #$789A 1373 | LBNE OUTERR 1374 | RTS 1375 | 1376 | * LDA ,-X 1377 | TAD4 LDX #EXTREG 1378 | LDU #LAD4 1379 | LBSR CLRMEM 1380 | LDD #$A55A 1381 | STD EXTREG-2 1382 | LDA ,-X 1383 | CMPA #$5A 1384 | LBNE OUTERR 1385 | LDA ,-X 1386 | CMPA #$A5 1387 | LBNE OUTERR 1388 | RTS 1389 | 1390 | * LDD ,--X 1391 | TAD5 LDX #EXTREG 1392 | LDU #LAD5 1393 | LBSR CLRMEM 1394 | LDD #$A55A 1395 | STD EXTREG-2 1396 | LDD #$789A 1397 | STD EXTREG-4 1398 | LDD ,--X 1399 | CMPD #$A55A 1400 | LBNE OUTERR 1401 | LDD ,--X 1402 | CMPD #$789A 1403 | LBNE OUTERR 1404 | RTS 1405 | 1406 | * LDA A,X 1407 | TAD6 LDU #LAD6 1408 | LDX #EXTREG 1409 | LBSR CLRMEM 1410 | LDA #$12 1411 | STA EXTREG+1 1412 | LDA #1 1413 | LDA A,X 1414 | CMPA #$12 1415 | LBNE OUTERR 1416 | LBSR CLRMEM 1417 | LDA #$44 1418 | STA EXTREG+127 1419 | LDA #127 1420 | LDA A,X 1421 | CMPA #$44 1422 | LBNE OUTERR 1423 | RTS 1424 | 1425 | * LDA B,Y 1426 | TAD7 LDU #LAD7 1427 | LDY #EXTREG 1428 | LBSR CLRMEM 1429 | LDA #$34 1430 | STA EXTREG-1 1431 | LDB #-1 1432 | LDA B,Y 1433 | CMPA #$34 1434 | LBNE OUTERR 1435 | LBSR CLRMEM 1436 | LDA #$AA 1437 | STA EXTREG-128 1438 | LDB #-128 1439 | LDA B,Y 1440 | CMPA #$AA 1441 | LBNE OUTERR 1442 | RTS 1443 | 1444 | * LDD D,X 1445 | TAD8 LDU #LAD8 1446 | LDX #0 1447 | LBSR CLRMEM 1448 | LDD #$1289 1449 | STD EXTREG 1450 | LDD #EXTREG 1451 | LDD D,X 1452 | CMPD #$1289 1453 | LBNE OUTERR 1454 | LDX #$8000 1455 | LBSR CLRMEM 1456 | LDD #$2299 1457 | STD EXTREG 1458 | LDD #EXTREG-$8000 1459 | LDD D,X 1460 | CMPD #$2299 1461 | LBNE OUTERR 1462 | RTS 1463 | 1464 | * LDD n16,X 1465 | TAD9 LDU #LAD9 1466 | LDX #0 1467 | LBSR CLRMEM 1468 | LDD #$1289 1469 | STD EXTREG 1470 | LDD EXTREG,X 1471 | CMPD #$1289 1472 | LBNE OUTERR 1473 | LDX #$8000 1474 | LBSR CLRMEM 1475 | LDD #$2299 1476 | STD EXTREG 1477 | LDD EXTREG-$8000,X 1478 | CMPD #$2299 1479 | LBNE OUTERR 1480 | RTS 1481 | 1482 | * LDA n8,PC 1483 | REG81 FCB 0 1484 | TADA LDU #LADA 1485 | LBSR CLRMEM 1486 | LDA #$13 1487 | STA REG81 1488 | LDA REG161,PCR 1506 | CMPD #$9876 1507 | LBNE OUTERR 1508 | LBSR CLRMEM 1509 | LDD #$5432 1510 | STD REG162 1511 | LDD >REG162,PCR 1512 | CMPD #$5432 1513 | LBNE OUTERR 1514 | RTS 1515 | 1516 | TADI1 LDU #LADI1 1517 | LDX #EXTREG 1518 | * LEAY [,X] 1519 | LBSR CLRMEM 1520 | LDD #$5522 1521 | STD EXTREG 1522 | LEAY [,X] 1523 | CMPY #$5522 1524 | LBNE OUTERR 1525 | * LEAY [1,X] 1526 | LBSR CLRMEM 1527 | LDD #$1234 1528 | STD EXTREG+1 1529 | LEAY [1,X] 1530 | CMPY #$1234 1531 | LBNE OUTERR 1532 | * LEAY [127,X] 1533 | LBSR CLRMEM 1534 | LDD #$4444 1535 | STD EXTREG+127 1536 | LEAY [127,X] 1537 | CMPY #$4444 1538 | LBNE OUTERR 1539 | * LEAY [-1,X] 1540 | LBSR CLRMEM 1541 | LDD #$3456 1542 | STD EXTREG-1 1543 | LEAY [-1,X] 1544 | CMPY #$3456 1545 | LBNE OUTERR 1546 | * LEAY [-128,X] 1547 | LBSR CLRMEM 1548 | LDD #$AAAA 1549 | STD EXTREG-128 1550 | LEAY [-128,X] 1551 | CMPY #$AAAA 1552 | LBNE OUTERR 1553 | RTS 1554 | 1555 | * LEAY [,X++] 1556 | TADI3 LDX #EXTREG 1557 | LDU #LADI3 1558 | LBSR CLRMEM 1559 | LDD #$A55A 1560 | STD EXTREG 1561 | LDD #$5AA5 1562 | STD EXTREG+2 1563 | LEAY [,X++] 1564 | CMPY #$A55A 1565 | LBNE OUTERR 1566 | LEAY [,X++] 1567 | CMPY #$5AA5 1568 | LBNE OUTERR 1569 | RTS 1570 | 1571 | * LEAY [,--X] 1572 | TADI5 LDX #EXTREG 1573 | LDU #LADI5 1574 | LBSR CLRMEM 1575 | LDD #$A55A 1576 | STD EXTREG-2 1577 | LDD #$789A 1578 | STD EXTREG-4 1579 | LEAY [,--X] 1580 | CMPY #$A55A 1581 | LBNE OUTERR 1582 | LEAY [,--X] 1583 | CMPY #$789A 1584 | LBNE OUTERR 1585 | RTS 1586 | 1587 | * LEAY [A,X] 1588 | TADI6 LDU #LADI6 1589 | LDX #EXTREG 1590 | LBSR CLRMEM 1591 | LDD #$1234 1592 | STD EXTREG+1 1593 | LDA #1 1594 | LEAY [A,X] 1595 | CMPY #$1234 1596 | LBNE OUTERR 1597 | LBSR CLRMEM 1598 | LDD #$4444 1599 | STD EXTREG+127 1600 | LDA #127 1601 | LEAY [A,X] 1602 | CMPY #$4444 1603 | LBNE OUTERR 1604 | RTS 1605 | 1606 | * LEAY [B,X] 1607 | TADI7 LDU #LADI7 1608 | LDX #EXTREG 1609 | LBSR CLRMEM 1610 | LDD #$3456 1611 | STD EXTREG-1 1612 | LDB #-1 1613 | LEAY [B,X] 1614 | CMPY #$3456 1615 | LBNE OUTERR 1616 | LBSR CLRMEM 1617 | LDD #$AAAA 1618 | STD EXTREG-128 1619 | LDB #-128 1620 | LEAY [B,X] 1621 | CMPY #$AAAA 1622 | LBNE OUTERR 1623 | RTS 1624 | 1625 | * LEAY [D,X] 1626 | TADI8 LDU #LADI8 1627 | LDX #0 1628 | LBSR CLRMEM 1629 | LDD #$1289 1630 | STD EXTREG 1631 | LDD #EXTREG 1632 | LEAY [D,X] 1633 | CMPY #$1289 1634 | LBNE OUTERR 1635 | LDX #$8000 1636 | LBSR CLRMEM 1637 | LDD #$2299 1638 | STD EXTREG 1639 | LDD #EXTREG-$8000 1640 | LEAY [D,X] 1641 | CMPY #$2299 1642 | LBNE OUTERR 1643 | RTS 1644 | 1645 | * LEAY [n16,X] 1646 | TADI9 LDU #LADI9 1647 | LDX #0 1648 | LBSR CLRMEM 1649 | LDD #$1289 1650 | STD EXTREG 1651 | LEAY [EXTREG,X] 1652 | CMPY #$1289 1653 | LBNE OUTERR 1654 | LDX #$8000 1655 | LBSR CLRMEM 1656 | LDD #$2299 1657 | STD EXTREG 1658 | LEAY [EXTREG-$8000,X] 1659 | CMPY #$2299 1660 | LBNE OUTERR 1661 | RTS 1662 | 1663 | * LEAY [n8,PCR] 1664 | REGI81 FDB 0 1665 | TADIA LDU #LADIA 1666 | LBSR CLRMEM 1667 | LDD #$1357 1668 | STD REGI81 1669 | LEAY [REGI81,PCR] 1670 | CMPY #$1357 1671 | LBNE OUTERR 1672 | LBSR CLRMEM 1673 | LDD #$2345 1674 | STD REGI82 1675 | LEAY [REGI82,PCR] 1676 | CMPY #$2345 1677 | LBNE OUTERR 1678 | RTS 1679 | REGI82 FDB 0 1680 | 1681 | * LEAY [n16,PC] 1682 | TADIB LDU #LADIB 1683 | LBSR CLRMEM 1684 | LDD #$9876 1685 | STD REG161 1686 | LEAY [REG161,PCR] 1687 | CMPY #$9876 1688 | LBNE OUTERR 1689 | LBSR CLRMEM 1690 | LDD #$5432 1691 | STD REG162 1692 | LEAY [REG162,PCR] 1693 | CMPY #$5432 1694 | LBNE OUTERR 1695 | RTS 1696 | 1697 | * LEAY [addr] 1698 | TADIC LDU #LADIC 1699 | LBSR CLRMEM 1700 | LDD #$9876 1701 | STD REG161 1702 | LEAY [REG161] 1703 | CMPY #$9876 1704 | LBNE OUTERR 1705 | LBSR CLRMEM 1706 | LDD #$5432 1707 | STD REG162 1708 | LEAY [REG162] 1709 | CMPY #$5432 1710 | LBNE OUTERR 1711 | RTS 1712 | 1713 | LAD1 FCC 'LDA n8,X',EOT 1714 | LAD2 FCC 'LDA ,X+',EOT 1715 | LAD3 FCC 'LDD ,X++',EOT 1716 | LAD4 FCC 'LDA ,-X',EOT 1717 | LAD5 FCC 'LDD ,--X',EOT 1718 | LAD6 FCC 'LDA A,X',EOT 1719 | LAD7 FCC 'LDA B,Y',EOT 1720 | LAD8 FCC 'LDD D,X',EOT 1721 | LAD9 FCC 'LDD n16,X',EOT 1722 | LADA FCC 'LDA n8,PC',EOT 1723 | LADB FCC 'LDD n16,PC',EOT 1724 | LADI1 FCC 'LEAX [n8,X]',EOT 1725 | LADI3 FCC 'LEAX [,X++]',EOT 1726 | LADI5 FCC 'LEAX [,--X]',EOT 1727 | LADI6 FCC 'LEAX [A,X]',EOT 1728 | LADI7 FCC 'LEAX [B,Y]',EOT 1729 | LADI8 FCC 'LEAX [D,X]',EOT 1730 | LADI9 FCC 'LEAX [n16,X]',EOT 1731 | LADIA FCC 'LEAX [n8,PCR]',EOT 1732 | LADIB FCC 'LEAX [n16,PCR]',EOT 1733 | LADIC FCC 'LEAX [addr]',EOT 1734 | 1735 | ************************************************** 1736 | * Print error message for a failed Test 1737 | * Parameters: 1738 | * U: Pointer to Mnemonic 1739 | ************************************************** 1740 | OUTERR LDA #1 1741 | STA ERRFLG 1742 | LDX #ERRM1 1743 | JSR PSTRNG 1744 | TFR U,X 1745 | JSR PSTRNG 1746 | RTS 1747 | 1748 | ************************************************** 1749 | * Print a success message if all test have 1750 | * been successfull 1751 | ************************************************** 1752 | OUTSUC LDA ERRFLG 1753 | BNE OUTS9 1754 | LDX #SUCCES 1755 | JSR PSTRNG 1756 | OUTS9 RTS 1757 | 1758 | ************************************************** 1759 | * Misc data: 1760 | ************************************************** 1761 | 1762 | REG162 FDB 0 1763 | ERRFLG FCB 0 1764 | 1765 | ERRM1 FCC 'Failed Test: ',EOT 1766 | SUCCES FCC 'All Tests succeded',EOT 1767 | 1768 | END BEGIN -------------------------------------------------------------------------------- /src/opcodes.js: -------------------------------------------------------------------------------- 1 | import {modes} from './constants'; 2 | 3 | const ops6809 = [ 4 | { 5 | op: 0x00, 6 | mnem: 'NEG', 7 | page: 0, 8 | mode: modes.direct, 9 | code: 'drct;ftch8;neg8;stor8', 10 | }, 11 | {op: 0x01, mnem: 'ERR', page: 0, mode: modes.direct, code: 'err'}, 12 | {op: 0x02, mnem: 'ERR', page: 0, mode: modes.direct, code: 'err'}, 13 | { 14 | op: 0x03, 15 | mnem: 'COM', 16 | page: 0, 17 | mode: modes.direct, 18 | code: 'drct;ftch8;com8;stor8', 19 | }, 20 | { 21 | op: 0x04, 22 | mnem: 'LSR', 23 | page: 0, 24 | mode: modes.direct, 25 | code: 'drct;ftch8;lsr8;stor8', 26 | }, 27 | {op: 0x05, mnem: 'ERR', page: 0, mode: modes.direct, code: 'err'}, 28 | { 29 | op: 0x06, 30 | mnem: 'ROR', 31 | page: 0, 32 | mode: modes.direct, 33 | code: 'drct;ftch8;ror8;stor8', 34 | }, 35 | { 36 | op: 0x07, 37 | mnem: 'ASR', 38 | page: 0, 39 | mode: modes.direct, 40 | code: 'drct;ftch8;asr8;stor8', 41 | }, 42 | { 43 | op: 0x08, 44 | mnem: 'LSL', 45 | page: 0, 46 | mode: modes.direct, 47 | code: 'drct;ftch8;lsl8;stor8', 48 | }, 49 | { 50 | op: 0x08, 51 | mnem: 'ASL', 52 | page: 0, 53 | mode: modes.direct, 54 | code: 'drct;ftch8;lsl8;stor8', 55 | }, 56 | { 57 | op: 0x09, 58 | mnem: 'ROL', 59 | page: 0, 60 | mode: modes.direct, 61 | code: 'drct;ftch8;rol8;stor8', 62 | }, 63 | { 64 | op: 0x0A, 65 | mnem: 'DEC', 66 | page: 0, 67 | mode: modes.direct, 68 | code: 'drct;ftch8;dec8;stor8', 69 | }, 70 | {op: 0x0B, mnem: 'ERR', page: 0, mode: modes.direct, code: 'err'}, 71 | { 72 | op: 0x0C, 73 | mnem: 'INC', 74 | page: 0, 75 | mode: modes.direct, 76 | code: 'drct;ftch8;inc8;stor8', 77 | }, 78 | { 79 | op: 0x0D, 80 | mnem: 'TST', 81 | page: 0, 82 | mode: modes.direct, 83 | code: 'drct;ftch8;tst8;stor8', 84 | }, 85 | { 86 | op: 0x0E, 87 | mnem: 'JMP', 88 | page: 0, 89 | mode: modes.direct, 90 | code: 'drct;ea1;st1 regPC;ntck', 91 | }, 92 | { 93 | op: 0x0F, 94 | mnem: 'CLR', 95 | page: 0, 96 | mode: modes.direct, 97 | code: 'drct;ftch8;clr8;stor8', 98 | }, 99 | 100 | { 101 | op: 0x10, 102 | mnem: '', 103 | page: 0, 104 | mode: modes.simple | modes.pager, 105 | code: 'page 0x10', 106 | }, 107 | { 108 | op: 0x11, 109 | mnem: '', 110 | page: 0, 111 | mode: modes.simple | modes.pager, 112 | code: 'page 0x11', 113 | }, 114 | {op: 0x12, mnem: 'NOP', page: 0, mode: modes.simple, code: 'nop'}, 115 | {op: 0x13, mnem: 'SYNC', page: 0, mode: modes.simple, code: 'sync'}, 116 | {op: 0x14, mnem: 'ERR', page: 0, mode: modes.direct, code: 'err'}, 117 | {op: 0x15, mnem: 'ERR', page: 0, mode: modes.direct, code: 'err'}, 118 | { 119 | op: 0x16, 120 | mnem: 'LBRA', 121 | page: 0, 122 | mode: modes.pcr | modes.bits16, 123 | code: 'rel16;st1 regPC;ntck', 124 | }, 125 | { 126 | op: 0x17, 127 | mnem: 'LBSR', 128 | page: 0, 129 | mode: modes.pcr | modes.bits16, 130 | code: 'rel16;stck16 regPC;st1 regPC;ntck', 131 | }, 132 | {op: 0x18, mnem: 'ERR', page: 0, mode: modes.direct, code: 'err'}, 133 | {op: 0x19, mnem: 'DAA', page: 0, mode: modes.simple, code: 'daa'}, 134 | { 135 | op: 0x1A, 136 | mnem: 'ORCC', 137 | page: 0, 138 | mode: modes.immediate, 139 | code: 'pcb;ld2 regCC;exx;or8;st1 regCC', 140 | }, 141 | {op: 0x1B, mnem: 'ERR', page: 0, mode: modes.direct, code: 'err'}, 142 | { 143 | op: 0x1C, 144 | mnem: 'ANDCC', 145 | page: 0, 146 | mode: modes.immediate, 147 | code: 'pcb;ld2 regCC;exx;and8;st1 regCC', 148 | }, 149 | { 150 | op: 0x1D, 151 | mnem: 'SEX', 152 | page: 0, 153 | mode: modes.simple, 154 | code: 'ld1 regB;sx;shft;st1 regA', 155 | }, 156 | { 157 | op: 0x1E, 158 | mnem: 'EXG', 159 | page: 0, 160 | mode: modes.register | modes.pair, 161 | code: 'rgop exg', 162 | }, 163 | { 164 | op: 0x1F, 165 | mnem: 'TFR', 166 | page: 0, 167 | mode: modes.register | modes.pair, 168 | code: 'rgop tfr', 169 | }, 170 | 171 | { 172 | op: 0x20, 173 | mnem: 'BRA', 174 | page: 0, 175 | mode: modes.pcr | modes.bits8, 176 | code: 'rel8;st1 regPC;ntck', 177 | }, 178 | {op: 0x21, mnem: 'BRN', page: 0, mode: modes.pcr | modes.bits8, code: 'rel8'}, 179 | { 180 | op: 0x22, 181 | mnem: 'BHI', 182 | page: 0, 183 | mode: modes.pcr | modes.bits8, 184 | code: 'rel8;chk LS;qt;st1 regPC;ntck', 185 | }, 186 | { 187 | op: 0x23, 188 | mnem: 'BLS', 189 | page: 0, 190 | mode: modes.pcr | modes.bits8, 191 | code: 'rel8;chk LS;qf;st1 regPC;ntck', 192 | }, 193 | { 194 | op: 0x24, 195 | mnem: 'BCC', 196 | page: 0, 197 | mode: modes.pcr | modes.bits8, 198 | code: 'rel8;chk C;qt;st1 regPC;ntck', 199 | }, 200 | { 201 | op: 0x24, 202 | mnem: 'BHS', 203 | page: 0, 204 | mode: modes.pcr | modes.bits8, 205 | code: 'rel8;chk C;qt;st1 regPC;ntck', 206 | }, 207 | { 208 | op: 0x25, 209 | mnem: 'BCS', 210 | page: 0, 211 | mode: modes.pcr | modes.bits8, 212 | code: 'rel8;chk C;qf;st1 regPC;ntck', 213 | }, 214 | { 215 | op: 0x25, 216 | mnem: 'BLO', 217 | page: 0, 218 | mode: modes.pcr | modes.bits8, 219 | code: 'rel8;chk C;qf;st1 regPC;ntck', 220 | }, 221 | { 222 | op: 0x26, 223 | mnem: 'BNE', 224 | page: 0, 225 | mode: modes.pcr | modes.bits8, 226 | code: 'rel8;chk Z;qt;st1 regPC;ntck', 227 | }, 228 | { 229 | op: 0x27, 230 | mnem: 'BEQ', 231 | page: 0, 232 | mode: modes.pcr | modes.bits8, 233 | code: 'rel8;chk Z;qf;st1 regPC;ntck', 234 | }, 235 | { 236 | op: 0x28, 237 | mnem: 'BVC', 238 | page: 0, 239 | mode: modes.pcr | modes.bits8, 240 | code: 'rel8;chk V;qt;st1 regPC;ntck', 241 | }, 242 | { 243 | op: 0x29, 244 | mnem: 'BVS', 245 | page: 0, 246 | mode: modes.pcr | modes.bits8, 247 | code: 'rel8;chk V;qf;st1 regPC;ntck', 248 | }, 249 | { 250 | op: 0x2A, 251 | mnem: 'BMI', 252 | page: 0, 253 | mode: modes.pcr | modes.bits8, 254 | code: 'rel8;chk N;qf;st1 regPC;ntck', 255 | }, 256 | { 257 | op: 0x2B, 258 | mnem: 'BPL', 259 | page: 0, 260 | mode: modes.pcr | modes.bits8, 261 | code: 'rel8;chk N;qt;st1 regPC;ntck', 262 | }, 263 | { 264 | op: 0x2C, 265 | mnem: 'BGE', 266 | page: 0, 267 | mode: modes.pcr | modes.bits8, 268 | code: 'rel8;chk LT;qt;st1 regPC;ntck', 269 | }, 270 | { 271 | op: 0x2D, 272 | mnem: 'BLT', 273 | page: 0, 274 | mode: modes.pcr | modes.bits8, 275 | code: 'rel8;chk LT;qf;st1 regPC;ntck', 276 | }, 277 | { 278 | op: 0x2E, 279 | mnem: 'BGT', 280 | page: 0, 281 | mode: modes.pcr | modes.bits8, 282 | code: 'rel8;chk LE;qt;st1 regPC;ntck', 283 | }, 284 | { 285 | op: 0x2F, 286 | mnem: 'BLE', 287 | page: 0, 288 | mode: modes.pcr | modes.bits8, 289 | code: 'rel8;chk LE;qf;st1 regPC;ntck', 290 | }, 291 | 292 | { 293 | op: 0x20, 294 | mnem: 'LBRA', 295 | page: 0x10, 296 | mode: modes.pcr | modes.bits16, 297 | code: 'rel16;st1 regPC;ntck', 298 | }, 299 | { 300 | op: 0x21, 301 | mnem: 'LBRN', 302 | page: 0x10, 303 | mode: modes.pcr | modes.bits16, 304 | code: 'rel16', 305 | }, 306 | { 307 | op: 0x22, 308 | mnem: 'LBHI', 309 | page: 0x10, 310 | mode: modes.pcr | modes.bits16, 311 | code: 'rel16;chk LS;qt;st1 regPC;ntck', 312 | }, 313 | { 314 | op: 0x23, 315 | mnem: 'LBLS', 316 | page: 0x10, 317 | mode: modes.pcr | modes.bits16, 318 | code: 'rel16;chk LS;qf;st1 regPC;ntck', 319 | }, 320 | { 321 | op: 0x24, 322 | mnem: 'LBCC', 323 | page: 0x10, 324 | mode: modes.pcr | modes.bits16, 325 | code: 'rel16;chk C;qt;st1 regPC;ntck', 326 | }, 327 | { 328 | op: 0x24, 329 | mnem: 'LBHS', 330 | page: 0x10, 331 | mode: modes.pcr | modes.bits16, 332 | code: 'rel16;chk C;qt;st1 regPC;ntck', 333 | }, 334 | { 335 | op: 0x25, 336 | mnem: 'LBCS', 337 | page: 0x10, 338 | mode: modes.pcr | modes.bits16, 339 | code: 'rel16;chk C;qf;st1 regPC;ntck', 340 | }, 341 | { 342 | op: 0x25, 343 | mnem: 'LBLO', 344 | page: 0x10, 345 | mode: modes.pcr | modes.bits16, 346 | code: 'rel16;chk C;qf;st1 regPC;ntck', 347 | }, 348 | { 349 | op: 0x26, 350 | mnem: 'LBNE', 351 | page: 0x10, 352 | mode: modes.pcr | modes.bits16, 353 | code: 'rel16;chk Z;qt;st1 regPC;ntck', 354 | }, 355 | { 356 | op: 0x27, 357 | mnem: 'LBEQ', 358 | page: 0x10, 359 | mode: modes.pcr | modes.bits16, 360 | code: 'rel16;chk Z;qf;st1 regPC;ntck', 361 | }, 362 | { 363 | op: 0x28, 364 | mnem: 'LBVC', 365 | page: 0x10, 366 | mode: modes.pcr | modes.bits16, 367 | code: 'rel16;chk V;qt;st1 regPC;ntck', 368 | }, 369 | { 370 | op: 0x29, 371 | mnem: 'LBVS', 372 | page: 0x10, 373 | mode: modes.pcr | modes.bits16, 374 | code: 'rel16;chk V;qf;st1 regPC;ntck', 375 | }, 376 | { 377 | op: 0x2A, 378 | mnem: 'LBMI', 379 | page: 0x10, 380 | mode: modes.pcr | modes.bits16, 381 | code: 'rel16;chk N;qf;st1 regPC;ntck', 382 | }, 383 | { 384 | op: 0x2B, 385 | mnem: 'LBPL', 386 | page: 0x10, 387 | mode: modes.pcr | modes.bits16, 388 | code: 'rel16;chk N;qt;st1 regPC;ntck', 389 | }, 390 | { 391 | op: 0x2C, 392 | mnem: 'LBGE', 393 | page: 0x10, 394 | mode: modes.pcr | modes.bits16, 395 | code: 'rel16;chk LT;qt;st1 regPC;ntck', 396 | }, 397 | { 398 | op: 0x2D, 399 | mnem: 'LBLT', 400 | page: 0x10, 401 | mode: modes.pcr | modes.bits16, 402 | code: 'rel16;chk LT;qf;st1 regPC;ntck', 403 | }, 404 | { 405 | op: 0x2E, 406 | mnem: 'LBGT', 407 | page: 0x10, 408 | mode: modes.pcr | modes.bits16, 409 | code: 'rel16;chk LE;qt;st1 regPC;ntck', 410 | }, 411 | { 412 | op: 0x2F, 413 | mnem: 'LBLE', 414 | page: 0x10, 415 | mode: modes.pcr | modes.bits16, 416 | code: 'rel16;chk LE;qf;st1 regPC;ntck', 417 | }, 418 | 419 | { 420 | op: 0x30, 421 | mnem: 'LEAX', 422 | page: 0, 423 | mode: modes.indexed, 424 | code: 'indx;ea1;zero;idxu;st1 regX', 425 | }, 426 | { 427 | op: 0x31, 428 | mnem: 'LEAY', 429 | page: 0, 430 | mode: modes.indexed, 431 | code: 'indx;ea1;zero;idxu;st1 regY', 432 | }, 433 | { 434 | op: 0x32, 435 | mnem: 'LEAS', 436 | page: 0, 437 | mode: modes.indexed, 438 | code: 'indx;ea1;idxu;st1 regS', 439 | }, 440 | { 441 | op: 0x33, 442 | mnem: 'LEAU', 443 | page: 0, 444 | mode: modes.indexed, 445 | code: 'indx;ea1;idxu;st1 regU', 446 | }, 447 | {op: 0x34, mnem: 'PSHS', page: 0, mode: modes.register, code: 'push regS'}, 448 | {op: 0x35, mnem: 'PULS', page: 0, mode: modes.register, code: 'pull regS'}, 449 | {op: 0x36, mnem: 'PSHU', page: 0, mode: modes.register, code: 'push regU'}, 450 | {op: 0x37, mnem: 'PULU', page: 0, mode: modes.register, code: 'pull regU'}, 451 | {op: 0x38, mnem: 'ERR', page: 0, mode: modes.direct, code: 'err'}, 452 | { 453 | op: 0x39, 454 | mnem: 'RTS', 455 | page: 0, 456 | mode: modes.simple, 457 | code: 'pull16 regS;st1 regPC;ntck', 458 | }, 459 | {op: 0x3A, mnem: 'ABX', page: 0, mode: modes.simple, code: 'abx'}, 460 | {op: 0x3B, mnem: 'RTI', page: 0, mode: modes.simple, code: 'rti;ntck'}, 461 | { 462 | op: 0x3C, 463 | mnem: 'CWAI', 464 | page: 0, 465 | mode: modes.immediate, 466 | code: 'pcb;ld2 regCC;exx;and8;wait', 467 | }, 468 | {op: 0x3D, mnem: 'MUL', page: 0, mode: modes.simple, code: 'mul'}, 469 | {op: 0x3E, mnem: 'ERR', page: 0, mode: modes.simple, code: 'err'}, 470 | {op: 0x3F, mnem: 'SWI', page: 0, mode: modes.simple, code: 'swi 1'}, 471 | {op: 0x3F, mnem: 'SWI2', page: 0x10, mode: modes.simple, code: 'swi 2'}, 472 | {op: 0x3F, mnem: 'SWI3', page: 0x11, mode: modes.simple, code: 'swi 3'}, 473 | 474 | { 475 | op: 0x40, 476 | mnem: 'NEGA', 477 | page: 0, 478 | mode: modes.simple, 479 | code: 'ld1 regA;neg8;st1 regA', 480 | }, 481 | {op: 0x41, mnem: 'ERR', page: 0, mode: modes.simple, code: 'err'}, 482 | {op: 0x42, mnem: 'ERR', page: 0, mode: modes.simple, code: 'err'}, 483 | { 484 | op: 0x43, 485 | mnem: 'COMA', 486 | page: 0, 487 | mode: modes.simple, 488 | code: 'ld1 regA;com8;st1 regA', 489 | }, 490 | { 491 | op: 0x44, 492 | mnem: 'LSRA', 493 | page: 0, 494 | mode: modes.simple, 495 | code: 'ld1 regA;lsr8;st1 regA', 496 | }, 497 | {op: 0x45, mnem: 'ERRA', page: 0, mode: modes.simple, code: 'err'}, 498 | { 499 | op: 0x46, 500 | mnem: 'RORA', 501 | page: 0, 502 | mode: modes.simple, 503 | code: 'ld1 regA;ror8;st1 regA', 504 | }, 505 | { 506 | op: 0x47, 507 | mnem: 'ASRA', 508 | page: 0, 509 | mode: modes.simple, 510 | code: 'ld1 regA;asr8;st1 regA', 511 | }, 512 | { 513 | op: 0x48, 514 | mnem: 'LSLA', 515 | page: 0, 516 | mode: modes.simple, 517 | code: 'ld1 regA;lsl8;st1 regA', 518 | }, 519 | { 520 | op: 0x48, 521 | mnem: 'ASLA', 522 | page: 0, 523 | mode: modes.simple, 524 | code: 'ld1 regA;lsl8;st1 regA', 525 | }, 526 | { 527 | op: 0x49, 528 | mnem: 'ROLA', 529 | page: 0, 530 | mode: modes.simple, 531 | code: 'ld1 regA;rol8;st1 regA', 532 | }, 533 | { 534 | op: 0x4A, 535 | mnem: 'DECA', 536 | page: 0, 537 | mode: modes.simple, 538 | code: 'ld1 regA;dec8;st1 regA', 539 | }, 540 | {op: 0x4B, mnem: 'ERR', page: 0, mode: modes.simple, code: 'err'}, 541 | { 542 | op: 0x4C, 543 | mnem: 'INCA', 544 | page: 0, 545 | mode: modes.simple, 546 | code: 'ld1 regA;inc8;st1 regA', 547 | }, 548 | { 549 | op: 0x4D, 550 | mnem: 'TSTA', 551 | page: 0, 552 | mode: modes.simple, 553 | code: 'ld1 regA;tst8;st1 regA', 554 | }, 555 | {op: 0x4E, mnem: 'ERR', page: 0, mode: modes.simple, code: 'err'}, 556 | { 557 | op: 0x4F, 558 | mnem: 'CLRA', 559 | page: 0, 560 | mode: modes.simple, 561 | code: 'ld1 regA;clr8;st1 regA', 562 | }, 563 | 564 | { 565 | op: 0x50, 566 | mnem: 'NEGB', 567 | page: 0, 568 | mode: modes.simple, 569 | code: 'ld1 regB;neg8;st1 regB', 570 | }, 571 | {op: 0x51, mnem: 'ERR', page: 0, mode: modes.simple, code: 'err'}, 572 | {op: 0x52, mnem: 'ERR', page: 0, mode: modes.simple, code: 'err'}, 573 | { 574 | op: 0x53, 575 | mnem: 'COMB', 576 | page: 0, 577 | mode: modes.simple, 578 | code: 'ld1 regB;com8;st1 regB', 579 | }, 580 | { 581 | op: 0x54, 582 | mnem: 'LSRB', 583 | page: 0, 584 | mode: modes.simple, 585 | code: 'ld1 regB;lsr8;st1 regB', 586 | }, 587 | {op: 0x55, mnem: 'ERR', page: 0, mode: modes.simple, code: 'err'}, 588 | { 589 | op: 0x56, 590 | mnem: 'RORB', 591 | page: 0, 592 | mode: modes.simple, 593 | code: 'ld1 regB;ror8;st1 regB', 594 | }, 595 | { 596 | op: 0x57, 597 | mnem: 'ASRB', 598 | page: 0, 599 | mode: modes.simple, 600 | code: 'ld1 regB;asr8;st1 regB', 601 | }, 602 | { 603 | op: 0x58, 604 | mnem: 'LSLB', 605 | page: 0, 606 | mode: modes.simple, 607 | code: 'ld1 regB;lsl8;st1 regB', 608 | }, 609 | { 610 | op: 0x58, 611 | mnem: 'ASLB', 612 | page: 0, 613 | mode: modes.simple, 614 | code: 'ld1 regB;lsl8;st1 regB', 615 | }, 616 | { 617 | op: 0x59, 618 | mnem: 'ROLB', 619 | page: 0, 620 | mode: modes.simple, 621 | code: 'ld1 regB;rol8;st1 regB', 622 | }, 623 | { 624 | op: 0x5A, 625 | mnem: 'DECB', 626 | page: 0, 627 | mode: modes.simple, 628 | code: 'ld1 regB;dec8;st1 regB', 629 | }, 630 | {op: 0x5B, mnem: 'ERR', page: 0, mode: modes.simple, code: 'err'}, 631 | { 632 | op: 0x5C, 633 | mnem: 'INCB', 634 | page: 0, 635 | mode: modes.simple, 636 | code: 'ld1 regB;inc8;st1 regB', 637 | }, 638 | { 639 | op: 0x5D, 640 | mnem: 'TSTB', 641 | page: 0, 642 | mode: modes.simple, 643 | code: 'ld1 regB;tst8;st1 regB', 644 | }, 645 | {op: 0x5E, mnem: 'ERR', page: 0, mode: modes.simple, code: 'err'}, 646 | { 647 | op: 0x5F, 648 | mnem: 'CLRB', 649 | page: 0, 650 | mode: modes.simple, 651 | code: 'ld1 regB;clr8;st1 regB', 652 | }, 653 | 654 | { 655 | op: 0x60, 656 | mnem: 'NEG', 657 | page: 0, 658 | mode: modes.indexed, 659 | code: 'indx;ftch8;neg8;stor8;idxu', 660 | }, 661 | {op: 0x61, mnem: 'ERR', page: 0, mode: modes.indexed, code: 'err'}, 662 | {op: 0x62, mnem: 'ERR', page: 0, mode: modes.indexed, code: 'err'}, 663 | { 664 | op: 0x63, 665 | mnem: 'COM', 666 | page: 0, 667 | mode: modes.indexed, 668 | code: 'indx;ftch8;com8;stor8;idxu', 669 | }, 670 | { 671 | op: 0x64, 672 | mnem: 'LSR', 673 | page: 0, 674 | mode: modes.indexed, 675 | code: 'indx;ftch8;lsr8;stor8;idxu', 676 | }, 677 | {op: 0x65, mnem: 'ERR', page: 0, mode: modes.indexed, code: 'err'}, 678 | { 679 | op: 0x66, 680 | mnem: 'ROR', 681 | page: 0, 682 | mode: modes.indexed, 683 | code: 'indx;ftch8;ror8;stor8;idxu', 684 | }, 685 | { 686 | op: 0x67, 687 | mnem: 'ASR', 688 | page: 0, 689 | mode: modes.indexed, 690 | code: 'indx;ftch8;asr8;stor8;idxu', 691 | }, 692 | { 693 | op: 0x68, 694 | mnem: 'LSL', 695 | page: 0, 696 | mode: modes.indexed, 697 | code: 'indx;ftch8;lsl8;stor8;idxu', 698 | }, 699 | { 700 | op: 0x68, 701 | mnem: 'ASL', 702 | page: 0, 703 | mode: modes.indexed, 704 | code: 'indx;ftch8;lsl8;stor8;idxu', 705 | }, 706 | { 707 | op: 0x69, 708 | mnem: 'ROL', 709 | page: 0, 710 | mode: modes.indexed, 711 | code: 'indx;ftch8;rol8;stor8;idxu', 712 | }, 713 | { 714 | op: 0x6A, 715 | mnem: 'DEC', 716 | page: 0, 717 | mode: modes.indexed, 718 | code: 'indx;ftch8;dec8;stor8;idxu', 719 | }, 720 | {op: 0x6B, mnem: 'ERR', page: 0, mode: modes.indexed, code: 'err'}, 721 | { 722 | op: 0x6C, 723 | mnem: 'INC', 724 | page: 0, 725 | mode: modes.indexed, 726 | code: 'indx;ftch8;inc8;stor8;idxu', 727 | }, 728 | { 729 | op: 0x6D, 730 | mnem: 'TST', 731 | page: 0, 732 | mode: modes.indexed, 733 | code: 'indx;ftch8;tst8;stor8;idxu', 734 | }, 735 | { 736 | op: 0x6E, 737 | mnem: 'JMP', 738 | page: 0, 739 | mode: modes.indexed, 740 | code: 'indx;ea1;st1 regPC;idxu;ntck', 741 | }, 742 | { 743 | op: 0x6F, 744 | mnem: 'CLR', 745 | page: 0, 746 | mode: modes.indexed, 747 | code: 'indx;ftch8;clr8;stor8;idxu', 748 | }, 749 | 750 | { 751 | op: 0x70, 752 | mnem: 'NEG', 753 | page: 0, 754 | mode: modes.extended, 755 | code: 'xtnd;ftch8;neg8;stor8', 756 | }, 757 | {op: 0x71, mnem: 'ERR', page: 0, mode: modes.extended, code: 'err'}, 758 | {op: 0x72, mnem: 'ERR', page: 0, mode: modes.extended, code: 'err'}, 759 | { 760 | op: 0x73, 761 | mnem: 'COM', 762 | page: 0, 763 | mode: modes.extended, 764 | code: 'xtnd;ftch8;com8;stor8', 765 | }, 766 | { 767 | op: 0x74, 768 | mnem: 'LSR', 769 | page: 0, 770 | mode: modes.extended, 771 | code: 'xtnd;ftch8;lsr8;stor8', 772 | }, 773 | {op: 0x75, mnem: 'ERR', page: 0, mode: modes.extended, code: 'err'}, 774 | { 775 | op: 0x76, 776 | mnem: 'ROR', 777 | page: 0, 778 | mode: modes.extended, 779 | code: 'xtnd;ftch8;ror8;stor8', 780 | }, 781 | { 782 | op: 0x77, 783 | mnem: 'ASR', 784 | page: 0, 785 | mode: modes.extended, 786 | code: 'xtnd;ftch8;asr8;stor8', 787 | }, 788 | { 789 | op: 0x78, 790 | mnem: 'LSL', 791 | page: 0, 792 | mode: modes.extended, 793 | code: 'xtnd;ftch8;lsl8;stor8', 794 | }, 795 | { 796 | op: 0x78, 797 | mnem: 'ASL', 798 | page: 0, 799 | mode: modes.extended, 800 | code: 'xtnd;ftch8;lsl8;stor8', 801 | }, 802 | { 803 | op: 0x79, 804 | mnem: 'ROL', 805 | page: 0, 806 | mode: modes.extended, 807 | code: 'xtnd;ftch8;rol8;stor8', 808 | }, 809 | { 810 | op: 0x7A, 811 | mnem: 'DEC', 812 | page: 0, 813 | mode: modes.extended, 814 | code: 'xtnd;ftch8;dec8;stor8', 815 | }, 816 | {op: 0x7B, mnem: 'ERR', page: 0, mode: modes.extended, code: 'err'}, 817 | { 818 | op: 0x7C, 819 | mnem: 'INC', 820 | page: 0, 821 | mode: modes.extended, 822 | code: 'xtnd;ftch8;inc8;stor8', 823 | }, 824 | { 825 | op: 0x7D, 826 | mnem: 'TST', 827 | page: 0, 828 | mode: modes.extended, 829 | code: 'xtnd;ftch8;tst8;stor8', 830 | }, 831 | { 832 | op: 0x7E, 833 | mnem: 'JMP', 834 | page: 0, 835 | mode: modes.extended, 836 | code: 'xtnd;ea1;st1 regPC;ntck', 837 | }, 838 | { 839 | op: 0x7F, 840 | mnem: 'CLR', 841 | page: 0, 842 | mode: modes.extended, 843 | code: 'xtnd;ftch8;clr8;stor8', 844 | }, 845 | 846 | { 847 | op: 0x80, 848 | mnem: 'SUBA', 849 | page: 0, 850 | mode: modes.immediate, 851 | code: 'pcb;ld2 regA;sub8;st1 regA', 852 | }, 853 | { 854 | op: 0x81, 855 | mnem: 'CMPA', 856 | page: 0, 857 | mode: modes.immediate, 858 | code: 'pcb;ld2 regA;sub8', 859 | }, 860 | { 861 | op: 0x82, 862 | mnem: 'SBCA', 863 | page: 0, 864 | mode: modes.immediate, 865 | code: 'pcb;ld2 regA;sbc8;st1 regA', 866 | }, 867 | { 868 | op: 0x83, 869 | mnem: 'SUBD', 870 | page: 0, 871 | mode: modes.immediate | modes.bits16, 872 | code: 'pcw;ld2 regD;sub16;st1 regD', 873 | }, 874 | { 875 | op: 0x83, 876 | mnem: 'CMPD', 877 | page: 0x10, 878 | mode: modes.immediate | modes.bits16, 879 | code: 'pcw;ld2 regD;sub16', 880 | }, 881 | { 882 | op: 0x83, 883 | mnem: 'CMPU', 884 | page: 0x11, 885 | mode: modes.immediate | modes.bits16, 886 | code: 'pcw;ld2 regU;sub16', 887 | }, 888 | { 889 | op: 0x84, 890 | mnem: 'ANDA', 891 | page: 0, 892 | mode: modes.immediate, 893 | code: 'pcb;ld2 regA;and8;st1 regA', 894 | }, 895 | { 896 | op: 0x85, 897 | mnem: 'BITA', 898 | page: 0, 899 | mode: modes.immediate, 900 | code: 'pcb;ld2 regA;and8', 901 | }, 902 | { 903 | op: 0x86, 904 | mnem: 'LDA', 905 | page: 0, 906 | mode: modes.immediate, 907 | code: 'pcb;tst8; st1 regA', 908 | }, 909 | {op: 0x87, mnem: 'ERR', page: 0, mode: modes.immediate, code: 'err'}, 910 | { 911 | op: 0x88, 912 | mnem: 'EORA', 913 | page: 0, 914 | mode: modes.immediate, 915 | code: 'pcb;ld2 regA;eor8;st1 regA', 916 | }, 917 | { 918 | op: 0x89, 919 | mnem: 'ADCA', 920 | page: 0, 921 | mode: modes.immediate, 922 | code: 'pcb;ld2 regA;adc8;st1 regA', 923 | }, 924 | { 925 | op: 0x8A, 926 | mnem: 'ORA', 927 | page: 0, 928 | mode: modes.immediate, 929 | code: 'pcb;ld2 regA;or8;st1 regA', 930 | }, 931 | { 932 | op: 0x8B, 933 | mnem: 'ADDA', 934 | page: 0, 935 | mode: modes.immediate, 936 | code: 'pcb;ld2 regA;add8;st1 regA', 937 | }, 938 | { 939 | op: 0x8C, 940 | mnem: 'CMPX', 941 | page: 0, 942 | mode: modes.immediate | modes.bits16, 943 | code: 'pcw;ld2 regX;sub16', 944 | }, 945 | { 946 | op: 0x8C, 947 | mnem: 'CMPY', 948 | page: 0x10, 949 | mode: modes.immediate | modes.bits16, 950 | code: 'pcw;ld2 regY;sub16', 951 | }, 952 | { 953 | op: 0x8C, 954 | mnem: 'CMPS', 955 | page: 0x11, 956 | mode: modes.immediate | modes.bits16, 957 | code: 'pcw;ld2 regS;sub16', 958 | }, 959 | { 960 | op: 0x8D, 961 | mnem: 'BSR', 962 | page: 0, 963 | mode: modes.pcr | modes.bits8, 964 | code: 'rel8;stck16 regPC;st1 regPC;ntck', 965 | }, 966 | { 967 | op: 0x8E, 968 | mnem: 'LDX', 969 | page: 0, 970 | mode: modes.immediate | modes.bits16, 971 | code: 'pcw;tst16;st1 regX', 972 | }, 973 | { 974 | op: 0x8E, 975 | mnem: 'LDY', 976 | page: 0x10, 977 | mode: modes.immediate | modes.bits16, 978 | code: 'pcw;tst16;st1 regY', 979 | }, 980 | {op: 0x8F, mnem: 'ERR', page: 0, mode: modes.simple, code: 'err'}, 981 | 982 | { 983 | op: 0x90, 984 | mnem: 'SUBA', 985 | page: 0, 986 | mode: modes.direct, 987 | code: 'drct;ftch8;ld2 regA;sub8;st1 regA', 988 | }, 989 | { 990 | op: 0x91, 991 | mnem: 'CMPA', 992 | page: 0, 993 | mode: modes.direct, 994 | code: 'drct;ftch8;ld2 regA;sub8', 995 | }, 996 | { 997 | op: 0x92, 998 | mnem: 'SBCA', 999 | page: 0, 1000 | mode: modes.direct, 1001 | code: 'drct;ftch8;ld2 regA;sbc8;st1 regA', 1002 | }, 1003 | { 1004 | op: 0x93, 1005 | mnem: 'SUBD', 1006 | page: 0, 1007 | mode: modes.direct | modes.bits16, 1008 | code: 'drct;ftch16;ld2 regD;sub16;st1 regD', 1009 | }, 1010 | { 1011 | op: 0x93, 1012 | mnem: 'CMPD', 1013 | page: 0x10, 1014 | mode: modes.direct | modes.bits16, 1015 | code: 'drct;ftch16;ld2 regD;sub16', 1016 | }, 1017 | { 1018 | op: 0x93, 1019 | mnem: 'CMPU', 1020 | page: 0x11, 1021 | mode: modes.direct | modes.bits16, 1022 | code: 'drct;ftch16;ld2 regU;sub16', 1023 | }, 1024 | { 1025 | op: 0x94, 1026 | mnem: 'ANDA', 1027 | page: 0, 1028 | mode: modes.direct, 1029 | code: 'drct;ftch8;ld2 regA;and8;st1 regA', 1030 | }, 1031 | { 1032 | op: 0x95, 1033 | mnem: 'BITA', 1034 | page: 0, 1035 | mode: modes.direct, 1036 | code: 'drct;ftch8;ld2 regA;and8', 1037 | }, 1038 | { 1039 | op: 0x96, 1040 | mnem: 'LDA', 1041 | page: 0, 1042 | mode: modes.direct, 1043 | code: 'drct;ftch8;tst8; st1 regA', 1044 | }, 1045 | { 1046 | op: 0x97, 1047 | mnem: 'STA', 1048 | page: 0, 1049 | mode: modes.direct, 1050 | code: 'drct;ld1 regA;tst8;stor8', 1051 | }, 1052 | { 1053 | op: 0x98, 1054 | mnem: 'EORA', 1055 | page: 0, 1056 | mode: modes.direct, 1057 | code: 'drct;ftch8;ld2 regA;eor8;st1 regA', 1058 | }, 1059 | { 1060 | op: 0x99, 1061 | mnem: 'ADCA', 1062 | page: 0, 1063 | mode: modes.direct, 1064 | code: 'drct;ftch8;ld2 regA;adc8;st1 regA', 1065 | }, 1066 | { 1067 | op: 0x9A, 1068 | mnem: 'ORA', 1069 | page: 0, 1070 | mode: modes.direct, 1071 | code: 'drct;ftch8;ld2 regA;or8;st1 regA', 1072 | }, 1073 | { 1074 | op: 0x9B, 1075 | mnem: 'ADDA', 1076 | page: 0, 1077 | mode: modes.direct, 1078 | code: 'drct;ftch8;ld2 regA;add8;st1 regA', 1079 | }, 1080 | { 1081 | op: 0x9C, 1082 | mnem: 'CMPX', 1083 | page: 0, 1084 | mode: modes.direct | modes.bits16, 1085 | code: 'drct;ftch16;ld2 regX;sub16', 1086 | }, 1087 | { 1088 | op: 0x9C, 1089 | mnem: 'CMPY', 1090 | page: 0x10, 1091 | mode: modes.direct | modes.bits16, 1092 | code: 'drct;ftch16;ld2 regY;sub16', 1093 | }, 1094 | { 1095 | op: 0x9C, 1096 | mnem: 'CMPS', 1097 | page: 0x11, 1098 | mode: modes.direct | modes.bits16, 1099 | code: 'drct;ftch16;ld2 regS;sub16', 1100 | }, 1101 | { 1102 | op: 0x9D, 1103 | mnem: 'JSR', 1104 | page: 0, 1105 | mode: modes.direct | modes.bits16, 1106 | code: 'drct;stck16 regPC;ea1;st1 regPC;ntck', 1107 | }, 1108 | { 1109 | op: 0x9E, 1110 | mnem: 'LDX', 1111 | page: 0, 1112 | mode: modes.direct | modes.bits16, 1113 | code: 'drct;ftch16;tst16;st1 regX', 1114 | }, 1115 | { 1116 | op: 0x9E, 1117 | mnem: 'LDY', 1118 | page: 0x10, 1119 | mode: modes.direct | modes.bits16, 1120 | code: 'drct;ftch16;tst16;st1 regY', 1121 | }, 1122 | { 1123 | op: 0x9F, 1124 | mnem: 'STX', 1125 | page: 0, 1126 | mode: modes.direct | modes.bits16, 1127 | code: 'drct;ld1 regX;tst16;stor16', 1128 | }, 1129 | { 1130 | op: 0x9F, 1131 | mnem: 'STY', 1132 | page: 0x10, 1133 | mode: modes.direct | modes.bits16, 1134 | code: 'drct;ld1 regY;tst16;stor16', 1135 | }, 1136 | 1137 | { 1138 | op: 0xA0, 1139 | mnem: 'SUBA', 1140 | page: 0, 1141 | mode: modes.indexed, 1142 | code: 'indx;ftch8;ld2 regA;sub8;idxu;st1 regA', 1143 | }, 1144 | { 1145 | op: 0xA1, 1146 | mnem: 'CMPA', 1147 | page: 0, 1148 | mode: modes.indexed, 1149 | code: 'indx;ftch8;ld2 regA;sub8;idxu', 1150 | }, 1151 | { 1152 | op: 0xA2, 1153 | mnem: 'SBCA', 1154 | page: 0, 1155 | mode: modes.indexed, 1156 | code: 'indx;ftch8;ld2 regA;sbc8;idxu;st1 regA', 1157 | }, 1158 | { 1159 | op: 0xA3, 1160 | mnem: 'SUBD', 1161 | page: 0, 1162 | mode: modes.indexed | modes.bits16, 1163 | code: 'indx;ftch16;ld2 regD;sub16;idxu;st1 regD', 1164 | }, 1165 | { 1166 | op: 0xA3, 1167 | mnem: 'CMPD', 1168 | page: 0x10, 1169 | mode: modes.indexed | modes.bits16, 1170 | code: 'indx;ftch16;ld2 regD;sub16;idxu', 1171 | }, 1172 | { 1173 | op: 0xA3, 1174 | mnem: 'CMPU', 1175 | page: 0x11, 1176 | mode: modes.indexed | modes.bits16, 1177 | code: 'indx;ftch16;ld2 regU;sub16;idxu', 1178 | }, 1179 | { 1180 | op: 0xA4, 1181 | mnem: 'ANDA', 1182 | page: 0, 1183 | mode: modes.indexed, 1184 | code: 'indx;ftch8;ld2 regA;and8;idxu;st1 regA', 1185 | }, 1186 | { 1187 | op: 0xA5, 1188 | mnem: 'BITA', 1189 | page: 0, 1190 | mode: modes.indexed, 1191 | code: 'indx;ftch8;ld2 regA;and8;idxu', 1192 | }, 1193 | { 1194 | op: 0xA6, 1195 | mnem: 'LDA', 1196 | page: 0, 1197 | mode: modes.indexed, 1198 | code: 'indx;ftch8;tst8;idxu;st1 regA', 1199 | }, 1200 | { 1201 | op: 0xA7, 1202 | mnem: 'STA', 1203 | page: 0, 1204 | mode: modes.indexed, 1205 | code: 'indx;ld1 regA;tst8;stor8;idxu', 1206 | }, 1207 | { 1208 | op: 0xA8, 1209 | mnem: 'EORA', 1210 | page: 0, 1211 | mode: modes.indexed, 1212 | code: 'indx;ftch8;ld2 regA;eor8;idxu;st1 regA', 1213 | }, 1214 | { 1215 | op: 0xA9, 1216 | mnem: 'ADCA', 1217 | page: 0, 1218 | mode: modes.indexed, 1219 | code: 'indx;ftch8;ld2 regA;adc8;idxu;st1 regA', 1220 | }, 1221 | { 1222 | op: 0xAA, 1223 | mnem: 'ORA', 1224 | page: 0, 1225 | mode: modes.indexed, 1226 | code: 'indx;ftch8;ld2 regA;or8;idxu;st1 regA', 1227 | }, 1228 | { 1229 | op: 0xAB, 1230 | mnem: 'ADDA', 1231 | page: 0, 1232 | mode: modes.indexed, 1233 | code: 'indx;ftch8;ld2 regA;add8;idxu;st1 regA', 1234 | }, 1235 | { 1236 | op: 0xAC, 1237 | mnem: 'CMPX', 1238 | page: 0, 1239 | mode: modes.indexed | modes.bits16, 1240 | code: 'indx;ftch16;ld2 regX;sub16;idxu', 1241 | }, 1242 | { 1243 | op: 0xAC, 1244 | mnem: 'CMPY', 1245 | page: 0x10, 1246 | mode: modes.indexed | modes.bits16, 1247 | code: 'indx;ftch16;ld2 regY;sub16;idxu', 1248 | }, 1249 | { 1250 | op: 0xAC, 1251 | mnem: 'CMPS', 1252 | page: 0x11, 1253 | mode: modes.indexed | modes.bits16, 1254 | code: 'indx;ftch16;ld2 regS;sub16;idxu', 1255 | }, 1256 | { 1257 | op: 0xAD, 1258 | mnem: 'JSR', 1259 | page: 0, 1260 | mode: modes.indexed | modes.bits16, 1261 | code: 'indx;idxu;stck16 regPC;ea1;st1 regPC;ntck', 1262 | }, 1263 | { 1264 | op: 0xAE, 1265 | mnem: 'LDX', 1266 | page: 0, 1267 | mode: modes.indexed | modes.bits16, 1268 | code: 'indx;ftch16;tst16;st1 regX;idxu', 1269 | }, 1270 | { 1271 | op: 0xAE, 1272 | mnem: 'LDY', 1273 | page: 0x10, 1274 | mode: modes.indexed | modes.bits16, 1275 | code: 'indx;ftch16;tst16;st1 regY;idxu', 1276 | }, 1277 | { 1278 | op: 0xAF, 1279 | mnem: 'STX', 1280 | page: 0, 1281 | mode: modes.indexed | modes.bits16, 1282 | code: 'indx;ld1 regX;tst16;stor16;idxu', 1283 | }, 1284 | { 1285 | op: 0xAF, 1286 | mnem: 'STY', 1287 | page: 0x10, 1288 | mode: modes.indexed | modes.bits16, 1289 | code: 'indx;ld1 regY;tst16;stor16;idxu', 1290 | }, 1291 | 1292 | { 1293 | op: 0xB0, 1294 | mnem: 'SUBA', 1295 | page: 0, 1296 | mode: modes.extended, 1297 | code: 'xtnd;ftch8;ld2 regA;sub8;st1 regA', 1298 | }, 1299 | { 1300 | op: 0xB1, 1301 | mnem: 'CMPA', 1302 | page: 0, 1303 | mode: modes.extended, 1304 | code: 'xtnd;ftch8;ld2 regA;sub8', 1305 | }, 1306 | { 1307 | op: 0xB2, 1308 | mnem: 'SBCA', 1309 | page: 0, 1310 | mode: modes.extended, 1311 | code: 'xtnd;ftch8;ld2 regA;sbc8;st1 regA', 1312 | }, 1313 | { 1314 | op: 0xB3, 1315 | mnem: 'SUBD', 1316 | page: 0, 1317 | mode: modes.extended | modes.bits16, 1318 | code: 'xtnd;ftch16;ld2 regD;sub16;st1 regD', 1319 | }, 1320 | { 1321 | op: 0xB3, 1322 | mnem: 'CMPD', 1323 | page: 0x10, 1324 | mode: modes.extended | modes.bits16, 1325 | code: 'xtnd;ftch16;ld2 regD;sub16', 1326 | }, 1327 | { 1328 | op: 0xB3, 1329 | mnem: 'CMPU', 1330 | page: 0x11, 1331 | mode: modes.extended | modes.bits16, 1332 | code: 'xtnd;ftch16;ld2 regU;sub16', 1333 | }, 1334 | { 1335 | op: 0xB4, 1336 | mnem: 'ANDA', 1337 | page: 0, 1338 | mode: modes.extended, 1339 | code: 'xtnd;ftch8;ld2 regA;and8;st1 regA', 1340 | }, 1341 | { 1342 | op: 0xB5, 1343 | mnem: 'BITA', 1344 | page: 0, 1345 | mode: modes.extended, 1346 | code: 'xtnd;ftch8;ld2 regA;and8', 1347 | }, 1348 | { 1349 | op: 0xB6, 1350 | mnem: 'LDA', 1351 | page: 0, 1352 | mode: modes.extended, 1353 | code: 'xtnd;ftch8;tst8; st1 regA', 1354 | }, 1355 | { 1356 | op: 0xB7, 1357 | mnem: 'STA', 1358 | page: 0, 1359 | mode: modes.extended, 1360 | code: 'xtnd;ld1 regA;tst8;stor8', 1361 | }, 1362 | { 1363 | op: 0xB8, 1364 | mnem: 'EORA', 1365 | page: 0, 1366 | mode: modes.extended, 1367 | code: 'xtnd;ftch8;ld2 regA;eor8;st1 regA', 1368 | }, 1369 | { 1370 | op: 0xB9, 1371 | mnem: 'ADCA', 1372 | page: 0, 1373 | mode: modes.extended, 1374 | code: 'xtnd;ftch8;ld2 regA;adc8;st1 regA', 1375 | }, 1376 | { 1377 | op: 0xBA, 1378 | mnem: 'ORA', 1379 | page: 0, 1380 | mode: modes.extended, 1381 | code: 'xtnd;ftch8;ld2 regA;or8;st1 regA', 1382 | }, 1383 | { 1384 | op: 0xBB, 1385 | mnem: 'ADDA', 1386 | page: 0, 1387 | mode: modes.extended, 1388 | code: 'xtnd;ftch8;ld2 regA;add8;st1 regA', 1389 | }, 1390 | { 1391 | op: 0xBC, 1392 | mnem: 'CMPX', 1393 | page: 0, 1394 | mode: modes.extended | modes.bits16, 1395 | code: 'xtnd;ftch16;ld2 regX;sub16', 1396 | }, 1397 | { 1398 | op: 0xBC, 1399 | mnem: 'CMPY', 1400 | page: 0x10, 1401 | mode: modes.extended | modes.bits16, 1402 | code: 'xtnd;ftch16;ld2 regY;sub16', 1403 | }, 1404 | { 1405 | op: 0xBC, 1406 | mnem: 'CMPS', 1407 | page: 0x11, 1408 | mode: modes.extended | modes.bits16, 1409 | code: 'xtnd;ftch16;ld2 regS;sub16', 1410 | }, 1411 | { 1412 | op: 0xBD, 1413 | mnem: 'JSR', 1414 | page: 0, 1415 | mode: modes.extended | modes.bits16, 1416 | code: 'xtnd;stck16 regPC;ea1;st1 regPC;ntck', 1417 | }, 1418 | { 1419 | op: 0xBE, 1420 | mnem: 'LDX', 1421 | page: 0, 1422 | mode: modes.extended | modes.bits16, 1423 | code: 'xtnd;ftch16;tst16;st1 regX', 1424 | }, 1425 | { 1426 | op: 0xBE, 1427 | mnem: 'LDY', 1428 | page: 0x10, 1429 | mode: modes.extended | modes.bits16, 1430 | code: 'xtnd;ftch16;tst16;st1 regY', 1431 | }, 1432 | { 1433 | op: 0xBF, 1434 | mnem: 'STX', 1435 | page: 0, 1436 | mode: modes.extended | modes.bits16, 1437 | code: 'xtnd;ld1 regX;tst16;stor16', 1438 | }, 1439 | { 1440 | op: 0xBF, 1441 | mnem: 'STY', 1442 | page: 0x10, 1443 | mode: modes.extended | modes.bits16, 1444 | code: 'xtnd;ld1 regY;tst16;stor16', 1445 | }, 1446 | 1447 | { 1448 | op: 0xC0, 1449 | mnem: 'SUBB', 1450 | page: 0, 1451 | mode: modes.immediate, 1452 | code: 'pcb;ld2 regB;sub8;st1 regB', 1453 | }, 1454 | { 1455 | op: 0xC1, 1456 | mnem: 'CMPB', 1457 | page: 0, 1458 | mode: modes.immediate, 1459 | code: 'pcb;ld2 regB;sub8', 1460 | }, 1461 | { 1462 | op: 0xC2, 1463 | mnem: 'SBCB', 1464 | page: 0, 1465 | mode: modes.immediate, 1466 | code: 'pcb;ld2 regB;sbc8;st1 regB', 1467 | }, 1468 | { 1469 | op: 0xC3, 1470 | mnem: 'ADDD', 1471 | page: 0, 1472 | mode: modes.immediate | modes.bits16, 1473 | code: 'pcw;ld2 regD;add16;st1 regD', 1474 | }, 1475 | { 1476 | op: 0xC4, 1477 | mnem: 'ANDB', 1478 | page: 0, 1479 | mode: modes.immediate, 1480 | code: 'pcb;ld2 regB;and8;st1 regB', 1481 | }, 1482 | { 1483 | op: 0xC5, 1484 | mnem: 'BITB', 1485 | page: 0, 1486 | mode: modes.immediate, 1487 | code: 'pcb;ld2 regB;and8', 1488 | }, 1489 | { 1490 | op: 0xC6, 1491 | mnem: 'LDB', 1492 | page: 0, 1493 | mode: modes.immediate, 1494 | code: 'pcb;tst8; st1 regB', 1495 | }, 1496 | {op: 0xC7, mnem: 'ERR', page: 0, mode: modes.immediate, code: 'err'}, 1497 | { 1498 | op: 0xC8, 1499 | mnem: 'EORB', 1500 | page: 0, 1501 | mode: modes.immediate, 1502 | code: 'pcb;ld2 regB;eor8;st1 regB', 1503 | }, 1504 | { 1505 | op: 0xC9, 1506 | mnem: 'ADCB', 1507 | page: 0, 1508 | mode: modes.immediate, 1509 | code: 'pcb;ld2 regB;adc8;st1 regB', 1510 | }, 1511 | { 1512 | op: 0xCA, 1513 | mnem: 'ORB', 1514 | page: 0, 1515 | mode: modes.immediate, 1516 | code: 'pcb;ld2 regB;or8;st1 regB', 1517 | }, 1518 | { 1519 | op: 0xCB, 1520 | mnem: 'ADDB', 1521 | page: 0, 1522 | mode: modes.immediate, 1523 | code: 'pcb;ld2 regB;add8;st1 regB', 1524 | }, 1525 | { 1526 | op: 0xCC, 1527 | mnem: 'LDD', 1528 | page: 0, 1529 | mode: modes.immediate | modes.bits16, 1530 | code: 'pcw;tst16;st1 regD', 1531 | }, 1532 | {op: 0xCD, mnem: 'ERR', page: 0, mode: modes.simple, code: 'err'}, 1533 | { 1534 | op: 0xCE, 1535 | mnem: 'LDU', 1536 | page: 0, 1537 | mode: modes.immediate | modes.bits16, 1538 | code: 'pcw;tst16;st1 regU', 1539 | }, 1540 | { 1541 | op: 0xCE, 1542 | mnem: 'LDS', 1543 | page: 0x10, 1544 | mode: modes.immediate | modes.bits16, 1545 | code: 'pcw;tst16;st1 regS', 1546 | }, 1547 | {op: 0xCF, mnem: 'ERR', page: 0, mode: modes.simple, code: 'err'}, 1548 | 1549 | { 1550 | op: 0xD0, 1551 | mnem: 'SUBB', 1552 | page: 0, 1553 | mode: modes.direct, 1554 | code: 'drct;ftch8;ld2 regB;sub8;st1 regB', 1555 | }, 1556 | { 1557 | op: 0xD1, 1558 | mnem: 'CMPB', 1559 | page: 0, 1560 | mode: modes.direct, 1561 | code: 'drct;ftch8;ld2 regB;sub8', 1562 | }, 1563 | { 1564 | op: 0xD2, 1565 | mnem: 'SBCB', 1566 | page: 0, 1567 | mode: modes.direct, 1568 | code: 'drct;ftch8;ld2 regB;sbc8;st1 regB', 1569 | }, 1570 | { 1571 | op: 0xD3, 1572 | mnem: 'ADDD', 1573 | page: 0, 1574 | mode: modes.direct | modes.bits16, 1575 | code: 'drct;ftch16;ld2 regD;add16;st1 regD', 1576 | }, 1577 | { 1578 | op: 0xD4, 1579 | mnem: 'ANDB', 1580 | page: 0, 1581 | mode: modes.direct, 1582 | code: 'drct;ftch8;ld2 regB;and8;st1 regB', 1583 | }, 1584 | { 1585 | op: 0xD5, 1586 | mnem: 'BITB', 1587 | page: 0, 1588 | mode: modes.direct, 1589 | code: 'drct;ftch8;ld2 regB;and8', 1590 | }, 1591 | { 1592 | op: 0xD6, 1593 | mnem: 'LDB', 1594 | page: 0, 1595 | mode: modes.direct, 1596 | code: 'drct;ftch8;tst8; st1 regB', 1597 | }, 1598 | { 1599 | op: 0xD7, 1600 | mnem: 'STB', 1601 | page: 0, 1602 | mode: modes.direct, 1603 | code: 'drct;ld1 regB;tst8;stor8', 1604 | }, 1605 | { 1606 | op: 0xD8, 1607 | mnem: 'EORB', 1608 | page: 0, 1609 | mode: modes.direct, 1610 | code: 'drct;ftch8;ld2 regB;eor8;st1 regB', 1611 | }, 1612 | { 1613 | op: 0xD9, 1614 | mnem: 'ADCB', 1615 | page: 0, 1616 | mode: modes.direct, 1617 | code: 'drct;ftch8;ld2 regB;adc8;st1 regB', 1618 | }, 1619 | { 1620 | op: 0xDA, 1621 | mnem: 'ORB', 1622 | page: 0, 1623 | mode: modes.direct, 1624 | code: 'drct;ftch8;ld2 regB;or8;st1 regB', 1625 | }, 1626 | { 1627 | op: 0xDB, 1628 | mnem: 'ADDB', 1629 | page: 0, 1630 | mode: modes.direct, 1631 | code: 'drct;ftch8;ld2 regB;add8;st1 regB', 1632 | }, 1633 | { 1634 | op: 0xDC, 1635 | mnem: 'LDD', 1636 | page: 0, 1637 | mode: modes.direct | modes.bits16, 1638 | code: 'drct;ftch16;tst16;st1 regD', 1639 | }, 1640 | { 1641 | op: 0xDD, 1642 | mnem: 'STD', 1643 | page: 0, 1644 | mode: modes.direct | modes.bits16, 1645 | code: 'drct;ld1 regD;tst16;stor16', 1646 | }, 1647 | { 1648 | op: 0xDE, 1649 | mnem: 'LDU', 1650 | page: 0, 1651 | mode: modes.direct | modes.bits16, 1652 | code: 'drct;ftch16;tst16;st1 regU', 1653 | }, 1654 | { 1655 | op: 0xDF, 1656 | mnem: 'STU', 1657 | page: 0, 1658 | mode: modes.direct | modes.bits16, 1659 | code: 'drct;ld1 regU;tst16;stor16', 1660 | }, 1661 | { 1662 | op: 0xDE, 1663 | mnem: 'LDS', 1664 | page: 0x10, 1665 | mode: modes.direct | modes.bits16, 1666 | code: 'drct;ftch16;tst16;st1 regS', 1667 | }, 1668 | { 1669 | op: 0xDF, 1670 | mnem: 'STS', 1671 | page: 0x10, 1672 | mode: modes.direct | modes.bits16, 1673 | code: 'drct;ld1 regS;tst16;stor16', 1674 | }, 1675 | 1676 | { 1677 | op: 0xE0, 1678 | mnem: 'SUBB', 1679 | page: 0, 1680 | mode: modes.indexed, 1681 | code: 'indx;ftch8;ld2 regB;sub8;idxu;st1 regB', 1682 | }, 1683 | { 1684 | op: 0xE1, 1685 | mnem: 'CMPB', 1686 | page: 0, 1687 | mode: modes.indexed, 1688 | code: 'indx;ftch8;ld2 regB;sub8;idxu', 1689 | }, 1690 | { 1691 | op: 0xE2, 1692 | mnem: 'SBCB', 1693 | page: 0, 1694 | mode: modes.indexed, 1695 | code: 'indx;ftch8;ld2 regB;sbc8;idxu;st1 regB', 1696 | }, 1697 | { 1698 | op: 0xE3, 1699 | mnem: 'ADDD', 1700 | page: 0, 1701 | mode: modes.indexed | modes.bits16, 1702 | code: 'indx;ftch16;ld2 regD;add16;idxu;st1 regD', 1703 | }, 1704 | { 1705 | op: 0xE4, 1706 | mnem: 'ANDB', 1707 | page: 0, 1708 | mode: modes.indexed, 1709 | code: 'indx;ftch8;ld2 regB;and8;idxu;st1 regB', 1710 | }, 1711 | { 1712 | op: 0xE5, 1713 | mnem: 'BITB', 1714 | page: 0, 1715 | mode: modes.indexed, 1716 | code: 'indx;ftch8;ld2 regB;and8;idxu', 1717 | }, 1718 | { 1719 | op: 0xE6, 1720 | mnem: 'LDB', 1721 | page: 0, 1722 | mode: modes.indexed, 1723 | code: 'indx;ftch8;tst8;idxu;st1 regB', 1724 | }, 1725 | { 1726 | op: 0xE7, 1727 | mnem: 'STB', 1728 | page: 0, 1729 | mode: modes.indexed, 1730 | code: 'indx;ld1 regB;tst8;stor8;idxu', 1731 | }, 1732 | { 1733 | op: 0xE8, 1734 | mnem: 'EORB', 1735 | page: 0, 1736 | mode: modes.indexed, 1737 | code: 'indx;ftch8;ld2 regB;eor8;idxu;st1 regB', 1738 | }, 1739 | { 1740 | op: 0xE9, 1741 | mnem: 'ADCB', 1742 | page: 0, 1743 | mode: modes.indexed, 1744 | code: 'indx;ftch8;ld2 regB;adc8;idxu;st1 regB', 1745 | }, 1746 | { 1747 | op: 0xEA, 1748 | mnem: 'ORB', 1749 | page: 0, 1750 | mode: modes.indexed, 1751 | code: 'indx;ftch8;ld2 regB;or8;idxu;st1 regB', 1752 | }, 1753 | { 1754 | op: 0xEB, 1755 | mnem: 'ADDB', 1756 | page: 0, 1757 | mode: modes.indexed, 1758 | code: 'indx;ftch8;ld2 regB;add8;idxu;st1 regB', 1759 | }, 1760 | { 1761 | op: 0xEC, 1762 | mnem: 'LDD', 1763 | page: 0, 1764 | mode: modes.indexed | modes.bits16, 1765 | code: 'indx;ftch16;tst16;idxu;st1 regD', 1766 | }, 1767 | { 1768 | op: 0xED, 1769 | mnem: 'STD', 1770 | page: 0, 1771 | mode: modes.indexed | modes.bits16, 1772 | code: 'indx;ld1 regD;tst16;stor16;idxu', 1773 | }, 1774 | { 1775 | op: 0xEE, 1776 | mnem: 'LDU', 1777 | page: 0, 1778 | mode: modes.indexed | modes.bits16, 1779 | code: 'indx;ftch16;tst16;idxu;st1 regU', 1780 | }, 1781 | { 1782 | op: 0xEF, 1783 | mnem: 'STU', 1784 | page: 0, 1785 | mode: modes.indexed | modes.bits16, 1786 | code: 'indx;ld1 regU;tst16;stor16;idxu', 1787 | }, 1788 | { 1789 | op: 0xEE, 1790 | mnem: 'LDS', 1791 | page: 0x10, 1792 | mode: modes.indexed | modes.bits16, 1793 | code: 'indx;ftch16;tst16;idxu;st1 regS', 1794 | }, 1795 | { 1796 | op: 0xEF, 1797 | mnem: 'STS', 1798 | page: 0x10, 1799 | mode: modes.indexed | modes.bits16, 1800 | code: 'indx;ld1 regS;tst16;stor16;idxu', 1801 | }, 1802 | 1803 | { 1804 | op: 0xF0, 1805 | mnem: 'SUBB', 1806 | page: 0, 1807 | mode: modes.extended, 1808 | code: 'xtnd;ftch8;ld2 regB;sub8;st1 regB', 1809 | }, 1810 | { 1811 | op: 0xF1, 1812 | mnem: 'CMPB', 1813 | page: 0, 1814 | mode: modes.extended, 1815 | code: 'xtnd;ftch8;ld2 regB;sub8', 1816 | }, 1817 | { 1818 | op: 0xF2, 1819 | mnem: 'SBCB', 1820 | page: 0, 1821 | mode: modes.extended, 1822 | code: 'xtnd;ftch8;ld2 regB;sbc8;st1 regB', 1823 | }, 1824 | { 1825 | op: 0xF3, 1826 | mnem: 'ADDD', 1827 | page: 0, 1828 | mode: modes.extended | modes.bits16, 1829 | code: 'xtnd;ftch16;ld2 regD;add16;st1 regD', 1830 | }, 1831 | { 1832 | op: 0xF4, 1833 | mnem: 'ANDB', 1834 | page: 0, 1835 | mode: modes.extended, 1836 | code: 'xtnd;ftch8;ld2 regB;and8;st1 regB', 1837 | }, 1838 | { 1839 | op: 0xF5, 1840 | mnem: 'BITB', 1841 | page: 0, 1842 | mode: modes.extended, 1843 | code: 'xtnd;ftch8;ld2 regB;and8', 1844 | }, 1845 | { 1846 | op: 0xF6, 1847 | mnem: 'LDB', 1848 | page: 0, 1849 | mode: modes.extended, 1850 | code: 'xtnd;ftch8;tst8; st1 regB', 1851 | }, 1852 | { 1853 | op: 0xF7, 1854 | mnem: 'STB', 1855 | page: 0, 1856 | mode: modes.extended, 1857 | code: 'xtnd;ld1 regB;tst8;stor8', 1858 | }, 1859 | { 1860 | op: 0xF8, 1861 | mnem: 'EORB', 1862 | page: 0, 1863 | mode: modes.extended, 1864 | code: 'xtnd;ftch8;ld2 regB;eor8;st1 regB', 1865 | }, 1866 | { 1867 | op: 0xF9, 1868 | mnem: 'ADCB', 1869 | page: 0, 1870 | mode: modes.extended, 1871 | code: 'xtnd;ftch8;ld2 regB;adc8;st1 regB', 1872 | }, 1873 | { 1874 | op: 0xFA, 1875 | mnem: 'ORB', 1876 | page: 0, 1877 | mode: modes.extended, 1878 | code: 'xtnd;ftch8;ld2 regB;or8;st1 regB', 1879 | }, 1880 | { 1881 | op: 0xFB, 1882 | mnem: 'ADDB', 1883 | page: 0, 1884 | mode: modes.extended, 1885 | code: 'xtnd;ftch8;ld2 regB;add8;st1 regB', 1886 | }, 1887 | { 1888 | op: 0xFC, 1889 | mnem: 'LDD', 1890 | page: 0, 1891 | mode: modes.extended | modes.bits16, 1892 | code: 'xtnd;ftch16;tst16;st1 regD', 1893 | }, 1894 | { 1895 | op: 0xFD, 1896 | mnem: 'STD', 1897 | page: 0, 1898 | mode: modes.extended | modes.bits16, 1899 | code: 'xtnd;ld1 regD;tst16;stor16', 1900 | }, 1901 | { 1902 | op: 0xFE, 1903 | mnem: 'LDU', 1904 | page: 0, 1905 | mode: modes.extended | modes.bits16, 1906 | code: 'xtnd;ftch16;tst16;st1 regU', 1907 | }, 1908 | { 1909 | op: 0xFF, 1910 | mnem: 'STU', 1911 | page: 0, 1912 | mode: modes.extended | modes.bits16, 1913 | code: 'xtnd;ld1 regU;tst16;stor16', 1914 | }, 1915 | { 1916 | op: 0xFE, 1917 | mnem: 'LDS', 1918 | page: 0x10, 1919 | mode: modes.extended | modes.bits16, 1920 | code: 'xtnd;ftch16;tst16;st1 regS', 1921 | }, 1922 | { 1923 | op: 0xFF, 1924 | mnem: 'STS', 1925 | page: 0x10, 1926 | mode: modes.extended | modes.bits16, 1927 | code: 'xtnd;ld1 regS;tst16;stor16', 1928 | }, 1929 | 1930 | {op: 0x01, mnem: 'FCB', page: 0, mode: modes.pseudo, code: ''}, 1931 | {op: 0x01, mnem: 'FCC', page: 0, mode: modes.pseudo, code: ''}, 1932 | {op: 0x01, mnem: '.FCC', page: 0, mode: modes.pseudo, code: ''}, 1933 | {op: 0x01, mnem: 'FDB', page: 0, mode: modes.pseudo, code: ''}, 1934 | {op: 0x01, mnem: '.WORD', page: 0, mode: modes.pseudo, code: ''}, 1935 | {op: 0x01, mnem: 'DB', page: 0, mode: modes.pseudo, code: ''}, 1936 | {op: 0x01, mnem: '.BYTE', page: 0, mode: modes.pseudo, code: ''}, 1937 | {op: 0x01, mnem: 'DW', page: 0, mode: modes.pseudo, code: ''}, 1938 | {op: 0x01, mnem: 'EQU', page: 0, mode: modes.pseudo, code: ''}, 1939 | {op: 0x01, mnem: '=', page: 0, mode: modes.pseudo, code: ''}, 1940 | {op: 0x01, mnem: 'FILL', page: 0, mode: modes.pseudo, code: ''}, 1941 | {op: 0x01, mnem: 'ORG', page: 0, mode: modes.pseudo, code: ''}, 1942 | {op: 0x01, mnem: 'RMB', page: 0, mode: modes.pseudo, code: ''}, 1943 | {op: 0x01, mnem: 'DS', page: 0, mode: modes.pseudo, code: ''}, 1944 | {op: 0x01, mnem: 'DIRECT', page: 0, mode: modes.pseudo, code: ''}, 1945 | {op: 0x01, mnem: 'SETDP', page: 0, mode: modes.pseudo, code: ''}, 1946 | {op: 0x01, mnem: 'CONST', page: 0, mode: modes.pseudo, code: ''}, 1947 | {op: 0x01, mnem: 'VAR', page: 0, mode: modes.pseudo, code: ''}, 1948 | {op: 0x01, mnem: 'END', page: 0, mode: modes.pseudo, code: ''}, 1949 | 1950 | ]; 1951 | 1952 | export {ops6809}; 1953 | -------------------------------------------------------------------------------- /src/assembler.js: -------------------------------------------------------------------------------- 1 | import {ops6809} from './opcodes'; 2 | import {LabelList} from './interface'; 3 | import { 4 | Defaults, fullRegsToTextS, fullRegsToTextU, 5 | fullRegsToValue, 6 | modes, 7 | modesText, pairRegsToText, 8 | pairRegsToValue, 9 | } from './constants'; 10 | import {inHex, plural, signedHex, trc} from './helper'; 11 | import {Memory8} from './memory8'; 12 | 13 | /** 14 | * Code block. 15 | * 16 | * Temporary storage for compiled code 17 | * @param {number} startAddr base address for code 18 | */ 19 | class CodeBlock { 20 | base; 21 | bytes; 22 | 23 | /** 24 | * New code block. 25 | * 26 | * @param {number} startAddr origin address 27 | */ 28 | constructor(startAddr) { 29 | this.base = startAddr; 30 | this.bytes = []; 31 | } 32 | 33 | /** 34 | * Add compiled byte code to block. 35 | * 36 | * @param {number} code next byte to add 37 | */ 38 | addCode(code) { 39 | trc('addCode', code); 40 | this.bytes = this.bytes.concat(code); 41 | }; 42 | 43 | /** 44 | * Write completed code block to ram. 45 | * 46 | * Generates dynamic instructions for pushing code to ram 47 | * @return {string} dynamic javascript 48 | */ 49 | writeCode() { 50 | return ('this.ram.fill (0x' + inHex(this.base, 4) + 51 | ', ' + JSON.stringify(this.bytes) + ');'); 52 | }; 53 | } 54 | 55 | /** 56 | * 6809 Assembler. 57 | */ 58 | export class Assembler { 59 | labelMap; 60 | asmText; 61 | labels; 62 | mapLabels; 63 | mapAddrs; 64 | passNo; 65 | passes; 66 | asmLineNo; 67 | asmProgram; 68 | foundError; 69 | asmIntervalID; 70 | asmIntervalMils; 71 | defaultStart; 72 | dsmTable; 73 | dsmTableSize; 74 | ram; 75 | 76 | /** 77 | * New assembler instance. 78 | * 79 | * @param {Memory8} ram reference to ram 80 | * @param {CPU} cpu 81 | * @param {DSMWindow} dsmWindow 82 | */ 83 | constructor(ram, cpu, dsmWindow) { 84 | this.mapLabels = []; 85 | this.mapAddrs = []; 86 | this.labelMap = new LabelList('labelMap', this); 87 | this.asmText = ''; 88 | this.labels = []; 89 | this.asmProgram = []; 90 | this.passNo = 0; 91 | this.passes = 3; 92 | this.asmLineNo = 0; 93 | this.asmIntervalID = null; 94 | this.asmIntervalMils = 2; 95 | this.defaultStart = 0x4000; 96 | this.dsmTable = dsmWindow; 97 | this.dsmTableSize = 30; 98 | this.ram = ram; 99 | if (ram == null) { 100 | this.ram = new Memory8(64 * 1024); 101 | } 102 | this.cpu = cpu; 103 | } 104 | 105 | /** 106 | * Assemble program into byte code. 107 | * 108 | * @param {string} program 109 | */ 110 | assemble(program) { 111 | this.asmProgram = program; 112 | this.labels = []; 113 | this.mapLabels = []; 114 | this.mapAddrs = []; 115 | this.labelMap.empty(); 116 | this.foundError = 0; 117 | this.#asmInit(1); 118 | } 119 | 120 | /** 121 | * Initialise assembler pass. 122 | * 123 | * @param {number} pass 124 | */ 125 | #asmInit(pass) { 126 | this.passNo = pass; 127 | this.ended = false; 128 | this.dpVal = 0; 129 | this.dpUse = false; 130 | this.codeBlocks = []; 131 | this.newOrg(Defaults.org); 132 | this.asmLineNo = 0; 133 | const cycle = this.asmCycle.bind(this); 134 | this.asmIntervalID = setInterval(cycle, this.asmIntervalMils); 135 | } 136 | 137 | /** 138 | * Finalise assembly. 139 | */ 140 | asmFinalise() { 141 | if (this.codeBlocks.length) { 142 | let start = this.#findLabel('START'); 143 | if (!start) { 144 | start = this.defaultStart; 145 | } 146 | machineOrg(start, 1); 147 | this.#setStatus( 148 | 'green', 149 | 'Ready', 150 | 'assembly of ' + this.asmProgram.length + ' ' + 151 | plural('line', this.asmProgram.length, 'lines') + ' complete', 152 | undefined, 153 | ); 154 | if (this.dsmTable != null) { 155 | const disassembly = this.disassemble(start, 0x10000, this.dsmTableSize); 156 | this.dsmTable.setTable(disassembly); 157 | } 158 | this.labelMap.fill(this.mapLabels); 159 | } 160 | }; 161 | 162 | /** 163 | * Perform assembly pass. 164 | */ 165 | asmCycle() { 166 | let encoded; 167 | this.#setStatus( 168 | '#d07010', 169 | 'Assembling pass ' + this.passNo, 170 | 'line number ' + (this.asmLineNo + 1), 171 | this.asmText, 172 | ); 173 | if ((this.asmLineNo < this.asmProgram.length) && (!this.ended)) { 174 | encoded = this.asmLine(this.asmProgram[this.asmLineNo], true); 175 | this.asmLineNo++; 176 | if (!this.foundError) { 177 | if (encoded.length > 0) { 178 | trc('Assemble @ ', inHex(this.pcVal, 4)); 179 | if (this.pcVal != null) { 180 | this.pcVal = this.ram.fill(this.pcVal, encoded); 181 | this.codeBlocks [this.codeBlocks.length - 1].addCode(encoded); 182 | } else { 183 | this.#error('No value set for origin', 0); 184 | } 185 | } 186 | } 187 | } else { 188 | clearInterval(this.asmIntervalID); 189 | this.asmIntervalID = null; 190 | if (this.passNo < this.passes) { 191 | this.#asmInit(this.passNo + 1); 192 | } else { 193 | this.asmFinalise(); 194 | } 195 | } 196 | } 197 | 198 | /** 199 | * Find value of label. 200 | * 201 | * @param {string} asmLabel 202 | * @return {number} 203 | */ 204 | #findLabel(asmLabel) { 205 | const matches = /\s*([a-z_][\w_]*)/i.exec(asmLabel); 206 | if (matches !== null ) { 207 | const key = matches[1].toUpperCase(); 208 | if (key in this.labels) { 209 | trc('Found label \'' + key + '\' of value', inHex(this.labels[key], 4)); 210 | return this.labels[key]; 211 | } 212 | } 213 | }; 214 | 215 | /** 216 | * Assign value to label. 217 | * 218 | * @param {string} asmLabel label 219 | * @param {number} operand value 220 | * @return {number} 221 | */ 222 | #assignLabel(asmLabel, operand) { 223 | const key = asmLabel.toUpperCase(); 224 | trc('Assigning label (' + key + ') with', inHex(operand, 4)); 225 | if ((this.#findLabel(key) != null) && (this.passNo === 1)) { 226 | this.#error('Attempt to redefine label', key); 227 | return 0; 228 | } else { 229 | this.labels[key] = operand; 230 | return 1; 231 | } 232 | }; 233 | 234 | /** 235 | * Identify op code. 236 | * 237 | * @param {number} opcode operator byte 238 | * @param {string} page 239 | * @return {Object} instruction 240 | */ 241 | opFind(opcode, page) { 242 | const opPage = parseInt(page); 243 | const instruction = ops6809.find(function(element) { 244 | return (element.op === opcode) && (element.page === opPage); 245 | }); 246 | if (instruction) { 247 | return instruction; 248 | } else { 249 | const errorCode = inHex((opPage * 256) + opcode); 250 | trc('OpFind failed for ', errorCode); 251 | } 252 | }; 253 | 254 | /** 255 | * Identify mnemonic. 256 | * 257 | * @param {string} mnemonic source code mnemonic 258 | * @param {number} mode 259 | * @return {Object} instruction 260 | */ 261 | #mnemonicFind(mnemonic, mode) { 262 | const instruction = ops6809.find((element) => { 263 | return (element.mnem === mnemonic) && ((element.mode & mode) !== 0); 264 | }); 265 | if (instruction !== null) { 266 | return instruction; 267 | } else { 268 | trc('MnemonicFind failed for', mnemonic); 269 | } 270 | }; 271 | 272 | /** 273 | * Parse and extract label, and assign value. 274 | * 275 | * @param {string} asmLabel label 276 | * @param {number} value value 277 | * @param {boolean} leadingSpace 278 | * @return {(string|string)[]} 279 | */ 280 | #readLabel(asmLabel, value, leadingSpace) { 281 | let matches; let key; 282 | trc('ReadLabel', asmLabel); 283 | trc('leadingSpace', leadingSpace); 284 | matches = /^\s*([a-z_][\w_]*):\s*(.*)/i.exec(asmLabel); 285 | if (matches !== null) { 286 | key = matches[1].toUpperCase(); 287 | trc('readLabel key', key); 288 | this.#assignLabel(key, value); 289 | return [matches[2], key]; 290 | } 291 | matches = /^([a-z_][\w_]*)\s*(.*)/i.exec(asmLabel); 292 | if ((!leadingSpace) && (matches !== null)) { 293 | key = matches[1].toUpperCase(); 294 | if (!this.#mnemonicFind(key, 0xffff)) { 295 | this.#assignLabel(key, value); 296 | return [matches[2], key]; 297 | } 298 | } 299 | return [asmLabel, '']; 300 | }; 301 | 302 | /** 303 | * Find next value in expression. 304 | * 305 | * @param {string} expressionIn 306 | * @param {boolean} needsValue 307 | * @return {number|null} 308 | */ 309 | #nextVal(expressionIn, needsValue) { 310 | let matches; let value; let valueNum; let minus; let radix; 311 | let total = 0; 312 | let valid = false; 313 | const matchValue = /^\s*(('(.))|(-|\+|)(\$|%|0x|)([\w_]+))/i; 314 | let expression = String(expressionIn); 315 | trc('nextVal input', expression); 316 | while (matches = matchValue.exec(expression)) { 317 | minus = 0; 318 | radix = 10; 319 | if (matches[3]) { 320 | trc('matches[3]', matches[3]); 321 | valueNum = matches[3].charCodeAt(0); 322 | } else { 323 | value = matches[6].toUpperCase(); 324 | trc('nextVal item', value); 325 | trc('nextVal radix', matches[5]); 326 | trc('matches[5] "' + matches[5] + '" ', matches[5].charCodeAt(0)); 327 | if (matches[4] === '-') { 328 | minus = 1; 329 | } 330 | if ((matches[5] === '$') || (matches[5].toUpperCase() === '0X')) { 331 | radix = 16; 332 | } 333 | if (matches[5] === '%') { 334 | radix = 2; 335 | } 336 | if ((radix <= 10) && value.match(/^[A-Z_]/)) { 337 | trc('FindLabel value', value); 338 | valueNum = this.#findLabel(value); 339 | if (valueNum == null) { 340 | if ((this.passNo > 1) || (needsValue)) { 341 | this.#error('Unable to resolve label'); 342 | return null; 343 | } else { 344 | trc('Label not yet defined', value); 345 | return null; 346 | } 347 | } 348 | } else { 349 | trc('Radix', radix); 350 | valueNum = parseInt(value, radix); 351 | } 352 | } 353 | if (!isNaN(valueNum)) { 354 | if (minus) { 355 | valueNum = -valueNum; 356 | } 357 | } else { 358 | this.#error('Can\'t read numeric value', valueNum); 359 | return null; 360 | } 361 | total = total + valueNum; 362 | valid = true; 363 | trc('Total', inHex(total, 4)); 364 | trc('Increment', inHex(valueNum, 4)); 365 | trc('Expression', expression); 366 | expression = expression.substring(matches[0].length); 367 | } 368 | if ((total < -32768) || (total >= 0x10000)) { 369 | this.#error('Constant out of range (' + total + ')', expressionIn); 370 | } 371 | if (valid) { 372 | return total; 373 | } else { 374 | this.#error('Unable to interpret expression\'' + expression + '\''); 375 | } 376 | }; 377 | 378 | /** 379 | * Strip comments from code. 380 | * 381 | * @param {string} text raw source code line 382 | * @return {string} cleaned source code 383 | */ 384 | #parseOutComments(text) { 385 | let trimmed = ''; 386 | let inQuotes = null; 387 | let lastSpace = true; 388 | for (let i = 0; i < text.length; i++) { 389 | const c = text.charAt(i); 390 | // if ((c=="'") || (c=='"')) { 391 | if (c === '"') { 392 | if (inQuotes === c) { 393 | inQuotes = null; 394 | } else { 395 | if (inQuotes == null) { 396 | inQuotes = c; 397 | } 398 | } 399 | } 400 | if ( 401 | ((c === ';') || (c === '*')) && 402 | (inQuotes === null) && 403 | (lastSpace === true) 404 | ) { 405 | i = text.length; 406 | } else { 407 | lastSpace = ((c === ' ') || (c === '\t')); 408 | if ((!lastSpace) || (trimmed.length > 0)) { 409 | trimmed += c; 410 | } 411 | } 412 | } 413 | return trimmed.replace(/\s+$/, ''); 414 | }; 415 | 416 | /** 417 | * Encode operator. 418 | * 419 | * @param {number[]} encoding byte code sequence reference 420 | * @param {Object} instruction operator instruction 421 | */ 422 | #encodeOp(encoding, instruction) { 423 | if (instruction.page) { 424 | encoding.push(instruction.page); 425 | } 426 | encoding.push(instruction.op); 427 | }; 428 | 429 | /** 430 | * Encode numeric data. 431 | * 432 | * @param {number[]} encoding byte code sequence reference 433 | * @param {number} value data value 434 | * @param {number} bits expected data size 435 | */ 436 | #encodeValue(encoding, value, bits) { 437 | let n; 438 | trc('Encode value initial', value); 439 | if (value) { 440 | n = this.#nextVal(String(value), false); 441 | } else { 442 | n = 0; 443 | } 444 | trc('Encode value', n); 445 | trc('Encode bits', bits); 446 | if (bits > 8) { 447 | if (n < 0) { 448 | n += 0x10000; 449 | } 450 | if ((n >= 0) && (n < 0x10000)) { 451 | encoding.push(n >>> 8); 452 | encoding.push(n & 0xff); 453 | } else { 454 | this.#error('Value (16 bits) expected', value); 455 | } 456 | } else if (bits > 0) { 457 | if (n < 0) { 458 | n += 0x100; 459 | } 460 | if ((n >= 0) && (n < 0x100)) { 461 | encoding.push(n); 462 | } else { 463 | this.#error('Value (8 bits) expected', value); 464 | } 465 | } 466 | }; 467 | 468 | /** 469 | * Encode string value. 470 | * 471 | * @param {number[]} encoding byte code sequence reference 472 | * @param {string} s source string 473 | */ 474 | #encodeString(encoding, s) { 475 | for (let i = 0; i < s.length; i++) { 476 | const c = s.charCodeAt(i); 477 | trc('String character', inHex(c, 2)); 478 | if (c < 0x100) { 479 | encoding.push(c); 480 | } 481 | } 482 | }; 483 | 484 | /** 485 | * Encode mixed numeric and string data. 486 | * 487 | * @param {number[]} encoding byte code sequence reference 488 | * @param {string[]} items data items 489 | * @param {number} bits allowed data size 490 | */ 491 | #encodeData(encoding, items, bits) { 492 | let matches = 0; 493 | for (let i = 0; i < items.length; i++) { 494 | const item = items[i]; 495 | trc('Encode data', item); 496 | matches = /\s*"(.*)"/.exec(item); 497 | if (matches === null) { 498 | trc('Try to match single quotes', item); 499 | matches = /\s*'(.*)'/.exec(item); 500 | } 501 | if (matches !== null) { 502 | this.#encodeString(encoding, matches[1]); 503 | } else { 504 | if (item.startsWith("$")) { 505 | const hex = item.replace("$","0x"); 506 | this.#encodeValue(encoding, parseInt(hex), bits); 507 | } else { 508 | this.#encodeValue(encoding, parseInt(item), bits); 509 | } 510 | } 511 | } 512 | }; 513 | 514 | /** 515 | * Set new code base address. 516 | * 517 | * @param {number} baseAddress 518 | */ 519 | newOrg(baseAddress) { 520 | trc('newOrg', inHex(baseAddress, 4)); 521 | this.pcVal = baseAddress; 522 | this.codeBlocks.push(new CodeBlock(baseAddress)); 523 | }; 524 | 525 | /** 526 | * Safely split numeric and string mixed data by comma. 527 | * 528 | * @param {string} text raw text 529 | * @return {string[]} separated text 530 | */ 531 | splitByComma(text) { 532 | let item; 533 | const items = []; 534 | let textList = text; 535 | trc('splitByComma', text); 536 | while (textList.length > 0) { 537 | item = ''; 538 | let matches = /^("(?:[^"\\]|\\.)*")|^('(?:[^'\\]|\\.)*)'/.exec(textList); 539 | if (matches !== null) { 540 | item = matches[0]; 541 | } else { 542 | matches = /^([^,]*)/.exec(textList); 543 | if (matches) { 544 | item = matches[1]; 545 | } 546 | } 547 | if (item === '') { 548 | textList = ''; 549 | } else { 550 | items.push(item); 551 | trc('item', item); 552 | textList = textList.substring(item.length).replace(/^\s*,/, ''); 553 | } 554 | } 555 | return items; 556 | }; 557 | 558 | /** 559 | * Set direct page value. 560 | * 561 | * @param {number} operand new dp value 562 | */ 563 | #setDp(operand) { 564 | const value = this.#nextVal(String(operand), true); 565 | if ((value >= 0) && (value < 0x100)) { 566 | this.dpVal = value; 567 | this.dpUse = true; 568 | } else { 569 | if (value < 0) { 570 | this.dpVal = 0; 571 | this.dpUse = false; 572 | } else { 573 | this.#error('Direct page value must be 8 bits'); 574 | } 575 | } 576 | }; 577 | 578 | /** 579 | * Fill memory with n copies of static data value. 580 | * 581 | * @param {number[]} encoding byte code sequence reference 582 | * @param {string[]} items [value, count] 583 | */ 584 | #fillData(encoding, items) { 585 | let filler; 586 | if (items.length === 2) { 587 | filler = this.#nextVal(items[0], false); 588 | const count = this.#nextVal(items[1], true); 589 | if (filler == null) { 590 | return; 591 | } 592 | if (filler < 0) { 593 | filler += 0x100; 594 | } 595 | if ((filler >= 0) && (filler < 0x100)) { 596 | if ((count > 0) && (count < 0x10000)) { 597 | trc('filling ' + count + ' bytes with value', filler); 598 | for (let i = 0; i < count; i++) { 599 | encoding.push(filler); 600 | } 601 | } else { 602 | this.#error('Value for fill count out of range'); 603 | } 604 | } else { 605 | this.#error('Value for data byte out of range'); 606 | } 607 | } else { 608 | this.#error('Directive requires [data byte] and [count] operands'); 609 | } 610 | }; 611 | 612 | /** 613 | * Encode constant assignment. 614 | * 615 | * @param {string[]} items 616 | */ 617 | #encodeConstants(items) { 618 | for (let i = 0; i < items.length; i++) { 619 | const item = items[i]; 620 | const matches = /\s*([A-Z_][\w_]*)\s*=\s*(.+)/i.exec(item); 621 | if (matches != null) { 622 | const labelValue = this.#nextVal(matches[2], true); 623 | if (labelValue) { 624 | this.#assignLabel(matches[1], labelValue); 625 | } else { 626 | this.#assignLabel(matches[1], 0); 627 | } 628 | } else { 629 | this.#error('Unable to interpret constant assignment', item); 630 | } 631 | } 632 | }; 633 | 634 | /** 635 | * Encode variable names as addresses. 636 | * 637 | * @param {string[]} items 638 | */ 639 | #encodeVariables(items) { 640 | let item = items.shift(); 641 | const varSize = this.#nextVal(item, false); 642 | if (varSize != null) { 643 | trc('varSize=', varSize); 644 | while (item = items.shift()) { 645 | const matches = /\s*([A-Z_][\w_]*)/i.exec(item); 646 | if (matches != null ) { 647 | this.#assignLabel(matches[1], this.pcVal); 648 | this.pcVal += varSize; 649 | } else { 650 | this.#error('Invalid label in variable list', item); 651 | } 652 | } 653 | } else { 654 | this.#error('Invalid variable size (usually 1 or 2)', item); 655 | } 656 | this.newOrg(this.pcVal); 657 | }; 658 | 659 | /** 660 | * Encode pseudo-op directive. 661 | * 662 | * @param {number[]} encoding 663 | * @param {Object} instruction 664 | * @param {string} operand 665 | * @param {string} label 666 | */ 667 | #encodeDirective(encoding, instruction, operand, label) { 668 | trc('Encode directive name', instruction.mnem); 669 | trc('Encode directive operand', operand); 670 | switch (instruction.mnem) { 671 | case 'DB': 672 | case '.BYTE': 673 | case 'FCB': 674 | case 'FCC': 675 | this.#encodeData(encoding, this.splitByComma(operand), 8); 676 | break; 677 | case 'DW': 678 | case '.WORD': 679 | case 'FDB': 680 | this.#encodeData(encoding, operand.split(','), 16); 681 | break; 682 | case 'FILL': 683 | this.#fillData(encoding, operand.split(',')); 684 | break; 685 | case 'ORG': 686 | this.newOrg(this.#nextVal(operand, true)); 687 | break; 688 | case 'DS': 689 | case 'RMB': 690 | this.newOrg(this.pcVal + this.#nextVal(operand, true)); 691 | break; 692 | case 'SETDP': 693 | case 'DIRECT': 694 | this.#setDp(parseInt(operand)); 695 | break; 696 | case '=': 697 | case 'EQU': 698 | if (label) { 699 | this.labels[label] = this.#nextVal(operand, false); 700 | } else { 701 | this.#error('EQU directive must have a label', ''); 702 | } 703 | break; 704 | case 'CONST': 705 | this.#encodeConstants(operand.split(',')); 706 | break; 707 | case 'VAR': 708 | this.#encodeVariables(operand.split(',')); 709 | break; 710 | case 'END': 711 | this.ended = true; 712 | } 713 | }; 714 | 715 | /** 716 | * Calculate offset from PC to target. 717 | * 718 | * @param {number} target target address 719 | * @param {number} bits constrain offset to bits 720 | * @param {number} pcIn base PC value 721 | * @return {number[]} offset 722 | */ 723 | #pcr(target, bits, pcIn) { 724 | trc('this.pcr pcIn', inHex(pcIn, 4)); 725 | const pc = this.ram.wrap(pcIn + ((bits === 8) ? 1 : 2)); 726 | trc('PCR pc value', inHex(pc, 4)); 727 | trc('PCR target', inHex(target, 4)); 728 | trc('PCR bits', bits); 729 | let n = this.#nextVal(String(target), false); 730 | trc('this.pcr nextVal', n); 731 | if (n == null) { 732 | if (bits > 8) { 733 | return [null, 0, 0]; 734 | } else { 735 | return [null, 0]; 736 | } 737 | } 738 | n = n - pc; 739 | if (n < -0x8000) { 740 | n += 0x10000; 741 | } 742 | trc('PCR offset value', inHex(n)); 743 | switch (bits) { 744 | case 7: 745 | case 8: 746 | if (((n < -0x80) || (n >= 0x80)) && (this.passNo > 1)) { 747 | this.#error( 748 | 'PC relative offset (\'' + inHex(target, 4) + '\')' + 749 | ' outside 8 bit range', 750 | n, 751 | ); 752 | } 753 | return [n, n & 0xff]; 754 | case 0: 755 | case 15: 756 | case 16: 757 | if (((n < -0x8000) || (n >= 0x10000)) && (this.passNo > 1)) { 758 | this.#error( 759 | 'PC relative offset (\'' + target + '\') outside 16 bit range', 760 | n, 761 | ); 762 | } 763 | return [n, (n & 0xffff) >>> 8, n & 0xff]; 764 | } 765 | }; 766 | 767 | /** 768 | * Decode indexed operator register pair into postbyte. 769 | * 770 | * @param {string} s source line 771 | * @return {number} operator postbyte 772 | */ 773 | #pairPostByte(s) { 774 | /** 775 | * Convert register name into postbyte nybble value. 776 | * 777 | * @param {string} regText register 778 | * @return {number} nybble 779 | */ 780 | function getRegister(regText) { 781 | trc('getRegister', regText); 782 | if (regText in pairRegsToValue) { 783 | return pairRegsToValue[regText]; 784 | } 785 | } 786 | trc('pairPostByte', s); 787 | const matches = /(\w+)\s*,\s*(\w+)/.exec(s); 788 | const reg1 = getRegister(matches[1].toUpperCase()); 789 | const reg2 = getRegister(matches[2].toUpperCase()); 790 | if ((reg1 != null) && (reg2 != null)) { 791 | return ((reg1 << 4) | reg2); 792 | } else { 793 | this.#error('Syntax error in register pair postbyte: \'' + s + '\''); 794 | } 795 | }; 796 | 797 | /** 798 | * Decode register list into postbyte for stack push. 799 | * 800 | * @param {string} mnemonic operator mnemonic 801 | * @param {string} registerString comma separated list of registers 802 | * @return {number} operator postbyte 803 | */ 804 | #fullPostByte(mnemonic, registerString) { 805 | let postByte = 0; 806 | const thisStack = mnemonic[mnemonic.length - 1].toUpperCase(); 807 | const regList = registerString.split(','); 808 | trc('fullPostByte thisStack', thisStack); 809 | for (let i = 0; i < regList.length; i++) { 810 | const reg = regList[i].trim().toUpperCase(); 811 | trc('fullPostByte register', reg); 812 | if (reg in fullRegsToValue) { 813 | if (reg === thisStack) { 814 | this.#error('Can\'t stack register on its own stack', reg); 815 | } else { 816 | postByte |= fullRegsToValue[reg]; 817 | } 818 | } else { 819 | if (reg.match(/\w/)) { 820 | this.#error('Unknown register', reg); 821 | } 822 | } 823 | } 824 | return postByte; 825 | }; 826 | 827 | /** 828 | * Add label to registry. 829 | * 830 | * @param {string} asmLabel label name 831 | * @param {number} value label address 832 | */ 833 | #addMapLabel(asmLabel, value) { 834 | trc('Setting map label \'' + asmLabel + '\' with value', value); 835 | this.mapLabels[asmLabel] = value; 836 | this.mapAddrs[inHex(value, 4)] = asmLabel; 837 | }; 838 | 839 | /** 840 | * Calculate number of bits needed for an indexed operation. 841 | * 842 | * @param {number} n indexed offset 843 | * @return {number} bits required 844 | */ 845 | #opSize(n) { 846 | let bits = 7; 847 | if (n < -0x80) { 848 | bits = 15; 849 | if (n < -0x8000) { 850 | bits = 32; 851 | } 852 | } else { 853 | if (n >= 0x80) { 854 | bits = 8; 855 | if (n >= 0x100) { 856 | bits = 15; 857 | if (n >= 0x8000) { 858 | bits = 16; 859 | if (n >= 0x10000) { 860 | bits = 32; 861 | } 862 | } 863 | } 864 | } 865 | } 866 | return bits; 867 | }; 868 | 869 | /** 870 | * Get Index Mode. 871 | * 872 | * @param {string} s source 873 | * @return {(number)[]} [index, increment] 874 | */ 875 | #getIndexMode(s) { 876 | // determine index register and autoincrement, return index=-1 if error; 877 | let index = -1; 878 | let increment = 0; 879 | trc('getIndexMode', s); 880 | const matches = /\s*(-{0,2})([A-Za-z]{1,3})(\+{0,2})/.exec(s.toUpperCase()); 881 | if (matches) { 882 | trc('Index mode match', matches[2]); 883 | switch (matches[2]) { 884 | case 'X': 885 | index = 0x00; 886 | break; 887 | case 'Y': 888 | index = 0x20; 889 | break; 890 | case 'U': 891 | index = 0x40; 892 | break; 893 | case 'S': 894 | index = 0x60; 895 | break; 896 | case 'PC': 897 | index = 0x8C; 898 | break; 899 | case 'PCR': 900 | index = 0x8D; 901 | break; 902 | default: 903 | this.#error('Unrecognised index register', matches[2]); 904 | } 905 | trc('index postbyte', inHex(index, 2)); 906 | trc('Postincrement', matches[3]); 907 | switch (matches[3]) { 908 | case '+': 909 | increment = 0x80; 910 | break; 911 | case '++': 912 | increment = 0x81; 913 | break; 914 | } 915 | trc('Predecrement', matches[1]); 916 | if (matches[1]) { 917 | if (increment > 0) { 918 | index = -1; 919 | this.#error( 920 | 'Index mode error: Can\'t have increment ' + 921 | 'and decrement at the same time', 922 | s, 923 | ); 924 | } else { 925 | switch (matches[1]) { 926 | case '-': 927 | increment = 0x82; 928 | break; 929 | case '--': 930 | increment = 0x83; 931 | break; 932 | } 933 | } 934 | } 935 | } else { 936 | this.#error('Syntax error in index register expression', s); 937 | } 938 | return [index, increment]; 939 | }; 940 | 941 | /** 942 | * Parse Sized Value. 943 | * 944 | * @param {string} s source 945 | * @param {boolean} noError 946 | * @param {number} dp direct page 947 | * @param {boolean} useDp 948 | * @return {(number|number)[]} 949 | */ 950 | parseSizedVal(s, noError, dp, useDp) { 951 | let value; 952 | let bits = 0; 953 | trc('ParseSizedVal', s); 954 | const matches = /\s*([<>])(.+)/.exec(s); 955 | if (matches) { 956 | trc('SizedVal match', matches[1]); 957 | switch (matches[1]) { 958 | case '<': 959 | bits = 8; 960 | break; 961 | case '>': 962 | bits = 16; 963 | break; 964 | } 965 | value = this.#nextVal(matches[2], false); 966 | } else { 967 | value = this.#nextVal(s, false); 968 | } 969 | if (value != null) { 970 | switch (bits) { 971 | case 16: 972 | if (((value < -32768) || (value >= 65536)) && (!noError)) { 973 | this.#error('Constant out of 16 bit range', value); 974 | } 975 | break; 976 | case 8: 977 | if (useDp) { 978 | value = (value - (dp << 8) & 0xffff); 979 | } 980 | if (((value < -128) || (value >= 256)) && (!noError)) { 981 | this.#error('Constant out of 8 bit range', value); 982 | } 983 | break; 984 | } 985 | } 986 | return [value, bits]; 987 | }; 988 | 989 | /** 990 | * 991 | * @param {number} opMode operator mode 992 | * @param {string} s source 993 | * @param {number} pcrVal program counter value 994 | * @return {number[]} [mode, value, bits, postByte] 995 | */ 996 | #adrMode(opMode, s, pcrVal) { 997 | let matches; let bits; let forceBits; let value; let mode; let indirect; 998 | let indexMode; let increment; let postByte; let offset; let values; 999 | let signedValue; 1000 | let withDPValue; 1001 | indirect = 0; 1002 | postByte = -1; 1003 | let hasValue = false; 1004 | value = 0; 1005 | bits = 0; 1006 | forceBits = 0; 1007 | matches = /\s*#\s*(.+)/.exec(s); 1008 | if (matches != null) { 1009 | value = this.#nextVal(matches[1], false); 1010 | bits = (opMode & modes.bits16) !== 0 ? 16 : 8; 1011 | mode = modes.immediate; 1012 | } else { 1013 | matches = /\s*[(\[]\s*(.+?)[)\]]\s*/.exec(s); 1014 | if (matches != null) { 1015 | trc('Indirect addressing', matches[1]); 1016 | s = matches[1]; 1017 | indirect = 1; 1018 | } 1019 | matches = /\s*(\S*?)\s*,\s*(\S+)/.exec(s); 1020 | if (matches != null) { 1021 | offset = matches[1].toUpperCase(); 1022 | trc('Indexed addressing', matches[2]); 1023 | trc('Offset', offset); 1024 | mode = modes.indexed; 1025 | [indexMode, increment] = this.#getIndexMode(matches[2]); 1026 | if (offset) { 1027 | matches = /^([BAD])$/.exec(offset); 1028 | if (matches != null) { 1029 | trc('Register offset', matches[1]); 1030 | indexMode |= {'B': 0x05, 'A': 0x06, 'D': 0x0B}[matches[1]] | 0x80; 1031 | } else { 1032 | trc('Constant offset', inHex(offset, 4)); 1033 | [value, forceBits] = 1034 | this.parseSizedVal(offset, true, 0, false); 1035 | hasValue = true; 1036 | trc('forceBits=' + forceBits, value); 1037 | } 1038 | } 1039 | trc('indexMode', indexMode); 1040 | trc('increment', increment); 1041 | postByte = indexMode | increment; 1042 | if (increment) { 1043 | if ((hasValue) && (value !== 0)) { 1044 | this.#error( 1045 | 'Indexing error: can\'t have offset with auto inc/decrement', 1046 | value, 1047 | ); 1048 | } 1049 | } else { 1050 | trc('non-autoincrement mode postByte', inHex(postByte, 2)); 1051 | if ((indexMode < 0x80) && (value === 0)) { 1052 | postByte = postByte | 0x84; 1053 | } else if (hasValue) { 1054 | trc('Indexed constant offset', value); 1055 | if (indexMode === 0x8D) { 1056 | // force 16 bit offset for PCR references unless 8 bit specified 1057 | if (forceBits === 0) { 1058 | forceBits = 16; 1059 | } 1060 | if (value === null) { 1061 | value = 0; 1062 | } 1063 | values = this.#pcr(value, forceBits, pcrVal); 1064 | signedValue = values[0]; 1065 | value = values[1]; 1066 | if (values.length === 3) { 1067 | value = (value << 8) | values[2]; 1068 | } 1069 | indexMode = 0x8C; 1070 | postByte = indexMode; 1071 | } else { 1072 | signedValue = value; 1073 | } 1074 | if ( 1075 | ((value >= -16) && (value < 16)) && 1076 | (indexMode < 0x80) && (!indirect) 1077 | ) { 1078 | postByte = postByte | (value & 0x1f); 1079 | trc('5 bit indexed postByte', postByte); 1080 | } else { 1081 | // choose between extended and PCR 1082 | postByte = postByte | ((indexMode < 0x80) ? 0x88 : 0x8C); 1083 | trc('PCR signed value', signedValue); 1084 | bits = this.#opSize(signedValue); 1085 | trc('PCR opSize bits', bits); 1086 | if (forceBits > 0) { 1087 | trc('Deal with forceBits', forceBits); 1088 | if ((this.passNo > 1) && (bits + 1 > forceBits)) { 1089 | this.#error( 1090 | 'Constant offset out of ' + forceBits + ' bit range', 1091 | signedValue, 1092 | ); 1093 | } 1094 | bits = forceBits - 1; 1095 | } 1096 | if (bits > 7) { 1097 | postByte = postByte | 0x01; 1098 | bits = 16; 1099 | } 1100 | trc(bits + ' bit indexed postByte', inHex(postByte, 2)); 1101 | } 1102 | } 1103 | } 1104 | if (indirect) { 1105 | postByte |= 0x10; 1106 | } 1107 | } else { 1108 | [value, forceBits] = 1109 | this.parseSizedVal(s, false, this.dpVal, this.dpUse); 1110 | trc('Extended or indirect mode', value); 1111 | bits = this.#opSize(value); 1112 | if ((forceBits === 8) && (indirect === 0)) { 1113 | mode = modes.direct; 1114 | trc('Direct mode bit size', bits); 1115 | if ((bits > 8) || (value < 0)) { 1116 | this.#error( 1117 | 'Direct mode address ($' + inHex(value, 4) + ') out of range', 1118 | value, 1119 | ); 1120 | } 1121 | } else { 1122 | if (indirect) { 1123 | postByte = 0x9F; 1124 | mode = modes.indexed; 1125 | } else { 1126 | withDPValue = (value - (this.dpVal << 8) & 0xffff); 1127 | trc('withDP', inHex(withDPValue, 4)); 1128 | if ((this.dpUse) && (value != null) && 1129 | (withDPValue < 0x100) && (forceBits !== 16)) { 1130 | trc('Using DP', value); 1131 | value = withDPValue; 1132 | bits = 8; 1133 | mode = modes.direct; 1134 | } else { 1135 | mode = modes.extended; 1136 | bits = 16; 1137 | } 1138 | } 1139 | if (value < 0) { 1140 | this.#error( 1141 | 'Extended mode requires a 16 bit unsigned value ', 1142 | value, 1143 | ); 1144 | } 1145 | } 1146 | } 1147 | } 1148 | return [mode, value, bits, postByte]; 1149 | }; 1150 | 1151 | /** 1152 | * Assemble next line of source code. 1153 | * 1154 | * @param {string} s source code 1155 | * @param {boolean} allowLabel 1156 | * @return {number[]} encoded bytes 1157 | */ 1158 | asmLine(s, allowLabel) { 1159 | let encoded = []; 1160 | let opLabel = ''; 1161 | let instruction; let mode; let operand; let value; 1162 | let bits; let postByte; let offsetValues; 1163 | this.asmText = this.#parseOutComments(s); 1164 | if (allowLabel) { 1165 | [this.asmText, opLabel] = 1166 | this.#readLabel(this.asmText, this.pcVal, /^\s+/.test(s)); 1167 | if (opLabel) { 1168 | this.lastLabel = opLabel; 1169 | } 1170 | } 1171 | this.asmText = this.asmText.replace(/^\s*/, ''); 1172 | trc('asmText', this.asmText); 1173 | const matches = /\s*([a-zA-Z=.]\w*)($|\s*(.+))/.exec(this.asmText); 1174 | if (matches !== null) { 1175 | const mnemonic = matches[1]; 1176 | trc('asmLine match:', mnemonic); 1177 | instruction = this.#mnemonicFind(mnemonic.toUpperCase(), 0xffff); 1178 | if (instruction !== null) { 1179 | trc('Opcode:', inHex(instruction.op, 2)); 1180 | mode = instruction.mode; 1181 | operand = matches[3]; 1182 | if ((mode & modes.simple) !== 0) { 1183 | if (operand) { 1184 | this.#error('Junk after instruction: \'' + operand + '\''); 1185 | } else { 1186 | this.#encodeOp(encoded, instruction); 1187 | } 1188 | } else if ((mode & modes.pseudo) !== 0) { 1189 | this.#encodeDirective(encoded, instruction, operand, opLabel); 1190 | } else if ((mode & modes.simple) === 0) { 1191 | trc('Memory mode', mode); 1192 | trc('modes.register', modes.register); 1193 | if ((mode & modes.pcr) !== 0) { 1194 | this.#encodeOp(encoded, instruction); 1195 | // console.dir (instruction); 1196 | trc('ASM mode pcr instruction length', encoded.length); 1197 | offsetValues = this.#pcr( 1198 | operand, 1199 | (mode & modes.bits16) !== 0 ? 16 : 8, 1200 | this.pcVal + encoded.length, 1201 | ); 1202 | offsetValues.shift(); 1203 | encoded = encoded.concat(offsetValues); 1204 | } else if ((mode & modes.register) !== 0) { 1205 | trc('Modes register', ''); 1206 | if ((mode & modes.pair) !== 0) { 1207 | postByte = this.#pairPostByte(operand); 1208 | } else { 1209 | postByte = this.#fullPostByte(mnemonic, operand); 1210 | } 1211 | if (postByte !== null) { 1212 | trc('Postbyte value', postByte); 1213 | this.#encodeOp(encoded, instruction); 1214 | encoded.push(postByte); 1215 | } 1216 | } else { 1217 | trc('this pcVal', inHex(this.pcVal)); 1218 | [mode, value, bits, postByte] = this.#adrMode( 1219 | instruction.mode, 1220 | operand, 1221 | this.pcVal + (instruction.page ? 3 : 2), 1222 | ); 1223 | trc('Mem mode', mode); 1224 | trc('postByte', inHex(postByte, 2)); 1225 | instruction = this.#mnemonicFind(mnemonic.toUpperCase(), mode); 1226 | if (instruction !== null) { 1227 | trc('mnemonicFind Bits', bits); 1228 | if ( 1229 | ((instruction.mode & modes.immediate) !== 0) && 1230 | (bits > 8) && 1231 | ((instruction.mode & modes.bits16) === 0) 1232 | ) { 1233 | this.#error('16 bit value found where 8 bit expected: \'' + 1234 | value + '\''); 1235 | } else { 1236 | this.#encodeOp(encoded, instruction); 1237 | if (postByte >= 0) { 1238 | encoded.push(postByte); 1239 | } 1240 | this.#encodeValue(encoded, value, bits); 1241 | } 1242 | } else { 1243 | this.#error(modesText[mode] + 1244 | ' addressing mode not allowed with instruction'); 1245 | } 1246 | } 1247 | } 1248 | } else { 1249 | this.#error('Unknown instruction', mnemonic); 1250 | } 1251 | } 1252 | if ( 1253 | (this.lastLabel) && (encoded.length > 0) && 1254 | ((mode & modes.pseudo) === 0) 1255 | ) { 1256 | this.#addMapLabel(this.lastLabel, this.pcVal); 1257 | this.lastLabel = ''; 1258 | } 1259 | return encoded; 1260 | } 1261 | 1262 | /** 1263 | * Generate info level status message. 1264 | * 1265 | * @param {string} statusColour 1266 | * @param {string} alert 1267 | * @param {string} message 1268 | * @param {string} source 1269 | */ 1270 | #setStatus(statusColour, alert, message, source) { 1271 | let HTML; 1272 | let sourceText = source; 1273 | if (sourceText) { 1274 | sourceText = sourceText.replace(//g, '>'); 1276 | } 1277 | HTML = '' + 1278 | alert + ' ' + message + ''; 1279 | if (source != null) { 1280 | HTML += '
Input: ' + 1281 | sourceText + ''; 1282 | } 1283 | document.dispatchEvent(new CustomEvent('assemblerEvent', { 1284 | detail: { 1285 | message: HTML, 1286 | }, 1287 | })); 1288 | } 1289 | 1290 | /** 1291 | * Generate error level status message. 1292 | * 1293 | * @param {string} message status message 1294 | * @param {Object=} value 1295 | */ 1296 | #error(message, value = null) { 1297 | const stateMessage = message + (value == null ? '':' ' + value); 1298 | this.foundError = 1; 1299 | this.#setStatus( 1300 | 'red', 1301 | 'Error @ line ' + (this.asmLineNo + 1) + ':', 1302 | stateMessage, 1303 | this.asmText, 1304 | ); 1305 | clearInterval(this.asmIntervalID); 1306 | this.asmIntervalID = null; 1307 | } 1308 | 1309 | /** 1310 | * Convert postbyte list of registers to comma separated string. 1311 | * 1312 | * @param {number} postByte 1313 | * @param {string[]} regList 1314 | * @return {string} 1315 | */ 1316 | #regGroupList = function(postByte, regList) { 1317 | const theseRegs = []; 1318 | for (let i = 0; i < 8; ++i) { 1319 | if ((postByte & (0x01 << i)) !== 0) { 1320 | theseRegs.push(regList[i].substring(3)); 1321 | } 1322 | } 1323 | return theseRegs.join(','); 1324 | }; 1325 | 1326 | /** 1327 | * Convert post byte nybble pairs to register names. 1328 | * 1329 | * @param {number} postByte 1330 | * @param {Object} regList 1331 | * @return {string} 1332 | */ 1333 | #regPairList(postByte, regList) { 1334 | /** 1335 | * Find register name by nybble value. 1336 | * 1337 | * @param {number} regNum 1338 | * @return {string} register names 1339 | */ 1340 | function regName(regNum) { 1341 | if (regNum in regList) { 1342 | return regList[regNum].substring(3); 1343 | } else { 1344 | return 'ERR'; 1345 | } 1346 | } 1347 | 1348 | return regName((postByte & 0xf0) >>> 4) + ',' + regName((postByte & 0x0f)); 1349 | }; 1350 | 1351 | /** 1352 | * Disassemble. 1353 | * 1354 | * @param {number} startAddress 1355 | * @param {number} endAddress 1356 | * @param {number} maxLines 1357 | * @return {string[]} 1358 | */ 1359 | disassemble(startAddress, endAddress, maxLines) { 1360 | let opCode; let opPage; let postByte; let instruction; let disassembly; 1361 | let pc = startAddress; 1362 | const lines = []; 1363 | 1364 | /** 1365 | * Get next byte at PC. 1366 | * 1367 | * @param {Assembler} assembler host CPU 1368 | * @return {number} 1369 | */ 1370 | function nextByte(assembler) { 1371 | let byte; 1372 | [pc, byte] = assembler.ram.read(pc); 1373 | disassembly.bytes.push(byte); 1374 | return byte; 1375 | } 1376 | 1377 | /** 1378 | * Find label associated with next address. 1379 | * 1380 | * @param {Assembler} assembler host CPU 1381 | * @param {boolean} bits16 read 2 bytes when true 1382 | * @param {string} prefix default 1383 | * @return {string} 1384 | */ 1385 | function readWord(assembler, bits16, prefix) { 1386 | let word = nextByte(assembler); 1387 | if (bits16) { 1388 | word = (word << 8) | nextByte(assembler); 1389 | return labelled(assembler.mapAddrs, parseInt(inHex(word, 4)), prefix); 1390 | } else { 1391 | return labelled(assembler.mapAddrs, parseInt(inHex(word, 2)), prefix); 1392 | } 1393 | } 1394 | 1395 | /** 1396 | * Convert indexed post byte details to text. 1397 | * 1398 | * @param {Assembler} assembler 1399 | * @param {number} postByte 1400 | * @return {string} 1401 | */ 1402 | function disIndexed(assembler, postByte) { 1403 | let operand = ''; 1404 | // find index register name 1405 | const indexReg = ['X', 'Y', 'U', 'S'][(postByte & 0x60) >>> 5]; 1406 | // extract 5 bit offset 1407 | if ((postByte & 0x80) === 0) { 1408 | trc('5 bit', ''); 1409 | operand = signedHex(postByte & 0x1f, 5, '$') + ',' + indexReg; 1410 | } else { 1411 | switch (postByte & 0x0f) { 1412 | case 0x00: 1413 | operand = ',' + indexReg + '+'; 1414 | break; 1415 | case 0x01: 1416 | operand = ',' + indexReg + '++'; 1417 | break; 1418 | case 0x02: 1419 | operand = ',' + '-' + indexReg; 1420 | break; 1421 | case 0x03: 1422 | operand = ',' + '--' + indexReg; 1423 | break; 1424 | case 0x04: 1425 | operand = ',' + indexReg; 1426 | break; 1427 | case 0x05: 1428 | operand = 'B,' + indexReg; 1429 | break; 1430 | case 0x06: 1431 | operand = 'A,' + indexReg; 1432 | break; 1433 | case 0x07: 1434 | operand = 'ERR'; 1435 | break; 1436 | case 0x08: 1437 | operand = signedHex( 1438 | parseInt( 1439 | readWord(assembler, modes.bits8, ''), 16), 1440 | 8, '$') + ', ' + indexReg; 1441 | break; 1442 | case 0x09: 1443 | operand = signedHex( 1444 | parseInt( 1445 | readWord(assembler, modes.bits16, ''), 16), 1446 | 16, '$') + ', ' + indexReg; 1447 | break; 1448 | case 0x0A: 1449 | operand = 'ERR'; 1450 | break; 1451 | case 0x0B: 1452 | operand = 'D,' + indexReg; 1453 | break; 1454 | case 0x0C: 1455 | operand = findPCR(assembler, parseInt( 1456 | readWord(assembler, modes.bits8, ''), 1457 | 16), modes.bits8, pc) + ',PCR'; 1458 | break; 1459 | case 0x0D: 1460 | operand = findPCR(assembler, parseInt( 1461 | readWord(assembler, modes.bits16, ''), 1462 | 16), modes.bits16, pc) + ',PCR'; 1463 | break; 1464 | case 0x0E: 1465 | operand = 'ERR'; 1466 | break; 1467 | case 0X0F: 1468 | operand = readWord(assembler, modes.bits16, '$'); 1469 | break; 1470 | } 1471 | if ((postByte & 0x10) !== 0) { 1472 | operand = '[' + operand + ']'; 1473 | } 1474 | } 1475 | return operand; 1476 | } 1477 | 1478 | /** 1479 | * Disassemble code at program counter. 1480 | * 1481 | * @param {Assembler} assembler host CPU 1482 | * @param {number} offset offset from PC 1483 | * @param {boolean} bits16 1484 | * @param {number} pc PC 1485 | * @return {string} List of disassembled instructions 1486 | */ 1487 | function findPCR(assembler, offset, bits16, pc) { 1488 | let d = offset; 1489 | if (!bits16) { 1490 | d |= (offset & 0x80) !== 0 ? 0xff00 : 0; 1491 | } 1492 | return labelled( 1493 | assembler.mapAddrs, parseInt(inHex((pc + d) & 0xffff, 4)), '$'); 1494 | } 1495 | 1496 | /** 1497 | * Identify label associated with address. 1498 | * 1499 | * Attempts to find the label associated with the given (word) address, 1500 | * Returns prefix + address if label is not found 1501 | * @param {string[]} mapAddresses list of labels by address 1502 | * @param {number} word address 1503 | * @param {string} prefix default prefix 1504 | * @return {string} 1505 | */ 1506 | function labelled(mapAddresses, word, prefix) { 1507 | if (word in mapAddresses) { 1508 | return mapAddresses[word]; 1509 | } else { 1510 | return prefix + word; 1511 | } 1512 | } 1513 | 1514 | trc('Disassembling from', inHex(startAddress, 4)); 1515 | trc('PC', inHex(pc, 4)); 1516 | trc('endAddress', inHex(endAddress, 4)); 1517 | trc('maxLines', maxLines); 1518 | while ((pc < endAddress) && (lines.length < maxLines)) { 1519 | opPage = 0; 1520 | instruction = null; 1521 | disassembly = new DisCode(pc); 1522 | opCode = nextByte(this); 1523 | instruction = this.opFind(opCode, opPage); 1524 | if (instruction != null) { 1525 | if ((instruction.mode & modes.pager) !== 0) { 1526 | trc('Pager', opCode); 1527 | opPage = opCode; 1528 | opCode = nextByte(this); 1529 | instruction = this.opFind(opCode, opPage); 1530 | } 1531 | } 1532 | if (instruction) { 1533 | disassembly.operation = instruction.mnem; 1534 | if ((instruction.mode & modes.simple) !== 0) { 1535 | } else if ((instruction.mode & modes.immediate) !== 0) { 1536 | disassembly.operand = '#' + readWord( 1537 | this, (instruction.mode & modes.bits16) !== 0, '$'); 1538 | } else if ((instruction.mode & modes.direct) !== 0) { 1539 | disassembly.operand = '<' + readWord( 1540 | this, modes.bits8, '$'); 1541 | } else if ((instruction.mode & modes.extended) !== 0) { 1542 | disassembly.operand = readWord(this, modes.bits16, '$'); 1543 | } else if ((instruction.mode & modes.indexed) !== 0) { 1544 | disassembly.operand = disIndexed(this, nextByte(this)); 1545 | } else if ((instruction.mode & modes.register) !== 0) { 1546 | postByte = nextByte(this); 1547 | if ((instruction.mode & modes.pair) !== 0) { 1548 | disassembly.operand = this.#regPairList(postByte, pairRegsToText); 1549 | } else { 1550 | disassembly.operand = this.#regGroupList( 1551 | postByte, (disassembly 1552 | .operation[disassembly.operation.length - 1] === 'S' 1553 | ) ? fullRegsToTextS : fullRegsToTextU, 1554 | ); 1555 | } 1556 | } else if ((instruction.mode & modes.pcr) !== 0) { 1557 | disassembly.operand = findPCR( 1558 | this, 1559 | parseInt( 1560 | readWord( 1561 | this, 1562 | (instruction.mode & modes.bits16) !== 0, 1563 | ''), 1564 | 16), 1565 | (instruction.mode & modes.bits16) !== 0, 1566 | pc); 1567 | } 1568 | } else { 1569 | disassembly.operation = 'ERR'; 1570 | } 1571 | lines.push(disassembly); 1572 | } 1573 | return lines; 1574 | }; 1575 | } 1576 | 1577 | /** 1578 | * Disassemble byte code. 1579 | * 1580 | * @param {number} address 1581 | * @constructor 1582 | */ 1583 | function DisCode(address) { 1584 | this.address = address; 1585 | this.label = ''; 1586 | this.bytes = []; 1587 | this.operation = ''; 1588 | this.operand = ''; 1589 | this.maxInstructionLength = 5; 1590 | this.show = function() { 1591 | let s = inHex(this.address, 4) + ': '; 1592 | for (let i = 0; i < this.maxInstructionLength; i++) { 1593 | if (i < this.bytes.length) { 1594 | s += inHex(this.bytes[i], 2) + ' '; 1595 | } else { 1596 | s += ' '; 1597 | } 1598 | } 1599 | return s + this.operation + ' ' + this.operand; 1600 | }; 1601 | } 1602 | --------------------------------------------------------------------------------