64-bit IThumbnailProvider, BBC BASIC matrices and clocks
Friday, 16th October 2009
Work commitments have left me with little time to pursue my own projects of late, hence the lack of updates.
A chap named Jeremy contacted me with problems relating to the IThumbnailProvider code I'd posted here before. We narrowed it down to a 64-bit issue, demonstrated by the fact that the thumbnails appeared in the file open dialog of a 32-bit application, but not in Explorer. Not having a 64-bit version of Windows to tinker with, I was unable to help, but he found the solution was to register the assembly using the 64-bit version of regasm. You can read more about his experiences on his blog.
I had made a mistake in the BBC BASIC (Z80) for TI-83+ documentation, describing the old coordinate system in the graphics documentation rather than the current one (which is more closely aligned to other versions of BBC BASIC). I have uploaded a new version of the documentation to ticalc.org. This build also includes some basic matrix operations via the MAT statement. This statement is rather incomplete, but I've run out of ROM space (not to mention time) to implement it fully. Still, the bits that are there are quite useful, and a half-arsed implementation is better than no implementation... right?

On a whim, I purchased a 32×8 LED display on eBay which I've (very) slowly been turning into a remote-controlled clock. A Sony-compatible remote control is used to type in the time, after which you can cycle through different styles with the channel up/down buttons and change the brightness with the volume and mute buttons. I'm using a 4MHz PIC16F84 to drive the display, with a DS1307 responsible for time-keeping and a 32KB 24LC256 to store the font data and text strings.
As well as dates and times, I thought a thermometer might be a useful addition so I put together an order for a DS18B20. It's silly to just order one thing, so I bulked up the order with one of the snazzy new PICAXE-20X2 chips (yes, they run a BASIC interpreter but the new 64MHz clock speed is certainly impressive). I find PICAXE microcontrollers invaluable for prototyping, being so very easy to use! ![]()
In an attempt to broaden my horizons, I also purchased two AVRs, as I have zero experience with these popular chips. I went for the two ends of the scale as offered by the supplier - an ATmega168 and an ATtiny13. Having lost a battle with PayPal's cart (it kept forgetting old items as I added new ones) I neglected to purchase a D-sub hood so I'll be waiting until I can go and buy one before I start assembling a programmer. I was intending on going for the simple SI Prog, but if anyone has any suggestions for variations I'd be interested in hearing them!
Nibbles and Logo
Thursday, 19th February 2009
Work on BBC BASIC has slowed down quite a bit, with only minor features being added. A *FONT command lets you output large or font sized text to the graphics cursor position regardless of the current MODE:

10 MODE 3 20 VDU 5 30 MOVE 0,255 : PRINT "Small" 40 *FONT LARGE 50 MOVE 0,227 : PRINT "Large" 60 VDU 4 70 PRINT TAB(0,3) "Small (VDU 4)"
Another new command is the dangerous *GBUF that can - when used correctly - let you switch the location of the graphics buffer. You can simulate greyscale by quickly flickering between two different images on the LCD, which is where this command may come in use.

