flat assembler
Message board for the users of flat assembler.
Index
> DOS > Quasi-multitasking in DOS Goto page 1, 2 Next |
Author |
|
Dex4u 26 Sep 2011, 17:33
Nice work, but TSR is multi-tasking
|
|||
26 Sep 2011, 17:33 |
|
me239 26 Sep 2011, 20:19
Dex4u wrote: Nice work, but TSR is multi-tasking |
|||
26 Sep 2011, 20:19 |
|
addes3 26 Sep 2011, 20:47
This doesn't compile. csSadint08 does not exist, though it is used in line 150. May be a misspell.
|
|||
26 Sep 2011, 20:47 |
|
me239 26 Sep 2011, 21:18
addes3 wrote: This doesn't compile. csSadint08 does not exist, though it is used in line 150. May be a misspell. |
|||
26 Sep 2011, 21:18 |
|
addes3 26 Sep 2011, 21:46
Ohhhhhhh okay.
|
|||
26 Sep 2011, 21:46 |
|
typedef 27 Sep 2011, 00:38
Doesn't do anything on my PC. Just pops up a console and quits. I tried running it from CMD but it does the same thing. It doesn't show anything either.
OS: XP Home Edition SP 3 |
|||
27 Sep 2011, 00:38 |
|
me239 27 Sep 2011, 00:46
typedef wrote: Doesn't do anything on my PC. Just pops up a console and quits. I tried running it from CMD but it does the same thing. It doesn't show anything either. |
|||
27 Sep 2011, 00:46 |
|
bitRAKE 27 Sep 2011, 04:56
me239 wrote: Say two programs are run, program 1 and program 2 respectively. If one were to close program 1 before program 2, int 08 would be returned to it's original vector rather than program 2, thus destroying the chain of tasks. I still have yet to figure out a workaround. Code: int08old: db $EA int08 dw 0,0 task: ... jmp int08old _________________ ¯\(°_o)/¯ “languages are not safe - uses can be” Bjarne Stroustrup |
|||
27 Sep 2011, 04:56 |
|
me239 27 Sep 2011, 05:20
bitRAKE wrote:
|
|||
27 Sep 2011, 05:20 |
|
bitRAKE 27 Sep 2011, 07:14
(0) First INT08 looks like this:
INT08: dd org_val ; segment:offset (of course) (1) Next a task is installed: Code: INT08: dd task_A ... db $EA dd org_val task_A: Code: INT08: dd task_B ... db $EA dd org_val task_A: ... db $EA dd task_A task_B: Code: INT08: dd task_B ... db $EA org_val task_B: Code: old = [task_A-4] val = [INT08] if val <> task_A while [val-4] <> task_A ; while not chained to removed task val = [val-4] ; get next task in chain end while [val-4] = old ; set forward link else [INT08] = old end if |
|||
27 Sep 2011, 07:14 |
|
me239 27 Sep 2011, 21:37
bitRAKE wrote: (0) First INT08 looks like this: |
|||
27 Sep 2011, 21:37 |
|
bitshifter 27 Sep 2011, 23:39
Have you seen my 512 byte multitasking OS demo?
http://board.flatassembler.net/topic.php?t=13063 I thought about making some changes to run on DOS but i am too damn lazy right now... Maybe you could learn something from it? |
|||
27 Sep 2011, 23:39 |
|
me239 28 Sep 2011, 00:20
bitshifter wrote: Have you seen my 512 byte multitasking OS demo? |
|||
28 Sep 2011, 00:20 |
|
bitshifter 28 Sep 2011, 01:53
It is slow because of the IPC indirection (which the KVP version doesnt have)
His had done IO within the timer IRQ wheras mine just sets flags and routes things later through the console. It also explains why his text merges better than mine. Hope that makes sense... |
|||
28 Sep 2011, 01:53 |
|
me239 28 Sep 2011, 02:21
bitshifter wrote: It is slow because of the IPC indirection (which the KVP version doesnt have) |
|||
28 Sep 2011, 02:21 |
|
bitshifter 28 Sep 2011, 02:34
In my demo the INT 08h vector only sets flags and then re-schedules.
The tasks have message-boxes and data-packets to communicate via IPC. It may take you a few hours or days to really understand the code. I recommend studying it until you understand every single byte. It took me about a week to understand it good enough to write my own version completely from scratch. Notice my version was inspired by KVP's version but shares no code which was copy and paste. |
|||
28 Sep 2011, 02:34 |
|
bitshifter 28 Sep 2011, 03:25
Assume CS = DS = ES = SS = whatever
Uses BIOS keyboard and video interrupts. ESC quits console server and exits to DOS. I have not debugged this code. There is things i need to know: Does hardware interrupt and software interrupt push same 3 regs? Is it ok to yield by issuing software interrupt? Code: ;====================================== ; smt4dos ;====================================== ;---------------; ; max constants ; ;---------------; MAX_STACK equ 512 ;number of words in each stack MAX_TASKS equ 8 ;-------------; ; task states ; ;-------------; STATE_FREE equ 0 ;dead, available task slot STATE_READY equ 1 ;running, no ipc activity STATE_SEND equ 2 ;sending an ipc message STATE_RECV equ 3 ;awaiting an ipc message STATE_SREQ equ 4 ;requesting an ipc service ;------------; ; task stack ; ;------------; TSS_SIZE equ 26 ;structure size (not on stack) TSS_FLAGS equ 24 ;int/iret TSS_CS equ 22 ;... TSS_IP equ 20 ;... TSS_AX equ 18 ;pusha/popa TSS_CX equ 16 ;... TSS_DX equ 14 ;... TSS_BX equ 12 ;... TSS_SP equ 10 ;... TSS_BP equ 8 ;... TSS_SI equ 6 ;... TSS_DI equ 4 ;... TSS_DS equ 2 ;push/pop ds TSS_ES equ 0 ;push/pop es ;---------------; ; service types ; ;---------------; SERVICE_NONE equ 0 ;intermediate service (Ex: idle,console,hello) SERVICE_GETC equ 1 ;character input service (Ex: stdin) SERVICE_PUTC equ 2 ;character output service (Ex: stdout) ;-------------; ; irq offsets ; ;-------------; IRQ0_IP equ (08h*4) IRQ0_CS equ (08h*4+2) ;======================================= ; program entry point ;======================================= use16 org 0100h ; assume cs = ds = es = ss = shared ;--------------------; ; disable interrupts ; ;--------------------; cli ;---------------------; ; init kernel context ; ;---------------------; ; mov ax,cs ; mov ds,ax ; mov es,ax ; mov ss,ax ; mov sp,0fffeh ;----------------; ; zero .bss data ; ;----------------; cld mov di,BSS_START mov cx,BSS_SIZE xor ax,ax ;zero high-bits for later rep stosb ;-----------------; ; chain into irq0 ; ;-----------------; push es push ax ;zero pop es mov ax,[es:IRQ0_IP] ;get old ip mov [ds:old_irq0_ip],ax ;store old ip mov [es:IRQ0_IP],word irq0 ;write new ip mov ax,[es:IRQ0_CS] ;get old cs mov [ds:old_irq0_cs],ax ;store old cs mov [es:IRQ0_CS],cs ;set new cs pop es ;--------------------; ; start system tasks ; ;--------------------; mov ax,server_idle ;task entry point offset mov cl,SERVICE_NONE ;services the task can provide call sys_exec ;input: ax = offset, cl = services ;output: bx = handle mov ax,server_console ;task entry point offset mov cl,SERVICE_NONE ;services the task can provide call sys_exec ;input: ax = offset, cl = services ;output: bx = handle ;---------------------------------; ; map kernel into idle task space ; ;---------------------------------; mov [ds:active_task],MAX_TASKS*2-2 ;first task handle mov sp,MAX_STACK*2*MAX_TASKS+task_stacks sti ;enable scheduler ; jmp server_idle ;=============================== ; system servers ;=============================== ;---------------------------------- server_idle: int 08h ;yield jmp server_idle ;----------------------------------- server_video: ;-----------------------------; ; await video service request ; ;-----------------------------; .await_request: call sys_recv ;out: bx = handle, dx = message, ax = packet ;------------------------------; ; handle video service request ; ;------------------------------; cmp dx,SERVICE_PUTC ;only service we provide jne .await_request ;go wait for more work ;---------------------------------------; ; provide teletype video output service ; ;---------------------------------------; .on_putc: mov ah,0eh ;teletype output mov bh,0 ;video page number ;handle backspace characters properly cmp al,8 jne .do_it int 10h ;BIOS video service mov al,32 ;print a space char int 10h ;BIOS video service mov al,8 .do_it: int 10h ;BIOS video service ;compliment carriage-return with line-feed sub al,3 cmp al,10 je .do_it jmp .await_request ;go wait for more work ;--------------------------------------------- server_keyboard: ;--------------------------------; ; await keyboard service request ; ;--------------------------------; .await_request: call sys_recv ;out: bx = handle, dx = message, ax = packet ;---------------------------------; ; handle keyboard service request ; ;---------------------------------; cmp dx,SERVICE_GETC ;only service we provide jne .await_request ;go wait for more work ;--------------------------------; ; provide keyboard input service ; ;--------------------------------; .on_getc: ;check keyboard buffer for keystroke mov ah,01h ;check keystroke int 16h ;BIOS keyboard service ;if there is no keystroke available we wait for one jz .on_getc_wait ;remove keystroke from keyboard buffer xor ah,ah ;get keystroke int 16h ;BIOS keyboard service ;send service request reply with data packet call sys_send ;in: bx = handle, dx = message, ax = packet jmp .await_request ;go wait for more work .on_getc_wait: ;an input request is still pending. ;dont continuosly poll via yield. int 08h ;yield jmp .on_getc ;try again ;---------------------------------------- server_console: ;--------------------; ; start video server ; ;--------------------; mov ax,server_video ;code entry point offset mov cl,SERVICE_PUTC ;services the task can provide call sys_exec ;in: ax = offset, cl = services ;out: bx = handle ;TODO: Verify task handle and try agin later if no slots available. ; This should never happen since its the third task started. mov [ds:console_stdout],bx ;store stdout handle ;-----------------------; ; start keyboard server ; ;-----------------------; mov ax,server_keyboard ;code entry point offset mov cl,SERVICE_GETC ;services the task can provide call sys_exec ;in: ax = offset, cl = services ;out: bx = handle ;TODO: Verify task handle and try agin later if no slots available. ; This should never happen since its the fourth task started. mov [ds:console_stdin],bx ;store stdin handle ;--------------------------; ; start hello world server ; ;--------------------------; .say_hello: mov ax,server_hello ;task entry point offset mov cl,SERVICE_NONE ;services the task can provide call sys_exec ;in: ax = offset, cl = services ;out: bx = handle ;TODO: Verify task handle and try again later if no slots available. ; At the moment we just ignore the request and go on living. ;--------------------------------; ; acquire and process user input ; ;--------------------------------; .wait_input: ;send input service request message to keyboard server mov dx,SERVICE_GETC ;service request mov bx,[ds:console_stdin] ;send to stdin call sys_send ;in: bx = handle, dx = message ;wait for keyboard server to reply call sys_recv ;out: bx = handle, dx = message, ax = packet ;TODO: Verify reply service by testing handle in bx and message in dx. ; (bx should be console_stdin and dx should be SERVICE_GETC) ;ESC character quits program cmp al,1bh je .quit ;'H' character spawns new hello world application cmp al,'H' je .say_hello ;any other data gets sent to stdout server mov dx,SERVICE_PUTC ;service request mov bx,[ds:console_stdout] ;send to stdout call sys_send ;in: bx = handle, dx = message, ax = packet jmp .wait_input ;go wait for more work .quit: cli ; lock the scheduler ; If the stdin/stdout servers needed to be cleaned ; we would send each one a cleanup message first. ;restore IRQ vector push 0 pop es mov ax,[ds:old_irq0_ip] mov [es:IRQ0_IP],ax mov ax,[ds:old_irq0_cs] mov [es:IRQ0_CS],ax int 20h jmp $ ;--------------------------------------------- str_hello db 'Hello World!',0 server_hello: ;--------------------------------------; ; display hello world message and quit ; ;--------------------------------------; mov si,str_hello .print: lodsb cmp al,0 je .done ;This task has no idea of who provides video services ;so we must ask the system to try and find a handler. mov dx,SERVICE_PUTC ;service request call sys_sreq ;in: dx = message, ax = packet ;out: bx = handle, dx = message, ax = packet ;If no video server was found, quit this task. or bx,bx ;compare bx to -2 jns .print .done: ;This task exits upon completion of displaying its message. call sys_exit ;never returns ;============================== ; system api ;============================== ;-------------------------------------- ; sys_exit -- exits a task ; in: no parameters ; out: never returns ; uses: bx ;-------------------------------------- sys_exit: pop ax ;discard return address mov bx,[ds:active_task] mov byte[ds:bx+task_states],STATE_FREE .dying: int 08h ;yield jmp .dying ;-------------------------------------- ; sys_exec -- starts a new task ; in: ax = task offset, cl = ipc services ; out: bx = task handle (-2 = out of task slots) ; uses: di,dx ; notes: If no test slots are available it is up to the caller to try again ; later, rather than hanging it while waiting for an open slot. ;-------------------------------------- sys_exec: pushf ;disable interrupts within this context cli mov bx,MAX_TASKS*2 ;allocate task handles from top down mov di,MAX_TASKS*2*MAX_STACK+task_stacks+MAX_STACK*2-TSS_SIZE ;allocate task stacks from top down .find_free_slot: sub di,MAX_STACK*2 dec bx dec bx js .no_free_slot ;-2 = no task slots available cmp byte[ds:bx+task_states],STATE_FREE jne .find_free_slot mov [ds:bx+stack_ptrs],di pushf pop dx or dx,512 ;'IRQ enable' bit in the flags register mov [ds:di+TSS_FLAGS],dx mov [ds:di+TSS_CS],cs mov [ds:di+TSS_IP],ax ; mov [ds:di+TSS_AX],0 ;no need to initialize these ; mov [ds:di+TSS_CX],0 ; mov [ds:di+TSS_DX],0 ; mov [ds:di+TSS_BX],0 ; mov [ds:di+TSS_SP],0 ; mov [ds:di+TSS_BP],0 ; mov [ds:di+TSS_SI],0 ; mov [ds:di+TSS_DI],0 mov [ds:di+TSS_DS],cs mov [ds:di+TSS_ES],cs mov byte[ds:bx+ipc_services],cl mov byte[ds:bx+task_states],STATE_READY .no_free_slot: popf ret ;--------------------------------------- ; sys_send -- sends an ipc message ; in: bx = ipc target handle, dx = message to send, ax = data packet to send ; out: no parameters ; uses: bp,cl ;--------------------------------------- sys_send: mov cl,STATE_SEND jmp ipc_squak ;--------------------------------------- ; sys_recv -- receives an ipc message ; in: no parameters ; out: bx = source handle, dx = message to recv, ax = data packet to recv ; uses: bp,cl ;--------------------------------------- sys_recv: mov cl,STATE_RECV jmp ipc_squak ;--------------------------------------- ; sys_sreq -- requests an ipc service ; in: dx = message, ax = data packet ; out: bx = ipc service handle (-2 = no handler found) ; uses: bp,cl ;--------------------------------------- sys_sreq: mov cl,STATE_SREQ ; jmp ipc_squak ;---------------------------------------- ; ipc_squak -- setup an ipc connection ; in: bx = handle, dx = message, ax = packet, cl = new state ; out: bx = handle, dx = message, ax = packet ; uses: bp ;---------------------------------------- ipc_squak: mov bp,[ds:active_task] mov [ss:bp+ipc_links],bx mov [ss:bp+ipc_messages],dx mov [ss:bp+ipc_packets],ax mov byte[ss:bp+task_states],cl .wait: cmp byte[ss:bp+task_states],STATE_READY je .ready ; int 08h ;yield, DEBUG -- is broken? jmp .wait .ready: mov bx,[ss:bp+ipc_links] mov dx,[ss:bp+ipc_messages] mov ax,[ss:bp+ipc_packets] ret ;===================================== ; IRQ0 hook ;===================================== ; we can yield here but next task only gets what time remains irq0: ;--------------------; ; disable interrupts ; ;--------------------; cli ;DEBUG -- does the cpu clear this? ;----------------------; ; store active context ; ;----------------------; pusha push ds push es ;---------------------; ; load kernel context ; ;---------------------; mov ax,cs mov ds,ax mov es,ax ; mov ss,ax ;----------------; ; load task info ; ;----------------; mov bx,[ds:active_task] mov ax,[ds:bx+task_states] mov di,[ds:bx+ipc_links] mov cx,[ds:bx+ipc_messages] mov dx,[ds:bx+ipc_packets] ;----------------------------; ; handle ipc service request ; ;----------------------------; cmp al,STATE_SREQ jne .not_sreq mov di,MAX_TASKS*2 .find_service_handler: dec di dec di js .no_service_handler cmp [ds:di+ipc_services],cx ;can he handle this type of service request message jne .find_service_handler ;keep looking for someone who can mov [ds:bx+ipc_links],di ;he can do it, so lets link ourself to him jmp .ipc_send ;send package it to him .no_service_handler: mov [ds:bx+ipc_links],di ;no handler found so return -2 jmp .task_done ;stop trying to post service request .not_sreq: ;----------------------------; ; handle ipc message passing ; ;----------------------------; cmp al,STATE_SEND jne .next_task .ipc_send: cmp byte[ds:di+task_states],STATE_RECV ;is target in recv mode? jne .next_task ;if not, try again later .ipc_copy: mov [ds:di+ipc_links],bx ;tell target who sent it (us) mov [ds:di+ipc_messages],cx ;put message in his mailbox mov [ds:di+ipc_packets],dx ;put data in his mailbox mov byte[ds:di+task_states],STATE_READY ;take target out of recv mode (break his wait loop) .task_done: mov byte[ds:bx+task_states],STATE_READY ;take us out of send/sreq mode .next_task: ;------------------------; ; perform task sheduling ; ;------------------------; ;BX = active task handle ;The sheduler requires an idle task whith constant READY state to work properly. ;Otherwise we could end up in and endless loop trying to find a task to schedule. mov [ds:bx+stack_ptrs],sp .find_work: dec bx dec bx jns .check_state mov bx,MAX_TASKS*2-2 ;wrap around .check_state: cmp byte[ds:bx+task_states],STATE_FREE je .find_work ;dont schedule dead tasks cmp byte[ds:bx+task_states],STATE_RECV je .find_work ;dont schedule waiting tasks mov [ds:active_task],bx ;new active task handle mov sp,[ds:bx+stack_ptrs] ;-------------------; ; load task context ; ;-------------------; pop es pop ds popa ;---------------------------; ; jump far into old handler ; ;---------------------------; db 0eah ;opcode: jmp far old_irq0_ip dw 0000h ;hot-patch: ip old_irq0_cs dw 0000h ;hot-patch: cs ;================================== ; uninitialized data ;================================== BSS_START: active_task rw 1 task_stacks rw MAX_TASKS*MAX_STACK stack_ptrs rw MAX_TASKS task_states rw MAX_TASKS ;only lobyte is used ipc_services rw MAX_TASKS ;only lobyte is used ipc_messages rw MAX_TASKS ipc_links rw MAX_TASKS ipc_packets rw MAX_TASKS ;console server private data console_stdin rw 1 console_stdout rw 1 BSS_SIZE = $ - BSS_START ;=================================== _________________ Coding a 3D game engine with fasm is like trying to eat an elephant, you just have to keep focused and take it one 'byte' at a time. Last edited by bitshifter on 30 Sep 2011, 00:35; edited 3 times in total |
|||
28 Sep 2011, 03:25 |
|
me239 28 Sep 2011, 04:30
bitshifter wrote: Ok, this was EZ-4-ME so here it is ported to DOS as a COM program. Last edited by me239 on 29 Sep 2011, 03:58; edited 1 time in total |
|||
28 Sep 2011, 04:30 |
|
bitshifter 28 Sep 2011, 08:42
I updated the code posted above...
|
|||
28 Sep 2011, 08:42 |
|
Goto page 1, 2 Next < Last Thread | Next Thread > |
Forum Rules:
|
Copyright © 1999-2024, Tomasz Grysztar. Also on GitHub, YouTube.
Website powered by rwasa.