mirror of
https://github.com/hsoft/collapseos.git
synced 2024-09-08 09:28:46 +10:00
112 lines
4.8 KiB
Markdown
112 lines
4.8 KiB
Markdown
# User applications
|
|
|
|
This folder contains code designed to be "userspace" application. Unlike the
|
|
kernel, which always stay in memory. Those apps here will more likely be loaded
|
|
in RAM from storage, ran, then discarded so that another userspace program can
|
|
be run.
|
|
|
|
That doesn't mean that you can't include that code in your kernel though, but
|
|
you will typically not want to do that.
|
|
|
|
## Userspace convention
|
|
|
|
We execute a userspace application by calling the address it's loaded into.
|
|
|
|
This means that userspace applications must be assembled with a proper `.org`,
|
|
otherwise labels in its code will be wrong.
|
|
|
|
The `.org`, it is not specified by glue code of the apps themselves. It is
|
|
expected to be set either in the `user.h` file to through `zasm` 3rd argument.
|
|
|
|
That a userspace is called also means that an application, when finished
|
|
running, is expected to return with a regular `ret` and a clean stack.
|
|
|
|
Whatever calls the userspace app (usually, it will be the shell), should set
|
|
HL to a pointer to unparsed arguments in string form, null terminated.
|
|
|
|
The userspace application is expected to set A on return. 0 means success,
|
|
non-zero means error.
|
|
|
|
A userspace application can expect the `SP` pointer to be properly set. If it
|
|
moves it, it should take care of returning it where it was before returning
|
|
because otherwise, it will break the kernel.
|
|
|
|
## Memory management
|
|
|
|
Apps in Collapse OS are design to be ROM-compatible, that is, they don't write
|
|
to addresses that are part of the code's address space.
|
|
|
|
By default, apps set their RAM to begin at the end of the binary because in
|
|
most cases, these apps will be ran from RAM. If they're ran from ROM, make sure
|
|
to set `USER_RAMSTART` properly in your `user.h` to ensure that the RAM is
|
|
placed properly.
|
|
|
|
Applications that are ran as a shell (the "shell" app, of course, but also,
|
|
possibly, "basic" and others to come) need a manual override to their main
|
|
`RAMSTART` constant: You don't want them to run in the same RAM region as your
|
|
other userspace apps because if you do, as soon as you launch an app with your
|
|
shell, its memory is going to be overwritten!
|
|
|
|
What you'll do then is that you'll reserve some space in your memory layout for
|
|
the shell and add a special constant in your `user.h`, which will override the
|
|
basic one (remember, in zasm, the first `.equ` for a given constant takes
|
|
precedence).
|
|
|
|
For example, if you want a "basic" shell and that you reserve space right
|
|
after your kernel RAM for it, then your `user.h` would contain
|
|
`.equ BAS_RAMSTART KERNEL_RAMEND`.
|
|
|
|
You can also include your shell's code directly in the kernel by copying
|
|
relevant parts of the app's glue unit in your kernel's glue unit. This is often
|
|
simpler and more efficient. However, if your shell is a big program, it might
|
|
run into zasm's limits. In that case, you'd have to assemble your shell
|
|
separately.
|
|
|
|
## Common features
|
|
|
|
The folder `lib/` contains code shared in more than one apps and this has the
|
|
effect that some concepts are exactly the same in many application. They are
|
|
therefore sharing documentation, here.
|
|
|
|
### Number literals
|
|
|
|
There are decimal, hexadecimal and binary literals. A "straight" number is
|
|
parsed as a decimal. Hexadecimal literals must be prefixed with `0x` (`0xf4`).
|
|
Binary must be prefixed with `0b` (`0b01100110`).
|
|
|
|
Decimals and hexadecimal are "flexible". Whether they're written in a byte or
|
|
a word, you don't need to prefix them with zeroes. Watch out for overflow,
|
|
however.
|
|
|
|
Binary literals are also "flexible" (`0b110` is fine), but can't go over a byte.
|
|
|
|
There is also the char literal (`'X'`), that is, two quotes with a character in
|
|
the middle. The value of that character is interpreted as-is, without any
|
|
encoding involved. That is, whatever binary code is written in between those
|
|
two quotes, it's what is evaluated. Only a single byte at once can be evaluated
|
|
thus. There is no escaping. `'''` results in `0x27`. You can't express a newline
|
|
this way, it's going to mess with the parser.
|
|
|
|
### Expressions
|
|
|
|
An expression is a bunch of literals or symbols assembled by operators.
|
|
Supported operators are `+`, `-`, `*`, `/`, `%` (modulo), `&` (bitwise and),
|
|
`|` (bitwise or), `^` (bitwise xor), `{` (shift left), `}` (shift right).
|
|
Bitwise operator always operate on the whole 16-bits.
|
|
|
|
Shift operators break from the `<<` and `>>` tradition because the complexity
|
|
if two-sized operator is significant and deemed not worth it. The shift
|
|
operator shift the left operand X times, X being the right operand.
|
|
|
|
There is no parenthesis support yet.
|
|
|
|
Symbols have a different meaning depending on the application. In zasm, it's
|
|
labels and constants. In basic, it's variables.
|
|
|
|
Expressions can't contain spaces.
|
|
|
|
Expressions can have an empty left operand. It will then be considered as 0.
|
|
This allows signed integers, for example, `-42` to be expressed as expected.
|
|
That form doesn't work well everywhere and is mostly supported for BASIC. In
|
|
zasm, you're safer with `0-42`.
|