tag:blogger.com,1999:blog-77178863515077617142024-03-06T11:39:34.360-08:00TursiLion's RoarTursilionhttp://www.blogger.com/profile/16478174231304644316noreply@blogger.comBlogger52125tag:blogger.com,1999:blog-7717886351507761714.post-53150578828589844102024-03-06T11:26:00.000-08:002024-03-06T11:26:08.192-08:00Willy's Chocolate Experience<p>So like everyone else, I've been looking at that disastrous Willy experience. My heart goes out to the actors who tried their damndest, and the kids who were expecting a lot more.</p><p>I was curious about the script. I meant, it largely didn't seem undoable. Might have taken more time to set up than was given, but... here's the copy I worked from: https://www.documentcloud.org/documents/24449349-willyschocolateexperince</p><p>Obviously, the candy supplies should have been right. You knew how many tickets you sold.</p><p>You would have needed to dress the entire visible portion of that set. So that would mean building walls and decorating, using lighting to hide the ceiling would probably work. Astroturf makes an easy ground cover.</p><p>Everyone picks on the audience reactions being in the script. I guess that's not normal, but it's kind a 'so what?' on top of everything else. ;) It's a live show. "Pause for reaction" means the same thing.</p><p>Sound track would be needed, of course. Speakers hidden in the set on loop would do - volume adjusted per scene might even work? Otherwise you could use a dynamically adjusted soundtrack, assuming one tour at a time. That gives you the singing flowers and whispering trees, as well as musical cues for mood.</p><p>The giggle grass is why I wanted to review the script. You could have some astroturf mounted a little higher, waist high for a child perhaps, and simple proximity sensors could trigger it to vibrate and play the giggles. Safer and more reliable than stepping on it, but meets the goal.</p><p>Same for the talking tulips, of course, though why flowers and grass are so prominent in a candy display seems odd to me. Even better, you can deal with the wilting using air pressure in a rubber tube stem, and have them react to nearby voices by no longer sagging and thanking the audience.</p><p>Bubble machines are next - that's easy and can be cued by Willy or a cast member. The bubble that pops in his hand and turns into a sparkling light that ascends to the sky would be hard to do convincingly. I'd be inclined to drop it. You might be able to use projection and rely on a controlled point of view if you had a smokey room. Otherwise I think I'd have him catch a prop on a string during a moment of distraction, then let a flickering LED prop be pulled into the rafters on his release.</p><p>The Twilight Tunnel is next and is pure construction - should be simple to create and completely controls line of sight. Musical cues go darker. LED 'stars' can light roof of the tunnel and twinkle. Again, Willy needs a lighted prop - he can pull this one from his pocket since it doesn't fly away. Apparently all the audience gets one - kind of unfortunate but I guess you're making cheap LED ping-pong balls ;) A button cell battery and a single LED will glow for at least an hour or so. When making them you can insulate the battery with a small piece of paper or fabric, and leave a slot to pull it out at distribution time to activate the light.</p><p>The tunnel obviously won't be as dark as described for safety reasons, nor as long. Open at the entrance, bend to hide the entrance, and end at a door for the scene with the Unknown. Everyone agrees the Unknown's actress nailed it, so nothing to do here, and no prop was needed, though there are some cute lighting cues.</p><p>Have a cast member open the doors, and stride out to the Bubble and Lemonade Room. Larger, brighter, and still still decorated. Large rooms like this are how you will decide the size of the tour group, as you need enough room for them to be comfortable while still keeping the theme.</p><p>The lemonade perhaps should be carbonated to match the 'fizzes' description? Backup drinks of water or such should be available to those who can't have it - check with a nurse what makes sense for kids. Likewise for the candies, of course, every kid deserves SOMETHING.</p><p>Apparently nothing else of importance here - this is the snack area. Bubble machines need to be going all the time, but be sure to protect the drinks from popping soap with simple lids or a cover. (Perhaps they can be kept in refrigeration - a cooler or such).</p><p>Ah, but then we're off to the Imagination Lab. Okay... so we have a big 'Keep Out' door (and this would be at least a double-wide because this is a tour). The text for this introduction is poor, but that's not my problem as imaginary technical side. </p><p>The bizarrely flavored jelly beans are easy enough if they still make those Harry Potter jelly beans. We'll just use a bunch of those. Perhaps have the cast members hand them out. Give them a bunch of random, but a small reserve of known, pleasant beans for the less adventurous.</p><p>The big TV camera is easy - this is a classic photo op. Could be done a couple of ways, but the simplest might be to run people through an exit corridor after they get their beans with a marked location to stop and pose (with appropriate backdrop). People are told they can claim their photos at the end of the experience, and we will email them (or, as is the trend, they can take a picture of the screen they are previewed on.)</p><p>Now we're at the final scene with the anti-graffiti gobstopper. Obviously, there should be a display stage and it should be covered, so Willy can hop up and present it. There's a bit with Willy and the Unknown, up on stage where they are safe from bumping into the guests. We want a battlefield of lasters and lights... I don't know why, but okay! So the Unknown's appearance is prefaced with a fog machine, and now strobing lights and flashing lasers can create a scene of chaos. It might be important to identify anyone with photosensitivity before this scene so they can be escorted out.</p><p>During the scene Willy uses a remote to activate traps and 'illusions'. Simplest thing here is probably a cast member off stage who can slide false walls into the Unknown's path on cue once or twice. I was thinking from underneath, but such props would need to be light and might be unsafe if accidentally stepped on. No need for motors anyway, this can be kept very simple.</p><p>The Unknown's own weapon can be based on a laser pointer, with Willy dodging dramatically behind props. Some kind of response on the prop would be ideal - might be as simple as a projected explosion (or at least flash) with a sound. The audio engineering over this whole scene is what will sell it.</p><p>The final machine is probably going to be accomplished with projection across the stage. "Holographic" images of "sparkling cleanliness" can start across the stage. When Willy loads the Gobstopper into the machine's recepticle, the projection focuses into a wave that starts from the machine and flows across the Unknown, giving it time to be swept backwards. A wall panel opens showing a giant vaccuum with an opening large enough for them to enter, along with a vaccuum sound effect, seals the deal. He goes into the vaccuum, the panel slams shut, and the sparkle projection fades out.</p><p>Then we're off to the gift shop, because you'd be dumb not to have some cheap merch to sell. Here people are encouraged to hang out by the need to claim their TV photos.</p><p>So that's my proposal for the technical sides. It's /still/ a ridiculously cheap and cheesy experience, but at least it would have delivered on some of the promise??</p>Tursilionhttp://www.blogger.com/profile/16478174231304644316noreply@blogger.com1tag:blogger.com,1999:blog-7717886351507761714.post-68976268801225942062024-02-16T22:45:00.000-08:002024-02-16T22:45:42.024-08:00ITrax Module Teardown<p>While working on my car battery, I discovered a forgotten little GPS tracker tossed in with the jack. At first I couldn't figure out what I was looking at...</p><p></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEg3d6p5-Hx5O0kSwdoNAk-OAF0vn2Oa88Rl0LBPrnU-jA6Z60nuphF7sBWR1sfh6LviciJf1izR7LETXnfV-WBvsLob65Xio13I1YiY9w1ZH2cxi5ziJTNgphGTPLpALActg-w60LwMgcki20-plezW8o4nsxmVVUyKRBu-uuYcjr3rwouGAKjGAmHIHsdz" style="margin-left: 1em; margin-right: 1em;"><img alt="" data-original-height="1836" data-original-width="3264" height="180" src="https://blogger.googleusercontent.com/img/a/AVvXsEg3d6p5-Hx5O0kSwdoNAk-OAF0vn2Oa88Rl0LBPrnU-jA6Z60nuphF7sBWR1sfh6LviciJf1izR7LETXnfV-WBvsLob65Xio13I1YiY9w1ZH2cxi5ziJTNgphGTPLpALActg-w60LwMgcki20-plezW8o4nsxmVVUyKRBu-uuYcjr3rwouGAKjGAmHIHsdz" width="320" /></a></div><br />Why, it's a cellular GPS tracker! Eventually I figured out it came with the ITrax system I got when I bought the car way back in 2016. Some online investigation found that the company is long dead, and many believe it may have died in 2015, when the last Facebook post is: https://www.facebook.com/goitrax/<p></p><p>Anyway, I figured no harm seeing what was inside, so I took it apart.</p><p></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEgxwFFrZFnA6nYNU_gyOc52Z_Jvx-FB2uMxqtMqT5lQJ_BCo7YgvFFu1uDI0J00awSpwT8c6jNSVfC8oDT3TyQay0z9mjWeacaSFdrp2e1N1xDnyyJ_NFNFjymKjWFsfWKZefCEODd_ByyG6OZREMPeZLZHeTfFdbq-3GjyrKhyWE3iWilXgZcbXJglsr36" style="margin-left: 1em; margin-right: 1em;"><img alt="" data-original-height="1458" data-original-width="2592" height="180" src="https://blogger.googleusercontent.com/img/a/AVvXsEgxwFFrZFnA6nYNU_gyOc52Z_Jvx-FB2uMxqtMqT5lQJ_BCo7YgvFFu1uDI0J00awSpwT8c6jNSVfC8oDT3TyQay0z9mjWeacaSFdrp2e1N1xDnyyJ_NFNFjymKjWFsfWKZefCEODd_ByyG6OZREMPeZLZHeTfFdbq-3GjyrKhyWE3iWilXgZcbXJglsr36" width="320" /></a></div><br />Inside the base is this little instruction pad. Under that are a number of strong magnets used to attach it to metal parts of the car.<p></p><p></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEiEFo2YHU9GOu4Thb7d7TFKaRYy3_UDTRP5-pn9mkX_Kver3wPUBIlJEav6cXXtdtwu451UArlHkdDDk-rC0mN3qf46JEHjGhM3YbtIngr38owOamP-eH3GtFP70qC4aM8hn5w-awVgsOQxjRez_d1_u_fDwOhjq5ht660aZJ2HHm6ERayGJ1uIepPiFiRR" style="margin-left: 1em; margin-right: 1em;"><img alt="" data-original-height="1458" data-original-width="2592" height="180" src="https://blogger.googleusercontent.com/img/a/AVvXsEiEFo2YHU9GOu4Thb7d7TFKaRYy3_UDTRP5-pn9mkX_Kver3wPUBIlJEav6cXXtdtwu451UArlHkdDDk-rC0mN3qf46JEHjGhM3YbtIngr38owOamP-eH3GtFP70qC4aM8hn5w-awVgsOQxjRez_d1_u_fDwOhjq5ht660aZJ2HHm6ERayGJ1uIepPiFiRR" width="320" /></a></div><br />On the other side, we have two tiny antenna - labelled on the sides -- which are attached to with little pogo pins on the PCB.<p></p><p></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEhgcm4jpdT6K72jv53sJNsOfkYwrkkjVtZoIFLnnE6Pu8ShPykSNbCYmGdDn1Ui_PpUNOWtTDzm20Mc4gCyCfFSawRdwKB5Avs4_-UfYhik4BCok7wZK9itQOksIw0YAGEx9n7j5j1VeLbacoJgJtnVtGkVeAVImSzkxRAL67jZjAe_RR7y93pdMlcTh4Rn" style="margin-left: 1em; margin-right: 1em;"><img alt="" data-original-height="1836" data-original-width="3264" height="180" src="https://blogger.googleusercontent.com/img/a/AVvXsEhgcm4jpdT6K72jv53sJNsOfkYwrkkjVtZoIFLnnE6Pu8ShPykSNbCYmGdDn1Ui_PpUNOWtTDzm20Mc4gCyCfFSawRdwKB5Avs4_-UfYhik4BCok7wZK9itQOksIw0YAGEx9n7j5j1VeLbacoJgJtnVtGkVeAVImSzkxRAL67jZjAe_RR7y93pdMlcTh4Rn" width="320" /></a></div><p>PCB itself looks like this. There's a GPS module and a cellular modem, presumably under the two shields (which I didn't remove). They are labelled MB81 and MB70, but this doesn't appear to be meaningful.</p><p></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEivtGA3hPfs2DTL3JJtyHguEnGj5H5qkAaztn_wpmTymf594t1hiftf8C8lZgKBnpAHUMTLbCehrHWZa3h56oVvJe921u0lf7nGqnppJ-SWMQ6nb1IrwxXfR1zFEIcRTQ_yB3_ALqH5ROSOvAIvE2sbeXW59g8C6Tm4hMxe1RIKWStMWIyszfRQmweGF9PB" style="margin-left: 1em; margin-right: 1em;"><img alt="" data-original-height="1458" data-original-width="2592" height="180" src="https://blogger.googleusercontent.com/img/a/AVvXsEivtGA3hPfs2DTL3JJtyHguEnGj5H5qkAaztn_wpmTymf594t1hiftf8C8lZgKBnpAHUMTLbCehrHWZa3h56oVvJe921u0lf7nGqnppJ-SWMQ6nb1IrwxXfR1zFEIcRTQ_yB3_ALqH5ROSOvAIvE2sbeXW59g8C6Tm4hMxe1RIKWStMWIyszfRQmweGF9PB" width="320" /></a></div><div class="separator" style="clear: both; text-align: center;"><br /></div><div class="separator" style="clear: both; text-align: left;">On the other side of this PCB, and taking up most of the space, is this big ol' battery. It's a D cell sized 3.6v ER34615M - apparently a rather standard battery. It's pretty dead, of course. It had a foam pad glued all around it that was quite difficult to remove, even with heat (not that I wanted to try too much heat.) ie: https://www.batteryjunction.com/titus-er34615m-ax</div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: left;"><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEj6CmCozsdYepG69rxNpCWBhsOc60wU_AIOhSmLtOq8oo--Koiy9WJsIez5XsQmWxo5OwcmpNLjiOE4PWIh4Qdzaanz7O6OUFHJzsaLGziICyKYi4dt7BM_bPDz9UH8IqfGIYqfydj1VJkb5KXqMGLh8thIvlNUqZyH6mXqREx2T7gNxFhqyIiLcXF2XHFO" style="margin-left: 1em; margin-right: 1em;"><img alt="" data-original-height="1458" data-original-width="2592" height="180" src="https://blogger.googleusercontent.com/img/a/AVvXsEj6CmCozsdYepG69rxNpCWBhsOc60wU_AIOhSmLtOq8oo--Koiy9WJsIez5XsQmWxo5OwcmpNLjiOE4PWIh4Qdzaanz7O6OUFHJzsaLGziICyKYi4dt7BM_bPDz9UH8IqfGIYqfydj1VJkb5KXqMGLh8thIvlNUqZyH6mXqREx2T7gNxFhqyIiLcXF2XHFO" width="320" /></a></div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: left;">The SIM card has no markings besides the standard identification data on the reverse side. I didn't take a picture of that in case it still worked -- but of course it doesn't still work. ;)</div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: left;"><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEhmib3nHuEx1DAv6hovy_LmgEbZL5_ein-beb-iqAPhoVhvWLlCHMNI9csNkJiW3bkRx-5By-VsZ10FWobK49PVCrGc0sMEwCcgfrF_bRtESx-7XZs37Hgvp5CAYQ3GxvQIvGMqW-VdZdOxcWWkXfuuIM0wM_ifla4y3mF-9L0T0-1a2DfMHGYJeWZNZkVy" style="margin-left: 1em; margin-right: 1em;"><img alt="" data-original-height="1836" data-original-width="3264" height="180" src="https://blogger.googleusercontent.com/img/a/AVvXsEhmib3nHuEx1DAv6hovy_LmgEbZL5_ein-beb-iqAPhoVhvWLlCHMNI9csNkJiW3bkRx-5By-VsZ10FWobK49PVCrGc0sMEwCcgfrF_bRtESx-7XZs37Hgvp5CAYQ3GxvQIvGMqW-VdZdOxcWWkXfuuIM0wM_ifla4y3mF-9L0T0-1a2DfMHGYJeWZNZkVy" width="320" /></a></div><div class="separator" style="clear: both; text-align: left;"><br /></div>The USB port was interesting so I decided to power it up and see if it spoke to me as anything. It didn't take power from the USB port, so I ran 3.6v across the battery terminals, which happily didn't explode. The LEDs began blinking as the lid suggested they might.</div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: left;"><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEhWtUeu7cLNGrS3qcGD98WOo9yYE-ypSeDe5IQHhc_b2XaWjdztQrwvIylENGDr1gRJfpnntIg8cSvWb2bDMvWCWmN2W7GI93riim_zOwZ0-gmK8xQUZzZeLkazApHtglnJpScAwMXZa1CzuERYROJdnChwsNMbGMzol9PknL613NufAEnZsfixb7asl9n0" style="margin-left: 1em; margin-right: 1em;"><img alt="" data-original-height="3264" data-original-width="1836" height="240" src="https://blogger.googleusercontent.com/img/a/AVvXsEhWtUeu7cLNGrS3qcGD98WOo9yYE-ypSeDe5IQHhc_b2XaWjdztQrwvIylENGDr1gRJfpnntIg8cSvWb2bDMvWCWmN2W7GI93riim_zOwZ0-gmK8xQUZzZeLkazApHtglnJpScAwMXZa1CzuERYROJdnChwsNMbGMzol9PknL613NufAEnZsfixb7asl9n0" width="135" /></a></div><br />Windows didn't know what to make of it, but gave me the VID/PID 0E8D/0003, which mapped down to a MediaTek MT6227 phone. I couldn't find a lot of information about this unit, but I did see it was supported under Linux. https://linux-hardware.org/index.php?id=usb:0e8d-0003</div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: left;"><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEgySHEKWrFgxIuuSXkrrXOzi7gjE_X22M8QHr0AT6fUYwVXB1pjdm_9uX79gNwPcqGl4Qs-CBxksQLSR-mnw8SGfFSs_BXWPcLNNdvwrkNmF4atSCNjMzmL048FMjqGLEexFcaMJ9AxfxqxGzIpUsIIy0J_qoZarPlFUx0Kp2l1ajBDdPDYzRTt9oZmEcAl" style="margin-left: 1em; margin-right: 1em;"><img alt="" data-original-height="1836" data-original-width="3264" height="180" src="https://blogger.googleusercontent.com/img/a/AVvXsEgySHEKWrFgxIuuSXkrrXOzi7gjE_X22M8QHr0AT6fUYwVXB1pjdm_9uX79gNwPcqGl4Qs-CBxksQLSR-mnw8SGfFSs_BXWPcLNNdvwrkNmF4atSCNjMzmL048FMjqGLEexFcaMJ9AxfxqxGzIpUsIIy0J_qoZarPlFUx0Kp2l1ajBDdPDYzRTt9oZmEcAl" width="320" /></a></div><div class="separator" style="clear: both; text-align: center;"><br /></div><div class="separator" style="clear: both; text-align: left;">So I booted up Minicom to have a look at it, and yeah, it talks like a GSM modem! </div><div class="separator" style="clear: both; text-align: left;"><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEiUBqcX3Gvo79Sjr3VQmf-VdI3M824QqfeBRxrte5EtZrxCDqthJv0GUbWMXGdSJEIQ5M0ZivClWl1Kyj1thDNMmgNUpGWDJjxiwgQlq8KbSJWjhid6mohqqSu12J8PocQOo_3VMunqqZfI69E3EmCn4BL118f0R-ZDM4UnKfRtNscb1rhvOiFaQpsuac6i" style="margin-left: 1em; margin-right: 1em;"><img alt="" data-original-height="1458" data-original-width="2592" height="180" src="https://blogger.googleusercontent.com/img/a/AVvXsEiUBqcX3Gvo79Sjr3VQmf-VdI3M824QqfeBRxrte5EtZrxCDqthJv0GUbWMXGdSJEIQ5M0ZivClWl1Kyj1thDNMmgNUpGWDJjxiwgQlq8KbSJWjhid6mohqqSu12J8PocQOo_3VMunqqZfI69E3EmCn4BL118f0R-ZDM4UnKfRtNscb1rhvOiFaQpsuac6i" width="320" /></a></div><br /></div><div class="separator" style="clear: both; text-align: left;">The MCU is also trying to initialize the connection, but since there wasn't one, it didn't seem to get very far.</div><div class="separator" style="clear: both; text-align: left;"><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEiJHnfQc2UAs7Xrvrkl6osRoz_fCWXS3kWaEC3mz25QLZwsa4cql0idRZHeo04rfdcwsb-8AWRIYY-V6oYr4CHmO8_Bd1_kUZM9O3VO_l5piMehJAgt6ST-WAZkHHIJPnyizCFFEgvawuzqZkm81n9fUVon2tCKQy-eqlhgh5le1qHYju23YrsR4RW-p2Kf" style="margin-left: 1em; margin-right: 1em;"><img alt="" data-original-height="1458" data-original-width="2592" height="180" src="https://blogger.googleusercontent.com/img/a/AVvXsEiJHnfQc2UAs7Xrvrkl6osRoz_fCWXS3kWaEC3mz25QLZwsa4cql0idRZHeo04rfdcwsb-8AWRIYY-V6oYr4CHmO8_Bd1_kUZM9O3VO_l5piMehJAgt6ST-WAZkHHIJPnyizCFFEgvawuzqZkm81n9fUVon2tCKQy-eqlhgh5le1qHYju23YrsR4RW-p2Kf" width="320" /></a></div><div class="separator" style="clear: both; text-align: center;"><br /></div><div class="separator" style="clear: both; text-align: left;">I did try putting my T-Mobile SIM in, and seemed like it may have initialized it, eventually stopping on an ATH instead of the repeated AT%IPSYS? above, but I didn't catch it going further. (I didn't leave it on long, perhaps it was trying to acquire satellites.)</div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: left;"><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEh2IOq-rqUdwlggYdUUMmI_SYq0ILZygnY52s_MJTycj7rXcvFfejoMMF9RW_0DOg4tf171MrDLA93YgePbqB4pmuwzgyaP6I4t2f0X0i2MvoAUm0g7j4XNE4DT6hXE8d_XdU4duwv6mfqleiud8Px3VLwAt37EL7uPDZ65MIkT0vbfETeZOqfLrp-P9WTx" style="margin-left: 1em; margin-right: 1em;"><img alt="" data-original-height="2592" data-original-width="1458" height="240" src="https://blogger.googleusercontent.com/img/a/AVvXsEh2IOq-rqUdwlggYdUUMmI_SYq0ILZygnY52s_MJTycj7rXcvFfejoMMF9RW_0DOg4tf171MrDLA93YgePbqB4pmuwzgyaP6I4t2f0X0i2MvoAUm0g7j4XNE4DT6hXE8d_XdU4duwv6mfqleiud8Px3VLwAt37EL7uPDZ65MIkT0vbfETeZOqfLrp-P9WTx" width="135" /></a></div><div class="separator" style="clear: both; text-align: center;"><br /></div><div class="separator" style="clear: both; text-align: left;">The MCU would appear to be over here, labelled SBK TI 571 AKY1. Couldn't find much, though there is a CH571 based on RISC-V. I think it has the right number of pins... This page has the 573/571 datasheet: https://www.aliexpress.com/item/1005005805175647.html - if that's it, it has 256k of flash, 18k of RAM, and a ton of onboard peripheral support at 20MHz.</div><br />I didn't go any further with it, but I was surprised to see at least as recently as 2020 people were still being sold these systems. The unit was dropped randomly all over the car - one person found it in their glove box! And cellular modems aren't really expensive anymore, so I'm not sure how useful this may be. But, if you wanted to use such a thing, you could try disabling the MCU to just have a USB modem (possibly), or even potentially try to reprogram it.</div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: left;">Other things I should have done but didn't - remove the the shields to verify what's under them, and see what the RX/TX pads under the SIM card are for. ;)</div><div class="separator" style="clear: both; text-align: left;"><br /></div><br /><br /></div><br /><br /></div><div class="separator" style="clear: both; text-align: center;"><br /></div><br /><br /></div><br /><br /><p></p><br /><p></p>Tursilionhttp://www.blogger.com/profile/16478174231304644316noreply@blogger.com1tag:blogger.com,1999:blog-7717886351507761714.post-89238079621893654472024-02-13T20:13:00.000-08:002024-02-15T10:39:12.071-08:00AI Code Gen<p>blah blah blah you've heard all about AI. Let's walk through a quick example of trying to get ChatGPT to generate some TMS9900 assembly code for us. This is a difficult challenge for it - it doesn't have a lot of examples to draw from.</p><p>My ChatGPT instance is set up to talk to me as Skeletor. So, just be warned about that. My text will be <span style="color: #2b00fe;">blue</span>, replies will be <span style="color: red;">red</span>, and code I will have to figure out if Blogger has a format option... whatever.</p><p><span face="Söhne, ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, Ubuntu, Cantarell, "Noto Sans", sans-serif, "Helvetica Neue", Arial, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"" style="background-color: white; font-size: 16px; white-space-collapse: preserve;"><span style="color: #2b00fe;">Hello evil one! Today we are going to work together to create a program in TMS9900 assembly language that bounces a ball on the screen of a TI-99/4A.</span></span></p><p style="--tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-ring-color: rgba(69,89,164,.5); --tw-ring-offset-color: #fff; --tw-ring-offset-shadow: 0 0 transparent; --tw-ring-offset-width: 0px; --tw-ring-shadow: 0 0 transparent; --tw-rotate: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-scroll-snap-strictness: proximity; --tw-shadow-colored: 0 0 transparent; --tw-shadow: 0 0 transparent; --tw-skew-x: 0; --tw-skew-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; background-color: white; border: 0px solid rgb(227, 227, 227); box-sizing: border-box; font-family: Söhne, ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, Ubuntu, Cantarell, "Noto Sans", sans-serif, "Helvetica Neue", Arial, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; font-size: 16px; margin: 0px 0px 1.25em; white-space-collapse: preserve;"><span style="color: red;">Ah, a worthy endeavor for our combined might, you puny mortal! The TI-99/4A, with its TMS9900 microprocessor, presents an interesting challenge for our dark purposes. We shall bend it to our will and make it display a bouncing ball upon its screen. Let us proceed with this nefarious plan step by step, weaving the dark magic of assembly language to bring our creation to life.</span></p><p style="--tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-ring-color: rgba(69,89,164,.5); --tw-ring-offset-color: #fff; --tw-ring-offset-shadow: 0 0 transparent; --tw-ring-offset-width: 0px; --tw-ring-shadow: 0 0 transparent; --tw-rotate: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-scroll-snap-strictness: proximity; --tw-shadow-colored: 0 0 transparent; --tw-shadow: 0 0 transparent; --tw-skew-x: 0; --tw-skew-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; background-color: white; border: 0px solid rgb(227, 227, 227); box-sizing: border-box; font-family: Söhne, ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, Ubuntu, Cantarell, "Noto Sans", sans-serif, "Helvetica Neue", Arial, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; font-size: 16px; margin: 1.25em 0px; white-space-collapse: preserve;"><span style="color: red;">First, we must understand that to create a bouncing ball, we need to manipulate the graphics or character patterns directly, since the TI-99/4A allows for such manipulation through its Video Display Processor (VDP). The essence of our dark spell will involve:</span></p><ol style="--tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-ring-color: rgba(69,89,164,.5); --tw-ring-offset-color: #fff; --tw-ring-offset-shadow: 0 0 transparent; --tw-ring-offset-width: 0px; --tw-ring-shadow: 0 0 transparent; --tw-rotate: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-scroll-snap-strictness: proximity; --tw-shadow-colored: 0 0 transparent; --tw-shadow: 0 0 transparent; --tw-skew-x: 0; --tw-skew-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; background-color: white; border: 0px solid rgb(227, 227, 227); box-sizing: border-box; counter-reset: list-number 0; display: flex; flex-direction: column; font-family: Söhne, ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, Ubuntu, Cantarell, "Noto Sans", sans-serif, "Helvetica Neue", Arial, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; font-size: 16px; list-style: none; margin: 1.25em 0px; padding: 0px; white-space-collapse: preserve;"><li style="--tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-ring-color: rgba(69,89,164,.5); --tw-ring-offset-color: #fff; --tw-ring-offset-shadow: 0 0 transparent; --tw-ring-offset-width: 0px; --tw-ring-shadow: 0 0 transparent; --tw-rotate: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-scroll-snap-strictness: proximity; --tw-shadow-colored: 0 0 transparent; --tw-shadow: 0 0 transparent; --tw-skew-x: 0; --tw-skew-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; border: 0px solid rgb(227, 227, 227); box-sizing: border-box; counter-increment: list-number 1; display: block; margin-bottom: 0px; margin-top: 0px; min-height: 28px; padding-left: 0.375em;"><span style="color: red;"><span style="--tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-ring-color: rgba(69,89,164,.5); --tw-ring-offset-color: #fff; --tw-ring-offset-shadow: 0 0 transparent; --tw-ring-offset-width: 0px; --tw-ring-shadow: 0 0 transparent; --tw-rotate: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-scroll-snap-strictness: proximity; --tw-shadow-colored: 0 0 transparent; --tw-shadow: 0 0 transparent; --tw-skew-x: 0; --tw-skew-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; border: 0px solid rgb(227, 227, 227); box-sizing: border-box; font-weight: 600; margin-bottom: 1.25em; margin-top: 1.25em;">Setting up the screen</span>: Prepare the graphics mode that we intend to use.</span></li><li style="--tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-ring-color: rgba(69,89,164,.5); --tw-ring-offset-color: #fff; --tw-ring-offset-shadow: 0 0 transparent; --tw-ring-offset-width: 0px; --tw-ring-shadow: 0 0 transparent; --tw-rotate: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-scroll-snap-strictness: proximity; --tw-shadow-colored: 0 0 transparent; --tw-shadow: 0 0 transparent; --tw-skew-x: 0; --tw-skew-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; border: 0px solid rgb(227, 227, 227); box-sizing: border-box; counter-increment: list-number 1; display: block; margin-bottom: 0px; margin-top: 0px; min-height: 28px; padding-left: 0.375em;"><span style="color: red;"><span style="--tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-ring-color: rgba(69,89,164,.5); --tw-ring-offset-color: #fff; --tw-ring-offset-shadow: 0 0 transparent; --tw-ring-offset-width: 0px; --tw-ring-shadow: 0 0 transparent; --tw-rotate: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-scroll-snap-strictness: proximity; --tw-shadow-colored: 0 0 transparent; --tw-shadow: 0 0 transparent; --tw-skew-x: 0; --tw-skew-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; border: 0px solid rgb(227, 227, 227); box-sizing: border-box; font-weight: 600; margin-bottom: 1.25em; margin-top: 1.25em;">Drawing the ball</span>: Define a character or a set of characters that will represent our ball.</span></li><li style="--tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-ring-color: rgba(69,89,164,.5); --tw-ring-offset-color: #fff; --tw-ring-offset-shadow: 0 0 transparent; --tw-ring-offset-width: 0px; --tw-ring-shadow: 0 0 transparent; --tw-rotate: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-scroll-snap-strictness: proximity; --tw-shadow-colored: 0 0 transparent; --tw-shadow: 0 0 transparent; --tw-skew-x: 0; --tw-skew-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; border: 0px solid rgb(227, 227, 227); box-sizing: border-box; counter-increment: list-number 1; display: block; margin-bottom: 0px; margin-top: 0px; min-height: 28px; padding-left: 0.375em;"><span style="color: red;"><span style="--tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-ring-color: rgba(69,89,164,.5); --tw-ring-offset-color: #fff; --tw-ring-offset-shadow: 0 0 transparent; --tw-ring-offset-width: 0px; --tw-ring-shadow: 0 0 transparent; --tw-rotate: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-scroll-snap-strictness: proximity; --tw-shadow-colored: 0 0 transparent; --tw-shadow: 0 0 transparent; --tw-skew-x: 0; --tw-skew-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; border: 0px solid rgb(227, 227, 227); box-sizing: border-box; font-weight: 600; margin-bottom: 1.25em; margin-top: 1.25em;">Movement</span>: Calculate the ball's position on the screen, updating its location to simulate bouncing off the screen edges.</span></li><li style="--tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-ring-color: rgba(69,89,164,.5); --tw-ring-offset-color: #fff; --tw-ring-offset-shadow: 0 0 transparent; --tw-ring-offset-width: 0px; --tw-ring-shadow: 0 0 transparent; --tw-rotate: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-scroll-snap-strictness: proximity; --tw-shadow-colored: 0 0 transparent; --tw-shadow: 0 0 transparent; --tw-skew-x: 0; --tw-skew-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; border: 0px solid rgb(227, 227, 227); box-sizing: border-box; counter-increment: list-number 1; display: block; margin-bottom: 0px; margin-top: 0px; min-height: 28px; padding-left: 0.375em;"><span style="color: red;"><span style="--tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-ring-color: rgba(69,89,164,.5); --tw-ring-offset-color: #fff; --tw-ring-offset-shadow: 0 0 transparent; --tw-ring-offset-width: 0px; --tw-ring-shadow: 0 0 transparent; --tw-rotate: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-scroll-snap-strictness: proximity; --tw-shadow-colored: 0 0 transparent; --tw-shadow: 0 0 transparent; --tw-skew-x: 0; --tw-skew-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; border: 0px solid rgb(227, 227, 227); box-sizing: border-box; font-weight: 600; margin-bottom: 1.25em; margin-top: 1.25em;">Looping and Delay</span>: Implement a loop to continuously update the screen, along with a delay to make the movement visible to human eyes.</span></li></ol><p style="--tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-ring-color: rgba(69,89,164,.5); --tw-ring-offset-color: #fff; --tw-ring-offset-shadow: 0 0 transparent; --tw-ring-offset-width: 0px; --tw-ring-shadow: 0 0 transparent; --tw-rotate: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-scroll-snap-strictness: proximity; --tw-shadow-colored: 0 0 transparent; --tw-shadow: 0 0 transparent; --tw-skew-x: 0; --tw-skew-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; background-color: white; border: 0px solid rgb(227, 227, 227); box-sizing: border-box; font-family: Söhne, ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, Ubuntu, Cantarell, "Noto Sans", sans-serif, "Helvetica Neue", Arial, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; font-size: 16px; margin: 1.25em 0px; white-space-collapse: preserve;"><span style="color: red;">Given the complexities of TMS9900 assembly language and the limited space for incantations here, I shall provide you with a skeletal framework. You will need to flesh it out with your own dark powers (and possibly consult the TI-99/4A manual for specific details like VDP memory addresses and character pattern definitions).</span></p><p><span face=""Söhne Mono", Monaco, "Andale Mono", "Ubuntu Mono", monospace" style="background-color: #f3f3f3; font-size: 14px; white-space: pre;">* Setting up the screen
LI R0, >02 * Load immediate VDP register number for setting graphics mode
LI R1, >XXXX * Load immediate value for graphics mode
* Drawing the ball at initial position
LI R2, >YYYY * Load immediate address for character pattern in VDP RAM
LI R3, >ZZZZ * Load immediate character pattern for the ball
* Main loop for movement
LOOP:
* Calculate new position
* Check for screen boundaries
* Update position in VDP RAM
* Delay
JMP LOOP * Jump back to the start of the loop
END</span></p><p style="--tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-ring-color: rgba(69,89,164,.5); --tw-ring-offset-color: #fff; --tw-ring-offset-shadow: 0 0 transparent; --tw-ring-offset-width: 0px; --tw-ring-shadow: 0 0 transparent; --tw-rotate: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-scroll-snap-strictness: proximity; --tw-shadow-colored: 0 0 transparent; --tw-shadow: 0 0 transparent; --tw-skew-x: 0; --tw-skew-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; background-color: white; border: 0px solid rgb(227, 227, 227); box-sizing: border-box; font-family: Söhne, ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, Ubuntu, Cantarell, "Noto Sans", sans-serif, "Helvetica Neue", Arial, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; font-size: 16px; margin: 1.25em 0px; white-space-collapse: preserve;"><span style="color: red;">Ah, but heed this well, you aspiring dark wizard of code: the actual implementation details, like the values to load for setting up the screen mode (<code style="--tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-ring-color: rgba(69,89,164,.5); --tw-ring-offset-color: #fff; --tw-ring-offset-shadow: 0 0 transparent; --tw-ring-offset-width: 0px; --tw-ring-shadow: 0 0 transparent; --tw-rotate: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-scroll-snap-strictness: proximity; --tw-shadow-colored: 0 0 transparent; --tw-shadow: 0 0 transparent; --tw-skew-x: 0; --tw-skew-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; border: 0px solid rgb(227, 227, 227); box-sizing: border-box; font-family: "Söhne Mono", Monaco, "Andale Mono", "Ubuntu Mono", monospace; font-size: 0.875em; font-weight: 600;">XXXX</code>), the address for the character pattern (<code style="--tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-ring-color: rgba(69,89,164,.5); --tw-ring-offset-color: #fff; --tw-ring-offset-shadow: 0 0 transparent; --tw-ring-offset-width: 0px; --tw-ring-shadow: 0 0 transparent; --tw-rotate: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-scroll-snap-strictness: proximity; --tw-shadow-colored: 0 0 transparent; --tw-shadow: 0 0 transparent; --tw-skew-x: 0; --tw-skew-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; border: 0px solid rgb(227, 227, 227); box-sizing: border-box; font-family: "Söhne Mono", Monaco, "Andale Mono", "Ubuntu Mono", monospace; font-size: 0.875em; font-weight: 600;">YYYY</code>), and the pattern itself (<code style="--tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-ring-color: rgba(69,89,164,.5); --tw-ring-offset-color: #fff; --tw-ring-offset-shadow: 0 0 transparent; --tw-ring-offset-width: 0px; --tw-ring-shadow: 0 0 transparent; --tw-rotate: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-scroll-snap-strictness: proximity; --tw-shadow-colored: 0 0 transparent; --tw-shadow: 0 0 transparent; --tw-skew-x: 0; --tw-skew-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; border: 0px solid rgb(227, 227, 227); box-sizing: border-box; font-family: "Söhne Mono", Monaco, "Andale Mono", "Ubuntu Mono", monospace; font-size: 0.875em; font-weight: 600;">ZZZZ</code>), will require consulting the tome of knowledge for the TI-99/4A. The VDP memory manipulation commands (like <code style="--tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-ring-color: rgba(69,89,164,.5); --tw-ring-offset-color: #fff; --tw-ring-offset-shadow: 0 0 transparent; --tw-ring-offset-width: 0px; --tw-ring-shadow: 0 0 transparent; --tw-rotate: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-scroll-snap-strictness: proximity; --tw-shadow-colored: 0 0 transparent; --tw-shadow: 0 0 transparent; --tw-skew-x: 0; --tw-skew-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; border: 0px solid rgb(227, 227, 227); box-sizing: border-box; font-family: "Söhne Mono", Monaco, "Andale Mono", "Ubuntu Mono", monospace; font-size: 0.875em; font-weight: 600;">VMBW</code> for writing to VDP memory) and the exact mechanics of screen update will test the limits of your dark sorcery.</span></p><p style="--tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-ring-color: rgba(69,89,164,.5); --tw-ring-offset-color: #fff; --tw-ring-offset-shadow: 0 0 transparent; --tw-ring-offset-width: 0px; --tw-ring-shadow: 0 0 transparent; --tw-rotate: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-scroll-snap-strictness: proximity; --tw-shadow-colored: 0 0 transparent; --tw-shadow: 0 0 transparent; --tw-skew-x: 0; --tw-skew-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; background-color: white; border: 0px solid rgb(227, 227, 227); box-sizing: border-box; font-family: Söhne, ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, Ubuntu, Cantarell, "Noto Sans", sans-serif, "Helvetica Neue", Arial, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; font-size: 16px; margin: 1.25em 0px; white-space-collapse: preserve;"><span style="color: red;">To implement the delay, you might use a simple loop that wastes time, or for a more sophisticated approach, delve into the TI-99/4A's interrupt system to create a timing-based delay, though this requires deeper knowledge of the system's dark heart.</span></p><p style="--tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-ring-color: rgba(69,89,164,.5); --tw-ring-offset-color: #fff; --tw-ring-offset-shadow: 0 0 transparent; --tw-ring-offset-width: 0px; --tw-ring-shadow: 0 0 transparent; --tw-rotate: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-scroll-snap-strictness: proximity; --tw-shadow-colored: 0 0 transparent; --tw-shadow: 0 0 transparent; --tw-skew-x: 0; --tw-skew-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; background-color: white; border: 0px solid rgb(227, 227, 227); box-sizing: border-box; font-family: Söhne, ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, Ubuntu, Cantarell, "Noto Sans", sans-serif, "Helvetica Neue", Arial, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; font-size: 16px; margin: 1.25em 0px 0px; white-space-collapse: preserve;"><span style="color: red;">Now go forth, and bring our vision to life! Let the TI-99/4A tremble at our combined might! Mwahahaha!</span></p><p style="--tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-ring-color: rgba(69,89,164,.5); --tw-ring-offset-color: #fff; --tw-ring-offset-shadow: 0 0 transparent; --tw-ring-offset-width: 0px; --tw-ring-shadow: 0 0 transparent; --tw-rotate: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-scroll-snap-strictness: proximity; --tw-shadow-colored: 0 0 transparent; --tw-shadow: 0 0 transparent; --tw-skew-x: 0; --tw-skew-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; background-color: white; border: 0px solid rgb(227, 227, 227); box-sizing: border-box; font-family: Söhne, ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, Ubuntu, Cantarell, "Noto Sans", sans-serif, "Helvetica Neue", Arial, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; font-size: 16px; margin: 1.25em 0px 0px; white-space-collapse: preserve;">Okay, well, that's a bit of a cop-out. But it's right in that organizing the code into blocks is the first step. But the code doesn't do anything but load a few registers, and frankly most of that is junk anyway. So let's educate it a little bit and try to get the screen clear done (we don't need to set a graphics mode on the TI.)</p><p style="--tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-ring-color: rgba(69,89,164,.5); --tw-ring-offset-color: #fff; --tw-ring-offset-shadow: 0 0 transparent; --tw-ring-offset-width: 0px; --tw-ring-shadow: 0 0 transparent; --tw-rotate: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-scroll-snap-strictness: proximity; --tw-shadow-colored: 0 0 transparent; --tw-shadow: 0 0 transparent; --tw-skew-x: 0; --tw-skew-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; background-color: white; border: 0px solid rgb(227, 227, 227); box-sizing: border-box; font-family: Söhne, ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, Ubuntu, Cantarell, "Noto Sans", sans-serif, "Helvetica Neue", Arial, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; font-size: 16px; margin: 1.25em 0px 0px; white-space-collapse: preserve;"><span style="color: #2b00fe;">Let's drill down deeper. Let's start with the screen setup. Since the screen mode is already set for us by the OS, all we need to do is clear the screen. You will need some information - the VDP memory is accessed as a memory mapped device. The screen starts at address 0 which is convenient. To clear the screen, we need to write the two bytes of address 0 to >8C02, then we can write the ASCII space character to >8C00. We will need to write 32 times 24 times to clear the entire display. Generate this method.</span></p><p style="--tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-ring-color: rgba(69,89,164,.5); --tw-ring-offset-color: #fff; --tw-ring-offset-shadow: 0 0 transparent; --tw-ring-offset-width: 0px; --tw-ring-shadow: 0 0 transparent; --tw-rotate: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-scroll-snap-strictness: proximity; --tw-shadow-colored: 0 0 transparent; --tw-shadow: 0 0 transparent; --tw-skew-x: 0; --tw-skew-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; background-color: white; border: 0px solid rgb(227, 227, 227); box-sizing: border-box; font-family: Söhne, ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, Ubuntu, Cantarell, "Noto Sans", sans-serif, "Helvetica Neue", Arial, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; font-size: 16px; margin: 1.25em 0px 0px; white-space-collapse: preserve;">Note here that I didn't explicitly tell it several things. For instance, I gave it the screen dimensions, but not the total number of bytes. I also didn't tell it that the TI uses '>' as a hexadecimal prefix (but, the previous code infers it knew that.)</p><p style="--tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-ring-color: rgba(69,89,164,.5); --tw-ring-offset-color: #fff; --tw-ring-offset-shadow: 0 0 transparent; --tw-ring-offset-width: 0px; --tw-ring-shadow: 0 0 transparent; --tw-rotate: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-scroll-snap-strictness: proximity; --tw-shadow-colored: 0 0 transparent; --tw-shadow: 0 0 transparent; --tw-skew-x: 0; --tw-skew-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; background-color: white; border: 0px solid rgb(227, 227, 227); box-sizing: border-box; font-family: Söhne, ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, Ubuntu, Cantarell, "Noto Sans", sans-serif, "Helvetica Neue", Arial, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; font-size: 16px; margin: 1.25em 0px 0px; white-space-collapse: preserve;"><span style="color: red;">Ah, focusing on the task of clearing the screen, are we? Very well, let us dive into the abyss of assembly to command the TI-99/4A to bend to our will.</span></p><p style="--tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-ring-color: rgba(69,89,164,.5); --tw-ring-offset-color: #fff; --tw-ring-offset-shadow: 0 0 transparent; --tw-ring-offset-width: 0px; --tw-ring-shadow: 0 0 transparent; --tw-rotate: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-scroll-snap-strictness: proximity; --tw-shadow-colored: 0 0 transparent; --tw-shadow: 0 0 transparent; --tw-skew-x: 0; --tw-skew-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; background-color: white; border: 0px solid rgb(227, 227, 227); box-sizing: border-box; font-family: Söhne, ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, Ubuntu, Cantarell, "Noto Sans", sans-serif, "Helvetica Neue", Arial, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; font-size: 16px; margin: 1.25em 0px; white-space-collapse: preserve;"><span style="color: red;">To clear the screen by filling it with spaces, we must repeatedly write the ASCII space character (which is >20 in hexadecimal) to the entire display area, which consists of 32 columns and 24 rows. Since you've enlightened me about the method of accessing VDP memory, let's proceed with crafting the spell in TMS9900 assembly.</span></p><p style="--tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-ring-color: rgba(69,89,164,.5); --tw-ring-offset-color: #fff; --tw-ring-offset-shadow: 0 0 transparent; --tw-ring-offset-width: 0px; --tw-ring-shadow: 0 0 transparent; --tw-rotate: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-scroll-snap-strictness: proximity; --tw-shadow-colored: 0 0 transparent; --tw-shadow: 0 0 transparent; --tw-skew-x: 0; --tw-skew-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; background-color: white; border: 0px solid rgb(227, 227, 227); box-sizing: border-box; font-family: Söhne, ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, Ubuntu, Cantarell, "Noto Sans", sans-serif, "Helvetica Neue", Arial, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; font-size: 16px; margin: 1.25em 0px; white-space-collapse: preserve;"><span style="color: red;">We'll use the VDP write address >8C02 to set the address pointer, starting at 0, and then repeatedly write >20 to >8C00 to fill the screen with spaces. Here's how you can do it:</span></p><p style="--tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-ring-color: rgba(69,89,164,.5); --tw-ring-offset-color: #fff; --tw-ring-offset-shadow: 0 0 transparent; --tw-ring-offset-width: 0px; --tw-ring-shadow: 0 0 transparent; --tw-rotate: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-scroll-snap-strictness: proximity; --tw-shadow-colored: 0 0 transparent; --tw-shadow: 0 0 transparent; --tw-skew-x: 0; --tw-skew-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; border: 0px solid rgb(227, 227, 227); box-sizing: border-box; font-family: Söhne, ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, Ubuntu, Cantarell, "Noto Sans", sans-serif, "Helvetica Neue", Arial, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; font-size: 16px; margin: 1.25em 0px; white-space-collapse: preserve;"><span face=""Söhne Mono", Monaco, "Andale Mono", "Ubuntu Mono", monospace" style="background-color: #f3f3f3; font-size: 14px; text-wrap: nowrap;"> LI R0, >0000 * Load the initial screen address into R0
LI R1, >8C02 * Load the VDP write address register
LI R2, >2000 * Load the ASCII space character (>20) and the repeat count (32*24 = 768 = >0300)
CLEAR: MOV R0, R3 * Move the current address to R3 for manipulation
SWPB R3 * Swap bytes to get the address in the right format for VDP
MOVB R3, *R1 * Write the high byte of the address to the VDP write address register
AI R3, >4000 * Adjust R3 to correctly position the low byte of the address
MOVB R3, *R1 * Write the low byte of the address to the VDP write address register
LI R3, >8C00 * Load the VDP data write address
MOVB R2, *R3 * Write the space character to the VDP data register
AI R0, 1 * Increment the screen address
CI R0, >0300 * Compare current address to the end of the screen area
JNE CLEAR * If not at the end, jump back to CLEAR
RT * Return from subroutine</span></p><p style="--tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-ring-color: rgba(69,89,164,.5); --tw-ring-offset-color: #fff; --tw-ring-offset-shadow: 0 0 transparent; --tw-ring-offset-width: 0px; --tw-ring-shadow: 0 0 transparent; --tw-rotate: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-scroll-snap-strictness: proximity; --tw-shadow-colored: 0 0 transparent; --tw-shadow: 0 0 transparent; --tw-skew-x: 0; --tw-skew-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; background-color: white; border: 0px solid rgb(227, 227, 227); box-sizing: border-box; font-family: Söhne, ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, Ubuntu, Cantarell, "Noto Sans", sans-serif, "Helvetica Neue", Arial, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; font-size: 16px; margin: 1.25em 0px; white-space-collapse: preserve;"><span style="color: red;">This code starts by initializing the registers:</span></p><ul style="--tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-ring-color: rgba(69,89,164,.5); --tw-ring-offset-color: #fff; --tw-ring-offset-shadow: 0 0 transparent; --tw-ring-offset-width: 0px; --tw-ring-shadow: 0 0 transparent; --tw-rotate: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-scroll-snap-strictness: proximity; --tw-shadow-colored: 0 0 transparent; --tw-shadow: 0 0 transparent; --tw-skew-x: 0; --tw-skew-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; background-color: white; border: 0px solid rgb(227, 227, 227); box-sizing: border-box; display: flex; flex-direction: column; font-family: Söhne, ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, Ubuntu, Cantarell, "Noto Sans", sans-serif, "Helvetica Neue", Arial, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; font-size: 16px; list-style-image: initial; list-style-position: initial; margin: 1.25em 0px; padding: 0px; white-space-collapse: preserve;"><li style="--tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-ring-color: rgba(69,89,164,.5); --tw-ring-offset-color: #fff; --tw-ring-offset-shadow: 0 0 transparent; --tw-ring-offset-width: 0px; --tw-ring-shadow: 0 0 transparent; --tw-rotate: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-scroll-snap-strictness: proximity; --tw-shadow-colored: 0 0 transparent; --tw-shadow: 0 0 transparent; --tw-skew-x: 0; --tw-skew-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; border: 0px solid rgb(227, 227, 227); box-sizing: border-box; display: block; margin: 0px; min-height: 28px; padding-left: 0.375em;"><span style="color: red;"><code style="--tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-ring-color: rgba(69,89,164,.5); --tw-ring-offset-color: #fff; --tw-ring-offset-shadow: 0 0 transparent; --tw-ring-offset-width: 0px; --tw-ring-shadow: 0 0 transparent; --tw-rotate: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-scroll-snap-strictness: proximity; --tw-shadow-colored: 0 0 transparent; --tw-shadow: 0 0 transparent; --tw-skew-x: 0; --tw-skew-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; border: 0px solid rgb(227, 227, 227); box-sizing: border-box; font-family: "Söhne Mono", Monaco, "Andale Mono", "Ubuntu Mono", monospace; font-size: 0.875em; font-weight: 600; margin-bottom: 1.25em; margin-top: 1.25em;">R0</code> holds the current address we're writing to in the screen memory, starting at 0.</span></li><li style="--tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-ring-color: rgba(69,89,164,.5); --tw-ring-offset-color: #fff; --tw-ring-offset-shadow: 0 0 transparent; --tw-ring-offset-width: 0px; --tw-ring-shadow: 0 0 transparent; --tw-rotate: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-scroll-snap-strictness: proximity; --tw-shadow-colored: 0 0 transparent; --tw-shadow: 0 0 transparent; --tw-skew-x: 0; --tw-skew-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; border: 0px solid rgb(227, 227, 227); box-sizing: border-box; display: block; margin: 0px; min-height: 28px; padding-left: 0.375em;"><span style="color: red;"><code style="--tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-ring-color: rgba(69,89,164,.5); --tw-ring-offset-color: #fff; --tw-ring-offset-shadow: 0 0 transparent; --tw-ring-offset-width: 0px; --tw-ring-shadow: 0 0 transparent; --tw-rotate: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-scroll-snap-strictness: proximity; --tw-shadow-colored: 0 0 transparent; --tw-shadow: 0 0 transparent; --tw-skew-x: 0; --tw-skew-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; border: 0px solid rgb(227, 227, 227); box-sizing: border-box; font-family: "Söhne Mono", Monaco, "Andale Mono", "Ubuntu Mono", monospace; font-size: 0.875em; font-weight: 600; margin-top: 1.25em;">R1</code> is set to the VDP write address (<code style="--tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-ring-color: rgba(69,89,164,.5); --tw-ring-offset-color: #fff; --tw-ring-offset-shadow: 0 0 transparent; --tw-ring-offset-width: 0px; --tw-ring-shadow: 0 0 transparent; --tw-rotate: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-scroll-snap-strictness: proximity; --tw-shadow-colored: 0 0 transparent; --tw-shadow: 0 0 transparent; --tw-skew-x: 0; --tw-skew-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; border: 0px solid rgb(227, 227, 227); box-sizing: border-box; font-family: "Söhne Mono", Monaco, "Andale Mono", "Ubuntu Mono", monospace; font-size: 0.875em; font-weight: 600; margin-bottom: 1.25em;">>8C02</code>), used to set where we're writing in the VDP memory.</span></li><li style="--tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-ring-color: rgba(69,89,164,.5); --tw-ring-offset-color: #fff; --tw-ring-offset-shadow: 0 0 transparent; --tw-ring-offset-width: 0px; --tw-ring-shadow: 0 0 transparent; --tw-rotate: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-scroll-snap-strictness: proximity; --tw-shadow-colored: 0 0 transparent; --tw-shadow: 0 0 transparent; --tw-skew-x: 0; --tw-skew-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; border: 0px solid rgb(227, 227, 227); box-sizing: border-box; display: block; margin: 0px; min-height: 28px; padding-left: 0.375em;"><span style="color: red;"><code style="--tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-ring-color: rgba(69,89,164,.5); --tw-ring-offset-color: #fff; --tw-ring-offset-shadow: 0 0 transparent; --tw-ring-offset-width: 0px; --tw-ring-shadow: 0 0 transparent; --tw-rotate: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-scroll-snap-strictness: proximity; --tw-shadow-colored: 0 0 transparent; --tw-shadow: 0 0 transparent; --tw-skew-x: 0; --tw-skew-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; border: 0px solid rgb(227, 227, 227); box-sizing: border-box; font-family: "Söhne Mono", Monaco, "Andale Mono", "Ubuntu Mono", monospace; font-size: 0.875em; font-weight: 600; margin-top: 1.25em;">R2</code> holds the ASCII value for a space (<code style="--tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-ring-color: rgba(69,89,164,.5); --tw-ring-offset-color: #fff; --tw-ring-offset-shadow: 0 0 transparent; --tw-ring-offset-width: 0px; --tw-ring-shadow: 0 0 transparent; --tw-rotate: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-scroll-snap-strictness: proximity; --tw-shadow-colored: 0 0 transparent; --tw-shadow: 0 0 transparent; --tw-skew-x: 0; --tw-skew-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; border: 0px solid rgb(227, 227, 227); box-sizing: border-box; font-family: "Söhne Mono", Monaco, "Andale Mono", "Ubuntu Mono", monospace; font-size: 0.875em; font-weight: 600; margin-bottom: 1.25em;">>20</code>) and the repeat flag set to >0000 as we will manually control the loop.</span></li></ul><p style="--tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-ring-color: rgba(69,89,164,.5); --tw-ring-offset-color: #fff; --tw-ring-offset-shadow: 0 0 transparent; --tw-ring-offset-width: 0px; --tw-ring-shadow: 0 0 transparent; --tw-rotate: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-scroll-snap-strictness: proximity; --tw-shadow-colored: 0 0 transparent; --tw-shadow: 0 0 transparent; --tw-skew-x: 0; --tw-skew-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; background-color: white; border: 0px solid rgb(227, 227, 227); box-sizing: border-box; font-family: Söhne, ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, Ubuntu, Cantarell, "Noto Sans", sans-serif, "Helvetica Neue", Arial, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; font-size: 16px; margin: 1.25em 0px; white-space-collapse: preserve;"><span style="color: red;">The loop labeled <code style="--tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-ring-color: rgba(69,89,164,.5); --tw-ring-offset-color: #fff; --tw-ring-offset-shadow: 0 0 transparent; --tw-ring-offset-width: 0px; --tw-ring-shadow: 0 0 transparent; --tw-rotate: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-scroll-snap-strictness: proximity; --tw-shadow-colored: 0 0 transparent; --tw-shadow: 0 0 transparent; --tw-skew-x: 0; --tw-skew-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; border: 0px solid rgb(227, 227, 227); box-sizing: border-box; font-family: "Söhne Mono", Monaco, "Andale Mono", "Ubuntu Mono", monospace; font-size: 0.875em; font-weight: 600;">CLEAR</code> does the following:</span></p><ul style="--tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-ring-color: rgba(69,89,164,.5); --tw-ring-offset-color: #fff; --tw-ring-offset-shadow: 0 0 transparent; --tw-ring-offset-width: 0px; --tw-ring-shadow: 0 0 transparent; --tw-rotate: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-scroll-snap-strictness: proximity; --tw-shadow-colored: 0 0 transparent; --tw-shadow: 0 0 transparent; --tw-skew-x: 0; --tw-skew-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; background-color: white; border: 0px solid rgb(227, 227, 227); box-sizing: border-box; display: flex; flex-direction: column; font-family: Söhne, ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, Ubuntu, Cantarell, "Noto Sans", sans-serif, "Helvetica Neue", Arial, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; font-size: 16px; list-style-image: initial; list-style-position: initial; margin: 1.25em 0px; padding: 0px; white-space-collapse: preserve;"><li style="--tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-ring-color: rgba(69,89,164,.5); --tw-ring-offset-color: #fff; --tw-ring-offset-shadow: 0 0 transparent; --tw-ring-offset-width: 0px; --tw-ring-shadow: 0 0 transparent; --tw-rotate: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-scroll-snap-strictness: proximity; --tw-shadow-colored: 0 0 transparent; --tw-shadow: 0 0 transparent; --tw-skew-x: 0; --tw-skew-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; border: 0px solid rgb(227, 227, 227); box-sizing: border-box; display: block; margin: 0px; min-height: 28px; padding-left: 0.375em;"><span style="color: red;">Moves the current address in <code style="--tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-ring-color: rgba(69,89,164,.5); --tw-ring-offset-color: #fff; --tw-ring-offset-shadow: 0 0 transparent; --tw-ring-offset-width: 0px; --tw-ring-shadow: 0 0 transparent; --tw-rotate: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-scroll-snap-strictness: proximity; --tw-shadow-colored: 0 0 transparent; --tw-shadow: 0 0 transparent; --tw-skew-x: 0; --tw-skew-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; border: 0px solid rgb(227, 227, 227); box-sizing: border-box; font-family: "Söhne Mono", Monaco, "Andale Mono", "Ubuntu Mono", monospace; font-size: 0.875em; font-weight: 600; margin-top: 1.25em;">R0</code> to <code style="--tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-ring-color: rgba(69,89,164,.5); --tw-ring-offset-color: #fff; --tw-ring-offset-shadow: 0 0 transparent; --tw-ring-offset-width: 0px; --tw-ring-shadow: 0 0 transparent; --tw-rotate: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-scroll-snap-strictness: proximity; --tw-shadow-colored: 0 0 transparent; --tw-shadow: 0 0 transparent; --tw-skew-x: 0; --tw-skew-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; border: 0px solid rgb(227, 227, 227); box-sizing: border-box; font-family: "Söhne Mono", Monaco, "Andale Mono", "Ubuntu Mono", monospace; font-size: 0.875em; font-weight: 600; margin-bottom: 1.25em;">R3</code> for manipulation.</span></li><li style="--tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-ring-color: rgba(69,89,164,.5); --tw-ring-offset-color: #fff; --tw-ring-offset-shadow: 0 0 transparent; --tw-ring-offset-width: 0px; --tw-ring-shadow: 0 0 transparent; --tw-rotate: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-scroll-snap-strictness: proximity; --tw-shadow-colored: 0 0 transparent; --tw-shadow: 0 0 transparent; --tw-skew-x: 0; --tw-skew-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; border: 0px solid rgb(227, 227, 227); box-sizing: border-box; display: block; margin: 0px; min-height: 28px; padding-left: 0.375em;"><span style="color: red;">Swaps the bytes of <code style="--tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-ring-color: rgba(69,89,164,.5); --tw-ring-offset-color: #fff; --tw-ring-offset-shadow: 0 0 transparent; --tw-ring-offset-width: 0px; --tw-ring-shadow: 0 0 transparent; --tw-rotate: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-scroll-snap-strictness: proximity; --tw-shadow-colored: 0 0 transparent; --tw-shadow: 0 0 transparent; --tw-skew-x: 0; --tw-skew-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; border: 0px solid rgb(227, 227, 227); box-sizing: border-box; font-family: "Söhne Mono", Monaco, "Andale Mono", "Ubuntu Mono", monospace; font-size: 0.875em; font-weight: 600; margin-bottom: 1.25em; margin-top: 1.25em;">R3</code> to match the VDP's addressing format.</span></li><li style="--tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-ring-color: rgba(69,89,164,.5); --tw-ring-offset-color: #fff; --tw-ring-offset-shadow: 0 0 transparent; --tw-ring-offset-width: 0px; --tw-ring-shadow: 0 0 transparent; --tw-rotate: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-scroll-snap-strictness: proximity; --tw-shadow-colored: 0 0 transparent; --tw-shadow: 0 0 transparent; --tw-skew-x: 0; --tw-skew-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; border: 0px solid rgb(227, 227, 227); box-sizing: border-box; display: block; margin: 0px; min-height: 28px; padding-left: 0.375em;"><span style="color: red;">Writes the high and then the low byte of the address to the VDP write address, effectively setting the VDP's address pointer.</span></li><li style="--tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-ring-color: rgba(69,89,164,.5); --tw-ring-offset-color: #fff; --tw-ring-offset-shadow: 0 0 transparent; --tw-ring-offset-width: 0px; --tw-ring-shadow: 0 0 transparent; --tw-rotate: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-scroll-snap-strictness: proximity; --tw-shadow-colored: 0 0 transparent; --tw-shadow: 0 0 transparent; --tw-skew-x: 0; --tw-skew-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; border: 0px solid rgb(227, 227, 227); box-sizing: border-box; display: block; margin: 0px; min-height: 28px; padding-left: 0.375em;"><span style="color: red;">Writes the space character to the VDP at the current address.</span></li><li style="--tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-ring-color: rgba(69,89,164,.5); --tw-ring-offset-color: #fff; --tw-ring-offset-shadow: 0 0 transparent; --tw-ring-offset-width: 0px; --tw-ring-shadow: 0 0 transparent; --tw-rotate: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-scroll-snap-strictness: proximity; --tw-shadow-colored: 0 0 transparent; --tw-shadow: 0 0 transparent; --tw-skew-x: 0; --tw-skew-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; border: 0px solid rgb(227, 227, 227); box-sizing: border-box; display: block; margin: 0px; min-height: 28px; padding-left: 0.375em;"><span style="color: red;">Increments the address in <code style="--tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-ring-color: rgba(69,89,164,.5); --tw-ring-offset-color: #fff; --tw-ring-offset-shadow: 0 0 transparent; --tw-ring-offset-width: 0px; --tw-ring-shadow: 0 0 transparent; --tw-rotate: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-scroll-snap-strictness: proximity; --tw-shadow-colored: 0 0 transparent; --tw-shadow: 0 0 transparent; --tw-skew-x: 0; --tw-skew-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; border: 0px solid rgb(227, 227, 227); box-sizing: border-box; font-family: "Söhne Mono", Monaco, "Andale Mono", "Ubuntu Mono", monospace; font-size: 0.875em; font-weight: 600; margin-bottom: 1.25em; margin-top: 1.25em;">R0</code> and checks if we've filled the entire screen. If not, it repeats.</span></li></ul><p style="--tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-ring-color: rgba(69,89,164,.5); --tw-ring-offset-color: #fff; --tw-ring-offset-shadow: 0 0 transparent; --tw-ring-offset-width: 0px; --tw-ring-shadow: 0 0 transparent; --tw-rotate: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-scroll-snap-strictness: proximity; --tw-shadow-colored: 0 0 transparent; --tw-shadow: 0 0 transparent; --tw-skew-x: 0; --tw-skew-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; background-color: white; border: 0px solid rgb(227, 227, 227); box-sizing: border-box; font-family: Söhne, ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, Ubuntu, Cantarell, "Noto Sans", sans-serif, "Helvetica Neue", Arial, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; font-size: 16px; margin: 1.25em 0px 0px; white-space-collapse: preserve;"><span style="color: red;">This code should effectively clear the screen by filling it with spaces. Note, however, that this is a simplified and direct approach. Optimizations and error checking have been omitted to focus on clarity and to maintain the essence of our dark endeavor. Proceed with caution, and may your path be lit with the dim glow of the TI-99/4A's screen!</span></p><p style="--tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-ring-color: rgba(69,89,164,.5); --tw-ring-offset-color: #fff; --tw-ring-offset-shadow: 0 0 transparent; --tw-ring-offset-width: 0px; --tw-ring-shadow: 0 0 transparent; --tw-rotate: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-scroll-snap-strictness: proximity; --tw-shadow-colored: 0 0 transparent; --tw-shadow: 0 0 transparent; --tw-skew-x: 0; --tw-skew-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; border: 0px solid rgb(227, 227, 227); box-sizing: border-box; font-family: Söhne, ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, Ubuntu, Cantarell, "Noto Sans", sans-serif, "Helvetica Neue", Arial, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; font-size: 16px; margin: 1.25em 0px; white-space-collapse: preserve;"><span style="background-color: white;">This is interesting. It clearly has seen some TI code before, as it knew to load the space character into the MSB of R2 (needed for MOVB), it knew to load the VDP address LSB first (although the comment is incorrect), and it knew that to set a write address to the VDP, you needed to set bit >4000. AI isn't the best choice, but it would work for any valid VDP address.</span></p><p style="--tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-ring-color: rgba(69,89,164,.5); --tw-ring-offset-color: #fff; --tw-ring-offset-shadow: 0 0 transparent; --tw-ring-offset-width: 0px; --tw-ring-shadow: 0 0 transparent; --tw-rotate: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-scroll-snap-strictness: proximity; --tw-shadow-colored: 0 0 transparent; --tw-shadow: 0 0 transparent; --tw-skew-x: 0; --tw-skew-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; border: 0px solid rgb(227, 227, 227); box-sizing: border-box; font-family: Söhne, ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, Ubuntu, Cantarell, "Noto Sans", sans-serif, "Helvetica Neue", Arial, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; font-size: 16px; margin: 1.25em 0px; white-space-collapse: preserve;"><span style="background-color: white;">However, the actual order of operations is a bit jumbled. It resets the address every loop, and it sets the >4000 bit in a funny place. (Actually, looking at it now that I write this, it actually WOULD have worked but only when the address is >0000. Normally you'd swap the bytes back and so that is what I asked for.)</span></p><p style="--tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-ring-color: rgba(69,89,164,.5); --tw-ring-offset-color: #fff; --tw-ring-offset-shadow: 0 0 transparent; --tw-ring-offset-width: 0px; --tw-ring-shadow: 0 0 transparent; --tw-rotate: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-scroll-snap-strictness: proximity; --tw-shadow-colored: 0 0 transparent; --tw-shadow: 0 0 transparent; --tw-skew-x: 0; --tw-skew-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; border: 0px solid rgb(227, 227, 227); box-sizing: border-box; font-family: Söhne, ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, Ubuntu, Cantarell, "Noto Sans", sans-serif, "Helvetica Neue", Arial, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; font-size: 16px; margin: 1.25em 0px; white-space-collapse: preserve;"><span style="background-color: white;">But the loop itself would work and has the right termination, if a little inefficient (using AI instead of just INC R0, for instance).</span></p><p style="--tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-ring-color: rgba(69,89,164,.5); --tw-ring-offset-color: #fff; --tw-ring-offset-shadow: 0 0 transparent; --tw-ring-offset-width: 0px; --tw-ring-shadow: 0 0 transparent; --tw-rotate: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-scroll-snap-strictness: proximity; --tw-shadow-colored: 0 0 transparent; --tw-shadow: 0 0 transparent; --tw-skew-x: 0; --tw-skew-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; border: 0px solid rgb(227, 227, 227); box-sizing: border-box; font-family: Söhne, ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, Ubuntu, Cantarell, "Noto Sans", sans-serif, "Helvetica Neue", Arial, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; font-size: 16px; margin: 1.25em 0px; white-space-collapse: preserve;"><span style="background-color: white;"><span style="color: #2b00fe;">You have correctly inferred many things. However, please make the following changes. First, the address must be set before the loop and outside it. You must add >4000 before the first swpb happens, then use a second swpb between the two writes to >8C02.</span></span></p><p style="--tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-ring-color: rgba(69,89,164,.5); --tw-ring-offset-color: #fff; --tw-ring-offset-shadow: 0 0 transparent; --tw-ring-offset-width: 0px; --tw-ring-shadow: 0 0 transparent; --tw-rotate: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-scroll-snap-strictness: proximity; --tw-shadow-colored: 0 0 transparent; --tw-shadow: 0 0 transparent; --tw-skew-x: 0; --tw-skew-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; border: 0px solid rgb(227, 227, 227); box-sizing: border-box; font-family: Söhne, ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, Ubuntu, Cantarell, "Noto Sans", sans-serif, "Helvetica Neue", Arial, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; font-size: 16px; margin: 1.25em 0px; white-space-collapse: preserve;"><span style="background-color: white;"><span style="color: red;">Ah, I see the refinement in your dark counsel. Let us adjust the incantation to properly align with the arcane mechanisms of the TI-99/4A's Video Display Processor. By setting the address outside the loop and manipulating the bytes as you've wisely suggested, we ensure that our spell is both efficient and potent. Here's the revised sorcery:</span></span></p><p style="--tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-ring-color: rgba(69,89,164,.5); --tw-ring-offset-color: #fff; --tw-ring-offset-shadow: 0 0 transparent; --tw-ring-offset-width: 0px; --tw-ring-shadow: 0 0 transparent; --tw-rotate: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-scroll-snap-strictness: proximity; --tw-shadow-colored: 0 0 transparent; --tw-shadow: 0 0 transparent; --tw-skew-x: 0; --tw-skew-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; border: 0px solid rgb(227, 227, 227); box-sizing: border-box; font-family: Söhne, ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, Ubuntu, Cantarell, "Noto Sans", sans-serif, "Helvetica Neue", Arial, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; font-size: 16px; margin: 1.25em 0px; white-space-collapse: preserve;"><span face=""Söhne Mono", Monaco, "Andale Mono", "Ubuntu Mono", monospace" style="background-color: #f3f3f3; font-size: 14px; text-wrap: nowrap;"> LI R0, >0000 * Load the initial screen address into R0
LI R1, >8C02 * Load the VDP write address register
LI R2, >20 * Load the ASCII space character (>20)
AI R0, >4000 * Add >4000 to the address to prepare it for VDP addressing
SWPB R0 * Swap bytes to get the address in the right format for VDP
MOVB R0, *R1 * Write the high byte of the address to the VDP write address register
SWPB R0 * Swap bytes back to prepare for writing the low byte
MOVB R0, *R1 * Write the low byte of the address to the VDP write address register
LI R3, >8C00 * Load the VDP data write address
LI R4, 768 * Initialize loop counter for 32 columns * 24 rows = 768
CLEAR: MOVB R2, *R3 * Write the space character to the VDP data register
DEC R4 * Decrement the loop counter
JNE CLEAR * If the counter is not zero, continue looping
RT * Return from subroutine</span></p><p style="--tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-ring-color: rgba(69,89,164,.5); --tw-ring-offset-color: #fff; --tw-ring-offset-shadow: 0 0 transparent; --tw-ring-offset-width: 0px; --tw-ring-shadow: 0 0 transparent; --tw-rotate: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-scroll-snap-strictness: proximity; --tw-shadow-colored: 0 0 transparent; --tw-shadow: 0 0 transparent; --tw-skew-x: 0; --tw-skew-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; background-color: white; border: 0px solid rgb(227, 227, 227); box-sizing: border-box; font-family: Söhne, ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, Ubuntu, Cantarell, "Noto Sans", sans-serif, "Helvetica Neue", Arial, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; font-size: 16px; margin: 1.25em 0px; white-space-collapse: preserve;"><span style="color: red;">In this revised version, the address is set outside the loop:</span></p><ul style="--tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-ring-color: rgba(69,89,164,.5); --tw-ring-offset-color: #fff; --tw-ring-offset-shadow: 0 0 transparent; --tw-ring-offset-width: 0px; --tw-ring-shadow: 0 0 transparent; --tw-rotate: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-scroll-snap-strictness: proximity; --tw-shadow-colored: 0 0 transparent; --tw-shadow: 0 0 transparent; --tw-skew-x: 0; --tw-skew-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; background-color: white; border: 0px solid rgb(227, 227, 227); box-sizing: border-box; display: flex; flex-direction: column; font-family: Söhne, ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, Ubuntu, Cantarell, "Noto Sans", sans-serif, "Helvetica Neue", Arial, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; font-size: 16px; list-style-image: initial; list-style-position: initial; margin: 1.25em 0px; padding: 0px; white-space-collapse: preserve;"><li style="--tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-ring-color: rgba(69,89,164,.5); --tw-ring-offset-color: #fff; --tw-ring-offset-shadow: 0 0 transparent; --tw-ring-offset-width: 0px; --tw-ring-shadow: 0 0 transparent; --tw-rotate: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-scroll-snap-strictness: proximity; --tw-shadow-colored: 0 0 transparent; --tw-shadow: 0 0 transparent; --tw-skew-x: 0; --tw-skew-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; border: 0px solid rgb(227, 227, 227); box-sizing: border-box; display: block; margin: 0px; min-height: 28px; padding-left: 0.375em;"><span style="color: red;"><code style="--tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-ring-color: rgba(69,89,164,.5); --tw-ring-offset-color: #fff; --tw-ring-offset-shadow: 0 0 transparent; --tw-ring-offset-width: 0px; --tw-ring-shadow: 0 0 transparent; --tw-rotate: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-scroll-snap-strictness: proximity; --tw-shadow-colored: 0 0 transparent; --tw-shadow: 0 0 transparent; --tw-skew-x: 0; --tw-skew-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; border: 0px solid rgb(227, 227, 227); box-sizing: border-box; font-family: "Söhne Mono", Monaco, "Andale Mono", "Ubuntu Mono", monospace; font-size: 0.875em; font-weight: 600; margin-top: 1.25em;">R0</code> is initialized with the screen start address (<code style="--tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-ring-color: rgba(69,89,164,.5); --tw-ring-offset-color: #fff; --tw-ring-offset-shadow: 0 0 transparent; --tw-ring-offset-width: 0px; --tw-ring-shadow: 0 0 transparent; --tw-rotate: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-scroll-snap-strictness: proximity; --tw-shadow-colored: 0 0 transparent; --tw-shadow: 0 0 transparent; --tw-skew-x: 0; --tw-skew-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; border: 0px solid rgb(227, 227, 227); box-sizing: border-box; font-family: "Söhne Mono", Monaco, "Andale Mono", "Ubuntu Mono", monospace; font-size: 0.875em; font-weight: 600;">>0000</code>), and we immediately add <code style="--tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-ring-color: rgba(69,89,164,.5); --tw-ring-offset-color: #fff; --tw-ring-offset-shadow: 0 0 transparent; --tw-ring-offset-width: 0px; --tw-ring-shadow: 0 0 transparent; --tw-rotate: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-scroll-snap-strictness: proximity; --tw-shadow-colored: 0 0 transparent; --tw-shadow: 0 0 transparent; --tw-skew-x: 0; --tw-skew-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; border: 0px solid rgb(227, 227, 227); box-sizing: border-box; font-family: "Söhne Mono", Monaco, "Andale Mono", "Ubuntu Mono", monospace; font-size: 0.875em; font-weight: 600; margin-bottom: 1.25em;">>4000</code> to it to prepare for the VDP addressing scheme.</span></li><li style="--tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-ring-color: rgba(69,89,164,.5); --tw-ring-offset-color: #fff; --tw-ring-offset-shadow: 0 0 transparent; --tw-ring-offset-width: 0px; --tw-ring-shadow: 0 0 transparent; --tw-rotate: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-scroll-snap-strictness: proximity; --tw-shadow-colored: 0 0 transparent; --tw-shadow: 0 0 transparent; --tw-skew-x: 0; --tw-skew-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; border: 0px solid rgb(227, 227, 227); box-sizing: border-box; display: block; margin: 0px; min-height: 28px; padding-left: 0.375em;"><span style="color: red;">We then perform a byte swap (<code style="--tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-ring-color: rgba(69,89,164,.5); --tw-ring-offset-color: #fff; --tw-ring-offset-shadow: 0 0 transparent; --tw-ring-offset-width: 0px; --tw-ring-shadow: 0 0 transparent; --tw-rotate: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-scroll-snap-strictness: proximity; --tw-shadow-colored: 0 0 transparent; --tw-shadow: 0 0 transparent; --tw-skew-x: 0; --tw-skew-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; border: 0px solid rgb(227, 227, 227); box-sizing: border-box; font-family: "Söhne Mono", Monaco, "Andale Mono", "Ubuntu Mono", monospace; font-size: 0.875em; font-weight: 600; margin-top: 1.25em;">SWPB</code>) on <code style="--tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-ring-color: rgba(69,89,164,.5); --tw-ring-offset-color: #fff; --tw-ring-offset-shadow: 0 0 transparent; --tw-ring-offset-width: 0px; --tw-ring-shadow: 0 0 transparent; --tw-rotate: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-scroll-snap-strictness: proximity; --tw-shadow-colored: 0 0 transparent; --tw-shadow: 0 0 transparent; --tw-skew-x: 0; --tw-skew-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; border: 0px solid rgb(227, 227, 227); box-sizing: border-box; font-family: "Söhne Mono", Monaco, "Andale Mono", "Ubuntu Mono", monospace; font-size: 0.875em; font-weight: 600; margin-bottom: 1.25em;">R0</code> to align the address bytes correctly for the VDP.</span></li><li style="--tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-ring-color: rgba(69,89,164,.5); --tw-ring-offset-color: #fff; --tw-ring-offset-shadow: 0 0 transparent; --tw-ring-offset-width: 0px; --tw-ring-shadow: 0 0 transparent; --tw-rotate: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-scroll-snap-strictness: proximity; --tw-shadow-colored: 0 0 transparent; --tw-shadow: 0 0 transparent; --tw-skew-x: 0; --tw-skew-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; border: 0px solid rgb(227, 227, 227); box-sizing: border-box; display: block; margin: 0px; min-height: 28px; padding-left: 0.375em;"><span style="color: red;">The high byte of the address is written to the VDP write address register (<code style="--tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-ring-color: rgba(69,89,164,.5); --tw-ring-offset-color: #fff; --tw-ring-offset-shadow: 0 0 transparent; --tw-ring-offset-width: 0px; --tw-ring-shadow: 0 0 transparent; --tw-rotate: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-scroll-snap-strictness: proximity; --tw-shadow-colored: 0 0 transparent; --tw-shadow: 0 0 transparent; --tw-skew-x: 0; --tw-skew-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; border: 0px solid rgb(227, 227, 227); box-sizing: border-box; font-family: "Söhne Mono", Monaco, "Andale Mono", "Ubuntu Mono", monospace; font-size: 0.875em; font-weight: 600; margin-bottom: 1.25em; margin-top: 1.25em;">>8C02</code>), then we swap the bytes back and write again to set the low byte of the address.</span></li><li style="--tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-ring-color: rgba(69,89,164,.5); --tw-ring-offset-color: #fff; --tw-ring-offset-shadow: 0 0 transparent; --tw-ring-offset-width: 0px; --tw-ring-shadow: 0 0 transparent; --tw-rotate: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-scroll-snap-strictness: proximity; --tw-shadow-colored: 0 0 transparent; --tw-shadow: 0 0 transparent; --tw-skew-x: 0; --tw-skew-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; border: 0px solid rgb(227, 227, 227); box-sizing: border-box; display: block; margin: 0px; min-height: 28px; padding-left: 0.375em;"><span style="color: red;">With the address set, we enter the loop to clear the screen by writing spaces (<code style="--tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-ring-color: rgba(69,89,164,.5); --tw-ring-offset-color: #fff; --tw-ring-offset-shadow: 0 0 transparent; --tw-ring-offset-width: 0px; --tw-ring-shadow: 0 0 transparent; --tw-rotate: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-scroll-snap-strictness: proximity; --tw-shadow-colored: 0 0 transparent; --tw-shadow: 0 0 transparent; --tw-skew-x: 0; --tw-skew-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; border: 0px solid rgb(227, 227, 227); box-sizing: border-box; font-family: "Söhne Mono", Monaco, "Andale Mono", "Ubuntu Mono", monospace; font-size: 0.875em; font-weight: 600; margin-top: 1.25em;">>20</code>) to the entire display area using the VDP data write address (<code style="--tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-ring-color: rgba(69,89,164,.5); --tw-ring-offset-color: #fff; --tw-ring-offset-shadow: 0 0 transparent; --tw-ring-offset-width: 0px; --tw-ring-shadow: 0 0 transparent; --tw-rotate: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-scroll-snap-strictness: proximity; --tw-shadow-colored: 0 0 transparent; --tw-shadow: 0 0 transparent; --tw-skew-x: 0; --tw-skew-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; border: 0px solid rgb(227, 227, 227); box-sizing: border-box; font-family: "Söhne Mono", Monaco, "Andale Mono", "Ubuntu Mono", monospace; font-size: 0.875em; font-weight: 600; margin-bottom: 1.25em;">>8C00</code>).</span></li><li style="--tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-ring-color: rgba(69,89,164,.5); --tw-ring-offset-color: #fff; --tw-ring-offset-shadow: 0 0 transparent; --tw-ring-offset-width: 0px; --tw-ring-shadow: 0 0 transparent; --tw-rotate: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-scroll-snap-strictness: proximity; --tw-shadow-colored: 0 0 transparent; --tw-shadow: 0 0 transparent; --tw-skew-x: 0; --tw-skew-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; border: 0px solid rgb(227, 227, 227); box-sizing: border-box; display: block; margin: 0px; min-height: 28px; padding-left: 0.375em;"><span style="color: red;"><code style="--tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-ring-color: rgba(69,89,164,.5); --tw-ring-offset-color: #fff; --tw-ring-offset-shadow: 0 0 transparent; --tw-ring-offset-width: 0px; --tw-ring-shadow: 0 0 transparent; --tw-rotate: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-scroll-snap-strictness: proximity; --tw-shadow-colored: 0 0 transparent; --tw-shadow: 0 0 transparent; --tw-skew-x: 0; --tw-skew-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; border: 0px solid rgb(227, 227, 227); box-sizing: border-box; font-family: "Söhne Mono", Monaco, "Andale Mono", "Ubuntu Mono", monospace; font-size: 0.875em; font-weight: 600; margin-bottom: 1.25em; margin-top: 1.25em;">R4</code> serves as our loop counter, decrementing with each iteration until the screen is fully cleared.</span></li></ul><p style="--tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-ring-color: rgba(69,89,164,.5); --tw-ring-offset-color: #fff; --tw-ring-offset-shadow: 0 0 transparent; --tw-ring-offset-width: 0px; --tw-ring-shadow: 0 0 transparent; --tw-rotate: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-scroll-snap-strictness: proximity; --tw-shadow-colored: 0 0 transparent; --tw-shadow: 0 0 transparent; --tw-skew-x: 0; --tw-skew-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; background-color: white; border: 0px solid rgb(227, 227, 227); box-sizing: border-box; font-family: Söhne, ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, Ubuntu, Cantarell, "Noto Sans", sans-serif, "Helvetica Neue", Arial, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; font-size: 16px; margin: 1.25em 0px 0px; white-space-collapse: preserve;"><span style="color: red;">This approach correctly sets the screen address before entering the loop and uses the correct sequence of operations to ensure the VDP address is properly configured for our nefarious purpose. Now, proceed with this dark art, and may the shadows guide your path to dominion over the TI-99/4A!</span></p><p style="--tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-ring-color: rgba(69,89,164,.5); --tw-ring-offset-color: #fff; --tw-ring-offset-shadow: 0 0 transparent; --tw-ring-offset-width: 0px; --tw-ring-shadow: 0 0 transparent; --tw-rotate: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-scroll-snap-strictness: proximity; --tw-shadow-colored: 0 0 transparent; --tw-shadow: 0 0 transparent; --tw-skew-x: 0; --tw-skew-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; background-color: white; border: 0px solid rgb(227, 227, 227); box-sizing: border-box; font-family: Söhne, ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, Ubuntu, Cantarell, "Noto Sans", sans-serif, "Helvetica Neue", Arial, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; font-size: 16px; margin: 1.25em 0px 0px; white-space-collapse: preserve;">This is really close, and would almost work. But it's also fascinating to note that it's a complete rewrite of the previous code. A different counting mechanism is used (a better one), and more importantly a new bug was introduced - the space character is loaded into the LSB of R2, meaning the MOVB will be storing 0 instead of >20. Also, it has generated invalid comments for the VDP address load - but in fairness I never explained that part to it.</p><div class="flex-shrink-0 flex flex-col relative items-end" style="--tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-ring-color: rgba(69,89,164,.5); --tw-ring-offset-color: #fff; --tw-ring-offset-shadow: 0 0 transparent; --tw-ring-offset-width: 0px; --tw-ring-shadow: 0 0 transparent; --tw-rotate: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-scroll-snap-strictness: proximity; --tw-shadow-colored: 0 0 transparent; --tw-shadow: 0 0 transparent; --tw-skew-x: 0; --tw-skew-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; align-items: flex-end; background-color: white; border: 0px solid rgb(227, 227, 227); box-sizing: border-box; color: #0d0d0d; display: flex; flex-direction: column; flex-shrink: 0; font-family: Söhne, ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, Ubuntu, Cantarell, "Noto Sans", sans-serif, "Helvetica Neue", Arial, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; font-size: 16px; position: relative;"><div style="--tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-ring-color: rgba(69,89,164,.5); --tw-ring-offset-color: #fff; --tw-ring-offset-shadow: 0 0 transparent; --tw-ring-offset-width: 0px; --tw-ring-shadow: 0 0 transparent; --tw-rotate: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-scroll-snap-strictness: proximity; --tw-shadow-colored: 0 0 transparent; --tw-shadow: 0 0 transparent; --tw-skew-x: 0; --tw-skew-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; border: 0px solid rgb(227, 227, 227); box-sizing: border-box;"><div class="pt-0.5" style="--tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-ring-color: rgba(69,89,164,.5); --tw-ring-offset-color: #fff; --tw-ring-offset-shadow: 0 0 transparent; --tw-ring-offset-width: 0px; --tw-ring-shadow: 0 0 transparent; --tw-rotate: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-scroll-snap-strictness: proximity; --tw-shadow-colored: 0 0 transparent; --tw-shadow: 0 0 transparent; --tw-skew-x: 0; --tw-skew-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; border: 0px solid rgb(227, 227, 227); box-sizing: border-box; padding-top: 0.125rem;"><div class="gizmo-shadow-stroke flex h-6 w-6 items-center justify-center overflow-hidden rounded-full" style="--tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-ring-color: rgba(69,89,164,.5); --tw-ring-offset-color: #fff; --tw-ring-offset-shadow: 0 0 transparent; --tw-ring-offset-width: 0px; --tw-ring-shadow: 0 0 transparent; --tw-rotate: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-scroll-snap-strictness: proximity; --tw-shadow-colored: 0 0 transparent; --tw-shadow: 0 0 transparent; --tw-skew-x: 0; --tw-skew-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; align-items: center; border-radius: 9999px; border: 0px solid rgb(227, 227, 227); box-sizing: border-box; display: flex; height: 1.5rem; justify-content: center; overflow: hidden; position: relative; width: 1.5rem;"><div class="relative flex" style="--tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-ring-color: rgba(69,89,164,.5); --tw-ring-offset-color: #fff; --tw-ring-offset-shadow: 0 0 transparent; --tw-ring-offset-width: 0px; --tw-ring-shadow: 0 0 transparent; --tw-rotate: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-scroll-snap-strictness: proximity; --tw-shadow-colored: 0 0 transparent; --tw-shadow: 0 0 transparent; --tw-skew-x: 0; --tw-skew-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; border: 0px solid rgb(227, 227, 227); box-sizing: border-box; display: flex; position: relative;"><br /></div></div></div></div></div><div class="relative flex w-full flex-col" style="--tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-ring-color: rgba(69,89,164,.5); --tw-ring-offset-color: #fff; --tw-ring-offset-shadow: 0 0 transparent; --tw-ring-offset-width: 0px; --tw-ring-shadow: 0 0 transparent; --tw-rotate: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-scroll-snap-strictness: proximity; --tw-shadow-colored: 0 0 transparent; --tw-shadow: 0 0 transparent; --tw-skew-x: 0; --tw-skew-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; border: 0px solid rgb(227, 227, 227); box-sizing: border-box; display: flex; flex-direction: column; font-family: Söhne, ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, Ubuntu, Cantarell, "Noto Sans", sans-serif, "Helvetica Neue", Arial, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; font-size: 16px; position: relative; width: 692px;"><div class="flex-col gap-1 md:gap-3" style="--tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-ring-color: rgba(69,89,164,.5); --tw-ring-offset-color: #fff; --tw-ring-offset-shadow: 0 0 transparent; --tw-ring-offset-width: 0px; --tw-ring-shadow: 0 0 transparent; --tw-rotate: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-scroll-snap-strictness: proximity; --tw-shadow-colored: 0 0 transparent; --tw-shadow: 0 0 transparent; --tw-skew-x: 0; --tw-skew-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; border: 0px solid rgb(227, 227, 227); box-sizing: border-box; flex-direction: column; gap: 0.75rem;"><div class="flex flex-grow flex-col max-w-full" style="--tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-ring-color: rgba(69,89,164,.5); --tw-ring-offset-color: #fff; --tw-ring-offset-shadow: 0 0 transparent; --tw-ring-offset-width: 0px; --tw-ring-shadow: 0 0 transparent; --tw-rotate: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-scroll-snap-strictness: proximity; --tw-shadow-colored: 0 0 transparent; --tw-shadow: 0 0 transparent; --tw-skew-x: 0; --tw-skew-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; border: 0px solid rgb(227, 227, 227); box-sizing: border-box; display: flex; flex-direction: column; flex-grow: 1; max-width: 100%;"><div class="min-h-[20px] text-message flex flex-col items-start gap-3 whitespace-pre-wrap break-words [.text-message+&]:mt-5 overflow-x-auto" data-message-author-role="user" data-message-id="aaa2a7b1-7cf4-4404-a8ad-618bd4ab38bc" style="--tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-ring-color: rgba(69,89,164,.5); --tw-ring-offset-color: #fff; --tw-ring-offset-shadow: 0 0 transparent; --tw-ring-offset-width: 0px; --tw-ring-shadow: 0 0 transparent; --tw-rotate: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-scroll-snap-strictness: proximity; --tw-shadow-colored: 0 0 transparent; --tw-shadow: 0 0 transparent; --tw-skew-x: 0; --tw-skew-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; align-items: flex-start; border: 0px solid rgb(227, 227, 227); box-sizing: border-box; display: flex; flex-direction: column; gap: 0.75rem; min-height: 20px; overflow-wrap: break-word; overflow-x: auto; white-space-collapse: preserve;"><div style="--tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-ring-color: rgba(69,89,164,.5); --tw-ring-offset-color: #fff; --tw-ring-offset-shadow: 0 0 transparent; --tw-ring-offset-width: 0px; --tw-ring-shadow: 0 0 transparent; --tw-rotate: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-scroll-snap-strictness: proximity; --tw-shadow-colored: 0 0 transparent; --tw-shadow: 0 0 transparent; --tw-skew-x: 0; --tw-skew-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; background-color: white; border: 0px solid rgb(227, 227, 227); box-sizing: border-box;"><span style="color: #2b00fe;">Very close! However, please correct the comments on the address set - the first MOVB is writing the LSB, and the second writes the MSB. Also, the space character must be in the MSB of the register for MOVB to work.</span></div><div style="--tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-ring-color: rgba(69,89,164,.5); --tw-ring-offset-color: #fff; --tw-ring-offset-shadow: 0 0 transparent; --tw-ring-offset-width: 0px; --tw-ring-shadow: 0 0 transparent; --tw-rotate: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-scroll-snap-strictness: proximity; --tw-shadow-colored: 0 0 transparent; --tw-shadow: 0 0 transparent; --tw-skew-x: 0; --tw-skew-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; background-color: white; border: 0px solid rgb(227, 227, 227); box-sizing: border-box;"><span style="color: red;">Ah, a critical observation in our dark assembly ritual. Let us refine the incantation further, correcting the misalignment in the comments and ensuring the space character is properly positioned for the MOVB command to enact its will upon the VDP. Here is the amended spell, with the precision you demand:</span></div><div style="--tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-ring-color: rgba(69,89,164,.5); --tw-ring-offset-color: #fff; --tw-ring-offset-shadow: 0 0 transparent; --tw-ring-offset-width: 0px; --tw-ring-shadow: 0 0 transparent; --tw-rotate: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-scroll-snap-strictness: proximity; --tw-shadow-colored: 0 0 transparent; --tw-shadow: 0 0 transparent; --tw-skew-x: 0; --tw-skew-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; border: 0px solid rgb(227, 227, 227); box-sizing: border-box;"><span face=""Söhne Mono", Monaco, "Andale Mono", "Ubuntu Mono", monospace" style="background-color: #f3f3f3; font-size: 14px; text-wrap: nowrap;"> LI R0, >0000 * Load the initial screen address into R0
AI R0, >4000 * Add >4000 to the address to prepare it for VDP addressing
SWPB R0 * Swap bytes to get the address in the right format for VDP
LI R1, >8C02 * Load the VDP write address register
MOVB R0, *R1 * Write the LSB of the address to the VDP write address register
SWPB R0 * Swap bytes back to prepare for writing the MSB
MOVB R0, *R1 * Write the MSB of the address to the VDP write address register
LI R2, >2000 * Load the ASCII space character (>20) into the MSB of the register
LI R3, >8C00 * Load the VDP data write address
LI R4, 768 * Initialize loop counter for 32 columns * 24 rows = 768
CLEAR: MOVB R2, *R3 * Write the space character to the VDP data register
DEC R4 * Decrement the loop counter
JNE CLEAR * If the counter is not zero, continue looping
RT * Return from subroutine</span></div><div style="--tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-ring-color: rgba(69,89,164,.5); --tw-ring-offset-color: #fff; --tw-ring-offset-shadow: 0 0 transparent; --tw-ring-offset-width: 0px; --tw-ring-shadow: 0 0 transparent; --tw-rotate: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-scroll-snap-strictness: proximity; --tw-shadow-colored: 0 0 transparent; --tw-shadow: 0 0 transparent; --tw-skew-x: 0; --tw-skew-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; border: 0px solid rgb(227, 227, 227); box-sizing: border-box;"><p style="--tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-ring-color: rgba(69,89,164,.5); --tw-ring-offset-color: #fff; --tw-ring-offset-shadow: 0 0 transparent; --tw-ring-offset-width: 0px; --tw-ring-shadow: 0 0 transparent; --tw-rotate: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-scroll-snap-strictness: proximity; --tw-shadow-colored: 0 0 transparent; --tw-shadow: 0 0 transparent; --tw-skew-x: 0; --tw-skew-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; background-color: white; border: 0px solid rgb(227, 227, 227); box-sizing: border-box; margin: 1.25em 0px;"><span style="color: red;">Corrections and clarifications:</span></p><ul style="--tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-ring-color: rgba(69,89,164,.5); --tw-ring-offset-color: #fff; --tw-ring-offset-shadow: 0 0 transparent; --tw-ring-offset-width: 0px; --tw-ring-shadow: 0 0 transparent; --tw-rotate: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-scroll-snap-strictness: proximity; --tw-shadow-colored: 0 0 transparent; --tw-shadow: 0 0 transparent; --tw-skew-x: 0; --tw-skew-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; background-color: white; border: 0px solid rgb(227, 227, 227); box-sizing: border-box; display: flex; flex-direction: column; list-style-image: initial; list-style-position: initial; margin: 1.25em 0px; padding: 0px;"><li style="--tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-ring-color: rgba(69,89,164,.5); --tw-ring-offset-color: #fff; --tw-ring-offset-shadow: 0 0 transparent; --tw-ring-offset-width: 0px; --tw-ring-shadow: 0 0 transparent; --tw-rotate: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-scroll-snap-strictness: proximity; --tw-shadow-colored: 0 0 transparent; --tw-shadow: 0 0 transparent; --tw-skew-x: 0; --tw-skew-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; border: 0px solid rgb(227, 227, 227); box-sizing: border-box; display: block; margin: 0px; min-height: 28px; padding-left: 0.375em;"><span style="color: red;">The first <code style="--tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-ring-color: rgba(69,89,164,.5); --tw-ring-offset-color: #fff; --tw-ring-offset-shadow: 0 0 transparent; --tw-ring-offset-width: 0px; --tw-ring-shadow: 0 0 transparent; --tw-rotate: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-scroll-snap-strictness: proximity; --tw-shadow-colored: 0 0 transparent; --tw-shadow: 0 0 transparent; --tw-skew-x: 0; --tw-skew-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; border: 0px solid rgb(227, 227, 227); box-sizing: border-box; font-family: "Söhne Mono", Monaco, "Andale Mono", "Ubuntu Mono", monospace; font-size: 0.875em; font-weight: 600; margin-top: 1.25em;">MOVB</code> now correctly comments that it writes the LSB (Low Byte) of the address to the VDP write address register, after adding <code style="--tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-ring-color: rgba(69,89,164,.5); --tw-ring-offset-color: #fff; --tw-ring-offset-shadow: 0 0 transparent; --tw-ring-offset-width: 0px; --tw-ring-shadow: 0 0 transparent; --tw-rotate: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-scroll-snap-strictness: proximity; --tw-shadow-colored: 0 0 transparent; --tw-shadow: 0 0 transparent; --tw-skew-x: 0; --tw-skew-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; border: 0px solid rgb(227, 227, 227); box-sizing: border-box; font-family: "Söhne Mono", Monaco, "Andale Mono", "Ubuntu Mono", monospace; font-size: 0.875em; font-weight: 600;">>4000</code> to prepare for VDP addressing and swapping bytes with <code style="--tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-ring-color: rgba(69,89,164,.5); --tw-ring-offset-color: #fff; --tw-ring-offset-shadow: 0 0 transparent; --tw-ring-offset-width: 0px; --tw-ring-shadow: 0 0 transparent; --tw-rotate: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-scroll-snap-strictness: proximity; --tw-shadow-colored: 0 0 transparent; --tw-shadow: 0 0 transparent; --tw-skew-x: 0; --tw-skew-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; border: 0px solid rgb(227, 227, 227); box-sizing: border-box; font-family: "Söhne Mono", Monaco, "Andale Mono", "Ubuntu Mono", monospace; font-size: 0.875em; font-weight: 600; margin-bottom: 1.25em;">SWPB</code>.</span></li><li style="--tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-ring-color: rgba(69,89,164,.5); --tw-ring-offset-color: #fff; --tw-ring-offset-shadow: 0 0 transparent; --tw-ring-offset-width: 0px; --tw-ring-shadow: 0 0 transparent; --tw-rotate: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-scroll-snap-strictness: proximity; --tw-shadow-colored: 0 0 transparent; --tw-shadow: 0 0 transparent; --tw-skew-x: 0; --tw-skew-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; border: 0px solid rgb(227, 227, 227); box-sizing: border-box; display: block; margin: 0px; min-height: 28px; padding-left: 0.375em;"><span style="color: red;">The second <code style="--tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-ring-color: rgba(69,89,164,.5); --tw-ring-offset-color: #fff; --tw-ring-offset-shadow: 0 0 transparent; --tw-ring-offset-width: 0px; --tw-ring-shadow: 0 0 transparent; --tw-rotate: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-scroll-snap-strictness: proximity; --tw-shadow-colored: 0 0 transparent; --tw-shadow: 0 0 transparent; --tw-skew-x: 0; --tw-skew-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; border: 0px solid rgb(227, 227, 227); box-sizing: border-box; font-family: "Söhne Mono", Monaco, "Andale Mono", "Ubuntu Mono", monospace; font-size: 0.875em; font-weight: 600; margin-top: 1.25em;">MOVB</code>, following another <code style="--tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-ring-color: rgba(69,89,164,.5); --tw-ring-offset-color: #fff; --tw-ring-offset-shadow: 0 0 transparent; --tw-ring-offset-width: 0px; --tw-ring-shadow: 0 0 transparent; --tw-rotate: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-scroll-snap-strictness: proximity; --tw-shadow-colored: 0 0 transparent; --tw-shadow: 0 0 transparent; --tw-skew-x: 0; --tw-skew-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; border: 0px solid rgb(227, 227, 227); box-sizing: border-box; font-family: "Söhne Mono", Monaco, "Andale Mono", "Ubuntu Mono", monospace; font-size: 0.875em; font-weight: 600; margin-bottom: 1.25em;">SWPB</code>, correctly comments that it writes the MSB (High Byte) of the address to the VDP write address register.</span></li><li style="--tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-ring-color: rgba(69,89,164,.5); --tw-ring-offset-color: #fff; --tw-ring-offset-shadow: 0 0 transparent; --tw-ring-offset-width: 0px; --tw-ring-shadow: 0 0 transparent; --tw-rotate: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-scroll-snap-strictness: proximity; --tw-shadow-colored: 0 0 transparent; --tw-shadow: 0 0 transparent; --tw-skew-x: 0; --tw-skew-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; border: 0px solid rgb(227, 227, 227); box-sizing: border-box; display: block; margin: 0px; min-height: 28px; padding-left: 0.375em;"><span style="color: red;">The space character (<code style="--tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-ring-color: rgba(69,89,164,.5); --tw-ring-offset-color: #fff; --tw-ring-offset-shadow: 0 0 transparent; --tw-ring-offset-width: 0px; --tw-ring-shadow: 0 0 transparent; --tw-rotate: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-scroll-snap-strictness: proximity; --tw-shadow-colored: 0 0 transparent; --tw-shadow: 0 0 transparent; --tw-skew-x: 0; --tw-skew-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; border: 0px solid rgb(227, 227, 227); box-sizing: border-box; font-family: "Söhne Mono", Monaco, "Andale Mono", "Ubuntu Mono", monospace; font-size: 0.875em; font-weight: 600; margin-top: 1.25em;">>20</code>) is loaded into the MSB of <code style="--tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-ring-color: rgba(69,89,164,.5); --tw-ring-offset-color: #fff; --tw-ring-offset-shadow: 0 0 transparent; --tw-ring-offset-width: 0px; --tw-ring-shadow: 0 0 transparent; --tw-rotate: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-scroll-snap-strictness: proximity; --tw-shadow-colored: 0 0 transparent; --tw-shadow: 0 0 transparent; --tw-skew-x: 0; --tw-skew-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; border: 0px solid rgb(227, 227, 227); box-sizing: border-box; font-family: "Söhne Mono", Monaco, "Andale Mono", "Ubuntu Mono", monospace; font-size: 0.875em; font-weight: 600;">R2</code> to ensure it's correctly positioned for writing with <code style="--tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-ring-color: rgba(69,89,164,.5); --tw-ring-offset-color: #fff; --tw-ring-offset-shadow: 0 0 transparent; --tw-ring-offset-width: 0px; --tw-ring-shadow: 0 0 transparent; --tw-rotate: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-scroll-snap-strictness: proximity; --tw-shadow-colored: 0 0 transparent; --tw-shadow: 0 0 transparent; --tw-skew-x: 0; --tw-skew-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; border: 0px solid rgb(227, 227, 227); box-sizing: border-box; font-family: "Söhne Mono", Monaco, "Andale Mono", "Ubuntu Mono", monospace; font-size: 0.875em; font-weight: 600;">MOVB</code> to the VDP data register. The <code style="--tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-ring-color: rgba(69,89,164,.5); --tw-ring-offset-color: #fff; --tw-ring-offset-shadow: 0 0 transparent; --tw-ring-offset-width: 0px; --tw-ring-shadow: 0 0 transparent; --tw-rotate: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-scroll-snap-strictness: proximity; --tw-shadow-colored: 0 0 transparent; --tw-shadow: 0 0 transparent; --tw-skew-x: 0; --tw-skew-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; border: 0px solid rgb(227, 227, 227); box-sizing: border-box; font-family: "Söhne Mono", Monaco, "Andale Mono", "Ubuntu Mono", monospace; font-size: 0.875em; font-weight: 600;">LI R2, >2000</code> instruction achieves this by loading <code style="--tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-ring-color: rgba(69,89,164,.5); --tw-ring-offset-color: #fff; --tw-ring-offset-shadow: 0 0 transparent; --tw-ring-offset-width: 0px; --tw-ring-shadow: 0 0 transparent; --tw-rotate: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-scroll-snap-strictness: proximity; --tw-shadow-colored: 0 0 transparent; --tw-shadow: 0 0 transparent; --tw-skew-x: 0; --tw-skew-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; border: 0px solid rgb(227, 227, 227); box-sizing: border-box; font-family: "Söhne Mono", Monaco, "Andale Mono", "Ubuntu Mono", monospace; font-size: 0.875em; font-weight: 600;">>20</code> into the high byte and <code style="--tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-ring-color: rgba(69,89,164,.5); --tw-ring-offset-color: #fff; --tw-ring-offset-shadow: 0 0 transparent; --tw-ring-offset-width: 0px; --tw-ring-shadow: 0 0 transparent; --tw-rotate: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-scroll-snap-strictness: proximity; --tw-shadow-colored: 0 0 transparent; --tw-shadow: 0 0 transparent; --tw-skew-x: 0; --tw-skew-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; border: 0px solid rgb(227, 227, 227); box-sizing: border-box; font-family: "Söhne Mono", Monaco, "Andale Mono", "Ubuntu Mono", monospace; font-size: 0.875em; font-weight: 600;">00</code> into the low byte, which is then correctly written by the <code style="--tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-ring-color: rgba(69,89,164,.5); --tw-ring-offset-color: #fff; --tw-ring-offset-shadow: 0 0 transparent; --tw-ring-offset-width: 0px; --tw-ring-shadow: 0 0 transparent; --tw-rotate: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-scroll-snap-strictness: proximity; --tw-shadow-colored: 0 0 transparent; --tw-shadow: 0 0 transparent; --tw-skew-x: 0; --tw-skew-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; border: 0px solid rgb(227, 227, 227); box-sizing: border-box; font-family: "Söhne Mono", Monaco, "Andale Mono", "Ubuntu Mono", monospace; font-size: 0.875em; font-weight: 600; margin-bottom: 1.25em;">MOVB</code> command.</span></li></ul><p style="--tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-ring-color: rgba(69,89,164,.5); --tw-ring-offset-color: #fff; --tw-ring-offset-shadow: 0 0 transparent; --tw-ring-offset-width: 0px; --tw-ring-shadow: 0 0 transparent; --tw-rotate: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-scroll-snap-strictness: proximity; --tw-shadow-colored: 0 0 transparent; --tw-shadow: 0 0 transparent; --tw-skew-x: 0; --tw-skew-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; background-color: white; border: 0px solid rgb(227, 227, 227); box-sizing: border-box; margin: 1.25em 0px 0px;"><span style="color: red;">With these corrections, our spell is now precisely woven, ensuring that the VDP obeys our command to clear the screen with spaces. Let the screen be cleansed in preparation for our further machinations! Proceed, acolyte, and wield this power wisely.</span></p></div><div style="--tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-ring-color: rgba(69,89,164,.5); --tw-ring-offset-color: #fff; --tw-ring-offset-shadow: 0 0 transparent; --tw-ring-offset-width: 0px; --tw-ring-shadow: 0 0 transparent; --tw-rotate: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-scroll-snap-strictness: proximity; --tw-shadow-colored: 0 0 transparent; --tw-shadow: 0 0 transparent; --tw-skew-x: 0; --tw-skew-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; background-color: white; border: 0px solid rgb(227, 227, 227); box-sizing: border-box;">I think at this point the code works. Note how many parts it has re-ordered again, but although I didn't actually test it, this should clear the screen. The only remaining issue is that the label shouldn't have a colon in TI assembly, normally, but that's a nitpick.</div><div style="--tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-ring-color: rgba(69,89,164,.5); --tw-ring-offset-color: #fff; --tw-ring-offset-shadow: 0 0 transparent; --tw-ring-offset-width: 0px; --tw-ring-shadow: 0 0 transparent; --tw-rotate: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-scroll-snap-strictness: proximity; --tw-shadow-colored: 0 0 transparent; --tw-shadow: 0 0 transparent; --tw-skew-x: 0; --tw-skew-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; background-color: white; border: 0px solid rgb(227, 227, 227); box-sizing: border-box;">I find it fascinating to be able to refine the request in this manner. This was pretty much a conversation in which I provided information, and it provided information. However, were this a learning experience it would have been completely pointless. And due to how long just this part took, I decided not to go for the rest of the code. (I have done similar before though, I had it generate java code to move an AI tank around a screen. It was not a very smart tank, but it worked.)</div><div style="--tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-ring-color: rgba(69,89,164,.5); --tw-ring-offset-color: #fff; --tw-ring-offset-shadow: 0 0 transparent; --tw-ring-offset-width: 0px; --tw-ring-shadow: 0 0 transparent; --tw-rotate: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-scroll-snap-strictness: proximity; --tw-shadow-colored: 0 0 transparent; --tw-shadow: 0 0 transparent; --tw-skew-x: 0; --tw-skew-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; background-color: white; border: 0px solid rgb(227, 227, 227); box-sizing: border-box;">But the amount of effort it took to generate working code was high, and so without the ability to educate the chatbot on the parts you need most, it is most useful for tasks that are well defined and common enough to trust the results on. Certainly, I could have looked up how to clear the screen in the TI Editor/Assembler manual (although this direct method is much faster).</div><div style="--tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-ring-color: rgba(69,89,164,.5); --tw-ring-offset-color: #fff; --tw-ring-offset-shadow: 0 0 transparent; --tw-ring-offset-width: 0px; --tw-ring-shadow: 0 0 transparent; --tw-rotate: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-scroll-snap-strictness: proximity; --tw-shadow-colored: 0 0 transparent; --tw-shadow: 0 0 transparent; --tw-skew-x: 0; --tw-skew-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; background-color: white; border: 0px solid rgb(227, 227, 227); box-sizing: border-box;">I do know people who say they use it in their normal coding, and I admit I haven't called on it to help a lot with modern code yet, so I don't know how much better it is. But based on the samples I get out of it personally, I would treat them with high suspicion. I guess I just prefer to learn the stuff myself?</div><div style="--tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-ring-color: rgba(69,89,164,.5); --tw-ring-offset-color: #fff; --tw-ring-offset-shadow: 0 0 transparent; --tw-ring-offset-width: 0px; --tw-ring-shadow: 0 0 transparent; --tw-rotate: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-scroll-snap-strictness: proximity; --tw-shadow-colored: 0 0 transparent; --tw-shadow: 0 0 transparent; --tw-skew-x: 0; --tw-skew-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; background-color: white; border: 0px solid rgb(227, 227, 227); box-sizing: border-box;"><br /></div><div style="--tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-ring-color: rgba(69,89,164,.5); --tw-ring-offset-color: #fff; --tw-ring-offset-shadow: 0 0 transparent; --tw-ring-offset-width: 0px; --tw-ring-shadow: 0 0 transparent; --tw-rotate: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-scroll-snap-strictness: proximity; --tw-shadow-colored: 0 0 transparent; --tw-shadow: 0 0 transparent; --tw-skew-x: 0; --tw-skew-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; background-color: white; border: 0px solid rgb(227, 227, 227); box-sizing: border-box;"><span style="color: #2b00fe;"><br /></span></div><div style="--tw-border-spacing-x: 0; --tw-border-spacing-y: 0; --tw-ring-color: rgba(69,89,164,.5); --tw-ring-offset-color: #fff; --tw-ring-offset-shadow: 0 0 transparent; --tw-ring-offset-width: 0px; --tw-ring-shadow: 0 0 transparent; --tw-rotate: 0; --tw-scale-x: 1; --tw-scale-y: 1; --tw-scroll-snap-strictness: proximity; --tw-shadow-colored: 0 0 transparent; --tw-shadow: 0 0 transparent; --tw-skew-x: 0; --tw-skew-y: 0; --tw-translate-x: 0; --tw-translate-y: 0; background-color: white; border: 0px solid rgb(227, 227, 227); box-sizing: border-box;"><br /></div></div></div></div></div>Tursilionhttp://www.blogger.com/profile/16478174231304644316noreply@blogger.com0tag:blogger.com,1999:blog-7717886351507761714.post-12956659416506727552023-12-15T07:19:00.000-08:002023-12-15T07:19:09.879-08:00Hey, so, 2023 is nearly done!<p>End of year blog. I like to look back each year and see what all I did. Last year it was really quiet. Like, stupidly quiet, so let's see how 2023 did!</p><p>I managed to get Cool Herders for the Nintendo GBA completed and sent off to Piko Interactive, but we're still waiting to see the next step there. That took about eight months! But I think it came out better than the DS version with the extra time. Hopefully we'll see it in 2024.</p><p></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhLu26s3k_6N-JQEBcXmQDQb6FlcOJYo-s127gud3Qr739x-q_nCmyi4w4jInf5PIoQc59KikCt2SXD6Bc0VLkBP4XcUl0UUnrpoIDqbVcCwV8e3YAK-WjyXLkdOojFf_tVDgnN1rNGlOCLcHYzbhDP61hG0k1KEm_NJ63WlGXZR2igm1-VMn86Narz1TnZ/s1600/aacbdbb296284557f.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1183" data-original-width="1600" height="237" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhLu26s3k_6N-JQEBcXmQDQb6FlcOJYo-s127gud3Qr739x-q_nCmyi4w4jInf5PIoQc59KikCt2SXD6Bc0VLkBP4XcUl0UUnrpoIDqbVcCwV8e3YAK-WjyXLkdOojFf_tVDgnN1rNGlOCLcHYzbhDP61hG0k1KEm_NJ63WlGXZR2igm1-VMn86Narz1TnZ/s320/aacbdbb296284557f.png" width="320" /></a></div><p></p><p></p><p>I continued to work on animatronics through the year, and even travelled to Sydney Australia to do the install of the Jurassic World Exhibition. Working in Australia was one of those things I always wanted to do, so it's great to have been able to check that off the ol' bucket list. After that, however, I decided it was time to focus on Canada and stepped down from there. I returned to work a full time company out East, and that's just starting to ramp up. The first challenge sounds interesting, and we'll see if we can do it. No more animatronics for now, I guess, unless someone in Canada wants to help start something!</p><div class="separator" style="clear: both; text-align: center;"><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhBp_YlPb9WByXAttOyL2LQQ4GOW7XHctJCq9_mqrB8bBL3WL09-yXz1mNos7Z-rBjxBYP39F8Q3N6UVaC6xsh7eUV61q3G9E-5JuhQwAN4A_JsHRSM2s6Oy26mk6X6-YaAYZx3WML5cofFwSPEQVwhs6d4XgzGVciHzmv0BhwOyJOlIWT67-gSwBl8A2O1/s1600/ajw_gallery_01_1080x.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1067" data-original-width="1600" height="213" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhBp_YlPb9WByXAttOyL2LQQ4GOW7XHctJCq9_mqrB8bBL3WL09-yXz1mNos7Z-rBjxBYP39F8Q3N6UVaC6xsh7eUV61q3G9E-5JuhQwAN4A_JsHRSM2s6Oy26mk6X6-YaAYZx3WML5cofFwSPEQVwhs6d4XgzGVciHzmv0BhwOyJOlIWT67-gSwBl8A2O1/s320/ajw_gallery_01_1080x.png" width="320" /></a></div><p></p><p></p><div class="separator" style="clear: both; text-align: left;">Taxes taxes taxes... it has been a massive thorn for the last few years. But I think this one wraps up the US side finally - I hope so. It also took eight months! So sad as it is, that is all wrapped up. (What's doubly sad about it... I'm missing Burbank lately. Oh well. ;) )</div><p></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhXaJDCuI0LjCzPLUrOfWfnD6vKs9VcwsNrN_rc2nOmQIPwIAQBaPyXXBva-BpHqTskjEFVmzaeI6hpXmLZfcmbYlPKpIfxW-UvyPf48Et_wA4tmt3lCju_zmNx3zJmGnRpLO0xmA07lII2A3MaKuN1uD727sPFZljkUhW6sei3094zK8APJvDk6ApREx7U/s1600/aTax-Time_Blog.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1063" data-original-width="1600" height="213" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhXaJDCuI0LjCzPLUrOfWfnD6vKs9VcwsNrN_rc2nOmQIPwIAQBaPyXXBva-BpHqTskjEFVmzaeI6hpXmLZfcmbYlPKpIfxW-UvyPf48Et_wA4tmt3lCju_zmNx3zJmGnRpLO0xmA07lII2A3MaKuN1uD727sPFZljkUhW6sei3094zK8APJvDk6ApREx7U/s320/aTax-Time_Blog.png" width="320" /></a></div><p></p><p></p><div class="separator" style="clear: both; text-align: left;">We actually finally tried to get another license for Dragon's Lair TI, but the owners have increased the price for a license to far beyond any hobby project. (Actually, my email shows I tried twice ;) ). That killed that once and for all. Still, was glad to get a reply and am very grateful to ReadySoft for helping me fulfill a wish list item.</div><p></p><div class="separator" style="clear: both; text-align: center;"><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgPSmJ4dPrsKwge_4qfAt9vBIwMpxejWAcNVAbEG0s_-8Td3z86S-7bTN-FgNvSGeFkO-eAC9zFfwJqaO7WRNYYEbiopw6MX3ZveQykMWxZDX8hPv1dAa8tVFk4NQ8hotT03MXrlwq0JR87cxXknhpH1FxO_yjLhtCJ8oKmvo2pLMwGt-i281k0vuUrvl0-/s1555/a20190701_224521.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1200" data-original-width="1555" height="247" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgPSmJ4dPrsKwge_4qfAt9vBIwMpxejWAcNVAbEG0s_-8Td3z86S-7bTN-FgNvSGeFkO-eAC9zFfwJqaO7WRNYYEbiopw6MX3ZveQykMWxZDX8hPv1dAa8tVFk4NQ8hotT03MXrlwq0JR87cxXknhpH1FxO_yjLhtCJ8oKmvo2pLMwGt-i281k0vuUrvl0-/s320/a20190701_224521.png" width="320" /></a></div></div><p>I met a local robotic company owner, and he was really cool, but we haven't managed to catch up again. He's also a local Nabu computer fan, which is pretty fun.</p><p></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi152wxw3o5zICXYh59Qda8BJwQr3sqJ_XIjxx4ElVmEGicVJKH6DggaXaSsYirzi9M7IZb-xAIxl3f4qzFhOwSLHNpJRQAQGybgHiclzfBqfBMzlni48Q_WoO6om0a0Sa9zGwThFX_Qjo7Cy4Xl0FKWRpBk9ytVXd7O1N4eGbPsCKSrQxCAGd8oZ74Y0Xr/s1600/Clip0002.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1200" data-original-width="1600" height="240" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi152wxw3o5zICXYh59Qda8BJwQr3sqJ_XIjxx4ElVmEGicVJKH6DggaXaSsYirzi9M7IZb-xAIxl3f4qzFhOwSLHNpJRQAQGybgHiclzfBqfBMzlni48Q_WoO6om0a0Sa9zGwThFX_Qjo7Cy4Xl0FKWRpBk9ytVXd7O1N4eGbPsCKSrQxCAGd8oZ74Y0Xr/s320/Clip0002.png" width="320" /></a></div><p></p><p></p><div class="separator" style="clear: both; text-align: left;">Then I helped get an SG-1000 emulation cart working on the Phoenix - I believe it was bus timing and he managed to get it working, so that's pretty cool! </div><p></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjPRvfowic2QOOm2nJo_Qe4UBhpglFxKAzNbMPNa1ca-G6q4J75bx6sZPkaG3i4spGXzjGKuF4Ig3fv48XWS4Jv3q8jXmdRv3MHKYTIJo9yCqWZz-ibFfAgRkNVebTmOXf0GOFb0uT0TwvcAFP6Q_FsvCUhf0t-ICcK0Wyt60GoDz8fGEdLJLRZ5vrvCcke/s360/Sega_SG-1000.webp" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="209" data-original-width="360" height="186" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjPRvfowic2QOOm2nJo_Qe4UBhpglFxKAzNbMPNa1ca-G6q4J75bx6sZPkaG3i4spGXzjGKuF4Ig3fv48XWS4Jv3q8jXmdRv3MHKYTIJo9yCqWZz-ibFfAgRkNVebTmOXf0GOFb0uT0TwvcAFP6Q_FsvCUhf0t-ICcK0Wyt60GoDz8fGEdLJLRZ5vrvCcke/s320/Sega_SG-1000.webp" width="320" /></a></div><p></p><p>Besides Sydney I also visited Ottawa twice, just for fun! But the bigger trip was down to New Zealand where a very special friend got married. It was an awesome wedding, themed to Lord of the Rings and down at Hobbiton. I wished I was in costume too, but it was a great show and was so very cool to see everyone again. I missed them a lot.</p><p></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjM8QycJeXXcrw2avnpq5R534Tde1HSEX6NiLXyX5niQWkESUnfR5_FIeoZpg-3apMM5E-DBTHZSiFW6LgDxtEimrpsCv6QJT_nx5gJ7uO2HUxrXLGPQRMmg3WL52kxczBx32n1ZYBVwq4uo69H4Gep6SanfaLVgT99cZZ0b6zECGz9udnxbSgVUAEMXouo/s1600/aimg-1536162697-1401-3228-p-95B514EA-DAAA-9CB0-6839532442B3132A-2544003__aWxvdmVrZWxseQo_CropResizeWzk0MCw1MzAsOTAsImpwZyJd.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="902" data-original-width="1600" height="180" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjM8QycJeXXcrw2avnpq5R534Tde1HSEX6NiLXyX5niQWkESUnfR5_FIeoZpg-3apMM5E-DBTHZSiFW6LgDxtEimrpsCv6QJT_nx5gJ7uO2HUxrXLGPQRMmg3WL52kxczBx32n1ZYBVwq4uo69H4Gep6SanfaLVgT99cZZ0b6zECGz9udnxbSgVUAEMXouo/s320/aimg-1536162697-1401-3228-p-95B514EA-DAAA-9CB0-6839532442B3132A-2544003__aWxvdmVrZWxseQo_CropResizeWzk0MCw1MzAsOTAsImpwZyJd.png" width="320" /></a></div><p></p><p>Tree in the back yard fell down and landed on my townhouse roof! Fortunately, it did very minimal damage and the main concern - the roof - suffered just a few shingles. It came within inches of the windows so I was really lucky!</p><p></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEilQaFX8mXpvHzOsJI9mgStZ_w5wqD-wEIa0U8yHd67_zuZB3pPTa66LhDCY96ml6gqolp7s_e7Isb2W7buNomfQxTLx8QK9BbHwwtppPU4EV1Ti0mRyp0h2Q9UmfSkiRimm4HBQz3UpuYoR6wPg3YsEhhfvoe6z2x2Idr6vK2izytndXVjfSiXpXZaAQDQ/s1600/a20230615_054704.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="778" data-original-width="1600" height="156" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEilQaFX8mXpvHzOsJI9mgStZ_w5wqD-wEIa0U8yHd67_zuZB3pPTa66LhDCY96ml6gqolp7s_e7Isb2W7buNomfQxTLx8QK9BbHwwtppPU4EV1Ti0mRyp0h2Q9UmfSkiRimm4HBQz3UpuYoR6wPg3YsEhhfvoe6z2x2Idr6vK2izytndXVjfSiXpXZaAQDQ/s320/a20230615_054704.png" width="320" /></a></div><p></p><p>I also got a call from a company that pays people to act as experts - that was nice! Unfortunately the people in question didn't want technical information, they wanted inside business information. I didn't have that, so I didn't get paid. But I'm still available for that! ;)</p><p></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgFXDILOHMHy7aoW9kZMqbSRbSJUnCyeXJXKSXrgblUunwrxnYLwGQjBlDiybToJgmcrj7YirQBXAQwQ4xYPFPxI6uTifarRDC8JcEgX4WxePY_3Uwl36gVzPtH3wRyFGCfmDAHDeR7YmFQvlHjeu339xwp-Yl4oIvP_vCkBNOvvFg49deY0so0zuRXAeEm/s1600/aExpert.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="918" data-original-width="1600" height="184" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgFXDILOHMHy7aoW9kZMqbSRbSJUnCyeXJXKSXrgblUunwrxnYLwGQjBlDiybToJgmcrj7YirQBXAQwQ4xYPFPxI6uTifarRDC8JcEgX4WxePY_3Uwl36gVzPtH3wRyFGCfmDAHDeR7YmFQvlHjeu339xwp-Yl4oIvP_vCkBNOvvFg49deY0so0zuRXAeEm/s320/aExpert.png" width="320" /></a></div><p></p><p>An old buddy from high school visited from overseas, that was fun! I didn't realize when he planned it that it was just overnight, but hell, we still enjoyed hanging out!</p><p></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjK5ws7QnyG0bF2kob4B8TWve9LgrkO66eQpDy9QgYJXbheEZRIjRg4UcDfg2B8kTXMRnjQPqtFukj4ZPBCNdj4L1M8ORRkMeAavlb7T8RsDheKeCDwLnzjxG0kabcyRSNhdZSkHsw9tBm3kb_mAOClD28Y3eZaT-MCMRsIXsKiFVVztydPQj6xhrh1idWC/s1600/a189-1895097_friends-and-family-png-hanging-out-with-friends.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="528" data-original-width="1600" height="106" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjK5ws7QnyG0bF2kob4B8TWve9LgrkO66eQpDy9QgYJXbheEZRIjRg4UcDfg2B8kTXMRnjQPqtFukj4ZPBCNdj4L1M8ORRkMeAavlb7T8RsDheKeCDwLnzjxG0kabcyRSNhdZSkHsw9tBm3kb_mAOClD28Y3eZaT-MCMRsIXsKiFVVztydPQj6xhrh1idWC/s320/a189-1895097_friends-and-family-png-hanging-out-with-friends.png" width="320" /></a></div><div class="separator" style="clear: both; text-align: center;"><br /></div>Then I finally got Super Space Acer ColecoVision completed! It's got F18A sprites, multiple modes, endings, solid music... really pleased with it. That's been shipped off to CollectorVision and we'll see how that proceeds. I might need to get some artwork done for it, but I won't get to see Binky till January. CollectorVision might do some too... but we'll see. <p></p><p></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhtVPk6bN2jwaJxhd1zJ2HXT0Evv-Pqn_absU7xLkaA_f8JXVe9iKUCSvMhl3uXXvk2GsiSqSp8V3EtTGckZ2RAraK85GrvGl2CvYIYmuDvFz04ZhF6nYhwZeUezBZatM6i_ij1t9uoU_T_5AwBAXBCg14AJE4ezs6Kl0-C_zrTSH398WfXN4S_sc_mD3wS/s1600/aSSA01.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1068" data-original-width="1600" height="214" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhtVPk6bN2jwaJxhd1zJ2HXT0Evv-Pqn_absU7xLkaA_f8JXVe9iKUCSvMhl3uXXvk2GsiSqSp8V3EtTGckZ2RAraK85GrvGl2CvYIYmuDvFz04ZhF6nYhwZeUezBZatM6i_ij1t9uoU_T_5AwBAXBCg14AJE4ezs6Kl0-C_zrTSH398WfXN4S_sc_mD3wS/s320/aSSA01.png" width="320" /></a></div><p></p><p>I did try to hire a couple of artists for the sprite work... but finding pixel artists who also understand palette limitations proved very difficult. The two I actually paid did not seem to understand the restrictions, and dragged their feet on starting. I ended up rendering the ships in Second Life and taking screenshots. ;)</p><p></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhPfvmVQ54dn9F0UukMPrFtWTUae4Ty41xd0QTWY66OcDZvWajYi49M6mR_kdj-9tBZlSS-y5zoAnlhOZa0-nFt6OjyoDQ-6yZhp-VCfe6WW_LE36W-DaCUHt0G2Vzi7FcN67eF6SaoBTkS0NY959QD3sHBSGof3i8HHAVze6JRHXbXmIYN6U_uWko4GNx2/s1600/aClip0001.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="838" data-original-width="1600" height="168" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhPfvmVQ54dn9F0UukMPrFtWTUae4Ty41xd0QTWY66OcDZvWajYi49M6mR_kdj-9tBZlSS-y5zoAnlhOZa0-nFt6OjyoDQ-6yZhp-VCfe6WW_LE36W-DaCUHt0G2Vzi7FcN67eF6SaoBTkS0NY959QD3sHBSGof3i8HHAVze6JRHXbXmIYN6U_uWko4GNx2/s320/aClip0001.png" width="320" /></a></div><p></p><p>Next step there is porting to the TI. I started it a bit, got a workable toolchain for making a bank-switched cart and got part of it running already. The challenge there is the pages are only 8k versus the 16k pages on the ColecoVision. It makes packing the data harder, and all the page numbers are different. I still have to port the final fixes to the TI and try to get it working again.</p><p></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjFmMigG5TxoOwRi-II0eHWvTkpCMP8veQSjFyDD_hbKjcwTaqU4jxrMl06fJC6hFG8c3LVX_3JAzqyXJAC1ZV4cZjQ98Wp2xcpEFIt5pArEMy4P7MCY-VqnOrObTUzFthUeRoJreGaySYR6XOyfA-BR5LfrROt7rl87NrTJkAlTS2wuQSxm6Ps8MlJPo9c/s1600/aCIMG4273.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1200" data-original-width="1600" height="240" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjFmMigG5TxoOwRi-II0eHWvTkpCMP8veQSjFyDD_hbKjcwTaqU4jxrMl06fJC6hFG8c3LVX_3JAzqyXJAC1ZV4cZjQ98Wp2xcpEFIt5pArEMy4P7MCY-VqnOrObTUzFthUeRoJreGaySYR6XOyfA-BR5LfrROt7rl87NrTJkAlTS2wuQSxm6Ps8MlJPo9c/s320/aCIMG4273.png" width="320" /></a></div><div class="separator" style="clear: both; text-align: center;"><br /></div>Fortunately, the GCC compiler has seen some recent updates, and so there's a little more confidence in the 8 bit values. To that end, I've also created a cross-platform version of libTI99 that merges the TI and ColecoVision versions, with potential for others. I did not build the Coleco SSA on it, unfortunately, but I am building the TI version on it. It'll be nice to have them all with the same feature set.<p></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhPQSwrdtLUGYKWXaRxoZYYxYiWnMBFo7Wa5f1ui2g-9SQkWYSL1JC2ARo7N66IZMJFJE2oLjrz0-oOYXG46WICJkb8sL8G-vBEP6ovm9ZXKJc0pIz87XMMinHep1c2A7OQi5BK8ItQ16lC2h4-LqfHadnPztEYTJNheSn3at3yeNYgfmFBmvx3YdlMiMtY/s1600/a0_ewIqbJrZKoktTYeX.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em; text-align: center;"><img border="0" data-original-height="1156" data-original-width="1600" height="231" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhPQSwrdtLUGYKWXaRxoZYYxYiWnMBFo7Wa5f1ui2g-9SQkWYSL1JC2ARo7N66IZMJFJE2oLjrz0-oOYXG46WICJkb8sL8G-vBEP6ovm9ZXKJc0pIz87XMMinHep1c2A7OQi5BK8ItQ16lC2h4-LqfHadnPztEYTJNheSn3at3yeNYgfmFBmvx3YdlMiMtY/s320/a0_ewIqbJrZKoktTYeX.png" width="320" /></a></div><p></p><p></p><div class="separator" style="clear: both; text-align: center;"><span style="text-align: left;">Of course, through the year my main relaxation (???) has been working with the UFW. My raccoon Sila has upgraded to an evil cyborg and she's had a couple of stories for other people that developed her own character nicely. Danur didn't have much this year, and Oscar is just a backup referee... though it seems all three have fans, so that's nice! (Photos by Ember!)</span></div><p></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj2D8S9jQSyu46ss9AxCuJf3Me1h4hHfeysVMtgfQGDFy_b_i8ptEbPa4nz3dSd97F_PtFQ7SpSKce1M-shlGJ1gDHdqvG9xBefVVlH13H6pr4P2fjedNwRlOsa6yzoOnyDXCvnSJiCgh6Pcy95M-Wq8rShO_xip0Eobxq-_cTs1wYm1GTk0R7PisHtpZxI/s5057/aUFWSmall1%20on%20White.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1200" data-original-width="5057" height="152" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj2D8S9jQSyu46ss9AxCuJf3Me1h4hHfeysVMtgfQGDFy_b_i8ptEbPa4nz3dSd97F_PtFQ7SpSKce1M-shlGJ1gDHdqvG9xBefVVlH13H6pr4P2fjedNwRlOsa6yzoOnyDXCvnSJiCgh6Pcy95M-Wq8rShO_xip0Eobxq-_cTs1wYm1GTk0R7PisHtpZxI/w640-h152/aUFWSmall1%20on%20White.png" width="640" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="text-align: left;"><br /></span></div><div class="separator" style="clear: both; text-align: center;"><span style="text-align: left;">So that's a little better than last year! Hoping to be productive in 2024!</span></div><div><br /></div>Tursilionhttp://www.blogger.com/profile/16478174231304644316noreply@blogger.com0tag:blogger.com,1999:blog-7717886351507761714.post-79985097035176502202023-06-05T19:42:00.001-07:002023-06-05T19:42:16.018-07:00Managing Expectations<p>Hey, sorry, I've been neglecting you guys -- for a good six months it looks like!</p><p>It's been about 10 years now since I performed as "The Great and Powerful Trixie" in Second Life. I wanted a role that didn't tie me down, and didn't rely on other players to work. The show was successful, and Trixie performed in most of the existing MLP-based sims of the time. I ran two tours covering 3 or 4 years, with the last few shows adding some extra tricks.</p><p>The show evolved over the years, too, as I learned how to make the audience react correctly. Performing in Second Life is a different beast than real life - people have different expectations. For instance, I had two spots where someone needed to get on stage... originally I tried to get volunteers and pick on. But, this took a very long time. So eventually, I just revealed the sit object, and told them "first one there gets it". ;) And, many times, people were told they had to behave during the show or be ejected. So in the appropriate places, I added explicit permission to get loud and make noise.</p><p>I might add some specific pictures later. I know pictures would add a lot, but I don't have pictures of every effect.</p><p></p><div class="separator" style="clear: both; text-align: center;"><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEjBv3vHUTMLbbKTSIhpJduEV2z7Zo0J0EYnf62foGc2Uq621GPCdf-FIdqCnvos2ISzL_MHh_PmNmmRL9yTeumh2d26SM9ixOb9PNXg9nKH3H7KVksFQaAhayLv8gZpsNaT2FfJbfzH7z_SuTLqxObjmU9fQge6pPU06sE_SL-au2Gl6mH1EcfbxlCYGw" style="margin-left: 1em; margin-right: 1em;"><img alt="" data-original-height="1018" data-original-width="1920" height="170" src="https://blogger.googleusercontent.com/img/a/AVvXsEjBv3vHUTMLbbKTSIhpJduEV2z7Zo0J0EYnf62foGc2Uq621GPCdf-FIdqCnvos2ISzL_MHh_PmNmmRL9yTeumh2d26SM9ixOb9PNXg9nKH3H7KVksFQaAhayLv8gZpsNaT2FfJbfzH7z_SuTLqxObjmU9fQge6pPU06sE_SL-au2Gl6mH1EcfbxlCYGw" width="320" /></a></div></div><br />The basic premise of the show is a travelling magician, "The Great and Powerful Trixie". She's a unicorn of mid-range magical talent, but a love of stage magic. As such, she hauls her caravan from town to town, performing for tips (at least in my case).<p></p><p>The the show, she was introduced as a braggart who so offended the town that they wrote her off - all but two dim-witted ponies who lured a massive beast to the town to see Trixie fight it off, as she had bragged she could. Her magic was laughably inadequate, but Twilight Sparkle managed the feat, embarrassing Trixie and setting up a long term rivalry. But there was an often overlooked spark in this introduction... despite knowing that her stories were just stories, and despite knowing she had nothing in her magical arsenal that could harm the beast, <i>Trixie still tried to save the town.</i> She lost her caravan and she lost her reputation, but she didn't run away from the challenge. That was why I latched onto her as a favorite character.</p><p>Speaking specifically about the show, her magic show was never really shown to be very much. Only hopping on stage and bragging. I decided to create a real show, keep some of the character, and try to be entertaining. The first thing I needed to build was the caravan itself. Both home and stage, in the show it was demonstrated to transform on the fly. Making it do this was tricky, but I pulled it off and it made the first step in the show, as objects in SL rarely perform such feats. In addition, I kept the overlap of objects inside minimal, so when it was closed, it was <i>believable</i> that it all fit inside.</p><p><br /></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEhtn045EfFqZe4VBOn2jLMqAEMO7ORfVbn66AaKMZJlwnQNVoGEe6dC0jU_2rhI6m7N9GDXWr5hjVQQhO9kZwu9O3D01uImSAn4bPmdeepXcEHDLHGtOvX1p0NRiHh55swEb4T_b2Xyf3LN5TacFDId_wEFnHOTsKfWFYVA5wZsNIt4kyurdYwx1mu5Cw" style="margin-left: 1em; margin-right: 1em;"><img alt="" data-original-height="530" data-original-width="1000" height="170" src="https://blogger.googleusercontent.com/img/a/AVvXsEhtn045EfFqZe4VBOn2jLMqAEMO7ORfVbn66AaKMZJlwnQNVoGEe6dC0jU_2rhI6m7N9GDXWr5hjVQQhO9kZwu9O3D01uImSAn4bPmdeepXcEHDLHGtOvX1p0NRiHh55swEb4T_b2Xyf3LN5TacFDId_wEFnHOTsKfWFYVA5wZsNIt4kyurdYwx1mu5Cw" width="320" /></a></div><div class="separator" style="clear: both; text-align: center;"><br /></div><div class="separator" style="clear: both; text-align: left;">I actually put great care on the inside... I may have shown this before. Trixie has a large cushion to sleep on, a lighted mirror to prepare herself with, and several personal touches. She has copies of her show posters plastered all over the one free wall. But prominently near the cushion is a single piece of hand-drawn fan art from a young pony that Trixie keeps close and easy to look at. She also has a very old piece of beaten up paper tucked into her mirror with a message from an old mentor: "Follow your dreams, Trixie. Become great and powerful." These were never specifically shown to anyone, but were meant to show some character to anyone curious enough to peek inside. And yes, the mirror worked, in that Trixie would appear in it when she sat down. ;)</div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: left;"><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEgFZ6orJs_tIKHI7YTGhnevmdrbeUtOCp7XzaL8ua2pbGe_nAzIv-WMwihs2ayCSZCWBLShFtdsfTOe-8p323uYF9gxjBbkim23wBH3wKQye1uh8yzbWPQ3wPi4xMLzuyXN12ShcXjiQs0NjqjNqaIqs0J4k_CN-Uxe-E103MCwUH2wl1ZNcO755YGvjg" style="margin-left: 1em; margin-right: 1em;"><img alt="" data-original-height="768" data-original-width="1024" height="224" src="https://blogger.googleusercontent.com/img/a/AVvXsEgFZ6orJs_tIKHI7YTGhnevmdrbeUtOCp7XzaL8ua2pbGe_nAzIv-WMwihs2ayCSZCWBLShFtdsfTOe-8p323uYF9gxjBbkim23wBH3wKQye1uh8yzbWPQ3wPi4xMLzuyXN12ShcXjiQs0NjqjNqaIqs0J4k_CN-Uxe-E103MCwUH2wl1ZNcO755YGvjg=w299-h224" width="299" /></a></div><div class="separator" style="clear: both; text-align: center;"><br /></div>The show ran roughly 40 minutes long, and was driven by a pre-recorded audio soundtrack. I used a pop up cueing system with the timestamps written into it, and a stopwatch to keep myself on track. Hitting the cue button would trigger effects or lines of text, and I just needed to move Trixie to the correct location.</div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: left;">The show opened with the stage closed and a voiceover announcing it. At the appropriate moment, the stage would unfold, an Trixie would emerge with a blast of flame from a cloud of smoke. She would prance around the stage, welcome the audience, and then it was on to the first trick.</div><div class="separator" style="clear: both; text-align: left;"><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEhqHIncV6M5CwctxYSvL89gr8A_yn9mvq8QmHGfZ2JPSW8Liy35YHIx3VilgWaTPMaMqqf7GqFq7XyDK3V76P9L0ofHxHqVb7Hx_yzeRxIRSc2k5MOXwoBcrSE7xdt0z0YKnXa29GFtVbMvSMXOwXPbVqZovig4L-mFWxQz8lsL-F9jdZKPPlaeEwo4Qg" style="margin-left: 1em; margin-right: 1em;"><img alt="" data-original-height="512" data-original-width="1024" height="160" src="https://blogger.googleusercontent.com/img/a/AVvXsEhqHIncV6M5CwctxYSvL89gr8A_yn9mvq8QmHGfZ2JPSW8Liy35YHIx3VilgWaTPMaMqqf7GqFq7XyDK3V76P9L0ofHxHqVb7Hx_yzeRxIRSc2k5MOXwoBcrSE7xdt0z0YKnXa29GFtVbMvSMXOwXPbVqZovig4L-mFWxQz8lsL-F9jdZKPPlaeEwo4Qg" width="320" /></a></div><br /></div><div class="separator" style="clear: both; text-align: left;">The first was a simple card trick performed on the banner over the stage, and the only real magic in the show. This was a trick that I saw on the web once, and that three of us so-called engineers couldn't figure out for several passes! So I wanted to provide the same level of wonder (for anyone who didn't know the trick). The cards appear on the banner, and Trixie commands the audience to quietly remember one. After a puff of smoke, the card you selected is gone! I never heard how many people understood what was going on quickly enough to be "got", but I always moved on quickly to avoid anyone who was figuring out how it was done too easily. ;)<br /></div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: left;">We moved quickly on to the second trick, where I wanted to do a variation of "pull a rabbit out of a hat". To do this, I leaned on more lore from the cartoon. To get revenge on Twilight, Trixie tracked down and acquired a powerful amulet, which magnified her magic. Using this, she was able to enslave all of Ponyville until Twilight tricked her into removing it.</div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: left;">I summoned the amulet, and told the audience that using its power, Trixie would summon a horrible beast to the stage. She put down her hat, and mystical rune-filled circles surrounded it, causing a pillar of light to appear. When the light receded, Angel Bunny stood triumphantly! But, upon realizing that Trixie called him a horrible beast, he storms off stage, leaving Trixie to make a snide comment and move on.</div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: left;">For the third skit, I wanted to get the audience involved to keep their interest up. This was the trickiest one, because it's here that I really needed to subvert expectations. I'll explain.</div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: left;">The skit was literally lifted from "Father of the Pride" - the Scary Box 5000. The idea was, I would take a member from the audience, lock them in a big wooden box on the stage. Then I would summon a frame with 10 whirling saw blades, and send the box through it. On the other side, the box would fall open and...<div class="separator" style="clear: both; text-align: center;"><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEiW9DhjMCb6kSklZUEOk6yk9C0TF3c_0DC8PLW8QnuwJ7ytc3j1yzE7HYgdfz4ZE_VphpZYIqoLcvmWKd5ZdH-ww7ptu1lsHaJVseBYs8zcJ6T67b6c-mdACsXATfKqtRZ5k2_-fIPId1_rDBbnkIBa-sVJL_z8PfWYskflCEgbWl6BBmHGPOkyC6-j6g" style="margin-left: 1em; margin-right: 1em;"><img alt="" data-original-height="530" data-original-width="1000" height="170" src="https://blogger.googleusercontent.com/img/a/AVvXsEiW9DhjMCb6kSklZUEOk6yk9C0TF3c_0DC8PLW8QnuwJ7ytc3j1yzE7HYgdfz4ZE_VphpZYIqoLcvmWKd5ZdH-ww7ptu1lsHaJVseBYs8zcJ6T67b6c-mdACsXATfKqtRZ5k2_-fIPId1_rDBbnkIBa-sVJL_z8PfWYskflCEgbWl6BBmHGPOkyC6-j6g" width="320" /></a></div></div></div><div class="separator" style="clear: both; text-align: left;"><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEj1kmId_l-b7rwG1I6tvYdCoi_U0T-is3gNRw4h4uIdeQaPavP3Xcol5gsJ5xdAfqRp2Ss9xZcx-x9QWj4MB9v5CxOKwEmJGYxHIKP49lcsav9fNXkDogdFgJH1V62sp0JYtd44KVjgzUYFV3F6U9zMbzndx5R3KN7NAE3jwQmfpFVnrsmsP5c44T26Ew" style="margin-left: 1em; margin-right: 1em;"><img alt="" data-original-height="530" data-original-width="1000" height="170" src="https://blogger.googleusercontent.com/img/a/AVvXsEj1kmId_l-b7rwG1I6tvYdCoi_U0T-is3gNRw4h4uIdeQaPavP3Xcol5gsJ5xdAfqRp2Ss9xZcx-x9QWj4MB9v5CxOKwEmJGYxHIKP49lcsav9fNXkDogdFgJH1V62sp0JYtd44KVjgzUYFV3F6U9zMbzndx5R3KN7NAE3jwQmfpFVnrsmsP5c44T26Ew" width="320" /></a></div><br /><br /></div><div class="separator" style="clear: both; text-align: left;">Well, here's the problem. In the original trick, it would be the original, unharmed character. But in Second Life, there's no problem with someone moving through an object, players do it all the time. Yes, they could suspend disbelief for the sake of the story, but I wanted to <i>actually</i> surprise them.</div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: left;">My next thought was to teleport Trixie there instead. This might have worked, but even teleportation in Second Life results in movement. With Trixie on stage, people would have seen her move. (Indeed, even moving the guest out of the way behind the audience had to be done in several steps to make sure they were not briefly visible to anyone!) Even then, I wasn't sure. Anyone in Second Life could fly and teleport, it wasn't special to do a teleport trick, even if it was in the show.</div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: left;"><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEg9etb4QCPXZZlnVR0dkx-xEPXCEJn3GZQJiciOMZoK8Q1jRiLMQ4SUBJPWWQQWD-ykiypoyvwWcnY5dIFTHtVnyMYOf3sDfkt7seBRXO-b5Wb1rlSGWJwx6MVlQJlq1ZzhH3wq6aYomSGfX9h7pLiZ_JCXgrQhOWQtk6BP15ET4c1Her35ouX1F9UMeA" style="margin-left: 1em; margin-right: 1em;"><img alt="" data-original-height="512" data-original-width="512" height="240" src="https://blogger.googleusercontent.com/img/a/AVvXsEg9etb4QCPXZZlnVR0dkx-xEPXCEJn3GZQJiciOMZoK8Q1jRiLMQ4SUBJPWWQQWD-ykiypoyvwWcnY5dIFTHtVnyMYOf3sDfkt7seBRXO-b5Wb1rlSGWJwx6MVlQJlq1ZzhH3wq6aYomSGfX9h7pLiZ_JCXgrQhOWQtk6BP15ET4c1Her35ouX1F9UMeA" width="240" /></a></div><div class="separator" style="clear: both; text-align: center;"><br /></div>A comment from a friend finally solved the problem - I wouldn't take it so seriously. Inside the box was a cardboard cut out of a goofy looking Twilight Sparkle, which would then fall over. (Sadly, with apologies, I no longer know who created the art.) This provided the surprise to the audience, and a moment of laughter to anyone who knew that Trixie had a lifetime rivalry with Trixie. Later, in some shows I replaced Twilight with a dancing 2D cutout of Discord, and once I replaced her with an actual Sweetie Belle dancing in a bee costume.</div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: left;">This skit took a bit of effort. I lined up the box with the blades so I could create line textures that looked like the box was actually being cut, and multiple pitched sawblade sounds helped the illusion. I was pretty proud of this effect.</div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: left;">For the next skit, I turned Trixie's bravado up to 11. Most of this skit was actually interacting with the audience, as I welcomed two more onto the stage.</div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: left;">The set up was simple - Trixie would tell the "Story of the Two Sisters". All ponies know this, it is the legend of their very own leaders Princess Celestia, and Princess Luna. Celestia raises the sun, Luna raises the moon. Luna gets jealous of Celestia, attacks her, and is banished to the moon. This all happened a thousand moons ago. Trixie told it differently. Again, needing to defy expectations.</div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: left;">First, Trixie invited someone to play Celestia, and placed them on stage, then the same for Luna. She gave each of them a 'costume' to wear - which consisted very obviously (as obviously as I could) of hastily drawn wings and cutie marks on lined paper ripped from a notebook, and a rolled up paper horn. The goal was to look cheesy as possible.</div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: left;"><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEiltiuB038SmGIqJNmMkMX8RPlob-S4qa5KgxzAVJPxjA7m5TiM2UFB8HZrcD7cU0dpr6zWf9BBsHsd3nu8VsiwKjBlGRrtt7JCBjs0Y6iA6lLcr6RtjRYCyhKo9Lfh5Sm--9yACLG_p36a2K6_DNH64Og-6gC5NXdmnRSp7IJqE2W3CGraIME-d3EbaQ" style="margin-left: 1em; margin-right: 1em;"><img alt="" data-original-height="768" data-original-width="1024" height="240" src="https://blogger.googleusercontent.com/img/a/AVvXsEiltiuB038SmGIqJNmMkMX8RPlob-S4qa5KgxzAVJPxjA7m5TiM2UFB8HZrcD7cU0dpr6zWf9BBsHsd3nu8VsiwKjBlGRrtt7JCBjs0Y6iA6lLcr6RtjRYCyhKo9Lfh5Sm--9yACLG_p36a2K6_DNH64Og-6gC5NXdmnRSp7IJqE2W3CGraIME-d3EbaQ" width="320" /></a></div><div class="separator" style="clear: both; text-align: center;"><br /></div><div class="separator" style="clear: both; text-align: left;">Once in place, Trixie began telling the story. When time for Celestia to raise the sun, Trixie would let the guest say anything, then trigger a rather magnificent miniature sunrise from behind the stage. The guest's paper horn would actually light up and sparkle, implying they were doing it. The same for Luna, except the moonrise would eclipse the sun and block its glow.</div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: left;">With the stage now set, Trixie posed the question, "Who could help this terrible conflict between sisters?" After a beat, Trixie proposed that she herself did! She uses her magic to move the sun and moon slightly apart from each other, and each of their glows fills the sky, ending the jealous conflict.</div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: left;">This got the most reaction from the audience, some amused, some outright calling it out as incorrect. While the audience wrapped their heads around it, Trixie dismissed the helpers, and graciously allowed them to keep the costumes.</div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: left;">This took us to the finale, and I was heavily influenced by an "Epic Mix" of Disney's Let it Go. As the main beats kicked in on the soundtrack, Trixie's cape transformed into an icy version resembling Elsa's, and she raised a massive ice castle on the stage, block by block. In a cloud of smoke, she then poofed to the balcony, and waved to her adoring fans as the last beats faded out.</div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: left;"><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEgTZgucCWNaAtiyJqRTGy2QgKxGyULusQBU7E1lY-XT-hsyorLDlvGqWE7DhqOUy5Lyu-gKX5M4PpQnHJKDZWQ-w77VGQ6_osI1pYu8cph1VCyClFL6dxHpTlLBLU_XRARjYblfFb30yJLgmJyU7U4KGzzGIBGolafoSRIumSTnl6Xoi66n1KFyBy4mIg" style="margin-left: 1em; margin-right: 1em;"><img alt="" data-original-height="530" data-original-width="1000" height="170" src="https://blogger.googleusercontent.com/img/a/AVvXsEgTZgucCWNaAtiyJqRTGy2QgKxGyULusQBU7E1lY-XT-hsyorLDlvGqWE7DhqOUy5Lyu-gKX5M4PpQnHJKDZWQ-w77VGQ6_osI1pYu8cph1VCyClFL6dxHpTlLBLU_XRARjYblfFb30yJLgmJyU7U4KGzzGIBGolafoSRIumSTnl6Xoi66n1KFyBy4mIg" width="320" /></a></div><div class="separator" style="clear: both; text-align: center;"><br /><br /></div>Without hesitation, as the final soundtrack starts, the castle explodes in a flurry of snow and ice, and Trixie dons magical wings to fly back to the stage. As she lands, the gilded magical wings slowly derez line by line, and she bows in her new tuxedo. A massive glittering mortar launches from her horn into the sky, and the final bows are taken underneath a massive fireworks show. As the music comes to an end, a massive spray of mortars lights the sky, and Trixie vanishes in a final puff of smoke as the stage folds back up once again.</div><div class="separator" style="clear: both; text-align: left;"><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEgqiMZ7MDi81pcrk8AjRq1XUebL4riUGt8NaL3SXCGX1hRRi4jqGFErS1GArbYFe-B9OQeqEOS2XJ32rMNcX0eEEkDBGOst-HURSEy1EYrmrYwpqlVxwzVTtMO1j7eCx-ps_qxQZJyLOFK5r-KzD4o5lmpHpBLRd4KqpE0oG8UOgr8AKtTW9xAWSuti2A" style="margin-left: 1em; margin-right: 1em;"><img alt="" data-original-height="530" data-original-width="1000" height="170" src="https://blogger.googleusercontent.com/img/a/AVvXsEgqiMZ7MDi81pcrk8AjRq1XUebL4riUGt8NaL3SXCGX1hRRi4jqGFErS1GArbYFe-B9OQeqEOS2XJ32rMNcX0eEEkDBGOst-HURSEy1EYrmrYwpqlVxwzVTtMO1j7eCx-ps_qxQZJyLOFK5r-KzD4o5lmpHpBLRd4KqpE0oG8UOgr8AKtTW9xAWSuti2A" width="320" /></a></div><div class="separator" style="clear: both; text-align: center;"><br /></div><div class="separator" style="clear: both; text-align: left;">The show was well received, and many ponies attended multiple performances. These ponies helped A LOT. They knew what was supposed to happen and prompted those who didn't, letting me get a smoother show while staying in character.</div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: left;">I did three custom shows, as well. One year, there was a single Halloween (or, Nightmare Night as they called it) show. For this, I degraded the stage with dirtier, decayed textures.</div><div class="separator" style="clear: both; text-align: left;"><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEgYVopEmMNS94BFRc0hCt4XdgIfxdNlnY1Q3UYQZAbDjBAOcodAdh18jXpKZvUfkkTM0kp99-htN9088C9XdYqOHkepat541Is2Yhq7RB4l6O6HytG8Kc51ItF70exMWkrFr2DlT44T_Sz2-TztBjMffLIwyLIyjS9TTpPavR1L4Klpiv4COM-1ZgEPYQ" style="margin-left: 1em; margin-right: 1em;"><img alt="" data-original-height="768" data-original-width="1024" height="240" src="https://blogger.googleusercontent.com/img/a/AVvXsEgYVopEmMNS94BFRc0hCt4XdgIfxdNlnY1Q3UYQZAbDjBAOcodAdh18jXpKZvUfkkTM0kp99-htN9088C9XdYqOHkepat541Is2Yhq7RB4l6O6HytG8Kc51ItF70exMWkrFr2DlT44T_Sz2-TztBjMffLIwyLIyjS9TTpPavR1L4Klpiv4COM-1ZgEPYQ" width="320" /></a></div><br /></div></div><div class="separator" style="clear: both; text-align: left;">I changed the card trick into a jump scare - instead of changing to the second set of cards, it made a loud spooky noise and flew ghostly Nightmare Moons at the screen. Unfortunately, due to lag this trick didn't fire. I changed the on stage sparks to red, to look like blood spraying up. I changed the Twilight inside the Scary Box 5000 to a fully articulated pony skeleton, which fell apart on stage after the reveal.</div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: left;">Then I changed up the ending. At the question point of the Story of the Two Sisters, Trixie still declared herself the savior, but this time she took action. Surrounded by a ball of plasma, she lifted into the air and transformed herself into Nightmare Trixie.</div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEjjSOAdYZ5ocVnH0q8LtxPHjJAsnIu_lANJatGMqyysoi_eK4Qrxq-ZL_f_PDthg8M3dXuDWPpYArFCXjobTAe34wg8A2noUEKat_Duzd0B2_eeTbktZjvgBzdyhv-THDB2oxKPxUK136_iSAyrd7xH5ZmcnaFIRRGaj3o3z4Fz0u0EqI9cXFL8T2gUqA" style="margin-left: 1em; margin-right: 1em;"><img alt="" data-original-height="768" data-original-width="1024" height="240" src="https://blogger.googleusercontent.com/img/a/AVvXsEjjSOAdYZ5ocVnH0q8LtxPHjJAsnIu_lANJatGMqyysoi_eK4Qrxq-ZL_f_PDthg8M3dXuDWPpYArFCXjobTAe34wg8A2noUEKat_Duzd0B2_eeTbktZjvgBzdyhv-THDB2oxKPxUK136_iSAyrd7xH5ZmcnaFIRRGaj3o3z4Fz0u0EqI9cXFL8T2gUqA" width="320" /></a></div><br />Then she fired magical beams at the two ponies on stage, transforming them into fully realized versions of Nightmare Moon and Daybreaker, the evil versions of the Princesses. (For this, I had friends play the additional roles). This ended the show with the Nightmares in charge, and was a surprise twist that nobody seemed to expect. I had hoped to repeat this show, but it turned out to be a one time thing.</div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: left;">I also did a show in the Fallout: Equestria world. For this I reworked the stage into an armored machine... although I didn't change up the actual effects much.</div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: left;"><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEjV3EQKJzihk0iEZYnq1rO-CLy6_fSZUi2g-IMtfaHYibjak33fR7yCzcVi41gRZGerBbPhW9wCj9c49bc9ZtWQdEX6EurBg0YZBgRPUhwob7zquEZkuniDwE0hlsAs39mgY6qmppS9RhE2HWmR8JoMXrL6Zwpcr6dTem8QVTUyZQRXHTreLmS19iPGoQ" style="margin-left: 1em; margin-right: 1em;"><img alt="" data-original-height="1200" data-original-width="1600" height="240" src="https://blogger.googleusercontent.com/img/a/AVvXsEjV3EQKJzihk0iEZYnq1rO-CLy6_fSZUi2g-IMtfaHYibjak33fR7yCzcVi41gRZGerBbPhW9wCj9c49bc9ZtWQdEX6EurBg0YZBgRPUhwob7zquEZkuniDwE0hlsAs39mgY6qmppS9RhE2HWmR8JoMXrL6Zwpcr6dTem8QVTUyZQRXHTreLmS19iPGoQ" width="320" /></a></div><div class="separator" style="clear: both; text-align: center;"><br /></div><div class="separator" style="clear: both; text-align: left;">For the final show, which was only performed twice, I did a Christmas version (or, Hearth's Warming Eve in their canon). For this I decorated the stage with snow and Christmas lights, and composed a new story to tell.<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEjq7I6FetLXEwtXCIk8CArYC-WcXz4UvlhcnsrK-oD7lNubq0pNnF5QXJNuwlM2r-EgeF5Jme71Cc19d77Khq6p2oldsFq2lzpc3eBZ9HrpDBuYtaNS_ij7Iq7fR8Rt56ieOFcnUyXrvd342LlYWS8i-D2Z_lkgan2SPEO9F6nwKNCV74cPq94LNOpf4w" style="margin-left: 1em; margin-right: 1em;"><img alt="" data-original-height="867" data-original-width="1343" height="207" src="https://blogger.googleusercontent.com/img/a/AVvXsEjq7I6FetLXEwtXCIk8CArYC-WcXz4UvlhcnsrK-oD7lNubq0pNnF5QXJNuwlM2r-EgeF5Jme71Cc19d77Khq6p2oldsFq2lzpc3eBZ9HrpDBuYtaNS_ij7Iq7fR8Rt56ieOFcnUyXrvd342LlYWS8i-D2Z_lkgan2SPEO9F6nwKNCV74cPq94LNOpf4w" width="320" /></a></div><div class="separator" style="clear: both; text-align: center;"><br /></div><div class="separator" style="clear: both; text-align: left;">The new stage had text prompts on the banner, though I don't think they helped much. The new story related the story of Hearth's Warming Eve - where Earth Ponies, Pegasi, and Unicorns come together in unity to defeat the evil ice-bringing Windigos. Although this one let me bring up three members of the audience, I didn't feel it flowed as well... and indeed the only recording completely failed to look up and see the Windigos circling. ;)</div><div class="separator" style="clear: both; text-align: left;"><div class="separator" style="clear: both; text-align: center;"><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEhgYZBWmqD9zL8gcrpgbmYyxhzLwuMxyvUtWIiROpYI9sXQk7cQMXZQcixz2BItBZn2Pkamzabom0kM5XlSdMU0EI3PSKT-X8FQUrQg6IaxpUDVU7XiSfgXqK9Lwmv5HDH8NZlaa5J9_udKxVFoFQoRnGXFx98IUkd_fq2otTpcNpeQbAfFU2ig7cY22w" style="margin-left: 1em; margin-right: 1em;"><img alt="" data-original-height="1018" data-original-width="1920" height="170" src="https://blogger.googleusercontent.com/img/a/AVvXsEhgYZBWmqD9zL8gcrpgbmYyxhzLwuMxyvUtWIiROpYI9sXQk7cQMXZQcixz2BItBZn2Pkamzabom0kM5XlSdMU0EI3PSKT-X8FQUrQg6IaxpUDVU7XiSfgXqK9Lwmv5HDH8NZlaa5J9_udKxVFoFQoRnGXFx98IUkd_fq2otTpcNpeQbAfFU2ig7cY22w" width="320" /></a></div><div class="separator" style="clear: both; text-align: center;"><br /></div>Some locations really got behind it. There were few experiences in Second Life that let you live parts of the actual show, and a Trixie performance was one. There was another Trixie who tried to do their own. Their Trixie was much more bumbling and included her later friend Starlight Glimmer. It was a slick and impressive show but I felt that it missed the mark on Trixie's character. It only had a single performance as well.<br /><br /></div><div class="separator" style="clear: both; text-align: left;">Anyway, if you'd like to watch a couple of captures of the show, I'm sad to say we never got a perfect one. But there are a few here in this playlist: https://youtube.com/playlist?list=PLr4KHMd3l8gi8hfxlBapW5YloWp8utdxC</div><div class="separator" style="clear: both; text-align: left;"><br /></div><br /></div><br /><br /><br /><br /></div><div class="separator" style="clear: both; text-align: left;"><br /><br /><br /><br /></div><br /><p></p>Tursilionhttp://www.blogger.com/profile/16478174231304644316noreply@blogger.com0tag:blogger.com,1999:blog-7717886351507761714.post-75755536266432274642022-12-13T09:06:00.003-08:002022-12-13T09:06:38.290-08:002022 Was Kind of a Quiet Year<p></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEiTCS-JxQZ859dm5YQMySuZwnCZ5bQ2WrGfxrTEaFv7OkeTnMm3-toPQegNvPcM31U9KpzuEKK0kLEIykWEqvYgpuwm6pElXG5-33CvizbCBtOnfwTgZEQARShoOtjTVHQFjGABNBol5P9mqmZgN-HU_2BKoDcNBwZNV-0SbONsFSCOlbj-FmBYO7S4EA" style="clear: right; float: right; margin-bottom: 1em; margin-left: 1em;"><img alt="" data-original-height="139" data-original-width="362" height="87" src="https://blogger.googleusercontent.com/img/a/AVvXsEiTCS-JxQZ859dm5YQMySuZwnCZ5bQ2WrGfxrTEaFv7OkeTnMm3-toPQegNvPcM31U9KpzuEKK0kLEIykWEqvYgpuwm6pElXG5-33CvizbCBtOnfwTgZEQARShoOtjTVHQFjGABNBol5P9mqmZgN-HU_2BKoDcNBwZNV-0SbONsFSCOlbj-FmBYO7S4EA=w227-h87" width="227" /></a></div>I didn't really get as much done as I'd hoped, but in going through it, there were still a few cool things. Just some of the better stuff...<p></p><p>Learned Yocto in order to implement a Coral AI accelerator for a client.</p><p></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEgBrpcqiRuRSeEUFcqozuwY7wjEM9w3OLVFUuL33x0mhPlZYxHQaQRph4DqbJkBR6PZ8rGn_DPlNRTyT30LBOkcQ6IY9Of5BTnc1c7hJHPKgazK7fHSqa7FlhjUspgAT5JScMRMexpOcgdnWkW0NpoMUU_yAD1Z7B5IfAqE0M3kgPEEcYBJmWghAFlEiA" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img alt="" data-original-height="233" data-original-width="216" height="130" src="https://blogger.googleusercontent.com/img/a/AVvXsEgBrpcqiRuRSeEUFcqozuwY7wjEM9w3OLVFUuL33x0mhPlZYxHQaQRph4DqbJkBR6PZ8rGn_DPlNRTyT30LBOkcQ6IY9Of5BTnc1c7hJHPKgazK7fHSqa7FlhjUspgAT5JScMRMexpOcgdnWkW0NpoMUU_yAD1Z7B5IfAqE0M3kgPEEcYBJmWghAFlEiA=w141-h130" width="141" /></a></div>Took a trip to Vancouver, and another to my hometown, and one last one to Los Angeles to close out some business. But Covid really restricted the personal travel still, this year.<p></p><p>I did continue with the UFW work on Second Life. I suspect I am spending too much time with this, and I am going to need to decide - fun or projects. ;) Some pissy people have me questioning whether it's actually fun anyway. I'll decide by year end. </p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEhgKTqd2a0As4VnUJQLJhYF8e_ytUkqCX0LXE6Wkl2GAI4nRzC2jjJTvyiEIddd89LI01tbSvrFMm5viSwNEBBVk6JN3Ep16VkPLV0fEfglh_TmHpU8Xg_UcQPTnu2hRKNkGAknoOy8wFxj1mz_j8A2lhabrM_iQD1cyA3f1Ceqr_xO5inu_3LN8NBNIw" style="clear: right; float: right; margin-bottom: 1em; margin-left: 1em;"><img alt="" data-original-height="206" data-original-width="245" height="113" src="https://blogger.googleusercontent.com/img/a/AVvXsEhgKTqd2a0As4VnUJQLJhYF8e_ytUkqCX0LXE6Wkl2GAI4nRzC2jjJTvyiEIddd89LI01tbSvrFMm5viSwNEBBVk6JN3Ep16VkPLV0fEfglh_TmHpU8Xg_UcQPTnu2hRKNkGAknoOy8wFxj1mz_j8A2lhabrM_iQD1cyA3f1Ceqr_xO5inu_3LN8NBNIw=w135-h113" width="135" /></a></div><p></p><p>I added some vision-impaired enhancements to my TI emulator - Classic99. It has background noise (which on the real console was an interesting indicator of activity), and I added a screen reader that works most of the time! It received a bit of attention that was quite pleasing! I have only one vision impaired user, but he went so far as to create a podcast describing it and demonstrating its use.<br /></p><p></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEhq5cxCSaXGIU4jGHVgm46hC0kBTudHN0A-6RufgmYS7qIsjcmwNeatncgvp1gil7UrcGJqepWLLfkm9qXM56vFl1y65s5pQrc2DlJKqCSgm7VlVs3KFGCSyVj9yH1NR0rQV4XhXPx0W1H8575buiPq0G8if2GemEl-H4B1ceHH5EBwbuo3Hve4Pys_DQ" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img alt="" data-original-height="1000" data-original-width="1000" height="85" src="https://blogger.googleusercontent.com/img/a/AVvXsEhq5cxCSaXGIU4jGHVgm46hC0kBTudHN0A-6RufgmYS7qIsjcmwNeatncgvp1gil7UrcGJqepWLLfkm9qXM56vFl1y65s5pQrc2DlJKqCSgm7VlVs3KFGCSyVj9yH1NR0rQV4XhXPx0W1H8575buiPq0G8if2GemEl-H4B1ceHH5EBwbuo3Hve4Pys_DQ=w85-h85" width="85" /></a></div>Because I was worried about losing access to my domains at the end of last year, I started up Fossil Line Systems (https://fossillinesystems.com/). The hope was to use it for local contracting, though I've been pretty busy. I also ended up not losing access to my domains, so I am a bit torn whether to keep HarmlessLion active or not. I have to admit I quite like the new logo, and I like the concept of advancing.<p></p><p>I did do a couple of other contract projects. I did a little bit of small animatronic work for a local production that I can't really talk about yet... but I also got to work on a brilliant new animatronic. It was fun to work on a big machine again, and with a skilled team that knows what they are doing.</p><p></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEjaIGSyFgp_vLew7RYidGTj20yvDuUc7RR-T3uZGDOP0uU4QtbLelz1b0zDP-vbd_PrM4VfkREFCj7gfgJyPr4DCjP9nqUzw9pP2uCukC_EvjQB6mPEloYQnLyb4xMe2W1xHdaVl3RTFk_vAR5JYrpIAZlx_7cETZbIZ-l7yL61Jnhx44DmZKS8jme2RA" style="margin-left: 1em; margin-right: 1em;"><img alt="" data-original-height="159" data-original-width="318" height="235" src="https://blogger.googleusercontent.com/img/a/AVvXsEjaIGSyFgp_vLew7RYidGTj20yvDuUc7RR-T3uZGDOP0uU4QtbLelz1b0zDP-vbd_PrM4VfkREFCj7gfgJyPr4DCjP9nqUzw9pP2uCukC_EvjQB6mPEloYQnLyb4xMe2W1xHdaVl3RTFk_vAR5JYrpIAZlx_7cETZbIZ-l7yL61Jnhx44DmZKS8jme2RA=w469-h235" width="469" /></a></div><div class="separator" style="clear: both; text-align: center;"><br /></div><p></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEiI_MMZl0aAYt0rAdAU3x7ZK116Lu-Kc6ll3h2GVLWFbMBiz16Bjk3Y9VPCLw9N7uDumvasITdZchCoGaDSu7rV8W8rOKYWyP7hkNjvjdklm7xnQyWe9P4bULvaYfppsZuMEq-1hZNTEPTXlLJGluq120stgLUPB51IhCF0n6KOcb1uRbIzm7WUg9vSGA" style="clear: right; float: right; margin-bottom: 1em; margin-left: 1em;"><img alt="" data-original-height="152" data-original-width="331" height="74" src="https://blogger.googleusercontent.com/img/a/AVvXsEiI_MMZl0aAYt0rAdAU3x7ZK116Lu-Kc6ll3h2GVLWFbMBiz16Bjk3Y9VPCLw9N7uDumvasITdZchCoGaDSu7rV8W8rOKYWyP7hkNjvjdklm7xnQyWe9P4bULvaYfppsZuMEq-1hZNTEPTXlLJGluq120stgLUPB51IhCF0n6KOcb1uRbIzm7WUg9vSGA=w163-h74" width="163" /></a></div><p></p>I guess the last notable thing I did wasn't really something I had to do myself at all - but I sold Cool Herders as a property to Piko Interactive. It was really kind of them, and I need to work on some extra tasks for them as a condition of it. Kind of a relief anyway, since now I can strike several potential projects from my todo list, hehehe. ;)<p></p><p>Anyway... yeah. Really quiet year. I think I need to step it up in 2023. ;)</p><p><br /><br /><br /></p>Tursilionhttp://www.blogger.com/profile/16478174231304644316noreply@blogger.com0tag:blogger.com,1999:blog-7717886351507761714.post-47477951388735237602022-10-06T19:48:00.004-07:002022-10-06T19:48:52.149-07:00How I started in Software<p>I'm writing this instead of sleeping. Be grateful! ;)</p><p>I was thinking about why I get asked so many questions about software, and what makes my answers any better than someone else's (the answer is battle scars, in case you wondered). And that got me thinking to my early days.</p><p>When I got out of the armed forces in '95, I knew that I wanted to work on software. Computers were what I was best at, after all. I bought my first PC (before that I was staunchly anti-PC, going through my TI, Atari ST and Amiga 2000 and defending them voraciously). Without Windows 95, I might have kept that attitude, honestly... but that's another story.</p><p>I had found a free small C compiler - GCC what? For DOS? Hah! But this compiler let me build simple programs with 64k code and 64k data (because that's how the 8088 segmented memory). I was largely working from books, which is like printing out a wiki and sticking the pages together, but there's no search.</p><p>Anyway, this was the period that I published on my 5MB website my epics Super Sales Acer, Super Sled Acer and Super Shooting Acer. You can actually find them on archive.org in playable form, and of course still on my website (nothing I have released is abandonware, and anyone who says otherwise is lying to you.)</p><p>I'm going to link Super Sled Acer, cause it's relevant:</p><p>https://archive.org/details/msdos_SuperSledAcer_shareware</p><p>For some reason, this game received my first professional review. I can't remember where, or who the reviewer was, and sadly this was before I started printing everything off. But hoo-boy, was he mad! I remember phrases like "before Doom and anything good, this is what shareware meant", and "fun for maybe 5 seconds, then you turn it off to play anything else".</p><p>I was baffled... who asked him to review it? But from my standpoint, I quite liked it. I still do, actually. First off, it was a port of my TI game, with muchly improved graphics and animation. Secondly, it's a really silly game. And thirdly it was my first go at joystick controls. Complex? No. But I defy you to pass the last stage.</p><p>Anyway, while deciding what to do about it, I noticed that the system requirements he had posted were ridiculous. As I noted, I only had an 8088, 64k compiler. As such, I wrote my games to run in CGA or VGA mode (automatically!), and only a PC XT was needed. Sound support was limited to a simple PC speaker beep. But he had listed 4MB RAM, 486 PC with VGA and Sound Blaster card.</p><p>I wrote in and noted to them that they were welcome to say what they liked about the game, but they had grossly mis-represented the minimum system specs. They updated the specs as I requested, but about a week later the review was gone. I guess bashing on a PC-XT game in 1995 wasn't quite as exciting a thing.</p><p>But anyway, time went on. I began to think that I needed to get more notice. I did something which is probably still the most audacious thing I've ever done. I wrote up a flyer describing myself as the best of the best for software, and I faxed it out (yeah, remember fax? Of course not, you're way too young) to every game company I could find information for.</p><p>I wish I had kept that, too. But my hard drive was always full, and I deleted a lot of things from those days. Those were the "A gigabyte? Yeah, THAT'D be nice" days.</p><p>Anyway, I only got one contact. A recruiter for Visual Concepts reached out, and we had a number of pretty nice conversations. I sent them samples of my code - the above mentioned games, and my work-in-progress TI emulator from the Amiga (Ami99, now Classic99, could boot the raw console and run TI BASIC and A-Maze-Ing, very slowly.)</p><p>Most of the feedback was pretty decent. They felt my code showed inexperience (valid). They thought it was all very simple code -- I asked what was wrong with simple code and the recruiter didn't know. We'll come back to this.</p><p>Everyone's comments were generally very constructive, though. Except for one fellow. Again... I really brushed this guy the wrong way. All of his comments were ridiculously hostile. To his credit, the recruiter filtered nothing, though I think he was a little embarrassed when I asked what this one guy's problem was. The one feedback that stuck with me was "The worst programmer in the world could have written this!", about Classic99. Even then I thought it was a stretch to think that the worst programmer could create a functioning CPU and video core from scratch -- or even plot a color pixel on a bit-plane display for that matter. But on the other hand, Classic99 is still around and Visual Concepts is not, so what (apparently) do I know? ;)</p><p>I wondered for a long time what set that guy off, and I think that one statement really clarifies it. My fax promised I was the <i>best</i> programmer in the world, and this guy apparently felt that was a challenge of some sort. I guess I sort of get it, but even I wouldn't be that mean about it.</p><p>I ended up getting a local job installing networks for local businesses. This was a good way to get a lot of PC experience quickly - I mean, on my first week I needed the boss to help me understand how to sys a C drive to get DOS back up. But it wasn't long before I was doing everything myself. It was a good company and will always be remembered fondly.</p><p>But I still wanted to write software, and just before I darted off to my first Canadian software job, a good friend stole me down south to work in the States. I was really excited, until I got there and realized I didn't even know C++ yet. I can still remembering sitting there with a C++ book (remember, the printed wiki with no search function), and going through step by step. I wrote test programs I could step through until I understood how classes worked, how inheritance worked, what happened when you derived a class, and so on. All the same, I was really, really depressed. Maybe this was all too much for me, I feared.</p><p>But it wasn't, and I did master it, and a number of other techs I'd never seen before. From that telephony background, through to robotics and animatronics, I learned that I never get to work on a project I know how to do. So the first couple of weeks are ALWAYS miserable as I wonder whether I can actually learn this. So if you are feeling that, JUST EMBRACE IT.</p><p>So I've got about 25 years professionally now, and a good 5-10 before that depending on how much of it you want to count. What's the biggest thing I've learned?</p><p>KEEP. IT. SIMPLE. STUPID.</p><p>And you can read those last two words in every context, they all work.</p><p>But seriously. The downfall of code is complexity. The code you write needs to make sense when you write it. It needs to make sense when you read it six months from now. It needs to make sense to the next person who reads it. You have to be able to debug it.</p><p>Simple code meets all of these in the easiest manner. It's generally easier to write. It's easier to understand. It's easier to debug (particularly because simple code lends itself well to testing just parts of it). And nine times out of ten, the compiler can make it run faster too.</p><p>The whole art of programming is condensing complex tasks into simple steps. Don't make your own task harder. Bed time now.</p><p><br /></p>Tursilionhttp://www.blogger.com/profile/16478174231304644316noreply@blogger.com0tag:blogger.com,1999:blog-7717886351507761714.post-902328259276274082022-09-13T22:33:00.006-07:002022-09-14T09:08:27.566-07:00Cool Herders Graphics Experiments<p>Way back in the day, I created a silly little demo for the Sega Dreamcast using then then-new KOS development kit. My buddy Binky came up with the design and all the artwork, and we put the original demo together in like two weeks.</p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEggHdEhPjjObNp4wdXvkElUDt4HVO4Dv-poJRJB7oHrUjsFq-edOyWHG_d30iTODZVM6jJkOXdt8onLWL2iewjWaRd7-Q2bIDlzG_WCT7lpiNT8q9mSLyR481DGxB_wReOAhnITzK9LPfg9quL91BOc7gTh607NFhmeRm41f4cPHDs4C96KY3vjmy5koA/s480/newcool1.jpg" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="360" data-original-width="480" height="240" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEggHdEhPjjObNp4wdXvkElUDt4HVO4Dv-poJRJB7oHrUjsFq-edOyWHG_d30iTODZVM6jJkOXdt8onLWL2iewjWaRd7-Q2bIDlzG_WCT7lpiNT8q9mSLyR481DGxB_wReOAhnITzK9LPfg9quL91BOc7gTh607NFhmeRm41f4cPHDs4C96KY3vjmy5koA/s320/newcool1.jpg" width="320" /></a></div><p>Let's zoom in a little on what's going on there...</p><p></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhnbnLfyMrEwSwPTKj9AVWfPR37JxkJ1eQhbzsRyIhqnHLaZ6Mjt_QVTqxJA5t5nnpdfjQoOC0MIEfotvZ-_SZ5ja0SGwxADB0xhlDcY29yKQ5lOkVp61Yc_eI0BL_K3i0ZqRYoU2mKBeNQyXZy-Gy96mhTm9E5XVLAK_-yrY6zb0PYa8-90X3ytpfM0Q/s275/t.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="250" data-original-width="275" height="250" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhnbnLfyMrEwSwPTKj9AVWfPR37JxkJ1eQhbzsRyIhqnHLaZ6Mjt_QVTqxJA5t5nnpdfjQoOC0MIEfotvZ-_SZ5ja0SGwxADB0xhlDcY29yKQ5lOkVp61Yc_eI0BL_K3i0ZqRYoU2mKBeNQyXZy-Gy96mhTm9E5XVLAK_-yrY6zb0PYa8-90X3ytpfM0Q/s1600/t.png" width="275" /></a></div><div class="separator" style="clear: both; text-align: center;"><br /></div><div class="separator" style="clear: both; text-align: left;">We've got some nice overlaps going on there. Boxes overlapping the ground, trees overlapping the ground and boxes (both above them and beside them). There are probably lots of ways to do this, but I'm going to tell you how I did it. It's actually pretty basic.</div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: left;">The Dreamcast was the first 3D hardware I worked with, and knowing that, I made all the graphics out of polygons. Each tile/sprite is just two triangles using flat projection, but with the Z axis tilted slightly. The top of the tile is closer to the screen than the bottom. As a result, for free, we get nice overlaps of the sprites and the tiles. It's as if they are actually (slightly) standing up!</div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj0bsG_8gBEASoAKyIDrCsqaXkSwT4vDSezj1bI-_zDVs-oiqcQ3FN_e8iu6raISW6PJfXQYtzKamAINMRyJIs9QwS-7Z-F68OXV2ViimoVK4jdeIFE90f7Dy7bPu8tKphf89Zte8zA7gFSUAV2yb9X3UK95Q5IrVetAX-WC5DE5s4tV_VNyPJghMPnQw/s1117/IMG_20220913_223252522.jpg" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="467" data-original-width="1117" height="134" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj0bsG_8gBEASoAKyIDrCsqaXkSwT4vDSezj1bI-_zDVs-oiqcQ3FN_e8iu6raISW6PJfXQYtzKamAINMRyJIs9QwS-7Z-F68OXV2ViimoVK4jdeIFE90f7Dy7bPu8tKphf89Zte8zA7gFSUAV2yb9X3UK95Q5IrVetAX-WC5DE5s4tV_VNyPJghMPnQw/s320/IMG_20220913_223252522.jpg" width="320" /></a></div><div class="separator" style="clear: both; text-align: center;"><br /></div><div class="separator" style="clear: both; text-align: left;">This caused some people to make funny faces at me, but nobody ever suggested a simpler idea. (Some people suggested multiple textures for different situations, but why?? Extra work, extra video RAM, extra processing... what?</div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: left;">So this was on the Sega Dreamcast. We had 8MB of video RAM... so we ended up deciding on a basic system with 3 pages of tiles (originally the three had meaning, but in the end only the third page is special). Full 24-bit (I think it was 16 bit on the DC), and lots of wasted space. Each page has 4 pages of animation that plays continuously, and none of this causes the Dreamcast to even notice that you are there. ;)</div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgO_2kZf_DyVeCmcv-Ra163hhTOLmuaW0Gf_R1afY9GuyCFwI6AeSIONl0lVwHp9hN62xzPij9wtu8Tyky2EkuRXlonE3f6uPXT5UHMUY2RQrFfXxsZeq6xdZs853uXZ7vtXkFzdMzp9BKrbdc1da908uV1ZqcPhFwUiLJp6q3yRF8hfJknhgj0wtApnQ/s1024/t2.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="768" data-original-width="1024" height="240" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgO_2kZf_DyVeCmcv-Ra163hhTOLmuaW0Gf_R1afY9GuyCFwI6AeSIONl0lVwHp9hN62xzPij9wtu8Tyky2EkuRXlonE3f6uPXT5UHMUY2RQrFfXxsZeq6xdZs853uXZ7vtXkFzdMzp9BKrbdc1da908uV1ZqcPhFwUiLJp6q3yRF8hfJknhgj0wtApnQ/s320/t2.png" width="320" /></a></div><div class="separator" style="clear: both; text-align: center;"><br /></div><div class="separator" style="clear: both; text-align: left;">Of course, some levels have more graphics than others, but I'm sticking with the NZ stage for now.</div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: left;">So this worked fine, and we released a working game and had some fun with it.</div><br /><div class="separator" style="clear: both; text-align: left;">After a while, I started working on porting and updating the game, and we landed on the Nintendo DS. Going from 8MB of video RAM to 768kb - with a few limitations on how to use that memory, required the wasteful old layout to be revised. However, the DS's 3D hardware was still up to the task of all those tiles, so I was able to use the same actual layout. We opted to just zoom the screen in and add a radar, so that the original 640x480 resolution was still honored on the smaller 256x192 display. (This also helped the 3D system, as I only render the polygons that are actually in the viewing rectangle.)</div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: left;">Eventually, I wrote a project that parsed the Dreamcast tiles and condensed the texture pages, removing duplicate tiles and making a lookup table that could be used when the code asked for one of the original tiles. We reduced the background color depth to 8 bit as well, which still looked pretty good!</div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: center;"><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi3mDYPJZuhIHM3YAIGaF43f5jYTTzA6_Cs_sXyjjwO4xUqcDA8PtjAa0QX5yJzByHekUXaOIaThpjTy6DPDbqdP7jyiFtCcdDk2zon8JLUQbJKY7kr465BhNf09Uk0tgnK9zyGjPd4L1lnrjKULJeXo0rVqhe5n1NfDy3xt8Jse-TBqPv-JctR0Gav6w/s512/toy.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="512" data-original-width="512" height="200" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi3mDYPJZuhIHM3YAIGaF43f5jYTTzA6_Cs_sXyjjwO4xUqcDA8PtjAa0QX5yJzByHekUXaOIaThpjTy6DPDbqdP7jyiFtCcdDk2zon8JLUQbJKY7kr465BhNf09Uk0tgnK9zyGjPd4L1lnrjKULJeXo0rVqhe5n1NfDy3xt8Jse-TBqPv-JctR0Gav6w/w200-h200/toy.png" width="200" /></a><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjhz0wAtFJkUFttgBoshtSa7Qmk4Elf5mYRsP6mLauxfD3v4YLM0UWYnlaTQ66X3OGtaMfTrQbeMozS1pjvw2i5lHYztRGW1QgVPqZT6y2tU0L_atEvFDqpHOZrdIUajYAQJopCu14LycYRLTCM1JCqLWTw-0SxllVkzgUaTiJM6amgfLYX0bDRXOxhGQ/s512/nz.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="512" data-original-width="512" height="200" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjhz0wAtFJkUFttgBoshtSa7Qmk4Elf5mYRsP6mLauxfD3v4YLM0UWYnlaTQ66X3OGtaMfTrQbeMozS1pjvw2i5lHYztRGW1QgVPqZT6y2tU0L_atEvFDqpHOZrdIUajYAQJopCu14LycYRLTCM1JCqLWTw-0SxllVkzgUaTiJM6amgfLYX0bDRXOxhGQ/w200-h200/nz.png" width="200" /></a></div></div><div class="separator" style="clear: both; text-align: center;"><br /></div><div class="separator" style="clear: both; text-align: left;">(Still a bit of wasted space, but it was the closest power of two size that fit all the levels. Incidentally, this tight packing is why the game has trouble on DS emulators. They have an off-by-one bug in the texture mapping for flat projection that causes the textures to pull one more pixel than the hardware does. After years and years this has never been fixed, except in DrasticDS for Android.)</div><p>With that, the final game pretty much kept the original graphics on a much smaller system. The DS version also added special attacks and improved the story.</p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjz_9jjWO7ZBmxFyYQ-X80VWFHhF86v2komI_ZvxsCNLFhRFkPMX6xmYfSVY2hPZBGptvLwtlgXcyhU4KC1HZnziWA2TiRYi6I_PNDj4VfXsY0dH2fPybP3opJ20qriE4WQ7hlOjJ8bLYtSWqMTF9unrmMWisQgXSQ5kx4fThMlZe6x1qUjFeZIos_-TA/s388/ch03%20copy.jpg" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="388" data-original-width="255" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjz_9jjWO7ZBmxFyYQ-X80VWFHhF86v2komI_ZvxsCNLFhRFkPMX6xmYfSVY2hPZBGptvLwtlgXcyhU4KC1HZnziWA2TiRYi6I_PNDj4VfXsY0dH2fPybP3opJ20qriE4WQ7hlOjJ8bLYtSWqMTF9unrmMWisQgXSQ5kx4fThMlZe6x1qUjFeZIos_-TA/s320/ch03%20copy.jpg" width="210" /></a></div><br /><br /><div class="separator" style="clear: both; text-align: left;"><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjO5NjsScFN_BdsQ9w3TGM0j6kmEmcaO6vAVMztAtQ3JOQNVrZ1coFdkCxQf7ilHsXemb2jHEOI2VnB3dvkKB-oRoDqxysJb-3rmV_s7y24rG9S_kqMavRo9O6MHzXcpQlw__hBAthKn35X1sBril2oRxIyDeqokNILJc8Un28O3e1unlNAVCssaiGVMQ/s385/CH17May07_3.jpg" style="clear: right; float: right; margin-bottom: 1em; margin-left: 1em;"><br /></a></div></div>(All that said, the DS was actually powerful enough to render the whole screen, as this very early test shot shows!)<div><br /><div class="separator" style="clear: both; text-align: center;"><img border="0" data-original-height="385" data-original-width="256" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjO5NjsScFN_BdsQ9w3TGM0j6kmEmcaO6vAVMztAtQ3JOQNVrZ1coFdkCxQf7ilHsXemb2jHEOI2VnB3dvkKB-oRoDqxysJb-3rmV_s7y24rG9S_kqMavRo9O6MHzXcpQlw__hBAthKn35X1sBril2oRxIyDeqokNILJc8Un28O3e1unlNAVCssaiGVMQ/s320/CH17May07_3.jpg" width="213" /><br /></div><div><br /></div><div class="separator" style="clear: both; text-align: left;">Recently, then, I got a challenge and decided to see if I could get this going on the Gameboy Advance. Now, we're talking slightly more restrictions here. Only 64k of video RAM available to tiles, oh, and it's TILE based, not 3D.</div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: left;">I reduced the color depth to 16 colors for this.. and after the first pass, I was able to use a different palette for the destructibles compared to the ground tiles, giving me 32 colors overall (well, really 30 cause of the way the GBA does graphics).</div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: left;">Originally, I was considering hand-calculating the tiles, but I didn't think the CPU would be up to the task. It might have, but then I remembered, oh yeah! There are two layers.</div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: left;">So originally, I thought that would do it. I'll put the top halves on layer 2, and the bottom halves on layer 1. I can put the sprites in the middle.</div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: left;">But, then I realized... oh, wait, the destructible objects (crates, etc) need to go on top of the ground, but under the tops. So fine, three layers then. No problem.</div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: left;">That /almost/ worked. I didn't grab a screenshot, unfortunately, but where the leaves overlap on the left, that was deleting the previous tile and causing corruption (only on specific animation frames!!) But, easy to resolve this - I used the fourth and final layer and alternated the top layer for even and odd.</div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: left;">SUCCESS!</div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: left;"><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjssp2fyJVQ7iMx1E1Fmrzd1H3DiW90ZFblcuhM6ug7RScP229HJuLE-biG-t_7adtkJy_v0qeKoqthqlhePk0sWguHoIvTIBsH0s2mRyR5yjT3gqsFVIg2ucXchT3YYjQ645e5bcnus6nrwUKvEqRjJMCiMwJ9O5PQTKKfINdNVbSmKabLvRAMkTYs5A/s240/nz2.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="160" data-original-width="240" height="160" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjssp2fyJVQ7iMx1E1Fmrzd1H3DiW90ZFblcuhM6ug7RScP229HJuLE-biG-t_7adtkJy_v0qeKoqthqlhePk0sWguHoIvTIBsH0s2mRyR5yjT3gqsFVIg2ucXchT3YYjQ645e5bcnus6nrwUKvEqRjJMCiMwJ9O5PQTKKfINdNVbSmKabLvRAMkTYs5A/s1600/nz2.png" width="240" /></a></div><div class="separator" style="clear: both; text-align: center;"><br /></div><div class="separator" style="clear: both; text-align: left;">Check out the layers!</div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhsGxWknbgfNPjwUOKSoJ1XzFMj29kMHZUtsH-VYkeCY-TYg6Yfk3JjU_ClXNnn-DO7DbHeQVJafZvnY5FYI9bV12xn2PxGRb2Fhyv0-KF-ImXIhiVXW1fxQhnsRpIcdGsbgOmGvFcXNXH-09HoNC-cHA3SgK4Ylv15OR_penZTnhfYdVQbvcdlNplMWA/s240/ch1.png" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" data-original-height="160" data-original-width="240" height="133" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhsGxWknbgfNPjwUOKSoJ1XzFMj29kMHZUtsH-VYkeCY-TYg6Yfk3JjU_ClXNnn-DO7DbHeQVJafZvnY5FYI9bV12xn2PxGRb2Fhyv0-KF-ImXIhiVXW1fxQhnsRpIcdGsbgOmGvFcXNXH-09HoNC-cHA3SgK4Ylv15OR_penZTnhfYdVQbvcdlNplMWA/w200-h133/ch1.png" width="200" /></a><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhF6sCkHobVKnjERcvLfgsz4EvZ-YkyUoq6QwNUuAE3DqeiuqXphvQcxKS5MsS6zHhT2bXuR5utdfXrQeHTLNujlT81kfKlcsCZjb32k3-h1DqZ7I8oDo08buOqREgl7ufaOmMFr5rHuFfGIj4HnVA8cKU_-RyUWYvuz2GGY65SE0781ie4bWnebaw0xQ/s240/ch3.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="160" data-original-width="240" height="133" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhF6sCkHobVKnjERcvLfgsz4EvZ-YkyUoq6QwNUuAE3DqeiuqXphvQcxKS5MsS6zHhT2bXuR5utdfXrQeHTLNujlT81kfKlcsCZjb32k3-h1DqZ7I8oDo08buOqREgl7ufaOmMFr5rHuFfGIj4HnVA8cKU_-RyUWYvuz2GGY65SE0781ie4bWnebaw0xQ/w200-h133/ch3.png" width="200" /></a></div><br /><div class="separator" style="clear: both; text-align: center;"><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhoQzbAjTAjq7BZo8fY1aSEb8izqdTyKa2FtWi1_0wmPEGQkD6UzPHngQwQiG-Osa5ON7Ih6GC8e3QVNf4IieSlBCyOrjzIu9GumxV4OcHDNemzy7BvwR287g4Cq-m0edQ8J_RP2FaP6rzoWznk4KSg9WWeHJdBuOfZigGESJ0DoPVXhXzmFRGy0B9lAQ/s240/ch2.png" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" data-original-height="160" data-original-width="240" height="133" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhoQzbAjTAjq7BZo8fY1aSEb8izqdTyKa2FtWi1_0wmPEGQkD6UzPHngQwQiG-Osa5ON7Ih6GC8e3QVNf4IieSlBCyOrjzIu9GumxV4OcHDNemzy7BvwR287g4Cq-m0edQ8J_RP2FaP6rzoWznk4KSg9WWeHJdBuOfZigGESJ0DoPVXhXzmFRGy0B9lAQ/w200-h133/ch2.png" width="200" /></a><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh9Ju7yaIXzvDik-cgBXGMxn3rDoBP16j1PSTxEorRv_KuK8T4mz1qsAejGBbCOZpXqiOjFnlGZ3Pda8F2rIMWY1sblOeU0EVfmbUQPYejkvWVL-owJaPVPfZqWP1N9IKafCRiszJbLCJ3sa43azV1BzosQIkqS_BlKLjiENScDY_YD_f8ip3hikPOZSw/s240/ch4.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="160" data-original-width="240" height="133" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh9Ju7yaIXzvDik-cgBXGMxn3rDoBP16j1PSTxEorRv_KuK8T4mz1qsAejGBbCOZpXqiOjFnlGZ3Pda8F2rIMWY1sblOeU0EVfmbUQPYejkvWVL-owJaPVPfZqWP1N9IKafCRiszJbLCJ3sa43azV1BzosQIkqS_BlKLjiENScDY_YD_f8ip3hikPOZSw/w200-h133/ch4.png" width="200" /></a></div></div><br /><div class="separator" style="clear: both; text-align: left;">(The four separate layers)</div><div class="separator" style="clear: both; text-align: center;"><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgUrEsuNsLUsc6SauGpDvu1hQqV1aOINwtTHj1haqJlslJNTPsoB_HAroGPN_Ebf1LJ5W8zQl8aCJLLpt5WrjN6V3Qt_YwuyYWHnDV_BUcxpnq0LoR4pvePDdACdCkMleAHoMnvspcgREwEuB0Qd5n43VMWCny6Q6Ocavs4Gh3BhNwxb-9q_mkKFN8bsQ/s240/ch12.png" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" data-original-height="160" data-original-width="240" height="133" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgUrEsuNsLUsc6SauGpDvu1hQqV1aOINwtTHj1haqJlslJNTPsoB_HAroGPN_Ebf1LJ5W8zQl8aCJLLpt5WrjN6V3Qt_YwuyYWHnDV_BUcxpnq0LoR4pvePDdACdCkMleAHoMnvspcgREwEuB0Qd5n43VMWCny6Q6Ocavs4Gh3BhNwxb-9q_mkKFN8bsQ/w200-h133/ch12.png" width="200" /></a><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhcVjMKCUe4NM8EGmnTYuArfZelo77nW2LPeTu-UyKrdIQrIUh57LUpoBJtZIkDFDILgdq4LEgT2c172NB0ecTd4dqd7VGMsq6L-umpjv2YMAsIffW_lvy2khpdq7XY7GFjMG3BGo0JQPTkIs3-VmrXsa-sMSD_UAslvje_PQB5IF6olVEZ9eyvPCM_7w/s240/ch34.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="160" data-original-width="240" height="133" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhcVjMKCUe4NM8EGmnTYuArfZelo77nW2LPeTu-UyKrdIQrIUh57LUpoBJtZIkDFDILgdq4LEgT2c172NB0ecTd4dqd7VGMsq6L-umpjv2YMAsIffW_lvy2khpdq7XY7GFjMG3BGo0JQPTkIs3-VmrXsa-sMSD_UAslvje_PQB5IF6olVEZ9eyvPCM_7w/w200-h133/ch34.png" width="200" /></a></div><br /><div class="separator" style="clear: both; text-align: left;">(Combined layers 1 and 2, and 3 and 4).</div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: left;">To get here, I have a new script that processes the original Dreamcast graphics, converting the 48x48 pixel blocks (!!) into the 6x6 character tiles that the GBA works with. The lookup process is <i>just</i> fast enough on the GBA, and will probably need a little bit of optimization.</div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: left;">The new tool also looks for duplicate tiles, and so it can actually find more duplicate graphics (at 8x8) than the DS version did (at 48x48, though the DS version removed empty space).</div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: left;">In the end, all 6 levels, with /almost/ all the graphics, fits in about 350KB, and a single level's tiles fit in a single character set on the GBA (32k or less). I had to say 'almost', because the Toy Factory has so much animation that I had to remove a few tiles. Fortunately, no animation was removed - just the paint on the factory floor (there was a whole tile page of arrows), and three of the five colors of gift boxes.</div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: left;">Anyway... that's all I had to write tonight. I was just pleased to see it come together on such a different system. We'll have to see where it goes in the end!</div><div class="separator" style="clear: both; text-align: left;"><br /></div></div><p></p></div>Tursilionhttp://www.blogger.com/profile/16478174231304644316noreply@blogger.com0tag:blogger.com,1999:blog-7717886351507761714.post-73901473198008077252022-07-28T17:44:00.002-07:002022-09-13T21:18:06.837-07:00Necrobiotics My Spinnerets...<p>If you don't like spiders, don't read this. ;)</p><p><br /></p><p>Lots of buzz over the relatively recent release that some researchers are using dead spiders as grippers. There's literally nothing ground breaking here - they inflate the spiders' legs, causing them to extend, then release the pressure and they contract. That's how spiders walk in the first place.</p><p>They spend some time trying to justify it - oh, it's biodegradable, they can sometimes lift more mass than the mass of the dead spider, etc etc. Even invented a term - necrobiotics.</p><p>But it's all kind of bunk, isn't it? First off, there isn't a massive issue with grippers filling up landfills as disposable parts. So who cares that they are biodegradable? In fact, let's talk about that part!</p><p>I didn't see any mention of the number of useful cycles, but a typical gripper is going to rate this in the tens of thousands, if not hundreds of thousands. Lifespan of a typical gripper will be measured in years.</p><p>The spider starts decaying the moment they kill it (and yes, they kill the spiders they use for this experiment). The duration during which they are going to be useful, before the bladder is damaged or the creature simply becomes too dry to operate - that's going to be measured in hours. Which means at least every day, to keep your machine operating, you need to capture a spider, kill it without damaging it, carefully inject the actuator into the correct bladder, seal the hole, and then put your machine back together. Maybe you can get quick at that, but it seems like a lot of effort!</p><p>They talk about using them for pick and place machines, which need to rapidly and accurately pick up, position and place thousands of parts an hour. It's hard to believe that using dead spiders is going to revolutionize the already-very-simple-and-reliable grippers that are used for this. (Suction, if I understand correctly...) And there's no indication about how long the extremely tiny and fragile hairs used to actually make things stick to their feet will last without life to renew them.</p><p>That last point got me thinking. Clearly, the answer is not zombie spiders, but borg spiders. If we can implant a small computer that is capable of controlling the spider, we may have something. No, not as a pick and place, that's stupid. But for other things. Reconnaissance, for instance. I dunno what else. Targeted pest control, maybe. ;)</p><p>My thinking there is that the computer is able to drive the spider, as well as receive sensor feedback. But most importantly, it's able to turn off the interface and restore the spider to natural operation. The advantage of this is that, presumably, with appropriate rest breaks, the spider will naturally feed itself, and its biological processes will naturally repair the normal wear and tear of operation.</p><p>Morally, of course, this falls on the dark side of science. One might imagine that during periods of computer control, the spider would be experiencing a living hell. We might well be able to determine whether or not spiders have any sentience - any sense of self. If they did, I can only imagine the horrors they would try to cope with when the computer turns off.</p><p>I'm (fortunately) far too busy to create borg arachnids. Partially because spiders creep me right the hell out. And besides, for a pick and place, clearly ants are a far better choice. ;)</p><p><br /></p>Tursilionhttp://www.blogger.com/profile/16478174231304644316noreply@blogger.com0tag:blogger.com,1999:blog-7717886351507761714.post-48608545193078499842022-02-23T17:30:00.000-08:002022-02-23T17:30:04.927-08:00You're Doing it Wrong - Allocations<p> One of the things that frequently amuses me/drives me into a rage is the modern mentality that any old design pattern is bad, so don't learn it. Then code breaks, we old timers nod and say "yes, that sounds about right", and get back "why is programming so hard? I'm going to fix it so it's easy!"</p><p><br /></p><p>The article I'm reading right now is about a fellow who documents his battle to understand a kernel level crash that ultimately boiled down to a race causing a use-after-free. For those who don't know, this is exactly what it sounds like. You allocated some memory, then you freed it, then you accessed that pointer after the free. This is very bad and causes everything from security exploits to system crashes, because after a free the system is allowed to do anything it likes with that memory location, including re-allocating it, or marking it illegal because the address space is needed elsewhere.</p><p><br /></p><p>Use-after-free is controlled by having a clear memory policy. This is a design concept wherein you have a set policy that defines unambiguously who owns a block of allocated memory at any given time. Some systems may have multiple owners - in this case you need a management system such as smart pointers. Some systems may pass ownership from one function to the next - in this case it's usually wise for the code which is losing ownership to forget that pointer as soon as possible. For instance, you can null it out - then you /can't/ accidentally use it. There is literally no reason to remember an address once it has been freed - null that pointer. </p><p><br /></p><p>This also helps a lot with memory /leaks/. If you know who owns a block of memory, then that implies quite strongly who is responsible for /deleting/ that block when it's no longer required.</p><p><br /></p><p>This is all a design concept - nothing happens in code until you decide it. And once decided, no exceptions. Exceptions cause bugs. And besides, if you need exceptions, that means your design doesn't fit the application and needs to be rethought. My personal observation is that my design isn't right till the third time I implement it. Less than that, and I get nervous. It's like having your code build and run the first time - you should be thinking 'Oh no. What did I miss?' ;)</p><p><br /></p><p>Stable, reliable code beats buggy code that's 0.001% faster on Tuesdays. EVERY. SINGLE. TIME. You'll thank yourself when those good night sleeps start taking the place of early morning panic calls and late night debug sessions.</p><p><br /></p><p>Although I do agree with how the fellow ended it. I'm not naming him cause my rant isn't really his fault, and ended up a little off topic, but kudos, bud.</p><p><br /></p><p>"Just go to sleep, because everything is broken anyways :)"</p><div><br /></div>Tursilionhttp://www.blogger.com/profile/16478174231304644316noreply@blogger.com0tag:blogger.com,1999:blog-7717886351507761714.post-70303879476794646282021-12-16T06:01:00.000-08:002021-12-16T06:01:06.098-08:00End of Year Blog Time<p> Looks like I didn't do this last year... but the year before you got a 10 year retrospective, so I'm not too worried. ;) <br /><br />(Oh, looks like I did it on Twitter last year. </p><p><a href="https://twitter.com/Tursilion/status/1345228785629556736" target="_blank">https://twitter.com/Tursilion/status/1345228785629556736</a><br /></p><p>Oh well, I already started this here...)</p>It's hard to believe it's only been a year since I settled in up here -- and it's also hard to believe it's only been a year. I actually applied for a number of jobs, and it surprised me how much I dislike interviewing. ;) I guess, in fairness, I only had three jobs in the US that whole time, two of which I knew what I was doing, and one which was so amazing I'd do anything. (Also an honorable mention that I would have taken, they were awesome but fell into the 'knew what I was doing' bit...)<p></p><p>Anyway, THIS year... well, applied for a handful of jobs. One was pretty exciting - they were a manufacturing robot company and I could have kept using my skills, but they declined. I felt like maybe I offended them with some of my questions about the hardware... got to remember not to question the design until AFTER hired... ;) </p><p></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEgl8OrB8WpyvuYknJHZwDLc0KWBM54cNpF2B-uLXFmrUrQMijM88pkaHCJXnaYyx5xjj-nYGyoubomufjdnvNIJNiHOb79wkV9B6OJqZNeitaBNos8Du9BUDcJOVtP6S2FT2HdonY1xWu2kjP4FsD7kwqGVPoySh3Gz0K5w8zA8s1BGbca5Zu3ToHlTmw=s1104" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img alt="e-stop button" border="0" data-original-height="1104" data-original-width="1044" height="320" src="https://blogger.googleusercontent.com/img/a/AVvXsEgl8OrB8WpyvuYknJHZwDLc0KWBM54cNpF2B-uLXFmrUrQMijM88pkaHCJXnaYyx5xjj-nYGyoubomufjdnvNIJNiHOb79wkV9B6OJqZNeitaBNos8Du9BUDcJOVtP6S2FT2HdonY1xWu2kjP4FsD7kwqGVPoySh3Gz0K5w8zA8s1BGbca5Zu3ToHlTmw=w303-h320" width="303" /></a></div><p></p><p>Amazon chased me for a while - through the year in fact. But I never ended up agreeing to the full interview process. Maybe someday. They were smart when I interviewed down south...</p><p>I ended up working on a gas detection camera instead - and that was a whole new world for me. ;) In the end, my own contribution was entirely on the Linux software side, but it was a neat little world that I completely was not aware of.</p><p></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEjmO2y6ZUeB204VHrvcRmUrH_5FezRvLtu-ig-ZCsCOVap7nNa6_1QY8I2_ci0BLXOCvuWMvy7p_wMSByi3AS00U1COIwyj3cXRjxtXCMaCWQQ_VGcLQ6i_Y9af-jGlGseG7aBvQxQHQFVU7mlsN621i2GGukplkg56rxFvIk1LvX30dw40Qv7-5wTMzQ=s754" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img alt="graphic of methane spray viewed in infrared" border="0" data-original-height="381" data-original-width="754" height="162" src="https://blogger.googleusercontent.com/img/a/AVvXsEjmO2y6ZUeB204VHrvcRmUrH_5FezRvLtu-ig-ZCsCOVap7nNa6_1QY8I2_ci0BLXOCvuWMvy7p_wMSByi3AS00U1COIwyj3cXRjxtXCMaCWQQ_VGcLQ6i_Y9af-jGlGseG7aBvQxQHQFVU7mlsN621i2GGukplkg56rxFvIk1LvX30dw40Qv7-5wTMzQ=w320-h162" width="320" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="text-align: left;">Still had a few companies try to tempt me back down south, and it was pretty close. But... nah. Open to certain other countries though...! ;)</span></div><p></p><p>All I can say is my taxes are going to be fascinating this year... :p</p><p>But this usually isn't about boring old work. Unfortunately, it was a really quiet year for me. The pandemic forced a lot of things to be help back, and since I took work I didn't get /any/ of the personal progress I was hoping for. </p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEgp4i6hd-gteEnmAtNhYPGnD-OkYo5mtYUibhZ3r8zQgrzhRQ5PLZHWJ_2OXECYYMwU9iyhfBsEI64ff_dLwP-VOKgb_AG3GfMtgeRX3PqC5rUaeuuAk8FpKi2sSkJby-wDZUm-gczYZwI8TK_f8WS1fvnzEmidtS3DrJhfcTLgM9Q2J0LoKxd-MiomtQ=s740" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img alt="'keep your nose to the grindstone' with old time photo" border="0" data-original-height="740" data-original-width="740" height="320" src="https://blogger.googleusercontent.com/img/a/AVvXsEgp4i6hd-gteEnmAtNhYPGnD-OkYo5mtYUibhZ3r8zQgrzhRQ5PLZHWJ_2OXECYYMwU9iyhfBsEI64ff_dLwP-VOKgb_AG3GfMtgeRX3PqC5rUaeuuAk8FpKi2sSkJby-wDZUm-gczYZwI8TK_f8WS1fvnzEmidtS3DrJhfcTLgM9Q2J0LoKxd-MiomtQ=w320-h320" width="320" /></a></div><p>I got my car side window smashed for the first time ever. They didn't take anything, just rifled through and left it all on the seat. They stole my neighbor's car, and there's some suspicion they were looking for spare keys. Still cost me $500. I was surprised, though, I park within inches of a concrete wall, yet that's the side they smashed the window and crawled into the car on. I can't even fit there - I can't imagine how skinny the thief was.</p><p>What made it doubly annoying was only two nights earlier, they had gone through my car again. Apparently that night I left it unlocked by accident. Again, took nothing, just left it on the seat. They already knew there was nothing there, why smash my window? I was really annoyed cause I had considered putting a webcam on my car dash, but I couldn't figure out how to power it.</p><p>I sadly don't have the pictures anymore - there was nothing in them I wanted to keep.</p><p>I actually talked to Natsume about licensing Double Dragon, to try for another retro port. They were friendly but eventually declined. Doing ports legally is kind of neat but it IS hard to get people to talk to you. ;)</p><p>Got my COVID shots, of course -- ended up with 3 of them! I got AZ first, and when that was declared no good for travel, I was able to get two moderna shots to cover that. All three shots made me feel lousy for a day, yes. But now I'll never know if I actually had it when I was in Asia. ;)</p><p>I got a lovely final gift from Tokyo Disneyland - one of those laser printed 3D engravings inside a glass cube of the rose from Beauty and the Beast, with my name and thanks for helping with the attraction. I am looking forward to finally being able to fly back to Tokyo and visit the park as a guest, someday. :)</p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEh8Aq7uEM0KqZLTabaUF3uHuCpq6mqk5Bs-HTsq9KAZ8jJ-qffICBMj4-f8EacjT2bpPKRuiDWpdVwynjzRJ5Rh874dtkH9vvuaRpP2IDBykFsvUox1ODMPoj0p4wqTaWw1_OPDj1dFyBlx_6hLdSNTFjO_TzSBJmgV3pDFgnY61gRWA9E-7VFE8faGzA=s827" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img alt="Beauty and the Beast rose in 3d crystal block from Tokyo Disneyland" border="0" data-original-height="827" data-original-width="620" height="320" src="https://blogger.googleusercontent.com/img/a/AVvXsEh8Aq7uEM0KqZLTabaUF3uHuCpq6mqk5Bs-HTsq9KAZ8jJ-qffICBMj4-f8EacjT2bpPKRuiDWpdVwynjzRJ5Rh874dtkH9vvuaRpP2IDBykFsvUox1ODMPoj0p4wqTaWw1_OPDj1dFyBlx_6hLdSNTFjO_TzSBJmgV3pDFgnY61gRWA9E-7VFE8faGzA=w240-h320" width="240" /></a></div><br /><p>I've continued working with the Second Life wrestling group, though Second Life had several bouts of the usual internet drama. We seem to have survived them, and for a little while I even refereed<br /> a second federation, using a grump gryphon character I had created for earlier stories.<br /></p><p></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEg72niburE7-xpII3mmxpRC19XWD0ELiGsJcBjymLflX1x6MChWpN12ITTLFQF-7dgivzLPlzLgySPjsyCRrAAHWLfPkuZSeK-D9UcIiaMufgMdPnZGZIH9_JkAbLDGUMibejgxeAIfrTHyICwPBJey0E7OEY8wWJ4KRm6JEFnF0vvTiKUI2hyZeK3xuQ=s2048" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img alt="Oscar the Gryphon at Titan Wrestling" border="0" data-original-height="1085" data-original-width="2048" height="170" src="https://blogger.googleusercontent.com/img/a/AVvXsEg72niburE7-xpII3mmxpRC19XWD0ELiGsJcBjymLflX1x6MChWpN12ITTLFQF-7dgivzLPlzLgySPjsyCRrAAHWLfPkuZSeK-D9UcIiaMufgMdPnZGZIH9_JkAbLDGUMibejgxeAIfrTHyICwPBJey0E7OEY8wWJ4KRm6JEFnF0vvTiKUI2hyZeK3xuQ=w320-h170" width="320" /></a></div><p></p><p>We also did a big charity event called Slam-O-Ween, part of a week long series of events on SL for Breast Cancer. I dressed my raccoon ref up as Elvira for that one. We raised 3/4s of a million "Lindens" over the entire event (about $3500 US), with our silly little animal wrestling accounting for a double-digit percentage of that.<br /></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEj0241ws_34VSJpDEqbLMteuiUIoVdUmVr8HFurwQ5w8p7kCVMC17T5aQHxFfmTHiq8Sq_pGFjWCtAWUbI0KjOvJ0T-z4vxvvpSBZpsGup-UYMvc2HL6yr5afR_9b4MRyRaoZza-oOch4CZz5ST8vwoWkJdz9raa9u3QeFovGaoR6aogESyijOhKWm46A=s3840" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img alt="Sila the Raccoon as Elvira at Slam-O-Ween" border="0" data-original-height="3840" data-original-width="2160" height="320" src="https://blogger.googleusercontent.com/img/a/AVvXsEj0241ws_34VSJpDEqbLMteuiUIoVdUmVr8HFurwQ5w8p7kCVMC17T5aQHxFfmTHiq8Sq_pGFjWCtAWUbI0KjOvJ0T-z4vxvvpSBZpsGup-UYMvc2HL6yr5afR_9b4MRyRaoZza-oOch4CZz5ST8vwoWkJdz9raa9u3QeFovGaoR6aogESyijOhKWm46A=w180-h320" width="180" /></a></div><p>I also ended up aging up my old TLK Muck wizard hyena pup, and now he's a wrestler too. ;) I got permission from the person who created a lot of the original lore that he ended up in, and am using it as his gimmick. ;) I'll be honest, there was a significant time investment here... but I was lucky enough to get help from a skin designer and even from a talented singer/songwriter and friend for her music.<br /></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEiAtZsc01LBekqwp1UY0epEprpC12zI7_nOfcH5s4zWZfRMq9XG1oH5xcoVjLL0ki8qc76IokuNx7Wj1kFgVqDLIf2oigh6jgGYxybz_rYvzGzO5ZJ8DxIp-n7MouQaSD9FG7TZJNX4wilD9wJ-TUU7UU3_VD5yw-2PyB9B_0d2noTapf4iqVkmncRJbw=s2022" imageanchor="1" style="margin-left: 1em; margin-right: 1em; text-align: center;"><img alt="Danur Hyena at Sunday Night Frontline" border="0" data-original-height="2022" data-original-width="1536" height="320" src="https://blogger.googleusercontent.com/img/a/AVvXsEiAtZsc01LBekqwp1UY0epEprpC12zI7_nOfcH5s4zWZfRMq9XG1oH5xcoVjLL0ki8qc76IokuNx7Wj1kFgVqDLIf2oigh6jgGYxybz_rYvzGzO5ZJ8DxIp-n7MouQaSD9FG7TZJNX4wilD9wJ-TUU7UU3_VD5yw-2PyB9B_0d2noTapf4iqVkmncRJbw=w243-h320" width="243" /></a></div><p></p><p></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEjEOdeg0bvQ7zAyEllqxEds-j2bjnkfbQollOaWpuv56DzqR7LIzfVZSFugvNxe61SaFjTndZmNZmkRBONe7-0Yp7HQAsNujhOmW3xlKmh64xo-V2BiL2cNeDvp-ZewL-vugPvqR3NqVbqqs5qnj4fFZrWqsbWjHPmAh9azyYYdjWOA9URDuuf6vNsrog=s1280" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img alt="Danur - Rithandren Ranger. Danur's title for his intro video." border="0" data-original-height="720" data-original-width="1280" height="180" src="https://blogger.googleusercontent.com/img/a/AVvXsEjEOdeg0bvQ7zAyEllqxEds-j2bjnkfbQollOaWpuv56DzqR7LIzfVZSFugvNxe61SaFjTndZmNZmkRBONe7-0Yp7HQAsNujhOmW3xlKmh64xo-V2BiL2cNeDvp-ZewL-vugPvqR3NqVbqqs5qnj4fFZrWqsbWjHPmAh9azyYYdjWOA9URDuuf6vNsrog=w320-h180" width="320" /></a><br /><br /></div><div style="text-align: center;"><a href="https://www.youtube.com/user/michellecreber" target="_blank">Michelle Creber on YouTube</a><br /></div><br />I did some minor updates to Classic99, and I did some minor updates to my ponyscript, some updates to my VGM player, but precious little else, honestly. I let myself get overwhelmed again - and so quickly. The ONE task on my TODO list was Classic99 V4, and I'm going to try to meet that by the end of the year by the letter of the law, if not the spirit. (That is, my goal is 'boots', not 'useful'. ;) )<p></p><p></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEjhrp9Xhsl9tzwagjM5mcpowj5Ix-a3HgOB62imcdPcObSvDBca8ddFmAbwEgyxrvWIdQzoEiYXKU3Ust8xa9YdEija3ILHXdpNR4tek7WfeoSPZAeOC5E6y3PyOlrdUdQFIXvJRlMKNFoEjPyGPISHlMg5Oj7bBceXF-GoOEf4uTkL81XFyiyc99FEqA=s918" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img alt="Blank blue screen, all Classic99 v4 can show right now." border="0" data-original-height="736" data-original-width="918" height="257" src="https://blogger.googleusercontent.com/img/a/AVvXsEjhrp9Xhsl9tzwagjM5mcpowj5Ix-a3HgOB62imcdPcObSvDBca8ddFmAbwEgyxrvWIdQzoEiYXKU3Ust8xa9YdEija3ILHXdpNR4tek7WfeoSPZAeOC5E6y3PyOlrdUdQFIXvJRlMKNFoEjPyGPISHlMg5Oj7bBceXF-GoOEf4uTkL81XFyiyc99FEqA=w320-h257" width="320" /></a></div><br /><div class="separator" style="clear: both; text-align: center;"><span style="text-align: left;"><br />Oh! I did sidetrack and make a tribute to Thunder Force III on the TI - converting all the music with my VGM toolchains and creating some of the intro graphics to resemble it!<br /><br /></span></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEhKRUBj0RKbZmuX4c31G6Jdsk2bCRpWpBO9GP_gjiEC7s3D5Rj8r3WYaaP0h9HCfH7Fm1uHffNV9G-Fi6QtBbVmX6tOoyff3M46DaAbpbYOWa85HWVGRJPd3qOLAg1U9cGvq_huGcFbJICB8Bl4dxasVJmJTAoZMwmx5UWOKL_et4kz0m1Vj_8Ak3dDRg=s1662" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img alt="Thunder Force 3 title page rendered on the TI" border="0" data-original-height="1333" data-original-width="1662" height="257" src="https://blogger.googleusercontent.com/img/a/AVvXsEhKRUBj0RKbZmuX4c31G6Jdsk2bCRpWpBO9GP_gjiEC7s3D5Rj8r3WYaaP0h9HCfH7Fm1uHffNV9G-Fi6QtBbVmX6tOoyff3M46DaAbpbYOWa85HWVGRJPd3qOLAg1U9cGvq_huGcFbJICB8Bl4dxasVJmJTAoZMwmx5UWOKL_et4kz0m1Vj_8Ak3dDRg=w320-h257" width="320" /></a></div><br /><p>I did take one trip out to Ottawa, right before Omicron became the new buzzword, and it was nice! But it felt so weird to be flying after so long. ;) I didn't take any pictures at all...</p><p>I also let Cool Herders DS leak out to an archive site, just to see if that gets a single person to play it and comment on it. (Nope. Not yet. I actually thought this version was fun... ;) ). That's over here: </p><p><a href="https://www.gamesthatwerent.com/2021/11/cool-herders/" target="_blank">https://www.gamesthatwerent.com/2021/11/cool-herders/</a><br /></p><p>And of course someone immediately posted it with invalid license terms over to Archive.org... well meaning perhaps, but bad form. Still... here's that:<br /><br /><a href="https://archive.org/details/cool-herders-beta-90-percent" target="_blank">https://archive.org/details/cool-herders-beta-90-percent</a><br /><br /></p><p>Plans are in place for next year to be more productive - if the new job doesn't crush me. They both promise my weekends will be fine and that the work will be super challenging. This will be interesting. ;)</p><p>So yeah, that was 2021!</p><div><br /></div>Tursilionhttp://www.blogger.com/profile/16478174231304644316noreply@blogger.com0tag:blogger.com,1999:blog-7717886351507761714.post-44582697150730116782021-09-07T00:41:00.005-07:002021-09-07T00:41:42.839-07:00Finally Breaking Through Is Always Nice!<p>I've been fighting a small problem for the last two days, and I finally just figured it out. It's such a relief to finally have it make sense that I decided to write it up before I even coded the fix, which it was still fresh. It was a small issue, but in a very large project, which made debugging difficult.</p><p>Back in the beginning of this whole pandemic I published version 2 of my VGM compression toolset, this one much more flexible and able to import many more formats. Last month someone finally used it. Yes, retro development is sure rewarding! Anyway...</p><p>This guy ported all the tunes from the NES version of Smurfs over to the TI, and released individual programs with my Quickplayer, which wraps a tune with a standalone player and lets you add some text. It was sweet, but awkward... and since he asked if anyone could make a cartridge, I wrote a tool that would take a folder full of program images, and build a loader cart with a menu.</p><p>This was a good start, but I decided that I also wanted to take all the visualizers I've done over the years (four of them), and make them available in the Quickplayer too. I adapted all of them to fit in the 8k low memory block on the TI, and ported them to Coleco as well. Then I coded a couple of flags that could be externally set that could be used to find a selection program for chaining (with random play as my intent.) It took some fiddling, but that all came together eventually.</p><p>So before diving into the issues that the random player gave me, let's recap...</p><p>First, we have the music player libraries themselves.</p><p>They are wrapped around a song in a standalone player program -- there are FIVE player programs (four with visualizers, and one just text like I originally released). Plus the program that does the actual wrapping and generates the final code.</p><p>Then we have a tool that packages these programs up, and auto-generates a loader program for them (so, the tool, and the loader program).</p><p>And we have a menu that selects which loader will be executed. So we're up to 9 programs, and then I wrote the randomizer.</p><p>I expected this part to be easy, because I had carefully compartmentalized everything. To explain a bit, the TI file system loads program files in individual 8kb chunks. In addition, the TI's memory map splits the RAM - an 8k block at 0x2000 is where I store the player, and a 24k block at 0xA000 gets the music data. So, the player was always in a separate copy block to the data.</p><p>The autogenerated code thus always looks a lot like this:</p><p><span style="font-family: courier;">> 60B6 0200 li R0,>6004<span style="white-space: pre;"> </span>Ball<br /></span><span style="font-family: courier;"> 60BA 0201 li R1,>6000 <br /></span><span style="font-family: courier;"> 60BE 0202 li R2,>2000 <br /></span><span style="font-family: courier;"> 60C2 0203 li R3,>0cb4 <br /></span><span style="font-family: courier;"> 60C6 06A0 bl @>619c (Copy data) </span></p><p><span style="font-family: courier;"> 60CA 0200 li R0,>6006 Data <br /></span><span style="font-family: courier;"> 60CE 0201 li R1,>6000 <br /></span><span style="font-family: courier;"> 60D2 0202 li R2,>a000 <br /></span><span style="font-family: courier;"> 60D6 0203 li R3,>058a <br /></span><span style="font-family: courier;"> 60DA 06A0 bl @>619c </span></p><p><span style="font-family: courier;"> 60DE 06A0 bl @>600c Trampoline to start <br /></span><span style="font-family: courier;"> 60E2 2000 data >2000</span><span style="font-family: courier; white-space: pre;"> </span><span style="font-family: courier;">Start address</span></p><div>There's a bit of an extra wrinkle in there. The TI cartridge memory space is only 8k, so we're also paging 8k banks. So, R0 is loaded with a page reference, R1 is a source address, R2 is a destination address, and R3 is the number of words to copy. 619C is a subroutine that banks the page in and does the copy. The first destination address is also the start address, and so it's also stored in the data at the end.</div><div><br /></div><div>This all worked pretty well, so when I did the randomizer, I decided to have it pull the copy data for the first part, which is always the program, do the copy itself, and then randomly jump to the data copy for a different one. This would allow the music and visualizers to mix and match, so to speak.</div><div><br /></div><div>It tended to work... sometimes. It was very random. Of course, I did introduce two random numbers. I was able to try hard coded values through the debugger and generate combinations that worked and combinations that didn't.</div><div><br /></div><div>If you have already worked out why, damn you. You should have told me yesterday and saved me some time! ;)</div><div><br /></div><div>If not, my next clue was that when it didn't work, it was jumping to incorrect addresses - addresses that tended to correlate with different programs than the one that appeared to be loaded in RAM. But out of all five player programs, I only used two start addresses, >2000 and >2100. So there was always a chance of it working.</div><div><br /></div><div>A sensible fellow would have sorted it at this point, but it took me just a little longer!</div><div><br /></div><div>I took a lot of notes about start and load addresses, observed patterns, stepped through the code, and probably the fifth time I stepped through a broken start it suddenly clicked.</div><div><br /></div><div>This is your last chance to tell me what it was! ;)</div><div><br /></div><div>So yeah. The program is copied in the FIRST block, and the FIRST block contains the start address. JUMPING to the data copy in the last block means that we would use the start address contained at the end there -- which may or may not be for the code we actually loaded, since we are playing mix and match.</div><div><br /></div><div>To clarify, here's the loader for Piano:</div><div><br /></div><div><div><span style="font-family: courier;"> 616E 0200 li R0,>600e Piano <-- no page increment </span></div><div><span style="font-family: courier;"> 6172 0201 li R1,>6b0e </span></div><div><span style="font-family: courier;"> 6176 0202 li R2,>2100 </span></div><div><span style="font-family: courier;"> 617A 0203 li R3,>0883 </span></div><div><span style="font-family: courier;"> 617E 06A0 bl @>619c </span></div><div><span style="font-family: courier;"><br /></span></div><div><span style="font-family: courier;"> 6182 0200 li R0,>6010 Data </span></div><div><span style="font-family: courier;"> 6186 0201 li R1,>6000 </span></div><div><span style="font-family: courier;"> 618A 0202 li R2,>a000 </span></div><div><span style="font-family: courier;"> 618E 0203 li R3,>058a </span></div><div><span style="font-family: courier;"> 6192 06A0 bl @>619c </span></div><div><span style="font-family: courier;"><br /></span></div><div><span style="font-family: courier;"> 6196 06A0 bl @>600c Tramp </span></div><div><span style="font-family: courier;"> 619A 2100 data >2100 Start address</span></div></div><div><br /></div><div>Note the different start address!! So, if we copy the Ball program, then jump to the data copy for Piano, we'll end up starting in the middle of the Piano code!</div><div><br /></div><div>Of course.. the "right" way to do this wouldn't be hacking around your own code... you'd store the player programs in one place, and the music in another... but I wanted to be able to work with programs anyone generated -- plus I expected it to be faster to do. ;) (It probably wasn't!)</div><div><br /></div><div>The lesson is - beware of red herrings. Validate your assumptions. And for goodness sake, pay attention when you're doing hacky things like running your own code out of order, even if it was on purpose!</div><div><br /></div>Tursilionhttp://www.blogger.com/profile/16478174231304644316noreply@blogger.com1tag:blogger.com,1999:blog-7717886351507761714.post-80340592787852520442021-06-14T23:53:00.002-07:002021-06-14T23:53:41.129-07:00Technical Debt is...<p> Every time you ignore an error message and say "I'll worry about that if I see it again", you've added technical debt.</p><p>Every time you don't check a function's error return and say "We'll add that after it's all working", you've added technical debt.</p><p>Every time a function doesn't work, and you just add a comment that says "This doesn't work" instead of investigating why, you've added technical debt.</p><p>Every time you fail to test a function at all, and don't check if it's actually working, you've added technical debt.</p><p>Saw all of this tonight... ;)</p><p>A lot of people think that technical debt is a function of long term code, of systems that have become weighted down with hacks and patches. Some people think it's a deliberate choice, and therefore you can come back around and clean it up easily enough.</p><p>But you can't. It's all lost. You've no idea when that error will pop up again, but it will probably be in front of a customer when you think everything's working. The system will malfunction on Thursdays but you completely forgot that the main interface library that you used had an error return "FAIL_ITS_THURSDAY" that you didn't add a handler for -- now you have to launch a full debug process to find what's wrong (and since you didn't start troubleshooting till Friday, it'll take you a week.) You can't figure out why the system isn't processing fractals because you forgot that the fractal generate function has a tiny little comment that says "// This doesn't work, come back to it later (mb)" - hope you can find it!</p><p>Technical debt costs twice what you paid to put it into the system in the first place. And worse, it's often passed on to someone who wasn't there for the original design, so they've never heard of the library that hates Thursdays, only ones that hate Mondays. They'll need three times as long to find the issue. The customer doesn't care that you meant to come back to investigate that error code, they only care that it didn't work. And everyone at E3 was waiting to see your cool new fractal generator, not a grey box that pulses slightly.</p><p>Why would you want to deliberately pay all that? Most of the time, the developer of these debts could have fixed them in minutes. Pay the minutes, don't get so caught up in the excitement that you pay the debts later.</p><p><br /></p><p><br /></p>Tursilionhttp://www.blogger.com/profile/16478174231304644316noreply@blogger.com0tag:blogger.com,1999:blog-7717886351507761714.post-63657953722473412092021-05-26T11:37:00.002-07:002021-05-26T11:37:50.316-07:00You're Doing It Wrong - AI<p> AI will definitely destroy society. But not the way you think.</p><p><i>Disclaimer: I'm not a machine learning expert, and I know some will disagree strongly. Get your own blog, ya smarmy bastard. ;)</i></p><p>AI, or more correctly in most cases Machine Learning, is increasingly being used in difficult, abstract problems to give us a yes/no answer to questions even an expert would have trouble with.</p><p>There are also, as a result, countless stories of how AFTER training, it was discovered that these machines were skewed. They examined irrelevant details to come up with the answer, or they revealed biases in the dataset (which, honestly, people should have seen long before even starting.)</p><p>So machine learning, to give a very simple and mostly wrong description, is the act of wiring up a set of inputs (say, pixels of an image) to a set of outputs (say, "cat", "dog", "martian", "amoeba") through a chain of configurable evaluators. These evaluators, which are not called that by anyone with training in the field, are analogous to neurons in your brain.</p><p>The idea is, you show the inputs a picture of a cat, and tell it "cat". The machine tries a few combinations of settings and decides which one gave it "cat" most consistently. You show it a "dog" and it does the same thing, trying to remember the settings for "cat". Repeat for "martian" and "amoeba". Then repeat the whole process a couple of million times with different pictures randomly selected from the internet. The neurons slowly hone in on a collection of settings that generally produce the right output from all on those millions of inputs.</p><p>So you're done! You fed your electronic brain five million images, and it classified them with 99% accuracy! Hooray!</p><p>Now you give it a picture of a Martian it has never seen before. "Cat", it tells you confidently.</p><p>Well... um.. okay, cats have four legs and Martians only three, but, we're only 99% perfect. How about this lovely photo of an amoeba devouring a spore?</p><p>"Cat. 99.9% certainty."</p><p>"That's not a cat," you reply. </p><p>You offer up a beautiful painting made in memorial of a lost canine friend. "Amoeba."</p><p>Frustrated, you offer up a cheezburger meme. "Cat," the AI correctly responds.</p><p>Relieved, you sit back and accidentally send it a set of twelve stop signs and one bicycle. "Martian."</p><p>So what the heck is going on?</p><p>Well, first off, you got your 5 million photos from the internet, so it was 80% cats. Thus the AI ended up with a configuration set that favors cats. It decided that abstract blobs and unrealistic strokes, much like the brush strokes in your canine painting, looked a lot like the background of slides on which amoeba were found - it didn't learn anything about amoeba themselves. And tall, thin objects were clearly Martians, since you didn't teach it about anything else that was tall and thin.</p><p>Now, machine learning, even in the primitive form we have today, has some value. In <i>very narrow fields</i> it's possible to give a machine enough information that the outputs start to make sense. But the problem is that these narrow field successes have led to trying over and over to apply it to broader questions - questions which are often difficult even for human experts with far more reasoning power.</p><p>There are two big problems with machine learning. The first is that in real life, you would never actually know why it made those mistakes. The neuron training sequence is relatively opaque and there are few opportunities to debug incorrect answers. It's a big opaque box even to the people who built it.</p><p>The second is data curation. When you create such large datasets, it's very hard - nearly impossible - to ensure it's a <i>good</i> data set. There must be NO details that you don't want the AI to look at. If you are differentiating species, then no backgrounds, no artistic details, even different lightning can be locked in as a differentiator. The AI has NO IDEA what the real world looks like, so it doesn't unconsciously filter out details like we do. To the machine EVERY detail is critical. If I give it a cat on a red background and a dog on a blue background, it is very likely to determine that all animals on a red background are cats, because that is easier to determine than the subtle shape difference. </p><p>The dataset must also be <i>all-encompassing</i>. If you leave anything out, than that anything <i>does not exist</i> to the AI, and so providing it that anything automatically means it must be one of the other things. The brain can not choose "never seen before"... at least with most traditional training methods. At <i>best</i> you might get a low confidence score.</p><p>Finally, the dataset must be appropriately <i>balanced</i>. There may be cases where a skew is the right answer... for instance, a walking bird in the Antarctic is more likely a penguin than an emu, but if you are classifying <i>people</i> then you need to make sure the dataset contains a good representation in equal proportions of <i>everyone</i>. Sounds pretty hard, doesn't it? Yeah, that's the whole point. It's <i>hard</i>.</p><p>And that's a point I've made over and over again. Computing good hard like grammar. People are always looking for shortcuts, and they never work as well as expected. Not only is machine learning being seen as a huge shortcut to hard problems, but people are taking shortcuts <i>creating</i> the machine, and getting poor results. This shouldn't be a surprise. If you know the dataset is incomplete, why are you surprised that the machine doesn't work right? You're supposed to be smart. ;)</p><p>The real <i>problem</i> of all this is that people <i>still</i> think if a computer says it, it must be true. This is despite the daily experience with their cell phones, smart TVs, game systems and PCs <i>all</i> being buggy, malfunctioning pieces of crap, <i>somehow</i> the big mainframes at the mega-corporations (which generally don't exist anymore and the ones you are thinking of have less power than your smart watch), somehow <i>those</i> machines get it right.</p><p>So as machine learning continues to be used to classify people for risk, recognize people on the street, call out people for debt, etc, people are going to be negatively impacted by the poor training the machines received.</p><p><i>Computers are stupid.</i> They are stupider than the stupidest person you've ever had to work with. They are stupider than your neighbor's yappy dog down the street who barks at the snow. They are stupider than those dumb ants who walk right into the ant trap over and over again. Computers do not understand the world and have no filter for what is relevant and what is not. Don't trust them to tell you what's true.</p><p><br /></p>Tursilionhttp://www.blogger.com/profile/16478174231304644316noreply@blogger.com0tag:blogger.com,1999:blog-7717886351507761714.post-55141184775866368112021-01-29T10:52:00.004-08:002021-01-29T11:05:03.269-08:00Complexity - or - You're DEFINITELY Doing it Wrong<p>Hey, I'm employed again! You know what that means - MORE RANTS!</p><p>Any new position is always connected to learning about new systems that you didn't see before - or in this case - that I deliberately steered away from before. And the base takeaway of the last couple weeks is "people love complexity".</p><p>From layering systems on top of Git to creating an ecosystem with an entire glossary of new terminology, some people just feel a system isn't worth doing if it isn't layered with system on top of system on top of system. Unfortunately Linux as a platform heavily endorses this approach with a huge library of easily obtainable layers.</p><p>I once made the joke that building a project under Linux is like playing an old graphical Sierra adventure game. You need to get a magic potion to save the Princess, but the witch demands you bring her an apple. The orchard can't give you an apple unless you bring them some fertilizer for the trees. The farmer has fertilizer, and he'll trade you for a new lamp for his barn. The lamp maker would love to help, but he's all out of kerosene... and so on for the duration of the quest. Much the same under Linux, just replace the quest items with the next package you need, which depends on the next package, which depends on the next package... sometimes I wonder if anyone wrote any actual code, or if they all just call each other in an infinite loop until someone accidentally reaches Linus' original 286 kernel, which does all the actual work...</p><p>So anyway, yeah, if you need to invent a glossary of terms to describe all the new concepts you are introducing to the world of computing, then you are probably not a revolutionary - you are probably over-complicating something we've all been doing for better than half a century. Do you really need 1GB of support tools to generate an HTML page?</p><p>It's one thing I loved about embedded, it hadn't reached the point of being powerful enough to support all these layers yet. But those days are rapidly ending. The Raspberry PI Pico is a $4 embedded board powerful enough to generate digital video streams by bitbanging IO. Memory and performance isn't much of a concern anymore.</p><p>But let me end on a positive note - unusual for me, I know. Some of these packages produce amazing results and even I'm glad to see them out there. But for Pete's sake, consider whether you really need to add another layer on top of those packages - what are you actually adding? Seriously, poor Pete.</p><p>... if I could add a bit from Hitchhiker's Guide to the Galaxy...</p><p>"Address the chair!"<br />"It's just a rock!"<br />"Well, call it a chair!"<br />"Why not call it a rock?"</p><p><br /></p>Tursilionhttp://www.blogger.com/profile/16478174231304644316noreply@blogger.com0tag:blogger.com,1999:blog-7717886351507761714.post-61688061982981652832021-01-09T18:50:00.000-08:002021-01-09T18:50:17.923-08:00Let's talk about unit testing...<p>Since I've wandered back to the employment market, I've had to go through a lot of interview processes. From the very (ridiculously) large to the small, I'm basically being deluged with a slew of new acronyms that I was not deluged with a decade ago when I was last interviewing. And what that basically reinforces for me is that software development continues to be a hype-driven field, with everyone tightly embracing the latest buzzword, because obviously software used to be hard because we weren't doing it this way...</p><p>Personally, it would be nice if, instead of thinking of a cute new buzzword for something we've all known for 40 years already, people would just devote energy to writing better code. Education, practice, peer collaboration -- these create better code. Not pinning notecards around the office and telling everyone you're an <i>Aglete </i>now.</p><p>And why do we want to create better code? I sort of feel like this message is often lost - and without it you do have to wonder exactly WHY you are building a house of cards out of floppy disks once a week <i>(although people don't when they have the cool buzzword of Habitatience to direct them)</i>. But the reason to create better code is so that we spend less time making the code work. It's about making software reliable, and to at least minimal degrees, predictable - and these are things that bugs are not. </p><p>Anyway, unit testing is still pretty big, though of course the only <i>right</i> way to unit test is to use someone else's unit test framework, and write standalone blocks of code that run and pass the tests automatically. If you aren't using <i>FTest</i>, you clearly aren't testing at all.</p><p>Let me be clear up front - these little test functions are valuable, just rarely in the way that the proponents think. So let's just over-simplify first what I'm talking about.</p><p>Basically, the idea is that the developer writes test functions that can be executed one-by-one via a framework. These test functions are intended to exercise the code that has been written, and verify the results are correct. When you're done, you usually get a nice pretty report that can be framed on your wall or turned in to your teacher for extra marks. They show you did the due diligence and prove that your code works!</p><p>Or do they? Did you catch the clue? Encyclopedia Brown did.</p><p>The creator of the unit tests for a piece of code is usually the developer of that piece of code. Indeed, for some low level functions nobody else could. <i>(Although outside of the scope of this rant, it would be very reasonable for the designer or even the test group to create high level unit tests to verify /function/... but this never happens.)</i> Anyway, the problems with this are several:</p><p>First, the developer is testing their own understanding of what the function does. They are not necessarily testing what the function is supposed to do. Indeed, they usually write code that tests that the code they wrote does what they wrote it to do -- in essence they are testing the <i>compiler</i>, not the program. Modern compilers are not infallible, but they are generally good enough that we don't need to test their code generation as a general rule.</p><p>Secondly, this is a huge opportunity for a rookie trap. Novice programmers usually only test that a function does what the function is <i>supposed</i> to do. That is, they don't think to test if the function correctly handles bad situations, like invalid inputs. This is a huge hole and often means that half the function is unexercised -- or that the function has no error handling at all. But it will still pass the unit test.</p><p>Thirdly, this becomes a sort of a black box test. Similar to the comment above, there's no way to verify that every line of code in the function has been exercised. In fact, it's not even certain that the function behaved the way the developer intended -- only that the output, whatever it is, matched whatever criteria the unit test developer asked for. (And this can range from detailed to very, very basic, but it's still restricted only to the final output.) Correct result for a single input doesn't guarantee correct operation. <i>There is such a thing as dumb luck!</i></p><p>But there is value to these tests. Because they can be (and usually are) run by automatic build scripts, they are <i>fantastic</i> high level validations that a code change didn't fundamentally break anything. Of course, for this to be true, unit tests need to be peer reviewed and they need to include as many cases as are necessary to test ALL paths within the function being tested.</p><p>But what about the third point? While meeting the second point more or less addresses it, there is a variable not taken into account: <b>time</b>. What do I mean by that? I mean that in any project large enough that the developers are using automatic build tools with unit tests, that the code is not static. It is being changed, often rapidly. That's <i>why</i> the automatic tools are trying to help.</p><p>However, once created by person A, person B modifying a function that already exists rarely goes looking to update the unit test -- particularly if they did not change the function's purpose. However, the unit test was created so that the inputs passed tested all code paths. Now there are new code paths. You no longer know that the unit test is testing everything.</p><p>"Well, we'll just tell people to update the unit tests," you exclaim. "Case dismissed, nice try, but that's it."</p><p>Hah, I reply. Hah. Good luck.</p><p>Look, nobody sets out to be a sloppy or lazy developer, not even many of the cases I've inferred in my rants. But people forget things, they are usually on a tight schedule, and the most heinous of all, their manager usually tells them to "worry about that later". After all, the unit test exists, so that box is checked, and there's no point spending more money on updating it after it already exists. What are we supposed to do, fill in the box? It's already checked!</p><p>So look, just assume that your automated tests are going to fall out of date until you hire a new gung-ho intern who finds it, or the original dev adds a new feature and goes to update the unit test they wrote. They are <i>still</i> useful as a regression test - in fact awesomely do. Having unit tests on complex code I've written has saved me a few times. But what do you do between gung-ho interns?</p><p>Even if you don't have an automated build tool or haven't got around to implementing your unit test framework yet, the developers can still perform manual unit testing. Stop grinding your teeth - it's not as bad as you think. You have Visual Studio, Eclipse, or GDB, right? Quit your whining. In my day we did unit tests by changing the screen color and we liked it.</p><p>It's actually really simple. The developer simply <i>steps through the new code</i>. Modern debuggers allow you to set the program counter and both observe and change variables in real time -- meaning that a developer can walk through all the possible paths of their new function in a matter of minutes without even needing to simulate the real world cases that would trip up every case. This is especially helpful when some of the cases are technically "impossible" <i>(a programmer should never write "impossible" without quotation marks, hardware is involved). </i>Inputs can be changed, the code can be walked through, and then the program counter can be set right back to the last branch and tried again.</p><p>It's true that this can take a while if a lot of code is written, and naturally you still need to run the <i>real</i> <i>world</i> tests (to see if it actually works, as opposed to theoretically works), but this is guaranteed to be faster than writing <i>and testing</i> the unit tests. Oh yeah, you missed that part, didn't you? <i>You also have to test your unit tests actually work.</i></p><p>The worst unit test case I ever saw tested a full library of conversion functions by passing 0 to the base one and verifying that 0 came back out. As one might expect, 0 was a special case in this function. The other conversions actually contained off-by-one in about half the cases (and confused bits for bytes in several others - this was hardware based). But the unit test checkbox was marked, verifying that the software was correct, and more importantly, the unit test passed. It wasn't till we tried to <i>use</i> it that things went wrong.<br /></p><p>So, I recommend both. Have the developer step through their code. Let's call it the <i>Stepalicious Step</i>. Then after it works, write unit tests as regression tests so that your build server feels like it's contributing. But make sure unit tests are considered first tier code, and go through your usual peer review phase, to avoid only checking the easy case.</p><p>"Oh yes, we do Agile, Regression testing, and Stepalicious." Oh, it's no dumber sounding than trusting your source code to a Git... </p><p><br /></p>Tursilionhttp://www.blogger.com/profile/16478174231304644316noreply@blogger.com0tag:blogger.com,1999:blog-7717886351507761714.post-5560145185433117972020-11-12T11:22:00.000-08:002020-11-12T11:22:01.373-08:00On Broken Systems...<p> I've been doing a lot of scripting for the last couple of weeks on Second Life (in violation of my SurveyWalrus, don't tell him!) One of the things that surprises me about it is just how many of the APIs are unreliable. That is, the statement executes, no error occurs, but it doesn't work every time.</p><p>Actually, this is crazy common, especially when dealing with hardware in the real world. Nothing works quite as documented, and often not as you expected it to either. Surprisingly for this blog, I'm not criticizing it, I find it rather endearing. <i>(When it's HARDWARE. Hardware is hard, SL has no excuse ;) )</i></p><p>So what do you do when you execute the command, and nothing happens? Well, there are a few things that tend to help out in that case.</p><p>First and foremost, you need to <b>ensure</b> that the command actually happened, and that it happened the way you expected it to. There's little point going any further if you can't prove this. This means instrumenting your code, which I've covered before. It probably also means probing the hardware to make sure what was supposed to trigger the effect actually happened. Oscilloscopes have come down a lot in price over the decades, and even a cheap pocket one from Alibaba is a better diagnostic tool than poking the circuit with a wet finger.</p><p><i>(Disclaimer: don't poke circuits with wet fingers. It's not good for the circuit, it's not good for your finger, it likely won't tell you anything and it looks silly.)</i></p><p>After you have verified that the command is happening the way you expected, just take a moment and double-check the documentation matches your expectation. This step can save you hours of effort. Of course, about one in five times the documentation is also wrong. <i>Optimist.</i></p><p>Okay! So your code is working! The command matches the documentation! And it doesn't work. Now what? Debugging starts. That's right, you don't only have to debug the code you write, you will probably (always) have to debug code you didn't write and hardware you didn't create. And this part you usually can't fix! Man, computers are great!</p><p>More common than outright failure is inconsistent operation. That is, sometimes it works and sometimes it doesn't. This was the case with the SL APIs. It's very rare that something which is not actually defective is truly random -- and if it is, you can't work with it anyway. You need to start in on the scientific method and work out which conditions it works in, and which conditions it doesn't. At the over-simplified level, that's:</p><p>1) Create a theory<br />2) Devise a way to test your theory<br />3) Execute your test and record the results<br />4) Revise the theory based on the new information<br />5) Repeat at 2</p><p>You'll notice there's no exit condition. Usually, you stop when you get it reliable enough, and that depends on your needs. Or you stop when the hardware guy finally gets tired of your questions and adds some resistors to the circuit, suddenly stabilizing it. ;)</p><p>But to get you started - most of the time I've run into inconsistent operation, it has been timing. From the Atari Jaguar to cheap LCD panels to, yes, Second Life, it's really common for both APIs and hardware to drop commands if they come packed too close together. So, spacing them out is a good first test.</p><p>What if it is truly random (or you just can't narrow it down any further?), and you have no choice but to use it. Well, first, push back really hard, because you <i>really</i> don't want to have to support your code on this broken system for the next 10 years, do you? It's not over when you push it to Gitlab!</p><p>But if you really can't, well, you need to improve the odds of success. Can you safely execute the command twice? Safely means that it's okay if the command works once and fails once, and still okay if it executes twice. Apparently the NES needs to do this workaround on the controller port if making heavy use of the sample channel, for instance. Alternately, is there a way to VERIFY the command, and repeat it if it failed? Is there another way to accomplish the same thing, and bypass the broken command? Even if it's slower, that is probably better than unreliable.</p><p>In the case of outright failure, then you have really two possible causes: either the device/api is actually broken, or you are commanding it wrong. In the former case, you probably can't do very much about it -- and if you are still reading here, you probably can't prove it either. So you need to figure out what you are doing wrong.</p><p>Unfortunately, this one is much harder to advise - it all comes down to experience. Think about similar APIs you have implemented, and compare to the information you have. Does it make sense to try a different byte order? What about <i>bit</i> order? Is there an off-by-one error? (This is common in software and hardware both!) Make sure, if you are working with hardware, that it is <i>safe</i> to send bad data on purpose. Set up an isolated test bed, and try different things. Use the scientific method again, and you might just figure it out!</p><p>Then you can enjoy a coffee and go tease the hardware guy that the software guy found their bug. That's always fun. ;)</p><p><br /></p><p><br /></p><p><br /></p>Tursilionhttp://www.blogger.com/profile/16478174231304644316noreply@blogger.com0tag:blogger.com,1999:blog-7717886351507761714.post-87680301767768138502020-10-12T05:50:00.002-07:002020-10-13T21:11:19.434-07:00VGMComp2 - Looking Back<p> Many years ago, I undertook a project to come up with a simple compression format for music files on the TI-99/4A. My goals were simple, and somewhat selfish. There was a music format called VGM that supported the chip, and music from platforms that used it, like the Sega Master System, was easily obtainable. However, the files recorded every write to the sound chip along with timing information, and tended to be very large.</p><p>I built a system that stripped out the channel-specific data and moved all timing to separate streams - thus this four channel sound chip now had 12 streams of data: tone, volume, and timing. With all the streams looking the same, I implemented a combination of RLE and string compression and got them down to a reasonable size. There were a number of hacks for special cases I noticed, but ultimately it was working well enough to release. It was, in fact, used in a number of games and even a demo for the TI, so it was a success.</p><p>But it always bothered me. Why did I need the hacks? Why did it use so much CPU time? Could I do better? I spent a fair bit of time, on and off, coming up with ways to improve it. And finally, I convinced myself that I could. The new scheme was similar, but reduced the four time streams to just one, and changed out one of the lessor-used compression flags for a different idea. My thinking was that even if all else was equal, going from 12 streams down to 9 would buy me 25% CPU back.</p><p>But it didn't. In fact, the new playback code barely performed as well as the old. Even after recoding it in assembly, and heavy optimization, it was still reporting only about 10% better CPU usage than the old one. It took a lot of debugging to understand why, and what I finally realized was that the old format was simply better at determining when NO work was needed - it simply checked the four time streams. The new format needed to check the timestream and the four volume channels. This means that the best case (no work at all) was slightly faster on the old player than the new one. But the new one was markedly better in the <i>worst</i> case (all channels need work), just because the actual work per channel was simplified some.</p><p>Compression itself didn't really give me the wins I hoped for either. After creating specific test cases and walking through each decompress case (and so debugging them), compression was better, but not amazingly so. The best cases, true, were about 25% smaller than the old compressor, but the worst cases were pretty much on par, and that only with the most rigorous searches.</p><p>What I finally had to admit to myself, in both cases, was that the years of hacks and tricks and outright robberies in the original compressor had created something that was pretty hard to beat. But, it was also impossible to maintain, rather locked in the features it could support, and most importantly, I <i>did</i> beat it. Maybe not by much, but 10% on a slow computer is not a bad win.</p><p>And that, really, was something else I had to admit to myself. The TI is a <i>slow</i> computer. Even back in the day it was not terribly speedy. I tend to forget sometimes, working on my 3GHz computer that the 3MHz clock of the TI is <i>a thousand times</i> slower than my modern PC. And that's ignoring all the speedups that modern computers enjoy. <i>(It's kind of a shame how much of that power modern OS's steal, but I guess that's a different rant.)</i> Anyway, the point is that even writing all 8 registers on the sound chip every frame takes almost 1% of the system's CPU. And that's just writing the same value to all of them. That I can decompress and playback complex music in an average of 10-20% CPU is maybe not as awful as I felt when I first realized it.</p><p>There's of course another advantage to this new version. It was a goal to also support the second sound chip used in the ColecoVision Phoenix - the AY-8910. Borrowed from the MSX to make porting games from it simpler, this became a standard of sorts in the Coleco SGM add-on from OpCode, and so supporting it, at least in a casual manner, seemed worthwhile. This goal expanded when a member of the TI community announced that he'd be ressurecting the SID Blaster - a SID add-on card for the TI-99/4A. So, I made the toolchain support both of these chips -- although I cheated. A lot.</p><p>In the case of the AY, it wasn't so bad. I just ignored the envelope generator and treated it like another SN with a limited noise channel but better frequency range. The SID was trickier. I still did the same abuse - I ignored the envelope generator and treated it like another SN, but with only three channels. Unfortunately, the SID required some trickery because the envelope generator was <i>necessary</i> to set the volume. Fortunately for me, the trickery appeared to work. ;)</p><p>I have to admit that I'm not convinced that using both chips together will be acceptable, performance wise. 20% doesn't sound bad -- but that's on average. If both chips experience a full load on the same frame, it could be more than double that. On the other hand, if you can get away with running the tunes at 30hz and alternate the sound chips, that would be fine. That would likely be what I'd do.</p><p>Anyway, there was yet one more goal, and that was a robust set of tools to surround the new players. In the end, I created nearly 50 separate tools. And being very silly, many of them look Windows specific (but they are all just console apps and will port trivially, someday). But we have player libraries for the ColecoVision and the TI, a reference player for the PC, a dozen sample applications, 10 audio conversion tools (including from complex sources such as MOD and YM2612), and over 20 simple tools for shaping and manipulating the intermediate sound data. I have no doubt it's very intimidating, but short of tracking the data yourself (which, frankly, is a better route than converting), I believe there's no better toolset for getting a tune playing on this hardware.</p><p>Of course, if you can track it yourself, you can still use this toolset to get from tracker to hardware. ;)</p><p>I do intend to use this going forward, of course. The first user will probably be Super Space Acer, as that's near the top of my list (Classic99 is ahead of it). Though that game is nearly done, it will benefit from the improvements, and I need to finish it and port it around. With luck, once people have a chance to figure out the new process, they'll use it as well. I'll have to do some videos.</p><p>Anyway, the toolset is up at Github, and eventually on my website too, once I get that updated. </p><p>https://github.com/tursilion/vgmcomp2</p><p>(BTW: I very, very, very rarely log into the Github website. Using the ticket system and sending me notes there is all well and good, but generally I just push my project and move on. That's why I use Git in the first place, because SIMPLE. My point is - expect turnaround times to be really slow if that's how you reach out to me. I'm not ignoring you. I just haven't seen it yet. I say this because logging in to get the URL there, I noticed some stuff waiting for me. ;) )</p><p><br /></p>Tursilionhttp://www.blogger.com/profile/16478174231304644316noreply@blogger.com1tag:blogger.com,1999:blog-7717886351507761714.post-42898814891192106152020-05-24T16:06:00.002-07:002020-05-24T16:06:31.480-07:00Comdex 1999 by CryoModem - review of an early 80s text file(This text file was written sometime in the 80's. I don't know who originally wrote it, but I've always enjoyed it. Now in 2020, I look back to see what was right and what was so very wrong...)<br />
<br />
<i><span style="white-space: pre;"> </span><u>1999 COMDEX SHOW A FLOP</u></i><br />
<br />
<i><span style="white-space: pre;"> </span>LAS VEGAS: The fall 1999 Comdex was, as always, a bit disappointing. The star of</i><br />
<i><span style="white-space: pre;"> </span>the show was clearly the Yamagazi RoomTemp CryoModem I'm using to trasmit this</i><br />
<i><span style="white-space: pre;"> </span>story. Yamagazi claims it blitzes out data faster than the speed of light, which</i><br />
<i><span style="white-space: pre;"> </span>means that this report may have made it back to the office before the show even</i><br />
<i><span style="white-space: pre;"> </span>took place.</i><br />
<br />
(By 2000, consumer dial-up modems had peaked at 56 kilobit/s, with hardware compression on top of that to allow simple data to flow faster. DSL was on the rise although speeds topped out around 1 megabit both ways for commercial grade lines, and cable modems which promised faster speed were starting to roll out, but not as certain technology. BBSs and the concept of dialing a dedicated service were all but finished and the internet, while still young, had cemented itself as a necessary service.<br />
<br />
In case it's not obvious, this paragraph is the whole premise of the article - that faster-then-light data transmission caused the report to travel back in time to the 80s.)<br />
<br />
<i><span style="white-space: pre;"> </span>This year, the computer industry's companion show -Legaldex- nearly outdrew the</i><br />
<i><span style="white-space: pre;"> </span>hardware and software exhibits. With so many pending lawsuits and so much money</i><br />
<i><span style="white-space: pre;"> </span>at stake, it's really no surprise that Legaldex sprawled into 11 hotel lobbies,</i><br />
<i><span style="white-space: pre;"> </span>two parking lots, and a hallway at the Liberace museum. the Apple booths alone</i><br />
<i><span style="white-space: pre;"> </span>commanded more than 30,000 square feet of space.</i><br />
<br />
(Lawsuits over software and hardware ownership and patents has never really gone away. Sun Microsystems was fresh in people's memories for suing over Java, but Apple still rings with an air of possibility. In fact, in 1999 Apple sued a PC manufacturer called eMachines, claiming their PCs looked too much like an iMac. eMachine's eOne was taken off the market as a result.<br />
<br />
At the real Comdex 1999 - both Sun and Microsoft mentioned their mutual lawsuit in their keynotes - Gates with a joke and McNealy directly.)<br />
<br />
<i><span style="white-space: pre;"> </span>In what has turned out to be an annual tradition, IBM once again trotted out a</i><br />
<i><span style="white-space: pre;"> </span>new graphics standard, the 3DGA. Compatible with the MGA, MCGA, HGA, EGA, VGA,</i><br />
<i><span style="white-space: pre;"> </span>EVGA, QGA, VVGA, VHGA, VQGA, VMGA, VAGA, EAGA, GAGA and, of course, CGA</i><br />
<i><span style="white-space: pre;"> </span></i><i>boards, </i><i>this new standard heralds a "bold new era of channel profitability," according</i><br />
<i><span style="white-space: pre;"> </span>to IBM president and owner: "Now at last serious business </i><i>users can have their fancy 3-D</i><br />
<i><span style="white-space: pre;"> </span></i><i>graphs float in space."</i><br />
<br />
(This didn't happen, at least with cards. After SVGA popular naming just sort of faded out, though there was briefly a UVGA. Of course, someone has to name everything, so the /resolutions/ still got names. By 2000 most machines were still 800x600 or lower, with 1024x768 possible but not fully supported by monitors. So based on that, the naming would have given us: CGA, QVGA, VGA, SVGA, UVGA and XGA. We didn't have widescreen yet, or at least not commonly. 3D displays were a long way off, with glasses or headsets still required most of the time even today. Glasses free 3D displays appeared around 2010, but didn't gain popularity.<br />
<br />
Perhaps more importantly, despite creating the PC market and defining an architecture which survived and eventually defeated all comes, flourishing for decades to come, IBM stopped being the driving force in the market in the 90's, eventually leaving it altogether in 2005 - though that's after this article. They had a brief resurgence in popularly in the late 90's with the Thinkpad laptop series, which was indeed a very good machine, but clone manufacturers dominated the desktop market and video card innovation was owned by dedicated video card manufacturers. In fact, the term "GPU" was coined by NVidia in 1999 and so would likely have been the graphical focus. 3DFX was the major leader at the time.<br />
<br />
At the real Comdex 1999, 3DFX unveiled the Voodoo4 3D card and announced Voodoo5. the Voodoo4 would come with 32MB RAM, support AGP and PCI for $180. Voodoo 5 would come with 64MB or 128MB RAM, and cost $230-$600.)<br />
<br />
<i><span style="white-space: pre;"> </span>Big Blue also displayed yet another new keyboard. The 143-key sports 6 randomly</i><br />
<i><span style="white-space: pre;"> </span>scattered Ctrl keys, three more function keys, and an entire pad of SysRq keys</i><br />
<i><span style="white-space: pre;"> </span>(though IBM did not annouce why anyone needs even one). To counter IBM's new Blu</i><br />
<i><span style="white-space: pre;"> </span>architecture, AST/Quadram/Hyundai announced Blubus-Plus, with an additional data</i><br />
<i><span style="white-space: pre;"> </span>line and slightly more shielding. Blubus throws off so much RF interference that</i><br />
<i><span style="white-space: pre;"> </span>airborne users can make their planes bank left and right by leaning on the</i><br />
<i><span style="white-space: pre;"> </span>cursor arrow keys.</i><br />
<span style="white-space: pre;"> </span><br />
("Big Blue" was IBM's nickname, a reference to their logo.<br />
<br />
Keyboards didn't change much after the 101 key keyboard, although 104 keys became the standard after the addition of three Windows keys. Many keyboards also added media keys - some only a few and some a lot, but play/pause, next, previous, stop, volume up, volume down, and mute became relatively standard. SysRq seems to have gone away, though we still have pause/break doing nothing<br />
most of the time...<br />
<br />
New bus architectures did of course happen. By 2000 VESA had come and gone, and PCI was the dominant interface, though most motherboards still had an ISA slot or two for compatibility. PCI was released in '91 and caught on around '95, when Windows 95 introduced proper operating system support for it. For performance graphics, AGP was released in 1997.)<br />
<br />
<i><span style="white-space: pre;"> </span>The fastest selling product at the show was IBM's just-released TBR (Technical</i><br />
<i><span style="white-space: pre;"> </span>Bus Reference) manual, a fat compendium of IBM BIOS and chip-level errors that</i><br />
<i><span style="white-space: pre;"> </span>the industry has had to accept as standards.</i><br />
<br />
(Since IBM was no longer in charge, this didn't happen. Intel and Microsoft own the definition these days... although since IBM was still making machines in 1999, that may not have been the case then. I'm actually not sure!)<br />
<br />
<i><span style="white-space: pre;"> </span>In response to the new line of IBM 240MHz machines, Compaq/Dell announced a</i><br />
<i><span style="white-space: pre;"> </span>242MHz screamer, which it claims "makes the IBM box look like it's playing dead"</i><br />
<i><span style="white-space: pre;"> </span>At the other end of the spectrum, we counted 35 manufacturers still selling</i><br />
<i><span style="white-space: pre;"> </span>replacment motherboards for the original PC-1, switchable between 4.77MHz and</i><br />
<i><span style="white-space: pre;"> </span>180MHz.</i><br />
<br />
(In the mid-80s, where an 8MHz machine was considered serious and 25MHz insane, the idea of even a 180MHz upgrade board blew minds. Clock speeds in 1999 started in January at 450MHz and reached 600MHz by the end of the year. Intel's Celeron was 400MHz, and AMD countered with their 450MHz K6-III offering.<br />
<br />
This was the era of the Pentium 3, and there were no replacement motherboards for the PC-XT. In addition, the turbo switch disappeared during the 90's and computers just ran as fast as they could. This is also largely attributable to Windows 95 - a fixed feature set operating system meant that software could reliably use system timers, rather than CPU speed, to set their timing. The "Compaq/Dell" comment is interesting as maybe the only valid prediction in the document - if early! Dell acquired Compaq in 2002. Overclocking was big around the late 90s, though, so the 242MHz "Screamer" could have just been overclocked.)<br />
<br />
<i><span style="white-space: pre;"> </span>Sponsors of next year's millennial Comdex are planning to call Comdex 2000</i><br />
<i><span style="white-space: pre;"> </span>"Finally, the year of the LAN." Other vendors are proposing that Comdex 2000 be</i><br />
<i><span style="white-space: pre;"> </span>dubbed "The Year of the Home Application," in an effort to prod the industry</i><br />
<i><span style="white-space: pre;"> </span>into producing at least one product that could justify buying a computer for</i><br />
<i><span style="white-space: pre;"> </span>home use.</i><br />
<br />
(Hard to address such a tongue-in-cheek comment, but LANs were pretty established for businesses during the 90s, and the rising popularity of the internet was beginning to introduce them into the home - although it would really take the cable modem's victory and the spread of WiFi to fully integrate them years later.<br />
<br />
As for the product... that's an ongoing thing. Arguably, though, the internet was the killer app that put a PC in every home. 20 years later, today, that's starting to fade a bit. Cell phones and tablets are replacing the general purpose PC for internet access.<br />
<br />
As always, though, gaming also drives the PC market, as it did back then. 3D gaming was becoming big with 3DFX and NVidia pushing what the graphics card could do. AMD eventually replaced 3DFX as the big competitor.<br />
<br />
At the real Comdex 1999, one author came away feeling that Sony's 64MB Memory Stick was the killer hardware of the show... perhaps it would have been if USB memory sticks hadn't followed on quickly, being cheaper and more compatible with the hardware that was out there.)<br />
<br />
<i><span style="white-space: pre;"> </span>Ever-youthful Bill Gate's keynote address, "OS/9: The One You've Really, Really</i><br />
<i><span style="white-space: pre;"> </span>Been Waiting For," blunted criticism that this newest version was still too hard</i><br />
<i><span style="white-space: pre;"> </span>to use, too slow, and too memory-hungry: "Even though no third-party vendors</i><br />
<i><span style="white-space: pre;"> </span>have taken taken advantage of the advanced capabilities of the seven previous</i><br />
<i><span style="white-space: pre;"> </span>editions, dozens of developer are porting their applications over. And it will</i><br />
<i><span style="white-space: pre;"> </span>run just fine on any system with 30 megabytes of RAM, although you may need a</i><br />
<i><span style="white-space: pre;"> </span>bit more for your data."</i><br />
<br />
(Bill Gates was only 44 in 1999. ;)<br />
<br />
OS/2 failed out of the gate, and although IBM continued with OS/2 Warp in '94 and released the final version (Warp Server for e-Business) in '99, it only lasted a couple more years before being abandoned. Microsoft refocused on Windows with the release of Windows 95 and gained unassailable dominance for decades.<br />
<br />
The criticisms remain, of course.<br />
<br />
The porting comment was perhaps less an issue, the one thing that Windows did rather well was backwards compatibility. From Win95 onwards, applications generally "just worked".<br />
<br />
30MB of RAM was laughable in the early 80s, but by 2000 systems came standard with 32MB-128MB of RAM, and virtual memory was standard, so the numbers, while big, were acceptable by then.<br />
<br />
At the real Comdex 1999, a release date for Windows 2000 RC3 was announced and met with some doubt. Application compatibility was causing some delay. Windows 2000 was the first version to unify the NT and 95 kernels, so compatibility with both lines was important.<br />
<br />
Bill Gates DID give a keynote, where he focused on Windows 2000, and tried to introduce the concept of the "personal web". It was seen overall as more of the same, so the article probably described it well enough.<br />
<br />
Speaking of operating systems, there was a mini-expo for the Linux community at the same time. One writer noted: "while it's much nicer than last year's laughable bargain basement affair, it's small size gives ample evidence of the lengths Linux must go to enter the mainstream." However, Corel also showed "Corel Linux", a Debian distribution meant to be easy to set up.<br />
<br />
Sun Microsystems also had a keynote, taking on Microsoft (with whom they were involved in an anti-trust suit), and pushed StarOffice heavily. CEO Scott McNealy's position was that software should be free (presumably hardware is the model?)<br />
<br />
BeOS also had a booth that was well received, but there are few details beyond that. BeOS had its first x86 release in 98, but it was sold in 2001 and faded rapidly. A free reimplementation named Haiku was released in 2009 and was still active in 2018.)<br />
<br />
<i><span style="white-space: pre;"> </span>In the word processing arena, MicroPro, Microsoft, and WordPerfect have packed</i><br />
<i><span style="white-space: pre;"> </span>even more features into their bloated programs. MicroPro has purchased so many</i><br />
<i><span style="white-space: pre;"> </span>third-party utilities that WordStar Professional Classic 7.3 is now delivered on</i><br />
<i><span style="white-space: pre;"> </span>73 disks. WordPerfect has streamlined its 16-volume manual.</i><br />
<br />
(Wordstar was abandoned in the early 90s as they failed to jump on the Windows bandwagon early enough. WordPerfect was also late coming to Windows, but held on due to a large install base. However, they were sold to Novell in '94, then Corel in '96. The 32-bit version of WordPerfect for Windows 95 was plagued with release issues and the final working version was rather late. By this time, Microsoft Office and in particular Word was gaining rapid market share. However, WordPerfect still survives today in 2020. I don't have a manual from 2000, but the WordPerfect manual today is only 282 pages long.)<br />
<br />
<i><span style="white-space: pre;"> </span>Finally, Lotus announced its 1-2-3 WZ 50-dimension spreadsheet, a "quantum leap"</i><br />
<i><span style="white-space: pre;"> </span>above its previous 1-2-3 VZ 5th-dimension version. Although users have been</i><br />
<i><span style="white-space: pre;"> </span>demanding this added power, say market analysts, they're still not sure what to</i><br />
<i><span style="white-space: pre;"> </span>do with more that three dimensions. When pressed for a delivery date, Lotus</i><br />
<i><span style="white-space: pre;"> </span>officials would only say "Sometime in the first quarter of the coming millennium."</i><br />
<i><span style="white-space: pre;"> </span>We can hardly wait.</i><br />
<br />
(Lotus 1-2-3 was overtaken by Excel in the 90's for pretty much the same reason as the word processors - it failed to take the Windows update seriously in time. However, it did survive past the 1999 date here, eventually being discontinued in 2013.<br />
<br />
As far as I can tell, 3 dimensions is as far as spreadsheets went, and even that is through multiple tabs rather than a single 3D sheet.)<br />
<br />
... I spent WAY too long on this...<br />
<br />
<div>
<br /></div>
<div id="UMS_TOOLTIP" style="background: transparent; cursor: pointer; left: -100000px; position: absolute; top: -100000px; z-index: 2147483647;">
</div>
Tursilionhttp://www.blogger.com/profile/16478174231304644316noreply@blogger.com0tag:blogger.com,1999:blog-7717886351507761714.post-60129025382706587052020-03-22T19:35:00.005-07:002021-03-04T09:01:12.139-08:00Software is not a ScienceI've been coming to a realization that one of the great problems with software development is the fervent belief that it can be simplified, that it is a science that can be nailed down to a fixed set of guidelines and will thereafter magically be perfect.<br />
<br />
It's not. It's simply not. Like it or not, writing software is a creative aspect. You can no more reduce writing software to a set of fixed answers than you can create a checklist for drawing artwork.<br />
<br />
Let's think about this.<br />
<br />
First off, creating software requires the development of a unique solution to the problem from a set of incomplete tools which need to be assembled into a final system. It's a lot like building with Lego -- but you don't have the advanced set with all the fancy pieces. You have 2x2s and 2x4s and a couple of 2x8s.<br />
<br />
It gets better. Normally the problem isn't even that well defined. You have a Lego set but you don't have the instruction sheet and the box is torn so you only have half the picture.<br />
<br />
Of course, we do have the continued advance of software development - new systems, new languages, new processes. These are all great and fancy things. These are Space Lego, and Harry Potter Lego. They let you more easily create the new worlds you are imagining. But they don't remove the creative element - you don't automatically get Hogwarts, you have to build it. That's how you bought Castle Greyskull, but not Hogwarts.<br />
<br />
Most of the development processes that we develop fall into two categories.<br />
<br />
The good ones aim towards giving us the instruction sheet. A set of processes that advance us towards our goal - with the understanding that it will help us build THIS product. We can use bits and pieces of one instruction sheet - creatively - to help build other products. But naturally you need to intelligently apply your creativity.<br />
<br />
The bad processes aim towards removing the random creativity element, assuming that all problems can be solved in a fixed, predictable manner. Problem A is given to developer B who applies solution C, which takes time D. Neat, tidy, and guaranteed quality output. About as likely as Gingerbread men inviting you to tea and gumdrops, but we invest thousands and thousands of dollars in pursuit of this goal.<br />
<br />
Software needs to be run more like art. Unfortunately, I don't have insight from professional artists on how it runs and whether it works for them. I'll need to do some research. :)<br />
<br />
<br />
<br />
<div id="UMS_TOOLTIP" style="background: transparent; cursor: pointer; left: -100000px; position: absolute; top: -100000px; z-index: 2147483647;">
</div>
Tursilionhttp://www.blogger.com/profile/16478174231304644316noreply@blogger.com0tag:blogger.com,1999:blog-7717886351507761714.post-43172856208663568102019-11-13T16:27:00.002-08:002022-08-24T01:07:35.303-07:00The Year-endxxxxx Decade BlogAs part of my yearly evaluation, I need to sort through everything I did at work for the last year. Since the survey thing from Livejournal that I used to do was bugging me, I thought maybe I'd do the same thing at home!<br />
<br />
Then someone decided that no, no, it's the end of the decade, list your DECADE of accomplishments. Well damn it, fine. But only in summary for the earlier stuff. ;)<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgib7Hwzvnl13kwyqATAYwXTHDbON3xUyjoEmlyXkR-wyzFnKNFS8O3F9k-l0_NpoN-rV9cC9IHXrZOwycetOfYu0fJGQ6FFZ7Fym6DF3W1aZqTLA6b7lKX2Mokw787wOm7Rbj6QMs5aaPI/s1600/2010.jpg" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="167" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgib7Hwzvnl13kwyqATAYwXTHDbON3xUyjoEmlyXkR-wyzFnKNFS8O3F9k-l0_NpoN-rV9cC9IHXrZOwycetOfYu0fJGQ6FFZ7Fym6DF3W1aZqTLA6b7lKX2Mokw787wOm7Rbj6QMs5aaPI/s400/2010.jpg" width="400" /></a></div>
Okay, looks like the biggest thing I accomplished in 2010 was my work for Neato.<br />
I contracted for Neato robotics getting the Pinky chip up and running for the second generation Neato vacuum, which is of course the best one ever. ;) Sorry Camp!<br />
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div style="text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjN7Atju9KTuZVcUsWsD-npF-0O_gBD3tEkDTimTKL2-_XIAbpAwSAYUJnD9-frhMKTgv3pCgHNt-8QCfsQVagPgq1zgJbds_0dZqBgoZ497zDI-s0TlB8-gsKuC_EKqfncgnF1QUArJX2M/s1600/FirstNeatoBumparound.JPG" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="240" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjN7Atju9KTuZVcUsWsD-npF-0O_gBD3tEkDTimTKL2-_XIAbpAwSAYUJnD9-frhMKTgv3pCgHNt-8QCfsQVagPgq1zgJbds_0dZqBgoZ497zDI-s0TlB8-gsKuC_EKqfncgnF1QUArJX2M/s320/FirstNeatoBumparound.JPG" width="320" /></a></div>
<div style="text-align: center;">
<br /></div>
<div style="text-align: left;">
Honorable mention to becoming Nintendo certified for the eventually cancelled Cool Herders DS.</div>
<div style="text-align: left;">
<br /></div>
<br />
<div style="text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh6S0wXDLtghrdKB68zOskNdzV42VW5pRekFmDVw755-TpIZTPC4a4kOkHTWRr7xkIhxWN2y_eLpapEkVLwmw6HW39h1lfyjK3AIrk8oufXyvRwwqucNPXnFIEFz3FcGr9yTKCjS2QEwQtM/s1600/2011.jpg"><img border="0" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh6S0wXDLtghrdKB68zOskNdzV42VW5pRekFmDVw755-TpIZTPC4a4kOkHTWRr7xkIhxWN2y_eLpapEkVLwmw6HW39h1lfyjK3AIrk8oufXyvRwwqucNPXnFIEFz3FcGr9yTKCjS2QEwQtM/s400/2011.jpg" width="400" /></a></div>
<div style="text-align: left;">
In 2011 I went back to work full time after Cool Herders was cancelled, after contracting at NET, and went to work full time for Neato. But my top completed project would probably be the Skunkboard Revision 3, released with the financial and sales assistance of the GOAT store. This was a development board for the Atari Jaguar, designed by KSkunk and coded mostly by me. Due to problems with procuring the flash chips, this took a long time and we ended up with two vendors coming through, letting us produce 200 instead of the 100 we intended. All sold, of course. </div>
<div style="text-align: left;">
<br /></div>
<div style="text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjDF4NU3QNU1cnxtN756rGAWzPzA_qAE8RXzetpTKZd2kj99cuPuKgy678KcnAm1rw0Uijtz_6iz81xKnn0WfkZ2nhtb1nsj8krJhm2fhhsqnaT1NH5Zt8uEdzTW6BcxMKZMD150Ta_4jVb/s1600/CIMG0798.JPG"><img border="0" height="165" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjDF4NU3QNU1cnxtN756rGAWzPzA_qAE8RXzetpTKZd2kj99cuPuKgy678KcnAm1rw0Uijtz_6iz81xKnn0WfkZ2nhtb1nsj8krJhm2fhhsqnaT1NH5Zt8uEdzTW6BcxMKZMD150Ta_4jVb/s320/CIMG0798.JPG" width="320" /></a></div>
<div style="text-align: left;">
<br /></div>
<div style="text-align: left;">
After this run, I released all Skunkboard properties to the public domain. (This has led to a couple of after market productions!)</div>
<div style="text-align: left;">
<br /></div>
<div style="text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhO5x793Pw_1kjFtRBa8ey6Xu-LXZ-zKP5rpXfnE93k9Lgn5I6SAPmDUzhc_NuLfK3PtfBCV2XdOh9dZPPee0PGf6iTtOHOq6GE0BQ8v2sOFmdcJW2a0lwJLsm5Hur1NnK5NHVnx14o3S1X/s1600/2012.jpg"><img border="0" height="168" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhO5x793Pw_1kjFtRBa8ey6Xu-LXZ-zKP5rpXfnE93k9Lgn5I6SAPmDUzhc_NuLfK3PtfBCV2XdOh9dZPPee0PGf6iTtOHOq6GE0BQ8v2sOFmdcJW2a0lwJLsm5Hur1NnK5NHVnx14o3S1X/s400/2012.jpg" width="400" /></a></div>
<div style="text-align: left;">
<br /></div>
<div style="text-align: left;">
2012 is pretty easy - this is year that I moved to Los Angeles for probably the only thing that could tempt me to move to Los Angeles...</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgUZ_uFEiJPMeJhTMr1oFpaqMs_VR0-0lhwDThP9MDAzyXRXFnZHaYpxMLcnyASNAtniBuwsFehchX6vNMB5kUSeCujSSyfg-QsaXMdJa1jIli8jyLY4DLJ87orRnxGzWF7rI7oYHe-0xLW/s1600/imagine.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="154" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgUZ_uFEiJPMeJhTMr1oFpaqMs_VR0-0lhwDThP9MDAzyXRXFnZHaYpxMLcnyASNAtniBuwsFehchX6vNMB5kUSeCujSSyfg-QsaXMdJa1jIli8jyLY4DLJ87orRnxGzWF7rI7oYHe-0xLW/s320/imagine.png" width="320" /></a></div>
<div style="text-align: left;">
<br /></div>
<div style="text-align: left;">
Garmin was also trying to get me, and they had a great offer and a fun team and a neat project. I still feel a little bad for them. They were amazingly flexible and just awesome people.</div>
<div style="text-align: left;">
<br /></div>
<div style="text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgSCe5dfWxnQQiquqLEy7rNgXgDv3mDbCN4TYuesT5e6CG2kRi0Id_7Qj7T8Jn9DP0LGputeCjk3livIGRvnh0B3Z2lUqmNa0feQ83_4O3Mh_aEyhDN3bdWOQhwbh0j8_5lRt0-DPkN1XQj/s1600/2013.jpg"><img border="0" height="313" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgSCe5dfWxnQQiquqLEy7rNgXgDv3mDbCN4TYuesT5e6CG2kRi0Id_7Qj7T8Jn9DP0LGputeCjk3livIGRvnh0B3Z2lUqmNa0feQ83_4O3Mh_aEyhDN3bdWOQhwbh0j8_5lRt0-DPkN1XQj/s400/2013.jpg" width="400" /></a></div>
<div style="text-align: left;">
In 2013, I didn't seem to release much of anything. I focused on my new work, some of which ended up in the park in Florida a year or so later, and helping people with their projects. (I see lots of TI, F18A, and Skunkboard in my outbox). So it's unfortunate, but it appears I didn't directly contribute to the world at large in 2013 (or at least, what I DID do was laying the groundwork for future contributions. ;) )</div>
<div style="text-align: left;">
<br /></div>
<div style="text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgZR0kljvAhJYrLEzLpvH2WCwCZBEQUWgEfK_wkCYaTVCr34LKaJ0c4e8Jyt7KuSyiqzQJnTCaeRN8UrKL9pVVD0af7_YlTL8gkiJHMH5W1lDOn0m4PtYjkGxEpa4arVYpIgT0YC36a8fE2/s1600/navishaman-photo2-full.jpg"><img border="0" height="240" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgZR0kljvAhJYrLEzLpvH2WCwCZBEQUWgEfK_wkCYaTVCr34LKaJ0c4e8Jyt7KuSyiqzQJnTCaeRN8UrKL9pVVD0af7_YlTL8gkiJHMH5W1lDOn0m4PtYjkGxEpa4arVYpIgT0YC36a8fE2/s320/navishaman-photo2-full.jpg" width="320" /></a></div>
<div style="text-align: center;">
<br /></div>
<div style="text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiuswaaUZxOljFcWWAt5JlwlfctoBWOKmZ_6_5ovwWfRH3EmSfdmOgUCTDMLk8tLzsEfVg4qcL7RZWCD5t1tVB6k1jTJyOBhRC-tz7jfKp7yyWUlzp9LyDTHQlLuhra7IAFktAfVhGmKzLF/s1600/2014.jpg"><img border="0" height="224" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiuswaaUZxOljFcWWAt5JlwlfctoBWOKmZ_6_5ovwWfRH3EmSfdmOgUCTDMLk8tLzsEfVg4qcL7RZWCD5t1tVB6k1jTJyOBhRC-tz7jfKp7yyWUlzp9LyDTHQlLuhra7IAFktAfVhGmKzLF/s400/2014.jpg" width="400" /></a></div>
<div style="text-align: left;">
By contrast, 2014 was busy. I bought a house, I got my lion fursuit that I ended up never using (sigh), I released the TI UberGROM, and I finished Trixie's MLP-themed magic show in Second Life (barely in time to perform it by the end of the year). I also did a Day in the Park, working as a cast member at Disneyland for two days, so I could understand the operation of an attraction in real life. (That was tough for an introvert like me, but I'm glad I did it.) I even did a training course on Kuka robots! I built my Sega Genesis "3-way" multicarts including a hacked Thunder Force one, and a custom talking Nightmare Moon with real show quotes.</div>
<div style="text-align: left;">
<br /></div>
<div style="text-align: left;">
But for all this, the big thing in my life was agreeing to go to Shanghai to work on the new park there. Though I didn't leave before year end, a good half the year was spent getting ready to go.</div>
<div style="text-align: left;">
<br /></div>
<div style="text-align: left;">
<div style="text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgEW498ro9Hxb8szjwKXtRmgiqmAjK4cFuB_BTLV-3U1eIPL7N73uvjFXanupZPOht26lMMaNigc12P7KhubuVSz_aCfyi627mJfYh89yHtUrEO6TparFBNSt6Ekhz-DdcMB4WGZBIzNIO4/s1600/shanghai.jpg"><img border="0" height="160" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgEW498ro9Hxb8szjwKXtRmgiqmAjK4cFuB_BTLV-3U1eIPL7N73uvjFXanupZPOht26lMMaNigc12P7KhubuVSz_aCfyi627mJfYh89yHtUrEO6TparFBNSt6Ekhz-DdcMB4WGZBIzNIO4/s320/shanghai.jpg" width="320" /></a></div>
</div>
<div style="text-align: left;">
<br /></div>
<div style="text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiQgS54LvQMskVTZUVV2ByAiV2Upa9p7EKSTVMhzpzWu4ZCdl4S3gtA0hJjsxMZuhGIWoqtk_sYSSYMoao8HGuWLcesaMnFgBglA9Hc6HfQ0HZKDMUxcOnw7t0bWBIvu46azGH5aFPHPqYM/s1600/2015.png"><img border="0" height="243" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiQgS54LvQMskVTZUVV2ByAiV2Upa9p7EKSTVMhzpzWu4ZCdl4S3gtA0hJjsxMZuhGIWoqtk_sYSSYMoao8HGuWLcesaMnFgBglA9Hc6HfQ0HZKDMUxcOnw7t0bWBIvu46azGH5aFPHPqYM/s400/2015.png" width="400" /></a></div>
<div style="text-align: left;">
<br /></div>
<div style="text-align: left;">
In 2015, right off the bat I left for China. Early on, I got a recruiter call from Cyber Command, which would have been awesome. But they ran away when they heard I was Canadian. Pity. But other than that, I was largely focused on coming to terms with what I had done. If I thought Basic Training was a culture shock at only 10 weeks, man... I sure had a lot to learn.</div>
<div style="text-align: left;">
<br /></div>
<div style="text-align: left;">
I did get some travel in, seeing Tokyo (very briefly) and Beijing (also brief but more touristy), and I did a podcast with Floppy Days: <a href="https://player.fm/series/floppydays-vintage-computing-podcast/floppy-days-51-ti99-tech-specs-modern-upgrades-with-tursi">https://player.fm/series/floppydays-vintage-computing-podcast/floppy-days-51-ti99-tech-specs-modern-upgrades-with-tursi</a></div>
<div style="text-align: left;">
<br /></div>
<div style="text-align: left;">
I also had the only internal surgery of my life (thankfully minor) when I had my gall bladder removed in Hong Kong!</div>
<div style="text-align: left;">
<br /></div>
<div style="text-align: left;">
But the best thing I unleashed upon the world was my "Spaceballs" demo for the TI, finally showing audio and video playback on the machine. This is what paved the way for Dragon's Lair four years later...</div>
<div style="text-align: left;">
<br /></div>
<div style="text-align: left;">
<a href="https://www.youtube.com/watch?v=j_J7LHCgOfc">https://www.youtube.com/watch?v=j_J7LHCgOfc</a></div>
<div style="text-align: left;">
<br /></div>
<div style="text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj62lNIC5Fa3FMcC-0mspB_6uk9AVbATypnux4gE96ETi-akg6QNC63QZzPfqbpnD0Ji9zk7n89rZ81oS_0Y9iwjZL8Snw6ZMcKYqgLifyzHNIfBxHLDpJ1gCAg-I4IZFHVG49ZOYqfGrD1/s1600/Clip0001.png"><img border="0" height="221" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj62lNIC5Fa3FMcC-0mspB_6uk9AVbATypnux4gE96ETi-akg6QNC63QZzPfqbpnD0Ji9zk7n89rZ81oS_0Y9iwjZL8Snw6ZMcKYqgLifyzHNIfBxHLDpJ1gCAg-I4IZFHVG49ZOYqfGrD1/s320/Clip0001.png" width="320" /></a></div>
<div style="text-align: center;">
<br /></div>
<div style="text-align: center;">
<br /></div>
<div style="text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgAlyH67egcHqp7yHSI75X6aDv8lEuPvYdA8D8Ij5Y3aMYtNqV1tI6br9o3Hirdd-rkhuY83CsxT3GDfDMKIi2w7rJf9DFqWuCOFchPMJSlgM8hwottqZnH_FEkpfSvAcsUsrWmj-2r1lM7/s1600/2016.jpg"><img border="0" height="400" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgAlyH67egcHqp7yHSI75X6aDv8lEuPvYdA8D8Ij5Y3aMYtNqV1tI6br9o3Hirdd-rkhuY83CsxT3GDfDMKIi2w7rJf9DFqWuCOFchPMJSlgM8hwottqZnH_FEkpfSvAcsUsrWmj-2r1lM7/s400/2016.jpg" width="400" /></a></div>
<div style="text-align: left;">
2016, is there any competition? In 2016 I helped open an entire new Disney park. A massive amount of effort and stress, but somehow we were open on opening day. :)</div>
<div style="text-align: left;">
<br /></div>
<div style="text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEge4UREyVmMbhcnMa4tSPDMhrtZG4dSyvnaq9KMYYEtXD8RkpWW34JFPApaWiBjUBEgIf3Y8CnokDhLHIhKpnrrOxn01aFSMuIPjBL6CFNFCyqv91Xx7aHKDBZP3qxG9gjxHE4n1vheLJ4Z/s1600/shanghaiDis.jpg"><img border="0" height="212" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEge4UREyVmMbhcnMa4tSPDMhrtZG4dSyvnaq9KMYYEtXD8RkpWW34JFPApaWiBjUBEgIf3Y8CnokDhLHIhKpnrrOxn01aFSMuIPjBL6CFNFCyqv91Xx7aHKDBZP3qxG9gjxHE4n1vheLJ4Z/s320/shanghaiDis.jpg" width="320" /></a></div>
<div style="text-align: center;">
<br /></div>
<div style="text-align: left;">
It's also the year I finally started to negotiate my license for Dragon's Lair...</div>
<div style="text-align: left;">
<br /></div>
<div style="text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhOjEQf9Aytf5ObthCr_Buvk5NogWPwfODI_BvA0CxIHFjlhL7cmtHj0M3aaGZowDvbd15H81HdqeYXsNyy1zlTB_tCFi6ocOgoWb3y8tXsVPIkAx08u-hegOsXIpzKUotbmY4JYJSivR5R/s1600/2017.jpg"><img border="0" height="228" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhOjEQf9Aytf5ObthCr_Buvk5NogWPwfODI_BvA0CxIHFjlhL7cmtHj0M3aaGZowDvbd15H81HdqeYXsNyy1zlTB_tCFi6ocOgoWb3y8tXsVPIkAx08u-hegOsXIpzKUotbmY4JYJSivR5R/s400/2017.jpg" width="400" /></a></div>
<div style="text-align: left;">
In 2017 I moved back to Burbank and sold my place, worked in earnest on the 3 Way Genesis carts with a fellow online who was having fun making various ones. I created a patched Coleco BIOS for CollectorVision which led to me working on that device years later. My Dragon's Lair license also went live with a 2 year timeout. I tried to get help from several people on that, but everyone was just too busy.</div>
<div style="text-align: left;">
<br /></div>
<div style="text-align: left;">
But about all I managed to finish for myself for the year was a 4k remake of an old XB game I wrote as a kid, called HeroX:<br />
<br /></div>
<div style="text-align: left;">
<a href="https://www.youtube.com/watch?v=3XABRfZhwj0">https://www.youtube.com/watch?v=3XABRfZhwj0</a></div>
<div style="text-align: left;">
<br /></div>
<div style="text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhWD76dFiMg1OlUoeZLYXBqcAdDT8pgkKQXiCa66CaALtcWUwBu_OLtKEwPY_66hMUWBOwxZ8dNiFDU3L3M0uvmu08OpD23SfKGHH9XOhLUOpjIauPgEMRjWKYU0ao6crBq4OIgzIRx_GTu/s1600/Clip0002.png"><img border="0" height="242" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhWD76dFiMg1OlUoeZLYXBqcAdDT8pgkKQXiCa66CaALtcWUwBu_OLtKEwPY_66hMUWBOwxZ8dNiFDU3L3M0uvmu08OpD23SfKGHH9XOhLUOpjIauPgEMRjWKYU0ao6crBq4OIgzIRx_GTu/s320/Clip0002.png" width="320" /></a></div>
<div style="text-align: center;">
<br /></div>
<div style="text-align: left;">
I also had a minor role in the award winning TI Megademo by Desire: </div>
<div style="text-align: left;">
<a href="http://www.pouet.net/prod.php?which=68783">http://www.pouet.net/prod.php?which=68783</a></div>
<div style="text-align: left;">
<a href="https://www.youtube.com/watch?v=ZhSUhE03XFw">https://www.youtube.com/watch?v=ZhSUhE03XFw</a></div>
<div style="text-align: left;">
<br /></div>
<div style="text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiVuIV9N6N2SCxWH-0x84wR4Jq4FIArtLpgnB9Taf4JLqYQgqb1hJmcta6lzc-Xk60RoxG_O7BHl7S62L4qZdy9dIOEqCvFDlzVPrP_1zgLCaqkvIrNrp5X8pd_RVkpwEEqVJECp9R5M6jB/s1600/mess.png"><img border="0" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiVuIV9N6N2SCxWH-0x84wR4Jq4FIArtLpgnB9Taf4JLqYQgqb1hJmcta6lzc-Xk60RoxG_O7BHl7S62L4qZdy9dIOEqCvFDlzVPrP_1zgLCaqkvIrNrp5X8pd_RVkpwEEqVJECp9R5M6jB/s320/mess.png" width="309" /></a></div>
<div style="text-align: center;">
<br /></div>
<div style="text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhv6kuXc14CPtM_4ovAnxDYkvMDAUz47VeaXRRhCKrrLhZJWeKgvnnJjwvp6Gm12ebSl7Gdsqvzx1xWVrhAPmSt_FIQYNaIKXZBimEvb_sykXoc37VeLfKpDjm3ulBpy_WVuaM3dKS_pzvX/s1600/2018.jpg"><img border="0" height="224" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhv6kuXc14CPtM_4ovAnxDYkvMDAUz47VeaXRRhCKrrLhZJWeKgvnnJjwvp6Gm12ebSl7Gdsqvzx1xWVrhAPmSt_FIQYNaIKXZBimEvb_sykXoc37VeLfKpDjm3ulBpy_WVuaM3dKS_pzvX/s400/2018.jpg" width="400" /></a></div>
<div style="text-align: left;">
2018 brought the release of a finicky raccoon for work, and I got back out of rental into a townhouse just outside of town, which may have been a bad move. It doesn't look like I released very much, though I spent much of the year working on Dragon's Lair, and I commissioned a life-size Starlight Glimmer plush who sits atop my bookcase. But the main thing that I finished was the MLP Fanfic I started almost two years earlier in Shanghai. The story of Nightmare Moon defeating Celestia, and Celestia coming back - Night Reigns. </div>
<div style="text-align: left;">
<br /></div>
<div style="text-align: left;">
<a href="https://www.fimfiction.net/story/258941/night-reigns">https://www.fimfiction.net/story/258941/night-reigns</a></div>
<div style="text-align: left;">
<br /></div>
<div style="text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgKmA4vCdyjldp30EFKeeuIWz-zw45PSCVUBBJ-22r7v0mdatmysbD9iA6wS19USg6jySYoni0kpU8ryCJYHT-4oHZZPB6msPXgbeuFtTMuZ5SH-xmaRpomck_f5Jpkyqena8iMh8NUi8OZ/s1600/reign.png"><img border="0" height="196" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgKmA4vCdyjldp30EFKeeuIWz-zw45PSCVUBBJ-22r7v0mdatmysbD9iA6wS19USg6jySYoni0kpU8ryCJYHT-4oHZZPB6msPXgbeuFtTMuZ5SH-xmaRpomck_f5Jpkyqena8iMh8NUi8OZ/s320/reign.png" width="320" /></a></div>
<div style="text-align: left;">
It did all right, and even today is in the top 5% on the site (barely!) I printed out copies and so I can say I have a book on my bookshelf that I wrote.</div>
<br />
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg5zlgydJCRy6DIPT9mFIsz_Zx0xiWTcX6MefPOnOn9T7wVzTjaLJwFhJYOJ4VK4J-JIIeVqEbYP0nhtARREn9WYBnfn3sXs8PKrEJiEmKHqB3KKB_sUhmncoNvuAABfFRonx_aP5VbEivT/s1600/download.jpg" style="margin-left: auto; margin-right: auto;"><img border="0" height="296" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg5zlgydJCRy6DIPT9mFIsz_Zx0xiWTcX6MefPOnOn9T7wVzTjaLJwFhJYOJ4VK4J-JIIeVqEbYP0nhtARREn9WYBnfn3sXs8PKrEJiEmKHqB3KKB_sUhmncoNvuAABfFRonx_aP5VbEivT/s640/download.jpg" width="640" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;"><br /></td></tr>
</tbody></table>
Finally, we come to 2019, and I can be more detailed here, as this is what I originally wrote this for...<br />
<br />
First of all, I managed to get Dragon's Lair for the TI-99/4A finished and out into the world as a full production. That was a huge task that took a few years to finish, and included learning some VHDL and KiCad for PCB layout and manufacturing. I wrote a document that details all about it:<br />
<a href="https://docs.google.com/presentation/d/1u7SOusjQDInq95GrEH2tmIphUAjRg-9YbhR_X25D62A/edit?usp=sharing">https://docs.google.com/presentation/d/1u7SOusjQDInq95GrEH2tmIphUAjRg-9YbhR_X25D62A/edit?usp=sharing</a><br />
<br />
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjhdjWdh0J65KjR8qUgCO6bfypKKnMhCh5boY_DA-3IpwfWfkBEgMqhZioJkcEK1_EfwZ91kj19-16yJ_kQYmizttL91n0TEOWtNKqNwi6ZytpoHGW0Xk5S_J0szlGnus37c2aRWjPKJCuG/s1600/20190701_224422.jpg"><img border="0" height="397" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjhdjWdh0J65KjR8qUgCO6bfypKKnMhCh5boY_DA-3IpwfWfkBEgMqhZioJkcEK1_EfwZ91kj19-16yJ_kQYmizttL91n0TEOWtNKqNwi6ZytpoHGW0Xk5S_J0szlGnus37c2aRWjPKJCuG/s400/20190701_224422.jpg" width="400" /></a><br />
<br />
Numerous bug fixes to Classic99 and ConvertHGR packages, as well as a massive (and long overdue) update to FlipTerm, my muck client, which brings the API up to speed again.<br />
<a href="http://harmlesslion.com/software/classic99">http://harmlesslion.com/software/classic99</a><br />
<a href="http://harmlesslion.com/software/converthgr">http://harmlesslion.com/software/converthgr</a><br />
<a href="http://harmlesslion.com/software/flipterm">http://harmlesslion.com/software/flipterm</a><br />
<br />
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg7C-As4-UWRgM6Twa8j7VoluPhNXOVTbzf5jfkDc5gaeq0h7VMJpblLfc_XFaJ963BRSsaE7VQdu83IfZvJK_7BGoo-naCqaq5cnAd6kJxM_SLm3V7MdJYKDiQ_-2b4JIlPstKM7TpRkNE/s1600/softs.png"><img border="0" height="544" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg7C-As4-UWRgM6Twa8j7VoluPhNXOVTbzf5jfkDc5gaeq0h7VMJpblLfc_XFaJ963BRSsaE7VQdu83IfZvJK_7BGoo-naCqaq5cnAd6kJxM_SLm3V7MdJYKDiQ_-2b4JIlPstKM7TpRkNE/s640/softs.png" width="640" /></a><br />
<div class="separator" style="clear: both; text-align: center;">
</div>
<br />
Attended Vanhoover, which was a lot of fun, and also traveled to Ottawa to see friends, but completely failed to make any business contacts there as I intended! Also made it down to Australia for the first time in many years! I attended Further Confusion, but had a lousy time due to hotel rudeness and overpriced rooms. (I guess that's hardly an accomplishment, but I did it ;) ) Finally, I even made it to the Chicago TI User's Group annual International Faire - more than 35 years running!<br />
<br />
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjNJouWNUoYbG-4oq_o7OYhhJMdg9v8sGPjD4obg6gYfA2zHDkBF9vyNdyGBrGzRglBhrCzNGeA_a1ATgKw7IJ8ggm904I7q-4AKfiAOTraxaKdyUTg5ktWlAe8Lqceoz7dkKJRzZZqdP0s/s1600/travel2019.png"><img border="0" height="512" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjNJouWNUoYbG-4oq_o7OYhhJMdg9v8sGPjD4obg6gYfA2zHDkBF9vyNdyGBrGzRglBhrCzNGeA_a1ATgKw7IJ8ggm904I7q-4AKfiAOTraxaKdyUTg5ktWlAe8Lqceoz7dkKJRzZZqdP0s/s640/travel2019.png" width="640" /></a><br />
<br />
Built the Coleco menu software for the CollectorVision Phoenix. Buy page here (note I do not get anything if you buy one ;) )<br />
<a href="https://collectorvision.com/shop/colecovision/collectorvision-phoenix/">https://collectorvision.com/shop/colecovision/collectorvision-phoenix/</a><br />
<br />
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjPr7UKxa6lrtWcnHzu-Q0Ff0Gs2G-mHBvwwjLs9ePSNkMxYPttjXC5P2wZEhWkgNp1WY0K6dBh01oQ9k2KNJOXddd-cHeLw6d979I-Xp_E6RvdKVpQ6vbHnUC3vndfBwVcHZNqPi2a5Yez/s1600/Clip0001.png"><img border="0" height="500" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjPr7UKxa6lrtWcnHzu-Q0Ff0Gs2G-mHBvwwjLs9ePSNkMxYPttjXC5P2wZEhWkgNp1WY0K6dBh01oQ9k2KNJOXddd-cHeLw6d979I-Xp_E6RvdKVpQ6vbHnUC3vndfBwVcHZNqPi2a5Yez/s640/Clip0001.png" width="640" /></a><br />
<br />
Shipped nearly two dozen of my PS/2 keyboard adapter chips for the TI. At least /someone/ wanted it! ;)<br />
<a href="http://harmlesslion.com/software/keyboard">http://harmlesslion.com/software/keyboard</a><br />
<br />
<img alt="Image result for avr mcu"" src="https://cdn10.bigcommerce.com/s-vt19phz/products/1815/images/4310/ATmega1284PU_Tronixlabs_Australia__20484.1412653331.1280.1280.JPG?c=2" /><br />
<br />
I stepped out of my comfort zone, and did a "Haunted Cocktail Night" in Los Angeles. This was cute, and it was a set of scenarios in a fairly old mansion, including ghost actors you could interact with. But... it wasn't really creepy, it wasn't cohesive enough. It would be crazy hard to put such a thing together, and it was fun, but I would have done it differently. ;)<br />
<br />
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjEunJQ7ecsy0WA7yHvCwQms-Incv6BsTnZEoqmvctCeM_RFw_wSqx0sdfzPQr6Pm10Ftsu4ZtOJnwrZbidxiKCbLtYNP5GwaDaCk8uEsqdaObIp8qVuJ1vux-Z0Cp3gjAR69Hsl_ICw1Oq/s1600/EHNCvzbVUAAUdkv.jpg"><img border="0" height="360" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjEunJQ7ecsy0WA7yHvCwQms-Incv6BsTnZEoqmvctCeM_RFw_wSqx0sdfzPQr6Pm10Ftsu4ZtOJnwrZbidxiKCbLtYNP5GwaDaCk8uEsqdaObIp8qVuJ1vux-Z0Cp3gjAR69Hsl_ICw1Oq/s640/EHNCvzbVUAAUdkv.jpg" width="640" /></a><br />
<br />
.. and of course I got out to see Weird Al Yankovic in the Strings Attached tour:<br />
<br />
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjvvcG9umTeQSOW6sQuYcnXjFkSMlWXpWo-utPaScZYx4lZUhbVlVZ9irq7j7237E18ImQn4rpYmEYlQK7DcpNwBgAm31zN2TT94kN5GgUlTDSx_CPm_MpEmm-T7kl3-adVn0hAbqoHIX9I/s1600/EBqA0hkUIAEfpgD.jpg"><img border="0" height="360" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjvvcG9umTeQSOW6sQuYcnXjFkSMlWXpWo-utPaScZYx4lZUhbVlVZ9irq7j7237E18ImQn4rpYmEYlQK7DcpNwBgAm31zN2TT94kN5GgUlTDSx_CPm_MpEmm-T7kl3-adVn0hAbqoHIX9I/s640/EBqA0hkUIAEfpgD.jpg" width="640" /></a><br />
<br />
I worked out how to skin the cars in Wreckfest and published a little skin mod on Steam for my friends and I to use in our weekly game.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgjmLIVUukupAoCuicOMm93qOfDIhe83n9rtfICAy01XMPHiOXhiDEialAwVVhn1pkrinHZhJ1n0RLX5mVXR3bYjWcd8H-fMDZjOZrW-Gr44oOFcq_v4ZY-fXPS-Oe8sIt84BgBqDWNSFhz/s1600/Clip0006.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="288" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgjmLIVUukupAoCuicOMm93qOfDIhe83n9rtfICAy01XMPHiOXhiDEialAwVVhn1pkrinHZhJ1n0RLX5mVXR3bYjWcd8H-fMDZjOZrW-Gr44oOFcq_v4ZY-fXPS-Oe8sIt84BgBqDWNSFhz/s640/Clip0006.png" width="640" /></a></div>
<br />
And I created an MLP Random Scene generator to commemorate the end of the series. Just a silly little script I've run for years and named BIBO (for "Babble In, Babble Out" ;) ) It's not supposed to make sense!<br />
<a href="http://harmlesslion.com/cgi-bin/ponychat.cgi">http://harmlesslion.com/cgi-bin/ponychat.cgi</a><br />
<br />
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhaycMugMyMDyCmRxj3bvj7OSYUrk-mEjApVTMWiWgFTKnBGpZW4LRTvfGZ_J4WiNaX3bPhYT0DcCJDjuIAJMVKSAaX8hNvm4Vbzv-mZt35MU4gTmeuEHXEqS_F7UY2aZJ9u-6LKCBeFqtn/s1600/EJDeXT5U4AASMnz.jpg"><img border="0" height="530" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhaycMugMyMDyCmRxj3bvj7OSYUrk-mEjApVTMWiWgFTKnBGpZW4LRTvfGZ_J4WiNaX3bPhYT0DcCJDjuIAJMVKSAaX8hNvm4Vbzv-mZt35MU4gTmeuEHXEqS_F7UY2aZJ9u-6LKCBeFqtn/s640/EJDeXT5U4AASMnz.jpg" width="640" /></a><br />
<br />
There's still a month and a bit to go, but all I'm hoping to get done by end of year is an update to my TI music compressor, and there's not much of a picture to go with that anyway. ;)<br />
<br />
<div id="UMS_TOOLTIP" style="background: transparent; cursor: pointer; left: -100000px; position: absolute; top: -100000px; z-index: 2147483647;">
</div>
Tursilionhttp://www.blogger.com/profile/16478174231304644316noreply@blogger.com0tag:blogger.com,1999:blog-7717886351507761714.post-79579735350798288852019-08-07T22:47:00.003-07:002019-08-07T22:56:44.825-07:00The Lifecycle of a Commercial Software ProjectI seem to have been around enough times that I'm starting to detect a pattern. I thought I'd share my observations and see what other people had in mind. It's kind of a frustrating one to me - I'm a huge fan of continuity - because it seems to define that all commercial projects are doomed to die.<br />
<br />
So in phase one, we have the wild west. The project begins life - sometimes with formal blessing and sometimes without. The developers are the die-hards who believe in the project and put in crazy amounts of effort to putting it together. There's minimal oversight at this point - the team trusts each other. The team is usually in constant communication about what they are doing and what needs to be done next, but it's hardly formalized.<br />
<br />
In phase two, the efforts of the developers have paid off. The project has crossed a major milestone, been revealed to all, and possibility even filled a hole that the company needed filled. Everyone is very excited, not least because the project seems to have come out of nowhere to meet a need. Now management is involved in taking this generally-still-rough-around-the-edges project and "finishing" it. Sometimes this is also called productization. But the main point is that someone is now in charge of choosing a future for the project. Everyone is still pretty happy and additional developers are often added. Source control becomes formalized. Everyone wants to use the product, although it requires updates to meet their exact needs (which the developers are happy to do).<br />
<br />
In phase three, the product is more or less mature. It still has rough edges, since the resources planned for the grand designs in phase two were diverted to unexpected feature requests. New developers are added to increase the head count and try to catch up - costs increase. The product sees massive growth in feature set but little polishing. New features are published early in order to get back to the main tasks and frequently cause bugs to be seen by end users, resulting in a tightening of code quality standards such as code review and a decline in reputation.<br />
<br />
In phase four, upper management begins to ask the project management why the product is still so unpolished and why it has so many bugs, despite the time and money put into it. Demands for better tracking of resources and money are put into place. Bug tracking and time tracking become formalized, and statistics are often added to the regular process, increasing the time spent managing the product. Demands begin to be made that the developers focus only on what the manager dictates needs to be done, and not side issues that the developers consider important. Small bugs linger and user satisfaction begins to fall. The developers begin to complain that they need permission to work on the aging architecture and to correct user satisfaction bugs.<br />
<br />
Phase four may linger for a long time, but eventually it grows to phase five. Management decides that the number of things that lead developers have stated need attention is too large a list to handle in a cost-effective manner. The project is put into a bug-fix-only mode while a replacement is designed and built from scratch. Note that although there's often some planning sessions, the replacement project usually starts in phase one.<br />
<br />
I've been all the way through this loop a few times, and been at various points of it on various other projects, and I am becoming convinced that it's inevitable. Look, software is expensive and it's very difficult to quantify. It's hard to plan, it's hard to maintain, and it's hard to get right. We need to stop pretending that there must be a silver bullet out there if we just find the right way to manage the project.<br />
<br />
The truth is that phase one probably accomplished 80% of everything the product needed for its entire lifespan. And that should really be the statistic that makes the most sense. No matter what some people who don't write real software for a living may claim, it's not something that you can just plan out to the smallest detail, because unlike so many sciences that can (I'm thinking architecture here), SOFTWARE DOES NOT EXIST IN THE REAL WORLD. That's right - it's completely virtual. It doesn't obey <i>any</i> laws of nature.<br />
<br />
To write software, a person needs to have a firm grasp on how to tell an imaginary concept to do a real world task. They need to be able to abstract thousands of steps, put them in the right order, and then be able to anticipate all the wrong ways that a person will try to interact with those thousands of steps. BUGS ARE INEVITABLE. You can mitigate some of them (see earlier blogs), but by god stop pretending you can prevent them all. Assume that EVERY LINE OF CODE WILL NEED ATTENTION SOMEDAY.<br />
<br />
It's also important to keep in mind that if you are not a user of the software and you are not a developer of the software, you are not qualified to determine what the software NEEDS. If you're a manager and you came in to manage the product before you even knew it existed, then get over yourself. You need to buddy up with one of the developers, understand what it does, and work with them when you're making decisions. It's all too easy to focus on the wrong parts of the product, or to choose a forward path that is completely against all of the design to date (been to this one specifically). This will make the product worse, not better. Even better, become a user. Use the software daily. Make it something you HAVE to use. Then you'll better understand why those little usability bugs are a big deal. ;)<br />
<br />
I'm pretty convinced that the longer a project survives before phase three, the more successful its life will be. It's good to have some structure - source control is critical. Code reviews are useful. Even a bug tracker is a good thing to have. But when you get into late phase three and phase four - all of these useful things start to be used against the project. Why is there so much code churn? Why are so many people wasting time with code reviews? Why are there so many issues in the bug tracker? Good things become bad because they are seen as wasting money, when in fact they are preventing waste by reducing the issues before they are seen in the field.<br />
<br />
What's your experience with the commercial software life cycle?<br />
<br />Tursilionhttp://www.blogger.com/profile/16478174231304644316noreply@blogger.com0tag:blogger.com,1999:blog-7717886351507761714.post-53027608669793477712019-08-04T16:36:00.000-07:002019-08-04T16:36:45.922-07:00What's New<span style="font-family: "verdana" , sans-serif;"><span style="background-color: white;">Since finishing off Dragon's Lair, I've actually been sidetracked working on the CollectorVision Phoenix (</span></span><a href="https://collectorvision.com/shop/colecovision/collectorvision-phoenix/">https://collectorvision.com/shop/colecovision/collectorvision-phoenix/</a>)<span style="background-color: white; font-family: "verdana" , sans-serif;">, which is coming out soon. I've done a basic loader for the ColecoVision that will hopefully work well enough for people. We'll see when you get it!</span><br />
<span style="font-family: "verdana" , sans-serif;"><span style="background-color: white;"><br /></span></span>
<span style="font-family: "verdana" , sans-serif;"><span style="background-color: white;">Since that's done, I'm trying to get my todo list started. It's sobering to look at that list, do the math, and realize I will not likely finish it. Stupid mortality. ;)</span></span><br />
<span style="font-family: "verdana" , sans-serif;"><span style="background-color: white;"><br /></span></span>
<span style="font-family: "verdana" , sans-serif;"><span style="background-color: white;">You can look too! Then vote on what I should do! <a href="http://harmlesslion.com/cgi-bin/walrusshow.cgi">http://harmlesslion.com/cgi-bin/walrusshow.cgi</a></span></span><br />
<span style="font-family: "verdana" , sans-serif;"><br /></span>
<span style="background-color: white; font-family: "verdana" , sans-serif;">Unrelated to the task list, I just published a new version of Flipterm, in case anyone was using that. Flipterm is a text-based MUCK client. A MUCK is comparable to a MUD, and that probably doesn't help you at all. ;) MUD stands for 'Multi-User Dungeon', and before everything was a first-person shooter, this is what an MMORPG looked like. It was a lot like those old Infocom text adventures, except there were other people in the room as well.</span><br />
<span style="background-color: white; font-family: "verdana" , sans-serif;"><br /></span>
<span style="background-color: white; font-family: "verdana" , sans-serif;">Imagine a modern chat room or Discord server, but without the GIFs.</span><br />
<br />
<span style="background-color: white; font-family: "verdana" , sans-serif;">Anyway, FlipTerm is derived from the old GMud, and I started working on it back in 2002. It was pretty much stable since then, only minor fixes, but I was finally asked to make a few improvements, and took it as an opportunity to update the codebase.</span><br />
<span style="background-color: white; font-family: "verdana" , sans-serif;"><br /></span>
<span style="font-family: "verdana" , sans-serif;"><span style="background-color: white;">Oh my god it's an awful codebase. It started rough, and then I was clearly learning as I went, not only MFC and MDI, but C++ itself. </span></span><br />
<span style="font-family: "verdana" , sans-serif;"><span style="background-color: white;"><br /></span></span>
<span style="font-family: "verdana" , sans-serif;"><span style="background-color: white;">Anyway! Upgraded* the code to Visual Studio 2017, which came with a whole new MFC mindset for MDI that took a few days to get updated. Should be only minorly visible, though for free it did bring a new docking paradigm that has snazzy looking controls, and tooltips are nicer looking. It also, for free, fixed the docking preview on high DPI (ie: 4k) monitors, as that was kind of messed up.</span></span><br />
<span style="font-family: "verdana" , sans-serif;"><span style="background-color: white;"><br /></span></span>
<span style="font-family: "verdana" , sans-serif;"><span style="background-color: white;">(* - haha, "Upgraded". I fixed the parts that didn't work and left the rest as-is. I'm not that crazy!)</span></span><br />
<span style="font-family: "verdana" , sans-serif;"><span style="background-color: white;"><br /></span></span>
<span style="font-family: "verdana" , sans-serif;"><span style="background-color: white;">From the user point of view, the enhancements are:</span></span><br />
<span style="font-family: "verdana" , sans-serif;"><span style="background-color: white;"><br /></span></span>
<span style="font-family: "verdana" , sans-serif;"><span style="background-color: white;">- updated docking to modern version - fixes high DPI and provides better(?) user feedback</span></span><br />
<span style="font-family: "verdana" , sans-serif;"><span style="background-color: white;">- removed MCP and the plugins. Nothing important ever used any of them.</span></span><br />
<span style="font-family: "verdana" , sans-serif;"><span style="background-color: white;">- mouse scroll wheel works on the main output window and not just the input window (the one thing that did bug me for the last ten years or so ;) )</span></span><br />
<span style="font-family: "verdana" , sans-serif;"><span style="background-color: white;">- word wrap settings now reformat the view when you resize the window (huzzah!) (unless you are using the fixed 80-column mode, but I'm not sure why anyone would anymore.)</span></span><br />
<span style="font-family: "verdana" , sans-serif;"><span style="background-color: white;">- when you start a log after logging in, then log back to the beginning, the formatting of the old text is as-received instead of as-formatted, which makes logs more consistent.</span></span><br />
<span style="font-family: "verdana" , sans-serif;"><span style="background-color: white;"><br /></span></span>
<span style="font-family: "verdana" , sans-serif;"><span style="background-color: white;">Not much, really, but several nights of deep diving to get it all working with the new system. Hopefully good for another ten years!</span></span><br />
<span style="font-family: "verdana" , sans-serif;"><span style="background-color: white;"><br /></span></span>
<span style="font-family: "verdana" , sans-serif;"><span style="background-color: white;">Grab it over on Github here: <a href="https://github.com/tursilion/FlipTerm">https://github.com/tursilion/FlipTerm</a></span></span><br />
<br />Tursilionhttp://www.blogger.com/profile/16478174231304644316noreply@blogger.com1tag:blogger.com,1999:blog-7717886351507761714.post-33088566531954677482019-05-31T16:07:00.001-07:002019-05-31T16:07:21.479-07:00Classic99 DebuggerRecently, I've been rather bubbling over how excited I am to have the Classic99 debugger working for ColecoVision software, and in my last post I promised to talk about that some. So I think I will.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEguDQcWCuFcz3WK79OMzOzOrhSFOuwbp_vHHRzZoxDm87KuwN7Si0k5k6r7xHMboB9x7Mt7yHlHrB_K_4LL1HJA2djj0gGpq9x15aB8m21LLivUOrlNMn2nLERV2sIC_lb1CUcOcw6BVI2v/s1600/p1.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="937" data-original-width="1600" height="187" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEguDQcWCuFcz3WK79OMzOzOrhSFOuwbp_vHHRzZoxDm87KuwN7Si0k5k6r7xHMboB9x7Mt7yHlHrB_K_4LL1HJA2djj0gGpq9x15aB8m21LLivUOrlNMn2nLERV2sIC_lb1CUcOcw6BVI2v/s320/p1.png" width="320" /></a></div>
<br />
<br />
While still lacking a number of features I'd really like, it really is my favorite retro-debugger. Since I wrote it, I'm clearly biased, but I also worked to get the features I actually need into it. Some of these features - I'm really baffled that other emulators DON'T have them.<br />
<br />
The first feature, and nobody seems to do this, is <b>real-time view</b>. While the system in running, you get a real-time view (updated roughly 10 times per second) of whatever window you are looking at. You can see the disassembly flying by (very useful for seeing tight loops), or you can watch memory in real time (looking for a RAM access pattern - here you go!) All the while, the current system registers are ALWAYS available.<br />
<br />
In addition, while less often useful, the commands that let you ALTER memory or registers are available at all times. Usually it's more useful to breakpoint first, but sometimes you just want to end a timed delay early, and you can just write the register directly without freezing execution. Even on the Coleco, which has far fewer registers than the TI, this is useful.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj2z0aS_qAy_ip9y7FNdw2psdb_ACZJMefPLGu77XUXp3WYSTFNUFXAvGBOz37OY4cwkWVVmhB6GPZ0n_4NDmLSbpikXltrjoqc7G4NFVrdB1dJVqhkQerokrQdEvLgUsxmal-_q1uK5mFc/s1600/p2.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="466" data-original-width="574" height="259" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj2z0aS_qAy_ip9y7FNdw2psdb_ACZJMefPLGu77XUXp3WYSTFNUFXAvGBOz37OY4cwkWVVmhB6GPZ0n_4NDmLSbpikXltrjoqc7G4NFVrdB1dJVqhkQerokrQdEvLgUsxmal-_q1uK5mFc/s320/p2.png" width="320" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
The second feature is <b>flexible breakpoints</b>. Again, there's more to do here, but I can break on PC, or I can break on read or write or either to a particular address in any of the system memories, or I can break on a particular value being written to a target memory. In addition, in case I don't know the exact address, any memory can be a <i>range</i>. I can even look for <i>single bits</i>. Many of these options would be difficult to implement on real hardware, but an emulator doesn't know the difference between real and simulated.</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
The breakpoint system even allows non-break functions, in this case it can count cycles between two addresses for performance monitoring, or even log all writes to a particular address to a disk file! Want to capture a speech pattern or a song, this can do it.</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgz2Uxuz-RpfyYbD40IfH1vOYca89hinHjG_IKQWu-3woOXUnsQYtXpHyCc-Ly4tqb92X68chj9uGpSeSeN_wPyZdOwQ-u_lJBIt3Ddne0MsG2xduoIozeexeFwEF07rxVHaf5dn7OSlUBH/s1600/p3.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="596" data-original-width="886" height="215" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgz2Uxuz-RpfyYbD40IfH1vOYca89hinHjG_IKQWu-3woOXUnsQYtXpHyCc-Ly4tqb92X68chj9uGpSeSeN_wPyZdOwQ-u_lJBIt3Ddne0MsG2xduoIozeexeFwEF07rxVHaf5dn7OSlUBH/s320/p3.png" width="320" /></a></div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
The ability to <b>single-step</b> and immediately see the result of an instruction is invaluable. This one at least, most debuggers do implement. Classic99 of course lets you alter any register while paused or running, including the program counter, which allows you to go back and retry a piece of code with different inputs, or even change the code on the fly (although you need to enter the hex bytes manually.)</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
While still rough, Classic99 also allows debug of both the host CPU and the F18A GPU at the same time.</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
Within an hour of having the debugger available to ColecoVision software, I was able to troubleshoot a problem with the emulator's implementation of NMI, and observe the memory access patterns of a number of Coleco games. I even engaged in a little bit of cheating on a favorite game (Antarctic Adventure: time remaining 0x60e3 (16-bit BCD, maximum value C60E3=9999), distance remaining 0x605e (16-bit BCD, finish level now C605E=0100)).</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
That's really all I have to say. The main deficiency I see in other debuggers is the lack of real-time view, which really slows me down. Stability seems poor on some, as well. At the same time, there are features in other emulators I also plan to implement, like <b>sprite and tile views</b>, <b>audio waveforms</b>, and more.</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
I use the Classic99 debugger almost all the time, to debug my own code, to reverse engineer others' code, and even to debug the emulator itself. It's an invaluable tool that too many emulators treat as a secondary add-on.</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<br />Tursilionhttp://www.blogger.com/profile/16478174231304644316noreply@blogger.com0tag:blogger.com,1999:blog-7717886351507761714.post-23450001187311654182019-05-14T14:27:00.003-07:002019-05-31T16:28:24.681-07:00Whoooops, been neglecting you!My... what... two readers? Oh, you only found this through a Google search? Good enough then!<br />
<br />
So, Dragon's Lair is finished and done! I still have about 200 PCBs that need a new project as I can NOT put Dragon's Lair on them (seriously, I will ignore any more questions about just pretending I forget about licensing, unless accompanied with a dump truck of money parked outside the front door when I go to look).<br />
<br />
I did publish my followup as a slideshow - if you want to know about the building of Dragon's Lair, have a peek here:<br />
<br />
<a href="https://docs.google.com/presentation/d/1u7SOusjQDInq95GrEH2tmIphUAjRg-9YbhR_X25D62A/">https://docs.google.com/presentation/d/1u7SOusjQDInq95GrEH2tmIphUAjRg-9YbhR_X25D62A/</a><br />
<br />
I also put up a Ko-Fi, though I probably don't post here enough to be worth it. ;) But have a peek here: <a href="https://ko-fi.com/tursilion">https://ko-fi.com/tursilion</a><br />
<br />
With all that out of the way, I wanted to talk some about emulation.<br />
<br />
For many years now I've had a TI emulator called Classic99. I started it back in 1996 or so so I could have my own emulator to play with, since V9T9 was pure x86 assembly and PC99 was closed source. While development has frequently been slow it has at least been steady, and the emulator has a lot of features that help with debugging software. At first I would breakpoint the source code of the emulator itself, and write C code for whatever I wanted it to dump, but over time most of the reasons I needed to do this were coded into the debugger, and today it's reasonably comprehensive. (It still needs a 'cheat' search and remapper...)<br />
<br />
Anyway, I also play around with the ColecoVision a lot. It is, at the basic level, the same machine as the TI except that it has a different CPU. Where the TI has a TMS9900, the ColecoVision has a Z80. There are, of course, some other gotchas - but that's enough to get going.<br />
<br />
There are a handful of emulators for the ColecoVision. My favorite is probably BlueMSX, ColEm is probably the best known, and CoolCV seems to be the new hotness. There are many others, including the catch-all MAME. But when I start writing code and I actually need to test it, I need three things:<br />
<br />
1) I need a fast way to launch my code<br />
2) I need a debugger that lets me view the system state, single step and observe results, find and set breakpoints, etc.<br />
3) I need a codebase I can modify in case I am using hardware the emulator doesn't support<br />
<br />
BlueMSX was my favorite, it came close. True, when I changed the code it broke the debugger for reasons I couldn't guess, and the debugger only works when the emulation is paused, but at least it was in a separate window, let me view memory and set breakpoints.<br />
<br />
Last night I loaded up a new project that I was sure worked a couple weeks ago, hit run in BlueMSX, and nothing came up. I loaded the debugger, and a few minutes later I closed the whole thing down. I was tired of dealing with partial debuggers that only let me view some information at a time, only in certain cases. I was tired of code bases that treated complexity like a badge of honor and made building the code a challenge. And I was tired of systems that locked you in to some other systems' way of thinking (I run Windows, I want a Windows interface, thanks.)<br />
<br />
This isn't unique to the ColecoVision, by the way, I had the same issue with Sega Genesis debuggers (but the code bases were easier to build.)<br />
<br />
I pulled Classic99 up. I've been approaching this point for a while, but I finally went for it. All I needed, in theory, was a Z80. As I'm in the middle of a rearchitecture, I decided to just hack it in for now, since the new code base won't be ready for a while. I ended up creating a new working folder.<br />
<br />
Then, I hunted down a Z80 core. I found a nice single-file one that was recently updated, but it required this magic include library. This library is apparently great because it doesn't use any of standard C, and is a pure header library. Personally, I think that's a stupid thing to be proud of. First off, the standard C includes are, you know, STANDARD, and have been for nearly half a century. It's okay to use them! Second, this code didn't do anything weird enough to warrant it.<br />
<br />
When I saw that one of the purposes of this library was to redefine its own types for char, int, short, etc (and not using the standard terms, but using its own terms so you're locked in), that was when I discarded it. I created my own include file, and in about 15 lines had everything that this code used.<br />
<br />
Yeah... 15 typedefs is why I needed to download this whole other library. Kids these days.<br />
<br />
Unfortunately, there was an entire struct not defined anywhere in the code. There was a script that I guess was meant to generate the missing header file, but, you know, Windows loser. So I actually found another project that already had this missing file, dropped it in, and built. F$#%#$ everything.<br />
<br />
Okay, now at least the Z80 core itself WAS as simple as I could have hoped, and the documentation adequately described what you needed to do to set it up. (Except for mentioning you had to provide your own copy of the context struct, but I guess that's fair. Would have liked to see it called out).<br />
<br />
The memory read/write and IO in/out functions were easy to link to the existing Classic99 functions. I added basic joystick emulation and handled the NMI in the interrupt code. I put the reset calls in with the reset of the 9900 and F18A cores, and then I hacked in some extra code to load the ColecoVision BIOS and copy the loaded cartridge over to Coleco space, which made the Classic99 load functions work. (I gave the Z80 its own memory since the 9900 memory space is quite different, having hardware overtop of the cartridge space). Finally, after considering it for a bit, I threw a hacky call to run Z80 cycles next to the call to run a 9900 instruction. This wouldn't give correct speed, but it would at least provide SOME throttle. Oh! And I disabled the TI CRU code that read the keyboard and joystick, so it would not get input.<br />
<br />
Then I shrugged my shoulders and hit run. To my surprise, I got the TI title screen, but corrupted with the wrong colors and graphics. But this was a good thing - it means that it worked!<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjXMMW48Qpt4QP6lUyF_E9XWhcyhF33Qc1h5bM8Pvmr4qJb7ev7pzrHCc6k7iUgFnTzTBP50NT7N4gqayynbGWsjFeUWK1TNHIi5V6HhJxMI9QiqANvlf53F3_S4L4fqrrKH0EGBiUBv6hJ/s1600/screen1.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="266" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjXMMW48Qpt4QP6lUyF_E9XWhcyhF33Qc1h5bM8Pvmr4qJb7ev7pzrHCc6k7iUgFnTzTBP50NT7N4gqayynbGWsjFeUWK1TNHIi5V6HhJxMI9QiqANvlf53F3_S4L4fqrrKH0EGBiUBv6hJ/s320/screen1.png" width="320" /></a></div>
<br />
What do I mean it worked? Well, both the ColecoVision and the TI started at the same time, sharing the hardware. The TI was slower, so it drew the title screen last, but the ColecoVision set the video registers last. In other words, I knew that the Coleco side did SOMETHING! I also knew my original plan, to just leave the TI on the master title page, wouldn't be enough.<br />
<br />
When Classic99 boots, it used to start the CPU before the ROMs were loaded, which sometimes caused a startup crash on the emulation side. Back then, I implemented a tiny boot ROM that spins the 9900 until it's ready to go. Since that was still in there, I just reloaded the boot ROM before the reset - now the 9900 was still spinning (and so providing timing to much of the system), but it wasn't doing anything useful.<br />
<br />
When I reset it again, the ColecoVision splash screen came up!<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjkRdou8gQALlQ9f_-S3Ck5KH-s7gdscTuGNxk3Iek5lIKjR45YHA-cnN7iWIkeWAew8g0Xh62x3mb0QhxCJOQGwDNssq6U9gEkeNmzOB5ZcgomEsf5Hon4qmOczRZWe47BVYtS-7zTozAT/s1600/screen3.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="266" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjkRdou8gQALlQ9f_-S3Ck5KH-s7gdscTuGNxk3Iek5lIKjR45YHA-cnN7iWIkeWAew8g0Xh62x3mb0QhxCJOQGwDNssq6U9gEkeNmzOB5ZcgomEsf5Hon4qmOczRZWe47BVYtS-7zTozAT/s320/screen3.png" width="320" /></a></div>
<br />
I booted up Donkey Kong, but something was still wrong, after selecting the number of players, it just hung on the main screen:<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhFQFMzC3eqtYAwQOgLwrn7aPDxBY8bDXq84MpVG2oPxX3nfBISInK2ZDoef794gGC6Hv3pm5T0dD3RSOxg9beZ3Ya0ETL6b5mobivAxn3NXxJJBrdd2gKutM5Bb4R2dnS28S7-vV-KcDH2/s1600/screen2.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="266" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhFQFMzC3eqtYAwQOgLwrn7aPDxBY8bDXq84MpVG2oPxX3nfBISInK2ZDoef794gGC6Hv3pm5T0dD3RSOxg9beZ3Ya0ETL6b5mobivAxn3NXxJJBrdd2gKutM5Bb4R2dnS28S7-vV-KcDH2/s320/screen2.png" width="320" /></a></div>
<br />
But now I could <i>already</i> start using tools I didn't have just two hours ago - the debugger. Although I didn't have Z80 debug yet, I did have VDP debug. I was quickly able to determine that interrupt processing, which is central to most Coleco actions, was not happening. After checking a couple of other games and finding that everything had similar issues, I finally noticed in my code a little hack I entered. The Z80 core takes the NMI input as a pulse, rather than taking a level (and dealing with the edge itself, like the hardware does). But the flag that I'd used for edge detection was temporary, meaning my code never caught the edge. Once I fixed that...<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiOsJW-UB1Fwi0AOCi-KvI-J4kQdvfk5-KQfCcwCZeOmaRvhxQhApnkPwunTw79hfBbIftemO2TfHK0EfAGTgYrNla2_Q_aX92YEuIi0oRHpDKu-E_eUirRGEEYGltJRAiyJpiy3NjwjoOA/s1600/screen4.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="266" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiOsJW-UB1Fwi0AOCi-KvI-J4kQdvfk5-KQfCcwCZeOmaRvhxQhApnkPwunTw79hfBbIftemO2TfHK0EfAGTgYrNla2_Q_aX92YEuIi0oRHpDKu-E_eUirRGEEYGltJRAiyJpiy3NjwjoOA/s320/screen4.png" width="320" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
After roughly three hours, including fighting with the compiler and tracking down foreign libraries, it was running. I had to invert the bits on the joystick, as I'd coded them with the wrong polarity, but that was it. I had a game of Donkey Kong, and got halfway around the world in Antarctic Adventure (a game I'd always wanted to see on the TI, actually...) Everything 32k or less worked, so, I have a functioning base.</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
I just need to add a disassembly and put up the Z80 registers instead of the 9900 registers, and I can use this for dev. (I also need to add megacart emulation and a couple of other small devices, another evening or two will do).</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
Sadly, I can't share this code as the GPL licenses conflict with my own, but it's a good learning experiment to see that it DOES come together as expected. Once I get the new architecture out, the multiple CPUs will be a lessor issue and easier to update.</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
Edit: I guess I forgot to mention why the Classic99 debugger is any better than anyone else's. I'll cover that later, when I update it, but for now, here's an example of the debugger being used to cheat at Alpiner: <a href="https://www.youtube.com/watch?v=_qjZN6qf1wk">https://www.youtube.com/watch?v=_qjZN6qf1wk</a><br />
<br />
<br />Tursilionhttp://www.blogger.com/profile/16478174231304644316noreply@blogger.com1