├── .gitignore
├── LICENSE
├── Makefile
├── README.md
├── cgb
└── picture.asm
├── data
├── font_8x8.chr
├── gbcyus.atr
├── gbcyus.bmp
├── gbcyus.chr
├── gbcyus.map
├── gbcyus.pal
├── gbhorror.bmp
├── gbhorror.chr
├── gbhorror.map
├── hlgbmcp.bmp
├── hlgbmcp.chr
├── hlgbmcp_bg.map
├── hlgbmcp_win.map
├── opti.bmp
├── opti.chr
├── opti.map
├── tsodki1.bmp
├── tsodki1.chr
├── tsodki1.map
├── tsodki2.bmp
├── tsodki2.chr
└── tsodki2.map
├── dmg
├── bg_scroll_x_y.asm
├── hello.asm
├── joypad.asm
├── large_picture.asm
├── meta_sprite.asm
├── picture.asm
├── score_bcd.asm
├── score_hex.asm
├── sprite.asm
├── sprite_collision.asm
├── timer_clock.asm
└── window.asm
├── inc
└── hardware.inc
└── make.cmd
/.gitignore:
--------------------------------------------------------------------------------
1 | *.gb
2 | *.gbc
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | GNU GENERAL PUBLIC LICENSE
2 | Version 3, 29 June 2007
3 |
4 | Copyright (C) 2007 Free Software Foundation, Inc.
5 | Everyone is permitted to copy and distribute verbatim copies
6 | of this license document, but changing it is not allowed.
7 |
8 | Preamble
9 |
10 | The GNU General Public License is a free, copyleft license for
11 | software and other kinds of works.
12 |
13 | The licenses for most software and other practical works are designed
14 | to take away your freedom to share and change the works. By contrast,
15 | the GNU General Public License is intended to guarantee your freedom to
16 | share and change all versions of a program--to make sure it remains free
17 | software for all its users. We, the Free Software Foundation, use the
18 | GNU General Public License for most of our software; it applies also to
19 | any other work released this way by its authors. You can apply it to
20 | your programs, too.
21 |
22 | When we speak of free software, we are referring to freedom, not
23 | price. Our General Public Licenses are designed to make sure that you
24 | have the freedom to distribute copies of free software (and charge for
25 | them if you wish), that you receive source code or can get it if you
26 | want it, that you can change the software or use pieces of it in new
27 | free programs, and that you know you can do these things.
28 |
29 | To protect your rights, we need to prevent others from denying you
30 | these rights or asking you to surrender the rights. Therefore, you have
31 | certain responsibilities if you distribute copies of the software, or if
32 | you modify it: responsibilities to respect the freedom of others.
33 |
34 | For example, if you distribute copies of such a program, whether
35 | gratis or for a fee, you must pass on to the recipients the same
36 | freedoms that you received. You must make sure that they, too, receive
37 | or can get the source code. And you must show them these terms so they
38 | know their rights.
39 |
40 | Developers that use the GNU GPL protect your rights with two steps:
41 | (1) assert copyright on the software, and (2) offer you this License
42 | giving you legal permission to copy, distribute and/or modify it.
43 |
44 | For the developers' and authors' protection, the GPL clearly explains
45 | that there is no warranty for this free software. For both users' and
46 | authors' sake, the GPL requires that modified versions be marked as
47 | changed, so that their problems will not be attributed erroneously to
48 | authors of previous versions.
49 |
50 | Some devices are designed to deny users access to install or run
51 | modified versions of the software inside them, although the manufacturer
52 | can do so. This is fundamentally incompatible with the aim of
53 | protecting users' freedom to change the software. The systematic
54 | pattern of such abuse occurs in the area of products for individuals to
55 | use, which is precisely where it is most unacceptable. Therefore, we
56 | have designed this version of the GPL to prohibit the practice for those
57 | products. If such problems arise substantially in other domains, we
58 | stand ready to extend this provision to those domains in future versions
59 | of the GPL, as needed to protect the freedom of users.
60 |
61 | Finally, every program is threatened constantly by software patents.
62 | States should not allow patents to restrict development and use of
63 | software on general-purpose computers, but in those that do, we wish to
64 | avoid the special danger that patents applied to a free program could
65 | make it effectively proprietary. To prevent this, the GPL assures that
66 | patents cannot be used to render the program non-free.
67 |
68 | The precise terms and conditions for copying, distribution and
69 | modification follow.
70 |
71 | TERMS AND CONDITIONS
72 |
73 | 0. Definitions.
74 |
75 | "This License" refers to version 3 of the GNU General Public License.
76 |
77 | "Copyright" also means copyright-like laws that apply to other kinds of
78 | works, such as semiconductor masks.
79 |
80 | "The Program" refers to any copyrightable work licensed under this
81 | License. Each licensee is addressed as "you". "Licensees" and
82 | "recipients" may be individuals or organizations.
83 |
84 | To "modify" a work means to copy from or adapt all or part of the work
85 | in a fashion requiring copyright permission, other than the making of an
86 | exact copy. The resulting work is called a "modified version" of the
87 | earlier work or a work "based on" the earlier work.
88 |
89 | A "covered work" means either the unmodified Program or a work based
90 | on the Program.
91 |
92 | To "propagate" a work means to do anything with it that, without
93 | permission, would make you directly or secondarily liable for
94 | infringement under applicable copyright law, except executing it on a
95 | computer or modifying a private copy. Propagation includes copying,
96 | distribution (with or without modification), making available to the
97 | public, and in some countries other activities as well.
98 |
99 | To "convey" a work means any kind of propagation that enables other
100 | parties to make or receive copies. Mere interaction with a user through
101 | a computer network, with no transfer of a copy, is not conveying.
102 |
103 | An interactive user interface displays "Appropriate Legal Notices"
104 | to the extent that it includes a convenient and prominently visible
105 | feature that (1) displays an appropriate copyright notice, and (2)
106 | tells the user that there is no warranty for the work (except to the
107 | extent that warranties are provided), that licensees may convey the
108 | work under this License, and how to view a copy of this License. If
109 | the interface presents a list of user commands or options, such as a
110 | menu, a prominent item in the list meets this criterion.
111 |
112 | 1. Source Code.
113 |
114 | The "source code" for a work means the preferred form of the work
115 | for making modifications to it. "Object code" means any non-source
116 | form of a work.
117 |
118 | A "Standard Interface" means an interface that either is an official
119 | standard defined by a recognized standards body, or, in the case of
120 | interfaces specified for a particular programming language, one that
121 | is widely used among developers working in that language.
122 |
123 | The "System Libraries" of an executable work include anything, other
124 | than the work as a whole, that (a) is included in the normal form of
125 | packaging a Major Component, but which is not part of that Major
126 | Component, and (b) serves only to enable use of the work with that
127 | Major Component, or to implement a Standard Interface for which an
128 | implementation is available to the public in source code form. A
129 | "Major Component", in this context, means a major essential component
130 | (kernel, window system, and so on) of the specific operating system
131 | (if any) on which the executable work runs, or a compiler used to
132 | produce the work, or an object code interpreter used to run it.
133 |
134 | The "Corresponding Source" for a work in object code form means all
135 | the source code needed to generate, install, and (for an executable
136 | work) run the object code and to modify the work, including scripts to
137 | control those activities. However, it does not include the work's
138 | System Libraries, or general-purpose tools or generally available free
139 | programs which are used unmodified in performing those activities but
140 | which are not part of the work. For example, Corresponding Source
141 | includes interface definition files associated with source files for
142 | the work, and the source code for shared libraries and dynamically
143 | linked subprograms that the work is specifically designed to require,
144 | such as by intimate data communication or control flow between those
145 | subprograms and other parts of the work.
146 |
147 | The Corresponding Source need not include anything that users
148 | can regenerate automatically from other parts of the Corresponding
149 | Source.
150 |
151 | The Corresponding Source for a work in source code form is that
152 | same work.
153 |
154 | 2. Basic Permissions.
155 |
156 | All rights granted under this License are granted for the term of
157 | copyright on the Program, and are irrevocable provided the stated
158 | conditions are met. This License explicitly affirms your unlimited
159 | permission to run the unmodified Program. The output from running a
160 | covered work is covered by this License only if the output, given its
161 | content, constitutes a covered work. This License acknowledges your
162 | rights of fair use or other equivalent, as provided by copyright law.
163 |
164 | You may make, run and propagate covered works that you do not
165 | convey, without conditions so long as your license otherwise remains
166 | in force. You may convey covered works to others for the sole purpose
167 | of having them make modifications exclusively for you, or provide you
168 | with facilities for running those works, provided that you comply with
169 | the terms of this License in conveying all material for which you do
170 | not control copyright. Those thus making or running the covered works
171 | for you must do so exclusively on your behalf, under your direction
172 | and control, on terms that prohibit them from making any copies of
173 | your copyrighted material outside their relationship with you.
174 |
175 | Conveying under any other circumstances is permitted solely under
176 | the conditions stated below. Sublicensing is not allowed; section 10
177 | makes it unnecessary.
178 |
179 | 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
180 |
181 | No covered work shall be deemed part of an effective technological
182 | measure under any applicable law fulfilling obligations under article
183 | 11 of the WIPO copyright treaty adopted on 20 December 1996, or
184 | similar laws prohibiting or restricting circumvention of such
185 | measures.
186 |
187 | When you convey a covered work, you waive any legal power to forbid
188 | circumvention of technological measures to the extent such circumvention
189 | is effected by exercising rights under this License with respect to
190 | the covered work, and you disclaim any intention to limit operation or
191 | modification of the work as a means of enforcing, against the work's
192 | users, your or third parties' legal rights to forbid circumvention of
193 | technological measures.
194 |
195 | 4. Conveying Verbatim Copies.
196 |
197 | You may convey verbatim copies of the Program's source code as you
198 | receive it, in any medium, provided that you conspicuously and
199 | appropriately publish on each copy an appropriate copyright notice;
200 | keep intact all notices stating that this License and any
201 | non-permissive terms added in accord with section 7 apply to the code;
202 | keep intact all notices of the absence of any warranty; and give all
203 | recipients a copy of this License along with the Program.
204 |
205 | You may charge any price or no price for each copy that you convey,
206 | and you may offer support or warranty protection for a fee.
207 |
208 | 5. Conveying Modified Source Versions.
209 |
210 | You may convey a work based on the Program, or the modifications to
211 | produce it from the Program, in the form of source code under the
212 | terms of section 4, provided that you also meet all of these conditions:
213 |
214 | a) The work must carry prominent notices stating that you modified
215 | it, and giving a relevant date.
216 |
217 | b) The work must carry prominent notices stating that it is
218 | released under this License and any conditions added under section
219 | 7. This requirement modifies the requirement in section 4 to
220 | "keep intact all notices".
221 |
222 | c) You must license the entire work, as a whole, under this
223 | License to anyone who comes into possession of a copy. This
224 | License will therefore apply, along with any applicable section 7
225 | additional terms, to the whole of the work, and all its parts,
226 | regardless of how they are packaged. This License gives no
227 | permission to license the work in any other way, but it does not
228 | invalidate such permission if you have separately received it.
229 |
230 | d) If the work has interactive user interfaces, each must display
231 | Appropriate Legal Notices; however, if the Program has interactive
232 | interfaces that do not display Appropriate Legal Notices, your
233 | work need not make them do so.
234 |
235 | A compilation of a covered work with other separate and independent
236 | works, which are not by their nature extensions of the covered work,
237 | and which are not combined with it such as to form a larger program,
238 | in or on a volume of a storage or distribution medium, is called an
239 | "aggregate" if the compilation and its resulting copyright are not
240 | used to limit the access or legal rights of the compilation's users
241 | beyond what the individual works permit. Inclusion of a covered work
242 | in an aggregate does not cause this License to apply to the other
243 | parts of the aggregate.
244 |
245 | 6. Conveying Non-Source Forms.
246 |
247 | You may convey a covered work in object code form under the terms
248 | of sections 4 and 5, provided that you also convey the
249 | machine-readable Corresponding Source under the terms of this License,
250 | in one of these ways:
251 |
252 | a) Convey the object code in, or embodied in, a physical product
253 | (including a physical distribution medium), accompanied by the
254 | Corresponding Source fixed on a durable physical medium
255 | customarily used for software interchange.
256 |
257 | b) Convey the object code in, or embodied in, a physical product
258 | (including a physical distribution medium), accompanied by a
259 | written offer, valid for at least three years and valid for as
260 | long as you offer spare parts or customer support for that product
261 | model, to give anyone who possesses the object code either (1) a
262 | copy of the Corresponding Source for all the software in the
263 | product that is covered by this License, on a durable physical
264 | medium customarily used for software interchange, for a price no
265 | more than your reasonable cost of physically performing this
266 | conveying of source, or (2) access to copy the
267 | Corresponding Source from a network server at no charge.
268 |
269 | c) Convey individual copies of the object code with a copy of the
270 | written offer to provide the Corresponding Source. This
271 | alternative is allowed only occasionally and noncommercially, and
272 | only if you received the object code with such an offer, in accord
273 | with subsection 6b.
274 |
275 | d) Convey the object code by offering access from a designated
276 | place (gratis or for a charge), and offer equivalent access to the
277 | Corresponding Source in the same way through the same place at no
278 | further charge. You need not require recipients to copy the
279 | Corresponding Source along with the object code. If the place to
280 | copy the object code is a network server, the Corresponding Source
281 | may be on a different server (operated by you or a third party)
282 | that supports equivalent copying facilities, provided you maintain
283 | clear directions next to the object code saying where to find the
284 | Corresponding Source. Regardless of what server hosts the
285 | Corresponding Source, you remain obligated to ensure that it is
286 | available for as long as needed to satisfy these requirements.
287 |
288 | e) Convey the object code using peer-to-peer transmission, provided
289 | you inform other peers where the object code and Corresponding
290 | Source of the work are being offered to the general public at no
291 | charge under subsection 6d.
292 |
293 | A separable portion of the object code, whose source code is excluded
294 | from the Corresponding Source as a System Library, need not be
295 | included in conveying the object code work.
296 |
297 | A "User Product" is either (1) a "consumer product", which means any
298 | tangible personal property which is normally used for personal, family,
299 | or household purposes, or (2) anything designed or sold for incorporation
300 | into a dwelling. In determining whether a product is a consumer product,
301 | doubtful cases shall be resolved in favor of coverage. For a particular
302 | product received by a particular user, "normally used" refers to a
303 | typical or common use of that class of product, regardless of the status
304 | of the particular user or of the way in which the particular user
305 | actually uses, or expects or is expected to use, the product. A product
306 | is a consumer product regardless of whether the product has substantial
307 | commercial, industrial or non-consumer uses, unless such uses represent
308 | the only significant mode of use of the product.
309 |
310 | "Installation Information" for a User Product means any methods,
311 | procedures, authorization keys, or other information required to install
312 | and execute modified versions of a covered work in that User Product from
313 | a modified version of its Corresponding Source. The information must
314 | suffice to ensure that the continued functioning of the modified object
315 | code is in no case prevented or interfered with solely because
316 | modification has been made.
317 |
318 | If you convey an object code work under this section in, or with, or
319 | specifically for use in, a User Product, and the conveying occurs as
320 | part of a transaction in which the right of possession and use of the
321 | User Product is transferred to the recipient in perpetuity or for a
322 | fixed term (regardless of how the transaction is characterized), the
323 | Corresponding Source conveyed under this section must be accompanied
324 | by the Installation Information. But this requirement does not apply
325 | if neither you nor any third party retains the ability to install
326 | modified object code on the User Product (for example, the work has
327 | been installed in ROM).
328 |
329 | The requirement to provide Installation Information does not include a
330 | requirement to continue to provide support service, warranty, or updates
331 | for a work that has been modified or installed by the recipient, or for
332 | the User Product in which it has been modified or installed. Access to a
333 | network may be denied when the modification itself materially and
334 | adversely affects the operation of the network or violates the rules and
335 | protocols for communication across the network.
336 |
337 | Corresponding Source conveyed, and Installation Information provided,
338 | in accord with this section must be in a format that is publicly
339 | documented (and with an implementation available to the public in
340 | source code form), and must require no special password or key for
341 | unpacking, reading or copying.
342 |
343 | 7. Additional Terms.
344 |
345 | "Additional permissions" are terms that supplement the terms of this
346 | License by making exceptions from one or more of its conditions.
347 | Additional permissions that are applicable to the entire Program shall
348 | be treated as though they were included in this License, to the extent
349 | that they are valid under applicable law. If additional permissions
350 | apply only to part of the Program, that part may be used separately
351 | under those permissions, but the entire Program remains governed by
352 | this License without regard to the additional permissions.
353 |
354 | When you convey a copy of a covered work, you may at your option
355 | remove any additional permissions from that copy, or from any part of
356 | it. (Additional permissions may be written to require their own
357 | removal in certain cases when you modify the work.) You may place
358 | additional permissions on material, added by you to a covered work,
359 | for which you have or can give appropriate copyright permission.
360 |
361 | Notwithstanding any other provision of this License, for material you
362 | add to a covered work, you may (if authorized by the copyright holders of
363 | that material) supplement the terms of this License with terms:
364 |
365 | a) Disclaiming warranty or limiting liability differently from the
366 | terms of sections 15 and 16 of this License; or
367 |
368 | b) Requiring preservation of specified reasonable legal notices or
369 | author attributions in that material or in the Appropriate Legal
370 | Notices displayed by works containing it; or
371 |
372 | c) Prohibiting misrepresentation of the origin of that material, or
373 | requiring that modified versions of such material be marked in
374 | reasonable ways as different from the original version; or
375 |
376 | d) Limiting the use for publicity purposes of names of licensors or
377 | authors of the material; or
378 |
379 | e) Declining to grant rights under trademark law for use of some
380 | trade names, trademarks, or service marks; or
381 |
382 | f) Requiring indemnification of licensors and authors of that
383 | material by anyone who conveys the material (or modified versions of
384 | it) with contractual assumptions of liability to the recipient, for
385 | any liability that these contractual assumptions directly impose on
386 | those licensors and authors.
387 |
388 | All other non-permissive additional terms are considered "further
389 | restrictions" within the meaning of section 10. If the Program as you
390 | received it, or any part of it, contains a notice stating that it is
391 | governed by this License along with a term that is a further
392 | restriction, you may remove that term. If a license document contains
393 | a further restriction but permits relicensing or conveying under this
394 | License, you may add to a covered work material governed by the terms
395 | of that license document, provided that the further restriction does
396 | not survive such relicensing or conveying.
397 |
398 | If you add terms to a covered work in accord with this section, you
399 | must place, in the relevant source files, a statement of the
400 | additional terms that apply to those files, or a notice indicating
401 | where to find the applicable terms.
402 |
403 | Additional terms, permissive or non-permissive, may be stated in the
404 | form of a separately written license, or stated as exceptions;
405 | the above requirements apply either way.
406 |
407 | 8. Termination.
408 |
409 | You may not propagate or modify a covered work except as expressly
410 | provided under this License. Any attempt otherwise to propagate or
411 | modify it is void, and will automatically terminate your rights under
412 | this License (including any patent licenses granted under the third
413 | paragraph of section 11).
414 |
415 | However, if you cease all violation of this License, then your
416 | license from a particular copyright holder is reinstated (a)
417 | provisionally, unless and until the copyright holder explicitly and
418 | finally terminates your license, and (b) permanently, if the copyright
419 | holder fails to notify you of the violation by some reasonable means
420 | prior to 60 days after the cessation.
421 |
422 | Moreover, your license from a particular copyright holder is
423 | reinstated permanently if the copyright holder notifies you of the
424 | violation by some reasonable means, this is the first time you have
425 | received notice of violation of this License (for any work) from that
426 | copyright holder, and you cure the violation prior to 30 days after
427 | your receipt of the notice.
428 |
429 | Termination of your rights under this section does not terminate the
430 | licenses of parties who have received copies or rights from you under
431 | this License. If your rights have been terminated and not permanently
432 | reinstated, you do not qualify to receive new licenses for the same
433 | material under section 10.
434 |
435 | 9. Acceptance Not Required for Having Copies.
436 |
437 | You are not required to accept this License in order to receive or
438 | run a copy of the Program. Ancillary propagation of a covered work
439 | occurring solely as a consequence of using peer-to-peer transmission
440 | to receive a copy likewise does not require acceptance. However,
441 | nothing other than this License grants you permission to propagate or
442 | modify any covered work. These actions infringe copyright if you do
443 | not accept this License. Therefore, by modifying or propagating a
444 | covered work, you indicate your acceptance of this License to do so.
445 |
446 | 10. Automatic Licensing of Downstream Recipients.
447 |
448 | Each time you convey a covered work, the recipient automatically
449 | receives a license from the original licensors, to run, modify and
450 | propagate that work, subject to this License. You are not responsible
451 | for enforcing compliance by third parties with this License.
452 |
453 | An "entity transaction" is a transaction transferring control of an
454 | organization, or substantially all assets of one, or subdividing an
455 | organization, or merging organizations. If propagation of a covered
456 | work results from an entity transaction, each party to that
457 | transaction who receives a copy of the work also receives whatever
458 | licenses to the work the party's predecessor in interest had or could
459 | give under the previous paragraph, plus a right to possession of the
460 | Corresponding Source of the work from the predecessor in interest, if
461 | the predecessor has it or can get it with reasonable efforts.
462 |
463 | You may not impose any further restrictions on the exercise of the
464 | rights granted or affirmed under this License. For example, you may
465 | not impose a license fee, royalty, or other charge for exercise of
466 | rights granted under this License, and you may not initiate litigation
467 | (including a cross-claim or counterclaim in a lawsuit) alleging that
468 | any patent claim is infringed by making, using, selling, offering for
469 | sale, or importing the Program or any portion of it.
470 |
471 | 11. Patents.
472 |
473 | A "contributor" is a copyright holder who authorizes use under this
474 | License of the Program or a work on which the Program is based. The
475 | work thus licensed is called the contributor's "contributor version".
476 |
477 | A contributor's "essential patent claims" are all patent claims
478 | owned or controlled by the contributor, whether already acquired or
479 | hereafter acquired, that would be infringed by some manner, permitted
480 | by this License, of making, using, or selling its contributor version,
481 | but do not include claims that would be infringed only as a
482 | consequence of further modification of the contributor version. For
483 | purposes of this definition, "control" includes the right to grant
484 | patent sublicenses in a manner consistent with the requirements of
485 | this License.
486 |
487 | Each contributor grants you a non-exclusive, worldwide, royalty-free
488 | patent license under the contributor's essential patent claims, to
489 | make, use, sell, offer for sale, import and otherwise run, modify and
490 | propagate the contents of its contributor version.
491 |
492 | In the following three paragraphs, a "patent license" is any express
493 | agreement or commitment, however denominated, not to enforce a patent
494 | (such as an express permission to practice a patent or covenant not to
495 | sue for patent infringement). To "grant" such a patent license to a
496 | party means to make such an agreement or commitment not to enforce a
497 | patent against the party.
498 |
499 | If you convey a covered work, knowingly relying on a patent license,
500 | and the Corresponding Source of the work is not available for anyone
501 | to copy, free of charge and under the terms of this License, through a
502 | publicly available network server or other readily accessible means,
503 | then you must either (1) cause the Corresponding Source to be so
504 | available, or (2) arrange to deprive yourself of the benefit of the
505 | patent license for this particular work, or (3) arrange, in a manner
506 | consistent with the requirements of this License, to extend the patent
507 | license to downstream recipients. "Knowingly relying" means you have
508 | actual knowledge that, but for the patent license, your conveying the
509 | covered work in a country, or your recipient's use of the covered work
510 | in a country, would infringe one or more identifiable patents in that
511 | country that you have reason to believe are valid.
512 |
513 | If, pursuant to or in connection with a single transaction or
514 | arrangement, you convey, or propagate by procuring conveyance of, a
515 | covered work, and grant a patent license to some of the parties
516 | receiving the covered work authorizing them to use, propagate, modify
517 | or convey a specific copy of the covered work, then the patent license
518 | you grant is automatically extended to all recipients of the covered
519 | work and works based on it.
520 |
521 | A patent license is "discriminatory" if it does not include within
522 | the scope of its coverage, prohibits the exercise of, or is
523 | conditioned on the non-exercise of one or more of the rights that are
524 | specifically granted under this License. You may not convey a covered
525 | work if you are a party to an arrangement with a third party that is
526 | in the business of distributing software, under which you make payment
527 | to the third party based on the extent of your activity of conveying
528 | the work, and under which the third party grants, to any of the
529 | parties who would receive the covered work from you, a discriminatory
530 | patent license (a) in connection with copies of the covered work
531 | conveyed by you (or copies made from those copies), or (b) primarily
532 | for and in connection with specific products or compilations that
533 | contain the covered work, unless you entered into that arrangement,
534 | or that patent license was granted, prior to 28 March 2007.
535 |
536 | Nothing in this License shall be construed as excluding or limiting
537 | any implied license or other defenses to infringement that may
538 | otherwise be available to you under applicable patent law.
539 |
540 | 12. No Surrender of Others' Freedom.
541 |
542 | If conditions are imposed on you (whether by court order, agreement or
543 | otherwise) that contradict the conditions of this License, they do not
544 | excuse you from the conditions of this License. If you cannot convey a
545 | covered work so as to satisfy simultaneously your obligations under this
546 | License and any other pertinent obligations, then as a consequence you may
547 | not convey it at all. For example, if you agree to terms that obligate you
548 | to collect a royalty for further conveying from those to whom you convey
549 | the Program, the only way you could satisfy both those terms and this
550 | License would be to refrain entirely from conveying the Program.
551 |
552 | 13. Use with the GNU Affero General Public License.
553 |
554 | Notwithstanding any other provision of this License, you have
555 | permission to link or combine any covered work with a work licensed
556 | under version 3 of the GNU Affero General Public License into a single
557 | combined work, and to convey the resulting work. The terms of this
558 | License will continue to apply to the part which is the covered work,
559 | but the special requirements of the GNU Affero General Public License,
560 | section 13, concerning interaction through a network will apply to the
561 | combination as such.
562 |
563 | 14. Revised Versions of this License.
564 |
565 | The Free Software Foundation may publish revised and/or new versions of
566 | the GNU General Public License from time to time. Such new versions will
567 | be similar in spirit to the present version, but may differ in detail to
568 | address new problems or concerns.
569 |
570 | Each version is given a distinguishing version number. If the
571 | Program specifies that a certain numbered version of the GNU General
572 | Public License "or any later version" applies to it, you have the
573 | option of following the terms and conditions either of that numbered
574 | version or of any later version published by the Free Software
575 | Foundation. If the Program does not specify a version number of the
576 | GNU General Public License, you may choose any version ever published
577 | by the Free Software Foundation.
578 |
579 | If the Program specifies that a proxy can decide which future
580 | versions of the GNU General Public License can be used, that proxy's
581 | public statement of acceptance of a version permanently authorizes you
582 | to choose that version for the Program.
583 |
584 | Later license versions may give you additional or different
585 | permissions. However, no additional obligations are imposed on any
586 | author or copyright holder as a result of your choosing to follow a
587 | later version.
588 |
589 | 15. Disclaimer of Warranty.
590 |
591 | THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
592 | APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
593 | HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
594 | OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
595 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
596 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
597 | IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
598 | ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
599 |
600 | 16. Limitation of Liability.
601 |
602 | IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
603 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
604 | THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
605 | GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
606 | USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
607 | DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
608 | PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
609 | EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
610 | SUCH DAMAGES.
611 |
612 | 17. Interpretation of Sections 15 and 16.
613 |
614 | If the disclaimer of warranty and limitation of liability provided
615 | above cannot be given local legal effect according to their terms,
616 | reviewing courts shall apply local law that most closely approximates
617 | an absolute waiver of all civil liability in connection with the
618 | Program, unless a warranty or assumption of liability accompanies a
619 | copy of the Program in return for a fee.
620 |
621 | END OF TERMS AND CONDITIONS
622 |
623 | How to Apply These Terms to Your New Programs
624 |
625 | If you develop a new program, and you want it to be of the greatest
626 | possible use to the public, the best way to achieve this is to make it
627 | free software which everyone can redistribute and change under these terms.
628 |
629 | To do so, attach the following notices to the program. It is safest
630 | to attach them to the start of each source file to most effectively
631 | state the exclusion of warranty; and each file should have at least
632 | the "copyright" line and a pointer to where the full notice is found.
633 |
634 | {one line to give the program's name and a brief idea of what it does.}
635 | Copyright (C) {year} {name of author}
636 |
637 | This program is free software: you can redistribute it and/or modify
638 | it under the terms of the GNU General Public License as published by
639 | the Free Software Foundation, either version 3 of the License, or
640 | (at your option) any later version.
641 |
642 | This program is distributed in the hope that it will be useful,
643 | but WITHOUT ANY WARRANTY; without even the implied warranty of
644 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
645 | GNU General Public License for more details.
646 |
647 | You should have received a copy of the GNU General Public License
648 | along with this program. If not, see .
649 |
650 | Also add information on how to contact you by electronic and paper mail.
651 |
652 | If the program does terminal interaction, make it output a short
653 | notice like this when it starts in an interactive mode:
654 |
655 | {project} Copyright (C) {year} {fullname}
656 | This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
657 | This is free software, and you are welcome to redistribute it
658 | under certain conditions; type `show c' for details.
659 |
660 | The hypothetical commands `show w' and `show c' should show the appropriate
661 | parts of the General Public License. Of course, your program's commands
662 | might be different; for a GUI interface, you would use an "about box".
663 |
664 | You should also get your employer (if you work as a programmer) or school,
665 | if any, to sign a "copyright disclaimer" for the program, if necessary.
666 | For more information on this, and how to apply and follow the GNU GPL, see
667 | .
668 |
669 | The GNU General Public License does not permit incorporating your program
670 | into proprietary programs. If your program is a subroutine library, you
671 | may consider it more useful to permit linking proprietary applications with
672 | the library. If this is what you want to do, use the GNU Lesser General
673 | Public License instead of this License. But first, please read
674 | .
675 |
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 | AS := rgbasm
2 | ASFLAGS := -i inc/ -i data/ -o
3 | LD := rgblink
4 | LDFLAGS1 := -d -o
5 | LDFLAGS2 := -o
6 | FX := rgbfix
7 | FXFLAGS1 := -p 0 -r 0 -t DMG_EXAMPLE -v
8 | FXFLAGS2 := -C -p 0 -r 0 -t CGB_EXAMPLE -v
9 |
10 | dmg_src := $(wildcard dmg/*.asm)
11 | cgb_src := $(wildcard cgb/*.asm)
12 | dmg_rom := $(dmg_src:.asm=.gb)
13 | cgb_rom := $(cgb_src:.asm=.gbc)
14 |
15 | all: $(dmg_rom) $(cgb_rom)
16 |
17 | %.gb: %.o
18 | $(LD) $(LDFLAGS1) $@ $<
19 | $(FX) $(FXFLAGS1) $@
20 |
21 | %.gbc: %.o
22 | $(LD) $(LDFLAGS2) $@ $<
23 | $(FX) $(FXFLAGS2) $@
24 |
25 | %.o: %.asm
26 | $(AS) $(ASFLAGS) $@ $<
27 |
28 | clean:
29 | rm -f dmg/*.o
30 | rm -f dmg/*.gb
31 | rm -f cgb/*.o
32 | rm -f cgb/*.gbc
33 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ### Notice
2 | Starting October 12th, 2023 GitHub is enforcing mandatory [two-factor authentication](https://github.blog/2023-03-09-raising-the-bar-for-software-security-github-2fa-begins-march-13/) on my account.
3 | I'm not going to comply and move all my activity to GitLab instead.
4 | Any future updates / releases will be available at: [https://gitlab.com/gitendo/helloworld](https://gitlab.com/gitendo/helloworld)
5 | Thanks and see you there!
6 | ___
7 |
8 | # Hello Game Boy!
9 | This repo started as simple "Hello world!" for Gameboy (DMG) written in assembly language. Few stars later I thought I could start adding some other examples as well, including Game Boy Color (CGB). So here it is - new folder structure, makefiles for Windows / Linux and content that will gradually follow. Everything commented and ready to assemble and link with [RGBASM](https://github.com/rednex/rgbds). Currently it contains:
10 |
11 | ```
12 | [DMG]
13 | - Hello world
14 | - Display picture composed of 242 unique tiles
15 | - Display picture composed of 355 unique tiles
16 | - Background scroll (clockwise)
17 | - Reading joypad state
18 | - Window
19 | - Single, d-pad moveable sprite
20 | - Meta sprite
21 | - 8x8 sprite collision detection
22 | - Game score in Binary Coded Decimal
23 | - Game score in hexadecimal
24 | - ClockBoy - timer based clock
25 |
26 | [CGB]
27 | - Display picture composed of 247 unique tiles, 8 palettes
28 | ```
29 | On Windows make sure RGBDS binaries are added to path - here's [how to](https://www.computerhope.com/issues/ch000549.htm) in case you don't know. Otherwise you'd need to change path to files being included and use these commands for each source file:
30 |
31 | ```
32 | rgbasm.exe -o hello.o hello.s
33 | rgblink.exe -d -o hello.gb hello.o
34 | rgbfix.exe -p 0 -r 0 -v hello.gb
35 | ```
36 |
--------------------------------------------------------------------------------
/cgb/picture.asm:
--------------------------------------------------------------------------------
1 | ; display color picture composed of 247 unique tiles, 8 palettes by tmk @ https://github.com/gitendo/
2 | ; Yus Bird goes Gameboy Color pixeled by ptoing @ http://pixeljoint.com/pixelart/55124.htm
3 |
4 | INCLUDE "hardware.inc" ; system defines
5 |
6 | SECTION "Start",ROM0[$100] ; start vector, followed by header data applied by rgbfix.exe
7 | nop
8 | jp start
9 |
10 | SECTION "Example",ROM0[$150] ; code starts here
11 |
12 | start:
13 | di ; disable interrupts
14 | ld sp,$E000 ; setup stack
15 |
16 | .wait_vbl ; wait for vblank to properly disable lcd
17 | ld a,[rLY]
18 | cp $90
19 | jr nz,.wait_vbl
20 |
21 | xor a ; reset important registers
22 | ld [rIF],a
23 | ld [rLCDC],a
24 | ld [rSTAT],a
25 | ld [rSCX],a
26 | ld [rSCY],a
27 | ld [rLYC],a
28 | ld [rIE],a
29 | ld [rVBK],a
30 | ld [rSVBK],a
31 | ld [rRP],a
32 |
33 | ld hl,_RAM ; clear ram (fill with a which is 0 here)
34 | ld bc,$2000-2 ; watch out for stack ;)
35 | call fill
36 |
37 | ld hl,_HRAM ; clear hram
38 | ld c,$80 ; a = 0, b = 0 here, so let's save a byte and 4 cycles (ld c,$80 - 2/8 vs ld bc,$80 - 3/12)
39 | call fill
40 | ; no point in clearing vram, we'll overwrite it with picture data anyway
41 | ; lcdc is already disabled so we have 'easy' access to vram
42 |
43 | ld hl,picture_chr ; picture data
44 | ld de,_VRAM ; place it between $8000-8FFF (tiles are numbered here from 0 to 255)
45 | ld bc,3952 ; gbhorror.chr file size
46 | call copy
47 |
48 | ld hl,picture_map ; picture map (160x144px padded = 32*18)
49 | ld de,_SCRN0 ; place it at $9800
50 | ld bc,576 ; gbcyus.map file size
51 | call copy
52 |
53 | ld a,1 ; switch to vram bank 1
54 | ld [rVBK],a ; this is where we place attribute map
55 |
56 | ld hl,picture_atr ; picture attributes
57 | ld de,_SCRN0 ; place it at $9800 just like map
58 | ld bc,576 ; gbcyus.atr file size
59 | call copy
60 |
61 | xor a ; switch back to vram bank 0
62 | ld [rVBK],a
63 |
64 | ld hl,picture_pal ; picture palette
65 | ld b,64 ; gbcyus.pal file size
66 | ; 1 palette has 4 colors, 1 color takes 2 bytes, so 8 palettes = 64 bytes
67 | call set_bg_pal
68 |
69 |
70 | ld a,LCDCF_ON | LCDCF_BG8000 | LCDCF_BG9800 | LCDCF_OBJ8 | LCDCF_OBJOFF | LCDCF_WINOFF | LCDCF_BGON
71 | ; lcd setup: tiles at $8000, map at $9800, 8x8 sprites (disabled), no window, etc.
72 | ld [rLCDC],a ; enable lcd
73 |
74 | .the_end
75 | halt ; save battery
76 | ; nop ; nop after halt is mandatory but rgbasm takes care of it :)
77 | jr .the_end ; endless loop
78 |
79 |
80 | ;-------------------------------------------------------------------------------
81 | copy:
82 | ;-------------------------------------------------------------------------------
83 | ; hl - source address
84 | ; de - destination
85 | ; bc - size
86 |
87 | inc b
88 | inc c
89 | jr .skip
90 | .copy
91 | ld a,[hl+]
92 | ld [de],a
93 | inc de
94 | .skip
95 | dec c
96 | jr nz,.copy
97 | dec b
98 | jr nz,.copy
99 | ret
100 |
101 |
102 | ;-------------------------------------------------------------------------------
103 | fill:
104 | ;-------------------------------------------------------------------------------
105 | ; a - byte to fill with
106 | ; hl - destination address
107 | ; bc - size of area to fill
108 |
109 | inc b
110 | inc c
111 | jr .skip
112 | .fill
113 | ld [hl+],a
114 | .skip
115 | dec c
116 | jr nz,.fill
117 | dec b
118 | jr nz,.fill
119 | ret
120 |
121 |
122 | ;-------------------------------------------------------------------------------
123 | set_bg_pal:
124 | ;-------------------------------------------------------------------------------
125 | ld a,%10000000 ; bit 7 - enable palette auto increment
126 | ; bits 5,4,3 - palette number (0-7)
127 | ; bits 2,1 - color number (0-3)
128 | ld [rBCPS],a ; we start from color #0 in palette #0 and let the hardware to auto increment those values while we copy palette data
129 | .copy
130 | ld a,[hl+] ; this is really basic = slow way of doing things
131 | ldh [rBCPD],a
132 | dec b
133 | jr nz,.copy
134 | ret
135 |
136 | ;-------------------------------------------------------------------------------
137 |
138 | picture_chr: ; bmp2cgb -e0 gbcyus.bmp
139 | INCBIN "gbcyus.chr"
140 | picture_map:
141 | INCBIN "gbcyus.map"
142 | picture_atr:
143 | INCBIN "gbcyus.atr"
144 | picture_pal:
145 | INCBIN "gbcyus.pal"
146 |
--------------------------------------------------------------------------------
/data/font_8x8.chr:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gitendo/helloworld/17cae56b11435ae815d52b5d809c0e7cdd53963a/data/font_8x8.chr
--------------------------------------------------------------------------------
/data/gbcyus.atr:
--------------------------------------------------------------------------------
1 | #
--------------------------------------------------------------------------------
/data/gbcyus.bmp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gitendo/helloworld/17cae56b11435ae815d52b5d809c0e7cdd53963a/data/gbcyus.bmp
--------------------------------------------------------------------------------
/data/gbcyus.chr:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gitendo/helloworld/17cae56b11435ae815d52b5d809c0e7cdd53963a/data/gbcyus.chr
--------------------------------------------------------------------------------
/data/gbcyus.map:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gitendo/helloworld/17cae56b11435ae815d52b5d809c0e7cdd53963a/data/gbcyus.map
--------------------------------------------------------------------------------
/data/gbcyus.pal:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gitendo/helloworld/17cae56b11435ae815d52b5d809c0e7cdd53963a/data/gbcyus.pal
--------------------------------------------------------------------------------
/data/gbhorror.bmp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gitendo/helloworld/17cae56b11435ae815d52b5d809c0e7cdd53963a/data/gbhorror.bmp
--------------------------------------------------------------------------------
/data/gbhorror.chr:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gitendo/helloworld/17cae56b11435ae815d52b5d809c0e7cdd53963a/data/gbhorror.chr
--------------------------------------------------------------------------------
/data/gbhorror.map:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gitendo/helloworld/17cae56b11435ae815d52b5d809c0e7cdd53963a/data/gbhorror.map
--------------------------------------------------------------------------------
/data/hlgbmcp.bmp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gitendo/helloworld/17cae56b11435ae815d52b5d809c0e7cdd53963a/data/hlgbmcp.bmp
--------------------------------------------------------------------------------
/data/hlgbmcp.chr:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gitendo/helloworld/17cae56b11435ae815d52b5d809c0e7cdd53963a/data/hlgbmcp.chr
--------------------------------------------------------------------------------
/data/hlgbmcp_bg.map:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gitendo/helloworld/17cae56b11435ae815d52b5d809c0e7cdd53963a/data/hlgbmcp_bg.map
--------------------------------------------------------------------------------
/data/hlgbmcp_win.map:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gitendo/helloworld/17cae56b11435ae815d52b5d809c0e7cdd53963a/data/hlgbmcp_win.map
--------------------------------------------------------------------------------
/data/opti.bmp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gitendo/helloworld/17cae56b11435ae815d52b5d809c0e7cdd53963a/data/opti.bmp
--------------------------------------------------------------------------------
/data/opti.chr:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gitendo/helloworld/17cae56b11435ae815d52b5d809c0e7cdd53963a/data/opti.chr
--------------------------------------------------------------------------------
/data/opti.map:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gitendo/helloworld/17cae56b11435ae815d52b5d809c0e7cdd53963a/data/opti.map
--------------------------------------------------------------------------------
/data/tsodki1.bmp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gitendo/helloworld/17cae56b11435ae815d52b5d809c0e7cdd53963a/data/tsodki1.bmp
--------------------------------------------------------------------------------
/data/tsodki1.chr:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gitendo/helloworld/17cae56b11435ae815d52b5d809c0e7cdd53963a/data/tsodki1.chr
--------------------------------------------------------------------------------
/data/tsodki1.map:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gitendo/helloworld/17cae56b11435ae815d52b5d809c0e7cdd53963a/data/tsodki1.map
--------------------------------------------------------------------------------
/data/tsodki2.bmp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gitendo/helloworld/17cae56b11435ae815d52b5d809c0e7cdd53963a/data/tsodki2.bmp
--------------------------------------------------------------------------------
/data/tsodki2.chr:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gitendo/helloworld/17cae56b11435ae815d52b5d809c0e7cdd53963a/data/tsodki2.chr
--------------------------------------------------------------------------------
/data/tsodki2.map:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gitendo/helloworld/17cae56b11435ae815d52b5d809c0e7cdd53963a/data/tsodki2.map
--------------------------------------------------------------------------------
/dmg/bg_scroll_x_y.asm:
--------------------------------------------------------------------------------
1 | ; -----------------------------------------------------------------------------
2 | ; Example: Background scroll (clockwise)
3 | ; -----------------------------------------------------------------------------
4 | ; Optical Illusion pixeled by Phexion @ http://pixeljoint.com/pixelart/81815.htm
5 | ; More examples by tmk @ https://github.com/gitendo/helloworld
6 | ; -----------------------------------------------------------------------------
7 |
8 | INCLUDE "hardware.inc" ; system defines
9 |
10 | SECTION "V-Blank",ROM0[$0040] ; vblank interrupt handler
11 | jp vblank
12 |
13 | SECTION "Start",ROM0[$100] ; start vector, followed by header data applied by rgbfix.exe
14 | nop
15 | jp start
16 |
17 | SECTION "Example",ROM0[$150] ; code starts here
18 |
19 | start:
20 | di ; disable interrupts
21 | ld sp,$E000 ; setup stack
22 |
23 | .wait_vbl ; wait for vblank to properly disable lcd
24 | ld a,[rLY]
25 | cp $90
26 | jr nz,.wait_vbl
27 |
28 | xor a ; reset important registers
29 | ld [rIF],a
30 | ld [rLCDC],a
31 | ld [rSTAT],a
32 | ld [rSCX],a
33 | ld [rSCY],a
34 | ld [rLYC],a
35 | ld [rIE],a
36 |
37 | ld hl,_RAM ; clear ram (fill with a which is 0 here)
38 | ld bc,$2000-2 ; watch out for stack ;)
39 | call fill
40 |
41 | ld hl,_HRAM ; clear hram
42 | ld c,$80 ; a = 0, b = 0 here, so let's save a byte and 4 cycles (ld c,$80 - 2/8 vs ld bc,$80 - 3/12)
43 | call fill
44 | ; no point in clearing vram, we'll overwrite it with picture data anyway
45 | ; lcdc is already disabled so we have 'easy' access to vram
46 |
47 | ld hl,picture_chr ; picture data
48 | ld de,_VRAM ; place it between $8000-8FFF (tiles are numbered here from 0 to 255)
49 | ld bc,3872 ; opti.chr file size
50 | call copy
51 |
52 | ld hl,picture_map ; picture map (256x256px = 32*32) takes whole _SCRN0
53 | ld de,_SCRN0 ; place it at $9800
54 | ld bc,3872 ; opti.map file size
55 | call copy
56 |
57 | ld a,%00011011 ; bits: 7-6 = 1st color, 5-4 = 2nd, 3-2 = 3rd and 1-0 = 4th color
58 | ; color values: 00 - light, 01 - gray, 10 - dark gray, 11 - dark
59 | ld [rBGP],a ; bg palette
60 | ld [rOBP0],a ; obj palettes (not used in this example)
61 | ld [rOBP1],a
62 |
63 | ld a,IEF_VBLANK ; vblank interrupt
64 | ld [rIE],a ; setup
65 |
66 | ld a,LCDCF_ON | LCDCF_BG8000 | LCDCF_BG9800 | LCDCF_OBJ8 | LCDCF_OBJOFF | LCDCF_WINOFF | LCDCF_BGON
67 | ; lcd setup: tiles at $8000, map at $9800, 8x8 sprites (disabled), no window, etc.
68 | ld [rLCDC],a ; enable lcd
69 |
70 | ei ; enable interrupts
71 |
72 | .the_end
73 | halt ; save battery
74 | ; nop ; nop after halt is mandatory but rgbasm takes care of it :)
75 | jr .the_end ; endless loop
76 |
77 |
78 | vblank:
79 | ldh a,[delay] ; fetch delay value, it's 0 after hram initialization
80 | xor 1 ; (0 xor 1 = 1) then (1 xor 1 = 0) - this makes code bellow to be called every second frame
81 | ldh [delay],a ; store delay value
82 | and a ; check if a = 0
83 | jr z,.scroll ; execute scroll part if so
84 | reti
85 |
86 | .scroll
87 | ldh a,[direction] ; first load direction value
88 | .right
89 | cp 0 ; move right if it's 0
90 | jr nz,.down ; not 'right', check another direction
91 | ldh a,[rSCX] ; increase scroll x
92 | inc a
93 | ldh [rSCX],a
94 | cp 96 ; boundary (256 - 160)
95 | jr nz,.r_done ; we haven't reached it yet
96 | ld a,1 ; boundary reached, change direction to 'down'
97 | ldh [direction],a
98 | .r_done
99 | reti
100 |
101 | .down
102 | cp 1 ; move down if it's 1
103 | jr nz,.left ; not 'down', check another direction
104 | ldh a,[rSCY] ; increase scroll y
105 | inc a
106 | ldh [rSCY],a
107 | cp 112 ; boundary (256 - 144)
108 | jr nz,.d_done ; we haven't reached it yet
109 | ld a,2 ; boundary reached, change direction to 'left'
110 | ldh [direction],a
111 | .d_done
112 | reti
113 |
114 | .left
115 | cp 2 ; move left if it's 2
116 | jr nz,.up ; not 'left', check another direction
117 | ldh a,[rSCX] ; decrease scroll x
118 | dec a
119 | ldh [rSCX],a
120 | and a ; let's see if we reached starting point = 0
121 | jr nz,.l_done ; nope
122 | ld a,3 ; true, change direction to 'up'
123 | ldh [direction],a
124 | .l_done
125 |
126 | reti
127 |
128 | .up ; no point in checking direction here sinc it's last possibility
129 | ldh a,[rSCY] ; decrease scroll y
130 | dec a
131 | ldh [rSCY],a
132 | and a ; let's see if we reached starting point = 0
133 | jr nz,.u_done ; nope
134 | xor a ; true, change direction to 'right'
135 | ldh [direction],a
136 | .u_done
137 | reti
138 |
139 |
140 | ;-------------------------------------------------------------------------------
141 | copy:
142 | ;-------------------------------------------------------------------------------
143 | ; hl - source address
144 | ; de - destination
145 | ; bc - size
146 |
147 | inc b
148 | inc c
149 | jr .skip
150 | .copy
151 | ld a,[hl+]
152 | ld [de],a
153 | inc de
154 | .skip
155 | dec c
156 | jr nz,.copy
157 | dec b
158 | jr nz,.copy
159 | ret
160 |
161 |
162 | ;-------------------------------------------------------------------------------
163 | fill:
164 | ;-------------------------------------------------------------------------------
165 | ; a - byte to fill with
166 | ; hl - destination address
167 | ; bc - size of area to fill
168 |
169 | inc b
170 | inc c
171 | jr .skip
172 | .fill
173 | ld [hl+],a
174 | .skip
175 | dec c
176 | jr nz,.fill
177 | dec b
178 | jr nz,.fill
179 | ret
180 |
181 | ;-------------------------------------------------------------------------------
182 |
183 | picture_chr: ; bmp2cgb -x -y -z opti.bmp
184 | INCBIN "opti.chr"
185 | picture_map:
186 | INCBIN "opti.map"
187 |
188 |
189 | SECTION "Variables",HRAM
190 |
191 | delay:
192 | ds 1
193 | direction:
194 | ds 1
195 |
--------------------------------------------------------------------------------
/dmg/hello.asm:
--------------------------------------------------------------------------------
1 | ; -----------------------------------------------------------------------------
2 | ; Example: Hello world - DMG ver.
3 | ; -----------------------------------------------------------------------------
4 | ; Font comes from ZX Spectrum - https://en.wikipedia.org/wiki/ZX_Spectrum_character_set
5 | ; More examples by tmk @ https://github.com/gitendo/helloworld
6 | ; -----------------------------------------------------------------------------
7 |
8 | INCLUDE "hardware.inc" ; system defines
9 |
10 | SECTION "Start",ROM0[$100] ; start vector, followed by header data applied by rgbfix.exe
11 | nop
12 | jp start
13 |
14 | SECTION "Example",ROM0[$150] ; code starts here
15 |
16 | start:
17 | di ; disable interrupts
18 | ld sp,$E000 ; setup stack
19 |
20 | .wait_vbl ; wait for vblank to properly disable lcd
21 | ld a,[rLY]
22 | cp $90
23 | jr nz,.wait_vbl
24 |
25 | xor a
26 | ld [rIF],a ; reset important registers
27 | ld [rLCDC],a
28 | ld [rSTAT],a
29 | ld [rSCX],a
30 | ld [rSCY],a
31 | ld [rLYC],a
32 | ld [rIE],a
33 |
34 | ld hl,_RAM ; clear ram (fill with a which is 0 here)
35 | ld bc,$2000-2 ; watch out for stack ;)
36 | call fill
37 |
38 | ld hl,_HRAM ; clear hram
39 | ld c,$80 ; a = 0, b = 0 here, so let's save a byte and 4 cycles (ld c,$80 - 2/8 vs ld bc,$80 - 3/12)
40 | call fill
41 |
42 | ld hl,_VRAM ; clear vram
43 | ld b,$18 ; a = 0, bc should be $1800; c = 0 here, so..
44 | call fill
45 |
46 | ld a,$20 ; ascii code for 'space' character
47 |
48 | ; no need to setup hl since _SCRN0 ($9800) and _SCRN1 ($9C00) are part of _VRAM, just continue
49 |
50 | ld b,8 ; bc should be $800 (_SCRN0/1 are 32*32 bytes); c = 0 here, so..
51 | call fill
52 |
53 | ld a,%10010011 ; bits: 7-6 = 1st color, 5-4 = 2nd, 3-2 = 3rd and 1-0 = 4th color
54 | ; color values: 00 - light, 01 - gray, 10 - dark gray, 11 - dark
55 | ld [rBGP],a ; bg palette
56 | ld [rOBP0],a ; obj palettes (not used in this example)
57 | ld [rOBP1],a
58 |
59 | ld hl,font ; font data
60 | ld de,_VRAM+$200 ; place it here to get ascii mapping ('space' code is $20, tile size $10)
61 | ld bc,1776 ; font_8x8.chr file size
62 | call copy
63 |
64 | ld hl,text ; hello message
65 | ld de,_SCRN0+$100 ; center it a bit
66 | ld c,text_end-text ; b = 0, our string = 18 chars, so..
67 | call copy ; lcdc is disabled so you have 'easy' access to vram
68 |
69 | ld a,LCDCF_ON | LCDCF_BG8000 | LCDCF_BG9800 | LCDCF_OBJ8 | LCDCF_OBJOFF | LCDCF_WINOFF | LCDCF_BGON
70 | ; lcd setup: tiles at $8000, map at $9800, 8x8 sprites (disabled), no window, etc.
71 | ld [rLCDC],a ; enable lcd
72 |
73 | .the_end
74 | halt ; save battery
75 | ; nop ; nop after halt is mandatory but rgbasm takes care of it :)
76 | jr .the_end ; endless loop
77 |
78 | ;-------------------------------------------------------------------------------
79 | copy:
80 | ;-------------------------------------------------------------------------------
81 | ; hl - source address
82 | ; de - destination
83 | ; bc - size
84 |
85 | inc b
86 | inc c
87 | jr .skip
88 | .copy
89 | ld a,[hl+]
90 | ld [de],a
91 | inc de
92 | .skip
93 | dec c
94 | jr nz,.copy
95 | dec b
96 | jr nz,.copy
97 | ret
98 |
99 | ;-------------------------------------------------------------------------------
100 | fill:
101 | ;-------------------------------------------------------------------------------
102 | ; a - byte to fill with
103 | ; hl - destination address
104 | ; bc - size of area to fill
105 |
106 | inc b
107 | inc c
108 | jr .skip
109 | .fill
110 | ld [hl+],a
111 | .skip
112 | dec c
113 | jr nz,.fill
114 | dec b
115 | jr nz,.fill
116 | ret
117 |
118 | ;-------------------------------------------------------------------------------
119 |
120 | font:
121 | INCBIN "font_8x8.chr" ; converted with https://github.com/gitendo/bmp2cgb
122 |
123 | text:
124 | DB " Hello 8-bit world! "
125 | text_end:
--------------------------------------------------------------------------------
/dmg/joypad.asm:
--------------------------------------------------------------------------------
1 | ; -----------------------------------------------------------------------------
2 | ; Example: Reading joypad state
3 | ; -----------------------------------------------------------------------------
4 | ; Font comes from ZX Spectrum - https://en.wikipedia.org/wiki/ZX_Spectrum_character_set
5 | ; More examples by tmk @ https://github.com/gitendo/helloworld
6 | ; -----------------------------------------------------------------------------
7 |
8 | INCLUDE "hardware.inc" ; system defines
9 |
10 | SECTION "VBL",ROM0[$0040] ; vblank interrupt handler
11 | jp vbl
12 |
13 | SECTION "Start",ROM0[$100] ; start vector, followed by header data applied by rgbfix.exe
14 | nop
15 | jp start
16 |
17 | SECTION "Example",ROM0[$150] ; code starts here
18 |
19 | start:
20 | di ; disable interrupts
21 | ld sp,$E000 ; setup stack
22 |
23 | .wait_vbl ; wait for vblank to properly disable lcd
24 | ld a,[rLY]
25 | cp $90
26 | jr nz,.wait_vbl
27 |
28 | xor a
29 | ld [rIF],a ; reset important registers
30 | ld [rLCDC],a
31 | ld [rSTAT],a
32 | ld [rSCX],a
33 | ld [rSCY],a
34 | ld [rLYC],a
35 | ld [rIE],a
36 |
37 | ld hl,_RAM ; clear ram (fill with a which is 0 here)
38 | ld bc,$2000-2 ; watch out for stack ;)
39 | call fill
40 |
41 | ld hl,_HRAM ; clear hram
42 | ld c,$80 ; a = 0, b = 0 here, so let's save a byte and 4 cycles (ld c,$80 - 2/8 vs ld bc,$80 - 3/12)
43 | call fill
44 |
45 | ld hl,_VRAM ; clear vram, lcdc is disabled so you have 'easy' access
46 | ld b,$18 ; a = 0, bc should be $1800; c = 0 here, so..
47 | call fill
48 |
49 | ld a,$20 ; ascii code for 'space' character
50 |
51 | ; no need to setup hl since _SCRN0 ($9800) and _SCRN1 ($9C00) are part of _VRAM, just continue
52 |
53 | ld b,8 ; bc should be $800 (_SCRN0/1 are 32*32 bytes); c = 0 here, so..
54 | call fill
55 |
56 | ld a,%10010011 ; bits: 7-6 = 1st color, 5-4 = 2nd, 3-2 = 3rd and 1-0 = 4th color
57 | ; color values: 00 - light, 01 - gray, 10 - dark gray, 11 - dark
58 | ld [rBGP],a ; bg palette
59 | ld [rOBP0],a ; obj palettes (not used in this example)
60 | ld [rOBP1],a
61 |
62 | ld hl,font ; font data
63 | ld de,_VRAM+$200 ; place it here to get ascii mapping ('space' code is $20, tile size $10)
64 | ld bc,1776 ; font_8x8.chr file size
65 | call copy
66 |
67 | ld hl,text ; menu text
68 | ld de,_SCRN0+$60 ; center it a bit
69 | ld b,11
70 | call copy_text
71 |
72 | ld a,IEF_VBLANK ; vblank interrupt
73 | ld [rIE],a ; setup
74 |
75 | ld a,LCDCF_ON | LCDCF_BG8000 | LCDCF_BG9800 | LCDCF_OBJ8 | LCDCF_OBJOFF | LCDCF_WINOFF | LCDCF_BGON
76 | ; lcd setup: tiles at $8000, map at $9800, 8x8 sprites (disabled), no window, etc.
77 | ld [rLCDC],a ; enable lcd
78 |
79 | ei ; enable interrupts
80 |
81 | .loop
82 | call parse_input ; read joypad and update inputs array that holds individual keys status
83 | halt ; save battery
84 | ; nop ; nop after halt is mandatory but rgbasm takes care of it :)
85 |
86 |
87 | jr .loop ; endless loop
88 |
89 |
90 | vbl: ; update screen
91 | ld hl,_SCRN0+$C5 ; this points exactly at vram character between square brackets in 'Down' entry
92 | ld bc,32 ; next line, hl + bc will point to another entry
93 |
94 | ldh a,[btn_dn] ; use ldh instead of ld to copy value from hram, it's one byte shorter and 8 cycles faster
95 | ld [hl],a ; since it's vblank we have easy access to vram, update 1st entry
96 | add hl,bc ; and go to another
97 |
98 | ldh a,[btn_up] ; repeat 7 times ...
99 | ld [hl],a
100 | add hl,bc
101 |
102 | ldh a,[btn_lt]
103 | ld [hl],a
104 | add hl,bc
105 |
106 | ldh a,[btn_rt]
107 | ld [hl],a
108 | add hl,bc
109 |
110 | ldh a,[btn_st]
111 | ld [hl],a
112 | add hl,bc
113 |
114 | ldh a,[btn_sl]
115 | ld [hl],a
116 | add hl,bc
117 |
118 | ldh a,[btn_b]
119 | ld [hl],a
120 | add hl,bc
121 |
122 | ldh a,[btn_a]
123 | ld [hl],a
124 |
125 | reti
126 |
127 |
128 | ;-------------------------------------------------------------------------------
129 | parse_input:
130 | ;-------------------------------------------------------------------------------
131 |
132 | ld a,"-" ; button not pressed, you could write $2D instead
133 | ld hl,inputs ; 8 byte array that holds individual keys status
134 | ld c,8
135 | .clear
136 | ld [hl+],a ; mark all keys as not pressed
137 | dec c
138 | jr nz,.clear
139 |
140 | call read_keys ; read joypad
141 |
142 | ld a,"+" ; button pressed, you could write $2B instead
143 | dec l ; hl points here to next byte after inputs array, move it back to point on btn_a
144 | .btn_a
145 | bit 0,b ; is button a pressed ? (bit must be 1)
146 | jr z,.btn_b ; no, check other key (apparently it's 0)
147 | ldh [btn_a],a ; it is, mark it as +
148 | .btn_b
149 | bit 1,b ; ...
150 | jr z,.select
151 | ldh [btn_b],a
152 | .select
153 | bit 2,b
154 | jr z,.start
155 | ldh [btn_sl],a
156 | .start
157 | bit 3,b
158 | jr z,.right
159 | ldh [btn_st],a
160 | .right
161 | bit 4,b
162 | jr z,.left
163 | ldh [btn_rt],a
164 | .left
165 | bit 5,b
166 | jr z,.up
167 | ldh [btn_lt],a
168 | .up
169 | bit 6,b
170 | jr z,.down
171 | ldh [btn_up],a
172 | .down
173 | bit 7,b
174 | ret z
175 | ldh [btn_dn],a
176 |
177 | ret
178 |
179 |
180 | ;-------------------------------------------------------------------------------
181 | copy:
182 | ;-------------------------------------------------------------------------------
183 | ; hl - source address
184 | ; de - destination
185 | ; bc - size
186 |
187 | inc b
188 | inc c
189 | jr .skip
190 | .copy
191 | ld a,[hl+]
192 | ld [de],a
193 | inc de
194 | .skip
195 | dec c
196 | jr nz,.copy
197 | dec b
198 | jr nz,.copy
199 | ret
200 |
201 |
202 | ;-------------------------------------------------------------------------------
203 | copy_text:
204 | ;-------------------------------------------------------------------------------
205 | ; hl - text to display
206 | ; de - _SCRN0 or _SCRN1
207 | ; b - rows
208 | ; c - columns
209 |
210 | .next_row
211 | ld c,20
212 | .row
213 | ld a,[hl+] ; fetch one byte from text array and increase hl to point to another one
214 | ld [de],a ; store it at _SCRN0
215 | inc de ; unfortunately there's no [de+]
216 | dec c ; one byte done
217 | jr nz,.row ; next byte, copy untill c=0
218 |
219 | ld a,e ; our row = 20 which is what you can see on the screen
220 | add a,12 ; the part you don't see = 12, so we need to add it
221 | jr nc,.skip ; to make sure the next row is copied at right offset
222 | inc d ; nc flag is set when a+12 > 255
223 | .skip
224 | ld e,a
225 |
226 | dec b ; next row, copy untill b=0
227 | jr nz,.next_row
228 | ret
229 |
230 |
231 | ;-------------------------------------------------------------------------------
232 | fill:
233 | ;-------------------------------------------------------------------------------
234 | ; a - byte to fill with
235 | ; hl - destination address
236 | ; bc - size of area to fill
237 |
238 | inc b
239 | inc c
240 | jr .skip
241 | .fill
242 | ld [hl+],a
243 | .skip
244 | dec c
245 | jr nz,.fill
246 | dec b
247 | jr nz,.fill
248 | ret
249 |
250 |
251 | ;-------------------------------------------------------------------------------
252 | read_keys:
253 | ;-------------------------------------------------------------------------------
254 | ; this function returns two different values in b and c registers:
255 | ; b - returns raw state (pressing key triggers given action continuously as long as it's pressed - it does not prevent bouncing)
256 | ; c - returns debounced state (pressing key triggers given action only once - key must be released and pressed again)
257 |
258 | ld a,$20 ; read P15 - returns a, b, select, start
259 | ldh [rP1],a
260 | ldh a,[rP1] ; mandatory
261 | ldh a,[rP1]
262 | cpl ; rP1 returns not pressed keys as 1 and pressed as 0, invert it to make result more readable
263 | and $0f ; lower nibble has a, b, select, start state
264 | swap a
265 | ld b,a
266 |
267 | ld a,$10 ; read P14 - returns up, down, left, right
268 | ldh [rP1],a
269 | ldh a,[rP1] ; mandatory
270 | ldh a,[rP1]
271 | ldh a,[rP1]
272 | ldh a,[rP1]
273 | ldh a,[rP1]
274 | ldh a,[rP1]
275 | cpl ; rP1 returns not pressed keys as 1 and pressed as 0, invert it to make result more readable
276 | and $0f ; lower nibble has up, down, left, right state
277 | or b ; combine P15 and P14 states in one byte
278 | ld b,a ; store it
279 |
280 | ldh a,[previous] ; this is when important part begins, load previous P15 & P14 state
281 | xor b ; result will be 0 if it's the same as current read
282 | and b ; keep buttons that were pressed during this read only
283 | ldh [current],a ; store final result in variable and register
284 | ld c,a
285 | ld a,b ; current P15 & P14 state will be previous in next read
286 | ldh [previous],a
287 |
288 | ld a,$30 ; reset rP1
289 | ldh [rP1],a
290 |
291 | ret
292 |
293 |
294 | ;-------------------------------------------------------------------------------
295 |
296 | font:
297 | INCBIN "font_8x8.chr" ; converted with https://github.com/gitendo/bmp2cgb
298 |
299 | text:
300 | DB " Joypad state: "
301 | DB " "
302 | DB " "
303 | DB " [-] - Down "
304 | DB " [-] - Up "
305 | DB " [-] - Left "
306 | DB " [-] - Right "
307 | DB " [-] - Start "
308 | DB " [-] - Select "
309 | DB " [-] - B "
310 | DB " [-] - A "
311 |
312 | ;-------------------------------------------------------------------------------
313 |
314 |
315 | SECTION "Variables",HRAM
316 |
317 | current: DS 1 ; usually you read keys state and store it into variable for further processing
318 | previous: DS 1 ; this is previous keys state used by debouncing part of read_keys function
319 | inputs: ; array of buttons
320 | btn_dn: DS 1
321 | btn_up: DS 1
322 | btn_lt: DS 1
323 | btn_rt: DS 1
324 | btn_st: DS 1
325 | btn_sl: DS 1
326 | btn_b: DS 1
327 | btn_a: DS 1
--------------------------------------------------------------------------------
/dmg/large_picture.asm:
--------------------------------------------------------------------------------
1 | ; -----------------------------------------------------------------------------
2 | ; Example: Display picture composed of 355 unique tiles
3 | ; -----------------------------------------------------------------------------
4 | ; [gameboy demake] the secret of donkey kong island pixeled by tomic @ http://pixeljoint.com/pixelart/28278.htm
5 | ; More examples by tmk @ https://github.com/gitendo/helloworld
6 | ; -----------------------------------------------------------------------------
7 |
8 | INCLUDE "hardware.inc" ; system defines
9 |
10 | SECTION "VBL",ROM0[$0040] ; vblank interrupt handler
11 | jp vbl
12 |
13 | SECTION "LCDC",ROM0[$0048] ; lcdc interrupt handler
14 | jp lcdc
15 |
16 |
17 | SECTION "Start",ROM0[$100] ; start vector, followed by header data applied by rgbfix.exe
18 | nop
19 | jp start
20 |
21 | SECTION "Example",ROM0[$150] ; code starts here
22 |
23 | start:
24 | di ; disable interrupts
25 | ld sp,$E000 ; setup stack
26 |
27 | .wait_vbl ; wait for vblank to properly disable lcd
28 | ld a,[rLY]
29 | cp $90
30 | jr nz,.wait_vbl
31 |
32 | xor a ; reset important registers
33 | ld [rIF],a
34 | ld [rLCDC],a
35 | ld [rSTAT],a
36 | ld [rSCX],a
37 | ld [rSCY],a
38 | ld [rLYC],a
39 | ld [rIE],a
40 |
41 | ld hl,_RAM ; clear ram (fill with a which is 0 here)
42 | ld bc,$2000-2 ; watch out for stack ;)
43 | call fill
44 |
45 | ld hl,_HRAM ; clear hram
46 | ld c,$80 ; a = 0, b = 0 here, so let's save a byte and 4 cycles (ld c,$80 - 2/8 vs ld bc,$80 - 3/12)
47 | call fill
48 | ; no point in clearing vram, we'll overwrite it with picture data anyway
49 | ; lcdc is already disabled so we have 'easy' access to vram
50 |
51 | ld hl,picture_top_chr ; upper part takes 255 tiles
52 | ld de,_VRAM ; place it between $8000-8FFF (tiles are numbered here from 0 to 255)
53 | ld bc,4080 ; tsodki1.chr file size
54 | call copy
55 |
56 | ld hl,picture_bottom_chr ; bottom part takes 100 tiles
57 | ld de,_VRAM+$1000 ; place it between $8800-97FF (tiles are numbered here from -128 to 127)
58 | ld bc,1600 ; tsodki2.chr file size
59 | call copy
60 |
61 | ld hl,picture_top_map ; picture's map upper part (padded to 32 columns, so we can easily copy it)
62 | ld de,_SCRN0 ; tile map at $9800
63 | ld bc,416 ; tsodki1.map file size
64 | call copy
65 |
66 | ld hl,picture_bottom_map ; picture's map bottom part (also padded)
67 | ; de = _SCRN0+416, so we continue right after upper part
68 | ld bc,160 ; tsodki2.map file size
69 | call copy
70 |
71 | ld a,%00011011 ; bits: 7-6 = 1st color, 5-4 = 2nd, 3-2 = 3rd and 1-0 = 4th color
72 | ; color values: 00 - light, 01 - gray, 10 - dark gray, 11 - dark
73 | ld [rBGP],a ; bg palette
74 | ld [rOBP0],a ; obj palettes (not used in this example)
75 | ld [rOBP1],a
76 |
77 | ld a,104 ; this is where upper part of picture ends and bottom starts, we'll switch map base here
78 | ld [rLYC],a ; line at which lcdc interrupt will be fired
79 | ld a,STATF_LYC ; important!
80 | ld [rSTAT],a ; bit 6 needs to be set to make lcdc interrupt work
81 |
82 | ld a,IEF_VBLANK | IEF_LCDC ; vblank and lcdc interrupts
83 | ld [rIE],a ; setup
84 |
85 | ld a,LCDCF_ON | LCDCF_BG8000 | LCDCF_BG9800 | LCDCF_OBJ8 | LCDCF_OBJOFF | LCDCF_WINOFF | LCDCF_BGON
86 | ; lcd setup: tiles at $8000, map at $9800, 8x8 sprites (disabled), no window, etc.
87 | ld [rLCDC],a ; enable lcd
88 |
89 | ei ; enable interrupts
90 |
91 | .the_end
92 | halt ; save battery
93 | ; nop ; nop after halt is mandatory but rgbasm takes care of it :)
94 | jr .the_end ; endless loop
95 |
96 |
97 | lcdc: ; lcdc interrupt - executed every frame when LY=104 (end of picture's upper part)
98 | ld hl,rLCDC ; contains lcd setup
99 | res 4,[hl] ; change map location to $9C00, currently it's $9800
100 | reti
101 |
102 | vbl: ; vblank interrupt - executed every frame when LY=144
103 | ld hl,rLCDC ; contains lcd setup
104 | set 4,[hl] ; restore map location to $9800, currently it's $9C00
105 | reti ; return from interrupt
106 |
107 |
108 | ;-------------------------------------------------------------------------------
109 | copy:
110 | ;-------------------------------------------------------------------------------
111 | ; hl - source address
112 | ; de - destination
113 | ; bc - size
114 |
115 | inc b
116 | inc c
117 | jr .skip
118 | .copy
119 | ld a,[hl+]
120 | ld [de],a
121 | inc de
122 | .skip
123 | dec c
124 | jr nz,.copy
125 | dec b
126 | jr nz,.copy
127 | ret
128 |
129 | ;-------------------------------------------------------------------------------
130 | fill:
131 | ;-------------------------------------------------------------------------------
132 | ; a - byte to fill with
133 | ; hl - destination address
134 | ; bc - size of area to fill
135 |
136 | inc b
137 | inc c
138 | jr .skip
139 | .fill
140 | ld [hl+],a
141 | .skip
142 | dec c
143 | jr nz,.fill
144 | dec b
145 | jr nz,.fill
146 | ret
147 |
148 | ;-------------------------------------------------------------------------------
149 |
150 | picture_top_chr: ; bmp2cgb -e255 tsodki1.bmp (there's no x,y,x/y duplicates)
151 | INCBIN "tsodki1.chr"
152 | picture_top_map:
153 | INCBIN "tsodki1.map"
154 | picture_bottom_chr: ; bmp2cgb -e255 tsodki1.bmp (there's no x,y,x/y duplicates)
155 | INCBIN "tsodki2.chr"
156 | picture_bottom_map:
157 | INCBIN "tsodki2.map"
158 |
--------------------------------------------------------------------------------
/dmg/meta_sprite.asm:
--------------------------------------------------------------------------------
1 | ; -----------------------------------------------------------------------------
2 | ; Example: Meta sprite
3 | ; -----------------------------------------------------------------------------
4 | ; Knight pixelled by Stratto @ http://pixeljoint.com/pixelart/52412.htm
5 | ; More examples by tmk @ https://github.com/gitendo/helloworld
6 | ; -----------------------------------------------------------------------------
7 |
8 | INCLUDE "hardware.inc" ; system defines
9 |
10 | SECTION "VBL",ROM0[$0040] ; vblank interrupt handler
11 | jp vbl
12 |
13 | SECTION "Start",ROM0[$100] ; start vector, followed by header data applied by rgbfix.exe
14 | nop
15 | jp start
16 |
17 | SECTION "Example",ROM0[$150] ; code starts here
18 |
19 | start:
20 | di ; disable interrupts
21 | ld sp,$E000 ; setup stack
22 |
23 | .wait_vbl ; wait for vblank to properly disable lcd
24 | ld a,[rLY]
25 | cp $90
26 | jr nz,.wait_vbl
27 |
28 | xor a
29 | ld [rIF],a ; reset important registers
30 | ld [rLCDC],a
31 | ld [rSTAT],a
32 | ld [rSCX],a
33 | ld [rSCY],a
34 | ld [rLYC],a
35 | ld [rIE],a
36 |
37 | ld hl,_RAM ; clear ram (fill with a which is 0 here)
38 | ld bc,$2000-2 ; watch out for stack ;)
39 | call fill
40 |
41 | ld hl,_HRAM ; clear hram
42 | ld c,$80 ; a = 0, b = 0 here, so let's save a byte and 4 cycles (ld c,$80 - 2/8 vs ld bc,$80 - 3/12)
43 | call fill
44 |
45 | ld hl,_VRAM ; clear vram
46 | ld b,$18 ; a = 0, bc should be $1800; c = 0 here, so..
47 | call fill
48 |
49 | ld a,$10 ; tile number to fill the _SCRN0 with - 16 tiles is used for meta sprite, rest is empty
50 |
51 | ; no need to setup hl since _SCRN0 ($9800) and _SCRN1 ($9C00) are part of _VRAM, just continue
52 |
53 | ld b,8 ; bc should be $800 (_SCRN0/1 are 32*32 bytes); c = 0 here, so..
54 | call fill
55 |
56 | ld a,%00011110 ; bits: 7-6 = 1st color, 5-4 = 2nd, 3-2 = 3rd and 1-0 = 4th color
57 | ; color values: 00 - light, 01 - gray, 10 - dark gray, 11 - dark
58 | ld [rBGP],a ; bg palette
59 | ld [rOBP0],a ; obj palettes
60 | ld [rOBP1],a
61 |
62 | ld hl,knight ; tiles used as sprites
63 | ld de,_VRAM
64 | ld bc,256 ; tiles size
65 | call copy
66 |
67 | ld c,$80 ; dma sub will be copied to _HRAM, at $FF80
68 | ld b,dma_sub_end-dma_sub_start ; size of dma sub, which is 10 bytes
69 | ld hl,dma_sub_start ; dma sub code
70 | .copy
71 | ld a,[hl+]
72 | ld [c],a
73 | inc c
74 | dec b
75 | jr nz,.copy
76 |
77 | ld hl,knight_oam_start ; precalculated part of OAM table that contains our meta sprite
78 | ld de,_RAM ; OAM table mirror is located at $C000
79 | ld bc,knight_oam_end-knight_oam_start
80 | call copy
81 |
82 | ld a,IEF_VBLANK ; setup vblank interrupt
83 | ld [rIE],a
84 |
85 | ld a,LCDCF_ON | LCDCF_BG8000 | LCDCF_BG9800 | LCDCF_OBJ16 | LCDCF_OBJON | LCDCF_WINOFF | LCDCF_BGON
86 | ; lcd setup: tiles at $8000, map at $9800, 8x16 sprites (enabled), no window, etc.
87 | ld [rLCDC],a ; enable lcd
88 |
89 | ei ; enable interrupts
90 |
91 | .the_end
92 | halt ; save battery
93 | ; nop ; nop after halt is mandatory but rgbasm takes care of it :)
94 | jr .the_end ; endless loop
95 |
96 |
97 | vbl:
98 | call $FF80
99 | reti
100 |
101 | ;-------------------------------------------------------------------------------
102 | copy:
103 | ;-------------------------------------------------------------------------------
104 | ; hl - source address
105 | ; de - destination
106 | ; bc - size
107 |
108 | inc b
109 | inc c
110 | jr .skip
111 | .copy
112 | ld a,[hl+]
113 | ld [de],a
114 | inc de
115 | .skip
116 | dec c
117 | jr nz,.copy
118 | dec b
119 | jr nz,.copy
120 | ret
121 |
122 | ;-------------------------------------------------------------------------------
123 | fill:
124 | ;-------------------------------------------------------------------------------
125 | ; a - byte to fill with
126 | ; hl - destination address
127 | ; bc - size of area to fill
128 |
129 | inc b
130 | inc c
131 | jr .skip
132 | .fill
133 | ld [hl+],a
134 | .skip
135 | dec c
136 | jr nz,.fill
137 | dec b
138 | jr nz,.fill
139 | ret
140 |
141 |
142 | ;-------------------------------------------------------------------------------
143 |
144 | dma_sub_start:
145 | db $3E,$C0 ; ld a,$C0 ; OAM table mirror in RAM at $C000
146 | db $E0,$46 ; ld [rDMA],a
147 | db $3E,$28 ; ld a,40 ; delay = 160 cycles
148 | ;.copy
149 | db $3D ; dec a
150 | db $20,$FD ; jr nz,.copy
151 | db $C9 ; ret
152 | dma_sub_end:
153 |
154 | ;-------------------------------------------------------------------------------
155 |
156 | ; knight gfx is 32x32 px, so when using 8x8 sprites tile order wouldn't need to be shuffled, they'd be stored one after another:
157 |
158 | ; 0 1 2 3
159 | ; 4 5 6 7
160 | ; 8 9 a b
161 | ; c d e f
162 |
163 | ; but for 8x16 sprites we need to do place the tiles like this:
164 |
165 | ; 0 4 1 5
166 | ; 2 6 3 7
167 | ; 8 C 9 D
168 | ; A E B F
169 |
170 | knight:
171 | db $00,$00,$00,$00,$1C,$00,$12,$0C,$09,$06,$09,$06,$08,$07,$04,$03 ; 0
172 | db $04,$03,$02,$01,$01,$00,$00,$00,$03,$00,$04,$03,$08,$07,$10,$0F ; 4
173 | db $00,$00,$07,$00,$18,$07,$26,$1F,$46,$3F,$9E,$7F,$9F,$7F,$1F,$FF ; 1
174 | db $1E,$F1,$1F,$F0,$9F,$7E,$9F,$7E,$9F,$7E,$DF,$BF,$FF,$C0,$FF,$D0 ; 5
175 | db $00,$00,$00,$00,$C1,$00,$63,$C1,$77,$E3,$7F,$F3,$FF,$F7,$F7,$FE ; 2
176 | db $DF,$BE,$DE,$3C,$BC,$70,$B8,$70,$AE,$70,$F1,$EE,$F9,$06,$F8,$17 ; 6
177 | db $00,$00,$00,$00,$C0,$00,$C0,$80,$80,$00,$80,$00,$80,$00,$00,$00 ; 3
178 | db $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$30,$00,$D8,$30 ; 7
179 | db $10,$0F,$11,$0F,$0F,$00,$0F,$00,$0B,$07,$0B,$07,$0B,$07,$0B,$07 ; 8
180 | db $0B,$06,$0F,$00,$08,$07,$08,$07,$07,$00,$00,$00,$00,$00,$00,$00 ; c
181 | db $DF,$AF,$DF,$AE,$D6,$2D,$CC,$33,$D9,$37,$B3,$4E,$A7,$5C,$CE,$3B ; 9
182 | db $9E,$77,$FB,$2C,$FF,$80,$FC,$00,$98,$60,$18,$60,$78,$00,$98,$60 ; d
183 | db $F8,$07,$FF,$C8,$7F,$C8,$EF,$98,$CC,$33,$DC,$E3,$FF,$18,$77,$F8 ; a
184 | db $77,$F8,$D7,$38,$FF,$00,$7E,$01,$C8,$37,$CF,$30,$F0,$00,$C8,$30 ; e
185 | db $8C,$78,$76,$8C,$FA,$04,$FB,$06,$7B,$86,$F9,$06,$52,$EC,$C4,$F8 ; b
186 | db $08,$F0,$90,$60,$20,$C0,$40,$80,$80,$00,$00,$00,$00,$00,$00,$00 ; f
187 |
188 | x equ 72 ; sprite x coordinate
189 | y equ 72 ; sprite y xoordinate
190 |
191 | ; 7 6 5 4 3 2 1 0
192 | ; y, x, chr, atr (priority, v-flip, h-flip, dmg pal, bank, palette, palette, palette)
193 |
194 | knight_oam_start: ; knight gfx is 32x32 px (16 tiles) but we use 8x16 sprites, so we need 8 of them
195 | db y+00, x+00, $00, %00000000 ; 1st row
196 | db y+00, x+08, $02, %00000000
197 | db y+00, x+16, $04, %00000000
198 | db y+00, x+24, $06, %00000000
199 | db y+16, x+00, $08, %00000000 ; 2nd row
200 | db y+16, x+08, $0a, %00000000
201 | db y+16, x+16, $0c, %00000000
202 | db y+16, x+24, $0e, %00000000
203 | knight_oam_end:
204 |
--------------------------------------------------------------------------------
/dmg/picture.asm:
--------------------------------------------------------------------------------
1 | ; -----------------------------------------------------------------------------
2 | ; Example: Display picture composed of 242 unique tiles
3 | ; -----------------------------------------------------------------------------
4 | ; Gameboy Horror pixeled by vassink @ http://pixeljoint.com/pixelart/61800.htm
5 | ; More examples by tmk @ https://github.com/gitendo/helloworld
6 | ; -----------------------------------------------------------------------------
7 |
8 | INCLUDE "hardware.inc" ; system defines
9 |
10 | SECTION "Start",ROM0[$100] ; start vector, followed by header data applied by rgbfix.exe
11 | nop
12 | jp start
13 |
14 | SECTION "Example",ROM0[$150] ; code starts here
15 |
16 | start:
17 | di ; disable interrupts
18 | ld sp,$E000 ; setup stack
19 |
20 | .wait_vbl ; wait for vblank to properly disable lcd
21 | ld a,[rLY]
22 | cp $90
23 | jr nz,.wait_vbl
24 |
25 | xor a ; reset important registers
26 | ld [rIF],a
27 | ld [rLCDC],a
28 | ld [rSTAT],a
29 | ld [rSCX],a
30 | ld [rSCY],a
31 | ld [rLYC],a
32 | ld [rIE],a
33 |
34 | ld hl,_RAM ; clear ram (fill with a which is 0 here)
35 | ld bc,$2000-2 ; watch out for stack ;)
36 | call fill
37 |
38 | ld hl,_HRAM ; clear hram
39 | ld c,$80 ; a = 0, b = 0 here, so let's save a byte and 4 cycles (ld c,$80 - 2/8 vs ld bc,$80 - 3/12)
40 | call fill
41 | ; no point in clearing vram, we'll overwrite it with picture data anyway
42 | ; lcdc is already disabled so we have 'easy' access to vram
43 |
44 | ld hl,picture_chr ; picture data
45 | ld de,_VRAM ; place it between $8000-8FFF (tiles are numbered here from 0 to 255)
46 | ld bc,3872 ; gbhorror.chr file size
47 | call copy
48 |
49 | ld hl,picture_map ; picture map (not padded, 160x144px = 20*18)
50 | ld de,_SCRN0 ; place it at $9800
51 | call copy_map ; should have used bmp2cgb with -e option :)
52 |
53 | ld a,%00011011 ; bits: 7-6 = 1st color, 5-4 = 2nd, 3-2 = 3rd and 1-0 = 4th color
54 | ; color values: 00 - light, 01 - gray, 10 - dark gray, 11 - dark
55 | ld [rBGP],a ; bg palette
56 | ld [rOBP0],a ; obj palettes (not used in this example)
57 | ld [rOBP1],a
58 |
59 | ld a,LCDCF_ON | LCDCF_BG8000 | LCDCF_BG9800 | LCDCF_OBJ8 | LCDCF_OBJOFF | LCDCF_WINOFF | LCDCF_BGON
60 | ; lcd setup: tiles at $8000, map at $9800, 8x8 sprites (disabled), no window, etc.
61 | ld [rLCDC],a ; enable lcd
62 |
63 | .the_end
64 | halt ; save battery
65 | ; nop ; nop after halt is mandatory but rgbasm takes care of it :)
66 | jr .the_end ; endless loop
67 |
68 |
69 | ;-------------------------------------------------------------------------------
70 | copy:
71 | ;-------------------------------------------------------------------------------
72 | ; hl - source address
73 | ; de - destination
74 | ; bc - size
75 |
76 | inc b
77 | inc c
78 | jr .skip
79 | .copy
80 | ld a,[hl+]
81 | ld [de],a
82 | inc de
83 | .skip
84 | dec c
85 | jr nz,.copy
86 | dec b
87 | jr nz,.copy
88 | ret
89 |
90 |
91 | ;-------------------------------------------------------------------------------
92 | copy_map:
93 | ;-------------------------------------------------------------------------------
94 | ; hl - map data
95 | ; de - _SCRN0 or _SCRN1
96 | ; b - rows
97 | ; c - columns
98 | ; picture is 160x144px,
99 | ld b,18 ; 144/8 = 18 rows
100 | .next_row
101 | ld c,20 ; 160/8 = 20 tiles each
102 | .row
103 | ld a,[hl+] ; fetch one byte from rom and increase hl to point to another one
104 | ld [de],a ; store it at _SCRN0
105 | inc de ; unfortunately there's no [de+]
106 | dec c ; one byte done
107 | jr nz,.row ; next byte, copy untill c=0
108 |
109 | ld a,e ; our row = 20 which is what you can see on the screen
110 | add a,12 ; the part you don't see is 12, so we need to add it
111 | jr nc,.skip ; to make sure the next row is copied at right offset
112 | inc d ; nc flag is set when a+12 > 255
113 | .skip
114 | ld e,a
115 |
116 | dec b ; next row, copy untill b=0
117 | jr nz,.next_row
118 | ret
119 |
120 |
121 | ;-------------------------------------------------------------------------------
122 | fill:
123 | ;-------------------------------------------------------------------------------
124 | ; a - byte to fill with
125 | ; hl - destination address
126 | ; bc - size of area to fill
127 |
128 | inc b
129 | inc c
130 | jr .skip
131 | .fill
132 | ld [hl+],a
133 | .skip
134 | dec c
135 | jr nz,.fill
136 | dec b
137 | jr nz,.fill
138 | ret
139 |
140 | ;-------------------------------------------------------------------------------
141 |
142 | picture_chr: ; bmp2cgb -x -y -z gbhorror.bmp
143 | INCBIN "gbhorror.chr"
144 | picture_map:
145 | INCBIN "gbhorror.map"
146 |
--------------------------------------------------------------------------------
/dmg/score_bcd.asm:
--------------------------------------------------------------------------------
1 | ; -----------------------------------------------------------------------------
2 | ; Example: Game score in Binary Coded Decimal
3 | ; -----------------------------------------------------------------------------
4 | ; This is alternative approach to score_hex.asm. If you've never heard of BCD
5 | ; here's some reading: https://ehaskins.com/2018-01-30%20Z80%20DAA/
6 | ; Font comes from ZX Spectrum - https://en.wikipedia.org/wiki/ZX_Spectrum_character_set
7 | ; More examples by tmk @ https://github.com/gitendo/helloworld
8 | ; -----------------------------------------------------------------------------
9 |
10 | INCLUDE "hardware.inc" ; system defines
11 |
12 | SECTION "VBL",ROM0[$0040] ; vblank interrupt handler
13 | jp vbl
14 |
15 | SECTION "Start",ROM0[$100] ; start vector, followed by header data applied by rgbfix.exe
16 | nop
17 | jp start
18 |
19 | SECTION "Example",ROM0[$150] ; code starts here
20 |
21 | start:
22 | di ; disable interrupts
23 | ld sp,$E000 ; setup stack
24 |
25 | .wait_vbl ; wait for vblank to properly disable lcd
26 | ld a,[rLY]
27 | cp $90
28 | jr nz,.wait_vbl
29 |
30 | xor a
31 | ld [rIF],a ; reset important registers
32 | ld [rLCDC],a
33 | ld [rSTAT],a
34 | ld [rSCX],a
35 | ld [rSCY],a
36 | ld [rLYC],a
37 | ld [rIE],a
38 |
39 | ld hl,_RAM ; clear ram (fill with a which is 0 here)
40 | ld bc,$2000-2 ; watch out for stack ;)
41 | call fill
42 |
43 | ld hl,_HRAM ; clear hram
44 | ld c,$80 ; a = 0, b = 0 here, so let's save a byte and 4 cycles (ld c,$80 - 2/8 vs ld bc,$80 - 3/12)
45 | call fill
46 |
47 | ld hl,_VRAM ; clear vram, lcdc is disabled so you have 'easy' access
48 | ld b,$18 ; a = 0, bc should be $1800; c = 0 here, so..
49 | call fill
50 |
51 | ld a,$20 ; ascii code for 'space' character
52 |
53 | ; no need to setup hl since _SCRN0 ($9800) and _SCRN1 ($9C00) are part of _VRAM, just continue
54 |
55 | ld b,8 ; bc should be $800 (_SCRN0/1 are 32*32 bytes); c = 0 here, so..
56 | call fill
57 |
58 | ld a,%10010011 ; bits: 7-6 = 1st color, 5-4 = 2nd, 3-2 = 3rd and 1-0 = 4th color
59 | ; color values: 00 - light, 01 - gray, 10 - dark gray, 11 - dark
60 | ld [rBGP],a ; bg palette
61 | ld [rOBP0],a ; obj palettes (not used in this example)
62 | ld [rOBP1],a
63 |
64 | ld hl,font ; font data
65 | ld de,_VRAM+$200 ; place it here to get ascii mapping ('space' code is $20, tile size $10)
66 | ld bc,1776 ; font_8x8.chr file size
67 | call copy
68 |
69 | ld hl,text ; menu text
70 | ld de,_SCRN0+$A0 ; center it a bit
71 | ld b,8 ; it has 8 lines
72 | call copy_text
73 |
74 | ld a,IEF_VBLANK ; vblank interrupt
75 | ld [rIE],a ; setup
76 |
77 | ld a,LCDCF_ON | LCDCF_BG8000 | LCDCF_BG9800 | LCDCF_OBJ8 | LCDCF_OBJOFF | LCDCF_WINOFF | LCDCF_BGON
78 | ; lcd setup: tiles at $8000, map at $9800, 8x8 sprites (disabled), no window, etc.
79 | ld [rLCDC],a ; enable lcd
80 |
81 | ei ; enable interrupts
82 |
83 | .loop
84 | call parse_input ; read joypad and update inputs array that holds individual keys status
85 | halt ; save battery
86 | ; nop ; nop after halt is mandatory but rgbasm takes care of it :)
87 | jr .loop ; endless loop
88 |
89 |
90 | vbl: ; update screen
91 | ld hl,score
92 | ld de,_SCRN0+$E7 ; this points exactly at map coordinate where score string is stored
93 | ld c,3 ; score takes 3 bytes, each byte holds 2 digits
94 | .copy ; copy from hram to vram without waiting for access since it's vblank
95 | ld a,[hl+] ; get byte
96 | ld b,a ; store it for further processing
97 | and a,$F0 ; leave upper nible, remove lower one
98 | swap a ; swap nibbles with places, lower is upper now and upper is lower
99 | or $30 ; upper nibble is 3, lower keeps its value - we have valid number in ascii notation now
100 | ld [de],a ; put it on screen - map actually
101 | inc de ; next map entry
102 | ld a,b ; restore byte and repeat process above to lower nibble
103 | and a,$0F
104 | or $30
105 | ld [de],a
106 | inc de
107 | dec c ; repeat 3 times
108 | jr nz,.copy
109 |
110 | reti
111 |
112 |
113 | ;-------------------------------------------------------------------------------
114 | parse_input:
115 | ;-------------------------------------------------------------------------------
116 |
117 | call read_keys ; read joypad
118 |
119 | .btn_a
120 | bit 0,c ; is button a pressed ? (bit must be 1)
121 | jr z,.btn_b ; no, check other key (apparently it's 0)
122 | ld bc,1 ; 1 - thousands and hundreds
123 | ld a,$30 ; increase score by 3000
124 | call increase_score ; read explanation there
125 | ret
126 |
127 | .btn_b
128 | bit 1,c ; ...
129 | jr z,.right
130 | ld bc,1
131 | ld a,$30 ; decrease score by 3000
132 | call decrease_score
133 | ret
134 |
135 | .right
136 | bit 4,b ; b has no debounce check, counter will be increasing while button is pressed
137 | jr z,.left
138 | ld bc,2 ; 2 - tens and ones
139 | ld a,$01 ; increase score by 1
140 | call increase_score
141 | ret
142 |
143 | .left
144 | bit 5,b
145 | jr z,.up
146 | ld bc,2
147 | ld a,$01 ; decrease score by 1
148 | call decrease_score
149 | ret
150 |
151 | .up
152 | bit 6,c
153 | jr z,.down
154 | ld bc,2 ; 2 - tens and ones
155 | ld a,$20 ; increase score by 20
156 | call increase_score
157 | ret
158 |
159 | .down
160 | bit 7,c
161 | jr z,.done
162 | ld bc,2
163 | ld a,$20 ; decrease score by 20
164 | call decrease_score
165 |
166 | .done
167 | ret
168 |
169 |
170 | ;-------------------------------------------------------------------------------
171 | copy:
172 | ;-------------------------------------------------------------------------------
173 | ; hl - source address
174 | ; de - destination
175 | ; bc - size
176 |
177 | inc b
178 | inc c
179 | jr .skip
180 | .copy
181 | ld a,[hl+]
182 | ld [de],a
183 | inc de
184 | .skip
185 | dec c
186 | jr nz,.copy
187 | dec b
188 | jr nz,.copy
189 | ret
190 |
191 |
192 | ;-------------------------------------------------------------------------------
193 | copy_text:
194 | ;-------------------------------------------------------------------------------
195 | ; hl - text to display
196 | ; de - _SCRN0 or _SCRN1
197 | ; b - rows
198 | ; c - columns
199 |
200 | .next_row
201 | ld c,20
202 | .row
203 | ld a,[hl+] ; fetch one byte from text array and increase hl to point to another one
204 | ld [de],a ; store it at _SCRN0
205 | inc de ; unfortunately there's no [de+]
206 | dec c ; one byte done
207 | jr nz,.row ; next byte, copy untill c=0
208 |
209 | ld a,e ; our row = 20 which is what you can see on the screen
210 | add a,12 ; the part you don't see = 12, so we need to add it
211 | jr nc,.skip ; to make sure the next row is copied at right offset
212 | inc d ; nc flag is set when a+12 > 255
213 | .skip
214 | ld e,a
215 |
216 | dec b ; next row, copy untill b=0
217 | jr nz,.next_row
218 | ret
219 |
220 |
221 | ;-------------------------------------------------------------------------------
222 | fill:
223 | ;-------------------------------------------------------------------------------
224 | ; a - byte to fill with
225 | ; hl - destination address
226 | ; bc - size of area to fill
227 |
228 | inc b
229 | inc c
230 | jr .skip
231 | .fill
232 | ld [hl+],a
233 | .skip
234 | dec c
235 | jr nz,.fill
236 | dec b
237 | jr nz,.fill
238 | ret
239 |
240 |
241 | ;-------------------------------------------------------------------------------
242 | read_keys:
243 | ;-------------------------------------------------------------------------------
244 | ; this function returns two different values in b and c registers:
245 | ; b - returns raw state (pressing key triggers given action continuously as long as it's pressed - it does not prevent bouncing)
246 | ; c - returns debounced state (pressing key triggers given action only once - key must be released and pressed again)
247 |
248 | ld a,$20 ; read P15 - returns a, b, select, start
249 | ldh [rP1],a
250 | ldh a,[rP1] ; mandatory
251 | ldh a,[rP1]
252 | cpl ; rP1 returns not pressed keys as 1 and pressed as 0, invert it to make result more readable
253 | and $0f ; lower nibble has a, b, select, start state
254 | swap a
255 | ld b,a
256 |
257 | ld a,$10 ; read P14 - returns up, down, left, right
258 | ldh [rP1],a
259 | ldh a,[rP1] ; mandatory
260 | ldh a,[rP1]
261 | ldh a,[rP1]
262 | ldh a,[rP1]
263 | ldh a,[rP1]
264 | ldh a,[rP1]
265 | cpl ; rP1 returns not pressed keys as 1 and pressed as 0, invert it to make result more readable
266 | and $0f ; lower nibble has up, down, left, right state
267 | or b ; combine P15 and P14 states in one byte
268 | ld b,a ; store it
269 |
270 | ldh a,[previous] ; this is when important part begins, load previous P15 & P14 state
271 | xor b ; result will be 0 if it's the same as current read
272 | and b ; keep buttons that were pressed during this read only
273 | ldh [current],a ; store final result in variable and register
274 | ld c,a
275 | ld a,b ; current P15 & P14 state will be previous in next read
276 | ldh [previous],a
277 |
278 | ld a,$30 ; reset rP1
279 | ldh [rP1],a
280 |
281 | ret
282 |
283 |
284 | ;-------------------------------------------------------------------------------
285 | increase_score:
286 | ;-------------------------------------------------------------------------------
287 | ; score consists of 3 bytes, each byte holds two digits in bcd format ie. 00 - 99
288 |
289 | ; bc - points to a pair of digits in score
290 | ; 0 - hundreds of thousands and tens of thousands, 1 - thousands and hundreds, 2 - tens and ones
291 |
292 | ; a - value of register (upper/lower byte) decides which digit gets increased, use bcd values only ie. $01, $20, $09, etc.
293 |
294 | ; hl - score offset in ram
295 |
296 | ld hl,score ; get offset
297 | add hl,bc ; move to a pair of digits to be updated
298 | inc c ; recycle pointer to a counter of pair of digits left
299 |
300 | add a,[hl] ; add selected pair of digits to value
301 | daa ; keep result as bcd
302 | ld [hl-],a ; store it and move to another pair of digits
303 | ret nc ; carry flag is set when overflow occurs (ie. $99 + $20 = $19), we need to update other pairs then
304 |
305 | .recurse
306 | dec c ; counter keeps track of pair of digits we're dealing with
307 | ret z
308 | ld a,b ; b = 0 here, we save 1 byte and 4 cycles by not using ld a,0
309 | adc a,[hl] ; carry flag is set so 1 will be added to adjacent pair of digits
310 | daa ; keep result as bcd
311 | ld [hl-],a ; store it
312 | call c,.recurse ; if there's overflow go to another pair of digits (update the rest of the score)
313 | ret
314 |
315 | ;-------------------------------------------------------------------------------
316 | decrease_score:
317 | ;-------------------------------------------------------------------------------
318 | ; clone of increase_score that does subtraction, look at the comments above
319 |
320 | ld hl,score
321 | add hl,bc
322 | inc c
323 |
324 | ld b,a
325 | ld a,[hl]
326 | sub a,b
327 | daa
328 | ld [hl-],a
329 | ret nc
330 | ld b,0
331 |
332 | .recurse
333 | dec c
334 | ret z
335 | ld a,[hl]
336 | sbc a,b
337 | daa
338 | ld [hl-],a
339 | call c,.recurse
340 | ret
341 |
342 |
343 | ;-------------------------------------------------------------------------------
344 |
345 | font:
346 | INCBIN "font_8x8.chr" ; converted with https://github.com/gitendo/bmp2cgb
347 |
348 | text:
349 | DB " Score: "
350 | DB " "
351 | DB " 00000 "
352 | DB " "
353 | DB " Press UP or DOWN, "
354 | DB " LEFT or RIGHT, "
355 | DB " A or B "
356 | DB " to update score. "
357 |
358 | ;-------------------------------------------------------------------------------
359 |
360 |
361 | SECTION "Variables",HRAM
362 |
363 | score: DS 3 ; score in bcd format, ranges from 000000 to 999999, should be enough for most games ;)
364 | current: DS 1 ; usually you read keys state and store it into variable for further processing
365 | previous: DS 1 ; this is previous keys state used by debouncing part of read_keys function
366 |
--------------------------------------------------------------------------------
/dmg/score_hex.asm:
--------------------------------------------------------------------------------
1 | ; -----------------------------------------------------------------------------
2 | ; Example: Game score in hexadecimal
3 | ; -----------------------------------------------------------------------------
4 | ; Font comes from ZX Spectrum - https://en.wikipedia.org/wiki/ZX_Spectrum_character_set
5 | ; More examples by tmk @ https://github.com/gitendo/helloworld
6 | ; -----------------------------------------------------------------------------
7 |
8 | INCLUDE "hardware.inc" ; system defines
9 |
10 | SECTION "VBL",ROM0[$0040] ; vblank interrupt handler
11 | jp vbl
12 |
13 | SECTION "Start",ROM0[$100] ; start vector, followed by header data applied by rgbfix.exe
14 | nop
15 | jp start
16 |
17 | SECTION "Example",ROM0[$150] ; code starts here
18 |
19 | start:
20 | di ; disable interrupts
21 | ld sp,$E000 ; setup stack
22 |
23 | .wait_vbl ; wait for vblank to properly disable lcd
24 | ld a,[rLY]
25 | cp $90
26 | jr nz,.wait_vbl
27 |
28 | xor a
29 | ld [rIF],a ; reset important registers
30 | ld [rLCDC],a
31 | ld [rSTAT],a
32 | ld [rSCX],a
33 | ld [rSCY],a
34 | ld [rLYC],a
35 | ld [rIE],a
36 |
37 | ld hl,_RAM ; clear ram (fill with a which is 0 here)
38 | ld bc,$2000-2 ; watch out for stack ;)
39 | call fill
40 |
41 | ld hl,_HRAM ; clear hram
42 | ld c,$80 ; a = 0, b = 0 here, so let's save a byte and 4 cycles (ld c,$80 - 2/8 vs ld bc,$80 - 3/12)
43 | call fill
44 |
45 | ld hl,_VRAM ; clear vram, lcdc is disabled so you have 'easy' access
46 | ld b,$18 ; a = 0, bc should be $1800; c = 0 here, so..
47 | call fill
48 |
49 | ld a,$20 ; ascii code for 'space' character
50 |
51 | ; no need to setup hl since _SCRN0 ($9800) and _SCRN1 ($9C00) are part of _VRAM, just continue
52 |
53 | ld b,8 ; bc should be $800 (_SCRN0/1 are 32*32 bytes); c = 0 here, so..
54 | call fill
55 |
56 | ld a,%10010011 ; bits: 7-6 = 1st color, 5-4 = 2nd, 3-2 = 3rd and 1-0 = 4th color
57 | ; color values: 00 - light, 01 - gray, 10 - dark gray, 11 - dark
58 | ld [rBGP],a ; bg palette
59 | ld [rOBP0],a ; obj palettes (not used in this example)
60 | ld [rOBP1],a
61 |
62 | ld hl,font ; font data
63 | ld de,_VRAM+$200 ; place it here to get ascii mapping ('space' code is $20, tile size $10)
64 | ld bc,1776 ; font_8x8.chr file size
65 | call copy
66 |
67 | ld hl,text ; menu text
68 | ld de,_SCRN0+$A0 ; center it a bit
69 | ld b,6 ; it has 6 lines
70 | call copy_text
71 |
72 | ld a,IEF_VBLANK ; vblank interrupt
73 | ld [rIE],a ; setup
74 |
75 | ld a,LCDCF_ON | LCDCF_BG8000 | LCDCF_BG9800 | LCDCF_OBJ8 | LCDCF_OBJOFF | LCDCF_WINOFF | LCDCF_BGON
76 | ; lcd setup: tiles at $8000, map at $9800, 8x8 sprites (disabled), no window, etc.
77 | ld [rLCDC],a ; enable lcd
78 |
79 | ei ; enable interrupts
80 |
81 | .loop
82 | call parse_input ; read joypad and update inputs array that holds individual keys status
83 | halt ; save battery
84 | ; nop ; nop after halt is mandatory but rgbasm takes care of it :)
85 | jr .loop ; endless loop
86 |
87 |
88 | vbl: ; update screen
89 | ld hl,ascii_score
90 | ld de,_SCRN0+$E7 ; this points exactly at map coordinate where score string is stored
91 | ld c,5 ; score string length
92 | .copy ; copy from hram to vram without waiting for access since it's vblank
93 | ld a,[hl+]
94 | ld [de],a
95 | inc de
96 | dec c
97 | jr nz,.copy
98 |
99 |
100 | reti
101 |
102 |
103 | ;-------------------------------------------------------------------------------
104 | parse_input:
105 | ;-------------------------------------------------------------------------------
106 | ldh a,[hex_score_h] ; score high byte
107 | ld h,a
108 | ldh a,[hex_score_l] ; score low byte
109 | ld l,a
110 |
111 | call read_keys ; read joypad
112 |
113 | .up
114 | bit 6,b ; joypad state in b has no debounce check (reads constantly pressed buttons) as opposite to c
115 | jr z,.down ; up not pressed, check down
116 | inc hl ; increase score
117 | .down
118 | bit 7,b
119 | jr z,.done ; down not pressed
120 | dec hl ; decrease score
121 | .done
122 | ld a,h ; store current score value in ram
123 | ldh [hex_score_h],a
124 | ld a,l
125 | ldh [hex_score_l],a
126 |
127 | ld c,LOW(ascii_score) ; HRAM offset at which decimal ascii string representing score will be stored
128 | call update_score
129 |
130 | ret
131 |
132 |
133 | ;-------------------------------------------------------------------------------
134 | copy:
135 | ;-------------------------------------------------------------------------------
136 | ; hl - source address
137 | ; de - destination
138 | ; bc - size
139 |
140 | inc b
141 | inc c
142 | jr .skip
143 | .copy
144 | ld a,[hl+]
145 | ld [de],a
146 | inc de
147 | .skip
148 | dec c
149 | jr nz,.copy
150 | dec b
151 | jr nz,.copy
152 | ret
153 |
154 |
155 | ;-------------------------------------------------------------------------------
156 | copy_text:
157 | ;-------------------------------------------------------------------------------
158 | ; hl - text to display
159 | ; de - _SCRN0 or _SCRN1
160 | ; b - rows
161 | ; c - columns
162 |
163 | .next_row
164 | ld c,20
165 | .row
166 | ld a,[hl+] ; fetch one byte from text array and increase hl to point to another one
167 | ld [de],a ; store it at _SCRN0
168 | inc de ; unfortunately there's no [de+]
169 | dec c ; one byte done
170 | jr nz,.row ; next byte, copy untill c=0
171 |
172 | ld a,e ; our row = 20 which is what you can see on the screen
173 | add a,12 ; the part you don't see = 12, so we need to add it
174 | jr nc,.skip ; to make sure the next row is copied at right offset
175 | inc d ; nc flag is set when a+12 > 255
176 | .skip
177 | ld e,a
178 |
179 | dec b ; next row, copy untill b=0
180 | jr nz,.next_row
181 | ret
182 |
183 |
184 | ;-------------------------------------------------------------------------------
185 | fill:
186 | ;-------------------------------------------------------------------------------
187 | ; a - byte to fill with
188 | ; hl - destination address
189 | ; bc - size of area to fill
190 |
191 | inc b
192 | inc c
193 | jr .skip
194 | .fill
195 | ld [hl+],a
196 | .skip
197 | dec c
198 | jr nz,.fill
199 | dec b
200 | jr nz,.fill
201 | ret
202 |
203 |
204 | ;-------------------------------------------------------------------------------
205 | read_keys:
206 | ;-------------------------------------------------------------------------------
207 | ; this function returns two different values in b and c registers:
208 | ; b - returns raw state (pressing key triggers given action continuously as long as it's pressed - it does not prevent bouncing)
209 | ; c - returns debounced state (pressing key triggers given action only once - key must be released and pressed again)
210 |
211 | ld a,$20 ; read P15 - returns a, b, select, start
212 | ldh [rP1],a
213 | ldh a,[rP1] ; mandatory
214 | ldh a,[rP1]
215 | cpl ; rP1 returns not pressed keys as 1 and pressed as 0, invert it to make result more readable
216 | and $0f ; lower nibble has a, b, select, start state
217 | swap a
218 | ld b,a
219 |
220 | ld a,$10 ; read P14 - returns up, down, left, right
221 | ldh [rP1],a
222 | ldh a,[rP1] ; mandatory
223 | ldh a,[rP1]
224 | ldh a,[rP1]
225 | ldh a,[rP1]
226 | ldh a,[rP1]
227 | ldh a,[rP1]
228 | cpl ; rP1 returns not pressed keys as 1 and pressed as 0, invert it to make result more readable
229 | and $0f ; lower nibble has up, down, left, right state
230 | or b ; combine P15 and P14 states in one byte
231 | ld b,a ; store it
232 |
233 | ldh a,[previous] ; this is when important part begins, load previous P15 & P14 state
234 | xor b ; result will be 0 if it's the same as current read
235 | and b ; keep buttons that were pressed during this read only
236 | ldh [current],a ; store final result in variable and register
237 | ld c,a
238 | ld a,b ; current P15 & P14 state will be previous in next read
239 | ldh [previous],a
240 |
241 | ld a,$30 ; reset rP1
242 | ldh [rP1],a
243 |
244 | ret
245 |
246 |
247 | ;-------------------------------------------------------------------------------
248 | update_score:
249 | ;-------------------------------------------------------------------------------
250 | ; found it on Milos "baze" Bazelides webpage and adjusted for gb cpu
251 | ; hl - contains score value, it's 16 bits so maximum value is 65535
252 | ; c - offset in HRAM that stores hl as decimal ascii string
253 |
254 | ld de,-10000 ; count tens of thousands
255 | call .hex2ascii
256 | ld de,-1000 ; count tousands
257 | call .hex2ascii
258 | ld de,-100 ; count hundreds
259 | call .hex2ascii
260 | ld e,-10 ; count tens
261 | call .hex2ascii
262 | ld e,d ; count ones
263 |
264 | .hex2ascii
265 | ld a,$2F ; preload a with $2F = $30 - 1, $30 is "0" in ascii notation
266 | ; code below is executed at least once so we get value in $30 - $39 range
267 | .count
268 | inc a ; increase counter
269 | add hl,de ; adding de to our score value might cause overflow, c flag is set then
270 | jr c,.count ; repeat the loop untill there's no overflow
271 |
272 | ld [c],a ; a contains number of repeats as ascii decimal value, store it
273 | inc c ; next number
274 |
275 | ld a,l ; restore last "overflow" value, hl = hl - de
276 | sub a,e
277 | ld l,a
278 | ld a,h
279 | sbc a,d
280 | ld h,a
281 |
282 | ret
283 |
284 |
285 | ;-------------------------------------------------------------------------------
286 |
287 | font:
288 | INCBIN "font_8x8.chr" ; converted with https://github.com/gitendo/bmp2cgb
289 |
290 | text:
291 | DB " Score: "
292 | DB " "
293 | DB " 00000 "
294 | DB " "
295 | DB " Press UP or DOWN "
296 | DB " to update score. "
297 |
298 | ;-------------------------------------------------------------------------------
299 |
300 |
301 | SECTION "Variables",HRAM
302 |
303 | hex_score_l: DS 1 ; 16 bit number that contains score value (0-65535)
304 | hex_score_h: DS 1
305 | ascii_score: DS 5 ; ascii string that contains hex score in decimal format
306 | current: DS 1 ; usually you read keys state and store it into variable for further processing
307 | previous: DS 1 ; this is previous keys state used by debouncing part of read_keys function
308 |
--------------------------------------------------------------------------------
/dmg/sprite.asm:
--------------------------------------------------------------------------------
1 | ; -----------------------------------------------------------------------------
2 | ; Example: Single, d-pad moveable sprite
3 | ; -----------------------------------------------------------------------------
4 | ; Font comes from ZX Spectrum - https://en.wikipedia.org/wiki/ZX_Spectrum_character_set
5 | ; More examples by tmk @ https://github.com/gitendo/helloworld
6 | ; -----------------------------------------------------------------------------
7 |
8 | INCLUDE "hardware.inc" ; system defines
9 |
10 | SECTION "VBL",ROM0[$0040] ; vblank interrupt handler
11 | jp vbl
12 |
13 | SECTION "Start",ROM0[$100] ; start vector, followed by header data applied by rgbfix.exe
14 | nop
15 | jp start
16 |
17 | SECTION "Example",ROM0[$150] ; code starts here
18 |
19 | start:
20 | di ; disable interrupts
21 | ld sp,$E000 ; setup stack
22 |
23 | .wait_vbl ; wait for vblank to properly disable lcd
24 | ld a,[rLY]
25 | cp $90
26 | jr nz,.wait_vbl
27 |
28 | xor a
29 | ld [rIF],a ; reset important registers
30 | ld [rLCDC],a
31 | ld [rSTAT],a
32 | ld [rSCX],a
33 | ld [rSCY],a
34 | ld [rLYC],a
35 | ld [rIE],a
36 |
37 | ld hl,_RAM ; clear ram (fill with a which is 0 here)
38 | ld bc,$2000-2 ; watch out for stack ;)
39 | call fill
40 |
41 | ld hl,_HRAM ; clear hram
42 | ld c,$80 ; a = 0, b = 0 here, so let's save a byte and 4 cycles (ld c,$80 - 2/8 vs ld bc,$80 - 3/12)
43 | call fill
44 |
45 | ld hl,_VRAM ; clear vram
46 | ld b,$18 ; a = 0, bc should be $1800; c = 0 here, so..
47 | call fill
48 |
49 | ld a,2 ; tile number to fill the _SCRN0 with - tiles 0, 1 are used for sprite, rest is empty
50 |
51 | ; no need to setup hl since _SCRN0 ($9800) and _SCRN1 ($9C00) are part of _VRAM, just continue
52 |
53 | ld b,8 ; bc should be $800 (_SCRN0/1 are 32*32 bytes); c = 0 here, so..
54 | call fill
55 |
56 | ld a,%01101100 ; bits: 7-6 = 1st color, 5-4 = 2nd, 3-2 = 3rd and 1-0 = 4th color
57 | ; color values: 00 - light, 01 - gray, 10 - dark gray, 11 - dark
58 | ld [rBGP],a ; bg palette
59 | ld [rOBP0],a ; obj palettes
60 | ld [rOBP1],a
61 |
62 | ld hl,heart ; tiles used as sprites
63 | ld de,_VRAM
64 | ld bc,32 ; two tiles, 16 bytes each
65 | call copy
66 |
67 | ld c,$80 ; dma sub will be copied to _HRAM, at $FF80
68 | ld b,dma_sub_end-dma_sub_start ; size of dma sub, which is 10 bytes
69 | ld hl,dma_sub_start ; dma sub code to be copied
70 | .copy
71 | ld a,[hl+]
72 | ld [c],a
73 | inc c
74 | dec b
75 | jr nz,.copy
76 |
77 | ld a,80 ; OAM table mirror is located at $C000, let's set up 1st sprite
78 | ld [$C000],a ; y coordinate
79 | ld a,84
80 | ld [$C001],a ; x coordinate
81 | ; sprite will use tile 0 and no attributes, we already zeroed whole RAM so no need to do it again
82 |
83 | ld a,IEF_VBLANK ; set up vblank interrupt
84 | ld [rIE],a
85 |
86 | ld a,LCDCF_ON | LCDCF_BG8000 | LCDCF_BG9800 | LCDCF_OBJ8 | LCDCF_OBJON | LCDCF_WINOFF | LCDCF_BGON
87 | ; lcd setup: tiles at $8000, map at $9800, 8x8 sprites (enabled), no window, etc.
88 | ld [rLCDC],a ; enable lcd
89 |
90 | ei ; enable interrupts
91 |
92 | .loop
93 | halt ; save battery
94 | ; nop ; nop after halt is mandatory but rgbasm takes care of it :)
95 |
96 | call read_keys ; read joypad
97 | ld hl,$C000
98 | .btn_a
99 | bit 0,b ; is button a pressed ? (bit must be 1)
100 | jr z,.btn_b ; no, check other key (apparently it's 0)
101 | ld l,2 ; hl = $C002 which is 1st sprite in OAM table mirror, located at $C000
102 | xor a ; change sprite to tile 0
103 | ld [hl],a
104 | .btn_b
105 | bit 1,b ; ...
106 | jr z,.right
107 | ld l,2
108 | ld a,1 ; change sprite to tile 1
109 | ld [hl],a
110 | .right
111 | bit 4,b
112 | jr z,.left
113 | ld l,1 ; x coordinate
114 | inc [hl] ; increase
115 | .left
116 | bit 5,b
117 | jr z,.up
118 | ld l,1 ; x coordinate
119 | dec [hl] ; decrease
120 | .up
121 | bit 6,b
122 | jr z,.down
123 | ld l,0 ; y coordinate
124 | dec [hl] ; decrease
125 | .down
126 | bit 7,b
127 | jr z,.loop
128 | ld l,0 ; y coordinate
129 | inc [hl] ; increase
130 |
131 | jr .loop ; endless loop
132 |
133 |
134 | vbl:
135 | call $FF80 ; copy OAM mirror table using DMA
136 | reti
137 |
138 | ;-------------------------------------------------------------------------------
139 | read_keys:
140 | ;-------------------------------------------------------------------------------
141 | ; this function returns two different values in b and c registers:
142 | ; b - returns raw state (pressing key triggers given action continuously as long as it's pressed - it does not prevent bouncing)
143 | ; c - returns debounced state (pressing key triggers given action only once - key must be released and pressed again)
144 |
145 | ld a,$20 ; read P15 - returns a, b, select, start
146 | ldh [rP1],a
147 | ldh a,[rP1] ; mandatory
148 | ldh a,[rP1]
149 | cpl ; rP1 returns not pressed keys as 1 and pressed as 0, invert it to make result more readable
150 | and $0f ; lower nibble has a, b, select, start state
151 | swap a
152 | ld b,a
153 |
154 | ld a,$10 ; read P14 - returns up, down, left, right
155 | ldh [rP1],a
156 | ldh a,[rP1] ; mandatory
157 | ldh a,[rP1]
158 | ldh a,[rP1]
159 | ldh a,[rP1]
160 | ldh a,[rP1]
161 | ldh a,[rP1]
162 | cpl ; rP1 returns not pressed keys as 1 and pressed as 0, invert it to make result more readable
163 | and $0f ; lower nibble has up, down, left, right state
164 | or b ; combine P15 and P14 states in one byte
165 | ld b,a ; store it
166 |
167 | ldh a,[previous] ; this is when important part begins, load previous P15 & P14 state
168 | xor b ; result will be 0 if it's the same as current read
169 | and b ; keep buttons that were pressed during this read only
170 | ldh [current],a ; store final result in variable and register
171 | ld c,a
172 | ld a,b ; current P15 & P14 state will be previous in next read
173 | ldh [previous],a
174 |
175 | ld a,$30 ; reset rP1
176 | ldh [rP1],a
177 |
178 | ret
179 |
180 |
181 | ;-------------------------------------------------------------------------------
182 | copy:
183 | ;-------------------------------------------------------------------------------
184 | ; hl - source address
185 | ; de - destination
186 | ; bc - size
187 |
188 | inc b
189 | inc c
190 | jr .skip
191 | .copy
192 | ld a,[hl+]
193 | ld [de],a
194 | inc de
195 | .skip
196 | dec c
197 | jr nz,.copy
198 | dec b
199 | jr nz,.copy
200 | ret
201 |
202 | ;-------------------------------------------------------------------------------
203 | fill:
204 | ;-------------------------------------------------------------------------------
205 | ; a - byte to fill with
206 | ; hl - destination address
207 | ; bc - size of area to fill
208 |
209 | inc b
210 | inc c
211 | jr .skip
212 | .fill
213 | ld [hl+],a
214 | .skip
215 | dec c
216 | jr nz,.fill
217 | dec b
218 | jr nz,.fill
219 | ret
220 |
221 |
222 | ;-------------------------------------------------------------------------------
223 | dma_sub_start:
224 | ;-------------------------------------------------------------------------------
225 | db $3E,$C0 ; ld a,$C0 ; OAM table mirror in RAM at $C000 (high byte)
226 | db $E0,$46 ; ld [rDMA],a
227 | db $3E,$28 ; ld a,40 ; delay = 160 cycles
228 | ;.copy
229 | db $3D ; dec a
230 | db $20,$FD ; jr nz,.copy
231 | db $C9 ; ret
232 | dma_sub_end:
233 |
234 | ;-------------------------------------------------------------------------------
235 |
236 | heart:
237 | db $00,$6C,$6C,$92,$3C,$82,$7C,$C2,$7C,$82,$38,$44,$10,$28,$00,$10 ; 1st heart tile
238 | db $6C,$6C,$FE,$FE,$FE,$FE,$FE,$FE,$FE,$FE,$7C,$7C,$38,$38,$10,$10 ; 2nd heart tile
239 |
240 |
241 | ;-------------------------------------------------------------------------------
242 |
243 |
244 | SECTION "Variables",HRAM[$FF8A] ; $FF80 - $FF89 is taken by dma_sub function
245 |
246 | current: DS 1 ; usually you read keys state and store it into variable for further processing
247 | previous: DS 1 ; this is previous keys state used by debouncing part of read_keys function
248 |
--------------------------------------------------------------------------------
/dmg/sprite_collision.asm:
--------------------------------------------------------------------------------
1 | ; -----------------------------------------------------------------------------
2 | ; Example: Sprite collision example
3 | ; -----------------------------------------------------------------------------
4 | ; More examples by tmk @ https://github.com/gitendo/helloworld
5 | ; -----------------------------------------------------------------------------
6 |
7 | INCLUDE "hardware.inc" ; system defines
8 |
9 | SECTION "VBL",ROM0[$0040] ; vblank interrupt handler
10 | jp vbl
11 |
12 | SECTION "Start",ROM0[$100] ; start vector, followed by header data applied by rgbfix.exe
13 | nop
14 | jp start
15 |
16 | SECTION "Example",ROM0[$150] ; code starts here
17 |
18 | OAM_MIRROR equ $C000 ; oam table mirror will be stored in RAM at $C000
19 |
20 | start:
21 | di ; disable interrupts
22 | ld sp,$E000 ; setup stack
23 |
24 | .wait_vbl ; wait for vblank to properly disable lcd
25 | ld a,[rLY]
26 | cp $90
27 | jr nz,.wait_vbl
28 |
29 | xor a
30 | ld [rIF],a ; reset important registers
31 | ld [rLCDC],a
32 | ld [rSTAT],a
33 | ld [rSCX],a
34 | ld [rSCY],a
35 | ld [rLYC],a
36 | ld [rIE],a
37 |
38 | ld hl,_RAM ; clear ram (fill with a which is 0 here)
39 | ld bc,$2000-2 ; watch out for stack ;)
40 | call fill
41 |
42 | ld hl,_HRAM ; clear hram
43 | ld c,$80 ; a = 0, b = 0 here, so let's save a byte and 4 cycles (ld c,$80 - 2/8 vs ld bc,$80 - 3/12)
44 | call fill
45 |
46 | ld hl,_VRAM ; clear vram
47 | ld b,$18 ; a = 0, bc should be $1800; c = 0 here, so..
48 | call fill
49 |
50 | ld a,2 ; tile number to fill the _SCRN0 with - tiles 0, 1 are used for sprite, rest is empty
51 |
52 | ; no need to setup hl since _SCRN0 ($9800) and _SCRN1 ($9C00) are part of _VRAM, just continue
53 |
54 | ld b,8 ; bc should be $800 (_SCRN0/1 are 32*32 bytes); c = 0 here, so..
55 | call fill
56 |
57 | ld a,%01101100 ; bits: 7-6 = 1st color, 5-4 = 2nd, 3-2 = 3rd and 1-0 = 4th color
58 | ; color values: 00 - light, 01 - gray, 10 - dark gray, 11 - dark
59 | ld [rBGP],a ; bg palette
60 | ld [rOBP0],a ; obj palette for "enemy" sprites
61 | ld a,%00111001 ; and inverted for "hero" sprite
62 | ld [rOBP1],a
63 |
64 | ld hl,heart ; tiles used as sprites
65 | ld de,_VRAM
66 | ld bc,32 ; two tiles, 16 bytes each
67 | call copy
68 |
69 | ld c,$80 ; dma sub will be copied to _HRAM, at $FF80
70 | ld b,dma_sub_end-dma_sub_start ; size of dma sub, which is 10 bytes
71 | ld hl,dma_sub_start ; dma sub code to be copied
72 | .copy
73 | ld a,[hl+]
74 | ld [c],a
75 | inc c
76 | dec b
77 | jr nz,.copy
78 |
79 | ld hl,oam_stub ; predefined values for 4 sprites used in this example
80 | ld de,OAM_MIRROR ; sprites table in RAM
81 | ld bc,16 ; 4 sprites, each entry needs 4 bytes
82 | call copy
83 |
84 | ld hl,dir_stub ; predefined values for moving/speed directions (y, x) for each sprite
85 | ld de,directions ; proper table in RAM
86 | ld bc,4*2
87 | call copy
88 |
89 | ld a,IEF_VBLANK ; set up vblank interrupt
90 | ld [rIE],a
91 |
92 | ld a,LCDCF_ON | LCDCF_BG8000 | LCDCF_BG9800 | LCDCF_OBJ8 | LCDCF_OBJON | LCDCF_WINOFF | LCDCF_BGON
93 | ; lcd setup: tiles at $8000, map at $9800, 8x8 sprites (enabled), no window, etc.
94 | ld [rLCDC],a ; enable lcd
95 |
96 | ei ; enable interrupts
97 |
98 | .loop
99 | halt ; save battery
100 | ; nop ; nop after halt is mandatory but rgbasm takes care of it :)
101 |
102 | ldh a,[frame] ; make sure functions below are executed every second frame
103 | and a ; this is to faciliate seeing when collision happens and can be omitted
104 | jr nz,.loop
105 |
106 | call move_sprites ; move sprites around
107 | call check_boundaries ; make sure they stay on the screen
108 | call check_collision ; check if they collide and animate when that happens
109 |
110 | jr .loop ; endless loop
111 |
112 |
113 | ;-------------------------------------------------------------------------------
114 | vbl:
115 | ;-------------------------------------------------------------------------------
116 | push af
117 | call $FF80 ; copy OAM_MIRROR table using DMA
118 | ldh a,[frame] ; vbl is executed 60 times per second
119 | xor 1 ; xoring frame variable causes it to have value of 1 every second frame
120 | ld [frame],a ; this is used in main loop to slow sprites update - 30 fps instead of 60 fps
121 | pop af
122 | reti
123 |
124 |
125 | ;-------------------------------------------------------------------------------
126 | move_sprites:
127 | ;-------------------------------------------------------------------------------
128 | ld de,OAM_MIRROR ; sprites table
129 | ld hl,directions ; movement directions (y, x)
130 | ld c,4 ; number of sprites to move
131 | .move
132 | ld a,[de] ; get sprite y position
133 | add a,[hl] ; depending on movement direction value increase or decrease it to move sprite up or down
134 | ld [de],a ; store updated y position
135 | inc e ; move to sprite x position
136 | inc l ; move to x movement direction
137 | ld a,[de] ; get sprite x position
138 | add a,[hl] ; depending on movement direction value increase or decrease it to move sprite left or right
139 | ld [de],a ; store updated x position
140 | ld a,3 ; move to another sprite y position
141 | add a,e
142 | ld e,a
143 | inc l ; move to another y movement direction
144 | dec c ; do another sprite
145 | jr nz,.move
146 | ret
147 |
148 |
149 | ;-------------------------------------------------------------------------------
150 | check_boundaries:
151 | ;-------------------------------------------------------------------------------
152 | ld hl,OAM_MIRROR ; sprites table
153 | ld de,directions ; movement directions (y, x) for each sprite
154 | ld c,4 ; number of sprites to check
155 | .check_top
156 | ld a,[hl+] ; get sprite y position
157 | cp 16 ; top boundary
158 | jr nz,.check_bottom ; not reached yet
159 | ld a,1 ; top reached, change direction to positive number to move sprite down
160 | ld [de],a ; update y direction
161 | jr .check_left ; no reason to check bottom boundary, do left
162 | .check_bottom
163 | cp 152 ; bottom boundary
164 | jr nz,.check_left ; not reached yet
165 | ld a,-1 ; bottom reached, change direction to negative number to move sprite up
166 | ld [de],a ; update y direction
167 | .check_left
168 | inc e ; move to x movement direction
169 | ld a,[hl+] ; get sprite x position
170 | cp 8 ; left boundary
171 | jr nz,.check_right ; not reached yet
172 | ld a,1 ; left reached, change direction to positive number to move sprite right
173 | ld [de],a ; update x direction
174 | jr .next ; no reason to check right boundary, do next
175 | .check_right
176 | cp 160 ; right boundary
177 | jr nz,.next ; not reached yet
178 | ld a,-1 ; right reached, change direction to negative number to move sprite left
179 | ld [de],a ; update x direction
180 | .next
181 | inc e ; move to y direction (next pair)
182 | inc l ; move to next sprite (skip tile and attribute bytes)
183 | inc l
184 | dec c ; do another sprite
185 | jr nz,.check_top
186 | ret
187 |
188 |
189 | ;-------------------------------------------------------------------------------
190 | check_collision:
191 | ;-------------------------------------------------------------------------------
192 | ld hl,OAM_MIRROR ; sprites table
193 | ld c,3 ; 1 "hero" sprite and 3 "enemy" sprites, for sake of simplicity we don't check collision between "enemy" sprites
194 |
195 | ld a,[hl+] ; get "hero" sprite y position
196 | and $F8 ; strip 3 lower bits to get row where sprite is located (sprites in this example are 8x8 px)
197 | ld d,a ; store it in d
198 | ld a,[hl+] ; get "hero" sprite x position
199 | and $F8 ; strip 3 lower bits to get column where sprite is located
200 | ld e,a ; store it in e
201 | inc l ; move to next sprite
202 | inc l
203 | .next
204 | ld b,0 ; b holds tile number (0 - normal tile, 1 - collision tile) to perform animation during collision
205 | ld a,[hl+] ; get "enemy" sprite y position
206 | and $F8 ; strip 3 lower bits to get row where sprite is located
207 | cp d ; compare with "hero" sprite y position
208 | jr nz,.l1 ; skip if not equal
209 | ld a,[hl+] ; get "enemy" sprite x position
210 | and $F8 ; strip 3 lower bits to get column where sprite is located
211 | cp e ; compare with "hero" sprite x position
212 | jr nz,.l2 ; skip if not equal
213 | inc b ; collision detected
214 | jr .l2 ; update tile
215 | .l1
216 | inc l ; move to tile byte of "enemy" sprite
217 | .l2
218 | ld a,b ; 0 - normal tile, 1 - collision tile
219 | ld [hl+],a ; update "enemy" sprite tile
220 | inc l ; move to next sprite data
221 | dec c ; check another sprite
222 | jr nz,.next
223 | ret
224 |
225 |
226 | ;-------------------------------------------------------------------------------
227 | copy:
228 | ;-------------------------------------------------------------------------------
229 | ; hl - source address
230 | ; de - destination
231 | ; bc - size
232 |
233 | inc b
234 | inc c
235 | jr .skip
236 | .copy
237 | ld a,[hl+]
238 | ld [de],a
239 | inc de
240 | .skip
241 | dec c
242 | jr nz,.copy
243 | dec b
244 | jr nz,.copy
245 | ret
246 |
247 | ;-------------------------------------------------------------------------------
248 | fill:
249 | ;-------------------------------------------------------------------------------
250 | ; a - byte to fill with
251 | ; hl - destination address
252 | ; bc - size of area to fill
253 |
254 | inc b
255 | inc c
256 | jr .skip
257 | .fill
258 | ld [hl+],a
259 | .skip
260 | dec c
261 | jr nz,.fill
262 | dec b
263 | jr nz,.fill
264 | ret
265 |
266 |
267 | ;-------------------------------------------------------------------------------
268 | dma_sub_start:
269 | ;-------------------------------------------------------------------------------
270 | ld a,$C0 ; OAM table mirror in RAM at $C000 (high byte)
271 | ld [rDMA],a
272 | ld a,40 ; delay = 160 cycles
273 | .copy
274 | dec a
275 | jr nz,.copy
276 | ret
277 | dma_sub_end:
278 |
279 | ;-------------------------------------------------------------------------------
280 |
281 |
282 | oam_stub: ; let's setup 4 sprites
283 | db 84,84,0,16
284 | db 84,84,0,0
285 | db 84,84,0,0
286 | db 84,84,0,0
287 |
288 | dir_stub: ; (y, x) -1 = move up / left, 1 = move down / right
289 | db -1, -1
290 | db -1, 1
291 | db 1, -1
292 | db 1, 1
293 |
294 | heart:
295 | db $00,$6C,$6C,$92,$3C,$82,$7C,$C2,$7C,$82,$38,$44,$10,$28,$00,$10 ; 1st heart tile
296 | db $6C,$6C,$FE,$FE,$FE,$FE,$FE,$FE,$FE,$FE,$7C,$7C,$38,$38,$10,$10 ; 2nd heart tile
297 |
298 |
299 | ;-------------------------------------------------------------------------------
300 |
301 | SECTION "Variables",HRAM[$FF8A] ; $FF80 - $FF89 is taken by dma_sub function
302 |
303 | directions:
304 | ds 4*2 ; dir_stub will be copied here
305 | frame:
306 | ds 1
307 |
--------------------------------------------------------------------------------
/dmg/timer_clock.asm:
--------------------------------------------------------------------------------
1 | ; -----------------------------------------------------------------------------
2 | ; Example: ClockBoy - timer based clock
3 | ; -----------------------------------------------------------------------------
4 | ; Turn your GameBoy into clock by utilizing timer interrupt!
5 | ; Font comes from ZX Spectrum - https://en.wikipedia.org/wiki/ZX_Spectrum_character_set
6 | ; More examples by tmk @ https://github.com/gitendo/helloworld
7 | ; -----------------------------------------------------------------------------
8 |
9 | INCLUDE "hardware.inc" ; system defines
10 |
11 | SECTION "VBL",ROM0[$0040] ; vblank interrupt handler
12 | jp vbl
13 |
14 | SECTION "TMR",ROM0[$0050] ; timer interrupt handler
15 | jp tmr
16 |
17 | SECTION "Start",ROM0[$100] ; start vector, followed by header data applied by rgbfix.exe
18 | nop
19 | jp start
20 |
21 | SECTION "Example",ROM0[$150] ; code starts here
22 |
23 | start:
24 | di ; disable interrupts
25 | ld sp,$E000 ; setup stack
26 |
27 | .wait_vbl ; wait for vblank to properly disable lcd
28 | ld a,[rLY]
29 | cp $90
30 | jr nz,.wait_vbl
31 |
32 | xor a
33 | ld [rIF],a ; reset important registers
34 | ld [rLCDC],a
35 | ld [rSTAT],a
36 | ld [rSCX],a
37 | ld [rSCY],a
38 | ld [rLYC],a
39 | ld [rIE],a
40 |
41 | ld hl,_RAM ; clear ram (fill with a which is 0 here)
42 | ld bc,$2000-2 ; watch out for stack ;)
43 | call fill
44 |
45 | ld hl,_HRAM ; clear hram
46 | ld c,$80 ; a = 0, b = 0 here, so let's save a byte and 4 cycles (ld c,$80 - 2/8 vs ld bc,$80 - 3/12)
47 | call fill
48 |
49 | ld hl,_VRAM ; clear vram, lcdc is disabled so you have 'easy' access
50 | ld b,$18 ; a = 0, bc should be $1800; c = 0 here, so..
51 | call fill
52 |
53 | ld a,$20 ; ascii code for 'space' character
54 |
55 | ; no need to setup hl since _SCRN0 ($9800) and _SCRN1 ($9C00) are part of _VRAM, just continue
56 |
57 | ld b,8 ; bc should be $800 (_SCRN0/1 are 32*32 bytes); c = 0 here, so..
58 | call fill
59 |
60 | ld a,%10010011 ; bits: 7-6 = 1st color, 5-4 = 2nd, 3-2 = 3rd and 1-0 = 4th color
61 | ; color values: 00 - light, 01 - gray, 10 - dark gray, 11 - dark
62 | ld [rBGP],a ; bg palette
63 | ld [rOBP0],a ; obj palettes (not used in this example)
64 | ld [rOBP1],a
65 |
66 | ld hl,font ; font data
67 | ld de,_VRAM+$200 ; place it here to get ascii mapping ('space' code is $20, tile size $10)
68 | ld bc,1776 ; font_8x8.chr file size
69 | call copy
70 |
71 | ld hl,text ; clock menu text
72 | ld de,_SCRN0+$80 ; center it a bit
73 | ld b,9 ; it has 9 lines
74 | call copy_text
75 |
76 | ld a,$12 ; set clock to 12:00:00:000
77 | ld [hours],a
78 | ; things are going to be more complicated here :)
79 | ; timer consists of 3 registers:
80 | ; - rTIMA (timer counter) which is automatically incremented at given intervals and when it overflows interrupt is generated
81 | ; - rTMA (timer modulo), when rTIMA overflows rTMA value is reloaded into rTIMA so it always starts counting from that value
82 | ; - rTAC (timer controller), enables / disables timer and allows to select frequency rTIMA is incremented with
83 | ; - there're 4 options: 4096 Hz, 16384 Hz, 65536 Hz and 262144 Hz but since Hz doesn't tell us much so we convert
84 | ; them to count up pulses by dividing gameboy clock with them, ie. 4194304 Hz / 4096 Hz = 1024
85 | ;
86 | ; we know that gameboy clock speed is 4194304 Hz, 1 Hz means one cycle per second, so it does 4194304 clock cycles per second
87 | ; our equation looks like this: 1024 * 256 (maximum rTMA value) * x = 4194304
88 | ; so x = 16 therfore with timer frequency of 4096 Hz our interrupt will be triggered 16 times per second
89 | ; we could also use some other rTMA value to trigger it more often or just change frequency, that really depends on scenario
90 |
91 | xor a ; proper way of setting up timer
92 | ld [rTMA],a ; we go for 256 increments after which interrupt is called
93 | ld a,TACF_4KHZ ; 1st set up frequency / count up pulses
94 | ld [rTAC],a
95 | or TACF_START ; then enable timer
96 | ld [rTAC],a
97 |
98 | ld a,IEF_VBLANK | IEF_TIMER ; use vblank and timer interrupts
99 | ld [rIE],a ; set up
100 |
101 | ld a,LCDCF_ON | LCDCF_BG8000 | LCDCF_BG9800 | LCDCF_OBJ8 | LCDCF_OBJOFF | LCDCF_WINOFF | LCDCF_BGON
102 | ; lcd setup: tiles at $8000, map at $9800, 8x8 sprites (disabled), no window, etc.
103 | ld [rLCDC],a ; enable lcd
104 |
105 | ei ; enable interrupts
106 |
107 | .loop
108 | halt ; save battery
109 | ; nop ; nop after halt is mandatory but rgbasm takes care of it :)
110 | call parse_input ; read joypad and handle pause mode
111 | jr .loop ; endless loop
112 |
113 |
114 | ;-------------------------------------------------------------------------------
115 | vbl: ; update screen
116 | ;-------------------------------------------------------------------------------
117 |
118 | push af ; make sure to preserve original values when there's other code in main loop
119 | push bc ; without it glitches are bound to happen
120 | push de
121 | push hl
122 |
123 | ld hl,time
124 | ld de,_SCRN0+$E4 ; this points exactly at map coordinate where clock digits are stored
125 | ld c,4 ; clock takes 4 bytes and 1 nibble, each byte holds 2 digits
126 | .copy ; copy from hram to vram without waiting for access since it's vblank
127 | ld a,[hl+] ; get byte
128 | ld b,a ; store it for further processing
129 | and a,$F0 ; leave upper nible, remove lower one
130 | swap a ; swap nibbles with places, lower is upper now and upper is lower
131 | or $30 ; upper nibble is 3, lower keeps its value - we have valid number in ascii notation now
132 | ld [de],a ; put it on the screen - map actually
133 | inc de ; next map entry
134 | ld a,b ; restore byte and repeat process above to lower nibble
135 | and a,$0F
136 | or $30
137 | ld [de],a
138 | inc de
139 | inc de
140 | dec c ; repeat 3 times
141 | jr nz,.copy
142 | dec de ; next map entry
143 | ld a,[hl] ; here's last nibble that contains single milliseconds, lower one is not needed
144 | and a,$F0 ; process as above
145 | swap a
146 | or $30
147 | ld [de],a
148 |
149 | pop hl ; restore original values and return
150 | pop de
151 | pop bc
152 | pop af
153 | reti
154 |
155 | ;-------------------------------------------------------------------------------
156 | tmr: ; timer (i leave it unrolled so it's hopefully easier to read / understand)
157 | ;-------------------------------------------------------------------------------
158 |
159 | push af ; make sure to preserve original values since timer will be called also when main loop code is executed
160 | push bc ; without it glitches are bound to happen
161 | push hl
162 |
163 | ld a,$25 ; interrupt is executed 16 times per second, 1000 ms / 16 = 62,5 ms - this is decimal point value so we need to _be clever_ here
164 | ld hl,milliseconds+1 ; we use 3 nibbles for integers and 1 nibble for fractional part to store milliseconds, 4 nibbles = 2 bytes in total ($0625)
165 | add a,[hl] ; let's add lower byte ($25)
166 | daa ; convert to bcd format
167 | ld [hl-],a ; store and move hl to upper byte
168 | ld b,a ; keep result in b
169 | ld a,$06 ; now the same with upper byte ($06)
170 | adc a,[hl] ; add with carry here to increase upper byte when lower overflows
171 | daa ; convert to bcd format
172 | ld [hl-],a ; store and move hl to seconds
173 | cp b ; a = b when 1000 milliseconds have passed, they both will be 0 then (0 -> 62,5 -> 125 -> 187,5 -> (...) -> 937,5 -> 0)
174 | jr nz,.done ; no need to update seconds yet
175 |
176 | ld a,[hl] ; load seconds
177 | inc a ; increase by 1
178 | daa ; convert to bcd format
179 | ld [hl],a ; and store
180 | cp $60 ; 60 seconds passed?
181 | jr nz,.done ; not yet
182 | xor a ; reset seconds
183 | ld [hl-],a ; update and move hl to minutes
184 |
185 | ld a,[hl] ; same as above but minutes this time, a lot of duplicated code here that could be fit into smaller procedure
186 | inc a
187 | daa
188 | ld [hl],a
189 | cp $60
190 | jr nz,.done
191 | xor a
192 | ld [hl-],a
193 |
194 | ld a,[hl] ; and again, hours this time
195 | inc a
196 | daa
197 | ld [hl],a
198 | cp $24 ; 24h ftw!
199 | jr nz,.done
200 | xor a
201 | ld [hl],a
202 |
203 | .done
204 | pop hl ; restore original values and return
205 | pop bc
206 | pop af
207 | reti
208 |
209 |
210 | ;-------------------------------------------------------------------------------
211 | parse_input:
212 | ;-------------------------------------------------------------------------------
213 |
214 | call read_keys ; read joypad
215 |
216 | .start
217 | bit 3,c ; key code is in c, see if start was pressed
218 | jr z,.done ; not pressed
219 |
220 | ld a,[rIE] ; get interrupt setup
221 | xor IEF_TIMER ; turn timer on / off
222 | ld [rIE],a ; update interrupt setup
223 |
224 | .done
225 | ret
226 |
227 |
228 | ;-------------------------------------------------------------------------------
229 | copy:
230 | ;-------------------------------------------------------------------------------
231 | ; hl - source address
232 | ; de - destination
233 | ; bc - size
234 |
235 | inc b
236 | inc c
237 | jr .skip
238 | .copy
239 | ld a,[hl+]
240 | ld [de],a
241 | inc de
242 | .skip
243 | dec c
244 | jr nz,.copy
245 | dec b
246 | jr nz,.copy
247 | ret
248 |
249 |
250 | ;-------------------------------------------------------------------------------
251 | copy_text:
252 | ;-------------------------------------------------------------------------------
253 | ; hl - text to display
254 | ; de - _SCRN0 or _SCRN1
255 | ; b - rows
256 | ; c - columns
257 |
258 | .next_row
259 | ld c,20
260 | .row
261 | ld a,[hl+] ; fetch one byte from text array and increase hl to point to another one
262 | ld [de],a ; store it at _SCRN0
263 | inc de ; unfortunately there's no [de+]
264 | dec c ; one byte done
265 | jr nz,.row ; next byte, copy untill c=0
266 |
267 | ld a,e ; our row = 20 which is what you can see on the screen
268 | add a,12 ; the part you don't see = 12, so we need to add it
269 | jr nc,.skip ; to make sure the next row is copied at right offset
270 | inc d ; nc flag is set when a+12 > 255
271 | .skip
272 | ld e,a
273 |
274 | dec b ; next row, copy untill b=0
275 | jr nz,.next_row
276 | ret
277 |
278 |
279 | ;-------------------------------------------------------------------------------
280 | fill:
281 | ;-------------------------------------------------------------------------------
282 | ; a - byte to fill with
283 | ; hl - destination address
284 | ; bc - size of area to fill
285 |
286 | inc b
287 | inc c
288 | jr .skip
289 | .fill
290 | ld [hl+],a
291 | .skip
292 | dec c
293 | jr nz,.fill
294 | dec b
295 | jr nz,.fill
296 | ret
297 |
298 |
299 | ;-------------------------------------------------------------------------------
300 | read_keys:
301 | ;-------------------------------------------------------------------------------
302 | ; this function returns two different values in b and c registers:
303 | ; b - returns raw state (pressing key triggers given action continuously as long as it's pressed - it does not prevent bouncing)
304 | ; c - returns debounced state (pressing key triggers given action only once - key must be released and pressed again)
305 |
306 | ld a,$20 ; read P15 - returns a, b, select, start
307 | ldh [rP1],a
308 | ldh a,[rP1] ; mandatory
309 | ldh a,[rP1]
310 | cpl ; rP1 returns not pressed keys as 1 and pressed as 0, invert it to make result more readable
311 | and $0f ; lower nibble has a, b, select, start state
312 | swap a
313 | ld b,a
314 |
315 | ld a,$10 ; read P14 - returns up, down, left, right
316 | ldh [rP1],a
317 | ldh a,[rP1] ; mandatory
318 | ldh a,[rP1]
319 | ldh a,[rP1]
320 | ldh a,[rP1]
321 | ldh a,[rP1]
322 | ldh a,[rP1]
323 | cpl ; rP1 returns not pressed keys as 1 and pressed as 0, invert it to make result more readable
324 | and $0f ; lower nibble has up, down, left, right state
325 | or b ; combine P15 and P14 states in one byte
326 | ld b,a ; store it
327 |
328 | ldh a,[previous] ; this is when important part begins, load previous P15 & P14 state
329 | xor b ; result will be 0 if it's the same as current read
330 | and b ; keep buttons that were pressed during this read only
331 | ldh [current],a ; store final result in variable and register
332 | ld c,a
333 | ld a,b ; current P15 & P14 state will be previous in next read
334 | ldh [previous],a
335 |
336 | ld a,$30 ; reset rP1
337 | ldh [rP1],a
338 |
339 | ret
340 |
341 | ;-------------------------------------------------------------------------------
342 |
343 | font:
344 | INCBIN "font_8x8.chr" ; converted with https://github.com/gitendo/bmp2cgb
345 |
346 | text:
347 | DB " ClockBoy "
348 | DB " "
349 | DB " "
350 | DB " 00:00:00:000 "
351 | DB " "
352 | DB " "
353 | DB " Press Start to "
354 | DB " pause the timer. "
355 | DB " "
356 |
357 | ;-------------------------------------------------------------------------------
358 |
359 | SECTION "Variables",HRAM
360 |
361 | time:
362 | hours: DS 1 ; time in bcd format
363 | minutes: DS 1
364 | seconds: DS 1
365 | milliseconds: DS 2
366 | current: DS 1 ; usually you read keys state and store it into variable for further processing
367 | previous: DS 1 ; this is previous keys state used by debouncing part of read_keys function
368 |
--------------------------------------------------------------------------------
/dmg/window.asm:
--------------------------------------------------------------------------------
1 | ; -----------------------------------------------------------------------------
2 | ; Example: Window
3 | ; -----------------------------------------------------------------------------
4 | ; [gameboy demake] pick up that can! pixeled by b236 @ http://pixeljoint.com/pixelart/129407.htm
5 | ; Press select to enable/disable window and use d-pad to change its coordinates.
6 | ; More examples by tmk @ https://github.com/gitendo/helloworld
7 | ; -----------------------------------------------------------------------------
8 |
9 | INCLUDE "hardware.inc" ; system defines
10 |
11 | SECTION "VBL",ROM0[$0040] ; vblank interrupt handler
12 | jp vbl
13 |
14 | SECTION "Start",ROM0[$100] ; start vector, followed by header data applied by rgbfix.exe
15 | nop
16 | jp start
17 |
18 | SECTION "Example",ROM0[$150] ; code starts here
19 |
20 | start:
21 | di ; disable interrupts
22 | ld sp,$E000 ; setup stack
23 |
24 | .wait_vbl ; wait for vblank to properly disable lcd
25 | ld a,[rLY]
26 | cp $90
27 | jr nz,.wait_vbl
28 |
29 | xor a ; reset important registers
30 | ld [rIF],a
31 | ld [rLCDC],a
32 | ld [rSTAT],a
33 | ld [rSCX],a
34 | ld [rSCY],a
35 | ld [rWX],a
36 | ld [rWY],a
37 | ld [rIE],a
38 |
39 | ld hl,_RAM ; clear ram (fill with a which is 0 here)
40 | ld bc,$2000-2 ; watch out for stack ;)
41 | call fill
42 |
43 | ld hl,_HRAM ; clear hram
44 | ld c,$80 ; a = 0, b = 0 here, so let's save a byte and 4 cycles (ld c,$80 - 2/8 vs ld bc,$80 - 3/12)
45 | call fill
46 | ; no point in clearing vram, we'll overwrite it with picture data anyway
47 | ; lcdc is already disabled so we have 'easy' access to vram
48 |
49 | ld hl,tiles ; picture tiles
50 | ld de,_VRAM ; place it between $8000-8FFF (tiles are numbered here from 0 to 255)
51 | ld bc,3040 ; hlgbmcp.chr file size
52 | call copy
53 |
54 | ld hl,bg_map ; main picture map (padded to 32 columns, so we can easily copy it)
55 | ld de,_SCRN0 ; store it at $9800
56 | ld bc,576 ; hlgbmcp_bg.map file size
57 | call copy
58 |
59 | ld hl,window_map ; dialog window map (also padded)
60 | ld de,_SCRN1 ; store it at $9C00
61 | ld bc,576 ; hlgbmcp_win.map file size
62 | call copy
63 |
64 | ld a,%00011011 ; bits: 7-6 = 1st color, 5-4 = 2nd, 3-2 = 3rd and 1-0 = 4th color
65 | ; color values: 00 - light, 01 - gray, 10 - dark gray, 11 - dark
66 | ld [rBGP],a ; bg palette
67 | ld [rOBP0],a ; obj palettes (not used in this example)
68 | ld [rOBP1],a
69 |
70 | ld a,7 ; window x coordinate
71 | ldh [x],a ;
72 | ld a,112 ; window y coordinate
73 | ldh [y],a ;
74 |
75 | ld a,IEF_VBLANK ; vblank interrupt
76 | ld [rIE],a ; setup
77 |
78 | ld a,LCDCF_ON | LCDCF_BG8000 | LCDCF_BG9800 | LCDCF_WIN9C00 | LCDCF_OBJ8 | LCDCF_OBJOFF | LCDCF_WINOFF | LCDCF_BGON
79 | ; lcd setup: tiles at $8000, map at $9800, 8x8 sprites (disabled), window (disabled), etc.
80 | ld [rLCDC],a ; enable lcd
81 |
82 | ei ; enable interrupts
83 |
84 | .the_end
85 | halt ; save battery
86 | ; nop ; nop after halt is mandatory but rgbasm takes care of it :)
87 | call read_keys ; read joypad
88 | jr .the_end ; endless loop
89 |
90 |
91 | vbl: ; vblank interrupt - executed every frame when LY=144
92 |
93 | ; please notice that b still contains [previous] key state
94 | ; and c holds [current] one which is debounce free,
95 | ; there're no other functions in main loop so we don't have to reload them
96 | .select
97 | bit 2,c ; check if select was pressed
98 | jr z,.right
99 | ldh a,[rLCDC] ; contains lcd setup
100 | xor LCDCF_WINON ; if window is enabled it will be disabled and otherwise
101 | ldh [rLCDC],a ; update lcd with window status
102 | .right
103 | bit 4,b
104 | jr z,.left
105 | ld hl,x ; increase window x coordinate
106 | inc [hl]
107 | .left
108 | bit 5,b
109 | jr z,.up
110 | ld hl,x ; decrease window x coordinate
111 | dec [hl]
112 | .up
113 | bit 6,b
114 | jr z,.down
115 | ld hl,y ; decrease window y coordinate
116 | dec [hl]
117 | .down
118 | bit 7,b
119 | jr z,.quit
120 | ld hl,y ; increase window y coordinate
121 | inc [hl]
122 | .quit
123 | ldh a,[x] ; rWX: 0 - 166 is valid
124 | ld [rWX],a
125 | ldh a,[y] ; rWY: 0 - 143 is valid
126 | ld [rWY],a
127 | ; rWX=7, rWY=0 locates the window at top left corner, completly covering background
128 | reti ; return from interrupt
129 |
130 |
131 | ;-------------------------------------------------------------------------------
132 | copy:
133 | ;-------------------------------------------------------------------------------
134 | ; hl - source address
135 | ; de - destination
136 | ; bc - size
137 |
138 | inc b
139 | inc c
140 | jr .skip
141 | .copy
142 | ld a,[hl+]
143 | ld [de],a
144 | inc de
145 | .skip
146 | dec c
147 | jr nz,.copy
148 | dec b
149 | jr nz,.copy
150 | ret
151 |
152 | ;-------------------------------------------------------------------------------
153 | fill:
154 | ;-------------------------------------------------------------------------------
155 | ; a - byte to fill with
156 | ; hl - destination address
157 | ; bc - size of area to fill
158 |
159 | inc b
160 | inc c
161 | jr .skip
162 | .fill
163 | ld [hl+],a
164 | .skip
165 | dec c
166 | jr nz,.fill
167 | dec b
168 | jr nz,.fill
169 | ret
170 |
171 | ;-------------------------------------------------------------------------------
172 | read_keys:
173 | ;-------------------------------------------------------------------------------
174 | ; this function returns two different values in b and c registers:
175 | ; b - returns raw state (pressing key triggers given action continuously as long as it's pressed - it does not prevent bouncing)
176 | ; c - returns debounced state (pressing key triggers given action only once - key must be released and pressed again)
177 |
178 | ld a,$20 ; read P15 - returns a, b, select, start
179 | ldh [rP1],a
180 | ldh a,[rP1] ; mandatory
181 | ldh a,[rP1]
182 | cpl ; rP1 returns not pressed keys as 1 and pressed as 0, invert it to make result more readable
183 | and $0f ; lower nibble has a, b, select, start state
184 | swap a
185 | ld b,a
186 |
187 | ld a,$10 ; read P14 - returns up, down, left, right
188 | ldh [rP1],a
189 | ldh a,[rP1] ; mandatory
190 | ldh a,[rP1]
191 | ldh a,[rP1]
192 | ldh a,[rP1]
193 | ldh a,[rP1]
194 | ldh a,[rP1]
195 | cpl ; rP1 returns not pressed keys as 1 and pressed as 0, invert it to make result more readable
196 | and $0f ; lower nibble has up, down, left, right state
197 | or b ; combine P15 and P14 states in one byte
198 | ld b,a ; store it
199 |
200 | ldh a,[previous] ; this is when important part begins, load previous P15 & P14 state
201 | xor b ; result will be 0 if it's the same as current read
202 | and b ; keep buttons that were pressed during this read only
203 | ldh [current],a ; store final result in variable and register
204 | ld c,a
205 | ld a,b ; current P15 & P14 state will be previous in next read
206 | ldh [previous],a
207 |
208 | ld a,$30 ; reset rP1
209 | ldh [rP1],a
210 |
211 | ret
212 |
213 |
214 | ;-------------------------------------------------------------------------------
215 |
216 | tiles: ; bmp2cgb -x -y -z -e26 hlgbmcp.bmp
217 | INCBIN "hlgbmcp.chr"
218 | bg_map:
219 | INCBIN "hlgbmcp_bg.map"
220 | window_map:
221 | INCBIN "hlgbmcp_win.map"
222 |
223 | ;-------------------------------------------------------------------------------
224 |
225 | SECTION "Variables",HRAM
226 |
227 | current: DS 1 ; usually you read keys state and store it into variable for further processing
228 | previous: DS 1 ; this is previous keys state used by debouncing part of read_keys function
229 | x DS 1
230 | y DS 1
--------------------------------------------------------------------------------
/inc/hardware.inc:
--------------------------------------------------------------------------------
1 | ;*
2 | ;* Gameboy Hardware definitions
3 | ;*
4 | ;* Based on Jones' hardware.inc
5 | ;* And based on Carsten Sorensen's ideas.
6 | ;*
7 | ;* Rev 1.1 - 15-Jul-97 : Added define check
8 | ;* Rev 1.2 - 18-Jul-97 : Added revision check macro
9 | ;* Rev 1.3 - 19-Jul-97 : Modified for RGBASM V1.05
10 | ;* Rev 1.4 - 27-Jul-97 : Modified for new subroutine prefixes
11 | ;* Rev 1.5 - 15-Aug-97 : Added _HRAM, PAD, CART defines
12 | ;* : and Nintendo Logo
13 | ;* Rev 1.6 - 30-Nov-97 : Added rDIV, rTIMA, rTMA, & rTAC
14 | ;* Rev 1.7 - 31-Jan-98 : Added _SCRN0, _SCRN1
15 | ;* Rev 1.8 - 15-Feb-98 : Added rSB, rSC
16 | ;* Rev 1.9 - 16-Feb-98 : Converted I/O registers to $FFXX format
17 | ;* Rev 2.0 - : Added GBC registers
18 | ;* Rev 2.1 - : Added MBC5 & cart RAM enable/disable defines
19 | ;* Rev 2.2 : Fixed NR42,NR43, & NR44 equates
20 | ;* Rev 2.3 - : Fixed incorrect _HRAM equate
21 | ;* Rev 2.4 - : Completed CART defines
22 | ;* Rev 2.5 - : Fixed bug in CART defines
23 |
24 | ; If all of these are already defined, don't do it again.
25 |
26 | IF !DEF(HARDWARE_INC)
27 | HARDWARE_INC SET 1
28 |
29 | rev_Check_hardware_inc: MACRO
30 | ;NOTE: REVISION NUMBER CHANGES MUST BE ADDED
31 | ;TO SECOND PARAMETER IN FOLLOWING LINE.
32 | IF \1 > 2.2 ;PUT REVISION NUMBER HERE
33 | WARN "Version \1 or later of 'hardware.inc' is required."
34 | ENDC
35 | ENDM
36 |
37 | _HW EQU $FF00
38 |
39 | _VRAM EQU $8000 ; $8000->$A000
40 | _SCRN0 EQU $9800 ; $9800->$9BFF
41 | _SCRN1 EQU $9C00 ; $9C00->$9FFF
42 | _RAM EQU $C000 ; $C000->$E000
43 | _HRAM EQU $FF80 ; $FF80->$FFFE
44 | _OAMRAM EQU $FE00 ; $FE00->$FE9F
45 | _AUD3WAVERAM EQU $FF30 ; $FF30->$FF3F
46 |
47 | ; *** MBC5 Equates ***
48 |
49 | rRAMG EQU $0000 ; $0000->$1fff
50 | rROMB0 EQU $2000 ; $2000->$2fff
51 | rROMB1 EQU $3000 ; $3000->$3fff
52 | rRAMB EQU $4000 ; $4000->$5fff
53 |
54 |
55 | ; --
56 | ; -- OAM flags
57 | ; --
58 |
59 | OAMF_PRI EQU %10000000 ; Priority
60 | OAMF_YFLIP EQU %01000000 ; Y flip
61 | OAMF_XFLIP EQU %00100000 ; X flip
62 | OAMF_PAL0 EQU %00000000 ; Palette number; 0,1
63 | OAMF_PAL1 EQU %00010000 ; Palette number; 0,1
64 |
65 |
66 | ;***************************************************************************
67 | ;*
68 | ;* Custom registers
69 | ;*
70 | ;***************************************************************************
71 |
72 | ; --
73 | ; -- P1 ($FF00)
74 | ; -- Register for reading joy pad info. (R/W)
75 | ; --
76 | rP1 EQU $FF00
77 |
78 | P1F_5 EQU %00100000 ; P15 out port
79 | P1F_4 EQU %00010000 ; P14 out port
80 | P1F_3 EQU %00001000 ; P13 in port
81 | P1F_2 EQU %00000100 ; P12 in port
82 | P1F_1 EQU %00000010 ; P11 in port
83 | P1F_0 EQU %00000001 ; P10 in port
84 |
85 | ; --
86 | ; -- SB ($FF01)
87 | ; -- Serial Transfer Data (R/W)
88 | ; --
89 | rSB EQU $FF01
90 |
91 | ; --
92 | ; -- SC ($FF02)
93 | ; -- Serial I/O Control (R/W)
94 | ; --
95 | rSC EQU $FF02
96 |
97 | ; --
98 | ; -- DIV ($FF04)
99 | ; -- Divider register (R/W)
100 | ; --
101 | rDIV EQU $FF04
102 |
103 |
104 | ; --
105 | ; -- TIMA ($FF05)
106 | ; -- Timer counter (R/W)
107 | ; --
108 | rTIMA EQU $FF05
109 |
110 |
111 | ; --
112 | ; -- TMA ($FF06)
113 | ; -- Timer modulo (R/W)
114 | ; --
115 | rTMA EQU $FF06
116 |
117 |
118 | ; --
119 | ; -- TAC ($FF07)
120 | ; -- Timer control (R/W)
121 | ; --
122 | rTAC EQU $FF07
123 |
124 | TACF_START EQU %00000100
125 | TACF_STOP EQU %00000000
126 | TACF_4KHZ EQU %00000000
127 | TACF_16KHZ EQU %00000011
128 | TACF_65KHZ EQU %00000010
129 | TACF_262KHZ EQU %00000001
130 |
131 | ; --
132 | ; -- IF ($FF0F)
133 | ; -- Interrupt Flag (R/W)
134 | ; --
135 | rIF EQU $FF0F
136 |
137 | ; --
138 | ; -- LCDC ($FF40)
139 | ; -- LCD Control (R/W)
140 | ; --
141 | rLCDC EQU $FF40
142 |
143 | LCDCF_OFF EQU %00000000 ; LCD Control Operation
144 | LCDCF_ON EQU %10000000 ; LCD Control Operation
145 | LCDCF_WIN9800 EQU %00000000 ; Window Tile Map Display Select
146 | LCDCF_WIN9C00 EQU %01000000 ; Window Tile Map Display Select
147 | LCDCF_WINOFF EQU %00000000 ; Window Display
148 | LCDCF_WINON EQU %00100000 ; Window Display
149 | LCDCF_BG8800 EQU %00000000 ; BG & Window Tile Data Select
150 | LCDCF_BG8000 EQU %00010000 ; BG & Window Tile Data Select
151 | LCDCF_BG9800 EQU %00000000 ; BG Tile Map Display Select
152 | LCDCF_BG9C00 EQU %00001000 ; BG Tile Map Display Select
153 | LCDCF_OBJ8 EQU %00000000 ; OBJ Construction
154 | LCDCF_OBJ16 EQU %00000100 ; OBJ Construction
155 | LCDCF_OBJOFF EQU %00000000 ; OBJ Display
156 | LCDCF_OBJON EQU %00000010 ; OBJ Display
157 | LCDCF_BGOFF EQU %00000000 ; BG Display
158 | LCDCF_BGON EQU %00000001 ; BG Display
159 | ; "Window Character Data Select" follows BG
160 |
161 |
162 | ; --
163 | ; -- STAT ($FF41)
164 | ; -- LCDC Status (R/W)
165 | ; --
166 | rSTAT EQU $FF41
167 |
168 | STATF_LYC EQU %01000000 ; LYCEQULY Coincidence (Selectable)
169 | STATF_MODE10 EQU %00100000 ; Mode 10
170 | STATF_MODE01 EQU %00010000 ; Mode 01 (V-Blank)
171 | STATF_MODE00 EQU %00001000 ; Mode 00 (H-Blank)
172 | STATF_LYCF EQU %00000100 ; Coincidence Flag
173 | STATF_HB EQU %00000000 ; H-Blank
174 | STATF_VB EQU %00000001 ; V-Blank
175 | STATF_OAM EQU %00000010 ; OAM-RAM is used by system
176 | STATF_LCD EQU %00000011 ; Both OAM and VRAM used by system
177 | STATF_BUSY EQU %00000010 ; When set, VRAM access is unsafe
178 |
179 |
180 | ; --
181 | ; -- SCY ($FF42)
182 | ; -- Scroll Y (R/W)
183 | ; --
184 | rSCY EQU $FF42
185 |
186 |
187 | ; --
188 | ; -- SCY ($FF43)
189 | ; -- Scroll X (R/W)
190 | ; --
191 | rSCX EQU $FF43
192 |
193 |
194 | ; --
195 | ; -- LY ($FF44)
196 | ; -- LCDC Y-Coordinate (R)
197 | ; --
198 | ; -- Values range from 0->153. 144->153 is the VBlank period.
199 | ; --
200 | rLY EQU $FF44
201 |
202 |
203 | ; --
204 | ; -- LYC ($FF45)
205 | ; -- LY Compare (R/W)
206 | ; --
207 | ; -- When LYEQUEQULYC, STATF_LYCF will be set in STAT
208 | ; --
209 | rLYC EQU $FF45
210 |
211 |
212 | ; --
213 | ; -- DMA ($FF46)
214 | ; -- DMA Transfer and Start Address (W)
215 | ; --
216 | rDMA EQU $FF46
217 |
218 |
219 | ; --
220 | ; -- BGP ($FF47)
221 | ; -- BG Palette Data (W)
222 | ; --
223 | ; -- Bit 7-6 - Intensity for %11
224 | ; -- Bit 5-4 - Intensity for %10
225 | ; -- Bit 3-2 - Intensity for %01
226 | ; -- Bit 1-0 - Intensity for %00
227 | ; --
228 | rBGP EQU $FF47
229 |
230 |
231 | ; --
232 | ; -- OBP0 ($FF48)
233 | ; -- Object Palette 0 Data (W)
234 | ; --
235 | ; -- See BGP for info
236 | ; --
237 | rOBP0 EQU $FF48
238 |
239 |
240 | ; --
241 | ; -- OBP1 ($FF49)
242 | ; -- Object Palette 1 Data (W)
243 | ; --
244 | ; -- See BGP for info
245 | ; --
246 | rOBP1 EQU $FF49
247 |
248 |
249 | ; --
250 | ; -- WY ($FF4A)
251 | ; -- Window Y Position (R/W)
252 | ; --
253 | ; -- 0 SO2 ON/OFF (Vin??)
385 | ; -- Bit 6-4 - SO2 output level (volume) (# 0-7)
386 | ; -- Bit 3 - Vin->SO1 ON/OFF (Vin??)
387 | ; -- Bit 2-0 - SO1 output level (volume) (# 0-7)
388 | ; --
389 | rNR50 EQU $FF24
390 | rAUDVOL EQU rNR50
391 |
392 |
393 | ; --
394 | ; -- AUDTERM/NR51 ($FF25)
395 | ; -- Selection of Sound output terminal (R/W)
396 | ; --
397 | ; -- Bit 7 - Output sound 4 to SO2 terminal
398 | ; -- Bit 6 - Output sound 3 to SO2 terminal
399 | ; -- Bit 5 - Output sound 2 to SO2 terminal
400 | ; -- Bit 4 - Output sound 1 to SO2 terminal
401 | ; -- Bit 3 - Output sound 4 to SO1 terminal
402 | ; -- Bit 2 - Output sound 3 to SO1 terminal
403 | ; -- Bit 1 - Output sound 2 to SO1 terminal
404 | ; -- Bit 0 - Output sound 0 to SO1 terminal
405 | ; --
406 | rNR51 EQU $FF25
407 | rAUDTERM EQU rNR51
408 |
409 |
410 | ; --
411 | ; -- AUDENA/NR52 ($FF26)
412 | ; -- Sound on/off (R/W)
413 | ; --
414 | ; -- Bit 7 - All sound on/off (sets all audio regs to 0!)
415 | ; -- Bit 3 - Sound 4 ON flag (doesn't work!)
416 | ; -- Bit 2 - Sound 3 ON flag (doesn't work!)
417 | ; -- Bit 1 - Sound 2 ON flag (doesn't work!)
418 | ; -- Bit 0 - Sound 1 ON flag (doesn't work!)
419 | ; --
420 | rNR52 EQU $FF26
421 | rAUDENA EQU rNR52
422 |
423 |
424 | ;***************************************************************************
425 | ;*
426 | ;* SoundChannel #1 registers
427 | ;*
428 | ;***************************************************************************
429 |
430 | ; --
431 | ; -- AUD1SWEEP/NR10 ($FF10)
432 | ; -- Sweep register (R/W)
433 | ; --
434 | ; -- Bit 6-4 - Sweep Time
435 | ; -- Bit 3 - Sweep Increase/Decrease
436 | ; -- 0: Addition (frequency increases???)
437 | ; -- 1: Subtraction (frequency increases???)
438 | ; -- Bit 2-0 - Number of sweep shift (# 0-7)
439 | ; -- Sweep Time: (n*7.8ms)
440 | ; --
441 | rNR10 EQU $FF10
442 | rAUD1SWEEP EQU rNR10
443 |
444 |
445 | ; --
446 | ; -- AUD1LEN/NR11 ($FF11)
447 | ; -- Sound length/Wave pattern duty (R/W)
448 | ; --
449 | ; -- Bit 7-6 - Wave Pattern Duty (00:12.5% 01:25% 10:50% 11:75%)
450 | ; -- Bit 5-0 - Sound length data (# 0-63)
451 | ; --
452 | rNR11 EQU $FF11
453 | rAUD1LEN EQU rNR11
454 |
455 |
456 | ; --
457 | ; -- AUD1ENV/NR12 ($FF12)
458 | ; -- Envelope (R/W)
459 | ; --
460 | ; -- Bit 7-4 - Initial value of envelope
461 | ; -- Bit 3 - Envelope UP/DOWN
462 | ; -- 0: Decrease
463 | ; -- 1: Range of increase
464 | ; -- Bit 2-0 - Number of envelope sweep (# 0-7)
465 | ; --
466 | rNR12 EQU $FF12
467 | rAUD1ENV EQU rNR12
468 |
469 |
470 | ; --
471 | ; -- AUD1LOW/NR13 ($FF13)
472 | ; -- Frequency lo (W)
473 | ; --
474 | rNR13 EQU $FF13
475 | rAUD1LOW EQU rNR13
476 |
477 |
478 | ; --
479 | ; -- AUD1HIGH/NR14 ($FF14)
480 | ; -- Frequency hi (W)
481 | ; --
482 | ; -- Bit 7 - Initial (when set, sound restarts)
483 | ; -- Bit 6 - Counter/consecutive selection
484 | ; -- Bit 2-0 - Frequency's higher 3 bits
485 | ; --
486 | rNR14 EQU $FF14
487 | rAUD1HIGH EQU rNR14
488 |
489 |
490 | ;***************************************************************************
491 | ;*
492 | ;* SoundChannel #2 registers
493 | ;*
494 | ;***************************************************************************
495 |
496 | ; --
497 | ; -- AUD2LEN/NR21 ($FF16)
498 | ; -- Sound Length; Wave Pattern Duty (R/W)
499 | ; --
500 | ; -- see AUD1LEN for info
501 | ; --
502 | rNR21 EQU $FF16
503 | rAUD2LEN EQU rNR21
504 |
505 |
506 | ; --
507 | ; -- AUD2ENV/NR22 ($FF17)
508 | ; -- Envelope (R/W)
509 | ; --
510 | ; -- see AUD1ENV for info
511 | ; --
512 | rNR22 EQU $FF17
513 | rAUD2ENV EQU rNR22
514 |
515 |
516 | ; --
517 | ; -- AUD2LOW/NR23 ($FF18)
518 | ; -- Frequency lo (W)
519 | ; --
520 | rNR23 EQU $FF18
521 | rAUD2LOW EQU rNR23
522 |
523 |
524 | ; --
525 | ; -- AUD2HIGH/NR24 ($FF19)
526 | ; -- Frequency hi (W)
527 | ; --
528 | ; -- see AUD1HIGH for info
529 | ; --
530 | rNR24 EQU $FF19
531 | rAUD2HIGH EQU rNR24
532 |
533 |
534 | ;***************************************************************************
535 | ;*
536 | ;* SoundChannel #3 registers
537 | ;*
538 | ;***************************************************************************
539 |
540 | ; --
541 | ; -- AUD3ENA/NR30 ($FF1A)
542 | ; -- Sound on/off (R/W)
543 | ; --
544 | ; -- Bit 7 - Sound ON/OFF (1EQUON,0EQUOFF)
545 | ; --
546 | rNR30 EQU $FF1A
547 | rAUD3ENA EQU rNR30
548 |
549 |
550 | ; --
551 | ; -- AUD3LEN/NR31 ($FF1B)
552 | ; -- Sound length (R/W)
553 | ; --
554 | ; -- Bit 7-0 - Sound length
555 | ; --
556 | rNR31 EQU $FF1B
557 | rAUD3LEN EQU rNR31
558 |
559 |
560 | ; --
561 | ; -- AUD3LEVEL/NR32 ($FF1C)
562 | ; -- Select output level
563 | ; --
564 | ; -- Bit 6-5 - Select output level
565 | ; -- 00: 0/1 (mute)
566 | ; -- 01: 1/1
567 | ; -- 10: 1/2
568 | ; -- 11: 1/4
569 | ; --
570 | rNR32 EQU $FF1C
571 | rAUD3LEVEL EQU rNR32
572 |
573 |
574 | ; --
575 | ; -- AUD3LOW/NR33 ($FF1D)
576 | ; -- Frequency lo (W)
577 | ; --
578 | ; -- see AUD1LOW for info
579 | ; --
580 | rNR33 EQU $FF1D
581 | rAUD3LOW EQU rNR33
582 |
583 |
584 | ; --
585 | ; -- AUD3HIGH/NR34 ($FF1E)
586 | ; -- Frequency hi (W)
587 | ; --
588 | ; -- see AUD1HIGH for info
589 | ; --
590 | rNR34 EQU $FF1E
591 | rAUD3HIGH EQU rNR34
592 |
593 |
594 | ; --
595 | ; -- AUD4LEN/NR41 ($FF20)
596 | ; -- Sound length (R/W)
597 | ; --
598 | ; -- Bit 5-0 - Sound length data (# 0-63)
599 | ; --
600 | rNR41 EQU $FF20
601 | rAUD4LEN EQU rNR41
602 |
603 |
604 | ; --
605 | ; -- AUD4ENV/NR42 ($FF21)
606 | ; -- Envelope (R/W)
607 | ; --
608 | ; -- see AUD1ENV for info
609 | ; --
610 | rNR42 EQU $FF21
611 | rAUD4ENV EQU rNR42
612 |
613 |
614 | ; --
615 | ; -- AUD4POLY/NR43 ($FF22)
616 | ; -- Polynomial counter (R/W)
617 | ; --
618 | ; -- Bit 7-4 - Selection of the shift clock frequency of the (scf)
619 | ; -- polynomial counter (0000-1101)
620 | ; -- freqEQUdrf*1/2^scf (not sure)
621 | ; -- Bit 3 - Selection of the polynomial counter's step
622 | ; -- 0: 15 steps
623 | ; -- 1: 7 steps
624 | ; -- Bit 2-0 - Selection of the dividing ratio of frequencies (drf)
625 | ; -- 000: f/4 001: f/8 010: f/16 011: f/24
626 | ; -- 100: f/32 101: f/40 110: f/48 111: f/56 (fEQU4.194304 Mhz)
627 | ; --
628 | rNR43 EQU $FF22
629 | rAUD4POLY EQU rNR43
630 |
631 |
632 | ; --
633 | ; -- AUD4GO/NR44 ($FF23)
634 | ; -- (has wrong name and value (ff30) in Dr.Pan's doc!)
635 | ; --
636 | ; -- Bit 7 - Inital
637 | ; -- Bit 6 - Counter/consecutive selection
638 | ; --
639 | rNR44 EQU $FF23
640 | rAUD4GO EQU rNR44 ; silly name!
641 |
642 | ;***************************************************************************
643 | ;*
644 | ;* Cart related
645 | ;*
646 | ;***************************************************************************
647 |
648 | CART_ROM EQU 0 ; ROM
649 | CART_ROM_MBC1 EQU 1 ; ROM+MBC1
650 | CART_ROM_MBC1_RAM EQU 2 ; ROM+MBC1+RAM
651 | CART_ROM_MBC1_RAM_BAT EQU 3 ; ROM+MBC1+RAM+BATTERY
652 | CART_ROM_MBC2 EQU 5 ; ROM+MBC2
653 | CART_ROM_MBC2_BAT EQU 6 ; ROM+MBC2+BATTERY
654 | CART_ROM_RAM EQU 8 ; ROM+RAM
655 | CART_ROM_RAM_BAT EQU 9 ; ROM+RAM+BATTERY
656 | CART_ROM_MMM EQU $b ; ROM+MMM01
657 | CART_ROM_RAM_MMM EQU $c ; ROM+RAM+MMM01
658 | CART_ROM_RAM_MMM_BAT EQU $d ; ROM+RAM+MMM01+BATTERY
659 | CART_ROM_MBC3_TIM_BAT EQU $f ; ROM+MBC3+TIMER+BATTERY
660 | CART_ROM_MBC3_TIM_RAM_BAT EQU $10 ; ROM+MBC3+TIMER+RAM+BATTERY
661 | CART_ROM_MBC3 EQU $11 ; ROM+MBC3
662 | CART_ROM_MBC3_RAM EQU $12 ; ROM+MBC3+RAM
663 | CART_ROM_MBC3_RAM_BAT EQU $13 ; ROM+MBC3+RAM+BATTERY
664 | CART_ROM_MBC4 EQU $15 ; ROM+MBC4
665 | CART_ROM_MBC4_RAM EQU $16 ; ROM+MBC4+RAM
666 | CART_ROM_MBC4_RAM_BAT EQU $17 ; ROM+MBC4+RAM+BATTERY
667 | CART_ROM_MBC5 EQU $19 ; ROM+MBC5
668 | CART_ROM_MBC5_RAM EQU $1a ; ROM+MBC5+RAM
669 | CART_ROM_MBC5_RAM_BAT EQU $1b ; ROM+MBC5+RAM+BATTERY
670 | CART_ROM_MBC5_RUM EQU $1c ; ROM+MBC5+RUMBLE
671 | CART_ROM_MBC5_RUM_RAM EQU $1d ; ROM+MBC5+RUMBLE+RAM
672 | CART_ROM_MBC5_RUM_RAM_BAT EQU $1e ; ROM+MBC5+RUMBLE+RAM+BATTERY
673 | CART_CAMERA EQU $fc ; Camera ROM
674 | CART_TAMA5 EQU $fd ; Bandai Tama 5
675 | CART_HuC3 EQU $fe ; HuC3
676 | CART_HuC1_RAM_BAT EQU $ff ; HuC1+RAM+BATTERY
677 |
678 | CART_ROM_256K EQU 0
679 | CART_ROM_512K EQU 1
680 | CART_ROM_1M EQU 2
681 | CART_ROM_2M EQU 3
682 | CART_ROM_4M EQU 4
683 | CART_ROM_8M EQU 5
684 | CART_ROM_16M EQU 6
685 |
686 | CART_RAM_NONE EQU 0
687 | CART_RAM_16K EQU 1
688 | CART_RAM_64K EQU 2
689 | CART_RAM_256K EQU 3
690 |
691 | CART_RAM_ENABLE EQU $0a
692 | CART_RAM_DISABLE EQU $00
693 |
694 | ;***************************************************************************
695 | ;*
696 | ;* Keypad related
697 | ;*
698 | ;***************************************************************************
699 |
700 | PADF_DOWN EQU $80
701 | PADF_UP EQU $40
702 | PADF_LEFT EQU $20
703 | PADF_RIGHT EQU $10
704 | PADF_START EQU $08
705 | PADF_SELECT EQU $04
706 | PADF_B EQU $02
707 | PADF_A EQU $01
708 |
709 | PADB_DOWN EQU $7
710 | PADB_UP EQU $6
711 | PADB_LEFT EQU $5
712 | PADB_RIGHT EQU $4
713 | PADB_START EQU $3
714 | PADB_SELECT EQU $2
715 | PADB_B EQU $1
716 | PADB_A EQU $0
717 |
718 | ;***************************************************************************
719 | ;*
720 | ;* Screen related
721 | ;*
722 | ;***************************************************************************
723 |
724 | SCRN_X EQU 160 ; Width of screen in pixels
725 | SCRN_Y EQU 144 ; Height of screen in pixels
726 | SCRN_X_B EQU 20 ; Width of screen in bytes
727 | SCRN_Y_B EQU 18 ; Height of screen in bytes
728 |
729 | SCRN_VX EQU 256 ; Virtual width of screen in pixels
730 | SCRN_VY EQU 256 ; Virtual height of screen in pixels
731 | SCRN_VX_B EQU 32 ; Virtual width of screen in bytes
732 | SCRN_VY_B EQU 32 ; Virtual height of screen in bytes
733 |
734 | NINTENDO_LOGO: MACRO
735 | ;*
736 | ;* Nintendo scrolling logo
737 | ;* (Code won't work on a real GameBoy)
738 | ;* (if next six lines are altered.)
739 | DB $CE,$ED,$66,$66,$CC,$0D,$00,$0B,$03,$73,$00,$83,$00,$0C,$00,$0D
740 | DB $00,$08,$11,$1F,$88,$89,$00,$0E,$DC,$CC,$6E,$E6,$DD,$DD,$D9,$99
741 | DB $BB,$BB,$67,$63,$6E,$0E,$EC,$CC,$DD,$DC,$99,$9F,$BB,$B9,$33,$3E
742 | ENDM
743 |
744 | ENDC ;HARDWARE_INC
--------------------------------------------------------------------------------
/make.cmd:
--------------------------------------------------------------------------------
1 | @REM RGBDS Makefile for Windows, written by tmk - https://github.com/gitendo
2 |
3 | @CD dmg
4 | @FOR /F "delims==" %%i in ('dir /b /on *.asm') DO @(
5 | rgbasm -i ..\inc\ -i ..\data\ -o %%~ni.o %%i
6 | @IF ERRORLEVEL 1 (
7 | ECHO Failed to assemble %%~i
8 | GOTO :eof
9 | )
10 | rgblink -d -o %%~ni.gb %%~ni.o
11 | @IF ERRORLEVEL 1 (
12 | ECHO Failed to link %%~ni.o
13 | GOTO :eof
14 | )
15 | @DEL %%~ni.o
16 | rgbfix -p 0 -r 0 -t DMG_EXAMPLE -v %%~ni.gb
17 | @IF ERRORLEVEL 1 (
18 | ECHO Failed to fix %%~ni.gb
19 | GOTO :eof
20 | )
21 | )
22 |
23 | @CD ../cgb
24 | @FOR /F "delims==" %%i in ('dir /b /on *.asm') DO @(
25 | rgbasm -i ..\inc\ -i ..\data\ -o %%~ni.o %%i
26 | @IF ERRORLEVEL 1 (
27 | ECHO Failed to assemble %%~i
28 | GOTO :eof
29 | )
30 | rgblink -o %%~ni.gbc %%~ni.o
31 | @IF ERRORLEVEL 1 (
32 | ECHO Failed to link %%~ni.o
33 | GOTO :eof
34 | )
35 | @DEL %%~ni.o
36 | rgbfix -C -p 0 -r 0 -t CGB_EXAMPLE -v %%~ni.gbc
37 | @IF ERRORLEVEL 1 (
38 | ECHO Failed to fix %%~ni.gbc
39 | GOTO :eof
40 | )
41 | )
42 |
43 |
44 | @ECHO Build successful!
--------------------------------------------------------------------------------