Sunday, August 20, 2017

Launching FDISK+FORMAT direct from boot sequence

Another little job done tonight: Fixing running the FDISK/FORMAT utility from the Hypervisor.  This has been almost working for quite some time, but not quite.

 The first step has been working for some time, which is to watch for the user pressing the SPACE bar repeatedly during boot.  This interrupts the normal boot sequence and displays the list of utilities compiled into the bitstream.  These utilities hide in the top 30KB of colour RAM, where no C64 or C65 program knows how to touch, and are pre-initialised in the FPGA bitstream, so that the RAM in this location "just happens" to have these programs there.

 

What was not working was actually running the FDISK program. This was because I had written it using CC65, which does a JSR $FFD2 to set lower-case character set in its entry routine. However, when running in the Hypervisor, there is no ROM present. To solve this, the boot ROM now writes an RTS instruction at $2FFD2, so that a JSR to $FFD2 will safely do nothing and return.

That got the FDISK utility running, and after a bit of mucking about with character sets (there is only the partial Hypervisor character set available), and various other little fixes, the FDISK utility now happily starts, and tries to probe your SD card:


 Note the friendly warning message: This is an improvement from before, when it would just go right ahead and repartition and reformat your SD card without asking, on the assumption that if you ran FDISK on the MEGA65, it was to get your SD card working, not for any other purpose. It now politely asks you to type the two words DELETE EVERYTHING in capitals before it will proceed.  If you get it wrong, for example, type it in lower case, then it tells you to try again:


 If you get it correct, then it does as promised, completely reformat and repartition your SD card:

This process is quite fast, taking only a few seconds to zero out the important parts of the disk and put the half-dozen or so correct sectors in.

What is not immediately obvious here, is that the keyboard input is using the new hardware-accelerated keyboard input: Reading ASCII decoded keys, including all modifier key effects, is as simple as reading $D610 to peek at the next character, and then writing anything back to $D610 to pop the key from the queue.

Hardware animating the on-screen keyboad

I have done a bit more work on the on-screen keyboard, adding hardware animation for it to appear from the bottom off the screen, and also to horizontally centre itself, and choose the correct width, based on the current video mode, so that it fills (or almost fills) the full width of the screen.  

Together, these features are important for adding touch-screen support, where touching the screen should cause the on-screen keyboard to automatically appear in a sensible place, and without the key boxes being too small to use, and all ideally without having to trap to the hypervisor (you might want to be typing something into the hypervisor).

I now have it running fairly well in simulation, and am currently building a bitstream with these changes incorporated.  But since I have the framework already for producing image files of the running simulation, I figured it would be fun to make an animated GIF of the keyboard appearing. 


Note that the speed it will appear on screen in reality will be faster than this, as animated GIFs only support a fairly low maximum animation speed.

Friday, August 18, 2017

Solid-state Joystick

This is not something that I was expecting to be doing this year, but sometimes opportunities just pop up.

Early in the year, one of my colleagues, Damian, showed me one of these strain-gauge solid-state joysticks that they were using as part of the undergraduate engineering curriculum:


Their goal was to teach the students how to read strain-gauges.  But I immediately saw the applicability for making a no-moving-parts super-robust joystick for the MEGA65 and all other retro computer users.

Strain-gauges measure the strain on an object, by effectively measuring the stretching or compression force on the sensor caused by deformation of the object under strain (apologies to any mechanical engineers who are probably cringing at my description here).  All you have to do is to try to move the joystick handle, and the gauges will pick up the minute deformation of the steel plate it is connected to.  This is how those touchpoint pointing devices that you find in the keyboards of some laptops work.

Seeings as we have only one sick TAC2 joystick in the lab, and haven't really seen anything worth replacing it with on the market, we decided to explore designing a MEGA65/C64/Amiga/Atari compatible joystick around this concept -- especially since we had working hardware on hand to work with.

The teaching unit was designed to work with an Arduino, so I went and bought one this morning, and between meetings today hacked up a tiny Arduino sketch to interface to it.  I figured we only needed 2 of the 4 sensors, since they are at 90 degrees to each other.  It turned out that all we needed to do was to tare two of the sensors, i.e., subtract their value when the stick is standing un-touched, and then monitor the sign and magnitude of deviation from zero for the two sensors, and we could quite easily detect all 8 directions with good reliability. The lack of travel makes this a potentially very fast joystick for those games where you have to toggle rapidly from side to side.



