Archive for the ‘UNIX’ Category

Steganografi och hemliga meddelanden

10/02/2022

Datorarkeologi, hemliga meddelanden.

Jag tror att rätt många barn som nyligen har lärt sig läsa har gjort sina egna hemliga alfabet där det vanliga latinska/nordiska alfabetet ersätts med ”hemliga tecken” så att meddelandet blir oläsligt. Alternativt kan man använda Cesars kryptering där man tänker sig alfabetet som två ringar där man förskjuter den ena med ett visst antal steg. Om vi antar att vårt vanliga alfabet är den första ringen och vi vrider kryptoalfabetsringen tillbaka ett steg så får vi ett kryptoalfabet där

Vanlig text    Krypterad text
a          --> b
b          --> c
osv.

Ett hemligt meddelande av denna typ är naturligtvis urenkelt att lösa. Med dator kan vi naturligtvis enkelt och snabbt testa alla kombinationer men också för hand går det snabbt att titta på tex. fördelningen av de vanligaste bokstäverna i det gissade språket i meddelandet vilket ger information om hur alfabetet skall förskjutas. Ett barns hemliga alfabet är likaså väldigt enkelt att läsa om vi har en vettig längd på meddelandet. Vi kan ur ordlängd etc. gissa bokstäver och rätt enkelt få fram det hemliga alfabetet.

Enkla substitutionsskiffer dvs. förskjutning av bokstäverna i alfabetet eller hemliga symboler i stället för det normala alfabetet är så enkla att lösa att man kan säga att ett meddelande som kodats på detta sätt egentligen endast visar att meddelandet inte är tänkt att läsas rakt upp och ner.

En intressant detalj är Stanley Kubricks film ”Ett rymdäventyr 2001” där skeppets tänkande dator heter ”HAL”. Av en slump 😉 så är HAL ordet IBM förskjutet en bokstav i riktning mot A d.v.s. IBM har kodats met ett Caesarskiffer försjutet endast ett steg i riktning mot A. Om man vill göra en textfil besvärlig att läsa men helt utan risk att man tappar lösenordet till texten så kan man koda en text med Unixverktyget rot13 som alltså förskjuter alfabetet med 13 steg. Säkerheten är lika med noll men det går inte att se vad texten innehåller bara genom att skumma av den med ögat.

Steganografi

Steganografi är tekniken att gömma ett meddelande tex inom ett skenbart oskyldigt meddelande. Antag att en medeltida krigsherre börjar ha slut på krutet och skickar ett meddelande till den egna kungen där han ber om 1500 kaggar fläsk, 20 kärror bröd … och på slutet konstaterar han krigståget måste avbrytas om han inte snabbt får mera mjöl, smör och salt … där den hemliga betydelsen kunde vara ‘mjöl=kol’, ‘smör=svavel’ och ‘salt=salpeter’ (de tre ingredienserna i svartkrut).

Under antiken kunde en kung t.ex. skicka en slav med ett hemligt meddelande så att håret rakades av huvudet på slaven varefter meddelandet skrevs på skalpen. Då håret hade vuxit ut skickades slaven till mottagaren som rakade av håret igen och läste meddelandet. Andra alternativ kunde vara att lägga in ett meddelande i ett bakat bröd … alternativen är många.

Vi såg i föregående inlägg hur man kan generera morsekod med hjälp av ett dataprogram. Ett kort meddelande, några ord, går på kanske 20 sekunder och ljudfilens längd är ungefär en miljon tecken. Antag att jag, den hemliga agenten, vill skicka en femsidig rapport till min uppdragsgivare utan att väcka uppmärksamhet. Jag kan då ta i bruk mitt morseprogram och regelbundet under en tid skicka t.ex. hälsningar till olika personer med morse. Meddelandet byts med någon dags mellanrum och fienden tittar på varje meddelande … men hittar inget.

Jag har redan tidigare, med tanke på användning för steganografi, modifierat både ljudfilerna och pauserna jag använder för att bygga upp meddelandena så att det finns brus i signalerna t.ex. med toppvärdet ungefär 8- bitar av den 16 bitars amplitud ljudfilen tillåter. Bruset ligger då på ungefär 0.5% vilket inte är speciellt störande.

Antag att jag vill skicka min rapport som innehåller 10000 tecken inbakad i morsesignalen. Min text består av tecken som alla ryms i en byte (8 bitar) som i sin tur ryms inom bottenbruset i min morsesignal. Jag behöver nu endast via någon annan kanal meddela min uppdragsgivare att ”Kom ihåg att gratulera den brittiska drottningen då hon fyller 100 år”. Hundra i detta meddelande betyder att jag byter ut vart hundrade talvärde i bruset i meddelandet mot en bokstav. Bruset kommer att öka marginellt men inte så att man enkelt hör skillnaden. Jag måste då skriva ett morsemeddelande som producerar en morse wav-fil med längden större än en miljon talvärden … enkelt.

Jag lägger ut den mixade morsefilen på den vanliga platsen för min morsehobby och min uppdragsgivare laddar ner filen och kör ett program som plockar ut vart hundrade talvärde i wav-filen och dumpar resultatet i en textfil som är min återskapade rapport.

Jag har alltså dolt en textrapport på 10000 tecken i ett oskyldigt morsemeddelande som gick på kanske 20-30 bokstäver. Notera att den sända dolda texten naturligtvis i sig kan vara krypterad innan den läggs till bruset i morsekoden. Det är naturligtvis självklart att texten inte behöver läggas in med 100 teckens intervall utan jag kan använda en slumptalsgenerator som genererar en lämplig slumptalssekvens som säger hur långt avståndet är mellan det hemliga dokumentets bokstäver. Det är också sannolikt att jag endast vill lägga in text i bruset i pauser inte i den reguljära sinusvågen jag använder som ljud eftersom det kan verka misstänkt in enstaka sampel ligger mycket nära noll då sinusvågen ligger nära ett. Jag kan hoppa över områden där jag har en morseton. Både jag och min uppdragsgivare måste naturligtvis kunna generera samma sekvens. Det är självklart att det enkelt går att gömma stora mängder text i en ljudfil som ovan men också självklart att det krävs en del funderande över hur man bäst döljer att det ligger ett meddelande inbakat i filen.

Bilden visar ljusrött brus med amplituden 0.125 (signalen har amplituden 1.0). Om vi antar att ljudfilen är kodad som 16-bitars PCM så kan vi lägga in data med ett största värde 8192 utan att vårt hemliga meddelande sticker ut på något sätt.

Digitalbilder innehåller också enorma mängder data. En modern digitalkamera producerar bilder vars storlek är tiotals megabyte d.v.s. tiotals gånger större än morseljudfilen. Varje bildpunkt innehåller information om tre olika färger och varje färg kodas i en eller flera byte. Det är självklart att jag kan koda information, om jag så vill i pixlar i bilden t.ex. så att jag modifierar färgdata så att jag modifierar en färg så att om färgens värde är ”jämnt” d.v.s. 2, 4, 6 … 254 så skall färgen tolkas som en etta d.v.s. en bit med värdet = 1. På motsvarande sätt kan jag koda en nolla så att jag modifierar ett färgvärde till ”udda” som då tolkas som en bit=0. Förändringarna jag behöver göra är extremt små och sannolikt odetekterbara speciellt som mitt meddelande matar in varierande bitar. Slutresultatet är en bild som ser helt normal ut men i vilken jag kan koda in mängder av dolda data. Olika typer av steganografiska metoder används idag till att koda in t.e.x. copyright information i bilden vilket gör att det i efterhand går att bevisa vem som ägde rättigheterna till bilden.

