Oh man...
Oh man...
Okay, first I'm sorry for not putting a CLI and STI where it's
needed But even when I put them there it still has the same
problem. I remarked out the routine that prints a '!' so it's nothing
more than a Start: JMP Start (JMP $) now. And STILL doesn't work.
Sounds like this "spin lock" thing is the key but I don't even know
what a freaken spin lock is! Please bare with me, I'm trying my
hardest and it's 3:45am in the morning. WHY does it work when ran 2
times but on the 3rd DOS stalls? WHAT AM I DOING WRONG?! Eh.
And just when I thought I knew enough to program this code I can't
even get the simple things to work.
needed But even when I put them there it still has the same
problem. I remarked out the routine that prints a '!' so it's nothing
more than a Start: JMP Start (JMP $) now. And STILL doesn't work.
Sounds like this "spin lock" thing is the key but I don't even know
what a freaken spin lock is! Please bare with me, I'm trying my
hardest and it's 3:45am in the morning. WHY does it work when ran 2
times but on the 3rd DOS stalls? WHAT AM I DOING WRONG?! Eh.
And just when I thought I knew enough to program this code I can't
even get the simple things to work.
RE:Oh man...
Is it allways two times it runs, then it stalls. Or can it run(sometimes) 3 times, and then stall, or run one time and then stall?
The thread of execution is not only your code, other IRQ can happen(on the second controller), and you interrupt them.
A spin lock is when you test some value in a loop:
int need_to_run;//global var
....
....
while(need_to_run){
...any code..like printf("!");
}
...
...
...
need_to_run=0;//the next loop, the while loop will end.Place this code in the
//interrupt handler.
...
The thread of execution is not only your code, other IRQ can happen(on the second controller), and you interrupt them.
A spin lock is when you test some value in a loop:
int need_to_run;//global var
....
....
while(need_to_run){
...any code..like printf("!");
}
...
...
...
need_to_run=0;//the next loop, the while loop will end.Place this code in the
//interrupt handler.
...
Runs only 2 times...
It runs fine under pure MS-DOS but when ran in DOSEMU it only runs
2 times and then fails. The third time it prints '!' non stop as if
the timer wont reenter. It acts as if INT 1C was disabled (the third
time). Maybe I have to reset INT 1C somehow????
It's not only my code that wont work, I have tried various real-mode
multitaskers and they fail in a simular way. But when I have ran
commercial DOS multitaskers like Multidos and MCDOS they work fine.
Those programs use real-mode and are still able to multitask programs
just fine. How do they do this so flawlessly?
Could someone point me to some multitasking code for real-mode please.
I know assembly the best but C would be okay.
I really want to figure this out since it's part of a big project.
If I have to I will unassemble a commercial multitasker and figure out
how it works the hard way.
Thanks.
2 times and then fails. The third time it prints '!' non stop as if
the timer wont reenter. It acts as if INT 1C was disabled (the third
time). Maybe I have to reset INT 1C somehow????
It's not only my code that wont work, I have tried various real-mode
multitaskers and they fail in a simular way. But when I have ran
commercial DOS multitaskers like Multidos and MCDOS they work fine.
Those programs use real-mode and are still able to multitask programs
just fine. How do they do this so flawlessly?
Could someone point me to some multitasking code for real-mode please.
I know assembly the best but C would be okay.
I really want to figure this out since it's part of a big project.
If I have to I will unassemble a commercial multitasker and figure out
how it works the hard way.
Thanks.
RE:Runs only 2 times...
The following code works perfect.
.model small
.code
ORG 100H
start:
jmp Init ;goto startup
OldINT1C: DW 0
DW 0
end_loop: DW 0;this is for a spin lock
NewINT1C:
push ax
mov WORD ptr [CS:end_loop], 1
mov AL, 20H
out 20H, AL ;INT done
pop ax;
IRET ;Return to Done:
Init: ;Starts here...
mov word ptr [CS:end_loop],0;good programing habit
;reading interupt vector adres
cli;
xor ax,ax;
mov es,ax;
mov bx,[ES:1Ch*4 + 0];
mov word ptr [OldINT1C + 0], BX ;Save old INT 1C
mov bx,[ES:1Ch*4 + 2];
mov word ptr [OldINT1C + 2], BX ;...
;seting interrupt address
mov bx, offset NewINT1C;
mov [es:1ch*4 + 0],bx;
mov bx,cs
mov [es:1ch*4+2],bx;
sti;
SStart: ;endless code , only exits when INT 1C wants us to.
mov ah, 0Eh
mov al, '!'
mov bx, 0007h
int 10h ;Teletype '!' over and over....
cmp word ptr [end_loop], 0
je SStart
;restoring handler
cli;
xor ax,ax;
mov es,ax;
mov bx, word ptr [oldINT1C +0]
mov [es:1ch*4+0],bx;
mov bx,word ptr [OldINT1C+2]
mov [es:1ch*4+2],bx;
sti;
;Done
mov ah, 0Eh
mov al, 'D'
mov bx, 0007h
int 10h ;Print a 'D' for Done (for debug)
mov ax,4c00h
int 21h ;Exit to DOS, 4C00H I21 works also
END start
Explanation.
I took the restoring of the interupt out of the handler, since, it's just a bad programing habit to lose data(CS:IP), and put it in the main program.
The main program loops, printing ! , until the ending condition is met, then it restores the interupt, prints 'D', and ends the program.
The handler sets the ending condition
On my computer, it ran at least 5 times in a row.
Anton.
PS
The reason i took the restoring code out of the handler, is because we have no garanty that the CS,IP are from our program, and not form some other IRQ handler.
.model small
.code
ORG 100H
start:
jmp Init ;goto startup
OldINT1C: DW 0
DW 0
end_loop: DW 0;this is for a spin lock
NewINT1C:
push ax
mov WORD ptr [CS:end_loop], 1
mov AL, 20H
out 20H, AL ;INT done
pop ax;
IRET ;Return to Done:
Init: ;Starts here...
mov word ptr [CS:end_loop],0;good programing habit
;reading interupt vector adres
cli;
xor ax,ax;
mov es,ax;
mov bx,[ES:1Ch*4 + 0];
mov word ptr [OldINT1C + 0], BX ;Save old INT 1C
mov bx,[ES:1Ch*4 + 2];
mov word ptr [OldINT1C + 2], BX ;...
;seting interrupt address
mov bx, offset NewINT1C;
mov [es:1ch*4 + 0],bx;
mov bx,cs
mov [es:1ch*4+2],bx;
sti;
SStart: ;endless code , only exits when INT 1C wants us to.
mov ah, 0Eh
mov al, '!'
mov bx, 0007h
int 10h ;Teletype '!' over and over....
cmp word ptr [end_loop], 0
je SStart
;restoring handler
cli;
xor ax,ax;
mov es,ax;
mov bx, word ptr [oldINT1C +0]
mov [es:1ch*4+0],bx;
mov bx,word ptr [OldINT1C+2]
mov [es:1ch*4+2],bx;
sti;
;Done
mov ah, 0Eh
mov al, 'D'
mov bx, 0007h
int 10h ;Print a 'D' for Done (for debug)
mov ax,4c00h
int 21h ;Exit to DOS, 4C00H I21 works also
END start
Explanation.
I took the restoring of the interupt out of the handler, since, it's just a bad programing habit to lose data(CS:IP), and put it in the main program.
The main program loops, printing ! , until the ending condition is met, then it restores the interupt, prints 'D', and ends the program.
The handler sets the ending condition
On my computer, it ran at least 5 times in a row.
Anton.
PS
The reason i took the restoring code out of the handler, is because we have no garanty that the CS,IP are from our program, and not form some other IRQ handler.
Great!...
I will try it in a sec. I hope it runs more than five times though since I plan to run the code over
and over as many times as needed and this could be 500 times as far as I know. I didn't even
think about putting the interrupt restore routine outside of the interrupt. Good idea, thanks.
Also, I found that by using INT 15H to act as a timer it seems to work even better than 1CH.
This uses the RTC and seems more stable but I'm not sure if it will work on many computers since
I only tried it under DOSEMU. INT 15H AH=83H seems to do the trick better than INT 1CH.
I'm about this close " " to just saying the heck with it and using pmode and tss's. Thanks.
and over as many times as needed and this could be 500 times as far as I know. I didn't even
think about putting the interrupt restore routine outside of the interrupt. Good idea, thanks.
Also, I found that by using INT 15H to act as a timer it seems to work even better than 1CH.
This uses the RTC and seems more stable but I'm not sure if it will work on many computers since
I only tried it under DOSEMU. INT 15H AH=83H seems to do the trick better than INT 1CH.
I'm about this close " " to just saying the heck with it and using pmode and tss's. Thanks.
Ummm.... (anyone here)...
I just gave your code a better look. The routine that prints '!' may not always loop in my program.
Ok, to make my code more understandable this is what I want to do (the bigger picture)...
>kernel loads demo into memory (demo is the code that sets the 1C handler and prints '!' or whatever)
>kernel jumps to demo in memory
>Demo sets INT 1C to *its* handler
>Demo starts running *its* code IE: '!' or whatever it may be (could be anything, its an application/task)
>keeps looping the code if needed (its an application/task, who knows what it may do)
>INT 1C handler called?
>If so it restores the original 1C handler and saves Demo programs registers (like a context switch)
>jumps back to kernel
>kernel goes to next task.....
Once the kernel loads the Demo program back into memory it will restore its context and
go back into the code where it left off.
Basicly I want to put the context switching in the applications so that the kernel does very
little work of its own to do this. All this must be done so that it can run on a 8086++.
I know this sounds like a lot of overhead for the code but I have my reasons
So instead of having the timer handler and context switch done inside the kernel, it's all done
inside the applications themselfs. Then all the kernel must do is just loop the tasks like this...
redo:
call task1 ;run task1 until timer routine in code tells it to stop, if stopped- saves its TCB...
call task2 ;reloads task2 TCB, runs until timer routine in code tells it to stop, ect...
call task3 ;and so on...
jmp redo
Each task is kindof like a DOS TSR except that each time on re-entry it starts where it left off, like
a 386 task using tss's would do. Normally a TSR would just run the code and exit,
starting at the codes start. This is fine if I wanted to do a cooperative multitasking kernel but I want
preemtive and I want ALL the context switching done inside the task its self.
The Task Context Block TCB would be inside the code its self and relative to ONLY its self.
Each task this way only has to worry about its own TCB and not others. The kernel worries about
nothing since it does almost nothing in the first place
Any ideas?
The header of the task could be as little as 256 bytes (not including its stack). The TCB would
take about 16 words, AX, BX, CX, ES, ect... And the rest would be the timer/switch code of cource.
Has this been done before?
Is it a bad idea?
Thanks.
Ok, to make my code more understandable this is what I want to do (the bigger picture)...
>kernel loads demo into memory (demo is the code that sets the 1C handler and prints '!' or whatever)
>kernel jumps to demo in memory
>Demo sets INT 1C to *its* handler
>Demo starts running *its* code IE: '!' or whatever it may be (could be anything, its an application/task)
>keeps looping the code if needed (its an application/task, who knows what it may do)
>INT 1C handler called?
>If so it restores the original 1C handler and saves Demo programs registers (like a context switch)
>jumps back to kernel
>kernel goes to next task.....
Once the kernel loads the Demo program back into memory it will restore its context and
go back into the code where it left off.
Basicly I want to put the context switching in the applications so that the kernel does very
little work of its own to do this. All this must be done so that it can run on a 8086++.
I know this sounds like a lot of overhead for the code but I have my reasons
So instead of having the timer handler and context switch done inside the kernel, it's all done
inside the applications themselfs. Then all the kernel must do is just loop the tasks like this...
redo:
call task1 ;run task1 until timer routine in code tells it to stop, if stopped- saves its TCB...
call task2 ;reloads task2 TCB, runs until timer routine in code tells it to stop, ect...
call task3 ;and so on...
jmp redo
Each task is kindof like a DOS TSR except that each time on re-entry it starts where it left off, like
a 386 task using tss's would do. Normally a TSR would just run the code and exit,
starting at the codes start. This is fine if I wanted to do a cooperative multitasking kernel but I want
preemtive and I want ALL the context switching done inside the task its self.
The Task Context Block TCB would be inside the code its self and relative to ONLY its self.
Each task this way only has to worry about its own TCB and not others. The kernel worries about
nothing since it does almost nothing in the first place
Any ideas?
The header of the task could be as little as 256 bytes (not including its stack). The TCB would
take about 16 words, AX, BX, CX, ES, ect... And the rest would be the timer/switch code of cource.
Has this been done before?
Is it a bad idea?
Thanks.
RE:Ummm.... (anyone here)...
It's interesting, but why can't you do the task by the kernel?
Do you plan to run your own tasks, or any(any exe,com,...)
Anton.
Do you plan to run your own tasks, or any(any exe,com,...)
Anton.
RE:Ummm.... (anyone here)...
" but why can't you do the task by the kernel?"->but why can't you do the task switch by the kernel?
I could...
I just wanted to try this newish idea and see how well it worked. The kernel would be much smaller,
almost exokernel kindof. Just an idea of mine. I still can't get the code to work. I'm just going to give
up on the idea. Multitasking and the 8086 just don't go hand-in-hand. I guess the only multitasking
able to be done "correctly" on a PC is using a 286++. Oh well.
Thanks.
almost exokernel kindof. Just an idea of mine. I still can't get the code to work. I'm just going to give
up on the idea. Multitasking and the 8086 just don't go hand-in-hand. I guess the only multitasking
able to be done "correctly" on a PC is using a 286++. Oh well.
Thanks.
RE:I could...
You could do multitasking on a 8086, but the task switch will be inside the handler. I've done it:)
Anton.
Anton.
Would you care...
to tell me how it's done or show me how you did it? That would be great.
Also when and if I get something developed around these ideas I will add your
name under the credits if you want.
Thankyou.
Also when and if I get something developed around these ideas I will add your
name under the credits if you want.
Thankyou.
RE:Would you care...
It's actualy very simple, and a well know method( called software task switch). In short, all the regs are saved on entrens to the handler, then the stack pointer is saved, and a new stack poiter is loaded(for the new task), and then all regs are poped.
asm-like-code:
1c handler:
pusha;
mov ax,ss;
mov bx,sp;
mov [CS:task_array*2+this_task_index],ax;
mov [CS:task_array*2+this_task_index+2],bx;
call get_next_task_index;
mov this_task_index,ax;//return value in ax.
mov ax,[CS:task_array+this_task_index];
mov bx,[CS:task_array+this_task_index+2];
mov ss,ax;
mov sp,bx;
out 0x20,0x20;
popa
iret
Anton.
PS. No thanks for the credits[:)], like i said it's a well know thing:look
http://osdev.neopages.net/tutorials/soft_ts.php(but this is a software task switching for pm, but that does not mater(it is explained for pm, because software switch works faster then hardware))
asm-like-code:
1c handler:
pusha;
mov ax,ss;
mov bx,sp;
mov [CS:task_array*2+this_task_index],ax;
mov [CS:task_array*2+this_task_index+2],bx;
call get_next_task_index;
mov this_task_index,ax;//return value in ax.
mov ax,[CS:task_array+this_task_index];
mov bx,[CS:task_array+this_task_index+2];
mov ss,ax;
mov sp,bx;
out 0x20,0x20;
popa
iret
Anton.
PS. No thanks for the credits[:)], like i said it's a well know thing:look
http://osdev.neopages.net/tutorials/soft_ts.php(but this is a software task switching for pm, but that does not mater(it is explained for pm, because software switch works faster then hardware))