Variablenbezüge in Assembler innerhalb Pascal

Diskussion zum Thema Programmierung unter DOS (Intel x86)
Antworten
Benutzeravatar
zatzen
DOS-Guru
Beiträge: 518
Registriert: Di 17. Apr 2012, 05:10
Wohnort: bei Köln
Kontaktdaten:

Variablenbezüge in Assembler innerhalb Pascal

Beitrag von zatzen »

Ich stehe davor, mir einen Renderer bzw. Player für mein vereinfachtes Trackermodul-Format zu schreiben.

Der soll natürlich möglichst weitläufig in Assembler geschrieben werden, ich würde den bei Borland Pascal 7.0
integrierten verwenden.

Da ich Variablenbezüge bisher immer nur innerhalb einer procedure gemacht habe,
möchte ich fragen, wie ich mich in einem Assembler-Code auf beliebige Variablen
und Pointer beziehen kann, die ich irgendwo im Programm verwende.

Allein schon für die Samples, die jeweils mittels getmem einen Speicherbereich
nutzen sollen, muss ich wissen wie ich im ASM-Teil an die Daten rankomme, die
überall im 640K Bereich liegen können.

PS: Nervt eigentlich mein Avatar?
mov ax, 13h
int 10h

while vorne_frei do vor;
Brueggi

Re: Variablenbezüge in Assembler innerhalb Pascal

Beitrag von Brueggi »

Nein, dein Avatar nervt nicht :-)
Aber zum Thema Variablen, da reicht einfach z. B.

var b1: Byte;
w1: Word;

begin
.
.
asm
mov bx,w1
mov al,b1
.
.
.
end;

end.
wobo
DOS-Guru
Beiträge: 613
Registriert: So 17. Okt 2010, 14:40

Re: Variablenbezüge in Assembler innerhalb Pascal

Beitrag von wobo »

zatzen hat geschrieben: Da ich Variablenbezüge bisher immer nur innerhalb einer procedure gemacht habe,
möchte ich fragen, wie ich mich in einem Assembler-Code auf beliebige Variablen
und Pointer beziehen kann, die ich irgendwo im Programm verwende.

Allein schon für die Samples, die jeweils mittels getmem einen Speicherbereich
nutzen sollen, muss ich wissen wie ich im ASM-Teil an die Daten rankomme, die
überall im 640K Bereich liegen können.

PS: Nervt eigentlich mein Avatar?
Als Ergänzung zu Brueggi (Guten Morgen, Brueggi :-)):

Code: Alles auswählen

var p : pointer;
begin
    GetMem( p, 32768 );
    asm
        les di, p
        mov cx, 32768
        mov al, 0
        @ClearData:
            mov es:[di], al
            inc di
            dec cx
            jnz @ClearData
        end;
    end;
   FreeMem( p, 32768);
end.
PS: Avatar nervt mich schon ein bisschen. Bin nämlich mentaler Statiker... ...ich halt's aber aus ;-)
Benutzeravatar
zatzen
DOS-Guru
Beiträge: 518
Registriert: Di 17. Apr 2012, 05:10
Wohnort: bei Köln
Kontaktdaten:

Re: Variablenbezüge in Assembler innerhalb Pascal

Beitrag von zatzen »

Vielen Dank schonmal!

Ich fasse mal zusammen was ich mehr oder weniger jetzt neues gelernt habe:
- Sprungadressen beginnen immer mit einem @, danach kann aber ein beliebiger Name folgen
(habe das ursrpünglich mit Ziffern gelernt, das war dann etwas unübersichtlich).
Frage: Ist wirklich immer ein @ vonnöten oder geht das auch ohne?
- Pointer liest man, im Falle von Daten, mit les di, (pointervariable) aus,
und um sich auf die Variable selbst, also nicht den Pointer zu beziehen,
schreibt man bei es:[di] eben das di in eckigen Klammern.
Ich habe auch noch das Assembler-Buch von Trutz Eyke Podschun,
das wird mir einige "Tricks" verraten und mir Assembler umfassend
zu verstehen geben, allerdings hat es wenn ich mich recht entsinne
keine Anleitung für den Assembler innerhalb von Pascal.
Ausserdem aber auch nicht zu vergessen, Dosferatus sehr
gute Beschreibung der ASM Programmierung im Real Mode.