The only caveat with using only two sensors instead of four is that we can't then interpret a tap on the top of the joystick. While such tap detection is a fun idea, for a retro gaming joystick, it isn't really required, as you can't tap a stick while yanking it around at high speed.  Thus we will still need to have a real fire button, but it does mean we can save on sensors and the associated amplification circuitry for reading them.

Current idea for the fire button(s) is to have a fire button which interrupts an infra-red sensor, like a shop door sensor.  That way, there will be the absolute minimum of moving parts, short of making the fire button touch-sensitive -- but that doesn't feel right.

Otherwise, the biggest challenge we saw was the drift in readings, which means that there is a need for recalibration.  This is a well known problem with the Touchpoint devices, as they have to fairly frequently recalibrate. This occurs automatically, and shouldn't be a big problem, but we will have to implement the algorithm for this. 

Apparently a common approach is to look for a steady reading with very little variation as an indication of it being stationary, and recalibrate to that point. This would be quite easy to implement.

Otherwise from an electronic perspective, we just need to add the joystick port signalling, which is fairly easy to do.

Simultaneously, we can also start looking at laying out the important parts of the Arduino and the strain gauge shield onto a single PCB that can fit over the metal base plate.  We have a student who will hopefully look at this as part of their project, but I might also talk to Damian about this.  

I would also like to add PWM output onto the pot lines, so that we can have it support 1351 mouse mode, using the proportional/analog nature of the strain gauges to allow the joystick to work as a pointing device for GEOS, so that you don't need to swap joystick and mouse all the time.

Then the plan is to design the plastic case and knob for it, and make necessary adjustments to the metal base plate, so that we can assemble these into complete working joysticks, and indeed have a design that is feasible to produce in modest quantities. Maybe we will design it for a clear case, so that the no-moving-parts insides are visible. Either that or traditional Joystick Black.

Either way, if we like the result, and they are robust enough in practice, we might look at making them available to folks if there is sufficient interest.

Tuesday, August 15, 2017

On-screen keyboard display

Today I more or less got the on-screen keyboard working for the MEGA65:



Not only does it appear as a nice alpha-blended composited display, it also shows which keys are being pressed, even if not being pressed on the on-screen keyboard (more on input modes in a moment):


Some might be asking why a computer with a keyboard needs to have an on-screen display in the first place.  This is indeed a very good question, with several possible (if not plausible) answers:

1. If you were using a C64 keyboard instead of a C65 keyboard, you might like to press one of the additional keys.

2. If you are using a Nexys4 board, and can't remember the key mapping, you can now mash keys until you see the one you want toggle.

3. You might have a broken key, and need an emergency rescue.

4. You might be playing a game, and find it is just too inconvenient to lean forward to press a key on the keyboard, when you could instead do it from your joystick.

5. You might be using a model of the MEGA65 that completely lacks a keyboard by default, such as a tablet or phone form factor.

6. You might want to just show off when people complain that 8 bit computers can't do advanced things like composited video.

As I say, while some of those might be possible, they might not be plausible.

Now, for how this works behind the scenes.

First, this is the fourth layer of compositing that the MEGA65 supports. The other layers are:

1. Bitplaned sprite mode, which allows modifying colours of underlying objects.

2. Alpha-blended text mode, that allows pixels to shade between the foreground and background colours.

3. Matrix Mode, that displays the serial console as a composited overlay, not dissimilar to what the on-screen keyboard does.

Like Matrix Mode, the On Screen Keyboard (OSK for short) is a post-process composited display.  It takes the output of the VIC-IV and Matrix Mode, and overlays the keyboard display on top.  It goes on top of Matrix Mode, because you might need to drive Matrix Mode via the OSK if you don't have a real keyboard available for some reason.

Also like Matrix Mode it has its own character set ROM (currently the ASCII 8x8 font I created for the MEGA65 text editor).  It also has to draw the complete keyboard layout, which is procedurally generated.

