Speicher beschreiben mit Assembler über Turbo Pascal

Für allgemeine Fragen zur Programmierung, welche nicht! direkt mit Lazarus zu tun haben.
Antworten
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

Speicher beschreiben mit Assembler über Turbo Pascal

Beitrag von Nixsager »

Hallo

Ich versuche in Turbo Pascal mit Assembler den Speicher zu beschreiben.
Aber wenn ich Variabeln nutze, dann ist der Offset 0 nicht mehr 0, und je nachdem welchen Datentyp (Byte, ShortInt, Integer, Word) muss ich zusätzlich von dem Wert der Variabel noch einen bestimmten Wert abziehen (Word: 66h, Integer: 6Ah, Byte: 61, ShortInt: 63h) um auf den Offset 0 zu kommen.

Problem scheint mir der Befehl 'MOV ES:[Wert/Variabel/Register], AL' zu machen.
Wenn eine Variabel nutze, muss das Quellregister die selbe Breite wie die Variabel haben.
Nutze ich einen Wert oder ein Register, kann ich ein halbes oder ganzes Register nutzen.

Code: Alles auswählen

	ByteValue:=0;
	ShortIntValue:=0;
	WordValue:=0;
	IntegerValue:=0;

	Asm
		MOV	BX,	0b800h
		MOV	ES,	BX
		MOV	AX,	0F058h
		MOV	ES:[ShortIntValue-61h],	AL
	End;
Zum erfolgreichen schreiben nutze ich folgenden Code:

Code: Alles auswählen


	WordValue:=47104;
	Word2Value:=0;
	Word3Value:=2288;
	Word3Value:=3928;
	IntegerValue:=0;
	ByteValue:=0;
	Asm
		MOV	BX,	WordValue
		MOV	ES,	BX
		MOV	BX,	Word2Value
		MOV	AX,	Word3Value
		MOV	ES:[BX],	AL
	End;
Was mache ich falsch, und was ist die bessere Lösung?

P.S.
Wenn ich mit dem Thema hier falsch bin, bin ich für Vorschläge offen.
Jeder der sagt, ich könnte programmieren, der hat noch weniger Ahnung vom programmieren als ich!!!

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

Re: Speicher beschreiben mit Assembler über Turbo Pascal

Beitrag von Mathias »

Sehe ich es richtig, du willst im Textmodus ins VRAM schreiben ?

Code: Alles auswählen

WordValue:=47104;
Da kannst du auch schreiben:

Code: Alles auswählen

WordValue:=$B800;
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: Speicher beschreiben mit Assembler über Turbo Pascal

Beitrag von Nixsager »

Es ist nicht begrenzt auf den Grafikspeicher, aber man sieht dort halt, ob es funktioniert.

Das mit der Schreibweise weiß ich, aber ich schreibe. wenn ich Werte an eine Variabel übergebe liebe in Dezimal.
Jeder der sagt, ich könnte programmieren, der hat noch weniger Ahnung vom programmieren als ich!!!

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

Re: Speicher beschreiben mit Assembler über Turbo Pascal

Beitrag von Mathias »

Was mache ich falsch, und was ist die bessere Lösung?
Ich habe gerade in alten Code von mir rumgeschnuppert.
Problem scheint mir der Befehl 'MOV ES:[Wert/Variabel/Register], AL' zu machen.
Ist die überhaupt erlaubt bei einemI286er ?
Ich sehe in meinem Code nur folgendes:

Code: Alles auswählen

mov     ax, es:[si]
Oder sowas

Code: Alles auswählen

        mov     [offset YStep + 2], ax
"offest" scheint ein reserviertes Wort zu sein. "YStep" ist ein LongInt.
Versuche doch einfach mal "offset" rein zuschreiben. Evtl. geht es.

Einen Auschnitt von meinem Code:

Code: Alles auswählen

var
  XStep, YStep, creal, cimag : Longint;
  
  procedure Start; assembler;
    asm
        push    bp
        mov     bp, sp
        mov     ax, 0010h      { ; Vio-Modus 10h     640x350}
        int     10h
        mov     ax, 3513h      { ; Vio-Ram auf 848 Pixel einstellen}
        mov     dx, 3D4h
        out     dx, ax
        mov     ax, 0010Eh
        mov     [offset XStep + 0], ax
        mov     ax, 00000h
        mov     [offset XStep + 2], ax
        mov     ax, 0FEC2h
        mov     [offset YStep + 0], ax
        mov     ax, 0FFFFh
        mov     [offset YStep + 2], ax
        mov     ax, 00000h
        mov     [offset creal + 0], ax
        mov     ax, 0FFFEh
        mov     [offset creal + 2], ax
        mov     cx, 847