Snake/Nibbles is a fun game and an easy one to write, so here's a simple implementation that features variable speeds and mazes. The game runs quickly on a 6MHz TI-83+, which I'm happy with. And yes, I know I'm terrible at it. ![]()
One thing I've always been pretty bad at is writing language parsers resulting in poor performance and bugs. I've started writing a primitive Logo interpreter in C# to try and improve my skills in this area. So far it supports a handful of the basic language features and statements:
- print [Hello World] Hello World - make "animals [cat dog sheep] show :animals [cat dog sheep] - make "animals lput "goat :animals show :animals [cat dog sheep goat] - print last :animals goat - repeat 2 [ print "A repeat 2 [ print "B ] ] A B B A B B - show fput [1 2 3] [4 5 6] [[1 2 3] 4 5 6] - [10 9 8] Not sure what to do with [10 9 8]
(No, no turtle graphics yet
). There's no support for infix operators yet. The BBC BASIC ROM manual describes the top-down parsing method it uses to evaluate expressions so I'm going to attempt to reimplement that.
One issue I've already run into are the parenthesis rules: for example the sum function outside parentheses only allows two arguments, but inside parentheses works until the closing parenthesis:
- print (sum 4 5) 9 - print (sum 4 5 6) 15 - print sum 4 5 9 - print sum 4 5 6 9 Not sure what to do with 6
I'm not sure whether a "this statement was preceded by an opening parenthesis" flag would be sufficient.
Extending BBC BASIC
Sunday, 1st February 2009
BBC BASIC may have originated with the 8-bit home computer era, but it's still being updated and its most up-to-date incarnation - BBC BASIC for Windows - has a wealth of features that are unavailable on the Z80 version.
The BBC BASIC graphics API is primarily accessed via the multi-purpose PLOT statement. PLOT is followed by three arguments - the type of graphics operation being carried out followed by an X and a Y coordinate. For example, to draw a line between (20,30) and (100,120) you could do this:
PLOT 4,20,30 : REM Move graphics cursor to (20,30) PLOT 5,100,120 : REM Draw a line to (100,120)
This results in needing to remember a lot of different plot codes (there is a logic to how they are formed but I still need to consult a list of codes from time to time). All implementations of BBC BASIC feature two helper statements to aid the user:
- MOVE x,y (equivalent to PLOT 4,x,y)
- DRAW x,y (equivalent to PLOT 5,x,y)
More recent versions, such as BBC BASIC for Windows, also implements the following helper statements, amongst others:
- CIRCLE x,y,r (equivalent to MOVE x,y : PLOT 145,r,0)
- ELLIPSE x,y,w,h (equivalent to MOVE x,y : PLOT 0,w,0 : PLOT 193,0,h)
- FILL x,y (equivalent to PLOT 133,x,y)
- RECTANGLE FILL x,y,w,h (equivalent to MOVE x,y : PLOT 97,w,h)
This is all very well, but the BBC BASIC (Z80) interpreter is a sealed box as far as I am concerned. I can ask it to perform tasks for me ("evaluate this expression") and it can ask me to perform tasks for it ("output this character to the display") but I can't modify its behaviour.
Or, so I thought - until I read through the copy of BASIC ROM User Guide that a friend had rescued and sent to me. It has a section on adding statements, which it achieves by using a clever - but simple - trick.
When BBC BASIC encounters a statement it doesn't recognise it triggers the Mistake error. On the BBC Micro the error handler is vectored, meaning that it loads the address of the error handling routine from RAM first instead of jumping to a fixed address. This allows the user to override the normal error handler, detect the Mistake condition and try and parse the erroneous statement themselves. If they can't handle the statement either control is passed back to BBC BASIC's usual error handler, otherwise the error condition is cleared and execution continues as normal.
BBC BASIC (Z80) follows the same procedure but with one major difference - the error handler routine is not vectored. Unfortunately, the only practical workaround I can think of is to patch the interpreter's error handler routine directly. Richard Russell somehow managed to add support for additional commands to the Z88 version via a patch that runs from RAM, but I haven't been able to work out how he managed to do that yet.
The first series of additional statements I added were the graphics helper statements listed above, WAIT (which pauses execution for a certain number of centi-seconds) and SWAP which exchanges the contents of two variables. These are all relatively simple statements to implement as they do not affect the state of BBC BASIC in any other way; they perform a single, simple task then exit.
One of the more useful additions to more recent versions of BBC BASIC is the WHILE...ENDWHILE loop structure. A limitation of BBC BASIC (Z80)'s statement blocks is that their contents must be executed at least once, hence IF statements must fit on one line, multi-line procedures or functions should be placed at the end of the file after an END statement and REPEAT...UNTIL loops - where the looping conditional is at the end of the block, rather than the start - are provided. If a WHILE condition evaluates to FALSE, control needs to resume at the matching ENDWHILE. This is an interesting technical challenge, as it needs to handle nested WHILE...ENDWHILE stataments when searching through the code to find the terminating ENDWHILE, but appears to work pretty well now.
Another useful recent addition is EXIT (in three variations - EXIT FOR, EXIT REPEAT and EXIT WHILE) which breaks out of a loop structure. This has the same technical challenges as the WHILE...ENDWHILE loop structure (searching for the matching loop terminator) with the additional difficulty of unwinding the stack to the correct position.
By combining WHILE loops and EXIT WHILE you can simulate multi-line IF statement blocks, so
IF <condition> THEN <statements>
becomes
WHILE <condition> <statements> EXIT WHILE:ENDWHILE
These additions are not without their downsides. Most of the statements supported natively by BBC BASIC (Z80) are represented by single-byte tokens, whereas these extensions are stored as ASCII text. This makes them take up more room in the source file and slower to execute (searching for and handling strings is a much more complex operation than searching for bytes). Using them makes your programs incompatible with other versions of BBC BASIC (Z80). I personally feel that these disadvantages are far outweighed by the advantage of easier to read code, however.
To round the entry off, have a fractal. ![]()
BBC BASIC for the TI-83+/TI-84+ beta release
Wednesday, 21st January 2009
Work commitments have prevented me from doing much on my own projects recently, but zipping up a few files to get BBC BASIC tested is not a time-consuming process so I've started to release test builds.
The documentation is available online. It's generated by a little tool I hacked together to turn a MediaWiki database into a CHM file.
I've had a few issues with the TI-84+ hardware, such as LCD corruption, difficulty in getting key presses to register and crashes when USB devices are unplugged. I think I've fixed the LCD and key issues by dropping the CPU speed down to 6MHz when the full 15MHz is not required, but am still stumped by the USB issues. Unfortunately documentation on the USB hardware is rather thin on the ground and I don't own a TI-84+ for testing.
The package comes with a few demo programs from the CP/M release and a few I cobbled together myself. Most recently I've tried putting together a few little graphics demos.
There's still a fair amount of work to go on this project (especially optimising - some of the code is extremely inefficient) but it feels nice to have something out there for people to try. ![]()
Controller input updates to Cogwheel
Monday, 5th January 2009
I hope you all had a good Christmas and New Year period!
I received an Xbox 360 controller for Christmas, so have done a bit of work on Cogwheel to add support for it. (You can download a copy of the latest version 1.0.2.0 with SlimDX here).
The first issue to deal with was the D-pad on the Xbox 360 controller. When treated as a conventional joystick or DirectInput device the D-pad state is returned via the point-of-view (POV) hat. The joystick input source class couldn't raise events generated by the POV hat so support for that had to be added. This now allows other controllers that used the POV hat for slightly bizarre reasons (eg the faceplate buttons on the PlayStation controller when using PPJoy) to work too.
The second issue was the slightly odd way that the Xbox 360's DirectInput driver returns the state of the triggers - as a single axis, with one trigger moving the axis in one direction, the other trigger moving it in the other. You cannot differentiate between both triggers being held and both being released, as both states return 0. To get around this, I've added support for XInput devices, where all buttons and triggers operate independently.
The Xbox 360 controller now shows up twice in the UI - once as an XInput device and again as a conventional joystick. Fortunately, you can check if a device is an XInput device by the presence of IG_ in its device ID. Here's some C# code that can be used to check with a joystick is an XInput device or not.
using System.Globalization; using System.Management; using System.Text.RegularExpressions; namespace CogwheelSlimDX.JoystickInput { /// <summary> /// Provides methods for retrieving the state from a joystick. /// </summary> public class Joystick { /* ... */ /// <summary> /// Gets the vendor identifier of the <see cref="Joystick"/>. /// </summary> public ushort VendorId { get; private set; } /// <summary> /// Gets the product identifier of the <see cref="Joystick"/>. /// </summary> public ushort ProductId { get; private set; } /* ... */ /// <summary> /// Determines whether the device is an XInput device or not. Returns true if it is, false if it isn't. /// </summary> public bool IsXInputDevice { get { var ParseIds = new Regex(@"([VP])ID_([\da-fA-F]{4})"); // Used to grab the VID/PID components from the device ID string. // Iterate over all PNP devices. using (var QueryPnp = new ManagementObjectSearcher(@"\\.\root\cimv2", string.Format("Select * FROM Win32_PNPEntity"), new EnumerationOptions() { BlockSize = 20 })) { foreach (var PnpDevice in QueryPnp.Get()) { // Check if the DeviceId contains the tell-tale "IG_". var DeviceId = (string)PnpDevice.Properties["DeviceID"].Value; if (DeviceId.Contains("IG_")) { // Check the VID/PID components against the joystick's. var Ids = ParseIds.Matches(DeviceId); if (Ids.Count == 2) { ushort? VId = null, PId = null; foreach (Match M in Ids) { ushort Value = ushort.Parse(M.Groups[2].Value, NumberStyles.HexNumber); switch (M.Groups[1].Value) { case "V": VId = Value; break; case "P": PId = Value; break; } } if (VId.HasValue && this.VendorId == VId && PId.HasValue && this.ProductId == PId) return true; } } } } return false; } } /* ... */ } }
When the joysticks are enumerated they are only added to the input manager if they are not XInput devices.
To round up the entry, here's a screenshot of a minesweeper clone I've been working on in BBC BASIC.

You can view/download the code here and it will run in the shareware version of BBC BASIC for Windows. The code has been deliberately uglified (cramming multiple statements onto a single line, few comments, trimmed whitespace) to try and keep it within the shareware version's 8KB limit as this is a good limit to keep in mind for the TI-83+ version too.
Virtual screen resolutions for BBC Micro compatibility
Monday, 8th December 2008
The BBC Micro had a virtual resolution of 1280×1024, meaning that if you drew a circle centred on (1280/2,1024/2) it would appear in the middle of the screen regardless of its pixel resolution. On top of that, (0,0) was in the bottom-left hand corner of the screen with the Y axis pointing upwards.

Thus far I'd been using the slightly more intuitive fixed resolution of 96×64 with (0,0) in the top-left hand corner with the Y axis pointing downwards. This means that any graphics program for the TI-83+ version appears upside down and squashed into the bottom-left corner when run on the BBC Micro.
I have worked on attempting to remedy this. 1280×1024 does not divide cleanly into 96×64, so I've used a constant scale factor of 16 on both axes resulting in a virtual resolution of 1536×1024. (Flipping the Y axis is easy enough). This means that programs drawing shapes (lines, circles, triangles, rectangles, parallelograms) will run on both BBC Micro "compatible" versions of BBC BASIC and the TI-83+ and produce roughly the same results.

As this may not be to everyone's tastes the two options may be independently controlled with two new star commands;
- *YAXIS UP|DOWN
- *GSCALE ON|OFF
The default is to have *YAXIS UP and *GSCALE ON. To revert to the old behaviour you could specify *YAXIS DOWN and *GSCALE OFF.
I have also been working on implementing the OS call OSGBPB. This call allows you to read/write multiple bytes of data in one go, so is much faster than using the byte-at-a-time BGET# and BPUT# commands. It also provides a way to enumerate filenames, a feature I have yet to implement but one that should be useful (eg to search for data files for your own program without having the filename hard-coded or having to prompt the user).
Three sides good, four sides bad.
Sunday, 30th November 2008
Work on the TI-83+/TI-84+ port of BBC BASIC continues bit-by-bit.
I've added triangle filling (left) and, by extension, parallelogram filling (right) PLOT commands. The triangle filler is a little sluggish, tracing each edge of the triangle using 16-bit arithmetic, but it seems fairly robust. I am trying to focus on robustness over speed for the moment, but it would seem easy enough to add a special-case triangle edge tracer if both ends of the edge can fit into 8-bit coordinates (all inputs to plot commands use 16-bit coordinates).
The parallelogram on the right is specified with three coordinates, and the fourth point's position is calculated with point3-point2+point1. As parallelograms are drawn as two triangles there's an overdraw bug when they are drawn in an inverting plotting mode.

This needs to be fixed.
The BBC Micro OS exposed certain routines in the &FF80..&FFFF address range. These routines carried out a wide variety of tasks, from outputting a byte to the VDU to reading a line of input or changing the keyboard's auto-repeat rate. BBC BASIC (Z80) lets the person implementing the host interface catch these special-case calls, so I've started adding support for them. A friend very kindly donated copies of three BBC Micro books, including the advanced user guide (documenting, amongst other things, the OS routines) and the BASIC ROM manual.
As an example, if you write the value 16 to the VDU it clears the text viewport. BBC BASIC has the CLS keyword for this, but you can also send values directly to the VDU with the VDU statement, like this: VDU 16. This in turn calls the BBC Micro's OSWRCH routine, located at &FFEE, with the accumulator A containing the value to send to the VDU. An alternative method to clear the text viewport would therefore be A%=16:CALL &FFEE.
Now, you may well be wondering how this is of any use, given the existance of a perfectly good CLS statement (or, failing that, the VDU statement). The usefulness becomes apparent when you remember that BBC BASIC has an inline assembler. There is no CLS or VDU instruction in Z80 assembly, but by providing an OSWRCH routine you can interact with the host interface and so clear the screen from an assembly code routine; in this case [LD A,16:CALL &FFEE:] (square brackets delimit assembly code).
Sadly, there is a limitiation in the TI-83+/TI-84+ hardware that prevents this from working seamlessly. The memory in the range &C000..&FFFF, where these routines reside, is mapped to RAM page 0. RAM page 0 has a form of execution protection applied to it, so if the Z80's program counter wanders onto RAM page 0 the hardware triggers a Z80 reset. To this end all of these OS calls are relocated to &4080..&40FF, so in the Z80 assembly snippet above you would CALL &40EE instead. This only applies to CALLs made from assembly code - the BASIC CALL statement traps calls to the &FF80..&FFFF so they can be redirected seamlessly to retain compatibility with other versions of BBC BASIC (Z80).
After all this work I noticed that the host interface was crashing in certain situations, especially when writing to a variable-sized file in a loop. This is the sort of bug that is tricky to fix; sometimes it would crash instantly, sometimes it would write the first 5KB of the file fine then crash.
It turned out to be a bug in the interrupt service routine (ISR). In this application the ISR is used to handle a number of tasks such as trapping the On key being pressed to set the Escape condition or to increment the TIME counter (as well as other time-related features such as the keyboard auto-repeat or cursor flash). On the TI-83+, which doesn't have a real-time clock, it also calls a RTC.Tick function approximately once per second to update the (very inaccurate) software real-time clock. To call this function it uses the BCALL OS routine. It appears that if the BCALL routine was used from an ISR when the TI-OS was in the process of enlarging a file it would crash. Removing the call to RTC.Tick appears to have fixed the bug entirely.

It is possible to put BBC BASIC into an infinite loop if you make a mistake in your error handler. In the above example program the error handler in line 10 fails to bail out on an error condition, running back into line 20 that itself triggers a division by zero error. You cannot break out of the loop by pressing On as that works by triggering an error (error 17, Escape). To improve safety I've added a feature whereby holding the On key down for about 5 seconds causes BBC BASIC to restart. This loses the program that was previously loaded in RAM, but you can retrieve with the OLD statement.
I've also rewritten all of the "star" commands. These are commands, usually prefixed with an asterisk, that are intended to be passed to the OS. As the TI-83+/TI-84+ does not have an especially useful command-line driven interface (most of the UI is menu-driven) I've implemented this part myself, basing its commands on ones provided by the BBC Micro OS. For example, *SAVE can be used to save a block of memory to a file, or *CAT (aliased to *DIR and *.) can be used to show a list of files.

In the case of *CAT I've added a pattern-matching feature that lets you use ? and * as wildcards to limit the files shown.
After noticing that *COPY took three seconds to copy an 860 byte file I optimised some of the file routines to handle block operations more efficiently. Reading and writing single bytes at a time is still rather sluggish, but I'm not sure that there's much I can really do about that.

Finally, for a bit of fun I noticed a forum post enquiring about writing assembly programs on the calculator. Here's a program that assembles a regular Ion program using BBC BASIC's assembler.
BBC BASIC's improved filling, *EXEC and Lights Out
Thursday, 13th November 2008
Progress on the TI-83+/TI-84+ port of BBC BASIC continues - I'm hoping to get a beta release out soon. ![]()

I've done quite a lot of work on the graphics features. Every shape that is plotted can be set to either the foreground colour, background colour or to invert the pixels it covers. This wasn't implemented properly (everything was always drawn in the foreground colour) which has been corrected.
The first image in the above group shows the flood-filler in action, filling inside and outside a triangle. The second image demonstrates the ellipse drawing and filling code by qarnos. It had a small amount of overdraw, which is not normally a problem, but in an inverting plot mode drawing a pixel twice causes it to reset to its original value. This ends up leaving gaps in the circle. Fortunately he was able to give me a lot of help in fixing it. ![]()
The third image demonstrates a non-standard feature I've added - being able to set your own fill patterns. The GCOL statement lets you set the foreground or background colour, and for values between black and white a dithered fill pattern is substituted instead. GCOLPAT takes a pointer to an 8×8 pixel fill pattern and subsequent fill operations will use that instead; passing FALSE (0) to GCOLPAT or setting a colour normally via GCOL reverts to the standard dither fills.
I've also done a small amount of benchmarking. There's a sample program in the TI-83+ guidebook that draws a Sierpinski triangle.

On a regular 6MHz TI-83+, the TI program takes 7 minutes and 8 seconds to run. A direct translation to BBC BASIC executes in 2 minutes and 21 seconds, and a simplified version executes in 1 minute and 56 seconds.

I'm also trying to improve the number of OS-level "star" commands. Above is a demonstration of *EXEC which reads console input from a text file. A file is opened for output using OPENOUT, some text is written into it using PRINT#, and then it it *EXECuted. This is one possible way of converting a text file into a BBC BASIC program.

Finally, I'm trying to write a game as an example program. The above screenshot shows an incomplete clone of the Lights Out game by Tiger Electronics.
TIME$ to resume work on TI-83+ BBC BASIC
Wednesday, 29th October 2008
It's been a while since I worked on the TI-83+ calculator port of BBC BASIC, and due to a relatively modular design some of the new features I'd been working on for the Z80 computer project version could be easily transferred across.
The first addition to the calculator port is the TIME$ keyword, which lets you get or set the system time.

That's all very well and good, but only the TI-84+ calculator has real-time clock hardware - the TI-83+ doesn't have any sort of accurate timekeeping to speak of. Rather than display an error when TIME$ is used I opted to use an inaccurate software-based clock. It uses the TI-83+'s timer interrupts (roughly 118Hz) to update the date and time about once a second. The clock is reset to Mon,01 Jan 2001.00:00:00 every time BBC BASIC is restarted and keeps abysmal time, but software designed to use the clock will at least run.
I have been transferring and amending documentation from Richard Russell's website to a private installation of MediaWiki. There are about 120 entries so far; having documentation puts me much closer to being able to make a release.
I have also fixed a handful of bugs. One that had me tearing my hair out was something like this:
250 DEF PROC_someproc(a,b) 260 a=a*PI 270 ENDPROC
The program kept displaying a No such variable error on line 260. Well, a is clearly defined, and retyping the procedure in another program worked, so what was the problem here? I thought that maybe one of the graphics calls or similar was corrupting some important memory or modifying a register it shouldn't. It turns out that the problem lay in the Windows-based tokeniser - it was not picking up PI as a token, for starters, and was storing the ASCII string "PI" instead. On top of that, it was treating anything after a * as a star command, which aren't tokenised either. (Star commands, such as *REFRESH, are passed directly to the host interface or OS). Retyping the problematic lines caused BBC BASIC to retokenise them, which was why I couldn't replicate the problem in other programs. By fixing the tokeniser, everything started working again.
The source code for the analogue clock program is listed below.
10 *REFRESH OFF 20 VDU 29,48;32; 30 GCOL 0,128 40 REPEAT 50 t$=TIME$ 60 hour%=VAL(MID$(t$,17,2))MOD12 70 min%=VAL(MID$(t$,20,2)) 80 sec%=VAL(MID$(t$,23,2)) 90 sec=sec%/60 100 min=(min%+sec)/60 110 hour=(hour%+min)/12 120 CLG 130 GCOL 0,127 140 MOVE 0,0 150 PLOT 153,31,0 160 GCOL 0,0 170 FOR h=1TO12 180 hA= h/6*PI 190 hX=30*SIN(hA) 200 hY=30*COS(hA) 210 MOVE hX,hY 220 DRAW hX*0.9,hY*0.9 230 NEXT h 240 PROC_drawHand(sec,30) 250 PROC_drawHand(min,24) 260 PROC_drawHand(hour,16) 270 *REFRESH 280 UNTIL INKEY(0)<>-1 290 *REFRESH ON 300 END 310 DEF PROC_drawHand(pos,length) 320 MOVE 0,0 330 pos=pos*2*PI 340 DRAW length*SIN(pos),-length*COS(pos) 350 ENDPROC
I translated the tokeniser source code to PHP so that by pointing a browser to file.bbcs for a known file.bbc the highlighted, detokenised source code is served as HTML instead. Hurrah for mod_rewrite, and if you're using IIS Ionic's Isapi Rewrite Filter performs a similar job using the same syntax.
Times, backlights and off-page calls
Sunday, 14th September 2008
Dates, times and backlights
I'm using a DS1307 real-time clock to provide the computer with real-time date and time functions. It's a great little chip - all it needs is power, two lines for I2C communications, a 32768Hz crystal between two pins and a back-up battery to keep it ticking when main power is removed and it's happy. That accounts for seven pins; the last remaining pin can be used as a one-bit output (you can set it to a high or low state in software) or it can be configured to output a square wave at 1Hz, ~4kHz, ~8kHz or ~32kHz.

BBC BASIC can access the clock via the TIME$ pseudo-variable. This string variable returns the date and time in the format Sun,14 Sep 2008.15:20:00, and you can set the clock by assigning to the variable. When setting the clock you can specify either the date, the time, or both. Parsing the string has been an interesting exercise in Z80 programming, as it's not something I've ever attempted without regular expressions before!

The only hardware modification since last time is a very poorly implemented software control of the backlight. The fifth bit of the control port specifies whether the backlight is on or off, and it can be toggled with the *BACKLIGHT command. I say "poorly implemented" as the transistor driver I'm using to interface the hardware port with the backlight LEDs results in a much dimmer backlight than when I had the LEDs hooked up directly to the power supply (on the positive side, at least the 5V regulator's heatsink is cool enough to touch - the backlight draws a lot of current).
Calling off-page functions
Now that I have access to all eight 16KB "pages" that make up the 128KB OS ROM, it may help to explain how one can use all of this memory. After all, if page 1 is swapped in and you wish to call a function on page 2, a regular Z80 call isn't going to work as you need to swap page 2 before calling the function then swap page 1 back in afterwards.
The trick is to exploit the way that the Z80 handles calling subroutines. There is a 16-bit register, PC, which stores the address of the next instruction to execute. When you call a subroutine, the Z80 pushes PC onto the stack then sets PC to the address of the subroutine. When you return from a subroutine (via the ret instruction) the Z80 simply pops the value it previously pushed onto the stack and copies this back to PC. Instead of calling the target subroutine directly, you call a special handler that is available on every page. Following your call is 16-bit identifier for the off-page function you wish to call. This handler then (prematurely) pops off the return address from the stack, reads the 16-bit value that follows it (which is the indentifier of the function you wish to call), looks up the page and address of the target function, swaps in the correct page and calls it as normal. When the function returns, the handler then swaps back the calling page and jumps back to the return address.
The Z80 has a series of rst instructions that call fixed addresses within the first 256 bytes of memory. These instructions are useful as they're small (one byte vs three bytes for a regular call) and fast, so I'm using rst $28 to call the off-page call handler (for no other reason than it's the same as the handler on the TI-83+).
As an example, let's say you had this function call at address $2B00:
$2B00: rst $28 $2B01: .dw $30F0 $2B03: ; We'd return here.
When the Z80 executed that rst $28 it would push $2B01 (address of the next instruction) to the stack then jump to $28. The handler at $28 would do something like this:
pop hl ; hl is a 16-bit register and would now contain $2B01 ld e,(hl) ; Read "e" from address pointed to by hl, now equals $F0 inc hl ; hl = $2B02 ld d,(hl) ; Read "d" from address pointed to by hl, now equals $30 inc hl ; hl = $2B03 ("real" return address) push hl ; push hl back on the stack so when we return from here we end up in the correct place.
Now, de is $30F0 - this is the identifier of the function we're calling. In my case, the identifier points to a function table on page 0. Each entry in the table is three bytes - one byte for the page index and two bytes for the address of the function on the that page. We'd need to do something like this:
in a,(Page) ; Read the current page into A.
push af ; Push A and F to the stack for later retrieval.
and ~7 ; Mask out the lower three bits of the address.
out (Page),a ; Sets current ROM page to 0.
ex de,hl ; Exchanges de and hl, so hl now points to the function identifier.
or (hl) ; ORs contents of memory at (hl) (ie, page number) with a, to set the target page.
inc hl
ld e,(hl) ; e = LSB of target address
inc hl
ld d,(hl) ; d = MSB of target address
ex de,hl ; hl = target address.
out (Page),a ; Swaps in the correct page.
ld de,ReturnFromHandler ; Address to return to. push de ; Store on stack. jp (hl) ; Set pc = hl. ReturnFromHandler ; Swap back the original page which was pushed earlier... pop af out (Page),a ret ; ...and return to the calling page!
A further advantage of using rst $28 to replace call is that both are the same size, so the assembler can check if you're calling an address on the same page or a different one and insert the regular (and much faster) Z80 call in places where you don't need to swap the page.
Finally, the obligatory video, this time showing a clock that toggles the backlight once a second.
Running BBC BASIC on a home-built computer
Sunday, 7th September 2008

This computer needs a name - I'd welcome any suggestions!
I have built a circuit on another piece of stripboard that will handle memory, clock signal generation and the Z80 itself.
A few posts ago I was wondering about how I'd partition memory. To date I've been using a very simple circuit where the lower 32KB of addressable memory is mapped to ROM and the upper 32KB is mapped to RAM. As my ROM chip is 128KB and I have two 32KB RAM chips, this seems a bit wasteful.
The memory layout I'm now using is quite simple: the upper 32KB is still mapped to RAM. However, only the first 16KB is mapped to ROM, and the three most significant bits of the ROM chip's address lines are connected to a device on the I/O board so that one of its eight 16KB "pages" can be swapped in. The next 16KB will be mapped to RAM, and the most significant bit of the RAM chip's address is connected to the same device on the I/O board so one of its two 16KB "pages" can be swapped in.

For more information, see the Wikipedia article on bank switching. There is a potential problem here; the Z80 uses particular fixed addresses for certain operations. The three most obvious ones are $0000 (jumped to on reset), $0038 (address of maskable interrupt handler) and $0066 (address of non-maskable interrupt handler). As which 16KB bank switched in at power-on is effectively random, the easy way around this problem is to ensure that the first 256 bytes or so of every ROM page has the same code assembled on it. This means that whichever page is swapped in on boot doesn't matter, as the same common boot code is available on each page.
The assembled memory board looks like this:
I have only attached one of the 32KB RAM chips. The wiring was becoming a bit of a nightmare (I think I'll need to solder to the track side of the stripboard to fit in that other RAM chip) so for the moment the system can only access the fixed 32KB RAM. I haven't yet added the device on the I/O board to handle bank switching, so for the moment the ROM is permanently configured to access the first 16KB page by pulling the its three externally controllable address lines low.
That said, this machine does genuinely run BBC BASIC (the last system only ran a mockup with a dummy header at the top of the screen). I've done quite a bit of work on the OS in the emulator and it works pretty well there, and with a minor adjustment to cram it onto a single 16KB page it works well on hardware too.
The row of chips along the bottom of the memory board are responsible for generating the clock signals that drive the computer. If this looks needlessly complex, that's because it can run at either 10MHz or 2MHz and generates the E signal for LCD access. The CPU needs to drop to 2MHz when accessing the LCD (the LCD driver can't keep up, otherwise) so I'll probably end up connecting the input for this 2MHz/10MHz switch to the LCD chip enable pins so that normally the system runs at 10MHz but drops to 2MHz when accessing the LCD. Allowing the user to drop to 2MHz to save power is an appealing idea, however...
Graphical text, BASIC tokeniser and flood-filling
Tuesday, 29th July 2008
I've got a fairly hackish "graphical text" mode set up (enabled with VDU 5, disabled with VDU 4) that causes all text that is sent to the console to be drawn using the current graphics mode (at the graphics cursor position, using the graphics colour and logical plotting mode and graphics viewport). This allows text to be drawn at any position on-screen, but is (understandably) a bit slower and doesn't let you do some of the things you may be used to (such as scrolling text, copy-key editing and the like).

I've also done some work on a tool to convert files from the PC to use in BBC BASIC. It takes the form of a Notepad-like text editor:

BBC BASIC programs are stored in a tokenised format (usually .bbc files on a PC) and need to be wrapped into a .8xp for transferring to the calculator. The editor above can open .8xp, .bbc and .txt directly, and will save to .8xp.
The detokeniser can be passed a number of settings, which can be used to (for example) generate HTML output, like this. The indentation is generated by the detokeniser (leading/trailing whitespace is stripped by the tokeniser). The tool can also be used to directly convert binaries into .8xp files if need be.

I've been doing a little work on a flood-filling algorithm. (PLOT 128-135, 136-143). The above images show its progress; on the left is the first version (which can only fill in black). There is a hole in the bottom-left of the shape, so the leaking is intentional. It also stops one pixel away from the screen boundary -- this too is intentional (it clips against the viewport). The second version, in the middle, plugs the leak and applies a pattern (which will be a dither pattern in BBC BASIC) to the filled area. On the right is the third version, which will fill over black or white pixels with a pattern.
The main filling algorithm needs a 764 byte buffer for the node queue and three 16-bit pointer variables to manage the queue. I've rounded the queue size up to 768 bytes, so it fits neatly on one of the RAM areas designed to store a bitmap of the display.
The problem is filling with a pattern. The way I currently do this is to back up the current screen image to a second 768-byte buffer, fill in black as normal, then compare the two buffers to work out which bits have been filled and use those as a mask to overlay the dither pattern. This is quite a lot of RAM, just to flood-fill an image!
For those who are interested, I'm using the "practical" implementation of a flood fill algorithm from Wikipedia.
Text viewports and sprites
Monday, 21st July 2008
Back to work on the TI-83 Plus port of BBC BASIC! To complement the graphics viewport I've added support for text viewports — this lets you define the area the text console uses. The following VDU commands are now supported:
- VDU 24,<left>;<top>;<right>;<bottom>;
Define a graphics viewport. - VDU 28,<left>,<top>,<right>,<bottom>
Define a text viewport. - VDU 26
Reset both viewports to their default settings (full screen). - VDU 29,<x>;<y>;
Defines the graphics origin.

The above screenshots defines the graphics viewport to fill the left hand side of the screen and shunts the text viewport over to the right half, using the following code:
VDU 24,0;0;47;63; VDU 28,12,0,23,9 VDU 29,24;32;I've also added simple sprite drawing to BBC BASIC's PLOT command. PLOT usually takes a shape type and two coordinates, but for sprites (shapes 208..215) I've added an extra parameter - the address of the sprite data to use.

10 DIM ball 7 20 ball?0=&3C 30 ball?1=&5E 40 ball?2=&8F 50 ball?3=&DF 60 ball?4=&FF 70 ball?5=&FF 80 ball?6=&7E 90 ball?7=&3C 100 *REFRESH OFF 110 REPEAT 120 CLG 130 T=TIME/100 140 FOR P=0 TO 5 150 A=P/3*PI+T 160 X=16*SIN(A)+44 170 Y=16*COS(A)+28 180 PLOT 213,X,Y,ball 190 NEXT 200 *REFRESH 210 UNTIL INKEY(0)<>-1 220 *REFRESH ON
The above code allocates 8 bytes of memory (DIM ball 7) then copies the sprite data to it by use of the ? indirection operator. This is a little laborious, so in reality you'd probably store your sprites in a binary file external to the main program, and might load them like this:
10 ball%=FN_loadSprite("SPRITES",0) 20 face%=FN_loadSprite("SPRITES",1) 30 *REFRESH OFF 40 REPEAT 50 CLG 60 T=TIME/100 70 FOR P=0 TO 5 80 A=P/3*PI+T 90 X=16*SIN(A)+44 100 Y=16*COS(A)+28 110 PLOT 213,X,Y,ball% 120 NEXT 130 PLOT 213,44,28,face% 140 *REFRESH 150 UNTIL INKEY(0)<>-1 160 *REFRESH ON 170 END 180 DEF FN_loadSprite(f$,i%) 190 fh%=OPENIN(f$) 200 PTR#fh%=i%*8 210 DIM spr 7 220 FOR j%=0 TO 7 230 spr?j%=BGET#fh% 240 NEXT j% 250 CLOSE#fh% 260 =spr 270 ENDPROC
(Note FN_loadSprite() at the end of the program). The result is the following:

Next up: drawing text at the graphics cursor position (as sprites).
Clipped graphics and ellipses
Monday, 23rd June 2008
qarnos — author of the superb Aether 3D engine — has been lending a hand with the BBC BASIC graphics API and contributed a large amount of very useful code.

First up is some code to clip 16-bit line coordinates down to 8-bit coordinates. This allows for lines to be partially (or completely) off the screen.

He's also written a fast ellipse drawing and filling routine. The ellipses are also clipped to the viewport and are filled with an 8×8 pixel pattern.

The graphics viewport can be redefined using the VDU 24,left;top;right;bottom; command as demonstrated in the above example.

GCOL can also be used to set a plotting mode; either plotting the specified colour directly, performing a logical operation (OR, AND, EOR) or inverting the existing colour.

All but the last of the above screenshots are the result of running BBC BASIC on a TI-83+ SE at 15MHz. The final screenshot is running at the regular 6MHz.
Gyrating cubes in BBC BASIC
Thursday, 12th June 2008
Work has been keeping me busy recently, but I've tried to set aside a small amount of time each evening to reclaim some sanity and do a little work on BBC BASIC. Not much progress has been made, but there has been some at least.

On the left is the program running on an 83+ SE at 15MHz, on the right on the regular 83+ at 6MHz. If you really wanted to do 3D in BBC BASIC you could probably get away with writing some of the more expensive operations — such as transforming/projecting vertices in batches — in assembly, but that would sort of go against the whole point of trying to write a program to test the speed of BASIC. ![]()
Here's the rather naïve code:
10 *REFRESH OFF 20 DIM p%(15) 30 fps%=0 40 lfps%=0 50 fpst%=TIME+100 60 REPEAT 70 rX=TIME/300 80 rY=TIME/400 90 SrX=SIN(rX) 100 CrX=COS(rX) 110 SrY=SIN(rY) 120 CrY=COS(rY) 130 pt%=0 140 FOR x=-1TO1STEP2 150 FOR y=-1TO1STEP2 160 FOR z=-1TO1STEP2 170 tX=y*CrX-x*SrX 180 tY=-x*CrX*SrY-y*SrX*SrY-z*CrY 190 tZ=3-x*CrX*CrY-y*SrX*CrY+z*SrY 200 p%(pt%)=tX*40/tZ+48 210 pt%=pt%+1 220 p%(pt%)=tY*40/tZ+32 230 pt%=pt%+1 240 NEXT 250 NEXT 260 NEXT 270 CLG 280 PRINTTAB(10,0)lfps%" FPS" 290 MOVE p%(0),p%(1) 300 DRAW p%(4),p%(5) 310 DRAW p%(12),p%(13) 320 DRAW p%(8),p%(9) 330 DRAW p%(0),p%(1) 340 DRAW p%(2),p%(3) 350 DRAW p%(6),p%(7) 360 DRAW p%(14),p%(15) 370 DRAW p%(10),p%(11) 380 DRAW p%(2),p%(3) 390 MOVE p%(4),p%(5) 400 DRAW p%(6),p%(7) 410 MOVE p%(12),p%(13) 420 DRAW p%(14),p%(15) 430 MOVE p%(8),p%(9) 440 DRAW p%(10),p%(11) 450 *REFRESH 460 fps%=fps%+1 470 IF TIME>fpst% THEN lfps%=fps%:fps%=0:fpst%=TIME+100 480 UNTIL INKEY(0)<>-1 490 *REFRESH ON 500 END
I have also added support for the COLOUR statement (for changing the text foreground and background colour) and copy key editing.

Copy key editing, as demonstrated in the screenshot on the right, lets you break the text input cursor into two parts - a write cursor (which is left behind on the line you were editing) and a read cursor, which can be positioned anywhere on the screen. Pressing the copy key (in this case, XTθn) reads a character under the read cursor and writes it to the write cursor, then increments both.
One feature that's a bit more fun is the support of device files. This is a way of accessing external devices as if they were files. For example, by opening the file AT.DEV you can read and write bytes using the AT protocol (used by AT and PS/2 keyboards and mice) using BBC BASIC's built-in file manipulation routines.

You could use this to do something useful, or could just use this to flash the LED on a keyboard back and forth.
10 keyb%=OPENOUT"AT.DEV" 20 DATA 2,4,1,4,-1 : REM LED flash pattern (-1 terminated). 30 REPEAT 40 READ l% 50 REPEAT 60 PROC_setled(l%) 70 PROC_pause(30) 80 READ l% 90 UNTIL l%=-1 100 RESTORE 110 UNTIL FALSE 120 END 130 : 140 DEF PROC_flushin 150 REPEAT 160 IF EXT#keyb% d%=BGET#keyb% 170 UNTIL NOT EXT#keyb% 180 ENDPROC 190 : 200 DEF PROC_setled(l%) 210 BPUT#keyb%,&ED 220 PROC_flushin 230 BPUT#keyb%,l% 240 PROC_flushin 250 ENDPROC 260 : 270 DEF PROC_pause(t%) 280 start%=TIME 290 REPEAT UNTIL TIME >= start%+t% 300 ENDPROC
BBC BASIC running as an application
Tuesday, 3rd June 2008
Richard Russell has kindly supplied the project with the BBC BASIC relocatable modules — compiled object files which can be relocated to any memory address by a linker — which means that BBC BASIC can now be configured to run on the TI's hardware.
The tools to relocate the modules run under CP/M, which means that rather trying to integrate the relocation into the build process (which would be a little awkward) I'm going to relocate the modules to a fixed base address and inject the resulting binary file directly into the application.
BBC BASIC will reside from &4100. From &4000..&40FF is a jump table, which BASIC uses to interact with the host. As the addresses of the host interface entry points will change as the code changes, and I don't wish to keep on relinking BASIC in CP/M, a fixed jump table makes life a lot easier. BASIC jumps to a predetermined fixed address in the jump table, which redirects - via a second jump - to the real entry point.

I think I've implemented all of the main host interface entry points, though some — notably those involved in file I/O — need making more robust. I don't currently reserve any memory for BASIC's scratch area, which means that the TI-OS can (and does) decide to overwrite it at inconvenient moments. Even though TI provided us with at least three different 768-byte buffers (the exact size of BBC BASIC's scratch area), none of them are aligned to a 256 byte boundary. ![]()
Z80 BBC BASIC - Emulated on Windows
Thursday, 22nd May 2008
I've started working with the actual BBC BASIC interpreter. As it won't run in its current state on the TI calculator (it relies on a jump table at &FF80..&FFFF to interact with the host, which is protected) I'm using the Z80 emulator I wrote for Cogwheel to try and puzzle out what the host interface should be doing from the relative sanity of C# code (the jump table is populated with OUT (n), A instructions which are subsequently trapped and handled by the emulator).

One thing I hadn't realised is that the graphics operations that BBC BASIC offers are actually implemented via the OSWRCH handler (OS WRite CHaracter), which means that BBC BASIC's PLOT, MOVE and DRAW commands will also be available, as well as any commands that use them indirectly (such as CIRCLE).
BBC BASIC
Monday, 19th May 2008
This is a project I initially attempted to get off the ground about four years ago, but never did. Anyhow, I've started work on it, and thanks to help from Richard Russell (the original developer) and J.G.Harston (who comparatively recently developed the Sinclair ZX Spectrum port) it looks like it should be possible this time around. ![]()
BBC BASIC was the native programming language on Acorn's BBC Micro. It's a structured BASIC dialect and supports procedures and functions, permitting far nicer code than the line-numbered GOTO and GOSUB code on other contemporary machines. It also has a built-in assembler, for inline assembly.
There is no source available, which is where the problems start to come in. Fortunately, J.G.Harston has developed a utility that permits the platform-agnostic BBC BASIC interpreter to be relocated. However, it assumes that the system has a jump table in RAM from $FF80..$FFFF (this jump table would be used to call platform-specific code); this memory range is not executable on the TI-83+. Execution protection in the $C000..$FFFF range may also cause issues for inline assembly code (which is, naturally, executed from RAM).
The TI-OS does not offer an especially suitable environment for BBC BASIC either; it is mainly menu driven (a command-line driven environment is preferable), does not have a plain text editor and does not use ASCII. To resolve this issues, I've concentrated on developing a suitable environment for BBC BASIC to live in, including a command-line interface and text editor.

Text files are stored as AppVars with a TEXTFILE header, and I've developed a Windows-based notepad clone for editing them (it saves and loads directly to and from .8xv). The following commands are currently supported (see here for a reference from the Windows verion): BYE, COPY, DELETE, DIR, ERASE, EXEC, QUIT, RENAME, TYPE, |.
To enter the editor, EDIT can be used. This presents a full-screen editor a little like the TI-OS program editor, but edits plain text files.
The interface transparently supports AT keyboards (which are rather easier to type on than the TI's keypad). The character resolution is 24 columns in 10 rows (4x6 pixel characters), giving you quite a lot of room to see what you're working on.
I intend on the final program being a 2-page Flash application; one page for BBC BASIC, and one page for the environment and OS interface. This unfortunately makes this a TI-83+ only project.
Even if I don't manage to shoe-horn BBC BASIC onto the TI-83+, the interface code (which uses direct hardware access for everything but opening and editing AppVars) could be useful for other projects.
Subscribe to an RSS feed that only contains items with the BBC BASIC tag.






