├── .gitignore ├── LICENSE ├── Makefile ├── README.md ├── bits.h ├── device.h ├── docs └── MC6809.pdf ├── history ├── ANNOUNCE-0.11.txt ├── ANNOUNCE-0.90.txt ├── ANNOUNCE-0.91.txt └── CVu.doc ├── library.json ├── machdep.c ├── main.cpp ├── mc6809.cpp ├── mc6809.h ├── mc6809in.cpp ├── mc6850.cpp ├── mc6850.h ├── memory.cpp ├── memory.h ├── term.cpp ├── term.h ├── tests ├── tbasic.hex ├── tbasic.s ├── test.s ├── test_main.hex └── test_main.s ├── typedefs.h ├── usim.cpp ├── usim.h └── wiring.h /.gitignore: -------------------------------------------------------------------------------- 1 | machdep 2 | machdep.h 3 | **/*.o 4 | **/*.a 5 | *.bak 6 | *.sublime-workspace 7 | usim 8 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Mozilla Public License, version 2.0 2 | 3 | 1. Definitions 4 | 5 | 1.1. "Contributor" 6 | 7 | means each individual or legal entity that creates, contributes to the 8 | creation of, or owns Covered Software. 9 | 10 | 1.2. "Contributor Version" 11 | 12 | means the combination of the Contributions of others (if any) used by a 13 | Contributor and that particular Contributor's Contribution. 14 | 15 | 1.3. "Contribution" 16 | 17 | means Covered Software of a particular Contributor. 18 | 19 | 1.4. "Covered Software" 20 | 21 | means Source Code Form to which the initial Contributor has attached the 22 | notice in Exhibit A, the Executable Form of such Source Code Form, and 23 | Modifications of such Source Code Form, in each case including portions 24 | thereof. 25 | 26 | 1.5. "Incompatible With Secondary Licenses" 27 | means 28 | 29 | a. that the initial Contributor has attached the notice described in 30 | Exhibit B to the Covered Software; or 31 | 32 | b. that the Covered Software was made available under the terms of 33 | version 1.1 or earlier of the License, but not also under the terms of 34 | a Secondary License. 35 | 36 | 1.6. "Executable Form" 37 | 38 | means any form of the work other than Source Code Form. 39 | 40 | 1.7. "Larger Work" 41 | 42 | means a work that combines Covered Software with other material, in a 43 | separate file or files, that is not Covered Software. 44 | 45 | 1.8. "License" 46 | 47 | means this document. 48 | 49 | 1.9. "Licensable" 50 | 51 | means having the right to grant, to the maximum extent possible, whether 52 | at the time of the initial grant or subsequently, any and all of the 53 | rights conveyed by this License. 54 | 55 | 1.10. "Modifications" 56 | 57 | means any of the following: 58 | 59 | a. any file in Source Code Form that results from an addition to, 60 | deletion from, or modification of the contents of Covered Software; or 61 | 62 | b. any new file in Source Code Form that contains any Covered Software. 63 | 64 | 1.11. "Patent Claims" of a Contributor 65 | 66 | means any patent claim(s), including without limitation, method, 67 | process, and apparatus claims, in any patent Licensable by such 68 | Contributor that would be infringed, but for the grant of the License, 69 | by the making, using, selling, offering for sale, having made, import, 70 | or transfer of either its Contributions or its Contributor Version. 71 | 72 | 1.12. "Secondary License" 73 | 74 | means either the GNU General Public License, Version 2.0, the GNU Lesser 75 | General Public License, Version 2.1, the GNU Affero General Public 76 | License, Version 3.0, or any later versions of those licenses. 77 | 78 | 1.13. "Source Code Form" 79 | 80 | means the form of the work preferred for making modifications. 81 | 82 | 1.14. "You" (or "Your") 83 | 84 | means an individual or a legal entity exercising rights under this 85 | License. For legal entities, "You" includes any entity that controls, is 86 | controlled by, or is under common control with You. For purposes of this 87 | definition, "control" means (a) the power, direct or indirect, to cause 88 | the direction or management of such entity, whether by contract or 89 | otherwise, or (b) ownership of more than fifty percent (50%) of the 90 | outstanding shares or beneficial ownership of such entity. 91 | 92 | 93 | 2. License Grants and Conditions 94 | 95 | 2.1. Grants 96 | 97 | Each Contributor hereby grants You a world-wide, royalty-free, 98 | non-exclusive license: 99 | 100 | a. under intellectual property rights (other than patent or trademark) 101 | Licensable by such Contributor to use, reproduce, make available, 102 | modify, display, perform, distribute, and otherwise exploit its 103 | Contributions, either on an unmodified basis, with Modifications, or 104 | as part of a Larger Work; and 105 | 106 | b. under Patent Claims of such Contributor to make, use, sell, offer for 107 | sale, have made, import, and otherwise transfer either its 108 | Contributions or its Contributor Version. 109 | 110 | 2.2. Effective Date 111 | 112 | The licenses granted in Section 2.1 with respect to any Contribution 113 | become effective for each Contribution on the date the Contributor first 114 | distributes such Contribution. 115 | 116 | 2.3. Limitations on Grant Scope 117 | 118 | The licenses granted in this Section 2 are the only rights granted under 119 | this License. No additional rights or licenses will be implied from the 120 | distribution or licensing of Covered Software under this License. 121 | Notwithstanding Section 2.1(b) above, no patent license is granted by a 122 | Contributor: 123 | 124 | a. for any code that a Contributor has removed from Covered Software; or 125 | 126 | b. for infringements caused by: (i) Your and any other third party's 127 | modifications of Covered Software, or (ii) the combination of its 128 | Contributions with other software (except as part of its Contributor 129 | Version); or 130 | 131 | c. under Patent Claims infringed by Covered Software in the absence of 132 | its Contributions. 133 | 134 | This License does not grant any rights in the trademarks, service marks, 135 | or logos of any Contributor (except as may be necessary to comply with 136 | the notice requirements in Section 3.4). 137 | 138 | 2.4. Subsequent Licenses 139 | 140 | No Contributor makes additional grants as a result of Your choice to 141 | distribute the Covered Software under a subsequent version of this 142 | License (see Section 10.2) or under the terms of a Secondary License (if 143 | permitted under the terms of Section 3.3). 144 | 145 | 2.5. Representation 146 | 147 | Each Contributor represents that the Contributor believes its 148 | Contributions are its original creation(s) or it has sufficient rights to 149 | grant the rights to its Contributions conveyed by this License. 150 | 151 | 2.6. Fair Use 152 | 153 | This License is not intended to limit any rights You have under 154 | applicable copyright doctrines of fair use, fair dealing, or other 155 | equivalents. 156 | 157 | 2.7. Conditions 158 | 159 | Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted in 160 | Section 2.1. 161 | 162 | 163 | 3. Responsibilities 164 | 165 | 3.1. Distribution of Source Form 166 | 167 | All distribution of Covered Software in Source Code Form, including any 168 | Modifications that You create or to which You contribute, must be under 169 | the terms of this License. You must inform recipients that the Source 170 | Code Form of the Covered Software is governed by the terms of this 171 | License, and how they can obtain a copy of this License. You may not 172 | attempt to alter or restrict the recipients' rights in the Source Code 173 | Form. 174 | 175 | 3.2. Distribution of Executable Form 176 | 177 | If You distribute Covered Software in Executable Form then: 178 | 179 | a. such Covered Software must also be made available in Source Code Form, 180 | as described in Section 3.1, and You must inform recipients of the 181 | Executable Form how they can obtain a copy of such Source Code Form by 182 | reasonable means in a timely manner, at a charge no more than the cost 183 | of distribution to the recipient; and 184 | 185 | b. You may distribute such Executable Form under the terms of this 186 | License, or sublicense it under different terms, provided that the 187 | license for the Executable Form does not attempt to limit or alter the 188 | recipients' rights in the Source Code Form under this License. 189 | 190 | 3.3. Distribution of a Larger Work 191 | 192 | You may create and distribute a Larger Work under terms of Your choice, 193 | provided that You also comply with the requirements of this License for 194 | the Covered Software. If the Larger Work is a combination of Covered 195 | Software with a work governed by one or more Secondary Licenses, and the 196 | Covered Software is not Incompatible With Secondary Licenses, this 197 | License permits You to additionally distribute such Covered Software 198 | under the terms of such Secondary License(s), so that the recipient of 199 | the Larger Work may, at their option, further distribute the Covered 200 | Software under the terms of either this License or such Secondary 201 | License(s). 202 | 203 | 3.4. Notices 204 | 205 | You may not remove or alter the substance of any license notices 206 | (including copyright notices, patent notices, disclaimers of warranty, or 207 | limitations of liability) contained within the Source Code Form of the 208 | Covered Software, except that You may alter any license notices to the 209 | extent required to remedy known factual inaccuracies. 210 | 211 | 3.5. Application of Additional Terms 212 | 213 | You may choose to offer, and to charge a fee for, warranty, support, 214 | indemnity or liability obligations to one or more recipients of Covered 215 | Software. However, You may do so only on Your own behalf, and not on 216 | behalf of any Contributor. You must make it absolutely clear that any 217 | such warranty, support, indemnity, or liability obligation is offered by 218 | You alone, and You hereby agree to indemnify every Contributor for any 219 | liability incurred by such Contributor as a result of warranty, support, 220 | indemnity or liability terms You offer. You may include additional 221 | disclaimers of warranty and limitations of liability specific to any 222 | jurisdiction. 223 | 224 | 4. Inability to Comply Due to Statute or Regulation 225 | 226 | If it is impossible for You to comply with any of the terms of this License 227 | with respect to some or all of the Covered Software due to statute, 228 | judicial order, or regulation then You must: (a) comply with the terms of 229 | this License to the maximum extent possible; and (b) describe the 230 | limitations and the code they affect. Such description must be placed in a 231 | text file included with all distributions of the Covered Software under 232 | this License. Except to the extent prohibited by statute or regulation, 233 | such description must be sufficiently detailed for a recipient of ordinary 234 | skill to be able to understand it. 235 | 236 | 5. Termination 237 | 238 | 5.1. The rights granted under this License will terminate automatically if You 239 | fail to comply with any of its terms. However, if You become compliant, 240 | then the rights granted under this License from a particular Contributor 241 | are reinstated (a) provisionally, unless and until such Contributor 242 | explicitly and finally terminates Your grants, and (b) on an ongoing 243 | basis, if such Contributor fails to notify You of the non-compliance by 244 | some reasonable means prior to 60 days after You have come back into 245 | compliance. Moreover, Your grants from a particular Contributor are 246 | reinstated on an ongoing basis if such Contributor notifies You of the 247 | non-compliance by some reasonable means, this is the first time You have 248 | received notice of non-compliance with this License from such 249 | Contributor, and You become compliant prior to 30 days after Your receipt 250 | of the notice. 251 | 252 | 5.2. If You initiate litigation against any entity by asserting a patent 253 | infringement claim (excluding declaratory judgment actions, 254 | counter-claims, and cross-claims) alleging that a Contributor Version 255 | directly or indirectly infringes any patent, then the rights granted to 256 | You by any and all Contributors for the Covered Software under Section 257 | 2.1 of this License shall terminate. 258 | 259 | 5.3. In the event of termination under Sections 5.1 or 5.2 above, all end user 260 | license agreements (excluding distributors and resellers) which have been 261 | validly granted by You or Your distributors under this License prior to 262 | termination shall survive termination. 263 | 264 | 6. Disclaimer of Warranty 265 | 266 | Covered Software is provided under this License on an "as is" basis, 267 | without warranty of any kind, either expressed, implied, or statutory, 268 | including, without limitation, warranties that the Covered Software is free 269 | of defects, merchantable, fit for a particular purpose or non-infringing. 270 | The entire risk as to the quality and performance of the Covered Software 271 | is with You. Should any Covered Software prove defective in any respect, 272 | You (not any Contributor) assume the cost of any necessary servicing, 273 | repair, or correction. This disclaimer of warranty constitutes an essential 274 | part of this License. No use of any Covered Software is authorized under 275 | this License except under this disclaimer. 276 | 277 | 7. Limitation of Liability 278 | 279 | Under no circumstances and under no legal theory, whether tort (including 280 | negligence), contract, or otherwise, shall any Contributor, or anyone who 281 | distributes Covered Software as permitted above, be liable to You for any 282 | direct, indirect, special, incidental, or consequential damages of any 283 | character including, without limitation, damages for lost profits, loss of 284 | goodwill, work stoppage, computer failure or malfunction, or any and all 285 | other commercial damages or losses, even if such party shall have been 286 | informed of the possibility of such damages. This limitation of liability 287 | shall not apply to liability for death or personal injury resulting from 288 | such party's negligence to the extent applicable law prohibits such 289 | limitation. Some jurisdictions do not allow the exclusion or limitation of 290 | incidental or consequential damages, so this exclusion and limitation may 291 | not apply to You. 292 | 293 | 8. Litigation 294 | 295 | Any litigation relating to this License may be brought only in the courts 296 | of a jurisdiction where the defendant maintains its principal place of 297 | business and such litigation shall be governed by laws of that 298 | jurisdiction, without reference to its conflict-of-law provisions. Nothing 299 | in this Section shall prevent a party's ability to bring cross-claims or 300 | counter-claims. 301 | 302 | 9. Miscellaneous 303 | 304 | This License represents the complete agreement concerning the subject 305 | matter hereof. If any provision of this License is held to be 306 | unenforceable, such provision shall be reformed only to the extent 307 | necessary to make it enforceable. Any law or regulation which provides that 308 | the language of a contract shall be construed against the drafter shall not 309 | be used to construe this License against a Contributor. 310 | 311 | 312 | 10. Versions of the License 313 | 314 | 10.1. New Versions 315 | 316 | Mozilla Foundation is the license steward. Except as provided in Section 317 | 10.3, no one other than the license steward has the right to modify or 318 | publish new versions of this License. Each version will be given a 319 | distinguishing version number. 320 | 321 | 10.2. Effect of New Versions 322 | 323 | You may distribute the Covered Software under the terms of the version 324 | of the License under which You originally received the Covered Software, 325 | or under the terms of any subsequent version published by the license 326 | steward. 327 | 328 | 10.3. Modified Versions 329 | 330 | If you create software not governed by this License, and you want to 331 | create a new license for such software, you may create and use a 332 | modified version of this License if you rename the license and remove 333 | any references to the name of the license steward (except to note that 334 | such modified license differs from this License). 335 | 336 | 10.4. Distributing Source Code Form that is Incompatible With Secondary 337 | Licenses If You choose to distribute Source Code Form that is 338 | Incompatible With Secondary Licenses under the terms of this version of 339 | the License, the notice described in Exhibit B of this License must be 340 | attached. 341 | 342 | Exhibit A - Source Code Form License Notice 343 | 344 | This Source Code Form is subject to the 345 | terms of the Mozilla Public License, v. 346 | 2.0. If a copy of the MPL was not 347 | distributed with this file, You can 348 | obtain one at 349 | http://mozilla.org/MPL/2.0/. 350 | 351 | If it is not possible or desirable to put the notice in a particular file, 352 | then You may include the notice in a location (such as a LICENSE file in a 353 | relevant directory) where a recipient would be likely to look for such a 354 | notice. 355 | 356 | You may add additional accurate notices of copyright ownership. 357 | 358 | Exhibit B - "Incompatible With Secondary Licenses" Notice 359 | 360 | This Source Code Form is "Incompatible 361 | With Secondary Licenses", as defined by 362 | the Mozilla Public License, v. 2.0. 363 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | DEBUG = -O3 2 | CXX = g++ --std=c++17 -Wall -Wextra -Werror -flto 3 | CC = gcc --std=c9x -Wall -Werror 4 | CCFLAGS = $(DEBUG) 5 | CPPFLAGS = -D_POSIX_SOURCE -I. -o $(@) 6 | LDFLAGS = -flto 7 | 8 | LIB_SRCS = usim.cpp mc6809.cpp mc6809in.cpp mc6850.cpp memory.cpp 9 | 10 | OBJS = $(LIB_SRCS:.cpp=.o) 11 | BIN = usim 12 | 13 | LIB = libusim.a 14 | 15 | all: $(BIN) 16 | 17 | $(LIB): $(OBJS) # $(LIB)($(OBJS)) 18 | ar crs $(@) $^ 19 | ranlib $(@) 20 | 21 | $(BIN): $(LIB) main.o term.o 22 | $(CXX) $(CCFLAGS) $(LDFLAGS) main.o term.o -L. -lusim -o $(@) 23 | 24 | .SUFFIXES: .cpp 25 | 26 | .cpp.o: 27 | $(CXX) $(CPPFLAGS) $(CCFLAGS) -c $< 28 | 29 | $(OBJS): machdep.h 30 | 31 | machdep: machdep.o 32 | $(CC) -o $(@) $(CCFLAGS) $(LDFLAGS) machdep.o 33 | 34 | machdep.h: machdep 35 | ./machdep $(@) 36 | 37 | clean: 38 | $(RM) machdep.h machdep.o machdep $(BIN) $(OBJS) main.o term.o $(LIB) 39 | 40 | depend: machdep.h 41 | makedepend $(LIB_SRCS) main.cpp term.cpp 42 | 43 | # Manually defined dependencies 44 | 45 | usim.o: usim.h device.h typedefs.h memory.h wiring.h 46 | usim.o: bits.h 47 | mc6809.o: mc6809.h wiring.h usim.h device.h typedefs.h 48 | mc6809.o: memory.h bits.h machdep.h 49 | mc6809in.o: mc6809.h wiring.h usim.h device.h typedefs.h 50 | mc6809in.o: memory.h bits.h machdep.h 51 | mc6850.o: mc6850.h device.h typedefs.h wiring.h bits.h 52 | memory.o: memory.h device.h typedefs.h 53 | main.o: mc6809.h wiring.h usim.h device.h 54 | main.o: typedefs.h memory.h bits.h machdep.h mc6850.h 55 | main.o: term.h 56 | term.o: term.h mc6850.h device.h typedefs.h wiring.h 57 | 58 | # DO NOT DELETE THIS LINE -- make depend depends on it. 59 | 60 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # usim 2 | 3 | An mc6809 emulator written in C++ 4 | 5 | NB: version 0.91 is historic (written 1993 - 1994) and has some serious 6 | known bugs in the handling of some instructions and addressing modes. 7 | Many thanks are due to B. Armstrong and Soren Roug for finding and 8 | resolving those. 9 | 10 | The master branch on the primary Github repository 11 | (https://github.com/raybellis/usim/) now contains fixes for those 12 | issues. 13 | 14 | As of January 2021 (!) support for interrupts has been implemented, and 15 | the code has been refactored so that complete machines are generated 16 | by creating instances of a CPU, memory devices and peripherals and then 17 | "attaching" those to each other. See main.cpp for an example of how 18 | this is done. 19 | -------------------------------------------------------------------------------- /bits.h: -------------------------------------------------------------------------------- 1 | // 2 | // 3 | // bits.h 4 | // 5 | // (C) R.P.Bellis 1993 - 2021 6 | // 7 | // 8 | 9 | #pragma once 10 | 11 | #include "typedefs.h" 12 | 13 | // 8 bit operations 14 | inline bool btst(Byte x, int n) 15 | { 16 | return (x & (1 << n)) ? true : false; 17 | } 18 | 19 | inline void bset(Byte& x, int n) 20 | { 21 | x |= (1 << n); 22 | } 23 | 24 | inline void bclr(Byte& x, int n) 25 | { 26 | x &= ~(1 << n); 27 | } 28 | 29 | // 16 bit operations 30 | inline bool btst(Word x, int n) 31 | { 32 | return (x & (1 << n)) ? true : false; 33 | } 34 | 35 | inline void bset(Word& x, int n) 36 | { 37 | x |= (1 << n); 38 | } 39 | 40 | inline void bclr(Word& x, int n) 41 | { 42 | x &= ~(1 << n); 43 | } 44 | 45 | // 32 bit operations 46 | inline bool btst(DWord x, int n) 47 | { 48 | return (x & (1L << n)) ? true : false; 49 | } 50 | 51 | inline void bset(DWord& x, int n) 52 | { 53 | x |= (1L << n); 54 | } 55 | 56 | inline void bclr(DWord& x, int n) 57 | { 58 | x &= ~(1L << n); 59 | } 60 | 61 | // Bit extend operations 62 | inline Word extend5(Byte x) 63 | { 64 | if (x & 0x10) { 65 | return (Word)x | 0xffe0; 66 | } else { 67 | return (Word)x; 68 | } 69 | } 70 | 71 | inline Word extend8(Byte x) 72 | { 73 | if (x & 0x80) { 74 | return (Word)x | 0xff00; 75 | } else { 76 | return (Word)x; 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /device.h: -------------------------------------------------------------------------------- 1 | // 2 | // 3 | // device.h 4 | // 5 | // (C) R.P.Bellis 2021 6 | // 7 | // 8 | 9 | #pragma once 10 | 11 | #include 12 | #include 13 | #include 14 | #include "typedefs.h" 15 | 16 | /* 17 | * an abstract device that responds to CPU cycle ticks and might be reset 18 | */ 19 | class ActiveDevice { 20 | 21 | public: 22 | virtual void reset() = 0; 23 | virtual void tick(uint8_t cycles) = 0; 24 | 25 | public: 26 | using shared_ptr = std::shared_ptr; 27 | 28 | virtual ~ActiveDevice() {}; 29 | }; 30 | 31 | /* 32 | * an abstract memory mapped device 33 | */ 34 | class MappedDevice { 35 | 36 | public: 37 | virtual Byte read(Word offset) = 0; 38 | virtual void write(Word offset, Byte val) = 0; 39 | 40 | public: 41 | using shared_ptr = std::shared_ptr; 42 | 43 | virtual ~MappedDevice() {}; 44 | }; 45 | 46 | /* 47 | * an abstract class combining the above two features 48 | */ 49 | class ActiveMappedDevice : virtual public ActiveDevice, virtual public MappedDevice { 50 | public: 51 | using shared_ptr = std::shared_ptr; 52 | 53 | virtual ~ActiveMappedDevice() {}; 54 | }; 55 | 56 | /* 57 | * a container for mapping from memory locations to MappedDevices 58 | */ 59 | struct MappedDeviceEntry { 60 | MappedDevice::shared_ptr device; 61 | Word base; 62 | Word mask; 63 | }; 64 | 65 | /* 66 | * a container for ActiveDevices { 67 | */ 68 | struct ActiveDeviceEntry { 69 | ActiveDevice::shared_ptr device; 70 | }; 71 | 72 | typedef std::vector ActiveDevList; 73 | typedef std::vector MappedDevList; 74 | 75 | /* 76 | * template to resolve smart point ambiguity issues 77 | * see https://stackoverflow.com/questions/66032442/ 78 | */ 79 | template struct rank : rank {}; 80 | template<> struct rank<0> {}; 81 | -------------------------------------------------------------------------------- /docs/MC6809.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/raybellis/usim/52c4b2500d78a3300589cb72f94caed52569cba5/docs/MC6809.pdf -------------------------------------------------------------------------------- /history/ANNOUNCE-0.11.txt: -------------------------------------------------------------------------------- 1 | From: rpb@psy.ox.ac.uk (Ray Bellis) 2 | Newsgroups: comp.sys.m6809 3 | Subject: New version of mc6809 simulator available 4 | Message-ID: 5 | Date: 8 Feb 93 16:04:07 GMT 6 | Organization: Dept. of Experimental Psychology, Oxford, England. 7 | Lines: 21 8 | 9 | 10 | I've put a new version (0.11) of my mc6809 simulator on 11 | ftp.cns.ox.ac.uk:/pub/mc6809/usim-0.11.tar.Z 12 | 13 | There are no bug fixes or things like that in there, just 14 | some modifications to the way in which the A, B & D registers 15 | are handled. 16 | 17 | There is also some documentation, which forms the first article 18 | in a possible series describing the implementation in `CVu', 19 | the Journal of the C User's Group (UK) 20 | 21 | Ray. 22 | -- 23 | ------------------------------------------------------------------------------ 24 | R. P. Bellis E-Mail: 25 | Dept. of Experimental Psychology Whois: (RB83) 26 | University of Oxford Tel: +44 865 271419 27 | South Parks Road Fax: +44 865 310447 28 | Oxford OX1 3UD 29 | ------------------------------------------------------------------------------ 30 | -------------------------------------------------------------------------------- /history/ANNOUNCE-0.90.txt: -------------------------------------------------------------------------------- 1 | Newsgroups: comp.sys.m6809 2 | Path: bga.com!news.sprintlink.net!demon!uknet!comlab.ox.ac.uk!newshost!rpb 3 | From: rpb@psy.ox.ac.uk (Ray Bellis) 4 | Subject: Announce: New version of usim (mc6809 simulator) 5 | Message-ID: 6 | Organization: O.U. Dept. of Experimental Psychology 7 | Date: 25 May 1994 13:19:53 GMT 8 | Lines: 39 9 | 10 | Available from URL: 11 | 12 | 13 | or 14 | 15 | 16 | This is a Motorola mc6809 simulator written in C++. 17 | 18 | The processor simulator is implemented as a C++ class and it is 19 | designed to be subclassed to provide virtual I/O devices and status 20 | information. 21 | 22 | The `mc6809' class doesn't provide any status information, but the 23 | derived `mc6809_X' class shows processor status in an X Window. 24 | 25 | The simple `sys' class in main.cc adds a virtual mc6850 UART by 26 | overloading the `read' and `write' methods. 27 | 28 | The previously released version (0.1x) had some serious bugs in the 29 | instruction decoder but this latest version seems to run perfectly. 30 | It successfully runs the Tiny Basic interpreter that was posted 31 | to comp.sys.m6809 a few months ago. 32 | 33 | Please excuse the lack of decent release notes, but I felt that I 34 | needed to make this available but I don't have the time to do much 35 | in the way of packaging. 36 | 37 | Ray. 38 | 39 | 40 | 41 | -- 42 | ------------------------------------------------------------------------------ 43 | R. P. Bellis E-Mail: 44 | Dept. of Experimental Psychology Whois: (RB83) 45 | University of Oxford Tel: +44 865 271419 46 | South Parks Road Fax: +44 865 310447 47 | Oxford OX1 3UD 48 | ------------------------------------------------------------------------------ 49 | 50 | 51 | -------------------------------------------------------------------------------- /history/ANNOUNCE-0.91.txt: -------------------------------------------------------------------------------- 1 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~ 2 | usim-0.91: mc6809 simulator 3 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~ 4 | 5 | This is a Motorola mc6809 simulator written in C++. 6 | 7 | The processor simulator is implemented as a C++ class and it is 8 | designed to be subclassed to provide virtual I/O devices and status 9 | information. 10 | 11 | The `mc6809' class doesn't provide any status information, but the 12 | derived `mc6809_X' class shows processor status in an X Window. 13 | 14 | The simple `sys' class in main.cc adds a virtual mc6850 UART by 15 | overloading the `read' and `write' methods. 16 | 17 | The previously released version (0.1x) had some serious bugs in the 18 | instruction decoder but this latest version seems to run perfectly. 19 | It successfully runs the Tiny Basic interpreter that was posted 20 | to comp.sys.m6809 a few months ago. 21 | 22 | v0.91 adds rudimentary support for running under DOS. To be more 23 | useful a minimal `conio' based terminal emulator needs to be built 24 | into the DOS terminal handling code. 25 | 26 | ------------------------------------------------------------------------------ 27 | R. P. Bellis E-Mail: 28 | Computing Officer 29 | MRC Centre in Brain and Behaviour 30 | Dept. of Experimental Psychology 31 | University of Oxford 32 | South Parks Road Tel: +44 865 271359 33 | Oxford OX1 3UD Fax: +44 865 310447 34 | ------------------------------------------------------------------------------ 35 | -------------------------------------------------------------------------------- /history/CVu.doc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/raybellis/usim/52c4b2500d78a3300589cb72f94caed52569cba5/history/CVu.doc -------------------------------------------------------------------------------- /library.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "usim", 3 | "version": "0.99.0", 4 | "keywords": "emulation, mc6809", 5 | "description": "USim 6809 emulator framework", 6 | "authors": { 7 | "name": "Ray Bellis", 8 | "maintainer": true 9 | }, 10 | "license": "MPL-2.0", 11 | "frameworks": "*", 12 | "platforms": "*", 13 | "repository": { 14 | "type": "git", 15 | "url": "https://github.com/raybellis/usim.git" 16 | }, 17 | "headers": [ 18 | "usim.h", 19 | "mc6809.h", 20 | "mc6850.h" 21 | ], 22 | "build": { 23 | "flags": [ 24 | "-DUSIM_MACHDEP_H", 25 | "-DMACH_BYTE_ORDER_LSB_FIRST", 26 | "-DMACH_BITFIELDS_LSB_FIRST" 27 | ], 28 | "includeDir": ".", 29 | "srcDir": ".", 30 | "srcFilter": [ 31 | "+", 32 | "+", 33 | "+", 34 | "+", 35 | "+" 36 | ] 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /machdep.c: -------------------------------------------------------------------------------- 1 | /* 2 | // machdep.c 3 | // 4 | // Machine dependencies checker 5 | // 6 | // (C) R.P.Bellis 1993 7 | */ 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | void byte_order(FILE *f) 17 | { 18 | union { 19 | struct { 20 | uint8_t field1; 21 | uint8_t field2; 22 | } bytes; 23 | uint16_t value; 24 | } tmp; 25 | 26 | tmp.value = 0; 27 | tmp.bytes.field1 = 1; 28 | 29 | if (tmp.value == 0x0001) { 30 | fprintf(f, "#define MACH_BYTE_ORDER_LSB_FIRST\n"); 31 | } else if (tmp.value == 0x0100) { 32 | fprintf(f, "#define MACH_BYTE_ORDER_MSB_FIRST\n"); 33 | } else { 34 | fprintf(stderr, "cannot determine byte order\n"); 35 | exit(EXIT_FAILURE); 36 | } 37 | } 38 | 39 | void bitfield_order(FILE *f) 40 | { 41 | union { 42 | struct { 43 | unsigned int field1 : 1; 44 | unsigned int dummys : 6; 45 | unsigned int field2 : 1; 46 | } bits; 47 | unsigned int value; 48 | } tmp; 49 | 50 | tmp.value = 0; 51 | tmp.bits.field1 = 1; 52 | 53 | if (tmp.value == 1) { 54 | fprintf(f, "#define MACH_BITFIELDS_LSB_FIRST\n"); 55 | } else { 56 | fprintf(f, "#define MACH_BITFIELDS_MSB_FIRST\n"); 57 | } 58 | } 59 | 60 | int main(int argc, char *argv[]) 61 | { 62 | FILE *f; 63 | char *path; 64 | time_t tp; 65 | 66 | if (argc != 2) { 67 | fprintf(stderr, "usage: machdep \n"); 68 | return EXIT_FAILURE; 69 | } 70 | path = argv[1]; 71 | 72 | /* Open output stream */ 73 | if ((f = fopen(path, "w")) == NULL) { 74 | perror("fopen"); 75 | return EXIT_FAILURE; 76 | } 77 | 78 | /* Add head of output file */ 79 | tp = time(NULL); 80 | fprintf(f, "/*\n"); 81 | fprintf(f, " *\tmachdep.h generated by machdep at %s", ctime(&tp)); 82 | fprintf(f, " */\n\n"); 83 | fprintf(f, "#pragma once\n\n"); 84 | fprintf(f, "#define USIM_MACHDEP_H\n"); 85 | 86 | /* Call the determination functions */ 87 | byte_order(f); 88 | bitfield_order(f); 89 | 90 | /* and clean up */ 91 | fclose(f); 92 | 93 | return EXIT_SUCCESS; 94 | } 95 | -------------------------------------------------------------------------------- /main.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // main.cpp 3 | // 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #include "mc6809.h" 11 | #include "mc6850.h" 12 | #include "term.h" 13 | #include "memory.h" 14 | 15 | int main(int argc, char *argv[]) 16 | { 17 | if (argc != 2) { 18 | fprintf(stderr, "usage: usim \n"); 19 | return EXIT_FAILURE; 20 | } 21 | 22 | (void)signal(SIGINT, SIG_IGN); 23 | 24 | const Word ram_size = 0x8000; 25 | const Word rom_base = 0xe000; 26 | const Word rom_size = 0x10000 - rom_base; 27 | 28 | mc6809 cpu; 29 | Terminal term(cpu); 30 | 31 | auto ram = std::make_shared(ram_size); 32 | auto rom = std::make_shared(rom_size); 33 | auto acia = std::make_shared(term); 34 | 35 | cpu.attach(ram, 0x0000, ~(ram_size - 1)); 36 | cpu.attach(rom, rom_base, ~(rom_size - 1)); 37 | cpu.attach(acia, 0xc000, 0xfffe); 38 | 39 | cpu.FIRQ.bind([&]() { 40 | return acia->IRQ; 41 | }); 42 | 43 | rom->load_intelhex(argv[1], rom_base); 44 | 45 | cpu.reset(); 46 | cpu.run(); 47 | 48 | return EXIT_SUCCESS; 49 | } 50 | -------------------------------------------------------------------------------- /mc6809.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // 3 | // mc6809.cpp 4 | // 5 | // (C) R.P.Bellis 6 | // 7 | 8 | #include "mc6809.h" 9 | #include 10 | #include 11 | 12 | mc6809::mc6809() : a(acc.byte.a), b(acc.byte.b), d(acc.d) 13 | { 14 | } 15 | 16 | mc6809::~mc6809() 17 | { 18 | } 19 | 20 | void mc6809::reset() 21 | { 22 | USim::reset(); 23 | 24 | pc = read_word(0xfffe); 25 | cycles = 0; 26 | dp = 0x00; /* Direct page register = 0x00 */ 27 | d = 0x0000; 28 | x = 0x0000; 29 | y = 0x0000; 30 | cc.all = 0x00; /* Clear all flags */ 31 | cc.bit.i = 1; /* IRQ disabled */ 32 | cc.bit.f = 1; /* FIRQ disabled */ 33 | waiting_sync = false; /* not in SYNC */ 34 | waiting_cwai = false; /* not in CWAI */ 35 | nmi_previous = true; /* no NMI present */ 36 | } 37 | 38 | void mc6809::tick() 39 | { 40 | // handle the attached devices 41 | USim::tick(); 42 | 43 | // get interrupt pin states 44 | bool c_nmi = NMI; 45 | bool c_firq = FIRQ; 46 | bool c_irq = IRQ; 47 | 48 | // check for NMI falling edge 49 | bool nmi_triggered = !c_nmi && nmi_previous; 50 | nmi_previous = c_nmi; 51 | 52 | if (waiting_sync) { 53 | // if NMI or IRQ or FIRQ asserts (flags don't matter) 54 | if (nmi_triggered || !c_firq || !c_irq) { 55 | waiting_sync = false; 56 | } else { 57 | return; 58 | } 59 | } 60 | 61 | // look for external interrupts 62 | if (nmi_triggered) { 63 | do_nmi(); 64 | } else if (!c_firq && !cc.bit.f) { 65 | do_firq(); 66 | } else if (!c_irq && !cc.bit.i) { 67 | do_irq(); 68 | } else if (waiting_cwai) { 69 | return; 70 | } 71 | 72 | // if we got here, then CWAI is no longer in effect 73 | waiting_cwai = false; 74 | 75 | // remember current instruction address 76 | insn_pc = pc; 77 | 78 | // hook 79 | pre_exec(); 80 | 81 | // fetch the next instruction 82 | fetch_instruction(); 83 | 84 | // and process it 85 | execute_instruction(); 86 | 87 | // hook 88 | post_exec(); 89 | 90 | // deduct a cycle to account for the one added in USim::tick 91 | --cycles; 92 | } 93 | 94 | void mc6809::do_nmi() 95 | { 96 | if (!waiting_cwai) { 97 | cc.bit.e = 1; 98 | help_psh(0xff, s, u); 99 | } 100 | cc.bit.f = cc.bit.i = 1; 101 | pc = read_word(0xfffc); 102 | } 103 | 104 | void mc6809::do_firq() 105 | { 106 | if (!waiting_cwai) { 107 | cc.bit.e = 0; 108 | help_psh(0x81, s, u); 109 | } 110 | cc.bit.f = cc.bit.i = 1; 111 | pc = read_word(0xfff6); 112 | } 113 | 114 | void mc6809::do_irq() 115 | { 116 | if (!waiting_cwai) { 117 | cc.bit.e = 1; 118 | help_psh(0xff, s, u); 119 | } 120 | cc.bit.f = cc.bit.i = 1; 121 | pc = read_word(0xfff8); 122 | } 123 | 124 | void mc6809::fetch_instruction() 125 | { 126 | ir = fetch(); 127 | 128 | // look for two-byte instructions 129 | if (ir == 0x10 || ir == 0x11) { 130 | ir <<= 8; 131 | ir |= fetch(); 132 | } 133 | 134 | // Decode addressing mode 135 | switch (ir & 0xf0) { 136 | case 0x00: case 0x90: case 0xd0: 137 | mode = direct; break; 138 | case 0x20: 139 | mode = relative; break; 140 | case 0x30: case 0x40: case 0x50: 141 | if (ir < 0x34) { 142 | mode = indexed; 143 | } else if (ir < 0x38 || ir == 0x3c) { 144 | mode = immediate; 145 | } else { 146 | mode = inherent; 147 | } 148 | break; 149 | case 0x60: case 0xa0: case 0xe0: 150 | mode = indexed; break; 151 | case 0x70: case 0xb0: case 0xf0: 152 | mode = extended; break; 153 | case 0x80: case 0xc0: 154 | if (ir == 0x8d) { 155 | mode = relative; 156 | } else { 157 | mode = immediate; 158 | } 159 | break; 160 | case 0x10: 161 | switch (ir & 0x0f) { 162 | case 0x02: case 0x03: case 0x09: case 0x0d: 163 | mode = inherent; break; 164 | case 0x06: case 0x07: 165 | mode = relative; break; 166 | case 0x0a: case 0x0c: case 0x0e: case 0x0f: 167 | mode = immediate; break; 168 | } 169 | break; 170 | } 171 | } 172 | 173 | void mc6809::execute_instruction() 174 | { 175 | switch (ir) { 176 | case 0x3a: 177 | abx(); break; 178 | case 0x89: case 0x99: case 0xa9: case 0xb9: 179 | adca(); break; 180 | case 0xc9: case 0xd9: case 0xe9: case 0xf9: 181 | adcb(); break; 182 | case 0x8b: case 0x9b: case 0xab: case 0xbb: 183 | adda(); break; 184 | case 0xcb: case 0xdb: case 0xeb: case 0xfb: 185 | addb(); break; 186 | case 0xc3: case 0xd3: case 0xe3: case 0xf3: 187 | addd(); break; 188 | case 0x84: case 0x94: case 0xa4: case 0xb4: 189 | anda(); break; 190 | case 0xc4: case 0xd4: case 0xe4: case 0xf4: 191 | andb(); break; 192 | case 0x1c: 193 | andcc(); break; 194 | case 0x47: 195 | asra(); break; 196 | case 0x57: 197 | asrb(); break; 198 | case 0x07: case 0x67: case 0x77: 199 | asr(); break; 200 | case 0x24: 201 | bcc(); break; 202 | case 0x25: 203 | bcs(); break; 204 | case 0x27: 205 | beq(); break; 206 | case 0x2c: 207 | bge(); break; 208 | case 0x2e: 209 | bgt(); break; 210 | case 0x22: 211 | bhi(); break; 212 | case 0x85: case 0x95: case 0xa5: case 0xb5: 213 | bita(); break; 214 | case 0xc5: case 0xd5: case 0xe5: case 0xf5: 215 | bitb(); break; 216 | case 0x2f: 217 | ble(); break; 218 | case 0x23: 219 | bls(); break; 220 | case 0x2d: 221 | blt(); break; 222 | case 0x2b: 223 | bmi(); break; 224 | case 0x26: 225 | bne(); break; 226 | case 0x2a: 227 | bpl(); break; 228 | case 0x20: 229 | bra(); break; 230 | case 0x16: 231 | lbra(); break; 232 | case 0x21: 233 | brn(); break; 234 | case 0x8d: 235 | bsr(); break; 236 | case 0x17: 237 | lbsr(); break; 238 | case 0x28: 239 | bvc(); break; 240 | case 0x29: 241 | bvs(); break; 242 | case 0x4e: case 0x4f: 243 | // 0x4e undocumented 244 | clra(); break; 245 | case 0x5e: case 0x5f: 246 | // 0x5e undocumented 247 | clrb(); break; 248 | case 0x0f: case 0x6f: case 0x7f: 249 | clr(); break; 250 | case 0x81: case 0x91: case 0xa1: case 0xb1: 251 | cmpa(); break; 252 | case 0xc1: case 0xd1: case 0xe1: case 0xf1: 253 | cmpb(); break; 254 | case 0x1083: case 0x1093: case 0x10a3: case 0x10b3: 255 | cmpd(); break; 256 | case 0x118c: case 0x119c: case 0x11ac: case 0x11bc: 257 | cmps(); break; 258 | case 0x8c: case 0x9c: case 0xac: case 0xbc: 259 | cmpx(); break; 260 | case 0x1183: case 0x1193: case 0x11a3: case 0x11b3: 261 | cmpu(); break; 262 | case 0x108c: case 0x109c: case 0x10ac: case 0x10bc: 263 | cmpy(); break; 264 | case 0x42: case 0x43: case 0x1042: 265 | // 0x42 / 0x1042 undocumented 266 | coma(); break; 267 | case 0x52: case 0x53: 268 | // 0x52 undocumented 269 | comb(); break; 270 | case 0x03: case 0x62: case 0x63: case 0x73: 271 | // 0x62 undocumented 272 | com(); break; 273 | case 0x3c: 274 | cwai(); break; 275 | case 0x19: 276 | daa(); break; 277 | case 0x4a: case 0x4b: 278 | // 0x4b undocumented 279 | deca(); break; 280 | case 0x5a: case 0x5b: 281 | // 0x5b undocumented 282 | decb(); break; 283 | case 0x0a: case 0x0b: 284 | case 0x6a: case 0x6b: 285 | case 0x7a: case 0x7b: 286 | // 0x0b, 0x6b, 0x7b undocumented 287 | dec(); break; 288 | case 0x88: case 0x98: case 0xa8: case 0xb8: 289 | eora(); break; 290 | case 0xc8: case 0xd8: case 0xe8: case 0xf8: 291 | eorb(); break; 292 | case 0x1e: 293 | exg(); break; 294 | case 0x4c: 295 | inca(); break; 296 | case 0x5c: 297 | incb(); break; 298 | case 0x0c: case 0x6c: case 0x7c: 299 | inc(); break; 300 | case 0x0e: case 0x6e: case 0x7e: 301 | jmp(); break; 302 | case 0x9d: case 0xad: case 0xbd: 303 | jsr(); break; 304 | case 0x86: case 0x96: case 0xa6: case 0xb6: 305 | lda(); break; 306 | case 0xc6: case 0xd6: case 0xe6: case 0xf6: 307 | ldb(); break; 308 | case 0xcc: case 0xdc: case 0xec: case 0xfc: 309 | ldd(); break; 310 | case 0x10ce: case 0x10de: case 0x10ee: case 0x10fe: 311 | lds(); break; 312 | case 0xce: case 0xde: case 0xee: case 0xfe: 313 | ldu(); break; 314 | case 0x8e: case 0x9e: case 0xae: case 0xbe: 315 | ldx(); break; 316 | case 0x108e: case 0x109e: case 0x10ae: case 0x10be: 317 | ldy(); break; 318 | case 0x32: 319 | leas(); break; 320 | case 0x33: 321 | leau(); break; 322 | case 0x30: 323 | leax(); break; 324 | case 0x31: 325 | leay(); break; 326 | case 0x48: 327 | lsla(); break; 328 | case 0x58: 329 | lslb(); break; 330 | case 0x08: case 0x68: case 0x78: 331 | lsl(); break; 332 | case 0x44: case 0x45: 333 | // 0x45 undocumented 334 | lsra(); break; 335 | case 0x54: case 0x55: 336 | // 0x55 undocumented 337 | lsrb(); break; 338 | case 0x04: case 0x05: 339 | case 0x64: case 0x65: 340 | case 0x74: case 0x75: 341 | // 0x05, 0x65, 0x75 undocumented 342 | lsr(); break; 343 | case 0x3d: 344 | mul(); break; 345 | case 0x40: case 0x41: 346 | // 0x41 undocumented 347 | nega(); break; 348 | case 0x50: case 0x51: 349 | // 0x51 undocumented 350 | negb(); break; 351 | case 0x00: case 0x01: 352 | case 0x60: case 0x61: 353 | case 0x70: case 0x71: 354 | // 0x01, 0x61, 0x71 undocumented 355 | neg(); break; 356 | case 0x12: 357 | nop(); break; 358 | case 0x8a: case 0x9a: case 0xaa: case 0xba: 359 | ora(); break; 360 | case 0xca: case 0xda: case 0xea: case 0xfa: 361 | orb(); break; 362 | case 0x1a: 363 | orcc(); break; 364 | case 0x34: 365 | pshs(); break; 366 | case 0x36: 367 | pshu(); break; 368 | case 0x35: 369 | puls(); break; 370 | case 0x37: 371 | pulu(); break; 372 | case 0x49: 373 | rola(); break; 374 | case 0x59: 375 | rolb(); break; 376 | case 0x09: case 0x69: case 0x79: 377 | rol(); break; 378 | case 0x46: 379 | rora(); break; 380 | case 0x56: 381 | rorb(); break; 382 | case 0x06: case 0x66: case 0x76: 383 | ror(); break; 384 | case 0x3b: 385 | rti(); break; 386 | case 0x39: 387 | rts(); break; 388 | case 0x82: case 0x92: case 0xa2: case 0xb2: 389 | sbca(); break; 390 | case 0xc2: case 0xd2: case 0xe2: case 0xf2: 391 | sbcb(); break; 392 | case 0x1d: 393 | sex(); break; 394 | case 0x97: case 0xa7: case 0xb7: 395 | sta(); break; 396 | case 0xd7: case 0xe7: case 0xf7: 397 | stb(); break; 398 | case 0xdd: case 0xed: case 0xfd: 399 | std(); break; 400 | case 0x10df: case 0x10ef: case 0x10ff: 401 | sts(); break; 402 | case 0xdf: case 0xef: case 0xff: 403 | stu(); break; 404 | case 0x9f: case 0xaf: case 0xbf: 405 | stx(); break; 406 | case 0x109f: case 0x10af: case 0x10bf: 407 | sty(); break; 408 | case 0x80: case 0x90: case 0xa0: case 0xb0: 409 | suba(); break; 410 | case 0xc0: case 0xd0: case 0xe0: case 0xf0: 411 | subb(); break; 412 | case 0x83: case 0x93: case 0xa3: case 0xb3: 413 | subd(); break; 414 | case 0x3f: 415 | swi(); break; 416 | case 0x103f: 417 | swi2(); break; 418 | case 0x113f: 419 | swi3(); break; 420 | case 0x13: 421 | sync(); break; 422 | case 0x1f: 423 | tfr(); break; 424 | case 0x4d: 425 | tsta(); break; 426 | case 0x5d: 427 | tstb(); break; 428 | case 0x0d: case 0x6d: case 0x7d: 429 | tst(); break; 430 | case 0x1024: 431 | lbcc(); break; 432 | case 0x1025: 433 | lbcs(); break; 434 | case 0x1027: 435 | lbeq(); break; 436 | case 0x102c: 437 | lbge(); break; 438 | case 0x102e: 439 | lbgt(); break; 440 | case 0x1022: 441 | lbhi(); break; 442 | case 0x102f: 443 | lble(); break; 444 | case 0x1023: 445 | lbls(); break; 446 | case 0x102d: 447 | lblt(); break; 448 | case 0x102b: 449 | lbmi(); break; 450 | case 0x1026: 451 | lbne(); break; 452 | case 0x102a: 453 | lbpl(); break; 454 | case 0x1021: 455 | lbrn(); break; 456 | case 0x1028: 457 | lbvc(); break; 458 | case 0x1029: 459 | lbvs(); break; 460 | default: 461 | invalid("invalid instruction"); 462 | } 463 | } 464 | 465 | void mc6809::print_regs() 466 | { 467 | char flags[] = "EFHINZVC"; 468 | for (uint8_t i = 0, mask = 0x80; mask; ++i, mask >>= 1) { 469 | if ((cc.all & mask) == 0) { 470 | flags[i] = '-'; 471 | } 472 | } 473 | fprintf(stderr, "PC:%04X CC:%s S:%04X U:%04X A:%02X B:%02X X:%04X Y:%04X DP:%02X\r\n", 474 | pc, flags, s, u, a, b, x, y, dp); 475 | } 476 | 477 | void mc6809::pre_exec() 478 | { 479 | if (!m_trace) return; 480 | 481 | print_regs(); 482 | } 483 | 484 | void mc6809::post_exec() 485 | { 486 | if (!m_trace) return; 487 | 488 | fprintf(stderr, "/ %04X: [%2d] %-8s%s\r\n", insn_pc, cycles, insn, disasm_operand().c_str()); 489 | } 490 | 491 | // used for EXG and TFR instructions 492 | Word& mc6809::wordrefreg(int r) 493 | { 494 | static Word no_return = 0; 495 | 496 | switch (r) { 497 | case 0: return d; 498 | case 1: return x; 499 | case 2: return y; 500 | case 3: return u; 501 | case 4: return s; 502 | case 5: return pc; 503 | } 504 | 505 | invalid("invalid word register selector"); 506 | return no_return; 507 | } 508 | 509 | Byte& mc6809::byterefreg(int r) 510 | { 511 | static Byte no_return = 0; 512 | 513 | switch (r) { 514 | case 8: return a; 515 | case 9: return b; 516 | case 10: return cc.all; 517 | case 11: return dp; 518 | } 519 | 520 | invalid("invalid byte register selector"); 521 | return no_return; 522 | } 523 | 524 | // decodes the postbyte for most indexed modes 525 | Word& mc6809::ix_refreg(Byte post) 526 | { 527 | static Word no_return = 0; 528 | 529 | post = (post >> 5) & 0x03; 530 | switch (post) { 531 | case 0: return x; 532 | case 1: return y; 533 | case 2: return u; 534 | case 3: return s; 535 | } 536 | 537 | invalid("invalid register reference"); 538 | return no_return; 539 | } 540 | 541 | Byte mc6809::fetch_operand() 542 | { 543 | switch (mode) { 544 | case immediate: 545 | return operand = extend8(fetch()); 546 | case relative: { 547 | Byte r = fetch(); 548 | operand = pc + extend8(r); 549 | return r; 550 | } 551 | default: 552 | return read(fetch_effective_address()); 553 | } 554 | } 555 | 556 | Word mc6809::fetch_word_operand() 557 | { 558 | switch (mode) { 559 | case immediate: 560 | return operand = fetch_word(); 561 | case relative: { 562 | Word r = fetch_word(); 563 | operand = pc + r; 564 | return r; 565 | } 566 | default: 567 | return read_word(fetch_effective_address()); 568 | } 569 | } 570 | 571 | Word mc6809::fetch_effective_address() 572 | { 573 | switch (mode) { 574 | case extended: 575 | ++cycles; 576 | return operand = fetch_word(); 577 | case direct: 578 | ++cycles; 579 | operand = fetch(); 580 | return ((Word)dp << 8) | operand; 581 | case indexed: { 582 | post = fetch(); 583 | 584 | do_predecrement(); 585 | Word addr = fetch_indexed_operand(); 586 | do_postincrement(); 587 | 588 | // handle indirect indexed mode 589 | if (btst(post, 4) && btst(post, 7)) { 590 | ++cycles; 591 | addr = read_word(addr); 592 | } 593 | return addr; 594 | } 595 | default: 596 | invalid("invalid addressing mode"); 597 | return 0; 598 | } 599 | } 600 | 601 | Word mc6809::fetch_indexed_operand() 602 | { 603 | if ((post & 0x80) == 0x00) { // ,R + 5 bit offset 604 | cycles += 2; 605 | return ix_refreg(post) + extend5(post & 0x1f); 606 | } 607 | 608 | switch (post & 0x1f) { 609 | case 0x00: // ,R+ 610 | cycles += 3; 611 | return ix_refreg(post); 612 | case 0x01: case 0x11: // ,R++ 613 | cycles += 4; 614 | return ix_refreg(post); 615 | case 0x02: // ,-R 616 | cycles += 3; 617 | return ix_refreg(post); 618 | case 0x03: case 0x13: // ,--R 619 | cycles += 4; 620 | return ix_refreg(post); 621 | case 0x04: case 0x14: // ,R + 0 622 | cycles += 1; 623 | return ix_refreg(post); 624 | break; 625 | case 0x05: case 0x15: // ,R + B 626 | cycles += 2; 627 | return extend8(b) + ix_refreg(post); 628 | case 0x06: case 0x16: // ,R + A 629 | cycles += 2; 630 | return extend8(a) + ix_refreg(post); 631 | case 0x08: case 0x18: // ,R + 8 bit 632 | cycles += 1; 633 | operand = extend8(fetch()); 634 | return ix_refreg(post) + operand; 635 | case 0x09: case 0x19: // ,R + 16 bit 636 | cycles += 3; 637 | operand = fetch_word(); 638 | return ix_refreg(post) + operand; 639 | case 0x0b: case 0x1b: // ,R + D 640 | cycles += 5; 641 | return d + ix_refreg(post); 642 | case 0x0c: case 0x1c: // ,PC + 8 643 | cycles += 1; 644 | operand = extend8(fetch()); 645 | return pc + operand; 646 | case 0x0d: case 0x1d: // ,PC + 16 647 | cycles += 3; 648 | operand = fetch_word(); 649 | return pc + operand; 650 | case 0x1f: // [,Address] 651 | cycles += 1; 652 | operand = fetch_word(); 653 | return operand; 654 | default: 655 | invalid("invalid indexed addressing postbyte"); 656 | return 0; 657 | } 658 | } 659 | 660 | void mc6809::do_postincrement() 661 | { 662 | switch (post & 0x9f) { 663 | case 0x80: 664 | ix_refreg(post) += 1; 665 | break; 666 | case 0x90: 667 | invalid("invalid post-increment operation"); 668 | break; 669 | case 0x81: case 0x91: 670 | ix_refreg(post) += 2; 671 | break; 672 | } 673 | } 674 | 675 | void mc6809::do_predecrement() 676 | { 677 | switch (post & 0x9f) { 678 | case 0x82: 679 | ix_refreg(post) -= 1; 680 | break; 681 | case 0x92: 682 | invalid("invalid pre-decrement operation"); 683 | break; 684 | case 0x83: case 0x93: 685 | ix_refreg(post) -= 2; 686 | break; 687 | } 688 | } 689 | 690 | //--------------------------------------------------------------------- 691 | // 692 | // disassembly support 693 | // 694 | //--------------------------------------------------------------------- 695 | 696 | static std::string disasm_reglist(Byte w, const char *other_sr) 697 | { 698 | static const char* regs[] = { 699 | "CC", "A", "B", "DP", "X", "Y", "", "PC" 700 | }; 701 | 702 | std::string r; 703 | 704 | for (int n = 0; (n < 8) && w; ++n, w >>= 1) { 705 | if (w & 1) { 706 | r += (n == 6) ? other_sr : regs[n]; 707 | if (w & 0xfe) { 708 | r += ","; 709 | } 710 | } 711 | } 712 | 713 | return r; 714 | } 715 | 716 | static std::string disasm_regpair(Byte w) 717 | { 718 | static const char* regnames[] = { 719 | "D", "X", "Y", "U", "S", "PC", "", "", 720 | "A", "B", "CC", "DP", "", "", "", "" 721 | }; 722 | 723 | int r1 = (w & 0xf0) >> 4; 724 | int r2 = (w & 0x0f) >> 0; 725 | 726 | return std::string(regnames[r1]) + "," + std::string(regnames[r2]); 727 | } 728 | 729 | template 730 | static std::string fmt(const std::string& format, Args ... args) 731 | { 732 | int size = ::snprintf(nullptr, 0, format.c_str(), args ...) + 1; 733 | if (size <= 0) { 734 | return "string formatting error"; 735 | } 736 | 737 | std::unique_ptr buf(new char[size]); 738 | ::snprintf(buf.get(), size, format.c_str(), args ...); 739 | return std::string(buf.get(), buf.get() + size - 1 ); 740 | } 741 | 742 | std::string mc6809::disasm_indexed() 743 | { 744 | static const char regs[] = "XYUS"; 745 | const char reg = regs[(post >> 5) & 0x03]; 746 | 747 | if (!btst(post, 7)) { // ,R + 5 bit offset 748 | return fmt("%d,%c", (int16_t)extend5(post & 0x1f), reg); 749 | } 750 | 751 | switch (post & 0x1f) { 752 | case 0x00: // ,R+ 753 | return fmt(",%c+", reg); 754 | case 0x01: case 0x11: // ,R++ 755 | return fmt(",%c++", reg); 756 | case 0x02: // ,-R 757 | return fmt(",-%c", reg); 758 | case 0x03: case 0x13: // ,--R 759 | return fmt(",--%c", reg); 760 | case 0x04: case 0x14: // ,R + 0 761 | return fmt(",%c", reg); 762 | case 0x05: case 0x15: // ,R + B 763 | return fmt("B,%c", reg); 764 | case 0x06: case 0x16: // ,R + A 765 | return fmt("A,%c", reg); 766 | case 0x08: case 0x18: // ,R + offset 767 | case 0x09: case 0x19: 768 | return fmt("%d,%c", (int16_t)operand, reg); 769 | case 0x0b: case 0x1b: // ,R + D 770 | return fmt("D,%c", reg); 771 | case 0x0c: case 0x1c: // ,PCR + offset 772 | case 0x0d: case 0x1d: 773 | return fmt("%d,PCR", (int16_t)operand, reg); 774 | case 0x1f: // ,Address 775 | return fmt(",$%04hx", (int16_t)operand); 776 | default: 777 | invalid("indirect addressing postbyte"); 778 | return ""; 779 | } 780 | } 781 | 782 | std::string mc6809::disasm_operand() 783 | { 784 | // special cases for PSHx / PULx / EXG / TFR 785 | switch (ir) { 786 | case 0x34: case 0x36: // PSHS / PULS 787 | return disasm_reglist(operand, "U"); 788 | case 0x35: case 0x37: // PSHU / PULU 789 | return disasm_reglist(operand, "S"); 790 | case 0x1e: case 0x1f: // EXG / TFR 791 | return disasm_regpair(operand); 792 | } 793 | 794 | switch (mode) { 795 | case inherent: 796 | return ""; 797 | case immediate: 798 | return fmt("#$%02X", operand); 799 | case relative: 800 | return fmt("$%04X", operand); 801 | case direct: 802 | return fmt("<$%02X", operand); 803 | case extended: 804 | return fmt("$%04X", operand); 805 | case indexed: { 806 | auto r = disasm_indexed(); 807 | if (btst(post, 4) && btst(post, 7)) { 808 | r = "[" + r + "]"; 809 | } 810 | return r; 811 | } 812 | } 813 | 814 | return ""; 815 | } 816 | -------------------------------------------------------------------------------- /mc6809.h: -------------------------------------------------------------------------------- 1 | // 2 | // mc6809.h 3 | // 4 | // Class definition for Motorola MC6809 microprocessor 5 | // 6 | // (C) R.P.Bellis 1993 7 | // 8 | 9 | #pragma once 10 | 11 | #include 12 | #include "wiring.h" 13 | #include "usim.h" 14 | #include "bits.h" 15 | 16 | #ifndef USIM_MACHDEP_H 17 | #include "machdep.h" 18 | #endif 19 | 20 | class mc6809 : virtual public USimMotorola { 21 | 22 | protected: // Processor addressing modes 23 | 24 | enum { 25 | immediate, 26 | direct, 27 | indexed, 28 | extended, 29 | inherent, 30 | relative 31 | } mode; 32 | 33 | protected: // Processor registers 34 | 35 | Word u, s; // Stack pointers 36 | Word x, y; // Index registers 37 | Byte dp; // Direct Page register 38 | union { 39 | Word d; // Combined accumulator 40 | struct { 41 | #ifdef MACH_BYTE_ORDER_MSB_FIRST 42 | Byte a; // Accumulator a 43 | Byte b; // Accumulator b 44 | #else 45 | Byte b; // Accumulator b 46 | Byte a; // Accumulator a 47 | #endif 48 | } byte; 49 | } acc; 50 | Byte& a; 51 | Byte& b; 52 | Word& d; 53 | union { 54 | Byte all; // Condition code register 55 | struct { 56 | #ifdef MACH_BITFIELDS_LSB_FIRST 57 | Byte c : 1; // Carry 58 | Byte v : 1; // Overflow 59 | Byte z : 1; // Zero 60 | Byte n : 1; // Negative 61 | Byte i : 1; // IRQ disable 62 | Byte h : 1; // Half carry 63 | Byte f : 1; // FIRQ disable 64 | Byte e : 1; // Entire 65 | #else 66 | Byte e : 1; // Entire 67 | Byte f : 1; // FIRQ disable 68 | Byte h : 1; // Half carry 69 | Byte i : 1; // IRQ disable 70 | Byte n : 1; // Negative 71 | Byte z : 1; // Zero 72 | Byte v : 1; // Overflow 73 | Byte c : 1; // Carry 74 | #endif 75 | } bit; 76 | } cc; 77 | 78 | private: // internal processor state 79 | bool waiting_sync; 80 | bool waiting_cwai; 81 | bool nmi_previous; 82 | 83 | private: // instruction and operand fetch and decode 84 | Word& ix_refreg(Byte); 85 | 86 | void fetch_instruction(); 87 | Byte fetch_operand(); 88 | Word fetch_word_operand(); 89 | Word fetch_effective_address(); 90 | Word fetch_indexed_operand(); 91 | void execute_instruction(); 92 | 93 | void do_predecrement(); 94 | void do_postincrement(); 95 | 96 | private: // instruction implementations 97 | void abx(); 98 | void adca(), adcb(); 99 | void adda(), addb(), addd(); 100 | void anda(), andb(), andcc(); 101 | void asra(), asrb(), asr(); 102 | void bcc(), lbcc(); 103 | void bcs(), lbcs(); 104 | void beq(), lbeq(); 105 | void bge(), lbge(); 106 | void bgt(), lbgt(); 107 | void bhi(), lbhi(); 108 | void bita(), bitb(); 109 | void ble(), lble(); 110 | void bls(), lbls(); 111 | void blt(), lblt(); 112 | void bmi(), lbmi(); 113 | void bne(), lbne(); 114 | void bpl(), lbpl(); 115 | void bra(), lbra(); 116 | void brn(), lbrn(); 117 | void bsr(), lbsr(); 118 | void bvc(), lbvc(); 119 | void bvs(), lbvs(); 120 | void clra(), clrb(), clr(); 121 | void cmpa(), cmpb(); 122 | void cmpd(), cmpx(), cmpy(), cmpu(), cmps(); 123 | void coma(), comb(), com(); 124 | void cwai(); 125 | void daa(); 126 | void deca(), decb(), dec(); 127 | void eora(), eorb(); 128 | void exg(); 129 | void inca(), incb(), inc(); 130 | void jmp(); 131 | void jsr(); 132 | void lda(), ldb(); 133 | void ldd(), ldx(), ldy(), lds(), ldu(); 134 | void leax(), leay(), leas(), leau(); 135 | void lsla(), lslb(), lsl(); 136 | void lsra(), lsrb(), lsr(); 137 | void mul(); 138 | void nega(), negb(), neg(); 139 | void nop(); 140 | void ora(), orb(), orcc(); 141 | void pshs(), pshu(); 142 | void puls(), pulu(); 143 | void rola(), rolb(), rol(); 144 | void rora(), rorb(), ror(); 145 | void rti(), rts(); 146 | void sbca(), sbcb(); 147 | void sex(); 148 | void sta(), stb(); 149 | void std(), stx(), sty(), sts(), stu(); 150 | void suba(), subb(); 151 | void subd(); 152 | void swi(), swi2(), swi3(); 153 | void sync(); 154 | void tfr(); 155 | void tsta(), tstb(), tst(); 156 | 157 | protected: // helper functions 158 | void help_adc(Byte&); 159 | void help_add(Byte&); 160 | void help_and(Byte&); 161 | void help_asr(Byte&); 162 | void help_bit(Byte); 163 | void help_clr(Byte&); 164 | void help_cmp(Byte); 165 | void help_cmp(Word); 166 | void help_com(Byte&); 167 | void help_dec(Byte&); 168 | void help_eor(Byte&); 169 | void help_inc(Byte&); 170 | void help_ld(Byte&); 171 | void help_ld(Word&); 172 | void help_lsr(Byte&); 173 | void help_lsl(Byte&); 174 | void help_neg(Byte&); 175 | void help_or(Byte&); 176 | void help_psh(Byte, Word&, Word&); 177 | void help_pul(Byte, Word&, Word&); 178 | void help_ror(Byte&); 179 | void help_rol(Byte&); 180 | void help_sbc(Byte&); 181 | void help_st(Byte); 182 | void help_st(Word); 183 | void help_sub(Byte&); 184 | void help_sub(Word&); 185 | void help_tst(Byte); 186 | 187 | protected: // overloadable functions (e.g. for breakpoints) 188 | virtual void do_br(const char *, bool); 189 | virtual void do_lbr(const char *, bool); 190 | 191 | virtual void do_psh(Word& sp, Byte); 192 | virtual void do_psh(Word& sp, Word); 193 | virtual void do_pul(Word& sp, Byte&); 194 | virtual void do_pul(Word& sp, Word&); 195 | 196 | virtual void do_nmi(); 197 | virtual void do_firq(); 198 | virtual void do_irq(); 199 | 200 | virtual void pre_exec(); 201 | virtual void post_exec(); 202 | 203 | protected: // instruction tracing 204 | Word insn_pc; 205 | const char* insn; 206 | Byte post; 207 | Word operand; 208 | 209 | std::string disasm_operand(); 210 | std::string disasm_indexed(); 211 | 212 | public: // external signal pins 213 | InputPin IRQ, FIRQ, NMI; 214 | 215 | public: 216 | mc6809(); // public constructor 217 | virtual ~mc6809(); // public destructor 218 | 219 | virtual void reset(); // CPU reset 220 | virtual void tick(); 221 | 222 | virtual void print_regs(); 223 | 224 | Byte& byterefreg(int); 225 | Word& wordrefreg(int); 226 | 227 | }; 228 | 229 | inline void mc6809::do_br(const char *mnemonic, bool test) 230 | { 231 | (void)mnemonic; 232 | Word offset = extend8(fetch_operand()); 233 | if (test) pc += offset; 234 | ++cycles; 235 | } 236 | 237 | inline void mc6809::do_lbr(const char *mnemonic, bool test) 238 | { 239 | (void)mnemonic; 240 | Word offset = fetch_word_operand(); 241 | if (test) { 242 | pc += offset; 243 | ++cycles; 244 | } 245 | ++cycles; 246 | } 247 | 248 | inline void mc6809::do_psh(Word& sp, Byte val) 249 | { 250 | write(--sp, val); 251 | } 252 | 253 | inline void mc6809::do_psh(Word& sp, Word val) 254 | { 255 | write(--sp, (Byte)val); 256 | write(--sp, (Byte)(val >> 8)); 257 | } 258 | 259 | inline void mc6809::do_pul(Word& sp, Byte& val) 260 | { 261 | val = read(sp++); 262 | } 263 | 264 | inline void mc6809::do_pul(Word& sp, Word& val) 265 | { 266 | val = read(sp++) << 8; 267 | val |= read(sp++); 268 | } 269 | -------------------------------------------------------------------------------- /mc6809in.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // mc6809ins.cpp 3 | // 4 | // (C) R.P.Bellis 5 | // 6 | // Updated from BDA and Soren Roug 12/2003 primarily 7 | // with fixes for SBC / CMP / NEG instructions with 8 | // incorrect carry flag settings 9 | // 10 | 11 | #include 12 | #include "mc6809.h" 13 | 14 | //-- helper functions 15 | 16 | void mc6809::help_adc(Byte& x) 17 | { 18 | Byte m = fetch_operand(); 19 | 20 | { 21 | Byte t = (x & 0x0f) + (m & 0x0f) + cc.bit.c; 22 | cc.bit.h = btst(t, 4); // Half carry 23 | } 24 | 25 | { 26 | Byte t = (x & 0x7f) + (m & 0x7f) + cc.bit.c; 27 | cc.bit.v = btst(t, 7); // Bit 7 carry in 28 | } 29 | 30 | { 31 | Word t = x + m + cc.bit.c; 32 | cc.bit.c = btst(t, 8); // Bit 7 carry out 33 | x = t & 0xff; 34 | } 35 | 36 | cc.bit.v ^= cc.bit.c; 37 | cc.bit.n = btst(x, 7); 38 | cc.bit.z = !x; 39 | } 40 | 41 | void mc6809::help_add(Byte& x) 42 | { 43 | Byte m = fetch_operand(); 44 | 45 | { 46 | Byte t = (x & 0x0f) + (m & 0x0f); 47 | cc.bit.h = btst(t, 4); // Half carry 48 | } 49 | 50 | { 51 | Byte t = (x & 0x7f) + (m & 0x7f); 52 | cc.bit.v = btst(t, 7); // Bit 7 carry in 53 | } 54 | 55 | { 56 | Word t = x + m; 57 | cc.bit.c = btst(t, 8); // Bit 7 carry out 58 | x = t & 0xff; 59 | } 60 | 61 | cc.bit.v ^= cc.bit.c; 62 | cc.bit.n = btst(x, 7); 63 | cc.bit.z = !x; 64 | } 65 | 66 | void mc6809::help_and(Byte& x) 67 | { 68 | x = x & fetch_operand(); 69 | cc.bit.n = btst(x, 7); 70 | cc.bit.z = !x; 71 | cc.bit.v = 0; 72 | } 73 | 74 | void mc6809::help_asr(Byte& x) 75 | { 76 | cc.bit.c = btst(x, 0); 77 | x >>= 1; /* Shift word right */ 78 | if ((cc.bit.n = btst(x, 6)) != 0) { 79 | bset(x, 7); 80 | } 81 | cc.bit.z = !x; 82 | ++cycles; 83 | } 84 | 85 | void mc6809::help_bit(Byte x) 86 | { 87 | Byte t = x & fetch_operand(); 88 | cc.bit.n = btst(t, 7); 89 | cc.bit.v = 0; 90 | cc.bit.z = !t; 91 | } 92 | 93 | void mc6809::help_clr(Byte& x) 94 | { 95 | cc.all &= 0xf0; 96 | cc.all |= 0x04; 97 | x = 0; 98 | ++cycles; 99 | } 100 | 101 | void mc6809::help_cmp(Byte x) 102 | { 103 | Byte m = fetch_operand(); 104 | int t = x - m; 105 | 106 | cc.bit.v = btst((Byte)(x ^ m ^ t ^ (t >> 1)), 7); 107 | cc.bit.c = btst((Word)t, 8); 108 | cc.bit.n = btst((Byte)t, 7); 109 | cc.bit.z = !(t & 0xff); 110 | } 111 | 112 | void mc6809::help_cmp(Word x) 113 | { 114 | Word m = fetch_word_operand(); 115 | long t = x - m; 116 | 117 | cc.bit.v = btst((DWord)(x ^ m ^ t ^ (t >> 1)), 15); 118 | cc.bit.c = btst((DWord)t, 16); 119 | cc.bit.n = btst((DWord)t, 15); 120 | cc.bit.z = !(t & 0xffff); 121 | ++cycles; 122 | } 123 | 124 | void mc6809::help_com(Byte& x) 125 | { 126 | x = ~x; 127 | cc.bit.c = 1; 128 | cc.bit.v = 0; 129 | cc.bit.n = btst(x, 7); 130 | cc.bit.z = !x; 131 | ++cycles; 132 | } 133 | 134 | void mc6809::help_dec(Byte& x) 135 | { 136 | cc.bit.v = (x == 0x80); 137 | x = x - 1; 138 | cc.bit.n = btst(x, 7); 139 | cc.bit.z = !x; 140 | ++cycles; 141 | } 142 | 143 | void mc6809::help_eor(Byte& x) 144 | { 145 | x = x ^ fetch_operand(); 146 | cc.bit.v = 0; 147 | cc.bit.n = btst(x, 7); 148 | cc.bit.z = !x; 149 | } 150 | 151 | void mc6809::help_inc(Byte& x) 152 | { 153 | cc.bit.v = (x == 0x7f); 154 | x = x + 1; 155 | cc.bit.n = btst(x, 7); 156 | cc.bit.z = !x; 157 | ++cycles; 158 | } 159 | 160 | void mc6809::help_ld(Byte& x) 161 | { 162 | x = fetch_operand(); 163 | cc.bit.n = btst(x, 7); 164 | cc.bit.v = 0; 165 | cc.bit.z = !x; 166 | } 167 | 168 | void mc6809::help_ld(Word& x) 169 | { 170 | x = fetch_word_operand(); 171 | cc.bit.n = btst(x, 15); 172 | cc.bit.v = 0; 173 | cc.bit.z = !x; 174 | } 175 | 176 | void mc6809::help_lsl(Byte& x) 177 | { 178 | cc.bit.c = btst(x, 7); 179 | cc.bit.v = btst(x, 7) ^ btst(x, 6); 180 | x <<= 1; 181 | cc.bit.n = btst(x, 7); 182 | cc.bit.z = !x; 183 | ++cycles; 184 | } 185 | 186 | void mc6809::help_lsr(Byte& x) 187 | { 188 | cc.bit.c = btst(x, 0); 189 | x >>= 1; /* Shift word right */ 190 | cc.bit.n = 0; 191 | cc.bit.z = !x; 192 | ++cycles; 193 | } 194 | 195 | void mc6809::help_neg(Byte& x) 196 | { 197 | int t = 0 - x; 198 | 199 | cc.bit.v = btst((Byte)(x ^ t ^ (t >> 1)), 7); 200 | cc.bit.c = btst((Word)t, 8); 201 | cc.bit.n = btst((Byte)t, 7); 202 | x = t & 0xff; 203 | cc.bit.z = !x; 204 | ++cycles; 205 | } 206 | 207 | void mc6809::help_or(Byte& x) 208 | { 209 | x = x | fetch_operand(); 210 | cc.bit.v = 0; 211 | cc.bit.n = btst(x, 7); 212 | cc.bit.z = !x; 213 | } 214 | 215 | void mc6809::help_psh(Byte w, Word& s, Word& u) 216 | { 217 | if (btst(w, 7)) do_psh(s, pc); 218 | if (btst(w, 6)) do_psh(s, u); 219 | if (btst(w, 5)) do_psh(s, y); 220 | if (btst(w, 4)) do_psh(s, x); 221 | if (btst(w, 3)) do_psh(s, dp); 222 | if (btst(w, 2)) do_psh(s, b); 223 | if (btst(w, 1)) do_psh(s, a); 224 | if (btst(w, 0)) do_psh(s, cc.all); 225 | } 226 | 227 | void mc6809::help_pul(Byte w, Word& s, Word& u) 228 | { 229 | if (btst(w, 0)) do_pul(s, cc.all); 230 | if (btst(w, 1)) do_pul(s, a); 231 | if (btst(w, 2)) do_pul(s, b); 232 | if (btst(w, 3)) do_pul(s, dp); 233 | if (btst(w, 4)) do_pul(s, x); 234 | if (btst(w, 5)) do_pul(s, y); 235 | if (btst(w, 6)) do_pul(s, u); 236 | if (btst(w, 7)) do_pul(s, pc); 237 | } 238 | 239 | void mc6809::help_rol(Byte& x) 240 | { 241 | int oc = cc.bit.c; 242 | cc.bit.v = btst(x, 7) ^ btst(x, 6); 243 | cc.bit.c = btst(x, 7); 244 | x = x << 1; 245 | if (oc) bset(x, 0); 246 | cc.bit.n = btst(x, 7); 247 | cc.bit.z = !x; 248 | ++cycles; 249 | } 250 | 251 | void mc6809::help_ror(Byte& x) 252 | { 253 | int oc = cc.bit.c; 254 | cc.bit.c = btst(x, 0); 255 | x = x >> 1; 256 | if (oc) bset(x, 7); 257 | cc.bit.n = btst(x, 7); 258 | cc.bit.z = !x; 259 | ++cycles; 260 | } 261 | 262 | void mc6809::help_sbc(Byte& x) 263 | { 264 | Byte m = fetch_operand(); 265 | int t = x - m - cc.bit.c; 266 | 267 | cc.bit.v = btst((Byte)(x ^ m ^ t ^ (t >> 1)), 7); 268 | cc.bit.c = btst((Word)t, 8); 269 | cc.bit.n = btst((Byte)t, 7); 270 | x = t & 0xff; 271 | cc.bit.z = !x; 272 | } 273 | 274 | void mc6809::help_st(Byte x) 275 | { 276 | Word addr = fetch_effective_address(); 277 | write(addr, x); 278 | cc.bit.v = 0; 279 | cc.bit.n = btst(x, 7); 280 | cc.bit.z = !x; 281 | } 282 | 283 | void mc6809::help_st(Word x) 284 | { 285 | Word addr = fetch_effective_address(); 286 | write_word(addr, x); 287 | cc.bit.v = 0; 288 | cc.bit.n = btst(x, 15); 289 | cc.bit.z = !x; 290 | } 291 | 292 | void mc6809::help_sub(Byte& x) 293 | { 294 | Byte m = fetch_operand(); 295 | int t = x - m; 296 | 297 | cc.bit.v = btst((Byte)(x^m^t^(t>>1)),7); 298 | cc.bit.c = btst((Word)t,8); 299 | cc.bit.n = btst((Byte)t, 7); 300 | x = t & 0xff; 301 | cc.bit.z = !x; 302 | } 303 | 304 | void mc6809::help_tst(Byte x) 305 | { 306 | cc.bit.v = 0; 307 | cc.bit.n = btst(x, 7); 308 | cc.bit.z = !x; 309 | ++cycles; 310 | } 311 | 312 | //-- individual instructions 313 | 314 | void mc6809::abx() 315 | { 316 | insn = "ABX"; 317 | x += b; 318 | ++cycles; 319 | } 320 | 321 | void mc6809::adca() 322 | { 323 | insn = "ADCA"; 324 | help_adc(a); 325 | } 326 | 327 | void mc6809::adcb() 328 | { 329 | insn = "ADCB"; 330 | help_adc(b); 331 | } 332 | 333 | void mc6809::adda() 334 | { 335 | insn = "ADDA"; 336 | help_add(a); 337 | } 338 | 339 | void mc6809::addb() 340 | { 341 | insn = "ADDB"; 342 | help_add(b); 343 | } 344 | 345 | void mc6809::addd() 346 | { 347 | insn = "ADDD"; 348 | Word m = fetch_word_operand(); 349 | 350 | { 351 | Word t = (d & 0x7fff) + (m & 0x7fff); 352 | cc.bit.v = btst(t, 15); 353 | } 354 | 355 | { 356 | DWord t = (DWord)d + m; 357 | cc.bit.c = btst(t, 16); 358 | d = (Word)(t & 0xffff); 359 | } 360 | 361 | cc.bit.v ^= cc.bit.c; 362 | cc.bit.n = btst(d, 15); 363 | cc.bit.z = !d; 364 | ++cycles; 365 | } 366 | 367 | void mc6809::anda() 368 | { 369 | insn = "ANDA"; 370 | help_and(a); 371 | } 372 | 373 | void mc6809::andb() 374 | { 375 | insn = "ANDB"; 376 | help_and(b); 377 | } 378 | 379 | void mc6809::andcc() 380 | { 381 | insn = "ANDCC"; 382 | cc.all &= fetch_operand(); 383 | ++cycles; 384 | } 385 | 386 | void mc6809::asra() 387 | { 388 | insn = "ASRA"; 389 | help_asr(a); 390 | } 391 | 392 | void mc6809::asrb() 393 | { 394 | insn = "ASRB"; 395 | help_asr(b); 396 | } 397 | 398 | void mc6809::asr() 399 | { 400 | insn = "ASR"; 401 | Word addr = fetch_effective_address(); 402 | Byte m = read(addr); 403 | 404 | help_asr(m); 405 | write(addr, m); 406 | } 407 | 408 | void mc6809::bcc() 409 | { 410 | insn = "BCC"; 411 | do_br("cc", !cc.bit.c); 412 | } 413 | 414 | void mc6809::lbcc() 415 | { 416 | insn = "LBCC"; 417 | do_lbr("cc", !cc.bit.c); 418 | } 419 | 420 | void mc6809::bcs() 421 | { 422 | insn = "BCS"; 423 | do_br("cs", cc.bit.c); 424 | } 425 | 426 | void mc6809::lbcs() 427 | { 428 | insn = "LBCS"; 429 | do_lbr("cs", cc.bit.c); 430 | } 431 | 432 | void mc6809::beq() 433 | { 434 | insn = "BEQ"; 435 | do_br("eq", cc.bit.z); 436 | } 437 | 438 | void mc6809::lbeq() 439 | { 440 | insn = "LBEQ"; 441 | do_lbr("eq", cc.bit.z); 442 | } 443 | 444 | void mc6809::bge() 445 | { 446 | insn = "BGE"; 447 | do_br("ge", !(cc.bit.n ^ cc.bit.v)); 448 | } 449 | 450 | void mc6809::lbge() 451 | { 452 | insn = "LGBE"; 453 | do_lbr("ge", !(cc.bit.n ^ cc.bit.v)); 454 | } 455 | 456 | void mc6809::bgt() 457 | { 458 | insn = "BGT"; 459 | do_br("gt", !(cc.bit.z | (cc.bit.n ^ cc.bit.v))); 460 | } 461 | 462 | void mc6809::lbgt() 463 | { 464 | insn = "LBGT"; 465 | do_lbr("gt", !(cc.bit.z | (cc.bit.n ^ cc.bit.v))); 466 | } 467 | 468 | void mc6809::bhi() 469 | { 470 | insn = "BHI"; 471 | do_br("hi", !(cc.bit.c | cc.bit.z)); 472 | } 473 | 474 | void mc6809::lbhi() 475 | { 476 | insn = "LBHI"; 477 | do_lbr("hi", !(cc.bit.c | cc.bit.z)); 478 | } 479 | 480 | void mc6809::bita() 481 | { 482 | insn = "BITA"; 483 | help_bit(a); 484 | } 485 | 486 | void mc6809::bitb() 487 | { 488 | insn = "BITB"; 489 | help_bit(b); 490 | } 491 | 492 | void mc6809::ble() 493 | { 494 | insn = "BLE"; 495 | do_br("le", cc.bit.z | (cc.bit.n ^ cc.bit.v)); 496 | } 497 | 498 | void mc6809::lble() 499 | { 500 | insn = "LBLE"; 501 | do_lbr("le", cc.bit.z | (cc.bit.n ^ cc.bit.v)); 502 | } 503 | 504 | void mc6809::bls() 505 | { 506 | insn = "BLS"; 507 | do_br("ls", cc.bit.c | cc.bit.z); 508 | } 509 | 510 | void mc6809::lbls() 511 | { 512 | insn = "LBLS"; 513 | do_lbr("ls", cc.bit.c | cc.bit.z); 514 | } 515 | 516 | void mc6809::blt() 517 | { 518 | insn = "BLT"; 519 | do_br("lt", cc.bit.n ^ cc.bit.v); 520 | } 521 | 522 | void mc6809::lblt() 523 | { 524 | insn = "LBLT"; 525 | do_lbr("lt", cc.bit.n ^ cc.bit.v); 526 | } 527 | 528 | void mc6809::bmi() 529 | { 530 | insn = "BMI"; 531 | do_br("mi", cc.bit.n); 532 | } 533 | 534 | void mc6809::lbmi() 535 | { 536 | insn = "LBMI"; 537 | do_lbr("mi", cc.bit.n); 538 | } 539 | 540 | void mc6809::bne() 541 | { 542 | insn = "BNE"; 543 | do_br("ne", !cc.bit.z); 544 | } 545 | 546 | void mc6809::lbne() 547 | { 548 | insn = "LBNE"; 549 | do_lbr("ne", !cc.bit.z); 550 | } 551 | 552 | void mc6809::bpl() 553 | { 554 | insn = "BPL"; 555 | do_br("pl", !cc.bit.n); 556 | } 557 | 558 | void mc6809::lbpl() 559 | { 560 | insn = "LBPL"; 561 | do_lbr("pl", !cc.bit.n); 562 | } 563 | 564 | void mc6809::bra() 565 | { 566 | insn = "BRA"; 567 | do_br("ra", 1); 568 | } 569 | 570 | void mc6809::lbra() 571 | { 572 | insn = "LBRA"; 573 | do_lbr("ra", 1); 574 | } 575 | 576 | void mc6809::brn() 577 | { 578 | insn = "BRN"; 579 | do_br("rn", 0); 580 | } 581 | 582 | void mc6809::lbrn() 583 | { 584 | insn = "LBRN"; 585 | do_lbr("rn", 0); 586 | } 587 | 588 | void mc6809::bsr() 589 | { 590 | insn = "BSR"; 591 | Byte x = fetch_operand(); 592 | do_psh(s, pc); 593 | pc += extend8(x); 594 | cycles += 3; 595 | } 596 | 597 | void mc6809::lbsr() 598 | { 599 | insn = "LBSR"; 600 | Word x = fetch_word_operand(); 601 | do_psh(s, pc); 602 | pc += x; 603 | cycles += 4; 604 | } 605 | 606 | void mc6809::bvc() 607 | { 608 | insn = "BVC"; 609 | do_br("vc", !cc.bit.v); 610 | } 611 | 612 | void mc6809::lbvc() 613 | { 614 | insn = "LBVC"; 615 | do_lbr("vc", !cc.bit.v); 616 | } 617 | 618 | void mc6809::bvs() 619 | { 620 | insn = "BVS"; 621 | do_br("vs", cc.bit.v); 622 | } 623 | 624 | void mc6809::lbvs() 625 | { 626 | insn = "LBVS"; 627 | do_lbr("vs", cc.bit.v); 628 | } 629 | 630 | void mc6809::clra() 631 | { 632 | insn = "CLRA"; 633 | help_clr(a); 634 | } 635 | 636 | void mc6809::clrb() 637 | { 638 | insn = "CLRB"; 639 | help_clr(b); 640 | } 641 | 642 | void mc6809::clr() 643 | { 644 | insn = "CLR"; 645 | Word addr = fetch_effective_address(); 646 | Byte m = read(addr); 647 | help_clr(m); 648 | write(addr, m); 649 | } 650 | 651 | void mc6809::cmpa() 652 | { 653 | insn = "CMPA"; 654 | help_cmp(a); 655 | } 656 | 657 | void mc6809::cmpb() 658 | { 659 | insn = "CMPB"; 660 | help_cmp(b); 661 | } 662 | 663 | void mc6809::cmpd() 664 | { 665 | insn = "CMPD"; 666 | help_cmp(d); 667 | } 668 | 669 | void mc6809::cmpx() 670 | { 671 | insn = "CMPX"; 672 | help_cmp(x); 673 | } 674 | 675 | void mc6809::cmpy() 676 | { 677 | insn = "CMPY"; 678 | help_cmp(y); 679 | } 680 | 681 | void mc6809::cmpu() 682 | { 683 | insn = "CMPU"; 684 | help_cmp(u); 685 | } 686 | 687 | void mc6809::cmps() 688 | { 689 | insn = "CMPS"; 690 | help_cmp(s); 691 | } 692 | 693 | void mc6809::cwai() 694 | { 695 | insn = "CWAI"; 696 | Byte n = fetch_operand(); 697 | cc.all &= n; 698 | cc.bit.e = 1; 699 | help_psh(0xff, s, u); 700 | cycles += 2; 701 | waiting_cwai = true; 702 | } 703 | 704 | void mc6809::coma() 705 | { 706 | insn = "COMA"; 707 | help_com(a); 708 | } 709 | 710 | void mc6809::comb() 711 | { 712 | insn = "COMB"; 713 | help_com(b); 714 | } 715 | 716 | void mc6809::com() 717 | { 718 | insn = "COM"; 719 | Word addr = fetch_effective_address(); 720 | Byte m = read(addr); 721 | help_com(m); 722 | write(addr, m); 723 | } 724 | 725 | void mc6809::daa() 726 | { 727 | insn = "DAA"; 728 | Byte c = 0; 729 | Byte lsn = (a & 0x0f); 730 | Byte msn = (a & 0xf0) >> 4; 731 | 732 | if (cc.bit.h || (lsn > 9)) { 733 | c |= 0x06; 734 | } 735 | 736 | if (cc.bit.c || 737 | (msn > 9) || 738 | ((msn > 8) && (lsn > 9))) { 739 | c |= 0x60; 740 | } 741 | 742 | { 743 | Word t = (Word)a + c; 744 | cc.bit.c |= btst(t, 8); 745 | a = (Byte)t; 746 | } 747 | 748 | cc.bit.n = btst(a, 7); 749 | cc.bit.z = !a; 750 | ++cycles; 751 | } 752 | 753 | void mc6809::deca() 754 | { 755 | insn = "DECA"; 756 | help_dec(a); 757 | } 758 | 759 | void mc6809::decb() 760 | { 761 | insn = "DECB"; 762 | help_dec(b); 763 | } 764 | 765 | void mc6809::dec() 766 | { 767 | insn = "DEC"; 768 | Word addr = fetch_effective_address(); 769 | Byte m = read(addr); 770 | help_dec(m); 771 | write(addr, m); 772 | } 773 | 774 | void mc6809::eora() 775 | { 776 | insn = "EORA"; 777 | help_eor(a); 778 | } 779 | 780 | void mc6809::eorb() 781 | { 782 | insn = "EORB"; 783 | help_eor(b); 784 | } 785 | 786 | void mc6809::exg() 787 | { 788 | insn = "EXG"; 789 | Byte w = fetch_operand(); 790 | int r1 = (w & 0xf0) >> 4; 791 | int r2 = (w & 0x0f) >> 0; 792 | 793 | if (r1 <= 5 && r2 <= 5) { 794 | std::swap(wordrefreg(r2), wordrefreg(r1)); 795 | } else if (r1 >= 8 && r1 <= 11 && r2 >= 8 && r2 <= 11) { 796 | std::swap(byterefreg(r2), byterefreg(r1)); 797 | } else { 798 | invalid("invalid EXG operand"); 799 | } 800 | 801 | cycles += 6; 802 | } 803 | 804 | void mc6809::inca() 805 | { 806 | insn = "INCA"; 807 | help_inc(a); 808 | } 809 | 810 | void mc6809::incb() 811 | { 812 | insn = "INCB"; 813 | help_inc(b); 814 | } 815 | 816 | void mc6809::inc() 817 | { 818 | insn = "INC"; 819 | Word addr = fetch_effective_address(); 820 | Byte m = read(addr); 821 | help_inc(m); 822 | write(addr, m); 823 | } 824 | 825 | void mc6809::jmp() 826 | { 827 | insn = "JMP"; 828 | pc = fetch_effective_address(); 829 | } 830 | 831 | void mc6809::jsr() 832 | { 833 | insn = "JSR"; 834 | Word addr = fetch_effective_address(); 835 | do_psh(s, pc); 836 | pc = addr; 837 | cycles += 2; 838 | } 839 | 840 | void mc6809::lda() 841 | { 842 | insn = "LDA"; 843 | help_ld(a); 844 | } 845 | 846 | void mc6809::ldb() 847 | { 848 | insn = "LDB"; 849 | help_ld(b); 850 | } 851 | 852 | void mc6809::ldd() 853 | { 854 | insn = "LDD"; 855 | help_ld(d); 856 | } 857 | 858 | void mc6809::ldx() 859 | { 860 | insn = "LDX"; 861 | help_ld(x); 862 | } 863 | 864 | void mc6809::ldy() 865 | { 866 | insn = "LDY"; 867 | help_ld(y); 868 | } 869 | 870 | void mc6809::lds() 871 | { 872 | insn = "LDS"; 873 | help_ld(s); 874 | } 875 | 876 | void mc6809::ldu() 877 | { 878 | insn = "LDU"; 879 | help_ld(u); 880 | } 881 | 882 | void mc6809::leax() 883 | { 884 | insn = "LEAX"; 885 | x = fetch_effective_address(); 886 | cc.bit.z = !x; 887 | ++cycles; 888 | } 889 | 890 | void mc6809::leay() 891 | { 892 | insn = "LEAY"; 893 | y = fetch_effective_address(); 894 | cc.bit.z = !y; 895 | ++cycles; 896 | } 897 | 898 | void mc6809::leas() 899 | { 900 | insn = "LEAS"; 901 | s = fetch_effective_address(); 902 | ++cycles; 903 | } 904 | 905 | void mc6809::leau() 906 | { 907 | insn = "LEAU"; 908 | u = fetch_effective_address(); 909 | ++cycles; 910 | } 911 | 912 | void mc6809::lsla() 913 | { 914 | insn = "LSLA"; 915 | help_lsl(a); 916 | } 917 | 918 | void mc6809::lslb() 919 | { 920 | insn = "LSLB"; 921 | help_lsl(b); 922 | } 923 | 924 | void mc6809::lsl() 925 | { 926 | insn = "LSL"; 927 | Word addr = fetch_effective_address(); 928 | Byte m = read(addr); 929 | help_lsl(m); 930 | write(addr, m); 931 | } 932 | 933 | void mc6809::lsra() 934 | { 935 | insn = "LSRA"; 936 | help_lsr(a); 937 | } 938 | 939 | void mc6809::lsrb() 940 | { 941 | insn = "LSRB"; 942 | help_lsr(b); 943 | } 944 | 945 | void mc6809::lsr() 946 | { 947 | insn = "LSR"; 948 | Word addr = fetch_effective_address(); 949 | Byte m = read(addr); 950 | help_lsr(m); 951 | write(addr, m); 952 | } 953 | 954 | void mc6809::mul() 955 | { 956 | insn = "MUL"; 957 | d = a * b; 958 | cc.bit.c = btst(b, 7); 959 | cc.bit.z = !d; 960 | cycles += 10; 961 | } 962 | 963 | void mc6809::nega() 964 | { 965 | insn = "NEGA"; 966 | help_neg(a); 967 | } 968 | 969 | void mc6809::negb() 970 | { 971 | insn = "NEGB"; 972 | help_neg(b); 973 | } 974 | 975 | void mc6809::neg() 976 | { 977 | insn = "NEG"; 978 | Word addr = fetch_effective_address(); 979 | Byte m = read(addr); 980 | help_neg(m); 981 | write(addr, m); 982 | } 983 | 984 | void mc6809::nop() 985 | { 986 | insn = "NOP"; 987 | ++cycles; 988 | } 989 | 990 | void mc6809::ora() 991 | { 992 | insn = "ORA"; 993 | help_or(a); 994 | } 995 | 996 | void mc6809::orb() 997 | { 998 | insn = "ORB"; 999 | help_or(b); 1000 | } 1001 | 1002 | void mc6809::orcc() 1003 | { 1004 | insn = "ORCC"; 1005 | cc.all |= fetch_operand(); 1006 | ++cycles; 1007 | } 1008 | 1009 | void mc6809::pshs() 1010 | { 1011 | insn = "PSHS"; 1012 | Byte w = fetch_operand(); 1013 | help_psh(w, s, u); 1014 | cycles += 3; 1015 | } 1016 | 1017 | void mc6809::pshu() 1018 | { 1019 | insn = "PSHU"; 1020 | Byte w = fetch_operand(); 1021 | help_psh(w, u, s); 1022 | cycles += 3; 1023 | } 1024 | 1025 | void mc6809::puls() 1026 | { 1027 | insn = "PULS"; 1028 | Byte w = fetch_operand(); 1029 | help_pul(w, s, u); 1030 | cycles += 3; 1031 | } 1032 | 1033 | void mc6809::pulu() 1034 | { 1035 | insn = "PULU"; 1036 | Byte w = fetch_operand(); 1037 | help_pul(w, u, s); 1038 | cycles += 3; 1039 | } 1040 | 1041 | void mc6809::rola() 1042 | { 1043 | insn = "ROLA"; 1044 | help_rol(a); 1045 | } 1046 | 1047 | void mc6809::rolb() 1048 | { 1049 | insn = "ROLB"; 1050 | help_rol(b); 1051 | } 1052 | 1053 | void mc6809::rol() 1054 | { 1055 | insn = "ROL"; 1056 | Word addr = fetch_effective_address(); 1057 | Byte m = read(addr); 1058 | help_rol(m); 1059 | write(addr, m); 1060 | } 1061 | 1062 | void mc6809::rora() 1063 | { 1064 | insn = "RORA"; 1065 | help_ror(a); 1066 | } 1067 | 1068 | void mc6809::rorb() 1069 | { 1070 | insn = "RORB"; 1071 | help_ror(b); 1072 | } 1073 | 1074 | void mc6809::ror() 1075 | { 1076 | insn = "ROR"; 1077 | Word addr = fetch_effective_address(); 1078 | Byte m = read(addr); 1079 | help_ror(m); 1080 | write(addr, m); 1081 | } 1082 | 1083 | void mc6809::rti() 1084 | { 1085 | insn = "RTI"; 1086 | help_pul(0x01, s, u); 1087 | if (cc.bit.e) { 1088 | help_pul(0xfe, s, u); 1089 | } else { 1090 | help_pul(0x80, s, u); 1091 | } 1092 | cycles += 2; 1093 | } 1094 | 1095 | void mc6809::rts() 1096 | { 1097 | insn = "RTS"; 1098 | do_pul(s, pc); 1099 | cycles += 2; 1100 | } 1101 | 1102 | void mc6809::sbca() 1103 | { 1104 | insn = "SBCA"; 1105 | help_sbc(a); 1106 | } 1107 | 1108 | void mc6809::sbcb() 1109 | { 1110 | insn = "SBCB"; 1111 | help_sbc(b); 1112 | } 1113 | 1114 | void mc6809::sex() 1115 | { 1116 | insn = "SEX"; 1117 | cc.bit.n = btst(b, 7); 1118 | cc.bit.z = !b; 1119 | a = cc.bit.n ? 255 : 0; 1120 | ++cycles; 1121 | } 1122 | 1123 | void mc6809::sta() 1124 | { 1125 | insn = "STA"; 1126 | help_st(a); 1127 | } 1128 | 1129 | void mc6809::stb() 1130 | { 1131 | insn = "STB"; 1132 | help_st(b); 1133 | } 1134 | 1135 | void mc6809::std() 1136 | { 1137 | insn = "STD"; 1138 | help_st(d); 1139 | } 1140 | 1141 | void mc6809::stx() 1142 | { 1143 | insn = "STX"; 1144 | help_st(x); 1145 | } 1146 | 1147 | void mc6809::sty() 1148 | { 1149 | insn = "STY"; 1150 | help_st(y); 1151 | } 1152 | 1153 | void mc6809::sts() 1154 | { 1155 | insn = "STS"; 1156 | help_st(s); 1157 | } 1158 | 1159 | void mc6809::stu() 1160 | { 1161 | insn = "STU"; 1162 | help_st(u); 1163 | } 1164 | 1165 | void mc6809::suba() 1166 | { 1167 | insn = "SUBA"; 1168 | help_sub(a); 1169 | } 1170 | 1171 | void mc6809::subb() 1172 | { 1173 | insn = "SUBB"; 1174 | help_sub(b); 1175 | } 1176 | 1177 | void mc6809::subd() 1178 | { 1179 | insn = "SUBD"; 1180 | Word m = fetch_word_operand(); 1181 | int t = d - m; 1182 | 1183 | cc.bit.v = btst((DWord)(d ^ m ^ t ^(t >> 1)), 15); 1184 | cc.bit.c = btst((DWord)t, 16); 1185 | cc.bit.n = btst((DWord)t, 15); 1186 | d = t & 0xffff; 1187 | cc.bit.z = !d; 1188 | } 1189 | 1190 | void mc6809::swi() 1191 | { 1192 | insn = "SWI"; 1193 | cc.bit.e = 1; 1194 | help_psh(0xff, s, u); 1195 | cc.bit.f = cc.bit.i = 1; 1196 | pc = read_word(0xfffa); 1197 | cycles += 4; 1198 | } 1199 | 1200 | void mc6809::swi2() 1201 | { 1202 | insn = "SWI2"; 1203 | cc.bit.e = 1; 1204 | help_psh(0xff, s, u); 1205 | pc = read_word(0xfff4); 1206 | cycles += 4; 1207 | } 1208 | 1209 | void mc6809::swi3() 1210 | { 1211 | insn = "SWI3"; 1212 | cc.bit.e = 1; 1213 | help_psh(0xff, s, u); 1214 | pc = read_word(0xfff2); 1215 | cycles += 4; 1216 | } 1217 | 1218 | void mc6809::sync() 1219 | { 1220 | insn = "SYNC"; 1221 | waiting_sync = true; 1222 | ++cycles; 1223 | } 1224 | 1225 | void mc6809::tfr() 1226 | { 1227 | insn = "TFR"; 1228 | Byte w = fetch_operand(); 1229 | int r1 = (w & 0xf0) >> 4; 1230 | int r2 = (w & 0x0f) >> 0; 1231 | 1232 | if (r1 <= 5 && r2 <= 5) { 1233 | wordrefreg(r2) = wordrefreg(r1); 1234 | } else if (r1 >= 8 && r1 <= 11 && r2 >= 8 && r2 <= 11) { 1235 | byterefreg(r2) = byterefreg(r1); 1236 | } else { 1237 | invalid("invalid TFR operand"); 1238 | } 1239 | 1240 | cycles += 4; 1241 | } 1242 | 1243 | void mc6809::tsta() 1244 | { 1245 | insn = "TSTA"; 1246 | help_tst(a); 1247 | } 1248 | 1249 | void mc6809::tstb() 1250 | { 1251 | insn = "TSTB"; 1252 | help_tst(b); 1253 | } 1254 | 1255 | void mc6809::tst() 1256 | { 1257 | insn = "TST"; 1258 | Word addr = fetch_effective_address(); 1259 | Byte m = read(addr); 1260 | help_tst(m); 1261 | ++cycles; 1262 | } 1263 | -------------------------------------------------------------------------------- /mc6850.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // 3 | // mc6850.cpp 4 | // 5 | // (C) R.P.Bellis 1994 6 | // 7 | 8 | #include "mc6850.h" 9 | #include "bits.h" 10 | 11 | mc6850::mc6850(mc6850_impl& impl, uint16_t interval) 12 | : impl(impl), 13 | interval(interval), 14 | IRQ(sr, 7, true) // ~IRQ = SR bit 7 15 | { 16 | reset(); 17 | } 18 | 19 | mc6850::~mc6850() 20 | { 21 | } 22 | 23 | void mc6850::reset() 24 | { 25 | cr = 0; // Clear all control flags 26 | sr = TDRE; // Clear all status bits except TDRE 27 | cycles = 0; 28 | } 29 | 30 | void mc6850::tick(uint8_t ticks) 31 | { 32 | if ((sr & IRQB) == 0) { 33 | if (((sr & TDRE) && ((cr & 0x60) == 0x20)) || 34 | ((sr & RDRF) && ((cr & 0x80) == 0x80))) 35 | { 36 | sr |= IRQB; 37 | } 38 | } 39 | 40 | cycles += ticks; 41 | if (cycles < interval) return; 42 | cycles = 0; 43 | 44 | // Check for a received character if one isn't available 45 | if ((sr & RDRF) == 0) { 46 | // If input is ready read a character 47 | if (impl.poll_read()) { 48 | rd = impl.read(); 49 | sr |= RDRF; 50 | } 51 | } 52 | 53 | if ((sr & TDRE) == 0) { 54 | impl.write(td); 55 | sr |= TDRE; 56 | } 57 | } 58 | 59 | Byte mc6850::read(Word offset) 60 | { 61 | switch (offset & 1) { 62 | case 0: // status register 63 | return sr; 64 | break; 65 | case 1: // read data 66 | default: 67 | sr &= ~(RDRF | IRQB); 68 | return rd; 69 | break; 70 | } 71 | } 72 | 73 | void mc6850::write(Word offset, Byte val) 74 | { 75 | switch (offset & 1) { 76 | case 0: // control register 77 | cr = val; 78 | if ((cr & 0x03) == 0x03) { 79 | reset(); 80 | } 81 | break; 82 | case 1: // data register 83 | td = val; 84 | sr &= ~(IRQB | TDRE); 85 | break; 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /mc6850.h: -------------------------------------------------------------------------------- 1 | // 2 | // 3 | // mc6850.h 4 | // 5 | // (C) R.P.Bellis 1994 6 | // 7 | 8 | #pragma once 9 | 10 | #include "device.h" 11 | #include "wiring.h" 12 | 13 | class mc6850_impl { 14 | 15 | public: 16 | virtual bool poll_read() = 0; 17 | virtual bool poll_write() { return true; }; 18 | 19 | public: 20 | virtual Byte read() = 0; 21 | virtual void write(Byte) = 0; 22 | 23 | public: 24 | mc6850_impl() = default; 25 | virtual ~mc6850_impl() = default; 26 | }; 27 | 28 | class mc6850 : virtual public ActiveMappedDevice { 29 | 30 | protected: 31 | enum sr_flags : Byte { 32 | RDRF = 0x01, 33 | TDRE = 0x02, 34 | DCDB = 0x04, 35 | CTSB = 0x08, 36 | FE = 0x10, 37 | OVRN = 0x20, 38 | PE = 0x40, 39 | IRQB = 0x80 40 | }; 41 | 42 | // Internal registers 43 | protected: 44 | 45 | Byte td, rd, cr, sr; 46 | 47 | // Access to real IO device 48 | mc6850_impl& impl; 49 | uint16_t interval; // how often to poll 50 | uint16_t cycles; // cycles since last poll 51 | 52 | // Initialisation functions 53 | 54 | protected: 55 | virtual void tick(uint8_t); 56 | virtual void reset(); 57 | 58 | // Read and write functions 59 | public: 60 | 61 | virtual Byte read(Word offset); 62 | virtual void write(Word offset, Byte val); 63 | 64 | // Other exposed interfaces 65 | public: 66 | OutputPinReg IRQ; 67 | 68 | // Public constructor and destructor 69 | 70 | mc6850(mc6850_impl& impl, uint16_t interval = 1000); 71 | virtual ~mc6850(); 72 | 73 | }; 74 | -------------------------------------------------------------------------------- /memory.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // 3 | // memory.c 4 | // 5 | // (C) R.P.Bellis 2021 6 | // 7 | // 8 | 9 | #include 10 | #include 11 | #include "memory.h" 12 | 13 | Byte fread_hex_byte(FILE *fp) 14 | { 15 | char str[3]; 16 | long l; 17 | 18 | str[0] = fgetc(fp); 19 | str[1] = fgetc(fp); 20 | str[2] = '\0'; 21 | 22 | l = strtol(str, NULL, 16); 23 | return (Byte)(l & 0xff); 24 | } 25 | 26 | Word fread_hex_word(FILE *fp) 27 | { 28 | Word ret; 29 | 30 | ret = fread_hex_byte(fp); 31 | ret <<= 8; 32 | ret |= fread_hex_byte(fp); 33 | 34 | return ret; 35 | } 36 | 37 | void ROM::load_intelhex(const char *filename, Word base) 38 | { 39 | FILE *fp; 40 | int done = 0; 41 | 42 | fp = fopen(filename, "r"); 43 | if (!fp) { 44 | perror("filename"); 45 | exit(EXIT_FAILURE); 46 | } 47 | 48 | while (!done) { 49 | Byte n, t; 50 | Word addr; 51 | Byte b; 52 | 53 | (void)fgetc(fp); 54 | n = fread_hex_byte(fp); 55 | addr = fread_hex_word(fp); 56 | t = fread_hex_byte(fp); 57 | if (t == 0x00) { 58 | while (n--) { 59 | b = fread_hex_byte(fp); 60 | if ((addr >= base) && (addr < ((DWord)base + size))) { 61 | memory[addr - base] = b; 62 | } 63 | ++addr; 64 | } 65 | } else if (t == 0x01) { 66 | done = 1; 67 | } 68 | // Read and discard checksum byte 69 | (void)fread_hex_byte(fp); 70 | if (fgetc(fp) == '\r') (void)fgetc(fp); 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /memory.h: -------------------------------------------------------------------------------- 1 | // 2 | // 3 | // memory.h 4 | // 5 | // (C) R.P.Bellis 2021 6 | // 7 | // 8 | 9 | #pragma once 10 | 11 | #include "device.h" 12 | 13 | /* 14 | * generic memory interface, dynamically assigned space 15 | */ 16 | class GenericMemory : public MappedDevice { 17 | 18 | protected: 19 | std::vector memory; 20 | size_t size; 21 | 22 | public: 23 | GenericMemory(size_t size) : memory(size), size(size) {}; 24 | 25 | public: 26 | virtual Byte read(Word offset) { 27 | return (offset < size) ? memory[offset] : 0xff; 28 | }; 29 | 30 | virtual void write(Word offset, Byte val) { 31 | if (offset < size) { 32 | memory[offset] = val; 33 | } 34 | }; 35 | }; 36 | 37 | /* 38 | * RAM: can be written to 39 | */ 40 | class RAM : public GenericMemory { 41 | 42 | public: 43 | RAM(size_t size) : GenericMemory(size) {}; 44 | 45 | }; 46 | 47 | /* 48 | * ROM: can't be written 49 | * can be pre-loaded from a hex file 50 | */ 51 | class ROM : public GenericMemory { 52 | 53 | public: 54 | ROM(size_t size) : GenericMemory(size) {}; 55 | 56 | virtual void write(Word offset, Byte val) { // no-op 57 | (void)offset; 58 | (void)val; 59 | } 60 | 61 | public: 62 | void load_intelhex(const char *filename, Word base); 63 | 64 | }; 65 | 66 | /* 67 | * ROM_Data 68 | * 69 | * For use when embedding static firmware data inside a compiled image 70 | */ 71 | class ROM_Data : public MappedDevice { 72 | 73 | protected: 74 | const uint8_t* memory; 75 | size_t size; // size of virtual device 76 | size_t memsize; // size of allocated data 77 | 78 | public: 79 | ROM_Data(const uint8_t* p, size_t size) : memory(p), size(size), memsize(size) {}; 80 | 81 | ROM_Data(const uint8_t* p, size_t size, size_t memsize) : memory(p), size(size), memsize(memsize) {}; 82 | 83 | virtual Byte read(Word offset) { 84 | if (offset < size && offset < memsize) { 85 | return memory[offset]; 86 | } else { 87 | return 0xff; 88 | } 89 | } 90 | 91 | virtual void write(Word offset, Byte val) { // no-op 92 | (void)offset; 93 | (void)val; 94 | } 95 | }; 96 | -------------------------------------------------------------------------------- /term.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // 3 | // term.cpp 4 | // 5 | // (C) R.P.Bellis 1994 6 | // 7 | 8 | #include 9 | #include 10 | #include "term.h" 11 | 12 | //------------------------------------------------------------------------ 13 | // Machine dependent Terminal implementations 14 | //------------------------------------------------------------------------ 15 | 16 | //------------------------------------------------------------------------ 17 | #if defined(_POSIX_SOURCE) 18 | 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | 27 | Terminal::Terminal(USim& sys) : sys(sys) 28 | { 29 | input = stdin; 30 | output = stdout; 31 | input_fd = fileno(input); 32 | 33 | // Set input and output to be unbuffered 34 | setbuf(input, (char *)0); 35 | setbuf(output, (char *)0); 36 | 37 | // Get copies of startup terminal attributes 38 | tcgetattr(input_fd, &oattr); 39 | tcgetattr(input_fd, &nattr); 40 | 41 | setup(); 42 | } 43 | 44 | Terminal::~Terminal() 45 | { 46 | reset(); 47 | } 48 | 49 | void Terminal::setup() 50 | { 51 | nattr.c_lflag &= ~ICANON; 52 | nattr.c_lflag &= ~ISIG; 53 | 54 | nattr.c_lflag &= ~ECHO; 55 | nattr.c_lflag |= ECHOE; 56 | 57 | nattr.c_iflag &= ~ICRNL; 58 | nattr.c_oflag &= ~ONLCR; 59 | 60 | tcsetattr(input_fd, TCSANOW, &nattr); 61 | } 62 | 63 | void Terminal::reset() 64 | { 65 | tcsetattr(input_fd, TCSANOW, &oattr); 66 | } 67 | 68 | bool Terminal::real_poll_read() 69 | { 70 | fd_set fds; 71 | 72 | // Uses minimal (10us) delay in select(2) call to 73 | // ensure that idling simulations don't chew 74 | // up masses of CPU time 75 | static struct timeval tv = { 0L, 10L }; 76 | 77 | FD_ZERO(&fds); 78 | FD_SET(input_fd, &fds); 79 | (void)select(FD_SETSIZE, &fds, NULL, NULL, &tv); 80 | 81 | return FD_ISSET(input_fd, &fds); 82 | } 83 | 84 | Byte Terminal::real_read() 85 | { 86 | return fgetc(input); 87 | } 88 | 89 | void Terminal::write(Byte ch) 90 | { 91 | fputc(ch, output); 92 | } 93 | 94 | //------------------------------------------------------------------------ 95 | #elif defined(__MSDOS__) || defined(__BORLANDC__) 96 | 97 | #include 98 | 99 | Terminal::Terminal() 100 | { 101 | } 102 | 103 | Terminal::~Terminal() 104 | { 105 | } 106 | 107 | bool Terminal::real_poll_read() 108 | { 109 | return kbhit(); 110 | } 111 | 112 | Byte Terminal::real_read() 113 | { 114 | return getch(); 115 | } 116 | 117 | void Terminal::write(Byte ch) 118 | { 119 | putch(ch); 120 | } 121 | 122 | void Terminal::setup() 123 | { 124 | } 125 | 126 | void Terminal::reset() 127 | { 128 | } 129 | 130 | #endif 131 | //------------------------------------------------------------------------ 132 | 133 | //------------------------------------------------------------------------ 134 | // Machine independent part, handles ssh-like tilde-escapes 135 | //------------------------------------------------------------------------ 136 | 137 | void Terminal::tilde_escape_help() 138 | { 139 | fprintf(stderr, "\r\nSupported escape sequences:\r\n"); 140 | fprintf(stderr, " ~. - terminate emulator\r\n"); 141 | fprintf(stderr, " ~? - this message\r\n"); 142 | fprintf(stderr, " ~~ - send the escape character by typing it twice\r\n"); 143 | tilde_escape_help_other(); 144 | fprintf(stderr, "(Note that escapes are only recognized immediately after newline.)\r\n"); 145 | } 146 | 147 | bool Terminal::poll_read() 148 | { 149 | if (read_data_available) { 150 | return true; 151 | } 152 | 153 | bool ready = real_poll_read(); 154 | if (!ready) { 155 | read_data_available = false; 156 | return read_data_available; 157 | } 158 | 159 | Byte ch = read_data = real_read(); 160 | read_data_available = true; 161 | 162 | switch (tilde_escape_phase) { 163 | case 0: 164 | if (ch == 0x0a || ch == 0x0d) { 165 | tilde_escape_phase = 1; 166 | } 167 | break; 168 | 169 | case 1: 170 | if (ch == '~') { 171 | tilde_escape_phase = 2; 172 | read_data_available = false; 173 | } else { 174 | tilde_escape_phase = 0; 175 | } 176 | break; 177 | 178 | case 2: 179 | tilde_escape_phase = 0; 180 | read_data_available = false; 181 | 182 | switch (ch) { 183 | case '~': 184 | read_data_available = true; 185 | break; 186 | case '.': 187 | sys.halt(); 188 | break; 189 | case '?': 190 | tilde_escape_help(); 191 | break; 192 | default: 193 | tilde_escape_do_other(ch); 194 | break; 195 | } 196 | break; 197 | 198 | default: 199 | assert(false); 200 | break; 201 | } 202 | 203 | return read_data_available; 204 | } 205 | 206 | void Terminal::tilde_escape_do_other(char ch) 207 | { 208 | (void)ch; 209 | } 210 | 211 | void Terminal::tilde_escape_help_other() 212 | { 213 | } 214 | 215 | Byte Terminal::read() 216 | { 217 | read_data_available = false; 218 | return read_data; 219 | } 220 | -------------------------------------------------------------------------------- /term.h: -------------------------------------------------------------------------------- 1 | // 2 | // 3 | // term.h 4 | // 5 | // (C) R.P.Bellis 1994 6 | // 7 | 8 | #pragma once 9 | 10 | #include 11 | #include "usim.h" 12 | #include "mc6850.h" 13 | 14 | #ifdef _POSIX_SOURCE 15 | #include 16 | #endif 17 | 18 | class Terminal : virtual public mc6850_impl { 19 | 20 | protected: 21 | USim& sys; 22 | Byte read_data; 23 | bool read_data_available = false; 24 | int tilde_escape_phase = 0; 25 | 26 | void tilde_escape_help(); 27 | virtual void tilde_escape_help_other(); 28 | virtual void tilde_escape_do_other(char ch); 29 | bool real_poll_read(); 30 | Byte real_read(); 31 | 32 | #ifdef _POSIX_SOURCE 33 | FILE* input; 34 | FILE* output; 35 | int input_fd; 36 | struct termios oattr, nattr; 37 | #endif // _POSIX_SOURCE 38 | 39 | public: 40 | 41 | virtual bool poll_read(); 42 | virtual void write(Byte); 43 | virtual Byte read(); 44 | 45 | public: 46 | virtual void setup(); 47 | virtual void reset(); 48 | 49 | // Public constructor and destructor 50 | public: 51 | Terminal(USim& sys); 52 | virtual ~Terminal(); 53 | 54 | }; 55 | -------------------------------------------------------------------------------- /tests/tbasic.hex: -------------------------------------------------------------------------------- 1 | :20F000007EF00310CE06CC10FF0086CC0149FD0080FD0082FD0084BDF15F8EF07ABDF1589C 2 | :20F0200010FE00867F0093BDF15FBE0080BF00888E0000BF008C7D00932605863ABDF8030C 3 | :20F04000BDF1B4BDF322240E292DBDF290810427DFBDF23720CA3410BE0082BC0084351051 4 | :20F0600027037EF180C30000270D340683270F350622048D1720B97EF17754494E5920560F 5 | :20F08000312E3338204D4336383039043406BDF290BF008EA6E4BE0088BC0082270510A368 6 | :20F0A000842403BE0080BDF403BF0088252BBF008A3002A680810426FABC00822712A68039 7 | :20F0C000BF0090BE008AA780BF008ABE009020E9BE008ABF0082BF0084BE008EC6FF5CA6F3 8 | :20F0E00080810426F95D2603326239301FCB04301F5AA684812027F78604A7014FBE008228 9 | :20F10000BF0090F30082FD0082FD0084BDF39A2409BF0082BF00847EF16FBE0082BF008AC9 10 | :20F12000BE0090BC0088270CA682BF0090BE008AA78220E93506BE0088ED81BF0090BE001D 11 | :20F140008EA680BF008EBE0090A780BF0090810426EC39BDF8033001A684810426F5398EA0 12 | :20F16000F1688DF47F0092390D0A7F000000048D26534F525259048D1E57484154203F0439 13 | :20F180008D15484F57203F048D0D425245414B048D0553544F50048DC68607BDF803FC0009 14 | :20F1A0008CBDF6A88620BDF80335108DAB8DB07EF0208DAB8E0100BDF7F881202514817F75 15 | :20F1C00027F58C0148260486072002A780BDF80320E581082725811827D8810A2732810DA2 16 | :20F1E00026D57D00932705BDF80320073410BDF15F35108604A7848E0100398C010027B77B 17 | :20F20000301F8608BDF8038620BDF803860820BD1A0176009320B630018D75810426F8BD03 18 | :20F22000F571B6008CBA008D2716BC008226037EF180EC81FD008CBDF7F38D0825033406B8 19 | :20F24000397EF5828D4ABF00888EF78EA68081042606BE00881A0139BF0090BE0088BF008A 20 | :20F260008EBE008EA18426193001BF008EBE0090A680BF0090810426E8EC84BE008E1CFEA6 21 | :20F2800039BE0090A680810426FA300220BE3001A684812027F8398D1A2422814125118152 22 | :20F2A00046220D80371CFE3981412504815A230D1A0139813025F9813922F580301CFE39E2 23 | :20F2C0008DCE8DE425131F89A6018DDC24E23001C041584FF300861CFE39BDF5503406BDCE 24 | :20F2E000F290812C270981291A0127157EF1773001BDF4833402BDF2908129350226ED1CDE 25 | :20F30000FE3001BF0088ADF1BE00881CFE39BDF290812D260D30018D092506405082001C00 26 | :20F32000FC39BDF290BDF2B3242F81241A01266030016FE26FE2A684BDF297254F30013442 27 | :20F34000103402EC6385F0264A5849584958495849EBE0ED62351020DD300134026FE2A6F5 28 | :20F3600084BDF2B32526300134103402EC63584929215849291DE363291958492915EBE45A 29 | :20F380008900290FED633261351020D335061CFE1CFD39AE6132651A033910FF008AFC0059 30 | :20F3A0008A830030B3008439BDF53D34063410E6F802351032624F39BDF53D3406BDF2908A 31 | :20F3C000813D27037EF1773001BDF483BDF5713410E7F802351032627EF222BDF290BF0049 32 | :20F3E000888EF3ECBDF24C250234063955535204F2DA5045454B04F3A84D454D04F39A0481 33 | :20F40000BE0080BC008226031A033910A38426031CFC3924051A011CFD39340286043001B9 34 | :20F420003001A18426FA3502300120D78D5534065FBDF290813D2723813C261030015CBDF8 35 | :20F44000F290813E26113001CB042013813E265F3001CB04BDF290813D26043001CB023464 36 | :20F46000048D203410A3631FA8441F8948483404ABE0840626014C5FA4622701534F35101A 37 | :20F480003263396FE26FE2BDF290812D2717812B260230018D1CE3E4EDE4BDF290812B2779 38 | :20F4A000F1812D260A30018D094050820020E7350639BDF5253406BDF290812A2748812F0F 39 | :20F4C000270335063930018D5C341030623406A884BDF56430E4BDF5643402861134024FA6 40 | :20F4E0005FA3622406E3621CFE20021A016967696659496AE426EAA66132644D2A04306299 41 | :20F500008D66351020B130018D1B3404E6623DA661E761E6E43DA662E76235043DABE4ABF5 42 | :20F5200061EDE42092BDF2C0250934101F01EC84351039BDF32224FABDF3DB24F58D113492 43 | :20F5400002BDF2908129350226033001397EF177BDF39A24037EF16FBDF290812826EE3095 44 | :20F56000017EF4836D842A086084600124026A84393402BDF290810427037EF17730013570 45 | :20F580000239BDF2C024037EF1773406BDF290813D27037EF1773001BDF4838DD4BF008860 46 | :20F5A0003510ED84BE00887EF222BDF42C5D27037EF2377EF219BDF4838DB6BDF4002510CC 47 | :20F5C0007EF232BDF4838DA9BF0088BDF40024037EF180BDF39A24037EF16FFC0088340604 48 | :20F5E000FC008C3406BDF2323506FD008C35107EF222BDF290812C2736813B273E810427B7 49 | :20F60000258122260630018D432009BDF48334108D483510BDF290812C2714813B271C8193 50 | :20F620000427037EF1773410BDF15F35102015C6078620BDF803F5009226F63001BDF290AD 51 | :20F64000810426B130017EF222BDF803A680810426037EF177812226F0394D2A0D40508291 52 | :20F66000003402862DBDF80335028EF69C300210A38424058CF6A626F47F009010A3842553 53 | :20F6800007A3847C009020F434028630BB0090BDF80335028CF6A62704300220DC39271005 54 | :20F6A00003E80064000A00018EF6A020CCBDF2C0253F3406BF0088863FBDF803BDF1B4BDF0 55 | :20F6C000F290810427F1BDF30E240B8EF706BDF158BDF15F20E1BF008E3510ED84BE008836 56 | :20F6E000BDF290812C27037EF21F3001BDF2C024037EF17734063410BE008EBDF290812C02 57 | :20F7000026BD300120B952452D454E54455204BE008686346F804A26FBBE00807EF22ABDC9 58 | :20F72000F32224094F5FFD0088867F2019FD0088BDF290812C2705B60088200A3001BDF330 59 | :20F740002224037EF177BDF5713406FC0088BF0088BDF400BC00822728350610A384252855 60 | :20F760003406EC813410BDF6A835108620BDF803BDF15830013410BDF15F3510BDF7F3200C 61 | :20F78000D332628603BDF803BE00887EF2224C455404F582494604F5AA474F544F04F5B66F 62 | :20F7A000474F53554204F5C352455455524E04F571504F4B4504F3B85052494E5404F5F26D 63 | :20F7C000494E50555404F6AD52454D04F21953544F5004F190454E4404F19052554E04F7E8 64 | :20F7E0000F4C49535404F71F4E455704F00B3F04F5F204BDF822270ABDF809810326037E9C 65 | :20F80000F188397C00927EF8138D1727FCB6C001847F393402B6C000850227F93502B7C024 66 | :15F8200001393402B6C00085202705B6C00120F485013502399B 67 | :02FFFE00F00011 68 | :00000001FF 69 | -------------------------------------------------------------------------------- /tests/tbasic.s: -------------------------------------------------------------------------------- 1 | ; NAM TB01V137 2 | ; WRITTEN 20-OCT-77 BY JOHN BYRNS 3 | ; REVISED 30-DEC-77 4 | ; REVISED 18-JAN-78 5 | ; REVISED 10-APR-78 6 | ; REVISED 08-MAY-79 TO ELIMINATE USE OF SP 7 | ; REVISED 24-JAN-80 TO USE 6801 ON CHIP RAM 8 | ; REVISED 26-JAN-80 FOR NEW 6801 INSTRUCTIONS 9 | ; REVISED 24-JUL-81 FOR WHISTON BOARD 10 | ; REVISED 24-SEP-81 INCLUDE USER FUNCTION 11 | ; REVISED 08-APR-82 MAKE STANDALONE INCLUDE HEX CONSTANTS AND MEM FUNCTION 12 | ; REVISED 21-NOV-84 FOR 6809 13 | ; 14 | ; 15 | 16 | EOL EQU $04 17 | ETX EQU $03 18 | SPACE EQU $20 19 | CR EQU $0D 20 | LF EQU $0A 21 | BS EQU $08 22 | CAN EQU $18 23 | BELL EQU $07 24 | FILL EQU $00 25 | DEL EQU $7F 26 | BSIZE EQU 73 27 | STKCUS EQU 48 28 | ; 29 | ACIA EQU $C000 30 | RMCR EQU ACIA 31 | TRCS EQU ACIA 32 | RECEV EQU ACIA+1 33 | TRANS EQU ACIA+1 34 | CNTL1 EQU $03 35 | CNTL2 EQU $15 36 | RDRF EQU $01 37 | ORFE EQU $20 38 | TDRE EQU $02 39 | 40 | ; EDIT THE FOLLOWING EQUATES TO REFLECT THE 41 | ; DESIRED ROM AND RAM LAYOUT 42 | LORAM EQU $0080 ;ADDRESS OF DIRECT PAGE SCRATCH RAM 43 | BUFFER EQU $0100 ;ADDRESS OF MAIN RAM 44 | RAMSIZ EQU $0600 ;SIZE OF MAIN RAM 45 | ROMADR EQU $F000 ;ADDRESS OF TINY BASIC ROM 46 | ; 47 | RAMBEG EQU BUFFER+BSIZE 48 | RAMEND EQU BUFFER+RAMSIZ 49 | ; 50 | 51 | ORG LORAM 52 | USRBAS RMB 2 53 | USRTOP RMB 2 54 | STKLIM RMB 2 55 | STKTOP RMB 2 56 | CURSOR RMB 2 57 | SAVESP RMB 2 58 | LINENB RMB 2 59 | SCRTCH RMB 2 60 | CHAR RMB 2 61 | ZONE RMB 1 62 | MODE RMB 1 63 | RESRVD RMB 1 64 | LOEND EQU * 65 | ; 66 | ORG ROMADR 67 | BASIC JMP SETUP 68 | ;WARMS LDS STKTOP 69 | ; JSR INTEEE 70 | ; BRA WMS05 71 | SETUP LDS #RAMEND-52 72 | SET03 STS STKTOP 73 | ; JSR INTEEE 74 | CLEAR LDD #RAMBEG 75 | STD USRBAS 76 | STD USRTOP 77 | CLR02 STD STKLIM 78 | WMS05 JSR CRLF 79 | LDX #VSTR 80 | JSR PUTSTR 81 | CMDB LDS STKTOP 82 | CLR MODE 83 | JSR CRLF 84 | LDX USRBAS 85 | STX CURSOR 86 | CMDE LDX #0000 87 | STX LINENB 88 | TST MODE 89 | BNE CMD01 90 | LDA #':' 91 | JSR PUTCHR 92 | CMD01 JSR GETLIN 93 | JSR TSTNBR 94 | BCC CMD02 95 | BVS CMD05 96 | JSR SKIPSP 97 | CMPA #EOL 98 | BEQ CMDE 99 | JSR MSLINE 100 | BRA CMDB 101 | CMD02 PSHS X 102 | LDX USRTOP 103 | CMPX STKLIM 104 | PULS X 105 | BEQ CMD03 106 | JMP ERRORR 107 | CMD03 ADDD #0 108 | BEQ CMD05 109 | CMD04 PSHS D 110 | SUBD #9999 111 | PULS D 112 | BHI CMD05 113 | BSR EDITOR 114 | BRA CMDE 115 | CMD05 JMP ERRORS 116 | VSTR FCC "TINY V1.38 MC6809" 117 | FCB EOL 118 | ;***************************** 119 | ;***************************** 120 | EDITOR PSHS D 121 | JSR SKIPSP 122 | STX SCRTCH 123 | LDA 0,S 124 | LDX CURSOR 125 | CMPX USRTOP 126 | BEQ ED00 127 | CMPD 0,X 128 | BCC ED01 129 | ED00 LDX USRBAS 130 | ED01 JSR FNDLIN 131 | STX CURSOR 132 | BCS ED04 133 | STX SAVESP 134 | LEAX 2,X 135 | ED02 LDA ,X+ 136 | CMPA #EOL 137 | BNE ED02 138 | ED03 CMPX USRTOP 139 | BEQ ED35 140 | LDA ,X+ 141 | STX CHAR 142 | LDX SAVESP 143 | STA ,X+ 144 | STX SAVESP 145 | LDX CHAR 146 | BRA ED03 147 | ED35 LDX SAVESP 148 | STX USRTOP 149 | STX STKLIM 150 | ED04 LDX SCRTCH 151 | LDB #-1 152 | ED05 INCB 153 | LDA ,X+ 154 | CMPA #EOL 155 | BNE ED05 156 | TSTB 157 | BNE ED55 158 | LEAS 2,S 159 | RTS 160 | ED55 LEAX -1,X 161 | ADDB #4 162 | ED06 LEAX -1,X 163 | DECB 164 | LDA 0,X 165 | CMPA #SPACE 166 | BEQ ED06 167 | LDA #EOL 168 | STA 1,X 169 | CLRA 170 | LDX USRTOP 171 | STX CHAR 172 | ADDD USRTOP 173 | STD USRTOP 174 | STD STKLIM 175 | JSR TSTSTK 176 | BCC ED07 177 | STX USRTOP 178 | STX STKLIM 179 | JMP ERRORF 180 | ED07 LDX USRTOP 181 | ED08 STX SAVESP 182 | LDX CHAR 183 | CMPX CURSOR 184 | BEQ ED09 185 | LDA ,-X 186 | STX CHAR 187 | LDX SAVESP 188 | STA ,-X 189 | BRA ED08 190 | ED09 PULS D 191 | LDX CURSOR 192 | STD ,X++ 193 | STX CHAR 194 | ED10 LDX SCRTCH 195 | LDA ,X+ 196 | STX SCRTCH 197 | LDX CHAR 198 | STA ,X+ 199 | STX CHAR 200 | CMPA #EOL 201 | BNE ED10 202 | RTS 203 | ;***************************** 204 | ;***************************** 205 | PUTS01 JSR PUTCHR 206 | LEAX 1,X 207 | PUTSTR LDA 0,X 208 | CMPA #EOL 209 | BNE PUTS01 210 | RTS 211 | ;***************************** 212 | ;***************************** 213 | CRLF LDX #CRLFST 214 | BSR PUTSTR 215 | CLR ZONE 216 | RTS 217 | CRLFST FCB CR,LF,DEL,FILL,FILL,FILL,EOL 218 | ;***************************** 219 | ;***************************** 220 | ERRORF BSR ER01 221 | FCC "SORRY" 222 | FCB EOL 223 | ERRORS BSR ER01 224 | FCC "WHAT ?" 225 | FCB EOL 226 | ERRORR BSR ER01 227 | FCC "HOW ?" 228 | FCB EOL 229 | BREAK BSR ER01 230 | FCC "BREAK" 231 | FCB EOL 232 | END BSR ER01 233 | FCC "STOP" 234 | FCB EOL 235 | ER01 BSR CRLF 236 | LDA #BELL 237 | JSR PUTCHR 238 | LDD LINENB 239 | JSR PRNT4 240 | LDA #SPACE 241 | JSR PUTCHR 242 | PULS X 243 | BSR PUTSTR 244 | BSR CRLF 245 | JMP CMDB 246 | ;***************************** 247 | ;***************************** 248 | GL00 BSR CRLF 249 | GETLIN LDX #BUFFER 250 | GL03 JSR GETCHR 251 | CMPA #SPACE 252 | BCS GL05 253 | CMPA #$7F 254 | BEQ GL03 255 | CMPX #BUFFER+BSIZE-1 256 | BNE GL04 257 | LDA #BELL 258 | BRA GL02 259 | GL04 STA ,X+ 260 | GL02 JSR PUTCHR 261 | BRA GL03 262 | GL05 CMPA #BS 263 | BEQ GL07 264 | CMPA #CAN 265 | BEQ GL00 266 | CMPA #LF 267 | BEQ GL09 268 | CMPA #CR 269 | BNE GL03 270 | TST MODE 271 | BEQ GL06 272 | JSR PUTCHR 273 | BRA GL08 274 | GL06 PSHS X 275 | JSR CRLF 276 | PULS X 277 | GL08 LDA #EOL 278 | STA 0,X 279 | LDX #BUFFER 280 | RTS 281 | GL07 CMPX #BUFFER 282 | BEQ GL03 283 | LEAX -1,X 284 | LDA #BS 285 | JSR PUTCHR 286 | LDA #SPACE 287 | JSR PUTCHR 288 | LDA #BS 289 | BRA GL02 290 | GL09 ORCC #$01 291 | ROR MODE 292 | BRA GL02 293 | ;***************************** 294 | ;***************************** 295 | REM00 LEAX 1,X 296 | REM BSR SKIPSP 297 | CMPA #EOL 298 | BNE REM00 299 | ENDSMT JSR TSTEOL 300 | ENDS02 LDA LINENB 301 | ORA LINENB+1 302 | BEQ REM09 303 | REM05 CMPX USRTOP 304 | BNE NXTLIN 305 | JMP ERRORR 306 | NXTLIN LDD ,X++ 307 | STD LINENB 308 | MSLINE JSR TSTBRK 309 | BSR IFAN 310 | BCS IMPLET 311 | PSHS D 312 | REM09 RTS 313 | IMPLET JMP LET 314 | ;***************************** 315 | ;***************************** 316 | IFAN BSR SKIPSP 317 | STX CURSOR 318 | LDX #VERBT 319 | FAN00 LDA ,X+ 320 | CMPA #EOL 321 | BNE FAN04 322 | LDX CURSOR 323 | ORCC #$01 324 | RTS 325 | FAN04 STX CHAR 326 | LDX CURSOR 327 | STX SCRTCH 328 | FAN05 LDX SCRTCH 329 | CMPA 0,X 330 | BNE FAN07 331 | LEAX 1,X 332 | STX SCRTCH 333 | LDX CHAR 334 | LDA ,X+ 335 | STX CHAR 336 | CMPA #EOL 337 | BNE FAN05 338 | LDD 0,X 339 | LDX SCRTCH 340 | ANDCC #$FE 341 | RTS 342 | FAN07 LDX CHAR 343 | FAN08 LDA ,X+ 344 | CMPA #EOL 345 | BNE FAN08 346 | LEAX 2,X 347 | BRA FAN00 348 | ;***************************** 349 | ;***************************** 350 | NXTNSP LEAX 1,X 351 | SKIPSP LDA 0,X 352 | CMPA #SPACE 353 | BEQ NXTNSP 354 | RTS 355 | ;***************************** 356 | ;***************************** 357 | TSTHEX BSR TSTDIG 358 | BCC TST05 359 | CMPA #'A' 360 | BCS TST03 361 | CMPA #'F' 362 | BHI TST03 363 | SUBA #'A'-10 364 | ANDCC #$FE 365 | RTS 366 | ;***************************** 367 | ;***************************** 368 | TSTLTR CMPA #'A' 369 | BCS TST03 370 | CMPA #'Z' 371 | BLS TST05 372 | TST03 ORCC #$01 373 | RTS 374 | ;***************************** 375 | ;***************************** 376 | TSTDIG CMPA #'0' 377 | BCS TST03 378 | CMPA #'9' 379 | BHI TST03 380 | SUBA #'0' 381 | TST05 ANDCC #$FE 382 | RTS 383 | ;***************************** 384 | ;***************************** 385 | TSTVAR BSR SKIPSP 386 | BSR TSTLTR 387 | BCS TSTV03 388 | TFR A,B 389 | LDA 1,X 390 | BSR TSTLTR 391 | BCC TST03 392 | LEAX 1,X 393 | SUBB #'A' 394 | ASLB 395 | CLRA 396 | ADDD STKTOP 397 | TSTV02 ANDCC #$FE 398 | TSTV03 RTS 399 | ;***************************** 400 | ;***************************** 401 | USER JSR ARGONE 402 | PSHS D 403 | JSR SKIPSP 404 | CMPA #',' 405 | BEQ USER03 406 | CMPA #')' 407 | ORCC #$01 408 | BEQ USER05 409 | USER02 JMP ERRORS 410 | USER03 LEAX 1,X 411 | JSR EXPR 412 | PSHS A 413 | JSR SKIPSP 414 | CMPA #')' 415 | PULS A 416 | BNE USER02 417 | ANDCC #$FE 418 | USER05 LEAX 1,X 419 | STX CURSOR 420 | JSR [,S++] 421 | LDX CURSOR 422 | ANDCC #$FE 423 | RTS 424 | ;***************************** 425 | ;***************************** 426 | TSTSNB JSR SKIPSP 427 | CMPA #'-' 428 | BNE TSTNBR 429 | LEAX 1,X 430 | BSR TSTNBR 431 | BCS TSN02 432 | NEGA 433 | NEGB 434 | SBCA #0 435 | ANDCC #$FC 436 | TSN02 RTS 437 | ;***************************** 438 | ;***************************** 439 | TSTNBR JSR SKIPSP 440 | JSR TSTDIG 441 | BCC TSTN02 442 | CMPA #'$' 443 | ORCC #$01 444 | BNE TSTN09 445 | TSTN20 LEAX 1,X 446 | CLR ,-S 447 | CLR ,-S 448 | TSTN23 LDA 0,X 449 | JSR TSTHEX 450 | BCS TSTN07 451 | LEAX 1,X 452 | PSHS X 453 | PSHS A 454 | LDD 3,S 455 | BITA #$F0 456 | BNE TSTN11 457 | ASLB 458 | ROLA 459 | ASLB 460 | ROLA 461 | ASLB 462 | ROLA 463 | ASLB 464 | ROLA 465 | ADDB ,S+ 466 | STD 2,S 467 | PULS X 468 | BRA TSTN23 469 | TSTN02 LEAX 1,X 470 | PSHS A 471 | CLR ,-S 472 | TSTN03 LDA 0,X 473 | JSR TSTDIG 474 | BCS TSTN07 475 | LEAX 1,X 476 | PSHS X 477 | PSHS A 478 | LDD 3,S 479 | ASLB 480 | ROLA 481 | BVS TSTN11 482 | ASLB 483 | ROLA 484 | BVS TSTN11 485 | ADDD 3,S 486 | BVS TSTN11 487 | ASLB 488 | ROLA 489 | BVS TSTN11 490 | ADDB 0,S 491 | ADCA #0 492 | BVS TSTN11 493 | STD 3,S 494 | LEAS 1,S 495 | PULS X 496 | BRA TSTN03 497 | TSTN07 PULS D 498 | ANDCC #$FE 499 | TSTN09 ANDCC #$FD 500 | RTS 501 | TSTN11 LDX 1,S 502 | LEAS 5,S 503 | ORCC #$03 504 | RTS 505 | ;***************************** 506 | ;***************************** 507 | TSTSTK STS SAVESP 508 | LDD SAVESP 509 | SUBD #STKCUS 510 | SUBD STKLIM 511 | RTS 512 | ;***************************** 513 | ;***************************** 514 | PEEK JSR PAREXP 515 | PSHS D 516 | PSHS X 517 | LDB [2,S] 518 | PULS X 519 | LEAS 2,S 520 | CLRA 521 | RTS 522 | ;***************************** 523 | ;***************************** 524 | POKE JSR PAREXP 525 | PSHS D 526 | JSR SKIPSP 527 | CMPA #'=' 528 | BEQ POKE05 529 | JMP ERRORS 530 | POKE05 LEAX 1,X 531 | JSR EXPR 532 | JSR TSTEOL 533 | PSHS X 534 | STB [2,S] 535 | PULS X 536 | LEAS 2,S 537 | JMP ENDS02 538 | ;***************************** 539 | ;***************************** 540 | TSTFUN JSR SKIPSP 541 | STX CURSOR 542 | LDX #FUNT 543 | JSR FAN00 544 | BCS TSTF05 545 | PSHS D 546 | TSTF05 RTS 547 | ;***************************** 548 | ;***************************** 549 | FUNT FCC "USR" 550 | FCB EOL 551 | FDB USER 552 | FCC "PEEK" 553 | FCB EOL 554 | FDB PEEK 555 | FCC "MEM" 556 | FCB EOL 557 | FDB TSTSTK 558 | FCB EOL 559 | ;***************************** 560 | ;***************************** 561 | FLINE LDX USRBAS 562 | FNDLIN CMPX USRTOP 563 | BNE FND03 564 | ORCC #$03 565 | RTS 566 | FND03 CMPD 0,X 567 | BNE FND05 568 | ANDCC #$FC 569 | RTS 570 | FND05 BCC FND07 571 | ORCC #$01 572 | ANDCC #$FD 573 | RTS 574 | FND07 PSHS A 575 | LDA #EOL 576 | LEAX 1,X 577 | FND09 LEAX 1,X 578 | CMPA 0,X 579 | BNE FND09 580 | PULS A 581 | LEAX 1,X 582 | BRA FNDLIN 583 | ;***************************** 584 | ;***************************** 585 | RELEXP BSR EXPR 586 | PSHS D 587 | CLRB 588 | JSR SKIPSP 589 | CMPA #'=' 590 | BEQ REL06 591 | CMPA #'<' 592 | BNE REL03 593 | LEAX 1,X 594 | INCB 595 | JSR SKIPSP 596 | CMPA #'>' 597 | BNE REL05 598 | LEAX 1,X 599 | ADDB #4 600 | BRA REL07 601 | REL03 CMPA #'>' 602 | BNE EXPR06 603 | LEAX 1,X 604 | ADDB #4 605 | JSR SKIPSP 606 | REL05 CMPA #'=' 607 | BNE REL07 608 | REL06 LEAX 1,X 609 | ADDB #2 610 | REL07 PSHS B 611 | BSR EXPR 612 | PSHS X 613 | SUBD 3,S 614 | TFR CC,A 615 | LSRA 616 | TFR A,B 617 | ASLA 618 | ASLA 619 | PSHS B 620 | ADDA ,S+ 621 | ANDA #$06 622 | BNE REL08 623 | INCA 624 | REL08 CLRB 625 | ANDA 2,S 626 | BEQ REL09 627 | COMB 628 | REL09 CLRA 629 | PULS X 630 | LEAS 3,S 631 | RTS 632 | ;***************************** 633 | ;***************************** 634 | EXPR CLR ,-S 635 | CLR ,-S 636 | JSR SKIPSP 637 | CMPA #'-' 638 | BEQ EXPR05 639 | CMPA #'+' 640 | BNE EXPR03 641 | EXPR02 LEAX 1,X 642 | EXPR03 BSR TERM 643 | EXPR04 ADDD 0,S 644 | STD 0,S 645 | JSR SKIPSP 646 | CMPA #'+' 647 | BEQ EXPR02 648 | CMPA #'-' 649 | BNE EXPR06 650 | EXPR05 LEAX 1,X 651 | BSR TERM 652 | NEGA 653 | NEGB 654 | SBCA #0 655 | BRA EXPR04 656 | EXPR06 PULS D 657 | RTS 658 | ;***************************** 659 | ;***************************** 660 | TERM JSR FACT 661 | PSHS D 662 | TERM03 JSR SKIPSP 663 | CMPA #'*' 664 | BEQ TERM07 665 | CMPA #'/' 666 | BEQ TERM05 667 | PULS D 668 | RTS 669 | TERM05 LEAX 1,X 670 | BSR FACT 671 | PSHS X 672 | LEAX 2,S 673 | PSHS D 674 | EORA 0,X 675 | JSR ABSX 676 | LEAX 0,S 677 | JSR ABSX 678 | PSHS A 679 | LDA #17 680 | PSHS A 681 | CLRA 682 | CLRB 683 | DIV05 SUBD 2,S 684 | BCC DIV07 685 | ADDD 2,S 686 | ANDCC #$FE 687 | BRA DIV09 688 | DIV07 ORCC #$01 689 | DIV09 ROL 7,S 690 | ROL 6,S 691 | ROLB 692 | ROLA 693 | DEC 0,S 694 | BNE DIV05 695 | LDA 1,S 696 | LEAS 4,S 697 | TSTA 698 | BPL TERM06 699 | LEAX 2,S 700 | BSR NEGX 701 | TERM06 PULS X 702 | BRA TERM03 703 | TERM07 LEAX 1,X 704 | BSR FACT 705 | MULT PSHS B 706 | LDB 2,S 707 | MUL 708 | LDA 1,S 709 | STB 1,S 710 | LDB 0,S 711 | MUL 712 | LDA 2,S 713 | STB 2,S 714 | PULS B 715 | MUL 716 | ADDA 0,S 717 | ADDA 1,S 718 | STD 0,S 719 | BRA TERM03 720 | ;***************************** 721 | ;***************************** 722 | FACT JSR TSTVAR 723 | BCS FACT03 724 | PSHS X 725 | TFR D,X 726 | LDD 0,X 727 | PULS X 728 | FACT02 RTS 729 | FACT03 JSR TSTNBR 730 | BCC FACT02 731 | JSR TSTFUN 732 | BCC FACT02 733 | PAREXP BSR ARGONE 734 | PSHS A 735 | JSR SKIPSP 736 | CMPA #')' 737 | PULS A 738 | BNE FACT05 739 | LEAX 1,X 740 | RTS 741 | FACT05 JMP ERRORS 742 | ;***************************** 743 | ;***************************** 744 | ARGONE JSR TSTSTK 745 | BCC FACT04 746 | JMP ERRORF 747 | FACT04 JSR SKIPSP 748 | CMPA #'(' 749 | BNE FACT05 750 | LEAX 1,X 751 | JMP EXPR 752 | ;***************************** 753 | ;***************************** 754 | ABSX TST 0,X 755 | BPL NEG05 756 | NEGX NEG 0,X 757 | NEG 1,X 758 | BCC NEG05 759 | DEC 0,X 760 | NEG05 RTS 761 | ;***************************** 762 | ;***************************** 763 | TSTEOL PSHS A 764 | JSR SKIPSP 765 | CMPA #EOL 766 | BEQ TEOL03 767 | JMP ERRORS 768 | TEOL03 LEAX 1,X 769 | PULS A 770 | RTS 771 | ;***************************** 772 | ;***************************** 773 | LET JSR TSTVAR 774 | BCC LET03 775 | JMP ERRORS 776 | LET03 PSHS D 777 | JSR SKIPSP 778 | CMPA #'=' 779 | BEQ LET05 780 | JMP ERRORS 781 | LET05 LEAX 1,X 782 | JSR EXPR 783 | BSR TSTEOL 784 | STX CURSOR 785 | PULS X 786 | STD 0,X 787 | LDX CURSOR 788 | JMP ENDS02 789 | ;***************************** 790 | ;***************************** 791 | IF JSR RELEXP 792 | TSTB 793 | BEQ IF03 794 | JMP MSLINE 795 | IF03 JMP REM 796 | ;***************************** 797 | ;***************************** 798 | GOTO JSR EXPR 799 | BSR TSTEOL 800 | JSR FLINE 801 | BCS GOSB04 802 | JMP NXTLIN 803 | ;***************************** 804 | ;***************************** 805 | GOSUB JSR EXPR 806 | BSR TSTEOL 807 | STX CURSOR 808 | JSR FLINE 809 | BCC GOSB03 810 | GOSB04 JMP ERRORR 811 | GOSB03 JSR TSTSTK 812 | BCC GOSB05 813 | JMP ERRORF 814 | GOSB05 LDD CURSOR 815 | PSHS D 816 | LDD LINENB 817 | PSHS D 818 | JSR NXTLIN 819 | PULS D 820 | STD LINENB 821 | PULS X 822 | JMP ENDS02 823 | ;***************************** 824 | ;***************************** 825 | RETURN EQU TSTEOL 826 | ;***************************** 827 | ;***************************** 828 | PRINT JSR SKIPSP 829 | PR01 CMPA #',' 830 | BEQ PR05 831 | CMPA #';' 832 | BEQ PR07 833 | CMPA #EOL 834 | BEQ PR04 835 | CMPA #'"' 836 | BNE PR02 837 | LEAX 1,X 838 | BSR PRNTQS 839 | BRA PR03 840 | PR02 JSR EXPR 841 | PSHS X 842 | BSR PRNTN 843 | PULS X 844 | PR03 JSR SKIPSP 845 | CMPA #',' 846 | BEQ PR05 847 | CMPA #';' 848 | BEQ PR07 849 | CMPA #EOL 850 | BEQ PR04 851 | JMP ERRORS 852 | PR04 PSHS X 853 | JSR CRLF 854 | PULS X 855 | BRA PR08 856 | PR05 LDB #$7 857 | PR06 LDA #SPACE 858 | JSR PUTCHR 859 | BITB ZONE 860 | BNE PR06 861 | PR07 LEAX 1,X 862 | JSR SKIPSP 863 | CMPA #EOL 864 | BNE PR01 865 | PR08 LEAX 1,X 866 | JMP ENDS02 867 | ; 868 | ; 869 | PRQ01 JSR PUTCHR 870 | PRNTQS LDA ,X+ 871 | CMPA #EOL 872 | BNE PRQ03 873 | JMP ERRORS 874 | PRQ03 CMPA #'"' 875 | BNE PRQ01 876 | RTS 877 | ; 878 | PRNTN TSTA 879 | BPL PRN03 880 | NEGA 881 | NEGB 882 | SBCA #0 883 | PSHS A 884 | LDA #'-' 885 | JSR PUTCHR 886 | PULS A 887 | PRN03 LDX #PRNPT-2 888 | PRN05 LEAX 2,X 889 | CMPD 0,X 890 | BCC PRN07 891 | CMPX #PRNPTO 892 | BNE PRN05 893 | PRN07 CLR CHAR 894 | PRN09 CMPD 0,X 895 | BCS PRN11 896 | SUBD 0,X 897 | INC CHAR 898 | BRA PRN09 899 | PRN11 PSHS A 900 | LDA #'0' 901 | ADDA CHAR 902 | JSR PUTCHR 903 | PULS A 904 | CMPX #PRNPTO 905 | BEQ PRN13 906 | LEAX 2,X 907 | BRA PRN07 908 | PRN13 RTS 909 | PRNPT FDB 10000 910 | FDB 1000 911 | FDB 100 912 | FDB 10 913 | PRNPTO FDB 1 914 | ; 915 | PRNT4 LDX #PRNPT+2 916 | BRA PRN07 917 | ;***************************** 918 | ;***************************** 919 | INPUT JSR TSTVAR 920 | BCS IN11 921 | PSHS D 922 | STX CURSOR 923 | IN03 LDA #'?' 924 | JSR PUTCHR 925 | JSR GETLIN 926 | IN05 JSR SKIPSP 927 | CMPA #EOL 928 | BEQ IN03 929 | JSR TSTSNB 930 | BCC IN07 931 | LDX #RMESS 932 | JSR PUTSTR 933 | JSR CRLF 934 | BRA IN03 935 | IN07 STX SCRTCH 936 | PULS X 937 | STD 0,X 938 | LDX CURSOR 939 | JSR SKIPSP 940 | CMPA #',' 941 | BEQ IN09 942 | JMP ENDSMT 943 | IN09 LEAX 1,X 944 | JSR TSTVAR 945 | BCC IN13 946 | IN11 JMP ERRORS 947 | IN13 PSHS D 948 | PSHS X 949 | LDX SCRTCH 950 | JSR SKIPSP 951 | CMPA #',' 952 | BNE IN05 953 | LEAX 1,X 954 | BRA IN05 955 | RMESS FCC "RE-ENTER" 956 | FCB EOL 957 | ;***************************** 958 | ;***************************** 959 | RUN LDX STKTOP 960 | LDA #52 961 | RUN01 CLR ,X+ 962 | DECA 963 | BNE RUN01 964 | LDX USRBAS 965 | JMP REM05 966 | ;***************************** 967 | ;***************************** 968 | LIST JSR TSTNBR 969 | BCC LIST03 970 | CLRA 971 | CLRB 972 | STD CURSOR 973 | LDA #$7F 974 | BRA LIST07 975 | LIST03 STD CURSOR 976 | JSR SKIPSP 977 | CMPA #',' 978 | BEQ LIST05 979 | LDA CURSOR 980 | BRA LIST07 981 | LIST05 LEAX 1,X 982 | JSR TSTNBR 983 | BCC LIST07 984 | JMP ERRORS 985 | LIST07 JSR TSTEOL 986 | PSHS D 987 | LDD CURSOR 988 | STX CURSOR 989 | JSR FLINE 990 | LIST09 CMPX USRTOP 991 | BEQ LIST10 992 | PULS D 993 | CMPD 0,X 994 | BCS LIST11 995 | PSHS D 996 | LDD ,X++ 997 | PSHS X 998 | JSR PRNT4 999 | PULS X 1000 | LDA #SPACE 1001 | JSR PUTCHR 1002 | JSR PUTSTR 1003 | LEAX 1,X 1004 | PSHS X 1005 | JSR CRLF 1006 | PULS X 1007 | JSR TSTBRK 1008 | BRA LIST09 1009 | LIST10 LEAS 2,S 1010 | LDA #ETX 1011 | JSR PUTCHR 1012 | LIST11 LDX CURSOR 1013 | JMP ENDS02 1014 | ;***************************** 1015 | ;***************************** 1016 | VERBT FCC "LET" 1017 | FCB EOL 1018 | FDB LET 1019 | FCC "IF" 1020 | FCB EOL 1021 | FDB IF 1022 | FCC "GOTO" 1023 | FCB EOL 1024 | FDB GOTO 1025 | FCC "GOSUB" 1026 | FCB EOL 1027 | FDB GOSUB 1028 | FCC "RETURN" 1029 | FCB EOL 1030 | FDB RETURN 1031 | FCC "POKE" 1032 | FCB EOL 1033 | FDB POKE 1034 | FCC "PRINT" 1035 | FCB EOL 1036 | FDB PRINT 1037 | FCC "INPUT" 1038 | FCB EOL 1039 | FDB INPUT 1040 | FCC "REM" 1041 | FCB EOL 1042 | FDB REM 1043 | FCC "STOP" 1044 | FCB EOL 1045 | FDB END 1046 | FCC "END" 1047 | FCB EOL 1048 | FDB END 1049 | FCC "RUN" 1050 | FCB EOL 1051 | FDB RUN 1052 | FCC "LIST" 1053 | FCB EOL 1054 | FDB LIST 1055 | FCC "NEW" 1056 | FCB EOL 1057 | FDB CLEAR 1058 | FCC "?" 1059 | FCB EOL 1060 | FDB PRINT 1061 | FCB EOL 1062 | ;***************************** 1063 | ;***************************** 1064 | TSTBRK JSR BRKEEE 1065 | BEQ GETC05 1066 | GETCHR JSR INEEE 1067 | CMPA #ETX 1068 | BNE GETC05 1069 | JMP BREAK 1070 | GETC05 RTS 1071 | PUTCHR INC ZONE 1072 | JMP OUTEEE 1073 | ;***************************** 1074 | ;***************************** 1075 | INEEE BSR BRKEEE 1076 | BEQ INEEE 1077 | LDA RECEV 1078 | ANDA #$7F 1079 | RTS 1080 | OUTEEE PSHS A 1081 | OUT01 LDA TRCS 1082 | BITA #TDRE 1083 | BEQ OUT01 1084 | PULS A 1085 | STA TRANS 1086 | RTS 1087 | BRKEEE PSHS A 1088 | BRK03 LDA TRCS 1089 | BITA #ORFE 1090 | BEQ BRK05 1091 | LDA RECEV 1092 | BRA BRK03 1093 | BRK05 BITA #RDRF 1094 | PULS A 1095 | RTS 1096 | ; 1097 | ; LDA #CNTL1 1098 | ; STA RMCR 1099 | ; LDA #CNTL2 1100 | ; STA TRCS 1101 | ;INTEEE EQU * 1102 | ; RTS 1103 | ;***************************** 1104 | ;***************************** 1105 | 1106 | ORG $FFFE 1107 | FDB BASIC 1108 | -------------------------------------------------------------------------------- /tests/test.s: -------------------------------------------------------------------------------- 1 | pshu a,b,x,y 2 | pulu a,b,x,y 3 | 4 | leax 1,x 5 | 6 | lda #$80 ; enable ACIA interrupt 7 | sta acia 8 | 9 | loop cwai #$bf 10 | lda inchar 11 | jsr puthexbyte 12 | exg a,b 13 | swi 14 | bra loop 15 | 16 | test rts 17 | -------------------------------------------------------------------------------- /tests/test_main.hex: -------------------------------------------------------------------------------- 1 | :20E0000010CE0200CE04001A50308D00FC17008E3636373630018680B7C0003CBF9600BDB1 2 | :20E02000E0AB1E893F20F4398EE07D170070A6E4847F1700768EE082170063A66117006BA3 3 | :20E040008EE087170058A6621700608EE08C17004DA6631700558EE091170042A664170091 4 | :20E060004AA6651700458EE096170032A66617003AA6671700358EE09B1700223B204343C9 5 | :20E080003A002020413A002020423A002044503A002020583A002020593A000D0A003413DE 6 | :20E0A000A68027048D2820F83513393401464646468D0A46464646468D03350139340384C5 7 | :20E0C0000F8B3081392F028B278D033503393402B6C000850227F93502B7C00139B6C00027 8 | :20E0E000850127F9B6C00139340181612B06817A22028020350139340181412B06815A222F 9 | :20E10000028B203501393E200053797374656D206C6F6164656420616E64207265616479EF 10 | :1AE120000D0A003B3402B6C0002A08442405B6C001970035023B3B3B3B3BDC 11 | :10FFF000E136E138E137E124E123E028E139E000AE 12 | :00E000011F 13 | -------------------------------------------------------------------------------- /tests/test_main.s: -------------------------------------------------------------------------------- 1 | uart equ $c000 2 | system_stack equ $0200 3 | user_stack equ $0400 4 | vector_table equ $fff0 5 | rom_start equ $e000 6 | 7 | acia equ $c000 8 | 9 | inchar equ $00 10 | 11 | ; setdp $00 12 | 13 | ; 14 | ; Start of System ROM 15 | ; 16 | org rom_start 17 | 18 | handle_reset lds #system_stack 19 | ldu #user_stack 20 | orcc #$50 ; disable interrupts 21 | 22 | leax system_ready,pcr 23 | lbsr putstr 24 | 25 | include "test.s" 26 | 27 | ;-- Status printing software interrupt 28 | status ldx #str_cc 29 | lbsr putstr 30 | lda ,s 31 | anda #$7f 32 | lbsr puthexbyte 33 | 34 | ldx #str_a 35 | lbsr putstr 36 | lda 1,s 37 | lbsr puthexbyte 38 | 39 | ldx #str_b 40 | lbsr putstr 41 | lda 2,s 42 | lbsr puthexbyte 43 | 44 | ldx #str_dp 45 | lbsr putstr 46 | lda 3,s 47 | lbsr puthexbyte 48 | 49 | ldx #str_x 50 | lbsr putstr 51 | lda 4,s 52 | lbsr puthexbyte 53 | lda 5,s 54 | lbsr puthexbyte 55 | 56 | ldx #str_y 57 | lbsr putstr 58 | lda 6,s 59 | lbsr puthexbyte 60 | lda 7,s 61 | lbsr puthexbyte 62 | 63 | ldx #str_nl 64 | lbsr putstr 65 | 66 | rti 67 | 68 | str_cc fcn " CC:" 69 | str_a fcn " A:" 70 | str_b fcn " B:" 71 | str_dp fcn " DP:" 72 | str_x fcn " X:" 73 | str_y fcn " Y:" 74 | 75 | str_nl fcb 13,10,0 76 | 77 | package_io 78 | 79 | putstr pshs a,x,cc 80 | putstr_loop lda ,x+ 81 | beq putstr_done 82 | bsr putchar 83 | bra putstr_loop 84 | putstr_done puls a,x,cc 85 | rts 86 | 87 | puthexbyte pshs cc 88 | rora 89 | rora 90 | rora 91 | rora 92 | bsr puthexdigit 93 | rora 94 | rora 95 | rora 96 | rora 97 | rora ; rotate through carry bit 98 | bsr puthexdigit 99 | puls cc 100 | rts 101 | 102 | puthexdigit pshs a,cc 103 | anda #$0f 104 | adda #'0' 105 | cmpa #'9' 106 | ble _puthexdigit1 107 | adda #$27 108 | _puthexdigit1 bsr putchar 109 | puls a,cc 110 | rts 111 | 112 | putchar pshs a 113 | _putchar1 lda uart 114 | bita #$02 115 | beq _putchar1 116 | puls a 117 | sta uart+1 118 | rts 119 | 120 | getchar lda uart 121 | bita #$01 122 | beq getchar 123 | lda uart+1 124 | rts 125 | 126 | package_str 127 | 128 | toupper pshs cc 129 | cmpa #$61 130 | bmi toupper_done 131 | cmpa #$7a 132 | bhi toupper_done 133 | suba #$20 134 | toupper_done puls cc 135 | rts 136 | 137 | tolower pshs cc 138 | cmpa #$41 139 | bmi tolower_done 140 | cmpa #$5a 141 | bhi tolower_done 142 | adda #$20 143 | tolower_done puls cc 144 | rts 145 | 146 | prompt_str fcn "> " 147 | system_ready fcc "System loaded and ready" 148 | fcb 13,10+$80 149 | 150 | handle_irq rti 151 | 152 | handle_firq pshs a 153 | lda acia ; status register 154 | bpl irq_done ; done if IRQ = 0 155 | lsra ; shift RDRF -> C 156 | bcc irq_done ; done if clear 157 | lda acia + 1 158 | sta inchar 159 | irq_done puls a 160 | rti 161 | 162 | handle_undef rti 163 | 164 | handle_swi equ status 165 | 166 | handle_swi2 rti 167 | 168 | handle_swi3 rti 169 | 170 | handle_nmi rti 171 | 172 | ; 173 | ; System vector specification 174 | ; 175 | org vector_table 176 | fdb handle_undef ; $fff0 177 | fdb handle_swi3 ; $fff2 178 | fdb handle_swi2 ; $fff4 179 | fdb handle_firq ; $fff6 180 | fdb handle_irq ; $fff8 181 | fdb handle_swi ; $fffa 182 | fdb handle_nmi ; $fffc 183 | fdb handle_reset ; $fffe 184 | 185 | end handle_reset 186 | -------------------------------------------------------------------------------- /typedefs.h: -------------------------------------------------------------------------------- 1 | // 2 | // 3 | // typedefs.h 4 | // 5 | // (C) R.P.Bellis 1994 6 | // 7 | // 8 | 9 | #pragma once 10 | 11 | #ifdef __cplusplus 12 | 13 | #include 14 | #include 15 | 16 | #else 17 | 18 | #include 19 | 20 | #endif 21 | 22 | typedef uint8_t Byte; 23 | typedef uint16_t Word; 24 | typedef uint32_t DWord; 25 | -------------------------------------------------------------------------------- /usim.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // 3 | // usim.cpp 4 | // 5 | // (C) R.P.Bellis 1994 6 | // 7 | // 8 | 9 | #include 10 | #include 11 | #include "usim.h" 12 | 13 | //---------------------------------------------------------------------------- 14 | // Generic processor run state routines 15 | //---------------------------------------------------------------------------- 16 | 17 | void USim::run() 18 | { 19 | halted = false; 20 | while (!halted) { 21 | tick(); 22 | } 23 | } 24 | 25 | void USim::tick() 26 | { 27 | // assume one cycle happens every time 28 | ++cycles; 29 | 30 | // update all active devices 31 | for (auto& d : dev_active) { 32 | d.device->tick(cycles); 33 | } 34 | 35 | // reset the cycle counter 36 | cycles = 0; 37 | } 38 | 39 | void USim::reset() 40 | { 41 | // reset all active devices 42 | for (auto& d : dev_active) { 43 | d.device->reset(); 44 | } 45 | } 46 | 47 | void USim::halt() 48 | { 49 | halted = true; 50 | } 51 | 52 | void USim::invalid(const char *msg) 53 | { 54 | fprintf(stderr, "error: %s [PC:$%04X IR:$%04X]\n", msg, pc, ir); 55 | this->abort(); 56 | } 57 | 58 | Byte USim::fetch() 59 | { 60 | return read(pc++); 61 | } 62 | 63 | //---------------------------------------------------------------------------- 64 | // Device handling 65 | //---------------------------------------------------------------------------- 66 | 67 | void USim::attach(const ActiveDevice::shared_ptr& dev) 68 | { 69 | dev_active.push_back({ dev }); 70 | } 71 | 72 | void USim::attach(const MappedDevice::shared_ptr& dev, Word base, Word mask, rank<0>) 73 | { 74 | dev_mapped.push_back({ dev, base, mask }); 75 | } 76 | 77 | void USim::attach(const ActiveMappedDevice::shared_ptr& dev, Word base, Word mask, rank<1>) 78 | { 79 | dev_active.push_back({ dev }); 80 | dev_mapped.push_back({ dev, base, mask }); 81 | } 82 | 83 | //---------------------------------------------------------------------------- 84 | // Mapped Device IO 85 | //---------------------------------------------------------------------------- 86 | 87 | // Single byte read 88 | Byte USim::read(Word offset) 89 | { 90 | ++cycles; 91 | for (auto& d : dev_mapped) { 92 | if ((offset & d.mask) == d.base) { 93 | return d.device->read(offset - d.base); 94 | } 95 | } 96 | return 0xff; 97 | } 98 | 99 | // Single byte write 100 | void USim::write(Word offset, Byte val) 101 | { 102 | ++cycles; 103 | for (auto& d : dev_mapped) { 104 | if ((offset & d.mask) == d.base) { 105 | d.device->write(offset - d.base, val); 106 | break; 107 | } 108 | } 109 | } 110 | 111 | //---------------------------------------------------------------------------- 112 | // Word memory access routines for big-endian (Motorola type) 113 | //---------------------------------------------------------------------------- 114 | 115 | Word USimMotorola::fetch_word() 116 | { 117 | Word tmp; 118 | 119 | tmp = fetch() << 8; 120 | tmp |= fetch(); 121 | 122 | return tmp; 123 | } 124 | 125 | Word USimMotorola::read_word(Word offset) 126 | { 127 | Word tmp; 128 | 129 | tmp = read(offset++) << 8; 130 | tmp |= read(offset); 131 | 132 | return tmp; 133 | } 134 | 135 | void USimMotorola::write_word(Word offset, Word val) 136 | { 137 | write(offset++, (Byte)(val >> 8)); 138 | write(offset, (Byte)val); 139 | } 140 | 141 | //---------------------------------------------------------------------------- 142 | // Word memory access routines for little-endian (Intel type) 143 | //---------------------------------------------------------------------------- 144 | 145 | Word USimIntel::fetch_word() 146 | { 147 | Word tmp; 148 | 149 | tmp = fetch(); 150 | tmp |= fetch() << 8; 151 | 152 | return tmp; 153 | } 154 | 155 | Word USimIntel::read_word(Word offset) 156 | { 157 | Word tmp; 158 | 159 | tmp = read(offset++); 160 | tmp |= (read(offset) << 8); 161 | 162 | return tmp; 163 | } 164 | 165 | void USimIntel::write_word(Word offset, Word val) 166 | { 167 | write(offset++, (Byte)val); 168 | write(offset, (Byte)(val >> 8)); 169 | } 170 | -------------------------------------------------------------------------------- /usim.h: -------------------------------------------------------------------------------- 1 | // 2 | // 3 | // usim.h 4 | // 5 | // (C) R.P.Bellis 1994 6 | // 7 | // 8 | 9 | #pragma once 10 | 11 | #include 12 | #include "device.h" 13 | #include "memory.h" 14 | #include "wiring.h" 15 | #include "bits.h" 16 | 17 | /* 18 | * main system wide base class for CPU emulators 19 | * 20 | * assumes an 8 bit Von-Neumann architecture with a 16 bit 21 | * address space and memory mapped peripherals 22 | */ 23 | class USim { 24 | 25 | // Generic processor state 26 | protected: 27 | 28 | bool m_trace = false; 29 | bool halted = true; 30 | uint8_t cycles = 0; 31 | 32 | // Generic internal registers that we assume all CPUs have 33 | 34 | Word ir; 35 | Word pc; 36 | 37 | // Generic read/write/execute functions 38 | public: 39 | 40 | virtual Byte read(Word offset); 41 | virtual Word read_word(Word offset) = 0; 42 | virtual void write(Word offset, Byte val); 43 | virtual void write_word(Word offset, Word val) = 0; 44 | virtual Byte fetch(); 45 | 46 | // Device handling: 47 | protected: 48 | ActiveDevList dev_active; 49 | MappedDevList dev_mapped; 50 | 51 | virtual void attach(const MappedDevice::shared_ptr& dev, Word base, Word mask, rank<0>); 52 | virtual void attach(const ActiveMappedDevice::shared_ptr& dev, Word base, Word mask, rank<1>); 53 | 54 | public: 55 | virtual void attach(const ActiveDevice::shared_ptr& dev); 56 | 57 | template 58 | void attach(const std::shared_ptr& dev, Word base, Word mask) { 59 | attach(dev, base, mask, rank<2>{}); 60 | }; 61 | 62 | // Functions to start and stop the virtual processor 63 | public: 64 | 65 | std::function abort = ::abort; 66 | virtual void invalid(const char*); 67 | virtual void run(); 68 | virtual void tick(); 69 | virtual void halt(); 70 | virtual void reset(); 71 | 72 | // Debugging 73 | void tron() { m_trace = true; }; 74 | void troff() { m_trace = false; }; 75 | 76 | }; 77 | 78 | class USimMotorola : virtual public USim { 79 | 80 | // Memory access functions taking target byte order into account 81 | public: 82 | virtual Word fetch_word(); 83 | 84 | virtual Word read_word(Word offset); 85 | virtual void write_word(Word offset, Word val); 86 | 87 | }; 88 | 89 | class USimIntel : virtual public USim { 90 | 91 | // Memory access functions taking target byte order into account 92 | public: 93 | virtual Word fetch_word(); 94 | 95 | virtual Word read_word(Word offset); 96 | virtual void write_word(Word offset, Word val); 97 | 98 | }; 99 | -------------------------------------------------------------------------------- /wiring.h: -------------------------------------------------------------------------------- 1 | // 2 | // 3 | // wiring.h 4 | // 5 | // (C) R.P.Bellis 2021 6 | // 7 | // 8 | 9 | #pragma once 10 | 11 | #include 12 | 13 | //--------------------------------------------------------------------- 14 | // 15 | // helper functions for InputPin and Input Port 16 | // 17 | static inline constexpr bool default_true() { 18 | return true; 19 | } 20 | 21 | static inline constexpr uint8_t default_high() { 22 | return 0xff; 23 | } 24 | 25 | //--------------------------------------------------------------------- 26 | // 27 | // OutputPin: 28 | // 29 | // An object providing read-only access to a reference 30 | // to a bool, representing the state of an IO pin. 31 | // 32 | // If the `invert` flag is set then it indicates a pin 33 | // that outputs the opposite of the referenced variable. 34 | // 35 | class OutputPin { 36 | 37 | protected: 38 | bool& val; 39 | const bool invert; 40 | 41 | public: 42 | OutputPin(bool& val, bool invert = false) 43 | : val(val), invert(invert) 44 | { } 45 | 46 | operator bool() const { return val ^ invert; } 47 | }; 48 | 49 | //--------------------------------------------------------------------- 50 | // 51 | // OutputPinReg: 52 | // 53 | // An object providing read-only access to a single bit 54 | // within uint8_t, representing the state of an IO pin. 55 | // 56 | // Use this to handle cases like the 6522 VIA, where the 57 | // ~IRQ pin always represents the value of IFR bit 7. 58 | // 59 | // If the `invert` flag is set then it indicates a pin 60 | // that outputs the opposite of the referenced bit. 61 | // 62 | class OutputPinReg { 63 | 64 | protected: 65 | uint8_t& val; 66 | const uint8_t mask; 67 | const bool invert; 68 | 69 | public: 70 | OutputPinReg(uint8_t& val, uint8_t bit, bool invert = false) 71 | : val(val), mask(1 << bit), invert(invert) 72 | { } 73 | 74 | operator bool() const { 75 | return (bool)(val & mask) ^ invert; 76 | } 77 | }; 78 | 79 | //--------------------------------------------------------------------- 80 | // 81 | // OutputPort: 82 | // 83 | // An object providing read-only access to the N least 84 | // significant bits of a uint8_t 85 | // 86 | template 87 | class OutputPort { 88 | 89 | static_assert(N <= 8, "OutputPort too large"); 90 | 91 | protected: 92 | uint8_t& data; 93 | const uint8_t mask = (1 << N) - 1; 94 | 95 | public: 96 | OutputPort(uint8_t& data) 97 | : data(data) 98 | { } 99 | 100 | operator uint8_t() const { 101 | return data & mask; 102 | } 103 | }; 104 | 105 | //--------------------------------------------------------------------- 106 | // 107 | // InputPin: 108 | // 109 | // An object that represents a single input pin, where 110 | // the current value of that pin is determined by calling 111 | // a developer-supplied function that typically will 112 | // poll the state of one or more Output* objects 113 | // 114 | class InputPin { 115 | 116 | protected: 117 | using Function = std::function; 118 | 119 | protected: 120 | Function f = default_true; 121 | 122 | public: 123 | void bind(const Function& _f) { 124 | f = _f; 125 | } 126 | 127 | bool get() const { 128 | return f(); 129 | } 130 | 131 | operator bool() const { 132 | return get(); 133 | } 134 | }; 135 | 136 | //--------------------------------------------------------------------- 137 | // 138 | // InputPort 139 | // 140 | // An object that represents an N-bit input port, where 141 | // the current value of the port is determined by calling 142 | // a developer-supplied function that typically will 143 | // poll the state of one or more Output* objects 144 | // 145 | // The value may be read by casting to (uint8_t), and will 146 | // be masked to be within the expected legal range. 147 | // 148 | template 149 | class InputPort { 150 | 151 | static_assert(N <= 8, "InputPort too large"); 152 | using Function = std::function; 153 | 154 | protected: 155 | Function f = default_high; 156 | 157 | protected: 158 | const uint8_t mask = (1 << N) - 1; 159 | 160 | 161 | public: 162 | void bind(const Function& _f) { 163 | f = _f; 164 | } 165 | 166 | uint8_t get() const { 167 | return f() & mask; 168 | } 169 | 170 | operator uint8_t() const { 171 | return get(); 172 | } 173 | }; 174 | --------------------------------------------------------------------------------