Background

Work specifically on the 32bit version of the OS had been delayed for so very long for a variety of reasons. One of these was that there was so little to be gained from doing so - it would effectively mean that there were no applications initially available for the platform. As the hardware manufacturers had failed to produce any significant hardware which would require the system (and were markedly making very little effort in that direction), this would mean that any 'users' of a 32bit version of the OS would be doing so on hardware which could run the 26bit version - with all of its applications - or a 32bit version with very few-to-no applications. From a user's perspective this was a no-brainer - no point in investing towards a system that they saw no gain in.

Any work towards a 32bit system would be wide ranging and would involve quite a bit of time. Certainly earlier on I wasn't confident in my ability to make those changes on my own - without anyone to review, and limited testing, it was very likely to take significant time, cause issues with the non-32bit versions, and take away time from any other features. And at the end you would be left with a system that wasn't able to run much.

There was the fact that there was 32bit version which had been created by a few people in their 'spare' time at Pace - not as a real project - which would have been useful to merge. There had been meetings with Pace which had been very encouraging, and might have meant that we could have worked together, sharing the code.

I remember being at one where we (Paul, Matthew, maybe Andrew, and myself - might have been that we had someone else as well, but I think that was about right) went to talk to them, for a quite informal meeting about how we could work together. We were shown to a meeting room and the rest of the room filled with Pace engineers - which was quite daunting at the time.

Aside from there being some discussions about how the code had diverged (on our part, it wasn't quite as well managed as we might have done these days, but it wasn't insane), I don't remember all that much. But I do remember that it was predicated on the fact that we shared code and expertise, and that was quite surprising and hard to work into a discussion. I never quite understood what Pace would gain out of such a relationship - maybe a little goodwill from the RISC OS community, and bug feedback for some things. There was talk about the fact that the desktop community could provide a testing ground for the system - thus reducing the amount of problems that would go into their paying customers systems.

I'm pretty sure that was the goal with the !Browse and !Java releases, and I don't think it ran so well. At least that was my view from the outside. The amount of work needed to run that, and the amount of triage and support needed to ensure that it remained viable was probably quite high. Doing the same for an entire OS might be more difficult.

It might be nice to think that people at Pace were impressed at what we had done and wanted to ensure that they benefited from our work, but they were always entitled to OS releases, and really the work we did to get RISC OS 4 released wasn't quite as significant as the stuff that I did later, so that seems like a false hope.

Anyhow, that came to nothing. But there was still talk of that during the development time, until even a few years later.

The decision by the RISCOS Ltd board to abandon all work on hardware development, and instead to focus on the emulation solutions stung a lot at the time - and was the primary reason for leaving the company really. When I returned later, the decision to do no work towards no hardware was still there. It had been made clear that the extant hardware, and the emulation systems, were the only ways that should be pursued. This tended to colour judgement, but it was always in my mind that a portable system - new hardware with suitable capabilities - should be a goal.

Castle let us know that they were going to produce a desktop system themselves - what became the Iyonix - based on the abandoned work for a Pace STB, using developers who had left Pace. There were arguments about this, and whether this was at all within the licence agreement - none of which were ever resolved properly. Essentially they ignored everything that came from the RISCOS Ltd strand of the OS, and took the RISC OS 3.7/STB derived OS to run on the Iyonix.

This fragmented things a little, and general goodwill amongst the hardware manufacturers was already at a low point. The issues with the USB stack which they had released previously, and the work done by Simtec on a separate stack had been a public split as well. There was a general distrust (some might say hatred, but they might know the situation better than I) of Castle by some individuals and groups because of prior incidents, and the issues surrounding the release of the Iyonix only reinforced this with them.

