Tag: Apollo software

Il codice sorgente dell’AGC

Il codice sorgente dell’AGC montato a bordo del CM e del LM per la missione Apollo 11, da circa dieci anni è liberamente disponibile e consultabile grazie al lavoro di Chris Garry, ex dipendente della NASA, che ha dedicato tempo a scansire e copiare i sorgenti in formato testuale (con estensione agc) e pubblicarli in un repository sulla piattaforma GitHub.

Dark Mode

Apollo-11 (this link opens in a new window) by chrislgarry (this link opens in a new window)

Original Apollo 11 Guidance Computer (AGC) source code for the command and lunar modules.

Puntando il browser all’indirizzo qui sopra si apre il repository nel quale si tovano due directoy principali con i commenti dei programmatori originali.:

  • Comanche055: il quale contiene il codice sorgente Colossus 2A (CM)
  • Luminary099: il quale contiene il codice sorgente Luminary 1A (LM)

Il linguaggio mnemonico usato si chiama YUL (assembler) il cui formato di ogni istruzione rispecchia la sintassi

<etichetta> <istruzione> <commento>

I token <etichetta> e <commento> sono opzionali. Il seguente estratto ad esempio:

ERRORS          INHINT
                CA      Q
                TS      SFAIL           # SAVE Q FOR FAILURE LOCATION

preso dal file AGC_BLOCK_TWO_SELF-CHECK.agc è costituito da tre istruzioni (una per riga). La prima riga rispecchia la sintassi <etichetta> <istruzione> e possiede il seguente significato:

  • ERRORS: nome dell’etichetta, ovvero riferimento di rimando nel codice.
  • INHINT: istruzione, per disabilitare le interruzioni. Nell’AGC tutti i task che richiedevano una temporizzzazione critica o lavoravano con dati in aree di memoria sensibili dovevano disabilitare le interruzioni per consentire loro di portare a termine il task in un periodo di tempo noto.

La seconda riga contiene solo il token <istruzione> con il seguente significato:

  • CA Q: azzera l’accumulatore e aggiungi il contenuto del registro Q (registro di stash).

La terza riga ha il formato <istruzione> <commento> e possiede il seguente significato:

  • TS SFAIL: Trasferisci il contenuto dell’accumulatore nella locazione di memoria SFAIL

