Tja, dann würde ich sagen, fehlt es nur noch an denen, die sich damit auskennen und was eintragen.
Bitte, keine schlafenden Doppelpunkte wecken!
Es gibt 719 Antworten in diesem Thema, welches 94.538 mal aufgerufen wurde. Der letzte Beitrag (
Tja, dann würde ich sagen, fehlt es nur noch an denen, die sich damit auskennen und was eintragen.
Bitte, keine schlafenden Doppelpunkte wecken!
Hier geht es aber um die Nutzung unter Assembler.
Eigentlich geht es hier um den Assemblerkurs von markusk2020 .
Hier geht es aber um die Nutzung unter Assembler.
Eigentlich geht es hier um den Assemblerkurs von markusk2020 .
Ich denke, dass sich 64erGrufti hier als sehr hilfreich und positiv motiviert erwiesen hat.
Bitte, keine schlafenden Doppelpunkte wecken!
Du meinst, damit es kein Semilokon wird?![]()
Eigentlich geht es hier um den Assemblerkurs von markusk2020 .
Ja, aber auch in dem fängt jetzt die Nutzung der Kernel-Funktionen an. Das ist ja auch OK und gehört dazu. Nur wenn man sowas noch nie gemacht hat, kommt man mit den Funktionen ohne Beschreibung einfach nicht klar. Und ich denke, so als Referenz ist sowas immer gut.
OK, ich verstehe schon, dass die Basic-Funktionen nicht immer so uneingeschränkt unter Assembler nutzbar sind, da sie dafür nicht gemacht sind. Aber es werden immer wieder welche verwendet. Es wäre doch ne tolle Sache, wenn man dafür eine Referenz hätte. Nicht zuletzt wären beide Referenzen doch auch etwas für den Anhang zur Komplettierung des Kurses von markusk2020
Hallo!
So, habe nun auch den Abschnitt über das Löschen und Setzen von Bits fertig.
Auch hier habe ich wieder den BASIC- und Assembler-Code gegenübergestellt.
Nun brauch ich mal eine Pause, um mir zu überlegen, was ich im nächsten Kapitel bringe. In der Zwischenzeit freue ich mich wie immer über euer Feedback zum aktuellen Stand!
lg, Markus
Hallo Markus,
in der Erklärung zu BCS sollte stehen, dass bei Differenz X-Wert größer/GLEICH Null das Carry gesetzt wird.
Also
LDX Bitte melde dich an, um diesen Link zu sehen.
CPX Bitte melde dich an, um diesen Link zu sehen.
setzt ebenso das Carry wie
CPX Bitte melde dich an, um diesen Link zu sehen..
Grüße und weiter so ![]()
Jörg
in der Erklärung zu BCS sollte stehen, dass bei Differenz X-Wert größer/GLEICH Null das Carry gesetzt wird.
Vor Jahren schrub jemand im Forum (EDIT: es war atomcode )
BCC -> Branch if ClitzeClein
BCS -> Branch if Crößer oder dasSelbe
...je dümmer die Eselsbrücke, desto besser kann man sie sich merken! ![]()
Alles anzeigenHallo!
So, habe nun auch den Abschnitt über das Löschen und Setzen von Bits fertig.
Auch hier habe ich wieder den BASIC- und Assembler-Code gegenübergestellt.
Nun brauch ich mal eine Pause, um mir zu überlegen, was ich im nächsten Kapitel bringe. In der Zwischenzeit freue ich mich wie immer über euer Feedback zum aktuellen Stand!
lg, Markus
Hallo Markus,
in der Erklärung zu BCS sollte stehen, dass bei Differenz X-Wert größer/GLEICH Null das Carry gesetzt wird.
Also
LDX Bitte melde dich an, um diesen Link zu sehen.
CPX Bitte melde dich an, um diesen Link zu sehen.
setzt ebenso das Carry wie
CPX Bitte melde dich an, um diesen Link zu sehen..
Grüße und weiter so
Jörg
Hallo!
Ok danke, schau ich mir an ![]()
Leute, ich sag euch, es zahlt sich wirklich aus, Assembler zu lernen. Ich stelle gerade das Kapitel über die Sprites fertig und da hab ich natürlich auch Beispielprogramme, in denen die Sprites bewegt werden. Hab zuerst die BASIC-Variante erstellt und dann zum Vergleich in Assembler umgesetzt. Da liegen Universen dazwischen! In BASIC kann man dem C64 richtig gut beim Arbeiten zuschauen, in Assembler musste ich zwischen den Bewegungsschritten Warteschleifen einbauen, damit man überhaupt erkennt, dass da eine Bewegung vom linken zum rechten Bildschirmrand stattgefunden hat.
Bin auch selbst erstaunt darüber, wie sich die Dinge gewendet haben. Wenn mir vor ein paar Monaten jemand gesagt hätte, dass ich mal so einen Assembler-Kurs für den C64 erstelle, dann hätte ich das nicht geglaubt. Irgendwie geht damit auch ein Traum aus Jugendtagen in Erinnerung. Damals wollte ich auch hinter das Geheimnis der Maschinensprache kommen, aber es ist nie was daraus geworden, weil mir einfach der richtige Zugang gefehlt hat. Ich hab immer nur ein Meer aus POKE, PEEK und DATA gesehen. Es hat sich mir nie richtig erschlossen, was diese Zahlen bedeuten und warum es genau diese Zahlen sind und nicht etwa andere.
Umso mehr freue ich mich, dass sich das nun geändert hat und dass ich das auch weitergeben kann ![]()
lg, Markus
Irgendwie geht damit auch ein Traum aus Jugendtagen in Erinnerung. Damals wollte ich auch hinter das Geheimnis der Maschinensprache kommen, aber es ist nie was daraus geworden, weil mir einfach der richtige Zugang gefehlt hat
Exakt wie bei mir. Ich hatte zwar etwas angefangen damals, aber so wirkliche Projekte waren das nicht.
Hallo!
Hab das Kapitel über Sprites aktualisiert, eine Kleinigkeit fehlt noch, und zwar ein Beispiel, in dem das Register 53264 ins Spiel kommt (X-Koordinate > 255), aber da arbeite ich daran.
Wichtig wäre für mich, zu wissen, wie verständlich ich das Thema Sprites rübergebracht habe, ob der BASIC- und der Assembler-Code nachvollziehbar ist usw.
Bin schon auf das Feedback gespannt ![]()
lg, Markus
Finde ich gut. Ich hatte mich noch nie mit Sprites beschäftigt.
Da die Programme zu den mehrfarbigen Sprites nicht im Image sind, habe ich sie selbst getippt. Beim Basic habe ich ewig nach meinem Fehler gesucht. Eine 3 durch eine 2 vertauscht.
Die Assembler-Version habe ich noch etwas kürzer bekommen:
*=$0801
!basic start
start
; Blocknummer schreiben
lda #$0b
ldx #$00
write_bn
sta $07f8,x
inx
cpx #$08
bne write_bn
; Spritedaten kopieren
ldx #$00
copy_spritedata
lda spritedaten,x
sta $02c0,x
inx
cpx #$3f
bne copy_spritedata
; Sprites mehrfarbig
lda #$ff
sta $d01c
; Sprites vor hintergrund
lda #$00
sta $d01b
; Erste gemeinsame Farbe
lda #$06
sta $d025
; Zweite gemeinsame Farbe
lda #$01
sta $d026
; Individuelle Farbe
lda #$00
sta $d027
lda #$0a
sta $d028
lda #$04
sta $d029
lda #$02
sta $d02a
lda #$05
sta $d02b
lda #$07
sta $d02c
lda #$0e
sta $d02d
lda #$0d
sta $d02e
; X-Koordinaten
lda #$18
sta $d000
lda #$37
sta $d002
lda #$56
sta $d004
lda #$75
sta $d006
lda #$94
sta $d008
lda #$b3
sta $d00a
lda #$d2
sta $d00c
lda #$f1
sta $d00e
; Y-Koordinaten
lda #$32
sta $d001
sta $d003
sta $d005
sta $d007
sta $d009
sta $d00b
sta $d00d
sta $d00f
; Alle Sprites aktivieren
lda #$ff
sta $d015
; Sprites nach unten bewegen
ldy #$33
y_loop
jsr store_y
jsr wait
iny
cpy #$e6
bne y_loop
; Sprites nach oben bewegen
ldy #$e4
y1_loop
jsr store_y
jsr wait
dey
cpy #$31
bne y1_loop
rts
store_y
sty $d001
sty $d003
sty $d005
sty $d007
sty $d009
sty $d00b
sty $d00d
sty $d00f
rts
wait
ldx #$00
wait_loop
inx
cpx #$ff
bne wait_loop
rts
spritedaten
!byte $00,$aa,$00
!byte $02,$aa,$80
!byte $0a,$aa,$a0
!byte $0a,$aa,$a0
!byte $2a,$aa,$a8
!byte $2b,$aa,$e8
!byte $2f,$eb,$f8
!byte $af,$eb,$fa
!byte $ad,$eb,$7a
!byte $ad,$eb,$7a
!byte $ab,$aa,$ea
!byte $aa,$aa,$aa
!byte $aa,$aa,$aa
!byte $aa,$aa,$aa
!byte $aa,$aa,$aa
!byte $aa,$aa,$aa
!byte $aa,$aa,$aa
!byte $a2,$8a,$8a
!byte $a2,$82,$8a
!byte $80,$82,$02
!byte $80,$82,$02
Alles anzeigen
Jetzt habe ich aber mal eine Frage zur Sprite-Kollision.
Es gibt die beiden Regster D019 und D01A.
In beiden Registern gibt es ein Bit, um den IRQ bei einer Sprite-Kollision zu aktivieren. Aber warum zwei mal? Was ist der Unterschied?
Jetzt habe ich aber mal eine Frage zur Sprite-Kollision.
Es gibt die beiden Regster D019 und D01A.
In beiden Registern gibt es ein Bit, um den IRQ bei einer Sprite-Kollision zu aktivieren. Aber warum zwei mal? Was ist der Unterschied?
Das ist im C64-Wiki ganz gut erklärt:
Programmierung beim VIC
Beim VIC muss zum einen die Rasterzeile angegeben werden, bei der ein Interrupt ausgelöst werden soll. Dies passiert in den Registern 18 ($D012) und dem höchstwertigen Bit von Register 17 ($D011). Anschließend muss der Rasterzeilen-Interrupt noch durch Setzen des 0-Bit in Register 26 ($D01A) angeschaltet werden.
Zuvor sollte allerdings auch noch die entsprechende Interrupt-Routine angepasst werden. Beim C64 ist die Interrupt-Leitung des VIC mit dem IRQ verbunden. Dementsprechend muss dort der IRQ angepasst werden.
Wichtig ist, dass die Interrupt-Routine den Interrupt bestätigt, damit der VIC das Interrupt-Signal wieder abschalten kann. Sonst würde, sobald die Interrupt-Routine beendet wurde, direkt ein neuer Interrupt ausgelöst werden. Dies geschieht, indem Bit 0 in Register 25 ($D019) gesetzt wird.
Da es auch noch andere Quellen für den IRQ gibt, sollte die Interrupt-Routine zudem prüfen, ob der aktuelle Interrupt tatsächlich durch einen Rasterzeilen-Interrupt ausgelöst wurde. Dafür kann man Register 25 ($D019) auslesen. Wenn dort Bit 7 (Interrupt durch VIC) und Bit 0 (Rasterzeilen-Interrupt) gesetzt sind, handelt es sich um einen Rasterzeilen-Interrupt.
Edit: Oh, sorry! Habe ganz übersehen, dass es um Sprites geht. Ich lass den Beitrag trotzdem mal stehen. ![]()
Es gibt die beiden Regster D019 und D01A.
In beiden Registern gibt es ein Bit, um den IRQ bei einer Sprite-Kollision zu aktivieren.
Nicht so ganz.
$D01A bestimmt, bei welchen Ereignissen der VIC einen Interrupt auslösen soll. Mit diesem Register kann man also z.B. den Rasterinterrupt ein- und die Kollisionsinterrupts ausschalten.
$D019 verrät einem beim Lesen, welche Ereignisse im VIC aufgetreten sind, und durch das Beschreiben des Registers kann man diese Ereignisse dann quittieren (so dass der VIC die Interruptleitung "wieder loslässt").
EDIT: Nur mal so als Beispiel: Hat man keine Lust auf Interrupts und will alles per Polling abhandeln, dann kommt man komplett mit Register $D019 aus und braucht $D01A gar nicht.
In beiden Registern gibt es jeweils zwei Bits für Sprite-Kollisionen, weil die beiden Ereignisse "ein Sprite ist mit einem anderen Sprite kollidiert" und "ein Sprite ist mit Zeichen/Grafikpixeln kollidiert" vom VIC separat behandelt werden.
$D019 verrät einem beim Lesen, welche Ereignisse im VIC aufgetreten sind, und durch das Beschreiben des Registers kann man diese Ereignisse dann quittieren
Ah, das hatte ich nicht verstanden. OK, dann ist es klar.
Finde ich gut. Ich hatte mich noch nie mit Sprites beschäftigt.
Da die Programme zu den mehrfarbigen Sprites nicht im Image sind, habe ich sie selbst getippt. Beim Basic habe ich ewig nach meinem Fehler gesucht. Eine 3 durch eine 2 vertauscht.
Die Assembler-Version habe ich noch etwas kürzer bekommen:
Code Alles anzeigen*=$0801 !basic start start ; Blocknummer schreiben lda #$0b ldx #$00 write_bn sta $07f8,x inx cpx #$08 bne write_bn ; Spritedaten kopieren ldx #$00 copy_spritedata lda spritedaten,x sta $02c0,x inx cpx #$3f bne copy_spritedata ; Sprites mehrfarbig lda #$ff sta $d01c ; Sprites vor hintergrund lda #$00 sta $d01b ; Erste gemeinsame Farbe lda #$06 sta $d025 ; Zweite gemeinsame Farbe lda #$01 sta $d026 ; Individuelle Farbe lda #$00 sta $d027 lda #$0a sta $d028 lda #$04 sta $d029 lda #$02 sta $d02a lda #$05 sta $d02b lda #$07 sta $d02c lda #$0e sta $d02d lda #$0d sta $d02e ; X-Koordinaten lda #$18 sta $d000 lda #$37 sta $d002 lda #$56 sta $d004 lda #$75 sta $d006 lda #$94 sta $d008 lda #$b3 sta $d00a lda #$d2 sta $d00c lda #$f1 sta $d00e ; Y-Koordinaten lda #$32 sta $d001 sta $d003 sta $d005 sta $d007 sta $d009 sta $d00b sta $d00d sta $d00f ; Alle Sprites aktivieren lda #$ff sta $d015 ; Sprites nach unten bewegen ldy #$33 y_loop jsr store_y jsr wait iny cpy #$e6 bne y_loop ; Sprites nach oben bewegen ldy #$e4 y1_loop jsr store_y jsr wait dey cpy #$31 bne y1_loop rts store_y sty $d001 sty $d003 sty $d005 sty $d007 sty $d009 sty $d00b sty $d00d sty $d00f rts wait ldx #$00 wait_loop inx cpx #$ff bne wait_loop rts spritedaten !byte $00,$aa,$00 !byte $02,$aa,$80 !byte $0a,$aa,$a0 !byte $0a,$aa,$a0 !byte $2a,$aa,$a8 !byte $2b,$aa,$e8 !byte $2f,$eb,$f8 !byte $af,$eb,$fa !byte $ad,$eb,$7a !byte $ad,$eb,$7a !byte $ab,$aa,$ea !byte $aa,$aa,$aa !byte $aa,$aa,$aa !byte $aa,$aa,$aa !byte $aa,$aa,$aa !byte $aa,$aa,$aa !byte $aa,$aa,$aa !byte $a2,$8a,$8a !byte $a2,$82,$8a !byte $80,$82,$02 !byte $80,$82,$02
Sorry, hatte ich ganz vergessen, das BASIC-Programm und das Assembler-Programm für die Multicolor-Sprites sind nun auch im Image auf GitHub.
Das Assembler-Programm hab ich als BASIC-Loader unter dem Namen COLSPRITELOADER zur Verfügung gestellt. Einfach laden, mit RUN starten damit das Maschinenprogramm in den Speicher kommt und dann mit SYS 5440 starten.
Der Geschwindigkeits-Unterschied ist wie gesagt enorm.
lg, Markus
Wie kann man denn sowas vergessen?![]()
Nein im Ernst, dann muss man wenigstens auch mal was selbst machen. Das ist doch für einen Kurs auch gut. Man muss halt nur richtig abschreiben, sonst muss man halt suchen. Copy&Paste aus dem Screenshot geht ja nicht.
Wobei ich zuerst der Einfachheit halber im kleinen Notepad-Fenster abgetippt hatte. Beim Copy&Paste in C64Studio musste ich dann auf unerwartete Probleme stoßen. Also, Cop&Paste ist auch nicht immer so unproblematisch.
Vielleicht noch zwei Bemerkungen:
Was ich als etwas verwirrend, manchmal auch unpraktisch finde, dass der Einsprungspunkt bei den Beispielen immer wieder woanders liegt. Ich könnte mir vorstellen, dass es für Anfänger einfacher wäre, wenn der Einsprungspunkt immer an der gleichen Adresse wäre.
Wie man an meinem Beispiel zu den mehrfarbigen Sprites sehen kann, habe ich einen anderen Aufbau gewählt, wodurch ich sogar noch ein paar Bytes einsparen konnte. Dabei meine ich nicht die sparsamere Routine des Y-Koordinaten setzen, sondern dass ich das Hauptprogramm in einem durch geschrieben habe. Ich bin in Assembler ja noch kein Profi, erst Recht nicht auf dem C64, aber mir ist aufgefallen, dass markusk2020 immer wieder Sprünge über Funktionen macht. Hier bei den Sprites z.B. der Sprung über die Unterfunktion zum Setzen der Y-Position und der Warteschleife. Ich habe diese hinten dran gehängt, was den Sprungbefehl erspart und außerdem das Hauptprogramm in einem durch hat. Ich weiß nicht, ob es einen besonderen Grund für die Vorgehensweise gab. Wenn nein, würde ich das vielleicht noch ändern. Einem Neuling erst etwas falsches/ungünstiges beibringen und später erzählen "das kann man auch besser machen", ist didaktisch nicht so praktisch. Falsch gelerntes wieder umzulernen ist wesentlich schwieriger, als es gleich richtig zu lernen.
Nur so zwei Überlegungen.
Vielleicht noch zwei Bemerkungen:
Was ich als etwas verwirrend, manchmal auch unpraktisch finde, dass der Einsprungspunkt bei den Beispielen immer wieder woanders liegt. Ich könnte mir vorstellen, dass es für Anfänger einfacher wäre, wenn der Einsprungspunkt immer an der gleichen Adresse wäre.
Wie man an meinem Beispiel zu den mehrfarbigen Sprites sehen kann, habe ich einen anderen Aufbau gewählt, wodurch ich sogar noch ein paar Bytes einsparen konnte. Dabei meine ich nicht die sparsamere Routine des Y-Koordinaten setzen, sondern dass ich das Hauptprogramm in einem durch geschrieben habe. Ich bin in Assembler ja noch kein Profi, erst Recht nicht auf dem C64, aber mir ist aufgefallen, dass markusk2020 immer wieder Sprünge über Funktionen macht. Hier bei den Sprites z.B. der Sprung über die Unterfunktion zum Setzen der Y-Position und der Warteschleife. Ich habe diese hinten dran gehängt, was den Sprungbefehl erspart und außerdem das Hauptprogramm in einem durch hat. Ich weiß nicht, ob es einen besonderen Grund für die Vorgehensweise gab. Wenn nein, würde ich das vielleicht noch ändern. Einem Neuling erst etwas falsches/ungünstiges beibringen und später erzählen "das kann man auch besser machen", ist didaktisch nicht so praktisch. Falsch gelerntes wieder umzulernen ist wesentlich schwieriger, als es gleich richtig zu lernen.
Nur so zwei Überlegungen.
Das mit den Sprüngen über Funktionen hinweg ist zugegeben nicht so schön, normalerweise mache ich das beim Programmieren auch immer so, dass ich die Unterprogramme entweder am Beginn oder am Ende des Programms zusammenfasse. Das Problem ist, dass der SMON in Bezug auf Änderungen am Programmcode langsam recht unpraktisch wird. Mittendrin Programmcode einfügen ist beispielsweise sehr aufwendig, und wenn es nur eine Zeile ist. Man muss ja alles was nachher kommt dann verschieben und ggf. auch Zieladressen bei Sprüngen anpassen.
Der SMON bietet zwar die Möglichkeit, Programmcode zu verschieben, aber irgendwie hat das oft nicht so richtig geklappt. Kann auch sein, dass ich die Funktion nicht richtig angewandt habe.
Im C64 Studio oder CBM prg Studio hat man es da natürlich leicht, denn da kann man Änderungen am Programmcode jederzeit in beliebiger Art und Weise durchführen und schickt das komplette neue Programm dann in den Emulator.
Eine Alternative wäre, auf den Turbo Assembler zu wechseln. Der läuft wie der SMON auch direkt am C64, hat aber den Vorteil, dass er was Änderungen am Programmcode betrifft wesentlich flexibler ist.
Und die unterschiedlichen Einsprungadressen ergeben sich dadurch, dass ich die Daten immer am Anfang des Programms abgelegt habe. Je nach Umfang der Daten verschiebt sich natürlich auch die Startadresse des eigentlichen Programms. Auch hier habe ich beim SMON das Problem mit dem Einfügen neuer Daten.
Werde mir den Turbo Assembler mal näher ansehen, um zu prüfen, wie groß die Umgewöhnung vom SMON kommend ist. Ein Wechsel scheint jedoch unausweichlich, vor allem weil die Programme ja immer umfangreicher werden.
lg, Markus
Gut, soweit ich mich jetzt an den Inhalt des Kurses erinnere, hast Du im Kurs selbst aber nicht so oft etwas verändert, oder eingefügt. Das war dann vermutlich bei Deinen Versuchen zum Aufbau des Codes.
Wäre es dann nicht vielleicht eine Lösung, den Code selbst z.B. in C64Studio zu entwickeln und wenn er dann fertig ist, das Kompilat im Emulator zu "fotografieren"?
Ja, Turbo Assembler, oder andere wären da auf dem C64 direkt durchaus eine Möglichkeit. Ich habe früher glaube mit Hypra-Ass oder so ähnlich gearbeitet. Auch ExAss habe ich mir schon mal angesehen. Generell finde ich zumindest zu Anfang des Kurses die direkte Eingabe aber gar nicht so falsch, damit der Leser erstmal eine Vorstellung davon bekommt, was da passiert. Im Laufe des Kurses könnte man tatsächlich auf einen komfortableren Assembler umsteigen.
Gut, soweit ich mich jetzt an den Inhalt des Kurses erinnere, hast Du im Kurs selbst aber nicht so oft etwas verändert, oder eingefügt. Das war dann vermutlich bei Deinen Versuchen zum Aufbau des Codes.
Wäre es dann nicht vielleicht eine Lösung, den Code selbst z.B. in C64Studio zu entwickeln und wenn er dann fertig ist, das Kompilat im Emulator zu "fotografieren"?
Fände ich auch besser. Man sollte Anfängern ja nicht unbedingt zeigen, wie man es normalerweise nicht macht. ![]()
Ich hätte das Programm auch mir einem komfortablen Assembler geschrieben und dann das fertige Programm in den Monitor geladen.