Zugriffoptimierung eterner Ram
Zugriffoptimierung eterner Ram
Die Ablage (write) und das lesen (read) der Daten aus dem externen Ram erfolgt im allgemeinen sequentiell.
Ich bin der Ansicht, das dies in der gegebenen Konfiguration nicht optimal ist.
Der bisherige Ablauf erfolgt folgendermaßen:
Ausgabe High-Adresse und Zwischenpeicherung auf latch (a11-a18), ausgabe low-Adresse
(a0-a10), dann CS und rd/wr und oe.
Dies wird für jedes byte gemacht.
Wäre es nicht besser, die Adresse auszugeben und dann über cs/oe (port 19/20) den entsprechenden Baustein zu aktivieren? Cs/oe ist der Wert der Adressleitung 0. Es entspräche sozusagen einem Raid-O.
Vorteil: mit einer Adressoperation und nur durch Veränderung von oe und cs sind zwei Speicherzellen Les/Schreibbar, die Schreib/Lese-Geschwindigkeit erhöht sich, weil eine zweite Ausgabe der Adressen entfällt.
Nachteil: wir bei Raid0 sind die Daten über zwei Speichermedien verteilt.
Liege ich richtig?
Ich bin der Ansicht, das dies in der gegebenen Konfiguration nicht optimal ist.
Der bisherige Ablauf erfolgt folgendermaßen:
Ausgabe High-Adresse und Zwischenpeicherung auf latch (a11-a18), ausgabe low-Adresse
(a0-a10), dann CS und rd/wr und oe.
Dies wird für jedes byte gemacht.
Wäre es nicht besser, die Adresse auszugeben und dann über cs/oe (port 19/20) den entsprechenden Baustein zu aktivieren? Cs/oe ist der Wert der Adressleitung 0. Es entspräche sozusagen einem Raid-O.
Vorteil: mit einer Adressoperation und nur durch Veränderung von oe und cs sind zwei Speicherzellen Les/Schreibbar, die Schreib/Lese-Geschwindigkeit erhöht sich, weil eine zweite Ausgabe der Adressen entfällt.
Nachteil: wir bei Raid0 sind die Daten über zwei Speichermedien verteilt.
Liege ich richtig?
Re: Zugriffoptimierung eterner Ram
Das war ja die Idee von mir bezüglich simuliertem "Burst-Mode" in einem anderen Thread.
Ich habe nur noch keine Ahnung ob das funktioniert. Wäre cool, wenn Du da was rausfinden könntest.
Gruß.
Rainer
Ich habe nur noch keine Ahnung ob das funktioniert. Wäre cool, wenn Du da was rausfinden könntest.
Gruß.
Rainer
"Wer andauernd begreift, was er tut, bleibt unter seinem Niveau."
Re: Zugriffoptimierung eterner Ram
Hm, die extrene RAM geschwindigkeit müsste ungefähr wie folgt aussehen.
Soweit ich das verfolgen konnte kann der Propeller die IO's bei maximaler COG nutzung mit maximal 80MHz abfragen/ schalten. Diese Info habe ich aus einem Logiganalyser Projekt entnommen in dem ein Propeller mit maximal 80Mhz seine IO-Ports ausliesst um Logigpegel mitzuloggen und zu verarbeiten. Ich gehe daher davon aus, das der Propeller schnell genug ist um das RAM mit der vom RAM her vorgegebenen maximalen geschwindigkeit nutzen zu können.
Das verbaute Ram ist ein 55ns Typ, der maximal mit 18,1 MHz abgefragt werden kann. Alle 2048 Byte muss man das Latch nutzen um die oberen Addressleitungen neu zu setzen. Mit 5 Volt söllte sich für das Latch nach Datenblatt eine geschwindigkeit zwischen 16ns (typisch) und 28,7ns(maximal) im "propagation delay" ergeben.
Wenn man die RAM's im wechsel Betreiben möchte, sollte man wohl folgende Schritte einhalten.
0. RAM 1 Datenausgabe an / RAM 2 datenausgabe aus
1. Neue Adresse anlegen.
2. 55 ns warten, die das 1. RAM bis zur Datenausgabe braucht
3. Das erste Byte am Bus abholen
4. RAM 1 Datenausgabe aus
5. 22 ns warten die das 1. RAM zum abschalten braucht.
6. RAM 1 Datenausgabe an
7. 25 ns warten, die das 2. RAM braucht um die Ausgänge hochzufahren
8. Das zweite Byte am BUS abholen
9. RAM 2 Datenausgabe aus
10. 22 ns warten die das 1. RAM zum abschalten braucht.
11. Ram 1 Datenausgabe einschalten
12. bei 1. weitermachen
Hieraus ergibt sicht folgendes Bild:
Würde man nur ein RAM nehmen, braucht man ca. 110ns für das lesen von 2 Bytes. Nimmt man wie oben beschrieben beide RAM's im wechsel, werden für das lesen von 2 Bytes insgesammt 124ns benötigt, was im ganzen sogar langsamer wäre als nur 1 RAM zu nehmen.
Wenn die 2KB Adressgrenze auf dem Adressbuss überschritten wird und man das Latch neu beschreiben muss kommen in beiden fällen nochmal ca. 16-20 ns umschaltzeit hinzu. Wenn man beide RAM's im wechsel betreibt halbieren sich die zusätzlich hierfür benötigten Umschaltzeiten, da man ja erst nach 4KB und nicht schon nach 2KB umschalten muss.
Nicht berücksichtigt habe ich hier die internen Abläufe im Propeller, also wie lange es z.B. dauert die Ausgaben auf die Adressleitungen zu legen und wie lange er braucht um die Bytes vom Buss abzuholen.
Grüße
Janaha
Soweit ich das verfolgen konnte kann der Propeller die IO's bei maximaler COG nutzung mit maximal 80MHz abfragen/ schalten. Diese Info habe ich aus einem Logiganalyser Projekt entnommen in dem ein Propeller mit maximal 80Mhz seine IO-Ports ausliesst um Logigpegel mitzuloggen und zu verarbeiten. Ich gehe daher davon aus, das der Propeller schnell genug ist um das RAM mit der vom RAM her vorgegebenen maximalen geschwindigkeit nutzen zu können.
Das verbaute Ram ist ein 55ns Typ, der maximal mit 18,1 MHz abgefragt werden kann. Alle 2048 Byte muss man das Latch nutzen um die oberen Addressleitungen neu zu setzen. Mit 5 Volt söllte sich für das Latch nach Datenblatt eine geschwindigkeit zwischen 16ns (typisch) und 28,7ns(maximal) im "propagation delay" ergeben.
Wenn man die RAM's im wechsel Betreiben möchte, sollte man wohl folgende Schritte einhalten.
0. RAM 1 Datenausgabe an / RAM 2 datenausgabe aus
1. Neue Adresse anlegen.
2. 55 ns warten, die das 1. RAM bis zur Datenausgabe braucht
3. Das erste Byte am Bus abholen
4. RAM 1 Datenausgabe aus
5. 22 ns warten die das 1. RAM zum abschalten braucht.
6. RAM 1 Datenausgabe an
7. 25 ns warten, die das 2. RAM braucht um die Ausgänge hochzufahren
8. Das zweite Byte am BUS abholen
9. RAM 2 Datenausgabe aus
10. 22 ns warten die das 1. RAM zum abschalten braucht.
11. Ram 1 Datenausgabe einschalten
12. bei 1. weitermachen
Hieraus ergibt sicht folgendes Bild:
Würde man nur ein RAM nehmen, braucht man ca. 110ns für das lesen von 2 Bytes. Nimmt man wie oben beschrieben beide RAM's im wechsel, werden für das lesen von 2 Bytes insgesammt 124ns benötigt, was im ganzen sogar langsamer wäre als nur 1 RAM zu nehmen.
Wenn die 2KB Adressgrenze auf dem Adressbuss überschritten wird und man das Latch neu beschreiben muss kommen in beiden fällen nochmal ca. 16-20 ns umschaltzeit hinzu. Wenn man beide RAM's im wechsel betreibt halbieren sich die zusätzlich hierfür benötigten Umschaltzeiten, da man ja erst nach 4KB und nicht schon nach 2KB umschalten muss.
Nicht berücksichtigt habe ich hier die internen Abläufe im Propeller, also wie lange es z.B. dauert die Ausgaben auf die Adressleitungen zu legen und wie lange er braucht um die Bytes vom Buss abzuholen.
Grüße
Janaha
Re: Zugriffoptimierung eterner Ram
Leider habe ich in den Unterlagen zum Propeller keine aussagekräftigen Taktdiagramme gefunden. Ich empfinde die Chipbeschreibung als dürftig, oder ich habe die richtigen noch nicht gefunden. Es sind also mehr Vermutungen, die ich hier anstelle.
Aus den Assemblerdirektiven geht hervor, daß die durchschnittliche Abarbeitung eines Befehls 4 Takte verbraucht. Wenn ich also einen Cog mit 80 MHz takte, kann ich an den Ports maximal 20 MHz herausholen. Dies entspricht einer Zeit von 50 ns.
Eine höhere Auflösung ist durch die Verwendung mehrere Cogs möglich, aber auch nur dadurch, das die Cogs zum IO_Pin eine daisy-chain bilden. Ein am Pin anliegendes Signal benötigt zum durchschalten vom 0ten bis 7ten Cog 1,7 ns.
Völlig unklar ist mir, ob man Cogs taktversetzt ansteuern kann. Ich meine das so, das cog 0 bei Takt0, cog1 bei Takt1, cog2 bei takt2 und cog3 bei Takt3 mit seine Arbeit beginnen kann. Dann wären 80 MHz am io-pin möglich.
Aber zurück zum Thema.
Das lesen/schreiben läuft fogendermaßen:
1. Ausgabe highteil
2. Ausgabe lowteil
3. Ausgabe cs/oe Ram1
4. in/out Operation byte 1
5. ausgabe highteil
6. ausgabe lowteil+1
7. ausgabe cs/oe Ram1
8. in/out byte 2
9. weiter wieder mit 1
erste Alternative (burstmode)
1. Ausgabe highteil
2. Ausgabe lowteil
3. Ausgabe cs/oe Ram1
4. in/out Operation byte 1
5. ausgabe lowteil+1
6. ausgabe cs/oe Ram1
7. in/out byte 2
8. Ausgabe lowteil+1 weiter mit 3
zweite Alternativ (burstmode, quasi16bit)
1. Ausgabe highteil
2. Ausgabe lowteil
3. Ausgabe cs/oe Ram1
4. in/out Operation byte 1
5. ausgabe cs/oe Ram2 <-----
6. in/out byte 2
7. Ausgabe lowteil+1 weiter mit 3
Natürlich ist das nicht vollständig, nur ein Gedanke.
Aus den Assemblerdirektiven geht hervor, daß die durchschnittliche Abarbeitung eines Befehls 4 Takte verbraucht. Wenn ich also einen Cog mit 80 MHz takte, kann ich an den Ports maximal 20 MHz herausholen. Dies entspricht einer Zeit von 50 ns.
Eine höhere Auflösung ist durch die Verwendung mehrere Cogs möglich, aber auch nur dadurch, das die Cogs zum IO_Pin eine daisy-chain bilden. Ein am Pin anliegendes Signal benötigt zum durchschalten vom 0ten bis 7ten Cog 1,7 ns.
Völlig unklar ist mir, ob man Cogs taktversetzt ansteuern kann. Ich meine das so, das cog 0 bei Takt0, cog1 bei Takt1, cog2 bei takt2 und cog3 bei Takt3 mit seine Arbeit beginnen kann. Dann wären 80 MHz am io-pin möglich.
Aber zurück zum Thema.
Das lesen/schreiben läuft fogendermaßen:
1. Ausgabe highteil
2. Ausgabe lowteil
3. Ausgabe cs/oe Ram1
4. in/out Operation byte 1
5. ausgabe highteil
6. ausgabe lowteil+1
7. ausgabe cs/oe Ram1
8. in/out byte 2
9. weiter wieder mit 1
erste Alternative (burstmode)
1. Ausgabe highteil
2. Ausgabe lowteil
3. Ausgabe cs/oe Ram1
4. in/out Operation byte 1
5. ausgabe lowteil+1
6. ausgabe cs/oe Ram1
7. in/out byte 2
8. Ausgabe lowteil+1 weiter mit 3
zweite Alternativ (burstmode, quasi16bit)
1. Ausgabe highteil
2. Ausgabe lowteil
3. Ausgabe cs/oe Ram1
4. in/out Operation byte 1
5. ausgabe cs/oe Ram2 <-----
6. in/out byte 2
7. Ausgabe lowteil+1 weiter mit 3
Natürlich ist das nicht vollständig, nur ein Gedanke.
Re: Zugriffoptimierung eterner Ram
Nun, vielleicht hilft das weiter (zumindestens was die Machbarkeit betrifft)
http://mikronauts.com/products/morpheus/
Der Benutzt auch SRAM's. Ich habe es mir aber noch nicht im Detail angesehen .. vll. hat der da irgendwelche "Superchips" drin.
Auf seiner Seite schreibt er:
***************************
working burst read speed: 20MB/sec at 80MHz (requires 3 cogs)
working burst write speed: 20MB/sec at 80MHz (requires 3 cogs)
can switch “pages” in as little as three instructions
selecting a different address within a page takes one instruction
easy to use 10MB/sec mode with random access within a 256 byte page
***************************
Gruß.
Rainer
http://mikronauts.com/products/morpheus/
Der Benutzt auch SRAM's. Ich habe es mir aber noch nicht im Detail angesehen .. vll. hat der da irgendwelche "Superchips" drin.
Auf seiner Seite schreibt er:
***************************
working burst read speed: 20MB/sec at 80MHz (requires 3 cogs)
working burst write speed: 20MB/sec at 80MHz (requires 3 cogs)
can switch “pages” in as little as three instructions
selecting a different address within a page takes one instruction
easy to use 10MB/sec mode with random access within a 256 byte page
***************************
Gruß.
Rainer
"Wer andauernd begreift, was er tut, bleibt unter seinem Niveau."
Re: Zugriffoptimierung eterner Ram
Also von Haus ist das nicht möglich. Alle Cogs laufen erst einmal syncron los. Wenn man sich die Assemblerbefehle anschaut kann man über die WAIT Befehle die Cogs asyncron laufen lassen. (WAITCNT braucht mindestens 5 Takte) Das funktioniert nur bis zu einem Zugrif auf den HUB dann wären sie wieder syncron. Ausserdem wäre das ziemlich aufwendig zu programmieren (OK, grundsätzlich kein Problem sondern eine Herausforderung ).Völlig unklar ist mir, ob man Cogs taktversetzt ansteuern kann.
Wenn man mehrere COGs verwendet hat mann natürlich noch das Nadelöhr HUBRam zu überwinden. Dort dauert der zugriff im schlimmsten Fall ja 275 nS. Ansonsten stimme ich Janaha zu. Diese Zeiten hatte ich mir auch ausgerechnet.
Wenn mann 110ns für das lesen von 2 Bytes vorausetzt könnte man 4 Bytes lesen bevor man dann ein Long ins HUBRam schreibt. Das wären dann ca. 14,5 MByte pro Sekunde ins HubRam.
Finde ich persönlich (ersteinmal ) schnell genug
Wenn ich meinen Hive habe werd ich mal meinen Logikanalyser ranhängen und schauen was maximal möglich ist.
Re: Zugriffoptimierung eterner Ram
Nicht das ich das Rad zum 2 mal erfinde habt Ihr da schon was optimiertes in PASM?
Wenn nicht auch egal nur dann müste ich nicht lange nach passenden waitstates suchen.
Grüsse Joshy
Wenn nicht auch egal nur dann müste ich nicht lange nach passenden waitstates suchen.
Grüsse Joshy
Re: Zugriffoptimierung eterner Ram
Nein, noch nicht.
Der Grund: das schreiben, lesen, verify ist wohl nicht so schwierig, aber ich wollte die Fehlerausgabe seriell machen.
Ich verstehe den Prozessor in seiner arbeitsweise noch nicht.
Die Syntax weicht stark von den mir bisher bekannten Typen ab.
Insbesondere habe ich noch Probleme bei der Ergebnisübergabe zwischen den cog's.
Außerdem habe ich das Problem, oder einfach gesagt die fehlende Kenntnis, zu den einzelnen Registern, Zuordnungen im globalen Ram. Im Moment beschäftige ich mich mit dem cnt. Die Register sind zwar 32 bit breit, es muß aber einen Überlauf im cnt geben, den man abfangen muß. Beim Überlauf wird anscheinend kein auswertbares flag gesetzt.
Das cnt habe ich verwendet, um eine Zeitbasis zu schaffen. Ich habe cnt gelesen und eine Verzögerung addiert. Dann mit waitcnt auf das Ereignis gewartet. Irgendwann gab es dann einen Überlauf (2^32+1) und das Ereignis trat niemehr auf.
Momentan muß ich mich erstmal in die CPU tiefer einarbeiten.
Nach dem was ich bisher gelesen habe, wird der i/o-Takt bei 8 bis 10 MHz ankommen, also nur unbedeutend schneller als bei den AVR-Teilen. Vorteil ist einfach die Möglichkeit der parallelen Abarbeitung.
Der Grund: das schreiben, lesen, verify ist wohl nicht so schwierig, aber ich wollte die Fehlerausgabe seriell machen.
Ich verstehe den Prozessor in seiner arbeitsweise noch nicht.
Die Syntax weicht stark von den mir bisher bekannten Typen ab.
Insbesondere habe ich noch Probleme bei der Ergebnisübergabe zwischen den cog's.
Außerdem habe ich das Problem, oder einfach gesagt die fehlende Kenntnis, zu den einzelnen Registern, Zuordnungen im globalen Ram. Im Moment beschäftige ich mich mit dem cnt. Die Register sind zwar 32 bit breit, es muß aber einen Überlauf im cnt geben, den man abfangen muß. Beim Überlauf wird anscheinend kein auswertbares flag gesetzt.
Das cnt habe ich verwendet, um eine Zeitbasis zu schaffen. Ich habe cnt gelesen und eine Verzögerung addiert. Dann mit waitcnt auf das Ereignis gewartet. Irgendwann gab es dann einen Überlauf (2^32+1) und das Ereignis trat niemehr auf.
Momentan muß ich mich erstmal in die CPU tiefer einarbeiten.
Nach dem was ich bisher gelesen habe, wird der i/o-Takt bei 8 bis 10 MHz ankommen, also nur unbedeutend schneller als bei den AVR-Teilen. Vorteil ist einfach die Möglichkeit der parallelen Abarbeitung.
Re: Zugriffoptimierung eterner Ram
Ich hab das in assembler gestestet bei einer 1:1 Umsetzung des aktuellen Protokols
es ist gerade ca. 3 mal schneller als der gleiche Spin Code.
In pasm kann man z.B. nicht einfach ' latch = 0
schreiben dafür muss man erst mal die Pin Maske bilden und die Flags benutzen
Das langsamste ist aber die Parameterübergabe von Spin zu pasm
Das lesen der Parameter aus dem Hub Ram ist dann auch noch nötig
Also auf Bytebasis lohnt sich das nicht weil für jedes einzelne Byte /wr, Portrichtung der 8 Datenleitungen, Latch, /RAM 1 o. 2 getoggelt werden muss.
Es ist auch nicht mit dem shiften der Lo und Hi Addresse getan sie muss auch mit $00FF00 und $01FF00 geANDed werden.
PASM lohnt sich nur wenn man grössere Blöcke Schreiben,Lesen,Kopieren oder Verschieben möchte.
Dann kann man etwas ausserhalb der Schleife erledigen und ist so ca 15 mal schneller als Spin.
Ist aber schon enttäuschend so den Faktor 20-25 für WriteByte hatte ich schon erwartet.
Meine ersten Resultate was das Tempo betrifft können sich aber noch positiv ändern wenn ich die PASM Tricks verinnerlicht habe.
Grüsse Joshy
es ist gerade ca. 3 mal schneller als der gleiche Spin Code.
In pasm kann man z.B. nicht einfach
Code: Alles auswählen
mov outa[23],1 ' latch = 1
mov outa[23],0
schreiben dafür muss man erst mal die Pin Maske bilden und die Flags benutzen
Code: Alles auswählen
mov t,#1 wz
shl t,latchshift ' enthält 23
muxnz outa, t ' latch = 1
muxz outa, t ' latch = 0
Code: Alles auswählen
PUB ram_write(wert,addresse): okay
pValue := wert
pAddress := addresse
okay := cognew(@asm_mem_write, @pValue) + 1
Code: Alles auswählen
mov p,par ' ptr of params
rdbyte v,p ' get value
add p,#1
rdlong al,p ' get address lo
mov ah,al ' make copy for adress hi
shr ah,#3
and ah,#ahm ' $00FF00
or ah,v ' adresse hi or value
Es ist auch nicht mit dem shiften der Lo und Hi Addresse getan sie muss auch mit $00FF00 und $01FF00 geANDed werden.
PASM lohnt sich nur wenn man grössere Blöcke Schreiben,Lesen,Kopieren oder Verschieben möchte.
Dann kann man etwas ausserhalb der Schleife erledigen und ist so ca 15 mal schneller als Spin.
Ist aber schon enttäuschend so den Faktor 20-25 für WriteByte hatte ich schon erwartet.
Meine ersten Resultate was das Tempo betrifft können sich aber noch positiv ändern wenn ich die PASM Tricks verinnerlicht habe.
Grüsse Joshy
Re: Zugriffoptimierung eterner Ram
Hier der Arbeitsstand Ram lesen schreiben, im Moment beschäftigt mich noch die Adressierung und das Multiplexen der Adressen. Die Signalpegel stimmen auch noch nicht.
{{test ram schreiben lesen}}
CON
_clkmode = xtal1 + pll16x
_xinfreq = 5_000_000
VAR
long Cog, TestVar
OBJ
dbg : "PASDebug" '<---- Add for Debugger
PUB main
Cog := cognew(@entry, @TestVar) + 1
dbg.start(31,30,@entry) '<---- Add for Debugger
PUB stop
if Cog
cogstop(Cog~ - 1)
DAT
org 0
entry
' --------- Debugger Kernel add this at Entry (Addr 0) ---------
long $34FC1202,$6CE81201,$83C120B,$8BC0E0A,$E87C0E03,$8BC0E0A
long $EC7C0E05,$A0BC1207,$5C7C0003,$5C7C0003,$7FFC,$7FF8
' --------------------------------------------------------------
init
mov dira, adressport
mov adresse,#0
mov outa, adresse
xor outa,cs
xor outa,cs
:l1
mov highadress,adresse
shr highadress,#8
mov lowadress,adresse
and lowadress,lowmaske
'xor lowadress,lowmaske
mov outa,highadress
or outa,cs
xor outa,cs
shl lowadress, #8
mov outa,lowadress
and outa,cs0
xor outa,cs0
add adresse,#1
cmp adresse,ramende wz
if_e jmp #:l2 ' ein Ram fertig
add zahl,#1 'Test anzahl Zugriffe
jmp #:l1
:l2
nop
nop
adressport long %00000100100111111111111100000000
ramende long $40000 'max Ram 3ffff
adresse long $0
highadress long 0 'Ramadresse auseinandernehmen wegen Adressmultiplex
lowadress long 0
maske long %00000000000111111111111100000000
lowmaske long %00000000000000000000011111111111
cs long %00000000100000000000000000000000
cs0 long %00000000000010000000000000000000
cs1 long %00000000000100000000000000000000
zahl long %0
we long %00000100000000000000000000000000
fit
{{test ram schreiben lesen}}
CON
_clkmode = xtal1 + pll16x
_xinfreq = 5_000_000
VAR
long Cog, TestVar
OBJ
dbg : "PASDebug" '<---- Add for Debugger
PUB main
Cog := cognew(@entry, @TestVar) + 1
dbg.start(31,30,@entry) '<---- Add for Debugger
PUB stop
if Cog
cogstop(Cog~ - 1)
DAT
org 0
entry
' --------- Debugger Kernel add this at Entry (Addr 0) ---------
long $34FC1202,$6CE81201,$83C120B,$8BC0E0A,$E87C0E03,$8BC0E0A
long $EC7C0E05,$A0BC1207,$5C7C0003,$5C7C0003,$7FFC,$7FF8
' --------------------------------------------------------------
init
mov dira, adressport
mov adresse,#0
mov outa, adresse
xor outa,cs
xor outa,cs
:l1
mov highadress,adresse
shr highadress,#8
mov lowadress,adresse
and lowadress,lowmaske
'xor lowadress,lowmaske
mov outa,highadress
or outa,cs
xor outa,cs
shl lowadress, #8
mov outa,lowadress
and outa,cs0
xor outa,cs0
add adresse,#1
cmp adresse,ramende wz
if_e jmp #:l2 ' ein Ram fertig
add zahl,#1 'Test anzahl Zugriffe
jmp #:l1
:l2
nop
nop
adressport long %00000100100111111111111100000000
ramende long $40000 'max Ram 3ffff
adresse long $0
highadress long 0 'Ramadresse auseinandernehmen wegen Adressmultiplex
lowadress long 0
maske long %00000000000111111111111100000000
lowmaske long %00000000000000000000011111111111
cs long %00000000100000000000000000000000
cs0 long %00000000000010000000000000000000
cs1 long %00000000000100000000000000000000
zahl long %0
we long %00000100000000000000000000000000
fit