-
Ich habe das früher mal aus dem Buch "Commodore 128 Intern" von Data Becker auf Lochrasterplatine nachgebaut. Dort ist eine kleine Schaltung am Userport auf Seite 19 beschrieben. Die Programmierung ist in Basic. Ich habe das mit dem Beispiel erst richtig verstanden, wie man den Userport programmiert.
Man findet das Buch zum Beispiel auf archive.org
Ich weiß nicht, ob ein Link hier sinnvoll ist, aber ich versuch's: https://archive.org/details/co…8-intern/page/19/mode/2up
-
Hallo, ich klinke mich hier auch mal in die Diskussion ein, denn im allerersten Posting steht doch was interessantes:
Zitat
The Z80 has a separate I/O address space, but in the C128 it is not mapped to anything else than the normal address space IIRC. So you can chose whether to use IN and OUT or normal LD instructions for talking to hardware, whatever is more convenient.
Ich habe immer gedacht, dass man beim Z80 nur über die Befehle: OUT (C), A und IN A, (C) auf die IO-Adressen zugreifen kann, was extrem langsam ist (12 Taktzyklen). Die anderen IO-Befehle funktionieren anscheinend wegen eines Bugs nicht:
https://dr.ea.ms/c128hardwarebug.html
Hat das mal jemand ausprobiert, ob man Ein- und Ausgabe beim C128 über den Z80 auch direkt machen kann?
Dann könnte man ja doch recht schnell auf die IO-Chips zugreifen zum Beispiel über: LD A,(HL) (7 Zyklen) oder über den Stack: PUSH BC (11 Zyklen).
-
Hier ist nochmal ein anderer Ansatz ohne Tabelle. Es wird immer durch 10 dividiert und y hochgezählt bis das Ergebnis 0 ist. Aber es ist etwas länger als die Tabellenversion:
- dividend_lo = $63
- dividend_hi = $62
-
- ldy #0
- loop
- iny
- divide10
- lda #0
- ldx #16
- divloop
- asl dividend_lo
- rol dividend_hi
- rol
- cmp #10
- bcc skip
- sbc #10
- inc dividend_lo
- skip
- dex
- bne divloop
- lda dividend_lo
- ora dividend_hi
- bne loop
Alles anzeigen
-
Wow, 5ace und YPS, Ihr habt ja im Grunde schon die Lösung.
Mir fällt dazu im Augenblick auch nichts anderes ein, außer einfach mal wieder zu schnorren und aufgrund eurer Vorarbeit das ganze minimal zu verkürzen:
- ldy #6
- loop
- dey
- cmp tablo-1,y
- pha
- txa
- sbc tabhi-1,y
- pla
- bcc loop ; A/X < tab ?
- ...
- tabhi
- !byte >0, >10, >100, >1000, >10000
- tablo
- !byte <0, <10, <100, <1000, <10000
Alles anzeigen
-
7 nach 6 ist auch nicht komplizierter:
- lda byte
- and #%10111111
- bpl +
- ora #%01000000
- + sta byte
-
Andernfalls mit bit 1 "initialisieren":
- lda zeropageByte [3] ; clear bit 1
- and #%00000010 [2]
- sta zeropageByte [3]
- lsr zeropageByte [6] ; shift to the right, carry flag contains now former bit 0
- bcc nottin [2/3] ; carry is clear: do nothing
- inc zeropageByte [5] ; carry is set: increase zeropageByte => current bit 0 becomes 1
- .nottin
- rol zeropageByte [5] ; rotate to the left, carry flag is shifted into bit 0
insgesamt 26/27 Taktzyklen und 14 bytes.
Freitags-brain-fart und ungestestet.
Ich glaube, du meinst and #%11111101, sonst hast du dein zeropageByte fast komplett zerstört.
-
Ich habe noch einen Vorschlag, inspiriert durch bernies erste Version und ayvazhzfs Version. Der ist aber auch ungetestet:
- ldx byte
- inx
- txa
- and #%00000010
- eor byte
- sta byte
Die Idee ist, dass man sich das shiften spart und damit weniger Bytes braucht.
Ich denke, dass bspw. "xxxxxx11" nicht funktionieren würde, weil das inx das nächste Bit (Bit 2) beeinflusst.
Bit 2 kann nicht beeinflusst werden, da and #%00000010 alle Bits außer Bit 1 neutralisiert.
-
Ich habe noch einen Vorschlag, inspiriert durch bernies erste Version und ayvazhzfs Version. Der ist aber auch ungetestet:
- ldx byte
- inx
- txa
- and #%00000010
- eor byte
- sta byte
Die Idee ist, dass man sich das shiften spart und damit weniger Bytes braucht.
-
Ich war in letzter Zeit viel unterwegs und deshalb kommt der Quelltext zu meinem Beitrag erst jetzt.
- processor 6502
- org $0801
- zp_033c = $b2
- zp_0aad = $79
- zp_0ab0 = $7e
- dc.b $0b,$08
- loop1
- lda (zp_033c),y
- dc.b $9e,$32,$30,$36,$33
- sta (zp_0aad),y
- sha $037f,y
- iny
- bpl loop1
- ldx #$3c
- loop2
- ldy #$3f
- loop
- rla (zp_0ab0),y
- dey
- rla (zp_0ab0),y
- dey
- rla (zp_0ab0),y
- ror $0380,x
- ror $0381,x
- ror $0382,x
- dey
- bne loop
- dex
- dex
- dex
- bpl loop2
- rts
Alles anzeigen
Ich muss zugeben, dass ich es diesmal etwas verkackt habe. Ich war der Meinung, dass ich in jedem Fall vorher die Daten durch Kopieren in Sicherheit bringen muss, weil ich zuwenig Platz zum Rangieren habe. Das stimmt aber nicht.
Ich brauche immer die Angaben, wo ungefähr gerade die beste Lösung liegt. Wenn ich zum Beispiel gewusst hätte, dass 43 Byte möglich sind, dann hätte ich gewusst, dass mein Ansatz falsch ist und es einen besseren geben muss. So habe ich nur meinen Ansatz mit Gewalt in den 4x Bereich gequetscht.
Die Compos machen mir immer viel Spaß. Aber ab einem gewissen Grad bin ich mir unsicher wegen der Regeln. Es war zum Beispiel vorgegeben, dass das Zielsprite gelöscht werden soll, obwohl es nach einem Reset auf 0 gesetzt wird. Mein Programm geht aber zum Beispiel davon aus, dass im Basicspeicher irgenwo in den ersten 256 Bytes drei Nullen stehen. Ansonsten stürzt es beim Laden ab. Davon kann man aber eigentlich nicht ausgehen. Der Speicher kann ja irgendwie belegt sein. Also wenn man "sauber" programmiert, muss man mein rts durch 3 Nullen ersetzen und mein Programm hat 51 Bytes.
-
Oh, da war ich knapp zu spät.
-
Am einfachsten geht es so:
- lda #$08; der Wert steht ursprünglich im Akku
- eor #$ff; Dann steht $ff-Akku im Akku
- sec
- sbc #$01; noch eins abziehen, dann steht $ff-Akku-1 im Akku
Wenn du das x-Register vom Akku abziehen willst, dann geht das nur mit Zwischenspeicher:
- lda #$08
- sta $02; Zwischenspeicher
- lda #$ff
- sec
- sbc $02; Akku = $ff-Akku
- sec
- sbc #$01; Akku = $ff-Akku-1
-
Ich habe noch zwei Fragen:
1) Kann man davon ausgehen, dass die Register (A,X,Y) auf 0 initialisiert sind?
2) Kann man davon ausgehen, dass bestimmte ZP-Adressen gesetzt sind? Ich denke da so an $39/$3a mit der aktuellen Zeilennummer oder $2d/$2e, die direkt hinter das Programm zeigen sollen.
-
- Die Abfrage mit dem Index 0 wird nicht mehr benötigt, falls der Fall einmal aufgetreten ist. Dann wird die Abfrage gelöscht.
Ahh, verdammt. Ich glaube, der Punkt wäre es gewesen. Ich hätte die Abfrage, nach dem der Index 0 gefunden wurde, einfach löschen sollen, dann hätte ich mehr Platz zum Schleifenentrollen gehabt. Damit hätte sich mein Code entscheidend verschnellert.

Aber was solls. Eigentlich wollte ich gar nicht mitmachen. Dann habe ich gesehen, dass meine erste Lösung so etwa 20000 Zyklen gebraucht hat und ich damit gut im Rennen lag. Peiselulli hat zuerst, glaube ich, 25000 Zyklen angekündigt. Danke dafür. Auch für die 13500 Zyklen-Ansge. 
Auf die kurze Version bin ich nicht gekommen, deshalb
an die Gewinner.
-
Die Tabelle bucket liegt bei ce00. Es wird also ein and "#cf" gemacht. Das bedeutet, dass das and egal ist bei folgenden Werten: $00-$0f, $40-$4f, $80-$8f, $c0-$cf. Das sind zusammen 64 Werte.
Das "beq *-4" oder "beq *+5" ist natürlich nicht mehr lesbar, aber ich brauche mich dann beim Schleifen-Entrollen nicht mehr darum zu kümmern. Ich habe das vergessen wieder auszubauen, als ich das Listing hier gepastet habe.
-
Das war sauknapp am Ende, aber ich hab's versucht.
Glückwunsch peiselulli 
Meine eingereichte Version ist nicht mehr lesbar. Deshalb zeige ich hier zwei Programmversionen, die vielleicht nützlich sind.
Version1, kurz und einigermaßen schnell, einer Bucketsort:
Identical: 17607 cycles
Random Data: 18939 cycles (average of 100 runs)
Fixed Data: 18936 cycles (with duplicates)
Fixed Data: 19218 cycles (no duplicates)
Ascending: 19218 cycles
Descending: 19218 cycles
67 Byte
- processor 6502
- org $c000
- ;*** init
- bucket = $cf00
- liste2 = $ce00
- ldy #0
- tya
- loop1 sta bucket,y
- iny
- bne loop1
- ;*** fill bucket
- ;ldy #0
- loop2 dey
- ldx $0400,y
- lda bucket,x
- sta liste2,y
- tya
- sta bucket,x
- bne loop2
- inc bucket,x
- stx mod2+1
- ;*** empty bucket
- ;ldy #0
- ldx #0
- jmp start
- mod1 lda liste2
- bne loop4
- start dex
- lda bucket,x
- beq start
- mod2 cpx #0
- bne loop4
- lda #0
- loop4 sta $0500,y
- sta mod1+1
- txa
- sta $0400,y
- iny
- bne mod1
- rts
Alles anzeigen
Hier ist eine Version, die das Prinzip meines eingereichten Beitrags deutlich macht:
Descending: 14877 cycles
Fixed Data: 15091 cycles (no duplicates)
Identical: 15127 cycles
Ascending: 15387 cycles
Random Data: 15407 cycles (average of 100 runs)
Fixed Data: 15442 cycles (with duplicates)
Jetzt muss man nur noch die Schleifen entrollen. Ich habe auch noch 64 mal den tya; sta bucket,x durch shy bucket,x ersetzt und 128 Zyklen gespart:
- processor 6502
- org $c000,0
- ;*** init
- bucket = $cf00
- liste2 = $ce00
- ;*** fill bucket
- ldy #0
- loop2 dey
- ldx $0400,y
- lda bucket,x
- beq *+5
- sta liste2,y
- tya
- sta bucket,x
- bne loop2
- lda #1
- sta bucket,x
- stx mod2+1
- ;*** empty bucket
- ldy #0
- ldx #0
- jmp start
- mod2 cpx #0
- beq sack
- loop4 sta $0500,y
- sta mod1+1
- txa
- sta $0400,y
- iny
- mod1 lda liste2
- bne loop4
- start
- dex
- lda bucket,x
- bne mod2
- dex
- lda bucket,x
- bne mod2
- dex
- lda bucket,x
- bne mod2
- dex
- lda bucket,x
- bne mod2
- jmp start
- sack lda #0
- jmp loop4b
- mod1b lda liste2
- bne loop4b
- dex
- lda bucket,x
- beq *-4
- loop4b sta $0500,y
- sta mod1b+1
- txa
- sta $0400,y
- iny
- bne mod1b
- rts
- org $cfff
- brk
Alles anzeigen
-
Ich habe es das ganze Wochenende probiert aber wahrscheinlich doch nicht geschafft, den Rekord von peiselulli zu knacken.
Mit normalen Mitteln lande ich bei der zufälligen Sortierung bei 13.7xx .
Ich habe jetzt eine Version eingereicht, die irgendwo im Bereich 13xxx liegt. Manchmal ist sie schneller und manchmal langsamer als die vorgegeben 13.500 Zyklen. Ich frage mich, was für ein Zufallszahlengenerator bei dem Testprogramm auf der Webseite verwendet wird. Nach 100 Durchläufen liegt der Durchschnitt mehrere Hundert Zylen auseinander.
Mein Programm verwendet einen reinen Bucketsort mit verketteten Listen. Das heißt, ich muss mühsam den Nullzeiger vom Element mit der Position 0 unterscheiden. Das könnte bei einem Countingsort vielleicht einfacher sein. Ich bin schon gespannt auf die anderen Programme.
Bei dreckiger Programmierung fällt mir noch etwas ein. Ich hätte beinahe den Befehl LAS bucket,y zusammen mit tsx, txs und pla, pha verwendet. Wäre das eigentlich erlaubt gewesen? Wie auch immer. Das hat es dann leider doch nicht gebracht. Schade, ich habe den Befehl LAS (opcode $BB) noch nie irgendwo sinnvoll in Verwendung gesehen.
-
Um Mafiosino zu motivieren (und damit ich nicht den nächsten Wettbewerb austragen muss
)
Danke peiselulli, jetzt bin ich tatsächlich motiviert 
Ich frage mich nur, wie ich noch 1000 cycles wegoptimieren soll? Aber ich habe ja noch Zeit. 
Ich gebe noch nicht auf, ich kann es noch schaffen zweiter zu werden (hinter Roland).
-
Ich hatte eigentlich schon abgegeben. Aber nach der Liste von Acorn muss ich noch mal ran, da seine Werte knapp besser als meine sind.
Danke Acorn. Ich hätte sonst nichts mehr gemacht.
Aber jetzt wird es wirklich schon sehr dreckig. Ich denke auch schon über illegal codes nach.
Villeicht motiviere ich noch jemanden mit meinen aktuellen Zahlen.
-
Ich habe nach den letzten Beiträgen doch noch zwei Fragen.
1.) Ich benutze eine Tabelle mit 256 Einträgen, die mit 0 initialisiert werden müssen. In den Regeln steht, dass das Programm 4 mal aufgerufen wird und dabei stabil laufen soll. Danach wird das Programm 100 mal neu geladen und mit anderen Werten 4 mal neu gestartet. Im Augenblick lösche ich die Tabelle mit einer unrolled loop und brauche daher ungefähr 4*256=1024 cycles. Ich könnte mir 1000 cycles sparen, wenn ich mein Programm um 4*256 0 Bytes erweitere, und bei jedem Start die Zeiger auf die Tabelle 256 Bytes verschiebe. Ist so etwas erlaubt?
2.) Ich finde, das Programm ist schwer zu testen. Die Anzahl der Zyklen kann ich mit dem Programm von peiselulli und auf der Webseite von ALeX checken. Kann ich davon ausgehen, dass die Webpage einen Fehler augibt, falls die Daten nicht korrekt sortiert sind?
Mein Programm braucht im Augenblick 16816 Zyklen bei den sortierten Listen und 16631 bei zufälligen Listen. Ich bin mir aber nicht sicher, ob es immer korrekt läuft.
-
Ich habe das Programm jetzt auf meinem Blech C128D getestet. Außer einem 20 read error 18 0 gleich am Anfang, weil die Diskette noch nie formatiert war, gab es keine Fehlermeldungen.