.TITLE Hxload - Load ASCII hex files in KIM format .SBTTL Author - Antonino N. J. Mione ; ; Edit # Date Description ; ------ ---- ----------- ; .SBTTL Macro definitions .macro nasc str opt .irpc chr .byte ''chr!$80 .endr .ifnz .byte $00 .endc .endm .SBTTL Definitions ; Zero-page definitions saddr = 0 ; Work area for addresses count = 2 ; Character count of line laddr = 3 ; Start-of-line address ysav = 5 ; Save area for y-reg lind = 6 ; Line index hold = 7 ; Hold area for nibbles cswl = $36 ; Address of character out routine cswh = $37 ; ... kswl = $38 ; Address of keyin routine kswh = $39 ; ... ; ; Monitor and DOS routine addresses ; slot = $c200 ; Slot where modem card resides (default=2) home = $fc58 ; Mon routine - clear screen nxtchr = $fd75 ; Mon routine - get line of input from keyboard prbl3 = $f94c ; Mon routine - print A reg and (X)-1 blanks prbyte = $fdda ; Mon routine - print A-reg as hex prerr = $ff2d ; Mon routine- print 'err' rdkey = $fd0c ; Mon routine - read a key from input device keyin = $fd1b ; Mon routine - read a key from keyboard cout = $fded ; Mon routine - output char through output dev cout1 = $fdf0 ; Mon routine - output char to screen dos = $03d0 ; Warmstart address of DOS ; ; Definitions ; inbuf = $0200 ; Monitor input buffer address cr = $8d ; with H.O. bit on lf = $8a ; with H.O. bit on semi = $bb ; Semicolon with H.O. bit on space = $a0 ; with H.O. bit on ; ; Start of assembly address ; .=$2000 .PHASE $9000 st: jmp start ; Jump past data to start of code ; ; Working storage definitions ; chksum: .byte $00,$00 ; Checksum for line hxwrk1: .byte $00 ; Hold area mess1: nasc 1 ; Prompt message for filename mess2: nasc 1 ; 'TYPE ' command for most DECsystems mess3: nasc 1 ; 'Checksum' error message fnam: .blkb $1e ; Filename buffer fnlen = .-fnam ; Length of filename buffer ; ; Start of program ; start: jsr home ; Clear the screen ldx #mess1\ ; Get the address of the prompt message ldy #mess1^ ; ... jsr prstr ; Print the message ldx #$00 ; Make sure X is zero for the monitor call jsr nxtchr ; Go get the filename stx count ; Store the index as the character count ldx #fnlen-1 ; Get the buffer length lda #space ; Use spaces to clear the buffer fill1: sta fnam,x ; Stuff a space dex ; Decrement the count bmi movfl1 ; If we are done, go move the filename jmp fill1 ; Otherwise, continue clearing buffer movfl1: ldx count ; Get the count lda #$00 ; Stuff a null just past the filename sta fnam,x ; ... dex ; Decrement the count movfl2: lda inbuf,x ; Get a char from input buf (last char first) sta fnam,x ; Stuff it in the filename buffer dex ; Decrement the count bmi sendcm ; If we are done, send the message jmp movfl2 ; Otherwise, continue sendcm: lda #slot\ ; Change the output device to the prot sta cswl ; ... lda #slot^ ; ... sta cswh ; ... ldx #$00 ; Zero X snloop: lda mess2,x ; Start with the command 'type' cmp #$00 ; Done? beq snl2 ; If so, go do the filename jsr cout ; Stuff a character at the port inx ; Increment the buffer index jmp snloop ; Loop for another character snl2: ldx #$00 ; Zero X snl3: lda fnam,x ; Get a character from the filename cmp #$00 ; Is it a null? beq snl3a ; If so, go try to receive the file jsr cout ; Otherwise, stuff the character at the port inx ; Increment the buffer index jmp snl3 ; Loop for another character snl3a: lda #cr ; Get a jsr cout ; and print it snl4: lda #cout1\ ; Redirect output to be to the screen... sta cswl ; ... lda #cout1^ ; ... sta cswh ; ... lda #slot\ ; and input to be from the port sta kswl ; ... lda #slot^ ; ... sta kswh ; ... receve: jsr rdkey ; Get a character from the port jsr cout ; Print the character cmp #semi ; Is it the beginning of a line? bne receve ; If not, try again jsr doline ; Otherwise, read a line of ascii hex jmp receve ; If that didn't skip, go back for next line lda #keyin\ ; Doline skipped, we are done sta kswl ; Redirect input to be from keyboard lda #keyin^ ; ... sta kswh ; ... jmp dos ; Jump to the DOS warmstart address ; ; Doline routine ; doline: ldy #$00 ; Zero the sty lind ; load point index sty chksum ; and the checksum sty chksum+1 ; ... lda #cr ; Start by printing a space jsr cout ; ... dolin1: jsr getbyt ; Get a hex byte pha ; Save it on the stack jsr prbyte ; Display it on the screen pla ; Fetch it back cmp #$00 ; Is it zero? bne norskp ; If not, continue gobbling line jmp rskp ; Otherwise, return with a skip norskp: pha ; Save the character on the stack lda #space ; Get a space and jsr cout ; print it pla ; Fetch the character back jsr chksad ; Add it to the checksum sta count ; The first byte is a count, store it jsr getbyt ; Get the next hex byte jsr chksad ; Add it to the checksum sta laddr+1 ; That is the H.O. byte of the load address jsr prbyte ; Print the hex on the screen jsr getbyt ; Get the next byte jsr chksad ; Add that into the checksum sta laddr ; That is the L.O. byte of the load address jsr prbyte ; Print that byte on the screen dolin2: ldx count ; Fetch the character count dolin3: dex ; Decrement the count bmi dolchk ; If we are done, do the checksum stuff jsr getbyt ; Get a byte ldy lind ; Get the load point index jsr chksad ; Add the data into the checksum sta (laddr),y ; Stuff the data where it belongs jsr prbyte ; Print the byte out as hex inc lind ; Up the load point index once jmp dolin3 ; Loop for more data dolchk: jsr getbyt ; Get another byte from the port pha ; Stuff it on the stack jsr prbyte ; Print it out on the creen pla ; Fetch back the character cmp chksum+1 ; Compare that with the checksum bne chkerr ; If they don't match, we have problems lda chksum+1 ; Get the H.O. byte of the checksum jsr prbyte ; Print it as hex lda #space ; Get a space jsr cout ; Print that out next jsr getbyt ; Get another byte from the port pha ; Hold it on the stack jsr prbyte ; Print the byte on the screen pla ; Fetch the data back cmp chksum ; Compare that to the L.O. byte of the checksum bne chkerr ; If they don't match, tell the user lda chksum ; Fetch the L.O. byte of the checksum jsr prbyte ; Print that as hex rts ; Return, this line worked good chksad: pha ; Save the accumulator accross this call clc ; Clear the carry flag for addition adc chksum ; Add in the checksum sta chksum ; Stuff that back lda chksum+1 ; Adjust the H.O. byte of the checksum adc #$00 ; by whatever is in the carry sta chksum+1 ; ... pla ; Restore the AC rts ; Return chkerr: ldx #mess3\ ; Get the address of the 'checksum error' mess. ldy #mess3^ ; ... jsr prstr ; Print that error text rts ; Return ; ; Getbyt routine ; getbyt: jsr getnib ; Get the first nibble of the two sta hold ; Stuff that here jsr getnib ; Get the second nibble sta hold+1 ; Hold that here lda hold ; Get the first of the two asl a ; Shift it to the left side asl a ; ... asl a ; ... asl a ; ... ora hold+1 ; Combine that with the second nibble rts ; and return ; ; Getnib routine ; getnib: jsr rdkey ; Read a character from the port cmp #$b0 ; Is it in the proper range? bmi badchr ; 0<=char<=f cmp #$ba ; ... bmi getnb3 ; This is good, no special adjustment cmp #$c1 ; ... bmi badchr ; ... cmp #$c7 ; ... bmi getnb2 ; This is good, but adjust it down a bit jmp badchr ; Bad character in input getnb2: sec ; Set the carry flag sbc #$07 ; Adjust the letters into the proper range getnb3: sec ; Set the carry flag sbc #$b0 ; Make the character numeric rts ; and return badchr: pla ; Pull 3 return addresses off the stack pla ; ... pla ; ... pla ; ... pla ; ... pla ; ... jmp receve ; Try to recover from next line ; ; Prstr subroutine ; prstr: stx saddr ; Store the address in a work area sty saddr+1 ; ... ldy #$00 ; Zero Y prst1: lda (saddr),y ; Get a byte to print beq prsdon ; If it is a null, we are done jsr cout ; Output the character iny ; Increment the index beq prsdon ; If this wraps around, we are done jmp prst1 ; Loop for another character prsdon: rts ; Return ; ; Rskp - do a skip return ; rskp: sta hxwrk1 ; Hold the accumulator pla ; Fetch the L.O. byte of the return address tax ; Put that in X pla ; Get the H.O. byte of the return address tay ; Stuff that in Y txa ; Get the L.O. byte back again clc ; Clear the carry flag adc #$04 ; Add in 4 (3 byte inst. + 1 for not doing rts) bcc rskp2 ; If there was no carry, continue iny ; Increment the H.O. byte rskp2: sta saddr ; Store the L.O. byte sty saddr+1 ; and the H.O. byte lda hxwrk1 ; Get back the old value in the AC jmp (saddr) ; Jump to the new return address ; ; End of HEXLD source ; .DEPHASE .end