@@X1:   push    cx
        mov     ax, 9000h
        mov     [offset cimag + 0], ax
        mov     ax, 0001h
        mov     [offset cimag + 2], ax
        mov     cx, 617
@@Y1:   push    cx
        call    Calc
        mov     cx, [bp - 2]   { x von Stack }
        push    cx
        mov     cx, [bp - 4]   { y von Stack }
        push    cx
        push    ax
        call    PutPixel;
        pop     cx
        loop    @@Y1
        mov     ax, [offset XStep + 0] {    Inc(creal, XStep);}
        mov     dx, [offset XStep + 2]
        add     [offset creal + 0], ax
        adc     [offset creal + 2], dx
        pop     cx
        loop    @@X1
        pop     bp
end;
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot

siro
Beiträge: 732
Registriert: Di 23. Aug 2016, 14:25
OS, Lazarus, FPC: Windows 11
CPU-Target: 64Bit
Wohnort: Berlin

Re: Speicher beschreiben mit Assembler über Turbo Pascal

Beitrag von siro »

Ich habe auch mal einen Code von 1990 :roll: von mir rausgekramt.....

Einen Auschnitt packe ich mal hier rein, vielleicht hilft es weiter:
TextScrSeg ist die Adresse $B800 bei der Hercules Grafikkarte war das $B000

Code: Alles auswählen

;=============================================================================
; Procedure Poke(Spalte,Zeile,Attr,Zeichen:Integer);
;---------------------------------------------------
Poke Proc Far
     Push BP                      ; Base-Pointer sichern
     Mov  BP,SP                   ; Base-Pointer = Stack-Pointer
     Push ES                      ; Extra-Segment sichern
     Mov  BX,Word Ptr SS:[BP+10]  ; Zeile vom Stack holen
     Cmp  BX,24                   ; Zeile > 24 ?   kleiner 0 Test automatisch
     JA   PokeEx                  ; dann Exit
     Cmp  Byte Ptr SS:[BP+12],79  ; Spalte > 79 ?  kleiner 0 Test automatisch
     JA   PokeEx                  ; dann Exit
     Shl  BX,1                    ; Zeile *  2
     Shl  BX,1                    ; Zeile *  4
     Shl  BX,1                    ; Zeile *  8
     Shl  BX,1                    ; Zeile * 16
     Mov  AX,BX                   ; Zeile * 16 in AX merken
     Shl  BX,1                    ; Zeile * 32
     Shl  BX,1                    ; Zeile * 64
     Add  BX,AX                   ; BX ist nun Zeile * 80
     Add  BX,Word Ptr SS:[BP+12]  ; Spalte + Zeile
     Shl  BX,1                    ; (Spalte + Zeile) * 2
     Mov  ES,TextScrSeg           ; ES auf Bildschirm Segment
     Mov  AH,Byte Ptr SS:[BP+8]   ; Farbe nach AH
     Mov  AL,Byte Ptr SS:[BP+6]   ; Zeichen nach AL
     Mov  Word Ptr ES:[BX],AX     ; in Bildspeicher schreiben
PokeEx:                           ; Aussprung aus Poke-Routine
     Pop  ES                      ; Extra-Segment vom Stack
     Pop  BP                      ; Base-Pointer vom Stack
     Ret  8                       ; 8 Bytes = 4 Words vom Stack entfernen
