Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
31 changes: 28 additions & 3 deletions .github/workflows/branch.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ env:
AUTOTESTER_ROM: ${{github.workspace}}/secrets/83pce_515_530.rom
CEDEV: ${{github.workspace}}/CEdev
CEDEV_BIN: ${{github.workspace}}/CEdev/bin
CEDEV_BINUTILS_BIN: ${{github.workspace}}/CEdev/binutils/bin
CEDEV_EXAMPLES: ${{github.workspace}}/CEdev/examples
CEDEV_TEST: ${{github.workspace}}/toolchain/test
CEMU_PATH: ${{github.workspace}}/CEmu
Expand All @@ -33,24 +34,30 @@ jobs:
fasmg: /source/macos/x64/fasmg
arch-suffix: "-intel"
ez80-bins-suffix: macOS_intel
binutils-suffix: macos_intel
- runs-on: macos-14
fasmg: /source/macos/x64/fasmg
arch-suffix: "-arm"
ez80-bins-suffix: macOS_arm
binutils-suffix: macos_arm
- runs-on: windows-latest
fasmg: /fasmg.exe
ez80-bins-suffix: windows
binutils-suffix: windows
env: "env:"
exe: .exe
nul: nul
ldflags: LDFLAGS="-static-libgcc -static-libstdc++ -static"
- runs-on: ubuntu-22.04
ez80-bins-suffix: ubuntu
binutils-suffix: ubuntu
fasmg: /fasmg.x64
runs-on: ${{matrix.runs-on}}
steps:
- name: Prepare Build Environment
run: cmake -E echo >> $${{matrix.env}}GITHUB_PATH ${{env.CEDEV_BIN}}
run: |
cmake -E echo >> $${{matrix.env}}GITHUB_PATH ${{env.CEDEV_BIN}}
cmake -E echo >> $${{matrix.env}}GITHUB_PATH ${{env.CEDEV_BINUTILS_BIN}}

- name: Download ez80-clang and ez80-link
id: ez80-bins
Expand All @@ -63,6 +70,17 @@ jobs:
pathSource: ${{steps.ez80-bins.outputs.file-path}}
pathTarget: ${{env.CEDEV_BIN}}

- name: Download binutils
id: binutils
uses: carlosperate/download-file-action@v2.0.2
with:
file-url: https://github.com/CE-Programming/binutils-gdb/releases/download/nightly/binutils_${{matrix.binutils-suffix}}_nightly.zip
- name: Extract binutils
uses: DuckSoft/extract-7z-action@v1.0
with:
pathSource: ${{steps.binutils.outputs.file-path}}
pathTarget: ${{env.CEDEV}}

- name: Add fasmg website to /etc/hosts since DNS seems to be broken
if: runner.os == 'macOS'
run: |
Expand Down Expand Up @@ -109,7 +127,9 @@ jobs:

