User Tools

Site Tools


base:threads_on_the_6502

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

base:threads_on_the_6502 [2015-04-17 04:34] (current)
Line 1: Line 1:
 +====== 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.
 +
 +<​code>​
 +
 +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:​
 +</​code>​
 +
 +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)