I could have done it using a bitmap instead, which would have been more flexible for the base layer, but would have also required 640x145 = ~11.3kB, unless I compressed it. More the point, it would not be possible to decide to show individual keys highlighted to show when they are being pressed.

I started out by thinking about how I could generate it procedurally.  I began with the ASCII-art keyboard layout from the C65 specifications guide, and
modified it slightly to better suite my tastes:

----+    +----+----+----+----+    +----+----+----+----+    +----+----+----+----
RUN |    |ESC |ALT |ASC | NO |    | F1 | F3 | F5 | F7 |    | F9 | F11| F13|HELP
STOP|    |    |    |DIN |SCRL|    | F2 | F4 | F6 | F8 |    | F10| F12| F14|   
----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----
 ~  | !  | "  | #  | $  | %  | &  | '  | (  | )  | {  |    |    |    |CLR |INST
 _  | 1  | 2  | 3  | 4  | 5  | 6  | 7  | 8  | 9  | 0  | +  | -  |GBP |HOME|DEL
----+--+-+--+-+--+-+--+-+--+-+--+-+--+-+--+-+--+-+--+-+--+-+--+-+--+-+--+-+----
TAB    |    |    |    |    |    |    |    |    |    |    |    |    | PI |
       | Q  | W  | E  | R  | T  | Y  | U  | I  | O  | P  | @  | *  | ^  |RESTOR
----+--+-+--+-+--+-+--+-+--+-+--+-+--+-+--+-+--+-+--+-+--+-+--+-+--+-+--+------
CTRL|SHFT|    |    |    |    |    |    |    |    |    | [  | ]  | }  |
    |LOCK| A  | S  | D  | F  | G  | H  | J  | K  | L  | :  | ;  | =  |  RETURN
----+----+--+-+--+-+--+-+--+-+--+-+--+-+--+-+--+-+--+-+--+-+--+-+----+----+----
    |       |    |    |    |    |    |    |    | <  | >  | ?  |      |    |
 M= | SHIFT | Z  | X  | C  | V  | B  | N  | M  | ,  | .  | /  | SHIFT|  UP|
----+-------+-+--+----+----+----+----+----+----+----+----+-+--+-+----+----+----
              |                   SPACE                    |    |    |    |
              |                                            |    |LEFT|DOWN|RGHT
              +--------------------------------------------+    +----+----+----

Note that I have also trimmed the left edge and right edge from the key art, and replaced some of the more exotic characters to descriptions of them.  This is to keep the result to 80 columns wide (as the compositor expects 80 columns), and to fit the character set I already had (since we are still not totally sure that it is safe to use the C64 character set without a license.)

I then wrote a C programme that directly reads this ASCII form of the keyboard and creates a packed version of the key labels, ignoring all the +, - and | characters that draw the outlines of the keys, and produces a simple packed format, where multiple spaces are run-length encoded.  The whole thing packs to about 400 bytes.

Then I hand-wrote the key mapping for each discrete key on each row using the keyboard matrix position numbers that the MEGA65 internally uses, numbered from $00 - $47.  If a key was wide, it had $80 added to it.  I probably could have figured out a way to automate the table generation, but for the small size, I figured it wasn't worth it.  Also, even though I made a few mistakes initially, they were easy to find and fix by pressing keys and seeing if the correct one lit up on the screen.

This gave the following table of 7 x 16 entries:

3F,7F,47,42,50,40,7F,04,05,06,03,7F,44,45,46,43
39,38,3B,08,0B,10,13,18,1B,20,23,28,2B,30,33,00
C1,3E,09,0E,11,16,19,1E,21,26,29,2E,31,36,D1,7F
3A,0F,0A,0D,12,15,1A,1D,22,25,2A,2D,32,35,01,01
3D,8F,0C,17,14,1F,1C,27,24,2F,2C,37,B4,52,7E,7E
7E,7E,7E,3C,3C,3C,3C,3C,3C,3C,3C,3C,7E,53,07,02
7F,7F,7F,7E,7E,7E,7E,7E,7E,7E,7E,7E,7F,7E,7E,7E