Despite this, there was a good deal of user support for the system. My view is that the end consumers do not really care for the licence issues, rights and legalities. They see something they want and the groups that are involved should sort those sorts of things out between themselves. My experience was that what it actually comes down to is the group's conviction in their goals, the amount of shouting they are prepared to do, and how much money they are prepared to burn. Over the period, the number of solicitors letters thrown around - and not just by the above groups, by others only peripherally involved - seem now to be quite bizarre. The last flails of a dying market.

Maybe I heard things worse because of who I spoke to, but that is my memory of how things were. I say that, and then I realise that I skipped out the biggy...

Castle GPL violation

Someone sent me a copy of the Iyonix ROM because they thought I would be interested. RISCOS Ltd actually had an Iyonix anyhow, although I had not really used it save to look at for a few things at the time. I had a look at the ROM image and noticed a bunch of functions signatures - names of functions - hiding in the Kernel which handled PCI and looked out of place. Firstly they were out of place because Pace's OS had not included any C code in the Kernel when I saw it, and because... well, it had a feel of a free OS. I looked at the Linux 2.4.18 kernel source that I had locally, and it seemed a little similar. I tried looking at the FreeBSD and NetBSD sources and they had quite different handling, so I stuck with the Linux code.

I extracted some bits from the Linux 2.4.18 kernel I had, and compared the source code to what the assembler looked like in the ROM. Over the years I've become quite good at knowing what C source code will look like when compiled to ARM, at least with the Norcroft compiler. Some bits matched up but others didn't. It wasn't quite right. I did a little more searching around and found discussions about the development 2.5 series Kernels, and so decided to try one of those - 2.5.49, which was the most current at the time. As I said, I know the code that Norcroft produces for RISC OS and it was very clear to me that the code that was compiled came from these sources, or a source very closely related to them.

Just emailing the relevant people without any justification than 'look this looks a bit similar' was unlikely to be fruitful. So I compiled up the code with some simple modifications - changes that I would have made if I were to be trying to make that code work in RISC OS - and allowing for general drift caused by taking development versions of the Linux source and then modifying it for your own purposes. The results convinced me that I should mention this... so I went and asked Castle for a copy of the source to RISC OS under the terms of the GPL (over a few mails). They denied that there was any such source there and were 'intrigued' to know why I thought that.

I replied stating explicitly which terms of the GPL I was asking for the source under, and the stated that the Kernel incorporated sections of the Linux kernel - and the parts that they had used. They went quiet.

I mailed the maintainers of that code and Russell King, as maintainer of the ARM code base. He suggested that I mail Castle again to give them a chance to respond. After I had not got a response, Russell posted to the Linux Kernel Mailing list about the issue. That got slashdotted, and commented on in Usenet - I supplied a link to my findings, which I had carefully documented so that others who knew the detail could check in order to confirm that I wasn't talking out of my behind.

There were a lot of comments from people on Usenet, but one that I remember with the most fondness (no offence to anyone else who said anything positive or negative) was the one from John Kortink - we had clashed numerous times about things, and I really admire his skills. Despite our disagreements he made a very reassuring post that he believed I was being both cautious and shown what I set out to. That meant a lot to me at the time.

A few cynical posters pointed out that it was suspicious that I was looking into things close to release, or maybe there had been sponsorship going on, and a couple of suggestions that the companies would like to sabotage one another. Cynical, yes, but reasonable to ask those questions - it is obviously fair to ask why this sort of thing happens, especially when there has been no secrets about the awkward situation in the past. I replied to a few personally, a couple in public, but there was no sponsorship, or any glorious intention for malice.

I made sure that they were given ample opportunity to respond, to address the issue or to refute and instead they denied. Being quiet on an issue I was certain of when it came to copying things without permission is... well, it's happened to me and I didn't like it - it cost me at University. Plus, I believe in following the rules - and I don't think that others should get away with it when they do not. It certainly wasn't good for RISC OS as a whole to allow people to get away with such things. As for going after Castle by disassembling the ROM and clearly not having better things to do - one commentator (who amused me greatly as they clearly had little idea what I did every day - or was just trying to be rude if they did) even said that the person reporting should do something useful for RISC OS. I have always looked in to things, to see what is being done. I looked at whether they had fixed the sprite redirection bugs, what other interesting things might be found, the style of sprites and messages (and whether they had compressed the messages) and a few other things. It is always interesting to look at such things. I am pretty sure if you look at the stuff I have done in my past, this inquisitiveness holds true, so I certainly don't think it is anything special (but then I'm biased!).

