mirror of
https://github.com/mnaberez/py65.git
synced 2025-01-04 16:30:42 +00:00
adding examples including hexloader boot rom
This commit is contained in:
parent
10f6681798
commit
57d5e71913
235
examples/65Org16.boot.asm
Normal file
235
examples/65Org16.boot.asm
Normal file
@ -0,0 +1,235 @@
|
||||
.LIST
|
||||
|
||||
; bootrom for py65 monitor in 65Org16 mode
|
||||
; based on
|
||||
; Intel Hex format loader by Ross Archer (9 February 2001, freeware)
|
||||
; from http: http://www.6502.org/source/monitors/intelhex/intelhex.htm
|
||||
;
|
||||
|
||||
; use this monitor like this:
|
||||
; PYTHONPATH=. python py65/monitor.py -m 65Org16
|
||||
; load bootrom.bin fe00
|
||||
; goto fe00
|
||||
|
||||
START = $FFFFFe00
|
||||
|
||||
; I/O is memory-mapped in py65:
|
||||
PUTC = $f001
|
||||
GETC = $f005 ; blocking input
|
||||
|
||||
; Note that Hex format for 65Org16 uses ';' not ':' as the start of record mark
|
||||
; also note that some fields are now composed of 16-bit elements:
|
||||
; previously:
|
||||
; length offset type data checksum
|
||||
; :/08/E008/00/08090A0B0C0D0E0F/xx
|
||||
; now
|
||||
; ;/10/E008/00/00080009000A000B000C000D000E000F/xx
|
||||
|
||||
; Zero-page storage
|
||||
DPL = $00 ; data pointer (two bytes) used by PUTSTRI
|
||||
DPH = $01 ; high of data pointer
|
||||
RECLEN = $02 ; record length in bytes
|
||||
START_LO = $03
|
||||
START_HI = $04
|
||||
RECTYPE = $05
|
||||
CHKSUM = $06 ; record checksum accumulator
|
||||
DLFAIL = $07 ; flag for download failure
|
||||
TEMP = $08 ; save hex value
|
||||
TMPHEX = $09 ; save another hex value
|
||||
|
||||
; where the RAM program MUST have its first instruction
|
||||
ENTRY_POINT = $0200
|
||||
|
||||
.ORG START
|
||||
|
||||
sei ; disable interrupts
|
||||
cld ; binary mode arithmetic
|
||||
ldx #$1FFFF ; Set up the stack pointer
|
||||
txs ; "
|
||||
|
||||
; Download Intel hex. The program you download MUST have its entry
|
||||
; instruction (even if only a jump to somewhere else) at ENTRY_POINT.
|
||||
HEXDNLD lda #0
|
||||
sta START_HI ; store all programs in bank 0 (page 0) for now
|
||||
sta DLFAIL ;Start by assuming no D/L failure
|
||||
jsr PUTSTRI
|
||||
.byte 13,10,13,10
|
||||
.byte "Send 65Org16 code in"
|
||||
.byte " variant Intel Hex format"
|
||||
.byte " at 19200,n,8,1 ->"
|
||||
.byte 13,10
|
||||
.byte 0 ; Null-terminate unless you prefer to crash.
|
||||
HDWRECS jsr GETSER ; Wait for start of record mark ';'
|
||||
cmp #';'
|
||||
bne HDWRECS ; not found yet
|
||||
; Start of record marker has been found
|
||||
lda #0
|
||||
sta CHKSUM
|
||||
jsr GETHEX ; Get the record length
|
||||
sta RECLEN ; save it
|
||||
jsr GET4HX ; Get the 16-bit offset
|
||||
sta START_LO
|
||||
jsr GETHEX ; Get the record type
|
||||
sta RECTYPE ; & save it
|
||||
bne HDER1 ; end-of-record
|
||||
ldx RECLEN ; number of data bytes to write to memory
|
||||
ldy #0 ; start offset at 0
|
||||
HDLP1 jsr GET4HX ; Get the first/next/last data word
|
||||
sta (START_LO),y ; Save it to RAM
|
||||
iny ; update data pointer
|
||||
dex ; decrement character count
|
||||
dex ; ... twice
|
||||
bne HDLP1
|
||||
jsr GETHEX ; get the checksum
|
||||
lda CHKSUM
|
||||
bne HDDLF1 ; If failed, report it
|
||||
; Another successful record has been processed
|
||||
lda #'#' ; Character indicating record OK = '#'
|
||||
sta PUTC ; write it out but don't wait for output
|
||||
jmp HDWRECS ; get next record
|
||||
HDDLF1 lda #'F' ; Character indicating record failure = 'F'
|
||||
sta DLFAIL ; download failed if non-zero
|
||||
sta PUTC ; write it to transmit buffer register
|
||||
jmp HDWRECS ; wait for next record start
|
||||
HDER1 cmp #1 ; Check for end-of-record type
|
||||
beq HDER2
|
||||
jsr PUTSTRI ; Warn user of unknown record type
|
||||
.byte 13,10,13,10
|
||||
.byte "Unknown record type $"
|
||||
.byte 0 ; null-terminate unless you prefer to crash!
|
||||
lda RECTYPE ; Get it
|
||||
sta DLFAIL ; non-zero --> download has failed
|
||||
jsr PUTHEX ; print it
|
||||
lda #13 ; but we'll let it finish so as not to
|
||||
jsr PUTSER ; falsely start a new d/l from existing
|
||||
lda #10 ; file that may still be coming in for
|
||||
jsr PUTSER ; quite some time yet.
|
||||
jmp HDWRECS
|
||||
; We've reached the end-of-record record
|
||||
HDER2 jsr GETHEX ; get the checksum
|
||||
lda CHKSUM ; Add previous checksum accumulator value
|
||||
beq HDER3 ; checksum = 0 means we're OK!
|
||||
jsr PUTSTRI ; Warn user of bad checksum
|
||||
.byte 13,10,13,10
|
||||
.byte "Bad record checksum!",13,10
|
||||
.byte 0 ; Null-terminate or 6502 go bye-bye
|
||||
jmp START
|
||||
HDER3 lda DLFAIL
|
||||
beq HDEROK
|
||||
;A download failure has occurred
|
||||
jsr PUTSTRI
|
||||
.byte 13,10,13,10
|
||||
.byte "Download Failed",13,10
|
||||
.byte "Aborting!",13,10
|
||||
.byte 0 ; null-terminate every string yada yada.
|
||||
jmp START
|
||||
HDEROK jsr PUTSTRI
|
||||
.byte 13,10,13,10
|
||||
.byte "Download Successful!",13,10
|
||||
.byte "Jumping to location $"
|
||||
.byte 0 ; by now, I figure you know what this is for. :)
|
||||
lda #HI(ENTRY_POINT) ; Print the entry point in hex
|
||||
jsr PUTHEX
|
||||
lda #LO(ENTRY_POINT)
|
||||
jsr PUTHEX
|
||||
jsr PUTSTRI
|
||||
.byte 13,10
|
||||
.byte 0 ; stop lemming-like march of the program ctr. thru data
|
||||
jmp ENTRY_POINT ; jump to canonical entry point
|
||||
|
||||
; For py65, the input routine will block until a character arrives
|
||||
GETSER lda GETC
|
||||
rts
|
||||
|
||||
; get four ascii chars, adding both octets into the checksum
|
||||
GET4HX jsr GETHEX
|
||||
asl a
|
||||
asl a
|
||||
asl a
|
||||
asl a
|
||||
asl a
|
||||
asl a
|
||||
asl a
|
||||
asl a
|
||||
sta TMPHEX
|
||||
jsr GETHEX
|
||||
ora TMPHEX
|
||||
rts
|
||||
|
||||
; get two ascii chars, add into the checksum
|
||||
GETHEX jsr GETSER
|
||||
jsr MKNIBL ; Convert to 0..F numeric
|
||||
asl a
|
||||
asl a
|
||||
asl a
|
||||
asl a ; This is the upper nibble
|
||||
and #$F0
|
||||
sta TEMP
|
||||
jsr GETSER
|
||||
jsr MKNIBL
|
||||
ora TEMP
|
||||
sta TEMP
|
||||
clc
|
||||
adc CHKSUM ; Add in the checksum
|
||||
and #$ff
|
||||
sta CHKSUM ;
|
||||
lda TEMP
|
||||
rts ; return with the nibble received
|
||||
|
||||
; Convert the ASCII nibble to numeric value from 0-F:
|
||||
MKNIBL cmp #'9'+1 ; See if it's 0-9 or 'A'..'F' (no lowercase yet)
|
||||
bcc MKNNH ; If we borrowed, we lost the carry so 0..9
|
||||
sbc #7+1 ; Subtract off extra 7 (sbc subtracts off one less)
|
||||
; If we fall through, carry is set unlike direct entry at MKNNH
|
||||
MKNNH sbc #'0'-1 ; subtract off '0' (if carry clear coming in)
|
||||
and #$0F ; no upper nibble no matter what
|
||||
rts ; and return the nibble
|
||||
|
||||
; Put byte in A as hexydecascii
|
||||
PUTHEX pha ;
|
||||
lsr a
|
||||
lsr a
|
||||
lsr a
|
||||
lsr a
|
||||
jsr PRNIBL
|
||||
pla
|
||||
PRNIBL and #$0F ; strip off the low nibble
|
||||
cmp #$0A
|
||||
bcc NOTHEX ; if it's 0-9, add '0' else also add 7
|
||||
adc #6 ; Add 7 (6+carry=1), result will be carry clear
|
||||
NOTHEX adc #'0' ; If carry clear, we're 0-9
|
||||
; Write the character in A as ASCII:
|
||||
PUTSER sta PUTC
|
||||
rts
|
||||
|
||||
;Put the string following in-line until a NULL out to the console
|
||||
PUTSTRI pla ; Get the low part of "return" address (data start address)
|
||||
sta DPL
|
||||
pla
|
||||
sta DPH ; Get the high part of "return" address
|
||||
; (data start address)
|
||||
; Note: actually we're pointing one short
|
||||
PSINB ldy #1
|
||||
lda (DPL),y ; Get the next string character
|
||||
inc DPL ; update the pointer
|
||||
bne PSICHO ; if not, we're pointing to next character
|
||||
inc DPH ; account for page crossing
|
||||
PSICHO ora #0 ; Set flags according to contents of Accumulator
|
||||
beq PSIX1 ; don't print the final NULL
|
||||
jsr PUTSER ; write it out
|
||||
jmp PSINB ; back around
|
||||
PSIX1 inc DPL ;
|
||||
bne PSIX2 ;
|
||||
inc DPH ; account for page crossing
|
||||
PSIX2 jmp (DPL) ; return to byte following final NULL
|
||||
;
|
||||
; Dummy interrupt handlers
|
||||
GOIRQ
|
||||
GONMI RTI
|
||||
|
||||
; vectors
|
||||
.ORG $FFFFFFFA
|
||||
NMIENT .word GONMI
|
||||
RSTENT .word START
|
||||
IRQENT .word GOIRQ
|
||||
.end ; finally. das Ende.
|
BIN
examples/65Org16.boot.rom
Normal file
BIN
examples/65Org16.boot.rom
Normal file
Binary file not shown.
12
examples/README.txt
Normal file
12
examples/README.txt
Normal file
@ -0,0 +1,12 @@
|
||||
Some example code and usage:
|
||||
|
||||
For linux:
|
||||
|
||||
(no need to install or build - just unpack)
|
||||
|
||||
$ cd src
|
||||
$ env PYTHONPATH=. python py65/monitor.py -m 65Org16 -r ../examples/65Org16.boot.rom
|
||||
|
||||
Then paste in a hex file, such as ../examples/swapcase.hex
|
||||
|
||||
(Type in some mixed-case input and it will echo it back with the upper and lowercase swapped)
|
28
examples/swapcase.asm
Normal file
28
examples/swapcase.asm
Normal file
@ -0,0 +1,28 @@
|
||||
; trivial demo program: read input, swap case and write out
|
||||
|
||||
; assemble using Anton Treuenfels' HXA assembler
|
||||
; with I6502.A macro file
|
||||
; HXA_TW.EXE swapcase.asm
|
||||
; (runs on Linux if you have WINE installed)
|
||||
; which will make
|
||||
; SWAPCASE.HEX
|
||||
; where the first line should not be input to the hexloader
|
||||
|
||||
.hexfile
|
||||
|
||||
.cpu T_32_M16
|
||||
.assume BIT32=1032, BIT32R=3210
|
||||
.include "i6502.a"
|
||||
|
||||
; I/O is memory-mapped in py65:
|
||||
PUTC = $f001
|
||||
GETC = $f005 ; blocking input
|
||||
|
||||
; the py65 hexload boot ROM will only load to $0200
|
||||
.ORG $200
|
||||
|
||||
another
|
||||
lda GETC
|
||||
eor #$20 ; swap upper and lower case as a demo
|
||||
sta PUTC
|
||||
jmp another
|
3
examples/swapcase.hex
Normal file
3
examples/swapcase.hex
Normal file
@ -0,0 +1,3 @@
|
||||
;020000040000FA
|
||||
;1202000000A5F005004900200085F001004C0200000025
|
||||
;00000001FF
|
Loading…
Reference in New Issue
Block a user