Etwas unsicher bin ich noch bzgl. der Frage ob ich mich in einer unter(!)-"procedure"
mit Assembler auch auf beliebige Variablen ausserhalb der Routine beziehen kann,
die weiter oben im Pascal code definiert sind und nicht in der Unter-Routine selbst.
Für reine Pascal-Unterroutinen funktioniert das ja, aber bei Assembler innerhalb
einr Unterroutine bin ich mir da nicht sicher.

Also z.B.:

Code: Alles auswählen

var bla: word;

procedure assembler_routine;
begin
  asm
    mov ax, bla
    inc ax
    mov bla, ax    { nur ne dumme demo, klar kann man auch direkt inc bla machen, oder? }
  end;
end;
{ zudem kann man die routine auch direkt als "assembler" deklarieren, aber es }
{ ist wahrscheinlich dass ich in so einer routine auch noch ein wenig mit pascal mache }

begin
   bla := 1;
   assembler_routine;
   writeln(bla);
end.
Und ich hab's getestet und et jeeeeiht!
Ihr braucht mir das jetzt nur noch zu bestätigen!




Meinen Avatar werde ich bei Gelegenheit durch was statisches oder "smootheres" ersetzen,
ein bisschen nervt er mich selbst auch, aber so ein Ding ist praktisch um direkt zu erkennen
von wem das Posting ist.
mov ax, 13h
int 10h

while vorne_frei do vor;
wobo
DOS-Guru
Beiträge: 613
Registriert: So 17. Okt 2010, 14:40

Re: Variablenbezüge in Assembler innerhalb Pascal

Beitrag von wobo »

zatzen hat geschrieben: Ich fasse mal zusammen was ich mehr oder weniger jetzt neues gelernt habe:
- Sprungadressen beginnen immer mit einem @, danach kann aber ein beliebiger Name folgen
(habe das ursrpünglich mit Ziffern gelernt, das war dann etwas unübersichtlich).
Frage: Ist wirklich immer ein @ vonnöten oder geht das auch ohne?
Sprungadressen (labels) müssen grundsätzlich in Pascal global, d.h. einmal im Programm vorher definiert sein. Es dürfen Bezeichner und Ziffernfolgen von 0 bis 9999 verwendet werden (alles ohne @), z.B. "label 1,2,Sprungziel;"

Diese Labels sind global, d.h. einmal definiert gelten sie für das gesamte Programm.

Labels innerhalb eines ASM-Blocks können auch lokal definiert werden, indem das @ vorangestellt wird. Das Label gilt nur innerhalb des ASM-Blocks. Dafür kann die Label-Bezeichnung im nächsten ASM-Block auf dieselbe Weise erneut verwendet werden. Es bezeichnet dann natürlich das neue, lokale Sprungziel.

Das @ bedeutet in Pascal übrigens immer den Verweis auf eine Speicherstelle. Du kannst so auch die Adresse einer Variable in Erfahrung bringen. @MyVar ist dann äquivalent zu addr(MyVar). Innerhalb eines ASM-Blocks bedeutet es halt Verweis auf die Speicherstelle, die durch Deinen Label-Identfier bezeichnet wird.

zatzen hat geschrieben: Etwas unsicher bin ich noch bzgl. der Frage ob ich mich in einer unter(!)-"procedure"
mit Assembler auch auf beliebige Variablen ausserhalb der Routine beziehen kann,
die weiter oben im Pascal code definiert sind und nicht in der Unter-Routine selbst.
[...]
Ihr braucht mir das jetzt nur noch zu bestätigen!
Ja jeeeeht.

PS: Meinetwegen musst Du Deinen Avatar natürlich nicht verändern. Es war nur so, dass Du ja explizit danach gefragt hattest ;-)
freecrac
DOS-Guru
Beiträge: 861
Registriert: Mi 21. Apr 2010, 11:44
Wohnort: Hamburg Horn

Re: Variablenbezüge in Assembler innerhalb Pascal

Beitrag von freecrac »

Bei Pascal muss ich passen.

Mit

les di, POINTER
POINTER DW ?, ? ; Offset, Segment

bekommt das DI-Register den Inhalt von POINTER und das ES-Register bekommt den Inhalt von POINTER+2.

