[Return to Main Page]

Interrupt-Serviced 256-Byte Data Buffer from 6502 Applications
[Up to Source Code Repository]

Interrupt-Serviced 256-Byte Data Buffer

An Interrupt-Serviced 256-Byte Data Buffer in 6502 assembly lanauge.
By Lee Davison (leeedavison@googlemail.com), 19 October 2000.

    ; code for an interrupt serviced data buffer. similar code is used to drive the XY
    ; stepper motors on a plotter with new position information every 5mS and also to
    ; allow pen up/down movement time of 70mS

                    *= $B000        ; set origin (buffer and variables must be in RAM)

    Buffer				; 256 byte buffer (must start at page edge)
    	.word	$0000,$0000,$0000,$0000,$0000,$0000,$0000,$0000
    	.word	$0000,$0000,$0000,$0000,$0000,$0000,$0000,$0000
    	.word	$0000,$0000,$0000,$0000,$0000,$0000,$0000,$0000
    	.word	$0000,$0000,$0000,$0000,$0000,$0000,$0000,$0000
    	.word	$0000,$0000,$0000,$0000,$0000,$0000,$0000,$0000
    	.word	$0000,$0000,$0000,$0000,$0000,$0000,$0000,$0000
    	.word	$0000,$0000,$0000,$0000,$0000,$0000,$0000,$0000
    	.word	$0000,$0000,$0000,$0000,$0000,$0000,$0000,$0000
    	.word	$0000,$0000,$0000,$0000,$0000,$0000,$0000,$0000
    	.word	$0000,$0000,$0000,$0000,$0000,$0000,$0000,$0000
    	.word	$0000,$0000,$0000,$0000,$0000,$0000,$0000,$0000
    	.word	$0000,$0000,$0000,$0000,$0000,$0000,$0000,$0000
    	.word	$0000,$0000,$0000,$0000,$0000,$0000,$0000,$0000
    	.word	$0000,$0000,$0000,$0000,$0000,$0000,$0000,$0000
    	.word	$0000,$0000,$0000,$0000,$0000,$0000,$0000,$0000
    	.word	$0000,$0000,$0000,$0000,$0000,$0000,$0000,$0000

    BRindx				; buffer read index
    	.byte $00

    BWindx				; buffer write index
    	.byte $00

    Sendf                           ; am sending flag
    	.byte $00

    WByte                           ; temp store for the byte to be sent
    	.byte $00

    ; write the data to the buffer a byte at a time and increment the pointer.
    ; the routine is called with the byte to write in A. If the interrupt device
    ; is idle when this routine is called it will wake it up by doing a BRK
    ; before it exits
    ;
    ; destroys the Y register

    		*= $C000	; set origin (can be ROM or RAM)

    Incwritb
    	STA	WByte		; save byte to write
    	LDA	BRindx		; get read index
            SEC                     ; set carry for subtract
    	SBC	BWindx		; subtract write index
    	BEQ	Dowrite		; if equal then buffer empty so do write
    	CMP	#$02		; need at least n+1 bytes to avoid rollover
    	BCC	Incwritb	; loop if no space

                                    ; construct and write data to buffer
    Dowrite
    	LDY	BWindx		; get write index
    	LDA	WByte		; get byte to write
    	STA	Buffer,Y	; save it
            INY                     ; increment index to next byte
    	STY	BWindx		; save new write index byte

    ; now see if the interrupt service routine is already running or if it's idle

    	LDA	Sendf		; get the sending flag
    	BNE	Doingit		; skip call if running
            BRK                     ; software call to interrupt routine
            NOP                     ; need this as return from BRK is +1 byte!
            CLI                     ; enable the interrupts

    Doingit
    	RTS

    ; this is the interrupt service routine. takes a byte a time from the buffer
    ; and does some thing with it. also sets up the device(s) for the next interrupt

    ; no registers altered

    BuffIRQ
            PHA                     ; save A
            TXA                     ; copy X
            PHA                     ; save X
            TYA                     ; copy Y
            PHA                     ; save Y

    ; insert code here to ensure this is the interrupt you want. if it isn't then just exit
    ; quietly via ResExit the end of the routine

    Getnext
    	JSR	Increadb	; increment pointer and read byte from buffer
    	BCS	ExitIRQ		; branch if no byte to do

    ; here would be the guts of the routine such as sending the byte to the ACIA or a
    ; printer port or some other byte device. it will also ensure the device is set to
    ; generate an interrupt when it's completed it's task

    	LDA	#$FF		; set byte
    	STA	Sendf		; set sending flag
    	JMP	ResExit		; restore the registers & exit

                                    ; all done so clear the flag restore the regs & exit
    ExitIRQ
            LDA     #$00            ; clear byte
    	STA	Sendf		; clear sending flag

    ResExit
            PLA                     ; pull Y
            TAY                     ; restore it
            PLA                     ; pull X
            TAX                     ; restore it
            PLA                     ; restore A
            RTI                     ; this was an interrupt service so exit properly

    ; get byte from the buffer and increment the pointer. If the buffer is empty then
    ; exit with the carry flag set else exit with carry clear and the byte in A

    Increadb
    	LDY	BRindx		; get buffer read index
    	CPY	BWindx		; compare write index
    	BEQ	NOktoread	; branch if empty (= sets carry)
    	LDA	Buffer,Y	; get byte from buffer
            INY                     ; increment pointer
    	STY	BRindx		; save buffer read index
            CLC                     ; clear not ok flag

    NOktoread
    	RTS

Last page update: October 27, 2000.