Tuesday, July 30, 2013

RC 2013 SC Wrap-Up

Once again, a Retrochallenge event draws to a close.  As usual, I have greatly enjoyed participating in this event.  Setting some deadlines is a good way to motivate progress on a project, even silly ones involving retro computers.  Plus, it is always great to have the recognition and the feeling of accomplishment that comes from having the audience that comes with participation in a great event!

Recap

My project for this month was to adapt the Dunfield Micro-C compiler for building code to run on the CoCo.  Initially I just wanted to make it relatively simple to use the tool for building simple CoCo programs.  After some initial victories, I went further by supporting a variety of ways for loading and starting such programs.  I also now support several options for passing data between C programs and the built-in Color BASIC on the CoCo.  To prove the point, I implemented a couple of non-trivial CoCo programs in C -- an animated clock display and a solver for Sudoku puzzles.  Although I have more in mind to do on this project, I am extremely happy with the results as they stand right now!

Benefit

The CoCo community has a bit of a schism between users of OS-9 (or its descendant Nitros-9) and those that mostly stick to the Disk Extended Color BASIC (DECB) environment.  For sure, most CoCoNuts have a foot in each camp.  Yet, most prefer one or the other.  Each option has its own merits, but those that prefer the DECB environment usually cite both simplicity and the direct control of the CoCo's hardware as important strengths.

Both camps have both BASIC (including BASIC09) programmers and assembly language programmers.  The OS-9ers have also enjoyed a C compiler for decades, but the DECB-based C compilers are mostly the stuff of barely remembered advertisements in The Rainbow.  Now, the DECB crowd has at least the beginnings of another option!

Onward

I have really enjoyed using C to program for the DECB environment.  So, I am planning to continue this project in the hopes of enabling more CoCoNuts to have the same opportunity.

As I have pursued this project, I have generated a list of more TODO items than I have had a chance to pursue.  These include a few more startup options, code libraries, hardware drivers, and the like.  I expect to hit many of these over the next few weeks or months.  If nothing else, then I should have something together by next year's CoCoFEST!

Normally I would like to have more code to release at this point.  Unfortunately, I haven't had a chance to pull a release package together.  Since this project depends on the Dunfield compiler distribution, I want to make sure that I can release something as clean as possible to make the distinction clear between my code and the Micro-C package.  Also, I want to put together at least some minimal documentation on how to put everything together in order to start building CoCo programs!

So, for now you will have to make do with the bits and pieces that I have released along the way.  I hope that whets your appetite for more.  If you want to collaborate on advancing this project, then feel free to contact me and let me know so.  And, in any case, be sure to stay tuned... :-)

Sunday, July 28, 2013

Sudoku Solver

My Micro-C for CoCo project is showing some real strength!  Yesterday, in just a couple of hours I was able to crank-out a non-trivial C program to solve a popular style of number puzzle.  That was a lot of fun!  Moreover, it was simpler than trying to implement the same thing in pure assembly language and the resulting program ran a lot faster than it would run if it were written in Color BASIC.

Sudoku

In the past decade or so, Sudoku puzzles have become as commonplace as the venerable crossword puzzle.  The use of numbers seems to have a special appeal for some folks, and it has been quite common for people to implement solvers for these puzzles as a programming exercise.  Quite a lot of discussion is available over various algorithms for solving such puzzles, and implementations of these algorithms are quite numerous.

A friend of mine had such a project a while back.  When he learned of my current project, he jokingly suggested that I should try to compile his solver for the CoCo.  I think that his project implemented some clever algorithm or another -- I never saw his code, so I don't know if it would be out of the question for the CoCo or not.  But, I did find a brute force algorithm that seemed simple enough to implement.

Recursion

If one makes the distinction between computer scientists and computer engineers, one often finds that the scientists love recursion while the engineers are more skeptical.  To be sure, recursive algorithms often lead to elegant programs that are powerful, expressive, and succinct.  On the other hand, language implementations often impose practical costs on function call stacks that can grow very deep with recursion.  The engineers...ahem...are correct, of course!

Recursive algorithms are only safe when there is a finite and tolerable limit to the recursion.  In the case of Sudoku, there are only 81 positions on the game board to evaluate.  My implementation uses a recursive, brute force algorithm, and it runs without issue in the 8K of RAM that I'm currently allocating for the code and the stack.  It will probably run in half of that or even less, but I haven't tested to find out.

Load 'Em Up

A puzzle solver isn't of much use if it always solves the same puzzle.  On the other hand, writing a puzzle editor doesn't sound like much fun for the amount of effort involved.  What to do?  If only the CoCo came with some sort of built-in editing facility that could help with such tedious tasks...hmmm...

Rather than delving into the minutiae of building a Sudoku editor in C, I decided to let BASIC do the work for me.  I wrote a short BASIC program that first reserves space for the C program and loads that there.  The BASIC code then READs the Sudoku game setup from the included DATA statements and pokes that into memory where the C program can find it.  The puzzle can be changed by simply editing the DATA statements to reflect the new puzzle.  It would be hard to make things any easier, and IMHO it isn't worthwhile to do so.


Burlington Mini Maker Faire

Where I live, we have a little "maker club" called the Alamance Makers Guild.  Last year we held a mini Maker Faire at the local mall, and we will do so again this year on August 17, 2013.  At last year's event, Fahrfall made a good showing and at least some people seemed to enjoy seeing that and my video player for the CoCo3.  I think the Sudoku solver will make its public debut there this year, and I am planning to make a little contest out of it.  I'm thinking that I will challenge humans to see if they can solve a Sudoku puzzle before the CoCo can do it.  I might even make them edit the BASIC program with the Sudoku data themselves before they run it!  Well, it sounds like fun to me...

This seems like a high note on which to end this summer's Retrochallenge event.  I probably won't be doing much more technically on this project before the end of that event.  I do, however, plan to be back with a more reflective post as a wrap-up.  Until then, please do stay tuned...

Friday, July 26, 2013

Marking Time

It is time once again for another exciting update on my Micro-C for CoCo project.  It has been a busy week for me here in North Cackalacky!  Unfortunately for me, it has mostly been a "work" kind of busy...  Nevertheless, I have been able to make a little progress on my project.

Pak It In

Like many machines of it's era (e.g. the Atari 2600), the CoCo had the option of using software distributed on ROM cartridges.  The clever marketing folks at Tandy marketed this as "Program Pak" software...  In any case, there are advantages to this software format.  So, it might be nice to distribute compiled C programs the same way.

Relocating the compiled code to the ROM cartridge address space is the obvious first step.  An added twist is the question of where to put the variables.  Obviously, storing "variables" in ROM is of limited value.  Luckily, the Dunfield library already provides for allocating variables in a different address range from where the code resides.  Yet another variation of the startup code allows for selecting this configuration.


Many programs require the use of interrupts for proper operation.  But, handling interrupts requires machine-specific accommodations that aren't part of the standard C language.  Many compilers provide mechanisms for implementing interrupt handlers in C, and Micro-C is no exception.  Unfortunately, the default mechanism provided with the Micro-C package generates code to hook the 6809's interrupt vectors in a ROM image.  That is fine for use in an embedded system, but it won't work with the CoCo.

The CoCo ROMs redirect the interrupt vectors through a secondary set of vectors in RAM.  Using the stock Micro-C interrupt implementation as a guide for interfacing with the compiled code, I implemented a CoCo-compatible version.  My implementation uses a macro to output some inline assembly code in order to establish some code labels and to provide a 'trampoline' function.  The trampoline function calls the C interrupt handler and then uses an RTI instruction to resume normal operation of the CPU.  I also added some macros to make it easier to point the secondary interrupt vectors at the appropriate handlers in the C code.

Time Flies

One of the few timing sources on the CoCo is the ~60 Hz Vertical Sync (a.k.a. "Vsync") interrupt.  With the code described above I was able to build a simple clock program that keeps time by counting Vsync interrupts.  I also used an inline assembly macro to provide access to the SYNC instruction.  This allowed me to properly time a colorful border animation for the clock -- the border is timed to complete a loop in approximately 1 second.  Just for fun, I compiled the clock to run in the emulator as a ROM image.  Since I didn't bother to burn a physical ROM, I also re-compiled the clock as a BIN file to load through the cassette interface on a real CoCo.


If you experiment with running my clock demo, you will find that the CoCo isn't really a very good time keeper.  Keeping time by dead reckoning with an almost-but-not-quite 60 Hz timing source doesn't compete with the accuracy of a Swiss watch!  I toyed with a few drift compensation strategies, but so far all I've done is prove that programming the CoCo in C is every bit as much fun as it is to program one in BASIC or assembly... :-)

Anyway, I guess that is enough for now.  Only a few more days remain for the Summer 2013 Retrochallenge event.  I hope to make the most of them, but I suspect that in any case I will be working on this project well past the end of the competition.  Either way, I hope you will stay tuned!

Sunday, July 21, 2013

BASIC Instinct

As I was working on implementing a CoCo API comparable to what Color BASIC provides, I had a couple of realizations.  The first was that while such an API might be superficially familiar to some CoCo programmers, it wouldn't necessarily be a good API for anyone to use.  The other was that an API implementation wasn't actually as interesting as some other aspects of the project!

So for now, I'll leave the remainder of the API library work undone.  I may return to expanding the library later, but for now I want to hit a few more objectives.  In this episode, we will look at interfacing C programs to Color BASIC...

CLEAR Some Space

Once again we come to the problem of where to put a program in the CoCo's memory space.  This is similar to what we faced before, except that now we have to share the available memory with a BASIC program at the same time.  What needs to happen is for BASIC to give us some space to live and for it then to leave us alone.

Color BASIC is ready for us.  The CLEAR command allows us to influence how BASIC allocates memory, including the ability to set a limit on the highest address BASIC will use for its programs.  This allows a BASIC program to make room for us before loading and executing our program.

Corresponding to that, I created options in the startup code to allow the C programmer to specify what CLEAR value is being used.  This causes the C program to be compiled to run in the proper space and to allocate memory appropriately.  More importantly, it provides us an open field in which to run without worrying that we might trample on something important to our BASIC program.


CoCo programs that don't interact with BASIC don't have any way to accept anything like a 'command-line argument', so there has been no need to worry about that until now.  BASIC doesn't offer C programs a command-line either, but there are ways to pass information to our C program if we so desire.  In fact, perusal of the Color BASIC documentation reveals that there are a variety of options for passing information both into and out of C programs.

Lacking a single path to follow, I implemented a variety of options in the startup code.  These correspond to the documented options for Color BASIC to pass information to a 6809 machine language program, and they require certain variations to the 'main' declaration in the C program.  Some of those options require data structures that are foreign to anything resembling standard C, so I also knocked together a header file to describe the various data structures involved.  I posted that header file and some sample prefix files that set options for the startup code, if anyone is interested.


The Color BASIC documentation had another interesting point -- the stack provided by Color BASIC is only good for about 30 bytes of usage.  It wouldn't take many levels of function calls with arguments pushed onto the stack to burn-up that little amount of space!  Not only that, but the Micro-C library's implementation of malloc presumes that the stack is at a higher address than the heap.  The memory provided by the CLEAR command is at a higher address than the Color BASIC stack, so malloc won't work with it.

The answer is simple enough -- allocate a new stack at the top of RAM.  Of course, in order to return to the calling BASIC program the Color BASIC stack pointer has to be saved at program entry and restored at program exit.  A few more simple modifications to the library startup code accomplished this task without incident.

So, now we can produce CoCo programs written in C that either stand alone or which can fully cooperate with programs written in BASIC.  Things are coming together nicely!  There is only a little more than a week left in the Summer 2013 Retrochallenge event.  Do you want to see what comes next?  Then I guess you'll have to stay tuned!

