Переглянути джерело

zasm: read input in two passes

pull/10/head
Virgil Dupras 5 роки тому
джерело
коміт
c239ec7dea
4 змінених файлів з 83 додано та 19 видалено
  1. +5
    -0
      apps/zasm/io.asm
  2. +67
    -16
      apps/zasm/main.asm
  3. +5
    -2
      tools/emul/zasm.c
  4. +6
    -1
      tools/emul/zasm_glue.asm

+ 5
- 0
apps/zasm/io.asm Переглянути файл

@@ -22,6 +22,11 @@ ioPutC:
ld ix, (IO_OUT_PUTC)
jp (ix)

ioRewind:
ld hl, 0
ld ix, (IO_IN_SEEK)
jp (ix)

; Sets Z is A is CR, LF, or null.
isLineEnd:
or a ; same as cp 0


+ 67
- 16
apps/zasm/main.asm Переглянути файл

@@ -1,3 +1,22 @@
; zasm
;
; Reads input from specified blkdev ID, assemble the binary in two passes and
; spit the result in another specified blkdev ID.
;
; We don't buffer the whole source in memory, so we need our input blkdev to
; support Seek so we can read the file a second time. So, for input, we need
; GetC and Seek.
;
; For output, we only need PutC. Output doesn't start until the second pass.
;
; The goal of the second pass is to assign values to all symbols so that we
; can have forward references (instructions referencing a label that happens
; later).
;
; Labels and constants are both treated the same way, that is, they can be
; forward-referenced in instructions. ".equ" directives, however, are evaluated
; during the first pass so forward references are not allowed.
;
; *** Requirements ***
; blockdev
; JUMP_STRNCMP
@@ -10,9 +29,20 @@
; JUMP_BLKSEL
; RAMSTART (where we put our variables in RAM)

jp main
; *** Variables ***

; A bool flag indicating that we're on first pass. When we are, we don't care
; about actual output, but only about the length of each upcode. This means
; that when we parse instructions and directive that error out because of a
; missing symbol, we don't error out and just write down a dummy value.
.equ ZASM_FIRST_PASS RAMSTART
.equ ZASM_RAMEND ZASM_FIRST_PASS+1

; *** Code ***
jp zasmMain

#include "util.asm"
.equ IO_RAMSTART RAMSTART
.equ IO_RAMSTART ZASM_RAMEND
#include "io.asm"
#include "parse.asm"
#include "literal.asm"
@@ -21,26 +51,30 @@ jp main
.equ SYM_RAMSTART IO_RAMEND
#include "symbol.asm"

; *** Code ***
; Read file through blockdev ID in H and outputs its upcodes through blockdev
; ID in L.
main:
zasmMain:
ld a, h
ld de, IO_IN_GETC
call JUMP_BLKSEL
ld a, l
ld de, IO_OUT_GETC
call JUMP_BLKSEL
ld hl, 0
ld (curOutputOffset), hl
.loop:
call ioReadLine
or a ; is A 0?
jr z, .stop ; We have EOF
call parseLine
jr nz, .stop
jr .loop
.stop:
; First pass
ld a, 1
ld (ZASM_FIRST_PASS), a
call zasmParseFile
; Second pass
call ioRewind
xor a
ld (ZASM_FIRST_PASS), a
call zasmParseFile
ret

; Sets Z according to whether we're in first pass.
zasmIsFirstPass:
ld a, (ZASM_FIRST_PASS)
cp 1
ret

; Increase (curOutputOffset) by A
@@ -52,6 +86,17 @@ incOutputOffset:
pop de
ret

zasmParseFile:
ld hl, 0
ld (curOutputOffset), hl
.loop:
call ioReadLine
or a ; is A 0?
ret z ; We have EOF
call parseLine
ret nz
jr .loop

; Parse line in (HL), write the resulting opcode(s) in (DE) and increases
; (curOutputOffset) by the number of bytes written. Advances HL where
; tokenization stopped and DE to where we should write the next upcode.
@@ -75,8 +120,10 @@ parseLine:
call parseInstruction
or a ; is zero?
jr z, .error
ld b, a ; save output byte count
call incOutputOffset
ld b, a
call zasmIsFirstPass
jr z, .success ; first pass, nothing to write
ld hl, instrUpcode
.loopInstr:
ld a, (hl)
@@ -87,8 +134,10 @@ parseLine:
.direc:
ld a, c ; D_*
call parseDirective
ld b, a ; save output byte count
call incOutputOffset
ld b, a
call zasmIsFirstPass
jr z, .success ; first pass, nothing to write
ld hl, direcData
.loopDirec:
ld a, (hl)
@@ -97,6 +146,8 @@ parseLine:
djnz .loopDirec
jr .success
.label:
call zasmIsFirstPass
jr nz, .success ; not in first pass? nothing to do
; The string in (scratchpad) is a label with its trailing ':' removed.
ld hl, scratchpad
ld de, (curOutputOffset)


+ 5
- 2
tools/emul/zasm.c Переглянути файл

@@ -4,9 +4,12 @@
#include "zasm-kernel.h"
#include "zasm-user.h"

/* zasm is a "pure memory" application. It starts up being told memory location
* to read and memory location to write.
/* zasm reads from a specified blkdev, assemble the file and writes the result
* in another specified blkdev. In our emulator layer, we use stdin and stdout
* as those specified blkdevs.
*
* Because the input blkdev needs support for Seek, we buffer it in the emulator
* layer.
*
* Memory layout:
*


+ 6
- 1
tools/emul/zasm_glue.asm Переглянути файл

@@ -2,6 +2,7 @@
.equ RAMSTART 0x4000
.equ USER_CODE 0x4800
.equ STDIO_PORT 0x00
.equ STDIN_REWIND 0x01

jr init ; 2 bytes
; *** JUMP TABLE ***
@@ -40,10 +41,14 @@ emulPutC:
out (STDIO_PORT), a
ret

emulSeek:
out (STDIN_REWIND), a
ret

#include "core.asm"
.equ BLOCKDEV_RAMSTART RAMSTART
.equ BLOCKDEV_COUNT 2
#include "blockdev.asm"
; List of devices
.dw emulGetC, 0, 0, 0
.dw emulGetC, 0, emulSeek, 0
.dw 0, emulPutC, 0, 0

Завантаження…
Відмінити
Зберегти