The astute will note that there are only 6 rows of keys, and that the bottom row looks rather repetitive.  This is because $7E is a special value that means "a non-existent key, but with a horizontal line drawn on the top edge" and $7F means "a non-existent key, with no horizontal line drawn on the top edge".  This sequence draws the bottom edge on the space bar and the cursor keys in the last real row.  This is also the reason for the $7F's on the first row, to leave the tops uncapped on the non-keys between the groups of keys there. If we used $7E, they would have been closed at the top.

The $C1 at the start off the third row is the TAB key, which is wide, so is really key $41 + $80 = $C1.  The wide flag causes the key to be drawn 150% wide, and for the text labels to be offset by half a character, so that they don't get drawn over the vertical lines between keys.

For wider keys, like RETURN or SPACE, the same key value is simply repeated enough times to get the required width, and the logic that draws the boxes around the keys knows that this means a single longer key.

It was then a bit of fiddling to get the VHDL code working correctly to draw all this, although the end result ended up being only 400 lines.  To speed up development, I wrote another little program that could be fed the output of the GHDL simulation of the OSK, and produce a PNG image of the OSK.  This allowed me to find and fix bugs in a seconds instead of the almost hour it takes to synthesise the design to FPGA. Here is an example of the output of the simulation:


Here you can also see several keys being held down with the respective keys being shown in reverse video with a thin border.  This was one off my goals to provide nice visual feedback of keyboard activity, and that the procedural rendering allowed without great trouble.

All in all, I am pretty happy with the result.  The keyboard is clear and accurately laid out, nicely composited over the display, and yet still has a distinctively 8-bit feel to it -- and if we want to change the layout a bit, it is as easy as changing the text file that is pre-processed to produce the packed representation.

Next step will probably be to add a mechanism to have a "cursor" in the form of a highlight key that is used to navigate around the OSK, so that keys can be pressed using a joystick or other input device.  This will be in addition to touch-screen support, that I hope to add in due course.

Sunday, August 6, 2017

Fast booting the MEGA65 with custom bitstream, kickstart and ROMs

The last couple of days I have put some more work into makingg a stream-lined software development process for the MEGA65.  The goal is to make it possible to test changes to software in a few seconds, and without hassle, instead of mucking about with pulling SD cards out, flashing the SQI flash on the FPGA boards and generally forgetting what it was you were trying by the time you got your modified software loaded.

An additional motivation for this is that the SD card interface on one of our hand-modified prototypes is not working at the moment, and Falk needed another way to get bitstreams, Kickstart firmware, C65 ROMs and software he is writing onto the machine easily.

This was a new requirement, that required something more advanced than the monitor_load utility that I wrote last week to solve some of these problems. 

Specifically, it needed to be posssible to load a C65 ROM and character ROM image, without ever even initialising the SD card.

So I set about modifying monitor_load to load the ROMs into the correct memory location.  That was fairly easy, apart from a little speed bump caused by the limitation of the bulk memory upload command in the serial monitor.  That problem is that the address counter when loading only increments the bottom 16 bits of the address, combined with the start address needing to be one less than the first address.  

For example, to load memory to pre-load $20000-$2FFFF, i.e., the first 64KB of a C65 ROM, we couldn't just subtract one from the address, and say l1ffff 2ffff, because it would only increment the bottom 16 bits, and leave the "1" at the front of the address the same.  (The "l" in front of the address is the command code to tell the serial monitor to bulk load memory.)

Instead, we have to say l2ffff 2ffff: 1 is added automatically, but only to the bottom 16 bits which rotate over from $FFFF to $0000, leaving the leading "2" unchanged, for a complete address of $20000 -- exactly what we want.

The next challenge was how to tell Kickstart not to initialise the SD card, but instead to just launch the loaded ROM.  My simple solution to this problem was to add two consecutive instructions just before SD card initialisation would occur:

  BIT go64
  BIT $1234

where go64 is the label in the assembly language of the routine to launch the loaded ROM.  The monitor_load program searches for this signature, and changes the first BIT instruction into a JMP, so that it becomes JMP go64, thus exiting to the loaded ROM, without worrying about the SD card.

With this change in place, there is really very little for Kickstart to do, and it does it so quickly at 50MHz, that you don't even see the MEGA65 kickstart screen, before it drops to C65 mode, as can be seen in the following video:


video

