Amiga-Request@cs.odu.edu (Amiga Sources/Binaries Moderator) (06/04/90)
Submitted-by: jcs@crash.uucp Posting-number: Volume 90, Issue 176 Archive-name: util/st/part01 This code directly accesses the hardware and achieves very high baud rates without errors. This code should be legal if the serial device is first opened and exclusive access is granted. Speeds of over 130k baud between a stock, nofastmem 500 and a 25mhz GVP 68030 have been achieved. The '030 Amiga can go much faster; it can read at least 223,720 baud. The 500 poops out at 132,575 baud. Writing fast is no problem, reading eats up some bandwidth, and is thus the bottleneck. Polled I/O (yuk) can yield faster rates. These baud rates were accomplished with a direct 2,3,7 wire, 50 foot shielded cable. Max baud rates may vary depending on cable and hardware configurations. #!/bin/sh # This is a shell archive. Remove anything before this line, then unpack # it by saving it into a file and typing "sh file". To overwrite existing # files, type "sh file -c". You can also feed this as standard input via # unshar, or by typing "sh <file", e.g.. If this archive is complete, you # will see the following message at the end: # "End of archive 1 (of 1)." # Contents: input.c input.h inputhandler.a makefile readme serial.a # st.c # Wrapped by tadguy@xanth on Sun Jun 3 20:05:27 1990 PATH=/bin:/usr/bin:/usr/ucb ; export PATH if test -f 'input.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'input.c'\" else echo shar: Extracting \"'input.c'\" \(2035 characters\) sed "s/^X//" >'input.c' <<'END_OF_FILE' X/* input.c X created by John Schultz, 10-Sep-89 X X*/ X X#include <exec/types.h> X#include <exec/io.h> X#include <exec/ports.h> X#include <exec/interrupts.h> X#include <proto/exec.h> X#include <proto/graphics.h> X#include <devices/input.h> X#include <devices/inputevent.h> X#include "input.h" X Xunsigned short volatile raw; /* raw key value */ X Xstruct MsgPort indevport; Xstruct MsgPort * indevportptr; Xstruct IOStdReq * inreqblockptr; Xstruct Interrupt inhandler; Xstruct InputEvent * eventp; X Xextern void totalinput(); X Xint createti(void) { X X indevportptr = CreatePort("indevport",0); X if (!indevportptr) { X return 0; X } X X inreqblockptr = CreateStdIO((struct MsgPort *)indevportptr); X if (!inreqblockptr) { X DeletePort(indevportptr); X return 0; X } X X inhandler.is_Data = (APTR)&raw; X inhandler.is_Code = totalinput; X inhandler.is_Node.ln_Pri = 51; /* One ahead of Intuition */ X X if (OpenDevice("input.device",0L, X (struct IORequest *)inreqblockptr,0L)) { X DeletePort(indevportptr); X DeleteStdIO(inreqblockptr); X return 0; X } X X inreqblockptr->io_Command = IND_ADDHANDLER; X inreqblockptr->io_Data = (APTR)&inhandler; X X if (DoIO((struct IORequest *)inreqblockptr)) { X DeletePort(indevportptr); X DeleteStdIO(inreqblockptr); X CloseDevice((struct IORequest *)inreqblockptr); X return 0; X } X X GfxBase = (struct GfxBase *)OpenLibrary("graphics.library",0); X if(!GfxBase) { X DeletePort(indevportptr); X DeleteStdIO(inreqblockptr); X CloseDevice((struct IORequest *)inreqblockptr); X return 0; X } X FreeSprite(0); X X CloseLibrary((struct Library *)GfxBase); X X return 1; X X} /* end createti */ X Xvoid deleteti(void) { X X if ((indevportptr) && (inreqblockptr)) { X inreqblockptr->io_Command = IND_REMHANDLER; X inreqblockptr->io_Data = (APTR)&inhandler; X DoIO((struct IORequest *)inreqblockptr); X CloseDevice((struct IORequest *)inreqblockptr); X DeleteStdIO(inreqblockptr); X DeletePort(indevportptr); X } /* end if */ X X} /* END deleteti */ X X X/* END input.c */ END_OF_FILE if test 2035 -ne `wc -c <'input.c'`; then echo shar: \"'input.c'\" unpacked with wrong size! fi # end of 'input.c' fi if test -f 'input.h' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'input.h'\" else echo shar: Extracting \"'input.h'\" \(241 characters\) sed "s/^X//" >'input.h' <<'END_OF_FILE' X/* input.h - total input X created by John Schultz, 10-Sep-89 X*/ X X#ifndef INPUTTI X#define INPUTTI X Xextern unsigned short volatile raw; /* raw key input */ X Xextern int createti(void); X Xextern void deleteti(void); X X#endif X X/* end input.h */ END_OF_FILE if test 241 -ne `wc -c <'input.h'`; then echo shar: \"'input.h'\" unpacked with wrong size! fi # end of 'input.h' fi if test -f 'inputhandler.a' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'inputhandler.a'\" else echo shar: Extracting \"'inputhandler.a'\" \(418 characters\) sed "s/^X//" >'inputhandler.a' <<'END_OF_FILE' X; Input Handler X; created by John Schultz, 17-Sep-89 X X section "TotalInput",code X X xdef _totalinput X X; Input event structure offsets X XIECLASS equ 4 XIECODE equ 6 X X; A0 = inputevent pointer X; A1 = data pointer X X_totalinput: X cmp.b #1,IECLASS(A0) ; event->ie_Class == IECLASS_RAWKEY ? X bne.b notrawkey X move.w IECODE(A0),(A1) ; raw = event->ie_Code Xnotrawkey: X moveq.l #0,D0 ; don't pass events to intuition X rts X X END X END_OF_FILE if test 418 -ne `wc -c <'inputhandler.a'`; then echo shar: \"'inputhandler.a'\" unpacked with wrong size! fi # end of 'inputhandler.a' fi if test -f 'makefile' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'makefile'\" else echo shar: Extracting \"'makefile'\" \(352 characters\) sed "s/^X//" >'makefile' <<'END_OF_FILE' X# serial makefile, created by John Schultz, 17-Sep-89 X Xst: st.o serial.o input.o inputhandler.o X blink from lib:c.o+st.o+serial.o+input.o+inputhandler.o to st \ X lib lib:lc.lib sc sd nd X Xst.o: st.c X lc -O st.c X Xserial.o: serial.a X asm serial.a X Xinput.o: input.h input.c X lc input.c X Xinputhandler.o: inputhandler.a X asm inputhandler.a X END_OF_FILE if test 352 -ne `wc -c <'makefile'`; then echo shar: \"'makefile'\" unpacked with wrong size! fi # end of 'makefile' fi if test -f 'readme' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'readme'\" else echo shar: Extracting \"'readme'\" \(2076 characters\) sed "s/^X//" >'readme' <<'END_OF_FILE' X X Interrupt-driven Serial I/O Testbed X by John Schultz X 4/16/90 X X This code directly accesses the hardware and achieves very high Xbaud rates without errors. This code should be legal if the serial Xdevice is first opened and exclusive access is granted. Speeds of Xover 130k baud between a stock, nofastmem 500 and a 25mhz GVP 68030 Xhave been achieved. The '030 Amiga can go much faster; it can read Xat least 223,720 baud. The 500 poops out at 132,575 baud. Writing Xfast is no problem, reading eats up some bandwidth, and is thus Xthe bottleneck. Polled I/O (yuk) can yield faster rates. These Xbaud rates were accomplished with a direct 2,3,7 wire, 50 foot Xshielded cable. Max baud rates may vary depending on cable and Xhardware configurations. X The current test code, ST (Serial Test), writes characters typed Xon the keyboard 10 times. Errors at high speed show up when less Xthan 10 characters are received or funny characters are inserted. X I can run DNet and leave it running while I run this code! DNet Xmust be idling, and the baud rate must be the same as DNet's (usually X19200) the last time you run ST. This is very useful as quiting and Xrestarting DNet is not necessary. X Part of the original assembly code came from the Amiga Transactor, XSeptember 1989: Volume 2, Issue 6,pp 42-44, by Mike Schwartz. The Xexample changed the AutoVectors directly, and had a few typos. I use XSetIntVector(), and do things a little differently with the rbf and Xtbe code. This was pretty much the first assembly language program I Xwrote, so experts feel free to point out improvements. X I wrote the code using Lattice 5.04. I currently use the Cape Xor Devpac assemblers for speed, but for this example used Lattice's Xasm (everyone with Lattice should have it). X X As always, please point out any optimizations, errors, or illegal Xacts committed in this code. If you enhance the code, please email me Xa copy. X X Use this code as you wish; no strings, ropes, cables, or Xbungee cords attached. X X X X John END_OF_FILE if test 2076 -ne `wc -c <'readme'`; then echo shar: \"'readme'\" unpacked with wrong size! fi # end of 'readme' fi if test -f 'serial.a' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'serial.a'\" else echo shar: Extracting \"'serial.a'\" \(5691 characters\) sed "s/^X//" >'serial.a' <<'END_OF_FILE' X; Serial.a X; created by John Schultz, 17-Sep-89 X; last modified 17-April-90 X X section Serial,CODE X X xref _raw X X xdef _baudper X xdef _openserial X xdef _closeserial X xdef _sendser X xdef _readser X xdef _checkser X xdef _rawtoascii X xdef _sendsernobuff X X X_LVOSetIntVector equ $FFFFFF5E X XESCAPE equ 69 ; input-handler rawkey code X XCLOCK equ 3579545 X_baudper dc.w (CLOCK/19200)-1 ; defaualt X XCUSTOM equ $dff000 XSERDATR equ $000018 XSERDAT equ $000030 XSERPER equ $000032 X XINTENA equ $00009a XINTENAR equ $00001c XINTREQ equ $00009c X XTBEQSIZE equ 128 ; buffer size in bytes, XRBFQSIZE equ 128 ; increase or decrease as needed X XLED equ $bfe001 ; toggle power led, audio filter X Xledroll dc.b %00010001 ; flash every 4 bytes Xledpad dc.b 0 X Xoldintena dc.w 0 X Xtbequeue ds.b TBEQSIZE ; circular queue Xtbeqend Xtbehead dc.l tbequeue Xtbetail dc.l tbequeue X Xoldtbeinterrupt dc.l 0 Xoldrbfinterrupt dc.l 0 X Xtbeinterrupt X dc.l 0 ; ln_succ X dc.l 0 ; ln_prec X dc.b 2 ; NT_INTERRUPT X dc.b 127 ; ln_pri X dc.l 0 ; ln_name X dc.l tbehead ; is_data X dc.l tbehandler ; is_code X Xrbfinterrupt X dc.l 0 ; ln_succ X dc.l 0 ; ln_prec X dc.b 2 ; NT_INTERRUPT X dc.b 127 ; ln_pri X dc.l 0 ; ln_name X dc.l rbftail ; is_data X dc.l rbfhandler ; is_code X X Xtbehandler X move.w #1,INTREQ(a0) ; clear TBE interrupt X move.l (a1),a1 ; a1 = tbehead, (a1) = pointer X cmp.l tbetail,a1 ; now a1 = pointer X beq.b 99$ X move.w SERDATR(a0),d0 ; check to make sure emtpy X btst #13,d0 X beq.b 99$ X move.w #$100,d0 X move.b (a1)+,d0 ; get byte from queue X move.w d0,SERDAT(a0) ; send byte X cmpa.l #tbeqend,a1 X bne.b 10$ X lea tbequeue(pc),a1 X10$ move.l a1,tbehead X99$ X rts X Xrbfqueue ds.b RBFQSIZE Xrbfqend Xrbfhead dc.l rbfqueue Xrbftail dc.l rbfqueue X Xrbfhandler X move.w SERDATR(a0),d0 ; a0 = custom X move.w #$800,INTREQ(a0) ; clear RBF interrupt X move.l (a1),a0 ; a1 = rbftail, get pointer X move.b d0,(a0)+ ; write byte to buffer X cmpa.l #rbfqend,a0 X bne.b 10$ X lea rbfqueue(pc),a0 X10$ move.l a0,(a1) ; a1 = rbftail X X;99$ X; move.b ledroll(pc),d0 ; remove from 99$-100$ for more X; rol.b #1,d0 ; speed X; move.b d0,ledroll X; btst #1,d0 X; beq.b 100$ X; bchg.b #1,LED ; toggle power led / audio filter X;100$ X rts X X_openserial X move.l a6,-(sp) X lea CUSTOM,a0 X move.w #$4000,INTENA(a0) ; disable X move.l $4,a6 ; execbase X lea rbfinterrupt(pc),a1 X moveq.l #11,d0 X jsr _LVOSetIntVector(a6) X move.l d0,oldrbfinterrupt X lea tbeinterrupt(pc),a1 X moveq.l #0,d0 X jsr _LVOSetIntVector(a6) X move.l d0,oldtbeinterrupt X X lea CUSTOM,a0 X move.w _baudper,SERPER(a0) ; set period X X move.w #$3fff,$bfd0fe ; init handshake lines X move.w INTENAR(a0),oldintena X move.w #$8801,INTENA(a0) ; turn on RBF and TBE INTENA X move.w #$0801,INTREQ(a0) ; clear RBF and TBE INTREQ X move.w #$c000,INTENA(a0) ; enable X move.l (sp)+,a6 X rts X X X_closeserial X move.l a6,-(sp) X lea CUSTOM,a0 X move.w #$4000,INTENA(a0) ; disable X move.l $4,a6 ; execbase X move.l oldrbfinterrupt,a1 X moveq.l #11,d0 X jsr _LVOSetIntVector(a6) X move.l oldtbeinterrupt,a1 X moveq.l #0,d0 X jsr _LVOSetIntVector(a6) X X lea CUSTOM,a0 X move.w #$0801,INTENA(a0) ; turn off RBF and TBE INTENA X move.w oldintena,d0 X and.w #$0801,d0 ; mask for bit 11 and bit 1. X bset #15,d0 ; set/clr = 1 (set) X move.w d0,INTENA(a0) ; reset old RBF and TBE INTENA X X bclr.b #1,LED X X move.w #$0801,INTREQ(a0) ; clear RBF and TBE INTREQ X move.w #$c000,INTENA(a0) ; enable X move.l (sp)+,a6 X rts X X_sendser X lea CUSTOM,a0 X move.w #$4000,INTENA(a0) X X move.l tbetail,a1 X cmpa.l tbehead,a1 X beq.b 5$ X move.w #$8001,INTREQ(a0) ; generate a tbe interrupt X5$ X move.b d0,(a1)+ ; queue up byte X cmpa.l #tbeqend,a1 X bne.b 10$ X lea tbequeue(pc),a1 X10$ move.l a1,tbetail X X move.w #$c000,INTENA(a0) X rts X X X; send byte in d0 to serial port, non-buffered. X_sendsernobuff X lea CUSTOM,a0 X move.w #$4000,INTENA(a0) X1$ move.w SERDATR,d1 X btst #13,d1 ; check TBE X beq.b 1$ ; buffer busy X X move.w #$100,d1 X move.b d0,d1 X move.w d1,SERDAT(a0) X2$ move.w SERDATR(a0),d1 X btst #13,d1 ; check TBE X beq.b 2$ ; buffer busy X move.w #$001,INTREQ(a0) ; clear TBE interrupt X X move.w #$c000,INTENA(a0) X rts X X X; uses a0 X_readser X cmp.w #ESCAPE,_raw ; quits on ESC from input handler X beq.b 20$ X move.l rbfhead,a0 X cmpa.l rbftail,a0 X beq.b _readser X move.b (a0)+,d0 X cmpa.l #rbfqend,a0 X bne.b 10$ X lea rbfqueue(pc),a0 X10$ move.l a0,rbfhead X20$ X rts X X_checkser X move.l rbfhead,a0 X cmpa.l rbftail,a0 X bne.b dataisin X moveq.l #0,d0 X rts Xdataisin X moveq.l #1,d0 X rts X X X; rawkey in d0 X; ascii returned in d0 X_rawtoascii X cmp.b #79,d0 X bls.b getascii X moveq.l #0,d0 X rts Xgetascii X lea asciitable,a0 X move.b 0(a0,d0),d0 X rts X X X section asciitable,data X X; This is a quick trick, don't do this for anything other than X; home use, boys and girls. Use rawkeyconvert, etc. X Xasciitable X dc.b '`' ; backquote ` X dc.b '1' X dc.b '2' X dc.b '3' X dc.b '4' X dc.b '5' X dc.b '6' X dc.b '7' X dc.b '8' X dc.b '9' X dc.b '0' X dc.b '-' X dc.b '=' X dc.b $0D ; \ X dc.b 0 X dc.b '0' ; keypad 0 X dc.b 'q' X dc.b 'w' X dc.b 'e' X dc.b 'r' X dc.b 't' X dc.b 'y' X dc.b 'u' X dc.b 'i' X dc.b 'o' X dc.b 'p' X dc.b '[' X dc.b ']' X dc.b 0 X dc.b '1' X dc.b '2' X dc.b '3' X dc.b 'a' X dc.b 's' X dc.b 'd' X dc.b 'f' X dc.b 'g' X dc.b 'h' X dc.b 'j' X dc.b 'k' X dc.b 'l' X dc.b ';' X dc.b $27 ; ' single quote X dc.b 0 X dc.b 0 X dc.b '4' X dc.b '5' X dc.b '6' X dc.b 0 X dc.b 'z' X dc.b 'x' X dc.b 'c' X dc.b 'v' X dc.b 'b' X dc.b 'n' X dc.b 'm' X dc.b ',' X dc.b '.' X dc.b '/' X dc.b 0 X dc.b '.' ; keypad X dc.b '7' X dc.b '8' X dc.b '9' X dc.b ' ' X dc.b $8 ; backspace X dc.b $9 ; tab X dc.b $D ; enter cr X dc.b $D ; return cr X dc.b $1B ; ESC X dc.b $7f ; delete X dc.b '' X dc.b 0 X dc.b 0 X dc.b '-' ; keypad X dc.b 0 X dc.b 0 X dc.b $b ; up arrow X dc.b $a ; down arrow X dc.b $20 ; rt arrow X dc.b $8 ; left arrow X X END END_OF_FILE if test 5691 -ne `wc -c <'serial.a'`; then echo shar: \"'serial.a'\" unpacked with wrong size! fi # end of 'serial.a' fi if test -f 'st.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'st.c'\" else echo shar: Extracting \"'st.c'\" \(1882 characters\) sed "s/^X//" >'st.c' <<'END_OF_FILE' X/* ST.c : Serial Test */ X/* Created by John Schultz, 4/16/90 */ X/* Interrupt driven serial I/O testbed */ X X#include <stdio.h> X#include <dos.h> X#include "input.h" X X#define CLOCK 3579545 X X#define MINBAUD 300 /* Change these at will */ X#define MAXBAUD 230000 X X#define BUFFSIZE 80 X X#define ESCAPE 69 X Xextern void openserial(void); Xextern void __asm sendser(register __d0 char c); Xextern void __asm sendsernobuff(register __d0 char c); Xextern char __asm readser(void); Xextern short __asm checkser(void); Xextern char __asm rawtoascii(register __d0 char c); X Xextern short far baudper; X Xvoid main(int argc,char ** argv) { Xshort i = 0; Xlong console; Xlong baud; Xchar traw; Xshort notquit = 1; Xchar buffer[BUFFSIZE]; X X X if (argc != 2) { X printf("USAGE: st <baud>\n"); X exit(0); X } X X baud = atoi(argv[1]); X if (baud < MINBAUD) X baud = MINBAUD; X else if (baud > MAXBAUD) X baud = MAXBAUD; X X printf("Setting baud to %d. Press ESC to quit.\n",baud); X X baudper = (CLOCK / baud)-1; X X console = _dopen("*",MODE_OLDFILE); X if (console == -1) { X printf("Couldn't open console.\n"); X exit(0); X } X X if (createti()) { X openserial(); X traw = 0; X raw = 0; X X while (notquit) { X if (raw) { X traw = raw; X raw = 0; X if (traw == ESCAPE) notquit = 0; /* ESC */ X traw = rawtoascii(traw); X sendser(traw); X sendser(traw); X sendser(traw); X sendser(traw); X sendser(traw); X sendser(traw); X sendser(traw); X sendser(traw); X sendser(traw); X sendser(traw); X X } X X if (checkser()) X for (i = 0; X (i < BUFFSIZE) && (checkser()); X buffer[i++] = readser()); X X if (i > 0) _dwrite(console,buffer,i); X X i = 0; X X } /* while notquit */ X X closeserial(); X deleteti(); X } /* if createti */ X X printf("\n"); X X} /* END ST.c */ END_OF_FILE if test 1882 -ne `wc -c <'st.c'`; then echo shar: \"'st.c'\" unpacked with wrong size! fi # end of 'st.c' fi echo shar: End of archive 1 \(of 1\). cp /dev/null ark1isdone MISSING="" for I in 1 ; do if test ! -f ark${I}isdone ; then MISSING="${MISSING} ${I}" fi done if test "${MISSING}" = "" ; then echo You have the archive. rm -f ark[1-9]isdone else echo You still need to unpack the following archives: echo " " ${MISSING} fi ## End of shell archive. exit 0 -- Mail submissions (sources or binaries) to <amiga@cs.odu.edu>. Mail comments to the moderator at <amiga-request@cs.odu.edu>. Post requests for sources, and general discussion to comp.sys.amiga.