Forum: Mikrocontroller und Digitale Elektronik AT91SAM7S256: ldr "expression out of range" - Problem


von Peter P. (uncle-sam7)


Lesenswert?

Hallo NG,

ich habe hier ein Problem, von dem ich nicht weiß, warum es da ist.

Für meinen Programmcounter des 6502 Emulators habe ich das Register R8 
vorgesehen, was auch super funktioniert. Jetzt habe angefangen, die 
restlichen Opcodes "einzubauen". Der Assembler (IAR) fängt nun plötzlich 
zum Meckern an, dass ein Label out of range wäre.

Das Komische daran: Wenn ich die Adresse des Labels "hart" übergebe 
funktioniert es. Dabei verliere ich allerdings den Komfort, dass sich 
diese Adresse nach einer Programmveräderung ändern kann.

Vielen Dank für jeden Hinweis und viele Grüße
Peter

----------------------
Im Quelltext:
----------------------
// program counter (pc)
  ldr r8, =0xc80 // FUNKTIONIERT
  // ldr r8, =memory // expression out of range

----------------------
Nach dem Assemblieren:
----------------------
...
__iar_program_start:
         0x80: 0xe3a08ec8     MOV       r8, #3200               ; 0xc80
...
memory:
        0xc80: 0x0a0a0a0a     DC32      168430090               ; '....'
        0xc84: 0x0a0a0a0a     DC32      168430090               ; '....'

von Lennart S. (lennart_s)


Lesenswert?

ich denke mal der IAR versucht beim...

ldr r8, =memory

nen 32bit wert in den Opcode einzubauen. wenn ich es aber richtig 
verstehe kann das der Arm nicht.

Schau mal hier rein (letzten 2 Seiten)...
http://www.informatik.uni-ulm.de/ni/Lehre/WS01/TI2/folien/ciscC.PDF


----EDIT:
hab nochmal geschaut ... versuch das doch mal mit dem GNU AS zu 
assemblieren ... in meinem startupcode mach ich das auch recht oft genau 
so und es funzelt wunderbar ... evtl macht der IAR da iwas anders

ne gute toolchain die gut funzelt ist die sog. YAGARTO
http://www.yagarto.de/

von Frank B. (foobar)


Lesenswert?

Ich kenne den ARM-Befehlssatz nicht so gut, aber hier:

http://simplemachines.it/doc/arm_inst.pdf

steht auf Seite 35, daß LDR alles laden kann. Wenn's nicht passt, dann 
wird es per Literal geladen. Zumindest sollte der Compiler es so 
umsetzen.

Aber warum schreibst du den C64-Emulator überhaupt in Assembler? Ich 
habe letztens mal einen IIR-Filter in C implementiert und der war mit 
-O2 und GCC compiliert problemlos noch halb so schnell, wie die 
handoptimierte Referenzimplementation aus einem ARM Handbuch, die 
mehrere Seiten brauchte und interessante Tricks mit zwei Werte in einem 
Register speichern usw. angewendet hat. Meine C-Implementierung war 5 
Zeilen oder so lang, denn die IIR-Implementierung ist trivial, wenn man 
erstmal die Koeffizienten hat.

von Peter P. (uncle-sam7)


Lesenswert?

Frank Buss schrieb:
> http://simplemachines.it/doc/arm_inst.pdf
> steht auf Seite 35, daß LDR alles laden kann. Wenn's nicht passt, dann
> wird es per Literal geladen. Zumindest sollte der Compiler es so
> umsetzen.

Wie gesagt, er machte es z.Zt. nur noch, wenn ich die Adresse "fest" 
reinschreibe.

> Aber warum schreibst du den C64-Emulator überhaupt in Assembler?

naja, das mit C hat ja bei mir schon mal ein SID-File abgespielt. Der 
negative Beigeschmack war allerdings, dass der Compiler für sich auch 
Dinge im SRAM des AT91SAM7 reserviert (Stack, Variablen etc.).

In der Assembler Version passiert in der Emulationsschicht überhaupt 
nichts im SRAM ausser Zugriffe auf den "64er"-Speicher. Mir gefällt der 
Weg so viel besser, da ich mir da um viele andere Dinge keine Gedanken 
machen muss...

@Lennart S.: hab http://www.yagarto.de/ bei mir installiert. Ein 
C-Projekt jabe ich damit schon mal gemacht. Wie muss denn ein 
Assemblerprojekt damit aussehen? Hast Du da ein Beispiel oder einen 
Link?

Viele Grüße,
Peter

von (prx) A. K. (prx)


Lesenswert?

Die Operation
 LDR rx, =symbol
legt üblicherweise das gewünschte Adresswort in den Speicher und erzeugt 
einen LDR-Befehl, der dieses Wort PC-relativ läd. Solche Konstanten 
werden in einem Konstanten-Pool gesammelt, der irgenwann raus muss. 
Rechtzeitig raus muss, bevor die PC-relative Distanz dazu grösser als 
4KB wird. Man muss also dem Assembler gelegentlich zu verstehen geben, 
dass nun im Code Platz dafür ist, denn von sich aus darf der das ja 
nicht irgendwo zwischen zwei Befehlen reinschieben.

von Peter (Gast)


Lesenswert?

A. K. schrieb:
> Man muss also dem Assembler gelegentlich zu verstehen geben,
> dass nun im Code Platz dafür ist, denn von sich aus darf der das ja
> nicht irgendwo zwischen zwei Befehlen reinschieben.

hmm, das verstehe ich nicht ganz, die 4K-Grenze könnte wirklich sein, 
aber wieso funktioniert das dann, wenn ich nicht den Labelnamen 
verwende, sondern die Adresse, die das Label nach dem Assemblieren haben 
wird?

ldr r8, =0xc80  // FUNKTIONIERT
ldr r8, =memory // funktioniert NICHT: expression out of range

Hast Du vielleich ein Schlagwort, wonach ich diesbezgl. in den 
Einstllungen sichen könnte?

Viele Grüße,
Peter

von (prx) A. K. (prx)


Lesenswert?

Peter schrieb:

> hmm, das verstehe ich nicht ganz, die 4K-Grenze könnte wirklich sein,
> aber wieso funktioniert das dann, wenn ich nicht den Labelnamen
> verwende, sondern die Adresse, die das Label nach dem Assemblieren haben
> wird?

Das liegt daran, dass "memory" für den Assembler eine verschiebliche 
Adresse ist, deren exakten Wert erst der Linker kennt, während 0xC80 ein 
bereits dem Assembler bekannter Wert ist. Für bekannte passende 
Konstanten erzeugt er MOV/MVN, andernfalls LDR PC-rel. Nur letzteres 
benötigt den literal pool.

Zum literal pool siehe Assembler-Statement LTORG. Darauf wird übrigens 
auch in der (m.E. hier ziemlich miesen) IAR Assembler Doku verwiesen.

von Peter P. (uncle-sam7)


Lesenswert?

Hallo nochmal,

