├── 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
--------------------------------------------------------------------------------