Wie am besten in die Konsole Zeichen ausgeben?

Für Fragen von Einsteigern und Programmieranfängern...
Nixsager
Beiträge: 168
Registriert: Sa 8. Okt 2016, 08:38
OS, Lazarus, FPC: Winux (L 0.9.xy FPC 2.2.z)
CPU-Target: xxBit
Wohnort: Polska

Re: Wie am besten in die Konsole Zeichen ausgeben?

Beitrag von Nixsager »

Danke für den Assembler-Code. Auch wenn ich ihn nicht verstehe.

Die Funktion $13 hat zwei Nachteile. 1. ist sie erst am einem 286er nutzbar, und 2. man kann nicht in die letzte Spalte in der letzte Zeile ohne Zeilenumbruch schreiben.

Aber vielleicht kann ich mit dem letzten Beispiel, den Code für die einzelne Zeichenausgabe für die Zeichenkette-Ausgabe anpassen.

Irgendwie erinnert mich die Funktion $13 an die MemW-Funktion. Na gut, Mem-Ist eigentlich keine Funktion sondern ein Array.

Ich frage mich echt, wie die das bei der 8088 Corruption-Demo hinbekommen haben.
Die Idee für so was hatte auch mal, als ich das erste mal mit den Speicherabbilder des Textmodus gearbeitet habe.
Jeder der sagt, ich könnte programmieren, der hat noch weniger Ahnung vom programmieren als ich!!!

Mathias
Beiträge: 6194
Registriert: Do 2. Jan 2014, 17:21
OS, Lazarus, FPC: Linux (die neusten Trunk)
CPU-Target: 64Bit
Wohnort: Schweiz

Re: Wie am besten in die Konsole Zeichen ausgeben?

Beitrag von Mathias »

Die Funktion $13 hat zwei Nachteile. 1. ist sie erst am einem 286er nutzbar,

Bist du das sicher ?
Ich denke, wen man bei eine 8088 eine EGA/VGA-Karte einbaut müsste die Funktion vorhanden sein.
Die int 10h Funktionen sind für CGA und MDA-Karten fix im Mainboard-BIOS vorhanden, und dies mindestens bis zu einem Pentium 1, höher habe ich nicht probiert, es gab dann auch kein ISA mehr.
Bei EGA und besser sind die Funktion in einen Zusatz-BIOS der Graka vorhanden.

2. man kann nicht in die letzte Spalte in der letzte Zeile ohne Zeilenumbruch schreiben.

Ich habe dies gerade probiert, auch mit AL=0 (die Cursor-Position beibehalten).
Meisten wird das letzte Zeichen sowieso nur für eine schönen Hintergrund gebraucht, und somit eignet sich so wieso die 09h Funktion besser, die angeblich auf dem letzten Zeichen funktioniert.
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot

Nixsager
Beiträge: 168
Registriert: Sa 8. Okt 2016, 08:38
OS, Lazarus, FPC: Winux (L 0.9.xy FPC 2.2.z)
CPU-Target: xxBit
Wohnort: Polska

Re: Wie am besten in die Konsole Zeichen ausgeben?

Beitrag von Nixsager »

Na gut das mit dem 286er war falsch ausgedrückt. Aber es funktioniert nicht mit CGA, und der letzte Assemblercode führt auf dem XT zu dem Laufzeitfehler 105.
Jeder der sagt, ich könnte programmieren, der hat noch weniger Ahnung vom programmieren als ich!!!

Mathias
Beiträge: 6194
Registriert: Do 2. Jan 2014, 17:21
OS, Lazarus, FPC: Linux (die neusten Trunk)
CPU-Target: 64Bit
Wohnort: Schweiz

Re: Wie am besten in die Konsole Zeichen ausgeben?

Beitrag von Mathias »

Aber es funktioniert nicht mit CGA, und der letzte Assemblercode führt auf dem XT zu dem Laufzeitfehler 105.

Das liegt nicht an der int 10h-Funktion, sondern am

Code: Alles auswählen

shl bl, 4

auf dem 8088 ist nur

Code: Alles auswählen

shl bl, 1

gestattet.

Ich habe das durch

Code: Alles auswählen

shl bl, 1
shl bl, 1
shl bl, 1
shl bl, 1

ersetzt. Es kommt zwar kein Fehler mehr, Text kommt aber leider auch keiner, nur der Cursor wird positioniert.
@Jole: Hast du das getestet ?

@Nixsager:
Wie hast du den Laufzeitfehler 105 hingekriegt. ?
Mit TP kompiliert ?
Bei dem Cross8086, motz der Kompiler schon.
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot

Nixsager
Beiträge: 168
Registriert: Sa 8. Okt 2016, 08:38
OS, Lazarus, FPC: Winux (L 0.9.xy FPC 2.2.z)
CPU-Target: xxBit
Wohnort: Polska

Re: Wie am besten in die Konsole Zeichen ausgeben?

Beitrag von Nixsager »

Ja das war TP.
Zuerst hat er gemeckert das kein 286/287-Code erlaubt ist, das habe ich dann eingeschaltet.
Und dann kam dieser Fehler. Das eine Fehler kommt, damit habe ich gerechnet, ein ein 105?

Wenn ich deine SHL-Modifikation nutze, kriege ich Text angezeigt.

AL ist bei mir immer 0, ich will ja nur Text ausgeben.
Jeder der sagt, ich könnte programmieren, der hat noch weniger Ahnung vom programmieren als ich!!!

Mathias
Beiträge: 6194
Registriert: Do 2. Jan 2014, 17:21
OS, Lazarus, FPC: Linux (die neusten Trunk)
CPU-Target: 64Bit
Wohnort: Schweiz

Re: Wie am besten in die Konsole Zeichen ausgeben?

Beitrag von Mathias »

Irgendwie hat der Cross8086 Probleme mit LES und LDS.
Mit dem Umweg über SegTemp, OffTemp funktioniert es, aber direkt mit LES geht es nicht.

Code: Alles auswählen

Procedure IntTest(const Value: String; X, Y: Byte; col: Byte);
var
   LengTemp: Integer;
   SegTemp: Integer;
   OffTemp: Integer;
begin
   SegTemp := Seg(Value);
   OffTemp := Ofs(Value);
   LengTemp := Length(Value);
 
   asm
      MOV AH, 13h
      MOV AL, 00h
      MOV BH, 00h
      MOV BL, col
      MOV CX, LengTemp
      MOV DL, X
      MOV DH, Y
push bp 
 
les bp, Value  // geht nicht
//      MOV ES, SegTemp  // geht
//      MOV BP, OffTemp   // geht
 
    inc bp
    INT 10h
    pop bp
  end;
end

Bei meinem Pacman ist das Programm auch bei Move stecken geblieben und Move verwendet intern auch LDS und LES.
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot

Jole
Beiträge: 114
Registriert: Fr 4. Jul 2014, 14:39
OS, Lazarus, FPC: Linux
CPU-Target: amd64

Re: Wie am besten in die Konsole Zeichen ausgeben?

Beitrag von Jole »

Mathias hat geschrieben:@Jole: Hast du das getestet ?

Ich hab den Dosemulator(Freedos) unter Linux installiert, dort verwende ich TP7, damit funktioniert der Code fehlerfrei.

@Nixsager: Wenn dein Code auf so vielen unterschiedlichen Systemen laufen soll, dann würde ich Persönlich möglichst auf Assembler verzichten. Es geht mit TP Hausmittelchen nämlich noch schneller als BIOS Funktionen zu nutzen. Versuch mal ob beispielsweise das läuft.

Code: Alles auswählen

 
Procedure PutString (Const Text: String; Page, X, Y, Attr: Word);
Var VideoSeg: ^Word;
    Inx: Word; {offset}
Begin
  VideoSeg:= Ptr ($B800, Y* 160+ X* 2+ 4000* Page); {geht einfach von Segment B800h aus}
  Attr:= Attr Shl 8;
  For Inx:= 1 To Length (Text) Do Begin
    VideoSeg^:= Attr Or Ord (Text[Inx]);
    Inc(VideoSeg);
  End;
End;
 

Das läuft bei mir um einiges schneller als der Assemblercode mit der Funktion 13H (Interpretiert hier jetzt natürlich keine Steuerzeichen).

marcov
Beiträge: 1100
Registriert: Di 5. Aug 2008, 09:37
OS, Lazarus, FPC: Windows ,Linux,FreeBSD,Dos (L trunk FPC trunk)
CPU-Target: 32/64,PPC(+64), ARM
Wohnort: Eindhoven (Niederlande)

Re: Wie am besten in die Konsole Zeichen ausgeben?

Beitrag von marcov »

Wenn Performance nicht wichtig ist, wurde ich unit Video nutzen. (also 486+ und Emulationen). Nur auf altes, langsames Eisen macht das etwas aus.

Nixsager
Beiträge: 168
Registriert: Sa 8. Okt 2016, 08:38
OS, Lazarus, FPC: Winux (L 0.9.xy FPC 2.2.z)
CPU-Target: xxBit
Wohnort: Polska

Re: Wie am besten in die Konsole Zeichen ausgeben?

Beitrag von Nixsager »

@Jole
Mal abgesehen davon das ich deinen Code nicht ganz verstehe.
Dein Code ist langsamer als die Mem-Methode, aber sie hat den Vorteil das sie kein Schnee erzeugt.

