Old news (July 09 - Dec 09)

From Spectrum hardware wiki
Jump to: navigation, search

Bit 3 of 0x7FFD

I thought it would not be possible to shoe-horn anything more into the CPLD after putting the three flip flops needed to monitor the border colour...

However, I decided to give it a try - this time to save bit 3 of port 0x7FFD. This port is used by the 128K Spectrum to select which memory pages are paged in (which ROM, and which page of RAM at 0xC000), plus the bit to "lock" it in 48K mode, and one bit - bit 3 - which selects between the screen memory being in its usual place at 16384, and being in page 7 of RAM.

Bit 3 is the only one that can't be detected by software. It's possible to figure out which memory page is in use in 0xC000, by saving a little bit of it, putting something recognisable (for example, a string like "Spectranet snapshot") in that location, then paging through all 7 pages until you find the string that you put there. Similarly, the ROM page can be detected by copying a small routine to main RAM (and copying the existing contents to Spectranet RAM) - this routine looks at the currently paged ROM, and determines which one it is. But there's nothing you can do to actually tell which screen is in use, the normal one at 16384 or the 128K-only one in page 7. You could ask the user ("Press A if you see this" in 16384, and "Press B if you see this" in page 7), but it would be very clumsy.

My first attempt at adding the one extra flip flop that would be necessary didn't work, sure enough, it didn't fit. But while looking at the CPLD design, I saw that there's one address line going spare. The CPLD has address lines A12-A17 (plus four chip select lines) that allows you to have memory chips up to 256K. However, 128K chips are in use, and I don't think A17 is even routed on the Spectranet's PCB. So I deleted the A17 line.