also ich hab nichts mehr rausfinden können, wie man dem Assembler 
beibringt, nicht so kleinlich zu sein :-(

Naja, jetzt habe ich es - um weitermachen zu können - einfach über einen 
"Zeigerumweg" gelöst (siehe unten). Gefällt mir nicht, aber es geht.

Was mir noch aufgefallen ist: für "memory" benötige ich ja sowas eh 
nicht, da die Adresse dann ja sowieso innerhalb 0x200000 (SRAM) liegt. 
"Memory" war für mich nur ne Krücke, um die Opcodes testen zu können. 
Und den Opcodes-Pointer kann ich ja zu Beginn 1x setzen. Während des 
Betriebs wird dieses Register dann eh nicht mehr geändert.

@A.K.: wäre schön, wenn Du mir noch sagen könntest, ob es da nicht doch 
ne Lösung innerhalb der IAR gibt, damit die 4k keine Rolle spielen. Wäre 
rein Interessehalber...

PS.: Die Opcodes die mit "_" beginnen und noch keine Adressierungsart am 
Ende haben, muss ich noch umsetzen. Die anderen funktionieren schon.

PPS.: Hab übrigens noch richtig gute Testsuites für 6502-Emulator-Bauern 
gefunden: http://visual6502.org/wiki/index.php?title=6502TestPrograms 
(nur für die, die es interessiert).

PPPS.: Die Adressierungsarten / Clockcyclecount etc. habe ich nicht in 
eine getrennte Sprungtabelle gepackt. Somit spare ich mir auch wieder 
ein paar Takte...
1
...
2
3
pointer_memory:  
4
  DC32 memory
5
  
6
pointer_opcodes:  
7
  DC32 opcodes
8
9
// -------------------------------------------------------------------
10
// include headers
11
// -------------------------------------------------------------------
12
#include <at91sam7s256.h> 
13
14
// -------------------------------------------------------------------
15
// main entry point
16
// -------------------------------------------------------------------
17
__iar_program_start:
18
  
19
// -------------------------------------------------------------------
20
// definitions for 6502 cpu
21
// -------------------------------------------------------------------
22
// stack pointer (sp)
23
  ldr r7, =0xff
24
25
// program counter (pc)
26
  ldr r8, pointer_memory
27
28
...
29
30
// -------------------------------------------------------------------
31
// 6502 main loop
32
// -------------------------------------------------------------------
33
drive_cpu:
34
  ldrb r4, [r8], #1
35
  ldr r3, pointer_opcodes
36
  ldr pc, [r3, r4, lsl #2]
37
38
...
39
40
// -------------------------------------------------------------------
41
// c64 memory / this is where the sidfiles remaining
42
// -------------------------------------------------------------------
43
  ALIGNRAM 4
44
memory:  
45
  DC8 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a
46
47
// -------------------------------------------------------------------
48
// c64 opcodes 
49
// -------------------------------------------------------------------
50
// _imm = #$xx
51
// __zp = $xx
52
// _zpx = $xx,X
53
// _zpy = $xx,Y
54
// _izx = ($xx,X)
55
// _izy = ($xx),Y
56
// _abs = $xxxx
57
// _abx = $xxxx,X
58
// _aby = $xxxx,Y
59
// _ind = ($xxxx)
60
// _rel = $xxxx (pc-relative) 
61
// -------------------------------------------------------------------
62
  ALIGNRAM 4
63
  
64
// -------------------------------------------------------------------
65
opcodes: /*          00       01       02       03       04       05       06       07       08       09       0A       0B       0C       0D      0E       0F  */
66
// -------------------------------------------------------------------
67
  DC32 /*00*/ _BRK   , ORA_izx, _xxx   , _xxx   , _xxx   , ORA__zp, ASL__zp, _xxx   , _PHP   , ORA_imm, ASL_imp, _xxx   , _xxx   , ORA_abs, ASL_abs, _xxx
68
// -------------------------------------------------------------------
69
  DC32 /*01*/ _BPL   , ORA_izy, _xxx   , _xxx   , _xxx   , ORA_zpx, ASL_zpx, _xxx   , _CLC   , ORA_aby, _xxx   , _xxx   , _xxx   , ORA_abx, ASL_abx, _xxx
70
// -------------------------------------------------------------------
71
  DC32 /*02*/ _JSR   , AND_izx, _xxx   , _xxx   , _BIT   , AND__zp, _ROL   , _xxx   , _PLP   , AND_imm, _ROL   , _xxx   , _BIT   , AND_abs, _ROL   , _xxx
72
// -------------------------------------------------------------------
73
  DC32 /*03*/ _BMI   , AND_izy, _xxx   , _xxx   , _xxx   , AND_zpx, _ROL   , _xxx   , _SEC   , AND_aby, _xxx   , _xxx   , _xxx   , AND_abx, _ROL   , _xxx
74
// -------------------------------------------------------------------
75
  DC32 /*04*/ _RTI   , EOR_izx, _xxx   , _xxx   , _xxx   , EOR__zp, _LSR   , _xxx   , _PHA   , EOR_imm, _LSR   , _xxx   , JMP_abs, EOR_abs, _LSR   , _xxx
76
// -------------------------------------------------------------------
77
  DC32 /*05*/ _BVC   , EOR_izy, _xxx   , _xxx   , _xxx   , EOR_zpx, _LSR   , _xxx   , _CLI   , EOR_aby, _xxx   , _xxx   , _xxx   , EOR_abx, _LSR   , _xxx
78
// -------------------------------------------------------------------
79
  DC32 /*06*/ _RTS   , _ADC   , _xxx   , _xxx   , _xxx   , _ADC   , _ROR   , _xxx   , _PLA   , _ADC   , _ROR   , _xxx   , JMP_ind, _ADC   , _ROR   , _xxx
80
// -------------------------------------------------------------------
81
  DC32 /*07*/ _BVS   , _ADC   , _xxx   , _xxx   , _xxx   , _ADC   , _ROR   , _xxx   , _SEI   , _ADC   , _xxx   , _xxx   , _xxx   , _ADC   , _ROR   , _xxx
82
// -------------------------------------------------------------------
83
  DC32 /*08*/ _xxx   , STA_izx, _xxx   , _xxx   , STY__zp, STA__zp, STX__zp, _xxx   , DEY_imp, _xxx   , TXA_imp, _xxx   , STY_abs, STA_abs, STX_abs, _xxx
84
// -------------------------------------------------------------------
85
  DC32 /*09*/ _BCC   , STA_izy, _xxx   , _xxx   , STY_zpx, STA_zpx, STX_zpy, _xxx   , TYA_imp, STA_aby, TXS_imp, _xxx   , _xxx   , STA_abx, _xxx   , _xxx
86
// -------------------------------------------------------------------
87
  DC32 /*0A*/ LDY_imm, LDA_izx, LDX_imm, _xxx   , LDY__zp, LDA__zp, LDX__zp, _xxx   , TAY_imp, LDA_imm, TAX_imp, _xxx   , LDY_abs, LDA_abs, LDX_abs, _xxx
88
// -------------------------------------------------------------------
89
  DC32 /*0B*/ _BCS   , LDA_izy, _xxx   , _xxx   , LDY_zpx, LDA_zpx, LDX_zpy, _xxx   , _CLV   , LDA_aby, TSX_imp, _xxx   , LDY_abx, LDA_abx, LDX_aby, _xxx
90
// -------------------------------------------------------------------
91
  DC32 /*0C*/ CPY_imm, CMP_izx, _xxx   , _xxx   , CPY__zp, CMP__zp, DEC__zp, _xxx   , INY_imp, CMP_imm, DEX_imp, _xxx   , CPY_abs, CMP_abs, DEC_abs, _xxx
92
// -------------------------------------------------------------------
93
  DC32 /*0D*/ _BNE   , CMP_izy, _xxx   , _xxx   , _xxx   , CMP_zpx, DEC_zpx, _xxx   , _CLD   , CMP_aby, _xxx   , _xxx   , _xxx   , CMP_abx, DEC_abx, _xxx
94
// -------------------------------------------------------------------
95
  DC32 /*0E*/ CPX_imm, _SBC   , _xxx   , _xxx   , CPX__zp, _SBC   , INC__zp, _xxx   , INX_imp, _SBC   , NOP_imp, _xxx   , CPX_abs, _SBC   , INC_abs, _xxx
96
// -------------------------------------------------------------------
97
  DC32 /*0F*/ _BEQ   , _SBC   , _xxx   , _xxx   , _xxx   , _SBC   , INC_zpx, _xxx   , _SED   , _SBC   , _xxx   , _xxx   , _xxx   , _SBC   , INC_abx, _xxx
98
// -------------------------------------------------------------------

von (prx) A. K. (prx)


Lesenswert?

Peter Pippinger schrieb:

> @A.K.: wäre schön, wenn Du mir noch sagen könntest, ob es da nicht doch
> ne Lösung innerhalb der IAR gibt, damit die 4k keine Rolle spielen. Wäre
> rein Interessehalber...

Klar. Rechtzeitig mal ein LTORG einstreuen, damit der Assembler den 
literal pool los wird bevor die 4K rum sind. Wirst ja wohl irgendwo ein 
Plätzchen finden, bei dem die so erzeugten Daten dem Code nicht im Weg 
sind, beispielsweise hinter einem unbedingten Sprung oder Return.

von Peter P. (uncle-sam7)


Lesenswert?

Vielen Dank, A.K.!

das funktioniert. Habe jetzt bei einem Opcode (ca. in der Mitte des 
Codes) folgendes gemacht:
1
...
2
3
ORA_aby:
4
  mov r4, #4            // at least 4 clock-cycles
5
  mem_aby
6
  opc_ORA
7
  b drive_cpu
8
  LTORG 
9
10
...

Jetzt funktioniert auch das Assemblieren wieder auf die "alte" Art :-)

Danke nochmal und viele Grüße,
Peter

von Frank B. (foobar)


Lesenswert?

Peter Pippinger schrieb:
> naja, das mit C hat ja bei mir schon mal ein SID-File abgespielt. Der
> negative Beigeschmack war allerdings, dass der Compiler für sich auch
> Dinge im SRAM des AT91SAM7 reserviert (Stack, Variablen etc.).
>
> In der Assembler Version passiert in der Emulationsschicht überhaupt
> nichts im SRAM ausser Zugriffe auf den "64er"-Speicher. Mir gefällt der
> Weg so viel besser, da ich mir da um viele andere Dinge keine Gedanken
> machen muss...

Also streng genommen brauchst du mehr als 64k Speicher, um den C64 
perfekt nachzubilden, siehe die Dekodierungstabelle des PLAs:

http://www.c64-wiki.de/index.php/PLA_(C64-Chip)

Also die 64 kB RAM, die man tatsächlich komplett einblenden kann in den 
adressierbaren Bereich (natürlich bis auf die Adressen 0 und 1) und 
zusätzlich die IO-Bereiche von SID, VIC usw., die sich zwar größtenteils 
wiederholen, aber man darf auch nicht das 1k Nibble RAM des 
Farbspeichers vergessen.

Ich würde aber mal vermuten, daß es keine Musik gibt, die das alles 
ausnutzt. Habe gerade die HVSC durchsucht und gibt zwar einige 
SID-Dateien, die bis zu 62k groß sind, aber das sind meist nur 
langweilige Samples, kein richtiger Chip-Tune. Man könnte bestimmt mit 
32k fast alle (interessanten) SID-Files abspielen. Wäre also kein Grund 
für Assembler. Ich verstehe aber, wenn du in Assembler programmieren 
willst, weil das cool ist oder so :-)