Monday, July 15, 2013

Know Your Compiler

We've reached the half-way point for the 2013 Summer Retrochallenge event!  I would, of course, like to be further along with my Micro-C/6809 support package for the CoCo.  But, overall, I think the project is making good progress.  Over the weekend I posted about my success at getting some initial routines implemented, and I was able to show a simple low-res graphics program running.  In the process, I have learned a bit more about how that compiler works and how best to make use of it.

Cast Away

When I was implementing a routine to compute the address for a byte of graphics data, I discovered an anomaly.  I initially tried to use an expression that added a computed value to a constant offset, but found that the resulting value was incorrect.  Surprisingly, separating the addition of the computed value into a different line from the initial assignment of the offset value resulted in a correct result.  Reviewing the generated code showed that the non-working case was adding a 16-bit constant to an 8-bit register -- oops!

Compilers often have quirks, and "small" compilers often have some weird ones.  I suspected that I might have been hitting one of those, so I reviewed the docs that came with Micro-C.  The docs revealed that due to performance considerations (i.e. a preference for 8-bit operations), untyped constants used in an expression with 8-bit types are treated as 8-bit values.  I can't help but think that this sort of situation begs for throwing a warning at compile time, but alas it did not.  Anyway, adding an explicit typecast to a 16-bit type prompted the compiler into generating working code.

Optimism

As I was rooting around in the code generated by the compiler, I noted some oddities.  The code was doing some weird things, like a register store to memory followed immediately by a load from that same memory location to the exact same register.  This sub-optimal behavior reminded me that I was not telling the compiler to run the optimizer.  So, I added the "-o" option to the invocation of cc09 and observed many improvements to the generated code.

When running the test code built without optimization, I observed that the program didn't run significantly faster than the BASIC program upon which it was based.  I originally surmised that the slow speed was the result of including a keyboard scan inside the "blinking" loop.  However, the optimized code was easily observed to run much faster than the non-optimized code!  Maybe compiled languages really are faster... ;-)

Handiwork

The expression in question included a combination of multiplication and division by powers of two, which I recognized could be implemented with logical operations like masking and shifting.  I observed that even with optimization enabled, the generated code was still using multiply and divide operations to compute that expression.  A more modern compiler might be expected to recognize this situation and to use the logical operations instead, but the "peephole" optimizer included with Micro-C doesn't make the connection.

In order to squeeze out a little more performance, I re-implemented the expression using logical operations in the C code itself.  This generated the code as expected, and a modest performance gain was observed with the test program.  Sometimes you just have to take matters into your own hands!

I'll make a study of the generated code available for those interested in such things.  Next time I'll probably move onto implementing some solutions for better integration with BASIC...or maybe I'll do something else...  Anyway, I guess you'll have to stay tuned to find out!

Saturday, July 13, 2013

Set, Reset, Point

Another week passes with limited progress on my Retrochallenge project.  My day job has been keeping me busy lately.  So, I've been working for the weekend! :-)

BASIC Functionality

I wasn't sure where to start on designing an API for the CoCo.  So for now, I've decided to punt by simply mimicking the commands provided by the CoCo's built-in BASIC programming environment.  I won't attempt to transform C into BASIC with implementations of MID$ and the like.  But, I will try to implement some of the machine-specific commands for graphics, sound, and the like.

With that said, I have begun by implementing the simplest suite of graphics commands.  On the CoCo, this is provided by the set, reset, and point operations for turning pixels on and off and querying a pixel's status on the "semi-graphics" (i.e. VDG mode SG4) screen.  Since that mode allows for mixed text and graphics, I also included routines for clearing the screen and for positioning the text cursor.

Parsing Anomaly?

A funny thing happened on the way to the forum...  While implementing the code to calculate the addresses used in the graphics routines, I discovered that the calculation was producing incorrect results.  To debug that situation, I deconstructed a complex statement into multiple simpler statements.  To my surprise, the calculation then produced the correct results!

I still don't see what difference exists between those implementations that could explain why one performs correctly and the other does not.  Sometimes compilers (particularly "small" ones) have some idiosyncrasies, and the Dunfield compiler is no exception.  I'll have to dig back through the documentation to see if I am hitting one of those cases.  On the other hand, I may simply have done something wrong.  I would welcome anyone who is interested to look at the code in _getpos and to let me know if they see the difference.


Slow Ride

The program running in the video is a C implementation of a program from page 128 of Getting Started with Extended Color BASIC.  As I commented in the video, the C program doesn't seem to run any faster than the original BASIC program.  The difference is that the C program checks for keyboard input after each "blink", while the BASIC program just loops with a GOTO and has to be stopped by pressing BREAK.  If you remove the keyboard check in the C program, the blink is more like a fast flicker.

I would guess that the same keyboard scan routine is called in either case, with that fact hidden in the case of the BASIC program.  The keyboard scan in the ROM does a lot of work, and that work takes time.  Hopefully the speed penalty demonstrated with the C program calling the ROM routine illustrates that simply coding a program in a compiled language is insufficient to guarantee improved performance.

I had a lot of fun working on this today.  Hopefully I can get some chores done and find more time to work on this tomorrow!  If you want to see what comes of that, then I guess you'll have to stay tuned...

Sunday, July 7, 2013

Small Steps

Well, I'm still trudging along on retargeting Micro-C for the CoCo.  As with any project, the fundamentals must come first!

The docs from the Micro-C package covered how to run the tools, what they do, etc.  The key to targeting a specific system is to port the included library, lib09, to the target system.  This is described in the readme.txt file under the lib09 directory.

Location, Location, Location

First and foremost, the decision must be made as to where the code will live in the CoCo's memory.  This location might be anywhere, but realistically it needs to be somewhere in RAM.   Ideally the code will also be located somewhere that won't interfere with Color BASIC, or at least somewhere that allows Color BASIC to load our programs.