Surprisingly, this freed up 2 macrocells (probably by reducing how much needs to be routed - more than the circuit itself, it's only simple combinatorial logic that brings A17 out to a pin), and allowed the circuit to monitor bit 3 of port 0x7FFD (actually, A15 = 0 and A1 = 0, the Spectrum only does very partial port decoding) to fit into the CPLD.

It's still a tight fit (the fitter has to make three or four iterations while attempting to fit it in the device) but at least it fits.

Winston 14:41, 15 November 2009 (GMT)

128K snapshots

With the 48K snaps working to my satisfaction - the next step, do the same for 128K. Once again, I'm starting with the .SNA format, since it's simple and what the Spectranet will be using to save.

48K snapshots are very simple. They were originally made by real hardware (the Mirage Microdriver), and so are inherently suitable for other real hardware. 128K snapshots came with the emulation era. In a misguided attempt to make them compatible with 48K snapshots (so if a loader that only knew 48K snapshots encountered one, it would still load OK), there is some awkwardness. Like a 48K snapshot, there's a 27 byte header followed by 48K of memory data. However, the last 16K of this has to go into 128K paged memory. The trouble is, the second "header" - let's call it a "stomacher" because it comes sort of in the middle of the file - is 4 bytes long and comes after the first 48K of memory data - and you have to actually read it to know where to load the last 16K of that 48K block that came before it. The trouble is 48K compatibility is broken in the 128K snapshot format because the stack doesn't have the address to return to on RETN - so there was actually no need to organize a 128K snapshot in this manner at all.

What this means is this. The header, then the first 32K of the snapshot is loaded. Then you have to seek forwards 16K and load the "stomacher", the 4 bytes which contain the program counter, the value of port 0x7FFD and a byte that indicates whether TR-DOS is paged. Then read all the other pages into RAM, 16K at a time. Then seek again - backwards - to 32K+27 bytes, set the value of port 0x7FFD to what the snapshot says it must be, then read the 16K block that lives in 0xC000-0xFFFF. Finally, the snapshot can be started.

My first full test (once I had cleared the "not enough caffiene" bugs out of the code) was to load "Escuela de Ladrones" in Fuse, make a snapshot, and see if it would load OK - play it, and make sure nothing odd happened. And it works fine. I need to do some more detailed tests, but first I'll get 128K snapshot saving done.

Winston 20:14, 7 November 2009 (GMT)

Saving snapshots

A couple of weeks ago, I implemented snapshot loading. A pre-requisite for snapshot saving was to fix the NMI problem, once that was out of the way, I could go forward with snapshot saving. Again, so far, just 48K snapshots have been implemented. The stress test so far was to save a snapshot while playing Exolon, so I could skip the boring bits (the first 7 or so levels)...

There's a number of interesting things about making the Spectrum be introspective about its state. There are a number of things that cannot be read directly - most importantly for us, interrupt mode and whether interrupts are actually enabled. To find this out, what has to be done is this: use the RETN instruction to restore IFF1 (i.e. restore interrupts back to the state they were when the NMI button was pressed), then... wait.

To detect interrupt mode 1, I have a delay loop that lasts long enough that at least one interrupt happens. The Spectranet ROM has an interrupt service routine at the normal place - all it does is update a counter, just like the FRAMES sysvar which the main ROM ISR keeps updated. The counter gets reset, then the delay loop runs, then the counter is examined. If it's nonzero, we know interrupts are enabled and we are in IM 1. Also there is another interrupt service routine for IM 2. To make this work, a vector table is created in Spectranet RAM. If the IM 2 ISR is called, it sets the appropriate value in the snapshot header that's being built. If we see IM 2 set in this byte, then we know interrupts are enabled and we are using IM 2. (IM 0 can't be used on a standard Spectrum - I don't test for it at all, indeed, IM 0 would present quite a few difficulties on a Spectrum).

Of course, it's entirely possible that interrupts are actually disabled. So if we've not detected IM 1 or IM 2, we know interrupts were disabled. At this stage, the IM 1 and IM 2 tests are run a second time, but interrupts are explicitly enabled with EI.

Then the state can be saved to the filesystem, then it all has to be restored, and the NMI routine finally exited back to where we were.

I wrote a couple of small test routines to make sure the snapshot code was working correctly (and help discover what bugs I had put in the code!) - these were just simple short programs to show that all the register values were correct, and that the interrupt mode remained as it should have been. Much more needs to be developed - the issue of 128K snapshots, the ability to load .Z80 as well as .SNA. I also need to think about whether I want to put the snapshot code in its own module or not (at the moment it lives in the BASIC extensions module, owing to the %loadsnap command living there). Additionally, some kind of sane snapshot management on the lines of the ResiDOS task manager so that snapshots are easy to use outside of BASIC. I also need to see whether I can shoe-horn three flip flops into the CPLD to allow the border colour to be detected - the only way of knowing the border is to monitor output to port 0xFE.

  • Edit - I got the shoehorn out, and yes, the three flip flops did fit. Just! So the correct border colour is saved in the snapshot, too.

Winston 22:55, 3 November 2009 (GMT)

A session of hardware debugging

Error creating thumbnail: File missing
Debugging the NMI problem - JTAG leads and two scope probes connected

To cut a long story short: the problem of multiple NMI triggering that I wrote about yesterday was caused by the CPLD falsely decoding an NMI instruction.

The longer version: I spent about three hours this evening banging my head against the problem. There were multiple things over which to bang my head: lack of resources remaining in the CPLD and simple solutions that should work not working. I decided to make the Spectranet generate the NMI signal like the DivIDE does - keep NMI low until the next instruction fetch after the NMI. That should have been fine, but it took a lot of rejigging things to be able to get one more flip flop on the CPLD. I sacrified the read of the status bits that I've never actually found it necessary to read. Then after exhaustive fitting by the Xilinx ISE fitter (that took long enough I managed to watch a half hour TV programme while it was running), it didn't really work. The second flip flop, theoretically at least - could only be triggered when an NMI event occurred, but it seems that it could latch sometimes in the chaos of power up (even when explicitly held in reset while the Spectrum's reset was active... but you don't have to scroll down far to find out the realities of the verrrry sllooooow rise of the Spectrum's reset signal, and the problems it caused me).

After many iterations of this, I came up with something that should have worked, but in fact guaranteed a double NMI triggering. It made no sense. However, putting the 'scope on a fairly long time base (1 millisecond) showed what was happening - it really WAS double triggering. On a hunch, I stopped RETN from resetting the "I'm in an NMI right now" flip flop (whose purpose is to prevent double triggering of the NMI by switch bounce) and lo and behold, no double NMI.

I looked at the RETN decoder. It certainly looked right - decode the M1 cycle, then the other half of the instruction. Theoretically, nothing but RETN could trigger it.

Then I thought - why am I bothering to decode RETN anyway? Why not release the flip flops when we unpage? I couldn't think of any reason.

So I deleted the entire RETN decoder. I also deleted the bits that was giving an NMI pulse until M1, and went back to the old behaviour. Now it works perfectly, and I've freed up a whole heap of CPLD resource (well, perhaps not a heap, but enough that I could put some new, useful function in the CPLD that I may want in future). And it proves for certain that yes - there must have been an NMI signal bounce, and the Z80 that I have is behaving how the manual says it should. Who cares why RETN was being decoded when it shouldn't - that circuit has ceased to be. (Actually I am very curious on why the same code and the same CPLD did not get false RETN decodes on the +3, but did on the rubber key machine).

Later, I remembered why the RETN decoder was there - in the first incarnation of the NMI menu, it used the Spectrum keyboard scan/key decode routines by calling them in the Spectrum ROM, and had to unpage to do that, well within the time the NMI switch could still be bouncing as the user's finger leaves it. So the NMI event latch needed to remain set while the ROM routine was called, so instead of being reset by pageout, it was reset by RETN. However, problems with doing this on a Spectrum +3 meant that I put the key scan routines into the Spectranet ROM, so the NMI menu hasn't called any Spectrum ROM routines in quite a while.

As for the strongest candidates to put into the CPLD - the interrupt functions that were dropped, perhaps (the W5100 interrupt line is connected to the CPLD, but it isn't even made available to a status register read, owing to the lack of CPLD resources).

Winston 20:04, 31 October 2009 (GMT)

Another hardware bug found...

Or at least, certain "bad interactions" with some Z80 processors.

Error creating thumbnail: File missing
Spectranet NMI - goes low and stays low until RETN
Error creating thumbnail: File missing
DivIDE NMI - goes low until (probably) the subsequent M1 cycle

It started last week. I'm beginning to implement snapshot saving, and I just wanted to sanity check things (make sure the NMI button didn't crash games, and that kind of thing). And...it did crash games. It even crashed Manic Miner. Since the NMI button only (is supposed to) result in one new entry pushed onto the stack - which is unavoidable - it shouldn't crash Manic Miner, which doesn't do anything particularly fancy and is not tight on stack space.

First, I investigated the software. No problems found - I wrote a little test to do a "before" and "after" register test, to make sure no registers had been disturbed - none had. I looked at the code, and couldn't see anything that would cause a crash on NMI return. However, I noticed one curious thing - there would be a noticeable delay before the NMI menu came up (on the order of 1/4 second or so) at times when Manic Miner was running. Occasionally, I saw the NMI menu half paint, the screen clear, then the NMI menu repaint. That to me said an obvious double (or more) triggering. The really odd thing was it hardly ever happened when sitting in BASIC, or running a program to try and test the conditions before and after NMI. However, with a game loaded, multiple NMI triggering would happen all the time.

Fortuitously, I had managed to obtain a digital storage oscilloscope. It arrived yesterday. So the first real use of the new scope - see if the NMI signal was "bouncing" and causing multiple NMIs. First, a bit of background to how the Spectranet makes an NMI - basically, when you hit the switch, there's some debounce logic in the CPLD (which is very, very simple - basically a flip flop that goes low until the CPLD decodes a RETN instruction). The output of this flip flop is an open drain pin on the CPLD, which pulls down on the NMI line on the Spectrum. The Z80's NMI is level triggered, and it should not trigger again until the NMI signal has returned high. What I guessed was happening was that the NMI was going low and then "bouncing", instead of staying at 0v, perhaps crossing the logic 1 threshold of the Z80 numerous times before settling. However, within seconds of connecting the new 'scope, that was proven to be unequivocally untrue - the signal was as perfect as can be. (See the picture to the top right). I decided to have a look at the DivIDE, and see what its NMI signal looked like, since I hadn't heard any complaints about crashes being caused by the DivIDE's NMI button. Sure enough, it gets returned back to a logic high level. I suspect the M1 cycle subsequent to the NMI being triggered probably resets the DivIDE's NMI output (it resets between 15 and 23 T-states after being asserted). You can see the NMI output of the DivIDE in the picture on the bottom right.

The upshot of this is I've got to squeeze more logic into the already pretty full CPLD to reset the NMI output but do it in a way that it can't be reinvoked until the RETN instruction has been seen on the bus. And again, the reason I had never seen this problem is because it's not a problem on the Spectrum +3. I can invoke the Spectranet's NMI as often as I like while playing Manic Miner, and it never crashes - so obviously, different Z80s behave a bit differently to an NMI signal that's held low for a long time.

Winston 21:30, 30 October 2009 (GMT)

Snapshots

A feature that I found would be important at RetroReunited (on talking to a few other people) is the ability to snapshot - to be able to load and save snapshots to a filesystem.

To start, I've done the easy one - load from a 48K .SNA file. Surprisingly, this worked first time. There's a BASIC command to do it now, named %loadsnap. (Ultimately, it'll detect the kind of snapshot, and do the right thing). For loading, I intend to support at least 48K and 128K .SNA files, and probably .Z80 files too. For saving, I'll just support .SNA because it's the most straightforward to support, and should do the job fine for nearly all uses.

This also requires an overhaul of the NMI menu. Snapshotting will be done from the NMI menu as you'd expect, but it's going to be done from a module. Currently the NMI menu is hard coded in the utility ROM. What it needs to do is to go through all the ROM modules, to see if they have an NMI action (in which case, print an string and allow a jump to the address of whatever routine will handle the NMI).

Incidentally, as for the next "Spectranet World Tour" event, I'm already planning for the Vintage Computer Fair, which will be held at the historic Bletchley Park next June. I intend to have a LAN of at least 4 Spectrums set up and running, plus the VAX fileserver I had at RetroReunited.

Winston 18:55, 25 October 2009 (GMT)

Making streams usable

After much work here and there, BASIC streams support now is a bit more worthwhile. Not only does it support TCP sockets, but now also reading/writing files on a file system, as well as reading directories. A brief summing up of what's been done to make streams into something practically useful:

  • Bug fixes. The TNFS module wasn't freeing up file/directory descriptors on close (whoops!)
  • Better memory management in the streams module itself (of the memory allocated by BASIC's MAKE-ROOM routine)
  • File and directory support
  • Lots and lots of testing!

Supporting files and directories, is I think quite a big thing. It means the BASIC programmer can take advantage of any filesystem module that's written - for instance, write a HTTP filesystem, and BASIC can use it. Write an FTP filesystem, and BASIC can use it. Write an IDE filesystem for an attached DivIDE, and BASIC can use it - and no programs have to be modified. This of course was the original intention of streams in the BASIC ROM, but the support was never finished back in the day. I hope the Spectranet can show the true beauty of what was actually intended back in the day.

There are other things I need to support, and I want to try and support without a proliferation of BASIC extensions, by means of streams. I still need to write a control stream which can be opened to find status of other streams. The syntax of INPUT# is actually quite handy for this kind of thing. For instance, imagine we have a stream that can stat (find information) on a file. A line in BASIC could be written as such to use a control stream to do this. Imagine the "stat" command returns the size in bytes, followed by the type of file, followed by the permissions...

INPUT #4, "stat /path/to/some/file";size;t$;p$

(It's a pity that BASIC only allows single characters for string variable names).

The other thing that I've made streams support is EOF (end of file) handling not by returning an error to BASIC (which makes your program bale out with the unhelpful error '8 End of file', at which point your program has stopped and left all the channels open...) The usual idiom in a language like C for reading a file or something you fully and correctly expect to stop reading at EOF looks something like this (in C-like pseudocode):

filehandle=fopen("/path/to/file", "r");
while(data = read(filehandle))
{
    do_stuff();
}
fclose(filehandle);

And handily, when we hit EOF (or some other error condition) the while loop exits, and we get to close the file handle and do whatever else we need to do. Normally, Spectrum BASIC does not allow this - you just end up fallling over with 8 End of file. However, Spectranet streams support now allows you to at least do this - using the %oneof (on end of file) command:

 10 %fopen #4,"filename","r"
 20 %oneof 100
 30 INPUT #4;a$
 40 ...do something ...
 50 GO TO 30
100 %close #4

As a demonstrator and aid to testing it works as I meant it to, I wrote a small games menu program. It reads a list of games and their filenames from a file, then allows you to press a key to launch whichever game you choose (the game, of course, is in a .TAP file). This also brought up a few other issues...

The most significant is that when you %fopen (or %connect or %opendir or whatever) a stream is that some memory must be allocated to store the stub that makes a call into the Spectranet streams module to actually do the work. Memory management in the ZX ROM is fairly basic, to say the least - you can call MAKE-ROOM to make some space somewhere (for streams, just below the BASIC program itself in memory), and RECLAIM-1 to free that memory. However, I can't just call RECLAIM-1 whenever a stream gets closed without a great deal of shuffling stuff around - and the other complication is that if someone else has done a MAKE-ROOM, my code won't know about it. This means calling RECLAIM-1 automatically when a stream is closed something that may tread on someone else's code. So at the moment, the Spectranet streams module just keeps a note of what memory it has allocated, and tries to reuse it (for instance, if you open a stream and close it, RECLAIM-1 doesn't get called, but the streams module knows it allocated space for the stub, so the next time you open a stream, it just reuses this already allocated space for the new stub). Instead, if the programmer wants this room reclaimed by the ZX ROM, they explictly need to tell the streams module to do it. The programmer, after all, is the only person who will know if they did other non-Spectranet streams stuff there. Most of the time, the room will never need to be permanently reclaimed. But there are instances where it's essential.

In the case of my games loader, if you don't actually reclaim the room - many games just won't load - they die with "M RAMTOP no good" when they try CLEAR xxxxx. So, when a game is selected in my BASIC game loader menu, the command:

%reclaim

is executed, which makes the streams module deallocate all memory from the original value of PROG to whatever the latest value of PROG was when it made the last call to MAKE-ROOM.

What's next? Probably a poll stream (in which you can do INKEY$# without actually reading off a character, which will tell the programmer which stream has stuff ready to read), and a control stream to allow other more complex things to be done with INPUT#. I also intend to make a video this weekend, showing what's been done so far.

Winston 20:55, 20 October 2009 (BST)

Improving tape emulation

A while back I added tape traps to the Spectranet, meaning you can put a TAP file on a network filesystem, and load it. It's similar functionality to what the DivIDE has, and what is available in ResiDOS, except you're loading a TAP file over the network rather than directly off an IDE device.

I decided "wouldn't it be nice if there were a default file", so if you just typed LOAD "", it would load this file. So I added this - typing LOAD "" will try to load a file called "boot" in the current directory. The file "boot" is a TAP file (just because it doesn't end in .TAP doesn't mean it's not a TAP file!) - because the format of files saved using the %save command is TAP - it's how the metadata associated with a file is stored. (I made the standard file format be TAP because then it makes it easy to transfer files from a Spectrum to an emulator and vice versa. And TAP holds all the information that's needed).

So what you can do is this. You can write something like a menu in BASIC, and %save it as "boot". Then when you type LOAD "", it'll load this BASIC program. Or, on a 128K machine you can use the Loader. (This unfortunately doesn't work on a +3 or +2A owing to the different way they arranged the ROMs).

The idea of this is what I learned by watching people at RetroReunited - if they reset the Spectrum, they'd always do something like bring up the loader or type LOAD "" expecting something to happen. So I decided something ought to happen if you did do that!

Then there were a couple of bugs - well, not bugs so much, but problems with certain games. For example, Starstrike and Skool Daze do something different to many games - and if you've loaded them off tape you'll know that after the SCREEN$ image loads, they don't then start loading another block - the loader simply continues until the game is loaded. What happens, though, is the stack gets overwritten by the tape loader. With a real tape, this is harmless - the right return address got written by the tape file, so when the ROM loader returns, it goes to the right place. (Perhaps an address set up in the tape data itself). But when the tape trap fires, it's a programmable trap and enters via the NMI - and a whole lot of registers get pushed onto the stack. Additionally, the Spectranet replacement for the main rom's LD-BYTES routine (which would normally be loading the bytes off tape) needs to use the stack. Plus the original value of the Spectranet page B register is on the stack. Generally, this means bad things happen when the stack gets overwritten by the TAP file that's being loaded.

The solution: make the NMI routine's stack live in Spectranet RAM. This way, it can't be overwritten this way. Now both Starstrike and Skool Daze load just fine (as well as probably a heap of other games).

However, I did run into an interesting problem I should have thought of - especially as I actually documented it on the wiki when I first added programmable traps! The layout of the ROM got shuffled around a little bit, and this meant the default trap for LOAD "" actually caused a trigger in the Spectranet ROM, because code now happened to execute at the same address as LD-BYTES in the main ROM. So I added a little extra logic to the CPLD to disable traps while the Spectranet ROM is actually paged. As a workaround for users of the other prototypes, I can probably find the right combination of NOPs to make the ROM not hit this address.

Winston 21:19, 29 September 2009 (BST)

The Analogue World

For a great deal of time, I've been doing everything with the Spectranet on my +3. There's a couple of good reasons for this: first, it has RGB out (and all my UHF only Speccies have serious modulator drift problems), and secondly, the floppy disc drive makes it easier to reload the Spectranet ROM if I bork it. (Otherwise, it must be loaded through the tape port while I hold the DISABLETRAP connection at 5v by hand...)

But I got given a Spectrum+ last weekend, and it turns out it has a good modulator (it still drifts, they all do) but it gives good colour output on my TV. But I just got the "pixel vomit" screen when I tried to use it with the Spectranet. I had the same problem with an issue 4 board with the composite mod earlier, but I had put it down to a dirty edge connector. So I tried it on more machines, pixel vomit on all of them except my Issue 2 Spectrum. Which, once warmed up for a few minutes...also gave pixel vomit.

There was obviously some problem with initialization. First, I checked the Spectrum had actually come out of the RESET state by checking the voltage of the RESET line, it was indeed 5 volts. (The Spectrum's RESET circuit is very high impedance, and the CPLD will prevent it from working at all, so it's buffered before reaching the CPLD). I checked various other things, checked that the clock signal was present (recently, I made changes to the clock circuits in the CPLD), I checked that the voltage was adequate, and everything obvious. Then I started up Xilinx ISE and started going through the CPLD design.

One thing I had in mind was the slowness of the reset circuit on these machines - it's just a simple R/C circuit, and I had thoughts that perhaps it was possibly resulting in a bit of "jitter" in the CPLD as the voltage passed through the threshold oh so slowly. I tried all sorts of things to eliminate them - they'd always work the first five or six times (solved it! I thought each time...), but then would inexplicably fail. (As the Spectrum warms up, the R/C reset circuit gets slower). The one place I didn't think to look after banging my head on the table for two days was the memory paging registers in the CPLD. I had forgotten they get reset too (they don't actually need to be reset), and didn't even look at that part of the circuit - until out of complete frustration I had deleted the entire RESET net in the CPLD...

What is happening is the RESET level reaches the Z80's logic high threshold long before it reaches the logic high threshold for the 74HCT1G125 buffer, which feeds the CPLD's reset input. So the CPLD is being held in reset for quite a long time after the Z80 starts running - at least 100,000 T-states! The best fix is to just get rid of the reset circuit from the memory paging registers, but with a few Spectranets already out there with people who don't have the kit to program the CPLD, well, a huge delay loop in software was the pragmatic approach to take. And of course, now it works perfectly on all my Spectrums.

Winston 20:20, 26 September 2009 (BST)

At long last, addressing +3 BASIC

The Spectrum +3 brought some good enhancements to the world of the Speccy (even if a bit flawed - oh for a 3.5in disc instead of the unusual Amstrad 3in unit), but also some irksome compatibility issues. Not only is it incompatible with any peripheral with a ROM which wasn't +3 aware (i.e. anything designed before the +3) due to the change in the edge connector, but the other problem is the way the BASIC interpreter in 128K mode breaks with what happened with the toastrack 128 and the grey +2. In those machines, all the BASIC interpretation was still strictly done by the original interpreter. But in the +3, some work is done in a different ROM - including the RST 8 error handler.

So when you trap an error to extend BASIC, it suddenly doesn't work even though you've made your device electrically compatible with the +3.

I want the Spectranet to smoothly support all of the original machines - that is the rubber 48K machine up to the +3, and anything with a compatible edge connector and compatible ROMs. I want it to smoothly support +3 BASIC as well as 128K BASIC without forcing USR 0 mode.

This is how I'm going to do it.

On power up, the Spectranet will find out whether it's on a machine with the +3 ROMs. This can be done by looking at the first 6 bytes of ROM 1, which contain the string "Syntax" on a +3. It will store this in a Spectranet system variable (i.e. in the 0x3F00 system variables area in the Spectranet's own static RAM).

When the error trap fires, it'll see if this flag is set, and if so, will check to see whether we're in USR 0 mode or in 128K BASIC mode. This can be done by checking for the presence of the paging routine, which is kept where the printer buffer used to be in RAM. USR 0 mode and 48K mode wipes this routine out - so we can use this to tell that we're in 128K BASIC. If we are in 128K BASIC, ROM 3 (the original syntax ROM, and where the ROM routines that the Spectranet BASIC extensions use) will be paged for the duration of the BASIC extension, then restored when we exit, either due to successful completion or some sort of error.

I suspect I'll hit some bumps in the road while doing this (I hit a few while writing the detection routine yesterday). But the upshot of this is that BASIC support for all the machines should "just work".

Also, this week, I've implemented the "default file" concept. If you type LOAD "", it will load the first BASIC block it sees in a file named "boot" in the current working directory (TAP format, as the Spectranet's BASIC filesystem support uses TAP as its container format). This even works with the 128K Loader. What it's doing is trapping the tape loading routine and opening the file "boot" if it's present, and then setting up normal tape traps to load this TAP file. The upshot of this is that the next retro party I go to, it'll be really easy for people to just load stuff over the network - just LOAD "", or on a 128K machine, select the Loader, and away you go. (I'll write a little menu program in BASIC for navigating to the various programs).

Winston 19:55, 17 September 2009 (BST)

The Spectranet world tour continues!

Error creating thumbnail: File missing
Spectranet setup at Retro Reunited, with the VAX fileserver

First Oxford, then Bilbao, now Huddersfield!

The Spectranet was on show (with all the latest code enhancements) at Retro Reunited, on the 12th/13th September. The Speccy was paired up with a MicroVAX as a fileserver. (The VAX was also the DNS and DHCP server, unfortunately the hotel had no "wider LAN" with these things, nor an internet connection other than WiFi. I could have set up my old PowerBook to be a router on WiFi, but owing to a shortage of TVs, I only had one Speccy on the network so decided to show off the network filesystem rather than the IRC client!)

Which brings me on to more recent developments.

Since the last update, I've added more code to the BASIC streams support, so you can now write a server program in ZX BASIC. Also, I've made the mount command for mounting filesystems MUCH better - instead of passing half a dozen parameters, which was rather clumsy, you now supply just two - the mount point, and an URL for the filesystem you want to mount, in the usual format - proto://user:passwd@host/some/path . The default protocol at the moment is TNFS, so if you just specify an IP address or hostname, it does an anonymous TNFS mount of the root on that host.

Also, I've now added the ability to mount more than one filesystem at a time - up to four filesystems can be mounted simultaneously. If the filesystems are TNFS, then only one network socket is used for the lot, since TNFS is a very low resource UDP protocol.

What was clear from Retro Reunited is that one of the priority developments for the BASIC module is to add a "default" file to load (this will of course work with the Loader on 128K machines). Of course, people just casually playing stuff - for example, at a show like this, may just want to start the Speccy and have it load a menu of games. The other big feature I think people would like is the ability to save snapshots to a filesystem - a bit like the Multiface - hit the NMI button, then save a snapshot to any of the mounted filesystems.

Winston 22:11, 14 September 2009 (BST)

RetroEuskal, and BASIC streams

No updates for about a month, but I've been a bit busy!

First, I had the grand challenge of demonstrating the Spectranet at RetroEuskal - held inside Euskal Encounter (the second largest LAN party in Spain, with 4096 network ports - most in use). Fortunately, the DHCP client worked fine with the Euskal Encounter DHCP servers, and braved a very busy network segment with vast quantities of broadcast traffic (mostly DHCP requests and ARP who-has requests). The demonstration went well, and people even seemed to understand my undoubtedly heavily accented Spanish...

Secondly, one of the things I'd been working hard on so that I could demonstrate it at RetroEuskal was BASIC streams. I got the prototype code done just in time, and tested it with things like an SMTP client written in ZX BASIC (yes! It worked!). So far, you can write TCP client programs in BASIC. Writing servers is going to take a bit more effort (it'll need a separate control channel so that you can peek at the state of things without reading).

It's now possible to write a program like this in BASIC:

10 %connect #4, "some.computer.com", 2000
20 INPUT #4;"Tell me> ";a$
30 PRINT "Remote computer said: ";a$
40 PRINT #4; "You said: ";a$
50 IF a$="q" THEN GO TO 100
60 GO TO 20
100 PRINT #4; "Bye!"
110 %close #4

Once accessability from BASIC and the network filesystem is done, basically, the base software is actually finished. The end is in sight!

On the hardware side, I'm thinking of getting some PCBs made, with the aim of making sure my modifications for "production" are good. There's one bug that had to be fixed (which won't affect normal users), plus I want to try and make a small mod to the routing of the ethernet traces from the magjack to try and get rid of a couple of vias, sometimes the W5100 has trouble getting a stable connection on reset, and I want to eliminate that from my enquiries. Also I want to put another jumper in so the user can select the voltage source for the 3.3v regulator - either the 5V from the Spectrum (works on all models), or the 9V (48K only) - the reasoning, to lessen the load on a rubber key Speccy's 7805 regulator.

Winston 21:33, 6 August 2009 (BST)

A whole lot of new excitement

Just over a week ago, you may have seen the news that the Speccy made its first tweet on Twitter. The client was hacked together in the Gloucester Arms in Oxford, over a pint of Black Beauty (you do get some odd looks with a Speccy on the pub table, but it was the CSS meet!)

But other than that, more exciting times: I've put together a basic automounter (it needs much more work to do what I eventually want it to do), so that filesystems may be mounted at boot/reset time. So the Spectrum can now be powered on, and you can immedately start using the network filesystem. Also, a comprehensive "%info" command has been added to the Spectranet BASIC ROM module which gives information on files. For generic non-Spectrum files (and directories) it just shows the basics, such as filesize (and I intend to show file mode too). But for Spectrum files (the native format being used is TAP), it lists the contents - so, if you have a complete TAP file for a game for instance, it'll show all the blocks that are contained in the TAP file. Also, for testing, I wrote a program in BASIC to give a game loader menu, and then load the game from a TAP file. I wrote it on a real Spectrum, and trusted the TNFS code enough to save it over the network!

There are some games that don't seem to load properly - I need to investigate whether this is just a +3 incompatibility, or whether there are bugs in the tape traps.

Other than that, I've fixed a couple more bugs that I discovered in the base ROM.

Next I want to add support for BASIC streams. (Andrew Owen will like that of course!) For the time being, I intend to add a few commands using the RST 8 trap for opening a socket - it has been suggested that a control channel can be used for sending commands, but that involves a lot of extra work and I'd like to have at least TCP client streams working to demo at RetroEuskal (now wouldn't it be nice to do a Twitter client in ZX BASIC!)

Winston 21:58, 7 July 2009 (BST)

Older News