What is also really nice is that the whole process takes only a few seconds.  You can see that the FPGA fires up in a couple of seconds. Much of the rest of the time is waiting for the monitor to wake up from sleep.

Combining this with the existing ability of monitor_load to load and automatically run a program in C64 mode (and C65 mode would not be hard to add), it is possible to execute a single command that loads the bitstream, kickstart, C65 ROM and program of choice, and sets it running -- all in less than 10 seconds, as can be seen in this video:

video

As usual, the curious can checkout the source code on github.

(Also, for the curious, the strange program that runs in this video is an old test of the hardware-accelerated proportional text mode that the MEGA65 has.  This little program takes a UTF-8 text file, and renders the variable width glyphs in text mode, which makes it both fast, and very memory efficient, as repeating the same character re-uses the glyph memory.) 

For Falk and the machine without a working SD card, the next challenge is to provide remote control of the floppy controller, so that D81 disk images can be used, without having to load them on the (in his case, not working) SD card.

The ability to automatically trap to the hypervisor already exists, and it is now a case of writing the trap code in Kickstart, and modifying monitor_load to interface to it, so that a disk image can also be specified when starting the machine, and knowning that all disk access will be redirected to it.

With that in place, the ongoing development of the MEGA65 version of GEOS will hopefully be able to proceed very quickly, with no inserting of SD cards required.

And it shouldn't take too much effort to make the disk virtualisation code, because we already have the tools to iterate on the Kickstart firmware very quickly, through monitor_load itself.

Tuesday, August 1, 2017

Getting 1080p 50Hz working ... using a video mode editor written in BASIC v2

One of the joys of the MEGA65 project is that it is all about doing something that is not grounded in conventional measures of wisdom or practice -- at least none invented since the 1980s.

One of the TODO items for a while now has been to get 1080p at 50Hz (for PAL) and 60Hz (for NTSC) video modes working, ready for the move to HDMI on the new MEGA65 mother board.

This has been a bit of a drawn out process, partly because of everything else I have going on, and partly because I didn't have the tools to quickly and easily test and move forward.  That latter problem has now been substantially improved on several fronts:

1. The monitor_load program makes it easy to try a new bitstream and/or Hypervisor ROM on the MEGA65, without having to fiddle about with SD cards.

2. I now have a native Linux machine, so that I don't have to muck about with transferring bitstreams and source back and forth in and out of a virtual machine on my mac.  It also means that synthesis is a bit faster, without the overhead of the virtual machine.

Together, those two things, while not particularly ground shaking, have made a huge difference to what I can achieve in the little puddles of time I have.

The next step today was to implement a monitor_save program, that lets me save whatever is loaded in C64 mode, even if the program is running. This isn't a freeze function, but rather just saving BASIC program memory.  This makes it easy to work on a BASIC program on the MEGA65, saving it as I go along.

So now I had the means to save and load a program from my Linux box from and onto the MEGA65 in a second or two, as well as build and try out new bitstreams quickly, thus allowing me to do even more in the limited time available to me.

Back to 1080p video modes, I have worked over the past week to make VIC-IV registers at $D072-$D07C that allow complete control over the VGA video signal generation, so that I could try out various mode lines, with a view to generating the 1080p modes.

I also found out by accident that one of the VGA monitors at work is totally happy to do very low frame rates, down to and below 50Hz.

Now I was set, I had the tools to allow me to write a simple program to try out and modify video parameters on the MEGA65, to tweak them for proper video image placement and timing.

One of the joys of the C64, is that it contains a powerful and simple programming language out of the box, i.e., BASIC. While BASIC v2 is a bit minimal, it is totally functional, so I started hacking away on an interactive video mode line explorer.

Within an hour or so, I had not only a functional video mode editor, but had also worked out the correct parameters for 1080p 50Hz,  1080p 60Hz, and 1200p 60Hz, all using a fixed 150MHz pixel clock.  Here are some screen shots of my program in the various modes, and as I was testing them on the monitor:


First we have 1080p @ 60Hz. The BASIC program calculates a rough estimate of the horizontal and vertical frequencies of the mode. The letters and numbers in  brackets let you adjust the value to the left by -10, -1, +1 and +10 respectively.  If you look carefully you can see the bit of letter-boxing, because this monitor is actually nativelly 1200p.


