Skip to content

Commit

Permalink
kernel_headers: add support for GNU's assembler (z80-elf)
Browse files Browse the repository at this point in the history
  • Loading branch information
Zeal8bit committed Sep 30, 2024
1 parent b2bd978 commit a8c31b4
Show file tree
Hide file tree
Showing 10 changed files with 1,091 additions and 3 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -469,7 +469,7 @@ This also means that when invoking the `exec` syscall in an assembly program, on

### Syscall documentation

The syscalls are all documented in the header files provided for both assembly and C, you will find [assembly headers here](https://github.com/Zeal8bit/Zeal-8-bit-OS/tree/main/kernel_headers/z88dk-z80asm) and [C headers here](https://github.com/Zeal8bit/Zeal-8-bit-OS/tree/main/kernel_headers/sdcc/include) respectively.
The syscalls are all documented in the header files provided for both assembly and C, you will find these header file in the `kernel_headers/` directory, check its [README file for more information](https://github.com/Zeal8bit/Zeal-8-bit-OS/tree/main/kernel_headers/README.md).

## Drivers

Expand Down
5 changes: 3 additions & 2 deletions kernel_headers/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,11 @@ For more info, check the `README.md` files contained inside each supported compi

Currently, assembly header files are provided for the following assemblers:

* z88dk-z80asm. The directory `z88dk-z80asm` contains an assembly file that is meant to be included inside any assembly project. Of course, that project should be assembled with z88dk's `z80asm` assembler.
* z88dk-z80asm. The directory `z88dk-z80asm` contains assembly files that are meant to be included inside any z80asm assembly project.
* gnu-as. The direcotry `gnu-as` contains assembly files that are meant to be included in any assembly project that is assembled with `z80-elf` assembler.

## Examples

As its name states, the directory `examples`, contains code samples that can be compiled/assembled for Zeal 8-bit OS.

For more info, check the `README.md` files contained inside each example directory.
For more info, check the `README.md` files contained inside each example directory.
49 changes: 49 additions & 0 deletions kernel_headers/examples/gnu-as/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
SHELL := /bin/bash

SRCS = main.asm
BIN = main.bin

# Only extract the following sections from the ELF file
SECTIONS=.text .data

# Assembler flags, provide a path to the Zeal 8-bit OS header files. The option `-g` is not mandatory,
# it will only generate more debug symbols in the final ELF file, making it possible to use utils
# like `addr2line`. It can be omitted.
ASFLAGS = -I$(ZOS_INCLUDE) -g
# The binary must be relocated at address 0x4000 since this is where Zeal 8-bit OS kernel will copy
# the program and execute it from. Make sure all the other sections follow the `.text` section.
# If not, it may be necessary to make a custom Linker Script file `.ld` and provide it at link time.
LDFLAGS = -Ttext 0x4000

# Directory where source files are and where the binaries will be put
INPUT_DIR = src
OUTPUT_DIR = bin
OBJS := $(addprefix $(OUTPUT_DIR)/, $(SRCS:.asm=.asm.o))

# Include directory containing Zeal 8-bit OS header file.
ifndef ZOS_PATH
$(error "Please define ZOS_PATH environment variable. It must point to Zeal 8-bit OS source code path.")
endif
ZOS_INCLUDE = $(ZOS_PATH)/kernel_headers/gnu-as/

# Assembler binary name
AS = z80-elf-as
LD = z80-elf-ld
OBJCPY = z80-elf-objcopy
.PHONY: all

all: $(OUTPUT_DIR) $(OUTPUT_DIR)/$(BIN)

$(OUTPUT_DIR)/$(BIN): $(OBJS)
$(LD) $(LDFLAGS) -o $@.elf $<
$(OBJCPY) $(addprefix --only-section=, $(SECTIONS)) -O binary $@.elf $@


$(OUTPUT_DIR)/%.asm.o: $(INPUT_DIR)/%.asm
$(AS) $(ASFLAGS) -o $@ $<

$(OUTPUT_DIR):
mkdir -p $@

clean:
rm -r bin/
58 changes: 58 additions & 0 deletions kernel_headers/examples/gnu-as/src/main.asm
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
; SPDX-FileCopyrightText: 2024 Zeal 8-bit Computer <contact@zeal8bit.com>
;
; SPDX-License-Identifier: CC0-1.0

; Include the Zeal 8-bit OS header file, containing all the syscalls macros.
.include "zos_sys.asm"

; The .text section will be linked at address `0x4000`
.text

; We can start the code here, directly, no need to create a routine, but let's keep it clean.
.global _start
_start:
; Start by printing a message on the standard output. As we know at compile time the message, the length
; and the dev we want to write on, we can use S_WRITE3 macro.
S_WRITE3 DEV_STDOUT, _message, _message_end - _message
; Read from the input to get the user name. Let's use a 128-byte buffer, this should be more than enough.
; We could use S_READ3, but let's use READ instead as most syscalls require us to setup the parameters.
ld h, DEV_STDIN ; Standard input dev (already opened by the kernel)
ld de, _buffer ; Destination buffer
ld bc, 128 ; Buffer size
READ()
; Syscalls only alters the registers that contain a return value. READ() puts error in A and the number
; of bytes/character in BC.
; Check for errors, we can use `cp ERR_SUCCESS`, but let's optimize a bit as ERR_SUCCESS is 0.
or a
; Exit on error
jr nz, _end
; No error, print "Hello <name>", we have to add the size of "Hello " to BC
ld hl, _buffer - _hello_name
add hl, bc
; Put the final size in BC
ld b, h
ld c, l
; Prepare the other parameters to print: H and DE.
; We could use S_WRITE2 here, but let's prepare the parameters manually instead.
ld h, DEV_STDOUT
ld de, _hello_name
WRITE
_end:
; We MUST execute EXIT() syscall at the end of any program.
; Exit code is stored in H, it is 0 if everything went fine.
ld h, a
EXIT()
; Only used for debugging, `readelf` will show the size of this routine, not necessary
; for runtime, can be ignore or removed.
.size _start, . - _start

.data
; Define a label before and after the message, so that we can get the length of the string
; thanks to `_message_end - _message`.
_message: .ascii "Type your name: "
_message_end:

; Prefix the buffer with the word "Hello ", so that we can print "Hello <name>".
_hello_name: .ascii "Hello "
; Buffer we will use to store the input text
_buffer: .space 128
17 changes: 17 additions & 0 deletions kernel_headers/gnu-as/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# Assembly header file for z88dk's z80asm assembler

In this directory, you will find an assembly file, `zos_sys.asm`, that acts as an header file. Indeed, it shall be included by any assembly project targeting Zeal 8-bit OS.

This file is fairly simple, it contains macros for all the syscalls available in Zeal 8-bit OS kernel. For more info about each of them, check the header file directly.

## Usage

The following line needs be added at the top of the assembly file using Zeal 8-bit OS syscalls:
```
INCLUDE "zos_sys.asm"
```

When assembling, either copy this file in the project's directory, either provide the following option to `z80asm`:
```
z88dk-z80asm -I<path_to_directory_containing_zos_sys.asm>
```
33 changes: 33 additions & 0 deletions kernel_headers/gnu-as/zos_err.asm
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
; SPDX-FileCopyrightText: 2024 Zeal 8-bit Computer <contact@zeal8bit.com>
;
; SPDX-License-Identifier: Apache-2.0

.equiv ZOS_ERR_HEADER, 1

.equ ERR_SUCCESS, 0
.equ ERR_FAILURE, 1
.equ ERR_NOT_IMPLEMENTED, 2
.equ ERR_NOT_SUPPORTED, 3
.equ ERR_NO_SUCH_ENTRY, 4
.equ ERR_INVALID_SYSCALL, 5
.equ ERR_INVALID_PARAMETER, 6
.equ ERR_INVALID_VIRT_PAGE, 7
.equ ERR_INVALID_PHYS_ADDRESS, 8
.equ ERR_INVALID_OFFSET, 9
.equ ERR_INVALID_NAME, 10
.equ ERR_INVALID_PATH, 11
.equ ERR_INVALID_FILESYSTEM, 12
.equ ERR_INVALID_FILEDEV, 13
.equ ERR_PATH_TOO_LONG, 14
.equ ERR_ALREADY_EXIST, 15
.equ ERR_ALREADY_OPENED, 16
.equ ERR_ALREADY_MOUNTED, 17
.equ ERR_READ_ONLY, 18
.equ ERR_BAD_MODE, 19
.equ ERR_CANNOT_REGISTER_MORE, 20
.equ ERR_NO_MORE_ENTRIES, 21
.equ ERR_NO_MORE_MEMORY, 22
.equ ERR_NOT_A_DIR, 23
.equ ERR_NOT_A_FILE, 24
.equ ERR_ENTRY_CORRUPTED, 25
.equ ERR_DIR_NOT_EMPTY, 26
178 changes: 178 additions & 0 deletions kernel_headers/gnu-as/zos_keyboard.asm
Original file line number Diff line number Diff line change
@@ -0,0 +1,178 @@

; SPDX-FileCopyrightText: 2024 Zeal 8-bit Computer <contact@zeal8bit.com>
;
; SPDX-License-Identifier: Apache-2.0

.equiv ZOS_KEYBOARD_H, 1

; This file represents the keyboard interface for a key input driver.

; kb_cmd_t: This group represents the IOCTL commands an input/keyboard driver should implement
; Set the current input mode, check the attributes in the group below.
; Parameters:
; E - New mode
.equ KB_CMD_SET_MODE, 0
; Number of commands above
.equ KB_CMD_COUNT, 1


; kb_mode_t: Modes supported by input/keyboard driver
; In raw mode, all the characters that are pressed or released are sent to the user
; program when a read occurs.
; This means that no treatment is performed by the driver whatsoever. For example,
; if (Left) Shift and A are pressed, the bytes sent to the user program will be:
; 0x93 0x61
; Left shift Ascii lower A
; The non-special characters must be sent in lowercase mode.
.equ KB_MODE_RAW, 0
; In COOKED mode, the entry is buffered. So when a key is pressed, it is
; first processed before being stored in a buffer and sent to the user
; program (on "read").
; The buffer is flushed when it is full or when Enter ('\n') is pressed.
; The keys that will be treated by the driver are:
; - Non-special characters:
; which includes all printable characters: letters, numbers, punctuation, etc.
; - Special characters that have a well defined behavior:
; which includes caps lock, (left/right) shifts, left arrow,
; right arrow, delete key, tabulation, enter.
; The remaining special characters are ignored. Release key events are
; also ignored.
.equ KB_MODE_COOKED, 1
; HALFCOOKED mode is similar to COOKED mode, the difference is, when an
; unsupported key is pressed, instead of being ignored, it is filled in
; the buffer and a special error code is returned: ERR_SPECIAL_STATE
; The "release key" events shall still be ignored and not transmitted to
; the user program.
.equ KB_MODE_HALFCOOKED, 2
; Number of modes above
.equ KB_MODE_COUNT, 3


; kb_block_t: Blocking/non-blocking modes, can be ORed with the mode above
; In blocking mode, the `read` syscall will not return until a newline character ('\n')
; is encountered.
.equ KB_READ_BLOCK, 0 << 2
; In non-blocking mode, the syscall `read` can return 0 if there is no pending keys that were
; typed by the user. Please note that the driver must NOT return KB_RELEASED without a key following it.
; In other words, if the buffer[i] has been filled with a KB_RELEASED, buffer[i+1] must be valid
; and contain the key that was released.
.equ KB_READ_NON_BLOCK, 1 << 2


; The following codes represent the keys of a 104-key keyboard that can be detected by
; the keyboard driver.
; When the input mode is set to RAW, the following keys can be sent to the
; user program to mark which keys were pressed (or released).
.equ KB_KEY_A, 'a'
.equ KB_KEY_B, 'b'
.equ KB_KEY_C, 'c'
.equ KB_KEY_D, 'd'
.equ KB_KEY_E, 'e'
.equ KB_KEY_F, 'f'
.equ KB_KEY_G, 'g'
.equ KB_KEY_H, 'h'
.equ KB_KEY_I, 'i'
.equ KB_KEY_J, 'j'
.equ KB_KEY_K, 'k'
.equ KB_KEY_L, 'l'
.equ KB_KEY_M, 'm'
.equ KB_KEY_N, 'n'
.equ KB_KEY_O, 'o'
.equ KB_KEY_P, 'p'
.equ KB_KEY_Q, 'q'
.equ KB_KEY_R, 'r'
.equ KB_KEY_S, 's'
.equ KB_KEY_T, 't'
.equ KB_KEY_U, 'u'
.equ KB_KEY_V, 'v'
.equ KB_KEY_W, 'w'
.equ KB_KEY_X, 'x'
.equ KB_KEY_Y, 'y'
.equ KB_KEY_Z, 'z'
.equ KB_KEY_0, '0'
.equ KB_KEY_1, '1'
.equ KB_KEY_2, '2'
.equ KB_KEY_3, '3'
.equ KB_KEY_4, '4'
.equ KB_KEY_5, '5'
.equ KB_KEY_6, '6'
.equ KB_KEY_7, '7'
.equ KB_KEY_8, '8'
.equ KB_KEY_9, '9'
.equ KB_KEY_BACKQUOTE, '`'
.equ KB_KEY_MINUS, '-'
.equ KB_KEY_EQUAL, '='
.equ KB_KEY_BACKSPACE, '\b'
.equ KB_KEY_SPACE, ' '
.equ KB_KEY_ENTER, '\n'
.equ KB_KEY_TAB, '\t'
.equ KB_KEY_COMMA, ','
.equ KB_KEY_PERIOD, '.'
.equ KB_KEY_SLASH, '/'
.equ KB_KEY_SEMICOLON, ';'
.equ KB_KEY_QUOTE, 0x27
.equ KB_KEY_LEFT_BRACKET, '['
.equ KB_KEY_RIGHT_BRACKET, ']'
.equ KB_KEY_BACKSLASH, 0x5c

; When the input mode is set to RAW or HALFCOOKED, the following keys can be sent to the
; user program to mark which special keys were pressed (or released).
.equ KB_NUMPAD_0, 0x80
.equ KB_NUMPAD_1, 0x81
.equ KB_NUMPAD_2, 0x82
.equ KB_NUMPAD_3, 0x83
.equ KB_NUMPAD_4, 0x84
.equ KB_NUMPAD_5, 0x85
.equ KB_NUMPAD_6, 0x86
.equ KB_NUMPAD_7, 0x87
.equ KB_NUMPAD_8, 0x88
.equ KB_NUMPAD_9, 0x89
.equ KB_NUMPAD_DOT, 0x8a
.equ KB_NUMPAD_ENTER, 0x8b
.equ KB_NUMPAD_PLUS, 0x8c
.equ KB_NUMPAD_MINUS, 0x8d
.equ KB_NUMPAD_MUL, 0x8e
.equ KB_NUMPAD_DIV, 0x8f
.equ KB_NUMPAD_LOCK, 0x90
.equ KB_SCROLL_LOCK, 0x91
.equ KB_CAPS_LOCK, 0x92
.equ KB_LEFT_SHIFT, 0x93
.equ KB_LEFT_ALT, 0x94
.equ KB_LEFT_CTRL, 0x95
.equ KB_RIGHT_SHIFT, 0x96
.equ KB_RIGHT_ALT, 0x97
.equ KB_RIGHT_CTRL, 0x98
.equ KB_HOME, 0x99
.equ KB_END, 0x9a
.equ KB_INSERT, 0x9b
.equ KB_DELETE, 0x9c
.equ KB_PG_DOWN, 0x9d
.equ KB_PG_UP, 0x9e
.equ KB_PRINT_SCREEN, 0x9f
.equ KB_UP_ARROW, 0xa0
.equ KB_DOWN_ARROW, 0xa1
.equ KB_LEFT_ARROW, 0xa2
.equ KB_RIGHT_ARROW, 0xa3
.equ KB_LEFT_SPECIAL, 0xa4

.equ KB_ESC, 0xf0
.equ KB_F1, 0xf1
.equ KB_F2, 0xf2
.equ KB_F3, 0xf3
.equ KB_F4, 0xf4
.equ KB_F5, 0xf5
.equ KB_F6, 0xf6
.equ KB_F7, 0xf7
.equ KB_F8, 0xf8
.equ KB_F9, 0xf9
.equ KB_F10, 0xfa
.equ KB_F11, 0xfb
.equ KB_F12, 0xfc

; When a released event is triggered, this value shall precede the key concerned.
; As such, in RAW mode, each key press should at some point generate a release
; sequence. For example:
; 0x61 [...] 0xFE 0x61
; A [...] A released
.equ KB_RELEASED, 0xfe
.equ KB_UNKNOWN, 0xff
Loading

0 comments on commit a8c31b4

Please sign in to comment.