Notera att det inte är självklart att ovan beskrivna kodningar överlever packning. Om jag konverterar min morse ljudfil till mp3 formatet så kommer filen att packas ihop betydligt. En mp3 kodning är inte förlustfri vilket betyder att om jag packar upp filen tillbaka till wav så har sannolikt mitt hemliga meddelande också förstörts. Samma princip gäller bilder. Enkla hemliga kodningar kan förstöras av packning till något icke förlustfritt format.

En motståndare som försöker hitta mina dolda meddelanden skulle sannolikt bli mycket misstänksam om jag ibland skulle skicka mp3 morsemeddelanden och andra gånger wav meddelanden. Lösningen skulle naturligtvis vara att alltid skicka wav-filer som är opackade.

Antik datorteknik: Att skriva program på svenska

04/02/2022

Detta är en artikel i serien ”Antik datateknik”.

Jag kommer i denna artikel att visa hur jag enkelt kan skapa en svenskspråkig variant av programmeringsspråket C, språket kallar jag sv och kompilatorn blir då csv. Notera att avsikten med denna övning är att illustrera hur enkelt det vore att erbjuda en nationell nybörejarplattform för unga programmerare. För att verifiera programspråket sv skriver jag ett program som läser in en textsträng och sänder resultatet som morsekod. Morsekoden visas också i textform. Följande steg blir att undersöka vilka förändringar jag behöver göra i koden för att programmet skall fungera på min emulerade minidator PDP11/70 som kör en gammal BSD Unix 2.11 från början av 1990-talet. Unix utvecklades i tiden på minidatorn PDP11 som klarade av att hatera flera användare på olika terminaler allt detta på en maskin med 4 MB (4 miljoner byte) minne. En modern hemdator har typiskt 2000 gånger mera minne … eller ännu mer.

Kompilering av ett program skrivet i sv görs på någon sekund. Jag kompilerar morsesändaren smorse.sv dock utan filtyp eftersom mitt kompileringsskript förenklas en aning om jag inte behöver kontrollera filtypen utan kan anta att användaren vet vad hen gör.

./csv smorse
Källkod:smorse.sv
Översättaren är definierad i swe.lex
Kompilerar översätteren swe.lex till c-kod
Kompilerar lex analysatorn till körbar maskinkod: sv
Översätter sv-programmet smorse.sv till c-kod: smorse.c
C-kod finns nu i smorse.c
Kompilerar nu till körbar maskinkod!
The executable is: smorse.run

Jag kan nu köra programmet med smorse.run

Notera att morsesändningen i ljudfilen är en annan än på skärmen ovan. En utmaning för lyssnare är att bena ut vad som sänts!

Texten nedan visar hur ”kompilatorn” för språket sv är konstruerad. Jag skriver därefter programmet smorse i språket sv för att verifiera att kompileringen fungerar. Notera att programmet på min Linux-dator genererar hörbar morsekod. PDP11 har inte ljudstöd varför jag tänker generera ett simulerat magnetband som huvuddatorn kan sända som ljud.

En elev som lär sig att programmera kommer att stöta på flera samtidiga utmaningar. Vid programmering dyker det upp nya begrepp såsom ”variabel”, ”fil”, ”adress” och många andra begrepp som inte är bekanta från vardagslivet. Eleven lär sig också ett nytt språk, mycket enkelt dock, som beskriver logiken i programmet. Det språk som ligger under de flesta programmeringsspråk idag är engelska. Om vi börjar undervisa tex. en 10-12 årig elev programmering så kan engelskan som sådan vara ett visst problem som kan göra det svårare för eleven att komma över den första tröskeln in i programmeringens värld.

En enkel lösning på problemet programmering på ett främmande språk är naturligtvis att vi i inledningsaskedet skulle låta eleverna programmera på svenska/finska/norska/estniska för att därefter då grunderna finns gå över till engelska som idag är en de facto standard.

Skulle programmering på t.ex. svenska kräva våldsamma ekonomiska resurser? Är inte utveckling av ett nytt programmeringsspråk samt kompilator för det ”nya” språket extremt dyrt? Svaret är att en enkel tvåstegskompilator kan skrivas i ungefär hundra rader kod … inte dyrt alltså!

Om någon läsare är intresserad av att experimentera med språket sv eller modifiera det för något annat språk så kan det löna sig att ta kontakt via en kommentar så skickar jag alla filerna som ett paket med epost. Jag gör inte dessa förfrågningar synliga. Programlistningar på vebben tenderar att vara opålitliga vilket kan leda till onödig felsökning om man kopierar koden direkt från skärmen.

Språket ”sv” samt kompilatorn ”csv”

Min emulerade PDP11/70 minidator kör idag på mitt arbetsbord och jag måste således hitta på något vettigt leksaksprojekt. Jag kör BSD Unix v2.11 på PDP11:an vilket betyder att jag har tillgång till i princip samma programmeringsverktyg som på min huvuddator d.v.s. en kompilator för språket ”c” (kompilatorn heter cc) samt verktyget lex (lex har jag använt mycket sällan).

Ett trevligt miniprojekt kunde då vara att skapa ett svenskt programmeringsspråk som strukturellt är identiskt med programmeringsspråket ”c” under Unix/Linux. Tanken är att det skall vara möjligt att koda helt i ”sv” eller koda i en hybridmiljö där det är möjligt att använda ”c” direkt utan att programmets funktion påverkas. Tanken är att översätta ”sv” till normalt ”c” som därefter kompileras till maskinspråk som vilket normalt c-program som helst.

Fördelen med att använda c som mellanliggande språk är naturligtvis at jag inte behöver skriva den egentliga kompilatorn och maskinkodsgeneratorn (jag har för många år sedan skrivit ett komplett programmeringsspråk ”sil=simple language). Problemet är alltså att skriva en översättare från
språket sv till språket c.

Unix ger tillgång till två klassiska verktyg för att skapa kompilatorer
lex (lexical analyzer) och yacc (yacc=yet another compiler compiler). Jag har aldrig tidigare aktivt använt någondera. Programmet ”lex” kan enkelt sköta översättningen från sv till c d.v.s. jag behöver inte yacc eftersom min kompilator redan finns under förutsättning att det program lex producerar förmår att skapa kompilerbar c-kod.

Jag definierar ett antal ”REGLER” i lex som beskriver hur t.ex. ett nyckelord, en kommentar, en textsträng o.s.v. definieras. Då en regel passar in på källtexten skriver mitt genererade analysatorprogram ut motsvarande element för språket c.

Då jag skriver min översättare från sv till c i lex blir programmets längd ungefär hundra rader kod d.v.s. programmet är väldigt litet och överskådligt. Mitt sv-språk är i detta skede ett subset av språket c men redan i nedanstående form kan man skriva riktiga program i sv. Språket kan enkelt utvidgas genom att modifiera filen swe.lex. Då jag använder lex för att kompilera min definition av sv blir resultatet ett c-program som heter lex.yy.c . Jag kompilerar därefter lex.yy.c till ett körbart program sv som sköter översättningen av en källkodsfil i sv till motsvarande c-program.

