As might be gleaned by examining other documents available on this site, I have somewhat of an affinity for the absurd. In terms of outrageous applications for computers, I peaked early in my career, with the program you find below. This program, written in the fall of 1971, was a full-fledged operating system which transformed a UNIVAC 1108 mainframe computer worth millions of dollars into…a code practice oscillator! When idle, it played synthesised music generated by an algorithm invented by Harry Pyle and used in a little digital gizmo he built.
This program was written more than 20 years before audio hardware became a commonplace component of computers. Nonetheless, the UNIVAC 1108 maintenance panel included an “Audio” button. This was an obscure feature intended to be used in conjunction with the program alarm for debugging operating systems. It caused the program alarm, sounded by the ALRM instruction, to be gated by the guard mode bit in the processor state register. This resulted in an audible signal on the console when the operating system was in control, for example, because the system had gone idle.
A little experimentation (no button must go unpushed, after all) revealed that even if the program alarm was not sounding, an artifact of the circuit caused the program alarm speaker on the operator's console to emit a little “tick” every time the processor went into or out of guard mode. And that, of course, was a glitch big enough to permit generation of arbitrary tones, given a suitable program to flip guard mode on and off at the proper rate.
Since user programs always ran with guard mode on, that meant the tone generation trick had to be done by code in the operating system, or by a stand-alone operating system booted from tape. I chose the latter, in large part to compound the absurdity of the whole thing; very few UNIVAC programmers ever wrote stand-alone operating systems—they wrote user programs that ran under the operating system or modified components of the operating system itself, but few ever looked at the boot code in the system or contemplated writing their own. Shortly before I wrote this program, I had been involved in the development of the boot code for CHI/OS, an operating system being developed from scratch at Chi Corporation in Cleveland, so I was sufficiently familiar with low-level boot code to pull this off.
Despite its ridiculous intent, this was a fully general 1108 operating system which could be booted by any processor of a multiprocessor system, and into any memory module. On a multiprocessor system with a console on each processor, one could even boot multiple copies into different memory banks and enjoy stereo or three-channel sound. To my knowledge, nobody ever tried this. The 1108 console had a set of “selective jump” switches on the operator's console which could be tested by programs, so I used them to allow the user to set the speed at which the Morse code was transmitted. The code even adapted automatically when run on an 1106, which it detected by timing instruction speed against the hardware real-time clock. Unhappily, the successors of the 1108 and 1106 lacked the “Audio” feature, so the Morse code exec passed into history when the machines for which it was written retired from service.
The program was written so that, when executed in user mode, it wrote its own boot tape. Gosh it was cool, late at night, to type on the console and know that several million dollars of hardware were exclusively dedicated to making Morse code come out of the speaker. Folks familiar with user-mode 1100 programming will notice some oddities resulting from the fact that this code runs in the executive set of registers, which have different memory-mapped addresses when referenced in instructions. If you're hazy on the 1100 instruction set after all these years, check out the instruction set reference.
. . M O R S E / S Y N T H E S I Z E R E X E C . . OCTOBER 1971 BY JOHN WALKER . . YOU BOOT THE TAPE THIS THING WRITES INTO ANY MODULE THROUGH . ANY CHANNEL OR IOC PATH OF ANY PROCESSOR. BEFORE PUSHING START, PUSH . THE 'AUDIO' BUTTON ON THE MAINTENANCE PANEL (IT'S RIGHT BENEATH THE . PHASE LIGHTS, AND TO THE LEFT OF 'INITIAL LOAD'.) AFTER STARTING UP . THE PROCESSOR, BEHOLD THE MARVELOUS SOUND THAT ISSUES FROM THE ALARM . SPEAKER ON THE OPERATOR'S CONSOLE. . . AFTER YOU TIRE OF THAT, TRY TYPING ON THE CONSOLE. YOUR . INPUT WILL BE SENT BACK TO YOU IN MORSE CODE. THE SPEED OF THE MORSE . CODE IS SET BY THE BINARY VALUE IN THE JUMP KEYS 1-10 (1 IS THE LOW . ORDER BIT). THE JUMP KEYS ARE READ WHENEVER THE RETURN KEY IS HIT. . YOU MAY GET AS FAR AHEAD OF THE OUTPUT AS YOU LIKE. SETTING JUMP KEY . 15 WILL CAUSE INPUT TO BE QUEUED, AND TO BE SENT AFTER JUMP KEY 15 IS . TURNED OFF. IF YOU TYPE NOTHING FOR 10 SECONDS AFTER OUTPUT CEASES, . THE SYNTHESIZER WILL START AGAIN. TYPING A HAPPY-PUNCH (¤) WILL . IMMEDIATELY ABORT THE MORSE CODE AND START THE SYNTHESIZER. /. AXR$ R0 EQU 0100 . . 'HOW IT SOUNDS' CONSTANTS . RATE EQU ; HOW FAST TO SHIFT SYNTHESIZER REGISTER 100000 BSLENG EQU ; BASIC TIME INTERVAL FOR MORSE CODE 3 SYNPTC EQU ; SYNTHESIZER BASIC HIGH NOTE PITCH 250 MPITCH EQU ; COUNT FOR MORSE PITCH 1000 . . REGISTER DEFINITIONS . XR EQU 0140 EXEC REGISTERS BIAS . . . X2 *INTERRUPT REGISTER* . . X3 *INTERRUPT REGISTER* . . . A6 *INTERRUPT REGISTER* SIX EQU A7 1 IF RUNNING ON AN 1106 LENGTH EQU A8 LENGTH OF BASIC MORSE INTERVAL . . A9 TIMEOUT COUNTER FOR MORSE MODE BITS EQU A10 FEEDBACK SHIFT REGISTER BITS REGISTER PITCH EQU A11 PITCH COUNT FOR TONE SUBROUTINE . . A12 CONSOLE ACCESS WORD (ABSOLUTE) . . A13 ONE FOR MORSE MODE, ZERO FOR SYNTHESIZER . . A14 GUARD MODE OFF PSR . . A15 GUARD MODE ON PSR . CIP EQU R5 CONSOLE LOAD POINTER CDP EQU R6 CONSOLE DEPOSIT POINTER . DOT EQU '.'--' ' DASH EQU '-'--' ' . P PROC 0,1 UNGUARD* NAME 0 GUARD* NAME 1 DO P(0,0)=0 , ER 0 DO P(0,0)=1 , LMJ X2,TON END . P PROC 1 ORG* NAME 0 DO +(P(1,1)-$)<0 ,A0 EQU 08+(GOO )+3*RETID+(LA 100) RES P(1,1)-$ END . P PROC 0 TAG* NAME 0 * EQU $-O1000 END . P PROC 1,1 SCN* NAME 0 I$ 072,014,,,,P(1,1) END . S* FUNC . END $-O1000+S(1) . JKL* PROC 1,2 JK JKL(1,1),S(2) REMOVE THIS BIT ? ANA,U A6,1*/(JKL(1,1)-1) YES END . M* PROC *2 M$$1 NAME 0 DO +(M(2,1)**0770000000000)<0 , GO M$$2 M(2,1) EQU +(M(2,1)*/6)+' ' GO M$$1 M$$2* NAME 0 CH$*(M(1,1)) EQU M(2,1) END . P PROC 0,1 GEN* NAME 0 DO CH$(I-1)=0 ,CH$(I-1) EQU ' ' + CH$(I-1)--' ' END . $(1) LIT O1000 . /. BOOT TAG SCN A0+XR SAVE BOOT CHANNEL LA A0,040,A0 GET ACCESS WORD FROM BOOT SSL A0,15 SHIFT ALL BUT MODULE NUMBER OFF LSSL A0,15 GET BACK BOOT MODULE ADDRESS LX,U X1,,A0 MOVE IBANK BIAS TO X1 LSSL A0,9 SHIFT IBANK BIAS TO BI LXM,U A0,0177000 SET 65K BS LPS A0+XR LOAD UP NEW PSR NOP 5 WAIT FOR IT LA A14,A0+XR GET GUARD MODE OFF PSR AU A14,K1S29 ADD GUARD MODE BIT LA,U A13 CLEAR MORSE MODE LA A0,LMJINS GET TRAP INSTRUCTION SA A0,ISILOC PUT IN ISI INTERRUPT LOCATION LA A12,K1CDW LOAD CONSOLE ACCESS WORD AA A12,X1+XR ADD BASING LR CDP,K1CDBUF LOAD CONSOLE DATA POINTER SR CDP,CIP INITIALIZE LOAD POINTER LA A0,K3BIG GET COUNT FOR SPEED DETERMINATION LA,U SIX CLEAR 1106 FLAG LR,U R0,2500 GET RTC COUNT FOR TIMING JGD A0,S(0) WAIT FOR A WHILE LA A0,R0 GET RTC COUNT LSSL A0,18 GET SIGN BIT AS FLAG JP A0,S(2) 1108 CAN FINISH IN ALLOTTED TIME LA,U SIX,1 1106 CANNOT. LICM 15,A12 BRING UP CONSOLE INPUT LA,U BITS,1 INITIALIZE BITS NON-ZERO LA LENGTH,ISNRAT GET INITIAL SENDING RATE TZ SIX IS IT AN 1106 ? SSL LENGTH,1 YES. FUDGE SENDING RATE AAIJ IDLE ENTER IDLE LOOP . NSI TAG LPS X0 RELOAD PSR AT INTERRUPT TIME AAIJ 0,X2 RETURN TO CODE . TOFF TAG LPS A14 RELOAD PSR WITH GUARD MODE OFF AAIJ 0,X2 RETURN . TON TAG LPS A15 LOAD GUARD MODE ON PSR AAIJ 0,X2 RETURN . TONE TAG GUARD . TURN ON GUARD MODE LR R4,PITCH GET PITCH CODE JGD R4,S(0) WAIT WITH IT ON UNGUARD . TURN OFF GUARD MODE LR R4,PITCH RELOAD PITCH CODE JGD R4,S(0) WAIT WITH IT OFF JGD A0,TONE DO FOR TONAL DURATION J 0,X11 RETURN TO CALL . ISIIM TAG SCN A6+XR GET INTERRUPTING CHANNEL NUMBER TE,U A6,15 IS IT THE CONSOLE ? PAIJ NSI NO. IGNORE THE INTERRUPT LPS A14 LOAD GUARD MODE OFF PSR NOP 8 ALLOW IT TO COME INTO EFFECT LA A6,CDW GET CONSOLE POINTER LX X3,CDP GET CONSOLE POINTER TZ A13 ARE WE IN MORSE MODE ? J QCI YES. QUEUE INPUT LA,U A13,1 NO. SET MORSE MODE SA A6,,*X3 PUT CHARACTER IN BUFFER SX X3,CDP UPDATE POINTER LICM 15,A12 BRING CONSOLE BACK UP AAIJ MORSE ENTER MORSE ROUTINE . QCI TAG TNE,U A6,'¤' IS IT ABORT CHARACTER ? PAIJ ABORT YES. TERMINATE MORSE OUTPUT TE,U A6,'#' IS IT NEW LINE ? TNE,U A6,'^' IS IT A CARRIAGE RETURN ? PAIJ COMPUTE YES. COMPUTE OUTPUT SPEED SA A6,,*X3 PUT CHARACTER IN BUFFER SX X3,CDP UPDATE POINTER RTN TAG LICM 15,A12 BRING INPUT BACK UP LX X2,X2+XR GET ADDRESS OF INTERRUPT PAIJ NSI RETURN TO INTERRUPTED INSTRUCTION . ABORT TAG LA A0,K1CDBUF RELOAD BUFFER POINTER SA A0,CDP PUT BACK IN BUFFER SA A0,CIP RESET LOAD POINTER ALSO LA,U A13 CLEAR MORSE MODE LICM 15,A12 RESET INPUT ACCESS WORD AAIJ IDLE ENTER IDLE SYNTHESIZER . . RECOMPUTE SPEED . COMPUTE TAG LA,U A6,1*/10-1 GET ONE BITS I DO 10 , JKL I MSI,U A6,BSLENG MULTIPLY BY BASE LENGTH TZ SIX IS IT AN 1106 ? SSL A6,1 YES. FUDGE LENGTH SA A6,LENGTH SAVE LENGTH PAIJ RTN BRING BACK INPUT, RETURN TO PROCESSING . . FEEDBACK SHIFT REGISTER MUSIC SYNTHESIZER . IDLE TAG LA A0,K1SEC ONE SECOND DELAY JGD A0,S(0) WAIT A WHILE IDLOOP TAG LA A0,BITS GET CURRENT BITS AND,U A0,1*/4 AND OFF FIFTH BIT LA A2,A1 SAVE ANDED VALUE JNB A0,S(2) SHIFTING OUT A BIT ? XOR,U A1,1*/4 YES. FLIP FIFTH BIT SSL A0,1 SHIFT RIGHT ONE PLACE JZ A2,S(2) ONE BIT TO SHIFT IN ? AA,U A0,1*/8 YES. SHIFT IN THE BIT SA A0,BITS UPDATE BITS DSL A0,36+5 ISOLATE HIGH BITS LA,U A0,SYNPTC LOAD PITCH BASE FOR SYNTHESISER AA,U A1,1 INSURE BITS NOT ZERO MSI A0,A1 COMPUTE FINAL PITCH TZ SIX IS IT AN 1106 ? SSL A0,1 YES. USE HALF THE COUNT SA A0,PITCH SAVE PITCH LA,U A1,RATE GET BASE RATE COUNT LA,U A0 CLEAR A0 DI A0,PITCH COMPUTE NUMBER OF TIMES THRU LOOP TZ SIX ARE WE ON AN 1106 ? SSL A0,1 YES. HALVE THE COUNT LMJ X11,TONE GENERATE TONE J IDLOOP COMPUTE NEXT TONE . . INTERRUPT LOCATIONS . ORG 0217 DAY CLOCK INTERRUPT LMJ X2,NSI IGNORE IT ORG 0220 ISI INPUT MONITOR ISILOC TAG NOP 4 SET TO IGNORE BOOT INTERRUPT ORG 0231 REAL TIME INTERRUPT LMJ X2,NSI IGNORE IT ORG 0242 ER INTERRUPT LMJ X2,TOFF TURN OFF GUARD MODE . ORG 0300 . . MORSE CODE GENERATOR . MORSE TAG LA A0,K1SEC ONE SECOND DELAY JGD A0,S(0) MAKE TRANSITION GENTLE LA,U A9 CLEAR TIMEOUT COUNTER LA,U A2,MPITCH GET PITCH CODE FOR MORSE TZ SIX IS IT AN 1106 ? SSL A2,1 YES. CUT LOOP COUNT IN HALF SA A2,PITCH SET UP PITCH MLOOP TAG JK 14,S(0) JK 14: QUEUE INPUT PAIJ S(1) PREVENT INTERRUPTS LA A0,CIP GET INPUT POINTER TNE A0,CDP IS IT EQUAL TO THE DEPOSIT POINTER ? AAIJ EMPTY YES. NOTHING TO OUTPUT AAIJ S(1) ALLOW INTERRUPTS LA A1,,*A0 GET THE NEXT CHARACTER TO OUTPUT LA,U A9 CLEAR 'CHARACTER GET FAILED' SA A0,CIP RESTORE INPUT POINTER TNE,U A1,' ' IS IT A SPACE ? J EWORD YES. GENERATE END-OF-WORD PAUSE LA A1,MTABL,A1 CONVERT FIELDATA TO MORSE CODE MOLOOP TAG LA,U A0 CLEAR 'DOT OR DASH' LDSL A0,6 SHIFT NEXT CODE INTO A0 JZ A0,ELETTR GO TO END OF LETTER PROCESSING TE,U A0,DOT IS IT A DOT ? J DASHP NO. MUST BE A DASH LA A0,LENGTH GET MORSE TONE LENGTH LMJ X11,TONE SOUND OFF EBIT TAG LA A0,LENGTH GET LENGTH CODE MSI,U A0,MPITCH*2 COMPUTE EQUIVALENT LOOP COUNT FOR JGD A0,S(0) ALLOW ONE TIME INTERVAL TO PASS J MOLOOP PROCESS NEXT DOT OR DASH . DASHP TAG LA A0,LENGTH GET DOT LENGTH MSI,U A0,3 DASH IS THREE TIMES LONGER LMJ X11,TONE SEND THAT TONE J EBIT JOIN PROCESSING FOR END-OF-BIT . ELETTR TAG LA A0,LENGTH GET BASIC LENGTH MSI,U A0,3*MPITCH*2 GET DASH'S WORTH OF SILENCE JGD A0,S(0) ALLOW THAT MUCH TIME TO PASS J MLOOP GET NEXT CHARACTER . EWORD TAG LA A0,LENGTH GET BASIC LENGTH MSI,U A0,6*MPITCH*2 GET TWO DASHES OF LENGTH JGD A0,S(0) TWO DASHES BETWEEN WORDS J MLOOP PROCESS NEXT CHARACTER . EMPTY TAG AA,U A9,1 BUMP NUMBER OF FAILURES TLE A9,K5BIG IDLE TOO LONG ? J MLOOP NO. TRY AGAIN JK 14,S(2) IGNORE TIMEOUT ? PAIJ ABORT NO. GO BACK TO SYNTHESIZER LA,U A9 CLEAR TIMEOUT J MLOOP ENTER MORSE MODE. . . MORSE TABLE INITIALIZATION . . REF. ARRL HANDBOOK, 1950 EDITION . M 'A' '.-' M 'B' '-...' M 'C' '-.-.' M 'D' '-..' M 'E' '.' M 'F' '..-.' M 'G' '--.' M 'H' '....' M 'I' '..' M 'J' '.---' M 'K' '-.-' M 'L' '.-..' M 'M' '--' M 'N' '-.' M 'O' '---' M 'P' '.--.' M 'Q' '--.-' M 'R' '.-.' M 'S' '...' M 'T' '-' M 'U' '..-' M 'V' '...-' M 'W' '.--' M 'X' '-..-' M 'Y' '-.--' M 'Z' '--..' M '1' '.----' M '2' '..---' M '3' '...--' M '4' '....-' M '5' '.....' M '6' '-....' M '7' '--...' M '8' '---..' M '9' '----.' M '0' '-----' M '.' '.-.-.-' M ',' '--..--' M '?' '..--..' M '/' '-..-.' M ';' '-.-.-.' M 072 '.----.' M ':' '---...' . . FIELDATA TO MORSE CODE CONVERSION TABLE . MTABL TAG I DO 64 , GEN . CDBUF EQU 02000 START OF CONSOLE DATA CDW TAG * 0 DATA WORD FOR CONSOLE INPUT K1S29 TAG * 1*/29 LMJINS TAG LMJ X2,ISIIM K1CDW TAG * 1,CDW K1CDBUF TAG * 1,CDBUF K3BIG TAG * 300000 ISNRAT TAG * BSLENG*(1*/3) K1SEC TAG * 1250000 K5BIG TAG * 500000 ORG 01777 INSURE ENOUGH CORE ALLOCATED $(2). WRITE LA,U A0,WRPKT LOAD PACKET ADDRESS ER IOW$ ER EXIT$ WRPKT 'BOOTFILE' * 0 F FORM 6,6,24 F 0,W$,0 * 02000,O1000 END WRITE
UNIVAC has been, over the years, a registered trademark of Eckert-Mauchly Computer Corporation, Remington Rand Corporation, Sperry Rand Corporation, Sperry Corporation, and Unisys Corporation.