Forum: PC-Programmierung x86 Assembler auf einem nackten 8086 - wie Startadresse des ROMs setzen?


von Sascha (Gast)


Lesenswert?

Hallo!

Ich versuche mich gerade mit x86-Assembler auf einem 8086 (bare metal 
chip; kein PC mit BIOS, sondern der nackte 8086).

Ich habe an Adresse 0xC0000 - 0xFFFFF mein ROM (2 MBit/ 128k x 16).

Nun beginnt der 8086 nach einem Reset an Adresse 0xFFFF0 den Code 
ausführen.

Ich habe als erstes ein simples Programm geschrieben, welches einen Wert 
an I/O-Adresse 0 ausgibt (dort habe ich ein Latch mit 8 LEDs):

<code>
.intel_syntax
.code16
.globl _start
_start:
        cli
        movb %al, 0xaa
        mov %dx, 0x0
        outb %dx, %al
</code>

Wenn ich das jetzt übersetze mit
<code>
as -32 -o test.o test.s
ld -m elf_i386 --oformat binary test.o -o test.bin
</code>

dann kommt folgendes heraus:

<code>
hexdump test.bin
0000000 b0fa baaa 0000 f4ee
0000008
</code>

Wenn ich das jetzt manuell in der EPROM-Programmiersoftware an die 
Adresse 3FFF0 (da das EPROM bei C0000 beginnt ist die Adresse im System 
dann 0xFFFF0) kopiere und das EPROM brenne, dann funktioniert es wie 
gedacht und die CPU schreibt 0xaa an I/O-Adresse 0.



Nun habe ich am Reset-Vektor 0xFFFF0 nur noch 16 Bytes bis zum Ende des 
ROMs Platz. Daher würde ich gerne von da zum Anfang des ROM springen.


Wie bekomme ich meine Assembler-Datei hin, so dass das Ergebnis 
(Binärdatei) so groß wie das ROM wird (256kB), der Code bei 0xC0000 
beginnt und ich bei 0xFFFF0 einem jmp zu einem Label am Anfang meines 
Codes habe?

Ich habe folgendes probiert:

<code>
.intel_syntax
.code16
.org 0xc0000
.section .text
.globl _start
_start:
        cli
        movb %al, 0xaa
        mov %dx, 0x0
        outb %dx, %al
        hlt


.org 0xffff0
        jmp _start

.org 0xfffff
.byte 0
</code>

Dann wird aber das Object-File und das gelinkte Binary 1MiB groß...

von Sigi (Gast)


Lesenswert?

Ich bin alles andere als ein 8086-BIOS-Experte
(habe selbst einige FPGA-8086er-Systeme mit
vergleichbaren Problemen), in solchen Fällen
zerlege ich den Code in zwei Teilen:
1. den ab FFFF0, der idR 16 Bytes mit einer
   Sprunganweisung umfasst
2. den eigentliche Code
Daraus ergeben sich dann 2 BIN-Files. Die musst
Du dann an deinen EPROM-Brenner weiterreichen.

Und Btw: die 16 Bytes sind eiglich ja immer
gleich, evtl. bis auf die Zieladresse, die je
nach Wunsch manuell ohne Übersetzung angepasst
werden kann.

von Sebastian Hepp (Gast)


Lesenswert?

Das ist das Problem an den *.bin-Dateien. Diese repräsentieren den 
gesamten Speicher. Wenn das Program also bei 0xc0000 anfängt enthält die 
Datei auch Daten von Adresse 0 an. Das macht bis 0xFFFFF eben genau 
1MByte. So kannst du das auch nicht in den ROM schreiben, weil die Daten 
vor 0xc0000 müll sind.

Das Problem ist, dass man die org direktive nicht weglassen kann, sonst 
werden die Adressen vom Assembler falsch berechnet. Wenn du unbedingt 
ein Binärfile brauchst, dann könntest du als schlimmen Workaround 
einfach die ersten 0xc0000 Bytes der 1MByte Datei entfernen/abschneiden.

Du kannst auch 2 Quellcodes erzeugen, das ist richtig. Aber dazu musst 
du das ROM Byteweise bzw. in maximal 16 Byte Blöcken beschreiben können. 
Sonst überschreibst du Teile der jeweils anderen Datei.
Ein weiteres Problem ist, dass der Assembler nicht meckert, wenn dein 
Program ab Adresse 0xc0000 so groß wird, dass es in den Speicher ab 
0xf0000 reicht.

von Helmut L. (helmi1)


Lesenswert?

Sascha schrieb:
> Dann wird aber das Object-File und das gelinkte Binary 1MiB groß...

Dann mach da kein BIN File draus sondern ein Intel-HEX File. Da stehen 
dann die Ladeaddressen mit drin.

Wenn dein Programmer keine Offsetverschiebung bei Intel-HEX Files 
zulaesst must du dir dann noch eben ein kleines Hex-File 
Verschiebeprogramm schreiben.

Beispiel:

Du erzeugst das HEX-File direkt aus deinem Code:

Dann wird da drin stehen:

:020C0000.....  Die Addresse ist dann C00000   (zu Hoch fuer das EPROM)

Dann must du in deinem Programmer einen Offset angeben der von dieser 
Ladeaddresse abgezogen wird damit es ins EPROM passt.

Kann dein Programmer das nicht dann must du dir ein Programmchen 
schreiben das die HEX Zeile einliest und das Addressfeld umrechnet. Also 
im Beispiel muesste dann C0000H abgezogen werden. An deinem eigentlichen 
Code aendert das nichts, lediglich die Ladeaddresse wird geaendert.

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Sebastian Hepp schrieb:
> Das ist das Problem an den *.bin-Dateien. Diese repräsentieren den
> gesamten Speicher.

Einfache Lösung: Von der Bin-Datei den nicht benötigten Teil abschneiden 
und nur den Rest weiterverarbeiten.

von Pandur S. (jetztnicht)


Lesenswert?

Ich bin 8086 Experte. Das Segment Register muss auch noch betrachtet 
werde. Ueblicherweise ist ja die Interrupt Tabelle auf Null, und man 
springt an den Begin des Bios, zB auf F000:0000 = F0000. Also entweder 
steht das CSEG schon auf F000, oder man muss es so setzen.

Du hast das Instruction manual ?
Am Anfang des BIOS, oder wie auch immer man diesen Code nennt, muss man 
erst mal alle Segment Regiter setzen.

: Bearbeitet durch User
von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Oh D. schrieb:
> Ueblicherweise ist ja die Interrupt Tabelle auf Null, und man springt
> an den Begin des Bios, zB auf F000:0000 = F0000. Also entweder steht das
> CSEG schon auf F000, oder man muss es so setzen.

Es geht um den Resetvektor. Für den muss kein Segmentregister gesetzt 
werden.

von Winfried J. (Firma: Nisch-Aufzüge) (winne) Benutzerseite


Lesenswert?

das wär auch plöd ;)

Namaste

von Sascha (Gast)


Lesenswert?

Danke für die vielen Tips!

Ich habe inzwischen einen passenden Blog-Artikel gefunden:
http://pete.akeo.ie/2011/06/crafting-bios-from-scratch.html

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.