2010年2月2日火曜日

ATTiny2313 モニタ用 SerialSlave

シリアル端末で,RAM(レジスタ,I/Oポート)/プログラムメモリの読み書きができるモニタプログラム.ただしプログラムメモリの書き込みは,まだ「未実装.」
AVRはPCの値をレジスタのようにして読み出せないのだろうか?しょうがないので割り込み処理サブルーチンの最初にプッシュされたスタック領域から読んでいる.
gcc のレジスタ利用規則を理解するのがめんどくさそうなので,アセンブラで作ったが,関数の中のアドレスラベルなど,一切構造化できないので,久しぶりにめんどくさかった.AVRの命令体系には subi イミディエト値で減算はあるのに addi はない.
不思議なのでさがしたら,AVRフリークのBBS?で英語で
「イミディエト値なんだからマイナスにして足せばいいだろ」
「フラグの違いに注意しましょう」
「アホが!おまえの脳みそでもわかるように説明してやる」
などと盛り上がっていた.
RISCにはよくあるパターンらしい.なんでないかは,設計者に聞くしかないらしい.マクロで addi を作った.

ユーザーのプログラムに影響するからグローバルでメモリを使えないなあ,と思っていたが,SPをずらしてこそっと確保すればいいことに気がついた.

USARTにつないで機械語プログラミングの学習に使える教材まで,あと一歩?だ.プログラムメモリへの書き込みはバッファリングしないといけないので,めんどくさい.

;
;
.include "tn2313def.inc"

;.macro ldiwx
; ldi xh, high(@0)
; ldi xl, low(@0)
;.endmacro

.macro ldiaz
ldi zh, high(@0<<1)
ldi zl, low(@0<<1)
.endmacro

; Create an Add Immediate by subtracting the negative 
.macro   addi 
   subi   @0, -@1      ;subtract the negative of an immediate value 
.endmacro 


.macro reserve
sts tempByte, zl
in   zl, SPL
sts shadowSPL, zl
lds zl, tempByte
;
push zh
push zl
push r17
push r16
push r3
push r2
push r1
push r0
in r16, SREG
sts shadowSREG, r16
.endmacro

.macro restore
lds r16, shadowSREG
out SREG, r16
pop r0
pop r1
pop r2
pop r3
pop r16
pop r17
pop zl
pop zh
.endmacro

.equ     clock = 8000000          ;clock frequency
.equ     baudrate = 2*9600          ;choose a baudrate
;
.equ     ubrrval = (clock/(16*baudrate))-1

.def buf0 = r0
.def buf1 = r1
.def buf2 = r2
.def buf3 = r3


.cseg
;reset and interrupt vectors
.org 0x0000
rjmp reset
.org 0x0007
rjmp ISR_USART0_RX
; the end of interrupt vectors

.org 0x0013
reset:
ldi     r16, LOW(STACKBOTTOM)
out     SPL, r16     ;set spl
; ldi r16, (0<<<
; out DDRB, r16
init:
rcall USART_Init
sei
rjmp main


ISR_USART0_RX:
reserve
rcall assume_PC

rcall RX_hexbuf
sts   tempByte, r16 ; end char
rcall hexbuf_to_temp
;
; ldiaz HexPrefix
; rcall TX_message
lds r16, tempWord+1
rcall TX_r16
lds r16, tempWord
rcall TX_r16
ldiaz SPACECHAR
rcall TX_message

lds r16, tempByte
cpi r16, $52 ; R
breq read_progmem
cpi r16, $53 ; S
breq store_ram
load_ram:
; ldiaz Data_Prefix
; rcall TX_message
lds zl, tempWord
lds zh, tempWord+1
ld r16, Z+
rcall TX_r16
rjmp output_end

read_progmem:
; ldiaz HexPrefix
; rcall TX_message
lds zl, tempWord
lds zh, tempWord+1
lsl zl
rol zh
lpm r16, Z+
sts tempByte, r16
lpm r16, Z
rcall TX_r16
lds r16, tempByte
rcall TX_r16
rjmp output_end

store_ram:
lds zl, tempWord
lds zh, tempWord+1
rcall RX_hexbuf
rcall hexbuf_to_temp
lds r16, tempWord ; only low byte
st   Z, r16
; ldiaz Data_Prefix
; rcall TX_message
lds r16, tempWord
rcall TX_r16
rjmp output_end

output_end:
ldiaz CRLF
rcall TX_message
restore
reti

assume_PC:
clr zh
lds zl, shadowSPL
adiw zl,1
ld   r16, Z+
sts shadowPC, r16
ld   r16, Z
sts shadowPC+1, r16
ret

;
;r16_to_digit:
; cpi r16, $41
; brcs zero_nine
; andi r16, $4f
; subi r16, 7 ; after '9'
; rjmp aligned
;zero_nine:
; andi r16, $3f
;aligned:
; ret
;hex_to_digit end.




USART_Init:
ldi r17, HIGH(ubrrval)
ldi r16, LOW(ubrrval)
; Set baud rate
out UBRRH, r17
out UBRRL, r16
; Enable receiver and transmitter, receiver interrupt
ldi r16, (1<<<<
out UCSRB,r16
; Set frame format: 8data, 2stop bit
ldi r16, (1<<
out UCSRC,r16
ret

USART_Transmit:
; Wait for empty transmit buffer
sbis UCSRA,UDRE
rjmp USART_Transmit
; Put data (r16) into buffer, sends the data
out UDR,r16
ret

USART_Receive:
; Wait for data to be received
sbis UCSRA, RXC
rjmp USART_Receive
; Get and return received data from buffer
in r16, UDR
ret

USART_Flush:
sbis UCSRA, RXC
ret
in r16, UDR
rjmp USART_Flush

RX_string:
rcall USART_Receive
st   Z+, r16
subi r16, $2e
brne RX_string
ldi r16, $00
st   -Z, r16 ; place the terminal char
ret
;RX_string end.

RX_hexbuf:
ldi r16, $30
mov buf3, r16
mov buf2, r16
mov buf1, r16
mov buf0, r16
RX_hexbuf_receive:
rcall USART_Receive
cpi r16, $30
brcs RX_hexbuf_exit
cpi r16, $3a
brcs RX_hexbuf_cont
cpi r16, $41
brcs RX_hexbuf_exit
cpi r16, $47
brcs RX_hexbuf_cont
cpi r16, $61
brcs RX_hexbuf_exit
cpi r16, $67
brcs RX_hexbuf_cont
breq RX_hexbuf_exit
RX_hexbuf_cont:
mov   buf3, buf2
mov   buf2, buf1
mov   buf1, buf0
mov   buf0, r16
rjmp RX_hexbuf_receive
RX_hexbuf_exit:
ret
;RX_qbytes end.

hexbuf_to_temp:
mov r16, buf3
rcall hex_to_nibble
mov r17, r16
swap r17
mov r16, buf2
rcall hex_to_nibble
or   r17, r16
sts tempWord+1, r17
mov r16, buf1
rcall hex_to_nibble
mov r17, r16
swap r17
mov r16, buf0
rcall hex_to_nibble
or   r16, r17
sts tempWord, r16
ret

;
hex_to_nibble:
subi r16, $30
cpi r16, $10
brcs hex_to_nibble_exit
andi r16, $17
subi r16, 7
hex_to_nibble_exit:
ret
;hex_to_nibble end.

nibble_to_hexdec:
andi r16, $0f
cpi r16, 10
brcs PC+2
subi r16, -$7  ; addi r16, $7
;nibble_to_hexdec_2:
subi r16, -$30 ; addi r16, $30
ret

;TX_string:
; ld   r16, X+
; cpi r16, $00
; breq TX_string_done
; rcall USART_Transmit
; rjmp TX_string
;TX_string_done:
; ret
;TX_string end.

TX_r16:
push r16
swap r16
rcall nibble_to_hexdec  ;ntohex
rcall USART_Transmit
pop r16
rcall nibble_to_hexdec
rcall USART_Transmit
ret
;TX_bytehex end.


;ntohex:
; andi r16, $0f
; ldiaz Hex_Table
; add zl, r16
; clr r16
; adc zh, r16
; lpm r16, Z
; ret

TX_message:
lpm   r16, Z+
cpi r16, $00
brne PC+2
ret
rcall USART_Transmit
rjmp TX_message
;TX_message end.


;Hex_Table:
;.db "0123456789abcdef"
;
;Hex_Suffix:
;.db "H",0

Data_Prefix:
.db "$",0
HexPrefix:
.db "0x",0, 0

SPACECHAR:
.db " ",0
CRLF:
.db $0d, $0a, 0, 0


.org 0x200
main:
ldi r16, 0xff
out DDRB, r16
clr r16
loop:
out PORTB, r16
rcall wait
inc r16
rjmp loop

wait:
ldi r18, 10
wait_loop:
rcall wait01
dec r18
brne wait_loop
ret

wait01:
ldi r19, 100
wait01_loop:
rcall wait1m
dec r19
brne wait01_loop
ret

wait1m:
ldi r20, 250
wait1m_loop:
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
dec r20
brne wait1m_loop
ret


.dseg
.org 0x00d8
STACKBOTTOM:

.org 0x00d9
workspace:
tempByte: .byte 1
tempWord: .byte 2

shadowPC: .byte 2
shadowSREG: .byte 1
shadowSPL: .byte 1

0 件のコメント:

コメントを投稿