Seite 6 von 7

Re: Variablenbezüge in Assembler innerhalb Pascal

Verfasst: So 17. Jun 2012, 11:03
von Dosenware
wobo hat geschrieben: Das inc bx habe ich nur verwendet, weil es ein 1-byte-opcode ist, und ich deswegen durch Auszählen bestimmen kann, wie groß die procedure wird. Die procedure EndOfTestProc enthält z.B. 64* inc bx, so dass ich sicher weiß, dass diese Procedure mehr als 64 byte im CodeSegment umfasst.
Ich habe mir einfach ein PChar geschnappt - ein komplettes Segment für mich alleine (Pchar=64kb - getmem schafft das nicht).

Re: Variablenbezüge in Assembler innerhalb Pascal

Verfasst: So 17. Jun 2012, 11:13
von wobo
DOSferatu hat geschrieben:Wegen "comp":

Um die Typen "single", "double", "extended" und "comp" einzuschalten, bzw möglich zu machen, muß man einfach nur den Compilerschalter {$N+} verwenden. Voraussetzung dafür ist das Vorhandensein eines 80x87 (oder der 80x87 Funktionalität in einem 80x86).
Ist kein 80x87 vorhanden, kann man zusätzlich {$E+} benutzen, der fügt Code ein, um die Funktionen des 80x87 softwaremäßig zu emulieren (ist dann natürlich langsamer, denke ich).
Ahh, danke. Dass man die Schalter $N+ und $E+ kombinieren muß und kann, war mir unbekannt. Ich hatte ja auch noch nie etwas mit 80x87 gemacht.
DOSferatu hat geschrieben: (Aber vielleicht habe ich das alles ja jetzt auch umsonst geschrieben.)
Nein, natürlich nicht :-). Von meiner Seite aus kannst Du übrigens ruhig immer Deinen "Senf" zugeben - auch wenn Du meintest, ich oder ein anderer wüsste das bereits. Erstens weiß ich es meistens doch nicht. Und wenn schon, dann ist meist trotzdem hilfreich, wenn ich etwas noch einmal in den Worten eines anderen höre: bei mir jedenfalls erhöht das allgemein die Verständnistiefe für einen Sachverhalt.

Re: Variablenbezüge in Assembler innerhalb Pascal

Verfasst: So 17. Jun 2012, 11:17
von wobo
Dosenware hat geschrieben:
wobo hat geschrieben: Das inc bx habe ich nur verwendet, weil es ein 1-byte-opcode ist, und ich deswegen durch Auszählen bestimmen kann, wie groß die procedure wird. Die procedure EndOfTestProc enthält z.B. 64* inc bx, so dass ich sicher weiß, dass diese Procedure mehr als 64 byte im CodeSegment umfasst.
Ich habe mir einfach ein PChar geschnappt - ein komplettes Segment für mich alleine (Pchar=64kb - getmem schafft das nicht).
Ahh. Auch das wußte ich nicht :-). Mein Sprachumfang ist irgendwie bei TP 5.5 stehen geblieben. Alles was danach kam, hatte ich bisher noch nicht benötigt.

Re: Variablenbezüge in Assembler innerhalb Pascal

Verfasst: So 17. Jun 2012, 11:24
von Dosenware
hier kommt noch einer: PChar ist ein pointer of array of char d.h. es ist
"Pchar[irgendwas zwischen 0 und 65535]:=char(bytevariable);"
möglich... sehr geil z.b. für den Bildspeicher -> Pchar einfach auf die Startadresse A000 setzen und schon hast du Spaß (ich weiß, geht auch mit Mem) - per absolute müssten dann auch 64kb Arrays of word und dword möglich sein... (16/32bit Farbtiefe - mit basteln auch 24bit)

Re: Variablenbezüge in Assembler innerhalb Pascal

Verfasst: So 17. Jun 2012, 15:31
von DOSferatu
Ja, wenn man sich's einfach machen will, kann man auch dieses tun:

var SC:array[0..199,0..319]of byte absolute $A000:0;
begin
asm mov ax,$13;int $10;end;
{hier das programm}
end;

Und schon kann man Pixel setzen mit SC[Y,X]:=Farbe;
oder Pixel holen mit Farbe:=SC[Y,X];
(Zu beachten, daß erst die Zeile, dann die Spalte genannt werden muß).
Genauso kann man sich dann auch so eine Art "Textmatrix" bauen:
var SCTXT:array[0..24,0..7,0..39,0..7]of byte absolute $A000:0;
Und man kann die Pixel von so 8x8-Pixel-Zeichen setzen:
SC[Zeile,Zeichenzeile,Spalte,Zeichenspalte]:=Zeichenfarbe;

Ist zwar lame und nicht effizient - aber wenn's mal schnell gehen muß...

Re: Variablenbezüge in Assembler innerhalb Pascal

Verfasst: Mo 7. Apr 2014, 20:52
von zatzen
Ich wollte nicht extra nen Thread aufmachen und denk das Thema passt hier am besten:

Es geht um Units in TP.

Vielleicht nur ne Frage des Programmierstils, aber:

Ist es besser, im Interface-Teil nur Prozeduren und keine Variablen zu "veröffentlichen"?

So würde ich, anstatt bestimmte programmübergreifende Datenfelder im Interface-Teil
zu definieren, stattdessen kleine Prozeduren machen, die einen Pointer auf Strukturen
legen, welche im Hauptprogramm definiert sind.

Ist das sinnvoll?

Re: Variablenbezüge in Assembler innerhalb Pascal

Verfasst: Di 8. Apr 2014, 12:11
von freecrac
zatzen hat geschrieben:Ich wollte nicht extra nen Thread aufmachen und denk das Thema passt hier am besten:

Es geht um Units in TP.

Vielleicht nur ne Frage des Programmierstils, aber:

Ist es besser, im Interface-Teil nur Prozeduren und keine Variablen zu "veröffentlichen"?

So würde ich, anstatt bestimmte programmübergreifende Datenfelder im Interface-Teil
zu definieren, stattdessen kleine Prozeduren machen, die einen Pointer auf Strukturen
legen, welche im Hauptprogramm definiert sind.

Ist das sinnvoll?
Wird dadurch weniger Speicher verwendet?

Dirk

Re: Variablenbezüge in Assembler innerhalb Pascal

Verfasst: Di 8. Apr 2014, 13:27
von zatzen
Da bin ich mir nicht sicher, ob dadurch weniger Speicher verwendet wird.

Ich hätte nur auch einfach mehr ein Gefühl von Ordnung, wenn ich im
Hauptprogramm alle Datenfelder anlege, auf die das Hauptprogramm
und die Units gemeinsam Zugriff habe, ohne dass ich mir durch eine
Unit irgendein dickes Array "einfange".

Es ist eine Weile her dass ich ein sehr umfangreiches Programm mit
dutzenden Units geschrieben habe... Da kann ich ja nochmal reingucken.

Ich denke aber auch, die Frage stellt sich mir hier nur deshalb, weil
ich gerade einen Converter der Einfachheit halber in Free Pascal stricke.
Und da gibt es (fast) keine Grenzen was die Anzahl der Variablen und die
Größe der Datenfelder angeht. In DOS-Pascal werde ich aber mit Pointern
und Getmem arbeiten müssen.

Re: Variablenbezüge in Assembler innerhalb Pascal

Verfasst: Do 10. Apr 2014, 18:32
von DOSferatu
Pascal (zumindest Borland Pascal) compiliert nur das, was wirklich gebraucht, d.h. irgendwo aufgerufen/verwendet wird.
D.h. wenn eine Variable (oder Array) an keiner Stelle von irgendeinem Programm/Programmteil benutzt wirdm wird sie auch nicht "eincompiliert" - d.h. keine Speicher dafür reserviert usw.

Wichtig: In der Unit ist ALLES enthalten, was man angibt. Es liegt dann am "Hauptprogramm", das diese Units verwendet, was aus diesen Units dann benutzt (compiliert) wird und was nicht.
Es spielt dabei erst einmal keine Rolle, ob im INTERFACE Bereich oder nicht.
Der Unterschied ist nur, daß Variablen/Konstanten/Procedures/Functions, die NICHT im INTERFACE Bereich der Unit deklariert sind, NUR innerhalb der Unit "bekannt" sind (nur von Procedures/Functions innerhalb dieser Unit benutzt werden können), also daß das Hauptprogramm die Namen (Bezeichner) dieser Elemente nicht kennt.
(Ich hoffe, ich konnte es einigermaßen verständlich erklären.)

Re: Variablenbezüge in Assembler innerhalb Pascal

Verfasst: So 13. Apr 2014, 20:09
von zatzen
Trotzdem hätte ich das bestreben, das Benutzen von Units nicht ineinander zu verschachteln,
d.h. dass eine Unit A selbst eine Unit B benutzt welche ebenfalls von einer Unit C benutzt wird,
die aber auch Unit A benutzt... Die Frage ist da aber auch, ob Unit C automatisch Unit B benutzen
kann. Nuja, kann ich ja ausprobieren.

Dann noch eine Sache, eine Unit hat ja auch einen "Hauptprogramm"-Teil.
Darin könnte man Variablen initialisieren oder irgendwelche initiierenden
Dinge laufen lassen. Allerings packe ich soetwas lieber in eine Procedure
wie z.B. "Init_blabla", die dann von dem Programm das die Unit verwendet
aufgerufen werden muss.

Re: Variablenbezüge in Assembler innerhalb Pascal

Verfasst: So 13. Apr 2014, 23:17
von zatzen
Ok, noch eine verwandte Fragestellung:

Für meine Grafikroutinen benötige ich, da ich je nach Blocktyp verschiedene Routinen
verwende, eine Auswertung des "Headers" eines jeden Blocks, wovon ausgehend dann
die entsprechenden Routinen aufgerufen werden sollen.

Rein Pascal-mäßig würde man das vielleicht am ehesten mit Select Case lösen.

Jetzt weiss ich aber nicht, wie optimierend der Compiler das umsetzt.

In Assembler würde ich die Header-Info in AL einlesen, und dann entsprechende
Vergleiche mit CMP durchführen, so dass ich nur jeweils einmal auf den Speicher
zugreifen muss, eben für eine gewisse Zahl mit der ich AL vergleiche.

Dabei wäre es mir aber zu unübersichtlich, wenn ich die Assembler Routinen
am langen Stück hätte und diese einfach anspringen würde.
Vielmehr hätte ich lieber diese Entscheidungsroutine in Assembler, welche
dann per CALL die einzelnen Routinen aufruft.

Ich kann es mir fast schon selber erklären, aber frage vorab nochmals nach.

Könnte es quasi so aussehen?

Code: Alles auswählen

procedure blocktyp1; assembler;
asm
 ...
end;

procedure blocktyp2; assembler;
asm
 ...
end;

procedure ...
...


procedure choose; assembler;
asm
  cmp al, 1
  jne @2
  call blocktyp1
  jmp ende
  
  @2:
  cmp al, 2
  jne @3
  call blocktyp2
  jmp ende

  @3:
  cmp al, 3
  ...

  ende:
end;
Für "choose" müsste man dann vorher in al den entsprechenden Wert übergeben.
Konkret muss man diesen mit 15 ANDen, weil die restlichen Bits noch Parameter beinhalten.

Besser wäre es noch, wenn man die Speicheradressen der Routinen in ein Datenfeld laden könnte.
So würde man sich je nachdem viele Vergleiche und Speicherzugriffe sparen. Aber wie das
geht, und wie man die dann aufruft, das weiss ich nicht. Aber... Vielleicht einfach Pointer auf die Procedures setzen?

Re: Variablenbezüge in Assembler innerhalb Pascal

Verfasst: Mo 14. Apr 2014, 00:27
von Dosenware
zatzen hat geschrieben: Rein Pascal-mäßig würde man das vielleicht am ehesten mit Select Case lösen.
Jetzt weiss ich aber nicht, wie optimierend der Compiler das umsetzt.
if then else ist schneller... ernsthaft.
In Assembler würde ich die Header-Info in AL einlesen, und dann entsprechende
Vergleiche mit CMP durchführen
Ich würde mit einer Sprungtabelle arbeiten, ist rasend schnell.

Sagen wir ein JMP hat 3 byte. (finde grad meine alten Sourcen nicht)

dann sieht das ganze in etwa so aus:

Code: Alles auswählen

Procedure P0;
Begin;end;

Procedure P1;
begin;end;

Procedure P2;
begin;end;

{Sprungtabelle im Hauptprogramm}
...
asm
 MOV DX,0
 MOV DL, Blocktyp {Dein Selector}
 SHL DX,2 {DX*4)

{EDIT: mir fällt grad auf dass diese Zeile dank relativer  Sprünge gar nicht benötigt wird...}
 ADD DX,@SPRUNGTAB {Startadresse der Sprungtabelle hinzuaddieren}
{/EDIT} 

 PUSH @END {Rücksprungadresse auf den Stack schieben, für den RET der Unterprogramme}
 JMP DX


:SPRUNGTAB {Die eigentliche Sprungtabelle}
 JMP P0 {Ich gehe mal davon aus, dass ein NEAR JMP 3byte hat}
 NOP {das NOP ist ein lückenfüller um oben die schnellen Rotationsbefehle nutzen zu können}
 JMP P1
 NOP
 JMP P2
 NOP
 ...
:END
end;
{/ENDE Sprungtabelle}

Re: Variablenbezüge in Assembler innerhalb Pascal

Verfasst: Mo 14. Apr 2014, 01:03
von zatzen
Danke, ich frage mich nur gerade ob man statt JMP da nicht ein CALL braucht. Aber nein, ich verstehe, wir
bauen uns das quasi selber.
Was mir bisher untergekommen ist war, dass ein Near Jump über einen Shortint funktioniert.
Daher wäre ich mir hier nicht so sicher ob die entsprechenden Routinen immer innerhalb -128 bis + 127
Byte liegen. Das müsste man klären, denn ich bin mir ziemlich sicher, dass man dort einen 16 Bit
Wert benötigt. Aber darum kümmert sich ja der Compiler, so dass man tatsächlich nur überlegen
braucht, ob es wirklich jeweils 3 Byte sind und die Sprungtabelle somit stimmig ist.
Neu ist mir aber auch, dass man Adressen einfach in Register oder auf den Stack schieben kann,
und dass Labels mit Doppelpunkt beginnen können anstatt dass man ihn dahinter schreibt.
Überhaupt auch, dass der Name einer Prozedur für den Assembler das Label einer Adresse darstellt.
Eine Sache noch: mov dx, 0 - ist xor dx, dx nicht schneller?

Re: Variablenbezüge in Assembler innerhalb Pascal

Verfasst: Mo 14. Apr 2014, 01:14
von Dosenware
zatzen hat geschrieben:Danke, ich frage mich nur gerade ob man statt JMP da nicht ein CALL braucht. Aber nein, ich verstehe, wir
bauen uns das quasi selber.
Jepp, deshalb speichern wir die Adresse von END auf dem Stack - damit der RET des Unterprogramms seine Rücksprungadresse hat.
Ich hatte mir sowas schonmal gebaut (hatte den 8085 Rechner von meiner Ausbildung emuliert) - allerdings finde ich die Sourcen (mit Sprungtabelle) nicht mehr - ich weiß aber noch: SCHNELL...
Was mir bisher untergekommen ist war, dass ein Near Jump über einen Shortint funktioniert.
Daher wäre ich mir hier nicht so sicher ob die entsprechenden Routinen immer innerhalb -128 bis + 127
Byte liegen.
Afair ist das ein relativer Sprung, der Near (immernoch AFAIR) JMP hüpft innerhalb des Codesegments hin und her: d.h. 16Bit Adresse
-> für deine Sprungtabelle aus 16 Einträgen reicht der 128 Byte JMP
Neu ist mir aber auch, dass man Adressen einfach in Register oder auf den Stack schieben kann
natuerlich, sind doch nur Zahlen - evtl. musst du Assm bescheid geben dass du nur den Offset brauchst.
und dass Labels mit Doppelpunkt beginnen können anstatt dass man ihn dahinter schreibt. Überhaupt auch, dass der Name einer Prozedur für den Assembler das Label einer Adresse darstellt.
alles Pseudocode, ist ewig her dass ich Programmiert habe - aber ich denke, dass zumindest die Funktionsweise deutlich wird.
Eine Sache noch: mov dx, 0 - ist xor dx, dx nicht schneller?
kommt auf den Prozessor an.

EDIT: hatte damals übrigens mit dem Inlineassembler von Pascal gearbeitet.
EDIT2: In Pascal könntest du aber auch folgendes machen:

Code: Alles auswählen

Procedure P0;begin;end;
Procedure P1;begin;end;
Procedure P1;begin;end;
...
var Proce:array[0..15] of Procedure;
var x:byte;

begin;
 {INITIALISIERUNG}
 Proce[0]:=P0;
 Proce[1]:=P1;
 ...

 x:=x and $0F;
 Proce[x];
 ...
end.
Ist im endeffekt das gleiche, das ganze ist nur ein Array von typisierten Zeigern.

PPS. der 128byte JMP ist ein Short Jump, der Near Jump springt innerhalb eines Segments und der Far Jump spring überall hin.

Re: Variablenbezüge in Assembler innerhalb Pascal

Verfasst: Mo 14. Apr 2014, 07:57
von freecrac
Moin.
zatzen hat geschrieben: procedure choose; assembler;
asm
cmp al, 1
jne @2
call blocktyp1
jmp ende

@2:
cmp al, 2
jne @3
call blocktyp2
jmp ende

@3:
cmp al, 3
...

ende:
end;
[/code]
Wenn man viele Werte hat die man vergleichen möchte, dann macht es Sinn die Vergleichswerte in eine Tabelle zu legen. Und anstelle dass die Vergleichswerte mit vielen einzelenen Abfragen untereinander plaziert überprüft werden, kann man dann alle Werte in einer Schleife von einem einzigen Vergleichsbefehl überprüfen lassen und dabei den Zeiger innerhalb der Tabelle erhöhen, wenn der Wert noch nicht gefunden wurde, um danach auf den nächsten Eintrag in der Tabelle zugreifen zu können.

Wenn der Wert gefunden wurde, dann können wir danach von dem Zeiger die Offset-Adresse der Tabelle abziehen und erhalten damit die Position innerhalb der Tabellle. Nun können wir zu dem Positionswert eine neue Offset-Adresse von einer Sprungtabellle hinzuaddieren und darüber zu einer Routine verzweigen.

Die Einträge in der Sprungtabellle enthalten 16 Bit Offset-Adressen und im Falle unsere Vergleichswerte in der Tabelle nur ein Byte gross sind, können wir die ermittelte Position verdoppeln, damit wir danach auf den richtigen Eintrag in der Sprungtabelle zugreifen können.

Beispiel:

Code: Alles auswählen

; Vergleichswerte
TABELLE DB 1,2,3,4,5,6,7,8,9,10
tablen = ($-TABELLE)

; Sprungtabellle
JUMPTAB DW OFFSET ROUTINE1, OFFSET ROUTINE2, OFFSET ROUTINE3, ...... usw.

       mov  si,OFFSET TABELLE
	    mov  cx,tablen           ; länge
SUCH:  cmp  al,[si] 
	    jz  short FOUND          ;  gefunden ?
	    inc  si
 	   dec  cx
	    jnz SUCH
       jmp NOTFOUND

FOUND: sub  si,OFFSET TABELLE
       lea  si,[si+si+OFFSET JUMPTAB]
       mov  ax,[si]             ; Sprungadresse
Müsste doch auch mit einem Array von typisierten Zeigern als Sprungtabelle machbar sein, oder nicht?

Dirk