Come descrive il commento (la stringa che segue #), queste tre istruzioni nel complesso mostrano la procedura di salvataggio dati e disabilita gli interrupt all’inizio della subroutine ERRORS.  In caso di cambio di contesto l’AGC non aveva la possibilità di gestire lo stack, quindi tutti i passaggi per il salvataggio di registri dovevano essere gestiti dal programmatore. In generale all’interno del codice sorgente si trovano numerose annotazioni dei programmatori dell’epoca che descrivono le funzioni dei singoli comandi o blocchi di codice. Questo accorgimento è considerato anche oggi una buona prassi di programmazione a patto di accompagnare il codice con commenti pertinenti. I commenti che si trovano nei sorgenti dell’AGC sono invece molto vari: alcuni commenti sono un po’ poetici e mostrano la creatività degli autori e vanno oltre il linguaggio tecnico .


Sebbene il listato originale sia costituito come un blocco monolitico ovvero come un unico blocco funzionale, nel repository l’autore lo ha riorganizzato in moduli al fine di migliorarne la leggibilità. Per un’analisi del listato si consiglia di partire dai file seguenti:

  • file MAIN.agc di ogni modulo (Luminary e Comanche) che spiega come è strutturato il codice. Ognuno di questi due moduli contiene la suddivisione logica in moduli funzionali del software con le pagine di rimando nel caso di una ricerca veloce all’interno dello stesso. Qui sotto per esempio c’e un estratto del MAIN.agc del Luminary (Colossus 2A)
$ASSEMBLY_AND_OPERATION_INFORMATION.agc         # pp. 1-27
$TAGS_FOR_RELATIVE_SETLOC.agc                   # pp. 28-37
$CONTROLLED_CONSTANTS.agc                       # pp. 38-53
  • file CONTACT_AND_APPROVALS.agc che contiene le informazioni generali del progetto. In testa al file nella maschera d’intestazione si legge il seguente commento:
#         SUBMITTED:    MARGARET H. HAMILTON              DATE:  28 MAR 69
#             M.H.HAMILTON, COLOSSUS PROGRAMMING LEADER
#             APOLLO GUIDANCE AND NAVIGATION

La maschera contiene le informazioni generali circa la descrizione del software, alcune indicazioni sulla struttura, il team di sviluppo e la storicità del sorgente.

  • file  ASSEMBLY_AND_OPERATION_INFORMATION.agc (Colossus 2A) contiene la suddivisione logica in moduli funzionali del software con le pagine di rimando nel caso di una ricerca veloce all’interno dello stesso. Un file analogo è presente anche per il Luminary.
  • file ASSEMBLY_AND_OPERATION_INFORMATION.agc elenca i nomi (NOUNS) e verbi (VERBS) che l’AGC era in grado di processare. L’AGC infatti era in grado di accettare ed interpretare i comandi impartiti dagli astronauti interagendo con l’interfaccia DSKY secondo la sintassi:

<VERB> <NOUN>

Sia VERB che NOUN sono stringhe identificate da un codice univoco a due cifre. Ad ogni codice viene associato un comando (VERB) seguito (eventualmente) da un parametro specifico di quel comando (NOUN).

# NORMAL NOUNS                             COMPONENTS   SCALE AND DECIMAL POINT         RESTRICTIONS

# 00    NOT IN USE
# 01    SPECIFY MACHINE ADDRESS (FRACTIONAL)    3COMP   .XXXXX FOR EACH
# 02    SPECIFY MACHINE ADDRESS (WHOLE)         3COMP   XXXXX. FOR EACH
# 03    SPECIFY MACHINE ADDRESS (DEGREES)       3COMP   XXX.XX DEG FOR EACH

Più in basso c’è l’elenco dei verbi:

# REGULAR VERBS

# 00 NOT IN USE
# 01 DISPLAY OCTAL COMP 1 IN R1
# 02 DISPLAY OCTAL COMP 2 IN R1
# 03 DISPLAY OCTAL COMP 3 IN R1
# 04 DISPLAY OCTAL COMP 1,2 IN R1,R2

All’interno del progetto i seguenti moduli software sono particolarmente importanti:

  • BURN_BABY_BURN—MASTER_IGNITION_ROUTINE.agc esso contiene la sezione incaricata di inizializzare e controllare l’accensione del motore per la gestione dell’APS (programm P42), DPS (programma P40), PDI (programma P63) a l’ascesa dalla superficie lunare del LM (programma P12).
  • ALARM_AND_ABORT.agc contiene le routine di gestione degli errori (P00DOO, BAILOUT)

Lo screenshot seguente invece è estratto dal modulo LUNAR_LANDING.agc (Luminary 1A):

P63SPOT3        CA      BIT6            # IS THE LR ANTENNA IN POSITION 1 YET
                EXTEND
                RAND    CHAN33
                EXTEND
                BZF     P63SPOT4        # BRANCH IF ANTENNA ALREADY IN POSITION 1

                CAF     CODE500         # ASTRONAUT:    PLEASE CRANK THE
                TC      BANKCALL        #               SILLY THING AROUND
                CADR    GOPERF1
                TCF     GOTOPOOH        # TERMINATE
                TCF     P63SPOT3        # PROCEED       SEE IF HÈS LYING
P63SPOT4        TC      BANKCALL        # ENTER         INITIALIZE LANDING RADAR
                CADR    SETPOS1

                TC      POSTJUMP        # OFF TO SEE THE WIZARD...
                CADR    BURNBABY

Esso esegue il controllo della lettura del Landing Radar (LR) per l’allunaggio. L’algoritmo implementato è il seguente:

  1. Controlla se il radar è in posizione leggendo lo stato dal bit 6 del canale I/O33 dove viene memorizzato lo stato del radar.
    • In caso affermativo salta alla locazione P63SPOT4 per l’inizializzazione
    • altrimenti lancia la routine GOPERF1 per visualizzare sul DSKY il messaggio il cui valore è indirizzato dalla costante CODE500
      • Se l’astronauta digita il comando “TERMINATE”, trasferisci il controllo a P00 (stato di idle, in attesa di altri comandi) che si trova nel modulo FRESH_START_AND_RESTART.agc
      • Se digita il comando “PROCEED” torna al punto 1 e rileggi lo stato del radar.
  2. Esegui la routine SETPOS1 per inizializzare il LR, la routine POSTJUMP, e fai partire il motore del LM per iniziare la discesa (BURNBABY).

Un’ultima sezione interessante da analizzare riguarda la routine di calcolo delle funzioni trigonometriche. Per muoversi nello spazio l’uso delle funzioni trascendenti quali seno e coseno (così come il calcolo matriciale) sono fondamentali per l’implementazione degli algoritmi di navigazione. Qui si può trovare l’algoritmo implementato da Margaret Hamilton datato Marzo 1969 usato sia nel CM che nel LM e per comodità riportato anche qui sotto.

# SINGLE PRECISION SINE AND COSINE

		COUNT*	$$/INTER
SPCOS		AD	HALF		# ARGUMENTS SCALED AT PI
SPSIN		TS	TEMK
		TCF	SPT
		CS	TEMK
SPT		DOUBLE
		TS	TEMK
		TCF	POLLEY
		XCH	TEMK
		INDEX	TEMK
		AD 	LIMITS
		COM
		AD	TEMK
		TS	TEMK
		TCF	POLLEY
		TCF	ARG90
POLLEY		EXTEND
		MP	TEMK
		TS	SQ
		EXTEND
		MP	C5/2
		AD	C3/2
		EXTEND
		MP	SQ
		AD	C1/2
		EXTEND
		MP	TEMK
		DDOUBL
		TS	TEMK
		TC	Q
ARG90		INDEX	A
		CS	LIMITS
		TC	Q		# RESULT SCALED AT 1.

La routine (punto di ingresso SPCOS) calcola cos(\pi x) sfruttando l’equivalenza:

cos(\pi x)=sin(\pi (x + \frac{1}{2}))

A tal scopo la funzione somma \frac{1}{2} al valore iniziale x (nel registro A) quindi passa il controllo alla funzione SPSIN per il calcolo della funzione seno. Viene salvato il contenuto nella locazione temporanea TEMK per utilizzarlo in seguito nel calcolo del polinomio.

SINGLE PRECISION SUBROUTINE TEMPORARIES (3D)               
                # SPSIN, SPCOS, SPROOT VARIABLES.
                # DO NOT SHARE.  THESE ARE USED BY DAPS IN INTERRUPT
                # AND CURRENTLY ARE NOT PROTECTED.  IF OTHER USERS
                # MATERIALIZE, THEN THIS CAN BE CHANGED.
HALFY   ERASE
ROOTRET ERASE
SQRARG  ERASE
TEMK    EQUALS HALFY

Viene raddoppiato (DOUBLE) il suo valore (y_{a}) e chiamata la routine POLLEY tramite l’istruzione TCF. Lo scopo di POLLEY è calcolare y_{b}:

\begin{cases} y = x + \frac{1}{2} \\ y_{a} = 2 y  \\ y_{b} = \frac{1}{2} sin (\frac{\pi}{2} y_{a})  \end{cases}

tramite lo sviluppo in serie polinomiale di Taylor al quinto ordine (tre coefficienti).

Il blocco di codice racchiuso in SPT calcola:

y^{'} = \frac{1}{2} sin (\frac{\pi}{2} x) \approx 0.7853134 x - 0.3216147 x^{3} + 0.0363551 x^{5}
Confronto fra la funzione seno e con la stessa funzione ottenuta con lo sviluppo in serie di Taylor con tre coefficienti.
Per un’analisi dettagliata vedere: https://fermatslibrary.com/s/apollo-11-implementation-of-trigonometric-functions
Fonte: https://www.desmos.com/calculator/fmnu5rs6d6

I coefficienti di Taylor:

\begin{cases} C_{1} = 0.7853134  \\ C_{3}=−0.3216147 \\ C_{5}=0.0363551 \end{cases}

I coefficienti sono definiti nel codice nel seguente file: FIXED_FIXED_CONSTANT_POOL.agc

C1/2 DEC .7853134 # (OCTAL 31103)
…
C5/2 DEC .0363551 # (OCTAL 01124)
…
C3/2 DEC -.3216147 # (OCTAL 65552)

Essi non sono uguali a quelli che si otterrebbero con lo sviluppo in serie, tuttavia sono molto simili; questo perché gli ingegneri hanno ottimizzato i loro valori allo scopo di minimizzare l’errore di approssimazione nell’intervallo di utilizzo della funzione sul campo -1\leq x\leq 1.

Al termine di POLLEY viene nuovamente trasferito il controllo al programma chiamante ed il flusso di controllo procede con la chiamata alla routine ARG90, si sottrae LIMITS e si salva il risultato in virgola fissa, prima di ritornare il controllo al programma chiamante (TC Q).

Bibliografia

Per una descrizione più approfondita del codice di Margaret Hamilton, fare riferimento ai seguenti link in cui viene spiegato in maniera molto precisa e dettagliata.

Glossario istruzioni assembler

  • L’istruzione TCF lavora solo con indirizzi fissi e carica nel registro Z l’operando passato come parametro quindi trasferisce il controllo del programma alla locazione specificata dall’operando.
  • L’istruzione TC serve per impostare l’indirizzo di ritorno da una subroutine.
  • L’istruzione MP effettua la moltiplicazione (sempre in doppia precisione) con la parte alta in A e la parte bassa nel registro L. Il valore originale del moltiplicando viene perso.
  • L’istruzione XCH scambia il contenuto di A con il contenuto della locazione di memoria volatile specificata come parametro.
  • L’istruzione TS trasferisce il valore di A nella locazione di memoria volatile specificata come parametro.
  • L’istruzione CS azzera e sottrae l’operando passato come parametro al registro A.
  • L’istruzione DOUBLE raddoppia il contenuto di A.
  • Le istruzioni INDEX/EXTEND sono usate per l’accesso a tabelle/array tramite l’indicizzazione. Rappresenta un offset per l’accesso in memoria di un elemento.