The Complete Spectrum ROM Disassembly
speccy.xyz
speccy.xyz
Looking forward to browsing some of the other code linked to from the site - e.g. Manic Miner which was a particular favourite.
A couple of points about the Spectrum ROM.
- Spectrum BASIC was very slow especially compared to BBC Basic. I think that this was partly due to the constraints of having to fit everything into 16k vs 32k for the BBC - so code was optimised for size rather than speed.
- It included a stack based VM for floating point operations which I think was again mainly to reduce the code size (one byte for each operation rather than three bytes for a subroutine call).
Would seem appropriate to give credit to the main author of the code, Steve Vickers [1], who went on to found Jupiter Computing, makers of the Jupiter Ace.
[1] https://web.archive.org/web/20110516082258/http://www.sincus...
edit: added Steve Vickers credit.
Yes. The commercial games were all assembly anyway. The BASIC was just to get the idea what is possible, assembly to achieve the speed.
> a stack based VM for floating point operation
Of course, even Intel 8087 FPU chip and all the FPU operations is x86 before the introduction of SSE2 were done based on the stack based code and operations. Stack based calculations indeed allow amazing code density.
The Z80 had plenty of features that the BBC micro's 6502 did not have, so the code should have been quicker with fewer CPU cycles used and fewer lines of code. But the lack of supporting hardware negated this gain.
BBC BASIC was also a more complete implementation of the language. So any code written in BASIC was more efficient just because you didn't have to use your own BASIC workarounds. Being able to drop into assembly language also helped, the Spectrum lacked this option to truly turbo charge your code. The BBC used 16k for BASIC in ROM and had 16k for the OS. This enabled ROMs to be swapped out so you could run BCPL or another ROM, e.g. Fortran.
The Spectrum had BASIC and the OS in 16k with 48k available for RAM. The BBC could use more than 32k of RAM if installed, as per the later Master system that used bank switching.
I am not familiar with the code but I would be surprised if the BBC Basic ROM was anything less than a work of genius concise code. Every byte counted in those days regardless of what home computer you were programming for.
0->16K: ROM
16K->32K: "Slower" RAM (ULA/Video has preference so may delay CPU)
32K->64K: "Faster" RAM (Same RAM, but nothing other than CPU accesses it)
So when manipulating memory (which is .. most of the time), The Z80 often needed 3-4 instructions for what the 6502 could do in one. The z80 had more registers and some 16-bit arithmetic.
Absolutely agree on the hardware point as Sinclair's real talent was squeezing as much out of basic hardware as possible even at the expense of performance (e.g. CPU driving the screen in ZX80/81).
As a commercial decision limiting the ROM to 16k was a very good move in the end for Sinclair. It allowed full colour with 42k of spare RAM whereas the BBC only had c24k after allowing for screen memory, so in the end the Spectrum could support much larger and richer games than the BBC and (later) the Electron.
https://github.com/jhallen/joes-sandbox/tree/master/classic-...
I remember hearing Steve Furber say that they realised that memory bandwidth was the biggest constraint in 8/16 bit CPUs so the ARM1/2 really focused on this and it shows (in fact I think they approached Intel with the idea of commissioning an 8086 with more bandwidth but were turned away - funny how things work out).
Even if this isn’t in the zero page, it surprises me that those expensive x indirect loads and stores are cheaper than worth having to increase the source and destination addresses often, but that probably is because my 6502 is very rusty.
Also: I stared at that code for a while, but couldn’t figure out why that jmp immer is there. If you move the 3 instructions starting at lastpage to the end, it can be removed, can’t it? (I didn’t check, but there may be further code shuffles that do not decrease the number of instructions, but do decrease the number of branches and with it, the number of cycles spent)
>moving it into the zero page and not using indexed mode
I'm not sure I follow.. you mean restrict the memcpy to only within the zero-page?
>jmp inner..
Yeah, it doesn't matter to much, not in the inner loop. You could move the start of the code to right after the rts also..
Increasing an address is faster in the zero page, and self-modifying code is faster. That combines the two.
inc $c9 5 cycles
00c8: lda $xxxx 4 cycles
vs. lda $xxxx,x 4
inx 2
Mine is still faster...http://map.grauw.nl/articles/fast_loops.php#unrollingldir
The reason for this is a bit obscure, but was caused by a peculiarity of the Z80's implementation of LDIR. For each iteration it actually decrements PC by 2 and reloads the instruction. This is apparently so that the CPU can still service interrupts during the loop. Since LDIR is an "extended" instruction it has to reread 2 bytes. LDI being a single byte was quicker to read.
ld d,(hl) 7 cycles
inc hl 6 cycles
ld e,(hl) 7 cycles
inc hl 6 cycles
push de 11
18.5 cycles per byte, vs. 16 cycles per byte using ldiUsing hexadecimal monitors wasn't that appealing to me, specially trying to find out why a checksum row wasn't correct. Much worse than finding errors on BASIC listings.
Sadly I didn't get him to sign my original copy of the ZX81 Manual :-(
I.e. "Does non-presence of an asserted relation, mean the relation is instead refuted (i.e. is this table a total membership-function for a set whose members are its present rows)? Or does non-presence of an assertion of a relation mean that this system just hasn't been informed of that assertion, and is in a default state of not-knowing the truth value of the relation (i.e. is this table a partial membership function, defined only on asserted relations)?"
Or, to put that another way: if you were to create an RDBMS that "correctly" reflects formal relational algebra, then should a search query looking for P(X), which you haven't asserted to be true, be "satisfied" to say -P(X); or should it be "unsatisfied" / non-halting, because whatever answer it would give could potentially be wrong in the face of later learning?
...does that question have something to do with the concept of "open" vs "closed" sublocales, or am I way off?
https://www.abebooks.co.uk/9780861611164/Complete-Spectrum-R...
by Dr Ian Logan and Dr Frank O'Hara, 1983
published by Melbourne House, here is the scan of their catalog from these times:
http://www.ourdigitalheritage.org/archive/playitagain/wp-con...
I see in the changelog of this project:
https://speccy.xyz/rom/reference/changelog.html
"20160709 The disassembly is now 'complete'.
- Added annotations from The Complete Spectrum ROM Disassembly by Dr Ian Logan and Dr Frank O'Hara"
The interesting aspect of this online version is its relation to
[0] https://www.computinghistory.org.uk/det/41998/The-Spectrum-M...
edit: I originally wrote that the author was Rodney Zacks but was mistaken -- googling found that it's by Richard Ross-Langley
Go to 23*N
Off topic. Little quiz:
RANDOMIZE USR 0
What for ?So preservance using what the 8bit systems offered was a must anyway.
20 PRINT USR 16514
16514
16509 is the address of the start of the program in memory. Bytes 16509-16510 are the line number (2 byte LSB int). Bytes 16511-16512 are the length of the line. Byte 16513 is the command keyword (REM).
Thank you for getting me to dig them out and great that they live on in libvirt!
ps The memory mapping reminded me that ZX81 managed to squeeze a 32 x 24 screen into a 1k total RAM. I think someone managed to write a chess program with those restrictions - but only using 8 x 8 or so of the screen.
I had this chess game on tape, and I've often wondered if the two are related, but this one needed 16K: http://www.zx81stuff.org.uk/zx81/tape/ZXChessII(Black)