{"id":53,"date":"2021-09-17T13:20:00","date_gmt":"2021-09-17T12:20:00","guid":{"rendered":"https:\/\/techblog.dansbo.dk\/?p=53"},"modified":"2024-01-04T14:01:44","modified_gmt":"2024-01-04T13:01:44","slug":"commodore-64-to-commander-x16-converter","status":"publish","type":"post","link":"https:\/\/techblog.dansbo.dk\/?p=53","title":{"rendered":"Commodore 64 to Commander X16 converter"},"content":{"rendered":"\n<p>Here I want to provide an example of a very\u00a0<em>very<\/em>\u00a0simple program for the Commodore 64 and what is needed in order to convert that program to run on the Commander X16<\/p>\n\n\n\n<p>First the small progam that uses direct memory access to write to the screen.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>*=<font color=\"blue\">$0BB8<\/font> ; 3000 decimal, address where program should be loaded to.\n\n; Program writes an 'A' at top left and bottom right of screen and\n; sets it's color\nmain:\n\t<font color=\"orange\">lda<\/font>\t<font color=\"blue\">#01<\/font>\t; Screen code of 'A'\n\t<font color=\"orange\">sta<\/font>\t<font color=\"blue\">$0400<\/font>\t; Write to upper left corner\n\t<font color=\"orange\">sta<\/font>\t<font color=\"blue\">$07E7<\/font>\t; Write to lower right corner\n\n\t<font color=\"orange\">lda<\/font>\t<font color=\"blue\">#13<\/font>\t; Light Green color\n\t<font color=\"orange\">sta<\/font>\t<font color=\"blue\">$D800<\/font>\t; Top left character\n\t<font color=\"orange\">lda<\/font>\t<font color=\"blue\">#5<\/font>\t; Green color\n\t<font color=\"orange\">sta<\/font>\t<font color=\"blue\">$DBE7<\/font>\t; Lower right character\n\t<font color=\"orange\">rts<\/font><\/code><\/pre>\n\n\n\n<p>The result should look something like this:<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"715\" height=\"544\" src=\"https:\/\/techblog.dansbo.dk\/wp-content\/uploads\/2024\/01\/c64run.jpg\" alt=\"\" class=\"wp-image-54\" srcset=\"https:\/\/techblog.dansbo.dk\/wp-content\/uploads\/2024\/01\/c64run.jpg 715w, https:\/\/techblog.dansbo.dk\/wp-content\/uploads\/2024\/01\/c64run-300x228.jpg 300w\" sizes=\"auto, (max-width: 715px) 100vw, 715px\" \/><\/figure>\n\n\n\n<p>Here is a hexdump of the compiled program:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code> b8 0b a9 01 8d 00 04 8d  e7 07 a9 0d 8d 00 d8 a9\n 05 8d e7 db 60<\/code><\/pre>\n\n\n\n<p>Let me try and clean this up a bit to figure out what all these codes mean:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>  b8 0b\t\t; Address in mem where program is stored\n  a9 01\t\t; lda #01\n  8d 00 04\t; sta $0400\n  8d e7 07\t; sta $07E7\n  a9 0d\t\t; lda #13\n  8d 00 d8\t; sta $D800\n  a9 05\t\t; lda #5\n  8d e7 db\t; sta $DBE7\n  60\t\t; rts<\/code><\/pre>\n\n\n\n<p>Now that all the opcodes have been lined up and we have some nice comments, it is very easy to see that the hex numbers are just the small program we wrote. Remember that the 6502\/6510 is little-endian which means that it writes the low byte first.<\/p>\n\n\n\n<p>Now if the above program was run directly on the Commander X16, it would definitely not do what was intended. $400-$7FF in CX16 is just memory (called golden memory) so writing to it will not display anything on the screen. $0800-$9EFF is also just memory so writing to these addresses is not going to display anything on screen. Fortunately it is not going to break anything either unless we have other programs loaded at those addresses.<\/p>\n\n\n\n<p>Our program is very simple, but we still need to change it in order to make it run on the Commander X16. In this example, we know that every time something is stored to an address from $400-$7FF it is the same as plotting a character to the screen and every time something is stored to an address from $D800-$DBFF it is the same as setting a foreground color for a character on screen.<\/p>\n\n\n\n<p>Next issue is that the Commodore 64 default resolution is 40\u00d725.<br>The Commander X16 default resolution is 80\u00d760, but can be set to 40\u00d730<br>For ease of use, we will just set the CX16 to run in 40\u00d730 mode and ignore the bottom 5 lines of the screen.<\/p>\n\n\n\n<p>In order to calculate the coordinates where characters or colorcodes are stored, we first convert our hexadecimal numbers to decimal. This time we start from the bottom:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>$DBE7 = 56295 ; address being written to<\/li>\n\n\n\n<li>$D800 = 55296 ; base address<\/li>\n<\/ul>\n\n\n\n<p>Then we subtract the base address from the address we write to.<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>56295-55296 = 999<\/li>\n<\/ul>\n\n\n\n<p>To calculate the Y coordinate, we simply divide by the number of columns and disregard anything after the comma.<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>999 \/ 40 = 24.975 = 24<\/li>\n<\/ul>\n\n\n\n<p>So the Y coordinate is 24. To calculate the X coordinate, we subtract Y coordinate multiplied with columns (40)<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>999 \u2013 (24*40) = 39<\/li>\n<\/ul>\n\n\n\n<p>So the final set of coordinates is X=39, Y=24, but we already knew that\u00a0\ud83d\ude09<\/p>\n\n\n\n<p>Let us try with the other set of numbers.<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>$0400 = 1024<\/li>\n\n\n\n<li>$07E7 = 2023<\/li>\n\n\n\n<li>2023-1024 = 999<\/li>\n\n\n\n<li>999 \/ 40 = 24.975 = 24<\/li>\n\n\n\n<li>999 \u2013 (24*40) = 39<\/li>\n<\/ul>\n\n\n\n<p>In this case the character set and color values in Commander X16\u2019s VERA are the same as the Commodote 64 so we can write the character and colors without any conversion. That means that all we really need to do is:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Ensure that LOAD address works in Commander X16<\/li>\n\n\n\n<li>\u201cCatch\u201d all the writes that are going to Commodore 64 screen\/color RAM<\/li>\n\n\n\n<li>Set up VERA to point to correct VRAM address<\/li>\n\n\n\n<li>Store the value to VERA<\/li>\n<\/ul>\n\n\n\n<p>I will try to write some pseudo code to give an example on how the C64 program would be converted to X16.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Read the 2 first bytes of program to know where converted program should be stored\nSet screen mode to 40x30\nRead file in a loop\n\tIf opcode is LDA Then\n\t\tExecute the opcode\n\t\tPush A to stack\n\tEndif\n\tIf opcode is STA Then\n\t\tIf address is between $0400 &amp; $07FF\n\t\t\tCalculate the screen coordinate\n\t\t\tWrite screen coordinate to VERA\n\t\t\tPull A from stack\n\t\t\tWrite A to VERA\n\t\tEndif\n\t\tIf address is between $D800 &amp; $DBFF\n\t\t\tCalculate the screen coordinate\n\t\t\tWrite screen coordinate to VERA\n\t\t\tPull A from stack\n\t\t\tCombine background color with A\n\t\t\tWrite A to VERA\n\t\tEndif\n\tEndif\n\tIf opcode is RTS Then\n\t\tExecute the opcode\n\tEndif\nUntil end of file is reached<\/code><\/pre>\n\n\n\n<p>Above code is extremely simplified and only takes the 3 opcodes that are actually used in our c64 test program into account (LDA, STA &amp; RTS).<\/p>\n\n\n\n<p>Everytime LDA is encountered, we need to store the value read to the stack as we do not yet know what will happen with the value.<\/p>\n\n\n\n<p>Let us say that after LDA we encounter ASL, then we need to do a PLA to get the value from stack, do the ASL and then do a PHA to save the value onto the stack again.<\/p>\n\n\n\n<p>When we encounter STA, we need to figure out where we are storing to. If it is in Screen- or color-memory, we need to calculate the screen coordinates and write them to vera.<\/p>\n\n\n\n<p>If it is screen-memory, we can then PLA and STA to VERAs dataport.<\/p>\n\n\n\n<p>If it is color-memory we need to PLA and combine it with the existing background color before writing it back to VERA dataport.<\/p>\n\n\n\n<p>The generated code would look something like this:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>*=<font color=\"blue\">$0BB8<\/font> ; 3000 decimal\n\n;Program writes an 'A' at top left and bottom right of screen and sets it's color\nmain:\n\t<font color=\"orange\">lda<\/font>\t<font color=\"blue\">#0<\/font>\t; Set screen to 40x30\n\t<font color=\"orange\">jsr<\/font>\t<font color=\"blue\">$FF5F<\/font>\n\n\t<font color=\"orange\">lda<\/font>\t<font color=\"blue\">#00<\/font>\t; Write 0 to high addr\n\t<font color=\"orange\">sta<\/font>\t<font color=\"blue\">$9F22<\/font>\n\t<font color=\"orange\">lda<\/font>\t<font color=\"blue\">#00<\/font>\t; Write 0 to middle addr\n\t<font color=\"orange\">sta<\/font>\t<font color=\"blue\">$9F21<\/font>\n\t<font color=\"orange\">lda<\/font>\t<font color=\"blue\">#00<\/font>\t; double 0\n\t<font color=\"orange\">clc<\/font>\n\t<font color=\"orange\">asl<\/font>\n\t<font color=\"orange\">sta<\/font>\t<font color=\"blue\">$9F20<\/font>\t; Write it to low addr\n\t<font color=\"orange\">lda<\/font>\t<font color=\"blue\">#01<\/font>\t; Screen code of 'A'\n\t<font color=\"orange\">sta<\/font>\t<font color=\"blue\">$9F23<\/font>\t; Write upper left corner\n\n\t<font color=\"orange\">lda<\/font>\t<font color=\"blue\">#00\t<\/font>; write 0 to high addr\n\t<font color=\"orange\">sta<\/font>\t<font color=\"blue\">$9F22<\/font>\n\t<font color=\"orange\">lda<\/font>\t<font color=\"blue\">#24<\/font>\t; write 24 to middle addr\n\t<font color=\"orange\">sta<\/font>\t<font color=\"blue\">$9F21<\/font>\n\t<font color=\"orange\">lda<\/font>\t<font color=\"blue\">#39<\/font>\t; double 39\n\t<font color=\"orange\">clc<\/font>\n\t<font color=\"orange\">asl<\/font>\n\t<font color=\"orange\">sta<\/font>\t<font color=\"blue\">$9F20<\/font>\t; write it to low addr\n\t<font color=\"orange\">lda<\/font>\t<font color=\"blue\">#01<\/font>\t; Screen code of 'A'\n\t<font color=\"orange\">sta<\/font>\t<font color=\"blue\">$9F23<\/font>\n\n\t<font color=\"orange\">lda<\/font>\t<font color=\"blue\">#00<\/font>\t; Write 0 to high addr\n\t<font color=\"orange\">sta<\/font>\t<font color=\"blue\">$9F22<\/font>\n\t<font color=\"orange\">lda<\/font>\t<font color=\"blue\">#00<\/font>\t; Write 0 to middle addr\n\t<font color=\"orange\">sta<\/font>\t<font color=\"blue\">$9F21<\/font>\n\t<font color=\"orange\">lda<\/font>\t<font color=\"blue\">#00<\/font>\t; double 0\n\t<font color=\"orange\">clc<\/font>\n\t<font color=\"orange\">asl<\/font>\n\t<font color=\"orange\">inc<\/font>\t\t; increment for color addr\n\t<font color=\"orange\">sta<\/font>\t<font color=\"blue\">$9F20<\/font>\t; Write it to low addr\n\t<font color=\"orange\">lda<\/font>\t<font color=\"blue\">$9F23<\/font>\n\t<font color=\"orange\">and<\/font>\t<font color=\"blue\">#$F0<\/font>\n\t<font color=\"orange\">ora<\/font>\t<font color=\"blue\">#13<\/font>\t; Light Green color\n\t<font color=\"orange\">sta<\/font>\t<font color=\"blue\">$9F23<\/font>\n\n\t<font color=\"orange\">lda<\/font>\t<font color=\"blue\">#00<\/font>\t; write 0 to high addr\n\t<font color=\"orange\">sta<\/font>\t<font color=\"blue\">$9F22<\/font>\n\t<font color=\"orange\">lda<\/font>\t<font color=\"blue\">#24<\/font>\t; write 24 to middle addr\n\t<font color=\"orange\">sta<\/font>\t<font color=\"blue\">$9F21<\/font>\n\t<font color=\"orange\">lda<\/font>\t<font color=\"blue\">#39<\/font>\t; double 39\n\t<font color=\"orange\">clc<\/font>\n\t<font color=\"orange\">asl<\/font>\n\t<font color=\"orange\">inc<\/font>\t\t; increment for color addr\n\t<font color=\"orange\">sta<\/font>\t<font color=\"blue\">$9F20<\/font>\t; write it to low addr\n\t<font color=\"orange\">lda<\/font>\t<font color=\"blue\">$9F23<\/font>\n\t<font color=\"orange\">and<\/font>\t<font color=\"blue\">#$F0<\/font>\n\t<font color=\"orange\">ora<\/font>\t<font color=\"blue\">#5<\/font>\t; Green color\n\t<font color=\"orange\">sta<\/font>\t<font color=\"blue\">$9F23<\/font>\n\n\t<font color=\"orange\">rts<\/font><\/font><\/code><\/pre>\n\n\n\n<p>On the Commander X16, the result would end up looking like this:<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"642\" height=\"479\" src=\"https:\/\/techblog.dansbo.dk\/wp-content\/uploads\/2024\/01\/x16run.jpg\" alt=\"\" class=\"wp-image-55\" srcset=\"https:\/\/techblog.dansbo.dk\/wp-content\/uploads\/2024\/01\/x16run.jpg 642w, https:\/\/techblog.dansbo.dk\/wp-content\/uploads\/2024\/01\/x16run-300x224.jpg 300w\" sizes=\"auto, (max-width: 642px) 100vw, 642px\" \/><\/figure>\n\n\n\n<p>The above is not very sophisticated code and a lot could be done to improve the quality, but there are a lot of things that needs to be taken into consideration when converting from C64 to CX16. Our program only works directly with the screen- and color-ram, but programs can easily be manipulating things like KERNAL jump-vectors<\/p>\n\n\n\n<p>It may be possible to write a program that runs on a normal PC that can convert Commodore 64 programs to Commander X16 programs, but as far as I can see it would be an almost impossible task to create a program that runs on the Commander X16 and converts Commodore 64 programs on the fly.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Here I want to provide an example of a very\u00a0very\u00a0simple program for the Commodore 64 and what is needed in order to convert that program to run on the Commander&#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-53","post","type-post","status-publish","format-standard","hentry","category-uncategorized"],"_links":{"self":[{"href":"https:\/\/techblog.dansbo.dk\/index.php?rest_route=\/wp\/v2\/posts\/53","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=53"}],"version-history":[{"count":1,"href":"https:\/\/techblog.dansbo.dk\/index.php?rest_route=\/wp\/v2\/posts\/53\/revisions"}],"predecessor-version":[{"id":56,"href":"https:\/\/techblog.dansbo.dk\/index.php?rest_route=\/wp\/v2\/posts\/53\/revisions\/56"}],"wp:attachment":[{"href":"https:\/\/techblog.dansbo.dk\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=53"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/techblog.dansbo.dk\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=53"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/techblog.dansbo.dk\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=53"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}