Anyhow, that happened late in the week. There was a weekend and it was all 'settled'. Not to my satisfaction - and I still disagree with their characterisation of the issue - but the parties involved were happy and as only the recipient of the code I had no further grounds to complain.

The argument Castle offered was that of semantics - that the code was in the section of the OS called the HAL, which was distinct from the Kernel, and thus the Kernel was not in violation. However, the Kernel links with it - the Kernel accesses the HAL's functions and the HAL boots the Kernel. As the two are linked, they are, in my reading of the terms, covered by the GPL. This is why the LGPL exists - to allow the linkage between components to be the boundary, not the whole. You cannot just take GPL components and place them in a shared library to isolate yourself from the GPL's requirements on the whole. Modules, and the HAL as a shared library for the Kernel, fall solidly into this category. In particular, you cannot argue that the HAL is a standalone component - it has no standalone qualities, because its sole purpose is to boot the Kernel and provide support for it.

Anyhow, the point is moot as that was 8 years ago. Because of the GPL issue, though, I received death threats and abuse by email. Later I received similar threats about EasySocket and my desire to not have a 32bit version. There is a saying about 'if they're shooting at you, you're doing something right', but... it gets tiring very fast.

A few months later I emailed Castle to ask for a copy of the EtherY driver, when I remembered that I had been told it was based on the GPL sources provided by the chipset manufacturer. Castle responded and sent me a copy, and at the same time asked who sent me a copy of the ROM. I declined their request, but asked whether they wanted feedback on the source for bug fixes and the like. They didn't reply.

In researching bits of this so that I am getting at least some of my facts right, I was amused to find a reference that I had completely forgotten about. One of the meetings I went to was to speak to Tematic (the group of ex-Pace developers who were contracted by Castle for RISC OS 5) about how we - RISCOS Ltd and Castle - could work together in the future. Things went ok, and so I passed over to them the summary lists of the changes that went into all of the components - which would be useful for evaluating the scale of work, and even if we were not working together would give pointers to areas of concern (the summary notes were similar to those that appeared in the Select Component Changes on the RISCOS Ltd site, albeit an earlier version of them).

Feeling at least slightly better, and that things would improve in this cold war, I returned home. And when I had got in, had a cup of tea, and started to chat to people, I found that the RISC OS hardware manufacturers had each been sent 'cease and desist' letters by Castle's solicitors, demanding they stop distribution of their products.

Last flails of a dying market. <laugh> It is amazing, it truly is.

I also found that I had complained to Castle because they were distributing my MimeMap module, but not including the source, or offer of the source, very shortly before the Kernel bits. I am pretty sure that other than one mail I never followed up on that.

Distrust and paranoia

Some developers would come direct to me for early allocations (which they were meant to do) because they didn't want Castle to be aware of products that they were working on. Others came to me very late asking for 'emergency' allocations because they didn't want to even chance that, which I didn't want to deal with, but had to because otherwise we ended up with a mess. I even did similar things for many smaller projects - I had a huge allocation request that I had collected over many months and sent to Alan at Pineapple in one lump. He didn't appreciate it, and asked me not to do it again - which is completely fair given that it was a pretty thankless task.

Thanks to Alan for his good work on handling the allocations over the years. <smile>

Back... to 32bitty things

Anyhow, to return to the matter at hand - the possibilities of maybe working together had gone back and forth over the years, those issues above aside. Eventually it was clear that we weren't going anywhere and pretty much gave up on trying to do anything actively towards it, and focused on the other parts of the problem - hardware abstraction, system improvements and bug fixes.

