Detecting Risc PC vs earlier machines in assembly code

chat about arc/risc pc gaming & RISC OS software here (NOT the core OS!)Related forum: adventures


Post Reply
User avatar
myelin
Posts: 726
Joined: Tue Apr 26, 2016 9:17 pm
Location: Mountain View, CA, USA
Contact:

Detecting Risc PC vs earlier machines in assembly code

Post by myelin » Wed Mar 06, 2019 9:25 pm

I have a puzzle to solve...

I want to make the Arcflash bootloader work on everything from an original A305 through a StrongARM-equipped Risc PC. It runs as a ROM, and doesn't include RISC OS, which presents some interesting challenges. In particular, it looks like the Risc PC memory map puts the rom at address zero, whereas on the Archimedes class machines it's at 0x3800000. I can deal with this, but I'll have to be able to detect whether I'm running on an Arc or RPC without much in the way of hardware probing (although it's possible that MEMC will let me access the IO controller space on startup -- I'm not quite sure whether it just maps the ROM on top of the mapped memory space, or if it repeats it across the entire memory map).

Has anyone already done such a thing?
SW/EE from New Zealand, now in Mountain View, CA, making BBC/Electron hardware projects for fun.
Most interesting: Arcflash, FX2+PiTubeDirect Tube/Cartridge adapter, USB cart interface.

User avatar
SarahWalker
Posts: 1196
Joined: Fri Jan 14, 2005 3:56 pm
Contact:

Re: Detecting Risc PC vs earlier machines in assembly code

Post by SarahWalker » Wed Mar 06, 2019 10:14 pm

You could use the CP15 ID register (assuming you can handle an illegal instruction exception on ARM2/250 machines); if it returns ARM6 or later then that's a dead giveaway that you aren't on MEMC-based hardware.

I don't think MEMC will allow you to access IO controllers without shutting the low ROM mapping off. The datasheet states :
To ensure that the processor always finds valid code [...] MEMC continually enables ROM.
and
To restore the normal memory map, the processor must first perform a memory access with the address lines A[25] and A[24] both LOW, and then perform a memory access with address line A[25] HIGH.
which seems to suggest you're out of luck here; even if accessing IO space didn't shut the ROM off, you'd just read ROM data anyway.
Last edited by SarahWalker on Wed Mar 06, 2019 10:18 pm, edited 3 times in total.

User avatar
SarahWalker
Posts: 1196
Joined: Fri Jan 14, 2005 3:56 pm
Contact:

Re: Detecting Risc PC vs earlier machines in assembly code

Post by SarahWalker » Wed Mar 06, 2019 10:20 pm

Another possibility might be to try reading from 0x1000000 - on IOMD this is explicitly 'extension ROM', which at the very least would differ from normal ROM, whereas on MEMC this might mirror? It's not clear from the MEMC datasheet which ROM is continually enabled, if it's always high ROM (0x3800000-0x3ffffff) then this should work.

Having said this, the ARM7500 datasheet suggests that a single nROMCS signal is used for both ROM regions on that chip, so this may mirror on at least A7000 hardware.
Last edited by SarahWalker on Wed Mar 06, 2019 10:22 pm, edited 1 time in total.

Phlamethrower
Posts: 112
Joined: Fri Nov 24, 2017 1:35 pm
Contact:

Re: Detecting Risc PC vs earlier machines in assembly code

Post by Phlamethrower » Wed Mar 06, 2019 10:48 pm

Detecting Archimedes vs. newer machines is easy - the MRS & MSR instructions are NOPs in ARMv2, so you can do something like:

Code: Select all

MOVS R0,#0
MRS R0,CPSR
CMP R0,#0
; NE = IOMD-era, EQ = IOC-era
(I'm using MOVS for the first instruction instead of MOV just to guarantee that one of the PSR bits is set - just in case someone sees this post and expects it to work in user mode, where all the PSR bits might be clear)
Last edited by Phlamethrower on Wed Mar 06, 2019 10:52 pm, edited 1 time in total.

User avatar
myelin
Posts: 726
Joined: Tue Apr 26, 2016 9:17 pm
Location: Mountain View, CA, USA
Contact:

Re: Detecting Risc PC vs earlier machines in assembly code

Post by myelin » Wed Mar 06, 2019 10:57 pm

SarahWalker wrote:
Wed Mar 06, 2019 10:20 pm
Another possibility might be to try reading from 0x1000000 - on IOMD this is explicitly 'extension ROM', which at the very least would differ from normal ROM, whereas on MEMC this might mirror? It's not clear from the MEMC datasheet which ROM is continually enabled, if it's always high ROM (0x3800000-0x3ffffff) then this should work.
I like this idea... I'll try some reads from different parts of the memory map to see what MEMC1A really does. If it just holds nROMCS low and leaves nVIDRQ, nIORQ etc high, I'll see the ROM repeated through the whole memory map on MEMC systems, whereas an IOMD will show registers, RAM etc at various places. All I need is an IOMD/ARM7500 register that is set to a known value on startup, and I can set a different value at the corresponding ROM location and differentiate based on that.

It looks like the undefined instruction vector lives at address 4 on ARMv2, so that approach should work well too when the ROM is mapped in at 0.
SW/EE from New Zealand, now in Mountain View, CA, making BBC/Electron hardware projects for fun.
Most interesting: Arcflash, FX2+PiTubeDirect Tube/Cartridge adapter, USB cart interface.

User avatar
myelin
Posts: 726
Joined: Tue Apr 26, 2016 9:17 pm
Location: Mountain View, CA, USA
Contact:

Re: Detecting Risc PC vs earlier machines in assembly code

Post by myelin » Wed Mar 06, 2019 11:10 pm

Phlamethrower wrote:
Wed Mar 06, 2019 10:48 pm
Detecting Archimedes vs. newer machines is easy - the MRS & MSR instructions are NOPs in ARMv2, so you can do something like:

Code: Select all

MOVS R0,#0
MRS R0,CPSR
CMP R0,#0
; NE = IOMD-era, EQ = IOC-era
(I'm using MOVS for the first instruction instead of MOV just to guarantee that one of the PSR bits is set - just in case someone sees this post and expects it to work in user mode, where all the PSR bits might be clear)
Perfect! That's a nice easy way to do it.
SW/EE from New Zealand, now in Mountain View, CA, making BBC/Electron hardware projects for fun.
Most interesting: Arcflash, FX2+PiTubeDirect Tube/Cartridge adapter, USB cart interface.

User avatar
jgharston
Posts: 3673
Joined: Thu Sep 24, 2009 11:22 am
Location: Whitby/Sheffield
Contact:

Re: Detecting Risc PC vs earlier machines in assembly code

Post by jgharston » Thu Mar 07, 2019 3:02 am

myelin wrote:
Wed Mar 06, 2019 9:25 pm
In particular, it looks like the Risc PC memory map puts the rom at address zero, whereas on the Archimedes class machines it's at 0x3800000.
On RESET ROM is at &00000000, otherwise there would be no way to execute the RESET code as RESET does PC=0.

Technically, on RESET, ROM is *everywhere*, once the jump from &0000000 to &03800000 has executed the memory map goes to normal.

Code: Select all

$ bbcbasic
PDP11 BBC BASIC IV Version 0.25
(C) Copyright J.G.Harston 1989,2005-2015
>_

User avatar
myelin
Posts: 726
Joined: Tue Apr 26, 2016 9:17 pm
Location: Mountain View, CA, USA
Contact:

Re: Detecting Risc PC vs earlier machines in assembly code

Post by myelin » Thu Mar 07, 2019 7:07 am

jgharston wrote:
Thu Mar 07, 2019 3:02 am
Technically, on RESET, ROM is *everywhere*, once the jump from &0000000 to &03800000 has executed the memory map goes to normal.
That's right, although I believe that the ROM is *always* mapped in at zero on a Risc PC, as opposed to on an Arc, where it's only there until MEMC sees an access with one of the higher order bits set. So on a Risc PC I want to jump into the startup code with origin=0, whereas on an Arc I want to jump to some point after &3800000. Anyway it looks easy with Jeffrey's trick, so this is no longer a problem :)

Next question will be how to build just the IOMD HAL and not the rest of RISC OS, so I can avoid having to redo all my startup and video code for the RPC bootloader!
SW/EE from New Zealand, now in Mountain View, CA, making BBC/Electron hardware projects for fun.
Most interesting: Arcflash, FX2+PiTubeDirect Tube/Cartridge adapter, USB cart interface.

User avatar
jgharston
Posts: 3673
Joined: Thu Sep 24, 2009 11:22 am
Location: Whitby/Sheffield
Contact:

Re: Detecting Risc PC vs earlier machines in assembly code

Post by jgharston » Fri Mar 08, 2019 1:03 pm

myelin wrote:
Thu Mar 07, 2019 7:07 am
jgharston wrote:
Thu Mar 07, 2019 3:02 am
Technically, on RESET, ROM is *everywhere*, once the jump from &0000000 to &03800000 has executed the memory map goes to normal.
That's right, although I believe that the ROM is *always* mapped in at zero on a Risc PC, as opposed to on an Arc, where it's only there until MEMC sees an access with one of the higher order bits set.
That can't be right as RISC OS uses 0-16K as workspace and 16K-32K usable as scratch space, so needs to be read/write, and the FIQ code is written directly to zero page at the FIQ entry, the 'F' part meaning 'F'ast, part of that being no jumps away from the entry point.

Looking at the Castle RISC OS sources shows ROM code at &00000000 jumping to high memory, doing some tests, then mapping the ROM out of low memory, in all build cases.

Code: Select all

$ bbcbasic
PDP11 BBC BASIC IV Version 0.25
(C) Copyright J.G.Harston 1989,2005-2015
>_

User avatar
SarahWalker
Posts: 1196
Joined: Fri Jan 14, 2005 3:56 pm
Contact:

Re: Detecting Risc PC vs earlier machines in assembly code

Post by SarahWalker » Fri Mar 08, 2019 6:38 pm

ROM is always mapped at 0 in the RiscPC's physical address space. RISC OS maps it to 0x3800000 in the virtual address space using the MMU.

On MEMC systems, 0x2000000-0x3ffffff are never subject to translation and hence 0x3800000 is the physical location of ROM.


User avatar
SarahWalker
Posts: 1196
Joined: Fri Jan 14, 2005 3:56 pm
Contact:

Re: Detecting Risc PC vs earlier machines in assembly code

Post by SarahWalker » Fri Mar 08, 2019 9:42 pm

That would require RISC OS to be present and running. myelin is coding bare metal.

User avatar
myelin
Posts: 726
Joined: Tue Apr 26, 2016 9:17 pm
Location: Mountain View, CA, USA
Contact:

Re: Detecting Risc PC vs earlier machines in assembly code

Post by myelin » Tue Mar 19, 2019 5:15 pm

So this all worked splendidly. I now have a build of my bootloader which fits in 384kB, and consists of:

- first 336kB: cut-down RISC OS IOMD32 build with just kernel, HAL, and some IO modules
- next 8 bytes: pointers to RPC and Arc versions of the bootloader
- Arc (MEMC) bootloader
- RPC (IOMD) bootloader

The RO build executes Jeffrey's CPU-detection code in 'start' (HAL/IOMD/s/Top) and jumps into the Arc bootloader if it detects an ARMv2 chip. Otherwise it continues with the RO init process, then jumps to the RPC bootloader instead of starting the configured language module. If the bootloader isn't present (&FFFFFFFF where the pointer should be) it starts the Supervisor instead, so if you're curious to see this in action, try padding risc_os.bin out to 2MB (with 0xFF bytes) and running it in RPCEmu -- it should get you into the supervisor.

The Arc bootloader is bare metal, whereas the RPC bootloader uses kernel/HAL functions for text display etc. It copies itself down to &8000 and runs from there, using more or less the same C environment. Right now it's running in user mode so SWI calls don't corrupt R13/R14, but I might just add those two registers to the 'clobbers' list in my asm volatile calls and keep it in SVC mode so I can access timer registers directly.
SW/EE from New Zealand, now in Mountain View, CA, making BBC/Electron hardware projects for fun.
Most interesting: Arcflash, FX2+PiTubeDirect Tube/Cartridge adapter, USB cart interface.

Post Reply