跳转到内容

Aros/平台/68k 支持/开发人员/编译器

来自维基教科书,开放世界中的开放书籍
Aros 维基教科书的导航栏
Aros 用户
Aros 用户文档
Aros 用户常见问题解答
Aros 用户应用程序
Aros 用户 DOS Shell
Aros/用户/AmigaLegacy
Aros 开发文档
Aros 开发人员文档
从 AmigaOS/SDL 移植软件
Zune 初学者指南
Zune .MUI 类
SDL 初学者指南
Aros 开发人员构建系统
特定平台
Aros x86 完整系统 HCL
Aros x86 音频/视频支持
Aros x86 网络支持
Aros Intel AMD x86 安装
Aros 存储支持 IDE SATA 等
Aros Poseidon USB 支持
x86-64 支持
摩托罗拉 68k Amiga 支持
Linux 和 FreeBSD 支持
Windows Mingw 和 MacOSX 支持
Android 支持
Arm Raspberry Pi 支持
PPC Power Architecture
杂项
Aros 公共许可证


交叉编译器

[编辑 | 编辑源代码]

从 AROS 和 AROS-contrib 树为 i386 构建需要很长时间,并且通常需要相当新的软件版本,并且试图在缓慢的模拟下使用过时的构建工具版本或在真实的 m68k 硬件上构建,不会让工作变得更容易。

更有意义的是,在 GNU-Linux 或 FreeBSD 或 Windows 下创建一个 gnu m68k-amiga 交叉编译环境,然后尝试为 m68k-amiga 目标构建 AROS。将文件传输过去并测试与 UAE 或 amiga-forever 的兼容性。建议创建一个 68k-Linux 托管的 AROS,并在 Aranym 中对其进行测试。这样,您就不必担心一开始的定制芯片。您不需要编写任何新的驱动程序;为其他 Linux 托管的 AROS 风格的现有驱动程序应该可以正常工作。

这里,如果您删除了这个完整文件以及我发布的链接中的 g++ 文件,那么 G++ 应该可以使用 c++ 库进行构建。

--enable-languages=c


Download latest Ubuntu image.

Start vmware, let it install using automatic installation, everything is done automatically, when it is ready, it boots directly to desktop. Select synaptics package manager from admin menu, select and install all packages I listed...

Packages needed:

binutils-source
libcloog-ppl-dev (adds lots of other dependencies)
g++
libelf-dev
bison
flex
gcc-4.5-source
libmpfr-dev
libmpc-dev
libecm-dev
netpbm

mkdir dev
cd dev
mkdir binutils
cd binutils
tar xvfJ /usr/src/binutils/binutils-2.20.51.tar.xz
binutils-2.20.51/configure --prefix=/opt/m68k-elf --target=m68k-elf
make -j2
sudo -s
make install
exit
cd ..
mkdir gcc
cd gcc
tar xvfJ /usr/src/gcc-4.5/gcc-4.5.1.tar.xz
cd gcc-4.5.1
patch -p1 <path>/0001-m68k-amiga-Amiga-ABI-support.patch
cd ..
gcc-4.5.1/configure --without-headers --disable-threads --disable-libssp
--disable-nls --disable-shared --without-pic --prefix=/opt/m68k-elf
--target=m68k-elf --enable-languages=c
make -j2
sudo -s
make install
exit

然后按照我的指南操作。只需要大约 30 分钟。

add PATH=$PATH:/opt/m68k-elf/bin to ~.bashrc


我在 12.10 上尝试自己构建,并且成功了。这是我的配置行

CC=gcc-4.6 /home/weissms/aros/aros-src/configure --target=amiga-m68k --enable-ccache --with-portssources=~/aros/Sources --with-aros-toolchain-install=/home/weissms/media/data/aros/build/crosstools/

m68k-amiga-aros-ar 是一个指向 /home/weissms/media/data/aros/build/crosstools/m68k-aros-ar 的链接。


在我的 VirtualBox Linux 机器上构建了大约 4 个小时后,它最终中止并出现以下错误:确保您的树是最新的。该文件几天前损坏。(r46006)顺便说一句,没有必要编译所有内容,可启动设置只需要 workbench 和 kernel-link-amiga-m68k 目标。据我所知,非 m68k 驱动程序没有被禁用,因为没有人费心去禁用它们,而且至少在理论上,大多数驱动程序可以通过 Amiga Zorro PCI 桥工作。当然,英特尔 GMA 不行 :)


有人尝试为 68k 制作 g++ 交叉编译器吗?或者,也许有更简单的方法来为 Aros 68k 编译 owb?这是 Fab 的 Odyssey。构建没有与 AROS 构建系统耦合。它确实需要 cmake,以及一些默认情况下不在 contrib 中构建的库。(并且它在 3GHz 机器上使用 -j 3 构建需要 1 个小时。)



我为 MegaDrive 制作了一个 680x0 交叉编译器(它还包含一个 SH2 交叉编译器,但这很容易被剪掉)。它是 4.5.2 的通用构建,但是,它可能没有所需的标志。以下是版本信息

Target: m68k-elf
Configured with: ../gcc-4.5.2/configure --target=m68k-elf
--prefix=/opt/toolchains/gen/m68k-elf --without-headers --with-newlib
--enable-languages=c --disable-libssp --disable-tls --with-cpu=m68000
: (reconfigured) ../gcc-4.5.2/configure --target=m68k-elf
--prefix=/opt/toolchains/gen/m68k-elf --without-headers --with-newlib
--enable-languages=c --disable-libssp --disable-tls --with-cpu=m68000
: (reconfigured) ../gcc-4.5.2/configure --target=m68k-elf
--prefix=/opt/toolchains/gen/m68k-elf --with-newlib --disable-libssp
--disable-tls --enable-threads=single
--enable-languages=c,c++,objc,obj-c++ --with-cpu=m68000
Thread model: single
gcc version 4.5.2 (GCC)

请注意诸如线程模型、禁用的线程本地存储等内容。这些需要在构建工具链的 makefile 中更改。我在 GenDev GenDev 用于构建工具链的过程和文件。

它可以很容易地进行更改以适应 AROS 所需的任何标志,以及不同的默认目标 CPU(当前设置为 68000)。



使用 svn 获取最新树。

cd ~
mkdir build
cd build

(It is very important to have separate build tree, do not compile inside source tree)

 ../AROS/configure --target=amiga-m68k --with-optimization="-Os" --with-serial-debug --disable-mmu 
(do not change optimization setting, it is not going to work) 
 make
(wait until you get some error, it is some package that is not yet m68k compatible, not important) 

 make kernel-link-amiga-m68k

rom images are now in distfiles

make workbench to create full wb setup

嗯。看起来您的交叉编译器不允许 .text 对齐。您使用的是哪个版本的 m68k gcc?如果您使用了 arch/m68k-amiga/doc/build-toolchain.sh 脚本,那么您应该使用这个版本

$ m68k-elf-gcc -v
Using built-in specs.
COLLECT_GCC=m68k-elf-gcc
COLLECT_LTO_WRAPPER=/opt/m68k-elf/libexec/gcc/m68k-elf/4.5.1/lto-wrapper
Target: m68k-elf
Configured with: ../configure --without-headers --disable-threads --disable-libssp --disable-nls --disable-shared --without-pic --prefix=/opt/m68k-elf --target=m68k-elf --program-prefix=m68k-elf- --enable-languages=c
Thread model: single
gcc version 4.5.1 (GCC)

i386 和 x86_64 构建使用一个“伪交叉编译器”(主机的 gcc + 配置)。我认为您应该看看 mingw32 端口是如何构建的 - 它使用真实的、预构建的交叉编译器来完成整个链(就我所知,向 Pavel Fedin 咨询更多信息)。如果您遵循这种方法,我们甚至可以在 VPS 上为您的端口设置每日构建 - 我认为这对于避免在 m68k 上引入由处理其他端口的人员引入的回归非常重要。

如果很多东西被添加到“通用”目标(例如 linklibs),然后通过同一个目标使用,这会导致当您尝试使用特定目标时,大量无关的东西被构建。我认为(IMHO)如果这些目标只用于分组主要系统对象,而不仅仅是所有对象,并且 mmakefile 正确地使用它们实际使用的模块的依赖项目标,那就太好了。

目标应该是摆脱所有包含和 linklibs 作为元依赖项,而不是扩展它们。

Core-linklibs 是 gcc 默认添加的 linklibs 的元目标。使用某些 linklibs 的程序需要在其 mmakefile 中明确提供正确的依赖项。

这是我的 binutils 的“strip”,它消除了 .rela.text 和 .rela.rodata(大小为零)。据我所知,我们不应该在 AROS 二进制文件上使用 strip 作为单独的命令。但是,我们可以将 -s 添加到链接器的命令行中。不要明确使用 strip,因为它会删除某些符号,而这些符号对于 AROS 程序正常工作是必需的。

--strip-unneeded --remove-section .comment 

没问题,但是纯“strip”会创建损坏的二进制文件。

我不得不将 Graphics/*LayerRom 系列更改为使用 A4 而不是 A5,因为 GCC 似乎认为 A5 帧指针是不可变的。"-fomit-frame-pointer -fcall-saved-reg-a5" 选项怎么样?您可以在层跳转表中添加一个丑陋的包装器,以切换寄存器吗?(类似于 Disable() 及其朋友)这是否也导致了无法解释的引导菜单崩溃?

但是

  • GCC 将 -fomit-frame-pointer 视为提示,而不是要求。GCC 中的 reload1.c 算法可以强制使用帧指针,而不管“omit-frame-pointer”设置如何。
  • GCC 当帧指针 (%a5) 在使用中时,由于上述解释,我得到以下错误
cc1: error: can't use 'a5' as a call-saved register

最大的问题不是这个问题的普遍性,而是这个问题的*稀有性*。如果这是一个*严重*问题,那么我可以忍受它并处理会导致巨大膨胀的更改。

就目前而言,以下是在 AROS 中的所有调用(在 *.conf 文件中定义),这些调用可能存在问题,这意味着我无法证明巨大的膨胀

rom/exec/exec.conf:
    ULONG Supervisor(ULONG_FUNC userFunction) (A5)
rom/expansion/
    UCF5 calls to the ROM diagPoint
rom/dos/

rom/graphics/graphics.conf:
    void LockLayerRom(struct Layer *l) (A5)
    void UnlockLayerRom(struct Layer *l) (A5)
    BOOL AttemptLockLayerRom(struct Layer *l) (A5)

workbench/libs/popupmenu/popupmenu.conf:
    APTR PM_OBSOLETEFilterIMsgA(struct Window *window, struct
PopupMenu *pm, struct IntuiMessage *im, struct TagItem *tags) (A1, A2, A3, A5)

workbench/libs/datatypes/datatypes.conf:
    ULONG DoDTDomainA(Object *o, struct Window *win, struct Requester
*req, struct RastPort *rport, ULONG which, struct IBox *domain, struct TagItem *attrs) (A0, A1, A2, A3, D0, A4, A5)

我有一些想法,但它们都有缺点

  • 为所有库函数创建一个堆栈参数包装器,然后通过 jsr NN(%a6) 调用真正的寄存器调用函数。
+ In this model, the AROS_LH* macros generate _Exec_Foo (stackcall) wrappers for Exec_Foo (regcall). AROS_LC* macros would call the _Exec_Foo stackcall wrappers 
+ AmigaOS 3.x apps would work unchanged against the ROM
- Unneccessary bloat for the ROM. This bloats all calls in the ROM to fix only 10 calls. 
- Only works for the ROM. Things get out of hand and messy for building the AROS user-space libraries and apps. 
  • 为每个使用 A4 而不是 A5 的受影响的 libcalls 创建一个额外的库调用(即 Exec/Supervisor_A4),并修复调用者以便在他们的头文件中有一个“#define Supervisor Supervisor_A4”。然后为每个函数定义一个 asm 存根,该存根保存 A5 并将 A4 移动到 A5 中,调用真正的例程,

然后恢复 A5。

+ Relatively low impact, only affects the problem APIs
+ Will work with existing AmigaOS 3.x apps
+ No problems with compiling AROS apps
- May have to get genmodule in the act to get this to work cleanly.
- Will *permanently* affect the AROS ABI for m68k, and consume library call slots for *ALL OTHER ARCHITECTURES*.


  • 修复 gcc 以在它认为“强制”使用帧指针时给出诊断信息,这些诊断信息足以让程序员做出正确的更改,以便 gcc 不会在该例程中生成帧指针。
- This code is very convoluted and ugly. I tried this once, and ran away screaming.
  • 修复 gcc 使其永远不需要在 m68k 上使用帧指针。
  - This may be impossible. reload1.c is an impenetrable morass of evil.
  • 修复 gcc 使其能够识别何时 FP 将被覆盖,并将 FP 移动到一个备用寄存器。

+ 将是一个极好的修复,并且应该可以移植到其他架构。- 看起来这可能是一项巨大的任务,或者至少是一项超出我技能范围的任务。


  • 为 LLVM 创建一个 M68K 目标后端
- Would distract from the AROS KS Phase I task for at least a month. 
- May run into intractable issues (fixed ABI definition per arch?, impossible to debug LLVM code generation issues?, etc)
+ HUGE long term benefits if we get it to work!



GCC 2.95.3

[编辑 | 编辑源代码]
  • gcc 2.95 已经过时了 - AROS 在编译和链接时使用了许多 GCC 3.x 或更高版本的特性。
  • gcc 2.95 代码生成在 m68k 上非常臃肿 - 比 gcc 4.5.1 还要糟糕得多。例如,使用我的寄存器调用(损坏)内联黑客的 4.5.1 上的 400K ROM 文本空间在 gcc 2.95 上膨胀到了 1.2M。不能接受!- 最糟糕的情况之一是 Exec/Forbid - 它从 2 条指令膨胀到了 35 条!

我本来希望避免的代码生成错误 - 它显然很古老,因为 2.95.3 在相同的位置仍然生成相同的错误。(由于某些极端情况下的优化问题,它使用 lea %sp(#n),%a3 而不是 move.l %sp(#n),%a3)。所以,我现在要做的就是专注于 2.95.3 代码优化错误(不幸的是,它出现在 PrepareExecBase 中),修复它,然后将该补丁移植到 gcc 4.5.1。它是 -fpic 优化,它被寄存器使用破坏了。-fno-pic 现在暂时解决了这个错误,但我需要在我需要制作“真正的”PIC 库时重新调查这个问题。

GCC 2.95(可能不是所有版本,但 IIRC 2.95.3 做到了)可以为像这样的 vararg 宏生成错误的代码

#define OpenWindowTags(arg1, ...) \
({ \
    IPTR __args[] = { AROS_PP_VARIADIC_CAST2IPTR(__VA_ARGS__) }; \
    OpenWindowTagList((arg1), (struct TagItem *)__args); \
})

在 x86 和 68k 上。IIRC 这是切换到 gcc 3 的原因之一。

这是来自 binutils 汇编器的。要查找错误,可以使用一个开关,即临时文件不会被删除。

要避免启动代码,链接器选项

nostarfiles 
noixemul

GCC 3.4 太过破损,无法用优化器编译 ffmpeg。ffmpeg 使用 GCC 4.5.0(不是 AROS 版本)构建。但可以很好地用 GCC 4.3.2 编译(在 GCC 4.5 发布之前使用过)。

这里只有 cygwin 托管的 GCC 4.3.2 和 GCC 4.50。使用这些编译器,许多 amiga 端口可以编译

在这些编译器上还有一个文本文件说明如何构建 GCC。68k GCC 在 GCC 中得到官方支持。因此,为您的喜欢的 Linux 编译 GCC 很容易。

我建议使用来自 includes 或 ixemul 的新的 math-68881.h。这是专门修改以与更新的编译器一起工作。GCC 的问题是在 asm 行之后的更新编译器中,需要添加 \n\t。但更新的 asm 代码已经包含了这个。

我认为在这个 AROS 构建中优化器被关闭了。默认的 GCC 仅创建 68000 代码。

我不知道他们如何在仅 3.1 级启动盘中容纳所有东西,而不使用 4000T 使用的技巧,比如将 Workbench.library 移到磁盘。在这种情况下,编译后的 C 代码几乎都会更大。AmigaOS 3.1 的大部分是用 C 编写的。dos.library 在 1.3 之前是用 BCPL 编写的,并在 2.0(甚至 1.4 beta?)时被转换为 C。 IIRC,他们使用了多个编译器,其中一个是 Lattice。后来变成了 SAS/C。在 gcc 2.95 时代,我做了一些基准测试,我尝试过的软件在 gcc 上比在 SAS/C 上更快。许多因素会影响 AROS68K 的运行速度和大小。现在谈论它将是什么样子还为时过早。



由于使用了 compiler/include/asm.c 中的惯用法,我们似乎已经将自己锁定在 GCC 编译器系列中。

这些惯用法用于让目标的 GCC C 编译器确定结构元素的偏移量,并将它们作为内联汇编发出。然后使用内联汇编生成汇编头文件。

之所以这样做是因为主机编译器无法正确计算偏移量 - 例如,在 Linux 主机(小端,长对齐)上为 m68k(小端,短对齐)编译。在 AROS 的历史上,是否有任何理由不使用 #pragma pack(n) 预处理器指令?我认为,pragma pack() 可以得到跨编译器生成结构偏移量的近似值,但 asm.c 方法可以精确地得到偏移量。对于大多数情况,pragma pack() 可能可以得到您想要的结果(特别是对于 PPC 与 m68k,它们具有相似的打包规则和相同的字节序),但对于在 x86 上为 m68k 跨编译来说,可能并不总是得到正确的结果。这应该保证相同的结构对齐方式和偏移量,与主机架构和正在使用的编译器无关。OS4 和 MorphOS 使用它,vbcc 也支持它。我认为 OS4 仅将其用于已在 OS3.x 中定义的结构。新的结构不使用这种打包。在 64 位系统上,情况不会这样,因为指针(以及替换 ULONG 的 IPTR)将占用双倍空间。PPC 和 m68k 的打包规则类似,x86 可能非常奇怪。我们决定使用 CPU 的本机打包,以获得最大的速度。

不幸的是,VBCC 的内联汇编方法不允许在汇编中进行替换操作(它会被原封不动地塞入输出文件),因此 asm.c 方法无法使用。这样的功能不容易添加。即使它存在,它也无法帮助您使用 vbcc/vasm。我浏览了一下 asm.c,它看起来会将 #define 指令插入到汇编源代码中。这无法与 vasm 一起使用,因为 vasm 不会在其输入源代码上运行 C 预处理器(最终它是一个汇编器,对 C 一无所知)。对于 AROS/VBCC 工具链,我仅使用 vbcc。cpp、as、ld 等来自 GCC/binutils。我不想重写我所有的汇编器,而且我对 GNU 工具链的复杂性非常了解。但您知道 vasm 为编译器执行所有窥孔优化工作吗?如果没有优化汇编器,代码将明显变慢且更大。简单。我使用 '-gas' 选项为 vbccm68k,它发出 AT&T 语法。

对于 VBCC(或 SASC,或任何其他“Amiga 风格”的编译器),asm.c 技术不可用。之前已经讨论过这个问题。有些人建议尝试通过一些技巧从目标 .o 文件中提取所需的信息。另一种可能性是为每个 CPU 编写一个 cpu.i 文件,并让它不要通过代码生成。如果让我要求一个 *vbcc* 更改,那将是支持这种惯用法

char array[];
int func(void) = "movl #%d,d0\nret\nmova %s,a0\nmove a0@(d0),d0",1234,"array";

基本上,能够像对待 sprintf() 字符串一样对待内联汇编。如果我们有这个,我可以让 asm.c 在 vbcc 下工作。您可以向函数传递一个参数,然后您将编写

int func(__reg("a0") char *array) = "...";

或者您将使用一个全局变量

int func(void) = "lea _array,a0 ...";

但您可能需要类似的东西

int func(void) = "movl #%d,d0\nrts",offsetof(struct Task, tc_State);

看起来我们被困在 GCC(可能还有 LLVM)中,适用于所有架构。是的,不幸的是,不仅用于编译 AROS 系统,也用于编译一般的 AROS 程序。我多年前就放弃了尝试使用 vbcc 支持 AROS,因为 SDK 似乎是专门为 gcc 设计的,而且我不希望在每次新版本发布时都对其进行修补。:(

我有一些补丁来支持

  • 将 -include、-iquote 和 -isystem 传递给 cpp
  • 支持 __section( ".with" "_string" "_concatenation")
  • Void * 算术(是的,我知道,非 C99,但 AROS 中到处都是)

哦,还有一件事。这是我的 vc.config 文件,供您参考。

-pp=m68k-elf-cpp -P -undef -isystem /opt/vbcc/include
-I/home/jmcmullan/private/AROS.vbcc/bin/amiga-m68k/AROS/Development/include
-D__ELF__ -U__GNUC__ -D__VBCC__ -D__mc68000__ -D__mc68000 %s %s %s
-ppv=m68k-elf-cpp -P -undef -isystem /opt/vbcc/include
-I/home/jmcmullan/private/AROS.vbcc/bin/amiga-m68k/AROS/Development/include
-D__ELF__ -U__GNUC__ -D__VBCC__ -D__mc68000__ -D__mc68000 %s %s %s
-cc=vbccm68k -quiet -c99 -gas -elf %s -o= %s %s -O=%ld
-ccv=vbccm68k -c99 -gas -elf %s -o= %s %s -O=%ld
-as=m68k-elf-as %s -o %s
-asv=m68k-elf-as %s -o %s
-ld=m68k-elf-ld %s %s -o %s
-l2=m68k-elf-ld %s %s -o %s
-ldv=m68k-elf-ld %s %s -o %s
-l2v=m68k-elf-ld %s %s -o %s
-ldnodb=-s
-ul=-l%s
-cf=-F%s
-ml=500



体系结构

[编辑 | 编辑源代码]

arch/m68k-all: 充实 m68k 通用内核例程。所有端口都需要通用的例程。特别值得关注的是 arch/m68k-all/include/gencall.c 帮助程序,它生成 GCC 粘合宏,这些宏(希望)将使我们获得一个工作本机库 API,而不需要太多的 GCC 补丁。

arch/m68k-all/exec/cachecleare.c 
arch/m68k-all/exec/cacheclearu.c 
arch/m68k-all/exec/cachecontrol.c 
arch/m68k-all/exec/cachepostdma.c 
arch/m68k-all/exec/cachepredma.c 
arch/m68k-all/exec/getcc.c 
arch/m68k-all/exec/mmakefile.src 
arch/m68k-all/exec/newstackswap.c 
arch/m68k-all/exec/offsets.c 
arch/m68k-all/exec/stackswap.S 
arch/m68k-all/include/aros/m68k/atomic.h 
arch/m68k-all/include/aros/m68k/cpu.h 
arch/m68k-all/include/aros/m68k/fenv.h 
arch/m68k-all/include/gencall.c 
arch/m68k-all/include/jmpdefs.h 
arch/m68k-all/include/mmakefile.src 
arch/m68k-all/mlib/fenv.c 
arch/m68k-all/mlib/mmakefile.src 
compiler/arossupport/include/atomic.h 
compiler/mlib/mmakefile.src


arch/m68k-amiga: 本机 Amiga 支持。提供对基于堆栈和 bincompat amiga-m68k 构建的支持。基于寄存器的 amiga-m68k 确实存在一些函数的编译器问题(例如 Exec/Forbid())。

arch/m68k-amiga/boot/linkerscript 
arch/m68k-amiga/boot/m68k-gdbstub.c 
arch/m68k-amiga/boot/mmakefile.src 
arch/m68k-amiga/boot/rom_entry.S 
arch/m68k-amiga/boot/rom_init.S 
arch/m68k-amiga/boot/romcheck.c 
arch/m68k-amiga/boot/start.c 
arch/m68k-amiga/exec/coldreboot.c 
arch/m68k-amiga/exec/exec_init.c 
arch/m68k-amiga/exec/mmakefile.src 
arch/m68k-amiga/exec/preparecontext.c 
arch/m68k-amiga/exec/stackswap.s 
arch/m68k-amiga/include/mmakefile.src 
arch/m68k-amiga/include/sigcore.h 
arch/m68k-amiga/kernel/cli.c 
arch/m68k-amiga/kernel/issuper.c 
arch/m68k-amiga/kernel/kernel.conf	
arch/m68k-amiga/kernel/kernel_debug.c 
arch/m68k-amiga/kernel/kernel_init.c 
arch/m68k-amiga/kernel/maygetchar.c 
arch/m68k-amiga/kernel/mmakefile.src 
arch/m68k-amiga/kernel/sti.c 
arch/m68k-amiga/mmakefile.src 
configure.in 
rom/exec/mmakefile.src

使用通用的 exec/preparecontext.c?因为在所有系统上使其可用花费了很多时间... 必须避免使用 sigcore.h,而是使用 arch/m68k-amiga/kernel_cpu.h 并定义必要的宏。

计划按 CPU 系列统一 CPU 上下文结构,并将其公开。或者发明一些 API 来操作上下文。因此,私有上下文是临时性的。

尚不清楚我们是否可以在 gallium 中安全地使用 Disable()/Enable()。最好为 m68k 实现原子操作。通用原子操作可以被视为临时技巧。不幸的是,m68k CAS 和 TAS 指令在 ChipRAM 上是非法的(参见 Amiga HRM)。我们必须在 m68k-amiga 上使用 Enable()/Disable() 进行读-修改-写操作。


m68k AROS_LIBFUNC_INIT 在哪里定义?在 compiler/arossupport/include/libcall.h 中。

这可能有助于调试 libcall 的进入和退出。

#undef AROS_LIBFUNC_INIT
#define AROS_LIBFUNC_INIT if (SysBase->DebugAROSBase) bug("+%s\n", __func__); {
#undef AROS_LIBFUNC_EXIT
#define AROS_LIBFUNC_EXIT } if (SysBase->DebugAROSBase) bug("-%s\n", __func__); }
#endif
  • 创建一个 ROM,它加载到 0xF00000 而不是 0xF80000(“卡带”空间)
  • 位于 0xF80000 的 Amiga Kickstart 将看到 AROS ROM,并跳到它,而不是跳到它自己的 Exec(在 KS 1.3 或更高版本中会自动发生)。
  • AROS Exec 将扫描其 ROM 空间 *和* KickStart ROM 空间,并使用 KS ROM 库来“填补”硬件驱动程序的空白。

这将使我们获得一个“Frankenrom”,它将使更多开发人员能够获得一个能够加载 AROS m68k ELF 程序并在验证和 KS 库替换方面进行工作的启动 AROS。我将使用 Amiga Kickstart 3.1 的图形、dos、鼠标、键盘和 trackdisk 驱动程序来对其进行 FrankenROMing,以确保我可以进入 AROS 桌面。在那之后(这将验证 exec.library 和 kernel.resource),我将继续添加 AROS 库(并删除 KS 3.1 库),直到全部都是 AROS。

一种更容易且更兼容的方法

将 AROS ROM 留在 0xf80000 中,但将 0xE00000-0xE7FFFF 添加到 exec 的常驻结构扫描列表中。使用 romsplit 和 remus 实用程序将所需的原始 KS 模块放到 0xE00000“扩展 ROM”区域。

Romsplit 提取 KS rom 模块并重新创建重定位数据。Remus 可用于构建自定义 rom,将其重新定位到您想要的任何地址。

这完全兼容 UAE(无需 0xf00000 技巧/UAE 启动 rom 修改),只需配置扩展 rom 映像,它也更真实地兼容 Amiga,1M EPROM 替换原始 ROM 会自动映射 0xE0 和 0xF8 区域。(除了那些因某种原因丢失了 1M ROM 功能的 Fat Gary 基于的 Amiga,它在 A500/A600 和 A1200 上运行良好)。真正的 CD32 也使用这种方式。CDTV 是唯一一个使用 0xF0 空间的“奇怪”的 Amiga。(0xF0 也被 Blizzard 060 卡使用)。请注意,0xE0 通常反映 0xF8(如果使用正常的 512K rom),不要意外地加载两次模块:),还要确保安装了 0xE0 ROM 头,因为如果安装了,PC 在复位时会从 0xE0 ROM 加载。


在哪里扫描 UAE ROM 扩展(UAE HDF、UAE SCSI 等)?

该 ROM 通常位于 0xf00000,但也包含伪造的自动配置板,它会自动挂载。(至少在 WinUAE 中它是相对于 PC 的,可以移动到其他位置,其他 UAE 版本不确定)。

  • 内存映射转储中的“文件系统自动配置区域”。
  • “UAE 启动 ROM”包含代码。

(同样,不确定这是否在其他 UAE 版本中报告)。

您能否在 WinUAE 中添加基于 TCP 端口的串行仿真?这将使您端的调试工作变得更加轻松。我已经在我的 e-uae 中打上了补丁来实现这一功能。或者,如果您真的喜欢挑战,您可以在 WinUAE 上实现一个 GDB 桩 TCP 端口...... 我在调试时通常会使用单独的 WinUAE 调试日志窗口,串行到 write_log() 的转换通常已经足够了。

在 WinUAE 中,这种工作方式需要您的 Amiga 程序调用一个函数。因为 uae.resource 可能会位于不同的地址,在更新的 WinUAE 中,一些额外的代码需要读取向量来启动它。

向量 20 执行强制器和串行到 WinUAE 控制台输出启用。当 d1 & 1 !=0 时,强制器被启用。当 d1 & 2 !=0 时,9600 波特率的串行数据将被发送到 WinUAE 日志文件或控制台。但在某些情况下,您可能希望更快地进行串行输出,Toni 可能会修改代码,使例如 600000 波特率也能写入控制台,并且无需切换。

d1 & 4 != 0 是非法地址停止程序模式。这类似于死神,但在 WinUAE 中,您可以跳过对所有 AOS 图形调试器可访问的非法地址的访问。

所有模式都可以在运行时切换。串行模式是粘性的,因此一旦设置,在重启后,串行数据将写入 WinUAE 日志控制台或 Windows。



风格

[edit | edit source]
amiga-m68k-eabi (ELF stack based ABI) - STANDALONE (obsolete) 
amiga-m68k-aros (AROS register ABI for m68k) STANDALONE | NATIVE | BINCOMPAT

完全删除 NATIVE。此标志在代码中启用了某些 Amiga 特定的怪癖(使用 grep 搜索它,您会看到)。这可以通过内核中的架构特定代码和 CPU 特定代码来处理。在一些真正需要 #ifdef 的罕见情况下(比如在 a3 寄存器中返回某些内容),您可以更好地依赖 BINCOMPAT,我认为它在这里更适合。

BINCOMPAT 风格的目标之一是消除 ROM 对于 BSS 部分的需求。此补丁删除了 BINCOMPAT 风格的 rom/kernel 的 BSS 数据,并将 KernelBase 设置为 M68K 向量 0(位于 SysBase 正下方)。最近还有更多 BINCOMPAT 更改。请注意,目前还有其他端口是 BINCOMPAT 的,尽管它们并不真正兼容,因为它们缺乏兼容的结构填充。但它们将来可以真正实现二进制兼容,在支持大端 CPU 的每个端口都可以。您的端口是否在某些地方使用了 pragma pack(2)?我想我们现在应该为 BINCOMPAT 端口添加这个功能。

但即使这样,与上述类似的更改也会破坏其他端口,因为它们可能需要这些全局变量。在这里我们需要另一种解决方案。我之所以会遇到所有这些问题,是因为 sam 端口不再启动。目前,我已经将它从 ppcnative 切换到独立模式,并且它可以正常工作了。

gcc-m68k 的所有结构都隐式地使用 pack(2)。

我不会引入太多 AROS_FLAVOUR 定义,因为目标是在 ABI V1 之后和 SDK V1 中摆脱它们。我希望使带有全局变量的模块可以 ROM 化。我将通过将这些全局变量链接到一个已知位于 RAM 中的绝对地址来做到这一点。然后,第一个 ROM 初始化代码将保留全局变量链接位置的适当数量,并进行初始化。

AROS_FLAVOUR_NATIVE

使用本地操作系统的系统调用而不是内核

AROS_FLAVOUR_STANDALONE

使用内核直接控制调度

AROS_FLAVOUR_EMULATION

???

AROS_FLAVOUR_LINKLIB

???

AROS_FLAVOUR_BINCOMPAT

与 AmigaOS 3.x API 二进制兼容(PPC 和 M68K)

我想添加一些类似于以下内容的内容

AROS_FLAVOUR_ROM

rom/* 库中不允许使用 .bss 或 .data 段

如果我们在 ABI V1 切换之前保留当前标志,则不应该有任何问题。对于 sam 和 efika 端口以及以下代码行

  1. if (AROS_FLAVOUR & AROS_FLAVOUR_BINCOMPAT)

我需要更多信息,以确定这是用于 Amiga 硬件还是仅用于二进制兼容。目前,16 字节堆栈对齐不起作用,或者存在一些直接硬件访问操作。这可以通过使用更多预处理器符号(哪些符号?)重写,这些符号被分离到架构相关的宏或内联函数中,或者被 build_arch_specific 覆盖。

我不知道 ABI V1 将如何更改风格相关的设置,但我假设需要有关 AROS_TARGET_ARCH 和 AROS_TARGET_CPU 的信息,那么现在将这些信息放在我们生成的 config.h 中如何?然后,这些信息可以帮助解决上述问题。


好的,我想要 config.h 包含类似以下内容的东西

  1. define AROS_TARGET_ARCH_AMIGA
  2. define AROS_TARGET_CPU_M68K

  1. define AROS_TARGET_ARCH_SAM440
  2. define AROS_TARGET_CPU_PPC

<其他内容>

具体取决于 configure 的调用方式。

一些托管模块中使用的预处理器符号,例如 HOST_OS_linux、HOST_OS_darwin 或 AROS_ARCHITECTURE,可以以相同的方式生成并放置在 config.h 中。您能否进行 configure.in 的更改,然后我会“赶上”并修复代码,在需要的地方使用这些符号来代替 BINCOMPAT。


或者,它应该是一个单独的“CONFIG_ROMMABLE”之类的符号吗?

AmigaOS Exec 的一个基本优点是,(通过添加一些硬件互斥体)带有 MMU 的 SMP 支持非常简单。每个 CPU 都有自己的内存空间,以及自己的 SysBase,您可以创建一个特殊的 CPU 间消息管道来向其他 CPU 发送消息。

一种方法是让(例如)CPU0 控制所有硬件,所有其他 CPU 都有代理库,这些库使用 GetMsg() 来“向上调用”CPU0 以进行硬件访问。

当然,您也可以将硬件访问分配给不同的 CPU,或者其他任何可能性。所有 CPU 都使用相同的只读内存来保存 Exec/Intuitiuon/etc 库,但每个库的 LibBase 对每个 CPU 都是私有的。

我不明白这两者之间如何发生冲突。可能 SMP 感知驱动程序不会为了效率而使用全局变量,但这并不意味着应该禁止所有驱动程序使用全局变量。我希望能够将任何驱动程序或库放到 ROM 中。例如,对于具有数 MB 非易失性内存的移动设备。为每个 CPU/核心提供自己的内存空间,当您想在 CPU/核心之间移动进程时会产生问题。我会为每个 CPU 提供一个 SysBase 的副本,但我将使用 MMU 将其定位在相同的虚拟地址空间。这样就可以在 CPU/核心之间移动进程。

旧式 Amiga 中断处理程序的条件代码标志 Z 位于 %sr 中,用于确定处理程序是否处理了 IRQ。不幸的是,真的没有干净的方法来同时支持旧式和新式中断处理程序,因此对于 BINCOMPAT,我们将忽略返回值,并处理所有处理程序。



标志和调用

[edit | edit source]

为什么在配置 AROS 时不将 TARGET_CC & TARGET_CFLAGS 和 HOST_CC & HOST_CFLAGS 作为可选变量呢?只需使用众所周知的默认值来处理常见情况。如果我们想使用其他编译器,这将更加灵活。

AROS_LC(库调用)宏应该使用 AROS_LD(库声明)系列进行类型转换 - AROS_LP(库原型)用于 C 桩和原型,而不是用于库 ABI。

In the __AROS_LP_BASE(basetype,basename) macro, it is unsafe to ever use or return the 'basetype' element, since it is frequently corrupted by #defines, for example:

struct foo_data {
   struct GfxBase *GfxBase;
   ...;
}

#define GfxBase data->GfxBase

...

int blah_blah(struct foo_data *data, ...)
{
    AddDisplayDriverA(gfxhidd, &tags);
    ...
}

In the above example, AddDisplayDriverA is defined as a call to __AddDisplayDriverA_WB(GfxBase, (arg1), (arg2)), which uses the AROS_LC2() macro, which uses the __AROS_LP_BASE() macro to cast the type. If __AROS_LP_BASE() returns the basetype, the macro expands to the following for the cast of the function pointer: 

(LONG (*)(APTR, struct TagItem *,struct GfxBase *))

Which is all fine, until GfxBase gets expanded:

(LONG (*)(APTR, struct TagItem *,struct data->GfxBase *))

So, if '#defineing' lib bases is an allowed idiom, then
__AROS_LP_BASE() must never return basetype, correct?
When I compiled some AROS libs (like diskfont.library) under AOS/68k I used:

/* What to do with the library base in header, prototype and call */
#define __AROS_LH_BASE(basetype,basename)   register basetype basename __asm("a6")
#define __AROS_LP_BASE(basetype,basename)   register void * __asm("a6")
#define __AROS_LC_BASE(basetype,basename)   basename
#define __AROS_LD_BASE(basetype,basename)   register basetype __asm("a6")

