├── LICENSE ├── README.md ├── config.fs ├── crude65816.fs ├── data.bin ├── docs ├── CHANGELOG.txt ├── MANUAL.md └── TODO.txt ├── io.fs ├── roms ├── mmm │ ├── README.md │ ├── mmm.bin │ ├── mmm.tasm │ ├── test_mmm.bin │ └── test_mmm.tasm ├── rom65816.bin └── rom65816.fs ├── tests ├── README.txt ├── TEST-dp-wrapping.tasmf ├── TEST-phe.tasmf ├── fragments.tasmf └── testsources.txt └── tools ├── hex2rom.fs ├── make-opc-routines.fs ├── opc-routines.txt └── testrom.bin /LICENSE: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 3, 29 June 2007 3 | 4 | Copyright (C) 2007 Free Software Foundation, Inc. 5 | Everyone is permitted to copy and distribute verbatim copies 6 | of this license document, but changing it is not allowed. 7 | 8 | Preamble 9 | 10 | The GNU General Public License is a free, copyleft license for 11 | software and other kinds of works. 12 | 13 | The licenses for most software and other practical works are designed 14 | to take away your freedom to share and change the works. By contrast, 15 | the GNU General Public License is intended to guarantee your freedom to 16 | share and change all versions of a program--to make sure it remains free 17 | software for all its users. We, the Free Software Foundation, use the 18 | GNU General Public License for most of our software; it applies also to 19 | any other work released this way by its authors. You can apply it to 20 | your programs, too. 21 | 22 | When we speak of free software, we are referring to freedom, not 23 | price. Our General Public Licenses are designed to make sure that you 24 | have the freedom to distribute copies of free software (and charge for 25 | them if you wish), that you receive source code or can get it if you 26 | want it, that you can change the software or use pieces of it in new 27 | free programs, and that you know you can do these things. 28 | 29 | To protect your rights, we need to prevent others from denying you 30 | these rights or asking you to surrender the rights. Therefore, you have 31 | certain responsibilities if you distribute copies of the software, or if 32 | you modify it: responsibilities to respect the freedom of others. 33 | 34 | For example, if you distribute copies of such a program, whether 35 | gratis or for a fee, you must pass on to the recipients the same 36 | freedoms that you received. You must make sure that they, too, receive 37 | or can get the source code. And you must show them these terms so they 38 | know their rights. 39 | 40 | Developers that use the GNU GPL protect your rights with two steps: 41 | (1) assert copyright on the software, and (2) offer you this License 42 | giving you legal permission to copy, distribute and/or modify it. 43 | 44 | For the developers' and authors' protection, the GPL clearly explains 45 | that there is no warranty for this free software. For both users' and 46 | authors' sake, the GPL requires that modified versions be marked as 47 | changed, so that their problems will not be attributed erroneously to 48 | authors of previous versions. 49 | 50 | Some devices are designed to deny users access to install or run 51 | modified versions of the software inside them, although the manufacturer 52 | can do so. This is fundamentally incompatible with the aim of 53 | protecting users' freedom to change the software. The systematic 54 | pattern of such abuse occurs in the area of products for individuals to 55 | use, which is precisely where it is most unacceptable. Therefore, we 56 | have designed this version of the GPL to prohibit the practice for those 57 | products. If such problems arise substantially in other domains, we 58 | stand ready to extend this provision to those domains in future versions 59 | of the GPL, as needed to protect the freedom of users. 60 | 61 | Finally, every program is threatened constantly by software patents. 62 | States should not allow patents to restrict development and use of 63 | software on general-purpose computers, but in those that do, we wish to 64 | avoid the special danger that patents applied to a free program could 65 | make it effectively proprietary. To prevent this, the GPL assures that 66 | patents cannot be used to render the program non-free. 67 | 68 | The precise terms and conditions for copying, distribution and 69 | modification follow. 70 | 71 | TERMS AND CONDITIONS 72 | 73 | 0. Definitions. 74 | 75 | "This License" refers to version 3 of the GNU General Public License. 76 | 77 | "Copyright" also means copyright-like laws that apply to other kinds of 78 | works, such as semiconductor masks. 79 | 80 | "The Program" refers to any copyrightable work licensed under this 81 | License. Each licensee is addressed as "you". "Licensees" and 82 | "recipients" may be individuals or organizations. 83 | 84 | To "modify" a work means to copy from or adapt all or part of the work 85 | in a fashion requiring copyright permission, other than the making of an 86 | exact copy. The resulting work is called a "modified version" of the 87 | earlier work or a work "based on" the earlier work. 88 | 89 | A "covered work" means either the unmodified Program or a work based 90 | on the Program. 91 | 92 | To "propagate" a work means to do anything with it that, without 93 | permission, would make you directly or secondarily liable for 94 | infringement under applicable copyright law, except executing it on a 95 | computer or modifying a private copy. Propagation includes copying, 96 | distribution (with or without modification), making available to the 97 | public, and in some countries other activities as well. 98 | 99 | To "convey" a work means any kind of propagation that enables other 100 | parties to make or receive copies. Mere interaction with a user through 101 | a computer network, with no transfer of a copy, is not conveying. 102 | 103 | An interactive user interface displays "Appropriate Legal Notices" 104 | to the extent that it includes a convenient and prominently visible 105 | feature that (1) displays an appropriate copyright notice, and (2) 106 | tells the user that there is no warranty for the work (except to the 107 | extent that warranties are provided), that licensees may convey the 108 | work under this License, and how to view a copy of this License. If 109 | the interface presents a list of user commands or options, such as a 110 | menu, a prominent item in the list meets this criterion. 111 | 112 | 1. Source Code. 113 | 114 | The "source code" for a work means the preferred form of the work 115 | for making modifications to it. "Object code" means any non-source 116 | form of a work. 117 | 118 | A "Standard Interface" means an interface that either is an official 119 | standard defined by a recognized standards body, or, in the case of 120 | interfaces specified for a particular programming language, one that 121 | is widely used among developers working in that language. 122 | 123 | The "System Libraries" of an executable work include anything, other 124 | than the work as a whole, that (a) is included in the normal form of 125 | packaging a Major Component, but which is not part of that Major 126 | Component, and (b) serves only to enable use of the work with that 127 | Major Component, or to implement a Standard Interface for which an 128 | implementation is available to the public in source code form. A 129 | "Major Component", in this context, means a major essential component 130 | (kernel, window system, and so on) of the specific operating system 131 | (if any) on which the executable work runs, or a compiler used to 132 | produce the work, or an object code interpreter used to run it. 133 | 134 | The "Corresponding Source" for a work in object code form means all 135 | the source code needed to generate, install, and (for an executable 136 | work) run the object code and to modify the work, including scripts to 137 | control those activities. However, it does not include the work's 138 | System Libraries, or general-purpose tools or generally available free 139 | programs which are used unmodified in performing those activities but 140 | which are not part of the work. For example, Corresponding Source 141 | includes interface definition files associated with source files for 142 | the work, and the source code for shared libraries and dynamically 143 | linked subprograms that the work is specifically designed to require, 144 | such as by intimate data communication or control flow between those 145 | subprograms and other parts of the work. 146 | 147 | The Corresponding Source need not include anything that users 148 | can regenerate automatically from other parts of the Corresponding 149 | Source. 150 | 151 | The Corresponding Source for a work in source code form is that 152 | same work. 153 | 154 | 2. Basic Permissions. 155 | 156 | All rights granted under this License are granted for the term of 157 | copyright on the Program, and are irrevocable provided the stated 158 | conditions are met. This License explicitly affirms your unlimited 159 | permission to run the unmodified Program. The output from running a 160 | covered work is covered by this License only if the output, given its 161 | content, constitutes a covered work. This License acknowledges your 162 | rights of fair use or other equivalent, as provided by copyright law. 163 | 164 | You may make, run and propagate covered works that you do not 165 | convey, without conditions so long as your license otherwise remains 166 | in force. You may convey covered works to others for the sole purpose 167 | of having them make modifications exclusively for you, or provide you 168 | with facilities for running those works, provided that you comply with 169 | the terms of this License in conveying all material for which you do 170 | not control copyright. Those thus making or running the covered works 171 | for you must do so exclusively on your behalf, under your direction 172 | and control, on terms that prohibit them from making any copies of 173 | your copyrighted material outside their relationship with you. 174 | 175 | Conveying under any other circumstances is permitted solely under 176 | the conditions stated below. Sublicensing is not allowed; section 10 177 | makes it unnecessary. 178 | 179 | 3. Protecting Users' Legal Rights From Anti-Circumvention Law. 180 | 181 | No covered work shall be deemed part of an effective technological 182 | measure under any applicable law fulfilling obligations under article 183 | 11 of the WIPO copyright treaty adopted on 20 December 1996, or 184 | similar laws prohibiting or restricting circumvention of such 185 | measures. 186 | 187 | When you convey a covered work, you waive any legal power to forbid 188 | circumvention of technological measures to the extent such circumvention 189 | is effected by exercising rights under this License with respect to 190 | the covered work, and you disclaim any intention to limit operation or 191 | modification of the work as a means of enforcing, against the work's 192 | users, your or third parties' legal rights to forbid circumvention of 193 | technological measures. 194 | 195 | 4. Conveying Verbatim Copies. 196 | 197 | You may convey verbatim copies of the Program's source code as you 198 | receive it, in any medium, provided that you conspicuously and 199 | appropriately publish on each copy an appropriate copyright notice; 200 | keep intact all notices stating that this License and any 201 | non-permissive terms added in accord with section 7 apply to the code; 202 | keep intact all notices of the absence of any warranty; and give all 203 | recipients a copy of this License along with the Program. 204 | 205 | You may charge any price or no price for each copy that you convey, 206 | and you may offer support or warranty protection for a fee. 207 | 208 | 5. Conveying Modified Source Versions. 209 | 210 | You may convey a work based on the Program, or the modifications to 211 | produce it from the Program, in the form of source code under the 212 | terms of section 4, provided that you also meet all of these conditions: 213 | 214 | a) The work must carry prominent notices stating that you modified 215 | it, and giving a relevant date. 216 | 217 | b) The work must carry prominent notices stating that it is 218 | released under this License and any conditions added under section 219 | 7. This requirement modifies the requirement in section 4 to 220 | "keep intact all notices". 221 | 222 | c) You must license the entire work, as a whole, under this 223 | License to anyone who comes into possession of a copy. This 224 | License will therefore apply, along with any applicable section 7 225 | additional terms, to the whole of the work, and all its parts, 226 | regardless of how they are packaged. This License gives no 227 | permission to license the work in any other way, but it does not 228 | invalidate such permission if you have separately received it. 229 | 230 | d) If the work has interactive user interfaces, each must display 231 | Appropriate Legal Notices; however, if the Program has interactive 232 | interfaces that do not display Appropriate Legal Notices, your 233 | work need not make them do so. 234 | 235 | A compilation of a covered work with other separate and independent 236 | works, which are not by their nature extensions of the covered work, 237 | and which are not combined with it such as to form a larger program, 238 | in or on a volume of a storage or distribution medium, is called an 239 | "aggregate" if the compilation and its resulting copyright are not 240 | used to limit the access or legal rights of the compilation's users 241 | beyond what the individual works permit. Inclusion of a covered work 242 | in an aggregate does not cause this License to apply to the other 243 | parts of the aggregate. 244 | 245 | 6. Conveying Non-Source Forms. 246 | 247 | You may convey a covered work in object code form under the terms 248 | of sections 4 and 5, provided that you also convey the 249 | machine-readable Corresponding Source under the terms of this License, 250 | in one of these ways: 251 | 252 | a) Convey the object code in, or embodied in, a physical product 253 | (including a physical distribution medium), accompanied by the 254 | Corresponding Source fixed on a durable physical medium 255 | customarily used for software interchange. 256 | 257 | b) Convey the object code in, or embodied in, a physical product 258 | (including a physical distribution medium), accompanied by a 259 | written offer, valid for at least three years and valid for as 260 | long as you offer spare parts or customer support for that product 261 | model, to give anyone who possesses the object code either (1) a 262 | copy of the Corresponding Source for all the software in the 263 | product that is covered by this License, on a durable physical 264 | medium customarily used for software interchange, for a price no 265 | more than your reasonable cost of physically performing this 266 | conveying of source, or (2) access to copy the 267 | Corresponding Source from a network server at no charge. 268 | 269 | c) Convey individual copies of the object code with a copy of the 270 | written offer to provide the Corresponding Source. This 271 | alternative is allowed only occasionally and noncommercially, and 272 | only if you received the object code with such an offer, in accord 273 | with subsection 6b. 274 | 275 | d) Convey the object code by offering access from a designated 276 | place (gratis or for a charge), and offer equivalent access to the 277 | Corresponding Source in the same way through the same place at no 278 | further charge. You need not require recipients to copy the 279 | Corresponding Source along with the object code. If the place to 280 | copy the object code is a network server, the Corresponding Source 281 | may be on a different server (operated by you or a third party) 282 | that supports equivalent copying facilities, provided you maintain 283 | clear directions next to the object code saying where to find the 284 | Corresponding Source. Regardless of what server hosts the 285 | Corresponding Source, you remain obligated to ensure that it is 286 | available for as long as needed to satisfy these requirements. 287 | 288 | e) Convey the object code using peer-to-peer transmission, provided 289 | you inform other peers where the object code and Corresponding 290 | Source of the work are being offered to the general public at no 291 | charge under subsection 6d. 292 | 293 | A separable portion of the object code, whose source code is excluded 294 | from the Corresponding Source as a System Library, need not be 295 | included in conveying the object code work. 296 | 297 | A "User Product" is either (1) a "consumer product", which means any 298 | tangible personal property which is normally used for personal, family, 299 | or household purposes, or (2) anything designed or sold for incorporation 300 | into a dwelling. In determining whether a product is a consumer product, 301 | doubtful cases shall be resolved in favor of coverage. For a particular 302 | product received by a particular user, "normally used" refers to a 303 | typical or common use of that class of product, regardless of the status 304 | of the particular user or of the way in which the particular user 305 | actually uses, or expects or is expected to use, the product. A product 306 | is a consumer product regardless of whether the product has substantial 307 | commercial, industrial or non-consumer uses, unless such uses represent 308 | the only significant mode of use of the product. 309 | 310 | "Installation Information" for a User Product means any methods, 311 | procedures, authorization keys, or other information required to install 312 | and execute modified versions of a covered work in that User Product from 313 | a modified version of its Corresponding Source. The information must 314 | suffice to ensure that the continued functioning of the modified object 315 | code is in no case prevented or interfered with solely because 316 | modification has been made. 317 | 318 | If you convey an object code work under this section in, or with, or 319 | specifically for use in, a User Product, and the conveying occurs as 320 | part of a transaction in which the right of possession and use of the 321 | User Product is transferred to the recipient in perpetuity or for a 322 | fixed term (regardless of how the transaction is characterized), the 323 | Corresponding Source conveyed under this section must be accompanied 324 | by the Installation Information. But this requirement does not apply 325 | if neither you nor any third party retains the ability to install 326 | modified object code on the User Product (for example, the work has 327 | been installed in ROM). 328 | 329 | The requirement to provide Installation Information does not include a 330 | requirement to continue to provide support service, warranty, or updates 331 | for a work that has been modified or installed by the recipient, or for 332 | the User Product in which it has been modified or installed. Access to a 333 | network may be denied when the modification itself materially and 334 | adversely affects the operation of the network or violates the rules and 335 | protocols for communication across the network. 336 | 337 | Corresponding Source conveyed, and Installation Information provided, 338 | in accord with this section must be in a format that is publicly 339 | documented (and with an implementation available to the public in 340 | source code form), and must require no special password or key for 341 | unpacking, reading or copying. 342 | 343 | 7. Additional Terms. 344 | 345 | "Additional permissions" are terms that supplement the terms of this 346 | License by making exceptions from one or more of its conditions. 347 | Additional permissions that are applicable to the entire Program shall 348 | be treated as though they were included in this License, to the extent 349 | that they are valid under applicable law. If additional permissions 350 | apply only to part of the Program, that part may be used separately 351 | under those permissions, but the entire Program remains governed by 352 | this License without regard to the additional permissions. 353 | 354 | When you convey a copy of a covered work, you may at your option 355 | remove any additional permissions from that copy, or from any part of 356 | it. (Additional permissions may be written to require their own 357 | removal in certain cases when you modify the work.) You may place 358 | additional permissions on material, added by you to a covered work, 359 | for which you have or can give appropriate copyright permission. 360 | 361 | Notwithstanding any other provision of this License, for material you 362 | add to a covered work, you may (if authorized by the copyright holders of 363 | that material) supplement the terms of this License with terms: 364 | 365 | a) Disclaiming warranty or limiting liability differently from the 366 | terms of sections 15 and 16 of this License; or 367 | 368 | b) Requiring preservation of specified reasonable legal notices or 369 | author attributions in that material or in the Appropriate Legal 370 | Notices displayed by works containing it; or 371 | 372 | c) Prohibiting misrepresentation of the origin of that material, or 373 | requiring that modified versions of such material be marked in 374 | reasonable ways as different from the original version; or 375 | 376 | d) Limiting the use for publicity purposes of names of licensors or 377 | authors of the material; or 378 | 379 | e) Declining to grant rights under trademark law for use of some 380 | trade names, trademarks, or service marks; or 381 | 382 | f) Requiring indemnification of licensors and authors of that 383 | material by anyone who conveys the material (or modified versions of 384 | it) with contractual assumptions of liability to the recipient, for 385 | any liability that these contractual assumptions directly impose on 386 | those licensors and authors. 387 | 388 | All other non-permissive additional terms are considered "further 389 | restrictions" within the meaning of section 10. If the Program as you 390 | received it, or any part of it, contains a notice stating that it is 391 | governed by this License along with a term that is a further 392 | restriction, you may remove that term. If a license document contains 393 | a further restriction but permits relicensing or conveying under this 394 | License, you may add to a covered work material governed by the terms 395 | of that license document, provided that the further restriction does 396 | not survive such relicensing or conveying. 397 | 398 | If you add terms to a covered work in accord with this section, you 399 | must place, in the relevant source files, a statement of the 400 | additional terms that apply to those files, or a notice indicating 401 | where to find the applicable terms. 402 | 403 | Additional terms, permissive or non-permissive, may be stated in the 404 | form of a separately written license, or stated as exceptions; 405 | the above requirements apply either way. 406 | 407 | 8. Termination. 408 | 409 | You may not propagate or modify a covered work except as expressly 410 | provided under this License. Any attempt otherwise to propagate or 411 | modify it is void, and will automatically terminate your rights under 412 | this License (including any patent licenses granted under the third 413 | paragraph of section 11). 414 | 415 | However, if you cease all violation of this License, then your 416 | license from a particular copyright holder is reinstated (a) 417 | provisionally, unless and until the copyright holder explicitly and 418 | finally terminates your license, and (b) permanently, if the copyright 419 | holder fails to notify you of the violation by some reasonable means 420 | prior to 60 days after the cessation. 421 | 422 | Moreover, your license from a particular copyright holder is 423 | reinstated permanently if the copyright holder notifies you of the 424 | violation by some reasonable means, this is the first time you have 425 | received notice of violation of this License (for any work) from that 426 | copyright holder, and you cure the violation prior to 30 days after 427 | your receipt of the notice. 428 | 429 | Termination of your rights under this section does not terminate the 430 | licenses of parties who have received copies or rights from you under 431 | this License. If your rights have been terminated and not permanently 432 | reinstated, you do not qualify to receive new licenses for the same 433 | material under section 10. 434 | 435 | 9. Acceptance Not Required for Having Copies. 436 | 437 | You are not required to accept this License in order to receive or 438 | run a copy of the Program. Ancillary propagation of a covered work 439 | occurring solely as a consequence of using peer-to-peer transmission 440 | to receive a copy likewise does not require acceptance. However, 441 | nothing other than this License grants you permission to propagate or 442 | modify any covered work. These actions infringe copyright if you do 443 | not accept this License. Therefore, by modifying or propagating a 444 | covered work, you indicate your acceptance of this License to do so. 445 | 446 | 10. Automatic Licensing of Downstream Recipients. 447 | 448 | Each time you convey a covered work, the recipient automatically 449 | receives a license from the original licensors, to run, modify and 450 | propagate that work, subject to this License. You are not responsible 451 | for enforcing compliance by third parties with this License. 452 | 453 | An "entity transaction" is a transaction transferring control of an 454 | organization, or substantially all assets of one, or subdividing an 455 | organization, or merging organizations. If propagation of a covered 456 | work results from an entity transaction, each party to that 457 | transaction who receives a copy of the work also receives whatever 458 | licenses to the work the party's predecessor in interest had or could 459 | give under the previous paragraph, plus a right to possession of the 460 | Corresponding Source of the work from the predecessor in interest, if 461 | the predecessor has it or can get it with reasonable efforts. 462 | 463 | You may not impose any further restrictions on the exercise of the 464 | rights granted or affirmed under this License. For example, you may 465 | not impose a license fee, royalty, or other charge for exercise of 466 | rights granted under this License, and you may not initiate litigation 467 | (including a cross-claim or counterclaim in a lawsuit) alleging that 468 | any patent claim is infringed by making, using, selling, offering for 469 | sale, or importing the Program or any portion of it. 470 | 471 | 11. Patents. 472 | 473 | A "contributor" is a copyright holder who authorizes use under this 474 | License of the Program or a work on which the Program is based. The 475 | work thus licensed is called the contributor's "contributor version". 476 | 477 | A contributor's "essential patent claims" are all patent claims 478 | owned or controlled by the contributor, whether already acquired or 479 | hereafter acquired, that would be infringed by some manner, permitted 480 | by this License, of making, using, or selling its contributor version, 481 | but do not include claims that would be infringed only as a 482 | consequence of further modification of the contributor version. For 483 | purposes of this definition, "control" includes the right to grant 484 | patent sublicenses in a manner consistent with the requirements of 485 | this License. 486 | 487 | Each contributor grants you a non-exclusive, worldwide, royalty-free 488 | patent license under the contributor's essential patent claims, to 489 | make, use, sell, offer for sale, import and otherwise run, modify and 490 | propagate the contents of its contributor version. 491 | 492 | In the following three paragraphs, a "patent license" is any express 493 | agreement or commitment, however denominated, not to enforce a patent 494 | (such as an express permission to practice a patent or covenant not to 495 | sue for patent infringement). To "grant" such a patent license to a 496 | party means to make such an agreement or commitment not to enforce a 497 | patent against the party. 498 | 499 | If you convey a covered work, knowingly relying on a patent license, 500 | and the Corresponding Source of the work is not available for anyone 501 | to copy, free of charge and under the terms of this License, through a 502 | publicly available network server or other readily accessible means, 503 | then you must either (1) cause the Corresponding Source to be so 504 | available, or (2) arrange to deprive yourself of the benefit of the 505 | patent license for this particular work, or (3) arrange, in a manner 506 | consistent with the requirements of this License, to extend the patent 507 | license to downstream recipients. "Knowingly relying" means you have 508 | actual knowledge that, but for the patent license, your conveying the 509 | covered work in a country, or your recipient's use of the covered work 510 | in a country, would infringe one or more identifiable patents in that 511 | country that you have reason to believe are valid. 512 | 513 | If, pursuant to or in connection with a single transaction or 514 | arrangement, you convey, or propagate by procuring conveyance of, a 515 | covered work, and grant a patent license to some of the parties 516 | receiving the covered work authorizing them to use, propagate, modify 517 | or convey a specific copy of the covered work, then the patent license 518 | you grant is automatically extended to all recipients of the covered 519 | work and works based on it. 520 | 521 | A patent license is "discriminatory" if it does not include within 522 | the scope of its coverage, prohibits the exercise of, or is 523 | conditioned on the non-exercise of one or more of the rights that are 524 | specifically granted under this License. You may not convey a covered 525 | work if you are a party to an arrangement with a third party that is 526 | in the business of distributing software, under which you make payment 527 | to the third party based on the extent of your activity of conveying 528 | the work, and under which the third party grants, to any of the 529 | parties who would receive the covered work from you, a discriminatory 530 | patent license (a) in connection with copies of the covered work 531 | conveyed by you (or copies made from those copies), or (b) primarily 532 | for and in connection with specific products or compilations that 533 | contain the covered work, unless you entered into that arrangement, 534 | or that patent license was granted, prior to 28 March 2007. 535 | 536 | Nothing in this License shall be construed as excluding or limiting 537 | any implied license or other defenses to infringement that may 538 | otherwise be available to you under applicable patent law. 539 | 540 | 12. No Surrender of Others' Freedom. 541 | 542 | If conditions are imposed on you (whether by court order, agreement or 543 | otherwise) that contradict the conditions of this License, they do not 544 | excuse you from the conditions of this License. If you cannot convey a 545 | covered work so as to satisfy simultaneously your obligations under this 546 | License and any other pertinent obligations, then as a consequence you may 547 | not convey it at all. For example, if you agree to terms that obligate you 548 | to collect a royalty for further conveying from those to whom you convey 549 | the Program, the only way you could satisfy both those terms and this 550 | License would be to refrain entirely from conveying the Program. 551 | 552 | 13. Use with the GNU Affero General Public License. 553 | 554 | Notwithstanding any other provision of this License, you have 555 | permission to link or combine any covered work with a work licensed 556 | under version 3 of the GNU Affero General Public License into a single 557 | combined work, and to convey the resulting work. The terms of this 558 | License will continue to apply to the part which is the covered work, 559 | but the special requirements of the GNU Affero General Public License, 560 | section 13, concerning interaction through a network will apply to the 561 | combination as such. 562 | 563 | 14. Revised Versions of this License. 564 | 565 | The Free Software Foundation may publish revised and/or new versions of 566 | the GNU General Public License from time to time. Such new versions will 567 | be similar in spirit to the present version, but may differ in detail to 568 | address new problems or concerns. 569 | 570 | Each version is given a distinguishing version number. If the 571 | Program specifies that a certain numbered version of the GNU General 572 | Public License "or any later version" applies to it, you have the 573 | option of following the terms and conditions either of that numbered 574 | version or of any later version published by the Free Software 575 | Foundation. If the Program does not specify a version number of the 576 | GNU General Public License, you may choose any version ever published 577 | by the Free Software Foundation. 578 | 579 | If the Program specifies that a proxy can decide which future 580 | versions of the GNU General Public License can be used, that proxy's 581 | public statement of acceptance of a version permanently authorizes you 582 | to choose that version for the Program. 583 | 584 | Later license versions may give you additional or different 585 | permissions. However, no additional obligations are imposed on any 586 | author or copyright holder as a result of your choosing to follow a 587 | later version. 588 | 589 | 15. Disclaimer of Warranty. 590 | 591 | THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY 592 | APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT 593 | HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY 594 | OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, 595 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 596 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM 597 | IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF 598 | ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 599 | 600 | 16. Limitation of Liability. 601 | 602 | IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 603 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS 604 | THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY 605 | GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE 606 | USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF 607 | DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD 608 | PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), 609 | EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF 610 | SUCH DAMAGES. 611 | 612 | 17. Interpretation of Sections 15 and 16. 613 | 614 | If the disclaimer of warranty and limitation of liability provided 615 | above cannot be given local legal effect according to their terms, 616 | reviewing courts shall apply local law that most closely approximates 617 | an absolute waiver of all civil liability in connection with the 618 | Program, unless a warranty or assumption of liability accompanies a 619 | copy of the Program in return for a fee. 620 | 621 | END OF TERMS AND CONDITIONS 622 | 623 | How to Apply These Terms to Your New Programs 624 | 625 | If you develop a new program, and you want it to be of the greatest 626 | possible use to the public, the best way to achieve this is to make it 627 | free software which everyone can redistribute and change under these terms. 628 | 629 | To do so, attach the following notices to the program. It is safest 630 | to attach them to the start of each source file to most effectively 631 | state the exclusion of warranty; and each file should have at least 632 | the "copyright" line and a pointer to where the full notice is found. 633 | 634 | {one line to give the program's name and a brief idea of what it does.} 635 | Copyright (C) {year} {name of author} 636 | 637 | This program is free software: you can redistribute it and/or modify 638 | it under the terms of the GNU General Public License as published by 639 | the Free Software Foundation, either version 3 of the License, or 640 | (at your option) any later version. 641 | 642 | This program is distributed in the hope that it will be useful, 643 | but WITHOUT ANY WARRANTY; without even the implied warranty of 644 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 645 | GNU General Public License for more details. 646 | 647 | You should have received a copy of the GNU General Public License 648 | along with this program. If not, see . 649 | 650 | Also add information on how to contact you by electronic and paper mail. 651 | 652 | If the program does terminal interaction, make it output a short 653 | notice like this when it starts in an interactive mode: 654 | 655 | {project} Copyright (C) {year} {fullname} 656 | This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 657 | This is free software, and you are welcome to redistribute it 658 | under certain conditions; type `show c' for details. 659 | 660 | The hypothetical commands `show w' and `show c' should show the appropriate 661 | parts of the General Public License. Of course, your program's commands 662 | might be different; for a GUI interface, you would use an "about box". 663 | 664 | You should also get your employer (if you work as a programmer) or school, 665 | if any, to sign a "copyright disclaimer" for the program, if necessary. 666 | For more information on this, and how to apply and follow the GNU GPL, see 667 | . 668 | 669 | The GNU General Public License does not permit incorporating your program 670 | into proprietary programs. If your program is a subroutine library, you 671 | may consider it more useful to permit linking proprietary applications with 672 | the library. If this is what you want to do, use the GNU Lesser General 673 | Public License instead of this License. But first, please read 674 | . 675 | 676 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # A Crude Emulator for the 65816 in Forth 2 | 3 | Scot W. Stevenson 4 | 5 | 6 | ### TL;DR 7 | 8 | This is an ALPHA version of an emulator for the 65816 8/16-bit CPU in Gforth. 9 | "Alpha" means that "everything does something, sometimes even the right thing". 10 | If you must jump in without reading the documentation, start it with 11 | 12 | ``` 13 | gforth -m 18M 14 | ``` 15 | 16 | and then load the emulator with 17 | 18 | ``` 19 | include crude65816.fs 20 | ``` 21 | 22 | You an either "run" or "step" through whatever is setup in CONFIG.FS. There is a 23 | discussion of the program [at 6502.org] 24 | (http://forum.6502.org/viewtopic.php?f=8&t=3306). 25 | 26 | ### SO WHAT'S THIS NOW? 27 | 28 | The 65816 is the ["big sibling"](http://en.wikipedia.org/wiki/WDC_65816/65802) 29 | of the venerable 6502 8-bit processor. It is a hybrid processor that can run in 30 | 16-bit ("native") and 8-bit ("emulated") mode. Its core can be found in single 31 | board computers such as the 32 | [W65C265SXB](http://wdc65xx.com/65xx-store/sxb-boards/w65c265sxb-engineering-development-system/). 33 | 34 | After bulding a 6502 machine as a hobby, [the "Übersquirrel" Mark Zero] 35 | (http://uebersquirrel.blogspot.de/) (ÜSqM0), I found eight bits to be too 36 | limiting. The 65816 is the logical next step up, since you can reuse the 8-bit 37 | code at first. 38 | 39 | Unfortunately, emulators for the 65816 are few and far between, and so I decided 40 | I would have to write my own. This is it. It is horribly crude -- hence the 41 | name. For instance, it completely ignores all timing and clock considerations. 42 | But it works. 43 | 44 | ### BUT MOTHER OF DRAGONS, WHY IN FORTH? 45 | 46 | The Übersquirrel Mark Zero taught me how powerful Forth is on simple hardware, 47 | how short the programs can be, and how fun it is just to code it. In fact one of 48 | the main reasons for switching to the 65816 is to be able to do more with Forth. 49 | The Crude Emulator itself relies on modern hardware to work and just assumes we 50 | have enough RAM and a fast processor for everything. 51 | 52 | See `docs/MANUAL.txt` for further information. 53 | 54 | ### DEVELOPMENT SPEED 55 | 56 | This program is a hobby, and is developed in fits and starts. Feedback is most 57 | welcome. 58 | -------------------------------------------------------------------------------- /config.fs: -------------------------------------------------------------------------------- 1 | \ Configuration file for A Crude 65816 Emulator 2 | \ Scot W. Stevenson 3 | \ This version: 25. Dec 2016 4 | 5 | \ This file must be included in crude65816.fs before io.fs 6 | 7 | \ --- ROMS --- 8 | 9 | \ Pick one as the operating system. 00ff00 is putchr, 00ff01 is getchar 10 | 11 | \ NOTE: THE FOLLOWING TWO ROMS ARE CURRENTLY BROKEN 12 | \ 00e000 s" roms/rom65816.bin" loadrom \ operating system, BIOS, *DEFAULT* 13 | \ 00e000 s" roms/rom65c02.bin" loadrom \ test program for the 65c02 14 | 15 | \ Dummy file to show how other ROM data is loaded. Later, these can be program 16 | \ libraries or other ROM chips. 17 | \ 800000 s" data.bin" loadrom 18 | 19 | \ Tests. Unless your name is Scot, you probably don't want to touch these 20 | \ 008000 s" tests/tink.bin" loadrom \ LiaraForth test for 265sxb Flash RAM 21 | 006000 s" tests/tink.bin" loadrom \ LiaraForth test for 265sxb RAM 22 | 23 | \ --- I/O ADRESSES --- 24 | 25 | \ These are referenced by io.fs These I/O addresses represent where (say) 26 | \ a 6522 would be in real hardware to write to and read from. The routines 27 | \ themselves are located in io.fs . If you do not need the default values, 28 | \ uncomment those you do. 29 | 30 | \ Default I/O addresses - use these when you don't care 31 | \ 00ff00 value putchr 32 | \ 00ff01 value getchr \ blocks until character received 33 | 34 | 35 | \ ** Stuff for the W65C265SXB MMM ROM ** 36 | \ These are for use with the Mock Mensch Monitor emulation ROM for the 265SXB. 37 | \ We're so crude in this version that we just need an address as a hook, 38 | \ regardless if it is where the real 265SXB writes to or not. These are subject 39 | \ to change as the emulation gets better. 40 | 00df75 value getchr \ actually the data register of UART 2 41 | 00df77 value putchr \ actually the data register of UART 3 42 | \ 008000 s" roms/mmm/test_mmm.bin" loadrom \ Test suite for the MMM ROM 43 | \ 00e000 s" roms/mmm/mmm.bin" loadrom \ Mock Mensch Monitor W65C265SXB ROM 44 | -------------------------------------------------------------------------------- /crude65816.fs: -------------------------------------------------------------------------------- 1 | \ A Crude 65816 Emulator 2 | \ Copyright 2015, 2016 Scot W. Stevenson 3 | \ Written with gforth 0.7 4 | \ First version: 09. Jan 2015 5 | \ This version: 22. Dec 2016 6 | 7 | \ This program is free software: you can redistribute it and/or modify 8 | \ it under the terms of the GNU General Public License as published by 9 | \ the Free Software Foundation, either version 3 of the License, or 10 | \ (at your option) any later version. 11 | 12 | \ This program is distributed in the hope that it will be useful, 13 | \ but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | \ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | \ GNU General Public License for more details. 16 | 17 | \ You should have received a copy of the GNU General Public License 18 | \ along with this program. If not, see . 19 | 20 | cr .( A Crude 65816 Emulator in Forth) 21 | cr .( Version ALPHA 22. Dec 2016) 22 | cr .( Copyright 2015 Scot W. Stevenson ) 23 | cr .( This program comes with ABSOLUTELY NO WARRANTY) cr 24 | 25 | 26 | \ ---- DEFINITIONS ---- 27 | cr .( Defining general stuff ...) 28 | hex 29 | 30 | 1000000 constant 16M 31 | 32 | 33 | \ ---- HARDWARE: CPU ---- 34 | cr .( Setting up CPU ... ) 35 | 36 | \ Names follow the convention from the WDC data sheet. We use uppercase letters. 37 | \ P is generated through "P>", not stored, as are A and the B register 38 | variable PC \ Program counter (16 bit) 39 | variable C \ C register (16 bit); MSB is B, LSB is A 40 | variable X \ X register (8\16 bit) 41 | variable Y \ Y register (8\16 bit) 42 | variable D \ Direct register (Zero Page on 6502) (16 bit) 43 | variable S \ Stack Pointer (8/16 bit) 44 | variable DBR \ Data Bank register ("B") (8 bit) 45 | variable PBR \ Program Bank register ("K") (8 bit) 46 | 47 | variable current-opcode 48 | 49 | \ Vectors for interrupts 50 | 00fffc constant reset-v \ same for emulated and native modes 51 | 52 | defer abort-v 00ffe8 constant abort-v.n 00fff8 constant abort-v.e 53 | defer cop-v 00ffe4 constant cop-v.n 00fff4 constant cop-v.e 54 | defer irq-v 00ffee constant irq-v.n 00fffe constant irq-v.e 55 | defer nmi-v 00ffea constant nmi-v.n 00fffa constant nmi-v.e 56 | defer brk-v 00ffe6 constant brk-v.n 00fffe constant brk-v.e 57 | 58 | 59 | \ ---- HELPER FUNCTIONS ---- 60 | cr .( Creating helper functions ...) 61 | \ These all assume HEX 62 | 63 | \ mask addresses / hex numbers 64 | defer mask.a defer mask.xy 65 | : mask8 ( u -- u8 ) 0ff and ; 66 | : mask16 ( u -- u16 ) 0ffff and ; 67 | : mask24 ( u -- u24 ) 0ffffff and ; 68 | 69 | \ Print byte as bits, does not add space, returns as HEX 70 | : .8bits ( u -- ) 71 | 2 base ! s>d <# # # # # # # # # #> type hex ; 72 | 73 | \ Format numbers to two, four, and six places, assumes HEX 74 | : .byte ( n -- ) s>d <# # # #> type space ; 75 | : .word ( n -- ) s>d <# # # # # #> type space ; 76 | : .longword ( n -- ) s>d <# # # # # # # #> type space ; 77 | 78 | \ return least, most significant byte of 16-bit number 79 | : lsb ( u -- u8 ) mask8 ; 80 | : msb ( u -- u8 ) 0ff00 and 8 rshift ; 81 | : bank ( u -- u8 ) 10 rshift mask8 ; 82 | 83 | \ Extend the sign of an 8-bit/16-bit number in a way we don't have to care about 84 | \ how large the cell size on the Forth machine is. Assumes that TRUE flag is 85 | \ some form of FFFF. MASK8/MASK16 is paranoid. Assumes HEX. 86 | : signextend ( u8 -- u ) mask8 dup 80 and 0<> 8 lshift or ; 87 | : signextend.l ( u16 -- u ) mask16 dup 8000 and 0<> 10 lshift or ; 88 | 89 | \ Accumulator manipulation 90 | \ Because we are paranoid, we tend to MASK16 all registers before we store them 91 | \ in their variables 92 | : C>A ( u16 -- u8 ) lsb ; \ gives us A from C during 8 to 16 bit switch 93 | : C>B ( u16 -- u8 ) msb ; \ gives us B from C during 8 to 16 bit switch 94 | : A ( -- u8 ) C @ C>A ; \ A is a word, not variable 95 | : B ( -- u8 ) C @ C>B ; \ B is a word, not variable 96 | \ Save A into C, protecting B 97 | : A>C! ( u8 -- ) B 8 lshift or mask16 C ! ; 98 | 99 | \ Take values from TOS and store them in the Accumulator depending on their size 100 | defer >C 101 | : 8>C! ( u8 -- ) mask8 B 8 lshift or C ! ; 102 | : 16>C! ( u16 -- ) mask16 C ! ; 103 | 104 | \ Takes C and puts it TOS depending on the size of the accumulator 105 | defer C> 106 | : C>8 ( -- u8 ) A ; 107 | : C>16 ( -- u16 ) C @ mask16 ; \ MASK is paranoid 108 | 109 | \ 16 bit addresses and endian conversion 110 | : 16>lsb/msb ( u16 -- lsb msb ) dup lsb swap msb ; 111 | : lsb/msb>16 ( lsb msb -- u16 ) 8 lshift or ; 112 | : msb/lsb>16 ( msb lsb -- u16 ) swap lsb/msb>16 ; 113 | 114 | \ 24 bit to three bytes 115 | : 24>bank/msb/lsb ( u24 -- bank msb lsb ) 116 | dup 16>lsb/msb ( u24 lsb msb ) 117 | swap rot ( msb lsb u24 ) 118 | bank -rot ; ( bank msb lsb ) 119 | : 24>lsb/msb/bank ( u24 -- lsb msb bank ) 120 | dup 16>lsb/msb ( n lsb msb ) 121 | rot bank ; ( lsb msb bank) 122 | 123 | \ Program Counter. Automatically wraps at 16 bit 124 | : PC+1 ( -- ) PC @ 1+ mask16 PC ! ; 125 | : PC+2 ( -- ) PC @ 2 + mask16 PC ! ; 126 | 127 | \ Make 24 bit value the new 24 bit address 128 | : 24>PC24! ( 65addr24 -- ) 24>lsb/msb/bank PBR ! lsb/msb>16 PC ! ; 129 | 130 | \ Convert various combinations to full 24 bit address. Assumes HEX 131 | \ Paranoid: Makes sure that 16 bit address is really only 16 bit 132 | : mem16/bank>24 ( 65addr16 bank -- 65addr24 ) 133 | swap mask16 swap 10 lshift or ; 134 | : mem16/PBR>24 ( 65addr16 -- 65addr24 ) PBR @ mem16/bank>24 ; 135 | : mem16/DBR>24 ( 65addr16 -- 65addr24 ) DBR @ mem16/bank>24 ; 136 | 137 | \ Create a full 24 bit address that is in bank zero. In other words, wrap to 138 | \ bank zero 139 | : mem16/bank00>24 ( 65addr16 -- 65addr24 ) 00 mem16/bank>24 ; 140 | : lsb/msb/bank>24 ( lsb msb bank -- 65addr24 ) 141 | -rot lsb/msb>16 swap mem16/bank>24 ; 142 | 143 | \ Advance PC depending on what size our registers are 144 | defer PC+a defer PC+xy 145 | 146 | \ Get full 24 bit current address (PC plus PBR) 147 | : PC24 ( -- 65addr24) PC @ PBR @ mem16/bank>24 ; 148 | 149 | \ Increase a full 24 bit address by n, but wrap so that the bank byte is not 150 | \ affected; that is, increase the "PC" part by one and wrap to bank 151 | : 65addr+/wrap ( n 65addr24 -- 65addr24+1 ) 152 | >r dup mask16 r> + mask16 swap bank mem16/bank>24 ; 153 | 154 | 155 | \ ---- MEMORY ---- 156 | cr .( Creating memory ...) 157 | 158 | \ All accesses to memory are always full 24 bit. Stack follows little-endian 159 | \ format with bank on top, then msb and lsb ( lsb msb bank -- ). However, we use 160 | \ the "normal" number for all calculations, so we need to convert all fetches. 161 | \ Also, we just allot the whole possible memory range. Note that this will fail 162 | \ unless you called Gforth with "-m 1G" or something of that size like you were 163 | \ told in the MANUAL.txt . You did read the manual, didn't you? 164 | create memory 16M allot 165 | 166 | : loadrom ( 65addr24 addr u -- ) 167 | r/o open-file drop ( 65addr fileid ) 168 | slurp-fid ( 65addr addr u ) 169 | rot memory + swap ( addr 65addrROM u ) 170 | move ; 171 | 172 | \ load ROM files into memory 173 | cr .( Loading ROM files to memory ...) 174 | include config.fs 175 | 176 | \ set up I/O stuff. Must be loaded after config.fs 177 | cr .( Setting up I/O system ...) 178 | include io.fs 179 | 180 | 181 | \ -- FETCH FROM MEMORY -- 182 | 183 | \ Fetching data from memory depends on two things: The size of the register in 184 | \ question (8/16 bit) and the memory structure based on banks. We adapt to the 185 | \ size of the register by DEFERing the general routine and switching what it 186 | \ refers to when the m- and x-flags are switched 187 | 188 | \ Simple FETCH are the basic routines that do not affect the PC and ignore 189 | \ wrapping. Used as the basis for all other fetch versions. FETCH8 includes the 190 | \ check for special addresses (I/O chips, etc) so all other store words must be 191 | \ based on it. Note we have to include this even for stack accesses because 192 | \ somebody might be crazy enough to put the stack over the I/O addresses in bank 193 | \ 00 194 | : fetch8 ( 65addr24 -- u8 ) 195 | special-fetch? dup 0= if ( 65addr24 0|xt) 196 | drop memory + c@ else \ c@ means no MASK8 is required 197 | nip execute then ; 198 | : fetch16 ( 65addr24 -- u16 ) 199 | dup fetch8 swap 1+ fetch8 lsb/msb>16 ; 200 | : fetch24 ( 65addr24 -- u24 ) 201 | dup fetch8 over 1+ fetch8 rot 2 + fetch8 lsb/msb/bank>24 ; 202 | 203 | \ FETCH/WRAP ("fetch with wrap") take an address and walks through it 204 | \ byte-for-byte in case there is a bank boundry that is crossed. These are used 205 | \ for LDA instructions, for example. These do not touch the PC, use FETCHPC for 206 | \ that 207 | defer fetch/wrap.a defer fetch/wrap.xy 208 | : fetch/wrap8 ( 65addr24 -- u8) fetch8 ; 209 | : fetch/wrap16 ( 65addr24 -- u16 ) 210 | dup fetch8 swap 1 65addr+/wrap fetch8 lsb/msb>16 ; 211 | : fetch/wrap24 ( 65addr24 -- u24 ) 212 | dup fetch16 swap 2 65addr+/wrap fetch8 mem16/bank>24 ; 213 | 214 | \ FETCHPC advances the PC while making sure we wrap at the bank boundry. Used 215 | \ to get the opcodes of the instructions. 216 | defer fetchPC.a defer fetchPC.xy 217 | : fetchPC8 ( -- u8 ) PC @ PBR @ mem16/bank>24 fetch8 PC+1 ; 218 | : fetchPC16 ( -- u16 ) fetchPC8 fetchPC8 lsb/msb>16 ; 219 | : fetchPC24 ( -- u24 ) fetchPC16 fetchPC8 mem16/bank>24 ; 220 | 221 | 222 | \ -- STORE IN MEMORY -- 223 | 224 | \ See remarks on fetching data from memory 225 | 226 | \ Simply store routines that do not affect the PC and ignore wrapping. STORE8 227 | \ includes the check for special addresses (I/O chips, etc) so all other store 228 | \ words must be based on it. 229 | defer store.a defer store.xy 230 | : store8 ( u8 65addr24 -- ) 231 | special-store? dup 0= if ( u8 65addr24 0|xt) 232 | drop memory + c! else \ C! means that no MASK is required 233 | nip execute then ; 234 | : store16 ( u16 65addr24 -- ) 235 | 2dup swap lsb swap store8 swap msb swap 1+ store8 ; 236 | : store24 ( u24 65addr24 -- ) \ This is only used for debugging 237 | dup 3 + swap >r >r \ Create and save loop parameters 238 | 24>bank/msb/lsb 239 | r> r> do i store8 loop ; 240 | 241 | \ STORE/WRAP ("store with wrap") stores a byte or a double byte on 242 | \ a byte-for-byte basis for cases when a bank-boundry can be crossed. These are 243 | \ used for STA instructions (duh). These do not touch the PC. There is no need 244 | \ for a STORE/WRAP24 245 | defer store/wrap.a defer store/wrap.xy 246 | : store/wrap8 ( u8 65addr24 -- ) store8 ; 247 | : store/wrap16 ( u16 65addr24 -- ) 248 | 2dup swap lsb swap store8 \ LSB 249 | swap msb swap 1 65addr+/wrap store8 ; \ MSB 250 | 251 | 252 | \ ---- FLAGS ---- 253 | cr .( Setting up flag routines ... ) 254 | 255 | \ make flag routines easier for humans to work with 256 | : set? ( addr -- f ) @ ; 257 | : clear? ( addr -- f ) @ invert ; 258 | : set ( addr -- ) true swap ! ; 259 | : clear ( addr -- ) false swap ! ; 260 | 261 | \ All 65816 are fully-formed Forth flags, that is, one cell wide. There is no 262 | \ flag in bit 5 in emulation mode. The convention is to use lowercase letters 263 | \ for the flags to avoid confusion with the register names 264 | 265 | create flags 266 | false , false , false , false , false , false , false , false , 267 | 268 | \ We start with n-flag, not c-flag, as first (LSBit) entry in the table to make 269 | \ creating P> with loops easier. 270 | : n-flag ( -- addr ) flags ; \ bit 7 271 | : v-flag ( -- addr ) flags cell + ; \ bit 6 272 | : m-flag ( -- addr ) flags 2 cells + ; \ bit 5 in native mode 273 | : x-flag ( -- addr ) flags 3 cells + ; \ bit 4 in native mode 274 | : b-flag ( -- addr ) flags 3 cells + ; \ bit 4 in emulated mode 275 | : d-flag ( -- addr ) flags 4 cells + ; \ bit 3 276 | : i-flag ( -- addr ) flags 5 cells + ; \ bit 2 277 | : z-flag ( -- addr ) flags 6 cells + ; \ bit 1 278 | : c-flag ( -- addr ) flags 7 cells + ; \ bit 0 279 | 280 | \ And then there's this guy. Emulation flag is not part of the status byte 281 | variable e-flag 282 | 283 | \ We don't use bit 5 in emulation mode, but it looks weird if it is set when we 284 | \ switch from 16-bit A in native to emulation mode, so we take care of it 285 | \ TODO check hardware to see what actually happens during these switches 286 | : unused-flag ( -- addr ) flags 2 cells + ; 287 | 288 | \ These are used to make a flag reflect the set/clear status of a bit in a byte 289 | \ or word provided. Mask byte or word with AND to isolate single bits and then 290 | \ use there 291 | : test&set-c ( u -- ) 0<> c-flag ! ; 292 | : test&set-n ( u -- ) 0<> n-flag ! ; 293 | : test&set-v ( u -- ) 0<> v-flag ! ; 294 | : test&set-z ( u -- ) 0= z-flag ! ; 295 | 296 | defer mask-n.a defer mask-n.xy 297 | : mask-n.8 ( u8 -- u8 ) 80 and ; 298 | : mask-n.16 ( u16 -- u16 ) 8000 and ; 299 | 300 | defer mask-v.a 301 | : mask-v.8 ( u8 -- u8 ) 40 and ; 302 | : mask-v.16 ( u16 -- u16 ) 4000 and ; 303 | 304 | : mask-c ( u -- u ) 1 and ; 305 | 306 | \ ---- TEST AND SET FLAGS ---- 307 | \ The basic, unspecific routines consume TOS, the register functions do not 308 | 309 | \ Carry Flag 310 | : check-c ( n n -- ) < invert c-flag ! ; 311 | 312 | \ Negative Flag 313 | : check-n8 ( n -- ) mask-n.8 test&set-n ; 314 | : check-n16 ( n -- ) mask-n.16 test&set-n ; 315 | : check-n.a ( -- ) C> mask-n.a test&set-n ; 316 | 317 | \ Zero Flag. We don't need a separate test routine for X and Y because they are 318 | \ always tested together with the Negative flag 319 | : check-z.a ( -- ) C> test&set-z ; 320 | 321 | \ Common combinations 322 | : check-nz.a ( -- ) check-n.a check-z.a ; 323 | : check-nz.xy ( X|Y -- ) dup mask-n.xy test&set-n test&set-z ; 324 | : check-nz.x ( -- ) X @ check-nz.xy ; 325 | : check-nz.y ( -- ) Y @ check-nz.xy ; 326 | 327 | defer check-nz.TOS \ Used for LSR and other instructions that don't work on C 328 | : check-nz.8 ( n8 -- ) dup check-n8 test&set-z ; 329 | : check-nz.16 ( n16 -- ) dup check-n16 test&set-z ; 330 | 331 | \ Routines to find out if addition produced a carry flag 332 | defer carry? 333 | : carry?.8 ( u -- f ) 100 and 0<> ; 334 | : carry?.16 ( u -- f ) 10000 and 0<> ; 335 | 336 | \ Create status byte out of flag array. We don't care if we are in emulation or 337 | \ native mode 338 | : P> ( -- u8 ) 339 | 00 \ initialize P> byte 340 | 8 0 ?do 341 | 1 lshift \ next bit; note first shift is a dummy 342 | flags i cells + @ \ loop thru flag table, from high bit to low 343 | 1 and + \ get last bit of Forth flag 344 | loop ; 345 | 346 | 347 | \ --- BCD ROUTINES --- 348 | cr .( Setting up BCD routines ...) 349 | 350 | \ BCD is required for decimal mode addition and subtraction operations. It is 351 | \ also a pain in the rear. See http://www.6502.org/tutorials/decimal_mode.html 352 | \ and https://en.wikipedia.org/wiki/Binary-coded_decimal for the background on 353 | \ these routines. Check the Known Issues section of MANUAL.txt for known 354 | \ problems with these routines 355 | 356 | \ TODO We should be able to simplify and condense these once they are very, 357 | \ very throughly tested 358 | 359 | \ -- 8 bits -- 360 | 361 | \ Nine's complement of a nibble, for BCD subtraction 362 | : 9s-comp ( u -- u ) 9 swap - ; 363 | 364 | : byte>nibbles ( u -- nh nl ) dup 0f0 and 4 rshift swap 0f and ; 365 | : nibbles>byte ( nh nl -- u ) swap 4 lshift or ; 366 | 367 | \ Split up a byte into nibbles that are nine's complement, used for BCD 368 | \ subtraction 369 | : byte>9s-nibbles ( u -- nh nl ) 370 | dup 0f0 and 4 rshift 9s-comp 371 | swap 0f and 9s-comp ; 372 | 373 | \ Split up two bytes and interweave their nibbles so they are ready for addition 374 | : nibbleweave-add ( u1 u2 -- n2h n1h n1l n2l) 375 | byte>nibbles rot byte>nibbles rot ; 376 | 377 | \ Split up two bytes and interweave their nibbles so they are ready for 378 | \ subtraction (more exactly, addition with nine's complement) 379 | : nibbleweave-sub ( u1 u2 -- n1h n2h n1l n2l) 380 | byte>9s-nibbles rot byte>nibbles rot 381 | >r -rot swap rot r> ; \ order is important for subtraction 382 | 383 | \ Add two nibbles in BCD style. Intialize the carry with zero. Results in the 384 | \ sum of the two nibbles (nr) and the "carry nibble" (nc) that is reused 385 | : bcd-add-nibble ( n1 n2 c -- nc nr) + + dup 9 > if 6 + then byte>nibbles ; 386 | 387 | \ Add two nibbles in BCD style. Intialize the carry with zero. Results in the 388 | \ sum of the two nibbles (nr) and the "carry nibble" (nc) that is reused 389 | : bcd-sub-nibble ( n1 n2 c -- nc nr) + + dup 9 > if 6 + then byte>nibbles ; 390 | 391 | \ Add two bytes BCD style, including the c-flag. We use this routine for the 392 | \ 8-bit ADC routine when the d-flag ist set 393 | : bcd-add-bytes ( u1 u2 -- ur ) 394 | nibbleweave-add c-flag @ mask-c 395 | bcd-add-nibble >r ( n2h n1h nc -- R: nl ) 396 | bcd-add-nibble r> nibbles>byte ( nc nr ) 397 | swap test&set-c ; 398 | 399 | \ Subtract two bytes BCD style, including the c-flag. We use this routine 400 | \ for the 8-bit SBC routine when the d-flag ist set 401 | : bcd-sub-bytes ( u1 u2 -- ur ) 402 | swap \ We fetch the operand before we get the accumulator 403 | nibbleweave-sub c-flag @ mask-c 404 | bcd-sub-nibble >r ( n2h n1h nc -- R: nl ) 405 | bcd-sub-nibble r> nibbles>byte ( nc nr ) 406 | swap test&set-c ; 407 | 408 | \ -- 16 bits -- 409 | 410 | : word>bytes ( w -- uh ul ) dup 0ff00 and 8 rshift swap 0ff and ; 411 | : bytes>word ( uh ul -- w ) swap 8 lshift or ; 412 | 413 | \ Split up two words and interweave their words so they are ready for addition 414 | : byteweave-add ( w1 w2 -- u2h u1h u1l u2l) word>bytes rot word>bytes rot ; 415 | 416 | \ Add two words BCD style, including the c-flag. We use this routine for the 417 | \ 16-bit ADC routine when the d-flag ist set 418 | : bcd-add-words ( w1 w2 -- w2 ) 419 | byteweave-add bcd-add-bytes >r bcd-add-bytes r> bytes>word ; 420 | 421 | \ Split up two words and interweave their words so they are ready for 422 | \ subtraction (rather, addition with nine's complement) 423 | : byteweave-sub ( w1 w2 -- u1h u2h u1l u2l) 424 | word>bytes rot word>bytes -rot swap rot ; 425 | \ 426 | \ Subtract two words BCD style, including the c-flag. We use this routine 427 | \ for the 16-bit SBC routine when the d-flag ist set 428 | : bcd-sub-words ( w1 w2 -- w2 ) 429 | byteweave-sub swap bcd-sub-bytes >r swap bcd-sub-bytes r> bytes>word ; 430 | 431 | 432 | \ --- COMPARE INSTRUCTIONS --- 433 | 434 | \ See http://www.6502.org/tutorials/compare_beyond.html for discussion 435 | defer cmp.a defer cmp.xy 436 | : cmp8 ( AXY u8 -- ) 2dup check-c - check-nz.8 ; 437 | : cmp16 ( CXY u16 -- ) 2dup check-c - check-nz.16 ; 438 | 439 | \ --- BRANCHING --- 440 | cr .( Setting up branching ...) 441 | 442 | : takebranch ( -- ) PC24 fetch8 signextend 1+ PC @ + PC ! ; 443 | : branch-if-true ( f -- ) if takebranch else PC+1 then ; 444 | 445 | 446 | \ --- STACK STUFF ---- 447 | cr .( Setting up stack ...) 448 | 449 | \ Stack wrapping is just about as much fun as Direct Page wrapping. When S is 450 | \ increased or decreased, we wrap to bank 00, page 01 if two conditions are 451 | \ true: We are in emulated mode and we're dealing with an "old" instruction 452 | \ that was already available on the 65C02. Otherwise, we just wrap to bank 0. 453 | \ See http://6502.org/tutorials/65c816opcodes.html#5.22 for details. Remember 454 | \ S points to the next empty stack entry 455 | defer S++ defer S-- 456 | 457 | \ There are 10 old instructions that affect the stack and 11 new ones. Searching 458 | \ through the old ones is slightly more efficient 459 | create old-s-opcodes 460 | 08 c, ( php) 20 c, ( jsr) 48 c, ( pha) 5a c, ( phy) 0da c, ( phx) 461 | 28 c, ( plp) 60 c, ( rts) 68 c, ( pla) 7a c, ( ply) 0fa c, ( plx) 462 | 463 | : new-s-opcode? ( -- f ) 464 | true current-opcode @ ( f u8) 465 | 0a 0 do 466 | dup old-s-opcodes i + c@ 467 | = if nip false swap then 468 | loop drop ; 469 | 470 | \ Increase and decrease stack pointer in native mode or if emulated mode with 471 | \ new instructions. We wrap to bank 0. This is the fast, easy case we like. 472 | : S++.n ( -- ) S @ 1+ mask16 S ! ; 473 | : S--.n ( -- ) S @ 1- mask16 S ! ; 474 | 475 | \ Increase or decrease the stack pointer by one, wrapping to page 01 and bank 00 476 | \ boundries 477 | : S++/wrap ( -- ) S @ 1+ mask8 0100 or S ! ; \ mask8 includes wrap to bank 478 | : S--/wrap ( -- ) S @ 1- mask8 0100 or S ! ; \ mask8 includes wrap to bank 479 | 480 | \ If this is a new opcode, we have to wrap to page 01 481 | : S++.e ( -- ) new-s-opcode? if S++.n else S++/wrap then ; 482 | : S--.e ( -- ) new-s-opcode? if S--.n else S--/wrap then ; 483 | 484 | \ Push stuff to stack. Use the naked STORE8 routine here because we don't want 485 | \ to touch the PC and S++ handles all the wrapping problems. PUSH8 is the base 486 | \ word for all other forms. 487 | defer push.a defer push.xy 488 | : push8 ( n8 -- ) S @ store8 S-- ; 489 | : push16 ( n16 -- ) 16>lsb/msb push8 push8 ; 490 | : push24 ( n24 -- ) 24>bank/msb/lsb rot push8 swap push8 push8 ; 491 | 492 | \ Pull stuff from stack. Use the naked FETCH8 routine here because we don't 493 | \ want to touch the PC and S++ handles the wrapping problems. PULL8 is the base 494 | \ word for all other forms 495 | defer pull.a defer pull.xy 496 | : pull8 ( -- n8 ) S++ S @ fetch8 ; 497 | : pull16 ( -- n16 ) pull8 pull8 lsb/msb>16 ; 498 | : pull24 ( -- n24 ) pull8 pull8 pull8 lsb/msb/bank>24 ; 499 | 500 | 501 | \ --- INTERRUPT ROUTINES --- 502 | cr .( Setting up interrupt routines ...) 503 | 504 | \ We do not use the BRK command to drop out of a running loop during emulation, 505 | \ this is the job of WAI and STP. 506 | defer brk.a 507 | : brk-core ( -- ) 508 | ." *** BRK encountered at " PC24 .longword ." ***" 509 | d-flag clear PC+1 PC @ push16 P> push8 i-flag set 510 | brk-v fetch/wrap16 PC ! ; 511 | : brk.n ( -- ) PBR @ push8 0 PBR ! brk-core ; 512 | : brk.e ( -- ) b-flag set brk-core ; 513 | 514 | \ COP is used as in textbook 515 | defer cop.a 516 | : cop.e ( -- ) 517 | ." *** COP encountered at " PC24 .longword ." ***" 518 | PC @ 2 + mask16 push16 519 | P> push8 520 | i-flag set 521 | d-flag clear 522 | cop-v fetch/wrap16 PC ! ; 523 | 524 | : cop.n ( -- ) PBR @ push8 0 PBR ! cop.e ; 525 | 526 | 527 | \ ---- REGISTER MODE SWITCHES ---- 528 | 529 | \ We use two internal flags to remember the width of the registers. Don't use 530 | \ the x and m flags directly because this can screw up the status byte P> 531 | variable a16flag a16flag clear 532 | variable xy16flag xy16flag clear 533 | 534 | \ Switch accumulator 8<->16 bit (p. 51 in Manual) 535 | : a:16 ( -- ) 536 | ['] fetch/wrap16 is fetch/wrap.a 537 | ['] fetchPC16 is fetchPC.a 538 | ['] store16 is store.a 539 | ['] store/wrap16 is store/wrap.a 540 | ['] 16>C! is >C 541 | ['] C>16 is C> 542 | ['] PC+2 is PC+a 543 | ['] check-nz.8 is check-nz.TOS 544 | ['] cmp16 is cmp.a 545 | ['] push16 is push.a 546 | ['] pull16 is pull.a 547 | ['] mask16 is mask.a 548 | ['] mask-n.16 is mask-n.a 549 | ['] mask-v.16 is mask-v.a 550 | ['] carry?.16 is carry? 551 | a16flag set ; 552 | 553 | : a:8 ( -- ) 554 | ['] fetch/wrap8 is fetch/wrap.a 555 | ['] fetchPC8 is fetchPC.a 556 | ['] store8 is store.a 557 | ['] store/wrap8 is store/wrap.a 558 | ['] 8>C! is >C 559 | ['] C>8 is C> 560 | ['] PC+1 is PC+a 561 | ['] check-nz.8 is check-nz.TOS 562 | ['] cmp8 is cmp.a 563 | ['] push8 is push.a 564 | ['] pull8 is pull.a 565 | ['] mask8 is mask.a 566 | ['] mask-n.8 is mask-n.a 567 | ['] mask-v.8 is mask-v.a 568 | ['] carry?.8 is carry? 569 | a16flag clear ; 570 | 571 | \ Switch X and Y 8<->16 bit (p. 51 in Manual) 572 | : xy:16 ( -- ) 573 | ['] fetch/wrap16 is fetch/wrap.xy 574 | ['] fetchPC16 is fetchPC.xy 575 | ['] store16 is store.xy 576 | ['] store/wrap16 is store/wrap.xy 577 | ['] mask16 is mask.xy 578 | ['] mask-n.16 is mask-n.xy 579 | ['] PC+2 is PC+xy 580 | ['] cmp16 is cmp.xy 581 | ['] push16 is push.xy 582 | ['] pull16 is pull.xy 583 | X @ 0FFFF AND X ! Y @ 0FFFF AND Y ! \ paranoid 584 | xy16flag set ; 585 | 586 | : xy:8 ( -- ) 587 | ['] fetch/wrap8 is fetch/wrap.xy 588 | ['] fetchPC8 is fetchPC.xy 589 | ['] store8 is store.xy 590 | ['] store/wrap8 is store/wrap.xy 591 | ['] mask8 is mask.xy 592 | ['] mask-n.8 is mask-n.xy 593 | ['] PC+1 is PC+xy 594 | ['] cmp8 is cmp.xy 595 | ['] push8 is push.xy 596 | ['] pull8 is pull.xy 597 | X @ 00FF AND X ! Y @ 00FF AND Y ! 598 | xy16flag clear ; 599 | 600 | 601 | \ --- STATUS BYTE --- 602 | \ These routines must come after mode switches for the registers 603 | 604 | \ In native mode, changing m and x flags might change the size of these 605 | \ registers 606 | : flag-modeswitch ( -- ) 607 | e-flag set? if unused-flag clear else 608 | m-flag set? if a:8 else a:16 then 609 | x-flag set? if xy:8 else xy:16 then 610 | then ; 611 | 612 | : >P ( u8 -- ) 613 | 0 7 ?do 614 | dup 1 and \ get lowest bit 615 | 0= if false else true then \ convert to Forth flag 616 | flags i cells + ! \ store in flag array 617 | 1 rshift 618 | -1 +loop 619 | 620 | flag-modeswitch ; 621 | 622 | \ Return from interrupt. This needs to come after the status byte routines but 623 | \ before the switch of the processor modes 624 | defer rti.a 625 | : rti-core ( -- ) pull8 >P pull16 PC ! ; 626 | : rti.e ( -- ) rti-core ; 627 | : rti.n ( -- ) rti-core pull8 PBR ! ; 628 | 629 | \ SEP, REP. These need to come after the status byte routines but before the 630 | \ switch of the processor modes 631 | defer sep.a 632 | : sep.n ( n8 -- ) P> fetchPC8 or >P ; 633 | : sep.e ( n8 -- ) fetchPC8 0cf and P> or >P ; \ Mask with 11001111 634 | 635 | defer rep.a 636 | : rep.n ( n8 -- ) fetchPC8 invert P> and >P ; 637 | : rep.e ( n8 -- ) fetchPC8 0cf and invert P> and >P ; \ Mask with 11001111 638 | 639 | \ switch processor modes (native/emulated). See p. 45 and 61 640 | : native ( -- ) 641 | e-flag clear 642 | m-flag set 643 | x-flag set 644 | ['] S++.n is S++ 645 | ['] S--.n is S-- 646 | ['] brk.n is brk.a 647 | ['] cop.n is cop.a 648 | ['] rti.n is rti.a 649 | ['] rep.n is rep.a 650 | ['] sep.n is sep.a 651 | ['] abort-v.n is abort-v 652 | ['] cop-v.n is cop-v 653 | ['] irq-v.n is irq-v 654 | ['] nmi-v.n is nmi-v 655 | ['] brk-v.n is brk-v ; 656 | 657 | : emulated ( -- ) \ p. 45 658 | \ TODO What happens with status bit 5 ? 659 | \ PBR and DBR switch unchanged 660 | e-flag set 661 | b-flag clear \ TODO Make sure this is really what happens 662 | unused-flag clear \ Make sure unused status bit 5 is not set 663 | a:8 xy:8 664 | S @ 00FF AND 0100 OR S ! \ stack pointer to 0100 665 | 0000 D ! \ direct page register initialized to zero 666 | ['] S++.e is S++ 667 | ['] S--.e is S-- 668 | ['] brk.e is brk.a 669 | ['] cop.e is cop.a 670 | ['] rti.e is rti.a 671 | ['] rep.e is rep.a 672 | ['] sep.e is sep.a 673 | ['] abort-v.e is abort-v 674 | ['] cop-v.e is cop-v 675 | ['] irq-v.e is irq-v 676 | ['] nmi-v.e is nmi-v 677 | ['] brk-v.e is brk-v ; 678 | 679 | 680 | \ ---- ADDRESSING MODES --- 681 | cr .( Defining addressing modes ...) 682 | 683 | \ Mode words leave the correct address as TOS before the PC. Note that the 684 | \ mnemonics for Absolute Mode have no suffix, but we use MODE.ABS for clarity. 685 | \ Not all modes are listed here, because some are easier to code by hand. Nodes 686 | \ advance the PC so we don't have to include that in the operand code; since the 687 | \ PC is usually TOS, this requires some stack manipulation. Register 688 | \ manipulation should come before the mode word (eg "Y @ MODE.ABS.DBR"), not 689 | \ behind it. 690 | 691 | \ Examples for the modes are given for the traditional syntax and for Typist's 692 | \ Assembler 693 | 694 | \ Absolute: "LDA $1000" / "lda 1000" # 695 | \ We need two different versions, one for instructions that affect data and take 696 | \ the DBR, and one for instructions that affect programs and take the PBR 697 | : mode.abs.DBR ( -- 65addr24 ) fetchPC16 mem16/DBR>24 ; 698 | : mode.abs.PBR ( -- 65addr24 ) fetchPC16 mem16/PBR>24 ; 699 | 700 | \ Absolute Indirect: "JMP ($1000)" / "jmp.i 1000" 701 | : mode.i ( -- 65addr24) 702 | fetchPC16 00 mem16/bank>24 fetch/wrap16 mem16/PBR>24 ; 703 | 704 | \ Absolute Indirect LONG: "JMP [$1000]" / "jmp.il 1000" 705 | : mode.il ( -- 65addr24) fetchPC16 00 mem16/bank>24 fetch/wrap24 ; 706 | 707 | \ Absolute Indexed X/Y (pp. 289-290): "LDA $1000,X" / "lda.x 1000" 708 | \ Assumes that X will be the correct width (8 or 16 bit) 709 | \ These DO NOT wrap to bank, so do not mask 710 | : mode.x ( -- 65addr24 ) mode.abs.DBR X @ + ; 711 | : mode.y ( -- 65addr24 ) mode.abs.DBR Y @ + ; 712 | 713 | \ Absolute X Indexed Indirect (p. 291): "JMP ($1000,X)" / "jmp.xi 1000" 714 | : mode.xi ( -- 65addr24 ) 715 | fetchPC16 X @ + mask16 PBR @ mem16/bank>24 716 | fetch/wrap16 ; 717 | 718 | \ Absolute Long: "LDA $100000" / "lda.l 100000" 719 | : mode.l ( -- 65addr24) fetchPC24 ; 720 | 721 | \ Absolute Long X Indexed: "LDA $100000,X" / "lda.lx 100000" 722 | \ assumes that X will be the correct width (8 or 16 bit) 723 | \ This DOES NOT wrap to bank 724 | : mode.lx ( -- 65addr24) mode.l X @ + ; 725 | 726 | \ Immediate Mode: "LDA #$10" / "lda.# 10" 727 | \ Note that this mode does not advance the PC as it is used with A and XY so we 728 | \ have to include a PC+a or PC+xy in the instructions themselves. Failure to do 729 | \ so was a common error during development 730 | : mode.imm ( -- 65addr24 ) PC24 ; 731 | 732 | 733 | \ -- DIRECT PAGE MODES -- 734 | 735 | \ DP modes are a serious pain because of emulation mode and the difference 736 | \ between page and bank wrapping. See 737 | \ http://forum.6502.org/viewtopic.php?f=8&t=3459&start=30#p40855 . 738 | 739 | \ TODO consider using a DEFER statement instead to distinguish between emulated 740 | \ and native modes for speed, keeping the tests in emulated mode only; compare 741 | \ code for stack handling 742 | 743 | \ We only wrap to the current page if all following three conditions are true: 744 | \ We are in emulation mode, the LSB of D is zero (that is, D is on a page 745 | \ boundry), and we are dealing with an old opcode that was available on the 746 | \ 65c02. TEST 1 is already defined via e-flag 747 | : on-page-boundry? ( 65addr -- f ) mask8 0= ; \ TEST 2 748 | 749 | \ The new DP opcodes with indexing which are never ever wrapped to the page 750 | \ all have the LSB of 7, that is, 07, 17, etc in HEX. This means we don't have 751 | \ to check them in a table, but can use a function. Life is good. 752 | : old-dp-opcode? ( -- f ) 753 | current-opcode @ 0F and 7 = invert ; \ TEST 3 754 | 755 | \ We do the e-flag test first because we assume that most people are going to 756 | \ run the MPU in native mode and we get to quit earlier then 757 | : wrap2page? ( -- f ) 758 | e-flag set? D @ on-page-boundry? and old-dp-opcode? and ; 759 | 760 | \ Given the result of adding D with the byte from the operand as well as the 761 | \ X or Y index, wrap correctly to page if necessary 762 | : add&wrap ( u16 u8|u16 -- u16 ) 763 | wrap2page? 764 | if over + mask8 \ discard MSB of addition, keeping LSB 765 | swap 0ff00 and \ keep MSB of D, thereby wrapping 766 | or else \ put LSB and MSB back together 767 | + then ; \ no page wrap, so just add; caller will wrap to bank 768 | 769 | \ If this wraps the page, it means by definition that the LSB of D was not zero, 770 | \ and so the legacy rules don't apply one way or another, so we don't need to do 771 | \ any fancy testing. MASK16 is paranoid 772 | : mode.d-core ( -- 65addr16 ) fetchPC8 D @ + mask16 ; 773 | 774 | \ Direct Page (DP) (pp. 94, 155, 278): "LDA $10" / "lda.d 10" 775 | \ Note that D can be relocated in emulated mode as well, see 776 | \ http://forum.6502.org/viewtopic.php?f=8&t=3459&p=40389#p40370 777 | : mode.d ( -- 65addr24) mode.d-core mem16/bank00>24 ; 778 | 779 | \ DP Indexed X/Y (p. 299): "LDA $10,X" / "lda.dx 10" 780 | : mode.dx ( -- 65addr24) mode.d-core X @ add&wrap mem16/bank00>24 ; 781 | : mode.dy ( -- 65addr24) mode.d-core Y @ add&wrap mem16/bank00>24 ; 782 | 783 | \ DP Indirect (p. 302): "LDA ($10)" / "lda.di 10" 784 | \ Note this uses the Data Bank Register DBR, not PBR 785 | : mode.di ( -- 65addr24) 786 | mode.d-core mem16/bank00>24 fetch/wrap16 DBR @ mem16/bank>24 ; 787 | 788 | \ DP Indirect X Indexed (p. 300): "LDA ($10,X)" / "lda.dxi 10" 789 | : mode.dxi ( -- 65addr24) 790 | mode.dx fetch/wrap16 DBR @ mem16/bank>24 ; 791 | 792 | \ DP Indirect Y Indexed (p. 304): "LDA ($10),Y" / "lda.diy 10" 793 | \ Does not need a "PC+1" because this is contained in MODE.DI 794 | \ HIER TESTING 795 | : mode.diy ( -- 65addr24) mode.di Y @ + ; 796 | 797 | \ DP Indirect Long: "LDA [$10]" / "lda.dil 10" 798 | : mode.dil ( -- 65addr24) mode.d-core mem16/bank00>24 fetch/wrap24 ; 799 | \ 800 | \ DP Indirect Long Y Addressing : "LDA [$10],y" / "lda.dily 10" 801 | : mode.dily ( -- 65addr24) mode.dil Y @ + ; 802 | 803 | 804 | \ -- STACK MODES -- 805 | 806 | \ Stack Relative (p. 324): "LDA $10,S" / "lda.s 10" 807 | : mode.s ( -- 65addr24 ) fetchPC8 S @ + mem16/bank00>24 ; 808 | 809 | \ Stack Relative Y Indexed: "LDA (10,S),Y" / "lda.siy 10" 810 | \ No "PC+1" because this is handled by MODE.S 811 | : mode.siy ( -- 65addr24 ) mode.s Y @ + DBR @ mem16/bank>24 ; 812 | 813 | 814 | \ ---- OUTPUT FUNCTIONS ---- 815 | cr .( Creating output functions ...) 816 | 817 | \ Print state of machine 818 | : .state ( -- ) 819 | 820 | \ Print status line 821 | cr ." PC K " 822 | 823 | a16flag clear? e-flag set? or if 824 | ." B A " else ." C " then 825 | 826 | xy16flag clear? e-flag set? or if 827 | ." X Y " else ." X Y " then 828 | 829 | e-flag set? if 830 | ." S D B NV-BDIZC" else 831 | ." S D B NVMXDIZC" then cr 832 | 833 | \ Print PC and Program Bank Register 834 | PC @ .word PBR @ .byte 835 | 836 | \ print BA or C 837 | a16flag clear? e-flag set? or if 838 | B .byte A .byte else 839 | C @ .word then 840 | 841 | \ print X and Y 842 | Y @ X @ xy16flag clear? if .byte .byte else .word .word then 843 | 844 | \ print Stack Pointer, Direct Page Register, Status Register 845 | S @ .word D @ .word DBR @ .byte P> .8bits space 846 | e-flag set? if ." emulated" else ." native" then cr ; 847 | 848 | 849 | \ Dump memory with 65816 addresses. Note you can also use the DUMP built-in 850 | \ word from Forth with "<65ADDR> memory + DUMP" 851 | : 65dump ( 65addr24 u -- ) 852 | cr 8 spaces ." 0 1 2 3 4 5 6 7 8 9 A B C D E F" 853 | over + swap 854 | 855 | dup 10 mod 0<> if 856 | dup 0fffff0 and cr .longword space 857 | dup 0f and 3 * spaces then 858 | ?do 859 | i 10 mod 0= if cr i mask24 .longword space then 860 | i fetch8 .byte 861 | loop cr ; 862 | 863 | \ Print Direct Page contents. We use D as a base regardless of which mode we are 864 | \ in; see MODE.D for discussion of what happens with D in emulation mode. 865 | \ Assumes HEX. 866 | : .direct ( -- ) D @ 100 65dump ; 867 | 868 | \ Print stack if we are in emulated mode 869 | : stackempty? ( -- f ) S @ 01ff = ; 870 | : .stack ( -- ) 871 | cr e-flag clear? if 872 | ." Can't dump stack when in native mode" 873 | else 874 | stackempty? if 875 | ." Stack is empty (S is 01FF in emulated mode)" cr else 876 | 0200 S @ 1+ ?do i dup . space fetch8 .byte cr loop 877 | then then ; 878 | 879 | 880 | \ ---- BLOCK MOVE INSTRUCTIONS ---- 881 | 882 | \ It would be really, really nice if we could just use Forth's MOVE word for 883 | \ this. However, MVP and MVN both wrap at the block boundry, so that won't work, 884 | \ see http://6502.org/tutorials/65c816opcodes.html#5.19 . Because we assume 885 | \ MOVE is a lot faster than a loop, we use it for the cases where there is no 886 | \ wrapping, and fall back on slower loop constructs otherwise. Remember 887 | \ C is number of bytes to be moved minus one, and the first operand is the 888 | \ destinantion bank byte, not the source. The return values are faked. 889 | \ TODO Since we're only moving 64k max and this is a rare instruction, 890 | \ get rid of two-mode system and just do everything the slow way 891 | \ TODO Factor words once we know they are working 892 | 893 | : move-without-wrap? ( -- f ) 894 | X @ C @ + 0ffff <= 895 | Y @ C @ + 0ffff <= and ; 896 | 897 | \ This is the best case, because fastest 898 | : no-wrap-move ( dest src -- ) 899 | X @ swap mem16/bank>24 memory + \ full source address 900 | swap Y @ swap mem16/bank>24 memory + \ full destination address 901 | C @ 1+ move ; 902 | 903 | \ Move core routine, used by both MVN and MVP 904 | : move-core ( dbb sbb -- ) 905 | X @ i + mask16 ( dbb sbb s16 ) \ get source addres w/o bank byte 906 | over mem16/bank>24 ( dbb sbb src ) \ calculate new every time 907 | fetch8 rot ( sbb u8 dbb ) 908 | Y @ i + mask16 ( sbb u8 dbb d16 ) 909 | over mem16/bank>24 ( sbb u8 dbb dest ) 910 | swap -rot ( sbb dbb u8 dest ) 911 | store8 swap ; ( dbb sbb ) 912 | 913 | \ MVN starts with the first byte and works forward to avoid overwriting data 914 | : mvn-slow ( dbb sbb -- ) C> 1+ 0 ?do move-core loop ; 915 | 916 | \ MVP starts with the last byte and works backwards to avoid overwriting data 917 | : mvp-slow ( dbb sbb -- ) 0 C> 1+ ?do move-core -1 +loop ; 918 | 919 | : mvn-core ( -- ) 920 | fetchPC8 dup >r \ destination bank byte (!) 921 | fetchPC8 \ source bank byte 922 | move-without-wrap? if no-wrap-move else mvn-slow then 923 | 0ffff C ! 1 X +! 1 Y +! r> DBR ! ; \ we fake the loop results 924 | 925 | : mvp-core ( -- ) 926 | fetchPC8 dup >r \ destination bank byte (!) 927 | fetchPC8 \ source bank byte 928 | move-without-wrap? if no-wrap-move else mvp-slow then 929 | 0ffff C ! 1 X +! 1 Y +! r> DBR ! ; \ we fake the loop results 930 | 931 | 932 | \ ---- OPCODE CORE ROUTINES ---- 933 | cr .( Defining core routines for opcodes ) 934 | \ TODO Rewrite/optimize/refract these 935 | 936 | \ These all work in both 8- and 16-bit modes 937 | : and-core ( 65addr -- ) fetch/wrap.a mask.a C> and >C check-nz.a ; 938 | : eor-core ( 65addr -- ) fetch/wrap.a mask.a C> xor >C check-nz.a ; 939 | : ora-core ( 65addr -- ) fetch/wrap.a mask.a C> or >C check-nz.a ; 940 | 941 | \ ASL-CORE is used for all, ASL-MEM for memory shifts 942 | : asl-core ( u -- u ) dup mask-n.a test&set-c 1 lshift ; 943 | : asl-mem ( addr -- ) 944 | dup fetch/wrap.a asl-core dup check-nz.TOS swap store/wrap.a ; 945 | 946 | \ LSR-CORE is used for all, LSR-MEM for memory shifts 947 | : lsr-core ( u -- u ) dup mask-c test&set-c 1 rshift ; 948 | : lsr-mem ( addr -- ) 949 | dup fetch/wrap.a lsr-core dup check-nz.TOS swap store/wrap.a ; 950 | 951 | \ ROL-CORE is used for all, ROL-MEM for memory shifts 952 | : rol-core ( u -- u ) 953 | c-flag @ mask-c swap dup mask-n.a test&set-c 1 lshift or ; 954 | : rol-mem ( addr -- ) 955 | dup fetch/wrap.a rol-core dup check-nz.TOS swap store/wrap.a ; 956 | 957 | \ ROR-CORE is used for all, ROR-MEM for memory shifts 958 | : ror-core ( u -- u ) 959 | c-flag @ mask-n.a swap dup mask-c test&set-c 1 rshift or ; 960 | : ror-mem ( addr -- ) 961 | dup fetch/wrap.a ror-core dup check-nz.TOS swap store/wrap.a ; 962 | 963 | : bit-core ( 65addr -- ) fetch/wrap.a 964 | dup mask-n.a test&set-n dup mask-v.a test&set-v C> and test&set-z ; 965 | 966 | : trb-core ( 65addr -- ) 967 | dup fetch/wrap.a 968 | dup C> and test&set-z 969 | C> true mask.a xor and swap store/wrap.a ; 970 | 971 | : tsb-core ( 65addr -- ) 972 | dup fetch/wrap.a 973 | dup C> and test&set-z 974 | C> or swap store/wrap.a ; 975 | 976 | \ INC and DEC for the Accumulator 977 | : inc.accu ( -- ) C> 1+ mask.a >C check-nz.a ; 978 | : dec.accu ( -- ) C> 1- mask.a >C check-nz.a ; 979 | 980 | \ INC and DEC for memory 981 | : inc.mem ( 65addr -- ) 982 | dup fetch/wrap.a 1+ mask.a dup check-nz.TOS swap store/wrap.a ; 983 | : dec.mem ( 65addr -- ) 984 | dup fetch/wrap.a 1- mask.a dup check-nz.TOS swap store/wrap.a ; 985 | 986 | : cmp-core ( u 65addr -- ) fetch/wrap.a cmp.a ; 987 | : cpxy-core ( u 65addr -- ) fetch/wrap.xy cmp.xy ; 988 | 989 | : lda-core ( 65addr -- ) fetch/wrap.a >C check-nz.a ; 990 | : ldx-core ( 65addr -- ) fetch/wrap.xy X ! check-nz.x ; 991 | : ldy-core ( 65addr -- ) fetch/wrap.xy Y ! check-nz.y ; 992 | 993 | 994 | \ -- Addition routines -- 995 | 996 | \ Use this for both ADC and SBC 997 | : adc-sbc-core ( u -- ) 998 | dup >r \ save operand for Overflow calculation 999 | C> dup >r \ save accumulator for Overflow calculation 1000 | + c-flag @ mask-c + dup >C carry? test&set-c check-nz.a 1001 | r> C> or r> C> or and mask-n.a 0<> v-flag ! ; \ calculate Overflow 1002 | 1003 | \ Common routine for 8- and 16-bit binary addition 1004 | : adc-bin ( addr -- ) fetch/wrap.a adc-sbc-core ; 1005 | 1006 | \ Routines for 8- and 16-bit BCD addition 1007 | \ WARNING: The v-flag is currently not correctly emulated in decimal mode, see 1008 | \ http://www.6502.org/tutorials/vflag.html for details 1009 | \ TODO see if we can fold this into one routine to simplify table 1010 | : adc-bcd.8 ( addr -- ) fetch/wrap.a C> bcd-add-bytes >C ; 1011 | : adc-bcd.16 ( addr -- ) fetch/wrap.a C> bcd-add-words >C ; 1012 | 1013 | create additions 1014 | ' adc-bin , \ 8 bit binary: D clear, a16flag clear (00) 1015 | ' adc-bin , \ 16 bit binary: D clear, a16flag set (01) 1016 | ' adc-bcd.8 , \ 16 bit decimal: D set, a16flag clear (10) 1017 | ' adc-bcd.16 , \ 8 bit decimal: D set, a16flag set (11) 1018 | 1019 | : adc-core ( 65addr -- ) 1020 | d-flag @ 2 and a16flag @ mask-c or cells \ calculate table index 1021 | additions + @ execute ; 1022 | 1023 | 1024 | \ --- Subtraction Routines --- 1025 | 1026 | \ The 6502 and 65816 use the c-flag as an inverted borrow 1027 | : invert-borrow ( -- ) c-flag dup @ invert swap ! ; 1028 | 1029 | \ Common routine for 8- and 16-bit binary subtraction 1030 | : sbc-bin ( addr -- ) fetch/wrap.a invert adc-sbc-core invert-borrow ; 1031 | 1032 | \ Routines for 8- and 16-bit BCD subtraction 1033 | \ WARNING: The v-flag is currently not correctly emulated in decimal mode, see 1034 | \ http://www.6502.org/tutorials/vflag.html for details 1035 | \ Also see http://visual6502.org/wiki/index.php?title=6502DecimalMode 1036 | \ TODO see if we can fold this into one routine to simplify table 1037 | : sbc-bcd.8 ( addr -- ) fetch/wrap.a C> bcd-sub-bytes >C ; 1038 | : sbc-bcd.16 ( addr -- ) fetch/wrap.a C> bcd-sub-words >C ; 1039 | 1040 | create subtractions 1041 | ' sbc-bin , \ 8 bit binary: D clear, a16flag clear (00) 1042 | ' sbc-bin , \ 16 bit binary: D clear, a16flag set (01) 1043 | ' sbc-bcd.8 , \ 16 bit decimal: D set, a16flag clear (10) 1044 | ' sbc-bcd.16 , \ 8 bit decimal: D set, a16flag set (11) 1045 | 1046 | : sbc-core ( 65addr -- ) 1047 | d-flag @ 2 and a16flag @ mask-c or cells \ calculate table index 1048 | subtractions + @ execute ; 1049 | 1050 | 1051 | \ ---- OPCODE ROUTINES ---- 1052 | cr .( Defining opcode routines themselves ... ) 1053 | 1054 | \ We note "new" instructions (not available on the 65c02) for DP and S modes 1055 | \ here for reference, see modes 1056 | 1057 | : opc-00 ( brk ) brk.a ; 1058 | : opc-01 ( ora.dxi ) mode.dxi ora-core ; 1059 | : opc-02 ( cop ) cop.a ; 1060 | : opc-03 ( ora.s ) mode.s ora-core ; \ New S opcode 1061 | : opc-04 ( tsb.d ) mode.d tsb-core ; 1062 | : opc-05 ( ora.d ) mode.d ora-core ; 1063 | : opc-06 ( asl.d ) mode.d asl-mem ; 1064 | : opc-07 ( ora.dil ) mode.dil ora-core ; \ New DP opcode 1065 | : opc-08 ( php ) P> push8 ; 1066 | : opc-09 ( ora.# ) mode.imm ora-core PC+a ; 1067 | : opc-0A ( asl.a ) C> asl-core >C check-nz.a ; 1068 | : opc-0B ( phd ) D @ mask16 push16 ; 1069 | : opc-0C ( tsb ) mode.abs.DBR tsb-core ; 1070 | : opc-0D ( ora ) mode.abs.DBR ora-core ; 1071 | : opc-0E ( asl ) mode.abs.DBR asl-mem ; 1072 | : opc-0F ( ora.l ) mode.l ora-core ; 1073 | : opc-10 ( bpl ) n-flag clear? branch-if-true ; 1074 | : opc-11 ( ora.diy ) mode.diy ora-core ; 1075 | : opc-12 ( ora.di ) mode.di ora-core ; 1076 | : opc-13 ( ora.siy ) mode.siy ora-core ; \ New S opcode 1077 | : opc-14 ( trb.d ) mode.d trb-core ; 1078 | : opc-15 ( ora.dx ) mode.dx ora-core ; 1079 | : opc-16 ( asl.dx ) mode.dx asl-mem ; 1080 | : opc-17 ( ora.dily ) mode.dily ora-core ; \ New DP opcode 1081 | : opc-18 ( clc ) c-flag clear ; 1082 | : opc-19 ( ora.y ) mode.y ora-core ; 1083 | : opc-1A ( inc.a ) inc.accu ; 1084 | \ Does not affect flags; compare TXS. In emulation mode, hi byte is paranoided 1085 | \ to 01, native mode always copies full C to S 1086 | : opc-1B ( tcs ) e-flag set? if 0100 A or else C @ then S ! ; 1087 | : opc-1C ( trb ) mode.abs.DBR trb-core ; 1088 | : opc-1D ( ora.x ) mode.x ora-core ; 1089 | : opc-1E ( asl.x ) mode.x asl-mem ; 1090 | : opc-1F ( ora.lx ) mode.lx ora-core ; 1091 | \ STEP already increases the PC by one, so we only need to add one byte because 1092 | \ the address pushed is the last byte of the instruction 1093 | : opc-20 ( jsr ) PC @ 1+ push16 fetchPC16 PC ! ; 1094 | : opc-21 ( and.dxi ) mode.dxi and-core ; 1095 | : opc-22 ( jsr.l ) PC24 2 + push24 fetchPC24 24>PC24! ; 1096 | : opc-23 ( and.s ) mode.s and-core ; \ New S opcode 1097 | : opc-24 ( bit.d ) mode.d bit-core ; 1098 | : opc-25 ( and.d ) mode.d and-core ; 1099 | : opc-26 ( rol.d ) mode.d rol-mem ; 1100 | : opc-27 ( and.dil ) mode.dil and-core ; \ New DP opcode 1101 | : opc-28 ( plp ) pull8 >P ; 1102 | : opc-29 ( and.# ) mode.imm and-core PC+a ; 1103 | : opc-2A ( rol.a ) C> rol-core >C check-nz.a ; 1104 | : opc-2B ( pld ) pull16 dup test&set-z dup check-n16 D ! ; 1105 | : opc-2C ( bit ) mode.abs.DBR bit-core ; 1106 | : opc-2D ( and ) mode.abs.DBR and-core ; 1107 | : opc-2E ( rol ) mode.abs.DBR rol-mem ; 1108 | : opc-2F ( and.l ) mode.l and-core ; 1109 | : opc-30 ( bmi ) n-flag set? branch-if-true ; 1110 | : opc-31 ( and.diy ) mode.diy and-core ; 1111 | : opc-32 ( and.di ) mode.di and-core ; 1112 | : opc-33 ( and.siy ) mode.siy and-core ; \ New S opcode 1113 | : opc-34 ( bit.dx ) mode.dx bit-core ; 1114 | : opc-35 ( and.dx ) mode.dx and-core ; 1115 | : opc-36 ( rol.dx ) mode.dx rol-mem ; 1116 | : opc-37 ( and.dily ) mode.dily and-core ; \ New DP opcode 1117 | : opc-38 ( sec ) c-flag set ; 1118 | : opc-39 ( and.y ) mode.y and-core ; 1119 | : opc-3A ( dec.a ) dec.accu ; 1120 | : opc-3B ( tsc ) S @ mask16 check-nz.a ; 1121 | : opc-3C ( bit.x ) mode.x bit-core ; 1122 | : opc-3D ( and.x ) mode.x and-core ; 1123 | : opc-3E ( rol.x ) mode.x rol-mem ; 1124 | : opc-3F ( and.lx ) mode.lx and-core ; 1125 | : opc-40 ( rti ) rti.a ; 1126 | : opc-41 ( eor.dxi ) mode.dxi eor-core ; 1127 | : opc-42 ( wdm ) cr cr ." WARNING: WDM executed at " 1128 | PBR @ .byte PC @ .word PC+1 ; 1129 | : opc-43 ( eor.s ) mode.s eor-core ; \ New S opcode 1130 | : opc-44 ( mvp ) mvp-core ; 1131 | : opc-45 ( eor.d ) mode.d eor-core ; 1132 | : opc-46 ( lsr.d ) mode.d lsr-mem ; 1133 | : opc-47 ( eor.dil ) mode.dil eor-core ; \ New DP opcode 1134 | : opc-48 ( pha ) C> push.a ; 1135 | : opc-49 ( eor.# ) mode.imm eor-core PC+a ; 1136 | : opc-4A ( lsr.a ) C> lsr-core >C check-nz.a ; 1137 | : opc-4B ( phk ) PBR @ push8 ; 1138 | : opc-4C ( jmp ) fetchPC16 PC ! ; 1139 | : opc-4D ( eor ) mode.abs.DBR eor-core ; 1140 | : opc-4E ( lsr ) mode.abs.DBR lsr-mem ; 1141 | : opc-4F ( eor.l ) mode.l eor-core ; 1142 | : opc-50 ( bvc ) v-flag clear? branch-if-true ; 1143 | : opc-51 ( eor.diy ) mode.diy eor-core ; 1144 | : opc-52 ( eor.di ) mode.di eor-core ; 1145 | : opc-53 ( eor.siy ) mode.siy eor-core ; \ New S opcode 1146 | : opc-54 ( mvn ) mvn-core ; 1147 | : opc-55 ( eor.dx ) mode.dx eor-core ; 1148 | : opc-56 ( lsr.dx ) mode.dx lsr-mem ; 1149 | : opc-57 ( eor.dily ) mode.dily eor-core ; \ New DP opcode 1150 | : opc-58 ( cli ) i-flag clear ; 1151 | : opc-59 ( eor.y ) mode.y eor-core ; 1152 | : opc-5A ( phy ) Y @ push.xy ; 1153 | : opc-5B ( tcd ) C @ mask16 dup check-nz.a D ! ; 1154 | : opc-5C ( jmp.l ) fetchPC24 24>PC24! ; 1155 | : opc-5D ( eor.x ) mode.x eor-core ; 1156 | : opc-5E ( lsr.x ) mode.x lsr-mem ; 1157 | : opc-5F ( eor.lx ) mode.lx eor-core ; 1158 | : opc-60 ( rts ) pull16 1+ PC ! ; 1159 | : opc-61 ( adc.dxi ) mode.dxi adc-core ; 1160 | : opc-62 ( phe.r ) fetch/wrap16 PC @ + push16 PC+2 ; \ TODO test 1161 | : opc-63 ( adc.s ) mode.s adc-core ; \ New S opcode 1162 | : opc-64 ( stz.d ) 0 mode.d store/wrap.a ; 1163 | : opc-65 ( adc.d ) mode.d adc-core ; 1164 | : opc-66 ( ror.d ) mode.d ror-mem ; 1165 | : opc-67 ( adc.dil ) mode.dil adc-core ; \ New DP opcode 1166 | : opc-68 ( pla ) pull.a >C check-nz.a ; 1167 | : opc-69 ( adc.# ) mode.imm adc-core PC+a ; 1168 | : opc-6A ( ror.a ) C> ror-core >C check-nz.a ; 1169 | : opc-6B ( rts.l ) pull24 1+ 24>PC24! ; 1170 | : opc-6C ( jmp.i ) mode.i PC ! ; 1171 | : opc-6D ( adc ) mode.abs.DBR adc-core ; 1172 | : opc-6E ( ror ) mode.abs.DBR ror-mem ; 1173 | : opc-6F ( adc.l ) mode.l adc-core ; 1174 | : opc-70 ( bvs ) v-flag set? branch-if-true ; 1175 | : opc-71 ( adc.diy ) mode.diy adc-core ; 1176 | : opc-72 ( adc.di ) mode.di adc-core ; 1177 | : opc-73 ( adc.siy ) mode.siy adc-core ; \ New S opcode 1178 | : opc-74 ( stz.dx ) 0 mode.dx store/wrap.a ; 1179 | : opc-75 ( adc.dx) mode.dx adc-core ; 1180 | : opc-76 ( ror.dx ) mode.dx ror-mem ; 1181 | : opc-77 ( adc.dily ) mode.dily adc-core ; \ New DP opcode 1182 | : opc-78 ( sei ) i-flag set ; 1183 | : opc-79 ( adc.y ) mode.y adc-core ; 1184 | : opc-7A ( ply ) pull.xy Y ! check-nz.y ; 1185 | : opc-7B ( tdc ) D @ mask16 dup check-nz.a >C ; 1186 | : opc-7C ( jmp.xi ) mode.xi PC ! ; 1187 | : opc-7D ( adc.x ) mode.x adc-core ; 1188 | : opc-7E ( ror.x ) mode.x ror-mem ; 1189 | : opc-7F ( adc.lx ) mode.lx adc-core ; 1190 | : opc-80 ( bra ) takebranch ; 1191 | : opc-81 ( sta.dxi ) C> mode.dxi store/wrap.a ; 1192 | : opc-82 ( bra.l ) fetchPC16 signextend.l 2 + PC ! ; 1193 | : opc-83 ( sta.s ) C> mode.s store/wrap.a ; \ New S opcode 1194 | : opc-84 ( sty.d ) Y @ mode.d store/wrap.xy ; 1195 | : opc-85 ( sta.d ) C> mode.d store/wrap.a ; 1196 | : opc-86 ( stx.d ) X @ mode.d store/wrap.xy ; 1197 | : opc-87 ( sta.dil ) C> mode.dil store/wrap.a ; \ New DP opcode 1198 | : opc-88 ( dey ) Y @ 1- mask.xy Y ! check-nz.y ; 1199 | : opc-89 ( bit.# ) C> mode.imm fetch/wrap.a and test&set-z PC+a ; 1200 | : opc-8A ( txa ) X @ >C check-nz.a ; 1201 | : opc-8B ( phb ) DBR @ push8 ; 1202 | : opc-8C ( sty ) Y @ mode.abs.DBR store/wrap.xy ; 1203 | : opc-8D ( sta ) C> mode.abs.DBR store/wrap.a ; 1204 | : opc-8E ( stx ) X @ mode.abs.DBR store/wrap.xy ; 1205 | : opc-8F ( sta.l ) C> mode.l store/wrap.a ; 1206 | : opc-90 ( bcc ) c-flag clear? branch-if-true ; 1207 | : opc-91 ( sta.diy ) C> mode.diy store/wrap.a ; 1208 | : opc-92 ( sta.di ) C> mode.di store/wrap.a ; 1209 | : opc-93 ( sta.siy ) C> mode.siy store/wrap.a ; \ New S opcode 1210 | : opc-94 ( sty.dx ) Y @ mode.dx store/wrap.xy ; 1211 | : opc-95 ( sta.dx ) C> mode.dx store/wrap.a ; 1212 | : opc-96 ( stx.dy ) X @ mode.dy store/wrap.xy ; 1213 | : opc-97 ( sta.dily ) C> mode.dily store/wrap.a ; \ New DP opcode 1214 | : opc-98 ( tya ) Y @ >C check-nz.a ; 1215 | : opc-99 ( sta.y ) C> mode.y store/wrap.a ; 1216 | : opc-9A ( txs ) 1217 | X @ e-flag set? if \ emulation mode, hi byte paranoided to 01 1218 | mask8 0100 or else 1219 | x-flag set? if mask8 then \ native mode, 8 bit X; hi byte is 00 1220 | then S ! ; 1221 | : opc-9B ( txy ) X @ Y ! check-nz.y ; 1222 | : opc-9C ( stz ) 0 mode.abs.DBR store/wrap.a ; 1223 | : opc-9D ( sta.x ) C> mode.x store/wrap.a ; 1224 | : opc-9E ( stz.x ) 0 mode.x store/wrap.a ; 1225 | : opc-9F ( sta.lx ) C> mode.lx store/wrap.a ; 1226 | : opc-A0 ( ldy.# ) mode.imm ldy-core PC+xy ; 1227 | : opc-A1 ( lda.dxi ) mode.dxi lda-core ; 1228 | : opc-A2 ( ldx.# ) mode.imm ldx-core PC+xy ; 1229 | : opc-A3 ( lda.s ) mode.s lda-core ; \ New S opcode 1230 | : opc-A4 ( ldy.d ) mode.d ldy-core ; 1231 | : opc-A5 ( lda.d ) mode.d lda-core ; 1232 | : opc-A6 ( ldx.d ) mode.d ldx-core ; 1233 | : opc-A7 ( lda.dil ) mode.dil lda-core ; \ New DP opcode 1234 | : opc-A8 ( tay ) C @ mask.xy Y ! check-nz.y ; 1235 | : opc-A9 ( lda.# ) mode.imm lda-core PC+a ; 1236 | : opc-AA ( tax ) C @ mask.xy X ! check-nz.x ; 1237 | : opc-AB ( plb ) pull8 dup check-nz.8 DBR ! ; 1238 | : opc-AC ( ldy ) mode.abs.DBR ldy-core ; 1239 | : opc-AD ( lda ) mode.abs.DBR lda-core ; 1240 | : opc-AE ( ldx ) mode.abs.DBR ldx-core ; 1241 | : opc-AF ( lda.l ) mode.l lda-core ; 1242 | : opc-B0 ( bcs ) c-flag set? branch-if-true ; 1243 | : opc-B1 ( lda.diy ) mode.diy lda-core ; 1244 | : opc-B2 ( lda.di ) mode.di lda-core ; 1245 | : opc-B3 ( lda.siy ) mode.siy lda-core ; \ New S opcode 1246 | : opc-B4 ( ldy.dx ) mode.dx ldy-core ; 1247 | : opc-B5 ( lda.dx ) mode.dx lda-core ; 1248 | : opc-B6 ( ldx.dy ) mode.dy ldx-core ; 1249 | : opc-B7 ( lda.dily ) mode.dily lda-core ; \ New DP opcode 1250 | : opc-B8 ( clv ) v-flag clear ; 1251 | : opc-B9 ( lda.y ) mode.y lda-core ; 1252 | : opc-BA ( tsx ) S @ xy16flag clear? if mask8 then X ! check-nz.x ; 1253 | : opc-BB ( tyx ) Y @ X ! check-nz.x ; 1254 | : opc-BC ( ldy.x ) mode.x ldy-core ; 1255 | : opc-BD ( lda.x ) mode.x lda-core ; 1256 | : opc-BE ( ldx.y ) mode.y ldx-core ; 1257 | : opc-BF ( lda.lx ) mode.lx lda-core ; 1258 | : opc-C0 ( cpy.# ) Y @ mode.imm cpxy-core PC+xy ; 1259 | : opc-C1 ( cmp.dxi ) C> mode.dxi cmp-core ; 1260 | : opc-C2 ( rep ) rep.a ; 1261 | : opc-C3 ( cmp.s ) C> mode.s cmp-core ; \ New S opcode 1262 | : opc-C4 ( cpy.d ) Y @ mode.d cpxy-core ; 1263 | : opc-C5 ( cmp.d ) C> mode.d cmp-core ; 1264 | : opc-C6 ( dec.d ) mode.d dec.mem ; 1265 | : opc-C7 ( cmp.dil ) C> mode.dil cmp-core ; \ New DP opcode 1266 | : opc-C8 ( iny ) Y @ 1+ mask.xy Y ! check-nz.y ; 1267 | : opc-C9 ( cmp.# ) C> mode.imm cmp-core PC+a ; 1268 | : opc-CA ( dex ) X @ 1- mask.xy X ! check-nz.x ; 1269 | : opc-CB ( wai ) cr cr 1270 | ." *** WAI encountered at " PC24 .longword 1271 | ." Resume with STEP, RUN or interrupt ***" cr 1272 | .state quit ; 1273 | : opc-CC ( cpy ) Y @ mode.abs.DBR cpxy-core ; 1274 | : opc-CD ( cmp ) C> mode.abs.DBR cmp-core ; 1275 | : opc-CE ( dec ) mode.abs.DBR dec.mem ; 1276 | : opc-CF ( cmp.l ) C> mode.l cmp-core ; 1277 | : opc-D0 ( bne ) z-flag clear? branch-if-true ; 1278 | : opc-D1 ( cmp.diy ) C> mode.diy cmp-core ; 1279 | : opc-D2 ( cmp.di ) C> mode.di cmp-core ; 1280 | : opc-D3 ( cmp.siy ) C> mode.siy cmp-core ; \ New S opcode 1281 | : opc-D4 ( phe.d ) mode.d fetch16 push16 ; \ pp. 169, 373 1282 | : opc-D5 ( cmp.dx ) C> mode.dx cmp-core ; 1283 | : opc-D6 ( dec.dx ) mode.dx dec.mem ; 1284 | : opc-D7 ( cmp.dily ) C> mode.dily cmp-core ; \ New DP opcode 1285 | : opc-D8 ( cld ) d-flag clear ; 1286 | : opc-D9 ( cmp.y ) C> mode.y cmp-core ; 1287 | : opc-DA ( phx ) X @ push.xy ; 1288 | : opc-DB ( stp ) cr cr 1289 | ." *** STP encountered at " PC24 .longword 1290 | ." Resume with STEP or RUN ***" cr 1291 | .state quit ; 1292 | : opc-DC ( jmp.il ) mode.il 24>PC24! ; 1293 | : opc-DD ( cmp.x ) C> mode.x cmp-core ; 1294 | : opc-DE ( dec.x ) mode.x dec.mem ; 1295 | : opc-DF ( cmp.lx ) C> mode.lx cmp-core ; 1296 | : opc-E0 ( cpx.# ) X @ mode.imm cpxy-core PC+xy ; 1297 | : opc-E1 ( sbc.dxi ) mode.dxi sbc-core ; 1298 | : opc-E2 ( sep ) sep.a ; 1299 | : opc-E3 ( sbc.s ) mode.s sbc-core ; \ New S opcode 1300 | : opc-E4 ( cpx.d ) X @ mode.d cpxy-core ; 1301 | : opc-E5 ( sbc.d ) mode.d sbc-core ; 1302 | : opc-E6 ( inc.d ) mode.d inc.mem ; 1303 | : opc-E7 ( sbc.dil ) mode.dil sbc-core ; \ New DP opcode 1304 | : opc-E8 ( inx ) X @ 1+ mask.xy X ! check-nz.x ; 1305 | : opc-E9 ( sbc.# ) mode.imm sbc-core PC+a ; 1306 | : opc-EA ( nop ) ; 1307 | : opc-EB ( xba ) \ N and Z depend only on value in (new) A 1308 | C @ dup mask8 8 lshift swap 0ff00 and 8 rshift dup check-nz.8 or C ! ; 1309 | : opc-EC ( cpx ) X @ mode.abs.DBR cpxy-core ; 1310 | : opc-ED ( sbc ) mode.abs.DBR sbc-core ; 1311 | : opc-EE ( inc ) mode.abs.DBR inc.mem ; 1312 | : opc-EF ( sbc.l ) mode.l sbc-core ; 1313 | : opc-F0 ( beq ) z-flag set? branch-if-true ; 1314 | : opc-F1 ( sbc.diy ) mode.diy sbc-core ; 1315 | : opc-F2 ( sbc.di ) mode.di sbc-core ; 1316 | : opc-F3 ( sbc.siy ) mode.siy sbc-core ; \ New S opcode 1317 | : opc-F4 ( phe.# ) fetchPC16 push16 ; 1318 | : opc-F5 ( sbc.dx ) mode.dx sbc-core ; 1319 | : opc-F6 ( inc.dx ) mode.dx inc.mem ; 1320 | : opc-F7 ( sbc.dily ) mode.dily sbc-core ; \ New DP opcode 1321 | : opc-F8 ( sed ) d-flag set ; 1322 | : opc-F9 ( sbc.y ) mode.y sbc-core ; 1323 | : opc-FA ( plx ) pull.xy X ! check-nz.x ; 1324 | : opc-FB ( xce ) c-flag @ e-flag @ c-flag ! dup e-flag ! 1325 | if emulated else native then ; 1326 | : opc-FC ( jsr.xi ) PC @ 1+ push16 mode.xi PC ! ; 1327 | : opc-FD ( sbc.x ) mode.x sbc-core ; 1328 | : opc-FE ( inc.x ) mode.x inc.mem ; 1329 | : opc-FF ( sbc.lx ) mode.lx sbc-core ; 1330 | 1331 | 1332 | \ ---- GENERATE OPCODE JUMP TABLE ---- 1333 | \ Routine stores xt in table, offset is the opcode of the word in a cell. Use 1334 | \ "opc-jumptable cells + @ execute" to call the opcode's word. 1335 | \ Assumes HEX 1336 | cr .( Generating opcode jump table ... ) 1337 | 1338 | : make-opc-jumptable ( -- ) 1339 | 100 0 do 1340 | i s>d <# # # [char] - hold [char] c hold [char] p hold [char] o hold #> 1341 | find-name name>int , 1342 | loop ; 1343 | 1344 | create opc-jumptable make-opc-jumptable 1345 | 1346 | 1347 | \ ---- INTERRUPTS ---- 1348 | \ See http://sbc.bcstechnology.net/65c816interrupts.html for details 1349 | \ See page 192, also http://6502.org/tutorials/interrupts.html 1350 | \ Remember interrupt vectors are constants, not variables 1351 | cr .( Setting up interrupts ...) 1352 | 1353 | \ native mode pushes the PBR to the stack as well 1354 | : interrupt-core ( -- ) 1355 | e-flag clear? if PBR @ push8 then 1356 | PC @ push16 1357 | P> push8 1358 | i-flag set d-flag clear 1359 | 0 PBR ! ; 1360 | 1361 | \ ABORT on real hardware actually completes the instruction that is currently 1362 | \ being executed, without saving the results, and then reruns it after the 1363 | \ interrupt is completed. We currently complete the instruction instead. 1364 | : abort-i ( -- ) interrupt-core abort-v fetch16 PC ! ; 1365 | : irq-i ( -- ) i-flag clear? if interrupt-core irq-v fetch16 PC ! then ; 1366 | : nmi-i ( -- ) interrupt-core nmi-v fetch16 PC ! ; 1367 | 1368 | \ Reset doesn't automatically start running but puts the correct vector in PC 1369 | \ and then waits for the user to type either RUN or STEP 1370 | : reset-i ( -- ) \ p.201 and http://www.pagetable.com/?p=410 1371 | i-flag set d-flag clear \ c, n, v, and z flags are in undefined state 1372 | emulated \ sets e, m, x-flags; MSB of X and Y are set to zero 1373 | 00 PBR ! 00 DBR ! 0000 D ! 1374 | \ LSB of S is decreased by 3, see http://forum.6502.org/viewtopic.php?f=4&t=2258 1375 | S @ 3 - mask8 0100 or S ! \ only MSB is reset to 01 1376 | reset-v fetch16 PC ! ; 1377 | 1378 | : poweron ( -- ) 1379 | 0000 D ! \ intiate Direct Page to zero (p. 155) 1380 | \ S, A, X, and Y are not put in a defined state after power on (see 1381 | \ http://forum.6502.org/viewtopic.php?f=4&t=2258) We use a weird but famous 1382 | \ number for the initial value to make this clear 1383 | 2a2a C ! 2a X ! 2a Y ! 1384 | reset-i ; 1385 | 1386 | \ ---- MAIN CONTROL ---- 1387 | \ Single-step through the program, or run emulation. To start at a given 1388 | \ memory location, save the bank number to PBK and the address to PC, then 1389 | \ type 'run' or 'step' 1390 | 1391 | \ Increase PC before executing instruction so we are pointing at the 1392 | \ operand (if available). We save the current opcode for tricky things like 1393 | \ emulated DP mode wrapping 1394 | : step ( -- ) 1395 | fetchPC8 dup current-opcode ! cells opc-jumptable + @ execute ; 1396 | : walk ( -- ) begin step .state key drop again ; 1397 | : run ( -- ) begin step again ; 1398 | 1399 | \ ---- START EMULATION ---- 1400 | cr cr .( All done. Bringing up machine.) cr 1401 | 1402 | poweron 1403 | .state 1404 | 1405 | cr ." Machine ready." 1406 | cr ." Type 'run' to start emulation, 'walk' or 'state' for single-step." 1407 | 1408 | -------------------------------------------------------------------------------- /data.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scotws/crude65816/e11a3a3fc99d0be33485eef5aa91181a526d11cb/data.bin -------------------------------------------------------------------------------- /docs/CHANGELOG.txt: -------------------------------------------------------------------------------- 1 | Changelog for A Crude Emulator for the 65816 in Forth 2 | Scot W. Stevenson 3 | 4 | Add new entries to the top, major changes only 5 | 6 | 22. Dec 2016 - PRE-ALPHA of Mock Mensch Monitor ROM included 7 | 09. Oct 2015 - ALPHA uploaded to GitHub. 8 | 08. Oct 2015 - All opcodes coded. 9 | 26. May 2015 - PRE-ALPHA uploaded to GitHub. 10 | -------------------------------------------------------------------------------- /docs/MANUAL.md: -------------------------------------------------------------------------------- 1 | # Manual for A Crude 65816 Emulator 2 | Scot W. Stevenson 3 | First version: 09. Jan 2015 4 | This version: 25. Dec 2016 5 | 6 | > THIS DOCUMENT IS CURRENTLY MERELY A COLLECTION OF NOTES. WHEN IN 7 | > DOUBT, USE THE SOURCE CODE. 8 | 9 | This is an emulator for the 65816 MPU, the "big sibling" of the famous 8-bit 10 | 6502 and 65c02 processors. It was created so I could more easily write 11 | a version of Forth for this processor after being frustrated by the limitations 12 | of the smaller processor while creating [Tali Forth for the 65c02](http://forum.6502.org/viewtopic.php?f=9&t=2926). 13 | 14 | Because of this, the emulator in Forth itself was the logical decision. It is 15 | written in Gforth, the [GNU version of 16 | Forth](https://www.gnu.org/software/gforth/). But fear not -- it is perfectly 17 | usable even if you have never seen a line of Forth in your life. It does, 18 | however, offer various tricks for Forthwrights. 19 | 20 | This manual provides a general introduction and guide to the emulator. The 21 | source code is heavily commented and should be consulted for details. Please 22 | note that at this moment, the emulator's status is ALPHA, defined as 23 | "everything does something, sometimes even the right thing". There has not been 24 | extensive testing of any part of the program yet. 25 | 26 | 27 | ## What It Does 28 | 29 | The Crude Emulator provides an environment to test 65816 binary programs. 30 | Because of the 8/16-bit hybrid nature of the MPU, it also functions as a 6502 31 | and 65c02 emulator when the processor is in Emulator Mode. The program allows 32 | defining various files as ROM areas via the main CONFIG.FS file. The emulator 33 | makes an spirited attempt to handle the correct wrapping of instructions at 34 | page and bank boundries. There is a primitive provision for interrupt testing. 35 | 36 | The emulator offers a _very_ crude emulation of some of the core utility 37 | routines present in the Mensch Monitor ROM shipped by WDC in the 38 | [W65C265SXB](http://wdc65xx.com/134_265_SXB-engineering-development-system/gettingstarted/). 39 | By very crude we mean that it doesn't really work yet for anything that is not 40 | PUT_CHR. 41 | 42 | 43 | ## What It Doesn't Do 44 | 45 | The emulator does not track the system clock and in fact has no concept of time 46 | at all. Things are done when they are done. Currently, there is no emulation of 47 | support chips such as the VIA 6522. Instead, there are "special addresses" that 48 | can be defined in the configuration file. 49 | 50 | There are a host of known issues where the emulator does not behave like the 51 | real silicon, mostly related to BCD addition and subtraction. See the bottom of 52 | this document for details. 53 | 54 | 55 | ## Starting the Emulator 56 | 57 | By default, Gforth reserves measly 256k for the dictionary, which is not enough 58 | when you are going to simulate a 16M large memory space. We need to call Gforth 59 | with at least 60 | 61 | ```gforth -m 18M``` 62 | 63 | Then, from Forth, include the main emulator file with 64 | 65 | ```include crude65816.fs``` 66 | 67 | You can also start the emulator directly from the command line with 68 | 69 | ```gforth -m 18M crude65816.fs``` 70 | 71 | You might want to put this in a shell script. 72 | 73 | The central configuration file is CONFIG.FS in the main folder. Its main 74 | function is to allow the user to load various binary files to simulate ROMs 75 | that are loaded at boot. There are various examples included. Note some of them 76 | might be for internal testing. 77 | 78 | 79 | ## Importing ROM from Files 80 | 81 | The Crude Emulator has a very, well, crude memory model: It simply reserves 16 82 | MByte of RAM as the complete memory range of the 65816. During boot, the 83 | emulator loads the contents of the files given in config.fs to the memory 84 | locations in the lines designated with LOADROM. This lets you simulate ROM 85 | data. Note, however, there is no write protection for ROM; the emulator will 86 | happily let you change any of these values. 87 | 88 | The current ROM file is a primitive test program. 89 | 90 | 91 | ## Using the Emulator 92 | 93 | In case you are new to Forth, know this: it is not a programming language, but 94 | a system to create specialized languages. As such, with the Crude Emulator you 95 | have access to all Forth commands such as DUMP, and in single-step mode can 96 | assign values to, say, the 65816 registers. 97 | 98 | The Crude Emulator current supports the following addition commands. Note that 99 | by Forth convention, a command that starts with a dot (for instance `.state`) 100 | prints some information to the screen. 101 | 102 | .direct - print the Direct Page based on D register 103 | .stack - print the 65816 stack if in emulated mode 104 | .state - print the CPU state (register content, etc) 105 | 65dump - dump memory range based on 65816 addresses 106 | abort-i - trigger the ABORT interrupt 107 | bye - end emulation (normal Forth command) 108 | fetch8 - fetch a byte from 24-bit address on Forth stack 109 | fetch16 - fetch a double byte from 24-bit address on Forth stack 110 | fetch24 - fetch three bytes from 24-bit address on Forth stack 111 | emulate - switch the CPU to emulated (8-bit) mode 112 | irq-i - trigger the IRQ interrupt 113 | native - switch the CPU to native (16-bit) mode 114 | nmi-i - tritter the NMI interrupt 115 | reset-i - trigger the RESET interrupt 116 | run - run the emulator continuously 117 | step - run one instruction in single-step mode 118 | walk - "step .state", press key to continue, CNTRL-C to quit 119 | 120 | Because of the nature of Forth, any word defined in the emulator can be used 121 | from the command line. To force the machine to run at a certain address, save it 122 | in the PC: 123 | 124 | ``` 125 | 00e000 PC ! 126 | ``` 127 | 128 | followed by a "run", "step" or "walk". The same procedure will let you store 129 | a value in, say, the A register: 130 | 131 | ``` 132 | 61 C ! 133 | ``` 134 | 135 | (note that the name is not "A") or X, Y, D, S, DBR, and PBR. To change the register sizes, use words 136 | ``` 137 | a:8 138 | a:16 139 | xy:8 140 | xy:16 141 | ``` 142 | from the command line. 143 | 144 | > For instance, to test the PUT_CHR routine of the Mock Mensch Monitor (MMM) ROM 145 | > included in the emulator, follow these steps (assuming that MMM was loaded 146 | > through config.fs): 147 | 148 | ``` 149 | native \ switches 65816 to native mode 150 | a:8 \ make A register 8 bit 151 | 61 C ! \ save ASCII value for "a" in A register 152 | 0e04b PC ! \ move to start of emulated PUT_CHR routine 153 | step .state \ walk through the routine 154 | ``` 155 | 156 | > At some point, a small "a" should appear. 157 | 158 | Interrupts can be triggered by hand as well: 159 | ``` 160 | reset-i 161 | ``` 162 | To use RUN and STEP during testing, use the WAI instruction in the 65816 code 163 | to pause execution, and STP to stop the system. 164 | 165 | 166 | ## Other Useful Combinations 167 | 168 | To walk through the program, use "walk" or 169 | ``` 170 | step .state 171 | ``` 172 | To walk through the program while showing the stack with every step (emulation mode only) 173 | ``` 174 | step .state .stack 175 | ``` 176 | To monitor a memory address every step, we can use the FETCH instructions. To 177 | watch what happens to $000000, for instance: 178 | ``` 179 | step .state ." DP 00:" 0000 fetch16 . 180 | ``` 181 | Note FETCH does not wrap at the bank boundry, use FETCH/WRAP for this. 182 | 183 | 184 | ## Halting the Emulation 185 | 186 | In many 6502 emulators, the BRK instruction is used to give control back to the 187 | emulator. We use the 65816's STP instruction, which halts the processor. After 188 | STP, you can resume the emulation with either STEP or RUN from the same spot. 189 | 190 | 191 | 192 | ## Emulating Interrupts 193 | 194 | To test interrupts, place a WAI instruction in the code at the place where you 195 | want the interrupt to trigger. Run the code until then. When the emulation 196 | stops, type the instruction for the interrupt (for instance irq-i), and then 197 | continue the run. 198 | 199 | Put differently, the emulator is too crude to allow interrupts during the 200 | execution of one word. Because of this, questions such if MVN and MVP are 201 | interruptable is not relevant. 202 | 203 | Note that after an interrupt, the emulator halts to let the user check things. 204 | It must be restared with RUN or STEP. 205 | 206 | 207 | ## Internal Syntax 208 | 209 | Internally, the Crude Emulator internally uses an assembler syntax called 210 | [Typist's Assembler Notation](https://github.com/scotws/tasm65816). TAN 211 | takes care of various problems with the "classical" syntax, especially with the 212 | 65816, is faster to type (hence the name), and comes in variants for "normal" 213 | postfix assemblers and those such as Forth with a prefix notation. Briefly, the 214 | modes are: 215 | ``` 216 | MODE WDC SYNTAX TYPIST'S SYNTAX 217 | 218 | implied dex dex 219 | accumulator inc inc.a 220 | immediate lda #$00 00 lda.# 221 | absolute lda $1000 1000 lda 222 | absolute x indexed lda $1000,x 1000 lda.x 223 | absolute y indexed lda $1000,y 1000 lda.y 224 | absolute indirect jmp ($1000) 1000 jmp.i 225 | indexed indirect jmp ($1000,x) 1000 jmp.xi 226 | absolute long jmp $101000 101000 jmp.l (65816) 227 | absolute long x indexed jmp $101000,x 101000 jmp.lx (65816) 228 | absolute indirect long jmp [$1000] 1000 jmp.il (65816) 229 | direct page lda $10 10 lda.d 230 | direct page x indexed lda $10,x 10 lda.dx 231 | direct page y indexed lda $10,y 10 lda.dy 232 | direct page indirect lda ($10) 10 lda.di 233 | dp indirect x indexed lda ($10,x) 10 lda.dxi 234 | dp indirect long lda [$10] 10 lda.dil (65816) 235 | dp indirect y indexed lda ($10),y 10 lda.diy 236 | dp indirect long y index lda [$10],y 10 lda.dily (65816) 237 | relative bne $2f00 2f00 bne 238 | relative long brl $20f000 20f000 brl (65816) 239 | stack relative lda 3,S 3 lda.s (65816) 240 | stack rel ind y indexed lda (3,S),y 3 lda.siy (65816) 241 | block move mvp 0,0 0 0 mvp (65816) 242 | ``` 243 | However, you do not need to know TAN (or any other notation, for that matter) 244 | to use the emulator. Where it is most important, both variants are given in the 245 | source code. 246 | 247 | 248 | 249 | ## For Forthwrights: Code Details 250 | 251 | The Crude Emulator puts all registers in variables. Experiments during 252 | development with either A/C or PC as TOS made working with the emulator too 253 | complicated. Instead, the Forth Data Stack must be empty after every RUN or 254 | STEP command. 255 | 256 | Because of the complicated wrapping rules for the 65816, in this stage of 257 | development various routines have extra "masking" instructions (for instance, 258 | MASK16) that are probably not necessary. These are marked with "paranoid" in 259 | the source code. 260 | 261 | 262 | ## Known Issues 263 | 264 | The Overflow Flag (v) is not correctly set in Decimal mode. See 265 | http://www.6502.org/tutorials/vflag.html and 266 | http://www.righto.com/2012/12/the-6502-overflow-flag-explained.html for 267 | details. This bug has low priority. 268 | 269 | The N and Z flag do not behave as required during subtraction in decimal 270 | mode. See source text for details. This bug will be corrected during ALPHA. 271 | 272 | The ABORT interrupt does not complete the instruction, throwing away the 273 | results, and then rerunning it, but instead is run after an instruction. This 274 | bug has low priority. 275 | 276 | 277 | ## Other Notes 278 | 279 | Though the documentation is unclear on this subject, tests have shown that you 280 | can relocate the Direct Page in Emulation Mode, see 281 | http://forum.6502.org/viewtopic.php?f=8&t=3459&p=40389#p40370 282 | 283 | 284 | ## Literature 285 | 286 | List of paper and online literature used, with date of last access where appropriate. 287 | 288 | ### Books 289 | 290 | "Forth Programmer's Handbook", 3rd edition. Conklin and Rather (2007) 291 | 292 | ### Special topics 293 | 294 | Interrupt system: http://sbc.bcstechnology.net/65c816interrupts.html 295 | Wrapping on banks and pages: http://forum.6502.org/viewtopic.php?f=8&t=3459&start=30#p40855 296 | 297 | -------------------------------------------------------------------------------- /docs/TODO.txt: -------------------------------------------------------------------------------- 1 | TODO for A Crude 65816 Emulator 2 | Scot W. Stevenson 3 | First version: 27. May 2015 4 | This version: 24. Dec 2016 5 | 6 | 7 | IMMEDIATELY 8 | 9 | - Add Mock Routines for the Mensch Monitor on the W65C265SXB 10 | - Begin extensive testing 11 | - Test individual themes 12 | - Create testing suite for native mode 13 | - Rewrite rom65816.tasm for new system 14 | 15 | 16 | SHORT TERM 17 | 18 | - Avoid all optimization before we know if we're going to have to rewrite 19 | 20 | LONG TERM 21 | 22 | - Consider rewriting Direct Page Modes with a DEFER construct so native mode avoids all the tests; compare stack code 23 | - Add FREEZE/THAW commands to save state of emulator 24 | 25 | 26 | NICE TO HAVE 27 | 28 | - Add color output to .STATE, .DIRECT, and .STACK on terminals that support it 29 | - Test to see if Forth's MOVE word is really that much faster than a ?DO loop for the MVP and MVN instructions 30 | 31 | 32 | QUESTIONS 33 | 34 | - How is the b-flag cleared after BRK in emulation mode? 35 | - In emulated mode, can REP, PLP, and SEP change the B flag and the unused flag (bit 5) of the status byte (P)? 36 | - If B is clear in emulation mode and we push P to the stack, and then switch to native mode, and then pull P again, will this set XY to 16 bit width (both are bit 3 in the status byte) ? 37 | - If in native mode the m-flag is set, and we go emulated, will unused bit 5 be set as well? 38 | 39 | 40 | 41 | END 42 | -------------------------------------------------------------------------------- /io.fs: -------------------------------------------------------------------------------- 1 | \ I/O stuff for A Crude Emulator for the 65816 2 | \ Scot W. Stevenson 3 | \ First version: 30. Jul 2015 4 | \ This version: 15. Sep 2015 5 | 6 | \ crude65816.fs must load this file after config.fs where putchr and getchr are 7 | \ defined 8 | 9 | \ Some day, this might emulate chips such as the 6522 or the 6551. Right now, 10 | \ it just provides putchr and getchr functionality with the addresses provided 11 | \ in config.fs 12 | : printchar ( n -- ) emit ; 13 | : readchar ( -- n ) key ; 14 | 15 | 16 | \ Handle all special addresses. There is no real reason to create two separate 17 | \ tables except that it cuts down on the number of loopings that store and read 18 | \ instructions have to go through. 19 | create store-addrs 20 | here 0 , 21 | \ ### add new routines here ### 22 | putchr , ' printchar , 23 | here swap ! \ save address of last entry in table in its first entry 24 | 25 | \ The equivalent for special read addresses 26 | create fetch-addrs 27 | here 0 , 28 | \ ### add new routines here ### 29 | getchr , ' readchar , 30 | here swap ! \ save address of last entry in table in its first entry 31 | 32 | 33 | \ Common routine for special i/o access. Takes the 65816 address in question and 34 | \ the address of the table, either STORE-ADDRS or READ-ADDRS. Because Forth 35 | \ doesn't have a BREAK statement for indefinite loops, we count the number of 36 | \ elements and put the count in the first address of the array. See 37 | \ http://forum.6502.org/viewtopic.php?f=9&t=3391 for a discussion of this code. 38 | \ Note this routine does not consume the address provided 39 | : special-io? ( 65addr table -- 65addr 0|xt) 40 | false swap ( 65addr 0 table ) \ default return value 41 | dup @ ( 65addr 0 addr-s addr-e ) \ start and end of table 42 | swap cell+ ( 65addr 0 addr-e addr-s+cell) 43 | ?do ( 65addr 0 ) 44 | over i @ ( 65addr 0 65addr 65addr ) 45 | = if drop i cell+ @ leave then 46 | [ cell 2* ] literal +loop ; 47 | 48 | : special-store? ( 65addr - 65addr 0|xt) store-addrs special-io? ; 49 | : special-fetch? ( 65addr - 65addr 0|xt) fetch-addrs special-io? ; 50 | 51 | -------------------------------------------------------------------------------- /roms/mmm/README.md: -------------------------------------------------------------------------------- 1 | # The Mock Mensch Monitor ROM file 2 | 3 | Scot W. Stevenson 4 | 5 | This is a ROM file for the [Crude 65816 6 | emulator](https://github.com/scotws/crude65816) that emulates certain utility 7 | routines of the W65C265SXB' Mensch Monitor from WDC to make development with 8 | that single board computer easier. It does _not_ function as a monitor itself. 9 | 10 | **NOTE THIS IS ALPHA STAGE SOFTWARE.** 11 | 12 | ## Utility routines currently emulated 13 | 14 | All these routines must be called with a Subroutine Long Jump (JSL / jsr.l) 15 | instruction. 16 | 17 | | Name | Location | Function | 18 | | :--- | :------: | :------- | 19 | | GET_CHR | 00:E036 | Read one character from input, no echo | 20 | | PUT_CHR | 00:E042 | Print a single character | 21 | | PUT_STR | 00:E04E | Print a string | 22 | | SEND_CR | 00:E066 | Print a Carriage Return | 23 | 24 | ## Testing 25 | 26 | This file includes a test suite. To test, make sure the correct files are 27 | uncommented in config.fs. Then, start Gforth: 28 | 29 | ``` 30 | gforth -m 18M 31 | ``` 32 | 33 | and then load the emulator with 34 | 35 | ``` 36 | include crude65816.fs 37 | ``` 38 | 39 | The Mock Mensch Monitor routines start at 00:e000, while the test suite starts 40 | at 00:8000. Therefore, we run the test with: 41 | 42 | ``` 43 | 8000 PC ! 44 | run 45 | ``` 46 | See the source code for details. 47 | 48 | # Chances related to the Mensch Monitor code 49 | 50 | *SEND_CR* does not send a CR ($0D) but rather a line feed (LF, $0A) character, 51 | because CR causes the text to overwrite itself on normal terminals. 52 | 53 | 54 | ## Links 55 | 56 | Consult the official [Mensch Monitor ROM Reference 57 | Manual](http://www.westerndesigncenter.com/Wdc/documentation/265monrom.pdf), the 58 | official [Assembler code listing of the Mensch 59 | Monitor](http://www.westerndesigncenter.com/wdc/documentation/265iromlist.pdf) 60 | or the [Most Very Unofficial Guide to the 61 | W65C265SXB](https://github.com/scotws/265SXB-Guide) for details on how these 62 | routines work. 63 | 64 | ## Interaction with the Crude 65816 Emulator 65 | 66 | The MMM was created to work with [A Crude Emulator for the 65186 in 67 | Forth](https://github.com/scotws/crude65816). The emulator assumes that the name 68 | of the file is `mmm.bin` in this directory. Make sure to uncomment the correct 69 | lines in config.sys, that is, both the LOADROM entry as well as the addresses 70 | for the emulator's PUTCHR and GETCHR routines. 71 | -------------------------------------------------------------------------------- /roms/mmm/mmm.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scotws/crude65816/e11a3a3fc99d0be33485eef5aa91181a526d11cb/roms/mmm/mmm.bin -------------------------------------------------------------------------------- /roms/mmm/mmm.tasm: -------------------------------------------------------------------------------- 1 | ; Mock Mensch Monitor (MMM) Utility Emulator for 2 | ; A Crude 65816 Emulator (crude65816) 3 | ; Scot W. Stevenson 4 | ; First version: 22. Feb 2016 5 | ; This version: 24. Dec 2016 6 | 7 | ; After assembly, this creates an 8K binary file that can be 8 | ; loaded to 00:E000 in an emulator via config.fs. 9 | 10 | ; This program is distributed in the hope that it will be useful, 11 | ; but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | ; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | ; GNU General Public License for more details. 14 | 15 | ; This program is written in Typist's Assembler Notation 16 | 17 | .mpu 65816 18 | .origin 00e000 19 | 20 | .equ putchr 00:df77 ; Address emulator uses for putchr 21 | .equ getchr 00:df75 ; Address emulator uses for getchr (blocks) 22 | .equ tmp4 00:0066 ; 3-byte DP address used by PUT_STR 23 | 24 | 25 | ; Jump table. These must remain in the exact same location for the 26 | ; routines to be the equivalent of the real WDC Mensch Monitor. Do not 27 | ; add the .NATIVE directive before this table 28 | 29 | jmp alter_memory ; must be at 00:e000 30 | jmp backspace ; 00:e003 31 | jmp .* ; 00:e006 32 | jmp control_tones ; 00:e009 33 | jmp do_low_pwr_pgm ; 00:e00c 34 | jmp dumpregs ; 00:e00f 35 | jmp dumps28 ; 00:e012 36 | jmp dump_1_line_to_output ; 00:e015 37 | jmp dump_1_line_to_screen ; 00:e018 38 | jmp dump_to_output ; 00:e01b 39 | jmp dump_to_printer ; 00:e01e 40 | jmp dump_to_screen ; 00:e021 41 | jmp dump_to_screen_ascii ; 00:e024 42 | jmp dump_it ; 00:e027 43 | jmp fill_memory ; 00:e02a 44 | jmp get_3byte_addr ; 00:e02d 45 | jmp get_alarm_status ; 00:e030 46 | jmp get_byte_from_pc ; 00:e033 47 | jmp get_chr ; 00:e036 48 | jmp get_hex ; 00:e039 49 | jmp get_put_chr ; 00:e03c 50 | jmp get_str ; 00:e03f 51 | jmp get_address ; 00:e042 52 | jmp get_e_address ; 00:e045 53 | jmp get_s_address ; 00:e048 54 | jmp put_chr ; 00:e04b 55 | jmp put_str ; 00:e04e 56 | jmp read_alarm ; 00:e051 57 | jmp read_date ; 00:e054 58 | jmp read_time ; 00:e057 59 | jmp reset_alarm ; 00:e05a 60 | jmp sbreak ; 00:e05d 61 | jmp select_common_baud_rate ; 00:e060 62 | jmp send_byte_to_pc ; 00:e063 63 | jmp send_cr ; 00:e066 64 | jmp send_space ; 00:e069 65 | jmp send_hex_out ; 00:e06c 66 | jmp set_alarm ; 00:e06f 67 | jmp set_breakpoint ; 00:e072 68 | jmp set_date ; 00:e075 69 | jmp set_time ; 00:e078 70 | jmp version ; 00:e07b 71 | jmp wr_3_address ; 00:e07e 72 | jmp xs28in ; 00:e081 73 | jmp reset ; 00:e084 74 | 75 | ; Subroutine table. These must remain in the exact same location for the 76 | ; routines to be the equivalent of the WDC Mensch Monitor 77 | 78 | jsr ascbin ; must be at 00:e087 79 | rts.l 80 | 81 | jsr bin2dec ; 00:e08b 82 | rts.l 83 | 84 | jsr binasc ; 00:e08f 85 | rts.l 86 | 87 | jsr hexin ; 00:e093 88 | rts.l 89 | 90 | jsr ifasc ; 00:e097 91 | rts.l 92 | 93 | jsr isdecimal ; 00:e09b 94 | rts.l 95 | 96 | jsr ishex ; 00:e09f 97 | rts.l 98 | 99 | jsr upper_case ; 00:e0a7 100 | rts.l 101 | 102 | .skip 08 ; "reserved for expansion" 103 | 104 | 105 | ; Jump targets. Those we don't code we send to a common routine 106 | 107 | alter_memory 108 | backspace 109 | control_tones 110 | do_low_pwr_pgm 111 | dumpregs 112 | dumps28 113 | dump_1_line_to_output 114 | dump_1_line_to_screen 115 | dump_to_output 116 | dump_to_printer 117 | dump_to_screen 118 | dump_to_screen_ascii 119 | dump_it 120 | fill_memory 121 | get_3byte_addr 122 | get_alarm_status 123 | get_byte_from_pc 124 | jmp notcoded 125 | 126 | 127 | ; GET_CHR -- Get a character from the keyboard. 128 | ; TODO see if we keep a16 or actually switch like here 129 | ; TODO Make sure ESC returns $1B 130 | ; TODO Make sure Control-C returns as $03 131 | get_chr 132 | .!native 133 | .a8 134 | lda 00df75 ; Address the emulator uses for getchr 135 | clc ; Mensch Monitor returns clear bit 136 | rts.l 137 | 138 | get_hex 139 | get_put_chr 140 | jmp notcoded 141 | 142 | ; GET_STR -- Get a string and store it with an added terminating zero at 143 | ; the address provided by A (bank byte) and X (16 bit address) 144 | get_str 145 | .!native 146 | .!a8 147 | .!xy16 148 | phy 149 | phd 150 | phb 151 | phe.# 0000 152 | pld 153 | 154 | sta.d tmp4 + 2 155 | stx.d tmp4 156 | 157 | ldy.# 0000 158 | 159 | get_str_loop 160 | jsr.l get_chr 161 | sta.dily tmp4 162 | iny 163 | cmp.# 0d ; CR ends input 164 | bne get_str_loop 165 | 166 | lda.# 00 167 | sta.dily tmp4 168 | 169 | plb 170 | pld 171 | ply 172 | rts.l 173 | 174 | 175 | get_address 176 | get_e_address 177 | get_s_address 178 | jmp notcoded 179 | 180 | ; PUT_CHR -- Print chracter in A routine to screen. We currently ignore 181 | ; the carry bit. If (once) we do include, we'll have to change PUT_STR 182 | ; as well 183 | ; TODO: Handle carry flag 184 | put_chr 185 | .!native 186 | .!a8 187 | sta.l putchr 188 | rts.l 189 | 190 | ; PUT_STR -- Print string to screen. Assumes bank byte of address of 191 | ; string is in 8-bit A and rest of address in 16-bit X. All registers 192 | ; are preserved, there are no error messages. WDC Manual for the Mensch 193 | ; Monitor states that maximal string length is 640 bytes, this limit is 194 | ; currently not emulated. As with PUT_CHR, we ignore the carry flag. 195 | ; TODO: Test bank wrapping behavior 196 | ; TODO: Handle carry flag 197 | put_str 198 | .!native 199 | .!a8 200 | .!xy16 201 | phy 202 | phd ; save Direct Page 203 | phb 204 | 205 | phe.# 0000 206 | pld ; Direct Page is 0000 207 | 208 | sta.d tmp4 + 2 ; save bank byte of string 209 | stx.d tmp4 210 | 211 | ldy.# 0000 212 | 213 | put_str_next lda.dily tmp4 ; LDA [TMP4],Y 214 | beq put_str_done 215 | 216 | ; The Mensch Monitor only prints 7-bit ASCII, which sucks 217 | ; if you're not coding in English, but this is an emulator 218 | ; so we go along 219 | and.# 7f 220 | jsr.l put_chr 221 | 222 | iny 223 | bra put_str_next 224 | 225 | put_str_done plb 226 | pld 227 | ply 228 | rts.l 229 | 230 | read_alarm 231 | read_date 232 | read_time 233 | reset_alarm 234 | sbreak 235 | select_common_baud_rate 236 | send_byte_to_pc 237 | jmp notcoded 238 | 239 | 240 | ; SEND_CR 241 | ; Send a Carriage Return (CR, $0D) to the screen. Assumes that A is 8-bit, 242 | ; conserves it. Must be called with long subroutine jump (jsr.l). 243 | 244 | ; NOTE: For emulation purposes, we do not send a CR, but a linefeed (LF, $0A), 245 | ; because a CR causes stuff to overwrite. 246 | send_cr 247 | .!native 248 | .!a8 249 | pha 250 | lda.# 0a 251 | sta.l putchr ; emulated address, assumes we're bank 00 252 | pla 253 | rts.l 254 | 255 | 256 | send_space 257 | send_hex_out 258 | set_alarm 259 | set_breakpoint 260 | set_date 261 | set_time 262 | version 263 | wr_3_address 264 | xs28in 265 | reset 266 | ascbin 267 | bin2dec 268 | binasc 269 | hexin 270 | ifasc 271 | isdecimal 272 | ishex 273 | upper_case jmp notcoded 274 | 275 | 276 | ; --- Generic Routines --- 277 | 278 | ; Common target for all routines that are not (yet) coded 279 | notcoded 280 | .!native 281 | .a8 282 | .xy16 283 | 284 | lda.# .bank s_notcoded 285 | ldx.# s_notcoded 286 | jsr.l put_str 287 | jmp alldone 288 | 289 | 290 | ; We don't really do anything monitor-like at all, so if for some 291 | ; reason we are interrupted, we land here with an error message 292 | hit_interrupt 293 | .!native 294 | .a8 295 | .xy16 296 | 297 | lda.# .bank s_interrupt 298 | ldx.# s_interrupt 299 | jsr.l put_str 300 | jmp alldone 301 | 302 | 303 | ; Common return point. Note we need a long subroutine jump 304 | ; TODO restore registers etc 305 | alldone rts.l 306 | 307 | ; Strings 308 | s_notcoded .byte "Routine not coded.", 0 309 | s_interrupt .byte "Interrupt triggered, halting.", 0 310 | 311 | 312 | ; Vector Table for the W65C264SXB 313 | ; TODO these must all point to hit_interrupt 314 | 315 | ; .advance 00:ffe4 316 | 317 | ; vectors w, \ ffe4 COP (native mode) 318 | ; vectors w, \ ffe6 BRK (native mode) 319 | ; vectors w, \ ffe8 ABORT (native mode) 320 | ; vectors w, \ ffea NMI (native mode) 321 | ; 0000 w, \ ffec -- unused -- 322 | ; vectors w, \ ffee IRQ (native mode) 323 | ; 0000 w, \ fff0 -- unused -- 324 | ; 0000 w, \ fff2 -- unused -- 325 | ; vectors w, \ fff4 COP (emulation mode) 326 | ; 0000 w, \ fff6 -- unused -- 327 | ; vectors w, \ fff8 ABORT (emulation mode) 328 | ; vectors w, \ fffa NMI (emulation mode) 329 | ; vectors w, \ fffc RESET (emulation mode) 330 | ; vectors w, \ fffe IRQ (emulation mode) 331 | 332 | .end 333 | -------------------------------------------------------------------------------- /roms/mmm/test_mmm.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scotws/crude65816/e11a3a3fc99d0be33485eef5aa91181a526d11cb/roms/mmm/test_mmm.bin -------------------------------------------------------------------------------- /roms/mmm/test_mmm.tasm: -------------------------------------------------------------------------------- 1 | ; Tests for the Mock Mensch Monitor ROM 2 | ; for the crude65816.fs emulator 3 | ; Scot W. Stevenson 4 | ; First version: 23. Dez 2016 5 | ; This version: 24. Dez 2016 6 | 7 | ; Tests are not run alphabetically, but by increasing complexity 8 | 9 | .mpu 65816 10 | .origin 08000 11 | 12 | .equ asclf 0A ; line feed ASCII character 13 | .equ asccr 0D ; carriage return ASCII character 14 | 15 | .native 16 | 17 | ; Print intro string. Yes, this is already a test for PUT_STR 18 | .a8 19 | .xy16 20 | lda.# 00 21 | ldx.# s_hello 22 | jsr.l 00:e04e 23 | 24 | ; --- Test 1: PUT_CHR 25 | 26 | lda.# 00 27 | ldx.# s_put_chr 28 | jsr.l 00:e04e 29 | 30 | lda.# 'a' 31 | jsr.l 00:e04b 32 | jsr.l 00:e04b 33 | jsr.l 00:e04b 34 | lda.# AscLF 35 | jsr.l 00:e04b 36 | 37 | ; --- Test 2: PUT_STR 38 | .xy16 39 | lda.# 00 ; bank byte, should be zero 40 | ldx.# s_put_str ; address of string 41 | jsr.l 00:e04e 42 | 43 | ; --- Test 4: SEND_CR 44 | lda.# 00 45 | ldx.# s_send_cr1 46 | jsr.l 00:e04e 47 | 48 | jsr.l 00:e066 49 | 50 | lda.# 00 51 | ldx.# s_send_cr2 52 | jsr.l 00:e04e 53 | 54 | ; --- TEST 5: GET_CHR 55 | ; Assumes we're still 8-bit A 56 | 57 | lda.# 00 58 | ldx.# s_get_chr1 59 | jsr.l 00:e04e 60 | 61 | sec ; test carry bit 62 | jsr.l 00:e036 63 | bcc + 64 | 65 | ; Carry should be not be set, abort 66 | lda.# 00 67 | ldx.# s_get_chr3 68 | jsr.l 00:e04e 69 | stp 70 | 71 | @ 72 | ; Compare various byte codes 73 | 74 | pha 75 | jsr.l 00:e04b ; PUT_CHR 76 | 77 | lda.# 00 78 | ldx.# s_get_chr2 79 | jsr.l 00:e04e 80 | 81 | pla 82 | cmp.# 1b ; ESC 83 | bne get_chr_done 84 | 85 | ; TODO test for arrow keys once we know what the 86 | ; acutal board produces 87 | 88 | lda.# 00 89 | ldx.# s_get_chr4 90 | jsr.l 00:e04e 91 | 92 | get_chr_done 93 | 94 | ; --- TEST 6: GET_STR 95 | ; --- TEST 7: GET_PUT_CHR 96 | 97 | ; --- All done 98 | 99 | .a8 100 | .xy16 101 | lda.# 00 102 | ldx.# s_bye 103 | jsr.l 00:e04e 104 | 105 | stp 106 | 107 | ; --- Strings 108 | 109 | s_hello .byte AscLF, "Test Suite for the Mock Mensch Monitor", AscLF, 0 110 | s_put_chr .byte AscLF, "- PUT_CHR: Should print 'aaa': ", 0 111 | s_put_str .byte "- PUT_STR: You should be reading this string", AscLF, 0 112 | s_get_chr1 .byte "- GET_CHR: Press a key please --> ", 0 113 | s_get_chr2 .byte " <-- is what we got.", AscLF, 0 114 | s_get_chr3 .byte "- GET_CHR ERROR: Carry Flag set. ABORTING.", AscLF, 0 115 | s_get_chr4 .byte "- GET_CHR: Got ESC ($1B) key (correct).", AscLF, 0 116 | s_send_cr1 .byte "- SEND_CR: You should see one empty line ...", AscLF, 0 117 | s_send_cr2 .byte "... between the last line and this one", AscLF, 0 118 | s_bye .byte AscLF, "All done, goodbye", AscLF, 0 119 | 120 | .end 121 | -------------------------------------------------------------------------------- /roms/rom65816.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scotws/crude65816/e11a3a3fc99d0be33485eef5aa91181a526d11cb/roms/rom65816.bin -------------------------------------------------------------------------------- /roms/rom65816.fs: -------------------------------------------------------------------------------- 1 | \ Example 8 KB ROM System for 2 | \ A Crude 65816 Emulator (crude65816) 3 | \ Scot W. Stevenson 4 | \ This version: 09. Jan 2015 5 | 6 | \ After assembly, this creates an 8 kb binary file that can be 7 | \ loaded to $E000 in a simulator. Currently, this is all 6502 8 | \ 8-bit code. 9 | 10 | \ This program is distributed in the hope that it will be useful, 11 | \ but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | \ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | \ GNU General Public License for more details. 14 | 15 | hex 16 | cr .( Starting assembly ... ) 17 | 18 | \ --- DEFINITIONS --- 19 | 20 | 0e000 origin \ required 21 | 22 | 0ff00 value putchr \ py65mon address for character output 23 | 0ff01 value getchr \ py65mon address to receive character input 24 | 25 | \ --- STRINGS --- 26 | \ Life is easier if you put these at the beginning of the text: It's 27 | \ tricky to put unresolved forward references in macros 28 | 29 | -> intro 30 | s" ------------------------------------------------" strlf, 31 | s" Test ROM for The Crude 65816 Emulator " strlf, 32 | s" Scot W. Stevenson " strlf, 33 | s" ------------------------------------------------" str0, 34 | 35 | 36 | \ --- SUBROUTINES --- 37 | \ These, too, should go before the main code if at all possible 38 | 39 | \ Print a zero-terminated string. Assumes address in $00, $01 40 | -> prtstr 41 | phy 42 | 00 ldy.# 43 | -> nxtchr 44 | 00 lda.ziy 45 | b> fini beq 46 | putchr sta 47 | iny 48 | nxtchr bra 49 | -> fini 50 | ply 51 | rts 52 | 53 | \ --- MACROS --- 54 | \ In contrast to normal assemblers, our macros don't do so well if 55 | \ they are first in the file. In this case, putting .STR here lets 56 | \ us access the strings and call the prtstr subroutine without 57 | \ much hassle 58 | 59 | \ Macro to print one linefeed 60 | : .linefeed ( -- ) 0a lda.# putchr sta ; 61 | 62 | \ Macro to print a string. Note this doesn't work with strings 63 | \ that were defined lower down because it gets tricky with 64 | \ unresolved links. Gforth already uses .STRING 65 | : .str ( link -- ) 66 | dup lsb lda.# 00 sta.z 67 | msb lda.# 01 sta.z 68 | prtstr jsr ; 69 | 70 | 71 | \ --- MAIN CODE --- 72 | 73 | \ All of our vectors go here because we're cheap 74 | -> vectors 75 | 76 | \ Print the intro string 77 | intro .str .linefeed 78 | 79 | 80 | 81 | \ --- INTERRUPT VECTORS --- 82 | 83 | \ skip to interrupt vectors, filling rest of the image with zeros 84 | 0ffe4 advance 85 | 86 | vectors w, \ ffe4 COP (native mode) 87 | vectors w, \ ffe6 BRK (native mode) 88 | vectors w, \ ffe8 ABORT (native mode) 89 | vectors w, \ ffea NMI (native mode) 90 | 0000 w, \ ffec -- unused -- 91 | vectors w, \ ffee IRQ (native mode) 92 | 0000 w, \ fff0 -- unused -- 93 | 0000 w, \ fff2 -- unused -- 94 | vectors w, \ fff4 COP (emulation mode) 95 | 0000 w, \ fff6 -- unused -- 96 | vectors w, \ fff8 ABORT (emulation mode) 97 | vectors w, \ fffa NMI (emulation mode) 98 | vectors w, \ fffc RESET (emulation mode) 99 | vectors w, \ fffe IRQ (emulation mode) 100 | 101 | end 102 | 103 | \ ----------------------------------- 104 | cr .( ... assembly finished. ) 105 | 106 | \ uncomment next line to save the hex dump to the file "rom.bin" 107 | 2dup save rom65816.bin 108 | -------------------------------------------------------------------------------- /tests/README.txt: -------------------------------------------------------------------------------- 1 | Test Routines for the Crude 65816 Emulator 2 | Scot W. Stevenson 3 | First version: 09. Okt 2015 4 | This version: 22. Dec 2016 5 | 6 | This folder contains various tests for the emulator. It's pretty unstructured and chaotic and probably confusing if you're not the author. At some point, this will be cleaned up properly. 7 | 8 | - Tali Forth is a 8-bit Forth for the 65c02, see FEHLT. This is included as a gimick until a 16-bit Forth is avaiable. Change the configuration files to 9 | 10 | putc f001 11 | getc f004 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /tests/TEST-dp-wrapping.tasmf: -------------------------------------------------------------------------------- 1 | \ Testing ROM for 2 | \ A Crude 65816 Emulator (crude65816) 3 | \ Scot W. Stevenson 4 | \ This version: 17. Okt 2015 5 | 6 | hex 7 | cr .( Starting assembly ... ) 8 | 9 | \ --- DEFINITIONS --- 10 | 11 | 0ff00 value putchr \ py65mon address for character output 12 | 0ff01 value getchr \ py65mon address to receive character input 13 | 14 | 0e000 origin \ required 15 | 16 | \ --- SETUP --- 17 | 18 | \ All of our vectors go here because we're cheap 19 | -> vectors 20 | 21 | \ init stack 22 | 0ff ldx.# 23 | txs 24 | 00 ldx.# 25 | 26 | \ wai 27 | 28 | 29 | \ *** TEST CODE *** 30 | 31 | \ These are not comprehesive tests. Execution stops either when all tests 32 | \ are completed successfully (X and Y both 0FF) or STP with error 33 | 34 | \ Error codes in A are 01, 02, etc 35 | \ Success codes in A are FF, FE, etc 36 | 37 | 38 | \ ############################### 39 | \ ## TESTING MODE.DX (MODE.DY) ## 40 | \ ############################### 41 | 42 | \ ------------------------------ 43 | -> dpw0 44 | 45 | \ We are in emulation mode (TEST 1), we SHOULD wrap on page 46 | \ We assume D is 0000 (on page boundry, TEST 2) 47 | 48 | 0ff lda.# 49 | 80 ldx.# 50 | 90 sta.dx \ old opcode (TEST 3) 51 | 52 | 10 cmp.d \ we should wrap to page so that 00:0010 is FF 53 | dpw1 60 | 61 | \ Move to native mode (TEST 1), we should NOT wrap on page, 62 | \ We assume D is 0000 (on page boundry, TEST 2) 63 | 64 | 0fe lda.# 65 | native 66 | 90 sta.dx \ old opcode (TEST 3) 67 | 68 | 0110 cmp \ 00:0110 should be FE 69 | dpw2 76 | 77 | \ Return to emulated mode (TEST 1), we should NOT wrap on page, 78 | \ We move D to 000f (NOT on page boundry, TEST 2) 79 | 80 | 81 | emulated 82 | 83 | 00 lda.# 84 | xba 85 | 0f lda.# 86 | tcd 87 | 88 | 0fd lda.# 89 | 90 sta.dx \ old opcode (TEST 3) 90 | 91 | 011F cmp \ 00:011f should be FD ( D + operand + X ) 92 | dpw3 99 | 100 | \ In emulated mode (TEST 1), Return D to 0000 (TEST 3), 101 | \ but use new opcode (TEST 3). We should NOT wrap on page 102 | 103 | 00 lda.# 104 | xba 105 | 00 lda.# 106 | tcd 107 | 108 | 20 ldy.# 109 | 110 | 0fc lda.# 111 | 30 sta.dily \ new opcode (TEST 3) 112 | 113 | 20 cmp.d \ [30] -> 00:0000 + 20 --> 00:0020 114 | dpw4 120 | 121 | \ ############################### 122 | \ ###### TESTING MODE.DI ######## 123 | \ ############################### 124 | 125 | 0fb lda.# \ 0fb is in 00:1122 126 | xba 127 | 1122 sta 128 | 129 | 22 lda.# \ store 1122 in 00:0040 130 | 40 sta.d 131 | 11 lda.# 132 | 41 sta.d 133 | 134 | xba \ get 0fb back 135 | 40 sta.di 136 | 137 | 1122 cmp 138 | dpw5 144 | 145 | \ ############################### 146 | \ ###### TESTING MODE.DIY ####### 147 | \ ############################### 148 | 149 | \ Note 00:0040 still contains 1122 150 | 0fa lda.# 151 | 01 ldy.# 152 | 153 | 40 sta.diy \ 0000 + 40 --> 1122 + 01 --> 1123 154 | 1123 cmp 155 | dpw6 161 | 162 | 163 | \ All is well! 164 | 165 | 0ff ldx.# 166 | txy 167 | 168 | \ *** END CODE *** 169 | 170 | 171 | stp 172 | stp 173 | 174 | 175 | \ === USEFUL SUBROUTINES === 176 | 177 | \ -> printchar 178 | \ rts 179 | 180 | \ Clear direct page. TODO temp version that assumes DP is 0 181 | \ -> clrd 182 | \ 183 | \ native axy:8 184 | \ 00 lda.# 185 | \ tax 186 | \ 187 | \ -> clrd01 188 | \ 0000 sta.x 189 | \ dex 190 | \ clrd01 bne 191 | \ 192 | \ rts 193 | 194 | 195 | \ --- INTERRUPT VECTORS --- 196 | 197 | \ skip to interrupt vectors, filling rest of the image with zeros 198 | 0ffe4 advance 199 | 200 | vectors w, \ ffe4 COP (native mode) 201 | vectors w, \ ffe6 BRK (native mode) 202 | vectors w, \ ffe8 ABORT (native mode) 203 | vectors w, \ ffea NMI (native mode) 204 | 0000 w, \ ffec -- unused -- 205 | vectors w, \ ffee IRQ (native mode) 206 | 0000 w, \ fff0 -- unused -- 207 | 0000 w, \ fff2 -- unused -- 208 | vectors w, \ fff4 COP (emulation mode) 209 | 0000 w, \ fff6 -- unused -- 210 | vectors w, \ fff8 ABORT (emulation mode) 211 | vectors w, \ fffa NMI (emulation mode) 212 | vectors w, \ fffc RESET (emulation mode) 213 | vectors w, \ fffe IRQ (emulation mode) 214 | 215 | end 216 | 217 | \ ----------------------------------- 218 | cr .( ... assembly finished. ) 219 | 220 | \ uncomment next line to save the hex dump to the file "rom.bin" 221 | 2dup save rom.bin 222 | -------------------------------------------------------------------------------- /tests/TEST-phe.tasmf: -------------------------------------------------------------------------------- 1 | \ Testing ROM for PHE family of instructions 2 | \ A Crude 65816 Emulator (crude65816) 3 | \ Scot W. Stevenson 4 | \ This version: 26. Okt 2015 5 | 6 | hex 7 | cr .( Starting assembly ... ) 8 | 9 | \ --- DEFINITIONS --- 10 | 11 | 0ff00 value putchr \ py65mon address for character output 12 | 0ff01 value getchr \ py65mon address to receive character input 13 | 14 | 0e000 origin \ required 15 | 16 | \ --- SETUP --- 17 | 18 | \ All of our vectors go here because we're cheap 19 | -> vectors 20 | 21 | \ init stack 22 | 0ff ldx.# 23 | txs 24 | 00 ldx.# 25 | 26 | \ wai 27 | 28 | 29 | \ *** TEST CODE *** 30 | 31 | \ These are not comprehesive tests. Execution stops either when all tests 32 | \ are completed successfully (X and Y both 0FF) or STP with error 33 | 34 | \ Error codes in A are 01, 02, etc 35 | \ Success codes in A are FF, FE, etc 36 | 37 | 38 | \ ############################### 39 | \ ## TESTING PHE INSTRUCTIONS ### 40 | \ ############################### 41 | 42 | \ (These are PEA, PEI, and PER in traditional notation) 43 | 44 | \ ------------------------------ 45 | -> dpw0 46 | 47 | \ HIER HIER 48 | 49 | 50 | stp 51 | 52 | \ We are in emulation mode (TEST 1), we SHOULD wrap on page 53 | \ We assume D is 0000 (on page boundry, TEST 2) 54 | 55 | 0ff lda.# 56 | 80 ldx.# 57 | 90 sta.dx \ old opcode (TEST 3) 58 | 59 | 10 cmp.d \ we should wrap to page so that 00:0010 is FF 60 | dpw1 67 | 68 | \ Move to native mode (TEST 1), we should NOT wrap on page, 69 | \ We assume D is 0000 (on page boundry, TEST 2) 70 | 71 | 0fe lda.# 72 | native 73 | 90 sta.dx \ old opcode (TEST 3) 74 | 75 | 0110 cmp \ 00:0110 should be FE 76 | dpw2 83 | 84 | \ Return to emulated mode (TEST 1), we should NOT wrap on page, 85 | \ We move D to 000f (NOT on page boundry, TEST 2) 86 | 87 | 88 | emulated 89 | 90 | 00 lda.# 91 | xba 92 | 0f lda.# 93 | tcd 94 | 95 | 0fd lda.# 96 | 90 sta.dx \ old opcode (TEST 3) 97 | 98 | 011F cmp \ 00:011f should be FD ( D + operand + X ) 99 | dpw3 106 | 107 | \ In emulated mode (TEST 1), Return D to 0000 (TEST 3), 108 | \ but use new opcode (TEST 3). We should NOT wrap on page 109 | 110 | 00 lda.# 111 | xba 112 | 00 lda.# 113 | tcd 114 | 115 | 20 ldy.# 116 | 117 | 0fc lda.# 118 | 30 sta.dily \ new opcode (TEST 3) 119 | 120 | 20 cmp.d \ [30] -> 00:0000 + 20 --> 00:0020 121 | dpw4 127 | 128 | \ ############################### 129 | \ ###### TESTING MODE.DI ######## 130 | \ ############################### 131 | 132 | 0fb lda.# \ 0fb is in 00:1122 133 | xba 134 | 1122 sta 135 | 136 | 22 lda.# \ store 1122 in 00:0040 137 | 40 sta.d 138 | 11 lda.# 139 | 41 sta.d 140 | 141 | xba \ get 0fb back 142 | 40 sta.di 143 | 144 | 1122 cmp 145 | dpw5 151 | 152 | \ ############################### 153 | \ ###### TESTING MODE.DIY ####### 154 | \ ############################### 155 | 156 | \ Note 00:0040 still contains 1122 157 | 0fa lda.# 158 | 01 ldy.# 159 | 160 | 40 sta.diy \ 0000 + 40 --> 1122 + 01 --> 1123 161 | 1123 cmp 162 | dpw6 168 | 169 | 170 | \ All is well! 171 | 172 | 0ff ldx.# 173 | txy 174 | 175 | \ *** END CODE *** 176 | 177 | 178 | stp 179 | stp 180 | 181 | 182 | \ === USEFUL SUBROUTINES === 183 | 184 | \ -> printchar 185 | \ rts 186 | 187 | \ Clear direct page. TODO temp version that assumes DP is 0 188 | \ -> clrd 189 | \ 190 | \ native axy:8 191 | \ 00 lda.# 192 | \ tax 193 | \ 194 | \ -> clrd01 195 | \ 0000 sta.x 196 | \ dex 197 | \ clrd01 bne 198 | \ 199 | \ rts 200 | 201 | 202 | \ --- INTERRUPT VECTORS --- 203 | 204 | \ skip to interrupt vectors, filling rest of the image with zeros 205 | 0ffe4 advance 206 | 207 | vectors w, \ ffe4 COP (native mode) 208 | vectors w, \ ffe6 BRK (native mode) 209 | vectors w, \ ffe8 ABORT (native mode) 210 | vectors w, \ ffea NMI (native mode) 211 | 0000 w, \ ffec -- unused -- 212 | vectors w, \ ffee IRQ (native mode) 213 | 0000 w, \ fff0 -- unused -- 214 | 0000 w, \ fff2 -- unused -- 215 | vectors w, \ fff4 COP (emulation mode) 216 | 0000 w, \ fff6 -- unused -- 217 | vectors w, \ fff8 ABORT (emulation mode) 218 | vectors w, \ fffa NMI (emulation mode) 219 | vectors w, \ fffc RESET (emulation mode) 220 | vectors w, \ fffe IRQ (emulation mode) 221 | 222 | end 223 | 224 | \ ----------------------------------- 225 | cr .( ... assembly finished. ) 226 | 227 | \ uncomment next line to save the hex dump to the file "rom.bin" 228 | 2dup save rom.bin 229 | -------------------------------------------------------------------------------- /tests/fragments.tasmf: -------------------------------------------------------------------------------- 1 | \ Test fragments for larger test program for the Crude 65816 Emulator 2 | \ Scot W. Stevenson 3 | \ First version: 05. Okt 2015 4 | \ This version: 05. Okt 2015 5 | 6 | 7 | \ ==== DECIMAL MODE ==== 8 | 9 | \ = Subtraction in Decimal Mode (SBC) = 10 | \ Based on http://visual6502.org/wiki/index.php?title=6502DecimalMode 11 | 12 | sed 13 | 14 | \ 00 - 00 and C=0 gives 99 and N=1 V=0 Z=0 C=0 15 | 00 lda.# 16 | clc 17 | 00 sbc.# 18 | 19 | \ 00 - 00 and C=1 gives 00 and N=0 V=0 Z=1 C=1 20 | 00 lda.# 21 | sec 22 | 00 sbc.# 23 | 24 | \ 00 - 01 and C=1 gives 99 and N=1 V=0 Z=0 C=0 25 | 00 lda.# 26 | sec 27 | 01 sbc.# 28 | 29 | \ 0a - 00 and C=1 gives 0a and N=0 V=0 Z=0 C=1 30 | 0a lda.# 31 | sec 32 | 00 sbc.# 33 | 34 | \ 0b - 00 and C=0 gives 0a and N=0 V=0 Z=0 C=1 35 | 0b lda.# 36 | clc 37 | 00 sbc.# 38 | 39 | \ 9a - 00 and C=1 gives 9a and N=1 V=0 Z=0 C=1 40 | 9a lda.# 41 | sec 42 | 00 sbc.# 43 | 44 | \ 9b - 00 and C=0 gives 9a and N=1 V=0 Z=0 C=1 45 | 9b lda.# 46 | clc 47 | 00 sbc.# 48 | 49 | 50 | \ === TRB Instrution === 51 | 52 | \ http://6502.org/tutorials/65c02opcodes.html 53 | 54 | 55 | 0a6 lda.# 56 | 00 sta.d 57 | 33 lda.# 58 | 00 trb.d \ 00 must be 84, Z=0 and A retains 33 59 | 60 | iny 61 | 62 | 0a6 lda.# 63 | 00 sta.d 64 | 41 lda.# 65 | 00 trb.d \ 00 must be A6, Z=1 and A retains 41 66 | 67 | 68 | 69 | 70 | -------------------------------------------------------------------------------- /tests/testsources.txt: -------------------------------------------------------------------------------- 1 | List of Sources for 6502/65816 tests 2 | Scot W. Stevenson 3 | First version: 05. Okt 2015 4 | This version: 12. Okt 2015 5 | 6 | Collect these for future test routines 7 | 8 | 9 | DECIMAL MODE: 10 | http://visual6502.org/wiki/index.php?title=6502DecimalMode (8 bit BCD) 11 | 12 | TRB/TSB: 13 | http://6502.org/tutorials/65c02opcodes.html 14 | 15 | VARIOUS: 16 | 17 | http://forum.6502.org/viewtopic.php?f=4&t=712 18 | 19 | For example, when e=0, m=0, and B=$12 (DBR), an ASL $FFFF (i.e. absolute addressing) performs a 16-bit shift whose low byte is at $12FFFF and whose high byte is at $130000. 20 | 21 | http://forum.6502.org/viewtopic.php?f=2&t=1345 22 | 23 | http://www.verycomputer.com/20_f32cfebe2a348b76_1.htm 24 | 25 | 26 | -------------------------------------------------------------------------------- /tools/hex2rom.fs: -------------------------------------------------------------------------------- 1 | \ hex2rom.fs - Store hex numbers in file to test ROM 2 | \ Tool for A Crude 65816 Emulator 3 | \ Scot W. Stevenson 4 | \ First version: 26. Mai 2015 5 | \ This version: 27. Mai 2015 6 | 7 | \ Edit program between the two lines by hand, and remember to 8 | \ update the number of bytes to write to file in the 9 | \ "write-file" line at the bottom. Then, call with 10 | \ "gforth hex2rom.fs", and on Linux, check results with 11 | \ "hexdump -C testrom.bin". Load that file via config.fs. In 12 | \ crude65816, set the PC to the first instruction (usually e000) 13 | \ before calling "run" or "step" 14 | 15 | hex 16 | 17 | variable fileid 18 | 19 | : makefile ( addr u -- ) w/o create-file drop ; 20 | 21 | create rombyhand 22 | 23 | \ ================================= 24 | 25 | 0a2 c, \ 0aa ldx.# 26 | 0aa c, \ 27 | 28 | 8e c, \ 0eeee stx 29 | 0ee c, 30 | 0ee c, 31 | 32 | 18 c, \ clc \ switch to native mode 33 | 0fb c, \ xce 34 | 35 | 0c2 c, \ 10 rep \ xy->16 36 | 10 c, 37 | 38 | 0a0 c, \ 0bbbb ldy.# 39 | 0bb c, \ 40 | 0bb c, \ 41 | 42 | 8c c, \ 0eeef sty 43 | 0ef c, 44 | 0ee c, 45 | 46 | 0db c, \ stp 47 | 48 | 49 | \ PUT UNUSED OPCODES BELOW THIS LINE 50 | 51 | \ 0a8 c, \ tay 52 | 53 | \ 4c c, \ jmp \ should BRK at 00eeee 54 | \ 0ee c, 55 | \ 0ee c, 56 | 57 | \ 0ea c, \ nop 58 | 59 | \ 0a0 c, \ 0bb ldy.# 60 | \ 0bb c, \ 61 | 62 | \ 9b c, \ txy 63 | 64 | \ 0a2 c, \ 0aa ldx.# 65 | \ 9b c, \ txy 66 | 67 | 68 | 69 | 70 | 71 | \ ================================= 72 | 73 | s" testrom.bin" makefile ( -- fileid ) 74 | fileid ! 75 | decimal 76 | rombyhand 16 fileid @ write-file 77 | fileid @ close-file 78 | 79 | bye 80 | 81 | -------------------------------------------------------------------------------- /tools/make-opc-routines.fs: -------------------------------------------------------------------------------- 1 | \ Create Opcode Routine List for 2 | \ The Crude 65816 Emulator 3 | \ Scot W. Stevenson 4 | \ This version 09. Jan 2015 5 | 6 | hex 7 | 8 | : make-opc-routines ( -- ) 9 | 100 0 do 10 | cr ." : opc-" i s>d <# # # #> type space 11 | ." ( TODO ) " 12 | ." " 2E emit 22 emit space 13 | i s>d <# # # #> type 14 | ." not coded yet" 22 emit ." ; " 15 | loop ; 16 | 17 | make-opc-routines 18 | 19 | bye 20 | 21 | -------------------------------------------------------------------------------- /tools/opc-routines.txt: -------------------------------------------------------------------------------- 1 | : opc-00 ( TODO ) ." 00 not coded yet" ; 2 | : opc-01 ( TODO ) ." 01 not coded yet" ; 3 | : opc-02 ( TODO ) ." 02 not coded yet" ; 4 | : opc-03 ( TODO ) ." 03 not coded yet" ; 5 | : opc-04 ( TODO ) ." 04 not coded yet" ; 6 | : opc-05 ( TODO ) ." 05 not coded yet" ; 7 | : opc-06 ( TODO ) ." 06 not coded yet" ; 8 | : opc-07 ( TODO ) ." 07 not coded yet" ; 9 | : opc-08 ( TODO ) ." 08 not coded yet" ; 10 | : opc-09 ( TODO ) ." 09 not coded yet" ; 11 | : opc-0A ( TODO ) ." 0A not coded yet" ; 12 | : opc-0B ( TODO ) ." 0B not coded yet" ; 13 | : opc-0C ( TODO ) ." 0C not coded yet" ; 14 | : opc-0D ( TODO ) ." 0D not coded yet" ; 15 | : opc-0E ( TODO ) ." 0E not coded yet" ; 16 | : opc-0F ( TODO ) ." 0F not coded yet" ; 17 | : opc-10 ( TODO ) ." 10 not coded yet" ; 18 | : opc-11 ( TODO ) ." 11 not coded yet" ; 19 | : opc-12 ( TODO ) ." 12 not coded yet" ; 20 | : opc-13 ( TODO ) ." 13 not coded yet" ; 21 | : opc-14 ( TODO ) ." 14 not coded yet" ; 22 | : opc-15 ( TODO ) ." 15 not coded yet" ; 23 | : opc-16 ( TODO ) ." 16 not coded yet" ; 24 | : opc-17 ( TODO ) ." 17 not coded yet" ; 25 | : opc-18 ( TODO ) ." 18 not coded yet" ; 26 | : opc-19 ( TODO ) ." 19 not coded yet" ; 27 | : opc-1A ( TODO ) ." 1A not coded yet" ; 28 | : opc-1B ( TODO ) ." 1B not coded yet" ; 29 | : opc-1C ( TODO ) ." 1C not coded yet" ; 30 | : opc-1D ( TODO ) ." 1D not coded yet" ; 31 | : opc-1E ( TODO ) ." 1E not coded yet" ; 32 | : opc-1F ( TODO ) ." 1F not coded yet" ; 33 | : opc-20 ( TODO ) ." 20 not coded yet" ; 34 | : opc-21 ( TODO ) ." 21 not coded yet" ; 35 | : opc-22 ( TODO ) ." 22 not coded yet" ; 36 | : opc-23 ( TODO ) ." 23 not coded yet" ; 37 | : opc-24 ( TODO ) ." 24 not coded yet" ; 38 | : opc-25 ( TODO ) ." 25 not coded yet" ; 39 | : opc-26 ( TODO ) ." 26 not coded yet" ; 40 | : opc-27 ( TODO ) ." 27 not coded yet" ; 41 | : opc-28 ( TODO ) ." 28 not coded yet" ; 42 | : opc-29 ( TODO ) ." 29 not coded yet" ; 43 | : opc-2A ( TODO ) ." 2A not coded yet" ; 44 | : opc-2B ( TODO ) ." 2B not coded yet" ; 45 | : opc-2C ( TODO ) ." 2C not coded yet" ; 46 | : opc-2D ( TODO ) ." 2D not coded yet" ; 47 | : opc-2E ( TODO ) ." 2E not coded yet" ; 48 | : opc-2F ( TODO ) ." 2F not coded yet" ; 49 | : opc-30 ( TODO ) ." 30 not coded yet" ; 50 | : opc-31 ( TODO ) ." 31 not coded yet" ; 51 | : opc-32 ( TODO ) ." 32 not coded yet" ; 52 | : opc-33 ( TODO ) ." 33 not coded yet" ; 53 | : opc-34 ( TODO ) ." 34 not coded yet" ; 54 | : opc-35 ( TODO ) ." 35 not coded yet" ; 55 | : opc-36 ( TODO ) ." 36 not coded yet" ; 56 | : opc-37 ( TODO ) ." 37 not coded yet" ; 57 | : opc-38 ( TODO ) ." 38 not coded yet" ; 58 | : opc-39 ( TODO ) ." 39 not coded yet" ; 59 | : opc-3A ( TODO ) ." 3A not coded yet" ; 60 | : opc-3B ( TODO ) ." 3B not coded yet" ; 61 | : opc-3C ( TODO ) ." 3C not coded yet" ; 62 | : opc-3D ( TODO ) ." 3D not coded yet" ; 63 | : opc-3E ( TODO ) ." 3E not coded yet" ; 64 | : opc-3F ( TODO ) ." 3F not coded yet" ; 65 | : opc-40 ( TODO ) ." 40 not coded yet" ; 66 | : opc-41 ( TODO ) ." 41 not coded yet" ; 67 | : opc-42 ( TODO ) ." 42 not coded yet" ; 68 | : opc-43 ( TODO ) ." 43 not coded yet" ; 69 | : opc-44 ( TODO ) ." 44 not coded yet" ; 70 | : opc-45 ( TODO ) ." 45 not coded yet" ; 71 | : opc-46 ( TODO ) ." 46 not coded yet" ; 72 | : opc-47 ( TODO ) ." 47 not coded yet" ; 73 | : opc-48 ( TODO ) ." 48 not coded yet" ; 74 | : opc-49 ( TODO ) ." 49 not coded yet" ; 75 | : opc-4A ( TODO ) ." 4A not coded yet" ; 76 | : opc-4B ( TODO ) ." 4B not coded yet" ; 77 | : opc-4C ( TODO ) ." 4C not coded yet" ; 78 | : opc-4D ( TODO ) ." 4D not coded yet" ; 79 | : opc-4E ( TODO ) ." 4E not coded yet" ; 80 | : opc-4F ( TODO ) ." 4F not coded yet" ; 81 | : opc-50 ( TODO ) ." 50 not coded yet" ; 82 | : opc-51 ( TODO ) ." 51 not coded yet" ; 83 | : opc-52 ( TODO ) ." 52 not coded yet" ; 84 | : opc-53 ( TODO ) ." 53 not coded yet" ; 85 | : opc-54 ( TODO ) ." 54 not coded yet" ; 86 | : opc-55 ( TODO ) ." 55 not coded yet" ; 87 | : opc-56 ( TODO ) ." 56 not coded yet" ; 88 | : opc-57 ( TODO ) ." 57 not coded yet" ; 89 | : opc-58 ( TODO ) ." 58 not coded yet" ; 90 | : opc-59 ( TODO ) ." 59 not coded yet" ; 91 | : opc-5A ( TODO ) ." 5A not coded yet" ; 92 | : opc-5B ( TODO ) ." 5B not coded yet" ; 93 | : opc-5C ( TODO ) ." 5C not coded yet" ; 94 | : opc-5D ( TODO ) ." 5D not coded yet" ; 95 | : opc-5E ( TODO ) ." 5E not coded yet" ; 96 | : opc-5F ( TODO ) ." 5F not coded yet" ; 97 | : opc-60 ( TODO ) ." 60 not coded yet" ; 98 | : opc-61 ( TODO ) ." 61 not coded yet" ; 99 | : opc-62 ( TODO ) ." 62 not coded yet" ; 100 | : opc-63 ( TODO ) ." 63 not coded yet" ; 101 | : opc-64 ( TODO ) ." 64 not coded yet" ; 102 | : opc-65 ( TODO ) ." 65 not coded yet" ; 103 | : opc-66 ( TODO ) ." 66 not coded yet" ; 104 | : opc-67 ( TODO ) ." 67 not coded yet" ; 105 | : opc-68 ( TODO ) ." 68 not coded yet" ; 106 | : opc-69 ( TODO ) ." 69 not coded yet" ; 107 | : opc-6A ( TODO ) ." 6A not coded yet" ; 108 | : opc-6B ( TODO ) ." 6B not coded yet" ; 109 | : opc-6C ( TODO ) ." 6C not coded yet" ; 110 | : opc-6D ( TODO ) ." 6D not coded yet" ; 111 | : opc-6E ( TODO ) ." 6E not coded yet" ; 112 | : opc-6F ( TODO ) ." 6F not coded yet" ; 113 | : opc-70 ( TODO ) ." 70 not coded yet" ; 114 | : opc-71 ( TODO ) ." 71 not coded yet" ; 115 | : opc-72 ( TODO ) ." 72 not coded yet" ; 116 | : opc-73 ( TODO ) ." 73 not coded yet" ; 117 | : opc-74 ( TODO ) ." 74 not coded yet" ; 118 | : opc-75 ( TODO ) ." 75 not coded yet" ; 119 | : opc-76 ( TODO ) ." 76 not coded yet" ; 120 | : opc-77 ( TODO ) ." 77 not coded yet" ; 121 | : opc-78 ( TODO ) ." 78 not coded yet" ; 122 | : opc-79 ( TODO ) ." 79 not coded yet" ; 123 | : opc-7A ( TODO ) ." 7A not coded yet" ; 124 | : opc-7B ( TODO ) ." 7B not coded yet" ; 125 | : opc-7C ( TODO ) ." 7C not coded yet" ; 126 | : opc-7D ( TODO ) ." 7D not coded yet" ; 127 | : opc-7E ( TODO ) ." 7E not coded yet" ; 128 | : opc-7F ( TODO ) ." 7F not coded yet" ; 129 | : opc-80 ( TODO ) ." 80 not coded yet" ; 130 | : opc-81 ( TODO ) ." 81 not coded yet" ; 131 | : opc-82 ( TODO ) ." 82 not coded yet" ; 132 | : opc-83 ( TODO ) ." 83 not coded yet" ; 133 | : opc-84 ( TODO ) ." 84 not coded yet" ; 134 | : opc-85 ( TODO ) ." 85 not coded yet" ; 135 | : opc-86 ( TODO ) ." 86 not coded yet" ; 136 | : opc-87 ( TODO ) ." 87 not coded yet" ; 137 | : opc-88 ( TODO ) ." 88 not coded yet" ; 138 | : opc-89 ( TODO ) ." 89 not coded yet" ; 139 | : opc-8A ( TODO ) ." 8A not coded yet" ; 140 | : opc-8B ( TODO ) ." 8B not coded yet" ; 141 | : opc-8C ( TODO ) ." 8C not coded yet" ; 142 | : opc-8D ( TODO ) ." 8D not coded yet" ; 143 | : opc-8E ( TODO ) ." 8E not coded yet" ; 144 | : opc-8F ( TODO ) ." 8F not coded yet" ; 145 | : opc-90 ( TODO ) ." 90 not coded yet" ; 146 | : opc-91 ( TODO ) ." 91 not coded yet" ; 147 | : opc-92 ( TODO ) ." 92 not coded yet" ; 148 | : opc-93 ( TODO ) ." 93 not coded yet" ; 149 | : opc-94 ( TODO ) ." 94 not coded yet" ; 150 | : opc-95 ( TODO ) ." 95 not coded yet" ; 151 | : opc-96 ( TODO ) ." 96 not coded yet" ; 152 | : opc-97 ( TODO ) ." 97 not coded yet" ; 153 | : opc-98 ( TODO ) ." 98 not coded yet" ; 154 | : opc-99 ( TODO ) ." 99 not coded yet" ; 155 | : opc-9A ( TODO ) ." 9A not coded yet" ; 156 | : opc-9B ( TODO ) ." 9B not coded yet" ; 157 | : opc-9C ( TODO ) ." 9C not coded yet" ; 158 | : opc-9D ( TODO ) ." 9D not coded yet" ; 159 | : opc-9E ( TODO ) ." 9E not coded yet" ; 160 | : opc-9F ( TODO ) ." 9F not coded yet" ; 161 | : opc-A0 ( TODO ) ." A0 not coded yet" ; 162 | : opc-A1 ( TODO ) ." A1 not coded yet" ; 163 | : opc-A2 ( TODO ) ." A2 not coded yet" ; 164 | : opc-A3 ( TODO ) ." A3 not coded yet" ; 165 | : opc-A4 ( TODO ) ." A4 not coded yet" ; 166 | : opc-A5 ( TODO ) ." A5 not coded yet" ; 167 | : opc-A6 ( TODO ) ." A6 not coded yet" ; 168 | : opc-A7 ( TODO ) ." A7 not coded yet" ; 169 | : opc-A8 ( TODO ) ." A8 not coded yet" ; 170 | : opc-A9 ( TODO ) ." A9 not coded yet" ; 171 | : opc-AA ( TODO ) ." AA not coded yet" ; 172 | : opc-AB ( TODO ) ." AB not coded yet" ; 173 | : opc-AC ( TODO ) ." AC not coded yet" ; 174 | : opc-AD ( TODO ) ." AD not coded yet" ; 175 | : opc-AE ( TODO ) ." AE not coded yet" ; 176 | : opc-AF ( TODO ) ." AF not coded yet" ; 177 | : opc-B0 ( TODO ) ." B0 not coded yet" ; 178 | : opc-B1 ( TODO ) ." B1 not coded yet" ; 179 | : opc-B2 ( TODO ) ." B2 not coded yet" ; 180 | : opc-B3 ( TODO ) ." B3 not coded yet" ; 181 | : opc-B4 ( TODO ) ." B4 not coded yet" ; 182 | : opc-B5 ( TODO ) ." B5 not coded yet" ; 183 | : opc-B6 ( TODO ) ." B6 not coded yet" ; 184 | : opc-B7 ( TODO ) ." B7 not coded yet" ; 185 | : opc-B8 ( TODO ) ." B8 not coded yet" ; 186 | : opc-B9 ( TODO ) ." B9 not coded yet" ; 187 | : opc-BA ( TODO ) ." BA not coded yet" ; 188 | : opc-BB ( TODO ) ." BB not coded yet" ; 189 | : opc-BC ( TODO ) ." BC not coded yet" ; 190 | : opc-BD ( TODO ) ." BD not coded yet" ; 191 | : opc-BE ( TODO ) ." BE not coded yet" ; 192 | : opc-BF ( TODO ) ." BF not coded yet" ; 193 | : opc-C0 ( TODO ) ." C0 not coded yet" ; 194 | : opc-C1 ( TODO ) ." C1 not coded yet" ; 195 | : opc-C2 ( TODO ) ." C2 not coded yet" ; 196 | : opc-C3 ( TODO ) ." C3 not coded yet" ; 197 | : opc-C4 ( TODO ) ." C4 not coded yet" ; 198 | : opc-C5 ( TODO ) ." C5 not coded yet" ; 199 | : opc-C6 ( TODO ) ." C6 not coded yet" ; 200 | : opc-C7 ( TODO ) ." C7 not coded yet" ; 201 | : opc-C8 ( TODO ) ." C8 not coded yet" ; 202 | : opc-C9 ( TODO ) ." C9 not coded yet" ; 203 | : opc-CA ( TODO ) ." CA not coded yet" ; 204 | : opc-CB ( TODO ) ." CB not coded yet" ; 205 | : opc-CC ( TODO ) ." CC not coded yet" ; 206 | : opc-CD ( TODO ) ." CD not coded yet" ; 207 | : opc-CE ( TODO ) ." CE not coded yet" ; 208 | : opc-CF ( TODO ) ." CF not coded yet" ; 209 | : opc-D0 ( TODO ) ." D0 not coded yet" ; 210 | : opc-D1 ( TODO ) ." D1 not coded yet" ; 211 | : opc-D2 ( TODO ) ." D2 not coded yet" ; 212 | : opc-D3 ( TODO ) ." D3 not coded yet" ; 213 | : opc-D4 ( TODO ) ." D4 not coded yet" ; 214 | : opc-D5 ( TODO ) ." D5 not coded yet" ; 215 | : opc-D6 ( TODO ) ." D6 not coded yet" ; 216 | : opc-D7 ( TODO ) ." D7 not coded yet" ; 217 | : opc-D8 ( TODO ) ." D8 not coded yet" ; 218 | : opc-D9 ( TODO ) ." D9 not coded yet" ; 219 | : opc-DA ( TODO ) ." DA not coded yet" ; 220 | : opc-DB ( TODO ) ." DB not coded yet" ; 221 | : opc-DC ( TODO ) ." DC not coded yet" ; 222 | : opc-DD ( TODO ) ." DD not coded yet" ; 223 | : opc-DE ( TODO ) ." DE not coded yet" ; 224 | : opc-DF ( TODO ) ." DF not coded yet" ; 225 | : opc-E0 ( TODO ) ." E0 not coded yet" ; 226 | : opc-E1 ( TODO ) ." E1 not coded yet" ; 227 | : opc-E2 ( TODO ) ." E2 not coded yet" ; 228 | : opc-E3 ( TODO ) ." E3 not coded yet" ; 229 | : opc-E4 ( TODO ) ." E4 not coded yet" ; 230 | : opc-E5 ( TODO ) ." E5 not coded yet" ; 231 | : opc-E6 ( TODO ) ." E6 not coded yet" ; 232 | : opc-E7 ( TODO ) ." E7 not coded yet" ; 233 | : opc-E8 ( TODO ) ." E8 not coded yet" ; 234 | : opc-E9 ( TODO ) ." E9 not coded yet" ; 235 | : opc-EA ( TODO ) ." EA not coded yet" ; 236 | : opc-EB ( TODO ) ." EB not coded yet" ; 237 | : opc-EC ( TODO ) ." EC not coded yet" ; 238 | : opc-ED ( TODO ) ." ED not coded yet" ; 239 | : opc-EE ( TODO ) ." EE not coded yet" ; 240 | : opc-EF ( TODO ) ." EF not coded yet" ; 241 | : opc-F0 ( TODO ) ." F0 not coded yet" ; 242 | : opc-F1 ( TODO ) ." F1 not coded yet" ; 243 | : opc-F2 ( TODO ) ." F2 not coded yet" ; 244 | : opc-F3 ( TODO ) ." F3 not coded yet" ; 245 | : opc-F4 ( TODO ) ." F4 not coded yet" ; 246 | : opc-F5 ( TODO ) ." F5 not coded yet" ; 247 | : opc-F6 ( TODO ) ." F6 not coded yet" ; 248 | : opc-F7 ( TODO ) ." F7 not coded yet" ; 249 | : opc-F8 ( TODO ) ." F8 not coded yet" ; 250 | : opc-F9 ( TODO ) ." F9 not coded yet" ; 251 | : opc-FA ( TODO ) ." FA not coded yet" ; 252 | : opc-FB ( TODO ) ." FB not coded yet" ; 253 | : opc-FC ( TODO ) ." FC not coded yet" ; 254 | : opc-FD ( TODO ) ." FD not coded yet" ; 255 | : opc-FE ( TODO ) ." FE not coded yet" ; 256 | : opc-FF ( TODO ) ." FF not coded yet" ; 257 | -------------------------------------------------------------------------------- /tools/testrom.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scotws/crude65816/e11a3a3fc99d0be33485eef5aa91181a526d11cb/tools/testrom.bin --------------------------------------------------------------------------------