I tried porting Homeworld and decided 'I need a bigger application space. Can't do that without a restructuring of a lot of things. Can't do that without a 32bit OS. Best start on that then', and so I started on the Kernel and trying to make all the components 32bit. After I had mentioned that this was what I was working on (and had no dissent from any of the parties involved), I managed to get some bits of the system running in both emulation and on the RiscPC.

This is partly where the component based build system came in. Once I had got a basic Kernel up and running, and needed to build ROMs with more complex stuff in, I needed a way to say 'just give me the Kernel, a couple of support modules and a command line' easily. The new build system allowed this far more easily.

Early work

Just getting the Kernel to boot was interesting. Doing so on the RiscPC emulator wasn't too bad - but the emulator only provides some of the restrictions for an actual system start up. I began to provide my equivalent of the 'HAL' that Castle were so proud of. However, I did things significantly differently in that it didn't do anything but set the system up and allow it to manage memory (ok, there's some debugging streams in there as well, but that is all). The 'SystemInit', as I called it, provided the necessary initialisation to put the system into a shape where the Kernel could begin running (memory defined in the right way, processor set up, IRQs and hardware placed into a safe state), and provided a few routines for the manipulation of the CPU.

Some of this involved new code, and some involved taking small sections that were common in the Kernel and making them available in the SystemInit entry points. A lot of the memory initialisation code was written in C, again because it was simple. The interface between the ROM (Kernel plus modules) and the SystemInit code was defined, and was very simple. Maybe because I'm very simple <smile>.

Having got a very simple initialisation working on the RiscPC which booted to a command line, I began to work with the 'QEmu' ARM emulator system using the Versatile system emulation to provide a '32bit only' emulation system. This immediately hit problems. The QEmu emulator did not (at the time) support the 4 processor flags that ARM provided. The N and the Z flag were tied together - if the N flag is set, the Z flag cannot be. This may be fine most of the time, but certain PSR manipulations can do this - and at times that is what you want. The handling of certain memory table types were also wrong and needed patching as well.

I reported some of these issues to the mailing list along with the justifications. I think the responses were that my changes were insufficient for general cases (which I don't doubt) and that there were problems. I don't know if any were addressed - I stuck with my changes and continued to work with what worked.

The RiscPC emulator had its own bugs that I had to address whilst doing the testing. It didn't support the multiple domains - an ARM feature that let you mark an group of memory map entries as faulting or accessible based on the domain they are in, which made quite a few operations fail.

It was very useful, early in the work to use the emulator to have the emulator providing debug functions. Rather than writing debug output to the serial port, as we would in a real machine, special system call could be used which would write directly to the log file, and allowed easier debugging of the registers. I initially implemented string and register output functions, but quickly added in a formatted string writing call. This used the same format as I later used in the AsmDebug library, and made it possible to debug the very early initialisation.

For the QEmu Versatile emulation, I created new modules for the IRQ handling and a new video driver that understood how to initialise its video chip. The IRQ handling had - finally - been abstracted from the Kernel as part of the 32bit work, so that the Kernel no longer deals with the actual IRQ handling. A separate hardware module provides whatever IRQ implementation is necessary for the hardware.

The new SystemInit, IRQ handler and video controller were sufficient to get a working system up and running under emulation, debug the initialisation and show that the IRQ handler system that had been provided could work with different hardware. And, of course, that the video abstraction worked on other hardware, albeit emulated.

At the time I was working with Advantage 6 to try to get their A9 machine up and running. They were reluctant to share any changes to the Kernel, and whilst the abstraction of the interfaces continued - which would have made things significantly easier for their implementation, there was very little changed in the Kernel.

Things like the NVRAM had been abstracted, but the interfaces they used on their hardware only supported the local read - it would never actually write to the NVRAM. The last I remember was that that still wasn't working and the system would forget its configuration every boot.

I had tried to hand off some bits of the 32bit conversion to them to spread the work, but the initial module that I gave them to see how they got on - CDFS - took months for them to do anything with. Finally, fed up with having to wait, I spent an evening converting it to 32bit, and had it up and running by the next morning... just in time to find that their converted version had arrived in my mailbox.

The Kernel, video drivers and SystemInit were up and running quite well, and worked in the emulators - both ARMulator and QEmu - so I was reasonably confident. Timers came last, mainly because I had offered the design of the Timers interface out to Advantage 6 and others, to design and give some input on whilst I was working on other things. Aside from a little discussion about how applications might get at the timers for timing things, nothing came of it and I needed to move on that area of the code.

I threw something together, with the intention of revisiting it later once the dust had settled. The Timers module itself was therefore a bit of a mess and didn't really fit with what I was hoping to get done. I had intended to allow multiple timer inputs, with a manager that controlled the triggering of events - which would allow different chips with timers in to be supported for different purposes. Might have been overkill, but that's what I wanted.

In the end I just settled on a single driver module that provided all the time input. The Kernel claimed the timers once the core modules had started up. This was itself interesting. Most modules expect that timers will be running by the time that the system initialises them. Indeed, most will expect to be able to register for interrupts and the like. But the modules which provide those functions might not have initialised yet. Mostly the system had been set up so that modules could be initialised in any order, but there were limits to where this had been applied.

For example, the Podule Manager was expected to start early on (the second module) so that other modules could be found through it. Not only is this a bad special case which doesn't allow for other similarly 'special' modules to start, it means that you cannot provide multiple distinct areas for 'Podules' to come from (as might be the case if you provided them through a bridge or similar). The ROM ordering was specified such that the important modules would start early, but I wanted to be able to provide a single base ROM, with hardware drivers - specific to the hardware being used (or maybe not - they could still check) - at the end.

My solution to this was to introduce another flags word in the module flags. I dropped Castle an email with the details in, but quite honestly I had given up on them paying the blindest attention to anything I had to say. The new flag - 'PreInit' - indicated that the modules supplied had to be initialised before any others. The Kernel would initialise those modules, and then start its work proper on the main modules. This still didn't completely solve the 'one Podule Manager allowed' problem, but it let modules like the NVRAM (and IIC, as NVRAM used it), IRQ, Timers and Podule initialise separately, regardless of where they were in the module chain.

Because of this, IRQ and Timer initialisation was deferred until module pre-initialisation. This meant that some bits of code had to go - which is good because they were a pain anyhow. In particular the code that handled the key press on start up could not be handled by the Kernel. Previously the Kernel would initialise the timers and IOMD key input, and would watch for a short time for a key press.

A minor bug in this code had broken the initialisation on Stealth hardware at one point, but this had been quickly fixed at the time. In the new world order, though, the Kernel had no rights poking at any hardware, especially not IOMD hardware, and this had to go. Ripping it out was simple, because the code had all been made pretty self contained in earlier versions. It was replaced with a 'boot options' entry point in SystemInit which returns the necessary details about the booting.

This allows the very early initialisation to pass through the necessary information about start up, before the Kernel gets to see it. NVRAM reset, disabled boot, and others could be detected in other ways by the SystemInit code and passed on to RISC OS proper.

Previously, the Kernel had also directly read details about the NVRAM and the real time clock (both of which were implemented on the same chip). These had been separated out into modules - NVRAM and RTC respectively. With the other changes this made it even easier to defer the initialisation of IRQs and Timers until far later in the Kernel initialisation.

With IRQs removed from the Kernel's control this made things interesting for claimants of the interrupts - the OS_ClaimDeviceVector call. The IRQ module provided these, and had to dispatch calls in the same way that the Kernel had in the past. Mostly this was pretty simple, because the driver was for IOMD, and therefore much of the code could just come out of the Kernel. I wasn't particularly happy with the way that the entry point was managed, partly because it had to keep other code working, and partly because it still had hooks in for the Podule Manager, but it was working.

Debugging

The SystemInit entry points provide for some very simple diagnostics. Firstly, there is screen colouring during initialisation. This is used to indicate where the system has reached whilst it starts up, and is useful for debugging when things go wrong. The colours used were simplified and documented - making it clear that on other hardware a similar colour coding system should be used.

This would make it easier for users to discover what had gone wrong, although might be omitted entirely on some systems. Of course, the initialisation can do anything it likes, so this changing the screen colour might actually only change a section of the screen whilst a logo remains displayed, or even change the power light - full colour LEDs are now available that could do this easily.

There were also the entry points to control the processor, keeping to very simple operations that the system was used to - round-robin cache replacement algorithms and similar. These would change later, once the system was more stable, but at the time they were sufficient to bring the machine up. It would be more useful to use the more advanced caching and memory management available on later processors, but to dive into that in the first iteration would lead to madness <smile>.

Additionally, there was a bidirectional diagnostics channel, by which the Kernel could provide information about what it was doing. That is just a fancy way of saying that there were two entry points - one which wrote a character to a debug port, and one which read a character. On the IOMD and Versatile hardware this would use the serial port, which made it quite simple to debug.

As well as dedicated debug messages, the WRCHV output could be configured to go to the output, and the RDCHV input could be configured to wait for input. This meant that even without any modules at all, the Kernel could still communicate. Once ReadLine and CLIV had been made to work (and a few others) the Kernel would be interactive. For a while it ran like that without Timers or IRQs being enabled, and modules could be tested out. Simple things would break - like a SWI OS_Byte 19, which waits for VSync would hang the machine, because no VSync was ever going to arrive.

There were a host of bad things about the VSync handling which still hadn't been dealt with. Like the fact that the cassette timer was used to block the operation of SWI OS_Byte 19. Yes, there still was a cassette timer provided by the Kernel, and the cassette timer was controlled by the VSync. That would have been cleared away later, but it was still there when I last dealt with it.

Converting modules

With a functional Kernel booting, it was possible to start adding in modules. With ReadLine and CLIV present, other modules could be added piecemeal and tested in the real environment. Within the emulator it was easy to add some extra SWIs to provide logged output, and a new Text Area gadget to show the results as they happened. This meant that debugging modules became significantly easier.

The first pass for the modules themselves happened quite a bit before the Kernel was updated and the OS ran 32bit safe. The main macros in the Hdr:Proc file were updated so that they would do the right thing in 32bit or 26bit modes. Every module (where feasible) was updated so that they used this header. This meant that in many cases the entry and exit code that was previously a STMFD sp!, {..., lr}, LDMFD sp!, {..., pc} (maybe with ^ on the end) needed to be changed to use the Entry and EXIT macros.

The functions which restored the processor flags were examined and it was determined whether the restoration was necessary or not. If it was necessary to restore the flags, the macros EntryS and EXITS would be used. These additionally stacked the CPSR if built for 32bit. This had the side effect that the registers on the stack could change depending on the type of build being performed. So any LDR rx, [sp, #n] sequences would need to change depending on the mode. This was catered for by having a variable, Proc_RegOffset which contained the offset from the stack pointer to the first stacked register. As the Entry macros could also reserve space on the stack if necessary, this was quite useful - it rationalised the entry and exit of most functions.

There were other functions that were used to perform different operations that were commonly used. For example, EXITVS would set the V flag (not exit if V set, as you might think), or PullEnv which would restore the registers on entry, but not return.

Many functions which had previously used awkward constructs were modified so that they could use these balanced calls. In some cases this meant that the calls were less efficient - they wrote to the stack and unstacked registers and returned, rather then just skipping over the registers and returning, or similar. That's not a big deal most of the time. The entry and exit sequences for modules had to be checked, as did all of the registered entry points - vectors, filters, callbacks and the like.

In some modules the code, when built for 26bit, was exactly the same as it was before the changes - because the code had already been well structured, didn't use register preservation except where necessary (or was too complex for me to spot that it wasn't necessary!), and it never did anything 'clever' with the stack.

Other modules, like BASIC were almost completely 32bit clean from the outset and despite not having the same stack model as any other component, didn't need any significant changes. Some modules were done in phases, like FontManager and FileSwitch, as they were complex and tackling them in one go was difficult.

There was a quick 'cheat sheet' for these operations, which I put together so that I could remember what the operations were after I had decided on them (many were macros that already existed, but I had to make a conscious decision to retain and continue using them). This included a number of Grep command lines to use to spot the problematic operations.

Many of the conversion phases were the result of searching for a group of known problematic cases and making decisions for each one that was found as to how to deal with it. In some cases they were easy - setting and clearing flags is often less difficult if you don't care about the state of the other flags. In other cases, the code had to be restructured to keep things working the way they did but with different operations.

Some of the places where code was generated became interesting. Usually this was pretty controlled, such as code variables, which had a known sequence which didn't care about processor flags, so was safe as it was. SpriteExtend also generates code, and is usually fun when it needs updating, but the code generation was already 32bit safe - determining that was a little tedious but as there weren't any macros which would generate the problematic instructions it wasn't that hard.

C code for modules often had some support assembler routines. These were often the same sorts of operations. For example, you would often find a a 'drop to USR mode, trigger interrupts, return to SVC mode' function in the network modules (for pretty rough reasons that aren't worth going into here), or you might have code that prevented reentry by turning IRQs off and then re-enabled them after the dangerous operations. These were collected into an Asm library which could be linked with the modules.

This library contained the correct, safe, code for whichever mode they were compiled, and they meant that some modules ended up with no assembler source at all. Before adding anything to the library I had to consider how often it would be used, and whether it could be implemented without an assembler veneer. In many cases there wasn't actually a need for an assembler function, so just replacing the assembler with a C function sufficed.

In other cases, the assembler was present only to get around failings in the CMHG veneer generation - failings that had been addressed in CMunge, so were easier to address by changing to its veneer generation.

CMunge itself was converted to use 32bit code by Robin and myself some time earlier, and was pretty much bullet proof when it came to its use in generating veneers for the C modules. It was nice to rely on it and know that it would do the job.

The one-off assembler that was needed for some modules, and the code that needed to interwork assembler modules with C in them, used a new set of headers in Hdr:ProcAPCS, to provide a standard entry and exit sequence. The APCS entry sequence had to be just right or the back traces would not be produced properly. As I had spent a lot of time getting the privileged mode back trace (through 'PBTS') working properly so that we could report where the problems were, I was keen to retain this where possible.

The APCSEntry and APCSExit macros allowed the code to be traced, and preserved registers as necessary - in 26bit builds it would restore flags and in 32bit builds the flags would be ignored. The macros set up 'fp' properly, and reserved local storage if required.

Many of the modules were easy conversions. Others were pains - CDFS took me only an evening to make 32bit safe. WindowManager took about 4 days. Most modules missed a few things in the conversion, or got something wrong which was found later in testing. It is pretty much inevitable that some things will go wrong with a complex system like this, but much of the preparation work that had gone on before made it significantly easier.

There is some fun in my notes as well - one note for the WindowManager has the summary "Separated Workspace and macros into individual files for ease.", but the 'detail' section says "Getting annoyed at huge files with lots of different things in? Why not rip them to shreds and end up with an organised source structure? You too can have a huge number of sensibly named files instead of the flabby mess of Wimp0x's. Only 15.99 a month from JML!"

The WindowManager was also more complex during the preparation work, as I mentioned in the earlier rambles - the workspace that the WindowManager used was in a Dynamic Area and therefore could be placed anywhere in memory. That meant that it could have the top bit set, even in a 26bit system. As many of the checks in the WindowManager were for negative window handles, this caused problems. I came up with a quite nice mapping that ensured the window handles followed the normal rules, but could still live in high memory, and at the same time changed the comparisons that looked for negative numbers to only look for the specific numbers that had been documented.

The WindowManager has support for handling the preservation of floating point state when tasks are switched. That's great, except that when you don't have a Floating Point Emulator module that is 32bit safe you cannot run the Desktop. I modified the WindowManager so that all the Floating Point code was actually optional, and could be enabled and disabled through build time switches. This allowed the system to be tested and used even when the FPEmulator wasn't present. Of course, I updated the module to be 32bit shortly afterwards, so it was made a little redundant, but I still like build switches - they at least give you options.

There were also interfaces that needed to be redefined to take account of the 32bit code. As well as the interfaces that were obvious - register buffers, registered callbacks and the like - there were interfaces you would otherwise have completely forgotten about. SWI Sound_QSchedule has the option to use a callback function, rather than a SWI number, and differentiates them by the SWI number having the top 4 bits set. Clearly this cannot work in 32bit mode and because this is the only way that the special operations can be flagged, the interface cannot be made 32bit safe at all.

In this case, I created a new SWI, which was easy enough to do. It is unlikely that many applications would actually have used it, but !Maestro would be one of those applications (even if it wouldn't have used that particular part of the API). Removing one of the core applications that were distributed with the Operating System would be guaranteed to annoy someone.

You could probably bet that someone somewhere had thought themselves very cunning for timing their game off the SoundScheduler clock, and being completely outraged if the call were deprecated with no replacement.

Similarly, there were internal constraints that needed to be resolved in some modules. I have already mentioned the WindowManager's manipulation of window handles, which needed to change as (even without 32bit) the workspace for the WindowManager could be anywhere in memory, including where the top bit was set (which would make it a negative signed number). All of the places where the WindowManager checks for a negative number to mean something special - top of the window stack, icon bar, background of the window (instead of icon number), and so on - needed to change to check more carefully.

In each case this was a matter of reviewing the PRMs and any related updated documentation through application notes and the like, checking what the documented behaviour was, and ensuring that the code matched the description. If the description allowed for any negative number (I don't remember where, but I'm sure there was one), it was reduced to a negative -1, -2, -3 (which were the most likely uses of the negative numbers). SWI Wimp_GetPointerInfo can return icon numbers that are lower than -3, if I am remembering right - if the pointer is over the furniture. All these were meant to be able to be returned but weren't expected to be passed to a WindowManager SWI call, so they shouldn't matter.

The last set of modules to be converted were the printer driver modules. These hadn't actually been touched by any part of the RISC OS work up till then, and they were in a very bad state for it. Many hadn't even been updated for the new Makefile system, and this had to be done first. By the time that they came to be updated, the BTS system was in full use throughout the system and it was easy to insert more detail into the printer drivers.

Adding the BTS data in the builds made for a significantly easier time of debugging the system. On failures within the WindowManager, the redirection system would be put back to a sensible state and it was rarely fatal (which is surprising given how complicated the printing system is and how many things are redirected). Usually it was simple to issue a *BTSDump -a to get a backtrace of where the last problem was, and be able to see the memory and operations which were being manipulated.

I did fix a few minor things in the process. For example, PDriverPS would complain if you tried to print without ever having seen the !Printers application - it wanted to load the prologue and other resources from within it. Normally this wouldn't be an issue, but !Draw allowed EPS ('Encapsulated PostScript') export in its save menu, which it implemented through printing to a file through the PDriverPS modules.

I added a few resources to the module so that if the !Printers resource could not be found it would use them instead - and then you could save to EPS from !Draw without having to know anything about how it was doing it. I'll make not comment on how reliable the EPS output was or the validity of the code it produced - that was a whole separate minefield that I didn't really want to get into at the time!