Poke endp
;=============================================================================
; Function Peek(Spalte,Zeile:Integer):Byte;
;------------------------------------------
Peek Proc Far
     Push BP                      ; Base-Pointer sichern
     Mov  BP,SP                   ; Base-Pointer = Stack-Pointer
     Push ES                      ; Extra-Segment sichern
     Mov  BX,Word Ptr SS:[BP+6]   ; Zeile vom Stack holen
     Cmp  BX,24                   ; Zeile > 24 ?   kleiner 0 Test automatisch
     JA   PeekEx                  ; dann Exit
     Cmp  Byte Ptr SS:[BP+8],79   ; Spalte > 79 ?  kleiner 0 Test automatisch
     JA   PeekEx                  ; dann Exit
     Shl  BX,1                    ; Zeile *  2
     Shl  BX,1                    ; Zeile *  4
     Shl  BX,1                    ; Zeile *  8
     Shl  BX,1                    ; Zeile * 16
     Mov  AX,BX                   ; Zeile * 16 in AX merken
     Shl  BX,1                    ; Zeile * 32
     Shl  BX,1                    ; Zeile * 64
     Add  BX,AX                   ; BX ist nun Zeile * 80
     Add  BX,Word Ptr SS:[BP+8]   ; Spalte + Zeile
     Shl  BX,1                    ; (Spalte + Zeile) * 2
     Mov  ES,TextScrSeg           ; ES auf Bildschirm Segment
     Mov  AX,Word Ptr ES:[BX]     ; Zeichen und Attr vom Bildschirm holen
PeekEx:                           ; Aussprung aus Poke-Routine
     Pop  ES                      ; Extra-Segment vom Stack
     Pop  BP                      ; Base-Pointer vom Stack
     Ret  4                       ; 4 Bytes = 2 Words vom Stack entfernen
Peek Endp
;=============================================================================
Grüße von Siro
Bevor ich "C" ertragen muß, nehm ich lieber Lazarus...

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

Re: Speicher beschreiben mit Assembler über Turbo Pascal

Beitrag von Mathias »

TextScrSeg ist die Adresse $B800 bei der Hercules Grafikkarte war das $B000
Die berühmten $A000, $B000 und $B800. Wobei $A000 nur EGA+ vorbehalten war.
Einen Auschnitt packe ich mal hier rein, vielleicht hilft es weiter:
So wie ich sehe, hast du in den [ ] nur Register + Konstanten.
Nixsager will, so wie es aussieht, Integer dort reinpacken.
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot

siro
Beiträge: 732
Registriert: Di 23. Aug 2016, 14:25
OS, Lazarus, FPC: Windows 11
CPU-Target: 64Bit
Wohnort: Berlin

Re: Speicher beschreiben mit Assembler über Turbo Pascal

Beitrag von siro »

Der Compiler setzt da vermutlich den Offset der Variablen im Speicher rein,
daher auch seine merkwürdigen Subtraktionswerte. Ich bin auch der Meinung, das geht in dieser Form nicht.
Die erste Variable liegt bei ihm vermutlich an Speicherstelle 61h, belegt 2 Bytes wegen "Word Aligned"
Die nächste Variable dann bei 63h usw.
Eigentlich liegen die immer auf graden Adresse fällt mir grade ein. Also eher 60h und 61h für die erste Variable und dann die folgenden...
Wenn er oben drüber noch andere Variablen definiert, muss er sicherlich auch seine Subtraktionswerte entsprechend ändern.
Der Compiler legt (zumindest früher bei Turbo Pascal) die Variablen fein säuberlich hintereinander im Speicher ab.
Grüße von Siro
Bevor ich "C" ertragen muß, nehm ich lieber Lazarus...

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: Speicher beschreiben mit Assembler über Turbo Pascal

Beitrag von Nixsager »

Mathias hat geschrieben:
Di 11. Jul 2023, 14:08
Nixsager will, so wie es aussieht, Integer dort reinpacken.
Wollen nicht. Nur verstehe ich nicht wieso bei 'ES:[X]' eine Variabel anders behandelt wird als ein Register. Denn beiden beinhaltet einen Wert.
Ich habe jetzt nicht alle Register gezogen, denn so wie ich es jetzt verstanden habe, sind Register nicht einfach nur Variabeln die Daten beinhalten, sondern habe auch noch einen speziellen Status.

Ich habe jetzt den Code so geändert, wie ich ihn von der Seite i8086 verstanden habe,

Für das Schreiben nutze ich jetzt folgendes:

Code: Alles auswählen

	MOV	ES,	SegmentValue	{Zielsegment in das Register ES schreiben}
	MOV	DI,	OffsetValue	{Offset in das Register DI schreiben}
	MOV	DL,	Value		{Den Wert in das Register DL geschrieben}
	MOV	ES:[DI],	DL	{Den Inhalt des Register DL in die Adresse des Registers ES:[Offset] schreiben}
Für das Lesen nutze ich folgendes:

Code: Alles auswählen

	MOV	ES,	SegmentValue	{Zielseqment in das Register ES schreiben}
	MOV	SI,	OffsetValue	{Offset in das Register SI schreiben}
	MOV	DL,	ES:[SI]		{Den Inhalt der Adresse aus dem Register ES:[Offset] in das Register DL schreiben}
	MOV	TempValue,	DL	{Den Inhalt des Register DL in die Variabel schreiben}
Die Register A, B, C und D habe ich immer als Variabeln genutzt, um kurz Daten zwischenzulagern, oder für einen CMP-Befehl.
Aber ich glaube das mit 'MOV ES, XX' muss ich noch sauberer machen.
Ich kann dem Register ES, mit einem Register und einer Variabel nutzen, aber einen Wert kann ich nicht zuweisen.
So wie ich das jetzt sehe, ist es besser Variabeln und Werte erstemal einem anderen Register zuweisen, und das Register dann dem ES-Register zuweisen.
Also das es am Ende so aussieht:

Code: Alles auswählen

	MOV	DX,	SegmentValue	{Zielsegment in das Register DX schreiben}
	MOV	ES,	DX		{Den Wert des Register DX in das Register ES schreiben}
	MOV	DI,	OffsetValue	{Offset in das Register DI schreiben}
	MOV	DL,	Value		{Den Wert in das Register DL geschrieben}
	MOV	ES:[DI],	DL	{Den Inhalt des Register DL in die Adresse des Registers ES:[Offset] schreiben}
siro hat geschrieben:
Di 11. Jul 2023, 14:22
Eigentlich liegen die immer auf graden Adresse fällt mir grade ein. Also eher 60h und 61h für die erste Variable und dann die folgenden...
Wenn er oben drüber noch andere Variablen definiert, muss er sicherlich auch seine Subtraktionswerte entsprechend ändern.
Der Witz ist, die Subtraktionswerte waren vorher andere. Ich hatte den Code geändert um zu testen, und habe es rückgängig gemacht, und dann musste ich andere Werte nehmen.

Danke für eure Codeschnippsel, aber die verwirren mich leider.
@siro
Was ist die Aufgabe deines Codes?

@Mathias
Das mit dem Offset-Befehl muss ich noch ausprobieren. Ich verstehe den Sinn nicht dahinter,
Jeder der sagt, ich könnte programmieren, der hat noch weniger Ahnung vom programmieren als ich!!!

siro
Beiträge: 732
Registriert: Di 23. Aug 2016, 14:25
OS, Lazarus, FPC: Windows 11
CPU-Target: 64Bit
Wohnort: Berlin

Re: Speicher beschreiben mit Assembler über Turbo Pascal

Beitrag von siro »

Ich habe mir nochmal die "Adressierungsarten" angesehen vom 8086 und folgenden Prozessoren.
Es ist tatsächlich so, man kann bei dieser "indirekten Adressierung" nur Register und Konstanten oder Kombination derer verwenden.
Eine Variable kann dort NICHT verwendet werden (Ein Variablenname schon)

Wenn man einen Variablenname angibt, dann trägt der Compiler bzw. Assembler automatisch den Offset (und damit wieder eine Konstante) ein,
nämlich den festen Wert, wo sich die Variable im Speicher befindet.
Dieser Offset (Adresswert) im Speicher verschiebt sich jedoch wenn man den Code ändert bzw. neue Variablen definiert.

Ich habe ein recht gutes deutsches Dokument gefunden:
Kapitel 2.4 Adressierungsarten ab Seite 31
https://homepages.thm.de/~hg6458/AS.pdf

---
Zu meinem Code, was er machen soll:
Der Bildschirmspeicher im Textmodus war damals aufgeteilt in 25 Zeilen zu je 80 Zeichen.
Hier war es jedoch so, das ein Zeichen aus 2 Bytes besteht.
Einmal ein Byte für das Zeichen und ein Byte für die Farbe.

Mit meiner damaligen Procedure Poke (Name abgeleitet aus den Ursprüngen der Basic Sprache)
konnte ich also sagen, wo welches Zeichen und in welcher Farbe dargestellt werden soll.
Grüße von Siro
Bevor ich "C" ertragen muß, nehm ich lieber Lazarus...

Antworten