Try out the completed N-Queens project discussed in this post
You may have noticed from my last few posts that I’ve been adding support for the C programming language to my db65xx debugging extension for VS Code. When I first started with cc65, the added complexities needed to program in C kept me firmly in the assembly language only camp. After a while, 65xx assembly coding became so natural, that I didn’t see a point using a less efficient, higher-level language.
About a year ago though, when I was first looked into implementing floating point for my Forth operating system, I thought about C again. I figured that its float data type would be perfect for creating some stubs to simplify adding the functionality to my system. I imagined that sure, it would be slow, but I’d have floating point. I was pretty disappointed when I learned cc65 didn’t support floating point. Wow! That seemed like a pretty basic requirement for a C compiler.
With that I didn’t consider the cc65 C compiler again until recently. I thought adding the capability to db65xx would be a great way to introduce myself to it. It’s interesting to note that my initial impression about the complexities of using the C compiler were true. Expect to take some time getting up to speed, unless you are programming for one of the supported operating systems. Actually, I’m kind of surprised that with all of the interest in 65xx single-board computers that there isn’t a canned cc65 system for one. I suppose the compiler is considered over kill for the typical hobbyist build. It’s probably better for newcomers to get their feet wet with assembly language first anyway.
After the initial learning curve, C programming with cc65 has been straightforward. I’ve only had to update my C library to accommodate any new standard functions I introduce into my program. The other day I decided to add input capability to my library. I started with the fgets function, reading from the STDIN stream. I’d seen the function used for simple input in a few other programs. It seemed perfect for adding input to the N-queens example project I was working on (the n-queens problem considers the various ways of placing n chess queens on an n×n chessboard so that no two queens threaten each other). The Rosetta code example I was using got the number of queens to use from a command-line parameter. I wanted to expand that to have the program ask the user how many queens to consider.
I had to write the needed system specific cgetc and read routines for my typcial build. I found the cc65 Atmos library code to be the most helpful in customizing system specific functions for my 65xx builds. No doubt this is because the Oric Atmos, which the library supports, is a fairly basic 6502 machine, not much more advanced in many ways than some of the builds I’ve done.
Initially, running the resulting program in db65xx resulted in an error message “n must be between 2 and 31!”. It didn’t matter what value I entered. Well, I was using a debugger. What did it tell me? Looking deeper, the buffer that I was using to record the user’s input always had a hexadecimal value of 0xd. From experience, I knew this was the ascii value of the carriage return control character, ‘\r’. It’s the value returned by the VS Code integrated terminal when the Enter key is pressed. For some reason I was only capturing the enter keypress.
A little sleuthing showed that my initial keypress was getting eaten by my kbhit routine. This routine returns a non-zero value if a keypress is available, otherwise it returns zero. It isn’t supposed to affect the availability of the keystroke. I had simply modeled this by checking if the system input address was non-zero and returning the appropriate value. I forgot that by reading the system input address, I pulled any awaiting input value from an internal buffer, advancing the buffer to the next input character. Clearly, I had some work to do in that regard, but for now I decided to just comment it out. It wasn’t really needed anyway as the fgets function handles the waiting for input.
Now you might think that this was the ‘Carriage Return` from my post title, but it wasn’t. I suppose I could have titled the post “Tripped Up by Carraige Returns”. But what happened next was more interesting and difficult to track down. After commenting out the kbhit call, the program never got out of the input loop, though this wasn’t clear at the time. To track it down, I had to add debug information to my library (interesting to note that this was possible!). With that, I could step through all of the code to see where the program was hanging. Turns out the cc65 standard fgets function was forever looping because I wasn’t sending it the C standard end of line character for streams, ‘\n’, the newline character, ascii ‘0xa’.
Note that the fgets local variables are shown but are not correct. This is because library functions use the fastcall calling convention which passes the last parameter to the function in registers and the function itself pushes it to the C stack on entry, changing the stack pointer which db65xx noted on function entry. It wouldn’t be worth the effort to change the library to the cdecl calling convention that dd65xx requires but I suppose I could change it for a single function if there was some uncertainty that parameters were being passed correctly. That wasn’t the case here though.
Now I’ve dealt with the CRLF line ending issue several times in moving between by hardware builds and simulators. In standard Forth, the method of indicating the end of an input line of text is implementation defined. I’ve designed my operating system around the carriage return since it’s the value assigned to the Enter key. Sometimes this is sufficient to advance the output to the beginning of a new line, which is what I want. Sometimes it isn’t. If not, I simply add an extra line feed to the code for that particular system and call it a day.
Unfortunately, this doesn’t make sense for this case. Sure, I could modify the cc65 code for the standard fgets function to use a carriage return rather than a new line character as an end of line indicator. With that though, I run the risk of breaking some other piece of standard code and have the hassle of maintaining a different version of the cc65 library code. I’ve already tried and given up on maintaining my own version of cc65, so I’m not going to start for this issue.
I like the idea of being able to write C function for use in my operating system, especially for I/O where speed isn’t usually critical, and C offers the possibility of doing more with less code. It’s also one area of assembly language programming I find tedious. If I decide to go that route, I’ll just need to modify my system to accommodate it.
For now, though, it looks like I need to consider how to change db65xx to handle both cases. It’s main purpose for me after all is debugging my Forth operating system. We’ll see. It might just be easier to change the appropriate instances of $0d in my system to $0a. It looks like there are less than two dozen of them. I don’t use escape characters in my assembly code. They are available with the .feature string_escapes control command, but I don’t use it to maintain keep my code as compiler independent as possible.
After a bit more thinking, I decided to just change the system specific read routine to convert instances of $0d in the input stream to the $0a value expected by C. I’m not sure why I thought changing everything else to accommodate C was the way to go.
The needed modifications to the read routine were more extensive than I thought. I needed to accommodate the backspace, $08, as well since the db65xx terminal passes this along in the input stream. As such I need to write a GETLINE routine to get a line of input from STDIN when the input buffer was empty. With that the read routine was very similar to the Atmos library routine. With that, the n-queens program processed input, including backspaces, correctly.
Next up is a version of n-queens with interrupt driven input for use with one of my hardware builds. Then I’m going to try to get it to run on a 65816 which at a minimum will involve switching the 65816 registers to 8-bit. That’s assuming that the C library functions don’t rely on any 65C02 extended instructions. (This last is an interesting point: As I’ve been writing system specific I/O routines, I’ve come to the conclusion that they must use the lowest common instructions, that is those from the 6502, to maintain compatibility with that processor. Thus, instructions like BRA, PHX, PHY, PLX, PLY, and STZ have to be avoided.