Browse Source

added LOADER_C128 LOADER_C65 LOADER_C65_RS232

pull/5/head
Michael Steil 4 years ago
parent
commit
4e183ce75d
  1. 621
      LOADER_C128/loader.src
  2. 602
      LOADER_C65/loader65.src
  3. 611
      LOADER_C65_RS232/l232.src
  4. 7
      README.md
  5. 6
      build.sh

621
LOADER_C128/loader.src

@ -0,0 +1,621 @@
.nam C/128 HEX LOADER (06/20/86)
.forml 60
; MOS Technology HEX loader for C/128 by Fred Bowen
;
; April 2, 1986 original (beta) release
; June 20, 1986 modification: add 'program overwrite' error check (FAB)
; August 25, 1986 modification: add bank check to overwrite check (FAB)
;
; system equates
cursor_on = $cd6f ;EDITOR: turn cursor on
cursor_off = $cd9f ;EDITOR: turn cursor off
close_all = $ff4a ;KERNEL: close all open files
stash = $ff77 ;KERNEL: banked indirect store routine
primm = $ff7d ;KERNEL: print immediate utility
setbnk = $ff68 ;KERNEL: set file name bank
get_config = $ff6b ;KERNEL: translate memory config to MMU data
setlfs = $ffba ;KERNEL: set la, fa, sa
setnam = $ffbd ;KERNEL: set file name
open = $ffc0 ;KERNEL: open file
close = $ffc3 ;KERNEL: close file
chkin = $ffc6 ;KERNEL: open input channel
clrchn = $ffcc ;KERNEL: close channel
basin = $ffcf ;KERNEL: input character
bsout = $ffd2 ;KERNEL: output character
stop = $ffe1 ;KERNEL: test for stop key
getin = $ffe4 ;KERNEL: input character (keyboard)
clall = $ffe7 ;KERNEL: init file tables & restore default chnls
mmucr = $ff00 ;I/O: memory configuration register
config = $00 ; system ROMs, I/O, RAM-0
; system variables
status = $90 ;I/O status byte
stash_vector = $2b9 ;pointer for banked memory store subroutine
*=$59 ;use BASIC's domain
load_address *=*+2 ;load address (2 bytes, low/high)
load_offset *=*+2 ;load offset (3 bytes, low/high/bank)
bank *=*+1 ;bank destination for load (0-15)
record_count *=*+2 ;input record count
checksum *=*+2 ;record checksum
next_address *=*+2 ;expected next address for contiguity
first *=*+1 ;flags first record
last_index *=*+1 ;last index from previous record
count *=*+1 ;temporary (number of data bytes per record)
index *=*+1 ;temporary (index from record sa to store byte)
temp *=*+1 ;temporary
disk *=*+1 ;la/fa/sa used for disk I/O
stack_ptr *=*+1 ;save for good return to call
*=$200 ;input buffer
buffer *=*+20 ;filename buffer
.page
; constants
break_key = $03 ;stop key character
bell = $07 ;bell character
cr = $0d ;carriage return
return = cr
rvs = $12 ;reverse field character
delete = $14 ;delete character
esc = $1b ;escape character
space = $20 ;space character
comma = $2c ;comma character
rvs_off = $92 ;reverse field off character
bs = $9d ;backspace character (cursor left)
.page
* = $1300 ;loader origin
start lda #config
sta mmucr ;configure memory
jsr clall ;clear all channels
sei
ldx #load_address
ldy #0
5$ lda $00,x ;save BASIC zero page
sta end,y
iny
inx
cpx #stack_ptr+1
bcc 5$
tsx
stx stack_ptr ;save for clean return
cli
jsr primm
.byte cr,'C/128 HEX LOADER V082586'
.byte cr,'(C)1986 BY COMMODORE BUSINESS MACHINES',cr,cr,0
jsr primm
.byte cr,'OBJECT FILE ([UNIT#,][DRIVE:]FILENAME) ? ',esc,'Q',0
.page
ldx #20 ;16 char name + 4 char (8,0:) = 20 total
stx count ;save maximum input character count
jsr cursor_on ;turn on cursor
ldx #0 ;read characters from keyboard until <cr>
10$ stx temp ;save buffer pointer
jsr get_key ;get a character from keyboard
ldx temp ;restore buffer pointer
tay ;save character
and #$7f ;mask to 7-bits
cmp #return
beq 40$ ;...branch if <cr>
cmp #delete
bne 20$ ;...branch if not <delete>
cpx #0 ;check buffer pointer
beq 25$ ;...branch if at start of line (ignore <delete>)
dex ;decrement buffer pointer
bpl 30$ ;...branch always (print <delete>)
20$ cmp #space
bcc 25$ ;...branch if control code (ignore)
tya ;restore character
sta buffer,x ;put character into buffer
inx ;increment buffer pointer
cpx count ;check buffer pointer
bcc 30$ ;...branch if not a end of line
dex ;at end of line (ignore everything but <cr> and <delete>)
25$ lda #bell ;substitute <bell> to warn user
30$ jsr bsout ;print the character
jmp 10$ ;loop for next character
40$ jsr cursor_off ;turn off cursor
ldx temp ;character input count
bne 50$ ;...branch if name given (not null)
jmp done ;exit to BASIC
50$ stx count ;save filename length
jsr primm
.byte cr,'LOAD ADDRESS ([BANK][4 HEX DIGIT ADDR]) ? ',esc,'Q',0
jsr cursor_on ;turn on cursor
ldx #0 ;read characters from keyboard until <cr>
stx load_offset ;init offset value
stx load_offset+1
stx load_offset+2
60$ stx temp ;save digit counter
jsr get_key ;get a character from keyboard
ldx temp
sta last_index ;save character (to print later)
and #$7f ;mask to 7-bits
cmp #return
beq 90$ ;...branch if <cr>
cmp #delete
bne 70$ ;...branch if not <delete>
cpx #0 ;check digit counter
beq 76$ ;...branch if at start of line (ignore <delete>)
dex ;decrement digit counter
ldy #4
65$ lsr load_offset+2 ;shift entire value right one nibble
ror load_offset+1
ror load_offset
dey
bne 65$
beq 80$ ;...branch always (print <delete>)
70$ cpx #5
bcs 76$ ;...branch if 5 digits already input (ignore)
cmp #'0'
bcc 76$ ;...branch if control code (ignore)
cmp #':'
bcc 71$ ;...branch if in range (0-9)
cmp #'A'
bcc 76$ ;...branch if >9 and <A (ignore)
cmp #'F'+1
bcs 76$ ;...branch if >F (ignore)
sbc #7 ;adjust if in range (A-F)
71$ sbc #47 ;adjust to (0-15)
asl a ;shift low nibble to high
asl a
asl a
asl a
ldy #4 ;multiply previous value by 16, then add new digit
75$ asl a
rol load_offset ;low
rol load_offset+1 ;high
rol load_offset+2 ;bank
dey
bne 75$
inx ;increment digit counter
lda last_index ;recall digit and print it
.byte $2c ;skip next instruction
76$ lda #bell ;substitute <bell> to warn user
80$ jsr bsout ;print the character
jmp 60$ ;loop for next character
90$ ldx temp
stx first ;flags null input vs. $0000 for offset calculations
jsr bsout ;print <cr>
jsr cursor_off ;turn off cursor
.page
; open object file
open_file
ldx #8
stx disk ;default disk unit
ldx #0 ;parse filename (look for [unit,])
stx temp ;init
1$ lda buffer,x
cmp #'9'+1 ;numeric?
bcs 5$ ;...no
cmp #'0'
bcc 5$ ;...no
sbc #'0' ;convert ascii to binary
sta index ;save digit
lda temp ;convert binary to decimal
asl a
bcs 9$
ldy #3
2$ asl temp ;3 shifts (8) + 1 shift (2) -> x10
bcs 9$
dey
bne 2$
adc temp
bcs 9$
adc index ;add current digit
sta temp
bcs 9$
inx
cpx count
bne 1$ ;...loop until done or EOL
beq 9$
3$ jmp error5 ;bad unit# or filename
5$ cmp #',' ;found non-numeric
bne 9$ ;...not <comma>, must not be a unit #
lda temp ;...got <comma>, use as unit #
sta disk
inx
ldy #0 ;squish unit# from buffer
6$ cpx count
beq 7$
lda buffer,x
sta buffer,y
iny
inx
bne 6$
7$ sty count
9$ ldx count
lda #',' ;append ',S' to filename
sta buffer,x
inx
lda #'S'
sta buffer,x
inx
stx count
lda disk ;la
cmp #31
bcs 3$
cmp #8
bcc 3$
tay ;sa
tax ;fa
jsr setlfs
lda count ;fnlen
ldx #<buffer ;fnadr
ldy #>buffer
jsr setnam
ldx #0
jsr setbnk ;fnbank (RAM-0)
jsr open ;open object file
bcc 20$ ;...branch if open successful
10$ jmp error0 ;else report disk error
.page
; begin actual load
20$ lda #0
sta last_index ;init previous record index
sta next_address+1 ;init for contiguity check
sta record_count ;init record count
sta record_count+1
lda #load_address
sta stash_vector ;set pointer for banked memory stores
ldx disk ;set channel
jsr chkin
bcs 10$ ;...branch on disk error
next_record
jsr stop
bne 10$ ;...branch if no STOP key
jmp error3 ;...else BREAK
10$ jsr get_character
cmp #';' ;record initiator?
bne next_record ;no...keep looking
lda #0
sta checksum ;reset record checksum
sta checksum+1
sta index ;reset memory index pointer
jsr get_byte ;read record's byte count
bne 30$ ;...branch if not last record (not null)
jsr get_byte ;check record count
cmp record_count+1
bne 20$ ;...branch if sums do not match- error
jsr get_byte
cmp record_count
bne 20$
jmp done ;exit to BASIC, all done correctly
20$ jmp error4 ;...branch if mismatch (missing record)
30$ sta count ;save record's byte count
jsr add_checksum ;add byte count to checksum
inc record_count ;increment record count
bne 40$
inc record_count+1
40$ lda first
beq 44$ ;...branch if not first record (or null sa given)
jsr offset_calc ;else read first address & calculate offset
jmp 50$
44$ jsr get_byte ;get record's starting address (high)
pha
jsr add_checksum ;add to checksum
pla
clc
adc load_offset+1 ;add user offset (high) to starting address
sta load_address+1
jsr get_byte ;get low address
pha
jsr add_checksum ;add to checksum
pla
clc
adc load_offset ;add user offset (low) to starting address
sta load_address
bcc 50$
inc load_address+1 ;add any carry to high byte
50$ jsr check_address ;check for program overwrite
lda load_address ;check contiguity
cmp next_address
bne 55$ ;...branch if beginning new block
lda load_address+1
cmp next_address+1
beq 60$
55$ lda #cr ;display starting address of new block
jsr bsout
jsr display_address ;write load address
jsr primm
.byte ' -> ',0 ;position cursor for ending address
60$ jsr get_byte ;get data byte
ldy index ;get current memory index
sty last_index ;save it for last address check
inc index ;increment it for next memory index
ldx bank ;get bank for memory store
sei ;disable interrupts for non-system banks
jsr stash ;store data byte--> sta (load_address),y
cli
jsr add_checksum ;add byte to checksum
dec count ;decrement record byte count
bne 60$ ;...loop until done all bytes for this record
jsr get_byte ;get record checksum (high)
cmp checksum+1 ;compare with calculated checksum
bne 65$ ;...branch if checksum error
jsr get_byte ;get record checksum (low)
cmp checksum ;compare with calculated checksum
65$ php ;save result- checksum error is non-fatal
clc
lda last_index ;add last index to last record index for last address
adc load_address
tay
lda load_address+1
adc #0
tax
jsr display_byte ;print the record ending address
tya
jsr display_byte
iny
sty next_address ;save for determining contiguity
bne 70$
inx
70$ stx next_address+1
plp ;check for non-fatal errors
bne error2
jsr primm
.byte bs,bs,bs,bs,0 ;format next for overwrite
jmp next_record ;continue with next record
.page
error0 jsr primm
.byte bell,cr,rvs,'DISK ERROR',rvs_off,' ',0
jsr clrchn
lda #0
jsr setnam
ldx disk
ldy #15 ;prepare to read disk command channel
jsr setlfs
jsr open
bcs error1 ;??? must be device not present
ldx #0
jsr chkin
bcs 20$
10$ jsr basin ;input error message from disk
jsr bsout ;print it
cmp #cr
beq 20$
lda status
and #$bf
beq 10$ ;loop until EOL or error
20$ jmp done
error1 jsr primm
.byte bell,cr,rvs,'DEVICE NOT PRESENT',cr,0
jmp done
error2 jsr primm
.byte bell,' ',rvs,'CHECKSUM ERROR',0
dec next_address
jmp next_record ;fake non-contiguous block by trashing next_address
error3 jsr primm
.byte bell,cr,rvs,'BREAK',cr,0
jmp done
error4 jsr primm
.byte bell,cr,rvs,'RECORD COUNT BAD',cr,0
jmp done
error5 jsr primm
.byte bell,cr,rvs,'INVALID DEVICE SPECIFIED',cr,0
jmp done
error6 jsr primm
.byte bell,cr,rvs,'PROGRAM OVERWRITE',cr,0
; jmp done
done jsr clrchn ;finished with load
lda disk
jsr close_all ;close disk channel
sei
ldx stack_ptr
txs
ldx #load_address ;restore zero page
ldy #0
10$ lda end,y
sta $00,x
iny
inx
cpx #stack_ptr
bcc 10$
cli
rts ;return to caller
.page
get_key
jsr getin ;loop until keypress
beq get_key
cmp #break_key
bne 10$
jmp error3 ;exit if STOP key
10$ rts
get_character
lda #0
sta status ;clean slate
jsr basin ;get next character from channel
bcs 10$ ;...branch if I/O error
pha
lda status
and #%10111111 ;mask EOI bit
bne 10$ ;...branch if I/O error
pla
rts
10$ jmp error0 ;...report disk error and exit
add_checksum
clc ;add current byte to record checksum
adc checksum
sta checksum
bcc 10$
inc checksum+1
10$ rts
offset_calc
jsr get_byte ;get first record's starting address (high)
sta load_address+1
jsr add_checksum ;add to checksum
jsr get_byte ;get low address
sta load_address
jsr add_checksum ;add to checksum
sec
lda load_offset ;calculate offset= alt_adr - rec_adr
pha ;save sa
sbc load_address
sta load_offset
lda load_offset+1
pha ;save sa
sbc load_address+1
sta load_offset+1
pla ;pop first load address (original load_offset)
sta load_address+1
pla
sta load_address
lda #0
sta first ;squash first record flag
rts
check_address
ldx bank ;check for record overwrite of program
jsr get_config
and #$c0
bne 20$ ;it's okay: bank is not same
lda load_address+1
jsr 10$ ;check record starting address
ldy count
dey
tya
clc ;calculate address of last byte of record
adc load_address
lda load_address+1 ;(only concerned with high bytes...)
adc #0 ;(fall into subroutine)
10$ cmp #>start ;beginning of this program
bcc 20$ ;...branch if below program- ok
cmp #>end+1 ;end of this program
bcs 20$ ;...branch if above program- ok
jmp error6 ;...error- loading this record would overwrite!
20$ rts
.page
; read ascii hex byte and return binary in .a
get_byte
lda #0 ;space
sta temp
jsr get_character ;get most significant digit
jsr get_binary ;convert to binary
asl a ;shift to most significant nibble
asl a
asl a
asl a
sta temp ;save it
jsr get_character ;get least significant digit
jsr get_binary ;convert to binary
ora temp ;merge nibbles
rts
get_binary
cmp #':' ;convert ascii hex digit to binary
php
and #$0f ;mask it
plp
bcc 10$ ;...branch if it was numeric (0-9)
adc #8 ;else in range (A-F), add 9 (assumes .c=1)
10$ rts
; write address
display_address
lda load_address+1 ;print current address, high/low
jsr display_byte ;print high byte
lda load_address ;print low byte (fall into display_byte)
display_byte
pha ;save byte to unpack
lsr a ;most significant nibble
lsr a
lsr a
lsr a
jsr display_digit ;convert binary to ascii & print it
pla
and #$0f ;least significant nibble (fall into display_digit)
display_digit
clc ;convert binary nibble to ascii
adc #$f6
bcc 10$
adc #$06
10$ adc #$3a
jmp bsout ;print it and RTS
end
.end

