Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Acorn C 2.0 crashes in B-Em #233

Open
egrath opened this issue Aug 15, 2024 · 25 comments
Open

Acorn C 2.0 crashes in B-Em #233

egrath opened this issue Aug 15, 2024 · 25 comments

Comments

@egrath
Copy link
Contributor

egrath commented Aug 15, 2024

Problem
Acorn C 2.01A for the ARM evaluation board crashes in B-Em (compiler and linker, both crash) with the following message:

image

How to reproduce
Download the SCSI image from: https://garm.twilightparadox.com/nextcloud/s/YsMKPeoi4GL97M4 which has Acorn C 2.01A installed
Turn on the ARM 2nd processor, mount the image and run:

*MOUNT 1
*LIB :1.$.LIBRARY
*DIR ARM.BENCH
*cc -super -o hellow hellow

Expected result
Compiler produces a working output without crashing

Notes

  • Manual says that the floating point emulator needs to be activated before running the compiler but this is not necessary (at least in BeebEm). Running the floating point emulator (fpe) on B-Em results another crash (error), this time:

image

  • Works in BeebEm 4.17
  • Does not work in BeebEm > 4.17 (regress introduced somewhere along the road)
@egrath
Copy link
Contributor Author

egrath commented Aug 18, 2024

Update: BeebEm's regress in the ARM emulation has been fixed (in case the emulation code has been taken from there) though there is still some problem with the Y2K RTC workaround that causes a problem for the compiler.

@SteveFosdick
Copy link
Collaborator

Did you try to load FPE after the error had already occurred with the compiler? If so, it may be a red herring. Starting FPE after just setting the directories, but not running the compiler, gives:
fpe
i.e. it seems to install fine.

I am glad the BeebEm regression is fixed but I don't think b-em uses that code and the symptom seems to be different.

@SteveFosdick
Copy link
Collaborator

B-Em actually has two ARM emulations: the ARM1, which is selected with the ARM evaluation system, and a Sprow ARM which, by default, starts ARM BASIC. Attempting to run the compiler there gives:
issue233a
But perhaps that is because ARM BASIC is the wrong environment for the compiler to run in. Where I am going with this is that if the Sprow ARM would run the compiler correctly, I could trace both, i.e. which ARM instructions each executes, and see where they diverge. I'll try the Sprow ARM emulation with the ROM from the ARM evaluation board.

@egrath
Copy link
Contributor Author

egrath commented Aug 19, 2024

Did you try to load FPE after the error had already occurred with the compiler?

Yes you are right, that was my fault. Running fpe before the compiler works.

@SteveFosdick
Copy link
Collaborator

On the fpe, I wouldn't say it was your fault - it just seems that the aborted run of the compiler has left things in a a strange state.

The ARM eval ROM doesn't work on the Sprow ARM emulation. Reading up on the ARM, it may be that the ARM eval ROM assumes 26-bit addresses where R15 also contains the flags, and the newer Sprow ARM does not offer compatibility with the 26-bit mode.

There are some possibilities as to how work out what is going wrong:

  1. A test suite for ARM. Do we have have one?
  2. Get BeebEm to trace all ARM instructions and have B-Em do the same. The B-Em debugger can already do this but I don't know if BeebEm can do the same. Obviously they would need to be in the same format. Then check for when they diverge.
  3. Likewise with instruction tracing, but try to have B-Em stop when the "branch though 0" exception is hit and then see if something is obviously going wrong in the run up to it.

@egrath
Copy link
Contributor Author

egrath commented Aug 19, 2024

As far as I know there is no test suite publically available for the original ARM1 processor. But there is one for the ARM2 if that helps, it's from the Amber project, which reimplemented the ARM2 in Verilog. May that help?

https://github.com/freecores/amber/tree/master/hw/tests

@hoglet67
Copy link
Contributor

Some other useful data points might be to test:

  • the ARM2 core in PiTubeDirect (Core 12) which uses the MAME ARM2 code
  • the ARM2 core in the Matchbox Co Pro (Core 12) which uses the Amber23 core

I'll try to do that tomorrow.

Dave

@SteveFosdick
Copy link
Collaborator

Ok, I modified the memory read/write functions to trap to the debugger when attempting to read or write an invalid memory address and also had the debugger trace instructions to a file. The trap was not triggered by the ROM or any of the preparation command but was triggered by the compiler:

cpu ARM: Bad Read Long at 00000074

