1
0
mirror of https://github.com/hsoft/collapseos.git synced 2024-11-02 18:10:55 +11:00

Compare commits

...

2 Commits

Author SHA1 Message Date
Virgil Dupras
aa8df95f7d Add "avr/" includes folder
Also, add a "real world" example in AVRA tests, a blink program on
a ATtiny45. Some instructions are commented out because they aren't
implemented yet, but not many.

The output of the program has been verified against AVRA's own
output.
2019-12-15 09:38:01 -05:00
Virgil Dupras
64935d8b40 avra: add IN and OUT instructions 2019-12-15 08:43:59 -05:00
14 changed files with 261 additions and 23 deletions

View File

@ -62,8 +62,12 @@ instrNames:
.equ I_RCALL 42 .equ I_RCALL 42
.db "RCALL", 0 .db "RCALL", 0
.db "RJMP", 0 .db "RJMP", 0
.equ I_IN 44
.db "IN", 0
.equ I_OUT 45
.db "OUT", 0
; no arg (from here, instrUpMasks2) ; no arg (from here, instrUpMasks2)
.equ I_BREAK 44 .equ I_BREAK 46
.db "BREAK", 0 .db "BREAK", 0
.db "CLC", 0 .db "CLC", 0
.db "CLH", 0 .db "CLH", 0
@ -91,7 +95,7 @@ instrNames:
.db "SLEEP", 0 .db "SLEEP", 0
.db "WDR", 0 .db "WDR", 0
; Rd(5) ; Rd(5)
.equ I_ASR 70 .equ I_ASR 72
.db "ASR", 0 .db "ASR", 0
.db "COM", 0 .db "COM", 0
.db "DEC", 0 .db "DEC", 0
@ -143,6 +147,9 @@ instrUpMasks1:
; k(12): XXXXkkkk kkkkkkkk ; k(12): XXXXkkkk kkkkkkkk
.db 0b11010000 ; RCALL .db 0b11010000 ; RCALL
.db 0b11000000 ; RJMP .db 0b11000000 ; RJMP
; IN and OUT
.db 0b10110000 ; IN
.db 0b10111000 ; OUT
; 16-bit constant masks associated with each instruction. In the same order as ; 16-bit constant masks associated with each instruction. In the same order as
; in instrNames ; in instrNames
@ -239,8 +246,11 @@ parseInstruction:
jr c, .spitRdK8 jr c, .spitRdK8
cp I_RCALL cp I_RCALL
jr c, .spitRdBit jr c, .spitRdBit
cp I_BREAK cp I_IN
jr c, .spitK12 jr c, .spitK12
jp z, .spitIN
cp I_OUT
jp z, .spitOUT
cp I_ASR cp I_ASR
jr c, .spitNoArg jr c, .spitNoArg
; spitRd5 ; spitRd5
@ -273,7 +283,7 @@ parseInstruction:
ld b, a ld b, a
call .getUp1 call .getUp1
; now that's our MSB ; now that's our MSB
jr .spitMSB jp .spitMSB
.spitRdK8: .spitRdK8:
ld ix, argSpecs+6 ; 'r', 8 ld ix, argSpecs+6 ; 'r', 8
@ -293,7 +303,7 @@ parseInstruction:
rra \ rra \ rra \ rra rra \ rra \ rra \ rra
ld b, a ld b, a
call .getUp1 call .getUp1
jr .spitMSB jp .spitMSB
.spitRdBit: .spitRdBit:
ld ix, argSpecs+8 ; 'R', 'b' ld ix, argSpecs+8 ; 'R', 'b'
@ -337,6 +347,36 @@ parseInstruction:
or b or b
jp ioPutB jp ioPutB
.spitOUT:
ld ix, argSpecs+12 ; 'A', 'R'
call _parseArgs
ret nz
ld a, h
ld h, l
ld l, a
jr .spitINOUT
.spitIN:
ld ix, argSpecs+14 ; 'R', 'A'
call _parseArgs
ret nz
.spitINOUT:
; Rd in H, A in L
ld a, h
call .placeRd
ld a, l
and 0xf
or c
; LSB ready
call ioPutB
; The two high bits of A go in bits 3:1 of MSB
ld a, l
rra \ rra \ rra
and 0b110
or b
ld b, a
; MSB is almost ready
call .getUp1
jr .spitMSB
.spit: .spit:
; LSB is spit *before* MSB ; LSB is spit *before* MSB
inc hl inc hl
@ -449,6 +489,8 @@ argSpecs:
.db 'r', 8 ; Rd(4) + K(8) .db 'r', 8 ; Rd(4) + K(8)
.db 'R', 'b' ; Rd(5) + bit .db 'R', 'b' ; Rd(5) + bit
.db 'b', 7 ; bit + k(7) .db 'b', 7 ; bit + k(7)
.db 'A', 'R' ; A(6) + Rr(5)
.db 'R', 'A' ; Rd(5) + A(6)
; Parse arguments in (HL) according to specs in IX ; Parse arguments in (HL) according to specs in IX
; Puts the results in HL (which is not needed anymore after the parsing). ; Puts the results in HL (which is not needed anymore after the parsing).
@ -493,25 +535,44 @@ _parseArgs:
jr z, _readR4 jr z, _readR4
cp 'b' cp 'b'
jr z, _readBit jr z, _readBit
cp 'A'
jr z, _readA6
cp 7 cp 7
jr z, _readk7 jr z, _readk7
cp 8 cp 8
jr z, _readK8 jr z, _readK8
ret ; something's wrong ret ; something's wrong
_readBit: ; Read expr and return success only if result in under number given in A
; Z for success
_readExpr:
push ix push ix
push bc
ld b, a
call parseExpr call parseExpr
ld a, 7 jr nz, .end
ld a, b
call _IX2A call _IX2A
jr nz, .end jr nz, .end
or c or c
ld c, a ld c, a
cp a ; ensure Z cp a ; ensure Z
.end: .end:
pop bc
pop ix pop ix
ret ret
_readBit:
ld a, 7
jr _readExpr
_readA6:
ld a, 0x3f
_readK8:
ld a, 0xff
jr _readExpr
_readk7: _readk7:
push hl push hl
push de push de
@ -549,16 +610,6 @@ _readk7:
call unsetZ call unsetZ
jr .end jr .end
_readK8:
push ix
call parseExpr
jr nz, .end
ld a, 0xff
call _IX2A
.end:
pop ix
ret
_readR4: _readR4:
call _readR5 call _readR5
ret nz ret nz

16
avr/README.md Normal file
View File

@ -0,0 +1,16 @@
# AVR include files
This folder contains header files that can be included in AVR assembly code.
These definitions are organized in a manner that is very similar to other
modern AVR assemblers, but most bits definitions (`PINB4`, `WGM01`, etc.) are
absent. This is because there's a lot of them, each symbol takes memory during
assembly and machines doing the assembling might be tight in memory. AVR code
post collapse will have to take the habit of using numerical masks accompanied
by comments describing associated symbols.
To avoid repeats, those includes are organized in 3 levels. First, there's the
`avr.h` file containing definitions common to all AVR models. Then, there's the
"family" file containing definitions common to a "family" (for example, the
ATtiny 25/45/85). Those definitions are the beefiests. Then, there's the exact
model file, which will typically contain RAM and Flash boundaries.

17
avr/avr.h Normal file
View File

@ -0,0 +1,17 @@
; *** CPU registers aliases ***
.equ XH 27
.equ XL 26
.equ YH 29
.equ YL 28
.equ ZH 31
.equ ZL 30
.equ SREG_C 0 ; Carry Flag
.equ SREG_Z 1 ; Zero Flag
.equ SREG_N 2 ; Negative Flag
.equ SREG_V 3 ; Two's Complement Overflow Flag
.equ SREG_S 4 ; Sign Bit
.equ SREG_H 5 ; Half Carry Flag
.equ SREG_T 6 ; Bit Copy Storage
.equ SREG_I 7 ; Global Interrupt Enable

10
avr/tn25.h Normal file
View File

@ -0,0 +1,10 @@
.equ FLASHEND 0x03ff ; Note: Word address
.equ IOEND 0x003f
.equ SRAM_START 0x0060
.equ SRAM_SIZE 128
.equ RAMEND 0x00df
.equ XRAMEND 0x0000
.equ E2END 0x007f
.equ EEPROMEND 0x007f
.equ EEADRBITS 7

74
avr/tn254585.h Normal file
View File

@ -0,0 +1,74 @@
; *** Registers ***
.equ SREG 0x3f
.equ SPH 0x3e
.equ SPL 0x3d
.equ GIMSK 0x3b
.equ GIFR 0x3a
.equ TIMSK 0x39
.equ TIFR 0x38
.equ SPMCSR 0x37
.equ MCUCR 0x35
.equ MCUSR 0x34
.equ TCCR0B 0x33
.equ TCNT0 0x32
.equ OSCCAL 0x31
.equ TCCR1 0x30
.equ TCNT1 0x2f
.equ OCR1A 0x2e
.equ OCR1C 0x2d
.equ GTCCR 0x2c
.equ OCR1B 0x2b
.equ TCCR0A 0x2a
.equ OCR0A 0x29
.equ OCR0B 0x28
.equ PLLCSR 0x27
.equ CLKPR 0x26
.equ DT1A 0x25
.equ DT1B 0x24
.equ DTPS 0x23
.equ DWDR 0x22
.equ WDTCR 0x21
.equ PRR 0x20
.equ EEARH 0x1f
.equ EEARL 0x1e
.equ EEDR 0x1d
.equ EECR 0x1c
.equ PORTB 0x18
.equ DDRB 0x17
.equ PINB 0x16
.equ PCMSK 0x15
.equ DIDR0 0x14
.equ GPIOR2 0x13
.equ GPIOR1 0x12
.equ GPIOR0 0x11
.equ USIBR 0x10
.equ USIDR 0x0f
.equ USISR 0x0e
.equ USICR 0x0d
.equ ACSR 0x08
.equ ADMUX 0x07
.equ ADCSRA 0x06
.equ ADCH 0x05
.equ ADCL 0x04
.equ ADCSRB 0x03
; *** Interrupt vectors ***
.equ INT0addr 0x0001 ; External Interrupt 0
.equ PCI0addr 0x0002 ; Pin change Interrupt Request 0
.equ OC1Aaddr 0x0003 ; Timer/Counter1 Compare Match 1A
.equ OVF1addr 0x0004 ; Timer/Counter1 Overflow
.equ OVF0addr 0x0005 ; Timer/Counter0 Overflow
.equ ERDYaddr 0x0006 ; EEPROM Ready
.equ ACIaddr 0x0007 ; Analog comparator
.equ ADCCaddr 0x0008 ; ADC Conversion ready
.equ OC1Baddr 0x0009 ; Timer/Counter1 Compare Match B
.equ OC0Aaddr 0x000a ; Timer/Counter0 Compare Match A
.equ OC0Baddr 0x000b ; Timer/Counter0 Compare Match B
.equ WDTaddr 0x000c ; Watchdog Time-out
.equ USI_STARTaddr 0x000d ; USI START
.equ USI_OVFaddr 0x000e ; USI Overflow
.equ INT_VECTORS_SIZE 15 ; size in words

9
avr/tn45.h Normal file
View File

@ -0,0 +1,9 @@
.equ FLASHEND 0x07ff ; Note: Word address
.equ IOEND 0x003f
.equ SRAM_START 0x0060
.equ SRAM_SIZE 256
.equ RAMEND 0x015f
.equ XRAMEND 0x0000
.equ E2END 0x00ff
.equ EEPROMEND 0x00ff
.equ EEADRBITS 8

9
avr/tn85.h Normal file
View File

@ -0,0 +1,9 @@
.equ FLASHEND 0x0fff ; Note: Word address
.equ IOEND 0x003f
.equ SRAM_START 0x0060
.equ SRAM_SIZE 512
.equ RAMEND 0x025f
.equ XRAMEND 0x0000
.equ E2END 0x01ff
.equ EEPROMEND 0x01ff
.equ EEADRBITS 9

View File

@ -0,0 +1,43 @@
; TODO: implement instructions that are commented out
; REGISTER USAGE
;
; R1: overflow counter
; R16: tmp stuff
.inc "avr.h"
.inc "tn254585.h"
.inc "tn45.h"
main:
ldi r16, RAMEND&0xff
out SPL, r16
ldi r16, RAMEND}8
out SPH, r16
;sbi DDRB, 0
;cbi PORTB, 0
; To have a blinking delay that's visible, we have to prescale a lot.
; The maximum prescaler is 1024, which makes our TCNT0 increase
; 976 times per second, which means that it overflows 4 times per
; second.
in r16, TCCR0B
ori r16, 0x05 ; CS00 + CS02 = 1024 prescaler
out TCCR0B, r16
;clr r1
loop:
in r16, TIFR ; TIFR0
sbrc r16, 1 ; is TOV0 flag clear?
rcall toggle
rjmp loop
toggle:
ldi r16, 0b00000010 ; TOV0
out TIFR, R16
inc r1
;cbi PORTB, 0
sbrs r1, 1 ; if LED is on
;sbi PORTB, 0
ret

View File

@ -0,0 +1 @@
å ¿à¿·`¿·ýÐüÏà¿þ

View File

@ -1,11 +1,12 @@
#!/bin/sh -e #!/bin/sh -e
AVRA=../../emul/zasm/avra ZASM=../../zasm.sh
AVRINC=../../../avr
cmpas() { cmpas() {
FN=$1 FN=$1
EXPECTED=$(xxd ${FN%.*}.expected) EXPECTED=$(xxd ${FN%.*}.expected)
ACTUAL=$(cat ${FN} | $AVRA | xxd) ACTUAL=$(cat ${FN} | "${ZASM}" -a "${AVRINC}" | xxd)
if [ "$ACTUAL" = "$EXPECTED" ]; then if [ "$ACTUAL" = "$EXPECTED" ]; then
echo ok echo ok
else else

View File

@ -12,3 +12,5 @@ sbrs r1, 3
rjmp foo rjmp foo
rcall baz rcall baz
baz: baz:
out 0x2e, r12
in r0, 0x9

Binary file not shown.

View File

@ -6,15 +6,22 @@
# binary. For example, "zasm.sh -o 4f < foo.asm" assembles foo.asm as if it # binary. For example, "zasm.sh -o 4f < foo.asm" assembles foo.asm as if it
# started with the line ".org 0x4f00". # started with the line ".org 0x4f00".
# The -a flag makes us switch to the AVR assembler
# 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'))")
DIR=$(dirname "${ABS_PATH}")
ZASMBIN="${DIR}/emul/zasm/zasm"
usage() { echo "Usage: $0 [-o <hexorg>] <paths-to-include>..." 1>&2; exit 1; } usage() { echo "Usage: $0 [-a] [-o <hexorg>] <paths-to-include>..." 1>&2; exit 1; }
org='00' org='00'
while getopts ":o:" opt; do while getopts ":ao:" opt; do
case "${opt}" in case "${opt}" in
a)
ZASMBIN="${DIR}/emul/zasm/avra"
;;
o) o)
org=${OPTARG} org=${OPTARG}
;; ;;
@ -26,8 +33,6 @@ done
shift $((OPTIND-1)) 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}")
ZASMBIN="${DIR}/emul/zasm/zasm"
CFSPACK="${DIR}/cfspack/cfspack" CFSPACK="${DIR}/cfspack/cfspack"
INCCFS=$(mktemp) INCCFS=$(mktemp)