So, dann möchte ich hier auch mal etwas vorstellen, was für meinen Beitrag zu "BASIC-Weihnachten" entstanden ist. Ich hatte ja früh die Idee, "nette" Musik einzubinden und dazu einen möglichst minimalen SID-Player für BASIC zu schreiben (der wird später auch noch separat veröffentlicht). Problem war dann, obwohl der nicht allzu viel kann, war der Code doch für ein abzutippendes BASIC-Programm recht groß -- 64 Zeilen DATA-Wüste nur für den Player waren es beim ersten Versuch. Außerdem dauerte da natürlich auch der Start recht lange .. DATA/READ und POKE sind nicht gerade flott.
Also habe ich mir etwas überlegt, um das besser zu machen. Die Idee war schnell, dass in den BASIC Zeilen einfach direkt der MC-Code als hex steht. Leider pfuscht da der Tokenizer rein, die Sequenz "DEF" wird z.B. in ein Token übersetzt. Also mussten noch Anführungszeichen drumherum.
Das Ergebnis ist ein kleines (PC) Tool, das ein PRG mit dem Maschinencode nimmt und passenden BASIC-Source ausgibt, inklusive einer kleinen Laderoutine, die "klassisch" per DATA/POKE in den Datasettenpuffer geschrieben wird. Diese Routine liest dann die Hex-Strings und springt am Ende direkt zu dem geladenen Maschinencode (es wird erwartet, dass die Ladeadresse auch die Einsprungadresse ist).
Im Ergebnis wird das BASIC Programm ein gutes Stück kleiner als mit klassischem DATA/POKE und die Geschwindigkeit ist um ein Vielfaches besser. Falls man viele sich wiederholende Bytes hat wird das Abtippen schwieriger (Nullen zählen) -- das kann man dann aber elegant durch crunchen (z.B. mit exomizer) umgehen.
Source: Please login to see this link.
Da ist auch ein kleines README -- Aufruf z.B. mit basicload <mycode.prg >loader.bas.
Einen win32 build hänge ich mal an ![]()
Hier noch der kommentierte Source der Laderoutine:
.code
.word $0334 ; load address (datasette buffer)
ldx #$1 ; index for writing start address
stx $2 ; init marker for hi-/lo- nibble
lineloop: jsr $0073 ; get next character from BASIC
beq eol ; 0 -> end of BASIC line
hexloop: jsr $0073 ; next char
beq done ; 0 -> end of BASIC program
cmp #'"'
beq checkend ; another quote, check whether done
sbc #$30 ; subtract offset for '0'
cmp #$11
bcc digit ; if below 10, it was a decimal digit
sbc #$7 ; otherwise subtract diff '10' to 'A'
digit: lsr $2 ; check bit #0 of marker
bcc seconddigit ; not set -> second digit (lo nibble)
asl ; otherwise shift 4 bits
asl
asl
asl
sta $fb ; store to temporary
bcc hexloop ; and continue at next digit
seconddigit: ora $fb ; combine with hi nibble
sec
rol $2 ; shift a 1 back into bit #0
cpx #$3 ; start address already read?
bne setpointers ; if not, set pointers
write: sta $0101 ; store to dest (placeholder)
inc write+1 ; next address
bne hexloop ; and repeat
inc write+2 ; on overflow, also increment hi byte
bne hexloop
setpointers: sta done,x ; write pointer to start program
sta write,x ; write pointer to store program
inx ; next index
bne hexloop ; and repeat
checkend: jsr $0073 ; on '"', get next character
beq eol ; 0 -> end of BASIC line
done: jmp $af08 ; start our program (placeholder)
eol: ldy #$5 ; load first character of next
lda ($7a),y ; BASIC line
cmp #'"'
bne done ; if it's not '"', we're done loading
ldy #$2 ; check next BASIC line pointer
lda ($7a),y
beq done ; 0 -> end of BASIC program, so done
iny
lda ($7a),y ; copy next BASIC line number
sta $39 ; to ZP location where BASIC expects it
iny
lda ($7a),y
sta $3a
clc
tya
adc $7a ; move CHRGET pointer to start of
sta $7a ; next BASIC line
bcc lineloop ; and continue reading
inc $7b ; adjust hi-byte on carry
bne lineloop
Display More