:-------------------

Mit

mov es:[di], al

wird der Inhalt vom AL-Register zu der Adresse die sich aus ES:DI bildet geschrieben.
zatzen hat geschrieben: Etwas unsicher bin ich noch bzgl. der Frage ob ich mich in einer unter(!)-"procedure"
mit Assembler.....
Ich vermute die bezogenen Pointer auf bestimmte Varable dürften sich wohl nicht ändern in einer subroutine.
Aber wo/wie kann man die Stackgrösse für asm-subroutinen(call/ret) angeben?

Dirk
Benutzeravatar
zatzen
DOS-Guru
Beiträge: 518
Registriert: Di 17. Apr 2012, 05:10
Wohnort: bei Köln
Kontaktdaten:

Re: Variablenbezüge in Assembler innerhalb Pascal

Beitrag von zatzen »

Na gut, weiss ich erstmal bescheid.

Nächste Frage wären Multiplikationen / Divisionen in DWORD Dimensionen.

Ich meine in nem anderen Thread wurde sowas schon angesprochen.

Aber trotzdem nochmal ein Beispiel:

Ich müsste in diesem Player sehr oft folgendes ausrechnen:

Notenfaktor * C3-Frequenz / Mixfrequenz.

Alle Werte können jeweils volle WORD-Größe sein.

Der Notenfaktor müsste eigentlich beim C-3 1 sein, aber
da ich mit Festkomma rechnen will mache ich ihn dort auf 1024.
mov ax, 13h
int 10h

while vorne_frei do vor;
Brueggi

Re: Variablenbezüge in Assembler innerhalb Pascal

Beitrag von Brueggi »

Ich nehme an, du möchtest das via MUL und DIV rechnen? Würde ich - je nach dem, für welche CPU dein Programm ist, aber lassen oder nur eingeschränkt verwenden, denn das kann (gerade am 286) viel Takte kosten.

Teilst/Multiplizierst Du durch/mit einem Word, dann verwendet der Prozessor automatisch DX:AX / wort, wobei dann AX=Ergebnis und DX glaub ich der Rest ist, bei der Multiplikation ist DX:AX=AX*Wort.

Falls es irgendwie möglich ist, würde ich aber lieber eine Tabelle anlegen, in welcher zumindest die wichtigsten Werte schon vorab ausgerechnet zu finden sind. Das kostet am wenigsten Zeit (wobei das dann am Pentium oder so egal sein dürfte).

Ich habe jetzt die Takte nicht im Kopf, meine aber, das DIV und MUL erst ab dem 80386 richtig sparsam sind, vorher aber richtig viel Zeit "verbraten".

Edit:
Notenfaktor * C3-Frequenz / Mixfrequenz.

MOV AX,notenfaktor
MOV BX,C3
MUL BX -> DX:AX = Ergebnis
MOV BX,mixfrequenz
DIV BX -> AX=Ergebnis, DX sollte der Rest sein

So Pi-Mal-Daumen würd ich das jetzt mal als Beispiel durchgehen lassen ;-)
wobo
DOS-Guru
Beiträge: 613
Registriert: So 17. Okt 2010, 14:40

Re: Variablenbezüge in Assembler innerhalb Pascal

Beitrag von wobo »

zatzen hat geschrieben:Na gut, weiss ich erstmal bescheid.

Nächste Frage wären Multiplikationen / Divisionen in DWORD Dimensionen.

Ich meine in nem anderen Thread wurde sowas schon angesprochen.

Aber trotzdem nochmal ein Beispiel:

Ich müsste in diesem Player sehr oft folgendes ausrechnen:

Notenfaktor * C3-Frequenz / Mixfrequenz.

Alle Werte können jeweils volle WORD-Größe sein.

Der Notenfaktor müsste eigentlich beim C-3 1 sein, aber
da ich mit Festkomma rechnen will mache ich ihn dort auf 1024.

Ich wollte schon immer mal anfangen, Assembler zu lernen. Deswegen nutze ich mal diese Gelegenheit zum üben :-):

Auf eine dword-Lösung bin ich leider nicht gekommen. Bei mir ist es nur eine 286/16-bit Lösung und setzt nur das um (hoffentlich), was Brueggi gerade geschrieben hat.