Mein halber Mem-Methode-Code:

Code: Alles auswählen

 
MemW[$B800:(0 + (IndexX * 2) + (IndexY * 160))]:= ($12 SHL 8)+Asc('X');
 
Jeder der sagt, ich könnte programmieren, der hat noch weniger Ahnung vom programmieren als ich!!!

marcov
Beiträge: 1100
Registriert: Di 5. Aug 2008, 09:37
OS, Lazarus, FPC: Windows ,Linux,FreeBSD,Dos (L trunk FPC trunk)
CPU-Target: 32/64,PPC(+64), ARM
Wohnort: Eindhoven (Niederlande)

Re: Wie am besten in die Konsole Zeichen ausgeben?

Beitrag von marcov »

Mathias hat geschrieben:Irgendwie hat der Cross8086 Probleme mit LES und LDS.


Welches Memory model nutzt du?

Es soll ein FAR data model sein um mit LES und LDS zu arbeiten, also sizeof(datapointer) soll 4 sein.
(oder inspectiere die generierter assembler mit -al)

Jole
Beiträge: 114
Registriert: Fr 4. Jul 2014, 14:39
OS, Lazarus, FPC: Linux
CPU-Target: amd64

Re: Wie am besten in die Konsole Zeichen ausgeben?

Beitrag von Jole »

@Nixsager, @Mathias: Ich muss nochmal auf den Assemblercode und SHL zurück kommen. Wenn der Code auch auf alten Rechnern (älter als 286) laufen soll, muss der Schalter {$G-} gesetzt werden. Das SHL BL, 1 unterscheidet sich nicht von SHL BL, 4, beides ist nur ab einem 286iger lauffähig. Um bei einem Rechner < 286 mit SHL mehrere Bits auf einmal zu verschieben, muss die zahl 4 mit einem initialisierten Register CL ersetzt werden. Also so

Code: Alles auswählen

 
  MOV CL, 4
  SHL  BL, CL
 

@Nixsager: Wenn die MemW Methode schneller ist und du die Funktionsweise auch besser verstehst, würde ich diese Methode auch nutzen. Egal welche du verwendest, du musst dir in jedem überlegen wie du den Zeilenumbruch in deiner Box realisierst. Eine Möglichkeit wäre ein den Text gleich mit Steuerzeichen zu versehen und in der Textausgabe ausgewertet wird. Zum Beispiel so:

Code: Alles auswählen

 
Procedure PutString (Const Text: String; Page, X, Y, Attr: Word);
Var VideoSeg, Tmp: ^Word;
  Inx: Word; {offset}
  i: Integer;