von Peter P. (uncle-sam7)


Lesenswert?

Frank Buss schrieb:
> Wäre also kein Grund für Assembler.
> Ich verstehe aber, wenn du in Assembler programmieren
> willst, weil das cool ist oder so :-)

Hallo Frank,

"oder so" trifft es gut ;-)

nee, im Ernst: Ich finde es tatsächlich cool, mal wieder was in 
Assembler zu machen. Das mit dem Speicher ist mir bekannt. Aber ich 
denke für die SIDs ist es nicht von Bedeutung.

Bin ja auch schon am schauen, was ich dann als nächste Hardware 
verwenden kann, gerade weil mir das mit dem "knappen" Speicher nicht so 
gefällt. Was hältst Du von diesem Board hier:

http://shop.embedded-projects.net/index.php?module=artikel&action=artikel&id=499

Viele Grüße,
Peter

von Frank B. (foobar)


Lesenswert?

Sieht gut aus das Board. Müsste man mal probieren, ob das mit dem 
externen RAM nicht problematisch wird mit der Zugriffszeit, aber sollte 
gehen. Wenn du es kleiner haben willst, gibt es von Renesas noch nette 
Microcontroller, z.B. mit 1 MB integriertem RAM, ziemlich schnell und 
mit vielen anderen Features:

http://www.renesas.com/products/mpumcu/superh/sh7260/sh7262/sh7262_root.jsp

Damit könnte man vielleicht sogar Teile der Grafikausgabe für einen C64 
simulieren. Natürlich keine VIC-Spezialeffekte, da braucht man dann 
einen FPGA für, wie beim C-One:

http://de.wikipedia.org/wiki/C-One

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.