Ich gehe mal davon aus, dass Du eine Tabelle mit 60 Einträgen hast, in die die Notenfaktoren mit 1024 multipliziert schon vorliegen. Denn diese sollten sich ja während des Programmablaufs nicht ändern. Ich gehe weiter davon aus, dass ein C-3 durch den Wert 36 repräsentiert ist.

Den konkreten Notenfaktor ermitteltest Du unter Pascal dann grds. mit

Notenfaktor := NotenfakTab[NotenNr];

Angenommen, Du hast in NotenNr die Nummer der Note (0-59) sowie C3Freq (4000-44000 khz) und MixSpeed (4000-44000 khz), dann müsste es so gehen:

Code: Alles auswählen

var Notenfaktor : array[0..59] of real;
     Notenf1024  : array[0..59] of word;

     i : integer;

     NotenNr,
     C3Freq, MixSpeed   : word;
     Stepspeed               : word;

begin

  for i := 0 to 59 do
  begin
    Notenfaktor[i] := exp( (-36+i)*ln(2)/12 );          {ok, keine wohltemperierte Stimmung :-(}
    Notenf1024[i] := Round(Notenfaktor[i]*1024); {Fixkomma-Wert}
  end;

  NotenNr := 36;           {C-3}
  C3Freq := 16000;
  MixSpeed := 22050;
  asm
    mov bx, NotenNr     
    add bx, bx                { Notenf1024 - Tabelle ist array of word, d.h. *2 }
    lea si, Notenf1024     { Tabelle liegt im Datensegment ds } 
    mov ax, [si+bx]	   { ax := Notenf1024[NotenNr] }
    mov cx, C3Freq
    mul cx		           { ax*cx --> Ergebnis in dx:ax; (vorheriger inhalt von dx geht verloren)}
    mov bx, MixSpeed
    div bx		           { dx:ax div bx --> Ergebnis in ax (Quotient) und dx (Rest)}
    mov StepSpeed, ax
  end;
  writeln( StepSpeed );
  readln;

end.
Das Problem dürfte - falls nicht noch andere Fehler vorhanden sind - aber auch sein, dass ich eingangs bei der Erstellung der Notenfaktortabelle runde, und nun bei der Division den Rest unter den Tisch fallen lasse. Vielleicht wissen ja die Profis hier (Brueggi,DosFeratu,Freecrac (A-Z-Order!)} Rat, wie man die Genaugikeit verbessern kann.
Zuletzt geändert von wobo am So 29. Apr 2012, 12:03, insgesamt 1-mal geändert.
freecrac
DOS-Guru
Beiträge: 861
Registriert: Mi 21. Apr 2010, 11:44
Wohnort: Hamburg Horn

Re: Variablenbezüge in Assembler innerhalb Pascal

Beitrag von freecrac »

zatzen hat geschrieben:Na gut, weiss ich erstmal bescheid.

Nächste Frage wären Multiplikationen / Divisionen in DWORD Dimensionen.

Ich meine in nem anderen Thread wurde sowas schon angesprochen.

Aber trotzdem nochmal ein Beispiel:

Ich müsste in diesem Player sehr oft folgendes ausrechnen:

Notenfaktor * C3-Frequenz / Mixfrequenz.

Alle Werte können jeweils volle WORD-Größe sein.

Der Notenfaktor müsste eigentlich beim C-3 1 sein, aber
da ich mit Festkomma rechnen will mache ich ihn dort auf 1024.
Um es zu programmieren gibt es viele Möglichkeiten.
Am Ende sollte aber eigentlich immer versucht werden alles mit so wenig Speicherzugriffen wie möglich hinzubekommen.
Hat man noch Register frei die gerade nicht verwendet werden, dann sollte man dort ggf. Werte retten, anstelle den Wert in das RAM zu schreiben. Manchmal genügt es bei einer Routine die Benutzung der Register zu vertauschen, um wieder einen weiteren Speicherzugriff zu vermeiden und herauszunehmen. Je weniger Befehle wir für eine bestimmte Aufgabe benötigen, um so übersichtlicher wird unser Code und damit sinkt auch die Wahrscheinlichkeit das sich dort Fehler einschleichen. Am Anfang bei der Entwicklung einer Routine ist das aber nicht unbedingt so wichtig. Hierbei geht es schlicht nur darum es überhaupt einmal funktionstüchtig hin zu bekommen.

Nun brauchen wir noch ein paar Befehle für die Berechnungen.

Bei der vorzeichenlosen Division mit dem DIV-Befehl dürfen wir nicht vergessen, das DX, oder EDX zum Dividend bei einigen Varianten des Befehl mit dazu gehört.

http://courses.engr.illinois.edu/ece390 ... neral.html

B.4.134 SHL, SHR: Bitwise Logical Shifts
SHL r/m8,1 ; D0 /4 [8086]
SHL r/m8,CL ; D2 /4 [8086]
SHL r/m8,imm8 ; C0 /4 ib [186]
SHL r/m16,1 ; o16 D1 /4 [8086]
SHL r/m16,CL ; o16 D3 /4 [8086]
SHL r/m16,imm8 ; o16 C1 /4 ib [186]
SHL r/m32,1 ; o32 D1 /4 [386]
SHL r/m32,CL ; o32 D3 /4 [386]
SHL r/m32,imm8 ; o32 C1 /4 ib [386]

SHR r/m8,1 ; D0 /5 [8086]
SHR r/m8,CL ; D2 /5 [8086]
SHR r/m8,imm8 ; C0 /5 ib [186]
SHR r/m16,1 ; o16 D1 /5 [8086]
SHR r/m16,CL ; o16 D3 /5 [8086]
SHR r/m16,imm8 ; o16 C1 /5 ib [186]
SHR r/m32,1 ; o32 D1 /5 [386]
SHR r/m32,CL ; o32 D3 /5 [386]
SHR r/m32,imm8 ; o32 C1 /5 ib [386]

SHL and SHR perform a logical shift operation on the given source/destination (first) operand. The vacated bits are filled with zero.

A synonym for SHL is SAL (see Section B.4.127). NASM will assemble either one to the same code.

The number of bits to shift by is given by the second operand. Only the bottom five bits of the shift count are considered by processors above the 8086.

You can force the longer (286 and upwards, beginning with a C1 byte) form of SHL foo,1 by using a BYTE prefix: SHL foo,BYTE 1. Similarly with SHR.
B.4.105 MUL: Unsigned Integer Multiply
MUL r/m8 ; F6 /4 [8086]
MUL r/m16 ; o16 F7 /4 [8086]
MUL r/m32 ; o32 F7 /4 [386]

MUL performs unsigned integer multiplication. The other operand to the multiplication, and the destination operand, are implicit, in the following way:

* For MUL r/m8, AL is multiplied by the given operand; the product is stored in AX.
* For MUL r/m16, AX is multiplied by the given operand; the product is stored in DX:AX.
* For MUL r/m32, EAX is multiplied by the given operand; the product is stored in EDX:EAX.
B.4.76 IMUL: Signed Integer Multiply
IMUL r/m8 ; F6 /5 [8086]
IMUL r/m16 ; o16 F7 /5 [8086]
IMUL r/m32 ; o32 F7 /5 [386]

IMUL reg16,r/m16 ; o16 0F AF /r [386]
IMUL reg32,r/m32 ; o32 0F AF /r [386]

IMUL reg16,imm8 ; o16 6B /r ib [186]
IMUL reg16,imm16 ; o16 69 /r iw [186]
IMUL reg32,imm8 ; o32 6B /r ib [386]
IMUL reg32,imm32 ; o32 69 /r id [386]

IMUL reg16,r/m16,imm8 ; o16 6B /r ib [186]
IMUL reg16,r/m16,imm16 ; o16 69 /r iw [186]
IMUL reg32,r/m32,imm8 ; o32 6B /r ib [386]
IMUL reg32,r/m32,imm32 ; o32 69 /r id [386]

IMUL performs signed integer multiplication. For the single-operand form, the other operand and destination are implicit, in the following way:

* For IMUL r/m8, AL is multiplied by the given operand; the product is stored in AX.
* For IMUL r/m16, AX is multiplied by the given operand; the product is stored in DX:AX.
* For IMUL r/m32, EAX is multiplied by the given operand; the product is stored in EDX:EAX.

The two-operand form multiplies its two operands and stores the result in the destination (first) operand. The three-operand form multiplies its last two operands and stores the result in the first operand.

The two-operand form with an immediate second operand is in fact a shorthand for the three-operand form, as can be seen by examining the opcode descriptions: in the two-operand form, the code /r takes both its register and r/m parts from the same operand (the first one).

In the forms with an 8-bit immediate operand and another longer source operand, the immediate operand is considered to be signed, and is sign-extended to the length of the other source operand. In these cases, the BYTE qualifier is necessary to force NASM to generate this form of the instruction.
B.4.23 DIV: Unsigned Integer Divide
DIV r/m8 ; F6 /6 [8086]
DIV r/m16 ; o16 F7 /6 [8086]
DIV r/m32 ; o32 F7 /6 [386]

DIV performs unsigned integer division. The explicit operand provided is the divisor; the dividend and destination operands are implicit, in the following way:

* For DIV r/m8, AX is divided by the given operand; the quotient is stored in AL and the remainder in AH.
* For DIV r/m16, DX:AX is divided by the given operand; the quotient is stored in AX and the remainder in DX.
* For DIV r/m32, EDX:EAX is divided by the given operand; the quotient is stored in EAX and the remainder in EDX.
B.4.75 IDIV: Signed Integer Divide
IDIV r/m8 ; F6 /7 [8086]
IDIV r/m16 ; o16 F7 /7 [8086]
IDIV r/m32 ; o32 F7 /7 [386]

IDIV performs signed integer division. The explicit operand provided is the divisor; the dividend and destination operands are implicit, in the following way:

* For IDIV r/m8, AX is divided by the given operand; the quotient is stored in AL and the remainder in AH.
* For IDIV r/m16, DX:AX is divided by the given operand; the quotient is stored in AX and the remainder in DX.
* For IDIV r/m32, EDX:EAX is divided by the given operand; the quotient is stored in EAX and the remainder in EDX.
Dirk
wobo
DOS-Guru
Beiträge: 613
Registriert: So 17. Okt 2010, 14:40

Re: Variablenbezüge in Assembler innerhalb Pascal

Beitrag von wobo »

freecrac hat geschrieben:Bei Pascal muss ich passen.

[...]
Ich vermute die bezogenen Pointer auf bestimmte Varable dürften sich wohl nicht ändern in einer subroutine.
Aber wo/wie kann man die Stackgrösse für asm-subroutinen(call/ret) angeben?

Dirk
Du meinst in (Turbo) Pascal? Da musst Du eigentlich nichts berechnen, das macht alles Pascal, z.B:

Code: Alles auswählen

procedure SetPixel( x, y : integer; farbe : byte ); assembler;  {Pixel setzen in 320x200p8}
asm
   mov ax, $A000
   mov es, ax
   mov ax, y
   mul 320
   mov di, x
   add di, ax
   mov al, farbe
   mov es:[di], al
end;  {Stack wird von Pascal aufgeräumt}
Benutzeravatar
zatzen
DOS-Guru
Beiträge: 518
Registriert: Di 17. Apr 2012, 05:10
Wohnort: bei Köln
Kontaktdaten:

Re: Variablenbezüge in Assembler innerhalb Pascal

Beitrag von zatzen »

VIelen Dank für die rege Beteiligung!

Ich denke damit kann ich jetzt durchstarten!

Nur nochmal um es klarzustellen:

Diese DWORD-Berechnungen würden recht selten auftreten.
Immer nur pro Zeile in einem Pattern, und ich hab 8 Kanäle.
Im Durchschnitt hätte ich vielleicht 40 solche Berechnungen
pro Sekunde...

Notenfaktor wäre eine Tabelle mit 108 WORD Werten,
die ich mir aus einer Tabelle zur realen temperierten
Stimmung generiere. A= 440 Hz, C=523,251 Hz usw...
(Der Tracker aus dem ich konvertiere kann 108 Noten).

Die anderen beiden Werte sind beliebig und müssen daher immer
neu in die Rechnung mit einbezogen werden.
Theoretisch könnte ich aber die Mixfrequenz noch "rauskürzen",
indem ich z.B. 3 Tabellen anlege für die Mixfrequenzen
11025, 22050 und 44100 Hz, das müsste eigentlich flexibel
genug sein. Evtl. noch 32000 Hz, das klingt nämlich in der
Praxis genauso "edel" wie 44100.
Oder, anders auch, einfach einen Divisor bzw. Multiplikator mit einbeziehen.

C-3 Frequenz kann theoretisch alles zwischen 1 und 65535 HZ sein,
wird aber in der Praxis irgendwo zwischen 4 kHz und 44100 Hz liegen,
wobei ich aus Sparsamkeit wohl nie höher als 22050 Hz gehen werde.
Aber für klitzekleine Hihats oder so schaden 44100 Hz nicht ;-)
mov ax, 13h
int 10h

