User Tools

Site Tools


base:threads_on_the_6502

Threads on the 6502

By Gregg.

Threads on the 6502, at first this might sound to be a little useless on the 6502 or inefficient to implement. But in fact, utilizing the stack, it is really easy, and has quite a few uses. Sometimes it can make code more elegant too.

In this example two threads will be initiated which will use different stack areas. Using a round-robin scheduler running in an irq (context_switch) these threads are ran one after the other. The thread data is stored on the stack, suitably for RTI, so you only need to manually push the register (A, X, Y) values. In the end it comes down to adjusting the stack pointer for each thread. The stack pointer of each thread is stored starting at thread_data.

num_threads = 2
thread_num = $fd		; current thread number

;--------------------------------------------------------------------------
		*= $0801
		!byte <.eol,>.eol,0,0,$9e
		!text "2061"
.eol:	!byte 0,0,0


*= $080d

init:	sei
		
		lda #<context_switch
		ldx #>context_switch
		sta $0314
		stx $0315
		
		; initialize threads
		ldx #0
		stx thread_num
		
		; main thread is automatically setup by first irq
		; we only need to setup further threads
		; split stack
		tsx
		txa
		tay
		sec
		sbc #$20
		tax
		txs
		
		; push thread data
		; program counter, status register, a, x, y
		lda #>thread2
		pha
		lda #<thread2
		pha
		lda #0
		pha
		pha
		pha
		pha
		
		; save stack pointer
		tsx
		txa
		sta thread_data+1
		
		; restore old stack pointer
		tya
		tax
		txs

		cli
		; go to main thread
		jmp thread1

;--------------------------------------------------------------------------
; if you're not using the kernal don't forget to save/restore A, X, Y *using the stack*!
context_switch:
		; save stack pointer
		ldy thread_num
		tsx
		txa
		sta thread_data,y
		
		; next thread, wraparound
		iny
		cpy #num_threads
		bne nowrap
		ldy #0
nowrap:
		sty thread_num
		
		; restore thread
		lda thread_data,y
		tax
		txs

		jmp $ea31

;--------------------------------------------------------------------------
; thread 1 switches the border color
thread1:
		inc $d020
		ldy #$01
		jsr wait2
		jmp thread1


; thread 2 displays a text message
thread2:
		lda #<msg1
		ldy #>msg1
		jsr $ab1e
		ldy #0
		jsr wait2
		jmp thread2

; delay a shitload of cycles
wait2:
-		ldx #0
		dex
		bne *-1
		dey
		bne -
		rts

;--------------------------------------------------------------------------
msg1:	!pet "hello, here is thread 2!",13,0
thread_data:

If you don't want to split the stack area (maybe a routine will use lots of stack or you want to use lots of threads) then it's possible to store and refresh the stack area for each thread context.

Using the NMI can also free up the normal IRQ.

base/threads_on_the_6502.txt · Last modified: 2015-04-17 04:34 (external edit)