<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-5108605455275049037</id><updated>2011-09-03T20:22:18.282+01:00</updated><category term='Random'/><category term='BASIC'/><category term='Toolchain'/><category term='VICE'/><category term='Sprite'/><category term='Screen'/><category term='IRQ'/><category term='Pseudocode'/><category term='6502'/><category term='DASM'/><category term='Plotting'/><category term='Raster'/><category term='Vsync'/><category term='Editor'/><category term='Crimson'/><category term='Kernal'/><category term='Map'/><category term='Collision Detection'/><category term='Blue Meanies'/><category term='Assembly'/><category term='PETSCII'/><category term='Sourcecode'/><category term='ROM'/><category term='NMI'/><category term='Macro'/><category term='VIC-20'/><category term='BSOD'/><category term='Memory'/><category term='Zero Page'/><category term='BRK'/><category term='Vector'/><category term='Character'/><title type='text'>?Device Not Present</title><subtitle type='html'>VIC-20 Development Diary
&lt;br&gt;
and related musings</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://devicenotpresent.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5108605455275049037/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://devicenotpresent.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Jonners</name><uri>http://www.blogger.com/profile/10783097207231622242</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='29' src='http://3.bp.blogspot.com/_k7S257jPIsM/S4BCVi6S3sI/AAAAAAAAAqc/4_pLkqr1Wxc/s1600-R/CommodorePET4032.jpg'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>31</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-5108605455275049037.post-7110972627872155635</id><published>2011-03-30T12:44:00.000+01:00</published><updated>2011-03-30T12:44:52.297+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Character'/><category scheme='http://www.blogger.com/atom/ns#' term='Plotting'/><category scheme='http://www.blogger.com/atom/ns#' term='6502'/><category scheme='http://www.blogger.com/atom/ns#' term='DASM'/><title type='text'>edoM esreveR</title><content type='html'>&lt;div style="text-align: justify;"&gt;I've had a good think about the ASCII conversion problem over the last couple of days, and toyed with a few possibilities. The options are:&lt;/div&gt;&lt;ol&gt;&lt;li&gt;Chuck the whole idea in the bin and just go back to using the already-working 6502 code which runs during application startup, working through all the in-memory strings and converting them where they lie.&lt;/li&gt;&lt;li&gt;Write a DASM macro to encapsulate strings in some sort of byte markers, and then write a post-processor to scan the assembled binary looking for those markers and convert the strings.&lt;/li&gt;&lt;li&gt;Dive into the DASM sourcecode and add either a custom directive that would convert strings during the assembly process, or a more generic directive that would allow a branch out to a named process during assembly which could do whatever was needed.&lt;/li&gt;&lt;li&gt;Alter the existing pre-processor to somehow encode converted strings in such a way that control codes like ASCII 13 wouldn't break the line structure.&lt;/li&gt;&lt;li&gt;Change the mechanics of the way the pre-processor works so that it generates binary data instead of modified sourcecode, and have DASM pull that data in with INCBIN.&lt;/li&gt;&lt;/ol&gt;&lt;div style="text-align: justify;"&gt;As I said last time, I'm loathe to choose Option 1 because it's always going to be more elegant to have the strings already in screen-code inside the binary, and thus not require space for conversion logic or time during startup to execute it. Option 2 was where I'd tentatively got to, but it wasn't ideal - not least because my suspicion about labels being offset from the actual string was proven true, and I didn't really like having to add 'junk' around each string to identify it. Option 3 has a certain appeal, but it could easily take me several months to figure-out what changes to make without breaking anything. And Option 5 was a brief favourite, but upon investigation turned-out to be a bit unwieldy - in order for labels to work properly, every string would have to be a separate INCBIN. Yuck.&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;Which leaves Option 4, finding a way to alter the encoding of converted strings so they don't upset DASM. By chance, I was idly looking at the original CHARPLOT code which handles string plotting, and noticed something interesting - I use a bit in the Control Byte to indicate whether characters should be plotted in normal or reverse mode, and simply AND that bit into Bit 7 of the character before it gets spat to the screen. Bit 7 controls whether a (non-graphical) character is displayed as ink-on-paper colours, or paper-on-ink (inverse) colours, and all the screen-codes are stored with this bit clear - CHARPLOT sets the bit for each character it plots if the Reverse Mode flag bit in the Control Byte is set.&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;So the solution to the encoding problem presented itself - if I encode the strings in their converted form, but additionally have the pre-processor set Bit 7 before writing them out to the source file, they'll all be in the range 128-255 and thus won't trigger any ASCII control code issues. Then I can modify CHARPLOT so that it works the other way around - instead of &lt;i&gt;setting&lt;/i&gt; Bit 7 if the Reverse Mode flag is set, it can just &lt;i&gt;clear&lt;/i&gt; Bit 7 &lt;i&gt;unless&lt;/i&gt; the Reverse Mode flag is set. This is absolutely no extra work for the routine, and means that I can make everything work by with just two minor tweaks to code I already have.&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;I'll post an updated link to the pre-processor when I get a moment.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5108605455275049037-7110972627872155635?l=devicenotpresent.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://devicenotpresent.blogspot.com/feeds/7110972627872155635/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://devicenotpresent.blogspot.com/2011/03/edom-esrever.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5108605455275049037/posts/default/7110972627872155635'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5108605455275049037/posts/default/7110972627872155635'/><link rel='alternate' type='text/html' href='http://devicenotpresent.blogspot.com/2011/03/edom-esrever.html' title='edoM esreveR'/><author><name>Jonners</name><uri>http://www.blogger.com/profile/10783097207231622242</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='29' src='http://3.bp.blogspot.com/_k7S257jPIsM/S4BCVi6S3sI/AAAAAAAAAqc/4_pLkqr1Wxc/s1600-R/CommodorePET4032.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5108605455275049037.post-1414303486814807892</id><published>2011-03-28T11:08:00.000+01:00</published><updated>2011-03-28T11:08:21.128+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Character'/><category scheme='http://www.blogger.com/atom/ns#' term='PETSCII'/><category scheme='http://www.blogger.com/atom/ns#' term='Sourcecode'/><category scheme='http://www.blogger.com/atom/ns#' term='6502'/><category scheme='http://www.blogger.com/atom/ns#' term='DASM'/><title type='text'>Preaching To The Unconverted</title><content type='html'>&lt;div style="text-align: justify;"&gt;There I was, merrily chugging along turning pseudocode into real 6502, when I hit a roadblock. The thing about roadblocks is that they stop you in your tracks - you have to back up, have a look around, figure out an alternate route, and then forge a path forwards. Sometimes you have to back up quite a way before being able to proceed again - this is both irksome and time-consuming, because all the effort you're putting into reversing and finding a way forward again is of course effort you're &lt;i&gt;not&lt;/i&gt; putting into actual real forward progress.&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;It's even worse when the roadblock is a chunk of rubble you've dropped, all unwitting, into your &lt;i&gt;own&lt;/i&gt; path. Grr.&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;In my last post, I gloried in my own cleverness; I'd found a way to preconvert PETSCII strings in the sourcecode so that they were assembled that way and thus already in screen-code when the program ran, meaning I didn't need a couple of chunks of code in the app itself to do that conversion at startup. I wrote a little C# utility to run prior to the assembly, turning strings into codes and letting the development rig do the work of the conversion instead of the VIC. How jolly efficient.&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;Yeah. But.&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;Something I didn't anticipate jumped up and bit me over the weekend. The converter utility has been working perfectly over the past couple of weeks, quite happily chewing through the bits of sourcecode I've fed it, and spitting-out nice results - until yesterday, when DASM started falling-over in a heap complaining about unreadable junk in a source file and politely but firmly telling me it frankly wasn't good enough and would I please sort it out before trying again. So I had a look and, as you can probably guess, the offending lines were where my converted strings were. Something had gone wrong in the conversion process, flying in the face of weeks of faultless operation.&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;It was immediately obvious what was wrong - the build script runs the converter when the file with strings in changes, and I'd just added a couple more messages to the list, so it'd been converted. The resultant source file looked mostly OK, apart from a line I'd changed which now included an 'M'. Incredibly, no other message prior to this point had had an 'M' in it, so this was the first time it had been encountered. The converter duly took that ASCII 'M' and turned it into screen code 13 before writing it back to the source file. And ASCII code 13 is CR, Carriage Return - which meant the line of source now had a line-break in it and DASM didn't like it.&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;So, I'm now having to back-up and rethink the converter, since I can't really brag about it if it won't handle the letter 'M' - it's embarrassing, and I'm not going to expend effort in trying to write messages in my games that don't have 'M's in! Obviously preconverting the sourcecode isn't working, so I think I shall have to &lt;i&gt;post&lt;/i&gt;-process the assembled code and convert the strings inside the executable binary itself. But how to find them?&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;I could embed a few marker bytes in the sourcecode around the string area, and then zero-terminate each string within that region so that a post-processor could find and identify each one - but that requires that the strings be contiguous, and have nothing else around them. So you wouldn't be able to have strings defined as part of larger structures, because the converter wouldn't be able to differentiate between a string byte and any other byte.&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;So instead, I'm thinking of writing a DASM macro that handles the embedding of strings, with some sort of identifier byte combination to indicate where a string starts, and a zero terminator to show where it ends. This naturally adds a few bytes to the length of each string, but would mean that the post-processor could just scan the entire binary looking for the string marker and converting everything until hitting a zero. What could be tricky is labelling - wherever the code refers to a string, it's usually via a label, and that label will have to point to the actual start of the string rather than the marker bytes. Or maybe I'll just accept the fact that the label will be a couple of bytes off. This is something I won't know for sure what the solution is until I get into writing the macro itself.&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;Why bother with all this? After all, the 6502-based converter code works perfectly well, so why not just revert to doing the conversion on the VIC when the app starts? Well, if all else fails, I will - but having got so close to a working solution that saves on code size and execution time (on the VIC) I'm loathe to give up without a fight.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5108605455275049037-1414303486814807892?l=devicenotpresent.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://devicenotpresent.blogspot.com/feeds/1414303486814807892/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://devicenotpresent.blogspot.com/2011/03/preaching-to-unconverted.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5108605455275049037/posts/default/1414303486814807892'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5108605455275049037/posts/default/1414303486814807892'/><link rel='alternate' type='text/html' href='http://devicenotpresent.blogspot.com/2011/03/preaching-to-unconverted.html' title='Preaching To The Unconverted'/><author><name>Jonners</name><uri>http://www.blogger.com/profile/10783097207231622242</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='29' src='http://3.bp.blogspot.com/_k7S257jPIsM/S4BCVi6S3sI/AAAAAAAAAqc/4_pLkqr1Wxc/s1600-R/CommodorePET4032.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5108605455275049037.post-7876002504140396903</id><published>2011-03-04T15:23:00.000Z</published><updated>2011-03-04T15:23:46.679Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='Character'/><category scheme='http://www.blogger.com/atom/ns#' term='Plotting'/><category scheme='http://www.blogger.com/atom/ns#' term='PETSCII'/><category scheme='http://www.blogger.com/atom/ns#' term='Assembly'/><category scheme='http://www.blogger.com/atom/ns#' term='Toolchain'/><category scheme='http://www.blogger.com/atom/ns#' term='Sourcecode'/><category scheme='http://www.blogger.com/atom/ns#' term='6502'/><category scheme='http://www.blogger.com/atom/ns#' term='DASM'/><title type='text'>Pesky PETSCII Prevented</title><content type='html'>&lt;div style="text-align: justify;"&gt;I'm in the process of converting all of the pseudocode from the previous posts into real, genuine 6502 assembly, and it's going well - I may post some actual code in a few days. Simultaneously I've been thinking about the main thing that the old CHARPLOT mechanism did that the new Sprite framework doesn't do, which is support plotting of text strings to the screen - the CHARPLOT structures incorporated a feature which allowed strings to be hooked onto the object, and then processed using the same basic logic, but there's no facility to do this in the new model.&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;I quickly came up with a modified structure that strips-out all of the CHARPLOT object-plotting stuff (because we use the Sprite engine for that now) and optimised the string-handling feature, leaving a new STRPLOT structure that is very easy to manage, and can be passed directly to the low-level plotting logic inside the Sprite engine - so no separate string-specific drawing code is needed. This means that strings are defined as separate entities to Sprites, as you'd expect, but use Sprite-drawing features when they need to be displayed. I can now group all the games' strings together in a tight little bunch, and just refer to them when I want one drawn. Which is nice.&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;This then got me thinking about the technique I used to convert strings from ASCII (as they appear in the sourcecode) to PETSCII screen codes, which is what the VIC uses when drawing direct to the screen. Regular readers may recall earlier discussions on the topic, which resulted in a slick little routine which gets called when the game starts to convert all these strings in-place; the downside was that since the strings were CHARPLOT objects, the converter had to know all about how the objects were structured in order to do it's thing - essentially it had to mimic a chunk of the CHARPLOT drawing logic, but convert the characters instead of displaying them. I was never entirely happy with that.&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;However, I now have all the strings collected together in a simplified structure. In fact, it's so simple that I realised I could tackle the problem in a completely different way, by having the strings converted to PETSCII directly in the sourcecode, &lt;i&gt;before assembling the program&lt;/i&gt;. The build script I'm using is very straight-forward as it just takes the name of the root source file and gives it to DASM with a few preset parameters; so there's no reason why I couldn't include a step prior to that which pre-processed a specific file, looking for ASCII strings and converting them in-place to PETSCII. By assembling the code with the strings already converted, I can then lose both the (tiny) converter routine and the (larger) structure-interpreting routine which needed to run at startup.&lt;br /&gt;&lt;br /&gt;A matter of an hours' work in Visual Studio gave me a little app which takes a path to a 6502 source file as its' parameter, and then scans through it looking for DC.B strings. When it finds any, it applies the same code-conversion logic as the original 6502 routine did, and writes the new values back into the strings. Finally, it copies the original source file to a backup, and writes the modified copy out - this is so any INCLUDEs in other source files will point at the converted version and DASM will just build everything as normal. The caveat is that the converted file may become difficult to edit, because some PETSCII codes get interpreted as control characters when viewed in ASCII - which is why the app creates a backup, so you can always delete the converted version and copy the original back over it for editing.&lt;br /&gt;&lt;br /&gt;It's a repeatable process - if the app finds that a backup of the source file already exists, it assumes the file has been converted and won't attempt to convert it a second time (which would scramble things rather spectacularly). Consequently I can embed the call to it in the build script and let it run on every build, but it'll only do something when it spots there's no backup for the file it's targetting.&lt;br /&gt;&lt;br /&gt;Download link to a zipfile containing the binary over there on the right. Just drop the files into a folder somewhere, no lengthy install required - but you'll need the .NET 3.5 or 4.0 framework on your machine first, of course.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5108605455275049037-7876002504140396903?l=devicenotpresent.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://devicenotpresent.blogspot.com/feeds/7876002504140396903/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://devicenotpresent.blogspot.com/2011/03/pesky-petscii-prevented.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5108605455275049037/posts/default/7876002504140396903'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5108605455275049037/posts/default/7876002504140396903'/><link rel='alternate' type='text/html' href='http://devicenotpresent.blogspot.com/2011/03/pesky-petscii-prevented.html' title='Pesky PETSCII Prevented'/><author><name>Jonners</name><uri>http://www.blogger.com/profile/10783097207231622242</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='29' src='http://3.bp.blogspot.com/_k7S257jPIsM/S4BCVi6S3sI/AAAAAAAAAqc/4_pLkqr1Wxc/s1600-R/CommodorePET4032.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5108605455275049037.post-5032672553496182987</id><published>2011-02-28T18:29:00.000Z</published><updated>2011-02-28T18:29:55.896Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='Plotting'/><category scheme='http://www.blogger.com/atom/ns#' term='Sprite'/><category scheme='http://www.blogger.com/atom/ns#' term='Pseudocode'/><category scheme='http://www.blogger.com/atom/ns#' term='Collision Detection'/><title type='text'>Teh Pseudocodez, Part II</title><content type='html'>&lt;div style="text-align: justify;"&gt;Continuing work on the pseudocode for the new Sprite Manager framework, we can now look at the logic that handles movement and cleaning-up the AST. This routine was originally three separate passes through the AST to undraw sprites, move them, and handle deactivations - but after a goodly amount of brainstorming, I managed to combine them into a single pass through the table:&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;pre style="background-color: #eeeeee; border: 1px dashed rgb(153, 153, 153); color: black; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; font-size: 12px; line-height: 14px; overflow: auto; padding: 5px; width: 100%;"&gt;&lt;code&gt;; Unplot sprites by redrawing underlying character, then either zap the AST entry or calculate movement&lt;br /&gt;SPZAPMVE:&lt;br /&gt;  FOR X = AST[0] TO AST[AST.NSAB] ; Process each sprite in the table&lt;br /&gt;    CALL CHARPLOT (X.SCB.7, X.SPB, X.UPCB, X.UPCN) ; Draw the original character at the screen position&lt;br /&gt;    IF X.SCB.6 = 0   ; Sprite active?&lt;br /&gt;      CALL (X.SOAL.SMAB) (X.SCB.7, X.SPB) ; Yes, call movement handler (sets X.SCB.7, X.SPB and maybe X.SCB.6)&lt;br /&gt;      IF X.SCB.6 = 1    ; Sprite inactive? (moved beyond end-of-path)&lt;br /&gt;        CALL SPKILL (X)   ; Yes - destroy current sprite&lt;br /&gt;      END IF&lt;br /&gt;    ELSE&lt;br /&gt;      CALL SPKILL (X)   ; Destroy current sprite&lt;br /&gt;    END IF&lt;br /&gt;  NEXT&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;&lt;div style="text-align: justify;"&gt;We first undraw the sprite by plotting the original character that was at the screen position before the sprite moved to it during the previous cycle, and then - for any sprites that are active this time around - call the object movement handler routine, which determines what the next position will be. If the movement sends the sprite beyond any end-of-path boundary, it'll also mark it for deactivation. Lastly, any deactivated sprites get zapped from the AST using the 'SPKILL' logic outlined in the last post.&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;Here's an example of the movement handler for the Dropship object:&lt;/div&gt;&lt;br /&gt;&lt;div style="text-align: justify;"&gt;&lt;pre style="background-color: #eeeeee; border: 1px dashed rgb(153, 153, 153); color: black; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; font-size: 12px; line-height: 14px; overflow: auto; padding: 5px; width: 100%;"&gt;&lt;code&gt;; Move the Dropship&lt;br /&gt;DSMOVE:&lt;br /&gt;  X = AST[DROPSHIP]  ; Processing the AST entry for the Dropship during SPZAPMVE&lt;br /&gt;  X.SPB = X.SPB + 22  ; Down 1 screen line&lt;br /&gt;  IF X.SPB GT 255  ; Did we cross the mid-screen page boundary?&lt;br /&gt;    X.SCB.7 = 1   ; Yes - set the Base Offset bit&lt;br /&gt;  END IF&lt;br /&gt;  IF X.SCB.7 = 1 AND X.SPB GT 192 ; Did we fall past the end of the playfield area?&lt;br /&gt;    X.SCB.6 = 1   ; Yes - set the Deactivation bit&lt;br /&gt;  END IF&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;&lt;div style="text-align: justify;"&gt;Fairly simple, eh? Now here's the logic that happens at the end of the cycle to draw active sprites to the screen:&lt;/div&gt;&lt;br /&gt;&lt;div style="text-align: justify;"&gt;&lt;pre style="background-color: #eeeeee; border: 1px dashed rgb(153, 153, 153); color: black; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; font-size: 12px; line-height: 14px; overflow: auto; padding: 5px; width: 100%;"&gt;&lt;code&gt;; Plot active sprites&lt;br /&gt;SPDRAW:&lt;br /&gt;  FOR X = AST[0] TO AST[AST.NSAB] ; Process each sprite in the table&lt;br /&gt;    IF X.SCB.6 = 0   ; Sprite active?&lt;br /&gt;      CALL CHARPLOT (X.SCB.7, X.SPB, X.SOAL.PCB, X.SCB.0-3) ; Yep - draw the character at the screen position&lt;br /&gt;    END IF&lt;br /&gt;  NEXT&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;&lt;div style="text-align: justify;"&gt;It's that easy. But here's the tricky part - this is the heart of the whole thing, the bit that makes the magic happen: testing for and handling collisions between sprites, and between sprites and the playfield (the static background stuff):&lt;/div&gt;&lt;br /&gt;&lt;div style="text-align: justify;"&gt;&lt;pre style="background-color: #eeeeee; border: 1px dashed rgb(153, 153, 153); color: black; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; font-size: 12px; line-height: 14px; overflow: auto; padding: 5px; width: 100%;"&gt;&lt;code&gt;; Sprite collision-detection&lt;br /&gt;SPDETECT:&lt;br /&gt;  FOR X = AST[0] TO AST[AST.NSAB] ; Process each sprite in the table&lt;br /&gt;    X.UPCB = GETUPCB (X.SCB.7, X.SPB) ; Get screen character code at sprites' position&lt;br /&gt;    X.UPCN = GETUPCN (X.SCB.7, X.SPB) ; Get screen colour nybble at sprites' position&lt;br /&gt;    FOR Y = AST[X+1] TO AST[AST.NSAB] ; Scan all subsequent sprites in the table&lt;br /&gt;      IF X.SCB.7 = Y.SCB.7 AND X.SPB = Y.SPB ; Does another sprite have the same target position as this one?&lt;br /&gt;        FOR Z = 0 TO X.SOAL.SCB.0-3  ; Yes - scan this sprites' object definition collision-objects list&lt;br /&gt;          IF X.SOAL.COP[Z][1] = #Y#.LO         ; Is the other sprite in this sprites' collision list?&lt;br /&gt;            CALL (X.SOAL.COP[Z][2])  ; Yes - invoke collision-handler for these two sprite objects&lt;br /&gt;            BREAK    ; Exit inner loop and check next sprite&lt;br /&gt;          END IF&lt;br /&gt;        NEXT&lt;br /&gt;      END IF&lt;br /&gt;    NEXT&lt;br /&gt;    FOR Y = SOD[PLAYFIELD] TO SOD[END]  ; Process playfield SODs (at end of SOD table after sprites)&lt;br /&gt;      IF X.UPCB = Y.PCB    ; Is this sprite going to hit a playfield character?&lt;br /&gt;        FOR Z = 0 TO X.SOAL.SCB.0-3         ; Yes - scan this sprites' object definition collision-objects list&lt;br /&gt;          IF X.SOAL.COP[Z][1] = #Y#.LO  ; Is the playfield character in this sprites' collision list?&lt;br /&gt;            CALL (X.SOAL.COP[Z][2])  ; Yes - invoke collision-handler for the sprite and playfield objects&lt;br /&gt;            BREAK    ; Exit inner loop and check next sprite&lt;br /&gt;          END IF&lt;br /&gt;        NEXT&lt;br /&gt;      END IF&lt;br /&gt;    NEXT&lt;br /&gt;  NEXT&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;&lt;div style="text-align: justify;"&gt;Yep, as you'd expect this is a fairly complicated routine to look at - but actually, it's pretty simple in operation. After grabbing the screen character and colour data for where the sprite is about to go (we execute this routine after SPZAPMVE but before SPDRAW) the logic is actually just doing two things; first, a pass over all the sprite objects in the AST after this one to see if any others are going to move to the same place, and second a pass over all the playfield sprite object definitions (which go at the end of the SOD table after the 'proper' sprites) to see if any of those register as collisions. In either case, if a collision happens we call the appropriate collision-handler routine as described in the SOD for this sprite, and carry on.&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;If any collisions did occur which resulted in an action being taken, the collision-handler takes care of all of that, and possibly sets this or the other sprites' deactivation bit. In order for all this to hang together, things have to happen in this order:&lt;/div&gt;&lt;br /&gt;&lt;div style="text-align: justify;"&gt;&lt;pre style="background-color: #eeeeee; border: 1px dashed rgb(153, 153, 153); color: black; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; font-size: 12px; line-height: 14px; overflow: auto; padding: 5px; width: 100%;"&gt;&lt;code&gt;; Update screen&lt;br /&gt;UPDTSCRN:&lt;br /&gt;  CALL SPZAPMVE   ; Undraw, move and/or zap sprites&lt;br /&gt;  CALL INITSPR   ; See if any sprites need instantiating&lt;br /&gt;  CALL SPDETECT   ; Check for and handle collisions&lt;br /&gt;  CALL SPDRAW   ; Draw sprites&lt;br /&gt;  WAIT VSYNC   ; Wait for VSYNC to draw screen&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;&lt;div style="text-align: justify;"&gt;And we're done - there are a few other minor support routines and tables of addresses that sit alongside this stuff, but this is the meat on the bones. Now to turn it into real 6502 code...&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5108605455275049037-5032672553496182987?l=devicenotpresent.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://devicenotpresent.blogspot.com/feeds/5032672553496182987/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://devicenotpresent.blogspot.com/2011/02/teh-pseudocodez-part-ii.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5108605455275049037/posts/default/5032672553496182987'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5108605455275049037/posts/default/5032672553496182987'/><link rel='alternate' type='text/html' href='http://devicenotpresent.blogspot.com/2011/02/teh-pseudocodez-part-ii.html' title='Teh Pseudocodez, Part II'/><author><name>Jonners</name><uri>http://www.blogger.com/profile/10783097207231622242</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='29' src='http://3.bp.blogspot.com/_k7S257jPIsM/S4BCVi6S3sI/AAAAAAAAAqc/4_pLkqr1Wxc/s1600-R/CommodorePET4032.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5108605455275049037.post-3982892343521045053</id><published>2011-02-27T12:11:00.001Z</published><updated>2011-02-27T16:50:47.615Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='Plotting'/><category scheme='http://www.blogger.com/atom/ns#' term='Sprite'/><category scheme='http://www.blogger.com/atom/ns#' term='Pseudocode'/><category scheme='http://www.blogger.com/atom/ns#' term='Collision Detection'/><title type='text'>Spritely Progress</title><content type='html'>&lt;div style="text-align: justify;"&gt;So, I switched to N++ for code-editing and managing the Assemble-Launch-Test stuff, and it all seems to be hanging together quite nicely. I fired-up the sourcecode for Meanies, and everything looked good - at which point I put my biggest thinking-cap on, and started to map out what the Sprite framework should look like. This has resulted in a good few lines of structure definitions and pseudocode, which I have now refined into an optimised form. Let's see what we've got so far.&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;This is the structure for a Sprite Object Definition (SOD - unfortunate nomenclature, but there it is) which largely replaces the original CHARPLOT structure:&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;pre style="background-color: #eeeeee; border: 1px dashed rgb(153, 153, 153); color: black; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; font-size: 12px; line-height: 14px; overflow: auto; padding: 5px; width: 100%;"&gt;&lt;code&gt;Sprite Object Definition&lt;br /&gt;------------------------&lt;br /&gt;&lt;br /&gt;Sprite Control Byte&lt;br /&gt;  7 : Colour 2&lt;br /&gt;  6 : Colour 1&lt;br /&gt;  5 : Colour 0 &lt;br /&gt;  4 : Initial Screen Position Base Offset (0=0, 1=256)&lt;br /&gt;  3 : Collidable Object Count 3&lt;br /&gt;  2 : Collidable Object Count 2&lt;br /&gt;  1 : Collidable Object Count 1&lt;br /&gt;  0 : Collidable Object Count 0&lt;br /&gt;&lt;br /&gt;Initial Screen Position Byte&lt;br /&gt;  Value added to SCB.4 for initial screen position&lt;br /&gt;&lt;br /&gt;Plot Code Byte&lt;br /&gt;  Character code to be plotted&lt;br /&gt;&lt;br /&gt;Sprite Movement Address Word&lt;br /&gt;  1-2 : Address of movement routine for this object&lt;br /&gt;&lt;br /&gt;Collidable Object Pointer(s)&lt;br /&gt;  1 : Byte reference to SOD with which this object can collide&lt;br /&gt;  2 : Byte reference to SCHT entry for address of collision-handler for this collision type&lt;br /&gt;  &lt;br /&gt;Notes: SOD entries must not cross page-boundaries as the lo-byte of each entry is used as the pointer in the AST.SOAL.&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;&lt;div style="text-align: justify;"&gt;In this model, sprites are constrained to character-level plotting, but the design allows for this to be extended to bitmap-level (i.e. pixel-based) hi-res mode later. Each SOD occupies a minimum of 5 bytes, plus 2 more for each Collidable Object reference - if this sprite needs to do something when it hits another sprite, we add a Collidable Object reference which gives us a pointer to the other sprite(s) which can be collided-with and a pointer to the address of the routine to call when we collide with it. The SCHT (Sprite Collision Handler Table) is a simple table of addresses which point to the collision-handlers:&lt;/div&gt;&lt;br /&gt;&lt;div style="text-align: justify;"&gt;&lt;pre style="background-color: #eeeeee; border: 1px dashed rgb(153, 153, 153); color: black; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; font-size: 12px; line-height: 14px; overflow: auto; padding: 5px; width: 100%;"&gt;&lt;code&gt;Sprite Collision Handler Table&lt;br /&gt;------------------------------&lt;br /&gt;&lt;br /&gt;Sprite Collision Address Word&lt;br /&gt;  1-2 : Address of collision-handler between first/second objects&lt;br /&gt;  &lt;br /&gt;Notes: SCHT entries must not cross page-boundaries as the lo-byte of each entry is used as the pointer in the SOD.COP.&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;&lt;div style="text-align: justify;"&gt;So these two tables together represent the 'static' object definitions and the pointers to the routines which handle their movement and any collisions with other objects. If a SOD can't collide with anything (that is, if we don't want to know when it collides) then it has no COP entries; on the other hand, anything we want to know about collisions with, and do something about, has a two-byte COP entry which points to the other SOD entry we want to register collisions with, and to the address of the routine which handles those collisions. Each SOD can register up to 15 collidable objects, but that's only limited due to the use of 4 bits in the SCB.&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;So we now need a structure which manages 'active' sprites - as we instantiate a sprite based on its' SOD entry, we have to keep track of where it is and what it's doing, and that's where the Active Sprite Table makes its' appearance:&lt;/div&gt;&lt;br /&gt;&lt;div style="text-align: justify;"&gt;&lt;pre style="background-color: #eeeeee; border: 1px dashed rgb(153, 153, 153); color: black; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; font-size: 12px; line-height: 14px; overflow: auto; padding: 5px; width: 100%;"&gt;&lt;code&gt;Active Sprite Table&lt;br /&gt;-------------------&lt;br /&gt;&lt;br /&gt;Next Slot Address Byte  [Next free AST slot]&lt;br /&gt;&lt;br /&gt;Last Slot Address Byte  [Last AST slot at end of table]&lt;br /&gt;&lt;br /&gt;Sprite Object Address Lo-Byte [Initialised from SOD Address]&lt;br /&gt;&lt;br /&gt;Sprite Control Byte  [Initialised from SOD.SCB]&lt;br /&gt;  7 : Screen Position Base Offset (0=0, 1=256)&lt;br /&gt;  6 : Deactivate Sprite (0=Do not deactivate, 1=Deactivate)&lt;br /&gt;  5 : Unused&lt;br /&gt;  4 : Unused&lt;br /&gt;  3 : Unused&lt;br /&gt;  2 : Colour 2&lt;br /&gt;  1 : Colour 1&lt;br /&gt;  0 : Colour 0 &lt;br /&gt;&lt;br /&gt;Screen Position Byte  [Initialised from SOD.ISPB]&lt;br /&gt;  Undraw Plot Code Byte  [Initialised to screen character code]&lt;br /&gt;&lt;br /&gt;Undraw Plot Colour Nybble [Initialised to screen character colour]&lt;br /&gt;  7 : Unused&lt;br /&gt;  6 : Unused&lt;br /&gt;  5 : Unused&lt;br /&gt;  4 : Unused&lt;br /&gt;  3 : Colour 3&lt;br /&gt;  2 : Colour 2&lt;br /&gt;  1 : Colour 1&lt;br /&gt;  0 : Colour 0 &lt;br /&gt; &lt;br /&gt;Notes: Sprites are active when they have an entry in the AST - when inactive, they do not appear here.&lt;br /&gt;AST entries must not cross page-boundaries since the NSAB and LSAB are indexes into the table.&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;&lt;div style="text-align: justify;"&gt;The first two bytes of the AST control where the current end-of-table point is and what the maximum is - each AST object entry is 5 bytes, which means that if we align the table to the start of a page it can host up to 50 sprites simultaneously. Meanies is going to need about a dozen, so we've got the option to reduce the maximum table size and have it share page space with the SOD table - ideally these will both sit in the Zero Page, meaning all the accesses can be written using ZP addressing for speed. For projects needing more sprites, the tables might have to sit in separate pages, and I'd need to tweak the code to do 'normal' address-mode access.&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;Speaking of code, let's look at the pseudocode for instantiating a sprite from the SOD into the AST:&lt;/div&gt;&lt;br /&gt;&lt;div style="text-align: justify;"&gt;&lt;pre style="background-color: #eeeeee; border: 1px dashed rgb(153, 153, 153); color: black; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; font-size: 12px; line-height: 14px; overflow: auto; padding: 5px; width: 100%;"&gt;&lt;code&gt;  ; Sprite activation (called as new sprites are needed)&lt;br /&gt;  SPCREATE:&lt;br /&gt;    IF AST.NSAB GT AST.LSAB ; Is next free slot address higher than last available slot address?&lt;br /&gt;      ERROR   ; Yep - too many sprites, crash and burn&lt;br /&gt;    ELSE&lt;br /&gt;      X = AST[AST.NSAB]  ; No - there is a free AST slot&lt;br /&gt;      Y = SOD   ; Specified sprite object definition for this new active sprite&lt;br /&gt;      X.SOAL = #Y#.LO  ; Populate new AST entry, lo-byte of address of the SOD&lt;br /&gt;      X.SCB = Y.SCB  ; Control Byte&lt;br /&gt;      X.SPB = Y.ISPB  ; Set Screen Position to Initial Position&lt;br /&gt;      X.SCB.0 = X.SCB.5  ; Move sprite colour from bits 5-7 to bits 0-2 (LSR)&lt;br /&gt;      X.SCB.1 = X.SCB.6&lt;br /&gt;      X.SCB.2 = X.SCB.7&lt;br /&gt;      X.SCB.7 = X.SCB.4  ; Move Initial Screen Base bit 4 to Base bit 7 (ROR)&lt;br /&gt;      AST.NSAB = AST.NSAB + 5 ; Increment pointer to next free AST slot&lt;br /&gt;    END IF&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;&lt;div style="text-align: justify;"&gt;Assuming there's a free slot at the end of the AST, we copy the SOD pointer, its' Control Byte, and Initial Screen Position Byte to the new AST entry, shuffle the bits in the SCB around to throw away the COP count and put things in positions which are faster to work with, and increment the AST pointer to the next slot. The two other AST bytes (UPCB and UPCN) don't need to be initialised - they're populated later, as we'll see. And that's it, the sprite is now active!&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;I'll end this post with the reciprocal code to deactivate a sprite and destroy its' AST entry. This routine gets called whenever a sprite is registered as being out of play, which arises either when a collision event occurs which kills it, or if it reaches an end-of-path situation (such as falling off the screen):&lt;/div&gt;&lt;br /&gt;&lt;div style="text-align: justify;"&gt;&lt;pre style="background-color: #eeeeee; border: 1px dashed rgb(153, 153, 153); color: black; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; font-size: 12px; line-height: 14px; overflow: auto; padding: 5px; width: 100%;"&gt;&lt;code&gt; ; Destroy a sprite AST entry and shuffle the rest down&lt;br /&gt;SPKILL:&lt;br /&gt;  FOR X = AST[N] TO AST[AST.NSAB]  ; Process sprites from 'N' to the end of the AST&lt;br /&gt;    X.SOAL = X+1.SOAL     ; Copy all sprite data down a slot (destroys object N)&lt;br /&gt;    X.SCB = X+1.SCB&lt;br /&gt;    X.SPB = X+1.SPB&lt;br /&gt;    X.UPCB = X+1.UPCB&lt;br /&gt;    X.UPCN = X+1.UPCN&lt;br /&gt;  NEXT&lt;br /&gt;  AST.NSAB = AST.NSAB - 5    ; Decrement pointer to next free AST slot &lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;&lt;div style="text-align: justify;"&gt;That's it for now - next time, I'll present the pseudocode for drawing/undrawing sprites, and the special sauce that is the collision-detection routine. I'll also demonstrate the order in which these various routines must be called during each frame-display cycle, and maybe post some actual code. Stay tuned!&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5108605455275049037-3982892343521045053?l=devicenotpresent.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://devicenotpresent.blogspot.com/feeds/3982892343521045053/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://devicenotpresent.blogspot.com/2011/02/spritely-progress.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5108605455275049037/posts/default/3982892343521045053'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5108605455275049037/posts/default/3982892343521045053'/><link rel='alternate' type='text/html' href='http://devicenotpresent.blogspot.com/2011/02/spritely-progress.html' title='Spritely Progress'/><author><name>Jonners</name><uri>http://www.blogger.com/profile/10783097207231622242</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='29' src='http://3.bp.blogspot.com/_k7S257jPIsM/S4BCVi6S3sI/AAAAAAAAAqc/4_pLkqr1Wxc/s1600-R/CommodorePET4032.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5108605455275049037.post-8499268899653914963</id><published>2011-02-11T13:10:00.000Z</published><updated>2011-02-11T13:10:38.276Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='Editor'/><category scheme='http://www.blogger.com/atom/ns#' term='Plotting'/><category scheme='http://www.blogger.com/atom/ns#' term='Toolchain'/><category scheme='http://www.blogger.com/atom/ns#' term='Crimson'/><category scheme='http://www.blogger.com/atom/ns#' term='VICE'/><category scheme='http://www.blogger.com/atom/ns#' term='Collision Detection'/><title type='text'>Resurrection Ship</title><content type='html'>&lt;div style="text-align: justify;"&gt;Well, I'm back. I can't believe my last post was in September of last year, and that over four months have passed me by - but then, that's what happens to side-projects like this when Real Life decides to slap you around a bit. It started with a bad back, which meant I couldn't sit in The Chair of Coding for a fortnight or so. Then some other family-related stuff consumed a bunch of time, followed by Christmas, New Year, and then the return of the bad back which actually took a serious turn and needed proper medical attention. I'm now on the mend (though still restricted of movement and unable to sit for more than 20 minutes at a time) thanks entirely to a wonderful physiotherapist who entertains herself by spending an hour every few days bending my lower back into new and interesting shapes.&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;So, with a Big Project just appearing over the horizon - I'm in the R&amp;amp;D stage right now, hoping to kick-off in April/May - and a little spare time available, I want to finish this game and publish it for all to enjoy, point-and-laugh at, or fall to their knees in awe of (delete as applicable). I've been thinking about the technicalities of the code over the past few days, and have decided that the best thing to do regarding the collision-detection cycle situation is to bite the bullet and write a proper framework to do this stuff in - kind of like what I did back at the beginning when pondering how to write to the screen efficiently, and which subsequently gave us CharPlot.&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;So, over this weekend my plan is to create a new 'Sprite' object structure, which will include the CharPlot structure but extend things by giving me a simple way to describe what was under the object when it moved, what to draw after it moves again, and what conditions trigger a collision-event. I use the term 'Sprite' loosely, since we're still working at the character level rather than at the pixel level, but since the CharPlot structure is already designed to accommodate pixel-level granularity (even though the CharPlot logic doesn't yet) this is a precursor to switching to that level in a later revision.&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;I will spend some hours reworking the routines that call CharPlot so that they route through a new Sprite handler to get to the right bits of data, and then I can rip out the nastiness that is the current collision-detection logic (or illogic, to be honest) and replace it with a nice Sprite-based routine which will use the extended features of the new structure.&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;But before I do any of that, I'm going to see if Notepad++ is really as good as it looks like it might be. Crimson Editor has served me well, but it's not quite up to the job of handling the kinds of complex macros I want to run when doing the save-assemble-test loop - and having played a little with N++ I'm thinking it might be just what I need to speed things up and remove some manual point-and-click steps when getting the code running in VICe.&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;So tonight is just going to be a couple of hours of environment tweaking, and then the next couple of sessions will be the aforementioned Sprite stuff. Stay tuned!&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5108605455275049037-8499268899653914963?l=devicenotpresent.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://devicenotpresent.blogspot.com/feeds/8499268899653914963/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://devicenotpresent.blogspot.com/2011/02/resurrection-ship.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5108605455275049037/posts/default/8499268899653914963'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5108605455275049037/posts/default/8499268899653914963'/><link rel='alternate' type='text/html' href='http://devicenotpresent.blogspot.com/2011/02/resurrection-ship.html' title='Resurrection Ship'/><author><name>Jonners</name><uri>http://www.blogger.com/profile/10783097207231622242</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='29' src='http://3.bp.blogspot.com/_k7S257jPIsM/S4BCVi6S3sI/AAAAAAAAAqc/4_pLkqr1Wxc/s1600-R/CommodorePET4032.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5108605455275049037.post-3286094322296774959</id><published>2010-09-27T14:47:00.000+01:00</published><updated>2010-09-27T14:47:36.098+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Screen'/><category scheme='http://www.blogger.com/atom/ns#' term='Collision Detection'/><title type='text'>Slow Meanies</title><content type='html'>&lt;div style="text-align: justify;"&gt;I've been incredibly busy with other stuff over the last two or three weeks, and haven't been able to get near the game aside from the odd 15-20 minutes here and there - hardly long enough to fire the development environment tools up, re-orientate myself to remember what needs doing next, and write anything productive longer than a few instructions.&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;However, I &lt;i&gt;did&lt;/i&gt; plug-in the code to stash the contents of the screen location that a Meanie is about to move to, so that we can then check to see what it hit &lt;b&gt;after&lt;/b&gt; the event, rather than before. This kind-of worked, in that I now have a view of what the Meanie overwrote when it moved, but I got lost in a tangle of logic when trying to figure-out exactly when I should look at that data to decide if the Meanie hit something (and therefore to trigger the events that happen when it does).&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;So I sat down and wrote the main game loop as a psuedo-code script, to make it easier to determine what happens when (and therefore when things need to be updated and checked) during each game cycle. This helped immensely, because although the code is not especially complex, it can sometimes be tricky to keep the whole picture - and the event sequence - in your head. Writing the sequence out has two benefits - firstly, you can see the whole chain of events at a glance, and don't have to keep trying to remember if the bit of code you're writing happens &lt;i&gt;before&lt;/i&gt; or &lt;i&gt;after&lt;/i&gt; a critical point; and secondly it forces you to account for things that happen in one cycle that have an effect in the next (or even the one after that).&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;So I now see why my first attempt at tracking Meanie collisions wasn't working - although I am now correctly stashing the screen contents before the Meanie moves, and correctly checking it later, there's actually a three game-cycle activity going on, where I had imagined it only as two:&lt;/div&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Cycle&amp;nbsp;&amp;nbsp;&amp;nbsp; Action&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;&amp;nbsp; 1&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp;&amp;nbsp; Meanie moves, and we track that it overwrote a wall character &lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;&amp;nbsp; 2 &amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; Meanie moves again, but we recognise that previously it hit a wall, so just blank it&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp; 3&amp;nbsp; &amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Meanie is now out of play and can be re-instantiated&lt;br /&gt;&lt;br /&gt;&lt;div style="text-align: justify;"&gt;This three-cycle collision sequence only became apparent when I mapped it out in pseudo-code, as before I was trying to combine two of these three steps in a single cycle. This meant I either didn't blank the Meanie when it hit a wall, or I did but then had the 'out-of-play' flag set at the wrong point in the cycle and had 'random' Meanie appearances even after it was supposed to be dead.&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;I can now go back and rework the main loop to handle this sequence - it reminds me of Eric Morcambe, playing the piano with Andre Previn: "All the right notes, just not necessarily in the right order".&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5108605455275049037-3286094322296774959?l=devicenotpresent.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://devicenotpresent.blogspot.com/feeds/3286094322296774959/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://devicenotpresent.blogspot.com/2010/09/slow-meanies.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5108605455275049037/posts/default/3286094322296774959'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5108605455275049037/posts/default/3286094322296774959'/><link rel='alternate' type='text/html' href='http://devicenotpresent.blogspot.com/2010/09/slow-meanies.html' title='Slow Meanies'/><author><name>Jonners</name><uri>http://www.blogger.com/profile/10783097207231622242</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='29' src='http://3.bp.blogspot.com/_k7S257jPIsM/S4BCVi6S3sI/AAAAAAAAAqc/4_pLkqr1Wxc/s1600-R/CommodorePET4032.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5108605455275049037.post-2701033219489201850</id><published>2010-09-04T23:48:00.000+01:00</published><updated>2010-09-04T23:48:56.659+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Character'/><category scheme='http://www.blogger.com/atom/ns#' term='Plotting'/><category scheme='http://www.blogger.com/atom/ns#' term='Raster'/><category scheme='http://www.blogger.com/atom/ns#' term='BASIC'/><category scheme='http://www.blogger.com/atom/ns#' term='Assembly'/><category scheme='http://www.blogger.com/atom/ns#' term='Vsync'/><category scheme='http://www.blogger.com/atom/ns#' term='Screen'/><category scheme='http://www.blogger.com/atom/ns#' term='Collision Detection'/><title type='text'>Collision Complication</title><content type='html'>&lt;div style="text-align: justify;"&gt;Solid progress today, much better than I expected - I now have Meanies and the Fuelship moving around on the screen, tidying-up after themselves and not leaving little trails lying around. The Meanies move the right way, the Fuelship appears at the right sort of interval and descends gracefully, and suddenly the whole game is starting to look 'alive'. There's a fair way to go yet, but it's definitely getting there!&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;I dropped a little 'Vsync' wait into the main game loop to get rid of plotting flicker, so the main loop now runs once per screen refresh and then waits for the raster counter to reset before continuing. There's no point running the game faster than this, because although it actually &lt;i&gt;can&lt;/i&gt; run about 50 'cycles' per frame, the player can't see the benefit of it because the screen isn't redrawn that quickly. Also, running faster than the refresh rate makes the updates a bit flickery, so it looks slightly rubbish. By waiting for Vsync, we only update the screen once per frame, just before the VIC chip draws it, which looks super-smooth. As it happens, the game is running &lt;b&gt;much&lt;/b&gt; faster than the original BASIC version (hardly surprising, since it's 100% assembler) so I've also had to put a sizable delay loop around Vsync to make it wait for around 50 or so frames to pass, just to slow things down and make it playable!&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;The problem I'm grappling with now is that of collision detection - figuring-out whether a moving thing has hit something else, and doing something appropriate if it did. The difficulty is that the logic is structured so that we check to see if something &lt;i&gt;will&lt;/i&gt; collide before it actually does, as when the Fuelship lands - we want to know that it is &lt;i&gt;about&lt;/i&gt; to hit the floor, not that it &lt;i&gt;has&lt;/i&gt; hit (and sunk into) the floor. This is working fine - the ship lands and I get a flag set to tell me so, and I can then both deactivate it (which removes it from the playfield) and increment the current fuel level.&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;However, Meanies have to actually smack into something before they explode, so checking to see if a Meanie &lt;i&gt;will&lt;/i&gt; hit a wall (for example) is no good - I don't want to do the collision processing until it actually impacts. Unfortunately, when the Meanie &lt;i&gt;does&lt;/i&gt; hit a wall, it overwrites the wall character with itself - which means that if I try to alter the check to see if the Meanie did just hit something, all I see at that position &lt;b&gt;is&lt;/b&gt; the Meanie.&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;I may have to stash the character the Meanie just overwrote when it moves, just so I can look to see what was there before the Meanie arrived. Not a huge issue, but since the VIC doesn't support hardware sprites and masks, I'll have to do it myself...&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5108605455275049037-2701033219489201850?l=devicenotpresent.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://devicenotpresent.blogspot.com/feeds/2701033219489201850/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://devicenotpresent.blogspot.com/2010/09/collision-complication.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5108605455275049037/posts/default/2701033219489201850'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5108605455275049037/posts/default/2701033219489201850'/><link rel='alternate' type='text/html' href='http://devicenotpresent.blogspot.com/2010/09/collision-complication.html' title='Collision Complication'/><author><name>Jonners</name><uri>http://www.blogger.com/profile/10783097207231622242</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='29' src='http://3.bp.blogspot.com/_k7S257jPIsM/S4BCVi6S3sI/AAAAAAAAAqc/4_pLkqr1Wxc/s1600-R/CommodorePET4032.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5108605455275049037.post-6644145806172649559</id><published>2010-09-03T16:52:00.000+01:00</published><updated>2010-09-03T16:52:27.883+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Character'/><category scheme='http://www.blogger.com/atom/ns#' term='Plotting'/><category scheme='http://www.blogger.com/atom/ns#' term='Sourcecode'/><category scheme='http://www.blogger.com/atom/ns#' term='Random'/><title type='text'>Slow But Sure...</title><content type='html'>&lt;div style="text-align: justify;"&gt;The beginning of a new school term and a heavy cold both kept me away from the code for a few days - but I have managed to scrape a few updates together in the odd spare minute or two, so progress continues albeit at a slow pace.&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;I now have a nice wrapper-routine around the Random Number Generator, through which I can pass a range limit value and have a sensible value passed back. So, for example, I can pass '2' in and get a random number back in the range of 1 to 2 (a 50/50 chance); equally, I can pass '5' in, and get values in the range 1 to 5 back (which is a 20% chance). The wrapper code uses pre-calculated tables to split the 0-255 RNG values into 'n' bands, and currently there are just two sets of data to split values into 2 or 5 bands. However, the code has a small amount of robustness built-in - if I pass in a range limit which has no table data defined, it always returns 255 rather than just chewing through memory until hitting a BRK.&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;I've also written some object-initialiser code which handles the instantiation of Meanies (and anything else) when a new one is needed - this code was previously inlined in the main loop, and was both unwieldy and non-generalised, so it's much nicer now. Also, the decision logic for moving objects around has been separated-out and much-improved, and is now a lot slicker than before. I need to add a little bit of code to re-calculate Base Offset Bit settings when objects move across the mid-screen page boundary, but aside from that it's largely complete.&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;Next on the list is to generalise the code that is specific to Meanie movement, because at the moment it's duplicated for each of the two Meanie objects; it should be lifted-out and turned into a general-purpose routine, because it's exactly the same except for the bits that reference each Meanie object. That way, the code exists in just one place, and I can then have each Meanie 'mover' decision-maker call it with a pointer to the Meanie in question. At the same time as I rework this routine, I'll also add the last missing piece of the jigsaw, which is to update the 'delete' table with the objects' old position so that the main update routine can draw the objects in their new positions and zap them from the old.&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;There's about three or four hours' work there, including debugging time, which in theory means I can get these tasks done over the weekend, and be ready next week to crack on with the next crucial bit of code which checks for collisions and out-of-bounds positions (like where a Meanie falls off the bottom of the screen). I'm still hoping to finish the game by the end of September, but I'm not too worried if it runs into next month, as is now looking likely. It'll be great when it's done and I can publish the whole thing though - really looking-forward to getting feedback on it!&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5108605455275049037-6644145806172649559?l=devicenotpresent.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://devicenotpresent.blogspot.com/feeds/6644145806172649559/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://devicenotpresent.blogspot.com/2010/09/slow-but-sure.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5108605455275049037/posts/default/6644145806172649559'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5108605455275049037/posts/default/6644145806172649559'/><link rel='alternate' type='text/html' href='http://devicenotpresent.blogspot.com/2010/09/slow-but-sure.html' title='Slow But Sure...'/><author><name>Jonners</name><uri>http://www.blogger.com/profile/10783097207231622242</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='29' src='http://3.bp.blogspot.com/_k7S257jPIsM/S4BCVi6S3sI/AAAAAAAAAqc/4_pLkqr1Wxc/s1600-R/CommodorePET4032.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5108605455275049037.post-7645924786388371967</id><published>2010-08-23T14:00:00.000+01:00</published><updated>2010-08-23T14:00:45.464+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Character'/><category scheme='http://www.blogger.com/atom/ns#' term='Plotting'/><category scheme='http://www.blogger.com/atom/ns#' term='Random'/><title type='text'>Movement!</title><content type='html'>&lt;div style="text-align: justify;"&gt;The routines for updating mobile characters are in place and working, so I now have a Meanie moving around on the screen. I also have the stubs ready to hook-up movement rules for the Repair Bot and the Fuel Ship, though the 'bot movement will have to wait until I have the logic written to process user keypresses, since it only moves in response to those. I didn't quite get around to doing collision-detection yet, so I'll hold-off on posting a demo until that's in place - which is next on the list, but first I have to revisit the Random Number Generator.&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;The RNG itself is working fine, but I want to write a little 'wrapper' around it to make it easier to use. The game actually only calls it in two places, both for Meanie movement - once to determine whether the Meanie moves horizontally at all (one or two positions to the left, or right, or not at all) and then again to find out if it moves down a line. In other words, there's a call asking for a 1-in-5 response (left two, left one, no movement, right one, right two) and another asking for a 1-in-2 response (move down, don't move down). So that equates to a 20% chance for horizontal movement of some kind - including no movement - and 50% for a vertical drop.&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;The RNG returns 256 possible values in the range 0-255, so the code currently does a simple series of tests to see where the return value is in that range. For the 50% test, that's just a case of checking the value to see if it's greater than 127 - if it is, the Meanie drops a line; if not, it stays on the same line. The code gets a bit nastier when checking the 20% response though, as it has to test a series of four values (51, 102, 153, 204) to see which fifth of the range the value is in, and determine horizontal movement based on that. What I want is a neater way of calling the RNG so that I can pass a value in (e.g. 5 or 2) and have a simple value returned in the range of 1 to 'n', where 'n' is the number I gave it. A 50/50 test would then call the RNG with a value of 2, and get either 1 or 2 back; passing a value of 5 would return a value in the range 1 to 5.&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;This means the wrapper has to automatically calculate where in the 0-255 range the actual RNG result occurs based on the number of 'slices' the range has been asked to divide by. This is a matter of dividing 256 by the passed-in value, finding out how many 'slices' that equates to, and then figuring-out which 'slice' the RNG result falls into and returning that as the output value. For the 50/50 test where a value of 2 would be passed in, it would divide 256 by 2 (giving 128) and then ask the RNG for a result - which would then map into either the 0-127 band, giving 1 as an output, or the 128-255 band, giving 2. It's a bit more complicated for the 20%-chance test, but the same basic principle.&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;I've decided that since this game is making limited use of the RNG, there's not much point writing a sophisticated routine to handle any given range value - we're only using 2 and 5, after all. So instead I'll pre-calculate the boundary values in a table and have the wrapper just look them up to decide where the RNG result falls, and return the appropriate value. It's not a fully-generalised solution, but there seems little advantage to writing an all-singing-and-dancing version when I only actually need two cases handled. If and when I re-use the code and need a more flexible solution, I can drop the auto-calculation logic into it and chop-out the table lookup. For now, it does what I need and is fairly efficient, so it'll suffice.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5108605455275049037-7645924786388371967?l=devicenotpresent.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://devicenotpresent.blogspot.com/feeds/7645924786388371967/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://devicenotpresent.blogspot.com/2010/08/movement.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5108605455275049037/posts/default/7645924786388371967'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5108605455275049037/posts/default/7645924786388371967'/><link rel='alternate' type='text/html' href='http://devicenotpresent.blogspot.com/2010/08/movement.html' title='Movement!'/><author><name>Jonners</name><uri>http://www.blogger.com/profile/10783097207231622242</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='29' src='http://3.bp.blogspot.com/_k7S257jPIsM/S4BCVi6S3sI/AAAAAAAAAqc/4_pLkqr1Wxc/s1600-R/CommodorePET4032.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5108605455275049037.post-6550012397675076346</id><published>2010-08-19T11:49:00.000+01:00</published><updated>2010-08-19T11:49:46.302+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Character'/><category scheme='http://www.blogger.com/atom/ns#' term='Plotting'/><category scheme='http://www.blogger.com/atom/ns#' term='Blue Meanies'/><title type='text'>Deep Thought</title><content type='html'>&lt;div style="text-align: justify;"&gt;I've decided to leave CHARPLOT alone after having a good think about whether to tweak it so that the structures use absolute addresses instead of the base+offset model it currently supports. Weighing-up the pros and cons, I couldn't see any absolute advantage in making the change, and in fact there were one or two things that I had a feeling might be less useful - for example, CHARPLOT figures-out where the screen is when it plots a character rather than having to do that work every time a structure is initialised. This makes the whole thing very adaptable to varying configurations of the system, as well as opening the door to double-buffering if I ever need it (by changing the SCREEN base address before calling a bunch of CHARPLOT updates). As a consequence I've decided to write a general-purpose structure update routine that manages the adjustments needed whenever a mobile object changes position.&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;The other problem, where CHARPLOT structures have no concept of a 'last' position, isn't actually that big a deal; I was playing with the idea of creating clone structures so that I could calculate the new position (of a Meanie, for example) but still have the old structure lurking around so that the screen-update routine could erase the character at the old position before drawing the new. In fact, I only really need to hold the Control Byte and Offset Byte of a character to be erased, and just drop those two bytes into a table which I can run through to zap whatever was at that position. So I can write a routine to step through the CHARPLOT objects, pick the first two bytes out of each and stash them somewhere, recompute the location of the object and update the structure, and then have a small loop zip through the 'old' positions table to clear those locations on screen.&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;I'll write these two routines this evening, and test them out with the one Meanie I currently have instantiated. Once they're working, I'll write some collision-tester code to detect when a Meanie hits something and goes out of play - and then I'll bring Meanie #2 online and have both wibbling around on the screen blowing stuff up. At that point, I might post a demo, even though it'll be fairly dull, just to prove to myself that progress has been made. ;)&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5108605455275049037-6550012397675076346?l=devicenotpresent.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://devicenotpresent.blogspot.com/feeds/6550012397675076346/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://devicenotpresent.blogspot.com/2010/08/deep-thought.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5108605455275049037/posts/default/6550012397675076346'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5108605455275049037/posts/default/6550012397675076346'/><link rel='alternate' type='text/html' href='http://devicenotpresent.blogspot.com/2010/08/deep-thought.html' title='Deep Thought'/><author><name>Jonners</name><uri>http://www.blogger.com/profile/10783097207231622242</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='29' src='http://3.bp.blogspot.com/_k7S257jPIsM/S4BCVi6S3sI/AAAAAAAAAqc/4_pLkqr1Wxc/s1600-R/CommodorePET4032.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5108605455275049037.post-6273081449531847194</id><published>2010-08-17T12:20:00.000+01:00</published><updated>2010-08-17T12:20:22.877+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Plotting'/><category scheme='http://www.blogger.com/atom/ns#' term='NMI'/><category scheme='http://www.blogger.com/atom/ns#' term='Kernal'/><category scheme='http://www.blogger.com/atom/ns#' term='Vector'/><category scheme='http://www.blogger.com/atom/ns#' term='Random'/><title type='text'>Restore Restart</title><content type='html'>&lt;div style="text-align: justify;"&gt;I implemented a couple of routines over the weekend, the first of which was the Random Number Generator. Unsurprisingly, it bears a striking resemblence to the snippet of code which Muttley posted as a comment a while back. Since it works in almost exactly the same way (aside from using Zero Page instead of ROM as part of the generated value) it's a virtual carbon-copy, even down to the initial seed value - which is as good as any other, and there didn't seem to be any advantage to changing it:&lt;/div&gt;&lt;br /&gt;&lt;div style="text-align: justify;"&gt;&lt;pre style="background-color: #eeeeee; border: 1px dashed rgb(153, 153, 153); color: black; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; font-size: 12px; line-height: 14px; overflow: auto; padding: 5px; width: 100%;"&gt;&lt;code&gt;;-------------------------------------------------------------------------------&lt;br /&gt;; RANDOMGEN&lt;br /&gt;; Generate a random number from 0-255&lt;br /&gt;; Notes:    Returns value in .A, uses no other registers&lt;br /&gt;&lt;br /&gt;randomgen    SUBROUTINE&lt;br /&gt;             lda $0                     ; Get next ZP value&lt;br /&gt;             adc .seed                  ; Add seed value&lt;br /&gt;             adc RASTER                 ; Add current raster count&lt;br /&gt;             sta .seed                  ; Update seed value&lt;br /&gt;             inc randomgen+1            ; Increment ZP address in first instruction&lt;br /&gt;             rts&lt;br /&gt;&lt;br /&gt;             ; Seed value&lt;br /&gt;.seed        DC.B $73                   ; Initial seed value&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;&lt;div style="text-align: justify;"&gt;I plugged it in, and as if by magic it started returning a pseudo-random sequence of values from 0-255. So I now have a way of making 'random' decisions about Meanie movement, and indeed about any situation where chance is a factor.&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;I also decided I wanted a way to abort the game in progress and return to the title screen. Since I also needed a way to disable RunStop/Restore, it seemed like an obvious solution to combine the two - instead of the RS/R key combination generating an NMI which returns to BASIC, how about if it instead restarted the application?&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;The first part of the trick is to trap the NMI (Non-Maskable Interrupt) that RS/S produces. It's hard-wired into the VIC design that this key combination will fire the NMI, and, unlike the IRQ interrupt, there's no way to disable it - it's called non-maskable for a reason! However, those jolly nice chaps at Commodore set things up so that the first thing the Kernal NMI handler does is an indirect jump through a vector at $0318/0319. By default, that vector just points straight back into the Kernal routine, but of course you can make it point anywhere else. So now the initialisation section of the main Meanies program adjusts the NMI vector to point at this:&lt;/div&gt;&lt;br /&gt;&lt;div style="text-align: justify;"&gt;&lt;pre style="background-color: #eeeeee; border: 1px dashed rgb(153, 153, 153); color: black; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; font-size: 12px; line-height: 14px; overflow: auto; padding: 5px; width: 100%;"&gt;&lt;code&gt;           ; NMI handler to handle 'Restore' interrupts&lt;br /&gt;.nmitrap   bit V1PORTAO       ; Read VIA1 Port A Output Register to acknowledge NMI&lt;br /&gt;           inc RESTART        ; Set restart flag&lt;br /&gt;           rti                ; Return from the NMI&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;&lt;div style="text-align: justify;"&gt;All we do here is a read of the VIA#1 Port A Output Register with the BIT instruction, set a flag we check in the main game loop, and return from the interrupt. By reading Port A, we trip the VIA handshake signal and the NMI is thereby 'acknowledged' so that further NMIs can happen. We use BIT because it affects no register values, except for flags in the Status Register - but that's OK, because the NMI logic in the 6502 is very well-behaved and saves both the PC and PSR registers when it gets invoked, and restores them after the RTI instruction. In other words, when we return from this custom NMI handler, the CPU state is exactly as we left it.&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;By incrementing the 'RESTART' flag value, we can have a simple test in the main game loop that looks for non-zero values - as long as the address contains zero, we carry on, but as soon as it gets incremented we exit the loop and go back to the title screen. So I now have a way to abort the game, and a handler for RS/S which prevents the game from being broken-into. Well, makes it harder to break into it, anyway. ;)&lt;/div&gt;&lt;br /&gt;&lt;div style="text-align: justify;"&gt;Sadly, it wasn't all sweetness and light whilst I was doing all this - after I'd got the RNG working, I started coding the routine to make the Meanies move based on the RNG output, and that was when the words of Field Marshall Helmuth Carl Bernard von Moltke came to mind:&lt;/div&gt;&lt;br /&gt;&lt;div style="text-align: center;"&gt;'No battle plan ever survives contact with the enemy' &lt;/div&gt;&lt;br /&gt;&lt;div style="text-align: justify;"&gt;It turns out that CHARPLOT, my stable and reliable screen-plotting workhorse, isn't quite suitable for plotting mobile objects after all. It's fast enough, absolutely, and pretty flexible when it comes to putting things at predefined places, but as I started to write the code to move a Meanie around, I encountered a weakness - it's actually a bit of a drag having to recalculate a characters' position in terms of a base+offset, and then update the CHARPLOT structure each time. Plus, the structures have no concept of a 'last' and 'current' position, which means I have to do some faffing-around with cloned structures in order to be able to calculate a new position without overwriting the old data so that I can erase the object from its' old location and draw it at the new location.&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;So I'm having a rethink about the way CHARPLOT works. The fundamentals are good, but I'm toying with the idea of altering it to use an absolute address as the base, rather than a simple bit which indicates where the base is. If I do that, I can then carry-out simple 16-bit mathematics on the address rather than having to do some inelegant bit-twiddling; I can then also span repeated sequences across the page boundary in the middle of the screen, plus I get an easy way to check for out-of-bounds sequence overruns.&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;I'm still playing with this in my head, really just trying to figure-out if it'll then give me what I want and not trap me in a corner again further down the line. It means the CHARPLOT structure will grow by a byte, but I think the tradeoff in flexibility will make up for the slight increase in space requirements. I might write a test version later and see what it looks like.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5108605455275049037-6273081449531847194?l=devicenotpresent.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://devicenotpresent.blogspot.com/feeds/6273081449531847194/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://devicenotpresent.blogspot.com/2010/08/restore-restart.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5108605455275049037/posts/default/6273081449531847194'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5108605455275049037/posts/default/6273081449531847194'/><link rel='alternate' type='text/html' href='http://devicenotpresent.blogspot.com/2010/08/restore-restart.html' title='Restore Restart'/><author><name>Jonners</name><uri>http://www.blogger.com/profile/10783097207231622242</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='29' src='http://3.bp.blogspot.com/_k7S257jPIsM/S4BCVi6S3sI/AAAAAAAAAqc/4_pLkqr1Wxc/s1600-R/CommodorePET4032.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5108605455275049037.post-302981960352354882</id><published>2010-08-12T11:52:00.000+01:00</published><updated>2010-08-12T11:52:52.164+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Raster'/><category scheme='http://www.blogger.com/atom/ns#' term='ROM'/><category scheme='http://www.blogger.com/atom/ns#' term='Memory'/><category scheme='http://www.blogger.com/atom/ns#' term='Random'/><title type='text'>Random Thoughts</title><content type='html'>&lt;div style="text-align: justify;"&gt;And ... we're back, and picking-up right where we left things with random numbers.&lt;br /&gt;&lt;br /&gt;Getting the Meanies to move randomly requires a little bit of code to generate a random value which will indicate how the little blue guys should change position. Generating random numbers is reasonably straight-forward, provided you choose your generation source carefully - what is needed is a source of values that change frequently, which you can tap as the baseline value to use in deriving what looks like randomness. The problem with computer-generated random numbers is that they're never 'truly' random, because ultimately the environment is deterministic - we &lt;i&gt;want&lt;/i&gt; the computer to behave in a known, repeatable, predictable way, and having random unpredictable stuff happening is highly undesirable. So we have to create the illusion of randomness by using some root value that &lt;i&gt;appears&lt;/i&gt; to be unpredictably different every time we look at it.&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;I'd been thinking about using the VIC Raster Counter register at $9003/$9004 as the baseline value for a RNG (Random Number Generator) and Muttleys' earlier comment on a previous post shows that this is a typical approach. The VIC doesn't support hardware raster interrupts (unlike its' successor the C64) so the raster counter simply keeps track of how many video raster lines have been drawn per frame - it starts at zero and rapidly counts up to however many lines are displayed (which varies depending on whether you're looking at the picture on a PAL or NTSC model) before resetting. Since this counter runs very rapidly, consecutive reads of the register will return different values, and provided you aren't reading it at precise intervals you'll get a different value from the range every time.&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;Of course, the Meanie code is fairly linear, so there is a slight chance that we &lt;i&gt;could&lt;/i&gt; fall into a situation where we are reading the raster counter at regular intervals - which means we &lt;i&gt;might&lt;/i&gt; get the same value every time. Ironically, this is precisely what coders want when they need to synchronise video effects to the raster line, but for the purposes of generating random numbers it's a disaster. So we need to add a further skewing value to what we get out of the raster counter, to ensure that even if we do end-up synchronised to it, we'll still get a variable result - and that's why I'm using a page of ROM data as an additional source (Muttley uses another memory area on the C64) to guarantee variability. By adding sequential values from ROM to the value obtained from the raster counter, we get pseudo-randomness - in the worst case, where we've synchronised to the raster count, we'll still get 256 successive values from the ROM that have the appearance of being random.&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;But that still isn't random 'enough', because we'd still only have a domain of a maximum of 256 values (which is itself unlikely, since a page of ROM code is probably going to contain a tiny subset of that) and that is quite a small working set - small enough that a keen eye could eventually spot a pattern and might therefore be able to predict with some success what was going to happen next. So we also need a 'seed' value, which changes over time, to act as a further layer of randomness - by incorporating the seed in the algorithm, we add an additional level of complexity to the values the RNG produces, ensuring that the worst-case scenario (synchronisation to the raster counter and a predictable ROM pattern) still generates apparent randomness.&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;The VIC raster counter occupies 9 bits, with $9004 holding the first 8 bits and the 9th bit sitting in bit 7 of $9003 - this makes sense, because a PAL or NTSC screen is made up of either 312 or 261 raster lines respectively, both of which require 9 bits to represent in binary. The VIC registers, like every other memory location, are bytes - so they contain 8 bits, and that means the 9th bit has to go somewhere else. In this case, it tucks into the end of the register at $9003, and is therefore clear when the counter is less than 256, and set when greater-than or equal to 256.&lt;br /&gt;&lt;br /&gt;We can ignore that 9th bit though, and just read the contents of $9004 - it'll give us values from 0-255, and it doesn't matter that it wraps back to zero before the end of the frame when bit 7 of $9003 is set for raster lines 256-312&amp;nbsp; (or 261 for NTSC). So I'm going to create a little subroutine that will pick-up the current value of $9004, add it to a sequentially-incremented ROM location (actually, thinking about it, I might use Zero Page - it's a faster operation, and just as 'random') and finally add a seed value. I'll post the code once it's in place, in a day or two.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5108605455275049037-302981960352354882?l=devicenotpresent.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://devicenotpresent.blogspot.com/feeds/302981960352354882/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://devicenotpresent.blogspot.com/2010/08/random-thoughts.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5108605455275049037/posts/default/302981960352354882'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5108605455275049037/posts/default/302981960352354882'/><link rel='alternate' type='text/html' href='http://devicenotpresent.blogspot.com/2010/08/random-thoughts.html' title='Random Thoughts'/><author><name>Jonners</name><uri>http://www.blogger.com/profile/10783097207231622242</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='29' src='http://3.bp.blogspot.com/_k7S257jPIsM/S4BCVi6S3sI/AAAAAAAAAqc/4_pLkqr1Wxc/s1600-R/CommodorePET4032.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5108605455275049037.post-3862484986519676099</id><published>2010-07-22T11:03:00.000+01:00</published><updated>2010-07-22T11:03:25.360+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Blue Meanies'/><title type='text'>Intermission</title><content type='html'>&lt;div style="text-align: justify;"&gt;I'm taking the Dev box off the grid for a week or two, as it's due for a disk upgrade and I'm using the opportunity to do a full rebuild of the OS. Win7 has been totally rock-solid since I installed it, but I want to adjust some of the partition sizes and do a few other bits of housekeeping that are easier when you're playing with a fresh build.&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;So whilst that's going-on, Meanies development will be on a short hiatus. I'm expecting to have everything up and running again early in August, at which point we'll resume normal service here. See you soon!&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5108605455275049037-3862484986519676099?l=devicenotpresent.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://devicenotpresent.blogspot.com/feeds/3862484986519676099/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://devicenotpresent.blogspot.com/2010/07/intermission.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5108605455275049037/posts/default/3862484986519676099'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5108605455275049037/posts/default/3862484986519676099'/><link rel='alternate' type='text/html' href='http://devicenotpresent.blogspot.com/2010/07/intermission.html' title='Intermission'/><author><name>Jonners</name><uri>http://www.blogger.com/profile/10783097207231622242</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='29' src='http://3.bp.blogspot.com/_k7S257jPIsM/S4BCVi6S3sI/AAAAAAAAAqc/4_pLkqr1Wxc/s1600-R/CommodorePET4032.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5108605455275049037.post-8152128520756424844</id><published>2010-07-19T20:12:00.000+01:00</published><updated>2010-07-19T20:12:38.126+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Character'/><category scheme='http://www.blogger.com/atom/ns#' term='Plotting'/><category scheme='http://www.blogger.com/atom/ns#' term='Blue Meanies'/><title type='text'>The Opposite of Artificial Intelligence</title><content type='html'>&lt;div style="text-align: justify;"&gt;...is, of course, natural stupidity.&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;It wasn't DASM doing odd things to the 'included' data. It was my code. I admit it - mea culpa. In my defence, it was late and I was tired and the cats were bugging me to let them out and there was something good on TV and my back was hurting. Oh, and I forgot to update a label in the CHARPLOT structures file for the new BSOD entries, which meant CHARCONV was reading junk and splatting data all over the memory map. Sigh.&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;So, on we go. We now have the playfield drawn, with the walls, floor, reactor core and laser turrets in place. I have a new routine called DRAWMOBS which is responsible for plotting all the 'mobile' characters during gameplay, which includes two Meanies, the Repair Bot, the Fuel Ship, laser beams, explosions, and in-game messages. And the first Meanie and the Repair Bot have made their appearance:&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://picasaweb.google.com/lh/photo/PX-XU2bSMLMlpRikeEz0kqcpcHmo15LK-1lQng1qVXk?feat=embedwebsite"&gt;&lt;img src="http://lh4.ggpht.com/_k7S257jPIsM/TESiRqXtMYI/AAAAAAAAAvo/WMO791jRHLY/s400/MeanieBot.png" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;The next item on the agenda is getting the Meanie to move - and this is going to be &lt;i&gt;very&lt;/i&gt; interesting, because it requires the use of random numbers to dictate what position it moves to. That's something I've never done in Assembly language before, so it'll be fun to find out how the mechanics of generating a random number series will work. :)&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5108605455275049037-8152128520756424844?l=devicenotpresent.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://devicenotpresent.blogspot.com/feeds/8152128520756424844/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://devicenotpresent.blogspot.com/2010/07/opposite-of-artificial-intelligence.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5108605455275049037/posts/default/8152128520756424844'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5108605455275049037/posts/default/8152128520756424844'/><link rel='alternate' type='text/html' href='http://devicenotpresent.blogspot.com/2010/07/opposite-of-artificial-intelligence.html' title='The Opposite of Artificial Intelligence'/><author><name>Jonners</name><uri>http://www.blogger.com/profile/10783097207231622242</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='29' src='http://3.bp.blogspot.com/_k7S257jPIsM/S4BCVi6S3sI/AAAAAAAAAqc/4_pLkqr1Wxc/s1600-R/CommodorePET4032.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh4.ggpht.com/_k7S257jPIsM/TESiRqXtMYI/AAAAAAAAAvo/WMO791jRHLY/s72-c/MeanieBot.png' height='72' width='72'/><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5108605455275049037.post-1655853946789785291</id><published>2010-07-18T23:00:00.000+01:00</published><updated>2010-07-18T23:00:13.079+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Character'/><category scheme='http://www.blogger.com/atom/ns#' term='BASIC'/><category scheme='http://www.blogger.com/atom/ns#' term='Memory'/><category scheme='http://www.blogger.com/atom/ns#' term='Assembly'/><title type='text'>User Defined Gibberish</title><content type='html'>&lt;div style="text-align: justify;"&gt;I've adjusted BSOD so that it uses CHARPLOT instead of STROUT, which took about an hour to do, and it's working fine again - so I'm finally free of that particular ROM routine and its' little temper tantrum caused by my Zero Page usage. Which meant I could return to the code to draw the main gameplay screen, which is pretty straight-forward. It's at this point that things start to get interesting, because the game now switches to a UDG (User Defined Graphics) characterset.&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;I yanked the chunk of binary data for the UDGs from the original game (which are stashed above the BASIC code at $1C00) and simply 'include' that as a block of data at the same place in the Assembler code - my current high-water-mark is at around $1400 or so, which means I have lots of room before I might start to encroach on that memory area. Since the original game doesn't climb that high, I have no significant worries that the 6502 code will get anywhere near it either. Which makes the problem I'm tackling all the more puzzling.&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;The character data looks fine in CharPad, a nifty little Windows utility written for designing maps, sprites and UDGs for the C64, and which handles VIC-20 UDGs just as neatly. But oddly, the first six characters - @, A, B, C, D and E - have some minor corruption when I display them in the game. Everything after that is exactly as CharPad shows them, but those first six (48 bytes) are slightly, but not entirely, damaged.&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;My suspicion is that something somewhere is splatting some random values over those memory locations - but the game is barely doing anything yet, and there just doesn't appear to be anything going remotely near that block of data. So I'm going to write a little test program to just pull the characterset in and display it without any other code to possibly injure it, and see what it looks like. If I'm right, and there's something in the Meanies code that's misbehaving, those six characters will look OK.&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;Of course, if that's the case, I'll have to do some careful tracing to see what is going wrong in the game, as I really am pretty confident that there just isn't anything that I'm doing that could cause the problem. If it &lt;i&gt;is&lt;/i&gt; the game code, it must be something to do with the way the BASIC stub line is being constructed that is causing some bizarre side-effect. On the other hand, if the characters are still corrupted even in my test code, that means that DASM is doing something odd when it includes the data at assembly time - and that could be a really nasty one to resolve.&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;I'm hoping to run the test code in the next day or so to see what light it sheds on the problem. It's a tricky one...&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5108605455275049037-1655853946789785291?l=devicenotpresent.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://devicenotpresent.blogspot.com/feeds/1655853946789785291/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://devicenotpresent.blogspot.com/2010/07/user-defined-gibberish.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5108605455275049037/posts/default/1655853946789785291'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5108605455275049037/posts/default/1655853946789785291'/><link rel='alternate' type='text/html' href='http://devicenotpresent.blogspot.com/2010/07/user-defined-gibberish.html' title='User Defined Gibberish'/><author><name>Jonners</name><uri>http://www.blogger.com/profile/10783097207231622242</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='29' src='http://3.bp.blogspot.com/_k7S257jPIsM/S4BCVi6S3sI/AAAAAAAAAqc/4_pLkqr1Wxc/s1600-R/CommodorePET4032.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5108605455275049037.post-3207835982737884165</id><published>2010-07-15T14:26:00.000+01:00</published><updated>2010-07-15T14:26:45.670+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Zero Page'/><category scheme='http://www.blogger.com/atom/ns#' term='BSOD'/><category scheme='http://www.blogger.com/atom/ns#' term='BRK'/><title type='text'>BSOD 2 - The Tweakening</title><content type='html'>&lt;div style="text-align: justify;"&gt;I was debugging a little bit of code last night, and dropped a BRK instruction into the code to trigger the BSOD routine so I could see whether the registers contained what I thought they should. At which point STROUT bit me in the behind again.&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;You might remember that I used this ROM routine to generate the BSOD display, and subsequently wrote CHARPLOT because it wasn't fast enough to draw the games' playfield screen - that exercise has been wholly successful, resulting in a nice chunk of code that's fast and flexible enough to let me draw the playfield instantly, as well as act as the 'engine' for moving things around during gameplay. I didn't bother going back to convert BSOD to use CHARPLOT because it just writes lines of text to the screen when the CPU hits a BRK instruction - at that point, speed is irrelevant because we're in a failure scenario and just displaying the wreckage.&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;However, my Zero Page usage has gone up recently to more than double the previous high-water-mark - I'm now using almost 30 bytes, and there will definitely be more added before I'm done. The thing about Zero Page is, it's used extensively by the BASIC and KERNAL ROMs - which is not a problem when you're in pure Assembly mode and not using any ROM routines which have ZP dependencies, but can be a headache if you happen to call a routine which, in turn, needs some ZP location you've overwritten with game data. Like, for example, STROUT - which evidently relies on something in those first 30 bytes of ZP that I have appropriated for the game. Consequently, when BSOD gets invoked and starts making calls to STROUT, all manner of nasty things now happen and the CPU gets shunted off into the weeds somewhere - VICE pops up an alert telling me everything has gone pear-shaped, and the BSOD never appears.&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt; I could trace through STROUT and figure-out what it's getting upset over, and then leave whatever byte(s) of Zero Page it needs alone - but actually, I don't really want to, because that would leave me with 'holes' in my ZP map which are only there because STROUT sulks otherwise. And of course STROUT is only being called by BSOD, which in the 'release' version of the code won't even be there (I use a conditional assembly directive to include BSOD in the 'debug' version of the code, and leave it out of the 'release' version). So I'm now back in the innards of the code converting it to use CHARPLOT instead.&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;Some days it feels like 2 steps forward, 1.97 back...&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5108605455275049037-3207835982737884165?l=devicenotpresent.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://devicenotpresent.blogspot.com/feeds/3207835982737884165/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://devicenotpresent.blogspot.com/2010/07/bsod-2-tweakening.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5108605455275049037/posts/default/3207835982737884165'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5108605455275049037/posts/default/3207835982737884165'/><link rel='alternate' type='text/html' href='http://devicenotpresent.blogspot.com/2010/07/bsod-2-tweakening.html' title='BSOD 2 - The Tweakening'/><author><name>Jonners</name><uri>http://www.blogger.com/profile/10783097207231622242</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='29' src='http://3.bp.blogspot.com/_k7S257jPIsM/S4BCVi6S3sI/AAAAAAAAAqc/4_pLkqr1Wxc/s1600-R/CommodorePET4032.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5108605455275049037.post-3979669576712011531</id><published>2010-07-14T19:12:00.000+01:00</published><updated>2010-07-14T19:12:10.161+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ROM'/><category scheme='http://www.blogger.com/atom/ns#' term='IRQ'/><category scheme='http://www.blogger.com/atom/ns#' term='Kernal'/><title type='text'>Interrupted Interrupts</title><content type='html'>&lt;div style="text-align: justify;"&gt;Having got the character translation routine finished, I have now written a short routine that executes when the game starts and which processes all the embedded strings, converting them to Screen Codes in-place. It bears more than a passing resemblance to CHARPLOT itself, since it processes the actual structures that are defined and given to the drawing routine - so it has to be able to interpret the Command Byte to isolate the Repeat/Length bit and figure-out where the characters start and how many there are to convert. Instead of drawing the characters, it just calls the translation routine and saves the result back to the structure - so it's a very simple cut-down variant of CHARPLOT itself, with the drawing and colour logic chopped out.&lt;/div&gt;&lt;br /&gt;&lt;div style="text-align: justify;"&gt;Having returned from these little diversions, I can now continue with the main task of converting logic from the&amp;nbsp; games' BASIC sourcecode into Assembly. But before progressing to the next stage of the process, I just needed a quick dive into the Kernal to see where the IRQ routine goes to read the keyboard - the title screen and main game itself both need to be aware of keypresses, but the program runs with interrupts disabled (for maximum speed) and therefore the keyboard-handler routine isn't automatically called. The IRQ routine at $EABF calls a few different routines needed to keep the machine ticking-over, and one of them is SCNKEY at $EB1E - this processes signals from VIA1 which is continually scanning the keyboard, and converts the results into characters in the keyboard buffer.&amp;nbsp;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;The IRQ handler calls SCNKEY (and all the other housekeeping routines) 60 times a second, but I don't need all those other bits of code running - so Meanies executes an SEI as its' very first instruction to disable the IRQ flag in the CPU and stop interrupts occurring. Consequently, it becomes the games' responsibility to call SCNKEY at appropriate times and intervals to have keypresses processed and made available. So, for example, the title screen waits for a keypress using the following simple loop:&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;pre style="background-color: #eeeeee; border: 1px dashed rgb(153, 153, 153); color: black; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; font-size: 12px; line-height: 14px; overflow: auto; padding: 5px; width: 100%;"&gt;&lt;code&gt;         ; Wait for keypress to start game&lt;br /&gt;.keywait jsr SCNKEY       ; Scan keyboard&lt;br /&gt;         lda KEYCOUNT     ; Get count of keypresses&lt;br /&gt;         beq .keywait     ; Loop until any key is pressed&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div style="text-align: justify;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;Of course, this is a spinlock - nothing else (except for NMIs) can happen whilst this loop is executing, so it's not the technique I'll be using in the main gameplay section. But it demonstrates the principle.&lt;br /&gt;&lt;br /&gt;I now also have a short bit of code which initialises a set of gameplay variables like Energy, Score, and so on. This includes a few CHARPLOT structures for things like the Repair Bot and Meanies - you'll recall that I have CHARPLOT running at around 50 frames per second, so it's plenty fast enough to draw all the 'mobile' entities in the game.&lt;br /&gt;&lt;br /&gt;The next thing to do is finalise the drawing of the main playfield elements, and then we'll be into the main loop of the game where Stuff Happens. :)&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5108605455275049037-3979669576712011531?l=devicenotpresent.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://devicenotpresent.blogspot.com/feeds/3979669576712011531/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://devicenotpresent.blogspot.com/2010/07/interrupted-interrupts.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5108605455275049037/posts/default/3979669576712011531'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5108605455275049037/posts/default/3979669576712011531'/><link rel='alternate' type='text/html' href='http://devicenotpresent.blogspot.com/2010/07/interrupted-interrupts.html' title='Interrupted Interrupts'/><author><name>Jonners</name><uri>http://www.blogger.com/profile/10783097207231622242</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='29' src='http://3.bp.blogspot.com/_k7S257jPIsM/S4BCVi6S3sI/AAAAAAAAAqc/4_pLkqr1Wxc/s1600-R/CommodorePET4032.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5108605455275049037.post-251154681857376012</id><published>2010-07-09T18:58:00.001+01:00</published><updated>2010-07-12T15:03:21.988+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Map'/><category scheme='http://www.blogger.com/atom/ns#' term='Character'/><category scheme='http://www.blogger.com/atom/ns#' term='PETSCII'/><category scheme='http://www.blogger.com/atom/ns#' term='Sourcecode'/><title type='text'>It's Not Big or Clever...</title><content type='html'>&lt;div style="text-align: justify;"&gt;I spent an hour last night finalising the mapping rules to convert PETSCII to Screen Codes, and then writing the code to implement them. I guess I've spent a total of three hours on this task, although the first half of that was occupied trying to figure-out how another mapping routine I found actually worked.&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;It was very clever, in that it used only the input value given in the Accumulator, and no other registers or memory. By shifting and masking bits in the PETSCII value it was given, and then selectively testing for specific resultant values, it derived the mapping value and left it in .A upon exit. The problem with it was that it is &lt;i&gt;very&lt;/i&gt; difficult to trace the logic, because at any moment in the execution path you have to be aware of whatever operations have been performed on .A up to that point, what the current value in .A is, and how that relates to the original PETSCII value. Aside from some comments asserting the mapping rules at the top of the code, none of the actual logic had any annotation, so I went through it line-by-line and added my own as I worked out what it was doing.&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;By the time I'd finished, I'd almost lost the will to live. Whilst I'd figured-out what the routine did, it was still pretty cryptic to look at, and worst of all I'd found a discrepancy between what the comments at the top said the results should be and what the code actually did. However, at that point I conceded defeat - I couldn't face working through the logic yet again to confirm the discrepancy, and I wasn't 100% sure I hadn't made a mistake myself and the code was actually right after all. So with a possible glitch in a 43-byte routine I'd spent 90 minutes looking at and still wasn't absolutely certain I understood properly, I decided enough was enough, and abandoned it.&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;I fired-up a copy of Excel and produced two simple columns with the PETSCII characters and Screen Code characters side-by-side. I then converted their decimal values to binary, and analysed the differences where one mapped to the other - which gave me a simple rule in each case for what to do to the PETSCII value to turn it into a Screen Code value. I didn't have to do this for all 256 characters, because they actually map in blocks of 32 (except for value 255) so I ended-up with 9 rules - and there were duplicates, so the actual number of &lt;i&gt;distinct&lt;/i&gt; rules is only 6.&lt;br /&gt;&lt;pre&gt;&lt;code&gt;    PETSCII Value    Mapping Rule              Logical Operation&lt;br /&gt;      0-31&amp;nbsp;&amp;nbsp; &amp;nbsp;        No change&amp;nbsp;&amp;nbsp; &lt;br /&gt;      32-63&amp;nbsp;&amp;nbsp;        &amp;nbsp;No change&amp;nbsp;&amp;nbsp; &lt;br /&gt;      64-95&amp;nbsp;&amp;nbsp; &amp;nbsp;       Clear bit 6&amp;nbsp;&amp;nbsp; &amp;nbsp;           and #%10111111&lt;br /&gt;      96-127&amp;nbsp;&amp;nbsp; &amp;nbsp;      Clear bit 5&amp;nbsp;&amp;nbsp; &amp;nbsp;           and #%11011111&lt;br /&gt;      128-159&amp;nbsp;&amp;nbsp;       No change&amp;nbsp;&amp;nbsp; &lt;br /&gt;      160-191&amp;nbsp;&amp;nbsp;       Set bit 7, clear bit 6&amp;nbsp;&amp;nbsp; &amp;nbsp;ora #%10000000, and #%10111111&lt;br /&gt;      192-223&amp;nbsp;&amp;nbsp;       Clear bit 7&amp;nbsp;&amp;nbsp; &amp;nbsp;           and #%01111111&lt;br /&gt;      224-254&amp;nbsp;&amp;nbsp;       Clear bit 7&amp;nbsp;&amp;nbsp; &amp;nbsp;           and #%01111111&lt;br /&gt;      255&amp;nbsp;&amp;nbsp; &amp;nbsp;         Output 94&amp;nbsp;&amp;nbsp; &amp;nbsp;             lda #94&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;I then wrote the code in it's simplest form, just testing for specific values and mapping appropriately - which gave me a routine 57 bytes long. I then spent a few minutes combining the duplicate rules, which reduced the byte count to 49. And finally I optimised it so that it re-used rule fragments where possible, and the code dropped to 40 bytes. More importantly, that's 40 bytes of readily-understandable logic, with comments. It only manipulates .A, uses no other registers or memory, and is a simple drop-through routine which only actually changes the value in .A when it performs the mapping, rather than twiddling bits as it progresses.&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;pre style="background-color: #eeeeee; border: 1px dashed rgb(153, 153, 153); color: black; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; font-size: 12px; line-height: 14px; overflow: auto; padding: 5px; width: 100%;"&gt;&lt;code&gt;;-------------------------------------------------------------------------------&lt;br /&gt;; CHAR2SCREEN&lt;br /&gt;; Converts PETSCII values to the appropriate Screen Code.&lt;br /&gt;; Notes: Load .A with PETSCII value - converted value is returned in .A&lt;br /&gt;;     Uses no other registers or memory&lt;br /&gt;;&lt;br /&gt;;&lt;br /&gt;; PETSCII Value    Mapping Rule              Logical Operation&lt;br /&gt;;   0-31            No change&lt;br /&gt;;   32-63           No change&lt;br /&gt;;   64-95           Clear bit 6               and #%10111111&lt;br /&gt;;   96-127          Clear bit 5               and #%11011111&lt;br /&gt;;   128-159         No change&lt;br /&gt;;   160-191         Set bit 7, clear bit 6    ora #%10000000, and #%10111111&lt;br /&gt;;   192-223         Clear bit 7               and #%01111111&lt;br /&gt;;   224-254         Clear bit 7               and #%01111111&lt;br /&gt;;   255             Output 94                 lda #94&lt;br /&gt;&lt;br /&gt;char2scrn SUBROUTINE&lt;br /&gt;     cmp #255       ; Input = 255?&lt;br /&gt;     bcc .tst192      ; Less than 255, skip to next test&lt;br /&gt;     lda #94        ; Input = 255, reset to 94&lt;br /&gt;     rts          ; Exit&lt;br /&gt;&lt;br /&gt;.tst192  cmp #192       ; Input &amp;gt;= 192?&lt;br /&gt;     bcc .tst160      ; Less than 192, skip to next test&lt;br /&gt;     and #%01111111    ; Input &amp;gt;= 192, clear bit 7&lt;br /&gt;     rts          ; Exit&lt;br /&gt;&lt;br /&gt;.tst160  cmp #160       ; Input &amp;gt;= 160?&lt;br /&gt;     bcc .tst128      ; Less than 160, skip to next test&lt;br /&gt;     ora #%10000000    ; Input &amp;gt;= 160, so set bit 7&lt;br /&gt;.clear6  and #%10111111    ; Clear bit 6&lt;br /&gt;     rts          ; Exit&lt;br /&gt;&lt;br /&gt;.tst128  cmp #128       ; Input &amp;gt;= 128?&lt;br /&gt;     bcc .tst96      ; Less than 128, skip to next test&lt;br /&gt;     rts          ; Exit (leave unchanged)&lt;br /&gt;&lt;br /&gt;.tst96  cmp #96        ; Input &amp;gt;= 96?&lt;br /&gt;     bcc .tst64      ; Less than 96, skip to next test&lt;br /&gt;     and #%11011111    ; Input &amp;gt;= 96, clear bit 5&lt;br /&gt;     rts          ; Exit&lt;br /&gt;&lt;br /&gt;.tst64  cmp #64        ; Input &amp;gt;= 64?&lt;br /&gt;     bcs .clear6      ; Input &amp;gt;= 64, so clear bit 6&lt;br /&gt;     rts          ; Less than 64, leave unchanged&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;It might not be as 'clever' as the routine I found, but it's understandable, and shorter. Which is nice.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5108605455275049037-251154681857376012?l=devicenotpresent.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://devicenotpresent.blogspot.com/feeds/251154681857376012/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://devicenotpresent.blogspot.com/2010/07/cracking-code.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5108605455275049037/posts/default/251154681857376012'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5108605455275049037/posts/default/251154681857376012'/><link rel='alternate' type='text/html' href='http://devicenotpresent.blogspot.com/2010/07/cracking-code.html' title='It&apos;s Not Big or Clever...'/><author><name>Jonners</name><uri>http://www.blogger.com/profile/10783097207231622242</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='29' src='http://3.bp.blogspot.com/_k7S257jPIsM/S4BCVi6S3sI/AAAAAAAAAqc/4_pLkqr1Wxc/s1600-R/CommodorePET4032.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5108605455275049037.post-2989624229514967450</id><published>2010-07-07T22:15:00.005+01:00</published><updated>2010-07-08T14:34:18.235+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Plotting'/><category scheme='http://www.blogger.com/atom/ns#' term='PETSCII'/><category scheme='http://www.blogger.com/atom/ns#' term='Sourcecode'/><category scheme='http://www.blogger.com/atom/ns#' term='6502'/><title type='text'>Plz sNd mE Teh Codez</title><content type='html'>&lt;div style="text-align: justify;"&gt;I've had a whole bunch of requests (well alright, one) for a peek at the code I've been writing, and writing about. So here's CHARPLOT in all its' glory, although the sharp-eyed amongst you will notice immediately that I'm not using the BIT command I wrote about a couple of posts ago. As it turned out, the motivation for sequencing the bits in the Control Byte so that I could do a fast test on the N and V flags with BIT became somewhat redundant when I stopped needing to test the Effect and RVS bits on every iteration through the drawing loop. So now the bits are arranged in a comfortably convenient way, since there's no speed advantage to be gained in coercing the structure any further.&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;Here's the routine, followed by the working-storage allocations which go in Zero Page; I have them starting at location $03, but you could assemble them anywhere safe:&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;pre style="background-color: #eeeeee; border: 1px dashed rgb(153, 153, 153); color: black; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; font-size: 12px; line-height: 14px; overflow: auto; padding: 5px; width: 100%;"&gt;&lt;code&gt;;-------------------------------------------------------------------------------&lt;br /&gt;; CHARPLOT&lt;br /&gt;; Displays one or more characters on the screen.&lt;br /&gt;; Notes: Load .A and .Y with address of charplot data table&lt;br /&gt;;     Uses all registers and ZP locations $03-0d for working storage&lt;br /&gt;;     Assumes character(s) have been converted from PETSCII to Screen Codes&lt;br /&gt;;&lt;br /&gt;;     Character-based screen plotting&lt;br /&gt;;       * Control Byte&lt;br /&gt;;         * Offset Byte&lt;br /&gt;;         * Repeat/Length Byte&lt;br /&gt;;         * Character Byte(s)&lt;br /&gt;;&lt;br /&gt;;     Control Byte Bits&lt;br /&gt;;         * 7 : Repeat/Length Type (0=Repeat Specified Character, 1=Use String of Specified Length)&lt;br /&gt;;         * 6 : Screen Base Offset (0=0, 1=256)&lt;br /&gt;;         * 5 : Unused&lt;br /&gt;;         * 4 : Unused&lt;br /&gt;;         * 3 : Colour 2  0=Black, 1=White, 2=Red, 3=Cyan, 4=Purple, 5=Green, 6=Blue, 7=Yellow&lt;br /&gt;;         * 2 : Colour 1&lt;br /&gt;;         * 1 : Colour 0&lt;br /&gt;;         * 0 : Reverse Mode (0=RVS OFF, 1=RVS ON)&lt;br /&gt;&lt;br /&gt;charplot SUBROUTINE&lt;br /&gt;     sta CPDATALO     ; Store charplot data start address in ZP (LSB/MSB)&lt;br /&gt;     sty CPDATAHI&lt;br /&gt;&lt;br /&gt;     ; Calculate and store charplot character address in ZP (LSB/MSB)&lt;br /&gt;     sty CPCHARHI     ; Assume character(s)&lt;br /&gt;     clc          ; Clear C flag before we start&lt;br /&gt;     adc #3        ; Add 3 to data LSB for character offset&lt;br /&gt;     sta CPCHARLO     ; Save it to ZP&lt;br /&gt;&lt;br /&gt;     ; Adjust character MSB if carry was set&lt;br /&gt;     bcc .setscrn     ; No carry - skip MSB adjustment&lt;br /&gt;     inc CPCHARHI     ; Increment character MSB&lt;br /&gt;&lt;br /&gt;     ; Set charplot screen and colour base MSB in ZP&lt;br /&gt;.setscrn lda #&amp;gt;SCREEN     ; Get screen base MSB&lt;br /&gt;     sta CPSCRNHI     ; Save in ZP&lt;br /&gt;     lda #&amp;gt;COLOUR     ; Get colour base MSB&lt;br /&gt;     sta CPCOLRHI     ; Save in ZP&lt;br /&gt;&lt;br /&gt;     ; Set RVS mask value&lt;br /&gt;     lda #0        ; Assume RVS is off&lt;br /&gt;     sta CPDATARM     ; Save in ZP&lt;br /&gt;&lt;br /&gt;     ; Get Repeat/Length, Offset and Control bytes&lt;br /&gt;     ldy #2        ; Set ZP indirect offset in .Y to third charplot byte&lt;br /&gt;     lda (CPDATALO),y   ; Get character repeat/length byte&lt;br /&gt;     sta CPDATARL     ; Save it to ZP (repeat/length value)&lt;br /&gt;&lt;br /&gt;     dey          ; Decrement .Y for second charplot byte&lt;br /&gt;     lda (CPDATALO),y   ; Get character offset byte&lt;br /&gt;     sta CPSCRNLO     ; Save it to ZP (charplot screen/colour address LSB)&lt;br /&gt;     sta CPCOLRLO&lt;br /&gt;&lt;br /&gt;     dey          ; Decrement .Y for first charplot byte&lt;br /&gt;     lda (CPDATALO),y   ; Get control byte&lt;br /&gt;     tax          ; Save in .X for later&lt;br /&gt;&lt;br /&gt;     ; Isolate and save RVS mode bit&lt;br /&gt;     ror          ; Rotate RVS bit into C flag&lt;br /&gt;     ror CPDATARM     ; Rotate C flag into RVS mask bit 7&lt;br /&gt;&lt;br /&gt;     ; Isolate and save the colour value&lt;br /&gt;     and #7        ; Mask colour value&lt;br /&gt;     sta CPDATACOL     ; Save it to ZP (colour value)&lt;br /&gt;&lt;br /&gt;     ; Is there a screen base offset?&lt;br /&gt;     txa          ; Get control byte from .X&lt;br /&gt;     and #%01000000    ; Mask offset bit&lt;br /&gt;     beq .plot       ; If bit not set (N flag set) skip base increment&lt;br /&gt;&lt;br /&gt;     ; The offset bit is set&lt;br /&gt;     inc CPSCRNHI     ; Add 1 (i.e. 256) to charplot screen/colour base address MSB&lt;br /&gt;     inc CPCOLRHI&lt;br /&gt;&lt;br /&gt;     ; Check repeat/length bit&lt;br /&gt;.plot   ldy #0        ; Assume we're repeating one character&lt;br /&gt;     txa          ; Get the control byte from .X&lt;br /&gt;     bpl .getchar     ; If N flag isn't set then we're repeating one character&lt;br /&gt;&lt;br /&gt;     ; The length bit is set, so this is a string to display&lt;br /&gt;     ldy CPDATARL     ; Get offset into string&lt;br /&gt;&lt;br /&gt;     ; Draw the character and colour&lt;br /&gt;.getchar lda (CPCHARLO),y   ; Get character byte&lt;br /&gt;     ora CPDATARM     ; Apply RVS mask&lt;br /&gt;     ldy CPDATARL     ; Get repeat/length value&lt;br /&gt;      sta (CPSCRNLO),y   ; Store Character at screen location&lt;br /&gt;     lda CPDATACOL     ; Get colour from ZP&lt;br /&gt;     sta (CPCOLRLO),y   ; Store colour at colour location&lt;br /&gt;&lt;br /&gt;     ; Decrement repeat count / string offset&lt;br /&gt;     dey          ; Decrement repeat/length value&lt;br /&gt;     sty CPDATARL     ; Save it to ZP&lt;br /&gt;     cpy #$ff       ; Did we decrement past zero?&lt;br /&gt;     bne .plot       ; Loop until repeat/length done&lt;br /&gt;&lt;br /&gt;     rts&lt;br /&gt;&lt;br /&gt;     ; CharPlot working storage (ZP)&lt;br /&gt;CPDATALO DS.B 1            ; CharPlot data address pointer (LSB)&lt;br /&gt;CPDATAHI DS.B 1            ; CharPlot data address pointer (MSB)&lt;br /&gt;CPCHARLO DS.B 1            ; CharPlot character address pointer (LSB)&lt;br /&gt;CPCHARHI DS.B 1            ; CharPlot character address pointer (MSB)&lt;br /&gt;CPSCRNLO DS.B 1            ; CharPlot screen base address (LSB)&lt;br /&gt;CPSCRNHI DS.B 1            ; CharPlot screen base address (MSB)&lt;br /&gt;CPCOLRLO DS.B 1            ; CharPlot colour base address (LSB)&lt;br /&gt;CPCOLRHI DS.B 1            ; CharPlot colour base address (MSB)&lt;br /&gt;CPDATARL DS.B 1            ; CharPlot Repeat/Length value&lt;br /&gt;CPDATARM DS.B 1            ; CharPlot Reverse Mode mask value&lt;br /&gt;CPDATACOL DS.B 1            ; CharPlot Colour value&lt;br /&gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;br /&gt;And here's a short demo program which uses CHARPLOT to draw a few simple lines on the screen. It's hardly rocket science, and in terms of graphical 'wow'-factor it's sorely lacking - but it does demonstrate how the 4-byte definition structure works, and shows how to invoke the routine to make it do its' thing:&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;pre style="background-color: #eeeeee; border: 1px dashed rgb(153, 153, 153); color: black; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; font-size: 12px; line-height: 14px; overflow: auto; padding: 5px; width: 100%;"&gt;&lt;code&gt;;-------------------------------------------------------------------------------&lt;br /&gt;; CHARPLOT Demo&lt;br /&gt;&lt;br /&gt;     ; Assemble for 6502 CPU&lt;br /&gt;     PROCESSOR 6502&lt;br /&gt;&lt;br /&gt;     ; Disable interrupts and make sure Decimal mode is off&lt;br /&gt;     sei          ; Disable interrupts&lt;br /&gt;     cld          ; Clear decimal mode&lt;br /&gt;&lt;br /&gt;     ; Start&lt;br /&gt;.restart lda #0        ; Clear keyboard buffer&lt;br /&gt;     sta KEYCOUNT&lt;br /&gt;     jsr CINT1       ; Reset VIC&lt;br /&gt;          jsr CLRSCRN      ; Clear the screen&lt;br /&gt;&lt;br /&gt;          ; Display a block of coloured lines&lt;br /&gt;        ldx .cplen      ; Get line table length&lt;br /&gt;.lineloop stx TMPSTOX      ; Store .X in ZP  ** Note - define this in ZP somewhere **&lt;br /&gt;     lda .cpaddr-1,x    ; Message address LSB&lt;br /&gt;     ldy .cpaddr,x     ; Message address MSB&lt;br /&gt;          jsr charplot     ; Draw to screen&lt;br /&gt;     ldx TMPSTOX      ; Get .X from ZP&lt;br /&gt;     dex          ; Decrement .X for next line address&lt;br /&gt;     dex&lt;br /&gt;     bpl .lineloop     ; Loop until all lines displayed&lt;br /&gt;&lt;br /&gt;     ; Wait for keypress&lt;br /&gt;.keywait lda KEYCOUNT     ; Get count of keypresses&lt;br /&gt;     beq .keywait     ; Loop until any key is pressed&lt;br /&gt;&lt;br /&gt;     cli          ; Re-enable interrupts&lt;br /&gt;     rts          ; Return to BASIC&lt;br /&gt;&lt;br /&gt;     ; CHARPLOT data&lt;br /&gt;.cpline1 DC.B 12    ; Control Byte&lt;br /&gt;     DC.B 70        ; Character Offset&lt;br /&gt;     DC.B 13        ; Repeat Byte&lt;br /&gt;     DC.B 160       ; Character Byte&lt;br /&gt;     &lt;br /&gt;.cpline2 DC.B 12    ; Control Byte&lt;br /&gt;     DC.B 114       ; Character Offset&lt;br /&gt;     DC.B 13        ; Repeat Byte&lt;br /&gt;     DC.B 160       ; Character Byte&lt;br /&gt;     &lt;br /&gt;.cpline3 DC.B 12    ; Control Byte&lt;br /&gt;     DC.B 158       ; Character Offset&lt;br /&gt;     DC.B 13        ; Repeat Byte&lt;br /&gt;     DC.B 160       ; Character Byte&lt;br /&gt;     &lt;br /&gt;.cpline4 DC.B 12    ; Control Byte&lt;br /&gt;     DC.B 202       ; Character Offset&lt;br /&gt;     DC.B 13        ; Repeat Byte&lt;br /&gt;     DC.B 160       ; Character Byte&lt;br /&gt;     &lt;br /&gt;.cpline5 DC.B 141    ; Control Byte&lt;br /&gt;     DC.B 92        ; Character Offset&lt;br /&gt;     DC.B 13        ; Length Byte&lt;br /&gt;     DC.B "0123456789!=-+" ; Character String&lt;br /&gt;&lt;br /&gt;     ; Charplot line addresses&lt;br /&gt;.cpaddr  DC.W .cpline5,.cpline4,.cpline3,.cpline2,.cpline1&lt;br /&gt;.cplen  DC.B (.-1-.cpaddr)&lt;br /&gt;&lt;br /&gt;     ; Subroutines&lt;br /&gt;     INCLUDE "charplot.6502"&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;&lt;div style="text-align: justify;"&gt;Note: there are a few symbols defined here that refer to VIC-20 memory locations or ROM routines - just download my VICMap.6502 file from &lt;a href="http://vicdev.googlecode.com/files/VICMap.6502"&gt;here&lt;/a&gt; and include it at the top of the routine to have them resolved at assembly time. In DASM, natch. :)&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;div style="text-align: justify;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;I'm still working on getting the PETSCII mapping routine done so that I can send readable messages to CHARPLOT for 'printing'. There are a couple of solutions around already, generally doing either a primitive table lookup (which is not wonderful, because it consumes 512 bytes for the mapping table) or some clever but convoluted bit-shuffling to remap without a lookup table. The latter is much neater, but quite hard to follow and not particularly efficient in the way it's structured - so although it's the approach I'm taking myself, I'm not simply dropping a pre-written chunk of code into Meanies; I've got an idea for a slicker technique which will be elegant and structured such that it's readable and readily-understood.&lt;/div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;The hard part is getting the mapping table right in the first place, which is where my attention is focussed right now; simply listing the PETSCII codes and Screen Codes next to each other isn't enough - I'm looking at the binary patterns each mapped chunk follows, and codifying rules that will translate one to the other (and back, if need be). When that's done, I can write a streamlined bit of 6502 that will action the appropriate rule (or rule-chain, to be precise) depending on the input.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5108605455275049037-2989624229514967450?l=devicenotpresent.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://devicenotpresent.blogspot.com/feeds/2989624229514967450/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://devicenotpresent.blogspot.com/2010/07/plz-snd-me-teh-codez.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5108605455275049037/posts/default/2989624229514967450'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5108605455275049037/posts/default/2989624229514967450'/><link rel='alternate' type='text/html' href='http://devicenotpresent.blogspot.com/2010/07/plz-snd-me-teh-codez.html' title='Plz sNd mE Teh Codez'/><author><name>Jonners</name><uri>http://www.blogger.com/profile/10783097207231622242</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='29' src='http://3.bp.blogspot.com/_k7S257jPIsM/S4BCVi6S3sI/AAAAAAAAAqc/4_pLkqr1Wxc/s1600-R/CommodorePET4032.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5108605455275049037.post-682117038735073350</id><published>2010-07-06T17:41:00.000+01:00</published><updated>2010-07-06T17:41:42.293+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Character'/><category scheme='http://www.blogger.com/atom/ns#' term='Plotting'/><category scheme='http://www.blogger.com/atom/ns#' term='PETSCII'/><category scheme='http://www.blogger.com/atom/ns#' term='Screen'/><title type='text'>Pesky PETSCII</title><content type='html'>&lt;div style="text-align: justify;"&gt;At long last, and after no less than five significant revisions since the first working version...&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;b&gt;CHARPLOT is finished.&lt;/b&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;Whew!&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;It's turned-out pretty nicely, I think - it handles plotting of single characters, repeated characters, and character strings to any location on the screen in any of the eight standard character-colours, plus a reverse-mode option. It's fast enough to fill the screen (i.e. change the character and colour at every visible location) 48 times a second with the standard IRQ handler active, and well over 50 times a second with interrupts disabled. It occupies 86 bytes of memory, plus 11 Zero Page bytes for working storage. It'll do. ;)&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;There is, however, a small fly in the ointment - and it's something I remember knowing about back in the '80s when I was writing code on real VICs and PETs, but had forgotten in the intervening years and have now been rudely reminded of. It's simply this - the PETSCII* codes used to display characters on the screen via the ROM 'Print' routines are not the same as the Screen Codes needed to map characters directly to the screen. The character 'A', for example, has a PETSCII code of 65, but a Screen Code of 1. So although CHARPLOT is working, it's being fed PETSCII codes (because that's what STROUT wanted) and so I get garbage plotted on the screen.&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;The thing to do is to write a little mapping routine that converts PETSCII into Screen Codes - a simple matter in theory, but in practice it's complicated by the fact that the mapping isn't contiguous. In fact, it's all over the place&amp;nbsp; - chunks of PETSCII map into different areas of Screen Code values, so this isn't just a case of subtracting 64 from the PETSCII code to convert 'A', for example. I'm currently writing a routine to do this mapping, so that I can still include readable strings in my code, and have them converted automatically into Screen Code values when the program runs - this conversion will happen once, when the program starts, so that CHARPLOT doesn't have to re-map 'on-the-fly' but can just take the pre-converted character(s) and plot them immediately.&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span style="font-size: x-small;"&gt;*PETSCII - the Commodore variant of the 1963 ASCII standard, developed for use in their PET computers and inherited by the VIC, C64, etc. It's different in a number of ways from the 1967 ASCII standard we know and love today. &lt;a href="http://en.wikipedia.org/wiki/PETSCII"&gt;Wikipedia&lt;/a&gt; has a reasonable entry on it.&lt;/span&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5108605455275049037-682117038735073350?l=devicenotpresent.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://devicenotpresent.blogspot.com/feeds/682117038735073350/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://devicenotpresent.blogspot.com/2010/07/pesky-petscii.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5108605455275049037/posts/default/682117038735073350'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5108605455275049037/posts/default/682117038735073350'/><link rel='alternate' type='text/html' href='http://devicenotpresent.blogspot.com/2010/07/pesky-petscii.html' title='Pesky PETSCII'/><author><name>Jonners</name><uri>http://www.blogger.com/profile/10783097207231622242</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='29' src='http://3.bp.blogspot.com/_k7S257jPIsM/S4BCVi6S3sI/AAAAAAAAAqc/4_pLkqr1Wxc/s1600-R/CommodorePET4032.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5108605455275049037.post-1389299773169226803</id><published>2010-06-30T15:49:00.000+01:00</published><updated>2010-06-30T15:49:56.680+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Plotting'/><category scheme='http://www.blogger.com/atom/ns#' term='Screen'/><title type='text'>Trust Your Feelings, Luke</title><content type='html'>&lt;div style="text-align: justify;"&gt;I was tweaking CHARPLOT last night, and got variable-length non-repeated strings working (at a cost of a mere 5 bytes of new code!) and was thinking about the last feature the routine needed, which was to plot characters in reverse-video mode (RVS ON) if requested.&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;Sometimes I can look at a piece of code and get 'that feeling'. It's impossible to describe, but it essentially amounts to a nagging sensation that this is Not The Right Way to do something - that there is, in fact, a much better way to achieve the result, and that even though I might not know what that better way is yet, I already know that what I have isn't it. Well, as I was contemplating adding the logic for RVS ON, I got that feeling.&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;If I had to pick what it was that triggered it, it would have to be the Effect Byte logic in the drawing-phase of the routine, near the end. It just stuck out like a sore thumb - 12 little bytes of code that I know are going to get executed precisely 44 times, once per character over two 22-character lines, on the title screen. That's 12 bytes of code (including a branch around it that will execute every single time the routine is called, except for the first two occasions) sitting there right smack in the middle of the draw logic, doing bugger-all for 99.99% of the time.&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;I knew it had to go - far better to take that Effect code out of the core routine, and just have a bespoke overdraw loop after the first two calls to re-colour the characters. So out it came, and that meant I could turn off the Effect bit in the Control Byte for those first two plotted lines. Ah, hold on - so now, that bit is never ever used, which means we can drop it from the Control Byte. Which means in turn that we can drop the code in CHARPLOT that interprets that bit and then reads the Effect Byte. And &lt;i&gt;that&lt;/i&gt; means we don't need the Effect Byte at all, so I can also re-sequence the bits in the Control Byte for greater efficiency. So I can re-write the logic that LSRs those bits and ... ah nuts, let's just start again from scratch.&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;I've standardised the data definition entries on 4 bytes, instead of a variable number between 3 and 5. That makes the CHARPLOT byte-reader code dead simple. I've re-sequenced the bits in the Control Byte (again!) so that I can use the BIT instruction to test bits 7 and 6 very quickly (since BIT loads the N and V flags with these two bits automatically) and then just mask them off to leave the plot colour value, which is stored discretely in ZP - once isolated - for speed during the draw logic. I've trimmed ZP usage overall as well, since there were several intermediate values being stored there that I don't need any more - and in trimming what was used, I've also trimmed (as in, hacked-out) a bunch of STAs in the code that were initialising ZP.&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;It might appear that I'm spending an inordinate amount of time perfecting this routine, when the whole of the rest of the game lies unwritten before me - but there is a method to my madness. When I described this routine back when I first started writing it, I mused that it might be useful as a more general-purpose plotting service later in the games' development process, and it has now evolved into a shape that is both small and fast enough to be utilised as the core of the main gameplay drawing code. By constructing all the on-screen objects as CHARPLOT definitions and then dynamically manipulating them, I'll be able to call this subroutine for all the on-screen activity, not just the static playfield elements.&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;I'm expecting to finish it, finally, this evening - at which point I'm hoping to be able to look at the result and know that I am at last doing it The Right Way.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5108605455275049037-1389299773169226803?l=devicenotpresent.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://devicenotpresent.blogspot.com/feeds/1389299773169226803/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://devicenotpresent.blogspot.com/2010/06/trust-your-feelings-luke.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5108605455275049037/posts/default/1389299773169226803'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5108605455275049037/posts/default/1389299773169226803'/><link rel='alternate' type='text/html' href='http://devicenotpresent.blogspot.com/2010/06/trust-your-feelings-luke.html' title='Trust Your Feelings, Luke'/><author><name>Jonners</name><uri>http://www.blogger.com/profile/10783097207231622242</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='29' src='http://3.bp.blogspot.com/_k7S257jPIsM/S4BCVi6S3sI/AAAAAAAAAqc/4_pLkqr1Wxc/s1600-R/CommodorePET4032.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5108605455275049037.post-5948415387424434821</id><published>2010-06-28T15:08:00.000+01:00</published><updated>2010-06-28T15:08:01.837+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Plotting'/><category scheme='http://www.blogger.com/atom/ns#' term='Zero Page'/><title type='text'>Still Plotting</title><content type='html'>&lt;div style="text-align: justify;"&gt;Over the weekend I only had about four hours in total to work on CHARPLOT, but in that time it went through two significant revisions, mostly in the 'middle third' of the code. The first section mostly deals with setting-up whatever screen offset the entry is intended to be drawn at, the last section does the actual drawing, and the middle chunk is where various Control bits are processed to figure-out whether there are any Repeat or Effect bytes to be read, and if so what their function is.&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;The first revision was intended to optimise the code by making better use of the CPU registers, rather than repeatedly reading memory. It did the job, but was not particularly readable - there was a fair amount of logic which was only there to determine what was in a given register at any time, and to make use of register data in preference to a memory access. In practical terms, it wasn't great - and once I'd completed it and proved it was working, I decided I didn't like it; the code had swollen to 120 bytes, and in places the amount of work it was doing to identify register contents was taking much longer than just re-reading the memory location where the data was stored!&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;So I re-wrote that middle part again, but making more use of Zero Page memory to hold values whilst decoding the Control bits. This has worked very well, especially since I re-ordered the bits in the Control Byte to make the decoding process a matter of simply LSR-ing them sequentially into the Carry flag and branching on that. This had two significant consequences - first, the 'drawing' part of the code became simpler because it had to do less work (just reading ZP memory instead of querying the Control Byte over and over again), and second, the whole routine reduced in size to 105 bytes.&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;I've got a little more work to do on it so that it'll handle variable-content strings and reverse-mode characters, but these are tweaks to the last part of the code where drawing occurs - the knotty decoding has already been done, so now I just need a few instructions to read and act upon the resultant commands.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5108605455275049037-5948415387424434821?l=devicenotpresent.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://devicenotpresent.blogspot.com/feeds/5948415387424434821/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://devicenotpresent.blogspot.com/2010/06/still-plotting.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5108605455275049037/posts/default/5948415387424434821'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5108605455275049037/posts/default/5948415387424434821'/><link rel='alternate' type='text/html' href='http://devicenotpresent.blogspot.com/2010/06/still-plotting.html' title='Still Plotting'/><author><name>Jonners</name><uri>http://www.blogger.com/profile/10783097207231622242</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='29' src='http://3.bp.blogspot.com/_k7S257jPIsM/S4BCVi6S3sI/AAAAAAAAAqc/4_pLkqr1Wxc/s1600-R/CommodorePET4032.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5108605455275049037.post-6316622158602331894</id><published>2010-06-24T10:37:00.000+01:00</published><updated>2010-06-24T10:37:35.633+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Plotting'/><category scheme='http://www.blogger.com/atom/ns#' term='Zero Page'/><category scheme='http://www.blogger.com/atom/ns#' term='BASIC'/><category scheme='http://www.blogger.com/atom/ns#' term='ROM'/><category scheme='http://www.blogger.com/atom/ns#' term='Assembly'/><category scheme='http://www.blogger.com/atom/ns#' term='BSOD'/><category scheme='http://www.blogger.com/atom/ns#' term='6502'/><title type='text'>Bughunting</title><content type='html'>&lt;div style="text-align: justify;"&gt;I re-wrote CHARPLOT last night, as I could see a number of ways to optimise and improve the logic - I tend to follow the doctrine of this quote...&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;/div&gt;&lt;dl style="font-family: Georgia,&amp;quot;Times New Roman&amp;quot;,serif; text-align: justify;"&gt;&lt;dt&gt;&lt;span style="font-size: small;"&gt;"Perfection is achieved, not when there is nothing more to add, but when there is nothing left to take away." &lt;/span&gt;&lt;/dt&gt;&lt;dd&gt;&lt;span style="font-size: small;"&gt; -  Antoine de Saint Exupery&lt;/span&gt;&lt;/dd&gt;&lt;/dl&gt;&lt;div style="font-family: Georgia,&amp;quot;Times New Roman&amp;quot;,serif; text-align: justify;"&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;...so having completed a working version, I could then sit back and view it with a critical eye, noting where I could do things a little differently and refine the routine. Doing this in 6502 Assembler often feels like a maths problem, where you're asked to reduce a complex fraction to its' simplest terms - as with almost all programming languages there are numerous different ways to achieve the same result, and when coding Assembler you're continually striving to use the fewest possible instructions to get the job done in the smallest number of clock cycles and bytes.&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;I managed to shrink the code by a dozen bytes or so, which doesn't sound like a lot but is actually about a 20% reduction in the overall size of the routine - it's looking like it'll be around 60 bytes by the time I apply the final tweaks.&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;I also took the opportunity to re-map my Zero Page usage - most of the locations from 0 - 255 are used by various BASIC and KERNAL routines as working areas and storage, and there's typically not much you can freely use; but since Meanies is a 100% Assembler game, I can appropriate large chunks of ZP for my own use because I don't care about interfering with most of the ROM routines that use it. So instead of my code trying to squeeze into the few genuinely free ZP locations, I'm now able to use much more of the available space - although at this point my ZP memory footprint is still only 17 bytes, so we're not exactly stressing the machine. ;)&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;During the remapping process I stumbled across a subtle bug in the BSOD routine, where in some cases the .SR bit readout went wrong - so that got fixed as I went along. I'm now debugging the new CHARPLOT routine, and applying the finishing touches to it - hopefully there's no more than an hours' work left to do on it.&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5108605455275049037-6316622158602331894?l=devicenotpresent.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://devicenotpresent.blogspot.com/feeds/6316622158602331894/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://devicenotpresent.blogspot.com/2010/06/bughunting.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5108605455275049037/posts/default/6316622158602331894'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5108605455275049037/posts/default/6316622158602331894'/><link rel='alternate' type='text/html' href='http://devicenotpresent.blogspot.com/2010/06/bughunting.html' title='Bughunting'/><author><name>Jonners</name><uri>http://www.blogger.com/profile/10783097207231622242</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='29' src='http://3.bp.blogspot.com/_k7S257jPIsM/S4BCVi6S3sI/AAAAAAAAAqc/4_pLkqr1Wxc/s1600-R/CommodorePET4032.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5108605455275049037.post-1008056904839543848</id><published>2010-06-21T12:35:00.000+01:00</published><updated>2010-06-21T12:35:42.407+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Character'/><category scheme='http://www.blogger.com/atom/ns#' term='Plotting'/><category scheme='http://www.blogger.com/atom/ns#' term='Screen'/><title type='text'>Painting by Numbers</title><content type='html'>&lt;div style="text-align: justify;"&gt;The work on the character-plotting routine (CHARPLOT) is now well under way - the first few hours were spent defining and then refining what the data structure should look like. I think this is close to being the final revision, but it might still evolve a little as the code moves towards its' final form:&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;/div&gt;&lt;ul style="text-align: justify;"&gt;&lt;li&gt;Control Byte&lt;/li&gt;&lt;li&gt;Offset Byte&lt;/li&gt;&lt;li&gt;Repeat Byte&lt;/li&gt;&lt;li&gt;Effect Byte&lt;/li&gt;&lt;li&gt;Character Byte&lt;/li&gt;&lt;/ul&gt;&lt;div style="text-align: justify;"&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;The bare minimum needed to plot a single character is three bytes - Control, Offset, and Character.&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;To plot a repeated sequence of a single character, you need four bytes - Control, Offset, Repeat and Character.&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;To plot a string of a given length, you need three bytes plus as many bytes as there are in the string - Control, Offset, Repeat and 'n' Characters.&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;You only need the Effect byte if you're using an auxiliary colour and/or a 'special effect' - i.e. some bespoke pre- or post-processing that has to happen to each character as it's plotted.&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;The CHARPLOT routine always reads the Control and Offset bytes, since these dictate what kind of plot it will do, and where on the screen to start. Two bits in the Control byte determine whether to read the Repeat and/or Effect bytes, so these may or may not be present. CHARPLOT then reads the Character byte, or a sequence of Character bytes if it's a string, and updates the screen and colour memory as appropriate.&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;As a general-purpose screen-painting routine, it serves its' purpose - I can encode a single character as three bytes (not especially efficient), or any repetition of that character up to 256 bytes long as four bytes (very efficient). If there's any kind of specific effect to be applied as the plot progresses, this is just one extra byte in the definition, plus a branch in the CHARPLOT code to whatever effect subroutine is needed (there are 15 effect 'slots' available).&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;The key thing, of course, is not so much that I can encode sequences of characters to paint to the screen in this way, but much more importantly that CHARPLOT is fast - much faster than the 'STROUT' routine in the BASIC ROM. It's working against a specific, predefined data structure that I create to enable stuff to appear on the screen, and it isn't doing anything in the way of making sure I've got it right - it'll just do what it's told, and if I've made a mistake somewhere then it'll splat junk to the screen. This is the big difference between CHARPLOT and STROUT - no hand-holding, no error-checking, and no forgiveness if I give it rubbish to play with - but, on the flipside, it absolutely blasts the screen with data as fast as it can.&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;This routine is good for drawing stuff like the static title screen and the 'playfield' structures on the main game screen. It might be fast enough to be used as a re-draw routine for 'scrolling' games, but I'm not testing that, as this game doesn't require it. It might also even be fast enough to draw (and re-draw) in-game characters like the Meanies themselves, the Repair Bot, and maybe the laser blasts and explosions - I'm anticipating writing custom code to handle the drawing of the dynamic stuff, but if it turns out that CHARPLOT is up to the task, then I'll use that instead. :)&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;In comparing the presentation of the games' title screen using the 'old' Assembly code which called STROUT, and the 'new' version using CHARPLOT, they look identical (as you'd expect). But what is immediately apparent is the fact that the update time to draw the whole screen using the second version is too small to measure by eye; it's instantaneous.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5108605455275049037-1008056904839543848?l=devicenotpresent.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://devicenotpresent.blogspot.com/feeds/1008056904839543848/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://devicenotpresent.blogspot.com/2010/06/painting-by-numbers.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5108605455275049037/posts/default/1008056904839543848'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5108605455275049037/posts/default/1008056904839543848'/><link rel='alternate' type='text/html' href='http://devicenotpresent.blogspot.com/2010/06/painting-by-numbers.html' title='Painting by Numbers'/><author><name>Jonners</name><uri>http://www.blogger.com/profile/10783097207231622242</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='29' src='http://3.bp.blogspot.com/_k7S257jPIsM/S4BCVi6S3sI/AAAAAAAAAqc/4_pLkqr1Wxc/s1600-R/CommodorePET4032.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5108605455275049037.post-3232908596282139672</id><published>2010-06-14T20:14:00.042+01:00</published><updated>2010-06-14T22:46:41.272+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='BASIC'/><category scheme='http://www.blogger.com/atom/ns#' term='ROM'/><category scheme='http://www.blogger.com/atom/ns#' term='Assembly'/><title type='text'>The Plot Thickens</title><content type='html'>&lt;div style="text-align: justify;"&gt;I've carried-on with the initialisation stuff for the game - in this version (the 'classic' incarnation) I'm literally converting lines of BASIC into pure Assembler, adding appropriate framework architecture as needed. So, for example, to get the title screen displayed fully, I reused a chunk of code I wrote for the BSOD routine to display the  text, and It Just Worked. With a little self-promotion (and some minor text alignment tweaking) we have the BASIC and Assembler versions side-by-side:&lt;/div&gt;&lt;table border="0" cellpadding="5" cellspacing="0"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td align="center" valign="top" width="25%"&gt;&lt;/td&gt;&lt;td align="center" valign="top" width="25%"&gt;&lt;br /&gt;&lt;a href="http://picasaweb.google.com/lh/photo/WdHJN7kU_h_ZB6geXKcZ-KcpcHmo15LK-1lQng1qVXk?feat=embedwebsite"&gt;&lt;img src="http://lh5.ggpht.com/_k7S257jPIsM/S-b98hPAP8I/AAAAAAAAAs4/5M_e-sfQAgQ/s288/BM-Title.png" /&gt;&lt;/a&gt;&lt;br /&gt;BASIC Meanies Title Screen&lt;/td&gt;&lt;td align="center" valign="top" width="25%"&gt;&lt;br /&gt;&lt;a href="http://picasaweb.google.co.uk/lh/photo/yp277Ab22Xp4YYDn1XFOeKcpcHmo15LK-1lQng1qVXk?feat=embedwebsite"&gt;&lt;img src="http://lh3.ggpht.com/_k7S257jPIsM/TBZ-98KtyLI/AAAAAAAAAvM/NlHxnsn2GYc/s288/Title2.png" /&gt;&lt;/a&gt;&lt;br /&gt;Assembler Meanies Title Screen&lt;/td&gt;&lt;td align="center" valign="top" width="25%"&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;&lt;div style="text-align: justify;"&gt;After I got the title screen working, I felt pretty pleased with myself - after all, this is pure 6502 Assembly here, so getting a screen display (albeit a static one) working and waiting for a keypress was very satisfying.&amp;nbsp; Enthused, I quickly moved on to the next phase, which is to draw the initial game playfield; essentially a giant square 'U' which comprises the 'walls' and 'floor' which the Meanies like to blow themselves up against:&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://lh5.ggpht.com/_k7S257jPIsM/S-b98l_Ik1I/AAAAAAAAAs8/f010Yd_EjmQ/s1600/BM-Game.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://lh5.ggpht.com/_k7S257jPIsM/S-b98l_Ik1I/AAAAAAAAAs8/f010Yd_EjmQ/s320/BM-Game.png" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;br /&gt;At this point, I once again cloned the basic logic of the BSOD display code, and that's when some of the shine&amp;nbsp; suddenly went off the product. The title screen is fairly sparsely-populated in terms of content, so it draws pretty quickly - certainly quicker than the BASIC original, which has perceptible visibility of the updates as they're applied to the screen. The problem was that, whereas I knew the BASIC playfield draw was perceptible, the Assembly playfield draw was &lt;i&gt;also&lt;/i&gt; visibly doing the update, and to my eye was only fractionally faster than BASIC - certainly not up to the blisteringly-fast 'blink' into existence I'd been anticipating. Something was wrong, and I knew what it was.&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;Here's a snippet of the code that reads data from a table of lines and displays them on the screen. The magic happens at the call to &lt;b&gt;STROUT&lt;/b&gt;, which is a BASIC ROM routine at $CB1E that takes the start-address of a zero-terminated string in .A and .Y and makes it appear on the screen - it's part of the code that the BASIC 'PRINT' command uses after all the interpretive parsing has been done:&lt;/div&gt;&lt;pre style="background-color: #eeeeee; border: 1px dashed rgb(153, 153, 153); color: black; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; font-size: 12px; line-height: 14px; overflow: auto; padding: 5px; width: 100%;"&gt;&lt;code&gt;          ; Display the title screen message lines&lt;br /&gt;          ldx #20               ; Message address offset in .X&lt;br /&gt;.msgloop  stx USRJMP            ; Save .X in ZP&lt;br /&gt;          lda .msgaddr,x        ; Message address LSB in .A&lt;br /&gt;          ldy .msgaddr+1,x      ; Message address MSB in .Y&lt;br /&gt;          jsr STROUT            ; Call ROM print routine&lt;br /&gt;          ldx USRJMP            ; Decrement counter for next message&lt;br /&gt;          dex&lt;br /&gt;          dex&lt;br /&gt;          bpl .msgloop          ; Loop until all messages displayed&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div style="text-align: justify;"&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;Now calling this routine in a BSOD display that essentially gets called once at program termination, when a BRK is hit, is fine. Even for some simple title-screen text display purposes, it's fine. But for drawing anything more complex, with more 'stuff' to get onto the screen, it is most assuredly &lt;i&gt;NOT&lt;/i&gt; fine.&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;The problem is this: the VIC-20 ROM is a 16K chunk of finely-crafted (mostly) 6502 code, divided into two sections. At $E000 you have the KERNEL, the 8K of code written by the engineers who designed the computer - it's there to talk to the bare metal of the machine and get stuff done, and is consequently pretty efficient, fast, and good-quality; the equivalent of todays' BIOS bootcode ROM in your PC that handles all the really low-level stuff.&lt;br /&gt;&lt;br /&gt;And then, at $C000, you have 8K of BASIC interpreter; code written by Microsoft as a generic 6502-based BASIC that could be (and was) licensed to computer manufacturers for inclusion into their products - usually with a little tweaking, although the core always largely remained the same. It too is pretty good-quality code, but it wasn't &lt;i&gt;designed&lt;/i&gt; for the VIC-20 as such - it's general-purpose code, and thus has somewhat less of a demand to be lean and mean. Which is not a bad thing - I think Microsoft did a good job overall - but...&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;This 6502 BASIC had four underlying design goals, which were&lt;/div&gt;&lt;ul&gt;&lt;li&gt;that it should fit into 8K, making it attractive to buyers - a decent BASIC implementation in one 8K ROM? Yes please!&lt;/li&gt;&lt;li&gt;that it be general-purpose, so young Mr. Gates could sell the same core product to lots of different people&lt;/li&gt;&lt;li&gt;that it be user-friendly, because BASIC is supposed to be easy to learn and use&lt;/li&gt;&lt;li&gt;and finally, that it be fairly idiot-proof, so that invalid commands or parameters wouldn't crash the machine&lt;/li&gt;&lt;/ul&gt;&lt;div style="text-align: justify;"&gt;This is all fine and dandy until you're writing Assembly and calling a BASIC ROM routine which does a whole bunch of user-friendly stuff (like handling special control characters for inverse video, colour, cursor movement, etc.) and which tests and checks everything before proceeding so you don't accidentally break anything.&amp;nbsp; Because that all adds up to &lt;i&gt;&lt;b&gt;S-L-O-W&lt;/b&gt;&lt;/i&gt;.&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;To put it bluntly, unless there's something VERY specific and VERY useful in the VIC-20 BASIC ROM that you desperately need, you're probably better-off staying away from it if you're writing Assembly for speed - unless you're writing some sort of extension to BASIC itself, of course. All of which means I need a general-purpose character-plotting routine that'll be a tailored substitute for &lt;b&gt;STROUT&lt;/b&gt;, because I don't want or need all the cotton-wool that the BASIC ROM comes wrapped in, and I certainly don't want the consequent decrease in speed.&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5108605455275049037-3232908596282139672?l=devicenotpresent.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://devicenotpresent.blogspot.com/feeds/3232908596282139672/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://devicenotpresent.blogspot.com/2010/06/plot-thickens.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5108605455275049037/posts/default/3232908596282139672'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5108605455275049037/posts/default/3232908596282139672'/><link rel='alternate' type='text/html' href='http://devicenotpresent.blogspot.com/2010/06/plot-thickens.html' title='The Plot Thickens'/><author><name>Jonners</name><uri>http://www.blogger.com/profile/10783097207231622242</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='29' src='http://3.bp.blogspot.com/_k7S257jPIsM/S4BCVi6S3sI/AAAAAAAAAqc/4_pLkqr1Wxc/s1600-R/CommodorePET4032.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh5.ggpht.com/_k7S257jPIsM/S-b98hPAP8I/AAAAAAAAAs4/5M_e-sfQAgQ/s72-c/BM-Title.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5108605455275049037.post-1733080105697044160</id><published>2010-06-11T19:41:00.001+01:00</published><updated>2010-06-11T19:42:02.862+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='BASIC'/><category scheme='http://www.blogger.com/atom/ns#' term='ROM'/><category scheme='http://www.blogger.com/atom/ns#' term='PETSCII'/><category scheme='http://www.blogger.com/atom/ns#' term='Assembly'/><title type='text'>To Business</title><content type='html'>&lt;div style="text-align: justify;"&gt;I thought I'd share this little snippet with you, even though it's hardly earth-shattering - I've actually started porting the original BASIC Blue Meanies code to Assembly. Here's an example - this is couple of lines from the beginning of the original program, concerned with initialisation (my annotation is prefixed with an '*' before each line):&lt;/div&gt;&lt;pre style="background-color: #eeeeee; border: 1px dashed rgb(153, 153, 153); color: black; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; font-size: 12px; line-height: 14px; overflow: auto; padding: 5px; width: 100%;"&gt;&lt;code&gt;* Clear keyboard buffer, clear screen, poke coloured blocks to top line, set screen colours to normal&lt;br /&gt;1 poke198,0:print"{clr}{blu}":fora=0to21:poke7680+a,160:poke38400+a,(aand7):next:vi=36864:pokevi+15,27&lt;br /&gt;&lt;br /&gt;* Set character memory pointer to normal, poke coloured blocks to bottom line, set volume to max&lt;br /&gt;2 pokevi+5,240:fora=21to0step-1:poke8164+a,160:poke38884+a,(aand7):next:pokevi+14,15&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;And here's what it looks like in Assembly:&lt;br /&gt;&lt;pre style="background-color: #eeeeee; border: 1px dashed rgb(153, 153, 153); color: black; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; font-size: 12px; line-height: 14px; overflow: auto; padding: 5px; width: 100%;"&gt;&lt;code&gt;          ; VIC chip initialisation&lt;br /&gt;          sei                   ; Disable interrupts&lt;br /&gt;          jsr CINT1             ; Reset VIC&lt;br /&gt;&lt;br /&gt;          ; Title screen&lt;br /&gt;          lda #0                ; Clear keyboard buffer&lt;br /&gt;          sta KEYCOUNT&lt;br /&gt;          jsr CLRSCRN           ; Clear the screen&lt;br /&gt;&lt;br /&gt;          ; Coloured blocks across top and bottom of screen&lt;br /&gt;          ldx #21               ; 22 character positions&lt;br /&gt;.block    lda #160              ; Inverse space character&lt;br /&gt;          sta #SCREEN,x         ; Top screen line character&lt;br /&gt;          sta #SCREEN+484,x     ; Bottom screen line character&lt;br /&gt;          txa                   ; Move counter in .X to .A&lt;br /&gt;          and #7                ; Mask for colour&lt;br /&gt;          sta #COLOUR,x         ; Top screen line colour&lt;br /&gt;          sta #COLOUR+484,x     ; Bottom screen line colour&lt;br /&gt;          dex                   ; Next character position&lt;br /&gt;          bpl .block            ; Loop until all done&lt;br /&gt;&lt;br /&gt;          cli                   ; Re-enable interrupts&lt;br /&gt;          rts                   ; Return to BASIC&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;div style="text-align: justify;"&gt;We disable interrupts whilst we're doing the setup stuff for two reasons; firstly, we don't need any of the IRQ service routines ticking along in the background when we're just doing setup stuff; and secondly, I want to make sure that no other events occur during the call to CINT1 (the routine in ROM at $E518 which initialises the VIC chip during startup) which I use to quickly reset it to a known state.&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;We clear the keyboard buffer and call the ROM routine to clear the screen (which CINT1 has reset to the standard startup configuration and colours), and then do a simple loop to poke inverse spaces (PETSCII code 160) into each of the 22 character positions along the top and bottom rows - setting the colour memory at the same time.&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;Differences? Well, we didn't bother setting the text colour to blue (no point), or assigning 36864 - the VIC chip start address - to a variable (don't need it, as it's in a separate memory map file). We didn't set the screen colour combination to 27 (CINT1 takes care of that) or set the character matrix address to 240 (CINT1 again) or set the sound volume to 15 (because we're not making any noises yet).&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;Oh, the other main differences? The BASIC line structures occupy 197 bytes, and it takes just under a second to execute and draw those blocks. The 6502 Assembly code occupies 34 bytes and executes instantaneously.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5108605455275049037-1733080105697044160?l=devicenotpresent.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://devicenotpresent.blogspot.com/feeds/1733080105697044160/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://devicenotpresent.blogspot.com/2010/06/to-business.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5108605455275049037/posts/default/1733080105697044160'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5108605455275049037/posts/default/1733080105697044160'/><link rel='alternate' type='text/html' href='http://devicenotpresent.blogspot.com/2010/06/to-business.html' title='To Business'/><author><name>Jonners</name><uri>http://www.blogger.com/profile/10783097207231622242</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='29' src='http://3.bp.blogspot.com/_k7S257jPIsM/S4BCVi6S3sI/AAAAAAAAAqc/4_pLkqr1Wxc/s1600-R/CommodorePET4032.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5108605455275049037.post-2054656259033653064</id><published>2010-06-11T16:06:00.004+01:00</published><updated>2010-06-11T18:31:46.922+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='BSOD'/><category scheme='http://www.blogger.com/atom/ns#' term='Vector'/><category scheme='http://www.blogger.com/atom/ns#' term='6502'/><category scheme='http://www.blogger.com/atom/ns#' term='BRK'/><title type='text'>Blue Screenies</title><content type='html'>&lt;div style="text-align: justify;"&gt;I was browsing Denial a week or two ago, and one of the regulars there was asking a question regarding the creation of a 'debug' dump screen that resembled the classic Windows 'Blue Screen of Death', or BSOD, that could be invoked if a VIC-20 Assembler program they were developing went rogue and crashed. There isn't an easy way to get the VIC to automatically do this, since the OS is a single-threaded kernel with no way of detecting when a 'process' goes bad - if things go pear-shaped in your code, there's little the 6502 can do to either recover from it or even provide much in the way of detail to describe what went wrong. Theoretically you could hook a 'watchdog' routine into the IRQ, but that's not much use if your program wants to use the IRQ for its own purposes - and even then, what would your IRQ watchdog watch for? How would it know your main program had gone AWOL - especially if it's in a tight infinite loop with no way for the watchdog to know it isn't &lt;i&gt;supposed&lt;/i&gt; to be doing that? How do you make a 30-year-old monolithic single-threaded kernel OS do this:&lt;/div&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://zineserver.com/OPS/OFFICIAL/zt/textures/BSOD-0p6b.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="240" src="http://zineserver.com/OPS/OFFICIAL/zt/textures/BSOD-0p6b.png" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;div style="text-align: justify;"&gt;The only real option is to hook into the BRK vector - this is a routine that gets called automatically by the processor when a BRK instruction ($00) is executed. What that means is that if you had BRK instructions dotted-around in your code that should never get executed, but one somehow &lt;i&gt;does&lt;/i&gt; get hit, you can escape main execution and display some kind of debugging data. Equally, if you wanted to find out the status of the processor at some point during program flow, you can deliberately embed a BRK in the code to trigger the BSOD. I thought this would be a very useful aid in writing the game, so I resolved to implement something that would give me a useful diagnostic screen to look at when the inevitable problems arise as I progress.&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;Tying a BSOD handler to the BRK vector is a simple matter of loading the routine start address into the indirection pointers at $0316 and $0317; when the 6502 hits a BRK, it transfers program control through the hard-wired IRQ vector at $FFFE, which points to a ROM routine at $FF72 that figures-out if the interrupt is an IRQ or BRK. If it &lt;i&gt;is&lt;/i&gt; a BRK, it then jumps to the routine pointed to by the address in $0316/$0317, which makes it easy to hook up a routine that will give us some meaningful information about what was going on when the BRK was hit. What I've ended-up with is something that does this:&lt;/div&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://lh4.ggpht.com/_k7S257jPIsM/TAGQ2vi0hmI/AAAAAAAAAuc/GSgGU0hBHNc/s1600/bsod.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://lh4.ggpht.com/_k7S257jPIsM/TAGQ2vi0hmI/AAAAAAAAAuc/GSgGU0hBHNc/s320/bsod.png" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;div style="text-align: justify;"&gt;I estimate it took a total of six hours to write, debug, optimise, and then optimise some more. The whole thing weighs-in at 377 bytes, of which around 30% is just formatting storage for the display - the code that actually extracts the debug data (Program Counter where the BRK occurred, register values at the time, stack contents) is tight and efficient, but constructing structures to pass to the ROM routine to display stuff on the screen is necessarily space-consuming. Nevertheless, my first working version occupied about 480 bytes, used 5 Zero-Page memory locations and didn't display any stack data; the final version is 22% smaller, uses just 3 ZP locations, and displays the top of the stack. I'm pleased with it. :)&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span style="font-size: x-small;"&gt;(p.s. I know the VIC BSOD image above shows a bug - I slipped-up with a label and assigned a value to the wrong display location. It's fixed now, of course, but bonus points to anyone who can&amp;nbsp; see what it was.) &lt;/span&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5108605455275049037-2054656259033653064?l=devicenotpresent.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://devicenotpresent.blogspot.com/feeds/2054656259033653064/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://devicenotpresent.blogspot.com/2010/06/blue-screenies.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5108605455275049037/posts/default/2054656259033653064'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5108605455275049037/posts/default/2054656259033653064'/><link rel='alternate' type='text/html' href='http://devicenotpresent.blogspot.com/2010/06/blue-screenies.html' title='Blue Screenies'/><author><name>Jonners</name><uri>http://www.blogger.com/profile/10783097207231622242</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='29' src='http://3.bp.blogspot.com/_k7S257jPIsM/S4BCVi6S3sI/AAAAAAAAAqc/4_pLkqr1Wxc/s1600-R/CommodorePET4032.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh4.ggpht.com/_k7S257jPIsM/TAGQ2vi0hmI/AAAAAAAAAuc/GSgGU0hBHNc/s72-c/bsod.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5108605455275049037.post-1299591154285636937</id><published>2010-05-12T20:32:00.021+01:00</published><updated>2010-05-14T17:38:32.730+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Map'/><category scheme='http://www.blogger.com/atom/ns#' term='Memory'/><category scheme='http://www.blogger.com/atom/ns#' term='Sourcecode'/><category scheme='http://www.blogger.com/atom/ns#' term='Macro'/><category scheme='http://www.blogger.com/atom/ns#' term='6502'/><title type='text'>Programming Framework</title><content type='html'>&lt;div style="text-align: justify;"&gt;The first step in creating the game is to set up the basics of the assembly process - I need a good set of VIC-20 memory layout tables, some DASM macros for generating pre-defined chunks of code, a subroutines library where I can keep common code, and of course the main game file itself.&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;To create the memory layout tables, I took a couple of the widely-available sets of documentation regarding the VIC-20 memory model and turned them into the appropriate 'ds' and 'equ' assembler mnemonics. In fact, I'd actually done this a couple of years ago when I first started writing the 6502 emulator, so that I could include annotated output in the debugging window to see what the processor was doing as it chewed through the VIC-20 ROM. So the main Blue Meanies game simply includes my 'VICMap' file, making it really easy to reference any memory location or ROM routine by name - here's a snippet from VICMap.6502:&lt;br /&gt;&lt;/div&gt;&lt;pre style="background-color: #eeeeee; border: 1px dashed rgb(153, 153, 153); color: black; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; font-size: 12px; line-height: 14px; overflow: auto; padding: 5px; width: 100%;"&gt;&lt;code&gt;         SEG.U vicmap_6522via2&lt;br /&gt;         ORG $9120&lt;br /&gt;V2PORTBO ds.b 1   ; VIA#2 Port B output register&lt;br /&gt;V2PORTAO ds.b 1   ; VIA#2 Port A output register&lt;br /&gt;V2PORTBD ds.b 1   ; VIA#2 Data direction register B&lt;br /&gt;V2PORTAD ds.b 1   ; VIA#2 Data direction register A&lt;br /&gt;V2T1LO1  ds.b 1   ; VIA#2 Timer 1, low byte latch&lt;br /&gt;V2T1HI1  ds.b 1   ; VIA#2 Timer 1, high byte latch&lt;br /&gt;V2T1LO2  ds.b 1   ; VIA#2 Timer 1, low byte counter&lt;br /&gt;V2T1HI2  ds.b 1   ; VIA#2 Timer 1, high byte counter&lt;br /&gt;V2T2LO1  ds.b 1   ; VIA#2 Timer 2, low byte latch&lt;br /&gt;V2T2HI1  ds.b 1   ; VIA#2 Timer 2, high byte latch&lt;br /&gt;V2SHIFT  ds.b 1   ; VIA#2 Shift register&lt;br /&gt;V2AUX    ds.b 1   ; VIA#2 Auxiliary control register&lt;br /&gt;V2PCR    ds.b 1   ; VIA#2 Peripheral control register&lt;br /&gt;V2INTFLG ds.b 1   ; VIA#2 Interrupt flag register&lt;br /&gt;V2INTENA ds.b 1   ; VIA#2 Interrupt enable register&lt;br /&gt;V2PORTA2 ds.b 1   ; VIA#2 Port A output register&lt;br /&gt;&lt;br /&gt;         SEG.U vicmap_basic_kernal&lt;br /&gt;BASICVEC EQU $C000  ; Basic Restart Vectors [WORD]&lt;br /&gt;CBMBASIC EQU $C004  ; 'CBMBASIC' [DATA]&lt;br /&gt;STMDSP   EQU $C00C  ; BASIC Command Vectors [WORD]&lt;br /&gt;FUNDSP   EQU $C052  ; BASIC Function Vectors [WORD]&lt;br /&gt;OPTAB    EQU $C080  ; BASIC Operator Vectors [WORD]&lt;br /&gt;RESLST   EQU $C09E  ; BASIC Command Keyword Table [DATA]&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div style="text-align: justify;"&gt;&lt;br /&gt;Next, there's at least one chunk of code that is essentially a pre-set block of data that I want to include in the game - the BASIC stub that incorporates the call to start the game itself. This block of code is really just a single line containing a 'SYS' command followed by the memory location of the start of the game - however, you can play some tricks with the BASIC interpreters' LIST command so that you can actually hide that SYS and replace it with something else. You do that by encoding some control bytes in the BASIC line structure so that when LIST tries to list the program, it actually executes the equivalent of some hidden escape characters and displays something else - which looks very cool, and also makes it a bit trickier for the casual user to hack the program.&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;My VICMacro.6502 file contains DASM macros for generating chunks of code like this - at the moment there's only one macro in there (BasicLine) which accepts a variety of parameters and builds the BASIC stub accordingly. This file is also included by the game - here's a snippet:&lt;br /&gt;&lt;/div&gt;&lt;pre style="background-color: #eeeeee; border: 1px dashed rgb(153, 153, 153); color: black; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; font-size: 12px; line-height: 14px; overflow: auto; padding: 5px; width: 100%;"&gt;&lt;code&gt;          ; Initialised segment for code generation&lt;br /&gt;          SEG basicline_code&lt;br /&gt;.LNDIGCNT EQU .SEGEND-.LNDIGITS  ; Count of digits in linenum&lt;br /&gt;&lt;br /&gt;          ; Where should we generate the BASIC line?&lt;br /&gt;          IF .VICMEM = 0 | .VICMEM = 3 | .VICMEM = 8&lt;br /&gt;            IF .VICMEM = 0       ; Unexpanded VIC-20&lt;br /&gt;              ORG $1000          ; Start of BASIC is at 4096&lt;br /&gt;            ENDIF&lt;br /&gt;            IF .VICMEM = 3       ; 3K expanded VIC-20&lt;br /&gt;              ORG $0400          ; Start of BASIC is at 1024&lt;br /&gt;            ENDIF&lt;br /&gt;            IF .VICMEM = 8       ; 8K+ expanded VIC-20&lt;br /&gt;              ORG $1200          ; Start of BASIC is at 4608&lt;br /&gt;            ENDIF&lt;br /&gt;          ELSE&lt;br /&gt;            ECHO "BASICLINE: 'vicmem' parameter must be 0, 3 or 8"&lt;br /&gt;            ERR&lt;br /&gt;          ENDIF&lt;br /&gt;&lt;br /&gt;          ; Check line number is valid&lt;br /&gt;          IF .LINENUM LT 0 | .LINENUM GT 63999&lt;br /&gt;            ECHO "BASICLINE: 'linenum' parameter must be 0-63999"&lt;br /&gt;            ERR&lt;br /&gt;          ENDIF&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div style="text-align: justify;"&gt;&lt;br /&gt;I also want a place to stash common or shared subroutines so that the main game file holds only core game-engine code - this is purely a stylistic preference, but I like to be able to look at subroutine code side-by-side with the calling code, and this helps me to do that. Here's a snippet of Subroutines.6502:&lt;br /&gt;&lt;/div&gt;&lt;pre style="background-color: #eeeeee; border: 1px dashed rgb(153, 153, 153); color: black; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; font-size: 12px; line-height: 14px; overflow: auto; padding: 5px; width: 100%;"&gt;&lt;code&gt;vidmode: lda RASTER   ; Get the raster line counter (upper 8 bits)&lt;br /&gt;         cmp #1       ; Line 2? (updates every 2nd line)&lt;br /&gt;         bne vidmode  ; Nope - keep looking&lt;br /&gt;&lt;br /&gt;line268: lda RASTER   ; Found line 2, now poll counter again&lt;br /&gt;         beq line0    ; Hit line 0 or 1 - missed 268, so this is NTSC&lt;br /&gt;         cmp #134     ; Line 268? NTSC only has 261 lines, PAL has 321&lt;br /&gt;         bne line268  ; If we hit 268 it's PAL, otherwise loop again&lt;br /&gt;&lt;br /&gt;line0:   rts          ; .A holds video mode flag byte&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div style="text-align: justify;"&gt;&lt;br /&gt;And finally here's the very simple and unremarkable beginning to the game itself, containing little more than the include statements for the other files, an 'INCBIN' to pull in the original Blue Meanies UDG* data, and a little bit of test code to make sure everything is hanging together. From little acorns...&lt;br /&gt;&lt;/div&gt;&lt;pre style="background-color: #eeeeee; border: 1px dashed rgb(153, 153, 153); color: black; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; font-size: 12px; line-height: 14px; overflow: auto; padding: 5px; width: 100%;"&gt;&lt;code&gt;;-------------------------------------------------------------------------------&lt;br /&gt;; Blue Meanies Revenge      Copyright (C) 2010 Jonners9&lt;br /&gt;; A game for the VIC-20 (PAL/NTSC)&lt;br /&gt;&lt;br /&gt;                    ; Assemble for 6502 CPU&lt;br /&gt;                    processor 6502&lt;br /&gt;&lt;br /&gt;                    ; Macros and map symbols&lt;br /&gt;                    include VICMacro.6502&lt;br /&gt;                    include VICMap.6502&lt;br /&gt;&lt;br /&gt;                    ; Generate a BASIC line to invoke our code&lt;br /&gt;                    basicline 0,2010,"","","Y"," BLUE MEANIES REVENGE                         (C) 2010  JONNERS9  "&lt;br /&gt;&lt;br /&gt;                    ; Set memory symbols&lt;br /&gt;                    setmemory 0                                    ; Unexpanded VIC&lt;br /&gt;&lt;br /&gt;                    ; Let the games commence&lt;br /&gt;                    jsr vidmode                                    ; Are we in PAL or NTSC mode?&lt;br /&gt;                    sta wvidmode&lt;br /&gt;&lt;br /&gt;                    ldx #$00&lt;br /&gt;loop                txa&lt;br /&gt;                    sta SCREEN,x&lt;br /&gt;                    lda #$00&lt;br /&gt;                    sta COLOUR,x&lt;br /&gt;                    dex&lt;br /&gt;                    bne loop&lt;br /&gt;&lt;br /&gt;                    lda #$ff&lt;br /&gt;                    sta CHARMEM&lt;br /&gt;                    rts&lt;br /&gt;&lt;br /&gt;                    ; Common subroutines&lt;br /&gt;                    include Subroutines.6502&lt;br /&gt;&lt;br /&gt;                    ; Working storage&lt;br /&gt;wvidmode            ds.b 1&lt;br /&gt;&lt;br /&gt;                    ; UDG binary data&lt;br /&gt;                    ORG $1C00&lt;br /&gt;udgdata             incbin "UDG Data.bin"&lt;br /&gt;&lt;br /&gt;                    ; Endpoint marker byte&lt;br /&gt;endpoint            dc.b $ff&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;Oh, you might be wondering why I'm using a '.6502' extension for my Assembler files, instead of the far more common '.asm'. The reason is that I have an existing file association for '.asm' which maps to Visual Studio and is used for the odd bit of x86 programming that I do from time to time. Since I want to work on Blue Meanies in Crimson Editor, I've set an association for it to open '.6502' files and use the appropriate syntax highlighting and command macro definitions. I guess if I ever publish the full sourcecode for the game, I'll rename everything to '.asm' so that it conforms to the usual naming convention.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;div style="text-align: justify;"&gt;&lt;span style="font-size: x-small;"&gt;* UDG - User Defined Graphics; simple bitmap data that the VIC-20 can be programmed to use as an alternate character set, and which in this case contains shapes representing the Meanies, explosions, laser turrets, the repair bot, etc.&lt;/span&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5108605455275049037-1299591154285636937?l=devicenotpresent.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://devicenotpresent.blogspot.com/feeds/1299591154285636937/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://devicenotpresent.blogspot.com/2010/05/programming-framework.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5108605455275049037/posts/default/1299591154285636937'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5108605455275049037/posts/default/1299591154285636937'/><link rel='alternate' type='text/html' href='http://devicenotpresent.blogspot.com/2010/05/programming-framework.html' title='Programming Framework'/><author><name>Jonners</name><uri>http://www.blogger.com/profile/10783097207231622242</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='29' src='http://3.bp.blogspot.com/_k7S257jPIsM/S4BCVi6S3sI/AAAAAAAAAqc/4_pLkqr1Wxc/s1600-R/CommodorePET4032.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5108605455275049037.post-3300858493125483825</id><published>2010-05-10T18:09:00.023+01:00</published><updated>2010-05-12T16:15:59.089+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Editor'/><category scheme='http://www.blogger.com/atom/ns#' term='Toolchain'/><category scheme='http://www.blogger.com/atom/ns#' term='Crimson'/><category scheme='http://www.blogger.com/atom/ns#' term='VICE'/><category scheme='http://www.blogger.com/atom/ns#' term='DASM'/><title type='text'>The Tools of The Trade</title><content type='html'>&lt;div style="text-align: justify;"&gt;You might like to know what the development environment toolchain is these days for writing 6502 Assembly Language on a PC and then squirting it to the target machine. Broadly speaking, it's a text editor, a cross-assembler, some sort of linker or packager (if necessary) to wrap the object code up, and a transfer mechanism to physically push the product to the target. You may then conceivably need something on the target to execute the product - maybe a script or something like that. For VIC-20 development, my toolchain (download links on the right) breaks down as follows:&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="background-color: black; color: white;"&gt;Text Editor&lt;/div&gt;&lt;div style="text-align: justify;"&gt;My preferred choice for a text editor is Crimson Editor, a nifty bit of freeware which is aimed at programmers who need something a bit slicker than Notepad, but without the massive overhead of a heavyweight IDE like Visual Studio (which, incidentally, I use for C# development). It supports multiple tabbed documents, macros, syntax highlighting, automatic backups, and a number of other little niceties which make it very comfortable to use. Here's an example screenshot from my desktop:&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://lh6.ggpht.com/_k7S257jPIsM/S-g8L0GS5SI/AAAAAAAAAtk/hlheOF8fFhU/s1600/Crimson.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://lh6.ggpht.com/_k7S257jPIsM/S-g8L0GS5SI/AAAAAAAAAtk/hlheOF8fFhU/s320/Crimson.png" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;div style="text-align: justify;"&gt;&lt;div style="background-color: black; color: white;"&gt;Cross-Assembler&lt;/div&gt;There are two or three really good 6502 cross-assemblers out there, but my favourite is DASM - simply because I've been using it for years, know its' strengths and weaknesses, and understand how to make it do what I want. It's a multi-pass assembler with support for labels, macros, segments, and so on - and it generates a variety of object types for several CPU models. It's fast, and being commandline-driven means it slots into automated build scripts with no fuss.&lt;br /&gt;&lt;br /&gt;&lt;div style="background-color: black; color: white;"&gt;Packager (Linker)&lt;/div&gt;Since DASM largely handles combining object and binary code if you ask it to, there's no need for a separate link stage to bind the code together. However, you might find that you want to extend the build process to the point that it generates full-blown disk images which can be distributed as the Commodore equivalent of an install package (broadly speaking - I realise this not a true comparison). For that, you could use the 'c1541' utility that ships as part of the VICE suite, and which is designed to build a variety of Commodore disk image types.&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;br /&gt;&lt;div style="background-color: black; color: white;"&gt;Physical Transfer&lt;/div&gt;Getting the finished software build to a real VIC-20 is not a simple matter, unless you have one of the various types of transfer hardware/software kits that exist - the fact that the target machine is pushing 30 years old means it has nothing in the way of the 'standard' interface connections that we take for granted today. So there are a few ways of effecting data transfer to and from the machine, but they all require some interface hardware to either be purchased from the specialists who make them, or to be built yourself if you're handy with a soldering-iron. Personally, though I have a VIC-20 in my collection, I just use the VICE emulation suite since it is sufficiently accurate that only extreme edge-conditions differ from the real hardware. The xVIC emulator in VICE looks like this:&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://lh4.ggpht.com/_k7S257jPIsM/S-b98ABlIEI/AAAAAAAAAs0/f659z8PAq_8/s1600/VIC-20.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://lh4.ggpht.com/_k7S257jPIsM/S-b98ABlIEI/AAAAAAAAAs0/f659z8PAq_8/s320/VIC-20.png" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;br /&gt;&lt;div style="background-color: black; color: white;"&gt;References and Resources&lt;/div&gt;Aside from the PC applications needed to make and test VIC-20 software, there are also a variety of online resources which are very handy for reference material regarding the target machine itself. Links to my favourites are on the right, with Denial and 6502.org being the two I hit the most frequently.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5108605455275049037-3300858493125483825?l=devicenotpresent.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://devicenotpresent.blogspot.com/feeds/3300858493125483825/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://devicenotpresent.blogspot.com/2010/05/tools-of-trade.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5108605455275049037/posts/default/3300858493125483825'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5108605455275049037/posts/default/3300858493125483825'/><link rel='alternate' type='text/html' href='http://devicenotpresent.blogspot.com/2010/05/tools-of-trade.html' title='The Tools of The Trade'/><author><name>Jonners</name><uri>http://www.blogger.com/profile/10783097207231622242</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='29' src='http://3.bp.blogspot.com/_k7S257jPIsM/S4BCVi6S3sI/AAAAAAAAAqc/4_pLkqr1Wxc/s1600-R/CommodorePET4032.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh6.ggpht.com/_k7S257jPIsM/S-g8L0GS5SI/AAAAAAAAAtk/hlheOF8fFhU/s72-c/Crimson.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5108605455275049037.post-4847358327239462103</id><published>2010-05-10T10:21:00.003+01:00</published><updated>2010-05-10T18:58:52.695+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Blue Meanies'/><category scheme='http://www.blogger.com/atom/ns#' term='VICE'/><category scheme='http://www.blogger.com/atom/ns#' term='VIC-20'/><title type='text'>In The Beginning...</title><content type='html'>&lt;div style="text-align: justify;"&gt;...there was the word. And the word was Commodore VIC-20. Hmm, that's two words. Anyway, if you've never heard them before, follow this link to the &lt;a href="http://en.wikipedia.org/wiki/Commodore_VIC-20"&gt;Wikipedia&lt;/a&gt; article, which does a fair job of describing what the VIC-20 is. In summary, it was a popular microcomputer of the early '80s, laughably primitive by todays' standards (and in some respects even by the standards of the time) but with enough features, personality and expandability that it was a favourite amongst the boom generation.&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;One of the first things I did when I unwrapped my shiny new VIC on Christmas Day 1981 - along with a C2N Cassette Deck and an 8K Expansion RAM Cartridge - was load-up some programs from the tapes that came with it. One of these was a game called "Blue Meanies From Outer Space", a somewhat quirky Space Invaders variant requiring the player to master no less than 11 key controls to fire the laser turrets and walk the repair 'bot around - the objective being to defend a nuclear reactor from the Meanies as they suicidally threw themselves down the screen trying to impact their bodies into anything breakable. Check it out:&lt;/div&gt;&lt;table border="0" cellpadding="5" cellspacing="0" width="100%"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td align="center" valign="top" width="33%"&gt;&lt;br /&gt;&lt;a href="http://picasaweb.google.com/lh/photo/uc1tRynxJS7AU80UG6BGc6cpcHmo15LK-1lQng1qVXk?feat=embedwebsite"&gt;&lt;img src="http://lh4.ggpht.com/_k7S257jPIsM/S-b98ABlIEI/AAAAAAAAAs0/f659z8PAq_8/s288/VIC-20.png" /&gt;&lt;/a&gt;&lt;br /&gt;VIC-20 Boot Screen&lt;/td&gt;&lt;td align="center" valign="top" width="33%"&gt;&lt;br /&gt;&lt;a href="http://picasaweb.google.com/lh/photo/WdHJN7kU_h_ZB6geXKcZ-KcpcHmo15LK-1lQng1qVXk?feat=embedwebsite"&gt;&lt;img src="http://lh5.ggpht.com/_k7S257jPIsM/S-b98hPAP8I/AAAAAAAAAs4/5M_e-sfQAgQ/s288/BM-Title.png" /&gt;&lt;/a&gt;&lt;br /&gt;Blue Meanies Title Screen&lt;/td&gt;&lt;td align="center" valign="top" width="33%"&gt;&lt;br /&gt;&lt;a href="http://picasaweb.google.com/lh/photo/X6cBS9tEWFS0XoHpwzm6hacpcHmo15LK-1lQng1qVXk?feat=embedwebsite"&gt;&lt;img src="http://lh5.ggpht.com/_k7S257jPIsM/S-b98l_Ik1I/AAAAAAAAAs8/f010Yd_EjmQ/s288/BM-Game.png" /&gt;&lt;/a&gt;&lt;br /&gt;Blue Meanies Gameplay&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;&lt;div style="text-align: justify;"&gt;Despite its' rudimentary gameplay and complex control system, I really enjoyed this game. Written in CBM BASIC V2 (the Commodore-licensed tweaked version of a standard Microsoft BASIC) it not only provided hours of entertainment, but also let the curious player have a look at the games' innards. I suspect this is why Commodore included it on the tape - it was pretty, interesting, and potentially educational. Win!&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;As far as I know, there's only ever been one remake of this game - the rather good Gaping Wolf version for the PC, which you can download from &lt;a href="http://www.gapingwolf.com/games/view/bluemeanies"&gt;here&lt;/a&gt; and which looks like this:&lt;/div&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://www.gapingwolf.com/photofile/d/13318-2/bmss1_large.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://www.gapingwolf.com/photofile/d/13318-2/bmss1_large.jpg" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;div style="text-align: justify;"&gt;I've been developing a 6502 emulator in C# for a couple of years now, and have been using the VIC-20 as the testbed to prove that the CPU emulation is good - essentially comparing the behavior of my emulated processor when dropped into a VIC memory model with that of the xVIC component of VICE, the excellent Commodore emulation suite. With that project drawing to a close, and having spent a lot of time replaying old VIC games when I should have been working on it, I thought it might be fun to remake Blue Meanies on the VIC itself, but in Assembler rather than BASIC, and with some up-to-date programming tricks and techniques to really make it shine on that old hardware.&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;This blog is where I'll post updates as the game progresses, alongside any other related items of interest. The intent is to first port the existing game to Assembler, and then rewrite it with a whole bunch of exciting bells and whistles - giving two basic playmodes, 'Classic' and 'Century 21'. The end result will be a game you can play either on the real hardware, if you have it, or in VICE.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5108605455275049037-4847358327239462103?l=devicenotpresent.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://devicenotpresent.blogspot.com/feeds/4847358327239462103/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://devicenotpresent.blogspot.com/2010/05/in-beginning.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5108605455275049037/posts/default/4847358327239462103'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5108605455275049037/posts/default/4847358327239462103'/><link rel='alternate' type='text/html' href='http://devicenotpresent.blogspot.com/2010/05/in-beginning.html' title='In The Beginning...'/><author><name>Jonners</name><uri>http://www.blogger.com/profile/10783097207231622242</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='29' src='http://3.bp.blogspot.com/_k7S257jPIsM/S4BCVi6S3sI/AAAAAAAAAqc/4_pLkqr1Wxc/s1600-R/CommodorePET4032.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh4.ggpht.com/_k7S257jPIsM/S-b98ABlIEI/AAAAAAAAAs0/f659z8PAq_8/s72-c/VIC-20.png' height='72' width='72'/><thr:total>0</thr:total></entry></feed>