Lex-program för översättning av sv till c

Filen swe.lex kan enkelt modofieras så att en större del av c-språket stöds. Notera att jag har skrivit swe.lex så att resulterande c-filen som ett sv-program översätts till har exakt samma antal rader som källkoden i sv. Detta betyder att då jag kompilerar mitt sv program så stämmer radnumren för felmeddelanden för både sv och c.

Min definition av sv-språket ser ut på följande sätt:

%{
/* A lexical analyzer for the computer language "sv". This is a simple translation */
/* of the "c" language into swedish. The corresponding "compiler" translates a */
/* sv-source into c-language that can be compiled using an ordinary c-compiler */
/* need this for the call to atof() below */
#include <math.h>
/* need this for printf(), fopen() and stdin below */
#include <stdio.h>
%}
WHITESPACE [ \t\n]+
DIGIT	  [0-9]
ID	  [a-zA-Z][a-zA-Z0-9]*
CHAR	  [a-zåäö][A-ZÅÄÖ][0-9][\ ][!?][\n]
COMMENT	  \/\/.*[\n]
STR1	  \".[\\]*\"
APP	  [\"]
LPAR	  [(]
RPAR	  [)]
LWAV	  [{]
RWAV	  [}]
TERMINATOR [;]
EXCL	  [!]
AE	  [Ä]
ae        [ä]
Aring	  [Å]
aring	  [å]

COMMA	  [,]

%%
{DIGIT}+		printf("%d",atoi(yytext));
{DIGIT}+"."{DIGIT}*	printf("%s", yytext);
{STR1}			printf("%s",yytext);
{LPAR}			printf("%s",yytext);
{RPAR}			printf("%s",yytext);
{LWAV}			printf("%s",yytext);
{RWAV}			printf("%s",yytext);
{EXCL}			printf("!");
{COMMA}			printf(",");
#inkludera		printf("#include");
#definiera		printf("#define");
program			printf("\nmain");
funktion		printf(" ");
resultat		printf("return ");
alternativ		printf("switch");
valt			printf("case ");
bryt			printf("break");
om			printf("if ");
medan			printf("while");
upprepa			printf("for");
annars			printf("else ");
skrivf			printf("printf");
skrivr			printf("printf");
fskrivf			printf("fprintf");
hämtarad		printf("getline");
hämta			printf("get");
sätt			printf("put");
läs			printf("read");
läsrd			printf("readln");
dröj			printf("delay");
heltal			printf("int ");
tecken			printf("char ");
byte			printf("byte ");
sanningsvärde		printf("boolean ");
register		printf("int");
bitmask			printf("int");
likamed			printf("==");
mindre_än		printf("<");
mindre_än_eller_likamed	printf("<=");
större_än		printf(">");
större_än_eller_likamed	printf(">=");
och			printf("&&");
binär_och		printf("&");
and			printf("&");
or			printf("|");
xor			printf("^");		
binär_exclusiv_och	printf("^\n");
vflytta			printf("<<");
hflytta			printf(">>");
storlek_t		printf("size_t");
\<\<			printf("<<");
\>\>			printf(">>");
=			printf("=");
\<			printf("<");
\>			printf(">");
\.			printf(".");
\&\&			printf("&&");
\&			printf("&");		
{ID}			printf("%s", yytext);
{TERMINATOR}		printf("%s",yytext);
{COMMENT}		printf("%s",yytext);
{WHITESPACE}		printf("%s",yytext);

"+"|"-"|"*"|"/"	printf("%s", yytext);
"{"[^}\n]*"}"	        /* eat up one-line comments */
%%
int main(int argc, char *argv[])
{
		++argv, --argc;	/* skip over program name */
		if (argc > 0)
			yyin = fopen(argv[0], "r");
		else
		yyin = stdin;
		yylex();
		return(0);
}

Verifiering av språket ”sv”

Ett enkelt sätt att visa att det nya språket ”fungerar” är naturligtvis att skriva ett riktigt program i
programspråket sv. Jag byggde för kanske tjugo år sedan några led-ficklampor med några barnhemsbarn där vi använde en liten mikroprocessor som programmerades i mitt språk ”sil” (simple language) för Microchips processor 16F84. Ficklamporna programmerades så att de olika barnens ficklampor kunde blinka ägarens namn i morsekod.

Nedan visar jag hur man kan skriva ett program i språket sv som läser in en textrad från användaren och
”sänder” texten som morsekod till skärmen men också som morseljud via datorns högtalare. Jag kommer att flytta programmet till PDP11 och något modifiera det så att PDP11 som saknar högtalare i stället skickar ett magnetband till huvuddatorn för sändning, detta beskrivs eventuellt i en senare artikel.

Morsesändare skriven i sv

En morseöversättare gör man enklast så att man tabellerar tecknen ”A-Z”, ”a-z” samt siffrorna 0-9 samt deras motsvarande teckenkoder. För en specifik bokstav vill vi alltså ha en översättarfunktion skrivMorse() av ungefär följande typ (ti=’*’ och taa=’-‘):