602
LOADER_C65/loader65.src

@ -0,0 +1,602 @@
.nam C/65 HEX LOADER (03/20/90)
.forml 60
; MOS Technology HEX loader for the C/65 by Fred Bowen
;
; April 2, 1986 original (beta) release
; June 20, 1986 modification: add 'program overwrite' error check (FAB)
; August 25, 1986 modification: add bank check to overwrite check (FAB)
; March 20, 1990 conversion to C65 (ver 900214) (FAB)
;
; system equates
cursor = $e030 ;EDITOR: turn cursor on/off (.c)
close_all = $ff50 ;KERNEL: close all open files
stash = $ff77 ;KERNEL: banked indirect store routine
primm = $ff7d ;KERNEL: print immediate utility
setbnk = $ff6b ;KERNEL: set file name bank
setlfs = $ffba ;KERNEL: set la, fa, sa
setnam = $ffbd ;KERNEL: set file name
open = $ffc0 ;KERNEL: open file
close = $ffc3 ;KERNEL: close file
chkin = $ffc6 ;KERNEL: open input channel
clrchn = $ffcc ;KERNEL: close channel
basin = $ffcf ;KERNEL: input character
bsout = $ffd2 ;KERNEL: output character
stop = $ffe1 ;KERNEL: test for stop key
getin = $ffe4 ;KERNEL: input character (keyboard)
clall = $ffe7 ;KERNEL: init file tables & restore default chnls
;mmucr = $ff00 ;I/O: memory configuration register
;config = $00 ; system ROMs, I/O, RAM-0
; system variables
status = $90 ;I/O status byte
*=$59 ;use BASIC's domain
load_address *=*+2 ;load address (2 bytes, low/high)
load_offset *=*+2 ;load offset (3 bytes, low/high/bank)
bank *=*+1 ;bank destination for load (0-15)
record_count *=*+2 ;input record count
checksum *=*+2 ;record checksum
next_address *=*+2 ;expected next address for contiguity
first *=*+1 ;flags first record
last_index *=*+1 ;last index from previous record
count *=*+1 ;temporary (number of data bytes per record)
index *=*+1 ;temporary (index from record sa to store byte)
temp *=*+1 ;temporary
disk *=*+1 ;la/fa/sa used for disk I/O
stack_ptr *=*+1 ;save for good return to call
*=$200 ;input buffer
buffer *=*+20 ;filename buffer
.page
; constants
break_key = $03 ;stop key character
bell = $07 ;bell character
cr = $0d ;carriage return
return = cr
rvs = $12 ;reverse field character
delete = $14 ;delete character
esc = $1b ;escape character
space = $20 ;space character
comma = $2c ;comma character
rvs_off = $92 ;reverse field off character
bs = $9d ;backspace character (cursor left)
.page
* = $1300 ;loader origin
start jsr clall ;clear all channels
sei
ldx #load_address
ldy #0
5$ lda $00,x ;save BASIC zero page
sta end,y
iny
inx
cpx #stack_ptr+1
bcc 5$
tsx
stx stack_ptr ;save for clean return
cli
jsr primm
.byte cr,'C/65 HEX LOADER V032090'
.byte cr,'(C)1990 BY COMMODORE BUSINESS MACHINES',cr,0
jsr primm
.byte cr,'OBJECT FILE ([UNIT#,][DRIVE:]FILENAME) ? ',esc,'Q',0
.page
ldx #20 ;16 char name + 4 char (8,0:) = 20 total
stx count ;save maximum input character count
ldx #0 ;read characters from keyboard until <cr>
10$ stx temp ;save buffer pointer
jsr get_key ;get a character from keyboard
ldx temp ;restore buffer pointer
tay ;save character
and #$7f ;mask to 7-bits
cmp #return
beq 40$ ;...branch if <cr>
cmp #delete
bne 20$ ;...branch if not <delete>
cpx #0 ;check buffer pointer
beq 25$ ;...branch if at start of line (ignore <delete>)
dex ;decrement buffer pointer
bpl 30$ ;...branch always (print <delete>)
20$ cmp #space
bcc 25$ ;...branch if control code (ignore)
tya ;restore character
sta buffer,x ;put character into buffer
inx ;increment buffer pointer
cpx count ;check buffer pointer
bcc 30$ ;...branch if not a end of line
dex ;at end of line (ignore everything but <cr> and <delete>)
25$ lda #bell ;substitute <bell> to warn user
30$ jsr bsout ;print the character
bra 10$ ;loop for next character
40$ ldx temp ;character input count
beq done ;...null input, exit to BASIC
50$ stx count ;save filename length
jsr primm
.byte cr,'LOAD ADDRESS ([BANK][4 HEX DIGIT ADDR]) ? ',esc,'Q',0
ldx #0 ;read characters from keyboard until <cr>
stx load_offset ;init offset value
stx load_offset+1
stx load_offset+2
60$ stx temp ;save digit counter
jsr get_key ;get a character from keyboard
ldx temp
sta last_index ;save character (to print later)
and #$7f ;mask to 7-bits
cmp #return
beq 90$ ;...branch if <cr>
cmp #delete
bne 70$ ;...branch if not <delete>
cpx #0 ;check digit counter
beq 76$ ;...branch if at start of line (ignore <delete>)
dex ;decrement digit counter
ldy #4
65$ lsr load_offset+2 ;shift entire value right one nibble
ror load_offset+1
ror load_offset
dey
bne 65$
beq 80$ ;...branch always (print <delete>)
70$ cpx #5
bcs 76$ ;...branch if 5 digits already input (ignore)
cmp #'0'
bcc 76$ ;...branch if control code (ignore)
cmp #':'
bcc 71$ ;...branch if in range (0-9)
cmp #'A'
bcc 76$ ;...branch if >9 and <A (ignore)
cmp #'F'+1
bcs 76$ ;...branch if >F (ignore)
sbc #7 ;adjust if in range (A-F)
71$ sbc #47 ;adjust to (0-15)
asl a ;shift low nibble to high
asl a
asl a
asl a
ldy #4 ;multiply previous value by 16, then add new digit
75$ asl a
rol load_offset ;low
rol load_offset+1 ;high
rol load_offset+2 ;bank
dey
bne 75$
inx ;increment digit counter
lda last_index ;recall digit and print it
.byte $2c ;skip next instruction
76$ lda #bell ;substitute <bell> to warn user
80$ jsr bsout ;print the character
bra 60$ ;loop for next character
90$ ldx temp
stx first ;flags null input vs. $0000 for offset calculations
jsr bsout ;print <cr>
.page
; open object file
open_file
ldx #8
stx disk ;default disk unit
ldx #0 ;parse filename (look for [unit,])
stx temp ;init
1$ lda buffer,x
cmp #'9'+1 ;numeric?
bcs 5$ ;...no
cmp #'0'
bcc 5$ ;...no
sbc #'0' ;convert ascii to binary
sta index ;save digit
lda temp ;convert binary to decimal
asl a
bcs 9$
ldy #3
2$ asl temp ;3 shifts (8) + 1 shift (2) -> x10
bcs 9$
dey
bne 2$
adc temp
bcs 9$
adc index ;add current digit
sta temp
bcs 9$
inx
cpx count
bne 1$ ;...loop until done or EOL
beq 9$
5$ cmp #',' ;found non-numeric
bne 9$ ;...not <comma>, must not be a unit #
lda temp ;...got <comma>, use as unit #
sta disk
inx
ldy #0 ;squish unit# from buffer
6$ cpx count
beq 7$
lda buffer,x
sta buffer,y
iny
inx
bne 6$
7$ sty count
9$ ldx count
lda #',' ;append ',S' to filename
sta buffer,x
inx
lda #'S'
sta buffer,x
inx
stx count
lda disk ;la
cmp #31
bcs error5 ;bad unit #
cmp #8
bcc error5 ;bad unit #
tay ;sa
tax ;fa
jsr setlfs
lda count ;fnlen
ldx #<buffer ;fnadr
ldy #>buffer
jsr setnam
ldx #0
jsr setbnk ;fnbank (RAM-0)
jsr open ;open object file
bcs error0 ;...report disk error
.page
; begin actual load
20$ lda #0
sta last_index ;init previous record index
sta next_address+1 ;init for contiguity check
sta record_count ;init record count
sta record_count+1
ldx disk ;set channel
jsr chkin
bcs error0 ;...branch on disk error
next_record
jsr stop
beq error3 ;...branch if STOP key- BREAK
10$ jsr get_character
cmp #';' ;record initiator?
bne next_record ;no...keep looking
lda #0
sta checksum ;reset record checksum
sta checksum+1
sta index ;reset memory index pointer
jsr get_byte ;read record's byte count
bne 30$ ;...branch if not last record (not null)
jsr get_byte ;check record count
cmp record_count+1
bne error4 ;...branch if sums do not match- error
jsr get_byte
cmp record_count
bne error4 ;...branch if mismatch (missing record)
bra done ;exit to BASIC, all done correctly
30$ sta count ;save record's byte count
jsr add_checksum ;add byte count to checksum
inw record_count ;increment record count
40$ lda first
beq 44$ ;...branch if not first record (or null sa given)
jsr offset_calc ;else read first address & calculate offset
bra 50$
44$ jsr get_byte ;get record's starting address (high)
pha
jsr add_checksum ;add to checksum
pla
clc
adc load_offset+1 ;add user offset (high) to starting address
sta load_address+1
jsr get_byte ;get low address
pha
jsr add_checksum ;add to checksum
pla
clc
adc load_offset ;add user offset (low) to starting address
sta load_address
bcc 50$
inc load_address+1 ;add any carry to high byte
50$ jsr check_address ;check for program overwrite
lda load_address ;check contiguity
cmp next_address
bne 55$ ;...branch if beginning new block
lda load_address+1
cmp next_address+1
beq 60$
55$ lda #cr ;display starting address of new block
jsr bsout
jsr display_address ;write load address
jsr primm
.byte ' -> ',0 ;position cursor for ending address
60$ jsr get_byte ;get data byte
ldy index ;get current memory index
sty last_index ;save it for last address check
inc index ;increment it for next memory index
ldz bank ;get bank for memory store
ldx #load_address
jsr stash ;store data byte--> sta (load_address),y
jsr add_checksum ;add byte to checksum
dec count ;decrement record byte count
bne 60$ ;...loop until done all bytes for this record
jsr get_byte ;get record checksum (high)
cmp checksum+1 ;compare with calculated checksum
bne 65$ ;...branch if checksum error
jsr get_byte ;get record checksum (low)
cmp checksum ;compare with calculated checksum
65$ php ;save result- checksum error is non-fatal
clc
lda last_index ;add last index to last record index for last address
adc load_address
tay
lda load_address+1
adc #0
tax
jsr display_byte ;print the record ending address
tya
jsr display_byte
iny
sty next_address ;save for determining contiguity
bne 70$
inx
70$ stx next_address+1
plp ;check for non-fatal errors
bne error2
jsr primm
.byte bs,bs,bs,bs,0 ;format next for overwrite
bra next_record ;continue with next record
.page
error0 jsr primm
.byte bell,cr,rvs,'DISK ERROR',rvs_off,' ',0
jsr clrchn
lda #0
jsr setnam
ldx disk
ldy #15 ;prepare to read disk command channel
jsr setlfs
jsr open
bcs error1 ;??? must be device not present
ldx #0
jsr chkin
bcs 20$
10$ jsr basin ;input error message from disk
jsr bsout ;print it
cmp #cr
beq 20$
lda status
and #$bf
beq 10$ ;loop until EOL or error
20$ bra done
error1 jsr primm
.byte bell,cr,rvs,'DEVICE NOT PRESENT',cr,0
bra done
error2 jsr primm
.byte bell,' ',rvs,'CHECKSUM ERROR',0
dec next_address
bra next_record ;fake non-contiguous block by trashing next_address
error3 jsr primm
.byte bell,cr,rvs,'BREAK',cr,0
bra done
error4 jsr primm
.byte bell,cr,rvs,'RECORD COUNT BAD',cr,0
bra done
error5 jsr primm
.byte bell,cr,rvs,'INVALID DEVICE SPECIFIED',cr,0
bra done
error6 jsr primm
.byte bell,cr,rvs,'PROGRAM OVERWRITE',cr,0
; jmp done
done jsr clrchn ;finished with load
lda disk
jsr close_all ;close disk channel
sei
ldx stack_ptr
txs
ldx #load_address ;restore zero page
ldy #0
10$ lda end,y
sta $00,x
iny
inx
cpx #stack_ptr
bcc 10$
cli
rts ;return to caller
.page
get_key
clc
jsr cursor ;turn on cursor
10$ jsr getin ;loop until keypress
beq 10$
pha
sec
jsr cursor ;turn off cursor
pla
cmp #break_key
beq error3 ;exit if STOP key
rts
get_character
lda #0
sta status ;clean slate
jsr basin ;get next character from channel
bcs error0 ;...branch if I/O error
pha
lda status
and #%10111111 ;mask EOI bit
bne error0 ;...branch if I/O error
pla
rts
add_checksum
clc ;add current byte to record checksum
adc checksum
sta checksum
bcc 10$
inc checksum+1
10$ rts
offset_calc
jsr get_byte ;get first record's starting address (high)
sta load_address+1
jsr add_checksum ;add to checksum
jsr get_byte ;get low address
sta load_address
jsr add_checksum ;add to checksum
sec
lda load_offset ;calculate offset= alt_adr - rec_adr
pha ;save sa
sbc load_address
sta load_offset
lda load_offset+1
pha ;save sa
sbc load_address+1
sta load_offset+1
pla ;pop first load address (original load_offset)
sta load_address+1
pla
sta load_address
lda #0
sta first ;squash first record flag
rts
check_address
ldx bank ;check for record overwrite of program
bne 20$ ;it's okay: bank is not same
lda load_address+1
jsr 10$ ;check record starting address
ldy count
dey
tya
clc ;calculate address of last byte of record
adc load_address
lda load_address+1 ;(only concerned with high bytes...)
adc #0 ;(fall into subroutine)
10$ cmp #>start ;beginning of this program
bcc 20$ ;...branch if below program- ok
cmp #>end+1 ;end of this program
bcc error6 ;...error- loading this record would overwrite!
20$ rts
.page
; read ASCII hex byte and return binary in .a
get_byte
lda #0 ;space
sta temp
jsr get_character ;get most significant digit
jsr get_binary ;convert to binary
asl a ;shift to most significant nibble
asl a
asl a
asl a
sta temp ;save it
jsr get_character ;get least significant digit
jsr get_binary ;convert to binary
ora temp ;merge nibbles
rts
get_binary
cmp #':' ;convert ascii hex digit to binary
php
and #$0f ;mask it
plp
bcc 10$ ;...branch if it was numeric (0-9)
adc #8 ;else in range (A-F), add 9 (assumes .c=1)
10$ rts
; write address
display_address
lda load_address+1 ;print current address, high/low
jsr display_byte ;print high byte
lda load_address ;print low byte (fall into display_byte)
display_byte
pha ;save byte to unpack
lsr a ;most significant nibble
lsr a
lsr a
lsr a
jsr display_digit ;convert binary to ascii & print it
pla
and #$0f ;least significant nibble (fall into display_digit)
display_digit
clc ;convert binary nibble to ascii
adc #$f6
bcc 10$
adc #$06
10$ adc #$3a
jmp bsout ;print it and RTS
end
.end

611
LOADER_C65_RS232/l232.src

@ -0,0 +1,611 @@
.nam C/65 HEX LOADER (03/20/90)
.forml 60
; MOS Technology HEX loader for the C/65 by Fred Bowen
;
; April 2, 1986 original (beta) release
; June 20, 1986 modification: add 'program overwrite' error check (FAB)
; August 25, 1986 modification: add bank check to overwrite check (FAB)
; March 20, 1990 conversion to C65 (ver 900214) (FAB)
;
; system equates
cursor = $e030 ;EDITOR: turn cursor on/off (.c)
close_all = $ff50 ;KERNEL: close all open files
stash = $ff77 ;KERNEL: banked indirect store routine
primm = $ff7d ;KERNEL: print immediate utility
setbnk = $ff6b ;KERNEL: set file name bank
setlfs = $ffba ;KERNEL: set la, fa, sa
setnam = $ffbd ;KERNEL: set file name
open = $ffc0 ;KERNEL: open file
close = $ffc3 ;KERNEL: close file
chkin = $ffc6 ;KERNEL: open input channel
clrchn = $ffcc ;KERNEL: close channel
basin = $ffcf ;KERNEL: input character
bsout = $ffd2 ;KERNEL: output character
stop = $ffe1 ;KERNEL: test for stop key
getin = $ffe4 ;KERNEL: input character (keyboard)
clall = $ffe7 ;KERNEL: init file tables & restore default chnls
;mmucr = $ff00 ;I/O: memory configuration register
;config = $00 ; system ROMs, I/O, RAM-0
; system variables
status = $90 ;I/O status byte
*=$59 ;use BASIC's domain
load_address *=*+2 ;load address (2 bytes, low/high)
load_offset *=*+2 ;load offset (3 bytes, low/high/bank)
bank *=*+1 ;bank destination for load (0-15)
record_count *=*+2 ;input record count
checksum *=*+2 ;record checksum
next_address *=*+2 ;expected next address for contiguity
first *=*+1 ;flags first record
last_index *=*+1 ;last index from previous record
count *=*+1 ;temporary (number of data bytes per record)
index *=*+1 ;temporary (index from record sa to store byte)
temp *=*+1 ;temporary
disk *=*+1 ;la/fa/sa used for disk I/O
stack_ptr *=*+1 ;save for good return to call
*=$200 ;input buffer
buffer *=*+20 ;filename buffer
.page
; constants
break_key = $03 ;stop key character
bell = $07 ;bell character
cr = $0d ;carriage return
return = cr
rvs = $12 ;reverse field character
delete = $14 ;delete character
esc = $1b ;escape character
space = $20 ;space character
comma = $2c ;comma character
rvs_off = $92 ;reverse field off character
bs = $9d ;backspace character (cursor left)
.page
* = $c400 ;loader origin
start jsr clall ;clear all channels
; sei
; ldx #load_address
; ldy #0
;5$ lda $00,x ;save BASIC zero page
; sta end,y
; iny
; inx
; cpx #stack_ptr+1
; bcc 5$
tsx
stx stack_ptr ;save for clean return
; cli
jsr primm
.byte cr,'C/65 HEX LOADER V032090'
.byte cr,'(C)1990 BY COMMODORE BUSINESS MACHINES',cr,0
; jsr primm
; .byte cr,'OBJECT FILE ([UNIT#,][DRIVE:]FILENAME) ? ',esc,'Q',0
; .page
; ldx #20 ;16 char name + 4 char (8,0:) = 20 total
; stx count ;save maximum input character count
; ldx #0 ;read characters from keyboard until <cr>
;
;10$ stx temp ;save buffer pointer
; jsr get_key ;get a character from keyboard
; ldx temp ;restore buffer pointer
; tay ;save character
; and #$7f ;mask to 7-bits
; cmp #return
; beq 40$ ;...branch if <cr>
; cmp #delete
; bne 20$ ;...branch if not <delete>
; cpx #0 ;check buffer pointer
; beq 25$ ;...branch if at start of line (ignore <delete>)
;
; dex ;decrement buffer pointer
; bpl 30$ ;...branch always (print <delete>)
;
;20$ cmp #space
; bcc 25$ ;...branch if control code (ignore)
; tya ;restore character
; sta buffer,x ;put character into buffer
; inx ;increment buffer pointer
; cpx count ;check buffer pointer
; bcc 30$ ;...branch if not a end of line
;
; dex ;at end of line (ignore everything but <cr> and <delete>)
;25$ lda #bell ;substitute <bell> to warn user
;
;30$ jsr bsout ;print the character
; bra 10$ ;loop for next character
;
;40$ ldx temp ;character input count
; beq done ;...null input, exit to BASIC
;
;50$ stx count ;save filename length
jsr primm
.byte cr,'LOAD ADDRESS ([BANK][4 HEX DIGIT ADDR]) ? ',esc,'Q',0
ldx #0 ;read characters from keyboard until <cr>
stx load_offset ;init offset value
stx load_offset+1
stx load_offset+2
60$ stx temp ;save digit counter
jsr get_key ;get a character from keyboard
ldx temp
sta last_index ;save character (to print later)
and #$7f ;mask to 7-bits
cmp #return
beq 90$ ;...branch if <cr>
cmp #delete
bne 70$ ;...branch if not <delete>
cpx #0 ;check digit counter
beq 76$ ;...branch if at start of line (ignore <delete>)
dex ;decrement digit counter
ldy #4
65$ lsr load_offset+2 ;shift entire value right one nibble
ror load_offset+1
ror load_offset
dey
bne 65$
beq 80$ ;...branch always (print <delete>)
70$ cpx #5
bcs 76$ ;...branch if 5 digits already input (ignore)
cmp #'0'
bcc 76$ ;...branch if control code (ignore)
cmp #':'
bcc 71$ ;...branch if in range (0-9)
cmp #'A'
bcc 76$ ;...branch if >9 and <A (ignore)
cmp #'F'+1
bcs 76$ ;...branch if >F (ignore)
sbc #7 ;adjust if in range (A-F)
71$ sbc #47 ;adjust to (0-15)
asl a ;shift low nibble to high
asl a
asl a
asl a
ldy #4 ;multiply previous value by 16, then add new digit
75$ asl a
rol load_offset ;low
rol load_offset+1 ;high
rol load_offset+2 ;bank
dey
bne 75$
inx ;increment digit counter
lda last_index ;recall digit and print it
.byte $2c ;skip next instruction
76$ lda #bell ;substitute <bell> to warn user
80$ jsr bsout ;print the character
bra 60$ ;loop for next character
90$ ldx temp
stx first ;flags null input vs. $0000 for offset calculations
jsr bsout ;print <cr>
.page
; open object file
open_file
; ldx #8
; stx disk ;default disk unit
;
; ldx #0 ;parse filename (look for [unit,])
; stx temp ;init
;1$ lda buffer,x
; cmp #'9'+1 ;numeric?
; bcs 5$ ;...no
; cmp #'0'
; bcc 5$ ;...no
; sbc #'0' ;convert ascii to binary
; sta index ;save digit
; lda temp ;convert binary to decimal
; asl a
; bcs 9$
; ldy #3
;2$ asl temp ;3 shifts (8) + 1 shift (2) -> x10
; bcs 9$
; dey
; bne 2$
; adc temp
; bcs 9$
; adc index ;add current digit
; sta temp
; bcs 9$
; inx
; cpx count
; bne 1$ ;...loop until done or EOL
; beq 9$
;
;5$ cmp #',' ;found non-numeric
; bne 9$ ;...not <comma>, must not be a unit #
; lda temp ;...got <comma>, use as unit #
; sta disk
; inx
; ldy #0 ;squish unit# from buffer
;6$ cpx count
; beq 7$
; lda buffer,x
; sta buffer,y
; iny
; inx
; bne 6$
;7$ sty count
;
;9$ ldx count
; lda #',' ;append ',S' to filename
; sta buffer,x
; inx
; lda #'S'
; sta buffer,x
; inx
; stx count
;
; lda disk ;la
; cmp #31
; bcs error5 ;bad unit #
; cmp #8
; bcc error5 ;bad unit #
lda #2 ;************************************ [910528]
sta disk
tay ;sa
tax ;fa
jsr setlfs
; lda count ;fnlen
lda #14 ;9600 baud
sta buffer
lda #1
ldx #<buffer ;fnadr
ldy #>buffer
jsr setnam
ldx #0
jsr setbnk ;fnbank (RAM-0)
jsr open ;open object file
bcs error0 ;...report disk error
jsr primm
.byte cr,'START DOWNLOAD NOW...',cr,0
.page
; begin actual load
20$ lda #0
sta last_index ;init previous record index
sta next_address+1 ;init for contiguity check
sta record_count ;init record count
sta record_count+1
ldx disk ;set channel
jsr chkin
bcs error0 ;...branch on disk error
next_record
jsr stop
beq error3 ;...branch if STOP key- BREAK
10$ jsr get_character
cmp #';' ;record initiator?
bne next_record ;no...keep looking
lda #0
sta checksum ;reset record checksum
sta checksum+1
sta index ;reset memory index pointer
jsr get_byte ;read record's byte count
bne 30$ ;...branch if not last record (not null)
jsr get_byte ;check record count
cmp record_count+1
bne error4 ;...branch if sums do not match- error
jsr get_byte
cmp record_count
bne error4 ;...branch if mismatch (missing record)
bra done ;exit to BASIC, all done correctly
30$ sta count ;save record's byte count
jsr add_checksum ;add byte count to checksum
inw record_count ;increment record count
40$ lda first
beq 44$ ;...branch if not first record (or null sa given)
jsr offset_calc ;else read first address & calculate offset
bra 50$
44$ jsr get_byte ;get record's starting address (high)
pha
jsr add_checksum ;add to checksum
pla
clc
adc load_offset+1 ;add user offset (high) to starting address
sta load_address+1
jsr get_byte ;get low address
pha
jsr add_checksum ;add to checksum
pla
clc
adc load_offset ;add user offset (low) to starting address
sta load_address
bcc 50$
inc load_address+1 ;add any carry to high byte
50$
; jsr check_address ;check for program overwrite
lda load_address ;check contiguity
cmp next_address
bne 55$ ;...branch if beginning new block
lda load_address+1
cmp next_address+1
beq 60$
55$ lda #cr ;display starting address of new block
jsr bsout
jsr display_address ;write load address
jsr primm
.byte ' -> ',0 ;position cursor for ending address
60$ jsr get_byte ;get data byte
ldy index ;get current memory index
sty last_index ;save it for last address check
inc index ;increment it for next memory index
ldz bank ;get bank for memory store
ldx #load_address
jsr stash ;store data byte--> sta (load_address),y
jsr add_checksum ;add byte to checksum
dec count ;decrement record byte count
bne 60$ ;...loop until done all bytes for this record
jsr get_byte ;get record checksum (high)
cmp checksum+1 ;compare with calculated checksum
bne 65$ ;...branch if checksum error
jsr get_byte ;get record checksum (low)
cmp checksum ;compare with calculated checksum
65$ php ;save result- checksum error is non-fatal
clc
lda last_index ;add last index to last record index for last address
adc load_address
tay
lda load_address+1
adc #0
tax
jsr display_byte ;print the record ending address
tya
jsr display_byte
iny
sty next_address ;save for determining contiguity
bne 70$
inx
70$ stx next_address+1
plp ;check for non-fatal errors
bne error2
jsr primm
.byte bs,bs,bs,bs,0 ;format next for overwrite
bra next_record ;continue with next record
.page
error0 jsr primm
.byte bell,cr,rvs,'DISK ERROR',rvs_off,' ',0
jsr clrchn
; lda #0
; jsr setnam
; ldx disk
; ldy #15 ;prepare to read disk command channel
; jsr setlfs
; jsr open
; bcs error1 ;??? must be device not present
; ldx #0
; jsr chkin
; bcs 20$
;10$ jsr basin ;input error message from disk
; jsr bsout ;print it
; cmp #cr
; beq 20$
; lda status
; and #$bf
; beq 10$ ;loop until EOL or error
;20$ bra done
error1 jsr primm
.byte bell,cr,rvs,'DEVICE NOT PRESENT',cr,0
bra done
error2 jsr primm
.byte bell,' ',rvs,'CHECKSUM ERROR',0
dec next_address
bra next_record ;fake non-contiguous block by trashing next_address
error3 jsr primm
.byte bell,cr,rvs,'BREAK',cr,0
bra done
error4 jsr primm
.byte bell,cr,rvs,'RECORD COUNT BAD',cr,0
bra done
error5 jsr primm
.byte bell,cr,rvs,'INVALID DEVICE SPECIFIED',cr,0
bra done
error6 jsr primm
.byte bell,cr,rvs,'PROGRAM OVERWRITE',cr,0
; jmp done
done jsr clrchn ;finished with load
lda disk
jsr close_all ;close disk channel
; sei
ldx stack_ptr
txs
; ldx #load_address ;restore zero page
; ldy #0
;10$ lda end,y
; sta $00,x
; iny
; inx
; cpx #stack_ptr
; bcc 10$
; cli
rts ;return to caller
.page
get_key
clc
jsr cursor ;turn on cursor
10$ jsr getin ;loop until keypress
beq 10$
pha
sec
jsr cursor ;turn off cursor
pla
cmp #break_key
beq error3 ;exit if STOP key
rts
get_character
lda #0
sta status ;clean slate
jsr basin ;get next character from channel
bcs error0 ;...branch if I/O error
pha
lda status
and #%10111111 ;mask EOI bit
bne error0 ;...branch if I/O error
pla
rts
add_checksum
clc ;add current byte to record checksum
adc checksum
sta checksum
bcc 10$
inc checksum+1
10$ rts
offset_calc
jsr get_byte ;get first record's starting address (high)
sta load_address+1
jsr add_checksum ;add to checksum
jsr get_byte ;get low address
sta load_address
jsr add_checksum ;add to checksum
sec
lda load_offset ;calculate offset= alt_adr - rec_adr
pha ;save sa
sbc load_address
sta load_offset
lda load_offset+1
pha ;save sa
sbc load_address+1
sta load_offset+1
pla ;pop first load address (original load_offset)
sta load_address+1
pla
sta load_address
lda #0
sta first ;squash first record flag
rts
;check_address
; ldx bank ;check for record overwrite of program
; bne 20$ ;it's okay: bank is not same
;
; lda load_address+1
; jsr 10$ ;check record starting address
; ldy count
; dey
; tya
; clc ;calculate address of last byte of record
; adc load_address
; lda load_address+1 ;(only concerned with high bytes...)
; adc #0 ;(fall into subroutine)
;
;10$ cmp #>start ;beginning of this program
; bcc 20$ ;...branch if below program- ok
; cmp #>end+1 ;end of this program
; bcc error6 ;...error- loading this record would overwrite!
;
;20$ rts
.page
; read ASCII hex byte and return binary in .a
get_byte
lda #0 ;space
sta temp
jsr get_character ;get most significant digit
jsr get_binary ;convert to binary
asl a ;shift to most significant nibble
asl a
asl a
asl a
sta temp ;save it
jsr get_character ;get least significant digit
jsr get_binary ;convert to binary
ora temp ;merge nibbles
rts
get_binary
cmp #':' ;convert ascii hex digit to binary
php
and #$0f ;mask it
plp
bcc 10$ ;...branch if it was numeric (0-9)
adc #8 ;else in range (A-F), add 9 (assumes .c=1)
10$ rts
; write address
display_address
lda load_address+1 ;print current address, high/low
jsr display_byte ;print high byte
lda load_address ;print low byte (fall into display_byte)
display_byte
pha ;save byte to unpack
lsr a ;most significant nibble
lsr a
lsr a
lsr a
jsr display_digit ;convert binary to ascii & print it
pla
and #$0f ;least significant nibble (fall into display_digit)
display_digit
clc ;convert binary nibble to ascii
adc #$f6
bcc 10$
adc #$06
10$ adc #$3a
jmp bsout ;print it and RTS
end
.end

