The good news: I seem to have gotten Sweet16 working (I think).
The bad news: now my "Frankenstein" mash-up of a monitor isn't working... the XModem receive stopped working, and I can't find the problem.
Can anyone figure this out?
Code:
;-------------------------- The Code ----------------------------
;
; zero page variables (adjust these to suit your needs)
;
;
.target "65C02"
*= $C000 ; Start of program (adjust to your needs)
.setting "HandleLongBranch", true
crc = $D8 ; CRC lo byte (two byte variable)
crch = $D9 ; CRC hi byte
ptr = $DA ; data pointer (two byte variable)
ptrh = $DB ; " "
blkno = $DC ; block number
retry = $DD ; retry counter
retry2 = $DE ; 2nd counter
bflag = $DF ; block flag
;
;Monitor Variables
;
IN = $0200 ;*Input buffer
XAML = $E4 ;*Index pointers
XAMH = $E5
STL = $E6
STH = $E7
L = $E8
H = $E9
YSAV = $EA
MODE = $EB
MSGL = $EC
MSGH = $ED
;
; non-zero page variables and buffers
;
;
Rbuff = $0300 ; temp 132 byte receive buffer
;(place anywhere, page aligned)
;
; XMODEM Control Character Constants
SOH = $F1 ; start block
EOT = $F4 ; end of text marker
ACK = $F6 ; good block acknowledged
NAK = $F5 ; bad block acknowledged
CAN = $F8 ; cancel (not standard, not supported)
CR = $FD ; carriage return
LF = $FA ; line feed
ESC = $FB ; ESC to exit
;Sweet16 Zero Page Variables
R0L .EQU $0
R0H .EQU $1
R14H .EQU $1D
R15L .EQU $1E
R15H .EQU $1F
;
;-------------------------------
ACC .EQU $20
XREG .EQU $21
YREG .EQU $22
STATUS .EQU $23
;
SAVE16
STA ACC
STX XREG
STY YREG
PHP
PLA
STA STATUS
CLD
RTS
;------------------------------
RESTORE16
LDA STATUS
PHA
LDA ACC
LDX XREG
LDY YREG
PLP
RTS
;
;^^^^^^^^^^^^^^^^^^^^^^ Start of Program ^^^^^^^^^^^^^^^^^^^^^^
;
; Xmodem/CRC upload routine
; By Daryl Rictor, July 31, 2002
;
; v0.3 tested good minus CRC
; v0.4 CRC fixed!!! init to $0000 rather than $FFFF as stated
; v0.5 added CRC tables vs. generation at run time
; v 1.0 recode for use with SBC2
; v 1.1 added block 1 masking (block 257 would be corrupted)
.org $C020 ;jump to address
JSR SAVE16 ;PRESERVE 6502 REG CONTENTS
PLA
STA R15L ;INIT SWEET16 PC
PLA ;FROM RETURN
STA R15H ;ADDRESS
SW16B JSR SW16C ;INTERPRET AND EXECUTE
JMP SW16B ;ONE SWEET16 INSTR.
SW16C INC R15L
BNE SW16D ;INCR SWEET16 PC FOR FETCH
INC R15H
SW16D LDA >SET ;COMMON HIGH BYTE ">" FOR ALL ROUTINES
PHA ;PUSH ON STACK FOR RTS
LDY $0
LDA (R15L),Y ;FETCH INSTR
AND $F ;MASK REG SPECIFICATION
ASL ;DOUBLE FOR TWO BYTE REGISTERS
TAX ;TO X REG FOR INDEXING
LSR
EOR (R15L),Y ;NOW HAVE OPCODE
BEQ TOBR ;IF ZERO THEN NON-REG OP
STX R14H ;INDICATE "PRIOR RESULT REG"
LSR
LSR ;OPCODE*2 TO LSB'S
LSR
TAY ;TO Y REG FOR INDEXING
LDA OPTBL-2,Y ;LOW ORDER ADR BYTE
PHA ;ONTO STACK
RTS ;GOTO REG-OP ROUTINE
TOBR INC R15L
BNE TOBR2 ;INCR PC
INC R15H
TOBR2 LDA BRTBL,X ;LOW ORDER ADR BYTE
PHA ;ONTO STACK FOR NON-REG OP
LDA R14H ;"PRIOR RESULT REG" INDEX
LSR ;PREPARE CARRY FOR BC, BNC.
RTS ;GOTO NON-REG OP ROUTINE
RTNZ PLA ;POP RETURN ADDRESS
PLA
JSR RESTORE16 ;RESTORE 6502 REG CONTENTS
JMP (R15L) ;RETURN TO 6502 CODE VIA PC
SETZ LDA (R15L),Y ;HIGH ORDER BYTE OF CONSTANT
STA R0H,X
DEY
LDA (R15L),Y ;LOW ORDER BYTE OF CONSTANT
STA R0L,X
TYA ;Y REG CONTAINS 1
SEC
ADC R15L ;ADD 2 TO PC
STA R15L
BCC SET2
INC R15H
SET2 RTS
OPTBL .lobyte SET-1 ;1X
BRTBL .lobyte RTN-1 ;0
.lobyte LD-1 ;2X
.lobyte BR-1 ;1
.lobyte ST-1 ;3X
.lobyte BNC-1 ;2
.lobyte LDAT-1 ;4X
.lobyte BC-1 ;3
.lobyte STAT-1 ;5X
.lobyte BP-1 ;4
.lobyte LDDAT-1 ;6X
.lobyte BM-1 ;5
.lobyte STDAT-1 ;7X
.lobyte BZ-1 ;6
.lobyte POP-1 ;8X
.lobyte BNZ-1 ;7
.lobyte STPAT-1 ;9X
.lobyte BM1-1 ;8
.lobyte ADD-1 ;AX
.lobyte BNM1-1 ;9
.lobyte SUB-1 ;BX
.lobyte BK-1 ;A
.lobyte POPD-1 ;CX
.lobyte RS-1 ;B
.lobyte CPR-1 ;DX
.lobyte BS-1 ;C
.lobyte INR-1 ;EX
.lobyte NUL-1 ;D
.lobyte DCR-1 ;FX
.lobyte NUL-1 ;E
.lobyte NUL-1 ;UNUSED
.lobyte NUL-1 ;F
; FOLLOWING CODE MUST BE
; CONTAINED ON A SINGLE PAGE!
.org $C0B0 ;single page start
SET BPL SETZ ;ALWAYS TAKEN
LD LDA R0L,X
BK .EQU *-1 ;"*" refers to the program counter
STA R0L
LDA R0H,X ;MOVE RX TO R0
STA R0H
RTS
ST LDA R0L
STA R0L,X ;MOVE R0 TO RX
LDA R0H
STA R0H,X
RTS
STAT LDA R0L
STAT2 STA (R0L,X) ;STORE BYTE INDIRECT
LDY $0
STAT3 STY R14H ;INDICATE R0 IS RESULT NEG
INR INC R0L,X
BNE INR2 ;INCR RX
INC R0H,X
INR2 RTS
LDAT LDA (R0L,X) ;LOAD INDIRECT (RX)
STA R0L ;TO R0
LDY $0
STY R0H ;ZERO HIGH ORDER R0 BYTE
BEQ STAT3 ;ALWAYS TAKEN
POP LDY $0 ;HIGH ORDER BYTE = 0
BEQ POP2 ;ALWAYS TAKEN
POPD JSR DCR ;DECR RX
LDA (R0L,X) ;POP HIGH ORDER BYTE @RX
TAY ;SAVE IN Y REG
POP2 JSR DCR ;DECR RX
LDA (R0L,X) ;LOW ORDER BYTE
STA R0L ;TO R0
STY R0H
POP3 LDY $0 ;INDICATE R0 AS LAST RESULT REG
STY R14H
RTS
LDDAT JSR LDAT ;LOW ORDER BYTE TO R0, INCR RX
LDA (R0L,X) ;HIGH ORDER BYTE TO R0
STA R0H
JMP INR ;INCR RX
STDAT JSR STAT ;STORE INDIRECT LOW ORDER
LDA R0H ;BYTE AND INCR RX. THEN
STA (R0L,X) ;STORE HIGH ORDER BYTE.
JMP INR ;INCR RX AND RETURN
STPAT JSR DCR ;DECR RX
LDA R0L
STA (R0L,X) ;STORE R0 LOW BYTE @RX
JMP POP3 ;INDICATE R0 AS LAST RESULT REG
DCR LDA R0L,X
BNE DCR2 ;DECR RX
DEC R0H,X
DCR2 DEC R0L,X
RTS
SUB LDY $0 ;RESULT TO R0
CPR SEC ;NOTE Y REG = 13*2 FOR CPR
LDA R0L
SBC R0L,X
STA R0L,Y ;R0-RX TO RY
LDA R0H
SBC R0H,X
SUB2 STA R0H,Y
TYA ;LAST RESULT REG*2
ADC $0 ;CARRY TO LSB
STA R14H
RTS
ADD LDA R0L
ADC R0L,X
STA R0L ;R0+RX TO R0
LDA R0H
ADC R0H,X
LDY $0 ;R0 FOR RESULT
BEQ SUB2 ;FINISH ADD
BS LDA R15L ;NOTE X REG IS 12*2!
JSR STAT2 ;PUSH LOW PC BYTE VIA R12
LDA R15H
JSR STAT2 ;PUSH HIGH ORDER PC BYTE
BR CLC
BNC BCS BNC2 ;NO CARRY TEST
BR1 LDA (R15L),Y ;DISPLACEMENT BYTE
BPL BR2
DEY
BR2 ADC R15L ;ADD TO PC
STA R15L
TYA
ADC R15H
STA R15H
BNC2 RTS
BC BCS BR
RTS
BP ASL ;DOUBLE RESULT-REG INDEX
TAX ;TO X REG FOR INDEXING
LDA R0H,X ;TEST FOR PLUS
BPL BR1 ;BRANCH IF SO
RTS
BM ASL ;DOUBLE RESULT-REG INDEX
TAX
LDA R0H,X ;TEST FOR MINUS
BMI BR1
RTS
BZ ASL ;DOUBLE RESULT-REG INDEX
TAX
LDA R0L,X ;TEST FOR ZERO
ORA R0H,X ;(BOTH BYTES)
BEQ BR1 ;BRANCH IF SO
RTS
BNZ ASL ;DOUBLE RESULT-REG INDEX
TAX
LDA R0L,X ;TEST FOR NON-ZERO
ORA R0H,X ;(BOTH BYTES)
BNE BR1 ;BRANCH IF SO
RTS
BM1 ASL ;DOUBLE RESULT-REG INDEX
TAX
LDA R0L,X ;CHECK BOTH BYTES
AND R0H,X ;FOR $FF (MINUS 1)
EOR $FF
BEQ BR1 ;BRANCH IF SO
RTS
BNM1 ASL ;DOUBLE RESULT-REG INDEX
TAX
LDA R0L,X
AND R0H,X ;CHECK BOTH BYTES FOR NO $FF
EOR $FF
BNE BR1 ;BRANCH IF NOT MINUS 1
NUL RTS
RS LDX $18 ;12*2 FOR R12 AS STACK POINTER
JSR DCR ;DECR STACK POINTER
LDA (R0L,X) ;POP HIGH RETURN ADDRESS TO PC
STA R15H
JSR DCR ;SAME FOR LOW ORDER BYTE
LDA (R0L,X)
STA R15L
RTS
RTN JMP RTNZ
;End of Sweet16
;
XModem jsr PrintMsg ; send prompt and info
lda #$01
sta blkno ; set block # to 1
sta bflag ; set flag to get address from block 1
StartCrc lda #"C" ; "C" start with CRC mode
jsr Put_Chr ; send it
lda #$FF
sta retry2 ; set loop counter for ~3 sec delay
lda #$00
sta crc
sta crch ; init CRC value
jsr GetByte ; wait for input
bcs GotByte ; byte received, process it
bcc StartCrc ; resend "C"
StartBlk lda #$FF ;
sta retry2 ; set loop counter for ~3 sec delay
lda #$00 ;
sta crc ;
sta crch ; init CRC value
jsr GetByte ; get first byte of block
bcc StartBlk ; timed out, keep waiting...
GotByte cmp #ESC ; quitting?
bne GotByte1 ; no
; lda #$FE ; Error code in "A" of desired
rts ; YES - do BRK or change to RTS if desired
GotByte1 cmp #SOH ; start of block?
beq BegBlk ; yes
cmp #EOT ;
bne BadCrc ; Not SOH or EOT, so flush buffer & send NAK
jmp Done ; EOT - all done!
BegBlk ldx #$00
GetBlk lda #$ff ; 3 sec window to receive characters
sta retry2 ;
GetBlk1 jsr GetByte ; get next character
bcc BadCrc ; chr rcv error, flush and send NAK
GetBlk2 sta Rbuff,x ; good char, save it in the rcv buffer
inx ; inc buffer pointer
cpx #$84 ; <01> <FE> <128 bytes> <CRCH> <CRCL>
bne GetBlk ; get 132 characters
ldx #$00 ;
lda Rbuff,x ; get block # from buffer
cmp blkno ; compare to expected block #
beq GoodBlk1 ; matched!
jsr Print_Err ; Unexpected block number - abort
jsr Flush ; mismatched - flush buffer and then do BRK
; lda #$FD ; put error code in "A" if desired
rts ; unexpected block # - fatal error - BRK or RTS
GoodBlk1 eor #$ff ; 1's comp of block #
inx ;
cmp Rbuff,x ; compare with expected 1's comp of block #
beq GoodBlk2 ; matched!
jsr Print_Err ; Unexpected block number - abort
jsr Flush ; mismatched - flush buffer and then do BRK
; lda #$FC ; put error code in "A" if desired
brk ; bad 1's comp of block#
GoodBlk2 ldy #$02 ;
CalcCrc lda Rbuff,y ; calculate the CRC for the 128 bytes of data
jsr UpdCrc ; could inline sub here for speed
iny ;
cpy #$82 ; 128 bytes
bne CalcCrc ;
lda Rbuff,y ; get hi CRC from buffer
cmp crch ; compare to calculated hi CRC
bne BadCrc ; bad crc, send NAK
iny ;
lda Rbuff,y ; get lo CRC from buffer
cmp crc ; compare to calculated lo CRC
beq GoodCrc ; good CRC
BadCrc jsr Flush ; flush the input port
lda #NAK ;
jsr Put_Chr ; send NAK to resend block
jmp StartBlk ; start over, get the block again
GoodCrc ldx #$02 ;
lda blkno ; get the block number
cmp #$01 ; 1st block?
bne CopyBlk ; no, copy all 128 bytes
lda bflag ; is it really block 1, not block 257, 513 etc.
beq CopyBlk ; no, copy all 128 bytes
lda Rbuff,x ; get target address from 1st 2 bytes of blk 1
sta ptr ; save lo address
inx ;
lda Rbuff,x ; get hi address
sta ptr+1 ; save it
inx ; point to first byte of data
dec bflag ; set the flag so we won't get another address
CopyBlk ldy #$00 ; set offset to zero
CopyBlk3 lda Rbuff,x ; get data byte from buffer
sta (ptr),y ; save to target
inc ptr ; point to next address
bne CopyBlk4 ; did it step over page boundary?
inc ptr+1 ; adjust high address for page crossing
CopyBlk4 inx ; point to next data byte
cpx #$82 ; is it the last byte
bne CopyBlk3 ; no, get the next one
IncBlk inc blkno ; done. Inc the block #
lda #ACK ; send ACK
jsr Put_Chr ;
jmp StartBlk ; get next block
Done lda #ACK ; last block, send ACK and exit.
jsr Put_Chr ;
jsr Flush ; get leftover characters, if any
jsr Print_Good ;
jmp RESET ;can be rts
;
;^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
;
; subroutines
;
; ;
GetByte lda #$00 ; wait for chr input and cycle timing loop
sta retry ; set low value of timing loop
StartCrcLp jsr Get_chr ; get chr from serial port, don't wait
bcs GetByte1 ; got one, so exit
dec retry ; no character received, so dec counter
bne StartCrcLp ;
dec retry2 ; dec hi byte of counter
bne StartCrcLp ; look for character again
clc ; if loop times out, CLC, else SEC and return
GetByte1 rts ; with character in "A"
;
Flush lda #$70 ; flush receive buffer
sta retry2 ; flush until empty for ~1 sec.
Flush1 jsr GetByte ; read the port
bcs Flush ; if chr recvd, wait for another
rts ; else done
;
PrintMsg ldx #$00 ; PRINT starting message
PrtMsg1 lda Msg,x
beq PrtMsg2
jsr Put_Chr
inx
bne PrtMsg1
PrtMsg2 rts
Msg .textz "Begin XMODEM/CRC upload. "
;.lobyte CR, LF
;.lobyte 0
;
Print_Err ldx #$00 ; PRINT Error message
PrtErr1 lda ErrMsg,x
beq PrtErr2
jsr Put_Chr
inx
bne PrtErr1
PrtErr2 rts
ErrMsg .textz "Upload Error!"
;.lobyte CR, LF
;.lobyte 0
;
Print_Good ldx #$00 ; PRINT Good Transfer message
Prtgood1 lda GoodMsg,x
beq Prtgood2
jsr Put_Chr
inx
bne Prtgood1
Prtgood2 rts
GoodMsg .textz "Upload Successful!"
;.lobyte CR, LF
;.lobyte 0
;
;
;======================================================================
; I/O Device Specific Routines
;
; Two routines are used to communicate with the I/O device.
;
; "Get_Chr" routine will scan the input port for a character. It will
; return without waiting with the Carry flag CLEAR if no character is
; present or return with the Carry flag SET and the character in the "A"
; register if one was present.
;
; "Put_Chr" routine will write one byte to the output port. Its alright
; if this routine waits for the port to be ready. its assumed that the
; character was send upon return from this routine.
;
; Here is an example of the routines used for a standard 6551 ACIA.
; You would call the ACIA_Init prior to running the xmodem transfer
; routine.
;
VIA_REG = $8800
VIA_DATA = $8801
VIA_DDRR = $8802
VIA_DDRD = $8803
VIA_HS = $880C
;
PSP_DATA = $9000
;
ACIA_Data = $8000 ; Adjust these addresses to point
ACIA_Status = $8001 ; to YOUR 6551!
ACIA_Command = $8002 ;
ACIA_Control = $8003 ;
ACIA = $8000
ACIA_CTRL = ACIA+3
ACIA_CMD = ACIA+2
ACIA_SR = ACIA+1
ACIA_DAT = ACIA
ACIA_Init lda #$10 ; 115.2k init is #%00010000
sta ACIA_Control ; control reg
lda #$C9 ; N parity/echo off/rx int off/ dtr active low
sta ACIA_Command ; command reg
lda #$99
sta VIA_HS
lda #$FF
sta VIA_DDRR
sta VIA_DDRD
sta VIA_REG
rts ; done
;
; input chr from ACIA (no waiting)
;
Get_Chr clc ; no chr present
lda ACIA_Status ; get Serial port status
and #$08 ; mask rcvr full bit
beq Get_Chr2 ; if not chr, done
Lda ACIA_Data ; else get chr
sec ; and set the Carry Flag
Get_Chr2 rts ; done
;
; output to OutPut Port
;
Put_Chr PHA ; save registers
Put_Chr1 lda ACIA_Status ; serial port status
and #$10 ; is tx buffer empty
beq Put_Chr1 ; no, go back and test it again
PLA ; yes, get chr to send
sta ACIA_Data ; put character to Port
jsr Delay
RTS ; done
;=========================================================================
;Main Routines/Program
RESET CLD ;Clear decimal arithmetic mode.
CLI
JSR ACIA_Init ;* Init ACIA
LDA #$0D
JSR ECHO ;* New line.
LDA #<MSG1
STA MSGL
LDA #>MSG1
STA MSGH
JSR SHWMSG ;* Show Welcome.
LDA #$0D
JSR ECHO ;* New line.
LDA #<MSG5
STA MSGL
LDA #>MSG5
STA MSGH
JSR SHWMSG
LDA #$0D
JSR ECHO ;* New line.
SOFTRESET LDA #$9B ;* Auto escape.
NOTCR CMP #$88 ;"<-"? * Note this was chaged to $88 which is the back space key.
BEQ BACKSPACE ;Yes.
CMP #$9B ;ESC?
BEQ ESCAPE ;Yes.
INY ;Advance text index.
BPL NEXTCHAR ;Auto ESC if >127.
ESCAPE LDA #$DC ;"\"
JSR ECHO ;Output it.
GETLINE LDA #$8D ;CR.
JSR ECHO ;Output it.
LDY #$01 ;Initiallize text index.
BACKSPACE DEY ;Backup text index.
BMI GETLINE ;Beyond start of line, reinitialize.
LDA #$A0 ;*Space, overwrite the backspaced char.
JSR ECHO
LDA #$88 ;*Backspace again to get to correct pos.
JSR ECHO
NEXTCHAR LDA ACIA_SR ;*See if we got an incoming char
AND #$08 ;*Test bit 3
BEQ NEXTCHAR ;*Wait for character
LDA ACIA_DAT ;*Load char
CMP #$60 ;*Is it Lower case
BMI CONVERT ;*Nope, just convert it
AND #$5F ;*If lower case, convert to Upper case
CONVERT ORA #$80 ;*Convert it to "ASCII Keyboard" Input
STA IN,Y ;Add to text buffer.
JSR ECHO ;Display character.
CMP #$8D ;CR?
BNE NOTCR ;No.
LDY #$FF ;Reset text index.
LDA #$00 ;For XAM mode.
TAX ;0->X.
SETSTOR ASL ;Leaves $7B if setting STOR mode.
SETMODE STA MODE ;$00 = XAM, $7B = STOR, $AE = BLOK XAM.
BLSKIP INY ;Advance text index.
NEXTITEM LDA IN,Y ;Get character.
CMP #$8D ;CR?
BEQ GETLINE ;Yes, done this line.
CMP #$AE ;"."?
BCC BLSKIP ;Skip delimiter.
BEQ SETMODE ;Set BLOCK XAM mode.
CMP #$BA ;":"?
BEQ SETSTOR ;Yes, set STOR mode.
CMP #$D2 ;"R"?
BEQ RUN ;Yes, run user program.
CMP #$D8 ;"X"?
BEQ XModem ;Yes, run XModem transfer.
STX L ;$00->L.
STX H ; and H.
STY YSAV ;Save Y for comparison.
NEXTHEX LDA IN,Y ;Get character for hex test.
EOR #$B0 ;Map digits to $0-9.
CMP #$0A ;Digit?
BCC DIG ;Yes.
ADC #$88 ;Map letter "A"-"F" to $FA-FF.
CMP #$FA ;Hex letter?
BCC NOTHEX ;No, character not hex.
DIG ASL
ASL ;Hex digit to MSD of A.
ASL
ASL
LDX #$04 ;Shift count.
HEXSHIFT ASL ;Hex digit left MSB to carry.
ROL L ;Rotate into LSD.
ROL H ;Rotate into MSD's.
DEX ;Done 4 shifts?
BNE HEXSHIFT ;No, loop.
INY ;Advance text index.
BNE NEXTHEX ;Always taken. Check next character for hex.
NOTHEX CPY YSAV ;Check if L, H empty (no hex digits).
BNE NOESCAPE ;* Branch out of range, had to improvise...
JMP ESCAPE ;Yes, generate ESC sequence.
RUN JSR ACTRUN ;* JSR to the Address we want to run.
JMP SOFTRESET ;* When returned for the program, reset monitor.
ACTRUN JMP (XAML) ;Run at current XAM index.
NOESCAPE BIT MODE ;Test MODE byte.
BVC NOTSTOR ;B6=0 for STOR, 1 for XAM and BLOCK XAM
LDA L ;LSD's of hex data.
STA (STL, X) ;Store at current "store index".
INC STL ;Increment store index.
BNE NEXTITEM ;Get next item. (no carry).
INC STH ;Add carry to 'store index' high order.
TONEXTITEM JMP NEXTITEM ;Get next command item.
NOTSTOR BMI XAMNEXT ;B7=0 for XAM, 1 for BLOCK XAM.
LDX #$02 ;Byte count.
SETADR LDA L-1,X ;Copy hex data to
STA STL-1,X ;"store index".
STA XAML-1,X ;And to "XAM index'.
DEX ;Next of 2 bytes.
BNE SETADR ;Loop unless X = 0.
NXTPRNT BNE PRDATA ;NE means no address to print.
LDA #$8D ;CR.
JSR ECHO ;Output it.
LDA XAMH ;'Examine index' high-order byte.
JSR PRBYTE ;Output it in hex format.
LDA XAML ;Low-order "examine index" byte.
JSR PRBYTE ;Output it in hex format.
LDA #$BA ;":".
JSR ECHO ;Output it.
PRDATA LDA #$A0 ;Blank.
JSR ECHO ;Output it.
LDA (XAML,X) ;Get data byte at 'examine index".
JSR PRBYTE ;Output it in hex format.
XAMNEXT STX MODE ;0-> MODE (XAM mode).
LDA XAML
CMP L ;Compare 'examine index" to hex data.
LDA XAMH
SBC H
BCS TONEXTITEM ;Not less, so no more data to output.
INC XAML
BNE MOD8CHK ;Increment 'examine index".
INC XAMH
MOD8CHK LDA XAML ;Check low-order 'exainine index' byte
AND #$0F ;For MOD 8=0 ** changed to $0F to get 16 values per row **
BPL NXTPRNT ;Always taken.
PRBYTE PHA ;Save A for LSD.
LSR
LSR
LSR ;MSD to LSD position.
LSR
JSR PRHEX ;Output hex digit.
PLA ;Restore A.
PRHEX AND #$0F ;Mask LSD for hex print.
ORA #$B0 ;Add "0".
CMP #$BA ;Digit?
BCC ECHO ;Yes, output it.
ADC #$06 ;Add offset for letter.
ECHO PHA ;*Save A
AND #$7F ;*Change to "standard ASCII"
STA ACIA_DAT ;*Send it.
jsr Delay ; try delay
WAIT LDA ACIA_SR ;*Load status register for ACIA
AND #$10 ;*Mask bit 4.
BEQ WAIT ;*ACIA not done yet, wait.
PLA ;*Restore A
RTS ;*Done, over and out...
SHWMSG LDY #$0
PRINT LDA (MSGL),Y
BEQ DONEX
JSR ECHO
INY
BNE PRINT
DONEX RTS
;Interrupt Service Routines
IRQ_ISA SEI
PHA
PHX
PHY
;actual routine
PLY
PLX
PLA
CLI
RTI
;
NMI_ISA SEI
PHA
PHX
PHY
;actual routine
PLY
PLX
PLA
CLI
RTI
;=========================================================================
;
;
; CRC subroutines
;
;
UpdCrc eor crc+1 ; Quick CRC computation with lookup tables
tax ; updates the two bytes at crc & crc+1
lda crc ; with the byte send in the "A" register
eor CRCHI,X
sta crc+1
lda CRCLO,X
sta crc
rts
;
; The following tables are used to calculate the CRC for the 128 bytes
; in the xmodem data blocks. You can use these tables if you plan to
; store this program in ROM. If you choose to build them at run-time,
; then just delete them and define the two labels: crclo & crchi.
;
; low byte CRC lookup table (should be page aligned)
*= $ED00
crclo
.lobyte $00,$21,$42,$63,$84,$A5,$C6,$E7,$08,$29,$4A,$6B,$8C,$AD,$CE,$EF
.lobyte $31,$10,$73,$52,$B5,$94,$F7,$D6,$39,$18,$7B,$5A,$BD,$9C,$FF,$DE
.lobyte $62,$43,$20,$01,$E6,$C7,$A4,$85,$6A,$4B,$28,$09,$EE,$CF,$AC,$8D
.lobyte $53,$72,$11,$30,$D7,$F6,$95,$B4,$5B,$7A,$19,$38,$DF,$FE,$9D,$BC
.lobyte $C4,$E5,$86,$A7,$40,$61,$02,$23,$CC,$ED,$8E,$AF,$48,$69,$0A,$2B
.lobyte $F5,$D4,$B7,$96,$71,$50,$33,$12,$FD,$DC,$BF,$9E,$79,$58,$3B,$1A
.lobyte $A6,$87,$E4,$C5,$22,$03,$60,$41,$AE,$8F,$EC,$CD,$2A,$0B,$68,$49
.lobyte $97,$B6,$D5,$F4,$13,$32,$51,$70,$9F,$BE,$DD,$FC,$1B,$3A,$59,$78
.lobyte $88,$A9,$CA,$EB,$0C,$2D,$4E,$6F,$80,$A1,$C2,$E3,$04,$25,$46,$67
.lobyte $B9,$98,$FB,$DA,$3D,$1C,$7F,$5E,$B1,$90,$F3,$D2,$35,$14,$77,$56
.lobyte $EA,$CB,$A8,$89,$6E,$4F,$2C,$0D,$E2,$C3,$A0,$81,$66,$47,$24,$05
.lobyte $DB,$FA,$99,$B8,$5F,$7E,$1D,$3C,$D3,$F2,$91,$B0,$57,$76,$15,$34
.lobyte $4C,$6D,$0E,$2F,$C8,$E9,$8A,$AB,$44,$65,$06,$27,$C0,$E1,$82,$A3
.lobyte $7D,$5C,$3F,$1E,$F9,$D8,$BB,$9A,$75,$54,$37,$16,$F1,$D0,$B3,$92
.lobyte $2E,$0F,$6C,$4D,$AA,$8B,$E8,$C9,$26,$07,$64,$45,$A2,$83,$E0,$C1
.lobyte $1F,$3E,$5D,$7C,$9B,$BA,$D9,$F8,$17,$36,$55,$74,$93,$B2,$D1,$F0
; hi byte CRC lookup table (should be page aligned)
*= $EE00
crchi
.lobyte $00,$10,$20,$30,$40,$50,$60,$70,$81,$91,$A1,$B1,$C1,$D1,$E1,$F1
.lobyte $12,$02,$32,$22,$52,$42,$72,$62,$93,$83,$B3,$A3,$D3,$C3,$F3,$E3
.lobyte $24,$34,$04,$14,$64,$74,$44,$54,$A5,$B5,$85,$95,$E5,$F5,$C5,$D5
.lobyte $36,$26,$16,$06,$76,$66,$56,$46,$B7,$A7,$97,$87,$F7,$E7,$D7,$C7
.lobyte $48,$58,$68,$78,$08,$18,$28,$38,$C9,$D9,$E9,$F9,$89,$99,$A9,$B9
.lobyte $5A,$4A,$7A,$6A,$1A,$0A,$3A,$2A,$DB,$CB,$FB,$EB,$9B,$8B,$BB,$AB
.lobyte $6C,$7C,$4C,$5C,$2C,$3C,$0C,$1C,$ED,$FD,$CD,$DD,$AD,$BD,$8D,$9D
.lobyte $7E,$6E,$5E,$4E,$3E,$2E,$1E,$0E,$FF,$EF,$DF,$CF,$BF,$AF,$9F,$8F
.lobyte $91,$81,$B1,$A1,$D1,$C1,$F1,$E1,$10,$00,$30,$20,$50,$40,$70,$60
.lobyte $83,$93,$A3,$B3,$C3,$D3,$E3,$F3,$02,$12,$22,$32,$42,$52,$62,$72
.lobyte $B5,$A5,$95,$85,$F5,$E5,$D5,$C5,$34,$24,$14,$04,$74,$64,$54,$44
.lobyte $A7,$B7,$87,$97,$E7,$F7,$C7,$D7,$26,$36,$06,$16,$66,$76,$46,$56
.lobyte $D9,$C9,$F9,$E9,$99,$89,$B9,$A9,$58,$48,$78,$68,$18,$08,$38,$28
.lobyte $CB,$DB,$EB,$FB,$8B,$9B,$AB,$BB,$4A,$5A,$6A,$7A,$0A,$1A,$2A,$3A
.lobyte $FD,$ED,$DD,$CD,$BD,$AD,$9D,$8D,$7C,$6C,$5C,$4C,$3C,$2C,$1C,$0C
.lobyte $EF,$FF,$CF,$DF,$AF,$BF,$8F,$9F,$6E,$7E,$4E,$5E,$2E,$3E,$0E,$1E
;
; End of File
;*****************************************************
; Delay
;
; Delay For 65535 Cycles
;
;*****************************************************
Delay
phx
phy
ldy #$8F ; restore to #$00
AL2 ldx #$05 ; restore to #$00
AL1 dex
bne AL1
dey
bne AL2
ply
plx
rts
;
MSG1 .textz "Welcome to JSMON 2.0."
MSG2 .textz "Start Intel Hex Transfer."
MSG3 .textz "Intel Hex Imported."
MSG4 .textz "Intel Hex Imported with error."
MSG5 .textz "Sweet16 Enabled at JSR $C020" ;modify accordingly
.ORG $FFFA
NMI_VEC .word NMI_ISA ;IRQ vector
RESET_VEC .word RESET ;RESET vector $C33F
IRQ_VEC .word IRQ_ISA ;IRQ vector