📄 cruntime.s90
字号:
extern _true,_false,?cmp
public _ult,_ugt,_uge,_ule
; Unsigned integer less than
_ult rcall ?cmp
brsh _false
rjmp _true
_ugt rcall ?cmp
brlo _false
breq _false
rjmp _true
_uge rcall ?cmp
brlo _false
rjmp _true
_ule rcall ?cmp
brlo _true
breq _true
rjmp _false
endmod
;------------------------------------------------------------
; Commons
module cmp
rseg scode
public ?cmp
?cmp sub r26,r30
sbc r27,r31
ret
endmod
;------------------------------------------------------------
module tf
rseg scode
public _false,_true
_false clr r30
rjmp _condx
_true ldi r30,1
_condx clr r31
ret
endmod
;------------------------------------------------------------
module lcmp
rseg scode
public _cmp_l
_cmp_l sub r22,r26
sbc r23,r27
sbc r24,r30
sbc r25,r31
ret
endmod
;------------------------------------------------------------
; Case
module case
rseg scode
public _case
; standard C case statement
_case mov r25,r31 ; save switch value
mov r24,r30
ld r31,y+ ; get table address
ld r30,y+
_cs1 rcall _cs4 ; get case value into Y
cp r26,r24 ; compare
cpc r27,r25
brne _cs2
rcall _cs4 ; get case label
breq _cs3 ; end, go to default
mov r31,r27
mov r30,r26
_cs1a asr r31
ror r30
ijmp ; jump to respective case
_cs2 rcall _cs4 ; get case label
brne _cs1 ; do next case
; default jump
_cs3 sbiw r30,4
lpm
mov r25,r0
adiw r30,1
lpm
mov r31,r0
mov r30,r25
rjmp _cs1a
; load from table
_cs4 lpm
mov r26,r0
adiw r30,1
lpm
mov r27,r0
adiw r30,1 ; read for next
or r0,r26
ret
endmod
;------------------------------------------------------------
; Divide by zero check
module dcheck
rseg scode
public _CheckDivZero
_CheckDivZero
clr r31
clr r30
sbrc r0,1
adiw r30,1
ret
endmod
;------------------------------------------------------------
; Long multiply & divide
module muldiv32
rseg scode
public _mul_l,_umul_l,_div_l,_udiv_l
extern _neg_l
_umul_l rcall _m32
ret
_udiv_l rcall _d32
ret
_mul_l rcall _lchksn
rcall _m32
_lmd1 sbrc r0,0
rcall _dolneg
ret
_div_l rcall _lchksn
rcall _d32
bld r0,1
rjmp _lmd1
;------------------------------------------------------------
; 32-bit multiply.
; Enter with 32-bit multiplier in r25-22, 32-bit multiplicand in r31-26.
; Returns with 32-bit result in r31-26, overflow in r25-22.
_m32 push r29
mov r21,r25 ; copy multiplicand into r21-18
mov r20,r24
mov r19,r23
mov r18,r22
clr r25 ; clear product low (r25-22)
clr r24
clr r23
clr r22
ldi r29,33 ; make a counter
clc ; clear carry
rjmp _m32c
_m32a brcc _m32b ; skip if no bit
add r22,r18 ; add multiplicand to partial product
adc r23,r19
adc r24,r20
adc r25,r21
_m32b lsr r25 ; right shift partial product
ror r24
ror r23
ror r22
_m32c ror r31 ; right shift multiplier into carry
ror r30
ror r27
ror r26
dec r29 ; all done
brne _m32a ; yes
pop r29
ret
;------------------------------------------------------------
; 32-bit divide.
; Enter with 32-bit dividend in r25-22, 32-bit divisor in r31-26.
; Returns with 32-bit result in r31-26, remainder in r25-22.
_d32 push r29
mov r21,r31 ; copy divisor into r21-18
mov r20,r30
mov r19,r27
mov r18,r26
clt
or r26,r27 ; check for zero divisor
or r26,r30
or r26,r31
brne _d32aa
set ; T will be set for divide by zero
ret
_d32aa mov r31,r25 ; copy dividend into r31-26
mov r30,r24
mov r27,r23
mov r26,r22
clr r25 ; clear
clr r24
clr r23
clr r22
ldi r29,32 ; make a counter
_d32a lsl r26 ; left shift dividend into remainder
rol r27
rol r30
rol r31
rol r22
rol r23
rol r24
rol r25
sub r22,r18 ; subtract r21-18 from r25-22
sbc r23,r19 ; answer in r25-22
sbc r24,r20
sbc r25,r21
sbr r26,1 ; assume positive, so set result bit
brcc _d32b ; jump if result positive
add r22,r18 ; negative, restore result
adc r23,r19
adc r24,r20
adc r25,r21
cbr r26,1 ; and clear result bit
_d32b dec r29 ; all done?
brne _d32a ; ..no
pop r29
ret
;------------------------------------------------------------
; Negate the numbers in r31-28 and r25-22
_dolneg rcall _neg_l
rcall _negb_l
ret
;------------------------------------------------------------
; Negate the 4-byte number in r25-22
_negb_l clt
sbrs r25,7
ret
com r22
com r23
com r24
com r25
subi r22,0xff
sbci r23,0xff
sbci r24,0xff
sbci r25,0xff
set
ret
;------------------------------------------------------------
_lchksn clr r0
clt
sbrs r31,7
rjmp _lchs1
rcall _neg_l
set
_lchs1 bld r0,0
rcall _negb_l
bld r1,0
eor r0,r1
ret
endmod
;------------------------------------------------------------
; Long overflow check
module mchecklong
rseg scode
public _CheckLongOverflow
; Returns Z non-zero if overflow
_CheckLongOverflow
clr r31
clr r30
or r30,r25
or r30,r24
or r30,r23
or r30,r22
ret
endmod
;------------------------------------------------------------
; Return Long Overflow
module getlongovf
rseg scode
public _GetLongOverflow
_GetLongOverflow
mov r31,r25
mov r30,r24
mov r27,r23
mov r26,r22
ret
endmod
;------------------------------------------------------------
; 16-bit Multiply & divide
module muldiv
rseg scode
public _mul,_umul,_div,_udiv
extern _neg
_umul clr r0
clt
rcall _m16
rjmp _md1a
_udiv clr r0
clt
rcall _d16
ret
_mul rcall _chksn
rcall _m16
_md1 sbrc r0,0
rcall _doneg
_md1a or r26,r27 ; check for overflow
breq _md2
set
_md2 ret
_div rcall _chksn
rcall _d16
bld r0,1
rjmp _md1
_chksn clr r0
clt
sbrs r31,7
rjmp _chks1
rcall _neg
set
_chks1 bld r0,0
rcall _negb
bld r1,0
eor r0,r1
ret
;------------------------------------------------------------
; 16-bit divide.
; Enter with 16-bit dividend in r27-26, 16-bit divisor in r31-30.
; Returns with 16-bit result in r31-30, remainder in r27-26.
_d16 mov r25,r31 ; copy divisor into r25-24
mov r24,r30
clt
or r30,r31 ; check for zero divisor
brne _d16aa
set ; T will be set for divide by zero
ret
_d16aa mov r31,r27 ; copy dividend into r31-30
mov r30,r26
clr r27 ; clear
clr r26
ldi r23,16 ; make a counter
_d16a lsl r30 ; left shift dividend into remainder
rol r31
rol r26
rol r27
sub r26,r24 ; subtract r25-24 from r26-27
sbc r27,r25 ; answer in r26-27
sbr r30,1 ; assume positive, so set result bit
brcc _d16b ; jump if result positive
add r26,r24 ; negative, restore result
adc r27,r25
cbr r30,1 ; and clear result bit
_d16b dec r23 ; all done?
brne _d16a ; ..no
ret
;------------------------------------------------------------
; 16-bit multiply.
; Enter with 16-bit multiplier in r27-26, 16-bit multiplicand in r31-30.
; Returns with 16-bit result in r31-30, overflow in r27-r26.
_m16 mov r25,r27 ; copy multiplicand into r21-18
mov r24,r26
clr r27 ; clear product low (X)
clr r26
ldi r23,17 ; make a counter
clc ; clear carry
rjmp _m16c
_m16a brcc _m16b ; skip if no bit
add r26,r24 ; add multiplicand to partial product
adc r27,r25
_m16b lsr r27 ; right shift partial product
ror r26
_m16c ror r31 ; right shift multiplier into carry
ror r30
dec r23 ; all done
brne _m16a ; yes
ret
;------------------------------------------------------------
; Negate the number in Y
_negb clt
sbrs r27,7
ret
com r26
com r27
adiw r26,1
set
ret
;------------------------------------------------------------
; Negate the numbers in Z and Y if required
_doneg rcall _neg
rcall _negb
ret
endmod
;------------------------------------------------------------
; Int overflow check
module mcheckint
rseg scode
public _CheckIntOverflow
_CheckIntOverflow
clr r31
or r30,r27
or r30,r26
_cloi ret
endmod
;------------------------------------------------------------
; String copy from prom
module romcpy
rseg scode
public _romcpy
_romcpy ldd r31,y+0
ldd r30,y+1
ldd r0,y+2
ldd r26,y+3
mov r27,r0 ; X dest, Z source
_romcpy1
lpm
st x+,r0
adiw r30,1
tst r0
brne _romcpy1
ret
endmod
;------------------------------------------------------------
; I/O Functions
module in ; x = inp(port)
rseg scode
public _inp
_inp ldd r30,y+1 ; port address
clr r31
ldd r30,z+32 ; input
ret
endmod
;------------------------------------------------------------
module out ; outp(port,val)
rseg scode
public _outp
_outp ldd r26,y+1 ; port value
ldd r30,y+3 ; port address
clr r31
std z+32,r26
ret
endmod
;------------------------------------------------------------
module sbi ; sbip(port,val)
rseg scode
extern ?posn
public _sbip
_sbip rcall ?posn
or r27,r26
std z+32,r27
ret
endmod
;------------------------------------------------------------
module cbi ; cbip(port,val)
rseg scode
extern ?posn
public _cbip
_cbip rcall ?posn
com r27
and r27,r26
std z+32,r27
ret
endmod
;------------------------------------------------------------
module posn
rseg scode
public ?posn
?posn ldd r26,y+1 ; value
ldd r30,y+3 ; port address
clr r31
ldi r27,1
tst r26
_posn1 breq _posn2
lsl r27
dec r26
rjmp _posn1
_posn2 ldd r26,z+32
ret
end
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -