Assembler für Einsteiger

Moderator: Rockford

Antworten
Benutzeravatar
Prodehl
Beiträge: 280
Registriert: 24.08.2021 14:40
Has thanked: 14 times
Been thanked: 52 times
Kontaktdaten:

Assembler für Einsteiger

Beitrag von Prodehl »

Hallo in die Runde,
auf der Fujiyama wollte ich eigentlich viel mehr Assembler programmieren und lernen... leider war zu wenig Zeit und zu viele andere wichtige Dinge.
Vielleicht hat jemand Lust hier auf dem Forum ein wenig mit mir zu lernen... da bin ich ja auch noch ganz blutiger Anfänger und mache jetzt erste Schritte!

Mein erster Schritt war natürlich eine "Hallo Welt!" Routine zu schreiben. Ich wollte dabei wirklich ohne die vorhandenen I/O-Routinen des Betriebssytems das selber auf den Bildschirm printen. Das ist zunächst relativ einfach, wenn man weiß, wo der Bildschirm anfängt: 40000 - bzw. in den Speicherstellen 88/89.
Nun wollte ich es aber so haben, daß das Programm 15 x "Hallo Welt!" untereinander (nicht nebeneinander) auf den Bildschirm printet. Eine nicht ganz einfache Aufgabe für den Start, muss ich sagen, aber wenn man das dann löst, hat man viel gelernt!! Hier nun meine (sicherlich echt für den Profi sehr holprige) Lösung - mit dem Aufruf: Wie bekommt man das noch schlanker, kürzer und eleganter hin??
Liebe Grüße
Peter

Code: Alles auswählen

		org $4000
text .byte "Hallo Welt! "
var = 88
var2 = 89
var3 = $6000

start		lda #0
		sta var3
main		ldy #0
		ldx #0
loop1		lda text,x
		sta (var),y
		inx
		iny
		cpx #12
		bne loop1
		clc
		ldy #0
		ldx #0
		lda var
		adc #40
		sta var
		lda var2
		adc #0
		sta var2
		ldx var3
		inx
		stx var3
		cpx #15
		bne main
		
loop3		jmp loop3
		
		
				
		run start

Benutzeravatar
Prodehl
Beiträge: 280
Registriert: 24.08.2021 14:40
Has thanked: 14 times
Been thanked: 52 times
Kontaktdaten:

Re: Assembler für Einsteiger

Beitrag von Prodehl »

Code: Alles auswählen

		org $4000
text .byte "Hallo Welt! "
var = 88
var2 = 89

start		ldx #0
main		ldy #0
loop1		lda text,y
		sta (var),y
		iny
		cpy #12
		bne loop1
		clc
		ldy #0
		lda var
		adc #40
		sta var
		lda var2
		adc #0
		sta var2
		inx
		cpx #15
		bne main
loop3		jmp loop3
		
		
				
		run start

Benutzeravatar
pps
Beiträge: 99
Registriert: 18.06.2021 23:05
Has thanked: 11 times
Been thanked: 40 times
Kontaktdaten:

Re: Assembler für Einsteiger

Beitrag von pps »

Drehe mal Deine loops um.

Also in der Art:

Code: Alles auswählen

   LDY #15
LOOP
   LDA text,y
   STA (var),y
   DEY
   BPL LOOP
Man spart sich so das extra CMP #0, da solange es nicht minus ist wieder zum LOOP gesprungen wird. Achtung! Das geht natürlich nur so ganz einfach bei kleinen Loops, die nicht so oft wiederholt werden müssen, dass das High Bit von y gesetzt ist. Also maximal bis $7F.
PP´s of STARSOFTBerlin__________github|meine Webseite

Benutzeravatar
Prodehl
Beiträge: 280
Registriert: 24.08.2021 14:40
Has thanked: 14 times
Been thanked: 52 times
Kontaktdaten:

Re: Assembler für Einsteiger

Beitrag von Prodehl »

Das Programm sieht dann so aus:

Code: Alles auswählen

		org $4000
text .byte "Hallo Welt! "
var = 88
var2 = 89
start		ldx #0
main		ldy #11
loop1		lda text,y
		sta (var),y
		dey
		bpl loop1
		clc
		lda var
		adc #40
		sta var
		lda var2
		adc #0
		sta var2
		inx
		cpx #15
		bne main
loop3		jmp loop3
						
		run start
... und ist tatsächlich noch schlanker... !! Supi!
Ich denke mit diesem Ansatz wird es nicht viel schlanker werden.. vielleicht gibt es noch einen ganz anderen Ansatz!

Als nächstes möchte ich den Text "Hallo Welt!" von links oben Zeile für Zeile nach links unten printen lassen, also ein grobes scrollen quasi.

Benutzeravatar
Irgendwer
Beiträge: 22
Registriert: 25.08.2021 19:05
Has thanked: 9 times
Been thanked: 9 times
Kontaktdaten:

Re: Assembler für Einsteiger

Beitrag von Irgendwer »

Code: Alles auswählen

		org $4000
text .byte "Hallo Welt! "
SAVMSC = 88
start	ldx #14
main	ldy #11
loop1	lda text,y
	sta (var),y
	dey
	bpl loop1
	clc
	lda SAVMSC
	adc #40
	sta SAVMSC
	bcc checkEnd
	inc SAVMSC+1
checkEnd
	dex
	bpl main

loop3	jmp loop3
			
	run start
(Ob es eine gute Idee ist SAVMSC zu verändern, oder ob man nicht lieber eine andere Variable dafür nutzt, ist eine andere Diskussion.)

Benutzeravatar
Prodehl
Beiträge: 280
Registriert: 24.08.2021 14:40
Has thanked: 14 times
Been thanked: 52 times
Kontaktdaten:

Re: Assembler für Einsteiger

Beitrag von Prodehl »

... cool ... damit ist der Übertrag natürlich deutlich eleganter gelöst und auch die 2. Schleife mit dex und bpl main!
Ob man SAVMSC (was bedeutet eigentlich SAVMSC??) verändern sollt, habe ich mich auch schon gefragt, da man dadurch ja den Vector für die Bildschirmadresse verliert... immerhin ging es so und er hat sich nicht gleich festgefressen ;-)

Benutzeravatar
Irgendwer
Beiträge: 22
Registriert: 25.08.2021 19:05
Has thanked: 9 times
Been thanked: 9 times
Kontaktdaten:

Re: Assembler für Einsteiger

Beitrag von Irgendwer »

Prodehl hat geschrieben:
28.09.2021 11:07
Ob man SAVMSC (was bedeutet eigentlich SAVMSC??) verändern sollt, habe ich mich auch schon gefragt, da man dadurch ja den Vector für die Bildschirmadresse verliert...
Die Adressen des Betriebssystems (und Hardware-Register) haben Standardnamen. Um die Lesbarkeit und Wiedererkennungswert (gerade bei Assembler) zu erhöhen, bietet es sich an diese auch zu verwenden.
Die Namen kannst Du z.B. auch im Atari-Profibuch finden (SAVMSC auf Seite 12). Gab es auf der alten Abbuc Seite mal zum Download - keine Ahnung wo es hier verfügbar ist.

Weil Du nach anderen Herangehensweisen gefragt hast: Es gibt noch die Technik selbstmodifizierenden Code zu schreiben - das ist aber nichts, was ich einem Anfänger empfehlen würde.
...und noch einen Hinweis: Ab einen bestimmten Punkt muss man sich fragen ob der Code schneller oder kürzer werden soll. Geschwindigkeit und Speicherplatzbedarf sind unterschiedliche Optimierungsziele.

Viel Spaß!

Edit:
Die symbolischen Namen kannst Du auch hier finden:
https://www.atariarchives.org/mapping/memorymap.php

Benutzeravatar
Prodehl
Beiträge: 280
Registriert: 24.08.2021 14:40
Has thanked: 14 times
Been thanked: 52 times
Kontaktdaten:

Re: Assembler für Einsteiger

Beitrag von Prodehl »

... mich hätte einfach interessiert, für was die savmsc genommen haben... ist aber egal.
Ganz so sehr Anfänger bin ich ja nicht, eher Wiedereinsteiger, der das jetzt hinsichtlich Assembler hobbymäßig intensiver betreiben will.
Damals habe ich schon direkt Maschinensprache gecodet, ist aber 40 Jahre her ... da habe ich auch mal mit selbstmodifizierenden Code experimentiert! Sehr spannend!
Damals musste man sich alles selber beibringen, an Bücher kam man kaum ran bzw. es gab sie schlichtweg gar nicht!!

Benutzeravatar
Irgendwer
Beiträge: 22
Registriert: 25.08.2021 19:05
Has thanked: 9 times
Been thanked: 9 times
Kontaktdaten:

Re: Assembler für Einsteiger

Beitrag von Irgendwer »

Prodehl hat geschrieben:
28.09.2021 12:49
... mich hätte einfach interessiert, für was die savmsc genommen haben... ist aber egal.
Ich würde mal auf "SAVe Memory SCreen" tippen.

Wenn Du Dich für selbstmodifizierenden Code interessiert, ich habe mal für ca65 ein Makro-Package geschrieben.
Das erhöht die Lesbarkeit enorm.

https://cc65.github.io/doc/smc.html

Benutzeravatar
Prodehl
Beiträge: 280
Registriert: 24.08.2021 14:40
Has thanked: 14 times
Been thanked: 52 times
Kontaktdaten:

Re: Assembler für Einsteiger

Beitrag von Prodehl »

eins noch zum Thema SAVMSC verändern... das Problem ist ja, daß man die indirekte Adressierung verwenden muss und die funktioniert ja nur bei page 0 - man muss also dann irgendwo im Bereich page 0 einen freien Bereich finden, wo man seine Variablen definieren kann... oder habe ich da einen Denkfehler??

Benutzeravatar
Irgendwer
Beiträge: 22
Registriert: 25.08.2021 19:05
Has thanked: 9 times
Been thanked: 9 times
Kontaktdaten:

Re: Assembler für Einsteiger

Beitrag von Irgendwer »

Prodehl hat geschrieben:
28.09.2021 15:46
eins noch zum Thema SAVMSC verändern... das Problem ist ja, daß man die indirekte Adressierung verwenden muss und die funktioniert ja nur bei page 0 - man muss also dann irgendwo im Bereich page 0 einen freien Bereich finden, wo man seine Variablen definieren kann... oder habe ich da einen Denkfehler??
Nein, genauso ist es. Man sucht sich einen freien Zero-Page-Bereich (z.B. ab $80 wenn man Basic und Fließkommazahlen nicht braucht) und arbeitet auf einer Kopie.

oder...:

Code: Alles auswählen

...
		lda SAVMSC
		sta storeToScreen+1
		lda SAVMSC+1
		sta storeToScreen+2
...
		lda text, y
storeToScreen	sta $ABCD, y
...
		clc
		lda storeToScreen+1
		adc #40
		sta storeToScreen+1
		bcc checkEnd
		inc storeToScreen+2
...
Das wäre die Version mit SMC ohne zusätzlichen Page-0-Bedarf.

Benutzeravatar
Prodehl
Beiträge: 280
Registriert: 24.08.2021 14:40
Has thanked: 14 times
Been thanked: 52 times
Kontaktdaten:

Re: Assembler für Einsteiger

Beitrag von Prodehl »

... jetzt verstehe ich es ... wie pfiffig!!!!

Benutzeravatar
Irgendwer
Beiträge: 22
Registriert: 25.08.2021 19:05
Has thanked: 9 times
Been thanked: 9 times
Kontaktdaten:

Re: Assembler für Einsteiger

Beitrag von Irgendwer »

Prodehl hat geschrieben:
30.09.2021 08:58
... jetzt verstehe ich es ... wie pfiffig!!!!
Ja, man kann interessante Sachen machen um Zyklen, Zero-Page oder generell Speicherplatz zu sparen. In einem ROM läuft der Code dann natürlich nicht mehr!

Benutzeravatar
Prodehl
Beiträge: 280
Registriert: 24.08.2021 14:40
Has thanked: 14 times
Been thanked: 52 times
Kontaktdaten:

Re: Assembler für Einsteiger

Beitrag von Prodehl »

Ein echt interessanter Ansatz!
Der Code programmiert bzw. verändert sich dabei selber an der Stelle storescr 1+2, wo die Inhalte von savmsc reinkommen... $1234 ist dabei nur ein Platzhalter - dennoch erstaunlich, daß das so schön funktioniert, damit hebt man quasi die Beschränkung der indirekt indizierten Adressierung auf Page 0 auf.... habe ich das richtig verstanden? ;-)
Der Code sieht dann so aus - und funktioniert!! Geil!

Code: Alles auswählen

			org $6000
savmsc = 88
text .byte "Hallo Welt! "

start			lda savmsc
			sta storescr+1
			lda savmsc+1
			sta storescr+2
			ldx #14
			
main			ldy #11
loop1			lda text,y
storescr		sta $1234,y
			dey
			bpl loop1
			clc
			lda storescr+1
			adc #40
			sta storescr+1
			bcc chkend
			inc storescr+2
chkend			dex
			bpl main

lp			jmp lp			
			
			
			
		
			run start
		

Benutzeravatar
Irgendwer
Beiträge: 22
Registriert: 25.08.2021 19:05
Has thanked: 9 times
Been thanked: 9 times
Kontaktdaten:

Re: Assembler für Einsteiger

Beitrag von Irgendwer »

Prodehl hat geschrieben:
30.09.2021 14:10
Der Code programmiert bzw. verändert sich dabei selber an der Stelle storescr 1+2, wo die Inhalte von savmsc reinkommen... $1234 ist dabei nur ein Platzhalter - dennoch erstaunlich, daß das so schön funktioniert, damit hebt man quasi die Beschränkung der indirekt indizierten Adressierung auf Page 0 auf.... habe ich das richtig verstanden? ;-)
Ja, ich hätte es nicht besser formulieren können.
Leider hat diese Art der Programmierung heutzutage keine Bedeutung mehr. CPUs mit einem Instruktionscache, der bei solchen Modifikationen gelöscht werden müsste, haben dadurch große Leistungseinbußen.
Viele Mikrocontroller besitzen zwar keinen Cache, haben aber einen Read-Only Programmspeicher der vom Datenspeicher getrennt ist.
SMC ist auch aus sicherheitstechnischen Gründen bei modernen Architekturen sehr kritisch zu sehen. Deswegen wurde auch das NX-Bit bei CPUs eingeführt: https://de.wikipedia.org/wiki/NX-Bit

Aber bei der 6502 Programmierung sind schöne kniffelige Sachen möglich.

Benutzeravatar
Prodehl
Beiträge: 280
Registriert: 24.08.2021 14:40
Has thanked: 14 times
Been thanked: 52 times
Kontaktdaten:

Re: Assembler für Einsteiger

Beitrag von Prodehl »

... im Rahmen der Sicherheit war diese Unterbindung sicherlich notwendig ... beim Atari natürlich heutzutage nicht relevant!
Interessant, daß ich nirgends was finde zur Dokumentation dieser Addressierungs / Programmierart. Immerhin erweitert das die Programmiermöglichkeiten ganz erheblich!
Gibt es noch mehr solcher interessanten und nicht dokumentierten Tricks??

Benutzeravatar
Prodehl
Beiträge: 280
Registriert: 24.08.2021 14:40
Has thanked: 14 times
Been thanked: 52 times
Kontaktdaten:

Re: Assembler für Einsteiger

Beitrag von Prodehl »

Hier jetzt noch abschließend mein Listing für "Hallo Welt!" Grobscrolling vom Bildschirmanfang nach unten. Inclusive Warteschleife!

Code: Alles auswählen

			org $6000
savmsc = 88
text .byte "Hallo Welt! "
var1 = 180
start			clc
			lda savmsc
			sta stor2+1
			adc #40
			sta stor1+1
			lda savmsc+1
			sta stor1+2
			sta stor2+2
			ldx #23
main			ldy #11
loop1			lda #0
stor2			sta 0,y
			lda text,y
stor1			sta 0,y
			dey
			bpl loop1
			clc 
			lda stor1+1
			adc #40
			sta stor1+1
			bcc chkend
			inc stor1+2
chkend			clc
			lda stor2+1
			adc #40
			sta stor2+1
			bcc chkend2
			inc stor2+2
chkend2			ldy #0
warten1			lda #0
			sta var1
warten2			lda var1
			adc #1
			sta var1
			bcc warten2
			iny
			bne warten1
			dex
			bpl main
			jmp start			
			
			run start
		

Benutzeravatar
Irgendwer
Beiträge: 22
Registriert: 25.08.2021 19:05
Has thanked: 9 times
Been thanked: 9 times
Kontaktdaten:

Re: Assembler für Einsteiger

Beitrag von Irgendwer »

Prodehl hat geschrieben:
01.10.2021 09:31
Interessant, daß ich nirgends was finde zur Dokumentation dieser Addressierungs / Programmierart. Immerhin erweitert das die Programmiermöglichkeiten ganz erheblich!
Ja, man liest in der Tat nicht viel darüber. Ich kann mich nicht mehr erinnern, wann ich zuerst darüber mal was gelesen habe (vielleicht in "Peter Finzels Assemblerecke"?). Die Verwendung war aber schon immer etwas "exotisch".
Prodehl hat geschrieben:
01.10.2021 09:31
Gibt es noch mehr solcher interessanten und nicht dokumentierten Tricks??
Das ist immer die Frage was interessant ist und ob wenig bzw. schwer auffindbare Dokumentation "auch schon was ist".

Es gibt z.B. noch die undokumentierten 6502 Opcodes (inzwischen sind sie aber mehr als gut dokumentiert), die auf den NMOS 6502 Varianten das Befehlsspektrum erweitern. Z.B. "SAX": Speichert das Ergebnis von "A und X" an die angegebene Adresse.
http://www.oxyron.de/html/opcodes02.html

Dann gibt es noch nette Tricksereien mit dem Stack - um z.B. flexible Parameterübergabe zu ermöglichen oder Rücksprungadressen anzupassen. "BRK" hat auch noch einiges, ungenutztes Potential.

Wenn Du 256 Bytes für eine "Identity Table" über hast, kannst Du neue, sinnvolle Instruktionen wie "tyx", "sbc x" oder "cmp y" damit bauen:

Code: Alles auswählen

identity_table:
    .byte $00,$01,$02,$03,$04,$05,$06,$07,$08,$09,$0a,$0b,$0c,$0d,$0e,$0f
    .byte $10,$11,$12,$13,$14,$15,$16,$17,$18,$19,$1a,$1b,$1c,$1d,$1e,$1f
    .byte $20,$21,$22,$23,$24,$25,$26,$27,$28,$29,$2a,$2b,$2c,$2d,$2e,$2f
    .byte $30,$31,$32,$33,$34,$35,$36,$37,$38,$39,$3a,$3b,$3c,$3d,$3e,$3f
    .byte $40,$41,$42,$43,$44,$45,$46,$47,$48,$49,$4a,$4b,$4c,$4d,$4e,$4f
    .byte $50,$51,$52,$53,$54,$55,$56,$57,$58,$59,$5a,$5b,$5c,$5d,$5e,$5f
    .byte $60,$61,$62,$63,$64,$65,$66,$67,$68,$69,$6a,$6b,$6c,$6d,$6e,$6f
    .byte $70,$71,$72,$73,$74,$75,$76,$77,$78,$79,$7a,$7b,$7c,$7d,$7e,$7f
    .byte $80,$81,$82,$83,$84,$85,$86,$87,$88,$89,$8a,$8b,$8c,$8d,$8e,$8f
    .byte $90,$91,$92,$93,$94,$95,$96,$97,$98,$99,$9a,$9b,$9c,$9d,$9e,$9f
    .byte $a0,$a1,$a2,$a3,$a4,$a5,$a6,$a7,$a8,$a9,$aa,$ab,$ac,$ad,$ae,$af
    .byte $b0,$b1,$b2,$b3,$b4,$b5,$b6,$b7,$b8,$b9,$ba,$bb,$bc,$bd,$be,$bf
    .byte $c0,$c1,$c2,$c3,$c4,$c5,$c6,$c7,$c8,$c9,$ca,$cb,$cc,$cd,$ce,$cf
    .byte $d0,$d1,$d2,$d3,$d4,$d5,$d6,$d7,$d8,$d9,$da,$db,$dc,$dd,$de,$df
    .byte $e0,$e1,$e2,$e3,$e4,$e5,$e6,$e7,$e8,$e9,$ea,$eb,$ec,$ed,$ee,$ef
    .byte $f0,$f1,$f2,$f3,$f4,$f5,$f6,$f7,$f8,$f9,$fa,$fb,$fc,$fd,$fe,$ff
Die Instruktionen:

Code: Alles auswählen

ldx identity_table,y 	tyx
ldy identity_table,x 	txy
and identity_table,x 	and X
and identity_table,y 	and Y
ora identity_table,x 	ora X
ora identity_table,y 	ora Y
eor identity_table,x 	eor X
eor identity_table,y 	eor Y
adc identity_table,x 	adc X
adc identity_table,y 	adc Y
sbc identity_table,x 	sbc X
sbc identity_table,y 	sbc Y
cmp identity_table,x 	cmp X
cmp identity_table,y 	cmp Y
bit identity_table+constant 	bit #constant

All the instructions above take 3 bytes and 4 CPU cycles, assuming the table is page-aligned (starts at $xx00) and not on zero page. (Crossing a page boundary causes slowdown with indexed addressing modes.)
dieses (https://wiki.nesdev.org/w/index.php?tit ... tity_table) und vieles andere kannst Du auf
https://wiki.nesdev.org finden:
https://wiki.nesdev.org/w/index.php?tit ... al_opcodes
https://wiki.nesdev.org/w/index.php?tit ... imisations
https://wiki.nesdev.org/w/index.php?tit ... structions
https://wiki.nesdev.org/w/index.php?title=RTS_Trick

Viel Spaß!

Benutzeravatar
LarsImNetz
Beiträge: 19
Registriert: 24.08.2021 18:27
Has thanked: 7 times
Been thanked: 6 times
Kontaktdaten:

Re: Assembler für Einsteiger

Beitrag von LarsImNetz »

Hallo,
ich wollte auch mal meinen Source-Code in die Runde werfen :D
* Es löscht den Schirm mittels OS (?chr$(125) wäre das in Basic)
* Gibt 24 Zeilen "Hallo Welt!" auf Graphics 0 aus
* Wartet per OS auf die "Anykey"-Taste.
Das Programm ist mit dem atasm 1.09 baubar. Die .bank/.set 6,0 braucht es, da ich am Ende der Adresse 736 die Startadresse zuweise, sonst würde der atasm die Reihenfolge Speicher-Richtig umdrehen, was bei 736 dann wenig hilfreich ist.

Ich mag den 6502 Assembler, da ist alles so schön einfach. Allerdings wird Assembler-Code sehr schnell sehr unverständlich. Bei meiner aktuellen Idee habe ich jetzt schon das nachsehen und weiß nicht mehr wirklich wie es funktioniert, nur das es funktioniert.

Und ehrlich, nutze ich auch lieber Hochsprachen statt Assembler. Aber dazu später mehr...

LG
Lars

Code: Alles auswählen

 .BANK
 .SET 6,0

savmsc=88
ptr_screen=203
ptr_text=205

EDITRV = $E400  ; Editor
KEYBDV = $E420  ; Keyboard

  *=$4000

  ldy #125
  jsr ?EDITOR_OUT


  lda savmsc          ; ptr fuer Startadresse oben links
  sta ptr_screen
  lda savmsc+1
  sta ptr_screen+1


  lda #<text          ; ptr fuer Text
  sta ptr_text
  lda #>text
  sta ptr_text+1

; Die eigentlichen Schleifen

  ldx #24             ; Anzahl Zeilen
line_loop

  ldy #0
output_loop           ; loop zur Ausgabe des Textes
  lda (ptr_text),y
  sta (ptr_screen),y
  iny
  cpy #(TEXTEND-TEXT)
  bne output_loop

  clc
  lda ptr_screen
  adc #41             ; 40 waere die normale Screen-Breite
  sta ptr_screen
  lda ptr_screen+1
  adc #0
  sta ptr_screen+1

  dex
  bne line_loop

; Warte auf Tastendruck
  jsr ?getkey
  rts

TEXT
  .sbyte " Hallo Welt!"
TEXTEND
  .byte $ff

; wartet, bis eine Taste gedrueckt wurde, gibt diese im Akku zurueck
?Getkey
  LDA KEYBDV+5 ;simuliere
  PHA
  LDA KEYBDV+4
  PHA
  RTS

; Gibt ein Zeichen im Y-Register auf dem Editor E: aus (Graphics 0)
?EDITOR_OUT
  LDA EDITRV+7
  PHA
  LDA EDITRV+6
  PHA
  TYA
  RTS


 .BANK
 .SET 6,0
 *=736
 .WORD $4000

Antworten

Wer ist online?

Mitglieder in diesem Forum: 0 Mitglieder und 1 Gast