There are a number of considerations that might influence this choice.  These include how one intends to load programs, what limits one might impose on the size of programs, what level of cooperation one might want to have between C and BASIC programs, etc.  For now, I'm going to shoot for loading under Disk Extended Color BASIC (i.e. DECB) and I'm not going to worry about cooperation between C and BASIC at runtime.  Being familiar with how DECB uses memory on the CoCo, I have chosen to load C programs at address $0E00 and to set the initial stack pointer to $8000 at program entry.  At program exit, the CPU reset vector at [$FFFE] will be executed.

Console I/O

The lib09 file called serio.asm implements the basic operations for reading and writing text, one character at a time.  The default implementation targets a 6551 ACIA, commonly used for RS-232 implementations on 6809-based machines of a certain era.  In fact, that would work great if we only wanted to use the Tandy Deluxe RS-232 Pak.  But, I think it would be better to write to the video screen and to read from the keyboard... :-)

Fortunately, Microsoft included ROM routines in Color BASIC for just this purpose.  The CHROUT routine handles screen output, including basic scrolling.  The POLCAT routine handles scanning the keyboard.  I implemented routines in serio.asm that used CHROUT and POLCAT in place of the example 6551-based routines.

File Format

The S-record file output by the Micro-C tools isn't directly usable by the CoCo.  The hex values need to be translated to the equivalent binary values, and both header and footer data need to be added to tell DECB where to load the program and how to execute it.  A little cleverness with ORG, FCB, and FDB statements in the lib09 prefix and suffix files tricks the Micro-C tools into generating the header and footer data required by DECB.  Translating the file into binary requires another utility.

Older versions of the Dunfield tools included a utility called hexfmt that could translate between S-record files and pure binary files (among other things).  I can't seem to find this file for download on the Dunfield site right now, but I might be overlooking it.  (It seems to be included in the Z80 cross assembler package here.)  On Linux the objcopy utility can also do such conversions.


Achievement Unlocked

With the fundamentals covered, I am now free to move onto library enhancements, better cooperation with Color BASIC, etc.  I also plan to go into a bit more detail on the wonders of MON09.  Of course, to see that you will have to stay tuned... :-)

Friday, July 5, 2013

Slow Start

The 2013 Summer Retrochallenge started days ago, but I haven't done much so far -- I did take some time to read the various docs that came with the Micro-C package, but beyond that I've been caught somewhere between laziness and real life demands.

I hope to get a bit more done this weekend.  In the meantime, I figured I could take a few moments to describe a little bit about my development environment for this project...

Penalty Box

For me, the biggest drawback with using the Micro-C tools is the fact that they run under DOS.  I was a DOS refugee long before Bill Gates said goodbye to DOS, having been an OS/2 user in the early- and mid-90's.  Alas, there is little to be done about that other than to adapt.  Fortunately, the world of free software has provided an acceptable option in the form of DOSbox!

DOSbox emulates an x86 PC running DOS.  This tool was originally created to enable playing DOS-era games on more modern systems, and that remains the focus of its development.  Fortunately, making games work generally requires the same things as making apps work.  The Micro-C tools work just fine under DOSbox.

Hear Me Roar

A compiler that runs on one system but produces code for another is called a "cross compiler".  This sort of tool provides many advantages, including faster compilation times and easier integration with other (e.g. modern) tools.  One problem with cross compiling is that the resulting code needs to be loaded onto the target system before it can be run and tested.  An emulator for the target system can make this task a lot more convenient.

One of the best CoCo emulators is called Xroar.  Xroar was actually written to emulate the Dragon, but the two systems are so similar that adding CoCo support must have seemed an obvious addition.  In any event, Xroar works and provides stable and accurate emulation of the CoCo.  It also provides options for quickly loading code -- perfect for a rapid development cadence!

Hall Monitor

Sometimes there is just no substitute for running on real hardware.  Loading code on a stock system can be slow and awkward.  Doing that might include audio playback through the cassette port, or even managing physical diskettes.  File transfers over the serial port are another option.

Using the serial port requires software running on the CoCo.  A good option for that is a machine code monitor.  Fortunately the Micro-C package includes such a monitor, called MON09.  Along with the ability to load code and modify memory, MON09 is capable of examining and modifying registers, setting breakpoints, etc.  It is a great development tool for working with the CoCo.  I'll describe my modifications to MON09 for the CoCo in a later post.

Well, that is enough for now.  I should have a bit more available soon.  Until then...stay tuned!

Sunday, June 30, 2013

A New Hope

It's that time again -- the 2013 Retrochallenge Summer event!  Over the past couple of years I've really enjoyed participating in these events.  The regular schedule brings a sort of discipline that reminds me that I need a little "retro" time.  So, here I go again... :-)

Project Options

As usual, I had to ponder a bit to decide on a project for this event.  I never have any shortage of possibilities, and I have at least one notebook where I've jotted down various project ideas in case I should ever be short for one.  This year I was drawn towards working on a CoCo-driven laser projection project, but I also considered a game for a vintage console (e.g. the Intellivision), attempting to adapt Boisy Pitre's Liber809 project to an Atari 5200, expanding my VDG tricks blog or adding enhancements to Fahrfall.  Those all would be good projects (and may still be).  But this time, something else appealed to me.

Stay On Target

Years ago I became aware of Micro-C and related tools from Dunfield Development Systems.  These tools target a variety of older and/or embedded processors, including the 6809 used in the CoCo.  They are provided in a form that is relatively easy to re-target to specific systems as needed.  In fact, I did a simplistic port of these tools to the CoCo several years ago for a simple project.

The Micro-C tools are now available for free (as in "beer") download.  That puts them within reach of a broader range of potential CoCo developers, but as-is they aren't particularly helpful for targeting the CoCo.  Even my simplistic port isn't too good for that, since it didn't have any CoCo-specific hardware support, etc.

Wrap It Up

So, that's the project -- target the Micro-C tools to the CoCo.  This should cover properly locating code, generating correct executable files, and at least basic console I/O.  I expect to also include at least some primitive support for configuring graphics modes, playing sounds, reading the joysticks, etc.  I doubt if I will get to supporting disk drives this month, but that can wait for later.

