| | gregg Account closed
Registered: Apr 2005 Posts: 56 |
Some sort of multithreading.
About a week ago the topic multithreading came up on #c-64. So today I gave it a try. However, there's something wrong with my code and I can't really figure out what it is.
A short description: I have a fixed number of threads running and a CIA IRQ deals with context switching in a round-robin fashion. Every IRQ I save all current state data (SP, status register, PC, A, X, Y) in a structure and fetch the state data for the next thread.
In this example the first thread increments the screen background color (fast), while the second thread changes the border background color (slow). However the wait in the second thread runs too fast every other time, and I have no idea why. It's probably something wrong with the context switch stuff, maybe some of you could take a look at it?
Sources are for ACME.
!to "threading.prg",cbm
!cpu 6510
;!source "mylib.a"
!macro basic_header .a, .b, .c, .d {
*= $0801
!byte <.eol,>.eol,0,0,$9e
!text .a, .b, .c, .d
.eol: !byte 0,0,0
}
num_threads = 2
thread_num = $fd ; current thread number
;--------------------------------------------------------------------------
+basic_header "2", "0", "6", "1"
*= $080d
init: sei
; set up context switch IRQ
lda #$35
sta $01
lda #<context_switch
ldx #>context_switch
sta $fffe
stx $ffff
lda #0
sta thread_num
cli
jmp thread1
;--------------------------------------------------------------------------
context_switch:
pha
txa
pha
tya
pha
lda $dc0d
; save current thread
lda thread_num
; *8
asl
asl
asl
tay
; save A,X,Y
pla
sta thread_data+6,y
pla
sta thread_data+5,y
pla
sta thread_data+4,y
; save PSW
pla
sta thread_data+1,y
; save PC
pla
sta thread_data+2,y
pla
sta thread_data+3,y
; save SP
tsx
txa
sta thread_data,y
; next thread, wraparound
ldy thread_num
iny
cpy #num_threads
bne +
ldy #0
+ sty thread_num
; *8
tya
asl
asl
asl
tay
; restore thread data
; stack pointer first
lda thread_data,y
tax
txs
; push PC, PSW for RTI
lda thread_data+3,y
pha
lda thread_data+2,y
pha
lda thread_data+1,y
pha
; push registers
lda thread_data+6,y
pha
lda thread_data+5,y
pha
lda thread_data+4,y
pha
pla
tay
pla
tax
pla
rti
;--------------------------------------------------------------------------
thread1:
inc $d021
ldy #$02
jsr wait2
jmp thread1
thread2:
inc $d020
ldy #$80
jsr wait2
jmp thread2
wait2:
- ldx #0
dex
bne *-1
dey
bne -
rts
;--------------------------------------------------------------------------
thread_data:
!fill 8, 0
!byte $ff-$40, $22, <thread2, >thread2, 0,0,0,0
|
|
... 211 posts hidden. Click here to view all posts.... |
| | chatGPZ
Registered: Dec 2001 Posts: 11386 |
you have an interisting definition of trolling, really :) |
| | gregg Account closed
Registered: Apr 2005 Posts: 56 |
The effect thread interrupts the main thread without any knowledge or consent of it. And that's by definition how preemption works (see WP for example). |
| | Oswald
Registered: Apr 2002 Posts: 5094 |
Quote: you have an interisting definition of trolling, really :)
and you have childish arguments, and trolling techniques. :) |
| | gregg Account closed
Registered: Apr 2005 Posts: 56 |
Please use 4chan for all your trolling needs! (Or heise.de for ze Germans) |
| | Oswald
Registered: Apr 2002 Posts: 5094 |
Quote: The effect thread interrupts the main thread without any knowledge or consent of it. And that's by definition how preemption works (see WP for example).
but it gives back control by own will which is cooperative. also threads does not preempt/return to other threads by own will. also threads has own context, stack, etc, which an interrupt clearly does not have. its just an interrupt not a thread. |
| | Laxity
Registered: Aug 2005 Posts: 459 |
One argument in Oswalds favor could be that the effect "thread" locks the system thread until it's done and then returns, so it's actually not preemtive multithreading. For it to be preemtive, it would have to be interrupted by the system for the main thread to run. It's not Cooperative multithreading either, because the main thread do not relinquish the system resources for the effect thread to run (unless you'd like to argument that the IRQ does that for it). It's not one nor the other. I doubt it would be considered multithreading. Dualthreading at most :)
That said, the concept of writing a multithreading kernel for the C64 is a very interesting concept. I'm not sure how useful it is (I lack the imagination for that, I guess), but it's really neat. Isn't there going to be some problems with stack in your implementation, Gregg?.. I mean, the more threads you add, the less stack there'd be free for each thread, correct?.. And copying the complete stack per thread (plus state) is going to be expensive in terms of both memory usage and CPU time spend on task switching... Hmm..
EDIT: Didn't see your previous reply, Dr. O.. So in fact we agree on this :) |
| | gregg Account closed
Registered: Apr 2005 Posts: 56 |
Quote: Isn't there going to be some problems with stack in your implementation, Gregg?.. I mean, the more threads you add, the less stack there'd be free for each thread, correct?..
Yes, I'm simply moving the stack pointer down by a fixed amount for each thread. This limits the the number of threads as well as the maximum recursion depth, but I don't think either will be a real issue on the c64... this is meant to be used for a handful of threads, not dozens and dozens of threads.
Quote:And copying the complete stack per thread (plus state) is going to be expensive in terms of both memory usage and CPU time spend on task switching...
I'm not copying the stack, but merely changing the stack pointer. The initialization only pushes initial thread data onto the stack, to make it possible to actually start it. |
| | Laxity
Registered: Aug 2005 Posts: 459 |
Quote: Quote: Isn't there going to be some problems with stack in your implementation, Gregg?.. I mean, the more threads you add, the less stack there'd be free for each thread, correct?..
Yes, I'm simply moving the stack pointer down by a fixed amount for each thread. This limits the the number of threads as well as the maximum recursion depth, but I don't think either will be a real issue on the c64... this is meant to be used for a handful of threads, not dozens and dozens of threads.
Quote:And copying the complete stack per thread (plus state) is going to be expensive in terms of both memory usage and CPU time spend on task switching...
I'm not copying the stack, but merely changing the stack pointer. The initialization only pushes initial thread data onto the stack, to make it possible to actually start it.
Yeah, I know you aren't copying the stack (I did look at the code, you know :)= ).. I was thinking that the implications of doing so would be relatively severe (on this system). The current implementation would enforce limitations on each thread. Effectively this means that adding a thread can result in previously added threads to stop working if they rely on a serain amount of the stack frame (if the stack is divided in to equal size per thread). |
| | gregg Account closed
Registered: Apr 2005 Posts: 56 |
Yeah, but I hope you're not going to seriously use recursion for algorithms on the c64, are you? :p I doubt this ever becomes a real problem. Even the tiny stack offset of $20 bytes allows a recursion depth (JSR) of 13... that's quite enough :) |
| | Krill
Registered: Apr 2002 Posts: 2980 |
Quote: but it gives back control by own will which is cooperative. also threads does not preempt/return to other threads by own will. also threads has own context, stack, etc, which an interrupt clearly does not have. its just an interrupt not a thread.
What are you nitpicking about anyways?
It is a fact that everything described here is some sort of multithreading. The details as to whether, e.g., who is in charge of what, or whether a thread has a complete own stack on its own or not, are not relevant.
Also pretty many embedded systems, among others, implement preemptive multithreading using timer interrupts and then switch states "manually".
Furthermore, there is any number of variations for multithreading in general, as to what is static, what is shared or private, et cetera.
That said, multithreading on C64 is neither expensive nor useless. I have used it myself here and there, and generic/elegant solutions are not bound to be expensive. |
Previous - 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | ... | 22 | 23 - Next | |