while vorne_frei do vor;
freecrac
DOS-Guru
Beiträge: 861
Registriert: Mi 21. Apr 2010, 11:44
Wohnort: Hamburg Horn

Re: Variablenbezüge in Assembler innerhalb Pascal

Beitrag von freecrac »

wobo hat geschrieben:
freecrac hat geschrieben:Bei Pascal muss ich passen.

[...]
Ich vermute die bezogenen Pointer auf bestimmte Varable dürften sich wohl nicht ändern in einer subroutine.
Aber wo/wie kann man die Stackgrösse für asm-subroutinen(call/ret) angeben?

Dirk
Du meinst in (Turbo) Pascal? Da musst Du eigentlich nichts berechnen, das macht alles Pascal, z.B:

Code: Alles auswählen

procedure SetPixel( x, y : integer; farbe : byte ); assembler;  {Pixel setzen in 320x200p8}
asm
   mov ax, $A000
   mov es, ax
   mov ax, y
   mul 320
   mov di, x
   add di, ax
   mov al, farbe
   mov es:[di], al
end;  {Stack wird von Pascal aufgeräumt}
Ich meinte eigentlich wenn dort verschachtelte Unterprogrammaufrufe vorgenommen werden, oder mit dem push-Befehl etwas auf den Stack geschoben wird. Dafür muss der Stack ja gross genug sein.