Begin
  VideoSeg:= Ptr ($B800, Y* 160+ X* 2+ 4000* Page); {geht einfach von Segment B800h aus}
  Tmp:= VideoSeg;
  Attr:= Attr Shl 8;
  Inx:= 1;
  For I:= 1 To Length (Text) Do Begin
    If(Text[Inx] <> #13) Then Begin
      Tmp^:= Attr Or Ord (Text[Inx]);
      Inc(Tmp);
    End Else Begin
      Inc(VideoSeg, 80);
      Tmp:= VideoSeg;
    End;
    Inc(Inx);
  End;
End;
 
Begin
  PutString ('Dieser Text'+#13+'wird in drei '+#13+'Zeilen ausgegeben', 0, 10, 10, 7);
  ReadLn;
End.
 

Für VideoSeg wird ein Zeiger auf das erste auszugebende Zeichen im VRAM berechnet, Tmp erhält eine Kopie davon. In der FOR schleife prüfe ich ob ein Steuerzeichen vorliegt, hier verwende ich den Wagenrücklauf. Wenn nein, dann wird Attribut und Zeichen ausgegeben und Tmp inkrementiert. Wenn das Zeichen #13 vorhanden ist, dann wird VideoSeg auf die nächste Zeile erhöht (Inc(VideoSeg, 80) = 160 Byte) und Tmp erhält wieder eine Kopie davon. In jedem Fall wird Inx um 1 erhöht.
Der wirkliche Aufwand kommt erst noch mit der Fensterverwaltung :mrgreen:

marcov hat geschrieben:Wenn Performance nicht wichtig ist, wurde ich unit Video nutzen. (also 486+ und Emulationen). Nur auf altes, langsames Eisen macht das etwas aus.

Wenn sein Code aber auch mit TP Kompilierbar sein soll kann er die nicht verwenden, die gibt es bei TP noch nicht.

marcov
Beiträge: 1100
Registriert: Di 5. Aug 2008, 09:37
OS, Lazarus, FPC: Windows ,Linux,FreeBSD,Dos (L trunk FPC trunk)
CPU-Target: 32/64,PPC(+64), ARM
Wohnort: Eindhoven (Niederlande)

Re: Wie am besten in die Konsole Zeichen ausgeben?

Beitrag von marcov »

Jole hat geschrieben:
marcov hat geschrieben:Wenn Performance nicht wichtig ist, wurde ich unit Video nutzen. (also 486+ und Emulationen). Nur auf altes, langsames Eisen macht das etwas aus.

Wenn sein Code aber auch mit TP Kompilierbar sein soll kann er die nicht verwenden, die gibt es bei TP noch nicht.


Ich glaube sie funktioniert mit ppc8086, und hat circa FPC 1.0 auch mit TP gearbeitet (fast compilierte zurzeit mit TP) wie schwierig kann es sein sie unter TP laufen zu lassen. Speziell wenn man TP langfristig will bleiben nutzen , soll man auch etwas drin investieren müssen, und nicht die nur die alte Kram mit minimale Modifikationen recyclen.

Jole
Beiträge: 114
Registriert: Fr 4. Jul 2014, 14:39
OS, Lazarus, FPC: Linux
CPU-Target: amd64

Re: Wie am besten in die Konsole Zeichen ausgeben?

Beitrag von Jole »

@marcov: Ich hab mal das Verzeichnis vom FPC für den cross8086 nach der Video unit durchsucht, hab aber keine gefunden.

Da Nixsager aber auch seinen eigenen Code haben will, nach eigener aussage, ist es doch in Ordnung wenn der den alten Kram benutzt, oder?

Mathias
Beiträge: 6194
Registriert: Do 2. Jan 2014, 17:21
OS, Lazarus, FPC: Linux (die neusten Trunk)
CPU-Target: 64Bit
Wohnort: Schweiz

Re: Wie am besten in die Konsole Zeichen ausgeben?

Beitrag von Mathias »

marcov hat geschrieben:
Mathias hat geschrieben:Irgendwie hat der Cross8086 Probleme mit LES und LDS.


Welches Memory model nutzt du?

Es soll ein FAR data model sein um mit LES und LDS zu arbeiten, also sizeof(datapointer) soll 4 sein.
(oder inspectiere die generierter assembler mit -al)

Ich weis zwar nicht, was du mit FAR data model meinst,
Aber wen ich es jetzt mit

Code: Alles auswählen

c:\FPC\3.0.0\bin\i386-win32\ppcross8086.exe -WmLarge PACMAN.lpr

kompiliere, funktioniert es fehlerfrei.

Gibt es dafür auch eine Kompilerschalter, oder muss man dies im beim kompilieren mit -WmLarge mit geben ?

@Jole
Mal abgesehen davon das ich deinen Code nicht ganz verstehe.
Dein Code ist langsamer als die Mem-Methode, aber sie hat den Vorteil das sie kein Schnee erzeugt.

Mein halber Mem-Methode-Code:

Code: Alles auswählen

MemW[$B800:(0 + (IndexX * 2) + (IndexY * 160))]:= ($12 SHL 8)+Asc('X');


Das verwundert mich, weil der Pointer VideoSeg^ auch direkt auf das VRAM zeigt.
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot

Jole
Beiträge: 114
Registriert: Fr 4. Jul 2014, 14:39
OS, Lazarus, FPC: Linux
CPU-Target: amd64

Re: Wie am besten in die Konsole Zeichen ausgeben?

Beitrag von Jole »

Mathias hat geschrieben: @Jole
Mal abgesehen davon das ich deinen Code nicht ganz verstehe.
Dein Code ist langsamer als die Mem-Methode, aber sie hat den Vorteil das sie kein Schnee erzeugt.

Mein halber Mem-Methode-Code:

Code: Alles auswählen

MemW[$B800:(0 + (IndexX * 2) + (IndexY * 160))]:= ($12 SHL 8)+Asc('X');

Das verwundert mich, weil der Pointer VideoSeg^ auch direkt auf das VRAM zeigt.

Ich wollte da nicht weiter drauf eingehen, aber tatsächlich ist es ja so das die MemW Methode, so wie sie da verwendet wird, für jedes einzelne Zeichen die Position im Video RAM neu berechnet wird. Im Fall meines Zeigers geschieht das nur ein einziges mal, danach wird der Zeiger nur noch inkrementiert. Ich hab das mal getestet und zwar habe eine Textzeile mit 80 Zeichen jeweils 500 000 mal ausgeben lassen. MemW benötigt rund 9 Sekunden, die Zeiger Variante ca. 4. Interessanterweise wird die Zeiger Methode aber erst so ab 10 000 Zeilen schneller als MemW.

Antworten