Thursday, 6 August 2026
Asymptotic Wildfires
Tuesday, 28 April 2026
Shorter QL GetHead
A couple of days ago I wrote a blog post about being able to read QL executable file headers so that you can restore them from original QL applications on QL disks, onto a modern OS which lacks them when running a QL emulator.
https://oneweekwonder.blogspot.com/
It's actually fairly involved here, involving one SuperBASIC program to load a machine code hex program (and then save it on disk); then write another SuperBASIC program to load that code, which adds a couple of functions to SuperBasic. And to make it even more complex I ended up wrapping them with SuperBASIC procedures to make opening the channel so you can use the SuperBASIC extensions and then closing it at the end.
It turns out though you can make it much shorter, a single, simple SuperBASIC program:
100 DEFine PROCedure GetHead(fName$)
110 OPEN #3,fName$:CALL mcode,71,64,500,0,0,0,0,ChanId(3),buffer
120 PRINT "Len:";PEEK_L(buffer);" Dataspace:";PEEK_L(buffer+6)
130 CLOSE #3
140 END DEFine
150 DEFine FuNction ChanId(chan):LOCal a6:a6=PEEK_L(163856)+104
160 RETURN PEEK_L(PEEK_L(a6+48)+a6+chan*40):END DEFine
Saturday, 25 April 2026
Recovering Sinclair QL App DataSpaces
Recently I've been playing with a QL emulator again, because I found a printed copy of my third year Computer Science dissertation, and wanted to retype it in the default word processor, QUILL.
However, I couldn't run QUILL, because when the program was copied to my Mac's file system it didn't copy the header, which contains the data and stack space allocated to the program. And that's part of how the QL works, executable files contain meta-data providing this information and it gets lost on modern operating systems including Linux and Windows.
In theory, fixing it is as easy as reserving memory for the program (progCode=RESPR(sizeOfFile)), then loading the code (lbytes fileName,progCode), then re-saving it under a different name: (sexec_w newFileName,progCode,dataSpace). But this means finding out how much data space has been allocated for static data and the stack. And... this information isn't generally available, even though many QL owners have had to face the problem.
The nearest I got was a web site which contained a BASIC program which could tweak QUILL for a few features I didn't care about (see the section called QUILL Mod). But at the end it did sexec_w QUILL with an actual data space which worked. I was then able to use QUILL to type in the first couple of pages of my dissertation, which was fun.
This wasn't a solution for all the other programs I could run on my QL emulator, e.g. Forth79! Amazingly though I found an intriguing program on one of my QL directories on my Mac called: HeadRead_bas. This turned out to be a machine code program and hexloader for it, which would then save the machine code in a file. Could this be it? Here's the program:
140 PRINT 'loading hex..':endAddr=hex_load(start)
150 INPUT 'save to file';f$
160 SBYTES f$,start,endAddr-start
170 STOP
180 DEFine FuNction dec(h$):RETurn h$(1) INSTR "0123456789ABCDEF"-1:END DEFine
190 DEFine FuNction hex_load(start)
195 LOCal sum,addr
200 PRINT 'Data entered at:',start
220 sum=0:addr=start
230 REPeat load_hex_digits
240 READ h$:IF LEN(h$)<>2*INT(LEN(h$)/2) THEN PRINT "Odd Hex digit Count";h$:STOP
300 FOR b=0 TO LEN(h$) STEP 2
360 byte=16*dec(h$(b+1))+dec(h$(b+2)):POKE addr,byte
370 sum=sum+byte
380 addr=addr+1
390 END FOR b
400 END REPeat load_hex_digits
410 READ check
420 IF check=sum then print "Sum OK":else print "Bad Sum"
430 RETurn addr
490 END DEFine
500 DATA 144
510 DATA '43FA000A34790000','01104ED20002001E'
520 DATA '0747657448454144','0010075365744845'
530 DATA '4144000000000000','784660027847BBCB'
540 DATA '675A2A0D4BEB0008','3479000001124E92'
550 DATA '664C3031E80054AE','0058264D2A45C0FC'
560 DATA '0028D0AE0030B0AE','00346C2C2A360800'
570 DATA '6B26347900000118','4E9266225343661C'
580 DATA '2031E80008000000','6612204522407440'
590 DATA '766420044E434E75','70FA4E7570F14E75'
600 DATA '*',10007
The program doesn't read QL program headers, it just creates the machine code file you can then use in another program to read headers. And that program was elsewhere in the same directory too:
100 BUFFER=RESPR(64)
120 INPUT 'ENTER DEVICE:';F$
130 OPEN #3,F$
140 GetHEAD #3,BUFFER
150 PRINT F$;', ';PEEK_L(BUFFER);' BYTES'
160 PRINT 'LAST ALTERED ';DATE$(PEEK_L(BUFFER+52))
170 PRINT 'CURRENT DATA SPACE ';PEEK_L(BUFFER+6)
210 CLOSE #3
It loads in the machine code first. It turns out the machine code adds the command GetHEAD to BASIC. GetHEAD reads the header from a file at the given channel and stores it in an allocated buffer. Then we can look at offsets in the file for the actual size of the executable and the data space.
This solves part of the problem: I now had a program which could read the headers. However, all the reported dataspace values were reported as 0. Fortunately, I still have my real Sinclair QL and a floppy disk system which is still largely reliable! I could either look for the same BASIC programs on a floppy disk, or type it out by hand again. Indeed, the programs were on floppy disk too!
Now I was able to list all the data spaces for the executable files I had. It turns out that all the PSION programs for version 2.3 (though Easel is version 2.0) had a data space of 1280 bytes. So, then I could get all of them to work! Mostly I used QUILL and the Spreadsheet, ABACUS. I used the ARCHIVE database a bit and EASEL very little.
The rest can be summarised in this scrappy table:
Computer One Editor: EDITOR 12714 256
Computer One Linker:LINKER 4278 256
And Linker_A (??): LINKER_A 8616 4800
Debugger: debug_exc 2272 500
eda 13653 256
eye_q_dp 31476 43008
forth79 12616 57528
You might like to know what the assembly code for Header read is? I disassembled it using the Alan Giles disassembler written in BASIC. It's slow, about 1 or 2 lines per second but good enough for this.
3FF04 347900000110 MOVE.W $00000110,A2
3FF0A 4ED2 JMP (A2)
3FF0C 0002001E OR.B #$1E,D2
3FF10 0747 BCHG D3,D7
3FF12 6574 BCS.S $74(PC)=$3FF88
3FF14 4845 SWAP D5
3FF16 4144 DC.B 'A','D'
3FF18 0010 DC.B 0,16
3FF1A 0753 BCHG D3,(A3)
3FF1C 6574 BCS.S $74(PC)=$3FF92
3FF1E 4845 SWAP D5
3FF20 4144 DC.B 'A','D'
3FF22 00000000 OR.B #$00,D0
3FF26 0000 DC.B 0,0
3FF28 7846 MOVEQ #$46,D4
3FF2A 6002 BRA.S $02(PC)=$3FF2E
3FF2C 7847 MOVEQ #$47,D4
3FF2E BBCB CMP.L A3,A5
3FF30 675A BEQ.S $5A(PC)=$3FF8C
3FF32 2A0D MOVE.L A5,D5
3FF34 4BEB0008 LEA $0008(A3),A5
3FF38 347900000112 MOVE.W $00000112,A2
3FF3E 4E92 JSR (A2)
3FF40 664C BNE.S $4C(PC)=$3FF8E
3FF42 3031E800 MOVE.W $00(A1,A6.L),D0
3FF46 54AE0058 ADDQ.L #2,$0058(A6)
3FF4A 264D MOVE.L A5,A3
3FF4C 2A45 MOVE.L D5,A5
3FF4E C0FC0028 MULU #$0028,D0
3FF52 D0AE0030 ADD.L $0030(A6),D0
3FF56 B0AE0034 CMP.L $0034(A6),D0
3FF5A 6C2C BGE.S $2C(PC)=$3FF88
3FF5C 2A360800 MOVE.L $00(A6,D0.L),D5
3FF60 6B26 BMI.S $26(PC)=$3FF88
3FF62 347900000118 MOVE.W $00000118,A2
3FF68 4E92 JSR (A2)
3FF6A 6622 BNE.S $22(PC)=$3FF8E
3FF6C 5343 SUBQ.W #1,D3
3FF6E 661C BNE.S $1C(PC)=$3FF8C
3FF70 2031E800 MOVE.L $00(A1,A6.L),D0
3FF74 08000000 BTST #$00,D0
3FF78 6612 BNE.S $12(PC)=$3FF8C
3FF7A 2045 MOVE.L D5,A0
3FF7C 2240 MOVE.L D0,A1
3FF7E 7440 MOVEQ #$40,D2
3FF80 7664 MOVEQ #$64,D3
3FF82 2004 MOVE.L D4,D0
3FF84 4E43 TRAP #$3
3FF86 4E75 RTS
3FF88 70FA MOVEQ #$FA,D0
3FF8A 4E75 RTS
3FF8C 70F1 MOVEQ #$F1,D0
3FF8E 4E75 RTS
3FF90 0000 DC.B 0,0
The section hilighted in yellow is actually the information passed to SuperBASIC for the new command names and their syntax. In a future edit I hope to annotate it better.
Anyway, armed with this information you too, can go back to your old, actual QL and work out the data spaces for all the executables you couldn't otherwise run on your QL. Feel free to add them in comments!
Tuesday, 24 February 2026
Bike vs BEV
Introduction
We're frequently told that non-motorised bicycles are the most energy efficient transport in the world. So, there's no way a full EV (BEV) can compete with a bike for energy efficiency.
Or can it?
For example, it's easy to show that a bicycle at 20km/h requires about 75W of power; whereas a typical BEV might use 8.2kW at 50km/h. So, it's no contest.
Or is it?
The problem is that when people make these kinds of comparisons, they're comparing the energy required for the final product rather than the energy required at the source. For a non-motorised bike, that energy comes from the sunlight used to grow crops or farm animals + the energy used to process the food, but for a BEV that energy can come from a renewable energy source (such as Solar PV). Thus the right question to ask is whether replacing the crops making the additional food the cyclist needs, with Solar PV is more than the Solar PV needed for the BEV for the same distance.
With a bit of maths and some publicly available data, we can work it out!
Method
We'll see that when we do the calculations, available data is often in different units, so we'll have to do some unit conversions too. Also, we'll end up calculating backwards. For the EV, it's:
We can see already there are fewer obvious areas of loss, but that's because I've combined the motor for the BEV and the BEV into the same box (whereas for the Bike, the human is the motor).
Bike Calculations
At 20km/h it gives 75W, which means that travelling 20km requires 75Wh of energy (3.75Wh/km). A Wh is 860 calories, so 75Wh is 860*75=64,500 calories, or 64.5kcal.
BEV Calculations
Results
Conclusion
Refs:
Wednesday, 31 December 2025
Personal Computer World Sun SparcStation-1 Review
While doing some research on the Sun Sparcstation-1 I was finding it difficult to search for pages that actually gave the prices of anything other than the basic diskless configuration. However, the review of the SparcStation in Personal Computer World (June 1989) in fact does. It's a comprehensive review and word reading!
This post is almost entirely just pictures!
The entry-level price for a SPARCstation 1 with 8Mbytes of RAM, a single 1.44Mbyte floppy drive, a standard 1152x900 video board and a 17in grey-scale screen is £7400, while a system with two104Mbyte hard disks and the same video board driving a 16in 256-colour screen costs £12,700. With two hard disks, a 19in colour screen and the GX graphics accelerator, the price goes up to £16,400.
Conclusion
TI-30LCD Says Hello & Does Stats!
There were a wide variety of scientific calculators in our Maths class in 1981. In 2025 I bought a Casio FX-180P to compensate for my original Casio FX-180P that got broken! It's great calculator with lots of features.
Although Casio calculators were the most popular at school at the time, other schoolmates had different makes. In my mind, I recall the TI-30LCD was one of the worst, but was it really that bad?
So, I bought one off eBay too! It turns out it's quite easy to make it says Hello!
Introduction
Stats
- n: the number of items entered.
- ∑x: the sum of the items.
- ∑x²: the sum of the squares of all the items.
| Number | ∑x Term | Generate x² (Display) | ∑ (Display) |
|---|---|---|---|
| 5 | [SUM] | [x²] 25 | [+] 25 |
| 4 | [SUM] | [x²] 16 | [+] 41 |
| 8 | [SUM] | [x²] 64 | [+] 105 |
| 3 | [SUM] | [x²] 9 | [+] 114 |
| 4 | [SUM] | [x²] 16 | [+] 130 |
| 5 | [SUM] | [x²] 25 | [+] 155 |
| 7 | [SUM] | [x²] 49 | [+] 204 |
| 4 | [SUM] | [x²] 16 | [+] 220 |
| 3 | [SUM] | [x²] 9 | [+] 229 |
- Average=[RCL]/9=4.78;
- Standard Deviation=√(∑x²/n -(∑x/n)²= √(229/9-(43/9)²)= 1.62.
Correcting Errors
Conclusion
Monday, 22 December 2025
D'oh, D'oh! Host <-> Target Transfer On MAME's SparcStation 1 Emulator
I'm interested in simulating the real-time experience of a Sun SparcStation 1, because I'm currently interested in RISC Workstation era at the turn of the 1990s and I've never used one. Without an actual SS1, an emulator is the easiest choice.
There are two primary emulators available. QEMU supports a SparcStation 5 emulator, but it runs as fast as possible. MAME supports SparcStation 1 emulator. It can be used to try out SunOS (e.g. version 4.1.2), but lots of things don't work, at least on the MAME Version 0.255 I'm exploring, e.g. ethernet, serial, colour framebuffers (and accelerated graphics), second drives, floppy disks, tape (I think, but I haven't tried that).
There's a fairly decent introduction to getting MAME's SS1 emulator running. The only major difference I'd make is to create an uncompressed hard disk image just using dd (which is the subject of this blog post). In my case, it's called SunHd320.hd not sunos412.chd.
dd if=/dev/zero of=SunHd320.hd bs=16k count=19530
I can then run the emulator with this command line:
./mame sun4_60 -window -slot1 "bwtwo" "-scsibus:0" harddisk "-scsibus:1" "" "-scsibus:6" cdrom -hard SunHd320.hd -cdrom SunOS_412.iso
To make it somewhat usable I needed to get data in and out, and I faffed a lot with trying to create floppy disk images or second hard disks or serial transfer, but it was basically a waste of time. I could describe my multiple attempts to use these, but suffice to say, don't go down that rabbit hole until there's good evidence they work! Then, today it occurred to me I could just use dd, which of course that Unix Workstation had in 1989 and I also have on the Mac mini 2012 I'm emulating it on.
Background: Why The SparcStation 1?
The SparcStation 1 is a really interesting Sun Workstation, because it appeared at the peak of RISC's ascendency (April 12, 1989), just 2 days after the Intel i486 was launched, proving that CISC CPUs could achieve RISC levels of performance. The first Intel 486 computer didn't actually appear until September. I'm a fan of RISC. I loved PowerPC and I'm super-glad Apple have switched to ARM-based Macs. But the 1990s were an awkward reckoning for the methodology as vendors strove to stay ahead of Intel despite having far fewer engineers, only to find Intel copying their techniques and often better than comparable RISC computers.
So, skipping back to 1989. The SparcStation 1 was Sun's attempt to compete with PCs by designing a highly-integrated, low-end Sparc workstation. It ran at a blazing 20MHz, delivering about 13 Dhrystone MIPS (and a SpecInt89 of about 13-14 too). This was over twice as fast as the fastest Intel i386DX at the time and about 30% faster than the just announced Intel i486. So, it was impressive. It had 64kB of external cache (no internal cache) and used the bizarre Sun MMU ported from their earlier 68020-based workstations. This MMU doesn't use a Translate Look-aside Buffer, but dedicated SRAM chips to maintain a large, 2-level cache of page translations.
Finally, it has a Sparc V7 CPU, the epitome of a classic RISC design. For example, it has no multiply or divide instructions (just a multiply step instruction: 32 cycles for a 32x32=>64 bit result, but other multiply sizes can be done quicker).
Setting Up Data Transfer
The basic principle is that the disk image (.hd) is divided 8 partitions in SunOS and only 5 of them are used, so assigning some space to a spare partition and then accessing it using dd from either side is relatively easy.
There are several stages to making it work though! I'm using a 320MB HD image (a Sun type 5 drive). This would have been very big for 1989. Standard drives from Sun were 80MB or 104MB. You can install the OS from a CD image as described in the earlier link. It's a horrible textual, menu-driven thing which is easy to get wrong. The critical thing though is that you can install the OS and then later modify the partitions. By convention, disk3 is used for the main HD; partition a is root '/'; partition b is swap (not mounted as such); c is a non-mounted partition that covers the whole drive; g is /usr and h is /home.
For this experiment I didn't quite do an 'easy' setup. Initially one needs to >b cdrom at the bootloader prompt. Then when it says:
Enter 2. It puts you in a # root type prompt, but there isn't a user as such and you can't logout. Enter format and it will take you through the standard setup. You can type ?<cr> at any time to see all the menu options. I typed disk<cr> 0<cr> type<cr> 5<cr> partition<cr> . I knew from an earlier, 207MB HD setup what sizes I needed, and wanted the rest of the space for the /home directory, so I basically duplicated that:| Partition (type letter<cr>) |
Cylinder (prompted) (672 x 512b blocks/ cylinder) |
Blocks (prompted) |
|---|---|---|
| a | 0 | 16800 |
| b | 25 | 102144 |
| c | 0 | 623616 |
| g | 177 | 201600 |
| h | 477 | 303072 |
You should check they all add up and no partitions overlap (apart from partition c which covers the whole disk). Then You need to type label<cr> y<cr> quit<cr> then I typed label<cr> y<cr> quit<cr> just to make sure. Back at the # prompt, type reboot cdrom<cr> and on this run through, type 1<cr> then it'll install miniroot, then type 2<cr> because you've already 'formatted' the disk, 1<cr> to reboot, note the vmunix is now a bit bigger at 802kB instead of about 737kB. If the SS1 doesn't automatically reboot, type >b disk3 at the prompt and it should boot. At the # prompt type suninstall<cr> and you'll be into the installer proper ("Welcome to SunInstall"). Type 1<cr> then n<cr>. Although this means the partitions will be overwritten, the sizes of partitions a, b, c, g and h will be preserved. I then chose the Programmer option by following the on-screen instructions, then finally y<cr> to start. Note also, the installer runs newfs for each of these partitions, which means it isn't changing the partition sizes.
After the basic install, it will complete the installation by asking you to provide extra information. I pressed 2<cr> <RETURN> I set the hostname to SS1mini , chose GMT for the time zone. 2<cr> then 22/12/2025<cr> for the date (UK format) and 11:34:30<cr> for the time. 1<cr> to accept that. 2<cr> (not on a network), y<cr> to accept. Finally I chose a password; I set up a user account with a full name of Julian Skidmore; user name as js; 100 as the user ID (because 0..99 are supposedly reserved) and the same password as root. It then finally completed the installation and dropped me into a login prompt.
I logged in as root ; then typed reboot cdrom to reboot into the cd and typed 2<cr> to use the single user shell; ran format again.
The trick is to steal space from another partition and because a, b, g and h are all mounted as proper filesystems, the obvious place is to steal from the swap partition. We have about 49MB allocated to that, for a 16MB SS1, so stealing around 1.44MB will be OK. Type 0<cr> then partition<cr> then make these changes:
| Partition (type letter<cr>) |
Cylinder (prompted) (672 x 512b blocks/ cylinder) |
Blocks (prompted) |
|---|---|---|
| b | 25 | 98784 |
| d | 172 | 3360 |
Then you need to check all the partitions add up; write the label (label<cr> y<cr>), then quit<cr> label<cr> quit<cr>. Finally you can reboot back into the emulator: reboot disk3<cr>.
You only have to do this once and you're now ready to do data transfer!
Performing A Data Transfer
As a test, I modified a version of dhrystone to provide more accurate results when using time() instead of the µsecond accurate system functions, then tar'd them up into a 40kB tar file. You could use any file as a demonstration. You need to measure the length of the files you want to transfer in this technique of course.
From the SS1 emulator I could then copy dhry.tar to d using:
dd if=dhry.tar of=/dev/sd3d bs=1024 count=40
Then I needed to logout, login as root; then /etc/halt the SS1 emulator and quit MAME. Now I could copy from the hard disk image to the host on my Mac mini using:
dd if=SunHd320.hd of=dhry.tar bs=1024 oseek=57792 count=40
(Since partition d was at cylinder 172 according to format: Partition: Print). If you had created a compressed, chd hard disk, you would need the MAME tool chdman and calculate absolute byte offsets and lengths ( e.g. ./chdman extracthd -i sunos412.chd -isb 84951040 -ib 40960 -o dhry.tar ).
I could then copy back to the SunHd320.hd, but this is a bit non-trivial, because I found dd truncates the file. I needed to do:
cp SunHd320.hd SunHd320B.hd
dd of=SunHd320.hd if=dhry.tar bs=1024 oseek=56112 count=40
Then add the rest of the hard disk image using:
dd of=SunHd320.hd if=SunHd320B.hd bs=1024 iseek=56152 oseek=56152
Finally I could boot back into the SS1 emulator and copy the data back (when logged in as root) using:
dd of=dhry.tar if=/dev/sd3d bs=1024 count=40
I could then untar it using tar -xvf dhry.tar.
Conclusion
MAME provides a real-time emulation of a SparcStation 1 on hardware at least a few hundred times faster (in my case, the 2.5GHz Dual-Core i5 on my Mac mini 2012). To make any emulator truly useful you have to get data in and out of it. However, this emulator is only barely working.
After quite a few dead ends, I realised I could use dd on the SparcStation emulator and the hard disk image on the host side to transfer data in a fairly clumsy way. It's very crude. Still, I have bi-directional data transfer and I can start playing around with some other SparcStation software installs.