Then a ~50Hz mode as I was trying to figure out a good 50Hz mode, and checking what the monitor thought of the mode.  This monitor, while nice for such funny modes, is a pain to get it to show the current mode. You have to navigate through quite a few menus to see the current mode info.

 And 1920x1200 @ 60-ish Hz.


In that mode in particular we can see that the scaling of the video imag is not correct within the borders. This is one of the next things on the list to fix.  It isn't hard, as the VIC-IV already has the necessary scaling registers.

Meanwhile, for the curious, here is the BASIC listing of the program I wrote to let me tweak and fiddle with the video modes, as output using petcat -2

   10 k=53295
   20 pokek,asc("g")
   30 pokek,asc("s")
   40 poke0,65
   50 r0=53248+7*16+2
   60 poke650,128
   70 poke53280,6:poke53281,11
  100 rem default mode values
  110 ss=2290:se=100
  120 fh=1072:dh=1056
  130 fw=2432:dw=1920
  140 fp=128
 1000 printchr$(147);"{wht}mega65 video mode editor"
 1010 print
 1020 print"hsync start=";ss;"  (a,s,d,f)"
 1030 print"hsync end=";se;"  (q,w,e,r)"
 1040 print"front porch=";fp;"  (z,x,c,v)"
 1050 print"frame width=";fw;"  (t,y,u,i)"
 1060 print"display width=";dw;"  (g,h,j,k)"
 1070 print"frame height=";fh;"  (1,2,3,4)"
 1080 print"display height=";dh;"  (5,6,7,8)"
 1900 print"hfreq = ";150000/fw;"khz"
 1910 print"vfreq = ";150000000/fw/fh;"hz"
 2000 poker0+1,se/256
 2010 poker0+2,seand255
 2020 poker0+10,ss/256
 2030 poker0+9,ssand255
 2040 poker0+0,fp
 2050 poker0+3,dwand255
 2060 poker0+4,fwand255
 2070 poker0+5,int(dw/256)+16*int(fw/256)
 2080 poker0+6,dhand255
 2090 poker0+7,fhand255
 2100 poker0+8,int(dh/256)+16*int(fh/256)
 3000 geta$:ifa$=""goto3000
 3005 printa$
 3010 ifa$="q"thense=se-10
 3020 ifa$="w"thense=se-1
 3030 ifa$="e"thense=se+1
 3040 ifa$="r"thense=se+10
 3050 ifa$="a"thenss=ss-10
 3060 ifa$="s"thenss=ss-1
 3070 ifa$="d"thenss=ss+1
 3080 ifa$="f"thenss=ss+10
 3090 ifa$="z"thenfp=fp-10
 3100 ifa$="x"thenfp=fp-1
 3110 ifa$="c"thenfp=fp+1
 3120 ifa$="v"thenfp=fp+10
 3130 ifa$="t"thenfw=fw-10
 3140 ifa$="y"thenfw=fw-1
 3150 ifa$="u"thenfw=fw+1
 3160 ifa$="i"thenfw=fw+10
 3170 ifa$="1"thenfh=fh-10
 3180 ifa$="2"thenfh=fh-1
 3190 ifa$="3"thenfh=fh+1
 3200 ifa$="4"thenfh=fh+10
 3210 ifa$="5"thendh=dh-10
 3220 ifa$="6"thendh=dh-1
 3230 ifa$="7"thendh=dh+1
 3240 ifa$="8"thendh=dh+10
 3500 ifss<0thenss=2999
 3510 ifse<0thense=2999
 3520 iffp<0thenfp=255
 3530 iffw<dwthenfp=dw+1000
 3540 ifdw<640thendw=1920
 3800 ifss>2999thenss=0
 3810 ifse>2999thense=0
 3820 iffp>255 thenfp=0
 3830 iffw>3000thenfw=dw+50
 3840 ifdw>1920thendw=640
 3850 iffw<ssthenss=fw-10
 3860 iffh<480thenfh=1500
 3870 ifdh<480thendh=fh-10
 3880 iffh<dhthenfh=dh+2
 3890 ifdh>1300thendh=480
 3900 iffh>1300thenfh=480
 4000 goto1000