Tuesday, 31 December 2024
Wobbly-Blue: An Optical Illusion on a ZX Spectrum And VIC-20
Tuesday, 19 November 2024
The Mythical Mac 256K
Introduction
This MacGUI blog post covers the boot process for the early System Software on a Mac 512K (or Mac 128K). In part of it, he talks about the Mythical Mac 256K.
At the beginning of the boot blocks are several stored parameters. The version number is two bytes. Another two bytes hold flags for the secondary sound and video pages. Then come a series of seven, 16-byte long file names. These are the names of the System resource file, Finder (or shell), debugger, disassembler, startup screen, initial application to run, and clipboard.
Following the names is a value for how many open files there may be at once, and the event queue size. Then come three, 4-byte values which are system heap size for a Mac with 128K of RAM, 256K, and 512K of RAM, respectively. If you could find me a Mac with 256K of RAM, I'd sure be impressed. Wink
<snip>
If you landed from planet Krypton with a Mac 256K, your system heap size would be $8000 (decimal 32,768).
Disappointingly, as he also covers in this blog post, the 64K ROM only checks for the 128K or 512K Mac models and the 128kB model memory size is defined explicitly by the line:
4002E4: LEA $0001FFFC,A1 ;128K RAM
The tests work by exploiting incomplete memory decoding on early Macs. A Mac 128K's memory appears to be duplicated 4 times (actually it's duplicated 32 times all the way up to 4MB); whereas a Mac 256K is duplicated twice and a Mac 512K's memory doesn't get duplicated at all (up to 512K).
First (Failed) Attempt
I took a 64K Mac ROM and changed it to $0003FFFC, then added 2 to the 3rd byte of the ROM checksum to adjust it, which is in the first long word of the ROM. Then I added a miniVMac option for a Mac 256K, hacking about with a few scripts and some of the source code. I thought I'd correctly achieved a 256kB Mac, but I hadn't - for my 19kB MacWrite test document I had misread the MacWrite splash screen, which says how much memory is free, and used. I'd mistaken 'free' and 'used' for each other, because the values were fairly plausible for a Mac 256K.
PICO-Mac
PCE-Mac Emulator
FindMemSize: | ; | |
4002DE: | LEA $7FFFC,A0 | ; 512K RAM |
4002E4: | LEA $1FFFC,A1 | ; 128K RAM |
4002EA: | CLR.L (A0)+ | |
4002EC: | TST.L (A1)+ | |
4002EE: | BNE.S 4002F2 | ; branch if 512K |
4002F0: | MOVE.L A1,A0 | ; this is a 128K machine |
4002F2: | MOVE.L A0,$0108 | ; set MemTop |
- It would mess up the ROM test for a 128KB Mac.
- It turns out the Boot block on the Floppy Disk does its own test, explicitly for a Mac 256K and does the wrong thing if MemTop is set to 256K.
0001008A: | 2238 0108 | MOVE.L $0108, D1 |
0001008E: | 4841 | SWAP D1 |
00010090: | 0C41 0004 | CMPI.W #$0004, D1 |
00010094: | 6E2C | BGT.S $000100C2 |
00010096: | 7200 | MOVEQ #$00000000, D1 |
00010098: | 50F9 0001 FFF0 | ST $0001FFF0 |
0001009E: | 42B9 0003 FFF0 | CLR.L $0003FFF0 |
000100A4: | 4AB9 0001 FFF0 | TST.L $0001FFF0 |
000100AA: | 6716 | BEQ.S $000100C2 |
000100AC: | 7002 | MOVEQ #$00000002, D0 |
000100AE: | 4840 | SWAP D0 |
000100B0: | D1B8 0108 | ADD.L D0, $0108 |
000100B4: | D1B8 0824 | ADD.L D0, $0824 |
000100B8: | D1B8 0266 | ADD.L D0, $0266 |
000100BC: | D1B8 010C | ADD.L D0, $010C |
000100C0: | 7204 | MOVEQ #$00000004, D1 |
A Correct ROM Fix
000002DE: | 7204 | MOVEQ #$00000004, D1 |
000002E0: | 4841 | SWAP D1 |
000002E2: | 2241 | MOVEA.L D1, A1 |
000002E4: | D281 | ADD.L D1, D1 |
000002E6: | 2041 | MOVEA.L D1, A0 |
000002E8: | 42A0 | CLR.L -(A0) |
000002EA: | 4AA1 | TST.L -(A1) |
000002EC: | 6602 | BNE.S $000002F0 |
000002EE: | E489 | LSR.L #$2, D1 |
000002F0: | 2041 | MOVEA.L D1, A0 |
Results
Conclusion
Next Steps
Sunday, 17 November 2024
Saving Europe-ASAP (Ally State Access Privileges)
In 1939, 85 years ago at the time of writing, the UK government declared war on the Nazi régime in order to defend the sovereignty of Poland, but ultimately to rescue Europe from fascism.
It was unsuccessful in the first aim, but successful in the second with the help of allies across the globe, in particular, the United States under President Roosevelt, and the set of countries that became the Commonwealth (which at the time were part of the British Empire).
Today Europe is at a similar crisis point following the insurgence of far-right political groups in Europe and the recent re-election of Donald Trump as the president of the United States.
It is already the case that his administration is demanding vassalage from European countries. Vassalage is an appropriate term, since Trump is acting like a medieval king. In this context, a number of far-right European leaders are already pledging support at a time when the most dominant EU countries, Germany and France are facing a democratic crisis.
Meanwhile, Britain, as in 1939 has never been more alone: cut-off from the EU since the 2016 Brexit referendum and now deeply at odds with a United States that considers the new Labour government to be a socialist enemy. Falling into line with Trump's demands would certainly destabilise the UK, given that high-profile Trump supporters such as Elon Musk regularly portray the country as a Police State or close to civil war.
What we need to do at this time is demonstrate solidarity with the EU, but this too is not easily possible, because the Labour government is determined to honour Brexit by not rejoining the EU. Perhaps though, given the ugency, there is another way: Ally State Access Privileges (ASAP), a temporary mechanism for supporting Europe in a new time of need.
This blog post is a rough (and very ignorant) draft proposal of the ASAP, how it operates, who is involved and its underlying purpose.
Purpose
Operation
- ASAP is a temporary political alliance between member states of the EU and nations willing to support European stability. It applies to an ASAP alliance member for a 1 year duration and must be renewed every 12 months.
- It confers the temporary elimination of trade barriers on conditions of EU regulation compliance, as per EU membership and includes temporary access to the single market and customs union.
- It confers Freedom of movement to individuals who are part of ASAP member states.
- It provides a subset of access to European Institutions:
- Voting privileges to ASAP alliance members in the European Parliament. The representative block is exactly the same size as would be the case if the ASAP member was an actual EU member, but the composition of an ASAP contingent is in proportion to the composition of the legislative in the respective member state. ASAP MEPs are chosen by decree from its member state by any mechanism they see fit.
- The head of state from an ASAP member is allowed on the European Council, as per EU membership.
- One ASAP member per ASAP state is allowed on the Council of the European Union and European Commission. However, no ASAP member can be a European President.
- One ASAP member per ASAP state is allowed as part of the Eurogroup specifically in order to temporarily influence and help align economic policy between ASAP members and the EU.
- Others?
- Access to social media dominated by the far-right is prohibited by law, where dominated means both that the content must be less than 3/5 represented by right-wing posts or reposts or contain more than 2% of far-right posts. (Is this reasonable - what's the criteria on Bluesky?).
- Editorial guidelines for Printed media (and their online counterparts) are to be placed in the hands of a trust, analogous to the Guardian Scott Trust, in order to eliminate editorial influence from their owners; while retaining the same rough remit for their political flavour. The intent is to ensure freedom of expression while restricting extremism.
- Extended powers for media regulators (such as OfCom in the UK) will ensure that factual errors in articles must be corrected with the same prominence given to the original article. Multiple regulatory breaches will lead to a process of mentoring by journalists from randomly chosen media outlets meeting higher regulatory standards. The purpose of this is to slow down the publication of objectively misleading articles while avoiding political bias.
Members
Conclusion
Wednesday, 24 July 2024
Why does Sin(a)≈a for small a in radians?
Introduction
Saturday, 6 April 2024
Space Shuttle CPU MMU, It's Not Rocket Science
The NASA Space Shuttle used a cut-down IBM System/360 influenced CPU called the AP-101S aimed mostly at military aeronautical applications. It's fairly weird, but then again, many architectures from the 1960s and even 1970s are weird.
I've known for a long time that the Space Shuttle initially had an addressing range of about 176K and because one of the weird things is that it's 16-bit word addressed (what they call half-words), this means 352kB. Later this was expanded to 1024kB (i.e. 512k half-words). How did they do this?
You might imagine that, being jolly clever people at NASA, they'd come up with a super-impressive extended memory technique, but in fact it's a simple bank-switched Harvard architecture where the address range for both code and data is split in two and 10 x 4-bit bank registers are used to map the upper half to 64kB (32k half-word) banks.
So, the scheme is simple and can be summarised as:
Documentation
- Budget cuts and pressure in the 1970s and 1980s led to poor documentation. This can be checked by reading the quality of the documentation prior to this mid-80s document and/or later if standards improved.
- Justification: all NASA hardware, including the AP-101S was expensive, so convoluted documentation helps convey the idea that the public and NASA were getting their money's worth: if you can't comprehend it, you won't grasp how simple and standard it was.
- Small developer-base: documentation tends to suffer when not many people are developing for a given product. That's partly because there's a lack of resources dedicated to documentation, but it's also because documentation is frequently passed on verbally (what I sarcastically call Cognitive documentation, i.e. no documentation 😉 ). I don't know the size of the Shuttle software developer team, but I guess it was in the low hundreds at any one time, because although the memory space was only a few hundred kB; I believe they loaded in various programs to handle different mission stages (e.g. ascent, docking, orbital corrections, satellite deployment, landing) and that means if there's a few MB of code, that's about 300,000 lines and given the safety requirements, perhaps only a few thousand lines per developer.
Conclusion
Thursday, 28 March 2024
Mouse Detechification! A PS/2 To Archimedes Quadrature Mouse conversion!
After an embarrassing amount of work I managed to convert a PS/2 mouse into a quadrature encoding mouse for my Acorn Archimedes A3020.
A Mini-Mouse History
I know I could have bought a USB to quadrature encoded mouse adapter (from here on, QE mouse, because I don't like the term Bus-mouse), but that seemed like a cop-out, so instead I decided to make things as painful as possible. The first stage was to cut out the blobtronics that made it a PS/2 mouse.
Then I added some pull-down / level-shifting resistors to see if the A3020 would recognise it as valid values but it didn't. Then I went through a long process of getting an Arduino to recognise the analog voltages from the phototransistor (yep, I also know I could use a Schmitt-trigger buffer chip) and write a small program to actually process them into quadrature encoded X and Y grey code (Ref: Dir are 00, 01, 11, 10, 00... for forward/up and 00, 10, 11, 01, 00.. for backward/down). It turned out it wasn't very digital!
I figured I could solve the problem in software using a small MCU that would fit in the mouse, so I chose an ATTINY24, a 14-pin AVR MCU with 8 ADC 10-bit channels and 4 other digital IO pins. I used a simple hysteresis algorithm: it first figures out the range of values it can get from the phototransistors; then allows a bit more time to see if the range is bigger; then once it's interpreted any given state, the ADC values have to change by 2/3 of the range to flip into the next state.
I went through quite a bit of a debugging process, because obviously when you go from a fairly lush environment like an Arduino (plenty of libraries, plenty of IO pins, lots of code space and relatively abundant RAM (2kB ;) )) to an ATTINY24 (2kB flash, 128 bytes of RAM, just 12 IO pins) and then stick it in a mouse, the fewer opportunities you have for debugging - and you can't even use an LED inside a trad, ball mouse, because ta-dah, you won't see it! So it's best to debug as much as possible in simulation, before you take the final step. In fact the program only ended up being about 906 bytes, because 'C' compiles pretty well on an 8-bit AVR.
I made a lot of mistakes at pretty much every stage - but amazingly getting the mouse directions inverted wasn't one of them :) . I started with 10K resistors for the phototransistors, but then ended up deducing 15K was best (22K || 47K) so that was 8 resistors! When soldering the analogue connections to the AVR I was out by one pin all the way along, because from the underside, I mistook the decoupling cap pins for the Pin1 and Pin 14 of the AVR. I had to desolder the phototransistor connections to the main cable - which I'd been using when analysing on the Arduino; then solder up the photo transistors to the analog inputs and then the digital outputs to the original wires. I tried to keep the wires no longer than they needed to be because it was cramped in there, but I ended up making the Y axis analog wires just 1mm too short (because, d'uh they get a bit shorter when you strip them and feed them through a PCB) so they had to be redone. Because there were a lot of wires I needed to glue them down as otherwise the casing wouldn't close, and I was particularly concerned about the phototransistor wires getting caught in the Y axis wheel, but then I glued them down directly underneath that wheel so it couldn't clip into place! I also glued the grey and green wires running up the right so that they got in the way of the case closing - so all of these had to be very carefully cut out and moved. Near the end I remembered I had to add a 10K resistor between reset and power so that the MCU would actually come out of reset and execute code! I also had to add an input signal, to software switch the Y axis inputs to the X axis grey code, because the only header I could find to fit the mouse cable plug for testing didn't leave room to test both X and Y grey codes! Hence what looks like an extra button!
Finally I connected it all up, glued the board and wires down (after correcting the locations) and got: A BIG FAT NOTHING! I thought maybe I'd messed up the analogue ranges and retried it with a different range and that didn't work. Then I realised I could output debug serial out of one of the grey code outputs to the Arduino and see what the ATTINY was reading! Bit-banged serial code can be very compact!
void PutCh(uint8_t ch)
{ // (ch<<1) adds a start bit in bit 0 and |0x200 adds a
uint16_t frame=((uint16_t)ch<<1)|0x200; // stop bit.
do {
if(frame&1) {
PORTB|=kSerTxPin;
}
else {
PORTB&=~kSerTxPin;
}
frame>>=1;
_delay_us(52.083333-11/8); // 19200 baud.
}while(frame); // & after the stop's been shifted out,
// the frame is 0 and we're done.
}
Before I tried it, I did a sanity check for power and ground only to find I hadn't actually connected up VCC properly!!!! I'd forgotten the final stage of solder-bridging the decoupling cap's +ve lead to Pin1 of the AVR and I ended up ungluing everything so I could see underneath.
But when I fixed this and packed it all back in the case: It Worked! I tried reading the digital outputs at the end of the cable on the Arduino and when I was satisfied (which only took a few minutes of testing) I decided to hook it up to my A3020 and hey-presto! I have a working QE Mouse!
I had been a bit concerned that doing analog sampling wouldn't be fast enough and so my algorithm has a heuristic whereby if it sees a jump of 2 transitions (00 <=> 11 or 01 <=> 10) it assumes it's a single step in the same direction as before. I could manage about 20K x 4 samples per second, but a little maths shows this will be fine, because a full 640 pixels on the Arc's screen can be sampled OK if you cover it in about 3.2ms and clearly we don't do that.
!Paint, which is like, 96kB I think! It's terribly unintuitive though! Note on the video that a 12MHz ARM250 can drag whole, 4-bpp x 640x480 windows around rather than just outlines! Note also the Taskbar, which was standard on the Archimedes before Windows 95, or Mac OS X (NeXT step had a floating Dock).
Here, again is the link to the project and source code.
Sunday, 24 March 2024
Colour Me Stupid - An Early Archimedes 8-bit Colour Quest!
I'm assuming, naïvely again, that I can write a short blog post, but on past performance this isn't likely. I recently managed to get my Acorn Archimedes A3020 working again by converting a PS/2 mouse to a Quadrature mouse as early Archimedes' expect (see this blog post) and this has given me more of an interest in the system, particularly from a hardware viewpoint.
Wonderfully, I'm currently writing this on my MacBook Air M2, a 32-year later descendent of the ARM250 that powers that original A3020, so things have come full circle in a sense.
These early Arcs had a video chip called VIDC which supports 1, 2, 4 and 8-bit colour video modes at different resolutions, but for decades (probably even since the first review I saw in Personal Computer World August 1987), I was confused as to why the 8-bit colour mode was described as merely having a 64 colour palette with 4 tints instead of proper 8-bit RGB colours.
Why create something complex, which doesn't even do the job? What kind of terminology is 'tints'? How do you really use them?
The confusion deepened when I started to look into the VIDC hardware, because it never supported a 64-colour palette and some tints, instead it always supported a 16 x 12-bit colour palette for all modes, including the 8-bit colour mode. So, how did that work?
Standard VIDC Palette Entry
Sup | Blue | Green | Red |
---|---|---|---|
S | B3 B2 B1 B0 | G3 G2 G1 G0 | R3 R2 R1 R0 |
Direct | Palette |
---|---|
B3 G3 G2 R3 | Palette 0..15 |
Direct | Palette |
---|---|
B3 G3 G2 R3 | B2 G1 R2 R1 |
How To Mess Up Palette Settings
B2G1\R2R1 | R2R1=0 | R2R1=2 | R2R1=4 | R2R1=6 |
---|---|---|---|---|
B2G1=00 | 0x000 | 0x002 | 0x004 | 0x006 |
B2G1=01 | 0x020 | 0x022 | 0x024 | 0x026 |
B2G1=10 | 0x400 | 0x402 | 0x404 | 0x406 |
B2G1=11 | 0x420 | 0x422 | 0x424 | 0x426 |
A Hint On Tints: Exact 8-bit RGB Is Impossible
The Alternative Palette Approach
Direct | Palette |
---|---|
B3 G3 G2 R3 | B2 R2 T1 T0 |
B2R2\Tint | 0 | 1 | 2 | 3 |
---|---|---|---|---|
B2R2=00 | 0x000 | 0x111 | 0x222 | 0x333 |
B2R2=01 | 0x004 | 0x115 | 0x226 | 0x337 |
B2R2=10 | 0x400 | 0x511 | 0x622 | 0x733 |
B2R2=11 | 0x404 | 0x515 | 0x626 | 0x737 |
- The RGB primaries are all evenly distributed, they get 2-bits each.
- There are 16 levels of grey, which means that anti-aliased black text on a white background (or its inverse) can be done pretty well.
- There's a brighter range because it goes up to 0xfff.
- Human vision is more attuned to brightness than colour, which is why the HSV colour model is effective, so it's possible that this convention can represent images that perceive better to us.
Dithering
* | 7/16 | |
3/16 | 5/16 | 1/16 |