diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 80d2a58..54d6942 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -8,49 +8,49 @@ jobs: release_linux: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 - - name: Add CEdev-Linux + - uses: actions/checkout@v4 + - name: Run compile.sh run: | - wget https://github.com/CE-Programming/toolchain/releases/download/v11.2/CEdev-Linux.tar.gz - mkdir /usr/share/CEdev - tar -xvf CEdev-Linux.tar.gz -C /usr/share/ - rm CEdev-Linux.tar.gz - cp -r . /usr/share/CEdev/ - + cd .. + mkdir temp + cd temp + sudo sh ${{ github.workspace }}/compile.sh ${{ github.workspace }} + - name: Zip (Linux) run: | - cd /usr/share - zip -r AgDev_release_${{ github.ref_name }}_linux.zip CEdev -x '*.git*' -x '*.github*' - + cd ${{ github.workspace }}/../temp/AgDev_build/ + zip -r "${{ github.workspace }}/../temp/AgDev_release_${{ github.ref_name }}_linux.zip" . + ls + - name: Upload Linux ZIP to GitHub Release uses: xresloader/upload-to-github-release@v1 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: - file: /usr/share/AgDev_release_${{ github.ref_name }}_linux.zip + file: ${{ github.workspace }}/../temp/AgDev_release_${{ github.ref_name }}_linux.zip tags: true release_windows: - runs-on: ubuntu-latest + runs-on: windows-latest steps: - - uses: actions/checkout@v3 - - name: Add CEdev-Windows + - uses: actions/checkout@v4 + - name: Run compile.bat run: | - wget https://github.com/CE-Programming/toolchain/releases/download/v11.2/CEdev-Windows.zip - mkdir /usr/share/CEdev - unzip CEdev-Windows.zip -d /usr/share/ - rm CEdev-Windows.zip - cp -r . /usr/share/CEdev/ - + cd .. + mkdir temp + cd temp + ${{ github.workspace }}\compile.bat ${{ github.workspace }} + - name: Zip (Windows) run: | - cd /usr/share - zip -r AgDev_release_${{ github.ref_name }}_windows.zip CEdev -x '*.git*' -x '*.github*' + cd ${{ github.workspace }}\..\temp\AgDev_build + powershell -Command "Compress-Archive * AgDev_release_${{ github.ref_name }}_windows.zip" + dir - name: Upload Windows ZIP to GitHub Release uses: xresloader/upload-to-github-release@v1 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: - file: /usr/share/AgDev_release_${{ github.ref_name }}_windows.zip + file: ${{ github.workspace }}\..\temp\AgDev_build\AgDev_release_${{ github.ref_name }}_windows.zip tags: true diff --git a/COMPILE.md b/COMPILE.md index 11b0f4d..f005d4f 100644 --- a/COMPILE.md +++ b/COMPILE.md @@ -1,10 +1,13 @@ # AgDev - compile instructions -A script ```compile.sh``` can be used to compile this source tree. -It is a Linux only compile script. +Broadly speaking, compiling AgDev entails cloning CEdev, then copying AgDev source files on top of that repo, and then building CEdev, with some additional cleanup work performed afterwards. However, there's a lot of ways this can go wrong, so build scripts are provided to make this process easier. These scripts will place the AgDev build inside the `AgDev_build` folder relative to where they're called. They take an optional argument which points to a local copy of the AgDev git repo; if this is not provided it will pull from the main branch on GitHub instead. -You should clone the repo or extract the release, then just run the bash script `compile.sh` -As part of the script it will download https://github.com/CE-Programming/toolchain/releases/latest/download/CEdev-Linux.tar.gz +If you run into issues, try installing the CEdev prerequisite libraries (fasmg, ez80-clang, and MinGW for Windows users) as described in the [CEdev compilation instructions](https://ce-programming.github.io/toolchain/static/contributing.html). -After the code is compiled, move the CEdev directory to wherever you desire and add the CEdev/bin directory to your path. +## Windows +`compile.bat [path\to\agdev\repo]` + +## Linux + +`sudo sh compile.sh [path/to/agdev/repo/]` diff --git a/README.md b/README.md index 84dcc83..20b8a35 100644 --- a/README.md +++ b/README.md @@ -1,995 +1,53 @@ -# AgDev - an Agon Light port of CE C/C++ Toolchain +# AgDev - a port of the CEdev C/C++ Toolchain to the Agon Platform -Based on LLVM toolchain, generating eZ80 ADL code and fasmg eZ80 assembler and linker. +## Overview -### Installation - -Install the CE Toolchain - see [getting started]([Getting Started — CE C/C++ Toolchain documentation](https://ce-programming.github.io/toolchain/static/getting-started.html)) page. The tool-chain can be installed on Windows, Linux or MacOS. Follow the instructions to complete the install, and test that the toolchain works by compiling some of the examples for the TI calculator. - -To adapt the the tool-chain for Agon, for this proof of concept, a number of files should be replaced with the files from the repository ([GitHub - pcawte/AgDev: Port to Agon Light of TI 84 plus CE Toolchain](https://github.com/pcawte/AgDev)). Clone the repository and copy over the top of the CE toolchain. For example, if the CE Toolchain is installed in AgDev and the downloaded repository in GitHub/AgDev copy the files over the top using: - -``` -cp -R -f GitHub/AgDev/ AgDev -``` - -Which should work for MacOS / Linux - not sure the equivalent for windows. - -### Building programs using AgDev toolchain - -This follows the same make approach as the original CE Toolchain, see bottom of the getting [started page]([Getting Started — CE C/C++ Toolchain documentation](https://ce-programming.github.io/toolchain/static/getting-started.html)). The build process had been modified to stop on the generation of the `.bin` file. This is the Agon Light executable. - -I recommend to use: - -``` -make clean -make V=1 -``` - -In the relevant: example, test or any other directory created at the same level. The makefile should be edited to contained the desired name of the .bin executable. - -### Change Log: - -04/06/2023: initial proof of concept completed - -06/06/2023: hosted on github - -09/06/2023: missing compile run-time routines added (these previously called routines in CE ROM) - -12/06/2023: - -- correct operation of malloc verified - comments added to `sbrk.src` as part of this - -- `crt0.src` updated to initialise stack - -- `makefile.mk` - - - updated to include program name in the program header - - - default locations of stack and BSS adjusted - -13/06/2023: - -- missing string and long jump routes added (these previously called routing in the CE ROM) - - - `strcasecmp` removed from the library - this previously called the CE ROM. Use the alternative `strncasecmp`. - -- `puts` modified to output CR / LF pair rather than just LF - -- `getchar` updated to echo character as per standard C - -18/06/2023: - -- stdio library updated to work on Agon - - - This is a simple, non-buffered library - it may have performance issues writing large volumes as in many cases does a system call for each character. - - - `fseek` only implements SEEK_SET (search from beginning of file). Other modes are not implemented, because requires `ftell` functionality (see below). - - - `ftell` is not implemented as functionality is not exposed via MOS - -19/06/2023: - -- C-runtime modified to include a work-around for emulator hanging -- Config parameter in `makefile.mk` corrected. `PREFER_OS_LIBC` changed to `NO` - -20/06/2023: - -- C-runtime workaround reversed as issue now resolved in the emulator. -- Development code for `scanf.c` included prior to tidying up and moving into libc - -23/06/2023: - -- stdio library updated to include: `ftell`, `clearerr`, `remove` and `rewind` - -- `fseek` updated to allow SEEK_SET and SEEK_CUR - note SEEK_END is not supported. If this required, close and reopen the file in append mode. - -- additional error codes added in `errno.h` - -24/06/2023: - -- `fseek` updated to support SEEK_END - -- bug it `gets_s` fixed - was assuming buffer was 1 shorter than it was, so input of 1 character, with buffer size 2 previously did not work. - -- test program updated (`tests/src/fileio.c`) to test functionality of stdio - -25/06/2023: - -- `scanf` and `sscanf` moved into standard library (libc) - -30/06/2023: - -- bug in `strncpy.src` which used a ZDS pseudo op that is not implemented in fasmg assembler. Replaced by individual assembly instructions. This problem may occur in other libraries copied from ZDS. For the moment, just fixed in this one location. - -- C-runtime `crt0.src` updated to added back functionality previously removed as part of the proof of concept - - - Supports the following C-functions: - - - `atexit()`, `on_exit()` - which register functions to be called at the end of the program - - - `exit()`, `_Exit()`, `abort()` - which exits the programme in various ways - - - Supports initialisers, constructors, destructors, finalisers (needs testing) - - - Added extensive commenting - -- Included a simple example of a user defined type (complex) which overloads a number of operators. - -- Changed default location of BSS & heap to 0x080000 to 0x09ffff - -02/07/2023: - -- mos_api updated: - - - `unit32_t getsysvar_time()` function added - - - typedef `RTC_DATA` created for the format of data returned from `getsysvar_rtc()` - - - `getsysvar_rtc()` updated to `volatile RTC_DATA *getsysvar_rtc()` to reflect that the returned pointer refers to a value that is dynamically changed by MOS - and shouldn't there be optimised. Changed to return type `RTC_DATA *` - - - Added example under `tests/mos_time` - -- `clock_t clock()` function implemented using the Agon timer. Other RTC related functions are in the process of being ported. - -03/07/2023: - -- Corrected` lib/crt/fpftol.src` to remove ZDS pseudo op not supported by fasmg and removed other ZDS assembler features that are different in fasmg - -- Corrected `lib/crt/fpultof.src` to remove ZDS assembler directives that are different in fasmg - -- Ported time functions: `difftime()`, `mktime()`, `time()`, `localtime()`, `gmtime()`, `asctime()`, `ctime()` - -- Updated comments in `mos_api.h` to note that `getsysvar_rtc()` data is only updated when `mos_getrtc()` is called. This is taken account of in `time()`. - -04/07/2023: - -- Dhrystone benchmark added under full `ansibench/dhrystone`. - -09/07/2023: - -- Support for output re-direction added for stdout. Cannot currently be done from the command line (todo), but can be done programmatically using `freopen()`. - - - `freopen()` added - - - `puts()` and `printf()` updated to call `putchar()` instead of directly calling `outchar()` - - - `putchar()` modified to either call `outchar()` of `fputc()` depending on whether output redirected - - - `fputc()` modified to call `outchar()` when outputting to `stdout` or `stderr` to avoid any danger of function call loops - - - `fclose()` modified to allow stdout to be closed if it has been redirected - - - `stdio.h` and `files.c` modified to support input / output redirection - - - `linker.script` updated to include `freopen()` - - - Test / demonstration program added under `test/stdout-redirect` - -10/07/2023: - -- Support for input re-direction added for stdin. Cannot currently be done from the command line (todo), but can be done programmatically using `freopen()`. - - - `getchar()`- calls `inchar()`to get the character and `outchar()`to echo the character (even if the output has been redirected). If output has not been re-directed calls `fgetc()`and does not echo the character. - - - `gets_s`- calls `getchar()`if input has not been redirected (line are terminated with CR). Calls `fgets()` of input has been redirected (lines are terminated with CR/LF pair). - - - `fgetc` - calls `mos_fgetc()` unless called on `stdin` when calls `inchar()` and echos with `outchar()` - avoids calling `getchar()` so that no risk of function call loops - - - Test / demonstration program added under `test/stdin-redirect` - -- Bug fixed previously if a program was run again from the command line without re-loading it, stdin, stdout and stderr were not reset. - - - Added re-run handling in `crt0.src` (currently very simplistic as only initialises stdio) - - - `_stdio_init()` function added to files.c. This is only called from `crt0.src` and is not declared in any header file. - -- Added fasmg quick reference guide (from [Assembling eZ80 code with flat assembler g - Cemetech | Forum | Your Projects [Topic]](https://www.cemetech.net/forum/viewtopic.php?t=13913&start=0)) - but formatted to make readable / intelligible. - -12/07/2023: - -- `puts()` modified to print "(NULL)" if called with a null pointer. Code shortened. Defines 2 static strings which can be used elsewhere. Note there is still an issue with `printf()`. - - - `__null_literal_str` as "(NULL)" - - - `__end_of_line_str` as CR/LF pair - -13/07/2023: - -- `fopen()` modified to correct apparent bug in MOS. Now seeks to end of file when file opened for append ("a"). Previously wrote from the beginning. Now writes from the end. - -- `gets_s()` corrected to also output LF after CR pressed by the user. - -- `puts()` corrected was outputting LF/CR not CR/LF - -- `gets_s()` corrected to strip CR/LF pair if used with input redirected - -14/07/2023: - -- support for input / output redirection added on the MOS command line, e.g. `RUN &040000 out.txt`. Enabled by including `LDHAS_ARG_PROCESSING = 1` in the makefile. -- This also supports quoting of command line arguments with double quotes. -- `tests/args` updated to demonstrate the effect of quoting -- `tests/quote` added to demonstrate input / output redirection from the MOS command line - -16/07/2023: - -- `linker_script` corrected to include` strncmp`, which was missing. - -17/07/2023: - -- And support for text and binary file modes - text mode has LF translation for input and output. Binary does not translate. At same time at support for unget of one character. - - - Definition of `FILE` changed in `stdio.h` and `file.c` to store mode and unget character in FILE struct. Note, need to recompile the whole of stdio library because of change in definition of FILE. - -- Translate LF (`'\n'`) to CR/LF when writing to console and file. For files this is done by default, but not if the file is opened in binary mode. - - - `putchar.src` modified to do translation when stdio is not redirected - - - `puts.src` modified to no longer send CR/LF at end of line - now just sends LF and allows `putchar` to do the translation. - - - `fputc.c` modified to translate LF to CR/LF if FILE was opened in text mode - - - `fputs.c` modified to no longer send CR/LF at end of line - now just sends LF and allows `fputc` to do the translation. - - - `getchar.src` modified to do translation of CR to LF and support `ungetc()`. Note that console keyboard only generates CR and not CR/LF pair. - - - `gets_s.c` modified - as translation is now done by `getchar()`, only needs to look for LF. - - - `fgetc.c` modified to do translation of CR/LF pair to LF and support `ungetc()` - - - `fgets.c` modified - as translation is now done by `fgetc()`, only needs to look for LF. - -- `fprintf()` and `vfprintf()` functions added in `nanoprintf.c` - - - CE toolchain option to use built in system printf function removed. Aliasing of names in `printf.src` no longer used. Naming simplified in `nanoprintf.c`. Linker option `HAS_PRINTF` no longer does anything. Entry for `printf.src` removed from `linker_script` - -- `ungetc()` function added - can only unget one character - - - `fseek()`, `fflush()` all modified to clear the character pushed back on the stream. - -- `fseek()` modified to allow seeking on redirected `stdin`, `stdout` or `stderr`. - -- `ftell()` modified to allow calling on redirected `stdin`, `stdout` or `stderr`. - -- `maptab.c` updated to include all white space characters. Is used by isspace() function. Previously it only had the actual space character listed as white space, causing problems for `scanf()`. - - - `isspace.src` comments added - -18/07/2023 - -- `setjmp.src` and `longjmp.src` corrected to fix bugs in conversion from ZDS to fasmg assembler - moved public statements inside section and replace ZDS pseudo ops. - -- `strstr.src` corrected to replace ZDS pseudo op - -- `memcmp.src` added to `linker_script` - was previously missing - -22/07/2023 - -- `crt0.src` and `sbrk.src` updated to fix reset start of heap if program is rerun. Previously if a program was rerun the start of heap used by malloc was not reset - potentially leading to not enough memory for malloc. - -- `crt0.src` updated to optimise the initialisation of BSS - -- `README.md` updated to included documentation on VDP and VDU commands - -- `mos_api.h` updated to include a structure for manipulating SYSVAR - -- `tests/malloc` updated to demonstrate correct functioning of `malloc()` - -- `tests/vdu` added to demonstrate use of VDU commands - part of developing VDP/VDU wrapper library - -23/07/2023 - -- Started process of converting VDP/VDU demo to a library with creation of `vdp_vdu.c` and `vdp_vdu.h` - although still in `tests/vdu` directory. - - - Added `tests/big-bitmap` to demonstrate the load of large bit maps from a file - this works on the emulator, but not on actual Agon Light HW, where there does not seem to be enough available memory in VDP (not sure of the reason for this). - -24/07/2023 - -- `crt0.src` problem fixed with return value from `exit()` or `_Exit()` not being properly returned to MOS - -25/07/2023 - -- Exit handler added to print error / exit message at end of program. This is required if program returns non-zero, as MOS interprets this as one of various file errors. - - - Added in `crt0.src` - - - If not required (to slightly shorted the code) can be disabled setting `LDHAS_EXIT_HANDLER:=0` in `makefile` - - - `makefile.mk` has been updated to include the exit handler by default - - - `stdlib.h `updated to include 3 exit codes - - - EXIT_SUCCESS - - - EXIT_FAILURE - - - EXIT_ABORT - - - Added test/exit to test/demonstrate the functionality - -26/07/2023 - -- `scanf` library updated - - - Handling of backspace, cursor left and control-C during input - - - Added `fscanf()` - - - Updated `tests/scanf` to include test of `fscanf()` - -- `gets_s()` updated to handle backspace, cursor left and control-C during input - -01/08/2023 - -- `Agon-HW.md` file started to collect documentation on Agon hardware - - - Section on UART0 / VDP interrupt with a focus on understanding keyboard input - -- `lib/agon/intagon.src` created - intercepts Agon UART0 interrupt to maintain an array of bits for key presses (one bit per key). This allows multiple key presses to be detected at the same time - -- `vdp_vdu` library created for using VDP graphics via the VDU commands - - - `vdp_bell()` - - - `vdp_cursor_left()` - - - `vdp_cursor_right()` - - - `vdp_cursor_down()` - - - `vdp_cursor_up()` - - - `vdp_clear_screen()` - - - `vdp_clear_graphics()` - - - `vdp_cursor_home()` - - - `vdp_cursor_tab()` - - - vdp_set_`text_colour()` - - - `vdp_mode()` - - - `vdp_graphics_origin()` - - - `vdp_get_scr_dims()` - - - `vdp_logical_scr_dims()` - - - `vdp_cursor_enable()` - - - `vdp_move_to()` - - - `vdp_line_to()` - - - `vdp_point()` - - - `vdp_triangle()` - - - `vdp_circle_radius()` - - - `vdp_circle()` - - - `vdp_select_bitmap()` - - - `vdp_draw_bitmap()` - - - `vdp_load_bitmap()` - - - `vdp_load_bitmap_file()` - - - `vdp_load_sprite_bitmaps()` - - - `vdp_create_sprite()` - - - `vdp_select_sprite()` - - - `vdp_move_sprite_to()` - - - `vdp_move_sprite_by()` - - - `vdp_show_sprite()` - - - `vdp_hide_sprite()` - - - `vdp_next_sprite_frame()` - - - `vdp_prev_sprite_frame()` - - - `vdp_nth_sprite_frame()` - - - `vdp_activate_sprites()` - - - `vdp_refresh_sprites()` - - - `vdp_reset_sprites()` - -- `vdp_key` library created for accessing VDP keyboard data to maintain a bit map of key presses (can be simultaneous) - - - `vdp_key_init():` initialise the VDP keyboard routines, which hook into the UART0 interrupt handler and maintains an array `vdp_key_bits[32]` of up/down status per key. - - - `vdp_key_reset_interrupt()`: resets the original interrupt vector. This does not normally need to be explicitly as it is registered to be call at the end of the program via `atexit()`. It can however be safely called. - - - `vdp_set_key_event_handler()`: sets a handler function to be called when a key is pressed. It is passed a KEY_EVENT - - - `vdp_update_key_state()`: this should be called frequently in the main game loop, otherwise events might be missed - there is in any case a small chance of this (could consider integrating into the interrupt routine). It is the routine that tiggers the event handler. - - - `vdp_check_key_press()`: checks for a key press by examining `vdp_key_bits[]`. - -- `linker_script`: updated to include the above 3 items and remove some CE items left over from the original version. - -- `tests/sprite` added to demonstrate sprites and keyboard handling - -02/08/2023 - -- Added sprite related functions - - - `vdp_clear_sprite()` - - - `vdp_add_sprite_bitmap()` - -- Header files updated to include `extern "C"` for correct linking from C++ - - - `vdp_key.h` - - - `vdp_vdu.h` - -- Corrected typo in `crt0.src`in conditional compilation of clearing BSS - -03/08/2023 - -- Added `vdp_solid_bitmap()` function - -10/08/2023 - -- TI-84 CE specific library items (under `lib/ce`) disabled in `linker_script`. Other items shifted to `lib/agon`. Note some items might rely on HW timing so not give accurate results. - - - atomic functions: should work, but not checked - - - delay, sleep functions: rely on CPU clock cycle timing. Will run, but results will be off due to different clock speed - - - random functions: okay - - - zx0 & zx7 compression: okay - -16/08/2023 - -- Corrected typo in this file - -17/08/2023 - -- `vdp_key.h` and `vdp_vdu.h` moved to `agon` subdirectory in `include` folder - -- Sprite C++ library header files stored in `Sprite` subdirectory in `include` folder - -- `sprite-demos` folder added with `invaders` demo - -### To-Do / Known Issues: - -- Testing / validation - -- Check for ZDS pseudo ops in any assembly language source files copied from ZDS - -- Review and improved efficiency / size of crt0.src and resulting binary - including the use of compile time options - -- For stdio remove stuff inherited from CE Toolchain (there is nothing used, but some remnants in the various files) - -- Change printf %s with NULL pointers to do something sensible - -- Close files that have not been closed on `exit()` as MOS does not close them and runs out of file handles - plus this is part of the C standard - -### To-Do - New Features - -- Complete vdp_vdu library - for example, need to add routines for colours and palette - -- Add command line support for redirection of stderr - -- Add simulation of pipes - -- Port / replace / expand library where necessary to the Agon Light. Including: - - - investigate benefits of buffering for stdio. - - VDP/VDU library - -- Create own repository that is not dependent on CE Toolchain - - - Clean out the CE specific stuff - -- Test / proof of concept for other LLVM front-ends. See, for example, [GitHub - maddymakesgames/Rust-CE: A proof-of-concept of rust on the ti-84+ce](https://github.com/maddymakesgames/Rust-CE), which is a proof of concept for running Rust on the TI-84-CE calculator. - -The rest of this file documents the process of porting the CE Toolchain to the Agon Light. This includes the process of discovery with respect to how the CE Toolchain works and the Agon Light, and the steps / decisions made in the porting process. This intended as reminder for myself and a guide to others who follow in my steps. - -## Introduction - -The Agon Light is based on the Zilog eZ80 processor. The eZ80 has a 24 bit address space supporting 16 megabytes of memory, compared to the 64 kilobytes of the original Z80. The eZ80 has two modes of operation, the standard Z80 mode, which has 16-bit registers making it easy to address 64k of memory, but requiring the use of "banking" to access more than 64k of memory. The other, ADL (address data long), mode of operation extends the registers to 24 bits, making the whole address space readily accessible. - -From the point of view of assembly language programming both Z80 and ADL mode are very similar, making it easy to convert programmes from Z80 to ADL mode. - -When we consider high-level programming languages, there are a number available for the Z80, but they are limited to 64k of memory or have awkward bank switching methods to access greater memory. Consequently it is very interesting to have a available high-level languages that make use of the ADL mode to allow use of the full 16M address space. - -Considering the C-programming languages, there are a number of Z80 C-compilers available. To date, the Agon community has focussed on two: - -- Zilog ZDS II development environment which can produce eZ80 ADL code. This was the original set of tools used by the developers of Agon, but it is closed source, runs on Windows only, and only supports the data C89 standard - -- SDCC (small devices C-compiler) this is a popular choice for 8-bit computers, and adapting this for Agon has been a focus of a number of people in the Agon computer. This is a good compile for Z80, but it only support Z80 and not ADL mode. - -As an alternative, open-source compiler that can produce ADL code there is the [CE C/C++ toolchain]([Welcome to the CE C/C++ Toolchain! — CE C/C++ Toolchain documentation](https://ce-programming.github.io/toolchain/index.html)). This has been developed for the TI 84 Plus CE calculator that is based on the eZ80 processor and has a quite a reasonably sized community. There is a well developed toolchain, which is based on eZ80 versions of LLVM compile and fasmg assembler. It produces ADL code with 24 bit pointers, 24 bit integers, 32 bit long, 16 bit short, 32 bit float. There is also quite an extensive library for C and C++ programs. - -Although this toolchain is focused heavily optimised for the TI calculator, work has become to adept it to support the Agon Light. At the moment a proof of concept has been achieved to demonstrate the feasibility of this by being able to compile and run a "Hello, world!" example, extend also to print the command line. This is an excellent first step. Further work is required to adapt the CE toolchain's extensive library to the Agon Light. The toolchain also supports C++, this has not been tested on the Agon. - -## Installation - -Install the CE Toolchain - see [getting started]([Getting Started — CE C/C++ Toolchain documentation](https://ce-programming.github.io/toolchain/static/getting-started.html)) page. The tool-chain can be installed on Windows, Linux or MacOS. Follow the instructions to complete the install, and test that the toolchain works by compiling some of the examples for the TI calculator. - -To adapt the the tool-chain for Agon, for this proof of concept, a number of files should be replaced with the files from the repository ([GitHub - pcawte/AgDev: Port to Agon Light of TI 84 plus CE Toolchain](https://github.com/pcawte/AgDev)). Clone the repository and copy over the top of the CE toolchain. For example, if the CE Toolchain is installed in AgDev and the downloaded repository in GitHub/AgDev copy the files over the top using: - -``` -cp -R -f GitHub/AgDev/ AgDev` -``` - -Which should work for MacOS / Linux - not sure the equivalent for windows. - -## Build process for proof of concept - -In the `AgExamples/hello_world` issue the `make` command (use V=1 not necessary but provides much more details on the commands used): - -``` -make V=1 -``` - -The `make clean`command can be used to delete the results of previous compilations and thereby force a recompilation. - -There are other examples in the test directory which can be built in the same way. - -The build process goes through the following steps: - -1. Compilation of .c source files to LLVM bitcode (.bc) using `ez80-clang` - -2. Linking of LLVM bitcode using `ez80-link`. This includes link time optimisation - -3. Generation of eZ80 assembly code (.src) for the source programmes using `ez80-clang` - -4. Assembling and linking of the of the generated assembly code (from step 3) with the libraries and compiler run-time using `fasmg` - this includes building the executable targeted at a specific memory location. This is the main part of the build process that needs to be adjusted. - -### Program Execution - -The compiler if successful produces the final "DEMO.bin". This should be transferred to the Agon for testing. - -On the Agon: - -``` -*load DEMO.bin -*run &040000 Hello AgDev -``` - -Should produce the following output: - -``` -Hello World! -Arguments: 3 -- argc: 3 -- argv[0]: HELLO.BIN -- argv[1]: Hello -- argv[2]: AgDev -``` - -### Step 1 compilation: - -``` -make V=1 - -ez80-clang -MD -c -emit-llvm -nostdinc - -isystem /AgDev/include -Isrc -fno-threadsafe-statics - -Xclang -fforce-mangle-main-argc-argv - -mllvm -profile-guided-section-prefix=false - -DNDEBUG -g0 -Wall -Wextra -Oz - 'src/main.c' -o 'obj/src/main.c.bc' -``` - -Compiles: - -- src/main.c - -Generates output: - -- obj/src/main.c.bc - -- obj/src/main.c.d - -The .bc files is an intermediate file in LLVM bitcode - -The .d file is a dependencies list for main.c.bc, for the source main.c and various include (.h) files - -### Step 2 linking of LLVM (and link time optimisation) +The [Agon Light](https://agonconsole8.github.io/agon-docs/) and other Agon Platform revisions are based on the Zilog eZ80 processor. The eZ80 has a 24 bit address space supporting 16 megabytes of memory, compared to the 64 kilobytes of the original Z80. The eZ80 has two modes of operation: the standard Z80 mode, which has 16-bit registers making it easy to address 64k of memory, but requiring the use of "banking" to access more than 64k of memory; and ADL (address data long) mode of operation, which extends the registers to 24 bits, making the whole address space readily accessible. -``` -ez80-link - '/AgDev/AgExamples/hello_world/obj/src/main.c.bc' - -o '/AgDev/AgExamples/hello_world/obj/lto.bc' -``` - -Links and optimises: - -- obj/src/main.c.bc - -Generates output: - -- obj/lto.bc - -### Step 3 eZ80 assembly language generation - -``` -ez80-clang -S - -mllvm -profile-guided-section-prefix=false - -Wall -Wextra -Oz - '/AgDev/AgExamples/hello_world/obj/lto.bc' - -o '/AgDev/AgExamples/hello_world/obj/lto.src' -``` - -Generates assembly language for - -- obj/lto.bc - -Outputs eZ80 assembly language to - -- obj/lto.src - -### Step 4 assembly and linking - -``` -fasmg -n '/AgDev/meta/ld.alm' - -i 'DEBUG := 0' - -i 'HAS_PRINTF := 1' - -i 'HAS_LIBC := 1' - -i 'HAS_LIBCXX := 1' - -i 'PREFER_OS_CRT := 0' - -i 'PREFER_OS_LIBC := 1' - -i 'include "/AgDev/meta/linker_script"' - -i 'range .bss $080000 : $09ffff' - -i 'locate .header at $040000' - -i map - -i 'source "obj/icon.src", - "/AgDev/lib/crt/crt0.src", -             "obj/lto.src"' - -i 'library "/AgDev/lib/libload/fatdrvce.lib", -             "/AgDev/lib/libload/fileioc.lib", -               "/AgDev/lib/libload/fontlibc.lib", -               "/AgDev/lib/libload/graphx.lib", -               "/AgDev/lib/libload/keypadc.lib", -               "/AgDev/lib/libload/msddrvce.lib", -               "/AgDev/lib/libload/srldrvce.lib", -               "/AgDev/lib/libload/usbdrvce.lib"' - bin/DEMO.bin -``` - -Source files: - -- lib/crt/crt0.src: C runtime (this has been customised for Agon) - -- obj/lto.src: previously generated eZ80 assembly language for all the source files - -Files generated - -- DEMO.bin - -- DEMO.map - -The .bin files has no location information in it, but is not position independent (e.g. has absolute jumps in it, etc.). It has an assumed location and needs to be loaded by the OS to the correct location. - -The .map files contains information on the locations of code / data sections and the global labels. The entry point to the program is at `__start` which is at the beginning of the `.init` section. - -### Summary of directories / files: - -- `bin` - -- `examples` - -- `include` - -- `lib` - - - `ce` - - - `crt`, which includes - - - `crt0.src`: the C-compiler runtime / startup & exit routines - - - many other runtime functions for basic arithmetic on the basic types, etc. From a quick inspection most of these should not need to be modified. There are likely a few that need to be changed, for example: - - - `os.src`: which seems to include addresses of functions in the CE ROM which would need to be replaced or copied somehow - - - `libc` - - - `libcxx` - - - `libload` - -- `meta` - - - `commands.alm`: defines some macros for the fasmg eZ80 assembly process. Don't need to change anything here - - - `ez80.alm`: configuration for fasmg to assemble eZ80 code. Don't need to change anything here - - - `ld.alm`: main configuration file for the fasmg assembler. Nothing needs to be changed here. Includes `commands.alm` and then `ez80.alm` - - - `linker_script`: included by fasmg as part of the assemblers linking process. Probably changes will need to be made here although it is possible that it is generic enough and just need to update the underlying libraries to the Agon target. - - - `makefile.mk`: this is included as part of the make process. It is the main place where configuration of the make compilation, assembly and linking is configured. It is included by the individual project makefile using `include $(shell cedev-config --makefile)` This has been edited to remove generation of icon and 8xp output files. - -## Customisation to change target to Agon - -Things to be changed: - -- makefile.mk: main makefile includes information of the location in memory of the program and data structures, libraries, etc. - -- crt0.src: C-compiler runtime / startup & exit routings - -- Various libraries - this needs to be investigated further, starting with something simple and then adding complexity - -### Main makefile - makefile.mk - -Modified to: - -- Don't include an icon - this was a specific TI calculator thing - -- Don't generate an 8xp file from the binary. This is a specific TI 84 format for transferring to the calculator - -Updated with Agon specific addresses / memory locations: - -- INIT_LOC = 040000: executable location - should change to 0B0000 for MOS binary executable that can be run from the command line (not sure what else needs to be changed) - -- BSSHEAP_LOW = 080000: this seems to work for a small programme - but not sure what should really be used - -- BSSHEAP_HIGH = 09FFFF: as above - -- STACK_HIGH = 0AFFFF: this seems to work - but not sure what should really be used - or even if this really needs to be set. For the moment this has been removed from the fasmg flags and whatever stack that is provided by MOS is used. - -See details below for memory layout. - -### C runtime - crt0.src - -This has been re-written based on a combination of code from the reverse engineered CE Toolchain version and some of the original [Agon projects]([GitHub - breakintoprogram/agon-projects: Official AGON QUARK Firmware: Projects](https://github.com/breakintoprogram/agon-projects)) which used the Zilog toolchain, some of the optimisations used in the CE Toolchain have been removed for clarity. Note that the Zilog assembler, fasmg assembler used by CE toolkit and ez80asm used by many in the Agon community all have different formats and different waves of organising program sections, etc. Part of the challenge of this proof of concept has been in understanding the fasmg assembler. - -### Memory layout - -From the MOS documentation, the memory layout for the Agon is as follows: - -- &000000 - &01FFFF: MOS (Flash ROM) -- &040000 - &0BDFFF: User RAM -- &0B0000 - &0B7FFF: Storage for loading MOS star command executables off SD card -- &0BC000 - 0BFFFFF: Global heap and stack - -Consequently we assume that the memory from 040000h to 0AFFFFh is useable for programs compiled with the AgDev toolchain (this can be adjusted) - -The layout of sections of the program is in the following order with each section immediately following the proceeding one: +When we consider high-level programming languages, there are a number available for the Z80, but they are limited to 64k of memory or have awkward bank switching methods to access greater memory. -- `section .header`: 040000h +Considering the C-programming languages, there are a number of Z80 C-compilers available. To date, the Agon community has focused on two: -- `section .init`: 040045h (this can be referenced by the label `__start`) +- **Zilog ZDS II development environment** which can produce eZ80 ADL code. This was the original set of tools used by the developers of Agon, but it is closed source, runs on Windows only, and only supports the data C89 standard -- `section .text`: this is where the main program code is located. The code is entered by calling `_main` or `___main_argc_argv` depending on whether `main(void)` or `main(int argc, char *argv[])` is used. Note that is almost certainly not at the beginning of of .text section. +- **SDCC (small devices C-compiler)**, a popular choice for 8-bit computers, and adapting this for Agon has been a focus of a number of people in the Agon computer. This is a good compiler for Z80, but it only supports Z80 and not ADL mode. -- `section .data`: contains static and global variables defined in the program code. +As an alternative, the [CEdev C/C++ toolchain](https://ce-programming.github.io/toolchain/index.html) is an open-source compiler that can produce ADL code. It targets the TI-84 Plus CE calculator (based on the eZ80 processor) and has a reasonably sized community. CEdev is based on eZ80 versions of the LLVM compiler and fasmg assembler. It produces ADL code with 24 bit pointers, 24 bit integers, 32 bit longs, 16 bit shorts, and 32 bit floats. There is also quite an extensive library for C and C++ programs (though it is not ISO compliant... yet). -- `section .rodata`: contains constant data, such as string literals in the program code. +AgDev is the result of an effort to modify CEdev to accommodate the feature set and hardware design of the Agon Platform. The result is a more powerful, and C++ capable, toolchain, compared to other options for the Agon. -There is then a gap before: - -- `section .bss`: contains uninitialised global and static variables. This is zeroed as part of the as part of the C-runtime setup (by crt0). - -- `heap`: this is used by malloc to programmatically allocate memory. This grows upwards towards the stack. - -- `stack`: used for storing return addresses, parameters for function calls and local variables. This grows downwards towards the heap. - -The layout in memory can be checked by examining the `.map` file generated as part of the final linking process. - -The location of .bss, heap and stack are configured in the `makefile.mk` which controls the build process: - -``` -BSSHEAP_LOW ?= 080000 -BSSHEAP_HIGH ?= 09FFFF -STACK_HIGH ?= 0AFFFF -``` - -The layout can be checked by examining the following labels in the `.map` file. - -``` -___low_bss = 080000 -___len_bss = 000000 -___heaptop = 09FFFF -___heapbot = 080000 -__stack = 0AFFFF -``` - -Memory in heap is managed by the `malloc` function . The malloc used is from Zilog, the comments state: - -``` -/* This implements a straight forward version of malloc, allocating */ -/* memory between the first unused address in RAM (__heapbot) and */ -/* the current stack pointer; the stack pointer being initialized to */ -/* the top of RAM (__heaptop). */ -``` - -Note however, in this AgDev Toolchain, `___heaptop` is set up independently of the stack, so that the heap should not overwrite the stack (unless insufficient space has been reserved for the stack). - -## Compiler runtime (compiler-rt) - -These are short assembly language subroutines that are output as part of the LLVM compiler eZ80 code generation (see discussion here https://github.com/jacobly0/llvm-project/pull/10). There are a number of these not included in the CE Toolkit, instead it calls routines in the CE ROM. The list of compile runtimes is contained in the file: `llvm/lib/Target/Z80/Z80ISelLowering.cpp`which is part of the eZ80 LLVM distribution. This list the calling convention to use. There is no detailed documentation on function of each, but in most cases it can be guessed from the naming. These are thought to derive from the original Zilog compiler distribution. There is documentation for each function at the start of the Zilog files - but it is not clear whether any functionality has been changed. Given that the routines in the CE ROM were most likely compiled using the Zilog compiler, one could reasonably assume that the routines still used in the ROM are the same as the original Zilog routines. - -The compiler-rt routines that are include are in the C runtime directory `lib/crt` of the CE Toolchain. The call address of the routines were the ROM is used is listed in `lib/crt/os.src`, see condensed version below: - -``` -__fadd := 000270h -__fcmp := 000274h -__fdiv := 000278h -__fmul := 000288h -__fsub := 000290h -__ftol := 00027Ch -__ftoul := __ftol -__dtol := __ftol -__dtoul := __ftoul -__imul_b := 000150h -__indcall := 00015Ch -__ishl_b := 000178h -__ishrs_b := 000180h -__ishru_b := 000188h -__itol := 000194h -__ltof := 000284h -__ltod := __ltof -__setflag := 000218h -__sshl_b := 000244h -__sshrs_b := 00024Ch -__sshru_b := 000254h -__stoi := 000260h -__stoiu := 000264h -__ultof := 000280h -__ultod := __ultof -``` - -## Libraries - -Contains mainly eZ80 ADL assembly (.src) files. - -Items mentioned have been checked - see details. Others have not been checked. - -- Public functions are part of the externally available library - -- Weak functions are internal to the library - -### CE (TI 84 plus CE specific stuff) - -### CRT (C-runtime) - -- crt0 (public): updated to target Agon - sufficient for the proof of concept, will need to be developed further to support the full library and C++ (constructors, destructors, etc. - this was in the original crt0 - needs to be added back in and tested) - -- inchar.src (weak): updated to input from MOS rst 008h GETKEY command - -### Libc (standard C-library) - -- outchar.src (weak): updated to output to VDP by MOS rst 010h - -- putchar.src (public): okay. Calls outchar (which needs to be modified) - -- getchar.src (public): updated to remove bug now typecasts from unsigned char to int (the CE version typecasts from signed char - which is contrary to the C-standard) . Call inchar to get character and outchar to echo on console - -In general the libc library has been derived from a number of sources: - -- Floating point comes from Zilog ZDS. Note that the some additional functions have been added such as hyperbolic trig functions, cubic root, etc. These use calculations from other floating point functions. - -- Sort and search from Zilog ZDS, including bsearch and qsort - -- Standard IO: uses nanoprintf - - - scanf and sscanf have been added based on the Zilog ZDS code - -- File IO: re-written / adapted from CE-Toolchain - -- Time +### Installation -- Memory management from Zilog ZDS. Includes free, malloc, realloc +Download a [release build](https://github.com/pcawte/agdev/releases/latest) or [build from source yourself](COMPILE.md). Place the build in a directory of your choosing. -- Exception handling +Afterward, make sure the `/bin` folder can be found in `PATH`; if you're on Windows, follow [this guide](https://www.architectryan.com/2018/03/17/add-to-the-path-on-windows-10/), or you can run cedev.bat and execute commands from there instead. On Linux, run `export PATH=//bin:$PATH` in a terminal window. -- String conversion from Zilog ZDS. Includes: strtof, strtol, strtoll, strtoul, strtoull +### Building programs -#### String Library (and longjmp / setjmp) +This follows the same approach as the original CE Toolchain (see bottom of the [CEdev getting started page](https://ce-programming.github.io/toolchain/static/getting-started.html#building-programs)). The build process had been modified to stop on the generation of the `.bin` file. This is the Agon Light executable. -In the CE Toolchain, many of the string library routines that are part of libc are called in the CE ROM, as listed in the `lib/libc/os.src` file. Condensed version below: +I recommend to use: +```shell +make clean +make V=1 ``` -_longjmp := 000098h -_memchr := 00009Ch -_memcmp := 0000A0h -_memcpy := 0000A4h -_memmove := 0000A8h -_setjmp := 0000B8h -_strcat := 0000C0h -_strchr := 0000C4h -_strcmp := 0000C8h -_strcpy := 0000CCh -_strcspn := 0000D0h -_strlen := 0000D4h -_strncat := 0000D8h -_strncmp := 0000DCh -_strcasecmp := 021E3Ch -_strncpy := 0000E0h -_strpbrk := 0000E4h -_strspn := 0000ECh -_strstr := 0000F0h -_strtok := 0000F4h -``` - -These are all available in the Zilog distribution as assembly source code, apart from: - -- `strcasecmp`: this is not part of standard libc - and has been deleted. There is, however, `strncasecmp`. - -- `strtok`: available as c source code - -All of these with the exception of `strcasecmp` have been added to the AgDev toolchain as part of libc .src files. - -#### File IO - -In the CE Toolchain the file IO functions are wrappers around the fileioc library. This library is CE specific and needs to be replaced. There is already provision in the CE library for doing this, see the CE Toolchain documentation: [Using File I/O Functions ](https://ce-programming.github.io/toolchain/static/fileio.html). Note that the `stdio.h` file has been modified so that there is no need for a `CUSTOM_FILE_FILE` as referred to in the CE documentation. - -The library has been modified to use Agon MOS calls and includes: - -- `fopen`, `fclose` - -- `fputc`, `fputs` - -- `fgetc`, `fgets` - -- `feof`, `ferror`, `fflush` - -- `fread`, `frwite` - -- `fseek`, `rewind`, `ftell` - -- `clearerr` - -- `remove` - -And includes files -- `files.c` +The `make clean` command can be used to delete the results of previous compilations and thereby force a recompilation. -- `stdio.h` - -On the Agon there are two different APIs for accessing the FatFS - MOS routines and FatFS routines. Having examined the MOS source code, the MOS routines are simple wrappers around the FatFS routines, just managing / storing the FatFS file descriptors in a table (supports 8 open files). Consequently it makes sense just to use the MOS routines. - -##### Text and Binary Files - -The stdio library has been modified to differentiate between text and binary files. - -- When files are opened, they are assumed to be texted, unless binary is specified in the mode flags (see `fopen()` documentation). - -- stdin, stdout and stderr are assumed to be text - if reopened via `freopen()`, it is possible to change to binary. - -For text files, a translation is done between standard C, where '\n' (LF) is the end of a line and the operating system, which requires CR/LF pair at the end of a line. This applies to the following functions: - -- `putchar()`, `puts()` - -- `fputc()`, `fputs()` - -- `printf()`, `fprintf()` - but not `sprintf()` - -Note that the following functions do not differentiate between text and binary files: - -- `fread()`, `frwite()` - -- `fseek()`, `ftell()` +The build process goes through the following steps: -### Libcxx (standard C++ library) +1. Compilation of .c source files to LLVM bitcode (.bc) using `ez80-clang` -This is very limited, mainly just C++ wrapper around C libraries +2. Linking of LLVM bitcode using `ez80-link`. This includes link time optimization -### Libload (dynamic library - I think) +3. Generation of eZ80 assembly code (.src) for the source programs using `ez80-clang` -Contains .lib library files - needs to be investigated further +4. Assembling and linking of the of the generated assembly code (from step 3) with the libraries and compiler run-time using `fasmg` - this includes building the executable targeted at a specific memory location. This is the main part of the build process that needs to be adjusted. -## C Calling Conventions +## C Calling Conventions (for interfacing with ASM applications) -See Zilog application note "an0333 - Calling C from asm.pdf" +See Zilog application note ["Calling C from asm.pdf"](https://www.zilog.com/docs/appnotes/an0333.pdf). Only IX register and stack need to be preserved by called functions. @@ -1025,63 +83,10 @@ This table lists which registers are used for return values from a function. The | double | E:UHL | | pointer | UHL | -## MOS Calling Conventions - -From the MOS documentation: - -1. Commands can be abbreviated with a dot, so `DELETE myfile` and `DEL. myfile` are equivalent. -2. Commands are case-insensitive and parameters are space delimited. -3. In the syntax description, optional parameters are written as `` -4. The dot (.) character can be used as a substitution for an optional numeric parameter -5. Default LOAD and RUN address is set to 0x040000 -6. Numbers are in decimal and can be prefixed by '&' for hexadecimal. -7. Addresses are 24-bit, unless otherwise specified - - `&000000 - &01FFFF`: MOS (Flash ROM) - - `&040000 - &0BDFFF`: User RAM - - `&0B0000 - &0B7FFF`: Storage for loading MOS star command executables off SD card - - `&0BC000 - 0BFFFFF`: Global heap and stack -8. The RUN command checks a header embedded from byte 64 of the executable and can run either Z80 or ADL mode executables -9. MOS will also search the `mos` folder on the SD card for any executables, and will run those like built-in MOS commands - -Programs are called from MOS using the the `_exec24()` function built into MOS : - -- This function will call the 24 bit address and keep the eZ80 in ADL mode. - -- The called function must do a RET and take care of preserving registers - -- On entry, HL contains the address of the command line parameter string - used for argc / argv processing. There is 256 bytes for storage of the command line including the terminating '`\0'`. - -- Save AF, BC, DE, IX and IY registers - -- Return with HL=0 - -On exit from a program, MOS interprets the value in HL as a "file error", with the following being defined (0=OK, 1=Error accessing SC card, etc): - - "OK", - "Error accessing SD card", - "Assertion failed", - "SD card failure", - "Could not find file", - "Could not find path", - "Invalid path name", - "Access denied or directory full", - "Access denied", - "Invalid file/directory object", - "SD card is write protected", - "Logical drive number is invalid", - "Volume has no work area", - "No valid FAT volume", - "Error occurred during mkfs", - "Volume timeout", - "Volume locked", - "LFN working buffer could not be allocated", - "Too many open files", - "Invalid parameter", - "Invalid command", - "Invalid executable", - ## Standard IO Library +**Not ISO compliant!** + Consists of the following: File IO: @@ -1122,9 +127,11 @@ Formatted input - `sscanf()` -### Stdio Redirection +There's some other stuff in here - like `stdint` and such - but it should mostly match expectations for the normal standard library. Mostly. + +### `stdio` Redirection -Can redirect output by using `freopen() `on `stdout` or `stderr`: +Can redirect output by using `freopen()` on `stdout` or `stderr`: - `putchar()` - outputs to `outchar()` unless the output is redirected, in which case outputs to `fputc()` @@ -1132,13 +139,13 @@ Can redirect output by using `freopen() `on `stdout` or `stderr`: - `printf()` (and `vprintf()`) - calls `npf_putc_std()`, which calls `putchar()` in `nanoprintf.c` -- `fputc()` - calls `mos_fputc()` unless called on `stdout` when calls `outchar()`- avoids calling `putchar()` so that no risk of function call loops +- `fputc()` - calls `mos_fputc()` unless called on `stdout` when calls `outchar()` - avoids calling `putchar()` so that no risk of function call loops Can redirect input by using `freopen()` on `stdin`: - `getchar()` - calls `inchar()` to get the character and `outchar()` to echo the character (even if the output has been redirected). If output has not been re-directed calls `fgetc()` and does not echo the character. -- `gets_s()`- calls `getchar()` if input has not been redirected (line are terminated with CR). Calls`fgets()` of input has been redirected (lines are terminated with CR/LF pair). +- `gets_s()` - calls `getchar()` if input has not been redirected (line are terminated with CR). Calls`fgets()` of input has been redirected (lines are terminated with CR/LF pair). - `scanf()` - calls `getchar()` in `uscan.c` (doesn't need updating) @@ -1166,21 +173,21 @@ MOS does not implement input / output redirection, so by default these all use t Two options are available for command line processing. -### Simple Command Line Processing +#### Simple Command Line Processing This is automatically included if the main function is defined as -``` +```cpp int main( int argc, char* argv[] ) ``` the splits the command line up using space as a delimiter. The command line options are available in the `argv[]` array as normal. -### Complex Command Line Processing - for Redirection & Quoting +#### Complex Command Line Processing - for Redirection & Quoting -This is optionally included if the makefile includes: +This is optionally included if the application makefile includes: -``` +```makefile LDHAS_ARG_PROCESSING = 1 ``` @@ -1195,398 +202,44 @@ This supports - `>>out_file.txt` - redirects stdout to `out_file.txt`, appending to the end of the file - `` for the bit masks - -Commands can be sent by: - -- `putch()` - single character (this is not part of the C standard library, on MS-DOS systems it is defined in `` - -- `mos_puts()` - multi-character string - -Both of which output directly to MOS/VDP - note that they are not part of STDIO library and not subject to CR/LF translation or redirection. +## MOS Commands -### VDU Commands +For current documentation on MOS commands, see the [Agon Console8 Documentation](https://agonconsole8.github.io/agon-docs/vdp/MOS-API/). -For current documentation on VDU commands, see the [Agon Console8 Documentation](https://agonconsole8.github.io/agon-docs/VDP.html) +The MOS (machine operating system) provides an interface to the Agon file system and some hardware peripherals, like the mouse. It keeps information on system variables in a large `SYSVAR` struct that can be accessed on the Z80 side. Generally your C code will declare a pointer to this struct, initialized like so: -These can be called by sending the appropriate control characters using `putch()` or `mos_puts()` as mentioned. - -Convenience functions for many of these are supplied in AgDev. - -For example, to change the screen MODE to 3, the C call `vdp_mode(3);` will send `22,3` as single bytes to the output, equivalent to `putch(22);putch(3);` - -For a list of the commands see `include/agon/vdp_vdu.h` - - -## VDP / Keyboard Interrupts - -## Appendix - eZ80 compile runtime - -``` -//===-- Z80ISelLowering.cpp - Z80 DAG Lowering Implementation -------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file defines the interfaces that Z80 uses to lower LLVM code into a -// selection DAG. -// -//===----------------------------------------------------------------------===// - - setLibcall(RTLIB::ZEXT_I16_I24, "_stoiu", CallingConv::Z80_LibCall ); - setLibcall(RTLIB::SEXT_I16_I24, "_stoi", CallingConv::Z80_LibCall ); - setLibcall(RTLIB::SEXT_I24_I32, "_itol", CallingConv::Z80_LibCall ); - - setLibcall(RTLIB::NOT_I16, "_snot", CallingConv::Z80_LibCall ); - setLibcall(RTLIB::NOT_I24, "_inot", CallingConv::Z80_LibCall ); - setLibcall(RTLIB::NOT_I32, "_lnot", CallingConv::Z80_LibCall ); - setLibcall(RTLIB::NOT_I64, "_llnot", CallingConv::Z80_LibCall ); - setLibcall(RTLIB::AND_I16, "_sand", CallingConv::Z80_LibCall ); - setLibcall(RTLIB::AND_I24, "_iand", CallingConv::Z80_LibCall ); - setLibcall(RTLIB::AND_I32, "_land", CallingConv::Z80_LibCall ); - setLibcall(RTLIB::AND_I64, "_lland", CallingConv::Z80_LibCall ); - setLibcall(RTLIB::OR_I16, "_sor", CallingConv::Z80_LibCall ); - setLibcall(RTLIB::OR_I24, "_ior", CallingConv::Z80_LibCall ); - setLibcall(RTLIB::OR_I32, "_lor", CallingConv::Z80_LibCall ); - setLibcall(RTLIB::OR_I64, "_llor", CallingConv::Z80_LibCall ); - setLibcall(RTLIB::XOR_I16, "_sxor", CallingConv::Z80_LibCall ); - setLibcall(RTLIB::XOR_I24, "_ixor", CallingConv::Z80_LibCall ); - setLibcall(RTLIB::XOR_I32, "_lxor", CallingConv::Z80_LibCall ); - setLibcall(RTLIB::XOR_I64, "_llxor", CallingConv::Z80_LibCall ); - setLibcall(RTLIB::SHL_I8, "_bshl", CallingConv::Z80_LibCall_AB); - setLibcall(RTLIB::SHL_I16, "_sshl", CallingConv::Z80_LibCall ); - setLibcall(RTLIB::SHL_I16_I8, "_sshl_b", CallingConv::Z80_LibCall_AC); - setLibcall(RTLIB::SHL_I24, "_ishl", CallingConv::Z80_LibCall ); - setLibcall(RTLIB::SHL_I24_I8, "_ishl_b", CallingConv::Z80_LibCall_AC); - setLibcall(RTLIB::SHL_I32, "_lshl", CallingConv::Z80_LibCall_L ); - setLibcall(RTLIB::SHL_I64, "_llshl", CallingConv::Z80_LibCall ); - setLibcall(RTLIB::SRA_I8, "_bshrs", CallingConv::Z80_LibCall_AB); - setLibcall(RTLIB::SRA_I16, "_sshrs", CallingConv::Z80_LibCall ); - setLibcall(RTLIB::SRA_I16_I8, "_sshrs_b", CallingConv::Z80_LibCall_AC); - setLibcall(RTLIB::SRA_I24, "_ishrs", CallingConv::Z80_LibCall ); - setLibcall(RTLIB::SRA_I24_I8, "_ishrs_b", CallingConv::Z80_LibCall_AC); - setLibcall(RTLIB::SRA_I32, "_lshrs", CallingConv::Z80_LibCall_L ); - setLibcall(RTLIB::SRA_I64, "_llshrs", CallingConv::Z80_LibCall ); - setLibcall(RTLIB::SRL_I8, "_bshru", CallingConv::Z80_LibCall_AB); - setLibcall(RTLIB::SRL_I16, "_sshru", CallingConv::Z80_LibCall ); - setLibcall(RTLIB::SRL_I16_I8, "_sshru_b", CallingConv::Z80_LibCall_AC); - setLibcall(RTLIB::SRL_I24, "_ishru", CallingConv::Z80_LibCall ); - setLibcall(RTLIB::SRL_I24_I8, "_ishru_b", CallingConv::Z80_LibCall_AC); - setLibcall(RTLIB::SRL_I32, "_lshru", CallingConv::Z80_LibCall_L ); - setLibcall(RTLIB::SRL_I64, "_llshru", CallingConv::Z80_LibCall ); - setLibcall(RTLIB::CMP_I32, "_lcmpu", CallingConv::Z80_LibCall_F ); - setLibcall(RTLIB::CMP_I64, "_llcmpu", CallingConv::Z80_LibCall_F ); - setLibcall(RTLIB::CMP_I16_0, "_scmpzero", CallingConv::Z80_LibCall_F ); - setLibcall(RTLIB::CMP_I24_0, "_icmpzero", CallingConv::Z80_LibCall_F ); - setLibcall(RTLIB::CMP_I32_0, "_lcmpzero", CallingConv::Z80_LibCall_F ); - setLibcall(RTLIB::CMP_I64_0, "_llcmpzero",CallingConv::Z80_LibCall_F ); - setLibcall(RTLIB::SCMP_I32, "_lcmps", CallingConv::Z80_LibCall_F ); - setLibcall(RTLIB::SCMP_I64, "_llcmps", CallingConv::Z80_LibCall_F ); - setLibcall(RTLIB::SCMP, "_setflag", CallingConv::Z80_LibCall_F ); - setLibcall(RTLIB::NEG_I16, "_sneg", CallingConv::Z80_LibCall ); - setLibcall(RTLIB::NEG_I24, "_ineg", CallingConv::Z80_LibCall ); - setLibcall(RTLIB::NEG_I32, "_lneg", CallingConv::Z80_LibCall ); - setLibcall(RTLIB::NEG_I64, "_llneg", CallingConv::Z80_LibCall ); - setLibcall(RTLIB::ADD_I32, "_ladd", CallingConv::Z80_LibCall ); - setLibcall(RTLIB::ADD_I32_I8, "_ladd_b", CallingConv::Z80_LibCall_AC); - setLibcall(RTLIB::ADD_I64, "_lladd", CallingConv::Z80_LibCall ); - setLibcall(RTLIB::SUB_I32, "_lsub", CallingConv::Z80_LibCall ); - setLibcall(RTLIB::SUB_I64, "_llsub", CallingConv::Z80_LibCall ); - setLibcall(RTLIB::MUL_I8, "_bmulu", CallingConv::Z80_LibCall_BC); - setLibcall(RTLIB::MUL_I16, "_smulu", CallingConv::Z80_LibCall ); - setLibcall(RTLIB::MUL_I24, "_imulu", CallingConv::Z80_LibCall ); - setLibcall(RTLIB::MUL_I24_I8, "_imul_b", CallingConv::Z80_LibCall_AC); - setLibcall(RTLIB::MUL_I32, "_lmulu", CallingConv::Z80_LibCall ); - setLibcall(RTLIB::MUL_I64, "_llmulu", CallingConv::Z80_LibCall ); - setLibcall(RTLIB::SDIV_I8, "_bdivs", CallingConv::Z80_LibCall_BC); - setLibcall(RTLIB::SDIV_I16, "_sdivs", CallingConv::Z80_LibCall_16); - setLibcall(RTLIB::SDIV_I24, "_idivs", CallingConv::Z80_LibCall ); - setLibcall(RTLIB::SDIV_I32, "_ldivs", CallingConv::Z80_LibCall ); - setLibcall(RTLIB::SDIV_I64, "_lldivs", CallingConv::Z80_LibCall ); - setLibcall(RTLIB::UDIV_I8, "_bdivu", CallingConv::Z80_LibCall_BC); - setLibcall(RTLIB::UDIV_I16, "_sdivu", CallingConv::Z80_LibCall_16); - setLibcall(RTLIB::UDIV_I24, "_idivu", CallingConv::Z80_LibCall ); - setLibcall(RTLIB::UDIV_I32, "_ldivu", CallingConv::Z80_LibCall ); - setLibcall(RTLIB::UDIV_I64, "_lldivu", CallingConv::Z80_LibCall ); - setLibcall(RTLIB::SREM_I8, "_brems", CallingConv::Z80_LibCall_AC); - setLibcall(RTLIB::SREM_I16, "_srems", CallingConv::Z80_LibCall_16); - setLibcall(RTLIB::SREM_I24, "_irems", CallingConv::Z80_LibCall ); - setLibcall(RTLIB::SREM_I32, "_lrems", CallingConv::Z80_LibCall ); - setLibcall(RTLIB::SREM_I64, "_llrems", CallingConv::Z80_LibCall ); - setLibcall(RTLIB::UREM_I8, "_bremu", CallingConv::Z80_LibCall_AC); - setLibcall(RTLIB::UREM_I16, "_sremu", CallingConv::Z80_LibCall_16); - setLibcall(RTLIB::UREM_I24, "_iremu", CallingConv::Z80_LibCall ); - setLibcall(RTLIB::UREM_I32, "_lremu", CallingConv::Z80_LibCall ); - setLibcall(RTLIB::UREM_I64, "_llremu", CallingConv::Z80_LibCall ); - setLibcall(RTLIB::UDIVREM_I24, "_idvrmu", CallingConv::Z80_LibCall ); - setLibcall(RTLIB::UDIVREM_I32, "_ldvrmu", CallingConv::Z80_LibCall ); - - setLibcall(RTLIB::CTLZ_I8, "_bctlz", CallingConv::Z80_LibCall_AC); - setLibcall(RTLIB::CTLZ_I16, "_sctlz", CallingConv::Z80_LibCall ); - setLibcall(RTLIB::CTLZ_I24, "_ictlz", CallingConv::Z80_LibCall ); - setLibcall(RTLIB::CTLZ_I32, "_lctlz", CallingConv::Z80_LibCall ); - setLibcall(RTLIB::CTLZ_I64, "_llctlz", CallingConv::Z80_LibCall ); - setLibcall(RTLIB::POPCNT_I8, "_bpopcnt", CallingConv::Z80_LibCall_AC); - setLibcall(RTLIB::POPCNT_I16, "_spopcnt", CallingConv::Z80_LibCall ); - setLibcall(RTLIB::POPCNT_I24, "_ipopcnt", CallingConv::Z80_LibCall ); - setLibcall(RTLIB::POPCNT_I32, "_lpopcnt", CallingConv::Z80_LibCall ); - setLibcall(RTLIB::POPCNT_I64, "_llpopcnt", CallingConv::Z80_LibCall ); - setLibcall(RTLIB::BITREV_I8, "_bbitrev", CallingConv::Z80_LibCall_AC); - setLibcall(RTLIB::BITREV_I16, "_sbitrev", CallingConv::Z80_LibCall ); - setLibcall(RTLIB::BITREV_I24, "_ibitrev", CallingConv::Z80_LibCall ); - setLibcall(RTLIB::BITREV_I32, "_lbitrev", CallingConv::Z80_LibCall ); - setLibcall(RTLIB::BITREV_I64, "_llbitrev", CallingConv::Z80_LibCall ); - setLibcall(RTLIB::BSWAP_I32, "_lbswap", CallingConv::Z80_LibCall ); - setLibcall(RTLIB::BSWAP_I64, "_llbswap", CallingConv::Z80_LibCall ); - - setLibcall(RTLIB::ADD_F32, "_fadd", CallingConv::Z80_LibCall_L ); - setLibcall(RTLIB::SUB_F32, "_fsub", CallingConv::Z80_LibCall_L ); - setLibcall(RTLIB::MUL_F32, "_fmul", CallingConv::Z80_LibCall_L ); - setLibcall(RTLIB::DIV_F32, "_fdiv", CallingConv::Z80_LibCall_L ); - setLibcall(RTLIB::REM_F32, "_frem", CallingConv::Z80_LibCall_L ); - setLibcall(RTLIB::NEG_F32, "_fneg", CallingConv::Z80_LibCall_L ); - setLibcall(RTLIB::CMP_F32, "_fcmp", CallingConv::Z80_LibCall_F ); - setLibcall(RTLIB::FPTOSINT_F32_I32, "_ftol", CallingConv::Z80_LibCall_L ); - setLibcall(RTLIB::FPTOSINT_F32_I64, "_ftoll", CallingConv::Z80_LibCall ); - setLibcall(RTLIB::FPTOUINT_F32_I32, "_ftoul", CallingConv::Z80_LibCall_L ); - setLibcall(RTLIB::FPTOUINT_F32_I64, "_ftoull", CallingConv::Z80_LibCall ); - setLibcall(RTLIB::SINTTOFP_I32_F32, "_ltof", CallingConv::Z80_LibCall_L ); - setLibcall(RTLIB::SINTTOFP_I64_F32, "_lltof", CallingConv::Z80_LibCall ); - setLibcall(RTLIB::UINTTOFP_I32_F32, "_ultof", CallingConv::Z80_LibCall_L ); - setLibcall(RTLIB::UINTTOFP_I64_F32, "_ulltof", CallingConv::Z80_LibCall ); - - setLibcall(RTLIB::ADD_F64, "_dadd", CallingConv::Z80_LibCall ); - setLibcall(RTLIB::SUB_F64, "_dsub", CallingConv::Z80_LibCall ); - setLibcall(RTLIB::MUL_F64, "_dmul", CallingConv::Z80_LibCall ); - setLibcall(RTLIB::DIV_F64, "_ddiv", CallingConv::Z80_LibCall ); - setLibcall(RTLIB::REM_F64, "_drem", CallingConv::Z80_LibCall ); - setLibcall(RTLIB::NEG_F64, "_dneg", CallingConv::Z80_LibCall ); - setLibcall(RTLIB::CMP_F64, "_dcmp", CallingConv::Z80_LibCall_F ); - setLibcall(RTLIB::FPEXT_F32_F64, "_ftod", CallingConv::Z80_LibCall ); - setLibcall(RTLIB::FPROUND_F64_F32, "_dtof", CallingConv::Z80_LibCall ); - setLibcall(RTLIB::FPTOSINT_F64_I32, "_dtol", CallingConv::Z80_LibCall ); - setLibcall(RTLIB::FPTOSINT_F64_I64, "_dtoll", CallingConv::Z80_LibCall ); - setLibcall(RTLIB::FPTOUINT_F64_I32, "_dtoul", CallingConv::Z80_LibCall ); - setLibcall(RTLIB::FPTOUINT_F64_I64, "_dtoull", CallingConv::Z80_LibCall ); - setLibcall(RTLIB::SINTTOFP_I32_F64, "_ltod", CallingConv::Z80_LibCall ); - setLibcall(RTLIB::SINTTOFP_I64_F64, "_lltod", CallingConv::Z80_LibCall ); - setLibcall(RTLIB::UINTTOFP_I32_F64, "_ultod", CallingConv::Z80_LibCall ); - setLibcall(RTLIB::UINTTOFP_I64_F64, "_ulltod", CallingConv::Z80_LibCall );c +```cpp +static volatile SYSVAR* sv; +sv = vdp_vdu_init(); ``` -## Appendix - FASMG Quick Reference Guide - -From: https://www.cemetech.net/forum/viewtopic.php?t=13913&start=0 - -### Expressions - -Each line is a precedence level, except where specified otherwise, operators within a precedence level are evaluated ltr. - -| Ops | Meaning | -| ------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| | ***Logical expressions*** | -| ~ | unary logical not, arguments can also be | -| &, \| | binary logical conjunction and disjunction | -| | ***All the operators below this line can only have basic expressions as arguments*** | -| =, <, >, <=, >=, <>, eq, eqtype, relativeto | Comparison, <> is not equal, eq is like = but returns false for uncomparable operands, eqtype returns true if both operands are the same (algebraic, string, float) type, relativeto returns true if both operands are comparable (differ by a constant) | -| defined, used | true if the basic expression to the right is entirely defined, true if the variable name to the right is used | -| | ***Basic expressions*** | -| lengthof, elementsof, float, trunc | length of a string in characters, length of a poly in terms, int to float, float to int | -| sizeof, elementof, scaleof, metadataof | rtl size associated with a label, poly op idx for element,  scale,   metadata idx op poly | -| not, bsf, bsr | complement, index of lowest set bit, index of highest set bit | -| shl, shr, bswap | shifts, byte swap (second arg is the size of the value to swap, in bytes) | -| xor, and, or | bitwise | -| mod | remainder | -| *, / | multiplication, division | -| +, - | addition, subtraction (includes unary ops) | -| string | converts a number to a string (strings are usually converted to numbers implicitly, or explicitly with a unary + operator) | - -### Builtin symbolic variable - -- `#` ; concatenates two names into a single identifier, but each side may get replaced individually if it matches a parameter name - -- `$` ; current pc - -- `$$` ; base of the current output section (address passed to last org) - -- `$@` ; address after last non-reserved data - -- `$%` ; offset within output file, does not work with tiformat.inc - -- `$%%` ; offset after last non-reserved data within output file, does not work with tiformat.inc - -- `%t` ; assembly timestamp - -- `__file__` ; current file - -- `__line__` ; current line - -### Commands - -#### Program Layout +For more information see ``. -- `org ` ; start a new output area to appear next in the file and assembled starting at address `` - -- `section ` ; same as org but do not output reserved bytes, does not work with tiformat.inc - -- `virtual [] `; start a new output area that does not get output to the file - end virtual ; restore the previous output area - -- `::` ; creates an area label that references the current output area - -- `load [ : ] from [ : ]` ; loads `` (defaults to `sizeof `) outputted bytes from address `` in output area `` (defaults to current output area) and store in variable `` - -- `store [ : ] at [ : ]` ; stores `` (defaults to `sizeof `) bytes to address `` in output area `` (default to current output area) and store in variable `` - -#### Data / Storage - -- `db [, ...] `; define 1-byte values - -- `rb ` ; reserve `` 1-byte locations - -- `dw [, ...]` ; define 2-byte values - -- `rw ` ; reserve `` 2-byte locations - -- `dl [, ...] `; define 3-byte values - -- `rl ` ; reserve `` 3-byte locations - -- `dd [, ...] `; define 4-byte values - -- `rd ` ; reserve `` 4-byte locations - -- `emit|dbx : [, ...] `; define ``-byte values; - -If any reserve or definition is preceded by a name with no colon, that name gets defined as a label to the first item, with a sizeof the item size - -Inside any definition - -- ` rep ` ; repeats `` `` times, to include more than one value in the repetition, enclose them with <> - -#### Names - -- ` equ ` ; define an arbitrary text substitution for a symbol - -- ` reequ ` ; same as equ but don't discard previous value - -- `define ` ; same as equ, but is not checked for recursive substitutions until use - -- `redefine ` ; same as define but don't discard previous value - -- ` = ` ; assign a value to a symbol, discarding current value - -- ` =: ` ; assign a value to a symbol, remembering the current value - -- ` := ` ; assign a value to a constant symbol only once, attempts to redefine will error, therefore it can always be forward referenced - -- `:` ; like ` := $` - -- `label [ : ][ at ] `; defines a constant symbol with size at address (defaults to $) - -- `restore [, ...] `; restore the previously remembered value for each symbol - -#### Namespaces - -Namespaces can be created by assigning anything to any symbol - -- `namespace ` ; switches to, but does not create, the namespace associated with the symbol - -- All new symbols `` defined in here can be referenced outside the namespace block with . - -- `end namespace` - -#### Macros - -- `macro [[, ...]] `; defines a macro, remembering the current contents. Macro body, parameters get substituted with their values every time the macro is executed - -- `end macro` - -- `purge ` ; restores the previously remembered contents of a macro - -- `struc [(