Beispiel:

Code: Alles auswählen

procedure blabla
asm
; Anfang der Hauptroutine
call Subroutine1
; Ende der Hauptroutine
; Wie sagt man TP nun bescheid das hier Ende ist, aber die folgenden Subroutinen ebenfalls benötigt werden?

; Anfang der Subroutinen
Subroutine1: pushad
             call Subroutine2
             popad
             ret

Subroutine2: pushad
             call Subroutine3
             popad
             ret

Subroutine3: pushad
             call Subroutine4
             popad
             ret

Subroutine4: ret

end;
Oder muss man für jede Subroutine eine eigene Pascal-procedure verwenden?

Aber was wenn man mit einem far call eine Bios-Subroutine(z.B. jene für die VESA-Bankumschaltung) aufrufen möchte?

Zählt Pascal etwa alle push und call Befehle die wir verwenden möchten durch, um den Stack gross genug zu dimensionieren?

Dirk
wobo
DOS-Guru
Beiträge: 613
Registriert: So 17. Okt 2010, 14:40

Re: Variablenbezüge in Assembler innerhalb Pascal

Beitrag von wobo »

freecrac hat geschrieben: Ich meinte eigentlich wenn dort verschachtelte Unterprogrammaufrufe vorgenommen werden, oder mit dem push-Befehl etwas auf den Stack geschoben wird. Dafür muss der Stack ja gross genug sein.