7
README.md

@ -157,6 +157,9 @@ Using [kernalemu](https://github.com/mist64/kernalemu) and [cbm6502asm](https://
| [EDT_C128](EDT_C128) | 1986 | |
| [LOADER_PET](LOADER_PET) | 1979 | OBJ Loader |
| [LOADER_C64](LOADER_C64) | 1986 | OBJ Loader |
| [LOADER_C128](LOADER_C128) | 1986 | rewrite |
| [LOADER_C65](LOADER_C65) | 1990 | |
| [LOADER_C65_RS232](LOADER_C65_RS232) | 1990 | RS-232 |
## Software: Games
@ -493,6 +496,10 @@ The PET OBJ Loader, version V121379. Extracted from [ted_kernal_basic_src.tar.gz
The OBJ Loader of the C64 Macro Assembler, version V072882. Extracted from [c64_kernal_bas_src.tar.gz](http://www.zimmers.net/anonftp/pub/cbm/src/c64/c64_kernal_bas_src.tar.gz) and converted to uppercase and LST-style indenting.
### LOADER_C128, LOADER_C65, LOADER_C65_RS232
The OBJ Loader of the HCD65 assembler. Versions for C128 and C65 (disk and RS-232). Source: [c128_dev_pack.tar.gz](http://www.zimmers.net/anonftp/pub/cbm/src/c128/index.html)
### EDT_C128
The editor for the HCD65 assembler for the C128 (1986). Source: [c128_dev_pack.tar.gz](http://www.zimmers.net/anonftp/pub/cbm/src/c128/index.html)

6
build.sh

@ -57,6 +57,9 @@ test_tools
rm -rf build
mkdir build
build2 LOADER_C128 loader
exit
build1 MONITOR_KIM kim.asm
build1 MONITOR_AIM65 pa00-j001a
build1 TIM tim.asm
@ -187,3 +190,6 @@ build1 FIG FOR1-1
# build2 HCD65_65CE02_0.1 c65
# build2 HCD65_65CE02_0.2 c65
# build2 EDT_C128 edt
# ldz zp/abs
# build2 LOADER_C65 loader65
# build2 LOADER_C65_RS232 l232

Loading…
Cancel
Save