{"id":41,"date":"2019-09-30T07:28:00","date_gmt":"2019-09-30T06:28:00","guid":{"rendered":"https:\/\/techblog.dansbo.dk\/?p=41"},"modified":"2024-01-04T12:49:43","modified_gmt":"2024-01-04T11:49:43","slug":"my-1st-assembler-game-for-cx16-part-1","status":"publish","type":"post","link":"https:\/\/techblog.dansbo.dk\/?p=41","title":{"rendered":"My 1st assembler game for CX16 \u2013 part 1"},"content":{"rendered":"\n<p>After I got done with&nbsp;<a href=\"https:\/\/techblog.dansbo.dk\/?p=38\" target=\"_blank\" rel=\"noreferrer noopener\">Hello World<\/a>&nbsp;in assembler for the Commander X16, I needed a new project to keep on learning about assembler programming for the 6502 processor and the CX16.<\/p>\n\n\n\n<p>As usual, when I need an idea, I could not think of anything that would fit. But one day I was playing a game, called Amaze, on my phone and I noticed that even though it is a graphical game, it actually uses \u201cblocks\u201d and I have yet to find a level that has more than 20\u00d720 blocks. It was perfect for a text-mode game.<\/p>\n\n\n\n<p>So the plan is to create a game similar to Amaze. It is simple, can be done in text-mode and does not need any sound to be playable.&nbsp;<a href=\"https:\/\/www.youtube.com\/watch?v=O2cVcbtyEWc\" target=\"_blank\" rel=\"noreferrer noopener\">Here<\/a>&nbsp;is a video showing one of the levels from Amaze to give you an idea of what the game is about.<\/p>\n\n\n\n<p>As the documentation for VERA seems to be very volatile and subject to changes, I want to avoid using it for now. Instead I will be using the&nbsp;<a href=\"https:\/\/cx16.dk\/c64-kernal-routines\/\" target=\"_blank\" rel=\"noreferrer noopener\">KERNAL API<\/a>s that are also referenced in the&nbsp;<a href=\"https:\/\/github.com\/x16Community\/x16-docs\/\" target=\"_blank\" rel=\"noreferrer noopener\">Commander X16 Programmers Reference<\/a>.<\/p>\n\n\n\n<p>I used my Hello World example as a template, but added some extra KERNAL functions and other constants.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>; Generate BASIC code so program can be\n; startet by issuing RUN command\n*=<font color=\"blue\">$0801<\/font>\t\t\t; Assembled code should start at $0801\n\t\t\t; (where BASIC programs start)\n\t\t\t; The real program starts at $0810 = 2064\n!byte <font color=\"blue\">$0C<\/font>,<font color=\"blue\">$08<\/font>$0A,<font color=\"blue\">$00<\/font>\t\t; 2-byte line number ($000A = 10)\n!byte <font color=\"blue\">$9E<\/font>\t\t; SYS BASIC token\n!byte <font color=\"blue\">$20<\/font>\t\t; &#91;space]\n!byte <font color=\"blue\">$32<\/font>,<font color=\"blue\">$30<\/font>,<font color=\"blue\">$36<\/font>,<font color=\"blue\">$34<\/font>\t; $32=\"2\",$30=\"0\",$36=\"6\",$34=\"4\"\n\t\t\t; (ASCII encoded nums for dec starting addr)\n!byte <font color=\"blue\">$00<\/font>\t\t; End of Line\n!byte <font color=\"blue\">$00<\/font>,<font color=\"blue\">$00<\/font>\t\t; This is address $080C containing\n\t\t\t; 2-byte pointer to next line of BASIC code\n\t\t\t; ($0000 = end of program)\n*=<font color=\"blue\">$0810<\/font>\t\t\t; Here starts the real program\n; ********** Commodore 64 KERNAL API ********************\nCHROUT=<font color=\"blue\">$FFD2<\/font>\t\t; CHROUT outputs a character\nCHRIN=<font color=\"blue\">$FFCF<\/font>\t\t; CHRIN reads from default input\nGETIN=<font color=\"blue\">$FFE4<\/font>\t\t; GETIN reads a single byte from\n\t\t\t; input, returns #0 if no key is\n\t\t\t; pressed = non-blocking\nPLOT=<font color=\"blue\">$FFF0<\/font>\t\t; PLOT gets or sets cursor position\n\n; ********** Commodore 128 KERNAL API *******************\nSWAPPER=<font color=\"blue\">$FF5F<\/font>\t\t; Switches between 40 &amp; 80 col mode\n\n; ********** Commander X16 specific *********************\nCOLPORT=<font color=\"blue\">$0286<\/font>\t\t; This address contains both\n\t\t\t; background and foreground color\n\t\t\t; On C64, only foreground\n\t\t\t; (low nibble) works.\n; ********** Available Zero-Page addresses **************\nTMP0=<font color=\"blue\">$00<\/font>\t\t; The first 3 and last 4 unused\nTMP1=<font color=\"blue\">$01<\/font>\t\t; zero-page locations are used\nTMP2=<font color=\"blue\">$02<\/font>\t\t; as temporary storage (registers)\n\nTMP3=<font color=\"blue\">$FB<\/font>\t\t; More space is available if we\nTMP4=<font color=\"blue\">$FC<\/font>\t\t; are sure that we are not using\nTMP5=<font color=\"blue\">$FD<\/font>\t\t; the BASIC Kernal\nTMP6=<font color=\"blue\">$FE<\/font>\t\t; I am NOT sure<\/code><\/pre>\n\n\n\n<p>NOTE: In the above code, SWAPPER=$FF5F refers the older emulator\/ROM where the function was copied directly from the C128 KERNAL. At ROM versions larger than R34, $FF5F is now called SCRMOD and does not work the way it is used in these examples. See The&nbsp;<a href=\"https:\/\/github.com\/x16Community\/x16-docs\/\" target=\"_blank\" rel=\"noreferrer noopener\">CX16 Programmers Reference<\/a><\/p>\n\n\n\n<p>Some information about Zero-Page addresses. The first 256 bytes ($0000-$00FF) of memory are referred to as Zero-Page. These can be used in a number of different addressing modes which can provide shorter\/faster instructions. They can also be used to allow indirect memory access. As the 6502 have a very limited number of registers, zero-page addresses are often used almost like registers.&nbsp;<s>In the Commander X16 there are only 7 zero-page addresses that are available to the user at alle times.<\/s><\/p>\n\n\n\n<p>After I got the KERNAL functions and constants in place, I startet creating small \u201chelper\u201d functions. The first couple of functions are very small and might just as well be macros. The reason I have created them as functions and not macros is to have the same calling convention for both the small and the large functions.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>; **************************************************************\n; GotoXY\n; **************************************************************\n; Description:\tMove cursor to specified coordinates\n; **************************************************************\n; Inputs:\tRegister X = Column (Y coordinate)\n;\t\tRegister Y = Row    (X coordinate)\n; **************************************************************\nGotoXY:\n\t<font color=\"orange\">clc<\/font>\t\t; Set Carry flag to ensure that\n\t\t\t; PLOT sets the position instead\n\t\t\t; of reading it\n\t<font color=\"orange\">jsr<\/font>\tPLOT\t; Call PLOT\n\t<font color=\"orange\">rts<\/font>\t\t; Return to caller\n\n; **************************************************************\n; HLine\n; **************************************************************\n; Description:\tPrint a horizontal line\n; **************************************************************\n; Inputs:\tRegister A = Character used to print the line\n;\t\tRegister X = Length of the line\n; **************************************************************\nHLine:\n\t<font color=\"orange\">jsr<\/font>\tCHROUT\t; Print character in register A\n\t<font color=\"orange\">dex<\/font>\t\t; Decrement value in register X\n\t<font color=\"orange\">bne<\/font>\tHLine\t; Jump to top if X &gt; 0\n\t<font color=\"orange\">rts<\/font>\t\t; Return to caller<\/code><\/pre>\n\n\n\n<p>The two functions above are very short and with the comments, my hope is that they are easy to understand as well. PLOT and CHROUT are both functions in the C64\/CX16&nbsp;<a href=\"https:\/\/cx16.dk\/c64-kernal-routines\/\" target=\"_blank\" rel=\"noreferrer noopener\">Kernal API<\/a>. Now that we have a function to create a horizontal line, we also need a function to create a vertical line.<\/p>\n\n\n\n<p>When creating a horizontal line, I was taking advantage of the fact that when a character is written to the screen with the CHROUT function, the cursor automatically advances to the next row and I could just write characters until I reached the length of the line.<\/p>\n\n\n\n<p>I do not have the same advantage when creating a vertical line. This time I need to ensure that the cursor is moved to the next column\/line before each character is printed.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>; **************************************************************\n; VLine\n; **************************************************************\n; Description:\tPrint a vertical line\n; **************************************************************\n; Inputs:\tRegister A = Character used to print the line\n;\t\tRegister X = Height of the line\n; **************************************************************\nVLine:\n\t<font color=\"orange\">stx<\/font>\tTMP0\t; Store line length in TMP0 variable\n\t<font color=\"orange\">sec<\/font>\t\t; Set carry flag to get cursor position\n\t<font color=\"orange\">jsr<\/font>\tPLOT\t; Get cursor position into X and Y regs\n\t<font color=\"orange\">stx<\/font>\tTMP1\t; Store Y position in TMP1 variable\n\n.loopVL\t<font color=\"orange\">jsr<\/font>\tCHROUT\t; Write character\n\t<font color=\"orange\">inc<\/font>\tTMP1\t; Increment Y position\n\t<font color=\"orange\">sta<\/font>\tTMP2\t; Save A reg as it is changed by GotoXY\n\t<font color=\"orange\">ldx<\/font>\tTMP1\t; Load Y position into X register\n\t<font color=\"orange\">jsr<\/font>\tGotoXY\t; Move cursor\n\t<font color=\"orange\">lda<\/font>\tTMP2\t; Restore A register (character)\n\t<font color=\"orange\">dec<\/font>\tTMP0\t; Decrement line height\n\t<font color=\"orange\">bne<\/font>\t.loopVL\t; Jump to top if we have not reached 0\n\t<font color=\"orange\">rts<\/font><\/code><\/pre>\n\n\n\n<p>Now the absolute basics are in place. I can move the cursor, I can draw horizontal- and vertical lines. Keep in mind that the line-drawing functions only work from left to right and top to bottom.<\/p>\n\n\n\n<p>Next up: Function to print strings. Function that can convert a value in a byte to decimal number represented in a string. Function that initializes the screen. Stay tuned for\u00a0<a href=\"https:\/\/techblog.dansbo.dk\/?p=43\">Part 2<\/a>.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>After I got done with&nbsp;Hello World&nbsp;in assembler for the Commander X16, I needed a new project to keep on learning about assembler programming for the 6502 processor and the CX16&#8230;.<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[],"class_list":["post-41","post","type-post","status-publish","format-standard","hentry","category-uncategorized"],"_links":{"self":[{"href":"https:\/\/techblog.dansbo.dk\/index.php?rest_route=\/wp\/v2\/posts\/41","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/techblog.dansbo.dk\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/techblog.dansbo.dk\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/techblog.dansbo.dk\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/techblog.dansbo.dk\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=41"}],"version-history":[{"count":2,"href":"https:\/\/techblog.dansbo.dk\/index.php?rest_route=\/wp\/v2\/posts\/41\/revisions"}],"predecessor-version":[{"id":46,"href":"https:\/\/techblog.dansbo.dk\/index.php?rest_route=\/wp\/v2\/posts\/41\/revisions\/46"}],"wp:attachment":[{"href":"https:\/\/techblog.dansbo.dk\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=41"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/techblog.dansbo.dk\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=41"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/techblog.dansbo.dk\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=41"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}