Beispiel:

Code: Alles auswählen

procedure blabla
asm
; Anfang der Hauptroutine
call Subroutine1
; Ende der Hauptroutine
; Wie sagt man TP nun bescheid das hier Ende ist, aber die folgenden Subroutinen ebenfalls benötigt werden?

; Anfang der Subroutinen
Subroutine1: pushad
             call Subroutine2
             popad
             ret

Subroutine2: pushad
             call Subroutine3
             popad
             ret

Subroutine3: pushad
             call Subroutine4
             popad
             ret

Subroutine4: ret

end; 
Oder muss man für jede Subroutine eine eigene Pascal-procedure verwenden?
Ja, man muss für jede Subroutine eine eigene Pascal-Procedure schreiben (Du bist ja auch unter Pascal), z.B.:

Code: Alles auswählen

procedure Sub01; assembler;
asm
  mov ax, 25
  [...]
end;

procedure Sub02( w : word ); assembler;
asm
  mov ax, w
  pusha
  call Sub01
  popa 
  [...]
end;

procedure Haupt( w1, w2 : word);
var Summe: word;
begin
   Summe := w1+w2;
   asm
     mov ax, Summe
     pusha
     push ax
     call Sub02
     popa
     mov Summe, ax
   end;
   writeln( Summe );
