mirror of
https://github.com/hsoft/collapseos.git
synced 2024-11-02 18:10:55 +11:00
Compare commits
2 Commits
0d7693a163
...
57c1a10434
Author | SHA1 | Date | |
---|---|---|---|
|
57c1a10434 | ||
|
e691dab070 |
@ -165,4 +165,17 @@ using `IX` and `IY` as 8-bit registers. We used to support them, but because
|
|||||||
this makes our code incompatible with Z80-compatible CPUs such as the Z180, we
|
this makes our code incompatible with Z80-compatible CPUs such as the Z180, we
|
||||||
prefer to avoid these in our code.
|
prefer to avoid these in our code.
|
||||||
|
|
||||||
|
## AVR assembler
|
||||||
|
|
||||||
|
`zasm` can be configured, at compile time, to be a AVR assembler instead of a
|
||||||
|
z80 assembler. Directives, literals, symbols, they're all the same, it's just
|
||||||
|
instructions and their arguments that change.
|
||||||
|
|
||||||
|
Instructions and their arguments have a ayntax that is similar to other AVR
|
||||||
|
assemblers: registers are referred to as `rXX`, mnemonics are the same,
|
||||||
|
arguments are separated by commas.
|
||||||
|
|
||||||
|
To assemble an AVR assembler, use the `gluea.asm` file instead of the regular
|
||||||
|
one.
|
||||||
|
|
||||||
[libz80]: https://github.com/ggambetta/libz80
|
[libz80]: https://github.com/ggambetta/libz80
|
||||||
|
263
apps/zasm/avr.asm
Normal file
263
apps/zasm/avr.asm
Normal file
@ -0,0 +1,263 @@
|
|||||||
|
; Same thing as instr.asm, but for AVR instructions
|
||||||
|
|
||||||
|
; *** Instructions table ***
|
||||||
|
|
||||||
|
; List of mnemonic names separated by a null terminator. Their index in the
|
||||||
|
; list is their ID. Unlike in zasm, not all mnemonics have constant associated
|
||||||
|
; to it because it's generally not needed. This list is grouped by argument
|
||||||
|
; categories, and then alphabetically. Categories are ordered so that the 8bit
|
||||||
|
; opcodes come first, then the 16bit ones. 0xff ends the chain
|
||||||
|
instrNames:
|
||||||
|
; Rd(5) + Rr(5)
|
||||||
|
.equ I_ADC 0
|
||||||
|
.db "ADC", 0
|
||||||
|
.db "ADD", 0
|
||||||
|
.db "AND", 0
|
||||||
|
.db "CLR", 0
|
||||||
|
.db "CP", 0
|
||||||
|
.db "CPC", 0
|
||||||
|
.db "CPSE", 0
|
||||||
|
.db "EOR", 0
|
||||||
|
.db "MOV", 0
|
||||||
|
.db "MUL", 0
|
||||||
|
.db "OR", 0
|
||||||
|
.db "SBC", 0
|
||||||
|
.db "SUB", 0
|
||||||
|
; no arg
|
||||||
|
.equ I_BREAK 13
|
||||||
|
.db "BREAK", 0
|
||||||
|
.db "CLC", 0
|
||||||
|
.db "CLH", 0
|
||||||
|
.db "CLI", 0
|
||||||
|
.db "CLN", 0
|
||||||
|
.db "CLS", 0
|
||||||
|
.db "CLT", 0
|
||||||
|
.db "CLV", 0
|
||||||
|
.db "CLZ", 0
|
||||||
|
.db "EICALL", 0
|
||||||
|
.db "EIJMP", 0
|
||||||
|
.db "ICALL", 0
|
||||||
|
.db "IJMP", 0
|
||||||
|
.db "NOP", 0
|
||||||
|
.db "RET", 0
|
||||||
|
.db "RETI", 0
|
||||||
|
.db "SEC", 0
|
||||||
|
.db "SEH", 0
|
||||||
|
.db "SEI", 0
|
||||||
|
.db "SEN", 0
|
||||||
|
.db "SES", 0
|
||||||
|
.db "SET", 0
|
||||||
|
.db "SEV", 0
|
||||||
|
.db "SEZ", 0
|
||||||
|
.db "SLEEP", 0
|
||||||
|
.db "WDR", 0
|
||||||
|
; Rd(5)
|
||||||
|
.equ I_ASR 39
|
||||||
|
.db "ASR", 0
|
||||||
|
.db "COM", 0
|
||||||
|
.db "DEC", 0
|
||||||
|
.db "INC", 0
|
||||||
|
.db "LAC", 0
|
||||||
|
.db "LAS", 0
|
||||||
|
.db "LAT", 0
|
||||||
|
.db "LSR", 0
|
||||||
|
.db "NEG", 0
|
||||||
|
.db "POP", 0
|
||||||
|
.db "PUSH", 0
|
||||||
|
.db "ROR", 0
|
||||||
|
.db "SWAP", 0
|
||||||
|
.db "XCH", 0
|
||||||
|
.db 0xff
|
||||||
|
|
||||||
|
|
||||||
|
; 8-bit constant masks associated with each instruction. In the same order as
|
||||||
|
; in instrNames
|
||||||
|
instrUpMasks1:
|
||||||
|
; Rd(5) + Rd(5): XXXXXXrd ddddrrrr
|
||||||
|
.db 0b00011100 ; ADC
|
||||||
|
.db 0b00001100 ; ADD
|
||||||
|
.db 0b00100000 ; AND
|
||||||
|
.db 0b00100100 ; CLR
|
||||||
|
.db 0b00010100 ; CP
|
||||||
|
.db 0b00000100 ; CPC
|
||||||
|
.db 0b00010000 ; CPSE
|
||||||
|
.db 0b00100100 ; EOR
|
||||||
|
.db 0b00101100 ; MOV
|
||||||
|
.db 0b10011100 ; MUL
|
||||||
|
.db 0b00101000 ; OR
|
||||||
|
.db 0b00001000 ; SBC
|
||||||
|
.db 0b00011000 ; SUB
|
||||||
|
|
||||||
|
; 16-bit constant masks associated with each instruction. In the same order as
|
||||||
|
; in instrNames
|
||||||
|
instrUpMasks2:
|
||||||
|
; no arg
|
||||||
|
.db 0b10010101, 0b10011000 ; BREAK
|
||||||
|
.db 0b10010100, 0b10001000 ; CLC
|
||||||
|
.db 0b10010100, 0b11011000 ; CLH
|
||||||
|
.db 0b10010100, 0b11111000 ; CLI
|
||||||
|
.db 0b10010100, 0b10101000 ; CLN
|
||||||
|
.db 0b10010100, 0b11001000 ; CLS
|
||||||
|
.db 0b10010100, 0b11101000 ; CLT
|
||||||
|
.db 0b10010100, 0b10111000 ; CLV
|
||||||
|
.db 0b10010100, 0b10011000 ; CLZ
|
||||||
|
.db 0b10010101, 0b00011001 ; EICALL
|
||||||
|
.db 0b10010100, 0b00011001 ; EIJMP
|
||||||
|
.db 0b10010101, 0b00001001 ; ICALL
|
||||||
|
.db 0b10010100, 0b00001001 ; IJMP
|
||||||
|
.db 0b00000000, 0b00000000 ; NOP
|
||||||
|
.db 0b10010101, 0b00001000 ; RET
|
||||||
|
.db 0b10010101, 0b00011000 ; RETI
|
||||||
|
.db 0b10010100, 0b00001000 ; SEC
|
||||||
|
.db 0b10010100, 0b01011000 ; SEH
|
||||||
|
.db 0b10010100, 0b01111000 ; SEI
|
||||||
|
.db 0b10010100, 0b00101000 ; SEN
|
||||||
|
.db 0b10010100, 0b01001000 ; SES
|
||||||
|
.db 0b10010100, 0b01101000 ; SET
|
||||||
|
.db 0b10010100, 0b00111000 ; SEV
|
||||||
|
.db 0b10010100, 0b00011000 ; SEZ
|
||||||
|
.db 0b10010101, 0b10001000 ; SLEEP
|
||||||
|
.db 0b10010101, 0b10101000 ; WDR
|
||||||
|
; Rd(5): XXXXXXXd ddddXXXX
|
||||||
|
.db 0b10010100, 0b00000101 ; ASR
|
||||||
|
.db 0b10010100, 0b00000000 ; COM
|
||||||
|
.db 0b10010100, 0b00001010 ; DEC
|
||||||
|
.db 0b10010100, 0b00000011 ; INC
|
||||||
|
.db 0b10010010, 0b00000110 ; LAC
|
||||||
|
.db 0b10010010, 0b00000101 ; LAS
|
||||||
|
.db 0b10010010, 0b00000111 ; LAT
|
||||||
|
.db 0b10010100, 0b00000110 ; LSR
|
||||||
|
.db 0b10010100, 0b00000001 ; NEG
|
||||||
|
.db 0b10010000, 0b00001111 ; POP
|
||||||
|
.db 0b10010010, 0b00001111 ; PUSH
|
||||||
|
.db 0b10010100, 0b00000111 ; ROR
|
||||||
|
.db 0b10010100, 0b00000010 ; SWAP
|
||||||
|
.db 0b10010010, 0b00000100 ; XCH
|
||||||
|
|
||||||
|
; Same signature as getInstID in instr.asm
|
||||||
|
; Reads string in (HL) and returns the corresponding ID (I_*) in A. Sets Z if
|
||||||
|
; there's a match.
|
||||||
|
getInstID:
|
||||||
|
push bc
|
||||||
|
push hl
|
||||||
|
push de
|
||||||
|
ex de, hl ; DE makes a better needle
|
||||||
|
; haystack. -1 because we inc HL at the beginning of the loop
|
||||||
|
ld hl, instrNames-1
|
||||||
|
ld b, 0xff ; index counter
|
||||||
|
.loop:
|
||||||
|
inc b
|
||||||
|
inc hl
|
||||||
|
ld a, (hl)
|
||||||
|
inc a ; check if 0xff
|
||||||
|
jr z, .notFound
|
||||||
|
call strcmpIN
|
||||||
|
jr nz, .loop
|
||||||
|
; found!
|
||||||
|
ld a, b ; index
|
||||||
|
cp a ; ensure Z
|
||||||
|
.end:
|
||||||
|
pop de
|
||||||
|
pop hl
|
||||||
|
pop bc
|
||||||
|
ret
|
||||||
|
.notFound:
|
||||||
|
dec a ; unset Z
|
||||||
|
jr .end
|
||||||
|
|
||||||
|
; Same signature as parseInstruction in instr.asm
|
||||||
|
; Parse instruction specified in A (I_* const) with args in I/O and write
|
||||||
|
; resulting opcode(s) in I/O.
|
||||||
|
; Sets Z on success. On error, A contains an error code (ERR_*)
|
||||||
|
parseInstruction:
|
||||||
|
; BC, during .spit, is ORred to the spitted opcode.
|
||||||
|
ld bc, 0
|
||||||
|
cp I_BREAK
|
||||||
|
jr c, .spitRd5Rr5
|
||||||
|
cp I_ASR
|
||||||
|
jr c, .spitNoArg
|
||||||
|
; spitRd5
|
||||||
|
ld d, a ; save A for later
|
||||||
|
call .readR5
|
||||||
|
ret nz
|
||||||
|
call .placeRd
|
||||||
|
ld a, d ; restore A
|
||||||
|
; continue to .spitNoArg
|
||||||
|
.spitNoArg:
|
||||||
|
call .getUp2
|
||||||
|
jr .spit
|
||||||
|
.spitRd5Rr5:
|
||||||
|
ld d, a ; save A for later
|
||||||
|
call .readR5
|
||||||
|
ret nz
|
||||||
|
call .placeRd
|
||||||
|
call readComma
|
||||||
|
call .readR5
|
||||||
|
ret nz
|
||||||
|
push af ; --> lvl 1
|
||||||
|
; let's start with the 4 lower bits
|
||||||
|
and 0xf
|
||||||
|
or c
|
||||||
|
; We now have our LSB in A. Let's spit it now.
|
||||||
|
call ioPutB
|
||||||
|
pop af ; <-- lvl 1
|
||||||
|
; and now that last high bit, currently bit 4, which must become bit 1
|
||||||
|
and 0b00010000
|
||||||
|
rra \ rra \ rra
|
||||||
|
or b
|
||||||
|
ld b, a
|
||||||
|
ld a, d ; restore A
|
||||||
|
ld hl, instrUpMasks1
|
||||||
|
call addHL
|
||||||
|
; now that's our MSB
|
||||||
|
jr .spitMSB
|
||||||
|
.spit:
|
||||||
|
; LSB is spit *before* MSB
|
||||||
|
inc hl
|
||||||
|
ld a, (hl)
|
||||||
|
or c
|
||||||
|
call ioPutB
|
||||||
|
dec hl
|
||||||
|
.spitMSB:
|
||||||
|
ld a, (hl)
|
||||||
|
or b
|
||||||
|
call ioPutB
|
||||||
|
xor a ; ensure Z, set success
|
||||||
|
ret
|
||||||
|
|
||||||
|
; local routines
|
||||||
|
; place number in A in BC at position .......d dddd....
|
||||||
|
; BC is assumed to be 0
|
||||||
|
.placeRd:
|
||||||
|
sla a \ rla \ rla \ rla ; last RLA might set carry
|
||||||
|
rl b
|
||||||
|
ld c, a
|
||||||
|
ret
|
||||||
|
; Fetch a 16-bit upcode specified by instr index in A and set that upcode in HL
|
||||||
|
.getUp2:
|
||||||
|
sub I_BREAK
|
||||||
|
sla a ; A * 2
|
||||||
|
ld hl, instrUpMasks2
|
||||||
|
jp addHL
|
||||||
|
|
||||||
|
; read a rXX argument and return register number in A.
|
||||||
|
; Set Z for success.
|
||||||
|
.readR5:
|
||||||
|
call readWord
|
||||||
|
ld a, (hl)
|
||||||
|
call upcase
|
||||||
|
cp 'R'
|
||||||
|
ret nz ; not a register
|
||||||
|
inc hl
|
||||||
|
call parseDecimal
|
||||||
|
ret nz
|
||||||
|
push ix \ pop hl
|
||||||
|
ld a, h
|
||||||
|
or a
|
||||||
|
ret nz ; should be zero
|
||||||
|
ld a, l
|
||||||
|
cp 32
|
||||||
|
jp nc, unsetZ ; must be < 32
|
||||||
|
; we're good!
|
||||||
|
cp a ; ensure Z
|
||||||
|
ret
|
134
apps/zasm/avr.txt
Normal file
134
apps/zasm/avr.txt
Normal file
@ -0,0 +1,134 @@
|
|||||||
|
The AVR instruction set is a bit more regular than z80's, which allows us for
|
||||||
|
simpler upcode spitting logic (simplicity which is lost when we need to take
|
||||||
|
into account all AVR models and instruction constraints on each models). This
|
||||||
|
file categorizes all available ops with their opcode signature. X means upcode
|
||||||
|
bit.
|
||||||
|
|
||||||
|
Categories are in descending order of "popularity"
|
||||||
|
|
||||||
|
Mnemonics with "*" are a bit special.
|
||||||
|
|
||||||
|
### 16-bit
|
||||||
|
|
||||||
|
## Plain
|
||||||
|
|
||||||
|
XXXX XXXX XXXX XXXX
|
||||||
|
|
||||||
|
BREAK, CLC, CLH, CLI, CLN, CLS, CLT, CLV, CLZ, EICALL, EIJMP, ELPM*, ICALL,
|
||||||
|
IJMP, NOP, RET, RETI, SEC, SEH, SEI, SEN, SES, SET, SEV, SEZ, SLEEP, SPM*, WDR
|
||||||
|
|
||||||
|
## Rd(5)
|
||||||
|
|
||||||
|
XXXX XXXd dddd XXXX
|
||||||
|
|
||||||
|
ASR, COM, DEC, ELPM*, INC, LAC, LAS, LAT, LD*, LPM*, LSR, NEG, POP, PUSH, ROR,
|
||||||
|
ST*, SWAP, XCH
|
||||||
|
|
||||||
|
## Rd(5) + Rr(5)
|
||||||
|
|
||||||
|
XXXX XXrd dddd rrrr
|
||||||
|
|
||||||
|
ADC, ADD, AND, CLR, CP, CPC, CPSE, EOR, MOV, MUL, OR, ROL*, SBC, SUB,
|
||||||
|
TST*
|
||||||
|
|
||||||
|
## k(7)
|
||||||
|
|
||||||
|
XXXX XXkk kkkk kXXX
|
||||||
|
|
||||||
|
BRCC, BRCS, BREQ, BRGE, BRHC, BRHS, BRID, BRIE, BRLO, BRLT, BRMI, BRNE, BRPL,
|
||||||
|
BRSH, BRTC, BRTS, BRVC, BRVS
|
||||||
|
|
||||||
|
## Rd(4) + K(8)
|
||||||
|
|
||||||
|
XXXX KKKK dddd KKKK
|
||||||
|
|
||||||
|
ANDI, CBR*, CPI, LDI, ORI, SBCI, SBR, SUBI
|
||||||
|
|
||||||
|
## Rd(5) + bit
|
||||||
|
|
||||||
|
XXXX XXXd dddd Xbbb
|
||||||
|
|
||||||
|
BLD, BST, SBRC, SBRS
|
||||||
|
|
||||||
|
## A(5) + bit
|
||||||
|
|
||||||
|
XXXX XXXX AAAA Abbb
|
||||||
|
|
||||||
|
CBI, SBI, SBIC, SBIS
|
||||||
|
|
||||||
|
## Rd(3) + Rr(3)
|
||||||
|
|
||||||
|
XXXX XXXX Xddd Xrrr
|
||||||
|
|
||||||
|
FMUL, FMULS, FMULSU, MULSU
|
||||||
|
|
||||||
|
## Rd(4) + Rr(4)
|
||||||
|
|
||||||
|
XXXX XXXX dddd rrrr
|
||||||
|
|
||||||
|
MOVW, MULS
|
||||||
|
|
||||||
|
## Rd(5) + A(6)
|
||||||
|
|
||||||
|
XXXX XAAd dddd AAAA
|
||||||
|
|
||||||
|
IN, OUT
|
||||||
|
|
||||||
|
## Rd(4) + k(7)
|
||||||
|
|
||||||
|
XXXX Xkkk dddd kkkk
|
||||||
|
|
||||||
|
LDS*, STS*
|
||||||
|
|
||||||
|
## Rd(2) + K
|
||||||
|
|
||||||
|
XXXX XXXX KKdd KKKK
|
||||||
|
|
||||||
|
ADIW, SBIW
|
||||||
|
|
||||||
|
## Rd(4)
|
||||||
|
|
||||||
|
XXXX XXXX dddd XXXX
|
||||||
|
|
||||||
|
SER
|
||||||
|
|
||||||
|
## K(4)
|
||||||
|
|
||||||
|
XXXX XXXX KKKK XXXX
|
||||||
|
|
||||||
|
DES
|
||||||
|
|
||||||
|
## k(12)
|
||||||
|
|
||||||
|
XXXX kkkk kkkk kkkk
|
||||||
|
|
||||||
|
RCALL, RJMP
|
||||||
|
|
||||||
|
## SREG
|
||||||
|
|
||||||
|
XXXX XXXX Xsss XXXX
|
||||||
|
|
||||||
|
BCLR, BSET
|
||||||
|
|
||||||
|
## SREG + k(7)
|
||||||
|
|
||||||
|
XXXX XXkk kkkk ksss
|
||||||
|
|
||||||
|
BRBC, BRBS
|
||||||
|
|
||||||
|
### 32-bit
|
||||||
|
|
||||||
|
## k(22)
|
||||||
|
|
||||||
|
XXXX XXXk kkkk XXXk
|
||||||
|
kkkk kkkk kkkk kkkk
|
||||||
|
|
||||||
|
CALL, JMP
|
||||||
|
|
||||||
|
## Rd(5) + k(16)
|
||||||
|
|
||||||
|
XXXX XXXd dddd XXXX
|
||||||
|
kkkk kkkk kkkk kkkk
|
||||||
|
|
||||||
|
LDS*, STS*
|
||||||
|
|
45
apps/zasm/gluea.asm
Normal file
45
apps/zasm/gluea.asm
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
; avra
|
||||||
|
;
|
||||||
|
; This glue code assembles as assembler for AVR microcontrollers. It looks a
|
||||||
|
; lot like zasm, but it spits AVR binary. Comments have been stripped, refer
|
||||||
|
; to glue.asm for details.
|
||||||
|
|
||||||
|
.inc "user.h"
|
||||||
|
|
||||||
|
; *** Overridable consts ***
|
||||||
|
.equ ZASM_REG_MAXCNT 0xff
|
||||||
|
.equ ZASM_LREG_MAXCNT 0x20
|
||||||
|
.equ ZASM_REG_BUFSZ 0x700
|
||||||
|
.equ ZASM_LREG_BUFSZ 0x100
|
||||||
|
|
||||||
|
; ******
|
||||||
|
|
||||||
|
.inc "err.h"
|
||||||
|
.inc "ascii.h"
|
||||||
|
.inc "blkdev.h"
|
||||||
|
.inc "fs.h"
|
||||||
|
jp zasmMain
|
||||||
|
|
||||||
|
.inc "core.asm"
|
||||||
|
.inc "zasm/const.asm"
|
||||||
|
.inc "lib/util.asm"
|
||||||
|
.inc "lib/ari.asm"
|
||||||
|
.inc "lib/parse.asm"
|
||||||
|
.inc "lib/args.asm"
|
||||||
|
.inc "zasm/util.asm"
|
||||||
|
.equ IO_RAMSTART USER_RAMSTART
|
||||||
|
.inc "zasm/io.asm"
|
||||||
|
.equ TOK_RAMSTART IO_RAMEND
|
||||||
|
.inc "zasm/tok.asm"
|
||||||
|
.inc "zasm/avr.asm"
|
||||||
|
.equ DIREC_RAMSTART TOK_RAMEND
|
||||||
|
.inc "zasm/directive.asm"
|
||||||
|
.inc "zasm/parse.asm"
|
||||||
|
.equ EXPR_PARSE parseNumberOrSymbol
|
||||||
|
.inc "lib/expr.asm"
|
||||||
|
.equ SYM_RAMSTART DIREC_RAMEND
|
||||||
|
.inc "zasm/symbol.asm"
|
||||||
|
.equ ZASM_RAMSTART SYM_RAMEND
|
||||||
|
.inc "zasm/main.asm"
|
||||||
|
USER_RAMSTART:
|
||||||
|
|
@ -417,26 +417,6 @@ matchArg:
|
|||||||
dec hl
|
dec hl
|
||||||
ret
|
ret
|
||||||
|
|
||||||
; Compare primary row at (DE) with ID in A. Sets Z flag if there's a match.
|
|
||||||
matchPrimaryRow:
|
|
||||||
push hl
|
|
||||||
push ix
|
|
||||||
push de \ pop ix
|
|
||||||
cp (ix)
|
|
||||||
jr nz, .end
|
|
||||||
; name matches, let's see the rest
|
|
||||||
ld hl, INS_CURARG1
|
|
||||||
ld a, (ix+1)
|
|
||||||
call matchArg
|
|
||||||
jr nz, .end
|
|
||||||
ld hl, INS_CURARG2
|
|
||||||
ld a, (ix+2)
|
|
||||||
call matchArg
|
|
||||||
.end:
|
|
||||||
pop ix
|
|
||||||
pop hl
|
|
||||||
ret
|
|
||||||
|
|
||||||
; *** Special opcodes ***
|
; *** Special opcodes ***
|
||||||
; The special upcode handling routines below all have the same signature.
|
; The special upcode handling routines below all have the same signature.
|
||||||
; Instruction row is at IX and we're expected to perform the same task as
|
; Instruction row is at IX and we're expected to perform the same task as
|
||||||
@ -574,16 +554,13 @@ handleRST:
|
|||||||
ld c, 0
|
ld c, 0
|
||||||
ret
|
ret
|
||||||
|
|
||||||
; Compute the upcode for argspec row at (DE) and arguments in curArg{1,2} and
|
; Compute the upcode for argspec row at (IX) and arguments in curArg{1,2} and
|
||||||
; writes the resulting upcode to IO.
|
; writes the resulting upcode to IO.
|
||||||
; A is zero, with Z set, on success. A is non-zero, with Z unset, on error.
|
; A is zero, with Z set, on success. A is non-zero, with Z unset, on error.
|
||||||
spitUpcode:
|
spitUpcode:
|
||||||
push ix
|
|
||||||
push de
|
push de
|
||||||
push hl
|
push hl
|
||||||
push bc
|
push bc
|
||||||
; First, let's go in IX mode. It's easier to deal with offsets here.
|
|
||||||
push de \ pop ix
|
|
||||||
|
|
||||||
; before we begin, are we in a 'l' argspec? Is it flagged for IX/IY
|
; before we begin, are we in a 'l' argspec? Is it flagged for IX/IY
|
||||||
; acceptance? If yes, a 'x' or 'y' instruction? Check this on both
|
; acceptance? If yes, a 'x' or 'y' instruction? Check this on both
|
||||||
@ -823,7 +800,6 @@ spitUpcode:
|
|||||||
pop bc
|
pop bc
|
||||||
pop hl
|
pop hl
|
||||||
pop de
|
pop de
|
||||||
pop ix
|
|
||||||
ret
|
ret
|
||||||
.checkCB:
|
.checkCB:
|
||||||
ld a, (INS_UPCODE)
|
ld a, (INS_UPCODE)
|
||||||
@ -876,7 +852,7 @@ parseInstruction:
|
|||||||
push bc
|
push bc
|
||||||
push hl
|
push hl
|
||||||
push de
|
push de
|
||||||
; A is reused in matchPrimaryRow but that register is way too changing.
|
; A is reused in .matchPrimaryRow but that register is way too changing.
|
||||||
; Let's keep a copy in a more cosy register.
|
; Let's keep a copy in a more cosy register.
|
||||||
ld c, a
|
ld c, a
|
||||||
xor a
|
xor a
|
||||||
@ -899,24 +875,24 @@ parseInstruction:
|
|||||||
; To speed up things a little, we use a poor man's indexing. Full
|
; To speed up things a little, we use a poor man's indexing. Full
|
||||||
; bisecting would involve too much complexity.
|
; bisecting would involve too much complexity.
|
||||||
ld a, c ; recall A param
|
ld a, c ; recall A param
|
||||||
ld de, instrTBl
|
ld ix, instrTBl
|
||||||
cp I_EX
|
cp I_EX
|
||||||
jr c, .loop
|
jr c, .loop
|
||||||
ld de, instrTBlEX
|
ld ix, instrTBlEX
|
||||||
cp I_LD
|
cp I_LD
|
||||||
jr c, .loop
|
jr c, .loop
|
||||||
ld de, instrTBlLD
|
ld ix, instrTBlLD
|
||||||
cp I_RET
|
cp I_RET
|
||||||
jr c, .loop
|
jr c, .loop
|
||||||
ld de, instrTBlRET
|
ld ix, instrTBlRET
|
||||||
.loop:
|
.loop:
|
||||||
ld a, c ; recall A param
|
ld a, c ; recall A param
|
||||||
call matchPrimaryRow
|
call .matchPrimaryRow
|
||||||
jr z, .match
|
jr z, .match
|
||||||
ld a, INSTR_TBL_ROWSIZE
|
ld de, INSTR_TBL_ROWSIZE
|
||||||
call addDE
|
add ix, de
|
||||||
ld a, (de)
|
ld a, 0xff
|
||||||
cp 0xff
|
cp (ix)
|
||||||
jr nz, .loop
|
jr nz, .loop
|
||||||
; No signature match
|
; No signature match
|
||||||
ld a, ERR_BAD_ARG
|
ld a, ERR_BAD_ARG
|
||||||
@ -936,6 +912,19 @@ parseInstruction:
|
|||||||
pop bc
|
pop bc
|
||||||
ret
|
ret
|
||||||
|
|
||||||
|
; Compare primary row at (IX) with ID in A. Sets Z flag if there's a match.
|
||||||
|
.matchPrimaryRow:
|
||||||
|
cp (ix)
|
||||||
|
ret nz
|
||||||
|
; name matches, let's see the rest
|
||||||
|
ld hl, INS_CURARG1
|
||||||
|
ld a, (ix+1)
|
||||||
|
call matchArg
|
||||||
|
ret nz
|
||||||
|
ld hl, INS_CURARG2
|
||||||
|
ld a, (ix+2)
|
||||||
|
jp matchArg
|
||||||
|
|
||||||
|
|
||||||
; In instruction metadata below, argument types arge indicated with a single
|
; In instruction metadata below, argument types arge indicated with a single
|
||||||
; char mnemonic that is called "argspec". This is the table of correspondence.
|
; char mnemonic that is called "argspec". This is the table of correspondence.
|
||||||
|
@ -76,6 +76,35 @@ strncmpI:
|
|||||||
; early, set otherwise)
|
; early, set otherwise)
|
||||||
ret
|
ret
|
||||||
|
|
||||||
|
; strcmp, then next. Same thing as strcmp, but case insensitive and if strings
|
||||||
|
; are not equal, make HL point to the character right after the null
|
||||||
|
; termination. We assume that the haystack (HL), has uppercase chars.
|
||||||
|
strcmpIN:
|
||||||
|
push de ; --> lvl 1
|
||||||
|
push hl ; --> lvl 2
|
||||||
|
|
||||||
|
.loop:
|
||||||
|
ld a, (de)
|
||||||
|
call upcase
|
||||||
|
cp (hl)
|
||||||
|
jr nz, .notFound ; not equal? break early.
|
||||||
|
or a ; If our chars are null, stop the cmp
|
||||||
|
jr z, .found
|
||||||
|
inc hl
|
||||||
|
inc de
|
||||||
|
jr .loop
|
||||||
|
.found:
|
||||||
|
pop hl ; <-- lvl 2
|
||||||
|
pop de ; <-- lvl 1
|
||||||
|
; Z already set
|
||||||
|
ret
|
||||||
|
.notFound:
|
||||||
|
; Not found, we skip the string
|
||||||
|
call strskip
|
||||||
|
pop de ; <-- lvl 2, junk
|
||||||
|
pop de ; <-- lvl 1
|
||||||
|
ret
|
||||||
|
|
||||||
; If string at (HL) starts with ( and ends with ), "enter" into the parens
|
; If string at (HL) starts with ( and ends with ), "enter" into the parens
|
||||||
; (advance HL and put a null char at the end of the string) and set Z.
|
; (advance HL and put a null char at the end of the string) and set Z.
|
||||||
; Otherwise, do nothing and reset Z.
|
; Otherwise, do nothing and reset Z.
|
||||||
|
1
tools/emul/.gitignore
vendored
1
tools/emul/.gitignore
vendored
@ -1,6 +1,7 @@
|
|||||||
/shell/shell
|
/shell/shell
|
||||||
/bshell/shell
|
/bshell/shell
|
||||||
/zasm/zasm
|
/zasm/zasm
|
||||||
|
/zasm/avra
|
||||||
/runbin/runbin
|
/runbin/runbin
|
||||||
/*/*-bin.h
|
/*/*-bin.h
|
||||||
/*/*.bin
|
/*/*.bin
|
||||||
|
@ -3,6 +3,7 @@ TARGETS = shell/shell zasm/zasm runbin/runbin
|
|||||||
KERNEL = ../../kernel
|
KERNEL = ../../kernel
|
||||||
APPS = ../../apps
|
APPS = ../../apps
|
||||||
ZASMBIN = zasm/zasm
|
ZASMBIN = zasm/zasm
|
||||||
|
AVRABIN = zasm/avra
|
||||||
ZASMSH = ../zasm.sh
|
ZASMSH = ../zasm.sh
|
||||||
SHELLAPPS = zasm ed
|
SHELLAPPS = zasm ed
|
||||||
SHELLTGTS = ${SHELLAPPS:%=cfsin/%}
|
SHELLTGTS = ${SHELLAPPS:%=cfsin/%}
|
||||||
@ -10,7 +11,7 @@ CFSIN_CONTENTS = $(SHELLTGTS) cfsin/user.h
|
|||||||
OBJS = emul.o libz80/libz80.o
|
OBJS = emul.o libz80/libz80.o
|
||||||
|
|
||||||
.PHONY: all
|
.PHONY: all
|
||||||
all: $(TARGETS) $(CFSIN_CONTENTS)
|
all: $(TARGETS) $(AVRABIN) $(CFSIN_CONTENTS)
|
||||||
|
|
||||||
# -o in sync with SHELL_CODE in shell/glue.asm
|
# -o in sync with SHELL_CODE in shell/glue.asm
|
||||||
shell/shell.bin: shell/glue.asm $(ZASMBIN)
|
shell/shell.bin: shell/glue.asm $(ZASMBIN)
|
||||||
@ -19,18 +20,27 @@ shell/shell.bin: shell/glue.asm $(ZASMBIN)
|
|||||||
shell/shell-bin.h: shell/shell.bin
|
shell/shell-bin.h: shell/shell.bin
|
||||||
./bin2c.sh KERNEL < shell/shell.bin | tee $@ > /dev/null
|
./bin2c.sh KERNEL < shell/shell.bin | tee $@ > /dev/null
|
||||||
|
|
||||||
|
shell/shell: shell/shell.c $(OBJS) shell/shell-bin.h
|
||||||
|
$(CC) shell/shell.c $(OBJS) -o $@
|
||||||
|
|
||||||
zasm/kernel-bin.h: zasm/kernel.bin
|
zasm/kernel-bin.h: zasm/kernel.bin
|
||||||
./bin2c.sh KERNEL < zasm/kernel.bin | tee $@ > /dev/null
|
./bin2c.sh KERNEL < zasm/kernel.bin | tee $@ > /dev/null
|
||||||
|
|
||||||
zasm/zasm-bin.h: zasm/zasm.bin
|
zasm/zasm-bin.h: zasm/zasm.bin
|
||||||
./bin2c.sh USERSPACE < zasm/zasm.bin | tee $@ > /dev/null
|
./bin2c.sh USERSPACE < zasm/zasm.bin | tee $@ > /dev/null
|
||||||
|
|
||||||
shell/shell: shell/shell.c $(OBJS) shell/shell-bin.h
|
|
||||||
$(CC) shell/shell.c $(OBJS) -o $@
|
|
||||||
|
|
||||||
$(ZASMBIN): zasm/zasm.c $(OBJS) zasm/kernel-bin.h zasm/zasm-bin.h $(CFSPACK)
|
$(ZASMBIN): zasm/zasm.c $(OBJS) zasm/kernel-bin.h zasm/zasm-bin.h $(CFSPACK)
|
||||||
$(CC) zasm/zasm.c $(OBJS) -o $@
|
$(CC) zasm/zasm.c $(OBJS) -o $@
|
||||||
|
|
||||||
|
zasm/avra.bin: $(ZASMBIN)
|
||||||
|
$(ZASMSH) $(KERNEL) $(APPS) zasm/user.h < $(APPS)/zasm/gluea.asm > $@
|
||||||
|
|
||||||
|
zasm/avra-bin.h: zasm/avra.bin
|
||||||
|
./bin2c.sh USERSPACE < zasm/avra.bin | tee $@ > /dev/null
|
||||||
|
|
||||||
|
$(AVRABIN): zasm/zasm.c $(OBJS) zasm/kernel-bin.h zasm/avra-bin.h
|
||||||
|
$(CC) -D AVRA zasm/zasm.c $(OBJS) -o $@
|
||||||
|
|
||||||
runbin/runbin: runbin/runbin.c $(OBJS)
|
runbin/runbin: runbin/runbin.c $(OBJS)
|
||||||
$(CC) runbin/runbin.c $(OBJS) -o $@
|
$(CC) runbin/runbin.c $(OBJS) -o $@
|
||||||
|
|
||||||
@ -52,7 +62,7 @@ cfsin/user.h: shell/user.h
|
|||||||
cp shell/user.h $@
|
cp shell/user.h $@
|
||||||
|
|
||||||
.PHONY: updatebootstrap
|
.PHONY: updatebootstrap
|
||||||
updatebootstrap: $(ZASMBIN) $(INCCFS)
|
updatebootstrap: $(ZASMBIN)
|
||||||
$(ZASMSH) $(KERNEL) < zasm/glue.asm > zasm/kernel.bin
|
$(ZASMSH) $(KERNEL) < zasm/glue.asm > zasm/kernel.bin
|
||||||
$(ZASMSH) $(KERNEL) $(APPS) zasm/user.h < $(APPS)/zasm/glue.asm > zasm/zasm.bin
|
$(ZASMSH) $(KERNEL) $(APPS) zasm/user.h < $(APPS)/zasm/glue.asm > zasm/zasm.bin
|
||||||
|
|
||||||
|
@ -60,6 +60,12 @@ Those binaries can be updated with the `make updatebootstrap` command. If they
|
|||||||
are up-to date and that zasm isn't broken, this command should output the same
|
are up-to date and that zasm isn't broken, this command should output the same
|
||||||
binary as before.
|
binary as before.
|
||||||
|
|
||||||
|
## avra
|
||||||
|
|
||||||
|
In the `zasm` folder, there's also `avra` which is a zasm compiled as an AVR
|
||||||
|
assembler. It works the same way as zasm except it expects AVR mnemonics and
|
||||||
|
spits AVR binaries.
|
||||||
|
|
||||||
## runbin
|
## runbin
|
||||||
|
|
||||||
This is a very simple tool that reads binary z80 code from stdin, loads it in
|
This is a very simple tool that reads binary z80 code from stdin, loads it in
|
||||||
|
@ -3,7 +3,11 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include "../emul.h"
|
#include "../emul.h"
|
||||||
#include "kernel-bin.h"
|
#include "kernel-bin.h"
|
||||||
|
#ifdef AVRA
|
||||||
|
#include "avra-bin.h"
|
||||||
|
#else
|
||||||
#include "zasm-bin.h"
|
#include "zasm-bin.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
/* zasm reads from a specified blkdev, assemble the file and writes the result
|
/* 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
|
* in another specified blkdev. In our emulator layer, we use stdin and stdout
|
||||||
|
@ -3,9 +3,10 @@ CFSPACK = ../cfspack/cfspack
|
|||||||
|
|
||||||
.PHONY: run
|
.PHONY: run
|
||||||
run:
|
run:
|
||||||
$(MAKE) -C $(EMULDIR) zasm/zasm runbin/runbin shell/shell
|
$(MAKE) -C $(EMULDIR) zasm/zasm zasm/avra runbin/runbin shell/shell
|
||||||
cd unit && ./runtests.sh
|
cd unit && ./runtests.sh
|
||||||
cd zasm && ./runtests.sh
|
cd zasm && ./runtests.sh
|
||||||
|
cd avra && ./runtests.sh
|
||||||
cd shell && ./runtests.sh
|
cd shell && ./runtests.sh
|
||||||
|
|
||||||
$(CFSPACK):
|
$(CFSPACK):
|
||||||
|
28
tools/tests/avra/runtests.sh
Executable file
28
tools/tests/avra/runtests.sh
Executable file
@ -0,0 +1,28 @@
|
|||||||
|
#!/bin/sh -e
|
||||||
|
|
||||||
|
AVRA=../../emul/zasm/avra
|
||||||
|
|
||||||
|
cmpas() {
|
||||||
|
FN=$1
|
||||||
|
EXPECTED=$(xxd ${FN%.*}.expected)
|
||||||
|
ACTUAL=$(cat ${FN} | $AVRA | xxd)
|
||||||
|
if [ "$ACTUAL" = "$EXPECTED" ]; then
|
||||||
|
echo ok
|
||||||
|
else
|
||||||
|
echo actual
|
||||||
|
echo "$ACTUAL"
|
||||||
|
echo expected
|
||||||
|
echo "$EXPECTED"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
if [ ! -z $1 ]; then
|
||||||
|
cmpas $1
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
for fn in *.asm; do
|
||||||
|
echo "Comparing ${fn}"
|
||||||
|
cmpas $fn
|
||||||
|
done
|
5
tools/tests/avra/test1.asm
Normal file
5
tools/tests/avra/test1.asm
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
add r1, r31
|
||||||
|
ret
|
||||||
|
sleep
|
||||||
|
break
|
||||||
|
asr r20
|
1
tools/tests/avra/test1.expected
Normal file
1
tools/tests/avra/test1.expected
Normal file
@ -0,0 +1 @@
|
|||||||
|
•ˆ•˜•E•
|
@ -1,4 +1,6 @@
|
|||||||
#!/bin/sh -e
|
#!/usr/bin/env bash
|
||||||
|
set -e
|
||||||
|
# TODO: find POSIX substitute to that PIPESTATUS thing
|
||||||
|
|
||||||
BASE=../../..
|
BASE=../../..
|
||||||
TOOLS=../..
|
TOOLS=../..
|
||||||
|
@ -46,15 +46,15 @@ runTests:
|
|||||||
halt
|
halt
|
||||||
|
|
||||||
testSpitUpcode:
|
testSpitUpcode:
|
||||||
ld ix, .t1
|
ld iy, .t1
|
||||||
call .test
|
call .test
|
||||||
ld ix, .t2
|
ld iy, .t2
|
||||||
call .test
|
call .test
|
||||||
ld ix, .t3
|
ld iy, .t3
|
||||||
call .test
|
call .test
|
||||||
ld ix, .t4
|
ld iy, .t4
|
||||||
call .test
|
call .test
|
||||||
ld ix, .t5
|
ld iy, .t5
|
||||||
call .test
|
call .test
|
||||||
ret
|
ret
|
||||||
|
|
||||||
@ -66,36 +66,36 @@ testSpitUpcode:
|
|||||||
ld (SPITBOWL+1), a
|
ld (SPITBOWL+1), a
|
||||||
ld (SPITBOWL+2), a
|
ld (SPITBOWL+2), a
|
||||||
ld (SPITBOWL+3), a
|
ld (SPITBOWL+3), a
|
||||||
push ix \ pop de
|
push iy \ pop ix
|
||||||
call intoDE
|
call intoIX
|
||||||
ld a, (ix+2)
|
ld a, (iy+2)
|
||||||
ld (INS_CURARG1), a
|
ld (INS_CURARG1), a
|
||||||
ld a, (ix+3)
|
ld a, (iy+3)
|
||||||
ld (INS_CURARG1+1), a
|
ld (INS_CURARG1+1), a
|
||||||
ld a, (ix+4)
|
ld a, (iy+4)
|
||||||
ld (INS_CURARG1+2), a
|
ld (INS_CURARG1+2), a
|
||||||
ld a, (ix+5)
|
ld a, (iy+5)
|
||||||
ld (INS_CURARG2), a
|
ld (INS_CURARG2), a
|
||||||
ld a, (ix+6)
|
ld a, (iy+6)
|
||||||
ld (INS_CURARG2+1), a
|
ld (INS_CURARG2+1), a
|
||||||
ld a, (ix+7)
|
ld a, (iy+7)
|
||||||
ld (INS_CURARG2+2), a
|
ld (INS_CURARG2+2), a
|
||||||
call spitUpcode
|
call spitUpcode
|
||||||
jp nz, fail
|
jp nz, fail
|
||||||
ld a, (SPITCNT)
|
ld a, (SPITCNT)
|
||||||
cp (ix+8)
|
cp (iy+8)
|
||||||
jp nz, fail
|
jp nz, fail
|
||||||
ld a, (SPITBOWL)
|
ld a, (SPITBOWL)
|
||||||
cp (ix+9)
|
cp (iy+9)
|
||||||
jp nz, fail
|
jp nz, fail
|
||||||
ld a, (SPITBOWL+1)
|
ld a, (SPITBOWL+1)
|
||||||
cp (ix+10)
|
cp (iy+10)
|
||||||
jp nz, fail
|
jp nz, fail
|
||||||
ld a, (SPITBOWL+2)
|
ld a, (SPITBOWL+2)
|
||||||
cp (ix+11)
|
cp (iy+11)
|
||||||
jp nz, fail
|
jp nz, fail
|
||||||
ld a, (SPITBOWL+3)
|
ld a, (SPITBOWL+3)
|
||||||
cp (ix+12)
|
cp (iy+12)
|
||||||
jp nz, fail
|
jp nz, fail
|
||||||
jp nexttest
|
jp nexttest
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user