PROGRAM ADORDA C A/D OR D/A C C VERSION 1.1 C C This program can either input data from the AR11 analog C input/output subsystem and output the data to tape (A/D C operation) or it can read data from tape and output it to C the AR11 (D/A operation). It processes data in blocks of C 1280 integers, uses a TE16 tape drive operating at 1600 BPI, C and can work at a continious rate of at least 4 kHz. C C The program flow is described below : C C if a/d then C fill buffer with data from the AR11 C start output of buffer to tape C toggle buffer numbers C repeat process until told to quit C else if d/a then C fill buffer with data from tape C output data in buffer at user input rate C toggle buffer numbers C repeat process until told to quit C end if C C By double buffering the data the program can run at a continious C rate of 4 kHz. 4kHz was tested and worked fine. The upper speed C limit has not been determined by the author at the time of this C writting. C C RESTRICTIONS : C This program was written for a PDP-11/55 running RSX-11M V.4.0 C that has a TE16 tape drive. If you have a PDP with 22 bit C addressing (i.e. a PDP-11/70) then this program will NOT run C as is on your system. Also, if you do not have a TE16 drive C then modifications will be in order. I leave all modifications C to the prospective user since I do not have access to other C PDP systems. C C If you do have a PDP with 18 bit addressing and a TE16 tape C drive then please check the DEFINE module in LABWORK.MAC C to be sure the CSR's and addresses of the AR11 and the TE16 C tape drive are the same as the devices actually on your system. C If they are different then modify the variables to the proper C values. C C The tape handling routines are setup for speed so error C checking is non-existant (error checking takes time and time C could not be spared with my appliction). What this means is C that if you have a parity error on a tape write, you will C never know it, the routine will simply clear out the error C register and keep on truck'n! As a result you might end up C with a bad block on tape. However, I have not experienced C any problems yet as I have kept the tape heads clean and C used new tapes. C C While running this program at a sample rate of 4000 Hz I C noticed that we seemed to lose one sample every second. C Since the only thing that runs at once a second is the C Line Frequency Clock it was decided to stop it. The program C CLOCKS was written to turn the clock off and the problem C went away. CLOCKS can turn the Clock off or it can turn it C on and set it according to out systems TCU-150 time keeper. C For further information see the program CLOCKS. C C The data written to tape is not formatted. Thus to read C it back you can either use QIO's or you can make use of C the subroutine TAPEIO.MAC submitted on an earlier DECUS C symposium tape. TAPEIO.MAC is included on this UIC for C convience. C C TO BUILD : C Use the command file BLDLAB.CMD found in this UIC. C C TO RUN : C Make sure the KLAB series support is included in your system C If it isn't then you need to gen it in. This is required since C this program maps to the I/O page via the KCOM partition. C C Now issue the following commmand : C C >@GO ADORDA C (See GO.CMD for further information) C C When you want to stop the program simply set the front panel C switch #0 high. C C VARIABLES : C LEN - Length of the output data blocks. C ARRAY - Two dimensional buffer that accepts data from the C AR11. C BASADD - Base address of the first element of each column C of ARRAY (the first 16 bits). C EXTADD - Extended address of the first element of each column C of ARRAY (the upper 2 bits). C Note : The combination of BASADD and EXTADD gives a C full 18 bit address. C TCMASK - Tape control register mask used in TPBLTR. C WCMASK - Word count register mask used in TPBLTR. C FCMASK - Frame count register mask used in TPBLTR. C CSRMSK - Control and status 1 register mask used in TPBLTR. C RATE - User input sampling rate (in Hz). C RMSK - The mask that specifies the clock rate in the AR11's C Clock Buffer/Preset Register. C TICKS - The number of counts the clock takes before a sample C is read or written. This along with RMSK will yield C the desired sampling rate. C C SUBROUTINES : C ADRESS - This subroutine finds the physical memory address of C a variable passed to it. It is used to determine the C base and extended addresses of the first element of C each column of ARRAY. C INITAT - Initialize the mag tape registers, clear all errors, C and select the proper controller and formatter. C SETWRT - Initialize various register masks used in TPBLTR C for writting. C SETRED - Initialize various register masks used in TPBLTR C for reading. C TPBLTR - TApe BLock TRansfer routine. C A2DGO - AR11 Initialization routine for A/D operation. C D2AGO - AR11 Initialization routine for D/A operation. C INAR - AR11 Reading routine. C OUTAR - AR11 Writting routine. C C Author : Richard A. Crawford C E-Systems, Inc. C P.O. Box 1056 CBN-27 C Greenville, Texas 75401 C (214) 457-6018 C C Date : January 10,1984 C C Revisions : C 1.1 : January 18, 1984 - Make use of improved AR11 routines. C PARAMETER LEN = 1280 CHARACTER*1 ANS INTEGER ARRAY(LEN,2), BASADD(2), EXTADD(2) INTEGER TCMASK, WCMASK, FCMASK, CSRMSK(2) INTEGER RATE, TICKS, RMSK C C Suppress End-Of-File message : C CALL ERRSET(24,.TRUE.,.FALSE.,.TRUE.,.FALSE.,15) C C Determine which tape drive to use : C WRITE(5,110) 100 READ(5,*,END=500)IN 110 FORMAT(1X,$'Enter tape drive number (0 or 1) : ') IF(IN.NE.0.AND.IN.NE.1)THEN WRITE(5,120) GOTO 100 120 FORMAT(1X,$'Please enter 0 or 1 : ') END IF C C Find out whether to do an A/D or a D/A : C WRITE(5,140) 130 READ(5,150,END=500)ANS 140 FORMAT(1X,$'Do an A/D (A) or a D/A (D) : ') 150 FORMAT(A1) IF(ANS.NE.'A'.AND.ANS.NE.'D')THEN WRITE(5,160) GOTO 130 160 FORMAT(1X,$'Please enter "A" or "D" : ') END IF C C Find out the required sampling frequency : C WRITE(5,170) READ(5,*,END=500)RATE 170 FORMAT(1X,$'Enter the desired sampling rate (in Hz) :') C C Set preliminary rate mask and # ticks : C RMSK = 1 !Start with the 1 MHz clock rate TICKS = 1000000 / RATE !Number of ticks of the 1 MHz clock C C TICKS can only be an 8 bit number. If it is greater than 8 bits then C we need to slow the clock rate and get TICKS to 8 bits : C 180 IF(TICKS.GT.255)THEN TICKS = TICKS / 10 !Decrease TICKS by factor of 10 RMSK = RMSK + 1 !Slow clock by factor of 10 GOTO 180 END IF TICKS = -TICKS !Get 2's Complement RMSK = ISHFT(RMSK,1) !Put RMSK in proper position RMSK = IAND(RMSK,'000016'O) !Make sure only RMSK is in the mask D WRITE(5,190)RMSK, TICKS 190 FORMAT(1X,'RMSK, TICKS',O6,',',O6) C C Determine the physical memory starting address of the arrays : C CALL ADRESS( ARRAY(1,1), EXTADD(1), BASADD(1) ) CALL ADRESS( ARRAY(1,2), EXTADD(2), BASADD(2) ) C C Initialize the tape drive : C CALL INITAT(IN) IF(ANS.EQ.'A')THEN C C Get the proper tape register masks for writting : C CALL SETWRT(IN,LEN,EXTADD(1),EXTADD(2),TCMASK,WCMASK,FCMASK, 1 CSRMSK(1),CSRMSK(2)) C C Initialize the buffer selector : C NUM = 1 C C Let the user know we're starting A/D conversion : C WRITE(5,*)'Beginning A/D operation now' WRITE(5,*)'Set Front Panel Switch #0 high to stop' C C Start the AR11 and the clock going : C CALL A2DGO(TICKS,RMSK) C C Fill up array with data from the AR11 : C 200 CALL INAR( ARRAY(1,NUM), LEN ) C C Write the data to tape (1600 BPI) : C CALL TPBLTR(TCMASK,WCMASK,FCMASK,BASADD(NUM),CSRMSK(NUM)) C C Toggle the buffer selector : C IF(NUM.EQ.1)THEN NUM = 2 ELSE NUM = 1 END IF GOTO 200 ELSE C C Get the proper tape register masks for reading : C CALL SETRED(IN,LEN,EXTADD(1),EXTADD(2),TCMASK,WCMASK,FCMASK, 1 CSRMSK(1),CSRMSK(2)) C C Initialize the buffer selector : C NUM = 1 C C Let the user know we're starting D/A conversion : C WRITE(5,*)'Beginning D/A operation now' WRITE(5,*)'Set Front Panel Switch #0 high to stop' C C Start the AR11 and the clock going : C CALL D2AGO(TICKS,RMSK) C C Fill up array with data from the tape (1600 BPI) : C 220 CALL TPBLTR(TCMASK,WCMASK,FCMASK,BASADD(NUM),CSRMSK(NUM)) C C Write the data out the AR11 : C CALL OUTAR( ARRAY(1,NUM), LEN ) C C Toggle the buffer selector : C IF(NUM.EQ.1)THEN NUM = 2 ELSE NUM = 1 END IF GOTO 220 END IF C C Take care of ^Z input responses : C 500 WRITE(5,*)' ADORDA -- EXITING' CALL EXIT(24) !24 is EOF error message number END SUBROUTINE ADRESS(NUM,HI,LO) C C This subroutine finds the physical memory address of a variable C passes to it. It puts the 18 bit address into two variables. C The first variable LO contains the lower 16 bits of the address C and the other variable HI contains the upper 2 bits. C INTEGER NUM, HI, LO INTEGER*2 IBUF(0:2), TEMP(2) INTEGER*4 UPLOW EQUIVALENCE ( UPLOW, TEMP(1) ) C C Get the start address of the task (In 32 word increments) : C CALL GETREG(, IBUF, IDS) C C Convert the start address into bytes : C TEMP(1) = IBUF(0) UPLOW = JISHFT( UPLOW, 6 ) C C Get the address of NUM (Relative to the program C starting address) : C CALL GETADR( IADR, NUM ) C C Now calculate the absolute address of NUM : C UPLOW = UPLOW + IADR HI = TEMP(2) LO = TEMP(1) C C Make sure the LO is even and ensure that HI contains only the C upper two bits of the address : C LO = IAND( LO , '177776'O ) !Base address of NUM HI = IAND( HI , '3'O) !Extended address of NUM RETURN END