/* How to transform an argument in header, prototype and call */
#define __AROS_LHA(type,name,reg)     register type name __asm(reg)
#define __AROS_LPA(type,name,reg)     register type __asm(reg)
#define __AROS_LCA(type,name,reg)     name
#define __AROS_LDA(type,name,reg)     register type __asm(reg)
#define __AROS_UFHA(type,name,reg)    register type name __asm(reg)
#define __AROS_UFPA(type,name,reg)    register type __asm(reg)
#define __AROS_UFCA(type,name,reg)    name
#define __AROS_UFDA(type,name,reg)    register type __asm(reg)

 #define __AROS_LP_BASE(basetype,basename)   register void * __asm("a6")
 #define __AROS_LPA(type,name,reg)     register type __asm(reg)

您是否意识到,这使得您所有的 C 桩都变成了 regcall 而不是 stack call?我不知道这些 C 桩是否真的被使用了。它们在几年前根本不存在。我认为 AROS_LP 宏不是/不打算用于 C 桩的原型。它们旨在用于真实 libcall 的原型(即使由于 libcall 的实现方式而很少使用)。C 桩的原型使用 AROS_LP 宏也是不合理的,而在实际实现(生成的 #?_stubs.c 文件)中根本没有使用任何宏。因为这意味着 AROS_LP 宏将始终需要“扩展”到正常的 C 调用约定 -> 为什么一开始要使用 AROS_LP 宏呢?

正确的行为是将它们用于真实库调用的原型,而不是用于桩。在过去,可能有一些奇怪的编译器需要单独的原型和定义,或者它只是额外的兼容性。它们可能从 rev 1 或更早的版本开始就存在了。因此,我个人更愿意保留它们并修复桩。

  1. define 被认为是一种技巧,应该避免使用。当使用它们时,人们应该注意不要引起问题。这并不是 AROS_LP 宏的责任来修复它。在 ABI V1 分支中,有一种机制可以帮助您摆脱所有这些 #define 语句。

AROS_UFCx() 应该*只*用于 regcall 例程。如果 VNewRawDoFmt() 需要一个 stackcall 例程,请勿使用 AROS_UFCx()。只需声明一个普通的 C 例程即可。是的,MorphOS 就是这样做的。对于这种破坏性更改,我感到很抱歉。我在完成文档之前就实现了 VNewRawDoFmt()。我非常确定没有人使用过它来执行自定义回调例程。事实上,在 exec/rawfmt.h 中声明的魔术常量涵盖了函数使用量的 99%。

我注意到 AROS 程序加载速度比 AOS 上慢很多。我查看了 AROS 源代码,看起来文件操作到 load_block 会经过多个角落,并且在使用 fgetc 时看起来很慢。为什么 load_block 函数不能直接执行 AOS 读取?ELF 文件的字节序是否与 68k 平台的字节序不同?一个块的大小是否不超过 4 KB?如果是,使用直接读取总是比使用 fgetc(从 ELF 加载程序调用)快很多。

static void * load_block
(
    BPTR               file,
    ULONG              offset,
    ULONG              size,
    LONG              *funcarray,
    struct DosLibrary *DOSBase
)
{
    void *block = MyAlloc(size, MEMF_ANY);
    if (block)
    {
        if (read_block(file, offset, block, size, funcarray, DOSBase))
            return block;

        MyFree(block, size);
    }
    else
        SetIoErr(ERROR_NO_FREE_STORE);

    return NULL;
}

here are the lots of corner snippets that do at end only load some bytes in.

.........................

static int read_block
(
    BPTR               file,
    ULONG              offset,
    APTR               buffer,
    ULONG              size,
    LONG              *funcarray,
    struct DosLibrary *DOSBase
)
{
    UBYTE *buf = (UBYTE *)buffer;
    LONG   subsize;

    if (Seek(file, offset, OFFSET_BEGINNING) < 0)
        return 0;

    while (size)
    {
        subsize = MyRead(file, buf, size);

        if (subsize <= 0)
        {
            if (subsize == 0)
                SetIoErr(ERROR_BAD_HUNK);

            return 0;
        }

        buf  += subsize;
        size -= subsize;
    }

    return 1;
}

#define MyRead(file, buf, size)      \
    AROS_CALL3                       \
    (                                \
        LONG, funcarray[0],          \
        AROS_LCA(BPTR,   file, D1),  \
        AROS_LCA(void *, buf,  D2),  \
        AROS_LCA(LONG,   size, D3),  \
        struct DosLibrary *, DOSBase \
    )


static AROS_UFH4(LONG, ReadFunc,
    AROS_UFHA(BPTR, file,   D1),
    AROS_UFHA(APTR, buffer, D2),
    AROS_UFHA(LONG, length, D3),
        AROS_UFHA(struct DosLibrary *, DOSBase, A6)
)
{
    AROS_USERFUNC_INIT

    return FRead(file, buffer, 1, length);

    AROS_USERFUNC_EXIT
}



优化

[edit | edit source]

优化就像修复 bug 一样,虽然您希望创建完美的产品,但现实情况是您的生命周期有限,并且您首先要解决最大的问题。如果程序非关键部分中的小错误没有导致产品无法使用,那么即使它们没有被修复也没关系。同样,如果很少使用的慢速例程永远不会被替换,因为总体速度提升可能是微不足道的。

两者之间的区别在于,bug 是绝对的:某件事要么在所有情况下都按照预期和允许的方式执行,要么不执行。如果不执行,那么导致这种情况的原因被称为 bug。另一方面,优化是相对的。对于速度优化,存在权衡。您始终可以获得比当前解决方案更快的速度,但代价是牺牲一个或多个其他因素,例如内存使用量、磁盘空间或可维护性。

在开发中,尤其是可维护性成本是一个问题:如果您仍在开发,但为了速度而使代码变得难以理解,那么就无法找到剩余的 bug。通常,这被称为“优化一个工作程序比让一个优化的程序工作更容易”。因此,在开发中,对于相同的代码段,修复 bug 的优先级高于速度优化。

这将是一个非常奇怪的现象。速度和清晰度通常是相互权衡的。是什么其他因素被优化了,导致这两者都受到了影响?

不,一个好的编译器可以为大多数抽象类型创建相当好的代码,包括面向对象编程。可能确实会有一些速度损失,因为这是为了获得更清晰的源代码而付出的代价。当然,更清晰的源代码使调试更容易,而不是更难。

Knud 提到一些程序员试图编写高度优化的代码,这会导致调试和维护方面出现重大问题。他认为,在 97% 的情况下,优化都是浪费。然后他说,过早优化是不好的,但我们应该优化那 3% 的代码。(言外之意是,在确定代码属于那 3% 之前,不应该进行优化。) 在 AROS 中,只有少数性能瓶颈,例如 exe 加载、图标库和 OO。当修复这些问题并且不优化其他代码时,AROS 对用户的响应速度会大幅提升。这确实与 Knud 的观点一致:如果我们知道 exe 加载、图标库或 OO 属于那 3%,无论它们是什么,都应该针对速度进行优化。


发现传递给 DoSuperNew() 的属性列表在到达超类的 OM_NEW 方法时已失效(例如,只有第一个 ti_Tag 值大于 0x80000000)。可以通过将 NList_mcc.c 和 NListview.c 的编译选项设置为 -O0 来解决此问题。

我怀疑 GCC 在启用优化时会将 DoSuperNew() 方法内联到这些文件中,因此不会将变长参数放在堆栈上,结果会导致传递给 DoSuperMethod() 的 &tag1(AROS_SLOWSTACKTAGS_ARG(tag1)) 作为属性列表,其后不一定跟着剩余的标签。这可能意味着我们不能再在 i386 上不用 AROS_SLOWSTACKTAGS 了,因为我们不应该假设变长参数位于堆栈上(而应该使用 va_list 等)。引入 ABIv0 的 SLOWSTACKTAGS 会破坏二进制兼容性吗?



GCC 补丁

[编辑 | 编辑源代码]

我的 GCC 4.5.1 补丁还没有准备好供大众使用。我仍然在任务就绪和等待列表中遇到列表损坏问题,我开始担心隐藏着 GCC 的错误。

From f68b80717efec2ccf4c181c9a3fc4184fde27be1 Mon Sep 17 00:00:00 2001
From: Jason S. McMullan <jason.mcmullan AT netronome.com>
Date: Sun, 10 Oct 2010 00:38:26 -0400
Subject: [PATCH] [m68k-amiga] Amiga ABI support

Moves the FP to A5, doubling up with the PIC
Breaks all -fpic modes.

NOT FOR UPSTREAM: This breaks *all* other m68k APIs!!!

Signed-off-by: Jason S. McMullan <jason.mcmullan AT netronome.com>
---
 gcc/config/m68k/m68k.c  |    8 ++++----
 gcc/config/m68k/m68k.h  |    6 +++---
 gcc/config/m68k/m68k.md |    4 ++--
 3 files changed, 9 insertions(+), 9 deletions(-)

diff --git a/gcc/config/m68k/m68k.c b/gcc/config/m68k/m68k.c
index c22f3b8..9718ccb 100644
--- a/gcc/config/m68k/m68k.c
+++ b/gcc/config/m68k/m68k.c
@@ -920,7 +920,7 @@ m68k_initial_elimination_offset (int from, int to)
 static bool
 m68k_save_reg (unsigned int regno, bool interrupt_handler)
 {
-  if (flag_pic && regno == PIC_REG)
+  if (flag_pic && regno == A5_REG)
     {
       if (crtl->saves_all_registers)
 	return true;
@@ -2186,7 +2186,7 @@ static rtx
 m68k_get_gp (void)
 {
   if (pic_offset_table_rtx == NULL_RTX)
-    pic_offset_table_rtx = gen_rtx_REG (Pmode, PIC_REG);
+    pic_offset_table_rtx = gen_rtx_REG (Pmode, A5_REG);
 
   crtl->uses_pic_offset_table = 1;
 
@@ -4640,7 +4640,7 @@ m68k_delegitimize_address (rtx orig_x)
   if (GET_CODE (x) == PLUS
       && GET_CODE (XEXP (x, 1)) == CONST
       && REG_P (XEXP (x, 0))
-      && REGNO (XEXP (x, 0)) == PIC_REG)
+      && REGNO (XEXP (x, 0)) == A5_REG)
     {
       y = x = XEXP (XEXP (x, 1), 0);
 
@@ -5145,7 +5145,7 @@ m68k_output_mi_thunk (FILE *file, tree thunk ATTRIBUTE_UNUSED,
 
   /* Restore the original PIC register.  */
   if (flag_pic)
-    SET_REGNO (pic_offset_table_rtx, PIC_REG);
+    SET_REGNO (pic_offset_table_rtx, A5_REG);
 }
 
 /* Worker function for TARGET_STRUCT_VALUE_RTX.  */
diff --git a/gcc/config/m68k/m68k.h b/gcc/config/m68k/m68k.h
index 5787e8a..1d36a63 100644
--- a/gcc/config/m68k/m68k.h
+++ b/gcc/config/m68k/m68k.h
@@ -348,7 +348,7 @@ along with GCC; see the file COPYING3.  If not see
 #define PIC_OFFSET_TABLE_REGNUM				\
   (!flag_pic ? INVALID_REGNUM				\
    : reload_completed ? REGNO (pic_offset_table_rtx)	\
-   : PIC_REG)
+   : A5_REG)
 
 /* 1 for registers that have pervasive standard uses
    and are not available for the register allocator.
@@ -416,7 +416,7 @@ along with GCC; see the file COPYING3.  If not see
 	  fixed_regs[i] = call_used_regs[i] = 1;		\
     }								\
   if (flag_pic)							\
-    fixed_regs[PIC_REG] = call_used_regs[PIC_REG] = 1;		\
+    fixed_regs[A5_REG] = call_used_regs[A5_REG] = 1;		\
 }
 
 /* On the m68k, ordinary registers hold 32 bits worth;
@@ -453,7 +453,7 @@ along with GCC; see the file COPYING3.  If not see
 /* Most m68k targets use %a6 as a frame pointer.  The AmigaOS
    ABI uses %a6 for shared library calls, therefore the frame
    pointer is shifted to %a5 on this target.  */
-#define FRAME_POINTER_REGNUM A6_REG
+#define FRAME_POINTER_REGNUM A5_REG
 
 /* Base register for access to arguments of the function.
  * This isn't a hardware register. It will be eliminated to the
diff --git a/gcc/config/m68k/m68k.md b/gcc/config/m68k/m68k.md
index f89037f..9f3da5a 100644
--- a/gcc/config/m68k/m68k.md
+++ b/gcc/config/m68k/m68k.md
@@ -131,7 +131,7 @@
   [(D0_REG		0)
    (A0_REG		8)
    (A1_REG		9)
-   (PIC_REG		13)
+   (A5_REG		13)
    (A6_REG		14)
    (SP_REG		15)
    (FP0_REG		16)
@@ -7295,7 +7295,7 @@
 {
   if (TARGET_ID_SHARED_LIBRARY)
     {
-      operands[1] = gen_rtx_REG (Pmode, PIC_REG);
+      operands[1] = gen_rtx_REG (Pmode, A5_REG);
       return MOTOROLA ? "move.l %?(%1),%0" : "movel %1@(%?), %0";
     }
   else if (MOTOROLA)
-- 
1.7.1




函数地址通过在库的 .conf 文件中列出它们来放置在库的 LVO 表中。在库中的任何位置,无论调用链有多深,都可以使用 AROS_GET_LIBBASE 宏访问库基址(实际上只是检索 %ebx 指向地址的值)(x86 代码)。那么,除了浪费 %bx 寄存器之外,这对于现有代码(已经将库基址传递给需要它的子函数)有什么优势呢?

在这种情况下,没有真正的优势,因为该代码已经绕过了当前 Amiga 共享库实现的缺陷。对于新的代码,可以节省每次函数调用时压入堆栈的所有 libbases 所占用的堆栈空间。

我个人没有看到在 i386 上实现它的方法,除非为它保留 %ebx。我选择 %ebx,因为它在 SYSV 中被记录为位置无关代码的全局偏移表基址寄存器;我发现它有点相关。

如果您打算使用 %bx 寄存器,也许使用 -fPIC 编译的代码会更好,并使用 %bx 指向该 OpenLibrary() 实例的 ELF GOT 表。这将使所有端口更容易,因为 -fPIC 对于 ARM、x86、x86_64、m68k 和 PPC 都有明确定义。

我快速浏览了一下,但似乎在 i386 上,生成的 __GLOBAL_OFFSET_TABLE__ 是一个地址,所以访问是通过地址而不是通过寄存器完成的。这在 AROS 上会带来问题,因为 AROS 只有一个地址空间,共享库只加载到内存中一次。

我对 -fPIC 的第二个问题是它是一种非此即彼的方法:当您指定它时,所有对全局变量的访问都通过 __GLOBAL_OFFSET_TABLE__ 完成。我想要继续支持当前情况,其中只有显式放在库基址中的字段是每个打开器(每个任务)的,而其余的全局符号是共享的。

总的来说,我发现 -fPIC 太过面向 UNIX 系统,UNIX 系统有虚拟内存和每个进程都有独立的地址空间。我不是这方面的专家,所以对于我可能做出的任何错误结论,我持开放态度。

但我确实需要类似于 -fPIC 但适应 AROS 架构的东西:- 在所有 CPU 上通过寄存器调用完成 - 能够在存根代码中设置寄存器 - 能够记住寄存器的先前值并在函数调用后恢复它。我认为如果使用 -fPIC,这还没有解决,因为我认为它是在链接时遇到 .so 时解决的。

我当然不想将 .so 共享对象概念复制到 AROS(就像 AOS4 所做的那样)。- 只有为 libbase 保留寄存器,默认情况下不要通过 GOT 对所有全局变量进行寻址。

对于 m68k,我认为我们想要的 -fPIC 编译选项是

-fPIC -msep-data

如果指定此选项,对 m68k 的影响是什么?我该如何通过这种机制传递 libbase?

我还忘了说,我打算在 %ebx 中使用 libbase,以便能够在不需要这些丑陋的 #define xxxBase 技巧的情况下拥有没有 .bss 或 .data 部分的模块。

最终,我认为我们必须深入研究一些编译器的内部。无论是 LLVM 还是 GCC,我认为选择 AROS 编译器并开始对其进行调整以满足我们的需求的时机已经到来。

我甚至更进一步 - 正确使用可变参数列表会带来如此大的改变吗?AROS 看起来是一个研究型操作系统,不正确使用可变参数列表是可以在很大程度上改进的地方之一…… 可变参数列表对于 x86_64 来说尤其成问题,因为 sizeof(void*) != sizeof(int)。

尽管我很想正确使用它们,但隐式可变参数列表在几乎所有使用 BOOPSI 的 Amiga 源代码中都被大量使用(并被滥用)。

打破这种假设会破坏类似这样的代码(根据我移植到 x86_64 的经验,这种代码非常普遍)。

struct fooStruct {
     int a;
     char b;
     void *c;
};

struct booStruct {
    long qux;
    char *name;
};

#define fooID 0xf00
#define booID 0xb00

void handleMethod(ULONG methodID, ...)
{
   struct fooStruct *foo;
   struct booStruct *boo;

   switch (methodID) {
   case fooID:
       foo = (struct fooStruct *)((&methodID)+1);
       handleFoo(foo);
       break;
   case booID:
       foo = (struct booStruct *)((&methodID)+1);
       handleBoo(boo);
       break;
   }
}

...

handleMethod(fooID, 1, 'd', &somebuffer);

handleMethod(booID, 99, "Hello World");



`.data' 无法放入区域 `invalid' /home/mike/amigaos/aros-m68k-bin/lib/gcc/m68k-elf/4.5.1/../../../../m68k-elf/bin/ld: 区域 `invalid' 溢出 136 字节

这意味着在某个地方存在一些非常量(不可 ROM 化)数据。

编辑 arch/m68k-amiga/boot/rom.ld,找到 "invalid (rwx)" 行,将 l = 0x0 替换为 l = 0x100(或其他大于 136 的值)。现在应该可以编译了(但无法运行)。

列出不正确的数据符号

m68k-elf-nm -ln <huge rom image.elf> | grep dead

请务必撤销对 rom.ld 的更改,如果忘记了修改并报告了将来因非法 0xdeadxxxx 地址导致的所谓的崩溃“错误”,我们概不负责。:)



哦,我计划在调用进程的 tc_TrapCode 时,使 m68k 异常在堆栈上与 AmigaOS 完全一致,但我需要知道 AROS 内核 Sonic 正在开发的内容的期望。

通过使用 %a6 的寄存器声明,gcc 假设所有对 %a6 的使用都是对 AROS_GET_FP 全局变量的引用。

要获取帧指针,您不能依赖 %fp(或 %bp,或任何类似的东西),因为如果使用 -fomit-frame-pointer,GCC 可能会覆盖它。

__builtin_frame_address(1) 应该是这种情况下所需要的(调用例程的帧指针)。

无论如何,%a5 都是 AROS/m68k 下的帧指针,而不是 %a6。

我现在正在编译和测试它,但这是根据“git bisect”得出的结论。


修复构建。exec/types.h 没有定义 size_t,sys/types.h 定义了它。

stddef.h 更好,因为它符合 ANSI-C。sys/types.h 符合 POSIX。



我在 AROS 代码中搜索 text bestcmodeid,但我没有看到 Wanderer 使用它。所以我想我的 modeid 与安装不匹配。使用 bestcmodeidtags 是最好的,因为 P96 模式编号在所有 winuae 系统上都不同。也许 Wanderer 可以改变?

以下代码来自 SDL。如果这里没有屏幕分辨率,此命令将自动提供下一个可能的 modeid。

        okid=BestCModeIDTags(CYBRBIDTG_NominalWidth,SDL_Display->Width,
                CYBRBIDTG_NominalHeight,SDL_Display->Height,
                CYBRBIDTG_Depth,bpp,
                TAG_DONE);
        }

以下是一些显示如何使用 P96 设置特定像素格式的源代码。它在 68k P96 和 68k CGX 上进行了测试,并在 Amiga GFX 卡上也报告工作正常。

        if (bpp == 16)
      {
          UWORD pixfmt[] ={PIXFMT_RGB16,-1};
        unsigned long *ret;
          struct CyberModeNode * cnode;
        ret = AllocCModeListTags(CYBRMREQ_MinWidth,width,CYBRMREQ_MinHeight,height,
            CYBRMREQ_MaxWidth,width+1000,CYBRMREQ_MaxHeight,height+1000,
            CYBRMREQ_MaxDepth,bpp,CYBRMREQ_MinDepth,16,CYBRMREQ_CModelArray,&pixfmt,TAG_END);
            if (ret)
                  {cnode = *ret;
                  if (cnode)okid = cnode->DisplayID;
                  }
      if (!IsCyberModeID(okid))okid = INVALID_ID;
      kprintf(" RGB16  Mode ID %lx\n",okid);
      }

也许是我的某些 winuae 设置。是否存在已知可以正常工作的 winuae 配置文件?


有人知道 m68k 的 ABI 参考吗?我感兴趣的是函数调用的参数传递。所有 C 语言参数都通过堆栈传递(对于非 LVO 调用)。C 函数的返回值位于 D0 中。寄存器 D0/D1 和 A0/A1 可以被被调用函数用作临时寄存器,调用者必须预期它们会被破坏。寄存器 D2-D7 和 A2-A7 必须被被调用函数保留。(一些编译器允许每个参数进行覆盖,但它们会显式地将寄存器映射到参数)。

更具体地说:谁在函数调用期间拥有 A6?调用者。它是否在函数调用中被保留?是的,如果被调用函数修改了它,则必须保留它。

寄存器 A6 是 LibBase,A5 是帧指针(可选),A4 是指向 .data/.bss 区域的指针(对于某些编译器)。

A6 是该库的 libbase,图形库中的大多数库内调用都是 LVO(寄存器)调用,所以这并不奇怪。

GfxBase 是一个 LVO 调用。

在 AmigaOS 中,有三种或四种主要的调用约定,具体取决于你问谁。我写的都是凭记忆,所以不要完全相信我说的话。

C 调用约定:慢如冰冻的糖蜜,将所有内容都通过堆栈传递。支持可变参数列表,但除此之外几乎毫无用处,通常会优化为另一种调用约定。返回值在 D0 中。不应与共享库一起使用,除非用于可变参数列表存根调用。

LVO 调用约定:LibCalls 始终允许将 D0/D1/A0/A1 用作临时寄存器,并且不会被子例程保留。剩余的寄存器必须被子例程保留。A6 寄存器始终在此调用约定期间保存库基址。可以保留 A4 中的全局变量和局部变量堆,除非使用大数据模型。可以使用 A5 中的可选帧指针进行调试。

标准调用约定:与 LVO 调用约定相同,只是不需要库基址。需要使用 C 调用约定编写的存根函数来实现可变参数列表,因为它们在此处不受支持。


有任何基准测试证实这种速度缓慢吗?如果它真的那么慢,为什么 C 调用函数会被用于非库调用?当然,这种影响在没有数据缓存且只有芯片内存的 CPU 上最为明显。我们应该让 m68k AROS 编译器对所有函数调用使用寄存器参数传递吗?

也就是说,堆栈缓存只存在于 '060 上,因此寄存器传递绝对是优先考虑的。C 调用约定之所以使用,仅仅是为了可变参数列表。没有其他理由使用 C 调用约定。使用寄存器传递的标准调用约定要常见得多。

此外,关于 LLVM 的调用约定,该编译器还支持另一种称为“cold”调用约定的约定,用于不太常调用的子例程,并且在调用它们时,需要尽可能少地接触寄存器。在 68k 上,这意味着只使用临时寄存器和堆栈,而不会覆盖任何其他寄存器。它只用于优化和与 LLVM 的兼容性。

虽然 Aros-m68k 不需要 MMU,但 68030 和 68040 使用不同的管理指令访问寄存器,(部分)不同的管理寄存器,以及不同的寄存器位映射和页面描述符。68030 MMU 确实支持更多页面大小,并且总体上更灵活。为了提高速度并降低复杂度,68040 简化了 MMU 设计。68040 和 68060 的 MMU 几乎相同,68060 只是在 mmu 表缓存和重命名一些缓存模式方面添加了一些限制。68060 上的 MMU 异常处理也不同。



记录一下,我写了 Haiku 中内核 elf 加载器 的 m68k 部分:(虽然现在还没有测试过,但内核目前无法构建)

顺便说一下,我在 Ti92 时代 (1997 年) 的档案中找到了一个用于将 HUNK 支持添加到 BFD 的旧 binutils 补丁,当然可以移植到更新的 binutils。奇怪的是,没有人保留它。我还记得写了一些代码来读取 hunks 以转换为 ti 格式。(第一次 Ti 68k 开发是使用 a68k 完成的,有些人使用 amiga 交叉编译器,早于 tigcc 时代。)

华夏公益教科书