The contest starts tomorrow, so that's all for now.  If any of the above sounds interesting to you, then be sure to stay tuned!

Wednesday, January 30, 2013

RC 2013 WW Wrap-Up

The month is drawing to a close, and this will probably be my last post before the end of the Retrochallenge 2013 Winter Warmup event.  So, let me give a quick update on the latest developments.  I'll also tell you where to get my Simon clone, in case you want to try it for yourself...

Draggin' The Line

I recognize that a software project which requires hardware that only I have is a bit like masturbation.  Don't worry!  I took pity on you and implemented keyboard support in my Simon clone.  I hacked a keyboard handling routine onto the end of my game loop.  Within that code I map the W, E, S, and D keys to the four colors of the game.  Any key can be used to start the game.

In case you are wondering, that key map was not my first choice.  I'm right-handed, and I originally thought to use the U, I, J, and K keys.  The CoCo uses a typical matrix circuit for it's keyboard, and it turns-out that the U, I, and J keys are all on the same row of the matrix.  That would be fine, but it happens that the CoCo also uses two of the keyboard matrix row inputs for reading the joystick buttons.  Of course, the line for the left joystick button is the same as the line for the U, I, and J keys.  Pressing the joystick button tended to be interpreted as pushing one of the keys on the keyboard!  Not good.

I suppose I could have just switched to the right joystick port, but the left joystick port seems to be the traditional favorite for player one (or a single player).  I also tried to avoid the problem by checking the joystick button immediately before checking the keyboard, and skipping the keyboard check if the joystick button was pressed.  That helped a little, but fate still found a way for the joystick button to interfere with the keyboard.  Fortunately, it wasn't too hard to find another grouping of keys that did not interfere with the joystick.

Enter The Dragon

The Dragon is extremely similar to the CoCo -- so similar that most software written for one will work on the other with few if any changes at all.  One sticking point is that the keyboard matrices are different.  The difference is minor, amounting to a mere shifting of rows of keys.  But, it is certainly enough to scramble the mapping between keys and their functions.

A variety of solutions to this situation are possible.  These include avoiding the keyboard completely, producing slightly different binaries for both the CoCo and the Dragon, or doing some sort of runtime probe to make a guess about which machine is running the software.  The approach I took is to simply enable both sets of keyboard inputs.  The W, E, S, and D keys should work on both the Dragon and the CoCo, while each will have four other keys that will also operate the game.  It will be a little weird if you happen to hit one of the other active keys, but I don't think that will be a big hindrance to enjoying the game.  Oh, and those keys don't interfere with the joystick buttons on the Dragon either!

Ship It!

Software is like art:  it is never finished, just abandoned.  Simon is reasonably well defined, but I'm sure that I could continue to tinker with this implementation indefinitely.  One of the great things about the Retrochallenge events is that they have a deadline.  In honor of that, I am releasing Follow Me, my clone of Simon for the Tandy Color Computer.

The git tree is available now.  In addition, I have made some files available for download:

Follow Me LOADM'able binary: followme.bin
Follow Me CLOADM'able audio file: followme.wav
License information for the above: COPYING
Text file describing the above: README

New Horizons

So, what next?  Well, there is The CoCo Coding Contest, which is already in progress.  I plan to expand upon my work from last summer's Retrochallenge event, using my 44-color CoCo graphics mode to make a sliding puzzle game.  Winners will be announced at this year's Chicago-area CoCoFEST! I hope everyone can make it there this year! :-)

I recently realized that the Tandy 1000 used the same joysticks as the CoCo.  Also, the Tandy 1000 has some interesting sound and video hardware that is a bit different from other PCs from that era.  Maybe it would be fun to implement something to use my rotary controller on a Tandy 1000?  Well, I guess we'll see...

Sunday, January 27, 2013

Game On!

The end of the Retrochallenge event draws ever nigh.  Fortunately, it looks like I will not be empty handed when the competition closes!

Feature Complete

I have now implemented all of the basic features of Simon.  I can generate random tone sequences, play them for the user, monitor the user's control inputs, and evaluate those inputs against the generated sequence.  I have added a timeout when monitoring the inputs.  A slow or inactive user loses the game, as does one that fails to match the tone sequence.  Losing the game results in a restart, while matching a maximum length sequence (31 tones) earns the player a congratulatory tone and a "you win" screen.  FWIW, I also think that the game is fun to play -- just like the original Simon. :-)


New Location

I am using the same development environment that I used when developing Fahrfall.  That environment is very flexible and allows me to load code or data anywhere in the CoCo's memory, without regard for compatibility with the CoCo's built-in BASIC environment.  Also, I have been arbitrarily loading code into an address above 16K -- higher than what many CoCo machines have.

I relocated the binary to location $0e00.  This location is relatively low in a CoCo's memory, but it is high enough to avoid interfering with the CoCo's disk accesses.  This should allow the game binary to load on either tape-based or disk-based CoCo systems.  It definitely works for loading from tape (i.e. MP3 playback on my phone).  I expect that it will work when loading from disk (or DriveWire) as well, but I haven't verified that just yet.

Unfortunately, the combination of that address and the length of the game binary is too high for CoCo machines with only 4K RAM.  If that turns-out to be a limitation, then a "cassette only" version can easily be generated... ;-)

More Options

A few more options remain for development.  An obvious one is to implement a keyboard interface so that people without the rotary controller (including emulator users) can play too.  Support for the Dragon should be a no-op as-is, but the addition of keyboard support will require extra code to support both CoCo and Dragon keyboards.  Also the current "you win" screen is a lame reward for someone that completes a 31 tone sequence -- perhaps something better could be done?

Further options could be modifications to the game itself.  The original Simon had a couple of multi-player options available, as well as options for playback of the previous and longest completed sequences since starting the game.  The AVRSimon project included other game options, including versions with no sound or no lights and a version where the tone matching was done in reverse order.  Any or all of these might be possibilities for future development.

For now, I think that I will focus on mopping-up things for the Retrochallenge event.  This will likely include the release of a git tree and some sort of wrap-up post in the next few days.  For that, of course, you will have to stay tuned...

Saturday, January 26, 2013

Still Moving

Another day, another opportunity for hacking!  Actually, we had a little ice event here on Friday, so this particular Saturday was a great day to stay inside for some retro-hacking.  Luckily, we had already stocked-up on bread and milk... :-)

Random Numbers

Simon is built around a randomly generated sequence of tones/colors that the player has to match to keep playing.  However, the truth is that computers aren't really imaginative enough to generate truly random numbers.  To compensate for that, there are a variety of common tricks that are used to generate seemingly random numbers through mathematical processes.  The technique I used for generating random numbers in Fahrfall  was a software implementation of an LFSR.

Perhaps surprisingly, Simon did something even simpler.  Simon used a free running counter which was incremented every time the game entered its main loop.  When it was time to extend the tone/color sequence, Simon simply used the two lowest-order bits of that counter in order to pick one of the four tone/color pairs (numbered 0-3).  The inherent inconsistency of human timing makes it impossible to predict which number is in the machine's counter when these choices are made, resulting in something random enough to be useful for the game.  This technique has worked well enough for Simon so far, so this is the technique I used in my implementation as well.

Getting Started

One thing I added to my code was a "start" screen.  This gives the user more control over exactly when a game starts, and offers an opportunity for displaying copyright notices or perhaps some basic instructions.  In this case, however, it provides another added benefit -- it gives the free running counter a chance to run for a while before the game starts.  Without this chance for the counter to run, the game would always start with the same tone/color pair every time.

Follow The Leader

With all that said, the point of the random numbers is to generate a sequence of tone/color pairs.  But having that sequence isn't worth much if you can't play it back for the game!  I already had some code to play tones as the player selected each color.  On top of that, I implemented some code to track the length of a sequence and to walk each member of it.  For each member of the sequence, the corresponding tone is played and its color is highlighted.  The tone playback is timed, and a short delay is inserted between each tone.


With that in place, I can move onto playing a generated sequence and adding the rest of the game logic.  I expect to get that done over the next day or so.  As always, stay tuned... :-)

Wednesday, January 23, 2013

Play It Again

The gears of progress creak forward once again!  There is nothing very monumental to report, but at least now my CoCo sings when you work the controls...

Hip To Be Square

The CoCo actually has two potential sources of audio output.  The higher quality output comes from the 6-bit DAC, which is capable of reproducing reasonably complex waveforms with the help of the CPU feeding it wave samples.  This isn't terribly difficult to use, but it isn't terribly simple either.  Plus, sharing the DAC for reading the controller further complicates its usage.

The other audio output on the CoCo is a 1-bit digital output used for generating square waves.  This sort of output is very simple to use, and was quite common in devices of the same era as the CoCo.  The tonal quality produced by this output isn't particularly pure or melodic, but it does have a certain richness to it.  Plus, it happens to be the same technique used by the original Simon hardware.

Time Critical

Audio tones vary according to their frequency.  The key to generating different frequencies is timing.  The square wave output of the CoCo needs to be switched at intervals that are timed reasonably precisely in order to generate consistently accurate tones.  But how?

Without external hardware, I can only think of three ways to do accurate timing on a CoCo:  cycle counting; vertical sync; and horizontal sync.  Instruction cycle counting is reliable, but it is difficult to apply to dynamic changes (e.g. playing different tones).  Vertical sync occurs 60 times per second, only enabling generation of tones up to 30 Hz.  That leaves leaves horizontal sync.

Horizontal sync on the CoCo fires 15720 times per second, enabling generation of tones up to 7860 Hz.  While the audiophiles will be horrified at such a low sample rate, the truth is that this covers a very useful range of tones.  Most importantly, it more than covers the range of tones required to play Simon.

Bugle Call

Legend has it that the creator of Simon sought long and hard for a set of tones that would always sound "in tune" no matter the order in which they were played.  The tones played by Simon are said to have been inspired by the notes of a bugle.  That may be so, but mimicking bugle tones doesn't quite match my vintage Simon game.

Luckily, some kind soul has gone through the trouble of reverse engineering the original Simon game and (more importantly) publishing that information for all to see.  With that info I was easily able to tune my implementation to more closely match the original.  That said, the bugle notes do sound a bit better -- I'm not sure which set of tones I will ultimately use!


Time is ticking, and I only have another week to finish-up.  Hopefully I can find some time this weekend to implement the game logic, etc.  To find-out how that goes, you'll have to stay tuned... :-)

Monday, January 21, 2013

Simple Simon

When last we met, I was just coming to peace with my rotary controller routines.  A perfect solution probably would require either more hardware, more CPU time dedicated to sampling, or both.  But, some experimentation with a clever software debounce algorithm and a pragmatic approach to handling illegal state transitions yielded empirical results that seemed acceptable for some sort of game.  But what?

Get The Feel

A rotary (a.k.a. "spinner") control is a little unusual.  It is constrained to a single degree of freedom, and the twisting mechanic is best suited to movement around a central point.  Not just any game will lend itself to this dynamic, and there isn't much point in using a rotary control for a game that would be better suited to a more common control scheme.

I had intended to make some sort of tube shooter game for the CoCo3.  I would still like to do that, but I don't think I can accomplish that during this month's Retrochallenge event.  Consequently, I need something simpler to implement!

Simple Simon

I started thinking about simple games and round shapes.  Before long, the answer became obvious -- Simon, an 80's classic.  The game logic and basic mechanics (e.g. playing sounds) should be simple enough to implement in the allotted time.  The rotary control might not seem like an obvious choice, but I think it will map well to Simon's four centrally arranged buttons.


Mock-Up

