Log inRegister an accountBrowse CSDbHelp & documentationFacts & StatisticsThe forumsAvailable RSS-feeds on CSDbSupport CSDb Commodore 64 Scene Database
You are not logged in - nap
CSDb User Forums


Forums > C64 Coding > Some sort of multithreading.
2008-04-08 22:51
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....
 
2008-04-13 13:17
Krill

Registered: Apr 2002
Posts: 2871
Did you deliberately grossly mix up the terms now?
2008-04-13 13:18
Oswald

Registered: Apr 2002
Posts: 5034
Krill, well if you say that interrupts are threads, then I'm with you. then the c64 OS is multithreading, doesnt it ?
2008-04-13 13:22
trident

Registered: May 2002
Posts: 85
Quote: 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 :)


A main program + IRQ is actually preemptive multithreading with priorities and two threads - even though we may not see this at first, because we are so accustomed to viewing this as "a main program and an IRQ" and tend to think of multithreading as something difficult, costly, and heavyweight (which it isn't). The IRQ thread has a higher priority than the main thread, so the IRQ thread preempts it. The main thread has a lower priority than the IRQ thread, so the IRQ thread is never preempted, but runs to completion.

Oswald: by adding the cli instruction in your IRQ handler, you make the IRQ preemptible. Thus you potentially have more than two threads: additional IRQs will preempt the IRQ thread (and store its state on the stack).

Here are accepted definitions for these concepts:

Thread = an execution context.
Preemption = a thread is moved off the CPU and another one is moved onto the CPU.
Multithreading = the ability to run multiple threads concurrently or in parallel.

On the 6510, an execution context is the CPU registers and the parts of the stack used by the program. When a thread is preempted (or yields voluntarily) the CPU registers are stored, typically on the thread's stack. An IRQ handler is an execution context. If the IRQ handler is preempted by another IRQ, the CPU registers are stored on the IRQ handler's stack. Since the IRQ handler will never be preempted by the main thread, the IRQ handler's stack can be physically placed on top of the main thread's stack.

The concepts of threads, preemption, stacks, interrupts, and priorities are difficult ones. I grew up with writing code that consisted of a main program + IRQs. It wasn't after thinking about these concepts a lot (and after writing 3-4 multithreading libraries and operating systems) that I understood that I had been doing preemptive multithreading with priorities all along :)

(For those that are interested in this, a highly related concept, which can be even trickier to grasp, is continuations (a continuation is a "snapshot" of a thread): http://en.wikipedia.org/wiki/Continuation http://c2.com/cgi/wiki?ContinuationExplanation )
2008-04-13 13:24
Krill

Registered: Apr 2002
Posts: 2871
The C64 OS, if you refer to the ROM software aka KERNAL, does not have any APIs to set up interrupts or threads. There are some basic hooks and ways to circumvent/disable the ROM routines, but in my book the C64's KERNAL is not multithreaded.

The mere hardware system, with the 6510 and various IRQ sources, is pretty well capable of multithreading.
2008-04-13 13:29
chatGPZ

Registered: Dec 2001
Posts: 11164
adam: now please, if you could tell in simple words whats the difference between a task, a process, and a thread .... it's giving me a headache all the time =P
2008-04-13 13:39
Oswald

Registered: Apr 2002
Posts: 5034
Quote: The C64 OS, if you refer to the ROM software aka KERNAL, does not have any APIs to set up interrupts or threads. There are some basic hooks and ways to circumvent/disable the ROM routines, but in my book the C64's KERNAL is not multithreaded.

The mere hardware system, with the 6510 and various IRQ sources, is pretty well capable of multithreading.


how is my example multithreading then? it does not have any APIs to set up interrupts or threads.
2008-04-13 13:44
Krill

Registered: Apr 2002
Posts: 2871
Oswald: To call an operating system multithreaded implies an API for that. The OS itself may use interrupts or some internal multithreading not accessible to the user, but still can't be called multithreaded from that perspective.

Any self-written code using some multithreading, and be it an OS, is multithreaded even without API.

So yes, sorry for not clearing up the different POVs earlier.
2008-04-13 13:54
trident

Registered: May 2002
Posts: 85
Quote: adam: now please, if you could tell in simple words whats the difference between a task, a process, and a thread .... it's giving me a headache all the time =P

The generally accepted definition of a process is that it is a set of threads (which may include only one thread) and a set of (dedicated) resources: memory, files, etc. So a process is more "heavy-weight" than a thread.

But there is no generally accepted definition of a task... Every system and discipline seems to have its own definition. We can also add the concept of a "job" to the mess and have even more headache... :/
2008-04-13 14:14
Krill

Registered: Apr 2002
Posts: 2871
IMHO, this is all basically the same, only with quite a few overlapping borders depending on implementation and definition.

Though, yes, a little tedious not to have exact 100% agreed and understood definitions, but there are just too many details which matter in one context or not in some other.
2008-04-13 14:22
Oswald

Registered: Apr 2002
Posts: 5034
Gregg&Krill,

IMHO you are forcing strict operating system terms into a context where there is literally no operating system.

threads lives inside processes, and processes lives inside operating systems. the term process/task&thread is meaningless without the context of an operating system. tasks own resources (memory, drivers, windows, etc) provided by the OS, and threads are forks of the given task, with their own resources: stack, register state, etc.

when it comes to the c64 how would you define a bare bone irq as a thread of a process ? how are the resources allocated who provides them? where is the scheduler? somewhere the line has to be drawn, and I'd put it much farer. Handling terms so loosely I could say that subroutines are threads aswell. they preempt the main program with the jsr, save the context to the stack, and the scheduler rts decides to go back... the terms thread/processes were invented with a reason, that being they are different and complex entities inside an OS, not to be mixed up or seriously compared with a barebone enviroment's irq handler or subroutine. Even in an OS context interrupt is a valid term and clearly distuingishable from threads/tasks. so why should we mix up our non OS irqs with threads is over me, if not for the brag effect: "look I'm multithreading".
Previous - 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | ... | 23 - Next
RefreshSubscribe to this thread:

You need to be logged in to post in the forum.

Search the forum:
Search   for   in  
All times are CET.
Search CSDb
Advanced
Users Online
Smasher/F4CG
r242
Mike
polynomy
Dr.j/Delysid
Guests online: 63
Top Demos
1 Next Level  (9.7)
2 13:37  (9.7)
3 Mojo  (9.7)
4 Coma Light 13  (9.7)
5 Edge of Disgrace  (9.6)
6 Uncensored  (9.6)
7 Comaland 100%  (9.6)
8 No Bounds  (9.6)
9 Aliens in Wonderland  (9.6)
10 Wonderland XIV  (9.6)
Top onefile Demos
1 Layers  (9.6)
2 Cubic Dream  (9.6)
3 Party Elk 2  (9.6)
4 Copper Booze  (9.6)
5 Rainbow Connection  (9.5)
6 It's More Fun to Com..  (9.5)
7 Dawnfall V1.1  (9.5)
8 Birth of a Flower  (9.5)
9 Daah, Those Acid Pil..  (9.5)
10 Morph  (9.5)
Top Groups
1 Nostalgia  (9.4)
2 Oxyron  (9.3)
3 Booze Design  (9.3)
4 Censor Design  (9.3)
5 Offence  (9.3)
Top Swappers
1 Derbyshire Ram  (10)
2 Jerry  (9.8)
3 Violator  (9.8)
4 Acidchild  (9.7)
5 Cash  (9.6)

Home - Disclaimer
Copyright © No Name 2001-2024
Page generated in: 0.056 sec.