end;
Die Subroutinen müssen vor den Routinen stehen, die die Subroutinen aufrufen.
Turbo Pascal ist für 80286, d.h. kann grundsätzlich nur 16-bit/286-instructions. "Pushad" etc. geht also grundsätzlich nicht.

Parameter kommen auf den Stack und werden von der Subroutine beim Verlassen auch wieder entfernt.
Lokale Variablen werden wie unter Pascal angelegt und ebenfalls automatisch beim Verlassen der procedure vom Stack entfernt.
Alles andere, was Du auf den Stack schmeißt, mußt Du auch wieder selbst entfernen (z.B.: die pusha/popa oben).

Irgendwo habe ich mal gelesen, dass man den in Pascal integrierten Assembler als logischen Assembler bezeichnet, da man grundsätzlich keine Adressen berechnen muss. Wenn mir also einfällt, ich brauchte noch 6 Variablen, dann kann ich sie gefahrlos vor (und natürlich auch nach) der bereits angelegten lokalen Variable "Summe" anlegen, ohne dass ich am Code was ändern müßte.
Also z.B.:

Code: Alles auswählen

procedure Haupt( w1, w2 : word);
var   ich, bin, so, ver, gess, lich : byte;
      Summe: word;
begin
   Summe := w1+w2;
   asm
     mov ax, Summe
     pusha
     push ax
     call Sub02
     popa
     mov Summe, ax
   end;
   writeln( Summe );
end;
freecrac hat geschrieben:Aber was wenn man mit einem far call eine Bios-Subroutine(z.B. jene für die VESA-Bankumschaltung) aufrufen möchte?
Leider habe ich mit VESA noch nichts gemacht. Wie kommt man denn an die Bankumschaltungsroutine und welche Parameter erwartet diese?
freecrac hat geschrieben:Zählt Pascal etwa alle push und call Befehle die wir verwenden möchten durch, um den Stack gross genug zu dimensionieren?
Nein. Der Programmierer muss gucken, dass der Stack groß genug ist. Pascal entfernt nur nach Verlassen einer Subroutine die übergebenen Parameter und die angelegten lokalen Variablen sowie die Rücksprungadresse.
Benutzeravatar
zatzen
DOS-Guru
Beiträge: 518
Registriert: Di 17. Apr 2012, 05:10
Wohnort: bei Köln
Kontaktdaten:

Re: Variablenbezüge in Assembler innerhalb Pascal

Beitrag von zatzen »

Habe das jetzt erstmal nur überflogen da ich gleich weg muss,

aber das mit den Subroutinen ist genau die Sache die ich auch

berücksichtigen muss.



Denn ich will ne Player-Routine schreiben, und die müsste
mitten während der Pufferbefüllung eine Sampleposition
oder die Schrittgröße, mit der ein Sample durchgegangen
wird, neu berechnen bzw. ändern.
Also muss ich da Subroutinen callen.
Wenn ich innerhalb von

Code: Alles auswählen

procedure dingsbums;
begin
  asm
   (was auch immer)
  end
end;
keine Subroutinen callen kann,
kann ich das ganze nicht einfach durch Sprünge umsetzen?
Also;

Code: Alles auswählen

procedure springeling
  asm
     jmp @weiter
     @subroutine:
        ...
     jmp @weiter
     cmp al, ah
     jz @subroutine
     @weiter:
        ...
  end;
end;
Naja so ungefähr. Hab etwas langer nicht mehr in Assembler gecodet,
aber die Frage ist halt, muss ich Subroutinen mit call und ret einbinden
oder geht's nicht auch einfach mit Sprüngen...

Natürlich haben Subroutinen die mal mit call aufruft den Vorteil, dass die
Register für die andere Aufgabe wieder frei sind. Aber, wenn ich euch
richtig verstehe, geht das nicht innerhalb eines asm - end blocks sondern
nur mit als reinen assembler deklarierten Subroutinen.
mov ax, 13h
int 10h

while vorne_frei do vor;
Antworten