heltal skrivMorse(tecken c){
heltal i;
tecken morse[16];
alternativ (c){
valt ‘a’: strcpy(morse, ”-”); bryt;

valt ‘b’: strcpy(morse,”-”); bryt;
valt ‘c’: strcpy(morse,”–”); bryt;
valt ‘d’: strcpy(morse,”-”); bryt;
valt ‘e’: strcpy(morse,”*”); bryt;

}

skrivf(”Morsekod:%s\n”,morse);

Som indata till vår funktion ”skrivMorse” ges ett tecken/en bokstav ”c” vid anrop till funktionen. Resultatet av översättningen finns efter exekvering nu i variabeln ”morse”. Jag antar att funktionen är ganska läslig även för personer som inte kan programmera. Nyckelordet ”bryt” betyder att rätt alternativ hittades och exekveringen fortsätter vid ”skrivf(…). Om vi vill översätta bokstaven ”s” till morse så anropar vi vår funktion med:

skrivMorse(‘s’);

Resultatet skulle bli Morsekod:***

Vi börjar vårt egentliga program med att låta programmet be om en text att sända samt läsa in en textrad som innehåller texten. Funktionen skrivf() skriver ut text som kan formatteras för heltal, flyttal etc. Vi kan göra detta med:

skrivf(”Skriv text att sända som morse:”);
l=hämtaRad(&line,&len,stdin);

Kommandot ”hämtaRad” använder biblioteksfunktionen ”getline” som finns definierad i biblioteket stdio.h. Vi måste då komma ihåg att deklarera att vi använder biblioteket stdio.h . Vi inkluderar ett standardbibliotek med:

#inkludera <stdio.h>

Vårt program har nu ungefär följande utseende och det utför inte ännu något vettigt :

#inkludera <stdio.h>

#inkludera <stdlib.h>

#inkludera <string.h>

heltal skrivMorse(tecken c){
heltal i;
char morse[16];
alternativ (c){
valt ‘a’: strcpy(morse, ”-”); bryt;
valt ‘b’: strcpy(morse,”-**”); bryt;
… fler definitioner av morsekoder …
}
}

heltal program(){
heltal l=0;
storlek_t len=0;
tecken *rad=NULL;
skrivf(”Skriv text att sända som morse:”);
l=hämtarad(&rad,&len,stdin);
// Skriv ut den lästa raden för att verifiera att inläsningen lyckades
skrivf(”Inläst rad:%s\n”,rad);
}

Variablerna l, len och *rad behövs för anropet till hämtarad().

Då vi skriver in vår text som skall skickas så vill vi gärna hantera texten ordvis d.v.s. vi skickar ett ord i taget och genererar en standardiserad paus mellan orden. För att splittra up vår textsträng i separata ord inkluderar vi biblioteket string (#inkludera <string.h> se ovan). String-biblioteket har en användbar funktion strtok() som splittrar upp den text vi ger som funktionsparameter i en tabell med separata textsträngar (ordsträngar) separerade med mellanslag ‘ ‘. Råtexten bryts alltså vid mellanslag. Jag splittrar upp den ingående råtexten genast då jag deklarerar ordtabellen som jag kallar ett_ord:

tecken *ett_ord = strtok(rad,” ”);

Om jag har matat in texten ”Lasse skickar morse” så kommer ett_ord efter anrop att innehålla textsträngar som jag kommer åt med:

ett_ord[0] = ”Lasse”
ett_ord[1] = ”skickar”
ett_ord[2] = ”morse”

Vi kan nu skriva en ny funktion som vi kallar skicka_text_som_ord(”någon text …”) .

heltal skicka_text_som_ord(tecken rad[]){
heltal i;
tecken *ett_ord = strtok(rad,” ”);
medan (ett_ord != NULL){
skrivf(”Ord=%s\n”,ett_ord);
upprepa(i=0; i<strlen(ett_ord);i++){
// Skriv ett tecken i nuvarande ord
skrivMorse(ett_ord[i]);
system(teckenpaus);
skrivf(”\n”);
}
skrivf(”\n”);
ett_ord = strtok(NULL, ” ”);
}
}

Efter att vi splittrade upp råtexten i ord så tar vi ett ord i taget och splittrar upp det i bokstäver som skickas för konvertering till morse.

Vi går igenom alla orden i vår råtext med:

medan (ett_ord != NULL){
skrivf(”Ord=%s\n”,ett_ord);

}

Motsvarande konstruktion i språket c är ”while(ett_ord != NULL){ … }” .
Vi skickar vidare orden för sändning så länge som ett_ord inte är tomt (NULL).

Vi lägger nu till en slinga för att skicka iväg varje ord bokstav för bokstav för översättning till morse och sändning. Slingan har följande utseende:

upprepa(i=0; i<strlen(ett_ord);i++){
  // Skriv ett tecken i nuvarande ord
  skrivMorse(ett_ord[i]);
  system(teckenpaus);
  skrivf("\n");
}

Vi använder konstruktionen ”upprepa” som motsvarar c-språkets ”for” slinga.
Slingan går igenom ordsträngen ett_ord bokstav för bokstav tills vi har nått den fulla längden på strängen ett_ord.

Slingan stegar alltså igenom ett_ord på följande sätt:

i=0 ett_ord[i] = ‘L’ som skickas till skrivMorse(‘L’)
i=1 ett_ord[i] = ‘a’ som skickas till skrivMorse(‘a’)
i=2 ett_ord[i] = ‘s’ som skickas till skrivMorse(‘s’)
i=3 ett_ord[i] = ‘s’ som skickas till skrivMorse(‘s’)
i=4 ett_ord[i] = ‘e’ som skickas till skrivMorse(‘e’)

Efter att vi har skickat ett helt ord så håller vi paus genom att anropa operativsystemets funktion sleep.

Vi låter systemet sova i 0.7 sekunder mellan ord. Sovtiden mellan bokstäver är 0.1 sekunder.

Vi spelar upp ”tit” och ”taa” under Linux så att jag med hjälp av programmet ”Audacity” genererade en ton med frekvensen 880 Hz. Från denna ton klippte jag två stumpar 0.1 repektive 0.3 sekunder långa som jag sparade som ljudfilerna 0_1.wav samt 0_3.wav . Jag kan spela upp en wavfil under Linux med hjälp av programmet ”aplay”.

Programmet i dess helhet (under linux i detta skede) har då följande utseende:

// Morse
// Programspråket "sv" är språket "c" med svenska kommando-ord.
// Språket översätts till standard "c" som sedan kompileras till maskinspråk
// för att köras.
// Språket "sv" är egentligen ett experiment med Unixverktyget "lex" som 
// har konstruerats för att känna igen ord och strukturer i en text.
// Strukturer som hittas skulle normalt skickas vidare till programmet "yacc"
// (yet another compiler compiler = en annan kompilator kompilator).
// Eftersom jag översätter språket "sv" till "c" så behöver jag inte
// någon kompilator eftersom denna redan finns och likaså behöver jag inte
// någon kodgenerator som skulle generera maskinspråk eftersom även den redan
// finns. Notera att jag kan använda c-språk direkt om motsvarande
// sv-konstruktion inte har definierats.
// Notera att endast en delmängd av SV-C har skrivits. 
// Vill man ha en mera fullständig 
// motsvarighet så måste filen swe.lex utvidgas med nya nyckelord.
// Jag kör för närvarande en emulerad minidator PDP11/70 från 1970-talet.
// Operativsystemet är BSD Unix 2.11.
// Detta är ett experiment i att skriva ett enkelt svenskt 
// programmeringsspråk som är körbart på denna urgamla dator.   
// 
// Lars Silen 2022
// Detta är öppen källkod som fritt får distribueras
// Författaren tar inget ansvar för eventuella fel i genererad kod 

#inkludera <stdio.h>
#inkludera <stdlib.h>
#inkludera <string.h>

// Definiera tidslängden på olika element i Morse 
tecken teckenpaus[] = "sleep 0.1";
tecken ordpaus[] = "sleep 0.7";

heltal skrivMorse(tecken c){
  heltal i;
  char morse[16];
  alternativ (c){
    valt 'a': strcpy(morse, "*-"); bryt;
    valt 'b': strcpy(morse,"-***"); bryt;
    valt 'c': strcpy(morse,"-*-*"); bryt;
    valt 'd': strcpy(morse,"-**"); bryt;
    valt 'e': strcpy(morse,"*"); bryt;
    valt 'f': strcpy(morse,"**-*"); bryt;
    valt 'g': strcpy(morse,"--*"); bryt;
    valt 'h': strcpy(morse,"****"); bryt;
    valt 'i': strcpy(morse,"**"); bryt;
    valt 'j': strcpy(morse,"*---"); bryt;
    valt 'k': strcpy(morse,"-*-"); bryt;
    valt 'l': strcpy(morse,"*-**"); bryt;
    valt 'm': strcpy(morse,"--"); bryt;
    valt 'n': strcpy(morse,"-*"); bryt;
    valt 'o': strcpy(morse,"---"); bryt;
    valt 'p': strcpy(morse,"*--*"); bryt;
    valt 'q': strcpy(morse,"--*-"); bryt;
    valt 'r': strcpy(morse,"*-*"); bryt;
    valt 's': strcpy(morse,"***"); bryt;
    valt 't': strcpy(morse,"-"); bryt;
    valt 'u': strcpy(morse,"**-"); bryt;
    valt 'v': strcpy(morse,"***-"); bryt;
    valt 'w': strcpy(morse,"*--"); bryt;
    valt 'x': strcpy(morse,"-**-"); bryt;
    valt 'y': strcpy(morse,"-*--"); bryt;
    valt 'z': strcpy(morse,"--**"); bryt;
    // Lägg till ÅÄÖ här om du behöver dem

    valt 'A': strcpy(morse, "*-"); bryt;
    valt 'B': strcpy(morse,"-***"); bryt;
    valt 'C': strcpy(morse,"-*-*"); bryt;
    valt 'D': strcpy(morse,"-**"); bryt;
    valt 'E': strcpy(morse,"*"); bryt;
    valt 'F': strcpy(morse,"**-*"); bryt;
    valt 'G': strcpy(morse,"--*"); bryt;
    valt 'H': strcpy(morse,"****"); bryt;
    valt 'I': strcpy(morse,"**"); bryt;
    valt 'J': strcpy(morse,"*---"); bryt;
    valt 'K': strcpy(morse,"-*-"); bryt;
    valt 'L': strcpy(morse,"*-**"); bryt;
    valt 'M': strcpy(morse,"--"); bryt;
    valt 'N': strcpy(morse,"-*"); bryt;
    valt 'O': strcpy(morse,"---"); bryt;
    valt 'P': strcpy(morse,"*--*"); bryt;
    valt 'Q': strcpy(morse,"--*-"); bryt;
    valt 'R': strcpy(morse,"*-*"); bryt;
    valt 'S': strcpy(morse,"***"); bryt;
    valt 'T': strcpy(morse,"-"); bryt;
    valt 'U': strcpy(morse,"**-"); bryt;
    valt 'V': strcpy(morse,"***-"); bryt;
    valt 'W': strcpy(morse,"*--"); bryt;
    valt 'X': strcpy(morse,"-**-"); bryt;
    valt 'Y': strcpy(morse,"-*--"); bryt;
    valt 'Z': strcpy(morse,"--**"); bryt;
    // Lägg till åäö här om du behöver dem

    valt '1': strcpy(morse,"*----"); bryt;
    valt '2': strcpy(morse,"**---"); bryt;
    valt '3': strcpy(morse,"***--"); bryt;
    valt '4': strcpy(morse,"****-"); bryt;
    valt '5': strcpy(morse,"*****"); bryt;
    valt '6': strcpy(morse,"-****"); bryt;
    valt '7': strcpy(morse,"--***"); bryt;
    valt '8': strcpy(morse,"---**"); bryt;
    valt '9': strcpy(morse,"----*"); bryt;
    valt '0': strcpy(morse,"-----"); bryt;
    // Lägg till skiljetecken etc här
  }

  // Skriv bokstaven som sänds (finns som variabelparametern "c" vid anropet)
  skrivf("%c  ",c);
  skrivf("%s  ",morse);
  // Generera ljud 
  upprepa(i=0; i<strlen(morse);i++){
    om (morse[i] == '*'){
       skrivf("ti ");
       system("aplay -q 0_1.wav >/dev/null");
    } annars {
       skrivf("taa ");
       system("aplay -q 0_3.wav >/dev/null");
    } 
    // skrivf("\n");
  } 
}

heltal skicka_text_som_ord(tecken rad[]){
  heltal i;
  tecken *ett_ord = strtok(rad," ");
  medan (ett_ord != NULL){
    skrivf("Ord=%s\n",ett_ord);
    upprepa(i=0; i<strlen(ett_ord);i++){
      // Skriv ett tecken i nuvarande ord
      skrivMorse(ett_ord[i]);
      system(teckenpaus);
      skrivf("\n");
    }
    skrivf("\n");
    ett_ord = strtok(NULL, " ");
  }  
}

heltal program(){
  heltal l=0;
  storlek_t len=0;
  tecken *rad=NULL;
  skrivf("Skriv text att sända som morse:");
  l=hämtarad(&rad,&len,stdin);
  skicka_text_som_ord(rad);
}

Den genererade c-koden är strukturellt identisk med sv-programmets kod d.v.s. vi gör en ord för ord översättning. Detta betyder att c-kompilatorn ger felmeddelanden som pekar till rätt rad också i sv källkoden. Min editor bör naturligtvis konfigureras så att den visar radnummer för att felsökning skall vara effektiv.

Översättaren bör sannolikt expanderas med ytterligare c-konstruktioner. Det är oklart i hur hög utsträckning det är värt att översätta funktioner i bibliotek men exemplet ”hämtaRad” visar att detta naturligtvis är möjligt. Det är naturligtvis också möjligt att översätta namnen på standardbiblioteken på samma sätt men knappast vettigt eftersom målet är att eleven också bekantar sig med c-språket och dess bibliotek.

Oversättarprogram komplett:

#!/bin/bash
# Name=csv
# Detta är en kompilator för programspråket "sv" som är en svensk översätytning av språket "c".
# Språket "sv" kan enkelt utvidgas genom att modifiera filen "swe.lex".
# Användning: ./csv program           
#             Notera att källkoden antas vara program.sv .
#             Resultatet blir det körbara programmet program.run
#
# En textfil som är en översättning till språket "c" genereras som program.c .
# Lars Silen 2022
# Detta är fri källkod som fritt får användas och modifieras på egen risk.

echo "Källkod:"$1.sv
echo "Översättaren är definierad i swe.lex"
echo "Kompilerar översätteren swe.lex till c-kod"
lex swe.lex
echo "Kompilerar lex analysatorn till körbar maskinkod: sv"
gcc lex.yy.c -ll -o sv
echo "Översätter sv-programmet " $1.sv " till c-kod: " $1.c
./sv $1.sv >$1.c
echo "C-kod finns nu i " $1.c
echo "Kompilerar nu till körbar maskinkod!"
gcc $1.c -o $1.run
echo "The executable is:" $1.run

Notera att skriptet kompilerar om swe.lex varje gång. Användaren kan alltså enkelt lägga till
nya definitioner som blir en del av språket. Om användaren uppfattar att språkdefinitionen är stabil så kan man naturligtvis lämna bort raderna lex swe.lex samt gcc lex.yy.c -ll -o sv , tidsvinsten blir dock marginell.

Antik datorteknik, flytta filer över nätet

11/01/2022

I föregående inlägg visade jag hur jag kan använda en simulerad magnetbandstation för att flytta filer mellan min PDP11/70 och den Raspberry Pi som kör emuleringen. Systemet är något omständligt men det fungerar i princip till belåtenhet. Systemet kunde t.ex. användas till att flytta över källkoden till en lite trevligare editor till PDP11 och därefter kompilera den. Resultatet skulle vara en lite bekvämare arbetsmiljö.

Jag kan utan problem köra min PDP11 också från min ”huvuddator” d.v.s. bordsdatorn. Jag ansluter via SSH d.v.s. en krypterad dataförbindelse till Raspberry Pi och använder samma fönster till att logga in mig på PDP11. Detta betyder att jag kan jobba vid min stora bildskärm med ett ensamt terminalfönster in till PDP11. Om jag vill flytta data direkt från huvuddatorn till PDP11 utan att behöva logga in på Raspberry Pi för att fixa magnetbandet, hur gör jag då?

Det faktum att jag kan koppla upp mig till PDP11 via en SSH förbindelse till Raspberry Pi betyder självklart att jag har en fungerande nätverksförbindelse. Jag kan också kontrollera om min PDP11 syns på nätverket med hjälp av verktyget ”ping”:

ping 192.168.0.xxx

där 192.168.0.xxx är PDP11:ns IP-adress. PDP11 har en egen IP-adress trots att den kör ”inom” Raspberry Pi d.v.s. all dess IP trafik routas via Raspberry Pi. Om PDP11 svarar på en ping så betyder detta att nätverksförbindelsen i princip fungerar. PDP11 känner till kommandot ftp d.v.s. det borde vara möjligt att flytta filer direkt mellan huvuddatorn och PDP11 utan att Raspberry Pi behöver delta i operationen. En intressant detalj är att jag inte kan pinga PDP11 från Raspberry Pi d.v.s. det kort på vilket både Raspberry Pi och PDP11 kör. Däremot kan jag pinga PDP11 från min bordsdator som sitter på samma nätverk som Raspberry Pi. Problemet går att åtgärda men så långt har jag inte ännu hunnit.

En ftp server på min huvuddator

Jag började med att installera en ftp server på min huvuddator. Det finns ett antal varianter för Linux och jag valde att installera en server som heter VSFTPD. Jag kör Linux Mint som stöder denna ftp-server. Installationen gick behändigt med:

sudo apt update

Detta kommando uppdaterar Linux Mint katalog över tillgängliga applikationer.

sudo apt install -y vsftpd

Installation av ftp-servern från kommandoraden. Jag kunde likaväl ha använt ett grafiskt verktyg.

Konfiguration av servern görs i filen /etc/vsftpd.conf

sudo nano /etc/vsftpd.conf

Det lönar sig att googla på vsftpd om man behöver information om konfigurationen. Jag måste installera och konfigurera som superuser ”root” eftersom jag installerar vsftpd för alla användare på maskinen och konfigurationsfilerna i /etc är skrivskyddade eftersom jag inte vill att en eventuell besökare skall kunna gå in och konfigurera min maskin. För att jag skall kunna flytta filer från måste jag åtminstone editera /etc/vsftpd.conf så att jag tillåter skrivning till min katalog på deNeb. Detta kan jag göra genom att sätta write_enable=YES . Denna modifikation behövs om jag vill flytta filer från PDP11 till deNeb.

Flytta filer till/från PDP11

Min PDP11 representerar tidsperioden 1970 till slutet av 1990-talet. I praktiken betyder detta att de programverktyg jag har tillgång till kör i en textterminal inte i ett modernt grafiskt fönster som på min huvuddator. Det visar sig dock att man mycket bekvämt kan flytta filer mellan datorer direkt från kommandoraden på PDP11 utan att detta egentligen är komplicerat.

PTF-inloggning till min huvuddator från PDP11

Jag kopplar upp till min huvuddator ”deNeb” från PDP11. Situationen är intressant genom att det terminalfönster i vilket PDP11 kör finns på deNeb men är kopplad över en ssh-förbindelse. PDP11 kör alltså på Raspberry Pi men terminalfönstret finns på deNeb vilket man kan se i fönstrets rubrik.

Jag jobbar alltså i PDP11 och lägger upp en ftp-förbindelse till deNeb. Steg för steg gör jag:

ftp deNeb

Jag ger mitt användarnamn och password till deNeb för att släppas in i maskinen. Inloggningen är avklarad då jag får svaret ”230 Login successful”.

ftp>

Datorn kommer visa ftp> på varje rad för att indikera att jag har en aktiv ftp-förbindelse. I kommandona nedan är denna indikator bortlämnad. tex. följande kommando nedan kommer att i terminalen vara: ftp>cd Prog/PDP11 men användaren skriver endast cd Prog/PDP11 .

Jag ger nu ett kommando till ftp-servern att jag vill flytta mig till katalogen Prog/PDP11 på datorn deNeb från vilken jag vill hämta en textfil.

cd Prog/PDP11

Svaret blir ”250 Directory successfully changed”. Jag listar nu innehållet (ls) i katalogen dit jag flyttade mig på deNeb.

ls

Katalogen innehåller endast en fil med namnet deNeb.txt. Jag kan nu flytta filen från deNeb till PDP11 där jag kör mitt ftp-program med kommandor ”get”.

get deNeb.txt

… 226 Transfer complete.

Jag har nu flyttat filen till PDP11 och jag kan undersöka vad jag fick. Först går jag ut ur PDP11 med kommandot ctrl-D.

cat deNeb.txt
Resultatet blir:

This text document is moved from the Linux computer ”deNeb” to the emulated PDP11.

Filens innehåll är korrekt. Vi kan ladda in filen i texteditorn ”vi” och göra en liten förändring. Vi ändrar texten till: This text document is moved from PDP11 to ”deNeb”. Jag byter namn på filen till PDP11.txt så att jag kan verifiera att jag faktiskt har flyttat filen tillbaka till PDP11.

Vi kan nu flytta den modifierade filen tillbaka till deNeb genom att på nytt starta ftp på PDP11. Vi flyttar oss till katalogen Prog/PDP11 och använder ”put” för att flytta filen från PDP11 till deNeb.

Jag kan kontrollera vad jag har i min lokala katalog på PDP11 inifrån ftp-programmet genom att ge normala UNIX-kommandon som inleds med ”!”.

!ls
hello hello.c

På PDP11 har jag endast två filer i min arbetskatalog d.v.s. ett ”Hello world!” c-program och samma program i kompilerad körbar form.

Jag flyttar filen PDP11.txt till deNeb med ftpkommandot put PDP11.txt . Jag kan nu i ett annat terminalfönster kontrollera att filen faktiskt levererades korrekt.

Efter kommandot på PDP11 ser vi att vi har fått en ny fil på deNeb d.v.s. överflyttning i båda riktningarna lyckas utan problem.

Det är igen intressant att se hur jag utan större problem kan kommunicera mellan min huvuddator deNeb och en 30 år gammal UNIX. Det finns klara fördelar av att operativsystemen är nära besläktade. Jag tror inte att det hade varit riktigt lika enkelt att idag försöka sätta upp en förbindelse mellan PDP11 och t.ex. Windows 3.1 från 1992 …

Att köra en PDP11 dator från 1970-talet

05/01/2022

Jag har under en tid bekantat mig med en emulerad/simulerad PDP11 minidator från mitten av 1970-talet. PDP11 datorn var mycket populär innan IBM PC:n slog igenom och i praktiken sopade bort konkurrenterna mot slutet av 1980-talet då minidatorn PDP11 redan hade kring tjugo år på nacken. Konstruktionen kom att kopieras på olika håll bl.a. tillverkade man kopior i Sovjetunionen t.ex. Electronica 60 som jag tittade på i slutet av 1980-talet som alternativ för kontroll av mätsystem för export till Sovjetunionen. Jag jobbade aldrig med en rysk dator eftersom det visade sig att vi kunde kringgå exportrestriktionerna genom att byta ut en HP 9836 dator baserad på Motorola 68000 processor, som omfattades av amerikanska restriktioner, mot en standad 8 MHz långsam första generationens PC 8088. Jag kommer inte ihåg vilken tillverkares PC vi använde men detta är inte viktigt eftersom de olika PC:na var lika som bär. Lösningen var säkerligen bra eftersom Electronica 60 torde ha haft en hel del problem med pålitligheten. Det skulle dock ha varit roligt att ha fått konkret erfarenhet av dåtidens PDP11.

Den PDP11 jag skriver om är en emulerad PDP11/70 från ungefär 1975 som hörde till den tidsperiodens tungviktare använd som laboratoriepersondator. Datorn kunde köra UNIX och den orkade med flera användare eftersom en PDP11/70 med max minne på 4 MByte kunde stöda flera samtidiga användare. Användarna har under 2.11BSD Unix tillgång till något mer än 300 kByte minne vilket på den tiden var mycket. En PC som lanserades ett antal år senare kunde ha 64 kB – 256 kB (-640kB) för användare och operativsystem. Eftersom det normalt inte fanns något grafiskt användargränssnitt så var minnesbehovet litet och det gick att skriva stora program i 300 kByte. Dagens persondatorers behov av ett stort minne 2000-4000 ggr större än PDP11:ns är en följd av den mycket sofistikerade grafiken som kräver väldigt mycket minne utan att egentligen ge annat mervärde än bling bling. Samma kommentar gäller själva processorn som klockades på några megaherz. Moderna datorer kör med en klocka som tickar igen kanske 1000 ggr snabbare. Det intressanta är dock att då man håller sig till en text-terminal och använder kommandoraden så känns maskinen väldigt OK.

Hur emuleras en antik dator

Redan på slutet av 1960-talet d.v.s. för mer än 50 år sedan skrevs den första emulatorn MIMIC som bl.a. användes för testning och utveckling av nya datorkonstruktioner. 1993 startades projektet simH för att bevara minnet av ålderdomlig hårdvara och program. Den första generationens hårdvara höll snabbt på att försvinna och mängder av data som lagrats på magnetband riskerade att förstöras tex. 1960-talets data från månprojektet. Programmet simH emulerar en mängd gamla datorer bl.a.:

  • Data General Nova, Eclipse
  • Digital Equipment Corporation PDP-1, PDP-4, PDP-7, PDP-8, PDP-9, PDP-10, PDP-11, PDP-15 (and UC15), VAX11/780, VAX3900
  • GRI Corporation GRI-909, GRI-99
  • IBM 1401, 1620, 7090/7094, System 3
  • Interdata (Perkin-Elmer) 16b and 32b systems
  • Hewlett-Packard 2114, 2115, 2116, 2100, 21MX, 1000, 3000
  • Honeywell H316/H516
  • MITS Altair 8800, 8080 only
  • Royal-Mcbee LGP-30, LGP-21
  • Scientific Data Systems SDS 940
  • Xerox Data Systems Sigma 32b systems

Listan är inte fullständig.

Det är intressant att konkret se hur extremt mycket mera processorkapacitet vi har tillgång till idag, nästan gratis, än för femtio år sedan. En PDP11/70 kostade med fullt utbyggt minne mer än en högklassig ny personbil medan min på en Raspberry Pi emulerad PDP11/70 med maximalt minne en mängd operativsystem etc. kostar kanske 50E (500 SEK). Min emulerade maskin kör dessutom ungefär dubbelt snabbare än orginalet. Min Raspberry Pi har en kapacitet där RAM-minnet är 1000 ggr större än orginalet. Massminnet (skivminnet) är kanske 10000 ggr större och processorns hastighet är kanske 1200 ggr högre än orginalets. Ordlängden i PDP11 var 16 bitar medan en Raspberry Pi kör med ordlängden 64 bitar d.v.s. 4 ggr längre. Totalt kan man eventuellt säga att dagens lilla Raspberry Pi, beroende på vilken applikation man betraktar har en kapacitet som är mellan 1000 och 1000000 ggr högre än 1970-talets PDP11. Sannolikt ligger sanningen närmare 1000000 ggr än 1000 ggr …

Hello world

Min PiDP11/70 minidator i form av en modern mikrodator av typen Raspberry Pi model 3B. Notera att jag inte kör på den snabbaste varianten av Raspberry Pi. Valet av maskin att emulera PDP11 på gjordes utgående från vad jag råkade ha i miljonlådan … Raspberry Pi ligger på en fusklapp med kommandon man behöver för att använda den klassiska Unixeditorn ”vi” beskriven nedan.

Ett första test av en okänd dator och ifrågavarande dators programvara är ofta att skriva ett mycket kort program, kompilera det och sedan köra det. Sekvensen testar på ett allmänt plan att själva maskinen är någorlunda vettigt konfigurerad, det finns en fungerande text editor, kompilator (eller t.ex. basic tolk) samt förbindelse till bildskärm och tangentbord fungerar.

Jag har kört BSD Unix version 2.11 på min PiDP11. Alla någorlunda färska Unixvarianter är skrivna i programspråket ”c” och motsvarande kompilator heter cc (c compiler). I ett system som kör Unix brukar det alltid finnas en text editor som heter ”vi”. Editorn ”vi” är urgammal men förvånande kraftfull om användaren känner till den. Utmärkande för vi är att den är modal d.v.s. den har en kommandomod och en insättningsmod. I kommandomoden kan man med kursortangenterna och via andra tangentbordskommandon flytta sig i texten, ta bort text, söka text, byta ut text etc. Då man vill skriva text går man in i insättningsmod med kommandot ”i”. Då man vill tillbaka till kommandomoden så trycker man på ”ESC” tangenten.

Man sparar texten med kommandot ESC :w .

Man kommer ut ur programmet med kommandot ESC :q .

Avslutning så att texten sparas kan göras med kombinationen ESC :wq .

Att tvinga stängning av programmet kan man göra med ESC :q! .

Många Unixanvändare uppfattar att det enda ”vi” kommando man behöver känna till är ESC :q eftersom ingen människa med förståndet i behåll vill göra något annat än att snabbt ta sig ur editorn.

Terminalfänster från min bordsdator deNeb över nätet ner till PDP11/70. Programmet hello.c i listningen är skrivet med vi-editorn beskriven ovan.

Vi startar vi-editorn med kommandot ”vi hello.c” och kan då studera själva programmet som innehåller två utskriftskommandon som skriver ut textraderna

Hello world!
Another line!

Vi kompilerar programmet till körbar form d.v.s. maskinspråk med kommandot:

cc hello.c -o hello

Programmet körs med kommandot:

./hello

Och resultatet blir:

Kompilering av programmet hello.c . Vi ger tilläggsinformationen -o hello åt kompilatorn för att lagra resultatet i den körbara filen ”hello”. Standardnamnet på resultatet av compileringen skulle ha varit a.out vilket blir onödigt kryptiskt. Det körbara programmet körs därefter med kommandot ./hello . Orsaken till att jag skriver ./ före hello är att jag säger åt systemet att jag vill köra det program ”hello” som finns i den katalog i vilken jag befinner mig för tillfället. En Unix maskin brukar konfigureras så att man inte av misstag kör program i den katalog där man jobbar.

Jag nämnde ovan att många moderna Unixanvändare anser att det enda vi-commando man behöver känna till är ESC :q så att man med äran i behåll kan ta sig ut ur editorn. Problemet blir då hur jag skall skriva program om jag inte vill använda vi. Alternativet i 211BSD Unix på min PDP11/70 är editorn ”jove” som jag personligen har samma relation till som ”vi” d.v.s. jag vill ut ur den så snabbt som möjligt. Lösningen är naturligtvis att sätta upp kommunikation mellan min normala bordsdator eller laptop rill min PDP11 och då använda en modern editor i den moderna maskinen för att sedan flytta över program för kompilering på PDP11. Olika processer för att flytta över data mellan maskinerna presenteras i nästa avsnitt.

Datorarkeologi

10/12/2021

Dessa funderingar skrev jag som ett Facebook inlägg men de kan eventuellt intressera någon läsare på bloggen varför jag kopierar över inlägget också hit.

Jag bekantar mig med hur det känns att köra en dator från mitten av 1970-talet. Maskinen är en Digital PDP-11/70 minidator som kostade ca. $14000 då jag var en fattig student på Helsingfors Universitet. Det är fråga om en relativt sen variant med mycket centralminne som vid denna tid var RAM och inte ferritkärnminne.

Mycket centralminne i maxkonfiguration betyder 4 megabyte minne vilket dock skall jämföras med IBM:s första PC som kom ca. 10 år senare och rätt länge hade en max konfiguration på 640 kilobyte d.v.s. 1/6 av PDP-11. PDP-11 kördes ofta med tidsdelning d.v.s. flera terminaler var kopplade till samma maskin och flera personer kunde alltså samtidigt dela på maskinen.

Då jag i början av 1980-talet fungerade som data-assistent på Ammattikoulujen opettajaopisto i Tavastehus så hade man en, om jag kommer rätt ihåg, Eclipse Nova minidator (motsvarade ungefär PDP-11) som en hel dataklass i den tekniska skolan bredvid kompilerade Fortran mot … 20 elever per klass. Resultatet var att maskinen kroknade d.v.s. man kunde vänta flera minuter på något livstecken på den egna terminalen men maskinen kraschade inte! Resultatet var att jag skrev en del program på en åtta bitars CP/M maskin (som ungefär motsvarade en Commodore 64) som var härlig att jobba med eftersom jag hade tillgång till den helt ensam.

Min PDP-11/70 kostar idag ungefär 50E. Maskinen emuleras i en Raspberry Pi model 3 med 1 Gigabyte minne och 16 Gigabyte ”skivminne” på ett mikro sd-kort. Vid den här tiden hade en hårdskiva typiskt en kapacitet på 5-10 Megabyte d.v.s. 1/1000 av Raspberry Pi:s mikro SD korts kapacitet. Den lilla Raspberry Pi maskinen har en kapacitet som man sannolikt endast kunde drömma om på Tekniska högskolan på den tiden. På SD-kortet ryms mängder med operativsystem och program för PDP-11.

För tillfället kör jag BSD 2.11 från slutet av 1980-talet. Som linuxanvändare är det inget problem att köra BSD-unix. Kommandona, då man kör i terminal, är de samma. Ett grafiskt användargränssnitt saknas men jag kan köra grafiska program i en emulerad vektorgrafisk terminal på Linuxsidan i ett fönster.

Jag jobbar mot PDP-11 så att jag från min vanliga dator loggar in över nätet med ssh. Till planerna hör att då nästa sats komponenter fås fram så bygger jag en frontpanel med blinkande ledar med plats för Raspberry Pi. Det är främst strömbrytarna på fronten som ger problem, de är specialkonstruerade för den här byggsatsen för att möjligast väl matcha den ursprungliga modellen. Det är intressant att se att emuleringen är så exakt att det är möjligt att via ett adapterkort använda ursprungliga kort för en riktig PDP-11. Man har t.ex. kopplat in ett ursprungligt kärnminne (ferritringminne) och kört program från detta.

Man får en bild av den extrema utvecklingen på datorområdet då man jämför en modern Raspberry Pi med PDP-11 (jag använder en äldre Raspberry Pi modell 3 som jag råkade ha liggande). Raspberry Pi har fyra processorkärnor med ordlängden 64 bitar jämfört med PDP-11 som hade 16 bitar. Ordlängden som sådan betyder att RPi är kanske 4x effektivare och då vi har fyra processorer i RPi så kan processorn utföra 4x mera arbete.Ursprungligen så körde PDP-11 med en cykeltid på 800 ns vilket betyder en klockfrekvens på ca. 1,25 MHz vilket skall jämföras med RPi som klockas ca. 1000 ggr högre. Jag nämnde att PDP-11/70 hade ett maximalt minne på ca. 4 megabyte vilket skall jämföras med dagens RPi modell 4 som har 4 gigabyte (1000 ggr mer).

Om vi lägger ihop skillnaden mellan dagens 50Euros RPi och gårdagens $14000 minidator så ser vi att RPi totalt sett har en kapacitet som är ungefär 4x4x1000x1000 = 16 000 000 större än gårdagens PDP-11/70. Vi förstår också hur stor kapaciteten hos en Raspberry Pi är idag då vi noterar att jag kör Linux på RPi med grafiskt användargränssnitt och under Linux på RPi kör PDP-11 emulatorn SIMH som alltså låtsas vara en äkta PDP-11/70 och på den emulerade PDP-11/70:an kör jag BSD Unix v. 2.11. Den emulerade PDP-11/70 kör med ungefär dubbel hastighet mot orginalet!

En annan intressant jämförelse är att en normal Android mobiltelefon har ungefär samma hårdvara som en Raspberry Pi (eventuellt något bättre). Mobiltelefonen har alltså en total beräkningskapacitet som är miljoner gånger större än hos 1970-talets minidator. Största delen av processorkraften i dagens datorer/telefoner bränns dock på all världens bling bling och gårdagens maskin känns förvånande OK bara man inte tvingar den att rita ett grafiskt användargränssnitt med halvtransparenta fönster etc.

Jag kör ”adventure” som är ett textbaserat spel med något som påminner om Morias grottor i Sagan om ringen. Programmet körs under UNIX (BSD 2.11 som de facto är detsamma som BSD 4.3 med alla PDP-11 upgraderingar). Fönstret finns på min vanliga bordsdator som kör Linux och jag kopplar upp mot PDP-11/70 över nätverket med ssh.

Dagens ”Minidator” en Raspberry Pi model 3 emulerar gårdagens mycket använda Minidator PDP-11/70 i dubbel hastighet. Notera att det inte finns någon fläkt då Raspberry Pi förbrukar endast ca. 5W. Orginalet d.v.s. den riktiga PDP-11:n var högljudd eftersom hela maskinen ursprungligen var byggd från diskreta TTL-kretsar med mycket låg integrationsgrad. Senare modeller av PDP-11 hade processorer integrerade i en eller ett litet antal kretsar. Med högre integrationsgrad så minskade också strömförbrukningen.

Några källor:

Om någon är intresserad av att försöka sig på lödning så är detta ett relativt enkelt projekt:

https://obsolescence.wixsite.com/obsolescence/pidp-11-technical-details

Wikipedia har en rätt bra artikel om PDP-11:

https://en.wikipedia.org/wiki/PDP-11


Pointman's

A lagrange point in life

THE HOCKEY SCHTICK

Lars Silén: Reflex och Spegling

NoTricksZone

Lars Silén: Reflex och Spegling

Big Picture News, Informed Analysis

Canadian journalist Donna Laframboise. Former National Post & Toronto Star columnist, past vice president of the Canadian Civil Liberties Association.

JoNova

Lars Silén: Reflex och Spegling

Climate Audit

by Steve McIntyre

Musings from the Chiefio

Techno bits and mind pleasers

Bishop Hill

Lars Silén: Reflex och Spegling

Watts Up With That?

The world's most viewed site on global warming and climate change

TED Blog

The TED Blog shares news about TED Talks and TED Conferences.

Larsil2009's Blog

Lars Silén: Reflex och Spegling

%d bloggare gillar detta: