1
0
mirror of https://github.com/hsoft/collapseos.git synced 2024-11-26 09:28:05 +11:00

Compare commits

..

No commits in common. "cdd0b64570a2f125e76d7ea11929e74b9b8368c2" and "79e04189b0ac1414a2c1b38ecc5c1935607188e5" have entirely different histories.

22 changed files with 50 additions and 137 deletions

View File

@ -10,16 +10,8 @@ you will typically not want to do that.
## Userspace convention ## Userspace convention
We execute a userspace application by calling the address it's loaded into. We execute a userspace application by calling the address it's loaded into. This
means: a userspace application is expected to return.
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 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. HL to a pointer to unparsed arguments in string form, null terminated.
@ -33,8 +25,3 @@ because otherwise, it will break the kernel.
Apps in Collapse OS are design to be ROM-compatible, that is, they don't write 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. 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 "user.h"
.inc "err.h" .inc "err.h"
.org USER_CODE
.equ AT28W_RAMSTART USER_RAMSTART .equ AT28W_RAMSTART USER_RAMSTART
jp at28wMain jp at28wMain
.inc "at28w/main.asm" .inc "at28w/main.asm"
USER_RAMSTART:

View File

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

View File

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

View File

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

View File

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

View File

@ -3,21 +3,6 @@
This is probably the most critical part of the Collapse OS project because it This is probably the most critical part of the Collapse OS project because it
ensures its self-reproduction. 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 ## Running on a "modern" machine
To be able to develop zasm efficiently, [libz80][libz80] is used to run zasm To be able to develop zasm efficiently, [libz80][libz80] is used to run zasm
@ -116,10 +101,7 @@ it was placed there.
Whenever a `.equ` directive is evaluated, its resulting value is saved in a 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 special "last value" register that can then be used in any expression. This
last value is referenced with the `@` special symbol. This is very useful for is very useful for variable definitions and for jump tables.
variable definitions and for jump tables.
Note that `.org` also affect the last value.
## Includes ## Includes

View File

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

View File

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

View File

@ -8,17 +8,14 @@
; whether we're in "local pass", that is, in local label scanning mode. During ; 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 ; 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. ; code behaves as is we were in the first pass.
.equ ZASM_LOCAL_PASS @+1 .equ ZASM_LOCAL_PASS ZASM_FIRST_PASS+1
; What IO_PC was when we started our context ; What IO_PC was when we started our context
.equ ZASM_CTX_PC @+1 .equ ZASM_CTX_PC ZASM_LOCAL_PASS+1
; current ".org" offset, that is, what we must offset all our label by. ; current ".org" offset, that is, what we must offset all our label by.
.equ ZASM_ORG @+2 .equ ZASM_ORG ZASM_CTX_PC+2
.equ ZASM_RAMEND @+2 .equ ZASM_RAMEND ZASM_ORG+2
; Takes 2 byte arguments, blkdev in and blkdev out, expressed as IDs. ; 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. ; Read file through blkdev in and outputs its upcodes through blkdev out.
; HL is set to the last lineno to be read. ; 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_*) ; Sets Z on success, unset on error. On error, A contains an error code (ERR_*)
@ -26,7 +23,7 @@ zasmMain:
; Parse args. HL points to string already ; Parse args. HL points to string already
; We don't allocate memory just to hold this. Because this happens ; We don't allocate memory just to hold this. Because this happens
; before initialization, we don't really care where those args are ; before initialization, we don't really care where those args are
; parsed. That's why we borrow zasm's RAMSTART for a little while. ; parsed.
ld de, .argspecs ld de, .argspecs
ld ix, ZASM_RAMSTART ld ix, ZASM_RAMSTART
call parseArgs call parseArgs
@ -47,18 +44,11 @@ zasmMain:
ld de, IO_OUT_BLK ld de, IO_OUT_BLK
call blkSel call blkSel
; Init .org ; Init modules
; 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 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_LOCAL_PASS), a
ld (ZASM_ORG), a
ld (ZASM_ORG+1), a
call ioInit call ioInit
call symInit call symInit
@ -83,7 +73,7 @@ zasmMain:
jp ioLineNo ; --> HL, --> DE, returns jp ioLineNo ; --> HL, --> DE, returns
.argspecs: .argspecs:
.db 0b001, 0b001, 0b101 .db 0b001, 0b001, 0
.sFirstPass: .sFirstPass:
.db "First pass", 0 .db "First pass", 0
.sSecondPass: .sSecondPass:

View File

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

View File

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

View File

@ -1,5 +1,8 @@
; 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 USER_RAMSTART 0xc200
.equ FS_HANDLE_SIZE 8 .equ FS_HANDLE_SIZE 6
.equ BLOCKDEV_SIZE 8 .equ BLOCKDEV_SIZE 8
; Make ed fit in SMS's memory ; Make ed fit in SMS's memory
.equ ED_BUF_MAXLINES 0x100 .equ ED_BUF_MAXLINES 0x100

View File

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

View File

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

View File

@ -56,20 +56,13 @@ init:
ld de, BLOCKDEV_SEL ld de, BLOCKDEV_SEL
call blkSel call blkSel
call fsOn 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 ld hl, .zasmArgs
call USER_CODE call USER_CODE
; signal the emulator we're done ; signal the emulator we're done
halt halt
.zasmArgs: .zasmArgs:
.db "0 1 XX", 0 .db "0 1", 0
; *** I/O *** ; *** I/O ***
emulGetB: emulGetB:

Binary file not shown.

View File

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

Binary file not shown.

View File

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

View File

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

View File

@ -1,30 +1,9 @@
#!/usr/bin/env bash #!/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 # 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 # 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'))") 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 # wrapper around ./emul/zasm/zasm that prepares includes CFS prior to call
DIR=$(dirname "${ABS_PATH}") DIR=$(dirname "${ABS_PATH}")
ZASMBIN="${DIR}/emul/zasm/zasm" ZASMBIN="${DIR}/emul/zasm/zasm"
@ -37,7 +16,7 @@ for p in "$@"; do
"${CFSPACK}" "${p}" "*.bin" >> "${INCCFS}" "${CFSPACK}" "${p}" "*.bin" >> "${INCCFS}"
done done
"${ZASMBIN}" "${org}" "${INCCFS}" "${ZASMBIN}" "${INCCFS}"
RES=$? RES=$?
rm "${INCCFS}" rm "${INCCFS}"
exit $RES exit $RES