To get started, I knocked-up some code to draw four colored boxes on the screen.  I refactored my controller code to buffer the movement indications a bit, so that turning the spinner resulted in controllable selections.  I am using a white outline to indicate the currently selected color.  Pressing the button changes the outline to match the color of the selected box, making a larger colored box.  The larger colored boxes will also be used when the patterns are being played for memorization.

I think that covers the basic mechanics, other than playing the tones.  That should be relatively simple -- YMMV, of course!  I guess we'll find-out about that soon enough.  Until then, stay tuned... :-)

Sunday, January 13, 2013

Debouncing Distractions

It's been a while since I last posted, so I guess it is time for an update...  I got a bit obsessed with debouncing the outputs from my controller, but never quite got it perfect.  I eventually had to declare it a rathole and move onto something else.  Nevertheless, I think I've made a little progress.

Debouncing

As I've noted, the rotary encoder I'm using (like all mechanical switches) is prone to "bounce" a bit as it changes state.  This is a common problem, and there are tons of options for addressing it.  I ruled-out using extra hardware, mostly to avoid the trouble of building the circuit into the controller.  This leaves a variety of software options.

I started with a simple algorithm which read the controller status periodically.  The algorithm insisted on three identical reads in a row before updating the "official" state of the controller.  This worked reasonably well, and I used it to play around a bit with how often I read the controller and how many identical reads were required to update the state.  Still, I was never quite satisfied with it.

I did some more research, and came across The Best Switch Debounce Routine Ever.  I don't know if it really lives-up to it's name or not, but it was relatively simple to code in 6809 assembly language and it seems to work somewhat better than what I was doing before.  That might be attributable to the fact that it also debounces the two inputs from the encoder independently (but simultaneously!), whereas my routine had considered them as a single 2-bit value.  In any case, the new algorithm delivers reasonably stable results at what seems like a reasonable computational cost.

The problem is not completely solved, however, because I do still get some observable bounce and even some invalid state transitions.  After reading Jack Ganssle's A Guide to Debouncing, I've concluded that the relatively slow clock speed of the CoCo's CPU and the demands of reading the rotary controller fast enough for playing a game means that I will not be able to filter-out all bounces.  So, all I can hope for is that the effects of these anomalies will be minor enough to be reasonably ignored.

Another Demo

To determine whether or not ignoring controller anomalies is acceptable, I needed a demo that acted a bit more like a real game.  I changed my demo code to use the data from the controller to move a cursor around the screen.  This gave me a better "feel" for how something on the screen would react to a player's controller movements.  After playing with that a bit, I am reasonably confident that enjoyable games can be made to use this controller.  Now, someone just needs to write them! :-)


Ready Player One

I almost didn't get around to working on CoCo stuff this weekend, as I became immersed in a novel that I've started reading.  Ready Player One is a really enjoyable sci-fi novel set in a dystopic future where humanity escapes the realities of a used-up world by living-out fantasies in a computer-generated virtual universe.  The protagonist is involved in a contest within that virtual universe that requires those involved in it to be masters of 80's pop culture and trivia, with a definite slant towards sci-fi, RPGs, classic arcade games, and other things geeks love.  As if this wasn't catnip enough for an old geek like me, the fictional creator of the virtual universe got his start on a CoCo2.  Moreover, one of the key points of the plot involves playing Dungeons of Daggorath on a CoCo2 inside that virtual universe!  I can hardly put it down...

Anyway, I'll be travelling some this week.  So, I probably won't be updating the blog any more frequently this week than the last.  Oh, well...I'm sure you will all live through it!  But, I do hope that I can knock-up something interesting to post here by next weekend or so.  Until then, stay tuned...

Monday, January 7, 2013

Rotary Visuals

I spent a little time on Sunday trying to get some code written that is more specific to the rotary controller.  I started with some existing code snippets for reading the CoCo's joystick inputs, and some basic video mode setup as well as other initializations.  It seems like that should have been simple, but I hit a bit of a snag...

That Ain't Right

I implemented a simple program to read the rotary controller by polling the joystick port in a tight loop.  I implemented the program for the CoCo3, and used a CoCo3-specific video mode.  After clearing the screen, I used the inputs from the controller to form a bitmask which I then used to change the color for palette entry 0.  This was intended to provide some basic feedback as a first step before going forward.

Unfortunately, I quickly noticed that I was only seeing three colors when I turned the knob on the controller.  I tweaked the code a bit, only to find that in some cases I was down to only two colors in the sequence.  After re-verifying that the controller hardware still worked with the earlier demo (on a CoCo1), I even tried a different CoCo3.  Still, the issue remained.  In an effort to verify the software itself, I transformed the program into something that would run on any CoCo.  Then I could test the program on all the same hardware that ran the other demo.

Back To Basics

I changed to using a text mode for the output.  Instead of changing a color, I used the bitmask derived from the controller inputs to generate a number character on the screen.  This allowed me to better understand the exact sequence of values being detected by the software.

At this point, I just fiddled with the controller and watched the numbers change.  After a while, I switched from the rotary controller to the standard joystick instead.  Eventually I was able to understand what I was seeing -- the second axis almost always read the same as the first axis, with some exceptions depending on a few tweaks here and there.

Wait For It

The CoCo reads the joysticks using a DAC and a comparator.  One of the comparator inputs is selected using a linear switch controlled by one of the CoCo's PIAs.  In order to read two axes, the switch has to be changed to select the second axis.  In my existing code, switching the axis is followed by setting a new DAC value before checking the comparator.

The rotary controller outputs are digital, so only one comparator check is needed per access.  Also, the same DAC value is used for the comparisons on both axes.  Consequently, I was checking the comparator immediately after switching to the second axis.  This seems to work fine on the CoCo1, but on the CoCo3 it is prone to failure.  Inserting a few NOP instructions seems to stabilize that situation.  A dummy set of the DAC value would probably give enough time for the comparator to stabilize as well.


