home *** CD-ROM | disk | FTP | other *** search
- {$A+,B-,D-,E-,F-,G-,I+,L+,N-,O-,P-,Q-,R-,S-,T-,V-,X-}
- {$M 16384,0,655360}
- (* ----------------------------------------------------------------------- *)
- (* DC.PAS *)
- (* Simulation eines einfachen didaktischen Computers "DC" *)
- (* Autor: Zbigniew Szkaradnik - Vers. 1.1 fuer DEC LSI-11 25-April-85 *)
- (* - Vers. 1.2 fuer JOYCE 10-Febr.-87 *)
- (* Modifikation und Implementierung (Vers. 1.3) von Michael Ceol fuer *)
- (* PC-/MS-DOS (Turbo Pascal), CP/M (Turbo Pascal), Atari ST (Pascal ST +) *)
- (* Sept. 87. Kurzanleitung siehe Datei "DC.HLP". Viel Spass.... *)
-
- (* 10-Minuten-Konvertierung auf Turbo 4-7 jb /3'94 *)
-
- PROGRAM Didactic_Computer;
-
- USES
- DOS, Crt;
-
- VAR
- Regs: Registers;
-
- CONST
- none = -1; null = 0; addr_start = 5; op_start = 1;
- addr_end = 10; op_end = 4; mnem_size = 3; word_size = 10;
- max_length = 30; mem_size = 63; winymin = 18; winymax = 24;
- instructions = 15; screen_lines = 25; sign_val = 512; sign_bit = 1;
- zero = '0000000000';
-
- TYPE
- dc_word = STRING[word_size]; op_str = STRING[op_end];
- mnem_str = STRING[mnem_size]; one_line = STRING[80];
- lines = STRING[max_length]; string2 = STRING[2];
- errors = (illcmd, illadd, illlab, illcod, illarg, illcon,
- loops, ovf, illfil, illhlp, break);
- mem_area = ARRAY [0..mem_size] OF dc_word;
-
- VAR
- end_of_program, out_cycle: BOOLEAN; inp_file: TEXT; esc: CHAR;
- command : (cl, instr, regr, step, run, go, tim, bpt, Int, ldf,
- other, hlp, view, ends);
- mode : (waiting, nowait, delaying);
- err : errors; memory : mem_area; Line : lines;
- item : ARRAY[1..3] OF lines;
- window : ARRAY[winymin..winymax] OF lines;
- mnems : ARRAY[0..instructions] OF mnem_str;
- op_codes: ARRAY[0..instructions] OF op_str;
- ar, pc, ac, dr, ir, sp: dc_word;
- address, counter, int_addr, break_addr, s_ptr,
- time, blink_num, blink_time, row, items, mempage, op_code: INTEGER;
- ve, he, ce, dle, dre, ule, ure, uhe, dhe, rve, lve, se, vd, led_on, dpc,
- led_off, wr, rd, sp2, ipc, pl, mi, sp1, u_arrow, d_arrow, bar, sl: string2;
-
- PROCEDURE RevOn; (* reverse (inverse) Textdarstellung an *)
- BEGIN
- TextColor(Black);
- TextBackGround(White);
- END;
-
- PROCEDURE RevOff; (* reverse (inverse) Textdarsetllung aus *)
- BEGIN
- TextColor(White);
- TextBackGround(Black);
- END;
-
- PROCEDURE CrsOn; (* Cursor einschalten *)
- BEGIN
- Regs.AX := $100;
- Regs.CX := 1543;
- Intr($10,Regs);
- END;
-
- PROCEDURE CrsOff; (* Cursor ausschalten *)
- BEGIN
- Regs.AX := $100;
- Regs.CX := 128 SHL 8;
- Intr($10,Regs);
- END;
-
- PROCEDURE Bell; (* einen Piepser ertoenen lassen *)
- BEGIN
- Write(Chr(7));
- END;
-
- PROCEDURE Exit_DC; (* alles wieder beim alten, wenn Programm beendet wird *)
- BEGIN
- ClrScr;
- GotoXY(1,1);
- RevOff;
- CrsOn;
- END;
-
- (* eine Datei zum Lesen oeffnen. Die I/O-Ueberwachung durch das Laufzeit- *)
- (* system wird dazu kurzzeitig deaktiviert (I- bzw. I+). Konnte die Datei *)
- (* geoeffnet werden, ist "Open_File" = TRUE, sonst FALSE. *)
- FUNCTION Open_File (filename: lines): BOOLEAN;
- BEGIN
- Assign(inp_file, filename);
- (*$I-*)
- Reset(inp_file);
- (*$I+*)
- Open_File := (IOResult = null);
- END;
-
- PROCEDURE Init_Sys;
- (* hier notfalls die entsprechenden ASCII-Codes Ihres Systems einsetzen: *)
- BEGIN (* Grafiksymbole, einfache Linien: *)
- ve := Chr(179); he := Chr(196); (* senkrechter, waagerechter Strich *)
- ce := Chr(197); (* Kreuz *)
- dle := Chr(217); dre := Chr(192); (* rechte untere, linke untere Ecke *)
- ule := Chr(191); ure := Chr(218); (* rechte obere, linke obere Ecke *)
- uhe := Chr(193); dhe := Chr(194); (* T-Stueck: nach oben, nach unten *)
- rve := Chr(195); lve := Chr(180); (* T-Stueck: nach rechts,nach links *)
- vd := Chr(186); (* senkrechte, doppelte Linie *)
- bar := Chr(179); sl := Chr(186); (* senkr. Strich: einfach, doppelt *)
- u_arrow := Chr(24); d_arrow := Chr(25); (* Pfeil nach oben, nach unten *)
- led_on := Chr(2); led_off := Chr(1); (* voller Kreis, leerer Kreis *)
- time := 1000; (* Zeitverzoegerung bei Prog-Ausfuehrung im Delay-Modus *)
- END;
-
- PROCEDURE To_Upper (VAR Str: lines); (* String in Grossbuchstaben *)
- VAR Aux: lines; i: INTEGER;
- BEGIN
- Aux := '';
- FOR i := 1 TO Length(Str) DO Aux := Concat(Aux, UpCase(Str[i]));
- Str := Aux;
- END;
-
- PROCEDURE Bin_to_Int (bin: dc_word; left,right: INTEGER; VAR value: INTEGER);
- VAR i: INTEGER;
- BEGIN
- value := Ord(bin[left])-Ord('0');
- FOR i := Succ(left) TO right DO value := 2*value + (Ord(bin[i])-Ord('0'));
- END;
-
- PROCEDURE Int_to_Bin (value, left, rigth: INTEGER; VAR bin: dc_word);
- VAR i: INTEGER;
- BEGIN
- FOR i := rigth DOWNTO left DO BEGIN
- IF (value MOD 2) = 0 THEN bin[i] := '0' ELSE bin[i] := '1';
- value := value DIV 2;
- END;
- END;
-
- FUNCTION Legal (n: INTEGER): BOOLEAN; (* Argument n im Adressbereich ? *)
- BEGIN
- IF (n > -1) AND (n <= mem_size) THEN Legal := TRUE ELSE Legal := FALSE;
- END;
-
- PROCEDURE Load_Int (i: INTEGER; VAR reg: dc_word);
- BEGIN
- IF i < 0 THEN BEGIN
- Int_to_Bin(i+sign_val,Succ(sign_bit),word_size,reg);
- reg[sign_bit] := '1';
- END
- ELSE BEGIN
- Int_to_Bin(i,Succ(sign_bit),word_size,reg); reg[sign_bit] := '0';
- END;
- END;
-
- FUNCTION is_Minus (VAR reg: dc_word): BOOLEAN;
- BEGIN is_Minus := reg[sign_bit] = '1'; END;
-
- PROCEDURE Increment (VAR value: INTEGER);
- BEGIN value := Succ(value) MOD Succ(mem_size); END;
-
- PROCEDURE Decrement (VAR value: INTEGER);
- BEGIN value := Pred(value); IF value < 0 THEN value := mem_size; END;
-
- PROCEDURE Copy_Bits (VAR source, dest: dc_word; left, right: INTEGER);
- VAR i: INTEGER;
- BEGIN FOR i:= left TO right DO dest[i] := source[i]; END;
-
- FUNCTION Int_Val (VAR reg: dc_word): INTEGER;
- VAR value: INTEGER;
- BEGIN
- Bin_to_Int(reg,Succ(sign_bit),word_size,value);
- IF is_Minus(reg) THEN Int_Val := value - sign_val ELSE Int_Val := value;
- END;
-
- PROCEDURE Error (error_type: errors); (* Fehleranzeige *)
- CONST
- s1 = 'falsch'; s2 = 'es Argument'; s3 = 'e Adresse';
- s4 = 'er Befehl'; s5 = 'e Konstante'; s6 = 'e Marke';
- s7 = 'er Code'; s8 = 'Ueberlauf'; s9 = 'Endlos-Schleife';
- s10= 'er Dateiname'; s11= 'Hilfe nicht gefunden'; s12= 'Programm gestoppt';
- BEGIN
- GotoXY(2,25); RevOn; Write('Fehler: ');
- CASE error_type OF
- illcmd: Write(s1, s4); (* Illegal command *)
- illadd: Write(s1, s3); (* Illegal address *)
- illarg: Write(s1, s2); (* Illegal argument *)
- illlab: Write(s1, s6); (* Illegal label *)
- illcod: Write(s1, s7); (* Illegal code *)
- illcon: Write(s1, s5); (* Illegal constant *)
- illfil: Write(s1, s10); (* Illegal filename *)
- illhlp: Write(s11); (* Help not found *)
- break : Write(s12); (* User break *)
- loops : Write(s9); (* Looping *)
- ovf : Write(s8); (* Overflow *)
- END;
- RevOff;
- END;
-
- PROCEDURE Erase_Error;
- BEGIN GotoXY(2,25); RevOn; Write(' ':31); RevOff; END;
- (* ----------------------------------------------------------------------- *)
- PROCEDURE Disassemble (VAR reg : dc_word; (* Code und Argument eines *)
- VAR mnem: mnem_str; (* Maschinenbefehls wieder *)
- VAR arg : INTEGER); (* zurueck uebersetzen *)
- BEGIN
- Bin_to_Int(reg,op_start,op_end,arg); mnem := mnems[arg];
- Bin_to_Int(reg,addr_start,addr_end,arg);
- END;
- (* ----------------------------------------------------------------------- *)
- PROCEDURE Print_Register (x, y: INTEGER; VAR reg: dc_word);
- BEGIN GotoXY(x,y); Write(reg); END;
-
- PROCEDURE Out_Cell (adr: INTEGER);
- VAR arg, y: INTEGER; mnem: mnem_str;
- BEGIN
- Disassemble(memory[adr],mnem,arg); y := (adr MOD 25) + 1;
- GotoXY(59,y); Write(adr:2,mnem:4,arg:3);
- GotoXY(69,y); Write(memory[adr],' ');
- END;
-
- PROCEDURE Print_MemPage (adr: INTEGER);
- VAR i, from_cell, to_cell, arg, y: INTEGER;
- BEGIN
- i := adr DIV screen_lines; RevOn;
- IF i <> mempage THEN BEGIN
- mempage := i; y := 0;
- from_cell := i*screen_lines; to_cell := from_cell+Pred(screen_lines);
- IF to_cell > mem_size THEN to_cell := mem_size;
- FOR i := from_cell TO to_cell DO BEGIN Out_Cell(i); y := Succ(y); END;
- WHILE y < screen_lines DO BEGIN
- y := Succ(y);
- GotoXY(59,y); Write(' ':9); GotoXY(69,y); Write(' ':Succ(word_size));
- END;
- END;
- RevOff;
- END;
-
- PROCEDURE Print_Cell (i: INTEGER); (* Inhalt einer Speicherzelle anzeigen *)
- BEGIN
- IF (i DIV screen_lines)=mempage THEN BEGIN RevOn; Out_Cell(i); RevOff; END;
- END;
-
- PROCEDURE Invert_Cell (i: INTEGER);
- BEGIN Print_MemPage(i); RevOff; Out_Cell(i); END;
-
- PROCEDURE Print_Cycle (Str: lines); (* Maschinen-Zyklus anzeigen *)
- BEGIN
- IF out_cycle THEN BEGIN RevOn; GotoXY(6,25); Write(Str); RevOff; END;
- END;
- (* ----------------------------------------------------------------------- *)
- PROCEDURE WriteCh (ch: string2; n: INTEGER); (* "n" Zeichen ausgeben *)
- VAR i: INTEGER;
- BEGIN FOR i := 1 TO n DO Write(ch); END;
-
- PROCEDURE Scroll_Up; (* Dialog-Fenster scrollen *)
- VAR i: INTEGER;
- BEGIN
- FOR i := winymin TO winymax-1 DO BEGIN
- window[i] := window[i+1]; GotoXY(3,i); Write(window[i]);
- END;
- GotoXY(3,winymax); WriteCh(' ',max_length); GotoXY(3,winymax);
- END;
-
- PROCEDURE W_Write (VAR Str: lines); (* In's Dialog-Fenster schreiben *)
- BEGIN
- window[row] := Str; row := row + 1; GotoXY(1,row);
- IF row = winymax+1 THEN BEGIN row := winymax; Scroll_Up; END;
- END;
- (* ----------------------------------------------------------------------- *)
- PROCEDURE LED (ch: CHAR); (* Die LEDs zur Anzeige von Registerinhalten *)
- BEGIN CASE ch OF '0': Write(led_off); '1': Write(led_on); END; END;
- (* ein Registerinhalt mit obigen LEDs anzeigen: *)
- PROCEDURE Display (VAR register: dc_word; x, y, left, right: INTEGER);
- VAR i: INTEGER;
- BEGIN
- IF out_cycle THEN
- BEGIN GotoXY(x,y); FOR i := left TO right DO LED(register[i]); END;
- END;
-
- PROCEDURE Display_AC; (* der Akkumulator *)
- BEGIN Display(ac,23,4,sign_bit,1); Display(ac,25,4,sign_bit+1,word_size);END;
-
- PROCEDURE Display_PC; (* der Programmzaehler *)
- BEGIN Display(pc,8,4,addr_start,addr_end); END;
-
- PROCEDURE Display_AR; (* das Adressregister *)
- BEGIN Display(ar,48,4,addr_start,addr_end); END;
-
- PROCEDURE Display_DR; (* das Datenregister *)
- BEGIN Display(dr,44,12,sign_bit,word_size); END;
-
- PROCEDURE Display_IR; (* das Befehlsregister *)
- BEGIN
- Display(ir,4,13,op_start,op_end); Display(ir,9,13,addr_start,addr_end);
- END;
-
- PROCEDURE Display_SP; (* der Stack-Pointer *)
- BEGIN Display(sp,4,7,addr_start,addr_end); END;
-
- PROCEDURE Print_Registers; (* und jetzt alle zusammen neben Dialog-Fenster *)
- BEGIN
- Print_Register(37,18,ac); Print_Register(37,19,dr);
- Print_Register(37,20,ar); Print_Register(37,21,ir);
- Print_Register(37,22,pc); Print_Register(37,23,sp);
- END;
-
- PROCEDURE Display_Status; (* logo ? *)
- BEGIN
- out_cycle := TRUE; Print_Registers; Display_AR; Display_PC; Display_AC;
- Display_DR; Display_IR; Display_SP;
- END;
- (* ----------------------------------------------------------------------- *)
- PROCEDURE Interrupt; (* Anzeige einer Unterbrechung *)
- VAR ia: dc_word; err: INTEGER;
- BEGIN
- IF items = 1 THEN BEGIN
- int_addr := none; GotoXY(41,25); RevOn; Write('none'); RevOff;
- GotoXY(38,4); WriteCh('-',Succ(addr_end-addr_start));
- END
- ELSE BEGIN
- Val(item[2],int_addr,err);
- IF (err = null) AND Legal(int_addr) THEN BEGIN
- GotoXY(41,25); RevOn; Write(int_addr:4); RevOff;
- Int_to_Bin(int_addr,addr_start,addr_end,ia);
- Display(ia,38,4,addr_start,addr_end);
- END
- ELSE Error(illadd); (* Illegall address *)
- END;
- END;
- (* ----------------------------------------------------------------------- *)
- PROCEDURE Breakpoint; (* Anzeige eines Haltepunktes *)
- VAR err: INTEGER;
- BEGIN
- IF items = 1 THEN BEGIN
- break_addr := none; GotoXY(41,24); RevOn; Write('none'); RevOff;
- END
- ELSE BEGIN
- Val(item[2],break_addr,err);
- IF (err = null) AND Legal(break_addr) THEN BEGIN
- GotoXY(41,24); RevOn; Write(break_addr:4); RevOff;
- END
- ELSE Error(illadd); (* Illegall address *)
- END;
- END;
- (* ----------------------------------------------------------------------- *)
- PROCEDURE Wait; (* bei der Ausfuehrung eines Progs. entspr. warten *)
- VAR ch: CHAR;
- BEGIN
- CASE mode OF
- waiting : IF command = step THEN BEGIN
- GotoXY(2,25); RevOn; Write('Druecke eine Taste'); RevOff;
- Bell; REPEAT UNTIL KeyPressed; ch := ReadKey;
- END;
- nowait : ;
- delaying: Delay(time);
- END;
- IF out_cycle THEN Erase_Error;
- END;
- (* ----------------------------------------------------------------------- *)
- (* Anzeigen der verschiedenen Steuersignale bei der Ausfuehrung: *)
- PROCEDURE Gate (VAR s: string2; x,y : INTEGER; blink: BOOLEAN);
- VAR i: INTEGER;
- BEGIN
- IF blink THEN
- FOR i := 1 TO blink_num DO BEGIN
- GotoXY(x,y); Write(s); Delay(blink_time); RevOn;
- GotoXY(x,y); Write(s); Delay(blink_time); RevOff;
- END
- ELSE BEGIN RevOff; GotoXY(x,y); Write(s); END;
- END;
- (* ----------------------------------------------------------------------- *)
- PROCEDURE Print_Computer; (* Bild des Computers zeichnen *)
- VAR i: INTEGER; s: CHAR;
- BEGIN
- s := ' '; GotoXY(1,1);
- Write('AB',he,dhe); WriteCh(he,6); Write(dhe); WriteCh(he,5); Write(dhe);
- WriteCh(he,23); Write(dhe); WriteCh(he,9); Write(dhe); WriteCh(he,4);
- WriteLn(ule);
- WriteCh(s,3); Write(sl); WriteCh(s,6); Write(sl); WriteCh(s,5);
- Write(sl,s,ure); WriteCh(he,8); Write(ule); WriteCh(s,12); Write(sl);
- WriteCh(s,9); Write(sl); WriteCh(s,4); WriteLn(sl);
- WriteCh(s,3); Write(ve); WriteCh(s,2); Write(ure,he,he,he,uhe,he,he,ule);
- WriteCh(s,2); Write(ve,s,ve); WriteCh(s,2); Write(ure); WriteCh(he,5);
- Write(uhe); WriteCh(he,5); Write(ule); WriteCh(s,2);
- Write(ure,he,he,he,uhe,he,he,ule); WriteCh(s,2);
- WriteLn(ure,he,he,he,uhe,he,he,ule,s,ve);
- WriteCh(s,3); Write(ve,'PC',ve); WriteCh(s,6); Write(rve); WriteCh(s,2);
- Write(ve,s,ve,'AC',ve); WriteCh(s,11); Write(ve,'IA',ve); WriteCh(s,6);
- Write(ve,'AR',ve); WriteCh(s,6); WriteLn(ve,s,ve);
- WriteCh(s,3); Write(ve); WriteCh(s,2); Write(dre); WriteCh(he,6);
- Write(dle); WriteCh(s,2); Write(ve,s,ve); WriteCh(s,2); Write(dre);
- WriteCh(he,5); Write(dhe); WriteCh(he,5); Write(dle); WriteCh(s,2);
- Write(rve); WriteCh(he,6); Write(lve); WriteCh(s,2);
- WriteLn(dre,he,he,he,dhe,he,he,dle,s,ve);
- Write(sp2,ure,uhe); WriteCh(he,5); Write(ule); WriteCh(s,6);
- Write(ve,s,ve); WriteCh(s,8); Write(sl); WriteCh(s,8);
- Write(ve,' INT ',ve,ure); WriteCh(he,5); WriteLn(uhe,he,he,ule,s,ve);
- Write('SP',ve); WriteCh(s,6); Write(rve); WriteCh(s,6); Write(ve,s,ve);
- WriteCh(s,5); Write(ure,he,he,uhe,he,he,ule); WriteCh(s,5); Write(dre);
- WriteCh(he,6); Write(dle,ve); WriteCh(s,8); WriteLn(ve,s,ve);
- Write(sp2,dre); WriteCh(he,6); Write(dle); WriteCh(s,6); Write(ve,s,ve);
- WriteCh(s,5); Write(ve); WriteCh(s,5); Write(ve); WriteCh(s,13);
- WriteLn(ve,' MEMORY ',ve,s,ve);
- Write(ure); WriteCh(he,9); Write(ule); WriteCh(s,5); Write(ve,s,ve,s,s);
- Write(ure,he,he,dle); WriteCh(s,5); Write(dre,he,he,ule); WriteCh(s,10);
- Write(lve); WriteCh(s,8); WriteLn(ve,s,ve);
- Write(ve,' CONTROL ',ve); WriteCh(s,5); Write(ve,s,ve,s,s,ve);
- WriteCh(s,4); Write('ALU'); WriteCh(s,4); Write(ve); WriteCh(s,10);
- Write(dre); WriteCh(he,5); WriteLn(dhe,he,he,dle,s,ve);
- Write(dre,he,ule); WriteCh(s,4); Write(ure,he,he,dle,ure);
- WriteCh(he,4); Write(dle,s,ve,s,s,ve); WriteCh(s,4); Write(ure,he,ule);
- WriteCh(s,4); Write(ve); WriteCh(s,8); Write(ure); WriteCh(he,7);
- WriteLn(uhe,he,he,ule,s,ve);
- WriteCh(s,2); Write(rve); WriteCh(s,4); Write(ce); WriteCh(he,3);
- Write(uhe,he,he,ule,s,s,s,ve,s,s,ve); WriteCh(s,4); Write(ve,s,ve);
- WriteCh(s,4); Write(ve); WriteCh(s,6); Write('DR',ve); WriteCh(s,10);
- WriteLn(ve,s,ve);
- Write('IR',ve); WriteCh(s,11); Write(ve,s,s,s,ve,s,s);
- Write(dre,he,dhe,he,he,dle,s,dre,he,he,dhe,he,dle);
- WriteCh(s,8); Write(dre); WriteCh(he,5); Write(dhe); WriteCh(he,4);
- WriteLn(dle,s,ve);
- WriteCh(s,2); Write(dre); WriteCh(he,4); Write(ce); WriteCh(he,6);
- Write(dle,s,s,s,rve); WriteCh(he,4); Write(dle); WriteCh(s,7); Write(ve);
- WriteCh(s,16); Write(ve); WriteCh(s,6); WriteLn(ve);
- WriteCh(s,7); Write(sl); WriteCh(s,10); Write(sl);
- WriteCh(s,12); Write(sl); WriteCh(s,16); Write(sl);
- WriteCh(s,6); WriteLn(ve);
- Write('DB'); WriteCh(he,5); Write(uhe); WriteCh(he,10); Write(uhe);
- WriteCh(he,12);Write(uhe); WriteCh(he,16);Write(uhe);
- WriteCh(he,6); WriteLn(dle);
- END;
- (* ----------------------------------------------------------------------- *)
- PROCEDURE Print_Display; (* das Drumherum zeichnen *)
- VAR i: INTEGER;
- BEGIN
- FOR i := 1 TO 25 DO
- BEGIN GotoXY(58,i); Write(vd); GotoXY(68,i); Write(vd); END;
- GotoXY(1,winymin-1);
- RevOn; Write(' DC v1.3 (c) 1987 PASCAL INT. ');
- Write(' Register: Mnem: '); RevOff;
- FOR i := winymin-1 TO winymax+1 DO
- BEGIN GotoXY(33,i); Write(vd); GotoXY(47,i); Write(vd); END;
- GotoXY(34,24); RevOn; Write(' Bpt: none ');
- GotoXY(34,25); Write(' Int: none ');
- GotoXY(1,25); Write(' ':32);
- GotoXY(48,18); Write(' LDA ??? '); GotoXY(48,19); Write(' STA ??? ');
- GotoXY(48,20); Write(' ADD ??? '); GotoXY(48,21); Write(' SUB ??? ');
- GotoXY(48,22); Write(' JMP ??? '); GotoXY(48,23); Write(' JMS ??? ');
- GotoXY(48,24); Write(' JSR ??? '); GotoXY(48,25); Write(' RTN DEF ');
- RevOff; GotoXY(34,18); Write('AC'); GotoXY(34,19); Write('DR');
- GotoXY(34,20); Write('AR'); GotoXY(34,21); Write('IR');
- GotoXY(34,22); Write('PC'); GotoXY(34,23); Write('SP');
- END;
-
- PROCEDURE Read_Cycle; (* der Lese-Zyklus *)
- BEGIN
- Print_Cycle('MEMORY -> DR'); Gate(rd,43,9,TRUE); Display_DR;
- Wait; Gate(sp2,43,9,FALSE);
- END;
-
- PROCEDURE Write_Cycle; (* der Schreib-Zyklus *)
- BEGIN
- Print_Cycle('DR -> MEMORY'); Gate(wr,43,9,TRUE);
- Print_Cell(address); Wait; Gate(sp2,43,9,FALSE);
- END;
-
- PROCEDURE Inc_PC; (* Programmzaehler erhoehen *)
- BEGIN
- Print_Cycle('PC+1 -> PC'); Gate(ipc,15,4,TRUE); Display_PC;
- Wait; Gate(sp2,15,4,FALSE);
- END;
-
- PROCEDURE Transfer_IA_AR; (* Interrupt-Adresse in's Adress-Register *)
- BEGIN
- Print_Cycle('IA -> AR'); Gate(bar,41,2,TRUE); Gate(d_arrow,51,2,TRUE);
- Display_AR; Wait; Gate(sl,41,2,FALSE); Gate(sl,51,2,FALSE);
- END;
-
- PROCEDURE Transfer_IA_PC; (* Interrupt-Adresse in den Programmzaehler *)
- BEGIN
- Print_Cycle('IA -> PC'); Gate(bar,41,2,TRUE); Gate(d_arrow,11,2,TRUE);
- Display_PC; Wait; Gate(sl,41,2,FALSE); Gate(sl,11,2,FALSE);
- END;
-
- PROCEDURE Transfer_PC_AR; (* Programmzaehler in's Adress-Register *)
- BEGIN
- Print_Cycle('PC -> AR'); Gate(bar,11,2,TRUE); Gate(d_arrow,51,2,TRUE);
- Display_AR; Wait; Gate(sl,11,2,FALSE); Gate(sl,51,2,FALSE);
- END;
-
- PROCEDURE Transfer_DR_IR; (* Daten-Register in's Befehlsregister *)
- BEGIN
- Print_Cycle('DR -> IR'); Gate(bar,49,15,TRUE); Gate(u_arrow,8,15,TRUE);
- Display_IR; Wait; Gate(sl,49,15,FALSE); Gate(sl,8,15,FALSE);
- END;
-
- PROCEDURE Transfer_AC_DR; (* Akku in's Datenregister *)
- BEGIN
- Print_Cycle('AC -> DR'); Gate(bar,19,15,TRUE); Gate(u_arrow,49,15,TRUE);
- Display_DR; Wait; Gate(sl,19,15,FALSE); Gate(sl,49,15,FALSE);
- END;
-
- PROCEDURE Transfer_AD_PC; (* Adressteil des Befehls in den Programmzaehler *)
- BEGIN
- Print_Cycle('XXX -> PC'); Gate(bar,17,2,TRUE); Gate(d_arrow,11,2,TRUE);
- Display_PC; Wait; Gate(sl,17,2,FALSE); Gate(sl,11,2,FALSE);
- END;
-
- PROCEDURE Transfer_AD_AR; (* Adressteil des Befehls in's Adress-Register *)
- BEGIN
- Print_Cycle('XXX -> AR'); Gate(bar,17,2,TRUE); Gate(d_arrow,51,2,TRUE);
- Display_AR; Wait; Gate(sl,17,2,FALSE); Gate(sl,51,2,FALSE);
- END;
-
- PROCEDURE Transfer_DR_ALU; (* Daten-Register ueber die ALU in den Akku *)
- BEGIN
- Print_Cycle('DR -> AC'); Gate(bar,49,15,TRUE); Gate(bar,32,15,TRUE);
- Gate(u_arrow,28,6,TRUE); Display_AC; Wait;
- Gate(sl,49,15,FALSE); Gate(sl,32,15,FALSE); Gate(sl,28,6,FALSE);
- END;
-
- PROCEDURE Transfer_DR_PC; (* Daten-Register in den Programmzaehler *)
- BEGIN
- Print_Cycle('DR -> PC'); Gate(bar,49,15,TRUE); Gate(bar,56,2,TRUE);
- Gate(d_arrow,11,2,TRUE); Display_PC; Wait;
- Gate(sl,49,15,FALSE); Gate(sl,56,2,FALSE); Gate(sl,11,2,FALSE);
- END;
-
- PROCEDURE Transfer_PC_DR; (* Programmzaehler in's Daten-Register *)
- BEGIN
- Print_Cycle('PC -> DR'); Gate(bar,11,2,TRUE); Gate(bar,56,2,TRUE);
- Gate(u_arrow,49,15,TRUE); Display_DR; Wait;
- Gate(sl,11,2,FALSE); Gate(sl,56,2,FALSE); Gate(sl,49,15,FALSE);
- END;
-
- PROCEDURE Transfer_SP_AR; (* Stackpointer in's Adress-Register *)
- BEGIN
- Print_Cycle('SP -> AR'); Gate(bar,4,2,TRUE); Gate(d_arrow,51,2,TRUE);
- Display_AR; Wait; Gate(sl,4,2,FALSE); Gate(sl,51,2,FALSE);
- END;
-
- PROCEDURE Inc_SP; (* Stackpointer erhoehen *)
- BEGIN
- Print_Cycle('SP+1 -> SP'); Gate(ipc,11,7,TRUE); Display_SP;
- Wait; Gate(sp2,11,7,FALSE);
- END;
-
- PROCEDURE Dec_SP;
- BEGIN
- Print_Cycle('SP-1 -> SP'); Gate(dpc,11,7,TRUE); Display_SP;
- Wait; Gate(sp2,11,7,FALSE);
- END;
-
- PROCEDURE Stop; (* nach Programmende bei "RUN" und "GO" alles anzeigen *)
- BEGIN
- IF command <> step THEN BEGIN Print_MemPage(counter); display_status; END;
- end_of_program := TRUE;
- END;
-
- PROCEDURE End_Condition; (* Programm in Endlos-Schleife ? *)
- BEGIN
- IF (ar = pc) AND ((command = run) OR (command = go)) THEN
- BEGIN Stop; error(loops); END;
- END;
- (* ----------------------------------------------------------------------- *)
- PROCEDURE Load_Accu (value: INTEGER);
- BEGIN
- IF (value > (-1 * Succ(sign_val))) AND (value < sign_val) THEN
- BEGIN Load_Int(value,ac); Transfer_DR_ALU; END
- ELSE BEGIN Stop; error(ovf); END; (* Overflow *)
- END;
- (* ----------------------------------------------------------------------- *)
- PROCEDURE Memory_Cycle;
- BEGIN Copy_Bits(ir,ar,addr_start,addr_end); Transfer_AD_AR; END;
-
- PROCEDURE Memory_Read;
- BEGIN Memory_Cycle; dr := memory[address]; Read_Cycle; END;
-
- PROCEDURE Memory_Write;
- BEGIN Memory_Cycle; memory[address] := dr; Write_Cycle; END;
-
- PROCEDURE Memory_Push;
- BEGIN
- ar := sp; Transfer_SP_AR; memory[s_ptr] := dr; Write_Cycle;
- decrement(s_ptr); Int_to_Bin(s_ptr,addr_start,addr_end,sp); Dec_SP;
- END;
-
- PROCEDURE Memory_Pop;
- BEGIN
- increment(s_ptr); Int_to_Bin(s_ptr,addr_start,addr_end,sp); Inc_SP;
- ar := sp; Transfer_SP_AR; dr := memory[s_ptr]; Read_Cycle;
- END;
- (* ----------------------------------------------------------------------- *)
- PROCEDURE Load;
- BEGIN Memory_Read; ac := dr; Transfer_DR_ALU; END;
-
- PROCEDURE Store;
- BEGIN dr := ac; Transfer_AC_DR; Memory_Write; END;
- (* ----------------------------------------------------------------------- *)
- PROCEDURE Add;
- BEGIN
- Memory_Read; Gate(pl,28,12,TRUE);
- Load_Accu(Int_Val(ac)+Int_Val(dr)); Gate(sp1,28,12,FALSE);
- END;
-
- PROCEDURE Subtract;
- BEGIN
- Memory_Read; Gate(mi,28,12,TRUE);
- Load_Accu(Int_Val(ac)-Int_Val(dr)); Gate(sp1,28,12,FALSE);
- END;
- (* ----------------------------------------------------------------------- *)
- PROCEDURE Jump;
- BEGIN
- Copy_Bits(ir,pc,addr_start,addr_end); Transfer_AD_PC;
- counter := address; End_Condition;
- END;
-
- PROCEDURE Jump_if_Minus;
- BEGIN IF is_Minus(ac) THEN Jump; END;
-
- PROCEDURE Jump_to_Subroutine;
- BEGIN
- dr := pc; Transfer_PC_DR; Memory_Push;
- Copy_Bits(ir,pc,addr_start,addr_end); Transfer_AD_PC;
- Int_to_Bin(address,addr_start,addr_end,pc); counter := address;
- END;
-
- PROCEDURE Return;
- BEGIN
- Memory_Pop; pc := dr; Transfer_DR_PC;
- Bin_to_Int(pc,addr_start,addr_end,counter); End_Condition;
- END;
- (* ----------------------------------------------------------------------- *)
- PROCEDURE Fetch_Instruction;
- BEGIN
- ar := pc; Transfer_PC_AR; Bin_to_Int(ar,addr_start,addr_end,address);
- dr := memory[address]; Read_Cycle; increment(counter);
- Int_to_Bin(counter,addr_start,addr_end,pc); Inc_PC;
- ir := dr; Transfer_DR_IR; Bin_to_Int(ir,op_start,op_end,op_code);
- Bin_to_Int(ir,addr_start,addr_end,address);
- END;
- (* ----------------------------------------------------------------------- *)
- PROCEDURE do_Interrupt; (* Unterbrechung ausfuehren *)
- BEGIN
- dr := pc; Transfer_PC_DR; Memory_Push; counter := int_addr;
- Int_to_Bin(int_addr,addr_start,addr_end,pc); Transfer_IA_PC;
- END;
-
- PROCEDURE check_Interrupt; (* Unterbrechung aufgetreten ? *)
- VAR ch: CHAR;
- BEGIN
- IF Legal(int_addr) THEN
- IF KeyPressed AND ((command = run) OR (command = go)) THEN BEGIN
- GotoXY(2,25); RevOn; Write(' Interrupt wird ausgefuehrt ');
- RevOff; Bell; Delay(2 * time); ch := ReadKey;
- Erase_Error; do_Interrupt;
- IF ch = esc THEN BEGIN Stop; error(break); END;
- END
- ELSE IF command = step THEN BEGIN
- GotoXY(2,25); RevOn; Write('<ESC>: Interrupt ausfuehren'); RevOff;
- ch := ReadKey; Erase_Error;
- IF ch = esc THEN do_Interrupt;
- END;
- END;
- (* ----------------------------------------------------------------------- *)
- PROCEDURE check_Breakpoint;
- BEGIN
- IF (counter = break_addr)
- AND ((command = run) OR (command = go)) THEN BEGIN
- Stop; GotoXY(2,25); RevOn; Write('Stop: Breakpoint erreicht'); RevOff;
- END
- END;
- (* ----------------------------------------------------------------------- *)
- PROCEDURE Execute_Instruction;
- VAR old_pc: INTEGER; ch: CHAR;
- BEGIN
- end_of_program := FALSE; old_pc := counter; Invert_Cell(old_pc);
- Fetch_Instruction;
- CASE op_code OF
- 0: Load; 1: Store; 2: Add;
- 3: Subtract; 4: Jump; 5: Jump_if_Minus;
- 6: Jump_to_Subroutine; 7: Return;
- END;
- IF out_cycle THEN Print_Registers;
- check_Interrupt; check_Breakpoint;
- IF KeyPressed THEN
- IF ReadKey = esc THEN BEGIN Stop; error(break); END;
- print_cell(old_pc);
- END;
- (* ----------------------------------------------------------------------- *)
- PROCEDURE Execute_Program;
- BEGIN
- blink_num := 0; blink_time := 0; out_cycle := mode = delaying;
- IF out_cycle THEN blink_num := 2;
- REPEAT Execute_Instruction; UNTIL end_of_program; END;
- (* ----------------------------------------------------------------------- *)
- PROCEDURE Go_From;
- VAR err: INTEGER;
- BEGIN
- Val(item[2],counter,err);
- IF (err = null) AND Legal(counter) THEN
- BEGIN Int_to_Bin(counter,addr_start,addr_end,pc); Execute_Program; END
- ELSE error(illadd); (* Illegal address *)
- END;
- (* ----------------------------------------------------------------------- *)
- PROCEDURE Single_Step;
- BEGIN
- blink_num := 2; blink_time := time DIV 2;
- out_cycle := TRUE; Execute_Instruction;
- END;
- (* ----------------------------------------------------------------------- *)
- PROCEDURE Clear; (* Computer zuruecksetzen: RESET *)
- VAR i: INTEGER;
- BEGIN
- FOR i := 0 TO mem_size DO memory[i] := zero;
- ac := zero; ar := zero; pc := zero; dr := zero; ir := zero;
- counter := 0; address := 0; s_ptr := mem_size;
- Int_to_Bin(s_ptr,addr_start,addr_end,sp);
- mempage := -1; Print_MemPage(0); out_cycle := TRUE;
- display_status; items := 1; breakpoint; interrupt;
- END;
-
- (* ----------------------------------------------------------------------- *)
-
- PROCEDURE Init;
- VAR i: INTEGER; temp: dc_word;
- BEGIN
- esc := Chr(27); RevOff; CrsOff; ClrScr; Init_Sys;
- pl := '+'; mi := '-'; sp1 := ' '; sp2 := ' ';
- ipc := '+1'; dpc := '-1'; rd := 'rd'; wr := 'wr'; mode := nowait;
- mnems[0] := 'LDA'; mnems[1] := 'STA'; mnems[2] := 'ADD';
- mnems[3] := 'SUB'; mnems[4] := 'JMP'; mnems[5] := 'JMS';
- mnems[6] := 'JSR'; mnems[7] := 'RTN';
- FOR i := 8 TO 15 DO mnems[i] := '???';
- temp := zero; sp := zero;
- FOR i := 0 TO instructions DO BEGIN
- Int_to_Bin(i,op_start,op_end,temp);
- op_codes[i] := Copy(temp,op_start,op_end);
- END;
- Print_Display; Print_Computer; Clear;
- GotoXY(2,25); revon; Write(' <H> fuer Information'); RevOff;
- row := winymin; GotoXY(1,row);
- END;
- (* ----------------------------------------------------------------------- *)
- PROCEDURE Load_Constant (address: INTEGER); (* Konstante in Speicher laden *)
- VAR value, err: INTEGER;
- BEGIN
- Val(item[3],value,err);
- IF (err = null)
- AND (value > (-1 * Succ(sign_val))) AND (value < sign_val) THEN BEGIN
- Load_Int(value,memory[address]); print_cell(address);
- END
- ELSE Error(illcon); (* Illegal constant *)
- END;
-
- PROCEDURE Load_Instruction (address: INTEGER; op_code: op_str);
- VAR arg, i: INTEGER; Mem: dc_word; (* Befehl in Speicher laden *)
- BEGIN
- IF item[2] = 'RTN' THEN item[3] := '0';
- Val(item[3],arg,i); Mem := zero;
- IF (i = null) AND Legal(arg) THEN BEGIN
- Int_to_Bin(arg,addr_start,addr_end,Mem);
- FOR i := op_start TO op_end DO Mem[i] := op_code[i];
- memory[address] := Mem; print_cell(address);
- END
- ELSE Error(illarg); (* Illegal argument *)
- END;
-
- PROCEDURE Load_PC;
- VAR temp: dc_word; value, err: INTEGER;
- BEGIN
- Val(item[2],value,err); Int_to_Bin(value,1,word_size,temp);
- IF (err = null) AND Legal(value) THEN
- IF item[1] = 'PC' THEN BEGIN pc := temp; counter := value; END
- ELSE Error(illcmd)
- ELSE Error(illadd); (* Illegal binary argument *)
- Display_Status;
- END;
- (* ----------------------------------------------------------------------- *)
- PROCEDURE Interpret_Instruction; (* Befehl in Maschinencode uebersetzen *)
- VAR i, address: INTEGER;
- BEGIN
- Val(item[1],address,i);
- IF (i = null) AND Legal(address) THEN BEGIN
- i := -1;
- REPEAT
- i := Succ(i);
- UNTIL (item[2] = mnems[i]) OR (i = instructions);
- IF item[2] = mnems[i] THEN Load_Instruction(address,op_codes[i])
- ELSE IF item[2] = 'DEF' THEN Load_Constant(address)
- ELSE Error(illcod); (* Illegal code *)
- END
- ELSE Error(illlab); (* Illegal label *)
- END;
- (* ----------------------------------------------------------------------- *)
- PROCEDURE Read_Line; (* Kommando-Zeile einlesen *)
- VAR st: lines; i: INTEGER;
- BEGIN
- Invert_Cell(counter); CrsOn; GotoXY(1,row); Bell;
- Write('> '); ReadLn(Line); st := Line;
- FOR i := 1 TO max_length - Length(Line) DO st := Concat(st,' ');
- CrsOff; w_write(st); Erase_Error; print_cell(counter);
- END;
- (* ----------------------------------------------------------------------- *)
- PROCEDURE Separate_Tokens; (* Bestandteile des Kommandos aufloesen *)
- VAR i: INTEGER;
-
- FUNCTION empty (VAR st: lines): BOOLEAN;
- VAR i: INTEGER; temp: BOOLEAN;
- BEGIN
- temp := FALSE; i := 0;
- REPEAT
- i := Succ(i);
- IF i <= Length(st) THEN IF st[i] <> ' ' THEN temp := TRUE;
- UNTIL temp OR (i >= Length(st));
- empty := NOT(temp);
- END;
-
- BEGIN
- FOR i := 1 TO 3 DO item[i] := '';
- i := Pos(';',Line);
- IF i > 0 THEN Delete(Line,i,Length(Line)-i+1); (* Kommentar entfernen *)
- items := 0;
- IF empty(Line) THEN Line := '';
- IF Length(Line) > 0 THEN BEGIN
- Line := Concat(Line,' ');
- REPEAT
- items := Succ(items);
- WHILE Line[1] = ' ' DO Delete(Line,1,1);
- i := Pos(' ',Line); item[items] := Copy(Line,1,Pred(i));
- Delete(Line,1,Length(item[items]))
- UNTIL (items = 3) OR empty(Line);
- END;
- END;
- (* ----------------------------------------------------------------------- *)
- PROCEDURE Interpret_Line; (* Kommandozeile uebersetzen *)
- VAR st: lines; i, err: INTEGER;
- BEGIN
- To_Upper(Line); Separate_Tokens; st := item[1]; command := other;
- Val(item[1],i,err);
- IF items = 0 THEN command := step
- ELSE IF err = null THEN command := instr
- ELSE IF (items = 1) AND (Length(st) = 1) THEN
- CASE st[1] OF
- 'H': command := hlp; 'I': command := Int;
- 'B': command := bpt; 'C': command := cl;
- 'R': command := run; 'E': command := ends;
- 'W': command := tim; 'N': command := tim;
- 'D': command := tim;
- END
- ELSE IF (items = 2) AND (Length(st) = 1) THEN
- CASE st[1] OF
- 'B': command := bpt; 'I': command := Int; 'V': command := view;
- 'G': command := go; 'L': command := ldf;
- END
- ELSE IF (items = 2) AND (Length(st) = 2) THEN
- IF (st = 'AR') OR (st = 'PC')
- OR (st = 'AC') OR (st = 'DR') OR (st = 'IR') THEN command := regr
- END;
- (* ----------------------------------------------------------------------- *)
- PROCEDURE Set_Time; (* Pause bei schrittweiser Ausfuehrung festlegen *)
- VAR st: lines;
- BEGIN
- st := item[1];
- CASE st[1] OF
- 'N': mode := nowait; 'W': mode := waiting; 'D': mode := delaying;
- END;
- END;
- (* ----------------------------------------------------------------------- *)
- PROCEDURE View_Page;
- VAR address, err: INTEGER; ch: CHAR;
- BEGIN
- Val(item[2],address,err); IF err = null THEN Print_Mempage(address);
- GotoXY(2,25); revon; Write('Druecke eine Taste'); RevOff;
- ch := ReadKey;
- END;
- (* ----------------------------------------------------------------------- *)
- PROCEDURE help;
- VAR counter, i: INTEGER; ch: CHAR; Str: lines;
- BEGIN
- IF Open_File('DC.HLP') THEN BEGIN
- counter := 0; ch := ' ';
- WHILE NOT Eof(inp_file) AND (ch <> esc) DO BEGIN
- counter := counter + 1; ReadLn(inp_file, Line); Str := Line;
- FOR i := 1 TO max_length - Length(Line) DO Str := Concat(Str, ' ');
- IF counter MOD 7 = 0 THEN BEGIN
- Write(Line);
- GotoXY (2,25); RevOn; Write('ESC: Ende WEITER: Taste'); RevOff;
- ch := ReadKey; Erase_Error;
- IF ch = esc THEN
- BEGIN GotoXY(1,row); Write ('> '); w_write(Str); END;
- END
- ELSE BEGIN GotoXY(1,row); Write('> '); w_write(Str); END;
- END;
- END
- ELSE error(illhlp);
- END;
- (* ----------------------------------------------------------------------- *)
- PROCEDURE Load_File; FORWARD; (* Programm aus Datei laden *)
- (* ----------------------------------------------------------------------- *)
- PROCEDURE Execute_Command; (* Kommando ausfuehren *)
- BEGIN
- CASE command OF
- hlp : help; cl : Clear;
- tim : Set_Time; regr : Load_PC;
- instr: Interpret_Instruction; go : Go_From;
- bpt : breakpoint; Int : interrupt;
- ldf : Load_File; step : Single_Step;
- run : execute_program; view : View_Page;
- other: Error(illcmd); ends : Exit_DC;
- END;
- END;
- (* ----------------------------------------------------------------------- *)
- PROCEDURE Load_File;
- BEGIN
- IF Pos('.',item[2]) = 0 THEN item[2] := Concat(item[2],'.DC');
- IF Open_File(item[2]) THEN
- WHILE NOT Eof(inp_file) DO BEGIN
- ReadLn(inp_file, Line); Interpret_Line; Execute_Command;
- END
- ELSE Error(illfil); (* Illegal filename *)
- END;
- (* ----------------------------------------------------------------------- *)
- BEGIN (* Didactic_Computer *)
- Init;
- REPEAT Read_Line; Interpret_Line; Execute_Command; UNTIL command = ends;
- END.
-