1
0
mirror of https://github.com/hsoft/collapseos.git synced 2024-11-02 16:30:57 +11:00

Compare commits

...

3 Commits

Author SHA1 Message Date
Virgil Dupras
cdd0b64570 Modify userspace .org and RAMSTART expectations
Instead of expecting a `USER_CODE` symbol to be set, we expect `.org` to be
set in all userspace glue code. This gives us more flexibility with regards to
how we manage that.

Moreover, instead of making `USER_RAMSTART` mandatory, we make it default to
the end of the binary, which is adequate in a majority of cases.

Will be useful for my upcoming mega-commit... :)
2019-11-15 10:33:13 -05:00
Virgil Dupras
d74b85f146 zasm: allow .org to be specified from command line
Also important for upcoming mega commit...
2019-11-15 09:57:53 -05:00
Virgil Dupras
e5255d22f9 zasm: make .org affect "@" symbol 2019-11-15 08:59:26 -05:00
22 changed files with 137 additions and 50 deletions

View File

@ -10,8 +10,16 @@ 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: a userspace application is expected to return.
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.
@ -25,3 +33,8 @@ because otherwise, it will break the kernel.
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.

View File

@ -16,9 +16,9 @@
.inc "user.h"
.inc "err.h"
.org USER_CODE
.equ AT28W_RAMSTART USER_RAMSTART
jp at28wMain
.inc "at28w/main.asm"
USER_RAMSTART:

View File

@ -7,7 +7,6 @@
.inc "user.h"
.inc "err.h"
.org USER_CODE
jp basStart
@ -16,3 +15,4 @@
.inc "lib/parse.asm"
.equ BAS_RAMSTART USER_RAMSTART
.inc "basic/main.asm"
USER_RAMSTART:

View File

@ -26,8 +26,6 @@
; ******
.inc "err.h"
.org USER_CODE
jp edMain
.inc "core.asm"
@ -41,3 +39,4 @@
.inc "ed/cmd.asm"
.equ ED_RAMSTART CMD_RAMEND
.inc "ed/main.asm"
USER_RAMSTART:

View File

@ -13,8 +13,7 @@
; *** Includes ***
.inc "user.h"
.org USER_CODE
jp memtMain
.inc "memt/main.asm"
USER_RAMSTART:

View File

@ -19,9 +19,9 @@
; *** Includes ***
.inc "user.h"
.org USER_CODE
.equ SDCT_RAMSTART USER_RAMSTART
jp sdctMain
.inc "sdct/main.asm"
USER_RAMSTART:

View File

@ -3,6 +3,21 @@
This is probably the most critical part of the Collapse OS project because it
ensures its self-reproduction.
## Invocation
`zasm` is invoked with 2 mandatory arguments and an optional one. The mandatory
arguments are input blockdev id and output blockdev id. For example, `zasm 0 1`
reads source code from blockdev 0, assembles it and spit the result in blockdev
1.
Input blockdev needs to be seek-able, output blockdev doesn't need to (zasm
writes in one pass, sequentially.
The 3rd argument, optional, is the initial `.org` value. It's the high byte of
the value. For example, `zasm 0 1 4f` assembles source in blockdev 0 as if it
started with the line `.org 0x4f00`. This also means that the initial value of
the `@` symbol is `0x4f00`.
## Running on a "modern" machine
To be able to develop zasm efficiently, [libz80][libz80] is used to run zasm
@ -101,7 +116,10 @@ it was placed there.
Whenever a `.equ` directive is evaluated, its resulting value is saved in a
special "last value" register that can then be used in any expression. This
is very useful for variable definitions and for jump tables.
last value is referenced with the `@` special symbol. This is very useful for
variable definitions and for jump tables.
Note that `.org` also affect the last value.
## Includes

View File

@ -18,7 +18,7 @@
; *** CODE ***
; 3 bytes per row, fill with zero
directiveNames:
dirNames:
.db "DB", 0
.db "DW", 0
.db "EQU"
@ -28,8 +28,8 @@ directiveNames:
.db "INC"
.db "BIN"
; This is a list of handlers corresponding to indexes in directiveNames
directiveHandlers:
; This is a list of handlers corresponding to indexes in dirNames
dirHandlers:
.dw handleDB
.dw handleDW
.dw handleEQU
@ -184,6 +184,7 @@ handleORG:
call parseExpr
jr nz, .badarg
push ix \ pop hl
ld (DIREC_LASTVAL), hl
call zasmSetOrg
cp a ; ensure Z
ret
@ -310,7 +311,7 @@ getDirectiveID:
inc hl
ld b, D_BIN+1 ; D_BIN is last
ld c, 3
ld de, directiveNames
ld de, dirNames
call findStringInList
pop de
pop bc
@ -324,9 +325,9 @@ getDirectiveID:
; error, A contains the error number (ERR_*).
parseDirective:
push de
; double A to have a proper offset in directiveHandlers
; double A to have a proper offset in dirHandlers
add a, a
ld de, directiveHandlers
ld de, dirHandlers
call addDE
call intoDE
push de \ pop ix

View File

@ -64,8 +64,6 @@
.inc "err.h"
.inc "ascii.h"
.org USER_CODE
jp zasmMain
.inc "core.asm"
@ -87,3 +85,4 @@ jp zasmMain
.inc "zasm/symbol.asm"
.equ ZASM_RAMSTART SYM_RAMEND
.inc "zasm/main.asm"
USER_RAMSTART:

View File

@ -8,14 +8,17 @@
; whether we're in "local pass", that is, in local label scanning mode. During
; this special pass, ZASM_FIRST_PASS will also be set so that the rest of the
; code behaves as is we were in the first pass.
.equ ZASM_LOCAL_PASS ZASM_FIRST_PASS+1
.equ ZASM_LOCAL_PASS @+1
; What IO_PC was when we started our context
.equ ZASM_CTX_PC ZASM_LOCAL_PASS+1
.equ ZASM_CTX_PC @+1
; current ".org" offset, that is, what we must offset all our label by.
.equ ZASM_ORG ZASM_CTX_PC+2
.equ ZASM_RAMEND ZASM_ORG+2
.equ ZASM_ORG @+2
.equ ZASM_RAMEND @+2
; Takes 2 byte arguments, blkdev in and blkdev out, expressed as IDs.
; Can optionally take a 3rd argument which is the high byte of the initial
; .org. For example, passing 0x42 to this 3rd arg is the equivalent of beginning
; the unit with ".org 0x4200".
; Read file through blkdev in and outputs its upcodes through blkdev out.
; HL is set to the last lineno to be read.
; Sets Z on success, unset on error. On error, A contains an error code (ERR_*)
@ -23,7 +26,7 @@ zasmMain:
; Parse args. HL points to string already
; We don't allocate memory just to hold this. Because this happens
; before initialization, we don't really care where those args are
; parsed.
; parsed. That's why we borrow zasm's RAMSTART for a little while.
ld de, .argspecs
ld ix, ZASM_RAMSTART
call parseArgs
@ -44,11 +47,18 @@ zasmMain:
ld de, IO_OUT_BLK
call blkSel
; Init modules
; Init .org
; This is the 3rd argument, optional, will be zero if not given.
; Save in "@" too
ld a, (ZASM_RAMSTART+2)
ld (ZASM_ORG+1), a ; high byte of .org
ld (DIREC_LASTVAL+1), a
xor a
ld (ZASM_ORG), a ; low byte zero in all cases
ld (DIREC_LASTVAL), a
; And then the rest.
ld (ZASM_LOCAL_PASS), a
ld (ZASM_ORG), a
ld (ZASM_ORG+1), a
call ioInit
call symInit
@ -73,7 +83,7 @@ zasmMain:
jp ioLineNo ; --> HL, --> DE, returns
.argspecs:
.db 0b001, 0b001, 0
.db 0b001, 0b001, 0b101
.sFirstPass:
.db "First pass", 0
.sSecondPass:

View File

@ -1,6 +1,5 @@
.equ USER_CODE 0x8700
.equ USER_RAMSTART USER_CODE+0x1900
.equ FS_HANDLE_SIZE 6
.org 0x8700
.equ FS_HANDLE_SIZE 8
.equ BLOCKDEV_SIZE 8
; *** JUMP TABLE ***

View File

@ -5,13 +5,13 @@ APPS = ../../../apps
.PHONY: all clean
all: os.sms
# -o value synced with offset in glue.asm
ed.bin: $(APPS)/ed/glue.asm
echo ".equ USER_CODE ED_CODE" | cat user-tmpl.h - > user.h
$(ZASM) $(KERNEL) $(APPS) user.h < $< > $@
$(ZASM) -o 19 $(KERNEL) $(APPS) user.h < $< > $@
# -o value synced with offset in glue.asm
zasm.bin: $(APPS)/zasm/glue.asm
echo ".equ USER_CODE ZASM_CODE" | cat user-tmpl.h - > user.h
$(ZASM) $(KERNEL) $(APPS) user.h < $< > $@
$(ZASM) -o 1d $(KERNEL) $(APPS) user.h < $< > $@
os.sms: glue.asm ed.bin zasm.bin
$(ZASM) $(KERNEL) ed.bin zasm.bin < $< > $@

View File

@ -1,8 +1,5 @@
; USER_CODE is filled in on-the-fly with either ED_CODE or ZASM_CODE
.equ ED_CODE 0x1900
.equ ZASM_CODE 0x1d00
.equ USER_RAMSTART 0xc200
.equ FS_HANDLE_SIZE 6
.equ FS_HANDLE_SIZE 8
.equ BLOCKDEV_SIZE 8
; Make ed fit in SMS's memory
.equ ED_BUF_MAXLINES 0x100

View File

@ -1,6 +1,4 @@
.inc "user.h"
.org USER_CODE
ld hl, sAwesome
call printstr
xor a ; success

View File

@ -1,5 +1,4 @@
.equ USER_CODE 0x4200
.equ USER_RAMSTART USER_CODE+0x1800
.org 0x4200 ; in sync with USERCODE in shell/shell_.asm
.equ FS_HANDLE_SIZE 8
.equ BLOCKDEV_SIZE 8

View File

@ -56,13 +56,20 @@ init:
ld de, BLOCKDEV_SEL
call blkSel
call fsOn
; There's a special understanding between zasm.c and this unit: The
; addresses 0xff00 and 0xff01 contain the two ascii chars to send to
; zasm as the 3rd argument.
ld a, (0xff00)
ld (.zasmArgs+4), a
ld a, (0xff01)
ld (.zasmArgs+5), a
ld hl, .zasmArgs
call USER_CODE
; signal the emulator we're done
halt
.zasmArgs:
.db "0 1", 0
.db "0 1 XX", 0
; *** I/O ***
emulGetB:

Binary file not shown.

View File

@ -1,4 +1,4 @@
.equ USER_CODE 0x4800
.org 0x4800 ; in sync with USER_CODE in glue.asm
.equ USER_RAMSTART 0x6000
.equ FS_HANDLE_SIZE 8
.equ BLOCKDEV_SIZE 8

Binary file not shown.

View File

@ -1,5 +1,6 @@
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include "../libz80/z80.h"
#include "kernel-bin.h"
#include "zasm-bin.h"
@ -8,8 +9,11 @@
* in another specified blkdev. In our emulator layer, we use stdin and stdout
* as those specified blkdevs.
*
* This executable takes one argument: the path to a .cfs file to use for
* includes.
* This executable takes two arguments. Both are optional, but you need to
* specify the first one if you want to get to the second one.
* The first one is the value to send to z80-zasm's 3rd argument (the initial
* .org). Defaults to '00'.
* The second one is the path to a .cfs file to use for includes.
*
* Because the input blkdev needs support for Seek, we buffer it in the emulator
* layer.
@ -155,7 +159,7 @@ static void mem_write(int unused, uint16_t addr, uint8_t val)
int main(int argc, char *argv[])
{
if (argc > 2) {
if (argc > 3) {
fprintf(stderr, "Too many args\n");
return 1;
}
@ -166,9 +170,19 @@ int main(int argc, char *argv[])
for (int i=0; i<sizeof(USERSPACE); i++) {
mem[i+USER_CODE] = USERSPACE[i];
}
char *init_org = "00";
if (argc >= 2) {
init_org = argv[1];
if (strlen(init_org) != 2) {
fprintf(stderr, "Initial org must be a two-character hex string");
}
}
// glue.asm knows that it needs to fetch these arguments at this address.
mem[0xff00] = init_org[0];
mem[0xff01] = init_org[1];
fsdev_size = 0;
if (argc == 2) {
FILE *fp = fopen(argv[1], "r");
if (argc == 3) {
FILE *fp = fopen(argv[2], "r");
if (fp == NULL) {
fprintf(stderr, "Can't open file %s\n", argv[1]);
return 1;

View File

@ -1,3 +1,8 @@
.equ foo 456 ; AFTER_ORG should not get that value
.org 0x1234
.equ AFTER_ORG @
.org 0
jp test
.inc "core.asm"
@ -40,6 +45,13 @@ test:
jp nz, fail
call nexttest
; test that "@" is updated by a .org directive
ld hl, AFTER_ORG
ld de, 0x1234
call cpHLDE
jp nz, fail
call nexttest
; *** cpHLDE ***
ld hl, 0x42
ld de, 0x42
@ -73,3 +85,4 @@ nexttest:
fail:
ld a, (testNum)
halt

View File

@ -1,9 +1,30 @@
#!/usr/bin/env bash
# Calls tools/emul/zasm/zasm in a convenient manner by wrapping specified
# paths to include in a single CFS file and then pass that file to zasm.
# Additionally, it takes a "-o" argument to set the initial ".org" of the
# binary. For example, "zasm.sh -o 4f < foo.asm" assembles foo.asm as if it
# started with the line ".org 0x4f00".
# readlink -f doesn't work with macOS's implementation
# so, if we can't get readlink -f to work, try python with a realpath implementation
ABS_PATH=$(readlink -f "$0" || python -c "import os; print(os.path.realpath('$0'))")
usage() { echo "Usage: $0 [-o <hexorg>] <paths-to-include>..." 1>&2; exit 1; }
org='00'
while getopts ":o:" opt; do
case "${opt}" in
o)
org=${OPTARG}
;;
*)
usage
;;
esac
done
shift $((OPTIND-1))
# wrapper around ./emul/zasm/zasm that prepares includes CFS prior to call
DIR=$(dirname "${ABS_PATH}")
ZASMBIN="${DIR}/emul/zasm/zasm"
@ -16,7 +37,7 @@ for p in "$@"; do
"${CFSPACK}" "${p}" "*.bin" >> "${INCCFS}"
done
"${ZASMBIN}" "${INCCFS}"
"${ZASMBIN}" "${org}" "${INCCFS}"
RES=$?
rm "${INCCFS}"
exit $RES