With that issue resolved, I extended my test program to use color and more screen real estate.  This makes it easier to visualize and track the states as they are read from the rotary controller.  It also confirms that switch bounce is a problem, as demonstrated in the video clip above.  Figuring-out how to deal with that will probably be my next step -- stay tuned!

Saturday, January 5, 2013

Smoke Test

Well, it seems I've been a bit lazy so far.  With the new year came the end of my Christmas vacation, and so I had to pay a bit more attention to work, etc.  I'm sure I'm not the only one!

Despite the lack of real progress, I thought that it might be worthwhile to demonstrate the workings of the rotary controller.  So, I posted a video of me stepping the controller through its paces using the joystick demo code I originally wrote while developing Fahrfall.


CoCo Joysticks

I'm using the joystick port on the CoCo to read the rotary controller.  That seems obvious enough, but the output from the rotary encoder is digital and the CoCo joystick inputs are analog.  I resolved that discrepancy using pull-up resistors, forcing the joystick inputs to always read either high or low (and not in between).  Given that understanding, the basic process for reading those inputs is the same as I described in the Fahrfall blog.  In this case we should be able to do only one value check per axis, since there won't be any "in between" readings.

Debounce

The rotary encoder I am using is mechanical.  Like all mechanical switches, there will tend to be some "bounce" when the contacts close.  It is possible to do switch debouncing with hardware, but it complicates the electrical design and construction.  Consequently, I didn't add any such hardware.

I'm not sure if debounce is usually an issue with game controllers or not.  In most cases, false readings probably just work themselves out with the next read.  But with the quadrature signal coming from the rotary controller, the sequence of values becomes important.  This is especially true if we were to miss a transitional state.

I found several references to people having switch bounce problems when using rotary controllers with Arduino projects.  I don't know if any of the techniques they use to fight switch bounce will be helpful on the CoCo or not, but I suspect that I may have to do something to account for switch bounce in software.

Keeping Up

A related problem with the rotary encoder will be the sampling rate.  The encoder I am using is rated for 24 pulses per revolution.  That number represents the number of full cycles per channel in a given revolution.  But since the signals are bound together using quadrature encoding, the real number of transitions to consider is 4x that, or 96 transitions per revolution.

The most common rate for sampling joysticks in an arcade game is around 60Hz.  It seems reasonable to suspect that someone could turn the controller knob more than 2/3 of a revolution during a second!  So, the sampling will have to happen more frequently.  If a game plays sound, there will need to be a routine running at a rate of several kHz in order to feed the DAC for audio output.  Maybe piggy-backing on that routine to read the controller input will be good enough to keep pace?  It might even fix the debounce issue for free?

Well, I guess we aren't going to find-out today...  I'll try to knuckle down on this and report back in a day or two.  Until then, stay tuned! :-)

Tuesday, January 1, 2013

CoCo Rotary Controller

In the early days of video games, there was a lot of variety in game controllers.  While plenty of games just used a joystick and a button or two, a number of games in the arcades had more interesting control mechanisms.  The Lunar Lander thrust controller, the Centipede trackball, the Battlezone dual control sticks, and the Star Wars flight yoke all come to mind as examples of how the controller itself can be a part of the overall gaming experience.  But for my money, few controllers matched their games as well as the rotary controller did for Tempest.


Inspiration

Tempest was a great game -- so much so, that Atari had it remade as Tempest 2000 and released for the Jaguar back in the early 90's.  Tempest 2000 works perfectly well with the D-pad, but it turns-out that Jeff Minter also added support to Tempest 2000 for rotary controllers.  The problem, of course, is that Atari never made such a controller...

I knew about the rotary controller support in Tempest 2000 when I bought it off the shelf 'back in the day'.  I had always intended to build such a controller, but only recently got around to doing that -- more on that in some later post!  Anyway, as part of that journey I ended-up with a few random extra parts.  In particular, I had an extra rotary encoder.

Making Something Beautiful

From an electrical standpoint, joysticks and most other controllers are fairly simple.  The real problem isn't wiring them, it is building something to hold those buttons, sticks, or whatever in a form that makes them usable.  Often the simplest solution is to repurpose something designed to do a similar job into something that works more as one wishes.


The original TRS-80 joysticks that Tandy offered for use with the CoCo were awkward and are generally unloved.  The best I can say about them is that they seem a bit less poorly designed than the ones made for the Dragon or the BBC Micro. :-)  Nevertheless, they do offer a plastic shell with some rudimentary ergonomics, an available button, accommodations for wiring, and a pre-drilled hole ready for mounting the shaft of a rotary encoder.

At some point, an idea became obvious -- take the guts out of an old CoCo joystick and turn it into a rotary controller!

Getting It To Work

The procedure was relatively simple.  First, disconnect the wires from the joystick gimbal and remove it from the housing.  Next, mount the rotary encoder in the now vacant hole in the housing.  Once the wiring is complete (see below), then install a knob that suits your tastes.  That completes the mechanical installation!




For the wiring, solder a 10k resistor to each of the signal outputs from the encoder.  Tie the other ends of those resistors to the +5V line from the CoCo.  The common input on the encoder gets tied to Ground from the CoCo, as does one of the button terminals.  The other button terminal connects to the button line from the CoCo, as expected.  The X and Y lines from the CoCo are each tied directly to one of the signal outputs from the encoder.  The connections are made so that in operation the X and Y lines alternate between +5V and Ground.  Turning the encoder clockwise will cause (X,Y) to follow the sequence of (0,0) -> (0,5) -> (5,5) -> (5,0).  Likewise, turning counter-clockwise will change the sequence to (0,0) -> (5,0) -> (5,5) -> (0,5).


Hopefully that description is clear?  The circuit really is simple.  I'll try to find some time to draw-up a little schematic to post.  If I don't manage to do so and you want to build one, feel free to contact me if you can't figure-out the schematic. :-)



In any case, building the hardware is only the first step.  This controller works a bit differently than the existing joysticks.  Consequently, there is no software to make any sense of it.  So, starting to figure that out will be the next step.  As always, be sure to stay tuned!