- name: Make Binaries Executable
if: runner.os != 'Windows'
run: chmod +x ${{env.CEDEV_BIN}}/*
run: |
chmod +x ${{env.CEDEV_BIN}}/*
chmod +x ${{env.CEDEV_BINUTILS_BIN}}/*
- name: Test Build Dependencies
run: |
ez80-clang --version
Expand All @@ -135,9 +155,14 @@ jobs:
PREFIX: ${{github.workspace}}
run: make -j4 -C ${{env.TOOLCHAIN_PATH}} install V=1 DESTDIR=${{github.workspace}}

- name: Remove Fasmg
run: cmake -E rm -f ${{env.CEDEV_BIN}}/fasmg${{matrix.exe}}

- name: Make Binaries Executable
if: runner.os != 'Windows'
run: chmod +x ${{env.CEDEV_BIN}}/*
run: |
chmod +x ${{env.CEDEV_BIN}}/*
chmod +x ${{env.CEDEV_BINUTILS_BIN}}/*

- name: Build Test Graphics
run: make -j4 -C ${{env.CEDEV_TEST}} COMPRESSED=${{matrix.compressed}} V=1 gfx
Expand Down
28 changes: 25 additions & 3 deletions .github/workflows/make.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ env:
AUTOTESTER_ROM: ${{github.workspace}}/secrets/83pce_515_530.rom
CEDEV: ${{github.workspace}}/CEdev
CEDEV_BIN: ${{github.workspace}}/CEdev/bin
CEDEV_BINUTILS_BIN: ${{github.workspace}}/CEdev/binutils/bin
CEDEV_EXAMPLES: ${{github.workspace}}/CEdev/examples
CEDEV_TEST: ${{github.workspace}}/toolchain/test
CEMU_PATH: ${{github.workspace}}/CEmu
Expand All @@ -33,28 +34,34 @@ jobs:
fasmg: /source/macos/x64/fasmg
arch-suffix: "-intel"
ez80-bins-suffix: macOS_intel
binutils-suffix: macos_intel
install-output-ext: "dmg"
- runs-on: macos-14
fasmg: /source/macos/x64/fasmg
arch-suffix: "-arm"
ez80-bins-suffix: macOS_arm
binutils-suffix: macos_arm
install-output-ext: "dmg"
- runs-on: windows-latest
fasmg: /fasmg.exe
ez80-bins-suffix: windows
binutils-suffix: windows
env: "env:"
exe: .exe
nul: nul
ldflags: LDFLAGS="-static-libgcc -static-libstdc++ -static"
install-output-ext: "zip"
- runs-on: ubuntu-22.04
ez80-bins-suffix: ubuntu
binutils-suffix: ubuntu
fasmg: /fasmg.x64
install-output-ext: "tar.gz"
runs-on: ${{matrix.runs-on}}
steps:
- name: Prepare Build Environment
run: cmake -E echo >> $${{matrix.env}}GITHUB_PATH ${{env.CEDEV_BIN}}
run: |
cmake -E echo >> $${{matrix.env}}GITHUB_PATH ${{env.CEDEV_BIN}}
cmake -E echo >> $${{matrix.env}}GITHUB_PATH ${{env.CEDEV_BINUTILS_BIN}}

- name: Download ez80-clang and ez80-link
id: ez80-bins
Expand All @@ -67,6 +74,17 @@ jobs:
pathSource: ${{steps.ez80-bins.outputs.file-path}}
pathTarget: ${{env.CEDEV_BIN}}

- name: Download binutils
id: binutils
uses: carlosperate/download-file-action@v2.0.2
with:
file-url: https://github.com/CE-Programming/binutils-gdb/releases/download/nightly/binutils_${{matrix.binutils-suffix}}_nightly.zip
- name: Extract binutils
uses: DuckSoft/extract-7z-action@v1.0
with:
pathSource: ${{steps.binutils.outputs.file-path}}
pathTarget: ${{env.CEDEV}}

- name: Add fasmg website to /etc/hosts since DNS seems to be broken
if: runner.os == 'macOS'
run: |
Expand Down Expand Up @@ -139,9 +157,14 @@ jobs:
PREFIX: ${{github.workspace}}
run: make -j4 -C ${{env.TOOLCHAIN_PATH}} install V=1 DESTDIR=${{github.workspace}}

- name: Remove Fasmg
run: cmake -E rm -f ${{env.CEDEV_BIN}}/fasmg${{matrix.exe}}

- name: Make Binaries Executable
if: runner.os != 'Windows'
run: chmod +x ${{env.CEDEV_BIN}}/*
run: |
chmod +x ${{env.CEDEV_BIN}}/*
chmod +x ${{env.CEDEV_BINUTILS_BIN}}/*

- name: "[macOS] CodeSign Toolchain binaries"
if: runner.os == 'macOS' && github.repository == 'CE-Programming/toolchain' # don't run on forks, since they don't have secrets
Expand Down Expand Up @@ -461,4 +484,3 @@ jobs:
token: ${{ secrets.CI_PAT_CLIBS_NIGHTLTY }}
repository: CE-Programming/libraries
event-type: ci-clibs-nightly

3 changes: 2 additions & 1 deletion docs/headers/ti/sprintf.rst
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,8 @@ The truncating behavior of C99 `snprintf` can be replicated with `boot_asprintf`
printf and fprintf
------------------
`printf` and `fprintf` can be replicated by using `fputs`

`printf` and `fprintf` can be replicated by using `fputs`.

.. code-block:: c
Expand Down
96 changes: 43 additions & 53 deletions docs/static/asm.rst
Original file line number Diff line number Diff line change
@@ -1,60 +1,50 @@
.. _asm:

Assembly Routines
=================
Assembly Files
==============

Assembly routines can be linked into a C/C++ program by putting them into the same **src** directory that your C/C++ sources are in, but with an **.asm** extension.
These can be placed in any subdirectory of **src** just like C/C++ sources.
Assembly files can be linked into a C/C++ program by putting them into the same **src** directory that your C/C++ sources are in.
Use a **.S** extension if you want the compiler's preprocessor to run on the file first, or use a **.s** extension if the assembly file does not need to be preprocessed.

Assembly Files
--------------
The use of inline assembly is supported, but highly discouraged as future changes to the compiler may render the inline assembly incompatible, and it reduces the readablity of the code.

Assembler
---------

.. _asm-consts:
The CE Toolchain uses the GNU Assembler (GAS) to assemble source files.
Historically the fasmg assembler was used, but is no longer supported to allow for better cross-platform support and linking performance.

Constants
^^^^^^^^^
Documentation for the GNU Assembler: https://www.sourceware.org/binutils/docs/as/index.html

The top of the file is a good place defining constants or including other files that define constants.
These will be availabe throughout the rest of the file, but not in other files.
You can define a constant by saying :code:`my_constant := 42`.
You can include common constants in multiple files by defining them in a file named, say, **file.inc** and putting :code:`include 'file.inc'` in every file that needs them.
You should not generally put any labels, code, or data here.
If you try to reference a label defined here, you will get an :code:`Error: variable term used where not expected.` linker error which means you are trying to resolve an address that doesn't belong to any section.
See :ref:`asm-section` to fix this problem.
Specific Z80/ez80 directives: https://www.sourceware.org/binutils/docs/as/Z80-Directives.html

.. _asm-assume:

Assume
^^^^^^

You should add a :code:`assume adl=1` before trying to emit any code, which ensures that you get 24-bit eZ80 instructions.
If you end an assembly file with :code:`assume adl=0` (which is the eZ80's 16-bit Z80 compatibility mode), it will propogate to another random assembly file.
All toolchain and compiler-generated sources make sure to reset the mode at the top of the file and end the file in the same mode, but if one of your sources end in Z80 mode, then any other one of your sources might begin in Z80 mode, so it is safer to put the :code:`assume` line in every file.
You should add a :code:`.assume ADL=1` before trying to emit any code, which ensures that you get 24-bit eZ80 instructions.

.. _asm-section:

Section
^^^^^^^
Sections
^^^^^^^^

Now that we are in the correct mode, we need to tell the linker where to put things.
We use :code:`section .text` for code, :code:`section .data` for variables, and :code:`section .rodata` for constant data.
Currently these are all placed in RAM, so which section you choose to switch to is much less important than how often you switch sections, even if you are switching to the same section you are already in.
This is because every time you start a new, or restart the same, section, the linker gets a new opportunity to delete a block of dead code/data.
The CE Toolchain uses :code:`.section .text` for code, :code:`.section .data` for variables, and :code:`.section .rodata` for constant data.
Every time you start a new section (such as :code:`.section .text.function`), the linker has an opportunity to delete a block of dead code/data.
Because of this, the correct time to switch sections is usually every time you start a new function or variable.
You should not let execution fall off the end of a block because you won't know if that block will be included or deleted from the output, however you can if you say :code:`require _symbol` of some public or private symbol defined in the next section to ensure that if the current block is included, then that will force the next block to also be included.
To define a symbol in a block that can be referenced from other blocks, you should do :code:`private _symbol` or :code:`public _symbol` right before its definition.
If it is private then it is only able to be referenced from the same file and no :ref:`extern <asm-extern>` should be used.
If it is public then it can be referenced within the same file without :ref:`extern <asm-extern>` just like private symbols, but public symbols can also be referenced from other files and even C/C++!
The public assembly symbol named :code:`_symbol` is accessible in C by the global name :code:`symbol`, assuming it is properly declared, with your asm symbol acting as the definition.
To define a symbol in a block that can be referenced from other blocks, you should do :code:`.local _symbol` or :code:`.global _symbol` right before its definition.
If it is local then it is only able to be referenced from the same file and no :ref:`.extern <asm-extern>` should be used.
If it is global then it can be referenced within the same file without :ref:`.extern <asm-extern>` just like local symbols, but global symbols can also be referenced from other files and even C/C++!
The gllobal assembly symbol named :code:`_symbol` is accessible in C by the global name :code:`symbol` (note the leading underscore), assuming it is properly declared, with your asm symbol acting as the definition.

.. _asm-extern:

Extern
^^^^^^

At the end of the file is a good place to list every external symbol that you might depend on like :code:`extern _symbol`.
This includes both public symbols defined in another assembly file and global symbols from C, prefixed with an underscore like usual.
Lastly, you should not let execution fall off the end of a file because the next file that gets assembled is unpredictable and you could end up anywhere!
At the end of the file is a good place to list every external symbol that you might depend on like :code:`.extern _symbol`.
This includes both global symbols defined in another assembly file and global symbols from C, prefixed with an underscore.
Block ordering can only be relied on within a single file, and only for blocks belonging to the same section.

Linking ASM routines to C/C++
Expand All @@ -69,17 +59,18 @@ Below is an example C prototype followed by the assembly implementation:

.. code-block:: c

void asm_func(int arg);
void asm_func(int argument);

:code:`asm_func.asm`

.. code-block::

assume adl=1

section .text

public _asm_func
.assume adl=1

.section .text._asm_func
.global _asm_func
.type _asm_func, @function

_asm_func:
pop hl
pop de
Expand All @@ -91,33 +82,29 @@ Below is an example C prototype followed by the assembly implementation:
pop de

ret
extern _external_func

.extern _external_func

:code:`asm_func.c`

.. code-block::

int external_func(int arg) {
int external_func(int arg)
{
printf("external_func called with %d\n", arg);
return 4321;
}

void test() {
void test(void)
{
int arg = 1234;
printf("calling asm_func with %d\n", arg);
int ret = asm_func(arg);
printf("asm_func returned %d\n", ret);
}

Preserve
^^^^^^^^

Assembly routines must preserve the :code:`IX` and :code:`SP` registers.
All other registers are free for use.

Arguments
^^^^^^^^^
ABI Arguments
^^^^^^^^^^^^^

Arguments are pushed from last to first corresponding to the C prototype.
In eZ80, 3 bytes are always pushed to the stack regardless of the actual size.
Expand All @@ -126,6 +113,9 @@ For example, if a *short* type is used, the upper byte of the value pushed on th
This table lists the locations relative to *sp* from within the called funciton.
Note that :code:`sp + [0,2]` contains the return address.

Assembly routines must preserve the :code:`IX` and :code:`SP` registers.
All other registers are free for use.

+-------------+------------+----------------------+
| C/C++ Type | Size | Stack Location |
+=============+============+======================+
Expand All @@ -150,8 +140,8 @@ Note that :code:`sp + [0,2]` contains the return address.
| pointer | 3 bytes | sp + [3,5] |
+-------------+------------+----------------------+

Returns
^^^^^^^
ABI Returns
^^^^^^^^^^^

This table lists which registers are used for return values from a function.
The type's sign does not affect the registers used, but may affect the value returned.
Expand Down
20 changes: 16 additions & 4 deletions docs/static/contributing.rst
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,16 @@ Building the CE Toolchain
Linux and macOS
~~~~~~~~~~~~~~~

Get the `ez80 LLVM compiler <https://github.com/jacobly0/llvm-project/wiki>`_.
It is usually easier to download a toolchain release which already contains the needed binaries for compiling/assembling if you are just making code modifications to the toolchain.
If you need to do everything from scratch though, the steps are below.

Download the prebuilt `ez80 LLVM compiler <https://github.com/CE-Programming/llvm-project/releases/tag/nightly>`_.
Make sure that ``ez80-clang`` and ``ez80-link`` are reachable by the system's PATH environment variable.

Get the `fasmg assembler <https://flatassembler.net/download.php>`_.
Download the prebuilt `ez80 GNU binutils <https://github.com/CE-Programming/binutils-gdb/releases/tag/nightly>`_
Make sure that ``bin`` directory is reachable by the system's PATH environment variable.

Download the `fasmg assembler <https://flatassembler.net/download.php>`_.
The download is located near the bottom of the page.
Extract the ``fasmg.x64`` executable to the same location as the compiler.
Rename it to just ``fasmg``.
Expand All @@ -51,15 +57,21 @@ This is configurable with :code:`make install PREFIX=[LOCATION]`
Windows
~~~~~~~

It is usually easier to download a toolchain release which already contains the needed binaries for compiling/assembling if you are just making code modifications to the toolchain.
If you need to do everything from scratch though, the steps are below.

Get `MSYS2 <https://www.msys2.org/>`_ and use the `MinGW64` environment.

The only required pacakge is `mingw-w64-x86_64-toolchain <https://packages.msys2.org/groups/mingw-w64-x86_64-toolchain>`_.
Make sure the ``C:\msys64\mingw64\bin`` directory is in the system's PATH environment variable.

Get the `ez80 LLVM compiler <https://github.com/jacobly0/llvm-project/wiki>`_.
Download the prebuilt `ez80 LLVM compiler <https://github.com/CE-Programming/llvm-project/releases/tag/nightly>`_.
Make sure that ``ez80-clang.exe`` and ``ez80-link.exe`` are reachable by the system's PATH environment variable.

Get the `fasmg assembler <https://flatassembler.net/download.php>`_.
Download the prebuilt `ez80 GNU binutils <https://github.com/CE-Programming/binutils-gdb/releases/tag/nightly>`_
Make sure that ``bin`` directory is reachable by the system's PATH environment variable.

Download the `fasmg assembler <https://flatassembler.net/download.php>`_.
The download is located near the bottom of the page.
Extract the ``fasmg.exe`` executable to the same location as the compiler.

Expand Down
Loading
Loading