the 74 is the PC, not the location being read. The last instructions logged were:

        00000848 e3a00001 mov r0, #1 003fe200 00000000 00000064 00049590 00000000 00000040 0009d76c 00008000 00000001 ffffff00 00000009 003fff90 01000000 0004aa84 80041954 00000850 00000000 00000000 00000000 00008000 01000000 00000020 60000d4f 01000000 00000020 01000000 00000de4 N:0 Z:1 C:0 V:0 I:0 F:0 M1:1 M0:1 (SVC)
        0000084c e58b000c str r0, [r11, #12] 00000001 00000000 00000064 00049590 00000000 00000040 0009d76c 00008000 00000001 ffffff00 00000009 003fff90 01000000 0004aa84 80041954 00000854 00000000 00000000 00000000 00008000 01000000 00000020 60000d4f 01000000 00000020 01000000 00000de4 N:0 Z:1 C:0 V:0 I:0 F:0 M1:1 M0:1 (SVC)
        00000850 e8bd0006 pop {r1,r2} 00000001 00000000 00000064 00049590 00000000 00000040 0009d76c 00008000 00000001 ffffff00 00000009 003fff90 01000000 0004aa84 80041954 00000858 00000000 00000000 00000000 00008000 01000000 00000020 60000d4f 01000000 00000020 01000000 00000de4 N:0 Z:1 C:0 V:0 I:0 F:0 M1:1 M0:1 (SVC)
        00000854 eafffe04 b &6c 00000001 0009d76c 00000000 00049590 00000000 00000040 0009d76c 00008000 00000001 ffffff00 00000009 003fff90 01000000 0004aa84 80041954 0000085c 00000000 00000000 00000000 00008000 01000000 00000020 60000d4f 01000000 00000020 01000000 00000dec N:0 Z:1 C:0 V:0 I:0 F:0 M1:1 M0:1 (SVC)
        0000006c e79af10b ldr pc, [r10, r11, lsl #2] 00000001 0009d76c 00000000 00049590 00000000 00000040 0009d76c 00008000 00000001 ffffff00 00000009 003fff90 01000000 0004aa84 80041954 00000074 00000000 00000000 00000000 00008000 01000000 00000020 60000d4f 01000000 00000020 01000000 00000dec N:0 Z:1 C:0 V:0 I:0 F:0 M1:1 M0:1 (SVC)

So it has executed a branch. Looking at the code leading up to the branch:

    00000800 e92d0006 push {r1,r2}
    00000804 e20010ff and r1, r0, #255
    00000808 e3a00002 mov r0, #2
    0000080c ef000009 svc #9
    00000810 e59fb0e8 ldr r11, [pc, #232]
    00000814 e24bbc02 sub r11, r11, #512
    00000818 e3a0a001 mov r10, #1
    0000081c e7cba001 strb r10, [r11, r1]
    00000820 e28bbc01 add r11, r11, #256
    00000824 e201a00f and r10, r1, #15
    00000828 e1a0000b mov r0, r11
    0000082c e08bb20a add r11, r11, r10, lsl #4
    00000830 e58b2008 str r2, [r11, #8]
    00000834 e3a01000 mov r1, #0
    00000838 e58b1000 str r1, [r11]
    0000083c e2400c41 sub r0, r0, #&4100
    00000840 e080050a add r0, r0, r10, lsl #10
    00000844 e58b0004 str r0, [r11, #4]
    00000848 e3a00001 mov r0, #1
    0000084c e58b000c str r0, [r11, #12]
    00000850 e8bd0006 pop {r1,r2}
    00000854 eafffe04 b &6c
    00000858 e3800c01 orr r0, r0, #256
    0000085c e48d0000 str r0, [sp], #256

To me that looks like it could be valid code. After the branch:

    0000006c e79af10b ldr pc, [r10, r11, lsl #2]
    00000070 000000e8 andeq r0, r0, r8, ror #1
    00000074 03001270 movweq r1, #624
    00000078 00000134 andeq r0, r0, r4, lsr r1
    0000007c 0000015c andeq r0, r0, r12, asr r1
    00000080 00000178 andeq r0, r0, r8, ror r1
    00000084 00000968 andeq r0, r0, r8, ror #18
    00000088 000001a0 andeq r0, r0, r0, lsr #3
    0000008c 00000278 andeq r0, r0, r8, ror r2
    00000090 0000034c andeq r0, r0, r12, asr #6
    00000094 0000039c muleq r0, r12, r3
    00000098 00000434 andeq r0, r0, r4, lsr r4

it looks less like valid code to me. It looks to be using the mul instruction that is ARM2. I realise from this that there some things I am not sure about. According to WikiChip, the ARM1 was produced in very small numbers which would be consistent with it being in the ARM Evaluation System but is that right? Is this compiler ARM1 code or ARM2?

@SteveFosdick
Copy link
Collaborator

Doing some reading, it seems the ARM evaluation system is definitely ARM1 but on the possibility that the C compiler is expecting ARM2 I looked at WikiChip (https://en.wikichip.org/wiki/arm/armv2) and the differences seem to be confined to the four multiply instructions (MUL, MULS, MLA, MLAS) and the instructions for communicating with a co-processor.

Interestingly, the B-Em ARM emulation had code for the multiply instructions commented out. Adding a debug message if there is an attempt to use these gave this in the log:

19/08/2024 22:56:58 DEBUG arm: MUL instruction E0020291 at 00043E0C
19/08/2024 22:56:58 DEBUG arm: MUL instruction E0010193 at 00043E1C
19/08/2024 22:56:58 DEBUG arm: MUL instruction E003039E at 00043E2C
19/08/2024 22:56:58 DEBUG arm: MUL instruction E004009B at 00043E40
19/08/2024 22:56:58 DEBUG arm: MUL instruction E0000091 at 00048290
19/08/2024 22:56:58 DEBUG arm: bad ARM read long of 00FFFE49 at 0000006C
19/08/2024 22:56:58 DEBUG arm: bad ARM read long of FFFFFFFC at FFFFFFF8

@hoglet67
Copy link
Contributor

hoglet67 commented Aug 20, 2024

A couple of observations:

  • this is dated July 14 1988
  • the disk image includes an arthur.h header file

So this was designed to run on Arthur 1.2 on the first generation of Archimedes machines (A305/A310/A440) which were ARM2.

RobC has successfully run this on the Matchbox Co Pro ARM Eval system, but that's actually also an ARM2 core, so is a bit misleading. See this link.

It's possible this would run on the original ARM Eval system if the multiply instruction caused an undefined instruction trap and was emulated in software.

Maybe that's the difference here....

What does b-em do with an ARM2 multply instruction?

What does beebem do with an ARM2 multply instruction?

What does the real ARM1 CPU do with an ARM2 multiply?

@chrisn
Copy link

chrisn commented Aug 20, 2024

BeebEm uses David Sharp's Tarmac emulator, which does emulate MUL, also SWP. Related BeebEm issue: stardot/beebem-windows#140

@hoglet67
Copy link
Contributor

hoglet67 commented Aug 20, 2024

For reference, the documentation for the original ARM1 CPU:
https://archive.org/details/arm-cpu-software-manual-version-1.0/mode/2up

(thanks to Graham Toal for scanning this, and BigEd for uploading)

My reading of this is that the opcode that became multiply in ARM2 would is a ligitimate AND instruction in ARM1. So I don't think it would trap.

@hoglet67
Copy link
Contributor

hoglet67 commented Aug 20, 2024

Just tried this on the Matchbox Co Pro:
capture30

It looks like the compile phase has run to completion, but the linker has barfed.

Same error on PiTubeDirect.

This is using ADFS 1.50... I wonder if the lack of dates in ADFS is throwing it? [ I think RISC-OS reuses the load/exec addresses as dates

@egrath
Copy link
Contributor Author

egrath commented Aug 20, 2024

Should have nothing to do with the load/exec address reused as timestamps. If the 12 upper bits of the load/exec address are 1's, it's interpreted as an timestamp as then the load/exec address is invalid (out of addressable memory range).

image

The error you are seeing is (at least in BeebEm) due to some Y2K fix and the linker "thinks" that the timestamp in the library is in the future and refuses to use it.

@hoglet67
Copy link
Contributor

Ah OK, thanks.

I was able to fix the time issue by setting the year to 1990 (rather than 1924!)

This is PiTubeDirect (latest indigo-alpha8 with multiply):
capture34

And here's a build with multiply commented out:
capture32

So it does look like this wouldn't actually run on a real ARM1.

Dave

@egrath
Copy link
Contributor Author

egrath commented Aug 20, 2024

Very interesting case, as the compiler explicitely has switches to produce binaries for the Brazil supervisor used in the ARM evaluation board ("-super"). The obvious question if this should be fixed at all in B-Em arises as fixing it would definitely would violate the precision of the emulation as it's not a emulated ARM1 anymore.

@SteveFosdick
Copy link
Collaborator

SteveFosdick commented Aug 20, 2024

Should have nothing to do with the load/exec address reused as timestamps. If the 12 upper bits of the load/exec address are 1's, it's interpreted as an timestamp as then the load/exec address is invalid (out of addressable memory range).
...
The error you are seeing is (at least in BeebEm) due to some Y2K fix and the linker "thinks" that the timestamp in the library is in the future and refuses to use it.

B-Em has Y2K fixed and as-original versions of both the Master MOS ROMs (w/MOS 3.22 and w/MOS 3.52 are the fixed versions). Of course, the linker may also have a Y2K bug.

The "ARM Evaluation System" model will use standard MOS 3.20 but you can get 3.22 by selecting "BBC Master 128 w/MOS 3.22" and then selecting ARM separately as the tube.

@SteveFosdick
Copy link
Collaborator

SteveFosdick commented Aug 20, 2024

So it does look like this wouldn't actually run on a real ARM1.

When you commented out multiply, did that include the if ((opcode & 0xF0) == 0x90) or similar test, i.e. so that would execute as an AND/ANDS/EOR/EORS instruction?

The error with multiply commented out on PiTubeDirect is not the same as the error with B-Em. Also, uncommenting the implementation of multiply in B-Em does not fix the problem. Chris mentions the SWP instruction. Maybe there are other differences between ARMv1 and ARMv2 that WikiChip did not mention?

@hoglet67
Copy link
Contributor

When you commented out multiply, did that include the if ((opcode & 0xF0) == 0x90) or similar test, i.e. so that would execute as an AND/ANDS/EOR/EORS instruction?

Yes, that's exactly what I did.

The error with multiply commented out on PiTubeDirect is not the same as the error with B-Em.

I was wondering if that's just because the system ended up jumping "into the weeds" so the exact error might vary depending on the memory contents. But is could very well be something else.

Also, uncommenting the implementation of multiply in B-Em does not fix the problem.

OK, so it looks like there is something else going on in b-em.

Chris mentions the SWP instruction. Maybe there are other differences between ARMv1 and ARMv2 that WikiChip did not mention?

SWP was apparently added in ARM3 (1989) so I guess that's not likely to be used in a C compiler from 1988.

Dave

@hoglet67
Copy link
Contributor

OK, let me try to look at the b-em issue....

  1. Check I can reproduce the error in the head post of this thread.

Yes:
Screenshot from 2024-08-20 18-01-23

  1. Check for environment differences between PiTubeDirect and B-em?

Look's like b-em is using the 8th August 1986 Brazil version of the ARM Tube ROM, which is different to PiTubeDirect:

Screenshot from 2024-08-20 18-02-22

So lets switch to than original 6th June 1986 version:
Screenshot from 2024-08-20 18-05-29

Source:
https://mdfs.net/Software/Tube/ARM/

  1. Check if the error is now consistent with PiTubeDirect:

Yes, we now get the object file corrupt error:
Screenshot from 2024-08-20 18-07-20

  1. Now uncomment the multiply instructions

Success:
Screenshot from 2024-08-20 18-10-43

I think that all makes sense now.

@SteveFosdick
Copy link
Collaborator

I think that all makes sense now.

Thanks for that. So, there is also an issue with the compiler and the August version of the ROM. That is not something I would have thought of.

@hoglet67
Copy link
Contributor

hoglet67 commented Aug 20, 2024

So, there is also an issue with the compiler and the August version of the ROM.

Apparantly so, but what exactly I have no idea. It could be:

  • an API difference
  • the C compiler jumping directly into the ROM (which is copied to RAM at 0000-3FFF)
  • the C compiler going as far as patching the RAM copy of the ROM (unlikely I guess)

Maybe your trace could answer this, if you looked back a few hundred instuctions before the crash?

@hoglet67
Copy link
Contributor

IanB found the sources for the Brazil kernel (including the 14th August 1986 date), which are posted here:
https://stardot.org.uk/forums/viewtopic.php?t=17198

I think this may be for the A500 Co Pro (which included MEMC/VIDC/IODC chips) rather than the ARM1 Eval Co Pro. But it was clearly derived from the ARM1 Eval client ROM, and seems to maintain the ability to build for that.

I would suggest you switch to the original ARM 1.00 tube ROM.

@SteveFosdick
Copy link
Collaborator

I have pushed a branch that contains a fix for this, in the form of a selectable ARM2 tube processor that still runs the ROM from the ARM evaluation system (July version).

@SteveFosdick
Copy link
Collaborator

Drifting slightly here, I notice in the data processing group of ARM instructions the 'S' versions, which set the flags, are consistently distinguished from the versions that don't by bit 20 in the instruction encoding being set. Using this scheme it would possible to encode the non-S versions of the TST, TEQ, CMP and CMN instructions. Before the SWAP instructions were introduced, it would be logical for these instructions to be effectively NOPs, i.e. storage of the result of the AND, EOF - or + is suppressed because it is a test instruction and setting the flags is suppressed as it is the non-S version. Is this actually the case, though?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants