From 67d25d837ac55f28a366c0a3b262e439a6e75fc3 Mon Sep 17 00:00:00 2001 From: Dimitri Sokolyuk Date: Sat, 19 Aug 2017 12:15:28 +0200 Subject: Add AmForth --- amforth-6.5/avr8/drivers/1wire.asm | 165 +++++++++++++++++++++++++++ amforth-6.5/avr8/drivers/generic-isr.asm | 41 +++++++ amforth-6.5/avr8/drivers/usart-rx-buffer.asm | 132 +++++++++++++++++++++ amforth-6.5/avr8/drivers/usart.asm | 30 +++++ amforth-6.5/avr8/drivers/usart_0.asm | 32 ++++++ amforth-6.5/avr8/drivers/usart_1.asm | 31 +++++ amforth-6.5/avr8/drivers/usart_2.asm | 34 ++++++ amforth-6.5/avr8/drivers/usart_3.asm | 31 +++++ amforth-6.5/avr8/drivers/usart_common.asm | 30 +++++ 9 files changed, 526 insertions(+) create mode 100644 amforth-6.5/avr8/drivers/1wire.asm create mode 100644 amforth-6.5/avr8/drivers/generic-isr.asm create mode 100644 amforth-6.5/avr8/drivers/usart-rx-buffer.asm create mode 100644 amforth-6.5/avr8/drivers/usart.asm create mode 100644 amforth-6.5/avr8/drivers/usart_0.asm create mode 100644 amforth-6.5/avr8/drivers/usart_1.asm create mode 100644 amforth-6.5/avr8/drivers/usart_2.asm create mode 100644 amforth-6.5/avr8/drivers/usart_3.asm create mode 100644 amforth-6.5/avr8/drivers/usart_common.asm (limited to 'amforth-6.5/avr8/drivers') diff --git a/amforth-6.5/avr8/drivers/1wire.asm b/amforth-6.5/avr8/drivers/1wire.asm new file mode 100644 index 0000000..ab5c9f4 --- /dev/null +++ b/amforth-6.5/avr8/drivers/1wire.asm @@ -0,0 +1,165 @@ +;; AUTHORs +; B. J. Rodriguez (MSP 430) +; Matthias Trute (AVR Atmega) +; COPYRIGHT +; (c) 2012 Bradford J. Rodriguez for the 430 code and API + +; adapted 430 assembly code to AVR +; wishlist: +; use a configurable pin at runtime, compatible with bitnames.frt +; no external pull up, no external power supply for devices +; ??? +; +;.EQU OW_BIT=4 +;.equ OW_PORT=PORTE +.set OW_DDR=(OW_PORT-1) +.set OW_PIN=(OW_DDR-1) + +;****f* 1W.RESET +; NAME +; 1W.RESET +; SYNOPSIS +; 1W.RESET ( -- f ) Initialize 1-wire devices; return true if present +; DESCRIPTION +; This configures the port pin used by the 1-wire interface, and then +; sends an "initialize" sequence to the 1-wire devices. If any device +; is present, it will be detected. +; +; Timing, per DS18B20 data sheet: +; a) Output "0" (drive output low) for >480 usec. +; b) Output "1" (let output float). +; c) After 15 to 60 usec, device will drive pin low for 60 to 240 usec. +; So, wait 75 usec and sample input. +; d) Leave output high (floating) for at least 480 usec. +;****** +; ( -- f ) +; Hardware +; Initialize 1-wire devices; return true if present +VE_OW_RESET: + .dw $ff08 + .db "1w.reset" + .dw VE_HEAD + .set VE_HEAD = VE_OW_RESET +XT_OW_RESET: + .dw PFA_OW_RESET +PFA_OW_RESET: + savetos + ; setup to output + sbi OW_DDR, OW_BIT + ; Pull output low + cbi OW_PORT, OW_BIT + ; Delay >480 usec + DELAY 480 + ; Critical timing period, disable interrupts. + in temp1, SREG + cli + ; Pull output high + sbi OW_PORT, OW_BIT + ; make pin input, sends "1" + cbi OW_DDR, OW_BIT + DELAY 64 ; delayB + ; Sample input pin, set TOS if input is zero + in tosl, OW_PIN + sbrs tosl, OW_BIT + ser tosh + ; End critical timing period, enable interrupts + out SREG, temp1 + ; release bus + cbi OW_DDR, OW_BIT + cbi OW_PORT, OW_BIT + + ; Delay rest of 480 usec + DELAY 416 + ; we now have the result flag in TOS + mov tosl, tosh + jmp_ DO_NEXT + +;****f* 1W.SLOT +; NAME +; 1W.SLOT +; SYNOPSIS +; 1W.SLOT ( c -- c' ) Write and read one bit to/from 1-wire. +; DESCRIPTION +; The "touch byte" function is described in Dallas App Note 74. +; It outputs a byte to the 1-wire pin, LSB first, and reads back +; the state of the 1-wire pin after a suitable delay. +; To read a byte, output $FF and read the reply data. +; To write a byte, output that byte and discard the reply. +; +; This function performs one bit of the "touch" operation -- +; one read/write "slot" in Dallas jargon. Perform this eight +; times in a row to get the "touch byte" function. +; +; PARAMETERS +; The input parameter is xxxxxxxxbbbbbbbo where +; 'xxxxxxxx' are don't cares, +; 'bbbbbbb' are bits to be shifted down, and +; 'o' is the bit to be output in the slot. This must be 1 +; to create a read slot. +; +; The returned value is xxxxxxxxibbbbbbb where +; 'xxxxxxxx' are not known (the input shifted down 1 position), +; 'i' is the bit read during the slot. This has no meaning +; if it was a write slot. +; 'bbbbbbb' are the 7 input bits, shifted down one position. +; +; This peculiar parameter usage allows OWTOUCH to be written as +; OWSLOT OWSLOT OWSLOT OWSLOT OWSLOT OWSLOT OWSLOT OWSLOT +; +; NOTES +; Interrupts are disabled during each bit. + +; Timing, per DS18B20 data sheet: +; a) Output "0" for start period. (> 1 us, < 15 us, typ. 6 us*) +; b) Output data bit (0 or 1), open drain +; c) After MS from start of cycle, sample input (15 to 60 us, typ. 25 us*) +; d) After write-0 period from start of cycle, output "1" (>60 us) +; e) After recovery period, loop or return. (> 1 us) +; For writes, DS18B20 samples input 15 to 60 usec from start of cycle. +; * "Typical" values are per App Note 132 for a 300m cable length. + +; --------- ------------------------------- +; \ / / +; ------------------------------- +; a b c d e +; | 6us | 19us | 35us | 2us | +;****** +; ( c -- c' ) +; Hardware +; Write and read one bit to/from 1-wire. +VE_OW_SLOT: + .dw $ff07 + .db "1w.slot",0 + .dw VE_HEAD + .set VE_HEAD = VE_OW_SLOT +XT_OW_SLOT: + .dw PFA_OW_SLOT +PFA_OW_SLOT: + ; pull low + cbi OW_PORT, OW_BIT + sbi OW_DDR, OW_BIT + ; disable interrupts + in temp1, SREG + cli + DELAY 6 ; DELAY A + ; check bit + clc + ror tosl + brcc PFA_OW_SLOT0 ; a 0 keeps the bus low + ; release bus, a 1 is written + sbi OW_PORT, OW_BIT + cbi OW_DDR, OW_BIT +PFA_OW_SLOT0: + ; sample the input (no action required if zero) + DELAY 9 ; wait DELAY E to sample + in temp0, OW_PIN + sbrc temp0, OW_BIT + ori tosl, $80 + + DELAY 51 ; DELAY B + sbi OW_PORT, OW_BIT ; release bus + cbi OW_DDR, OW_BIT + delay 2 + ; re-enable interrupts + out SREG, temp1 + jmp_ DO_NEXT diff --git a/amforth-6.5/avr8/drivers/generic-isr.asm b/amforth-6.5/avr8/drivers/generic-isr.asm new file mode 100644 index 0000000..e0aeaed --- /dev/null +++ b/amforth-6.5/avr8/drivers/generic-isr.asm @@ -0,0 +1,41 @@ +; ISR routines +.eseg +intvec: .byte INTVECTORS * CELLSIZE +.dseg +intcnt: .byte INTVECTORS +.cseg + +; interrupt routine gets called (again) by rcall! This gives the +; address of the int-vector on the stack. +isr: + st -Y, r0 + in r0, SREG + st -Y, r0 +.if (pclen==3) + pop r0 ; some 128+K Flash devices use 3 cells for call/ret +.endif + pop r0 + pop r0 ; = intnum * intvectorsize + 1 (address following the rcall) + dec r0 +.if intvecsize == 1 ; + lsl r0 +.endif + mov isrflag, r0 + push zh + push zl + ldi zl, low(intcnt) + ldi zh, high(intcnt) + lsr r0 ; we use byte addresses in the counter array, not words + add zl, r0 + adc zh, zeroh + ld r0, Z + inc r0 + st Z, r0 + pop zl + pop zh + + ld r0, Y+ + out SREG, r0 + ld r0, Y+ + ret ; returns the interrupt, the rcall stack frame is removed! + ; no reti here, see words/isr-end.asm diff --git a/amforth-6.5/avr8/drivers/usart-rx-buffer.asm b/amforth-6.5/avr8/drivers/usart-rx-buffer.asm new file mode 100644 index 0000000..b6a64b8 --- /dev/null +++ b/amforth-6.5/avr8/drivers/usart-rx-buffer.asm @@ -0,0 +1,132 @@ +;;; usart driver, receiving + +; sizes have to be powers of 2! +.equ usart_rx_size = $10 +.equ usart_rx_mask = usart_rx_size - 1 +.dseg + usart_rx_data: .byte usart_rx_size + usart_rx_in: .byte 1 + usart_rx_out: .byte 1 +.cseg + +VE_TO_RXBUF: + .dw $ff07 + .db ">rx-buf",0 + .dw VE_HEAD + .set VE_HEAD = VE_TO_RXBUF +XT_TO_RXBUF: + .dw PFA_rx_tobuf +PFA_rx_tobuf: + mov temp0, tosl + lds temp1, usart_rx_in + ldi zl, low(usart_rx_data) + ldi zh, high(usart_rx_data) + add zl, temp1 + adc zh, zeroh + st Z, temp0 + inc temp1 + andi temp1,usart_rx_mask + sts usart_rx_in, temp1 + loadtos + jmp_ DO_NEXT + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; setup with +; ' isr-rx URXCaddr int! +VE_ISR_RX: + .dw $ff06 + .db "isr-rx" + .dw VE_HEAD + .set VE_HEAD = VE_ISR_RX +XT_ISR_RX: + .dw DO_COLON +usart_rx_isr: + .dw XT_DOLITERAL + .dw usart_data + .dw XT_CFETCH + .dw XT_DUP + .dw XT_DOLITERAL + .dw 3 + .dw XT_EQUAL + .dw XT_DOCONDBRANCH + .dw usart_rx_isr1 + .dw XT_COLD +usart_rx_isr1: + .dw XT_TO_RXBUF + .dw XT_EXIT + +; ( -- ) Hardware Access +; R( --) +; initialize usart +;VE_USART_INIT_RXBUFFER: +; .dw $ff0x +; .db "+usart-buffer" +; .dw VE_HEAD +; .set VE_HEAD = VE_USART_INIT_RXBUFFER +XT_USART_INIT_RX_BUFFER: + .dw DO_COLON +PFA_USART_INIT_RX_BUFFER: ; ( -- ) + .dw XT_DOLITERAL, XT_ISR_RX + .dw XT_DOLITERAL, URXCaddr + .dw XT_INTSTORE + + .dw XT_DOLITERAL + .dw usart_rx_data + .dw XT_DOLITERAL + .dw usart_rx_size + 6 + .dw XT_ZERO + .dw XT_FILL + .dw XT_EXIT + +; ( -- c) +; MCU +; get 1 character from input queue, wait if needed using interrupt driver +VE_RX_BUFFER: + .dw $ff06 + .db "rx-buf" + .dw VE_HEAD + .set VE_HEAD = VE_RX_BUFFER +XT_RX_BUFFER: + .dw DO_COLON +PFA_RX_BUFFER: + .dw XT_RXQ_BUFFER + .dw XT_DOCONDBRANCH + .dw PFA_RX_BUFFER + .dw XT_DOLITERAL + .dw usart_rx_out + .dw XT_CFETCH + .dw XT_DUP + .dw XT_DOLITERAL + .dw usart_rx_data + .dw XT_PLUS + .dw XT_CFETCH + .dw XT_SWAP + .dw XT_1PLUS + .dw XT_DOLITERAL + .dw usart_rx_mask + .dw XT_AND + .dw XT_DOLITERAL + .dw usart_rx_out + .dw XT_CSTORE + .dw XT_EXIT + +; ( -- f) +; MCU +; check if unread characters are in the input queue +VE_RXQ_BUFFER: + .dw $ff07 + .db "rx?-buf",0 + .dw VE_HEAD + .set VE_HEAD = VE_RXQ_BUFFER +XT_RXQ_BUFFER: + .dw DO_COLON +PFA_RXQ_BUFFER: + .dw XT_PAUSE + .dw XT_DOLITERAL + .dw usart_rx_out + .dw XT_CFETCH + .dw XT_DOLITERAL + .dw usart_rx_in + .dw XT_CFETCH + .dw XT_NOTEQUAL + .dw XT_EXIT diff --git a/amforth-6.5/avr8/drivers/usart.asm b/amforth-6.5/avr8/drivers/usart.asm new file mode 100644 index 0000000..7274789 --- /dev/null +++ b/amforth-6.5/avr8/drivers/usart.asm @@ -0,0 +1,30 @@ + +.equ BAUDRATE_LOW = UBRRL+$20 +.equ BAUDRATE_HIGH = UBRRH+$20 +.equ USART_C = UCSRC+$20 +.equ USART_B = UCSRB+$20 +.equ USART_A = UCSRA+$20 +.equ USART_DATA = UDR+$20 +.equ bm_USARTC_en = 1 << 7 + +; some generic constants +.equ bm_USART_RXRD = 1 << RXC +.equ bm_USART_TXRD = 1 << UDRE +.equ bm_ENABLE_TX = 1 << TXEN +.equ bm_ENABLE_RX = 1 << RXEN +.equ bm_ENABLE_INT_RX = 1<