From d74b85f14630789cbf49e123d339980cebf871ed Mon Sep 17 00:00:00 2001 From: Virgil Dupras Date: Fri, 15 Nov 2019 09:57:53 -0500 Subject: [PATCH] zasm: allow .org to be specified from command line Also important for upcoming mega commit... --- apps/zasm/README.md | 15 +++++++++++++++ apps/zasm/main.asm | 28 +++++++++++++++++++--------- tools/emul/zasm/glue.asm | 9 ++++++++- tools/emul/zasm/kernel.bin | Bin 1497 -> 1512 bytes tools/emul/zasm/zasm.bin | Bin 4724 -> 4733 bytes tools/emul/zasm/zasm.c | 24 +++++++++++++++++++----- tools/zasm.sh | 23 ++++++++++++++++++++++- 7 files changed, 83 insertions(+), 16 deletions(-) diff --git a/apps/zasm/README.md b/apps/zasm/README.md index efcc78b..a313abc 100644 --- a/apps/zasm/README.md +++ b/apps/zasm/README.md @@ -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 diff --git a/apps/zasm/main.asm b/apps/zasm/main.asm index b69422b..8e0bd7a 100644 --- a/apps/zasm/main.asm +++ b/apps/zasm/main.asm @@ -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: diff --git a/tools/emul/zasm/glue.asm b/tools/emul/zasm/glue.asm index 6a8c6f3..f436838 100644 --- a/tools/emul/zasm/glue.asm +++ b/tools/emul/zasm/glue.asm @@ -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: diff --git a/tools/emul/zasm/kernel.bin b/tools/emul/zasm/kernel.bin index a4c866714e8b4b50233c4e40163b905b6374d718..760660fa17e7240625cdbf9b8d62c81868534084 100644 GIT binary patch delta 137 zcmcb~{epYLHYW4stfdU44BJ`vvtD35Y{hVRH|y7@b=x)A&hBPamiYGY>p*OQ zpAQe7{A$MwWZQ9_-97m&lZDc5)^cTmXY0!qxf~9jtoSFdaZ8)Ujsv7Z0Ym^h($ delta 122 zcmaFCeUp2`HYW2KtfdU43@cbSupVSRY{hVR4eQsZb=x)A&aPoqmiYGY>p*OQ zpAQe7{A$MwWZQ9_T{HPDlZDb6)^cTmXY0!qxf~9jtoSFdaZ8)Ujsv7Z0Ym^|+?GRyz~ diff --git a/tools/emul/zasm/zasm.bin b/tools/emul/zasm/zasm.bin index feb88a7888eadc29eebfc38daa49dc2297682c21..c312b97443525980f80a6a992e0a29d4ae1a43c6 100644 GIT binary patch delta 234 zcmeyO@>gX;5+mb@$;pfsjE6SQVSLL3q`Fw5m^cnaY8YRAdiK)hH*9;^fGSq;hBKa< z%*5vdRN&7S&B%Hv5+u8xe=;NEipkD`s?JvOWkyP6M)e8njTFm_>Jp6P%FgO~p0$Zk zTpf9~%FB+?NVe?k-ADxy#cd$|dLZ|%qItwwwMd}o;aD$5M%KxT1kIGcM;@s7_fLaK z;_KNHkqWG5v!f(l?>~7q)w|*!<0-+Ye@v%DC;t|d)Ho5TA$&G4LPPzoqHe@lpnHYS Y21iLq-c>Y;011ONas%Bs*+$3$0F#?vP5=M^ delta 272 zcmeyX@DPlHL~>)HL03an?7 zq9k7LKY2FQyW$_?DUPUrOs9CF{xNF^{QGypPVlg+N9ExH|H{LA!W2ysfEqM}&jv #include +#include #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= 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; diff --git a/tools/zasm.sh b/tools/zasm.sh index dd16e2a..10b1097 100755 --- a/tools/zasm.sh +++ b/tools/zasm.sh @@ -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 ] ..." 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