stella-emu / stella

A multi-platform Atari 2600 Emulator
https://stella-emu.github.io
GNU General Public License v2.0
589 stars 111 forks source link

Enhanced ARM support #1036

Open thrust26 opened 1 week ago

thrust26 commented 1 week ago

There are games which are using a new format and probably more.

https://forums.atariage.com/topic/344323-fluid-simulation-for-new-2600-game-concept/?do=findComment&comment=5490057

JetSetIlly commented 1 week ago

Reply to @DirtyHairy from the AtariAge thread:

From what you say @JetSetIlly I assume that the ARM program is compiled PIC and linked to a relocatable ELF? So you load the ELF according to the SOC memory layout, relocate it and start executing the entry point?

Yes.

The program runs 100% of the time and emits a stream of 6502 instructions?

Yes.

Current targets are arm7tdmi (the harmony, which is  ARMv4 + Thumb) and Cortex M4 (which ist Thumb + Thumb2)?

Is there more to the runtime environment of the ELF, like a library, or is it running on bare metal?
If there is no runtime library then I presume the ARM code accesses the hardware directly? If so you still need different builds for the different supported SOCs?

The unified driver for the UnoCart and PlusCart abstract away hardware details. I don't believe you will need different builds for different SOCs but that's really a question for Al Nafuur or ZackAttack. They'll have a better idea to what degree the components are abstracted.

I suppose it depends on what chip peripherals are used. ie. If the an FPU is required then that would limit the choice of SOC.

It would probably be a good idea to introduce a section in the ELF file that can be used to specify requirements. That way the cartridge/emulation can decide if the requirements can be met.

What time base is the ARM code using to drive the bus? I suppose it is syncing to address bus transitions, right? From the early code samples I have seen from @ZackAttack I assume that the kernel section calls a function for every instruction which then blocks until all bytes of the instruction have been processed by the 6507

From an emulation point of view, I treat the bus transition as the synchronisation point.

Is there any written documentation for this execution scheme?

Not yet.

DirtyHairy commented 1 week ago

Thanks alot @JetSetIlly . What resources did you use to implement this in Gopher? Are there test ROMs available somewhere?

DirtyHairy commented 1 week ago

Oh, and is there a harmony driver?

JetSetIlly commented 1 week ago

Oh, and is there a harmony driver?

There is no Harmony driver.

Thanks alot @JetSetIlly . What resources did you use to implement this in Gopher? Are there test ROMs available somewhere?

It's been a couple of years since I implemented this so I can't remember exactly how I bootstrapped it. But based on what I remember, we started off with an implementation of the standard 4k cartridge mapper in C. That was then compiled and linked as an ELF file. Both Gopher2600 and Uno/PlusCart load that into memory and stuff the data bus in the way described above.

If you can get that running then adding the StrongARM functions is easy.

