diff --git a/6502code/Makefile b/6502code/Makefile index 774dea7..59ada88 100644 --- a/6502code/Makefile +++ b/6502code/Makefile @@ -2,7 +2,7 @@ CA=ca65 LD=ld65 OBJCOPY=arm-none-eabi-objcopy -all: supermon.o figforth uchess ehbasic +all: supermon.o figforth uchess ehbasic wozmon clean: rm -f *.o *.lst *.bin bin nullmem @@ -16,7 +16,7 @@ clean: rm -f bin nullmem echo;echo -voodoo_probably_isnt_ready: voodooloader.o +voodoo: voodooloader.o $(CA) -o voodoo.o voodooloader.a $(LD) -t none voodoo.o -o bin dd if=/dev/zero bs=64k count=1 >nullmem @@ -28,14 +28,14 @@ voodoo_probably_isnt_ready: voodooloader.o gpascal_isnt_ready: ca65 gpascal-mini.a - ld65 -o gpascal.bin -t none -S 50688 gpascal-mini.o + $(LD) -o gpascal.bin -t none -S 50688 gpascal-mini.o rm -f gpascal.o $(OBJCOPY) -I binary -O elf32-littlearm -B arm gpascal.bin gpascal.o echo "Not working yet...";echo;echo figforth: $(CA) -l figforth.a - ld65 -o figforth.bin -t none -S 512 figforth.o + $(LD) -o figforth.bin -t none -S 512 figforth.o rm -f figforth.o dd if=/dev/zero bs=64k count=1 >nullmem dd nullmem dd nullmem dd nullmem + dd LAB_SMSG ; point to sign-on message (high addr) JSR LAB_18C3 ; print null terminated string from memory + lda #$4C + sta LAB_WARM LDA #LAB_1274 ; warm start vector high byte STA Wrmjpl ; save warm start vector low byte diff --git a/6502code/figforth.a b/6502code/figforth.a index 10691bf..0e21dfe 100644 --- a/6502code/figforth.a +++ b/6502code/figforth.a @@ -1,9 +1,5 @@ ;;; -*- mode: asm -*- -;;; FIG-FORTH is in the Public Domain. - -;;; Remember the 1980s? When people charged you up to $400 (in 1980s -;;; dollars!) to compensate their Hard Work at editing maybe ~200 -;;; lines of existing source code? +; XEMIT, XKEY, XQTER, XCR, AND RSLW .setcpu "6502" .feature labels_without_colons diff --git a/6502code/supermon.a b/6502code/supermon.a index 674aca0..60ac150 100644 --- a/6502code/supermon.a +++ b/6502code/supermon.a @@ -1,13 +1,11 @@ ;;; -*- asm -*- -;;; SuperMON - by Jim Butterfield. +.feature labels_without_colons ;;; -;;; Believed to be free to distribute and modify, as this was -;;; happening with Jim's permission while he was alive. +;;; SuperMON 64 ;;; -;;; Modified to suit the stm6502 simulator by Chris Baird -;;; May 2012 - -.feature labels_without_colons +;;; Original source code courtesy Jim Butterfield +;;; +;;; load/save routines removed.. pch = $01 ;these must remain in order pcl = $02 diff --git a/6502code/uchess.a b/6502code/uchess.a index cda77bf..6e2d419 100644 --- a/6502code/uchess.a +++ b/6502code/uchess.a @@ -18,8 +18,8 @@ ; Additional code by Lee Davidson, Darryl Richter and Ken Wessen ; Source formatted for KRUSADER - the Replica 1 Assembler -; modified for the SYM1 and the ca65 crossassembler --cjb20100909 -; ca65 symuchess.asm && ld65 -t none symuchess.o && mv a.out symchess.bin +;;; modified for the SYM1 and the ca65 crossassembler --cjb20100909 +;;; ca65 symuchess.asm && ld65 -t none symuchess.o && mv a.out symchess.bin .feature labels_without_colons diff --git a/6502code/voodooloader.a b/6502code/voodooloader.a new file mode 100644 index 0000000..a9acdc0 --- /dev/null +++ b/6502code/voodooloader.a @@ -0,0 +1,152 @@ +;;; -*- asm -*- + + GAME = 32592 + SERIALPORT = $FFF0 + CUR_OUT_DEV = $BA + + .org $F000 + +RESET: sei + cld + ldx #$FF + txs + + lda #3 + sta CUR_OUT_DEV + lda #80 + sta $75E0 ;adventure engine screen width + + inx +loop: lda patchtable,x + beq gogame + tay + inx + lda patchtable,x + sta $ff00,y + inx + lda patchtable,x + sta $ff01,y + inx + lda patchtable,x + sta $ff02,y + inx + bne loop + +gogame: jmp GAME + +;;; ---------------------------------------------------------------------- + +NULL: rts + +CHROUT: pha + ;; check what the output device currently is.. + lda CUR_OUT_DEV + cmp #3 + bne chro1 + pla + pha + ;; convert petscii to ascii + and #127 + cmp #'a' + bcc out1 + sbc #32 + bne doout +out1: cmp #'Z' + bcs out2 + cmp #'A' + bcc out2 + adc #31 + bne doout +out2: cmp #127 + bne doout + lda #$63 + +doout: sta SERIALPORT +chro1: pla + rts + +GETIN: lda SERIALPORT + rts + +;;; this sets the default output device for CHROUT; ignore everything +;;; when .X isn't 3 (the screen). The Adams Adventure games also open +;;; the rs232 device to a Votrax type and talk + +CHKOUT: stx CUR_OUT_DEV + rts + + +;;; ---------------------------------------------------------------------- + +NONMI: lda #'N' + sta SERIALPORT + lda #'M' + sta SERIALPORT + lda #'I' + sta SERIALPORT +hang: jmp hang + +DOBRK: pha + txa + pha + tya + pha + tsx + lda $0104,x ;look in status to see if BRK flag set + and #%00010000 + beq isbrk + +isirq: + lda #'I' + sta SERIALPORT + lda #'R' + sta SERIALPORT + lda #'Q' + sta SERIALPORT + + pla + tay + pla + tax + pla + rti + ;bne hang + +isbrk: lda #'B' + sta SERIALPORT + lda #'R' + sta SERIALPORT + lda #'K' + sta SERIALPORT + bne hang + +;;; ---------------------------------------------------------------------- + +patchtable: + .byte $BA ;$FFBA = SETLFS + jmp NULL + .byte $BD ;$FFBD = SETNAM + jmp NULL + .byte $C0 ;$FFC0 = OPEN + jmp NULL + .byte $C9 ;$FFC9 = CHKOUT + jmp CHKOUT + .byte $D2 ;$FFD2 = CHROUT + jmp CHROUT + .byte $D5 ;$FFD5 = LOAD + jmp NULL + .byte $D8 ;$FFD8 = SAVE + jmp NULL + .byte $E4 ;$FFE4 = GETIN + jmp GETIN + .byte 0 + +;;; ---------------------------------------------------------------------- + + .org $FFFA + + .word NONMI + .word RESET + .word DOBRK + +;;; ---------------------------------------------------------------------- diff --git a/LICENCE b/LICENCE index c913a36..94a9ed0 100644 --- a/LICENCE +++ b/LICENCE @@ -1,2 +1,674 @@ -It's be nice if there was one. I'm still waiting on word from the -origin repo owner on what his unlabelled code is under. -cjb + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..2aaaa42 --- /dev/null +++ b/Makefile @@ -0,0 +1,46 @@ +# Makefile -- project building without any of that newfangled IDE +# mucking about. +# Copyright (C) 2012 Chris J. Baird +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see + + +CC=arm-none-eabi-gcc +LDSCRIPT=linker.ld +INCS=/usr/local/arm-none-eabi/include +LIBS=/usr/local/arm-none-eabi/lib/thumb2 + +CFLAGS=-O3 -g -std=gnu99 -fno-common -Wall +ARCHFLAGS=-mcpu=cortex-m4 -mtune=cortex-m4 -mthumb -march=armv7-m + +OBJS=addressing_modes.o cpu.o init_6502.o instructions.o main.o opcodes.o vm.o usart.o rom.o +SRCS=addressing_modes.c cpu.c init_6502.c instructions.c main.c opcodes.c vm.c usart.c rom.s +PROG=stm6502 + +all: $(OBJS) + $(CC) $(ARCHFLAGS) -o $(PROG).elf $(OBJS) \ + -lopencm3_stm32f4 -lc -lnosys \ + -L$(LIBS) -L$(LIBS)/stm32/f4 \ + -T$(LDSCRIPT) -nostartfiles -Wl,--gc-sections + +clean: + rm -f *.o *.elf *.d + +.s.o: + $(CC) $(CFLAGS) $(ARCHFLAGS) -o $@ -c $< + +.c.o: + $(CC) $(CFLAGS) $(ARCHFLAGS) \ + -DSTM32F4 -I. -I$(INCS) \ + -o $@ -c $< diff --git a/README b/README index c9c7e10..bb0500d 100644 --- a/README +++ b/README @@ -1,53 +1,61 @@ -stm6502 is a (currently NMOS) 6502 CPU simulator for the -STMicroelectronics STM32F4-Discovery evalutation board, a neat little -product with a 168MHz Cortex-M4 processor, 128 kB of RAM, and 1 MB of -Flash rom... for under $20. (See your favourite electronics retailer -and http://www.st.com/internet/evalboard/product/252419.jsp for more -details.) And unlike that Tivo-ized PIC32 rubbish, you can hack on it -with a wholly free development system on a wholly GNU system, without -Corporate wankers having final control on what you do. +A basic 6502 CPU simulator for the STM32F4-Discovery evaluation board. *** Prerequisites -To get yourself up and going on the Disco, you'll first need to install: +To run this, you will need: - https://github.com/esden/summon-arm-toolchain - https://github.com/texane/stlink - http://libopencm3.org - cc65.org's cc65 + A STM32F4-Discovery (I bought mine for just under $20 from + au.element14.com, aka Farnell, aka Newark.) -As of early May 2012, you will also need a RS232 level converter with -breakout connectiors (...the USB cdcacm code isn't ready yet.) + A rs232 level converter with breakout connectors + +...and install the software from: + + https://github.com/esden/summon-arm-toolchain + + https://github.com/texane/stlink + + http://libopencm3.org + +The source code for this project (and a lot of other junk) is available +from http://kildall.apana.org.au/~cjb/stm32/ + +This is a OMG INFECTED GPL V3 licenced system, based on software from: + + https://github.com/charliesome/6502 (although heavily modified) + + Jim Butterfield's supermon (via + http://www.ffd2.com/fridge/programs/supermon.s) *** Getting started Connect the rs232 level converter's Tx line to the Disco's PA2 GPIO pin, the Rx to PA3, and its ground to a GND (and possibly Vcc as -well). Set up a terminal program to 115200 baud 8N1. On my system, I -find it easiest to do this in another window: +well). Set up a terminal program to 115200 baud 8N1. On my GNU +development system, I find it easiest to do this in another window: - cu -l ttyUSB0 -115200 --nostop -e -o + cu -l ttyUSB0 -115200 --nostop -e -o -Start up stlink's st-util (as root): +Start up stlink's st-util: - /usr/src/stlink/gdbserver/st-util fu bar + /usr/src/stlink/gdbserver/st-util fu bar Use arm-*-gdb to load the stm6502.elf file into the Disco: - $ arm-none-eabi-gdb - gdb> load stm6502.elf - (I usually have to press 'reset' on the Disco at this point - for the next command to work consistently) - gdb> run + $ arm-none-eabi-gdb + gdb> load stm6502.elf + (I usually have to press 'reset' on the Disco at this point + for the next command to work consistently) + gdb> run ..and then over in your terminal program, you should see a happy -little 6502 system waiting for you or your code-downloading scripts. -For code development, I find it easiest to have an RFC2217 server -controlling the serial port, and then using a Python script to blast -supermon ":xxxx xx xx xx xx xx" lines down the connection-- it is also -convienent to load memory directly with gdb if being used -("load 6502code/figforth.o 0x20000000"), provided the binary can be -munged into the correct object format-- see the 6502code/Makefile. +little ~2.5MHz 6502 system waiting for you or your code-downloading +scripts. For code development, I find it easiest to have an RFC2217 +server controlling the serial port, and then using a Python script to +blast supermon ":xxxx xx xx xx xx xx" lines down the connection-- it +is also convienent to load memory with gdb if being used ("load +6502code/figforth.o 0x20000000"), provided the binary can be munged +into the correct object format. Once the STM32F4 board is programmed, it will just need to be powered through its main USB connection to start up the 6502 system. @@ -55,13 +63,10 @@ through its main USB connection to start up the 6502 system. *** Simulated 6502 notes The system comes up with 64kB of pure unrefined RAM, with a hacked -copy of Jim Butterfield's supermon copied in from $F800, although that -can be overwritten later. Character output is written to $FFF0, and -input by reading the same address. There are no other devices at this -point, although mass storage on SD Cards is something I'm looking at. - -The intention (of my branch, at least) is to have a generic 6502 -system to test code on, not to simulate any particular hardware. +copy of Jim Butterfield's supermon copied in from $F800. Character +output is written to $FFF0, and input by reading the same address. +There are no other devices at this point, although mass storage +on SD Cards is something I'm looking at. -- Chris Baird,, diff --git a/addressing_modes.c b/addressing_modes.c index 43ce4d5..9510a77 100644 --- a/addressing_modes.c +++ b/addressing_modes.c @@ -1,100 +1,175 @@ -#include -#include -#include +// addressing_modes.c -- involving the various virtual cpu instruction +// addressing modes. +// Copyright (C) 2012 Chris J. Baird +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see + +// derived from unlicenced/BSD-2clause code by Charlie Somerville +// https://github.com/charliesome/6502 + +#include +#include "addressing_modes.h" +#include "vm.h" +#include "cpu.h" + ADDRMODE(implied) { - return 0; + return 0; } + ADDRMODE(imm8) { - return vm_next_8(cpu); + return vm_next_8(cpu); } -ADDRMODE(imm16) // also works for jmp's absolute addressing + +ADDRMODE(imm16) { - return vm_next_16(cpu); + return vm_next_16(cpu); } + ADDRMODE(relative) { - signed char offset = (signed char)vm_next_8(cpu); - return cpu->regs.pc + offset; + signed char offset = (signed char)vm_next_8(cpu); + return cpu->regs.pc + offset; } + ADDRMODE(abs) { - return vm_next_16(cpu); + return vm_next_16(cpu); } + ADDRMODE(abs_deref) { - return cpu_peek(cpu, vm_next_16(cpu)); + return cpu_peek(cpu, vm_next_16(cpu)); } + ADDRMODE(absx) { - return vm_next_16(cpu) + cpu->regs.x; + return vm_next_16(cpu) + cpu->regs.x; } + ADDRMODE(absx_deref) { - return cpu_peek(cpu, vm_next_16(cpu) + cpu->regs.x); + return cpu_peek(cpu, vm_next_16(cpu) + cpu->regs.x); } + ADDRMODE(absy) { - return vm_next_16(cpu) + cpu->regs.y; + return vm_next_16(cpu) + cpu->regs.y; } + ADDRMODE(absy_deref) { - return cpu_peek(cpu, vm_next_16(cpu) + cpu->regs.y); + return cpu_peek(cpu, vm_next_16(cpu) + cpu->regs.y); } + ADDRMODE(zp) { - return vm_next_8(cpu); + return vm_next_8(cpu); } + ADDRMODE(zp_deref) { - return cpu_peek(cpu, vm_next_8(cpu)); + return cpu_peek(cpu, vm_next_8(cpu)); } + ADDRMODE(zpx) { - return (vm_next_8(cpu) + (cpu->regs.x & 255)) & 255; + return (vm_next_8(cpu) + (cpu->regs.x & 255)) & 255; } + ADDRMODE(zpx_deref) { - return cpu_peek(cpu, (vm_next_8(cpu) + (cpu->regs.x & 255)) & 255); + return cpu_peek(cpu, (vm_next_8(cpu) + (cpu->regs.x & 255)) & 255); +} + + +ADDRMODE(zpy) +{ + return (vm_next_8(cpu) + (cpu->regs.y & 255)) & 255; +} + + +ADDRMODE(zpy_deref) +{ + return cpu_peek(cpu, (vm_next_8(cpu) + (cpu->regs.y & 255)) & 255); } + ADDRMODE(indirect) { - return cpu_peek_16(cpu, vm_next_16(cpu)); + unsigned short dest = cpu_peek_16(cpu, vm_next_16(cpu)); + + if ((dest & 255) == 0xFF) + { + printf("\n** Indirect JMP to address $%04x\n*** CPU halted\n", dest); + while (1) + ; + } + return dest; } + ADDRMODE(indy) { - return cpu_peek_16(cpu, vm_next_8(cpu)) + cpu->regs.y; + return cpu_peek_16(cpu, vm_next_8(cpu)) + cpu->regs.y; } + ADDRMODE(indy_deref) { - return cpu_peek(cpu, cpu_peek_16(cpu, vm_next_8(cpu)) + cpu->regs.y); + return cpu_peek(cpu, cpu_peek_16(cpu, vm_next_8(cpu)) + cpu->regs.y); } + ADDRMODE(indx) { - return cpu_peek_16(cpu, vm_next_8(cpu) + cpu->regs.x); + unsigned char fa; + unsigned short ret; + + fa = vm_next_8(cpu); + ret = cpu_peek_16(cpu, fa + cpu->regs.x); + //printf ("pc=%04X sta($%02X,X=%02X)=%04X A=%02X\n", + // cpu->regs.pc,fa,cpu->regs.x,ret,cpu->regs.a); + return ret; } + ADDRMODE(indx_deref) { - return cpu_peek(cpu, cpu_peek_16(cpu, vm_next_8(cpu) + cpu->regs.x)); + unsigned char fa; + cpu_t *ret; + unsigned short addr; + + fa = vm_next_8(cpu); + addr = cpu_peek_16(cpu, fa + cpu->regs.x); + ret = cpu_peek_16(cpu, addr); + //printf ("pc=%04X ld($%02X,X=%02X)=%04X\n",cpu->regs.pc,fa,cpu->regs.x,addr); + return ret; } diff --git a/addressing_modes.h b/addressing_modes.h index 8307af0..a744355 100644 --- a/addressing_modes.h +++ b/addressing_modes.h @@ -1,30 +1,51 @@ +// addressing_modes.h -- addressing_modes.c public declarations and defines. +// Copyright (C) 2012 Chris J. Baird +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see + +// derived from unlicenced/BSD-2clause code by Charlie Somerville +// https://github.com/charliesome/6502 + #ifndef ADDRESSING_MODES_H #define ADDRESSING_MODES_H -#include +#include "cpu.h" typedef unsigned short(*addrmode_t)(cpu_t*); #define ADDRMODE(mode) unsigned short addrmode_##mode(cpu_t* cpu) -ADDRMODE(implied); -ADDRMODE(imm8); -ADDRMODE(imm16); -ADDRMODE(relative); -ADDRMODE(abs); -ADDRMODE(abs_deref); -ADDRMODE(absx); -ADDRMODE(absx_deref); -ADDRMODE(absy); -ADDRMODE(absy_deref); -ADDRMODE(zp); -ADDRMODE(zp_deref); -ADDRMODE(zpx); -ADDRMODE(zpx_deref); -ADDRMODE(indirect); -ADDRMODE(indy); -ADDRMODE(indy_deref); -ADDRMODE(indx); -ADDRMODE(indx_deref); +ADDRMODE(implied); /* Accumulator, etc */ +ADDRMODE(imm8); /* Immediate */ +ADDRMODE(imm16); /* #$xxxx (jmp) */ +ADDRMODE(relative); /* branches */ +ADDRMODE(abs); /* Absolute (jsr) .. how is this different from imm16? */ +ADDRMODE(abs_deref); /* Absolute (value from) */ +ADDRMODE(absx); /* Absoulte,x WRITE */ +ADDRMODE(absx_deref); /* Absolute,x READ */ +ADDRMODE(absy); /* Absolute,y WRITE */ +ADDRMODE(absy_deref); /* Absolute,y READ ONLY */ +ADDRMODE(zp); /* Zero Page WRITE */ +ADDRMODE(zp_deref); /* Zero Page READ ONLY */ +ADDRMODE(zpx); /* Zero Page,x WRITED */ +ADDRMODE(zpx_deref); /* Zero Page,x READ ONLY */ +ADDRMODE(zpy); /* Zero Page,y WRITED */ +ADDRMODE(zpy_deref); /* Zero Page,y READ ONLY */ +ADDRMODE(indirect); /* jmp Indirect */ +ADDRMODE(indy); /* (Indirect),y WRITE */ +ADDRMODE(indy_deref); /* (Indirect),y READONLY */ +ADDRMODE(indx); /* (Indirect,x) WRITE */ +ADDRMODE(indx_deref); /* (Indirect,x) READONLY */ -#endif +#endif /* ADDRESSING_MODES_H */ diff --git a/config.h b/config.h new file mode 100644 index 0000000..ad928fd --- /dev/null +++ b/config.h @@ -0,0 +1,34 @@ +// config.h -- compile-time feature options for when it gets that far.. +// Copyright (C) 2012 Chris J. Baird +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see + +// derived from unlicenced/BSD-2clause code by Charlie Somerville +// https://github.com/charliesome/6502 + +#ifndef CONFIG_H +#define CONFIG_H + +// select one of the following +#define USE_USART 1 +#undef USE_USB_CDCACM + +// this might happen one day too.. +#define CPU_6502 +#undef CPU_65C02 +#undef CPU_65SC02 +#undef CPU_M740 /* Mitsubitshi 740, M50734, embedded controllers */ +#undef CPU_65CJB02 /* "..." */ + +#endif /* CONFIG_H */ diff --git a/cpu.c b/cpu.c index f69534e..4d73372 100644 --- a/cpu.c +++ b/cpu.c @@ -1,127 +1,139 @@ +// cpu.c -- memory access routines for the stm6502 virtual cpu. +// Copyright (C) 2012 Chris J. Baird +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see + +// derived from unlicenced/BSD-2clause code by Charlie Somerville +// https://github.com/charliesome/6502 + + #include #include +#include "cpu.h" + + +// The real address of the 6502 core memory in the F4's address space. +// Possibly could be relocated to the DMA area? +unsigned char *rawmemory=0x20000000; -#include cpu_t* new_cpu() { - cpu_t* cpu = (cpu_t*)calloc(1, sizeof(cpu_t)); - cpu->mem = (unsigned char*)calloc(1, 65536); - cpu->regs.sp = 255; - return cpu; + cpu_t* cpu = (cpu_t*)calloc(1, sizeof(cpu_t)); + cpu->mem = rawmemory; + cpu->regs.sp = 255; + return cpu; } -void free_cpu(cpu_t* cpu) -{ - free(cpu->mem); - free(cpu); -} -void cpu_push_8(cpu_t* cpu, unsigned char val) +inline void cpu_push_8(cpu_t* cpu, unsigned char val) { - cpu_poke(cpu, 256 + cpu->regs.sp, val); - cpu->regs.sp--; + cpu->mem[256 + cpu->regs.sp] = val; + cpu->regs.sp--; } + + void cpu_push_16(cpu_t* cpu, unsigned short val) { - cpu_push_8(cpu, (val >> 8) & 255); - cpu_push_8(cpu, val & 255); + cpu_push_8(cpu, (val >> 8) & 255); + cpu_push_8(cpu, val & 255); } -unsigned char cpu_pop_8(cpu_t* cpu) + +inline unsigned char cpu_pop_8(cpu_t* cpu) { - cpu->regs.sp++; - return cpu_peek(cpu, 256 + cpu->regs.sp); + cpu->regs.sp++; + return cpu->mem[256 + cpu->regs.sp]; } + + unsigned short cpu_pop_16(cpu_t* cpu) { - unsigned char lsb = cpu_pop_8(cpu); - unsigned char msb = cpu_pop_8(cpu); + unsigned char lsb = cpu_pop_8(cpu); + unsigned char msb = cpu_pop_8(cpu); - return msb << 8 | lsb; + return msb << 8 | lsb; } + void cpu_nmi(cpu_t* cpu) { - cpu_push_16(cpu, cpu->regs.pc); - cpu_push_8(cpu, cpu->regs.flags | FPUSHED); + cpu_push_16(cpu, cpu->regs.pc); + cpu_push_8(cpu, cpu->regs.flags); - cpu->regs.pc = cpu_peek(cpu, 0xFFFA) | (cpu_peek(cpu, 0xFFFB) << 8); + cpu->regs.pc = cpu->mem[0xFFFA] | (cpu->mem[0xFFFB] << 8); } + void cpu_rst(cpu_t* cpu) { - cpu_push_16(cpu, cpu->regs.pc); - cpu_push_8(cpu, cpu->regs.flags | FPUSHED); + cpu_push_16(cpu, cpu->regs.pc); + cpu_push_8(cpu, cpu->regs.flags); - cpu->regs.pc = cpu_peek(cpu, 0xFFFC) | (cpu_peek(cpu, 0xFFFD) << 8); + cpu->regs.pc = cpu->mem[0xFFFC] | (cpu->mem[0xFFFD] << 8); } + void cpu_brk(cpu_t* cpu) { - if(GET_FLAG(cpu, FNOBRK)) - return; - - cpu_push_16(cpu, cpu->regs.pc); - cpu_push_8(cpu, cpu->regs.flags | FPUSHED | FBRK); - - cpu->regs.pc = cpu_peek(cpu, 0xFFFE) | (cpu_peek(cpu, 0xFFFF) << 8); + cpu_push_16(cpu, cpu->regs.pc); + cpu_push_8(cpu, cpu->regs.flags | FBRK); + cpu->regs.pc = cpu->mem[0xFFFE] | (cpu->mem[0xFFFF] << 8); } + void cpu_mmap(cpu_t* cpu, mmapseg_t* segment) { - mmapseg_t* new_segment = (mmapseg_t*)malloc(sizeof(mmapseg_t)); - memcpy(new_segment, segment, sizeof(mmapseg_t)); - - new_segment->next = NULL; - - if(cpu->mmapped_chain_tail != NULL) - cpu->mmapped_chain_tail->next = new_segment; - - if(cpu->mmapped_chain_head == NULL) - cpu->mmapped_chain_head = new_segment; - - cpu->mmapped_chain_tail = new_segment; + mmapseg_t* new_segment = (mmapseg_t*)malloc(sizeof(mmapseg_t)); + + memcpy(new_segment, segment, sizeof(mmapseg_t)); + + new_segment->next = NULL; + + if(cpu->mmapped_chain_tail != NULL) + cpu->mmapped_chain_tail->next = new_segment; + + if(cpu->mmapped_chain_head == NULL) + cpu->mmapped_chain_head = new_segment; + + cpu->mmapped_chain_tail = new_segment; } + unsigned char cpu_peek(cpu_t* cpu, unsigned short address) { - for(mmapseg_t* node = cpu->mmapped_chain_head; node != NULL; node = node->next) - { - if(node->address <= address && node->address + node->length > address) - { - return node->get(cpu, node->state, address); - } - } - - return cpu->mem[address]; + if (address >= 0xFFF0) + for(mmapseg_t* node = cpu->mmapped_chain_head; node != NULL; node = node->next) + if(node->address <= address && node->address + node->length > address) + return node->get(cpu, address); + return cpu->mem[address]; } + void cpu_poke(cpu_t* cpu, unsigned short address, unsigned char val) { - for(mmapseg_t* node = cpu->mmapped_chain_head; node != NULL; node = node->next) - { - if(node->address <= address && node->address + node->length > address) - { - node->set(cpu, node->state, address, val); - return; - } - } - - cpu->mem[address] = val; + if (address >= 0xFFF0) + for(mmapseg_t* node = cpu->mmapped_chain_head; node != NULL; node = node->next) + if(node->address <= address && node->address + node->length > address) + return node->set(cpu, address, val); + cpu->mem[address] = val; } -unsigned short cpu_peek_16(cpu_t* cpu, unsigned short address) -{ - unsigned char lsb = cpu_peek(cpu, address); - unsigned char msb = cpu_peek(cpu, address + 1); - return msb << 8 | lsb; -} - -void cpu_poke_16(cpu_t* cpu, unsigned short address, unsigned short val) +inline unsigned short cpu_peek_16(cpu_t* cpu, unsigned short address) { - cpu_poke(cpu, address, val & 255); - cpu_poke(cpu, address + 1, val >> 8); + // calculating the 16bit address values won't involve the mmaps directly, + // so let's avoid cpu_peek().. + return cpu->mem[address] | (cpu->mem[address+1] << 8); } - diff --git a/cpu.h b/cpu.h index aa124dc..91d6351 100644 --- a/cpu.h +++ b/cpu.h @@ -1,77 +1,83 @@ +// cpu.h -- cpu.c public declarations and defines. +// Copyright (C) 2012 Chris J. Baird +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see + +// derived from unlicenced/BSD-2clause code by Charlie Somerville +// https://github.com/charliesome/6502 + + #ifndef CPU_H #define CPU_H -#define FCARRY 1 -#define FZERO 2 -#define FNOBRK 4 -#define FBCD 8 -#define FBRK 16 -#define FPUSHED 32 -#define FOFLOW 64 -#define FNEG 128 +#define FCARRY 1 /* "C" */ +#define FZERO 2 /* "Z" */ +#define FIRQ 4 /* "I" */ +#define FBCD 8 /* "D" */ +#define FBRK 16 /* "B" */ +#define FOFLOW 64 /* "V" */ +#define FNEG 128 /* "N" */ #define GET_FLAG(state,flag) ((state)->regs.flags & (flag)) #define SET_FLAG(state,flag) (state)->regs.flags |= (flag) #define CLEAR_FLAG(state,flag) (state)->regs.flags &= ~(flag); -#define FLAG_IF(state,flag,condition) if(condition) { SET_FLAG(state,flag); } else { CLEAR_FLAG(state,flag); } +#define FLAG_IF(state,flag,condition) \ + if(condition) { SET_FLAG(state,flag); } \ + else { CLEAR_FLAG(state,flag); } + typedef struct reg -{ - unsigned short pc; - unsigned char sp; - unsigned char a; - unsigned char x; - unsigned char y; - unsigned char flags; - +{ unsigned short pc; + unsigned char sp; + unsigned char a; + unsigned char x; + unsigned char y; + unsigned char flags; } reg_t; struct mmapseg; + typedef struct cpu -{ - unsigned char* mem; - reg_t regs; - - struct mmapseg* mmapped_chain_head; - struct mmapseg* mmapped_chain_tail; - +{ unsigned char* mem; + reg_t regs; + struct mmapseg* mmapped_chain_head; + struct mmapseg* mmapped_chain_tail; } cpu_t; -typedef struct mmapseg -{ - unsigned short address; - unsigned short length; - - void* state; - - unsigned char(*get)(cpu_t*, void*, unsigned short); - void(*set)(cpu_t*, void*, unsigned short, unsigned char); - struct mmapseg* next; - +typedef struct mmapseg +{ unsigned short address; + unsigned short length; + unsigned char(*get)(cpu_t*, unsigned short); + void(*set)(cpu_t*, unsigned short, unsigned char); + struct mmapseg* next; } mmapseg_t; -cpu_t* new_cpu(); -void free_cpu(cpu_t* cpu); - -void cpu_push_8(cpu_t* cpu, unsigned char val); -void cpu_push_16(cpu_t* cpu, unsigned short val); - -unsigned char cpu_pop_8(cpu_t* cpu); -unsigned short cpu_pop_16(cpu_t* cpu); - -void cpu_nmi(cpu_t* cpu); -void cpu_rst(cpu_t* cpu); -void cpu_brk(cpu_t* cpu); - -void cpu_mmap(cpu_t* cpu, mmapseg_t* segment); - -unsigned char cpu_peek(cpu_t* cpu, unsigned short address); -void cpu_poke(cpu_t* cpu, unsigned short address, unsigned char val); - -unsigned short cpu_peek_16(cpu_t* cpu, unsigned short address); -void cpu_poke_16(cpu_t* cpu, unsigned short address, unsigned short val); -#endif +cpu_t* new_cpu(); +void cpu_push_8(cpu_t* cpu, unsigned char val); +void cpu_push_16(cpu_t* cpu, unsigned short val); +unsigned char cpu_pop_8(cpu_t* cpu); +unsigned short cpu_pop_16(cpu_t* cpu); +void cpu_nmi(cpu_t* cpu); +void cpu_rst(cpu_t* cpu); +void cpu_brk(cpu_t* cpu); +void cpu_mmap(cpu_t* cpu, mmapseg_t* segment); +unsigned char cpu_peek(cpu_t* cpu, unsigned short address); +void cpu_poke(cpu_t* cpu, unsigned short address, unsigned char val); +unsigned short cpu_peek_16(cpu_t* cpu, unsigned short address); + +#endif /* CPU_H */ diff --git a/init_6502.c b/init_6502.c index 98da096..248f659 100644 --- a/init_6502.c +++ b/init_6502.c @@ -1,59 +1,54 @@ -#include -#include -#include -#include +// init_6502.c -- initalize the memory-mapped hooks for the virtual cpu +// Copyright (C) 2012 Chris J. Baird +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see -static void writeport_set(cpu_t* cpu, void*, unsigned short addr, unsigned char val); -static unsigned char writeport_get(cpu_t* cpu, void*, unsigned short addr); +// derived from unlicenced/BSD-2clause code by Charlie Somerville +// https://github.com/charliesome/6502 + + +#include "usart.h" +#include "init_6502.h" + + +static void writeport_set(cpu_t* cpu, unsigned short addr, unsigned char val); +static unsigned char readport_get(cpu_t* cpu, unsigned short addr); -static void readport_set(cpu_t* cpu, void*, unsigned short addr, unsigned char val); -static unsigned char readport_get(cpu_t* cpu, void*, unsigned short addr); void init_6502(cpu_t* cpu) { - cpu->regs.pc = 0xC000; - - mmapseg_t mmap = { - .address = 0xF001, - .length = 1, - .state = NULL, - .set = writeport_set, - .get = writeport_get, - }; - cpu_mmap(cpu, &mmap); - - mmap.address = 0xF004; - mmap.set = readport_set; - mmap.get = readport_get; - - cpu_mmap(cpu, &mmap); -} + mmapseg_t mmap; -static void writeport_set(cpu_t* cpu, void* state, unsigned short addr, unsigned char val) -{ - putchar(val); - fflush(stdout); + mmap.address = 0xFFF0; + mmap.length = 1; + mmap.set = writeport_set; + mmap.get = readport_get; + cpu_mmap(cpu, &mmap); } -static unsigned char writeport_get(cpu_t* cpu, void* state, unsigned short addr) + + +static void writeport_set(cpu_t* cpu, unsigned short addr, unsigned char val) { - printf("** Read from write-only port $F001\n"); - printf("** CPU halted\n"); - exit(1); + usart_putchar(val); + if (val == 13) /* this'll get in the way of xmodem.. */ + usart_putchar(10); } -static void readport_set(cpu_t* cpu, void* state, unsigned short addr, unsigned char val) + +static unsigned char readport_get(cpu_t* cpu, unsigned short addr) { - printf("** Write to read-only port $F004\n"); - printf("** CPU halted\n"); - exit(1); -} -static unsigned char readport_get(cpu_t* cpu, void* state, unsigned short addr) -{ - int c = getchar(); - - // tranlsate unix line feed to carriage return - commonly used by 6502 based computers - if(c == 0x0A) - c = 0x0D; - - return (unsigned char)c; + int c = usart_getchar(); + // translate unix line feed to carriage return - commonly used by 6502 based computers + return (unsigned char)(c == 10 ? 13 : c); } diff --git a/init_6502.h b/init_6502.h index 8101b66..6f041e6 100644 --- a/init_6502.h +++ b/init_6502.h @@ -1,7 +1,27 @@ +// init_6502.h -- public init_6502.c declarations +// Copyright (C) 2012 Chris J. Baird +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see + +// derived from unlicenced/BSD-2clause code by Charlie Somerville +// https://github.com/charliesome/6502 + + #ifndef INIT_6502_H #define INIT_6502_H -#include +#include "cpu.h" void init_6502(cpu_t* cpu); diff --git a/instructions.c b/instructions.c index 0d928e8..e028c39 100644 --- a/instructions.c +++ b/instructions.c @@ -1,390 +1,554 @@ -#include -#include +// instructions.c -- perform the virtual cpu instructions. +// Copyright (C) 2012 Chris J. Baird +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see + +// [Distantly] derived from unlicenced/BSD-2clause code by Charlie +// Somerville https://github.com/charliesome/6502 ..except that it +// works.. :P + + #include #include +#include "cpu.h" +#include "instructions.h" -INS(brk) + +INS(adc) { - cpu_brk(cpu); + if(!GET_FLAG(cpu, FBCD)) + { + unsigned short total; + unsigned char c; + int v; + + v = (char)cpu->regs.a + (char)param + (GET_FLAG(cpu, FCARRY) ? 1 : 0); + total = cpu->regs.a + (unsigned char)param + (GET_FLAG(cpu, FCARRY) ? 1 : 0); + c = total & 255; + FLAG_IF(cpu, FNEG, c & 128); + FLAG_IF(cpu, FOFLOW, ((c & 128) > 0) ^ (v < 0)); + FLAG_IF(cpu, FZERO, c == 0); + FLAG_IF(cpu, FCARRY, (total & 256) > 0); + cpu->regs.a = c; + } + else + { + printf("\nHALTING: bcd adc\n"); + while (1) + ; + } } -INS(lda) + +INS(and) { - cpu->regs.a = param & 255; + cpu->regs.a = cpu->regs.a & param; - FLAG_IF(cpu, FZERO, cpu->regs.a == 0); - FLAG_IF(cpu, FNEG, cpu->regs.a & 128); + FLAG_IF(cpu, FZERO, cpu->regs.a == 0); + FLAG_IF(cpu, FNEG, cpu->regs.a & 128); } -INS(ldx) + +INS(asl) { - cpu->regs.x = param & 255; + unsigned char val = cpu_peek(cpu, param); + FLAG_IF(cpu, FCARRY, val & 128); + val <<= 1; + FLAG_IF(cpu, FZERO, val == 0); + FLAG_IF(cpu, FNEG, val & 128); + cpu_poke(cpu, param, val); +} - FLAG_IF(cpu, FZERO, cpu->regs.x == 0); - FLAG_IF(cpu, FNEG, cpu->regs.x & 128); + +INS(asl_a) +{ + FLAG_IF(cpu, FCARRY, cpu->regs.a & 128); + cpu->regs.a <<= 1; + FLAG_IF(cpu, FZERO, cpu->regs.a == 0); + FLAG_IF(cpu, FNEG, cpu->regs.a & 128); } -INS(ldy) + +INS(bcc) { - cpu->regs.y = param & 255; + if(!GET_FLAG(cpu, FCARRY)) + cpu->regs.pc = param; +} + - FLAG_IF(cpu, FZERO, cpu->regs.y == 0); - FLAG_IF(cpu, FNEG, cpu->regs.y & 128); +INS(bcs) +{ + if(GET_FLAG(cpu, FCARRY)) + cpu->regs.pc = param; } -INS(rti) + +INS(beq) { - cpu->regs.flags = cpu_pop_8(cpu); - cpu->regs.pc = cpu_pop_16(cpu); + if(GET_FLAG(cpu, FZERO)) + cpu->regs.pc = param; } -INS(jmp) + +INS(bit) { - cpu->regs.pc = param; + unsigned char result = cpu->regs.a & param; + + FLAG_IF(cpu, FZERO, result == 0); + FLAG_IF(cpu, FOFLOW, param & 64); + FLAG_IF(cpu, FNEG, param & 128); + // printf ("PC=%04x Z=%d V=%d N=%d\n", + // cpu->regs.pc, GET_FLAG(cpu, FZERO),GET_FLAG(cpu, FOFLOW),GET_FLAG(cpu, FNEG)); } -INS(beq) + +INS(bmi) { - if(GET_FLAG(cpu, FZERO)) - cpu->regs.pc = param; + if(GET_FLAG(cpu, FNEG)) + cpu->regs.pc = param; } + INS(bne) { - if(!GET_FLAG(cpu, FZERO)) - cpu->regs.pc = param; + if(!GET_FLAG(cpu, FZERO)) + cpu->regs.pc = param; } -INS(bcc) + +INS(brk) { - if(!GET_FLAG(cpu, FCARRY)) - cpu->regs.pc = param; + cpu_brk(cpu); } -INS(bcs) + +INS(bpl) +{ + if(!GET_FLAG(cpu, FNEG)) + cpu->regs.pc = param; +} + + +INS(bvc) { - if(GET_FLAG(cpu, FCARRY)) - cpu->regs.pc = param; + if(!GET_FLAG(cpu, FOFLOW)) + cpu->regs.pc = param; } + INS(bvs) { - if(GET_FLAG(cpu, FOFLOW)) - cpu->regs.pc = param; + if(GET_FLAG(cpu, FOFLOW)) + cpu->regs.pc = param; } -INS(bmi) + +INS(clc) { - if(GET_FLAG(cpu, FNEG)) - cpu->regs.pc = param; + CLEAR_FLAG(cpu, FCARRY); } -INS(bpl) + +INS(cld) { - if(!GET_FLAG(cpu, FNEG)) - cpu->regs.pc = param; + CLEAR_FLAG(cpu, FBCD); } -INS(sta) + +INS(cli) { - cpu_poke(cpu, param, cpu->regs.a); + CLEAR_FLAG(cpu, FIRQ); } -INS(sty) + +INS(clv) { - cpu_poke(cpu, param, cpu->regs.y); + CLEAR_FLAG(cpu, FOFLOW); } -INS(stx) + +INS(cmp) { - cpu_poke(cpu, param, cpu->regs.x); + FLAG_IF(cpu, FCARRY, cpu->regs.a >= param); + FLAG_IF(cpu, FZERO, cpu->regs.a == param); + FLAG_IF(cpu, FNEG, (cpu->regs.a - param) & 128); + //FLAG_IF(cpu, FNEG, cpu->regs.a < param); } -INS(dex) + +INS(cpx) { - cpu->regs.x--; + FLAG_IF(cpu, FCARRY, cpu->regs.x >= param); + FLAG_IF(cpu, FZERO, cpu->regs.x == param); + FLAG_IF(cpu, FNEG, (cpu->regs.x - param) & 128); + //FLAG_IF(cpu, FNEG, cpu->regs.x < param); +} + - FLAG_IF(cpu, FZERO, cpu->regs.x == 0); - FLAG_IF(cpu, FNEG, cpu->regs.x & 128); +INS(cpy) +{ + FLAG_IF(cpu, FCARRY, cpu->regs.y >= param); + FLAG_IF(cpu, FZERO, cpu->regs.y == param); + FLAG_IF(cpu, FNEG, (cpu->regs.y - param) & 128); + //FLAG_IF(cpu, FNEG, cpu->regs.y < param); } + INS(dec) { - unsigned char val = cpu_peek(cpu, param) - 1; + unsigned char val = cpu_peek(cpu, param) - 1; - FLAG_IF(cpu, FZERO, val == 0); - FLAG_IF(cpu, FNEG, val & 128); + FLAG_IF(cpu, FZERO, val == 0); + FLAG_IF(cpu, FNEG, val & 128); - cpu_poke(cpu, param, val); + cpu_poke(cpu, param, val); } -INS(dey) + +INS(dex) { - cpu->regs.y--; + cpu->regs.x--; - FLAG_IF(cpu, FZERO, cpu->regs.y == 0); - FLAG_IF(cpu, FNEG, cpu->regs.y & 128); + FLAG_IF(cpu, FZERO, cpu->regs.x == 0); + FLAG_IF(cpu, FNEG, cpu->regs.x & 128); } -INS(inx) + +INS(dey) { - cpu->regs.x++; + cpu->regs.y--; - FLAG_IF(cpu, FZERO, cpu->regs.x == 0); - FLAG_IF(cpu, FNEG, cpu->regs.x & 128); + FLAG_IF(cpu, FZERO, cpu->regs.y == 0); + FLAG_IF(cpu, FNEG, cpu->regs.y & 128); } -INS(iny) + +INS(eor) { - cpu->regs.y++; + cpu->regs.a ^= (unsigned char)param; - FLAG_IF(cpu, FZERO, cpu->regs.y == 0); - FLAG_IF(cpu, FNEG, cpu->regs.y & 128); + FLAG_IF(cpu, FZERO, cpu->regs.a == 0); + FLAG_IF(cpu, FNEG, cpu->regs.a & 128); } + INS(inc) { - unsigned char n = cpu_peek(cpu, param) + 1; - cpu_poke(cpu, param, n); + unsigned char n = cpu_peek(cpu, param) + 1; - FLAG_IF(cpu, FZERO, n == 0); - FLAG_IF(cpu, FNEG, n & 128); + FLAG_IF(cpu, FZERO, n == 0); + FLAG_IF(cpu, FNEG, n & 128); + cpu_poke(cpu, param, n); } -INS(txa) + +INS(inx) { - cpu->regs.a = cpu->regs.x; + cpu->regs.x++; - FLAG_IF(cpu, FZERO, cpu->regs.a == 0); - FLAG_IF(cpu, FNEG, cpu->regs.a & 128); + FLAG_IF(cpu, FZERO, cpu->regs.x == 0); + FLAG_IF(cpu, FNEG, cpu->regs.x & 128); } -INS(tax) + +INS(iny) { - cpu->regs.x = cpu->regs.a; + cpu->regs.y++; - FLAG_IF(cpu, FZERO, cpu->regs.x == 0); - FLAG_IF(cpu, FNEG, cpu->regs.x & 128); + FLAG_IF(cpu, FZERO, cpu->regs.y == 0); + FLAG_IF(cpu, FNEG, cpu->regs.y & 128); } -INS(txs) + +INS(jsr) { - cpu->regs.sp = cpu->regs.x; + cpu_push_16(cpu, cpu->regs.pc - 1); + cpu->regs.pc = param; } -INS(tsx) + +INS(jmp) { - cpu->regs.x = cpu->regs.sp; + cpu->regs.pc = param; } -INS(tya) + +INS(lda) { - cpu->regs.a = cpu->regs.y; + cpu->regs.a = param & 255; + + FLAG_IF(cpu, FZERO, cpu->regs.a == 0); + FLAG_IF(cpu, FNEG, cpu->regs.a & 128); } -INS(tay) + +INS(ldx) { - cpu->regs.y = cpu->regs.a; + cpu->regs.x = param & 255; + + FLAG_IF(cpu, FZERO, cpu->regs.x == 0); + FLAG_IF(cpu, FNEG, cpu->regs.x & 128); } -INS(and) + +INS(ldy) { - cpu->regs.a = cpu->regs.a & param; + cpu->regs.y = param & 255; - FLAG_IF(cpu, FZERO, cpu->regs.a == 0); - FLAG_IF(cpu, FNEG, cpu->regs.a & 128); + FLAG_IF(cpu, FZERO, cpu->regs.y == 0); + FLAG_IF(cpu, FNEG, cpu->regs.y & 128); } -INS(cmp) + +INS(lsr) { - FLAG_IF(cpu, FCARRY, cpu->regs.a >= param); - FLAG_IF(cpu, FZERO, cpu->regs.a == param); - FLAG_IF(cpu, FNEG, cpu->regs.a & 128); + unsigned char val = cpu_peek(cpu, param); + FLAG_IF(cpu, FCARRY, val & 1); + val >>= 1; + FLAG_IF(cpu, FZERO, val == 0); + CLEAR_FLAG(cpu, FNEG); + cpu_poke(cpu, param, val); } -INS(cpx) + +INS(lsr_a) { - FLAG_IF(cpu, FCARRY, cpu->regs.x >= param); - FLAG_IF(cpu, FZERO, cpu->regs.x == param); - FLAG_IF(cpu, FNEG, cpu->regs.x & 128); + FLAG_IF(cpu, FCARRY, cpu->regs.a & 1); + cpu->regs.a >>= 1; + FLAG_IF(cpu, FZERO, cpu->regs.a == 0); + CLEAR_FLAG(cpu, FNEG); } -INS(cpy) + +INS(nop) { - FLAG_IF(cpu, FCARRY, cpu->regs.y >= param); - FLAG_IF(cpu, FZERO, cpu->regs.y == param); - FLAG_IF(cpu, FNEG, cpu->regs.y & 128); } -INS(nop) + +INS(ora) { + cpu->regs.a |= (unsigned char)param; + + FLAG_IF(cpu, FZERO, cpu->regs.a == 0); + FLAG_IF(cpu, FNEG, cpu->regs.a & 128); } -INS(adc) -{ - if(!GET_FLAG(cpu, FBCD)) - { - unsigned short total = cpu->regs.a + param + (GET_FLAG(cpu, FCARRY) ? 1 : 0); - - CLEAR_FLAG(cpu, FCARRY); - CLEAR_FLAG(cpu, FOFLOW); - CLEAR_FLAG(cpu, FNEG); - CLEAR_FLAG(cpu, FZERO); - - if(total > 255) - { - SET_FLAG(cpu, FOFLOW); - SET_FLAG(cpu, FCARRY); - - total &= 255; - } - - if(total == 0) - SET_FLAG(cpu, FZERO); - - if(total & 128) - SET_FLAG(cpu, FNEG); - - cpu->regs.a = (unsigned char)total; - } - else - { - fprintf(stderr, "bcd adc!\n"); - exit(1); - } + +INS(pha) +{ + cpu_push_8(cpu, cpu->regs.a); } -INS(sbc) + +INS(php) { - - if(!GET_FLAG(cpu, FBCD)) - { - unsigned short total = cpu->regs.a - param - (GET_FLAG(cpu, FCARRY) ? 0 : 1); - - CLEAR_FLAG(cpu, FCARRY); - CLEAR_FLAG(cpu, FOFLOW); - CLEAR_FLAG(cpu, FNEG); - CLEAR_FLAG(cpu, FZERO); - - if(total == 0) - { - SET_FLAG(cpu, FZERO); - SET_FLAG(cpu, FCARRY); - } - else if(total > 0) - SET_FLAG(cpu, FCARRY); - else - SET_FLAG(cpu, FOFLOW); - - if(total & 128) - SET_FLAG(cpu, FNEG); - - cpu->regs.a = total & 255; - } - else - { - fprintf(stderr, "bcd sbc! Flags: %x BCD Flag is %x\n", cpu->regs.flags, FBCD); - exit(1); - } + cpu_push_8(cpu, cpu->regs.flags); } -INS(jsr) + +INS(pla) { - cpu_push_16(cpu, cpu->regs.pc - 1); - cpu->regs.pc = param; + cpu->regs.a = cpu_pop_8(cpu); + FLAG_IF(cpu, FZERO, cpu->regs.a == 0); + FLAG_IF(cpu, FNEG, cpu->regs.a & 128); } -INS(rts) + +INS(plp) { - cpu->regs.pc = cpu_pop_16(cpu) + 1; + cpu->regs.flags = cpu_pop_8(cpu); } -INS(cld) + +INS(rol) { - CLEAR_FLAG(cpu, FBCD); + unsigned char c; + unsigned char val; + + c = (GET_FLAG(cpu, FCARRY) ? 1 : 0); + val = cpu_peek(cpu, param); + FLAG_IF(cpu, FCARRY, val & 128); + val <<= 1; + val += c; + FLAG_IF(cpu, FZERO, val == 0); + FLAG_IF(cpu, FNEG, val & 128); + cpu_poke(cpu, param, val); } -INS(clc) + +INS(rol_a) { - CLEAR_FLAG(cpu, FCARRY); + unsigned char c; + + c = (GET_FLAG(cpu, FCARRY) ? 1 : 0); + FLAG_IF(cpu, FCARRY, cpu->regs.a & 128); + cpu->regs.a <<= 1; + cpu->regs.a += c; + FLAG_IF(cpu, FZERO, cpu->regs.a == 0); + FLAG_IF(cpu, FNEG, cpu->regs.a & 128); } -INS(sec) + +INS(ror) { - SET_FLAG(cpu, FCARRY); + unsigned char c; + unsigned char val; + + c = (GET_FLAG(cpu, FCARRY) ? 128 : 0); + val = cpu_peek(cpu, param); + FLAG_IF(cpu, FCARRY, val & 1); + val >>= 1; + val += c; + FLAG_IF(cpu, FZERO, val == 0); + FLAG_IF(cpu, FNEG, c); + cpu_poke(cpu, param, val); } -INS(php) + +INS(ror_a) { - cpu_push_8(cpu, cpu->regs.flags | FPUSHED); + unsigned char c; + + c = (GET_FLAG(cpu, FCARRY) ? 128 : 0); + FLAG_IF(cpu, FCARRY, cpu->regs.a & 1); + cpu->regs.a >>= 1; + cpu->regs.a += c; + FLAG_IF(cpu, FZERO, cpu->regs.a == 0); + FLAG_IF(cpu, FNEG, c); } -INS(pha) + +INS(rti) { - cpu_push_8(cpu, cpu->regs.a); + cpu->regs.flags = cpu_pop_8(cpu); + cpu->regs.pc = cpu_pop_16(cpu); } -INS(pla) + +INS(rts) { - cpu->regs.a = cpu_pop_8(cpu); + cpu->regs.pc = cpu_pop_16(cpu) + 1; } -INS(plp) + +INS(sbc) { - cpu->regs.flags = cpu_pop_8(cpu); + + if(!GET_FLAG(cpu, FBCD)) + { + unsigned short total; + unsigned char c; + int v; + + /* 30+ attempts at getting this to work... ;_; -cjb */ + v = (char)cpu->regs.a - (char)param - (GET_FLAG(cpu, FCARRY) ? 0 : 1); + total = cpu->regs.a - param - (GET_FLAG(cpu, FCARRY) ? 0 : 1); + c = total & 255; + FLAG_IF(cpu, FOFLOW, ((c & 128) > 0) ^ ((v & 256) != 0) ); + FLAG_IF(cpu, FCARRY, total < 256); + FLAG_IF(cpu, FZERO, c == 0); + FLAG_IF(cpu, FNEG, c & 128); + cpu->regs.a = c; + } + else + { + printf("\nHALTING: bcd sbc\n"); + while (1) + ; + } } -INS(bit) + +INS(sec) { - unsigned char result = cpu->regs.a & param; + SET_FLAG(cpu, FCARRY); +} - FLAG_IF(cpu, FZERO, result == 0); - FLAG_IF(cpu, FOFLOW, result & 64); - FLAG_IF(cpu, FNEG, result & 128); + +INS(sed) +{ + SET_FLAG(cpu, FBCD); } -INS(lsr_a) + +INS(sei) { - FLAG_IF(cpu, FCARRY, cpu->regs.a & 1); - cpu->regs.a >>= 1; + SET_FLAG(cpu, FIRQ); } -INS(lsr) + +INS(sta) { - unsigned char val = cpu_peek(cpu, param); - FLAG_IF(cpu, FCARRY, val & 1); - val >>= 1; - cpu_poke(cpu, param, val); + cpu_poke(cpu, param, cpu->regs.a); } -INS(eor) + +INS(stx) { - cpu->regs.a ^= (unsigned char)param; + cpu_poke(cpu, param, cpu->regs.x); +} + - FLAG_IF(cpu, FZERO, cpu->regs.a == 0); - FLAG_IF(cpu, FNEG, cpu->regs.a & 128); +INS(sty) +{ + cpu_poke(cpu, param, cpu->regs.y); } -INS(asl_a) + +INS(tax) { - FLAG_IF(cpu, FCARRY, cpu->regs.a & 128); - cpu->regs.a <<= 1; + cpu->regs.x = cpu->regs.a; + + FLAG_IF(cpu, FZERO, cpu->regs.x == 0); + FLAG_IF(cpu, FNEG, cpu->regs.x & 128); } -INS(asl) + +INS(tsx) { - unsigned char val = cpu_peek(cpu, param); - FLAG_IF(cpu, FCARRY, val & 128); - val <<= 1; - cpu_poke(cpu, param, val); + cpu->regs.x = cpu->regs.sp; + FLAG_IF(cpu, FZERO, cpu->regs.x == 0); + FLAG_IF(cpu, FNEG, cpu->regs.x & 128); } -INS(ora) + +INS(txa) { - cpu->regs.a |= (unsigned char)param; - - FLAG_IF(cpu, FZERO, cpu->regs.a == 0); - FLAG_IF(cpu, FNEG, cpu->regs.a & 128); + cpu->regs.a = cpu->regs.x; + + FLAG_IF(cpu, FZERO, cpu->regs.a == 0); + FLAG_IF(cpu, FNEG, cpu->regs.a & 128); } +INS(txs) +{ + cpu->regs.sp = cpu->regs.x; +} + + +INS(tya) +{ + cpu->regs.a = cpu->regs.y; + FLAG_IF(cpu, FZERO, cpu->regs.a == 0); + FLAG_IF(cpu, FNEG, cpu->regs.a & 128); +} + + +INS(tay) +{ + cpu->regs.y = cpu->regs.a; + FLAG_IF(cpu, FZERO, cpu->regs.y == 0); + FLAG_IF(cpu, FNEG, cpu->regs.y & 128); +} diff --git a/instructions.h b/instructions.h index b9b19fe..f73382c 100644 --- a/instructions.h +++ b/instructions.h @@ -1,62 +1,92 @@ +// instructions.h -- declare everything in instructions.c, even if it +// doesn't quite look like it.. +// Copyright (C) 2012 Chris J. Baird +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see + +// derived from unlicenced/BSD-2clause code by Charlie Somerville +// https://github.com/charliesome/6502 + + #ifndef INSTRUCTIONS_H #define INSTRUCTIONS_H -#include +#include "cpu.h" typedef void(*ins_t)(cpu_t*, unsigned short); #define INS(name) void ins_##name(cpu_t* cpu, unsigned short param) -INS(brk); -INS(lda); -INS(ldy); -INS(ldx); -INS(rti); -INS(jmp); -INS(beq); -INS(bne); +INS(adc); +INS(and); +INS(asl); +INS(asl_a); INS(bcc); INS(bcs); -INS(bvs); +INS(beq); +INS(bit); INS(bmi); -INS(sta); -INS(sty); -INS(inx); -INS(inc); -INS(iny); -INS(txa); -INS(tax); -INS(and); +INS(bne); +INS(bpl); +INS(brk); +INS(bvc); +INS(bvs); +INS(clc); +INS(cld); +INS(cli); +INS(clv); INS(cmp); INS(cpx); INS(cpy); -INS(nop); -INS(adc); -INS(sbc); -INS(dey); -INS(dex); INS(dec); -INS(bpl); -INS(stx); -INS(txs); -INS(tsx); -INS(tya); -INS(tay); +INS(dex); +INS(dey); +INS(eor); +INS(inc); +INS(inx); +INS(iny); +INS(jmp); INS(jsr); -INS(rts); -INS(cld); -INS(clc); -INS(sec); -INS(php); +INS(lda); +INS(ldx); +INS(ldy); +INS(lsr); +INS(lsr_a); +INS(nop); +INS(ora); INS(pha); +INS(php); INS(pla); INS(plp); -INS(bit); -INS(lsr_a); -INS(lsr); -INS(eor); -INS(asl); -INS(asl_a); -INS(ora); +INS(rol); +INS(rol_a); +INS(ror); +INS(ror_a); +INS(rti); +INS(rts); +INS(sbc); +INS(sec); +INS(sed); +INS(sei); +INS(sta); +INS(stx); +INS(sty); +INS(tax); +INS(tay); +INS(tsx); +INS(txa); +INS(txs); +INS(tya); -#endif +#endif /* INSTRUCTIONS_H */ diff --git a/linker.ld b/linker.ld new file mode 100644 index 0000000..f6a4adb --- /dev/null +++ b/linker.ld @@ -0,0 +1,31 @@ +/* + * This file is part of the libopencm3 project. + * + * Copyright (C) 2009 Uwe Hermann + * Copyright (C) 2011 Stephen Caudle + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +/* Linker script for ST STM32F4DISCOVERY (STM32F407VG, 1024K flash, 128K RAM). */ + +/* Define memory regions. */ +MEMORY +{ + rom (rx) : ORIGIN = 0x08000000, LENGTH = 1024K + ram (rwx) : ORIGIN = 0x20010000, LENGTH = 64K /* first 64kB of sram reserved for the virtual cpu */ +} + +/* Include the common ld script. */ +INCLUDE libopencm3_stm32f4.ld diff --git a/main.c b/main.c index b6a6a23..2d6398e 100644 --- a/main.c +++ b/main.c @@ -1,83 +1,101 @@ +// main.c -- 6502 simulator startup and control main loop. +// Copyright (C) 2012 Chris J. Baird +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see + +// derived from unlicenced/BSD-2clause code by Charlie Somerville +// https://github.com/charliesome/6502 + + #include #include #include #include -#include -#include -#include -#include +#include "config.h" +#include "cpu.h" +#include "vm.h" +#include "init_6502.h" +#include "usart.h" +#include "rom.h" + -int send_rst = 0; -int debug_mode = 0; +int debug_mode = 0; /* protip: you can set this while running using gdb */ +int send_rst = 0; /* ..maybe this as well */ +// int restore_rom = 0; +int go_slow = 0; /* 1000000 typical for debugging */ -void sigint_handler(int n) +int main(void) { - send_rst = 1; -} + volatile unsigned int i; + unsigned char *m, *p; + unsigned short before_pc; -int main(int argc, char** argv) -{ - printf("\em"); +#if USE_USART + usart_init(); +#endif +#if USE_USB_CDCACM + usb_cdcacm_init(); +#endif - if(argc < 2) - { - fprintf(stderr, "Usage: ./6502 \n"); - return 1; - } + printf("\em\n\n*** STM32F4-Disco 6502 Simulator ***\n"); - if(argc > 2 && strcmp(argv[2], "-debug") == 0) - debug_mode = 1; + cpu_t* cpu = new_cpu(); + init_6502(cpu); - printf("** Loading image: %s... ", argv[1]); - FILE* img = fopen(argv[1], "r"); - if(img == NULL) - { - printf("failed.\n"); - return 1; - } + send_rst = 1; - cpu_t* cpu = new_cpu(); - fread(cpu->mem, 65536, 1, img); - fclose(img); + /* copy in the supermon 'rom' to the 6502 memory space */ + m = (unsigned char *)0x2000F800; + p = (unsigned char *)&ROM_F800; + while (p < (unsigned char *)&ROM_F800_END) + *m++ = *p++; + /* set up the 6502 RESET vector */ + m = (unsigned char *)0x2000FFFC; + *m = 0x00; + m = (unsigned char *)0x2000FFFD; + *m = 0xF8; - printf("ok.\n"); - - init_6502(cpu); - signal(SIGINT, sigint_handler); + while (1) + { + if (send_rst) + { + cpu_rst(cpu); + send_rst = 0; + } - // unbuffer stdin - struct termios attr; - tcgetattr(0, &attr); - attr.c_lflag &= ~ICANON; - attr.c_lflag &= ~ECHO; - tcsetattr(0, TCSANOW, &attr); + vm_step(cpu); - while(1) + if(debug_mode) { - vm_step(cpu); - - if(send_rst) - { - // we can't call cpu_rst() directly from the signal handler, as a signal may fire mid-step. - cpu_rst(cpu); - send_rst = 0; - } - - if(debug_mode) - { - reg_t* r = &cpu->regs; - - printf( - // push current cursor position, and go to (1,1) - "\e[s\e[1;1H" - // white on red - "\e[1;37;41m" - // print out status info, like registers - " A: %02x X: %02x Y: %02x PC: $%04x SP: %02x Flags: %x" - // restore colour and pop cursor - "\e[m\e[u", r->a & 255, r->x & 255, r->y & 255, r->pc & 65535, r->sp & 255, r->flags & 255); - } + reg_t* r = &cpu->regs; + + printf ("PC_After:$%04x A:%02x X:%02x Y:%02x SP:01%02x " + "C%c Z%c N%c V%c I%c D%c B%c\n", + r->pc & 65535, r->a & 255, r->x & 255, r->y & 255, r->sp & 255, + (r->flags & FCARRY ? 49 : 48), + (r->flags & FZERO ? 49 : 48), + (r->flags & FNEG ? 49 : 48), + (r->flags & FOFLOW ? 49 : 48), + (r->flags & FIRQ ? 49 : 48), + (r->flags & FBCD ? 49 : 48), + (r->flags & FBRK ? 49 : 48)); } + + if (go_slow) + for (i = go_slow; i > 0; i--) + ; + } } diff --git a/opcodes.c b/opcodes.c index de486f3..1a75c8e 100644 --- a/opcodes.c +++ b/opcodes.c @@ -1,328 +1,282 @@ -#include -#include -#include -#include +// opcodes.c -- the virtual cpu instruction jump array +// Copyright (C) 2012 Chris J. Baird +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see + +// derived from unlicenced/BSD-2clause code by Charlie Somerville +// https://github.com/charliesome/6502 -void* opcodes[] = { - // 00 - OP(brk, imm8), - OP(ora, indx_deref), - ILLEGAL, - ILLEGAL, - // 04 - ILLEGAL, - OP(ora, zp_deref), - OP(asl, zp), - ILLEGAL, - // 08 - OP(php, implied), - OP(ora, imm8), - OP(asl_a, implied), - ILLEGAL, - // 0C - ILLEGAL, - OP(ora, abs_deref), - OP(asl, abs), - ILLEGAL, - // 10 - OP(bpl, relative), - OP(ora, indy_deref), - ILLEGAL, - ILLEGAL, - // 14 - ILLEGAL, - OP(ora, zpx_deref), - OP(asl, zpx), - ILLEGAL, - // 18 - OP(clc, implied), - OP(ora, absy_deref), - ILLEGAL, - ILLEGAL, - // 1C - ILLEGAL, - OP(ora, abs_deref), - OP(asl, absx), - ILLEGAL, - // 20 - OP(jsr, abs), - ILLEGAL, - ILLEGAL, - ILLEGAL, - // 24 - OP(bit, zp_deref), - ILLEGAL, - ILLEGAL, - ILLEGAL, - // 28 - OP(plp, implied), - OP(and, imm8), - ILLEGAL, - ILLEGAL, - // 2C - OP(bit, abs_deref), - ILLEGAL, - ILLEGAL, - ILLEGAL, - // 30 - OP(bmi, relative), - ILLEGAL, - ILLEGAL, - ILLEGAL, - // 34 - ILLEGAL, - ILLEGAL, - ILLEGAL, - ILLEGAL, - // 38 - OP(sec, implied), - ILLEGAL, - ILLEGAL, - ILLEGAL, - // 3C - ILLEGAL, - ILLEGAL, - ILLEGAL, - ILLEGAL, - // 40 - OP(rti, implied), - OP(eor, indx_deref), - ILLEGAL, - ILLEGAL, - // 44 - ILLEGAL, - OP(eor, zp_deref), - OP(lsr, zp), - ILLEGAL, - // 48 - OP(pha, implied), - OP(eor, imm8), - OP(lsr_a, implied), - ILLEGAL, - // 4C - OP(jmp, imm16), - OP(eor, abs_deref), - ILLEGAL, - ILLEGAL, - // 50 - ILLEGAL, - OP(eor, indy_deref), - ILLEGAL, - ILLEGAL, - // 54 - ILLEGAL, - OP(eor, zpx_deref), - ILLEGAL, - ILLEGAL, - // 58 - ILLEGAL, - OP(eor, absy_deref), - ILLEGAL, - ILLEGAL, - // 5C - ILLEGAL, - OP(eor, absx_deref), - ILLEGAL, - ILLEGAL, - // 60 - OP(rts, implied), - ILLEGAL, - ILLEGAL, - ILLEGAL, - // 64 - ILLEGAL, - OP(adc, zp_deref), - ILLEGAL, - ILLEGAL, - // 68 - OP(pla, implied), - OP(adc, imm8), - ILLEGAL, - ILLEGAL, - // 6C - OP(jmp, indirect), - ILLEGAL, - ILLEGAL, - ILLEGAL, - // 70 - OP(bvs, relative), - ILLEGAL, - ILLEGAL, - ILLEGAL, - // 74 - ILLEGAL, - ILLEGAL, - ILLEGAL, - ILLEGAL, - // 78 - ILLEGAL, - ILLEGAL, - ILLEGAL, - ILLEGAL, - // 7C - ILLEGAL, - ILLEGAL, - ILLEGAL, - ILLEGAL, - // 80 - ILLEGAL, - ILLEGAL, - ILLEGAL, - ILLEGAL, - // 84 - OP(sty, zp), - OP(sta, zp), - OP(stx, zp), - ILLEGAL, - // 88 - OP(dey, implied), - ILLEGAL, - OP(txa, implied), - ILLEGAL, - // 8C - ILLEGAL, - OP(sta, abs), - OP(stx, abs), - ILLEGAL, - // 90 - OP(bcc, relative), - OP(sta, indy), - ILLEGAL, - ILLEGAL, - // 94 - OP(sty, zpx), - OP(sta, zpx), - ILLEGAL, - ILLEGAL, - // 98 - OP(tya, implied), - OP(sta, absy), - OP(txs, implied), - ILLEGAL, - // 9C - ILLEGAL, - OP(sta, absx), - ILLEGAL, - ILLEGAL, - // A0 - OP(ldy, imm8), - ILLEGAL, - OP(ldx, imm8), - ILLEGAL, - // A4 - OP(ldy, zp_deref), - OP(lda, zp_deref), - OP(ldx, zp_deref), - ILLEGAL, - // A8 - OP(tay, implied), - OP(lda, imm8), - OP(tax, implied), - ILLEGAL, - // AC - OP(ldy, abs_deref), - OP(lda, abs_deref), - ILLEGAL, - ILLEGAL, - // B0 - OP(bcs, relative), - OP(lda, indy_deref), - ILLEGAL, - ILLEGAL, - // B4 - OP(ldy, zpx_deref), - ILLEGAL, - ILLEGAL, - ILLEGAL, - // B8 - ILLEGAL, - OP(lda, absy_deref), - OP(tsx, implied), - ILLEGAL, - // BC - OP(ldy, absx_deref), - OP(lda, absx_deref), - ILLEGAL, - ILLEGAL, - // C0 - OP(cpy, imm8), - ILLEGAL, - ILLEGAL, - ILLEGAL, - // C4 - OP(cpy, zp_deref), - OP(cmp, zp_deref), - OP(dec, zp), - ILLEGAL, - // C8 - OP(iny, implied), - OP(cmp, imm8), - OP(dex, implied), - ILLEGAL, - // CC - ILLEGAL, - ILLEGAL, - OP(dec, abs), - ILLEGAL, - // D0 - OP(bne, relative), - OP(cmp, indy), - ILLEGAL, - ILLEGAL, - // D4 - ILLEGAL, - ILLEGAL, - OP(dec, zpx), - ILLEGAL, - // D8 - OP(cld, implied), - ILLEGAL, - ILLEGAL, - ILLEGAL, - // DC - ILLEGAL, - ILLEGAL, - OP(dec, absx), - ILLEGAL, - // E0 - OP(cpx, imm8), - ILLEGAL, - ILLEGAL, - ILLEGAL, - // E4 - OP(cpx, zp_deref), - OP(sbc, zp_deref), - OP(inc, zp), - ILLEGAL, - // E8 - OP(inx, implied), - OP(sbc, imm8), - OP(nop, implied), - ILLEGAL, - // EC - ILLEGAL, - ILLEGAL, - ILLEGAL, - ILLEGAL, - // F0 - OP(beq, relative), - ILLEGAL, - ILLEGAL, - ILLEGAL, - // F4 - ILLEGAL, - ILLEGAL, - ILLEGAL, - ILLEGAL, - // F8 - ILLEGAL, - ILLEGAL, - ILLEGAL, - ILLEGAL, - // FC - ILLEGAL, - ILLEGAL, - ILLEGAL, - ILLEGAL +#include "opcodes.h" +#include "addressing_modes.h" +#include "instructions.h" + +void* opcodes[] = { + /*00*/ OP(brk, imm8), /* I assume it's because of the NMOS cpu bug? */ + /*01*/ OP(ora, indx_deref), + /*02*/ ILLEGAL, + /*03*/ ILLEGAL, + /*04*/ ILLEGAL, + /*05*/ OP(ora, zp_deref), + /*06*/ OP(asl, zp), + /*07*/ ILLEGAL, + /*08*/ OP(php, implied), + /*09*/ OP(ora, imm8), + /*0A*/ OP(asl_a, implied), + /*0B*/ ILLEGAL, + /*0C*/ ILLEGAL, + /*0D*/ OP(ora, abs_deref), + /*0E*/ OP(asl, abs), + /*0F*/ ILLEGAL, + /*10*/ OP(bpl, relative), + /*11*/ OP(ora, indy_deref), + /*12*/ ILLEGAL, + /*13*/ ILLEGAL, + /*14*/ ILLEGAL, + /*15*/ OP(ora, zpx_deref), + /*16*/ OP(asl, zpx), + /*17*/ ILLEGAL, + /*18*/ OP(clc, implied), + /*19*/ OP(ora, absy_deref), + /*1A*/ ILLEGAL, + /*1B*/ ILLEGAL, + /*1C*/ ILLEGAL, + /*1D*/ OP(ora, absx_deref), + /*1E*/ OP(asl, absx), + /*1F*/ ILLEGAL, + /*20*/ OP(jsr, abs), + /*21*/ OP(and, indx_deref), + /*22*/ ILLEGAL, + /*23*/ ILLEGAL, + /*24*/ OP(bit, zp_deref), + /*25*/ OP(and, zp_deref), + /*26*/ OP(rol, zp), + /*27*/ ILLEGAL, + /*28*/ OP(plp, implied), + /*29*/ OP(and, imm8), + /*2A*/ OP(rol_a, implied), + /*2B*/ ILLEGAL, + /*2C*/ OP(bit, abs_deref), + /*2D*/ OP(and, abs_deref), + /*2E*/ OP(rol, abs), + /*2F*/ ILLEGAL, + /*30*/ OP(bmi, relative), + /*31*/ OP(and, indy_deref), + /*32*/ ILLEGAL, + /*33*/ ILLEGAL, + /*34*/ ILLEGAL, + /*35*/ OP(and, zpx_deref), + /*36*/ OP(rol, zpx), + /*37*/ ILLEGAL, + /*38*/ OP(sec, implied), + /*39*/ OP(and, absy_deref), + /*3A*/ ILLEGAL, + /*3B*/ ILLEGAL, + /*3C*/ ILLEGAL, + /*3D*/ OP(and, absx_deref), + /*3E*/ OP(rol, absx), + /*3F*/ ILLEGAL, + /*40*/ OP(rti, implied), + /*41*/ OP(eor, indx_deref), + /*42*/ ILLEGAL, + /*43*/ ILLEGAL, + /*44*/ ILLEGAL, + /*45*/ OP(eor, zp_deref), + /*46*/ OP(lsr, zp), + /*47*/ ILLEGAL, + /*48*/ OP(pha, implied), + /*49*/ OP(eor, imm8), + /*4A*/ OP(lsr_a, implied), + /*4B*/ ILLEGAL, + /*4C*/ OP(jmp, imm16), + /*4D*/ OP(eor, abs_deref), + /*4E*/ OP(lsr, abs), + /*4F*/ ILLEGAL, + /*50*/ OP(bvc, relative), + /*51*/ OP(eor, indy_deref), + /*52*/ ILLEGAL, + /*53*/ ILLEGAL, + /*54*/ ILLEGAL, + /*55*/ OP(eor, zpx_deref), + /*56*/ OP(lsr, zpx), + /*57*/ ILLEGAL, + /*58*/ OP(cli, implied), + /*59*/ OP(eor, absy_deref), + /*5A*/ ILLEGAL, + /*5B*/ ILLEGAL, + /*5C*/ ILLEGAL, + /*5D*/ OP(eor, absx_deref), + /*5E*/ OP(lsr, absx), + /*5F*/ ILLEGAL, + /*60*/ OP(rts, implied), + /*61*/ OP(adc, indx_deref), + /*62*/ ILLEGAL, + /*63*/ ILLEGAL, + /*64*/ ILLEGAL, + /*65*/ OP(adc, zp_deref), + /*66*/ OP(ror, zp), + /*67*/ ILLEGAL, + /*68*/ OP(pla, implied), + /*69*/ OP(adc, imm8), + /*6A*/ OP(ror_a, implied), + /*6B*/ ILLEGAL, + /*6C*/ OP(jmp, indirect), + /*6D*/ OP(adc, abs_deref), + /*6E*/ OP(ror, abs), + /*6F*/ ILLEGAL, + /*70*/ OP(bvs, relative), + /*71*/ OP(adc, indy_deref), + /*72*/ ILLEGAL, + /*73*/ ILLEGAL, + /*74*/ ILLEGAL, + /*75*/ OP(adc, zpx_deref), + /*76*/ OP(ror, zpx), + /*77*/ ILLEGAL, + /*78*/ OP(sei, implied), + /*79*/ OP(adc, absy_deref), + /*7A*/ ILLEGAL, + /*7B*/ ILLEGAL, + /*7C*/ ILLEGAL, + /*7D*/ OP(adc, absx_deref), + /*7E*/ OP(ror, absx), + /*7F*/ ILLEGAL, + /*80*/ ILLEGAL, + /*81*/ OP(sta, indx), + /*82*/ ILLEGAL, + /*83*/ ILLEGAL, + /*84*/ OP(sty, zp), + /*85*/ OP(sta, zp), + /*86*/ OP(stx, zp), + /*87*/ ILLEGAL, + /*88*/ OP(dey, implied), + /*89*/ ILLEGAL, + /*8A*/ OP(txa, implied), + /*8B*/ ILLEGAL, + /*8C*/ OP(sty, abs), + /*8D*/ OP(sta, abs), + /*8E*/ OP(stx, abs), + /*8F*/ ILLEGAL, + /*90*/ OP(bcc, relative), + /*91*/ OP(sta, indy), + /*92*/ ILLEGAL, + /*93*/ ILLEGAL, + /*94*/ OP(sty, zpx), + /*95*/ OP(sta, zpx), + /*96*/ OP(stx, zpy), + /*97*/ ILLEGAL, + /*98*/ OP(tya, implied), + /*99*/ OP(sta, absy), + /*9A*/ OP(txs, implied), + /*9B*/ ILLEGAL, + /*9C*/ ILLEGAL, + /*9D*/ OP(sta, absx), + /*9E*/ ILLEGAL, + /*9F*/ ILLEGAL, + /*A0*/ OP(ldy, imm8), + /*A1*/ OP(lda, indx_deref), + /*A2*/ OP(ldx, imm8), + /*A3*/ ILLEGAL, + /*A4*/ OP(ldy, zp_deref), + /*A5*/ OP(lda, zp_deref), + /*A6*/ OP(ldx, zp_deref), + /*A7*/ ILLEGAL, + /*A8*/ OP(tay, implied), + /*A9*/ OP(lda, imm8), + /*AA*/ OP(tax, implied), + /*AB*/ ILLEGAL, + /*AC*/ OP(ldy, abs_deref), + /*AD*/ OP(lda, abs_deref), + /*AE*/ OP(ldx, abs_deref), + /*AF*/ ILLEGAL, + /*B0*/ OP(bcs, relative), + /*B1*/ OP(lda, indy_deref), + /*B2*/ ILLEGAL, + /*B3*/ ILLEGAL, + /*B4*/ OP(ldy, zpx_deref), + /*B5*/ OP(lda, zpx_deref), + /*B6*/ OP(ldx, zpy_deref), + /*B7*/ ILLEGAL, + /*B8*/ OP(clv, implied), + /*B9*/ OP(lda, absy_deref), + /*BA*/ OP(tsx, implied), + /*BB*/ ILLEGAL, + /*BC*/ OP(ldy, absx_deref), + /*BD*/ OP(lda, absx_deref), + /*BE*/ OP(ldx, absy_deref), + /*BF*/ ILLEGAL, + /*C0*/ OP(cpy, imm8), + /*C1*/ OP(cmp, indx_deref), + /*C2*/ ILLEGAL, + /*C3*/ ILLEGAL, + /*C4*/ OP(cpy, zp_deref), + /*C5*/ OP(cmp, zp_deref), + /*C6*/ OP(dec, zp), + /*C7*/ ILLEGAL, + /*C8*/ OP(iny, implied), + /*C9*/ OP(cmp, imm8), + /*CA*/ OP(dex, implied), + /*CB*/ ILLEGAL, + /*CC*/ OP(cpy, abs_deref), + /*CD*/ OP(cmp, abs_deref), + /*CE*/ OP(dec, abs), + /*CF*/ ILLEGAL, + /*D0*/ OP(bne, relative), + /*D1*/ OP(cmp, indy_deref), + /*D2*/ ILLEGAL, + /*D3*/ ILLEGAL, + /*D4*/ ILLEGAL, + /*D5*/ OP(cmp, zpx_deref), + /*D6*/ OP(dec, zpx), + /*D7*/ ILLEGAL, + /*D8*/ OP(cld, implied), + /*D9*/ OP(cmp, absy_deref), + /*DA*/ ILLEGAL, + /*DB*/ ILLEGAL, + /*DC*/ ILLEGAL, + /*DD*/ OP(cmp, absx_deref), + /*DE*/ OP(dec, absx), + /*DF*/ ILLEGAL, + /*E0*/ OP(cpx, imm8), + /*E1*/ OP(sbc, indx_deref), + /*E2*/ ILLEGAL, + /*E3*/ ILLEGAL, + /*E4*/ OP(cpx, zp_deref), + /*E5*/ OP(sbc, zp_deref), + /*E6*/ OP(inc, zp), + /*E7*/ ILLEGAL, + /*E8*/ OP(inx, implied), + /*E9*/ OP(sbc, imm8), + /*EA*/ OP(nop, implied), + /*EB*/ ILLEGAL, + /*EC*/ OP(cpx, abs_deref), + /*ED*/ OP(sbc, abs_deref), + /*EE*/ OP(inc, abs), + /*EF*/ ILLEGAL, + /*F0*/ OP(beq, relative), + /*F1*/ OP(sbc, indy_deref), + /*F2*/ ILLEGAL, + /*F3*/ ILLEGAL, + /*F4*/ ILLEGAL, + /*F5*/ OP(sbc, zpx_deref), + /*F6*/ OP(inc, zpx), + /*F7*/ ILLEGAL, + /*F8*/ OP(sed, implied), + /*F9*/ OP(sbc, absy_deref), + /*FA*/ ILLEGAL, + /*FB*/ ILLEGAL, + /*FC*/ ILLEGAL, + /*FD*/ OP(sbc, absx_deref), + /*FE*/ OP(inc, absx), + /*FF*/ ILLEGAL }; diff --git a/opcodes.h b/opcodes.h index 3494ec5..0bd3e69 100644 --- a/opcodes.h +++ b/opcodes.h @@ -1,9 +1,29 @@ +// opcodes.h -- the virtual cpu instruction jump array defines +// Copyright (C) 2012 Chris J. Baird +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see + +// derived from unlicenced/BSD-2clause code by Charlie Somerville +// https://github.com/charliesome/6502 + + #ifndef OPCODES_H #define OPCODES_H #define OP(i,a) (ins_##i), (addrmode_##a) -#define ILLEGAL NULL, NULL +#define ILLEGAL (void *)0, (void*)0 extern void* opcodes[]; -#endif +#endif /* OPCODES_H */ diff --git a/rom.h b/rom.h new file mode 100644 index 0000000..c958fe1 --- /dev/null +++ b/rom.h @@ -0,0 +1,25 @@ +// rom.h -- address particulars for the included supermon binary loaded +// into the virtual cpu. +// Copyright (C) 2012 Chris J. Baird +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see + + +#ifndef ROM_H +#define ROM_H + +extern unsigned char *ROM_F800; /* from rom.s/supermon.bin */ +extern unsigned char *ROM_F800_END; + +#endif /* ROM_H */ diff --git a/rom.s b/rom.s new file mode 100644 index 0000000..d0d27d0 --- /dev/null +++ b/rom.s @@ -0,0 +1,8 @@ +.text +.global ROM_F800 +.global ROM_F800_END + +ROM_F800: +.incbin "supermon.bin" +ROM_F800_END: +.previous diff --git a/supermon.bin b/supermon.bin new file mode 100644 index 0000000..7902f08 Binary files /dev/null and b/supermon.bin differ diff --git a/usart.c b/usart.c new file mode 100644 index 0000000..877e727 --- /dev/null +++ b/usart.c @@ -0,0 +1,123 @@ +/* + * This file [was] part of the libopencm3 project. + * + * Copyright (C) 2010 Gareth McMullin + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +/* original code whittled-down to what I needed -cjb */ + + +#include "config.h" + +#ifdef USE_USART +#include +#include +#include +#include + +#include +#include +#include + +#include "usart.h" + + +void clock_setup(void) +{ + rcc_clock_setup_hse_3v3(&hse_8mhz_3v3[CLOCK_3V3_168MHZ]); + /* Enable GPIOD clock for LED & USARTs. */ + rcc_peripheral_enable_clock(&RCC_AHB1ENR, RCC_AHB1ENR_IOPDEN); + rcc_peripheral_enable_clock(&RCC_AHB1ENR, RCC_AHB1ENR_IOPAEN); + + /* Enable clocks for USART2. */ + rcc_peripheral_enable_clock(&RCC_APB1ENR, RCC_APB1ENR_USART2EN); +} + + +void usart_setup(void) +{ + /* Setup USART2 parameters. */ + usart_set_baudrate(USART2, 115200); + usart_set_databits(USART2, 8); + usart_set_stopbits(USART2, USART_STOPBITS_1); + usart_set_mode(USART2, USART_MODE_TX|USART_MODE_RX); + usart_set_parity(USART2, USART_PARITY_NONE); + usart_set_flow_control(USART2, USART_FLOWCONTROL_NONE); + + /* Finally enable the USART. */ + usart_enable(USART2); +} + + +void gpio_setup(void) +{ + /* Setup GPIO pins for USART2 transmit. */ + gpio_mode_setup(GPIOA, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO2|GPIO3); + + /* Setup USART2 TX pin as alternate function. */ + gpio_set_af(GPIOA, GPIO_AF7, GPIO2|GPIO3); +} + + +void usart_putchar(int c) +{ + usart_send_blocking(USART2,c); + if (c == '\n') + usart_send_blocking(USART2,'\r'); +} + + +int usart_getchar(void) +{ + return usart_recv_blocking(USART2); +} + + +void usart_putstr (char *str) +{ + char c; + + while ((c = *str++)) + usart_putchar(c); +} + + +/* the magic routine that gives us printf()... */ +int _write(int file, char *ptr, int len) +{ + int i; + + if ((file == 1) || (file == 2)) + { + for (i = 0; i < len; i++) + usart_putchar(ptr[i]); + return i; + } + errno = EIO; + return -1; +} + + +void usart_init(void) +{ + rcc_clock_setup_hse_3v3(&hse_8mhz_3v3[CLOCK_3V3_168MHZ]); + clock_setup(); + gpio_setup(); + usart_setup(); +} + + +#endif /* USE_USART */ diff --git a/usart.h b/usart.h new file mode 100644 index 0000000..b0c0759 --- /dev/null +++ b/usart.h @@ -0,0 +1,24 @@ +// usart.h -- public declarations for usart.c +// Copyright (C) 2012 Chris J. Baird +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see + + +void usart_init(void); +void usart_putchar(int c); +int usart_getchar(void); +void usart_putstr(char *str); + +/* + */ diff --git a/usb_cdcacm.c b/usb_cdcacm.c new file mode 100644 index 0000000..a1cffab --- /dev/null +++ b/usb_cdcacm.c @@ -0,0 +1,235 @@ +/* + * This file is part of the libopencm3 project. + * + * Copyright (C) 2010 Gareth McMullin + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +#include +#include +#include +#include +#include + +static const struct usb_device_descriptor dev = { + .bLength = USB_DT_DEVICE_SIZE, + .bDescriptorType = USB_DT_DEVICE, + .bcdUSB = 0x0200, + .bDeviceClass = USB_CLASS_CDC, + .bDeviceSubClass = 0, + .bDeviceProtocol = 0, + .bMaxPacketSize0 = 64, + .idVendor = 0x0483, + .idProduct = 0x5740, + .bcdDevice = 0x0200, + .iManufacturer = 1, + .iProduct = 2, + .iSerialNumber = 3, + .bNumConfigurations = 1, +}; + +/* + * This notification endpoint isn't implemented. According to CDC spec it's + * optional, but its absence causes a NULL pointer dereference in the + * Linux cdc_acm driver. + */ +static const struct usb_endpoint_descriptor comm_endp[] = {{ + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = 0x83, + .bmAttributes = USB_ENDPOINT_ATTR_INTERRUPT, + .wMaxPacketSize = 16, + .bInterval = 255, + }}; + +static const struct usb_endpoint_descriptor data_endp[] = {{ + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = 0x01, + .bmAttributes = USB_ENDPOINT_ATTR_BULK, + .wMaxPacketSize = 64, + .bInterval = 1, + }, { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = 0x82, + .bmAttributes = USB_ENDPOINT_ATTR_BULK, + .wMaxPacketSize = 64, + .bInterval = 1, + }}; + +static const struct { + struct usb_cdc_header_descriptor header; + struct usb_cdc_call_management_descriptor call_mgmt; + struct usb_cdc_acm_descriptor acm; + struct usb_cdc_union_descriptor cdc_union; +} __attribute__((packed)) cdcacm_functional_descriptors = { + .header = { + .bFunctionLength = sizeof(struct usb_cdc_header_descriptor), + .bDescriptorType = CS_INTERFACE, + .bDescriptorSubtype = USB_CDC_TYPE_HEADER, + .bcdCDC = 0x0110, + }, + .call_mgmt = { + .bFunctionLength = + sizeof(struct usb_cdc_call_management_descriptor), + .bDescriptorType = CS_INTERFACE, + .bDescriptorSubtype = USB_CDC_TYPE_CALL_MANAGEMENT, + .bmCapabilities = 0, + .bDataInterface = 1, + }, + .acm = { + .bFunctionLength = sizeof(struct usb_cdc_acm_descriptor), + .bDescriptorType = CS_INTERFACE, + .bDescriptorSubtype = USB_CDC_TYPE_ACM, + .bmCapabilities = 0, + }, + .cdc_union = { + .bFunctionLength = sizeof(struct usb_cdc_union_descriptor), + .bDescriptorType = CS_INTERFACE, + .bDescriptorSubtype = USB_CDC_TYPE_UNION, + .bControlInterface = 0, + .bSubordinateInterface0 = 1, + } +}; + +static const struct usb_interface_descriptor comm_iface[] = {{ + .bLength = USB_DT_INTERFACE_SIZE, + .bDescriptorType = USB_DT_INTERFACE, + .bInterfaceNumber = 0, + .bAlternateSetting = 0, + .bNumEndpoints = 1, + .bInterfaceClass = USB_CLASS_CDC, + .bInterfaceSubClass = USB_CDC_SUBCLASS_ACM, + .bInterfaceProtocol = USB_CDC_PROTOCOL_AT, + .iInterface = 0, + + .endpoint = comm_endp, + + .extra = &cdcacm_functional_descriptors, + .extralen = sizeof(cdcacm_functional_descriptors) + }}; + +static const struct usb_interface_descriptor data_iface[] = {{ + .bLength = USB_DT_INTERFACE_SIZE, + .bDescriptorType = USB_DT_INTERFACE, + .bInterfaceNumber = 1, + .bAlternateSetting = 0, + .bNumEndpoints = 2, + .bInterfaceClass = USB_CLASS_DATA, + .bInterfaceSubClass = 0, + .bInterfaceProtocol = 0, + .iInterface = 0, + + .endpoint = data_endp, + }}; + +static const struct usb_interface ifaces[] = {{ + .num_altsetting = 1, + .altsetting = comm_iface, + }, { + .num_altsetting = 1, + .altsetting = data_iface, + }}; + +static const struct usb_config_descriptor config = { + .bLength = USB_DT_CONFIGURATION_SIZE, + .bDescriptorType = USB_DT_CONFIGURATION, + .wTotalLength = 0, + .bNumInterfaces = 2, + .bConfigurationValue = 1, + .iConfiguration = 0, + .bmAttributes = 0x80, + .bMaxPower = 0x32, + + .interface = ifaces, +}; + +static const char *usb_strings[] = { + "x", + "World Wide Weasels", + "stm6502 Terminal", + "DEMO", +}; + +static int cdcacm_control_request(struct usb_setup_data *req, u8 **buf, u16 *len, + void (**complete)(struct usb_setup_data *req)) +{ + (void)complete; + (void)buf; + + switch (req->bRequest) { + case USB_CDC_REQ_SET_CONTROL_LINE_STATE: { + /* + * This Linux cdc_acm driver requires this to be implemented + * even though it's optional in the CDC spec, and we don't + * advertise it in the ACM functional descriptor. + */ + return 1; + } + case USB_CDC_REQ_SET_LINE_CODING: + if (*len < sizeof(struct usb_cdc_line_coding)) + return 0; + + return 1; + } + return 0; +} + +static void cdcacm_data_rx_cb(u8 ep) +{ + (void)ep; + + char buf[64]; + int len = usbd_ep_read_packet(0x01, buf, 64); + + if (len) + while (usbd_ep_write_packet(0x82, buf, len) == 0) + ; + + gpio_toggle(GPIOC, GPIO5); +} + +static void cdcacm_set_config(u16 wValue) +{ + (void)wValue; + + usbd_ep_setup(0x01, USB_ENDPOINT_ATTR_BULK, 64, cdcacm_data_rx_cb); + usbd_ep_setup(0x82, USB_ENDPOINT_ATTR_BULK, 64, NULL); + usbd_ep_setup(0x83, USB_ENDPOINT_ATTR_INTERRUPT, 16, NULL); + + usbd_register_control_callback( + USB_REQ_TYPE_CLASS | USB_REQ_TYPE_INTERFACE, + USB_REQ_TYPE_TYPE | USB_REQ_TYPE_RECIPIENT, + cdcacm_control_request); +} + +void usb_cdcacm_init(void); +{ + rcc_clock_setup_hse_3v3(&hse_8mhz_3v3[CLOCK_3V3_120MHZ]); + + rcc_peripheral_enable_clock(&RCC_AHB1ENR, RCC_AHB1ENR_IOPAEN); + rcc_peripheral_enable_clock(&RCC_AHB2ENR, RCC_AHB2ENR_OTGFSEN); + + gpio_mode_setup(GPIOA, GPIO_MODE_AF, GPIO_PUPD_NONE, + GPIO9 | GPIO11 | GPIO12); + gpio_set_af(GPIOA, GPIO_AF10, GPIO9 | GPIO11 | GPIO12); + + usbd_init(&otgfs_usb_driver, &dev, &config, usb_strings); + usbd_register_set_config_callback(cdcacm_set_config); + + while (1) + usbd_poll(); +} diff --git a/vm.c b/vm.c index ebe5590..12065b8 100644 --- a/vm.c +++ b/vm.c @@ -1,49 +1,60 @@ -#include -#include -#include +// vm.c -- dispatch the virtual cpu instructions +// Copyright (C) 2012 Chris J. Baird +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see + +// derived from unlicenced/BSD-2clause code by Charlie Somerville +// https://github.com/charliesome/6502 + + #include #include -#include -#include -#include +#include "cpu.h" +#include "vm.h" +#include "opcodes.h" +#include "instructions.h" +#include "addressing_modes.h" -unsigned char vm_next_8(cpu_t* cpu) + +inline unsigned char vm_next_8(cpu_t* cpu) { - return cpu_peek(cpu, cpu->regs.pc++); + return cpu_peek(cpu, cpu->regs.pc++); } -unsigned short vm_next_16(cpu_t* cpu) -{ - unsigned char lsb = vm_next_8(cpu); - unsigned char msb = vm_next_8(cpu); - return msb << 8 | lsb; -} +inline unsigned short vm_next_16(cpu_t* cpu) +{ + unsigned char lsb = vm_next_8(cpu); + unsigned char msb = vm_next_8(cpu); + return msb << 8 | lsb; +} void vm_step(cpu_t* cpu) -{ - unsigned short pc = cpu->regs.pc; - - unsigned char opcode = vm_next_8(cpu); - - addrmode_t addressing_mode = (addrmode_t)opcodes[opcode * 2 + 1]; - ins_t instruction = (ins_t)opcodes[opcode * 2]; - - if(addressing_mode == NULL || instruction == NULL) - { - fprintf(stderr, "** Illegal opcode: $%X at address $%x\n", opcode, pc); - fprintf(stderr, " A: %x\n X: %x\n Y: %x\n** CPU halted.\n", cpu->regs.a, cpu->regs.x, cpu->regs.y); - - // rebuffer stdin - struct termios attr; - tcgetattr(0, &attr); - attr.c_lflag &= ~ICANON; - attr.c_lflag &= ~ECHO; - tcsetattr(0, TCSANOW, &attr); - - exit(1); - } - - instruction(cpu, addressing_mode(cpu)); +{ + unsigned short pc = cpu->regs.pc; + unsigned char opcode = vm_next_8(cpu); + ins_t instruction = (ins_t)opcodes[opcode * 2]; + addrmode_t addressing_mode = (addrmode_t)opcodes[opcode * 2 + 1]; + + if (instruction == NULL) + { + printf("\n** Illegal opcode: $%X at address $%X\n*** CPU halted\n", + opcode, pc); + while (1) + ; + } + + instruction(cpu, addressing_mode(cpu)); } diff --git a/vm.h b/vm.h index be72214..ed0f4b1 100644 --- a/vm.h +++ b/vm.h @@ -1,10 +1,32 @@ +// vm.h -- what the rest of the code should know about vm.c +// Copyright (C) 2012 Chris J. Baird +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see + +// derived from unlicenced/BSD-2clause code by Charlie Somerville +// https://github.com/charliesome/6502 + + #ifndef VM_H #define VM_H -#include +#include "cpu.h" + void vm_step(cpu_t* cpu); unsigned char vm_next_8(cpu_t* cpu); unsigned short vm_next_16(cpu_t* cpu); -#endif + +#endif /* VM_H */