Forum: PC-Programmierung Daten auslesen in ASM aus einer Variable.


von Peter B. (funkheld)


Lesenswert?

Hallo, guten Tag.
Frohen Weihnachtstag,

Ich habe hier eine kleine Demo für DOS:
-------------------------------------------
DIM  HUGE buff1(63999) as byte
DIM bufseg1 as WORD
bufseg1 = varseg(buff1(0))

DIM  HUGE buff2(63999) as byte
DIM bufseg2 as WORD
bufseg2 = varseg(buff2(0))

!  mov  ax,bufseg1
!  push ax
!  pop  es

!   mov cx,320
!   mov di,0
forloop:
!  mov  al,1
!  mov  es:[di],al
!  inc  di
!  loop  forloop
.......
.......
-----------------------------------------
Ich lese 320x eine 1 ein in die Variable-Segment bufseg1.
Es funktioniert auch.
Wie kann ich jetzt bitte wieder die 320 Werte auslesen aus der bufseg1 
und in bufseg2 rein in den nächsten Befehlen mit ASM?

Danke.

: Bearbeitet durch User
von Kurt (sommerwin)


Lesenswert?

mov ax, bufseg1

push ax

pop es

mov bx, bufseg2

push bx

pop fs



mov di,0



forloop:


mov al, es:(di)

mov es:(di), al

inc di

loop forloop


...



so ähnlich sollte es gehen

schönes Fest

: Bearbeitet durch User
von Peter B. (funkheld)


Lesenswert?

Hallo , vielen dank für die Info.

von Kurt (sommerwin)


Lesenswert?

Sorry, so sollte das heissen:

mov fs:(di),al

Allerdings ist mir nicht klar, wie der Inhalt von CX in bi kommt, bi ist 
doch die Zählvariable. bi müsste mind. ein double sein, sonst kannst ja 
nur bis 255 zählen. Ich kenn sowas anders.

von Peter B. (funkheld)


Lesenswert?

Danke für die Info.
Habe es jetzt geschafft:

Angangsdaten in bufseg1 rein.
Daten aus bufseg1 raus und bei bufseg2 rein.
Diese fs funktionniert nicht in Powerbasic 3.5

Es funktioniert.
Weiß nicht wie man es einfacher machen kann ohne dauernd mit dem Wechsel 
in es.
1
DIM HUGE buff1(63999) as byte
2
DIM bufseg1 as WORD 
3
bufseg1 = varseg(buff1(0))
4
5
DIM  HUGE buff2(63999) as byte
6
DIM bufseg2 as WORD 
7
bufseg2 = varseg(buff2(0))
8
9
dim a as WORD 
10
11
a=0
12
13
!   mov es,bufseg1  
14
!   mov cx,40000
15
!   mov di,a
16
forloop:    
17
!   mov al,1    
18
!   mov  es:[di],al
19
!   inc  di  
20
!   loop  forloop  
21
22
!   mov cx,40000
23
!   mov di,a
24
forloop1:  
25
!   mov es,bufseg1    
26
!   mov  al,es:[di]
27
28
!   mov es,bufseg2      
29
!   mov  es:[di],al
30
!   inc  di  
31
!   loop  forloop1

: Bearbeitet durch User
von J. R. (yoc)


Lesenswert?

Bitte mal die Stringbefehle anschauen.
rep movsb
rep movsw

direction flag beachten.

Eine gute Hilfe war mir immer der Norton Guide.

von Ben B. (Firma: Funkenflug Industries) (stromkraft)


Lesenswert?

> Allerdings ist mir nicht klar, wie der Inhalt von CX in bi kommt,
> bi ist doch die Zählvariable. bi müsste mind. ein double sein,
> sonst kannst ja nur bis 255 zählen. Ich kenn sowas anders.
CX, (SI) und DI sind alle immer 16 Bit breit, kannst damit also von 
0..65535 zählen. CX lässt sich in CL und CH aufgeteilt ansprechen, diese 
repräsentieren jeweils die unteren und oberen 8 Bits.

SI und DI lassen sich nicht so einfach aufteilen bzw. man muss sie dazu 
in ein anderes Register laden. Ihre Aufgabe beschreibt sich aus dem 
Namen. SI ist Source Index und DI ist Destination Index. LODSB z.B. lädt 
ein Byte von DS:[SI] in AL (die unteren 8 Bit von AX) und erhöht SI um 
1. STOSB speichert ein Byte von AL in ES:[DI] und erhöht DI um 1.

von J. R. (yoc)


Lesenswert?

Ben B. schrieb:
> und erhöht DI um 1

Wenn DF = 0
bei DF = 1 decrement

siehe
CLD
STD

von Ben B. (Firma: Funkenflug Industries) (stromkraft)


Lesenswert?

Yep, wollte jetzt nur nicht gleich den kompletten x86er erklären. Daß 
man sich mit solchen Flags auskennen oder belesen sollte, setze ich mal 
voraus, denn die braucht man praktisch für alles.

von Purzel H. (hacky)


Lesenswert?

Die Zaehlvariable ist uebrigens immer CX, das wird implizit auf Null 
runtergezaehlt. Der Befehl loop enthaelt ein dec-cx @ jumpnz, und ein 
vorheriges mov CX, 320 macht nachher 320 Durchgaenge

: Bearbeitet durch User
von Rbx (rcx)


Lesenswert?

Purzel H. schrieb:
> Der Befehl loop enthaelt ein dec-cx @ jumpnz, und ein
> vorheriges mov CX, 320 macht nachher 320 Durchgaenge

Diesen Befehlszusammenhang gab es früher gar nicht, da musste man sich 
die Schleifen von Hand zusammenstricken.
Unabhängig davon wurden in professionellen Programmen mehr die 
rep-Goodies eingesetzt.
Die Norton-Guides waren hervorragend, u.a. weil P.N auch viel mit BASIC 
referenzieren konnte, und so auch schnell programmiertechnische 
Zusammenhänge deutlich machen konnte.

von Ben B. (Firma: Funkenflug Industries) (stromkraft)


Lesenswert?

Naja... doch schon. Ich habe durch mein Interesse an damaligen 
Computerviren in meiner Jugend recht viele Assemblerprogramme 
auseinandergepflückt und selbst geschrieben. Die Schleifen mit LOOP 
<blah> waren überall anzutreffen, genau wie die REP-basierten 
Wiederholungen z.B. REP SCASB, REP MOVSB oder auch REPZ/REPNZ. Gibt ja 
praktisch nichts woraus man nicht irgendwie eine Schleife basteln könnte 
und gerade bei Assembler wurde jeder dieser Kniffe auch irgendwo 
verwendet wenn es gerade ins Programm passt.

Oder wenn man Programme "optimiert" hat. XOR AX,AX ist beispielsweise 
zwei Byte kürzer als MOV AX,0 (müsste, XOR AX,AX ist glaube ich nur ein 
8 Bit OpCode wenn ich mich korrekt erinnere) oder XCHG AX,CX ist ein 
Byte kürzer als MOV AX,CX.

von Rolf M. (rmagnus)


Lesenswert?

Ben B. schrieb:
> Ihre Aufgabe beschreibt sich aus dem
> Namen. SI ist Source Index und DI ist Destination Index.

Übrigens ist das auch bei den allgemeinen Registern so. Die Sind zwar im 
Grunde beliebig nutzbar, aber es gibt bestimmte Instruktionen, die sie 
auch für spezifische Zwecke nutzen.
AX = Akku
BX = Base
CX = Count
DX = Data

von Ben B. (Firma: Funkenflug Industries) (stromkraft)


Lesenswert?

Das stimmt nicht uneingeschränkt, sie sind nicht beliebig nutzbar.

Sowas wie MOV AL, DS:[CX] geht nicht, weil solche Adressierungen nur mit 
BX, SI, DI und BP möglich sind.

von Rolf M. (rmagnus)


Lesenswert?

Genau sowas meinte ich mit "es gibt bestimmte Instruktionen, die sie 
auch für spezifische Zwecke nutzen". Deshalb ja auch nur "im Grunde".

von Rbx (rcx)


Lesenswert?

Rolf M. schrieb:
> Genau sowas meinte ich mit "es gibt bestimmte Instruktionen, die sie
> auch für spezifische Zwecke nutzen". Deshalb ja auch nur "im Grunde".

Was man sich merken sollte, ist, dass frühere CP-Systeme oft nur ein 
Register hatten, den typischen "Akkumulator".
Die Folge könnte sein, dass dann eben bestimmte Rechnungen über AX 
bevorzugt behandelt werden, bzw. schneller laufen.
Ob das noch aktuell Sinn macht, sei mal dahin gestellt.
Nette Lernhilfe ist eigentlich LEA 
(https://stackoverflow.com/questions/12869637/trouble-understanding-assembly-command-load-effective-address)
wo auch nur die üblichen Verdächtigen (zum Zusammenrechnen) gehen.

von Ben B. (Firma: Funkenflug Industries) (stromkraft)


Lesenswert?

LEA ist ja eigentlich nur ein Assembler-Hilfsmittel und kein echter 
Befehl, beim Assemblieren wird aus LEA SI,<label> ein MOV SI,<address>. 
Einer der Punkte, der das Disassemblieren von Programmen geringfügig 
erschwert, weil man erst ergründen muss, daß sowas z.B. mal ein LEA auf 
einen Puffer war. Viele Assembler erlauben auch sowas wie MOV SI,offset 
<label>, Ergebnis ist das Gleiche.

Register-Operationen sind alle sehr schnell, weil keinerlei Daten aus 
dem Speicher geholt oder hineingeschrieben werden müssen. Wenn man ein 
System mit langsamem Speicherzugriff hat, lohnt es sich natürlich, die 
Speicherzugriffe zu vermeiden.

Der Akkumulator ist so gut wie überall erforderlich, weil die 
Prozessoren sonst einfach sehr unflexibel werden. Ich finde Prozessoren 
mit ausschließlich einem Akkumulator ohne vollständigen Registersatz 
schon unflexibel. Deswegen bin ich bei µCs z.B. sehr schnell bei den 
AVRs gelandet, weil diese einen großen Register- und Befehlssatz bieten 
und nicht so eng genäht sind wie die PICs, die eher auf eine 
Programmierung mit Hochsprachen (C) optimiert zu sein scheinen. Da ist's 
egal was der Compiler aus dem Hochsprachenprogramm macht, aber kleiner 
und schneller (in der Ausführungsgeschwindigkeit) geht's natürlich mit 
dem AVR. Ansonsten bringt der Akkumulator schon viel für 
Rechenoperationen, beim x86 z.B. spielen AX und DX eine größere Rolle. 
Da muss man bei der Multiplikation oder Division den ersten Operanden 
ablegen und nach der Rechenoperation erhält man dort das Ergebnis. 
Andere Prozessoren verwenden die untersten Bytes des Arbeitsspeichers 
als Register-File (bspw. der 6502 mit seiner 256 Byte großen Zero Page, 
auf die der besonders schnell zugreifen kann), beim AVR bilden die 
ersten 32 Bytes ihres Speichers/Adressraumes den Registersatz, wobei das 
im Gegensatz zum x86 und 6502 eine Harvard-Architektur ist (getrennter 
Befehls- und Datenspeicher, wodurch auf beides gleichzeitig zugegriffen 
werden kann und daher kein Puffern von Daten im Prozessor erforderlich 
ist).

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.