(It's very similar to the ACE format which led directly onto the ELF format, so I think a lot of my code would have been based on ACE originally)

I'll have to ask @ZacharyScolaro if he's okay with me sharing that test ROM because he wrote it. I'm sure he'll be fine with it but I should ask first.

JetSetIlly commented 1 week ago

I'll have to ask @ZacharyScolaro if he's okay with me sharing that test ROM because he wrote it. I'm sure he'll be fine with it but I should ask first.

Zack pointed out that the ElfTests are in the United Carts of Atari repository. https://github.com/Al-Nafuur/United-Carts-of-Atari/tree/main/source/ElfTests

The specific test I was talking about is the rom-elf test. I note that the compilation target in the Makefile is armv7-m but for the purposes of bootstrapping Stella, you can change to to arm7tdmi.

Also, don't be fooled by the 4k_rom.bin file. That's just a regular 4k binary file. In this test, it is embedded in the elf file and served up using the "ELF" method. Get that method right and you've cracked it really.

For reference, this is the ELF launcher for the Uno/Pluscart. https://github.com/Al-Nafuur/United-Carts-of-Atari/blob/main/source/STM32firmware/PlusCart/Src/cartridge_emulation_ELF.c

DirtyHairy commented 1 week ago

Thanks a ton! I can take over from there, unless you want to implement it yourself.

JetSetIlly commented 1 week ago

You're in a better position than me to implement it. But I'm happy to answer any questions as best as I can

DirtyHairy commented 1 week ago

After poking a bit I already have a few questions 😏 I cannot fully compile those samples as the last linker step fails, which is not surprising as there are symbols missing (main and _exit for starters), which is not surprising in turn as this is not a full program being linked (and linking it would remove those symbols that refer to vcslib and replace them with stub calls instead).

In fact, it looks to me like the final ELF is not being used at all, but instead the intermediate relocatable ELF is what is being used and relocated by the loader. However, I am unable to run this on Gopher:

pestix@bladehenge:~/git/United-Carts-of-Atari/source/ElfTests$ ~/git/Gopher2600/gopher2600_darwin_arm64 raycaster/raycaster.bin
* error in RUN mode: debugger: preview: cpu: starting a new instruction is invalid mid-instruction

@JetSetIlly Can you give me pointer in the right direction?

JetSetIlly commented 1 week ago

What compiler are you using?

DirtyHairy commented 1 week ago
pestix@bladehenge:~/git/United-Carts-of-Atari/source/ElfTests$ arm-none-eabi-gcc --version
arm-none-eabi-gcc (GNU Tools for Arm Embedded Processors 8-2019-q3-update) 8.3.1 20190703 (release) [gcc-8-branch revision 273027]
Copyright (C) 2018 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

Slightly dated, but should be fit for the purpose 😛

But, anyway, those errors look pretty solid:

pestix@bladehenge:~/git/United-Carts-of-Atari/source/ElfTests/rom-elf$ make
arm-none-eabi-gcc -r -mlong-calls -fno-exceptions -march=armv7-m *.c -orom_elf.o -O2 -Wall
arm-none-eabi-ld -r rom_elf.o -b binary 4k_rom.bin -orom_elf.bin
arm-none-eabi-strip rom_elf.bin -d -R.comment -R.ARM.attributes
arm-none-eabi-ld rom_elf.bin vcsMock.a cartridge_io_mock.a -orom_elf-linked.elf -Tstm32f4_flash.ld
arm-none-eabi-ld: rom_elf.bin: in function `_start':
(.text+0x8a): undefined reference to `main'
arm-none-eabi-ld: rom_elf.bin: in function `exit':
(.text.exit+0x16): undefined reference to `_exit'
make: *** [rom_elf] Error 1

... which makes a lot of sense to me, as there is no CRT being linked.

DirtyHairy commented 1 week ago

I have attached what I get from the first linker invocation, which I presume should be what is run by the loader

rom_elf.bin.zip

JetSetIlly commented 1 week ago

The earliest version I have here is gcc-arm-none-eabi-10.3-2021.10

But I use arm-gnu-toolchain-12.2.rel1-x86_64-arm-none-eabi most of the time

Both of those compile rom_elf correctly.

I can't find a binary distribution arm-none-eabi v8.3.1 so I can't say what's happening.

These are the section headers reported by readelf (for a working binary)

There are 8 section headers, starting at offset 0x122c:

Section Headers:
  [Nr] Name              Type            Addr     Off    Size   ES Flg Lk Inf Al
  [ 0]                   NULL            00000000 000000 000000 00      0   0  0
  [ 1] .text             PROGBITS        00000000 000034 000070 00  AX  0   0  4
  [ 2] .rel.text         REL             00000000 0011d4 000028 08   I  5   1  4
  [ 3] .data             PROGBITS        00000000 0000a4 001000 00  WA  0   0  1
  [ 4] .bss              NOBITS          00000000 0010a4 000000 00  WA  0   0  1
  [ 5] .symtab           SYMTAB          00000000 0010a4 0000b0 10      6   3  4
  [ 6] .strtab           STRTAB          00000000 001154 00007d 00      0   0  1
  [ 7] .shstrtab         STRTAB          00000000 0011fc 000030 00      0   0  1

It looks like your compiler is linking a lot of stuff that's not needed. Gopher2600 is giving up because it doesn't like the look of it

I've attached my compile directory with output for you to look at.

rom-elf.zip

DirtyHairy commented 1 week ago

Hm, interesting, so the newer toolchains seems to resolve more symbols during the first link. Maybe it is linking stuff that was compiled with --ffunction-section in my version. I'll update.

This also confirms what I thought: the ELF being used is not the final linked executable, but the intermediate, relocatable one. Thanks!

JetSetIlly commented 1 week ago

Yes. I think the second linking was part of the early testing for Zack. I've never used the output of the second phase.

DirtyHairy commented 1 week ago

I wonder a bit why it links anyway as the missing references to main and _exit seem pretty much legit to me, but I think I can live with that mystery 😏

ZacharyScolaro commented 1 week ago

Linking as a relocatable elf will cause it to disregard any unresolved symbols. I was attempting to catch any potential loading errors that would be caused by references to functions that aren't built into the firmware. I.E. you typo vcsWrite5() as vcswrite5(). This isn't as relevant now that there's emulator support for it and is not something that you need to worry about when implementing it in emulators or firmware.

Finished games should be targeting armv6 because the stand-alone boards use the stm32g0 series which is a cortex m0+ cpu core. Supporting more than that is probably not something you should be too concerned with for now.

A harmony driver could be developed, but I'm not sure if it has the specs to match the stm32g0. The bare minimum should be 96KB flash and 32KB ram not including the driver.

Here's the makefile I'm currently using for Mattress Monkeys: https://github.com/ZacharyScolaro/mattress-monkeys-2600/blob/main/source/makefile

And here's the key files in the UCA repo that make elf loading possible.

Main entry point, handles setting up the args and initializing the elf loader. https://github.com/Al-Nafuur/United-Carts-of-Atari/blob/main/source/STM32firmware/PlusCart/Src/cartridge_emulation_ELF.c

Parses the elf file and performs relocation. https://github.com/Al-Nafuur/United-Carts-of-Atari/blob/main/source/STM32firmware/PlusCart/Src/elfLib.c

Implements all the vcs() functions including testing for bus-stuffing failures and auto correcting for them. https://github.com/Al-Nafuur/United-Carts-of-Atari/blob/main/source/STM32firmware/PlusCart/Src/vcsLib.c

For emulation there is no need to implement the test and correction of bus-stuffing since the emulator can just implement the vcsWrite3() to always succeed at stuffing. It would be nice if it tracked when vcsLd?2() and vcsLd?ForBusStuff2() are called and produces a faulty stuff if vcsLd*ForBusStuff2() weren't called last. That's just a nice to have for developers though.

thrust26 commented 1 week ago

Some less interesting questions:

JetSetIlly commented 1 week ago

Some less interesting questions:

* @JetSetIlly How do you name the mapper? (found nothing in Gopher2600 when running MM).

It's just called ELF. If you press the ` key (the key below the Escape key) the emulator enters the debugger. The mapper is shown in the top left of the menu bar.

* Are you auto detecting it. If so, how?

The first 3 bytes of an ELF file is 'E', 'L', 'F'. I look for that.

If the file extension is ".elf" then the choice is forced.

* It seems that MM is auto detecting NTSC and PAL, correct? Does this work in Gopher2600 too?

It should do. If it's not working correctly it's because I've been altering the television implementation in recent weeks.

* Are the ACE demos supported with this mapped too?

No. ACE is a different format.

JetSetIlly commented 1 week ago

It's just called ELF. If you press the ` key (the key below the Escape key) the emulator enters the debugger. The mapper is shown in the top left of the menu bar.

Top right.

thrust26 commented 1 week ago

Thanks! Oh, is that only found in the debugger? Or anywhere in the normal user interface too?

@DirtyHairy Please let me know when I should start with extending the bankswitching, auto detection etc. classes.

JetSetIlly commented 1 week ago

Thanks! Oh, is that only found in the debugger? Or anywhere in the normal user interface too?

Debugger only. F7 brings up the FPS window which is similar to the status window in Stella, but I've chosen not to include the mapper type in that.

thrust26 commented 1 week ago

You solely rely on auto detection? Or how can the user change the mapper if it fails?

JetSetIlly commented 1 week ago

You solely rely on auto detection? Or how can the user change the mapper if it fails?

You can specify the mapping with the filename extension or by the command line on launch (the '-mapping' option)

I should add the ability to change it via the ROM selector too but I haven't got around to that yet.

thrust26 commented 1 week ago

I suppose the ELF mapper has no maximal file size? Is there a minimal size?

DirtyHairy commented 1 week ago

Finished games should be targeting armv6 because the stand-alone boards use the stm32g0 series which is a cortex m0+ cpu core. Supporting more than that is probably not something you should be too concerned with for now.

Afaik M0+ is Thumb + Thumb2 --- are you explicitly excluding Thumb2 for now?

And here's the key files in the UCA repo that make elf loading possible.

Thanks, I found them myself by now, this should be more than sufficient to get this working in Stella. I wrote a basic elf parser some time ago here, I think I'll take that and work from there.

DirtyHairy commented 1 week ago

You solely rely on auto detection? Or how can the user change the mapper if it fails?

I think ELF can be detected very reliably if we check the magic and try and parse the header.

DirtyHairy commented 1 week ago

@DirtyHairy Please let me know when I should start with extending the bankswitching, auto detection etc. classes.

Thanks a lot. I think it's easiest if I just do that myself, but I'll get back to you if I need assistance.

thrust26 commented 1 week ago

You solely rely on auto detection? Or how can the user change the mapper if it fails?

I think ELF can be detected very reliably if we check the magic and try and parse the header.

True (coded it already :smile:), but I meant this as a general question.

thrust26 commented 1 week ago

@DirtyHairy Please let me know when I should start with extending the bankswitching, auto detection etc. classes.

Thanks a lot. I think it's easiest if I just do that myself, but I'll get back to you if I need assistance.

OK. I only committed ELF doc updates (I hope you don't mind 😈).

DirtyHairy commented 1 week ago

OK. I only committed ELF doc updates (I hope you don't mind 😈).

😆 Why should I

DirtyHairy commented 1 week ago

@ZacharyScolaro Do current ELF binaries use any hardware from the STM32x beyond the GPIOs that are wired to the bus (in particular timers)?

ZacharyScolaro commented 1 week ago

@ZacharyScolaro Do current ELF binaries use any hardware from the STM32x beyond the GPIOs that are wired to the bus (in particular timers)?

@ZacharyScolaro Do current ELF binaries use any hardware from the STM32x beyond the GPIOs that are wired to the bus (in particular timers)?

I'm not aware of any. Really, the GPIOs should be avoided too. Everything should be done through vcsLib functions in a hardware agnostic way.

DirtyHairy commented 1 day ago

https://github.com/stella-emu/stella/tree/elf

thrust26 commented 1 day ago

Why don't you merge? Are there even any updates yet?

DirtyHairy commented 1 day ago

Because I am not finished 😏 I saw that you assigned me, and this is the branch I am working on, just for reference.